diff --git a/br-ext-chip-hisilicon/board/hi3536cv100/hi3536cv100.config b/br-ext-chip-hisilicon/board/hi3536cv100/hi3536cv100.config
new file mode 100644
index 00000000..4e797567
--- /dev/null
+++ b/br-ext-chip-hisilicon/board/hi3536cv100/hi3536cv100.config
@@ -0,0 +1,2 @@
+MEM_START_ADDR=0x80000000
+KERNEL_UPLOAD_ADDR=0x82000000
diff --git a/br-ext-chip-hisilicon/board/hi3536cv100/kernel/hi3536cv100.generic.config b/br-ext-chip-hisilicon/board/hi3536cv100/kernel/hi3536cv100.generic.config
new file mode 100644
index 00000000..6a51d405
--- /dev/null
+++ b/br-ext-chip-hisilicon/board/hi3536cv100/kernel/hi3536cv100.generic.config
@@ -0,0 +1,2523 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# Linux/arm 3.18.20 Kernel Configuration
+#
+CONFIG_ARM=y
+CONFIG_ARM_HAS_SG_CHAIN=y
+CONFIG_MIGHT_HAVE_PCI=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_HAVE_PROC_CPU=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_ARCH_SUPPORTS_UPROBES=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_ARM_PATCH_PHYS_VIRT=y
+CONFIG_GENERIC_BUG=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_IRQ_WORK=y
+CONFIG_BUILDTIME_EXTABLE_SORT=y
+
+#
+# General setup
+#
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_CROSS_COMPILE=""
+# CONFIG_COMPILE_TEST is not set
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_HAVE_KERNEL_XZ=y
+CONFIG_HAVE_KERNEL_LZO=y
+CONFIG_HAVE_KERNEL_LZ4=y
+# CONFIG_KERNEL_GZIP is not set
+# CONFIG_KERNEL_LZMA is not set
+CONFIG_KERNEL_XZ=y
+# CONFIG_KERNEL_LZO is not set
+# CONFIG_KERNEL_LZ4 is not set
+CONFIG_DEFAULT_HOSTNAME="openipc"
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_CROSS_MEMORY_ATTACH=y
+# CONFIG_FHANDLE is not set
+CONFIG_USELIB=y
+# CONFIG_AUDIT is not set
+
+#
+# IRQ subsystem
+#
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_IRQ_DOMAIN=y
+CONFIG_HANDLE_DOMAIN_IRQ=y
+CONFIG_IRQ_FORCED_THREADING=y
+CONFIG_SPARSE_IRQ=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_ARCH_HAS_TICK_BROADCAST=y
+CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
+
+#
+# Timers subsystem
+#
+CONFIG_HZ_PERIODIC=y
+# CONFIG_NO_HZ_IDLE is not set
+# CONFIG_NO_HZ_FULL is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+
+#
+# CPU/Task time and stats accounting
+#
+CONFIG_TICK_CPU_ACCOUNTING=y
+# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set
+# CONFIG_IRQ_TIME_ACCOUNTING is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_TASKS_RCU is not set
+CONFIG_RCU_STALL_COMMON=y
+# CONFIG_RCU_USER_QS is not set
+CONFIG_RCU_FANOUT=32
+CONFIG_RCU_FANOUT_LEAF=16
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_RCU_NOCB_CPU is not set
+# CONFIG_BUILD_BIN2C is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=17
+CONFIG_LOG_CPU_MAX_BUF_SHIFT=12
+CONFIG_GENERIC_SCHED_CLOCK=y
+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_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_USER_NS is not set
+CONFIG_PID_NS=y
+CONFIG_NET_NS=y
+# 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=y
+CONFIG_RD_LZMA=y
+CONFIG_RD_XZ=y
+CONFIG_RD_LZO=y
+CONFIG_RD_LZ4=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_HAVE_UID16=y
+CONFIG_BPF=y
+# CONFIG_EXPERT is not set
+CONFIG_UID16=y
+# CONFIG_SGETMASK_SYSCALL is not set
+CONFIG_SYSFS_SYSCALL=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=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_BPF_SYSCALL is not set
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_ADVISE_SYSCALLS=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 is not set
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+CONFIG_SLUB_CPU_PARTIAL=y
+# CONFIG_PROFILING is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+# CONFIG_JUMP_LABEL is not set
+# CONFIG_UPROBES is not set
+# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
+CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
+CONFIG_ARCH_USE_BUILTIN_BSWAP=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_GENERIC_SMP_IDLE_THREAD=y
+CONFIG_GENERIC_IDLE_POLL_SETUP=y
+CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
+CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+CONFIG_HAVE_PERF_REGS=y
+CONFIG_HAVE_PERF_USER_STACK_DUMP=y
+CONFIG_HAVE_ARCH_JUMP_LABEL=y
+CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
+CONFIG_HAVE_CC_STACKPROTECTOR=y
+# CONFIG_CC_STACKPROTECTOR is not set
+CONFIG_CC_STACKPROTECTOR_NONE=y
+# CONFIG_CC_STACKPROTECTOR_REGULAR is not set
+# CONFIG_CC_STACKPROTECTOR_STRONG is not set
+CONFIG_HAVE_CONTEXT_TRACKING=y
+CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
+CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
+CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
+CONFIG_MODULES_USE_ELF_REL=y
+CONFIG_CLONE_BACKWARDS=y
+CONFIG_OLD_SIGSUSPEND3=y
+CONFIG_OLD_SIGACTION=y
+
+#
+# GCOV-based kernel profiling
+#
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_MODULE_SIG is not set
+# CONFIG_MODULE_COMPRESS is not set
+CONFIG_STOP_MACHINE=y
+CONFIG_BLOCK=y
+CONFIG_LBDAF=y
+CONFIG_BLK_DEV_BSG=y
+# CONFIG_BLK_DEV_BSGLIB is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+CONFIG_BLK_CMDLINE_PARSER=y
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_AIX_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=y
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_CMDLINE_PARTITION=y
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_DEADLINE=y
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="deadline"
+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_ARCH_SUPPORTS_ATOMIC_RMW=y
+CONFIG_MUTEX_SPIN_ON_OWNER=y
+CONFIG_RWSEM_SPIN_ON_OWNER=y
+CONFIG_FREEZER=y
+
+#
+# System Type
+#
+CONFIG_MMU=y
+CONFIG_ARCH_MULTIPLATFORM=y
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_GEMINI is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_DOVE is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_MMP is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_W90X900 is not set
+# CONFIG_ARCH_LPC32XX is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_SHMOBILE_LEGACY 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_DAVINCI is not set
+# CONFIG_ARCH_OMAP1 is not set
+
+#
+# Multiple platform selection
+#
+
+#
+# CPU Core family selection
+#
+# CONFIG_ARCH_MULTI_V6 is not set
+CONFIG_ARCH_MULTI_V7=y
+CONFIG_ARCH_MULTI_V6_V7=y
+# CONFIG_ARCH_MULTI_CPU_AUTO is not set
+# CONFIG_ARCH_VIRT is not set
+# CONFIG_ARCH_MVEBU is not set
+# CONFIG_ARCH_BCM is not set
+# CONFIG_ARCH_BERLIN is not set
+# CONFIG_ARCH_HIGHBANK is not set
+CONFIG_ARCH_HISI=y
+
+#
+# Hisilicon platform type
+#
+# CONFIG_ARCH_HI3xxx is not set
+# CONFIG_ARCH_HIP04 is not set
+# CONFIG_ARCH_HIX5HD2 is not set
+# CONFIG_ARCH_HI3519 is not set
+# CONFIG_ARCH_HI3519V101 is not set
+# CONFIG_ARCH_HI3516AV200 is not set
+# CONFIG_ARCH_HI3559 is not set
+# CONFIG_ARCH_HI3556 is not set
+CONFIG_ARCH_HI3536C=y
+# CONFIG_ARCH_HI3531D is not set
+# CONFIG_ARCH_HI3521D is not set
+# CONFIG_ARCH_KEYSTONE is not set
+# CONFIG_ARCH_MESON is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_MEDIATEK is not set
+
+#
+# TI OMAP/AM/DM/DRA Family
+#
+# CONFIG_ARCH_OMAP3 is not set
+# CONFIG_ARCH_OMAP4 is not set
+# CONFIG_SOC_OMAP5 is not set
+# CONFIG_SOC_AM33XX is not set
+# CONFIG_SOC_AM43XX is not set
+# CONFIG_SOC_DRA7XX is not set
+# CONFIG_ARCH_QCOM is not set
+# CONFIG_ARCH_ROCKCHIP is not set
+# CONFIG_ARCH_SOCFPGA is not set
+# CONFIG_PLAT_SPEAR is not set
+# CONFIG_ARCH_STI is not set
+# CONFIG_ARCH_S5PV210 is not set
+# CONFIG_ARCH_EXYNOS is not set
+# CONFIG_ARCH_SHMOBILE_MULTI is not set
+# CONFIG_ARCH_SUNXI is not set
+# CONFIG_ARCH_SIRF is not set
+# CONFIG_ARCH_TEGRA is not set
+# CONFIG_ARCH_U8500 is not set
+# CONFIG_ARCH_VEXPRESS is not set
+# CONFIG_ARCH_WM8850 is not set
+# CONFIG_ARCH_ZYNQ is not set
+CONFIG_ARM_TIMER_SP804=y
+
+#
+# Processor Type
+#
+CONFIG_CPU_V7=y
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_32v7=y
+CONFIG_CPU_ABRT_EV7=y
+CONFIG_CPU_PABRT_V7=y
+CONFIG_CPU_CACHE_V7=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V7=y
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_LPAE is not set
+# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
+CONFIG_ARM_THUMB=y
+# CONFIG_ARM_THUMBEE is not set
+CONFIG_ARM_VIRT_EXT=y
+CONFIG_SWP_EMULATE=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_KUSER_HELPERS=y
+CONFIG_MIGHT_HAVE_CACHE_L2X0=y
+# CONFIG_CACHE_L2X0 is not set
+CONFIG_ARM_L1_CACHE_SHIFT_6=y
+CONFIG_ARM_L1_CACHE_SHIFT=6
+CONFIG_ARM_DMA_MEM_BUFFERABLE=y
+CONFIG_MULTI_IRQ_HANDLER=y
+# CONFIG_ARM_ERRATA_430973 is not set
+# CONFIG_ARM_ERRATA_643719 is not set
+# CONFIG_ARM_ERRATA_720789 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_ARM_ERRATA_775420 is not set
+# CONFIG_ARM_ERRATA_798181 is not set
+# CONFIG_ARM_ERRATA_773022 is not set
+
+#
+# Bus support
+#
+CONFIG_ARM_AMBA=y
+# CONFIG_PCI is not set
+# 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_DISABLE_CPU_SCHED_DOMAIN_BALANCE is not set
+CONFIG_HAVE_ARM_SCU=y
+CONFIG_HAVE_ARM_ARCH_TIMER=y
+# CONFIG_MCPM is not set
+# CONFIG_BIG_LITTLE is not set
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_NR_CPUS=4
+CONFIG_HOTPLUG_CPU=y
+# CONFIG_ARM_PSCI is not set
+CONFIG_ARCH_NR_GPIO=0
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_HZ_FIXED=0
+CONFIG_HZ_100=y
+# CONFIG_HZ_200 is not set
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_500 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=100
+# CONFIG_SCHED_HRTICK is not set
+# CONFIG_THUMB2_KERNEL is not set
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+CONFIG_HAVE_ARCH_PFN_VALID=y
+CONFIG_HIGHMEM=y
+# CONFIG_HIGHPTE is not set
+CONFIG_ARCH_WANT_GENERAL_HUGETLB=y
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_HAVE_MEMBLOCK=y
+CONFIG_NO_BOOTMEM=y
+# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_COMPACTION=y
+CONFIG_MIGRATION=y
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_BOUNCE=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+# CONFIG_CLEANCACHE is not set
+# CONFIG_CMA is not set
+# CONFIG_ZPOOL is not set
+# CONFIG_ZBUD is not set
+# CONFIG_ZSMALLOC 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_SWIOTLB=y
+CONFIG_IOMMU_HELPER=y
+# CONFIG_XEN is not set
+# CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART is not set
+
+#
+# Boot options
+#
+CONFIG_USE_OF=y
+CONFIG_ATAGS=y
+# CONFIG_DEPRECATED_PARAM_STRUCT is not set
+# CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE is not set
+CONFIG_ZBOOT_ROM_TEXT=0
+CONFIG_ZBOOT_ROM_BSS=0
+CONFIG_ARM_APPENDED_DTB=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_KEXEC is not set
+# CONFIG_CRASH_DUMP is not set
+CONFIG_AUTO_ZRELADDR=y
+
+#
+# CPU Power Management
+#
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# CPU Idle
+#
+# CONFIG_CPU_IDLE is not set
+# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+# CONFIG_FPE_NWFPE is not set
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_VFP=y
+CONFIG_VFPv3=y
+CONFIG_NEON=y
+CONFIG_KERNEL_MODE_NEON=y
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_BINFMT_SCRIPT=y
+# CONFIG_HAVE_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+CONFIG_COREDUMP=y
+
+#
+# Power management options
+#
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+CONFIG_WAKELOCK=y
+# CONFIG_HISI_SNAPSHOT_BOOT is not set
+CONFIG_PM_SLEEP=y
+CONFIG_PM_SLEEP_SMP=y
+# CONFIG_PM_AUTOSLEEP is not set
+# CONFIG_PM_WAKELOCKS is not set
+# CONFIG_PM_RUNTIME is not set
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+# CONFIG_APM_EMULATION is not set
+CONFIG_PM_CLK=y
+# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set
+CONFIG_CPU_PM=y
+# CONFIG_SUSPEND_TIME is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_ARM_CPU_SUSPEND=y
+CONFIG_ARCH_HIBERNATION_POSSIBLE=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=y
+# 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_NET_IP_TUNNEL=y
+# CONFIG_IP_MROUTE is not set
+# CONFIG_SYN_COOKIES is not set
+CONFIG_NET_UDP_TUNNEL=y
+CONFIG_NET_FOU=y
+# CONFIG_GENEVE 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 is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+CONFIG_INET_LRO=y
+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_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 is not set
+# CONFIG_INET6_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET6_XFRM_MODE_BEET is not set
+# 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_ANDROID_PARANOID_NETWORK is not set
+CONFIG_NET_ACTIVITY_STATS=y
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NET_PTP_CLASSIFY is not set
+# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
+# CONFIG_NETFILTER 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_HAVE_NET_DSA=y
+# 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_PHONET is not set
+# CONFIG_6LOWPAN 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_VSOCKETS is not set
+# CONFIG_NETLINK_MMAP is not set
+# CONFIG_NETLINK_DIAG is not set
+# CONFIG_NET_MPLS_GSO is not set
+# CONFIG_HSR is not set
+CONFIG_RPS=y
+CONFIG_RFS_ACCEL=y
+CONFIG_XPS=y
+# CONFIG_CGROUP_NET_PRIO is not set
+# CONFIG_CGROUP_NET_CLASSID is not set
+CONFIG_NET_RX_BUSY_POLL=y
+CONFIG_BQL=y
+# CONFIG_BPF_JIT is not set
+CONFIG_NET_FLOW_LIMIT=y
+
+#
+# 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_WIRELESS_EXT=y
+CONFIG_WEXT_CORE=y
+CONFIG_WEXT_PROC=y
+CONFIG_WEXT_PRIV=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_DEFAULT_PS=y
+# CONFIG_CFG80211_INTERNAL_REGDB is not set
+# CONFIG_CFG80211_WEXT is not set
+# CONFIG_LIB80211 is not set
+CONFIG_MAC80211=m
+CONFIG_MAC80211_HAS_RC=y
+CONFIG_MAC80211_RC_MINSTREL=y
+CONFIG_MAC80211_RC_MINSTREL_HT=y
+CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y
+CONFIG_MAC80211_RC_DEFAULT="minstrel_ht"
+# CONFIG_MAC80211_MESH is not set
+# CONFIG_MAC80211_MESSAGE_TRACING is not set
+# CONFIG_MAC80211_DEBUG_MENU is not set
+# 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 is not set
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_STANDALONE=y
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_FW_LOADER_USER_HELPER_FALLBACK is not set
+CONFIG_ALLOW_DEV_COREDUMP=y
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_GENERIC_CPU_DEVICES is not set
+# CONFIG_HAVE_CPU_AUTOPROBE is not set
+CONFIG_REGMAP=y
+CONFIG_REGMAP_MMIO=y
+# CONFIG_DMA_SHARED_BUFFER is not set
+
+#
+# Bus devices
+#
+# CONFIG_BRCMSTB_GISB_ARB is not set
+# CONFIG_ARM_CCI is not set
+# CONFIG_VEXPRESS_CONFIG 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=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_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_HIFMC=y
+CONFIG_HIFMC_SPI_NAND=y
+# CONFIG_HIFMC_NAND is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SST25L is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+CONFIG_MTD_BLOCK2MTD=y
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOCG3 is not set
+CONFIG_MTD_NAND_IDS=y
+CONFIG_MTD_NAND_ECC=y
+# CONFIG_MTD_NAND_ECC_SMC is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_ECC_BCH is not set
+# CONFIG_MTD_SM_COMMON is not set
+# CONFIG_MTD_NAND_DENALI is not set
+# CONFIG_MTD_NAND_OMAP_BCH_BUILD is not set
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_DOCG4 is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_HISI_NAND_FS_MAY_NO_YAFFS2 is not set
+# CONFIG_HISI_NAND_ECC_STATUS_REPORT is not set
+# CONFIG_MTD_NAND_HINFC610 is not set
+# CONFIG_HIFMC100_NAND is not set
+CONFIG_HIFMC100_SPI_NAND=y
+CONFIG_SPI_NAND_MAX_CHIP_NUM=1
+# CONFIG_HIFMC100_HARDWARE_PAGESIZE_ECC is not set
+CONFIG_HIFMC100_AUTO_PAGESIZE_ECC=y
+# CONFIG_HIFMC100_PAGESIZE_AUTO_ECC_NONE is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR & LPDDR2 PCM memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+# CONFIG_MTD_LPDDR2_NVM is not set
+CONFIG_MTD_SPI_NOR=y
+# CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set
+CONFIG_SPI_HISI_SFC=y
+CONFIG_CLOSE_SPI_8PIN_4IO=y
+CONFIG_HISI_SPI_BLOCK_PROTECT=y
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_WL_THRESHOLD=4096
+CONFIG_MTD_UBI_BEB_LIMIT=20
+# CONFIG_MTD_UBI_FASTMAP is not set
+# CONFIG_MTD_UBI_GLUEBI is not set
+# CONFIG_MTD_UBI_BLOCK is not set
+CONFIG_DTC=y
+CONFIG_OF=y
+
+#
+# Device Tree and Open Firmware support
+#
+# 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_NET=y
+CONFIG_OF_MDIO=y
+CONFIG_OF_MTD=y
+CONFIG_OF_RESERVED_MEM=y
+CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_NULL_BLK is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP 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=65536
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH 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_DUMMY_IRQ 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_UID_STAT is not set
+# CONFIG_BMP085_I2C is not set
+# CONFIG_BMP085_SPI is not set
+# CONFIG_USB_SWITCH_FSA9480 is not set
+# CONFIG_LATTICE_ECP3_CONFIG is not set
+# CONFIG_SRAM is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_AT24 is not set
+# CONFIG_EEPROM_AT25 is not set
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
+CONFIG_EEPROM_93CX6=m
+# CONFIG_EEPROM_93XX46 is not set
+
+#
+# Texas Instruments shared transport line discipline
+#
+# CONFIG_SENSORS_LIS3_SPI is not set
+# CONFIG_SENSORS_LIS3_I2C is not set
+
+#
+# Altera FPGA firmware download module
+#
+# CONFIG_ALTERA_STAPL is not set
+
+#
+# Intel MIC Bus Driver
+#
+
+#
+# Intel MIC Host Driver
+#
+
+#
+# Intel MIC Card Driver
+#
+# CONFIG_ECHO is not set
+# CONFIG_CXL_BASE is not set
+
+#
+# hisi 'himm/himd.l/himc'support
+#
+# CONFIG_HISI_REG 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_NETLINK is not set
+# CONFIG_SCSI_MQ_DEFAULT is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+# CONFIG_SCSI_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 is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
+CONFIG_HI_SATA=y
+CONFIG_HI_SATA_IOBASE=0x11010000
+CONFIG_HI_SATA_FBS=1
+CONFIG_HI_SATA_NCQ=1
+CONFIG_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
+CONFIG_ATA_VERBOSE_ERROR=y
+CONFIG_SATA_PMP=y
+
+#
+# Controllers with non-SFF native interface
+#
+CONFIG_SATA_AHCI_PLATFORM=y
+# CONFIG_ATA_SFF is not set
+# CONFIG_MD 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_NET_TEAM is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_VXLAN is not set
+# 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_NLMON is not set
+
+#
+# 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_NET_DSA_MV88E6171 is not set
+# CONFIG_NET_DSA_BCM_SF2 is not set
+CONFIG_ETHERNET=y
+# CONFIG_ALTERA_TSE is not set
+# CONFIG_NET_XGENE is not set
+# CONFIG_NET_VENDOR_ARC is not set
+# CONFIG_NET_CADENCE is not set
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_CIRRUS is not set
+# CONFIG_DM9000 is not set
+# CONFIG_DNET is not set
+# CONFIG_NET_VENDOR_FARADAY is not set
+CONFIG_NET_VENDOR_HISILICON=y
+# CONFIG_HIX5HD2_GMAC is not set
+# CONFIG_HISI_FEMAC is not set
+CONFIG_HIETH_GMAC=y
+CONFIG_HIGMAC_DESC_4WORD=y
+CONFIG_HIGMAC_RXCSUM=y
+CONFIG_RX_FLOW_CTRL_SUPPORT=y
+CONFIG_TX_FLOW_CTRL_SUPPORT=y
+CONFIG_TX_FLOW_CTRL_PAUSE_TIME=0xFFFF
+CONFIG_TX_FLOW_CTRL_PAUSE_INTERVAL=0xFFFF
+CONFIG_TX_FLOW_CTRL_ACTIVE_THRESHOLD=16
+CONFIG_TX_FLOW_CTRL_DEACTIVE_THRESHOLD=32
+# CONFIG_HIETH_SWITCH_FABRIC is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_MICROCHIP is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_ETHOC is not set
+# CONFIG_NET_VENDOR_QUALCOMM is not set
+# CONFIG_NET_VENDOR_SAMSUNG is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
+# CONFIG_NET_VENDOR_VIA is not set
+# CONFIG_NET_VENDOR_WIZNET is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_AT803X_PHY is not set
+# CONFIG_AMD_PHY is not set
+# CONFIG_AMD_XGBE_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 is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_BCM7XXX_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_MMIOREG is not set
+# CONFIG_MDIO_BCM_UNIMAC is not set
+# CONFIG_MDIO_HISI_FEMAC is not set
+CONFIG_MDIO_HISI_GEMAC=y
+# CONFIG_MICREL_KS8995MA is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+CONFIG_USB_NET_DRIVERS=m
+# 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_RTL8152 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_USB_IPHETH 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=m
+# CONFIG_MAC80211_HWSIM is not set
+# CONFIG_WIFI_CONTROL_FUNC is not set
+# CONFIG_ATH_CARDS is not set
+# CONFIG_B43 is not set
+# CONFIG_B43LEGACY is not set
+# CONFIG_BRCMSMAC is not set
+# CONFIG_BRCMFMAC is not set
+# CONFIG_HOSTAP is not set
+# CONFIG_LIBERTAS is not set
+# CONFIG_P54_COMMON is not set
+CONFIG_RT2X00=m
+CONFIG_RT2500USB=m
+CONFIG_RT73USB=m
+CONFIG_RT2800USB=m
+CONFIG_RT2800USB_RT33XX=y
+CONFIG_RT2800USB_RT35XX=y
+# CONFIG_RT2800USB_RT3573 is not set
+# CONFIG_RT2800USB_RT53XX is not set
+# CONFIG_RT2800USB_RT55XX is not set
+# CONFIG_RT2800USB_UNKNOWN is not set
+CONFIG_RT2800_LIB=m
+CONFIG_RT2X00_LIB_USB=m
+CONFIG_RT2X00_LIB=m
+CONFIG_RT2X00_LIB_FIRMWARE=y
+CONFIG_RT2X00_LIB_CRYPTO=y
+# CONFIG_RT2X00_DEBUG is not set
+CONFIG_RTL_CARDS=m
+CONFIG_RTL8192CU=m
+CONFIG_RTLWIFI=m
+CONFIG_RTLWIFI_USB=m
+CONFIG_RTLWIFI_DEBUG=y
+CONFIG_RTL8192C_COMMON=m
+# CONFIG_WL_TI is not set
+# CONFIG_ZD1211RW is not set
+# CONFIG_MWIFIEX is not set
+# CONFIG_CW1200 is not set
+# CONFIG_RSI_91X 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 is not set
+# 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 is not set
+# CONFIG_INPUT_KEYRESET is not set
+# CONFIG_INPUT_KEYCOMBO 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=m
+# CONFIG_KEYBOARD_QT1070 is not set
+# CONFIG_KEYBOARD_QT2160 is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_TCA6416 is not set
+# CONFIG_KEYBOARD_TCA8418 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 is not set
+# CONFIG_KEYBOARD_CAP1106 is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=m
+CONFIG_MOUSE_PS2_ALPS=y
+CONFIG_MOUSE_PS2_LOGIPS2PP=y
+CONFIG_MOUSE_PS2_SYNAPTICS=y
+CONFIG_MOUSE_PS2_CYPRESS=y
+CONFIG_MOUSE_PS2_TRACKPOINT=y
+# CONFIG_MOUSE_PS2_ELANTECH is not set
+# CONFIG_MOUSE_PS2_SENTELIC is not set
+# CONFIG_MOUSE_PS2_TOUCHKIT is not set
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_APPLETOUCH is not set
+# CONFIG_MOUSE_BCM5974 is not set
+# CONFIG_MOUSE_CYAPA is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_MOUSE_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 is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_AMBAKMI is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_SERIO_ALTERA_PS2 is not set
+# CONFIG_SERIO_PS2MULT is not set
+# CONFIG_SERIO_ARC_PS2 is not set
+# CONFIG_SERIO_APBPS2 is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_TTY=y
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_VT_CONSOLE_SLEEP=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES 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_DEVMEM=y
+# CONFIG_DEVKMEM is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_EARLYCON=y
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_AMBA_PL010 is not set
+CONFIG_SERIAL_AMBA_PL011=y
+CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
+# CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST is not set
+# 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_SC16IS7XX is not set
+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
+# CONFIG_SERIAL_ALTERA_UART is not set
+# CONFIG_SERIAL_XILINX_PS_UART is not set
+# CONFIG_SERIAL_ARC is not set
+# CONFIG_SERIAL_FSL_LPUART is not set
+# CONFIG_SERIAL_ST_ASC is not set
+# CONFIG_HVC_DCC is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_DCC_TTY is not set
+# CONFIG_XILLYBUS is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_MUX=y
+
+#
+# Multiplexer I2C Chip support
+#
+# CONFIG_I2C_MUX_PCA9541 is not set
+# CONFIG_I2C_MUX_PINCTRL is not set
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_DESIGNWARE_PLATFORM is not set
+# CONFIG_I2C_HIBVT is not set
+# CONFIG_I2C_HISI_V110 is not set
+# CONFIG_I2C_NOMADIK 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_RK3X 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_ROBOTFUZZ_OSIF is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+CONFIG_HI_I2C=y
+CONFIG_HI_I2C0_IO_BASE=0x120c0000
+CONFIG_HI_I2C0_IO_SIZE=0x1000
+CONFIG_HI_I2C_RETRIES=0x1
+CONFIG_HI_I2C_TX_FIFO=0x8
+CONFIG_HI_I2C_RX_FIFO=0x8
+CONFIG_HI_I2C0_CLK_LIMIT=100000
+# 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_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_ALTERA is not set
+# CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_CADENCE is not set
+# CONFIG_SPI_FSL_SPI is not set
+CONFIG_SPI_PL022=y
+# CONFIG_SPI_PXA2XX_PCI is not set
+# CONFIG_SPI_ROCKCHIP 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=y
+# CONFIG_SPI_TLE62X0 is not set
+# CONFIG_SPMI is not set
+# CONFIG_HSI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+
+#
+# PPS generators support
+#
+
+#
+# PTP clock support
+#
+# CONFIG_PTP_1588_CLOCK is not set
+
+#
+# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
+#
+CONFIG_PINCTRL=y
+
+#
+# Pin controllers
+#
+CONFIG_PINMUX=y
+CONFIG_PINCONF=y
+CONFIG_GENERIC_PINCONF=y
+CONFIG_PINCTRL_SINGLE=y
+CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
+# CONFIG_GPIOLIB is not set
+# CONFIG_W1 is not set
+CONFIG_POWER_SUPPLY=y
+# CONFIG_POWER_SUPPLY_DEBUG is not set
+# CONFIG_PDA_POWER is not set
+# CONFIG_TEST_POWER is not set
+# CONFIG_BATTERY_DS2780 is not set
+# CONFIG_BATTERY_DS2781 is not set
+# CONFIG_BATTERY_DS2782 is not set
+# CONFIG_BATTERY_SBS is not set
+# CONFIG_BATTERY_BQ27x00 is not set
+# CONFIG_BATTERY_MAX17040 is not set
+# CONFIG_BATTERY_MAX17042 is not set
+# CONFIG_CHARGER_MAX8903 is not set
+# CONFIG_CHARGER_LP8727 is not set
+# CONFIG_CHARGER_MANAGER is not set
+# CONFIG_CHARGER_BQ2415X is not set
+# CONFIG_CHARGER_SMB347 is not set
+CONFIG_POWER_RESET=y
+# CONFIG_POWER_RESET_BRCMSTB is not set
+CONFIG_POWER_RESET_HISI=y
+# CONFIG_POWER_RESET_RESTART is not set
+# CONFIG_POWER_RESET_VERSATILE is not set
+# CONFIG_POWER_RESET_SYSCON is not set
+# CONFIG_POWER_AVS is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_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=y
+# CONFIG_MFD_AS3711 is not set
+# CONFIG_MFD_AS3722 is not set
+# CONFIG_PMIC_ADP5520 is not set
+# CONFIG_MFD_BCM590XX is not set
+# CONFIG_MFD_AXP20X is not set
+# CONFIG_MFD_CROS_EC is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_MFD_DA9052_SPI is not set
+# CONFIG_MFD_DA9052_I2C is not set
+# CONFIG_MFD_DA9055 is not set
+# CONFIG_MFD_DA9063 is not set
+# CONFIG_MFD_MC13XXX_SPI is not set
+# CONFIG_MFD_MC13XXX_I2C is not set
+# CONFIG_MFD_HI6421_PMIC is not set
+CONFIG_MFD_HISI_FMC=y
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_INTEL_SOC_PMIC is not set
+# CONFIG_MFD_KEMPLD is not set
+# CONFIG_MFD_88PM800 is not set
+# CONFIG_MFD_88PM805 is not set
+# CONFIG_MFD_88PM860X is not set
+# CONFIG_MFD_MAX14577 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_MENF21BMC is not set
+# CONFIG_EZX_PCAP is not set
+# CONFIG_MFD_VIPERBOARD is not set
+# CONFIG_MFD_RETU is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_MFD_PM8921_CORE is not set
+# CONFIG_MFD_RTSX_USB is not set
+# CONFIG_MFD_RC5T583 is not set
+# CONFIG_MFD_RK808 is not set
+# CONFIG_MFD_RN5T618 is not set
+# CONFIG_MFD_SEC_CORE is not set
+# CONFIG_MFD_SI476X_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_SMSC is not set
+# CONFIG_ABX500_CORE is not set
+# CONFIG_MFD_STMPE is not set
+CONFIG_MFD_SYSCON=y
+# CONFIG_MFD_TI_AM335X_TSCADC is not set
+# CONFIG_MFD_LP3943 is not set
+# CONFIG_MFD_LP8788 is not set
+# CONFIG_MFD_PALMAS is not set
+# CONFIG_TPS6105X is not set
+# CONFIG_TPS6507X is not set
+# CONFIG_MFD_TPS65090 is not set
+# CONFIG_MFD_TPS65217 is not set
+# CONFIG_MFD_TPS65218 is not set
+# CONFIG_MFD_TPS6586X is not set
+# CONFIG_MFD_TPS80031 is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_TWL6040_CORE is not set
+# CONFIG_MFD_WL1273_CORE is not set
+# CONFIG_MFD_LM3533 is not set
+# CONFIG_MFD_TC3589X is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
+# CONFIG_MFD_ARIZONA_I2C is not set
+# CONFIG_MFD_ARIZONA_SPI is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X_I2C is not set
+# CONFIG_MFD_WM831X_SPI is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_WM8994 is not set
+CONFIG_REGULATOR=y
+# CONFIG_REGULATOR_DEBUG is not set
+# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
+# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
+# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
+# CONFIG_REGULATOR_ACT8865 is not set
+# CONFIG_REGULATOR_AD5398 is not set
+# CONFIG_REGULATOR_ANATOP is not set
+# CONFIG_REGULATOR_DA9210 is not set
+# CONFIG_REGULATOR_DA9211 is not set
+# CONFIG_REGULATOR_FAN53555 is not set
+# CONFIG_REGULATOR_ISL9305 is not set
+# CONFIG_REGULATOR_ISL6271A is not set
+# CONFIG_REGULATOR_LP3971 is not set
+# CONFIG_REGULATOR_LP3972 is not set
+# CONFIG_REGULATOR_LP872X is not set
+# CONFIG_REGULATOR_LP8755 is not set
+# CONFIG_REGULATOR_LTC3589 is not set
+# CONFIG_REGULATOR_MAX1586 is not set
+# CONFIG_REGULATOR_MAX8649 is not set
+# CONFIG_REGULATOR_MAX8660 is not set
+# CONFIG_REGULATOR_MAX8952 is not set
+# CONFIG_REGULATOR_MAX8973 is not set
+# CONFIG_REGULATOR_PFUZE100 is not set
+# CONFIG_REGULATOR_TPS51632 is not set
+# CONFIG_REGULATOR_TPS62360 is not set
+# CONFIG_REGULATOR_TPS65023 is not set
+# CONFIG_REGULATOR_TPS6507X is not set
+# CONFIG_REGULATOR_TPS6524X is not set
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+# CONFIG_IMX_IPUV3_CORE is not set
+
+#
+# Direct Rendering Manager
+#
+# CONFIG_DRM is not set
+
+#
+# Frame buffer Devices
+#
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+CONFIG_FB_CMDLINE=y
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# 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_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_ARMCLCD is not set
+# CONFIG_FB_OPENCORES is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_SMSCUFX is not set
+# CONFIG_FB_UDL is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_BROADSHEET is not set
+# CONFIG_FB_AUO_K190X is not set
+# CONFIG_FB_SIMPLE is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+# CONFIG_VGASTATE is not set
+
+#
+# Console display driver support
+#
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE is not set
+# CONFIG_LOGO is not set
+# CONFIG_SOUND is not set
+
+#
+# HID support
+#
+CONFIG_HID=y
+# CONFIG_HID_BATTERY_STRENGTH is not set
+# CONFIG_HIDRAW is not set
+# CONFIG_UHID is not set
+CONFIG_HID_GENERIC=y
+
+#
+# Special HID drivers
+#
+CONFIG_HID_A4TECH=y
+# CONFIG_HID_ACRUX is not set
+CONFIG_HID_APPLE=y
+# CONFIG_HID_APPLEIR is not set
+# CONFIG_HID_AUREAL is not set
+CONFIG_HID_BELKIN=y
+CONFIG_HID_CHERRY=y
+CONFIG_HID_CHICONY=y
+CONFIG_HID_CYPRESS=y
+# CONFIG_HID_DRAGONRISE is not set
+# CONFIG_HID_EMS_FF is not set
+# CONFIG_HID_ELECOM is not set
+# CONFIG_HID_ELO is not set
+CONFIG_HID_EZKEY=y
+# CONFIG_HID_HOLTEK is not set
+# CONFIG_HID_HUION 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_ICADE is not set
+# CONFIG_HID_TWINHAN is not set
+CONFIG_HID_KENSINGTON=y
+# CONFIG_HID_LCPOWER is not set
+# CONFIG_HID_LENOVO is not set
+CONFIG_HID_LOGITECH=y
+# CONFIG_HID_LOGITECH_HIDPP is not set
+# CONFIG_LOGITECH_FF is not set
+# CONFIG_LOGIRUMBLEPAD2_FF is not set
+# CONFIG_LOGIG940_FF is not set
+# CONFIG_LOGIWHEELS_FF is not set
+# CONFIG_HID_MAGICMOUSE is not set
+CONFIG_HID_MICROSOFT=y
+CONFIG_HID_MONTEREY=y
+# 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_PENMOUNT is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_PICOLCD is not set
+# CONFIG_HID_PRIMAX is not set
+# CONFIG_HID_ROCCAT is not set
+# CONFIG_HID_SAITEK is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SPEEDLINK is not set
+# CONFIG_HID_STEELSERIES is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_HID_RMI 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_XINMO is not set
+# CONFIG_HID_ZEROPLUS is not set
+# CONFIG_HID_ZYDACRON is not set
+# CONFIG_HID_SENSOR_HUB is not set
+
+#
+# USB HID support
+#
+CONFIG_USB_HID=y
+# CONFIG_HID_PID is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# I2C HID support
+#
+# CONFIG_I2C_HID is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_COMMON=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB=y
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEFAULT_PERSIST=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_FSM is not set
+# CONFIG_USB_MON is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_XHCI_HCD is not set
+CONFIG_USB_EHCI_HCD=y
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+CONFIG_USB_EHCI_TT_NEWSCHED=y
+CONFIG_USB_EHCI_HCD_PLATFORM=y
+# 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_FUSBH200_HCD is not set
+# CONFIG_USB_FOTG210_HCD is not set
+# CONFIG_USB_MAX3421_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_HCD_PLATFORM=y
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_HCD_TEST_MODE is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+
+#
+# also be needed; see USB_STORAGE Help for more info
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_REALTEK is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_STORAGE_ENE_UB6250 is not set
+# CONFIG_USB_UAS is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USBIP_CORE is not set
+# CONFIG_USB_MUSB_HDRC is not set
+# CONFIG_USB_DWC3 is not set
+# CONFIG_USB_DWC2 is not set
+# CONFIG_USB_CHIPIDEA is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_EHSET_TEST_FIXTURE is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_YUREX is not set
+# CONFIG_USB_EZUSB_FX2 is not set
+# CONFIG_USB_HSIC_USB3503 is not set
+# CONFIG_USB_LINK_LAYER_TEST is not set
+
+#
+# USB Physical Layer drivers
+#
+# CONFIG_USB_PHY is not set
+# CONFIG_USB_OTG_WAKELOCK is not set
+# CONFIG_NOP_USB_XCEIV is not set
+# CONFIG_AM335X_PHY_USB is not set
+# CONFIG_USB_ISP1301 is not set
+# CONFIG_USB_ULPI is not set
+# CONFIG_USB_GADGET is not set
+# CONFIG_UWB is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_SWITCH is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_EDAC is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_SYSTOHC=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_DS3232 is not set
+# CONFIG_RTC_DRV_HYM8563 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_ISL12057 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF2127 is not set
+# CONFIG_RTC_DRV_PCF8523 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF85063 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_DS1343 is not set
+# CONFIG_RTC_DRV_DS1347 is not set
+# CONFIG_RTC_DRV_DS1390 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_R9701 is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_DS3234 is not set
+# CONFIG_RTC_DRV_PCF2123 is not set
+# CONFIG_RTC_DRV_RX4581 is not set
+# CONFIG_RTC_DRV_MCP795 is not set
+
+#
+# Platform RTC drivers
+#
+CONFIG_RTC_DRV_HIBVT=y
+# 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_DS2404 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
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_RTC_DRV_PL030 is not set
+# CONFIG_RTC_DRV_PL031 is not set
+# CONFIG_RTC_DRV_SNVS is not set
+# CONFIG_RTC_DRV_XGENE is not set
+
+#
+# HID Sensor RTC drivers
+#
+# CONFIG_RTC_DRV_HID_SENSOR_TIME is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+# CONFIG_VIRT_DRIVERS is not set
+
+#
+# Virtio drivers
+#
+# CONFIG_VIRTIO_MMIO is not set
+
+#
+# Microsoft Hyper-V guest support
+#
+CONFIG_STAGING=y
+# CONFIG_PRISM2_USB is not set
+# CONFIG_COMEDI is not set
+# CONFIG_RTLLIB is not set
+CONFIG_R8712U=m
+CONFIG_R8188EU=m
+CONFIG_88EU_AP_MODE=y
+# CONFIG_VT6656 is not set
+# CONFIG_BCM_WIMAX is not set
+# CONFIG_FT1000 is not set
+
+#
+# Speakup console speech
+#
+# CONFIG_SPEAKUP is not set
+# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4 is not set
+# CONFIG_STAGING_MEDIA is not set
+
+#
+# Android
+#
+# CONFIG_ANDROID is not set
+# CONFIG_USB_WPAN_HCD is not set
+# CONFIG_WIMAX_GDM72XX is not set
+# CONFIG_LTE_GDM724X is not set
+# CONFIG_MTD_SPINAND_MT29F is not set
+# CONFIG_LUSTRE_FS is not set
+# CONFIG_DGAP is not set
+# CONFIG_GS_FPGABOOT is not set
+
+#
+# SOC (System On Chip) specific Drivers
+#
+# CONFIG_SOC_TI is not set
+CONFIG_CLKDEV_LOOKUP=y
+CONFIG_HAVE_CLK_PREPARE=y
+CONFIG_COMMON_CLK=y
+
+#
+# Common Clock Framework
+#
+# CONFIG_COMMON_CLK_SI5351 is not set
+# CONFIG_COMMON_CLK_SI570 is not set
+# CONFIG_COMMON_CLK_PXA is not set
+# CONFIG_COMMON_CLK_QCOM is not set
+
+#
+# Hardware Spinlock drivers
+#
+
+#
+# Clock Source drivers
+#
+CONFIG_CLKSRC_OF=y
+CONFIG_CLKSRC_MMIO=y
+CONFIG_ARM_ARCH_TIMER=y
+CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y
+# CONFIG_ARM_ARCH_TIMER_VCT_ACCESS is not set
+# CONFIG_ATMEL_PIT is not set
+# CONFIG_SH_TIMER_CMT is not set
+# CONFIG_SH_TIMER_MTU2 is not set
+# CONFIG_SH_TIMER_TMU is not set
+# CONFIG_EM_TIMER_STI is not set
+# CONFIG_CLKSRC_VERSATILE is not set
+# CONFIG_MAILBOX is not set
+# CONFIG_IOMMU_SUPPORT is not set
+
+#
+# Remoteproc drivers
+#
+# CONFIG_STE_MODEM_RPROC is not set
+
+#
+# Rpmsg drivers
+#
+
+#
+# SOC (System On Chip) specific Drivers
+#
+# 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
+CONFIG_IRQCHIP=y
+CONFIG_ARM_GIC=y
+# CONFIG_IPACK_BUS is not set
+CONFIG_ARCH_HAS_RESET_CONTROLLER=y
+CONFIG_RESET_CONTROLLER=y
+# CONFIG_FMC is not set
+
+#
+# PHY Subsystem
+#
+CONFIG_GENERIC_PHY=y
+# CONFIG_BCM_KONA_USB2_PHY is not set
+CONFIG_PHY_HISI_INNO_USB2=y
+CONFIG_HI_NANO_PHY_SATA=y
+CONFIG_HI_SATA_PORTS=2
+CONFIG_HI_SATA_MODE=1
+# CONFIG_POWERCAP is not set
+# CONFIG_MCB is not set
+CONFIG_HI_DMAC=y
+CONFIG_HI_DMAC_CHANNEL_NUM=4
+
+#
+# Hisilicon driver support
+#
+
+#
+# File systems
+#
+CONFIG_DCACHE_WORD_ACCESS=y
+CONFIG_EXT2_FS=m
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=m
+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=m
+# CONFIG_EXT4_FS_POSIX_ACL is not set
+# CONFIG_EXT4_FS_SECURITY is not set
+# CONFIG_EXT4_DEBUG is not set
+CONFIG_JBD=m
+CONFIG_JBD2=m
+# CONFIG_JBD2_DEBUG is not set
+CONFIG_FS_MBCACHE=m
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FS_POSIX_ACL=y
+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 is not set
+# CONFIG_FUSE_FS is not set
+CONFIG_OVERLAY_FS=y
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS 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_KERNFS=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=m
+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_YAFFS_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 is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_UBIFS_FS is not set
+# CONFIG_LOGFS is not set
+CONFIG_CRAMFS=y
+CONFIG_SQUASHFS=y
+CONFIG_SQUASHFS_FILE_CACHE=y
+# CONFIG_SQUASHFS_FILE_DIRECT is not set
+CONFIG_SQUASHFS_DECOMP_SINGLE=y
+# CONFIG_SQUASHFS_DECOMP_MULTI is not set
+# CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU is not set
+# CONFIG_SQUASHFS_XATTR is not set
+CONFIG_SQUASHFS_ZLIB=y
+# CONFIG_SQUASHFS_LZO is not set
+CONFIG_SQUASHFS_XZ=y
+# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set
+# CONFIG_SQUASHFS_EMBEDDED is not set
+CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX6FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_PSTORE is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_F2FS_FS=m
+CONFIG_F2FS_FS_XATTR=y
+CONFIG_F2FS_FS_POSIX_ACL=y
+# CONFIG_F2FS_FS_SECURITY is not set
+# CONFIG_F2FS_CHECK_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V2=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_SWAP is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_GRACE_PERIOD=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_ACL_SUPPORT=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=m
+# 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=y
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+
+#
+# printk and dmesg options
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4
+
+#
+# Compile-time checks and compiler options
+#
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_FRAME_WARN=1024
+# CONFIG_STRIP_ASM_SYMS is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_SECTION_MISMATCH is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_DEBUG_KERNEL is not set
+
+#
+# Memory Debugging
+#
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS is not set
+CONFIG_HAVE_DEBUG_KMEMLEAK=y
+CONFIG_DEBUG_MEMORY_INIT=y
+
+#
+# Debug Lockups and Hangs
+#
+# CONFIG_PANIC_ON_OOPS is not set
+CONFIG_PANIC_ON_OOPS_VALUE=0
+CONFIG_PANIC_TIMEOUT=0
+
+#
+# Lock Debugging (spinlocks, mutexes, etc...)
+#
+CONFIG_STACKTRACE=y
+CONFIG_DEBUG_BUGVERBOSE=y
+
+#
+# RCU Debugging
+#
+# CONFIG_SPARSE_RCU_POINTER is not set
+# CONFIG_TORTURE_TEST is not set
+CONFIG_RCU_CPU_STALL_TIMEOUT=60
+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 is not set
+
+#
+# Runtime Testing
+#
+# CONFIG_ATOMIC64_SELFTEST is not set
+# CONFIG_TEST_STRING_HELPERS is not set
+# CONFIG_TEST_KSTRTOX is not set
+# CONFIG_TEST_RHASHTABLE is not set
+# CONFIG_DMA_API_DEBUG is not set
+# CONFIG_TEST_LKM is not set
+# CONFIG_TEST_USER_COPY is not set
+# CONFIG_TEST_BPF is not set
+# CONFIG_TEST_FIRMWARE is not set
+# CONFIG_TEST_UDELAY is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_STRICT_DEVMEM=y
+CONFIG_ARM_UNWIND=y
+# CONFIG_DEBUG_USER is not set
+CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S"
+# CONFIG_DEBUG_UART_PL01X is not set
+# CONFIG_DEBUG_UART_8250 is not set
+# CONFIG_DEBUG_UART_BCM63XX is not set
+CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"
+# CONFIG_OC_ETM is not set
+# CONFIG_PID_IN_CONTEXTIDR is not set
+# CONFIG_DEBUG_SET_MODULE_RONX is not set
+# CONFIG_CORESIGHT is not set
+
+#
+# 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_AEAD=m
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=m
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG=m
+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 is not set
+CONFIG_CRYPTO_WORKQUEUE=y
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_MCRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+CONFIG_CRYPTO_CCM=m
+# CONFIG_CRYPTO_GCM is not set
+CONFIG_CRYPTO_SEQIV=m
+
+#
+# Block modes
+#
+# CONFIG_CRYPTO_CBC is not set
+CONFIG_CRYPTO_CTR=m
+# 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_CMAC is not set
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
+
+#
+# Digest
+#
+CONFIG_CRYPTO_CRC32C=y
+# CONFIG_CRYPTO_CRC32 is not set
+# CONFIG_CRYPTO_CRCT10DIF 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_SHA1_ARM_NEON is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_SHA512_ARM_NEON 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_AES_ARM_BS is not set
+# 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 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=y
+# CONFIG_CRYPTO_ZLIB is not set
+CONFIG_CRYPTO_LZO=y
+# CONFIG_CRYPTO_LZ4 is not set
+# CONFIG_CRYPTO_LZ4HC is not set
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+# CONFIG_CRYPTO_DRBG_MENU is not set
+# CONFIG_CRYPTO_USER_API_HASH is not set
+# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
+CONFIG_CRYPTO_HW=y
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_STRNCPY_FROM_USER=y
+CONFIG_GENERIC_STRNLEN_USER=y
+CONFIG_GENERIC_NET_UTILS=y
+CONFIG_GENERIC_PCI_IOMAP=y
+CONFIG_GENERIC_IO=y
+CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
+CONFIG_CRC_CCITT=m
+CONFIG_CRC16=y
+# CONFIG_CRC_T10DIF is not set
+CONFIG_CRC_ITU_T=m
+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_AUDIT_ARCH_COMPAT_GENERIC is not set
+# CONFIG_RANDOM32_SELFTEST is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_LZ4_DECOMPRESS=y
+CONFIG_XZ_DEC=y
+CONFIG_XZ_DEC_X86=y
+CONFIG_XZ_DEC_POWERPC=y
+CONFIG_XZ_DEC_IA64=y
+CONFIG_XZ_DEC_ARM=y
+CONFIG_XZ_DEC_ARMTHUMB=y
+CONFIG_XZ_DEC_SPARC=y
+CONFIG_XZ_DEC_BCJ=y
+# CONFIG_XZ_DEC_TEST is not set
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_DECOMPRESS_BZIP2=y
+CONFIG_DECOMPRESS_LZMA=y
+CONFIG_DECOMPRESS_XZ=y
+CONFIG_DECOMPRESS_LZO=y
+CONFIG_DECOMPRESS_LZ4=y
+CONFIG_GENERIC_ALLOCATOR=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT_MAP=y
+CONFIG_HAS_DMA=y
+CONFIG_CPU_RMAP=y
+CONFIG_DQL=y
+CONFIG_GLOB=y
+# CONFIG_GLOB_SELFTEST is not set
+CONFIG_NLATTR=y
+CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
+CONFIG_AVERAGE=y
+# CONFIG_CORDIC is not set
+# CONFIG_DDR is not set
+CONFIG_LIBFDT=y
+CONFIG_ARCH_HAS_SG_CHAIN=y
+# CONFIG_VIRTUALIZATION is not set
diff --git a/br-ext-chip-hisilicon/board/hi3536cv100/kernel/hi3536cv100.generic.config.original b/br-ext-chip-hisilicon/board/hi3536cv100/kernel/hi3536cv100.generic.config.original
new file mode 100644
index 00000000..9f8b73a6
--- /dev/null
+++ b/br-ext-chip-hisilicon/board/hi3536cv100/kernel/hi3536cv100.generic.config.original
@@ -0,0 +1,2522 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# Linux/arm 3.18.20 Kernel Configuration
+#
+CONFIG_ARM=y
+CONFIG_ARM_HAS_SG_CHAIN=y
+CONFIG_MIGHT_HAVE_PCI=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_HAVE_PROC_CPU=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_ARCH_SUPPORTS_UPROBES=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_ARM_PATCH_PHYS_VIRT=y
+CONFIG_GENERIC_BUG=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_IRQ_WORK=y
+CONFIG_BUILDTIME_EXTABLE_SORT=y
+
+#
+# General setup
+#
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_CROSS_COMPILE=""
+# CONFIG_COMPILE_TEST is not set
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_HAVE_KERNEL_XZ=y
+CONFIG_HAVE_KERNEL_LZO=y
+CONFIG_HAVE_KERNEL_LZ4=y
+CONFIG_KERNEL_GZIP=y
+# CONFIG_KERNEL_LZMA is not set
+# CONFIG_KERNEL_XZ is not set
+# CONFIG_KERNEL_LZO is not set
+# CONFIG_KERNEL_LZ4 is not set
+CONFIG_DEFAULT_HOSTNAME="(none)"
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_CROSS_MEMORY_ATTACH=y
+# CONFIG_FHANDLE is not set
+CONFIG_USELIB=y
+# CONFIG_AUDIT is not set
+
+#
+# IRQ subsystem
+#
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_IRQ_DOMAIN=y
+CONFIG_HANDLE_DOMAIN_IRQ=y
+CONFIG_IRQ_FORCED_THREADING=y
+CONFIG_SPARSE_IRQ=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_ARCH_HAS_TICK_BROADCAST=y
+CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
+
+#
+# Timers subsystem
+#
+CONFIG_HZ_PERIODIC=y
+# CONFIG_NO_HZ_IDLE is not set
+# CONFIG_NO_HZ_FULL is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+
+#
+# CPU/Task time and stats accounting
+#
+CONFIG_TICK_CPU_ACCOUNTING=y
+# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set
+# CONFIG_IRQ_TIME_ACCOUNTING is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_TASKS_RCU is not set
+CONFIG_RCU_STALL_COMMON=y
+# CONFIG_RCU_USER_QS is not set
+CONFIG_RCU_FANOUT=32
+CONFIG_RCU_FANOUT_LEAF=16
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_RCU_NOCB_CPU is not set
+# CONFIG_BUILD_BIN2C is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=17
+CONFIG_LOG_CPU_MAX_BUF_SHIFT=12
+CONFIG_GENERIC_SCHED_CLOCK=y
+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_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_USER_NS is not set
+CONFIG_PID_NS=y
+CONFIG_NET_NS=y
+# 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=y
+CONFIG_RD_LZMA=y
+CONFIG_RD_XZ=y
+CONFIG_RD_LZO=y
+CONFIG_RD_LZ4=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_HAVE_UID16=y
+CONFIG_BPF=y
+# CONFIG_EXPERT is not set
+CONFIG_UID16=y
+# CONFIG_SGETMASK_SYSCALL is not set
+CONFIG_SYSFS_SYSCALL=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+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_BPF_SYSCALL is not set
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_ADVISE_SYSCALLS=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 is not set
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+CONFIG_SLUB_CPU_PARTIAL=y
+# CONFIG_PROFILING is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+# CONFIG_JUMP_LABEL is not set
+# CONFIG_UPROBES is not set
+# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
+CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
+CONFIG_ARCH_USE_BUILTIN_BSWAP=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_GENERIC_SMP_IDLE_THREAD=y
+CONFIG_GENERIC_IDLE_POLL_SETUP=y
+CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
+CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+CONFIG_HAVE_PERF_REGS=y
+CONFIG_HAVE_PERF_USER_STACK_DUMP=y
+CONFIG_HAVE_ARCH_JUMP_LABEL=y
+CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
+CONFIG_HAVE_CC_STACKPROTECTOR=y
+# CONFIG_CC_STACKPROTECTOR is not set
+CONFIG_CC_STACKPROTECTOR_NONE=y
+# CONFIG_CC_STACKPROTECTOR_REGULAR is not set
+# CONFIG_CC_STACKPROTECTOR_STRONG is not set
+CONFIG_HAVE_CONTEXT_TRACKING=y
+CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
+CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
+CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
+CONFIG_MODULES_USE_ELF_REL=y
+CONFIG_CLONE_BACKWARDS=y
+CONFIG_OLD_SIGSUSPEND3=y
+CONFIG_OLD_SIGACTION=y
+
+#
+# GCOV-based kernel profiling
+#
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_MODULE_SIG is not set
+# CONFIG_MODULE_COMPRESS is not set
+CONFIG_STOP_MACHINE=y
+CONFIG_BLOCK=y
+CONFIG_LBDAF=y
+CONFIG_BLK_DEV_BSG=y
+# CONFIG_BLK_DEV_BSGLIB is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+CONFIG_BLK_CMDLINE_PARSER=y
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_AIX_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=y
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_CMDLINE_PARTITION=y
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_DEADLINE=y
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="deadline"
+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_ARCH_SUPPORTS_ATOMIC_RMW=y
+CONFIG_MUTEX_SPIN_ON_OWNER=y
+CONFIG_RWSEM_SPIN_ON_OWNER=y
+CONFIG_FREEZER=y
+
+#
+# System Type
+#
+CONFIG_MMU=y
+CONFIG_ARCH_MULTIPLATFORM=y
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_GEMINI is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_DOVE is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_MMP is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_W90X900 is not set
+# CONFIG_ARCH_LPC32XX is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_SHMOBILE_LEGACY 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_DAVINCI is not set
+# CONFIG_ARCH_OMAP1 is not set
+
+#
+# Multiple platform selection
+#
+
+#
+# CPU Core family selection
+#
+# CONFIG_ARCH_MULTI_V6 is not set
+CONFIG_ARCH_MULTI_V7=y
+CONFIG_ARCH_MULTI_V6_V7=y
+# CONFIG_ARCH_MULTI_CPU_AUTO is not set
+# CONFIG_ARCH_VIRT is not set
+# CONFIG_ARCH_MVEBU is not set
+# CONFIG_ARCH_BCM is not set
+# CONFIG_ARCH_BERLIN is not set
+# CONFIG_ARCH_HIGHBANK is not set
+CONFIG_ARCH_HISI=y
+
+#
+# Hisilicon platform type
+#
+# CONFIG_ARCH_HI3xxx is not set
+# CONFIG_ARCH_HIP04 is not set
+# CONFIG_ARCH_HIX5HD2 is not set
+# CONFIG_ARCH_HI3519 is not set
+# CONFIG_ARCH_HI3519V101 is not set
+# CONFIG_ARCH_HI3516AV200 is not set
+# CONFIG_ARCH_HI3559 is not set
+# CONFIG_ARCH_HI3556 is not set
+CONFIG_ARCH_HI3536C=y
+# CONFIG_ARCH_HI3531D is not set
+# CONFIG_ARCH_HI3521D is not set
+# CONFIG_ARCH_KEYSTONE is not set
+# CONFIG_ARCH_MESON is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_MEDIATEK is not set
+
+#
+# TI OMAP/AM/DM/DRA Family
+#
+# CONFIG_ARCH_OMAP3 is not set
+# CONFIG_ARCH_OMAP4 is not set
+# CONFIG_SOC_OMAP5 is not set
+# CONFIG_SOC_AM33XX is not set
+# CONFIG_SOC_AM43XX is not set
+# CONFIG_SOC_DRA7XX is not set
+# CONFIG_ARCH_QCOM is not set
+# CONFIG_ARCH_ROCKCHIP is not set
+# CONFIG_ARCH_SOCFPGA is not set
+# CONFIG_PLAT_SPEAR is not set
+# CONFIG_ARCH_STI is not set
+# CONFIG_ARCH_S5PV210 is not set
+# CONFIG_ARCH_EXYNOS is not set
+# CONFIG_ARCH_SHMOBILE_MULTI is not set
+# CONFIG_ARCH_SUNXI is not set
+# CONFIG_ARCH_SIRF is not set
+# CONFIG_ARCH_TEGRA is not set
+# CONFIG_ARCH_U8500 is not set
+# CONFIG_ARCH_VEXPRESS is not set
+# CONFIG_ARCH_WM8850 is not set
+# CONFIG_ARCH_ZYNQ is not set
+CONFIG_ARM_TIMER_SP804=y
+
+#
+# Processor Type
+#
+CONFIG_CPU_V7=y
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_32v7=y
+CONFIG_CPU_ABRT_EV7=y
+CONFIG_CPU_PABRT_V7=y
+CONFIG_CPU_CACHE_V7=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V7=y
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_LPAE is not set
+# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
+CONFIG_ARM_THUMB=y
+# CONFIG_ARM_THUMBEE is not set
+CONFIG_ARM_VIRT_EXT=y
+CONFIG_SWP_EMULATE=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_KUSER_HELPERS=y
+CONFIG_MIGHT_HAVE_CACHE_L2X0=y
+# CONFIG_CACHE_L2X0 is not set
+CONFIG_ARM_L1_CACHE_SHIFT_6=y
+CONFIG_ARM_L1_CACHE_SHIFT=6
+CONFIG_ARM_DMA_MEM_BUFFERABLE=y
+CONFIG_MULTI_IRQ_HANDLER=y
+# CONFIG_ARM_ERRATA_430973 is not set
+# CONFIG_ARM_ERRATA_643719 is not set
+# CONFIG_ARM_ERRATA_720789 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_ARM_ERRATA_775420 is not set
+# CONFIG_ARM_ERRATA_798181 is not set
+# CONFIG_ARM_ERRATA_773022 is not set
+
+#
+# Bus support
+#
+CONFIG_ARM_AMBA=y
+# CONFIG_PCI is not set
+# 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_DISABLE_CPU_SCHED_DOMAIN_BALANCE is not set
+CONFIG_HAVE_ARM_SCU=y
+CONFIG_HAVE_ARM_ARCH_TIMER=y
+# CONFIG_MCPM is not set
+# CONFIG_BIG_LITTLE is not set
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_NR_CPUS=4
+CONFIG_HOTPLUG_CPU=y
+# CONFIG_ARM_PSCI is not set
+CONFIG_ARCH_NR_GPIO=0
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_HZ_FIXED=0
+CONFIG_HZ_100=y
+# CONFIG_HZ_200 is not set
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_500 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=100
+# CONFIG_SCHED_HRTICK is not set
+# CONFIG_THUMB2_KERNEL is not set
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+CONFIG_HAVE_ARCH_PFN_VALID=y
+CONFIG_HIGHMEM=y
+# CONFIG_HIGHPTE is not set
+CONFIG_ARCH_WANT_GENERAL_HUGETLB=y
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_HAVE_MEMBLOCK=y
+CONFIG_NO_BOOTMEM=y
+# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_COMPACTION=y
+CONFIG_MIGRATION=y
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_BOUNCE=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+# CONFIG_CLEANCACHE is not set
+# CONFIG_CMA is not set
+# CONFIG_ZPOOL is not set
+# CONFIG_ZBUD is not set
+# CONFIG_ZSMALLOC 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_SWIOTLB=y
+CONFIG_IOMMU_HELPER=y
+# CONFIG_XEN is not set
+# CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART is not set
+
+#
+# Boot options
+#
+CONFIG_USE_OF=y
+CONFIG_ATAGS=y
+# CONFIG_DEPRECATED_PARAM_STRUCT is not set
+# CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE is not set
+CONFIG_ZBOOT_ROM_TEXT=0
+CONFIG_ZBOOT_ROM_BSS=0
+CONFIG_ARM_APPENDED_DTB=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_KEXEC is not set
+# CONFIG_CRASH_DUMP is not set
+CONFIG_AUTO_ZRELADDR=y
+
+#
+# CPU Power Management
+#
+
+#
+# CPU Frequency scaling
+#
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_STAT=y
+# CONFIG_CPU_FREQ_STAT_DETAILS is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_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_DEFAULT_GOV_INTERACTIVE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
+# CONFIG_CPU_FREQ_GOV_USERSPACE is not set
+# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_GOV_INTERACTIVE is not set
+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+CONFIG_CPUFREQ_DT=y
+
+#
+# ARM CPU frequency scaling drivers
+#
+# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set
+
+#
+# CPU Idle
+#
+# CONFIG_CPU_IDLE is not set
+# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+# CONFIG_FPE_NWFPE is not set
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_VFP=y
+CONFIG_VFPv3=y
+CONFIG_NEON=y
+CONFIG_KERNEL_MODE_NEON=y
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_BINFMT_SCRIPT=y
+# CONFIG_HAVE_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+CONFIG_COREDUMP=y
+
+#
+# Power management options
+#
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+CONFIG_WAKELOCK=y
+# CONFIG_HISI_SNAPSHOT_BOOT is not set
+CONFIG_PM_SLEEP=y
+CONFIG_PM_SLEEP_SMP=y
+# CONFIG_PM_AUTOSLEEP is not set
+# CONFIG_PM_WAKELOCKS is not set
+# CONFIG_PM_RUNTIME is not set
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+# CONFIG_APM_EMULATION is not set
+CONFIG_PM_OPP=y
+CONFIG_PM_CLK=y
+# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set
+CONFIG_CPU_PM=y
+# CONFIG_SUSPEND_TIME is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_ARM_CPU_SUSPEND=y
+CONFIG_ARCH_HIBERNATION_POSSIBLE=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=y
+# 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_NET_IP_TUNNEL=m
+# CONFIG_IP_MROUTE is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_NET_UDP_TUNNEL is not set
+# CONFIG_NET_FOU is not set
+# CONFIG_GENEVE 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 is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+CONFIG_INET_LRO=y
+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=y
+# 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_VTI 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_ANDROID_PARANOID_NETWORK is not set
+CONFIG_NET_ACTIVITY_STATS=y
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NET_PTP_CLASSIFY 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_NF_TABLES is not set
+# CONFIG_NETFILTER_XTABLES is not set
+# CONFIG_IP_SET is not set
+# CONFIG_IP_VS is not set
+
+#
+# IP: Netfilter Configuration
+#
+# CONFIG_NF_DEFRAG_IPV4 is not set
+# CONFIG_NF_LOG_ARP is not set
+# CONFIG_NF_LOG_IPV4 is not set
+# CONFIG_NF_REJECT_IPV4 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_NF_REJECT_IPV6 is not set
+# CONFIG_NF_LOG_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_HAVE_NET_DSA=y
+# 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_PHONET is not set
+# CONFIG_6LOWPAN 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_VSOCKETS is not set
+# CONFIG_NETLINK_MMAP is not set
+# CONFIG_NETLINK_DIAG is not set
+# CONFIG_NET_MPLS_GSO is not set
+# CONFIG_HSR is not set
+CONFIG_RPS=y
+CONFIG_RFS_ACCEL=y
+CONFIG_XPS=y
+# CONFIG_CGROUP_NET_PRIO is not set
+# CONFIG_CGROUP_NET_CLASSID is not set
+CONFIG_NET_RX_BUSY_POLL=y
+CONFIG_BQL=y
+# CONFIG_BPF_JIT is not set
+CONFIG_NET_FLOW_LIMIT=y
+
+#
+# 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 is not set
+# 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 is not set
+CONFIG_DEVTMPFS=y
+# CONFIG_DEVTMPFS_MOUNT is not set
+CONFIG_STANDALONE=y
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_FW_LOADER_USER_HELPER_FALLBACK is not set
+CONFIG_ALLOW_DEV_COREDUMP=y
+# 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_HAVE_CPU_AUTOPROBE is not set
+CONFIG_REGMAP=y
+CONFIG_REGMAP_MMIO=y
+# CONFIG_DMA_SHARED_BUFFER is not set
+
+#
+# Bus devices
+#
+# CONFIG_BRCMSTB_GISB_ARB is not set
+# CONFIG_ARM_CCI is not set
+# CONFIG_VEXPRESS_CONFIG 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=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_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_HIFMC=y
+CONFIG_HIFMC_SPI_NAND=y
+# CONFIG_HIFMC_NAND is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SST25L is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+CONFIG_MTD_BLOCK2MTD=y
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOCG3 is not set
+CONFIG_MTD_NAND_IDS=y
+CONFIG_MTD_NAND_ECC=y
+# CONFIG_MTD_NAND_ECC_SMC is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_ECC_BCH is not set
+# CONFIG_MTD_SM_COMMON is not set
+# CONFIG_MTD_NAND_DENALI is not set
+# CONFIG_MTD_NAND_OMAP_BCH_BUILD is not set
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_DOCG4 is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_HISI_NAND_FS_MAY_NO_YAFFS2 is not set
+# CONFIG_HISI_NAND_ECC_STATUS_REPORT is not set
+# CONFIG_MTD_NAND_HINFC610 is not set
+# CONFIG_HIFMC100_NAND is not set
+CONFIG_HIFMC100_SPI_NAND=y
+CONFIG_SPI_NAND_MAX_CHIP_NUM=1
+# CONFIG_HIFMC100_HARDWARE_PAGESIZE_ECC is not set
+CONFIG_HIFMC100_AUTO_PAGESIZE_ECC=y
+# CONFIG_HIFMC100_PAGESIZE_AUTO_ECC_NONE is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR & LPDDR2 PCM memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+# CONFIG_MTD_LPDDR2_NVM is not set
+CONFIG_MTD_SPI_NOR=y
+# CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set
+CONFIG_SPI_HISI_SFC=y
+CONFIG_CLOSE_SPI_8PIN_4IO=y
+CONFIG_HISI_SPI_BLOCK_PROTECT=y
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_WL_THRESHOLD=4096
+CONFIG_MTD_UBI_BEB_LIMIT=20
+# CONFIG_MTD_UBI_FASTMAP is not set
+# CONFIG_MTD_UBI_GLUEBI is not set
+# CONFIG_MTD_UBI_BLOCK is not set
+CONFIG_DTC=y
+CONFIG_OF=y
+
+#
+# Device Tree and Open Firmware support
+#
+# 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_NET=y
+CONFIG_OF_MDIO=y
+CONFIG_OF_MTD=y
+CONFIG_OF_RESERVED_MEM=y
+CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_NULL_BLK is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP 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=65536
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH 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_DUMMY_IRQ 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_UID_STAT is not set
+# CONFIG_BMP085_I2C is not set
+# CONFIG_BMP085_SPI is not set
+# CONFIG_USB_SWITCH_FSA9480 is not set
+# CONFIG_LATTICE_ECP3_CONFIG is not set
+# CONFIG_SRAM is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_AT24 is not set
+# CONFIG_EEPROM_AT25 is not set
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_EEPROM_93XX46 is not set
+
+#
+# Texas Instruments shared transport line discipline
+#
+# 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
+
+#
+# Intel MIC Bus Driver
+#
+
+#
+# Intel MIC Host Driver
+#
+
+#
+# Intel MIC Card Driver
+#
+# CONFIG_ECHO is not set
+# CONFIG_CXL_BASE is not set
+
+#
+# hisi 'himm/himd.l/himc'support
+#
+# CONFIG_HISI_REG 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_NETLINK is not set
+# CONFIG_SCSI_MQ_DEFAULT is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+# CONFIG_SCSI_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 is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
+CONFIG_HI_SATA=y
+CONFIG_HI_SATA_IOBASE=0x11010000
+CONFIG_HI_SATA_FBS=1
+CONFIG_HI_SATA_NCQ=1
+CONFIG_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
+CONFIG_ATA_VERBOSE_ERROR=y
+CONFIG_SATA_PMP=y
+
+#
+# Controllers with non-SFF native interface
+#
+CONFIG_SATA_AHCI_PLATFORM=y
+# CONFIG_ATA_SFF is not set
+# CONFIG_MD 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_NET_TEAM is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_VXLAN is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_NLMON is not set
+
+#
+# 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_NET_DSA_MV88E6171 is not set
+# CONFIG_NET_DSA_BCM_SF2 is not set
+CONFIG_ETHERNET=y
+# CONFIG_ALTERA_TSE is not set
+# CONFIG_NET_XGENE is not set
+# CONFIG_NET_VENDOR_ARC is not set
+# CONFIG_NET_CADENCE is not set
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_CIRRUS is not set
+# CONFIG_DM9000 is not set
+# CONFIG_DNET is not set
+# CONFIG_NET_VENDOR_FARADAY is not set
+CONFIG_NET_VENDOR_HISILICON=y
+# CONFIG_HIX5HD2_GMAC is not set
+# CONFIG_HISI_FEMAC is not set
+CONFIG_HIETH_GMAC=y
+CONFIG_HIGMAC_DESC_4WORD=y
+CONFIG_HIGMAC_RXCSUM=y
+CONFIG_RX_FLOW_CTRL_SUPPORT=y
+CONFIG_TX_FLOW_CTRL_SUPPORT=y
+CONFIG_TX_FLOW_CTRL_PAUSE_TIME=0xFFFF
+CONFIG_TX_FLOW_CTRL_PAUSE_INTERVAL=0xFFFF
+CONFIG_TX_FLOW_CTRL_ACTIVE_THRESHOLD=16
+CONFIG_TX_FLOW_CTRL_DEACTIVE_THRESHOLD=32
+# CONFIG_HIETH_SWITCH_FABRIC is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_MICROCHIP is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_ETHOC is not set
+# CONFIG_NET_VENDOR_QUALCOMM is not set
+# CONFIG_NET_VENDOR_SAMSUNG is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
+# CONFIG_NET_VENDOR_VIA is not set
+# CONFIG_NET_VENDOR_WIZNET is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_AT803X_PHY is not set
+# CONFIG_AMD_PHY is not set
+# CONFIG_AMD_XGBE_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 is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_BCM7XXX_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_MMIOREG is not set
+# CONFIG_MDIO_BCM_UNIMAC is not set
+# CONFIG_MDIO_HISI_FEMAC is not set
+CONFIG_MDIO_HISI_GEMAC=y
+# CONFIG_MICREL_KS8995MA is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+CONFIG_USB_NET_DRIVERS=y
+# 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_RTL8152 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_USB_IPHETH is not set
+# CONFIG_WLAN is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+# CONFIG_WAN is not set
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+# CONFIG_INPUT_SPARSEKMAP is not set
+# CONFIG_INPUT_MATRIXKMAP is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+CONFIG_INPUT_JOYDEV=y
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+# CONFIG_INPUT_KEYRESET is not set
+# CONFIG_INPUT_KEYCOMBO 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_TCA6416 is not set
+# CONFIG_KEYBOARD_TCA8418 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 is not set
+# CONFIG_KEYBOARD_CAP1106 is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+CONFIG_MOUSE_PS2_ALPS=y
+CONFIG_MOUSE_PS2_LOGIPS2PP=y
+CONFIG_MOUSE_PS2_SYNAPTICS=y
+CONFIG_MOUSE_PS2_CYPRESS=y
+CONFIG_MOUSE_PS2_TRACKPOINT=y
+# CONFIG_MOUSE_PS2_ELANTECH is not set
+# CONFIG_MOUSE_PS2_SENTELIC is not set
+# CONFIG_MOUSE_PS2_TOUCHKIT is not set
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_APPLETOUCH is not set
+# CONFIG_MOUSE_BCM5974 is not set
+# CONFIG_MOUSE_CYAPA is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_MOUSE_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 is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_AMBAKMI is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_SERIO_ALTERA_PS2 is not set
+# CONFIG_SERIO_PS2MULT is not set
+# CONFIG_SERIO_ARC_PS2 is not set
+# CONFIG_SERIO_APBPS2 is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_TTY=y
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_VT_CONSOLE_SLEEP=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES 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_DEVMEM=y
+# CONFIG_DEVKMEM is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_EARLYCON=y
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_AMBA_PL010 is not set
+CONFIG_SERIAL_AMBA_PL011=y
+CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
+# CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST is not set
+# 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_SC16IS7XX is not set
+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
+# CONFIG_SERIAL_ALTERA_UART is not set
+# CONFIG_SERIAL_XILINX_PS_UART is not set
+# CONFIG_SERIAL_ARC is not set
+# CONFIG_SERIAL_FSL_LPUART is not set
+# CONFIG_SERIAL_ST_ASC is not set
+# CONFIG_HVC_DCC is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_DCC_TTY is not set
+# CONFIG_XILLYBUS is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_MUX=y
+
+#
+# Multiplexer I2C Chip support
+#
+# CONFIG_I2C_MUX_PCA9541 is not set
+# CONFIG_I2C_MUX_PINCTRL is not set
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_DESIGNWARE_PLATFORM is not set
+# CONFIG_I2C_HIBVT is not set
+# CONFIG_I2C_HISI_V110 is not set
+# CONFIG_I2C_NOMADIK 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_RK3X 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_ROBOTFUZZ_OSIF is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+CONFIG_HI_I2C=y
+CONFIG_HI_I2C0_IO_BASE=0x120c0000
+CONFIG_HI_I2C0_IO_SIZE=0x1000
+CONFIG_HI_I2C_RETRIES=0x1
+CONFIG_HI_I2C_TX_FIFO=0x8
+CONFIG_HI_I2C_RX_FIFO=0x8
+CONFIG_HI_I2C0_CLK_LIMIT=100000
+# 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_CADENCE is not set
+# CONFIG_SPI_FSL_SPI is not set
+CONFIG_SPI_PL022=y
+# CONFIG_SPI_PXA2XX_PCI is not set
+# CONFIG_SPI_ROCKCHIP 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=y
+# CONFIG_SPI_TLE62X0 is not set
+# CONFIG_SPMI is not set
+# CONFIG_HSI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+
+#
+# PPS generators support
+#
+
+#
+# PTP clock support
+#
+# CONFIG_PTP_1588_CLOCK is not set
+
+#
+# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
+#
+CONFIG_PINCTRL=y
+
+#
+# Pin controllers
+#
+CONFIG_PINMUX=y
+CONFIG_PINCONF=y
+CONFIG_GENERIC_PINCONF=y
+# CONFIG_DEBUG_PINCTRL is not set
+CONFIG_PINCTRL_SINGLE=y
+CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
+# CONFIG_GPIOLIB is not set
+# CONFIG_W1 is not set
+CONFIG_POWER_SUPPLY=y
+# CONFIG_POWER_SUPPLY_DEBUG is not set
+# CONFIG_PDA_POWER is not set
+# CONFIG_TEST_POWER is not set
+# CONFIG_BATTERY_DS2780 is not set
+# CONFIG_BATTERY_DS2781 is not set
+# CONFIG_BATTERY_DS2782 is not set
+# CONFIG_BATTERY_SBS is not set
+# CONFIG_BATTERY_BQ27x00 is not set
+# CONFIG_BATTERY_MAX17040 is not set
+# CONFIG_BATTERY_MAX17042 is not set
+# CONFIG_CHARGER_MAX8903 is not set
+# CONFIG_CHARGER_LP8727 is not set
+# CONFIG_CHARGER_MANAGER is not set
+# CONFIG_CHARGER_BQ2415X is not set
+# CONFIG_CHARGER_SMB347 is not set
+CONFIG_POWER_RESET=y
+# CONFIG_POWER_RESET_BRCMSTB is not set
+CONFIG_POWER_RESET_HISI=y
+# CONFIG_POWER_RESET_RESTART is not set
+# CONFIG_POWER_RESET_VERSATILE is not set
+# CONFIG_POWER_RESET_SYSCON is not set
+# CONFIG_POWER_AVS is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_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=y
+# CONFIG_MFD_AS3711 is not set
+# CONFIG_MFD_AS3722 is not set
+# CONFIG_PMIC_ADP5520 is not set
+# CONFIG_MFD_BCM590XX is not set
+# CONFIG_MFD_AXP20X is not set
+# CONFIG_MFD_CROS_EC is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_MFD_DA9052_SPI is not set
+# CONFIG_MFD_DA9052_I2C is not set
+# CONFIG_MFD_DA9055 is not set
+# CONFIG_MFD_DA9063 is not set
+# CONFIG_MFD_MC13XXX_SPI is not set
+# CONFIG_MFD_MC13XXX_I2C is not set
+# CONFIG_MFD_HI6421_PMIC is not set
+CONFIG_MFD_HISI_FMC=y
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_INTEL_SOC_PMIC is not set
+# CONFIG_MFD_KEMPLD is not set
+# CONFIG_MFD_88PM800 is not set
+# CONFIG_MFD_88PM805 is not set
+# CONFIG_MFD_88PM860X is not set
+# CONFIG_MFD_MAX14577 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_MENF21BMC is not set
+# CONFIG_EZX_PCAP is not set
+# CONFIG_MFD_VIPERBOARD is not set
+# CONFIG_MFD_RETU is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_MFD_PM8921_CORE is not set
+# CONFIG_MFD_RTSX_USB is not set
+# CONFIG_MFD_RC5T583 is not set
+# CONFIG_MFD_RK808 is not set
+# CONFIG_MFD_RN5T618 is not set
+# CONFIG_MFD_SEC_CORE is not set
+# CONFIG_MFD_SI476X_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_SMSC is not set
+# CONFIG_ABX500_CORE is not set
+# CONFIG_MFD_STMPE is not set
+CONFIG_MFD_SYSCON=y
+# CONFIG_MFD_TI_AM335X_TSCADC is not set
+# CONFIG_MFD_LP3943 is not set
+# CONFIG_MFD_LP8788 is not set
+# CONFIG_MFD_PALMAS is not set
+# CONFIG_TPS6105X is not set
+# CONFIG_TPS6507X is not set
+# CONFIG_MFD_TPS65090 is not set
+# CONFIG_MFD_TPS65217 is not set
+# CONFIG_MFD_TPS65218 is not set
+# CONFIG_MFD_TPS6586X is not set
+# CONFIG_MFD_TPS80031 is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_TWL6040_CORE is not set
+# CONFIG_MFD_WL1273_CORE is not set
+# CONFIG_MFD_LM3533 is not set
+# CONFIG_MFD_TC3589X is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
+# CONFIG_MFD_ARIZONA_I2C is not set
+# CONFIG_MFD_ARIZONA_SPI is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X_I2C is not set
+# CONFIG_MFD_WM831X_SPI is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_WM8994 is not set
+CONFIG_REGULATOR=y
+# CONFIG_REGULATOR_DEBUG is not set
+# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
+# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
+# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
+# CONFIG_REGULATOR_ACT8865 is not set
+# CONFIG_REGULATOR_AD5398 is not set
+# CONFIG_REGULATOR_ANATOP is not set
+# CONFIG_REGULATOR_DA9210 is not set
+# CONFIG_REGULATOR_DA9211 is not set
+# CONFIG_REGULATOR_FAN53555 is not set
+# CONFIG_REGULATOR_ISL9305 is not set
+# CONFIG_REGULATOR_ISL6271A is not set
+# CONFIG_REGULATOR_LP3971 is not set
+# CONFIG_REGULATOR_LP3972 is not set
+# CONFIG_REGULATOR_LP872X is not set
+# CONFIG_REGULATOR_LP8755 is not set
+# CONFIG_REGULATOR_LTC3589 is not set
+# CONFIG_REGULATOR_MAX1586 is not set
+# CONFIG_REGULATOR_MAX8649 is not set
+# CONFIG_REGULATOR_MAX8660 is not set
+# CONFIG_REGULATOR_MAX8952 is not set
+# CONFIG_REGULATOR_MAX8973 is not set
+# CONFIG_REGULATOR_PFUZE100 is not set
+# CONFIG_REGULATOR_TPS51632 is not set
+# CONFIG_REGULATOR_TPS62360 is not set
+# CONFIG_REGULATOR_TPS65023 is not set
+# CONFIG_REGULATOR_TPS6507X is not set
+# CONFIG_REGULATOR_TPS6524X is not set
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+# CONFIG_IMX_IPUV3_CORE is not set
+
+#
+# Direct Rendering Manager
+#
+# CONFIG_DRM is not set
+
+#
+# Frame buffer Devices
+#
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+CONFIG_FB_CMDLINE=y
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# 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_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_ARMCLCD is not set
+# CONFIG_FB_OPENCORES is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_SMSCUFX is not set
+# CONFIG_FB_UDL is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_BROADSHEET is not set
+# CONFIG_FB_AUO_K190X is not set
+# CONFIG_FB_SIMPLE is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+# CONFIG_VGASTATE is not set
+
+#
+# Console display driver support
+#
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE is not set
+# CONFIG_LOGO is not set
+# CONFIG_SOUND is not set
+
+#
+# HID support
+#
+CONFIG_HID=y
+# CONFIG_HID_BATTERY_STRENGTH is not set
+# CONFIG_HIDRAW is not set
+# CONFIG_UHID is not set
+CONFIG_HID_GENERIC=y
+
+#
+# Special HID drivers
+#
+CONFIG_HID_A4TECH=y
+# CONFIG_HID_ACRUX is not set
+CONFIG_HID_APPLE=y
+# CONFIG_HID_APPLEIR is not set
+# CONFIG_HID_AUREAL is not set
+CONFIG_HID_BELKIN=y
+CONFIG_HID_CHERRY=y
+CONFIG_HID_CHICONY=y
+CONFIG_HID_CYPRESS=y
+# CONFIG_HID_DRAGONRISE is not set
+# CONFIG_HID_EMS_FF is not set
+# CONFIG_HID_ELECOM is not set
+# CONFIG_HID_ELO is not set
+CONFIG_HID_EZKEY=y
+# CONFIG_HID_HOLTEK is not set
+# CONFIG_HID_HUION 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_ICADE is not set
+# CONFIG_HID_TWINHAN is not set
+CONFIG_HID_KENSINGTON=y
+# CONFIG_HID_LCPOWER is not set
+# CONFIG_HID_LENOVO is not set
+CONFIG_HID_LOGITECH=y
+# CONFIG_HID_LOGITECH_HIDPP is not set
+# CONFIG_LOGITECH_FF is not set
+# CONFIG_LOGIRUMBLEPAD2_FF is not set
+# CONFIG_LOGIG940_FF is not set
+# CONFIG_LOGIWHEELS_FF is not set
+# CONFIG_HID_MAGICMOUSE is not set
+CONFIG_HID_MICROSOFT=y
+CONFIG_HID_MONTEREY=y
+# 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_PENMOUNT is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_PICOLCD is not set
+# CONFIG_HID_PRIMAX is not set
+# CONFIG_HID_ROCCAT is not set
+# CONFIG_HID_SAITEK is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SPEEDLINK is not set
+# CONFIG_HID_STEELSERIES is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_HID_RMI 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_XINMO is not set
+# CONFIG_HID_ZEROPLUS is not set
+# CONFIG_HID_ZYDACRON is not set
+# CONFIG_HID_SENSOR_HUB is not set
+
+#
+# USB HID support
+#
+CONFIG_USB_HID=y
+# CONFIG_HID_PID is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# I2C HID support
+#
+# CONFIG_I2C_HID is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_COMMON=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB=y
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEFAULT_PERSIST=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_FSM is not set
+# CONFIG_USB_MON is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_XHCI_HCD is not set
+CONFIG_USB_EHCI_HCD=y
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+CONFIG_USB_EHCI_TT_NEWSCHED=y
+CONFIG_USB_EHCI_HCD_PLATFORM=y
+# 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_FUSBH200_HCD is not set
+# CONFIG_USB_FOTG210_HCD is not set
+# CONFIG_USB_MAX3421_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_HCD_PLATFORM=y
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_HCD_TEST_MODE is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+
+#
+# also be needed; see USB_STORAGE Help for more info
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_REALTEK is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_STORAGE_ENE_UB6250 is not set
+# CONFIG_USB_UAS is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USBIP_CORE is not set
+# CONFIG_USB_MUSB_HDRC is not set
+# CONFIG_USB_DWC3 is not set
+# CONFIG_USB_DWC2 is not set
+# CONFIG_USB_CHIPIDEA is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_EHSET_TEST_FIXTURE is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_YUREX is not set
+# CONFIG_USB_EZUSB_FX2 is not set
+# CONFIG_USB_HSIC_USB3503 is not set
+# CONFIG_USB_LINK_LAYER_TEST is not set
+
+#
+# USB Physical Layer drivers
+#
+# CONFIG_USB_PHY is not set
+# CONFIG_USB_OTG_WAKELOCK is not set
+# CONFIG_NOP_USB_XCEIV is not set
+# CONFIG_AM335X_PHY_USB is not set
+# CONFIG_USB_ISP1301 is not set
+# CONFIG_USB_ULPI is not set
+# CONFIG_USB_GADGET is not set
+# CONFIG_UWB is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_SWITCH is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_EDAC is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_SYSTOHC=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_DS3232 is not set
+# CONFIG_RTC_DRV_HYM8563 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_ISL12057 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF2127 is not set
+# CONFIG_RTC_DRV_PCF8523 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF85063 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_DS1343 is not set
+# CONFIG_RTC_DRV_DS1347 is not set
+# CONFIG_RTC_DRV_DS1390 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_R9701 is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_DS3234 is not set
+# CONFIG_RTC_DRV_PCF2123 is not set
+# CONFIG_RTC_DRV_RX4581 is not set
+# CONFIG_RTC_DRV_MCP795 is not set
+
+#
+# Platform RTC drivers
+#
+CONFIG_RTC_DRV_HIBVT=y
+# 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_DS2404 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
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_RTC_DRV_PL030 is not set
+# CONFIG_RTC_DRV_PL031 is not set
+# CONFIG_RTC_DRV_SNVS is not set
+# CONFIG_RTC_DRV_XGENE is not set
+
+#
+# HID Sensor RTC drivers
+#
+# CONFIG_RTC_DRV_HID_SENSOR_TIME is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+# CONFIG_VIRT_DRIVERS is not set
+
+#
+# Virtio drivers
+#
+# CONFIG_VIRTIO_MMIO is not set
+
+#
+# Microsoft Hyper-V guest support
+#
+# CONFIG_STAGING is not set
+
+#
+# SOC (System On Chip) specific Drivers
+#
+# CONFIG_SOC_TI is not set
+CONFIG_CLKDEV_LOOKUP=y
+CONFIG_HAVE_CLK_PREPARE=y
+CONFIG_COMMON_CLK=y
+
+#
+# Common Clock Framework
+#
+# CONFIG_COMMON_CLK_SI5351 is not set
+# CONFIG_COMMON_CLK_SI570 is not set
+# CONFIG_COMMON_CLK_PXA is not set
+# CONFIG_COMMON_CLK_QCOM is not set
+
+#
+# Hardware Spinlock drivers
+#
+
+#
+# Clock Source drivers
+#
+CONFIG_CLKSRC_OF=y
+CONFIG_CLKSRC_MMIO=y
+CONFIG_ARM_ARCH_TIMER=y
+CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y
+# CONFIG_ARM_ARCH_TIMER_VCT_ACCESS is not set
+# CONFIG_ATMEL_PIT is not set
+# CONFIG_SH_TIMER_CMT is not set
+# CONFIG_SH_TIMER_MTU2 is not set
+# CONFIG_SH_TIMER_TMU is not set
+# CONFIG_EM_TIMER_STI is not set
+# CONFIG_CLKSRC_VERSATILE is not set
+# CONFIG_MAILBOX is not set
+# CONFIG_IOMMU_SUPPORT is not set
+
+#
+# Remoteproc drivers
+#
+# CONFIG_STE_MODEM_RPROC is not set
+
+#
+# Rpmsg drivers
+#
+
+#
+# SOC (System On Chip) specific Drivers
+#
+# 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
+CONFIG_IRQCHIP=y
+CONFIG_ARM_GIC=y
+# CONFIG_IPACK_BUS is not set
+CONFIG_ARCH_HAS_RESET_CONTROLLER=y
+CONFIG_RESET_CONTROLLER=y
+# CONFIG_FMC is not set
+
+#
+# PHY Subsystem
+#
+CONFIG_GENERIC_PHY=y
+# CONFIG_BCM_KONA_USB2_PHY is not set
+CONFIG_PHY_HISI_INNO_USB2=y
+CONFIG_HI_NANO_PHY_SATA=y
+CONFIG_HI_SATA_PORTS=2
+CONFIG_HI_SATA_MODE=1
+# CONFIG_POWERCAP is not set
+# CONFIG_MCB is not set
+CONFIG_HI_DMAC=y
+CONFIG_HI_DMAC_CHANNEL_NUM=4
+
+#
+# Hisilicon driver support
+#
+
+#
+# File systems
+#
+CONFIG_DCACHE_WORD_ACCESS=y
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_USE_FOR_EXT23=y
+# CONFIG_EXT4_FS_POSIX_ACL is not set
+# CONFIG_EXT4_FS_SECURITY is not set
+# CONFIG_EXT4_DEBUG is not set
+CONFIG_JBD2=y
+# CONFIG_JBD2_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FS_POSIX_ACL=y
+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 is not set
+# CONFIG_FUSE_FS is not set
+# CONFIG_OVERLAY_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS 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_KERNFS=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=m
+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_YAFFS_FS=y
+CONFIG_YAFFS_YAFFS1=y
+# CONFIG_YAFFS_9BYTE_TAGS is not set
+# CONFIG_YAFFS_DOES_ECC is not set
+CONFIG_YAFFS_YAFFS2=y
+CONFIG_YAFFS_AUTO_YAFFS2=y
+# CONFIG_YAFFS_DISABLE_TAGS_ECC is not set
+# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
+# CONFIG_YAFFS_EMPTY_LOST_AND_FOUND is not set
+# CONFIG_YAFFS_DISABLE_BLOCK_REFRESHING is not set
+# CONFIG_YAFFS_DISABLE_BACKGROUND is not set
+# CONFIG_YAFFS_DISABLE_BAD_BLOCK_MARKING is not set
+CONFIG_YAFFS_XATTR=y
+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 is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN 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 is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V2=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_SWAP is not set
+# CONFIG_ROOT_NFS is not set
+# CONFIG_NFSD is not set
+CONFIG_GRACE_PERIOD=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_ACL_SUPPORT=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 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=y
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+
+#
+# printk and dmesg options
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4
+# CONFIG_BOOT_PRINTK_DELAY is not set
+
+#
+# Compile-time checks and compiler options
+#
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_FRAME_WARN=1024
+# CONFIG_STRIP_ASM_SYMS is not set
+# CONFIG_READABLE_ASM is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_SECTION_MISMATCH is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
+# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_DEBUG_KERNEL=y
+
+#
+# Memory Debugging
+#
+# CONFIG_DEBUG_PAGEALLOC is not set
+# 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_STACK_USAGE is not set
+# CONFIG_DEBUG_VM is not set
+CONFIG_DEBUG_MEMORY_INIT=y
+# CONFIG_DEBUG_PER_CPU_MAPS is not set
+# CONFIG_DEBUG_HIGHMEM is not set
+# CONFIG_DEBUG_SHIRQ is not set
+
+#
+# Debug Lockups and Hangs
+#
+# CONFIG_LOCKUP_DETECTOR is not set
+# CONFIG_DETECT_HUNG_TASK is not set
+# CONFIG_PANIC_ON_OOPS is not set
+CONFIG_PANIC_ON_OOPS_VALUE=0
+CONFIG_PANIC_TIMEOUT=0
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_SCHED_STACK_END_CHECK is not set
+# CONFIG_TIMER_STATS is not set
+
+#
+# Lock Debugging (spinlocks, mutexes, etc...)
+#
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_ATOMIC_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_LOCK_TORTURE_TEST is not set
+CONFIG_STACKTRACE=y
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_PI_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
+
+#
+# RCU Debugging
+#
+# CONFIG_SPARSE_RCU_POINTER is not set
+# CONFIG_TORTURE_TEST 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_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_NOTIFIER_ERROR_INJECTION is not set
+# CONFIG_FAULT_INJECTION 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 is not set
+
+#
+# Runtime Testing
+#
+# CONFIG_TEST_LIST_SORT is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_RBTREE_TEST is not set
+# CONFIG_INTERVAL_TREE_TEST is not set
+# CONFIG_PERCPU_TEST is not set
+# CONFIG_ATOMIC64_SELFTEST is not set
+# CONFIG_TEST_STRING_HELPERS is not set
+# CONFIG_TEST_KSTRTOX is not set
+# CONFIG_TEST_RHASHTABLE is not set
+# CONFIG_DMA_API_DEBUG is not set
+# CONFIG_TEST_LKM is not set
+# CONFIG_TEST_USER_COPY is not set
+# CONFIG_TEST_BPF is not set
+# CONFIG_TEST_FIRMWARE is not set
+# CONFIG_TEST_UDELAY is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+# CONFIG_ARM_PTDUMP is not set
+CONFIG_STRICT_DEVMEM=y
+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_DEBUG_UART_PL01X is not set
+# CONFIG_DEBUG_UART_8250 is not set
+# CONFIG_DEBUG_UART_BCM63XX is not set
+CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"
+# CONFIG_OC_ETM is not set
+# CONFIG_PID_IN_CONTEXTIDR is not set
+# CONFIG_DEBUG_SET_MODULE_RONX is not set
+# CONFIG_CORESIGHT is not set
+
+#
+# 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_HASH=y
+CONFIG_CRYPTO_HASH2=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_PCRYPT is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_MCRYPTD 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_CMAC is not set
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
+
+#
+# Digest
+#
+CONFIG_CRYPTO_CRC32C=y
+# CONFIG_CRYPTO_CRC32 is not set
+# CONFIG_CRYPTO_CRCT10DIF 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_SHA1_ARM_NEON is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_SHA512_ARM_NEON 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_AES_ARM_BS 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=y
+# CONFIG_CRYPTO_ZLIB is not set
+CONFIG_CRYPTO_LZO=y
+# CONFIG_CRYPTO_LZ4 is not set
+# CONFIG_CRYPTO_LZ4HC is not set
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+# CONFIG_CRYPTO_DRBG_MENU is not set
+# CONFIG_CRYPTO_USER_API_HASH is not set
+# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
+CONFIG_CRYPTO_HW=y
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_STRNCPY_FROM_USER=y
+CONFIG_GENERIC_STRNLEN_USER=y
+CONFIG_GENERIC_NET_UTILS=y
+CONFIG_GENERIC_PCI_IOMAP=y
+CONFIG_GENERIC_IO=y
+CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC16=y
+# CONFIG_CRC_T10DIF is not set
+# 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_AUDIT_ARCH_COMPAT_GENERIC is not set
+# CONFIG_RANDOM32_SELFTEST is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_LZ4_DECOMPRESS=y
+CONFIG_XZ_DEC=y
+CONFIG_XZ_DEC_X86=y
+CONFIG_XZ_DEC_POWERPC=y
+CONFIG_XZ_DEC_IA64=y
+CONFIG_XZ_DEC_ARM=y
+CONFIG_XZ_DEC_ARMTHUMB=y
+CONFIG_XZ_DEC_SPARC=y
+CONFIG_XZ_DEC_BCJ=y
+# CONFIG_XZ_DEC_TEST is not set
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_DECOMPRESS_BZIP2=y
+CONFIG_DECOMPRESS_LZMA=y
+CONFIG_DECOMPRESS_XZ=y
+CONFIG_DECOMPRESS_LZO=y
+CONFIG_DECOMPRESS_LZ4=y
+CONFIG_GENERIC_ALLOCATOR=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT_MAP=y
+CONFIG_HAS_DMA=y
+CONFIG_CPU_RMAP=y
+CONFIG_DQL=y
+CONFIG_GLOB=y
+# CONFIG_GLOB_SELFTEST is not set
+CONFIG_NLATTR=y
+CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
+# CONFIG_AVERAGE is not set
+# CONFIG_CORDIC is not set
+# CONFIG_DDR is not set
+CONFIG_LIBFDT=y
+CONFIG_ARCH_HAS_SG_CHAIN=y
+# CONFIG_VIRTUALIZATION is not set
diff --git a/br-ext-chip-hisilicon/board/hi3536cv100/kernel/overlay/include/linux/compiler-gcc7.h b/br-ext-chip-hisilicon/board/hi3536cv100/kernel/overlay/include/linux/compiler-gcc7.h
new file mode 100644
index 00000000..613f9936
--- /dev/null
+++ b/br-ext-chip-hisilicon/board/hi3536cv100/kernel/overlay/include/linux/compiler-gcc7.h
@@ -0,0 +1,65 @@
+#ifndef __LINUX_COMPILER_H
+#error "Please don't include <linux/compiler-gcc7.h> directly, include <linux/compiler.h> instead."
+#endif
+
+#define __used				__attribute__((__used__))
+#define __must_check			__attribute__((warn_unused_result))
+#define __compiler_offsetof(a, b)	__builtin_offsetof(a, b)
+
+/* Mark functions as cold. gcc will assume any path leading to a call
+   to them will be unlikely.  This means a lot of manual unlikely()s
+   are unnecessary now for any paths leading to the usual suspects
+   like BUG(), printk(), panic() etc. [but let's keep them for now for
+   older compilers]
+
+   Early snapshots of gcc 4.3 don't support this and we can't detect this
+   in the preprocessor, but we can live with this because they're unreleased.
+   Maketime probing would be overkill here.
+
+   gcc also has a __attribute__((__hot__)) to move hot functions into
+   a special section, but I don't see any sense in this right now in
+   the kernel context */
+#define __cold			__attribute__((__cold__))
+
+#define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __COUNTER__)
+
+#ifndef __CHECKER__
+# define __compiletime_warning(message) __attribute__((warning(message)))
+# define __compiletime_error(message) __attribute__((error(message)))
+#endif /* __CHECKER__ */
+
+/*
+ * Mark a position in code as unreachable.  This can be used to
+ * suppress control flow warnings after asm blocks that transfer
+ * control elsewhere.
+ *
+ * Early snapshots of gcc 4.5 don't support this and we can't detect
+ * this in the preprocessor, but we can live with this because they're
+ * unreleased.  Really, we need to have autoconf for the kernel.
+ */
+#define unreachable() __builtin_unreachable()
+
+/* Mark a function definition as prohibited from being cloned. */
+#define __noclone	__attribute__((__noclone__))
+
+/*
+ * Tell the optimizer that something else uses this function or variable.
+ */
+#define __visible __attribute__((externally_visible))
+
+/*
+ * GCC 'asm goto' miscompiles certain code sequences:
+ *
+ *   http://gcc.gnu.org/bugzilla/show_bug.cgi?id=58670
+ *
+ * Work it around via a compiler barrier quirk suggested by Jakub Jelinek.
+ *
+ * (asm goto is automatically volatile - the naming reflects this.)
+ */
+#define asm_volatile_goto(x...)	do { asm goto(x); asm (""); } while (0)
+
+#ifdef CONFIG_ARCH_USE_BUILTIN_BSWAP
+#define __HAVE_BUILTIN_BSWAP32__
+#define __HAVE_BUILTIN_BSWAP64__
+#define __HAVE_BUILTIN_BSWAP16__
+#endif /* CONFIG_ARCH_USE_BUILTIN_BSWAP */
diff --git a/br-ext-chip-hisilicon/board/hi3536cv100/kernel/patches/00_hi3536c_for_linux_v3.18.y.patch b/br-ext-chip-hisilicon/board/hi3536cv100/kernel/patches/00_hi3536c_for_linux_v3.18.y.patch
new file mode 100755
index 00000000..686771ff
--- /dev/null
+++ b/br-ext-chip-hisilicon/board/hi3536cv100/kernel/patches/00_hi3536c_for_linux_v3.18.y.patch
@@ -0,0 +1,326083 @@
+diff --git a/Documentation/ABI/testing/configfs-usb-gadget-midi b/Documentation/ABI/testing/configfs-usb-gadget-midi
+new file mode 100644
+index 0000000..6b341df
+--- /dev/null
++++ b/Documentation/ABI/testing/configfs-usb-gadget-midi
+@@ -0,0 +1,12 @@
++What:		/config/usb-gadget/gadget/functions/midi.name
++Date:		Nov 2014
++KernelVersion:	3.19
++Description:
++		The attributes:
++
++		index		- index value for the USB MIDI adapter
++		id		- ID string for the USB MIDI adapter
++		buflen		- MIDI buffer length
++		qlen		- USB read request queue length
++		in_ports	- number of MIDI input ports
++		out_ports	- number of MIDI output ports
+diff --git a/Documentation/ABI/testing/sysfs-class-dual-role-usb b/Documentation/ABI/testing/sysfs-class-dual-role-usb
+new file mode 100644
+index 0000000..a900fd7
+--- /dev/null
++++ b/Documentation/ABI/testing/sysfs-class-dual-role-usb
+@@ -0,0 +1,71 @@
++What:		/sys/class/dual_role_usb/.../
++Date:		June 2015
++Contact:	Badhri Jagan Sridharan<badhri@google.com>
++Description:
++		Provide a generic interface to monitor and change
++		the state of dual role usb ports. The name here
++		refers to the name mentioned in the
++		dual_role_phy_desc that is passed while registering
++		the dual_role_phy_intstance through
++		devm_dual_role_instance_register.
++
++What:           /sys/class/dual_role_usb/.../supported_modes
++Date:           June 2015
++Contact:        Badhri Jagan Sridharan<badhri@google.com>
++Description:
++		This is a static node, once initialized this
++		is not expected to change during runtime. "dfp"
++		refers to "downstream facing port" i.e. port can
++		only act as host. "ufp" refers to "upstream
++		facing port" i.e. port can only act as device.
++		"dfp ufp" refers to "dual role port" i.e. the port
++		can either be a host port or a device port.
++
++What:		/sys/class/dual_role_usb/.../mode
++Date:		June 2015
++Contact:	Badhri Jagan Sridharan<badhri@google.com>
++Description:
++		The mode node refers to the current mode in which the
++		port is operating. "dfp" for host ports. "ufp" for device
++		ports and "none" when cable is not connected.
++
++		On devices where the USB mode is software-controllable,
++		userspace can change the mode by writing "dfp" or "ufp".
++		On devices where the USB mode is fixed in hardware,
++		this attribute is read-only.
++
++What:		/sys/class/dual_role_usb/.../power_role
++Date:		June 2015
++Contact:	Badhri Jagan Sridharan<badhri@google.com>
++Description:
++		The power_role node mentions whether the port
++		is "sink"ing or "source"ing power. "none" if
++		they are not connected.
++
++		On devices implementing USB Power Delivery,
++		userspace can control the power role by writing "sink" or
++		"source". On devices without USB-PD, this attribute is
++		read-only.
++
++What:		/sys/class/dual_role_usb/.../data_role
++Date:		June 2015
++Contact:	Badhri Jagan Sridharan<badhri@google.com>
++Description:
++		The data_role node mentions whether the port
++		is acting as "host" or "device" for USB data connection.
++		"none" if there is no active data link.
++
++		On devices implementing USB Power Delivery, userspace
++		can control the data role by writing "host" or "device".
++		On devices without USB-PD, this attribute is read-only
++
++What:		/sys/class/dual_role_usb/.../powers_vconn
++Date:		June 2015
++Contact:	Badhri Jagan Sridharan<badhri@google.com>
++Description:
++		The powers_vconn node mentions whether the port
++		is supplying power for VCONN pin.
++
++		On devices with software control of VCONN,
++		userspace can disable the power supply to VCONN by writing "n",
++		or enable the power supply by writing "y".
+diff --git a/Documentation/ABI/testing/sysfs-kernel-wakeup_reasons b/Documentation/ABI/testing/sysfs-kernel-wakeup_reasons
+new file mode 100644
+index 0000000..acb19b9
+--- /dev/null
++++ b/Documentation/ABI/testing/sysfs-kernel-wakeup_reasons
+@@ -0,0 +1,16 @@
++What:		/sys/kernel/wakeup_reasons/last_resume_reason
++Date:		February 2014
++Contact:	Ruchi Kandoi <kandoiruchi@google.com>
++Description:
++		The /sys/kernel/wakeup_reasons/last_resume_reason is
++		used to report wakeup reasons after system exited suspend.
++
++What:		/sys/kernel/wakeup_reasons/last_suspend_time
++Date:		March 2015
++Contact:	jinqian <jinqian@google.com>
++Description:
++		The /sys/kernel/wakeup_reasons/last_suspend_time is
++		used to report time spent in last suspend cycle. It contains
++		two numbers (in seconds) separated by space. First number is
++		the time spent in suspend and resume processes. Second number
++		is the time spent in sleep state.
+\ No newline at end of file
+diff --git a/Documentation/android.txt b/Documentation/android.txt
+new file mode 100644
+index 0000000..0f40a78
+--- /dev/null
++++ b/Documentation/android.txt
+@@ -0,0 +1,121 @@
++				=============
++				A N D R O I D
++				=============
++
++Copyright (C) 2009 Google, Inc.
++Written by Mike Chan <mike@android.com>
++
++CONTENTS:
++---------
++
++1. Android
++  1.1 Required enabled config options
++  1.2 Required disabled config options
++  1.3 Recommended enabled config options
++2. Contact
++
++
++1. Android
++==========
++
++Android (www.android.com) is an open source operating system for mobile devices.
++This document describes configurations needed to run the Android framework on
++top of the Linux kernel.
++
++To see a working defconfig look at msm_defconfig or goldfish_defconfig
++which can be found at http://android.git.kernel.org in kernel/common.git
++and kernel/msm.git
++
++
++1.1 Required enabled config options
++-----------------------------------
++After building a standard defconfig, ensure that these options are enabled in
++your .config or defconfig if they are not already. Based off the msm_defconfig.
++You should keep the rest of the default options enabled in the defconfig
++unless you know what you are doing.
++
++ANDROID_PARANOID_NETWORK
++ASHMEM
++CONFIG_FB_MODE_HELPERS
++CONFIG_FONT_8x16
++CONFIG_FONT_8x8
++CONFIG_YAFFS_SHORT_NAMES_IN_RAM
++DAB
++EARLYSUSPEND
++FB
++FB_CFB_COPYAREA
++FB_CFB_FILLRECT
++FB_CFB_IMAGEBLIT
++FB_DEFERRED_IO
++FB_TILEBLITTING
++HIGH_RES_TIMERS
++INOTIFY
++INOTIFY_USER
++INPUT_EVDEV
++INPUT_GPIO
++INPUT_MISC
++LEDS_CLASS
++LEDS_GPIO
++LOCK_KERNEL
++LkOGGER
++LOW_MEMORY_KILLER
++MISC_DEVICES
++NEW_LEDS
++NO_HZ
++POWER_SUPPLY
++PREEMPT
++RAMFS
++RTC_CLASS
++RTC_LIB
++SWITCH
++SWITCH_GPIO
++TMPFS
++UID_STAT
++UID16
++USB_FUNCTION
++USB_FUNCTION_ADB
++USER_WAKELOCK
++VIDEO_OUTPUT_CONTROL
++WAKELOCK
++YAFFS_AUTO_YAFFS2
++YAFFS_FS
++YAFFS_YAFFS1
++YAFFS_YAFFS2
++
++
++1.2 Required disabled config options
++------------------------------------
++CONFIG_YAFFS_DISABLE_LAZY_LOAD
++DNOTIFY
++
++
++1.3 Recommended enabled config options
++------------------------------
++ANDROID_PMEM
++PSTORE_CONSOLE
++PSTORE_RAM
++SCHEDSTATS
++DEBUG_PREEMPT
++DEBUG_MUTEXES
++DEBUG_SPINLOCK_SLEEP
++DEBUG_INFO
++FRAME_POINTER
++CPU_FREQ
++CPU_FREQ_TABLE
++CPU_FREQ_DEFAULT_GOV_ONDEMAND
++CPU_FREQ_GOV_ONDEMAND
++CRC_CCITT
++EMBEDDED
++INPUT_TOUCHSCREEN
++I2C
++I2C_BOARDINFO
++LOG_BUF_SHIFT=17
++SERIAL_CORE
++SERIAL_CORE_CONSOLE
++
++
++2. Contact
++==========
++website: http://android.git.kernel.org
++
++mailing-lists: android-kernel@googlegroups.com
+diff --git a/Documentation/arm/small_task_packing.txt b/Documentation/arm/small_task_packing.txt
+new file mode 100644
+index 0000000..613f2aa
+--- /dev/null
++++ b/Documentation/arm/small_task_packing.txt
+@@ -0,0 +1,135 @@
++Small Task Packing in the big.LITTLE MP Reference Patch Set
++
++What is small task packing?
++----
++Simply that the scheduler will fit as many small tasks on a single CPU
++as possible before using other CPUs. A small task is defined as one
++whose tracked load is less than 90% of a NICE_0 task. This is a change
++from the usual behavior since the scheduler will normally use an idle
++CPU for a waking task unless that task is considered cache hot.
++
++
++How is it implemented?
++----
++Since all small tasks must wake up relatively frequently, the main
++requirement for packing small tasks is to select a partly-busy CPU when
++waking rather than looking for an idle CPU. We use the tracked load of
++the CPU runqueue to determine how heavily loaded each CPU is and the
++tracked load of the task to determine if it will fit on the CPU. We
++always start with the lowest-numbered CPU in a sched domain and stop
++looking when we find a CPU with enough space for the task.
++
++Some further tweaks are necessary to suppress load balancing when the
++CPU is not fully loaded, otherwise the scheduler attempts to spread
++tasks evenly across the domain.
++
++
++How does it interact with the HMP patches?
++----
++Firstly, we only enable packing on the little domain. The intent is that
++the big domain is intended to spread tasks amongst the available CPUs
++one-task-per-CPU. The little domain however is attempting to use as
++little power as possible while servicing its tasks.
++
++Secondly, since we offload big tasks onto little CPUs in order to try
++to devote one CPU to each task, we have a threshold above which we do
++not try to pack a task and instead will select an idle CPU if possible.
++This maintains maximum forward progress for busy tasks temporarily
++demoted from big CPUs.
++
++
++Can the behaviour be tuned?
++----
++Yes, the load level of a 'full' CPU can be easily modified in the source
++and is exposed through sysfs as /sys/kernel/hmp/packing_limit to be
++changed at runtime. The presence of the packing behaviour is controlled
++by CONFIG_SCHED_HMP_LITTLE_PACKING and can be disabled at run-time
++using /sys/kernel/hmp/packing_enable.
++The definition of a small task is hard coded as 90% of NICE_0_LOAD
++and cannot be modified at run time.
++
++
++Why do I need to tune it?
++----
++The optimal configuration is likely to be different depending upon the
++design and manufacturing of your SoC.
++
++In the main, there are two system effects from enabling small task
++packing.
++
++1. CPU operating point may increase
++2. wakeup latency of tasks may be increased
++
++There are also likely to be secondary effects from loading one CPU
++rather than spreading tasks.
++
++Note that all of these system effects are dependent upon the workload
++under consideration.
++
++
++CPU Operating Point
++----
++The primary impact of loading one CPU with a number of light tasks is to
++increase the compute requirement of that CPU since it is no longer idle
++as often. Increased compute requirement causes an increase in the
++frequency of the CPU through CPUfreq.
++
++Consider this example:
++We have a system with 3 CPUs which can operate at any frequency between
++350MHz and 1GHz. The system has 6 tasks which would each produce 10%
++load at 1GHz. The scheduler has frequency-invariant load scaling
++enabled. Our DVFS governor aims for 80% utilization at the chosen
++frequency.
++
++Without task packing, these tasks will be spread out amongst all CPUs
++such that each has 2. This will produce roughly 20% system load, and
++the frequency of the package will remain at 350MHz.
++
++With task packing set to the default packing_limit, all of these tasks
++will sit on one CPU and require a package frequency of ~750MHz to reach
++80% utilization. (0.75 = 0.6 * 0.8).
++
++When a package operates on a single frequency domain, all CPUs in that
++package share frequency and voltage.
++
++Depending upon the SoC implementation there can be a significant amount
++of energy lost to leakage from idle CPUs. The decision about how
++loaded a CPU must be to be considered 'full' is therefore controllable
++through sysfs (sys/kernel/hmp/packing_limit) and directly in the code.
++
++Continuing the example, lets set packing_limit to 450 which means we
++will pack tasks until the total load of all running tasks >= 450. In
++practise, this is very similar to a 55% idle 1Ghz CPU.
++
++Now we are only able to place 4 tasks on CPU0, and two will overflow
++onto CPU1. CPU0 will have a load of 40% and CPU1 will have a load of
++20%. In order to still hit 80% utilization, CPU0 now only needs to
++operate at (0.4*0.8=0.32) 320MHz, which means that the lowest operating
++point will be selected, the same as in the non-packing case, except that
++now CPU2 is no longer needed and can be power-gated.
++
++In order to use less energy, the saving from power-gating CPU2 must be
++more than the energy spent running CPU0 for the extra cycles. This
++depends upon the SoC implementation.
++
++This is obviously a contrived example requiring all the tasks to
++be runnable at the same time, but it illustrates the point.
++
++
++Wakeup Latency
++----
++This is an unavoidable consequence of trying to pack tasks together
++rather than giving them a CPU each. If you cannot find an acceptable
++level of wakeup latency, you should turn packing off.
++
++Cyclictest is a good test application for determining the added latency
++when configuring packing.
++
++
++Why is it turned off for the VersatileExpress V2P_CA15A7 CoreTile?
++----
++Simply, this core tile only has power gating for the whole A7 package.
++When small task packing is enabled, all our low-energy use cases
++normally fit onto one A7 CPU. We therefore end up with 2 mostly-idle
++CPUs and one mostly-busy CPU. This decreases the amount of time
++available where the whole package is idle and can be turned off.
+diff --git a/Documentation/arm64/legacy_instructions.txt b/Documentation/arm64/legacy_instructions.txt
+new file mode 100644
+index 0000000..01bf3d9
+--- /dev/null
++++ b/Documentation/arm64/legacy_instructions.txt
+@@ -0,0 +1,57 @@
++The arm64 port of the Linux kernel provides infrastructure to support
++emulation of instructions which have been deprecated, or obsoleted in
++the architecture. The infrastructure code uses undefined instruction
++hooks to support emulation. Where available it also allows turning on
++the instruction execution in hardware.
++
++The emulation mode can be controlled by writing to sysctl nodes
++(/proc/sys/abi). The following explains the different execution
++behaviours and the corresponding values of the sysctl nodes -
++
++* Undef
++  Value: 0
++  Generates undefined instruction abort. Default for instructions that
++  have been obsoleted in the architecture, e.g., SWP
++
++* Emulate
++  Value: 1
++  Uses software emulation. To aid migration of software, in this mode
++  usage of emulated instruction is traced as well as rate limited
++  warnings are issued. This is the default for deprecated
++  instructions, .e.g., CP15 barriers
++
++* Hardware Execution
++  Value: 2
++  Although marked as deprecated, some implementations may support the
++  enabling/disabling of hardware support for the execution of these
++  instructions. Using hardware execution generally provides better
++  performance, but at the loss of ability to gather runtime statistics
++  about the use of the deprecated instructions.
++
++The default mode depends on the status of the instruction in the
++architecture. Deprecated instructions should default to emulation
++while obsolete instructions must be undefined by default.
++
++Note: Instruction emulation may not be possible in all cases. See
++individual instruction notes for further information.
++
++Supported legacy instructions
++-----------------------------
++* SWP{B}
++Node: /proc/sys/abi/swp
++Status: Obsolete
++Default: Undef (0)
++
++* CP15 Barriers
++Node: /proc/sys/abi/cp15_barrier
++Status: Deprecated
++Default: Emulate (1)
++
++* SETEND
++Node: /proc/sys/abi/setend
++Status: Deprecated
++Default: Emulate (1)*
++Note: All the cpus on the system must have mixed endian support at EL0
++for this feature to be enabled. If a new CPU - which doesn't support mixed
++endian - is hotplugged in after this feature has been enabled, there could
++be unexpected results in the application.
+diff --git a/Documentation/cgroups/cgroups.txt b/Documentation/cgroups/cgroups.txt
+index 10c949b..925b820 100644
+--- a/Documentation/cgroups/cgroups.txt
++++ b/Documentation/cgroups/cgroups.txt
+@@ -578,6 +578,15 @@ is completely unused; @cgrp->parent is still valid. (Note - can also
+ be called for a newly-created cgroup if an error occurs after this
+ subsystem's create() method has been called for the new cgroup).
+ 
++int allow_attach(struct cgroup *cgrp, struct cgroup_taskset *tset)
++(cgroup_mutex held by caller)
++
++Called prior to moving a task into a cgroup; if the subsystem
++returns an error, this will abort the attach operation.  Used
++to extend the permission checks - if all subsystems in a cgroup
++return 0, the attach will be allowed to proceed, even if the
++default permission check (root or same user) fails.
++
+ int can_attach(struct cgroup *cgrp, struct cgroup_taskset *tset)
+ (cgroup_mutex held by caller)
+ 
+diff --git a/Documentation/cpu-freq/governors.txt b/Documentation/cpu-freq/governors.txt
+index 77ec215..2ed766e 100644
+--- a/Documentation/cpu-freq/governors.txt
++++ b/Documentation/cpu-freq/governors.txt
+@@ -28,6 +28,7 @@ Contents:
+ 2.3  Userspace
+ 2.4  Ondemand
+ 2.5  Conservative
++2.6  Interactive
+ 
+ 3.   The Governor Interface in the CPUfreq Core
+ 
+@@ -218,6 +219,90 @@ a decision on when to decrease the frequency while running in any
+ speed. Load for frequency increase is still evaluated every
+ sampling rate.
+ 
++2.6 Interactive
++---------------
++
++The CPUfreq governor "interactive" is designed for latency-sensitive,
++interactive workloads. This governor sets the CPU speed depending on
++usage, similar to "ondemand" and "conservative" governors, but with a
++different set of configurable behaviors.
++
++The tuneable values for this governor are:
++
++target_loads: CPU load values used to adjust speed to influence the
++current CPU load toward that value.  In general, the lower the target
++load, the more often the governor will raise CPU speeds to bring load
++below the target.  The format is a single target load, optionally
++followed by pairs of CPU speeds and CPU loads to target at or above
++those speeds.  Colons can be used between the speeds and associated
++target loads for readability.  For example:
++
++   85 1000000:90 1700000:99
++
++targets CPU load 85% below speed 1GHz, 90% at or above 1GHz, until
++1.7GHz and above, at which load 99% is targeted.  If speeds are
++specified these must appear in ascending order.  Higher target load
++values are typically specified for higher speeds, that is, target load
++values also usually appear in an ascending order. The default is
++target load 90% for all speeds.
++
++min_sample_time: The minimum amount of time to spend at the current
++frequency before ramping down. Default is 80000 uS.
++
++hispeed_freq: An intermediate "hi speed" at which to initially ramp
++when CPU load hits the value specified in go_hispeed_load.  If load
++stays high for the amount of time specified in above_hispeed_delay,
++then speed may be bumped higher.  Default is the maximum speed
++allowed by the policy at governor initialization time.
++
++go_hispeed_load: The CPU load at which to ramp to hispeed_freq.
++Default is 99%.
++
++above_hispeed_delay: When speed is at or above hispeed_freq, wait for
++this long before raising speed in response to continued high load.
++The format is a single delay value, optionally followed by pairs of
++CPU speeds and the delay to use at or above those speeds.  Colons can
++be used between the speeds and associated delays for readability.  For
++example:
++
++   80000 1300000:200000 1500000:40000
++
++uses delay 80000 uS until CPU speed 1.3 GHz, at which speed delay
++200000 uS is used until speed 1.5 GHz, at which speed (and above)
++delay 40000 uS is used.  If speeds are specified these must appear in
++ascending order.  Default is 20000 uS.
++
++timer_rate: Sample rate for reevaluating CPU load when the CPU is not
++idle.  A deferrable timer is used, such that the CPU will not be woken
++from idle to service this timer until something else needs to run.
++(The maximum time to allow deferring this timer when not running at
++minimum speed is configurable via timer_slack.)  Default is 20000 uS.
++
++timer_slack: Maximum additional time to defer handling the governor
++sampling timer beyond timer_rate when running at speeds above the
++minimum.  For platforms that consume additional power at idle when
++CPUs are running at speeds greater than minimum, this places an upper
++bound on how long the timer will be deferred prior to re-evaluating
++load and dropping speed.  For example, if timer_rate is 20000uS and
++timer_slack is 10000uS then timers will be deferred for up to 30msec
++when not at lowest speed.  A value of -1 means defer timers
++indefinitely at all speeds.  Default is 80000 uS.
++
++boost: If non-zero, immediately boost speed of all CPUs to at least
++hispeed_freq until zero is written to this attribute.  If zero, allow
++CPU speeds to drop below hispeed_freq according to load as usual.
++Default is zero.
++
++boostpulse: On each write, immediately boost speed of all CPUs to
++hispeed_freq for at least the period of time specified by
++boostpulse_duration, after which speeds are allowed to drop below
++hispeed_freq according to load as usual.
++
++boostpulse_duration: Length of time to hold CPU speed at hispeed_freq
++on a write to boostpulse, before allowing speed to drop according to
++load as usual.  Default is 80000 uS.
++
++
+ 3. The Governor Interface in the CPUfreq Core
+ =============================================
+ 
+diff --git a/Documentation/device-mapper/dm-crypt.txt b/Documentation/device-mapper/dm-crypt.txt
+index c81839b..692171f 100644
+--- a/Documentation/device-mapper/dm-crypt.txt
++++ b/Documentation/device-mapper/dm-crypt.txt
+@@ -5,7 +5,7 @@ Device-Mapper's "crypt" target provides transparent encryption of block devices
+ using the kernel crypto API.
+ 
+ For a more detailed description of supported parameters see:
+-http://code.google.com/p/cryptsetup/wiki/DMCrypt
++https://gitlab.com/cryptsetup/cryptsetup/wikis/DMCrypt
+ 
+ Parameters: <cipher> <key> <iv_offset> <device path> \
+ 	      <offset> [<#opt_params> <opt_params>]
+@@ -51,7 +51,7 @@ Parameters: <cipher> <key> <iv_offset> <device path> \
+     Otherwise #opt_params is the number of following arguments.
+ 
+     Example of optional parameters section:
+-        1 allow_discards
++        3 allow_discards same_cpu_crypt submit_from_crypt_cpus
+ 
+ allow_discards
+     Block discard requests (a.k.a. TRIM) are passed through the crypt device.
+@@ -63,11 +63,24 @@ allow_discards
+     used space etc.) if the discarded blocks can be located easily on the
+     device later.
+ 
++same_cpu_crypt
++    Perform encryption using the same cpu that IO was submitted on.
++    The default is to use an unbound workqueue so that encryption work
++    is automatically balanced between available CPUs.
++
++submit_from_crypt_cpus
++    Disable offloading writes to a separate thread after encryption.
++    There are some situations where offloading write bios from the
++    encryption threads to a single thread degrades performance
++    significantly.  The default is to offload write bios to the same
++    thread because it benefits CFQ to have writes submitted using the
++    same context.
++
+ Example scripts
+ ===============
+ LUKS (Linux Unified Key Setup) is now the preferred way to set up disk
+ encryption with dm-crypt using the 'cryptsetup' utility, see
+-http://code.google.com/p/cryptsetup/
++https://gitlab.com/cryptsetup/cryptsetup
+ 
+ [[
+ #!/bin/sh
+diff --git a/Documentation/device-mapper/verity.txt b/Documentation/device-mapper/verity.txt
+index 9884681..0075f70 100644
+--- a/Documentation/device-mapper/verity.txt
++++ b/Documentation/device-mapper/verity.txt
+@@ -125,7 +125,7 @@ block boundary) are the hash blocks which are stored a depth at a time
+ 
+ The full specification of kernel parameters and on-disk metadata format
+ is available at the cryptsetup project's wiki page
+-  http://code.google.com/p/cryptsetup/wiki/DMVerity
++  https://gitlab.com/cryptsetup/cryptsetup/wikis/DMVerity
+ 
+ Status
+ ======
+@@ -142,7 +142,7 @@ Set up a device:
+ 
+ A command line tool veritysetup is available to compute or verify
+ the hash tree or activate the kernel device. This is available from
+-the cryptsetup upstream repository http://code.google.com/p/cryptsetup/
++the cryptsetup upstream repository https://gitlab.com/cryptsetup/cryptsetup/
+ (as a libcryptsetup extension).
+ 
+ Create hash on the device:
+diff --git a/Documentation/devicetree/bindings/arm/coresight.txt b/Documentation/devicetree/bindings/arm/coresight.txt
+new file mode 100644
+index 0000000..88602b7
+--- /dev/null
++++ b/Documentation/devicetree/bindings/arm/coresight.txt
+@@ -0,0 +1,199 @@
++* CoreSight Components:
++
++CoreSight components are compliant with the ARM CoreSight architecture
++specification and can be connected in various topologies to suit a particular
++SoCs tracing needs. These trace components can generally be classified as
++sinks, links and sources. Trace data produced by one or more sources flows
++through the intermediate links connecting the source to the currently selected
++sink. Each CoreSight component device should use these properties to describe
++its hardware characteristcs.
++
++* Required properties for all components *except* non-configurable replicators:
++
++	* compatible: These have to be supplemented with "arm,primecell" as
++	  drivers are using the AMBA bus interface.  Possible values include:
++		- "arm,coresight-etb10", "arm,primecell";
++		- "arm,coresight-tpiu", "arm,primecell";
++		- "arm,coresight-tmc", "arm,primecell";
++		- "arm,coresight-funnel", "arm,primecell";
++		- "arm,coresight-etm3x", "arm,primecell";
++
++	* reg: physical base address and length of the register
++	  set(s) of the component.
++
++	* clocks: the clock associated to this component.
++
++	* clock-names: the name of the clock as referenced by the code.
++	  Since we are using the AMBA framework, the name should be
++	  "apb_pclk".
++
++	* port or ports: The representation of the component's port
++	  layout using the generic DT graph presentation found in
++	  "bindings/graph.txt".
++
++* Required properties for devices that don't show up on the AMBA bus, such as
++  non-configurable replicators:
++
++	* compatible: Currently supported value is (note the absence of the
++	  AMBA markee):
++		- "arm,coresight-replicator"
++
++	* port or ports: same as above.
++
++* Optional properties for ETM/PTMs:
++
++	* arm,cp14: must be present if the system accesses ETM/PTM management
++	  registers via co-processor 14.
++
++	* cpu: the cpu phandle this ETM/PTM is affined to. When omitted the
++	  source is considered to belong to CPU0.
++
++* Optional property for TMC:
++
++	* arm,buffer-size: size of contiguous buffer space for TMC ETR
++	 (embedded trace router)
++
++
++Example:
++
++1. Sinks
++	etb@20010000 {
++		compatible = "arm,coresight-etb10", "arm,primecell";
++		reg = <0 0x20010000 0 0x1000>;
++
++		clocks = <&oscclk6a>;
++		clock-names = "apb_pclk";
++		port {
++			etb_in_port: endpoint@0 {
++				slave-mode;
++				remote-endpoint = <&replicator_out_port0>;
++			};
++		};
++	};
++
++	tpiu@20030000 {
++		compatible = "arm,coresight-tpiu", "arm,primecell";
++		reg = <0 0x20030000 0 0x1000>;
++
++		clocks = <&oscclk6a>;
++		clock-names = "apb_pclk";
++		port {
++			tpiu_in_port: endpoint@0 {
++				slave-mode;
++				remote-endpoint = <&replicator_out_port1>;
++			};
++		};
++	};
++
++2. Links
++	replicator {
++		/* non-configurable replicators don't show up on the
++		 * AMBA bus.  As such no need to add "arm,primecell".
++		 */
++		compatible = "arm,coresight-replicator";
++
++		ports {
++			#address-cells = <1>;
++			#size-cells = <0>;
++
++			/* replicator output ports */
++			port@0 {
++				reg = <0>;
++				replicator_out_port0: endpoint {
++					remote-endpoint = <&etb_in_port>;
++				};
++			};
++
++			port@1 {
++				reg = <1>;
++				replicator_out_port1: endpoint {
++					remote-endpoint = <&tpiu_in_port>;
++				};
++			};
++
++			/* replicator input port */
++			port@2 {
++				reg = <0>;
++				replicator_in_port0: endpoint {
++					slave-mode;
++					remote-endpoint = <&funnel_out_port0>;
++				};
++			};
++		};
++	};
++
++	funnel@20040000 {
++		compatible = "arm,coresight-funnel", "arm,primecell";
++		reg = <0 0x20040000 0 0x1000>;
++
++		clocks = <&oscclk6a>;
++		clock-names = "apb_pclk";
++		ports {
++			#address-cells = <1>;
++			#size-cells = <0>;
++
++			/* funnel output port */
++			port@0 {
++				reg = <0>;
++				funnel_out_port0: endpoint {
++					remote-endpoint =
++							<&replicator_in_port0>;
++				};
++			};
++
++			/* funnel input ports */
++			port@1 {
++				reg = <0>;
++				funnel_in_port0: endpoint {
++					slave-mode;
++					remote-endpoint = <&ptm0_out_port>;
++				};
++			};
++
++			port@2 {
++				reg = <1>;
++				funnel_in_port1: endpoint {
++					slave-mode;
++					remote-endpoint = <&ptm1_out_port>;
++				};
++			};
++
++			port@3 {
++				reg = <2>;
++				funnel_in_port2: endpoint {
++					slave-mode;
++					remote-endpoint = <&etm0_out_port>;
++				};
++			};
++
++		};
++	};
++
++3. Sources
++	ptm@2201c000 {
++		compatible = "arm,coresight-etm3x", "arm,primecell";
++		reg = <0 0x2201c000 0 0x1000>;
++
++		cpu = <&cpu0>;
++		clocks = <&oscclk6a>;
++		clock-names = "apb_pclk";
++		port {
++			ptm0_out_port: endpoint {
++				remote-endpoint = <&funnel_in_port0>;
++			};
++		};
++	};
++
++	ptm@2201d000 {
++		compatible = "arm,coresight-etm3x", "arm,primecell";
++		reg = <0 0x2201d000 0 0x1000>;
++
++		cpu = <&cpu1>;
++		clocks = <&oscclk6a>;
++		clock-names = "apb_pclk";
++		port {
++			ptm1_out_port: endpoint {
++				remote-endpoint = <&funnel_in_port1>;
++			};
++		};
++	};
+diff --git a/Documentation/devicetree/bindings/clock/hi3519-clock.txt b/Documentation/devicetree/bindings/clock/hi3519-clock.txt
+new file mode 100644
+index 0000000..9fea878
+--- /dev/null
++++ b/Documentation/devicetree/bindings/clock/hi3519-clock.txt
+@@ -0,0 +1,46 @@
++* Hisilicon Hi3519 Clock and Reset Generator(CRG)
++
++The Hi3519 CRG module provides clock and reset signals to various
++controllers within the SoC.
++
++This binding uses the following bindings:
++    Documentation/devicetree/bindings/clock/clock-bindings.txt
++    Documentation/devicetree/bindings/reset/reset.txt
++
++Required Properties:
++
++- compatible: should be one of the following.
++  - "hisilicon,hi3519-clock" - controller compatible with Hi3519 SoC.
++
++- reg: physical base address of the controller and length of memory mapped
++  region.
++
++- #clock-cells: should be 1.
++
++Each clock is assigned an identifier and client nodes use this identifier
++to specify the clock which they consume.
++
++All these identifier could be found in <dt-bindings/clock/hi3519-clock.h>.
++
++- #reset-cells: should be 2.
++
++A reset signal can be controlled by writing a bit register in the CRG module.
++The reset specifier consists of two cells. The first cell represents the
++register offset relative to the base address. The second cell represents the
++bit index in the register.
++
++Example: CRG nodes
++CRG: clock-reset-controller {
++	compatible = "hisilicon,hi3519-clock";
++        reg = <0x12010000 0x10000>;
++        #clock-cells = <1>;
++        #reset-cells = <2>;
++};
++
++Example: consumer nodes
++i2c0: i2c@0x12110000 {
++	compatible = "hisilicon,hi3519-i2c";
++        reg = <0x12110000 0x1000>;
++        clocks = <&CRG HI3519_I2C0_RST>;*/
++        resets = <&CRG 0xE4 0>;
++};
+diff --git a/Documentation/devicetree/bindings/i2c/i2c-hibvt.txt b/Documentation/devicetree/bindings/i2c/i2c-hibvt.txt
+new file mode 100644
+index 0000000..db3d2e2
+--- /dev/null
++++ b/Documentation/devicetree/bindings/i2c/i2c-hibvt.txt
+@@ -0,0 +1,24 @@
++Hisilicon BVT I2C master controller
++
++Required properties:
++- compatible: should be "hisilicon,hibvt-i2c" and one of the following:
++	"hisilicon,hi3516cv300-i2c"
++- reg: physical base address of the controller and length of memory mapped.
++     region.
++- interrupts: interrupt number to the cpu.
++- clocks: phandles to input clocks.
++
++Optional properties:
++- clock-frequency: Desired I2C bus frequency in Hz, otherwise defaults to 100000.
++
++Other properties:
++see Documentation/devicetree/bindings/i2c/i2c.txt.
++
++Examples:
++i2c_bus0: i2c@12110000 {
++	compatible = "hisilicon,hi3516cv300-i2c", "hisilicon,hibvt-i2c";
++	reg = <0x12110000 0x100>;
++	interrupts = <20>;
++	clocks = <&crg_ctrl HI3516CV300_APB_CLK>;
++	clock-frequency = <100000>;
++};
+diff --git a/Documentation/devicetree/bindings/net/hisilicon-femac-mdio.txt b/Documentation/devicetree/bindings/net/hisilicon-femac-mdio.txt
+new file mode 100644
+index 0000000..23a39a3
+--- /dev/null
++++ b/Documentation/devicetree/bindings/net/hisilicon-femac-mdio.txt
+@@ -0,0 +1,22 @@
++Hisilicon Fast Ethernet MDIO Controller interface
++
++Required properties:
++- compatible: should be "hisilicon,hisi-femac-mdio".
++- reg: address and length of the register set for the device.
++- clocks: A phandle to the reference clock for this device.
++
++- PHY subnode: inherits from phy binding [1]
++[1] Documentation/devicetree/bindings/net/phy.txt
++
++Example:
++mdio: mdio@10091100 {
++	compatible = "hisilicon,hisi-femac-mdio";
++	reg = <0x10091100 0x10>;
++	clocks = <&crg HI3516CV300_MDIO_CLK>;
++	#address-cells = <1>;
++	#size-cells = <0>;
++
++	phy0: phy@1 {
++		reg = <1>;
++	};
++};
+diff --git a/Documentation/devicetree/bindings/net/hisilicon-femac.txt b/Documentation/devicetree/bindings/net/hisilicon-femac.txt
+new file mode 100644
+index 0000000..d11af5e
+--- /dev/null
++++ b/Documentation/devicetree/bindings/net/hisilicon-femac.txt
+@@ -0,0 +1,39 @@
++Hisilicon Fast Ethernet MAC controller
++
++Required properties:
++- compatible: should contain one of the following version strings:
++	* "hisilicon,hisi-femac-v1"
++	* "hisilicon,hisi-femac-v2"
++	and the soc string "hisilicon,hi3516cv300-femac".
++- reg: specifies base physical address(s) and size of the device registers.
++  The first region is the MAC core register base and size.
++  The second region is the global MAC control register.
++- interrupts: should contain the MAC interrupt.
++- clocks: A phandle to the MAC main clock.
++- resets: should contain the phandle to the MAC reset signal(required) and
++	the PHY reset signal(optional).
++- reset-names: should contain the reset signal name "mac"(required)
++	and "phy"(optional).
++- mac-address: see ethernet.txt [1].
++- phy-mode: see ethernet.txt [1].
++- phy-handle: see ethernet.txt [1].
++- hisilicon,phy-reset-delays-us: triplet of delays if PHY reset signal given.
++	The 1st cell is reset pre-delay in micro seconds.
++	The 2nd cell is reset pulse in micro seconds.
++	The 3rd cell is reset post-delay in micro seconds.
++
++[1] Documentation/devicetree/bindings/net/ethernet.txt
++
++Example:
++	hisi_femac: ethernet@10090000 {
++		compatible = "hisilicon,hi3516cv300-femac","hisilicon,hisi-femac-v2";
++		reg = <0x10090000 0x1000>,<0x10091300 0x200>;
++		interrupts = <12>;
++		clocks = <&crg HI3518EV200_ETH_CLK>;
++		resets = <&crg 0xec 0>,<&crg 0xec 3>;
++		reset-names = "mac","phy";
++		mac-address = [00 00 00 00 00 00];
++		phy-mode = "mii";
++		phy-handle = <&phy0>;
++		hisilicon,phy-reset-delays-us = <10000 20000 20000>;
++	};
+diff --git a/Documentation/devicetree/bindings/net/hisilicon-gemac-mdio.txt b/Documentation/devicetree/bindings/net/hisilicon-gemac-mdio.txt
+new file mode 100644
+index 0000000..c6f8202
+--- /dev/null
++++ b/Documentation/devicetree/bindings/net/hisilicon-gemac-mdio.txt
+@@ -0,0 +1,22 @@
++Hisilicon Gigabit Ethernet MDIO Controller interface
++
++Required properties:
++- compatible: should be "hisilicon,hisi-gemac-mdio".
++- reg: address and length of the register set for the device.
++- clocks: A phandle to the reference clock for this device.
++
++- PHY subnode: inherits from phy binding [1]
++[1] Documentation/devicetree/bindings/net/phy.txt
++
++Example:
++mdio: mdio@100503c0 {
++	compatible = "hisilicon,hisi-gemac-mdio";
++	reg = <0x100503c0 0x20>;
++	clocks = <&crg HI3519V100_MDIO_CLK>;
++	#address-cells = <1>;
++	#size-cells = <0>;
++
++	phy0: phy@1 {
++		reg = <1>;
++	};
++};
+diff --git a/Documentation/devicetree/bindings/net/hisilicon-hieth.txt b/Documentation/devicetree/bindings/net/hisilicon-hieth.txt
+new file mode 100644
+index 0000000..21f8744
+--- /dev/null
++++ b/Documentation/devicetree/bindings/net/hisilicon-hieth.txt
+@@ -0,0 +1,45 @@
++Hisilicon hieth controller
++
++Required properties:
++- compatible: should be "hisilicon,hieth".
++- reg: specifies base physical address(s) and size of the device registers.
++  The region is the MAC register base and size.
++- interrupts: should contain the MAC interrupt.
++- #address-cells: must be <1>.
++- #size-cells: must be <0>.
++- phy-mode: see ethernet.txt [1].
++- phy-handle: see ethernet.txt [1].
++- mac-address: see ethernet.txt [1].
++- clocks: clock phandle and specifier pair.
++- resets: reset controller phandle and specifier pair.
++
++- PHY subnode: inherits from phy binding [2]
++
++[1] Documentation/devicetree/bindings/net/ethernet.txt
++[2] Documentation/devicetree/bindings/net/phy.txt
++
++Example:
++	hieth: ethernet@10050000 {
++		compatible = "hisilicon,hieth";
++		reg = <0x10050000 0x4000>;
++		interrupts = <12>;
++
++		clocks = <&clock HI3516CV300_ETH_CLK>;
++		clock-names = "clk";
++
++		resets = <&clock 0xcc 0>,
++				<&clock 0xcc 3>;
++		reset-names = "mac_reset",
++				"phy0_reset";
++
++		phy-handle = <&hieth_phy0>;
++
++		#address-cells = <1>;
++		#size-cells = <0>;
++
++		hieth_phy0: hieth_phy@1 {
++			reg = <1>;
++			mac-address = [00 00 00 00 00 00];
++			phy-mode = "mii";
++		};
++	};
+diff --git a/Documentation/devicetree/bindings/net/hisilicon-higmac.txt b/Documentation/devicetree/bindings/net/hisilicon-higmac.txt
+new file mode 100644
+index 0000000..ea096d2
+--- /dev/null
++++ b/Documentation/devicetree/bindings/net/hisilicon-higmac.txt
+@@ -0,0 +1,52 @@
++Hisilicon higmac controller
++
++Required properties:
++- compatible: should be "hisilicon,higmac" and one of the following:
++	- "hisilicon,higmac-v1"
++	- "hisilicon,higmac-v2"
++	- "hisilicon,higmac-v3"
++	- "hisilicon,higmac-v4"
++	- "hisilicon,higmac-v5"
++- reg: specifies base physical address(s) and size of the device registers.
++  The first region is the MAC register base and size.
++  The second region is external interface control register.
++- interrupts: should contain the MAC interrupt.
++- #address-cells: must be <1>.
++- #size-cells: must be <0>.
++- phy-mode: see ethernet.txt [1].
++- phy-handle: see ethernet.txt [1].
++- mac-address: see ethernet.txt [1].
++- clocks: clock phandle and specifier pair.
++- resets: reset controller phandle and specifier pair.
++
++- PHY subnode: inherits from phy binding [2]
++
++[1] Documentation/devicetree/bindings/net/ethernet.txt
++[2] Documentation/devicetree/bindings/net/phy.txt
++
++Example:
++	higmac: ethernet@10050000 {
++		compatible = "hisilicon,higmac";
++		reg = <0x10050000 0x1000>,<0x120100ec 0x4>;
++		interrupts = <0 25 4>;
++		#address-cells = <1>;
++		#size-cells = <0>;
++		phy-mode = "rgmii";
++		phy-handle = <&eth_phy>;
++		mac-address = [00 00 00 00 00 00];
++		clocks = <&clock HI3519_ETH_CLK>,
++				<&clock HI3519_ETH_MACIF_CLK>;
++		clock-names = "higmac_clk",
++				"macif_clk";
++
++		resets = <&clock 0xcc 0>,
++				<&clock 0xcc 2>,
++				<&clock 0xcc 7>;
++		reset-names = "port_reset",
++				"macif_reset",
++				"phy_reset";
++
++		eth_phy: ethernet-phy@1 {
++			reg = <1>;
++		};
++	};
+diff --git a/Documentation/devicetree/bindings/phy/hisi-sata-nano-phy.txt b/Documentation/devicetree/bindings/phy/hisi-sata-nano-phy.txt
+new file mode 100644
+index 0000000..f06efeb
+--- /dev/null
++++ b/Documentation/devicetree/bindings/phy/hisi-sata-nano-phy.txt
+@@ -0,0 +1,22 @@
++Hisilicon SATA NANO PHY
++-----------------------
++
++Required properties:
++- compatible: should be "hisilicon,hisi-sata-nano-phy"
++- reg: offset and length of the PHY registers
++- #phy-cells: must be 0
++Refer to phy/phy-bindings.txt for the generic PHY binding properties
++
++Optional Properties:
++- hisilicon,peripheral-syscon: phandle of syscon used to control peripheral.
++- hisilicon,power-reg: offset and bit number within peripheral-syscon,
++	register of controlling sata power supply.
++
++Example:
++	sata_phy: phy@f9900000 {
++		compatible = "hisilicon,hisi-sata-nano-phy";
++		reg = <0xf9900000 0x10000>;
++		#phy-cells = <0>;
++		hisilicon,peripheral-syscon = <&peripheral_ctrl>;
++		hisilicon,power-reg = <0x8 10>;
++	};
+diff --git a/Documentation/devicetree/bindings/phy/hisi-usb-phy.txt b/Documentation/devicetree/bindings/phy/hisi-usb-phy.txt
+new file mode 100644
+index 0000000..5d53065
+--- /dev/null
++++ b/Documentation/devicetree/bindings/phy/hisi-usb-phy.txt
+@@ -0,0 +1,15 @@
++Hisilicon hi3519 USB2 PHY
++-----------------------
++
++Required properties:
++- compatible: should be "hisilicon,hisi-usb-phy"
++- reg: offset and length of the PHY registers
++- #phy-cells: must be 0
++Refer to phy/phy-bindings.txt for the generic PHY binding properties
++
++Example:
++	usb_phy: phy {
++		compatible = "hisilicon,hisi-usb-phy";
++		reg = <0x12030000 0x10000>, <0x12010000 0x10000>;
++		#phy-cells = <0>;
++	};
+diff --git a/Documentation/devicetree/bindings/phy/hisi-usb3-phy.txt b/Documentation/devicetree/bindings/phy/hisi-usb3-phy.txt
+new file mode 100644
+index 0000000..9781fc1
+--- /dev/null
++++ b/Documentation/devicetree/bindings/phy/hisi-usb3-phy.txt
+@@ -0,0 +1,15 @@
++Hisilicon hi3519 USB3 PHY
++-----------------------
++
++Required properties:
++- compatible: should be "hisilicon,hisi-usb3-phy"
++- reg: offset and length of the PHY registers
++- #phy-cells: must be 0
++Refer to phy/phy-bindings.txt for the generic PHY binding properties
++
++Example:
++	usb3_phy: phy {
++		compatible = "hisilicon,hisi-usb3-phy";
++		reg = <0x10180000 0x10000>, <0x12010000 0x10000>;
++		#phy-cells = <0>;
++	};
+diff --git a/Documentation/devicetree/bindings/phy/phy-hisi-inno-usb2.txt b/Documentation/devicetree/bindings/phy/phy-hisi-inno-usb2.txt
+new file mode 100644
+index 0000000..59eaf73
+--- /dev/null
++++ b/Documentation/devicetree/bindings/phy/phy-hisi-inno-usb2.txt
+@@ -0,0 +1,48 @@
++HiSilicon INNO USB2 PHY
++-----------------------
++Required properties:
++- compatible: Should be "hisilicon,inno_usb2_phy"
++- #phy-cells: Must be 0
++- hisilicon,peripheral-syscon: Phandle of syscon used to control phy.
++- hisilicon,reg-num: Number of phy registers which should be configured
++at phy intialization stage
++- hisilicon,reg-seq: Sequence of triplets of (address, value, delay-us).
++The number of triplets is equal to "hisilicon,reg-num". Each triplet is
++used to write one phy register. The delay-us cell represents the delay
++time in microseconds to be applied after each write.
++- clocks: Phandle and clock specifier pair for reference clock utmi_refclk.
++- resets: List of phandle and reset specifier pairs for each reset signal in
++reset-names.
++- reset-names: Should be "por_rst" and "test_rst". The test_rst only
++exists in some of SOCs, so it is optional.
++
++Phy node can includes up to four subnodes. Each subnode represents one port.
++The required properties of port node are as follows:
++- clocks: Phandle and clock specifier pair for utmi_clock.
++- resets: List of phandle and reset specifier pairs for port reset and utmi reset.
++- reset-names: List of reset signal names. Should be "port_rst" and "utmi_rst"
++
++Refer to phy/phy-bindings.txt for the generic PHY binding properties
++
++Example:
++usb_phy: phy {
++		 compatible = "hisilicon,inno_usb2_phy";
++		 #phy-cells = <0>;
++		 hisilicon,peripheral-syscon = <&peri_ctrl>;
++		 hisilicon,reg-num = <7>;
++		 hisilicon,reg-seq = <0x80 0x800000 20>,
++			 <0x80 0xa0060c 200>,
++			 <0x80 0x80001c 20>,
++			 <0x80 0xa0001c 20>,
++			 <0x80 0x80060f 20>,
++			 <0x80 0xa0060f 20>,
++			 <0x80 0x800a4b 20>;
++		 clocks = <&crg USB2_REF_CLK>;
++		 resets = <&crg 0xb4 2>;
++		 reset-names = "por_rst";
++		 port0 {
++			 clocks = <&crg USB2_UTMI0_CLK>;
++			 resets = <&crg 0xb4 5>, <&crg 0xb4 1>;
++			 reset-names = "port_rst", "utmi_rst";
++		 };
++	 };
+diff --git a/Documentation/devicetree/bindings/pwm/pwm-hibvt.txt b/Documentation/devicetree/bindings/pwm/pwm-hibvt.txt
+new file mode 100644
+index 0000000..2ecf4e4
+--- /dev/null
++++ b/Documentation/devicetree/bindings/pwm/pwm-hibvt.txt
+@@ -0,0 +1,20 @@
++Hisilicon PWM controller
++
++Required properties:
++-compatible: should contain one SoC specific compatible string and one generic compatible
++string "hisilicon, hibvt-pwm". The SoC specific strings supported including:
++	"hisilicon,hi3516cv300-pwm"
++	"hisilicon,hi3519v100-pwm"
++- reg: physical base address and length of the controller's registers.
++- clocks: phandle and clock specifier of the PWM reference clock.
++- resets: phandle and reset specifier for the PWM controller reset.
++
++Example:
++	pwm: pwm@12130000 {
++
++		compatible = "hisilicon,hi3516cv300-pwm", "hisilicon,hibvt-pwm";
++		compatible = "hisilicon,hi3519v100-pwm", "hisilicon,hibvt-pwm";
++		reg = <0x12130000 0x10000>;
++		clocks = <&crg_ctrl HI3516CV300_PWM_CLK>;
++		resets = <&crg_ctrl 0x38 0>;
++	};
+diff --git a/Documentation/devicetree/bindings/rtc/rtc-hibvt.txt b/Documentation/devicetree/bindings/rtc/rtc-hibvt.txt
+new file mode 100644
+index 0000000..1543ee1
+--- /dev/null
++++ b/Documentation/devicetree/bindings/rtc/rtc-hibvt.txt
+@@ -0,0 +1,16 @@
++Hisilicon RTC controller
++
++Required properties:
++-compatible: should contain one SoC specific compatible string
++The SoC specific strings supported including:
++- compatible: "hisilicon,hi35xvr-rtc"
++- reg: physical base address and length of the controller's registers.
++- interrupts: IRQ line for the RTC.
++
++Example:
++rtc: rtc@120b0000 {
++		 compatible = "hisilicon,hi35xvr-rtc";
++		 reg = <0x120b0000 0x10000>;
++		 interrupts = <0 5 4>;
++	 };
++
+diff --git a/Documentation/devicetree/bindings/thermal/thermal.txt b/Documentation/devicetree/bindings/thermal/thermal.txt
+index f5db6b7..99d6608 100644
+--- a/Documentation/devicetree/bindings/thermal/thermal.txt
++++ b/Documentation/devicetree/bindings/thermal/thermal.txt
+@@ -167,6 +167,13 @@ Optional property:
+ 			by means of sensor ID. Additional coefficients are
+ 			interpreted as constant offset.
+ 
++- sustainable-power:	An estimate of the sustainable power (in mW) that the
++  Type: unsigned	thermal zone can dissipate at the desired
++  Size: one cell	control temperature.  For reference, the
++			sustainable power of a 4'' phone is typically
++			2000mW, while on a 10'' tablet is around
++			4500mW.
++
+ Note: The delay properties are bound to the maximum dT/dt (temperature
+ derivative over time) in two situations for a thermal zone:
+ (i)  - when passive cooling is activated (polling-delay-passive); and
+@@ -546,6 +553,8 @@ thermal-zones {
+ 		 */
+ 		coefficients =		<1200	-345	890>;
+ 
++		sustainable-power = <2500>;
++
+ 		trips {
+ 			/* Trips are based on resulting linear equation */
+ 			cpu-trip: cpu-trip {
+diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
+index eb8a10e..e2def60 100644
+--- a/Documentation/filesystems/proc.txt
++++ b/Documentation/filesystems/proc.txt
+@@ -369,6 +369,8 @@ is not associated with a file:
+  [stack:1001]             = the stack of the thread with tid 1001
+  [vdso]                   = the "virtual dynamic shared object",
+                             the kernel system call handler
++ [anon:<name>]            = an anonymous mapping that has been
++                            named by userspace
+ 
+  or if empty, the mapping is anonymous.
+ 
+@@ -419,6 +421,7 @@ KernelPageSize:        4 kB
+ MMUPageSize:           4 kB
+ Locked:              374 kB
+ VmFlags: rd ex mr mw me de
++Name:           name from userspace
+ 
+ the first of these lines shows the same information as is displayed for the
+ mapping in /proc/PID/maps.  The remaining lines show the size of the mapping
+@@ -470,6 +473,9 @@ Note that there is no guarantee that every flag and associated mnemonic will
+ be present in all further kernel releases. Things get changed, the flags may
+ be vanished or the reverse -- new added.
+ 
++The "Name" field will only be present on a mapping that has been named by
++userspace, and will show the name passed in by userspace.
++
+ This file is only present if the CONFIG_MMU kernel configuration option is
+ enabled.
+ 
+@@ -488,6 +494,10 @@ To clear the bits for the file mapped pages associated with the process
+ To clear the soft-dirty bit
+     > echo 4 > /proc/PID/clear_refs
+ 
++To reset the peak resident set size ("high water mark") to the process's
++current value:
++    > echo 5 > /proc/PID/clear_refs
++
+ Any other value written to /proc/PID/clear_refs will have no effect.
+ 
+ The /proc/pid/pagemap gives the PFN, which can be used to find the pageflags
+diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
+index a476b08..64a0fc5 100644
+--- a/Documentation/networking/ip-sysctl.txt
++++ b/Documentation/networking/ip-sysctl.txt
+@@ -60,7 +60,9 @@ fwmark_reflect - BOOLEAN
+ 	Controls the fwmark of kernel-generated IPv4 reply packets that are not
+ 	associated with a socket for example, TCP RSTs or ICMP echo replies).
+ 	If unset, these packets have a fwmark of zero. If set, they have the
+-	fwmark of the packet they are replying to.
++	fwmark of the packet they are replying to. Similarly affects the fwmark
++	used by internal routing lookups triggered by incoming packets, such as
++	the ones used for Path MTU Discovery.
+ 	Default: 0
+ 
+ route/max_size - INTEGER
+@@ -516,6 +518,16 @@ tcp_fastopen - INTEGER
+ 
+ 	See include/net/tcp.h and the code for more details.
+ 
++tcp_fwmark_accept - BOOLEAN
++	If set, incoming connections to listening sockets that do not have a
++	socket mark will set the mark of the accepting socket to the fwmark of
++	the incoming SYN packet. This will cause all packets on that connection
++	(starting from the first SYNACK) to be sent with that fwmark. The
++	listening socket's mark is unchanged. Listening sockets that already
++	have a fwmark set via setsockopt(SOL_SOCKET, SO_MARK, ...) are
++	unaffected.
++	Default: 0
++
+ tcp_syn_retries - INTEGER
+ 	Number of times initial SYNs for an active TCP connection attempt
+ 	will be retransmitted. Should not be higher than 255. Default value
+@@ -1212,7 +1224,9 @@ fwmark_reflect - BOOLEAN
+ 	Controls the fwmark of kernel-generated IPv6 reply packets that are not
+ 	associated with a socket for example, TCP RSTs or ICMPv6 echo replies).
+ 	If unset, these packets have a fwmark of zero. If set, they have the
+-	fwmark of the packet they are replying to.
++	fwmark of the packet they are replying to. Similarly affects the fwmark
++	used by internal routing lookups triggered by incoming packets, such as
++	the ones used for Path MTU Discovery.
+ 	Default: 0
+ 
+ conf/interface/*:
+@@ -1466,6 +1480,19 @@ suppress_frag_ndisc - INTEGER
+ 	1 - (default) discard fragmented neighbor discovery packets
+ 	0 - allow fragmented neighbor discovery packets
+ 
++optimistic_dad - BOOLEAN
++	Whether to perform Optimistic Duplicate Address Detection (RFC 4429).
++		0: disabled (default)
++		1: enabled
++
++use_optimistic - BOOLEAN
++	If enabled, do not classify optimistic addresses as deprecated during
++	source address selection.  Preferred addresses will still be chosen
++	before optimistic addresses, subject to other ranking in the source
++	address selection algorithm.
++		0: disabled (default)
++		1: enabled
++
+ icmp/*:
+ ratelimit - INTEGER
+ 	Limit the maximal rates for sending ICMPv6 packets.
+diff --git a/Documentation/networking/phy.txt b/Documentation/networking/phy.txt
+index e839e7e..e9cb02a 100644
+--- a/Documentation/networking/phy.txt
++++ b/Documentation/networking/phy.txt
+@@ -337,3 +337,12 @@ Board Fixups
+  The stubs set one of the two matching criteria, and set the other one to
+  match anything.
+ 
++ When phy_register_fixup() or *_for_uid()/*_for_id() is called at module,
++ unregister fixup and free allocate memory are required.
++
++ Call one of following function before unloading module.
++
++ int phy_unregister_fixup(const char *phy_id, u32 phy_uid, u32 phy_uid_mask);
++ int phy_unregister_fixup_for_uid(u32 phy_uid, u32 phy_uid_mask);
++ int phy_register_fixup_for_id(const char *phy_id);
++
+diff --git a/Documentation/sync.txt b/Documentation/sync.txt
+new file mode 100644
+index 0000000..a2d05e7
+--- /dev/null
++++ b/Documentation/sync.txt
+@@ -0,0 +1,75 @@
++Motivation:
++
++In complicated DMA pipelines such as graphics (multimedia, camera, gpu, display)
++a consumer of a buffer needs to know when the producer has finished producing
++it.  Likewise the producer needs to know when the consumer is finished with the
++buffer so it can reuse it.  A particular buffer may be consumed by multiple
++consumers which will retain the buffer for different amounts of time.  In
++addition, a consumer may consume multiple buffers atomically.
++The sync framework adds an API which allows synchronization between the
++producers and consumers in a generic way while also allowing platforms which
++have shared hardware synchronization primitives to exploit them.
++
++Goals:
++	* provide a generic API for expressing synchronization dependencies
++	* allow drivers to exploit hardware synchronization between hardware
++	  blocks
++	* provide a userspace API that allows a compositor to manage
++	  dependencies.
++	* provide rich telemetry data to allow debugging slowdowns and stalls of
++	   the graphics pipeline.
++
++Objects:
++	* sync_timeline
++	* sync_pt
++	* sync_fence
++
++sync_timeline:
++
++A sync_timeline is an abstract monotonically increasing counter. In general,
++each driver/hardware block context will have one of these.  They can be backed
++by the appropriate hardware or rely on the generic sw_sync implementation.
++Timelines are only ever created through their specific implementations
++(i.e. sw_sync.)
++
++sync_pt:
++
++A sync_pt is an abstract value which marks a point on a sync_timeline. Sync_pts
++have a single timeline parent.  They have 3 states: active, signaled, and error.
++They start in active state and transition, once, to either signaled (when the
++timeline counter advances beyond the sync_pt’s value) or error state.
++
++sync_fence:
++
++Sync_fences are the primary primitives used by drivers to coordinate
++synchronization of their buffers.  They are a collection of sync_pts which may
++or may not have the same timeline parent.  A sync_pt can only exist in one fence
++and the fence's list of sync_pts is immutable once created.  Fences can be
++waited on synchronously or asynchronously.  Two fences can also be merged to
++create a third fence containing a copy of the two fences’ sync_pts.  Fences are
++backed by file descriptors to allow userspace to coordinate the display pipeline
++dependencies.
++
++Use:
++
++A driver implementing sync support should have a work submission function which:
++     * takes a fence argument specifying when to begin work
++     * asynchronously queues that work to kick off when the fence is signaled
++     * returns a fence to indicate when its work will be done.
++     * signals the returned fence once the work is completed.
++
++Consider an imaginary display driver that has the following API:
++/*
++ * assumes buf is ready to be displayed.
++ * blocks until the buffer is on screen.
++ */
++    void display_buffer(struct dma_buf *buf);
++
++The new API will become:
++/*
++ * will display buf when fence is signaled.
++ * returns immediately with a fence that will signal when buf
++ * is no longer displayed.
++ */
++struct sync_fence* display_buffer(struct dma_buf *buf,
++                                 struct sync_fence *fence);
+diff --git a/Documentation/sysctl/fs.txt b/Documentation/sysctl/fs.txt
+index 88152f2..302b5ed 100644
+--- a/Documentation/sysctl/fs.txt
++++ b/Documentation/sysctl/fs.txt
+@@ -32,6 +32,8 @@ Currently, these files are in /proc/sys/fs:
+ - nr_open
+ - overflowuid
+ - overflowgid
++- pipe-user-pages-hard
++- pipe-user-pages-soft
+ - protected_hardlinks
+ - protected_symlinks
+ - suid_dumpable
+@@ -159,6 +161,27 @@ The default is 65534.
+ 
+ ==============================================================
+ 
++pipe-user-pages-hard:
++
++Maximum total number of pages a non-privileged user may allocate for pipes.
++Once this limit is reached, no new pipes may be allocated until usage goes
++below the limit again. When set to 0, no limit is applied, which is the default
++setting.
++
++==============================================================
++
++pipe-user-pages-soft:
++
++Maximum total number of pages a non-privileged user may allocate for pipes
++before the pipe size gets limited to a single page. Once this limit is reached,
++new pipes will be limited to a single page in size for this user in order to
++limit total memory usage, and trying to increase them using fcntl() will be
++denied until usage goes below the limit again. The default value allows to
++allocate up to 1024 pipes at their default size. When set to 0, no limit is
++applied.
++
++==============================================================
++
+ protected_hardlinks:
+ 
+ A long-standing class of security issues is the hardlink-based
+diff --git a/Documentation/sysctl/vm.txt b/Documentation/sysctl/vm.txt
+index 4415aa9..9aecaa5 100644
+--- a/Documentation/sysctl/vm.txt
++++ b/Documentation/sysctl/vm.txt
+@@ -29,6 +29,7 @@ Currently, these files are in /proc/sys/vm:
+ - dirty_writeback_centisecs
+ - drop_caches
+ - extfrag_threshold
++- extra_free_kbytes
+ - hugepages_treat_as_movable
+ - hugetlb_shm_group
+ - laptop_mode
+@@ -225,6 +226,21 @@ fragmentation index is <= extfrag_threshold. The default value is 500.
+ 
+ ==============================================================
+ 
++extra_free_kbytes
++
++This parameter tells the VM to keep extra free memory between the threshold
++where background reclaim (kswapd) kicks in, and the threshold where direct
++reclaim (by allocating processes) kicks in.
++
++This is useful for workloads that require low latency memory allocations
++and have a bounded burstiness in memory allocations, for example a
++realtime application that receives and transmits network traffic
++(causing in-kernel memory allocations) with a maximum total message burst
++size of 200MB may need 200MB of extra free memory to avoid direct reclaim
++related latencies.
++
++==============================================================
++
+ hugepages_treat_as_movable
+ 
+ This parameter controls whether we can allocate hugepages from ZONE_MOVABLE
+diff --git a/Documentation/thermal/cpu-cooling-api.txt b/Documentation/thermal/cpu-cooling-api.txt
+index fca24c9..7165358 100644
+--- a/Documentation/thermal/cpu-cooling-api.txt
++++ b/Documentation/thermal/cpu-cooling-api.txt
+@@ -3,7 +3,7 @@ CPU cooling APIs How To
+ 
+ Written by Amit Daniel Kachhap <amit.kachhap@linaro.org>
+ 
+-Updated: 12 May 2012
++Updated: 6 Jan 2015
+ 
+ Copyright (c)  2012 Samsung Electronics Co., Ltd(http://www.samsung.com)
+ 
+@@ -25,8 +25,173 @@ the user. The registration APIs returns the cooling device pointer.
+ 
+    clip_cpus: cpumask of cpus where the frequency constraints will happen.
+ 
+-1.1.2 void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
++1.1.2 struct thermal_cooling_device *of_cpufreq_cooling_register(
++	struct device_node *np, const struct cpumask *clip_cpus)
++
++    This interface function registers the cpufreq cooling device with
++    the name "thermal-cpufreq-%x" linking it with a device tree node, in
++    order to bind it via the thermal DT code. This api can support multiple
++    instances of cpufreq cooling devices.
++
++    np: pointer to the cooling device device tree node
++    clip_cpus: cpumask of cpus where the frequency constraints will happen.
++
++1.1.3 struct thermal_cooling_device *cpufreq_power_cooling_register(
++    const struct cpumask *clip_cpus, u32 capacitance,
++    get_static_t plat_static_func)
++
++Similar to cpufreq_cooling_register, this function registers a cpufreq
++cooling device.  Using this function, the cooling device will
++implement the power extensions by using a simple cpu power model.  The
++cpus must have registered their OPPs using the OPP library.
++
++The additional parameters are needed for the power model (See 2. Power
++models).  "capacitance" is the dynamic power coefficient (See 2.1
++Dynamic power).  "plat_static_func" is a function to calculate the
++static power consumed by these cpus (See 2.2 Static power).
++
++1.1.4 struct thermal_cooling_device *of_cpufreq_power_cooling_register(
++    struct device_node *np, const struct cpumask *clip_cpus, u32 capacitance,
++    get_static_t plat_static_func)
++
++Similar to cpufreq_power_cooling_register, this function register a
++cpufreq cooling device with power extensions using the device tree
++information supplied by the np parameter.
++
++1.1.5 void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
+ 
+     This interface function unregisters the "thermal-cpufreq-%x" cooling device.
+ 
+     cdev: Cooling device pointer which has to be unregistered.
++
++2. Power models
++
++The power API registration functions provide a simple power model for
++CPUs.  The current power is calculated as dynamic + (optionally)
++static power.  This power model requires that the operating-points of
++the CPUs are registered using the kernel's opp library and the
++`cpufreq_frequency_table` is assigned to the `struct device` of the
++cpu.  If you are using CONFIG_CPUFREQ_DT then the
++`cpufreq_frequency_table` should already be assigned to the cpu
++device.
++
++The `plat_static_func` parameter of `cpufreq_power_cooling_register()`
++and `of_cpufreq_power_cooling_register()` is optional.  If you don't
++provide it, only dynamic power will be considered.
++
++2.1 Dynamic power
++
++The dynamic power consumption of a processor depends on many factors.
++For a given processor implementation the primary factors are:
++
++- The time the processor spends running, consuming dynamic power, as
++  compared to the time in idle states where dynamic consumption is
++  negligible.  Herein we refer to this as 'utilisation'.
++- The voltage and frequency levels as a result of DVFS.  The DVFS
++  level is a dominant factor governing power consumption.
++- In running time the 'execution' behaviour (instruction types, memory
++  access patterns and so forth) causes, in most cases, a second order
++  variation.  In pathological cases this variation can be significant,
++  but typically it is of a much lesser impact than the factors above.
++
++A high level dynamic power consumption model may then be represented as:
++
++Pdyn = f(run) * Voltage^2 * Frequency * Utilisation
++
++f(run) here represents the described execution behaviour and its
++result has a units of Watts/Hz/Volt^2 (this often expressed in
++mW/MHz/uVolt^2)
++
++The detailed behaviour for f(run) could be modelled on-line.  However,
++in practice, such an on-line model has dependencies on a number of
++implementation specific processor support and characterisation
++factors.  Therefore, in initial implementation that contribution is
++represented as a constant coefficient.  This is a simplification
++consistent with the relative contribution to overall power variation.
++
++In this simplified representation our model becomes:
++
++Pdyn = Capacitance * Voltage^2 * Frequency * Utilisation
++
++Where `capacitance` is a constant that represents an indicative
++running time dynamic power coefficient in fundamental units of
++mW/MHz/uVolt^2.  Typical values for mobile CPUs might lie in range
++from 100 to 500.  For reference, the approximate values for the SoC in
++ARM's Juno Development Platform are 530 for the Cortex-A57 cluster and
++140 for the Cortex-A53 cluster.
++
++
++2.2 Static power
++
++Static leakage power consumption depends on a number of factors.  For a
++given circuit implementation the primary factors are:
++
++- Time the circuit spends in each 'power state'
++- Temperature
++- Operating voltage
++- Process grade
++
++The time the circuit spends in each 'power state' for a given
++evaluation period at first order means OFF or ON.  However,
++'retention' states can also be supported that reduce power during
++inactive periods without loss of context.
++
++Note: The visibility of state entries to the OS can vary, according to
++platform specifics, and this can then impact the accuracy of a model
++based on OS state information alone.  It might be possible in some
++cases to extract more accurate information from system resources.
++
++The temperature, operating voltage and process 'grade' (slow to fast)
++of the circuit are all significant factors in static leakage power
++consumption.  All of these have complex relationships to static power.
++
++Circuit implementation specific factors include the chosen silicon
++process as well as the type, number and size of transistors in both
++the logic gates and any RAM elements included.
++
++The static power consumption modelling must take into account the
++power managed regions that are implemented.  Taking the example of an
++ARM processor cluster, the modelling would take into account whether
++each CPU can be powered OFF separately or if only a single power
++region is implemented for the complete cluster.
++
++In one view, there are others, a static power consumption model can
++then start from a set of reference values for each power managed
++region (e.g. CPU, Cluster/L2) in each state (e.g. ON, OFF) at an
++arbitrary process grade, voltage and temperature point.  These values
++are then scaled for all of the following: the time in each state, the
++process grade, the current temperature and the operating voltage.
++However, since both implementation specific and complex relationships
++dominate the estimate, the appropriate interface to the model from the
++cpu cooling device is to provide a function callback that calculates
++the static power in this platform.  When registering the cpu cooling
++device pass a function pointer that follows the `get_static_t`
++prototype:
++
++    int plat_get_static(cpumask_t *cpumask, int interval,
++                        unsigned long voltage, u32 &power);
++
++`cpumask` is the cpumask of the cpus involved in the calculation.
++`voltage` is the voltage at which they are operating.  The function
++should calculate the average static power for the last `interval`
++milliseconds.  It returns 0 on success, -E* on error.  If it
++succeeds, it should store the static power in `power`.  Reading the
++temperature of the cpus described by `cpumask` is left for
++plat_get_static() to do as the platform knows best which thermal
++sensor is closest to the cpu.
++
++If `plat_static_func` is NULL, static power is considered to be
++negligible for this platform and only dynamic power is considered.
++
++The platform specific callback can then use any combination of tables
++and/or equations to permute the estimated value.  Process grade
++information is not passed to the model since access to such data, from
++on-chip measurement capability or manufacture time data, is platform
++specific.
++
++Note: the significance of static power for CPUs in comparison to
++dynamic power is highly dependent on implementation.  Given the
++potential complexity in implementation, the importance and accuracy of
++its inclusion when using cpu cooling devices should be assessed on a
++case by case basis.
++
+diff --git a/Documentation/thermal/power_allocator.txt b/Documentation/thermal/power_allocator.txt
+new file mode 100644
+index 0000000..c3797b5
+--- /dev/null
++++ b/Documentation/thermal/power_allocator.txt
+@@ -0,0 +1,247 @@
++Power allocator governor tunables
++=================================
++
++Trip points
++-----------
++
++The governor requires the following two passive trip points:
++
++1.  "switch on" trip point: temperature above which the governor
++    control loop starts operating.  This is the first passive trip
++    point of the thermal zone.
++
++2.  "desired temperature" trip point: it should be higher than the
++    "switch on" trip point.  This the target temperature the governor
++    is controlling for.  This is the last passive trip point of the
++    thermal zone.
++
++PID Controller
++--------------
++
++The power allocator governor implements a
++Proportional-Integral-Derivative controller (PID controller) with
++temperature as the control input and power as the controlled output:
++
++    P_max = k_p * e + k_i * err_integral + k_d * diff_err + sustainable_power
++
++where
++    e = desired_temperature - current_temperature
++    err_integral is the sum of previous errors
++    diff_err = e - previous_error
++
++It is similar to the one depicted below:
++
++                                      k_d
++                                       |
++current_temp                           |
++     |                                 v
++     |                +----------+   +---+
++     |         +----->| diff_err |-->| X |------+
++     |         |      +----------+   +---+      |
++     |         |                                |      tdp        actor
++     |         |                      k_i       |       |  get_requested_power()
++     |         |                       |        |       |        |     |
++     |         |                       |        |       |        |     | ...
++     v         |                       v        v       v        v     v
++   +---+       |      +-------+      +---+    +---+   +---+   +----------+
++   | S |-------+----->| sum e |----->| X |--->| S |-->| S |-->|power     |
++   +---+       |      +-------+      +---+    +---+   +---+   |allocation|
++     ^         |                                ^             +----------+
++     |         |                                |                |     |
++     |         |        +---+                   |                |     |
++     |         +------->| X |-------------------+                v     v
++     |                  +---+                               granted performance
++desired_temperature       ^
++                          |
++                          |
++                      k_po/k_pu
++
++Sustainable power
++-----------------
++
++An estimate of the sustainable dissipatable power (in mW) should be
++provided while registering the thermal zone.  This estimates the
++sustained power that can be dissipated at the desired control
++temperature.  This is the maximum sustained power for allocation at
++the desired maximum temperature.  The actual sustained power can vary
++for a number of reasons.  The closed loop controller will take care of
++variations such as environmental conditions, and some factors related
++to the speed-grade of the silicon.  `sustainable_power` is therefore
++simply an estimate, and may be tuned to affect the aggressiveness of
++the thermal ramp. For reference, the sustainable power of a 4" phone
++is typically 2000mW, while on a 10" tablet is around 4500mW (may vary
++depending on screen size).
++
++If you are using device tree, do add it as a property of the
++thermal-zone.  For example:
++
++	thermal-zones {
++		soc_thermal {
++			polling-delay = <1000>;
++			polling-delay-passive = <100>;
++			sustainable-power = <2500>;
++			...
++
++Instead, if the thermal zone is registered from the platform code, pass a
++`thermal_zone_params` that has a `sustainable_power`.  If no
++`thermal_zone_params` were being passed, then something like below
++will suffice:
++
++	static const struct thermal_zone_params tz_params = {
++		.sustainable_power = 3500,
++	};
++
++and then pass `tz_params` as the 5th parameter to
++`thermal_zone_device_register()`
++
++k_po and k_pu
++-------------
++
++The implementation of the PID controller in the power allocator
++thermal governor allows the configuration of two proportional term
++constants: `k_po` and `k_pu`.  `k_po` is the proportional term
++constant during temperature overshoot periods (current temperature is
++above "desired temperature" trip point).  Conversely, `k_pu` is the
++proportional term constant during temperature undershoot periods
++(current temperature below "desired temperature" trip point).
++
++These controls are intended as the primary mechanism for configuring
++the permitted thermal "ramp" of the system.  For instance, a lower
++`k_pu` value will provide a slower ramp, at the cost of capping
++available capacity at a low temperature.  On the other hand, a high
++value of `k_pu` will result in the governor granting very high power
++whilst temperature is low, and may lead to temperature overshooting.
++
++The default value for `k_pu` is:
++
++    2 * sustainable_power / (desired_temperature - switch_on_temp)
++
++This means that at `switch_on_temp` the output of the controller's
++proportional term will be 2 * `sustainable_power`.  The default value
++for `k_po` is:
++
++    sustainable_power / (desired_temperature - switch_on_temp)
++
++Focusing on the proportional and feed forward values of the PID
++controller equation we have:
++
++    P_max = k_p * e + sustainable_power
++
++The proportional term is proportional to the difference between the
++desired temperature and the current one.  When the current temperature
++is the desired one, then the proportional component is zero and
++`P_max` = `sustainable_power`.  That is, the system should operate in
++thermal equilibrium under constant load.  `sustainable_power` is only
++an estimate, which is the reason for closed-loop control such as this.
++
++Expanding `k_pu` we get:
++    P_max = 2 * sustainable_power * (T_set - T) / (T_set - T_on) +
++        sustainable_power
++
++where
++    T_set is the desired temperature
++    T is the current temperature
++    T_on is the switch on temperature
++
++When the current temperature is the switch_on temperature, the above
++formula becomes:
++
++    P_max = 2 * sustainable_power * (T_set - T_on) / (T_set - T_on) +
++        sustainable_power = 2 * sustainable_power + sustainable_power =
++        3 * sustainable_power
++
++Therefore, the proportional term alone linearly decreases power from
++3 * `sustainable_power` to `sustainable_power` as the temperature
++rises from the switch on temperature to the desired temperature.
++
++k_i and integral_cutoff
++-----------------------
++
++`k_i` configures the PID loop's integral term constant.  This term
++allows the PID controller to compensate for long term drift and for
++the quantized nature of the output control: cooling devices can't set
++the exact power that the governor requests.  When the temperature
++error is below `integral_cutoff`, errors are accumulated in the
++integral term.  This term is then multiplied by `k_i` and the result
++added to the output of the controller.  Typically `k_i` is set low (1
++or 2) and `integral_cutoff` is 0.
++
++k_d
++---
++
++`k_d` configures the PID loop's derivative term constant.  It's
++recommended to leave it as the default: 0.
++
++Cooling device power API
++========================
++
++Cooling devices controlled by this governor must supply the additional
++"power" API in their `cooling_device_ops`.  It consists on three ops:
++
++1. int get_requested_power(struct thermal_cooling_device *cdev,
++	struct thermal_zone_device *tz, u32 *power);
++@cdev: The `struct thermal_cooling_device` pointer
++@tz: thermal zone in which we are currently operating
++@power: pointer in which to store the calculated power
++
++`get_requested_power()` calculates the power requested by the device
++in milliwatts and stores it in @power .  It should return 0 on
++success, -E* on failure.  This is currently used by the power
++allocator governor to calculate how much power to give to each cooling
++device.
++
++2. int state2power(struct thermal_cooling_device *cdev, struct
++        thermal_zone_device *tz, unsigned long state, u32 *power);
++@cdev: The `struct thermal_cooling_device` pointer
++@tz: thermal zone in which we are currently operating
++@state: A cooling device state
++@power: pointer in which to store the equivalent power
++
++Convert cooling device state @state into power consumption in
++milliwatts and store it in @power.  It should return 0 on success, -E*
++on failure.  This is currently used by thermal core to calculate the
++maximum power that an actor can consume.
++
++3. int power2state(struct thermal_cooling_device *cdev, u32 power,
++	unsigned long *state);
++@cdev: The `struct thermal_cooling_device` pointer
++@power: power in milliwatts
++@state: pointer in which to store the resulting state
++
++Calculate a cooling device state that would make the device consume at
++most @power mW and store it in @state.  It should return 0 on success,
++-E* on failure.  This is currently used by the thermal core to convert
++a given power set by the power allocator governor to a state that the
++cooling device can set.  It is a function because this conversion may
++depend on external factors that may change so this function should the
++best conversion given "current circumstances".
++
++Cooling device weights
++----------------------
++
++Weights are a mechanism to bias the allocation among cooling
++devices.  They express the relative power efficiency of different
++cooling devices.  Higher weight can be used to express higher power
++efficiency.  Weighting is relative such that if each cooling device
++has a weight of one they are considered equal.  This is particularly
++useful in heterogeneous systems where two cooling devices may perform
++the same kind of compute, but with different efficiency.  For example,
++a system with two different types of processors.
++
++If the thermal zone is registered using
++`thermal_zone_device_register()` (i.e., platform code), then weights
++are passed as part of the thermal zone's `thermal_bind_parameters`.
++If the platform is registered using device tree, then they are passed
++as the `contribution` property of each map in the `cooling-maps` node.
++
++Limitations of the power allocator governor
++===========================================
++
++The power allocator governor's PID controller works best if there is a
++periodic tick.  If you have a driver that calls
++`thermal_zone_device_update()` (or anything that ends up calling the
++governor's `throttle()` function) repetitively, the governor response
++won't be very good.  Note that this is not particular to this
++governor, step-wise will also misbehave if you call its throttle()
++faster than the normal thermal framework tick (due to interrupts for
++example) as it will overreact.
+diff --git a/Documentation/thermal/sysfs-api.txt b/Documentation/thermal/sysfs-api.txt
+index 87519cb..c1f6864 100644
+--- a/Documentation/thermal/sysfs-api.txt
++++ b/Documentation/thermal/sysfs-api.txt
+@@ -95,7 +95,7 @@ temperature) and throttle appropriate devices.
+ 1.3 interface for binding a thermal zone device with a thermal cooling device
+ 1.3.1 int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
+ 	int trip, struct thermal_cooling_device *cdev,
+-	unsigned long upper, unsigned long lower);
++	unsigned long upper, unsigned long lower, unsigned int weight);
+ 
+     This interface function bind a thermal cooling device to the certain trip
+     point of a thermal zone device.
+@@ -110,6 +110,8 @@ temperature) and throttle appropriate devices.
+     lower:the Minimum cooling state can be used for this trip point.
+           THERMAL_NO_LIMIT means no lower limit,
+ 	  and the cooling device can be in cooling state 0.
++    weight: the influence of this cooling device in this thermal
++            zone.  See 1.4.1 below for more information.
+ 
+ 1.3.2 int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz,
+ 		int trip, struct thermal_cooling_device *cdev);
+@@ -127,9 +129,15 @@ temperature) and throttle appropriate devices.
+     This structure defines the following parameters that are used to bind
+     a zone with a cooling device for a particular trip point.
+     .cdev: The cooling device pointer
+-    .weight: The 'influence' of a particular cooling device on this zone.
+-             This is on a percentage scale. The sum of all these weights
+-             (for a particular zone) cannot exceed 100.
++    .weight: The 'influence' of a particular cooling device on this
++             zone. This is relative to the rest of the cooling
++             devices. For example, if all cooling devices have a
++             weight of 1, then they all contribute the same. You can
++             use percentages if you want, but it's not mandatory. A
++             weight of 0 means that this cooling device doesn't
++             contribute to the cooling of this zone unless all cooling
++             devices have a weight of 0. If all weights are 0, then
++             they all contribute the same.
+     .trip_mask:This is a bit mask that gives the binding relation between
+                this thermal zone and cdev, for a particular trip point.
+                If nth bit is set, then the cdev and thermal zone are bound
+@@ -176,6 +184,14 @@ Thermal zone device sys I/F, created once it's registered:
+     |---trip_point_[0-*]_type:	Trip point type
+     |---trip_point_[0-*]_hyst:	Hysteresis value for this trip point
+     |---emul_temp:		Emulated temperature set node
++    |---sustainable_power:      Sustainable dissipatable power
++    |---k_po:                   Proportional term during temperature overshoot
++    |---k_pu:                   Proportional term during temperature undershoot
++    |---k_i:                    PID's integral term in the power allocator gov
++    |---k_d:                    PID's derivative term in the power allocator
++    |---integral_cutoff:        Offset above which errors are accumulated
++    |---slope:                  Slope constant applied as linear extrapolation
++    |---offset:                 Offset constant applied as linear extrapolation
+ 
+ Thermal cooling device sys I/F, created once it's registered:
+ /sys/class/thermal/cooling_device[0-*]:
+@@ -192,6 +208,8 @@ thermal_zone_bind_cooling_device/thermal_zone_unbind_cooling_device.
+ /sys/class/thermal/thermal_zone[0-*]:
+     |---cdev[0-*]:		[0-*]th cooling device in current thermal zone
+     |---cdev[0-*]_trip_point:	Trip point that cdev[0-*] is associated with
++    |---cdev[0-*]_weight:       Influence of the cooling device in
++                                this thermal zone
+ 
+ Besides the thermal zone device sysfs I/F and cooling device sysfs I/F,
+ the generic thermal driver also creates a hwmon sysfs I/F for each _type_
+@@ -265,6 +283,14 @@ cdev[0-*]_trip_point
+ 	point.
+ 	RO, Optional
+ 
++cdev[0-*]_weight
++        The influence of cdev[0-*] in this thermal zone. This value
++        is relative to the rest of cooling devices in the thermal
++        zone. For example, if a cooling device has a weight double
++        than that of other, it's twice as effective in cooling the
++        thermal zone.
++        RW, Optional
++
+ passive
+ 	Attribute is only present for zones in which the passive cooling
+ 	policy is not supported by native thermal driver. Default is zero
+@@ -289,6 +315,66 @@ emul_temp
+ 	  because userland can easily disable the thermal policy by simply
+ 	  flooding this sysfs node with low temperature values.
+ 
++sustainable_power
++	An estimate of the sustained power that can be dissipated by
++	the thermal zone. Used by the power allocator governor. For
++	more information see Documentation/thermal/power_allocator.txt
++	Unit: milliwatts
++	RW, Optional
++
++k_po
++	The proportional term of the power allocator governor's PID
++	controller during temperature overshoot. Temperature overshoot
++	is when the current temperature is above the "desired
++	temperature" trip point. For more information see
++	Documentation/thermal/power_allocator.txt
++	RW, Optional
++
++k_pu
++	The proportional term of the power allocator governor's PID
++	controller during temperature undershoot. Temperature undershoot
++	is when the current temperature is below the "desired
++	temperature" trip point. For more information see
++	Documentation/thermal/power_allocator.txt
++	RW, Optional
++
++k_i
++	The integral term of the power allocator governor's PID
++	controller. This term allows the PID controller to compensate
++	for long term drift. For more information see
++	Documentation/thermal/power_allocator.txt
++	RW, Optional
++
++k_d
++	The derivative term of the power allocator governor's PID
++	controller. For more information see
++	Documentation/thermal/power_allocator.txt
++	RW, Optional
++
++integral_cutoff
++	Temperature offset from the desired temperature trip point
++	above which the integral term of the power allocator
++	governor's PID controller starts accumulating errors. For
++	example, if integral_cutoff is 0, then the integral term only
++	accumulates error when temperature is above the desired
++	temperature trip point. For more information see
++	Documentation/thermal/power_allocator.txt
++	RW, Optional
++
++slope
++	The slope constant used in a linear extrapolation model
++	to determine a hotspot temperature based off the sensor's
++	raw readings. It is up to the device driver to determine
++	the usage of these values.
++	RW, Optional
++
++offset
++	The offset constant used in a linear extrapolation model
++	to determine a hotspot temperature based off the sensor's
++	raw readings. It is up to the device driver to determine
++	the usage of these values.
++	RW, Optional
++
+ *****************************
+ * Cooling device attributes *
+ *****************************
+@@ -318,7 +404,8 @@ passive, active. If an ACPI thermal zone supports critical, passive,
+ active[0] and active[1] at the same time, it may register itself as a
+ thermal_zone_device (thermal_zone1) with 4 trip points in all.
+ It has one processor and one fan, which are both registered as
+-thermal_cooling_device.
++thermal_cooling_device. Both are considered to have the same
++effectiveness in cooling the thermal zone.
+ 
+ If the processor is listed in _PSL method, and the fan is listed in _AL0
+ method, the sys I/F structure will be built like this:
+@@ -340,8 +427,10 @@ method, the sys I/F structure will be built like this:
+     |---trip_point_3_type:	active1
+     |---cdev0:			--->/sys/class/thermal/cooling_device0
+     |---cdev0_trip_point:	1	/* cdev0 can be used for passive */
++    |---cdev0_weight:           1024
+     |---cdev1:			--->/sys/class/thermal/cooling_device3
+     |---cdev1_trip_point:	2	/* cdev1 can be used for active[0]*/
++    |---cdev1_weight:           1024
+ 
+ |cooling_device0:
+     |---type:			Processor
+diff --git a/Documentation/trace/coresight.txt b/Documentation/trace/coresight.txt
+new file mode 100644
+index 0000000..77d14d5
+--- /dev/null
++++ b/Documentation/trace/coresight.txt
+@@ -0,0 +1,299 @@
++		Coresight - HW Assisted Tracing on ARM
++		======================================
++
++   Author:   Mathieu Poirier <mathieu.poirier@linaro.org>
++   Date:     September 11th, 2014
++
++Introduction
++------------
++
++Coresight is an umbrella of technologies allowing for the debugging of ARM
++based SoC.  It includes solutions for JTAG and HW assisted tracing.  This
++document is concerned with the latter.
++
++HW assisted tracing is becoming increasingly useful when dealing with systems
++that have many SoCs and other components like GPU and DMA engines.  ARM has
++developed a HW assisted tracing solution by means of different components, each
++being added to a design at synthesis time to cater to specific tracing needs.
++Compoments are generally categorised as source, link and sinks and are
++(usually) discovered using the AMBA bus.
++
++"Sources" generate a compressed stream representing the processor instruction
++path based on tracing scenarios as configured by users.  From there the stream
++flows through the coresight system (via ATB bus) using links that are connecting
++the emanating source to a sink(s).  Sinks serve as endpoints to the coresight
++implementation, either storing the compressed stream in a memory buffer or
++creating an interface to the outside world where data can be transferred to a
++host without fear of filling up the onboard coresight memory buffer.
++
++At typical coresight system would look like this:
++
++  *****************************************************************
++ **************************** AMBA AXI  ****************************===||
++  *****************************************************************    ||
++        ^                    ^                            |            ||
++        |                    |                            *            **
++     0000000    :::::     0000000    :::::    :::::    @@@@@@@    ||||||||||||
++     0 CPU 0<-->: C :     0 CPU 0<-->: C :    : C :    @ STM @    || System ||
++  |->0000000    : T :  |->0000000    : T :    : T :<--->@@@@@     || Memory ||
++  |  #######<-->: I :  |  #######<-->: I :    : I :      @@@<-|   ||||||||||||
++  |  # ETM #    :::::  |  # PTM #    :::::    :::::       @   |
++  |   #####      ^ ^   |   #####      ^ !      ^ !        .   |   |||||||||
++  | |->###       | !   | |->###       | !      | !        .   |   || DAP ||
++  | |   #        | !   | |   #        | !      | !        .   |   |||||||||
++  | |   .        | !   | |   .        | !      | !        .   |      |  |
++  | |   .        | !   | |   .        | !      | !        .   |      |  *
++  | |   .        | !   | |   .        | !      | !        .   |      | SWD/
++  | |   .        | !   | |   .        | !      | !        .   |      | JTAG
++  *****************************************************************<-|
++ *************************** AMBA Debug APB ************************
++  *****************************************************************
++   |    .          !         .          !        !        .    |
++   |    .          *         .          *        *        .    |
++  *****************************************************************
++ ******************** Cross Trigger Matrix (CTM) *******************
++  *****************************************************************
++   |    .     ^              .                            .    |
++   |    *     !              *                            *    |
++  *****************************************************************
++ ****************** AMBA Advanced Trace Bus (ATB) ******************
++  *****************************************************************
++   |          !                        ===============         |
++   |          *                         ===== F =====<---------|
++   |   :::::::::                         ==== U ====
++   |-->:: CTI ::<!!                       === N ===
++   |   :::::::::  !                        == N ==
++   |    ^         *                        == E ==
++   |    !  &&&&&&&&&       IIIIIII         == L ==
++   |------>&& ETB &&<......II     I        =======
++   |    !  &&&&&&&&&       II     I           .
++   |    !                    I     I          .
++   |    !                    I REP I<..........
++   |    !                    I     I
++   |    !!>&&&&&&&&&       II     I           *Source: ARM ltd.
++   |------>& TPIU  &<......II    I            DAP = Debug Access Port
++           &&&&&&&&&       IIIIIII            ETM = Embedded Trace Macrocell
++               ;                              PTM = Program Trace Macrocell
++               ;                              CTI = Cross Trigger Interface
++               *                              ETB = Embedded Trace Buffer
++          To trace port                       TPIU= Trace Port Interface Unit
++                                              SWD = Serial Wire Debug
++
++While on target configuration of the components is done via the APB bus,
++all trace data are carried out-of-band on the ATB bus.  The CTM provides
++a way to aggregate and distribute signals between CoreSight components.
++
++The coresight framework provides a central point to represent, configure and
++manage coresight devices on a platform.  This first implementation centers on
++the basic tracing functionality, enabling components such ETM/PTM, funnel,
++replicator, TMC, TPIU and ETB.  Future work will enable more
++intricate IP blocks such as STM and CTI.
++
++
++Acronyms and Classification
++---------------------------
++
++Acronyms:
++
++PTM:     Program Trace Macrocell
++ETM:     Embedded Trace Macrocell
++STM:     System trace Macrocell
++ETB:     Embedded Trace Buffer
++ITM:     Instrumentation Trace Macrocell
++TPIU:    Trace Port Interface Unit
++TMC-ETR: Trace Memory Controller, configured as Embedded Trace Router
++TMC-ETF: Trace Memory Controller, configured as Embedded Trace FIFO
++CTI:     Cross Trigger Interface
++
++Classification:
++
++Source:
++   ETMv3.x ETMv4, PTMv1.0, PTMv1.1, STM, STM500, ITM
++Link:
++   Funnel, replicator (intelligent or not), TMC-ETR
++Sinks:
++   ETBv1.0, ETB1.1, TPIU, TMC-ETF
++Misc:
++   CTI
++
++
++Device Tree Bindings
++----------------------
++
++See Documentation/devicetree/bindings/arm/coresight.txt for details.
++
++As of this writing drivers for ITM, STMs and CTIs are not provided but are
++expected to be added as the solution matures.
++
++
++Framework and implementation
++----------------------------
++
++The coresight framework provides a central point to represent, configure and
++manage coresight devices on a platform.  Any coresight compliant device can
++register with the framework for as long as they use the right APIs:
++
++struct coresight_device *coresight_register(struct coresight_desc *desc);
++void coresight_unregister(struct coresight_device *csdev);
++
++The registering function is taking a "struct coresight_device *csdev" and
++register the device with the core framework.  The unregister function takes
++a reference to a "strut coresight_device", obtained at registration time.
++
++If everything goes well during the registration process the new devices will
++show up under /sys/bus/coresight/devices, as showns here for a TC2 platform:
++
++root:~# ls /sys/bus/coresight/devices/
++replicator  20030000.tpiu    2201c000.ptm  2203c000.etm  2203e000.etm
++20010000.etb         20040000.funnel  2201d000.ptm  2203d000.etm
++root:~#
++
++The functions take a "struct coresight_device", which looks like this:
++
++struct coresight_desc {
++        enum coresight_dev_type type;
++        struct coresight_dev_subtype subtype;
++        const struct coresight_ops *ops;
++        struct coresight_platform_data *pdata;
++        struct device *dev;
++        const struct attribute_group **groups;
++};
++
++
++The "coresight_dev_type" identifies what the device is, i.e, source link or
++sink while the "coresight_dev_subtype" will characterise that type further.
++
++The "struct coresight_ops" is mandatory and will tell the framework how to
++perform base operations related to the components, each component having
++a different set of requirement.  For that "struct coresight_ops_sink",
++"struct coresight_ops_link" and "struct coresight_ops_source" have been
++provided.
++
++The next field, "struct coresight_platform_data *pdata" is acquired by calling
++"of_get_coresight_platform_data()", as part of the driver's _probe routine and
++"struct device *dev" gets the device reference embedded in the "amba_device":
++
++static int etm_probe(struct amba_device *adev, const struct amba_id *id)
++{
++ ...
++ ...
++ drvdata->dev = &adev->dev;
++ ...
++}
++
++Specific class of device (source, link, or sink) have generic operations
++that can be performed on them (see "struct coresight_ops").  The
++"**groups" is a list of sysfs entries pertaining to operations
++specific to that component only.  "Implementation defined" customisations are
++expected to be accessed and controlled using those entries.
++
++Last but not least, "struct module *owner" is expected to be set to reflect
++the information carried in "THIS_MODULE".
++
++How to use
++----------
++
++Before trace collection can start, a coresight sink needs to be identify.
++There is no limit on the amount of sinks (nor sources) that can be enabled at
++any given moment.  As a generic operation, all device pertaining to the sink
++class will have an "active" entry in sysfs:
++
++root:/sys/bus/coresight/devices# ls
++replicator  20030000.tpiu    2201c000.ptm  2203c000.etm  2203e000.etm
++20010000.etb         20040000.funnel  2201d000.ptm  2203d000.etm
++root:/sys/bus/coresight/devices# ls 20010000.etb
++enable_sink  status  trigger_cntr
++root:/sys/bus/coresight/devices# echo 1 > 20010000.etb/enable_sink
++root:/sys/bus/coresight/devices# cat 20010000.etb/enable_sink
++1
++root:/sys/bus/coresight/devices#
++
++At boot time the current etm3x driver will configure the first address
++comparator with "_stext" and "_etext", essentially tracing any instruction
++that falls within that range.  As such "enabling" a source will immediately
++trigger a trace capture:
++
++root:/sys/bus/coresight/devices# echo 1 > 2201c000.ptm/enable_source
++root:/sys/bus/coresight/devices# cat 2201c000.ptm/enable_source
++1
++root:/sys/bus/coresight/devices# cat 20010000.etb/status
++Depth:          0x2000
++Status:         0x1
++RAM read ptr:   0x0
++RAM wrt ptr:    0x19d3   <----- The write pointer is moving
++Trigger cnt:    0x0
++Control:        0x1
++Flush status:   0x0
++Flush ctrl:     0x2001
++root:/sys/bus/coresight/devices#
++
++Trace collection is stopped the same way:
++
++root:/sys/bus/coresight/devices# echo 0 > 2201c000.ptm/enable_source
++root:/sys/bus/coresight/devices#
++
++The content of the ETB buffer can be harvested directly from /dev:
++
++root:/sys/bus/coresight/devices# dd if=/dev/20010000.etb \
++of=~/cstrace.bin
++
++64+0 records in
++64+0 records out
++32768 bytes (33 kB) copied, 0.00125258 s, 26.2 MB/s
++root:/sys/bus/coresight/devices#
++
++The file cstrace.bin can be decompressed using "ptm2human", DS-5 or Trace32.
++
++Following is a DS-5 output of an experimental loop that increments a variable up
++to a certain value.  The example is simple and yet provides a glimpse of the
++wealth of possibilities that coresight provides.
++
++Info                                    Tracing enabled
++Instruction     106378866       0x8026B53C      E52DE004        false   PUSH     {lr}
++Instruction     0       0x8026B540      E24DD00C        false   SUB      sp,sp,#0xc
++Instruction     0       0x8026B544      E3A03000        false   MOV      r3,#0
++Instruction     0       0x8026B548      E58D3004        false   STR      r3,[sp,#4]
++Instruction     0       0x8026B54C      E59D3004        false   LDR      r3,[sp,#4]
++Instruction     0       0x8026B550      E3530004        false   CMP      r3,#4
++Instruction     0       0x8026B554      E2833001        false   ADD      r3,r3,#1
++Instruction     0       0x8026B558      E58D3004        false   STR      r3,[sp,#4]
++Instruction     0       0x8026B55C      DAFFFFFA        true    BLE      {pc}-0x10 ; 0x8026b54c
++Timestamp                                       Timestamp: 17106715833
++Instruction     319     0x8026B54C      E59D3004        false   LDR      r3,[sp,#4]
++Instruction     0       0x8026B550      E3530004        false   CMP      r3,#4
++Instruction     0       0x8026B554      E2833001        false   ADD      r3,r3,#1
++Instruction     0       0x8026B558      E58D3004        false   STR      r3,[sp,#4]
++Instruction     0       0x8026B55C      DAFFFFFA        true    BLE      {pc}-0x10 ; 0x8026b54c
++Instruction     9       0x8026B54C      E59D3004        false   LDR      r3,[sp,#4]
++Instruction     0       0x8026B550      E3530004        false   CMP      r3,#4
++Instruction     0       0x8026B554      E2833001        false   ADD      r3,r3,#1
++Instruction     0       0x8026B558      E58D3004        false   STR      r3,[sp,#4]
++Instruction     0       0x8026B55C      DAFFFFFA        true    BLE      {pc}-0x10 ; 0x8026b54c
++Instruction     7       0x8026B54C      E59D3004        false   LDR      r3,[sp,#4]
++Instruction     0       0x8026B550      E3530004        false   CMP      r3,#4
++Instruction     0       0x8026B554      E2833001        false   ADD      r3,r3,#1
++Instruction     0       0x8026B558      E58D3004        false   STR      r3,[sp,#4]
++Instruction     0       0x8026B55C      DAFFFFFA        true    BLE      {pc}-0x10 ; 0x8026b54c
++Instruction     7       0x8026B54C      E59D3004        false   LDR      r3,[sp,#4]
++Instruction     0       0x8026B550      E3530004        false   CMP      r3,#4
++Instruction     0       0x8026B554      E2833001        false   ADD      r3,r3,#1
++Instruction     0       0x8026B558      E58D3004        false   STR      r3,[sp,#4]
++Instruction     0       0x8026B55C      DAFFFFFA        true    BLE      {pc}-0x10 ; 0x8026b54c
++Instruction     10      0x8026B54C      E59D3004        false   LDR      r3,[sp,#4]
++Instruction     0       0x8026B550      E3530004        false   CMP      r3,#4
++Instruction     0       0x8026B554      E2833001        false   ADD      r3,r3,#1
++Instruction     0       0x8026B558      E58D3004        false   STR      r3,[sp,#4]
++Instruction     0       0x8026B55C      DAFFFFFA        true    BLE      {pc}-0x10 ; 0x8026b54c
++Instruction     6       0x8026B560      EE1D3F30        false   MRC      p15,#0x0,r3,c13,c0,#1
++Instruction     0       0x8026B564      E1A0100D        false   MOV      r1,sp
++Instruction     0       0x8026B568      E3C12D7F        false   BIC      r2,r1,#0x1fc0
++Instruction     0       0x8026B56C      E3C2203F        false   BIC      r2,r2,#0x3f
++Instruction     0       0x8026B570      E59D1004        false   LDR      r1,[sp,#4]
++Instruction     0       0x8026B574      E59F0010        false   LDR      r0,[pc,#16] ; [0x8026B58C] = 0x80550368
++Instruction     0       0x8026B578      E592200C        false   LDR      r2,[r2,#0xc]
++Instruction     0       0x8026B57C      E59221D0        false   LDR      r2,[r2,#0x1d0]
++Instruction     0       0x8026B580      EB07A4CF        true    BL       {pc}+0x1e9344 ; 0x804548c4
++Info                                    Tracing enabled
++Instruction     13570831        0x8026B584      E28DD00C        false   ADD      sp,sp,#0xc
++Instruction     0       0x8026B588      E8BD8000        true    LDM      sp!,{pc}
++Timestamp                                       Timestamp: 17107041535
+diff --git a/Documentation/trace/ftrace.txt b/Documentation/trace/ftrace.txt
+index 4da4261..0344f76 100644
+--- a/Documentation/trace/ftrace.txt
++++ b/Documentation/trace/ftrace.txt
+@@ -2043,6 +2043,35 @@ will produce:
+  1)   1.449 us    |             }
+ 
+ 
++You can disable the hierarchical function call formatting and instead print a
++flat list of function entry and return events.  This uses the format described
++in the Output Formatting section and respects all the trace options that
++control that formatting.  Hierarchical formatting is the default.
++
++	hierachical: echo nofuncgraph-flat > trace_options
++	flat: echo funcgraph-flat > trace_options
++
++  ie:
++
++  # tracer: function_graph
++  #
++  # entries-in-buffer/entries-written: 68355/68355   #P:2
++  #
++  #                              _-----=> irqs-off
++  #                             / _----=> need-resched
++  #                            | / _---=> hardirq/softirq
++  #                            || / _--=> preempt-depth
++  #                            ||| /     delay
++  #           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
++  #              | |       |   ||||       |         |
++                sh-1806  [001] d...   198.843443: graph_ent: func=_raw_spin_lock
++                sh-1806  [001] d...   198.843445: graph_ent: func=__raw_spin_lock
++                sh-1806  [001] d..1   198.843447: graph_ret: func=__raw_spin_lock
++                sh-1806  [001] d..1   198.843449: graph_ret: func=_raw_spin_lock
++                sh-1806  [001] d..1   198.843451: graph_ent: func=_raw_spin_unlock_irqrestore
++                sh-1806  [001] d...   198.843453: graph_ret: func=_raw_spin_unlock_irqrestore
++
++
+ You might find other useful features for this tracer in the
+ following "dynamic ftrace" section such as tracing only specific
+ functions or tasks.
+diff --git a/MAINTAINERS b/MAINTAINERS
+index c721042..0c921c8 100644
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -918,6 +918,14 @@ M:	Hubert Feurstein <hubert.feurstein@contec.at>
+ S:	Maintained
+ F:	arch/arm/mach-ep93xx/micro9.c
+ 
++ARM/CORESIGHT FRAMEWORK AND DRIVERS
++M:	Mathieu Poirier <mathieu.poirier@linaro.org>
++L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S:	Maintained
++F:	drivers/hwtracing/coresight/*
++F:	Documentation/trace/coresight.txt
++F:	Documentation/devicetree/bindings/arm/coresight.txt
++
+ ARM/CORGI MACHINE SUPPORT
+ M:	Richard Purdie <rpurdie@rpsys.net>
+ S:	Maintained
+@@ -9297,6 +9305,7 @@ Q:	https://patchwork.kernel.org/project/linux-pm/list/
+ S:	Supported
+ F:	drivers/thermal/
+ F:	include/linux/thermal.h
++F:	include/uapi/linux/thermal.h
+ F:	include/linux/cpu_cooling.h
+ F:	Documentation/devicetree/bindings/thermal/
+ 
+diff --git a/Makefile b/Makefile
+index 3ef5895..56992aa 100644
+--- a/Makefile
++++ b/Makefile
+@@ -2,7 +2,7 @@ VERSION = 3
+ PATCHLEVEL = 18
+ SUBLEVEL = 20
+ EXTRAVERSION =
+-NAME = Diseased Newt
++NAME = Shuffling Zombie Juror
+ 
+ # *DOCUMENTATION*
+ # To see a list of typical targets execute "make help"
+diff --git a/android/configs/README b/android/configs/README
+new file mode 100644
+index 0000000..8798731
+--- /dev/null
++++ b/android/configs/README
+@@ -0,0 +1,15 @@
++The files in this directory are meant to be used as a base for an Android
++kernel config. All devices should have the options in android-base.cfg enabled.
++While not mandatory, the options in android-recommended.cfg enable advanced
++Android features.
++
++Assuming you already have a minimalist defconfig for your device, a possible
++way to enable these options would be:
++
++     ARCH=<arch> scripts/kconfig/merge_config.sh <path_to>/<device>_defconfig android/configs/android-base.cfg android/configs/android-recommended.cfg
++
++This will generate a .config that can then be used to save a new defconfig or
++compile a new kernel with Android features enabled.
++
++Because there is no tool to consistently generate these config fragments,
++lets keep them alphabetically sorted instead of random.
+diff --git a/android/configs/android-base.cfg b/android/configs/android-base.cfg
+new file mode 100644
+index 0000000..154bf16
+--- /dev/null
++++ b/android/configs/android-base.cfg
+@@ -0,0 +1,160 @@
++#  KEEP ALPHABETICALLY SORTED
++# CONFIG_DEVKMEM is not set
++# CONFIG_DEVMEM is not set
++# CONFIG_INET_LRO is not set
++# CONFIG_MODULES is not set
++# CONFIG_OABI_COMPAT is not set
++CONFIG_ANDROID=y
++CONFIG_ANDROID_BINDER_IPC=y
++CONFIG_ANDROID_LOW_MEMORY_KILLER=y
++CONFIG_ARMV8_DEPRECATED=y
++CONFIG_ASHMEM=y
++CONFIG_AUDIT=y
++CONFIG_BLK_DEV_DM=y
++CONFIG_BLK_DEV_INITRD=y
++CONFIG_CGROUPS=y
++CONFIG_CGROUP_CPUACCT=y
++CONFIG_CGROUP_DEBUG=y
++CONFIG_CGROUP_FREEZER=y
++CONFIG_CGROUP_SCHED=y
++CONFIG_CP15_BARRIER_EMULATION=y
++CONFIG_DM_CRYPT=y
++CONFIG_DM_VERITY=y
++CONFIG_EMBEDDED=y
++CONFIG_FB=y
++CONFIG_HIGH_RES_TIMERS=y
++CONFIG_INET6_AH=y
++CONFIG_INET6_ESP=y
++CONFIG_INET6_IPCOMP=y
++CONFIG_INET=y
++CONFIG_INET_ESP=y
++CONFIG_INET_XFRM_MODE_TUNNEL=y
++CONFIG_IP6_NF_FILTER=y
++CONFIG_IP6_NF_IPTABLES=y
++CONFIG_IP6_NF_MANGLE=y
++CONFIG_IP6_NF_RAW=y
++CONFIG_IP6_NF_TARGET_REJECT=y
++CONFIG_IP6_NF_TARGET_REJECT_SKERR=y
++CONFIG_IPV6=y
++CONFIG_IPV6_MIP6=y
++CONFIG_IPV6_MULTIPLE_TABLES=y
++CONFIG_IPV6_OPTIMISTIC_DAD=y
++CONFIG_IPV6_PRIVACY=y
++CONFIG_IPV6_ROUTER_PREF=y
++CONFIG_IPV6_ROUTE_INFO=y
++CONFIG_IP_ADVANCED_ROUTER=y
++CONFIG_IP_MULTIPLE_TABLES=y
++CONFIG_IP_NF_ARPFILTER=y
++CONFIG_IP_NF_ARPTABLES=y
++CONFIG_IP_NF_ARP_MANGLE=y
++CONFIG_IP_NF_FILTER=y
++CONFIG_IP_NF_IPTABLES=y
++CONFIG_IP_NF_MANGLE=y
++CONFIG_IP_NF_MATCH_AH=y
++CONFIG_IP_NF_MATCH_ECN=y
++CONFIG_IP_NF_MATCH_TTL=y
++CONFIG_IP_NF_RAW=y
++CONFIG_IP_NF_SECURITY=y
++CONFIG_IP_NF_TARGET_MASQUERADE=y
++CONFIG_IP_NF_TARGET_NETMAP=y
++CONFIG_IP_NF_TARGET_REDIRECT=y
++CONFIG_IP_NF_TARGET_REJECT=y
++CONFIG_IP_NF_TARGET_REJECT_SKERR=y
++CONFIG_NET=y
++CONFIG_NETDEVICES=y
++CONFIG_NETFILTER=y
++CONFIG_NETFILTER_TPROXY=y
++CONFIG_NETFILTER_XT_MATCH_COMMENT=y
++CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
++CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
++CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
++CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
++CONFIG_NETFILTER_XT_MATCH_HELPER=y
++CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
++CONFIG_NETFILTER_XT_MATCH_LENGTH=y
++CONFIG_NETFILTER_XT_MATCH_LIMIT=y
++CONFIG_NETFILTER_XT_MATCH_MAC=y
++CONFIG_NETFILTER_XT_MATCH_MARK=y
++CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
++CONFIG_NETFILTER_XT_MATCH_POLICY=y
++CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
++CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
++CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
++CONFIG_NETFILTER_XT_MATCH_QUOTA=y
++CONFIG_NETFILTER_XT_MATCH_SOCKET=y
++CONFIG_NETFILTER_XT_MATCH_STATE=y
++CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
++CONFIG_NETFILTER_XT_MATCH_STRING=y
++CONFIG_NETFILTER_XT_MATCH_TIME=y
++CONFIG_NETFILTER_XT_MATCH_U32=y
++CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
++CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
++CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y
++CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y
++CONFIG_NETFILTER_XT_TARGET_MARK=y
++CONFIG_NETFILTER_XT_TARGET_NFLOG=y
++CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
++CONFIG_NETFILTER_XT_TARGET_SECMARK=y
++CONFIG_NETFILTER_XT_TARGET_TCPMSS=y
++CONFIG_NETFILTER_XT_TARGET_TPROXY=y
++CONFIG_NETFILTER_XT_TARGET_TRACE=y
++CONFIG_NET_CLS_ACT=y
++CONFIG_NET_CLS_U32=y
++CONFIG_NET_EMATCH=y
++CONFIG_NET_EMATCH_U32=y
++CONFIG_NET_KEY=y
++CONFIG_NET_SCHED=y
++CONFIG_NET_SCH_HTB=y
++CONFIG_NF_CONNTRACK=y
++CONFIG_NF_CONNTRACK_AMANDA=y
++CONFIG_NF_CONNTRACK_EVENTS=y
++CONFIG_NF_CONNTRACK_FTP=y
++CONFIG_NF_CONNTRACK_H323=y
++CONFIG_NF_CONNTRACK_IPV4=y
++CONFIG_NF_CONNTRACK_IPV6=y
++CONFIG_NF_CONNTRACK_IRC=y
++CONFIG_NF_CONNTRACK_NETBIOS_NS=y
++CONFIG_NF_CONNTRACK_PPTP=y
++CONFIG_NF_CONNTRACK_SANE=y
++CONFIG_NF_CONNTRACK_SECMARK=y
++CONFIG_NF_CONNTRACK_TFTP=y
++CONFIG_NF_CT_NETLINK=y
++CONFIG_NF_CT_PROTO_DCCP=y
++CONFIG_NF_CT_PROTO_SCTP=y
++CONFIG_NF_CT_PROTO_UDPLITE=y
++CONFIG_NF_NAT=y
++CONFIG_NO_HZ=y
++CONFIG_PACKET=y
++CONFIG_PM_AUTOSLEEP=y
++CONFIG_PM_WAKELOCKS=y
++CONFIG_PPP=y
++CONFIG_PPPOLAC=y
++CONFIG_PPPOPNS=y
++CONFIG_PPP_BSDCOMP=y
++CONFIG_PPP_DEFLATE=y
++CONFIG_PPP_MPPE=y
++CONFIG_PREEMPT=y
++CONFIG_RESOURCE_COUNTERS=y
++CONFIG_RTC_CLASS=y
++CONFIG_RT_GROUP_SCHED=y
++CONFIG_SECURITY=y
++CONFIG_SECURITY_NETWORK=y
++CONFIG_SECURITY_SELINUX=y
++CONFIG_SETEND_EMULATION=y
++CONFIG_STAGING=y
++CONFIG_SWITCH=y
++CONFIG_SWP_EMULATION=y
++CONFIG_SYNC=y
++CONFIG_SYSVIPC=y
++CONFIG_TUN=y
++CONFIG_UNIX=y
++CONFIG_USB_GADGET=y
++CONFIG_USB_CONFIGFS=y
++CONFIG_USB_CONFIGFS_F_FS=y
++CONFIG_USB_CONFIGFS_F_MTP=y
++CONFIG_USB_CONFIGFS_F_PTP=y
++CONFIG_USB_CONFIGFS_F_ACC=y
++CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y
++CONFIG_USB_CONFIGFS_UEVENT=y
++CONFIG_USB_OTG_WAKELOCK=y
++CONFIG_XFRM_USER=y
+diff --git a/android/configs/android-recommended.cfg b/android/configs/android-recommended.cfg
+new file mode 100644
+index 0000000..960b9de
+--- /dev/null
++++ b/android/configs/android-recommended.cfg
+@@ -0,0 +1,121 @@
++#  KEEP ALPHABETICALLY SORTED
++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
++# CONFIG_INPUT_MOUSE is not set
++# CONFIG_LEGACY_PTYS is not set
++# CONFIG_NF_CONNTRACK_SIP is not set
++# CONFIG_PM_WAKELOCKS_GC is not set
++# CONFIG_VT is not set
++CONFIG_ANDROID_TIMED_GPIO=y
++CONFIG_BACKLIGHT_LCD_SUPPORT=y
++CONFIG_BLK_DEV_LOOP=y
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_SIZE=8192
++CONFIG_COMPACTION=y
++CONFIG_DM_UEVENT=y
++CONFIG_DRAGONRISE_FF=y
++CONFIG_ENABLE_DEFAULT_TRACERS=y
++CONFIG_EXT4_FS=y
++CONFIG_EXT4_FS_SECURITY=y
++CONFIG_FUSE_FS=y
++CONFIG_GREENASIA_FF=y
++CONFIG_HIDRAW=y
++CONFIG_HID_A4TECH=y
++CONFIG_HID_ACRUX=y
++CONFIG_HID_ACRUX_FF=y
++CONFIG_HID_APPLE=y
++CONFIG_HID_BELKIN=y
++CONFIG_HID_CHERRY=y
++CONFIG_HID_CHICONY=y
++CONFIG_HID_CYPRESS=y
++CONFIG_HID_DRAGONRISE=y
++CONFIG_HID_ELECOM=y
++CONFIG_HID_EMS_FF=y
++CONFIG_HID_EZKEY=y
++CONFIG_HID_GREENASIA=y
++CONFIG_HID_GYRATION=y
++CONFIG_HID_HOLTEK=y
++CONFIG_HID_KENSINGTON=y
++CONFIG_HID_KEYTOUCH=y
++CONFIG_HID_KYE=y
++CONFIG_HID_LCPOWER=y
++CONFIG_HID_LOGITECH=y
++CONFIG_HID_LOGITECH_DJ=y
++CONFIG_HID_MAGICMOUSE=y
++CONFIG_HID_MICROSOFT=y
++CONFIG_HID_MONTEREY=y
++CONFIG_HID_MULTITOUCH=y
++CONFIG_HID_NTRIG=y
++CONFIG_HID_ORTEK=y
++CONFIG_HID_PANTHERLORD=y
++CONFIG_HID_PETALYNX=y
++CONFIG_HID_PICOLCD=y
++CONFIG_HID_PRIMAX=y
++CONFIG_HID_PRODIKEYS=y
++CONFIG_HID_ROCCAT=y
++CONFIG_HID_SAITEK=y
++CONFIG_HID_SAMSUNG=y
++CONFIG_HID_SMARTJOYPLUS=y
++CONFIG_HID_SONY=y
++CONFIG_HID_SPEEDLINK=y
++CONFIG_HID_SUNPLUS=y
++CONFIG_HID_THRUSTMASTER=y
++CONFIG_HID_TIVO=y
++CONFIG_HID_TOPSEED=y
++CONFIG_HID_TWINHAN=y
++CONFIG_HID_UCLOGIC=y
++CONFIG_HID_WACOM=y
++CONFIG_HID_WALTOP=y
++CONFIG_HID_WIIMOTE=y
++CONFIG_HID_ZEROPLUS=y
++CONFIG_HID_ZYDACRON=y
++CONFIG_INPUT_EVDEV=y
++CONFIG_INPUT_GPIO=y
++CONFIG_INPUT_JOYSTICK=y
++CONFIG_INPUT_KEYCHORD=y
++CONFIG_INPUT_KEYRESET=y
++CONFIG_INPUT_MISC=y
++CONFIG_INPUT_TABLET=y
++CONFIG_INPUT_UINPUT=y
++CONFIG_ION=y
++CONFIG_JOYSTICK_XPAD=y
++CONFIG_JOYSTICK_XPAD_FF=y
++CONFIG_JOYSTICK_XPAD_LEDS=y
++CONFIG_KALLSYMS_ALL=y
++CONFIG_KSM=y
++CONFIG_LOGIG940_FF=y
++CONFIG_LOGIRUMBLEPAD2_FF=y
++CONFIG_LOGITECH_FF=y
++CONFIG_MD=y
++CONFIG_MEDIA_SUPPORT=y
++CONFIG_MSDOS_FS=y
++CONFIG_PANIC_TIMEOUT=5
++CONFIG_PANTHERLORD_FF=y
++CONFIG_PERF_EVENTS=y
++CONFIG_PM_DEBUG=y
++CONFIG_PM_RUNTIME=y
++CONFIG_PM_WAKELOCKS_LIMIT=0
++CONFIG_POWER_SUPPLY=y
++CONFIG_PSTORE=y
++CONFIG_PSTORE_CONSOLE=y
++CONFIG_PSTORE_RAM=y
++CONFIG_SCHEDSTATS=y
++CONFIG_SMARTJOYPLUS_FF=y
++CONFIG_SND=y
++CONFIG_SOUND=y
++CONFIG_SUSPEND_TIME=y
++CONFIG_TABLET_USB_ACECAD=y
++CONFIG_TABLET_USB_AIPTEK=y
++CONFIG_TABLET_USB_GTCO=y
++CONFIG_TABLET_USB_HANWANG=y
++CONFIG_TABLET_USB_KBTAB=y
++CONFIG_TABLET_USB_WACOM=y
++CONFIG_TIMER_STATS=y
++CONFIG_TMPFS=y
++CONFIG_TMPFS_POSIX_ACL=y
++CONFIG_UHID=y
++CONFIG_UID_STAT=y
++CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
++CONFIG_USB_EHCI_HCD=y
++CONFIG_USB_HIDDEV=y
++CONFIG_USB_USBNET=y
++CONFIG_VFAT_FS=y
+diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
+index 89c4b5c..20c9e39 100644
+--- a/arch/arm/Kconfig
++++ b/arch/arm/Kconfig
+@@ -311,7 +311,7 @@ config ARCH_MULTIPLATFORM
+ 	select ARCH_WANT_OPTIONAL_GPIOLIB
+ 	select ARM_HAS_SG_CHAIN
+ 	select ARM_PATCH_PHYS_VIRT
+-	select AUTO_ZRELADDR
++    #select AUTO_ZRELADDR
+ 	select CLKSRC_OF
+ 	select COMMON_CLK
+ 	select GENERIC_CLOCKEVENTS
+@@ -1311,6 +1311,7 @@ source "drivers/pci/Kconfig"
+ source "drivers/pci/pcie/Kconfig"
+ 
+ source "drivers/pcmcia/Kconfig"
++source "drivers/pci/hipcie/Kconfig"
+ 
+ endmenu
+ 
+@@ -1385,6 +1386,107 @@ config SCHED_SMT
+ 	  MultiThreading at a cost of slightly increased overhead in some
+ 	  places. If unsure say N here.
+ 
++config DISABLE_CPU_SCHED_DOMAIN_BALANCE
++	bool "(EXPERIMENTAL) Disable CPU level scheduler load-balancing"
++	help
++	  Disables scheduler load-balancing at CPU sched domain level.
++
++config SCHED_HMP
++	bool "(EXPERIMENTAL) Heterogenous multiprocessor scheduling"
++	depends on DISABLE_CPU_SCHED_DOMAIN_BALANCE && SCHED_MC && FAIR_GROUP_SCHED && !SCHED_AUTOGROUP
++	help
++	  Experimental scheduler optimizations for heterogeneous platforms.
++	  Attempts to introspectively select task affinity to optimize power
++	  and performance. Basic support for multiple (>2) cpu types is in place,
++	  but it has only been tested with two types of cpus.
++	  There is currently no support for migration of task groups, hence
++	  !SCHED_AUTOGROUP. Furthermore, normal load-balancing must be disabled
++	  between cpus of different type (DISABLE_CPU_SCHED_DOMAIN_BALANCE).
++	  When turned on, this option adds sys/kernel/hmp directory which
++	  contains the following files:
++	  up_threshold - the load average threshold used for up migration
++	                 (0 - 1023)
++	  down_threshold - the load average threshold used for down migration
++	                 (0 - 1023)
++	  hmp_domains - a list of cpumasks for the present HMP domains,
++	                starting with the 'biggest' and ending with the
++	                'smallest'.
++	  Note that both the threshold files can be written at runtime to
++	  control scheduler behaviour.
++
++config SCHED_HMP_PRIO_FILTER
++	bool "(EXPERIMENTAL) Filter HMP migrations by task priority"
++	depends on SCHED_HMP
++	help
++	  Enables task priority based HMP migration filter. Any task with
++	  a NICE value above the threshold will always be on low-power cpus
++	  with less compute capacity.
++
++config SCHED_HMP_PRIO_FILTER_VAL
++	int "NICE priority threshold"
++	default 5
++	depends on SCHED_HMP_PRIO_FILTER
++
++config HMP_FAST_CPU_MASK
++       string "HMP scheduler fast CPU mask"
++       depends on SCHED_HMP
++       help
++          Specify the cpuids of the fast CPUs in the system as a list string,
++          e.g. cpuid 0+1 should be specified as 0-1.
++
++config HMP_SLOW_CPU_MASK
++       string "HMP scheduler slow CPU mask"
++       depends on SCHED_HMP
++       help
++         Specify the cpuids of the slow CPUs in the system as a list string,
++         e.g. cpuid 0+1 should be specified as 0-1.
++
++config HMP_VARIABLE_SCALE
++	bool "Allows changing the load tracking scale through sysfs"
++	depends on SCHED_HMP
++	help
++	  When turned on, this option exports the load average period value
++	  for the load tracking patches through sysfs.
++	  The values can be modified to change the rate of load accumulation
++	  used for HMP migration. 'load_avg_period_ms' is the time in ms to
++	  reach a load average of 0.5 for an idle task of 0 load average
++	  ratio which becomes 100% busy.
++	  For example, with load_avg_period_ms = 128 and up_threshold = 512,
++	  a running task with a load of 0 will be migrated to a bigger CPU after
++	  128ms, because after 128ms its load_avg_ratio is 0.5 and the real
++	  up_threshold is 0.5.
++	  This patch has the same behavior as changing the Y of the load
++	  average computation to
++	        (1002/1024)^(LOAD_AVG_PERIOD/load_avg_period_ms)
++	  but removes intermediate overflows in computation.
++
++config HMP_FREQUENCY_INVARIANT_SCALE
++	bool "(EXPERIMENTAL) Frequency-Invariant Tracked Load for HMP"
++	depends on SCHED_HMP && CPU_FREQ
++	help
++	  Scales the current load contribution in line with the frequency
++	  of the CPU that the task was executed on.
++	  In this version, we use a simple linear scale derived from the
++	  maximum frequency reported by CPUFreq.
++	  Restricting tracked load to be scaled by the CPU's frequency
++	  represents the consumption of possible compute capacity
++	  (rather than consumption of actual instantaneous capacity as
++	  normal) and allows the HMP migration's simple threshold
++	  migration strategy to interact more predictably with CPUFreq's
++	  asynchronous compute capacity changes.
++
++config SCHED_HMP_LITTLE_PACKING
++	bool "Small task packing for HMP"
++	depends on SCHED_HMP
++	default n
++	help
++	  Allows the HMP Scheduler to pack small tasks into CPUs in the
++	  smallest HMP domain.
++	  Controlled by two sysfs files in sys/kernel/hmp.
++	  packing_enable: 1 to enable, 0 to disable packing. Default 1.
++	  packing_limit: runqueue load ratio where a RQ is considered
++	    to be full. Default is NICE_0_LOAD * 9/8.
++
+ config HAVE_ARM_SCU
+ 	bool
+ 	help
+@@ -1790,6 +1892,15 @@ config XEN
+ 	help
+ 	  Say Y if you want to run Linux in a Virtual Machine on Xen on ARM.
+ 
++config ARM_FLUSH_CONSOLE_ON_RESTART
++	bool "Force flush the console on restart"
++	help
++	  If the console is locked while the system is rebooted, the messages
++	  in the temporary logbuffer would not have propogated to all the
++	  console drivers. This option forces the console lock to be
++	  released if it failed to be acquired, which will cause all the
++	  pending messages to be flushed.
++
+ endmenu
+ 
+ menu "Boot options"
+@@ -1820,6 +1931,21 @@ config DEPRECATED_PARAM_STRUCT
+ 	  This was deprecated in 2001 and announced to live on for 5 years.
+ 	  Some old boot loaders still use this way.
+ 
++config BUILD_ARM_APPENDED_DTB_IMAGE
++	bool "Build a concatenated zImage/dtb by default"
++	depends on OF
++	help
++	  Enabling this option will cause a concatenated zImage and list of
++	  DTBs to be built by default (instead of a standalone zImage.)
++	  The image will built in arch/arm/boot/zImage-dtb
++
++config BUILD_ARM_APPENDED_DTB_IMAGE_NAMES
++	string "Default dtb names"
++	depends on BUILD_ARM_APPENDED_DTB_IMAGE
++	help
++	  Space separated list of names of dtbs to append when
++	  building a concatenated zImage-dtb.
++
+ # Compressed boot loader in ROM.  Yes, we really want to ask about
+ # TEXT and BSS so we preserve their values in the config files.
+ config ZBOOT_ROM_TEXT
+diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
+index d8f6a2e..74debb3 100644
+--- a/arch/arm/Kconfig.debug
++++ b/arch/arm/Kconfig.debug
+@@ -232,6 +232,77 @@ choice
+ 		  Say Y here if you want kernel low-level debugging support
+ 		  on HI3716 UART.
+ 
++	config DEBUG_HI3516CV300_UART
++		bool "Hisilicon Hi3516cv300 Debug UART"
++		depends on ARCH_HI3516CV300
++		select DEBUG_UART_PL01X
++		help
++		  Say Y here if you want kernel low-level debugging support
++		  on HI3516CV300 UART.
++
++	config DEBUG_HI3519_UART
++		bool "Hisilicon Hi3519 Debug UART"
++		depends on ARCH_HI3519
++		select DEBUG_UART_PL01X
++		help
++		  Say Y here if you want kernel low-level debugging support
++		  on HI3519 UART.
++
++	config DEBUG_HI3519V101_UART
++		bool "Hisilicon Hi3519V101 Debug UART"
++		depends on ARCH_HI3519V101
++		select DEBUG_UART_PL01X
++		help
++		  Say Y here if you want kernel low-level debugging support
++		  on HI3519V101 UART.
++
++	config DEBUG_HI3559_UART
++		bool "Hisilicon Hi3559 Debug UART"
++		depends on ARCH_HI3559
++		select DEBUG_UART_PL01X
++		help
++		  Say Y here if you want kernel low-level debugging support
++		  on HI3559 UART.
++
++	config DEBUG_HI3516AV200_UART
++		bool "Hisilicon Hi3516AV200 Debug UART"
++		depends on ARCH_HI3516AV200
++		select DEBUG_UART_PL01X
++		help
++		  Say Y here if you want kernel low-level debugging support
++		  on HI3516AV200 UART.
++
++	config DEBUG_HI3556_UART
++		bool "Hisilicon Hi3556 Debug UART"
++		depends on ARCH_HI3556
++		select DEBUG_UART_PL01X
++		help
++		  Say Y here if you want kernel low-level debugging support
++		  on HI3556 UART.
++	config DEBUG_HI3536C_UART
++		bool "Hisilicon Hi3536C Debug UART"
++		depends on ARCH_HI3536C
++		select DEBUG_UART_PL01X
++		help
++		  Say Y here if you want kernel low-level debugging support
++		  on HI3536C UART.
++
++	config DEBUG_HI3531D_UART
++		bool "Hisilicon Hi3531D Debug UART"
++		depends on ARCH_HI3531D
++		select DEBUG_UART_PL01X
++		help
++		  Say Y here if you want kernel low-level debugging support
++		  on HI3531D UART.
++
++	config DEBUG_HI3521D_UART
++		bool "Hisilicon Hi3521D Debug UART"
++		depends on ARCH_HI3521D
++		select DEBUG_UART_PL01X
++		help
++		  Say Y here if you want kernel low-level debugging support
++		  on HI3521D UART.
++
+ 	config DEBUG_HIGHBANK_UART
+ 		bool "Kernel low-level debugging messages via Highbank UART"
+ 		depends on ARCH_HIGHBANK
+@@ -1160,6 +1231,15 @@ config DEBUG_UART_PHYS
+ 	default 0xf8b00000 if DEBUG_HIX5HD2_UART
+ 	default 0xf991e000 if DEBUG_QCOM_UARTDM
+ 	default 0xfcb00000 if DEBUG_HI3620_UART
++	default 0x12100000 if DEBUG_HI3516CV300_UART
++	default 0x12100000 if DEBUG_HI3519_UART
++	default 0x12100000 if DEBUG_HI3519V101_UART
++	default 0x12100000 if DEBUG_HI3516AV200_UART
++	default 0x12100000 if DEBUG_HI3559_UART
++	default 0x12100000 if DEBUG_HI3556_UART
++	default 0x12080000 if DEBUG_HI3536C_UART
++	default 0x12080000 if DEBUG_HI3531D_UART
++	default 0x12080000 if DEBUG_HI3521D_UART
+ 	default 0xfe800000 if ARCH_IOP32X
+ 	default 0xff690000 if DEBUG_RK32_UART2
+ 	default 0xffc02000 if DEBUG_SOCFPGA_UART
+@@ -1218,6 +1298,15 @@ config DEBUG_UART_VIRT
+ 	default 0xfe300000 if DEBUG_BCM_KONA_UART
+ 	default 0xfe800000 if ARCH_IOP32X
+ 	default 0xfeb00000 if DEBUG_HI3620_UART || DEBUG_HIX5HD2_UART
++	default 0xfef00000 if DEBUG_HI3516CV300_UART
++	default 0xfef00000 if DEBUG_HI3519_UART
++	default 0xfef00000 if DEBUG_HI3519V101_UART
++	default 0xfef00000 if DEBUG_HI3516AV200_UART
++	default 0xfef00000 if DEBUG_HI3559_UART
++	default 0xfef00000 if DEBUG_HI3556_UART
++	default 0xfe480000 if DEBUG_HI3536C_UART
++	default 0xfe880000 if DEBUG_HI3531D_UART
++	default 0xfe480000 if DEBUG_HI3521D_UART
+ 	default 0xfeb24000 if DEBUG_RK3X_UART0
+ 	default 0xfeb26000 if DEBUG_RK3X_UART1
+ 	default 0xfeb30c00 if DEBUG_KEYSTONE_UART0
+@@ -1299,7 +1388,7 @@ config EARLY_PRINTK
+ 
+ config OC_ETM
+ 	bool "On-chip ETM and ETB"
+-	depends on ARM_AMBA
++	depends on ARM_AMBA && !CORESIGHT
+ 	help
+ 	  Enables the on-chip embedded trace macrocell and embedded trace
+ 	  buffer driver that will allow you to collect traces of the
+@@ -1331,4 +1420,6 @@ config DEBUG_SET_MODULE_RONX
+ 	  against certain classes of kernel exploits.
+ 	  If in doubt, say "N".
+ 
++source "drivers/hwtracing/coresight/Kconfig"
++
+ endmenu
+diff --git a/arch/arm/Makefile b/arch/arm/Makefile
+index 034a949..d2b2bfb 100644
+--- a/arch/arm/Makefile
++++ b/arch/arm/Makefile
+@@ -50,6 +50,14 @@ AS		+= -EL
+ LD		+= -EL
+ endif
+ 
++#
++# The Scalar Replacement of Aggregates (SRA) optimization pass in GCC 4.9 and
++# later may result in code being generated that handles signed short and signed
++# char struct members incorrectly. So disable it.
++# (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65932)
++#
++KBUILD_CFLAGS   += $(call cc-option,-fno-ipa-sra)
++
+ # This selects which instruction set is used.
+ # Note that GCC does not numerically define an architecture version
+ # macro, but instead defines a whole series of macros which makes
+@@ -278,6 +286,8 @@ libs-y				:= arch/arm/lib/ $(libs-y)
+ # Default target when executing plain make
+ ifeq ($(CONFIG_XIP_KERNEL),y)
+ KBUILD_IMAGE := xipImage
++else ifeq ($(CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE),y)
++KBUILD_IMAGE := zImage-dtb
+ else
+ KBUILD_IMAGE := zImage
+ endif
+@@ -312,8 +322,15 @@ $(INSTALL_TARGETS):
+ 	$(Q)$(MAKE) $(build)=$(boot)/dts MACHINE=$(MACHINE) $(boot)/dts/$@
+ 
+ PHONY += dtbs dtbs_install
+-dtbs dtbs_install: prepare scripts
+-	$(Q)$(MAKE) $(build)=$(boot)/dts MACHINE=$(MACHINE) $@
++
++dtbs: prepare scripts
++	$(Q)$(MAKE) $(build)=$(boot)/dts MACHINE=$(MACHINE)
++
++dtbs_install:
++	$(Q)$(MAKE) $(dtbinst)=$(boot)/dts MACHINE=$(MACHINE)
++
++zImage-dtb: vmlinux scripts dtbs
++	$(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@
+ 
+ # We use MRPROPER_FILES and CLEAN_FILES now
+ archclean:
+diff --git a/arch/arm/boot/.gitignore b/arch/arm/boot/.gitignore
+index 3c79f85..ad7a025 100644
+--- a/arch/arm/boot/.gitignore
++++ b/arch/arm/boot/.gitignore
+@@ -4,3 +4,4 @@ xipImage
+ bootpImage
+ uImage
+ *.dtb
++zImage-dtb
+\ No newline at end of file
+diff --git a/arch/arm/boot/Makefile b/arch/arm/boot/Makefile
+index ec2f806..afe52d3 100644
+--- a/arch/arm/boot/Makefile
++++ b/arch/arm/boot/Makefile
+@@ -14,6 +14,8 @@
+ ifneq ($(MACHINE),)
+ include $(srctree)/$(MACHINE)/Makefile.boot
+ endif
++include $(srctree)/arch/arm/mach-hisi/Makefile.boot
++include $(srctree)/arch/arm/boot/dts/Makefile
+ 
+ # Note: the following conditions must always be true:
+ #   ZRELADDR == virt_to_phys(PAGE_OFFSET + TEXT_OFFSET)
+@@ -25,7 +27,15 @@ INITRD_PHYS := $(initrd_phys-y)
+ 
+ export ZRELADDR INITRD_PHYS PARAMS_PHYS
+ 
+-targets := Image zImage xipImage bootpImage uImage
++targets := Image zImage xipImage bootpImage uImage zImage-dtb
++
++DTB_NAMES := $(subst $\",,$(CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE_NAMES))
++ifneq ($(DTB_NAMES),)
++DTB_LIST := $(addsuffix .dtb,$(DTB_NAMES))
++else
++DTB_LIST := $(dtb-y)
++endif
++DTB_OBJS := $(addprefix $(obj)/dts/,$(DTB_LIST))
+ 
+ ifeq ($(CONFIG_XIP_KERNEL),y)
+ 
+@@ -55,6 +65,10 @@ $(obj)/zImage:	$(obj)/compressed/vmlinux FORCE
+ 	$(call if_changed,objcopy)
+ 	@$(kecho) '  Kernel: $@ is ready'
+ 
++$(obj)/zImage-dtb:	$(obj)/zImage $(DTB_OBJS) FORCE
++	$(call if_changed,cat)
++	@echo '  Kernel: $@ is ready'
++
+ endif
+ 
+ ifneq ($(LOADADDR),)
+@@ -75,7 +89,7 @@ if [ $(words $(UIMAGE_LOADADDR)) -ne 1 ]; then \
+ 	false; \
+ fi
+ 
+-$(obj)/uImage:	$(obj)/zImage FORCE
++$(obj)/uImage:	$(obj)/zImage-dtb FORCE
+ 	@$(check_for_multiple_loadaddr)
+ 	$(call if_changed,uimage)
+ 	@$(kecho) '  Image $@ is ready'
+diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile
+index 3ea230a..57bae7b 100644
+--- a/arch/arm/boot/compressed/Makefile
++++ b/arch/arm/boot/compressed/Makefile
+@@ -23,7 +23,11 @@ endif
+ 
+ AFLAGS_head.o += -DTEXT_OFFSET=$(TEXT_OFFSET)
+ HEAD	= head.o
++ifeq ($(CONFIG_HW_DECOMPRESS),y)
++OBJS	+= misc.o hw_decompress.o
++else
+ OBJS	+= misc.o decompress.o
++endif
+ ifeq ($(CONFIG_DEBUG_UNCOMPRESS),y)
+ OBJS	+= debug.o
+ endif
+diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S
+index 68be901..aaf54a8 100644
+--- a/arch/arm/boot/compressed/head.S
++++ b/arch/arm/boot/compressed/head.S
+@@ -176,6 +176,16 @@ not_angel:
+ 		ldr	r4, =zreladdr
+ #endif
+ 
++#if (defined CONFIG_ARCH_HI3519 || defined CONFIG_ARCH_HI3519V101\
++    || defined CONFIG_ARCH_HI3559 || defined CONFIG_ARCH_HI3556 || defined CONFIG_ARCH_HI3516AV200)
++		/*
++		 * set SMP bit ACTLR register to enable I cache and D cache
++		 */
++		mrc     p15, 0, r0, c1, c0, 1
++		orr     r0, #(1 << 6)
++		mcr     p15, 0, r0, c1, c0, 1
++#endif
++
+ 		/*
+ 		 * Set up a page table only if it won't overwrite ourself.
+ 		 * That means r4 < pc && r4 - 16k page directory > &_end.
+@@ -730,6 +740,8 @@ __armv7_mmu_cache_on:
+ 		bic     r6, r6, #1 << 31        @ 32-bit translation system
+ 		bic     r6, r6, #3 << 0         @ use only ttbr0
+ 		mcrne	p15, 0, r3, c2, c0, 0	@ load page table pointer
++		mcrne	p15, 0, r0, c8, c7, 0	@ flush I,D TLBs
++		mcr	p15, 0, r0, c7, c5, 4	@ ISB
+ 		mcrne	p15, 0, r1, c3, c0, 0	@ load domain access control
+ 		mcrne   p15, 0, r6, c2, c0, 2   @ load ttb control
+ #endif
+diff --git a/arch/arm/boot/compressed/hw_decompress.c b/arch/arm/boot/compressed/hw_decompress.c
+new file mode 100644
+index 0000000..20cd896
+--- /dev/null
++++ b/arch/arm/boot/compressed/hw_decompress.c
+@@ -0,0 +1,266 @@
++#include"hw_decompress.h"
++#if defined(CONFIG_ARCH_HI3559) || defined(CONFIG_ARCH_HI3556)
++#include"hw_decompress_hi3559.h"
++#endif
++
++static inline void udelay(unsigned long loops)
++{
++	__asm__ volatile ("1:\n"
++			"subs %0, %1, #1\n"
++			"bne 1b" : "=r" (loops) : "0" (loops));
++}
++
++unsigned int hw_dec_type = 0;
++unsigned int hw_dec_sop = 0;
++unsigned int hw_dec_eop = 0;
++unsigned int hw_dec_cur_blk = 0;
++unsigned int hw_blk_total_num = 0;
++
++void hw_dec_sop_eop_first_set(int block_num)
++{
++	if (block_num == 1) {
++		hw_dec_sop = 1;
++		hw_dec_eop = 1;
++	} else {
++		hw_dec_sop = 1;
++		hw_dec_eop = 0;
++	}
++
++	hw_dec_type = 0;
++	hw_dec_cur_blk = 0;
++	hw_blk_total_num = block_num;
++}
++
++static inline void hw_dec_work_en_set(unsigned int work_en_flg)
++{
++	/* Enable the emar*/
++	writel(work_en_flg, (void *)(HW_DEC_REG_BASE_ADDR + EAMR_WORK_EN_REG_OFST));
++}
++
++static inline void hw_dec_rtn_baddr_set(unsigned int addr)
++{
++	writel(addr, (void *)(HW_DEC_REG_BASE_ADDR + DPRS_DATA_RTN_BADDR));
++}
++
++static inline void hw_dec_dprs_data_baddr_set(unsigned int addr)
++{
++	writel(addr, (void *)(HW_DEC_REG_BASE_ADDR + DPRS_DATA_INFO_BADDR));
++}
++
++static inline void hw_dec_data_rtn_len_set(unsigned int len)
++{
++	writel(len, (void *)(HW_DEC_REG_BASE_ADDR + DPRS_DATA_RTN_LEN));
++}
++
++static inline void hw_dec_dprs_data_len_set(unsigned int len)
++{
++	writel(len, (void *)(HW_DEC_REG_BASE_ADDR + DPRS_DATA_INFO_LEN));
++}
++
++static inline void hw_dec_crc_check_en(unsigned int crc_en)
++{
++	writel(crc_en, (void *)(HW_DEC_REG_BASE_ADDR + CRC_CHECK_EN));
++}
++
++static inline void hw_dec_data_crc32_set(unsigned int crc32)
++{
++	writel(crc32, (void *)(HW_DEC_REG_BASE_ADDR + DPRS_DATA_CRC32));
++}
++
++static inline unsigned int hw_dec_buf_status_get(void)
++{
++	return readl((void *)(HW_DEC_REG_BASE_ADDR + BUF_INFO));
++}
++
++static inline unsigned int hw_dec_dprs_rtn_status_get(void)
++{
++	return readl((void *)(HW_DEC_REG_BASE_ADDR + DPRS_RTN_INFO));
++}
++
++static inline void hw_dec_buf_status_clr(void)
++{
++	writel(0x1, (void *)(HW_DEC_REG_BASE_ADDR + BUF_INFO_CLR));
++}
++
++static inline void hw_dec_dprs_rtn_status_clr(void)
++{
++	writel(0x1, (void *)(HW_DEC_REG_BASE_ADDR + RLT_INFO_CLR));
++}
++
++static inline void hw_dec_intr_en_set(int blk_intr_en, int task_intr_en)
++{
++	U_INTR_EN intr_en;
++	intr_en.bits.task_intrpt_en = task_intr_en;
++	intr_en.bits.block_intrpt_en = blk_intr_en;
++	writel(intr_en.u32, (void *)(HW_DEC_REG_BASE_ADDR + INT_EN_REG_ADDR));
++}
++
++static inline unsigned int hw_dec_intr_status_get(void)
++{
++	return readl((void *)(HW_DEC_REG_BASE_ADDR + INT_STATUS_REG_ADDR));
++}
++
++static inline void hw_dec_block_intr_status_clr(void)
++{
++	U_INTR_CLR intr_clr;
++
++	intr_clr.u32 = readl((void *)(HW_DEC_REG_BASE_ADDR + INT_CLEAR_REG_ADDR));
++	intr_clr.bits.block_intrpt_clr = 0x1;
++	writel(intr_clr.u32, (void *)(HW_DEC_REG_BASE_ADDR + INT_CLEAR_REG_ADDR));
++}
++
++static inline void hw_dec_task_intr_status_clr(void)
++{
++	U_INTR_CLR intr_clr;
++
++	intr_clr.u32 = readl((void *)(HW_DEC_REG_BASE_ADDR + INT_CLEAR_REG_ADDR));
++	intr_clr.bits.task_intrpt_clr = 0x1;
++	writel(intr_clr.u32, (void *)(HW_DEC_REG_BASE_ADDR + INT_CLEAR_REG_ADDR));
++}
++
++int hw_dec_intr_proc(int irq, void *para)
++{
++	U_BUF_STATUS buf_status;
++	U_INTR_STATUS intr_status;
++	U_DPRS_RTN_STATUS dprs_status;
++
++	intr_status.u32 = hw_dec_intr_status_get();
++	if (intr_status.bits.block_intrpt) {
++		buf_status.u32 = hw_dec_buf_status_get();
++		if (buf_status.bits.aval_flg)
++			hw_dec_buf_status_clr();
++
++		hw_dec_block_intr_status_clr();
++	}
++
++	if (intr_status.bits.task_intrpt) {
++		dprs_status.u32 = hw_dec_dprs_rtn_status_get();
++		if (dprs_status.bits.aval_flg) {
++			if (dprs_status.bits.err_info) {
++				// printk("err = 0x%x, dec_data_len = 0x%x\n",
++					// dprs_status.bits.err_info,
++					// readl(HW_DEC_REG_BASE_ADDR
++						// + DPRS_RTN_LEN));
++			}
++			hw_dec_dprs_rtn_status_clr();
++		}
++
++		hw_dec_task_intr_status_clr();
++		return 0;
++	}
++
++	return -1;
++}
++
++void hw_dec_start(unsigned int src_baddr,
++			unsigned int dst_baddr,
++			unsigned int src_len,
++			unsigned int dst_len,
++			unsigned int crc_en,
++			unsigned int crc32,
++			unsigned int dec_type)
++{
++	unsigned int val;
++
++	if (hw_dec_sop) {
++		if (!dec_type) {
++			/* set the parameters of output buffer */
++			hw_dec_rtn_baddr_set(dst_baddr);
++			hw_dec_data_rtn_len_set(dst_len);
++		} else {
++			/* set the parameter of output buffer */
++			hw_dec_dprs_data_baddr_set(dst_baddr);
++			hw_dec_dprs_data_len_set(PAGE_NR(dst_len) * 4);
++		}
++	}
++
++	/* set the parameter of input buffer */
++	writel(src_baddr, (void *)(HW_DEC_REG_BASE_ADDR + DPRS_DATA_SRC_BADDR));
++
++	val = src_len | (hw_dec_sop << 28)
++		| (hw_dec_eop << 29) | (!dec_type << 31);
++	writel(val, (void *)(HW_DEC_REG_BASE_ADDR + DPRS_DATA_SRC_LEN));
++
++	hw_dec_crc_check_en(crc_en);
++}
++
++int hw_dec_wait_finish(void)
++{
++	int ret;
++	int times = 0;
++
++	do {
++		ret = hw_dec_intr_proc(HW_DEC_INTR, NULL);
++		times++;
++		if (times > 100000) {
++			// printk("hardware decompress overtime!"
++					// " func:%s, line:%d\n",
++					// __func__, __LINE__);
++			times = 0;
++			break;
++		}
++
++		udelay(1000);
++	} while (-1 == ret);
++
++	return ret;
++}
++
++void hw_gzip_init(void)
++{
++	enable_decompress_clock();
++	/* Init the emar interface */
++	writel(0, (void *)(HW_DEC_REG_BASE_ADDR + EAMR_RID_REG_OFST));
++	writel(0x3, (void *)(HW_DEC_REG_BASE_ADDR + EAMR_ROSD_REG_OFST));
++	writel(0, (void *)(HW_DEC_REG_BASE_ADDR + EAMR_WID_REG_OFST));
++	writel(0x3, (void *)(HW_DEC_REG_BASE_ADDR + EAMR_WOSD_REG_OFST));
++
++	/*Enable interrupt*/
++	hw_dec_intr_en_set(0x1, 0x1);
++
++	/* Enable emar*/
++	hw_dec_work_en_set(0x1);
++}
++
++int hw_gzip_dec(unsigned int dst, int *dstlen, unsigned int src, int srclen)
++{
++	int ret;
++
++	hw_dec_sop_eop_first_set(1);
++
++	hw_dec_start(src, dst, srclen, *dstlen, 0, 0, hw_dec_type);
++
++	ret = hw_dec_wait_finish();
++	if (ret)
++		return -1;
++
++    //*dstlen = readl(HW_DEC_REG_BASE_ADDR + DPRS_RTN_LEN);
++
++	return 0;
++}
++
++void hw_gzip_exit(void)
++{
++	/*Disable emar*/
++	hw_dec_work_en_set(0x0);
++
++	/*Disable interrupt*/
++	hw_dec_intr_en_set(0x0, 0x0);
++	disable_decompress_clock();
++}
++
++
++int do_decompress(u8 *input, int len, u8 *output, void (*error)(char *x))
++{
++    unsigned int src_pa = (unsigned long)input;
++    unsigned int dst_pa = (unsigned long)output;
++    int dstlen = 0x800000;
++
++    hw_gzip_init();
++
++    hw_gzip_dec(dst_pa, &dstlen, src_pa, len);
++
++    hw_gzip_exit();
++
++    return 0;
++}
+diff --git a/arch/arm/boot/compressed/hw_decompress.h b/arch/arm/boot/compressed/hw_decompress.h
+new file mode 100644
+index 0000000..053c419
+--- /dev/null
++++ b/arch/arm/boot/compressed/hw_decompress.h
+@@ -0,0 +1,130 @@
++#include <linux/io.h>
++
++/* for fast boot */
++#define HW_DEC_INTR		(73)
++
++/* These are same definition as in linux 2.6.11 kernel. */
++//#define PAGE_SIZE	4096
++#define PAGE_NR(x) (((x)+PAGE_SIZE-1)/PAGE_SIZE)
++#define __ALIGN_UP(x,y) (((x)+(y)-1) & (~((y)-1)))
++
++/* The base address for emar*/
++#define HW_DEC_REG_BASE_ADDR	(0x110c0000)
++
++/* The global init registers for emar interface */
++#define EAMR_RID_REG_OFST	(0x0108)
++#define EAMR_ROSD_REG_OFST	(0x010C)
++#define EAMR_WID_REG_OFST	(0x0110)
++#define EAMR_WOSD_REG_OFST	(0x0114)
++
++/* The enable register */
++#define EAMR_WORK_EN_REG_OFST	(0x0100)
++
++#define DPRS_DATA_SRC_BADDR	(0x2040)
++#define DPRS_DATA_SRC_LEN	(0x2044)
++
++/* Decompress parameter reigsters for page address */
++#define DPRS_DATA_RTN_BADDR	(0x2020)
++#define DPRS_DATA_RTN_LEN	(0x2024)
++
++/* Decompress parameter registers for page data */
++#define DPRS_DATA_INFO_BADDR	(0x2028)
++#define DPRS_DATA_INFO_LEN	(0x202C)
++
++#define DPRS_DATA_CRC32		(0x2030)
++
++#define CRC_CHECK_EN        (0x4000)
++
++/* The status registers*/
++#define BUF_INFO			(0x2080)
++#define DPRS_RTN_INFO		(0x2084)
++#define DPRS_RTN_LEN		(0x2088)
++#define BUF_INFO_CLR		(0x2090)
++#define RLT_INFO_CLR		(0x2094)
++
++/* The intr registers*/
++#define INT_EN_REG_ADDR		(0x0128)
++#define INT_STATUS_REG_ADDR	(0x0124)
++#define INT_CLEAR_REG_ADDR	(0x0130)
++
++/* Define the union U_DPRS_DATA_BUF_INFO */
++typedef union {
++	/* Define the struct bits */
++	struct {
++		unsigned int    buf_len:24; /* [23..0] */
++		unsigned int    buf_id:2; /* [25..24] */
++		unsigned int    reserved_1:2; /* [27..26] */
++		unsigned int    eop:1; /* [28] */
++		unsigned int    sop:1; /* [29] */
++		unsigned int    reserved_0:1; /* [30] */
++		unsigned int    mode:1; /* [31] */
++	} bits;
++
++	/* Define an unsigned member */
++	unsigned int    u32;
++
++} U_DPRS_DATA_BUF_INFO;
++
++typedef union {
++	struct {
++		unsigned int buf_id:2;	/* [1:0] */
++		unsigned int rsv:29;	/* [30:2] */
++		unsigned int aval_flg:1;	/* [31] */
++	} bits;
++	unsigned int u32;
++} U_BUF_STATUS;
++
++typedef union {
++	struct {
++		unsigned int err_info:8;	/* [7:0] */
++		unsigned int rsv:23;	/* [30:8] */
++		unsigned int aval_flg:1;	/* [31] */
++	} bits;
++
++	unsigned int u32;
++
++} U_DPRS_RTN_STATUS;
++
++/* Define the union U_INT_EN */
++typedef union {
++	/* Define the struct bits */
++	struct {
++		unsigned int    task_intrpt_en:1; /* [0] */
++		unsigned int    block_intrpt_en:1; /* [1] */
++		unsigned int    reserved_0:30; /* [31..2] */
++	} bits;
++
++	/* Define an unsigned member */
++	unsigned int    u32;
++
++} U_INTR_EN;
++
++typedef union {
++	/* Define the struct bits */
++	struct {
++		unsigned int    task_intrpt:1; /* [0] */
++		unsigned int    block_intrpt:1; /* [1] */
++		unsigned int    reserved_0:30; /* [31..2] */
++	} bits;
++
++	/* Define an unsigned member */
++	unsigned int    u32;
++
++} U_INTR_STATUS;
++
++typedef union {
++	/* Define the struct bits */
++	struct {
++		unsigned int    task_intrpt_clr:1; /* [0] */
++		unsigned int    block_intrpt_clr:1; /* [1] */
++		unsigned int    reserved_0:30; /* [31..2] */
++	} bits;
++
++	/* Define an unsigned member */
++	unsigned int    u32;
++} U_INTR_CLR;
++
++
++void hw_gzip_exit(void);
++int hw_gzip_dec(unsigned int dst, int *dstlen, unsigned int src, int srclen);
++void hw_gzip_init(void);
+diff --git a/arch/arm/boot/compressed/hw_decompress_hi3559.h b/arch/arm/boot/compressed/hw_decompress_hi3559.h
+new file mode 100644
+index 0000000..32f4dde
+--- /dev/null
++++ b/arch/arm/boot/compressed/hw_decompress_hi3559.h
+@@ -0,0 +1,21 @@
++#define CRG_REG_BASE 0x12010000
++#define PERI_CRG33 0x84
++#define GZIP_CLKEN (1<<1)
++
++static void disable_decompress_clock(void)
++{
++	unsigned int regval;
++
++	regval = readl((void *)(CRG_REG_BASE + PERI_CRG33));
++	regval &= ~GZIP_CLKEN;
++	writel(regval, (void *)(CRG_REG_BASE + PERI_CRG33));
++}
++
++static void enable_decompress_clock(void)
++{
++	unsigned int regval;
++
++	regval = readl((void *)(CRG_REG_BASE + PERI_CRG33));
++	regval |= GZIP_CLKEN;
++	writel(regval, (void *)(CRG_REG_BASE + PERI_CRG33));
++}
+diff --git a/arch/arm/boot/compressed/vmlinux.lds.S b/arch/arm/boot/compressed/vmlinux.lds.S
+index 2b60b84..48ab3fb 100644
+--- a/arch/arm/boot/compressed/vmlinux.lds.S
++++ b/arch/arm/boot/compressed/vmlinux.lds.S
+@@ -48,6 +48,7 @@ SECTIONS
+     *(.rodata)
+     *(.rodata.*)
+   }
++  . = ALIGN(16);
+   .piggydata : {
+     *(.piggydata)
+   }
+diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
+index 38c89ca..3f541e2 100644
+--- a/arch/arm/boot/dts/Makefile
++++ b/arch/arm/boot/dts/Makefile
+@@ -91,6 +91,22 @@ dtb-$(CONFIG_ARCH_EXYNOS) += exynos4210-origen.dtb \
+ 	exynos5800-peach-pi.dtb
+ dtb-$(CONFIG_ARCH_HI3xxx) += hi3620-hi4511.dtb
+ dtb-$(CONFIG_ARCH_HIX5HD2) += hisi-x5hd2-dkb.dtb
++dtb-$(CONFIG_ARCH_HI3516CV300) += hi3516cv300-demb.dtb
++dtb-$(CONFIG_ARCH_HI3536C) += hi3536c-demb.dtb
++dtb-$(CONFIG_ARCH_HI3521D) += hi3521d-demb.dtb
++dtb-$(CONFIG_ARCH_HI3531D) += hi3531d-demb.dtb
++ifeq ($(CONFIG_SMP),y)
++dtb-$(CONFIG_ARCH_HI3519) += hisi-hi3519-hmp-demb.dtb
++dtb-$(CONFIG_ARCH_HI3519V101) += hisi-hi3519v101-hmp-demb.dtb
++dtb-$(CONFIG_ARCH_HI3516AV200) += hisi-hi3516av200-hmp-demb.dtb
++dtb-$(CONFIG_ARCH_HI3559) += hisi-hi3559-hmp-demb.dtb
++else
++dtb-$(CONFIG_ARCH_HI3519) += hisi-hi3519-demb.dtb
++dtb-$(CONFIG_ARCH_HI3519V101) += hisi-hi3519v101-demb.dtb
++dtb-$(CONFIG_ARCH_HI3516AV200) += hisi-hi3516av200-demb.dtb
++dtb-$(CONFIG_ARCH_HI3559) += hisi-hi3559-demb.dtb
++dtb-$(CONFIG_ARCH_HI3556) += hisi-hi3556-demb.dtb
++endif
+ dtb-$(CONFIG_ARCH_HIGHBANK) += highbank.dtb \
+ 	ecx-2000.dtb
+ dtb-$(CONFIG_ARCH_HIP04) += hip04-d01.dtb
+@@ -517,15 +533,14 @@ dtb-$(CONFIG_MACH_DOVE) += dove-cm-a510.dtb \
+ 	dove-dove-db.dtb
+ dtb-$(CONFIG_ARCH_MEDIATEK) += mt6589-aquaris5.dtb
+ 
+-targets += dtbs dtbs_install
+-targets += $(dtb-y)
++DTB_NAMES := $(subst $\",,$(CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE_NAMES))
++ifneq ($(DTB_NAMES),)
++DTB_LIST := $(addsuffix .dtb,$(DTB_NAMES))
++else
++DTB_LIST := $(dtb-y)
+ endif
+ 
+-# *.dtb used to be generated in the directory above. Clean out the
+-# old build results so people don't accidentally use them.
+-dtbs: $(addprefix $(obj)/, $(dtb-y))
+-	$(Q)rm -f $(obj)/../*.dtb
+-
+-clean-files := *.dtb
++endif
+ 
+-dtbs_install: $(addsuffix _dtbinst_, $(dtb-y))
++always		:= $(DTB_LIST)
++clean-files	:= *.dtb
+diff --git a/arch/arm/boot/dts/hi3516cv300-demb.dts b/arch/arm/boot/dts/hi3516cv300-demb.dts
+new file mode 100644
+index 0000000..1584a45
+--- /dev/null
++++ b/arch/arm/boot/dts/hi3516cv300-demb.dts
+@@ -0,0 +1,636 @@
++/*
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++
++/dts-v1/;
++#include "hi3516cv300.dtsi"
++
++/ {
++	model = "Hisilicon Hi3516CV300 DEMO Board";
++	compatible = "hisilicon,hi3516cv300";
++
++	memory {
++		device_type = "memory";
++		reg = <0x80000000 0x10000000>;
++	};
++};
++
++&dual_timer0 {
++	status = "okay";
++};
++
++&uart0 {
++	status = "okay";
++};
++
++&i2c_bus1 {
++	status = "okay";
++	clock-frequency = <100000>;
++	pinctrl-names = "default";
++	pinctrl-0 = <&i2c1_pmux &i2c1_pconf>;
++};
++
++&spi_bus1{
++	status = "disabled";
++	num-cs = <2>;
++	cs-gpios = <&gpio_chip5 3 0>, <&gpio_chip5 4 0>;
++	pinctrl-names = "default";
++	pinctrl-0 = <&spi1_pmux &spi1_pconf1 &spi1_pconf2 &spi1_pconf3>;
++
++	spidev@0 {
++		compatible = "rohm,dh2228fv";
++		reg = <0>;
++		pl022,interface = <0>;
++		pl022,com-mode = <0>;
++		spi-max-frequency = <50000000>;
++	};
++
++	spidev@1 {
++		compatible = "rohm,dh2228fv";
++		reg = <1>;
++		pl022,interface = <0>;
++		pl022,com-mode = <0>;
++		spi-max-frequency = <50000000>;
++	};
++};
++
++&pwm {
++	status = "okay";
++	pinctrl-names = "default";
++	pinctrl-0 = <&pwm_pmux>;
++};
++
++&hisfc {
++	assigned-clocks = <&crg_ctrl HI3516CV300_FMC_CLK>;
++	assigned-clock-rates = <24000000>;
++
++	hi_sfc {
++		compatible = "jedec,spi-nor";
++		reg = <0>;
++		spi-max-frequency = <160000000>;
++		m25p,fast-read;
++	};
++};
++
++&hisnfc {
++	assigned-clocks = <&crg_ctrl HI3516CV300_FMC_CLK>;
++	assigned-clock-rates = <83300000>;
++
++	hinand {
++		compatible = "jedec,spi-nand";
++		reg = <0>;
++		spi-max-frequency = <160000000>;
++	};
++};
++
++&mmc0 {
++	status = "okay";
++};
++
++&mmc1 {
++	status = "okay";
++};
++
++&mmc2 {
++	status = "okay";
++};
++
++&mdio {
++	phy0: phy@1 {
++		reg = <1>;
++	};
++};
++
++&hisi_femac {
++	mac-address = [00 00 00 00 00 00];
++	phy-mode = "rmii";
++	phy-handle = <&phy0>;
++	hisilicon,phy-reset-delays-us = <10000 10000 150000>;
++};
++
++&usb_phy {
++	status = "okay";
++};
++
++&ehci {
++	status = "okay";
++};
++
++&ohci {
++	status = "okay";
++};
++
++&hiudc {
++	status = "okay";
++};
++
++&hidmac {
++	status = "okay";
++};
++
++&dmac {
++	status = "disabled";
++};
++
++&gpio_chip0 {
++	status = "okay";
++};
++
++&gpio_chip1 {
++	status = "okay";
++};
++
++&gpio_chip2 {
++	status = "okay";
++};
++
++&gpio_chip3 {
++	status = "okay";
++};
++
++&gpio_chip4 {
++	status = "okay";
++};
++
++&gpio_chip5 {
++	status = "okay";
++};
++
++&gpio_chip6 {
++	status = "okay";
++};
++
++&gpio_chip7 {
++	status = "okay";
++};
++
++&gpio_chip8 {
++	status = "okay";
++};
++
++&pmux {
++	i2c0_pmux: i2c0_pmux {
++		pinctrl-single,pins = <
++			0x2c 0x3	/*I2C0_SDA*/
++			0x30 0x3	/*I2C0_SCL*/
++		>;
++	};
++
++	i2c1_pmux: i2c1_pmux {
++		pinctrl-single,pins = <
++			0x20 0x1	/*I2C1_SDA*/
++			0x24 0x1	/*I2C1_SCL*/
++		>;
++	};
++
++	spi0_pmux: spi0_pmux {
++		pinctrl-single,pins = <
++			0x28 0x1	/*SPI0_SDI*/
++			0x2c 0x1	/*SPI0_SDO*/
++			0x30 0x1	/*SPI0_SCLK*/
++			0x34 0x1	/*SPI0_CSN*/
++		>;
++	};
++
++	spi1_pmux: spi1_pmux {
++		pinctrl-single,pins = <
++			0xc4 0x1	/*SPI1_CSN1*/
++			0xc8 0x1	/*SPI1_CSN0*/
++			0xcc 0x1	/*SPI1_SDO*/
++			0xd0 0x1	/*SPI1_SDI*/
++			0xd4 0x1	/*SPI1_SCLK*/
++		>;
++	};
++
++	sensor_pmux: sensor_pmux {
++		pinctrl-single,pins = <
++			0x38 0x1	/*SENSOR_RSTN*/
++			0x3c 0x1	/*SENSOR_CLK*/
++		>;
++	};
++
++	spi_3wire_pmux: spi_3wire_pmux{
++		pinctrl-single,pins = <
++			0x2c 0x2	/*SPI_3LINE_SDATA*/
++			0x30 0x2	/*SPI_3LINE_SCLK*/
++			0x34 0x2	/*SPI_3LINE_CSN*/
++		>;
++	};
++
++	vi_flash_trig_pmux: vi_flash_trig_pmux {
++		pinctrl-single,pins = <
++			0x1c 0x1	/*FLASH_TRIG*/
++		>;
++	};
++
++	vi_shutter_trig_pmux: vi_shutter_trig_pmux {
++		pinctrl-single,pins = <
++			0x18 0x1	/*SHUTTER_TRIG*/
++		>;
++	};
++
++	vi_bt1120_pmux: vi_bt1120_pmux{
++		pinctrl-single,pins = <
++			0x40 0x1	/*VI_DATA13*/
++			0x44 0x1	/*VI_DATA10*/
++			0x48 0x1	/*VI_DATA12*/
++			0x4c 0x1	/*VI_DATA11*/
++			0x50 0x1	/*VI_DATA9*/
++			0x54 0x1	/*VI_DATA14*/
++			0x58 0x1	/*VI_DATA15*/
++			0x5c 0x1	/*VI_VS*/
++			0x60 0x1	/*VI_HS*/
++		>;
++	};
++
++	sensor_dc_pmux: sensor_dc_pmux{
++		pinctrl-single,pins = <
++			0x40 0x1	/*VI_DATA13*/
++			0x44 0x1	/*VI_DATA10*/
++			0x48 0x1	/*VI_DATA12*/
++			0x4c 0x1	/*VI_DATA11*/
++			0x50 0x1	/*VI_DATA9*/
++			0x54 0x1	/*VI_DATA14*/
++			0x58 0x1	/*VI_DATA15*/
++			0x5c 0x1	/*VI_VS*/
++			0x60 0x1	/*VI_HS*/
++		>;
++	};
++
++	vo_bt656_pmux: vo_bt656_pmux{
++		pinctrl-single,pins = <
++			0x40 0x2	/*VOU656_CLK*/
++			0x44 0x2	/*VOU656_DATA3*/
++			0x48 0x2	/*VOU656_DATA7*/
++			0x4c 0x2	/*VOU656_DATA2*/
++			0x50 0x2	/*VOU656_DATA6*/
++			0x54 0x2	/*VOU656_DATA5*/
++			0x58 0x2	/*VOU656_DATA4*/
++			0x5c 0x2	/*VOU656_DATA1*/
++			0x60 0x2	/*VOU656_DATA0*/
++		>;
++	};
++
++	vo_lcd_pmux: vo_lcd_pmux{
++		pinctrl-single,pins = <
++			0x40 0x3	/*LCD_CLK*/
++			0x44 0x3	/*LCD_DATA1*/
++			0x48 0x3	/*LCD_DATA3*/
++			0x4c 0x3	/*LCD_DATA2*/
++			0x50 0x3	/*LCD_DATA4*/
++			0x54 0x3	/*LCD_DATA5*/
++			0x58 0x3	/*LCD_DATA0*/
++			0x5c 0x3	/*LCD_HSYNC*/
++			0x60 0x3	/*LCD_VSYNC*/
++			0x64 0x3	/*LCD_DE*/
++		>;
++	};
++
++	i2s_with_jtag_pmux: i2s_with_jtag_pmux{
++		pinctrl-single,pins = <
++			0xc4 0x4	/*I2S_SD_TX*/
++			0xc8 0x4	/*I2S_WS_TX*/
++			0xcc 0x4	/*I2S_BCLK_TX*/
++			0xd0 0x4	/*I2S_MCLK*/
++			0xd4 0x4	/*I2S_SD_RX*/
++		>;
++	};
++
++	i2s_with_vi_pmux: i2s_with_vi_pmux{
++		pinctrl-single,pins = <
++			0x40 0x4	/*I2S_MCLK*/
++			0x44 0x4	/*I2S_SD_TX*/
++			0x48 0x4	/*I2S_BCLK_TX*/
++			0x4c 0x4	/*I2S_WS_TX*/
++			0x58 0x4	/*I2S_SD_RX*/
++		>;
++	};
++
++	pwm_pmux: pwm_pmux{
++		pinctrl-single,pins = <
++			0x04 0x1
++			0x08 0x1
++			0x0c 0x1
++		>;
++	};
++};
++
++&pconf {
++	i2c0_pconf: i2c0_pconf {
++		pinctrl-single,pins = <
++			0x2c 0
++			0x30 0
++		>;
++		pinctrl-single,drive-strength = <0x70 0xff>;
++	};
++
++	i2c1_pconf: i2c1_pconf {
++		pinctrl-single,pins = <
++			0x20 0
++			0x24 0
++		>;
++		pinctrl-single,drive-strength = <0x30 0xff>;
++	};
++
++	/*spi0 drive strength conf 1~3*/
++	spi0_pconf1: spi0_pconf1 {
++		pinctrl-single,pins = <
++			0x28 0
++			0x2c 0
++		>;
++		pinctrl-single,drive-strength = <0x20 0xff>;
++	};
++
++	spi0_pconf2: spi0_pconf2 {
++		pinctrl-single,pins = <
++			0x30 0
++		>;
++		pinctrl-single,drive-strength = <0x50 0xff>;
++	};
++
++	spi0_pconf3: spi0_pconf3 {
++		pinctrl-single,pins = <
++			0x34 0
++		>;
++		pinctrl-single,drive-strength = <0x30 0xff>;
++	};
++
++	/*spi1 drive strength conf 1~3*/
++	spi1_pconf1: spi1_pconf1 {
++		pinctrl-single,pins = <
++			0xe4 0
++			0xe8 0
++		>;
++		pinctrl-single,drive-strength = <0x30 0xff>;
++	};
++
++	spi1_pconf2: spi1_pconf2 {
++		pinctrl-single,pins = <
++			0xec 0
++			0xf0 0
++		>;
++		pinctrl-single,drive-strength = <0x20 0xff>;
++	};
++
++	spi1_pconf3: spi1_pconf3 {
++		pinctrl-single,pins = <
++			0xf4 0
++		>;
++		pinctrl-single,drive-strength = <0x0 0xff>;
++	};
++
++	spi_3wire_pconf: spi_3wire_pconf{
++		pinctrl-single,pins = <
++			0x2c 0
++			0x30 0
++			0x34 0
++		>;
++		pinctrl-single,drive-strength = <0x70 0xff>;
++	};
++
++	sensor_pconf1: sensor_pconf1 {
++		pinctrl-single,pins = <
++			0x38 0
++		>;
++		pinctrl-single,drive-strength = <0x31 0xff>;
++	};
++
++	sensor_pconf2: sensor_pconf2 {
++		pinctrl-single,pins = <
++			0x3c 0
++		>;
++		pinctrl-single,drive-strength = <0x20 0xff>;
++	};
++
++	vi_bt1120_pconf: vi_bt1120_pconf {
++		pinctrl-single,pins = <
++			0x40 0
++			0x44 0
++			0x48 0
++			0x4c 0
++			0x50 0
++			0x54 0
++			0x58 0
++			0x5c 0
++			0x60 0
++		>;
++		pinctrl-single,drive-strength = <0x70 0xff>;
++	};
++
++	sensor_dc_pconf: sensor_dc_pconf {
++		pinctrl-single,pins = <
++			0x40 0
++			0x44 0
++			0x48 0
++			0x4c 0
++			0x50 0
++			0x54 0
++			0x58 0
++			0x5c 0
++			0x60 0
++		>;
++		pinctrl-single,drive-strength = <0x70 0xff>;
++	};
++
++	vo_bt656_pconf1: vo_bt656_pconf1 {
++		pinctrl-single,pins = <
++			0x40 0
++		>;
++		pinctrl-single,drive-strength = <0x40 0xff>;
++	};
++
++	vo_bt656_pconf2: vo_bt656_pconf2 {
++		pinctrl-single,pins = <
++			0x44 0
++			0x48 0
++			0x4c 0
++			0x50 0
++			0x54 0
++			0x58 0
++			0x5c 0
++			0x60 0
++		>;
++		pinctrl-single,drive-strength = <0x20 0xff>;
++	};
++
++	vo_lcd_pconf1: vo_lcd_pconf1 {
++		pinctrl-single,pins = <
++			0x40 0
++		>;
++		pinctrl-single,drive-strength = <0x40 0xff>;
++	};
++
++	vo_lcd_pconf2: vo_lcd_pconf2 {
++		pinctrl-single,pins = <
++			0x44 0
++			0x48 0
++			0x4c 0
++			0x50 0
++			0x54 0
++			0x58 0
++			0x5c 0
++			0x60 0
++			0x64 0
++		>;
++		pinctrl-single,drive-strength = <0x10 0xff>;
++	};
++
++	i2s_with_jtag_pconf: i2s_with_jtag_pconf{
++		pinctrl-single,pins = <
++			0xe4 0
++			0xe8 0
++			0xec 0
++			0xf0 0
++			0xf4 0
++		>;
++		pinctrl-single,drive-strength = <0x30 0xff>;
++	};
++
++	i2s_with_vi_pconf: i2s_with_vi_pconf{
++		pinctrl-single,pins = <
++			0x40 0
++			0x44 0
++			0x48 0
++			0x4c 0
++			0x58 0
++		>;
++		pinctrl-single,drive-strength = <0x70 0xff>;
++	};
++};
++
++&i2c_bus0 {
++	status = "okay";
++	clock-frequency = <100000>;
++};
++
++&spi_bus0{
++	status = "okay";
++	num-cs = <1>;
++	cs-gpios = <&gpio_chip0 6 0>;
++
++	spidev@0 {
++		compatible = "rohm,dh2228fv";
++		reg = <0>;
++		pl022,interface = <0>;
++		pl022,com-mode = <0>;
++		spi-max-frequency = <50000000>;
++	};
++};
++
++&sensor_device0 {
++	pinctrl-names = "i2c_mipi", "ssp_mipi", "i2c_dc", "ssp_dc", "sleep";
++	pinctrl-0 = <&sensor_pmux &sensor_pconf1 &sensor_pconf2 &i2c0_pmux &i2c0_pconf>;
++	pinctrl-1 = <&sensor_pmux &sensor_pconf1 &sensor_pconf2 &spi0_pmux &spi0_pconf1 &spi0_pconf2 &spi0_pconf3>;
++	pinctrl-2 = <&sensor_pmux &sensor_pconf1 &sensor_pconf2 &i2c0_pmux &i2c0_pconf &sensor_dc_pmux &sensor_dc_pconf>;
++	pinctrl-3 = <&sensor_pmux &sensor_pconf1 &sensor_pconf2 &spi0_pmux &spi0_pconf1 &spi0_pconf2 &spi0_pconf3 &sensor_dc_pmux &sensor_dc_pconf>;
++	pinctrl-4 = <&sensor_pmux &sensor_pconf1 &sensor_pconf2>;
++};
++
++&viu {
++	pinctrl-names = "default", "bt1120", "sleep";
++	pinctrl-0 = <&vi_flash_trig_pmux &vi_shutter_trig_pmux>;
++	pinctrl-1 = <&vi_flash_trig_pmux &vi_shutter_trig_pmux &vi_bt1120_pmux &vi_bt1120_pconf>;
++	pinctrl-2 = <&vi_flash_trig_pmux &vi_shutter_trig_pmux>;
++};
++
++&vou {
++	pinctrl-names = "bt656", "lcd", "sleep", "default";
++	pinctrl-0 = <&vo_bt656_pmux &vo_bt656_pconf1 &vo_bt656_pconf2>;
++	pinctrl-1 = <&vo_lcd_pmux &vo_lcd_pconf1 &vo_lcd_pconf2>;
++	pinctrl-2 = <>;
++	pinctrl-3 = <>;
++};
++
++/*
++&audio {
++	pinctrl-names = "default";
++	pinctrl-0 = <&i2s_with_jtag_pmux &i2s_with_jtag_pconf>;
++};
++*/
++
++&pin_ctrl_online {
++	pinctrl-single,pins = <
++		0x12030000 0x00000080
++		0x12030044 0x66664111
++		0x12030048 0x66666013
++		0x1203004c 0x65266666
++		0x12030050 0x00000011
++		0x12030054 0x00000110
++		0x12030058 0x00000000
++		0x12060204 0x1f>;
++};
++
++&pin_ctrl_offline {
++	pinctrl-single,pins = <
++		0x12030000 0x00000000
++		0x12030044 0x66666111
++		0x12030048 0x66666023
++		0x1203004c 0x65266666
++		0x12030050 0x00000011
++		0x12030054 0x00000100
++		0x12030058 0x00000000
++		0x12060204 0x2>;
++};
++
++&pin_ctrl_ddr {
++	pinctrl-single,pins = <
++		0x120600c0 0x76543210
++		0x120600c4 0x76543210
++		0x120600c8 0x76543210
++		0x120600cc 0x76543210
++		0x120600d0 0x76543210
++		0x120600d4 0x76543210
++		0x12060100 0x76543210
++		0x12060104 0x76543210
++		0x12060108 0x76543210
++		0x1206010c 0x76543210
++		0x12060110 0x76543210
++		0x12060114 0x76543210
++		0x12060140 0x00000000
++		0x12060144 0x00000000
++		0x12060148 0x00000000
++		0x1206014c 0x00000000
++		0x12060150 0x00000000
++		0x12060154 0x00000000
++		0x12060180 0x00004000
++		0x12060184 0x00004000
++		0x12060188 0x00000000
++		0x1206018c 0x00000000
++		0x12060190 0x00000100
++		0x12060194 0x00000000
++		0x12060200 0x1f
++		0x12060208 0x2
++		0x1206020c 0x2
++		0x12060214 0x3
++		0x12060240 0xb
++		0x12060244 0x0
++		0x12060040 0x81001000
++		0x12060044 0x81001000
++		0x12060048 0x81001000
++		0x1206004c 0x81001000
++		0x12060050 0x81001000
++		0x12060054 0x81001000
++		0x120614bc 0x101
++		0x113200E0 0xd
++	>;
++};
++
++&user_pinmux {
++	pinctrl-single,pins = <
++	>;
++};
+diff --git a/arch/arm/boot/dts/hi3516cv300.dtsi b/arch/arm/boot/dts/hi3516cv300.dtsi
+new file mode 100644
+index 0000000..2832476
+--- /dev/null
++++ b/arch/arm/boot/dts/hi3516cv300.dtsi
+@@ -0,0 +1,675 @@
++/*
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include "skeleton.dtsi"
++#include <dt-bindings/clock/hi3516cv300-clock.h>
++/ {
++	#address-cells = <1>;
++	#size-cells = <1>;
++
++	aliases {
++		serial0 = &uart0;
++		serial1 = &uart1;
++		serial2 = &uart2;
++		i2c0 = &i2c_bus0;
++		i2c1 = &i2c_bus1;
++		spi0 = &spi_bus0;
++		spi1 = &spi_bus1;
++		gpio0 = &gpio_chip0;
++		gpio1 = &gpio_chip1;
++		gpio2 = &gpio_chip2;
++		gpio3 = &gpio_chip3;
++		gpio4 = &gpio_chip4;
++		gpio5 = &gpio_chip5;
++		gpio6 = &gpio_chip6;
++		gpio7 = &gpio_chip7;
++		gpio8 = &gpio_chip8;
++		sensor0 = &sensor_device0;
++	};
++
++	cpus {
++		#address-cells = <1>;
++		#size-cells = <0>;
++
++		cpu@0 {
++			device_type = "cpu";
++			compatible = "arm,arm926ej-s";
++			reg = <0>;
++		};
++	};
++
++	vic: interrupt-controller@10040000 {
++		compatible = "arm,pl190-vic";
++		interrupt-controller;
++		#interrupt-cells = <1>;
++		reg = <0x10040000 0x1000>;
++	};
++
++	soc {
++		#address-cells = <1>;
++		#size-cells = <1>;
++		compatible = "simple-bus";
++		interrupt-parent = <&vic>;
++		ranges;
++
++		crg_ctrl: crg_ctrl@12010000 {
++			compatible = "hisilicon,hi3516cv300-crg";
++			reg = <0x12010000 0x1000>;
++			#clock-cells = <1>;
++			#reset-cells = <2>;
++		};
++
++		sys_ctrl: system-controller@12020000 {
++			compatible = "hisilicon,hi3516cv300-sys", "syscon";
++			reg = <0x12020000 0x1000>;
++			#clock-cells = <1>;
++		};
++
++		reboot {
++			compatible = "syscon-reboot";
++			regmap = <&sys_ctrl>;
++			offset = <0x4>;
++			mask = <0xdeadbeef>;
++		};
++
++		pm {
++			compatible = "hisilicon,hibvt-pm";
++			reg = <0x12020000 0x1000>, <0x12000000 0x1000>;
++		};
++
++		pm_hibernate {
++			compatible = "hisilicon,hibvt-pm-hibernate";
++			reg = <0x12020000 0x1000>;
++		};
++
++		dual_timer0: dual_timer@12000000 {
++			compatible = "arm,sp804", "arm,primecell";
++			reg = <0x12000000 0x1000>;
++			interrupts = <3>;
++			clocks = <&sys_ctrl HI3516CV300_TIME00_CLK>,
++			       <&sys_ctrl HI3516CV300_TIME01_CLK>,
++			       <&crg_ctrl HI3516CV300_APB_CLK>;
++			clock-names = "timer0", "timer1", "apb_pclk";
++			status = "disabled";
++		};
++
++		dual_timer1: dual_timer@12001000 {
++			compatible = "arm,sp804", "arm,primecell";
++			reg = <0x12001000 0x1000>;
++			interrupts = <4>;
++			clocks = <&sys_ctrl HI3516CV300_TIME10_CLK>,
++			       <&sys_ctrl HI3516CV300_TIME11_CLK>,
++			       <&crg_ctrl HI3516CV300_APB_CLK>;
++			clock-names = "timer0", "timer1", "apb_pclk";
++			status = "disabled";
++		};
++
++		uart0: uart@12100000 {
++			compatible = "arm,pl011", "arm,primecell";
++			reg = <0x12100000 0x1000>;
++			interrupts = <5>;
++			clocks = <&crg_ctrl HI3516CV300_UART0_CLK>;
++			clock-names = "apb_pclk";
++			status = "disabled";
++		};
++
++		uart1: uart@12101000 {
++			compatible = "arm,pl011", "arm,primecell";
++			reg = <0x12101000 0x1000>;
++			interrupts = <30>;
++			clocks = <&crg_ctrl HI3516CV300_UART1_CLK>;
++			clock-names = "apb_pclk";
++			status = "disabled";
++		};
++
++		uart2: uart@12102000 {
++			compatible = "arm,pl011", "arm,primecell";
++			reg = <0x12102000 0x1000>;
++			interrupts = <25>;
++			clocks = <&crg_ctrl HI3516CV300_UART2_CLK>;
++			clock-names = "apb_pclk";
++			status = "disabled";
++		};
++
++		i2c_bus0: i2c@12110000 {
++			compatible = "hisilicon,hi3516cv300-i2c",
++				"hisilicon,hibvt-i2c";
++			reg = <0x12110000 0x1000>;
++			clocks = <&crg_ctrl HI3516CV300_APB_CLK>;
++			status = "disabled";
++		};
++
++		i2c_bus1: i2c@12112000 {
++			compatible = "hisilicon,hi3516cv300-i2c",
++				"hisilicon,hibvt-i2c";
++			reg = <0x12112000 0x1000>;
++			clocks = <&crg_ctrl HI3516CV300_APB_CLK>;
++			status = "disabled";
++		};
++
++		spi_bus0: spi@12120000 {
++			compatible = "arm,pl022", "arm,primecell";
++			arm,primecell-periphid = <0x00800022>;
++			reg = <0x12120000 0x1000>;
++			interrupts = <6>;
++			clocks = <&crg_ctrl HI3516CV300_SPI0_CLK>;
++			clock-names = "apb_pclk";
++			/* dmas = <&dmac 12 1>, <&dmac 13 2>; */
++			/* dma-names = "rx", "tx"; */
++			#address-cells = <1>;
++			#size-cells = <0>;
++			status = "disabled";
++		};
++
++		spi_bus1: spi@12121000 {
++			compatible = "arm,pl022", "arm,primecell";
++			arm,primecell-periphid = <0x00800022>;
++			reg = <0x12121000 0x1000>, <0x12030000 0x4>;
++			interrupts = <7>;
++			clocks = <&crg_ctrl HI3516CV300_SPI1_CLK>;
++			clock-names = "apb_pclk";
++			/* dmas = <&dmac 14 1>, <&dmac 15 2>; */
++			/* dma-names = "rx", "tx"; */
++			#address-cells = <1>;
++			#size-cells = <0>;
++			hisi,spi_cs_sb = <4>;
++			hisi,spi_cs_mask_bit = <0x10>;
++			status = "disabled";
++		};
++
++		fmc: spi-nor-controller@10000000 {
++			compatible = "hisilicon,hisi-fmc";
++			reg = <0x10000000 0x1000>, <0x14000000 0x1000000>;
++			reg-names = "control", "memory";
++			clocks = <&crg_ctrl HI3516CV300_FMC_CLK>;
++			#address-cells = <1>;
++			#size-cells = <0>;
++
++			hisfc:spi-nor@0 {
++				compatible = "hisilicon,hisi-sfc";
++				#address-cells = <1>;
++				#size-cells = <0>;
++			};
++
++			hisnfc:spi-nand@0 {
++				compatible = "hisilicon,hisi-spi-nand";
++				#address-cells = <1>;
++				#size-cells = <0>;
++			};
++		};
++
++		mmc2: himciv200.MMC@0x100e0000 {
++			compatible = "hisilicon,hi3516cv300-himciv200";
++			reg = <0x100e0000 0x1000>;
++			interrupts = <11>;
++			clocks = <&crg_ctrl HI3516CV300_MMC2_CLK>;
++			clock-names = "mmc_clk";
++			max-frequency = <99000000>;
++			bus-width = <4>;
++			cap-mmc-highspeed;
++			cap-mmc-hw-reset;
++			mmc-hs200-1_8v;
++			full-pwr-cycle;
++			devid = <2>;
++			regmap = <&sys_ctrl>;
++			status = "disabled";
++		};
++
++		mmc0: himciv200.SD@0x100c0000 {
++			compatible = "hisilicon,hi3516cv300-himciv200";
++			reg = <0x100c0000 0x1000>;
++			interrupts = <18>;
++			clocks = <&crg_ctrl HI3516CV300_MMC0_CLK>;
++			clock-names = "mmc_clk";
++			max-frequency = <49500000>;
++			bus-width = <4>;
++			cap-mmc-highspeed;
++			cap-sd-highspeed;
++			devid = <0>;
++			status = "disabled";
++		};
++
++		mmc1: himciv200.SD@0x100d0000 {
++			compatible = "hisilicon,hi3516cv300-himciv200";
++			reg = <0x100d0000 0x1000>;
++			interrupts = <27>;
++			clocks = <&crg_ctrl HI3516CV300_MMC1_CLK>;
++			clock-names = "mmc_clk";
++			max-frequency = <49500000>;
++			bus-width = <4>;
++			cap-mmc-highspeed;
++			cap-sd-highspeed;
++			devid = <1>;
++			status = "disabled";
++		};
++
++		mmc3: himciv200.SD@0x100f0000 {
++			compatible = "hisilicon,hi3516cv300-himciv200";
++			reg = <0x100f0000 0x1000>;
++			interrupts = <27>;
++			clocks = <&crg_ctrl HI3516CV300_MMC3_CLK>;
++			clock-names = "mmc_clk";
++			max-frequency = <49500000>;
++			bus-width = <4>;
++			cap-mmc-highspeed;
++			cap-sd-highspeed;
++			devid = <3>;
++			status = "disabled";
++		};
++
++		mdio: mdio@10051100 {
++			compatible = "hisilicon,hisi-femac-mdio";
++			reg = <0x10051100 0x10>;
++			clocks = <&crg_ctrl HI3516CV300_ETH_CLK>;
++			#address-cells = <1>;
++			#size-cells = <0>;
++		};
++
++		hisi_femac: ethernet@10090000 {
++			compatible = "hisilicon,hi3516cv300-femac",
++				"hisilicon,hisi-femac-v2";
++			reg = <0x10050000 0x1000>,<0x10051300 0x200>;
++			interrupts = <12>;
++			clocks = <&crg_ctrl HI3516CV300_ETH_CLK>;
++			resets = <&crg_ctrl 0xec 0>, <&crg_ctrl 0xec 3>;
++			reset-names = "mac","phy";
++		};
++
++		usb_phy: usbphy {
++			compatible = "hisilicon,inno_usb2_phy";
++			reg = <0x12030000 0x1000>, <0x120d0000 0x1000>,
++				<0x12010000 0x1000>, <0x12020000 0x1000>;
++			clocks = <&crg_ctrl HI3516CV300_USB2_BUS_CLK>;
++			clock-names = "ref_clk";
++			#phy-cells = <0>;
++			resets = <&crg_ctrl 0xb8 13>, <&crg_ctrl 0xb8 17>;
++			reset-names = "por_rst", "test_rst";
++			status = "disabled";
++			port0: port0 {
++				clocks = <&crg_ctrl HI3516CV300_UTMI0_CLK>;
++				resets = <&crg_ctrl 0xb8 14>,
++					<&crg_ctrl 0xb8 9>;
++				reset-names = "port_rst", "utmi_rst";
++			};
++		};
++
++		ehci: ehci@0x10120000 {
++			 compatible = "generic-ehci";
++			 reg = <0x10120000 0x10000>;
++			 interrupts = <15>;
++			 clocks = <&crg_ctrl HI3516CV300_USB2_CLK>;
++			 clock-names = "clk";
++			 status = "disabled";
++		 };
++
++		ohci: ohci@0x10110000 {
++			 compatible = "generic-ohci";
++			 reg = <0x10110000 0x10000>;
++			 interrupts = <16>;
++			 clocks = <&crg_ctrl HI3516CV300_USB2_CLK>;
++			 clock-names = "clk";
++			 status = "disabled";
++		 };
++
++		 hiudc: hiudc@0x10130000 {
++			 compatible = "hiudc";
++			 reg = <0x10130000 0x40000>;
++			 interrupts = <10>;
++			 clocks = <&crg_ctrl HI3516CV300_USB2_CLK>;
++			 clock-names = "clk";
++			 status = "disabled";
++		 };
++
++		hidmac: hidma-controller@10030000 {
++			compatible = "hisilicon,hisi-dmac";
++			reg = <0x10030000 0x1000>;
++			interrupts = <14>;
++			clocks = <&crg_ctrl HI3516CV300_DMAC_CLK>;
++			clock-names = "apb_pclk";
++			resets = <&crg_ctrl 0xd8 4>;
++			reset-names = "dma-reset";
++			#dma-cells = <2>;
++			status = "disabled";
++		};
++
++		dmac: dma-controller@10030000 {
++			compatible = "arm,pl080", "arm,primecell";
++			reg = <0x10030000 0x1000>;
++			interrupts = <14>;
++			clocks = <&crg_ctrl HI3516CV300_DMAC_CLK>;
++			clock-names = "apb_pclk";
++			lli-bus-interface-ahb1;
++			lli-bus-interface-ahb2;
++			mem-bus-interface-ahb1;
++			mem-bus-interface-ahb2;
++			memcpy-burst-size = <256>;
++			memcpy-bus-width = <32>;
++			#dma-cells = <2>;
++			status = "disabled";
++		};
++
++		gpio_chip0: gpio@12140000 {
++			compatible = "arm,pl061", "arm,primecell";
++			reg = <0x12140000 0x1000>;
++			interrupts = <31>;
++			clocks = <&crg_ctrl HI3516CV300_APB_CLK>;
++			clock-names = "apb_pclk";
++			#gpio-cells = <2>;
++			gpio-ranges = <&pmux 0 61 2>,
++				<&pmux 4 11 1>,
++				<&pmux 5 10 1>,
++				<&pmux 6 13 2>;
++
++			status = "disabled";
++		};
++
++		gpio_chip1: gpio@12141000 {
++			compatible = "arm,pl061", "arm,primecell";
++			reg = <0x12141000 0x1000>;
++			interrupts = <31>;
++			clocks = <&crg_ctrl HI3516CV300_APB_CLK>;
++			clock-names = "apb_pclk";
++			#gpio-cells = <2>;
++			gpio-ranges = <&pmux 0 16 7>,
++				<&pmux 7 0 1>;
++			status = "disabled";
++		};
++
++		gpio_chip2: gpio@12142000 {
++			compatible = "arm,pl061", "arm,primecell";
++			reg = <0x12142000 0x1000>;
++			interrupts = <31>;
++			clocks = <&crg_ctrl HI3516CV300_APB_CLK>;
++			clock-names = "apb_pclk";
++			#gpio-cells = <2>;
++			gpio-ranges = <&pmux 0 46 1>,
++				<&pmux 1 45 1>,
++				<&pmux 2 44 1>,
++				<&pmux 3 43 1>,
++				<&pmux 4 39 1>,
++				<&pmux 5 38 1>,
++				<&pmux 6 40 1>,
++				<&pmux 7 48 1>;
++			status = "disabled";
++		};
++
++		gpio_chip3: gpio@12143000 {
++			compatible = "arm,pl061", "arm,primecell";
++			reg = <0x12143000 0x1000>;
++			interrupts = <31>;
++			clocks = <&crg_ctrl HI3516CV300_APB_CLK>;
++			clock-names = "apb_pclk";
++			#gpio-cells = <2>;
++			gpio-ranges = <&pmux 0 37 1>,
++				<&pmux 1 36 1>,
++				<&pmux 2 35 1>,
++				<&pmux 3 34 1>,
++				<&pmux 4 23 2>,
++				<&pmux 6 8 2>;
++			status = "disabled";
++		};
++
++		gpio_chip4: gpio@12144000 {
++			compatible = "arm,pl061", "arm,primecell";
++			reg = <0x12144000 0x1000>;
++			interrupts = <31>;
++			clocks = <&crg_ctrl HI3516CV300_APB_CLK>;
++			clock-names = "apb_pclk";
++			#gpio-cells = <2>;
++			gpio-ranges = <&pmux 0 27 1>,
++				<&pmux 1 26 1>,
++				<&pmux 2 31 1>,
++				<&pmux 3 30 1>,
++				<&pmux 4 28 2>,
++				<&pmux 6 33 1>,
++				<&pmux 7 32 1>;
++			status = "disabled";
++		};
++
++		gpio_chip5: gpio@12145000 {
++			compatible = "arm,pl061", "arm,primecell";
++			reg = <0x12145000 0x1000>;
++			interrupts = <31>;
++			clocks = <&crg_ctrl HI3516CV300_APB_CLK>;
++			clock-names = "apb_pclk";
++			#gpio-cells = <2>;
++			gpio-ranges = <&pmux 0 53 1>,
++				<&pmux 1 51 2>,
++				<&pmux 3 50 1>,
++				<&pmux 4 49 1>,
++				<&pmux 5 47 1>,
++				<&pmux 6 40 2>;
++			status = "disabled";
++		};
++
++		gpio_chip6: gpio@12146000 {
++			compatible = "arm,pl061", "arm,primecell";
++			reg = <0x12146000 0x1000>;
++			interrupts = <31>;
++			clocks = <&crg_ctrl HI3516CV300_APB_CLK>;
++			clock-names = "apb_pclk";
++			#gpio-cells = <2>;
++			gpio-ranges = <&pmux 0 7 1>,
++				<&pmux 1 6 1>,
++				<&pmux 2 4 1>,
++				<&pmux 3 5 1>,
++				<&pmux 4 15 1>,
++				<&pmux 5 1 3>;
++			status = "disabled";
++		};
++
++		gpio_chip7: gpio@12147000 {
++			compatible = "arm,pl061", "arm,primecell";
++			reg = <0x12147000 0x1000>;
++			interrupts = <31>;
++			clocks = <&crg_ctrl HI3516CV300_APB_CLK>;
++			clock-names = "apb_pclk";
++			#gpio-cells = <2>;
++			gpio-ranges = <&pmux 1 55 6>,
++				<&pmux 7 25 1>;
++			status = "disabled";
++		};
++
++		gpio_chip8: gpio@12148000 {
++			compatible = "arm,pl061", "arm,primecell";
++			reg = <0x12148000 0x1000>;
++			interrupts = <31>;
++			clocks = <&crg_ctrl HI3516CV300_APB_CLK>;
++			clock-names = "apb_pclk";
++			#gpio-cells = <2>;
++			gpio-ranges = <&pmux 0 63 3>,
++				<&pmux 3 12 1>;
++			status = "disabled";
++		};
++
++		pmux: pinmux@12040000 {
++			compatible = "pinctrl-single";
++			reg = <0x12040000 0x108>;
++			#address-cells = <1>;
++			#size-cells = <1>;
++			#gpio-range-cells = <3>;
++			ranges;
++
++			pinctrl-single,register-width = <32>;
++			pinctrl-single,function-mask = <7>;
++			/* pin base, nr pins & gpio function */
++			pinctrl-single,gpio-range = <&range 0 54 0
++				&range 55 6 1 &range 61 5 0>;
++
++			range: gpio-range {
++				#pinctrl-single,gpio-range-cells = <3>;
++			};
++		};
++
++		pconf: pinconf@12040800 {
++			compatible = "pinconf-single";
++			reg = <0x12040800 0x130>;
++			#address-cells = <1>;
++			#size-cells = <1>;
++			ranges;
++
++			pinctrl-single,register-width = <32>;
++		};
++	};
++
++	media {
++		#address-cells = <1>;
++		#size-cells = <1>;
++		compatible = "simple-bus";
++		interrupt-parent = <&vic>;
++		ranges;
++
++		sys: sys@12010000 {
++			compatible = "hisilicon,hi35xx_sys";
++			reg = <0x12010000 0x10000>, <0x12020000 0x10000>,
++				<0x12060000 0x10000>, <0X12030000 0x10000>;
++			reg-names = "crg", "sys", "ddr", "misc";
++		};
++
++		audio: audio@11310000 {
++			compatible = "hisilicon,hi35xx_aiao";
++			interrupts = <9>;
++			reg = <0x11310000 0x10000>, <0x11320000 0x2000>;
++			reg-names = "aiao", "acodec";
++			clocks = <&crg_ctrl HI3516CV300_AIAO_CLK>;
++		};
++
++		ive: ive@11230000 {
++			compatible = "hisilicon,hi35xx_ive";
++			interrupts = <21>;
++			reg = <0x11230000 0x10000>;
++			clocks = <&crg_ctrl HI3516CV300_IVE_CLK>;
++		};
++
++		sensor_device0: sensor_device0 {
++			compatible = "hisilicon,hi35xx_sensor";
++			clocks = <&crg_ctrl HI3516CV300_SENSOR_CLK>;
++		};
++
++		mipi: mipi@11300000 {
++			compatible = "hisilicon,hi35xx_mipi";
++			interrupts = <28>;
++			reg = <0x11300000 0x10000>;
++			clocks = <&crg_ctrl HI3516CV300_MIPI_CLK>;
++		};
++
++		isp: isp@11380000 {
++			compatible = "hisilicon,hi35xx_isp";
++			interrupts = <22>;
++			reg = <0x11380000 0x10000>, <0x11392200 0x40000>;
++			reg-names = "reg_vicap_base_va", "reg_isp_base_va";
++		};
++
++		viu: viu@11380000 {
++			compatible = "hisilicon,hi35xx_viu";
++			interrupts = <22>;
++			interrupt-names = "viu0";
++			reg = <0x11380000 0x70000>;
++			reg-names = "viu0";
++			clocks = <&crg_ctrl HI3516CV300_VIU_CLK>, <&crg_ctrl HI3516CV300_ISP_CLK>;
++			clock-names = "viu0", "isp0";
++		};
++
++		vou: vou@11400000 {
++			compatible = "hisilicon,hi35xx_vou";
++			interrupts = <23>;
++			reg = <0x11400000 0x10000>;
++		};
++
++		vgs: vgs@11240000 {
++			compatible = "hisilicon,hi35xx_vgs";
++			interrupts = <29>;
++			reg = <0x11240000 0x10000>;
++			clocks = <&crg_ctrl HI3516CV300_VGS_CLK>;
++		};
++
++		vpss: vpss@11250000 {
++			compatible = "hisilicon,hi35xx_vpss";
++			interrupts = <17>, <22>;
++			interrupt-names = "vpss", "vi";
++			reg = <0x11250000 0x10000>;
++			clocks = <&crg_ctrl HI3516CV300_VPSS_CLK>;
++		};
++
++		vedu: vedu@11260000 {
++				compatible = "hisilicon,hi35xx_vedu";
++				interrupts = <24>;
++				reg = <0x11260000 0x10000>;
++				clocks = <&crg_ctrl HI3516CV300_VEDU_CLK>;
++		};
++
++		jpege: jpege@11220000 {
++				compatible = "hisilicon,hi35xx_jpege";
++				interrupts = <26>;
++				reg = <0x11220000 0x10000>;
++				clocks = <&crg_ctrl HI3516CV300_JPGE_CLK>;
++		};
++
++		pwm: pwm@12130000 {
++			compatible = "hisilicon,hi3516cv300-pwm";
++			reg = <0x12130000 0x10000>;
++			clocks = <&crg_ctrl HI3516CV300_PWM_CLK>;
++			resets = <&crg_ctrl 0x38 0>;
++			#pwm-cells = <3>;
++			status = "disabled";
++		};
++
++		piris: piris@12140000 {
++			compatible = "hisilicon,piris";
++			reg = <0x12140000 0x10000>;
++		};
++
++		wtdg: wtdg@12080000 {
++			compatible = "hisilicon,hi_wdg";
++			reg = <0x12080000 0x10000>;
++			reg-names = "wtdg";
++		};
++
++		rtc: rtc@12090000 {
++			compatible = "hisilicon,hi_rtc";
++			interrupts = <2>;
++			reg = <0x12090000 0x10000>;
++		};
++
++		ir: ir@120f0000{
++			compatible = "hisilicon,hi_ir";
++			interrupts = <19>;
++			reg = <0x120f0000 0x10000>;
++		};
++
++		online_flag: online_flag {
++			compatible = "hisilicon,vi-vpss-online";
++		};
++
++		pin_ctrl_ddr: pin_ctrl_ddr {
++			compatible = "hisilicon,pinctrl-ddr";
++		};
++
++		pin_ctrl_online: pin_ctrl_online {
++			compatible = "hisilicon,pinctrl-online";
++		};
++
++		pin_ctrl_offline: pin_ctrl_offline {
++			compatible = "hisilicon,pinctrl-offline";
++		};
++
++		user_pinmux: user_pinmux {
++			compatible = "hisilicon,user_define_pinmux";
++		};
++	};
++};
+diff --git a/arch/arm/boot/dts/hi3521d-demb.dts b/arch/arm/boot/dts/hi3521d-demb.dts
+new file mode 100644
+index 0000000..548ed81
+--- /dev/null
++++ b/arch/arm/boot/dts/hi3521d-demb.dts
+@@ -0,0 +1,275 @@
++/*
++ * Copyright (c) 2013-2014 Linaro Ltd.
++ * Copyright (c) 2015-2017 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++/dts-v1/;
++#include "hi3521d.dtsi"
++
++/ {
++	model = "Hisilicon HI3521D DEMO Board";
++	compatible = "hisilicon,hi3521d";
++
++	cpus {
++		#address-cells = <1>;
++		#size-cells = <0>;
++		enable-method = "hisilicon,hi3521d-smp";
++
++		cpu@0 {
++			compatible = "arm,cortex-a7";
++			device_type = "cpu";
++			clock-frequency = <HI3521D_FIXED_1500M>;
++			reg = <0>;
++		};
++
++		cpu@1 {
++			compatible = "arm,cortex-a7";
++			device_type = "cpu";
++			clock-frequency = <HI3521D_FIXED_1500M>;
++			reg = <1>;
++		};
++	};
++
++	memory {
++		device_type = "memory";
++		reg = <0x80000000 0x40000000>;
++	};
++};
++
++&uart0 {
++	status = "okay";
++};
++
++&spi_bus0{
++	status = "okay";
++	num-cs = <2>;
++
++	spidev@0 {
++		compatible = "spidev";
++		reg = <0>;
++		pl022,interface = <0>;
++		pl022,com-mode = <0>;
++		spi-max-frequency = <31250000>;
++	};
++
++	spidev@1 {
++		compatible = "spidev";
++		reg = <1>;
++		pl022,interface = <0>;
++		pl022,com-mode = <0>;
++		spi-max-frequency = <31250000>;
++	};
++};
++
++&hisfc {
++	hi_sfc {
++		compatible = "jedec,spi-nor";
++		reg = <0>;
++		spi-max-frequency = <160000000>;
++		m25p,fast-read;
++	};
++};
++
++&hisnfc {
++	hinand {
++		compatible = "jedec,spi-nand";
++		reg = <0>;
++		spi-max-frequency = <160000000>;
++	};
++};
++
++&hidmac {
++    status = "okay";
++};
++
++&mdio {
++	ethphy: ethernet-phy@1 {
++		reg = <1>;
++	};
++};
++
++&higmac {
++	phy-handle = <&ethphy>;
++	phy-mode = "rgmii";
++};
++
++&pmux {
++
++	viadclk_demob_pmux: viadclk_demob_pmux{
++		pinctrl-single,pins = <
++			0x0000 0x2
++			0x0024 0x2
++			0x0048 0x2
++			0x0070 0x2
++			0x0094 0x2
++		>;
++	};
++
++	viadclk_sck_pmux: viadclk_sck_pmux{
++		pinctrl-single,pins = <
++			0x0000 0x2
++			0x004c 0x2
++			0x0024 0x2
++			0x0048 0x2
++			0x0070 0x2
++			0x0094 0x2
++		>;
++	};
++
++	vicap_demob_pmux: vicap_demob_pmux{
++		pinctrl-single,pins = <
++			0x0004 0x1
++			0x0008 0x1
++			0x000c 0x1
++			0x0010 0x1
++			0x0014 0x1
++			0x0018 0x1
++			0x001c 0x1
++			0x0020 0x1
++			0x0028 0x1
++			0x002c 0x1
++			0x0030 0x1
++			0x0034 0x1
++			0x0038 0x1
++			0x003c 0x1
++			0x0040 0x1
++			0x0044 0x1
++			0x0050 0x1
++			0x0054 0x1
++			0x0058 0x1
++			0x005c 0x1
++			0x0060 0x1
++			0x0064 0x1
++			0x0068 0x1
++			0x006c 0x1
++			0x0074 0x1
++			0x0078 0x1
++			0x007c 0x1
++			0x0080 0x1
++			0x0084 0x1
++			0x0088 0x1
++			0x008c 0x1
++			0x0090 0x1
++		>;
++	};
++
++	vo_vga_pmux: vo_vga_pmux{
++		pinctrl-single,pins = <
++			0x0174 0x1
++			0x017c 0x1
++			0x0180 0x1
++		>;
++	};
++
++	vo_hdmi_pmux: vo_hdmi_pmux{
++		pinctrl-single,pins = <
++			0x0098 0x1
++			0x009c 0X1
++		>;
++	};
++
++	i2s0_pmux: i2s0_pmux {
++		pinctrl-single,pins = <
++			0x00a0 0x1
++			0x00a4 0x1
++			0x00a8 0x1
++		>;
++	};
++
++	i2s1_pmux: i2s1_pmux {
++		pinctrl-single,pins = <
++			0x00b0 0x1
++			0x00b4 0x1
++		>;
++	};
++
++	i2s2_demob_pmux: i2s2_demob_pmux {
++		pinctrl-single,pins = <
++			0x00b8 0x1
++			0x00bc 0x1
++			0x00c0 0x1
++		>;
++	};
++
++	i2s2_sck_pmux: i2s2_sck_pmux {
++		pinctrl-single,pins = <
++			0x00b8 0x1
++			0x00bc 0x1
++			0x00c0 0x1
++			0x00ac 0x2
++		>;
++	};
++};
++
++&sys_config_ctrl {
++	padctrl-ability,demo = <
++		0x120f08a0 0x120
++		0x120f08a4 0x130
++		0x120f08a8 0x130
++		0x120f08ac 0x120
++		0x120f08b0 0x130
++		0x120f08b4 0x130
++		0x120f08b8 0x120
++		0x120f08bc 0x130
++		0x120f08c0 0x130
++		0x120f0800 0x140
++		0x120f084c 0x140
++		0x120f0898 0x40
++		0x120f089c 0x40
++	>;
++
++	sysctrl-ddr,pins = <
++		0x12040098 0x00ffff1f
++		0x1204009c 0x8888
++		0x12040168 0x00000f55
++		0x1212007c 0x35533201
++		0x12120080 0x65335526
++		0x12120084 0x66666666
++		0x12120094 0x65       /*VIVO axi max: 7*/
++	>;
++	dllctrl-ddr,pins = <
++		0x120401e0 0x0      /*DLL rst, disable*/
++		0x120401ec 0x0
++		0x120401f8 0x0
++		0x12040204 0x0
++	        0x120401e0 0x4      /*DLL rst, disable*/
++		0x120401ec 0x4
++		0x120401f8 0x4
++		0x12040204 0x4
++		0x120401e0 0x6       /*DLL 150M and DLL rst, disable*/
++		0x120401ec 0x6
++		0x120401f8 0x6
++		0x12040204 0x6
++	        0x120401e0 0x7       /*DLL 150M and DLL rst, enable*/
++		0x120401ec 0x7
++		0x120401f8 0x7
++		0x12040204 0x7
++	        0x120401e0 0x3       /*DLL 150M and DLL unrst, enable*/
++		0x120401ec 0x3
++		0x120401f8 0x3
++		0x12040204 0x3
++		0x120401e4 0x10      /*dll_slave_en:1,dll_stop:0*/
++		0x120401F0 0x10
++		0x120401fC 0x10
++		0x12040208 0x10
++	>;
++
++	pinctrl-names =  "demo", "sck", "default";
++	pinctrl-0 = <&viadclk_demob_pmux &vicap_demob_pmux &i2s0_pmux  &i2s2_demob_pmux &vo_hdmi_pmux &vo_vga_pmux>;
++	pinctrl-1 = <&viadclk_sck_pmux   &vicap_demob_pmux &i2s0_pmux  &i2s1_pmux &i2s2_sck_pmux &vo_hdmi_pmux &vo_vga_pmux >;
++	pinctrl-2 = <>;
++};
+diff --git a/arch/arm/boot/dts/hi3521d.dtsi b/arch/arm/boot/dts/hi3521d.dtsi
+new file mode 100644
+index 0000000..5a2a2da
+--- /dev/null
++++ b/arch/arm/boot/dts/hi3521d.dtsi
+@@ -0,0 +1,392 @@
++/*
++ * Copyright (c) 2013-2014 Linaro Ltd.
++ * Copyright (c) 2015-2017 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include "skeleton.dtsi"
++#include <dt-bindings/clock/hi3521d-clock.h>
++/ {
++	aliases {
++		fmc = &fmc;
++		serial0 = &uart0;
++		spi0 = &spi_bus0;
++	};
++
++	clock: clock@12040000 {
++		compatible = "hisilicon,hi3521d-clock";
++		#address-cells = <1>;
++		#size-cells = <1>;
++		#clock-cells = <1>;
++		#reset-cells = <2>;
++		reg = <0x12040000 0x1000>;
++	};
++
++	gic: interrupt-controller@10300000 {
++		compatible = "arm,cortex-a7-gic";
++		#interrupt-cells = <3>;
++		#address-cells = <0>;
++		interrupt-controller;
++		/* gic dist base, gic cpu base , no virtual support */
++		reg = <0x10301000 0x1000>, <0x10302000 0x100>;
++	 };
++
++	soc {
++		#address-cells = <1>;
++		#size-cells = <1>;
++		compatible = "simple-bus";
++		interrupt-parent = <&gic>;
++		ranges;
++
++		sysctrl: system-controller@12050000 {
++			compatible = "hisilicon,sysctrl";
++			reg = <0x12050000 0x1000>;
++			reboot-offset = <0x4>;
++			#clock-cells = <1>;
++		};
++
++		pmu {
++			compatible = "arm,cortex-a7-pmu";
++			interrupts = <0 54 4>,
++					<0 48 4>;
++		};
++
++		amba {
++			#address-cells = <1>;
++			#size-cells = <1>;
++			compatible = "arm,amba-bus";
++			ranges;
++
++			uart0: uart@12080000 {
++				compatible = "arm,pl011", "arm,primecell";
++				reg = <0x12080000 0x1000>;
++				interrupts = <0 6 4>;
++				clocks = <&clock HI3521D_UART0_CLK>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++			};
++
++			uart1: uart@121090000 {
++				compatible = "arm,pl011", "arm,primecell";
++				reg = <0x12090000 0x1000>;
++				interrupts = <0 7 4>;
++				clocks = <&clock HI3521D_UART1_CLK>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++			};
++
++			uart2: uart@120a0000 {
++				compatible = "arm,pl011", "arm,primecell";
++				reg = <0x120a0000 0x1000>;
++				interrupts = <0 8 4>;
++				clocks = <&clock HI3521D_UART2_CLK>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++			};
++
++			timer@0x12000000 {
++				compatible = "hisilicon,timer";
++				/* timer0 & timer1 & timer2*/
++				reg = <0x12000000 0x20>, /* clocksource */
++					  <0x12000020 0x20>, /* local timer for each cpu */
++					  <0x12010000 0x20>;
++				interrupts = <0 1 4>, <0 2 4>; /* irq of local timer */
++				clocks = <&sysctrl HI3521D_TIME0_0_CLK>;
++				clock-names = "timer00";
++			};
++		};
++
++		/* dual timer 0 and 1 have used for clocksource and local timer */
++		dual_timer2: dual_timer@12020000 {
++			compatible = "arm,sp804", "arm,primecell";
++			/* timer4 & timer5 */
++			interrupts = <0 3 4>;
++			reg = <0x12020000 0x1000>;
++			clocks = <&sysctrl HI3521D_TIME2_4_CLK>,
++					<&sysctrl HI3521D_TIME2_5_CLK>,
++					<&clock HI3521D_SYSAXI_CLK>;
++			clock-names = "timer4", "timer5", "apb_pclk";
++			status = "disabled";
++		};
++
++		dual_timer3: dual_timer@12030000 {
++			compatible = "arm,sp804", "arm,primecell";
++			/* timer6 & timer7 */
++			interrupts = <0 4 4>;
++			reg = <0x12030000 0x1000>;
++			clocks = <&sysctrl HI3521D_TIME3_6_CLK>,
++					<&sysctrl HI3521D_TIME3_7_CLK>,
++					<&clock HI3521D_SYSAXI_CLK>;
++			clock-names = "timer6", "timer7", "apb_pclk";
++			status = "disabled";
++		};
++
++		spi_bus0: spi@120d0000 {
++				compatible = "arm,pl022", "arm,primecell";
++				arm,primecell-periphid = <0x00800022>;
++				reg = <0x120d0000 0x1000>, <0x12120014 0x4>;
++				interrupts = <0 14 4>;
++				clocks = <&clock HI3521D_SPI0_CLK>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++				#address-cells = <1>;
++				#size-cells = <0>;
++				hisi,spi_cs_sb = <0>;
++				hisi,spi_cs_mask_bit = <0x00000003>;
++		};
++
++		sata_phy: phy@11010000 {
++			compatible = "hisilicon,hisi-sata-nano-phy";
++			reg = <0x11010000 0x10000>;
++			#phy-cells = <0>;
++		};
++
++		ahci: sata@11010000 {
++			compatible = "hisilicon,hisi-ahci";
++			reg = <0x11010000 0x1000>;
++			interrupts = <0 17 4>;
++			phys = <&sata_phy>;
++			phy-names = "sata-phy";
++			#address-cells = <1>;
++			#size-cells = <0>;
++		};
++
++		usb_phy: usbphy {
++			compatible = "hisilicon,hi3521d-usb2-phy";
++			reg = <0x12040000 0x1000>, <0x12120000 0x1000>;
++		};
++
++		ehci@0x10120000 {
++			compatible = "generic-ehci";
++			reg = <0x10040000 0x10000>;
++			interrupts = <0 19 4>;
++		};
++
++		ohci@0x10110000 {
++			compatible = "generic-ohci";
++			reg = <0x10030000 0x10000>;
++			interrupts = <0 18 4>;
++		};
++
++		mdio: mdio@100a03c0 {
++			compatible = "hisilicon,hisi-gemac-mdio";
++			reg = <0x100a03c0 0x20>;
++			clocks = <&clock HI3521D_ETH_CLK>;
++			resets = <&clock 0x14c 5>;
++			reset-names = "phy_reset";
++			#address-cells = <1>;
++			#size-cells = <0>;
++		};
++
++		higmac: ethernet@100a0000 {
++			compatible = "hisilicon,higmac-v5";
++			reg = <0x100a0000 0x1000>,<0x100a300c 0x4>;
++			interrupts = <0 16 4>, <0 61 4>, <0 62 4>, <0 63 4>;
++
++			clocks = <&clock HI3521D_ETH_CLK>,
++					<&clock HI3521D_ETH_MACIF_CLK>;
++			clock-names = "higmac_clk",
++					"macif_clk";
++
++			resets = <&clock 0x14c 0>,
++					<&clock 0x14c 2>,
++					<&clock 0x14c 5>;
++			reset-names = "port_reset",
++					"macif_reset",
++					"phy_reset";
++
++			mac-address = [00 00 00 00 00 00];
++		};
++
++		fmc: flash-memory-controller@10000000 {
++			compatible = "hisilicon,hisi-fmc";
++			reg = <0x10000000 0x1000>, <0x14000000 0x10000>;
++			reg-names = "control", "memory";
++			clocks = <&clock HI3521D_FMC_CLK>;
++			#address-cells = <1>;
++			#size-cells = <0>;
++
++			hisfc:spi_nor_controller {
++				compatible = "hisilicon,hisi-sfc";
++				assigned-clocks = <&clock HI3521D_FMC_CLK>;
++				assigned-clock-rates = <24000000>;
++				#address-cells = <1>;
++				#size-cells = <0>;
++			};
++
++			hisnfc:spi_nand_controller {
++				compatible = "hisilicon,hisi-spi-nand";
++				assigned-clocks = <&clock HI3521D_FMC_CLK>;
++				assigned-clock-rates = <24000000>;
++				#address-cells = <1>;
++				#size-cells = <0>;
++			};
++		};
++
++		hidmac: hidma-controller@10060000 {
++			compatible = "hisilicon,hisi-dmac";
++			reg = <0x10060000 0x1000>;
++			interrupts = <0 10 4>;
++			clocks = <&clock HI3521D_DMAC_CLK>;
++			clock-names = "dmac_clk";
++			resets = <&clock 0x144 0>;
++			reset-names = "dma-reset";
++			#dma-cells = <2>;
++			status = "disabled";
++		};
++
++		pmux: pinmux@120F0000 {
++			compatible = "pinctrl-single";
++			reg = <0x120F0000 0x3A8>;
++			#address-cells = <1>;
++			#size-cells = <1>;
++			#gpio-range-cells = <3>;
++			ranges;
++
++			pinctrl-single,register-width = <32>;
++			pinctrl-single,function-mask = <7>;
++			/* pin base, nr pins & gpio function */
++			pinctrl-single,gpio-range = <&range 0 54 0
++				&range 55 6 1 &range 61 5 0>;
++
++			range: gpio-range {
++				#pinctrl-single,gpio-range-cells = <3>;
++			};
++		};
++	};
++
++	media {
++		#address-cells = <1>;
++		#size-cells = <1>;
++		compatible = "simple-bus";
++		interrupt-parent = <&gic>;
++		ranges;
++
++		osal: osal {
++			compatible = "hisilicon,osal";
++		};
++
++		sys: sys@12040000 {
++			compatible = "hisilicon,hi35xx_sys";
++			reg = <0x12040000 0x10000>, <0x12050000 0x10000>,
++				<0x12110000 0x10000>, <0x12120000 0x10000>;
++			reg-names = "crg", "sys", "ddr", "misc";
++		};
++
++		viu: viu@130C0000 {
++			compatible = "hisilicon,hi35xx_viu";
++			interrupts = <0 28 4>;
++			reg = <0x130C0000 0x40000>;
++			clocks = <&clock HI3521D_VIU_CLK>;
++			clock-names = "viu";
++		};
++
++		vou: vou@13020000 {
++			compatible = "hisilicon,hi35xx_vou";
++			interrupts = <0 30 4>;
++			reg = <0x13020000 0x10000>;
++		};
++
++		vda: vda@13150000 {
++			compatible = "hisilicon,hi35xx_vda";
++			interrupts = <0 43 4>;
++			reg = <0x13150000 0x10000>;
++		};
++
++		ive: ive@13060000 {
++			compatible = "hisilicon,hi35xx_ive";
++			interrupts = <0 33 4>;
++			reg = <0x13060000 0x10000>;
++		};
++
++		vgs: vgs@13080000 {
++			compatible = "hisilicon,hi35xx_vgs";
++			interrupts = <0 35 4>;
++			reg = <0x13080000 0x10000>;
++		};
++
++		vpss: vpss@13110000 {
++				compatible = "hisilicon,hi35xx_vpss";
++				interrupts = <0 37 4>;
++				interrupt-names = "vpss0";
++				reg = <0x13110000 0x10000>;
++				reg-names = "vpss0";
++		};
++
++		audio: audio@13140000 {
++			compatible = "hisilicon,hi35xx_aiao";
++			interrupts = <0 40 4>;
++			reg = <0x13140000 0x10000>, <0x13120000 0x10000>;
++			reg-names = "aiao", "voie";
++		};
++
++		vdec: vdec@13100000 {
++			compatible = "hisilicon,hi35xx_vdec";
++			interrupts =<0 21 4> , <0 23 4>;
++			interrupt-names ="vdm", "scd";
++			reg = <0x13100000 0xc000>, <0x1310c000 0x4000>;
++			reg-names = "vdm", "scd";
++		};
++
++		tde: tde@13050000 {
++			compatible = "hisilicon,hi35xx_tde";
++			interrupts = <0 32 4>;
++			reg = <0x13050000 0x1000>;
++		};
++
++		jpgd: jpgd@13070000 {
++			compatible = "hisilicon,hi35xx_jpgd";
++			interrupts = <0 34 4>;
++			interrupt-names = "jpgd";
++			reg = <0x13070000 0x10000>;
++			reg-names = "jpgd";
++		};
++
++		vedu: vedu@13040000 {
++			compatible = "hisilicon,hi35xx_vedu";
++			interrupts = <0 31 4>;
++			interrupt-names = "vedu0";
++			reg = <0x13040000 0x10000>;
++			reg-names = "vedu0";
++		};
++
++		jpege: jpege@13130000 {
++			compatible = "hisilicon,hi35xx_jpege";
++			interrupts = <0 39 4>;
++			reg = <0x13130000 0x10000>;
++		};
++
++		online_flag: online_flag {
++			compatible = "hisilicon,vi-vpss-online";
++		};
++
++		sys_config_ctrl: sys_config_ctrl {
++			compatible = "hisilicon,sys_config_ctrl";
++		};
++
++		pin_ctrl_ddr: pin_ctrl_ddr {
++			compatible = "hisilicon,pinctrl-ddrpinctrl-ddr";
++		};
++
++		pin_ctrl_online: pin_ctrl_online {
++			compatible = "hisilicon,pinctrl-online";
++		};
++
++		pin_ctrl_offline: pin_ctrl_offline {
++			compatible = "hisilicon,pinctrl-offline";
++		};
++	};
++};
+diff --git a/arch/arm/boot/dts/hi3531d-demb.dts b/arch/arm/boot/dts/hi3531d-demb.dts
+new file mode 100644
+index 0000000..901076a
+--- /dev/null
++++ b/arch/arm/boot/dts/hi3531d-demb.dts
+@@ -0,0 +1,558 @@
++/*
++ * Copyright (c) 2013-2014 Linaro Ltd.
++ * Copyright (c) 2015-2017 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++/dts-v1/;
++#include "hi3531d.dtsi"
++
++/ {
++	model = "Hisilicon HI3531D DEMO Board";
++	compatible = "hisilicon,hi3531d";
++
++	cpus {
++		#address-cells = <1>;
++		#size-cells = <0>;
++		enable-method = "hisilicon,hi3531d-smp";
++
++		cpu@0 {
++			compatible = "arm,cortex-a9";
++			device_type = "cpu";
++			reg = <0>;
++			next-level-cache = <&L2>;
++		};
++
++		cpu@1 {
++			compatible = "arm,cortex-a9";
++			device_type = "cpu";
++			reg = <1>;
++			next-level-cache = <&L2>;
++		};
++	};
++
++	memory {
++		device_type = "memory";
++		reg = <0x40000000 0xc0000000>;
++	};
++};
++
++&uart0 {
++	status = "okay";
++};
++
++&spi_bus0{
++	status = "okay";
++	num-cs = <4>;
++
++	spidev@0 {
++		compatible = "spidev";
++		reg = <0>;
++		pl022,interface = <0>;
++		pl022,com-mode = <0>;
++		spi-max-frequency = <40500000>;
++	};
++
++	spidev@1 {
++		compatible = "spidev";
++		reg = <1>;
++		pl022,interface = <0>;
++		pl022,com-mode = <0>;
++		spi-max-frequency = <40500000>;
++	};
++
++	spidev@2 {
++		compatible = "spidev";
++		reg = <2>;
++		pl022,interface = <0>;
++		pl022,com-mode = <0>;
++		spi-max-frequency = <40500000>;
++	};
++
++	spidev@3 {
++		compatible = "spidev";
++		reg = <3>;
++		pl022,interface = <0>;
++		pl022,com-mode = <0>;
++		spi-max-frequency = <40500000>;
++	};
++};
++
++&hisfc {
++	hi_sfc {
++		compatible = "jedec,spi-nor";
++		reg = <0>;
++		spi-max-frequency = <160000000>;
++		m25p,fast-read;
++	};
++};
++
++&hisnfc {
++	hinand {
++		compatible = "jedec,spi-nand";
++		reg = <0>;
++		spi-max-frequency = <160000000>;
++	};
++};
++
++&hinfc610 {
++	assigned-clocks = <&clock HI3531D_NFC_CLK>;
++	assigned-clock-rates = <200000000>;
++
++	hinand {
++		compatible = "jedec,nand";
++		reg = <0>;
++		nand-max-frequency = <200000000>;
++	};
++};
++
++&hidmac {
++    status = "okay";
++};
++
++&mdio {
++	ethphy: ethernet-phy@1 {
++		reg = <1>;
++	};
++};
++
++&higmac {
++	phy-handle = <&ethphy>;
++	phy-mode = "rgmii";
++};
++
++&pmux {
++	i2c0_pmux: i2c0_pmux {
++		pinctrl-single,pins = <
++			0x01CC 0x1	/*I2C0_SDA*/
++			0x01D0 0x1	/*I2C0_SCL*/
++		>;
++	};
++
++	i2c1_pmux: i2c1_pmux {
++		pinctrl-single,pins = <
++			0x0148 0x2	/*I2C1_SDA*/
++			0x014C 0x2	/*I2C1_SCL*/
++		>;
++	};
++
++	vicap_demob_pmux: vicap_demob_pmux{
++		pinctrl-single,pins = <
++			0x0000 0x0  /*VI0_CLK*/
++			0x0024 0x0  /*VI1_CLK*/
++			0x0048 0x1  /*VI_ADC_REFCLK0*/
++			0x004c 0x0  /*VI2_CLK*/
++			0x0070 0x0  /*VI3_CLK*/
++			0x0094 0x1  /*VI_ADC_REFCLK1*/
++			0x0098 0x0  /*VI4_CLK*/
++			0x00bc 0x0  /*VI5_CLK*/
++			0x00e4 0x0  /*VI6_CLK*/
++			0x0108 0x0  /*VI7_CLK*/
++		>;
++	};
++	vicap_demopro_pmux: vicap_demopro_pmux{
++		pinctrl-single,pins = <
++			0x0000 0x2  /*VI_ADC_REFCLK0*/
++			0x0024 0x2  /*VI0_CLK*/
++			0x0048 0x2  /*VI1_CLK*/
++			0x004c 0x2  /*VI_ADC_REFCLK1*/
++			0x0070 0x2  /*VI2_CLK*/
++			0x0094 0x2  /*VI3_CLK*/
++			0x00bc 0x2  /*VI_ADC_REFCLK2*/
++			0x00E0 0x2  /*VI4_CLK */
++			0x0108 0x2  /*VI_ADC_REFCLK3*/
++			0x012C 0x2  /*VI6_CLK */
++		>;
++	};
++	vicap_cascade_pmux: vicap_cascade_pmux{
++		pinctrl-single,pins = <
++			0x0290 0x1 /*VI8_DAT14*/
++			0x0294 0x1 /*VI8_DAT13*/
++			0x0298 0x1 /*VI8_DAT12*/
++			0x029C 0x1 /*VI8_DAT11*/
++			0x02A0 0x1 /*VI8_DAT10*/
++			0x02A4 0x1 /*VI8_DAT9 */
++			0x02A8 0x1 /*VI8_DAT8 */
++			0x02AC 0x1 /*VI8_DAT7 */
++			0x02B0 0x1 /*VI8_DAT1 */
++			0x02B4 0x1 /*VI8_CLK  */
++			0x02B8 0x1 /*VI8_DAT3 */
++			0x02BC 0x1 /*VI8_DAT4 */
++			0x02C0 0x1 /*VI8_DAT5 */
++			0x02C4 0x1 /*VI8_DAT6 */
++			0x02C8 0x1 /*VI8_DAT2 */
++			0x02CC 0x1 /*VI8_DAT0 */
++			0x02D0 0x1 /*VI8_DAT15*/
++		>;
++	};
++
++	vicap_sck_pmux: vicap_sck_pmux{
++		pinctrl-single,pins = <
++			0x0000 0x2				/* 0: VI0_CLK   1: GPIO21_0        2: VI_ADC_REFCLK0 */
++			0x0024 0x2				/* 0: VI1_CLK   1: GPIO21_1        2: VI0_CLK        */
++			0x0048 0x2				/* 0: GPIO21_2  1: VI_ADC_REFCLK0  2: VI1_CLK */   
++			0x004c 0x2				/* 0: VI2_CLK   1: GPIO21_3        2: VI_ADC_REFCLK1 */
++			0x0070 0x2				/* 0: VI3_CLK   1: GPIO21_4        2: VI2_CLK        */
++			0x0094 0x2				/* 0: GPIO21_5  1: VI_ADC_REFCLK1  2: VI3_CLK        */
++			0x0098 0x2				/* 0: VI4_CLK   1: GPIO21_6        2: VI_ADC_REFCLK2 */
++			0x00bc 0x2				/* 0: VI5_CLK   1: GPIO21_7        2: VI4_CLK        */
++			0x00E0 0x2				/* 0: GPIO12_1  1: VI_ADC_REFCLK2  2: VI5_CLK        */
++			0x00e4 0x2				/* 0: VI6_CLK   1: GPIO12_2        2: VI_ADC_REFCLK3 */
++			0x0108 0x2				/* 0: VI7_CLK   1: GPIO15_7        2: VI6_CLK        */
++			0x012C 0x2				/* 0: GPIO20_6  1: VI_ADC_REFCLK3  2: VI7_CLK        */
++		>;
++	};
++
++	vo_bt1120_pmux_demo: vo_bt1120_pmux_demo{
++		pinctrl-single,pins = <
++			0x0154 0x1	/*VOU_SLV_DAT15*/
++			0x0158 0x1	/*VOU_SLV_DAT1*/
++			0x015C 0x1	/*VOU1120_DAT1*/
++			0x0160 0x1	/*VOU1120_DAT2*/
++			0x0164 0x1	/*VOU1120_DAT3*/
++			0x0168 0x1	/*VOU1120_DAT4*/
++			0x016C 0x1	/*VOU1120_DAT5*/
++			0x0170 0x1	/*VOU1120_DAT6*/
++			0x0174 0x1	/*VOU1120_DAT7*/
++			0x0178 0x1	/*VOU1120_DAT8*/
++			0x017C 0x1	/*VOU1120_DAT9*/
++			0x0180 0x1	/*VOU1120_DAT10*/
++			0x0184 0x1	/*VOU1120_DAT11*/
++			0x0188 0x1	/*VOU1120_DAT12*/
++			0x018C 0x1	/*VOU1120_DAT13*/
++			0x0190 0x1	/*VOU1120_DAT14*/
++			0x0194 0x1	/*VOU1120_DAT15*/
++		>;
++	};
++
++	vo_bt1120_pmux_slave1: vo_bt1120_pmux_slave1{
++		pinctrl-single,pins = <
++			0x01D4 0x1	/*VOU_SLV_DAT15*/
++			0x01D8 0x1	/*VOU_SLV_DAT1*/
++			0x01DC 0x1	/*VOU_SLV_DAT0*/
++			0x01E0 0x1	/*VOU_SLV_DAT9*/
++			0x01E4 0x1	/*VOU_SLV_DAT14*/
++			0x01E8 0x1	/*VOU_SLV_DAT8*/
++			0x01EC 0x1	/*VOU_SLV_CLK*/
++			0x01F0 0x1	/*VOU_SLV_DAT2*/
++			0x01F4 0x1	/*VOU_SLV_DAT3*/
++			0x01F8 0x1	/*VOU_SLV_DAT5 */
++			0x01FC 0x1	/*VOU_SLV_DAT4 */
++			0x0200 0x1	/*VOU_SLV_DAT11*/
++			0x0204 0x1	/*VOU_SLV_DAT10*/
++			0x0208 0x1	/*VOU_SLV_DAT7 */
++			0x020C 0x1	/*VOU_SLV_DAT6 */
++			0x0210 0x1	/*VOU_SLV_DAT12*/
++			0x0214 0x1	/*VOU_SLV_DAT13*/
++		>;
++	};
++
++	vo_bt1120_pmux_slave2: vo_bt1120_pmux_slave2{
++		pinctrl-single,pins = <
++			0x01D4 0x1	/*VOU_SLV_DAT15*/
++			0x01D8 0x1	/*VOU_SLV_DAT1*/
++			0x01DC 0x1	/*VOU_SLV_DAT0*/
++			0x01E0 0x1	/*VOU_SLV_DAT9*/
++			0x01E4 0x1	/*VOU_SLV_DAT14*/
++			0x01E8 0x1	/*VOU_SLV_DAT8*/
++			0x01EC 0x1	/*VOU_SLV_CLK*/
++			0x01F0 0x1	/*VOU_SLV_DAT2*/
++			0x01F4 0x1	/*VOU_SLV_DAT3*/
++			0x01F8 0x1	/*VOU_SLV_DAT5 */
++			0x01FC 0x1	/*VOU_SLV_DAT4 */
++			0x0200 0x1	/*VOU_SLV_DAT11*/
++			0x0204 0x1	/*VOU_SLV_DAT10*/
++			0x0208 0x1	/*VOU_SLV_DAT7 */
++			0x020C 0x1	/*VOU_SLV_DAT6 */
++			0x0210 0x1	/*VOU_SLV_DAT12*/
++			0x0214 0x1	/*VOU_SLV_DAT13*/
++		>;
++	};
++
++
++	vo_vga_pmux: vo_vga_pmux{
++		pinctrl-single,pins = <
++			0x01A4 0x1	/*VGA_HS*/
++			0x01A8 0X1	/*VGA_VS*/
++		>;
++	};
++
++	i2s0_pmux: i2s0_pmux {
++		pinctrl-single,pins = <
++			0x0130 0x1  /*  0: GPIO11_0   1: I2S0_BCLK_RX */
++			0x0134 0x1  /*  0: GPIO11_1   1: I2S0_WS_RX   */
++			0x0138 0x1  /*  0: GPIO11_2   1: I2S0_SD_RX   */
++			0x01B4 0x1  /*  0: GPIO12_0   1: I2S2_SD_RX   */
++			0x01BC 0x1  /*  0: GPIO12_4   1: I2S2_MCLK    */
++		>;
++	};
++
++	i2s1_pmux: i2s1_pmux {
++		pinctrl-single,pins = <
++			0x013c 0x1 /*I2S1_BCLK_RX*/
++			0x0140 0x1 /*I2S1_WS_RX*/
++			0x0144 0x1 /*I2S1_SD_RX*/
++		>;
++	};
++
++	i2s2_pmux: i2s2_pmux {
++		pinctrl-single,pins = <
++			0x01AC 0x1 /*I2S2_BCLK_RX*/
++			0x01B0 0x1 /*I2S2_WS_RX*/
++			0x01B8 0x1 /*I2S2_SD_RX*/
++		>;
++	};
++
++	i2s3_pmux: i2s3_pmux {
++		pinctrl-single,pins = <
++			0x0198 0x1 /*I2S3_BCLK_RX*/
++			0x019C 0x1 /*I2S3_WS_RX*/
++			0x01A0 0x1 /*I2S3_SD_RX*/
++		>;
++	};
++
++	uart0_pmux: uart0_pmux {
++		pinctrl-single,pins = <
++			0x0158 0x2 /*0: GPIO9_0   1: VOU1120_DAT0  2: UART0_RXD*/
++			0x015c 0x2 /*0: GPIO9_1   1: VOU1120_DAT1  2: UART0_TXD*/
++		>;
++	};
++};
++
++&sys_config_ctrl {
++
++	padctrl-ability,demo = <
++		0x120f093c 0x130
++		0x120f0940 0x130
++		0x120f0944 0x130
++		0x120f09bc 0x130
++		0x120f09c0 0x130
++		0x120f09c8 0x530
++		0x120f09a8 0x130
++		0x120f09ac 0x130
++		0x120f09b0 0x530
++		0x120f0b1c 0x130
++		0x120f0b24 0x130
++		0x120f0b28 0x130
++		0x120f0964 0x40
++		0x120f0968 0x210
++		0x120f096c 0x10
++		0x120f0970 0x210
++		0x120f0974 0x10
++		0x120f0978 0x10
++		0x120f097c 0x10
++		0x120f0980 0x210
++		0x120f0984 0x10
++		0x120f0988 0x410
++		0x120f098c 0x410
++		0x120f0990 0x410
++		0x120f0994 0x10
++		0x120f0998 0x10
++		0x120f099c 0x10
++		0x120f09a0 0x10
++		0x120f09a4 0x10
++		0x120f09b4 0x40
++		0x120f09b8 0x40
++	>;
++
++	padctrl-ability,sck = <
++		0x120f093c 0x130
++		0x120f0940 0x130
++		0x120f0944 0x130
++		0x120f09bc 0x130
++		0x120f09c0 0x130
++		0x120f09c8 0x530
++		0x120f09a8 0x130
++		0x120f09ac 0x130
++		0x120f09b0 0x530
++		0x120f0b1c 0x130
++		0x120f0b24 0x130
++		0x120f0b28 0x130
++		0x120f0964 0x40
++		0x120f0968 0x210
++		0x120f096c 0x10
++		0x120f0970 0x210
++		0x120f0974 0x10
++		0x120f0978 0x10
++		0x120f097c 0x10
++		0x120f0980 0x210
++		0x120f0984 0x10
++		0x120f0988 0x410
++		0x120f098c 0x410
++		0x120f0990 0x410
++		0x120f0994 0x10
++		0x120f0998 0x10
++		0x120f099c 0x10
++		0x120f09a0 0x10
++		0x120f09a4 0x10
++		0x120f09b4 0x40
++		0x120f09b8 0x40
++		0x120f0930 0x130/* I2S0_BCLK_RX------I2S0_BCLK_RX  */
++		0x120f0934 0x130/* I2S0_WS_RX------I2S0_WS_RX  */
++		0x120f0938 0x130/* I2S0_SD_RX------I2S0_SD_RX      */
++		0x120f09c4 0x130/* I2S2_SD_RX------I2S2_SD_RX      */
++		0x120f09cc 0x530/* I2S2_MCLK------I2S2_MCLK        */
++	>;
++
++	padctrl-ability,slave1 = <
++		0x120f093c 0x130
++		0x120f0940 0x130
++		0x120f0944 0x130
++		0x120f09bc 0x130
++		0x120f09c0 0x130
++		0x120f09c8 0x530
++		0x120f0b1c 0x130
++		0x120f0b24 0x130
++		0x120f0b28 0x130
++		0x120f0ac4 0x330
++		0x120f0adc 0x130
++		0x120f0ac0 0x330
++		0x120f0ad8 0x130
++		0x120f0ac8 0x130
++		0x120f0acc 0x130
++		0x120f0ad0 0x130
++		0x120f0ad4 0x130
++		0x120f0abc 0x130
++		0x120f0ab8 0x130
++		0x120f0ab4 0x130
++		0x120f0ab0 0x130
++		0x120f0aac 0x130
++		0x120f0aa8 0x130
++		0x120f0aa4 0x130
++		0x120f0aa0 0x130
++		0x120f0ae0 0x130
++		0x120f09b4 0x40
++		0x120f09b8 0x40
++		0x120f09fc 0xD0
++		0x120f09ec 0x20
++		0x120f09e8 0x20
++		0x120f0a00 0x20
++		0x120f0a04 0x20
++		0x120f0a0c 0x20
++		0x120f0a08 0x220
++		0x120f0a1c 0x20
++		0x120f0a18 0x220
++		0x120f09f8 0x20
++		0x120f09f0 0x20
++		0x120f0a14 0x20
++		0x120f0a10 0x20
++		0x120f0a20 0x220
++		0x120f0a24 0x20
++		0x120f09f4 0x20
++		0x120f09e4 0x20
++		0x120f09fc 0xD0
++		0x12040178 0x40
++	>;
++
++padctrl-ability,slave2 = <
++		0x120f093c 0x130
++		0x120f0940 0x130
++		0x120f0944 0x130
++		0x120f09bc 0x130
++		0x120f09c0 0x130
++		0x120f09c8 0x530
++		0x120f09fc 0xD0
++		0x120f09ec 0x20
++		0x120f09e8 0x20
++		0x120f0a00 0x20
++		0x120f0a04 0x20
++		0x120f0a0c 0x20
++		0x120f0a08 0x220
++		0x120f0a1c 0x20
++		0x120f0a18 0x220
++		0x120f09f8 0x20
++		0x120f09f0 0x20
++		0x120f0a14 0x20
++		0x120f0a10 0x20
++		0x120f0a20 0x220
++		0x120f0a24 0x20
++		0x120f09f4 0x20
++		0x120f09e4 0x20
++		0x12040178 0x40
++	>;
++
++	sysctrl-ddr,pins = <
++		0x1212007c 0x35553301
++		0x12120080 0x33355633
++		0x12120084 0x66266623
++		0x12120088 0x66666666
++		0x12120054 0x80018001
++		0x12040094 0x0000FFFF /*PPC*/
++		0x12040098 0x01ffff1f
++	        0x1204009c 0x8888    /*PT clk default 9999*/
++		0x120400a0 0x88888
++		0x12040168 0x00000f55 /*ADC*/
++	>;
++	
++	dllctrl-ddr,pins = <
++		0x120401e0 0x0      /*DLL rst, disable*/
++		0x120401ec 0x0
++		0x120401f8 0x0
++		0x12040204 0x0
++		0x12040210 0x0
++		0x1204021c 0x0
++		0x12040228 0x0
++		0x12040234 0x0	
++	        0x120401e0 0x4      /*DLL rst, disable*/
++		0x120401ec 0x4
++		0x120401f8 0x4
++		0x12040204 0x4
++		0x12040210 0x4
++		0x1204021c 0x4
++		0x12040228 0x4
++		0x12040234 0x4
++		0x120401e0 0x6       /*DLL 150M and DLL rst, disable*/
++		0x120401ec 0x6
++		0x120401f8 0x6
++		0x12040204 0x6
++		0x12040210 0x6
++		0x1204021c 0x6
++		0x12040228 0x6
++		0x12040234 0x6
++	        0x120401e0 0x7       /*DLL 150M and DLL rst, enable*/
++		0x120401ec 0x7
++		0x120401f8 0x7
++		0x12040204 0x7
++		0x12040210 0x7
++		0x1204021c 0x7
++		0x12040228 0x7
++		0x12040234 0x7
++	        0x120401e0 0x3       /*DLL 150M and DLL unrst, enable*/
++		0x120401ec 0x3
++		0x120401f8 0x3
++		0x12040204 0x3
++		0x12040210 0x3
++		0x1204021c 0x3
++		0x12040228 0x3
++		0x12040234 0x3
++		0x120401e4 0x10      /*dll_slave_en:1,dll_stop:0*/
++		0x120401F0 0x10
++		0x120401fC 0x10
++		0x12040208 0x10
++		0x12040214 0x10
++		0x12040220 0x10
++		0x1204022c 0x10
++		0x12040238 0x10
++	>;
++
++	pinctrl-names = "demo", "demopro", "slave1", "slave2", "sck", "default";
++	pinctrl-0 = <&vo_bt1120_pmux_demo   &vo_vga_pmux &vicap_demob_pmux 	     &i2c0_pmux &i2c1_pmux 	&i2s1_pmux 	&i2s2_pmux 	&i2s3_pmux>;
++	pinctrl-1 = <&vo_bt1120_pmux_demo   &vo_vga_pmux &vicap_demopro_pmux 	 &i2c0_pmux &i2c1_pmux 	&i2s1_pmux 	&i2s2_pmux 	&i2s3_pmux>;
++	pinctrl-2 = <&vo_bt1120_pmux_slave1 &vo_vga_pmux &vicap_demob_pmux 	     &i2c0_pmux &i2c1_pmux 	&i2s1_pmux 	&i2s2_pmux 	&i2s3_pmux &vicap_cascade_pmux>;
++	pinctrl-3 = <&vo_bt1120_pmux_slave2 &vo_vga_pmux &vicap_demob_pmux   	     &i2c0_pmux &i2c1_pmux 	&i2s1_pmux 	&i2s2_pmux 	&i2s3_pmux &uart0_pmux>;
++	pinctrl-4 = <&vo_bt1120_pmux_demo   &vo_vga_pmux &vicap_sck_pmux 	     &i2c0_pmux &i2c1_pmux 	&i2s1_pmux 	&i2s2_pmux 	&i2s3_pmux &i2s0_pmux>;
++	pinctrl-5 = <>;
++};
+diff --git a/arch/arm/boot/dts/hi3531d.dtsi b/arch/arm/boot/dts/hi3531d.dtsi
+new file mode 100644
+index 0000000..aac76f7
+--- /dev/null
++++ b/arch/arm/boot/dts/hi3531d.dtsi
+@@ -0,0 +1,417 @@
++/*
++ * Copyright (c) 2013-2014 Linaro Ltd.
++ * Copyright (c) 2015-2017 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include "skeleton.dtsi"
++#include <dt-bindings/clock/hi3531d-clock.h>
++/ {
++	aliases {
++		fmc = &fmc;
++		serial0 = &uart0;
++		spi0 = &spi_bus0;
++	};
++
++	clock: clock@12040000 {
++		compatible = "hisilicon,hi3531d-clock";
++		#address-cells = <1>;
++		#size-cells = <1>;
++		#clock-cells = <1>;
++		#reset-cells = <2>;
++		reg = <0x12040000 0x1000>;
++	};
++
++	gic: interrupt-controller@10300000 {
++		compatible = "arm,cortex-a9-gic";
++		#interrupt-cells = <3>;
++		#address-cells = <0>;
++		interrupt-controller;
++		/* gic dist base, gic cpu base , no virtual support */
++		reg = <0x10301000 0x1000>, <0x10300100 0x100>;
++	 };
++
++	soc {
++		#address-cells = <1>;
++		#size-cells = <1>;
++		compatible = "simple-bus";
++		interrupt-parent = <&gic>;
++		ranges;
++
++		sysctrl: system-controller@12050000 {
++			compatible = "hisilicon,sysctrl";
++			reg = <0x12050000 0x1000>;
++			reboot-offset = <0x4>;
++			#clock-cells = <1>;
++		};
++
++		pmu {
++			compatible = "arm,cortex-a9-pmu";
++			interrupts = <0 25 4>,
++					<0 54 4>;
++		};
++
++		amba {
++			#address-cells = <1>;
++			#size-cells = <1>;
++			compatible = "arm,amba-bus";
++			ranges;
++
++			L2: l2-cache@10700000 {
++				compatible = "arm,pl310-cache";
++				reg = <0x10700000 0x10000>;
++				interrupts = <0 55 4>;
++				cache-unified;
++				cache-level = <2>;
++			};
++
++			uart0: uart@12080000 {
++				compatible = "arm,pl011", "arm,primecell";
++				reg = <0x12080000 0x1000>;
++				interrupts = <0 6 4>;
++				clocks = <&clock HI3531D_UART0_CLK>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++			};
++
++			uart1: uart@121090000 {
++				compatible = "arm,pl011", "arm,primecell";
++				reg = <0x12090000 0x1000>;
++				interrupts = <0 7 4>;
++				clocks = <&clock HI3531D_UART1_CLK>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++			};
++
++			uart2: uart@120a0000 {
++				compatible = "arm,pl011", "arm,primecell";
++				reg = <0x120a0000 0x1000>;
++				interrupts = <0 8 4>;
++				clocks = <&clock HI3531D_UART2_CLK>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++			};
++
++			uart3: uart@12130000 {
++				compatible = "arm,pl011", "arm,primecell";
++				reg = <0x12130000 0x1000>;
++				interrupts = <0 20 4>;
++				clocks = <&clock HI3531D_UART3_CLK>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++			};
++
++			timer@0x12000000 {
++				compatible = "hisilicon,timer";
++				/* timer0 & timer1 & timer2*/
++				reg = <0x12000000 0x20>, /* clocksource */
++					  <0x12000020 0x20>, /* local timer for each cpu */
++					  <0x12010000 0x20>;
++				interrupts = <0 1 4>, <0 2 4>; /* irq of local timer */
++				clocks = <&sysctrl HI3531D_TIME0_0_CLK>;
++				clock-names = "timer00";
++			};
++		};
++
++		/* dual timer 0 and 1 have used for clocksource and local timer */
++		dual_timer2: dual_timer@12020000 {
++			compatible = "arm,sp804", "arm,primecell";
++			/* timer4 & timer5 */
++			interrupts = <0 3 4>;
++			reg = <0x12020000 0x1000>;
++			clocks = <&sysctrl HI3531D_TIME2_4_CLK>,
++					<&sysctrl HI3531D_TIME2_5_CLK>,
++					<&clock HI3531D_PERIAXI_CLK>;
++			clock-names = "timer4", "timer5", "apb_pclk";
++			status = "disabled";
++		};
++
++		dual_timer3: dual_timer@12030000 {
++			compatible = "arm,sp804", "arm,primecell";
++			/* timer4 & timer5 */
++			interrupts = <0 4 4>;
++			reg = <0x12030000 0x1000>;
++			clocks = <&sysctrl HI3531D_TIME3_6_CLK>,
++					<&sysctrl HI3531D_TIME3_7_CLK>,
++					<&clock HI3531D_PERIAXI_CLK>;
++			clock-names = "timer6", "timer7", "apb_pclk";
++			status = "disabled";
++		};
++
++		spi_bus0: spi@120d0000 {
++				compatible = "arm,pl022", "arm,primecell";
++				arm,primecell-periphid = <0x00800022>;
++				reg = <0x120d0000 0x1000>, <0x12120014 0x4>;
++				interrupts = <0 14 4>;
++				clocks = <&clock HI3531D_SPI0_CLK>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++				#address-cells = <1>;
++				#size-cells = <0>;
++				hisi,spi_cs_sb = <0>;
++				hisi,spi_cs_mask_bit = <0x00000007>;
++		};
++
++		sata_phy: phy@11010000 {
++			compatible = "hisilicon,hisi-sata-nano-phy";
++			reg = <0x11010000 0x10000>;
++			#phy-cells = <0>;
++		};
++
++		ahci: sata@11010000 {
++			compatible = "hisilicon,hisi-ahci";
++			reg = <0x11010000 0x1000>;
++			interrupts = <0 17 4>;
++			phys = <&sata_phy>;
++			phy-names = "sata-phy";
++			#address-cells = <1>;
++			#size-cells = <0>;
++		};
++
++		usb_phy: usbphy {
++			compatible = "hisilicon,hi3531d-usb2-phy";
++			reg = <0x12040000 0x1000>, <0x12120000 0x1000>,
++				<0x12010000 0x1000>;
++		};
++
++		usb3_phy: phy3 {
++			compatible = "hisilicon,hi3531d-usb3-phy";
++			reg = <0x11000000 0x10000>, <0x12040000 0x10000>,
++				<0x12120000 0x10000>;
++			#phy-cells = <0>;
++		};
++
++		ehci@0x10120000 {
++			compatible = "generic-ehci";
++			reg = <0x100c0000 0x10000>;
++			interrupts = <0 19 4>;
++		};
++
++		ohci@0x10110000 {
++			compatible = "generic-ohci";
++			reg = <0x100b0000 0x10000>;
++			interrupts = <0 18 4>;
++		};
++
++		xhci@0x10180000 {
++			compatible = "hisilicon,hi3519-xhci", "generic-xhci";
++			reg = <0x11000000 0x10000>;
++			interrupts = <0 22 4>;
++		};
++
++		mdio: mdio@100a03c0 {
++			compatible = "hisilicon,hisi-gemac-mdio";
++			reg = <0x100a03c0 0x20>;
++			clocks = <&clock HI3531D_ETH_CLK>;
++			resets = <&clock 0x14c 5>;
++			reset-names = "phy_reset";
++			#address-cells = <1>;
++			#size-cells = <0>;
++		};
++
++		higmac: ethernet@100a0000 {
++			compatible = "hisilicon,higmac";
++			reg = <0x100a0000 0x1000>,<0x1204015c 0x4>;
++			interrupts = <0 16 4>;
++
++			clocks = <&clock HI3531D_ETH_CLK>,
++					<&clock HI3531D_ETH_MACIF_CLK>;
++			clock-names = "higmac_clk",
++					"macif_clk";
++
++			resets = <&clock 0x14c 0>,
++					<&clock 0x14c 2>,
++					<&clock 0x14c 5>;
++			reset-names = "port_reset",
++					"macif_reset",
++					"phy_reset";
++
++			mac-address = [00 00 00 00 00 00];
++		};
++
++		fmc: flash-memory-controller@10000000 {
++			compatible = "hisilicon,hisi-fmc";
++			reg = <0x10000000 0x1000>, <0x14000000 0x10000>;
++			reg-names = "control", "memory";
++			clocks = <&clock HI3531D_FMC_CLK>;
++			#address-cells = <1>;
++			#size-cells = <0>;
++
++			hisfc:spi_nor_controller {
++				compatible = "hisilicon,hisi-sfc";
++				assigned-clocks = <&clock HI3531D_FMC_CLK>;
++				assigned-clock-rates = <24000000>;
++				#address-cells = <1>;
++				#size-cells = <0>;
++			};
++
++			hisnfc:spi_nand_controller {
++				compatible = "hisilicon,hisi-spi-nand";
++				assigned-clocks = <&clock HI3531D_FMC_CLK>;
++				assigned-clock-rates = <24000000>;
++				#address-cells = <1>;
++				#size-cells = <0>;
++			};
++		};
++
++		hidmac: hidma-controller@10060000 {
++			compatible = "hisilicon,hisi-dmac";
++			reg = <0x10060000 0x1000>;
++			interrupts = <0 10 4>;
++			clocks = <&clock HI3531D_DMAC_CLK>;
++			clock-names = "dmac_clk";
++			resets = <&clock 0x144 0>;
++			reset-names = "dma-reset";
++			#dma-cells = <2>;
++			status = "disabled";
++		};
++
++		pmux: pinmux@120F0000 {
++			compatible = "pinctrl-single";
++			reg = <0x120F0000 0x3A8>;
++			#address-cells = <1>;
++			#size-cells = <1>;
++			#gpio-range-cells = <3>;
++			ranges;
++
++			pinctrl-single,register-width = <32>;
++			pinctrl-single,function-mask = <7>;
++			/* pin base, nr pins & gpio function */
++			pinctrl-single,gpio-range = <&range 0 54 0
++				&range 55 6 1 &range 61 5 0>;
++
++			range: gpio-range {
++				#pinctrl-single,gpio-range-cells = <3>;
++			};
++		};
++
++		hinfc610: parallel-nand-controller@10010000 {
++			compatible = "hisilicon,hinfc610-nand";
++			reg = <0x10010000 0x1000>, <0x15000000 0x10000>;
++			reg-names = "control", "memory";
++			clocks = <&clock HI3531D_NFC_CLK>;
++			#address-cells = <1>;
++			#size-cells = <0>;
++		};
++	};
++
++	media {
++		#address-cells = <1>;
++		#size-cells = <1>;
++		compatible = "simple-bus";
++		interrupt-parent = <&gic>;
++		ranges;
++
++		osal: osal {
++			compatible = "hisilicon,osal";
++		};
++
++		sys: sys@12040000 {
++			compatible = "hisilicon,hi35xx_sys";
++			reg = <0x12040000 0x10000>, <0x12050000 0x10000>,
++				<0x12110000 0x10000>, <0x12120000 0x10000>;
++			reg-names = "crg", "sys", "ddr", "misc";
++		};
++
++		viu: viu@130C0000 {
++			compatible = "hisilicon,hi35xx_viu";
++			interrupts = <0 28 4>;
++			reg = <0x130C0000 0x40000>;
++		    reg-names = "viu";
++			clocks = <&clock HI3531D_VIU_CLK>;
++			clock-names = "viu";
++		};
++
++		vou: vou@13020000 {
++			compatible = "hisilicon,hi35xx_vou";
++			interrupts = <0 30 4>;
++			reg = <0x13020000 0x10000>;
++		};
++
++		vda: vda@13090000 {
++			compatible = "hisilicon,hi35xx_vda";
++			interrupts = <0 43 4>;
++			reg = <0x13090000 0x10000>;
++		};
++
++		ive: ive@13060000 {
++			compatible = "hisilicon,hi35xx_ive";
++			interrupts = <0 33 4>;
++			reg = <0x13060000 0x10000>;
++		};
++
++		vgs: vgs@13150000 {
++			compatible = "hisilicon,hi35xx_vgs";
++			interrupts = <0 35 4>;
++			reg = <0x13150000 0x10000>;
++		};
++
++		vpss: vpss@13080000 {
++				compatible = "hisilicon,hi35xx_vpss";
++				interrupts = <0 37 4>, <0 46 4>, <0 47 4>;
++				interrupt-names = "vpss0", "vpss1", "vpss2";
++				reg = <0x13080000 0x10000>, <0x13110000 0x10000>, <0x13180000 0x10000>;
++				reg-names = "vpss0", "vpss1", "vpss2";
++		};
++
++		audio: audio@13140000 {
++			compatible = "hisilicon,hi35xx_aiao";
++			interrupts = <0 40 4>;
++			reg = <0x13140000 0x10000>, <0x13120000 0x10000>;
++			reg-names = "aiao", "voie";
++		};
++
++		vdec: vdec@13170000 {
++			compatible = "hisilicon,hi35xx_vdec";
++			interrupts = <0 81 4>, <0 83 4>;
++			interrupt-names = "vdm", "scd";
++			reg = <0x13170000 0xc000>, <0x1317c000 0x4000>;
++			reg-names = "vdm", "scd";
++		};
++
++		tde: tde@13050000 {
++			compatible = "hisilicon,hi35xx_tde";
++			interrupts = <0 32 4>;
++			reg = <0x13050000 0x1000>;
++		};
++
++		jpgd: jpgd@13070000 {
++			compatible = "hisilicon,hi35xx_jpgd";
++			interrupts = <0 34 4>;
++			interrupt-names = "jpgd";
++			reg = <0x13070000 0x10000>;
++			reg-names = "jpgd";
++		};
++
++		vedu: vedu@13040000 {
++			compatible = "hisilicon,hi35xx_vedu";
++			interrupts = <0 31 4>, <0 36 4>;
++			interrupt-names = "vedu0", "vedu1";
++			reg = <0x13040000 0x10000>, <0x13100000 0x10000>;
++			reg-names = "vedu0", "vedu1";
++		};
++
++		jpege: jpege@13130000 {
++			compatible = "hisilicon,hi35xx_jpege";
++			interrupts = <0 39 4>;
++			reg = <0x13130000 0x10000>;
++		};
++
++		sys_config_ctrl: sys_config_ctrl {
++			compatible = "hisilicon,sys_config_ctrl";
++		};
++	};
++};
+diff --git a/arch/arm/boot/dts/hi3536c-demb.dts b/arch/arm/boot/dts/hi3536c-demb.dts
+new file mode 100644
+index 0000000..afdbced
+--- /dev/null
++++ b/arch/arm/boot/dts/hi3536c-demb.dts
+@@ -0,0 +1,199 @@
++/*
++ * Copyright (c) 2013-2014 Linaro Ltd.
++ * Copyright (c) 2015-2017 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++/dts-v1/;
++#include "hi3536c.dtsi"
++
++/ {
++	model = "Hisilicon HI3536C DEMO Board";
++	compatible = "hisilicon,hi3536c";
++
++	cpus {
++		#address-cells = <1>;
++		#size-cells = <0>;
++		enable-method = "hisilicon,hi3536c-smp";
++
++		cpu@0 {
++			compatible = "arm,cortex-a7";
++			device_type = "cpu";
++			clock-frequency = <HI3536C_FIXED_1500M>;
++			reg = <0>;
++		};
++
++		cpu@1 {
++			compatible = "arm,cortex-a7";
++			device_type = "cpu";
++			clock-frequency = <HI3536C_FIXED_1500M>;
++			reg = <1>;
++		};
++	};
++
++	memory {
++		device_type = "memory";
++		reg = <0x80000000 0x20000000>;
++	};
++};
++
++&uart0 {
++	status = "okay";
++};
++
++&rtc {
++	status = "okay";
++};
++
++&spi_bus0{
++	status = "okay";
++	num-cs = <2>;
++
++	spidev@0 {
++		compatible = "spidev";
++		reg = <0>;
++		pl022,interface = <0>;
++		pl022,com-mode = <0>;
++		spi-max-frequency = <37500000>;
++	};
++
++	spidev@1 {
++		compatible = "spidev";
++		reg = <1>;
++		pl022,interface = <0>;
++		pl022,com-mode = <0>;
++		spi-max-frequency = <37500000>;
++	};
++};
++
++&hisfc {
++	hi_sfc {
++		compatible = "jedec,spi-nor";
++		reg = <0>;
++		spi-max-frequency = <160000000>;
++		m25p,fast-read;
++	};
++};
++
++&hisnfc {
++	hinand {
++		compatible = "jedec,spi-nand";
++		reg = <0>;
++		spi-max-frequency = <160000000>;
++	};
++};
++
++&hidmac {
++    status = "okay";
++};
++
++&mdio {
++	ethphy: ethernet-phy@1 {
++		reg = <1>;
++	};
++};
++&mdio1 {
++	ethphy1: ethernet-phy@2 {
++		reg = <2>;
++	};
++};
++
++&higmac {
++	phy-handle = <&ethphy>;
++	phy-mode = "rgmii";
++};
++&higmac1 {
++	phy-handle = <&ethphy1>;
++	phy-mode = "rgmii";
++};
++
++
++&pmux {
++
++	vo_vga_pmux: vo_vga_pmux{
++		pinctrl-single,pins = <
++			0x0174 0x1
++			0x017c 0x1
++			0x0180 0x1
++		>;
++	};
++
++	vo_hdmi_pmux: vo_hdmi_pmux{
++		pinctrl-single,pins = <
++			0x0098 0x1
++			0x009c 0X1
++		>;
++	};
++
++	i2c0_pmux: i2c0_pmux {
++		pinctrl-single,pins = <
++			0x00e0 0x1
++			0x00e4 0x1
++		>;
++	};
++	
++	i2s0_pmux: i2s0_pmux {
++		pinctrl-single,pins = <
++			0x00a0 0x1
++			0x00a4 0x1
++			0x00a8 0x1
++		>;
++	};
++
++	i2s1_pmux: i2s1_pmux {
++		pinctrl-single,pins = <
++			0x00b0 0x1
++			0x00b4 0x1
++		>;
++	};
++
++	i2s2_sck_pmux: i2s2_sck_pmux {
++		pinctrl-single,pins = <
++			0x00b8 0x1
++			0x00bc 0x1
++			0x00c0 0x1
++			0x00ac 0x2
++		>;
++	};
++};
++
++&sys_config_ctrl {
++	padctrl-ability,demo = <
++		0x120f08a0 0x120
++		0x120f08a4 0x130
++		0x120f08a8 0x130
++		0x120f08ac 0x120
++		0x120f08b0 0x130
++		0x120f08b4 0x130
++		0x120f08b8 0x120
++		0x120f08bc 0x130
++		0x120f08c0 0x130
++		0x120f0898 0x40
++		0x120f089c 0x40
++	>;
++
++	sysctrl-ddr,pins = <
++		0x1212007c 0x35533201
++		0x12120080 0x25335526
++		0x12120084 0x66666666
++		0x12120094 0x65
++	>;
++
++	pinctrl-names =  "demo", "sck", "default";
++	pinctrl-0 = <&i2c0_pmux  &i2s1_pmux  &i2s2_sck_pmux &vo_hdmi_pmux &vo_vga_pmux>;
++	pinctrl-1 = <&i2s0_pmux  &i2s1_pmux  &i2s2_sck_pmux &vo_hdmi_pmux &vo_vga_pmux>;
++	pinctrl-2 = <>;
++};
+diff --git a/arch/arm/boot/dts/hi3536c.dtsi b/arch/arm/boot/dts/hi3536c.dtsi
+new file mode 100644
+index 0000000..8605c9d
+--- /dev/null
++++ b/arch/arm/boot/dts/hi3536c.dtsi
+@@ -0,0 +1,408 @@
++/*
++ * Copyright (c) 2013-2014 Linaro Ltd.
++ * Copyright (c) 2015-2017 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include "skeleton.dtsi"
++#include <dt-bindings/clock/hi3536c-clock.h>
++/ {
++	aliases {
++		fmc = &fmc;
++		serial0 = &uart0;
++		spi0 = &spi_bus0;
++	};
++
++	clock: clock@12040000 {
++		compatible = "hisilicon,hi3536c-clock";
++		#address-cells = <1>;
++		#size-cells = <1>;
++		#clock-cells = <1>;
++		#reset-cells = <2>;
++		reg = <0x12040000 0x1000>;
++	};
++
++	gic: interrupt-controller@10300000 {
++		compatible = "arm,cortex-a7-gic";
++		#interrupt-cells = <3>;
++		#address-cells = <0>;
++		interrupt-controller;
++		/* gic dist base, gic cpu base , no virtual support */
++		reg = <0x10301000 0x1000>, <0x10302000 0x100>;
++	 };
++
++	soc {
++		#address-cells = <1>;
++		#size-cells = <1>;
++		compatible = "simple-bus";
++		interrupt-parent = <&gic>;
++		ranges;
++		
++		rtc: rtc@120b0000 {
++			compatible = "hisilicon,hi35xx-rtc";
++			interrupts = <0 5 4>;
++			reg = <0x120b0000 0x10000>;
++			status = "disabled";
++		};
++		sysctrl: system-controller@12050000 {
++			compatible = "hisilicon,sysctrl";
++			reg = <0x12050000 0x1000>;
++			reboot-offset = <0x4>;
++			#clock-cells = <1>;
++		};
++
++		pmu {
++			compatible = "arm,cortex-a7-pmu";
++			interrupts = <0 54 4>,
++					<0 48 4>;
++		};
++
++		amba {
++			#address-cells = <1>;
++			#size-cells = <1>;
++			compatible = "arm,amba-bus";
++			ranges;
++
++			uart0: uart@12080000 {
++				compatible = "arm,pl011", "arm,primecell";
++				reg = <0x12080000 0x1000>;
++				interrupts = <0 6 4>;
++				clocks = <&clock HI3536C_UART0_CLK>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++			};
++
++			uart1: uart@121090000 {
++				compatible = "arm,pl011", "arm,primecell";
++				reg = <0x12090000 0x1000>;
++				interrupts = <0 7 4>;
++				clocks = <&clock HI3536C_UART1_CLK>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++			};
++
++			uart2: uart@120a0000 {
++				compatible = "arm,pl011", "arm,primecell";
++				reg = <0x120a0000 0x1000>;
++				interrupts = <0 8 4>;
++				clocks = <&clock HI3536C_UART2_CLK>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++			};
++
++			timer@0x12000000 {
++				compatible = "hisilicon,timer";
++				/* timer0 & timer1 & timer2*/
++				reg = <0x12000000 0x20>, /* clocksource */
++					  <0x12000020 0x20>, /* local timer for each cpu */
++					  <0x12010000 0x20>;
++				interrupts = <0 1 4>, <0 2 4>; /* irq of local timer */
++				clocks = <&sysctrl HI3536C_TIME0_0_CLK>;
++				clock-names = "timer00";
++			};
++		};
++
++		/* dual timer 0 and 1 have used for clocksource and local timer */
++		dual_timer2: dual_timer@12020000 {
++			compatible = "arm,sp804", "arm,primecell";
++			/* timer4 & timer5 */
++			interrupts = <0 3 4>;
++			reg = <0x12020000 0x1000>;
++			clocks = <&sysctrl HI3536C_TIME2_4_CLK>,
++					<&sysctrl HI3536C_TIME2_5_CLK>,
++					<&clock HI3536C_SYSAXI_CLK>;
++			clock-names = "timer4", "timer5", "apb_pclk";
++			status = "disabled";
++		};
++
++		dual_timer3: dual_timer@12030000 {
++			compatible = "arm,sp804", "arm,primecell";
++			/* timer6 & timer7 */
++			interrupts = <0 4 4>;
++			reg = <0x12030000 0x1000>;
++			clocks = <&sysctrl HI3536C_TIME3_6_CLK>,
++					<&sysctrl HI3536C_TIME3_7_CLK>,
++					<&clock HI3536C_SYSAXI_CLK>;
++			clock-names = "timer6", "timer7", "apb_pclk";
++			status = "disabled";
++		};
++
++		spi_bus0: spi@120d0000 {
++				compatible = "arm,pl022", "arm,primecell";
++				arm,primecell-periphid = <0x00800022>;
++				reg = <0x120d0000 0x1000>, <0x12120014 0x4>;
++				interrupts = <0 14 4>;
++				clocks = <&clock HI3536C_SPI0_CLK>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++				#address-cells = <1>;
++				#size-cells = <0>;
++				hisi,spi_cs_sb = <0>;
++				hisi,spi_cs_mask_bit = <0x00000003>;
++		};
++
++		sata_phy: phy@11010000 {
++			compatible = "hisilicon,hisi-sata-nano-phy";
++			reg = <0x11010000 0x10000>;
++			#phy-cells = <0>;
++		};
++
++		ahci: sata@11010000 {
++			compatible = "hisilicon,hisi-ahci";
++			reg = <0x11010000 0x1000>;
++			interrupts = <0 17 4>;
++			phys = <&sata_phy>;
++			phy-names = "sata-phy";
++			#address-cells = <1>;
++			#size-cells = <0>;
++		};
++
++		usb_phy: usbphy {
++			compatible = "hisilicon,hisi-usb-phy";
++			reg = <0x12120000 0x1000>, <0x12040000 0x1000>;
++		};
++
++		ehci@0x10120000 {
++			compatible = "generic-ehci";
++			reg = <0x10040000 0x10000>;
++			interrupts = <0 19 4>;
++		};
++
++		ohci@0x10110000 {
++			compatible = "generic-ohci";
++			reg = <0x10030000 0x10000>;
++			interrupts = <0 18 4>;
++		};
++
++		mdio: mdio@100a03c0 {
++			compatible = "hisilicon,hisi-gemac-mdio";
++			reg = <0x100a03c0 0x20>;
++			clocks = <&clock HI3536C_ETH_CLK>;
++			resets = <&clock 0x14c 5>;
++			reset-names = "phy_reset";
++			#address-cells = <1>;
++			#size-cells = <0>;
++		};
++		mdio1: mdio@100a13c0 {
++			compatible = "hisilicon,hisi-gemac-mdio";
++			reg = <0x100a13c0 0x20>;
++			clocks = <&clock HI3536C_ETH1_CLK>;
++			resets = <&clock 0x14c 13>;
++			reset-names = "phy_reset";
++			#address-cells = <1>;
++			#size-cells = <0>;
++		};
++
++		higmac: ethernet@100a0000 {
++			compatible = "hisilicon,higmac-v5";
++			reg = <0x100a0000 0x1000>,<0x100a300c 0x4>;
++			interrupts = <0 16 4>, <0 61 4>, <0 62 4>, <0 63 4>;
++
++			clocks = <&clock HI3536C_ETH_CLK>,
++					<&clock HI3536C_ETH_MACIF_CLK>;
++			clock-names = "higmac_clk",
++					"macif_clk";
++
++			resets = <&clock 0x14c 0>,
++					<&clock 0x14c 2>,
++					<&clock 0x14c 5>;
++			reset-names = "port_reset",
++					"macif_reset",
++					"phy_reset";
++
++			mac-address = [00 00 00 00 00 00];
++		};
++		higmac1: ethernet@100a1000 {
++			compatible = "hisilicon,higmac-v5";
++			reg = <0x100a1000 0x1000>,<0x100a3010 0x4>;
++			interrupts = <0 16 4>, <0 61 4>, <0 62 4>, <0 63 4>;
++
++			clocks = <&clock HI3536C_ETH1_CLK>,
++					<&clock HI3536C_ETH_MACIF1_CLK>;
++			clock-names = "higmac_clk",
++					"macif_clk";
++
++			resets = <&clock 0x14c 8>,
++					<&clock 0x14c 10>,
++					<&clock 0x14c 13>;
++			reset-names = "port_reset",
++					"macif_reset",
++					"phy_reset";
++
++			mac-address = [00 00 00 00 00 00];
++		};
++
++
++		fmc: flash-memory-controller@10000000 {
++			compatible = "hisilicon,hisi-fmc";
++			reg = <0x10000000 0x1000>, <0x14000000 0x10000>;
++			reg-names = "control", "memory";
++			clocks = <&clock HI3536C_FMC_CLK>;
++			#address-cells = <1>;
++			#size-cells = <0>;
++
++			hisfc:spi_nor_controller {
++				compatible = "hisilicon,hisi-sfc";
++				assigned-clocks = <&clock HI3536C_FMC_CLK>;
++				assigned-clock-rates = <24000000>;
++				#address-cells = <1>;
++				#size-cells = <0>;
++			};
++
++			hisnfc:spi_nand_controller {
++				compatible = "hisilicon,hisi-spi-nand";
++				assigned-clocks = <&clock HI3536C_FMC_CLK>;
++				assigned-clock-rates = <24000000>;
++				#address-cells = <1>;
++				#size-cells = <0>;
++			};
++		};
++
++		hidmac: hidma-controller@10060000 {
++			compatible = "hisilicon,hisi-dmac";
++			reg = <0x10060000 0x1000>;
++			interrupts = <0 10 4>;
++			clocks = <&clock HI3536C_DMAC_CLK>;
++			clock-names = "dmac_clk";
++			resets = <&clock 0x144 0>;
++			reset-names = "dma-reset";
++			#dma-cells = <2>;
++			status = "disabled";
++		};
++
++		pmux: pinmux@120F0000 {
++			compatible = "pinctrl-single";
++			reg = <0x120F0000 0x3A8>;
++			#address-cells = <1>;
++			#size-cells = <1>;
++			#gpio-range-cells = <3>;
++			ranges;
++
++			pinctrl-single,register-width = <32>;
++			pinctrl-single,function-mask = <7>;
++			/* pin base, nr pins & gpio function */
++			pinctrl-single,gpio-range = <&range 0 54 0
++				&range 55 6 1 &range 61 5 0>;
++
++			range: gpio-range {
++				#pinctrl-single,gpio-range-cells = <3>;
++			};
++		};
++	};
++	
++	
++	media {
++		#address-cells = <1>;
++		#size-cells = <1>;
++		compatible = "simple-bus";
++		interrupt-parent = <&gic>;
++		ranges;
++
++		osal: osal {
++			compatible = "hisilicon,osal";
++		};
++
++		sys: sys@12040000 {
++			compatible = "hisilicon,hi35xx_sys";
++			reg = <0x12040000 0x10000>, <0x12050000 0x10000>,
++				<0x12110000 0x10000>, <0x12120000 0x10000>;
++			reg-names = "crg", "sys", "ddr", "misc";
++		};
++
++		vou: vou@13020000 {
++			compatible = "hisilicon,hi35xx_vou";
++			interrupts = <0 30 4>;
++			reg = <0x13020000 0x10000>;
++		};
++
++		vda: vda@13150000 {
++			compatible = "hisilicon,hi35xx_vda";
++			interrupts = <0 43 4>;
++			reg = <0x13150000 0x10000>;
++		};
++
++		ive: ive@13060000 {
++			compatible = "hisilicon,hi35xx_ive";
++			interrupts = <0 33 4>;
++			reg = <0x13060000 0x10000>;
++		};
++
++		vgs: vgs@13080000 {
++			compatible = "hisilicon,hi35xx_vgs";
++			interrupts = <0 35 4>;
++			reg = <0x13080000 0x10000>;
++		};
++
++		vpss: vpss@13110000 {
++				compatible = "hisilicon,hi35xx_vpss";
++				interrupts = <0 37 4>;
++				interrupt-names = "vpss0";
++				reg = <0x13110000 0x10000>;
++				reg-names = "vpss0";
++		};
++
++		audio: audio@13140000 {
++			compatible = "hisilicon,hi35xx_aiao";
++			interrupts = <0 40 4>;
++			reg = <0x13140000 0x10000>, <0x13120000 0x10000>;
++			reg-names = "aiao", "voie";
++		};
++
++		vdec: vdec@13100000 {
++			compatible = "hisilicon,hi35xx_vdec";
++			interrupts =<0 21 4> , <0 23 4>;
++			interrupt-names ="vdm", "scd";
++			reg = <0x13100000 0xc000>, <0x1310c000 0x4000>;
++			reg-names = "vdm", "scd";
++		};
++
++		tde: tde@13050000 {
++			compatible = "hisilicon,hi35xx_tde";
++			interrupts = <0 32 4>;
++			reg = <0x13050000 0x1000>;
++		};
++
++		jpgd: jpgd@13070000 {
++			compatible = "hisilicon,hi35xx_jpgd";
++			interrupts = <0 34 4>;
++			interrupt-names = "jpgd";
++			reg = <0x13070000 0x10000>;
++			reg-names = "jpgd";
++		};
++
++		vedu: vedu@13040000 {
++			compatible = "hisilicon,hi35xx_vedu";
++			interrupts = <0 31 4>;
++			interrupt-names = "vedu0";
++			reg = <0x13040000 0x10000>;
++			reg-names = "vedu0";
++		};
++
++		jpege: jpege@13130000 {
++			compatible = "hisilicon,hi35xx_jpege";
++			interrupts = <0 39 4>;
++			reg = <0x13130000 0x10000>;
++		};
++
++		sys_config_ctrl: sys_config_ctrl {
++			compatible = "hisilicon,sys_config_ctrl";
++		};
++
++		pin_ctrl_ddr: pin_ctrl_ddr {
++			compatible = "hisilicon,pinctrl-ddrpinctrl-ddr";
++		};
++	};
++};
+diff --git a/arch/arm/boot/dts/hip04.dtsi b/arch/arm/boot/dts/hip04.dtsi
+index 93b6c90..44044f2 100644
+--- a/arch/arm/boot/dts/hip04.dtsi
++++ b/arch/arm/boot/dts/hip04.dtsi
+@@ -190,6 +190,12 @@
+ 		clock-frequency = <168000000>;
+ 	};
+ 
++	clk_375m: clk_375m {
++		#clock-cells = <0>;
++		compatible = "fixed-clock";
++		clock-frequency = <375000000>;
++	};
++
+ 	soc {
+ 		/* It's a 32-bit SoC. */
+ 		#address-cells = <1>;
+@@ -264,4 +270,714 @@
+ 		};
+ 
+ 	};
++
++	etb@0,e3c42000 {
++		compatible = "arm,coresight-etb10", "arm,primecell";
++		reg = <0 0xe3c42000 0 0x1000>;
++
++		clocks = <&clk_375m>;
++		clock-names = "apb_pclk";
++		port {
++			etb0_in_port: endpoint@0 {
++				slave-mode;
++				remote-endpoint = <&replicator0_out_port0>;
++			};
++		};
++	};
++
++	etb@0,e3c82000 {
++		compatible = "arm,coresight-etb10", "arm,primecell";
++		reg = <0 0xe3c82000 0 0x1000>;
++
++		clocks = <&clk_375m>;
++		clock-names = "apb_pclk";
++		port {
++			etb1_in_port: endpoint@0 {
++				slave-mode;
++				remote-endpoint = <&replicator1_out_port0>;
++			};
++		};
++	};
++
++	etb@0,e3cc2000 {
++		compatible = "arm,coresight-etb10", "arm,primecell";
++		reg = <0 0xe3cc2000 0 0x1000>;
++
++		clocks = <&clk_375m>;
++		clock-names = "apb_pclk";
++		port {
++			etb2_in_port: endpoint@0 {
++				slave-mode;
++				remote-endpoint = <&replicator2_out_port0>;
++			};
++		};
++	};
++
++	etb@0,e3d02000 {
++		compatible = "arm,coresight-etb10", "arm,primecell";
++		reg = <0 0xe3d02000 0 0x1000>;
++
++		clocks = <&clk_375m>;
++		clock-names = "apb_pclk";
++		port {
++			etb3_in_port: endpoint@0 {
++				slave-mode;
++				remote-endpoint = <&replicator3_out_port0>;
++			};
++		};
++	};
++
++	tpiu@0,e3c05000 {
++		compatible = "arm,coresight-tpiu", "arm,primecell";
++		reg = <0 0xe3c05000 0 0x1000>;
++
++		clocks = <&clk_375m>;
++		clock-names = "apb_pclk";
++		port {
++			tpiu_in_port: endpoint@0 {
++				slave-mode;
++				remote-endpoint = <&funnel4_out_port0>;
++			};
++		};
++	};
++
++	replicator0 {
++		/* non-configurable replicators don't show up on the
++		 * AMBA bus.  As such no need to add "arm,primecell".
++		 */
++		compatible = "arm,coresight-replicator";
++
++		ports {
++			#address-cells = <1>;
++			#size-cells = <0>;
++
++			/* replicator output ports */
++			port@0 {
++				reg = <0>;
++				replicator0_out_port0: endpoint {
++					remote-endpoint = <&etb0_in_port>;
++				};
++			};
++
++			port@1 {
++				reg = <1>;
++				replicator0_out_port1: endpoint {
++					remote-endpoint = <&funnel4_in_port0>;
++				};
++			};
++
++			/* replicator input port */
++			port@2 {
++				reg = <0>;
++				replicator0_in_port0: endpoint {
++					slave-mode;
++					remote-endpoint = <&funnel0_out_port0>;
++				};
++			};
++		};
++	};
++
++	replicator1 {
++		/* non-configurable replicators don't show up on the
++		 * AMBA bus.  As such no need to add "arm,primecell".
++		 */
++		compatible = "arm,coresight-replicator";
++
++		ports {
++			#address-cells = <1>;
++			#size-cells = <0>;
++
++			/* replicator output ports */
++			port@0 {
++				reg = <0>;
++				replicator1_out_port0: endpoint {
++					remote-endpoint = <&etb1_in_port>;
++				};
++			};
++
++			port@1 {
++				reg = <1>;
++				replicator1_out_port1: endpoint {
++					remote-endpoint = <&funnel4_in_port1>;
++				};
++			};
++
++			/* replicator input port */
++			port@2 {
++				reg = <0>;
++				replicator1_in_port0: endpoint {
++					slave-mode;
++					remote-endpoint = <&funnel1_out_port0>;
++				};
++			};
++		};
++	};
++
++	replicator2 {
++		/* non-configurable replicators don't show up on the
++		 * AMBA bus.  As such no need to add "arm,primecell".
++		 */
++		compatible = "arm,coresight-replicator";
++
++		ports {
++			#address-cells = <1>;
++			#size-cells = <0>;
++
++			/* replicator output ports */
++			port@0 {
++				reg = <0>;
++				replicator2_out_port0: endpoint {
++					remote-endpoint = <&etb2_in_port>;
++				};
++			};
++
++			port@1 {
++				reg = <1>;
++					replicator2_out_port1: endpoint {
++					remote-endpoint = <&funnel4_in_port2>;
++				};
++			};
++
++			/* replicator input port */
++			port@2 {
++				reg = <0>;
++				replicator2_in_port0: endpoint {
++					slave-mode;
++					remote-endpoint = <&funnel2_out_port0>;
++				};
++			};
++		};
++	};
++
++	replicator3 {
++		/* non-configurable replicators don't show up on the
++		 * AMBA bus.  As such no need to add "arm,primecell".
++		 */
++		compatible = "arm,coresight-replicator";
++
++		ports {
++			#address-cells = <1>;
++			#size-cells = <0>;
++
++			/* replicator output ports */
++			port@0 {
++				reg = <0>;
++				replicator3_out_port0: endpoint {
++					remote-endpoint = <&etb3_in_port>;
++				};
++			};
++
++			port@1 {
++				reg = <1>;
++				replicator3_out_port1: endpoint {
++					remote-endpoint = <&funnel4_in_port3>;
++				};
++			};
++
++			/* replicator input port */
++			port@2 {
++				reg = <0>;
++				replicator3_in_port0: endpoint {
++					slave-mode;
++					remote-endpoint = <&funnel3_out_port0>;
++				};
++			};
++		};
++	};
++
++	funnel@0,e3c41000 {
++		compatible = "arm,coresight-funnel", "arm,primecell";
++		reg = <0 0xe3c41000 0 0x1000>;
++
++		clocks = <&clk_375m>;
++		clock-names = "apb_pclk";
++		ports {
++			#address-cells = <1>;
++			#size-cells = <0>;
++
++			/* funnel output port */
++			port@0 {
++				reg = <0>;
++				funnel0_out_port0: endpoint {
++					remote-endpoint =
++						<&replicator0_in_port0>;
++				};
++			};
++
++			/* funnel input ports */
++			port@1 {
++				reg = <0>;
++				funnel0_in_port0: endpoint {
++					slave-mode;
++					remote-endpoint = <&ptm0_out_port>;
++				};
++			};
++
++			port@2 {
++				reg = <1>;
++				funnel0_in_port1: endpoint {
++					slave-mode;
++					remote-endpoint = <&ptm1_out_port>;
++				};
++			};
++
++			port@3 {
++				reg = <2>;
++				funnel0_in_port2: endpoint {
++					slave-mode;
++					remote-endpoint = <&ptm2_out_port>;
++				};
++			};
++
++			port@4 {
++				reg = <3>;
++				funnel0_in_port3: endpoint {
++					slave-mode;
++					remote-endpoint = <&ptm3_out_port>;
++				};
++			};
++		};
++	};
++
++	funnel@0,e3c81000 {
++		compatible = "arm,coresight-funnel", "arm,primecell";
++		reg = <0 0xe3c81000 0 0x1000>;
++
++		clocks = <&clk_375m>;
++		clock-names = "apb_pclk";
++		ports {
++			#address-cells = <1>;
++			#size-cells = <0>;
++
++			/* funnel output port */
++			port@0 {
++				reg = <0>;
++				funnel1_out_port0: endpoint {
++					remote-endpoint =
++						<&replicator1_in_port0>;
++				};
++			};
++
++			/* funnel input ports */
++			port@1 {
++				reg = <0>;
++				funnel1_in_port0: endpoint {
++					slave-mode;
++					remote-endpoint = <&ptm4_out_port>;
++				};
++			};
++
++			port@2 {
++				reg = <1>;
++				funnel1_in_port1: endpoint {
++					slave-mode;
++					remote-endpoint = <&ptm5_out_port>;
++				};
++			};
++
++			port@3 {
++				reg = <2>;
++				funnel1_in_port2: endpoint {
++					slave-mode;
++					remote-endpoint = <&ptm6_out_port>;
++				};
++			};
++
++			port@4 {
++				reg = <3>;
++				funnel1_in_port3: endpoint {
++					slave-mode;
++					remote-endpoint = <&ptm7_out_port>;
++				};
++			};
++		};
++	};
++
++	funnel@0,e3cc1000 {
++		compatible = "arm,coresight-funnel", "arm,primecell";
++		reg = <0 0xe3cc1000 0 0x1000>;
++
++		clocks = <&clk_375m>;
++		clock-names = "apb_pclk";
++		ports {
++			#address-cells = <1>;
++			#size-cells = <0>;
++
++			/* funnel output port */
++			port@0 {
++				reg = <0>;
++				funnel2_out_port0: endpoint {
++					remote-endpoint =
++						<&replicator2_in_port0>;
++				};
++			};
++
++			/* funnel input ports */
++			port@1 {
++				reg = <0>;
++				funnel2_in_port0: endpoint {
++					slave-mode;
++					remote-endpoint = <&ptm8_out_port>;
++				};
++			};
++
++			port@2 {
++				reg = <1>;
++				funnel2_in_port1: endpoint {
++					slave-mode;
++					remote-endpoint = <&ptm9_out_port>;
++				};
++			};
++
++			port@3 {
++				reg = <2>;
++				funnel2_in_port2: endpoint {
++					slave-mode;
++					remote-endpoint = <&ptm10_out_port>;
++				};
++			};
++
++			port@4 {
++				reg = <3>;
++				funnel2_in_port3: endpoint {
++					slave-mode;
++					remote-endpoint = <&ptm11_out_port>;
++				};
++			};
++		};
++	};
++
++	funnel@0,e3d01000 {
++		compatible = "arm,coresight-funnel", "arm,primecell";
++		reg = <0 0xe3d01000 0 0x1000>;
++
++		clocks = <&clk_375m>;
++		clock-names = "apb_pclk";
++		ports {
++			#address-cells = <1>;
++			#size-cells = <0>;
++
++			/* funnel output port */
++			port@0 {
++				reg = <0>;
++				funnel3_out_port0: endpoint {
++					remote-endpoint =
++						<&replicator3_in_port0>;
++				};
++			};
++
++			/* funnel input ports */
++			port@1 {
++				reg = <0>;
++				funnel3_in_port0: endpoint {
++					slave-mode;
++					remote-endpoint = <&ptm12_out_port>;
++				};
++			};
++
++			port@2 {
++				reg = <1>;
++				funnel3_in_port1: endpoint {
++					slave-mode;
++					remote-endpoint = <&ptm13_out_port>;
++				};
++			};
++
++			port@3 {
++				reg = <2>;
++				funnel3_in_port2: endpoint {
++					slave-mode;
++					remote-endpoint = <&ptm14_out_port>;
++				};
++			};
++
++			port@4 {
++				reg = <3>;
++				funnel3_in_port3: endpoint {
++					slave-mode;
++					remote-endpoint = <&ptm15_out_port>;
++				};
++			};
++		};
++	};
++
++	funnel@0,e3c04000 {
++		compatible = "arm,coresight-funnel", "arm,primecell";
++		reg = <0 0xe3c04000 0 0x1000>;
++
++		clocks = <&clk_375m>;
++		clock-names = "apb_pclk";
++		ports {
++			#address-cells = <1>;
++			#size-cells = <0>;
++
++			/* funnel output port */
++			port@0 {
++				reg = <0>;
++				funnel4_out_port0: endpoint {
++					remote-endpoint = <&tpiu_in_port>;
++				};
++			};
++
++			/* funnel input ports */
++			port@1 {
++				reg = <0>;
++				funnel4_in_port0: endpoint {
++					slave-mode;
++					remote-endpoint =
++						<&replicator0_out_port1>;
++				};
++			};
++
++			port@2 {
++				reg = <1>;
++				funnel4_in_port1: endpoint {
++					slave-mode;
++					remote-endpoint =
++						<&replicator1_out_port1>;
++				};
++			};
++
++			port@3 {
++				reg = <2>;
++				funnel4_in_port2: endpoint {
++					slave-mode;
++					remote-endpoint =
++						<&replicator2_out_port1>;
++				};
++			};
++
++			port@4 {
++				reg = <3>;
++				funnel4_in_port3: endpoint {
++					slave-mode;
++					remote-endpoint =
++						<&replicator3_out_port1>;
++				};
++			};
++		};
++	};
++
++	ptm@0,e3c7c000 {
++		compatible = "arm,coresight-etm3x", "arm,primecell";
++		reg = <0 0xe3c7c000 0 0x1000>;
++
++		clocks = <&clk_375m>;
++		clock-names = "apb_pclk";
++		cpu = <&CPU0>;
++		port {
++			ptm0_out_port: endpoint {
++				remote-endpoint = <&funnel0_in_port0>;
++			};
++		};
++	};
++
++	ptm@0,e3c7d000 {
++		compatible = "arm,coresight-etm3x", "arm,primecell";
++		reg = <0 0xe3c7d000 0 0x1000>;
++
++		clocks = <&clk_375m>;
++		clock-names = "apb_pclk";
++		cpu = <&CPU1>;
++		port {
++			ptm1_out_port: endpoint {
++				remote-endpoint = <&funnel0_in_port1>;
++			};
++		};
++	};
++
++	ptm@0,e3c7e000 {
++		compatible = "arm,coresight-etm3x", "arm,primecell";
++		reg = <0 0xe3c7e000 0 0x1000>;
++
++		clocks = <&clk_375m>;
++		clock-names = "apb_pclk";
++		cpu = <&CPU2>;
++		port {
++			ptm2_out_port: endpoint {
++				remote-endpoint = <&funnel0_in_port2>;
++			};
++		};
++	};
++
++	ptm@0,e3c7f000 {
++		compatible = "arm,coresight-etm3x", "arm,primecell";
++		reg = <0 0xe3c7f000 0 0x1000>;
++
++		clocks = <&clk_375m>;
++		clock-names = "apb_pclk";
++		cpu = <&CPU3>;
++		port {
++			ptm3_out_port: endpoint {
++				remote-endpoint = <&funnel0_in_port3>;
++			};
++		};
++	};
++
++	ptm@0,e3cbc000 {
++		compatible = "arm,coresight-etm3x", "arm,primecell";
++		reg = <0 0xe3cbc000 0 0x1000>;
++
++		clocks = <&clk_375m>;
++		clock-names = "apb_pclk";
++		cpu = <&CPU4>;
++		port {
++			ptm4_out_port: endpoint {
++				remote-endpoint = <&funnel1_in_port0>;
++			};
++		};
++	};
++
++	ptm@0,e3cbd000 {
++		compatible = "arm,coresight-etm3x", "arm,primecell";
++		reg = <0 0xe3cbd000 0 0x1000>;
++
++		clocks = <&clk_375m>;
++		clock-names = "apb_pclk";
++		cpu = <&CPU5>;
++		port {
++			ptm5_out_port: endpoint {
++				remote-endpoint = <&funnel1_in_port1>;
++			};
++		};
++	};
++
++	ptm@0,e3cbe000 {
++		compatible = "arm,coresight-etm3x", "arm,primecell";
++		reg = <0 0xe3cbe000 0 0x1000>;
++
++		clocks = <&clk_375m>;
++		clock-names = "apb_pclk";
++		cpu = <&CPU6>;
++		port {
++			ptm6_out_port: endpoint {
++				remote-endpoint = <&funnel1_in_port2>;
++			};
++		};
++	};
++
++	ptm@0,e3cbf000 {
++		compatible = "arm,coresight-etm3x", "arm,primecell";
++		reg = <0 0xe3cbf000 0 0x1000>;
++
++		clocks = <&clk_375m>;
++		clock-names = "apb_pclk";
++		cpu = <&CPU7>;
++		port {
++			ptm7_out_port: endpoint {
++				remote-endpoint = <&funnel1_in_port3>;
++			};
++		};
++	};
++
++	ptm@0,e3cfc000 {
++		compatible = "arm,coresight-etm3x", "arm,primecell";
++		reg = <0 0xe3cfc000 0 0x1000>;
++
++		clocks = <&clk_375m>;
++		clock-names = "apb_pclk";
++		cpu = <&CPU8>;
++		port {
++			ptm8_out_port: endpoint {
++				remote-endpoint = <&funnel2_in_port0>;
++			};
++		};
++	};
++
++	ptm@0,e3cfd000 {
++		compatible = "arm,coresight-etm3x", "arm,primecell";
++		reg = <0 0xe3cfd000 0 0x1000>;
++		clocks = <&clk_375m>;
++		clock-names = "apb_pclk";
++		cpu = <&CPU9>;
++		port {
++			ptm9_out_port: endpoint {
++				remote-endpoint = <&funnel2_in_port1>;
++			};
++		};
++	};
++
++	ptm@0,e3cfe000 {
++		compatible = "arm,coresight-etm3x", "arm,primecell";
++		reg = <0 0xe3cfe000 0 0x1000>;
++
++		clocks = <&clk_375m>;
++		clock-names = "apb_pclk";
++		cpu = <&CPU10>;
++		port {
++			ptm10_out_port: endpoint {
++				remote-endpoint = <&funnel2_in_port2>;
++			};
++		};
++	};
++
++	ptm@0,e3cff000 {
++		compatible = "arm,coresight-etm3x", "arm,primecell";
++		reg = <0 0xe3cff000 0 0x1000>;
++
++		clocks = <&clk_375m>;
++		clock-names = "apb_pclk";
++		cpu = <&CPU11>;
++		port {
++			ptm11_out_port: endpoint {
++				remote-endpoint = <&funnel2_in_port3>;
++			};
++		};
++	};
++
++	ptm@0,e3d3c000 {
++		compatible = "arm,coresight-etm3x", "arm,primecell";
++		reg = <0 0xe3d3c000 0 0x1000>;
++
++		clocks = <&clk_375m>;
++		clock-names = "apb_pclk";
++		cpu = <&CPU12>;
++		port {
++			ptm12_out_port: endpoint {
++				remote-endpoint = <&funnel3_in_port0>;
++			};
++		};
++	};
++
++	ptm@0,e3d3d000 {
++		compatible = "arm,coresight-etm3x", "arm,primecell";
++		reg = <0 0xe3d3d000 0 0x1000>;
++
++		clocks = <&clk_375m>;
++		clock-names = "apb_pclk";
++		cpu = <&CPU13>;
++		port {
++			ptm13_out_port: endpoint {
++				remote-endpoint = <&funnel3_in_port1>;
++			};
++		};
++	};
++
++	ptm@0,e3d3e000 {
++		compatible = "arm,coresight-etm3x", "arm,primecell";
++		reg = <0 0xe3d3e000 0 0x1000>;
++
++		clocks = <&clk_375m>;
++		clock-names = "apb_pclk";
++		cpu = <&CPU14>;
++		port {
++			ptm14_out_port: endpoint {
++				remote-endpoint = <&funnel3_in_port2>;
++			};
++		};
++	};
++
++	ptm@0,e3d3f000 {
++		compatible = "arm,coresight-etm3x", "arm,primecell";
++		reg = <0 0xe3d3f000 0 0x1000>;
++
++		clocks = <&clk_375m>;
++		clock-names = "apb_pclk";
++		cpu = <&CPU15>;
++		port {
++			ptm15_out_port: endpoint {
++				remote-endpoint = <&funnel3_in_port3>;
++			};
++		};
++	};
+ };
+diff --git a/arch/arm/boot/dts/hisi-hi3516av200-demb.dts b/arch/arm/boot/dts/hisi-hi3516av200-demb.dts
+new file mode 100644
+index 0000000..6cf8ba4
+--- /dev/null
++++ b/arch/arm/boot/dts/hisi-hi3516av200-demb.dts
+@@ -0,0 +1,247 @@
++/*
++ * Copyright (c) 2013-2014 Linaro Ltd.
++ * Copyright (c) 2015 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++/dts-v1/;
++#include "hisi-hi3516av200.dtsi"
++
++/ {
++	model = "Hisilicon HI3516AV200 DEMO Board";
++	compatible = "hisilicon,hi3516av200";
++
++	cpus {
++		#address-cells = <1>;
++		#size-cells = <0>;
++		enable-method = "hisilicon,hi3516av200-smp";
++
++		cpu@0 {
++			compatible = "arm,cortex-a7";
++			device_type = "cpu";
++			clock-frequency = <HI3516AV200_FIXED_792M>;
++			reg = <0>;
++			cci-control-port = <&cci_control0>;
++		};
++
++		/*cpu@100 {
++			compatible = "arm,cortex-a17";
++			device_type = "cpu";
++			clock-frequency = <HI3516AV200_FIXED_1000M>;
++			reg = <0x100>;
++			cci-control-port = <&cci_control1>;
++		};*/
++	};
++
++	memory {
++		device_type = "memory";
++		reg = <0x80000000 0x40000000>;
++	};
++};
++
++&uart0 {
++	status = "okay";
++};
++
++&dual_timer0 {
++	status = "okay";
++};
++
++&i2c_bus0 {
++	status = "okay";
++};
++
++&i2c_bus1 {
++	status = "okay";
++};
++
++&i2c_bus2 {
++	status = "okay";
++};
++
++&i2c_bus3 {
++	status = "okay";
++};
++
++&spi_bus0 {
++	status = "okay";
++
++	spidev@0 {
++		compatible = "rohm,dh2228fv";
++		reg = <0>;
++		pl022,interface = <0>;
++		pl022,com-mode = <0>;
++		spi-max-frequency = <24750000>;
++	};
++
++};
++
++&spi_bus1 {
++	status = "okay";
++
++	spidev@0 {
++		compatible = "rohm,dh2228fv";
++		reg = <0>;
++		pl022,interface = <0>;
++		pl022,com-mode = <0>;
++		spi-max-frequency = <24750000>;
++	};
++};
++
++&spi_bus2 {
++	status = "okay";
++
++	spidev@0 {
++		compatible = "rohm,dh2228fv";
++		reg = <0>;
++		pl022,interface = <0>;
++		pl022,com-mode = <0>;
++		spi-max-frequency = <24750000>;
++	};
++
++	spidev@1 {
++		compatible = "rohm,dh2228fv";
++		reg = <1>;
++		pl022,interface = <0>;
++		pl022,com-mode = <0>;
++		spi-max-frequency = <24750000>;
++	};
++};
++
++&spi_bus3 {
++	status = "okay";
++
++	spidev@0 {
++		compatible = "rohm,dh2228fv";
++		reg = <0>;
++		pl022,interface = <0>;
++		pl022,com-mode = <0>;
++		spi-max-frequency = <24750000>;
++	};
++};
++
++&hisfc {
++	hi_sfc {
++		compatible = "jedec,spi-nor";
++		reg = <0>;
++		spi-max-frequency = <160000000>;
++		m25p,fast-read;
++	};
++
++};
++
++&hisnfc {
++	hinand {
++		compatible = "jedec,spi-nand";
++		reg = <0>;
++		spi-max-frequency = <160000000>;
++	};
++};
++
++&hinfc {
++	hinand {
++		compatible = "jedec,nand";
++		reg = <0>;
++		nand-max-frequency = <200000000>;
++	};
++};
++
++&mmc0 {
++	status = "okay";
++};
++
++&mmc1 {
++	status = "okay";
++};
++
++&mmc2 {
++	status = "okay";
++};
++
++&mdio {
++	ethphy: ethernet-phy@1 {
++		reg = <1>;
++	};
++};
++
++&higmac {
++	phy-handle = <&ethphy>;
++	phy-mode = "rgmii";
++};
++
++&gpio_chip0 {
++	status = "okay";
++};
++
++&gpio_chip1 {
++	status = "okay";
++};
++
++&gpio_chip2 {
++	status = "okay";
++};
++
++&gpio_chip3 {
++	status = "okay";
++};
++
++&gpio_chip4 {
++	status = "okay";
++};
++
++&gpio_chip5 {
++	status = "okay";
++};
++
++&gpio_chip6 {
++	status = "okay";
++};
++
++&gpio_chip7 {
++	status = "okay";
++};
++
++&gpio_chip8 {
++	status = "okay";
++};
++
++&gpio_chip9 {
++	status = "okay";
++};
++
++&gpio_chip10 {
++	status = "okay";
++};
++
++&gpio_chip11 {
++	status = "okay";
++};
++
++&gpio_chip12 {
++	status = "okay";
++};
++
++&gpio_chip13 {
++	status = "okay";
++};
++
++&gpio_chip14 {
++	status = "okay";
++};
++
++&gpio_chip16 {
++	status = "okay";
++};
+diff --git a/arch/arm/boot/dts/hisi-hi3516av200-hmp-demb.dts b/arch/arm/boot/dts/hisi-hi3516av200-hmp-demb.dts
+new file mode 100644
+index 0000000..3c6f10c
+--- /dev/null
++++ b/arch/arm/boot/dts/hisi-hi3516av200-hmp-demb.dts
+@@ -0,0 +1,310 @@
++/*
++ * Copyright (c) 2013-2014 Linaro Ltd.
++ * Copyright (c) 2015 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++/dts-v1/;
++#include "hisi-hi3516av200.dtsi"
++
++/ {
++	model = "Hisilicon HI3516AV200 DEMO Board";
++	compatible = "hisilicon,hi3516av200";
++
++	chosen {
++		bootargs = "console=ttyAMA0,115200 early_printk
++root=/dev/mtdblock2 rootfstype=jffs2 mtdparts=hi_sfc:1M(boot),
++4M(kernel),11M(rootfs)";
++	};
++
++	cpus {
++		#address-cells = <1>;
++		#size-cells = <0>;
++		enable-method = "hisilicon,hi3516av200-smp";
++
++		cpu@0 {
++			compatible = "arm,cortex-a7";
++			device_type = "cpu";
++			clock-frequency = <HI3516AV200_FIXED_792M>;
++			reg = <0>;
++			cci-control-port = <&cci_control0>;
++		};
++
++		cpu@100 {
++			compatible = "arm,cortex-a17";
++			device_type = "cpu";
++			reg = <0x100>;
++			cci-control-port = <&cci_control1>;
++			operating-points = <
++				/* KHz    uV */
++				1250000 1060000
++				1150000 1060000
++				1000000 1000000
++				 930000 1000000
++				 792000 940000
++				 594000 940000
++				>;
++			clocks = <&clock HI3516AV200_A17_MUX>,
++				<&clock HI3516AV200_FIXED_400M>,
++				<&clock HI3516AV200_FIXED_500M>,
++				<&clock HI3516AV200_FIXED_594M>,
++				<&clock HI3516AV200_FIXED_792M>,
++				<&clock HI3516AV200_APLL_CLK>;
++			clock-names = "a17_mux","400m", "500m",
++					"594m", "792m", "apll";
++			vcc-supply = <&a17_regulator>;
++		};
++	};
++
++	avs {
++	    compatible = "hi3516av200,avs";
++	    avs-num = <2>;
++	    avs-name-array = "cpu-avs","media-avs";
++	    cpu_avs: cpu_avs{
++		avs-name = "cpu-avs";
++			opp-num = <6>;
++			opp-freq = <1250000 1150000 1000000 930000 792000 594000 >;
++			opp-volt-min = <870000 870000 800000 800000 740000 740000>;
++			opp-hpm = <310 310 280 280 250 250>;
++			opp-div = <24 22 19 18 15 11>;
++			opp-volt-max = <1060000>;
++			};
++
++	    media_avs: media_avs{
++			avs-name = "media-avs";
++			opp-num = <4>;
++			opp-prof-num = <2>;
++			opp-temp-num = <2>;
++			opp-temp = <50 200>;
++			opp-freq = <1 2 3 4>;
++			opp-volt-min = <
++				/* profile2    profile3*/
++                                  770000       770000
++                                  770000       770000
++				      >;
++			opp-hpm = <
++				/* profile2    profile3*/
++				     210       215 
++				     190       215
++				  >;
++			opp-div = <3 3 3 3>;
++			opp-volt-max = <
++				/* profile2    profile3*/
++                                  977000       977000
++                                  977000       977000
++				>;
++			};
++	};
++
++	memory {
++		device_type = "memory";
++		reg = <0x80000000 0x40000000>;
++	};
++};
++
++&uart0 {
++	status = "okay";
++};
++
++&dual_timer0 {
++	status = "okay";
++};
++
++&i2c_bus0 {
++	status = "okay";
++};
++
++&i2c_bus1 {
++	status = "okay";
++};
++
++&i2c_bus2 {
++	status = "okay";
++};
++
++&i2c_bus3 {
++	status = "okay";
++};
++
++&spi_bus0 {
++	status = "okay";
++
++	spidev@0 {
++		compatible = "rohm,dh2228fv";
++		reg = <0>;
++		pl022,interface = <0>;
++		pl022,com-mode = <0>;
++		spi-max-frequency = <24000000>;
++	};
++
++};
++
++&spi_bus1 {
++	status = "okay";
++
++	spidev@0 {
++		compatible = "rohm,dh2228fv";
++		reg = <0>;
++		pl022,interface = <0>;
++		pl022,com-mode = <0>;
++		spi-max-frequency = <24000000>;
++	};
++
++	spidev@1 {
++		compatible = "rohm,dh2228fv";
++		reg = <1>;
++		pl022,interface = <0>;
++		pl022,com-mode = <0>;
++		spi-max-frequency = <24000000>;
++	};
++};
++
++&spi_bus2 {
++	status = "okay";
++
++	spidev@0 {
++		compatible = "rohm,dh2228fv";
++		reg = <0>;
++		pl022,interface = <0>;
++		pl022,com-mode = <0>;
++		spi-max-frequency = <24000000>;
++	};
++};
++
++&spi_bus3 {
++	status = "okay";
++
++	spidev@0 {
++		compatible = "rohm,dh2228fv";
++		reg = <0>;
++		pl022,interface = <0>;
++		pl022,com-mode = <0>;
++		spi-max-frequency = <24000000>;
++	};
++};
++
++&hisfc {
++	hi_sfc {
++		compatible = "jedec,spi-nor";
++		reg = <0>;
++		spi-max-frequency = <160000000>;
++		m25p,fast-read;
++	};
++};
++
++&hisnfc {
++	hinand {
++		compatible = "jedec,spi-nand";
++		reg = <0>;
++		spi-max-frequency = <160000000>;
++	};
++};
++
++&hinfc {
++	hinand {
++		compatible = "jedec,nand";
++		reg = <0>;
++		nand-max-frequency = <200000000>;
++	};
++};
++
++&mmc0 {
++	status = "okay";
++};
++
++&mmc1 {
++	status = "okay";
++};
++
++&mmc2 {
++	status = "okay";
++};
++
++&mdio {
++	ethphy: ethernet-phy@1 {
++		reg = <1>;
++	};
++};
++
++&higmac {
++	compatible = "hisilicon,higmac-v3", "hisilicon,higmac";
++	phy-handle = <&ethphy>;
++	phy-mode = "rgmii";
++};
++
++&gpio_chip0 {
++	status = "okay";
++};
++
++&gpio_chip1 {
++	status = "okay";
++};
++
++&gpio_chip2 {
++	status = "okay";
++};
++
++&gpio_chip3 {
++	status = "okay";
++};
++
++&gpio_chip4 {
++	status = "okay";
++};
++
++&gpio_chip5 {
++	status = "okay";
++};
++
++&gpio_chip6 {
++	status = "okay";
++};
++
++&gpio_chip7 {
++	status = "okay";
++};
++
++&gpio_chip8 {
++	status = "okay";
++};
++
++&gpio_chip9 {
++	status = "okay";
++};
++
++&gpio_chip10 {
++	status = "okay";
++};
++
++&gpio_chip11 {
++	status = "okay";
++};
++
++&gpio_chip12 {
++	status = "okay";
++};
++
++&gpio_chip13 {
++	status = "okay";
++};
++
++&gpio_chip14 {
++	status = "okay";
++};
++
++&gpio_chip16 {
++	status = "okay";
++};
+diff --git a/arch/arm/boot/dts/hisi-hi3516av200.dtsi b/arch/arm/boot/dts/hisi-hi3516av200.dtsi
+new file mode 100644
+index 0000000..f3f087a
+--- /dev/null
++++ b/arch/arm/boot/dts/hisi-hi3516av200.dtsi
+@@ -0,0 +1,777 @@
++/*
++ * Copyright (c) 2013-2014 Linaro Ltd.
++ * Copyright (c) 2015 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include "skeleton.dtsi"
++#include <dt-bindings/clock/hi3516av200-clock.h>
++/ {
++	aliases {
++		serial0 = &uart0;
++		i2c0 = &i2c_bus0;
++		i2c1 = &i2c_bus1;
++		i2c2 = &i2c_bus2;
++		i2c3 = &i2c_bus3;
++		spi0 = &spi_bus0;
++		spi1 = &spi_bus1;
++		spi2 = &spi_bus2;
++		spi3 = &spi_bus3;
++		gpio0 = &gpio_chip0;
++		gpio1 = &gpio_chip1;
++		gpio2 = &gpio_chip2;
++		gpio3 = &gpio_chip3;
++		gpio4 = &gpio_chip4;
++		gpio5 = &gpio_chip5;
++		gpio6 = &gpio_chip6;
++		gpio7 = &gpio_chip7;
++		gpio8 = &gpio_chip8;
++		gpio9 = &gpio_chip9;
++		gpio10 = &gpio_chip10;
++		gpio11 = &gpio_chip11;
++		gpio12 = &gpio_chip12;
++		gpio13 = &gpio_chip13;
++		gpio14 = &gpio_chip14;
++		gpio16 = &gpio_chip16;
++	};
++
++	gic: interrupt-controller@10300000 {
++		compatible = "arm,cortex-a7-gic";
++		#interrupt-cells = <3>;
++		#address-cells = <0>;
++		interrupt-controller;
++		/* gic dist base, gic cpu base , no virtual support */
++		reg = <0x10301000 0x1000>, <0x10302000 0x1000>;
++	};
++
++	clock: clock0 {
++		compatible = "hisilicon,hi3516av200-clock";
++		#address-cells = <1>;
++		#size-cells = <1>;
++		#clock-cells = <1>;
++		#reset-cells = <2>;
++		reg = <0x12010000 0x10000>;
++	};
++
++	syscounter {
++		compatible = "arm,armv7-timer";
++		interrupt-parent = <&gic>;
++		interrupts = <1 13 0xf08>,
++			<1 14 0xf08>;
++		clock-frequency = <24000000>;
++	};
++
++	soc {
++		#address-cells = <1>;
++		#size-cells = <1>;
++		compatible = "simple-bus";
++		interrupt-parent = <&gic>;
++		ranges;
++
++		amba {
++			#address-cells = <1>;
++			#size-cells = <1>;
++			compatible = "arm,amba-bus";
++			ranges;
++
++			uart0: uart@12100000 {
++				compatible = "arm,pl011", "arm,primecell";
++				reg = <0x12100000 0x1000>;
++				interrupts = <0 4 4>;
++				clocks = <&clock HI3516AV200_UART0_CLK>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++			};
++
++			uart1: uart@12101000 {
++				compatible = "arm,pl011", "arm,primecell";
++				reg = <0x12101000 0x1000>;
++				interrupts = <0 5 4>;
++				clocks = <&clock HI3516AV200_UART1_CLK>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++			};
++
++			uart2: uart@12102000 {
++				compatible = "arm,pl011", "arm,primecell";
++				reg = <0x12102000 0x1000>;
++				interrupts = <0 6 4>;
++				clocks = <&clock HI3516AV200_UART2_CLK>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++			};
++
++			uart3: uart@12103000 {
++				compatible = "arm,pl011", "arm,primecell";
++				reg = <0x12103000 0x1000>;
++				interrupts = <0 7 4>;
++				clocks = <&clock HI3516AV200_UART3_CLK>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++			};
++
++			uart4: uart@12104000 {
++				compatible = "arm,pl011", "arm,primecell";
++				reg = <0x12104000 0x1000>;
++				interrupts = <0 8 4>;
++				clocks = <&clock HI3516AV200_UART4_CLK>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++			};
++
++			sys: sys@12010000 {
++				compatible = "hisilicon,hi35xx_sys";
++				reg = <0x12020000 0x10000>, <0x12060000 0x10000>, <0X12030000 0x10000>;
++				reg-names = "sys", "ddr", "misc";
++			};
++
++			mipi: mipi@11300000 {
++				compatible = "hisilicon,hi35xx_mipi";
++				interrupts = <0 28 4>, <0 29 4>;
++				interrupt-names = "mipi0", "mipi1";
++				reg = <0x11300000 0x10000>;
++			};
++
++			isp: isp@11380000 {
++				compatible = "hisilicon,hi35xx_isp";
++				interrupts = <0 30 4>, <0 31 4>;
++				interrupt-names = "isp0", "isp1";
++			};
++
++			viu: viu@11380000 {
++				compatible = "hisilicon,hi35xx_viu";
++				interrupts = <0 30 4>, <0 31 4>;
++				interrupt-names = "viu0", "viu1";
++				reg = <0x11380000 0x70000>, <0x11480000 0x70000>;
++				reg-names = "viu0", "viu1";
++			};
++
++			vou: vou@11000000 {
++				compatible = "hisilicon,hi35xx_vou";
++				interrupts = <0 27 4>;
++				reg = <0x11000000 0x20000>;
++			};
++
++			tde: tde@11100000 {
++				compatible = "hisilicon,hi35xx_tde";
++				interrupts = <0 34 4>;
++				reg = <0x11100000 0x10000>;
++			};
++
++			fisheye: fisheye@11110000 {
++				compatible = "hisilicon,hi35xx_fisheye";
++				interrupts = <0 48 4>;
++				reg = <0x11110000 0x10000>;
++			};
++
++			vgs: vgs@11120000 {
++				compatible = "hisilicon,hi35xx_vgs";
++				interrupts = <0 35 4>;
++				reg = <0x11120000 0x10000>;
++			};
++
++			vpss: vpss@11180000 {
++				compatible = "hisilicon,hi35xx_vpss";
++				interrupts = <0 32 4>;
++				reg = <0x11180000 0x10000>;
++			};
++
++			vedu: vedu@11280000 {
++					compatible = "hisilicon,hi35xx_vedu";
++					interrupts = <0 37 4>;
++					reg = <0x11280000 0x10000>;
++			};
++
++			jpege: jpege@11200000 {
++					compatible = "hisilicon,hi35xx_jpege";
++					interrupts = <0 38 4>;
++					reg = <0x11200000 0x10000>;
++			};
++
++			aiao: aiao@11080000 {
++				compatible = "hisilicon,hi35xx_aiao";
++				interrupts = <0 36 4>;
++				reg = <0x11080000 0x3000>;
++			};
++
++			ive: ive@11040000 {
++				compatible = "hisilicon,hi35xx_ive";
++				interrupts = <0 39 4>;
++				reg = <0x11040000 0x10000>;
++			};
++
++			fd: fd@11060000 {
++				compatible = "hisilicon,hi35xx_fd";
++				interrupts = <0 40 4>;
++				reg = <0x11060000 0x10000>;
++			};
++
++			pwm: pwm@12130000 {
++				compatible = "hisilicon,pwm";
++				reg = <0x12130000 0x10000>;
++			};
++
++			piris: piris@12145000 {
++				compatible = "hisilicon,piris";
++				reg = <0x12145000 0x1000>;
++			};
++
++			wtdg: wtdg@12080000 {
++				compatible = "hisilicon,hi_wdg";
++				reg = <0x12080000 0x10000>;
++				reg-names = "wtdg";
++			};
++
++			rtc: rtc@12090000 {
++				compatible = "hisilicon,hi_rtc";
++				interrupts = <0 1 4>;
++				reg = <0x12090000 0x10000>;
++			};
++
++			ir: ir@120f0000{
++				compatible = "hisilicon,hi_ir";
++				interrupts = <0 15 4>;
++				reg = <0x120f0000 0x10000>;
++			};
++			
++			pm {
++				compatible = "hisilicon,hibvt-pm";
++				reg = <0x12020000 0x1000>, <0x12000000 0x1000>;
++			};
++
++			pm_hibernate {
++				compatible = "hisilicon,hibvt-pm-hibernate";
++				reg = <0x12020000 0x1000>;
++			};
++
++			dual_timer0: dual_timer@12000000 {
++				compatible = "arm,sp804";
++				/* timer0 & timer1 */
++				interrupts = <0 64 4>, <0 65 4>;
++				reg = <0x12000000 0x1000>;
++				clocks = <&clock HI3516AV200_FIXED_3M>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++			};
++
++			dual_timer1: dual_timer@12001000 {
++				compatible = "arm,sp804";
++				/* timer2 & timer3 */
++				interrupts = <0 66 4>, <0 67 4>;
++				reg = <0x12001000 0x1000>;
++				clocks = <&clock HI3516AV200_FIXED_3M>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++			};
++
++			dual_timer2: dual_timer@12002000 {
++				compatible = "arm,sp804";
++				/* timer4 & timer5 */
++				interrupts = <0 68 4>, <0 69 4>;
++				reg = <0x12002000 0x1000>;
++				clocks = <&clock HI3516AV200_FIXED_3M>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++			};
++
++			i2c_bus0: i2c@12110000 {
++				compatible = "hisilicon,hisi-i2c-v110";
++				reg = <0x12110000 0x100>;
++				clocks = <&clock HI3516AV200_I2C_MUX>;
++				clock-frequency = <100000>;
++				status = "disabled";
++			};
++
++			i2c_bus1: i2c@12111000 {
++				compatible = "hisilicon,hisi-i2c-v110";
++				reg = <0x12111000 0x100>;
++				clocks = <&clock HI3516AV200_I2C_MUX>;
++				clock-frequency = <100000>;
++				status = "disabled";
++			};
++
++			i2c_bus2: i2c@12112000 {
++				compatible = "hisilicon,hisi-i2c-v110";
++				reg = <0x12112000 0x100>;
++				clocks = <&clock HI3516AV200_I2C_MUX>;
++				clock-frequency = <100000>;
++				status = "disabled";
++			};
++
++			i2c_bus3: i2c@12113000 {
++				compatible = "hisilicon,hisi-i2c-v110";
++				reg = <0x12113000 0x100>;
++				clocks = <&clock HI3516AV200_I2C_MUX>;
++				clock-frequency = <100000>;
++				status = "disabled";
++			};
++
++			spi_bus0: spi@12120000 {
++				compatible = "arm,pl022", "arm,primecell";
++				arm,primecell-periphid = <0x00800022>;
++				reg = <0x12120000 0x1000>;
++				interrupts = <0 9 4>;
++				clocks = <&clock HI3516AV200_SPI0_CLK>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++				num-cs = <1>;
++				#address-cells = <1>;
++				#size-cells = <0>;
++			};
++
++			spi_bus1: spi@12121000 {
++				compatible = "arm,pl022", "arm,primecell";
++				arm,primecell-periphid = <0x00800022>;
++				reg = <0x12121000 0x1000>;
++				interrupts = <0 10 4>;
++				clocks = <&clock HI3516AV200_SPI1_CLK>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++				num-cs = <1>;
++				#address-cells = <1>;
++				#size-cells = <0>;
++			};
++
++			spi_bus2: spi@12122000 {
++				compatible = "arm,pl022", "arm,primecell";
++				arm,primecell-periphid = <0x00800022>;
++				reg = <0x12122000 0x1000>, <0x12030004 0x4>;
++				interrupts = <0 11 4>;
++				clocks = <&clock HI3516AV200_SPI2_CLK>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++				num-cs = <2>;
++				#address-cells = <1>;
++				#size-cells = <0>;
++				hisi,spi_cs_sb = <26>;
++				hisi,spi_cs_mask_bit = <0x0c000000>;
++			};
++
++			spi_bus3: spi@12123000 {
++				compatible = "arm,pl022", "arm,primecell";
++				arm,primecell-periphid = <0x00800022>;
++				reg = <0x12123000 0x1000>;
++				interrupts = <0 12 4>;
++				clocks = <&clock HI3516AV200_SPI3_CLK>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++				num-cs = <1>;
++				#address-cells = <1>;
++				#size-cells = <0>;
++			};
++
++			gpio_chip0: gpio_chip@12140000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x12140000 0x1000>;
++				interrupts = <0 43 4>;
++				clocks = <&clock HI3516AV200_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip1: gpio_chip@12141000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x12141000 0x1000>;
++				interrupts = <0 43 4>;
++				clocks = <&clock HI3516AV200_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip2: gpio_chip@12142000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x12142000 0x1000>;
++				interrupts = <0 43 4>;
++				clocks = <&clock HI3516AV200_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip3: gpio_chip@12143000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x12143000 0x1000>;
++				interrupts = <0 43 4>;
++				clocks = <&clock HI3516AV200_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip4: gpio_chip@12144000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x12144000 0x1000>;
++				interrupts = <0 43 4>;
++				clocks = <&clock HI3516AV200_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip5: gpio_chip@12145000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x12145000 0x1000>;
++				interrupts = <0 43 4>;
++				clocks = <&clock HI3516AV200_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip6: gpio_chip@12146000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x12146000 0x1000>;
++				interrupts = <0 43 4>;
++				clocks = <&clock HI3516AV200_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip7: gpio_chip@12147000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x12147000 0x1000>;
++				interrupts = <0 43 4>;
++				clocks = <&clock HI3516AV200_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip8: gpio_chip@12148000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x12148000 0x1000>;
++				interrupts = <0 44 4>;
++				clocks = <&clock HI3516AV200_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip9: gpio_chip@12149000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x12149000 0x1000>;
++				interrupts = <0 44 4>;
++				clocks = <&clock HI3516AV200_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip10: gpio_chip@1214a000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x1214a000 0x1000>;
++				interrupts = <0 44 4>;
++				clocks = <&clock HI3516AV200_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip11: gpio_chip@1214b000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x1214b000 0x1000>;
++				interrupts = <0 44 4>;
++				clocks = <&clock HI3516AV200_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip12: gpio_chip@1214c000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x1214c000 0x1000>;
++				interrupts = <0 44 4>;
++				clocks = <&clock HI3516AV200_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip13: gpio_chip@1214d000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x1214d000 0x1000>;
++				interrupts = <0 44 4>;
++				clocks = <&clock HI3516AV200_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip14: gpio_chip@1214e000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x1214e000 0x1000>;
++				interrupts = <0 44 4>;
++				clocks = <&clock HI3516AV200_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip16: gpio_chip@12150000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x12150000 0x1000>;
++				interrupts = <0 44 4>;
++				clocks = <&clock HI3516AV200_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++		};
++
++		pmc@0x120a0000 {
++			compatible = "hisilicon,pmc";
++			reg = <0x120a0000 0x1000>;
++		};
++
++		sysctrl: system-controller@00000000 {
++			compatible = "hisilicon,sysctrl";
++			reg = <0x12020000 0x1000>;
++			reboot-offset = <0x4>;
++		};
++
++		usb_phy: phy {
++			compatible = "hisilicon,hisi-usb-phy";
++			reg = <0x12030000 0x10000>, <0x12010000 0x10000>;
++			#phy-cells = <0>;
++		};
++
++		usb3_phy: phy3 {
++			compatible = "hisilicon,hisi-usb3-phy";
++			reg = <0x10180000 0x10000>, <0x12010000 0x10000>,
++				<0x12030000 0x10000>;
++			#phy-cells = <0>;
++		};
++		ehci@0x10120000 {
++			 compatible = "generic-ehci";
++			 reg = <0x10120000 0x10000>;
++			 interrupts = <0 19 4>;
++
++			clocks = <&clock HI3516AV200_USB2_CTRL_UTMI0_REQ>,
++					<&clock HI3516AV200_USB2_HRST_REQ>;
++			clock-names = "usb2_cttl_utmi0_req",  "usb2_hrst_req";
++		 };
++
++		ohci@0x10110000 {
++			compatible = "generic-ohci";
++			reg = <0x10110000 0x10000>;
++			interrupts = <0 20 4>;
++
++			clocks = <&clock HI3516AV200_USB2_CTRL_UTMI0_REQ>,
++					<&clock HI3516AV200_USB2_HRST_REQ>;
++			clock-names = "usb2_cttl_utmi0_req", "usb2_hrst_req";
++		 };
++
++		 xhci@0x10180000 {
++			  compatible = "hisilicon,hi3516av200-xhci", "generic-xhci";
++			  reg = <0x10180000 0x10000>;
++			  interrupts = <0 22 4>;
++
++			  clocks = <&clock HI3516AV200_USB3_CLK>;
++			  clock-names = "clk";
++		  };
++
++		 hiudc@0x10130000 {
++			 compatible = "hiudc";
++			 reg = <0x10130000 0x40000>;
++			 interrupts = <0 21 4>;
++
++			 clocks = <&clock HI3516AV200_USB2_HRST_REQ>;
++			 clock-names = "clk";
++		 };
++
++		 hiudc3@0x10180000 {
++			 compatible = "dwc_usb3";
++			 reg = <0x10180000 0x40000>;
++			 interrupts = <0 22 4>;
++
++			 clocks = <&clock HI3516AV200_USB3_CLK>;
++			 clock-names = "clk";
++		 };
++
++		cci: cci@1ff00000 {
++			compatible = "arm,cci-400";
++			#address-cells = <1>;
++			#size-cells = <1>;
++			reg = <0x1ff00000 0x1000>;
++			ranges = <0x0 0x1ff00000 0x6000>;
++
++			cci_control0: slave-if@4000 {
++				compatible = "arm,cci-400-ctrl-if";
++				interface-type = "ace";
++				reg = <0x2000 0x1000>;
++			};
++
++			cci_control1: slave-if@5000 {
++				compatible = "arm,cci-400-ctrl-if";
++				interface-type = "ace";
++				reg = <0x3000 0x1000>;
++			};
++
++		};
++
++		regulators@120a0000 {
++			compatible = "hi35xx,regulators";
++			reg = <0x120a0000 0x1000>;
++			regulator-num = <2>;
++			regulator-name-array = "regulator-a17","regulator-media";
++
++			a17_regulator: a17_regulator{
++				regulator-name = "regulator-a17";
++				regulator-min-microvolt = <651216>;
++				regulator-max-microvolt = <1083359>;
++				regulator-always-on;
++				reg_offset = <0x4>;
++			};
++
++			media_regulator: media_regulator{
++				regulator-name = "regulator-media";
++				regulator-min-microvolt = <649609>;
++				regulator-max-microvolt = <977031>;
++				regulator-always-on;
++				reg_offset = <0xC>;
++			};
++		};
++
++		pmu {
++			compatible = "arm,cortex-a7-pmu", "arm,cortex-a17-pmu";
++			interrupts = <0 45 4>,
++					<0 46 4>;
++		};
++
++		mdio: mdio@100503c0 {
++			compatible = "hisilicon,hisi-gemac-mdio";
++			reg = <0x100503c0 0x20>;
++			clocks = <&clock HI3516AV200_ETH_CLK>;
++			#address-cells = <1>;
++			#size-cells = <0>;
++		};
++
++		higmac: ethernet@10050000 {
++			compatible = "hisilicon,higmac";
++			reg = <0x10050000 0x1000>,<0x120100ec 0x4>;
++			interrupts = <0 25 4>;
++
++			clocks = <&clock HI3516AV200_ETH_CLK>,
++					<&clock HI3516AV200_ETH_MACIF_CLK>;
++			clock-names = "higmac_clk",
++					"macif_clk";
++
++			resets = <&clock 0xcc 0>,
++					<&clock 0xcc 2>,
++					<&clock 0xcc 7>;
++			reset-names = "port_reset",
++					"macif_reset",
++					"phy_reset";
++
++			mac-address = [00 00 00 00 00 00];
++		};
++
++		mmc2: himciv200.MMC@0x100e0000 {
++			compatible = "hisilicon,hi3516av200-himciv200";
++			reg = <0x100e0000 0x10000>;
++			interrupts = <0 13 4>;
++
++			clocks = <&clock HI3516AV200_MMC2_CLK>;
++			clock-names = "mmc_clk";
++
++			bus-width = <8>;
++			max-frequency = <148500000>;
++			cap-mmc-highspeed;
++			cap-mmc-hw-reset;
++			full-pwr-cycle;
++			mmc-hs400-1_8v;
++			devid = <2>;
++			status = "disabled";
++		};
++
++		mmc0: himciv200.SD@0x100c0000 {
++			compatible = "hisilicon,hi3516av200-himciv200";
++			reg = <0x100c0000 0x10000>;
++			interrupts = <0 23 4>;
++
++			clocks = <&clock HI3516AV200_MMC0_CLK>;
++			clock-names = "mmc_clk";
++
++			bus-width = <4>;
++			max-frequency = <148500000>;
++			cap-mmc-highspeed;
++			cap-sd-highspeed;
++			sd-uhs-sdr12;
++			sd-uhs-sdr25;
++			sd-uhs-sdr50;
++			sd-uhs-sdr104;
++			devid = <0>;
++			status = "disabled";
++		};
++
++		mmc1: himciv200.SD@0x100d0000 {
++			compatible = "hisilicon,hi3516av200-himciv200";
++			reg = <0x100d0000 0x10000>;
++			interrupts = <0 24 4>;
++
++			clocks = <&clock HI3516AV200_MMC1_CLK>;
++			clock-names = "mmc_clk";
++
++			bus-width = <4>;
++			max-frequency = <148500000>;
++			cap-mmc-highspeed;
++			cap-sd-highspeed;
++			sd-uhs-sdr12;
++			sd-uhs-sdr25;
++			sd-uhs-sdr50;
++			sd-uhs-sdr104;
++			devid = <1>;
++			status = "disabled";
++		};
++
++		fmc: spi-nor-controller@10000000 {
++			compatible = "hisilicon,hisi-fmc";
++			reg = <0x10000000 0x1000>, <0x14000000 0x1000000>;
++			reg-names = "control", "memory";
++			clocks = <&clock HI3516AV200_FMC_CLK>;
++			#address-cells = <1>;
++			#size-cells = <0>;
++
++			hisfc:spi-nor@0 {
++				compatible = "hisilicon,hisi-sfc";
++				assigned-clocks = <&clock HI3516AV200_FMC_CLK>;
++				assigned-clock-rates = <24000000>;
++				#address-cells = <1>;
++				#size-cells = <0>;
++			};
++
++			hisnfc:spi-nand@0 {
++				compatible = "hisilicon,hisi-spi-nand";
++				assigned-clocks = <&clock HI3516AV200_FMC_CLK>;
++				assigned-clock-rates = <24000000>;
++				#address-cells = <1>;
++				#size-cells = <0>;
++			};
++
++			hinfc:nand@0 {
++				compatible = "hisilicon,hisi-nand";
++				assigned-clocks = <&clock HI3516AV200_FMC_CLK>;
++				assigned-clock-rates = <200000000>;
++				#address-cells = <1>;
++				#size-cells = <0>;
++			};
++		};
++	};
++
++};
+diff --git a/arch/arm/boot/dts/hisi-hi3519-demb.dts b/arch/arm/boot/dts/hisi-hi3519-demb.dts
+new file mode 100644
+index 0000000..9b56684
+--- /dev/null
++++ b/arch/arm/boot/dts/hisi-hi3519-demb.dts
+@@ -0,0 +1,109 @@
++/*
++ * Copyright (c) 2013-2014 Linaro Ltd.
++ * Copyright (c) 2015 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++/dts-v1/;
++#include "hisi-hi3519.dtsi"
++
++/ {
++	model = "Hisilicon HI3519 DEMO Board";
++	compatible = "hisilicon,hi3519";
++
++	cpus {
++		#address-cells = <1>;
++		#size-cells = <0>;
++		enable-method = "hisilicon,hi3519-smp";
++
++		cpu@0 {
++			compatible = "arm,cortex-a7";
++			device_type = "cpu";
++			clock-frequency = <HI3519_FIXED_792M>;
++			reg = <0>;
++			cci-control-port = <&cci_control0>;
++		};
++
++		/*cpu@100 {
++			compatible = "arm,cortex-a17";
++			device_type = "cpu";
++			clock-frequency = <HI3519_FIXED_1000M>;
++			reg = <0x100>;
++			cci-control-port = <&cci_control1>;
++		};*/
++	};
++
++	memory {
++		device_type = "memory";
++		reg = <0x80000000 0x40000000>;
++	};
++};
++
++&uart0 {
++	status = "okay";
++};
++
++&dual_timer0 {
++	status = "okay";
++};
++
++&hisfc {
++	hi_sfc {
++		compatible = "jedec,spi-nor";
++		reg = <0>;
++		spi-max-frequency = <160000000>;
++		m25p,fast-read;
++	};
++};
++
++&hisnfc {
++	hinand {
++		compatible = "jedec,spi-nand";
++		reg = <0>;
++		spi-max-frequency = <160000000>;
++	};
++};
++
++&hinfc {
++	hinand {
++		compatible = "jedec,nand";
++		reg = <0>;
++		nand-max-frequency = <200000000>;
++	};
++};
++
++&mmc0 {
++	status = "okay";
++};
++
++&mmc1 {
++	status = "okay";
++};
++
++&mmc2 {
++	status = "okay";
++};
++
++&mdio {
++	ethphy: ethernet-phy@1 {
++		reg = <1>;
++	};
++};
++
++&higmac {
++	phy-handle = <&ethphy>;
++	phy-mode = "rgmii";
++};
+diff --git a/arch/arm/boot/dts/hisi-hi3519-hmp-demb.dts b/arch/arm/boot/dts/hisi-hi3519-hmp-demb.dts
+new file mode 100644
+index 0000000..c43b941
+--- /dev/null
++++ b/arch/arm/boot/dts/hisi-hi3519-hmp-demb.dts
+@@ -0,0 +1,159 @@
++/*
++ * Copyright (c) 2013-2014 Linaro Ltd.
++ * Copyright (c) 2015 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++/dts-v1/;
++#include "hisi-hi3519.dtsi"
++
++/ {
++	model = "Hisilicon HI3519 DEMO Board";
++	compatible = "hisilicon,hi3519";
++
++	chosen {
++		bootargs = "console=ttyAMA0,115200 early_printk
++root=/dev/mtdblock2 rootfstype=jffs2 mtdparts=hi_sfc:1M(boot),
++4M(kernel),11M(rootfs)";
++	};
++
++	cpus {
++		#address-cells = <1>;
++		#size-cells = <0>;
++		enable-method = "hisilicon,hi3519-smp";
++
++		cpu@0 {
++			compatible = "arm,cortex-a7";
++			device_type = "cpu";
++			clock-frequency = <HI3519_FIXED_792M>;
++			reg = <0>;
++			cci-control-port = <&cci_control0>;
++		};
++
++		cpu@100 {
++			compatible = "arm,cortex-a17";
++			device_type = "cpu";
++			reg = <0x100>;
++			cci-control-port = <&cci_control1>;
++#if 1
++			operating-points = <
++				/* KHz    uV */
++				1150000 1000000
++				1000000 960000
++				 880000 920000
++				 792000 890000
++				 594000 830000
++				>;
++			clocks = <&clock HI3519_A17_MUX>,
++				<&clock HI3519_FIXED_400M>,
++				<&clock HI3519_FIXED_500M>,
++				<&clock HI3519_FIXED_594M>,
++				<&clock HI3519_FIXED_792M>,
++				<&clock HI3519_FIXED_1000M>,
++				<&clock HI3519_APLL_CLK>;
++			clock-names = "a17_mux","400m", "500m",
++					"594m", "792m","1000m", "apll";
++			vcc-supply = <&a17_regulator>;
++#endif
++		};
++	};
++
++	avs {
++	    compatible = "hi3519,avs";
++	    avs-num = <2>;
++	    avs-name-array = "cpu-avs","media-avs";
++	    cpu_avs: cpu_avs{
++		avs-name = "cpu-avs";
++			opp-num = <5>;
++			opp-freq = <1150000 1000000 880000 792000 594000 >;
++			opp-volt-min = <800000 750000 720000 700000 670000 >;
++			opp-hpm = <305 290 270 240 220 >;
++			opp-div = <22 19 17 15 11 >;
++			opp-volt-max = <1000000>;
++			};
++
++	    media_avs: media_avs{
++			avs-name = "media-avs";
++			opp-num = <1>;
++			opp-freq = <1>;
++			opp-volt-min = <750000>;
++			opp-hpm = <260>;
++			opp-div = <3>;
++			opp-volt-max = <950000>;
++			};
++	};
++
++	memory {
++		device_type = "memory";
++		reg = <0x80000000 0x40000000>;
++	};
++};
++
++&uart0 {
++	status = "okay";
++};
++
++&dual_timer0 {
++	status = "okay";
++};
++
++&hisfc {
++	hi_sfc {
++		compatible = "jedec,spi-nor";
++		reg = <0>;
++		spi-max-frequency = <160000000>;
++		m25p,fast-read;
++	};
++};
++
++&hisnfc {
++	hinand {
++		compatible = "jedec,spi-nand";
++		reg = <0>;
++		spi-max-frequency = <160000000>;
++	};
++};
++
++&hinfc {
++	hinand {
++		compatible = "jedec,nand";
++		reg = <0>;
++		nand-max-frequency = <200000000>;
++	};
++};
++
++&mmc0 {
++	status = "okay";
++};
++
++&mmc1 {
++	status = "okay";
++};
++
++&mmc2 {
++	status = "okay";
++};
++
++&mdio {
++	ethphy: ethernet-phy@1 {
++		reg = <1>;
++	};
++};
++
++&higmac {
++	phy-handle = <&ethphy>;
++	phy-mode = "rgmii";
++};
+diff --git a/arch/arm/boot/dts/hisi-hi3519.dtsi b/arch/arm/boot/dts/hisi-hi3519.dtsi
+new file mode 100644
+index 0000000..8fb6d56
+--- /dev/null
++++ b/arch/arm/boot/dts/hisi-hi3519.dtsi
+@@ -0,0 +1,470 @@
++/*
++ * Copyright (c) 2013-2014 Linaro Ltd.
++ * Copyright (c) 2015 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include "skeleton.dtsi"
++#include <dt-bindings/clock/hi3519-clock.h>
++/ {
++	aliases {
++		serial0 = &uart0;
++		spi0 = &spi_bus0;
++		spi1 = &spi_bus1;
++		spi2 = &spi_bus2;
++	};
++
++	gic: interrupt-controller@10300000 {
++		compatible = "arm,cortex-a7-gic";
++		#interrupt-cells = <3>;
++		#address-cells = <0>;
++		interrupt-controller;
++		/* gic dist base, gic cpu base , no virtual support */
++		reg = <0x10301000 0x1000>, <0x10302000 0x1000>;
++	};
++
++	clock: clock0 {
++		compatible = "hisilicon,hi3519-clock";
++		#address-cells = <1>;
++		#size-cells = <1>;
++		#clock-cells = <1>;
++		#reset-cells = <2>;
++		reg = <0x12010000 0x10000>;
++	};
++
++	syscounter {
++		compatible = "arm,armv7-timer";
++		interrupt-parent = <&gic>;
++		interrupts = <1 13 0xf08>,
++			<1 14 0xf08>;
++		clock-frequency = <24000000>;
++	};
++
++	soc {
++		#address-cells = <1>;
++		#size-cells = <1>;
++		compatible = "simple-bus";
++		interrupt-parent = <&gic>;
++		ranges;
++
++		amba {
++			#address-cells = <1>;
++			#size-cells = <1>;
++			compatible = "arm,amba-bus";
++			ranges;
++
++			uart0: uart@12100000 {
++				compatible = "arm,pl011", "arm,primecell";
++				reg = <0x12100000 0x1000>;
++				interrupts = <0 4 4>;
++				clocks = <&clock HI3519_UART0_CLK>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++			};
++
++			uart1: uart@12101000 {
++				compatible = "arm,pl011", "arm,primecell";
++				reg = <0x12101000 0x1000>;
++				interrupts = <0 5 4>;
++				clocks = <&clock HI3519_UART1_CLK>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++			};
++
++			uart2: uart@12102000 {
++				compatible = "arm,pl011", "arm,primecell";
++				reg = <0x12102000 0x1000>;
++				interrupts = <0 6 4>;
++				clocks = <&clock HI3519_UART2_CLK>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++			};
++
++			uart3: uart@12103000 {
++				compatible = "arm,pl011", "arm,primecell";
++				reg = <0x12103000 0x1000>;
++				interrupts = <0 7 4>;
++				clocks = <&clock HI3519_UART3_CLK>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++			};
++
++			uart4: uart@12104000 {
++				compatible = "arm,pl011", "arm,primecell";
++				reg = <0x12104000 0x1000>;
++				interrupts = <0 8 4>;
++				clocks = <&clock HI3519_UART4_CLK>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++			};
++			
++			
++			pm {
++				compatible = "hisilicon,hibvt-pm";
++				reg = <0x12020000 0x1000>, <0x12000000 0x1000>;
++			};
++
++			pm_hibernate {
++				compatible = "hisilicon,hibvt-pm-hibernate";
++				reg = <0x12020000 0x1000>;
++			};
++
++			dual_timer0: dual_timer@12000000 {
++				compatible = "arm,sp804";
++				/* timer0 & timer1 */
++				interrupts = <0 64 4>, <0 65 4>;
++				reg = <0x12000000 0x1000>;
++				clocks = <&clock HI3519_FIXED_3M>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++			};
++
++			dual_timer1: dual_timer@12001000 {
++				compatible = "arm,sp804";
++				/* timer2 & timer3 */
++				interrupts = <0 66 4>, <0 67 4>;
++				reg = <0x12001000 0x1000>;
++				clocks = <&clock HI3519_FIXED_3M>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++			};
++
++			dual_timer2: dual_timer@12002000 {
++				compatible = "arm,sp804";
++				/* timer4 & timer5 */
++				interrupts = <0 68 4>, <0 69 4>;
++				reg = <0x12002000 0x1000>;
++				clocks = <&clock HI3519_FIXED_3M>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++			};
++
++			spi_bus0: spi@12120000 {
++				compatible = "arm,pl022", "arm,primecell";
++				arm,primecell-periphid = <0x00800022>;
++				reg = <0x12120000 0x1000>;
++				interrupts = <0 9 4>;
++				clocks = <&clock HI3519_SPI0_CLK>;
++				clock-names = "apb_pclk";
++				status = "okay";
++				num-cs = <1>;
++				#address-cells = <1>;
++				#size-cells = <0>;
++
++				spidev@0 {
++					compatible = "spidev";
++					reg = <0>;
++					pl022,interface = <0>;
++					pl022,com-mode = <0>;
++					spi-max-frequency = <24750000>;
++				};
++
++			};
++
++			spi_bus1: spi@12121000 {
++				compatible = "arm,pl022", "arm,primecell";
++				arm,primecell-periphid = <0x00800022>;
++				reg = <0x12121000 0x1000>, <0x12030004 0x4>;
++				interrupts = <0 10 4>;
++				clocks = <&clock HI3519_SPI1_CLK>;
++				clock-names = "apb_pclk";
++				status = "okay";
++				num-cs = <2>;
++				#address-cells = <1>;
++				#size-cells = <0>;
++				hisi,spi_cs_sb = <26>;
++				hisi,spi_cs_mask_bit = <0x0c000000>;
++
++				spidev@0 {
++					compatible = "spidev";
++					reg = <0>;
++					pl022,interface = <0>;
++					pl022,com-mode = <0>;
++					spi-max-frequency = <24750000>;
++				};
++
++				spidev@1 {
++					compatible = "spidev";
++					reg = <1>;
++					pl022,interface = <0>;
++					pl022,com-mode = <0>;
++					spi-max-frequency = <24750000>;
++				};
++			};
++
++			spi_bus2: spi@12122000 {
++				compatible = "arm,pl022", "arm,primecell";
++				arm,primecell-periphid = <0x00800022>;
++				reg = <0x12122000 0x1000>;
++				interrupts = <0 11 4>;
++				clocks = <&clock HI3519_SPI2_CLK>;
++				clock-names = "apb_pclk";
++				status = "okay";
++				num-cs = <1>;
++				#address-cells = <1>;
++				#size-cells = <0>;
++
++				spidev@0 {
++					compatible = "spidev";
++					reg = <0>;
++					pl022,interface = <0>;
++					pl022,com-mode = <0>;
++					spi-max-frequency = <24750000>;
++				};
++			};
++
++		};
++
++		pmc@0x120a0000 {
++			compatible = "hisilicon,pmc";
++			reg = <0x120a0000 0x1000>;
++		};
++
++		sysctrl: system-controller@00000000 {
++			compatible = "hisilicon,sysctrl";
++			reg = <0x12020000 0x1000>;
++			reboot-offset = <0x4>;
++		};
++
++		usb_phy: phy {
++			compatible = "hisilicon,hisi-usb-phy";
++			reg = <0x12030000 0x10000>, <0x12010000 0x10000>;
++			#phy-cells = <0>;
++		};
++
++		usb3_phy: phy3 {
++			compatible = "hisilicon,hisi-usb3-phy";
++			reg = <0x10180000 0x10000>, <0x12010000 0x10000>;
++			#phy-cells = <0>;
++		};
++		ehci@0x10120000 {
++			 compatible = "generic-ehci";
++			 reg = <0x10120000 0x10000>;
++			 interrupts = <0 19 4>;
++
++			clocks = <&clock HI3519_USB2_CTRL_UTMI0_REQ>,
++					<&clock HI3519_USB2_HRST_REQ>;
++			clock-names = "usb2_cttl_utmi0_req",  "usb2_hrst_req";
++		 };
++
++		ohci@0x10110000 {
++			compatible = "generic-ohci";
++			reg = <0x10110000 0x10000>;
++			interrupts = <0 20 4>;
++
++			clocks = <&clock HI3519_USB2_CTRL_UTMI0_REQ>,
++					<&clock HI3519_USB2_HRST_REQ>;
++			clock-names = "usb2_cttl_utmi0_req", "usb2_hrst_req";
++		 };
++
++		 xhci@0x10180000 {
++			  compatible = "hisilicon,hi3519-xhci", "generic-xhci";
++			  reg = <0x10180000 0x10000>;
++			  interrupts = <0 22 4>;
++
++			  clocks = <&clock HI3519_USB3_CLK>;
++			  clock-names = "clk";
++		  };
++
++		 hiudc@0x10130000 {
++			 compatible = "hiudc";
++			 reg = <0x10130000 0x40000>;
++			 interrupts = <0 21 4>;
++
++			 clocks = <&clock HI3519_USB2_HRST_REQ>;
++			 clock-names = "clk";
++		 };
++
++		 hiudc3@0x10180000 {
++			 compatible = "dwc_usb3";
++			 reg = <0x10180000 0x40000>;
++			 interrupts = <0 22 4>;
++
++			 clocks = <&clock HI3519_USB3_CLK>;
++			 clock-names = "clk";
++		 };
++
++		cci: cci@1ff00000 {
++			compatible = "arm,cci-400";
++			#address-cells = <1>;
++			#size-cells = <1>;
++			reg = <0x1ff00000 0x1000>;
++			ranges = <0x0 0x1ff00000 0x6000>;
++
++			cci_control0: slave-if@4000 {
++				compatible = "arm,cci-400-ctrl-if";
++				interface-type = "ace";
++				reg = <0x1000 0x1000>;
++			};
++
++			cci_control1: slave-if@5000 {
++				compatible = "arm,cci-400-ctrl-if";
++				interface-type = "ace";
++				reg = <0x2000 0x1000>;
++			};
++
++		};
++
++		regulators@120a0000 {
++			compatible = "hi3519,regulators";
++			reg = <0x120a0000 0x1000>;
++			regulator-num = <2>;
++			regulator-name-array = "regulator-a17","regulator-media";
++
++			a17_regulator: a17_regulator{
++				regulator-name = "regulator-a17";
++				regulator-min-microvolt = <648633>;
++				regulator-max-microvolt = <1200525>;
++				regulator-always-on;
++				reg_offset = <0x4>;
++			};
++
++			media_regulator: media_regulator{
++				regulator-name = "regulator-media";
++				regulator-min-microvolt = <649740>;
++				regulator-max-microvolt = <1204331>;
++				regulator-always-on;
++				reg_offset = <0xC>;
++			};
++		};
++
++		pmu {
++			compatible = "arm,cortex-a7-pmu", "arm,cortex-a17-pmu";
++			interrupts = <0 45 4>,
++					<0 46 4>;
++		};
++
++		mdio: mdio@100503c0 {
++			compatible = "hisilicon,hisi-gemac-mdio";
++			reg = <0x100503c0 0x20>;
++			clocks = <&clock HI3519_ETH_CLK>;
++			#address-cells = <1>;
++			#size-cells = <0>;
++		};
++		
++		higmac: ethernet@10050000 {
++			compatible = "hisilicon,higmac";
++			reg = <0x10050000 0x1000>,<0x120100ec 0x4>;
++			interrupts = <0 25 4>;
++
++			clocks = <&clock HI3519_ETH_CLK>,
++					<&clock HI3519_ETH_MACIF_CLK>;
++			clock-names = "higmac_clk",
++					"macif_clk";
++
++			resets = <&clock 0xcc 0>,
++					<&clock 0xcc 2>,
++					<&clock 0xcc 7>;
++			reset-names = "port_reset",
++					"macif_reset",
++					"phy_reset";
++
++			mac-address = [00 00 00 00 00 00];
++		};
++
++		mmc2: himciv200.MMC@0x100e0000 {
++			compatible = "hisilicon,hi3519-himciv200";
++			reg = <0x100e0000 0x10000>;
++			interrupts = <0 13 4>;
++
++			clocks = <&clock HI3519_MMC2_CLK>;
++			clock-names = "mmc_clk";
++
++			bus-width = <8>;
++			max-frequency = <99000000>;
++			cap-mmc-highspeed;
++			cap-mmc-hw-reset;
++			full-pwr-cycle;
++			mmc-hs400-1_8v;
++			devid = <2>;
++			status = "disabled";
++		};
++
++		mmc0: himciv200.SD@0x100c0000 {
++			compatible = "hisilicon,hi3519-himciv200";
++			reg = <0x100c0000 0x10000>;
++			interrupts = <0 23 4>;
++
++			clocks = <&clock HI3519_MMC0_CLK>;
++			clock-names = "mmc_clk";
++
++			bus-width = <4>;
++			max-frequency = <99000000>;
++			cap-mmc-highspeed;
++			cap-sd-highspeed;
++			sd-uhs-sdr12;
++			sd-uhs-sdr25;
++			sd-uhs-sdr50;
++			sd-uhs-sdr104;
++			devid = <0>;
++			status = "disabled";
++		};
++
++		mmc1: himciv200.SD@0x100d0000 {
++			compatible = "hisilicon,hi3519-himciv200";
++			reg = <0x100d0000 0x10000>;
++			interrupts = <0 24 4>;
++
++			clocks = <&clock HI3519_MMC1_CLK>;
++			clock-names = "mmc_clk";
++
++			bus-width = <4>;
++			max-frequency = <99000000>;
++			cap-mmc-highspeed;
++			cap-sd-highspeed;
++			sd-uhs-sdr12;
++			sd-uhs-sdr25;
++			sd-uhs-sdr50;
++			sd-uhs-sdr104;
++			devid = <1>;
++			status = "disabled";
++		};
++
++		fmc: spi-nor-controller@10000000 {
++			compatible = "hisilicon,hisi-fmc";
++			reg = <0x10000000 0x1000>, <0x14000000 0x1000000>;
++			reg-names = "control", "memory";
++			clocks = <&clock HI3519_FMC_CLK>;
++			#address-cells = <1>;
++			#size-cells = <0>;
++
++			hisfc:spi-nor@0 {
++				compatible = "hisilicon,hisi-sfc";
++				assigned-clocks = <&clock HI3519_FMC_CLK>;
++				assigned-clock-rates = <24000000>;
++				#address-cells = <1>;
++				#size-cells = <0>;
++			};
++
++			hisnfc:spi-nand@0 {
++				compatible = "hisilicon,hisi-spi-nand";
++				assigned-clocks = <&clock HI3519_FMC_CLK>;
++				assigned-clock-rates = <24000000>;
++				#address-cells = <1>;
++				#size-cells = <0>;
++			};
++
++			hinfc:nand@0 {
++				compatible = "hisilicon,hisi-nand";
++				assigned-clocks = <&clock HI3519_FMC_CLK>;
++				assigned-clock-rates = <200000000>;
++				#address-cells = <1>;
++				#size-cells = <0>;
++			};
++		};
++	};
++
++};
+diff --git a/arch/arm/boot/dts/hisi-hi3519v101-demb.dts b/arch/arm/boot/dts/hisi-hi3519v101-demb.dts
+new file mode 100644
+index 0000000..7478525
+--- /dev/null
++++ b/arch/arm/boot/dts/hisi-hi3519v101-demb.dts
+@@ -0,0 +1,247 @@
++/*
++ * Copyright (c) 2013-2014 Linaro Ltd.
++ * Copyright (c) 2015 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++/dts-v1/;
++#include "hisi-hi3519v101.dtsi"
++
++/ {
++	model = "Hisilicon HI3519V101 DEMO Board";
++	compatible = "hisilicon,hi3519v101";
++
++	cpus {
++		#address-cells = <1>;
++		#size-cells = <0>;
++		enable-method = "hisilicon,hi3519-smp";
++
++		cpu@0 {
++			compatible = "arm,cortex-a7";
++			device_type = "cpu";
++			clock-frequency = <HI3519_FIXED_792M>;
++			reg = <0>;
++			cci-control-port = <&cci_control0>;
++		};
++
++		/*cpu@100 {
++			compatible = "arm,cortex-a17";
++			device_type = "cpu";
++			clock-frequency = <HI3519_FIXED_1000M>;
++			reg = <0x100>;
++			cci-control-port = <&cci_control1>;
++		};*/
++	};
++
++	memory {
++		device_type = "memory";
++		reg = <0x80000000 0x40000000>;
++	};
++};
++
++&uart0 {
++	status = "okay";
++};
++
++&dual_timer0 {
++	status = "okay";
++};
++
++&i2c_bus0 {
++	status = "okay";
++};
++
++&i2c_bus1 {
++	status = "okay";
++};
++
++&i2c_bus2 {
++	status = "okay";
++};
++
++&i2c_bus3 {
++	status = "okay";
++};
++
++&spi_bus0 {
++	status = "okay";
++
++	spidev@0 {
++		compatible = "rohm,dh2228fv";
++		reg = <0>;
++		pl022,interface = <0>;
++		pl022,com-mode = <0>;
++		spi-max-frequency = <24750000>;
++	};
++
++};
++
++&spi_bus1 {
++	status = "okay";
++
++	spidev@0 {
++		compatible = "rohm,dh2228fv";
++		reg = <0>;
++		pl022,interface = <0>;
++		pl022,com-mode = <0>;
++		spi-max-frequency = <24750000>;
++	};
++};
++
++&spi_bus2 {
++	status = "okay";
++
++	spidev@0 {
++		compatible = "rohm,dh2228fv";
++		reg = <0>;
++		pl022,interface = <0>;
++		pl022,com-mode = <0>;
++		spi-max-frequency = <24750000>;
++	};
++
++	spidev@1 {
++		compatible = "rohm,dh2228fv";
++		reg = <1>;
++		pl022,interface = <0>;
++		pl022,com-mode = <0>;
++		spi-max-frequency = <24750000>;
++	};
++};
++
++&spi_bus3 {
++	status = "okay";
++
++	spidev@0 {
++		compatible = "rohm,dh2228fv";
++		reg = <0>;
++		pl022,interface = <0>;
++		pl022,com-mode = <0>;
++		spi-max-frequency = <24750000>;
++	};
++};
++
++&hisfc {
++	hi_sfc {
++		compatible = "jedec,spi-nor";
++		reg = <0>;
++		spi-max-frequency = <160000000>;
++		m25p,fast-read;
++	};
++
++};
++
++&hisnfc {
++	hinand {
++		compatible = "jedec,spi-nand";
++		reg = <0>;
++		spi-max-frequency = <160000000>;
++	};
++};
++
++&hinfc {
++	hinand {
++		compatible = "jedec,nand";
++		reg = <0>;
++		nand-max-frequency = <200000000>;
++	};
++};
++
++&mmc0 {
++	status = "okay";
++};
++
++&mmc1 {
++	status = "okay";
++};
++
++&mmc2 {
++	status = "okay";
++};
++
++&mdio {
++	ethphy: ethernet-phy@1 {
++		reg = <1>;
++	};
++};
++
++&higmac {
++	phy-handle = <&ethphy>;
++	phy-mode = "rgmii";
++};
++
++&gpio_chip0 {
++	status = "okay";
++};
++
++&gpio_chip1 {
++	status = "okay";
++};
++
++&gpio_chip2 {
++	status = "okay";
++};
++
++&gpio_chip3 {
++	status = "okay";
++};
++
++&gpio_chip4 {
++	status = "okay";
++};
++
++&gpio_chip5 {
++	status = "okay";
++};
++
++&gpio_chip6 {
++	status = "okay";
++};
++
++&gpio_chip7 {
++	status = "okay";
++};
++
++&gpio_chip8 {
++	status = "okay";
++};
++
++&gpio_chip9 {
++	status = "okay";
++};
++
++&gpio_chip10 {
++	status = "okay";
++};
++
++&gpio_chip11 {
++	status = "okay";
++};
++
++&gpio_chip12 {
++	status = "okay";
++};
++
++&gpio_chip13 {
++	status = "okay";
++};
++
++&gpio_chip14 {
++	status = "okay";
++};
++
++&gpio_chip16 {
++	status = "okay";
++};
+diff --git a/arch/arm/boot/dts/hisi-hi3519v101-hmp-demb.dts b/arch/arm/boot/dts/hisi-hi3519v101-hmp-demb.dts
+new file mode 100644
+index 0000000..dd2412f
+--- /dev/null
++++ b/arch/arm/boot/dts/hisi-hi3519v101-hmp-demb.dts
+@@ -0,0 +1,310 @@
++/*
++ * Copyright (c) 2013-2014 Linaro Ltd.
++ * Copyright (c) 2015 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++/dts-v1/;
++#include "hisi-hi3519v101.dtsi"
++
++/ {
++	model = "Hisilicon HI3519V101 DEMO Board";
++	compatible = "hisilicon,hi3519v101";
++
++	chosen {
++		bootargs = "console=ttyAMA0,115200 early_printk
++root=/dev/mtdblock2 rootfstype=jffs2 mtdparts=hi_sfc:1M(boot),
++4M(kernel),11M(rootfs)";
++	};
++
++	cpus {
++		#address-cells = <1>;
++		#size-cells = <0>;
++		enable-method = "hisilicon,hi3519-smp";
++
++		cpu@0 {
++			compatible = "arm,cortex-a7";
++			device_type = "cpu";
++			clock-frequency = <HI3519_FIXED_792M>;
++			reg = <0>;
++			cci-control-port = <&cci_control0>;
++		};
++
++		cpu@100 {
++			compatible = "arm,cortex-a17";
++			device_type = "cpu";
++			reg = <0x100>;
++			cci-control-port = <&cci_control1>;
++			operating-points = <
++				/* KHz    uV */
++				1250000 1060000
++				1150000 1060000
++				1000000 1000000
++				 930000 1000000
++				 792000 940000
++				 594000 940000
++				>;
++			clocks = <&clock HI3519_A17_MUX>,
++				<&clock HI3519_FIXED_400M>,
++				<&clock HI3519_FIXED_500M>,
++				<&clock HI3519_FIXED_594M>,
++				<&clock HI3519_FIXED_792M>,
++				<&clock HI3519_APLL_CLK>;
++			clock-names = "a17_mux","400m", "500m",
++					"594m", "792m", "apll";
++			vcc-supply = <&a17_regulator>;
++		};
++	};
++
++	avs {
++	    compatible = "hi3519,avs";
++	    avs-num = <2>;
++	    avs-name-array = "cpu-avs","media-avs";
++	    cpu_avs: cpu_avs{
++		avs-name = "cpu-avs";
++			opp-num = <6>;
++			opp-freq = <1250000 1150000 1000000 930000 792000 594000 >;
++			opp-volt-min = <870000 870000 800000 800000 740000 740000>;
++			opp-hpm = <310 310 280 280 250 250>;
++			opp-div = <24 22 19 18 15 11>;
++			opp-volt-max = <1060000>;
++			};
++
++	    media_avs: media_avs{
++			avs-name = "media-avs";
++			opp-num = <4>;
++			opp-prof-num = <2>;
++			opp-temp-num = <2>;
++			opp-temp = <50 200>;
++			opp-freq = <1 2 3 4>;
++			opp-volt-min = <
++				/* profile2    profile3*/
++                                  770000       770000
++                                  770000       770000
++				      >;
++			opp-hpm = <
++				/* profile2    profile3*/
++				     210       215 
++				     190       215
++				  >;
++			opp-div = <3 3 3 3>;
++			opp-volt-max = <
++				/* profile2    profile3*/
++                                  977000       977000
++                                  977000       977000
++				>;
++			};
++	};
++
++	memory {
++		device_type = "memory";
++		reg = <0x80000000 0x40000000>;
++	};
++};
++
++&uart0 {
++	status = "okay";
++};
++
++&dual_timer0 {
++	status = "okay";
++};
++
++&i2c_bus0 {
++	status = "okay";
++};
++
++&i2c_bus1 {
++	status = "okay";
++};
++
++&i2c_bus2 {
++	status = "okay";
++};
++
++&i2c_bus3 {
++	status = "okay";
++};
++
++&spi_bus0 {
++	status = "okay";
++
++	spidev@0 {
++		compatible = "rohm,dh2228fv";
++		reg = <0>;
++		pl022,interface = <0>;
++		pl022,com-mode = <0>;
++		spi-max-frequency = <24000000>;
++	};
++
++};
++
++&spi_bus1 {
++	status = "okay";
++
++	spidev@0 {
++		compatible = "rohm,dh2228fv";
++		reg = <0>;
++		pl022,interface = <0>;
++		pl022,com-mode = <0>;
++		spi-max-frequency = <24000000>;
++	};
++
++	spidev@1 {
++		compatible = "rohm,dh2228fv";
++		reg = <1>;
++		pl022,interface = <0>;
++		pl022,com-mode = <0>;
++		spi-max-frequency = <24000000>;
++	};
++};
++
++&spi_bus2 {
++	status = "okay";
++
++	spidev@0 {
++		compatible = "rohm,dh2228fv";
++		reg = <0>;
++		pl022,interface = <0>;
++		pl022,com-mode = <0>;
++		spi-max-frequency = <24000000>;
++	};
++};
++
++&spi_bus3 {
++	status = "okay";
++
++	spidev@0 {
++		compatible = "rohm,dh2228fv";
++		reg = <0>;
++		pl022,interface = <0>;
++		pl022,com-mode = <0>;
++		spi-max-frequency = <24000000>;
++	};
++};
++
++&hisfc {
++	hi_sfc {
++		compatible = "jedec,spi-nor";
++		reg = <0>;
++		spi-max-frequency = <160000000>;
++		m25p,fast-read;
++	};
++};
++
++&hisnfc {
++	hinand {
++		compatible = "jedec,spi-nand";
++		reg = <0>;
++		spi-max-frequency = <160000000>;
++	};
++};
++
++&hinfc {
++	hinand {
++		compatible = "jedec,nand";
++		reg = <0>;
++		nand-max-frequency = <200000000>;
++	};
++};
++
++&mmc0 {
++	status = "okay";
++};
++
++&mmc1 {
++	status = "okay";
++};
++
++&mmc2 {
++	status = "okay";
++};
++
++&mdio {
++	ethphy: ethernet-phy@1 {
++		reg = <1>;
++	};
++};
++
++&higmac {
++	compatible = "hisilicon,higmac-v3", "hisilicon,higmac";
++	phy-handle = <&ethphy>;
++	phy-mode = "rgmii";
++};
++
++&gpio_chip0 {
++	status = "okay";
++};
++
++&gpio_chip1 {
++	status = "okay";
++};
++
++&gpio_chip2 {
++	status = "okay";
++};
++
++&gpio_chip3 {
++	status = "okay";
++};
++
++&gpio_chip4 {
++	status = "okay";
++};
++
++&gpio_chip5 {
++	status = "okay";
++};
++
++&gpio_chip6 {
++	status = "okay";
++};
++
++&gpio_chip7 {
++	status = "okay";
++};
++
++&gpio_chip8 {
++	status = "okay";
++};
++
++&gpio_chip9 {
++	status = "okay";
++};
++
++&gpio_chip10 {
++	status = "okay";
++};
++
++&gpio_chip11 {
++	status = "okay";
++};
++
++&gpio_chip12 {
++	status = "okay";
++};
++
++&gpio_chip13 {
++	status = "okay";
++};
++
++&gpio_chip14 {
++	status = "okay";
++};
++
++&gpio_chip16 {
++	status = "okay";
++};
+diff --git a/arch/arm/boot/dts/hisi-hi3519v101.dtsi b/arch/arm/boot/dts/hisi-hi3519v101.dtsi
+new file mode 100644
+index 0000000..df48673
+--- /dev/null
++++ b/arch/arm/boot/dts/hisi-hi3519v101.dtsi
+@@ -0,0 +1,777 @@
++/*
++ * Copyright (c) 2013-2014 Linaro Ltd.
++ * Copyright (c) 2015 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include "skeleton.dtsi"
++#include <dt-bindings/clock/hi3519-clock.h>
++/ {
++	aliases {
++		serial0 = &uart0;
++		i2c0 = &i2c_bus0;
++		i2c1 = &i2c_bus1;
++		i2c2 = &i2c_bus2;
++		i2c3 = &i2c_bus3;
++		spi0 = &spi_bus0;
++		spi1 = &spi_bus1;
++		spi2 = &spi_bus2;
++		spi3 = &spi_bus3;
++		gpio0 = &gpio_chip0;
++		gpio1 = &gpio_chip1;
++		gpio2 = &gpio_chip2;
++		gpio3 = &gpio_chip3;
++		gpio4 = &gpio_chip4;
++		gpio5 = &gpio_chip5;
++		gpio6 = &gpio_chip6;
++		gpio7 = &gpio_chip7;
++		gpio8 = &gpio_chip8;
++		gpio9 = &gpio_chip9;
++		gpio10 = &gpio_chip10;
++		gpio11 = &gpio_chip11;
++		gpio12 = &gpio_chip12;
++		gpio13 = &gpio_chip13;
++		gpio14 = &gpio_chip14;
++		gpio16 = &gpio_chip16;
++	};
++
++	gic: interrupt-controller@10300000 {
++		compatible = "arm,cortex-a7-gic";
++		#interrupt-cells = <3>;
++		#address-cells = <0>;
++		interrupt-controller;
++		/* gic dist base, gic cpu base , no virtual support */
++		reg = <0x10301000 0x1000>, <0x10302000 0x1000>;
++	};
++
++	clock: clock0 {
++		compatible = "hisilicon,hi3519v101-clock";
++		#address-cells = <1>;
++		#size-cells = <1>;
++		#clock-cells = <1>;
++		#reset-cells = <2>;
++		reg = <0x12010000 0x10000>;
++	};
++
++	syscounter {
++		compatible = "arm,armv7-timer";
++		interrupt-parent = <&gic>;
++		interrupts = <1 13 0xf08>,
++			<1 14 0xf08>;
++		clock-frequency = <24000000>;
++	};
++
++	soc {
++		#address-cells = <1>;
++		#size-cells = <1>;
++		compatible = "simple-bus";
++		interrupt-parent = <&gic>;
++		ranges;
++
++		amba {
++			#address-cells = <1>;
++			#size-cells = <1>;
++			compatible = "arm,amba-bus";
++			ranges;
++
++			uart0: uart@12100000 {
++				compatible = "arm,pl011", "arm,primecell";
++				reg = <0x12100000 0x1000>;
++				interrupts = <0 4 4>;
++				clocks = <&clock HI3519_UART0_CLK>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++			};
++
++			uart1: uart@12101000 {
++				compatible = "arm,pl011", "arm,primecell";
++				reg = <0x12101000 0x1000>;
++				interrupts = <0 5 4>;
++				clocks = <&clock HI3519_UART1_CLK>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++			};
++
++			uart2: uart@12102000 {
++				compatible = "arm,pl011", "arm,primecell";
++				reg = <0x12102000 0x1000>;
++				interrupts = <0 6 4>;
++				clocks = <&clock HI3519_UART2_CLK>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++			};
++
++			uart3: uart@12103000 {
++				compatible = "arm,pl011", "arm,primecell";
++				reg = <0x12103000 0x1000>;
++				interrupts = <0 7 4>;
++				clocks = <&clock HI3519_UART3_CLK>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++			};
++
++			uart4: uart@12104000 {
++				compatible = "arm,pl011", "arm,primecell";
++				reg = <0x12104000 0x1000>;
++				interrupts = <0 8 4>;
++				clocks = <&clock HI3519_UART4_CLK>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++			};
++
++			sys: sys@12010000 {
++				compatible = "hisilicon,hi35xx_sys";
++				reg = <0x12020000 0x10000>, <0x12060000 0x10000>, <0X12030000 0x10000>;
++				reg-names = "sys", "ddr", "misc";
++			};
++
++			mipi: mipi@11300000 {
++				compatible = "hisilicon,hi35xx_mipi";
++				interrupts = <0 28 4>, <0 29 4>;
++				interrupt-names = "mipi0", "mipi1";
++				reg = <0x11300000 0x10000>;
++			};
++
++			isp: isp@11380000 {
++				compatible = "hisilicon,hi35xx_isp";
++				interrupts = <0 30 4>, <0 31 4>;
++				interrupt-names = "isp0", "isp1";
++			};
++
++			viu: viu@11380000 {
++				compatible = "hisilicon,hi35xx_viu";
++				interrupts = <0 30 4>, <0 31 4>;
++				interrupt-names = "viu0", "viu1";
++				reg = <0x11380000 0x70000>, <0x11480000 0x70000>;
++				reg-names = "viu0", "viu1";
++			};
++
++			vou: vou@11000000 {
++				compatible = "hisilicon,hi35xx_vou";
++				interrupts = <0 27 4>;
++				reg = <0x11000000 0x20000>;
++			};
++
++			tde: tde@11100000 {
++				compatible = "hisilicon,hi35xx_tde";
++				interrupts = <0 34 4>;
++				reg = <0x11100000 0x10000>;
++			};
++
++			fisheye: fisheye@11110000 {
++				compatible = "hisilicon,hi35xx_fisheye";
++				interrupts = <0 48 4>;
++				reg = <0x11110000 0x10000>;
++			};
++
++			vgs: vgs@11120000 {
++				compatible = "hisilicon,hi35xx_vgs";
++				interrupts = <0 35 4>;
++				reg = <0x11120000 0x10000>;
++			};
++
++			vpss: vpss@11180000 {
++				compatible = "hisilicon,hi35xx_vpss";
++				interrupts = <0 30 4>, <0 32 4>;
++				interrupt-names = "viu0", "vpss";
++				reg = <0x11180000 0x10000>;
++			};
++
++			vedu: vedu@11280000 {
++					compatible = "hisilicon,hi35xx_vedu";
++					interrupts = <0 37 4>;
++					reg = <0x11280000 0x10000>;
++			};
++
++			jpege: jpege@11200000 {
++					compatible = "hisilicon,hi35xx_jpege";
++					interrupts = <0 38 4>;
++					reg = <0x11200000 0x10000>;
++			};
++
++			aiao: aiao@11080000 {
++				compatible = "hisilicon,hi35xx_aiao";
++				interrupts = <0 36 4>;
++				reg = <0x11080000 0x3000>;
++			};
++
++			ive: ive@11040000 {
++				compatible = "hisilicon,hi35xx_ive";
++				interrupts = <0 39 4>;
++				reg = <0x11040000 0x10000>;
++			};
++
++			fd: fd@11060000 {
++				compatible = "hisilicon,hi35xx_fd";
++				interrupts = <0 40 4>;
++				reg = <0x11060000 0x10000>;
++			};
++
++			pwm: pwm@12130000 {
++				compatible = "hisilicon,pwm";
++				reg = <0x12130000 0x10000>;
++			};
++
++			piris: piris@12145000 {
++				compatible = "hisilicon,piris";
++				reg = <0x12145000 0x1000>;
++			};
++
++			wtdg: wtdg@12080000 {
++				compatible = "hisilicon,hi_wdg";
++				reg = <0x12080000 0x10000>;
++				reg-names = "wtdg";
++			};
++
++			rtc: rtc@12090000 {
++				compatible = "hisilicon,hi_rtc";
++				interrupts = <0 1 4>;
++				reg = <0x12090000 0x10000>;
++			};
++
++			ir: ir@120f0000{
++				compatible = "hisilicon,hi_ir";
++				interrupts = <0 15 4>;
++				reg = <0x120f0000 0x10000>;
++			};
++			
++			pm {
++				compatible = "hisilicon,hibvt-pm";
++				reg = <0x12020000 0x1000>, <0x12000000 0x1000>;
++			};
++
++			pm_hibernate {
++				compatible = "hisilicon,hibvt-pm-hibernate";
++				reg = <0x12020000 0x1000>;
++			};
++
++			dual_timer0: dual_timer@12000000 {
++				compatible = "arm,sp804";
++				/* timer0 & timer1 */
++				interrupts = <0 64 4>, <0 65 4>;
++				reg = <0x12000000 0x1000>;
++				clocks = <&clock HI3519_FIXED_3M>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++			};
++
++			dual_timer1: dual_timer@12001000 {
++				compatible = "arm,sp804";
++				/* timer2 & timer3 */
++				interrupts = <0 66 4>, <0 67 4>;
++				reg = <0x12001000 0x1000>;
++				clocks = <&clock HI3519_FIXED_3M>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++			};
++
++			dual_timer2: dual_timer@12002000 {
++				compatible = "arm,sp804";
++				/* timer4 & timer5 */
++				interrupts = <0 68 4>, <0 69 4>;
++				reg = <0x12002000 0x1000>;
++				clocks = <&clock HI3519_FIXED_3M>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++			};
++
++			i2c_bus0: i2c@12110000 {
++				compatible = "hisilicon,hisi-i2c-v110";
++				reg = <0x12110000 0x100>;
++				clocks = <&clock HI3519_I2C_MUX>;
++				clock-frequency = <100000>;
++				status = "disabled";
++			};
++
++			i2c_bus1: i2c@12111000 {
++				compatible = "hisilicon,hisi-i2c-v110";
++				reg = <0x12111000 0x100>;
++				clocks = <&clock HI3519_I2C_MUX>;
++				clock-frequency = <100000>;
++				status = "disabled";
++			};
++
++			i2c_bus2: i2c@12112000 {
++				compatible = "hisilicon,hisi-i2c-v110";
++				reg = <0x12112000 0x100>;
++				clocks = <&clock HI3519_I2C_MUX>;
++				clock-frequency = <100000>;
++				status = "disabled";
++			};
++
++			i2c_bus3: i2c@12113000 {
++				compatible = "hisilicon,hisi-i2c-v110";
++				reg = <0x12113000 0x100>;
++				clocks = <&clock HI3519_I2C_MUX>;
++				clock-frequency = <100000>;
++				status = "disabled";
++			};
++
++			spi_bus0: spi@12120000 {
++				compatible = "arm,pl022", "arm,primecell";
++				arm,primecell-periphid = <0x00800022>;
++				reg = <0x12120000 0x1000>;
++				interrupts = <0 9 4>;
++				clocks = <&clock HI3519_SPI0_CLK>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++				num-cs = <1>;
++				#address-cells = <1>;
++				#size-cells = <0>;
++			};
++
++			spi_bus1: spi@12121000 {
++				compatible = "arm,pl022", "arm,primecell";
++				arm,primecell-periphid = <0x00800022>;
++				reg = <0x12121000 0x1000>;
++				interrupts = <0 10 4>;
++				clocks = <&clock HI3519_SPI1_CLK>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++				num-cs = <1>;
++				#address-cells = <1>;
++				#size-cells = <0>;
++			};
++
++			spi_bus2: spi@12122000 {
++				compatible = "arm,pl022", "arm,primecell";
++				arm,primecell-periphid = <0x00800022>;
++				reg = <0x12122000 0x1000>, <0x12030004 0x4>;
++				interrupts = <0 11 4>;
++				clocks = <&clock HI3519_SPI2_CLK>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++				num-cs = <2>;
++				#address-cells = <1>;
++				#size-cells = <0>;
++				hisi,spi_cs_sb = <26>;
++				hisi,spi_cs_mask_bit = <0x0c000000>;
++			};
++
++			spi_bus3: spi@12123000 {
++				compatible = "arm,pl022", "arm,primecell";
++				arm,primecell-periphid = <0x00800022>;
++				reg = <0x12123000 0x1000>;
++				interrupts = <0 12 4>;
++				clocks = <&clock HI3519_SPI3_CLK>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++				num-cs = <1>;
++				#address-cells = <1>;
++				#size-cells = <0>;
++			};
++
++			gpio_chip0: gpio_chip@12140000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x12140000 0x1000>;
++				interrupts = <0 43 4>;
++				clocks = <&clock HI3519_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip1: gpio_chip@12141000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x12141000 0x1000>;
++				interrupts = <0 43 4>;
++				clocks = <&clock HI3519_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip2: gpio_chip@12142000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x12142000 0x1000>;
++				interrupts = <0 43 4>;
++				clocks = <&clock HI3519_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip3: gpio_chip@12143000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x12143000 0x1000>;
++				interrupts = <0 43 4>;
++				clocks = <&clock HI3519_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip4: gpio_chip@12144000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x12144000 0x1000>;
++				interrupts = <0 43 4>;
++				clocks = <&clock HI3519_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip5: gpio_chip@12145000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x12145000 0x1000>;
++				interrupts = <0 43 4>;
++				clocks = <&clock HI3519_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip6: gpio_chip@12146000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x12146000 0x1000>;
++				interrupts = <0 43 4>;
++				clocks = <&clock HI3519_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip7: gpio_chip@12147000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x12147000 0x1000>;
++				interrupts = <0 43 4>;
++				clocks = <&clock HI3519_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip8: gpio_chip@12148000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x12148000 0x1000>;
++				interrupts = <0 44 4>;
++				clocks = <&clock HI3519_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip9: gpio_chip@12149000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x12149000 0x1000>;
++				interrupts = <0 44 4>;
++				clocks = <&clock HI3519_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip10: gpio_chip@1214a000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x1214a000 0x1000>;
++				interrupts = <0 44 4>;
++				clocks = <&clock HI3519_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip11: gpio_chip@1214b000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x1214b000 0x1000>;
++				interrupts = <0 44 4>;
++				clocks = <&clock HI3519_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip12: gpio_chip@1214c000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x1214c000 0x1000>;
++				interrupts = <0 44 4>;
++				clocks = <&clock HI3519_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip13: gpio_chip@1214d000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x1214d000 0x1000>;
++				interrupts = <0 44 4>;
++				clocks = <&clock HI3519_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip14: gpio_chip@1214e000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x1214e000 0x1000>;
++				interrupts = <0 44 4>;
++				clocks = <&clock HI3519_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip16: gpio_chip@12150000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x12150000 0x1000>;
++				interrupts = <0 44 4>;
++				clocks = <&clock HI3519_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++		};
++
++		pmc@0x120a0000 {
++			compatible = "hisilicon,pmc";
++			reg = <0x120a0000 0x1000>;
++		};
++
++		sysctrl: system-controller@00000000 {
++			compatible = "hisilicon,sysctrl";
++			reg = <0x12020000 0x1000>;
++			reboot-offset = <0x4>;
++		};
++
++		usb_phy: phy {
++			compatible = "hisilicon,hisi-usb-phy";
++			reg = <0x12030000 0x10000>, <0x12010000 0x10000>;
++			#phy-cells = <0>;
++		};
++
++		usb3_phy: phy3 {
++			compatible = "hisilicon,hisi-usb3-phy";
++			reg = <0x10180000 0x10000>, <0x12010000 0x10000>,
++				<0x12030000 0x10000>;
++			#phy-cells = <0>;
++		};
++		ehci@0x10120000 {
++			 compatible = "generic-ehci";
++			 reg = <0x10120000 0x10000>;
++			 interrupts = <0 19 4>;
++
++			clocks = <&clock HI3519_USB2_CTRL_UTMI0_REQ>,
++					<&clock HI3519_USB2_HRST_REQ>;
++			clock-names = "usb2_cttl_utmi0_req",  "usb2_hrst_req";
++		 };
++
++		ohci@0x10110000 {
++			compatible = "generic-ohci";
++			reg = <0x10110000 0x10000>;
++			interrupts = <0 20 4>;
++			clocks = <&clock HI3519_USB2_CTRL_UTMI0_REQ>,
++					<&clock HI3519_USB2_HRST_REQ>;
++			clock-names = "usb2_cttl_utmi0_req", "usb2_hrst_req";
++		 };
++
++		 xhci@0x10180000 {
++			  compatible = "hisilicon,hi3519-xhci", "generic-xhci";
++			  reg = <0x10180000 0x10000>;
++			  interrupts = <0 22 4>;
++
++			  clocks = <&clock HI3519_USB3_CLK>;
++			  clock-names = "clk";
++		  };
++
++		 hiudc@0x10130000 {
++			 compatible = "hiudc";
++			 reg = <0x10130000 0x40000>;
++			 interrupts = <0 21 4>;
++
++			 clocks = <&clock HI3519_USB2_HRST_REQ>;
++			 clock-names = "clk";
++		 };
++
++		 hiudc3@0x10180000 {
++			 compatible = "dwc_usb3";
++			 reg = <0x10180000 0x40000>;
++			 interrupts = <0 22 4>;
++
++			 clocks = <&clock HI3519_USB3_CLK>;
++			 clock-names = "clk";
++		 };
++
++		cci: cci@1ff00000 {
++			compatible = "arm,cci-400";
++			#address-cells = <1>;
++			#size-cells = <1>;
++			reg = <0x1ff00000 0x1000>;
++			ranges = <0x0 0x1ff00000 0x6000>;
++
++			cci_control0: slave-if@4000 {
++				compatible = "arm,cci-400-ctrl-if";
++				interface-type = "ace";
++				reg = <0x2000 0x1000>;
++			};
++
++			cci_control1: slave-if@5000 {
++				compatible = "arm,cci-400-ctrl-if";
++				interface-type = "ace";
++				reg = <0x3000 0x1000>;
++			};
++
++		};
++
++		regulators@120a0000 {
++			compatible = "hi35xx,regulators";
++			reg = <0x120a0000 0x1000>;
++			regulator-num = <2>;
++			regulator-name-array = "regulator-a17","regulator-media";
++
++			a17_regulator: a17_regulator{
++				regulator-name = "regulator-a17";
++				regulator-min-microvolt = <651216>;
++				regulator-max-microvolt = <1083359>;
++				regulator-always-on;
++				reg_offset = <0x4>;
++			};
++
++			media_regulator: media_regulator{
++				regulator-name = "regulator-media";
++				regulator-min-microvolt = <649609>;
++				regulator-max-microvolt = <977031>;
++				regulator-always-on;
++				reg_offset = <0xC>;
++			};
++		};
++
++		pmu {
++			compatible = "arm,cortex-a7-pmu", "arm,cortex-a17-pmu";
++			interrupts = <0 45 4>,
++					<0 46 4>;
++		};
++
++		mdio: mdio@100503c0 {
++			compatible = "hisilicon,hisi-gemac-mdio";
++			reg = <0x100503c0 0x20>;
++			clocks = <&clock HI3519_ETH_CLK>;
++			#address-cells = <1>;
++			#size-cells = <0>;
++		};
++
++		higmac: ethernet@10050000 {
++			compatible = "hisilicon,higmac";
++			reg = <0x10050000 0x1000>,<0x120100ec 0x4>;
++			interrupts = <0 25 4>;
++
++			clocks = <&clock HI3519_ETH_CLK>,
++					<&clock HI3519_ETH_MACIF_CLK>;
++			clock-names = "higmac_clk",
++					"macif_clk";
++
++			resets = <&clock 0xcc 0>,
++					<&clock 0xcc 2>,
++					<&clock 0xcc 7>;
++			reset-names = "port_reset",
++					"macif_reset",
++					"phy_reset";
++
++			mac-address = [00 00 00 00 00 00];
++		};
++
++		mmc2: himciv200.MMC@0x100e0000 {
++			compatible = "hisilicon,hi3519-himciv200";
++			reg = <0x100e0000 0x10000>;
++			interrupts = <0 13 4>;
++
++			clocks = <&clock HI3519_MMC2_CLK>;
++			clock-names = "mmc_clk";
++
++			bus-width = <8>;
++			max-frequency = <148500000>;
++			cap-mmc-highspeed;
++			cap-mmc-hw-reset;
++			full-pwr-cycle;
++			mmc-hs400-1_8v;
++			devid = <2>;
++			status = "disabled";
++		};
++
++		mmc0: himciv200.SD@0x100c0000 {
++			compatible = "hisilicon,hi3519-himciv200";
++			reg = <0x100c0000 0x10000>;
++			interrupts = <0 23 4>;
++
++			clocks = <&clock HI3519_MMC0_CLK>;
++			clock-names = "mmc_clk";
++
++			bus-width = <4>;
++			max-frequency = <148500000>;
++			cap-mmc-highspeed;
++			cap-sd-highspeed;
++			sd-uhs-sdr12;
++			sd-uhs-sdr25;
++			sd-uhs-sdr50;
++			sd-uhs-sdr104;
++			devid = <0>;
++			status = "disabled";
++		};
++
++		mmc1: himciv200.SD@0x100d0000 {
++			compatible = "hisilicon,hi3519-himciv200";
++			reg = <0x100d0000 0x10000>;
++			interrupts = <0 24 4>;
++
++			clocks = <&clock HI3519_MMC1_CLK>;
++			clock-names = "mmc_clk";
++
++			bus-width = <4>;
++			max-frequency = <148500000>;
++			cap-mmc-highspeed;
++			cap-sd-highspeed;
++			sd-uhs-sdr12;
++			sd-uhs-sdr25;
++			sd-uhs-sdr50;
++			sd-uhs-sdr104;
++			devid = <1>;
++			status = "disabled";
++		};
++
++		fmc: spi-nor-controller@10000000 {
++			compatible = "hisilicon,hisi-fmc";
++			reg = <0x10000000 0x1000>, <0x14000000 0x1000000>;
++			reg-names = "control", "memory";
++			clocks = <&clock HI3519_FMC_CLK>;
++			#address-cells = <1>;
++			#size-cells = <0>;
++
++			hisfc:spi-nor@0 {
++				compatible = "hisilicon,hisi-sfc";
++				assigned-clocks = <&clock HI3519_FMC_CLK>;
++				assigned-clock-rates = <24000000>;
++				#address-cells = <1>;
++				#size-cells = <0>;
++			};
++
++			hisnfc:spi-nand@0 {
++				compatible = "hisilicon,hisi-spi-nand";
++				assigned-clocks = <&clock HI3519_FMC_CLK>;
++				assigned-clock-rates = <24000000>;
++				#address-cells = <1>;
++				#size-cells = <0>;
++			};
++
++			hinfc:nand@0 {
++				compatible = "hisilicon,hisi-nand";
++				assigned-clocks = <&clock HI3519_FMC_CLK>;
++				assigned-clock-rates = <200000000>;
++				#address-cells = <1>;
++				#size-cells = <0>;
++			};
++		};
++	};
++
++};
+diff --git a/arch/arm/boot/dts/hisi-hi3556-demb.dts b/arch/arm/boot/dts/hisi-hi3556-demb.dts
+new file mode 100644
+index 0000000..1e99e3e
+--- /dev/null
++++ b/arch/arm/boot/dts/hisi-hi3556-demb.dts
+@@ -0,0 +1,236 @@
++/*
++ * Copyright (c) 2013-2014 Linaro Ltd.
++ * Copyright (c) 2015 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++/dts-v1/;
++#include "hisi-hi3556.dtsi"
++
++/ {
++	model = "Hisilicon HI3556 DEMO Board";
++	compatible = "hisilicon,hi3556";
++
++	cpus {
++		#address-cells = <1>;
++		#size-cells = <0>;
++		enable-method = "hisilicon,hi3556-smp";
++
++		cpu@0 {
++			compatible = "arm,cortex-a7";
++			device_type = "cpu";
++			clock-frequency = <HI3556_FIXED_792M>;
++			reg = <0>;
++			cci-control-port = <&cci_control0>;
++		};
++
++		/*cpu@100 {
++			compatible = "arm,cortex-a17";
++			device_type = "cpu";
++			clock-frequency = <HI3556_FIXED_1000M>;
++			reg = <0x100>;
++			cci-control-port = <&cci_control1>;
++		};*/
++	};
++
++	memory {
++		device_type = "memory";
++		reg = <0x80000000 0x40000000>;
++	};
++};
++
++&uart0 {
++	status = "okay";
++};
++
++&dual_timer0 {
++	status = "okay";
++};
++
++&i2c_bus0 {
++	status = "disabled";
++};
++
++&i2c_bus1 {
++	status = "disabled";
++};
++
++&i2c_bus2 {
++	status = "disabled";
++};
++
++&i2c_bus3 {
++	status = "okay";
++};
++
++&spi_bus0 {
++	status = "disabled";
++
++	spidev@0 {
++		compatible = "rohm,dh2228fv";
++		reg = <0>;
++		pl022,interface = <0>;
++		pl022,com-mode = <0>;
++		spi-max-frequency = <24750000>;
++	};
++
++};
++
++&spi_bus1 {
++	status = "disabled";
++
++	spidev@0 {
++		compatible = "rohm,dh2228fv";
++		reg = <0>;
++		pl022,interface = <0>;
++		pl022,com-mode = <0>;
++		spi-max-frequency = <24750000>;
++	};
++};
++
++&spi_bus2 {
++	status = "okay";
++
++	spidev@0 {
++		compatible = "rohm,dh2228fv";
++		reg = <0>;
++		pl022,interface = <0>;
++		pl022,com-mode = <0>;
++		spi-max-frequency = <24750000>;
++	};
++
++	spidev@1 {
++		compatible = "rohm,dh2228fv";
++		reg = <1>;
++		pl022,interface = <0>;
++		pl022,com-mode = <0>;
++		spi-max-frequency = <24750000>;
++	};
++};
++
++&spi_bus3 {
++	status = "disabled";
++
++	spidev@0 {
++		compatible = "rohm,dh2228fv";
++		reg = <0>;
++		pl022,interface = <0>;
++		pl022,com-mode = <0>;
++		spi-max-frequency = <24750000>;
++	};
++};
++
++&hisfc {
++	hi_sfc {
++		compatible = "jedec,spi-nor";
++		reg = <0>;
++		spi-max-frequency = <160000000>;
++		m25p,fast-read;
++	};
++
++};
++
++&hisnfc {
++	hinand {
++		compatible = "jedec,spi-nand";
++		reg = <0>;
++		spi-max-frequency = <160000000>;
++	};
++};
++
++&hinfc {
++	hinand {
++		compatible = "jedec,nand";
++		reg = <0>;
++		nand-max-frequency = <200000000>;
++	};
++};
++
++&mmc0 {
++	status = "okay";
++};
++
++&mmc1 {
++	status = "okay";
++};
++
++&mmc2 {
++	status = "disabled";
++};
++
++&gpio_chip0 {
++	status = "disabled";
++};
++
++&gpio_chip1 {
++	status = "disabled";
++};
++
++&gpio_chip2 {
++	status = "disabled";
++};
++
++&gpio_chip3 {
++	status = "disabled";
++};
++
++&gpio_chip4 {
++	status = "disabled";
++};
++
++&gpio_chip5 {
++	status = "disabled";
++};
++
++&gpio_chip6 {
++	status = "disabled";
++};
++
++&gpio_chip7 {
++	status = "disabled";
++};
++
++&gpio_chip8 {
++	status = "disabled";
++};
++
++&gpio_chip9 {
++	status = "disabled";
++};
++
++&gpio_chip10 {
++	status = "disabled";
++};
++
++&gpio_chip11 {
++	status = "disabled";
++};
++
++&gpio_chip12 {
++	status = "disabled";
++};
++
++&gpio_chip13 {
++	status = "disabled";
++};
++
++&gpio_chip14 {
++	status = "disabled";
++};
++
++&gpio_chip16 {
++	status = "disabled";
++};
+diff --git a/arch/arm/boot/dts/hisi-hi3556.dtsi b/arch/arm/boot/dts/hisi-hi3556.dtsi
+new file mode 100644
+index 0000000..4a92aa6
+--- /dev/null
++++ b/arch/arm/boot/dts/hisi-hi3556.dtsi
+@@ -0,0 +1,755 @@
++/*
++ * Copyright (c) 2013-2014 Linaro Ltd.
++ * Copyright (c) 2015 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include "skeleton.dtsi"
++#include <dt-bindings/clock/hi3556-clock.h>
++/ {
++	aliases {
++		serial0 = &uart0;
++		i2c0 = &i2c_bus0;
++		i2c1 = &i2c_bus1;
++		i2c2 = &i2c_bus2;
++		i2c3 = &i2c_bus3;
++		spi0 = &spi_bus0;
++		spi1 = &spi_bus1;
++		spi2 = &spi_bus2;
++		spi3 = &spi_bus3;
++		gpio0 = &gpio_chip0;
++		gpio1 = &gpio_chip1;
++		gpio2 = &gpio_chip2;
++		gpio3 = &gpio_chip3;
++		gpio4 = &gpio_chip4;
++		gpio5 = &gpio_chip5;
++		gpio6 = &gpio_chip6;
++		gpio7 = &gpio_chip7;
++		gpio8 = &gpio_chip8;
++		gpio9 = &gpio_chip9;
++		gpio10 = &gpio_chip10;
++		gpio11 = &gpio_chip11;
++		gpio12 = &gpio_chip12;
++		gpio13 = &gpio_chip13;
++		gpio14 = &gpio_chip14;
++		gpio16 = &gpio_chip16;
++	};
++
++	gic: interrupt-controller@10300000 {
++		compatible = "arm,cortex-a7-gic";
++		#interrupt-cells = <3>;
++		#address-cells = <0>;
++		interrupt-controller;
++		/* gic dist base, gic cpu base , no virtual support */
++		reg = <0x10301000 0x1000>, <0x10302000 0x1000>;
++	};
++
++	clock: clock0 {
++		compatible = "hisilicon,hi3556-clock";
++		#address-cells = <1>;
++		#size-cells = <1>;
++		#clock-cells = <1>;
++		#reset-cells = <2>;
++		reg = <0x12010000 0x10000>;
++	};
++
++	syscounter {
++		compatible = "arm,armv7-timer";
++		interrupt-parent = <&gic>;
++		interrupts = <1 13 0xf08>,
++			<1 14 0xf08>;
++		clock-frequency = <24000000>;
++	};
++
++	soc {
++		#address-cells = <1>;
++		#size-cells = <1>;
++		compatible = "simple-bus";
++		interrupt-parent = <&gic>;
++		ranges;
++
++		amba {
++			#address-cells = <1>;
++			#size-cells = <1>;
++			compatible = "arm,amba-bus";
++			ranges;
++
++			uart0: uart@12100000 {
++				compatible = "arm,pl011", "arm,primecell";
++				reg = <0x12100000 0x1000>;
++				interrupts = <0 4 4>;
++				clocks = <&clock HI3556_UART0_CLK>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++			};
++
++			uart1: uart@12101000 {
++				compatible = "arm,pl011", "arm,primecell";
++				reg = <0x12101000 0x1000>;
++				interrupts = <0 5 4>;
++				clocks = <&clock HI3556_UART1_CLK>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++			};
++
++			uart2: uart@12102000 {
++				compatible = "arm,pl011", "arm,primecell";
++				reg = <0x12102000 0x1000>;
++				interrupts = <0 6 4>;
++				clocks = <&clock HI3556_UART2_CLK>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++			};
++
++			uart3: uart@12103000 {
++				compatible = "arm,pl011", "arm,primecell";
++				reg = <0x12103000 0x1000>;
++				interrupts = <0 7 4>;
++				clocks = <&clock HI3556_UART3_CLK>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++			};
++
++			uart4: uart@12104000 {
++				compatible = "arm,pl011", "arm,primecell";
++				reg = <0x12104000 0x1000>;
++				interrupts = <0 8 4>;
++				clocks = <&clock HI3556_UART4_CLK>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++			};
++
++			sys: sys@12010000 {
++				compatible = "hisilicon,hi35xx_sys";
++				reg = <0x12020000 0x10000>, <0x12060000 0x10000>, <0X12030000 0x10000>;
++				reg-names = "sys", "ddr", "misc";
++			};
++
++			mipi: mipi@11300000 {
++				compatible = "hisilicon,hi35xx_mipi";
++				interrupts = <0 28 4>, <0 29 4>;
++				interrupt-names = "mipi0", "mipi1";
++				reg = <0x11300000 0x10000>;
++			};
++
++			isp: isp@11380000 {
++				compatible = "hisilicon,hi35xx_isp";
++				interrupts = <0 30 4>, <0 31 4>;
++				interrupt-names = "isp0", "isp1";
++			};
++
++			viu: viu@11380000 {
++				compatible = "hisilicon,hi35xx_viu";
++				interrupts = <0 30 4>, <0 31 4>;
++				interrupt-names = "viu0", "viu1";
++				reg = <0x11380000 0x70000>, <0x11480000 0x70000>;
++				reg-names = "viu0", "viu1";
++			};
++
++			vou: vou@11000000 {
++				compatible = "hisilicon,hi35xx_vou";
++				interrupts = <0 27 4>;
++				reg = <0x11000000 0x20000>;
++			};
++
++			tde: tde@11100000 {
++				compatible = "hisilicon,hi35xx_tde";
++				interrupts = <0 34 4>;
++				reg = <0x11100000 0x10000>;
++			};
++
++			fisheye: fisheye@11110000 {
++				compatible = "hisilicon,hi35xx_fisheye";
++				interrupts = <0 48 4>;
++				reg = <0x11110000 0x10000>;
++			};
++
++			vgs: vgs@11120000 {
++				compatible = "hisilicon,hi35xx_vgs";
++				interrupts = <0 35 4>;
++				reg = <0x11120000 0x10000>;
++			};
++
++			vpss: vpss@11180000 {
++				compatible = "hisilicon,hi35xx_vpss";
++				interrupts = <0 32 4>;
++				reg = <0x11180000 0x10000>;
++			};
++
++			vedu: vedu@11280000 {
++					compatible = "hisilicon,hi35xx_vedu";
++					interrupts = <0 37 4>;
++					reg = <0x11280000 0x10000>;
++			};
++
++			jpege: jpege@11200000 {
++					compatible = "hisilicon,hi35xx_jpege";
++					interrupts = <0 38 4>;
++					reg = <0x11200000 0x10000>;
++			};
++
++			aiao: aiao@11080000 {
++				compatible = "hisilicon,hi35xx_aiao";
++				interrupts = <0 36 4>;
++				reg = <0x11080000 0x3000>;
++			};
++
++			ive: ive@11040000 {
++				compatible = "hisilicon,hi35xx_ive";
++				interrupts = <0 39 4>;
++				reg = <0x11040000 0x10000>;
++			};
++
++			fd: fd@11060000 {
++				compatible = "hisilicon,hi35xx_fd";
++				interrupts = <0 40 4>;
++				reg = <0x11060000 0x10000>;
++			};
++
++			pwm: pwm@12130000 {
++				compatible = "hisilicon,pwm";
++				reg = <0x12130000 0x10000>;
++			};
++
++			piris: piris@12145000 {
++				compatible = "hisilicon,piris";
++				reg = <0x12145000 0x1000>;
++			};
++
++			wtdg: wtdg@12080000 {
++				compatible = "hisilicon,hi_wdg";
++				reg = <0x12080000 0x10000>;
++				reg-names = "wtdg";
++			};
++
++			rtc: rtc@12090000 {
++				compatible = "hisilicon,hi_rtc";
++				interrupts = <0 1 4>;
++				reg = <0x12090000 0x8000>;
++			};
++
++			pwr: wtdg@12098000 {
++				compatible = "hisilicon,hi_pwr";
++				reg = <0x12098000 0x8000>;
++				reg-names = "pwr";
++			};
++
++			ir: ir@120f0000{
++				compatible = "hisilicon,hi_ir";
++				interrupts = <0 15 4>;
++				reg = <0x120f0000 0x10000>;
++			};
++
++			pm {
++				compatible = "hisilicon,hibvt-pm";
++				reg = <0x12020000 0x1000>, <0x12000000 0x1000>;
++			};
++
++			pm_hibernate {
++				compatible = "hisilicon,hibvt-pm-hibernate";
++				reg = <0x12020000 0x1000>;
++			};
++
++			dual_timer0: dual_timer@12000000 {
++				compatible = "arm,sp804";
++				/* timer0 & timer1 */
++				interrupts = <0 64 4>, <0 65 4>;
++				reg = <0x12000000 0x1000>;
++				clocks = <&clock HI3556_FIXED_3M>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++			};
++
++			dual_timer1: dual_timer@12001000 {
++				compatible = "arm,sp804";
++				/* timer2 & timer3 */
++				interrupts = <0 66 4>, <0 67 4>;
++				reg = <0x12001000 0x1000>;
++				clocks = <&clock HI3556_FIXED_3M>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++			};
++
++			dual_timer2: dual_timer@12002000 {
++				compatible = "arm,sp804";
++				/* timer4 & timer5 */
++				interrupts = <0 68 4>, <0 69 4>;
++				reg = <0x12002000 0x1000>;
++				clocks = <&clock HI3556_FIXED_3M>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++			};
++
++			i2c_bus0: i2c@12110000 {
++				compatible = "hisilicon,hisi-i2c-v110";
++				reg = <0x12110000 0x100>;
++				clocks = <&clock HI3556_I2C_MUX>;
++				clock-frequency = <100000>;
++				status = "disabled";
++			};
++
++			i2c_bus1: i2c@12111000 {
++				compatible = "hisilicon,hisi-i2c-v110";
++				reg = <0x12111000 0x100>;
++				clocks = <&clock HI3556_I2C_MUX>;
++				clock-frequency = <100000>;
++				status = "disabled";
++			};
++
++			i2c_bus2: i2c@12112000 {
++				compatible = "hisilicon,hisi-i2c-v110";
++				reg = <0x12112000 0x100>;
++				clocks = <&clock HI3556_I2C_MUX>;
++				clock-frequency = <100000>;
++				status = "disabled";
++			};
++
++			i2c_bus3: i2c@12113000 {
++				compatible = "hisilicon,hisi-i2c-v110";
++				reg = <0x12113000 0x100>;
++				clocks = <&clock HI3556_I2C_MUX>;
++				clock-frequency = <100000>;
++				status = "disabled";
++			};
++
++			spi_bus0: spi@12120000 {
++				compatible = "arm,pl022", "arm,primecell";
++				arm,primecell-periphid = <0x00800022>;
++				reg = <0x12120000 0x1000>;
++				interrupts = <0 9 4>;
++				clocks = <&clock HI3556_SPI0_CLK>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++				num-cs = <1>;
++				#address-cells = <1>;
++				#size-cells = <0>;
++			};
++
++			spi_bus1: spi@12121000 {
++				compatible = "arm,pl022", "arm,primecell";
++				arm,primecell-periphid = <0x00800022>;
++				reg = <0x12121000 0x1000>;
++				interrupts = <0 10 4>;
++				clocks = <&clock HI3556_SPI1_CLK>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++				num-cs = <1>;
++				#address-cells = <1>;
++				#size-cells = <0>;
++			};
++
++			spi_bus2: spi@12122000 {
++				compatible = "arm,pl022", "arm,primecell";
++				arm,primecell-periphid = <0x00800022>;
++				reg = <0x12122000 0x1000>, <0x12030004 0x4>;
++				interrupts = <0 11 4>;
++				clocks = <&clock HI3556_SPI2_CLK>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++				num-cs = <2>;
++				#address-cells = <1>;
++				#size-cells = <0>;
++				hisi,spi_cs_sb = <26>;
++				hisi,spi_cs_mask_bit = <0x0c000000>;
++			};
++
++			spi_bus3: spi@12123000 {
++				compatible = "arm,pl022", "arm,primecell";
++				arm,primecell-periphid = <0x00800022>;
++				reg = <0x12123000 0x1000>;
++				interrupts = <0 12 4>;
++				clocks = <&clock HI3556_SPI3_CLK>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++				num-cs = <1>;
++				#address-cells = <1>;
++				#size-cells = <0>;
++			};
++
++			gpio_chip0: gpio_chip@12140000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x12140000 0x1000>;
++				interrupts = <0 43 4>;
++				clocks = <&clock HI3556_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip1: gpio_chip@12141000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x12141000 0x1000>;
++				interrupts = <0 43 4>;
++				clocks = <&clock HI3556_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip2: gpio_chip@12142000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x12142000 0x1000>;
++				interrupts = <0 43 4>;
++				clocks = <&clock HI3556_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip3: gpio_chip@12143000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x12143000 0x1000>;
++				interrupts = <0 43 4>;
++				clocks = <&clock HI3556_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip4: gpio_chip@12144000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x12144000 0x1000>;
++				interrupts = <0 43 4>;
++				clocks = <&clock HI3556_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip5: gpio_chip@12145000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x12145000 0x1000>;
++				interrupts = <0 43 4>;
++				clocks = <&clock HI3556_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip6: gpio_chip@12146000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x12146000 0x1000>;
++				interrupts = <0 43 4>;
++				clocks = <&clock HI3556_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip7: gpio_chip@12147000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x12147000 0x1000>;
++				interrupts = <0 43 4>;
++				clocks = <&clock HI3556_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip8: gpio_chip@12148000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x12148000 0x1000>;
++				interrupts = <0 44 4>;
++				clocks = <&clock HI3556_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip9: gpio_chip@12149000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x12149000 0x1000>;
++				interrupts = <0 44 4>;
++				clocks = <&clock HI3556_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip10: gpio_chip@1214a000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x1214a000 0x1000>;
++				interrupts = <0 44 4>;
++				clocks = <&clock HI3556_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip11: gpio_chip@1214b000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x1214b000 0x1000>;
++				interrupts = <0 44 4>;
++				clocks = <&clock HI3556_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip12: gpio_chip@1214c000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x1214c000 0x1000>;
++				interrupts = <0 44 4>;
++				clocks = <&clock HI3556_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip13: gpio_chip@1214d000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x1214d000 0x1000>;
++				interrupts = <0 44 4>;
++				clocks = <&clock HI3556_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip14: gpio_chip@1214e000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x1214e000 0x1000>;
++				interrupts = <0 44 4>;
++				clocks = <&clock HI3556_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip16: gpio_chip@12150000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x12150000 0x1000>;
++				interrupts = <0 44 4>;
++				clocks = <&clock HI3556_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++		};
++
++		pmc@0x120a0000 {
++			compatible = "hisilicon,pmc";
++			reg = <0x120a0000 0x1000>;
++		};
++
++		sysctrl: system-controller@00000000 {
++			compatible = "hisilicon,sysctrl";
++			reg = <0x12020000 0x1000>;
++			reboot-offset = <0x4>;
++		};
++
++		usb_phy: phy {
++			compatible = "hisilicon,hisi-usb-phy";
++			reg = <0x12030000 0x10000>, <0x12010000 0x10000>;
++			#phy-cells = <0>;
++		};
++
++		usb3_phy: phy3 {
++			compatible = "hisilicon,hisi-usb3-phy";
++			reg = <0x10180000 0x10000>, <0x12010000 0x10000>,
++				<0x12030000 0x10000>;
++			#phy-cells = <0>;
++		};
++		ehci@0x10120000 {
++			 compatible = "generic-ehci";
++			 reg = <0x10120000 0x10000>;
++			 interrupts = <0 19 4>;
++
++			clocks = <&clock HI3556_USB2_CTRL_UTMI0_REQ>,
++					<&clock HI3556_USB2_HRST_REQ>;
++			clock-names = "usb2_cttl_utmi0_req",  "usb2_hrst_req";
++		 };
++
++		ohci@0x10110000 {
++			compatible = "generic-ohci";
++			reg = <0x10110000 0x10000>;
++			interrupts = <0 20 4>;
++
++			clocks = <&clock HI3556_USB2_CTRL_UTMI0_REQ>,
++					<&clock HI3556_USB2_HRST_REQ>;
++			clock-names = "usb2_cttl_utmi0_req", "usb2_hrst_req";
++		 };
++
++		 xhci@0x10180000 {
++			  compatible = "hisilicon,hi3556-xhci", "generic-xhci";
++			  reg = <0x10180000 0x10000>;
++			  interrupts = <0 22 4>;
++
++			  clocks = <&clock HI3556_USB3_CLK>;
++			  clock-names = "clk";
++		  };
++
++		 hiudc@0x10130000 {
++			 compatible = "hiudc";
++			 reg = <0x10130000 0x40000>;
++			 interrupts = <0 21 4>;
++
++			 clocks = <&clock HI3556_USB2_HRST_REQ>;
++			 clock-names = "clk";
++		 };
++
++		 hiudc3@0x10180000 {
++			 compatible = "dwc_usb3";
++			 reg = <0x10180000 0x40000>;
++			 interrupts = <0 22 4>;
++
++			 clocks = <&clock HI3556_USB3_CLK>;
++			 clock-names = "clk";
++		 };
++
++		cci: cci@1ff00000 {
++			compatible = "arm,cci-400";
++			#address-cells = <1>;
++			#size-cells = <1>;
++			reg = <0x1ff00000 0x1000>;
++			ranges = <0x0 0x1ff00000 0x6000>;
++
++			cci_control0: slave-if@4000 {
++				compatible = "arm,cci-400-ctrl-if";
++				interface-type = "ace";
++				reg = <0x2000 0x1000>;
++			};
++
++			cci_control1: slave-if@5000 {
++				compatible = "arm,cci-400-ctrl-if";
++				interface-type = "ace";
++				reg = <0x3000 0x1000>;
++			};
++
++		};
++
++		regulators@120a0000 {
++			compatible = "hi3556,regulators";
++			reg = <0x120a0000 0x1000>;
++			regulator-num = <2>;
++			regulator-name-array = "regulator-a17","regulator-media";
++
++			a17_regulator: a17_regulator{
++				regulator-name = "regulator-a17";
++				regulator-min-microvolt = <648633>;
++				regulator-max-microvolt = <1200525>;
++				regulator-always-on;
++				reg_offset = <0x4>;
++			};
++
++			media_regulator: media_regulator{
++				regulator-name = "regulator-media";
++				regulator-min-microvolt = <649740>;
++				regulator-max-microvolt = <1204331>;
++				regulator-always-on;
++				reg_offset = <0xC>;
++			};
++		};
++
++		pmu {
++			compatible = "arm,cortex-a7-pmu", "arm,cortex-a17-pmu";
++			interrupts = <0 45 4>,
++					<0 46 4>;
++		};
++
++		mmc2: himciv200.MMC@0x100e0000 {
++			compatible = "hisilicon,hi3556-himciv200";
++			reg = <0x100e0000 0x10000>;
++			interrupts = <0 13 4>;
++
++			clocks = <&clock HI3556_MMC2_CLK>;
++			clock-names = "mmc_clk";
++
++			bus-width = <8>;
++			max-frequency = <148500000>;
++			cap-mmc-highspeed;
++			cap-mmc-hw-reset;
++			full-pwr-cycle;
++			mmc-hs400-1_8v;
++			devid = <2>;
++			status = "disabled";
++		};
++
++		mmc0: himciv200.SD@0x100c0000 {
++			compatible = "hisilicon,hi3556-himciv200";
++			reg = <0x100c0000 0x10000>;
++			interrupts = <0 23 4>;
++
++			clocks = <&clock HI3556_MMC0_CLK>;
++			clock-names = "mmc_clk";
++
++			bus-width = <4>;
++			max-frequency = <148500000>;
++			cap-mmc-highspeed;
++			cap-sd-highspeed;
++			sd-uhs-sdr12;
++			sd-uhs-sdr25;
++			sd-uhs-sdr50;
++			sd-uhs-sdr104;
++			devid = <0>;
++			status = "disabled";
++		};
++
++		mmc1: himciv200.SD@0x100d0000 {
++			compatible = "hisilicon,hi3556-himciv200";
++			reg = <0x100d0000 0x10000>;
++			interrupts = <0 24 4>;
++
++			clocks = <&clock HI3556_MMC1_CLK>;
++			clock-names = "mmc_clk";
++
++			bus-width = <4>;
++			max-frequency = <148500000>;
++			cap-mmc-highspeed;
++			cap-sd-highspeed;
++			sd-uhs-sdr12;
++			sd-uhs-sdr25;
++			sd-uhs-sdr50;
++			sd-uhs-sdr104;
++			devid = <1>;
++			status = "disabled";
++		};
++
++		fmc: spi-nor-controller@10000000 {
++			compatible = "hisilicon,hisi-fmc";
++			reg = <0x10000000 0x1000>, <0x14000000 0x1000000>;
++			reg-names = "control", "memory";
++			clocks = <&clock HI3556_FMC_CLK>;
++			#address-cells = <1>;
++			#size-cells = <0>;
++
++			hisfc:spi-nor@0 {
++				compatible = "hisilicon,hisi-sfc";
++				assigned-clocks = <&clock HI3556_FMC_CLK>;
++				assigned-clock-rates = <24000000>;
++				#address-cells = <1>;
++				#size-cells = <0>;
++			};
++
++			hisnfc:spi-nand@0 {
++				compatible = "hisilicon,hisi-spi-nand";
++				assigned-clocks = <&clock HI3556_FMC_CLK>;
++				assigned-clock-rates = <24000000>;
++				#address-cells = <1>;
++				#size-cells = <0>;
++			};
++
++			hinfc:nand@0 {
++				compatible = "hisilicon,hisi-nand";
++				assigned-clocks = <&clock HI3556_FMC_CLK>;
++				assigned-clock-rates = <200000000>;
++				#address-cells = <1>;
++				#size-cells = <0>;
++			};
++		};
++	};
++
++};
+diff --git a/arch/arm/boot/dts/hisi-hi3559-demb.dts b/arch/arm/boot/dts/hisi-hi3559-demb.dts
+new file mode 100644
+index 0000000..0fa7209
+--- /dev/null
++++ b/arch/arm/boot/dts/hisi-hi3559-demb.dts
+@@ -0,0 +1,236 @@
++/*
++ * Copyright (c) 2013-2014 Linaro Ltd.
++ * Copyright (c) 2015 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++/dts-v1/;
++#include "hisi-hi3559.dtsi"
++
++/ {
++	model = "Hisilicon HI3559 DEMO Board";
++	compatible = "hisilicon,hi3559";
++
++	cpus {
++		#address-cells = <1>;
++		#size-cells = <0>;
++		enable-method = "hisilicon,hi3559-smp";
++
++		cpu@0 {
++			compatible = "arm,cortex-a7";
++			device_type = "cpu";
++			clock-frequency = <HI3559_FIXED_792M>;
++			reg = <0>;
++			cci-control-port = <&cci_control0>;
++		};
++
++		/*cpu@100 {
++			compatible = "arm,cortex-a17";
++			device_type = "cpu";
++			clock-frequency = <HI3559_FIXED_1000M>;
++			reg = <0x100>;
++			cci-control-port = <&cci_control1>;
++		};*/
++	};
++
++	memory {
++		device_type = "memory";
++		reg = <0x80000000 0x40000000>;
++	};
++};
++
++&uart0 {
++	status = "okay";
++};
++
++&dual_timer0 {
++	status = "okay";
++};
++
++&i2c_bus0 {
++	status = "disabled";
++};
++
++&i2c_bus1 {
++	status = "disabled";
++};
++
++&i2c_bus2 {
++	status = "disabled";
++};
++
++&i2c_bus3 {
++	status = "okay";
++};
++
++&spi_bus0 {
++	status = "disabled";
++
++	spidev@0 {
++		compatible = "rohm,dh2228fv";
++		reg = <0>;
++		pl022,interface = <0>;
++		pl022,com-mode = <0>;
++		spi-max-frequency = <24750000>;
++	};
++
++};
++
++&spi_bus1 {
++	status = "disabled";
++
++	spidev@0 {
++		compatible = "rohm,dh2228fv";
++		reg = <0>;
++		pl022,interface = <0>;
++		pl022,com-mode = <0>;
++		spi-max-frequency = <24750000>;
++	};
++};
++
++&spi_bus2 {
++	status = "okay";
++
++	spidev@0 {
++		compatible = "rohm,dh2228fv";
++		reg = <0>;
++		pl022,interface = <0>;
++		pl022,com-mode = <0>;
++		spi-max-frequency = <24750000>;
++	};
++
++	spidev@1 {
++		compatible = "rohm,dh2228fv";
++		reg = <1>;
++		pl022,interface = <0>;
++		pl022,com-mode = <0>;
++		spi-max-frequency = <24750000>;
++	};
++};
++
++&spi_bus3 {
++	status = "disabled";
++
++	spidev@0 {
++		compatible = "rohm,dh2228fv";
++		reg = <0>;
++		pl022,interface = <0>;
++		pl022,com-mode = <0>;
++		spi-max-frequency = <24750000>;
++	};
++};
++
++&hisfc {
++	hi_sfc {
++		compatible = "jedec,spi-nor";
++		reg = <0>;
++		spi-max-frequency = <160000000>;
++		m25p,fast-read;
++	};
++
++};
++
++&hisnfc {
++	hinand {
++		compatible = "jedec,spi-nand";
++		reg = <0>;
++		spi-max-frequency = <160000000>;
++	};
++};
++
++&hinfc {
++	hinand {
++		compatible = "jedec,nand";
++		reg = <0>;
++		nand-max-frequency = <200000000>;
++	};
++};
++
++&mmc0 {
++	status = "okay";
++};
++
++&mmc1 {
++	status = "okay";
++};
++
++&mmc2 {
++	status = "disabled";
++};
++
++&gpio_chip0 {
++	status = "disabled";
++};
++
++&gpio_chip1 {
++	status = "disabled";
++};
++
++&gpio_chip2 {
++	status = "disabled";
++};
++
++&gpio_chip3 {
++	status = "disabled";
++};
++
++&gpio_chip4 {
++	status = "disabled";
++};
++
++&gpio_chip5 {
++	status = "disabled";
++};
++
++&gpio_chip6 {
++	status = "disabled";
++};
++
++&gpio_chip7 {
++	status = "disabled";
++};
++
++&gpio_chip8 {
++	status = "disabled";
++};
++
++&gpio_chip9 {
++	status = "disabled";
++};
++
++&gpio_chip10 {
++	status = "disabled";
++};
++
++&gpio_chip11 {
++	status = "disabled";
++};
++
++&gpio_chip12 {
++	status = "disabled";
++};
++
++&gpio_chip13 {
++	status = "disabled";
++};
++
++&gpio_chip14 {
++	status = "disabled";
++};
++
++&gpio_chip16 {
++	status = "disabled";
++};
+diff --git a/arch/arm/boot/dts/hisi-hi3559.dtsi b/arch/arm/boot/dts/hisi-hi3559.dtsi
+new file mode 100644
+index 0000000..58b6d8c
+--- /dev/null
++++ b/arch/arm/boot/dts/hisi-hi3559.dtsi
+@@ -0,0 +1,755 @@
++/*
++ * Copyright (c) 2013-2014 Linaro Ltd.
++ * Copyright (c) 2015 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include "skeleton.dtsi"
++#include <dt-bindings/clock/hi3559-clock.h>
++/ {
++	aliases {
++		serial0 = &uart0;
++		i2c0 = &i2c_bus0;
++		i2c1 = &i2c_bus1;
++		i2c2 = &i2c_bus2;
++		i2c3 = &i2c_bus3;
++		spi0 = &spi_bus0;
++		spi1 = &spi_bus1;
++		spi2 = &spi_bus2;
++		spi3 = &spi_bus3;
++		gpio0 = &gpio_chip0;
++		gpio1 = &gpio_chip1;
++		gpio2 = &gpio_chip2;
++		gpio3 = &gpio_chip3;
++		gpio4 = &gpio_chip4;
++		gpio5 = &gpio_chip5;
++		gpio6 = &gpio_chip6;
++		gpio7 = &gpio_chip7;
++		gpio8 = &gpio_chip8;
++		gpio9 = &gpio_chip9;
++		gpio10 = &gpio_chip10;
++		gpio11 = &gpio_chip11;
++		gpio12 = &gpio_chip12;
++		gpio13 = &gpio_chip13;
++		gpio14 = &gpio_chip14;
++		gpio16 = &gpio_chip16;
++	};
++
++	gic: interrupt-controller@10300000 {
++		compatible = "arm,cortex-a7-gic";
++		#interrupt-cells = <3>;
++		#address-cells = <0>;
++		interrupt-controller;
++		/* gic dist base, gic cpu base , no virtual support */
++		reg = <0x10301000 0x1000>, <0x10302000 0x1000>;
++	};
++
++	clock: clock0 {
++		compatible = "hisilicon,hi3559-clock";
++		#address-cells = <1>;
++		#size-cells = <1>;
++		#clock-cells = <1>;
++		#reset-cells = <2>;
++		reg = <0x12010000 0x10000>;
++	};
++
++	syscounter {
++		compatible = "arm,armv7-timer";
++		interrupt-parent = <&gic>;
++		interrupts = <1 13 0xf08>,
++			<1 14 0xf08>;
++		clock-frequency = <24000000>;
++	};
++
++	soc {
++		#address-cells = <1>;
++		#size-cells = <1>;
++		compatible = "simple-bus";
++		interrupt-parent = <&gic>;
++		ranges;
++
++		amba {
++			#address-cells = <1>;
++			#size-cells = <1>;
++			compatible = "arm,amba-bus";
++			ranges;
++
++			uart0: uart@12100000 {
++				compatible = "arm,pl011", "arm,primecell";
++				reg = <0x12100000 0x1000>;
++				interrupts = <0 4 4>;
++				clocks = <&clock HI3559_UART0_CLK>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++			};
++
++			uart1: uart@12101000 {
++				compatible = "arm,pl011", "arm,primecell";
++				reg = <0x12101000 0x1000>;
++				interrupts = <0 5 4>;
++				clocks = <&clock HI3559_UART1_CLK>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++			};
++
++			uart2: uart@12102000 {
++				compatible = "arm,pl011", "arm,primecell";
++				reg = <0x12102000 0x1000>;
++				interrupts = <0 6 4>;
++				clocks = <&clock HI3559_UART2_CLK>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++			};
++
++			uart3: uart@12103000 {
++				compatible = "arm,pl011", "arm,primecell";
++				reg = <0x12103000 0x1000>;
++				interrupts = <0 7 4>;
++				clocks = <&clock HI3559_UART3_CLK>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++			};
++
++			uart4: uart@12104000 {
++				compatible = "arm,pl011", "arm,primecell";
++				reg = <0x12104000 0x1000>;
++				interrupts = <0 8 4>;
++				clocks = <&clock HI3559_UART4_CLK>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++			};
++
++			sys: sys@12010000 {
++				compatible = "hisilicon,hi35xx_sys";
++				reg = <0x12020000 0x10000>, <0x12060000 0x10000>, <0X12030000 0x10000>;
++				reg-names = "sys", "ddr", "misc";
++			};
++
++			mipi: mipi@11300000 {
++				compatible = "hisilicon,hi35xx_mipi";
++				interrupts = <0 28 4>, <0 29 4>;
++				interrupt-names = "mipi0", "mipi1";
++				reg = <0x11300000 0x10000>;
++			};
++
++			isp: isp@11380000 {
++				compatible = "hisilicon,hi35xx_isp";
++				interrupts = <0 30 4>, <0 31 4>;
++				interrupt-names = "isp0", "isp1";
++			};
++
++			viu: viu@11380000 {
++				compatible = "hisilicon,hi35xx_viu";
++				interrupts = <0 30 4>, <0 31 4>;
++				interrupt-names = "viu0", "viu1";
++				reg = <0x11380000 0x70000>, <0x11480000 0x70000>;
++				reg-names = "viu0", "viu1";
++			};
++
++			vou: vou@11000000 {
++				compatible = "hisilicon,hi35xx_vou";
++				interrupts = <0 27 4>;
++				reg = <0x11000000 0x20000>;
++			};
++
++			tde: tde@11100000 {
++				compatible = "hisilicon,hi35xx_tde";
++				interrupts = <0 34 4>;
++				reg = <0x11100000 0x10000>;
++			};
++
++			fisheye: fisheye@11110000 {
++				compatible = "hisilicon,hi35xx_fisheye";
++				interrupts = <0 48 4>;
++				reg = <0x11110000 0x10000>;
++			};
++
++			vgs: vgs@11120000 {
++				compatible = "hisilicon,hi35xx_vgs";
++				interrupts = <0 35 4>;
++				reg = <0x11120000 0x10000>;
++			};
++
++			vpss: vpss@11180000 {
++				compatible = "hisilicon,hi35xx_vpss";
++				interrupts = <0 32 4>;
++				reg = <0x11180000 0x10000>;
++			};
++
++			vedu: vedu@11280000 {
++					compatible = "hisilicon,hi35xx_vedu";
++					interrupts = <0 37 4>;
++					reg = <0x11280000 0x10000>;
++			};
++
++			jpege: jpege@11200000 {
++					compatible = "hisilicon,hi35xx_jpege";
++					interrupts = <0 38 4>;
++					reg = <0x11200000 0x10000>;
++			};
++
++			aiao: aiao@11080000 {
++				compatible = "hisilicon,hi35xx_aiao";
++				interrupts = <0 36 4>;
++				reg = <0x11080000 0x3000>;
++			};
++
++			ive: ive@11040000 {
++				compatible = "hisilicon,hi35xx_ive";
++				interrupts = <0 39 4>;
++				reg = <0x11040000 0x10000>;
++			};
++
++			fd: fd@11060000 {
++				compatible = "hisilicon,hi35xx_fd";
++				interrupts = <0 40 4>;
++				reg = <0x11060000 0x10000>;
++			};
++
++			pwm: pwm@12130000 {
++				compatible = "hisilicon,pwm";
++				reg = <0x12130000 0x10000>;
++			};
++
++			piris: piris@12145000 {
++				compatible = "hisilicon,piris";
++				reg = <0x12145000 0x1000>;
++			};
++
++			wtdg: wtdg@12080000 {
++				compatible = "hisilicon,hi_wdg";
++				reg = <0x12080000 0x10000>;
++				reg-names = "wtdg";
++			};
++
++			rtc: rtc@12090000 {
++				compatible = "hisilicon,hi_rtc";
++				interrupts = <0 1 4>;
++				reg = <0x12090000 0x8000>;
++			};
++
++			pwr: wtdg@12098000 {
++				compatible = "hisilicon,hi_pwr";
++				reg = <0x12098000 0x8000>;
++				reg-names = "pwr";
++			};
++
++			ir: ir@120f0000{
++				compatible = "hisilicon,hi_ir";
++				interrupts = <0 15 4>;
++				reg = <0x120f0000 0x10000>;
++			};
++
++			pm {
++				compatible = "hisilicon,hibvt-pm";
++				reg = <0x12020000 0x1000>, <0x12000000 0x1000>;
++			};
++
++			pm_hibernate {
++				compatible = "hisilicon,hibvt-pm-hibernate";
++				reg = <0x12020000 0x1000>;
++			};
++
++			dual_timer0: dual_timer@12000000 {
++				compatible = "arm,sp804";
++				/* timer0 & timer1 */
++				interrupts = <0 64 4>, <0 65 4>;
++				reg = <0x12000000 0x1000>;
++				clocks = <&clock HI3559_FIXED_3M>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++			};
++
++			dual_timer1: dual_timer@12001000 {
++				compatible = "arm,sp804";
++				/* timer2 & timer3 */
++				interrupts = <0 66 4>, <0 67 4>;
++				reg = <0x12001000 0x1000>;
++				clocks = <&clock HI3559_FIXED_3M>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++			};
++
++			dual_timer2: dual_timer@12002000 {
++				compatible = "arm,sp804";
++				/* timer4 & timer5 */
++				interrupts = <0 68 4>, <0 69 4>;
++				reg = <0x12002000 0x1000>;
++				clocks = <&clock HI3559_FIXED_3M>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++			};
++
++			i2c_bus0: i2c@12110000 {
++				compatible = "hisilicon,hisi-i2c-v110";
++				reg = <0x12110000 0x100>;
++				clocks = <&clock HI3559_I2C_MUX>;
++				clock-frequency = <100000>;
++				status = "disabled";
++			};
++
++			i2c_bus1: i2c@12111000 {
++				compatible = "hisilicon,hisi-i2c-v110";
++				reg = <0x12111000 0x100>;
++				clocks = <&clock HI3559_I2C_MUX>;
++				clock-frequency = <100000>;
++				status = "disabled";
++			};
++
++			i2c_bus2: i2c@12112000 {
++				compatible = "hisilicon,hisi-i2c-v110";
++				reg = <0x12112000 0x100>;
++				clocks = <&clock HI3559_I2C_MUX>;
++				clock-frequency = <100000>;
++				status = "disabled";
++			};
++
++			i2c_bus3: i2c@12113000 {
++				compatible = "hisilicon,hisi-i2c-v110";
++				reg = <0x12113000 0x100>;
++				clocks = <&clock HI3559_I2C_MUX>;
++				clock-frequency = <100000>;
++				status = "disabled";
++			};
++
++			spi_bus0: spi@12120000 {
++				compatible = "arm,pl022", "arm,primecell";
++				arm,primecell-periphid = <0x00800022>;
++				reg = <0x12120000 0x1000>;
++				interrupts = <0 9 4>;
++				clocks = <&clock HI3559_SPI0_CLK>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++				num-cs = <1>;
++				#address-cells = <1>;
++				#size-cells = <0>;
++			};
++
++			spi_bus1: spi@12121000 {
++				compatible = "arm,pl022", "arm,primecell";
++				arm,primecell-periphid = <0x00800022>;
++				reg = <0x12121000 0x1000>;
++				interrupts = <0 10 4>;
++				clocks = <&clock HI3559_SPI1_CLK>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++				num-cs = <1>;
++				#address-cells = <1>;
++				#size-cells = <0>;
++			};
++
++			spi_bus2: spi@12122000 {
++				compatible = "arm,pl022", "arm,primecell";
++				arm,primecell-periphid = <0x00800022>;
++				reg = <0x12122000 0x1000>, <0x12030004 0x4>;
++				interrupts = <0 11 4>;
++				clocks = <&clock HI3559_SPI2_CLK>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++				num-cs = <2>;
++				#address-cells = <1>;
++				#size-cells = <0>;
++				hisi,spi_cs_sb = <26>;
++				hisi,spi_cs_mask_bit = <0x0c000000>;
++			};
++
++			spi_bus3: spi@12123000 {
++				compatible = "arm,pl022", "arm,primecell";
++				arm,primecell-periphid = <0x00800022>;
++				reg = <0x12123000 0x1000>;
++				interrupts = <0 12 4>;
++				clocks = <&clock HI3559_SPI3_CLK>;
++				clock-names = "apb_pclk";
++				status = "disabled";
++				num-cs = <1>;
++				#address-cells = <1>;
++				#size-cells = <0>;
++			};
++
++			gpio_chip0: gpio_chip@12140000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x12140000 0x1000>;
++				interrupts = <0 43 4>;
++				clocks = <&clock HI3559_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip1: gpio_chip@12141000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x12141000 0x1000>;
++				interrupts = <0 43 4>;
++				clocks = <&clock HI3559_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip2: gpio_chip@12142000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x12142000 0x1000>;
++				interrupts = <0 43 4>;
++				clocks = <&clock HI3559_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip3: gpio_chip@12143000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x12143000 0x1000>;
++				interrupts = <0 43 4>;
++				clocks = <&clock HI3559_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip4: gpio_chip@12144000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x12144000 0x1000>;
++				interrupts = <0 43 4>;
++				clocks = <&clock HI3559_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip5: gpio_chip@12145000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x12145000 0x1000>;
++				interrupts = <0 43 4>;
++				clocks = <&clock HI3559_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip6: gpio_chip@12146000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x12146000 0x1000>;
++				interrupts = <0 43 4>;
++				clocks = <&clock HI3559_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip7: gpio_chip@12147000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x12147000 0x1000>;
++				interrupts = <0 43 4>;
++				clocks = <&clock HI3559_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip8: gpio_chip@12148000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x12148000 0x1000>;
++				interrupts = <0 44 4>;
++				clocks = <&clock HI3559_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip9: gpio_chip@12149000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x12149000 0x1000>;
++				interrupts = <0 44 4>;
++				clocks = <&clock HI3559_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip10: gpio_chip@1214a000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x1214a000 0x1000>;
++				interrupts = <0 44 4>;
++				clocks = <&clock HI3559_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip11: gpio_chip@1214b000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x1214b000 0x1000>;
++				interrupts = <0 44 4>;
++				clocks = <&clock HI3559_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip12: gpio_chip@1214c000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x1214c000 0x1000>;
++				interrupts = <0 44 4>;
++				clocks = <&clock HI3559_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip13: gpio_chip@1214d000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x1214d000 0x1000>;
++				interrupts = <0 44 4>;
++				clocks = <&clock HI3559_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip14: gpio_chip@1214e000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x1214e000 0x1000>;
++				interrupts = <0 44 4>;
++				clocks = <&clock HI3559_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++
++			gpio_chip16: gpio_chip@12150000 {
++				compatible = "arm,pl061", "arm,primecell";
++				reg = <0x12150000 0x1000>;
++				interrupts = <0 44 4>;
++				clocks = <&clock HI3559_SYSAPB_CLK>;
++				clock-names = "apb_pclk";
++				#gpio-cells = <2>;
++				status = "disabled";
++			};
++		};
++
++		pmc@0x120a0000 {
++			compatible = "hisilicon,pmc";
++			reg = <0x120a0000 0x1000>;
++		};
++
++		sysctrl: system-controller@00000000 {
++			compatible = "hisilicon,sysctrl";
++			reg = <0x12020000 0x1000>;
++			reboot-offset = <0x4>;
++		};
++
++		usb_phy: phy {
++			compatible = "hisilicon,hisi-usb-phy";
++			reg = <0x12030000 0x10000>, <0x12010000 0x10000>;
++			#phy-cells = <0>;
++		};
++
++		usb3_phy: phy3 {
++			compatible = "hisilicon,hisi-usb3-phy";
++			reg = <0x10180000 0x10000>, <0x12010000 0x10000>,
++				<0x12030000 0x10000>;
++			#phy-cells = <0>;
++		};
++		ehci@0x10120000 {
++			 compatible = "generic-ehci";
++			 reg = <0x10120000 0x10000>;
++			 interrupts = <0 19 4>;
++
++			clocks = <&clock HI3559_USB2_CTRL_UTMI0_REQ>,
++					<&clock HI3559_USB2_HRST_REQ>;
++			clock-names = "usb2_cttl_utmi0_req",  "usb2_hrst_req";
++		 };
++
++		ohci@0x10110000 {
++			compatible = "generic-ohci";
++			reg = <0x10110000 0x10000>;
++			interrupts = <0 20 4>;
++
++			clocks = <&clock HI3559_USB2_CTRL_UTMI0_REQ>,
++					<&clock HI3559_USB2_HRST_REQ>;
++			clock-names = "usb2_cttl_utmi0_req", "usb2_hrst_req";
++		 };
++
++		 xhci@0x10180000 {
++			  compatible = "hisilicon,hi3559-xhci", "generic-xhci";
++			  reg = <0x10180000 0x10000>;
++			  interrupts = <0 22 4>;
++
++			  clocks = <&clock HI3559_USB3_CLK>;
++			  clock-names = "clk";
++		  };
++
++		 hiudc@0x10130000 {
++			 compatible = "hiudc";
++			 reg = <0x10130000 0x40000>;
++			 interrupts = <0 21 4>;
++
++			 clocks = <&clock HI3559_USB2_HRST_REQ>;
++			 clock-names = "clk";
++		 };
++
++		 hiudc3@0x10180000 {
++			 compatible = "dwc_usb3";
++			 reg = <0x10180000 0x40000>;
++			 interrupts = <0 22 4>;
++
++			 clocks = <&clock HI3559_USB3_CLK>;
++			 clock-names = "clk";
++		 };
++
++		cci: cci@1ff00000 {
++			compatible = "arm,cci-400";
++			#address-cells = <1>;
++			#size-cells = <1>;
++			reg = <0x1ff00000 0x1000>;
++			ranges = <0x0 0x1ff00000 0x6000>;
++
++			cci_control0: slave-if@4000 {
++				compatible = "arm,cci-400-ctrl-if";
++				interface-type = "ace";
++				reg = <0x2000 0x1000>;
++			};
++
++			cci_control1: slave-if@5000 {
++				compatible = "arm,cci-400-ctrl-if";
++				interface-type = "ace";
++				reg = <0x3000 0x1000>;
++			};
++
++		};
++
++		regulators@120a0000 {
++			compatible = "hi3559,regulators";
++			reg = <0x120a0000 0x1000>;
++			regulator-num = <2>;
++			regulator-name-array = "regulator-a17","regulator-media";
++
++			a17_regulator: a17_regulator{
++				regulator-name = "regulator-a17";
++				regulator-min-microvolt = <648633>;
++				regulator-max-microvolt = <1200525>;
++				regulator-always-on;
++				reg_offset = <0x4>;
++			};
++
++			media_regulator: media_regulator{
++				regulator-name = "regulator-media";
++				regulator-min-microvolt = <649740>;
++				regulator-max-microvolt = <1204331>;
++				regulator-always-on;
++				reg_offset = <0xC>;
++			};
++		};
++
++		pmu {
++			compatible = "arm,cortex-a7-pmu", "arm,cortex-a17-pmu";
++			interrupts = <0 45 4>,
++					<0 46 4>;
++		};
++
++		mmc2: himciv200.MMC@0x100e0000 {
++			compatible = "hisilicon,hi3559-himciv200";
++			reg = <0x100e0000 0x10000>;
++			interrupts = <0 13 4>;
++
++			clocks = <&clock HI3559_MMC2_CLK>;
++			clock-names = "mmc_clk";
++
++			bus-width = <8>;
++			max-frequency = <148500000>;
++			cap-mmc-highspeed;
++			cap-mmc-hw-reset;
++			full-pwr-cycle;
++			mmc-hs400-1_8v;
++			devid = <2>;
++			status = "disabled";
++		};
++
++		mmc0: himciv200.SD@0x100c0000 {
++			compatible = "hisilicon,hi3559-himciv200";
++			reg = <0x100c0000 0x10000>;
++			interrupts = <0 23 4>;
++
++			clocks = <&clock HI3559_MMC0_CLK>;
++			clock-names = "mmc_clk";
++
++			bus-width = <4>;
++			max-frequency = <148500000>;
++			cap-mmc-highspeed;
++			cap-sd-highspeed;
++			sd-uhs-sdr12;
++			sd-uhs-sdr25;
++			sd-uhs-sdr50;
++			sd-uhs-sdr104;
++			devid = <0>;
++			status = "disabled";
++		};
++
++		mmc1: himciv200.SD@0x100d0000 {
++			compatible = "hisilicon,hi3559-himciv200";
++			reg = <0x100d0000 0x10000>;
++			interrupts = <0 24 4>;
++
++			clocks = <&clock HI3559_MMC1_CLK>;
++			clock-names = "mmc_clk";
++
++			bus-width = <4>;
++			max-frequency = <148500000>;
++			cap-mmc-highspeed;
++			cap-sd-highspeed;
++			sd-uhs-sdr12;
++			sd-uhs-sdr25;
++			sd-uhs-sdr50;
++			sd-uhs-sdr104;
++			devid = <1>;
++			status = "disabled";
++		};
++
++		fmc: spi-nor-controller@10000000 {
++			compatible = "hisilicon,hisi-fmc";
++			reg = <0x10000000 0x1000>, <0x14000000 0x1000000>;
++			reg-names = "control", "memory";
++			clocks = <&clock HI3559_FMC_CLK>;
++			#address-cells = <1>;
++			#size-cells = <0>;
++
++			hisfc:spi-nor@0 {
++				compatible = "hisilicon,hisi-sfc";
++				assigned-clocks = <&clock HI3559_FMC_CLK>;
++				assigned-clock-rates = <24000000>;
++				#address-cells = <1>;
++				#size-cells = <0>;
++			};
++
++			hisnfc:spi-nand@0 {
++				compatible = "hisilicon,hisi-spi-nand";
++				assigned-clocks = <&clock HI3559_FMC_CLK>;
++				assigned-clock-rates = <24000000>;
++				#address-cells = <1>;
++				#size-cells = <0>;
++			};
++
++			hinfc:nand@0 {
++				compatible = "hisilicon,hisi-nand";
++				assigned-clocks = <&clock HI3559_FMC_CLK>;
++				assigned-clock-rates = <200000000>;
++				#address-cells = <1>;
++				#size-cells = <0>;
++			};
++		};
++	};
++
++};
+diff --git a/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts b/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts
+index 322fd15..7a2aeac 100644
+--- a/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts
++++ b/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts
+@@ -358,6 +358,204 @@
+ 		};
+ 	};
+ 
++	etb@0,20010000 {
++		compatible = "arm,coresight-etb10", "arm,primecell";
++		reg = <0 0x20010000 0 0x1000>;
++
++		clocks = <&oscclk6a>;
++		clock-names = "apb_pclk";
++		port {
++			etb_in_port: endpoint@0 {
++				slave-mode;
++				remote-endpoint = <&replicator_out_port0>;
++			};
++		};
++	};
++
++	tpiu@0,20030000 {
++		compatible = "arm,coresight-tpiu", "arm,primecell";
++		reg = <0 0x20030000 0 0x1000>;
++
++		clocks = <&oscclk6a>;
++		clock-names = "apb_pclk";
++		port {
++			tpiu_in_port: endpoint@0 {
++				slave-mode;
++				remote-endpoint = <&replicator_out_port1>;
++			};
++		};
++	};
++
++	replicator {
++		/* non-configurable replicators don't show up on the
++		 * AMBA bus.  As such no need to add "arm,primecell".
++		 */
++		compatible = "arm,coresight-replicator";
++
++		ports {
++			#address-cells = <1>;
++			#size-cells = <0>;
++
++			/* replicator output ports */
++			port@0 {
++				reg = <0>;
++				replicator_out_port0: endpoint {
++					remote-endpoint = <&etb_in_port>;
++				};
++			};
++
++			port@1 {
++				reg = <1>;
++				replicator_out_port1: endpoint {
++					remote-endpoint = <&tpiu_in_port>;
++				};
++			};
++
++			/* replicator input port */
++			port@2 {
++				reg = <0>;
++				replicator_in_port0: endpoint {
++					slave-mode;
++					remote-endpoint = <&funnel_out_port0>;
++				};
++			};
++		};
++	};
++
++	funnel@0,20040000 {
++		compatible = "arm,coresight-funnel", "arm,primecell";
++		reg = <0 0x20040000 0 0x1000>;
++
++		clocks = <&oscclk6a>;
++		clock-names = "apb_pclk";
++		ports {
++			#address-cells = <1>;
++			#size-cells = <0>;
++
++			/* funnel output port */
++			port@0 {
++				reg = <0>;
++				funnel_out_port0: endpoint {
++					remote-endpoint =
++						<&replicator_in_port0>;
++				};
++			};
++
++			/* funnel input ports */
++			port@1 {
++				reg = <0>;
++				funnel_in_port0: endpoint {
++					slave-mode;
++					remote-endpoint = <&ptm0_out_port>;
++				};
++			};
++
++			port@2 {
++				reg = <1>;
++				funnel_in_port1: endpoint {
++					slave-mode;
++					remote-endpoint = <&ptm1_out_port>;
++				};
++			};
++
++			port@3 {
++				reg = <2>;
++				funnel_in_port2: endpoint {
++					slave-mode;
++					remote-endpoint = <&etm0_out_port>;
++				};
++			};
++
++			/* Input port #3 is for ITM, not supported here */
++
++			port@4 {
++				reg = <4>;
++				funnel_in_port4: endpoint {
++					slave-mode;
++					remote-endpoint = <&etm1_out_port>;
++				};
++			};
++
++			port@5 {
++				reg = <5>;
++				funnel_in_port5: endpoint {
++					slave-mode;
++					remote-endpoint = <&etm2_out_port>;
++				};
++			};
++		};
++	};
++
++	ptm@0,2201c000 {
++		compatible = "arm,coresight-etm3x", "arm,primecell";
++		reg = <0 0x2201c000 0 0x1000>;
++
++		cpu = <&cpu0>;
++		clocks = <&oscclk6a>;
++		clock-names = "apb_pclk";
++		port {
++			ptm0_out_port: endpoint {
++				remote-endpoint = <&funnel_in_port0>;
++			};
++		};
++	};
++
++	ptm@0,2201d000 {
++		compatible = "arm,coresight-etm3x", "arm,primecell";
++		reg = <0 0x2201d000 0 0x1000>;
++
++		cpu = <&cpu1>;
++		clocks = <&oscclk6a>;
++		clock-names = "apb_pclk";
++		port {
++			ptm1_out_port: endpoint {
++				remote-endpoint = <&funnel_in_port1>;
++			};
++		};
++	};
++
++	etm@0,2203c000 {
++		compatible = "arm,coresight-etm3x", "arm,primecell";
++		reg = <0 0x2203c000 0 0x1000>;
++
++		cpu = <&cpu2>;
++		clocks = <&oscclk6a>;
++		clock-names = "apb_pclk";
++		port {
++			etm0_out_port: endpoint {
++				remote-endpoint = <&funnel_in_port2>;
++			};
++		};
++	};
++
++	etm@0,2203d000 {
++		compatible = "arm,coresight-etm3x", "arm,primecell";
++		reg = <0 0x2203d000 0 0x1000>;
++
++		cpu = <&cpu3>;
++		clocks = <&oscclk6a>;
++		clock-names = "apb_pclk";
++		port {
++			etm1_out_port: endpoint {
++				remote-endpoint = <&funnel_in_port4>;
++			};
++		};
++	};
++
++	etm@0,2203e000 {
++		compatible = "arm,coresight-etm3x", "arm,primecell";
++		reg = <0 0x2203e000 0 0x1000>;
++
++		cpu = <&cpu4>;
++		clocks = <&oscclk6a>;
++		clock-names = "apb_pclk";
++		port {
++			etm2_out_port: endpoint {
++				remote-endpoint = <&funnel_in_port5>;
++			};
++		};
++	};
++
+ 	smb {
+ 		compatible = "simple-bus";
+ 
+diff --git a/arch/arm/common/Kconfig b/arch/arm/common/Kconfig
+index c3a4e9c..f4a38a7 100644
+--- a/arch/arm/common/Kconfig
++++ b/arch/arm/common/Kconfig
+@@ -20,3 +20,7 @@ config SHARP_SCOOP
+ 
+ config TI_PRIV_EDMA
+ 	bool
++
++config FIQ_GLUE
++	bool
++	select FIQ
+diff --git a/arch/arm/common/Makefile b/arch/arm/common/Makefile
+index 70b1eff..5748afd 100644
+--- a/arch/arm/common/Makefile
++++ b/arch/arm/common/Makefile
+@@ -4,6 +4,7 @@
+ 
+ obj-y				+= firmware.o
+ 
++obj-$(CONFIG_FIQ_GLUE)		+= fiq_glue.o fiq_glue_setup.o
+ obj-$(CONFIG_ICST)		+= icst.o
+ obj-$(CONFIG_SA1111)		+= sa1111.o
+ obj-$(CONFIG_DMABOUNCE)		+= dmabounce.o
+diff --git a/arch/arm/common/fiq_glue.S b/arch/arm/common/fiq_glue.S
+new file mode 100644
+index 0000000..24b42ce
+--- /dev/null
++++ b/arch/arm/common/fiq_glue.S
+@@ -0,0 +1,118 @@
++/*
++ * Copyright (C) 2008 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#include <linux/linkage.h>
++#include <asm/assembler.h>
++
++		.text
++
++		.global fiq_glue_end
++
++		/* fiq stack: r0-r15,cpsr,spsr of interrupted mode */
++
++ENTRY(fiq_glue)
++		/* store pc, cpsr from previous mode, reserve space for spsr */
++		mrs	r12, spsr
++		sub	lr, lr, #4
++		subs	r10, #1
++		bne	nested_fiq
++
++		str	r12, [sp, #-8]!
++		str	lr, [sp, #-4]!
++
++		/* store r8-r14 from previous mode */
++		sub	sp, sp, #(7 * 4)
++		stmia	sp, {r8-r14}^
++		nop
++
++		/* store r0-r7 from previous mode */
++		stmfd	sp!, {r0-r7}
++
++		/* setup func(data,regs) arguments */
++		mov	r0, r9
++		mov	r1, sp
++		mov	r3, r8
++
++		mov	r7, sp
++
++		/* Get sp and lr from non-user modes */
++		and	r4, r12, #MODE_MASK
++		cmp	r4, #USR_MODE
++		beq	fiq_from_usr_mode
++
++		mov	r7, sp
++		orr	r4, r4, #(PSR_I_BIT | PSR_F_BIT)
++		msr	cpsr_c, r4
++		str	sp, [r7, #(4 * 13)]
++		str	lr, [r7, #(4 * 14)]
++		mrs	r5, spsr
++		str	r5, [r7, #(4 * 17)]
++
++		cmp	r4, #(SVC_MODE | PSR_I_BIT | PSR_F_BIT)
++		/* use fiq stack if we reenter this mode */
++		subne	sp, r7, #(4 * 3)
++
++fiq_from_usr_mode:
++		msr	cpsr_c, #(SVC_MODE | PSR_I_BIT | PSR_F_BIT)
++		mov	r2, sp
++		sub	sp, r7, #12
++		stmfd	sp!, {r2, ip, lr}
++		/* call func(data,regs) */
++		blx	r3
++		ldmfd	sp, {r2, ip, lr}
++		mov	sp, r2
++
++		/* restore/discard saved state */
++		cmp	r4, #USR_MODE
++		beq	fiq_from_usr_mode_exit
++
++		msr	cpsr_c, r4
++		ldr	sp, [r7, #(4 * 13)]
++		ldr	lr, [r7, #(4 * 14)]
++		msr	spsr_cxsf, r5
++
++fiq_from_usr_mode_exit:
++		msr	cpsr_c, #(FIQ_MODE | PSR_I_BIT | PSR_F_BIT)
++
++		ldmfd	sp!, {r0-r7}
++		ldr	lr, [sp, #(4 * 7)]
++		ldr	r12, [sp, #(4 * 8)]
++		add	sp, sp, #(10 * 4)
++exit_fiq:
++		msr	spsr_cxsf, r12
++		add	r10, #1
++		cmp	r11, #0
++		moveqs	pc, lr
++		bx	r11 /* jump to custom fiq return function */
++
++nested_fiq:
++		orr	r12, r12, #(PSR_F_BIT)
++		b	exit_fiq
++
++fiq_glue_end:
++
++ENTRY(fiq_glue_setup) /* func, data, sp, smc call number */
++		stmfd		sp!, {r4}
++		mrs		r4, cpsr
++		msr		cpsr_c, #(FIQ_MODE | PSR_I_BIT | PSR_F_BIT)
++		movs		r8, r0
++		mov		r9, r1
++		mov		sp, r2
++		mov		r11, r3
++		moveq		r10, #0
++		movne		r10, #1
++		msr		cpsr_c, r4
++		ldmfd		sp!, {r4}
++		bx		lr
++
+diff --git a/arch/arm/common/fiq_glue_setup.c b/arch/arm/common/fiq_glue_setup.c
+new file mode 100644
+index 0000000..8cb1b61
+--- /dev/null
++++ b/arch/arm/common/fiq_glue_setup.c
+@@ -0,0 +1,147 @@
++/*
++ * Copyright (C) 2010 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/kernel.h>
++#include <linux/percpu.h>
++#include <linux/slab.h>
++#include <asm/fiq.h>
++#include <asm/fiq_glue.h>
++
++extern unsigned char fiq_glue, fiq_glue_end;
++extern void fiq_glue_setup(void *func, void *data, void *sp,
++			   fiq_return_handler_t fiq_return_handler);
++
++static struct fiq_handler fiq_debbuger_fiq_handler = {
++	.name = "fiq_glue",
++};
++DEFINE_PER_CPU(void *, fiq_stack);
++static struct fiq_glue_handler *current_handler;
++static fiq_return_handler_t fiq_return_handler;
++static DEFINE_MUTEX(fiq_glue_lock);
++
++static void fiq_glue_setup_helper(void *info)
++{
++	struct fiq_glue_handler *handler = info;
++	fiq_glue_setup(handler->fiq, handler,
++		__get_cpu_var(fiq_stack) + THREAD_START_SP,
++		fiq_return_handler);
++}
++
++int fiq_glue_register_handler(struct fiq_glue_handler *handler)
++{
++	int ret;
++	int cpu;
++
++	if (!handler || !handler->fiq)
++		return -EINVAL;
++
++	mutex_lock(&fiq_glue_lock);
++	if (fiq_stack) {
++		ret = -EBUSY;
++		goto err_busy;
++	}
++
++	for_each_possible_cpu(cpu) {
++		void *stack;
++		stack = (void *)__get_free_pages(GFP_KERNEL, THREAD_SIZE_ORDER);
++		if (WARN_ON(!stack)) {
++			ret = -ENOMEM;
++			goto err_alloc_fiq_stack;
++		}
++		per_cpu(fiq_stack, cpu) = stack;
++	}
++
++	ret = claim_fiq(&fiq_debbuger_fiq_handler);
++	if (WARN_ON(ret))
++		goto err_claim_fiq;
++
++	current_handler = handler;
++	on_each_cpu(fiq_glue_setup_helper, handler, true);
++	set_fiq_handler(&fiq_glue, &fiq_glue_end - &fiq_glue);
++
++	mutex_unlock(&fiq_glue_lock);
++	return 0;
++
++err_claim_fiq:
++err_alloc_fiq_stack:
++	for_each_possible_cpu(cpu) {
++		__free_pages(per_cpu(fiq_stack, cpu), THREAD_SIZE_ORDER);
++		per_cpu(fiq_stack, cpu) = NULL;
++	}
++err_busy:
++	mutex_unlock(&fiq_glue_lock);
++	return ret;
++}
++
++static void fiq_glue_update_return_handler(void (*fiq_return)(void))
++{
++	fiq_return_handler = fiq_return;
++	if (current_handler)
++		on_each_cpu(fiq_glue_setup_helper, current_handler, true);
++}
++
++int fiq_glue_set_return_handler(void (*fiq_return)(void))
++{
++	int ret;
++
++	mutex_lock(&fiq_glue_lock);
++	if (fiq_return_handler) {
++		ret = -EBUSY;
++		goto err_busy;
++	}
++	fiq_glue_update_return_handler(fiq_return);
++	ret = 0;
++err_busy:
++	mutex_unlock(&fiq_glue_lock);
++
++	return ret;
++}
++EXPORT_SYMBOL(fiq_glue_set_return_handler);
++
++int fiq_glue_clear_return_handler(void (*fiq_return)(void))
++{
++	int ret;
++
++	mutex_lock(&fiq_glue_lock);
++	if (WARN_ON(fiq_return_handler != fiq_return)) {
++		ret = -EINVAL;
++		goto err_inval;
++	}
++	fiq_glue_update_return_handler(NULL);
++	ret = 0;
++err_inval:
++	mutex_unlock(&fiq_glue_lock);
++
++	return ret;
++}
++EXPORT_SYMBOL(fiq_glue_clear_return_handler);
++
++/**
++ * fiq_glue_resume - Restore fiqs after suspend or low power idle states
++ *
++ * This must be called before calling local_fiq_enable after returning from a
++ * power state where the fiq mode registers were lost. If a driver provided
++ * a resume hook when it registered the handler it will be called.
++ */
++
++void fiq_glue_resume(void)
++{
++	if (!current_handler)
++		return;
++	fiq_glue_setup(current_handler->fiq, current_handler,
++		__get_cpu_var(fiq_stack) + THREAD_START_SP,
++		fiq_return_handler);
++	if (current_handler->resume)
++		current_handler->resume(current_handler);
++}
++
+diff --git a/arch/arm/common/timer-sp.c b/arch/arm/common/timer-sp.c
+index 1921132..687bafe 100644
+--- a/arch/arm/common/timer-sp.c
++++ b/arch/arm/common/timer-sp.c
+@@ -226,6 +226,10 @@ static void __init sp804_of_init(struct device_node *np)
+ 	writel(0, base + TIMER_CTRL);
+ 	writel(0, base + TIMER_2_BASE + TIMER_CTRL);
+ 
++	/* Ensure timer interrupts are clear */
++	writel(1, base + TIMER_INTCLR);
++	writel(1, base + TIMER_2_BASE + TIMER_INTCLR);
++
+ 	if (initialized || !of_device_is_available(np))
+ 		goto err;
+ 
+diff --git a/arch/arm/configs/hi3516av200_big_little_defconfig b/arch/arm/configs/hi3516av200_big_little_defconfig
+new file mode 100644
+index 0000000..afed80c
+--- /dev/null
++++ b/arch/arm/configs/hi3516av200_big_little_defconfig
+@@ -0,0 +1,2599 @@
++#
++# Automatically generated file; DO NOT EDIT.
++# Linux/arm 3.18.20 Kernel Configuration
++#
++CONFIG_ARM=y
++CONFIG_ARM_HAS_SG_CHAIN=y
++CONFIG_MIGHT_HAVE_PCI=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=y
++CONFIG_HAVE_PROC_CPU=y
++CONFIG_STACKTRACE_SUPPORT=y
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
++CONFIG_RWSEM_XCHGADD_ALGORITHM=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_NEED_DMA_MAP_STATE=y
++CONFIG_ARCH_SUPPORTS_UPROBES=y
++CONFIG_VECTORS_BASE=0xffff0000
++CONFIG_ARM_PATCH_PHYS_VIRT=y
++CONFIG_GENERIC_BUG=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++CONFIG_IRQ_WORK=y
++CONFIG_BUILDTIME_EXTABLE_SORT=y
++
++#
++# General setup
++#
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_CROSS_COMPILE=""
++# CONFIG_COMPILE_TEST is not set
++CONFIG_LOCALVERSION=""
++# CONFIG_LOCALVERSION_AUTO is not set
++CONFIG_HAVE_KERNEL_GZIP=y
++CONFIG_HAVE_KERNEL_LZMA=y
++CONFIG_HAVE_KERNEL_XZ=y
++CONFIG_HAVE_KERNEL_LZO=y
++CONFIG_HAVE_KERNEL_LZ4=y
++CONFIG_KERNEL_GZIP=y
++# CONFIG_KERNEL_LZMA is not set
++# CONFIG_KERNEL_XZ is not set
++# CONFIG_KERNEL_LZO is not set
++# CONFIG_KERNEL_LZ4 is not set
++CONFIG_DEFAULT_HOSTNAME="(none)"
++CONFIG_SWAP=y
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++# CONFIG_POSIX_MQUEUE is not set
++CONFIG_CROSS_MEMORY_ATTACH=y
++# CONFIG_FHANDLE is not set
++CONFIG_USELIB=y
++# CONFIG_AUDIT is not set
++CONFIG_HAVE_ARCH_AUDITSYSCALL=y
++
++#
++# IRQ subsystem
++#
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_GENERIC_IRQ_SHOW=y
++CONFIG_HARDIRQS_SW_RESEND=y
++CONFIG_IRQ_DOMAIN=y
++CONFIG_HANDLE_DOMAIN_IRQ=y
++CONFIG_IRQ_FORCED_THREADING=y
++CONFIG_SPARSE_IRQ=y
++CONFIG_GENERIC_CLOCKEVENTS=y
++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
++CONFIG_ARCH_HAS_TICK_BROADCAST=y
++CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
++
++#
++# Timers subsystem
++#
++CONFIG_TICK_ONESHOT=y
++CONFIG_NO_HZ_COMMON=y
++# CONFIG_HZ_PERIODIC is not set
++CONFIG_NO_HZ_IDLE=y
++# CONFIG_NO_HZ_FULL is not set
++CONFIG_NO_HZ=y
++# CONFIG_HIGH_RES_TIMERS is not set
++
++#
++# CPU/Task time and stats accounting
++#
++CONFIG_TICK_CPU_ACCOUNTING=y
++# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set
++# CONFIG_IRQ_TIME_ACCOUNTING is not set
++# CONFIG_BSD_PROCESS_ACCT is not set
++# CONFIG_TASKSTATS is not set
++
++#
++# RCU Subsystem
++#
++CONFIG_TREE_RCU=y
++# CONFIG_PREEMPT_RCU is not set
++# CONFIG_TASKS_RCU is not set
++CONFIG_RCU_STALL_COMMON=y
++# CONFIG_RCU_USER_QS is not set
++CONFIG_RCU_FANOUT=32
++CONFIG_RCU_FANOUT_LEAF=16
++# CONFIG_RCU_FANOUT_EXACT is not set
++# CONFIG_RCU_FAST_NO_HZ is not set
++# CONFIG_TREE_RCU_TRACE is not set
++# CONFIG_RCU_NOCB_CPU is not set
++# CONFIG_BUILD_BIN2C is not set
++# CONFIG_IKCONFIG is not set
++CONFIG_LOG_BUF_SHIFT=17
++CONFIG_LOG_CPU_MAX_BUF_SHIFT=12
++CONFIG_GENERIC_SCHED_CLOCK=y
++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_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_USER_NS is not set
++CONFIG_PID_NS=y
++CONFIG_NET_NS=y
++# 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=y
++CONFIG_RD_LZMA=y
++CONFIG_RD_XZ=y
++CONFIG_RD_LZO=y
++CONFIG_RD_LZ4=y
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++CONFIG_HAVE_UID16=y
++CONFIG_BPF=y
++# CONFIG_EXPERT is not set
++CONFIG_UID16=y
++# CONFIG_SGETMASK_SYSCALL is not set
++CONFIG_SYSFS_SYSCALL=y
++# CONFIG_SYSCTL_SYSCALL is not set
++CONFIG_KALLSYMS=y
++# CONFIG_KALLSYMS_ALL is not set
++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_BPF_SYSCALL is not set
++CONFIG_SHMEM=y
++CONFIG_AIO=y
++CONFIG_ADVISE_SYSCALLS=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_SLUB_CPU_PARTIAL=y
++# CONFIG_PROFILING is not set
++CONFIG_HAVE_OPROFILE=y
++# CONFIG_KPROBES is not set
++# CONFIG_JUMP_LABEL is not set
++# CONFIG_UPROBES is not set
++# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
++CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
++CONFIG_ARCH_USE_BUILTIN_BSWAP=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_GENERIC_SMP_IDLE_THREAD=y
++CONFIG_GENERIC_IDLE_POLL_SETUP=y
++CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
++CONFIG_HAVE_CLK=y
++CONFIG_HAVE_DMA_API_DEBUG=y
++CONFIG_HAVE_PERF_REGS=y
++CONFIG_HAVE_PERF_USER_STACK_DUMP=y
++CONFIG_HAVE_ARCH_JUMP_LABEL=y
++CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
++CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
++CONFIG_HAVE_CC_STACKPROTECTOR=y
++# CONFIG_CC_STACKPROTECTOR is not set
++CONFIG_CC_STACKPROTECTOR_NONE=y
++# CONFIG_CC_STACKPROTECTOR_REGULAR is not set
++# CONFIG_CC_STACKPROTECTOR_STRONG is not set
++CONFIG_HAVE_CONTEXT_TRACKING=y
++CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
++CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
++CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
++CONFIG_MODULES_USE_ELF_REL=y
++CONFIG_CLONE_BACKWARDS=y
++CONFIG_OLD_SIGSUSPEND3=y
++CONFIG_OLD_SIGACTION=y
++
++#
++# GCOV-based kernel profiling
++#
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_SLABINFO=y
++CONFIG_RT_MUTEXES=y
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++# CONFIG_MODULE_FORCE_LOAD is not set
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++# CONFIG_MODULE_SIG is not set
++# CONFIG_MODULE_COMPRESS is not set
++CONFIG_STOP_MACHINE=y
++CONFIG_BLOCK=y
++CONFIG_LBDAF=y
++CONFIG_BLK_DEV_BSG=y
++# CONFIG_BLK_DEV_BSGLIB is not set
++# CONFIG_BLK_DEV_INTEGRITY is not set
++CONFIG_BLK_CMDLINE_PARSER=y
++
++#
++# Partition Types
++#
++CONFIG_PARTITION_ADVANCED=y
++# CONFIG_ACORN_PARTITION is not set
++# CONFIG_AIX_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=y
++# CONFIG_SYSV68_PARTITION is not set
++CONFIG_CMDLINE_PARTITION=y
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++CONFIG_DEFAULT_DEADLINE=y
++# CONFIG_DEFAULT_CFQ is not set
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="deadline"
++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_ARCH_SUPPORTS_ATOMIC_RMW=y
++CONFIG_MUTEX_SPIN_ON_OWNER=y
++CONFIG_RWSEM_SPIN_ON_OWNER=y
++CONFIG_FREEZER=y
++
++#
++# System Type
++#
++CONFIG_MMU=y
++CONFIG_ARCH_MULTIPLATFORM=y
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_AT91 is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_GEMINI is not set
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_IOP13XX is not set
++# CONFIG_ARCH_IOP32X is not set
++# CONFIG_ARCH_IOP33X is not set
++# CONFIG_ARCH_IXP4XX is not set
++# CONFIG_ARCH_DOVE is not set
++# CONFIG_ARCH_MV78XX0 is not set
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_MMP is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_W90X900 is not set
++# CONFIG_ARCH_LPC32XX is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_MSM is not set
++# CONFIG_ARCH_SHMOBILE_LEGACY 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_DAVINCI is not set
++# CONFIG_ARCH_OMAP1 is not set
++
++#
++# Multiple platform selection
++#
++
++#
++# CPU Core family selection
++#
++# CONFIG_ARCH_MULTI_V6 is not set
++CONFIG_ARCH_MULTI_V7=y
++CONFIG_ARCH_MULTI_V6_V7=y
++# CONFIG_ARCH_MULTI_CPU_AUTO is not set
++# CONFIG_ARCH_VIRT is not set
++# CONFIG_ARCH_MVEBU is not set
++# CONFIG_ARCH_BCM is not set
++# CONFIG_ARCH_BERLIN is not set
++# CONFIG_ARCH_HIGHBANK is not set
++CONFIG_ARCH_HISI=y
++
++#
++# Hisilicon platform type
++#
++# CONFIG_ARCH_HI3xxx is not set
++# CONFIG_ARCH_HIP04 is not set
++# CONFIG_ARCH_HIX5HD2 is not set
++# CONFIG_ARCH_HI3519 is not set
++# CONFIG_ARCH_HI3519V101 is not set
++CONFIG_ARCH_HI3516AV200=y
++# CONFIG_ARCH_HI3559 is not set
++# CONFIG_ARCH_HI3556 is not set
++CONFIG_PMC=y
++# CONFIG_ARCH_HI3536C is not set
++# CONFIG_ARCH_KEYSTONE is not set
++# CONFIG_ARCH_MESON is not set
++# CONFIG_ARCH_MXC is not set
++# CONFIG_ARCH_MEDIATEK is not set
++
++#
++# TI OMAP/AM/DM/DRA Family
++#
++# CONFIG_ARCH_OMAP3 is not set
++# CONFIG_ARCH_OMAP4 is not set
++# CONFIG_SOC_OMAP5 is not set
++# CONFIG_SOC_AM33XX is not set
++# CONFIG_SOC_AM43XX is not set
++# CONFIG_SOC_DRA7XX is not set
++# CONFIG_ARCH_QCOM is not set
++# CONFIG_ARCH_ROCKCHIP is not set
++# CONFIG_ARCH_SOCFPGA is not set
++# CONFIG_PLAT_SPEAR is not set
++# CONFIG_ARCH_STI is not set
++# CONFIG_ARCH_S5PV210 is not set
++# CONFIG_ARCH_EXYNOS is not set
++# CONFIG_ARCH_SHMOBILE_MULTI is not set
++# CONFIG_ARCH_SUNXI is not set
++# CONFIG_ARCH_SIRF is not set
++# CONFIG_ARCH_TEGRA is not set
++# CONFIG_ARCH_U8500 is not set
++# CONFIG_ARCH_VEXPRESS is not set
++# CONFIG_ARCH_WM8850 is not set
++# CONFIG_ARCH_ZYNQ is not set
++CONFIG_ARM_TIMER_SP804=y
++
++#
++# Processor Type
++#
++CONFIG_CPU_V7=y
++CONFIG_CPU_32v6K=y
++CONFIG_CPU_32v7=y
++CONFIG_CPU_ABRT_EV7=y
++CONFIG_CPU_PABRT_V7=y
++CONFIG_CPU_CACHE_V7=y
++CONFIG_CPU_CACHE_VIPT=y
++CONFIG_CPU_COPY_V6=y
++CONFIG_CPU_TLB_V7=y
++CONFIG_CPU_HAS_ASID=y
++CONFIG_CPU_CP15=y
++CONFIG_CPU_CP15_MMU=y
++
++#
++# Processor Features
++#
++# CONFIG_ARM_LPAE is not set
++# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
++CONFIG_ARM_THUMB=y
++# CONFIG_ARM_THUMBEE is not set
++CONFIG_ARM_VIRT_EXT=y
++CONFIG_SWP_EMULATE=y
++# CONFIG_CPU_ICACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_DISABLE is not set
++# CONFIG_CPU_BPREDICT_DISABLE is not set
++CONFIG_KUSER_HELPERS=y
++CONFIG_MIGHT_HAVE_CACHE_L2X0=y
++# CONFIG_CACHE_L2X0 is not set
++CONFIG_ARM_L1_CACHE_SHIFT_6=y
++CONFIG_ARM_L1_CACHE_SHIFT=6
++CONFIG_ARM_DMA_MEM_BUFFERABLE=y
++CONFIG_MULTI_IRQ_HANDLER=y
++# CONFIG_ARM_ERRATA_430973 is not set
++# CONFIG_ARM_ERRATA_643719 is not set
++# CONFIG_ARM_ERRATA_720789 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_ARM_ERRATA_775420 is not set
++# CONFIG_ARM_ERRATA_798181 is not set
++# CONFIG_ARM_ERRATA_773022 is not set
++
++#
++# Bus support
++#
++CONFIG_ARM_AMBA=y
++# CONFIG_PCI is not set
++# 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=y
++# CONFIG_SCHED_SMT is not set
++CONFIG_DISABLE_CPU_SCHED_DOMAIN_BALANCE=y
++CONFIG_SCHED_HMP=y
++# CONFIG_SCHED_HMP_PRIO_FILTER is not set
++CONFIG_HMP_FAST_CPU_MASK=""
++CONFIG_HMP_SLOW_CPU_MASK=""
++CONFIG_HMP_VARIABLE_SCALE=y
++# CONFIG_HMP_FREQUENCY_INVARIANT_SCALE is not set
++# CONFIG_SCHED_HMP_LITTLE_PACKING is not set
++CONFIG_HAVE_ARM_ARCH_TIMER=y
++# CONFIG_MCPM is not set
++# CONFIG_BIG_LITTLE is not set
++CONFIG_VMSPLIT_3G=y
++# CONFIG_VMSPLIT_2G is not set
++# CONFIG_VMSPLIT_1G is not set
++CONFIG_PAGE_OFFSET=0xC0000000
++CONFIG_NR_CPUS=4
++CONFIG_HOTPLUG_CPU=y
++# CONFIG_ARM_PSCI is not set
++CONFIG_ARCH_NR_GPIO=0
++CONFIG_PREEMPT_NONE=y
++# CONFIG_PREEMPT_VOLUNTARY is not set
++# CONFIG_PREEMPT is not set
++CONFIG_HZ_FIXED=0
++CONFIG_HZ_100=y
++# CONFIG_HZ_200 is not set
++# CONFIG_HZ_250 is not set
++# CONFIG_HZ_300 is not set
++# CONFIG_HZ_500 is not set
++# CONFIG_HZ_1000 is not set
++CONFIG_HZ=100
++# CONFIG_SCHED_HRTICK is not set
++# CONFIG_THUMB2_KERNEL is not set
++CONFIG_AEABI=y
++# CONFIG_OABI_COMPAT is not set
++# 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_ARCH_WANT_GENERAL_HUGETLB=y
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_HAVE_MEMBLOCK=y
++CONFIG_NO_BOOTMEM=y
++CONFIG_MEMORY_ISOLATION=y
++# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=4
++CONFIG_COMPACTION=y
++CONFIG_MIGRATION=y
++# CONFIG_PHYS_ADDR_T_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_BOUNCE=y
++# CONFIG_KSM is not set
++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
++# CONFIG_CLEANCACHE is not set
++# CONFIG_FRONTSWAP is not set
++CONFIG_CMA=y
++# CONFIG_CMA_DEBUG is not set
++CONFIG_CMA_AREAS=7
++# CONFIG_ZPOOL is not set
++# CONFIG_ZBUD is not set
++# CONFIG_ZSMALLOC 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_SWIOTLB=y
++CONFIG_IOMMU_HELPER=y
++# CONFIG_XEN is not set
++# CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART is not set
++
++#
++# Boot options
++#
++CONFIG_USE_OF=y
++CONFIG_ATAGS=y
++# CONFIG_DEPRECATED_PARAM_STRUCT is not set
++# CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE is not set
++CONFIG_ZBOOT_ROM_TEXT=0
++CONFIG_ZBOOT_ROM_BSS=0
++CONFIG_ARM_APPENDED_DTB=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_KEXEC is not set
++# CONFIG_CRASH_DUMP is not set
++CONFIG_AUTO_ZRELADDR=y
++
++#
++# CPU Power Management
++#
++
++#
++# CPU Frequency scaling
++#
++CONFIG_CPU_FREQ=y
++CONFIG_CPU_FREQ_GOV_COMMON=y
++CONFIG_CPU_FREQ_STAT=y
++# CONFIG_CPU_FREQ_STAT_DETAILS is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
++CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
++# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE is not set
++CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
++CONFIG_CPU_FREQ_GOV_POWERSAVE=y
++CONFIG_CPU_FREQ_GOV_USERSPACE=y
++CONFIG_CPU_FREQ_GOV_ONDEMAND=y
++CONFIG_CPU_FREQ_GOV_INTERACTIVE=y
++CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
++CONFIG_CPUFREQ_DT=y
++
++#
++# ARM CPU frequency scaling drivers
++#
++# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set
++
++#
++# CPU Idle
++#
++CONFIG_CPU_IDLE=y
++CONFIG_CPU_IDLE_GOV_LADDER=y
++CONFIG_CPU_IDLE_GOV_MENU=y
++
++#
++# ARM CPU Idle Drivers
++#
++CONFIG_ARM_HI3516AV200_CPUIDLE=y
++# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++CONFIG_VFP=y
++CONFIG_VFPv3=y
++CONFIG_NEON=y
++CONFIG_KERNEL_MODE_NEON=y
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
++CONFIG_BINFMT_SCRIPT=y
++# CONFIG_HAVE_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
++CONFIG_COREDUMP=y
++
++#
++# Power management options
++#
++CONFIG_SUSPEND=y
++CONFIG_SUSPEND_FREEZER=y
++CONFIG_WAKELOCK=y
++CONFIG_HIBERNATE_CALLBACKS=y
++CONFIG_HISI_SNAPSHOT_BOOT=y
++# CONFIG_DEFAULT_MTD is not set
++CONFIG_DEFAULT_DDR=y
++CONFIG_SNAPSHOT_BUF_START=0x8a000000
++CONFIG_SNAPSHOT_BUF_SIZE=0x4000000
++CONFIG_HIBERNATION=y
++CONFIG_GZIP_COMPRESS=y
++CONFIG_PM_STD_PARTITION=""
++CONFIG_PM_SLEEP=y
++CONFIG_PM_SLEEP_SMP=y
++# CONFIG_PM_AUTOSLEEP is not set
++# CONFIG_PM_WAKELOCKS is not set
++# CONFIG_PM_RUNTIME is not set
++CONFIG_PM=y
++# CONFIG_PM_DEBUG is not set
++# CONFIG_APM_EMULATION is not set
++CONFIG_PM_OPP=y
++CONFIG_PM_CLK=y
++# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set
++CONFIG_CPU_PM=y
++# CONFIG_SUSPEND_TIME is not set
++CONFIG_ARCH_SUSPEND_POSSIBLE=y
++CONFIG_ARM_CPU_SUSPEND=y
++CONFIG_ARCH_HIBERNATION_POSSIBLE=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_NET_IP_TUNNEL=m
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_NET_IPVTI is not set
++# CONFIG_NET_UDP_TUNNEL is not set
++# CONFIG_NET_FOU is not set
++# CONFIG_GENEVE 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=y
++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=y
++# 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_VTI 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_ANDROID_PARANOID_NETWORK is not set
++CONFIG_NET_ACTIVITY_STATS=y
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NET_PTP_CLASSIFY 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_NF_TABLES is not set
++# CONFIG_NETFILTER_XTABLES is not set
++# CONFIG_IP_SET is not set
++# CONFIG_IP_VS is not set
++
++#
++# IP: Netfilter Configuration
++#
++# CONFIG_NF_DEFRAG_IPV4 is not set
++# CONFIG_NF_LOG_ARP is not set
++# CONFIG_NF_LOG_IPV4 is not set
++# CONFIG_NF_REJECT_IPV4 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_NF_REJECT_IPV6 is not set
++# CONFIG_NF_LOG_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_HAVE_NET_DSA=y
++# 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_PHONET is not set
++# CONFIG_6LOWPAN 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_VSOCKETS is not set
++# CONFIG_NETLINK_MMAP is not set
++# CONFIG_NETLINK_DIAG is not set
++# CONFIG_NET_MPLS_GSO is not set
++# CONFIG_HSR is not set
++CONFIG_RPS=y
++CONFIG_RFS_ACCEL=y
++CONFIG_XPS=y
++# CONFIG_CGROUP_NET_PRIO is not set
++# CONFIG_CGROUP_NET_CLASSID is not set
++CONFIG_NET_RX_BUSY_POLL=y
++CONFIG_BQL=y
++# CONFIG_BPF_JIT is not set
++CONFIG_NET_FLOW_LIMIT=y
++
++#
++# 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 is not set
++CONFIG_DEVTMPFS=y
++CONFIG_DEVTMPFS_MOUNT=y
++CONFIG_STANDALONE=y
++# CONFIG_PREVENT_FIRMWARE_BUILD is not set
++CONFIG_FW_LOADER=y
++# CONFIG_FIRMWARE_IN_KERNEL is not set
++CONFIG_EXTRA_FIRMWARE=""
++# CONFIG_FW_LOADER_USER_HELPER_FALLBACK is not set
++CONFIG_ALLOW_DEV_COREDUMP=y
++# 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_HAVE_CPU_AUTOPROBE is not set
++CONFIG_REGMAP=y
++CONFIG_REGMAP_MMIO=y
++# CONFIG_DMA_SHARED_BUFFER is not set
++CONFIG_DMA_CMA=y
++
++#
++# Default contiguous memory area size:
++#
++CONFIG_CMA_SIZE_MBYTES=16
++CONFIG_CMA_SIZE_SEL_MBYTES=y
++# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set
++# CONFIG_CMA_SIZE_SEL_MIN is not set
++# CONFIG_CMA_SIZE_SEL_MAX is not set
++CONFIG_CMA_ALIGNMENT=8
++
++#
++# Bus devices
++#
++# CONFIG_BRCMSTB_GISB_ARB is not set
++CONFIG_ARM_CCI=y
++# CONFIG_VEXPRESS_CONFIG 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=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_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
++CONFIG_HIFMC=y
++CONFIG_HIFMC_SPI_NAND=y
++# CONFIG_HIFMC_NAND is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++# CONFIG_MTD_CFI is not set
++# CONFIG_MTD_JEDECPROBE is not set
++CONFIG_MTD_MAP_BANK_WIDTH_1=y
++CONFIG_MTD_MAP_BANK_WIDTH_2=y
++CONFIG_MTD_MAP_BANK_WIDTH_4=y
++# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
++CONFIG_MTD_CFI_I1=y
++CONFIG_MTD_CFI_I2=y
++# CONFIG_MTD_CFI_I4 is not set
++# CONFIG_MTD_CFI_I8 is not set
++# CONFIG_MTD_RAM is not set
++# CONFIG_MTD_ROM is not set
++# CONFIG_MTD_ABSENT is not set
++
++#
++# Mapping drivers for chip access
++#
++# CONFIG_MTD_COMPLEX_MAPPINGS is not set
++# CONFIG_MTD_PLATRAM is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_DATAFLASH is not set
++# CONFIG_MTD_M25P80 is not set
++# CONFIG_MTD_SST25L is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_PHRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++# CONFIG_MTD_BLOCK2MTD is not set
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOCG3 is not set
++CONFIG_MTD_NAND_IDS=y
++CONFIG_MTD_NAND_ECC=y
++# CONFIG_MTD_NAND_ECC_SMC is not set
++CONFIG_MTD_NAND=y
++# CONFIG_MTD_NAND_ECC_BCH is not set
++# CONFIG_MTD_SM_COMMON is not set
++# CONFIG_MTD_NAND_DENALI is not set
++# CONFIG_MTD_NAND_GPIO is not set
++# CONFIG_MTD_NAND_OMAP_BCH_BUILD is not set
++# CONFIG_MTD_NAND_DISKONCHIP is not set
++# CONFIG_MTD_NAND_DOCG4 is not set
++# CONFIG_MTD_NAND_NANDSIM is not set
++# CONFIG_MTD_NAND_PLATFORM is not set
++# CONFIG_HISI_NAND_FS_MAY_NO_YAFFS2 is not set
++# CONFIG_HISI_NAND_ECC_STATUS_REPORT is not set
++# CONFIG_HIFMC100_NAND is not set
++CONFIG_HIFMC100_SPI_NAND=y
++CONFIG_SPI_NAND_MAX_CHIP_NUM=1
++# CONFIG_HIFMC100_HARDWARE_PAGESIZE_ECC is not set
++CONFIG_HIFMC100_AUTO_PAGESIZE_ECC=y
++# CONFIG_HIFMC100_PAGESIZE_AUTO_ECC_NONE is not set
++# CONFIG_MTD_ONENAND is not set
++
++#
++# LPDDR & LPDDR2 PCM memory drivers
++#
++# CONFIG_MTD_LPDDR is not set
++# CONFIG_MTD_LPDDR2_NVM is not set
++CONFIG_MTD_SPI_NOR=y
++# CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set
++CONFIG_SPI_HISI_SFC=y
++CONFIG_CLOSE_SPI_8PIN_4IO=y
++CONFIG_HISI_SPI_BLOCK_PROTECT=y
++# CONFIG_MTD_UBI is not set
++CONFIG_DTC=y
++CONFIG_OF=y
++
++#
++# Device Tree and Open Firmware support
++#
++# 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_NET=y
++CONFIG_OF_MDIO=y
++CONFIG_OF_MTD=y
++CONFIG_OF_RESERVED_MEM=y
++CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
++# CONFIG_PARPORT is not set
++CONFIG_BLK_DEV=y
++# CONFIG_BLK_DEV_NULL_BLK is not set
++# CONFIG_BLK_DEV_COW_COMMON is not set
++# CONFIG_BLK_DEV_LOOP 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=65536
++# 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_DUMMY_IRQ 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_UID_STAT is not set
++# CONFIG_BMP085_I2C is not set
++# CONFIG_BMP085_SPI is not set
++# CONFIG_USB_SWITCH_FSA9480 is not set
++# CONFIG_LATTICE_ECP3_CONFIG is not set
++# CONFIG_SRAM is not set
++# CONFIG_C2PORT is not set
++
++#
++# EEPROM support
++#
++# CONFIG_EEPROM_AT24 is not set
++# CONFIG_EEPROM_AT25 is not set
++# CONFIG_EEPROM_LEGACY is not set
++# CONFIG_EEPROM_MAX6875 is not set
++# CONFIG_EEPROM_93CX6 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
++
++#
++# Intel MIC Bus Driver
++#
++
++#
++# Intel MIC Host Driver
++#
++
++#
++# Intel MIC Card Driver
++#
++# CONFIG_ECHO is not set
++# CONFIG_CXL_BASE is not set
++
++#
++# hisi 'himm/himd.l/himc'support
++#
++CONFIG_HISI_REG=y
++
++#
++# SCSI device support
++#
++CONFIG_SCSI_MOD=y
++# CONFIG_RAID_ATTRS is not set
++CONFIG_SCSI=y
++CONFIG_SCSI_DMA=y
++# CONFIG_SCSI_NETLINK is not set
++# CONFIG_SCSI_MQ_DEFAULT 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_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 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_NET_CORE=y
++# CONFIG_BONDING is not set
++# CONFIG_DUMMY is not set
++# CONFIG_EQUALIZER is not set
++# CONFIG_NET_TEAM is not set
++# CONFIG_MACVLAN is not set
++# CONFIG_VXLAN is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_TUN is not set
++# CONFIG_VETH is not set
++# CONFIG_NLMON is not set
++
++#
++# 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_NET_DSA_MV88E6171 is not set
++# CONFIG_NET_DSA_BCM_SF2 is not set
++CONFIG_ETHERNET=y
++# CONFIG_ALTERA_TSE is not set
++# CONFIG_NET_XGENE is not set
++# CONFIG_NET_VENDOR_ARC is not set
++# CONFIG_NET_CADENCE is not set
++# CONFIG_NET_VENDOR_BROADCOM is not set
++# CONFIG_NET_VENDOR_CIRRUS is not set
++# CONFIG_DM9000 is not set
++# CONFIG_DNET is not set
++# CONFIG_NET_VENDOR_FARADAY is not set
++CONFIG_NET_VENDOR_HISILICON=y
++# CONFIG_HIX5HD2_GMAC is not set
++# CONFIG_HISI_FEMAC is not set
++CONFIG_HIETH_GMAC=y
++CONFIG_HIGMAC_DESC_4WORD=y
++CONFIG_HIGMAC_RXCSUM=y
++CONFIG_RX_FLOW_CTRL_SUPPORT=y
++CONFIG_TX_FLOW_CTRL_SUPPORT=y
++CONFIG_TX_FLOW_CTRL_PAUSE_TIME=0xFFFF
++CONFIG_TX_FLOW_CTRL_PAUSE_INTERVAL=0xFFFF
++CONFIG_TX_FLOW_CTRL_ACTIVE_THRESHOLD=16
++CONFIG_TX_FLOW_CTRL_DEACTIVE_THRESHOLD=32
++# CONFIG_HIETH_SWITCH_FABRIC is not set
++# CONFIG_NET_VENDOR_INTEL is not set
++# CONFIG_NET_VENDOR_MARVELL is not set
++# CONFIG_NET_VENDOR_MICREL is not set
++# CONFIG_NET_VENDOR_MICROCHIP is not set
++# CONFIG_NET_VENDOR_NATSEMI is not set
++# CONFIG_ETHOC is not set
++# CONFIG_NET_VENDOR_QUALCOMM is not set
++# CONFIG_NET_VENDOR_SAMSUNG is not set
++# CONFIG_NET_VENDOR_SEEQ is not set
++# CONFIG_NET_VENDOR_SMSC is not set
++# CONFIG_NET_VENDOR_STMICRO is not set
++# CONFIG_NET_VENDOR_VIA is not set
++# CONFIG_NET_VENDOR_WIZNET is not set
++CONFIG_PHYLIB=y
++
++#
++# MII PHY device drivers
++#
++# CONFIG_AT803X_PHY is not set
++# CONFIG_AMD_PHY is not set
++# CONFIG_AMD_XGBE_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 is not set
++# CONFIG_BROADCOM_PHY is not set
++# CONFIG_BCM7XXX_PHY is not set
++# CONFIG_BCM87XX_PHY is not set
++# CONFIG_ICPLUS_PHY is not set
++# CONFIG_REALTEK_PHY is not set
++# CONFIG_NATIONAL_PHY is not set
++# CONFIG_STE10XP is not set
++# CONFIG_LSI_ET1011C_PHY is not set
++# CONFIG_MICREL_PHY is not set
++# CONFIG_FIXED_PHY is not set
++# CONFIG_MDIO_BITBANG is not set
++# CONFIG_MDIO_BUS_MUX_GPIO is not set
++# CONFIG_MDIO_BUS_MUX_MMIOREG is not set
++# CONFIG_MDIO_BCM_UNIMAC is not set
++# CONFIG_MDIO_HISI_FEMAC is not set
++CONFIG_MDIO_HISI_GEMAC=y
++# CONFIG_MICREL_KS8995MA is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++CONFIG_USB_NET_DRIVERS=y
++# 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_RTL8152 is not set
++# CONFIG_USB_USBNET is not set
++# CONFIG_USB_IPHETH is not set
++# CONFIG_WLAN is not set
++
++#
++# Enable WiMAX (Networking options) to see the WiMAX drivers
++#
++# CONFIG_WAN is not set
++# CONFIG_ISDN is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
++# CONFIG_INPUT_POLLDEV is not set
++# CONFIG_INPUT_SPARSEKMAP is not set
++# CONFIG_INPUT_MATRIXKMAP is not set
++
++#
++# Userland interfaces
++#
++CONFIG_INPUT_MOUSEDEV=y
++CONFIG_INPUT_MOUSEDEV_PSAUX=y
++CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
++CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
++# CONFIG_INPUT_JOYDEV is not set
++CONFIG_INPUT_EVDEV=y
++# CONFIG_INPUT_EVBUG is not set
++# CONFIG_INPUT_KEYRESET is not set
++# CONFIG_INPUT_KEYCOMBO is not set
++
++#
++# Input Device Drivers
++#
++CONFIG_INPUT_KEYBOARD=y
++# CONFIG_KEYBOARD_ADP5588 is not set
++# CONFIG_KEYBOARD_ADP5589 is not set
++CONFIG_KEYBOARD_ATKBD=y
++# CONFIG_KEYBOARD_QT1070 is not set
++# CONFIG_KEYBOARD_QT2160 is not set
++# CONFIG_KEYBOARD_LKKBD is not set
++# CONFIG_KEYBOARD_GPIO is not set
++# CONFIG_KEYBOARD_GPIO_POLLED is not set
++# 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 is not set
++# CONFIG_KEYBOARD_CAP1106 is not set
++CONFIG_INPUT_MOUSE=y
++CONFIG_MOUSE_PS2=y
++CONFIG_MOUSE_PS2_ALPS=y
++CONFIG_MOUSE_PS2_LOGIPS2PP=y
++CONFIG_MOUSE_PS2_SYNAPTICS=y
++CONFIG_MOUSE_PS2_CYPRESS=y
++CONFIG_MOUSE_PS2_TRACKPOINT=y
++# CONFIG_MOUSE_PS2_ELANTECH is not set
++# CONFIG_MOUSE_PS2_SENTELIC is not set
++# CONFIG_MOUSE_PS2_TOUCHKIT is not set
++# CONFIG_MOUSE_SERIAL is not set
++# CONFIG_MOUSE_APPLETOUCH is not set
++# CONFIG_MOUSE_BCM5974 is not set
++# CONFIG_MOUSE_CYAPA is not set
++# CONFIG_MOUSE_VSXXXAA is not set
++# CONFIG_MOUSE_GPIO is not set
++# CONFIG_MOUSE_SYNAPTICS_I2C is not set
++# CONFIG_MOUSE_SYNAPTICS_USB is not set
++# CONFIG_INPUT_JOYSTICK is not set
++# CONFIG_INPUT_TABLET is not set
++# CONFIG_INPUT_TOUCHSCREEN is not set
++# CONFIG_INPUT_MISC is not set
++
++#
++# Hardware I/O ports
++#
++CONFIG_SERIO=y
++CONFIG_SERIO_SERPORT=y
++# CONFIG_SERIO_AMBAKMI is not set
++CONFIG_SERIO_LIBPS2=y
++# CONFIG_SERIO_RAW is not set
++# CONFIG_SERIO_ALTERA_PS2 is not set
++# CONFIG_SERIO_PS2MULT is not set
++# CONFIG_SERIO_ARC_PS2 is not set
++# CONFIG_SERIO_APBPS2 is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++CONFIG_TTY=y
++CONFIG_VT=y
++CONFIG_CONSOLE_TRANSLATIONS=y
++CONFIG_VT_CONSOLE=y
++CONFIG_VT_CONSOLE_SLEEP=y
++CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
++CONFIG_UNIX98_PTYS=y
++# CONFIG_DEVPTS_MULTIPLE_INSTANCES 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_DEVMEM=y
++CONFIG_DEVKMEM=y
++
++#
++# Serial drivers
++#
++CONFIG_SERIAL_EARLYCON=y
++# CONFIG_SERIAL_8250 is not set
++
++#
++# Non-8250 serial port support
++#
++# CONFIG_SERIAL_AMBA_PL010 is not set
++CONFIG_SERIAL_AMBA_PL011=y
++CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
++# CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST is not set
++# 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_SC16IS7XX is not set
++# CONFIG_SERIAL_ALTERA_JTAGUART is not set
++# CONFIG_SERIAL_ALTERA_UART is not set
++# CONFIG_SERIAL_IFX6X60 is not set
++# CONFIG_SERIAL_XILINX_PS_UART is not set
++# CONFIG_SERIAL_ARC is not set
++# CONFIG_SERIAL_FSL_LPUART is not set
++# CONFIG_SERIAL_ST_ASC is not set
++# CONFIG_HVC_DCC is not set
++# CONFIG_IPMI_HANDLER is not set
++# CONFIG_HW_RANDOM is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++# CONFIG_DCC_TTY is not set
++# CONFIG_XILLYBUS is not set
++
++#
++# I2C support
++#
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++# CONFIG_I2C_COMPAT is not set
++CONFIG_I2C_CHARDEV=y
++# CONFIG_I2C_MUX is not set
++# CONFIG_I2C_HELPER_AUTO is not set
++# CONFIG_I2C_SMBUS is not set
++
++#
++# I2C Algorithms
++#
++# CONFIG_I2C_ALGOBIT is not set
++# CONFIG_I2C_ALGOPCF is not set
++# CONFIG_I2C_ALGOPCA is not set
++
++#
++# I2C Hardware Bus support
++#
++
++#
++# I2C system bus drivers (mostly embedded / system-on-chip)
++#
++# CONFIG_I2C_CBUS_GPIO is not set
++# CONFIG_I2C_DESIGNWARE_PLATFORM is not set
++# CONFIG_I2C_GPIO is not set
++# CONFIG_I2C_HIBVT is not set
++CONFIG_I2C_HISI_V110=y
++# CONFIG_I2C_NOMADIK 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_RK3X 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_ROBOTFUZZ_OSIF 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_CADENCE is not set
++# CONFIG_SPI_GPIO is not set
++# CONFIG_SPI_FSL_SPI is not set
++# CONFIG_SPI_OC_TINY is not set
++CONFIG_SPI_PL022=y
++# CONFIG_SPI_PXA2XX_PCI is not set
++# CONFIG_SPI_ROCKCHIP 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=y
++# CONFIG_SPI_TLE62X0 is not set
++# CONFIG_SPMI is not set
++# CONFIG_HSI is not set
++
++#
++# PPS support
++#
++# CONFIG_PPS is not set
++
++#
++# PPS generators support
++#
++
++#
++# PTP clock support
++#
++# CONFIG_PTP_1588_CLOCK is not set
++
++#
++# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
++#
++CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
++CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
++CONFIG_GPIOLIB=y
++CONFIG_GPIO_DEVRES=y
++CONFIG_OF_GPIO=y
++CONFIG_GPIOLIB_IRQCHIP=y
++# CONFIG_DEBUG_GPIO is not set
++CONFIG_GPIO_SYSFS=y
++
++#
++# Memory mapped GPIO drivers:
++#
++# CONFIG_GPIO_GENERIC_PLATFORM is not set
++# CONFIG_GPIO_DWAPB is not set
++# CONFIG_GPIO_EM is not set
++# CONFIG_GPIO_ZEVIO is not set
++CONFIG_GPIO_PL061=y
++# CONFIG_GPIO_SCH311X is not set
++# CONFIG_GPIO_SYSCON is not set
++# CONFIG_GPIO_GRGPIO is not set
++
++#
++# I2C GPIO expanders:
++#
++# CONFIG_GPIO_MAX7300 is not set
++# CONFIG_GPIO_MAX732X is not set
++# CONFIG_GPIO_PCA953X is not set
++# CONFIG_GPIO_PCF857X is not set
++# CONFIG_GPIO_SX150X is not set
++# CONFIG_GPIO_ADP5588 is not set
++# CONFIG_GPIO_ADNP is not set
++
++#
++# PCI GPIO expanders:
++#
++
++#
++# SPI GPIO expanders:
++#
++# CONFIG_GPIO_MAX7301 is not set
++# CONFIG_GPIO_MCP23S08 is not set
++# CONFIG_GPIO_MC33880 is not set
++# CONFIG_GPIO_74X164 is not set
++
++#
++# AC97 GPIO expanders:
++#
++
++#
++# LPC GPIO expanders:
++#
++
++#
++# MODULbus GPIO expanders:
++#
++
++#
++# USB GPIO expanders:
++#
++# CONFIG_W1 is not set
++CONFIG_POWER_SUPPLY=y
++# CONFIG_POWER_SUPPLY_DEBUG is not set
++# CONFIG_PDA_POWER is not set
++# CONFIG_TEST_POWER is not set
++# CONFIG_BATTERY_DS2780 is not set
++# CONFIG_BATTERY_DS2781 is not set
++# CONFIG_BATTERY_DS2782 is not set
++# CONFIG_BATTERY_SBS is not set
++# CONFIG_BATTERY_BQ27x00 is not set
++# CONFIG_BATTERY_MAX17040 is not set
++# CONFIG_BATTERY_MAX17042 is not set
++# CONFIG_CHARGER_MAX8903 is not set
++# CONFIG_CHARGER_LP8727 is not set
++# CONFIG_CHARGER_GPIO is not set
++# CONFIG_CHARGER_BQ2415X is not set
++# CONFIG_CHARGER_BQ24190 is not set
++# CONFIG_CHARGER_BQ24735 is not set
++# CONFIG_CHARGER_SMB347 is not set
++CONFIG_POWER_RESET=y
++# CONFIG_POWER_RESET_BRCMSTB is not set
++# CONFIG_POWER_RESET_GPIO is not set
++# CONFIG_POWER_RESET_GPIO_RESTART is not set
++CONFIG_POWER_RESET_HISI=y
++# CONFIG_POWER_RESET_LTC2952 is not set
++# CONFIG_POWER_RESET_RESTART is not set
++# CONFIG_POWER_RESET_VERSATILE is not set
++# CONFIG_POWER_RESET_SYSCON is not set
++# CONFIG_POWER_AVS is not set
++# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
++# CONFIG_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=y
++# CONFIG_MFD_AS3711 is not set
++# CONFIG_MFD_AS3722 is not set
++# CONFIG_PMIC_ADP5520 is not set
++# CONFIG_MFD_AAT2870_CORE is not set
++# CONFIG_MFD_BCM590XX is not set
++# CONFIG_MFD_AXP20X is not set
++# CONFIG_MFD_CROS_EC is not set
++# CONFIG_MFD_ASIC3 is not set
++# CONFIG_PMIC_DA903X is not set
++# CONFIG_MFD_DA9052_SPI is not set
++# CONFIG_MFD_DA9052_I2C is not set
++# CONFIG_MFD_DA9055 is not set
++# CONFIG_MFD_DA9063 is not set
++# CONFIG_MFD_MC13XXX_SPI is not set
++# CONFIG_MFD_MC13XXX_I2C is not set
++# CONFIG_MFD_HI6421_PMIC is not set
++CONFIG_MFD_HISI_FMC=y
++# CONFIG_HTC_EGPIO is not set
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_HTC_I2CPLD is not set
++# CONFIG_INTEL_SOC_PMIC is not set
++# CONFIG_MFD_KEMPLD is not set
++# CONFIG_MFD_88PM800 is not set
++# CONFIG_MFD_88PM805 is not set
++# CONFIG_MFD_88PM860X is not set
++# CONFIG_MFD_MAX14577 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_MENF21BMC is not set
++# CONFIG_EZX_PCAP is not set
++# CONFIG_MFD_VIPERBOARD is not set
++# CONFIG_MFD_RETU is not set
++# CONFIG_MFD_PCF50633 is not set
++# CONFIG_MFD_PM8921_CORE is not set
++# CONFIG_MFD_RTSX_USB is not set
++# CONFIG_MFD_RC5T583 is not set
++# CONFIG_MFD_RK808 is not set
++# CONFIG_MFD_RN5T618 is not set
++# CONFIG_MFD_SEC_CORE is not set
++# CONFIG_MFD_SI476X_CORE is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_MFD_SMSC is not set
++# CONFIG_ABX500_CORE is not set
++# CONFIG_MFD_STMPE is not set
++CONFIG_MFD_SYSCON=y
++# CONFIG_MFD_TI_AM335X_TSCADC is not set
++# CONFIG_MFD_LP3943 is not set
++# CONFIG_MFD_LP8788 is not set
++# CONFIG_MFD_PALMAS is not set
++# CONFIG_TPS6105X is not set
++# CONFIG_TPS65010 is not set
++# CONFIG_TPS6507X is not set
++# CONFIG_MFD_TPS65090 is not set
++# CONFIG_MFD_TPS65217 is not set
++# CONFIG_MFD_TPS65218 is not set
++# CONFIG_MFD_TPS6586X is not set
++# CONFIG_MFD_TPS65910 is not set
++# CONFIG_MFD_TPS65912 is not set
++# CONFIG_MFD_TPS65912_I2C is not set
++# CONFIG_MFD_TPS65912_SPI is not set
++# CONFIG_MFD_TPS80031 is not set
++# CONFIG_TWL4030_CORE is not set
++# CONFIG_TWL6040_CORE is not set
++# CONFIG_MFD_WL1273_CORE is not set
++# CONFIG_MFD_LM3533 is not set
++# CONFIG_MFD_TC3589X is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_MFD_T7L66XB is not set
++# CONFIG_MFD_TC6387XB is not set
++# CONFIG_MFD_TC6393XB is not set
++# CONFIG_MFD_ARIZONA_I2C is not set
++# CONFIG_MFD_ARIZONA_SPI is not set
++# CONFIG_MFD_WM8400 is not set
++# CONFIG_MFD_WM831X_I2C is not set
++# CONFIG_MFD_WM831X_SPI is not set
++# CONFIG_MFD_WM8350_I2C is not set
++# CONFIG_MFD_WM8994 is not set
++CONFIG_REGULATOR=y
++# CONFIG_REGULATOR_DEBUG is not set
++# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
++# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
++# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
++# CONFIG_REGULATOR_ACT8865 is not set
++# CONFIG_REGULATOR_AD5398 is not set
++# CONFIG_REGULATOR_ANATOP is not set
++# CONFIG_REGULATOR_DA9210 is not set
++# CONFIG_REGULATOR_DA9211 is not set
++# CONFIG_REGULATOR_FAN53555 is not set
++# CONFIG_REGULATOR_GPIO is not set
++# CONFIG_REGULATOR_ISL9305 is not set
++# CONFIG_REGULATOR_ISL6271A is not set
++# CONFIG_REGULATOR_LP3971 is not set
++# CONFIG_REGULATOR_LP3972 is not set
++# CONFIG_REGULATOR_LP872X is not set
++# CONFIG_REGULATOR_LP8755 is not set
++# CONFIG_REGULATOR_LTC3589 is not set
++# CONFIG_REGULATOR_MAX1586 is not set
++# CONFIG_REGULATOR_MAX8649 is not set
++# CONFIG_REGULATOR_MAX8660 is not set
++# CONFIG_REGULATOR_MAX8952 is not set
++# CONFIG_REGULATOR_MAX8973 is not set
++# CONFIG_REGULATOR_PFUZE100 is not set
++# CONFIG_REGULATOR_TPS51632 is not set
++# CONFIG_REGULATOR_TPS62360 is not set
++# CONFIG_REGULATOR_TPS65023 is not set
++# CONFIG_REGULATOR_TPS6507X is not set
++# CONFIG_REGULATOR_TPS6524X is not set
++# CONFIG_MEDIA_SUPPORT is not set
++
++#
++# Graphics support
++#
++# CONFIG_IMX_IPUV3_CORE is not set
++
++#
++# Direct Rendering Manager
++#
++# CONFIG_DRM is not set
++
++#
++# Frame buffer Devices
++#
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++CONFIG_FB_CMDLINE=y
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++# CONFIG_FB_CFB_FILLRECT is not set
++# CONFIG_FB_CFB_COPYAREA is not set
++# CONFIG_FB_CFB_IMAGEBLIT is not set
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# 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_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_ARMCLCD is not set
++# CONFIG_FB_OPENCORES is not set
++# CONFIG_FB_S1D13XXX is not set
++# CONFIG_FB_SMSCUFX is not set
++# CONFIG_FB_UDL is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_BROADSHEET is not set
++# CONFIG_FB_AUO_K190X is not set
++# CONFIG_FB_SIMPLE is not set
++# CONFIG_FB_SSD1307 is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++# CONFIG_VGASTATE is not set
++
++#
++# Console display driver support
++#
++CONFIG_DUMMY_CONSOLE=y
++# CONFIG_FRAMEBUFFER_CONSOLE is not set
++# CONFIG_LOGO is not set
++# CONFIG_SOUND is not set
++
++#
++# HID support
++#
++CONFIG_HID=y
++# CONFIG_HID_BATTERY_STRENGTH is not set
++# CONFIG_HIDRAW is not set
++# CONFIG_UHID is not set
++CONFIG_HID_GENERIC=y
++
++#
++# Special HID drivers
++#
++CONFIG_HID_A4TECH=y
++# CONFIG_HID_ACRUX is not set
++CONFIG_HID_APPLE=y
++# CONFIG_HID_APPLEIR is not set
++# CONFIG_HID_AUREAL is not set
++CONFIG_HID_BELKIN=y
++CONFIG_HID_CHERRY=y
++CONFIG_HID_CHICONY=y
++# CONFIG_HID_CP2112 is not set
++CONFIG_HID_CYPRESS=y
++# CONFIG_HID_DRAGONRISE is not set
++# CONFIG_HID_EMS_FF is not set
++# CONFIG_HID_ELECOM is not set
++# CONFIG_HID_ELO is not set
++CONFIG_HID_EZKEY=y
++# CONFIG_HID_HOLTEK is not set
++# CONFIG_HID_HUION 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_ICADE is not set
++# CONFIG_HID_TWINHAN is not set
++CONFIG_HID_KENSINGTON=y
++# CONFIG_HID_LCPOWER is not set
++# CONFIG_HID_LENOVO is not set
++CONFIG_HID_LOGITECH=y
++# CONFIG_HID_LOGITECH_HIDPP is not set
++# CONFIG_LOGITECH_FF is not set
++# CONFIG_LOGIRUMBLEPAD2_FF is not set
++# CONFIG_LOGIG940_FF is not set
++# CONFIG_LOGIWHEELS_FF is not set
++# CONFIG_HID_MAGICMOUSE is not set
++CONFIG_HID_MICROSOFT=y
++CONFIG_HID_MONTEREY=y
++# 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_PENMOUNT is not set
++# CONFIG_HID_PETALYNX is not set
++# CONFIG_HID_PICOLCD is not set
++# CONFIG_HID_PRIMAX is not set
++# CONFIG_HID_ROCCAT is not set
++# CONFIG_HID_SAITEK is not set
++# CONFIG_HID_SAMSUNG is not set
++# CONFIG_HID_SPEEDLINK is not set
++# CONFIG_HID_STEELSERIES is not set
++# CONFIG_HID_SUNPLUS is not set
++# CONFIG_HID_RMI 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_XINMO is not set
++# CONFIG_HID_ZEROPLUS is not set
++# CONFIG_HID_ZYDACRON is not set
++# CONFIG_HID_SENSOR_HUB is not set
++
++#
++# USB HID support
++#
++CONFIG_USB_HID=y
++# CONFIG_HID_PID is not set
++# CONFIG_USB_HIDDEV is not set
++
++#
++# I2C HID support
++#
++# CONFIG_I2C_HID is not set
++CONFIG_USB_OHCI_LITTLE_ENDIAN=y
++CONFIG_USB_SUPPORT=y
++CONFIG_USB_COMMON=y
++CONFIG_USB_ARCH_HAS_HCD=y
++CONFIG_USB=y
++# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
++
++#
++# Miscellaneous USB options
++#
++CONFIG_USB_DEFAULT_PERSIST=y
++# CONFIG_USB_DYNAMIC_MINORS is not set
++# CONFIG_USB_OTG_WHITELIST is not set
++# CONFIG_USB_OTG_FSM is not set
++# CONFIG_USB_MON is not set
++# CONFIG_USB_WUSB_CBAF is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_C67X00_HCD is not set
++CONFIG_USB_XHCI_HCD=y
++CONFIG_USB_XHCI_PLATFORM=y
++CONFIG_USB_XHCI_HISILICON=y
++CONFIG_USB_EHCI_HCD=y
++# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
++CONFIG_USB_EHCI_TT_NEWSCHED=y
++CONFIG_USB_EHCI_HCD_PLATFORM=y
++# 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_FUSBH200_HCD is not set
++# CONFIG_USB_FOTG210_HCD is not set
++# CONFIG_USB_MAX3421_HCD is not set
++CONFIG_USB_OHCI_HCD=y
++CONFIG_USB_OHCI_HCD_PLATFORM=y
++# CONFIG_USB_SL811_HCD is not set
++# CONFIG_USB_R8A66597_HCD is not set
++# CONFIG_USB_HCD_TEST_MODE is not set
++
++#
++# USB Device Class drivers
++#
++# CONFIG_USB_ACM is not set
++# CONFIG_USB_PRINTER is not set
++# CONFIG_USB_WDM is not set
++# CONFIG_USB_TMC is not set
++
++#
++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
++#
++
++#
++# also be needed; see USB_STORAGE Help for more info
++#
++CONFIG_USB_STORAGE=y
++# CONFIG_USB_STORAGE_DEBUG is not set
++# CONFIG_USB_STORAGE_REALTEK is not set
++# CONFIG_USB_STORAGE_DATAFAB is not set
++# CONFIG_USB_STORAGE_FREECOM is not set
++# CONFIG_USB_STORAGE_ISD200 is not set
++# CONFIG_USB_STORAGE_USBAT is not set
++# CONFIG_USB_STORAGE_SDDR09 is not set
++# CONFIG_USB_STORAGE_SDDR55 is not set
++# CONFIG_USB_STORAGE_JUMPSHOT is not set
++# CONFIG_USB_STORAGE_ALAUDA is not set
++# CONFIG_USB_STORAGE_ONETOUCH is not set
++# CONFIG_USB_STORAGE_KARMA is not set
++# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
++# CONFIG_USB_STORAGE_ENE_UB6250 is not set
++# CONFIG_USB_UAS is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++# CONFIG_USBIP_CORE is not set
++# CONFIG_USB_MUSB_HDRC is not set
++# CONFIG_USB_DWC3 is not set
++# CONFIG_USB_DWC2 is not set
++# CONFIG_USB_CHIPIDEA is not set
++
++#
++# USB port drivers
++#
++# CONFIG_USB_SERIAL is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
++# CONFIG_USB_SEVSEG is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
++# CONFIG_USB_APPLEDISPLAY is not set
++# CONFIG_USB_SISUSBVGA is not set
++# CONFIG_USB_LD is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
++# CONFIG_USB_IOWARRIOR is not set
++# CONFIG_USB_TEST is not set
++# CONFIG_USB_EHSET_TEST_FIXTURE is not set
++# CONFIG_USB_ISIGHTFW is not set
++# CONFIG_USB_YUREX is not set
++# CONFIG_USB_EZUSB_FX2 is not set
++# CONFIG_USB_HSIC_USB3503 is not set
++# CONFIG_USB_LINK_LAYER_TEST is not set
++
++#
++# USB Physical Layer drivers
++#
++# CONFIG_USB_PHY is not set
++# CONFIG_USB_OTG_WAKELOCK is not set
++# CONFIG_NOP_USB_XCEIV is not set
++# CONFIG_AM335X_PHY_USB is not set
++# CONFIG_USB_GPIO_VBUS is not set
++# CONFIG_USB_ISP1301 is not set
++# CONFIG_USB_ULPI is not set
++CONFIG_USB_GADGET=y
++# CONFIG_USB_GADGET_DEBUG is not set
++# CONFIG_USB_GADGET_DEBUG_FILES is not set
++CONFIG_USB_GADGET_VBUS_DRAW=2
++CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2
++
++#
++# USB Peripheral Controller
++#
++# CONFIG_USB_FUSB300 is not set
++# CONFIG_USB_FOTG210_UDC is not set
++# CONFIG_USB_GR_UDC is not set
++# CONFIG_USB_R8A66597 is not set
++# CONFIG_USB_PXA27X is not set
++# CONFIG_USB_MV_UDC is not set
++CONFIG_HIUSB_DEVICE2_0=y
++CONFIG_USB_HISI_UDC=m
++# CONFIG_USB_AUTO_SWITCH is not set
++# CONFIG_HIUSB_DEVICE3_0 is not set
++# CONFIG_USB_MV_U3D is not set
++# CONFIG_USB_M66592 is not set
++# CONFIG_USB_NET2272 is not set
++# CONFIG_USB_GADGET_XILINX is not set
++# CONFIG_USB_DUMMY_HCD is not set
++CONFIG_USB_LIBCOMPOSITE=m
++CONFIG_USB_F_ACM=m
++CONFIG_USB_U_SERIAL=m
++CONFIG_USB_U_ETHER=m
++CONFIG_USB_F_SERIAL=m
++CONFIG_USB_F_OBEX=m
++CONFIG_USB_F_ECM=m
++CONFIG_USB_F_SUBSET=m
++CONFIG_USB_F_RNDIS=m
++CONFIG_USB_F_MASS_STORAGE=m
++# CONFIG_USB_CONFIGFS is not set
++# CONFIG_USB_ZERO 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 is not set
++# CONFIG_USB_FUNCTIONFS is not set
++CONFIG_USB_MASS_STORAGE=m
++CONFIG_USB_G_SERIAL=m
++# CONFIG_USB_G_PRINTER is not set
++# CONFIG_USB_CDC_COMPOSITE is not set
++# CONFIG_USB_G_ACM_MS is not set
++# CONFIG_USB_G_MULTI is not set
++# CONFIG_USB_G_HID is not set
++# CONFIG_USB_G_DBGP is not set
++# CONFIG_UWB is not set
++CONFIG_MMC=y
++# CONFIG_MMC_DEBUG is not set
++# CONFIG_MMC_CLKGATE is not set
++CONFIG_MMC_EMBEDDED_SDIO=y
++# CONFIG_MMC_PARANOID_SD_INIT is not set
++
++#
++# MMC/SD/SDIO Card Drivers
++#
++CONFIG_MMC_BLOCK=y
++CONFIG_MMC_BLOCK_MINORS=8
++CONFIG_MMC_BLOCK_BOUNCE=y
++# CONFIG_MMC_BLOCK_DEFERRED_RESUME is not set
++# CONFIG_SDIO_UART is not set
++# CONFIG_MMC_TEST is not set
++
++#
++# MMC/SD/SDIO Host Controller Drivers
++#
++# CONFIG_MMC_ARMMMCI is not set
++# CONFIG_MMC_SDHCI is not set
++# CONFIG_MMC_DW is not set
++# CONFIG_MMC_VUB300 is not set
++# CONFIG_MMC_USHC is not set
++# CONFIG_MMC_USDHI6ROL0 is not set
++CONFIG_HIMCIV200=y
++CONFIG_SEND_AUTO_STOP=y
++CONFIG_DETECT_CARD_TIME=200
++# CONFIG_MEMSTICK is not set
++# CONFIG_NEW_LEDS is not set
++# CONFIG_SWITCH is not set
++# CONFIG_ACCESSIBILITY is not set
++# CONFIG_EDAC is not set
++CONFIG_RTC_LIB=y
++# CONFIG_RTC_CLASS is not set
++# CONFIG_DMADEVICES is not set
++# CONFIG_AUXDISPLAY is not set
++# CONFIG_UIO is not set
++# CONFIG_VIRT_DRIVERS is not set
++
++#
++# Virtio drivers
++#
++# CONFIG_VIRTIO_MMIO is not set
++
++#
++# Microsoft Hyper-V guest support
++#
++# CONFIG_STAGING is not set
++
++#
++# SOC (System On Chip) specific Drivers
++#
++# CONFIG_SOC_TI is not set
++CONFIG_CLKDEV_LOOKUP=y
++CONFIG_HAVE_CLK_PREPARE=y
++CONFIG_COMMON_CLK=y
++
++#
++# Common Clock Framework
++#
++# CONFIG_COMMON_CLK_SI5351 is not set
++# CONFIG_COMMON_CLK_SI570 is not set
++# CONFIG_COMMON_CLK_PXA is not set
++# CONFIG_COMMON_CLK_QCOM is not set
++
++#
++# Hardware Spinlock drivers
++#
++
++#
++# Clock Source drivers
++#
++CONFIG_CLKSRC_OF=y
++CONFIG_CLKSRC_MMIO=y
++CONFIG_ARM_ARCH_TIMER=y
++CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y
++# CONFIG_ATMEL_PIT is not set
++# CONFIG_SH_TIMER_CMT is not set
++# CONFIG_SH_TIMER_MTU2 is not set
++# CONFIG_SH_TIMER_TMU is not set
++# CONFIG_EM_TIMER_STI is not set
++# CONFIG_CLKSRC_VERSATILE is not set
++# CONFIG_MAILBOX is not set
++# CONFIG_IOMMU_SUPPORT is not set
++
++#
++# Remoteproc drivers
++#
++# CONFIG_STE_MODEM_RPROC is not set
++
++#
++# Rpmsg drivers
++#
++
++#
++# SOC (System On Chip) specific Drivers
++#
++# 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
++CONFIG_IRQCHIP=y
++CONFIG_ARM_GIC=y
++# CONFIG_IPACK_BUS is not set
++CONFIG_ARCH_HAS_RESET_CONTROLLER=y
++CONFIG_RESET_CONTROLLER=y
++# CONFIG_FMC is not set
++
++#
++# PHY Subsystem
++#
++CONFIG_GENERIC_PHY=y
++# CONFIG_BCM_KONA_USB2_PHY is not set
++CONFIG_PHY_HISI_INNO_USB2=y
++CONFIG_PHY_HISI_USB3=y
++# CONFIG_POWERCAP is not set
++# CONFIG_MCB is not set
++CONFIG_HI_DMAC=y
++CONFIG_HI_DMAC_IO_BASE=0x10030000
++CONFIG_HI_DMAC_CHANNEL_NUM=4
++
++#
++# Hisilicon driver support
++#
++# CONFIG_CMA_MEM_SHARED is not set
++# CONFIG_CMA_ADVANCE_SHARE is not set
++
++#
++# File systems
++#
++CONFIG_DCACHE_WORD_ACCESS=y
++# CONFIG_EXT2_FS is not set
++# CONFIG_EXT3_FS is not set
++CONFIG_EXT4_FS=y
++CONFIG_EXT4_USE_FOR_EXT23=y
++# CONFIG_EXT4_FS_POSIX_ACL is not set
++# CONFIG_EXT4_FS_SECURITY is not set
++# CONFIG_EXT4_DEBUG is not set
++CONFIG_JBD2=y
++# CONFIG_JBD2_DEBUG is not set
++CONFIG_FS_MBCACHE=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_BTRFS_FS is not set
++# CONFIG_NILFS2_FS is not set
++CONFIG_FS_POSIX_ACL=y
++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 is not set
++# CONFIG_FUSE_FS is not set
++# CONFIG_OVERLAY_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_KERNFS=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=m
++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_YAFFS_FS=y
++CONFIG_YAFFS_YAFFS1=y
++# CONFIG_YAFFS_9BYTE_TAGS is not set
++# CONFIG_YAFFS_DOES_ECC is not set
++CONFIG_YAFFS_YAFFS2=y
++CONFIG_YAFFS_AUTO_YAFFS2=y
++# CONFIG_YAFFS_DISABLE_TAGS_ECC is not set
++# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
++# CONFIG_YAFFS_EMPTY_LOST_AND_FOUND is not set
++# CONFIG_YAFFS_DISABLE_BLOCK_REFRESHING is not set
++# CONFIG_YAFFS_DISABLE_BACKGROUND is not set
++# CONFIG_YAFFS_DISABLE_BAD_BLOCK_MARKING is not set
++CONFIG_YAFFS_XATTR=y
++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 is not set
++# CONFIG_JFFS2_FS_XATTR is not set
++# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
++CONFIG_JFFS2_ZLIB=y
++# CONFIG_JFFS2_LZO is not set
++CONFIG_JFFS2_RTIME=y
++# CONFIG_JFFS2_RUBIN 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 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 is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V2=y
++CONFIG_NFS_V3=y
++CONFIG_NFS_V3_ACL=y
++# CONFIG_NFS_V4 is not set
++# CONFIG_NFS_SWAP is not set
++# CONFIG_ROOT_NFS is not set
++# CONFIG_NFSD is not set
++CONFIG_GRACE_PERIOD=y
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_ACL_SUPPORT=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 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=y
++# CONFIG_DLM is not set
++
++#
++# Kernel hacking
++#
++
++#
++# printk and dmesg options
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4
++# CONFIG_BOOT_PRINTK_DELAY is not set
++
++#
++# Compile-time checks and compiler options
++#
++# CONFIG_DEBUG_INFO is not set
++# CONFIG_ENABLE_WARN_DEPRECATED is not set
++# CONFIG_ENABLE_MUST_CHECK is not set
++CONFIG_FRAME_WARN=1024
++# CONFIG_STRIP_ASM_SYMS is not set
++# CONFIG_READABLE_ASM is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++# CONFIG_DEBUG_FS is not set
++# CONFIG_HEADERS_CHECK is not set
++# CONFIG_DEBUG_SECTION_MISMATCH is not set
++# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
++# CONFIG_MAGIC_SYSRQ is not set
++CONFIG_DEBUG_KERNEL=y
++
++#
++# Memory Debugging
++#
++# 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_STACK_USAGE is not set
++# CONFIG_DEBUG_VM is not set
++CONFIG_DEBUG_MEMORY_INIT=y
++# CONFIG_DEBUG_PER_CPU_MAPS is not set
++# CONFIG_DEBUG_HIGHMEM is not set
++# CONFIG_DEBUG_SHIRQ is not set
++
++#
++# Debug Lockups and Hangs
++#
++# CONFIG_LOCKUP_DETECTOR is not set
++# CONFIG_DETECT_HUNG_TASK is not set
++# CONFIG_PANIC_ON_OOPS is not set
++CONFIG_PANIC_ON_OOPS_VALUE=0
++CONFIG_PANIC_TIMEOUT=0
++CONFIG_SCHED_DEBUG=y
++# CONFIG_SCHEDSTATS is not set
++# CONFIG_SCHED_STACK_END_CHECK is not set
++# CONFIG_TIMER_STATS is not set
++
++#
++# Lock Debugging (spinlocks, mutexes, etc...)
++#
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_LOCK_STAT is not set
++# CONFIG_DEBUG_ATOMIC_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_LOCK_TORTURE_TEST is not set
++CONFIG_STACKTRACE=y
++# CONFIG_DEBUG_KOBJECT is not set
++CONFIG_DEBUG_BUGVERBOSE=y
++# CONFIG_DEBUG_LIST is not set
++# CONFIG_DEBUG_PI_LIST is not set
++# CONFIG_DEBUG_SG is not set
++# CONFIG_DEBUG_NOTIFIERS is not set
++# CONFIG_DEBUG_CREDENTIALS is not set
++
++#
++# RCU Debugging
++#
++# CONFIG_SPARSE_RCU_POINTER is not set
++# CONFIG_TORTURE_TEST 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_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_NOTIFIER_ERROR_INJECTION is not set
++# CONFIG_FAULT_INJECTION 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 is not set
++
++#
++# Runtime Testing
++#
++# CONFIG_TEST_LIST_SORT is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_RBTREE_TEST is not set
++# CONFIG_INTERVAL_TREE_TEST is not set
++# CONFIG_PERCPU_TEST is not set
++# CONFIG_ATOMIC64_SELFTEST is not set
++# CONFIG_TEST_STRING_HELPERS is not set
++# CONFIG_TEST_KSTRTOX is not set
++# CONFIG_TEST_RHASHTABLE is not set
++# CONFIG_DMA_API_DEBUG is not set
++# CONFIG_TEST_LKM is not set
++# CONFIG_TEST_USER_COPY is not set
++# CONFIG_TEST_BPF is not set
++# CONFIG_TEST_FIRMWARE is not set
++# CONFIG_TEST_UDELAY is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_KGDB is not set
++# CONFIG_ARM_PTDUMP is not set
++CONFIG_STRICT_DEVMEM=y
++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_DEBUG_UART_PL01X is not set
++# CONFIG_DEBUG_UART_8250 is not set
++# CONFIG_DEBUG_UART_BCM63XX is not set
++CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"
++# CONFIG_OC_ETM is not set
++# CONFIG_PID_IN_CONTEXTIDR is not set
++# CONFIG_DEBUG_SET_MODULE_RONX is not set
++# CONFIG_CORESIGHT is not set
++
++#
++# 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_HASH=y
++CONFIG_CRYPTO_HASH2=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_PCRYPT is not set
++# CONFIG_CRYPTO_CRYPTD is not set
++# CONFIG_CRYPTO_MCRYPTD 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_CMAC is not set
++# CONFIG_CRYPTO_HMAC is not set
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_VMAC is not set
++
++#
++# Digest
++#
++CONFIG_CRYPTO_CRC32C=y
++# CONFIG_CRYPTO_CRC32 is not set
++# CONFIG_CRYPTO_CRCT10DIF 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_SHA1_ARM_NEON is not set
++# CONFIG_CRYPTO_SHA256 is not set
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_SHA512_ARM_NEON 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_AES_ARM_BS 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
++# CONFIG_CRYPTO_LZ4 is not set
++# CONFIG_CRYPTO_LZ4HC is not set
++
++#
++# Random Number Generation
++#
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++# CONFIG_CRYPTO_DRBG_MENU is not set
++# CONFIG_CRYPTO_USER_API_HASH is not set
++# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
++CONFIG_CRYPTO_HW=y
++# CONFIG_BINARY_PRINTF is not set
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++CONFIG_GENERIC_STRNCPY_FROM_USER=y
++CONFIG_GENERIC_STRNLEN_USER=y
++CONFIG_GENERIC_NET_UTILS=y
++CONFIG_GENERIC_PCI_IOMAP=y
++CONFIG_GENERIC_IO=y
++CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
++# CONFIG_CRC_CCITT is not set
++CONFIG_CRC16=y
++# CONFIG_CRC_T10DIF is not set
++# 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_AUDIT_ARCH_COMPAT_GENERIC is not set
++# CONFIG_RANDOM32_SELFTEST is not set
++CONFIG_ZLIB_INFLATE=y
++CONFIG_ZLIB_DEFLATE=y
++CONFIG_LZO_COMPRESS=y
++CONFIG_LZO_DECOMPRESS=y
++CONFIG_LZ4_DECOMPRESS=y
++CONFIG_XZ_DEC=y
++CONFIG_XZ_DEC_X86=y
++CONFIG_XZ_DEC_POWERPC=y
++CONFIG_XZ_DEC_IA64=y
++CONFIG_XZ_DEC_ARM=y
++CONFIG_XZ_DEC_ARMTHUMB=y
++CONFIG_XZ_DEC_SPARC=y
++CONFIG_XZ_DEC_BCJ=y
++# CONFIG_XZ_DEC_TEST is not set
++CONFIG_DECOMPRESS_GZIP=y
++CONFIG_DECOMPRESS_BZIP2=y
++CONFIG_DECOMPRESS_LZMA=y
++CONFIG_DECOMPRESS_XZ=y
++CONFIG_DECOMPRESS_LZO=y
++CONFIG_DECOMPRESS_LZ4=y
++CONFIG_GENERIC_ALLOCATOR=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT_MAP=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 is not set
++# CONFIG_CORDIC is not set
++# CONFIG_DDR is not set
++CONFIG_LIBFDT=y
++CONFIG_ARCH_HAS_SG_CHAIN=y
++# CONFIG_VIRTUALIZATION is not set
+diff --git a/arch/arm/configs/hi3516av200_big_little_nand_defconfig b/arch/arm/configs/hi3516av200_big_little_nand_defconfig
+new file mode 100644
+index 0000000..3990e3f
+--- /dev/null
++++ b/arch/arm/configs/hi3516av200_big_little_nand_defconfig
+@@ -0,0 +1,2597 @@
++#
++# Automatically generated file; DO NOT EDIT.
++# Linux/arm 3.18.20 Kernel Configuration
++#
++CONFIG_ARM=y
++CONFIG_ARM_HAS_SG_CHAIN=y
++CONFIG_MIGHT_HAVE_PCI=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=y
++CONFIG_HAVE_PROC_CPU=y
++CONFIG_STACKTRACE_SUPPORT=y
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
++CONFIG_RWSEM_XCHGADD_ALGORITHM=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_NEED_DMA_MAP_STATE=y
++CONFIG_ARCH_SUPPORTS_UPROBES=y
++CONFIG_VECTORS_BASE=0xffff0000
++CONFIG_ARM_PATCH_PHYS_VIRT=y
++CONFIG_GENERIC_BUG=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++CONFIG_IRQ_WORK=y
++CONFIG_BUILDTIME_EXTABLE_SORT=y
++
++#
++# General setup
++#
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_CROSS_COMPILE=""
++# CONFIG_COMPILE_TEST is not set
++CONFIG_LOCALVERSION=""
++# CONFIG_LOCALVERSION_AUTO is not set
++CONFIG_HAVE_KERNEL_GZIP=y
++CONFIG_HAVE_KERNEL_LZMA=y
++CONFIG_HAVE_KERNEL_XZ=y
++CONFIG_HAVE_KERNEL_LZO=y
++CONFIG_HAVE_KERNEL_LZ4=y
++CONFIG_KERNEL_GZIP=y
++# CONFIG_KERNEL_LZMA is not set
++# CONFIG_KERNEL_XZ is not set
++# CONFIG_KERNEL_LZO is not set
++# CONFIG_KERNEL_LZ4 is not set
++CONFIG_DEFAULT_HOSTNAME="(none)"
++CONFIG_SWAP=y
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++# CONFIG_POSIX_MQUEUE is not set
++CONFIG_CROSS_MEMORY_ATTACH=y
++# CONFIG_FHANDLE is not set
++CONFIG_USELIB=y
++# CONFIG_AUDIT is not set
++CONFIG_HAVE_ARCH_AUDITSYSCALL=y
++
++#
++# IRQ subsystem
++#
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_GENERIC_IRQ_SHOW=y
++CONFIG_HARDIRQS_SW_RESEND=y
++CONFIG_IRQ_DOMAIN=y
++CONFIG_HANDLE_DOMAIN_IRQ=y
++CONFIG_IRQ_FORCED_THREADING=y
++CONFIG_SPARSE_IRQ=y
++CONFIG_GENERIC_CLOCKEVENTS=y
++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
++CONFIG_ARCH_HAS_TICK_BROADCAST=y
++CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
++
++#
++# Timers subsystem
++#
++CONFIG_TICK_ONESHOT=y
++CONFIG_NO_HZ_COMMON=y
++# CONFIG_HZ_PERIODIC is not set
++CONFIG_NO_HZ_IDLE=y
++# CONFIG_NO_HZ_FULL is not set
++CONFIG_NO_HZ=y
++# CONFIG_HIGH_RES_TIMERS is not set
++
++#
++# CPU/Task time and stats accounting
++#
++CONFIG_TICK_CPU_ACCOUNTING=y
++# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set
++# CONFIG_IRQ_TIME_ACCOUNTING is not set
++# CONFIG_BSD_PROCESS_ACCT is not set
++# CONFIG_TASKSTATS is not set
++
++#
++# RCU Subsystem
++#
++CONFIG_TREE_RCU=y
++# CONFIG_PREEMPT_RCU is not set
++# CONFIG_TASKS_RCU is not set
++CONFIG_RCU_STALL_COMMON=y
++# CONFIG_RCU_USER_QS is not set
++CONFIG_RCU_FANOUT=32
++CONFIG_RCU_FANOUT_LEAF=16
++# CONFIG_RCU_FANOUT_EXACT is not set
++# CONFIG_RCU_FAST_NO_HZ is not set
++# CONFIG_TREE_RCU_TRACE is not set
++# CONFIG_RCU_NOCB_CPU is not set
++# CONFIG_BUILD_BIN2C is not set
++# CONFIG_IKCONFIG is not set
++CONFIG_LOG_BUF_SHIFT=17
++CONFIG_LOG_CPU_MAX_BUF_SHIFT=12
++CONFIG_GENERIC_SCHED_CLOCK=y
++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_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_USER_NS is not set
++CONFIG_PID_NS=y
++CONFIG_NET_NS=y
++# 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=y
++CONFIG_RD_LZMA=y
++CONFIG_RD_XZ=y
++CONFIG_RD_LZO=y
++CONFIG_RD_LZ4=y
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++CONFIG_HAVE_UID16=y
++CONFIG_BPF=y
++# CONFIG_EXPERT is not set
++CONFIG_UID16=y
++# CONFIG_SGETMASK_SYSCALL is not set
++CONFIG_SYSFS_SYSCALL=y
++# CONFIG_SYSCTL_SYSCALL is not set
++CONFIG_KALLSYMS=y
++# CONFIG_KALLSYMS_ALL is not set
++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_BPF_SYSCALL is not set
++CONFIG_SHMEM=y
++CONFIG_AIO=y
++CONFIG_ADVISE_SYSCALLS=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_SLUB_CPU_PARTIAL=y
++# CONFIG_PROFILING is not set
++CONFIG_HAVE_OPROFILE=y
++# CONFIG_KPROBES is not set
++# CONFIG_JUMP_LABEL is not set
++# CONFIG_UPROBES is not set
++# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
++CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
++CONFIG_ARCH_USE_BUILTIN_BSWAP=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_GENERIC_SMP_IDLE_THREAD=y
++CONFIG_GENERIC_IDLE_POLL_SETUP=y
++CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
++CONFIG_HAVE_CLK=y
++CONFIG_HAVE_DMA_API_DEBUG=y
++CONFIG_HAVE_PERF_REGS=y
++CONFIG_HAVE_PERF_USER_STACK_DUMP=y
++CONFIG_HAVE_ARCH_JUMP_LABEL=y
++CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
++CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
++CONFIG_HAVE_CC_STACKPROTECTOR=y
++# CONFIG_CC_STACKPROTECTOR is not set
++CONFIG_CC_STACKPROTECTOR_NONE=y
++# CONFIG_CC_STACKPROTECTOR_REGULAR is not set
++# CONFIG_CC_STACKPROTECTOR_STRONG is not set
++CONFIG_HAVE_CONTEXT_TRACKING=y
++CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
++CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
++CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
++CONFIG_MODULES_USE_ELF_REL=y
++CONFIG_CLONE_BACKWARDS=y
++CONFIG_OLD_SIGSUSPEND3=y
++CONFIG_OLD_SIGACTION=y
++
++#
++# GCOV-based kernel profiling
++#
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_SLABINFO=y
++CONFIG_RT_MUTEXES=y
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++# CONFIG_MODULE_FORCE_LOAD is not set
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++# CONFIG_MODULE_SIG is not set
++# CONFIG_MODULE_COMPRESS is not set
++CONFIG_STOP_MACHINE=y
++CONFIG_BLOCK=y
++CONFIG_LBDAF=y
++CONFIG_BLK_DEV_BSG=y
++# CONFIG_BLK_DEV_BSGLIB is not set
++# CONFIG_BLK_DEV_INTEGRITY is not set
++CONFIG_BLK_CMDLINE_PARSER=y
++
++#
++# Partition Types
++#
++CONFIG_PARTITION_ADVANCED=y
++# CONFIG_ACORN_PARTITION is not set
++# CONFIG_AIX_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=y
++# CONFIG_SYSV68_PARTITION is not set
++CONFIG_CMDLINE_PARTITION=y
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++CONFIG_DEFAULT_DEADLINE=y
++# CONFIG_DEFAULT_CFQ is not set
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="deadline"
++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_ARCH_SUPPORTS_ATOMIC_RMW=y
++CONFIG_MUTEX_SPIN_ON_OWNER=y
++CONFIG_RWSEM_SPIN_ON_OWNER=y
++CONFIG_FREEZER=y
++
++#
++# System Type
++#
++CONFIG_MMU=y
++CONFIG_ARCH_MULTIPLATFORM=y
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_AT91 is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_GEMINI is not set
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_IOP13XX is not set
++# CONFIG_ARCH_IOP32X is not set
++# CONFIG_ARCH_IOP33X is not set
++# CONFIG_ARCH_IXP4XX is not set
++# CONFIG_ARCH_DOVE is not set
++# CONFIG_ARCH_MV78XX0 is not set
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_MMP is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_W90X900 is not set
++# CONFIG_ARCH_LPC32XX is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_MSM is not set
++# CONFIG_ARCH_SHMOBILE_LEGACY 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_DAVINCI is not set
++# CONFIG_ARCH_OMAP1 is not set
++
++#
++# Multiple platform selection
++#
++
++#
++# CPU Core family selection
++#
++# CONFIG_ARCH_MULTI_V6 is not set
++CONFIG_ARCH_MULTI_V7=y
++CONFIG_ARCH_MULTI_V6_V7=y
++# CONFIG_ARCH_MULTI_CPU_AUTO is not set
++# CONFIG_ARCH_VIRT is not set
++# CONFIG_ARCH_MVEBU is not set
++# CONFIG_ARCH_BCM is not set
++# CONFIG_ARCH_BERLIN is not set
++# CONFIG_ARCH_HIGHBANK is not set
++CONFIG_ARCH_HISI=y
++
++#
++# Hisilicon platform type
++#
++# CONFIG_ARCH_HI3xxx is not set
++# CONFIG_ARCH_HIP04 is not set
++# CONFIG_ARCH_HIX5HD2 is not set
++# CONFIG_ARCH_HI3519 is not set
++# CONFIG_ARCH_HI3519V101 is not set
++CONFIG_ARCH_HI3516AV200=y
++# CONFIG_ARCH_HI3559 is not set
++# CONFIG_ARCH_HI3556 is not set
++CONFIG_PMC=y
++# CONFIG_ARCH_HI3536C is not set
++# CONFIG_ARCH_KEYSTONE is not set
++# CONFIG_ARCH_MESON is not set
++# CONFIG_ARCH_MXC is not set
++# CONFIG_ARCH_MEDIATEK is not set
++
++#
++# TI OMAP/AM/DM/DRA Family
++#
++# CONFIG_ARCH_OMAP3 is not set
++# CONFIG_ARCH_OMAP4 is not set
++# CONFIG_SOC_OMAP5 is not set
++# CONFIG_SOC_AM33XX is not set
++# CONFIG_SOC_AM43XX is not set
++# CONFIG_SOC_DRA7XX is not set
++# CONFIG_ARCH_QCOM is not set
++# CONFIG_ARCH_ROCKCHIP is not set
++# CONFIG_ARCH_SOCFPGA is not set
++# CONFIG_PLAT_SPEAR is not set
++# CONFIG_ARCH_STI is not set
++# CONFIG_ARCH_S5PV210 is not set
++# CONFIG_ARCH_EXYNOS is not set
++# CONFIG_ARCH_SHMOBILE_MULTI is not set
++# CONFIG_ARCH_SUNXI is not set
++# CONFIG_ARCH_SIRF is not set
++# CONFIG_ARCH_TEGRA is not set
++# CONFIG_ARCH_U8500 is not set
++# CONFIG_ARCH_VEXPRESS is not set
++# CONFIG_ARCH_WM8850 is not set
++# CONFIG_ARCH_ZYNQ is not set
++CONFIG_ARM_TIMER_SP804=y
++
++#
++# Processor Type
++#
++CONFIG_CPU_V7=y
++CONFIG_CPU_32v6K=y
++CONFIG_CPU_32v7=y
++CONFIG_CPU_ABRT_EV7=y
++CONFIG_CPU_PABRT_V7=y
++CONFIG_CPU_CACHE_V7=y
++CONFIG_CPU_CACHE_VIPT=y
++CONFIG_CPU_COPY_V6=y
++CONFIG_CPU_TLB_V7=y
++CONFIG_CPU_HAS_ASID=y
++CONFIG_CPU_CP15=y
++CONFIG_CPU_CP15_MMU=y
++
++#
++# Processor Features
++#
++# CONFIG_ARM_LPAE is not set
++# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
++CONFIG_ARM_THUMB=y
++# CONFIG_ARM_THUMBEE is not set
++CONFIG_ARM_VIRT_EXT=y
++CONFIG_SWP_EMULATE=y
++# CONFIG_CPU_ICACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_DISABLE is not set
++# CONFIG_CPU_BPREDICT_DISABLE is not set
++CONFIG_KUSER_HELPERS=y
++CONFIG_MIGHT_HAVE_CACHE_L2X0=y
++# CONFIG_CACHE_L2X0 is not set
++CONFIG_ARM_L1_CACHE_SHIFT_6=y
++CONFIG_ARM_L1_CACHE_SHIFT=6
++CONFIG_ARM_DMA_MEM_BUFFERABLE=y
++CONFIG_MULTI_IRQ_HANDLER=y
++# CONFIG_ARM_ERRATA_430973 is not set
++# CONFIG_ARM_ERRATA_643719 is not set
++# CONFIG_ARM_ERRATA_720789 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_ARM_ERRATA_775420 is not set
++# CONFIG_ARM_ERRATA_798181 is not set
++# CONFIG_ARM_ERRATA_773022 is not set
++
++#
++# Bus support
++#
++CONFIG_ARM_AMBA=y
++# CONFIG_PCI is not set
++# 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=y
++# CONFIG_SCHED_SMT is not set
++CONFIG_DISABLE_CPU_SCHED_DOMAIN_BALANCE=y
++CONFIG_SCHED_HMP=y
++# CONFIG_SCHED_HMP_PRIO_FILTER is not set
++CONFIG_HMP_FAST_CPU_MASK=""
++CONFIG_HMP_SLOW_CPU_MASK=""
++CONFIG_HMP_VARIABLE_SCALE=y
++# CONFIG_HMP_FREQUENCY_INVARIANT_SCALE is not set
++# CONFIG_SCHED_HMP_LITTLE_PACKING is not set
++CONFIG_HAVE_ARM_ARCH_TIMER=y
++# CONFIG_MCPM is not set
++# CONFIG_BIG_LITTLE is not set
++CONFIG_VMSPLIT_3G=y
++# CONFIG_VMSPLIT_2G is not set
++# CONFIG_VMSPLIT_1G is not set
++CONFIG_PAGE_OFFSET=0xC0000000
++CONFIG_NR_CPUS=4
++CONFIG_HOTPLUG_CPU=y
++# CONFIG_ARM_PSCI is not set
++CONFIG_ARCH_NR_GPIO=0
++CONFIG_PREEMPT_NONE=y
++# CONFIG_PREEMPT_VOLUNTARY is not set
++# CONFIG_PREEMPT is not set
++CONFIG_HZ_FIXED=0
++CONFIG_HZ_100=y
++# CONFIG_HZ_200 is not set
++# CONFIG_HZ_250 is not set
++# CONFIG_HZ_300 is not set
++# CONFIG_HZ_500 is not set
++# CONFIG_HZ_1000 is not set
++CONFIG_HZ=100
++# CONFIG_SCHED_HRTICK is not set
++# CONFIG_THUMB2_KERNEL is not set
++CONFIG_AEABI=y
++# CONFIG_OABI_COMPAT is not set
++# 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_ARCH_WANT_GENERAL_HUGETLB=y
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_HAVE_MEMBLOCK=y
++CONFIG_NO_BOOTMEM=y
++CONFIG_MEMORY_ISOLATION=y
++# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=4
++CONFIG_COMPACTION=y
++CONFIG_MIGRATION=y
++# CONFIG_PHYS_ADDR_T_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_BOUNCE=y
++# CONFIG_KSM is not set
++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
++# CONFIG_CLEANCACHE is not set
++# CONFIG_FRONTSWAP is not set
++CONFIG_CMA=y
++# CONFIG_CMA_DEBUG is not set
++CONFIG_CMA_AREAS=7
++# CONFIG_ZPOOL is not set
++# CONFIG_ZBUD is not set
++# CONFIG_ZSMALLOC 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_SWIOTLB=y
++CONFIG_IOMMU_HELPER=y
++# CONFIG_XEN is not set
++# CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART is not set
++
++#
++# Boot options
++#
++CONFIG_USE_OF=y
++CONFIG_ATAGS=y
++# CONFIG_DEPRECATED_PARAM_STRUCT is not set
++# CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE is not set
++CONFIG_ZBOOT_ROM_TEXT=0
++CONFIG_ZBOOT_ROM_BSS=0
++CONFIG_ARM_APPENDED_DTB=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_KEXEC is not set
++# CONFIG_CRASH_DUMP is not set
++CONFIG_AUTO_ZRELADDR=y
++
++#
++# CPU Power Management
++#
++
++#
++# CPU Frequency scaling
++#
++CONFIG_CPU_FREQ=y
++CONFIG_CPU_FREQ_GOV_COMMON=y
++CONFIG_CPU_FREQ_STAT=y
++# CONFIG_CPU_FREQ_STAT_DETAILS is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
++CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
++# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE is not set
++CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
++CONFIG_CPU_FREQ_GOV_POWERSAVE=y
++CONFIG_CPU_FREQ_GOV_USERSPACE=y
++CONFIG_CPU_FREQ_GOV_ONDEMAND=y
++CONFIG_CPU_FREQ_GOV_INTERACTIVE=y
++CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
++CONFIG_CPUFREQ_DT=y
++
++#
++# ARM CPU frequency scaling drivers
++#
++# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set
++
++#
++# CPU Idle
++#
++CONFIG_CPU_IDLE=y
++CONFIG_CPU_IDLE_GOV_LADDER=y
++CONFIG_CPU_IDLE_GOV_MENU=y
++
++#
++# ARM CPU Idle Drivers
++#
++CONFIG_ARM_HI3516AV200_CPUIDLE=y
++# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++CONFIG_VFP=y
++CONFIG_VFPv3=y
++CONFIG_NEON=y
++CONFIG_KERNEL_MODE_NEON=y
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
++CONFIG_BINFMT_SCRIPT=y
++# CONFIG_HAVE_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
++CONFIG_COREDUMP=y
++
++#
++# Power management options
++#
++CONFIG_SUSPEND=y
++CONFIG_SUSPEND_FREEZER=y
++CONFIG_WAKELOCK=y
++CONFIG_HIBERNATE_CALLBACKS=y
++CONFIG_HISI_SNAPSHOT_BOOT=y
++# CONFIG_DEFAULT_MTD is not set
++CONFIG_DEFAULT_DDR=y
++CONFIG_SNAPSHOT_BUF_START=0x8a000000
++CONFIG_SNAPSHOT_BUF_SIZE=0x4000000
++CONFIG_HIBERNATION=y
++CONFIG_GZIP_COMPRESS=y
++CONFIG_PM_STD_PARTITION=""
++CONFIG_PM_SLEEP=y
++CONFIG_PM_SLEEP_SMP=y
++# CONFIG_PM_AUTOSLEEP is not set
++# CONFIG_PM_WAKELOCKS is not set
++# CONFIG_PM_RUNTIME is not set
++CONFIG_PM=y
++# CONFIG_PM_DEBUG is not set
++# CONFIG_APM_EMULATION is not set
++CONFIG_PM_OPP=y
++CONFIG_PM_CLK=y
++# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set
++CONFIG_CPU_PM=y
++# CONFIG_SUSPEND_TIME is not set
++CONFIG_ARCH_SUSPEND_POSSIBLE=y
++CONFIG_ARM_CPU_SUSPEND=y
++CONFIG_ARCH_HIBERNATION_POSSIBLE=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_NET_IP_TUNNEL=m
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_NET_IPVTI is not set
++# CONFIG_NET_UDP_TUNNEL is not set
++# CONFIG_NET_FOU is not set
++# CONFIG_GENEVE 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=y
++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=y
++# 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_VTI 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_ANDROID_PARANOID_NETWORK is not set
++CONFIG_NET_ACTIVITY_STATS=y
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NET_PTP_CLASSIFY 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_NF_TABLES is not set
++# CONFIG_NETFILTER_XTABLES is not set
++# CONFIG_IP_SET is not set
++# CONFIG_IP_VS is not set
++
++#
++# IP: Netfilter Configuration
++#
++# CONFIG_NF_DEFRAG_IPV4 is not set
++# CONFIG_NF_LOG_ARP is not set
++# CONFIG_NF_LOG_IPV4 is not set
++# CONFIG_NF_REJECT_IPV4 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_NF_REJECT_IPV6 is not set
++# CONFIG_NF_LOG_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_HAVE_NET_DSA=y
++# 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_PHONET is not set
++# CONFIG_6LOWPAN 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_VSOCKETS is not set
++# CONFIG_NETLINK_MMAP is not set
++# CONFIG_NETLINK_DIAG is not set
++# CONFIG_NET_MPLS_GSO is not set
++# CONFIG_HSR is not set
++CONFIG_RPS=y
++CONFIG_RFS_ACCEL=y
++CONFIG_XPS=y
++# CONFIG_CGROUP_NET_PRIO is not set
++# CONFIG_CGROUP_NET_CLASSID is not set
++CONFIG_NET_RX_BUSY_POLL=y
++CONFIG_BQL=y
++# CONFIG_BPF_JIT is not set
++CONFIG_NET_FLOW_LIMIT=y
++
++#
++# 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 is not set
++CONFIG_DEVTMPFS=y
++CONFIG_DEVTMPFS_MOUNT=y
++CONFIG_STANDALONE=y
++# CONFIG_PREVENT_FIRMWARE_BUILD is not set
++CONFIG_FW_LOADER=y
++# CONFIG_FIRMWARE_IN_KERNEL is not set
++CONFIG_EXTRA_FIRMWARE=""
++# CONFIG_FW_LOADER_USER_HELPER_FALLBACK is not set
++CONFIG_ALLOW_DEV_COREDUMP=y
++# 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_HAVE_CPU_AUTOPROBE is not set
++CONFIG_REGMAP=y
++CONFIG_REGMAP_MMIO=y
++# CONFIG_DMA_SHARED_BUFFER is not set
++CONFIG_DMA_CMA=y
++
++#
++# Default contiguous memory area size:
++#
++CONFIG_CMA_SIZE_MBYTES=16
++CONFIG_CMA_SIZE_SEL_MBYTES=y
++# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set
++# CONFIG_CMA_SIZE_SEL_MIN is not set
++# CONFIG_CMA_SIZE_SEL_MAX is not set
++CONFIG_CMA_ALIGNMENT=8
++
++#
++# Bus devices
++#
++# CONFIG_BRCMSTB_GISB_ARB is not set
++CONFIG_ARM_CCI=y
++# CONFIG_VEXPRESS_CONFIG 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=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_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
++CONFIG_HIFMC=y
++# CONFIG_HIFMC_SPI_NAND is not set
++CONFIG_HIFMC_NAND=y
++
++#
++# 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_SST25L is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_PHRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++# CONFIG_MTD_BLOCK2MTD is not set
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOCG3 is not set
++CONFIG_MTD_NAND_IDS=y
++CONFIG_MTD_NAND_ECC=y
++# CONFIG_MTD_NAND_ECC_SMC is not set
++CONFIG_MTD_NAND=y
++# CONFIG_MTD_NAND_ECC_BCH is not set
++# CONFIG_MTD_SM_COMMON is not set
++# CONFIG_MTD_NAND_DENALI is not set
++# CONFIG_MTD_NAND_GPIO is not set
++# CONFIG_MTD_NAND_OMAP_BCH_BUILD is not set
++# CONFIG_MTD_NAND_DISKONCHIP is not set
++# CONFIG_MTD_NAND_DOCG4 is not set
++# CONFIG_MTD_NAND_NANDSIM is not set
++# CONFIG_MTD_NAND_PLATFORM is not set
++# CONFIG_HISI_NAND_FS_MAY_NO_YAFFS2 is not set
++# CONFIG_HISI_NAND_ECC_STATUS_REPORT is not set
++CONFIG_HIFMC100_NAND=y
++CONFIG_HIFMC100_MAX_NAND_CHIP=1
++# CONFIG_HIFMC100_NAND_EDO_MODE is not set
++CONFIG_RW_H_WIDTH=10
++CONFIG_R_L_WIDTH=10
++CONFIG_W_L_WIDTH=10
++# CONFIG_HIFMC100_NAND_HARDWARE_PAGESIZE_ECC is not set
++CONFIG_HIFMC100_NAND_AUTO_PAGESIZE_ECC=y
++# CONFIG_HIFMC100_NAND_PAGESIZE_AUTO_ECC_NONE is not set
++# CONFIG_MTD_ONENAND is not set
++
++#
++# LPDDR & LPDDR2 PCM memory drivers
++#
++# CONFIG_MTD_LPDDR is not set
++# CONFIG_MTD_LPDDR2_NVM is not set
++# CONFIG_MTD_SPI_NOR is not set
++# CONFIG_MTD_UBI is not set
++CONFIG_DTC=y
++CONFIG_OF=y
++
++#
++# Device Tree and Open Firmware support
++#
++# 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_NET=y
++CONFIG_OF_MDIO=y
++CONFIG_OF_MTD=y
++CONFIG_OF_RESERVED_MEM=y
++CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
++# CONFIG_PARPORT is not set
++CONFIG_BLK_DEV=y
++# CONFIG_BLK_DEV_NULL_BLK is not set
++# CONFIG_BLK_DEV_COW_COMMON is not set
++# CONFIG_BLK_DEV_LOOP 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=65536
++# 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_DUMMY_IRQ 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_UID_STAT is not set
++# CONFIG_BMP085_I2C is not set
++# CONFIG_BMP085_SPI is not set
++# CONFIG_USB_SWITCH_FSA9480 is not set
++# CONFIG_LATTICE_ECP3_CONFIG is not set
++# CONFIG_SRAM is not set
++# CONFIG_C2PORT is not set
++
++#
++# EEPROM support
++#
++# CONFIG_EEPROM_AT24 is not set
++# CONFIG_EEPROM_AT25 is not set
++# CONFIG_EEPROM_LEGACY is not set
++# CONFIG_EEPROM_MAX6875 is not set
++# CONFIG_EEPROM_93CX6 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
++
++#
++# Intel MIC Bus Driver
++#
++
++#
++# Intel MIC Host Driver
++#
++
++#
++# Intel MIC Card Driver
++#
++# CONFIG_ECHO is not set
++# CONFIG_CXL_BASE is not set
++
++#
++# hisi 'himm/himd.l/himc'support
++#
++CONFIG_HISI_REG=y
++
++#
++# SCSI device support
++#
++CONFIG_SCSI_MOD=y
++# CONFIG_RAID_ATTRS is not set
++CONFIG_SCSI=y
++CONFIG_SCSI_DMA=y
++# CONFIG_SCSI_NETLINK is not set
++# CONFIG_SCSI_MQ_DEFAULT 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_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 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_NET_CORE=y
++# CONFIG_BONDING is not set
++# CONFIG_DUMMY is not set
++# CONFIG_EQUALIZER is not set
++# CONFIG_NET_TEAM is not set
++# CONFIG_MACVLAN is not set
++# CONFIG_VXLAN is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_TUN is not set
++# CONFIG_VETH is not set
++# CONFIG_NLMON is not set
++
++#
++# 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_NET_DSA_MV88E6171 is not set
++# CONFIG_NET_DSA_BCM_SF2 is not set
++CONFIG_ETHERNET=y
++# CONFIG_ALTERA_TSE is not set
++# CONFIG_NET_XGENE is not set
++# CONFIG_NET_VENDOR_ARC is not set
++# CONFIG_NET_CADENCE is not set
++# CONFIG_NET_VENDOR_BROADCOM is not set
++# CONFIG_NET_VENDOR_CIRRUS is not set
++# CONFIG_DM9000 is not set
++# CONFIG_DNET is not set
++# CONFIG_NET_VENDOR_FARADAY is not set
++CONFIG_NET_VENDOR_HISILICON=y
++# CONFIG_HIX5HD2_GMAC is not set
++# CONFIG_HISI_FEMAC is not set
++CONFIG_HIETH_GMAC=y
++CONFIG_HIGMAC_DESC_4WORD=y
++CONFIG_HIGMAC_RXCSUM=y
++CONFIG_RX_FLOW_CTRL_SUPPORT=y
++CONFIG_TX_FLOW_CTRL_SUPPORT=y
++CONFIG_TX_FLOW_CTRL_PAUSE_TIME=0xFFFF
++CONFIG_TX_FLOW_CTRL_PAUSE_INTERVAL=0xFFFF
++CONFIG_TX_FLOW_CTRL_ACTIVE_THRESHOLD=16
++CONFIG_TX_FLOW_CTRL_DEACTIVE_THRESHOLD=32
++# CONFIG_HIETH_SWITCH_FABRIC is not set
++# CONFIG_NET_VENDOR_INTEL is not set
++# CONFIG_NET_VENDOR_MARVELL is not set
++# CONFIG_NET_VENDOR_MICREL is not set
++# CONFIG_NET_VENDOR_MICROCHIP is not set
++# CONFIG_NET_VENDOR_NATSEMI is not set
++# CONFIG_ETHOC is not set
++# CONFIG_NET_VENDOR_QUALCOMM is not set
++# CONFIG_NET_VENDOR_SAMSUNG is not set
++# CONFIG_NET_VENDOR_SEEQ is not set
++# CONFIG_NET_VENDOR_SMSC is not set
++# CONFIG_NET_VENDOR_STMICRO is not set
++# CONFIG_NET_VENDOR_VIA is not set
++# CONFIG_NET_VENDOR_WIZNET is not set
++CONFIG_PHYLIB=y
++
++#
++# MII PHY device drivers
++#
++# CONFIG_AT803X_PHY is not set
++# CONFIG_AMD_PHY is not set
++# CONFIG_AMD_XGBE_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 is not set
++# CONFIG_BROADCOM_PHY is not set
++# CONFIG_BCM7XXX_PHY is not set
++# CONFIG_BCM87XX_PHY is not set
++# CONFIG_ICPLUS_PHY is not set
++# CONFIG_REALTEK_PHY is not set
++# CONFIG_NATIONAL_PHY is not set
++# CONFIG_STE10XP is not set
++# CONFIG_LSI_ET1011C_PHY is not set
++# CONFIG_MICREL_PHY is not set
++# CONFIG_FIXED_PHY is not set
++# CONFIG_MDIO_BITBANG is not set
++# CONFIG_MDIO_BUS_MUX_GPIO is not set
++# CONFIG_MDIO_BUS_MUX_MMIOREG is not set
++# CONFIG_MDIO_BCM_UNIMAC is not set
++# CONFIG_MDIO_HISI_FEMAC is not set
++CONFIG_MDIO_HISI_GEMAC=y
++# CONFIG_MICREL_KS8995MA is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++CONFIG_USB_NET_DRIVERS=y
++# 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_RTL8152 is not set
++# CONFIG_USB_USBNET is not set
++# CONFIG_USB_IPHETH is not set
++# CONFIG_WLAN is not set
++
++#
++# Enable WiMAX (Networking options) to see the WiMAX drivers
++#
++# CONFIG_WAN is not set
++# CONFIG_ISDN is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
++# CONFIG_INPUT_POLLDEV is not set
++# CONFIG_INPUT_SPARSEKMAP is not set
++# CONFIG_INPUT_MATRIXKMAP is not set
++
++#
++# Userland interfaces
++#
++CONFIG_INPUT_MOUSEDEV=y
++CONFIG_INPUT_MOUSEDEV_PSAUX=y
++CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
++CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
++# CONFIG_INPUT_JOYDEV is not set
++CONFIG_INPUT_EVDEV=y
++# CONFIG_INPUT_EVBUG is not set
++# CONFIG_INPUT_KEYRESET is not set
++# CONFIG_INPUT_KEYCOMBO is not set
++
++#
++# Input Device Drivers
++#
++CONFIG_INPUT_KEYBOARD=y
++# CONFIG_KEYBOARD_ADP5588 is not set
++# CONFIG_KEYBOARD_ADP5589 is not set
++CONFIG_KEYBOARD_ATKBD=y
++# CONFIG_KEYBOARD_QT1070 is not set
++# CONFIG_KEYBOARD_QT2160 is not set
++# CONFIG_KEYBOARD_LKKBD is not set
++# CONFIG_KEYBOARD_GPIO is not set
++# CONFIG_KEYBOARD_GPIO_POLLED is not set
++# 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 is not set
++# CONFIG_KEYBOARD_CAP1106 is not set
++CONFIG_INPUT_MOUSE=y
++CONFIG_MOUSE_PS2=y
++CONFIG_MOUSE_PS2_ALPS=y
++CONFIG_MOUSE_PS2_LOGIPS2PP=y
++CONFIG_MOUSE_PS2_SYNAPTICS=y
++CONFIG_MOUSE_PS2_CYPRESS=y
++CONFIG_MOUSE_PS2_TRACKPOINT=y
++# CONFIG_MOUSE_PS2_ELANTECH is not set
++# CONFIG_MOUSE_PS2_SENTELIC is not set
++# CONFIG_MOUSE_PS2_TOUCHKIT is not set
++# CONFIG_MOUSE_SERIAL is not set
++# CONFIG_MOUSE_APPLETOUCH is not set
++# CONFIG_MOUSE_BCM5974 is not set
++# CONFIG_MOUSE_CYAPA is not set
++# CONFIG_MOUSE_VSXXXAA is not set
++# CONFIG_MOUSE_GPIO is not set
++# CONFIG_MOUSE_SYNAPTICS_I2C is not set
++# CONFIG_MOUSE_SYNAPTICS_USB is not set
++# CONFIG_INPUT_JOYSTICK is not set
++# CONFIG_INPUT_TABLET is not set
++# CONFIG_INPUT_TOUCHSCREEN is not set
++# CONFIG_INPUT_MISC is not set
++
++#
++# Hardware I/O ports
++#
++CONFIG_SERIO=y
++CONFIG_SERIO_SERPORT=y
++# CONFIG_SERIO_AMBAKMI is not set
++CONFIG_SERIO_LIBPS2=y
++# CONFIG_SERIO_RAW is not set
++# CONFIG_SERIO_ALTERA_PS2 is not set
++# CONFIG_SERIO_PS2MULT is not set
++# CONFIG_SERIO_ARC_PS2 is not set
++# CONFIG_SERIO_APBPS2 is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++CONFIG_TTY=y
++CONFIG_VT=y
++CONFIG_CONSOLE_TRANSLATIONS=y
++CONFIG_VT_CONSOLE=y
++CONFIG_VT_CONSOLE_SLEEP=y
++CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
++CONFIG_UNIX98_PTYS=y
++# CONFIG_DEVPTS_MULTIPLE_INSTANCES 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_DEVMEM=y
++CONFIG_DEVKMEM=y
++
++#
++# Serial drivers
++#
++CONFIG_SERIAL_EARLYCON=y
++# CONFIG_SERIAL_8250 is not set
++
++#
++# Non-8250 serial port support
++#
++# CONFIG_SERIAL_AMBA_PL010 is not set
++CONFIG_SERIAL_AMBA_PL011=y
++CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
++# CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST is not set
++# 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_SC16IS7XX is not set
++# CONFIG_SERIAL_ALTERA_JTAGUART is not set
++# CONFIG_SERIAL_ALTERA_UART is not set
++# CONFIG_SERIAL_IFX6X60 is not set
++# CONFIG_SERIAL_XILINX_PS_UART is not set
++# CONFIG_SERIAL_ARC is not set
++# CONFIG_SERIAL_FSL_LPUART is not set
++# CONFIG_SERIAL_ST_ASC is not set
++# CONFIG_HVC_DCC is not set
++# CONFIG_IPMI_HANDLER is not set
++# CONFIG_HW_RANDOM is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++# CONFIG_DCC_TTY is not set
++# CONFIG_XILLYBUS is not set
++
++#
++# I2C support
++#
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++# CONFIG_I2C_COMPAT is not set
++CONFIG_I2C_CHARDEV=y
++# CONFIG_I2C_MUX is not set
++# CONFIG_I2C_HELPER_AUTO is not set
++# CONFIG_I2C_SMBUS is not set
++
++#
++# I2C Algorithms
++#
++# CONFIG_I2C_ALGOBIT is not set
++# CONFIG_I2C_ALGOPCF is not set
++# CONFIG_I2C_ALGOPCA is not set
++
++#
++# I2C Hardware Bus support
++#
++
++#
++# I2C system bus drivers (mostly embedded / system-on-chip)
++#
++# CONFIG_I2C_CBUS_GPIO is not set
++# CONFIG_I2C_DESIGNWARE_PLATFORM is not set
++# CONFIG_I2C_GPIO is not set
++# CONFIG_I2C_HIBVT is not set
++CONFIG_I2C_HISI_V110=y
++# CONFIG_I2C_NOMADIK 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_RK3X 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_ROBOTFUZZ_OSIF 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_CADENCE is not set
++# CONFIG_SPI_GPIO is not set
++# CONFIG_SPI_FSL_SPI is not set
++# CONFIG_SPI_OC_TINY is not set
++CONFIG_SPI_PL022=y
++# CONFIG_SPI_PXA2XX_PCI is not set
++# CONFIG_SPI_ROCKCHIP 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=y
++# CONFIG_SPI_TLE62X0 is not set
++# CONFIG_SPMI is not set
++# CONFIG_HSI is not set
++
++#
++# PPS support
++#
++# CONFIG_PPS is not set
++
++#
++# PPS generators support
++#
++
++#
++# PTP clock support
++#
++# CONFIG_PTP_1588_CLOCK is not set
++
++#
++# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
++#
++CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
++CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
++CONFIG_GPIOLIB=y
++CONFIG_GPIO_DEVRES=y
++CONFIG_OF_GPIO=y
++CONFIG_GPIOLIB_IRQCHIP=y
++# CONFIG_DEBUG_GPIO is not set
++CONFIG_GPIO_SYSFS=y
++
++#
++# Memory mapped GPIO drivers:
++#
++# CONFIG_GPIO_GENERIC_PLATFORM is not set
++# CONFIG_GPIO_DWAPB is not set
++# CONFIG_GPIO_EM is not set
++# CONFIG_GPIO_ZEVIO is not set
++CONFIG_GPIO_PL061=y
++# CONFIG_GPIO_SCH311X is not set
++# CONFIG_GPIO_SYSCON is not set
++# CONFIG_GPIO_GRGPIO is not set
++
++#
++# I2C GPIO expanders:
++#
++# CONFIG_GPIO_MAX7300 is not set
++# CONFIG_GPIO_MAX732X is not set
++# CONFIG_GPIO_PCA953X is not set
++# CONFIG_GPIO_PCF857X is not set
++# CONFIG_GPIO_SX150X is not set
++# CONFIG_GPIO_ADP5588 is not set
++# CONFIG_GPIO_ADNP is not set
++
++#
++# PCI GPIO expanders:
++#
++
++#
++# SPI GPIO expanders:
++#
++# CONFIG_GPIO_MAX7301 is not set
++# CONFIG_GPIO_MCP23S08 is not set
++# CONFIG_GPIO_MC33880 is not set
++# CONFIG_GPIO_74X164 is not set
++
++#
++# AC97 GPIO expanders:
++#
++
++#
++# LPC GPIO expanders:
++#
++
++#
++# MODULbus GPIO expanders:
++#
++
++#
++# USB GPIO expanders:
++#
++# CONFIG_W1 is not set
++CONFIG_POWER_SUPPLY=y
++# CONFIG_POWER_SUPPLY_DEBUG is not set
++# CONFIG_PDA_POWER is not set
++# CONFIG_TEST_POWER is not set
++# CONFIG_BATTERY_DS2780 is not set
++# CONFIG_BATTERY_DS2781 is not set
++# CONFIG_BATTERY_DS2782 is not set
++# CONFIG_BATTERY_SBS is not set
++# CONFIG_BATTERY_BQ27x00 is not set
++# CONFIG_BATTERY_MAX17040 is not set
++# CONFIG_BATTERY_MAX17042 is not set
++# CONFIG_CHARGER_MAX8903 is not set
++# CONFIG_CHARGER_LP8727 is not set
++# CONFIG_CHARGER_GPIO is not set
++# CONFIG_CHARGER_BQ2415X is not set
++# CONFIG_CHARGER_BQ24190 is not set
++# CONFIG_CHARGER_BQ24735 is not set
++# CONFIG_CHARGER_SMB347 is not set
++CONFIG_POWER_RESET=y
++# CONFIG_POWER_RESET_BRCMSTB is not set
++# CONFIG_POWER_RESET_GPIO is not set
++# CONFIG_POWER_RESET_GPIO_RESTART is not set
++CONFIG_POWER_RESET_HISI=y
++# CONFIG_POWER_RESET_LTC2952 is not set
++# CONFIG_POWER_RESET_RESTART is not set
++# CONFIG_POWER_RESET_VERSATILE is not set
++# CONFIG_POWER_RESET_SYSCON is not set
++# CONFIG_POWER_AVS is not set
++# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
++# CONFIG_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=y
++# CONFIG_MFD_AS3711 is not set
++# CONFIG_MFD_AS3722 is not set
++# CONFIG_PMIC_ADP5520 is not set
++# CONFIG_MFD_AAT2870_CORE is not set
++# CONFIG_MFD_BCM590XX is not set
++# CONFIG_MFD_AXP20X is not set
++# CONFIG_MFD_CROS_EC is not set
++# CONFIG_MFD_ASIC3 is not set
++# CONFIG_PMIC_DA903X is not set
++# CONFIG_MFD_DA9052_SPI is not set
++# CONFIG_MFD_DA9052_I2C is not set
++# CONFIG_MFD_DA9055 is not set
++# CONFIG_MFD_DA9063 is not set
++# CONFIG_MFD_MC13XXX_SPI is not set
++# CONFIG_MFD_MC13XXX_I2C is not set
++# CONFIG_MFD_HI6421_PMIC is not set
++CONFIG_MFD_HISI_FMC=y
++# CONFIG_HTC_EGPIO is not set
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_HTC_I2CPLD is not set
++# CONFIG_INTEL_SOC_PMIC is not set
++# CONFIG_MFD_KEMPLD is not set
++# CONFIG_MFD_88PM800 is not set
++# CONFIG_MFD_88PM805 is not set
++# CONFIG_MFD_88PM860X is not set
++# CONFIG_MFD_MAX14577 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_MENF21BMC is not set
++# CONFIG_EZX_PCAP is not set
++# CONFIG_MFD_VIPERBOARD is not set
++# CONFIG_MFD_RETU is not set
++# CONFIG_MFD_PCF50633 is not set
++# CONFIG_MFD_PM8921_CORE is not set
++# CONFIG_MFD_RTSX_USB is not set
++# CONFIG_MFD_RC5T583 is not set
++# CONFIG_MFD_RK808 is not set
++# CONFIG_MFD_RN5T618 is not set
++# CONFIG_MFD_SEC_CORE is not set
++# CONFIG_MFD_SI476X_CORE is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_MFD_SMSC is not set
++# CONFIG_ABX500_CORE is not set
++# CONFIG_MFD_STMPE is not set
++CONFIG_MFD_SYSCON=y
++# CONFIG_MFD_TI_AM335X_TSCADC is not set
++# CONFIG_MFD_LP3943 is not set
++# CONFIG_MFD_LP8788 is not set
++# CONFIG_MFD_PALMAS is not set
++# CONFIG_TPS6105X is not set
++# CONFIG_TPS65010 is not set
++# CONFIG_TPS6507X is not set
++# CONFIG_MFD_TPS65090 is not set
++# CONFIG_MFD_TPS65217 is not set
++# CONFIG_MFD_TPS65218 is not set
++# CONFIG_MFD_TPS6586X is not set
++# CONFIG_MFD_TPS65910 is not set
++# CONFIG_MFD_TPS65912 is not set
++# CONFIG_MFD_TPS65912_I2C is not set
++# CONFIG_MFD_TPS65912_SPI is not set
++# CONFIG_MFD_TPS80031 is not set
++# CONFIG_TWL4030_CORE is not set
++# CONFIG_TWL6040_CORE is not set
++# CONFIG_MFD_WL1273_CORE is not set
++# CONFIG_MFD_LM3533 is not set
++# CONFIG_MFD_TC3589X is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_MFD_T7L66XB is not set
++# CONFIG_MFD_TC6387XB is not set
++# CONFIG_MFD_TC6393XB is not set
++# CONFIG_MFD_ARIZONA_I2C is not set
++# CONFIG_MFD_ARIZONA_SPI is not set
++# CONFIG_MFD_WM8400 is not set
++# CONFIG_MFD_WM831X_I2C is not set
++# CONFIG_MFD_WM831X_SPI is not set
++# CONFIG_MFD_WM8350_I2C is not set
++# CONFIG_MFD_WM8994 is not set
++CONFIG_REGULATOR=y
++# CONFIG_REGULATOR_DEBUG is not set
++# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
++# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
++# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
++# CONFIG_REGULATOR_ACT8865 is not set
++# CONFIG_REGULATOR_AD5398 is not set
++# CONFIG_REGULATOR_ANATOP is not set
++# CONFIG_REGULATOR_DA9210 is not set
++# CONFIG_REGULATOR_DA9211 is not set
++# CONFIG_REGULATOR_FAN53555 is not set
++# CONFIG_REGULATOR_GPIO is not set
++# CONFIG_REGULATOR_ISL9305 is not set
++# CONFIG_REGULATOR_ISL6271A is not set
++# CONFIG_REGULATOR_LP3971 is not set
++# CONFIG_REGULATOR_LP3972 is not set
++# CONFIG_REGULATOR_LP872X is not set
++# CONFIG_REGULATOR_LP8755 is not set
++# CONFIG_REGULATOR_LTC3589 is not set
++# CONFIG_REGULATOR_MAX1586 is not set
++# CONFIG_REGULATOR_MAX8649 is not set
++# CONFIG_REGULATOR_MAX8660 is not set
++# CONFIG_REGULATOR_MAX8952 is not set
++# CONFIG_REGULATOR_MAX8973 is not set
++# CONFIG_REGULATOR_PFUZE100 is not set
++# CONFIG_REGULATOR_TPS51632 is not set
++# CONFIG_REGULATOR_TPS62360 is not set
++# CONFIG_REGULATOR_TPS65023 is not set
++# CONFIG_REGULATOR_TPS6507X is not set
++# CONFIG_REGULATOR_TPS6524X is not set
++# CONFIG_MEDIA_SUPPORT is not set
++
++#
++# Graphics support
++#
++# CONFIG_IMX_IPUV3_CORE is not set
++
++#
++# Direct Rendering Manager
++#
++# CONFIG_DRM is not set
++
++#
++# Frame buffer Devices
++#
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++CONFIG_FB_CMDLINE=y
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++# CONFIG_FB_CFB_FILLRECT is not set
++# CONFIG_FB_CFB_COPYAREA is not set
++# CONFIG_FB_CFB_IMAGEBLIT is not set
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# 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_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_ARMCLCD is not set
++# CONFIG_FB_OPENCORES is not set
++# CONFIG_FB_S1D13XXX is not set
++# CONFIG_FB_SMSCUFX is not set
++# CONFIG_FB_UDL is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_BROADSHEET is not set
++# CONFIG_FB_AUO_K190X is not set
++# CONFIG_FB_SIMPLE is not set
++# CONFIG_FB_SSD1307 is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++# CONFIG_VGASTATE is not set
++
++#
++# Console display driver support
++#
++CONFIG_DUMMY_CONSOLE=y
++# CONFIG_FRAMEBUFFER_CONSOLE is not set
++# CONFIG_LOGO is not set
++# CONFIG_SOUND is not set
++
++#
++# HID support
++#
++CONFIG_HID=y
++# CONFIG_HID_BATTERY_STRENGTH is not set
++# CONFIG_HIDRAW is not set
++# CONFIG_UHID is not set
++CONFIG_HID_GENERIC=y
++
++#
++# Special HID drivers
++#
++CONFIG_HID_A4TECH=y
++# CONFIG_HID_ACRUX is not set
++CONFIG_HID_APPLE=y
++# CONFIG_HID_APPLEIR is not set
++# CONFIG_HID_AUREAL is not set
++CONFIG_HID_BELKIN=y
++CONFIG_HID_CHERRY=y
++CONFIG_HID_CHICONY=y
++# CONFIG_HID_CP2112 is not set
++CONFIG_HID_CYPRESS=y
++# CONFIG_HID_DRAGONRISE is not set
++# CONFIG_HID_EMS_FF is not set
++# CONFIG_HID_ELECOM is not set
++# CONFIG_HID_ELO is not set
++CONFIG_HID_EZKEY=y
++# CONFIG_HID_HOLTEK is not set
++# CONFIG_HID_HUION 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_ICADE is not set
++# CONFIG_HID_TWINHAN is not set
++CONFIG_HID_KENSINGTON=y
++# CONFIG_HID_LCPOWER is not set
++# CONFIG_HID_LENOVO is not set
++CONFIG_HID_LOGITECH=y
++# CONFIG_HID_LOGITECH_HIDPP is not set
++# CONFIG_LOGITECH_FF is not set
++# CONFIG_LOGIRUMBLEPAD2_FF is not set
++# CONFIG_LOGIG940_FF is not set
++# CONFIG_LOGIWHEELS_FF is not set
++# CONFIG_HID_MAGICMOUSE is not set
++CONFIG_HID_MICROSOFT=y
++CONFIG_HID_MONTEREY=y
++# 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_PENMOUNT is not set
++# CONFIG_HID_PETALYNX is not set
++# CONFIG_HID_PICOLCD is not set
++# CONFIG_HID_PRIMAX is not set
++# CONFIG_HID_ROCCAT is not set
++# CONFIG_HID_SAITEK is not set
++# CONFIG_HID_SAMSUNG is not set
++# CONFIG_HID_SPEEDLINK is not set
++# CONFIG_HID_STEELSERIES is not set
++# CONFIG_HID_SUNPLUS is not set
++# CONFIG_HID_RMI 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_XINMO is not set
++# CONFIG_HID_ZEROPLUS is not set
++# CONFIG_HID_ZYDACRON is not set
++# CONFIG_HID_SENSOR_HUB is not set
++
++#
++# USB HID support
++#
++CONFIG_USB_HID=y
++# CONFIG_HID_PID is not set
++# CONFIG_USB_HIDDEV is not set
++
++#
++# I2C HID support
++#
++# CONFIG_I2C_HID is not set
++CONFIG_USB_OHCI_LITTLE_ENDIAN=y
++CONFIG_USB_SUPPORT=y
++CONFIG_USB_COMMON=y
++CONFIG_USB_ARCH_HAS_HCD=y
++CONFIG_USB=y
++# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
++
++#
++# Miscellaneous USB options
++#
++CONFIG_USB_DEFAULT_PERSIST=y
++# CONFIG_USB_DYNAMIC_MINORS is not set
++# CONFIG_USB_OTG_WHITELIST is not set
++# CONFIG_USB_OTG_FSM is not set
++# CONFIG_USB_MON is not set
++# CONFIG_USB_WUSB_CBAF is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_C67X00_HCD is not set
++CONFIG_USB_XHCI_HCD=y
++CONFIG_USB_XHCI_PLATFORM=y
++CONFIG_USB_XHCI_HISILICON=y
++CONFIG_USB_EHCI_HCD=y
++# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
++CONFIG_USB_EHCI_TT_NEWSCHED=y
++CONFIG_USB_EHCI_HCD_PLATFORM=y
++# 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_FUSBH200_HCD is not set
++# CONFIG_USB_FOTG210_HCD is not set
++# CONFIG_USB_MAX3421_HCD is not set
++CONFIG_USB_OHCI_HCD=y
++CONFIG_USB_OHCI_HCD_PLATFORM=y
++# CONFIG_USB_SL811_HCD is not set
++# CONFIG_USB_R8A66597_HCD is not set
++# CONFIG_USB_HCD_TEST_MODE is not set
++
++#
++# USB Device Class drivers
++#
++# CONFIG_USB_ACM is not set
++# CONFIG_USB_PRINTER is not set
++# CONFIG_USB_WDM is not set
++# CONFIG_USB_TMC is not set
++
++#
++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
++#
++
++#
++# also be needed; see USB_STORAGE Help for more info
++#
++CONFIG_USB_STORAGE=y
++# CONFIG_USB_STORAGE_DEBUG is not set
++# CONFIG_USB_STORAGE_REALTEK is not set
++# CONFIG_USB_STORAGE_DATAFAB is not set
++# CONFIG_USB_STORAGE_FREECOM is not set
++# CONFIG_USB_STORAGE_ISD200 is not set
++# CONFIG_USB_STORAGE_USBAT is not set
++# CONFIG_USB_STORAGE_SDDR09 is not set
++# CONFIG_USB_STORAGE_SDDR55 is not set
++# CONFIG_USB_STORAGE_JUMPSHOT is not set
++# CONFIG_USB_STORAGE_ALAUDA is not set
++# CONFIG_USB_STORAGE_ONETOUCH is not set
++# CONFIG_USB_STORAGE_KARMA is not set
++# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
++# CONFIG_USB_STORAGE_ENE_UB6250 is not set
++# CONFIG_USB_UAS is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++# CONFIG_USBIP_CORE is not set
++# CONFIG_USB_MUSB_HDRC is not set
++# CONFIG_USB_DWC3 is not set
++# CONFIG_USB_DWC2 is not set
++# CONFIG_USB_CHIPIDEA is not set
++
++#
++# USB port drivers
++#
++# CONFIG_USB_SERIAL is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
++# CONFIG_USB_SEVSEG is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
++# CONFIG_USB_APPLEDISPLAY is not set
++# CONFIG_USB_SISUSBVGA is not set
++# CONFIG_USB_LD is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
++# CONFIG_USB_IOWARRIOR is not set
++# CONFIG_USB_TEST is not set
++# CONFIG_USB_EHSET_TEST_FIXTURE is not set
++# CONFIG_USB_ISIGHTFW is not set
++# CONFIG_USB_YUREX is not set
++# CONFIG_USB_EZUSB_FX2 is not set
++# CONFIG_USB_HSIC_USB3503 is not set
++# CONFIG_USB_LINK_LAYER_TEST is not set
++
++#
++# USB Physical Layer drivers
++#
++# CONFIG_USB_PHY is not set
++# CONFIG_USB_OTG_WAKELOCK is not set
++# CONFIG_NOP_USB_XCEIV is not set
++# CONFIG_AM335X_PHY_USB is not set
++# CONFIG_USB_GPIO_VBUS is not set
++# CONFIG_USB_ISP1301 is not set
++# CONFIG_USB_ULPI is not set
++CONFIG_USB_GADGET=y
++# CONFIG_USB_GADGET_DEBUG is not set
++# CONFIG_USB_GADGET_DEBUG_FILES is not set
++CONFIG_USB_GADGET_VBUS_DRAW=2
++CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2
++
++#
++# USB Peripheral Controller
++#
++# CONFIG_USB_FUSB300 is not set
++# CONFIG_USB_FOTG210_UDC is not set
++# CONFIG_USB_GR_UDC is not set
++# CONFIG_USB_R8A66597 is not set
++# CONFIG_USB_PXA27X is not set
++# CONFIG_USB_MV_UDC is not set
++CONFIG_HIUSB_DEVICE2_0=y
++CONFIG_USB_HISI_UDC=m
++# CONFIG_USB_AUTO_SWITCH is not set
++# CONFIG_HIUSB_DEVICE3_0 is not set
++# CONFIG_USB_MV_U3D is not set
++# CONFIG_USB_M66592 is not set
++# CONFIG_USB_NET2272 is not set
++# CONFIG_USB_GADGET_XILINX is not set
++# CONFIG_USB_DUMMY_HCD is not set
++CONFIG_USB_LIBCOMPOSITE=m
++CONFIG_USB_F_ACM=m
++CONFIG_USB_U_SERIAL=m
++CONFIG_USB_U_ETHER=m
++CONFIG_USB_F_SERIAL=m
++CONFIG_USB_F_OBEX=m
++CONFIG_USB_F_ECM=m
++CONFIG_USB_F_SUBSET=m
++CONFIG_USB_F_RNDIS=m
++CONFIG_USB_F_MASS_STORAGE=m
++# CONFIG_USB_CONFIGFS is not set
++# CONFIG_USB_ZERO 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 is not set
++# CONFIG_USB_FUNCTIONFS is not set
++CONFIG_USB_MASS_STORAGE=m
++CONFIG_USB_G_SERIAL=m
++# CONFIG_USB_G_PRINTER is not set
++# CONFIG_USB_CDC_COMPOSITE is not set
++# CONFIG_USB_G_ACM_MS is not set
++# CONFIG_USB_G_MULTI is not set
++# CONFIG_USB_G_HID is not set
++# CONFIG_USB_G_DBGP is not set
++# CONFIG_UWB is not set
++CONFIG_MMC=y
++# CONFIG_MMC_DEBUG is not set
++# CONFIG_MMC_CLKGATE is not set
++CONFIG_MMC_EMBEDDED_SDIO=y
++# CONFIG_MMC_PARANOID_SD_INIT is not set
++
++#
++# MMC/SD/SDIO Card Drivers
++#
++CONFIG_MMC_BLOCK=y
++CONFIG_MMC_BLOCK_MINORS=8
++CONFIG_MMC_BLOCK_BOUNCE=y
++# CONFIG_MMC_BLOCK_DEFERRED_RESUME is not set
++# CONFIG_SDIO_UART is not set
++# CONFIG_MMC_TEST is not set
++
++#
++# MMC/SD/SDIO Host Controller Drivers
++#
++# CONFIG_MMC_ARMMMCI is not set
++# CONFIG_MMC_SDHCI is not set
++# CONFIG_MMC_DW is not set
++# CONFIG_MMC_VUB300 is not set
++# CONFIG_MMC_USHC is not set
++# CONFIG_MMC_USDHI6ROL0 is not set
++CONFIG_HIMCIV200=y
++CONFIG_SEND_AUTO_STOP=y
++CONFIG_DETECT_CARD_TIME=200
++# CONFIG_MEMSTICK is not set
++# CONFIG_NEW_LEDS is not set
++# CONFIG_SWITCH is not set
++# CONFIG_ACCESSIBILITY is not set
++# CONFIG_EDAC is not set
++CONFIG_RTC_LIB=y
++# CONFIG_RTC_CLASS is not set
++# CONFIG_DMADEVICES is not set
++# CONFIG_AUXDISPLAY is not set
++# CONFIG_UIO is not set
++# CONFIG_VIRT_DRIVERS is not set
++
++#
++# Virtio drivers
++#
++# CONFIG_VIRTIO_MMIO is not set
++
++#
++# Microsoft Hyper-V guest support
++#
++# CONFIG_STAGING is not set
++
++#
++# SOC (System On Chip) specific Drivers
++#
++# CONFIG_SOC_TI is not set
++CONFIG_CLKDEV_LOOKUP=y
++CONFIG_HAVE_CLK_PREPARE=y
++CONFIG_COMMON_CLK=y
++
++#
++# Common Clock Framework
++#
++# CONFIG_COMMON_CLK_SI5351 is not set
++# CONFIG_COMMON_CLK_SI570 is not set
++# CONFIG_COMMON_CLK_PXA is not set
++# CONFIG_COMMON_CLK_QCOM is not set
++
++#
++# Hardware Spinlock drivers
++#
++
++#
++# Clock Source drivers
++#
++CONFIG_CLKSRC_OF=y
++CONFIG_CLKSRC_MMIO=y
++CONFIG_ARM_ARCH_TIMER=y
++CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y
++# CONFIG_ATMEL_PIT is not set
++# CONFIG_SH_TIMER_CMT is not set
++# CONFIG_SH_TIMER_MTU2 is not set
++# CONFIG_SH_TIMER_TMU is not set
++# CONFIG_EM_TIMER_STI is not set
++# CONFIG_CLKSRC_VERSATILE is not set
++# CONFIG_MAILBOX is not set
++# CONFIG_IOMMU_SUPPORT is not set
++
++#
++# Remoteproc drivers
++#
++# CONFIG_STE_MODEM_RPROC is not set
++
++#
++# Rpmsg drivers
++#
++
++#
++# SOC (System On Chip) specific Drivers
++#
++# 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
++CONFIG_IRQCHIP=y
++CONFIG_ARM_GIC=y
++# CONFIG_IPACK_BUS is not set
++CONFIG_ARCH_HAS_RESET_CONTROLLER=y
++CONFIG_RESET_CONTROLLER=y
++# CONFIG_FMC is not set
++
++#
++# PHY Subsystem
++#
++CONFIG_GENERIC_PHY=y
++# CONFIG_BCM_KONA_USB2_PHY is not set
++CONFIG_PHY_HISI_INNO_USB2=y
++CONFIG_PHY_HISI_USB3=y
++# CONFIG_POWERCAP is not set
++# CONFIG_MCB is not set
++CONFIG_HI_DMAC=y
++CONFIG_HI_DMAC_IO_BASE=0x10030000
++CONFIG_HI_DMAC_CHANNEL_NUM=4
++
++#
++# Hisilicon driver support
++#
++# CONFIG_CMA_MEM_SHARED is not set
++# CONFIG_CMA_ADVANCE_SHARE is not set
++
++#
++# File systems
++#
++CONFIG_DCACHE_WORD_ACCESS=y
++# CONFIG_EXT2_FS is not set
++# CONFIG_EXT3_FS is not set
++CONFIG_EXT4_FS=y
++CONFIG_EXT4_USE_FOR_EXT23=y
++# CONFIG_EXT4_FS_POSIX_ACL is not set
++# CONFIG_EXT4_FS_SECURITY is not set
++# CONFIG_EXT4_DEBUG is not set
++CONFIG_JBD2=y
++# CONFIG_JBD2_DEBUG is not set
++CONFIG_FS_MBCACHE=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_BTRFS_FS is not set
++# CONFIG_NILFS2_FS is not set
++CONFIG_FS_POSIX_ACL=y
++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 is not set
++# CONFIG_FUSE_FS is not set
++# CONFIG_OVERLAY_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_KERNFS=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=m
++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_YAFFS_FS=y
++CONFIG_YAFFS_YAFFS1=y
++# CONFIG_YAFFS_9BYTE_TAGS is not set
++# CONFIG_YAFFS_DOES_ECC is not set
++CONFIG_YAFFS_YAFFS2=y
++CONFIG_YAFFS_AUTO_YAFFS2=y
++# CONFIG_YAFFS_DISABLE_TAGS_ECC is not set
++# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
++# CONFIG_YAFFS_EMPTY_LOST_AND_FOUND is not set
++# CONFIG_YAFFS_DISABLE_BLOCK_REFRESHING is not set
++# CONFIG_YAFFS_DISABLE_BACKGROUND is not set
++# CONFIG_YAFFS_DISABLE_BAD_BLOCK_MARKING is not set
++CONFIG_YAFFS_XATTR=y
++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 is not set
++# CONFIG_JFFS2_FS_XATTR is not set
++# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
++CONFIG_JFFS2_ZLIB=y
++# CONFIG_JFFS2_LZO is not set
++CONFIG_JFFS2_RTIME=y
++# CONFIG_JFFS2_RUBIN 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 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 is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V2=y
++CONFIG_NFS_V3=y
++CONFIG_NFS_V3_ACL=y
++# CONFIG_NFS_V4 is not set
++# CONFIG_NFS_SWAP is not set
++# CONFIG_ROOT_NFS is not set
++# CONFIG_NFSD is not set
++CONFIG_GRACE_PERIOD=y
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_ACL_SUPPORT=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 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=y
++# CONFIG_DLM is not set
++
++#
++# Kernel hacking
++#
++
++#
++# printk and dmesg options
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4
++# CONFIG_BOOT_PRINTK_DELAY is not set
++
++#
++# Compile-time checks and compiler options
++#
++# CONFIG_DEBUG_INFO is not set
++# CONFIG_ENABLE_WARN_DEPRECATED is not set
++# CONFIG_ENABLE_MUST_CHECK is not set
++CONFIG_FRAME_WARN=1024
++# CONFIG_STRIP_ASM_SYMS is not set
++# CONFIG_READABLE_ASM is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++# CONFIG_DEBUG_FS is not set
++# CONFIG_HEADERS_CHECK is not set
++# CONFIG_DEBUG_SECTION_MISMATCH is not set
++# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
++# CONFIG_MAGIC_SYSRQ is not set
++CONFIG_DEBUG_KERNEL=y
++
++#
++# Memory Debugging
++#
++# 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_STACK_USAGE is not set
++# CONFIG_DEBUG_VM is not set
++CONFIG_DEBUG_MEMORY_INIT=y
++# CONFIG_DEBUG_PER_CPU_MAPS is not set
++# CONFIG_DEBUG_HIGHMEM is not set
++# CONFIG_DEBUG_SHIRQ is not set
++
++#
++# Debug Lockups and Hangs
++#
++# CONFIG_LOCKUP_DETECTOR is not set
++# CONFIG_DETECT_HUNG_TASK is not set
++# CONFIG_PANIC_ON_OOPS is not set
++CONFIG_PANIC_ON_OOPS_VALUE=0
++CONFIG_PANIC_TIMEOUT=0
++CONFIG_SCHED_DEBUG=y
++# CONFIG_SCHEDSTATS is not set
++# CONFIG_SCHED_STACK_END_CHECK is not set
++# CONFIG_TIMER_STATS is not set
++
++#
++# Lock Debugging (spinlocks, mutexes, etc...)
++#
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_LOCK_STAT is not set
++# CONFIG_DEBUG_ATOMIC_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_LOCK_TORTURE_TEST is not set
++CONFIG_STACKTRACE=y
++# CONFIG_DEBUG_KOBJECT is not set
++CONFIG_DEBUG_BUGVERBOSE=y
++# CONFIG_DEBUG_LIST is not set
++# CONFIG_DEBUG_PI_LIST is not set
++# CONFIG_DEBUG_SG is not set
++# CONFIG_DEBUG_NOTIFIERS is not set
++# CONFIG_DEBUG_CREDENTIALS is not set
++
++#
++# RCU Debugging
++#
++# CONFIG_SPARSE_RCU_POINTER is not set
++# CONFIG_TORTURE_TEST 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_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_NOTIFIER_ERROR_INJECTION is not set
++# CONFIG_FAULT_INJECTION 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 is not set
++
++#
++# Runtime Testing
++#
++# CONFIG_TEST_LIST_SORT is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_RBTREE_TEST is not set
++# CONFIG_INTERVAL_TREE_TEST is not set
++# CONFIG_PERCPU_TEST is not set
++# CONFIG_ATOMIC64_SELFTEST is not set
++# CONFIG_TEST_STRING_HELPERS is not set
++# CONFIG_TEST_KSTRTOX is not set
++# CONFIG_TEST_RHASHTABLE is not set
++# CONFIG_DMA_API_DEBUG is not set
++# CONFIG_TEST_LKM is not set
++# CONFIG_TEST_USER_COPY is not set
++# CONFIG_TEST_BPF is not set
++# CONFIG_TEST_FIRMWARE is not set
++# CONFIG_TEST_UDELAY is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_KGDB is not set
++# CONFIG_ARM_PTDUMP is not set
++CONFIG_STRICT_DEVMEM=y
++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_DEBUG_UART_PL01X is not set
++# CONFIG_DEBUG_UART_8250 is not set
++# CONFIG_DEBUG_UART_BCM63XX is not set
++CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"
++# CONFIG_OC_ETM is not set
++# CONFIG_PID_IN_CONTEXTIDR is not set
++# CONFIG_DEBUG_SET_MODULE_RONX is not set
++# CONFIG_CORESIGHT is not set
++
++#
++# 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_HASH=y
++CONFIG_CRYPTO_HASH2=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_PCRYPT is not set
++# CONFIG_CRYPTO_CRYPTD is not set
++# CONFIG_CRYPTO_MCRYPTD 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_CMAC is not set
++# CONFIG_CRYPTO_HMAC is not set
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_VMAC is not set
++
++#
++# Digest
++#
++CONFIG_CRYPTO_CRC32C=y
++# CONFIG_CRYPTO_CRC32 is not set
++# CONFIG_CRYPTO_CRCT10DIF 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_SHA1_ARM_NEON is not set
++# CONFIG_CRYPTO_SHA256 is not set
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_SHA512_ARM_NEON 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_AES_ARM_BS 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
++# CONFIG_CRYPTO_LZ4 is not set
++# CONFIG_CRYPTO_LZ4HC is not set
++
++#
++# Random Number Generation
++#
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++# CONFIG_CRYPTO_DRBG_MENU is not set
++# CONFIG_CRYPTO_USER_API_HASH is not set
++# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
++CONFIG_CRYPTO_HW=y
++# CONFIG_BINARY_PRINTF is not set
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++CONFIG_GENERIC_STRNCPY_FROM_USER=y
++CONFIG_GENERIC_STRNLEN_USER=y
++CONFIG_GENERIC_NET_UTILS=y
++CONFIG_GENERIC_PCI_IOMAP=y
++CONFIG_GENERIC_IO=y
++CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
++# CONFIG_CRC_CCITT is not set
++CONFIG_CRC16=y
++# CONFIG_CRC_T10DIF is not set
++# 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_AUDIT_ARCH_COMPAT_GENERIC is not set
++# CONFIG_RANDOM32_SELFTEST is not set
++CONFIG_ZLIB_INFLATE=y
++CONFIG_ZLIB_DEFLATE=y
++CONFIG_LZO_COMPRESS=y
++CONFIG_LZO_DECOMPRESS=y
++CONFIG_LZ4_DECOMPRESS=y
++CONFIG_XZ_DEC=y
++CONFIG_XZ_DEC_X86=y
++CONFIG_XZ_DEC_POWERPC=y
++CONFIG_XZ_DEC_IA64=y
++CONFIG_XZ_DEC_ARM=y
++CONFIG_XZ_DEC_ARMTHUMB=y
++CONFIG_XZ_DEC_SPARC=y
++CONFIG_XZ_DEC_BCJ=y
++# CONFIG_XZ_DEC_TEST is not set
++CONFIG_DECOMPRESS_GZIP=y
++CONFIG_DECOMPRESS_BZIP2=y
++CONFIG_DECOMPRESS_LZMA=y
++CONFIG_DECOMPRESS_XZ=y
++CONFIG_DECOMPRESS_LZO=y
++CONFIG_DECOMPRESS_LZ4=y
++CONFIG_GENERIC_ALLOCATOR=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT_MAP=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 is not set
++# CONFIG_CORDIC is not set
++# CONFIG_DDR is not set
++CONFIG_LIBFDT=y
++CONFIG_ARCH_HAS_SG_CHAIN=y
++# CONFIG_VIRTUALIZATION is not set
+diff --git a/arch/arm/configs/hi3516cv300_full_defconfig b/arch/arm/configs/hi3516cv300_full_defconfig
+new file mode 100644
+index 0000000..70f4635
+--- /dev/null
++++ b/arch/arm/configs/hi3516cv300_full_defconfig
+@@ -0,0 +1,2529 @@
++#
++# Automatically generated file; DO NOT EDIT.
++# Linux/arm 3.18.20 Kernel Configuration
++#
++CONFIG_ARM=y
++CONFIG_ARM_HAS_SG_CHAIN=y
++CONFIG_MIGHT_HAVE_PCI=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=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_XCHGADD_ALGORITHM=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_NEED_DMA_MAP_STATE=y
++CONFIG_ARCH_SUPPORTS_UPROBES=y
++CONFIG_VECTORS_BASE=0xffff0000
++CONFIG_ARM_PATCH_PHYS_VIRT=y
++CONFIG_GENERIC_BUG=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++CONFIG_IRQ_WORK=y
++CONFIG_BUILDTIME_EXTABLE_SORT=y
++
++#
++# General setup
++#
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_CROSS_COMPILE=""
++# CONFIG_COMPILE_TEST is not set
++CONFIG_LOCALVERSION=""
++# CONFIG_LOCALVERSION_AUTO is not set
++CONFIG_HAVE_KERNEL_GZIP=y
++CONFIG_HAVE_KERNEL_LZMA=y
++CONFIG_HAVE_KERNEL_XZ=y
++CONFIG_HAVE_KERNEL_LZO=y
++CONFIG_HAVE_KERNEL_LZ4=y
++CONFIG_KERNEL_GZIP=y
++# CONFIG_KERNEL_LZMA is not set
++# CONFIG_KERNEL_XZ is not set
++# CONFIG_KERNEL_LZO is not set
++# CONFIG_KERNEL_LZ4 is not set
++CONFIG_DEFAULT_HOSTNAME="(none)"
++CONFIG_SWAP=y
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++# CONFIG_POSIX_MQUEUE is not set
++CONFIG_CROSS_MEMORY_ATTACH=y
++# CONFIG_FHANDLE is not set
++CONFIG_USELIB=y
++# CONFIG_AUDIT is not set
++CONFIG_HAVE_ARCH_AUDITSYSCALL=y
++
++#
++# IRQ subsystem
++#
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_GENERIC_IRQ_SHOW=y
++CONFIG_HARDIRQS_SW_RESEND=y
++CONFIG_IRQ_DOMAIN=y
++CONFIG_HANDLE_DOMAIN_IRQ=y
++CONFIG_IRQ_FORCED_THREADING=y
++CONFIG_SPARSE_IRQ=y
++CONFIG_GENERIC_CLOCKEVENTS=y
++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
++
++#
++# Timers subsystem
++#
++CONFIG_TICK_ONESHOT=y
++CONFIG_NO_HZ_COMMON=y
++# CONFIG_HZ_PERIODIC is not set
++CONFIG_NO_HZ_IDLE=y
++CONFIG_NO_HZ=y
++# CONFIG_HIGH_RES_TIMERS is not set
++
++#
++# CPU/Task time and stats accounting
++#
++CONFIG_VIRT_CPU_ACCOUNTING=y
++# CONFIG_TICK_CPU_ACCOUNTING is not set
++CONFIG_VIRT_CPU_ACCOUNTING_GEN=y
++# CONFIG_IRQ_TIME_ACCOUNTING is not set
++# CONFIG_BSD_PROCESS_ACCT is not set
++# CONFIG_TASKSTATS is not set
++
++#
++# RCU Subsystem
++#
++CONFIG_TINY_RCU=y
++# CONFIG_PREEMPT_RCU is not set
++# CONFIG_TASKS_RCU is not set
++# CONFIG_RCU_STALL_COMMON is not set
++CONFIG_CONTEXT_TRACKING=y
++# CONFIG_CONTEXT_TRACKING_FORCE is not set
++# CONFIG_TREE_RCU_TRACE is not set
++# CONFIG_BUILD_BIN2C is not set
++# CONFIG_IKCONFIG is not set
++CONFIG_LOG_BUF_SHIFT=17
++CONFIG_GENERIC_SCHED_CLOCK=y
++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_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_USER_NS is not set
++CONFIG_PID_NS=y
++CONFIG_NET_NS=y
++# 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=y
++CONFIG_RD_LZMA=y
++CONFIG_RD_XZ=y
++CONFIG_RD_LZO=y
++CONFIG_RD_LZ4=y
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++CONFIG_HAVE_UID16=y
++CONFIG_BPF=y
++# CONFIG_EXPERT is not set
++CONFIG_UID16=y
++# CONFIG_SGETMASK_SYSCALL is not set
++CONFIG_SYSFS_SYSCALL=y
++# CONFIG_SYSCTL_SYSCALL is not set
++CONFIG_KALLSYMS=y
++# CONFIG_KALLSYMS_ALL is not set
++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_BPF_SYSCALL is not set
++CONFIG_SHMEM=y
++CONFIG_AIO=y
++CONFIG_ADVISE_SYSCALLS=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_PROFILING is not set
++CONFIG_HAVE_OPROFILE=y
++# CONFIG_KPROBES is not set
++# CONFIG_JUMP_LABEL is not set
++# CONFIG_UPROBES is not set
++# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
++CONFIG_ARCH_USE_BUILTIN_BSWAP=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_GENERIC_SMP_IDLE_THREAD=y
++CONFIG_GENERIC_IDLE_POLL_SETUP=y
++CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
++CONFIG_HAVE_CLK=y
++CONFIG_HAVE_DMA_API_DEBUG=y
++CONFIG_HAVE_PERF_REGS=y
++CONFIG_HAVE_PERF_USER_STACK_DUMP=y
++CONFIG_HAVE_ARCH_JUMP_LABEL=y
++CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
++CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
++CONFIG_HAVE_CC_STACKPROTECTOR=y
++# CONFIG_CC_STACKPROTECTOR is not set
++CONFIG_CC_STACKPROTECTOR_NONE=y
++# CONFIG_CC_STACKPROTECTOR_REGULAR is not set
++# CONFIG_CC_STACKPROTECTOR_STRONG is not set
++CONFIG_HAVE_CONTEXT_TRACKING=y
++CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
++CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
++CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
++CONFIG_MODULES_USE_ELF_REL=y
++CONFIG_CLONE_BACKWARDS=y
++CONFIG_OLD_SIGSUSPEND3=y
++CONFIG_OLD_SIGACTION=y
++
++#
++# GCOV-based kernel profiling
++#
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_SLABINFO=y
++CONFIG_RT_MUTEXES=y
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++# CONFIG_MODULE_FORCE_LOAD is not set
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++# CONFIG_MODULE_SIG is not set
++# CONFIG_MODULE_COMPRESS is not set
++CONFIG_BLOCK=y
++CONFIG_LBDAF=y
++CONFIG_BLK_DEV_BSG=y
++# CONFIG_BLK_DEV_BSGLIB is not set
++# CONFIG_BLK_DEV_INTEGRITY is not set
++CONFIG_BLK_CMDLINE_PARSER=y
++
++#
++# Partition Types
++#
++CONFIG_PARTITION_ADVANCED=y
++# CONFIG_ACORN_PARTITION is not set
++# CONFIG_AIX_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=y
++# CONFIG_SYSV68_PARTITION is not set
++CONFIG_CMDLINE_PARTITION=y
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++CONFIG_DEFAULT_DEADLINE=y
++# CONFIG_DEFAULT_CFQ is not set
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="deadline"
++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_ARCH_SUPPORTS_ATOMIC_RMW=y
++CONFIG_FREEZER=y
++
++#
++# System Type
++#
++CONFIG_MMU=y
++CONFIG_ARCH_MULTIPLATFORM=y
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_AT91 is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_GEMINI is not set
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_IOP13XX is not set
++# CONFIG_ARCH_IOP32X is not set
++# CONFIG_ARCH_IOP33X is not set
++# CONFIG_ARCH_IXP4XX is not set
++# CONFIG_ARCH_DOVE is not set
++# CONFIG_ARCH_MV78XX0 is not set
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_MMP is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_W90X900 is not set
++# CONFIG_ARCH_LPC32XX is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_MSM is not set
++# CONFIG_ARCH_SHMOBILE_LEGACY 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_DAVINCI is not set
++# CONFIG_ARCH_OMAP1 is not set
++
++#
++# Multiple platform selection
++#
++
++#
++# CPU Core family selection
++#
++# CONFIG_ARCH_MULTI_V4 is not set
++# CONFIG_ARCH_MULTI_V4T is not set
++CONFIG_ARCH_MULTI_V5=y
++CONFIG_ARCH_MULTI_V4_V5=y
++# CONFIG_ARCH_MULTI_V6 is not set
++# CONFIG_ARCH_MULTI_V7 is not set
++CONFIG_ARCH_MULTI_CPU_AUTO=y
++# CONFIG_ARCH_MVEBU is not set
++CONFIG_ARCH_HISI=y
++
++#
++# Hisilicon platform type
++#
++CONFIG_ARCH_HI3516CV300=y
++# CONFIG_ARCH_MXC is not set
++# CONFIG_ARCH_MXS is not set
++# CONFIG_ARCH_NOMADIK is not set
++# CONFIG_ARCH_NSPIRE is not set
++# CONFIG_PLAT_SPEAR is not set
++# CONFIG_ARCH_U300 is not set
++# CONFIG_ARCH_WM8505 is not set
++CONFIG_ARM_TIMER_SP804=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 is not set
++# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
++CONFIG_NEED_KUSER_HELPERS=y
++CONFIG_KUSER_HELPERS=y
++# CONFIG_CACHE_L2X0 is not set
++CONFIG_ARM_L1_CACHE_SHIFT=5
++CONFIG_MULTI_IRQ_HANDLER=y
++
++#
++# Bus support
++#
++CONFIG_ARM_AMBA=y
++# CONFIG_PCI is not set
++# CONFIG_PCI_SYSCALL is not set
++# CONFIG_PCCARD is not set
++
++#
++# Kernel Features
++#
++CONFIG_DISABLE_CPU_SCHED_DOMAIN_BALANCE=y
++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=y
++# CONFIG_PREEMPT_VOLUNTARY is not set
++# CONFIG_PREEMPT is not set
++CONFIG_HZ_FIXED=0
++CONFIG_HZ_100=y
++# CONFIG_HZ_200 is not set
++# CONFIG_HZ_250 is not set
++# CONFIG_HZ_300 is not set
++# CONFIG_HZ_500 is not set
++# CONFIG_HZ_1000 is not set
++CONFIG_HZ=100
++# CONFIG_SCHED_HRTICK is not set
++CONFIG_AEABI=y
++# CONFIG_OABI_COMPAT is not set
++# 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_ARCH_WANT_GENERAL_HUGETLB=y
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_HAVE_MEMBLOCK=y
++CONFIG_NO_BOOTMEM=y
++# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
++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=0
++CONFIG_BOUNCE=y
++# CONFIG_KSM is not set
++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
++CONFIG_NEED_PER_CPU_KM=y
++# CONFIG_CLEANCACHE is not set
++# CONFIG_FRONTSWAP is not set
++# CONFIG_CMA is not set
++# CONFIG_ZPOOL is not set
++# CONFIG_ZBUD is not set
++# CONFIG_ZSMALLOC 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_SWIOTLB=y
++CONFIG_IOMMU_HELPER=y
++# CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART is not set
++
++#
++# Boot options
++#
++CONFIG_USE_OF=y
++CONFIG_ATAGS=y
++# CONFIG_DEPRECATED_PARAM_STRUCT is not set
++# CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE is not set
++CONFIG_ZBOOT_ROM_TEXT=0
++CONFIG_ZBOOT_ROM_BSS=0
++CONFIG_ARM_APPENDED_DTB=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_KEXEC is not set
++# CONFIG_CRASH_DUMP is not set
++CONFIG_AUTO_ZRELADDR=y
++
++#
++# CPU Power Management
++#
++
++#
++# CPU Frequency scaling
++#
++# CONFIG_CPU_FREQ is not set
++
++#
++# CPU Idle
++#
++# CONFIG_CPU_IDLE is not set
++# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++CONFIG_VFP=y
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
++CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
++CONFIG_BINFMT_SCRIPT=y
++# CONFIG_HAVE_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
++CONFIG_COREDUMP=y
++
++#
++# Power management options
++#
++CONFIG_SUSPEND=y
++CONFIG_SUSPEND_FREEZER=y
++CONFIG_WAKELOCK=y
++CONFIG_HIBERNATE_CALLBACKS=y
++CONFIG_HISI_SNAPSHOT_BOOT=y
++# CONFIG_DEFAULT_MTD is not set
++CONFIG_DEFAULT_DDR=y
++CONFIG_SNAPSHOT_BUF_START=0x8a000000
++CONFIG_SNAPSHOT_BUF_SIZE=0x4000000
++CONFIG_HIBERNATION=y
++CONFIG_GZIP_COMPRESS=y
++CONFIG_PM_STD_PARTITION=""
++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_WQ_POWER_EFFICIENT_DEFAULT is not set
++CONFIG_CPU_PM=y
++# CONFIG_SUSPEND_TIME is not set
++CONFIG_ARCH_SUSPEND_POSSIBLE=y
++CONFIG_ARM_CPU_SUSPEND=y
++CONFIG_ARCH_HIBERNATION_POSSIBLE=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_NET_IP_TUNNEL=m
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_NET_IPVTI is not set
++# CONFIG_NET_UDP_TUNNEL is not set
++# CONFIG_NET_FOU is not set
++# CONFIG_GENEVE 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=y
++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=y
++# 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_VTI 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_ANDROID_PARANOID_NETWORK is not set
++CONFIG_NET_ACTIVITY_STATS=y
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NET_PTP_CLASSIFY 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_NF_TABLES is not set
++# CONFIG_NETFILTER_XTABLES is not set
++# CONFIG_IP_SET is not set
++# CONFIG_IP_VS is not set
++
++#
++# IP: Netfilter Configuration
++#
++# CONFIG_NF_DEFRAG_IPV4 is not set
++# CONFIG_NF_LOG_ARP is not set
++# CONFIG_NF_LOG_IPV4 is not set
++# CONFIG_NF_REJECT_IPV4 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_NF_REJECT_IPV6 is not set
++# CONFIG_NF_LOG_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_HAVE_NET_DSA=y
++# 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_PHONET is not set
++# CONFIG_6LOWPAN 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_VSOCKETS is not set
++# CONFIG_NETLINK_MMAP is not set
++# CONFIG_NETLINK_DIAG is not set
++# CONFIG_NET_MPLS_GSO is not set
++# CONFIG_HSR is not set
++# CONFIG_CGROUP_NET_PRIO is not set
++# CONFIG_CGROUP_NET_CLASSID is not set
++CONFIG_NET_RX_BUSY_POLL=y
++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_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 is not set
++CONFIG_DEVTMPFS=y
++CONFIG_DEVTMPFS_MOUNT=y
++CONFIG_STANDALONE=y
++# CONFIG_PREVENT_FIRMWARE_BUILD is not set
++CONFIG_FW_LOADER=y
++# CONFIG_FIRMWARE_IN_KERNEL is not set
++CONFIG_EXTRA_FIRMWARE=""
++# CONFIG_FW_LOADER_USER_HELPER_FALLBACK is not set
++CONFIG_ALLOW_DEV_COREDUMP=y
++# 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_HAVE_CPU_AUTOPROBE is not set
++CONFIG_REGMAP=y
++CONFIG_REGMAP_MMIO=y
++CONFIG_DMA_SHARED_BUFFER=y
++# CONFIG_FENCE_TRACE is not set
++
++#
++# Bus devices
++#
++# CONFIG_BRCMSTB_GISB_ARB is not set
++# CONFIG_VEXPRESS_CONFIG 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=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_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
++CONFIG_HIFMC=y
++CONFIG_HIFMC_SPI_NAND=y
++# CONFIG_HIFMC_NAND is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++# CONFIG_MTD_CFI is not set
++# CONFIG_MTD_JEDECPROBE is not set
++CONFIG_MTD_MAP_BANK_WIDTH_1=y
++CONFIG_MTD_MAP_BANK_WIDTH_2=y
++CONFIG_MTD_MAP_BANK_WIDTH_4=y
++# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
++CONFIG_MTD_CFI_I1=y
++CONFIG_MTD_CFI_I2=y
++# CONFIG_MTD_CFI_I4 is not set
++# CONFIG_MTD_CFI_I8 is not set
++# CONFIG_MTD_RAM is not set
++# CONFIG_MTD_ROM is not set
++# CONFIG_MTD_ABSENT is not set
++
++#
++# Mapping drivers for chip access
++#
++# CONFIG_MTD_COMPLEX_MAPPINGS is not set
++# CONFIG_MTD_PLATRAM is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_DATAFLASH is not set
++# CONFIG_MTD_M25P80 is not set
++# CONFIG_MTD_SST25L is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_PHRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++# CONFIG_MTD_BLOCK2MTD is not set
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOCG3 is not set
++CONFIG_MTD_NAND_IDS=y
++CONFIG_MTD_NAND_ECC=y
++# CONFIG_MTD_NAND_ECC_SMC is not set
++CONFIG_MTD_NAND=y
++# CONFIG_MTD_NAND_ECC_BCH is not set
++# CONFIG_MTD_SM_COMMON is not set
++# CONFIG_MTD_NAND_DENALI is not set
++# CONFIG_MTD_NAND_GPIO is not set
++# CONFIG_MTD_NAND_OMAP_BCH_BUILD is not set
++# CONFIG_MTD_NAND_DISKONCHIP is not set
++# CONFIG_MTD_NAND_DOCG4 is not set
++# CONFIG_MTD_NAND_NANDSIM is not set
++# CONFIG_MTD_NAND_PLATFORM is not set
++# CONFIG_HISI_NAND_FS_MAY_NO_YAFFS2 is not set
++# CONFIG_HISI_NAND_ECC_STATUS_REPORT is not set
++# CONFIG_HIFMC100_NAND is not set
++CONFIG_HIFMC100_SPI_NAND=y
++CONFIG_SPI_NAND_MAX_CHIP_NUM=1
++# CONFIG_HIFMC100_HARDWARE_PAGESIZE_ECC is not set
++CONFIG_HIFMC100_AUTO_PAGESIZE_ECC=y
++# CONFIG_HIFMC100_PAGESIZE_AUTO_ECC_NONE is not set
++# CONFIG_MTD_ONENAND is not set
++
++#
++# LPDDR & LPDDR2 PCM memory drivers
++#
++# CONFIG_MTD_LPDDR is not set
++# CONFIG_MTD_LPDDR2_NVM is not set
++CONFIG_MTD_SPI_NOR=y
++# CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set
++CONFIG_SPI_HISI_SFC=y
++CONFIG_CLOSE_SPI_8PIN_4IO=y
++CONFIG_HISI_SPI_BLOCK_PROTECT=y
++CONFIG_MTD_UBI=y
++CONFIG_MTD_UBI_WL_THRESHOLD=4096
++CONFIG_MTD_UBI_BEB_LIMIT=20
++# CONFIG_MTD_UBI_FASTMAP is not set
++# CONFIG_MTD_UBI_GLUEBI is not set
++# CONFIG_MTD_UBI_BLOCK is not set
++CONFIG_DTC=y
++CONFIG_OF=y
++
++#
++# Device Tree and Open Firmware support
++#
++# 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_NET=y
++CONFIG_OF_MDIO=y
++CONFIG_OF_MTD=y
++CONFIG_OF_RESERVED_MEM=y
++CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
++# CONFIG_PARPORT is not set
++CONFIG_BLK_DEV=y
++# CONFIG_BLK_DEV_NULL_BLK is not set
++# CONFIG_BLK_DEV_COW_COMMON is not set
++# CONFIG_BLK_DEV_LOOP 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=65536
++# 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_DUMMY_IRQ 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_UID_STAT is not set
++# CONFIG_BMP085_I2C is not set
++# CONFIG_BMP085_SPI is not set
++# CONFIG_USB_SWITCH_FSA9480 is not set
++# CONFIG_LATTICE_ECP3_CONFIG is not set
++# CONFIG_SRAM is not set
++# CONFIG_C2PORT is not set
++
++#
++# EEPROM support
++#
++# CONFIG_EEPROM_AT24 is not set
++# CONFIG_EEPROM_AT25 is not set
++# CONFIG_EEPROM_LEGACY is not set
++# CONFIG_EEPROM_MAX6875 is not set
++# CONFIG_EEPROM_93CX6 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
++
++#
++# Intel MIC Bus Driver
++#
++
++#
++# Intel MIC Host Driver
++#
++
++#
++# Intel MIC Card Driver
++#
++# CONFIG_ECHO is not set
++# CONFIG_CXL_BASE is not set
++
++#
++# hisi 'himm/himd.l/himc'support
++#
++# CONFIG_HISI_REG 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_NETLINK is not set
++# CONFIG_SCSI_MQ_DEFAULT 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_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 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_NET_CORE=y
++# CONFIG_BONDING is not set
++# CONFIG_DUMMY is not set
++# CONFIG_EQUALIZER is not set
++# CONFIG_NET_TEAM is not set
++# CONFIG_MACVLAN is not set
++# CONFIG_VXLAN is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_TUN is not set
++# CONFIG_VETH is not set
++# CONFIG_NLMON is not set
++
++#
++# 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_NET_DSA_MV88E6171 is not set
++# CONFIG_NET_DSA_BCM_SF2 is not set
++CONFIG_ETHERNET=y
++# CONFIG_ALTERA_TSE is not set
++# CONFIG_NET_XGENE is not set
++# CONFIG_NET_VENDOR_ARC is not set
++# CONFIG_NET_CADENCE is not set
++# CONFIG_NET_VENDOR_BROADCOM is not set
++# CONFIG_NET_VENDOR_CIRRUS is not set
++# CONFIG_DM9000 is not set
++# CONFIG_DNET is not set
++# CONFIG_NET_VENDOR_FARADAY is not set
++CONFIG_NET_VENDOR_HISILICON=y
++# CONFIG_HIX5HD2_GMAC is not set
++CONFIG_HISI_FEMAC=y
++# CONFIG_HIETH_GMAC is not set
++# CONFIG_HIETH_SWITCH_FABRIC is not set
++# CONFIG_NET_VENDOR_INTEL is not set
++# CONFIG_NET_VENDOR_MARVELL is not set
++# CONFIG_NET_VENDOR_MICREL is not set
++CONFIG_NET_VENDOR_MICROCHIP=y
++# CONFIG_ENC28J60 is not set
++# CONFIG_NET_VENDOR_NATSEMI is not set
++# CONFIG_ETHOC is not set
++# CONFIG_NET_VENDOR_QUALCOMM is not set
++# CONFIG_NET_VENDOR_SAMSUNG is not set
++# CONFIG_NET_VENDOR_SEEQ is not set
++# CONFIG_NET_VENDOR_SMSC is not set
++# CONFIG_NET_VENDOR_STMICRO is not set
++# CONFIG_NET_VENDOR_VIA is not set
++# CONFIG_NET_VENDOR_WIZNET is not set
++CONFIG_PHYLIB=y
++
++#
++# MII PHY device drivers
++#
++# CONFIG_AT803X_PHY is not set
++# CONFIG_AMD_PHY is not set
++# CONFIG_AMD_XGBE_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 is not set
++# CONFIG_BROADCOM_PHY is not set
++# CONFIG_BCM7XXX_PHY is not set
++# CONFIG_BCM87XX_PHY is not set
++# CONFIG_ICPLUS_PHY is not set
++# CONFIG_REALTEK_PHY is not set
++# CONFIG_NATIONAL_PHY is not set
++# CONFIG_STE10XP is not set
++# CONFIG_LSI_ET1011C_PHY is not set
++# CONFIG_MICREL_PHY is not set
++# CONFIG_FIXED_PHY is not set
++# CONFIG_MDIO_BITBANG is not set
++# CONFIG_MDIO_BUS_MUX_GPIO is not set
++# CONFIG_MDIO_BUS_MUX_MMIOREG is not set
++# CONFIG_MDIO_BCM_UNIMAC is not set
++CONFIG_MDIO_HISI_FEMAC=y
++# CONFIG_MDIO_HISI_GEMAC is not set
++# CONFIG_MICREL_KS8995MA is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++CONFIG_USB_NET_DRIVERS=y
++# 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_RTL8152 is not set
++# CONFIG_USB_USBNET is not set
++# CONFIG_USB_IPHETH is not set
++# CONFIG_WLAN is not set
++
++#
++# Enable WiMAX (Networking options) to see the WiMAX drivers
++#
++# CONFIG_WAN is not set
++# CONFIG_ISDN is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
++# CONFIG_INPUT_POLLDEV is not set
++# CONFIG_INPUT_SPARSEKMAP is not set
++# CONFIG_INPUT_MATRIXKMAP is not set
++
++#
++# Userland interfaces
++#
++CONFIG_INPUT_MOUSEDEV=y
++CONFIG_INPUT_MOUSEDEV_PSAUX=y
++CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
++CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
++# CONFIG_INPUT_JOYDEV is not set
++CONFIG_INPUT_EVDEV=y
++# CONFIG_INPUT_EVBUG is not set
++# CONFIG_INPUT_KEYRESET is not set
++# CONFIG_INPUT_KEYCOMBO is not set
++
++#
++# Input Device Drivers
++#
++CONFIG_INPUT_KEYBOARD=y
++# CONFIG_KEYBOARD_ADP5588 is not set
++# CONFIG_KEYBOARD_ADP5589 is not set
++CONFIG_KEYBOARD_ATKBD=y
++# CONFIG_KEYBOARD_QT1070 is not set
++# CONFIG_KEYBOARD_QT2160 is not set
++# CONFIG_KEYBOARD_LKKBD is not set
++# CONFIG_KEYBOARD_GPIO is not set
++# CONFIG_KEYBOARD_GPIO_POLLED is not set
++# 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 is not set
++# CONFIG_KEYBOARD_CAP1106 is not set
++CONFIG_INPUT_MOUSE=y
++CONFIG_MOUSE_PS2=y
++CONFIG_MOUSE_PS2_ALPS=y
++CONFIG_MOUSE_PS2_LOGIPS2PP=y
++CONFIG_MOUSE_PS2_SYNAPTICS=y
++CONFIG_MOUSE_PS2_CYPRESS=y
++CONFIG_MOUSE_PS2_TRACKPOINT=y
++# CONFIG_MOUSE_PS2_ELANTECH is not set
++# CONFIG_MOUSE_PS2_SENTELIC is not set
++# CONFIG_MOUSE_PS2_TOUCHKIT is not set
++# CONFIG_MOUSE_SERIAL is not set
++# CONFIG_MOUSE_APPLETOUCH is not set
++# CONFIG_MOUSE_BCM5974 is not set
++# CONFIG_MOUSE_CYAPA is not set
++# CONFIG_MOUSE_VSXXXAA is not set
++# CONFIG_MOUSE_GPIO is not set
++# CONFIG_MOUSE_SYNAPTICS_I2C is not set
++# CONFIG_MOUSE_SYNAPTICS_USB is not set
++# CONFIG_INPUT_JOYSTICK is not set
++# CONFIG_INPUT_TABLET is not set
++# CONFIG_INPUT_TOUCHSCREEN is not set
++# CONFIG_INPUT_MISC is not set
++
++#
++# Hardware I/O ports
++#
++CONFIG_SERIO=y
++CONFIG_SERIO_SERPORT=y
++# CONFIG_SERIO_AMBAKMI is not set
++CONFIG_SERIO_LIBPS2=y
++# CONFIG_SERIO_RAW is not set
++# CONFIG_SERIO_ALTERA_PS2 is not set
++# CONFIG_SERIO_PS2MULT is not set
++# CONFIG_SERIO_ARC_PS2 is not set
++# CONFIG_SERIO_APBPS2 is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++CONFIG_TTY=y
++CONFIG_VT=y
++CONFIG_CONSOLE_TRANSLATIONS=y
++CONFIG_VT_CONSOLE=y
++CONFIG_VT_CONSOLE_SLEEP=y
++CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
++CONFIG_UNIX98_PTYS=y
++# CONFIG_DEVPTS_MULTIPLE_INSTANCES 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_DEVMEM=y
++CONFIG_DEVKMEM=y
++
++#
++# Serial drivers
++#
++CONFIG_SERIAL_EARLYCON=y
++# CONFIG_SERIAL_8250 is not set
++
++#
++# Non-8250 serial port support
++#
++# CONFIG_SERIAL_AMBA_PL010 is not set
++CONFIG_SERIAL_AMBA_PL011=y
++CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
++# CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST is not set
++# 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_SC16IS7XX is not set
++# CONFIG_SERIAL_ALTERA_JTAGUART is not set
++# CONFIG_SERIAL_ALTERA_UART is not set
++# CONFIG_SERIAL_IFX6X60 is not set
++# CONFIG_SERIAL_XILINX_PS_UART is not set
++# CONFIG_SERIAL_ARC is not set
++# CONFIG_SERIAL_FSL_LPUART is not set
++# CONFIG_SERIAL_ST_ASC is not set
++# CONFIG_HVC_DCC is not set
++# CONFIG_IPMI_HANDLER is not set
++CONFIG_HW_RANDOM=y
++# CONFIG_HW_RANDOM_TIMERIOMEM is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++# CONFIG_DCC_TTY is not set
++# CONFIG_XILLYBUS is not set
++
++#
++# I2C support
++#
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++# CONFIG_I2C_COMPAT is not set
++CONFIG_I2C_CHARDEV=y
++CONFIG_I2C_MUX=m
++
++#
++# Multiplexer I2C Chip support
++#
++# CONFIG_I2C_ARB_GPIO_CHALLENGE is not set
++# CONFIG_I2C_MUX_GPIO is not set
++# CONFIG_I2C_MUX_PCA9541 is not set
++# CONFIG_I2C_MUX_PCA954x is not set
++# CONFIG_I2C_MUX_PINCTRL is not set
++# CONFIG_I2C_HELPER_AUTO is not set
++# CONFIG_I2C_SMBUS is not set
++
++#
++# I2C Algorithms
++#
++# CONFIG_I2C_ALGOBIT is not set
++# CONFIG_I2C_ALGOPCF is not set
++# CONFIG_I2C_ALGOPCA is not set
++
++#
++# I2C Hardware Bus support
++#
++
++#
++# I2C system bus drivers (mostly embedded / system-on-chip)
++#
++# CONFIG_I2C_CBUS_GPIO is not set
++# CONFIG_I2C_DESIGNWARE_PLATFORM is not set
++# CONFIG_I2C_GPIO is not set
++CONFIG_I2C_HIBVT=y
++# CONFIG_I2C_HISI_V110 is not set
++# CONFIG_I2C_NOMADIK 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_RK3X 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_ROBOTFUZZ_OSIF 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_CADENCE is not set
++# CONFIG_SPI_GPIO is not set
++# CONFIG_SPI_FSL_SPI is not set
++# CONFIG_SPI_OC_TINY is not set
++CONFIG_SPI_PL022=y
++# CONFIG_SPI_PXA2XX_PCI is not set
++# CONFIG_SPI_ROCKCHIP 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=y
++# CONFIG_SPI_TLE62X0 is not set
++# CONFIG_SPMI is not set
++# CONFIG_HSI is not set
++
++#
++# PPS support
++#
++# CONFIG_PPS is not set
++
++#
++# PPS generators support
++#
++
++#
++# PTP clock support
++#
++# CONFIG_PTP_1588_CLOCK is not set
++
++#
++# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
++#
++CONFIG_PINCTRL=y
++
++#
++# Pin controllers
++#
++CONFIG_PINMUX=y
++CONFIG_PINCONF=y
++CONFIG_GENERIC_PINCONF=y
++# CONFIG_DEBUG_PINCTRL is not set
++CONFIG_PINCTRL_SINGLE=y
++CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
++CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
++CONFIG_GPIOLIB=y
++CONFIG_GPIO_DEVRES=y
++CONFIG_OF_GPIO=y
++CONFIG_GPIOLIB_IRQCHIP=y
++# CONFIG_DEBUG_GPIO is not set
++CONFIG_GPIO_SYSFS=y
++
++#
++# Memory mapped GPIO drivers:
++#
++# CONFIG_GPIO_GENERIC_PLATFORM is not set
++# CONFIG_GPIO_DWAPB is not set
++# CONFIG_GPIO_EM is not set
++# CONFIG_GPIO_ZEVIO is not set
++CONFIG_GPIO_PL061=y
++# CONFIG_GPIO_SCH311X is not set
++# CONFIG_GPIO_SYSCON is not set
++# CONFIG_GPIO_GRGPIO is not set
++
++#
++# I2C GPIO expanders:
++#
++# CONFIG_GPIO_MAX7300 is not set
++# CONFIG_GPIO_MAX732X is not set
++# CONFIG_GPIO_PCA953X is not set
++# CONFIG_GPIO_PCF857X is not set
++# CONFIG_GPIO_SX150X is not set
++# CONFIG_GPIO_ADP5588 is not set
++# CONFIG_GPIO_ADNP is not set
++
++#
++# PCI GPIO expanders:
++#
++
++#
++# SPI GPIO expanders:
++#
++# CONFIG_GPIO_MAX7301 is not set
++# CONFIG_GPIO_MCP23S08 is not set
++# CONFIG_GPIO_MC33880 is not set
++# CONFIG_GPIO_74X164 is not set
++
++#
++# AC97 GPIO expanders:
++#
++
++#
++# LPC GPIO expanders:
++#
++
++#
++# MODULbus GPIO expanders:
++#
++
++#
++# USB GPIO expanders:
++#
++# CONFIG_W1 is not set
++CONFIG_POWER_SUPPLY=y
++# CONFIG_POWER_SUPPLY_DEBUG is not set
++# CONFIG_PDA_POWER is not set
++# CONFIG_TEST_POWER is not set
++# CONFIG_BATTERY_DS2780 is not set
++# CONFIG_BATTERY_DS2781 is not set
++# CONFIG_BATTERY_DS2782 is not set
++# CONFIG_BATTERY_SBS is not set
++# CONFIG_BATTERY_BQ27x00 is not set
++# CONFIG_BATTERY_MAX17040 is not set
++# CONFIG_BATTERY_MAX17042 is not set
++# CONFIG_CHARGER_MAX8903 is not set
++# CONFIG_CHARGER_LP8727 is not set
++# CONFIG_CHARGER_GPIO is not set
++# CONFIG_CHARGER_BQ2415X is not set
++# CONFIG_CHARGER_BQ24190 is not set
++# CONFIG_CHARGER_BQ24735 is not set
++# CONFIG_CHARGER_SMB347 is not set
++CONFIG_POWER_RESET=y
++# CONFIG_POWER_RESET_BRCMSTB is not set
++# CONFIG_POWER_RESET_GPIO is not set
++# CONFIG_POWER_RESET_GPIO_RESTART is not set
++CONFIG_POWER_RESET_HISI=y
++# CONFIG_POWER_RESET_LTC2952 is not set
++# CONFIG_POWER_RESET_RESTART is not set
++# CONFIG_POWER_RESET_VERSATILE is not set
++CONFIG_POWER_RESET_SYSCON=y
++# CONFIG_POWER_AVS is not set
++# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
++# CONFIG_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=y
++# CONFIG_MFD_AS3711 is not set
++# CONFIG_MFD_AS3722 is not set
++# CONFIG_PMIC_ADP5520 is not set
++# CONFIG_MFD_AAT2870_CORE is not set
++# CONFIG_MFD_BCM590XX is not set
++# CONFIG_MFD_AXP20X is not set
++# CONFIG_MFD_CROS_EC is not set
++# CONFIG_MFD_ASIC3 is not set
++# CONFIG_PMIC_DA903X is not set
++# CONFIG_MFD_DA9052_SPI is not set
++# CONFIG_MFD_DA9052_I2C is not set
++# CONFIG_MFD_DA9055 is not set
++# CONFIG_MFD_DA9063 is not set
++# CONFIG_MFD_MC13XXX_SPI is not set
++# CONFIG_MFD_MC13XXX_I2C is not set
++# CONFIG_MFD_HI6421_PMIC is not set
++CONFIG_MFD_HISI_FMC=y
++# CONFIG_HTC_EGPIO is not set
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_HTC_I2CPLD is not set
++# CONFIG_INTEL_SOC_PMIC is not set
++# CONFIG_MFD_KEMPLD is not set
++# CONFIG_MFD_88PM800 is not set
++# CONFIG_MFD_88PM805 is not set
++# CONFIG_MFD_88PM860X is not set
++# CONFIG_MFD_MAX14577 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_MENF21BMC is not set
++# CONFIG_EZX_PCAP is not set
++# CONFIG_MFD_VIPERBOARD is not set
++# CONFIG_MFD_RETU is not set
++# CONFIG_MFD_PCF50633 is not set
++# CONFIG_MFD_PM8921_CORE is not set
++# CONFIG_MFD_RTSX_USB is not set
++# CONFIG_MFD_RC5T583 is not set
++# CONFIG_MFD_RK808 is not set
++# CONFIG_MFD_RN5T618 is not set
++# CONFIG_MFD_SEC_CORE is not set
++# CONFIG_MFD_SI476X_CORE is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_MFD_SMSC is not set
++# CONFIG_ABX500_CORE is not set
++# CONFIG_MFD_STMPE is not set
++CONFIG_MFD_SYSCON=y
++# CONFIG_MFD_TI_AM335X_TSCADC is not set
++# CONFIG_MFD_LP3943 is not set
++# CONFIG_MFD_LP8788 is not set
++# CONFIG_MFD_PALMAS is not set
++# CONFIG_TPS6105X is not set
++# CONFIG_TPS65010 is not set
++# CONFIG_TPS6507X is not set
++# CONFIG_MFD_TPS65090 is not set
++# CONFIG_MFD_TPS65217 is not set
++# CONFIG_MFD_TPS65218 is not set
++# CONFIG_MFD_TPS6586X is not set
++# CONFIG_MFD_TPS65910 is not set
++# CONFIG_MFD_TPS65912 is not set
++# CONFIG_MFD_TPS65912_I2C is not set
++# CONFIG_MFD_TPS65912_SPI is not set
++# CONFIG_MFD_TPS80031 is not set
++# CONFIG_TWL4030_CORE is not set
++# CONFIG_TWL6040_CORE is not set
++# CONFIG_MFD_WL1273_CORE is not set
++# CONFIG_MFD_LM3533 is not set
++# CONFIG_MFD_TC3589X is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_MFD_T7L66XB is not set
++# CONFIG_MFD_TC6387XB is not set
++# CONFIG_MFD_TC6393XB is not set
++# CONFIG_MFD_ARIZONA_I2C is not set
++# CONFIG_MFD_ARIZONA_SPI is not set
++# CONFIG_MFD_WM8400 is not set
++# CONFIG_MFD_WM831X_I2C is not set
++# CONFIG_MFD_WM831X_SPI is not set
++# CONFIG_MFD_WM8350_I2C is not set
++# CONFIG_MFD_WM8994 is not set
++# CONFIG_REGULATOR is not set
++CONFIG_MEDIA_SUPPORT=m
++
++#
++# Multimedia core support
++#
++CONFIG_MEDIA_CAMERA_SUPPORT=y
++# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set
++# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set
++# CONFIG_MEDIA_RADIO_SUPPORT is not set
++# CONFIG_MEDIA_SDR_SUPPORT is not set
++# CONFIG_MEDIA_RC_SUPPORT is not set
++# CONFIG_MEDIA_CONTROLLER is not set
++CONFIG_VIDEO_DEV=m
++CONFIG_VIDEO_V4L2=m
++# CONFIG_VIDEO_ADV_DEBUG is not set
++# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
++CONFIG_VIDEOBUF2_CORE=m
++CONFIG_VIDEOBUF2_MEMOPS=m
++CONFIG_VIDEOBUF2_VMALLOC=m
++# CONFIG_TTPCI_EEPROM is not set
++
++#
++# Media drivers
++#
++# CONFIG_MEDIA_USB_SUPPORT is not set
++# CONFIG_V4L_PLATFORM_DRIVERS is not set
++# CONFIG_V4L_MEM2MEM_DRIVERS is not set
++# CONFIG_V4L_TEST_DRIVERS is not set
++
++#
++# Supported MMC/SDIO adapters
++#
++# CONFIG_CYPRESS_FIRMWARE is not set
++
++#
++# Media ancillary drivers (tuners, sensors, i2c, frontends)
++#
++CONFIG_MEDIA_SUBDRV_AUTOSELECT=y
++
++#
++# Audio decoders, processors and mixers
++#
++
++#
++# RDS decoders
++#
++
++#
++# Video decoders
++#
++
++#
++# Video and audio decoders
++#
++
++#
++# Video encoders
++#
++
++#
++# Camera sensor devices
++#
++
++#
++# Flash devices
++#
++
++#
++# Video improvement chips
++#
++
++#
++# Audio/Video compression chips
++#
++
++#
++# Miscellaneous helper chips
++#
++
++#
++# Sensors used on soc_camera driver
++#
++
++#
++# Tools to develop new frontends
++#
++# CONFIG_DVB_DUMMY_FE is not set
++
++#
++# Graphics support
++#
++# CONFIG_IMX_IPUV3_CORE is not set
++
++#
++# Direct Rendering Manager
++#
++# CONFIG_DRM is not set
++
++#
++# Frame buffer Devices
++#
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++CONFIG_FB_CMDLINE=y
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++# CONFIG_FB_CFB_FILLRECT is not set
++# CONFIG_FB_CFB_COPYAREA is not set
++# CONFIG_FB_CFB_IMAGEBLIT is not set
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# 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_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_ARMCLCD is not set
++# CONFIG_FB_OPENCORES is not set
++# CONFIG_FB_S1D13XXX is not set
++# CONFIG_FB_SMSCUFX is not set
++# CONFIG_FB_UDL is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_BROADSHEET is not set
++# CONFIG_FB_AUO_K190X is not set
++# CONFIG_FB_SIMPLE is not set
++# CONFIG_FB_SSD1307 is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++# CONFIG_VGASTATE is not set
++
++#
++# Console display driver support
++#
++CONFIG_DUMMY_CONSOLE=y
++# CONFIG_FRAMEBUFFER_CONSOLE is not set
++# CONFIG_LOGO is not set
++# CONFIG_SOUND is not set
++
++#
++# HID support
++#
++CONFIG_HID=y
++# CONFIG_HID_BATTERY_STRENGTH is not set
++# CONFIG_HIDRAW is not set
++# CONFIG_UHID is not set
++CONFIG_HID_GENERIC=y
++
++#
++# Special HID drivers
++#
++CONFIG_HID_A4TECH=y
++# CONFIG_HID_ACRUX is not set
++CONFIG_HID_APPLE=y
++# CONFIG_HID_APPLEIR is not set
++# CONFIG_HID_AUREAL is not set
++CONFIG_HID_BELKIN=y
++CONFIG_HID_CHERRY=y
++CONFIG_HID_CHICONY=y
++# CONFIG_HID_CP2112 is not set
++CONFIG_HID_CYPRESS=y
++# CONFIG_HID_DRAGONRISE is not set
++# CONFIG_HID_EMS_FF is not set
++# CONFIG_HID_ELECOM is not set
++# CONFIG_HID_ELO is not set
++CONFIG_HID_EZKEY=y
++# CONFIG_HID_HOLTEK is not set
++# CONFIG_HID_HUION 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_ICADE is not set
++# CONFIG_HID_TWINHAN is not set
++CONFIG_HID_KENSINGTON=y
++# CONFIG_HID_LCPOWER is not set
++# CONFIG_HID_LENOVO is not set
++CONFIG_HID_LOGITECH=y
++# CONFIG_HID_LOGITECH_HIDPP is not set
++# CONFIG_LOGITECH_FF is not set
++# CONFIG_LOGIRUMBLEPAD2_FF is not set
++# CONFIG_LOGIG940_FF is not set
++# CONFIG_LOGIWHEELS_FF is not set
++# CONFIG_HID_MAGICMOUSE is not set
++CONFIG_HID_MICROSOFT=y
++CONFIG_HID_MONTEREY=y
++# 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_PENMOUNT is not set
++# CONFIG_HID_PETALYNX is not set
++# CONFIG_HID_PICOLCD is not set
++# CONFIG_HID_PRIMAX is not set
++# CONFIG_HID_ROCCAT is not set
++# CONFIG_HID_SAITEK is not set
++# CONFIG_HID_SAMSUNG is not set
++# CONFIG_HID_SPEEDLINK is not set
++# CONFIG_HID_STEELSERIES is not set
++# CONFIG_HID_SUNPLUS is not set
++# CONFIG_HID_RMI 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_XINMO is not set
++# CONFIG_HID_ZEROPLUS is not set
++# CONFIG_HID_ZYDACRON is not set
++# CONFIG_HID_SENSOR_HUB is not set
++
++#
++# USB HID support
++#
++CONFIG_USB_HID=y
++# CONFIG_HID_PID is not set
++# CONFIG_USB_HIDDEV is not set
++
++#
++# I2C HID support
++#
++# CONFIG_I2C_HID is not set
++CONFIG_USB_OHCI_LITTLE_ENDIAN=y
++CONFIG_USB_SUPPORT=y
++CONFIG_USB_COMMON=y
++CONFIG_USB_ARCH_HAS_HCD=y
++CONFIG_USB=y
++# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
++
++#
++# Miscellaneous USB options
++#
++CONFIG_USB_DEFAULT_PERSIST=y
++# CONFIG_USB_DYNAMIC_MINORS is not set
++# CONFIG_USB_OTG_WHITELIST is not set
++# CONFIG_USB_OTG_FSM is not set
++# CONFIG_USB_MON is not set
++# CONFIG_USB_WUSB_CBAF is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_C67X00_HCD is not set
++# CONFIG_USB_XHCI_HCD is not set
++CONFIG_USB_EHCI_HCD=y
++# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
++CONFIG_USB_EHCI_TT_NEWSCHED=y
++CONFIG_USB_EHCI_HCD_PLATFORM=y
++# 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_FUSBH200_HCD is not set
++# CONFIG_USB_FOTG210_HCD is not set
++# CONFIG_USB_MAX3421_HCD is not set
++CONFIG_USB_OHCI_HCD=y
++CONFIG_USB_OHCI_HCD_PLATFORM=y
++# CONFIG_USB_SL811_HCD is not set
++# CONFIG_USB_R8A66597_HCD is not set
++# CONFIG_USB_HCD_TEST_MODE is not set
++
++#
++# USB Device Class drivers
++#
++# CONFIG_USB_ACM is not set
++# CONFIG_USB_PRINTER is not set
++# CONFIG_USB_WDM is not set
++# CONFIG_USB_TMC is not set
++
++#
++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
++#
++
++#
++# also be needed; see USB_STORAGE Help for more info
++#
++CONFIG_USB_STORAGE=y
++# CONFIG_USB_STORAGE_DEBUG is not set
++# CONFIG_USB_STORAGE_REALTEK is not set
++# CONFIG_USB_STORAGE_DATAFAB is not set
++# CONFIG_USB_STORAGE_FREECOM is not set
++# CONFIG_USB_STORAGE_ISD200 is not set
++# CONFIG_USB_STORAGE_USBAT is not set
++# CONFIG_USB_STORAGE_SDDR09 is not set
++# CONFIG_USB_STORAGE_SDDR55 is not set
++# CONFIG_USB_STORAGE_JUMPSHOT is not set
++# CONFIG_USB_STORAGE_ALAUDA is not set
++# CONFIG_USB_STORAGE_ONETOUCH is not set
++# CONFIG_USB_STORAGE_KARMA is not set
++# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
++# CONFIG_USB_STORAGE_ENE_UB6250 is not set
++# CONFIG_USB_UAS is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++# CONFIG_USBIP_CORE is not set
++# CONFIG_USB_MUSB_HDRC is not set
++# CONFIG_USB_DWC3 is not set
++# CONFIG_USB_DWC2 is not set
++# CONFIG_USB_CHIPIDEA is not set
++
++#
++# USB port drivers
++#
++# CONFIG_USB_SERIAL is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
++# CONFIG_USB_SEVSEG is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
++# CONFIG_USB_APPLEDISPLAY is not set
++# CONFIG_USB_SISUSBVGA is not set
++# CONFIG_USB_LD is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
++# CONFIG_USB_IOWARRIOR is not set
++# CONFIG_USB_TEST is not set
++# CONFIG_USB_EHSET_TEST_FIXTURE is not set
++# CONFIG_USB_ISIGHTFW is not set
++# CONFIG_USB_YUREX is not set
++# CONFIG_USB_EZUSB_FX2 is not set
++# CONFIG_USB_HSIC_USB3503 is not set
++# CONFIG_USB_LINK_LAYER_TEST is not set
++
++#
++# USB Physical Layer drivers
++#
++# CONFIG_USB_PHY is not set
++# CONFIG_USB_OTG_WAKELOCK is not set
++# CONFIG_NOP_USB_XCEIV is not set
++# CONFIG_AM335X_PHY_USB is not set
++# CONFIG_USB_GPIO_VBUS is not set
++# CONFIG_USB_ISP1301 is not set
++# CONFIG_USB_ULPI is not set
++CONFIG_USB_GADGET=y
++# CONFIG_USB_GADGET_DEBUG is not set
++# CONFIG_USB_GADGET_DEBUG_FILES is not set
++CONFIG_USB_GADGET_VBUS_DRAW=2
++CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2
++
++#
++# USB Peripheral Controller
++#
++# CONFIG_USB_FUSB300 is not set
++# CONFIG_USB_FOTG210_UDC is not set
++# CONFIG_USB_GR_UDC is not set
++# CONFIG_USB_R8A66597 is not set
++# CONFIG_USB_PXA27X is not set
++# CONFIG_USB_MV_UDC is not set
++CONFIG_HIUSB_DEVICE2_0=y
++CONFIG_USB_HISI_UDC=m
++# CONFIG_USB_AUTO_SWITCH is not set
++# CONFIG_HIUSB_DEVICE3_0 is not set
++# CONFIG_USB_MV_U3D is not set
++# CONFIG_USB_M66592 is not set
++# CONFIG_USB_NET2272 is not set
++# CONFIG_USB_GADGET_XILINX is not set
++# CONFIG_USB_DUMMY_HCD is not set
++CONFIG_USB_LIBCOMPOSITE=m
++CONFIG_USB_F_MASS_STORAGE=m
++CONFIG_USB_F_UAC1=m
++CONFIG_USB_F_UVC=m
++# CONFIG_USB_CONFIGFS is not set
++# CONFIG_USB_ZERO is not set
++CONFIG_USB_AUDIO=m
++CONFIG_GADGET_UAC1=y
++# CONFIG_USB_ETH is not set
++# CONFIG_USB_G_NCM is not set
++# CONFIG_USB_GADGETFS is not set
++# CONFIG_USB_FUNCTIONFS is not set
++CONFIG_USB_MASS_STORAGE=m
++# CONFIG_USB_G_SERIAL is not set
++# CONFIG_USB_G_PRINTER is not set
++# CONFIG_USB_CDC_COMPOSITE is not set
++# CONFIG_USB_G_ACM_MS is not set
++# CONFIG_USB_G_MULTI is not set
++# CONFIG_USB_G_HID is not set
++# CONFIG_USB_G_DBGP is not set
++# CONFIG_USB_G_WEBCAM is not set
++CONFIG_USB_G_WEBCAM_AUDIO=m
++# CONFIG_UWB is not set
++CONFIG_MMC=y
++# CONFIG_MMC_DEBUG is not set
++# CONFIG_MMC_CLKGATE is not set
++CONFIG_MMC_EMBEDDED_SDIO=y
++# CONFIG_MMC_PARANOID_SD_INIT is not set
++
++#
++# MMC/SD/SDIO Card Drivers
++#
++CONFIG_MMC_BLOCK=y
++CONFIG_MMC_BLOCK_MINORS=8
++CONFIG_MMC_BLOCK_BOUNCE=y
++# CONFIG_MMC_BLOCK_DEFERRED_RESUME is not set
++# CONFIG_SDIO_UART is not set
++# CONFIG_MMC_TEST is not set
++
++#
++# MMC/SD/SDIO Host Controller Drivers
++#
++# CONFIG_MMC_ARMMMCI is not set
++# CONFIG_MMC_SDHCI is not set
++# CONFIG_MMC_DW is not set
++# CONFIG_MMC_VUB300 is not set
++# CONFIG_MMC_USHC is not set
++# CONFIG_MMC_USDHI6ROL0 is not set
++CONFIG_HIMCIV200=y
++CONFIG_SEND_AUTO_STOP=y
++CONFIG_DETECT_CARD_TIME=200
++# CONFIG_MEMSTICK is not set
++# CONFIG_NEW_LEDS is not set
++# CONFIG_SWITCH is not set
++# CONFIG_ACCESSIBILITY is not set
++# CONFIG_EDAC is not set
++CONFIG_RTC_LIB=y
++# CONFIG_RTC_CLASS is not set
++# CONFIG_DMADEVICES is not set
++# CONFIG_AUXDISPLAY is not set
++# CONFIG_UIO is not set
++# CONFIG_VIRT_DRIVERS is not set
++
++#
++# Virtio drivers
++#
++# CONFIG_VIRTIO_MMIO is not set
++
++#
++# Microsoft Hyper-V guest support
++#
++# CONFIG_STAGING is not set
++
++#
++# SOC (System On Chip) specific Drivers
++#
++# CONFIG_SOC_TI is not set
++CONFIG_CLKDEV_LOOKUP=y
++CONFIG_HAVE_CLK_PREPARE=y
++CONFIG_COMMON_CLK=y
++
++#
++# Common Clock Framework
++#
++# CONFIG_COMMON_CLK_SI5351 is not set
++# CONFIG_COMMON_CLK_SI570 is not set
++# CONFIG_COMMON_CLK_PXA is not set
++# CONFIG_COMMON_CLK_QCOM is not set
++
++#
++# Hardware Spinlock drivers
++#
++
++#
++# Clock Source drivers
++#
++CONFIG_CLKSRC_OF=y
++CONFIG_CLKSRC_MMIO=y
++# CONFIG_ATMEL_PIT is not set
++# CONFIG_SH_TIMER_CMT is not set
++# CONFIG_SH_TIMER_MTU2 is not set
++# CONFIG_SH_TIMER_TMU is not set
++# CONFIG_EM_TIMER_STI is not set
++# CONFIG_CLKSRC_VERSATILE is not set
++# CONFIG_MAILBOX is not set
++# CONFIG_IOMMU_SUPPORT is not set
++
++#
++# Remoteproc drivers
++#
++# CONFIG_STE_MODEM_RPROC is not set
++
++#
++# Rpmsg drivers
++#
++
++#
++# SOC (System On Chip) specific Drivers
++#
++# 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
++CONFIG_IRQCHIP=y
++CONFIG_ARM_VIC=y
++CONFIG_ARM_VIC_NR=2
++# CONFIG_IPACK_BUS is not set
++CONFIG_RESET_CONTROLLER=y
++# CONFIG_FMC is not set
++
++#
++# PHY Subsystem
++#
++CONFIG_GENERIC_PHY=y
++# CONFIG_BCM_KONA_USB2_PHY is not set
++CONFIG_PHY_HISI_INNO_USB2=y
++# CONFIG_POWERCAP is not set
++# CONFIG_MCB is not set
++CONFIG_HI_DMAC=y
++CONFIG_HI_DMAC_CHANNEL_NUM=4
++
++#
++# Hisilicon driver support
++#
++
++#
++# File systems
++#
++# CONFIG_EXT2_FS is not set
++# CONFIG_EXT3_FS is not set
++CONFIG_EXT4_FS=y
++CONFIG_EXT4_USE_FOR_EXT23=y
++# CONFIG_EXT4_FS_POSIX_ACL is not set
++# CONFIG_EXT4_FS_SECURITY is not set
++# CONFIG_EXT4_DEBUG is not set
++CONFIG_JBD2=y
++# CONFIG_JBD2_DEBUG is not set
++CONFIG_FS_MBCACHE=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_BTRFS_FS is not set
++# CONFIG_NILFS2_FS is not set
++CONFIG_FS_POSIX_ACL=y
++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 is not set
++# CONFIG_FUSE_FS is not set
++# CONFIG_OVERLAY_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_KERNFS=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=m
++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_YAFFS_FS=y
++CONFIG_YAFFS_YAFFS1=y
++# CONFIG_YAFFS_9BYTE_TAGS is not set
++# CONFIG_YAFFS_DOES_ECC is not set
++CONFIG_YAFFS_YAFFS2=y
++CONFIG_YAFFS_AUTO_YAFFS2=y
++# CONFIG_YAFFS_DISABLE_TAGS_ECC is not set
++# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
++# CONFIG_YAFFS_EMPTY_LOST_AND_FOUND is not set
++# CONFIG_YAFFS_DISABLE_BLOCK_REFRESHING is not set
++# CONFIG_YAFFS_DISABLE_BACKGROUND is not set
++# CONFIG_YAFFS_DISABLE_BAD_BLOCK_MARKING is not set
++CONFIG_YAFFS_XATTR=y
++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 is not set
++# CONFIG_JFFS2_FS_XATTR is not set
++# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
++CONFIG_JFFS2_ZLIB=y
++# CONFIG_JFFS2_LZO is not set
++CONFIG_JFFS2_RTIME=y
++# CONFIG_JFFS2_RUBIN 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 is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V2=y
++CONFIG_NFS_V3=y
++CONFIG_NFS_V3_ACL=y
++# CONFIG_NFS_V4 is not set
++# CONFIG_NFS_SWAP is not set
++# CONFIG_ROOT_NFS is not set
++# CONFIG_NFSD is not set
++CONFIG_GRACE_PERIOD=y
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_ACL_SUPPORT=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 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
++# CONFIG_DLM is not set
++
++#
++# Kernel hacking
++#
++
++#
++# printk and dmesg options
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4
++# CONFIG_BOOT_PRINTK_DELAY is not set
++
++#
++# Compile-time checks and compiler options
++#
++# CONFIG_DEBUG_INFO is not set
++# CONFIG_ENABLE_WARN_DEPRECATED is not set
++# CONFIG_ENABLE_MUST_CHECK is not set
++CONFIG_FRAME_WARN=1024
++# CONFIG_STRIP_ASM_SYMS is not set
++# CONFIG_READABLE_ASM is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++# CONFIG_DEBUG_FS is not set
++# CONFIG_HEADERS_CHECK is not set
++# CONFIG_DEBUG_SECTION_MISMATCH is not set
++# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
++# CONFIG_MAGIC_SYSRQ is not set
++CONFIG_DEBUG_KERNEL=y
++
++#
++# Memory Debugging
++#
++# 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_STACK_USAGE is not set
++# CONFIG_DEBUG_VM is not set
++CONFIG_DEBUG_MEMORY_INIT=y
++# CONFIG_DEBUG_HIGHMEM is not set
++# CONFIG_DEBUG_SHIRQ is not set
++
++#
++# Debug Lockups and Hangs
++#
++# CONFIG_LOCKUP_DETECTOR is not set
++# CONFIG_DETECT_HUNG_TASK is not set
++CONFIG_PANIC_ON_OOPS=y
++CONFIG_PANIC_ON_OOPS_VALUE=1
++CONFIG_PANIC_TIMEOUT=0
++CONFIG_SCHED_DEBUG=y
++# CONFIG_SCHEDSTATS is not set
++# CONFIG_SCHED_STACK_END_CHECK is not set
++# CONFIG_TIMER_STATS is not set
++
++#
++# Lock Debugging (spinlocks, mutexes, etc...)
++#
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_LOCK_STAT is not set
++# CONFIG_DEBUG_ATOMIC_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_LOCK_TORTURE_TEST is not set
++CONFIG_STACKTRACE=y
++# CONFIG_DEBUG_KOBJECT is not set
++CONFIG_DEBUG_BUGVERBOSE=y
++# CONFIG_DEBUG_LIST is not set
++# CONFIG_DEBUG_PI_LIST is not set
++# CONFIG_DEBUG_SG is not set
++# CONFIG_DEBUG_NOTIFIERS is not set
++# CONFIG_DEBUG_CREDENTIALS is not set
++
++#
++# RCU Debugging
++#
++# CONFIG_SPARSE_RCU_POINTER is not set
++# CONFIG_TORTURE_TEST is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_RCU_TRACE is not set
++# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_NOTIFIER_ERROR_INJECTION is not set
++# CONFIG_FAULT_INJECTION is not set
++# CONFIG_LATENCYTOP 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 is not set
++
++#
++# Runtime Testing
++#
++# CONFIG_TEST_LIST_SORT is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_RBTREE_TEST is not set
++# CONFIG_INTERVAL_TREE_TEST is not set
++# CONFIG_PERCPU_TEST is not set
++# CONFIG_ATOMIC64_SELFTEST is not set
++# CONFIG_TEST_STRING_HELPERS is not set
++# CONFIG_TEST_KSTRTOX is not set
++# CONFIG_TEST_RHASHTABLE is not set
++# CONFIG_DMA_API_DEBUG is not set
++# CONFIG_TEST_LKM is not set
++# CONFIG_TEST_USER_COPY is not set
++# CONFIG_TEST_BPF is not set
++# CONFIG_TEST_FIRMWARE is not set
++# CONFIG_TEST_UDELAY is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_KGDB is not set
++# CONFIG_ARM_PTDUMP is not set
++CONFIG_STRICT_DEVMEM=y
++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_DEBUG_UART_PL01X is not set
++# CONFIG_DEBUG_UART_8250 is not set
++# CONFIG_DEBUG_UART_BCM63XX is not set
++CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"
++# CONFIG_OC_ETM is not set
++# CONFIG_DEBUG_SET_MODULE_RONX is not set
++# CONFIG_CORESIGHT is not set
++
++#
++# 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_HASH=y
++CONFIG_CRYPTO_HASH2=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_MCRYPTD 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_CMAC is not set
++# CONFIG_CRYPTO_HMAC is not set
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_VMAC is not set
++
++#
++# Digest
++#
++CONFIG_CRYPTO_CRC32C=y
++# CONFIG_CRYPTO_CRC32 is not set
++# CONFIG_CRYPTO_CRCT10DIF 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=y
++# CONFIG_CRYPTO_ZLIB is not set
++CONFIG_CRYPTO_LZO=y
++# CONFIG_CRYPTO_LZ4 is not set
++# CONFIG_CRYPTO_LZ4HC is not set
++
++#
++# Random Number Generation
++#
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++# CONFIG_CRYPTO_DRBG_MENU is not set
++# CONFIG_CRYPTO_USER_API_HASH is not set
++# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
++CONFIG_CRYPTO_HW=y
++# CONFIG_BINARY_PRINTF is not set
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++CONFIG_GENERIC_STRNCPY_FROM_USER=y
++CONFIG_GENERIC_STRNLEN_USER=y
++CONFIG_GENERIC_NET_UTILS=y
++CONFIG_GENERIC_PCI_IOMAP=y
++CONFIG_GENERIC_IO=y
++CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
++# CONFIG_CRC_CCITT is not set
++CONFIG_CRC16=y
++# CONFIG_CRC_T10DIF is not set
++# 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_AUDIT_ARCH_COMPAT_GENERIC is not set
++# CONFIG_RANDOM32_SELFTEST is not set
++CONFIG_ZLIB_INFLATE=y
++CONFIG_ZLIB_DEFLATE=y
++CONFIG_LZO_COMPRESS=y
++CONFIG_LZO_DECOMPRESS=y
++CONFIG_LZ4_DECOMPRESS=y
++CONFIG_XZ_DEC=y
++CONFIG_XZ_DEC_X86=y
++CONFIG_XZ_DEC_POWERPC=y
++CONFIG_XZ_DEC_IA64=y
++CONFIG_XZ_DEC_ARM=y
++CONFIG_XZ_DEC_ARMTHUMB=y
++CONFIG_XZ_DEC_SPARC=y
++CONFIG_XZ_DEC_BCJ=y
++# CONFIG_XZ_DEC_TEST is not set
++CONFIG_DECOMPRESS_GZIP=y
++CONFIG_DECOMPRESS_BZIP2=y
++CONFIG_DECOMPRESS_LZMA=y
++CONFIG_DECOMPRESS_XZ=y
++CONFIG_DECOMPRESS_LZO=y
++CONFIG_DECOMPRESS_LZ4=y
++CONFIG_GENERIC_ALLOCATOR=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT_MAP=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
++CONFIG_LIBFDT=y
++CONFIG_ARCH_HAS_SG_CHAIN=y
++# CONFIG_VIRTUALIZATION is not set
+diff --git a/arch/arm/configs/hi3516ev100_full_defconfig b/arch/arm/configs/hi3516ev100_full_defconfig
+new file mode 100644
+index 0000000..70f4635
+--- /dev/null
++++ b/arch/arm/configs/hi3516ev100_full_defconfig
+@@ -0,0 +1,2529 @@
++#
++# Automatically generated file; DO NOT EDIT.
++# Linux/arm 3.18.20 Kernel Configuration
++#
++CONFIG_ARM=y
++CONFIG_ARM_HAS_SG_CHAIN=y
++CONFIG_MIGHT_HAVE_PCI=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=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_XCHGADD_ALGORITHM=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_NEED_DMA_MAP_STATE=y
++CONFIG_ARCH_SUPPORTS_UPROBES=y
++CONFIG_VECTORS_BASE=0xffff0000
++CONFIG_ARM_PATCH_PHYS_VIRT=y
++CONFIG_GENERIC_BUG=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++CONFIG_IRQ_WORK=y
++CONFIG_BUILDTIME_EXTABLE_SORT=y
++
++#
++# General setup
++#
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_CROSS_COMPILE=""
++# CONFIG_COMPILE_TEST is not set
++CONFIG_LOCALVERSION=""
++# CONFIG_LOCALVERSION_AUTO is not set
++CONFIG_HAVE_KERNEL_GZIP=y
++CONFIG_HAVE_KERNEL_LZMA=y
++CONFIG_HAVE_KERNEL_XZ=y
++CONFIG_HAVE_KERNEL_LZO=y
++CONFIG_HAVE_KERNEL_LZ4=y
++CONFIG_KERNEL_GZIP=y
++# CONFIG_KERNEL_LZMA is not set
++# CONFIG_KERNEL_XZ is not set
++# CONFIG_KERNEL_LZO is not set
++# CONFIG_KERNEL_LZ4 is not set
++CONFIG_DEFAULT_HOSTNAME="(none)"
++CONFIG_SWAP=y
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++# CONFIG_POSIX_MQUEUE is not set
++CONFIG_CROSS_MEMORY_ATTACH=y
++# CONFIG_FHANDLE is not set
++CONFIG_USELIB=y
++# CONFIG_AUDIT is not set
++CONFIG_HAVE_ARCH_AUDITSYSCALL=y
++
++#
++# IRQ subsystem
++#
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_GENERIC_IRQ_SHOW=y
++CONFIG_HARDIRQS_SW_RESEND=y
++CONFIG_IRQ_DOMAIN=y
++CONFIG_HANDLE_DOMAIN_IRQ=y
++CONFIG_IRQ_FORCED_THREADING=y
++CONFIG_SPARSE_IRQ=y
++CONFIG_GENERIC_CLOCKEVENTS=y
++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
++
++#
++# Timers subsystem
++#
++CONFIG_TICK_ONESHOT=y
++CONFIG_NO_HZ_COMMON=y
++# CONFIG_HZ_PERIODIC is not set
++CONFIG_NO_HZ_IDLE=y
++CONFIG_NO_HZ=y
++# CONFIG_HIGH_RES_TIMERS is not set
++
++#
++# CPU/Task time and stats accounting
++#
++CONFIG_VIRT_CPU_ACCOUNTING=y
++# CONFIG_TICK_CPU_ACCOUNTING is not set
++CONFIG_VIRT_CPU_ACCOUNTING_GEN=y
++# CONFIG_IRQ_TIME_ACCOUNTING is not set
++# CONFIG_BSD_PROCESS_ACCT is not set
++# CONFIG_TASKSTATS is not set
++
++#
++# RCU Subsystem
++#
++CONFIG_TINY_RCU=y
++# CONFIG_PREEMPT_RCU is not set
++# CONFIG_TASKS_RCU is not set
++# CONFIG_RCU_STALL_COMMON is not set
++CONFIG_CONTEXT_TRACKING=y
++# CONFIG_CONTEXT_TRACKING_FORCE is not set
++# CONFIG_TREE_RCU_TRACE is not set
++# CONFIG_BUILD_BIN2C is not set
++# CONFIG_IKCONFIG is not set
++CONFIG_LOG_BUF_SHIFT=17
++CONFIG_GENERIC_SCHED_CLOCK=y
++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_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_USER_NS is not set
++CONFIG_PID_NS=y
++CONFIG_NET_NS=y
++# 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=y
++CONFIG_RD_LZMA=y
++CONFIG_RD_XZ=y
++CONFIG_RD_LZO=y
++CONFIG_RD_LZ4=y
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++CONFIG_HAVE_UID16=y
++CONFIG_BPF=y
++# CONFIG_EXPERT is not set
++CONFIG_UID16=y
++# CONFIG_SGETMASK_SYSCALL is not set
++CONFIG_SYSFS_SYSCALL=y
++# CONFIG_SYSCTL_SYSCALL is not set
++CONFIG_KALLSYMS=y
++# CONFIG_KALLSYMS_ALL is not set
++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_BPF_SYSCALL is not set
++CONFIG_SHMEM=y
++CONFIG_AIO=y
++CONFIG_ADVISE_SYSCALLS=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_PROFILING is not set
++CONFIG_HAVE_OPROFILE=y
++# CONFIG_KPROBES is not set
++# CONFIG_JUMP_LABEL is not set
++# CONFIG_UPROBES is not set
++# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
++CONFIG_ARCH_USE_BUILTIN_BSWAP=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_GENERIC_SMP_IDLE_THREAD=y
++CONFIG_GENERIC_IDLE_POLL_SETUP=y
++CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
++CONFIG_HAVE_CLK=y
++CONFIG_HAVE_DMA_API_DEBUG=y
++CONFIG_HAVE_PERF_REGS=y
++CONFIG_HAVE_PERF_USER_STACK_DUMP=y
++CONFIG_HAVE_ARCH_JUMP_LABEL=y
++CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
++CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
++CONFIG_HAVE_CC_STACKPROTECTOR=y
++# CONFIG_CC_STACKPROTECTOR is not set
++CONFIG_CC_STACKPROTECTOR_NONE=y
++# CONFIG_CC_STACKPROTECTOR_REGULAR is not set
++# CONFIG_CC_STACKPROTECTOR_STRONG is not set
++CONFIG_HAVE_CONTEXT_TRACKING=y
++CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
++CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
++CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
++CONFIG_MODULES_USE_ELF_REL=y
++CONFIG_CLONE_BACKWARDS=y
++CONFIG_OLD_SIGSUSPEND3=y
++CONFIG_OLD_SIGACTION=y
++
++#
++# GCOV-based kernel profiling
++#
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_SLABINFO=y
++CONFIG_RT_MUTEXES=y
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++# CONFIG_MODULE_FORCE_LOAD is not set
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++# CONFIG_MODULE_SIG is not set
++# CONFIG_MODULE_COMPRESS is not set
++CONFIG_BLOCK=y
++CONFIG_LBDAF=y
++CONFIG_BLK_DEV_BSG=y
++# CONFIG_BLK_DEV_BSGLIB is not set
++# CONFIG_BLK_DEV_INTEGRITY is not set
++CONFIG_BLK_CMDLINE_PARSER=y
++
++#
++# Partition Types
++#
++CONFIG_PARTITION_ADVANCED=y
++# CONFIG_ACORN_PARTITION is not set
++# CONFIG_AIX_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=y
++# CONFIG_SYSV68_PARTITION is not set
++CONFIG_CMDLINE_PARTITION=y
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++CONFIG_DEFAULT_DEADLINE=y
++# CONFIG_DEFAULT_CFQ is not set
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="deadline"
++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_ARCH_SUPPORTS_ATOMIC_RMW=y
++CONFIG_FREEZER=y
++
++#
++# System Type
++#
++CONFIG_MMU=y
++CONFIG_ARCH_MULTIPLATFORM=y
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_AT91 is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_GEMINI is not set
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_IOP13XX is not set
++# CONFIG_ARCH_IOP32X is not set
++# CONFIG_ARCH_IOP33X is not set
++# CONFIG_ARCH_IXP4XX is not set
++# CONFIG_ARCH_DOVE is not set
++# CONFIG_ARCH_MV78XX0 is not set
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_MMP is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_W90X900 is not set
++# CONFIG_ARCH_LPC32XX is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_MSM is not set
++# CONFIG_ARCH_SHMOBILE_LEGACY 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_DAVINCI is not set
++# CONFIG_ARCH_OMAP1 is not set
++
++#
++# Multiple platform selection
++#
++
++#
++# CPU Core family selection
++#
++# CONFIG_ARCH_MULTI_V4 is not set
++# CONFIG_ARCH_MULTI_V4T is not set
++CONFIG_ARCH_MULTI_V5=y
++CONFIG_ARCH_MULTI_V4_V5=y
++# CONFIG_ARCH_MULTI_V6 is not set
++# CONFIG_ARCH_MULTI_V7 is not set
++CONFIG_ARCH_MULTI_CPU_AUTO=y
++# CONFIG_ARCH_MVEBU is not set
++CONFIG_ARCH_HISI=y
++
++#
++# Hisilicon platform type
++#
++CONFIG_ARCH_HI3516CV300=y
++# CONFIG_ARCH_MXC is not set
++# CONFIG_ARCH_MXS is not set
++# CONFIG_ARCH_NOMADIK is not set
++# CONFIG_ARCH_NSPIRE is not set
++# CONFIG_PLAT_SPEAR is not set
++# CONFIG_ARCH_U300 is not set
++# CONFIG_ARCH_WM8505 is not set
++CONFIG_ARM_TIMER_SP804=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 is not set
++# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
++CONFIG_NEED_KUSER_HELPERS=y
++CONFIG_KUSER_HELPERS=y
++# CONFIG_CACHE_L2X0 is not set
++CONFIG_ARM_L1_CACHE_SHIFT=5
++CONFIG_MULTI_IRQ_HANDLER=y
++
++#
++# Bus support
++#
++CONFIG_ARM_AMBA=y
++# CONFIG_PCI is not set
++# CONFIG_PCI_SYSCALL is not set
++# CONFIG_PCCARD is not set
++
++#
++# Kernel Features
++#
++CONFIG_DISABLE_CPU_SCHED_DOMAIN_BALANCE=y
++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=y
++# CONFIG_PREEMPT_VOLUNTARY is not set
++# CONFIG_PREEMPT is not set
++CONFIG_HZ_FIXED=0
++CONFIG_HZ_100=y
++# CONFIG_HZ_200 is not set
++# CONFIG_HZ_250 is not set
++# CONFIG_HZ_300 is not set
++# CONFIG_HZ_500 is not set
++# CONFIG_HZ_1000 is not set
++CONFIG_HZ=100
++# CONFIG_SCHED_HRTICK is not set
++CONFIG_AEABI=y
++# CONFIG_OABI_COMPAT is not set
++# 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_ARCH_WANT_GENERAL_HUGETLB=y
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_HAVE_MEMBLOCK=y
++CONFIG_NO_BOOTMEM=y
++# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
++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=0
++CONFIG_BOUNCE=y
++# CONFIG_KSM is not set
++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
++CONFIG_NEED_PER_CPU_KM=y
++# CONFIG_CLEANCACHE is not set
++# CONFIG_FRONTSWAP is not set
++# CONFIG_CMA is not set
++# CONFIG_ZPOOL is not set
++# CONFIG_ZBUD is not set
++# CONFIG_ZSMALLOC 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_SWIOTLB=y
++CONFIG_IOMMU_HELPER=y
++# CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART is not set
++
++#
++# Boot options
++#
++CONFIG_USE_OF=y
++CONFIG_ATAGS=y
++# CONFIG_DEPRECATED_PARAM_STRUCT is not set
++# CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE is not set
++CONFIG_ZBOOT_ROM_TEXT=0
++CONFIG_ZBOOT_ROM_BSS=0
++CONFIG_ARM_APPENDED_DTB=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_KEXEC is not set
++# CONFIG_CRASH_DUMP is not set
++CONFIG_AUTO_ZRELADDR=y
++
++#
++# CPU Power Management
++#
++
++#
++# CPU Frequency scaling
++#
++# CONFIG_CPU_FREQ is not set
++
++#
++# CPU Idle
++#
++# CONFIG_CPU_IDLE is not set
++# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++CONFIG_VFP=y
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
++CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
++CONFIG_BINFMT_SCRIPT=y
++# CONFIG_HAVE_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
++CONFIG_COREDUMP=y
++
++#
++# Power management options
++#
++CONFIG_SUSPEND=y
++CONFIG_SUSPEND_FREEZER=y
++CONFIG_WAKELOCK=y
++CONFIG_HIBERNATE_CALLBACKS=y
++CONFIG_HISI_SNAPSHOT_BOOT=y
++# CONFIG_DEFAULT_MTD is not set
++CONFIG_DEFAULT_DDR=y
++CONFIG_SNAPSHOT_BUF_START=0x8a000000
++CONFIG_SNAPSHOT_BUF_SIZE=0x4000000
++CONFIG_HIBERNATION=y
++CONFIG_GZIP_COMPRESS=y
++CONFIG_PM_STD_PARTITION=""
++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_WQ_POWER_EFFICIENT_DEFAULT is not set
++CONFIG_CPU_PM=y
++# CONFIG_SUSPEND_TIME is not set
++CONFIG_ARCH_SUSPEND_POSSIBLE=y
++CONFIG_ARM_CPU_SUSPEND=y
++CONFIG_ARCH_HIBERNATION_POSSIBLE=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_NET_IP_TUNNEL=m
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_NET_IPVTI is not set
++# CONFIG_NET_UDP_TUNNEL is not set
++# CONFIG_NET_FOU is not set
++# CONFIG_GENEVE 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=y
++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=y
++# 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_VTI 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_ANDROID_PARANOID_NETWORK is not set
++CONFIG_NET_ACTIVITY_STATS=y
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NET_PTP_CLASSIFY 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_NF_TABLES is not set
++# CONFIG_NETFILTER_XTABLES is not set
++# CONFIG_IP_SET is not set
++# CONFIG_IP_VS is not set
++
++#
++# IP: Netfilter Configuration
++#
++# CONFIG_NF_DEFRAG_IPV4 is not set
++# CONFIG_NF_LOG_ARP is not set
++# CONFIG_NF_LOG_IPV4 is not set
++# CONFIG_NF_REJECT_IPV4 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_NF_REJECT_IPV6 is not set
++# CONFIG_NF_LOG_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_HAVE_NET_DSA=y
++# 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_PHONET is not set
++# CONFIG_6LOWPAN 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_VSOCKETS is not set
++# CONFIG_NETLINK_MMAP is not set
++# CONFIG_NETLINK_DIAG is not set
++# CONFIG_NET_MPLS_GSO is not set
++# CONFIG_HSR is not set
++# CONFIG_CGROUP_NET_PRIO is not set
++# CONFIG_CGROUP_NET_CLASSID is not set
++CONFIG_NET_RX_BUSY_POLL=y
++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_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 is not set
++CONFIG_DEVTMPFS=y
++CONFIG_DEVTMPFS_MOUNT=y
++CONFIG_STANDALONE=y
++# CONFIG_PREVENT_FIRMWARE_BUILD is not set
++CONFIG_FW_LOADER=y
++# CONFIG_FIRMWARE_IN_KERNEL is not set
++CONFIG_EXTRA_FIRMWARE=""
++# CONFIG_FW_LOADER_USER_HELPER_FALLBACK is not set
++CONFIG_ALLOW_DEV_COREDUMP=y
++# 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_HAVE_CPU_AUTOPROBE is not set
++CONFIG_REGMAP=y
++CONFIG_REGMAP_MMIO=y
++CONFIG_DMA_SHARED_BUFFER=y
++# CONFIG_FENCE_TRACE is not set
++
++#
++# Bus devices
++#
++# CONFIG_BRCMSTB_GISB_ARB is not set
++# CONFIG_VEXPRESS_CONFIG 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=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_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
++CONFIG_HIFMC=y
++CONFIG_HIFMC_SPI_NAND=y
++# CONFIG_HIFMC_NAND is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++# CONFIG_MTD_CFI is not set
++# CONFIG_MTD_JEDECPROBE is not set
++CONFIG_MTD_MAP_BANK_WIDTH_1=y
++CONFIG_MTD_MAP_BANK_WIDTH_2=y
++CONFIG_MTD_MAP_BANK_WIDTH_4=y
++# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
++CONFIG_MTD_CFI_I1=y
++CONFIG_MTD_CFI_I2=y
++# CONFIG_MTD_CFI_I4 is not set
++# CONFIG_MTD_CFI_I8 is not set
++# CONFIG_MTD_RAM is not set
++# CONFIG_MTD_ROM is not set
++# CONFIG_MTD_ABSENT is not set
++
++#
++# Mapping drivers for chip access
++#
++# CONFIG_MTD_COMPLEX_MAPPINGS is not set
++# CONFIG_MTD_PLATRAM is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_DATAFLASH is not set
++# CONFIG_MTD_M25P80 is not set
++# CONFIG_MTD_SST25L is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_PHRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++# CONFIG_MTD_BLOCK2MTD is not set
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOCG3 is not set
++CONFIG_MTD_NAND_IDS=y
++CONFIG_MTD_NAND_ECC=y
++# CONFIG_MTD_NAND_ECC_SMC is not set
++CONFIG_MTD_NAND=y
++# CONFIG_MTD_NAND_ECC_BCH is not set
++# CONFIG_MTD_SM_COMMON is not set
++# CONFIG_MTD_NAND_DENALI is not set
++# CONFIG_MTD_NAND_GPIO is not set
++# CONFIG_MTD_NAND_OMAP_BCH_BUILD is not set
++# CONFIG_MTD_NAND_DISKONCHIP is not set
++# CONFIG_MTD_NAND_DOCG4 is not set
++# CONFIG_MTD_NAND_NANDSIM is not set
++# CONFIG_MTD_NAND_PLATFORM is not set
++# CONFIG_HISI_NAND_FS_MAY_NO_YAFFS2 is not set
++# CONFIG_HISI_NAND_ECC_STATUS_REPORT is not set
++# CONFIG_HIFMC100_NAND is not set
++CONFIG_HIFMC100_SPI_NAND=y
++CONFIG_SPI_NAND_MAX_CHIP_NUM=1
++# CONFIG_HIFMC100_HARDWARE_PAGESIZE_ECC is not set
++CONFIG_HIFMC100_AUTO_PAGESIZE_ECC=y
++# CONFIG_HIFMC100_PAGESIZE_AUTO_ECC_NONE is not set
++# CONFIG_MTD_ONENAND is not set
++
++#
++# LPDDR & LPDDR2 PCM memory drivers
++#
++# CONFIG_MTD_LPDDR is not set
++# CONFIG_MTD_LPDDR2_NVM is not set
++CONFIG_MTD_SPI_NOR=y
++# CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set
++CONFIG_SPI_HISI_SFC=y
++CONFIG_CLOSE_SPI_8PIN_4IO=y
++CONFIG_HISI_SPI_BLOCK_PROTECT=y
++CONFIG_MTD_UBI=y
++CONFIG_MTD_UBI_WL_THRESHOLD=4096
++CONFIG_MTD_UBI_BEB_LIMIT=20
++# CONFIG_MTD_UBI_FASTMAP is not set
++# CONFIG_MTD_UBI_GLUEBI is not set
++# CONFIG_MTD_UBI_BLOCK is not set
++CONFIG_DTC=y
++CONFIG_OF=y
++
++#
++# Device Tree and Open Firmware support
++#
++# 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_NET=y
++CONFIG_OF_MDIO=y
++CONFIG_OF_MTD=y
++CONFIG_OF_RESERVED_MEM=y
++CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
++# CONFIG_PARPORT is not set
++CONFIG_BLK_DEV=y
++# CONFIG_BLK_DEV_NULL_BLK is not set
++# CONFIG_BLK_DEV_COW_COMMON is not set
++# CONFIG_BLK_DEV_LOOP 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=65536
++# 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_DUMMY_IRQ 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_UID_STAT is not set
++# CONFIG_BMP085_I2C is not set
++# CONFIG_BMP085_SPI is not set
++# CONFIG_USB_SWITCH_FSA9480 is not set
++# CONFIG_LATTICE_ECP3_CONFIG is not set
++# CONFIG_SRAM is not set
++# CONFIG_C2PORT is not set
++
++#
++# EEPROM support
++#
++# CONFIG_EEPROM_AT24 is not set
++# CONFIG_EEPROM_AT25 is not set
++# CONFIG_EEPROM_LEGACY is not set
++# CONFIG_EEPROM_MAX6875 is not set
++# CONFIG_EEPROM_93CX6 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
++
++#
++# Intel MIC Bus Driver
++#
++
++#
++# Intel MIC Host Driver
++#
++
++#
++# Intel MIC Card Driver
++#
++# CONFIG_ECHO is not set
++# CONFIG_CXL_BASE is not set
++
++#
++# hisi 'himm/himd.l/himc'support
++#
++# CONFIG_HISI_REG 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_NETLINK is not set
++# CONFIG_SCSI_MQ_DEFAULT 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_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 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_NET_CORE=y
++# CONFIG_BONDING is not set
++# CONFIG_DUMMY is not set
++# CONFIG_EQUALIZER is not set
++# CONFIG_NET_TEAM is not set
++# CONFIG_MACVLAN is not set
++# CONFIG_VXLAN is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_TUN is not set
++# CONFIG_VETH is not set
++# CONFIG_NLMON is not set
++
++#
++# 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_NET_DSA_MV88E6171 is not set
++# CONFIG_NET_DSA_BCM_SF2 is not set
++CONFIG_ETHERNET=y
++# CONFIG_ALTERA_TSE is not set
++# CONFIG_NET_XGENE is not set
++# CONFIG_NET_VENDOR_ARC is not set
++# CONFIG_NET_CADENCE is not set
++# CONFIG_NET_VENDOR_BROADCOM is not set
++# CONFIG_NET_VENDOR_CIRRUS is not set
++# CONFIG_DM9000 is not set
++# CONFIG_DNET is not set
++# CONFIG_NET_VENDOR_FARADAY is not set
++CONFIG_NET_VENDOR_HISILICON=y
++# CONFIG_HIX5HD2_GMAC is not set
++CONFIG_HISI_FEMAC=y
++# CONFIG_HIETH_GMAC is not set
++# CONFIG_HIETH_SWITCH_FABRIC is not set
++# CONFIG_NET_VENDOR_INTEL is not set
++# CONFIG_NET_VENDOR_MARVELL is not set
++# CONFIG_NET_VENDOR_MICREL is not set
++CONFIG_NET_VENDOR_MICROCHIP=y
++# CONFIG_ENC28J60 is not set
++# CONFIG_NET_VENDOR_NATSEMI is not set
++# CONFIG_ETHOC is not set
++# CONFIG_NET_VENDOR_QUALCOMM is not set
++# CONFIG_NET_VENDOR_SAMSUNG is not set
++# CONFIG_NET_VENDOR_SEEQ is not set
++# CONFIG_NET_VENDOR_SMSC is not set
++# CONFIG_NET_VENDOR_STMICRO is not set
++# CONFIG_NET_VENDOR_VIA is not set
++# CONFIG_NET_VENDOR_WIZNET is not set
++CONFIG_PHYLIB=y
++
++#
++# MII PHY device drivers
++#
++# CONFIG_AT803X_PHY is not set
++# CONFIG_AMD_PHY is not set
++# CONFIG_AMD_XGBE_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 is not set
++# CONFIG_BROADCOM_PHY is not set
++# CONFIG_BCM7XXX_PHY is not set
++# CONFIG_BCM87XX_PHY is not set
++# CONFIG_ICPLUS_PHY is not set
++# CONFIG_REALTEK_PHY is not set
++# CONFIG_NATIONAL_PHY is not set
++# CONFIG_STE10XP is not set
++# CONFIG_LSI_ET1011C_PHY is not set
++# CONFIG_MICREL_PHY is not set
++# CONFIG_FIXED_PHY is not set
++# CONFIG_MDIO_BITBANG is not set
++# CONFIG_MDIO_BUS_MUX_GPIO is not set
++# CONFIG_MDIO_BUS_MUX_MMIOREG is not set
++# CONFIG_MDIO_BCM_UNIMAC is not set
++CONFIG_MDIO_HISI_FEMAC=y
++# CONFIG_MDIO_HISI_GEMAC is not set
++# CONFIG_MICREL_KS8995MA is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++CONFIG_USB_NET_DRIVERS=y
++# 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_RTL8152 is not set
++# CONFIG_USB_USBNET is not set
++# CONFIG_USB_IPHETH is not set
++# CONFIG_WLAN is not set
++
++#
++# Enable WiMAX (Networking options) to see the WiMAX drivers
++#
++# CONFIG_WAN is not set
++# CONFIG_ISDN is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
++# CONFIG_INPUT_POLLDEV is not set
++# CONFIG_INPUT_SPARSEKMAP is not set
++# CONFIG_INPUT_MATRIXKMAP is not set
++
++#
++# Userland interfaces
++#
++CONFIG_INPUT_MOUSEDEV=y
++CONFIG_INPUT_MOUSEDEV_PSAUX=y
++CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
++CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
++# CONFIG_INPUT_JOYDEV is not set
++CONFIG_INPUT_EVDEV=y
++# CONFIG_INPUT_EVBUG is not set
++# CONFIG_INPUT_KEYRESET is not set
++# CONFIG_INPUT_KEYCOMBO is not set
++
++#
++# Input Device Drivers
++#
++CONFIG_INPUT_KEYBOARD=y
++# CONFIG_KEYBOARD_ADP5588 is not set
++# CONFIG_KEYBOARD_ADP5589 is not set
++CONFIG_KEYBOARD_ATKBD=y
++# CONFIG_KEYBOARD_QT1070 is not set
++# CONFIG_KEYBOARD_QT2160 is not set
++# CONFIG_KEYBOARD_LKKBD is not set
++# CONFIG_KEYBOARD_GPIO is not set
++# CONFIG_KEYBOARD_GPIO_POLLED is not set
++# 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 is not set
++# CONFIG_KEYBOARD_CAP1106 is not set
++CONFIG_INPUT_MOUSE=y
++CONFIG_MOUSE_PS2=y
++CONFIG_MOUSE_PS2_ALPS=y
++CONFIG_MOUSE_PS2_LOGIPS2PP=y
++CONFIG_MOUSE_PS2_SYNAPTICS=y
++CONFIG_MOUSE_PS2_CYPRESS=y
++CONFIG_MOUSE_PS2_TRACKPOINT=y
++# CONFIG_MOUSE_PS2_ELANTECH is not set
++# CONFIG_MOUSE_PS2_SENTELIC is not set
++# CONFIG_MOUSE_PS2_TOUCHKIT is not set
++# CONFIG_MOUSE_SERIAL is not set
++# CONFIG_MOUSE_APPLETOUCH is not set
++# CONFIG_MOUSE_BCM5974 is not set
++# CONFIG_MOUSE_CYAPA is not set
++# CONFIG_MOUSE_VSXXXAA is not set
++# CONFIG_MOUSE_GPIO is not set
++# CONFIG_MOUSE_SYNAPTICS_I2C is not set
++# CONFIG_MOUSE_SYNAPTICS_USB is not set
++# CONFIG_INPUT_JOYSTICK is not set
++# CONFIG_INPUT_TABLET is not set
++# CONFIG_INPUT_TOUCHSCREEN is not set
++# CONFIG_INPUT_MISC is not set
++
++#
++# Hardware I/O ports
++#
++CONFIG_SERIO=y
++CONFIG_SERIO_SERPORT=y
++# CONFIG_SERIO_AMBAKMI is not set
++CONFIG_SERIO_LIBPS2=y
++# CONFIG_SERIO_RAW is not set
++# CONFIG_SERIO_ALTERA_PS2 is not set
++# CONFIG_SERIO_PS2MULT is not set
++# CONFIG_SERIO_ARC_PS2 is not set
++# CONFIG_SERIO_APBPS2 is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++CONFIG_TTY=y
++CONFIG_VT=y
++CONFIG_CONSOLE_TRANSLATIONS=y
++CONFIG_VT_CONSOLE=y
++CONFIG_VT_CONSOLE_SLEEP=y
++CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
++CONFIG_UNIX98_PTYS=y
++# CONFIG_DEVPTS_MULTIPLE_INSTANCES 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_DEVMEM=y
++CONFIG_DEVKMEM=y
++
++#
++# Serial drivers
++#
++CONFIG_SERIAL_EARLYCON=y
++# CONFIG_SERIAL_8250 is not set
++
++#
++# Non-8250 serial port support
++#
++# CONFIG_SERIAL_AMBA_PL010 is not set
++CONFIG_SERIAL_AMBA_PL011=y
++CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
++# CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST is not set
++# 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_SC16IS7XX is not set
++# CONFIG_SERIAL_ALTERA_JTAGUART is not set
++# CONFIG_SERIAL_ALTERA_UART is not set
++# CONFIG_SERIAL_IFX6X60 is not set
++# CONFIG_SERIAL_XILINX_PS_UART is not set
++# CONFIG_SERIAL_ARC is not set
++# CONFIG_SERIAL_FSL_LPUART is not set
++# CONFIG_SERIAL_ST_ASC is not set
++# CONFIG_HVC_DCC is not set
++# CONFIG_IPMI_HANDLER is not set
++CONFIG_HW_RANDOM=y
++# CONFIG_HW_RANDOM_TIMERIOMEM is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++# CONFIG_DCC_TTY is not set
++# CONFIG_XILLYBUS is not set
++
++#
++# I2C support
++#
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++# CONFIG_I2C_COMPAT is not set
++CONFIG_I2C_CHARDEV=y
++CONFIG_I2C_MUX=m
++
++#
++# Multiplexer I2C Chip support
++#
++# CONFIG_I2C_ARB_GPIO_CHALLENGE is not set
++# CONFIG_I2C_MUX_GPIO is not set
++# CONFIG_I2C_MUX_PCA9541 is not set
++# CONFIG_I2C_MUX_PCA954x is not set
++# CONFIG_I2C_MUX_PINCTRL is not set
++# CONFIG_I2C_HELPER_AUTO is not set
++# CONFIG_I2C_SMBUS is not set
++
++#
++# I2C Algorithms
++#
++# CONFIG_I2C_ALGOBIT is not set
++# CONFIG_I2C_ALGOPCF is not set
++# CONFIG_I2C_ALGOPCA is not set
++
++#
++# I2C Hardware Bus support
++#
++
++#
++# I2C system bus drivers (mostly embedded / system-on-chip)
++#
++# CONFIG_I2C_CBUS_GPIO is not set
++# CONFIG_I2C_DESIGNWARE_PLATFORM is not set
++# CONFIG_I2C_GPIO is not set
++CONFIG_I2C_HIBVT=y
++# CONFIG_I2C_HISI_V110 is not set
++# CONFIG_I2C_NOMADIK 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_RK3X 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_ROBOTFUZZ_OSIF 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_CADENCE is not set
++# CONFIG_SPI_GPIO is not set
++# CONFIG_SPI_FSL_SPI is not set
++# CONFIG_SPI_OC_TINY is not set
++CONFIG_SPI_PL022=y
++# CONFIG_SPI_PXA2XX_PCI is not set
++# CONFIG_SPI_ROCKCHIP 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=y
++# CONFIG_SPI_TLE62X0 is not set
++# CONFIG_SPMI is not set
++# CONFIG_HSI is not set
++
++#
++# PPS support
++#
++# CONFIG_PPS is not set
++
++#
++# PPS generators support
++#
++
++#
++# PTP clock support
++#
++# CONFIG_PTP_1588_CLOCK is not set
++
++#
++# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
++#
++CONFIG_PINCTRL=y
++
++#
++# Pin controllers
++#
++CONFIG_PINMUX=y
++CONFIG_PINCONF=y
++CONFIG_GENERIC_PINCONF=y
++# CONFIG_DEBUG_PINCTRL is not set
++CONFIG_PINCTRL_SINGLE=y
++CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
++CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
++CONFIG_GPIOLIB=y
++CONFIG_GPIO_DEVRES=y
++CONFIG_OF_GPIO=y
++CONFIG_GPIOLIB_IRQCHIP=y
++# CONFIG_DEBUG_GPIO is not set
++CONFIG_GPIO_SYSFS=y
++
++#
++# Memory mapped GPIO drivers:
++#
++# CONFIG_GPIO_GENERIC_PLATFORM is not set
++# CONFIG_GPIO_DWAPB is not set
++# CONFIG_GPIO_EM is not set
++# CONFIG_GPIO_ZEVIO is not set
++CONFIG_GPIO_PL061=y
++# CONFIG_GPIO_SCH311X is not set
++# CONFIG_GPIO_SYSCON is not set
++# CONFIG_GPIO_GRGPIO is not set
++
++#
++# I2C GPIO expanders:
++#
++# CONFIG_GPIO_MAX7300 is not set
++# CONFIG_GPIO_MAX732X is not set
++# CONFIG_GPIO_PCA953X is not set
++# CONFIG_GPIO_PCF857X is not set
++# CONFIG_GPIO_SX150X is not set
++# CONFIG_GPIO_ADP5588 is not set
++# CONFIG_GPIO_ADNP is not set
++
++#
++# PCI GPIO expanders:
++#
++
++#
++# SPI GPIO expanders:
++#
++# CONFIG_GPIO_MAX7301 is not set
++# CONFIG_GPIO_MCP23S08 is not set
++# CONFIG_GPIO_MC33880 is not set
++# CONFIG_GPIO_74X164 is not set
++
++#
++# AC97 GPIO expanders:
++#
++
++#
++# LPC GPIO expanders:
++#
++
++#
++# MODULbus GPIO expanders:
++#
++
++#
++# USB GPIO expanders:
++#
++# CONFIG_W1 is not set
++CONFIG_POWER_SUPPLY=y
++# CONFIG_POWER_SUPPLY_DEBUG is not set
++# CONFIG_PDA_POWER is not set
++# CONFIG_TEST_POWER is not set
++# CONFIG_BATTERY_DS2780 is not set
++# CONFIG_BATTERY_DS2781 is not set
++# CONFIG_BATTERY_DS2782 is not set
++# CONFIG_BATTERY_SBS is not set
++# CONFIG_BATTERY_BQ27x00 is not set
++# CONFIG_BATTERY_MAX17040 is not set
++# CONFIG_BATTERY_MAX17042 is not set
++# CONFIG_CHARGER_MAX8903 is not set
++# CONFIG_CHARGER_LP8727 is not set
++# CONFIG_CHARGER_GPIO is not set
++# CONFIG_CHARGER_BQ2415X is not set
++# CONFIG_CHARGER_BQ24190 is not set
++# CONFIG_CHARGER_BQ24735 is not set
++# CONFIG_CHARGER_SMB347 is not set
++CONFIG_POWER_RESET=y
++# CONFIG_POWER_RESET_BRCMSTB is not set
++# CONFIG_POWER_RESET_GPIO is not set
++# CONFIG_POWER_RESET_GPIO_RESTART is not set
++CONFIG_POWER_RESET_HISI=y
++# CONFIG_POWER_RESET_LTC2952 is not set
++# CONFIG_POWER_RESET_RESTART is not set
++# CONFIG_POWER_RESET_VERSATILE is not set
++CONFIG_POWER_RESET_SYSCON=y
++# CONFIG_POWER_AVS is not set
++# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
++# CONFIG_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=y
++# CONFIG_MFD_AS3711 is not set
++# CONFIG_MFD_AS3722 is not set
++# CONFIG_PMIC_ADP5520 is not set
++# CONFIG_MFD_AAT2870_CORE is not set
++# CONFIG_MFD_BCM590XX is not set
++# CONFIG_MFD_AXP20X is not set
++# CONFIG_MFD_CROS_EC is not set
++# CONFIG_MFD_ASIC3 is not set
++# CONFIG_PMIC_DA903X is not set
++# CONFIG_MFD_DA9052_SPI is not set
++# CONFIG_MFD_DA9052_I2C is not set
++# CONFIG_MFD_DA9055 is not set
++# CONFIG_MFD_DA9063 is not set
++# CONFIG_MFD_MC13XXX_SPI is not set
++# CONFIG_MFD_MC13XXX_I2C is not set
++# CONFIG_MFD_HI6421_PMIC is not set
++CONFIG_MFD_HISI_FMC=y
++# CONFIG_HTC_EGPIO is not set
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_HTC_I2CPLD is not set
++# CONFIG_INTEL_SOC_PMIC is not set
++# CONFIG_MFD_KEMPLD is not set
++# CONFIG_MFD_88PM800 is not set
++# CONFIG_MFD_88PM805 is not set
++# CONFIG_MFD_88PM860X is not set
++# CONFIG_MFD_MAX14577 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_MENF21BMC is not set
++# CONFIG_EZX_PCAP is not set
++# CONFIG_MFD_VIPERBOARD is not set
++# CONFIG_MFD_RETU is not set
++# CONFIG_MFD_PCF50633 is not set
++# CONFIG_MFD_PM8921_CORE is not set
++# CONFIG_MFD_RTSX_USB is not set
++# CONFIG_MFD_RC5T583 is not set
++# CONFIG_MFD_RK808 is not set
++# CONFIG_MFD_RN5T618 is not set
++# CONFIG_MFD_SEC_CORE is not set
++# CONFIG_MFD_SI476X_CORE is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_MFD_SMSC is not set
++# CONFIG_ABX500_CORE is not set
++# CONFIG_MFD_STMPE is not set
++CONFIG_MFD_SYSCON=y
++# CONFIG_MFD_TI_AM335X_TSCADC is not set
++# CONFIG_MFD_LP3943 is not set
++# CONFIG_MFD_LP8788 is not set
++# CONFIG_MFD_PALMAS is not set
++# CONFIG_TPS6105X is not set
++# CONFIG_TPS65010 is not set
++# CONFIG_TPS6507X is not set
++# CONFIG_MFD_TPS65090 is not set
++# CONFIG_MFD_TPS65217 is not set
++# CONFIG_MFD_TPS65218 is not set
++# CONFIG_MFD_TPS6586X is not set
++# CONFIG_MFD_TPS65910 is not set
++# CONFIG_MFD_TPS65912 is not set
++# CONFIG_MFD_TPS65912_I2C is not set
++# CONFIG_MFD_TPS65912_SPI is not set
++# CONFIG_MFD_TPS80031 is not set
++# CONFIG_TWL4030_CORE is not set
++# CONFIG_TWL6040_CORE is not set
++# CONFIG_MFD_WL1273_CORE is not set
++# CONFIG_MFD_LM3533 is not set
++# CONFIG_MFD_TC3589X is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_MFD_T7L66XB is not set
++# CONFIG_MFD_TC6387XB is not set
++# CONFIG_MFD_TC6393XB is not set
++# CONFIG_MFD_ARIZONA_I2C is not set
++# CONFIG_MFD_ARIZONA_SPI is not set
++# CONFIG_MFD_WM8400 is not set
++# CONFIG_MFD_WM831X_I2C is not set
++# CONFIG_MFD_WM831X_SPI is not set
++# CONFIG_MFD_WM8350_I2C is not set
++# CONFIG_MFD_WM8994 is not set
++# CONFIG_REGULATOR is not set
++CONFIG_MEDIA_SUPPORT=m
++
++#
++# Multimedia core support
++#
++CONFIG_MEDIA_CAMERA_SUPPORT=y
++# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set
++# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set
++# CONFIG_MEDIA_RADIO_SUPPORT is not set
++# CONFIG_MEDIA_SDR_SUPPORT is not set
++# CONFIG_MEDIA_RC_SUPPORT is not set
++# CONFIG_MEDIA_CONTROLLER is not set
++CONFIG_VIDEO_DEV=m
++CONFIG_VIDEO_V4L2=m
++# CONFIG_VIDEO_ADV_DEBUG is not set
++# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
++CONFIG_VIDEOBUF2_CORE=m
++CONFIG_VIDEOBUF2_MEMOPS=m
++CONFIG_VIDEOBUF2_VMALLOC=m
++# CONFIG_TTPCI_EEPROM is not set
++
++#
++# Media drivers
++#
++# CONFIG_MEDIA_USB_SUPPORT is not set
++# CONFIG_V4L_PLATFORM_DRIVERS is not set
++# CONFIG_V4L_MEM2MEM_DRIVERS is not set
++# CONFIG_V4L_TEST_DRIVERS is not set
++
++#
++# Supported MMC/SDIO adapters
++#
++# CONFIG_CYPRESS_FIRMWARE is not set
++
++#
++# Media ancillary drivers (tuners, sensors, i2c, frontends)
++#
++CONFIG_MEDIA_SUBDRV_AUTOSELECT=y
++
++#
++# Audio decoders, processors and mixers
++#
++
++#
++# RDS decoders
++#
++
++#
++# Video decoders
++#
++
++#
++# Video and audio decoders
++#
++
++#
++# Video encoders
++#
++
++#
++# Camera sensor devices
++#
++
++#
++# Flash devices
++#
++
++#
++# Video improvement chips
++#
++
++#
++# Audio/Video compression chips
++#
++
++#
++# Miscellaneous helper chips
++#
++
++#
++# Sensors used on soc_camera driver
++#
++
++#
++# Tools to develop new frontends
++#
++# CONFIG_DVB_DUMMY_FE is not set
++
++#
++# Graphics support
++#
++# CONFIG_IMX_IPUV3_CORE is not set
++
++#
++# Direct Rendering Manager
++#
++# CONFIG_DRM is not set
++
++#
++# Frame buffer Devices
++#
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++CONFIG_FB_CMDLINE=y
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++# CONFIG_FB_CFB_FILLRECT is not set
++# CONFIG_FB_CFB_COPYAREA is not set
++# CONFIG_FB_CFB_IMAGEBLIT is not set
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# 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_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_ARMCLCD is not set
++# CONFIG_FB_OPENCORES is not set
++# CONFIG_FB_S1D13XXX is not set
++# CONFIG_FB_SMSCUFX is not set
++# CONFIG_FB_UDL is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_BROADSHEET is not set
++# CONFIG_FB_AUO_K190X is not set
++# CONFIG_FB_SIMPLE is not set
++# CONFIG_FB_SSD1307 is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++# CONFIG_VGASTATE is not set
++
++#
++# Console display driver support
++#
++CONFIG_DUMMY_CONSOLE=y
++# CONFIG_FRAMEBUFFER_CONSOLE is not set
++# CONFIG_LOGO is not set
++# CONFIG_SOUND is not set
++
++#
++# HID support
++#
++CONFIG_HID=y
++# CONFIG_HID_BATTERY_STRENGTH is not set
++# CONFIG_HIDRAW is not set
++# CONFIG_UHID is not set
++CONFIG_HID_GENERIC=y
++
++#
++# Special HID drivers
++#
++CONFIG_HID_A4TECH=y
++# CONFIG_HID_ACRUX is not set
++CONFIG_HID_APPLE=y
++# CONFIG_HID_APPLEIR is not set
++# CONFIG_HID_AUREAL is not set
++CONFIG_HID_BELKIN=y
++CONFIG_HID_CHERRY=y
++CONFIG_HID_CHICONY=y
++# CONFIG_HID_CP2112 is not set
++CONFIG_HID_CYPRESS=y
++# CONFIG_HID_DRAGONRISE is not set
++# CONFIG_HID_EMS_FF is not set
++# CONFIG_HID_ELECOM is not set
++# CONFIG_HID_ELO is not set
++CONFIG_HID_EZKEY=y
++# CONFIG_HID_HOLTEK is not set
++# CONFIG_HID_HUION 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_ICADE is not set
++# CONFIG_HID_TWINHAN is not set
++CONFIG_HID_KENSINGTON=y
++# CONFIG_HID_LCPOWER is not set
++# CONFIG_HID_LENOVO is not set
++CONFIG_HID_LOGITECH=y
++# CONFIG_HID_LOGITECH_HIDPP is not set
++# CONFIG_LOGITECH_FF is not set
++# CONFIG_LOGIRUMBLEPAD2_FF is not set
++# CONFIG_LOGIG940_FF is not set
++# CONFIG_LOGIWHEELS_FF is not set
++# CONFIG_HID_MAGICMOUSE is not set
++CONFIG_HID_MICROSOFT=y
++CONFIG_HID_MONTEREY=y
++# 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_PENMOUNT is not set
++# CONFIG_HID_PETALYNX is not set
++# CONFIG_HID_PICOLCD is not set
++# CONFIG_HID_PRIMAX is not set
++# CONFIG_HID_ROCCAT is not set
++# CONFIG_HID_SAITEK is not set
++# CONFIG_HID_SAMSUNG is not set
++# CONFIG_HID_SPEEDLINK is not set
++# CONFIG_HID_STEELSERIES is not set
++# CONFIG_HID_SUNPLUS is not set
++# CONFIG_HID_RMI 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_XINMO is not set
++# CONFIG_HID_ZEROPLUS is not set
++# CONFIG_HID_ZYDACRON is not set
++# CONFIG_HID_SENSOR_HUB is not set
++
++#
++# USB HID support
++#
++CONFIG_USB_HID=y
++# CONFIG_HID_PID is not set
++# CONFIG_USB_HIDDEV is not set
++
++#
++# I2C HID support
++#
++# CONFIG_I2C_HID is not set
++CONFIG_USB_OHCI_LITTLE_ENDIAN=y
++CONFIG_USB_SUPPORT=y
++CONFIG_USB_COMMON=y
++CONFIG_USB_ARCH_HAS_HCD=y
++CONFIG_USB=y
++# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
++
++#
++# Miscellaneous USB options
++#
++CONFIG_USB_DEFAULT_PERSIST=y
++# CONFIG_USB_DYNAMIC_MINORS is not set
++# CONFIG_USB_OTG_WHITELIST is not set
++# CONFIG_USB_OTG_FSM is not set
++# CONFIG_USB_MON is not set
++# CONFIG_USB_WUSB_CBAF is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_C67X00_HCD is not set
++# CONFIG_USB_XHCI_HCD is not set
++CONFIG_USB_EHCI_HCD=y
++# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
++CONFIG_USB_EHCI_TT_NEWSCHED=y
++CONFIG_USB_EHCI_HCD_PLATFORM=y
++# 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_FUSBH200_HCD is not set
++# CONFIG_USB_FOTG210_HCD is not set
++# CONFIG_USB_MAX3421_HCD is not set
++CONFIG_USB_OHCI_HCD=y
++CONFIG_USB_OHCI_HCD_PLATFORM=y
++# CONFIG_USB_SL811_HCD is not set
++# CONFIG_USB_R8A66597_HCD is not set
++# CONFIG_USB_HCD_TEST_MODE is not set
++
++#
++# USB Device Class drivers
++#
++# CONFIG_USB_ACM is not set
++# CONFIG_USB_PRINTER is not set
++# CONFIG_USB_WDM is not set
++# CONFIG_USB_TMC is not set
++
++#
++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
++#
++
++#
++# also be needed; see USB_STORAGE Help for more info
++#
++CONFIG_USB_STORAGE=y
++# CONFIG_USB_STORAGE_DEBUG is not set
++# CONFIG_USB_STORAGE_REALTEK is not set
++# CONFIG_USB_STORAGE_DATAFAB is not set
++# CONFIG_USB_STORAGE_FREECOM is not set
++# CONFIG_USB_STORAGE_ISD200 is not set
++# CONFIG_USB_STORAGE_USBAT is not set
++# CONFIG_USB_STORAGE_SDDR09 is not set
++# CONFIG_USB_STORAGE_SDDR55 is not set
++# CONFIG_USB_STORAGE_JUMPSHOT is not set
++# CONFIG_USB_STORAGE_ALAUDA is not set
++# CONFIG_USB_STORAGE_ONETOUCH is not set
++# CONFIG_USB_STORAGE_KARMA is not set
++# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
++# CONFIG_USB_STORAGE_ENE_UB6250 is not set
++# CONFIG_USB_UAS is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++# CONFIG_USBIP_CORE is not set
++# CONFIG_USB_MUSB_HDRC is not set
++# CONFIG_USB_DWC3 is not set
++# CONFIG_USB_DWC2 is not set
++# CONFIG_USB_CHIPIDEA is not set
++
++#
++# USB port drivers
++#
++# CONFIG_USB_SERIAL is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
++# CONFIG_USB_SEVSEG is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
++# CONFIG_USB_APPLEDISPLAY is not set
++# CONFIG_USB_SISUSBVGA is not set
++# CONFIG_USB_LD is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
++# CONFIG_USB_IOWARRIOR is not set
++# CONFIG_USB_TEST is not set
++# CONFIG_USB_EHSET_TEST_FIXTURE is not set
++# CONFIG_USB_ISIGHTFW is not set
++# CONFIG_USB_YUREX is not set
++# CONFIG_USB_EZUSB_FX2 is not set
++# CONFIG_USB_HSIC_USB3503 is not set
++# CONFIG_USB_LINK_LAYER_TEST is not set
++
++#
++# USB Physical Layer drivers
++#
++# CONFIG_USB_PHY is not set
++# CONFIG_USB_OTG_WAKELOCK is not set
++# CONFIG_NOP_USB_XCEIV is not set
++# CONFIG_AM335X_PHY_USB is not set
++# CONFIG_USB_GPIO_VBUS is not set
++# CONFIG_USB_ISP1301 is not set
++# CONFIG_USB_ULPI is not set
++CONFIG_USB_GADGET=y
++# CONFIG_USB_GADGET_DEBUG is not set
++# CONFIG_USB_GADGET_DEBUG_FILES is not set
++CONFIG_USB_GADGET_VBUS_DRAW=2
++CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2
++
++#
++# USB Peripheral Controller
++#
++# CONFIG_USB_FUSB300 is not set
++# CONFIG_USB_FOTG210_UDC is not set
++# CONFIG_USB_GR_UDC is not set
++# CONFIG_USB_R8A66597 is not set
++# CONFIG_USB_PXA27X is not set
++# CONFIG_USB_MV_UDC is not set
++CONFIG_HIUSB_DEVICE2_0=y
++CONFIG_USB_HISI_UDC=m
++# CONFIG_USB_AUTO_SWITCH is not set
++# CONFIG_HIUSB_DEVICE3_0 is not set
++# CONFIG_USB_MV_U3D is not set
++# CONFIG_USB_M66592 is not set
++# CONFIG_USB_NET2272 is not set
++# CONFIG_USB_GADGET_XILINX is not set
++# CONFIG_USB_DUMMY_HCD is not set
++CONFIG_USB_LIBCOMPOSITE=m
++CONFIG_USB_F_MASS_STORAGE=m
++CONFIG_USB_F_UAC1=m
++CONFIG_USB_F_UVC=m
++# CONFIG_USB_CONFIGFS is not set
++# CONFIG_USB_ZERO is not set
++CONFIG_USB_AUDIO=m
++CONFIG_GADGET_UAC1=y
++# CONFIG_USB_ETH is not set
++# CONFIG_USB_G_NCM is not set
++# CONFIG_USB_GADGETFS is not set
++# CONFIG_USB_FUNCTIONFS is not set
++CONFIG_USB_MASS_STORAGE=m
++# CONFIG_USB_G_SERIAL is not set
++# CONFIG_USB_G_PRINTER is not set
++# CONFIG_USB_CDC_COMPOSITE is not set
++# CONFIG_USB_G_ACM_MS is not set
++# CONFIG_USB_G_MULTI is not set
++# CONFIG_USB_G_HID is not set
++# CONFIG_USB_G_DBGP is not set
++# CONFIG_USB_G_WEBCAM is not set
++CONFIG_USB_G_WEBCAM_AUDIO=m
++# CONFIG_UWB is not set
++CONFIG_MMC=y
++# CONFIG_MMC_DEBUG is not set
++# CONFIG_MMC_CLKGATE is not set
++CONFIG_MMC_EMBEDDED_SDIO=y
++# CONFIG_MMC_PARANOID_SD_INIT is not set
++
++#
++# MMC/SD/SDIO Card Drivers
++#
++CONFIG_MMC_BLOCK=y
++CONFIG_MMC_BLOCK_MINORS=8
++CONFIG_MMC_BLOCK_BOUNCE=y
++# CONFIG_MMC_BLOCK_DEFERRED_RESUME is not set
++# CONFIG_SDIO_UART is not set
++# CONFIG_MMC_TEST is not set
++
++#
++# MMC/SD/SDIO Host Controller Drivers
++#
++# CONFIG_MMC_ARMMMCI is not set
++# CONFIG_MMC_SDHCI is not set
++# CONFIG_MMC_DW is not set
++# CONFIG_MMC_VUB300 is not set
++# CONFIG_MMC_USHC is not set
++# CONFIG_MMC_USDHI6ROL0 is not set
++CONFIG_HIMCIV200=y
++CONFIG_SEND_AUTO_STOP=y
++CONFIG_DETECT_CARD_TIME=200
++# CONFIG_MEMSTICK is not set
++# CONFIG_NEW_LEDS is not set
++# CONFIG_SWITCH is not set
++# CONFIG_ACCESSIBILITY is not set
++# CONFIG_EDAC is not set
++CONFIG_RTC_LIB=y
++# CONFIG_RTC_CLASS is not set
++# CONFIG_DMADEVICES is not set
++# CONFIG_AUXDISPLAY is not set
++# CONFIG_UIO is not set
++# CONFIG_VIRT_DRIVERS is not set
++
++#
++# Virtio drivers
++#
++# CONFIG_VIRTIO_MMIO is not set
++
++#
++# Microsoft Hyper-V guest support
++#
++# CONFIG_STAGING is not set
++
++#
++# SOC (System On Chip) specific Drivers
++#
++# CONFIG_SOC_TI is not set
++CONFIG_CLKDEV_LOOKUP=y
++CONFIG_HAVE_CLK_PREPARE=y
++CONFIG_COMMON_CLK=y
++
++#
++# Common Clock Framework
++#
++# CONFIG_COMMON_CLK_SI5351 is not set
++# CONFIG_COMMON_CLK_SI570 is not set
++# CONFIG_COMMON_CLK_PXA is not set
++# CONFIG_COMMON_CLK_QCOM is not set
++
++#
++# Hardware Spinlock drivers
++#
++
++#
++# Clock Source drivers
++#
++CONFIG_CLKSRC_OF=y
++CONFIG_CLKSRC_MMIO=y
++# CONFIG_ATMEL_PIT is not set
++# CONFIG_SH_TIMER_CMT is not set
++# CONFIG_SH_TIMER_MTU2 is not set
++# CONFIG_SH_TIMER_TMU is not set
++# CONFIG_EM_TIMER_STI is not set
++# CONFIG_CLKSRC_VERSATILE is not set
++# CONFIG_MAILBOX is not set
++# CONFIG_IOMMU_SUPPORT is not set
++
++#
++# Remoteproc drivers
++#
++# CONFIG_STE_MODEM_RPROC is not set
++
++#
++# Rpmsg drivers
++#
++
++#
++# SOC (System On Chip) specific Drivers
++#
++# 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
++CONFIG_IRQCHIP=y
++CONFIG_ARM_VIC=y
++CONFIG_ARM_VIC_NR=2
++# CONFIG_IPACK_BUS is not set
++CONFIG_RESET_CONTROLLER=y
++# CONFIG_FMC is not set
++
++#
++# PHY Subsystem
++#
++CONFIG_GENERIC_PHY=y
++# CONFIG_BCM_KONA_USB2_PHY is not set
++CONFIG_PHY_HISI_INNO_USB2=y
++# CONFIG_POWERCAP is not set
++# CONFIG_MCB is not set
++CONFIG_HI_DMAC=y
++CONFIG_HI_DMAC_CHANNEL_NUM=4
++
++#
++# Hisilicon driver support
++#
++
++#
++# File systems
++#
++# CONFIG_EXT2_FS is not set
++# CONFIG_EXT3_FS is not set
++CONFIG_EXT4_FS=y
++CONFIG_EXT4_USE_FOR_EXT23=y
++# CONFIG_EXT4_FS_POSIX_ACL is not set
++# CONFIG_EXT4_FS_SECURITY is not set
++# CONFIG_EXT4_DEBUG is not set
++CONFIG_JBD2=y
++# CONFIG_JBD2_DEBUG is not set
++CONFIG_FS_MBCACHE=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_BTRFS_FS is not set
++# CONFIG_NILFS2_FS is not set
++CONFIG_FS_POSIX_ACL=y
++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 is not set
++# CONFIG_FUSE_FS is not set
++# CONFIG_OVERLAY_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_KERNFS=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=m
++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_YAFFS_FS=y
++CONFIG_YAFFS_YAFFS1=y
++# CONFIG_YAFFS_9BYTE_TAGS is not set
++# CONFIG_YAFFS_DOES_ECC is not set
++CONFIG_YAFFS_YAFFS2=y
++CONFIG_YAFFS_AUTO_YAFFS2=y
++# CONFIG_YAFFS_DISABLE_TAGS_ECC is not set
++# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
++# CONFIG_YAFFS_EMPTY_LOST_AND_FOUND is not set
++# CONFIG_YAFFS_DISABLE_BLOCK_REFRESHING is not set
++# CONFIG_YAFFS_DISABLE_BACKGROUND is not set
++# CONFIG_YAFFS_DISABLE_BAD_BLOCK_MARKING is not set
++CONFIG_YAFFS_XATTR=y
++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 is not set
++# CONFIG_JFFS2_FS_XATTR is not set
++# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
++CONFIG_JFFS2_ZLIB=y
++# CONFIG_JFFS2_LZO is not set
++CONFIG_JFFS2_RTIME=y
++# CONFIG_JFFS2_RUBIN 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 is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V2=y
++CONFIG_NFS_V3=y
++CONFIG_NFS_V3_ACL=y
++# CONFIG_NFS_V4 is not set
++# CONFIG_NFS_SWAP is not set
++# CONFIG_ROOT_NFS is not set
++# CONFIG_NFSD is not set
++CONFIG_GRACE_PERIOD=y
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_ACL_SUPPORT=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 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
++# CONFIG_DLM is not set
++
++#
++# Kernel hacking
++#
++
++#
++# printk and dmesg options
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4
++# CONFIG_BOOT_PRINTK_DELAY is not set
++
++#
++# Compile-time checks and compiler options
++#
++# CONFIG_DEBUG_INFO is not set
++# CONFIG_ENABLE_WARN_DEPRECATED is not set
++# CONFIG_ENABLE_MUST_CHECK is not set
++CONFIG_FRAME_WARN=1024
++# CONFIG_STRIP_ASM_SYMS is not set
++# CONFIG_READABLE_ASM is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++# CONFIG_DEBUG_FS is not set
++# CONFIG_HEADERS_CHECK is not set
++# CONFIG_DEBUG_SECTION_MISMATCH is not set
++# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
++# CONFIG_MAGIC_SYSRQ is not set
++CONFIG_DEBUG_KERNEL=y
++
++#
++# Memory Debugging
++#
++# 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_STACK_USAGE is not set
++# CONFIG_DEBUG_VM is not set
++CONFIG_DEBUG_MEMORY_INIT=y
++# CONFIG_DEBUG_HIGHMEM is not set
++# CONFIG_DEBUG_SHIRQ is not set
++
++#
++# Debug Lockups and Hangs
++#
++# CONFIG_LOCKUP_DETECTOR is not set
++# CONFIG_DETECT_HUNG_TASK is not set
++CONFIG_PANIC_ON_OOPS=y
++CONFIG_PANIC_ON_OOPS_VALUE=1
++CONFIG_PANIC_TIMEOUT=0
++CONFIG_SCHED_DEBUG=y
++# CONFIG_SCHEDSTATS is not set
++# CONFIG_SCHED_STACK_END_CHECK is not set
++# CONFIG_TIMER_STATS is not set
++
++#
++# Lock Debugging (spinlocks, mutexes, etc...)
++#
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_LOCK_STAT is not set
++# CONFIG_DEBUG_ATOMIC_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_LOCK_TORTURE_TEST is not set
++CONFIG_STACKTRACE=y
++# CONFIG_DEBUG_KOBJECT is not set
++CONFIG_DEBUG_BUGVERBOSE=y
++# CONFIG_DEBUG_LIST is not set
++# CONFIG_DEBUG_PI_LIST is not set
++# CONFIG_DEBUG_SG is not set
++# CONFIG_DEBUG_NOTIFIERS is not set
++# CONFIG_DEBUG_CREDENTIALS is not set
++
++#
++# RCU Debugging
++#
++# CONFIG_SPARSE_RCU_POINTER is not set
++# CONFIG_TORTURE_TEST is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_RCU_TRACE is not set
++# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_NOTIFIER_ERROR_INJECTION is not set
++# CONFIG_FAULT_INJECTION is not set
++# CONFIG_LATENCYTOP 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 is not set
++
++#
++# Runtime Testing
++#
++# CONFIG_TEST_LIST_SORT is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_RBTREE_TEST is not set
++# CONFIG_INTERVAL_TREE_TEST is not set
++# CONFIG_PERCPU_TEST is not set
++# CONFIG_ATOMIC64_SELFTEST is not set
++# CONFIG_TEST_STRING_HELPERS is not set
++# CONFIG_TEST_KSTRTOX is not set
++# CONFIG_TEST_RHASHTABLE is not set
++# CONFIG_DMA_API_DEBUG is not set
++# CONFIG_TEST_LKM is not set
++# CONFIG_TEST_USER_COPY is not set
++# CONFIG_TEST_BPF is not set
++# CONFIG_TEST_FIRMWARE is not set
++# CONFIG_TEST_UDELAY is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_KGDB is not set
++# CONFIG_ARM_PTDUMP is not set
++CONFIG_STRICT_DEVMEM=y
++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_DEBUG_UART_PL01X is not set
++# CONFIG_DEBUG_UART_8250 is not set
++# CONFIG_DEBUG_UART_BCM63XX is not set
++CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"
++# CONFIG_OC_ETM is not set
++# CONFIG_DEBUG_SET_MODULE_RONX is not set
++# CONFIG_CORESIGHT is not set
++
++#
++# 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_HASH=y
++CONFIG_CRYPTO_HASH2=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_MCRYPTD 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_CMAC is not set
++# CONFIG_CRYPTO_HMAC is not set
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_VMAC is not set
++
++#
++# Digest
++#
++CONFIG_CRYPTO_CRC32C=y
++# CONFIG_CRYPTO_CRC32 is not set
++# CONFIG_CRYPTO_CRCT10DIF 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=y
++# CONFIG_CRYPTO_ZLIB is not set
++CONFIG_CRYPTO_LZO=y
++# CONFIG_CRYPTO_LZ4 is not set
++# CONFIG_CRYPTO_LZ4HC is not set
++
++#
++# Random Number Generation
++#
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++# CONFIG_CRYPTO_DRBG_MENU is not set
++# CONFIG_CRYPTO_USER_API_HASH is not set
++# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
++CONFIG_CRYPTO_HW=y
++# CONFIG_BINARY_PRINTF is not set
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++CONFIG_GENERIC_STRNCPY_FROM_USER=y
++CONFIG_GENERIC_STRNLEN_USER=y
++CONFIG_GENERIC_NET_UTILS=y
++CONFIG_GENERIC_PCI_IOMAP=y
++CONFIG_GENERIC_IO=y
++CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
++# CONFIG_CRC_CCITT is not set
++CONFIG_CRC16=y
++# CONFIG_CRC_T10DIF is not set
++# 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_AUDIT_ARCH_COMPAT_GENERIC is not set
++# CONFIG_RANDOM32_SELFTEST is not set
++CONFIG_ZLIB_INFLATE=y
++CONFIG_ZLIB_DEFLATE=y
++CONFIG_LZO_COMPRESS=y
++CONFIG_LZO_DECOMPRESS=y
++CONFIG_LZ4_DECOMPRESS=y
++CONFIG_XZ_DEC=y
++CONFIG_XZ_DEC_X86=y
++CONFIG_XZ_DEC_POWERPC=y
++CONFIG_XZ_DEC_IA64=y
++CONFIG_XZ_DEC_ARM=y
++CONFIG_XZ_DEC_ARMTHUMB=y
++CONFIG_XZ_DEC_SPARC=y
++CONFIG_XZ_DEC_BCJ=y
++# CONFIG_XZ_DEC_TEST is not set
++CONFIG_DECOMPRESS_GZIP=y
++CONFIG_DECOMPRESS_BZIP2=y
++CONFIG_DECOMPRESS_LZMA=y
++CONFIG_DECOMPRESS_XZ=y
++CONFIG_DECOMPRESS_LZO=y
++CONFIG_DECOMPRESS_LZ4=y
++CONFIG_GENERIC_ALLOCATOR=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT_MAP=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
++CONFIG_LIBFDT=y
++CONFIG_ARCH_HAS_SG_CHAIN=y
++# CONFIG_VIRTUALIZATION is not set
+diff --git a/arch/arm/configs/hi3516ev100_mini_defconfig b/arch/arm/configs/hi3516ev100_mini_defconfig
+new file mode 100644
+index 0000000..116773a
+--- /dev/null
++++ b/arch/arm/configs/hi3516ev100_mini_defconfig
+@@ -0,0 +1,2188 @@
++#
++# Automatically generated file; DO NOT EDIT.
++# Linux/arm 3.18.20 Kernel Configuration
++#
++CONFIG_ARM=y
++CONFIG_ARM_HAS_SG_CHAIN=y
++CONFIG_MIGHT_HAVE_PCI=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=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_XCHGADD_ALGORITHM=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_NEED_DMA_MAP_STATE=y
++CONFIG_ARCH_SUPPORTS_UPROBES=y
++CONFIG_VECTORS_BASE=0xffff0000
++CONFIG_ARM_PATCH_PHYS_VIRT=y
++CONFIG_GENERIC_BUG=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++CONFIG_IRQ_WORK=y
++CONFIG_BUILDTIME_EXTABLE_SORT=y
++
++#
++# General setup
++#
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_CROSS_COMPILE=""
++# CONFIG_COMPILE_TEST is not set
++CONFIG_LOCALVERSION=""
++# CONFIG_LOCALVERSION_AUTO is not set
++CONFIG_HAVE_KERNEL_GZIP=y
++CONFIG_HAVE_KERNEL_LZMA=y
++CONFIG_HAVE_KERNEL_XZ=y
++CONFIG_HAVE_KERNEL_LZO=y
++CONFIG_HAVE_KERNEL_LZ4=y
++CONFIG_KERNEL_GZIP=y
++# CONFIG_KERNEL_LZMA is not set
++# CONFIG_KERNEL_XZ is not set
++# CONFIG_KERNEL_LZO is not set
++# CONFIG_KERNEL_LZ4 is not set
++CONFIG_DEFAULT_HOSTNAME="(none)"
++CONFIG_SWAP=y
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++# CONFIG_POSIX_MQUEUE is not set
++CONFIG_CROSS_MEMORY_ATTACH=y
++# CONFIG_FHANDLE is not set
++CONFIG_USELIB=y
++# CONFIG_AUDIT is not set
++CONFIG_HAVE_ARCH_AUDITSYSCALL=y
++
++#
++# IRQ subsystem
++#
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_GENERIC_IRQ_SHOW=y
++CONFIG_HARDIRQS_SW_RESEND=y
++CONFIG_IRQ_DOMAIN=y
++CONFIG_HANDLE_DOMAIN_IRQ=y
++CONFIG_IRQ_FORCED_THREADING=y
++CONFIG_SPARSE_IRQ=y
++CONFIG_GENERIC_CLOCKEVENTS=y
++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
++
++#
++# Timers subsystem
++#
++CONFIG_TICK_ONESHOT=y
++CONFIG_NO_HZ_COMMON=y
++# CONFIG_HZ_PERIODIC is not set
++CONFIG_NO_HZ_IDLE=y
++CONFIG_NO_HZ=y
++# CONFIG_HIGH_RES_TIMERS is not set
++
++#
++# CPU/Task time and stats accounting
++#
++CONFIG_VIRT_CPU_ACCOUNTING=y
++# CONFIG_TICK_CPU_ACCOUNTING is not set
++CONFIG_VIRT_CPU_ACCOUNTING_GEN=y
++# CONFIG_IRQ_TIME_ACCOUNTING is not set
++# CONFIG_BSD_PROCESS_ACCT is not set
++# CONFIG_TASKSTATS is not set
++
++#
++# RCU Subsystem
++#
++CONFIG_TINY_RCU=y
++# CONFIG_PREEMPT_RCU is not set
++# CONFIG_TASKS_RCU is not set
++# CONFIG_RCU_STALL_COMMON is not set
++CONFIG_CONTEXT_TRACKING=y
++# CONFIG_CONTEXT_TRACKING_FORCE is not set
++# CONFIG_TREE_RCU_TRACE is not set
++# CONFIG_BUILD_BIN2C is not set
++# CONFIG_IKCONFIG is not set
++CONFIG_LOG_BUF_SHIFT=17
++CONFIG_GENERIC_SCHED_CLOCK=y
++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_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_USER_NS is not set
++CONFIG_PID_NS=y
++CONFIG_NET_NS=y
++# 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=y
++CONFIG_RD_LZMA=y
++CONFIG_RD_XZ=y
++CONFIG_RD_LZO=y
++CONFIG_RD_LZ4=y
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++CONFIG_HAVE_UID16=y
++CONFIG_BPF=y
++# CONFIG_EXPERT is not set
++CONFIG_UID16=y
++# CONFIG_SGETMASK_SYSCALL is not set
++CONFIG_SYSFS_SYSCALL=y
++# CONFIG_SYSCTL_SYSCALL is not set
++CONFIG_KALLSYMS=y
++# CONFIG_KALLSYMS_ALL is not set
++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_BPF_SYSCALL is not set
++CONFIG_SHMEM=y
++CONFIG_AIO=y
++CONFIG_ADVISE_SYSCALLS=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_PROFILING is not set
++CONFIG_HAVE_OPROFILE=y
++# CONFIG_KPROBES is not set
++# CONFIG_JUMP_LABEL is not set
++# CONFIG_UPROBES is not set
++# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
++CONFIG_ARCH_USE_BUILTIN_BSWAP=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_GENERIC_SMP_IDLE_THREAD=y
++CONFIG_GENERIC_IDLE_POLL_SETUP=y
++CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
++CONFIG_HAVE_CLK=y
++CONFIG_HAVE_DMA_API_DEBUG=y
++CONFIG_HAVE_PERF_REGS=y
++CONFIG_HAVE_PERF_USER_STACK_DUMP=y
++CONFIG_HAVE_ARCH_JUMP_LABEL=y
++CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
++CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
++CONFIG_HAVE_CC_STACKPROTECTOR=y
++# CONFIG_CC_STACKPROTECTOR is not set
++CONFIG_CC_STACKPROTECTOR_NONE=y
++# CONFIG_CC_STACKPROTECTOR_REGULAR is not set
++# CONFIG_CC_STACKPROTECTOR_STRONG is not set
++CONFIG_HAVE_CONTEXT_TRACKING=y
++CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
++CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
++CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
++CONFIG_MODULES_USE_ELF_REL=y
++CONFIG_CLONE_BACKWARDS=y
++CONFIG_OLD_SIGSUSPEND3=y
++CONFIG_OLD_SIGACTION=y
++
++#
++# GCOV-based kernel profiling
++#
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_SLABINFO=y
++CONFIG_RT_MUTEXES=y
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++# CONFIG_MODULE_FORCE_LOAD is not set
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++# CONFIG_MODULE_SIG is not set
++# CONFIG_MODULE_COMPRESS is not set
++CONFIG_BLOCK=y
++CONFIG_LBDAF=y
++CONFIG_BLK_DEV_BSG=y
++# CONFIG_BLK_DEV_BSGLIB is not set
++# CONFIG_BLK_DEV_INTEGRITY is not set
++CONFIG_BLK_CMDLINE_PARSER=y
++
++#
++# Partition Types
++#
++CONFIG_PARTITION_ADVANCED=y
++# CONFIG_ACORN_PARTITION is not set
++# CONFIG_AIX_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=y
++# CONFIG_SYSV68_PARTITION is not set
++CONFIG_CMDLINE_PARTITION=y
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++CONFIG_DEFAULT_DEADLINE=y
++# CONFIG_DEFAULT_CFQ is not set
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="deadline"
++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_ARCH_SUPPORTS_ATOMIC_RMW=y
++CONFIG_FREEZER=y
++
++#
++# System Type
++#
++CONFIG_MMU=y
++CONFIG_ARCH_MULTIPLATFORM=y
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_AT91 is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_GEMINI is not set
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_IOP13XX is not set
++# CONFIG_ARCH_IOP32X is not set
++# CONFIG_ARCH_IOP33X is not set
++# CONFIG_ARCH_IXP4XX is not set
++# CONFIG_ARCH_DOVE is not set
++# CONFIG_ARCH_MV78XX0 is not set
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_MMP is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_W90X900 is not set
++# CONFIG_ARCH_LPC32XX is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_MSM is not set
++# CONFIG_ARCH_SHMOBILE_LEGACY 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_DAVINCI is not set
++# CONFIG_ARCH_OMAP1 is not set
++
++#
++# Multiple platform selection
++#
++
++#
++# CPU Core family selection
++#
++# CONFIG_ARCH_MULTI_V4 is not set
++# CONFIG_ARCH_MULTI_V4T is not set
++CONFIG_ARCH_MULTI_V5=y
++CONFIG_ARCH_MULTI_V4_V5=y
++# CONFIG_ARCH_MULTI_V6 is not set
++# CONFIG_ARCH_MULTI_V7 is not set
++CONFIG_ARCH_MULTI_CPU_AUTO=y
++# CONFIG_ARCH_MVEBU is not set
++CONFIG_ARCH_HISI=y
++
++#
++# Hisilicon platform type
++#
++CONFIG_ARCH_HI3516CV300=y
++# CONFIG_ARCH_MXC is not set
++# CONFIG_ARCH_MXS is not set
++# CONFIG_ARCH_NOMADIK is not set
++# CONFIG_ARCH_NSPIRE is not set
++# CONFIG_PLAT_SPEAR is not set
++# CONFIG_ARCH_U300 is not set
++# CONFIG_ARCH_WM8505 is not set
++CONFIG_ARM_TIMER_SP804=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 is not set
++# CONFIG_CPU_ICACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
++# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
++CONFIG_NEED_KUSER_HELPERS=y
++CONFIG_KUSER_HELPERS=y
++# CONFIG_CACHE_L2X0 is not set
++CONFIG_ARM_L1_CACHE_SHIFT=5
++CONFIG_MULTI_IRQ_HANDLER=y
++
++#
++# Bus support
++#
++CONFIG_ARM_AMBA=y
++# CONFIG_PCI is not set
++# CONFIG_PCI_SYSCALL is not set
++# CONFIG_PCCARD is not set
++
++#
++# Kernel Features
++#
++CONFIG_DISABLE_CPU_SCHED_DOMAIN_BALANCE=y
++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=y
++# CONFIG_PREEMPT_VOLUNTARY is not set
++# CONFIG_PREEMPT is not set
++CONFIG_HZ_FIXED=0
++CONFIG_HZ_100=y
++# CONFIG_HZ_200 is not set
++# CONFIG_HZ_250 is not set
++# CONFIG_HZ_300 is not set
++# CONFIG_HZ_500 is not set
++# CONFIG_HZ_1000 is not set
++CONFIG_HZ=100
++# CONFIG_SCHED_HRTICK is not set
++CONFIG_AEABI=y
++# CONFIG_OABI_COMPAT is not set
++# 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_ARCH_WANT_GENERAL_HUGETLB=y
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_HAVE_MEMBLOCK=y
++CONFIG_NO_BOOTMEM=y
++# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
++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=0
++CONFIG_BOUNCE=y
++# CONFIG_KSM is not set
++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
++CONFIG_NEED_PER_CPU_KM=y
++# CONFIG_CLEANCACHE is not set
++# CONFIG_FRONTSWAP is not set
++# CONFIG_CMA is not set
++# CONFIG_ZPOOL is not set
++# CONFIG_ZBUD is not set
++# CONFIG_ZSMALLOC 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_SWIOTLB=y
++CONFIG_IOMMU_HELPER=y
++# CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART is not set
++
++#
++# Boot options
++#
++CONFIG_USE_OF=y
++CONFIG_ATAGS=y
++# CONFIG_DEPRECATED_PARAM_STRUCT is not set
++# CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE is not set
++CONFIG_ZBOOT_ROM_TEXT=0
++CONFIG_ZBOOT_ROM_BSS=0
++CONFIG_ARM_APPENDED_DTB=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_KEXEC is not set
++# CONFIG_CRASH_DUMP is not set
++CONFIG_AUTO_ZRELADDR=y
++
++#
++# CPU Power Management
++#
++
++#
++# CPU Frequency scaling
++#
++# CONFIG_CPU_FREQ is not set
++
++#
++# CPU Idle
++#
++# CONFIG_CPU_IDLE is not set
++# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++CONFIG_VFP=y
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
++CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
++CONFIG_BINFMT_SCRIPT=y
++# CONFIG_HAVE_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
++CONFIG_COREDUMP=y
++
++#
++# Power management options
++#
++CONFIG_SUSPEND=y
++CONFIG_SUSPEND_FREEZER=y
++CONFIG_WAKELOCK=y
++CONFIG_HIBERNATE_CALLBACKS=y
++CONFIG_HISI_SNAPSHOT_BOOT=y
++# CONFIG_DEFAULT_MTD is not set
++CONFIG_DEFAULT_DDR=y
++CONFIG_SNAPSHOT_BUF_START=0x8a000000
++CONFIG_SNAPSHOT_BUF_SIZE=0x4000000
++CONFIG_HIBERNATION=y
++CONFIG_GZIP_COMPRESS=y
++CONFIG_PM_STD_PARTITION=""
++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_WQ_POWER_EFFICIENT_DEFAULT is not set
++CONFIG_CPU_PM=y
++# CONFIG_SUSPEND_TIME is not set
++CONFIG_ARCH_SUSPEND_POSSIBLE=y
++CONFIG_ARM_CPU_SUSPEND=y
++CONFIG_ARCH_HIBERNATION_POSSIBLE=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_NET_IP_TUNNEL=m
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_NET_IPVTI is not set
++# CONFIG_NET_UDP_TUNNEL is not set
++# CONFIG_NET_FOU is not set
++# CONFIG_GENEVE 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=y
++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=y
++# 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_VTI 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_ANDROID_PARANOID_NETWORK is not set
++CONFIG_NET_ACTIVITY_STATS=y
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NET_PTP_CLASSIFY 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_NF_TABLES is not set
++# CONFIG_NETFILTER_XTABLES is not set
++# CONFIG_IP_SET is not set
++# CONFIG_IP_VS is not set
++
++#
++# IP: Netfilter Configuration
++#
++# CONFIG_NF_DEFRAG_IPV4 is not set
++# CONFIG_NF_LOG_ARP is not set
++# CONFIG_NF_LOG_IPV4 is not set
++# CONFIG_NF_REJECT_IPV4 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_NF_REJECT_IPV6 is not set
++# CONFIG_NF_LOG_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_HAVE_NET_DSA=y
++# 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_PHONET is not set
++# CONFIG_6LOWPAN 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_VSOCKETS is not set
++# CONFIG_NETLINK_MMAP is not set
++# CONFIG_NETLINK_DIAG is not set
++# CONFIG_NET_MPLS_GSO is not set
++# CONFIG_HSR is not set
++# CONFIG_CGROUP_NET_PRIO is not set
++# CONFIG_CGROUP_NET_CLASSID is not set
++CONFIG_NET_RX_BUSY_POLL=y
++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 is not set
++# CONFIG_WIMAX is not set
++# CONFIG_RFKILL 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 is not set
++CONFIG_DEVTMPFS=y
++CONFIG_DEVTMPFS_MOUNT=y
++CONFIG_STANDALONE=y
++# CONFIG_PREVENT_FIRMWARE_BUILD is not set
++CONFIG_FW_LOADER=y
++# CONFIG_FIRMWARE_IN_KERNEL is not set
++CONFIG_EXTRA_FIRMWARE=""
++# CONFIG_FW_LOADER_USER_HELPER_FALLBACK is not set
++CONFIG_ALLOW_DEV_COREDUMP=y
++# 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_HAVE_CPU_AUTOPROBE is not set
++CONFIG_REGMAP=y
++CONFIG_REGMAP_MMIO=y
++# CONFIG_DMA_SHARED_BUFFER is not set
++
++#
++# Bus devices
++#
++# CONFIG_BRCMSTB_GISB_ARB is not set
++# CONFIG_VEXPRESS_CONFIG 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=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_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
++CONFIG_HIFMC=y
++# CONFIG_HIFMC_SPI_NAND is not set
++# CONFIG_HIFMC_NAND is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++# CONFIG_MTD_CFI is not set
++# CONFIG_MTD_JEDECPROBE is not set
++CONFIG_MTD_MAP_BANK_WIDTH_1=y
++CONFIG_MTD_MAP_BANK_WIDTH_2=y
++CONFIG_MTD_MAP_BANK_WIDTH_4=y
++# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
++CONFIG_MTD_CFI_I1=y
++CONFIG_MTD_CFI_I2=y
++# CONFIG_MTD_CFI_I4 is not set
++# CONFIG_MTD_CFI_I8 is not set
++# CONFIG_MTD_RAM is not set
++# CONFIG_MTD_ROM is not set
++# CONFIG_MTD_ABSENT is not set
++
++#
++# Mapping drivers for chip access
++#
++# CONFIG_MTD_COMPLEX_MAPPINGS is not set
++# CONFIG_MTD_PLATRAM is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_DATAFLASH is not set
++# CONFIG_MTD_M25P80 is not set
++# CONFIG_MTD_SST25L is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_PHRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++# CONFIG_MTD_BLOCK2MTD is not set
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOCG3 is not set
++CONFIG_MTD_NAND_IDS=y
++# CONFIG_MTD_NAND is not set
++# CONFIG_MTD_ONENAND is not set
++
++#
++# LPDDR & LPDDR2 PCM memory drivers
++#
++# CONFIG_MTD_LPDDR is not set
++# CONFIG_MTD_LPDDR2_NVM is not set
++CONFIG_MTD_SPI_NOR=y
++# CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set
++CONFIG_SPI_HISI_SFC=y
++CONFIG_CLOSE_SPI_8PIN_4IO=y
++CONFIG_HISI_SPI_BLOCK_PROTECT=y
++CONFIG_MTD_UBI=y
++CONFIG_MTD_UBI_WL_THRESHOLD=4096
++CONFIG_MTD_UBI_BEB_LIMIT=20
++# CONFIG_MTD_UBI_FASTMAP is not set
++# CONFIG_MTD_UBI_GLUEBI is not set
++# CONFIG_MTD_UBI_BLOCK is not set
++CONFIG_DTC=y
++CONFIG_OF=y
++
++#
++# Device Tree and Open Firmware support
++#
++# 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_NET=y
++CONFIG_OF_MDIO=y
++CONFIG_OF_MTD=y
++CONFIG_OF_RESERVED_MEM=y
++CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
++# CONFIG_PARPORT is not set
++CONFIG_BLK_DEV=y
++# CONFIG_BLK_DEV_NULL_BLK is not set
++# CONFIG_BLK_DEV_COW_COMMON is not set
++# CONFIG_BLK_DEV_LOOP 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=65536
++# 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_DUMMY_IRQ 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_UID_STAT is not set
++# CONFIG_BMP085_I2C is not set
++# CONFIG_BMP085_SPI is not set
++# CONFIG_USB_SWITCH_FSA9480 is not set
++# CONFIG_LATTICE_ECP3_CONFIG is not set
++# CONFIG_SRAM is not set
++# CONFIG_C2PORT is not set
++
++#
++# EEPROM support
++#
++# CONFIG_EEPROM_AT24 is not set
++# CONFIG_EEPROM_AT25 is not set
++# CONFIG_EEPROM_LEGACY is not set
++# CONFIG_EEPROM_MAX6875 is not set
++# CONFIG_EEPROM_93CX6 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
++
++#
++# Intel MIC Bus Driver
++#
++
++#
++# Intel MIC Host Driver
++#
++
++#
++# Intel MIC Card Driver
++#
++# CONFIG_ECHO is not set
++# CONFIG_CXL_BASE is not set
++
++#
++# hisi 'himm/himd.l/himc'support
++#
++# CONFIG_HISI_REG 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_NETLINK is not set
++# CONFIG_SCSI_MQ_DEFAULT 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_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 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_NET_CORE=y
++# CONFIG_BONDING is not set
++# CONFIG_DUMMY is not set
++# CONFIG_EQUALIZER is not set
++# CONFIG_NET_TEAM is not set
++# CONFIG_MACVLAN is not set
++# CONFIG_VXLAN is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_TUN is not set
++# CONFIG_VETH is not set
++# CONFIG_NLMON is not set
++
++#
++# 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_NET_DSA_MV88E6171 is not set
++# CONFIG_NET_DSA_BCM_SF2 is not set
++CONFIG_ETHERNET=y
++# CONFIG_ALTERA_TSE is not set
++# CONFIG_NET_XGENE is not set
++# CONFIG_NET_VENDOR_ARC is not set
++# CONFIG_NET_CADENCE is not set
++# CONFIG_NET_VENDOR_BROADCOM is not set
++# CONFIG_NET_VENDOR_CIRRUS is not set
++# CONFIG_DM9000 is not set
++# CONFIG_DNET is not set
++# CONFIG_NET_VENDOR_FARADAY is not set
++CONFIG_NET_VENDOR_HISILICON=y
++# CONFIG_HIX5HD2_GMAC is not set
++CONFIG_HISI_FEMAC=y
++# CONFIG_HIETH_GMAC is not set
++# CONFIG_HIETH_SWITCH_FABRIC is not set
++# CONFIG_NET_VENDOR_INTEL is not set
++# CONFIG_NET_VENDOR_MARVELL is not set
++# CONFIG_NET_VENDOR_MICREL is not set
++CONFIG_NET_VENDOR_MICROCHIP=y
++# CONFIG_ENC28J60 is not set
++# CONFIG_NET_VENDOR_NATSEMI is not set
++# CONFIG_ETHOC is not set
++# CONFIG_NET_VENDOR_QUALCOMM is not set
++# CONFIG_NET_VENDOR_SAMSUNG is not set
++# CONFIG_NET_VENDOR_SEEQ is not set
++# CONFIG_NET_VENDOR_SMSC is not set
++# CONFIG_NET_VENDOR_STMICRO is not set
++# CONFIG_NET_VENDOR_VIA is not set
++# CONFIG_NET_VENDOR_WIZNET is not set
++CONFIG_PHYLIB=y
++
++#
++# MII PHY device drivers
++#
++# CONFIG_AT803X_PHY is not set
++# CONFIG_AMD_PHY is not set
++# CONFIG_AMD_XGBE_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 is not set
++# CONFIG_BROADCOM_PHY is not set
++# CONFIG_BCM7XXX_PHY is not set
++# CONFIG_BCM87XX_PHY is not set
++# CONFIG_ICPLUS_PHY is not set
++# CONFIG_REALTEK_PHY is not set
++# CONFIG_NATIONAL_PHY is not set
++# CONFIG_STE10XP is not set
++# CONFIG_LSI_ET1011C_PHY is not set
++# CONFIG_MICREL_PHY is not set
++# CONFIG_FIXED_PHY is not set
++# CONFIG_MDIO_BITBANG is not set
++# CONFIG_MDIO_BUS_MUX_GPIO is not set
++# CONFIG_MDIO_BUS_MUX_MMIOREG is not set
++# CONFIG_MDIO_BCM_UNIMAC is not set
++CONFIG_MDIO_HISI_FEMAC=y
++# CONFIG_MDIO_HISI_GEMAC is not set
++# CONFIG_MICREL_KS8995MA is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++
++#
++# Host-side USB support is needed for USB Network Adapter support
++#
++# CONFIG_WLAN is not set
++
++#
++# Enable WiMAX (Networking options) to see the WiMAX drivers
++#
++# CONFIG_WAN is not set
++# CONFIG_ISDN is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
++# CONFIG_INPUT_POLLDEV is not set
++# CONFIG_INPUT_SPARSEKMAP is not set
++# CONFIG_INPUT_MATRIXKMAP is not set
++
++#
++# Userland interfaces
++#
++CONFIG_INPUT_MOUSEDEV=y
++CONFIG_INPUT_MOUSEDEV_PSAUX=y
++CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
++CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
++# CONFIG_INPUT_JOYDEV is not set
++CONFIG_INPUT_EVDEV=y
++# CONFIG_INPUT_EVBUG is not set
++# CONFIG_INPUT_KEYRESET is not set
++# CONFIG_INPUT_KEYCOMBO is not set
++
++#
++# Input Device Drivers
++#
++CONFIG_INPUT_KEYBOARD=y
++# CONFIG_KEYBOARD_ADP5588 is not set
++# CONFIG_KEYBOARD_ADP5589 is not set
++CONFIG_KEYBOARD_ATKBD=y
++# CONFIG_KEYBOARD_QT1070 is not set
++# CONFIG_KEYBOARD_QT2160 is not set
++# CONFIG_KEYBOARD_LKKBD is not set
++# CONFIG_KEYBOARD_GPIO is not set
++# CONFIG_KEYBOARD_GPIO_POLLED is not set
++# 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 is not set
++# CONFIG_KEYBOARD_CAP1106 is not set
++CONFIG_INPUT_MOUSE=y
++CONFIG_MOUSE_PS2=y
++CONFIG_MOUSE_PS2_ALPS=y
++CONFIG_MOUSE_PS2_LOGIPS2PP=y
++CONFIG_MOUSE_PS2_SYNAPTICS=y
++CONFIG_MOUSE_PS2_CYPRESS=y
++CONFIG_MOUSE_PS2_TRACKPOINT=y
++# CONFIG_MOUSE_PS2_ELANTECH is not set
++# CONFIG_MOUSE_PS2_SENTELIC is not set
++# CONFIG_MOUSE_PS2_TOUCHKIT is not set
++# CONFIG_MOUSE_SERIAL is not set
++# CONFIG_MOUSE_CYAPA is not set
++# CONFIG_MOUSE_VSXXXAA is not set
++# CONFIG_MOUSE_GPIO is not set
++# CONFIG_MOUSE_SYNAPTICS_I2C is not set
++# CONFIG_INPUT_JOYSTICK is not set
++# CONFIG_INPUT_TABLET is not set
++# CONFIG_INPUT_TOUCHSCREEN is not set
++# CONFIG_INPUT_MISC is not set
++
++#
++# Hardware I/O ports
++#
++CONFIG_SERIO=y
++CONFIG_SERIO_SERPORT=y
++# CONFIG_SERIO_AMBAKMI is not set
++CONFIG_SERIO_LIBPS2=y
++# CONFIG_SERIO_RAW is not set
++# CONFIG_SERIO_ALTERA_PS2 is not set
++# CONFIG_SERIO_PS2MULT is not set
++# CONFIG_SERIO_ARC_PS2 is not set
++# CONFIG_SERIO_APBPS2 is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++CONFIG_TTY=y
++CONFIG_VT=y
++CONFIG_CONSOLE_TRANSLATIONS=y
++CONFIG_VT_CONSOLE=y
++CONFIG_VT_CONSOLE_SLEEP=y
++CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
++CONFIG_UNIX98_PTYS=y
++# CONFIG_DEVPTS_MULTIPLE_INSTANCES 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_DEVMEM=y
++CONFIG_DEVKMEM=y
++
++#
++# Serial drivers
++#
++CONFIG_SERIAL_EARLYCON=y
++# CONFIG_SERIAL_8250 is not set
++
++#
++# Non-8250 serial port support
++#
++# CONFIG_SERIAL_AMBA_PL010 is not set
++CONFIG_SERIAL_AMBA_PL011=y
++CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
++# CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST is not set
++# 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_SC16IS7XX is not set
++# CONFIG_SERIAL_ALTERA_JTAGUART is not set
++# CONFIG_SERIAL_ALTERA_UART is not set
++# CONFIG_SERIAL_IFX6X60 is not set
++# CONFIG_SERIAL_XILINX_PS_UART is not set
++# CONFIG_SERIAL_ARC is not set
++# CONFIG_SERIAL_FSL_LPUART is not set
++# CONFIG_SERIAL_ST_ASC is not set
++# CONFIG_HVC_DCC is not set
++# CONFIG_IPMI_HANDLER is not set
++CONFIG_HW_RANDOM=y
++# CONFIG_HW_RANDOM_TIMERIOMEM is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++# CONFIG_DCC_TTY is not set
++# CONFIG_XILLYBUS is not set
++
++#
++# I2C support
++#
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++# CONFIG_I2C_COMPAT is not set
++CONFIG_I2C_CHARDEV=y
++# CONFIG_I2C_MUX is not set
++# CONFIG_I2C_HELPER_AUTO is not set
++# CONFIG_I2C_SMBUS is not set
++
++#
++# I2C Algorithms
++#
++# CONFIG_I2C_ALGOBIT is not set
++# CONFIG_I2C_ALGOPCF is not set
++# CONFIG_I2C_ALGOPCA is not set
++
++#
++# I2C Hardware Bus support
++#
++
++#
++# I2C system bus drivers (mostly embedded / system-on-chip)
++#
++# CONFIG_I2C_CBUS_GPIO is not set
++# CONFIG_I2C_DESIGNWARE_PLATFORM is not set
++# CONFIG_I2C_GPIO is not set
++CONFIG_I2C_HIBVT=y
++# CONFIG_I2C_HISI_V110 is not set
++# CONFIG_I2C_NOMADIK 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_RK3X 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 is not set
++# CONFIG_SPI_CADENCE is not set
++# CONFIG_SPI_GPIO is not set
++# CONFIG_SPI_FSL_SPI is not set
++# CONFIG_SPI_OC_TINY is not set
++CONFIG_SPI_PL022=y
++# CONFIG_SPI_PXA2XX_PCI is not set
++# CONFIG_SPI_ROCKCHIP 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=y
++# CONFIG_SPI_TLE62X0 is not set
++# CONFIG_SPMI is not set
++# CONFIG_HSI is not set
++
++#
++# PPS support
++#
++# CONFIG_PPS is not set
++
++#
++# PPS generators support
++#
++
++#
++# PTP clock support
++#
++# CONFIG_PTP_1588_CLOCK is not set
++
++#
++# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
++#
++CONFIG_PINCTRL=y
++
++#
++# Pin controllers
++#
++CONFIG_PINMUX=y
++CONFIG_PINCONF=y
++CONFIG_GENERIC_PINCONF=y
++# CONFIG_DEBUG_PINCTRL is not set
++CONFIG_PINCTRL_SINGLE=y
++CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
++CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
++CONFIG_GPIOLIB=y
++CONFIG_GPIO_DEVRES=y
++CONFIG_OF_GPIO=y
++CONFIG_GPIOLIB_IRQCHIP=y
++# CONFIG_DEBUG_GPIO is not set
++CONFIG_GPIO_SYSFS=y
++
++#
++# Memory mapped GPIO drivers:
++#
++# CONFIG_GPIO_GENERIC_PLATFORM is not set
++# CONFIG_GPIO_DWAPB is not set
++# CONFIG_GPIO_EM is not set
++# CONFIG_GPIO_ZEVIO is not set
++CONFIG_GPIO_PL061=y
++# CONFIG_GPIO_SCH311X is not set
++# CONFIG_GPIO_SYSCON is not set
++# CONFIG_GPIO_GRGPIO is not set
++
++#
++# I2C GPIO expanders:
++#
++# CONFIG_GPIO_MAX7300 is not set
++# CONFIG_GPIO_MAX732X is not set
++# CONFIG_GPIO_PCA953X is not set
++# CONFIG_GPIO_PCF857X is not set
++# CONFIG_GPIO_SX150X is not set
++# CONFIG_GPIO_ADP5588 is not set
++# CONFIG_GPIO_ADNP is not set
++
++#
++# PCI GPIO expanders:
++#
++
++#
++# SPI GPIO expanders:
++#
++# CONFIG_GPIO_MAX7301 is not set
++# CONFIG_GPIO_MCP23S08 is not set
++# CONFIG_GPIO_MC33880 is not set
++# CONFIG_GPIO_74X164 is not set
++
++#
++# AC97 GPIO expanders:
++#
++
++#
++# LPC GPIO expanders:
++#
++
++#
++# MODULbus GPIO expanders:
++#
++
++#
++# USB GPIO expanders:
++#
++# CONFIG_W1 is not set
++CONFIG_POWER_SUPPLY=y
++# CONFIG_POWER_SUPPLY_DEBUG is not set
++# CONFIG_PDA_POWER is not set
++# CONFIG_TEST_POWER is not set
++# CONFIG_BATTERY_DS2780 is not set
++# CONFIG_BATTERY_DS2781 is not set
++# CONFIG_BATTERY_DS2782 is not set
++# CONFIG_BATTERY_SBS is not set
++# CONFIG_BATTERY_BQ27x00 is not set
++# CONFIG_BATTERY_MAX17040 is not set
++# CONFIG_BATTERY_MAX17042 is not set
++# CONFIG_CHARGER_MAX8903 is not set
++# CONFIG_CHARGER_LP8727 is not set
++# CONFIG_CHARGER_GPIO is not set
++# CONFIG_CHARGER_BQ2415X is not set
++# CONFIG_CHARGER_BQ24190 is not set
++# CONFIG_CHARGER_BQ24735 is not set
++# CONFIG_CHARGER_SMB347 is not set
++CONFIG_POWER_RESET=y
++# CONFIG_POWER_RESET_BRCMSTB is not set
++# CONFIG_POWER_RESET_GPIO is not set
++# CONFIG_POWER_RESET_GPIO_RESTART is not set
++CONFIG_POWER_RESET_HISI=y
++# CONFIG_POWER_RESET_LTC2952 is not set
++# CONFIG_POWER_RESET_RESTART is not set
++# CONFIG_POWER_RESET_VERSATILE is not set
++CONFIG_POWER_RESET_SYSCON=y
++# CONFIG_POWER_AVS is not set
++# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
++# CONFIG_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=y
++# CONFIG_MFD_AS3711 is not set
++# CONFIG_MFD_AS3722 is not set
++# CONFIG_PMIC_ADP5520 is not set
++# CONFIG_MFD_AAT2870_CORE is not set
++# CONFIG_MFD_BCM590XX is not set
++# CONFIG_MFD_AXP20X is not set
++# CONFIG_MFD_CROS_EC is not set
++# CONFIG_MFD_ASIC3 is not set
++# CONFIG_PMIC_DA903X is not set
++# CONFIG_MFD_DA9052_SPI is not set
++# CONFIG_MFD_DA9052_I2C is not set
++# CONFIG_MFD_DA9055 is not set
++# CONFIG_MFD_DA9063 is not set
++# CONFIG_MFD_MC13XXX_SPI is not set
++# CONFIG_MFD_MC13XXX_I2C is not set
++# CONFIG_MFD_HI6421_PMIC is not set
++CONFIG_MFD_HISI_FMC=y
++# CONFIG_HTC_EGPIO is not set
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_HTC_I2CPLD is not set
++# CONFIG_INTEL_SOC_PMIC is not set
++# CONFIG_MFD_KEMPLD is not set
++# CONFIG_MFD_88PM800 is not set
++# CONFIG_MFD_88PM805 is not set
++# CONFIG_MFD_88PM860X is not set
++# CONFIG_MFD_MAX14577 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_MENF21BMC is not set
++# CONFIG_EZX_PCAP is not set
++# CONFIG_MFD_RETU is not set
++# CONFIG_MFD_PCF50633 is not set
++# CONFIG_MFD_PM8921_CORE is not set
++# CONFIG_MFD_RC5T583 is not set
++# CONFIG_MFD_RK808 is not set
++# CONFIG_MFD_RN5T618 is not set
++# CONFIG_MFD_SEC_CORE is not set
++# CONFIG_MFD_SI476X_CORE is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_MFD_SMSC is not set
++# CONFIG_ABX500_CORE is not set
++# CONFIG_MFD_STMPE is not set
++CONFIG_MFD_SYSCON=y
++# CONFIG_MFD_TI_AM335X_TSCADC is not set
++# CONFIG_MFD_LP3943 is not set
++# CONFIG_MFD_LP8788 is not set
++# CONFIG_MFD_PALMAS is not set
++# CONFIG_TPS6105X is not set
++# CONFIG_TPS65010 is not set
++# CONFIG_TPS6507X is not set
++# CONFIG_MFD_TPS65090 is not set
++# CONFIG_MFD_TPS65217 is not set
++# CONFIG_MFD_TPS65218 is not set
++# CONFIG_MFD_TPS6586X is not set
++# CONFIG_MFD_TPS65910 is not set
++# CONFIG_MFD_TPS65912 is not set
++# CONFIG_MFD_TPS65912_I2C is not set
++# CONFIG_MFD_TPS65912_SPI is not set
++# CONFIG_MFD_TPS80031 is not set
++# CONFIG_TWL4030_CORE is not set
++# CONFIG_TWL6040_CORE is not set
++# CONFIG_MFD_WL1273_CORE is not set
++# CONFIG_MFD_LM3533 is not set
++# CONFIG_MFD_TC3589X is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_MFD_T7L66XB is not set
++# CONFIG_MFD_TC6387XB is not set
++# CONFIG_MFD_TC6393XB is not set
++# CONFIG_MFD_ARIZONA_I2C is not set
++# CONFIG_MFD_ARIZONA_SPI is not set
++# CONFIG_MFD_WM8400 is not set
++# CONFIG_MFD_WM831X_I2C is not set
++# CONFIG_MFD_WM831X_SPI is not set
++# CONFIG_MFD_WM8350_I2C is not set
++# CONFIG_MFD_WM8994 is not set
++# CONFIG_REGULATOR is not set
++# CONFIG_MEDIA_SUPPORT is not set
++
++#
++# Graphics support
++#
++# CONFIG_IMX_IPUV3_CORE is not set
++
++#
++# Direct Rendering Manager
++#
++# CONFIG_DRM is not set
++
++#
++# Frame buffer Devices
++#
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++CONFIG_FB_CMDLINE=y
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++# CONFIG_FB_CFB_FILLRECT is not set
++# CONFIG_FB_CFB_COPYAREA is not set
++# CONFIG_FB_CFB_IMAGEBLIT is not set
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# 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_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_ARMCLCD is not set
++# CONFIG_FB_OPENCORES is not set
++# CONFIG_FB_S1D13XXX is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_BROADSHEET is not set
++# CONFIG_FB_AUO_K190X is not set
++# CONFIG_FB_SIMPLE is not set
++# CONFIG_FB_SSD1307 is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++# CONFIG_VGASTATE is not set
++
++#
++# Console display driver support
++#
++CONFIG_DUMMY_CONSOLE=y
++# CONFIG_FRAMEBUFFER_CONSOLE is not set
++# CONFIG_LOGO is not set
++# CONFIG_SOUND is not set
++
++#
++# HID support
++#
++CONFIG_HID=y
++# CONFIG_HID_BATTERY_STRENGTH is not set
++# CONFIG_HIDRAW is not set
++# CONFIG_UHID is not set
++CONFIG_HID_GENERIC=y
++
++#
++# Special HID drivers
++#
++CONFIG_HID_A4TECH=y
++# CONFIG_HID_ACRUX is not set
++CONFIG_HID_APPLE=y
++# CONFIG_HID_AUREAL is not set
++CONFIG_HID_BELKIN=y
++CONFIG_HID_CHERRY=y
++CONFIG_HID_CHICONY=y
++CONFIG_HID_CYPRESS=y
++# CONFIG_HID_DRAGONRISE is not set
++# CONFIG_HID_EMS_FF is not set
++# CONFIG_HID_ELECOM is not set
++CONFIG_HID_EZKEY=y
++# 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_ICADE is not set
++# CONFIG_HID_TWINHAN is not set
++CONFIG_HID_KENSINGTON=y
++# CONFIG_HID_LCPOWER is not set
++# CONFIG_HID_LENOVO is not set
++CONFIG_HID_LOGITECH=y
++# CONFIG_HID_LOGITECH_HIDPP is not set
++# CONFIG_LOGITECH_FF is not set
++# CONFIG_LOGIRUMBLEPAD2_FF is not set
++# CONFIG_LOGIG940_FF is not set
++# CONFIG_LOGIWHEELS_FF is not set
++# CONFIG_HID_MAGICMOUSE is not set
++CONFIG_HID_MICROSOFT=y
++CONFIG_HID_MONTEREY=y
++# CONFIG_HID_MULTITOUCH 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_SAITEK is not set
++# CONFIG_HID_SAMSUNG is not set
++# CONFIG_HID_SPEEDLINK is not set
++# CONFIG_HID_STEELSERIES is not set
++# CONFIG_HID_SUNPLUS is not set
++# CONFIG_HID_RMI 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_XINMO is not set
++# CONFIG_HID_ZEROPLUS is not set
++# CONFIG_HID_ZYDACRON is not set
++# CONFIG_HID_SENSOR_HUB is not set
++
++#
++# I2C HID support
++#
++# CONFIG_I2C_HID is not set
++CONFIG_USB_OHCI_LITTLE_ENDIAN=y
++# CONFIG_USB_SUPPORT is not set
++# CONFIG_UWB is not set
++CONFIG_MMC=y
++# CONFIG_MMC_DEBUG is not set
++# CONFIG_MMC_CLKGATE is not set
++CONFIG_MMC_EMBEDDED_SDIO=y
++# CONFIG_MMC_PARANOID_SD_INIT is not set
++
++#
++# MMC/SD/SDIO Card Drivers
++#
++CONFIG_MMC_BLOCK=y
++CONFIG_MMC_BLOCK_MINORS=8
++CONFIG_MMC_BLOCK_BOUNCE=y
++# CONFIG_MMC_BLOCK_DEFERRED_RESUME is not set
++# CONFIG_SDIO_UART is not set
++# CONFIG_MMC_TEST is not set
++
++#
++# MMC/SD/SDIO Host Controller Drivers
++#
++# CONFIG_MMC_ARMMMCI is not set
++# CONFIG_MMC_SDHCI is not set
++# CONFIG_MMC_DW is not set
++# CONFIG_MMC_USDHI6ROL0 is not set
++CONFIG_HIMCIV200=y
++CONFIG_SEND_AUTO_STOP=y
++CONFIG_DETECT_CARD_TIME=200
++# CONFIG_MEMSTICK is not set
++# CONFIG_NEW_LEDS is not set
++# CONFIG_SWITCH is not set
++# CONFIG_ACCESSIBILITY is not set
++# CONFIG_EDAC is not set
++CONFIG_RTC_LIB=y
++# CONFIG_RTC_CLASS is not set
++# CONFIG_DMADEVICES is not set
++# CONFIG_AUXDISPLAY is not set
++# CONFIG_UIO is not set
++# CONFIG_VIRT_DRIVERS is not set
++
++#
++# Virtio drivers
++#
++# CONFIG_VIRTIO_MMIO is not set
++
++#
++# Microsoft Hyper-V guest support
++#
++# CONFIG_STAGING is not set
++
++#
++# SOC (System On Chip) specific Drivers
++#
++# CONFIG_SOC_TI is not set
++CONFIG_CLKDEV_LOOKUP=y
++CONFIG_HAVE_CLK_PREPARE=y
++CONFIG_COMMON_CLK=y
++
++#
++# Common Clock Framework
++#
++# CONFIG_COMMON_CLK_SI5351 is not set
++# CONFIG_COMMON_CLK_SI570 is not set
++# CONFIG_COMMON_CLK_PXA is not set
++# CONFIG_COMMON_CLK_QCOM is not set
++
++#
++# Hardware Spinlock drivers
++#
++
++#
++# Clock Source drivers
++#
++CONFIG_CLKSRC_OF=y
++CONFIG_CLKSRC_MMIO=y
++# CONFIG_ATMEL_PIT is not set
++# CONFIG_SH_TIMER_CMT is not set
++# CONFIG_SH_TIMER_MTU2 is not set
++# CONFIG_SH_TIMER_TMU is not set
++# CONFIG_EM_TIMER_STI is not set
++# CONFIG_CLKSRC_VERSATILE is not set
++# CONFIG_MAILBOX is not set
++# CONFIG_IOMMU_SUPPORT is not set
++
++#
++# Remoteproc drivers
++#
++# CONFIG_STE_MODEM_RPROC is not set
++
++#
++# Rpmsg drivers
++#
++
++#
++# SOC (System On Chip) specific Drivers
++#
++# 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
++CONFIG_IRQCHIP=y
++CONFIG_ARM_VIC=y
++CONFIG_ARM_VIC_NR=2
++# CONFIG_IPACK_BUS is not set
++CONFIG_RESET_CONTROLLER=y
++# CONFIG_FMC is not set
++
++#
++# PHY Subsystem
++#
++CONFIG_GENERIC_PHY=y
++# CONFIG_BCM_KONA_USB2_PHY is not set
++# CONFIG_POWERCAP is not set
++# CONFIG_MCB is not set
++CONFIG_HI_DMAC=y
++CONFIG_HI_DMAC_CHANNEL_NUM=4
++
++#
++# Hisilicon driver support
++#
++
++#
++# File systems
++#
++# CONFIG_EXT2_FS is not set
++# CONFIG_EXT3_FS is not set
++# CONFIG_EXT4_FS is not set
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_BTRFS_FS is not set
++# CONFIG_NILFS2_FS is not set
++CONFIG_FS_POSIX_ACL=y
++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 is not set
++# CONFIG_FUSE_FS is not set
++# CONFIG_OVERLAY_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_KERNFS=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=m
++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_YAFFS_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 is not set
++# CONFIG_JFFS2_FS_XATTR is not set
++# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
++CONFIG_JFFS2_ZLIB=y
++# CONFIG_JFFS2_LZO is not set
++CONFIG_JFFS2_RTIME=y
++# CONFIG_JFFS2_RUBIN 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 is not set
++# 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 is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V2=y
++CONFIG_NFS_V3=y
++CONFIG_NFS_V3_ACL=y
++# CONFIG_NFS_V4 is not set
++# CONFIG_NFS_SWAP is not set
++# CONFIG_ROOT_NFS is not set
++# CONFIG_NFSD is not set
++CONFIG_GRACE_PERIOD=y
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_ACL_SUPPORT=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 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
++# CONFIG_DLM is not set
++
++#
++# Kernel hacking
++#
++
++#
++# printk and dmesg options
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4
++# CONFIG_BOOT_PRINTK_DELAY is not set
++
++#
++# Compile-time checks and compiler options
++#
++# CONFIG_DEBUG_INFO is not set
++# CONFIG_ENABLE_WARN_DEPRECATED is not set
++# CONFIG_ENABLE_MUST_CHECK is not set
++CONFIG_FRAME_WARN=1024
++# CONFIG_STRIP_ASM_SYMS is not set
++# CONFIG_READABLE_ASM is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++# CONFIG_DEBUG_FS is not set
++# CONFIG_HEADERS_CHECK is not set
++# CONFIG_DEBUG_SECTION_MISMATCH is not set
++# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
++# CONFIG_MAGIC_SYSRQ is not set
++CONFIG_DEBUG_KERNEL=y
++
++#
++# Memory Debugging
++#
++# 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_STACK_USAGE is not set
++# CONFIG_DEBUG_VM is not set
++CONFIG_DEBUG_MEMORY_INIT=y
++# CONFIG_DEBUG_HIGHMEM is not set
++# CONFIG_DEBUG_SHIRQ is not set
++
++#
++# Debug Lockups and Hangs
++#
++# CONFIG_LOCKUP_DETECTOR is not set
++# CONFIG_DETECT_HUNG_TASK is not set
++CONFIG_PANIC_ON_OOPS=y
++CONFIG_PANIC_ON_OOPS_VALUE=1
++CONFIG_PANIC_TIMEOUT=0
++CONFIG_SCHED_DEBUG=y
++# CONFIG_SCHEDSTATS is not set
++# CONFIG_SCHED_STACK_END_CHECK is not set
++# CONFIG_TIMER_STATS is not set
++
++#
++# Lock Debugging (spinlocks, mutexes, etc...)
++#
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_LOCK_STAT is not set
++# CONFIG_DEBUG_ATOMIC_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_LOCK_TORTURE_TEST is not set
++CONFIG_STACKTRACE=y
++# CONFIG_DEBUG_KOBJECT is not set
++CONFIG_DEBUG_BUGVERBOSE=y
++# CONFIG_DEBUG_LIST is not set
++# CONFIG_DEBUG_PI_LIST is not set
++# CONFIG_DEBUG_SG is not set
++# CONFIG_DEBUG_NOTIFIERS is not set
++# CONFIG_DEBUG_CREDENTIALS is not set
++
++#
++# RCU Debugging
++#
++# CONFIG_SPARSE_RCU_POINTER is not set
++# CONFIG_TORTURE_TEST is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_RCU_TRACE is not set
++# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_NOTIFIER_ERROR_INJECTION is not set
++# CONFIG_FAULT_INJECTION is not set
++# CONFIG_LATENCYTOP 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 is not set
++
++#
++# Runtime Testing
++#
++# CONFIG_TEST_LIST_SORT is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_RBTREE_TEST is not set
++# CONFIG_INTERVAL_TREE_TEST is not set
++# CONFIG_PERCPU_TEST is not set
++# CONFIG_ATOMIC64_SELFTEST is not set
++# CONFIG_TEST_STRING_HELPERS is not set
++# CONFIG_TEST_KSTRTOX is not set
++# CONFIG_TEST_RHASHTABLE is not set
++# CONFIG_DMA_API_DEBUG is not set
++# CONFIG_TEST_LKM is not set
++# CONFIG_TEST_USER_COPY is not set
++# CONFIG_TEST_BPF is not set
++# CONFIG_TEST_FIRMWARE is not set
++# CONFIG_TEST_UDELAY is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_KGDB is not set
++# CONFIG_ARM_PTDUMP is not set
++CONFIG_STRICT_DEVMEM=y
++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_DEBUG_UART_PL01X is not set
++# CONFIG_DEBUG_UART_8250 is not set
++# CONFIG_DEBUG_UART_BCM63XX is not set
++CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"
++# CONFIG_OC_ETM is not set
++# CONFIG_DEBUG_SET_MODULE_RONX is not set
++# CONFIG_CORESIGHT is not set
++
++#
++# 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_HASH=y
++CONFIG_CRYPTO_HASH2=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_MCRYPTD 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_CMAC is not set
++# CONFIG_CRYPTO_HMAC is not set
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_VMAC is not set
++
++#
++# Digest
++#
++CONFIG_CRYPTO_CRC32C=y
++# CONFIG_CRYPTO_CRC32 is not set
++# CONFIG_CRYPTO_CRCT10DIF 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=y
++# CONFIG_CRYPTO_ZLIB is not set
++CONFIG_CRYPTO_LZO=y
++# CONFIG_CRYPTO_LZ4 is not set
++# CONFIG_CRYPTO_LZ4HC is not set
++
++#
++# Random Number Generation
++#
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++# CONFIG_CRYPTO_DRBG_MENU is not set
++# CONFIG_CRYPTO_USER_API_HASH is not set
++# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
++CONFIG_CRYPTO_HW=y
++# CONFIG_BINARY_PRINTF is not set
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++CONFIG_GENERIC_STRNCPY_FROM_USER=y
++CONFIG_GENERIC_STRNLEN_USER=y
++CONFIG_GENERIC_NET_UTILS=y
++CONFIG_GENERIC_PCI_IOMAP=y
++CONFIG_GENERIC_IO=y
++CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
++# CONFIG_CRC_CCITT is not set
++CONFIG_CRC16=y
++# CONFIG_CRC_T10DIF is not set
++# 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_AUDIT_ARCH_COMPAT_GENERIC is not set
++# CONFIG_RANDOM32_SELFTEST is not set
++CONFIG_ZLIB_INFLATE=y
++CONFIG_ZLIB_DEFLATE=y
++CONFIG_LZO_COMPRESS=y
++CONFIG_LZO_DECOMPRESS=y
++CONFIG_LZ4_DECOMPRESS=y
++CONFIG_XZ_DEC=y
++CONFIG_XZ_DEC_X86=y
++CONFIG_XZ_DEC_POWERPC=y
++CONFIG_XZ_DEC_IA64=y
++CONFIG_XZ_DEC_ARM=y
++CONFIG_XZ_DEC_ARMTHUMB=y
++CONFIG_XZ_DEC_SPARC=y
++CONFIG_XZ_DEC_BCJ=y
++# CONFIG_XZ_DEC_TEST is not set
++CONFIG_DECOMPRESS_GZIP=y
++CONFIG_DECOMPRESS_BZIP2=y
++CONFIG_DECOMPRESS_LZMA=y
++CONFIG_DECOMPRESS_XZ=y
++CONFIG_DECOMPRESS_LZO=y
++CONFIG_DECOMPRESS_LZ4=y
++CONFIG_GENERIC_ALLOCATOR=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT_MAP=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
++CONFIG_LIBFDT=y
++CONFIG_ARCH_HAS_SG_CHAIN=y
++# CONFIG_VIRTUALIZATION is not set
+diff --git a/arch/arm/configs/hi3519_big_little_defconfig b/arch/arm/configs/hi3519_big_little_defconfig
+new file mode 100644
+index 0000000..f09a9bf
+--- /dev/null
++++ b/arch/arm/configs/hi3519_big_little_defconfig
+@@ -0,0 +1,2515 @@
++#
++# Automatically generated file; DO NOT EDIT.
++# Linux/arm 3.18.20 Kernel Configuration
++#
++CONFIG_ARM=y
++CONFIG_ARM_HAS_SG_CHAIN=y
++CONFIG_MIGHT_HAVE_PCI=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=y
++CONFIG_HAVE_PROC_CPU=y
++CONFIG_STACKTRACE_SUPPORT=y
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
++CONFIG_RWSEM_XCHGADD_ALGORITHM=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_NEED_DMA_MAP_STATE=y
++CONFIG_ARCH_SUPPORTS_UPROBES=y
++CONFIG_VECTORS_BASE=0xffff0000
++CONFIG_ARM_PATCH_PHYS_VIRT=y
++CONFIG_GENERIC_BUG=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++CONFIG_IRQ_WORK=y
++CONFIG_BUILDTIME_EXTABLE_SORT=y
++
++#
++# General setup
++#
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_CROSS_COMPILE=""
++# CONFIG_COMPILE_TEST is not set
++CONFIG_LOCALVERSION=""
++# CONFIG_LOCALVERSION_AUTO is not set
++CONFIG_HAVE_KERNEL_GZIP=y
++CONFIG_HAVE_KERNEL_LZMA=y
++CONFIG_HAVE_KERNEL_XZ=y
++CONFIG_HAVE_KERNEL_LZO=y
++CONFIG_HAVE_KERNEL_LZ4=y
++CONFIG_KERNEL_GZIP=y
++# CONFIG_KERNEL_LZMA is not set
++# CONFIG_KERNEL_XZ is not set
++# CONFIG_KERNEL_LZO is not set
++# CONFIG_KERNEL_LZ4 is not set
++CONFIG_DEFAULT_HOSTNAME="(none)"
++CONFIG_SWAP=y
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++# CONFIG_POSIX_MQUEUE is not set
++CONFIG_CROSS_MEMORY_ATTACH=y
++# CONFIG_FHANDLE is not set
++CONFIG_USELIB=y
++# CONFIG_AUDIT is not set
++CONFIG_HAVE_ARCH_AUDITSYSCALL=y
++
++#
++# IRQ subsystem
++#
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_GENERIC_IRQ_SHOW=y
++CONFIG_HARDIRQS_SW_RESEND=y
++CONFIG_IRQ_DOMAIN=y
++CONFIG_HANDLE_DOMAIN_IRQ=y
++CONFIG_IRQ_FORCED_THREADING=y
++CONFIG_SPARSE_IRQ=y
++CONFIG_GENERIC_CLOCKEVENTS=y
++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
++CONFIG_ARCH_HAS_TICK_BROADCAST=y
++CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
++
++#
++# Timers subsystem
++#
++CONFIG_TICK_ONESHOT=y
++CONFIG_NO_HZ_COMMON=y
++# CONFIG_HZ_PERIODIC is not set
++CONFIG_NO_HZ_IDLE=y
++# CONFIG_NO_HZ_FULL is not set
++CONFIG_NO_HZ=y
++# CONFIG_HIGH_RES_TIMERS is not set
++
++#
++# CPU/Task time and stats accounting
++#
++CONFIG_TICK_CPU_ACCOUNTING=y
++# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set
++# CONFIG_IRQ_TIME_ACCOUNTING is not set
++# CONFIG_BSD_PROCESS_ACCT is not set
++# CONFIG_TASKSTATS is not set
++
++#
++# RCU Subsystem
++#
++CONFIG_TREE_RCU=y
++# CONFIG_PREEMPT_RCU is not set
++# CONFIG_TASKS_RCU is not set
++CONFIG_RCU_STALL_COMMON=y
++# CONFIG_RCU_USER_QS is not set
++CONFIG_RCU_FANOUT=32
++CONFIG_RCU_FANOUT_LEAF=16
++# CONFIG_RCU_FANOUT_EXACT is not set
++# CONFIG_RCU_FAST_NO_HZ is not set
++# CONFIG_TREE_RCU_TRACE is not set
++# CONFIG_RCU_NOCB_CPU is not set
++# CONFIG_BUILD_BIN2C is not set
++# CONFIG_IKCONFIG is not set
++CONFIG_LOG_BUF_SHIFT=17
++CONFIG_LOG_CPU_MAX_BUF_SHIFT=12
++CONFIG_GENERIC_SCHED_CLOCK=y
++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_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_USER_NS is not set
++CONFIG_PID_NS=y
++CONFIG_NET_NS=y
++# 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=y
++CONFIG_RD_LZMA=y
++CONFIG_RD_XZ=y
++CONFIG_RD_LZO=y
++CONFIG_RD_LZ4=y
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++CONFIG_HAVE_UID16=y
++CONFIG_BPF=y
++# CONFIG_EXPERT is not set
++CONFIG_UID16=y
++# CONFIG_SGETMASK_SYSCALL is not set
++CONFIG_SYSFS_SYSCALL=y
++# CONFIG_SYSCTL_SYSCALL is not set
++CONFIG_KALLSYMS=y
++# CONFIG_KALLSYMS_ALL is not set
++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_BPF_SYSCALL is not set
++CONFIG_SHMEM=y
++CONFIG_AIO=y
++CONFIG_ADVISE_SYSCALLS=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_SLUB_CPU_PARTIAL=y
++# CONFIG_PROFILING is not set
++CONFIG_HAVE_OPROFILE=y
++# CONFIG_KPROBES is not set
++# CONFIG_JUMP_LABEL is not set
++# CONFIG_UPROBES is not set
++# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
++CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
++CONFIG_ARCH_USE_BUILTIN_BSWAP=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_GENERIC_SMP_IDLE_THREAD=y
++CONFIG_GENERIC_IDLE_POLL_SETUP=y
++CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
++CONFIG_HAVE_CLK=y
++CONFIG_HAVE_DMA_API_DEBUG=y
++CONFIG_HAVE_PERF_REGS=y
++CONFIG_HAVE_PERF_USER_STACK_DUMP=y
++CONFIG_HAVE_ARCH_JUMP_LABEL=y
++CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
++CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
++CONFIG_HAVE_CC_STACKPROTECTOR=y
++# CONFIG_CC_STACKPROTECTOR is not set
++CONFIG_CC_STACKPROTECTOR_NONE=y
++# CONFIG_CC_STACKPROTECTOR_REGULAR is not set
++# CONFIG_CC_STACKPROTECTOR_STRONG is not set
++CONFIG_HAVE_CONTEXT_TRACKING=y
++CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
++CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
++CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
++CONFIG_MODULES_USE_ELF_REL=y
++CONFIG_CLONE_BACKWARDS=y
++CONFIG_OLD_SIGSUSPEND3=y
++CONFIG_OLD_SIGACTION=y
++
++#
++# GCOV-based kernel profiling
++#
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_SLABINFO=y
++CONFIG_RT_MUTEXES=y
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++# CONFIG_MODULE_FORCE_LOAD is not set
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++# CONFIG_MODULE_SIG is not set
++# CONFIG_MODULE_COMPRESS is not set
++CONFIG_STOP_MACHINE=y
++CONFIG_BLOCK=y
++CONFIG_LBDAF=y
++CONFIG_BLK_DEV_BSG=y
++# CONFIG_BLK_DEV_BSGLIB is not set
++# CONFIG_BLK_DEV_INTEGRITY is not set
++CONFIG_BLK_CMDLINE_PARSER=y
++
++#
++# Partition Types
++#
++CONFIG_PARTITION_ADVANCED=y
++# CONFIG_ACORN_PARTITION is not set
++# CONFIG_AIX_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=y
++# CONFIG_SYSV68_PARTITION is not set
++CONFIG_CMDLINE_PARTITION=y
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++CONFIG_DEFAULT_DEADLINE=y
++# CONFIG_DEFAULT_CFQ is not set
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="deadline"
++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_ARCH_SUPPORTS_ATOMIC_RMW=y
++CONFIG_MUTEX_SPIN_ON_OWNER=y
++CONFIG_RWSEM_SPIN_ON_OWNER=y
++CONFIG_FREEZER=y
++
++#
++# System Type
++#
++CONFIG_MMU=y
++CONFIG_ARCH_MULTIPLATFORM=y
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_AT91 is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_GEMINI is not set
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_IOP13XX is not set
++# CONFIG_ARCH_IOP32X is not set
++# CONFIG_ARCH_IOP33X is not set
++# CONFIG_ARCH_IXP4XX is not set
++# CONFIG_ARCH_DOVE is not set
++# CONFIG_ARCH_MV78XX0 is not set
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_MMP is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_W90X900 is not set
++# CONFIG_ARCH_LPC32XX is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_MSM is not set
++# CONFIG_ARCH_SHMOBILE_LEGACY 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_DAVINCI is not set
++# CONFIG_ARCH_OMAP1 is not set
++
++#
++# Multiple platform selection
++#
++
++#
++# CPU Core family selection
++#
++# CONFIG_ARCH_MULTI_V6 is not set
++CONFIG_ARCH_MULTI_V7=y
++CONFIG_ARCH_MULTI_V6_V7=y
++# CONFIG_ARCH_MULTI_CPU_AUTO is not set
++# CONFIG_ARCH_VIRT is not set
++# CONFIG_ARCH_MVEBU is not set
++# CONFIG_ARCH_BCM is not set
++# CONFIG_ARCH_BERLIN is not set
++# CONFIG_ARCH_HIGHBANK is not set
++CONFIG_ARCH_HISI=y
++
++#
++# Hisilicon platform type
++#
++# CONFIG_ARCH_HI3xxx is not set
++# CONFIG_ARCH_HIP04 is not set
++# CONFIG_ARCH_HIX5HD2 is not set
++CONFIG_ARCH_HI3519=y
++# CONFIG_ARCH_HI3519V101 is not set
++# CONFIG_ARCH_HI3516AV200 is not set
++# CONFIG_ARCH_HI3559 is not set
++# CONFIG_ARCH_HI3556 is not set
++CONFIG_PMC=y
++# CONFIG_ARCH_HI3536C is not set
++# CONFIG_ARCH_KEYSTONE is not set
++# CONFIG_ARCH_MESON is not set
++# CONFIG_ARCH_MXC is not set
++# CONFIG_ARCH_MEDIATEK is not set
++
++#
++# TI OMAP/AM/DM/DRA Family
++#
++# CONFIG_ARCH_OMAP3 is not set
++# CONFIG_ARCH_OMAP4 is not set
++# CONFIG_SOC_OMAP5 is not set
++# CONFIG_SOC_AM33XX is not set
++# CONFIG_SOC_AM43XX is not set
++# CONFIG_SOC_DRA7XX is not set
++# CONFIG_ARCH_QCOM is not set
++# CONFIG_ARCH_ROCKCHIP is not set
++# CONFIG_ARCH_SOCFPGA is not set
++# CONFIG_PLAT_SPEAR is not set
++# CONFIG_ARCH_STI is not set
++# CONFIG_ARCH_S5PV210 is not set
++# CONFIG_ARCH_EXYNOS is not set
++# CONFIG_ARCH_SHMOBILE_MULTI is not set
++# CONFIG_ARCH_SUNXI is not set
++# CONFIG_ARCH_SIRF is not set
++# CONFIG_ARCH_TEGRA is not set
++# CONFIG_ARCH_U8500 is not set
++# CONFIG_ARCH_VEXPRESS is not set
++# CONFIG_ARCH_WM8850 is not set
++# CONFIG_ARCH_ZYNQ is not set
++CONFIG_ARM_TIMER_SP804=y
++
++#
++# Processor Type
++#
++CONFIG_CPU_V7=y
++CONFIG_CPU_32v6K=y
++CONFIG_CPU_32v7=y
++CONFIG_CPU_ABRT_EV7=y
++CONFIG_CPU_PABRT_V7=y
++CONFIG_CPU_CACHE_V7=y
++CONFIG_CPU_CACHE_VIPT=y
++CONFIG_CPU_COPY_V6=y
++CONFIG_CPU_TLB_V7=y
++CONFIG_CPU_HAS_ASID=y
++CONFIG_CPU_CP15=y
++CONFIG_CPU_CP15_MMU=y
++
++#
++# Processor Features
++#
++# CONFIG_ARM_LPAE is not set
++# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
++CONFIG_ARM_THUMB=y
++# CONFIG_ARM_THUMBEE is not set
++CONFIG_ARM_VIRT_EXT=y
++CONFIG_SWP_EMULATE=y
++# CONFIG_CPU_ICACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_DISABLE is not set
++# CONFIG_CPU_BPREDICT_DISABLE is not set
++CONFIG_KUSER_HELPERS=y
++CONFIG_MIGHT_HAVE_CACHE_L2X0=y
++# CONFIG_CACHE_L2X0 is not set
++CONFIG_ARM_L1_CACHE_SHIFT_6=y
++CONFIG_ARM_L1_CACHE_SHIFT=6
++CONFIG_ARM_DMA_MEM_BUFFERABLE=y
++CONFIG_MULTI_IRQ_HANDLER=y
++# CONFIG_ARM_ERRATA_430973 is not set
++# CONFIG_ARM_ERRATA_643719 is not set
++# CONFIG_ARM_ERRATA_720789 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_ARM_ERRATA_775420 is not set
++# CONFIG_ARM_ERRATA_798181 is not set
++# CONFIG_ARM_ERRATA_773022 is not set
++
++#
++# Bus support
++#
++CONFIG_ARM_AMBA=y
++# CONFIG_PCI is not set
++# 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=y
++# CONFIG_SCHED_SMT is not set
++CONFIG_DISABLE_CPU_SCHED_DOMAIN_BALANCE=y
++CONFIG_SCHED_HMP=y
++# CONFIG_SCHED_HMP_PRIO_FILTER is not set
++CONFIG_HMP_FAST_CPU_MASK=""
++CONFIG_HMP_SLOW_CPU_MASK=""
++CONFIG_HMP_VARIABLE_SCALE=y
++# CONFIG_HMP_FREQUENCY_INVARIANT_SCALE is not set
++# CONFIG_SCHED_HMP_LITTLE_PACKING is not set
++CONFIG_HAVE_ARM_ARCH_TIMER=y
++# CONFIG_MCPM is not set
++# CONFIG_BIG_LITTLE is not set
++CONFIG_VMSPLIT_3G=y
++# CONFIG_VMSPLIT_2G is not set
++# CONFIG_VMSPLIT_1G is not set
++CONFIG_PAGE_OFFSET=0xC0000000
++CONFIG_NR_CPUS=4
++CONFIG_HOTPLUG_CPU=y
++# CONFIG_ARM_PSCI is not set
++CONFIG_ARCH_NR_GPIO=0
++CONFIG_PREEMPT_NONE=y
++# CONFIG_PREEMPT_VOLUNTARY is not set
++# CONFIG_PREEMPT is not set
++CONFIG_HZ_FIXED=0
++CONFIG_HZ_100=y
++# CONFIG_HZ_200 is not set
++# CONFIG_HZ_250 is not set
++# CONFIG_HZ_300 is not set
++# CONFIG_HZ_500 is not set
++# CONFIG_HZ_1000 is not set
++CONFIG_HZ=100
++# CONFIG_SCHED_HRTICK is not set
++# CONFIG_THUMB2_KERNEL is not set
++CONFIG_AEABI=y
++# CONFIG_OABI_COMPAT is not set
++# 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_ARCH_WANT_GENERAL_HUGETLB=y
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_HAVE_MEMBLOCK=y
++CONFIG_NO_BOOTMEM=y
++CONFIG_MEMORY_ISOLATION=y
++# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=4
++CONFIG_COMPACTION=y
++CONFIG_MIGRATION=y
++# CONFIG_PHYS_ADDR_T_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_BOUNCE=y
++# CONFIG_KSM is not set
++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
++# CONFIG_CLEANCACHE is not set
++# CONFIG_FRONTSWAP is not set
++CONFIG_CMA=y
++# CONFIG_CMA_DEBUG is not set
++CONFIG_CMA_AREAS=7
++# CONFIG_ZPOOL is not set
++# CONFIG_ZBUD is not set
++# CONFIG_ZSMALLOC 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_SWIOTLB=y
++CONFIG_IOMMU_HELPER=y
++# CONFIG_XEN is not set
++# CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART is not set
++
++#
++# Boot options
++#
++CONFIG_USE_OF=y
++CONFIG_ATAGS=y
++# CONFIG_DEPRECATED_PARAM_STRUCT is not set
++# CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE is not set
++CONFIG_ZBOOT_ROM_TEXT=0
++CONFIG_ZBOOT_ROM_BSS=0
++CONFIG_ARM_APPENDED_DTB=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_KEXEC is not set
++# CONFIG_CRASH_DUMP is not set
++CONFIG_AUTO_ZRELADDR=y
++
++#
++# CPU Power Management
++#
++
++#
++# CPU Frequency scaling
++#
++CONFIG_CPU_FREQ=y
++CONFIG_CPU_FREQ_GOV_COMMON=y
++CONFIG_CPU_FREQ_STAT=y
++# CONFIG_CPU_FREQ_STAT_DETAILS is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
++CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
++# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE is not set
++CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
++CONFIG_CPU_FREQ_GOV_POWERSAVE=y
++CONFIG_CPU_FREQ_GOV_USERSPACE=y
++CONFIG_CPU_FREQ_GOV_ONDEMAND=y
++CONFIG_CPU_FREQ_GOV_INTERACTIVE=y
++CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
++CONFIG_CPUFREQ_DT=y
++
++#
++# ARM CPU frequency scaling drivers
++#
++# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set
++
++#
++# CPU Idle
++#
++# CONFIG_CPU_IDLE is not set
++# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++CONFIG_VFP=y
++CONFIG_VFPv3=y
++CONFIG_NEON=y
++CONFIG_KERNEL_MODE_NEON=y
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
++CONFIG_BINFMT_SCRIPT=y
++# CONFIG_HAVE_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
++CONFIG_COREDUMP=y
++
++#
++# Power management options
++#
++CONFIG_SUSPEND=y
++CONFIG_SUSPEND_FREEZER=y
++CONFIG_WAKELOCK=y
++CONFIG_HIBERNATE_CALLBACKS=y
++CONFIG_HISI_SNAPSHOT_BOOT=y
++# CONFIG_DEFAULT_MTD is not set
++CONFIG_DEFAULT_DDR=y
++CONFIG_SNAPSHOT_BUF_START=0x8a000000
++CONFIG_SNAPSHOT_BUF_SIZE=0x4000000
++CONFIG_HIBERNATION=y
++CONFIG_GZIP_COMPRESS=y
++CONFIG_PM_STD_PARTITION=""
++CONFIG_PM_SLEEP=y
++CONFIG_PM_SLEEP_SMP=y
++# CONFIG_PM_AUTOSLEEP is not set
++# CONFIG_PM_WAKELOCKS is not set
++# CONFIG_PM_RUNTIME is not set
++CONFIG_PM=y
++# CONFIG_PM_DEBUG is not set
++# CONFIG_APM_EMULATION is not set
++CONFIG_PM_OPP=y
++CONFIG_PM_CLK=y
++# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set
++CONFIG_CPU_PM=y
++# CONFIG_SUSPEND_TIME is not set
++CONFIG_ARCH_SUSPEND_POSSIBLE=y
++CONFIG_ARM_CPU_SUSPEND=y
++CONFIG_ARCH_HIBERNATION_POSSIBLE=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_NET_IP_TUNNEL=m
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_NET_IPVTI is not set
++# CONFIG_NET_UDP_TUNNEL is not set
++# CONFIG_NET_FOU is not set
++# CONFIG_GENEVE 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=y
++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=y
++# 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_VTI 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_ANDROID_PARANOID_NETWORK is not set
++CONFIG_NET_ACTIVITY_STATS=y
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NET_PTP_CLASSIFY 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_NF_TABLES is not set
++# CONFIG_NETFILTER_XTABLES is not set
++# CONFIG_IP_SET is not set
++# CONFIG_IP_VS is not set
++
++#
++# IP: Netfilter Configuration
++#
++# CONFIG_NF_DEFRAG_IPV4 is not set
++# CONFIG_NF_LOG_ARP is not set
++# CONFIG_NF_LOG_IPV4 is not set
++# CONFIG_NF_REJECT_IPV4 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_NF_REJECT_IPV6 is not set
++# CONFIG_NF_LOG_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_HAVE_NET_DSA=y
++# 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_PHONET is not set
++# CONFIG_6LOWPAN 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_VSOCKETS is not set
++# CONFIG_NETLINK_MMAP is not set
++# CONFIG_NETLINK_DIAG is not set
++# CONFIG_NET_MPLS_GSO is not set
++# CONFIG_HSR is not set
++CONFIG_RPS=y
++CONFIG_RFS_ACCEL=y
++CONFIG_XPS=y
++# CONFIG_CGROUP_NET_PRIO is not set
++# CONFIG_CGROUP_NET_CLASSID is not set
++CONFIG_NET_RX_BUSY_POLL=y
++CONFIG_BQL=y
++# CONFIG_BPF_JIT is not set
++CONFIG_NET_FLOW_LIMIT=y
++
++#
++# 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 is not set
++CONFIG_DEVTMPFS=y
++CONFIG_DEVTMPFS_MOUNT=y
++CONFIG_STANDALONE=y
++# CONFIG_PREVENT_FIRMWARE_BUILD is not set
++CONFIG_FW_LOADER=y
++# CONFIG_FIRMWARE_IN_KERNEL is not set
++CONFIG_EXTRA_FIRMWARE=""
++# CONFIG_FW_LOADER_USER_HELPER_FALLBACK is not set
++CONFIG_ALLOW_DEV_COREDUMP=y
++# 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_HAVE_CPU_AUTOPROBE is not set
++CONFIG_REGMAP=y
++CONFIG_REGMAP_MMIO=y
++# CONFIG_DMA_SHARED_BUFFER is not set
++CONFIG_DMA_CMA=y
++
++#
++# Default contiguous memory area size:
++#
++CONFIG_CMA_SIZE_MBYTES=16
++CONFIG_CMA_SIZE_SEL_MBYTES=y
++# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set
++# CONFIG_CMA_SIZE_SEL_MIN is not set
++# CONFIG_CMA_SIZE_SEL_MAX is not set
++CONFIG_CMA_ALIGNMENT=8
++
++#
++# Bus devices
++#
++# CONFIG_BRCMSTB_GISB_ARB is not set
++CONFIG_ARM_CCI=y
++# CONFIG_VEXPRESS_CONFIG 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=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_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
++CONFIG_HIFMC=y
++CONFIG_HIFMC_SPI_NAND=y
++# CONFIG_HIFMC_NAND is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++# CONFIG_MTD_CFI is not set
++# CONFIG_MTD_JEDECPROBE is not set
++CONFIG_MTD_MAP_BANK_WIDTH_1=y
++CONFIG_MTD_MAP_BANK_WIDTH_2=y
++CONFIG_MTD_MAP_BANK_WIDTH_4=y
++# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
++CONFIG_MTD_CFI_I1=y
++CONFIG_MTD_CFI_I2=y
++# CONFIG_MTD_CFI_I4 is not set
++# CONFIG_MTD_CFI_I8 is not set
++# CONFIG_MTD_RAM is not set
++# CONFIG_MTD_ROM is not set
++# CONFIG_MTD_ABSENT is not set
++
++#
++# Mapping drivers for chip access
++#
++# CONFIG_MTD_COMPLEX_MAPPINGS is not set
++# CONFIG_MTD_PLATRAM is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_DATAFLASH is not set
++# CONFIG_MTD_M25P80 is not set
++# CONFIG_MTD_SST25L is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_PHRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++# CONFIG_MTD_BLOCK2MTD is not set
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOCG3 is not set
++CONFIG_MTD_NAND_IDS=y
++CONFIG_MTD_NAND_ECC=y
++# CONFIG_MTD_NAND_ECC_SMC is not set
++CONFIG_MTD_NAND=y
++# CONFIG_MTD_NAND_ECC_BCH is not set
++# CONFIG_MTD_SM_COMMON is not set
++# CONFIG_MTD_NAND_DENALI is not set
++# CONFIG_MTD_NAND_OMAP_BCH_BUILD is not set
++# CONFIG_MTD_NAND_DISKONCHIP is not set
++# CONFIG_MTD_NAND_DOCG4 is not set
++# CONFIG_MTD_NAND_NANDSIM is not set
++# CONFIG_MTD_NAND_PLATFORM is not set
++# CONFIG_HISI_NAND_FS_MAY_NO_YAFFS2 is not set
++# CONFIG_HISI_NAND_ECC_STATUS_REPORT is not set
++# CONFIG_HIFMC100_NAND is not set
++CONFIG_HIFMC100_SPI_NAND=y
++CONFIG_SPI_NAND_MAX_CHIP_NUM=1
++# CONFIG_HIFMC100_HARDWARE_PAGESIZE_ECC is not set
++CONFIG_HIFMC100_AUTO_PAGESIZE_ECC=y
++# CONFIG_HIFMC100_PAGESIZE_AUTO_ECC_NONE is not set
++# CONFIG_MTD_ONENAND is not set
++
++#
++# LPDDR & LPDDR2 PCM memory drivers
++#
++# CONFIG_MTD_LPDDR is not set
++# CONFIG_MTD_LPDDR2_NVM is not set
++CONFIG_MTD_SPI_NOR=y
++# CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set
++CONFIG_SPI_HISI_SFC=y
++CONFIG_CLOSE_SPI_8PIN_4IO=y
++CONFIG_HISI_SPI_BLOCK_PROTECT=y
++# CONFIG_MTD_UBI is not set
++CONFIG_DTC=y
++CONFIG_OF=y
++
++#
++# Device Tree and Open Firmware support
++#
++# 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_NET=y
++CONFIG_OF_MDIO=y
++CONFIG_OF_MTD=y
++CONFIG_OF_RESERVED_MEM=y
++CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
++# CONFIG_PARPORT is not set
++CONFIG_BLK_DEV=y
++# CONFIG_BLK_DEV_NULL_BLK is not set
++# CONFIG_BLK_DEV_COW_COMMON is not set
++# CONFIG_BLK_DEV_LOOP 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=65536
++# CONFIG_BLK_DEV_XIP is not set
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH 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_DUMMY_IRQ 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_UID_STAT is not set
++# CONFIG_BMP085_I2C is not set
++# CONFIG_BMP085_SPI is not set
++# CONFIG_USB_SWITCH_FSA9480 is not set
++# CONFIG_LATTICE_ECP3_CONFIG is not set
++# CONFIG_SRAM is not set
++# CONFIG_C2PORT is not set
++
++#
++# EEPROM support
++#
++# CONFIG_EEPROM_AT24 is not set
++# CONFIG_EEPROM_AT25 is not set
++# CONFIG_EEPROM_LEGACY is not set
++# CONFIG_EEPROM_MAX6875 is not set
++# CONFIG_EEPROM_93CX6 is not set
++# CONFIG_EEPROM_93XX46 is not set
++
++#
++# Texas Instruments shared transport line discipline
++#
++# 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
++
++#
++# Intel MIC Bus Driver
++#
++
++#
++# Intel MIC Host Driver
++#
++
++#
++# Intel MIC Card Driver
++#
++# CONFIG_ECHO is not set
++# CONFIG_CXL_BASE is not set
++
++#
++# hisi 'himm/himd.l/himc'support
++#
++CONFIG_HISI_REG=y
++
++#
++# SCSI device support
++#
++CONFIG_SCSI_MOD=y
++# CONFIG_RAID_ATTRS is not set
++CONFIG_SCSI=y
++CONFIG_SCSI_DMA=y
++# CONFIG_SCSI_NETLINK is not set
++# CONFIG_SCSI_MQ_DEFAULT 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_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 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_NET_CORE=y
++# CONFIG_BONDING is not set
++# CONFIG_DUMMY is not set
++# CONFIG_EQUALIZER is not set
++# CONFIG_NET_TEAM is not set
++# CONFIG_MACVLAN is not set
++# CONFIG_VXLAN is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_TUN is not set
++# CONFIG_VETH is not set
++# CONFIG_NLMON is not set
++
++#
++# 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_NET_DSA_MV88E6171 is not set
++# CONFIG_NET_DSA_BCM_SF2 is not set
++CONFIG_ETHERNET=y
++# CONFIG_ALTERA_TSE is not set
++# CONFIG_NET_XGENE is not set
++# CONFIG_NET_VENDOR_ARC is not set
++# CONFIG_NET_CADENCE is not set
++# CONFIG_NET_VENDOR_BROADCOM is not set
++# CONFIG_NET_VENDOR_CIRRUS is not set
++# CONFIG_DM9000 is not set
++# CONFIG_DNET is not set
++# CONFIG_NET_VENDOR_FARADAY is not set
++CONFIG_NET_VENDOR_HISILICON=y
++# CONFIG_HIX5HD2_GMAC is not set
++# CONFIG_HISI_FEMAC is not set
++CONFIG_HIETH_GMAC=y
++CONFIG_HIGMAC_DESC_4WORD=y
++CONFIG_HIGMAC_RXCSUM=y
++CONFIG_RX_FLOW_CTRL_SUPPORT=y
++CONFIG_TX_FLOW_CTRL_SUPPORT=y
++CONFIG_TX_FLOW_CTRL_PAUSE_TIME=0xFFFF
++CONFIG_TX_FLOW_CTRL_PAUSE_INTERVAL=0xFFFF
++CONFIG_TX_FLOW_CTRL_ACTIVE_THRESHOLD=16
++CONFIG_TX_FLOW_CTRL_DEACTIVE_THRESHOLD=32
++# CONFIG_HIETH_SWITCH_FABRIC is not set
++# CONFIG_NET_VENDOR_INTEL is not set
++# CONFIG_NET_VENDOR_MARVELL is not set
++# CONFIG_NET_VENDOR_MICREL is not set
++# CONFIG_NET_VENDOR_MICROCHIP is not set
++# CONFIG_NET_VENDOR_NATSEMI is not set
++# CONFIG_ETHOC is not set
++# CONFIG_NET_VENDOR_QUALCOMM is not set
++# CONFIG_NET_VENDOR_SAMSUNG is not set
++# CONFIG_NET_VENDOR_SEEQ is not set
++# CONFIG_NET_VENDOR_SMSC is not set
++# CONFIG_NET_VENDOR_STMICRO is not set
++# CONFIG_NET_VENDOR_VIA is not set
++# CONFIG_NET_VENDOR_WIZNET is not set
++CONFIG_PHYLIB=y
++
++#
++# MII PHY device drivers
++#
++# CONFIG_AT803X_PHY is not set
++# CONFIG_AMD_PHY is not set
++# CONFIG_AMD_XGBE_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 is not set
++# CONFIG_BROADCOM_PHY is not set
++# CONFIG_BCM7XXX_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_MMIOREG is not set
++# CONFIG_MDIO_BCM_UNIMAC is not set
++# CONFIG_MDIO_HISI_FEMAC is not set
++CONFIG_MDIO_HISI_GEMAC=y
++# CONFIG_MICREL_KS8995MA is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++CONFIG_USB_NET_DRIVERS=y
++# 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_RTL8152 is not set
++# CONFIG_USB_USBNET is not set
++# CONFIG_USB_IPHETH is not set
++# CONFIG_WLAN is not set
++
++#
++# Enable WiMAX (Networking options) to see the WiMAX drivers
++#
++# CONFIG_WAN is not set
++# CONFIG_ISDN is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
++# CONFIG_INPUT_POLLDEV is not set
++# CONFIG_INPUT_SPARSEKMAP is not set
++# CONFIG_INPUT_MATRIXKMAP is not set
++
++#
++# Userland interfaces
++#
++CONFIG_INPUT_MOUSEDEV=y
++CONFIG_INPUT_MOUSEDEV_PSAUX=y
++CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
++CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
++# CONFIG_INPUT_JOYDEV is not set
++CONFIG_INPUT_EVDEV=y
++# CONFIG_INPUT_EVBUG is not set
++# CONFIG_INPUT_KEYRESET is not set
++# CONFIG_INPUT_KEYCOMBO 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_TCA6416 is not set
++# CONFIG_KEYBOARD_TCA8418 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 is not set
++# CONFIG_KEYBOARD_CAP1106 is not set
++CONFIG_INPUT_MOUSE=y
++CONFIG_MOUSE_PS2=y
++CONFIG_MOUSE_PS2_ALPS=y
++CONFIG_MOUSE_PS2_LOGIPS2PP=y
++CONFIG_MOUSE_PS2_SYNAPTICS=y
++CONFIG_MOUSE_PS2_CYPRESS=y
++CONFIG_MOUSE_PS2_TRACKPOINT=y
++# CONFIG_MOUSE_PS2_ELANTECH is not set
++# CONFIG_MOUSE_PS2_SENTELIC is not set
++# CONFIG_MOUSE_PS2_TOUCHKIT is not set
++# CONFIG_MOUSE_SERIAL is not set
++# CONFIG_MOUSE_APPLETOUCH is not set
++# CONFIG_MOUSE_BCM5974 is not set
++# CONFIG_MOUSE_CYAPA is not set
++# CONFIG_MOUSE_VSXXXAA is not set
++# CONFIG_MOUSE_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 is not set
++# CONFIG_INPUT_MISC is not set
++
++#
++# Hardware I/O ports
++#
++CONFIG_SERIO=y
++CONFIG_SERIO_SERPORT=y
++# CONFIG_SERIO_AMBAKMI is not set
++CONFIG_SERIO_LIBPS2=y
++# CONFIG_SERIO_RAW is not set
++# CONFIG_SERIO_ALTERA_PS2 is not set
++# CONFIG_SERIO_PS2MULT is not set
++# CONFIG_SERIO_ARC_PS2 is not set
++# CONFIG_SERIO_APBPS2 is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++CONFIG_TTY=y
++CONFIG_VT=y
++CONFIG_CONSOLE_TRANSLATIONS=y
++CONFIG_VT_CONSOLE=y
++CONFIG_VT_CONSOLE_SLEEP=y
++CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
++CONFIG_UNIX98_PTYS=y
++# CONFIG_DEVPTS_MULTIPLE_INSTANCES 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_DEVMEM=y
++CONFIG_DEVKMEM=y
++
++#
++# Serial drivers
++#
++CONFIG_SERIAL_EARLYCON=y
++# CONFIG_SERIAL_8250 is not set
++
++#
++# Non-8250 serial port support
++#
++# CONFIG_SERIAL_AMBA_PL010 is not set
++CONFIG_SERIAL_AMBA_PL011=y
++CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
++# CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST is not set
++# 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_SC16IS7XX is not set
++# CONFIG_SERIAL_ALTERA_JTAGUART is not set
++# CONFIG_SERIAL_ALTERA_UART is not set
++# CONFIG_SERIAL_XILINX_PS_UART is not set
++# CONFIG_SERIAL_ARC is not set
++# CONFIG_SERIAL_FSL_LPUART is not set
++# CONFIG_SERIAL_ST_ASC is not set
++# CONFIG_HVC_DCC is not set
++# CONFIG_IPMI_HANDLER is not set
++# CONFIG_HW_RANDOM is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++# CONFIG_DCC_TTY is not set
++# CONFIG_XILLYBUS is not set
++
++#
++# I2C support
++#
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++CONFIG_I2C_COMPAT=y
++CONFIG_I2C_CHARDEV=y
++CONFIG_I2C_MUX=y
++
++#
++# Multiplexer I2C Chip support
++#
++# CONFIG_I2C_MUX_PCA9541 is not set
++CONFIG_I2C_HELPER_AUTO=y
++
++#
++# I2C Hardware Bus support
++#
++
++#
++# I2C system bus drivers (mostly embedded / system-on-chip)
++#
++# CONFIG_I2C_DESIGNWARE_PLATFORM is not set
++# CONFIG_I2C_HIBVT is not set
++# CONFIG_I2C_HISI_V110 is not set
++# CONFIG_I2C_NOMADIK 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_RK3X 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_ROBOTFUZZ_OSIF is not set
++# CONFIG_I2C_TAOS_EVM is not set
++# CONFIG_I2C_TINY_USB is not set
++
++#
++# Other I2C/SMBus bus drivers
++#
++CONFIG_HI_I2C=y
++CONFIG_HI_I2C0_IO_BASE=0x12110000
++CONFIG_HI_I2C0_IO_SIZE=0x1000
++CONFIG_HI_I2C1_IO_BASE=0x12111000
++CONFIG_HI_I2C1_IO_SIZE=0x1000
++CONFIG_HI_I2C2_IO_BASE=0x12112000
++CONFIG_HI_I2C2_IO_SIZE=0x1000
++CONFIG_HI_I2C3_IO_BASE=0x12113000
++CONFIG_HI_I2C3_IO_SIZE=0x1000
++CONFIG_HI_I2C_RETRIES=0x1
++CONFIG_HI_I2C_TX_FIFO=0x8
++CONFIG_HI_I2C_RX_FIFO=0x8
++CONFIG_HI_I2C0_CLK_LIMIT=100000
++CONFIG_HI_I2C1_CLK_LIMIT=100000
++CONFIG_HI_I2C2_CLK_LIMIT=100000
++CONFIG_HI_I2C3_CLK_LIMIT=100000
++# 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_CADENCE is not set
++# CONFIG_SPI_FSL_SPI is not set
++CONFIG_SPI_PL022=y
++# CONFIG_SPI_PXA2XX_PCI is not set
++# CONFIG_SPI_ROCKCHIP 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=y
++# CONFIG_SPI_TLE62X0 is not set
++# CONFIG_SPMI is not set
++# CONFIG_HSI is not set
++
++#
++# PPS support
++#
++# CONFIG_PPS is not set
++
++#
++# PPS generators support
++#
++
++#
++# PTP clock support
++#
++# CONFIG_PTP_1588_CLOCK is not set
++
++#
++# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
++#
++CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
++CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
++# CONFIG_GPIOLIB is not set
++# CONFIG_W1 is not set
++CONFIG_POWER_SUPPLY=y
++# CONFIG_POWER_SUPPLY_DEBUG is not set
++# CONFIG_PDA_POWER is not set
++# CONFIG_TEST_POWER is not set
++# CONFIG_BATTERY_DS2780 is not set
++# CONFIG_BATTERY_DS2781 is not set
++# CONFIG_BATTERY_DS2782 is not set
++# CONFIG_BATTERY_SBS is not set
++# CONFIG_BATTERY_BQ27x00 is not set
++# CONFIG_BATTERY_MAX17040 is not set
++# CONFIG_BATTERY_MAX17042 is not set
++# CONFIG_CHARGER_MAX8903 is not set
++# CONFIG_CHARGER_LP8727 is not set
++# CONFIG_CHARGER_BQ2415X is not set
++# CONFIG_CHARGER_SMB347 is not set
++CONFIG_POWER_RESET=y
++# CONFIG_POWER_RESET_BRCMSTB is not set
++CONFIG_POWER_RESET_HISI=y
++# CONFIG_POWER_RESET_RESTART is not set
++# CONFIG_POWER_RESET_VERSATILE is not set
++# CONFIG_POWER_RESET_SYSCON is not set
++# CONFIG_POWER_AVS is not set
++# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
++# CONFIG_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=y
++# CONFIG_MFD_AS3711 is not set
++# CONFIG_MFD_AS3722 is not set
++# CONFIG_PMIC_ADP5520 is not set
++# CONFIG_MFD_BCM590XX is not set
++# CONFIG_MFD_AXP20X is not set
++# CONFIG_MFD_CROS_EC is not set
++# CONFIG_PMIC_DA903X is not set
++# CONFIG_MFD_DA9052_SPI is not set
++# CONFIG_MFD_DA9052_I2C is not set
++# CONFIG_MFD_DA9055 is not set
++# CONFIG_MFD_DA9063 is not set
++# CONFIG_MFD_MC13XXX_SPI is not set
++# CONFIG_MFD_MC13XXX_I2C is not set
++# CONFIG_MFD_HI6421_PMIC is not set
++CONFIG_MFD_HISI_FMC=y
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_INTEL_SOC_PMIC is not set
++# CONFIG_MFD_KEMPLD is not set
++# CONFIG_MFD_88PM800 is not set
++# CONFIG_MFD_88PM805 is not set
++# CONFIG_MFD_88PM860X is not set
++# CONFIG_MFD_MAX14577 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_MENF21BMC is not set
++# CONFIG_EZX_PCAP is not set
++# CONFIG_MFD_VIPERBOARD is not set
++# CONFIG_MFD_RETU is not set
++# CONFIG_MFD_PCF50633 is not set
++# CONFIG_MFD_PM8921_CORE is not set
++# CONFIG_MFD_RTSX_USB is not set
++# CONFIG_MFD_RC5T583 is not set
++# CONFIG_MFD_RK808 is not set
++# CONFIG_MFD_RN5T618 is not set
++# CONFIG_MFD_SEC_CORE is not set
++# CONFIG_MFD_SI476X_CORE is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_MFD_SMSC is not set
++# CONFIG_ABX500_CORE is not set
++# CONFIG_MFD_STMPE is not set
++CONFIG_MFD_SYSCON=y
++# CONFIG_MFD_TI_AM335X_TSCADC is not set
++# CONFIG_MFD_LP3943 is not set
++# CONFIG_MFD_LP8788 is not set
++# CONFIG_MFD_PALMAS is not set
++# CONFIG_TPS6105X is not set
++# CONFIG_TPS6507X is not set
++# CONFIG_MFD_TPS65090 is not set
++# CONFIG_MFD_TPS65217 is not set
++# CONFIG_MFD_TPS65218 is not set
++# CONFIG_MFD_TPS6586X is not set
++# CONFIG_MFD_TPS80031 is not set
++# CONFIG_TWL4030_CORE is not set
++# CONFIG_TWL6040_CORE is not set
++# CONFIG_MFD_WL1273_CORE is not set
++# CONFIG_MFD_LM3533 is not set
++# CONFIG_MFD_TC3589X is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_MFD_T7L66XB is not set
++# CONFIG_MFD_TC6387XB is not set
++# CONFIG_MFD_TC6393XB is not set
++# CONFIG_MFD_ARIZONA_I2C is not set
++# CONFIG_MFD_ARIZONA_SPI is not set
++# CONFIG_MFD_WM8400 is not set
++# CONFIG_MFD_WM831X_I2C is not set
++# CONFIG_MFD_WM831X_SPI is not set
++# CONFIG_MFD_WM8350_I2C is not set
++# CONFIG_MFD_WM8994 is not set
++CONFIG_REGULATOR=y
++# CONFIG_REGULATOR_DEBUG is not set
++# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
++# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
++# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
++# CONFIG_REGULATOR_ACT8865 is not set
++# CONFIG_REGULATOR_AD5398 is not set
++# CONFIG_REGULATOR_ANATOP is not set
++# CONFIG_REGULATOR_DA9210 is not set
++# CONFIG_REGULATOR_DA9211 is not set
++# CONFIG_REGULATOR_FAN53555 is not set
++# CONFIG_REGULATOR_ISL9305 is not set
++# CONFIG_REGULATOR_ISL6271A is not set
++# CONFIG_REGULATOR_LP3971 is not set
++# CONFIG_REGULATOR_LP3972 is not set
++# CONFIG_REGULATOR_LP872X is not set
++# CONFIG_REGULATOR_LP8755 is not set
++# CONFIG_REGULATOR_LTC3589 is not set
++# CONFIG_REGULATOR_MAX1586 is not set
++# CONFIG_REGULATOR_MAX8649 is not set
++# CONFIG_REGULATOR_MAX8660 is not set
++# CONFIG_REGULATOR_MAX8952 is not set
++# CONFIG_REGULATOR_MAX8973 is not set
++# CONFIG_REGULATOR_PFUZE100 is not set
++# CONFIG_REGULATOR_TPS51632 is not set
++# CONFIG_REGULATOR_TPS62360 is not set
++# CONFIG_REGULATOR_TPS65023 is not set
++# CONFIG_REGULATOR_TPS6507X is not set
++# CONFIG_REGULATOR_TPS6524X is not set
++# CONFIG_MEDIA_SUPPORT is not set
++
++#
++# Graphics support
++#
++# CONFIG_IMX_IPUV3_CORE is not set
++
++#
++# Direct Rendering Manager
++#
++# CONFIG_DRM is not set
++
++#
++# Frame buffer Devices
++#
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++CONFIG_FB_CMDLINE=y
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++# CONFIG_FB_CFB_FILLRECT is not set
++# CONFIG_FB_CFB_COPYAREA is not set
++# CONFIG_FB_CFB_IMAGEBLIT is not set
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# 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_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_ARMCLCD is not set
++# CONFIG_FB_OPENCORES is not set
++# CONFIG_FB_S1D13XXX is not set
++# CONFIG_FB_SMSCUFX is not set
++# CONFIG_FB_UDL is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_BROADSHEET is not set
++# CONFIG_FB_AUO_K190X is not set
++# CONFIG_FB_SIMPLE is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++# CONFIG_VGASTATE is not set
++
++#
++# Console display driver support
++#
++CONFIG_DUMMY_CONSOLE=y
++# CONFIG_FRAMEBUFFER_CONSOLE is not set
++# CONFIG_LOGO is not set
++# CONFIG_SOUND is not set
++
++#
++# HID support
++#
++CONFIG_HID=y
++# CONFIG_HID_BATTERY_STRENGTH is not set
++# CONFIG_HIDRAW is not set
++# CONFIG_UHID is not set
++CONFIG_HID_GENERIC=y
++
++#
++# Special HID drivers
++#
++CONFIG_HID_A4TECH=y
++# CONFIG_HID_ACRUX is not set
++CONFIG_HID_APPLE=y
++# CONFIG_HID_APPLEIR is not set
++# CONFIG_HID_AUREAL is not set
++CONFIG_HID_BELKIN=y
++CONFIG_HID_CHERRY=y
++CONFIG_HID_CHICONY=y
++CONFIG_HID_CYPRESS=y
++# CONFIG_HID_DRAGONRISE is not set
++# CONFIG_HID_EMS_FF is not set
++# CONFIG_HID_ELECOM is not set
++# CONFIG_HID_ELO is not set
++CONFIG_HID_EZKEY=y
++# CONFIG_HID_HOLTEK is not set
++# CONFIG_HID_HUION 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_ICADE is not set
++# CONFIG_HID_TWINHAN is not set
++CONFIG_HID_KENSINGTON=y
++# CONFIG_HID_LCPOWER is not set
++# CONFIG_HID_LENOVO is not set
++CONFIG_HID_LOGITECH=y
++# CONFIG_HID_LOGITECH_HIDPP is not set
++# CONFIG_LOGITECH_FF is not set
++# CONFIG_LOGIRUMBLEPAD2_FF is not set
++# CONFIG_LOGIG940_FF is not set
++# CONFIG_LOGIWHEELS_FF is not set
++# CONFIG_HID_MAGICMOUSE is not set
++CONFIG_HID_MICROSOFT=y
++CONFIG_HID_MONTEREY=y
++# 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_PENMOUNT is not set
++# CONFIG_HID_PETALYNX is not set
++# CONFIG_HID_PICOLCD is not set
++# CONFIG_HID_PRIMAX is not set
++# CONFIG_HID_ROCCAT is not set
++# CONFIG_HID_SAITEK is not set
++# CONFIG_HID_SAMSUNG is not set
++# CONFIG_HID_SPEEDLINK is not set
++# CONFIG_HID_STEELSERIES is not set
++# CONFIG_HID_SUNPLUS is not set
++# CONFIG_HID_RMI 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_XINMO is not set
++# CONFIG_HID_ZEROPLUS is not set
++# CONFIG_HID_ZYDACRON is not set
++# CONFIG_HID_SENSOR_HUB is not set
++
++#
++# USB HID support
++#
++CONFIG_USB_HID=y
++# CONFIG_HID_PID is not set
++# CONFIG_USB_HIDDEV is not set
++
++#
++# I2C HID support
++#
++# CONFIG_I2C_HID is not set
++CONFIG_USB_OHCI_LITTLE_ENDIAN=y
++CONFIG_USB_SUPPORT=y
++CONFIG_USB_COMMON=y
++CONFIG_USB_ARCH_HAS_HCD=y
++CONFIG_USB=y
++# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
++
++#
++# Miscellaneous USB options
++#
++CONFIG_USB_DEFAULT_PERSIST=y
++# CONFIG_USB_DYNAMIC_MINORS is not set
++# CONFIG_USB_OTG_WHITELIST is not set
++# CONFIG_USB_OTG_FSM is not set
++# CONFIG_USB_MON is not set
++# CONFIG_USB_WUSB_CBAF is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_C67X00_HCD is not set
++CONFIG_USB_XHCI_HCD=y
++CONFIG_USB_XHCI_PLATFORM=y
++CONFIG_USB_XHCI_HISILICON=y
++CONFIG_USB_EHCI_HCD=y
++# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
++CONFIG_USB_EHCI_TT_NEWSCHED=y
++CONFIG_USB_EHCI_HCD_PLATFORM=y
++# 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_FUSBH200_HCD is not set
++# CONFIG_USB_FOTG210_HCD is not set
++# CONFIG_USB_MAX3421_HCD is not set
++CONFIG_USB_OHCI_HCD=y
++CONFIG_USB_OHCI_HCD_PLATFORM=y
++# CONFIG_USB_SL811_HCD is not set
++# CONFIG_USB_R8A66597_HCD is not set
++# CONFIG_USB_HCD_TEST_MODE is not set
++
++#
++# USB Device Class drivers
++#
++# CONFIG_USB_ACM is not set
++# CONFIG_USB_PRINTER is not set
++# CONFIG_USB_WDM is not set
++# CONFIG_USB_TMC is not set
++
++#
++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
++#
++
++#
++# also be needed; see USB_STORAGE Help for more info
++#
++CONFIG_USB_STORAGE=y
++# CONFIG_USB_STORAGE_DEBUG is not set
++# CONFIG_USB_STORAGE_REALTEK is not set
++# CONFIG_USB_STORAGE_DATAFAB is not set
++# CONFIG_USB_STORAGE_FREECOM is not set
++# CONFIG_USB_STORAGE_ISD200 is not set
++# CONFIG_USB_STORAGE_USBAT is not set
++# CONFIG_USB_STORAGE_SDDR09 is not set
++# CONFIG_USB_STORAGE_SDDR55 is not set
++# CONFIG_USB_STORAGE_JUMPSHOT is not set
++# CONFIG_USB_STORAGE_ALAUDA is not set
++# CONFIG_USB_STORAGE_ONETOUCH is not set
++# CONFIG_USB_STORAGE_KARMA is not set
++# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
++# CONFIG_USB_STORAGE_ENE_UB6250 is not set
++# CONFIG_USB_UAS is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++# CONFIG_USBIP_CORE is not set
++# CONFIG_USB_MUSB_HDRC is not set
++# CONFIG_USB_DWC3 is not set
++# CONFIG_USB_DWC2 is not set
++# CONFIG_USB_CHIPIDEA is not set
++
++#
++# USB port drivers
++#
++# CONFIG_USB_SERIAL is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
++# CONFIG_USB_SEVSEG is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
++# CONFIG_USB_APPLEDISPLAY is not set
++# CONFIG_USB_SISUSBVGA is not set
++# CONFIG_USB_LD is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
++# CONFIG_USB_IOWARRIOR is not set
++# CONFIG_USB_TEST is not set
++# CONFIG_USB_EHSET_TEST_FIXTURE is not set
++# CONFIG_USB_ISIGHTFW is not set
++# CONFIG_USB_YUREX is not set
++# CONFIG_USB_EZUSB_FX2 is not set
++# CONFIG_USB_HSIC_USB3503 is not set
++# CONFIG_USB_LINK_LAYER_TEST is not set
++
++#
++# USB Physical Layer drivers
++#
++# CONFIG_USB_PHY is not set
++# CONFIG_USB_OTG_WAKELOCK is not set
++# CONFIG_NOP_USB_XCEIV is not set
++# CONFIG_AM335X_PHY_USB is not set
++# CONFIG_USB_ISP1301 is not set
++# CONFIG_USB_ULPI is not set
++CONFIG_USB_GADGET=y
++# CONFIG_USB_GADGET_DEBUG is not set
++# CONFIG_USB_GADGET_DEBUG_FILES is not set
++CONFIG_USB_GADGET_VBUS_DRAW=2
++CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2
++
++#
++# USB Peripheral Controller
++#
++# CONFIG_USB_FUSB300 is not set
++# CONFIG_USB_FOTG210_UDC is not set
++# CONFIG_USB_GR_UDC is not set
++# CONFIG_USB_R8A66597 is not set
++# CONFIG_USB_PXA27X is not set
++# CONFIG_USB_MV_UDC is not set
++CONFIG_HIUSB_DEVICE2_0=y
++CONFIG_USB_HISI_UDC=m
++# CONFIG_USB_AUTO_SWITCH is not set
++# CONFIG_HIUSB_DEVICE3_0 is not set
++# CONFIG_USB_MV_U3D is not set
++# CONFIG_USB_M66592 is not set
++# CONFIG_USB_NET2272 is not set
++# CONFIG_USB_GADGET_XILINX is not set
++# CONFIG_USB_DUMMY_HCD is not set
++CONFIG_USB_LIBCOMPOSITE=m
++CONFIG_USB_F_ACM=m
++CONFIG_USB_U_SERIAL=m
++CONFIG_USB_U_ETHER=m
++CONFIG_USB_F_SERIAL=m
++CONFIG_USB_F_OBEX=m
++CONFIG_USB_F_ECM=m
++CONFIG_USB_F_SUBSET=m
++CONFIG_USB_F_RNDIS=m
++CONFIG_USB_F_MASS_STORAGE=m
++# CONFIG_USB_CONFIGFS is not set
++# CONFIG_USB_ZERO 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 is not set
++# CONFIG_USB_FUNCTIONFS is not set
++CONFIG_USB_MASS_STORAGE=m
++CONFIG_USB_G_SERIAL=m
++# CONFIG_USB_G_PRINTER is not set
++# CONFIG_USB_CDC_COMPOSITE is not set
++# CONFIG_USB_G_ACM_MS is not set
++# CONFIG_USB_G_MULTI is not set
++# CONFIG_USB_G_HID is not set
++# CONFIG_USB_G_DBGP is not set
++# CONFIG_UWB is not set
++CONFIG_MMC=y
++# CONFIG_MMC_DEBUG is not set
++# CONFIG_MMC_CLKGATE is not set
++CONFIG_MMC_EMBEDDED_SDIO=y
++# CONFIG_MMC_PARANOID_SD_INIT is not set
++
++#
++# MMC/SD/SDIO Card Drivers
++#
++CONFIG_MMC_BLOCK=y
++CONFIG_MMC_BLOCK_MINORS=8
++CONFIG_MMC_BLOCK_BOUNCE=y
++# CONFIG_MMC_BLOCK_DEFERRED_RESUME is not set
++# CONFIG_SDIO_UART is not set
++# CONFIG_MMC_TEST is not set
++
++#
++# MMC/SD/SDIO Host Controller Drivers
++#
++# CONFIG_MMC_ARMMMCI is not set
++# CONFIG_MMC_SDHCI is not set
++# CONFIG_MMC_DW is not set
++# CONFIG_MMC_VUB300 is not set
++# CONFIG_MMC_USHC is not set
++# CONFIG_MMC_USDHI6ROL0 is not set
++CONFIG_HIMCIV200=y
++CONFIG_SEND_AUTO_STOP=y
++CONFIG_DETECT_CARD_TIME=200
++# CONFIG_MEMSTICK is not set
++# CONFIG_NEW_LEDS is not set
++# CONFIG_SWITCH is not set
++# CONFIG_ACCESSIBILITY is not set
++# CONFIG_EDAC is not set
++CONFIG_RTC_LIB=y
++# CONFIG_RTC_CLASS is not set
++# CONFIG_DMADEVICES is not set
++# CONFIG_AUXDISPLAY is not set
++# CONFIG_UIO is not set
++# CONFIG_VIRT_DRIVERS is not set
++
++#
++# Virtio drivers
++#
++# CONFIG_VIRTIO_MMIO is not set
++
++#
++# Microsoft Hyper-V guest support
++#
++# CONFIG_STAGING is not set
++
++#
++# SOC (System On Chip) specific Drivers
++#
++# CONFIG_SOC_TI is not set
++CONFIG_CLKDEV_LOOKUP=y
++CONFIG_HAVE_CLK_PREPARE=y
++CONFIG_COMMON_CLK=y
++
++#
++# Common Clock Framework
++#
++# CONFIG_COMMON_CLK_SI5351 is not set
++# CONFIG_COMMON_CLK_SI570 is not set
++# CONFIG_COMMON_CLK_PXA is not set
++# CONFIG_COMMON_CLK_QCOM is not set
++
++#
++# Hardware Spinlock drivers
++#
++
++#
++# Clock Source drivers
++#
++CONFIG_CLKSRC_OF=y
++CONFIG_CLKSRC_MMIO=y
++CONFIG_ARM_ARCH_TIMER=y
++CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y
++# CONFIG_ATMEL_PIT is not set
++# CONFIG_SH_TIMER_CMT is not set
++# CONFIG_SH_TIMER_MTU2 is not set
++# CONFIG_SH_TIMER_TMU is not set
++# CONFIG_EM_TIMER_STI is not set
++# CONFIG_CLKSRC_VERSATILE is not set
++# CONFIG_MAILBOX is not set
++# CONFIG_IOMMU_SUPPORT is not set
++
++#
++# Remoteproc drivers
++#
++# CONFIG_STE_MODEM_RPROC is not set
++
++#
++# Rpmsg drivers
++#
++
++#
++# SOC (System On Chip) specific Drivers
++#
++# 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
++CONFIG_IRQCHIP=y
++CONFIG_ARM_GIC=y
++# CONFIG_IPACK_BUS is not set
++CONFIG_ARCH_HAS_RESET_CONTROLLER=y
++CONFIG_RESET_CONTROLLER=y
++# CONFIG_FMC is not set
++
++#
++# PHY Subsystem
++#
++CONFIG_GENERIC_PHY=y
++# CONFIG_BCM_KONA_USB2_PHY is not set
++CONFIG_PHY_HISI_INNO_USB2=y
++CONFIG_PHY_HISI_USB3=y
++# CONFIG_POWERCAP is not set
++# CONFIG_MCB is not set
++# CONFIG_HI_DMAC is not set
++
++#
++# Hisilicon driver support
++#
++# CONFIG_CMA_MEM_SHARED is not set
++# CONFIG_CMA_ADVANCE_SHARE is not set
++
++#
++# File systems
++#
++CONFIG_DCACHE_WORD_ACCESS=y
++# CONFIG_EXT2_FS is not set
++# CONFIG_EXT3_FS is not set
++CONFIG_EXT4_FS=y
++CONFIG_EXT4_USE_FOR_EXT23=y
++# CONFIG_EXT4_FS_POSIX_ACL is not set
++# CONFIG_EXT4_FS_SECURITY is not set
++# CONFIG_EXT4_DEBUG is not set
++CONFIG_JBD2=y
++# CONFIG_JBD2_DEBUG is not set
++CONFIG_FS_MBCACHE=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_BTRFS_FS is not set
++# CONFIG_NILFS2_FS is not set
++CONFIG_FS_POSIX_ACL=y
++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 is not set
++# CONFIG_FUSE_FS is not set
++# CONFIG_OVERLAY_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_KERNFS=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=m
++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_YAFFS_FS=y
++CONFIG_YAFFS_YAFFS1=y
++# CONFIG_YAFFS_9BYTE_TAGS is not set
++# CONFIG_YAFFS_DOES_ECC is not set
++CONFIG_YAFFS_YAFFS2=y
++CONFIG_YAFFS_AUTO_YAFFS2=y
++# CONFIG_YAFFS_DISABLE_TAGS_ECC is not set
++# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
++# CONFIG_YAFFS_EMPTY_LOST_AND_FOUND is not set
++# CONFIG_YAFFS_DISABLE_BLOCK_REFRESHING is not set
++# CONFIG_YAFFS_DISABLE_BACKGROUND is not set
++# CONFIG_YAFFS_DISABLE_BAD_BLOCK_MARKING is not set
++CONFIG_YAFFS_XATTR=y
++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 is not set
++# CONFIG_JFFS2_FS_XATTR is not set
++# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
++CONFIG_JFFS2_ZLIB=y
++# CONFIG_JFFS2_LZO is not set
++CONFIG_JFFS2_RTIME=y
++# CONFIG_JFFS2_RUBIN 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 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 is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V2=y
++CONFIG_NFS_V3=y
++CONFIG_NFS_V3_ACL=y
++# CONFIG_NFS_V4 is not set
++# CONFIG_NFS_SWAP is not set
++# CONFIG_ROOT_NFS is not set
++# CONFIG_NFSD is not set
++CONFIG_GRACE_PERIOD=y
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_ACL_SUPPORT=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 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=y
++# CONFIG_DLM is not set
++
++#
++# Kernel hacking
++#
++
++#
++# printk and dmesg options
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4
++# CONFIG_BOOT_PRINTK_DELAY is not set
++
++#
++# Compile-time checks and compiler options
++#
++# CONFIG_DEBUG_INFO is not set
++# CONFIG_ENABLE_WARN_DEPRECATED is not set
++# CONFIG_ENABLE_MUST_CHECK is not set
++CONFIG_FRAME_WARN=1024
++# CONFIG_STRIP_ASM_SYMS is not set
++# CONFIG_READABLE_ASM is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++# CONFIG_DEBUG_FS is not set
++# CONFIG_HEADERS_CHECK is not set
++# CONFIG_DEBUG_SECTION_MISMATCH is not set
++# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
++# CONFIG_MAGIC_SYSRQ is not set
++CONFIG_DEBUG_KERNEL=y
++
++#
++# Memory Debugging
++#
++# 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_STACK_USAGE is not set
++# CONFIG_DEBUG_VM is not set
++CONFIG_DEBUG_MEMORY_INIT=y
++# CONFIG_DEBUG_PER_CPU_MAPS is not set
++# CONFIG_DEBUG_HIGHMEM is not set
++# CONFIG_DEBUG_SHIRQ is not set
++
++#
++# Debug Lockups and Hangs
++#
++# CONFIG_LOCKUP_DETECTOR is not set
++# CONFIG_DETECT_HUNG_TASK is not set
++# CONFIG_PANIC_ON_OOPS is not set
++CONFIG_PANIC_ON_OOPS_VALUE=0
++CONFIG_PANIC_TIMEOUT=0
++CONFIG_SCHED_DEBUG=y
++# CONFIG_SCHEDSTATS is not set
++# CONFIG_SCHED_STACK_END_CHECK is not set
++# CONFIG_TIMER_STATS is not set
++
++#
++# Lock Debugging (spinlocks, mutexes, etc...)
++#
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_LOCK_STAT is not set
++# CONFIG_DEBUG_ATOMIC_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_LOCK_TORTURE_TEST is not set
++CONFIG_STACKTRACE=y
++# CONFIG_DEBUG_KOBJECT is not set
++CONFIG_DEBUG_BUGVERBOSE=y
++# CONFIG_DEBUG_LIST is not set
++# CONFIG_DEBUG_PI_LIST is not set
++# CONFIG_DEBUG_SG is not set
++# CONFIG_DEBUG_NOTIFIERS is not set
++# CONFIG_DEBUG_CREDENTIALS is not set
++
++#
++# RCU Debugging
++#
++# CONFIG_SPARSE_RCU_POINTER is not set
++# CONFIG_TORTURE_TEST is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++CONFIG_RCU_CPU_STALL_TIMEOUT=21
++# CONFIG_RCU_CPU_STALL_INFO is not set
++# CONFIG_RCU_TRACE is not set
++# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_NOTIFIER_ERROR_INJECTION is not set
++# CONFIG_FAULT_INJECTION 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 is not set
++
++#
++# Runtime Testing
++#
++# CONFIG_TEST_LIST_SORT is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_RBTREE_TEST is not set
++# CONFIG_INTERVAL_TREE_TEST is not set
++# CONFIG_PERCPU_TEST is not set
++# CONFIG_ATOMIC64_SELFTEST is not set
++# CONFIG_TEST_STRING_HELPERS is not set
++# CONFIG_TEST_KSTRTOX is not set
++# CONFIG_TEST_RHASHTABLE is not set
++# CONFIG_DMA_API_DEBUG is not set
++# CONFIG_TEST_LKM is not set
++# CONFIG_TEST_USER_COPY is not set
++# CONFIG_TEST_BPF is not set
++# CONFIG_TEST_FIRMWARE is not set
++# CONFIG_TEST_UDELAY is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_KGDB is not set
++# CONFIG_ARM_PTDUMP 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_DEBUG_UART_PL01X is not set
++# CONFIG_DEBUG_UART_8250 is not set
++# CONFIG_DEBUG_UART_BCM63XX is not set
++CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"
++# CONFIG_OC_ETM is not set
++# CONFIG_PID_IN_CONTEXTIDR is not set
++# CONFIG_DEBUG_SET_MODULE_RONX is not set
++# CONFIG_CORESIGHT is not set
++
++#
++# 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_HASH=y
++CONFIG_CRYPTO_HASH2=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_PCRYPT is not set
++# CONFIG_CRYPTO_CRYPTD is not set
++# CONFIG_CRYPTO_MCRYPTD 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_CMAC is not set
++# CONFIG_CRYPTO_HMAC is not set
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_VMAC is not set
++
++#
++# Digest
++#
++CONFIG_CRYPTO_CRC32C=y
++# CONFIG_CRYPTO_CRC32 is not set
++# CONFIG_CRYPTO_CRCT10DIF 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_SHA1_ARM_NEON is not set
++# CONFIG_CRYPTO_SHA256 is not set
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_SHA512_ARM_NEON 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_AES_ARM_BS 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
++# CONFIG_CRYPTO_LZ4 is not set
++# CONFIG_CRYPTO_LZ4HC is not set
++
++#
++# Random Number Generation
++#
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++# CONFIG_CRYPTO_DRBG_MENU is not set
++# CONFIG_CRYPTO_USER_API_HASH is not set
++# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
++CONFIG_CRYPTO_HW=y
++# CONFIG_BINARY_PRINTF is not set
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++CONFIG_GENERIC_STRNCPY_FROM_USER=y
++CONFIG_GENERIC_STRNLEN_USER=y
++CONFIG_GENERIC_NET_UTILS=y
++CONFIG_GENERIC_PCI_IOMAP=y
++CONFIG_GENERIC_IO=y
++CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
++# CONFIG_CRC_CCITT is not set
++CONFIG_CRC16=y
++# CONFIG_CRC_T10DIF is not set
++# 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_AUDIT_ARCH_COMPAT_GENERIC is not set
++# CONFIG_RANDOM32_SELFTEST is not set
++CONFIG_ZLIB_INFLATE=y
++CONFIG_ZLIB_DEFLATE=y
++CONFIG_LZO_COMPRESS=y
++CONFIG_LZO_DECOMPRESS=y
++CONFIG_LZ4_DECOMPRESS=y
++CONFIG_XZ_DEC=y
++CONFIG_XZ_DEC_X86=y
++CONFIG_XZ_DEC_POWERPC=y
++CONFIG_XZ_DEC_IA64=y
++CONFIG_XZ_DEC_ARM=y
++CONFIG_XZ_DEC_ARMTHUMB=y
++CONFIG_XZ_DEC_SPARC=y
++CONFIG_XZ_DEC_BCJ=y
++# CONFIG_XZ_DEC_TEST is not set
++CONFIG_DECOMPRESS_GZIP=y
++CONFIG_DECOMPRESS_BZIP2=y
++CONFIG_DECOMPRESS_LZMA=y
++CONFIG_DECOMPRESS_XZ=y
++CONFIG_DECOMPRESS_LZO=y
++CONFIG_DECOMPRESS_LZ4=y
++CONFIG_GENERIC_ALLOCATOR=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT_MAP=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 is not set
++# CONFIG_CORDIC is not set
++# CONFIG_DDR is not set
++CONFIG_LIBFDT=y
++CONFIG_ARCH_HAS_SG_CHAIN=y
++# CONFIG_VIRTUALIZATION is not set
+diff --git a/arch/arm/configs/hi3519_big_little_nand_defconfig b/arch/arm/configs/hi3519_big_little_nand_defconfig
+new file mode 100644
+index 0000000..9eed93e
+--- /dev/null
++++ b/arch/arm/configs/hi3519_big_little_nand_defconfig
+@@ -0,0 +1,2513 @@
++#
++# Automatically generated file; DO NOT EDIT.
++# Linux/arm 3.18.20 Kernel Configuration
++#
++CONFIG_ARM=y
++CONFIG_ARM_HAS_SG_CHAIN=y
++CONFIG_MIGHT_HAVE_PCI=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=y
++CONFIG_HAVE_PROC_CPU=y
++CONFIG_STACKTRACE_SUPPORT=y
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
++CONFIG_RWSEM_XCHGADD_ALGORITHM=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_NEED_DMA_MAP_STATE=y
++CONFIG_ARCH_SUPPORTS_UPROBES=y
++CONFIG_VECTORS_BASE=0xffff0000
++CONFIG_ARM_PATCH_PHYS_VIRT=y
++CONFIG_GENERIC_BUG=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++CONFIG_IRQ_WORK=y
++CONFIG_BUILDTIME_EXTABLE_SORT=y
++
++#
++# General setup
++#
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_CROSS_COMPILE=""
++# CONFIG_COMPILE_TEST is not set
++CONFIG_LOCALVERSION=""
++# CONFIG_LOCALVERSION_AUTO is not set
++CONFIG_HAVE_KERNEL_GZIP=y
++CONFIG_HAVE_KERNEL_LZMA=y
++CONFIG_HAVE_KERNEL_XZ=y
++CONFIG_HAVE_KERNEL_LZO=y
++CONFIG_HAVE_KERNEL_LZ4=y
++CONFIG_KERNEL_GZIP=y
++# CONFIG_KERNEL_LZMA is not set
++# CONFIG_KERNEL_XZ is not set
++# CONFIG_KERNEL_LZO is not set
++# CONFIG_KERNEL_LZ4 is not set
++CONFIG_DEFAULT_HOSTNAME="(none)"
++CONFIG_SWAP=y
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++# CONFIG_POSIX_MQUEUE is not set
++CONFIG_CROSS_MEMORY_ATTACH=y
++# CONFIG_FHANDLE is not set
++CONFIG_USELIB=y
++# CONFIG_AUDIT is not set
++CONFIG_HAVE_ARCH_AUDITSYSCALL=y
++
++#
++# IRQ subsystem
++#
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_GENERIC_IRQ_SHOW=y
++CONFIG_HARDIRQS_SW_RESEND=y
++CONFIG_IRQ_DOMAIN=y
++CONFIG_HANDLE_DOMAIN_IRQ=y
++CONFIG_IRQ_FORCED_THREADING=y
++CONFIG_SPARSE_IRQ=y
++CONFIG_GENERIC_CLOCKEVENTS=y
++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
++CONFIG_ARCH_HAS_TICK_BROADCAST=y
++CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
++
++#
++# Timers subsystem
++#
++CONFIG_TICK_ONESHOT=y
++CONFIG_NO_HZ_COMMON=y
++# CONFIG_HZ_PERIODIC is not set
++CONFIG_NO_HZ_IDLE=y
++# CONFIG_NO_HZ_FULL is not set
++CONFIG_NO_HZ=y
++# CONFIG_HIGH_RES_TIMERS is not set
++
++#
++# CPU/Task time and stats accounting
++#
++CONFIG_TICK_CPU_ACCOUNTING=y
++# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set
++# CONFIG_IRQ_TIME_ACCOUNTING is not set
++# CONFIG_BSD_PROCESS_ACCT is not set
++# CONFIG_TASKSTATS is not set
++
++#
++# RCU Subsystem
++#
++CONFIG_TREE_RCU=y
++# CONFIG_PREEMPT_RCU is not set
++# CONFIG_TASKS_RCU is not set
++CONFIG_RCU_STALL_COMMON=y
++# CONFIG_RCU_USER_QS is not set
++CONFIG_RCU_FANOUT=32
++CONFIG_RCU_FANOUT_LEAF=16
++# CONFIG_RCU_FANOUT_EXACT is not set
++# CONFIG_RCU_FAST_NO_HZ is not set
++# CONFIG_TREE_RCU_TRACE is not set
++# CONFIG_RCU_NOCB_CPU is not set
++# CONFIG_BUILD_BIN2C is not set
++# CONFIG_IKCONFIG is not set
++CONFIG_LOG_BUF_SHIFT=17
++CONFIG_LOG_CPU_MAX_BUF_SHIFT=12
++CONFIG_GENERIC_SCHED_CLOCK=y
++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_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_USER_NS is not set
++CONFIG_PID_NS=y
++CONFIG_NET_NS=y
++# 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=y
++CONFIG_RD_LZMA=y
++CONFIG_RD_XZ=y
++CONFIG_RD_LZO=y
++CONFIG_RD_LZ4=y
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++CONFIG_HAVE_UID16=y
++CONFIG_BPF=y
++# CONFIG_EXPERT is not set
++CONFIG_UID16=y
++# CONFIG_SGETMASK_SYSCALL is not set
++CONFIG_SYSFS_SYSCALL=y
++# CONFIG_SYSCTL_SYSCALL is not set
++CONFIG_KALLSYMS=y
++# CONFIG_KALLSYMS_ALL is not set
++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_BPF_SYSCALL is not set
++CONFIG_SHMEM=y
++CONFIG_AIO=y
++CONFIG_ADVISE_SYSCALLS=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_SLUB_CPU_PARTIAL=y
++# CONFIG_PROFILING is not set
++CONFIG_HAVE_OPROFILE=y
++# CONFIG_KPROBES is not set
++# CONFIG_JUMP_LABEL is not set
++# CONFIG_UPROBES is not set
++# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
++CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
++CONFIG_ARCH_USE_BUILTIN_BSWAP=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_GENERIC_SMP_IDLE_THREAD=y
++CONFIG_GENERIC_IDLE_POLL_SETUP=y
++CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
++CONFIG_HAVE_CLK=y
++CONFIG_HAVE_DMA_API_DEBUG=y
++CONFIG_HAVE_PERF_REGS=y
++CONFIG_HAVE_PERF_USER_STACK_DUMP=y
++CONFIG_HAVE_ARCH_JUMP_LABEL=y
++CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
++CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
++CONFIG_HAVE_CC_STACKPROTECTOR=y
++# CONFIG_CC_STACKPROTECTOR is not set
++CONFIG_CC_STACKPROTECTOR_NONE=y
++# CONFIG_CC_STACKPROTECTOR_REGULAR is not set
++# CONFIG_CC_STACKPROTECTOR_STRONG is not set
++CONFIG_HAVE_CONTEXT_TRACKING=y
++CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
++CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
++CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
++CONFIG_MODULES_USE_ELF_REL=y
++CONFIG_CLONE_BACKWARDS=y
++CONFIG_OLD_SIGSUSPEND3=y
++CONFIG_OLD_SIGACTION=y
++
++#
++# GCOV-based kernel profiling
++#
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_SLABINFO=y
++CONFIG_RT_MUTEXES=y
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++# CONFIG_MODULE_FORCE_LOAD is not set
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++# CONFIG_MODULE_SIG is not set
++# CONFIG_MODULE_COMPRESS is not set
++CONFIG_STOP_MACHINE=y
++CONFIG_BLOCK=y
++CONFIG_LBDAF=y
++CONFIG_BLK_DEV_BSG=y
++# CONFIG_BLK_DEV_BSGLIB is not set
++# CONFIG_BLK_DEV_INTEGRITY is not set
++CONFIG_BLK_CMDLINE_PARSER=y
++
++#
++# Partition Types
++#
++CONFIG_PARTITION_ADVANCED=y
++# CONFIG_ACORN_PARTITION is not set
++# CONFIG_AIX_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=y
++# CONFIG_SYSV68_PARTITION is not set
++CONFIG_CMDLINE_PARTITION=y
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++CONFIG_DEFAULT_DEADLINE=y
++# CONFIG_DEFAULT_CFQ is not set
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="deadline"
++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_ARCH_SUPPORTS_ATOMIC_RMW=y
++CONFIG_MUTEX_SPIN_ON_OWNER=y
++CONFIG_RWSEM_SPIN_ON_OWNER=y
++CONFIG_FREEZER=y
++
++#
++# System Type
++#
++CONFIG_MMU=y
++CONFIG_ARCH_MULTIPLATFORM=y
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_AT91 is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_GEMINI is not set
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_IOP13XX is not set
++# CONFIG_ARCH_IOP32X is not set
++# CONFIG_ARCH_IOP33X is not set
++# CONFIG_ARCH_IXP4XX is not set
++# CONFIG_ARCH_DOVE is not set
++# CONFIG_ARCH_MV78XX0 is not set
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_MMP is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_W90X900 is not set
++# CONFIG_ARCH_LPC32XX is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_MSM is not set
++# CONFIG_ARCH_SHMOBILE_LEGACY 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_DAVINCI is not set
++# CONFIG_ARCH_OMAP1 is not set
++
++#
++# Multiple platform selection
++#
++
++#
++# CPU Core family selection
++#
++# CONFIG_ARCH_MULTI_V6 is not set
++CONFIG_ARCH_MULTI_V7=y
++CONFIG_ARCH_MULTI_V6_V7=y
++# CONFIG_ARCH_MULTI_CPU_AUTO is not set
++# CONFIG_ARCH_VIRT is not set
++# CONFIG_ARCH_MVEBU is not set
++# CONFIG_ARCH_BCM is not set
++# CONFIG_ARCH_BERLIN is not set
++# CONFIG_ARCH_HIGHBANK is not set
++CONFIG_ARCH_HISI=y
++
++#
++# Hisilicon platform type
++#
++# CONFIG_ARCH_HI3xxx is not set
++# CONFIG_ARCH_HIP04 is not set
++# CONFIG_ARCH_HIX5HD2 is not set
++CONFIG_ARCH_HI3519=y
++# CONFIG_ARCH_HI3519V101 is not set
++# CONFIG_ARCH_HI3516AV200 is not set
++# CONFIG_ARCH_HI3559 is not set
++# CONFIG_ARCH_HI3556 is not set
++CONFIG_PMC=y
++# CONFIG_ARCH_HI3536C is not set
++# CONFIG_ARCH_KEYSTONE is not set
++# CONFIG_ARCH_MESON is not set
++# CONFIG_ARCH_MXC is not set
++# CONFIG_ARCH_MEDIATEK is not set
++
++#
++# TI OMAP/AM/DM/DRA Family
++#
++# CONFIG_ARCH_OMAP3 is not set
++# CONFIG_ARCH_OMAP4 is not set
++# CONFIG_SOC_OMAP5 is not set
++# CONFIG_SOC_AM33XX is not set
++# CONFIG_SOC_AM43XX is not set
++# CONFIG_SOC_DRA7XX is not set
++# CONFIG_ARCH_QCOM is not set
++# CONFIG_ARCH_ROCKCHIP is not set
++# CONFIG_ARCH_SOCFPGA is not set
++# CONFIG_PLAT_SPEAR is not set
++# CONFIG_ARCH_STI is not set
++# CONFIG_ARCH_S5PV210 is not set
++# CONFIG_ARCH_EXYNOS is not set
++# CONFIG_ARCH_SHMOBILE_MULTI is not set
++# CONFIG_ARCH_SUNXI is not set
++# CONFIG_ARCH_SIRF is not set
++# CONFIG_ARCH_TEGRA is not set
++# CONFIG_ARCH_U8500 is not set
++# CONFIG_ARCH_VEXPRESS is not set
++# CONFIG_ARCH_WM8850 is not set
++# CONFIG_ARCH_ZYNQ is not set
++CONFIG_ARM_TIMER_SP804=y
++
++#
++# Processor Type
++#
++CONFIG_CPU_V7=y
++CONFIG_CPU_32v6K=y
++CONFIG_CPU_32v7=y
++CONFIG_CPU_ABRT_EV7=y
++CONFIG_CPU_PABRT_V7=y
++CONFIG_CPU_CACHE_V7=y
++CONFIG_CPU_CACHE_VIPT=y
++CONFIG_CPU_COPY_V6=y
++CONFIG_CPU_TLB_V7=y
++CONFIG_CPU_HAS_ASID=y
++CONFIG_CPU_CP15=y
++CONFIG_CPU_CP15_MMU=y
++
++#
++# Processor Features
++#
++# CONFIG_ARM_LPAE is not set
++# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
++CONFIG_ARM_THUMB=y
++# CONFIG_ARM_THUMBEE is not set
++CONFIG_ARM_VIRT_EXT=y
++CONFIG_SWP_EMULATE=y
++# CONFIG_CPU_ICACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_DISABLE is not set
++# CONFIG_CPU_BPREDICT_DISABLE is not set
++CONFIG_KUSER_HELPERS=y
++CONFIG_MIGHT_HAVE_CACHE_L2X0=y
++# CONFIG_CACHE_L2X0 is not set
++CONFIG_ARM_L1_CACHE_SHIFT_6=y
++CONFIG_ARM_L1_CACHE_SHIFT=6
++CONFIG_ARM_DMA_MEM_BUFFERABLE=y
++CONFIG_MULTI_IRQ_HANDLER=y
++# CONFIG_ARM_ERRATA_430973 is not set
++# CONFIG_ARM_ERRATA_643719 is not set
++# CONFIG_ARM_ERRATA_720789 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_ARM_ERRATA_775420 is not set
++# CONFIG_ARM_ERRATA_798181 is not set
++# CONFIG_ARM_ERRATA_773022 is not set
++
++#
++# Bus support
++#
++CONFIG_ARM_AMBA=y
++# CONFIG_PCI is not set
++# 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=y
++# CONFIG_SCHED_SMT is not set
++CONFIG_DISABLE_CPU_SCHED_DOMAIN_BALANCE=y
++CONFIG_SCHED_HMP=y
++# CONFIG_SCHED_HMP_PRIO_FILTER is not set
++CONFIG_HMP_FAST_CPU_MASK=""
++CONFIG_HMP_SLOW_CPU_MASK=""
++CONFIG_HMP_VARIABLE_SCALE=y
++# CONFIG_HMP_FREQUENCY_INVARIANT_SCALE is not set
++# CONFIG_SCHED_HMP_LITTLE_PACKING is not set
++CONFIG_HAVE_ARM_ARCH_TIMER=y
++# CONFIG_MCPM is not set
++# CONFIG_BIG_LITTLE is not set
++CONFIG_VMSPLIT_3G=y
++# CONFIG_VMSPLIT_2G is not set
++# CONFIG_VMSPLIT_1G is not set
++CONFIG_PAGE_OFFSET=0xC0000000
++CONFIG_NR_CPUS=4
++CONFIG_HOTPLUG_CPU=y
++# CONFIG_ARM_PSCI is not set
++CONFIG_ARCH_NR_GPIO=0
++CONFIG_PREEMPT_NONE=y
++# CONFIG_PREEMPT_VOLUNTARY is not set
++# CONFIG_PREEMPT is not set
++CONFIG_HZ_FIXED=0
++CONFIG_HZ_100=y
++# CONFIG_HZ_200 is not set
++# CONFIG_HZ_250 is not set
++# CONFIG_HZ_300 is not set
++# CONFIG_HZ_500 is not set
++# CONFIG_HZ_1000 is not set
++CONFIG_HZ=100
++# CONFIG_SCHED_HRTICK is not set
++# CONFIG_THUMB2_KERNEL is not set
++CONFIG_AEABI=y
++# CONFIG_OABI_COMPAT is not set
++# 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_ARCH_WANT_GENERAL_HUGETLB=y
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_HAVE_MEMBLOCK=y
++CONFIG_NO_BOOTMEM=y
++CONFIG_MEMORY_ISOLATION=y
++# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=4
++CONFIG_COMPACTION=y
++CONFIG_MIGRATION=y
++# CONFIG_PHYS_ADDR_T_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_BOUNCE=y
++# CONFIG_KSM is not set
++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
++# CONFIG_CLEANCACHE is not set
++# CONFIG_FRONTSWAP is not set
++CONFIG_CMA=y
++# CONFIG_CMA_DEBUG is not set
++CONFIG_CMA_AREAS=7
++# CONFIG_ZPOOL is not set
++# CONFIG_ZBUD is not set
++# CONFIG_ZSMALLOC 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_SWIOTLB=y
++CONFIG_IOMMU_HELPER=y
++# CONFIG_XEN is not set
++# CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART is not set
++
++#
++# Boot options
++#
++CONFIG_USE_OF=y
++CONFIG_ATAGS=y
++# CONFIG_DEPRECATED_PARAM_STRUCT is not set
++# CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE is not set
++CONFIG_ZBOOT_ROM_TEXT=0
++CONFIG_ZBOOT_ROM_BSS=0
++CONFIG_ARM_APPENDED_DTB=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_KEXEC is not set
++# CONFIG_CRASH_DUMP is not set
++CONFIG_AUTO_ZRELADDR=y
++
++#
++# CPU Power Management
++#
++
++#
++# CPU Frequency scaling
++#
++CONFIG_CPU_FREQ=y
++CONFIG_CPU_FREQ_GOV_COMMON=y
++CONFIG_CPU_FREQ_STAT=y
++# CONFIG_CPU_FREQ_STAT_DETAILS is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
++CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
++# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE is not set
++CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
++CONFIG_CPU_FREQ_GOV_POWERSAVE=y
++CONFIG_CPU_FREQ_GOV_USERSPACE=y
++CONFIG_CPU_FREQ_GOV_ONDEMAND=y
++CONFIG_CPU_FREQ_GOV_INTERACTIVE=y
++CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
++CONFIG_CPUFREQ_DT=y
++
++#
++# ARM CPU frequency scaling drivers
++#
++# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set
++
++#
++# CPU Idle
++#
++# CONFIG_CPU_IDLE is not set
++# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++CONFIG_VFP=y
++CONFIG_VFPv3=y
++CONFIG_NEON=y
++CONFIG_KERNEL_MODE_NEON=y
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
++CONFIG_BINFMT_SCRIPT=y
++# CONFIG_HAVE_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
++CONFIG_COREDUMP=y
++
++#
++# Power management options
++#
++CONFIG_SUSPEND=y
++CONFIG_SUSPEND_FREEZER=y
++CONFIG_WAKELOCK=y
++CONFIG_HIBERNATE_CALLBACKS=y
++CONFIG_HISI_SNAPSHOT_BOOT=y
++# CONFIG_DEFAULT_MTD is not set
++CONFIG_DEFAULT_DDR=y
++CONFIG_SNAPSHOT_BUF_START=0x8a000000
++CONFIG_SNAPSHOT_BUF_SIZE=0x4000000
++CONFIG_HIBERNATION=y
++CONFIG_GZIP_COMPRESS=y
++CONFIG_PM_STD_PARTITION=""
++CONFIG_PM_SLEEP=y
++CONFIG_PM_SLEEP_SMP=y
++# CONFIG_PM_AUTOSLEEP is not set
++# CONFIG_PM_WAKELOCKS is not set
++# CONFIG_PM_RUNTIME is not set
++CONFIG_PM=y
++# CONFIG_PM_DEBUG is not set
++# CONFIG_APM_EMULATION is not set
++CONFIG_PM_OPP=y
++CONFIG_PM_CLK=y
++# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set
++CONFIG_CPU_PM=y
++# CONFIG_SUSPEND_TIME is not set
++CONFIG_ARCH_SUSPEND_POSSIBLE=y
++CONFIG_ARM_CPU_SUSPEND=y
++CONFIG_ARCH_HIBERNATION_POSSIBLE=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_NET_IP_TUNNEL=m
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_NET_IPVTI is not set
++# CONFIG_NET_UDP_TUNNEL is not set
++# CONFIG_NET_FOU is not set
++# CONFIG_GENEVE 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=y
++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=y
++# 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_VTI 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_ANDROID_PARANOID_NETWORK is not set
++CONFIG_NET_ACTIVITY_STATS=y
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NET_PTP_CLASSIFY 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_NF_TABLES is not set
++# CONFIG_NETFILTER_XTABLES is not set
++# CONFIG_IP_SET is not set
++# CONFIG_IP_VS is not set
++
++#
++# IP: Netfilter Configuration
++#
++# CONFIG_NF_DEFRAG_IPV4 is not set
++# CONFIG_NF_LOG_ARP is not set
++# CONFIG_NF_LOG_IPV4 is not set
++# CONFIG_NF_REJECT_IPV4 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_NF_REJECT_IPV6 is not set
++# CONFIG_NF_LOG_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_HAVE_NET_DSA=y
++# 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_PHONET is not set
++# CONFIG_6LOWPAN 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_VSOCKETS is not set
++# CONFIG_NETLINK_MMAP is not set
++# CONFIG_NETLINK_DIAG is not set
++# CONFIG_NET_MPLS_GSO is not set
++# CONFIG_HSR is not set
++CONFIG_RPS=y
++CONFIG_RFS_ACCEL=y
++CONFIG_XPS=y
++# CONFIG_CGROUP_NET_PRIO is not set
++# CONFIG_CGROUP_NET_CLASSID is not set
++CONFIG_NET_RX_BUSY_POLL=y
++CONFIG_BQL=y
++# CONFIG_BPF_JIT is not set
++CONFIG_NET_FLOW_LIMIT=y
++
++#
++# 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 is not set
++CONFIG_DEVTMPFS=y
++CONFIG_DEVTMPFS_MOUNT=y
++CONFIG_STANDALONE=y
++# CONFIG_PREVENT_FIRMWARE_BUILD is not set
++CONFIG_FW_LOADER=y
++# CONFIG_FIRMWARE_IN_KERNEL is not set
++CONFIG_EXTRA_FIRMWARE=""
++# CONFIG_FW_LOADER_USER_HELPER_FALLBACK is not set
++CONFIG_ALLOW_DEV_COREDUMP=y
++# 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_HAVE_CPU_AUTOPROBE is not set
++CONFIG_REGMAP=y
++CONFIG_REGMAP_MMIO=y
++# CONFIG_DMA_SHARED_BUFFER is not set
++CONFIG_DMA_CMA=y
++
++#
++# Default contiguous memory area size:
++#
++CONFIG_CMA_SIZE_MBYTES=16
++CONFIG_CMA_SIZE_SEL_MBYTES=y
++# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set
++# CONFIG_CMA_SIZE_SEL_MIN is not set
++# CONFIG_CMA_SIZE_SEL_MAX is not set
++CONFIG_CMA_ALIGNMENT=8
++
++#
++# Bus devices
++#
++# CONFIG_BRCMSTB_GISB_ARB is not set
++CONFIG_ARM_CCI=y
++# CONFIG_VEXPRESS_CONFIG 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=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_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
++CONFIG_HIFMC=y
++# CONFIG_HIFMC_SPI_NAND is not set
++CONFIG_HIFMC_NAND=y
++
++#
++# 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_SST25L is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_PHRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++# CONFIG_MTD_BLOCK2MTD is not set
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOCG3 is not set
++CONFIG_MTD_NAND_IDS=y
++CONFIG_MTD_NAND_ECC=y
++# CONFIG_MTD_NAND_ECC_SMC is not set
++CONFIG_MTD_NAND=y
++# CONFIG_MTD_NAND_ECC_BCH is not set
++# CONFIG_MTD_SM_COMMON is not set
++# CONFIG_MTD_NAND_DENALI is not set
++# CONFIG_MTD_NAND_OMAP_BCH_BUILD is not set
++# CONFIG_MTD_NAND_DISKONCHIP is not set
++# CONFIG_MTD_NAND_DOCG4 is not set
++# CONFIG_MTD_NAND_NANDSIM is not set
++# CONFIG_MTD_NAND_PLATFORM is not set
++# CONFIG_HISI_NAND_FS_MAY_NO_YAFFS2 is not set
++# CONFIG_HISI_NAND_ECC_STATUS_REPORT is not set
++CONFIG_HIFMC100_NAND=y
++CONFIG_HIFMC100_MAX_NAND_CHIP=1
++# CONFIG_HIFMC100_NAND_EDO_MODE is not set
++CONFIG_RW_H_WIDTH=10
++CONFIG_R_L_WIDTH=10
++CONFIG_W_L_WIDTH=10
++# CONFIG_HIFMC100_NAND_HARDWARE_PAGESIZE_ECC is not set
++CONFIG_HIFMC100_NAND_AUTO_PAGESIZE_ECC=y
++# CONFIG_HIFMC100_NAND_PAGESIZE_AUTO_ECC_NONE is not set
++# CONFIG_MTD_ONENAND is not set
++
++#
++# LPDDR & LPDDR2 PCM memory drivers
++#
++# CONFIG_MTD_LPDDR is not set
++# CONFIG_MTD_LPDDR2_NVM is not set
++# CONFIG_MTD_SPI_NOR is not set
++# CONFIG_MTD_UBI is not set
++CONFIG_DTC=y
++CONFIG_OF=y
++
++#
++# Device Tree and Open Firmware support
++#
++# 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_NET=y
++CONFIG_OF_MDIO=y
++CONFIG_OF_MTD=y
++CONFIG_OF_RESERVED_MEM=y
++CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
++# CONFIG_PARPORT is not set
++CONFIG_BLK_DEV=y
++# CONFIG_BLK_DEV_NULL_BLK is not set
++# CONFIG_BLK_DEV_COW_COMMON is not set
++# CONFIG_BLK_DEV_LOOP 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=65536
++# CONFIG_BLK_DEV_XIP is not set
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH 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_DUMMY_IRQ 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_UID_STAT is not set
++# CONFIG_BMP085_I2C is not set
++# CONFIG_BMP085_SPI is not set
++# CONFIG_USB_SWITCH_FSA9480 is not set
++# CONFIG_LATTICE_ECP3_CONFIG is not set
++# CONFIG_SRAM is not set
++# CONFIG_C2PORT is not set
++
++#
++# EEPROM support
++#
++# CONFIG_EEPROM_AT24 is not set
++# CONFIG_EEPROM_AT25 is not set
++# CONFIG_EEPROM_LEGACY is not set
++# CONFIG_EEPROM_MAX6875 is not set
++# CONFIG_EEPROM_93CX6 is not set
++# CONFIG_EEPROM_93XX46 is not set
++
++#
++# Texas Instruments shared transport line discipline
++#
++# 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
++
++#
++# Intel MIC Bus Driver
++#
++
++#
++# Intel MIC Host Driver
++#
++
++#
++# Intel MIC Card Driver
++#
++# CONFIG_ECHO is not set
++# CONFIG_CXL_BASE is not set
++
++#
++# hisi 'himm/himd.l/himc'support
++#
++CONFIG_HISI_REG=y
++
++#
++# SCSI device support
++#
++CONFIG_SCSI_MOD=y
++# CONFIG_RAID_ATTRS is not set
++CONFIG_SCSI=y
++CONFIG_SCSI_DMA=y
++# CONFIG_SCSI_NETLINK is not set
++# CONFIG_SCSI_MQ_DEFAULT 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_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 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_NET_CORE=y
++# CONFIG_BONDING is not set
++# CONFIG_DUMMY is not set
++# CONFIG_EQUALIZER is not set
++# CONFIG_NET_TEAM is not set
++# CONFIG_MACVLAN is not set
++# CONFIG_VXLAN is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_TUN is not set
++# CONFIG_VETH is not set
++# CONFIG_NLMON is not set
++
++#
++# 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_NET_DSA_MV88E6171 is not set
++# CONFIG_NET_DSA_BCM_SF2 is not set
++CONFIG_ETHERNET=y
++# CONFIG_ALTERA_TSE is not set
++# CONFIG_NET_XGENE is not set
++# CONFIG_NET_VENDOR_ARC is not set
++# CONFIG_NET_CADENCE is not set
++# CONFIG_NET_VENDOR_BROADCOM is not set
++# CONFIG_NET_VENDOR_CIRRUS is not set
++# CONFIG_DM9000 is not set
++# CONFIG_DNET is not set
++# CONFIG_NET_VENDOR_FARADAY is not set
++CONFIG_NET_VENDOR_HISILICON=y
++# CONFIG_HIX5HD2_GMAC is not set
++# CONFIG_HISI_FEMAC is not set
++CONFIG_HIETH_GMAC=y
++CONFIG_HIGMAC_DESC_4WORD=y
++CONFIG_HIGMAC_RXCSUM=y
++CONFIG_RX_FLOW_CTRL_SUPPORT=y
++CONFIG_TX_FLOW_CTRL_SUPPORT=y
++CONFIG_TX_FLOW_CTRL_PAUSE_TIME=0xFFFF
++CONFIG_TX_FLOW_CTRL_PAUSE_INTERVAL=0xFFFF
++CONFIG_TX_FLOW_CTRL_ACTIVE_THRESHOLD=16
++CONFIG_TX_FLOW_CTRL_DEACTIVE_THRESHOLD=32
++# CONFIG_HIETH_SWITCH_FABRIC is not set
++# CONFIG_NET_VENDOR_INTEL is not set
++# CONFIG_NET_VENDOR_MARVELL is not set
++# CONFIG_NET_VENDOR_MICREL is not set
++# CONFIG_NET_VENDOR_MICROCHIP is not set
++# CONFIG_NET_VENDOR_NATSEMI is not set
++# CONFIG_ETHOC is not set
++# CONFIG_NET_VENDOR_QUALCOMM is not set
++# CONFIG_NET_VENDOR_SAMSUNG is not set
++# CONFIG_NET_VENDOR_SEEQ is not set
++# CONFIG_NET_VENDOR_SMSC is not set
++# CONFIG_NET_VENDOR_STMICRO is not set
++# CONFIG_NET_VENDOR_VIA is not set
++# CONFIG_NET_VENDOR_WIZNET is not set
++CONFIG_PHYLIB=y
++
++#
++# MII PHY device drivers
++#
++# CONFIG_AT803X_PHY is not set
++# CONFIG_AMD_PHY is not set
++# CONFIG_AMD_XGBE_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 is not set
++# CONFIG_BROADCOM_PHY is not set
++# CONFIG_BCM7XXX_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_MMIOREG is not set
++# CONFIG_MDIO_BCM_UNIMAC is not set
++# CONFIG_MDIO_HISI_FEMAC is not set
++CONFIG_MDIO_HISI_GEMAC=y
++# CONFIG_MICREL_KS8995MA is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++CONFIG_USB_NET_DRIVERS=y
++# 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_RTL8152 is not set
++# CONFIG_USB_USBNET is not set
++# CONFIG_USB_IPHETH is not set
++# CONFIG_WLAN is not set
++
++#
++# Enable WiMAX (Networking options) to see the WiMAX drivers
++#
++# CONFIG_WAN is not set
++# CONFIG_ISDN is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
++# CONFIG_INPUT_POLLDEV is not set
++# CONFIG_INPUT_SPARSEKMAP is not set
++# CONFIG_INPUT_MATRIXKMAP is not set
++
++#
++# Userland interfaces
++#
++CONFIG_INPUT_MOUSEDEV=y
++CONFIG_INPUT_MOUSEDEV_PSAUX=y
++CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
++CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
++# CONFIG_INPUT_JOYDEV is not set
++CONFIG_INPUT_EVDEV=y
++# CONFIG_INPUT_EVBUG is not set
++# CONFIG_INPUT_KEYRESET is not set
++# CONFIG_INPUT_KEYCOMBO 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_TCA6416 is not set
++# CONFIG_KEYBOARD_TCA8418 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 is not set
++# CONFIG_KEYBOARD_CAP1106 is not set
++CONFIG_INPUT_MOUSE=y
++CONFIG_MOUSE_PS2=y
++CONFIG_MOUSE_PS2_ALPS=y
++CONFIG_MOUSE_PS2_LOGIPS2PP=y
++CONFIG_MOUSE_PS2_SYNAPTICS=y
++CONFIG_MOUSE_PS2_CYPRESS=y
++CONFIG_MOUSE_PS2_TRACKPOINT=y
++# CONFIG_MOUSE_PS2_ELANTECH is not set
++# CONFIG_MOUSE_PS2_SENTELIC is not set
++# CONFIG_MOUSE_PS2_TOUCHKIT is not set
++# CONFIG_MOUSE_SERIAL is not set
++# CONFIG_MOUSE_APPLETOUCH is not set
++# CONFIG_MOUSE_BCM5974 is not set
++# CONFIG_MOUSE_CYAPA is not set
++# CONFIG_MOUSE_VSXXXAA is not set
++# CONFIG_MOUSE_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 is not set
++# CONFIG_INPUT_MISC is not set
++
++#
++# Hardware I/O ports
++#
++CONFIG_SERIO=y
++CONFIG_SERIO_SERPORT=y
++# CONFIG_SERIO_AMBAKMI is not set
++CONFIG_SERIO_LIBPS2=y
++# CONFIG_SERIO_RAW is not set
++# CONFIG_SERIO_ALTERA_PS2 is not set
++# CONFIG_SERIO_PS2MULT is not set
++# CONFIG_SERIO_ARC_PS2 is not set
++# CONFIG_SERIO_APBPS2 is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++CONFIG_TTY=y
++CONFIG_VT=y
++CONFIG_CONSOLE_TRANSLATIONS=y
++CONFIG_VT_CONSOLE=y
++CONFIG_VT_CONSOLE_SLEEP=y
++CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
++CONFIG_UNIX98_PTYS=y
++# CONFIG_DEVPTS_MULTIPLE_INSTANCES 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_DEVMEM=y
++CONFIG_DEVKMEM=y
++
++#
++# Serial drivers
++#
++CONFIG_SERIAL_EARLYCON=y
++# CONFIG_SERIAL_8250 is not set
++
++#
++# Non-8250 serial port support
++#
++# CONFIG_SERIAL_AMBA_PL010 is not set
++CONFIG_SERIAL_AMBA_PL011=y
++CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
++# CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST is not set
++# 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_SC16IS7XX is not set
++# CONFIG_SERIAL_ALTERA_JTAGUART is not set
++# CONFIG_SERIAL_ALTERA_UART is not set
++# CONFIG_SERIAL_XILINX_PS_UART is not set
++# CONFIG_SERIAL_ARC is not set
++# CONFIG_SERIAL_FSL_LPUART is not set
++# CONFIG_SERIAL_ST_ASC is not set
++# CONFIG_HVC_DCC is not set
++# CONFIG_IPMI_HANDLER is not set
++# CONFIG_HW_RANDOM is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++# CONFIG_DCC_TTY is not set
++# CONFIG_XILLYBUS is not set
++
++#
++# I2C support
++#
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++CONFIG_I2C_COMPAT=y
++CONFIG_I2C_CHARDEV=y
++CONFIG_I2C_MUX=y
++
++#
++# Multiplexer I2C Chip support
++#
++# CONFIG_I2C_MUX_PCA9541 is not set
++CONFIG_I2C_HELPER_AUTO=y
++
++#
++# I2C Hardware Bus support
++#
++
++#
++# I2C system bus drivers (mostly embedded / system-on-chip)
++#
++# CONFIG_I2C_DESIGNWARE_PLATFORM is not set
++# CONFIG_I2C_HIBVT is not set
++# CONFIG_I2C_HISI_V110 is not set
++# CONFIG_I2C_NOMADIK 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_RK3X 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_ROBOTFUZZ_OSIF is not set
++# CONFIG_I2C_TAOS_EVM is not set
++# CONFIG_I2C_TINY_USB is not set
++
++#
++# Other I2C/SMBus bus drivers
++#
++CONFIG_HI_I2C=y
++CONFIG_HI_I2C0_IO_BASE=0x12110000
++CONFIG_HI_I2C0_IO_SIZE=0x1000
++CONFIG_HI_I2C1_IO_BASE=0x12111000
++CONFIG_HI_I2C1_IO_SIZE=0x1000
++CONFIG_HI_I2C2_IO_BASE=0x12112000
++CONFIG_HI_I2C2_IO_SIZE=0x1000
++CONFIG_HI_I2C3_IO_BASE=0x12113000
++CONFIG_HI_I2C3_IO_SIZE=0x1000
++CONFIG_HI_I2C_RETRIES=0x1
++CONFIG_HI_I2C_TX_FIFO=0x8
++CONFIG_HI_I2C_RX_FIFO=0x8
++CONFIG_HI_I2C0_CLK_LIMIT=100000
++CONFIG_HI_I2C1_CLK_LIMIT=100000
++CONFIG_HI_I2C2_CLK_LIMIT=100000
++CONFIG_HI_I2C3_CLK_LIMIT=100000
++# 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_CADENCE is not set
++# CONFIG_SPI_FSL_SPI is not set
++CONFIG_SPI_PL022=y
++# CONFIG_SPI_PXA2XX_PCI is not set
++# CONFIG_SPI_ROCKCHIP 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=y
++# CONFIG_SPI_TLE62X0 is not set
++# CONFIG_SPMI is not set
++# CONFIG_HSI is not set
++
++#
++# PPS support
++#
++# CONFIG_PPS is not set
++
++#
++# PPS generators support
++#
++
++#
++# PTP clock support
++#
++# CONFIG_PTP_1588_CLOCK is not set
++
++#
++# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
++#
++CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
++CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
++# CONFIG_GPIOLIB is not set
++# CONFIG_W1 is not set
++CONFIG_POWER_SUPPLY=y
++# CONFIG_POWER_SUPPLY_DEBUG is not set
++# CONFIG_PDA_POWER is not set
++# CONFIG_TEST_POWER is not set
++# CONFIG_BATTERY_DS2780 is not set
++# CONFIG_BATTERY_DS2781 is not set
++# CONFIG_BATTERY_DS2782 is not set
++# CONFIG_BATTERY_SBS is not set
++# CONFIG_BATTERY_BQ27x00 is not set
++# CONFIG_BATTERY_MAX17040 is not set
++# CONFIG_BATTERY_MAX17042 is not set
++# CONFIG_CHARGER_MAX8903 is not set
++# CONFIG_CHARGER_LP8727 is not set
++# CONFIG_CHARGER_BQ2415X is not set
++# CONFIG_CHARGER_SMB347 is not set
++CONFIG_POWER_RESET=y
++# CONFIG_POWER_RESET_BRCMSTB is not set
++CONFIG_POWER_RESET_HISI=y
++# CONFIG_POWER_RESET_RESTART is not set
++# CONFIG_POWER_RESET_VERSATILE is not set
++# CONFIG_POWER_RESET_SYSCON is not set
++# CONFIG_POWER_AVS is not set
++# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
++# CONFIG_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=y
++# CONFIG_MFD_AS3711 is not set
++# CONFIG_MFD_AS3722 is not set
++# CONFIG_PMIC_ADP5520 is not set
++# CONFIG_MFD_BCM590XX is not set
++# CONFIG_MFD_AXP20X is not set
++# CONFIG_MFD_CROS_EC is not set
++# CONFIG_PMIC_DA903X is not set
++# CONFIG_MFD_DA9052_SPI is not set
++# CONFIG_MFD_DA9052_I2C is not set
++# CONFIG_MFD_DA9055 is not set
++# CONFIG_MFD_DA9063 is not set
++# CONFIG_MFD_MC13XXX_SPI is not set
++# CONFIG_MFD_MC13XXX_I2C is not set
++# CONFIG_MFD_HI6421_PMIC is not set
++CONFIG_MFD_HISI_FMC=y
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_INTEL_SOC_PMIC is not set
++# CONFIG_MFD_KEMPLD is not set
++# CONFIG_MFD_88PM800 is not set
++# CONFIG_MFD_88PM805 is not set
++# CONFIG_MFD_88PM860X is not set
++# CONFIG_MFD_MAX14577 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_MENF21BMC is not set
++# CONFIG_EZX_PCAP is not set
++# CONFIG_MFD_VIPERBOARD is not set
++# CONFIG_MFD_RETU is not set
++# CONFIG_MFD_PCF50633 is not set
++# CONFIG_MFD_PM8921_CORE is not set
++# CONFIG_MFD_RTSX_USB is not set
++# CONFIG_MFD_RC5T583 is not set
++# CONFIG_MFD_RK808 is not set
++# CONFIG_MFD_RN5T618 is not set
++# CONFIG_MFD_SEC_CORE is not set
++# CONFIG_MFD_SI476X_CORE is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_MFD_SMSC is not set
++# CONFIG_ABX500_CORE is not set
++# CONFIG_MFD_STMPE is not set
++CONFIG_MFD_SYSCON=y
++# CONFIG_MFD_TI_AM335X_TSCADC is not set
++# CONFIG_MFD_LP3943 is not set
++# CONFIG_MFD_LP8788 is not set
++# CONFIG_MFD_PALMAS is not set
++# CONFIG_TPS6105X is not set
++# CONFIG_TPS6507X is not set
++# CONFIG_MFD_TPS65090 is not set
++# CONFIG_MFD_TPS65217 is not set
++# CONFIG_MFD_TPS65218 is not set
++# CONFIG_MFD_TPS6586X is not set
++# CONFIG_MFD_TPS80031 is not set
++# CONFIG_TWL4030_CORE is not set
++# CONFIG_TWL6040_CORE is not set
++# CONFIG_MFD_WL1273_CORE is not set
++# CONFIG_MFD_LM3533 is not set
++# CONFIG_MFD_TC3589X is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_MFD_T7L66XB is not set
++# CONFIG_MFD_TC6387XB is not set
++# CONFIG_MFD_TC6393XB is not set
++# CONFIG_MFD_ARIZONA_I2C is not set
++# CONFIG_MFD_ARIZONA_SPI is not set
++# CONFIG_MFD_WM8400 is not set
++# CONFIG_MFD_WM831X_I2C is not set
++# CONFIG_MFD_WM831X_SPI is not set
++# CONFIG_MFD_WM8350_I2C is not set
++# CONFIG_MFD_WM8994 is not set
++CONFIG_REGULATOR=y
++# CONFIG_REGULATOR_DEBUG is not set
++# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
++# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
++# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
++# CONFIG_REGULATOR_ACT8865 is not set
++# CONFIG_REGULATOR_AD5398 is not set
++# CONFIG_REGULATOR_ANATOP is not set
++# CONFIG_REGULATOR_DA9210 is not set
++# CONFIG_REGULATOR_DA9211 is not set
++# CONFIG_REGULATOR_FAN53555 is not set
++# CONFIG_REGULATOR_ISL9305 is not set
++# CONFIG_REGULATOR_ISL6271A is not set
++# CONFIG_REGULATOR_LP3971 is not set
++# CONFIG_REGULATOR_LP3972 is not set
++# CONFIG_REGULATOR_LP872X is not set
++# CONFIG_REGULATOR_LP8755 is not set
++# CONFIG_REGULATOR_LTC3589 is not set
++# CONFIG_REGULATOR_MAX1586 is not set
++# CONFIG_REGULATOR_MAX8649 is not set
++# CONFIG_REGULATOR_MAX8660 is not set
++# CONFIG_REGULATOR_MAX8952 is not set
++# CONFIG_REGULATOR_MAX8973 is not set
++# CONFIG_REGULATOR_PFUZE100 is not set
++# CONFIG_REGULATOR_TPS51632 is not set
++# CONFIG_REGULATOR_TPS62360 is not set
++# CONFIG_REGULATOR_TPS65023 is not set
++# CONFIG_REGULATOR_TPS6507X is not set
++# CONFIG_REGULATOR_TPS6524X is not set
++# CONFIG_MEDIA_SUPPORT is not set
++
++#
++# Graphics support
++#
++# CONFIG_IMX_IPUV3_CORE is not set
++
++#
++# Direct Rendering Manager
++#
++# CONFIG_DRM is not set
++
++#
++# Frame buffer Devices
++#
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++CONFIG_FB_CMDLINE=y
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++# CONFIG_FB_CFB_FILLRECT is not set
++# CONFIG_FB_CFB_COPYAREA is not set
++# CONFIG_FB_CFB_IMAGEBLIT is not set
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# 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_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_ARMCLCD is not set
++# CONFIG_FB_OPENCORES is not set
++# CONFIG_FB_S1D13XXX is not set
++# CONFIG_FB_SMSCUFX is not set
++# CONFIG_FB_UDL is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_BROADSHEET is not set
++# CONFIG_FB_AUO_K190X is not set
++# CONFIG_FB_SIMPLE is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++# CONFIG_VGASTATE is not set
++
++#
++# Console display driver support
++#
++CONFIG_DUMMY_CONSOLE=y
++# CONFIG_FRAMEBUFFER_CONSOLE is not set
++# CONFIG_LOGO is not set
++# CONFIG_SOUND is not set
++
++#
++# HID support
++#
++CONFIG_HID=y
++# CONFIG_HID_BATTERY_STRENGTH is not set
++# CONFIG_HIDRAW is not set
++# CONFIG_UHID is not set
++CONFIG_HID_GENERIC=y
++
++#
++# Special HID drivers
++#
++CONFIG_HID_A4TECH=y
++# CONFIG_HID_ACRUX is not set
++CONFIG_HID_APPLE=y
++# CONFIG_HID_APPLEIR is not set
++# CONFIG_HID_AUREAL is not set
++CONFIG_HID_BELKIN=y
++CONFIG_HID_CHERRY=y
++CONFIG_HID_CHICONY=y
++CONFIG_HID_CYPRESS=y
++# CONFIG_HID_DRAGONRISE is not set
++# CONFIG_HID_EMS_FF is not set
++# CONFIG_HID_ELECOM is not set
++# CONFIG_HID_ELO is not set
++CONFIG_HID_EZKEY=y
++# CONFIG_HID_HOLTEK is not set
++# CONFIG_HID_HUION 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_ICADE is not set
++# CONFIG_HID_TWINHAN is not set
++CONFIG_HID_KENSINGTON=y
++# CONFIG_HID_LCPOWER is not set
++# CONFIG_HID_LENOVO is not set
++CONFIG_HID_LOGITECH=y
++# CONFIG_HID_LOGITECH_HIDPP is not set
++# CONFIG_LOGITECH_FF is not set
++# CONFIG_LOGIRUMBLEPAD2_FF is not set
++# CONFIG_LOGIG940_FF is not set
++# CONFIG_LOGIWHEELS_FF is not set
++# CONFIG_HID_MAGICMOUSE is not set
++CONFIG_HID_MICROSOFT=y
++CONFIG_HID_MONTEREY=y
++# 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_PENMOUNT is not set
++# CONFIG_HID_PETALYNX is not set
++# CONFIG_HID_PICOLCD is not set
++# CONFIG_HID_PRIMAX is not set
++# CONFIG_HID_ROCCAT is not set
++# CONFIG_HID_SAITEK is not set
++# CONFIG_HID_SAMSUNG is not set
++# CONFIG_HID_SPEEDLINK is not set
++# CONFIG_HID_STEELSERIES is not set
++# CONFIG_HID_SUNPLUS is not set
++# CONFIG_HID_RMI 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_XINMO is not set
++# CONFIG_HID_ZEROPLUS is not set
++# CONFIG_HID_ZYDACRON is not set
++# CONFIG_HID_SENSOR_HUB is not set
++
++#
++# USB HID support
++#
++CONFIG_USB_HID=y
++# CONFIG_HID_PID is not set
++# CONFIG_USB_HIDDEV is not set
++
++#
++# I2C HID support
++#
++# CONFIG_I2C_HID is not set
++CONFIG_USB_OHCI_LITTLE_ENDIAN=y
++CONFIG_USB_SUPPORT=y
++CONFIG_USB_COMMON=y
++CONFIG_USB_ARCH_HAS_HCD=y
++CONFIG_USB=y
++# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
++
++#
++# Miscellaneous USB options
++#
++CONFIG_USB_DEFAULT_PERSIST=y
++# CONFIG_USB_DYNAMIC_MINORS is not set
++# CONFIG_USB_OTG_WHITELIST is not set
++# CONFIG_USB_OTG_FSM is not set
++# CONFIG_USB_MON is not set
++# CONFIG_USB_WUSB_CBAF is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_C67X00_HCD is not set
++CONFIG_USB_XHCI_HCD=y
++CONFIG_USB_XHCI_PLATFORM=y
++CONFIG_USB_XHCI_HISILICON=y
++CONFIG_USB_EHCI_HCD=y
++# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
++CONFIG_USB_EHCI_TT_NEWSCHED=y
++CONFIG_USB_EHCI_HCD_PLATFORM=y
++# 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_FUSBH200_HCD is not set
++# CONFIG_USB_FOTG210_HCD is not set
++# CONFIG_USB_MAX3421_HCD is not set
++CONFIG_USB_OHCI_HCD=y
++CONFIG_USB_OHCI_HCD_PLATFORM=y
++# CONFIG_USB_SL811_HCD is not set
++# CONFIG_USB_R8A66597_HCD is not set
++# CONFIG_USB_HCD_TEST_MODE is not set
++
++#
++# USB Device Class drivers
++#
++# CONFIG_USB_ACM is not set
++# CONFIG_USB_PRINTER is not set
++# CONFIG_USB_WDM is not set
++# CONFIG_USB_TMC is not set
++
++#
++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
++#
++
++#
++# also be needed; see USB_STORAGE Help for more info
++#
++CONFIG_USB_STORAGE=y
++# CONFIG_USB_STORAGE_DEBUG is not set
++# CONFIG_USB_STORAGE_REALTEK is not set
++# CONFIG_USB_STORAGE_DATAFAB is not set
++# CONFIG_USB_STORAGE_FREECOM is not set
++# CONFIG_USB_STORAGE_ISD200 is not set
++# CONFIG_USB_STORAGE_USBAT is not set
++# CONFIG_USB_STORAGE_SDDR09 is not set
++# CONFIG_USB_STORAGE_SDDR55 is not set
++# CONFIG_USB_STORAGE_JUMPSHOT is not set
++# CONFIG_USB_STORAGE_ALAUDA is not set
++# CONFIG_USB_STORAGE_ONETOUCH is not set
++# CONFIG_USB_STORAGE_KARMA is not set
++# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
++# CONFIG_USB_STORAGE_ENE_UB6250 is not set
++# CONFIG_USB_UAS is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++# CONFIG_USBIP_CORE is not set
++# CONFIG_USB_MUSB_HDRC is not set
++# CONFIG_USB_DWC3 is not set
++# CONFIG_USB_DWC2 is not set
++# CONFIG_USB_CHIPIDEA is not set
++
++#
++# USB port drivers
++#
++# CONFIG_USB_SERIAL is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
++# CONFIG_USB_SEVSEG is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
++# CONFIG_USB_APPLEDISPLAY is not set
++# CONFIG_USB_SISUSBVGA is not set
++# CONFIG_USB_LD is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
++# CONFIG_USB_IOWARRIOR is not set
++# CONFIG_USB_TEST is not set
++# CONFIG_USB_EHSET_TEST_FIXTURE is not set
++# CONFIG_USB_ISIGHTFW is not set
++# CONFIG_USB_YUREX is not set
++# CONFIG_USB_EZUSB_FX2 is not set
++# CONFIG_USB_HSIC_USB3503 is not set
++# CONFIG_USB_LINK_LAYER_TEST is not set
++
++#
++# USB Physical Layer drivers
++#
++# CONFIG_USB_PHY is not set
++# CONFIG_USB_OTG_WAKELOCK is not set
++# CONFIG_NOP_USB_XCEIV is not set
++# CONFIG_AM335X_PHY_USB is not set
++# CONFIG_USB_ISP1301 is not set
++# CONFIG_USB_ULPI is not set
++CONFIG_USB_GADGET=y
++# CONFIG_USB_GADGET_DEBUG is not set
++# CONFIG_USB_GADGET_DEBUG_FILES is not set
++CONFIG_USB_GADGET_VBUS_DRAW=2
++CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2
++
++#
++# USB Peripheral Controller
++#
++# CONFIG_USB_FUSB300 is not set
++# CONFIG_USB_FOTG210_UDC is not set
++# CONFIG_USB_GR_UDC is not set
++# CONFIG_USB_R8A66597 is not set
++# CONFIG_USB_PXA27X is not set
++# CONFIG_USB_MV_UDC is not set
++CONFIG_HIUSB_DEVICE2_0=y
++CONFIG_USB_HISI_UDC=m
++# CONFIG_USB_AUTO_SWITCH is not set
++# CONFIG_HIUSB_DEVICE3_0 is not set
++# CONFIG_USB_MV_U3D is not set
++# CONFIG_USB_M66592 is not set
++# CONFIG_USB_NET2272 is not set
++# CONFIG_USB_GADGET_XILINX is not set
++# CONFIG_USB_DUMMY_HCD is not set
++CONFIG_USB_LIBCOMPOSITE=m
++CONFIG_USB_F_ACM=m
++CONFIG_USB_U_SERIAL=m
++CONFIG_USB_U_ETHER=m
++CONFIG_USB_F_SERIAL=m
++CONFIG_USB_F_OBEX=m
++CONFIG_USB_F_ECM=m
++CONFIG_USB_F_SUBSET=m
++CONFIG_USB_F_RNDIS=m
++CONFIG_USB_F_MASS_STORAGE=m
++# CONFIG_USB_CONFIGFS is not set
++# CONFIG_USB_ZERO 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 is not set
++# CONFIG_USB_FUNCTIONFS is not set
++CONFIG_USB_MASS_STORAGE=m
++CONFIG_USB_G_SERIAL=m
++# CONFIG_USB_G_PRINTER is not set
++# CONFIG_USB_CDC_COMPOSITE is not set
++# CONFIG_USB_G_ACM_MS is not set
++# CONFIG_USB_G_MULTI is not set
++# CONFIG_USB_G_HID is not set
++# CONFIG_USB_G_DBGP is not set
++# CONFIG_UWB is not set
++CONFIG_MMC=y
++# CONFIG_MMC_DEBUG is not set
++# CONFIG_MMC_CLKGATE is not set
++CONFIG_MMC_EMBEDDED_SDIO=y
++# CONFIG_MMC_PARANOID_SD_INIT is not set
++
++#
++# MMC/SD/SDIO Card Drivers
++#
++CONFIG_MMC_BLOCK=y
++CONFIG_MMC_BLOCK_MINORS=8
++CONFIG_MMC_BLOCK_BOUNCE=y
++# CONFIG_MMC_BLOCK_DEFERRED_RESUME is not set
++# CONFIG_SDIO_UART is not set
++# CONFIG_MMC_TEST is not set
++
++#
++# MMC/SD/SDIO Host Controller Drivers
++#
++# CONFIG_MMC_ARMMMCI is not set
++# CONFIG_MMC_SDHCI is not set
++# CONFIG_MMC_DW is not set
++# CONFIG_MMC_VUB300 is not set
++# CONFIG_MMC_USHC is not set
++# CONFIG_MMC_USDHI6ROL0 is not set
++CONFIG_HIMCIV200=y
++CONFIG_SEND_AUTO_STOP=y
++CONFIG_DETECT_CARD_TIME=200
++# CONFIG_MEMSTICK is not set
++# CONFIG_NEW_LEDS is not set
++# CONFIG_SWITCH is not set
++# CONFIG_ACCESSIBILITY is not set
++# CONFIG_EDAC is not set
++CONFIG_RTC_LIB=y
++# CONFIG_RTC_CLASS is not set
++# CONFIG_DMADEVICES is not set
++# CONFIG_AUXDISPLAY is not set
++# CONFIG_UIO is not set
++# CONFIG_VIRT_DRIVERS is not set
++
++#
++# Virtio drivers
++#
++# CONFIG_VIRTIO_MMIO is not set
++
++#
++# Microsoft Hyper-V guest support
++#
++# CONFIG_STAGING is not set
++
++#
++# SOC (System On Chip) specific Drivers
++#
++# CONFIG_SOC_TI is not set
++CONFIG_CLKDEV_LOOKUP=y
++CONFIG_HAVE_CLK_PREPARE=y
++CONFIG_COMMON_CLK=y
++
++#
++# Common Clock Framework
++#
++# CONFIG_COMMON_CLK_SI5351 is not set
++# CONFIG_COMMON_CLK_SI570 is not set
++# CONFIG_COMMON_CLK_PXA is not set
++# CONFIG_COMMON_CLK_QCOM is not set
++
++#
++# Hardware Spinlock drivers
++#
++
++#
++# Clock Source drivers
++#
++CONFIG_CLKSRC_OF=y
++CONFIG_CLKSRC_MMIO=y
++CONFIG_ARM_ARCH_TIMER=y
++CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y
++# CONFIG_ATMEL_PIT is not set
++# CONFIG_SH_TIMER_CMT is not set
++# CONFIG_SH_TIMER_MTU2 is not set
++# CONFIG_SH_TIMER_TMU is not set
++# CONFIG_EM_TIMER_STI is not set
++# CONFIG_CLKSRC_VERSATILE is not set
++# CONFIG_MAILBOX is not set
++# CONFIG_IOMMU_SUPPORT is not set
++
++#
++# Remoteproc drivers
++#
++# CONFIG_STE_MODEM_RPROC is not set
++
++#
++# Rpmsg drivers
++#
++
++#
++# SOC (System On Chip) specific Drivers
++#
++# 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
++CONFIG_IRQCHIP=y
++CONFIG_ARM_GIC=y
++# CONFIG_IPACK_BUS is not set
++CONFIG_ARCH_HAS_RESET_CONTROLLER=y
++CONFIG_RESET_CONTROLLER=y
++# CONFIG_FMC is not set
++
++#
++# PHY Subsystem
++#
++CONFIG_GENERIC_PHY=y
++# CONFIG_BCM_KONA_USB2_PHY is not set
++CONFIG_PHY_HISI_INNO_USB2=y
++CONFIG_PHY_HISI_USB3=y
++# CONFIG_POWERCAP is not set
++# CONFIG_MCB is not set
++# CONFIG_HI_DMAC is not set
++
++#
++# Hisilicon driver support
++#
++# CONFIG_CMA_MEM_SHARED is not set
++# CONFIG_CMA_ADVANCE_SHARE is not set
++
++#
++# File systems
++#
++CONFIG_DCACHE_WORD_ACCESS=y
++# CONFIG_EXT2_FS is not set
++# CONFIG_EXT3_FS is not set
++CONFIG_EXT4_FS=y
++CONFIG_EXT4_USE_FOR_EXT23=y
++# CONFIG_EXT4_FS_POSIX_ACL is not set
++# CONFIG_EXT4_FS_SECURITY is not set
++# CONFIG_EXT4_DEBUG is not set
++CONFIG_JBD2=y
++# CONFIG_JBD2_DEBUG is not set
++CONFIG_FS_MBCACHE=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_BTRFS_FS is not set
++# CONFIG_NILFS2_FS is not set
++CONFIG_FS_POSIX_ACL=y
++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 is not set
++# CONFIG_FUSE_FS is not set
++# CONFIG_OVERLAY_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_KERNFS=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=m
++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_YAFFS_FS=y
++CONFIG_YAFFS_YAFFS1=y
++# CONFIG_YAFFS_9BYTE_TAGS is not set
++# CONFIG_YAFFS_DOES_ECC is not set
++CONFIG_YAFFS_YAFFS2=y
++CONFIG_YAFFS_AUTO_YAFFS2=y
++# CONFIG_YAFFS_DISABLE_TAGS_ECC is not set
++# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
++# CONFIG_YAFFS_EMPTY_LOST_AND_FOUND is not set
++# CONFIG_YAFFS_DISABLE_BLOCK_REFRESHING is not set
++# CONFIG_YAFFS_DISABLE_BACKGROUND is not set
++# CONFIG_YAFFS_DISABLE_BAD_BLOCK_MARKING is not set
++CONFIG_YAFFS_XATTR=y
++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 is not set
++# CONFIG_JFFS2_FS_XATTR is not set
++# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
++CONFIG_JFFS2_ZLIB=y
++# CONFIG_JFFS2_LZO is not set
++CONFIG_JFFS2_RTIME=y
++# CONFIG_JFFS2_RUBIN 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 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 is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V2=y
++CONFIG_NFS_V3=y
++CONFIG_NFS_V3_ACL=y
++# CONFIG_NFS_V4 is not set
++# CONFIG_NFS_SWAP is not set
++# CONFIG_ROOT_NFS is not set
++# CONFIG_NFSD is not set
++CONFIG_GRACE_PERIOD=y
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_ACL_SUPPORT=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 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=y
++# CONFIG_DLM is not set
++
++#
++# Kernel hacking
++#
++
++#
++# printk and dmesg options
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4
++# CONFIG_BOOT_PRINTK_DELAY is not set
++
++#
++# Compile-time checks and compiler options
++#
++# CONFIG_DEBUG_INFO is not set
++# CONFIG_ENABLE_WARN_DEPRECATED is not set
++# CONFIG_ENABLE_MUST_CHECK is not set
++CONFIG_FRAME_WARN=1024
++# CONFIG_STRIP_ASM_SYMS is not set
++# CONFIG_READABLE_ASM is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++# CONFIG_DEBUG_FS is not set
++# CONFIG_HEADERS_CHECK is not set
++# CONFIG_DEBUG_SECTION_MISMATCH is not set
++# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
++# CONFIG_MAGIC_SYSRQ is not set
++CONFIG_DEBUG_KERNEL=y
++
++#
++# Memory Debugging
++#
++# 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_STACK_USAGE is not set
++# CONFIG_DEBUG_VM is not set
++CONFIG_DEBUG_MEMORY_INIT=y
++# CONFIG_DEBUG_PER_CPU_MAPS is not set
++# CONFIG_DEBUG_HIGHMEM is not set
++# CONFIG_DEBUG_SHIRQ is not set
++
++#
++# Debug Lockups and Hangs
++#
++# CONFIG_LOCKUP_DETECTOR is not set
++# CONFIG_DETECT_HUNG_TASK is not set
++# CONFIG_PANIC_ON_OOPS is not set
++CONFIG_PANIC_ON_OOPS_VALUE=0
++CONFIG_PANIC_TIMEOUT=0
++CONFIG_SCHED_DEBUG=y
++# CONFIG_SCHEDSTATS is not set
++# CONFIG_SCHED_STACK_END_CHECK is not set
++# CONFIG_TIMER_STATS is not set
++
++#
++# Lock Debugging (spinlocks, mutexes, etc...)
++#
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_LOCK_STAT is not set
++# CONFIG_DEBUG_ATOMIC_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_LOCK_TORTURE_TEST is not set
++CONFIG_STACKTRACE=y
++# CONFIG_DEBUG_KOBJECT is not set
++CONFIG_DEBUG_BUGVERBOSE=y
++# CONFIG_DEBUG_LIST is not set
++# CONFIG_DEBUG_PI_LIST is not set
++# CONFIG_DEBUG_SG is not set
++# CONFIG_DEBUG_NOTIFIERS is not set
++# CONFIG_DEBUG_CREDENTIALS is not set
++
++#
++# RCU Debugging
++#
++# CONFIG_SPARSE_RCU_POINTER is not set
++# CONFIG_TORTURE_TEST is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++CONFIG_RCU_CPU_STALL_TIMEOUT=21
++# CONFIG_RCU_CPU_STALL_INFO is not set
++# CONFIG_RCU_TRACE is not set
++# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_NOTIFIER_ERROR_INJECTION is not set
++# CONFIG_FAULT_INJECTION 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 is not set
++
++#
++# Runtime Testing
++#
++# CONFIG_TEST_LIST_SORT is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_RBTREE_TEST is not set
++# CONFIG_INTERVAL_TREE_TEST is not set
++# CONFIG_PERCPU_TEST is not set
++# CONFIG_ATOMIC64_SELFTEST is not set
++# CONFIG_TEST_STRING_HELPERS is not set
++# CONFIG_TEST_KSTRTOX is not set
++# CONFIG_TEST_RHASHTABLE is not set
++# CONFIG_DMA_API_DEBUG is not set
++# CONFIG_TEST_LKM is not set
++# CONFIG_TEST_USER_COPY is not set
++# CONFIG_TEST_BPF is not set
++# CONFIG_TEST_FIRMWARE is not set
++# CONFIG_TEST_UDELAY is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_KGDB is not set
++# CONFIG_ARM_PTDUMP 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_DEBUG_UART_PL01X is not set
++# CONFIG_DEBUG_UART_8250 is not set
++# CONFIG_DEBUG_UART_BCM63XX is not set
++CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"
++# CONFIG_OC_ETM is not set
++# CONFIG_PID_IN_CONTEXTIDR is not set
++# CONFIG_DEBUG_SET_MODULE_RONX is not set
++# CONFIG_CORESIGHT is not set
++
++#
++# 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_HASH=y
++CONFIG_CRYPTO_HASH2=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_PCRYPT is not set
++# CONFIG_CRYPTO_CRYPTD is not set
++# CONFIG_CRYPTO_MCRYPTD 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_CMAC is not set
++# CONFIG_CRYPTO_HMAC is not set
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_VMAC is not set
++
++#
++# Digest
++#
++CONFIG_CRYPTO_CRC32C=y
++# CONFIG_CRYPTO_CRC32 is not set
++# CONFIG_CRYPTO_CRCT10DIF 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_SHA1_ARM_NEON is not set
++# CONFIG_CRYPTO_SHA256 is not set
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_SHA512_ARM_NEON 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_AES_ARM_BS 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
++# CONFIG_CRYPTO_LZ4 is not set
++# CONFIG_CRYPTO_LZ4HC is not set
++
++#
++# Random Number Generation
++#
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++# CONFIG_CRYPTO_DRBG_MENU is not set
++# CONFIG_CRYPTO_USER_API_HASH is not set
++# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
++CONFIG_CRYPTO_HW=y
++# CONFIG_BINARY_PRINTF is not set
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++CONFIG_GENERIC_STRNCPY_FROM_USER=y
++CONFIG_GENERIC_STRNLEN_USER=y
++CONFIG_GENERIC_NET_UTILS=y
++CONFIG_GENERIC_PCI_IOMAP=y
++CONFIG_GENERIC_IO=y
++CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
++# CONFIG_CRC_CCITT is not set
++CONFIG_CRC16=y
++# CONFIG_CRC_T10DIF is not set
++# 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_AUDIT_ARCH_COMPAT_GENERIC is not set
++# CONFIG_RANDOM32_SELFTEST is not set
++CONFIG_ZLIB_INFLATE=y
++CONFIG_ZLIB_DEFLATE=y
++CONFIG_LZO_COMPRESS=y
++CONFIG_LZO_DECOMPRESS=y
++CONFIG_LZ4_DECOMPRESS=y
++CONFIG_XZ_DEC=y
++CONFIG_XZ_DEC_X86=y
++CONFIG_XZ_DEC_POWERPC=y
++CONFIG_XZ_DEC_IA64=y
++CONFIG_XZ_DEC_ARM=y
++CONFIG_XZ_DEC_ARMTHUMB=y
++CONFIG_XZ_DEC_SPARC=y
++CONFIG_XZ_DEC_BCJ=y
++# CONFIG_XZ_DEC_TEST is not set
++CONFIG_DECOMPRESS_GZIP=y
++CONFIG_DECOMPRESS_BZIP2=y
++CONFIG_DECOMPRESS_LZMA=y
++CONFIG_DECOMPRESS_XZ=y
++CONFIG_DECOMPRESS_LZO=y
++CONFIG_DECOMPRESS_LZ4=y
++CONFIG_GENERIC_ALLOCATOR=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT_MAP=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 is not set
++# CONFIG_CORDIC is not set
++# CONFIG_DDR is not set
++CONFIG_LIBFDT=y
++CONFIG_ARCH_HAS_SG_CHAIN=y
++# CONFIG_VIRTUALIZATION is not set
+diff --git a/arch/arm/configs/hi3519v101_big_little_defconfig b/arch/arm/configs/hi3519v101_big_little_defconfig
+new file mode 100644
+index 0000000..509ac58
+--- /dev/null
++++ b/arch/arm/configs/hi3519v101_big_little_defconfig
+@@ -0,0 +1,2701 @@
++#
++# Automatically generated file; DO NOT EDIT.
++# Linux/arm 3.18.20 Kernel Configuration
++#
++CONFIG_ARM=y
++CONFIG_ARM_HAS_SG_CHAIN=y
++CONFIG_MIGHT_HAVE_PCI=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=y
++CONFIG_HAVE_PROC_CPU=y
++CONFIG_STACKTRACE_SUPPORT=y
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
++CONFIG_RWSEM_XCHGADD_ALGORITHM=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_NEED_DMA_MAP_STATE=y
++CONFIG_ARCH_SUPPORTS_UPROBES=y
++CONFIG_VECTORS_BASE=0xffff0000
++CONFIG_ARM_PATCH_PHYS_VIRT=y
++CONFIG_GENERIC_BUG=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++CONFIG_IRQ_WORK=y
++CONFIG_BUILDTIME_EXTABLE_SORT=y
++
++#
++# General setup
++#
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_CROSS_COMPILE=""
++# CONFIG_COMPILE_TEST is not set
++CONFIG_LOCALVERSION=""
++# CONFIG_LOCALVERSION_AUTO is not set
++CONFIG_HAVE_KERNEL_GZIP=y
++CONFIG_HAVE_KERNEL_LZMA=y
++CONFIG_HAVE_KERNEL_XZ=y
++CONFIG_HAVE_KERNEL_LZO=y
++CONFIG_HAVE_KERNEL_LZ4=y
++CONFIG_KERNEL_GZIP=y
++# CONFIG_KERNEL_LZMA is not set
++# CONFIG_KERNEL_XZ is not set
++# CONFIG_KERNEL_LZO is not set
++# CONFIG_KERNEL_LZ4 is not set
++CONFIG_DEFAULT_HOSTNAME="(none)"
++CONFIG_SWAP=y
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++# CONFIG_POSIX_MQUEUE is not set
++CONFIG_CROSS_MEMORY_ATTACH=y
++# CONFIG_FHANDLE is not set
++CONFIG_USELIB=y
++# CONFIG_AUDIT is not set
++CONFIG_HAVE_ARCH_AUDITSYSCALL=y
++
++#
++# IRQ subsystem
++#
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_GENERIC_IRQ_SHOW=y
++CONFIG_HARDIRQS_SW_RESEND=y
++CONFIG_IRQ_DOMAIN=y
++CONFIG_HANDLE_DOMAIN_IRQ=y
++CONFIG_IRQ_FORCED_THREADING=y
++CONFIG_SPARSE_IRQ=y
++CONFIG_GENERIC_CLOCKEVENTS=y
++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
++CONFIG_ARCH_HAS_TICK_BROADCAST=y
++CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
++
++#
++# Timers subsystem
++#
++CONFIG_TICK_ONESHOT=y
++CONFIG_NO_HZ_COMMON=y
++# CONFIG_HZ_PERIODIC is not set
++CONFIG_NO_HZ_IDLE=y
++# CONFIG_NO_HZ_FULL is not set
++CONFIG_NO_HZ=y
++# CONFIG_HIGH_RES_TIMERS is not set
++
++#
++# CPU/Task time and stats accounting
++#
++CONFIG_TICK_CPU_ACCOUNTING=y
++# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set
++# CONFIG_IRQ_TIME_ACCOUNTING is not set
++# CONFIG_BSD_PROCESS_ACCT is not set
++# CONFIG_TASKSTATS is not set
++
++#
++# RCU Subsystem
++#
++CONFIG_TREE_RCU=y
++# CONFIG_PREEMPT_RCU is not set
++# CONFIG_TASKS_RCU is not set
++CONFIG_RCU_STALL_COMMON=y
++# CONFIG_RCU_USER_QS is not set
++CONFIG_RCU_FANOUT=32
++CONFIG_RCU_FANOUT_LEAF=16
++# CONFIG_RCU_FANOUT_EXACT is not set
++# CONFIG_RCU_FAST_NO_HZ is not set
++# CONFIG_TREE_RCU_TRACE is not set
++# CONFIG_RCU_NOCB_CPU is not set
++# CONFIG_BUILD_BIN2C is not set
++# CONFIG_IKCONFIG is not set
++CONFIG_LOG_BUF_SHIFT=17
++CONFIG_LOG_CPU_MAX_BUF_SHIFT=12
++CONFIG_GENERIC_SCHED_CLOCK=y
++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_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_USER_NS is not set
++CONFIG_PID_NS=y
++CONFIG_NET_NS=y
++# 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=y
++CONFIG_RD_LZMA=y
++CONFIG_RD_XZ=y
++CONFIG_RD_LZO=y
++CONFIG_RD_LZ4=y
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++CONFIG_HAVE_UID16=y
++CONFIG_BPF=y
++# CONFIG_EXPERT is not set
++CONFIG_UID16=y
++# CONFIG_SGETMASK_SYSCALL is not set
++CONFIG_SYSFS_SYSCALL=y
++# CONFIG_SYSCTL_SYSCALL is not set
++CONFIG_KALLSYMS=y
++# CONFIG_KALLSYMS_ALL is not set
++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_BPF_SYSCALL is not set
++CONFIG_SHMEM=y
++CONFIG_AIO=y
++CONFIG_ADVISE_SYSCALLS=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_SLUB_CPU_PARTIAL=y
++# CONFIG_PROFILING is not set
++CONFIG_HAVE_OPROFILE=y
++# CONFIG_KPROBES is not set
++# CONFIG_JUMP_LABEL is not set
++# CONFIG_UPROBES is not set
++# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
++CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
++CONFIG_ARCH_USE_BUILTIN_BSWAP=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_GENERIC_SMP_IDLE_THREAD=y
++CONFIG_GENERIC_IDLE_POLL_SETUP=y
++CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
++CONFIG_HAVE_CLK=y
++CONFIG_HAVE_DMA_API_DEBUG=y
++CONFIG_HAVE_PERF_REGS=y
++CONFIG_HAVE_PERF_USER_STACK_DUMP=y
++CONFIG_HAVE_ARCH_JUMP_LABEL=y
++CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
++CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
++CONFIG_HAVE_CC_STACKPROTECTOR=y
++# CONFIG_CC_STACKPROTECTOR is not set
++CONFIG_CC_STACKPROTECTOR_NONE=y
++# CONFIG_CC_STACKPROTECTOR_REGULAR is not set
++# CONFIG_CC_STACKPROTECTOR_STRONG is not set
++CONFIG_HAVE_CONTEXT_TRACKING=y
++CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
++CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
++CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
++CONFIG_MODULES_USE_ELF_REL=y
++CONFIG_CLONE_BACKWARDS=y
++CONFIG_OLD_SIGSUSPEND3=y
++CONFIG_OLD_SIGACTION=y
++
++#
++# GCOV-based kernel profiling
++#
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_SLABINFO=y
++CONFIG_RT_MUTEXES=y
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++# CONFIG_MODULE_FORCE_LOAD is not set
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++# CONFIG_MODULE_SIG is not set
++# CONFIG_MODULE_COMPRESS is not set
++CONFIG_STOP_MACHINE=y
++CONFIG_BLOCK=y
++CONFIG_LBDAF=y
++CONFIG_BLK_DEV_BSG=y
++# CONFIG_BLK_DEV_BSGLIB is not set
++# CONFIG_BLK_DEV_INTEGRITY is not set
++CONFIG_BLK_CMDLINE_PARSER=y
++
++#
++# Partition Types
++#
++CONFIG_PARTITION_ADVANCED=y
++# CONFIG_ACORN_PARTITION is not set
++# CONFIG_AIX_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=y
++# CONFIG_SYSV68_PARTITION is not set
++CONFIG_CMDLINE_PARTITION=y
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++CONFIG_DEFAULT_DEADLINE=y
++# CONFIG_DEFAULT_CFQ is not set
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="deadline"
++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_ARCH_SUPPORTS_ATOMIC_RMW=y
++CONFIG_MUTEX_SPIN_ON_OWNER=y
++CONFIG_RWSEM_SPIN_ON_OWNER=y
++CONFIG_FREEZER=y
++
++#
++# System Type
++#
++CONFIG_MMU=y
++CONFIG_ARCH_MULTIPLATFORM=y
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_AT91 is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_GEMINI is not set
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_IOP13XX is not set
++# CONFIG_ARCH_IOP32X is not set
++# CONFIG_ARCH_IOP33X is not set
++# CONFIG_ARCH_IXP4XX is not set
++# CONFIG_ARCH_DOVE is not set
++# CONFIG_ARCH_MV78XX0 is not set
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_MMP is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_W90X900 is not set
++# CONFIG_ARCH_LPC32XX is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_MSM is not set
++# CONFIG_ARCH_SHMOBILE_LEGACY 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_DAVINCI is not set
++# CONFIG_ARCH_OMAP1 is not set
++
++#
++# Multiple platform selection
++#
++
++#
++# CPU Core family selection
++#
++# CONFIG_ARCH_MULTI_V6 is not set
++CONFIG_ARCH_MULTI_V7=y
++CONFIG_ARCH_MULTI_V6_V7=y
++# CONFIG_ARCH_MULTI_CPU_AUTO is not set
++# CONFIG_ARCH_VIRT is not set
++# CONFIG_ARCH_MVEBU is not set
++# CONFIG_ARCH_BCM is not set
++# CONFIG_ARCH_BERLIN is not set
++# CONFIG_ARCH_HIGHBANK is not set
++CONFIG_ARCH_HISI=y
++
++#
++# Hisilicon platform type
++#
++# CONFIG_ARCH_HI3xxx is not set
++# CONFIG_ARCH_HIP04 is not set
++# CONFIG_ARCH_HIX5HD2 is not set
++# CONFIG_ARCH_HI3519 is not set
++CONFIG_ARCH_HI3519V101=y
++# CONFIG_ARCH_HI3516AV200 is not set
++# CONFIG_ARCH_HI3559 is not set
++# CONFIG_ARCH_HI3556 is not set
++CONFIG_PMC=y
++# CONFIG_ARCH_HI3536C is not set
++# CONFIG_ARCH_KEYSTONE is not set
++# CONFIG_ARCH_MESON is not set
++# CONFIG_ARCH_MXC is not set
++# CONFIG_ARCH_MEDIATEK is not set
++
++#
++# TI OMAP/AM/DM/DRA Family
++#
++# CONFIG_ARCH_OMAP3 is not set
++# CONFIG_ARCH_OMAP4 is not set
++# CONFIG_SOC_OMAP5 is not set
++# CONFIG_SOC_AM33XX is not set
++# CONFIG_SOC_AM43XX is not set
++# CONFIG_SOC_DRA7XX is not set
++# CONFIG_ARCH_QCOM is not set
++# CONFIG_ARCH_ROCKCHIP is not set
++# CONFIG_ARCH_SOCFPGA is not set
++# CONFIG_PLAT_SPEAR is not set
++# CONFIG_ARCH_STI is not set
++# CONFIG_ARCH_S5PV210 is not set
++# CONFIG_ARCH_EXYNOS is not set
++# CONFIG_ARCH_SHMOBILE_MULTI is not set
++# CONFIG_ARCH_SUNXI is not set
++# CONFIG_ARCH_SIRF is not set
++# CONFIG_ARCH_TEGRA is not set
++# CONFIG_ARCH_U8500 is not set
++# CONFIG_ARCH_VEXPRESS is not set
++# CONFIG_ARCH_WM8850 is not set
++# CONFIG_ARCH_ZYNQ is not set
++CONFIG_ARM_TIMER_SP804=y
++
++#
++# Processor Type
++#
++CONFIG_CPU_V7=y
++CONFIG_CPU_32v6K=y
++CONFIG_CPU_32v7=y
++CONFIG_CPU_ABRT_EV7=y
++CONFIG_CPU_PABRT_V7=y
++CONFIG_CPU_CACHE_V7=y
++CONFIG_CPU_CACHE_VIPT=y
++CONFIG_CPU_COPY_V6=y
++CONFIG_CPU_TLB_V7=y
++CONFIG_CPU_HAS_ASID=y
++CONFIG_CPU_CP15=y
++CONFIG_CPU_CP15_MMU=y
++
++#
++# Processor Features
++#
++# CONFIG_ARM_LPAE is not set
++# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
++CONFIG_ARM_THUMB=y
++# CONFIG_ARM_THUMBEE is not set
++CONFIG_ARM_VIRT_EXT=y
++CONFIG_SWP_EMULATE=y
++# CONFIG_CPU_ICACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_DISABLE is not set
++# CONFIG_CPU_BPREDICT_DISABLE is not set
++CONFIG_KUSER_HELPERS=y
++CONFIG_MIGHT_HAVE_CACHE_L2X0=y
++# CONFIG_CACHE_L2X0 is not set
++CONFIG_ARM_L1_CACHE_SHIFT_6=y
++CONFIG_ARM_L1_CACHE_SHIFT=6
++CONFIG_ARM_DMA_MEM_BUFFERABLE=y
++CONFIG_MULTI_IRQ_HANDLER=y
++# CONFIG_ARM_ERRATA_430973 is not set
++# CONFIG_ARM_ERRATA_643719 is not set
++# CONFIG_ARM_ERRATA_720789 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_ARM_ERRATA_775420 is not set
++# CONFIG_ARM_ERRATA_798181 is not set
++# CONFIG_ARM_ERRATA_773022 is not set
++
++#
++# Bus support
++#
++CONFIG_ARM_AMBA=y
++# CONFIG_PCI is not set
++# 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=y
++# CONFIG_SCHED_SMT is not set
++CONFIG_DISABLE_CPU_SCHED_DOMAIN_BALANCE=y
++CONFIG_SCHED_HMP=y
++# CONFIG_SCHED_HMP_PRIO_FILTER is not set
++CONFIG_HMP_FAST_CPU_MASK=""
++CONFIG_HMP_SLOW_CPU_MASK=""
++CONFIG_HMP_VARIABLE_SCALE=y
++# CONFIG_HMP_FREQUENCY_INVARIANT_SCALE is not set
++# CONFIG_SCHED_HMP_LITTLE_PACKING is not set
++CONFIG_HAVE_ARM_ARCH_TIMER=y
++# CONFIG_MCPM is not set
++# CONFIG_BIG_LITTLE is not set
++CONFIG_VMSPLIT_3G=y
++# CONFIG_VMSPLIT_2G is not set
++# CONFIG_VMSPLIT_1G is not set
++CONFIG_PAGE_OFFSET=0xC0000000
++CONFIG_NR_CPUS=4
++CONFIG_HOTPLUG_CPU=y
++# CONFIG_ARM_PSCI is not set
++CONFIG_ARCH_NR_GPIO=0
++CONFIG_PREEMPT_NONE=y
++# CONFIG_PREEMPT_VOLUNTARY is not set
++# CONFIG_PREEMPT is not set
++CONFIG_HZ_FIXED=0
++CONFIG_HZ_100=y
++# CONFIG_HZ_200 is not set
++# CONFIG_HZ_250 is not set
++# CONFIG_HZ_300 is not set
++# CONFIG_HZ_500 is not set
++# CONFIG_HZ_1000 is not set
++CONFIG_HZ=100
++# CONFIG_SCHED_HRTICK is not set
++# CONFIG_THUMB2_KERNEL is not set
++CONFIG_AEABI=y
++# CONFIG_OABI_COMPAT is not set
++# 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_ARCH_WANT_GENERAL_HUGETLB=y
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_HAVE_MEMBLOCK=y
++CONFIG_NO_BOOTMEM=y
++CONFIG_MEMORY_ISOLATION=y
++# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=4
++CONFIG_COMPACTION=y
++CONFIG_MIGRATION=y
++# CONFIG_PHYS_ADDR_T_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_BOUNCE=y
++# CONFIG_KSM is not set
++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
++# CONFIG_CLEANCACHE is not set
++# CONFIG_FRONTSWAP is not set
++CONFIG_CMA=y
++# CONFIG_CMA_DEBUG is not set
++CONFIG_CMA_AREAS=7
++# CONFIG_ZPOOL is not set
++# CONFIG_ZBUD is not set
++# CONFIG_ZSMALLOC 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_SWIOTLB=y
++CONFIG_IOMMU_HELPER=y
++# CONFIG_XEN is not set
++# CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART is not set
++
++#
++# Boot options
++#
++CONFIG_USE_OF=y
++CONFIG_ATAGS=y
++# CONFIG_DEPRECATED_PARAM_STRUCT is not set
++# CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE is not set
++CONFIG_ZBOOT_ROM_TEXT=0
++CONFIG_ZBOOT_ROM_BSS=0
++CONFIG_ARM_APPENDED_DTB=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_KEXEC is not set
++# CONFIG_CRASH_DUMP is not set
++CONFIG_AUTO_ZRELADDR=y
++
++#
++# CPU Power Management
++#
++
++#
++# CPU Frequency scaling
++#
++CONFIG_CPU_FREQ=y
++CONFIG_CPU_FREQ_GOV_COMMON=y
++CONFIG_CPU_FREQ_STAT=y
++# CONFIG_CPU_FREQ_STAT_DETAILS is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
++CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
++# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE is not set
++CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
++CONFIG_CPU_FREQ_GOV_POWERSAVE=y
++CONFIG_CPU_FREQ_GOV_USERSPACE=y
++CONFIG_CPU_FREQ_GOV_ONDEMAND=y
++CONFIG_CPU_FREQ_GOV_INTERACTIVE=y
++CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
++CONFIG_CPUFREQ_DT=y
++
++#
++# ARM CPU frequency scaling drivers
++#
++# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set
++
++#
++# CPU Idle
++#
++CONFIG_CPU_IDLE=y
++CONFIG_CPU_IDLE_GOV_LADDER=y
++CONFIG_CPU_IDLE_GOV_MENU=y
++
++#
++# ARM CPU Idle Drivers
++#
++CONFIG_ARM_HI3519V101_CPUIDLE=y
++# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++CONFIG_VFP=y
++CONFIG_VFPv3=y
++CONFIG_NEON=y
++CONFIG_KERNEL_MODE_NEON=y
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
++CONFIG_BINFMT_SCRIPT=y
++# CONFIG_HAVE_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
++CONFIG_COREDUMP=y
++
++#
++# Power management options
++#
++CONFIG_SUSPEND=y
++CONFIG_SUSPEND_FREEZER=y
++CONFIG_WAKELOCK=y
++CONFIG_HIBERNATE_CALLBACKS=y
++CONFIG_HISI_SNAPSHOT_BOOT=y
++# CONFIG_DEFAULT_MTD is not set
++CONFIG_DEFAULT_DDR=y
++CONFIG_SNAPSHOT_BUF_START=0x8a000000
++CONFIG_SNAPSHOT_BUF_SIZE=0x4000000
++CONFIG_HIBERNATION=y
++CONFIG_GZIP_COMPRESS=y
++CONFIG_PM_STD_PARTITION=""
++CONFIG_PM_SLEEP=y
++CONFIG_PM_SLEEP_SMP=y
++# CONFIG_PM_AUTOSLEEP is not set
++# CONFIG_PM_WAKELOCKS is not set
++# CONFIG_PM_RUNTIME is not set
++CONFIG_PM=y
++# CONFIG_PM_DEBUG is not set
++# CONFIG_APM_EMULATION is not set
++CONFIG_PM_OPP=y
++CONFIG_PM_CLK=y
++# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set
++CONFIG_CPU_PM=y
++# CONFIG_SUSPEND_TIME is not set
++CONFIG_ARCH_SUSPEND_POSSIBLE=y
++CONFIG_ARM_CPU_SUSPEND=y
++CONFIG_ARCH_HIBERNATION_POSSIBLE=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_NET_IP_TUNNEL=m
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_NET_IPVTI is not set
++# CONFIG_NET_UDP_TUNNEL is not set
++# CONFIG_NET_FOU is not set
++# CONFIG_GENEVE 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=y
++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=y
++# 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_VTI 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_ANDROID_PARANOID_NETWORK is not set
++CONFIG_NET_ACTIVITY_STATS=y
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NET_PTP_CLASSIFY 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_NF_TABLES is not set
++# CONFIG_NETFILTER_XTABLES is not set
++# CONFIG_IP_SET is not set
++# CONFIG_IP_VS is not set
++
++#
++# IP: Netfilter Configuration
++#
++# CONFIG_NF_DEFRAG_IPV4 is not set
++# CONFIG_NF_LOG_ARP is not set
++# CONFIG_NF_LOG_IPV4 is not set
++# CONFIG_NF_REJECT_IPV4 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_NF_REJECT_IPV6 is not set
++# CONFIG_NF_LOG_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_HAVE_NET_DSA=y
++# 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_PHONET is not set
++# CONFIG_6LOWPAN 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_VSOCKETS is not set
++# CONFIG_NETLINK_MMAP is not set
++# CONFIG_NETLINK_DIAG is not set
++# CONFIG_NET_MPLS_GSO is not set
++# CONFIG_HSR is not set
++CONFIG_RPS=y
++CONFIG_RFS_ACCEL=y
++CONFIG_XPS=y
++# CONFIG_CGROUP_NET_PRIO is not set
++# CONFIG_CGROUP_NET_CLASSID is not set
++CONFIG_NET_RX_BUSY_POLL=y
++CONFIG_BQL=y
++# CONFIG_BPF_JIT is not set
++CONFIG_NET_FLOW_LIMIT=y
++
++#
++# 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 is not set
++CONFIG_DEVTMPFS=y
++CONFIG_DEVTMPFS_MOUNT=y
++CONFIG_STANDALONE=y
++# CONFIG_PREVENT_FIRMWARE_BUILD is not set
++CONFIG_FW_LOADER=y
++# CONFIG_FIRMWARE_IN_KERNEL is not set
++CONFIG_EXTRA_FIRMWARE=""
++# CONFIG_FW_LOADER_USER_HELPER_FALLBACK is not set
++CONFIG_ALLOW_DEV_COREDUMP=y
++# 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_HAVE_CPU_AUTOPROBE is not set
++CONFIG_REGMAP=y
++CONFIG_REGMAP_MMIO=y
++CONFIG_DMA_SHARED_BUFFER=y
++# CONFIG_FENCE_TRACE is not set
++CONFIG_DMA_CMA=y
++
++#
++# Default contiguous memory area size:
++#
++CONFIG_CMA_SIZE_MBYTES=16
++CONFIG_CMA_SIZE_SEL_MBYTES=y
++# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set
++# CONFIG_CMA_SIZE_SEL_MIN is not set
++# CONFIG_CMA_SIZE_SEL_MAX is not set
++CONFIG_CMA_ALIGNMENT=8
++
++#
++# Bus devices
++#
++# CONFIG_BRCMSTB_GISB_ARB is not set
++CONFIG_ARM_CCI=y
++# CONFIG_VEXPRESS_CONFIG 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=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_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
++CONFIG_HIFMC=y
++CONFIG_HIFMC_SPI_NAND=y
++# CONFIG_HIFMC_NAND is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++# CONFIG_MTD_CFI is not set
++# CONFIG_MTD_JEDECPROBE is not set
++CONFIG_MTD_MAP_BANK_WIDTH_1=y
++CONFIG_MTD_MAP_BANK_WIDTH_2=y
++CONFIG_MTD_MAP_BANK_WIDTH_4=y
++# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
++CONFIG_MTD_CFI_I1=y
++CONFIG_MTD_CFI_I2=y
++# CONFIG_MTD_CFI_I4 is not set
++# CONFIG_MTD_CFI_I8 is not set
++# CONFIG_MTD_RAM is not set
++# CONFIG_MTD_ROM is not set
++# CONFIG_MTD_ABSENT is not set
++
++#
++# Mapping drivers for chip access
++#
++# CONFIG_MTD_COMPLEX_MAPPINGS is not set
++# CONFIG_MTD_PLATRAM is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_DATAFLASH is not set
++# CONFIG_MTD_M25P80 is not set
++# CONFIG_MTD_SST25L is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_PHRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++# CONFIG_MTD_BLOCK2MTD is not set
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOCG3 is not set
++CONFIG_MTD_NAND_IDS=y
++CONFIG_MTD_NAND_ECC=y
++# CONFIG_MTD_NAND_ECC_SMC is not set
++CONFIG_MTD_NAND=y
++# CONFIG_MTD_NAND_ECC_BCH is not set
++# CONFIG_MTD_SM_COMMON is not set
++# CONFIG_MTD_NAND_DENALI is not set
++# CONFIG_MTD_NAND_GPIO is not set
++# CONFIG_MTD_NAND_OMAP_BCH_BUILD is not set
++# CONFIG_MTD_NAND_DISKONCHIP is not set
++# CONFIG_MTD_NAND_DOCG4 is not set
++# CONFIG_MTD_NAND_NANDSIM is not set
++# CONFIG_MTD_NAND_PLATFORM is not set
++# CONFIG_HISI_NAND_FS_MAY_NO_YAFFS2 is not set
++# CONFIG_HISI_NAND_ECC_STATUS_REPORT is not set
++# CONFIG_HIFMC100_NAND is not set
++CONFIG_HIFMC100_SPI_NAND=y
++CONFIG_SPI_NAND_MAX_CHIP_NUM=1
++# CONFIG_HIFMC100_HARDWARE_PAGESIZE_ECC is not set
++CONFIG_HIFMC100_AUTO_PAGESIZE_ECC=y
++# CONFIG_HIFMC100_PAGESIZE_AUTO_ECC_NONE is not set
++# CONFIG_MTD_ONENAND is not set
++
++#
++# LPDDR & LPDDR2 PCM memory drivers
++#
++# CONFIG_MTD_LPDDR is not set
++# CONFIG_MTD_LPDDR2_NVM is not set
++CONFIG_MTD_SPI_NOR=y
++# CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set
++CONFIG_SPI_HISI_SFC=y
++CONFIG_CLOSE_SPI_8PIN_4IO=y
++CONFIG_HISI_SPI_BLOCK_PROTECT=y
++# CONFIG_MTD_UBI is not set
++CONFIG_DTC=y
++CONFIG_OF=y
++
++#
++# Device Tree and Open Firmware support
++#
++# 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_NET=y
++CONFIG_OF_MDIO=y
++CONFIG_OF_MTD=y
++CONFIG_OF_RESERVED_MEM=y
++CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
++# CONFIG_PARPORT is not set
++CONFIG_BLK_DEV=y
++# CONFIG_BLK_DEV_NULL_BLK is not set
++# CONFIG_BLK_DEV_COW_COMMON is not set
++# CONFIG_BLK_DEV_LOOP 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=65536
++# 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_DUMMY_IRQ 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_UID_STAT is not set
++# CONFIG_BMP085_I2C is not set
++# CONFIG_BMP085_SPI is not set
++# CONFIG_USB_SWITCH_FSA9480 is not set
++# CONFIG_LATTICE_ECP3_CONFIG is not set
++# CONFIG_SRAM is not set
++# CONFIG_C2PORT is not set
++
++#
++# EEPROM support
++#
++# CONFIG_EEPROM_AT24 is not set
++# CONFIG_EEPROM_AT25 is not set
++# CONFIG_EEPROM_LEGACY is not set
++# CONFIG_EEPROM_MAX6875 is not set
++# CONFIG_EEPROM_93CX6 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
++
++#
++# Intel MIC Bus Driver
++#
++
++#
++# Intel MIC Host Driver
++#
++
++#
++# Intel MIC Card Driver
++#
++# CONFIG_ECHO is not set
++# CONFIG_CXL_BASE is not set
++
++#
++# hisi 'himm/himd.l/himc'support
++#
++CONFIG_HISI_REG=y
++
++#
++# SCSI device support
++#
++CONFIG_SCSI_MOD=y
++# CONFIG_RAID_ATTRS is not set
++CONFIG_SCSI=y
++CONFIG_SCSI_DMA=y
++# CONFIG_SCSI_NETLINK is not set
++# CONFIG_SCSI_MQ_DEFAULT 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_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 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_NET_CORE=y
++# CONFIG_BONDING is not set
++# CONFIG_DUMMY is not set
++# CONFIG_EQUALIZER is not set
++# CONFIG_NET_TEAM is not set
++# CONFIG_MACVLAN is not set
++# CONFIG_VXLAN is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_TUN is not set
++# CONFIG_VETH is not set
++# CONFIG_NLMON is not set
++
++#
++# 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_NET_DSA_MV88E6171 is not set
++# CONFIG_NET_DSA_BCM_SF2 is not set
++CONFIG_ETHERNET=y
++# CONFIG_ALTERA_TSE is not set
++# CONFIG_NET_XGENE is not set
++# CONFIG_NET_VENDOR_ARC is not set
++# CONFIG_NET_CADENCE is not set
++# CONFIG_NET_VENDOR_BROADCOM is not set
++# CONFIG_NET_VENDOR_CIRRUS is not set
++# CONFIG_DM9000 is not set
++# CONFIG_DNET is not set
++# CONFIG_NET_VENDOR_FARADAY is not set
++CONFIG_NET_VENDOR_HISILICON=y
++# CONFIG_HIX5HD2_GMAC is not set
++# CONFIG_HISI_FEMAC is not set
++CONFIG_HIETH_GMAC=y
++CONFIG_HIGMAC_DESC_4WORD=y
++CONFIG_HIGMAC_RXCSUM=y
++CONFIG_RX_FLOW_CTRL_SUPPORT=y
++CONFIG_TX_FLOW_CTRL_SUPPORT=y
++CONFIG_TX_FLOW_CTRL_PAUSE_TIME=0xFFFF
++CONFIG_TX_FLOW_CTRL_PAUSE_INTERVAL=0xFFFF
++CONFIG_TX_FLOW_CTRL_ACTIVE_THRESHOLD=16
++CONFIG_TX_FLOW_CTRL_DEACTIVE_THRESHOLD=32
++# CONFIG_HIETH_SWITCH_FABRIC is not set
++# CONFIG_NET_VENDOR_INTEL is not set
++# CONFIG_NET_VENDOR_MARVELL is not set
++# CONFIG_NET_VENDOR_MICREL is not set
++# CONFIG_NET_VENDOR_MICROCHIP is not set
++# CONFIG_NET_VENDOR_NATSEMI is not set
++# CONFIG_ETHOC is not set
++# CONFIG_NET_VENDOR_QUALCOMM is not set
++# CONFIG_NET_VENDOR_SAMSUNG is not set
++# CONFIG_NET_VENDOR_SEEQ is not set
++# CONFIG_NET_VENDOR_SMSC is not set
++# CONFIG_NET_VENDOR_STMICRO is not set
++# CONFIG_NET_VENDOR_VIA is not set
++# CONFIG_NET_VENDOR_WIZNET is not set
++CONFIG_PHYLIB=y
++
++#
++# MII PHY device drivers
++#
++# CONFIG_AT803X_PHY is not set
++# CONFIG_AMD_PHY is not set
++# CONFIG_AMD_XGBE_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 is not set
++# CONFIG_BROADCOM_PHY is not set
++# CONFIG_BCM7XXX_PHY is not set
++# CONFIG_BCM87XX_PHY is not set
++# CONFIG_ICPLUS_PHY is not set
++# CONFIG_REALTEK_PHY is not set
++# CONFIG_NATIONAL_PHY is not set
++# CONFIG_STE10XP is not set
++# CONFIG_LSI_ET1011C_PHY is not set
++# CONFIG_MICREL_PHY is not set
++# CONFIG_FIXED_PHY is not set
++# CONFIG_MDIO_BITBANG is not set
++# CONFIG_MDIO_BUS_MUX_GPIO is not set
++# CONFIG_MDIO_BUS_MUX_MMIOREG is not set
++# CONFIG_MDIO_BCM_UNIMAC is not set
++# CONFIG_MDIO_HISI_FEMAC is not set
++CONFIG_MDIO_HISI_GEMAC=y
++# CONFIG_MICREL_KS8995MA is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++CONFIG_USB_NET_DRIVERS=y
++# 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_RTL8152 is not set
++# CONFIG_USB_USBNET is not set
++# CONFIG_USB_IPHETH is not set
++# CONFIG_WLAN is not set
++
++#
++# Enable WiMAX (Networking options) to see the WiMAX drivers
++#
++# CONFIG_WAN is not set
++# CONFIG_ISDN is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
++# CONFIG_INPUT_POLLDEV is not set
++# CONFIG_INPUT_SPARSEKMAP is not set
++# CONFIG_INPUT_MATRIXKMAP is not set
++
++#
++# Userland interfaces
++#
++CONFIG_INPUT_MOUSEDEV=y
++CONFIG_INPUT_MOUSEDEV_PSAUX=y
++CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
++CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
++# CONFIG_INPUT_JOYDEV is not set
++CONFIG_INPUT_EVDEV=y
++# CONFIG_INPUT_EVBUG is not set
++# CONFIG_INPUT_KEYRESET is not set
++# CONFIG_INPUT_KEYCOMBO is not set
++
++#
++# Input Device Drivers
++#
++CONFIG_INPUT_KEYBOARD=y
++# CONFIG_KEYBOARD_ADP5588 is not set
++# CONFIG_KEYBOARD_ADP5589 is not set
++CONFIG_KEYBOARD_ATKBD=y
++# CONFIG_KEYBOARD_QT1070 is not set
++# CONFIG_KEYBOARD_QT2160 is not set
++# CONFIG_KEYBOARD_LKKBD is not set
++# CONFIG_KEYBOARD_GPIO is not set
++# CONFIG_KEYBOARD_GPIO_POLLED is not set
++# 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 is not set
++# CONFIG_KEYBOARD_CAP1106 is not set
++CONFIG_INPUT_MOUSE=y
++CONFIG_MOUSE_PS2=y
++CONFIG_MOUSE_PS2_ALPS=y
++CONFIG_MOUSE_PS2_LOGIPS2PP=y
++CONFIG_MOUSE_PS2_SYNAPTICS=y
++CONFIG_MOUSE_PS2_CYPRESS=y
++CONFIG_MOUSE_PS2_TRACKPOINT=y
++# CONFIG_MOUSE_PS2_ELANTECH is not set
++# CONFIG_MOUSE_PS2_SENTELIC is not set
++# CONFIG_MOUSE_PS2_TOUCHKIT is not set
++# CONFIG_MOUSE_SERIAL is not set
++# CONFIG_MOUSE_APPLETOUCH is not set
++# CONFIG_MOUSE_BCM5974 is not set
++# CONFIG_MOUSE_CYAPA is not set
++# CONFIG_MOUSE_VSXXXAA is not set
++# CONFIG_MOUSE_GPIO is not set
++# CONFIG_MOUSE_SYNAPTICS_I2C is not set
++# CONFIG_MOUSE_SYNAPTICS_USB is not set
++# CONFIG_INPUT_JOYSTICK is not set
++# CONFIG_INPUT_TABLET is not set
++# CONFIG_INPUT_TOUCHSCREEN is not set
++# CONFIG_INPUT_MISC is not set
++
++#
++# Hardware I/O ports
++#
++CONFIG_SERIO=y
++CONFIG_SERIO_SERPORT=y
++# CONFIG_SERIO_AMBAKMI is not set
++CONFIG_SERIO_LIBPS2=y
++# CONFIG_SERIO_RAW is not set
++# CONFIG_SERIO_ALTERA_PS2 is not set
++# CONFIG_SERIO_PS2MULT is not set
++# CONFIG_SERIO_ARC_PS2 is not set
++# CONFIG_SERIO_APBPS2 is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++CONFIG_TTY=y
++CONFIG_VT=y
++CONFIG_CONSOLE_TRANSLATIONS=y
++CONFIG_VT_CONSOLE=y
++CONFIG_VT_CONSOLE_SLEEP=y
++CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
++CONFIG_UNIX98_PTYS=y
++# CONFIG_DEVPTS_MULTIPLE_INSTANCES 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_DEVMEM=y
++CONFIG_DEVKMEM=y
++
++#
++# Serial drivers
++#
++CONFIG_SERIAL_EARLYCON=y
++# CONFIG_SERIAL_8250 is not set
++
++#
++# Non-8250 serial port support
++#
++# CONFIG_SERIAL_AMBA_PL010 is not set
++CONFIG_SERIAL_AMBA_PL011=y
++CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
++# CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST is not set
++# 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_SC16IS7XX is not set
++# CONFIG_SERIAL_ALTERA_JTAGUART is not set
++# CONFIG_SERIAL_ALTERA_UART is not set
++# CONFIG_SERIAL_IFX6X60 is not set
++# CONFIG_SERIAL_XILINX_PS_UART is not set
++# CONFIG_SERIAL_ARC is not set
++# CONFIG_SERIAL_FSL_LPUART is not set
++# CONFIG_SERIAL_ST_ASC is not set
++# CONFIG_HVC_DCC is not set
++# CONFIG_IPMI_HANDLER is not set
++# CONFIG_HW_RANDOM is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++# CONFIG_DCC_TTY is not set
++# CONFIG_XILLYBUS is not set
++
++#
++# I2C support
++#
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++# CONFIG_I2C_COMPAT is not set
++CONFIG_I2C_CHARDEV=y
++CONFIG_I2C_MUX=y
++
++#
++# Multiplexer I2C Chip support
++#
++# CONFIG_I2C_ARB_GPIO_CHALLENGE is not set
++# CONFIG_I2C_MUX_GPIO is not set
++# CONFIG_I2C_MUX_PCA9541 is not set
++# CONFIG_I2C_MUX_PCA954x is not set
++# CONFIG_I2C_HELPER_AUTO is not set
++# CONFIG_I2C_SMBUS is not set
++
++#
++# I2C Algorithms
++#
++# CONFIG_I2C_ALGOBIT is not set
++# CONFIG_I2C_ALGOPCF is not set
++# CONFIG_I2C_ALGOPCA is not set
++
++#
++# I2C Hardware Bus support
++#
++
++#
++# I2C system bus drivers (mostly embedded / system-on-chip)
++#
++# CONFIG_I2C_CBUS_GPIO is not set
++# CONFIG_I2C_DESIGNWARE_PLATFORM is not set
++# CONFIG_I2C_GPIO is not set
++# CONFIG_I2C_HIBVT is not set
++CONFIG_I2C_HISI_V110=y
++# CONFIG_I2C_NOMADIK 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_RK3X 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_ROBOTFUZZ_OSIF 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_CADENCE is not set
++# CONFIG_SPI_GPIO is not set
++# CONFIG_SPI_FSL_SPI is not set
++# CONFIG_SPI_OC_TINY is not set
++CONFIG_SPI_PL022=y
++# CONFIG_SPI_PXA2XX_PCI is not set
++# CONFIG_SPI_ROCKCHIP 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=y
++# CONFIG_SPI_TLE62X0 is not set
++# CONFIG_SPMI is not set
++# CONFIG_HSI is not set
++
++#
++# PPS support
++#
++# CONFIG_PPS is not set
++
++#
++# PPS generators support
++#
++
++#
++# PTP clock support
++#
++# CONFIG_PTP_1588_CLOCK is not set
++
++#
++# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
++#
++CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
++CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
++CONFIG_GPIOLIB=y
++CONFIG_GPIO_DEVRES=y
++CONFIG_OF_GPIO=y
++CONFIG_GPIOLIB_IRQCHIP=y
++# CONFIG_DEBUG_GPIO is not set
++CONFIG_GPIO_SYSFS=y
++
++#
++# Memory mapped GPIO drivers:
++#
++# CONFIG_GPIO_GENERIC_PLATFORM is not set
++# CONFIG_GPIO_DWAPB is not set
++# CONFIG_GPIO_EM is not set
++# CONFIG_GPIO_ZEVIO is not set
++CONFIG_GPIO_PL061=y
++# CONFIG_GPIO_SCH311X is not set
++# CONFIG_GPIO_SYSCON is not set
++# CONFIG_GPIO_GRGPIO is not set
++
++#
++# I2C GPIO expanders:
++#
++# CONFIG_GPIO_MAX7300 is not set
++# CONFIG_GPIO_MAX732X is not set
++# CONFIG_GPIO_PCA953X is not set
++# CONFIG_GPIO_PCF857X is not set
++# CONFIG_GPIO_SX150X is not set
++# CONFIG_GPIO_ADP5588 is not set
++# CONFIG_GPIO_ADNP is not set
++
++#
++# PCI GPIO expanders:
++#
++
++#
++# SPI GPIO expanders:
++#
++# CONFIG_GPIO_MAX7301 is not set
++# CONFIG_GPIO_MCP23S08 is not set
++# CONFIG_GPIO_MC33880 is not set
++# CONFIG_GPIO_74X164 is not set
++
++#
++# AC97 GPIO expanders:
++#
++
++#
++# LPC GPIO expanders:
++#
++
++#
++# MODULbus GPIO expanders:
++#
++
++#
++# USB GPIO expanders:
++#
++# CONFIG_W1 is not set
++CONFIG_POWER_SUPPLY=y
++# CONFIG_POWER_SUPPLY_DEBUG is not set
++# CONFIG_PDA_POWER is not set
++# CONFIG_TEST_POWER is not set
++# CONFIG_BATTERY_DS2780 is not set
++# CONFIG_BATTERY_DS2781 is not set
++# CONFIG_BATTERY_DS2782 is not set
++# CONFIG_BATTERY_SBS is not set
++# CONFIG_BATTERY_BQ27x00 is not set
++# CONFIG_BATTERY_MAX17040 is not set
++# CONFIG_BATTERY_MAX17042 is not set
++# CONFIG_CHARGER_MAX8903 is not set
++# CONFIG_CHARGER_LP8727 is not set
++# CONFIG_CHARGER_GPIO is not set
++# CONFIG_CHARGER_BQ2415X is not set
++# CONFIG_CHARGER_BQ24190 is not set
++# CONFIG_CHARGER_BQ24735 is not set
++# CONFIG_CHARGER_SMB347 is not set
++CONFIG_POWER_RESET=y
++# CONFIG_POWER_RESET_BRCMSTB is not set
++# CONFIG_POWER_RESET_GPIO is not set
++# CONFIG_POWER_RESET_GPIO_RESTART is not set
++CONFIG_POWER_RESET_HISI=y
++# CONFIG_POWER_RESET_LTC2952 is not set
++# CONFIG_POWER_RESET_RESTART is not set
++# CONFIG_POWER_RESET_VERSATILE is not set
++# CONFIG_POWER_RESET_SYSCON is not set
++# CONFIG_POWER_AVS is not set
++# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
++# CONFIG_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=y
++# CONFIG_MFD_AS3711 is not set
++# CONFIG_MFD_AS3722 is not set
++# CONFIG_PMIC_ADP5520 is not set
++# CONFIG_MFD_AAT2870_CORE is not set
++# CONFIG_MFD_BCM590XX is not set
++# CONFIG_MFD_AXP20X is not set
++# CONFIG_MFD_CROS_EC is not set
++# CONFIG_MFD_ASIC3 is not set
++# CONFIG_PMIC_DA903X is not set
++# CONFIG_MFD_DA9052_SPI is not set
++# CONFIG_MFD_DA9052_I2C is not set
++# CONFIG_MFD_DA9055 is not set
++# CONFIG_MFD_DA9063 is not set
++# CONFIG_MFD_MC13XXX_SPI is not set
++# CONFIG_MFD_MC13XXX_I2C is not set
++# CONFIG_MFD_HI6421_PMIC is not set
++CONFIG_MFD_HISI_FMC=y
++# CONFIG_HTC_EGPIO is not set
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_HTC_I2CPLD is not set
++# CONFIG_INTEL_SOC_PMIC is not set
++# CONFIG_MFD_KEMPLD is not set
++# CONFIG_MFD_88PM800 is not set
++# CONFIG_MFD_88PM805 is not set
++# CONFIG_MFD_88PM860X is not set
++# CONFIG_MFD_MAX14577 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_MENF21BMC is not set
++# CONFIG_EZX_PCAP is not set
++# CONFIG_MFD_VIPERBOARD is not set
++# CONFIG_MFD_RETU is not set
++# CONFIG_MFD_PCF50633 is not set
++# CONFIG_MFD_PM8921_CORE is not set
++# CONFIG_MFD_RTSX_USB is not set
++# CONFIG_MFD_RC5T583 is not set
++# CONFIG_MFD_RK808 is not set
++# CONFIG_MFD_RN5T618 is not set
++# CONFIG_MFD_SEC_CORE is not set
++# CONFIG_MFD_SI476X_CORE is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_MFD_SMSC is not set
++# CONFIG_ABX500_CORE is not set
++# CONFIG_MFD_STMPE is not set
++CONFIG_MFD_SYSCON=y
++# CONFIG_MFD_TI_AM335X_TSCADC is not set
++# CONFIG_MFD_LP3943 is not set
++# CONFIG_MFD_LP8788 is not set
++# CONFIG_MFD_PALMAS is not set
++# CONFIG_TPS6105X is not set
++# CONFIG_TPS65010 is not set
++# CONFIG_TPS6507X is not set
++# CONFIG_MFD_TPS65090 is not set
++# CONFIG_MFD_TPS65217 is not set
++# CONFIG_MFD_TPS65218 is not set
++# CONFIG_MFD_TPS6586X is not set
++# CONFIG_MFD_TPS65910 is not set
++# CONFIG_MFD_TPS65912 is not set
++# CONFIG_MFD_TPS65912_I2C is not set
++# CONFIG_MFD_TPS65912_SPI is not set
++# CONFIG_MFD_TPS80031 is not set
++# CONFIG_TWL4030_CORE is not set
++# CONFIG_TWL6040_CORE is not set
++# CONFIG_MFD_WL1273_CORE is not set
++# CONFIG_MFD_LM3533 is not set
++# CONFIG_MFD_TC3589X is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_MFD_T7L66XB is not set
++# CONFIG_MFD_TC6387XB is not set
++# CONFIG_MFD_TC6393XB is not set
++# CONFIG_MFD_ARIZONA_I2C is not set
++# CONFIG_MFD_ARIZONA_SPI is not set
++# CONFIG_MFD_WM8400 is not set
++# CONFIG_MFD_WM831X_I2C is not set
++# CONFIG_MFD_WM831X_SPI is not set
++# CONFIG_MFD_WM8350_I2C is not set
++# CONFIG_MFD_WM8994 is not set
++CONFIG_REGULATOR=y
++# CONFIG_REGULATOR_DEBUG is not set
++# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
++# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
++# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
++# CONFIG_REGULATOR_ACT8865 is not set
++# CONFIG_REGULATOR_AD5398 is not set
++# CONFIG_REGULATOR_ANATOP is not set
++# CONFIG_REGULATOR_DA9210 is not set
++# CONFIG_REGULATOR_DA9211 is not set
++# CONFIG_REGULATOR_FAN53555 is not set
++# CONFIG_REGULATOR_GPIO is not set
++# CONFIG_REGULATOR_ISL9305 is not set
++# CONFIG_REGULATOR_ISL6271A is not set
++# CONFIG_REGULATOR_LP3971 is not set
++# CONFIG_REGULATOR_LP3972 is not set
++# CONFIG_REGULATOR_LP872X is not set
++# CONFIG_REGULATOR_LP8755 is not set
++# CONFIG_REGULATOR_LTC3589 is not set
++# CONFIG_REGULATOR_MAX1586 is not set
++# CONFIG_REGULATOR_MAX8649 is not set
++# CONFIG_REGULATOR_MAX8660 is not set
++# CONFIG_REGULATOR_MAX8952 is not set
++# CONFIG_REGULATOR_MAX8973 is not set
++# CONFIG_REGULATOR_PFUZE100 is not set
++# CONFIG_REGULATOR_TPS51632 is not set
++# CONFIG_REGULATOR_TPS62360 is not set
++# CONFIG_REGULATOR_TPS65023 is not set
++# CONFIG_REGULATOR_TPS6507X is not set
++# CONFIG_REGULATOR_TPS6524X is not set
++CONFIG_MEDIA_SUPPORT=m
++
++#
++# Multimedia core support
++#
++CONFIG_MEDIA_CAMERA_SUPPORT=y
++# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set
++# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set
++# CONFIG_MEDIA_RADIO_SUPPORT is not set
++# CONFIG_MEDIA_SDR_SUPPORT is not set
++# CONFIG_MEDIA_RC_SUPPORT is not set
++# CONFIG_MEDIA_CONTROLLER is not set
++CONFIG_VIDEO_DEV=m
++CONFIG_VIDEO_V4L2=m
++# CONFIG_VIDEO_ADV_DEBUG is not set
++# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
++CONFIG_VIDEOBUF2_CORE=m
++CONFIG_VIDEOBUF2_MEMOPS=m
++CONFIG_VIDEOBUF2_VMALLOC=m
++# CONFIG_TTPCI_EEPROM is not set
++
++#
++# Media drivers
++#
++# CONFIG_MEDIA_USB_SUPPORT is not set
++# CONFIG_V4L_PLATFORM_DRIVERS is not set
++# CONFIG_V4L_MEM2MEM_DRIVERS is not set
++# CONFIG_V4L_TEST_DRIVERS is not set
++
++#
++# Supported MMC/SDIO adapters
++#
++# CONFIG_CYPRESS_FIRMWARE is not set
++
++#
++# Media ancillary drivers (tuners, sensors, i2c, frontends)
++#
++CONFIG_MEDIA_SUBDRV_AUTOSELECT=y
++
++#
++# Audio decoders, processors and mixers
++#
++
++#
++# RDS decoders
++#
++
++#
++# Video decoders
++#
++
++#
++# Video and audio decoders
++#
++
++#
++# Video encoders
++#
++
++#
++# Camera sensor devices
++#
++
++#
++# Flash devices
++#
++
++#
++# Video improvement chips
++#
++
++#
++# Audio/Video compression chips
++#
++
++#
++# Miscellaneous helper chips
++#
++
++#
++# Sensors used on soc_camera driver
++#
++
++#
++# Tools to develop new frontends
++#
++# CONFIG_DVB_DUMMY_FE is not set
++
++#
++# Graphics support
++#
++# CONFIG_IMX_IPUV3_CORE is not set
++
++#
++# Direct Rendering Manager
++#
++# CONFIG_DRM is not set
++
++#
++# Frame buffer Devices
++#
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++CONFIG_FB_CMDLINE=y
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++# CONFIG_FB_CFB_FILLRECT is not set
++# CONFIG_FB_CFB_COPYAREA is not set
++# CONFIG_FB_CFB_IMAGEBLIT is not set
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# 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_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_ARMCLCD is not set
++# CONFIG_FB_OPENCORES is not set
++# CONFIG_FB_S1D13XXX is not set
++# CONFIG_FB_SMSCUFX is not set
++# CONFIG_FB_UDL is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_BROADSHEET is not set
++# CONFIG_FB_AUO_K190X is not set
++# CONFIG_FB_SIMPLE is not set
++# CONFIG_FB_SSD1307 is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++# CONFIG_VGASTATE is not set
++
++#
++# Console display driver support
++#
++CONFIG_DUMMY_CONSOLE=y
++# CONFIG_FRAMEBUFFER_CONSOLE is not set
++# CONFIG_LOGO is not set
++# CONFIG_SOUND is not set
++
++#
++# HID support
++#
++CONFIG_HID=y
++# CONFIG_HID_BATTERY_STRENGTH is not set
++# CONFIG_HIDRAW is not set
++# CONFIG_UHID is not set
++CONFIG_HID_GENERIC=y
++
++#
++# Special HID drivers
++#
++CONFIG_HID_A4TECH=y
++# CONFIG_HID_ACRUX is not set
++CONFIG_HID_APPLE=y
++# CONFIG_HID_APPLEIR is not set
++# CONFIG_HID_AUREAL is not set
++CONFIG_HID_BELKIN=y
++CONFIG_HID_CHERRY=y
++CONFIG_HID_CHICONY=y
++# CONFIG_HID_CP2112 is not set
++CONFIG_HID_CYPRESS=y
++# CONFIG_HID_DRAGONRISE is not set
++# CONFIG_HID_EMS_FF is not set
++# CONFIG_HID_ELECOM is not set
++# CONFIG_HID_ELO is not set
++CONFIG_HID_EZKEY=y
++# CONFIG_HID_HOLTEK is not set
++# CONFIG_HID_HUION 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_ICADE is not set
++# CONFIG_HID_TWINHAN is not set
++CONFIG_HID_KENSINGTON=y
++# CONFIG_HID_LCPOWER is not set
++# CONFIG_HID_LENOVO is not set
++CONFIG_HID_LOGITECH=y
++# CONFIG_HID_LOGITECH_HIDPP is not set
++# CONFIG_LOGITECH_FF is not set
++# CONFIG_LOGIRUMBLEPAD2_FF is not set
++# CONFIG_LOGIG940_FF is not set
++# CONFIG_LOGIWHEELS_FF is not set
++# CONFIG_HID_MAGICMOUSE is not set
++CONFIG_HID_MICROSOFT=y
++CONFIG_HID_MONTEREY=y
++# 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_PENMOUNT is not set
++# CONFIG_HID_PETALYNX is not set
++# CONFIG_HID_PICOLCD is not set
++# CONFIG_HID_PRIMAX is not set
++# CONFIG_HID_ROCCAT is not set
++# CONFIG_HID_SAITEK is not set
++# CONFIG_HID_SAMSUNG is not set
++# CONFIG_HID_SPEEDLINK is not set
++# CONFIG_HID_STEELSERIES is not set
++# CONFIG_HID_SUNPLUS is not set
++# CONFIG_HID_RMI 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_XINMO is not set
++# CONFIG_HID_ZEROPLUS is not set
++# CONFIG_HID_ZYDACRON is not set
++# CONFIG_HID_SENSOR_HUB is not set
++
++#
++# USB HID support
++#
++CONFIG_USB_HID=y
++# CONFIG_HID_PID is not set
++# CONFIG_USB_HIDDEV is not set
++
++#
++# I2C HID support
++#
++# CONFIG_I2C_HID is not set
++CONFIG_USB_OHCI_LITTLE_ENDIAN=y
++CONFIG_USB_SUPPORT=y
++CONFIG_USB_COMMON=y
++CONFIG_USB_ARCH_HAS_HCD=y
++CONFIG_USB=y
++# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
++
++#
++# Miscellaneous USB options
++#
++CONFIG_USB_DEFAULT_PERSIST=y
++# CONFIG_USB_DYNAMIC_MINORS is not set
++# CONFIG_USB_OTG_WHITELIST is not set
++# CONFIG_USB_OTG_FSM is not set
++# CONFIG_USB_MON is not set
++# CONFIG_USB_WUSB_CBAF is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_C67X00_HCD is not set
++CONFIG_USB_XHCI_HCD=y
++CONFIG_USB_XHCI_PLATFORM=y
++CONFIG_USB_XHCI_HISILICON=y
++CONFIG_USB_EHCI_HCD=y
++# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
++CONFIG_USB_EHCI_TT_NEWSCHED=y
++CONFIG_USB_EHCI_HCD_PLATFORM=y
++# 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_FUSBH200_HCD is not set
++# CONFIG_USB_FOTG210_HCD is not set
++# CONFIG_USB_MAX3421_HCD is not set
++CONFIG_USB_OHCI_HCD=y
++CONFIG_USB_OHCI_HCD_PLATFORM=y
++# CONFIG_USB_SL811_HCD is not set
++# CONFIG_USB_R8A66597_HCD is not set
++# CONFIG_USB_HCD_TEST_MODE is not set
++
++#
++# USB Device Class drivers
++#
++# CONFIG_USB_ACM is not set
++# CONFIG_USB_PRINTER is not set
++# CONFIG_USB_WDM is not set
++# CONFIG_USB_TMC is not set
++
++#
++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
++#
++
++#
++# also be needed; see USB_STORAGE Help for more info
++#
++CONFIG_USB_STORAGE=y
++# CONFIG_USB_STORAGE_DEBUG is not set
++# CONFIG_USB_STORAGE_REALTEK is not set
++# CONFIG_USB_STORAGE_DATAFAB is not set
++# CONFIG_USB_STORAGE_FREECOM is not set
++# CONFIG_USB_STORAGE_ISD200 is not set
++# CONFIG_USB_STORAGE_USBAT is not set
++# CONFIG_USB_STORAGE_SDDR09 is not set
++# CONFIG_USB_STORAGE_SDDR55 is not set
++# CONFIG_USB_STORAGE_JUMPSHOT is not set
++# CONFIG_USB_STORAGE_ALAUDA is not set
++# CONFIG_USB_STORAGE_ONETOUCH is not set
++# CONFIG_USB_STORAGE_KARMA is not set
++# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
++# CONFIG_USB_STORAGE_ENE_UB6250 is not set
++# CONFIG_USB_UAS is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++# CONFIG_USBIP_CORE is not set
++# CONFIG_USB_MUSB_HDRC is not set
++# CONFIG_USB_DWC3 is not set
++# CONFIG_USB_DWC2 is not set
++# CONFIG_USB_CHIPIDEA is not set
++
++#
++# USB port drivers
++#
++# CONFIG_USB_SERIAL is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
++# CONFIG_USB_SEVSEG is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
++# CONFIG_USB_APPLEDISPLAY is not set
++# CONFIG_USB_SISUSBVGA is not set
++# CONFIG_USB_LD is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
++# CONFIG_USB_IOWARRIOR is not set
++# CONFIG_USB_TEST is not set
++# CONFIG_USB_EHSET_TEST_FIXTURE is not set
++# CONFIG_USB_ISIGHTFW is not set
++# CONFIG_USB_YUREX is not set
++# CONFIG_USB_EZUSB_FX2 is not set
++# CONFIG_USB_HSIC_USB3503 is not set
++# CONFIG_USB_LINK_LAYER_TEST is not set
++
++#
++# USB Physical Layer drivers
++#
++# CONFIG_USB_PHY is not set
++# CONFIG_USB_OTG_WAKELOCK is not set
++# CONFIG_NOP_USB_XCEIV is not set
++# CONFIG_AM335X_PHY_USB is not set
++# CONFIG_USB_GPIO_VBUS is not set
++# CONFIG_USB_ISP1301 is not set
++# CONFIG_USB_ULPI is not set
++CONFIG_USB_GADGET=y
++# CONFIG_USB_GADGET_DEBUG is not set
++# CONFIG_USB_GADGET_DEBUG_FILES is not set
++CONFIG_USB_GADGET_VBUS_DRAW=2
++CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2
++
++#
++# USB Peripheral Controller
++#
++# CONFIG_USB_FUSB300 is not set
++# CONFIG_USB_FOTG210_UDC is not set
++# CONFIG_USB_GR_UDC is not set
++# CONFIG_USB_R8A66597 is not set
++# CONFIG_USB_PXA27X is not set
++# CONFIG_USB_MV_UDC is not set
++CONFIG_HIUSB_DEVICE2_0=y
++CONFIG_USB_HISI_UDC=m
++# CONFIG_USB_AUTO_SWITCH is not set
++# CONFIG_HIUSB_DEVICE3_0 is not set
++# CONFIG_USB_MV_U3D is not set
++# CONFIG_USB_M66592 is not set
++# CONFIG_USB_NET2272 is not set
++# CONFIG_USB_GADGET_XILINX is not set
++# CONFIG_USB_DUMMY_HCD is not set
++CONFIG_USB_LIBCOMPOSITE=m
++CONFIG_USB_F_ACM=m
++CONFIG_USB_U_SERIAL=m
++CONFIG_USB_U_ETHER=m
++CONFIG_USB_F_SERIAL=m
++CONFIG_USB_F_OBEX=m
++CONFIG_USB_F_ECM=m
++CONFIG_USB_F_SUBSET=m
++CONFIG_USB_F_RNDIS=m
++CONFIG_USB_F_MASS_STORAGE=m
++CONFIG_USB_F_UAC1=m
++CONFIG_USB_F_UVC=m
++# CONFIG_USB_CONFIGFS is not set
++# CONFIG_USB_ZERO is not set
++CONFIG_USB_AUDIO=m
++CONFIG_GADGET_UAC1=y
++CONFIG_USB_ETH=m
++CONFIG_USB_ETH_RNDIS=y
++# CONFIG_USB_ETH_EEM is not set
++# CONFIG_USB_G_NCM is not set
++# CONFIG_USB_GADGETFS is not set
++# CONFIG_USB_FUNCTIONFS 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 is not set
++# CONFIG_USB_G_ACM_MS is not set
++# CONFIG_USB_G_MULTI is not set
++# CONFIG_USB_G_HID is not set
++# CONFIG_USB_G_DBGP is not set
++# CONFIG_USB_G_WEBCAM is not set
++CONFIG_USB_G_WEBCAM_AUDIO=m
++# CONFIG_UWB is not set
++CONFIG_MMC=y
++# CONFIG_MMC_DEBUG is not set
++# CONFIG_MMC_CLKGATE is not set
++CONFIG_MMC_EMBEDDED_SDIO=y
++# CONFIG_MMC_PARANOID_SD_INIT is not set
++
++#
++# MMC/SD/SDIO Card Drivers
++#
++CONFIG_MMC_BLOCK=y
++CONFIG_MMC_BLOCK_MINORS=8
++CONFIG_MMC_BLOCK_BOUNCE=y
++# CONFIG_MMC_BLOCK_DEFERRED_RESUME is not set
++# CONFIG_SDIO_UART is not set
++# CONFIG_MMC_TEST is not set
++
++#
++# MMC/SD/SDIO Host Controller Drivers
++#
++# CONFIG_MMC_ARMMMCI is not set
++# CONFIG_MMC_SDHCI is not set
++# CONFIG_MMC_DW is not set
++# CONFIG_MMC_VUB300 is not set
++# CONFIG_MMC_USHC is not set
++# CONFIG_MMC_USDHI6ROL0 is not set
++CONFIG_HIMCIV200=y
++CONFIG_SEND_AUTO_STOP=y
++CONFIG_DETECT_CARD_TIME=200
++# CONFIG_MEMSTICK is not set
++# CONFIG_NEW_LEDS is not set
++# CONFIG_SWITCH is not set
++# CONFIG_ACCESSIBILITY is not set
++# CONFIG_EDAC is not set
++CONFIG_RTC_LIB=y
++# CONFIG_RTC_CLASS is not set
++# CONFIG_DMADEVICES is not set
++# CONFIG_AUXDISPLAY is not set
++# CONFIG_UIO is not set
++# CONFIG_VIRT_DRIVERS is not set
++
++#
++# Virtio drivers
++#
++# CONFIG_VIRTIO_MMIO is not set
++
++#
++# Microsoft Hyper-V guest support
++#
++# CONFIG_STAGING is not set
++
++#
++# SOC (System On Chip) specific Drivers
++#
++# CONFIG_SOC_TI is not set
++CONFIG_CLKDEV_LOOKUP=y
++CONFIG_HAVE_CLK_PREPARE=y
++CONFIG_COMMON_CLK=y
++
++#
++# Common Clock Framework
++#
++# CONFIG_COMMON_CLK_SI5351 is not set
++# CONFIG_COMMON_CLK_SI570 is not set
++# CONFIG_COMMON_CLK_PXA is not set
++# CONFIG_COMMON_CLK_QCOM is not set
++
++#
++# Hardware Spinlock drivers
++#
++
++#
++# Clock Source drivers
++#
++CONFIG_CLKSRC_OF=y
++CONFIG_CLKSRC_MMIO=y
++CONFIG_ARM_ARCH_TIMER=y
++CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y
++# CONFIG_ATMEL_PIT is not set
++# CONFIG_SH_TIMER_CMT is not set
++# CONFIG_SH_TIMER_MTU2 is not set
++# CONFIG_SH_TIMER_TMU is not set
++# CONFIG_EM_TIMER_STI is not set
++# CONFIG_CLKSRC_VERSATILE is not set
++# CONFIG_MAILBOX is not set
++# CONFIG_IOMMU_SUPPORT is not set
++
++#
++# Remoteproc drivers
++#
++# CONFIG_STE_MODEM_RPROC is not set
++
++#
++# Rpmsg drivers
++#
++
++#
++# SOC (System On Chip) specific Drivers
++#
++# 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
++CONFIG_IRQCHIP=y
++CONFIG_ARM_GIC=y
++# CONFIG_IPACK_BUS is not set
++CONFIG_ARCH_HAS_RESET_CONTROLLER=y
++CONFIG_RESET_CONTROLLER=y
++# CONFIG_FMC is not set
++
++#
++# PHY Subsystem
++#
++CONFIG_GENERIC_PHY=y
++# CONFIG_BCM_KONA_USB2_PHY is not set
++CONFIG_PHY_HISI_INNO_USB2=y
++CONFIG_PHY_HISI_USB3=y
++# CONFIG_POWERCAP is not set
++# CONFIG_MCB is not set
++CONFIG_HI_DMAC=y
++CONFIG_HI_DMAC_IO_BASE=0x10030000
++CONFIG_HI_DMAC_CHANNEL_NUM=4
++
++#
++# Hisilicon driver support
++#
++# CONFIG_CMA_MEM_SHARED is not set
++# CONFIG_CMA_ADVANCE_SHARE is not set
++
++#
++# File systems
++#
++CONFIG_DCACHE_WORD_ACCESS=y
++# CONFIG_EXT2_FS is not set
++# CONFIG_EXT3_FS is not set
++CONFIG_EXT4_FS=y
++CONFIG_EXT4_USE_FOR_EXT23=y
++# CONFIG_EXT4_FS_POSIX_ACL is not set
++# CONFIG_EXT4_FS_SECURITY is not set
++# CONFIG_EXT4_DEBUG is not set
++CONFIG_JBD2=y
++# CONFIG_JBD2_DEBUG is not set
++CONFIG_FS_MBCACHE=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_BTRFS_FS is not set
++# CONFIG_NILFS2_FS is not set
++CONFIG_FS_POSIX_ACL=y
++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 is not set
++# CONFIG_FUSE_FS is not set
++# CONFIG_OVERLAY_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_KERNFS=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=m
++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_YAFFS_FS=y
++CONFIG_YAFFS_YAFFS1=y
++# CONFIG_YAFFS_9BYTE_TAGS is not set
++# CONFIG_YAFFS_DOES_ECC is not set
++CONFIG_YAFFS_YAFFS2=y
++CONFIG_YAFFS_AUTO_YAFFS2=y
++# CONFIG_YAFFS_DISABLE_TAGS_ECC is not set
++# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
++# CONFIG_YAFFS_EMPTY_LOST_AND_FOUND is not set
++# CONFIG_YAFFS_DISABLE_BLOCK_REFRESHING is not set
++# CONFIG_YAFFS_DISABLE_BACKGROUND is not set
++# CONFIG_YAFFS_DISABLE_BAD_BLOCK_MARKING is not set
++CONFIG_YAFFS_XATTR=y
++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 is not set
++# CONFIG_JFFS2_FS_XATTR is not set
++# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
++CONFIG_JFFS2_ZLIB=y
++# CONFIG_JFFS2_LZO is not set
++CONFIG_JFFS2_RTIME=y
++# CONFIG_JFFS2_RUBIN 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 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 is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V2=y
++CONFIG_NFS_V3=y
++CONFIG_NFS_V3_ACL=y
++# CONFIG_NFS_V4 is not set
++# CONFIG_NFS_SWAP is not set
++# CONFIG_ROOT_NFS is not set
++# CONFIG_NFSD is not set
++CONFIG_GRACE_PERIOD=y
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_ACL_SUPPORT=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 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=y
++# CONFIG_DLM is not set
++
++#
++# Kernel hacking
++#
++
++#
++# printk and dmesg options
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4
++# CONFIG_BOOT_PRINTK_DELAY is not set
++
++#
++# Compile-time checks and compiler options
++#
++# CONFIG_DEBUG_INFO is not set
++# CONFIG_ENABLE_WARN_DEPRECATED is not set
++# CONFIG_ENABLE_MUST_CHECK is not set
++CONFIG_FRAME_WARN=1024
++# CONFIG_STRIP_ASM_SYMS is not set
++# CONFIG_READABLE_ASM is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++# CONFIG_DEBUG_FS is not set
++# CONFIG_HEADERS_CHECK is not set
++# CONFIG_DEBUG_SECTION_MISMATCH is not set
++# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
++# CONFIG_MAGIC_SYSRQ is not set
++CONFIG_DEBUG_KERNEL=y
++
++#
++# Memory Debugging
++#
++# 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_STACK_USAGE is not set
++# CONFIG_DEBUG_VM is not set
++CONFIG_DEBUG_MEMORY_INIT=y
++# CONFIG_DEBUG_PER_CPU_MAPS is not set
++# CONFIG_DEBUG_HIGHMEM is not set
++# CONFIG_DEBUG_SHIRQ is not set
++
++#
++# Debug Lockups and Hangs
++#
++# CONFIG_LOCKUP_DETECTOR is not set
++# CONFIG_DETECT_HUNG_TASK is not set
++# CONFIG_PANIC_ON_OOPS is not set
++CONFIG_PANIC_ON_OOPS_VALUE=0
++CONFIG_PANIC_TIMEOUT=0
++CONFIG_SCHED_DEBUG=y
++# CONFIG_SCHEDSTATS is not set
++# CONFIG_SCHED_STACK_END_CHECK is not set
++# CONFIG_TIMER_STATS is not set
++
++#
++# Lock Debugging (spinlocks, mutexes, etc...)
++#
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_LOCK_STAT is not set
++# CONFIG_DEBUG_ATOMIC_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_LOCK_TORTURE_TEST is not set
++CONFIG_STACKTRACE=y
++# CONFIG_DEBUG_KOBJECT is not set
++CONFIG_DEBUG_BUGVERBOSE=y
++# CONFIG_DEBUG_LIST is not set
++# CONFIG_DEBUG_PI_LIST is not set
++# CONFIG_DEBUG_SG is not set
++# CONFIG_DEBUG_NOTIFIERS is not set
++# CONFIG_DEBUG_CREDENTIALS is not set
++
++#
++# RCU Debugging
++#
++# CONFIG_SPARSE_RCU_POINTER is not set
++# CONFIG_TORTURE_TEST 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_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_NOTIFIER_ERROR_INJECTION is not set
++# CONFIG_FAULT_INJECTION 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 is not set
++
++#
++# Runtime Testing
++#
++# CONFIG_TEST_LIST_SORT is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_RBTREE_TEST is not set
++# CONFIG_INTERVAL_TREE_TEST is not set
++# CONFIG_PERCPU_TEST is not set
++# CONFIG_ATOMIC64_SELFTEST is not set
++# CONFIG_TEST_STRING_HELPERS is not set
++# CONFIG_TEST_KSTRTOX is not set
++# CONFIG_TEST_RHASHTABLE is not set
++# CONFIG_DMA_API_DEBUG is not set
++# CONFIG_TEST_LKM is not set
++# CONFIG_TEST_USER_COPY is not set
++# CONFIG_TEST_BPF is not set
++# CONFIG_TEST_FIRMWARE is not set
++# CONFIG_TEST_UDELAY is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_KGDB is not set
++# CONFIG_ARM_PTDUMP is not set
++CONFIG_STRICT_DEVMEM=y
++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_DEBUG_UART_PL01X is not set
++# CONFIG_DEBUG_UART_8250 is not set
++# CONFIG_DEBUG_UART_BCM63XX is not set
++CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"
++# CONFIG_OC_ETM is not set
++# CONFIG_PID_IN_CONTEXTIDR is not set
++# CONFIG_DEBUG_SET_MODULE_RONX is not set
++# CONFIG_CORESIGHT is not set
++
++#
++# 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_HASH=y
++CONFIG_CRYPTO_HASH2=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_PCRYPT is not set
++# CONFIG_CRYPTO_CRYPTD is not set
++# CONFIG_CRYPTO_MCRYPTD 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_CMAC is not set
++# CONFIG_CRYPTO_HMAC is not set
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_VMAC is not set
++
++#
++# Digest
++#
++CONFIG_CRYPTO_CRC32C=y
++# CONFIG_CRYPTO_CRC32 is not set
++# CONFIG_CRYPTO_CRCT10DIF 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_SHA1_ARM_NEON is not set
++# CONFIG_CRYPTO_SHA256 is not set
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_SHA512_ARM_NEON 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_AES_ARM_BS 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
++# CONFIG_CRYPTO_LZ4 is not set
++# CONFIG_CRYPTO_LZ4HC is not set
++
++#
++# Random Number Generation
++#
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++# CONFIG_CRYPTO_DRBG_MENU is not set
++# CONFIG_CRYPTO_USER_API_HASH is not set
++# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
++CONFIG_CRYPTO_HW=y
++# CONFIG_BINARY_PRINTF is not set
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++CONFIG_GENERIC_STRNCPY_FROM_USER=y
++CONFIG_GENERIC_STRNLEN_USER=y
++CONFIG_GENERIC_NET_UTILS=y
++CONFIG_GENERIC_PCI_IOMAP=y
++CONFIG_GENERIC_IO=y
++CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
++# CONFIG_CRC_CCITT is not set
++CONFIG_CRC16=y
++# CONFIG_CRC_T10DIF is not set
++# 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_AUDIT_ARCH_COMPAT_GENERIC is not set
++# CONFIG_RANDOM32_SELFTEST is not set
++CONFIG_ZLIB_INFLATE=y
++CONFIG_ZLIB_DEFLATE=y
++CONFIG_LZO_COMPRESS=y
++CONFIG_LZO_DECOMPRESS=y
++CONFIG_LZ4_DECOMPRESS=y
++CONFIG_XZ_DEC=y
++CONFIG_XZ_DEC_X86=y
++CONFIG_XZ_DEC_POWERPC=y
++CONFIG_XZ_DEC_IA64=y
++CONFIG_XZ_DEC_ARM=y
++CONFIG_XZ_DEC_ARMTHUMB=y
++CONFIG_XZ_DEC_SPARC=y
++CONFIG_XZ_DEC_BCJ=y
++# CONFIG_XZ_DEC_TEST is not set
++CONFIG_DECOMPRESS_GZIP=y
++CONFIG_DECOMPRESS_BZIP2=y
++CONFIG_DECOMPRESS_LZMA=y
++CONFIG_DECOMPRESS_XZ=y
++CONFIG_DECOMPRESS_LZO=y
++CONFIG_DECOMPRESS_LZ4=y
++CONFIG_GENERIC_ALLOCATOR=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT_MAP=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 is not set
++# CONFIG_CORDIC is not set
++# CONFIG_DDR is not set
++CONFIG_LIBFDT=y
++CONFIG_ARCH_HAS_SG_CHAIN=y
++# CONFIG_VIRTUALIZATION is not set
+diff --git a/arch/arm/configs/hi3519v101_big_little_nand_defconfig b/arch/arm/configs/hi3519v101_big_little_nand_defconfig
+new file mode 100644
+index 0000000..7d44600
+--- /dev/null
++++ b/arch/arm/configs/hi3519v101_big_little_nand_defconfig
+@@ -0,0 +1,2699 @@
++#
++# Automatically generated file; DO NOT EDIT.
++# Linux/arm 3.18.20 Kernel Configuration
++#
++CONFIG_ARM=y
++CONFIG_ARM_HAS_SG_CHAIN=y
++CONFIG_MIGHT_HAVE_PCI=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=y
++CONFIG_HAVE_PROC_CPU=y
++CONFIG_STACKTRACE_SUPPORT=y
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
++CONFIG_RWSEM_XCHGADD_ALGORITHM=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_NEED_DMA_MAP_STATE=y
++CONFIG_ARCH_SUPPORTS_UPROBES=y
++CONFIG_VECTORS_BASE=0xffff0000
++CONFIG_ARM_PATCH_PHYS_VIRT=y
++CONFIG_GENERIC_BUG=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++CONFIG_IRQ_WORK=y
++CONFIG_BUILDTIME_EXTABLE_SORT=y
++
++#
++# General setup
++#
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_CROSS_COMPILE=""
++# CONFIG_COMPILE_TEST is not set
++CONFIG_LOCALVERSION=""
++# CONFIG_LOCALVERSION_AUTO is not set
++CONFIG_HAVE_KERNEL_GZIP=y
++CONFIG_HAVE_KERNEL_LZMA=y
++CONFIG_HAVE_KERNEL_XZ=y
++CONFIG_HAVE_KERNEL_LZO=y
++CONFIG_HAVE_KERNEL_LZ4=y
++CONFIG_KERNEL_GZIP=y
++# CONFIG_KERNEL_LZMA is not set
++# CONFIG_KERNEL_XZ is not set
++# CONFIG_KERNEL_LZO is not set
++# CONFIG_KERNEL_LZ4 is not set
++CONFIG_DEFAULT_HOSTNAME="(none)"
++CONFIG_SWAP=y
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++# CONFIG_POSIX_MQUEUE is not set
++CONFIG_CROSS_MEMORY_ATTACH=y
++# CONFIG_FHANDLE is not set
++CONFIG_USELIB=y
++# CONFIG_AUDIT is not set
++CONFIG_HAVE_ARCH_AUDITSYSCALL=y
++
++#
++# IRQ subsystem
++#
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_GENERIC_IRQ_SHOW=y
++CONFIG_HARDIRQS_SW_RESEND=y
++CONFIG_IRQ_DOMAIN=y
++CONFIG_HANDLE_DOMAIN_IRQ=y
++CONFIG_IRQ_FORCED_THREADING=y
++CONFIG_SPARSE_IRQ=y
++CONFIG_GENERIC_CLOCKEVENTS=y
++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
++CONFIG_ARCH_HAS_TICK_BROADCAST=y
++CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
++
++#
++# Timers subsystem
++#
++CONFIG_TICK_ONESHOT=y
++CONFIG_NO_HZ_COMMON=y
++# CONFIG_HZ_PERIODIC is not set
++CONFIG_NO_HZ_IDLE=y
++# CONFIG_NO_HZ_FULL is not set
++CONFIG_NO_HZ=y
++# CONFIG_HIGH_RES_TIMERS is not set
++
++#
++# CPU/Task time and stats accounting
++#
++CONFIG_TICK_CPU_ACCOUNTING=y
++# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set
++# CONFIG_IRQ_TIME_ACCOUNTING is not set
++# CONFIG_BSD_PROCESS_ACCT is not set
++# CONFIG_TASKSTATS is not set
++
++#
++# RCU Subsystem
++#
++CONFIG_TREE_RCU=y
++# CONFIG_PREEMPT_RCU is not set
++# CONFIG_TASKS_RCU is not set
++CONFIG_RCU_STALL_COMMON=y
++# CONFIG_RCU_USER_QS is not set
++CONFIG_RCU_FANOUT=32
++CONFIG_RCU_FANOUT_LEAF=16
++# CONFIG_RCU_FANOUT_EXACT is not set
++# CONFIG_RCU_FAST_NO_HZ is not set
++# CONFIG_TREE_RCU_TRACE is not set
++# CONFIG_RCU_NOCB_CPU is not set
++# CONFIG_BUILD_BIN2C is not set
++# CONFIG_IKCONFIG is not set
++CONFIG_LOG_BUF_SHIFT=17
++CONFIG_LOG_CPU_MAX_BUF_SHIFT=12
++CONFIG_GENERIC_SCHED_CLOCK=y
++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_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_USER_NS is not set
++CONFIG_PID_NS=y
++CONFIG_NET_NS=y
++# 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=y
++CONFIG_RD_LZMA=y
++CONFIG_RD_XZ=y
++CONFIG_RD_LZO=y
++CONFIG_RD_LZ4=y
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++CONFIG_HAVE_UID16=y
++CONFIG_BPF=y
++# CONFIG_EXPERT is not set
++CONFIG_UID16=y
++# CONFIG_SGETMASK_SYSCALL is not set
++CONFIG_SYSFS_SYSCALL=y
++# CONFIG_SYSCTL_SYSCALL is not set
++CONFIG_KALLSYMS=y
++# CONFIG_KALLSYMS_ALL is not set
++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_BPF_SYSCALL is not set
++CONFIG_SHMEM=y
++CONFIG_AIO=y
++CONFIG_ADVISE_SYSCALLS=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_SLUB_CPU_PARTIAL=y
++# CONFIG_PROFILING is not set
++CONFIG_HAVE_OPROFILE=y
++# CONFIG_KPROBES is not set
++# CONFIG_JUMP_LABEL is not set
++# CONFIG_UPROBES is not set
++# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
++CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
++CONFIG_ARCH_USE_BUILTIN_BSWAP=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_GENERIC_SMP_IDLE_THREAD=y
++CONFIG_GENERIC_IDLE_POLL_SETUP=y
++CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
++CONFIG_HAVE_CLK=y
++CONFIG_HAVE_DMA_API_DEBUG=y
++CONFIG_HAVE_PERF_REGS=y
++CONFIG_HAVE_PERF_USER_STACK_DUMP=y
++CONFIG_HAVE_ARCH_JUMP_LABEL=y
++CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
++CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
++CONFIG_HAVE_CC_STACKPROTECTOR=y
++# CONFIG_CC_STACKPROTECTOR is not set
++CONFIG_CC_STACKPROTECTOR_NONE=y
++# CONFIG_CC_STACKPROTECTOR_REGULAR is not set
++# CONFIG_CC_STACKPROTECTOR_STRONG is not set
++CONFIG_HAVE_CONTEXT_TRACKING=y
++CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
++CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
++CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
++CONFIG_MODULES_USE_ELF_REL=y
++CONFIG_CLONE_BACKWARDS=y
++CONFIG_OLD_SIGSUSPEND3=y
++CONFIG_OLD_SIGACTION=y
++
++#
++# GCOV-based kernel profiling
++#
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_SLABINFO=y
++CONFIG_RT_MUTEXES=y
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++# CONFIG_MODULE_FORCE_LOAD is not set
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++# CONFIG_MODULE_SIG is not set
++# CONFIG_MODULE_COMPRESS is not set
++CONFIG_STOP_MACHINE=y
++CONFIG_BLOCK=y
++CONFIG_LBDAF=y
++CONFIG_BLK_DEV_BSG=y
++# CONFIG_BLK_DEV_BSGLIB is not set
++# CONFIG_BLK_DEV_INTEGRITY is not set
++CONFIG_BLK_CMDLINE_PARSER=y
++
++#
++# Partition Types
++#
++CONFIG_PARTITION_ADVANCED=y
++# CONFIG_ACORN_PARTITION is not set
++# CONFIG_AIX_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=y
++# CONFIG_SYSV68_PARTITION is not set
++CONFIG_CMDLINE_PARTITION=y
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++CONFIG_DEFAULT_DEADLINE=y
++# CONFIG_DEFAULT_CFQ is not set
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="deadline"
++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_ARCH_SUPPORTS_ATOMIC_RMW=y
++CONFIG_MUTEX_SPIN_ON_OWNER=y
++CONFIG_RWSEM_SPIN_ON_OWNER=y
++CONFIG_FREEZER=y
++
++#
++# System Type
++#
++CONFIG_MMU=y
++CONFIG_ARCH_MULTIPLATFORM=y
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_AT91 is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_GEMINI is not set
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_IOP13XX is not set
++# CONFIG_ARCH_IOP32X is not set
++# CONFIG_ARCH_IOP33X is not set
++# CONFIG_ARCH_IXP4XX is not set
++# CONFIG_ARCH_DOVE is not set
++# CONFIG_ARCH_MV78XX0 is not set
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_MMP is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_W90X900 is not set
++# CONFIG_ARCH_LPC32XX is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_MSM is not set
++# CONFIG_ARCH_SHMOBILE_LEGACY 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_DAVINCI is not set
++# CONFIG_ARCH_OMAP1 is not set
++
++#
++# Multiple platform selection
++#
++
++#
++# CPU Core family selection
++#
++# CONFIG_ARCH_MULTI_V6 is not set
++CONFIG_ARCH_MULTI_V7=y
++CONFIG_ARCH_MULTI_V6_V7=y
++# CONFIG_ARCH_MULTI_CPU_AUTO is not set
++# CONFIG_ARCH_VIRT is not set
++# CONFIG_ARCH_MVEBU is not set
++# CONFIG_ARCH_BCM is not set
++# CONFIG_ARCH_BERLIN is not set
++# CONFIG_ARCH_HIGHBANK is not set
++CONFIG_ARCH_HISI=y
++
++#
++# Hisilicon platform type
++#
++# CONFIG_ARCH_HI3xxx is not set
++# CONFIG_ARCH_HIP04 is not set
++# CONFIG_ARCH_HIX5HD2 is not set
++# CONFIG_ARCH_HI3519 is not set
++CONFIG_ARCH_HI3519V101=y
++# CONFIG_ARCH_HI3516AV200 is not set
++# CONFIG_ARCH_HI3559 is not set
++# CONFIG_ARCH_HI3556 is not set
++CONFIG_PMC=y
++# CONFIG_ARCH_HI3536C is not set
++# CONFIG_ARCH_KEYSTONE is not set
++# CONFIG_ARCH_MESON is not set
++# CONFIG_ARCH_MXC is not set
++# CONFIG_ARCH_MEDIATEK is not set
++
++#
++# TI OMAP/AM/DM/DRA Family
++#
++# CONFIG_ARCH_OMAP3 is not set
++# CONFIG_ARCH_OMAP4 is not set
++# CONFIG_SOC_OMAP5 is not set
++# CONFIG_SOC_AM33XX is not set
++# CONFIG_SOC_AM43XX is not set
++# CONFIG_SOC_DRA7XX is not set
++# CONFIG_ARCH_QCOM is not set
++# CONFIG_ARCH_ROCKCHIP is not set
++# CONFIG_ARCH_SOCFPGA is not set
++# CONFIG_PLAT_SPEAR is not set
++# CONFIG_ARCH_STI is not set
++# CONFIG_ARCH_S5PV210 is not set
++# CONFIG_ARCH_EXYNOS is not set
++# CONFIG_ARCH_SHMOBILE_MULTI is not set
++# CONFIG_ARCH_SUNXI is not set
++# CONFIG_ARCH_SIRF is not set
++# CONFIG_ARCH_TEGRA is not set
++# CONFIG_ARCH_U8500 is not set
++# CONFIG_ARCH_VEXPRESS is not set
++# CONFIG_ARCH_WM8850 is not set
++# CONFIG_ARCH_ZYNQ is not set
++CONFIG_ARM_TIMER_SP804=y
++
++#
++# Processor Type
++#
++CONFIG_CPU_V7=y
++CONFIG_CPU_32v6K=y
++CONFIG_CPU_32v7=y
++CONFIG_CPU_ABRT_EV7=y
++CONFIG_CPU_PABRT_V7=y
++CONFIG_CPU_CACHE_V7=y
++CONFIG_CPU_CACHE_VIPT=y
++CONFIG_CPU_COPY_V6=y
++CONFIG_CPU_TLB_V7=y
++CONFIG_CPU_HAS_ASID=y
++CONFIG_CPU_CP15=y
++CONFIG_CPU_CP15_MMU=y
++
++#
++# Processor Features
++#
++# CONFIG_ARM_LPAE is not set
++# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
++CONFIG_ARM_THUMB=y
++# CONFIG_ARM_THUMBEE is not set
++CONFIG_ARM_VIRT_EXT=y
++CONFIG_SWP_EMULATE=y
++# CONFIG_CPU_ICACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_DISABLE is not set
++# CONFIG_CPU_BPREDICT_DISABLE is not set
++CONFIG_KUSER_HELPERS=y
++CONFIG_MIGHT_HAVE_CACHE_L2X0=y
++# CONFIG_CACHE_L2X0 is not set
++CONFIG_ARM_L1_CACHE_SHIFT_6=y
++CONFIG_ARM_L1_CACHE_SHIFT=6
++CONFIG_ARM_DMA_MEM_BUFFERABLE=y
++CONFIG_MULTI_IRQ_HANDLER=y
++# CONFIG_ARM_ERRATA_430973 is not set
++# CONFIG_ARM_ERRATA_643719 is not set
++# CONFIG_ARM_ERRATA_720789 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_ARM_ERRATA_775420 is not set
++# CONFIG_ARM_ERRATA_798181 is not set
++# CONFIG_ARM_ERRATA_773022 is not set
++
++#
++# Bus support
++#
++CONFIG_ARM_AMBA=y
++# CONFIG_PCI is not set
++# 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=y
++# CONFIG_SCHED_SMT is not set
++CONFIG_DISABLE_CPU_SCHED_DOMAIN_BALANCE=y
++CONFIG_SCHED_HMP=y
++# CONFIG_SCHED_HMP_PRIO_FILTER is not set
++CONFIG_HMP_FAST_CPU_MASK=""
++CONFIG_HMP_SLOW_CPU_MASK=""
++CONFIG_HMP_VARIABLE_SCALE=y
++# CONFIG_HMP_FREQUENCY_INVARIANT_SCALE is not set
++# CONFIG_SCHED_HMP_LITTLE_PACKING is not set
++CONFIG_HAVE_ARM_ARCH_TIMER=y
++# CONFIG_MCPM is not set
++# CONFIG_BIG_LITTLE is not set
++CONFIG_VMSPLIT_3G=y
++# CONFIG_VMSPLIT_2G is not set
++# CONFIG_VMSPLIT_1G is not set
++CONFIG_PAGE_OFFSET=0xC0000000
++CONFIG_NR_CPUS=4
++CONFIG_HOTPLUG_CPU=y
++# CONFIG_ARM_PSCI is not set
++CONFIG_ARCH_NR_GPIO=0
++CONFIG_PREEMPT_NONE=y
++# CONFIG_PREEMPT_VOLUNTARY is not set
++# CONFIG_PREEMPT is not set
++CONFIG_HZ_FIXED=0
++CONFIG_HZ_100=y
++# CONFIG_HZ_200 is not set
++# CONFIG_HZ_250 is not set
++# CONFIG_HZ_300 is not set
++# CONFIG_HZ_500 is not set
++# CONFIG_HZ_1000 is not set
++CONFIG_HZ=100
++# CONFIG_SCHED_HRTICK is not set
++# CONFIG_THUMB2_KERNEL is not set
++CONFIG_AEABI=y
++# CONFIG_OABI_COMPAT is not set
++# 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_ARCH_WANT_GENERAL_HUGETLB=y
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_HAVE_MEMBLOCK=y
++CONFIG_NO_BOOTMEM=y
++CONFIG_MEMORY_ISOLATION=y
++# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=4
++CONFIG_COMPACTION=y
++CONFIG_MIGRATION=y
++# CONFIG_PHYS_ADDR_T_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_BOUNCE=y
++# CONFIG_KSM is not set
++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
++# CONFIG_CLEANCACHE is not set
++# CONFIG_FRONTSWAP is not set
++CONFIG_CMA=y
++# CONFIG_CMA_DEBUG is not set
++CONFIG_CMA_AREAS=7
++# CONFIG_ZPOOL is not set
++# CONFIG_ZBUD is not set
++# CONFIG_ZSMALLOC 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_SWIOTLB=y
++CONFIG_IOMMU_HELPER=y
++# CONFIG_XEN is not set
++# CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART is not set
++
++#
++# Boot options
++#
++CONFIG_USE_OF=y
++CONFIG_ATAGS=y
++# CONFIG_DEPRECATED_PARAM_STRUCT is not set
++# CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE is not set
++CONFIG_ZBOOT_ROM_TEXT=0
++CONFIG_ZBOOT_ROM_BSS=0
++CONFIG_ARM_APPENDED_DTB=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_KEXEC is not set
++# CONFIG_CRASH_DUMP is not set
++CONFIG_AUTO_ZRELADDR=y
++
++#
++# CPU Power Management
++#
++
++#
++# CPU Frequency scaling
++#
++CONFIG_CPU_FREQ=y
++CONFIG_CPU_FREQ_GOV_COMMON=y
++CONFIG_CPU_FREQ_STAT=y
++# CONFIG_CPU_FREQ_STAT_DETAILS is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
++CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
++# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE is not set
++CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
++CONFIG_CPU_FREQ_GOV_POWERSAVE=y
++CONFIG_CPU_FREQ_GOV_USERSPACE=y
++CONFIG_CPU_FREQ_GOV_ONDEMAND=y
++CONFIG_CPU_FREQ_GOV_INTERACTIVE=y
++CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
++CONFIG_CPUFREQ_DT=y
++
++#
++# ARM CPU frequency scaling drivers
++#
++# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set
++
++#
++# CPU Idle
++#
++CONFIG_CPU_IDLE=y
++CONFIG_CPU_IDLE_GOV_LADDER=y
++CONFIG_CPU_IDLE_GOV_MENU=y
++
++#
++# ARM CPU Idle Drivers
++#
++CONFIG_ARM_HI3519V101_CPUIDLE=y
++# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++CONFIG_VFP=y
++CONFIG_VFPv3=y
++CONFIG_NEON=y
++CONFIG_KERNEL_MODE_NEON=y
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
++CONFIG_BINFMT_SCRIPT=y
++# CONFIG_HAVE_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
++CONFIG_COREDUMP=y
++
++#
++# Power management options
++#
++CONFIG_SUSPEND=y
++CONFIG_SUSPEND_FREEZER=y
++CONFIG_WAKELOCK=y
++CONFIG_HIBERNATE_CALLBACKS=y
++CONFIG_HISI_SNAPSHOT_BOOT=y
++# CONFIG_DEFAULT_MTD is not set
++CONFIG_DEFAULT_DDR=y
++CONFIG_SNAPSHOT_BUF_START=0x8a000000
++CONFIG_SNAPSHOT_BUF_SIZE=0x4000000
++CONFIG_HIBERNATION=y
++CONFIG_GZIP_COMPRESS=y
++CONFIG_PM_STD_PARTITION=""
++CONFIG_PM_SLEEP=y
++CONFIG_PM_SLEEP_SMP=y
++# CONFIG_PM_AUTOSLEEP is not set
++# CONFIG_PM_WAKELOCKS is not set
++# CONFIG_PM_RUNTIME is not set
++CONFIG_PM=y
++# CONFIG_PM_DEBUG is not set
++# CONFIG_APM_EMULATION is not set
++CONFIG_PM_OPP=y
++CONFIG_PM_CLK=y
++# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set
++CONFIG_CPU_PM=y
++# CONFIG_SUSPEND_TIME is not set
++CONFIG_ARCH_SUSPEND_POSSIBLE=y
++CONFIG_ARM_CPU_SUSPEND=y
++CONFIG_ARCH_HIBERNATION_POSSIBLE=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_NET_IP_TUNNEL=m
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_NET_IPVTI is not set
++# CONFIG_NET_UDP_TUNNEL is not set
++# CONFIG_NET_FOU is not set
++# CONFIG_GENEVE 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=y
++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=y
++# 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_VTI 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_ANDROID_PARANOID_NETWORK is not set
++CONFIG_NET_ACTIVITY_STATS=y
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NET_PTP_CLASSIFY 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_NF_TABLES is not set
++# CONFIG_NETFILTER_XTABLES is not set
++# CONFIG_IP_SET is not set
++# CONFIG_IP_VS is not set
++
++#
++# IP: Netfilter Configuration
++#
++# CONFIG_NF_DEFRAG_IPV4 is not set
++# CONFIG_NF_LOG_ARP is not set
++# CONFIG_NF_LOG_IPV4 is not set
++# CONFIG_NF_REJECT_IPV4 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_NF_REJECT_IPV6 is not set
++# CONFIG_NF_LOG_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_HAVE_NET_DSA=y
++# 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_PHONET is not set
++# CONFIG_6LOWPAN 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_VSOCKETS is not set
++# CONFIG_NETLINK_MMAP is not set
++# CONFIG_NETLINK_DIAG is not set
++# CONFIG_NET_MPLS_GSO is not set
++# CONFIG_HSR is not set
++CONFIG_RPS=y
++CONFIG_RFS_ACCEL=y
++CONFIG_XPS=y
++# CONFIG_CGROUP_NET_PRIO is not set
++# CONFIG_CGROUP_NET_CLASSID is not set
++CONFIG_NET_RX_BUSY_POLL=y
++CONFIG_BQL=y
++# CONFIG_BPF_JIT is not set
++CONFIG_NET_FLOW_LIMIT=y
++
++#
++# 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 is not set
++CONFIG_DEVTMPFS=y
++CONFIG_DEVTMPFS_MOUNT=y
++CONFIG_STANDALONE=y
++# CONFIG_PREVENT_FIRMWARE_BUILD is not set
++CONFIG_FW_LOADER=y
++# CONFIG_FIRMWARE_IN_KERNEL is not set
++CONFIG_EXTRA_FIRMWARE=""
++# CONFIG_FW_LOADER_USER_HELPER_FALLBACK is not set
++CONFIG_ALLOW_DEV_COREDUMP=y
++# 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_HAVE_CPU_AUTOPROBE is not set
++CONFIG_REGMAP=y
++CONFIG_REGMAP_MMIO=y
++CONFIG_DMA_SHARED_BUFFER=y
++# CONFIG_FENCE_TRACE is not set
++CONFIG_DMA_CMA=y
++
++#
++# Default contiguous memory area size:
++#
++CONFIG_CMA_SIZE_MBYTES=16
++CONFIG_CMA_SIZE_SEL_MBYTES=y
++# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set
++# CONFIG_CMA_SIZE_SEL_MIN is not set
++# CONFIG_CMA_SIZE_SEL_MAX is not set
++CONFIG_CMA_ALIGNMENT=8
++
++#
++# Bus devices
++#
++# CONFIG_BRCMSTB_GISB_ARB is not set
++CONFIG_ARM_CCI=y
++# CONFIG_VEXPRESS_CONFIG 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=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_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
++CONFIG_HIFMC=y
++# CONFIG_HIFMC_SPI_NAND is not set
++CONFIG_HIFMC_NAND=y
++
++#
++# 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_SST25L is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_PHRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++# CONFIG_MTD_BLOCK2MTD is not set
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOCG3 is not set
++CONFIG_MTD_NAND_IDS=y
++CONFIG_MTD_NAND_ECC=y
++# CONFIG_MTD_NAND_ECC_SMC is not set
++CONFIG_MTD_NAND=y
++# CONFIG_MTD_NAND_ECC_BCH is not set
++# CONFIG_MTD_SM_COMMON is not set
++# CONFIG_MTD_NAND_DENALI is not set
++# CONFIG_MTD_NAND_GPIO is not set
++# CONFIG_MTD_NAND_OMAP_BCH_BUILD is not set
++# CONFIG_MTD_NAND_DISKONCHIP is not set
++# CONFIG_MTD_NAND_DOCG4 is not set
++# CONFIG_MTD_NAND_NANDSIM is not set
++# CONFIG_MTD_NAND_PLATFORM is not set
++# CONFIG_HISI_NAND_FS_MAY_NO_YAFFS2 is not set
++# CONFIG_HISI_NAND_ECC_STATUS_REPORT is not set
++CONFIG_HIFMC100_NAND=y
++CONFIG_HIFMC100_MAX_NAND_CHIP=1
++# CONFIG_HIFMC100_NAND_EDO_MODE is not set
++CONFIG_RW_H_WIDTH=10
++CONFIG_R_L_WIDTH=10
++CONFIG_W_L_WIDTH=10
++# CONFIG_HIFMC100_NAND_HARDWARE_PAGESIZE_ECC is not set
++CONFIG_HIFMC100_NAND_AUTO_PAGESIZE_ECC=y
++# CONFIG_HIFMC100_NAND_PAGESIZE_AUTO_ECC_NONE is not set
++# CONFIG_MTD_ONENAND is not set
++
++#
++# LPDDR & LPDDR2 PCM memory drivers
++#
++# CONFIG_MTD_LPDDR is not set
++# CONFIG_MTD_LPDDR2_NVM is not set
++# CONFIG_MTD_SPI_NOR is not set
++# CONFIG_MTD_UBI is not set
++CONFIG_DTC=y
++CONFIG_OF=y
++
++#
++# Device Tree and Open Firmware support
++#
++# 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_NET=y
++CONFIG_OF_MDIO=y
++CONFIG_OF_MTD=y
++CONFIG_OF_RESERVED_MEM=y
++CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
++# CONFIG_PARPORT is not set
++CONFIG_BLK_DEV=y
++# CONFIG_BLK_DEV_NULL_BLK is not set
++# CONFIG_BLK_DEV_COW_COMMON is not set
++# CONFIG_BLK_DEV_LOOP 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=65536
++# 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_DUMMY_IRQ 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_UID_STAT is not set
++# CONFIG_BMP085_I2C is not set
++# CONFIG_BMP085_SPI is not set
++# CONFIG_USB_SWITCH_FSA9480 is not set
++# CONFIG_LATTICE_ECP3_CONFIG is not set
++# CONFIG_SRAM is not set
++# CONFIG_C2PORT is not set
++
++#
++# EEPROM support
++#
++# CONFIG_EEPROM_AT24 is not set
++# CONFIG_EEPROM_AT25 is not set
++# CONFIG_EEPROM_LEGACY is not set
++# CONFIG_EEPROM_MAX6875 is not set
++# CONFIG_EEPROM_93CX6 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
++
++#
++# Intel MIC Bus Driver
++#
++
++#
++# Intel MIC Host Driver
++#
++
++#
++# Intel MIC Card Driver
++#
++# CONFIG_ECHO is not set
++# CONFIG_CXL_BASE is not set
++
++#
++# hisi 'himm/himd.l/himc'support
++#
++CONFIG_HISI_REG=y
++
++#
++# SCSI device support
++#
++CONFIG_SCSI_MOD=y
++# CONFIG_RAID_ATTRS is not set
++CONFIG_SCSI=y
++CONFIG_SCSI_DMA=y
++# CONFIG_SCSI_NETLINK is not set
++# CONFIG_SCSI_MQ_DEFAULT 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_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 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_NET_CORE=y
++# CONFIG_BONDING is not set
++# CONFIG_DUMMY is not set
++# CONFIG_EQUALIZER is not set
++# CONFIG_NET_TEAM is not set
++# CONFIG_MACVLAN is not set
++# CONFIG_VXLAN is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_TUN is not set
++# CONFIG_VETH is not set
++# CONFIG_NLMON is not set
++
++#
++# 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_NET_DSA_MV88E6171 is not set
++# CONFIG_NET_DSA_BCM_SF2 is not set
++CONFIG_ETHERNET=y
++# CONFIG_ALTERA_TSE is not set
++# CONFIG_NET_XGENE is not set
++# CONFIG_NET_VENDOR_ARC is not set
++# CONFIG_NET_CADENCE is not set
++# CONFIG_NET_VENDOR_BROADCOM is not set
++# CONFIG_NET_VENDOR_CIRRUS is not set
++# CONFIG_DM9000 is not set
++# CONFIG_DNET is not set
++# CONFIG_NET_VENDOR_FARADAY is not set
++CONFIG_NET_VENDOR_HISILICON=y
++# CONFIG_HIX5HD2_GMAC is not set
++# CONFIG_HISI_FEMAC is not set
++CONFIG_HIETH_GMAC=y
++CONFIG_HIGMAC_DESC_4WORD=y
++CONFIG_HIGMAC_RXCSUM=y
++CONFIG_RX_FLOW_CTRL_SUPPORT=y
++CONFIG_TX_FLOW_CTRL_SUPPORT=y
++CONFIG_TX_FLOW_CTRL_PAUSE_TIME=0xFFFF
++CONFIG_TX_FLOW_CTRL_PAUSE_INTERVAL=0xFFFF
++CONFIG_TX_FLOW_CTRL_ACTIVE_THRESHOLD=16
++CONFIG_TX_FLOW_CTRL_DEACTIVE_THRESHOLD=32
++# CONFIG_HIETH_SWITCH_FABRIC is not set
++# CONFIG_NET_VENDOR_INTEL is not set
++# CONFIG_NET_VENDOR_MARVELL is not set
++# CONFIG_NET_VENDOR_MICREL is not set
++# CONFIG_NET_VENDOR_MICROCHIP is not set
++# CONFIG_NET_VENDOR_NATSEMI is not set
++# CONFIG_ETHOC is not set
++# CONFIG_NET_VENDOR_QUALCOMM is not set
++# CONFIG_NET_VENDOR_SAMSUNG is not set
++# CONFIG_NET_VENDOR_SEEQ is not set
++# CONFIG_NET_VENDOR_SMSC is not set
++# CONFIG_NET_VENDOR_STMICRO is not set
++# CONFIG_NET_VENDOR_VIA is not set
++# CONFIG_NET_VENDOR_WIZNET is not set
++CONFIG_PHYLIB=y
++
++#
++# MII PHY device drivers
++#
++# CONFIG_AT803X_PHY is not set
++# CONFIG_AMD_PHY is not set
++# CONFIG_AMD_XGBE_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 is not set
++# CONFIG_BROADCOM_PHY is not set
++# CONFIG_BCM7XXX_PHY is not set
++# CONFIG_BCM87XX_PHY is not set
++# CONFIG_ICPLUS_PHY is not set
++# CONFIG_REALTEK_PHY is not set
++# CONFIG_NATIONAL_PHY is not set
++# CONFIG_STE10XP is not set
++# CONFIG_LSI_ET1011C_PHY is not set
++# CONFIG_MICREL_PHY is not set
++# CONFIG_FIXED_PHY is not set
++# CONFIG_MDIO_BITBANG is not set
++# CONFIG_MDIO_BUS_MUX_GPIO is not set
++# CONFIG_MDIO_BUS_MUX_MMIOREG is not set
++# CONFIG_MDIO_BCM_UNIMAC is not set
++# CONFIG_MDIO_HISI_FEMAC is not set
++CONFIG_MDIO_HISI_GEMAC=y
++# CONFIG_MICREL_KS8995MA is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++CONFIG_USB_NET_DRIVERS=y
++# 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_RTL8152 is not set
++# CONFIG_USB_USBNET is not set
++# CONFIG_USB_IPHETH is not set
++# CONFIG_WLAN is not set
++
++#
++# Enable WiMAX (Networking options) to see the WiMAX drivers
++#
++# CONFIG_WAN is not set
++# CONFIG_ISDN is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
++# CONFIG_INPUT_POLLDEV is not set
++# CONFIG_INPUT_SPARSEKMAP is not set
++# CONFIG_INPUT_MATRIXKMAP is not set
++
++#
++# Userland interfaces
++#
++CONFIG_INPUT_MOUSEDEV=y
++CONFIG_INPUT_MOUSEDEV_PSAUX=y
++CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
++CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
++# CONFIG_INPUT_JOYDEV is not set
++CONFIG_INPUT_EVDEV=y
++# CONFIG_INPUT_EVBUG is not set
++# CONFIG_INPUT_KEYRESET is not set
++# CONFIG_INPUT_KEYCOMBO is not set
++
++#
++# Input Device Drivers
++#
++CONFIG_INPUT_KEYBOARD=y
++# CONFIG_KEYBOARD_ADP5588 is not set
++# CONFIG_KEYBOARD_ADP5589 is not set
++CONFIG_KEYBOARD_ATKBD=y
++# CONFIG_KEYBOARD_QT1070 is not set
++# CONFIG_KEYBOARD_QT2160 is not set
++# CONFIG_KEYBOARD_LKKBD is not set
++# CONFIG_KEYBOARD_GPIO is not set
++# CONFIG_KEYBOARD_GPIO_POLLED is not set
++# 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 is not set
++# CONFIG_KEYBOARD_CAP1106 is not set
++CONFIG_INPUT_MOUSE=y
++CONFIG_MOUSE_PS2=y
++CONFIG_MOUSE_PS2_ALPS=y
++CONFIG_MOUSE_PS2_LOGIPS2PP=y
++CONFIG_MOUSE_PS2_SYNAPTICS=y
++CONFIG_MOUSE_PS2_CYPRESS=y
++CONFIG_MOUSE_PS2_TRACKPOINT=y
++# CONFIG_MOUSE_PS2_ELANTECH is not set
++# CONFIG_MOUSE_PS2_SENTELIC is not set
++# CONFIG_MOUSE_PS2_TOUCHKIT is not set
++# CONFIG_MOUSE_SERIAL is not set
++# CONFIG_MOUSE_APPLETOUCH is not set
++# CONFIG_MOUSE_BCM5974 is not set
++# CONFIG_MOUSE_CYAPA is not set
++# CONFIG_MOUSE_VSXXXAA is not set
++# CONFIG_MOUSE_GPIO is not set
++# CONFIG_MOUSE_SYNAPTICS_I2C is not set
++# CONFIG_MOUSE_SYNAPTICS_USB is not set
++# CONFIG_INPUT_JOYSTICK is not set
++# CONFIG_INPUT_TABLET is not set
++# CONFIG_INPUT_TOUCHSCREEN is not set
++# CONFIG_INPUT_MISC is not set
++
++#
++# Hardware I/O ports
++#
++CONFIG_SERIO=y
++CONFIG_SERIO_SERPORT=y
++# CONFIG_SERIO_AMBAKMI is not set
++CONFIG_SERIO_LIBPS2=y
++# CONFIG_SERIO_RAW is not set
++# CONFIG_SERIO_ALTERA_PS2 is not set
++# CONFIG_SERIO_PS2MULT is not set
++# CONFIG_SERIO_ARC_PS2 is not set
++# CONFIG_SERIO_APBPS2 is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++CONFIG_TTY=y
++CONFIG_VT=y
++CONFIG_CONSOLE_TRANSLATIONS=y
++CONFIG_VT_CONSOLE=y
++CONFIG_VT_CONSOLE_SLEEP=y
++CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
++CONFIG_UNIX98_PTYS=y
++# CONFIG_DEVPTS_MULTIPLE_INSTANCES 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_DEVMEM=y
++CONFIG_DEVKMEM=y
++
++#
++# Serial drivers
++#
++CONFIG_SERIAL_EARLYCON=y
++# CONFIG_SERIAL_8250 is not set
++
++#
++# Non-8250 serial port support
++#
++# CONFIG_SERIAL_AMBA_PL010 is not set
++CONFIG_SERIAL_AMBA_PL011=y
++CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
++# CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST is not set
++# 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_SC16IS7XX is not set
++# CONFIG_SERIAL_ALTERA_JTAGUART is not set
++# CONFIG_SERIAL_ALTERA_UART is not set
++# CONFIG_SERIAL_IFX6X60 is not set
++# CONFIG_SERIAL_XILINX_PS_UART is not set
++# CONFIG_SERIAL_ARC is not set
++# CONFIG_SERIAL_FSL_LPUART is not set
++# CONFIG_SERIAL_ST_ASC is not set
++# CONFIG_HVC_DCC is not set
++# CONFIG_IPMI_HANDLER is not set
++# CONFIG_HW_RANDOM is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++# CONFIG_DCC_TTY is not set
++# CONFIG_XILLYBUS is not set
++
++#
++# I2C support
++#
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++# CONFIG_I2C_COMPAT is not set
++CONFIG_I2C_CHARDEV=y
++CONFIG_I2C_MUX=y
++
++#
++# Multiplexer I2C Chip support
++#
++# CONFIG_I2C_ARB_GPIO_CHALLENGE is not set
++# CONFIG_I2C_MUX_GPIO is not set
++# CONFIG_I2C_MUX_PCA9541 is not set
++# CONFIG_I2C_MUX_PCA954x is not set
++# CONFIG_I2C_HELPER_AUTO is not set
++# CONFIG_I2C_SMBUS is not set
++
++#
++# I2C Algorithms
++#
++# CONFIG_I2C_ALGOBIT is not set
++# CONFIG_I2C_ALGOPCF is not set
++# CONFIG_I2C_ALGOPCA is not set
++
++#
++# I2C Hardware Bus support
++#
++
++#
++# I2C system bus drivers (mostly embedded / system-on-chip)
++#
++# CONFIG_I2C_CBUS_GPIO is not set
++# CONFIG_I2C_DESIGNWARE_PLATFORM is not set
++# CONFIG_I2C_GPIO is not set
++# CONFIG_I2C_HIBVT is not set
++CONFIG_I2C_HISI_V110=y
++# CONFIG_I2C_NOMADIK 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_RK3X 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_ROBOTFUZZ_OSIF 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_CADENCE is not set
++# CONFIG_SPI_GPIO is not set
++# CONFIG_SPI_FSL_SPI is not set
++# CONFIG_SPI_OC_TINY is not set
++CONFIG_SPI_PL022=y
++# CONFIG_SPI_PXA2XX_PCI is not set
++# CONFIG_SPI_ROCKCHIP 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=y
++# CONFIG_SPI_TLE62X0 is not set
++# CONFIG_SPMI is not set
++# CONFIG_HSI is not set
++
++#
++# PPS support
++#
++# CONFIG_PPS is not set
++
++#
++# PPS generators support
++#
++
++#
++# PTP clock support
++#
++# CONFIG_PTP_1588_CLOCK is not set
++
++#
++# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
++#
++CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
++CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
++CONFIG_GPIOLIB=y
++CONFIG_GPIO_DEVRES=y
++CONFIG_OF_GPIO=y
++CONFIG_GPIOLIB_IRQCHIP=y
++# CONFIG_DEBUG_GPIO is not set
++CONFIG_GPIO_SYSFS=y
++
++#
++# Memory mapped GPIO drivers:
++#
++# CONFIG_GPIO_GENERIC_PLATFORM is not set
++# CONFIG_GPIO_DWAPB is not set
++# CONFIG_GPIO_EM is not set
++# CONFIG_GPIO_ZEVIO is not set
++CONFIG_GPIO_PL061=y
++# CONFIG_GPIO_SCH311X is not set
++# CONFIG_GPIO_SYSCON is not set
++# CONFIG_GPIO_GRGPIO is not set
++
++#
++# I2C GPIO expanders:
++#
++# CONFIG_GPIO_MAX7300 is not set
++# CONFIG_GPIO_MAX732X is not set
++# CONFIG_GPIO_PCA953X is not set
++# CONFIG_GPIO_PCF857X is not set
++# CONFIG_GPIO_SX150X is not set
++# CONFIG_GPIO_ADP5588 is not set
++# CONFIG_GPIO_ADNP is not set
++
++#
++# PCI GPIO expanders:
++#
++
++#
++# SPI GPIO expanders:
++#
++# CONFIG_GPIO_MAX7301 is not set
++# CONFIG_GPIO_MCP23S08 is not set
++# CONFIG_GPIO_MC33880 is not set
++# CONFIG_GPIO_74X164 is not set
++
++#
++# AC97 GPIO expanders:
++#
++
++#
++# LPC GPIO expanders:
++#
++
++#
++# MODULbus GPIO expanders:
++#
++
++#
++# USB GPIO expanders:
++#
++# CONFIG_W1 is not set
++CONFIG_POWER_SUPPLY=y
++# CONFIG_POWER_SUPPLY_DEBUG is not set
++# CONFIG_PDA_POWER is not set
++# CONFIG_TEST_POWER is not set
++# CONFIG_BATTERY_DS2780 is not set
++# CONFIG_BATTERY_DS2781 is not set
++# CONFIG_BATTERY_DS2782 is not set
++# CONFIG_BATTERY_SBS is not set
++# CONFIG_BATTERY_BQ27x00 is not set
++# CONFIG_BATTERY_MAX17040 is not set
++# CONFIG_BATTERY_MAX17042 is not set
++# CONFIG_CHARGER_MAX8903 is not set
++# CONFIG_CHARGER_LP8727 is not set
++# CONFIG_CHARGER_GPIO is not set
++# CONFIG_CHARGER_BQ2415X is not set
++# CONFIG_CHARGER_BQ24190 is not set
++# CONFIG_CHARGER_BQ24735 is not set
++# CONFIG_CHARGER_SMB347 is not set
++CONFIG_POWER_RESET=y
++# CONFIG_POWER_RESET_BRCMSTB is not set
++# CONFIG_POWER_RESET_GPIO is not set
++# CONFIG_POWER_RESET_GPIO_RESTART is not set
++CONFIG_POWER_RESET_HISI=y
++# CONFIG_POWER_RESET_LTC2952 is not set
++# CONFIG_POWER_RESET_RESTART is not set
++# CONFIG_POWER_RESET_VERSATILE is not set
++# CONFIG_POWER_RESET_SYSCON is not set
++# CONFIG_POWER_AVS is not set
++# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
++# CONFIG_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=y
++# CONFIG_MFD_AS3711 is not set
++# CONFIG_MFD_AS3722 is not set
++# CONFIG_PMIC_ADP5520 is not set
++# CONFIG_MFD_AAT2870_CORE is not set
++# CONFIG_MFD_BCM590XX is not set
++# CONFIG_MFD_AXP20X is not set
++# CONFIG_MFD_CROS_EC is not set
++# CONFIG_MFD_ASIC3 is not set
++# CONFIG_PMIC_DA903X is not set
++# CONFIG_MFD_DA9052_SPI is not set
++# CONFIG_MFD_DA9052_I2C is not set
++# CONFIG_MFD_DA9055 is not set
++# CONFIG_MFD_DA9063 is not set
++# CONFIG_MFD_MC13XXX_SPI is not set
++# CONFIG_MFD_MC13XXX_I2C is not set
++# CONFIG_MFD_HI6421_PMIC is not set
++CONFIG_MFD_HISI_FMC=y
++# CONFIG_HTC_EGPIO is not set
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_HTC_I2CPLD is not set
++# CONFIG_INTEL_SOC_PMIC is not set
++# CONFIG_MFD_KEMPLD is not set
++# CONFIG_MFD_88PM800 is not set
++# CONFIG_MFD_88PM805 is not set
++# CONFIG_MFD_88PM860X is not set
++# CONFIG_MFD_MAX14577 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_MENF21BMC is not set
++# CONFIG_EZX_PCAP is not set
++# CONFIG_MFD_VIPERBOARD is not set
++# CONFIG_MFD_RETU is not set
++# CONFIG_MFD_PCF50633 is not set
++# CONFIG_MFD_PM8921_CORE is not set
++# CONFIG_MFD_RTSX_USB is not set
++# CONFIG_MFD_RC5T583 is not set
++# CONFIG_MFD_RK808 is not set
++# CONFIG_MFD_RN5T618 is not set
++# CONFIG_MFD_SEC_CORE is not set
++# CONFIG_MFD_SI476X_CORE is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_MFD_SMSC is not set
++# CONFIG_ABX500_CORE is not set
++# CONFIG_MFD_STMPE is not set
++CONFIG_MFD_SYSCON=y
++# CONFIG_MFD_TI_AM335X_TSCADC is not set
++# CONFIG_MFD_LP3943 is not set
++# CONFIG_MFD_LP8788 is not set
++# CONFIG_MFD_PALMAS is not set
++# CONFIG_TPS6105X is not set
++# CONFIG_TPS65010 is not set
++# CONFIG_TPS6507X is not set
++# CONFIG_MFD_TPS65090 is not set
++# CONFIG_MFD_TPS65217 is not set
++# CONFIG_MFD_TPS65218 is not set
++# CONFIG_MFD_TPS6586X is not set
++# CONFIG_MFD_TPS65910 is not set
++# CONFIG_MFD_TPS65912 is not set
++# CONFIG_MFD_TPS65912_I2C is not set
++# CONFIG_MFD_TPS65912_SPI is not set
++# CONFIG_MFD_TPS80031 is not set
++# CONFIG_TWL4030_CORE is not set
++# CONFIG_TWL6040_CORE is not set
++# CONFIG_MFD_WL1273_CORE is not set
++# CONFIG_MFD_LM3533 is not set
++# CONFIG_MFD_TC3589X is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_MFD_T7L66XB is not set
++# CONFIG_MFD_TC6387XB is not set
++# CONFIG_MFD_TC6393XB is not set
++# CONFIG_MFD_ARIZONA_I2C is not set
++# CONFIG_MFD_ARIZONA_SPI is not set
++# CONFIG_MFD_WM8400 is not set
++# CONFIG_MFD_WM831X_I2C is not set
++# CONFIG_MFD_WM831X_SPI is not set
++# CONFIG_MFD_WM8350_I2C is not set
++# CONFIG_MFD_WM8994 is not set
++CONFIG_REGULATOR=y
++# CONFIG_REGULATOR_DEBUG is not set
++# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
++# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
++# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
++# CONFIG_REGULATOR_ACT8865 is not set
++# CONFIG_REGULATOR_AD5398 is not set
++# CONFIG_REGULATOR_ANATOP is not set
++# CONFIG_REGULATOR_DA9210 is not set
++# CONFIG_REGULATOR_DA9211 is not set
++# CONFIG_REGULATOR_FAN53555 is not set
++# CONFIG_REGULATOR_GPIO is not set
++# CONFIG_REGULATOR_ISL9305 is not set
++# CONFIG_REGULATOR_ISL6271A is not set
++# CONFIG_REGULATOR_LP3971 is not set
++# CONFIG_REGULATOR_LP3972 is not set
++# CONFIG_REGULATOR_LP872X is not set
++# CONFIG_REGULATOR_LP8755 is not set
++# CONFIG_REGULATOR_LTC3589 is not set
++# CONFIG_REGULATOR_MAX1586 is not set
++# CONFIG_REGULATOR_MAX8649 is not set
++# CONFIG_REGULATOR_MAX8660 is not set
++# CONFIG_REGULATOR_MAX8952 is not set
++# CONFIG_REGULATOR_MAX8973 is not set
++# CONFIG_REGULATOR_PFUZE100 is not set
++# CONFIG_REGULATOR_TPS51632 is not set
++# CONFIG_REGULATOR_TPS62360 is not set
++# CONFIG_REGULATOR_TPS65023 is not set
++# CONFIG_REGULATOR_TPS6507X is not set
++# CONFIG_REGULATOR_TPS6524X is not set
++CONFIG_MEDIA_SUPPORT=m
++
++#
++# Multimedia core support
++#
++CONFIG_MEDIA_CAMERA_SUPPORT=y
++# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set
++# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set
++# CONFIG_MEDIA_RADIO_SUPPORT is not set
++# CONFIG_MEDIA_SDR_SUPPORT is not set
++# CONFIG_MEDIA_RC_SUPPORT is not set
++# CONFIG_MEDIA_CONTROLLER is not set
++CONFIG_VIDEO_DEV=m
++CONFIG_VIDEO_V4L2=m
++# CONFIG_VIDEO_ADV_DEBUG is not set
++# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
++CONFIG_VIDEOBUF2_CORE=m
++CONFIG_VIDEOBUF2_MEMOPS=m
++CONFIG_VIDEOBUF2_VMALLOC=m
++# CONFIG_TTPCI_EEPROM is not set
++
++#
++# Media drivers
++#
++# CONFIG_MEDIA_USB_SUPPORT is not set
++# CONFIG_V4L_PLATFORM_DRIVERS is not set
++# CONFIG_V4L_MEM2MEM_DRIVERS is not set
++# CONFIG_V4L_TEST_DRIVERS is not set
++
++#
++# Supported MMC/SDIO adapters
++#
++# CONFIG_CYPRESS_FIRMWARE is not set
++
++#
++# Media ancillary drivers (tuners, sensors, i2c, frontends)
++#
++CONFIG_MEDIA_SUBDRV_AUTOSELECT=y
++
++#
++# Audio decoders, processors and mixers
++#
++
++#
++# RDS decoders
++#
++
++#
++# Video decoders
++#
++
++#
++# Video and audio decoders
++#
++
++#
++# Video encoders
++#
++
++#
++# Camera sensor devices
++#
++
++#
++# Flash devices
++#
++
++#
++# Video improvement chips
++#
++
++#
++# Audio/Video compression chips
++#
++
++#
++# Miscellaneous helper chips
++#
++
++#
++# Sensors used on soc_camera driver
++#
++
++#
++# Tools to develop new frontends
++#
++# CONFIG_DVB_DUMMY_FE is not set
++
++#
++# Graphics support
++#
++# CONFIG_IMX_IPUV3_CORE is not set
++
++#
++# Direct Rendering Manager
++#
++# CONFIG_DRM is not set
++
++#
++# Frame buffer Devices
++#
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++CONFIG_FB_CMDLINE=y
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++# CONFIG_FB_CFB_FILLRECT is not set
++# CONFIG_FB_CFB_COPYAREA is not set
++# CONFIG_FB_CFB_IMAGEBLIT is not set
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# 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_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_ARMCLCD is not set
++# CONFIG_FB_OPENCORES is not set
++# CONFIG_FB_S1D13XXX is not set
++# CONFIG_FB_SMSCUFX is not set
++# CONFIG_FB_UDL is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_BROADSHEET is not set
++# CONFIG_FB_AUO_K190X is not set
++# CONFIG_FB_SIMPLE is not set
++# CONFIG_FB_SSD1307 is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++# CONFIG_VGASTATE is not set
++
++#
++# Console display driver support
++#
++CONFIG_DUMMY_CONSOLE=y
++# CONFIG_FRAMEBUFFER_CONSOLE is not set
++# CONFIG_LOGO is not set
++# CONFIG_SOUND is not set
++
++#
++# HID support
++#
++CONFIG_HID=y
++# CONFIG_HID_BATTERY_STRENGTH is not set
++# CONFIG_HIDRAW is not set
++# CONFIG_UHID is not set
++CONFIG_HID_GENERIC=y
++
++#
++# Special HID drivers
++#
++CONFIG_HID_A4TECH=y
++# CONFIG_HID_ACRUX is not set
++CONFIG_HID_APPLE=y
++# CONFIG_HID_APPLEIR is not set
++# CONFIG_HID_AUREAL is not set
++CONFIG_HID_BELKIN=y
++CONFIG_HID_CHERRY=y
++CONFIG_HID_CHICONY=y
++# CONFIG_HID_CP2112 is not set
++CONFIG_HID_CYPRESS=y
++# CONFIG_HID_DRAGONRISE is not set
++# CONFIG_HID_EMS_FF is not set
++# CONFIG_HID_ELECOM is not set
++# CONFIG_HID_ELO is not set
++CONFIG_HID_EZKEY=y
++# CONFIG_HID_HOLTEK is not set
++# CONFIG_HID_HUION 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_ICADE is not set
++# CONFIG_HID_TWINHAN is not set
++CONFIG_HID_KENSINGTON=y
++# CONFIG_HID_LCPOWER is not set
++# CONFIG_HID_LENOVO is not set
++CONFIG_HID_LOGITECH=y
++# CONFIG_HID_LOGITECH_HIDPP is not set
++# CONFIG_LOGITECH_FF is not set
++# CONFIG_LOGIRUMBLEPAD2_FF is not set
++# CONFIG_LOGIG940_FF is not set
++# CONFIG_LOGIWHEELS_FF is not set
++# CONFIG_HID_MAGICMOUSE is not set
++CONFIG_HID_MICROSOFT=y
++CONFIG_HID_MONTEREY=y
++# 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_PENMOUNT is not set
++# CONFIG_HID_PETALYNX is not set
++# CONFIG_HID_PICOLCD is not set
++# CONFIG_HID_PRIMAX is not set
++# CONFIG_HID_ROCCAT is not set
++# CONFIG_HID_SAITEK is not set
++# CONFIG_HID_SAMSUNG is not set
++# CONFIG_HID_SPEEDLINK is not set
++# CONFIG_HID_STEELSERIES is not set
++# CONFIG_HID_SUNPLUS is not set
++# CONFIG_HID_RMI 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_XINMO is not set
++# CONFIG_HID_ZEROPLUS is not set
++# CONFIG_HID_ZYDACRON is not set
++# CONFIG_HID_SENSOR_HUB is not set
++
++#
++# USB HID support
++#
++CONFIG_USB_HID=y
++# CONFIG_HID_PID is not set
++# CONFIG_USB_HIDDEV is not set
++
++#
++# I2C HID support
++#
++# CONFIG_I2C_HID is not set
++CONFIG_USB_OHCI_LITTLE_ENDIAN=y
++CONFIG_USB_SUPPORT=y
++CONFIG_USB_COMMON=y
++CONFIG_USB_ARCH_HAS_HCD=y
++CONFIG_USB=y
++# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
++
++#
++# Miscellaneous USB options
++#
++CONFIG_USB_DEFAULT_PERSIST=y
++# CONFIG_USB_DYNAMIC_MINORS is not set
++# CONFIG_USB_OTG_WHITELIST is not set
++# CONFIG_USB_OTG_FSM is not set
++# CONFIG_USB_MON is not set
++# CONFIG_USB_WUSB_CBAF is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_C67X00_HCD is not set
++CONFIG_USB_XHCI_HCD=y
++CONFIG_USB_XHCI_PLATFORM=y
++CONFIG_USB_XHCI_HISILICON=y
++CONFIG_USB_EHCI_HCD=y
++# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
++CONFIG_USB_EHCI_TT_NEWSCHED=y
++CONFIG_USB_EHCI_HCD_PLATFORM=y
++# 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_FUSBH200_HCD is not set
++# CONFIG_USB_FOTG210_HCD is not set
++# CONFIG_USB_MAX3421_HCD is not set
++CONFIG_USB_OHCI_HCD=y
++CONFIG_USB_OHCI_HCD_PLATFORM=y
++# CONFIG_USB_SL811_HCD is not set
++# CONFIG_USB_R8A66597_HCD is not set
++# CONFIG_USB_HCD_TEST_MODE is not set
++
++#
++# USB Device Class drivers
++#
++# CONFIG_USB_ACM is not set
++# CONFIG_USB_PRINTER is not set
++# CONFIG_USB_WDM is not set
++# CONFIG_USB_TMC is not set
++
++#
++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
++#
++
++#
++# also be needed; see USB_STORAGE Help for more info
++#
++CONFIG_USB_STORAGE=y
++# CONFIG_USB_STORAGE_DEBUG is not set
++# CONFIG_USB_STORAGE_REALTEK is not set
++# CONFIG_USB_STORAGE_DATAFAB is not set
++# CONFIG_USB_STORAGE_FREECOM is not set
++# CONFIG_USB_STORAGE_ISD200 is not set
++# CONFIG_USB_STORAGE_USBAT is not set
++# CONFIG_USB_STORAGE_SDDR09 is not set
++# CONFIG_USB_STORAGE_SDDR55 is not set
++# CONFIG_USB_STORAGE_JUMPSHOT is not set
++# CONFIG_USB_STORAGE_ALAUDA is not set
++# CONFIG_USB_STORAGE_ONETOUCH is not set
++# CONFIG_USB_STORAGE_KARMA is not set
++# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
++# CONFIG_USB_STORAGE_ENE_UB6250 is not set
++# CONFIG_USB_UAS is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++# CONFIG_USBIP_CORE is not set
++# CONFIG_USB_MUSB_HDRC is not set
++# CONFIG_USB_DWC3 is not set
++# CONFIG_USB_DWC2 is not set
++# CONFIG_USB_CHIPIDEA is not set
++
++#
++# USB port drivers
++#
++# CONFIG_USB_SERIAL is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
++# CONFIG_USB_SEVSEG is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
++# CONFIG_USB_APPLEDISPLAY is not set
++# CONFIG_USB_SISUSBVGA is not set
++# CONFIG_USB_LD is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
++# CONFIG_USB_IOWARRIOR is not set
++# CONFIG_USB_TEST is not set
++# CONFIG_USB_EHSET_TEST_FIXTURE is not set
++# CONFIG_USB_ISIGHTFW is not set
++# CONFIG_USB_YUREX is not set
++# CONFIG_USB_EZUSB_FX2 is not set
++# CONFIG_USB_HSIC_USB3503 is not set
++# CONFIG_USB_LINK_LAYER_TEST is not set
++
++#
++# USB Physical Layer drivers
++#
++# CONFIG_USB_PHY is not set
++# CONFIG_USB_OTG_WAKELOCK is not set
++# CONFIG_NOP_USB_XCEIV is not set
++# CONFIG_AM335X_PHY_USB is not set
++# CONFIG_USB_GPIO_VBUS is not set
++# CONFIG_USB_ISP1301 is not set
++# CONFIG_USB_ULPI is not set
++CONFIG_USB_GADGET=y
++# CONFIG_USB_GADGET_DEBUG is not set
++# CONFIG_USB_GADGET_DEBUG_FILES is not set
++CONFIG_USB_GADGET_VBUS_DRAW=2
++CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2
++
++#
++# USB Peripheral Controller
++#
++# CONFIG_USB_FUSB300 is not set
++# CONFIG_USB_FOTG210_UDC is not set
++# CONFIG_USB_GR_UDC is not set
++# CONFIG_USB_R8A66597 is not set
++# CONFIG_USB_PXA27X is not set
++# CONFIG_USB_MV_UDC is not set
++CONFIG_HIUSB_DEVICE2_0=y
++CONFIG_USB_HISI_UDC=m
++# CONFIG_USB_AUTO_SWITCH is not set
++# CONFIG_HIUSB_DEVICE3_0 is not set
++# CONFIG_USB_MV_U3D is not set
++# CONFIG_USB_M66592 is not set
++# CONFIG_USB_NET2272 is not set
++# CONFIG_USB_GADGET_XILINX is not set
++# CONFIG_USB_DUMMY_HCD is not set
++CONFIG_USB_LIBCOMPOSITE=m
++CONFIG_USB_F_ACM=m
++CONFIG_USB_U_SERIAL=m
++CONFIG_USB_U_ETHER=m
++CONFIG_USB_F_SERIAL=m
++CONFIG_USB_F_OBEX=m
++CONFIG_USB_F_ECM=m
++CONFIG_USB_F_SUBSET=m
++CONFIG_USB_F_RNDIS=m
++CONFIG_USB_F_MASS_STORAGE=m
++CONFIG_USB_F_UAC1=m
++CONFIG_USB_F_UVC=m
++# CONFIG_USB_CONFIGFS is not set
++# CONFIG_USB_ZERO is not set
++CONFIG_USB_AUDIO=m
++CONFIG_GADGET_UAC1=y
++CONFIG_USB_ETH=m
++CONFIG_USB_ETH_RNDIS=y
++# CONFIG_USB_ETH_EEM is not set
++# CONFIG_USB_G_NCM is not set
++# CONFIG_USB_GADGETFS is not set
++# CONFIG_USB_FUNCTIONFS 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 is not set
++# CONFIG_USB_G_ACM_MS is not set
++# CONFIG_USB_G_MULTI is not set
++# CONFIG_USB_G_HID is not set
++# CONFIG_USB_G_DBGP is not set
++# CONFIG_USB_G_WEBCAM is not set
++CONFIG_USB_G_WEBCAM_AUDIO=m
++# CONFIG_UWB is not set
++CONFIG_MMC=y
++# CONFIG_MMC_DEBUG is not set
++# CONFIG_MMC_CLKGATE is not set
++CONFIG_MMC_EMBEDDED_SDIO=y
++# CONFIG_MMC_PARANOID_SD_INIT is not set
++
++#
++# MMC/SD/SDIO Card Drivers
++#
++CONFIG_MMC_BLOCK=y
++CONFIG_MMC_BLOCK_MINORS=8
++CONFIG_MMC_BLOCK_BOUNCE=y
++# CONFIG_MMC_BLOCK_DEFERRED_RESUME is not set
++# CONFIG_SDIO_UART is not set
++# CONFIG_MMC_TEST is not set
++
++#
++# MMC/SD/SDIO Host Controller Drivers
++#
++# CONFIG_MMC_ARMMMCI is not set
++# CONFIG_MMC_SDHCI is not set
++# CONFIG_MMC_DW is not set
++# CONFIG_MMC_VUB300 is not set
++# CONFIG_MMC_USHC is not set
++# CONFIG_MMC_USDHI6ROL0 is not set
++CONFIG_HIMCIV200=y
++CONFIG_SEND_AUTO_STOP=y
++CONFIG_DETECT_CARD_TIME=200
++# CONFIG_MEMSTICK is not set
++# CONFIG_NEW_LEDS is not set
++# CONFIG_SWITCH is not set
++# CONFIG_ACCESSIBILITY is not set
++# CONFIG_EDAC is not set
++CONFIG_RTC_LIB=y
++# CONFIG_RTC_CLASS is not set
++# CONFIG_DMADEVICES is not set
++# CONFIG_AUXDISPLAY is not set
++# CONFIG_UIO is not set
++# CONFIG_VIRT_DRIVERS is not set
++
++#
++# Virtio drivers
++#
++# CONFIG_VIRTIO_MMIO is not set
++
++#
++# Microsoft Hyper-V guest support
++#
++# CONFIG_STAGING is not set
++
++#
++# SOC (System On Chip) specific Drivers
++#
++# CONFIG_SOC_TI is not set
++CONFIG_CLKDEV_LOOKUP=y
++CONFIG_HAVE_CLK_PREPARE=y
++CONFIG_COMMON_CLK=y
++
++#
++# Common Clock Framework
++#
++# CONFIG_COMMON_CLK_SI5351 is not set
++# CONFIG_COMMON_CLK_SI570 is not set
++# CONFIG_COMMON_CLK_PXA is not set
++# CONFIG_COMMON_CLK_QCOM is not set
++
++#
++# Hardware Spinlock drivers
++#
++
++#
++# Clock Source drivers
++#
++CONFIG_CLKSRC_OF=y
++CONFIG_CLKSRC_MMIO=y
++CONFIG_ARM_ARCH_TIMER=y
++CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y
++# CONFIG_ATMEL_PIT is not set
++# CONFIG_SH_TIMER_CMT is not set
++# CONFIG_SH_TIMER_MTU2 is not set
++# CONFIG_SH_TIMER_TMU is not set
++# CONFIG_EM_TIMER_STI is not set
++# CONFIG_CLKSRC_VERSATILE is not set
++# CONFIG_MAILBOX is not set
++# CONFIG_IOMMU_SUPPORT is not set
++
++#
++# Remoteproc drivers
++#
++# CONFIG_STE_MODEM_RPROC is not set
++
++#
++# Rpmsg drivers
++#
++
++#
++# SOC (System On Chip) specific Drivers
++#
++# 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
++CONFIG_IRQCHIP=y
++CONFIG_ARM_GIC=y
++# CONFIG_IPACK_BUS is not set
++CONFIG_ARCH_HAS_RESET_CONTROLLER=y
++CONFIG_RESET_CONTROLLER=y
++# CONFIG_FMC is not set
++
++#
++# PHY Subsystem
++#
++CONFIG_GENERIC_PHY=y
++# CONFIG_BCM_KONA_USB2_PHY is not set
++CONFIG_PHY_HISI_INNO_USB2=y
++CONFIG_PHY_HISI_USB3=y
++# CONFIG_POWERCAP is not set
++# CONFIG_MCB is not set
++CONFIG_HI_DMAC=y
++CONFIG_HI_DMAC_IO_BASE=0x10030000
++CONFIG_HI_DMAC_CHANNEL_NUM=4
++
++#
++# Hisilicon driver support
++#
++# CONFIG_CMA_MEM_SHARED is not set
++# CONFIG_CMA_ADVANCE_SHARE is not set
++
++#
++# File systems
++#
++CONFIG_DCACHE_WORD_ACCESS=y
++# CONFIG_EXT2_FS is not set
++# CONFIG_EXT3_FS is not set
++CONFIG_EXT4_FS=y
++CONFIG_EXT4_USE_FOR_EXT23=y
++# CONFIG_EXT4_FS_POSIX_ACL is not set
++# CONFIG_EXT4_FS_SECURITY is not set
++# CONFIG_EXT4_DEBUG is not set
++CONFIG_JBD2=y
++# CONFIG_JBD2_DEBUG is not set
++CONFIG_FS_MBCACHE=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_BTRFS_FS is not set
++# CONFIG_NILFS2_FS is not set
++CONFIG_FS_POSIX_ACL=y
++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 is not set
++# CONFIG_FUSE_FS is not set
++# CONFIG_OVERLAY_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_KERNFS=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=m
++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_YAFFS_FS=y
++CONFIG_YAFFS_YAFFS1=y
++# CONFIG_YAFFS_9BYTE_TAGS is not set
++# CONFIG_YAFFS_DOES_ECC is not set
++CONFIG_YAFFS_YAFFS2=y
++CONFIG_YAFFS_AUTO_YAFFS2=y
++# CONFIG_YAFFS_DISABLE_TAGS_ECC is not set
++# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
++# CONFIG_YAFFS_EMPTY_LOST_AND_FOUND is not set
++# CONFIG_YAFFS_DISABLE_BLOCK_REFRESHING is not set
++# CONFIG_YAFFS_DISABLE_BACKGROUND is not set
++# CONFIG_YAFFS_DISABLE_BAD_BLOCK_MARKING is not set
++CONFIG_YAFFS_XATTR=y
++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 is not set
++# CONFIG_JFFS2_FS_XATTR is not set
++# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
++CONFIG_JFFS2_ZLIB=y
++# CONFIG_JFFS2_LZO is not set
++CONFIG_JFFS2_RTIME=y
++# CONFIG_JFFS2_RUBIN 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 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 is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V2=y
++CONFIG_NFS_V3=y
++CONFIG_NFS_V3_ACL=y
++# CONFIG_NFS_V4 is not set
++# CONFIG_NFS_SWAP is not set
++# CONFIG_ROOT_NFS is not set
++# CONFIG_NFSD is not set
++CONFIG_GRACE_PERIOD=y
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_ACL_SUPPORT=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 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=y
++# CONFIG_DLM is not set
++
++#
++# Kernel hacking
++#
++
++#
++# printk and dmesg options
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4
++# CONFIG_BOOT_PRINTK_DELAY is not set
++
++#
++# Compile-time checks and compiler options
++#
++# CONFIG_DEBUG_INFO is not set
++# CONFIG_ENABLE_WARN_DEPRECATED is not set
++# CONFIG_ENABLE_MUST_CHECK is not set
++CONFIG_FRAME_WARN=1024
++# CONFIG_STRIP_ASM_SYMS is not set
++# CONFIG_READABLE_ASM is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++# CONFIG_DEBUG_FS is not set
++# CONFIG_HEADERS_CHECK is not set
++# CONFIG_DEBUG_SECTION_MISMATCH is not set
++# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
++# CONFIG_MAGIC_SYSRQ is not set
++CONFIG_DEBUG_KERNEL=y
++
++#
++# Memory Debugging
++#
++# 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_STACK_USAGE is not set
++# CONFIG_DEBUG_VM is not set
++CONFIG_DEBUG_MEMORY_INIT=y
++# CONFIG_DEBUG_PER_CPU_MAPS is not set
++# CONFIG_DEBUG_HIGHMEM is not set
++# CONFIG_DEBUG_SHIRQ is not set
++
++#
++# Debug Lockups and Hangs
++#
++# CONFIG_LOCKUP_DETECTOR is not set
++# CONFIG_DETECT_HUNG_TASK is not set
++# CONFIG_PANIC_ON_OOPS is not set
++CONFIG_PANIC_ON_OOPS_VALUE=0
++CONFIG_PANIC_TIMEOUT=0
++CONFIG_SCHED_DEBUG=y
++# CONFIG_SCHEDSTATS is not set
++# CONFIG_SCHED_STACK_END_CHECK is not set
++# CONFIG_TIMER_STATS is not set
++
++#
++# Lock Debugging (spinlocks, mutexes, etc...)
++#
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_LOCK_STAT is not set
++# CONFIG_DEBUG_ATOMIC_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_LOCK_TORTURE_TEST is not set
++CONFIG_STACKTRACE=y
++# CONFIG_DEBUG_KOBJECT is not set
++CONFIG_DEBUG_BUGVERBOSE=y
++# CONFIG_DEBUG_LIST is not set
++# CONFIG_DEBUG_PI_LIST is not set
++# CONFIG_DEBUG_SG is not set
++# CONFIG_DEBUG_NOTIFIERS is not set
++# CONFIG_DEBUG_CREDENTIALS is not set
++
++#
++# RCU Debugging
++#
++# CONFIG_SPARSE_RCU_POINTER is not set
++# CONFIG_TORTURE_TEST 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_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_NOTIFIER_ERROR_INJECTION is not set
++# CONFIG_FAULT_INJECTION 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 is not set
++
++#
++# Runtime Testing
++#
++# CONFIG_TEST_LIST_SORT is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_RBTREE_TEST is not set
++# CONFIG_INTERVAL_TREE_TEST is not set
++# CONFIG_PERCPU_TEST is not set
++# CONFIG_ATOMIC64_SELFTEST is not set
++# CONFIG_TEST_STRING_HELPERS is not set
++# CONFIG_TEST_KSTRTOX is not set
++# CONFIG_TEST_RHASHTABLE is not set
++# CONFIG_DMA_API_DEBUG is not set
++# CONFIG_TEST_LKM is not set
++# CONFIG_TEST_USER_COPY is not set
++# CONFIG_TEST_BPF is not set
++# CONFIG_TEST_FIRMWARE is not set
++# CONFIG_TEST_UDELAY is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_KGDB is not set
++# CONFIG_ARM_PTDUMP is not set
++CONFIG_STRICT_DEVMEM=y
++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_DEBUG_UART_PL01X is not set
++# CONFIG_DEBUG_UART_8250 is not set
++# CONFIG_DEBUG_UART_BCM63XX is not set
++CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"
++# CONFIG_OC_ETM is not set
++# CONFIG_PID_IN_CONTEXTIDR is not set
++# CONFIG_DEBUG_SET_MODULE_RONX is not set
++# CONFIG_CORESIGHT is not set
++
++#
++# 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_HASH=y
++CONFIG_CRYPTO_HASH2=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_PCRYPT is not set
++# CONFIG_CRYPTO_CRYPTD is not set
++# CONFIG_CRYPTO_MCRYPTD 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_CMAC is not set
++# CONFIG_CRYPTO_HMAC is not set
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_VMAC is not set
++
++#
++# Digest
++#
++CONFIG_CRYPTO_CRC32C=y
++# CONFIG_CRYPTO_CRC32 is not set
++# CONFIG_CRYPTO_CRCT10DIF 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_SHA1_ARM_NEON is not set
++# CONFIG_CRYPTO_SHA256 is not set
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_SHA512_ARM_NEON 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_AES_ARM_BS 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
++# CONFIG_CRYPTO_LZ4 is not set
++# CONFIG_CRYPTO_LZ4HC is not set
++
++#
++# Random Number Generation
++#
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++# CONFIG_CRYPTO_DRBG_MENU is not set
++# CONFIG_CRYPTO_USER_API_HASH is not set
++# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
++CONFIG_CRYPTO_HW=y
++# CONFIG_BINARY_PRINTF is not set
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++CONFIG_GENERIC_STRNCPY_FROM_USER=y
++CONFIG_GENERIC_STRNLEN_USER=y
++CONFIG_GENERIC_NET_UTILS=y
++CONFIG_GENERIC_PCI_IOMAP=y
++CONFIG_GENERIC_IO=y
++CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
++# CONFIG_CRC_CCITT is not set
++CONFIG_CRC16=y
++# CONFIG_CRC_T10DIF is not set
++# 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_AUDIT_ARCH_COMPAT_GENERIC is not set
++# CONFIG_RANDOM32_SELFTEST is not set
++CONFIG_ZLIB_INFLATE=y
++CONFIG_ZLIB_DEFLATE=y
++CONFIG_LZO_COMPRESS=y
++CONFIG_LZO_DECOMPRESS=y
++CONFIG_LZ4_DECOMPRESS=y
++CONFIG_XZ_DEC=y
++CONFIG_XZ_DEC_X86=y
++CONFIG_XZ_DEC_POWERPC=y
++CONFIG_XZ_DEC_IA64=y
++CONFIG_XZ_DEC_ARM=y
++CONFIG_XZ_DEC_ARMTHUMB=y
++CONFIG_XZ_DEC_SPARC=y
++CONFIG_XZ_DEC_BCJ=y
++# CONFIG_XZ_DEC_TEST is not set
++CONFIG_DECOMPRESS_GZIP=y
++CONFIG_DECOMPRESS_BZIP2=y
++CONFIG_DECOMPRESS_LZMA=y
++CONFIG_DECOMPRESS_XZ=y
++CONFIG_DECOMPRESS_LZO=y
++CONFIG_DECOMPRESS_LZ4=y
++CONFIG_GENERIC_ALLOCATOR=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT_MAP=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 is not set
++# CONFIG_CORDIC is not set
++# CONFIG_DDR is not set
++CONFIG_LIBFDT=y
++CONFIG_ARCH_HAS_SG_CHAIN=y
++# CONFIG_VIRTUALIZATION is not set
+diff --git a/arch/arm/configs/hi3521d_full_defconfig b/arch/arm/configs/hi3521d_full_defconfig
+new file mode 100644
+index 0000000..0798397
+--- /dev/null
++++ b/arch/arm/configs/hi3521d_full_defconfig
+@@ -0,0 +1,2433 @@
++#
++# Automatically generated file; DO NOT EDIT.
++# Linux/arm 3.18.20 Kernel Configuration
++#
++CONFIG_ARM=y
++CONFIG_ARM_HAS_SG_CHAIN=y
++CONFIG_MIGHT_HAVE_PCI=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=y
++CONFIG_HAVE_PROC_CPU=y
++CONFIG_STACKTRACE_SUPPORT=y
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
++CONFIG_RWSEM_XCHGADD_ALGORITHM=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_NEED_DMA_MAP_STATE=y
++CONFIG_ARCH_SUPPORTS_UPROBES=y
++CONFIG_VECTORS_BASE=0xffff0000
++CONFIG_ARM_PATCH_PHYS_VIRT=y
++CONFIG_GENERIC_BUG=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++CONFIG_IRQ_WORK=y
++CONFIG_BUILDTIME_EXTABLE_SORT=y
++
++#
++# General setup
++#
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_CROSS_COMPILE=""
++# CONFIG_COMPILE_TEST is not set
++CONFIG_LOCALVERSION=""
++# CONFIG_LOCALVERSION_AUTO is not set
++CONFIG_HAVE_KERNEL_GZIP=y
++CONFIG_HAVE_KERNEL_LZMA=y
++CONFIG_HAVE_KERNEL_XZ=y
++CONFIG_HAVE_KERNEL_LZO=y
++CONFIG_HAVE_KERNEL_LZ4=y
++CONFIG_KERNEL_GZIP=y
++# CONFIG_KERNEL_LZMA is not set
++# CONFIG_KERNEL_XZ is not set
++# CONFIG_KERNEL_LZO is not set
++# CONFIG_KERNEL_LZ4 is not set
++CONFIG_DEFAULT_HOSTNAME="(none)"
++# CONFIG_SWAP is not set
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++# CONFIG_POSIX_MQUEUE is not set
++CONFIG_CROSS_MEMORY_ATTACH=y
++# CONFIG_FHANDLE is not set
++CONFIG_USELIB=y
++# CONFIG_AUDIT is not set
++
++#
++# IRQ subsystem
++#
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_GENERIC_IRQ_SHOW=y
++CONFIG_HARDIRQS_SW_RESEND=y
++CONFIG_IRQ_DOMAIN=y
++CONFIG_HANDLE_DOMAIN_IRQ=y
++CONFIG_IRQ_FORCED_THREADING=y
++CONFIG_SPARSE_IRQ=y
++CONFIG_GENERIC_CLOCKEVENTS=y
++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
++CONFIG_ARCH_HAS_TICK_BROADCAST=y
++CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
++
++#
++# Timers subsystem
++#
++CONFIG_HZ_PERIODIC=y
++# CONFIG_NO_HZ_IDLE is not set
++# CONFIG_NO_HZ_FULL is not set
++# CONFIG_NO_HZ is not set
++# CONFIG_HIGH_RES_TIMERS is not set
++
++#
++# CPU/Task time and stats accounting
++#
++CONFIG_TICK_CPU_ACCOUNTING=y
++# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set
++# CONFIG_IRQ_TIME_ACCOUNTING is not set
++# CONFIG_BSD_PROCESS_ACCT is not set
++# CONFIG_TASKSTATS is not set
++
++#
++# RCU Subsystem
++#
++CONFIG_TREE_RCU=y
++# CONFIG_PREEMPT_RCU is not set
++# CONFIG_TASKS_RCU is not set
++CONFIG_RCU_STALL_COMMON=y
++# CONFIG_RCU_USER_QS is not set
++CONFIG_RCU_FANOUT=32
++CONFIG_RCU_FANOUT_LEAF=16
++# CONFIG_RCU_FANOUT_EXACT is not set
++# CONFIG_TREE_RCU_TRACE is not set
++# CONFIG_RCU_NOCB_CPU is not set
++# CONFIG_BUILD_BIN2C is not set
++# CONFIG_IKCONFIG is not set
++CONFIG_LOG_BUF_SHIFT=17
++CONFIG_LOG_CPU_MAX_BUF_SHIFT=12
++CONFIG_GENERIC_SCHED_CLOCK=y
++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_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_USER_NS is not set
++CONFIG_PID_NS=y
++CONFIG_NET_NS=y
++# 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=y
++CONFIG_RD_LZMA=y
++CONFIG_RD_XZ=y
++CONFIG_RD_LZO=y
++CONFIG_RD_LZ4=y
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++CONFIG_HAVE_UID16=y
++CONFIG_BPF=y
++# CONFIG_EXPERT is not set
++CONFIG_UID16=y
++# CONFIG_SGETMASK_SYSCALL is not set
++CONFIG_SYSFS_SYSCALL=y
++# CONFIG_SYSCTL_SYSCALL is not set
++CONFIG_KALLSYMS=y
++# CONFIG_KALLSYMS_ALL is not set
++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_BPF_SYSCALL is not set
++CONFIG_SHMEM=y
++CONFIG_AIO=y
++CONFIG_ADVISE_SYSCALLS=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 is not set
++# CONFIG_SLAB is not set
++CONFIG_SLUB=y
++CONFIG_SLUB_CPU_PARTIAL=y
++# CONFIG_PROFILING is not set
++CONFIG_HAVE_OPROFILE=y
++# CONFIG_KPROBES is not set
++# CONFIG_JUMP_LABEL is not set
++# CONFIG_UPROBES is not set
++# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
++CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
++CONFIG_ARCH_USE_BUILTIN_BSWAP=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_GENERIC_SMP_IDLE_THREAD=y
++CONFIG_GENERIC_IDLE_POLL_SETUP=y
++CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
++CONFIG_HAVE_CLK=y
++CONFIG_HAVE_DMA_API_DEBUG=y
++CONFIG_HAVE_PERF_REGS=y
++CONFIG_HAVE_PERF_USER_STACK_DUMP=y
++CONFIG_HAVE_ARCH_JUMP_LABEL=y
++CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
++CONFIG_HAVE_CC_STACKPROTECTOR=y
++# CONFIG_CC_STACKPROTECTOR is not set
++CONFIG_CC_STACKPROTECTOR_NONE=y
++# CONFIG_CC_STACKPROTECTOR_REGULAR is not set
++# CONFIG_CC_STACKPROTECTOR_STRONG is not set
++CONFIG_HAVE_CONTEXT_TRACKING=y
++CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
++CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
++CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
++CONFIG_MODULES_USE_ELF_REL=y
++CONFIG_CLONE_BACKWARDS=y
++CONFIG_OLD_SIGSUSPEND3=y
++CONFIG_OLD_SIGACTION=y
++
++#
++# GCOV-based kernel profiling
++#
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_SLABINFO=y
++CONFIG_RT_MUTEXES=y
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++# CONFIG_MODULE_FORCE_LOAD is not set
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++# CONFIG_MODULE_SIG is not set
++# CONFIG_MODULE_COMPRESS is not set
++CONFIG_STOP_MACHINE=y
++CONFIG_BLOCK=y
++CONFIG_LBDAF=y
++CONFIG_BLK_DEV_BSG=y
++# CONFIG_BLK_DEV_BSGLIB is not set
++# CONFIG_BLK_DEV_INTEGRITY is not set
++CONFIG_BLK_CMDLINE_PARSER=y
++
++#
++# Partition Types
++#
++CONFIG_PARTITION_ADVANCED=y
++# CONFIG_ACORN_PARTITION is not set
++# CONFIG_AIX_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=y
++# CONFIG_SYSV68_PARTITION is not set
++CONFIG_CMDLINE_PARTITION=y
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++CONFIG_DEFAULT_DEADLINE=y
++# CONFIG_DEFAULT_CFQ is not set
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="deadline"
++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_ARCH_SUPPORTS_ATOMIC_RMW=y
++CONFIG_MUTEX_SPIN_ON_OWNER=y
++CONFIG_RWSEM_SPIN_ON_OWNER=y
++CONFIG_FREEZER=y
++
++#
++# System Type
++#
++CONFIG_MMU=y
++CONFIG_ARCH_MULTIPLATFORM=y
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_AT91 is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_GEMINI is not set
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_IOP13XX is not set
++# CONFIG_ARCH_IOP32X is not set
++# CONFIG_ARCH_IOP33X is not set
++# CONFIG_ARCH_IXP4XX is not set
++# CONFIG_ARCH_DOVE is not set
++# CONFIG_ARCH_MV78XX0 is not set
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_MMP is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_W90X900 is not set
++# CONFIG_ARCH_LPC32XX is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_MSM is not set
++# CONFIG_ARCH_SHMOBILE_LEGACY 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_DAVINCI is not set
++# CONFIG_ARCH_OMAP1 is not set
++
++#
++# Multiple platform selection
++#
++
++#
++# CPU Core family selection
++#
++# CONFIG_ARCH_MULTI_V6 is not set
++CONFIG_ARCH_MULTI_V7=y
++CONFIG_ARCH_MULTI_V6_V7=y
++# CONFIG_ARCH_MULTI_CPU_AUTO is not set
++# CONFIG_ARCH_VIRT is not set
++# CONFIG_ARCH_MVEBU is not set
++# CONFIG_ARCH_BCM is not set
++# CONFIG_ARCH_BERLIN is not set
++# CONFIG_ARCH_HIGHBANK is not set
++CONFIG_ARCH_HISI=y
++
++#
++# Hisilicon platform type
++#
++# CONFIG_ARCH_HI3xxx is not set
++# CONFIG_ARCH_HIP04 is not set
++# CONFIG_ARCH_HIX5HD2 is not set
++# CONFIG_ARCH_HI3519 is not set
++# CONFIG_ARCH_HI3519V101 is not set
++# CONFIG_ARCH_HI3516AV200 is not set
++# CONFIG_ARCH_HI3559 is not set
++# CONFIG_ARCH_HI3556 is not set
++# CONFIG_ARCH_HI3536C is not set
++# CONFIG_ARCH_HI3531D is not set
++CONFIG_ARCH_HI3521D=y
++# CONFIG_ARCH_KEYSTONE is not set
++# CONFIG_ARCH_MESON is not set
++# CONFIG_ARCH_MXC is not set
++# CONFIG_ARCH_MEDIATEK is not set
++
++#
++# TI OMAP/AM/DM/DRA Family
++#
++# CONFIG_ARCH_OMAP3 is not set
++# CONFIG_ARCH_OMAP4 is not set
++# CONFIG_SOC_OMAP5 is not set
++# CONFIG_SOC_AM33XX is not set
++# CONFIG_SOC_AM43XX is not set
++# CONFIG_SOC_DRA7XX is not set
++# CONFIG_ARCH_QCOM is not set
++# CONFIG_ARCH_ROCKCHIP is not set
++# CONFIG_ARCH_SOCFPGA is not set
++# CONFIG_PLAT_SPEAR is not set
++# CONFIG_ARCH_STI is not set
++# CONFIG_ARCH_S5PV210 is not set
++# CONFIG_ARCH_EXYNOS is not set
++# CONFIG_ARCH_SHMOBILE_MULTI is not set
++# CONFIG_ARCH_SUNXI is not set
++# CONFIG_ARCH_SIRF is not set
++# CONFIG_ARCH_TEGRA is not set
++# CONFIG_ARCH_U8500 is not set
++# CONFIG_ARCH_VEXPRESS is not set
++# CONFIG_ARCH_WM8850 is not set
++# CONFIG_ARCH_ZYNQ is not set
++CONFIG_ARM_TIMER_SP804=y
++
++#
++# Processor Type
++#
++CONFIG_CPU_V7=y
++CONFIG_CPU_32v6K=y
++CONFIG_CPU_32v7=y
++CONFIG_CPU_ABRT_EV7=y
++CONFIG_CPU_PABRT_V7=y
++CONFIG_CPU_CACHE_V7=y
++CONFIG_CPU_CACHE_VIPT=y
++CONFIG_CPU_COPY_V6=y
++CONFIG_CPU_TLB_V7=y
++CONFIG_CPU_HAS_ASID=y
++CONFIG_CPU_CP15=y
++CONFIG_CPU_CP15_MMU=y
++
++#
++# Processor Features
++#
++# CONFIG_ARM_LPAE is not set
++# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
++CONFIG_ARM_THUMB=y
++# CONFIG_ARM_THUMBEE is not set
++CONFIG_ARM_VIRT_EXT=y
++CONFIG_SWP_EMULATE=y
++# CONFIG_CPU_ICACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_DISABLE is not set
++# CONFIG_CPU_BPREDICT_DISABLE is not set
++CONFIG_KUSER_HELPERS=y
++CONFIG_MIGHT_HAVE_CACHE_L2X0=y
++# CONFIG_CACHE_L2X0 is not set
++CONFIG_ARM_L1_CACHE_SHIFT_6=y
++CONFIG_ARM_L1_CACHE_SHIFT=6
++CONFIG_ARM_DMA_MEM_BUFFERABLE=y
++CONFIG_MULTI_IRQ_HANDLER=y
++# CONFIG_ARM_ERRATA_430973 is not set
++# CONFIG_ARM_ERRATA_643719 is not set
++# CONFIG_ARM_ERRATA_720789 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_ARM_ERRATA_775420 is not set
++# CONFIG_ARM_ERRATA_798181 is not set
++# CONFIG_ARM_ERRATA_773022 is not set
++
++#
++# Bus support
++#
++CONFIG_ARM_AMBA=y
++# CONFIG_PCI is not set
++# 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_DISABLE_CPU_SCHED_DOMAIN_BALANCE is not set
++CONFIG_HAVE_ARM_SCU=y
++CONFIG_HAVE_ARM_ARCH_TIMER=y
++# CONFIG_MCPM is not set
++# CONFIG_BIG_LITTLE is not set
++CONFIG_VMSPLIT_3G=y
++# CONFIG_VMSPLIT_2G is not set
++# CONFIG_VMSPLIT_1G is not set
++CONFIG_PAGE_OFFSET=0xC0000000
++CONFIG_NR_CPUS=4
++CONFIG_HOTPLUG_CPU=y
++# CONFIG_ARM_PSCI is not set
++CONFIG_ARCH_NR_GPIO=0
++CONFIG_PREEMPT_NONE=y
++# CONFIG_PREEMPT_VOLUNTARY is not set
++# CONFIG_PREEMPT is not set
++CONFIG_HZ_FIXED=0
++CONFIG_HZ_100=y
++# CONFIG_HZ_200 is not set
++# CONFIG_HZ_250 is not set
++# CONFIG_HZ_300 is not set
++# CONFIG_HZ_500 is not set
++# CONFIG_HZ_1000 is not set
++CONFIG_HZ=100
++# CONFIG_SCHED_HRTICK is not set
++# CONFIG_THUMB2_KERNEL is not set
++CONFIG_AEABI=y
++CONFIG_OABI_COMPAT=y
++# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
++# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
++CONFIG_HAVE_ARCH_PFN_VALID=y
++CONFIG_HIGHMEM=y
++# CONFIG_HIGHPTE is not set
++CONFIG_ARCH_WANT_GENERAL_HUGETLB=y
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_HAVE_MEMBLOCK=y
++CONFIG_NO_BOOTMEM=y
++# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=4
++CONFIG_COMPACTION=y
++CONFIG_MIGRATION=y
++# CONFIG_PHYS_ADDR_T_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_BOUNCE=y
++# CONFIG_KSM is not set
++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
++# CONFIG_CLEANCACHE is not set
++# CONFIG_CMA is not set
++# CONFIG_ZPOOL is not set
++# CONFIG_ZBUD is not set
++# CONFIG_ZSMALLOC 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_SWIOTLB=y
++CONFIG_IOMMU_HELPER=y
++# CONFIG_XEN is not set
++# CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART is not set
++
++#
++# Boot options
++#
++CONFIG_USE_OF=y
++CONFIG_ATAGS=y
++# CONFIG_DEPRECATED_PARAM_STRUCT is not set
++# CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE is not set
++CONFIG_ZBOOT_ROM_TEXT=0
++CONFIG_ZBOOT_ROM_BSS=0
++CONFIG_ARM_APPENDED_DTB=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_KEXEC is not set
++# CONFIG_CRASH_DUMP is not set
++CONFIG_AUTO_ZRELADDR=y
++
++#
++# CPU Power Management
++#
++
++#
++# CPU Frequency scaling
++#
++CONFIG_CPU_FREQ=y
++CONFIG_CPU_FREQ_STAT=y
++# CONFIG_CPU_FREQ_STAT_DETAILS is not set
++CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
++# CONFIG_CPU_FREQ_DEFAULT_GOV_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_DEFAULT_GOV_INTERACTIVE is not set
++CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
++# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
++# CONFIG_CPU_FREQ_GOV_USERSPACE is not set
++# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
++# CONFIG_CPU_FREQ_GOV_INTERACTIVE is not set
++# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
++CONFIG_CPUFREQ_DT=y
++
++#
++# ARM CPU frequency scaling drivers
++#
++# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set
++
++#
++# CPU Idle
++#
++# CONFIG_CPU_IDLE is not set
++# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++# CONFIG_FPE_NWFPE is not set
++# CONFIG_FPE_FASTFPE is not set
++CONFIG_VFP=y
++CONFIG_VFPv3=y
++CONFIG_NEON=y
++CONFIG_KERNEL_MODE_NEON=y
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
++CONFIG_BINFMT_SCRIPT=y
++# CONFIG_HAVE_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
++CONFIG_COREDUMP=y
++
++#
++# Power management options
++#
++CONFIG_SUSPEND=y
++CONFIG_SUSPEND_FREEZER=y
++CONFIG_WAKELOCK=y
++# CONFIG_HISI_SNAPSHOT_BOOT is not set
++CONFIG_PM_SLEEP=y
++CONFIG_PM_SLEEP_SMP=y
++# CONFIG_PM_AUTOSLEEP is not set
++# CONFIG_PM_WAKELOCKS is not set
++# CONFIG_PM_RUNTIME is not set
++CONFIG_PM=y
++# CONFIG_PM_DEBUG is not set
++# CONFIG_APM_EMULATION is not set
++CONFIG_PM_OPP=y
++CONFIG_PM_CLK=y
++# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set
++CONFIG_CPU_PM=y
++# CONFIG_SUSPEND_TIME is not set
++CONFIG_ARCH_SUSPEND_POSSIBLE=y
++CONFIG_ARM_CPU_SUSPEND=y
++CONFIG_ARCH_HIBERNATION_POSSIBLE=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=y
++# 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_NET_IP_TUNNEL=m
++# CONFIG_IP_MROUTE is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_NET_UDP_TUNNEL is not set
++# CONFIG_NET_FOU is not set
++# CONFIG_GENEVE 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 is not set
++# CONFIG_INET_XFRM_MODE_TUNNEL is not set
++# CONFIG_INET_XFRM_MODE_BEET is not set
++CONFIG_INET_LRO=y
++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=y
++# 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_VTI 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_ANDROID_PARANOID_NETWORK is not set
++CONFIG_NET_ACTIVITY_STATS=y
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NET_PTP_CLASSIFY 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_NF_TABLES is not set
++# CONFIG_NETFILTER_XTABLES is not set
++# CONFIG_IP_SET is not set
++# CONFIG_IP_VS is not set
++
++#
++# IP: Netfilter Configuration
++#
++# CONFIG_NF_DEFRAG_IPV4 is not set
++# CONFIG_NF_LOG_ARP is not set
++# CONFIG_NF_LOG_IPV4 is not set
++# CONFIG_NF_REJECT_IPV4 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_NF_REJECT_IPV6 is not set
++# CONFIG_NF_LOG_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_HAVE_NET_DSA=y
++# 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_PHONET is not set
++# CONFIG_6LOWPAN 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_VSOCKETS is not set
++# CONFIG_NETLINK_MMAP is not set
++# CONFIG_NETLINK_DIAG is not set
++# CONFIG_NET_MPLS_GSO is not set
++# CONFIG_HSR is not set
++CONFIG_RPS=y
++CONFIG_RFS_ACCEL=y
++CONFIG_XPS=y
++# CONFIG_CGROUP_NET_PRIO is not set
++# CONFIG_CGROUP_NET_CLASSID is not set
++CONFIG_NET_RX_BUSY_POLL=y
++CONFIG_BQL=y
++# CONFIG_BPF_JIT is not set
++CONFIG_NET_FLOW_LIMIT=y
++
++#
++# 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 is not set
++# 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 is not set
++CONFIG_DEVTMPFS=y
++# CONFIG_DEVTMPFS_MOUNT is not set
++CONFIG_STANDALONE=y
++# CONFIG_PREVENT_FIRMWARE_BUILD is not set
++CONFIG_FW_LOADER=y
++CONFIG_FIRMWARE_IN_KERNEL=y
++CONFIG_EXTRA_FIRMWARE=""
++# CONFIG_FW_LOADER_USER_HELPER_FALLBACK is not set
++CONFIG_ALLOW_DEV_COREDUMP=y
++# 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_HAVE_CPU_AUTOPROBE is not set
++CONFIG_REGMAP=y
++CONFIG_REGMAP_MMIO=y
++# CONFIG_DMA_SHARED_BUFFER is not set
++
++#
++# Bus devices
++#
++# CONFIG_BRCMSTB_GISB_ARB is not set
++# CONFIG_ARM_CCI is not set
++# CONFIG_VEXPRESS_CONFIG 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=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_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_HIFMC=y
++CONFIG_HIFMC_SPI_NAND=y
++# CONFIG_HIFMC_NAND is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++# CONFIG_MTD_CFI is not set
++# CONFIG_MTD_JEDECPROBE is not set
++CONFIG_MTD_MAP_BANK_WIDTH_1=y
++CONFIG_MTD_MAP_BANK_WIDTH_2=y
++CONFIG_MTD_MAP_BANK_WIDTH_4=y
++# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
++CONFIG_MTD_CFI_I1=y
++CONFIG_MTD_CFI_I2=y
++# CONFIG_MTD_CFI_I4 is not set
++# CONFIG_MTD_CFI_I8 is not set
++# CONFIG_MTD_RAM is not set
++# CONFIG_MTD_ROM is not set
++# CONFIG_MTD_ABSENT is not set
++
++#
++# Mapping drivers for chip access
++#
++# CONFIG_MTD_COMPLEX_MAPPINGS is not set
++# CONFIG_MTD_PLATRAM is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_DATAFLASH is not set
++# CONFIG_MTD_M25P80 is not set
++# CONFIG_MTD_SST25L is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_PHRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++CONFIG_MTD_BLOCK2MTD=y
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOCG3 is not set
++CONFIG_MTD_NAND_IDS=y
++CONFIG_MTD_NAND_ECC=y
++# CONFIG_MTD_NAND_ECC_SMC is not set
++CONFIG_MTD_NAND=y
++# CONFIG_MTD_NAND_ECC_BCH is not set
++# CONFIG_MTD_SM_COMMON is not set
++# CONFIG_MTD_NAND_DENALI is not set
++# CONFIG_MTD_NAND_OMAP_BCH_BUILD is not set
++# CONFIG_MTD_NAND_DISKONCHIP is not set
++# CONFIG_MTD_NAND_DOCG4 is not set
++# CONFIG_MTD_NAND_NANDSIM is not set
++# CONFIG_MTD_NAND_PLATFORM is not set
++# CONFIG_HISI_NAND_FS_MAY_NO_YAFFS2 is not set
++# CONFIG_HISI_NAND_ECC_STATUS_REPORT is not set
++# CONFIG_MTD_NAND_HINFC610 is not set
++# CONFIG_HIFMC100_NAND is not set
++CONFIG_HIFMC100_SPI_NAND=y
++CONFIG_SPI_NAND_MAX_CHIP_NUM=1
++# CONFIG_HIFMC100_HARDWARE_PAGESIZE_ECC is not set
++CONFIG_HIFMC100_AUTO_PAGESIZE_ECC=y
++# CONFIG_HIFMC100_PAGESIZE_AUTO_ECC_NONE is not set
++# CONFIG_MTD_ONENAND is not set
++
++#
++# LPDDR & LPDDR2 PCM memory drivers
++#
++# CONFIG_MTD_LPDDR is not set
++# CONFIG_MTD_LPDDR2_NVM is not set
++CONFIG_MTD_SPI_NOR=y
++# CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set
++CONFIG_SPI_HISI_SFC=y
++CONFIG_CLOSE_SPI_8PIN_4IO=y
++CONFIG_HISI_SPI_BLOCK_PROTECT=y
++CONFIG_MTD_UBI=y
++CONFIG_MTD_UBI_WL_THRESHOLD=4096
++CONFIG_MTD_UBI_BEB_LIMIT=20
++# CONFIG_MTD_UBI_FASTMAP is not set
++# CONFIG_MTD_UBI_GLUEBI is not set
++# CONFIG_MTD_UBI_BLOCK is not set
++CONFIG_DTC=y
++CONFIG_OF=y
++
++#
++# Device Tree and Open Firmware support
++#
++# 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_NET=y
++CONFIG_OF_MDIO=y
++CONFIG_OF_MTD=y
++CONFIG_OF_RESERVED_MEM=y
++CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
++# CONFIG_PARPORT is not set
++CONFIG_BLK_DEV=y
++# CONFIG_BLK_DEV_NULL_BLK is not set
++# CONFIG_BLK_DEV_COW_COMMON is not set
++# CONFIG_BLK_DEV_LOOP 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=65536
++# CONFIG_BLK_DEV_XIP is not set
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH 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_DUMMY_IRQ 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_UID_STAT is not set
++# CONFIG_BMP085_I2C is not set
++# CONFIG_BMP085_SPI is not set
++# CONFIG_USB_SWITCH_FSA9480 is not set
++# CONFIG_LATTICE_ECP3_CONFIG is not set
++# CONFIG_SRAM is not set
++# CONFIG_C2PORT is not set
++
++#
++# EEPROM support
++#
++# CONFIG_EEPROM_AT24 is not set
++# CONFIG_EEPROM_AT25 is not set
++# CONFIG_EEPROM_LEGACY is not set
++# CONFIG_EEPROM_MAX6875 is not set
++# CONFIG_EEPROM_93CX6 is not set
++# CONFIG_EEPROM_93XX46 is not set
++
++#
++# Texas Instruments shared transport line discipline
++#
++# 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
++
++#
++# Intel MIC Bus Driver
++#
++
++#
++# Intel MIC Host Driver
++#
++
++#
++# Intel MIC Card Driver
++#
++# CONFIG_ECHO is not set
++# CONFIG_CXL_BASE is not set
++
++#
++# hisi 'himm/himd.l/himc'support
++#
++# CONFIG_HISI_REG 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_NETLINK is not set
++# CONFIG_SCSI_MQ_DEFAULT is not set
++CONFIG_SCSI_PROC_FS=y
++
++#
++# SCSI support type (disk, tape, CD-ROM)
++#
++CONFIG_BLK_DEV_SD=y
++# CONFIG_CHR_DEV_ST is not set
++# CONFIG_CHR_DEV_OSST is not set
++CONFIG_BLK_DEV_SR=y
++# CONFIG_BLK_DEV_SR_VENDOR is not set
++# CONFIG_CHR_DEV_SG is not set
++# CONFIG_CHR_DEV_SCH is not set
++# CONFIG_SCSI_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 is not set
++# CONFIG_SCSI_DH is not set
++# CONFIG_SCSI_OSD_INITIATOR is not set
++CONFIG_HI_SATA=y
++CONFIG_HI_SATA_IOBASE=0x11010000
++CONFIG_HI_SATA_FBS=1
++CONFIG_HI_SATA_NCQ=1
++CONFIG_ATA=y
++# CONFIG_ATA_NONSTANDARD is not set
++CONFIG_ATA_VERBOSE_ERROR=y
++CONFIG_SATA_PMP=y
++
++#
++# Controllers with non-SFF native interface
++#
++CONFIG_SATA_AHCI_PLATFORM=y
++# CONFIG_ATA_SFF is not set
++# CONFIG_MD 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_NET_TEAM is not set
++# CONFIG_MACVLAN is not set
++# CONFIG_VXLAN is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_TUN is not set
++# CONFIG_VETH is not set
++# CONFIG_NLMON is not set
++
++#
++# 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_NET_DSA_MV88E6171 is not set
++# CONFIG_NET_DSA_BCM_SF2 is not set
++CONFIG_ETHERNET=y
++# CONFIG_ALTERA_TSE is not set
++# CONFIG_NET_XGENE is not set
++# CONFIG_NET_VENDOR_ARC is not set
++# CONFIG_NET_CADENCE is not set
++# CONFIG_NET_VENDOR_BROADCOM is not set
++# CONFIG_NET_VENDOR_CIRRUS is not set
++# CONFIG_DM9000 is not set
++# CONFIG_DNET is not set
++# CONFIG_NET_VENDOR_FARADAY is not set
++CONFIG_NET_VENDOR_HISILICON=y
++# CONFIG_HIX5HD2_GMAC is not set
++# CONFIG_HISI_FEMAC is not set
++CONFIG_HIETH_GMAC=y
++CONFIG_HIGMAC_DESC_4WORD=y
++CONFIG_HIGMAC_RXCSUM=y
++CONFIG_RX_FLOW_CTRL_SUPPORT=y
++CONFIG_TX_FLOW_CTRL_SUPPORT=y
++CONFIG_TX_FLOW_CTRL_PAUSE_TIME=0xFFFF
++CONFIG_TX_FLOW_CTRL_PAUSE_INTERVAL=0xFFFF
++CONFIG_TX_FLOW_CTRL_ACTIVE_THRESHOLD=16
++CONFIG_TX_FLOW_CTRL_DEACTIVE_THRESHOLD=32
++# CONFIG_HIETH_SWITCH_FABRIC is not set
++# CONFIG_NET_VENDOR_INTEL is not set
++# CONFIG_NET_VENDOR_MARVELL is not set
++# CONFIG_NET_VENDOR_MICREL is not set
++# CONFIG_NET_VENDOR_MICROCHIP is not set
++# CONFIG_NET_VENDOR_NATSEMI is not set
++# CONFIG_ETHOC is not set
++# CONFIG_NET_VENDOR_QUALCOMM is not set
++# CONFIG_NET_VENDOR_SAMSUNG is not set
++# CONFIG_NET_VENDOR_SEEQ is not set
++# CONFIG_NET_VENDOR_SMSC is not set
++# CONFIG_NET_VENDOR_STMICRO is not set
++# CONFIG_NET_VENDOR_VIA is not set
++# CONFIG_NET_VENDOR_WIZNET is not set
++CONFIG_PHYLIB=y
++
++#
++# MII PHY device drivers
++#
++# CONFIG_AT803X_PHY is not set
++# CONFIG_AMD_PHY is not set
++# CONFIG_AMD_XGBE_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 is not set
++# CONFIG_BROADCOM_PHY is not set
++# CONFIG_BCM7XXX_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_MMIOREG is not set
++# CONFIG_MDIO_BCM_UNIMAC is not set
++# CONFIG_MDIO_HISI_FEMAC is not set
++CONFIG_MDIO_HISI_GEMAC=y
++# CONFIG_MICREL_KS8995MA is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++CONFIG_USB_NET_DRIVERS=y
++# 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_RTL8152 is not set
++# CONFIG_USB_USBNET is not set
++# CONFIG_USB_IPHETH is not set
++# CONFIG_WLAN is not set
++
++#
++# Enable WiMAX (Networking options) to see the WiMAX drivers
++#
++# CONFIG_WAN is not set
++# CONFIG_ISDN is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
++# CONFIG_INPUT_POLLDEV is not set
++# CONFIG_INPUT_SPARSEKMAP is not set
++# CONFIG_INPUT_MATRIXKMAP is not set
++
++#
++# Userland interfaces
++#
++CONFIG_INPUT_MOUSEDEV=y
++CONFIG_INPUT_MOUSEDEV_PSAUX=y
++CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
++CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
++CONFIG_INPUT_JOYDEV=y
++CONFIG_INPUT_EVDEV=y
++# CONFIG_INPUT_EVBUG is not set
++# CONFIG_INPUT_KEYRESET is not set
++# CONFIG_INPUT_KEYCOMBO 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_TCA6416 is not set
++# CONFIG_KEYBOARD_TCA8418 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 is not set
++# CONFIG_KEYBOARD_CAP1106 is not set
++CONFIG_INPUT_MOUSE=y
++CONFIG_MOUSE_PS2=y
++CONFIG_MOUSE_PS2_ALPS=y
++CONFIG_MOUSE_PS2_LOGIPS2PP=y
++CONFIG_MOUSE_PS2_SYNAPTICS=y
++CONFIG_MOUSE_PS2_CYPRESS=y
++CONFIG_MOUSE_PS2_TRACKPOINT=y
++# CONFIG_MOUSE_PS2_ELANTECH is not set
++# CONFIG_MOUSE_PS2_SENTELIC is not set
++# CONFIG_MOUSE_PS2_TOUCHKIT is not set
++# CONFIG_MOUSE_SERIAL is not set
++# CONFIG_MOUSE_APPLETOUCH is not set
++# CONFIG_MOUSE_BCM5974 is not set
++# CONFIG_MOUSE_CYAPA is not set
++# CONFIG_MOUSE_VSXXXAA is not set
++# CONFIG_MOUSE_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 is not set
++# CONFIG_INPUT_MISC is not set
++
++#
++# Hardware I/O ports
++#
++CONFIG_SERIO=y
++CONFIG_SERIO_SERPORT=y
++# CONFIG_SERIO_AMBAKMI is not set
++CONFIG_SERIO_LIBPS2=y
++# CONFIG_SERIO_RAW is not set
++# CONFIG_SERIO_ALTERA_PS2 is not set
++# CONFIG_SERIO_PS2MULT is not set
++# CONFIG_SERIO_ARC_PS2 is not set
++# CONFIG_SERIO_APBPS2 is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++CONFIG_TTY=y
++CONFIG_VT=y
++CONFIG_CONSOLE_TRANSLATIONS=y
++CONFIG_VT_CONSOLE=y
++CONFIG_VT_CONSOLE_SLEEP=y
++CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
++CONFIG_UNIX98_PTYS=y
++# CONFIG_DEVPTS_MULTIPLE_INSTANCES 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_DEVMEM=y
++# CONFIG_DEVKMEM is not set
++
++#
++# Serial drivers
++#
++CONFIG_SERIAL_EARLYCON=y
++# CONFIG_SERIAL_8250 is not set
++
++#
++# Non-8250 serial port support
++#
++# CONFIG_SERIAL_AMBA_PL010 is not set
++CONFIG_SERIAL_AMBA_PL011=y
++CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
++# CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST is not set
++# 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_SC16IS7XX is not set
++# CONFIG_SERIAL_ALTERA_JTAGUART is not set
++# CONFIG_SERIAL_ALTERA_UART is not set
++# CONFIG_SERIAL_XILINX_PS_UART is not set
++# CONFIG_SERIAL_ARC is not set
++# CONFIG_SERIAL_FSL_LPUART is not set
++# CONFIG_SERIAL_ST_ASC is not set
++# CONFIG_HVC_DCC is not set
++# CONFIG_IPMI_HANDLER is not set
++# CONFIG_HW_RANDOM is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++# CONFIG_DCC_TTY is not set
++# CONFIG_XILLYBUS is not set
++
++#
++# I2C support
++#
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++CONFIG_I2C_COMPAT=y
++CONFIG_I2C_CHARDEV=y
++CONFIG_I2C_MUX=y
++
++#
++# Multiplexer I2C Chip support
++#
++# CONFIG_I2C_MUX_PCA9541 is not set
++# CONFIG_I2C_MUX_PINCTRL is not set
++CONFIG_I2C_HELPER_AUTO=y
++
++#
++# I2C Hardware Bus support
++#
++
++#
++# I2C system bus drivers (mostly embedded / system-on-chip)
++#
++# CONFIG_I2C_DESIGNWARE_PLATFORM is not set
++# CONFIG_I2C_HIBVT is not set
++# CONFIG_I2C_HISI_V110 is not set
++# CONFIG_I2C_NOMADIK 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_RK3X 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_ROBOTFUZZ_OSIF is not set
++# CONFIG_I2C_TAOS_EVM is not set
++# CONFIG_I2C_TINY_USB is not set
++
++#
++# Other I2C/SMBus bus drivers
++#
++CONFIG_HI_I2C=y
++CONFIG_HI_I2C0_IO_BASE=0x120c0000
++CONFIG_HI_I2C0_IO_SIZE=0x1000
++CONFIG_HI_I2C_RETRIES=0x1
++CONFIG_HI_I2C_TX_FIFO=0x8
++CONFIG_HI_I2C_RX_FIFO=0x8
++CONFIG_HI_I2C0_CLK_LIMIT=100000
++# 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_CADENCE is not set
++# CONFIG_SPI_FSL_SPI is not set
++CONFIG_SPI_PL022=y
++# CONFIG_SPI_PXA2XX_PCI is not set
++# CONFIG_SPI_ROCKCHIP 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=y
++# CONFIG_SPI_TLE62X0 is not set
++# CONFIG_SPMI is not set
++# CONFIG_HSI is not set
++
++#
++# PPS support
++#
++# CONFIG_PPS is not set
++
++#
++# PPS generators support
++#
++
++#
++# PTP clock support
++#
++# CONFIG_PTP_1588_CLOCK is not set
++
++#
++# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
++#
++CONFIG_PINCTRL=y
++
++#
++# Pin controllers
++#
++CONFIG_PINMUX=y
++CONFIG_PINCONF=y
++CONFIG_GENERIC_PINCONF=y
++# CONFIG_DEBUG_PINCTRL is not set
++CONFIG_PINCTRL_SINGLE=y
++CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
++CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
++# CONFIG_GPIOLIB is not set
++# CONFIG_W1 is not set
++CONFIG_POWER_SUPPLY=y
++# CONFIG_POWER_SUPPLY_DEBUG is not set
++# CONFIG_PDA_POWER is not set
++# CONFIG_TEST_POWER is not set
++# CONFIG_BATTERY_DS2780 is not set
++# CONFIG_BATTERY_DS2781 is not set
++# CONFIG_BATTERY_DS2782 is not set
++# CONFIG_BATTERY_SBS is not set
++# CONFIG_BATTERY_BQ27x00 is not set
++# CONFIG_BATTERY_MAX17040 is not set
++# CONFIG_BATTERY_MAX17042 is not set
++# CONFIG_CHARGER_MAX8903 is not set
++# CONFIG_CHARGER_LP8727 is not set
++# CONFIG_CHARGER_BQ2415X is not set
++# CONFIG_CHARGER_SMB347 is not set
++CONFIG_POWER_RESET=y
++# CONFIG_POWER_RESET_BRCMSTB is not set
++CONFIG_POWER_RESET_HISI=y
++# CONFIG_POWER_RESET_RESTART is not set
++# CONFIG_POWER_RESET_VERSATILE is not set
++# CONFIG_POWER_RESET_SYSCON is not set
++# CONFIG_POWER_AVS is not set
++# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
++# CONFIG_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=y
++# CONFIG_MFD_AS3711 is not set
++# CONFIG_MFD_AS3722 is not set
++# CONFIG_PMIC_ADP5520 is not set
++# CONFIG_MFD_BCM590XX is not set
++# CONFIG_MFD_AXP20X is not set
++# CONFIG_MFD_CROS_EC is not set
++# CONFIG_PMIC_DA903X is not set
++# CONFIG_MFD_DA9052_SPI is not set
++# CONFIG_MFD_DA9052_I2C is not set
++# CONFIG_MFD_DA9055 is not set
++# CONFIG_MFD_DA9063 is not set
++# CONFIG_MFD_MC13XXX_SPI is not set
++# CONFIG_MFD_MC13XXX_I2C is not set
++# CONFIG_MFD_HI6421_PMIC is not set
++CONFIG_MFD_HISI_FMC=y
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_INTEL_SOC_PMIC is not set
++# CONFIG_MFD_KEMPLD is not set
++# CONFIG_MFD_88PM800 is not set
++# CONFIG_MFD_88PM805 is not set
++# CONFIG_MFD_88PM860X is not set
++# CONFIG_MFD_MAX14577 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_MENF21BMC is not set
++# CONFIG_EZX_PCAP is not set
++# CONFIG_MFD_VIPERBOARD is not set
++# CONFIG_MFD_RETU is not set
++# CONFIG_MFD_PCF50633 is not set
++# CONFIG_MFD_PM8921_CORE is not set
++# CONFIG_MFD_RTSX_USB is not set
++# CONFIG_MFD_RC5T583 is not set
++# CONFIG_MFD_RK808 is not set
++# CONFIG_MFD_RN5T618 is not set
++# CONFIG_MFD_SEC_CORE is not set
++# CONFIG_MFD_SI476X_CORE is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_MFD_SMSC is not set
++# CONFIG_ABX500_CORE is not set
++# CONFIG_MFD_STMPE is not set
++CONFIG_MFD_SYSCON=y
++# CONFIG_MFD_TI_AM335X_TSCADC is not set
++# CONFIG_MFD_LP3943 is not set
++# CONFIG_MFD_LP8788 is not set
++# CONFIG_MFD_PALMAS is not set
++# CONFIG_TPS6105X is not set
++# CONFIG_TPS6507X is not set
++# CONFIG_MFD_TPS65090 is not set
++# CONFIG_MFD_TPS65217 is not set
++# CONFIG_MFD_TPS65218 is not set
++# CONFIG_MFD_TPS6586X is not set
++# CONFIG_MFD_TPS80031 is not set
++# CONFIG_TWL4030_CORE is not set
++# CONFIG_TWL6040_CORE is not set
++# CONFIG_MFD_WL1273_CORE is not set
++# CONFIG_MFD_LM3533 is not set
++# CONFIG_MFD_TC3589X is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_MFD_T7L66XB is not set
++# CONFIG_MFD_TC6387XB is not set
++# CONFIG_MFD_TC6393XB is not set
++# CONFIG_MFD_ARIZONA_I2C is not set
++# CONFIG_MFD_ARIZONA_SPI is not set
++# CONFIG_MFD_WM8400 is not set
++# CONFIG_MFD_WM831X_I2C is not set
++# CONFIG_MFD_WM831X_SPI is not set
++# CONFIG_MFD_WM8350_I2C is not set
++# CONFIG_MFD_WM8994 is not set
++CONFIG_REGULATOR=y
++# CONFIG_REGULATOR_DEBUG is not set
++# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
++# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
++# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
++# CONFIG_REGULATOR_ACT8865 is not set
++# CONFIG_REGULATOR_AD5398 is not set
++# CONFIG_REGULATOR_ANATOP is not set
++# CONFIG_REGULATOR_DA9210 is not set
++# CONFIG_REGULATOR_DA9211 is not set
++# CONFIG_REGULATOR_FAN53555 is not set
++# CONFIG_REGULATOR_ISL9305 is not set
++# CONFIG_REGULATOR_ISL6271A is not set
++# CONFIG_REGULATOR_LP3971 is not set
++# CONFIG_REGULATOR_LP3972 is not set
++# CONFIG_REGULATOR_LP872X is not set
++# CONFIG_REGULATOR_LP8755 is not set
++# CONFIG_REGULATOR_LTC3589 is not set
++# CONFIG_REGULATOR_MAX1586 is not set
++# CONFIG_REGULATOR_MAX8649 is not set
++# CONFIG_REGULATOR_MAX8660 is not set
++# CONFIG_REGULATOR_MAX8952 is not set
++# CONFIG_REGULATOR_MAX8973 is not set
++# CONFIG_REGULATOR_PFUZE100 is not set
++# CONFIG_REGULATOR_TPS51632 is not set
++# CONFIG_REGULATOR_TPS62360 is not set
++# CONFIG_REGULATOR_TPS65023 is not set
++# CONFIG_REGULATOR_TPS6507X is not set
++# CONFIG_REGULATOR_TPS6524X is not set
++# CONFIG_MEDIA_SUPPORT is not set
++
++#
++# Graphics support
++#
++# CONFIG_IMX_IPUV3_CORE is not set
++
++#
++# Direct Rendering Manager
++#
++# CONFIG_DRM is not set
++
++#
++# Frame buffer Devices
++#
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++CONFIG_FB_CMDLINE=y
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++# CONFIG_FB_CFB_FILLRECT is not set
++# CONFIG_FB_CFB_COPYAREA is not set
++# CONFIG_FB_CFB_IMAGEBLIT is not set
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# 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_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_ARMCLCD is not set
++# CONFIG_FB_OPENCORES is not set
++# CONFIG_FB_S1D13XXX is not set
++# CONFIG_FB_SMSCUFX is not set
++# CONFIG_FB_UDL is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_BROADSHEET is not set
++# CONFIG_FB_AUO_K190X is not set
++# CONFIG_FB_SIMPLE is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++# CONFIG_VGASTATE is not set
++
++#
++# Console display driver support
++#
++CONFIG_DUMMY_CONSOLE=y
++# CONFIG_FRAMEBUFFER_CONSOLE is not set
++# CONFIG_LOGO is not set
++# CONFIG_SOUND is not set
++
++#
++# HID support
++#
++CONFIG_HID=y
++# CONFIG_HID_BATTERY_STRENGTH is not set
++# CONFIG_HIDRAW is not set
++# CONFIG_UHID is not set
++CONFIG_HID_GENERIC=y
++
++#
++# Special HID drivers
++#
++CONFIG_HID_A4TECH=y
++# CONFIG_HID_ACRUX is not set
++CONFIG_HID_APPLE=y
++# CONFIG_HID_APPLEIR is not set
++# CONFIG_HID_AUREAL is not set
++CONFIG_HID_BELKIN=y
++CONFIG_HID_CHERRY=y
++CONFIG_HID_CHICONY=y
++CONFIG_HID_CYPRESS=y
++# CONFIG_HID_DRAGONRISE is not set
++# CONFIG_HID_EMS_FF is not set
++# CONFIG_HID_ELECOM is not set
++# CONFIG_HID_ELO is not set
++CONFIG_HID_EZKEY=y
++# CONFIG_HID_HOLTEK is not set
++# CONFIG_HID_HUION 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_ICADE is not set
++# CONFIG_HID_TWINHAN is not set
++CONFIG_HID_KENSINGTON=y
++# CONFIG_HID_LCPOWER is not set
++# CONFIG_HID_LENOVO is not set
++CONFIG_HID_LOGITECH=y
++# CONFIG_HID_LOGITECH_HIDPP is not set
++# CONFIG_LOGITECH_FF is not set
++# CONFIG_LOGIRUMBLEPAD2_FF is not set
++# CONFIG_LOGIG940_FF is not set
++# CONFIG_LOGIWHEELS_FF is not set
++# CONFIG_HID_MAGICMOUSE is not set
++CONFIG_HID_MICROSOFT=y
++CONFIG_HID_MONTEREY=y
++# 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_PENMOUNT is not set
++# CONFIG_HID_PETALYNX is not set
++# CONFIG_HID_PICOLCD is not set
++# CONFIG_HID_PRIMAX is not set
++# CONFIG_HID_ROCCAT is not set
++# CONFIG_HID_SAITEK is not set
++# CONFIG_HID_SAMSUNG is not set
++# CONFIG_HID_SPEEDLINK is not set
++# CONFIG_HID_STEELSERIES is not set
++# CONFIG_HID_SUNPLUS is not set
++# CONFIG_HID_RMI 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_XINMO is not set
++# CONFIG_HID_ZEROPLUS is not set
++# CONFIG_HID_ZYDACRON is not set
++# CONFIG_HID_SENSOR_HUB is not set
++
++#
++# USB HID support
++#
++CONFIG_USB_HID=y
++# CONFIG_HID_PID is not set
++# CONFIG_USB_HIDDEV is not set
++
++#
++# I2C HID support
++#
++# CONFIG_I2C_HID is not set
++CONFIG_USB_OHCI_LITTLE_ENDIAN=y
++CONFIG_USB_SUPPORT=y
++CONFIG_USB_COMMON=y
++CONFIG_USB_ARCH_HAS_HCD=y
++CONFIG_USB=y
++# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
++
++#
++# Miscellaneous USB options
++#
++CONFIG_USB_DEFAULT_PERSIST=y
++# CONFIG_USB_DYNAMIC_MINORS is not set
++# CONFIG_USB_OTG_WHITELIST is not set
++# CONFIG_USB_OTG_FSM is not set
++# CONFIG_USB_MON is not set
++# CONFIG_USB_WUSB_CBAF is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_C67X00_HCD is not set
++# CONFIG_USB_XHCI_HCD is not set
++CONFIG_USB_EHCI_HCD=y
++# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
++CONFIG_USB_EHCI_TT_NEWSCHED=y
++CONFIG_USB_EHCI_HCD_PLATFORM=y
++# 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_FUSBH200_HCD is not set
++# CONFIG_USB_FOTG210_HCD is not set
++# CONFIG_USB_MAX3421_HCD is not set
++CONFIG_USB_OHCI_HCD=y
++CONFIG_USB_OHCI_HCD_PLATFORM=y
++# CONFIG_USB_SL811_HCD is not set
++# CONFIG_USB_R8A66597_HCD is not set
++# CONFIG_USB_HCD_TEST_MODE is not set
++
++#
++# USB Device Class drivers
++#
++# CONFIG_USB_ACM is not set
++# CONFIG_USB_PRINTER is not set
++# CONFIG_USB_WDM is not set
++# CONFIG_USB_TMC is not set
++
++#
++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
++#
++
++#
++# also be needed; see USB_STORAGE Help for more info
++#
++CONFIG_USB_STORAGE=y
++# CONFIG_USB_STORAGE_DEBUG is not set
++# CONFIG_USB_STORAGE_REALTEK is not set
++# CONFIG_USB_STORAGE_DATAFAB is not set
++# CONFIG_USB_STORAGE_FREECOM is not set
++# CONFIG_USB_STORAGE_ISD200 is not set
++# CONFIG_USB_STORAGE_USBAT is not set
++# CONFIG_USB_STORAGE_SDDR09 is not set
++# CONFIG_USB_STORAGE_SDDR55 is not set
++# CONFIG_USB_STORAGE_JUMPSHOT is not set
++# CONFIG_USB_STORAGE_ALAUDA is not set
++# CONFIG_USB_STORAGE_ONETOUCH is not set
++# CONFIG_USB_STORAGE_KARMA is not set
++# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
++# CONFIG_USB_STORAGE_ENE_UB6250 is not set
++# CONFIG_USB_UAS is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++# CONFIG_USBIP_CORE is not set
++# CONFIG_USB_MUSB_HDRC is not set
++# CONFIG_USB_DWC3 is not set
++# CONFIG_USB_DWC2 is not set
++# CONFIG_USB_CHIPIDEA is not set
++
++#
++# USB port drivers
++#
++# CONFIG_USB_SERIAL is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
++# CONFIG_USB_SEVSEG is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
++# CONFIG_USB_APPLEDISPLAY is not set
++# CONFIG_USB_SISUSBVGA is not set
++# CONFIG_USB_LD is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
++# CONFIG_USB_IOWARRIOR is not set
++# CONFIG_USB_TEST is not set
++# CONFIG_USB_EHSET_TEST_FIXTURE is not set
++# CONFIG_USB_ISIGHTFW is not set
++# CONFIG_USB_YUREX is not set
++# CONFIG_USB_EZUSB_FX2 is not set
++# CONFIG_USB_HSIC_USB3503 is not set
++# CONFIG_USB_LINK_LAYER_TEST is not set
++
++#
++# USB Physical Layer drivers
++#
++# CONFIG_USB_PHY is not set
++# CONFIG_USB_OTG_WAKELOCK is not set
++# CONFIG_NOP_USB_XCEIV is not set
++# CONFIG_AM335X_PHY_USB is not set
++# CONFIG_USB_ISP1301 is not set
++# CONFIG_USB_ULPI is not set
++# CONFIG_USB_GADGET is not set
++# CONFIG_UWB is not set
++# CONFIG_MMC is not set
++# CONFIG_MEMSTICK is not set
++# CONFIG_NEW_LEDS is not set
++# CONFIG_SWITCH is not set
++# CONFIG_ACCESSIBILITY is not set
++# CONFIG_EDAC is not set
++CONFIG_RTC_LIB=y
++# CONFIG_RTC_CLASS is not set
++# CONFIG_DMADEVICES is not set
++# CONFIG_AUXDISPLAY is not set
++# CONFIG_UIO is not set
++# CONFIG_VIRT_DRIVERS is not set
++
++#
++# Virtio drivers
++#
++# CONFIG_VIRTIO_MMIO is not set
++
++#
++# Microsoft Hyper-V guest support
++#
++# CONFIG_STAGING is not set
++
++#
++# SOC (System On Chip) specific Drivers
++#
++# CONFIG_SOC_TI is not set
++CONFIG_CLKDEV_LOOKUP=y
++CONFIG_HAVE_CLK_PREPARE=y
++CONFIG_COMMON_CLK=y
++
++#
++# Common Clock Framework
++#
++# CONFIG_COMMON_CLK_SI5351 is not set
++# CONFIG_COMMON_CLK_SI570 is not set
++# CONFIG_COMMON_CLK_PXA is not set
++# CONFIG_COMMON_CLK_QCOM is not set
++
++#
++# Hardware Spinlock drivers
++#
++
++#
++# Clock Source drivers
++#
++CONFIG_CLKSRC_OF=y
++CONFIG_CLKSRC_MMIO=y
++CONFIG_ARM_ARCH_TIMER=y
++CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y
++# CONFIG_ARM_ARCH_TIMER_VCT_ACCESS is not set
++# CONFIG_ATMEL_PIT is not set
++# CONFIG_SH_TIMER_CMT is not set
++# CONFIG_SH_TIMER_MTU2 is not set
++# CONFIG_SH_TIMER_TMU is not set
++# CONFIG_EM_TIMER_STI is not set
++# CONFIG_CLKSRC_VERSATILE is not set
++# CONFIG_MAILBOX is not set
++# CONFIG_IOMMU_SUPPORT is not set
++
++#
++# Remoteproc drivers
++#
++# CONFIG_STE_MODEM_RPROC is not set
++
++#
++# Rpmsg drivers
++#
++
++#
++# SOC (System On Chip) specific Drivers
++#
++# 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
++CONFIG_IRQCHIP=y
++CONFIG_ARM_GIC=y
++# CONFIG_IPACK_BUS is not set
++CONFIG_ARCH_HAS_RESET_CONTROLLER=y
++CONFIG_RESET_CONTROLLER=y
++# CONFIG_FMC is not set
++
++#
++# PHY Subsystem
++#
++CONFIG_GENERIC_PHY=y
++# CONFIG_BCM_KONA_USB2_PHY is not set
++# CONFIG_PHY_HISI_INNO_USB2 is not set
++CONFIG_PHY_HI35x1D_INNO_USB2=y
++CONFIG_HI_NANO_PHY_SATA=y
++CONFIG_HI_SATA_PORTS=2
++CONFIG_HI_SATA_MODE=1
++# CONFIG_POWERCAP is not set
++# CONFIG_MCB is not set
++CONFIG_HI_DMAC=y
++CONFIG_HI_DMAC_CHANNEL_NUM=4
++
++#
++# Hisilicon driver support
++#
++
++#
++# File systems
++#
++CONFIG_DCACHE_WORD_ACCESS=y
++# CONFIG_EXT2_FS is not set
++# CONFIG_EXT3_FS is not set
++CONFIG_EXT4_FS=y
++CONFIG_EXT4_USE_FOR_EXT23=y
++# CONFIG_EXT4_FS_POSIX_ACL is not set
++# CONFIG_EXT4_FS_SECURITY is not set
++# CONFIG_EXT4_DEBUG is not set
++CONFIG_JBD2=y
++# CONFIG_JBD2_DEBUG is not set
++CONFIG_FS_MBCACHE=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_BTRFS_FS is not set
++# CONFIG_NILFS2_FS is not set
++CONFIG_FS_POSIX_ACL=y
++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 is not set
++# CONFIG_FUSE_FS is not set
++# CONFIG_OVERLAY_FS is not set
++
++#
++# Caches
++#
++# CONFIG_FSCACHE is not set
++
++#
++# CD-ROM/DVD Filesystems
++#
++CONFIG_ISO9660_FS=y
++# CONFIG_JOLIET is not set
++# CONFIG_ZISOFS is not set
++CONFIG_UDF_FS=y
++CONFIG_UDF_NLS=y
++
++#
++# DOS/FAT/NT Filesystems
++#
++CONFIG_FAT_FS=y
++CONFIG_MSDOS_FS=y
++CONFIG_VFAT_FS=y
++CONFIG_FAT_DEFAULT_CODEPAGE=437
++CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
++# CONFIG_NTFS_FS is not set
++
++#
++# Pseudo filesystems
++#
++CONFIG_PROC_FS=y
++CONFIG_PROC_SYSCTL=y
++CONFIG_PROC_PAGE_MONITOR=y
++CONFIG_KERNFS=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=m
++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_YAFFS_FS=y
++CONFIG_YAFFS_YAFFS1=y
++# CONFIG_YAFFS_9BYTE_TAGS is not set
++# CONFIG_YAFFS_DOES_ECC is not set
++CONFIG_YAFFS_YAFFS2=y
++CONFIG_YAFFS_AUTO_YAFFS2=y
++# CONFIG_YAFFS_DISABLE_TAGS_ECC is not set
++# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
++# CONFIG_YAFFS_EMPTY_LOST_AND_FOUND is not set
++# CONFIG_YAFFS_DISABLE_BLOCK_REFRESHING is not set
++# CONFIG_YAFFS_DISABLE_BACKGROUND is not set
++# CONFIG_YAFFS_DISABLE_BAD_BLOCK_MARKING is not set
++CONFIG_YAFFS_XATTR=y
++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 is not set
++# CONFIG_JFFS2_FS_XATTR is not set
++# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
++CONFIG_JFFS2_ZLIB=y
++# CONFIG_JFFS2_LZO is not set
++CONFIG_JFFS2_RTIME=y
++# CONFIG_JFFS2_RUBIN 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 is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V2=y
++CONFIG_NFS_V3=y
++CONFIG_NFS_V3_ACL=y
++# CONFIG_NFS_V4 is not set
++# CONFIG_NFS_SWAP is not set
++# CONFIG_ROOT_NFS is not set
++# CONFIG_NFSD is not set
++CONFIG_GRACE_PERIOD=y
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_ACL_SUPPORT=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 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=y
++# CONFIG_DLM is not set
++
++#
++# Kernel hacking
++#
++
++#
++# printk and dmesg options
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4
++# CONFIG_BOOT_PRINTK_DELAY is not set
++
++#
++# Compile-time checks and compiler options
++#
++# CONFIG_DEBUG_INFO is not set
++# CONFIG_ENABLE_WARN_DEPRECATED is not set
++# CONFIG_ENABLE_MUST_CHECK is not set
++CONFIG_FRAME_WARN=1024
++# CONFIG_STRIP_ASM_SYMS is not set
++# CONFIG_READABLE_ASM is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++# CONFIG_DEBUG_FS is not set
++# CONFIG_HEADERS_CHECK is not set
++# CONFIG_DEBUG_SECTION_MISMATCH is not set
++# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
++# CONFIG_MAGIC_SYSRQ is not set
++CONFIG_DEBUG_KERNEL=y
++
++#
++# Memory Debugging
++#
++# CONFIG_DEBUG_PAGEALLOC is not set
++# 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_STACK_USAGE is not set
++# CONFIG_DEBUG_VM is not set
++CONFIG_DEBUG_MEMORY_INIT=y
++# CONFIG_DEBUG_PER_CPU_MAPS is not set
++# CONFIG_DEBUG_HIGHMEM is not set
++# CONFIG_DEBUG_SHIRQ is not set
++
++#
++# Debug Lockups and Hangs
++#
++# CONFIG_LOCKUP_DETECTOR is not set
++# CONFIG_DETECT_HUNG_TASK is not set
++# CONFIG_PANIC_ON_OOPS is not set
++CONFIG_PANIC_ON_OOPS_VALUE=0
++CONFIG_PANIC_TIMEOUT=0
++CONFIG_SCHED_DEBUG=y
++# CONFIG_SCHEDSTATS is not set
++# CONFIG_SCHED_STACK_END_CHECK is not set
++# CONFIG_TIMER_STATS is not set
++
++#
++# Lock Debugging (spinlocks, mutexes, etc...)
++#
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_LOCK_STAT is not set
++# CONFIG_DEBUG_ATOMIC_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_LOCK_TORTURE_TEST is not set
++CONFIG_STACKTRACE=y
++# CONFIG_DEBUG_KOBJECT is not set
++CONFIG_DEBUG_BUGVERBOSE=y
++# CONFIG_DEBUG_LIST is not set
++# CONFIG_DEBUG_PI_LIST is not set
++# CONFIG_DEBUG_SG is not set
++# CONFIG_DEBUG_NOTIFIERS is not set
++# CONFIG_DEBUG_CREDENTIALS is not set
++
++#
++# RCU Debugging
++#
++# CONFIG_SPARSE_RCU_POINTER is not set
++# CONFIG_TORTURE_TEST 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_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_NOTIFIER_ERROR_INJECTION is not set
++# CONFIG_FAULT_INJECTION 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 is not set
++
++#
++# Runtime Testing
++#
++# CONFIG_TEST_LIST_SORT is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_RBTREE_TEST is not set
++# CONFIG_INTERVAL_TREE_TEST is not set
++# CONFIG_PERCPU_TEST is not set
++# CONFIG_ATOMIC64_SELFTEST is not set
++# CONFIG_TEST_STRING_HELPERS is not set
++# CONFIG_TEST_KSTRTOX is not set
++# CONFIG_TEST_RHASHTABLE is not set
++# CONFIG_DMA_API_DEBUG is not set
++# CONFIG_TEST_LKM is not set
++# CONFIG_TEST_USER_COPY is not set
++# CONFIG_TEST_BPF is not set
++# CONFIG_TEST_FIRMWARE is not set
++# CONFIG_TEST_UDELAY is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_KGDB is not set
++# CONFIG_ARM_PTDUMP is not set
++CONFIG_STRICT_DEVMEM=y
++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_DEBUG_UART_PL01X is not set
++# CONFIG_DEBUG_UART_8250 is not set
++# CONFIG_DEBUG_UART_BCM63XX is not set
++CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"
++# CONFIG_OC_ETM is not set
++# CONFIG_PID_IN_CONTEXTIDR is not set
++# CONFIG_DEBUG_SET_MODULE_RONX is not set
++# CONFIG_CORESIGHT is not set
++
++#
++# 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_HASH=y
++CONFIG_CRYPTO_HASH2=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_PCRYPT is not set
++# CONFIG_CRYPTO_CRYPTD is not set
++# CONFIG_CRYPTO_MCRYPTD 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_CMAC is not set
++# CONFIG_CRYPTO_HMAC is not set
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_VMAC is not set
++
++#
++# Digest
++#
++CONFIG_CRYPTO_CRC32C=y
++# CONFIG_CRYPTO_CRC32 is not set
++# CONFIG_CRYPTO_CRCT10DIF 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_SHA1_ARM_NEON is not set
++# CONFIG_CRYPTO_SHA256 is not set
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_SHA512_ARM_NEON 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_AES_ARM_BS 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=y
++# CONFIG_CRYPTO_ZLIB is not set
++CONFIG_CRYPTO_LZO=y
++# CONFIG_CRYPTO_LZ4 is not set
++# CONFIG_CRYPTO_LZ4HC is not set
++
++#
++# Random Number Generation
++#
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++# CONFIG_CRYPTO_DRBG_MENU is not set
++# CONFIG_CRYPTO_USER_API_HASH is not set
++# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
++CONFIG_CRYPTO_HW=y
++# CONFIG_BINARY_PRINTF is not set
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++CONFIG_GENERIC_STRNCPY_FROM_USER=y
++CONFIG_GENERIC_STRNLEN_USER=y
++CONFIG_GENERIC_NET_UTILS=y
++CONFIG_GENERIC_PCI_IOMAP=y
++CONFIG_GENERIC_IO=y
++CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
++# CONFIG_CRC_CCITT is not set
++CONFIG_CRC16=y
++# CONFIG_CRC_T10DIF is not set
++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 is not set
++# CONFIG_LIBCRC32C is not set
++# CONFIG_CRC8 is not set
++# CONFIG_AUDIT_ARCH_COMPAT_GENERIC is not set
++# CONFIG_RANDOM32_SELFTEST is not set
++CONFIG_ZLIB_INFLATE=y
++CONFIG_ZLIB_DEFLATE=y
++CONFIG_LZO_COMPRESS=y
++CONFIG_LZO_DECOMPRESS=y
++CONFIG_LZ4_DECOMPRESS=y
++CONFIG_XZ_DEC=y
++CONFIG_XZ_DEC_X86=y
++CONFIG_XZ_DEC_POWERPC=y
++CONFIG_XZ_DEC_IA64=y
++CONFIG_XZ_DEC_ARM=y
++CONFIG_XZ_DEC_ARMTHUMB=y
++CONFIG_XZ_DEC_SPARC=y
++CONFIG_XZ_DEC_BCJ=y
++# CONFIG_XZ_DEC_TEST is not set
++CONFIG_DECOMPRESS_GZIP=y
++CONFIG_DECOMPRESS_BZIP2=y
++CONFIG_DECOMPRESS_LZMA=y
++CONFIG_DECOMPRESS_XZ=y
++CONFIG_DECOMPRESS_LZO=y
++CONFIG_DECOMPRESS_LZ4=y
++CONFIG_GENERIC_ALLOCATOR=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT_MAP=y
++CONFIG_HAS_DMA=y
++CONFIG_CPU_RMAP=y
++CONFIG_DQL=y
++CONFIG_GLOB=y
++# CONFIG_GLOB_SELFTEST is not set
++CONFIG_NLATTR=y
++CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
++# CONFIG_AVERAGE is not set
++# CONFIG_CORDIC is not set
++# CONFIG_DDR is not set
++CONFIG_LIBFDT=y
++CONFIG_ARCH_HAS_SG_CHAIN=y
++# CONFIG_VIRTUALIZATION is not set
+diff --git a/arch/arm/configs/hi3531d_full_defconfig b/arch/arm/configs/hi3531d_full_defconfig
+new file mode 100644
+index 0000000..309c44f
+--- /dev/null
++++ b/arch/arm/configs/hi3531d_full_defconfig
+@@ -0,0 +1,2611 @@
++#
++# Automatically generated file; DO NOT EDIT.
++# Linux/arm 3.18.20 Kernel Configuration
++#
++CONFIG_ARM=y
++CONFIG_ARM_HAS_SG_CHAIN=y
++CONFIG_MIGHT_HAVE_PCI=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=y
++CONFIG_HAVE_PROC_CPU=y
++CONFIG_STACKTRACE_SUPPORT=y
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
++CONFIG_RWSEM_XCHGADD_ALGORITHM=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_NEED_DMA_MAP_STATE=y
++CONFIG_ARCH_SUPPORTS_UPROBES=y
++CONFIG_VECTORS_BASE=0xffff0000
++CONFIG_ARM_PATCH_PHYS_VIRT=y
++CONFIG_NEED_MACH_IO_H=y
++CONFIG_GENERIC_BUG=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++CONFIG_IRQ_WORK=y
++CONFIG_BUILDTIME_EXTABLE_SORT=y
++
++#
++# General setup
++#
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_CROSS_COMPILE=""
++# CONFIG_COMPILE_TEST is not set
++CONFIG_LOCALVERSION=""
++# CONFIG_LOCALVERSION_AUTO is not set
++CONFIG_HAVE_KERNEL_GZIP=y
++CONFIG_HAVE_KERNEL_LZMA=y
++CONFIG_HAVE_KERNEL_XZ=y
++CONFIG_HAVE_KERNEL_LZO=y
++CONFIG_HAVE_KERNEL_LZ4=y
++CONFIG_KERNEL_GZIP=y
++# CONFIG_KERNEL_LZMA is not set
++# CONFIG_KERNEL_XZ is not set
++# CONFIG_KERNEL_LZO is not set
++# CONFIG_KERNEL_LZ4 is not set
++CONFIG_DEFAULT_HOSTNAME="(none)"
++# CONFIG_SWAP is not set
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++# CONFIG_POSIX_MQUEUE is not set
++CONFIG_CROSS_MEMORY_ATTACH=y
++# CONFIG_FHANDLE is not set
++CONFIG_USELIB=y
++# CONFIG_AUDIT is not set
++
++#
++# IRQ subsystem
++#
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_GENERIC_IRQ_SHOW=y
++CONFIG_HARDIRQS_SW_RESEND=y
++CONFIG_IRQ_DOMAIN=y
++CONFIG_HANDLE_DOMAIN_IRQ=y
++CONFIG_IRQ_FORCED_THREADING=y
++CONFIG_SPARSE_IRQ=y
++CONFIG_GENERIC_CLOCKEVENTS=y
++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
++CONFIG_ARCH_HAS_TICK_BROADCAST=y
++CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
++
++#
++# Timers subsystem
++#
++CONFIG_HZ_PERIODIC=y
++# CONFIG_NO_HZ_IDLE is not set
++# CONFIG_NO_HZ_FULL is not set
++# CONFIG_NO_HZ is not set
++# CONFIG_HIGH_RES_TIMERS is not set
++
++#
++# CPU/Task time and stats accounting
++#
++CONFIG_TICK_CPU_ACCOUNTING=y
++# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set
++# CONFIG_IRQ_TIME_ACCOUNTING is not set
++# CONFIG_BSD_PROCESS_ACCT is not set
++# CONFIG_TASKSTATS is not set
++
++#
++# RCU Subsystem
++#
++CONFIG_TREE_RCU=y
++# CONFIG_PREEMPT_RCU is not set
++# CONFIG_TASKS_RCU is not set
++CONFIG_RCU_STALL_COMMON=y
++# CONFIG_RCU_USER_QS is not set
++CONFIG_RCU_FANOUT=32
++CONFIG_RCU_FANOUT_LEAF=16
++# CONFIG_RCU_FANOUT_EXACT is not set
++# CONFIG_TREE_RCU_TRACE is not set
++# CONFIG_RCU_NOCB_CPU is not set
++# CONFIG_BUILD_BIN2C is not set
++# CONFIG_IKCONFIG is not set
++CONFIG_LOG_BUF_SHIFT=17
++CONFIG_LOG_CPU_MAX_BUF_SHIFT=12
++CONFIG_GENERIC_SCHED_CLOCK=y
++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_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_USER_NS is not set
++CONFIG_PID_NS=y
++CONFIG_NET_NS=y
++# 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=y
++CONFIG_RD_LZMA=y
++CONFIG_RD_XZ=y
++CONFIG_RD_LZO=y
++CONFIG_RD_LZ4=y
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++CONFIG_HAVE_UID16=y
++CONFIG_BPF=y
++# CONFIG_EXPERT is not set
++CONFIG_UID16=y
++# CONFIG_SGETMASK_SYSCALL is not set
++CONFIG_SYSFS_SYSCALL=y
++# CONFIG_SYSCTL_SYSCALL is not set
++CONFIG_KALLSYMS=y
++# CONFIG_KALLSYMS_ALL is not set
++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_BPF_SYSCALL is not set
++CONFIG_SHMEM=y
++CONFIG_AIO=y
++CONFIG_ADVISE_SYSCALLS=y
++CONFIG_PCI_QUIRKS=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 is not set
++# CONFIG_SLAB is not set
++CONFIG_SLUB=y
++CONFIG_SLUB_CPU_PARTIAL=y
++# CONFIG_PROFILING is not set
++CONFIG_HAVE_OPROFILE=y
++# CONFIG_KPROBES is not set
++# CONFIG_JUMP_LABEL is not set
++# CONFIG_UPROBES is not set
++# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
++CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
++CONFIG_ARCH_USE_BUILTIN_BSWAP=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_GENERIC_SMP_IDLE_THREAD=y
++CONFIG_GENERIC_IDLE_POLL_SETUP=y
++CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
++CONFIG_HAVE_CLK=y
++CONFIG_HAVE_DMA_API_DEBUG=y
++CONFIG_HAVE_PERF_REGS=y
++CONFIG_HAVE_PERF_USER_STACK_DUMP=y
++CONFIG_HAVE_ARCH_JUMP_LABEL=y
++CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
++CONFIG_HAVE_CC_STACKPROTECTOR=y
++# CONFIG_CC_STACKPROTECTOR is not set
++CONFIG_CC_STACKPROTECTOR_NONE=y
++# CONFIG_CC_STACKPROTECTOR_REGULAR is not set
++# CONFIG_CC_STACKPROTECTOR_STRONG is not set
++CONFIG_HAVE_CONTEXT_TRACKING=y
++CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
++CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
++CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
++CONFIG_MODULES_USE_ELF_REL=y
++CONFIG_CLONE_BACKWARDS=y
++CONFIG_OLD_SIGSUSPEND3=y
++CONFIG_OLD_SIGACTION=y
++
++#
++# GCOV-based kernel profiling
++#
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_SLABINFO=y
++CONFIG_RT_MUTEXES=y
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++# CONFIG_MODULE_FORCE_LOAD is not set
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++# CONFIG_MODULE_SIG is not set
++# CONFIG_MODULE_COMPRESS is not set
++CONFIG_STOP_MACHINE=y
++CONFIG_BLOCK=y
++CONFIG_LBDAF=y
++CONFIG_BLK_DEV_BSG=y
++# CONFIG_BLK_DEV_BSGLIB is not set
++# CONFIG_BLK_DEV_INTEGRITY is not set
++CONFIG_BLK_CMDLINE_PARSER=y
++
++#
++# Partition Types
++#
++CONFIG_PARTITION_ADVANCED=y
++# CONFIG_ACORN_PARTITION is not set
++# CONFIG_AIX_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=y
++# CONFIG_SYSV68_PARTITION is not set
++CONFIG_CMDLINE_PARTITION=y
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++CONFIG_DEFAULT_DEADLINE=y
++# CONFIG_DEFAULT_CFQ is not set
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="deadline"
++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_ARCH_SUPPORTS_ATOMIC_RMW=y
++CONFIG_MUTEX_SPIN_ON_OWNER=y
++CONFIG_RWSEM_SPIN_ON_OWNER=y
++CONFIG_FREEZER=y
++
++#
++# System Type
++#
++CONFIG_MMU=y
++CONFIG_ARCH_MULTIPLATFORM=y
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_AT91 is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_GEMINI is not set
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_IOP13XX is not set
++# CONFIG_ARCH_IOP32X is not set
++# CONFIG_ARCH_IOP33X is not set
++# CONFIG_ARCH_IXP4XX is not set
++# CONFIG_ARCH_DOVE is not set
++# CONFIG_ARCH_MV78XX0 is not set
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_MMP is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_W90X900 is not set
++# CONFIG_ARCH_LPC32XX is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_MSM is not set
++# CONFIG_ARCH_SHMOBILE_LEGACY 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_DAVINCI is not set
++# CONFIG_ARCH_OMAP1 is not set
++
++#
++# Multiple platform selection
++#
++
++#
++# CPU Core family selection
++#
++# CONFIG_ARCH_MULTI_V6 is not set
++CONFIG_ARCH_MULTI_V7=y
++CONFIG_ARCH_MULTI_V6_V7=y
++# CONFIG_ARCH_MULTI_CPU_AUTO is not set
++# CONFIG_ARCH_VIRT is not set
++# CONFIG_ARCH_MVEBU is not set
++# CONFIG_ARCH_BCM is not set
++# CONFIG_ARCH_BERLIN is not set
++# CONFIG_ARCH_HIGHBANK is not set
++CONFIG_ARCH_HISI=y
++
++#
++# Hisilicon platform type
++#
++# CONFIG_ARCH_HI3xxx is not set
++# CONFIG_ARCH_HIP04 is not set
++# CONFIG_ARCH_HIX5HD2 is not set
++# CONFIG_ARCH_HI3519 is not set
++# CONFIG_ARCH_HI3519V101 is not set
++# CONFIG_ARCH_HI3516AV200 is not set
++# CONFIG_ARCH_HI3559 is not set
++# CONFIG_ARCH_HI3556 is not set
++# CONFIG_ARCH_HI3536C is not set
++CONFIG_ARCH_HI3531D=y
++# CONFIG_ARCH_HI3521D is not set
++# CONFIG_ARCH_KEYSTONE is not set
++# CONFIG_ARCH_MESON is not set
++# CONFIG_ARCH_MXC is not set
++# CONFIG_ARCH_MEDIATEK is not set
++
++#
++# TI OMAP/AM/DM/DRA Family
++#
++# CONFIG_ARCH_OMAP3 is not set
++# CONFIG_ARCH_OMAP4 is not set
++# CONFIG_SOC_OMAP5 is not set
++# CONFIG_SOC_AM33XX is not set
++# CONFIG_SOC_AM43XX is not set
++# CONFIG_SOC_DRA7XX is not set
++# CONFIG_ARCH_QCOM is not set
++# CONFIG_ARCH_ROCKCHIP is not set
++# CONFIG_ARCH_SOCFPGA is not set
++# CONFIG_PLAT_SPEAR is not set
++# CONFIG_ARCH_STI is not set
++# CONFIG_ARCH_S5PV210 is not set
++# CONFIG_ARCH_EXYNOS is not set
++# CONFIG_ARCH_SHMOBILE_MULTI is not set
++# CONFIG_ARCH_SUNXI is not set
++# CONFIG_ARCH_SIRF is not set
++# CONFIG_ARCH_TEGRA is not set
++# CONFIG_ARCH_U8500 is not set
++# CONFIG_ARCH_VEXPRESS is not set
++# CONFIG_ARCH_WM8850 is not set
++# CONFIG_ARCH_ZYNQ is not set
++CONFIG_ARM_TIMER_SP804=y
++
++#
++# Processor Type
++#
++CONFIG_CPU_V7=y
++CONFIG_CPU_32v6K=y
++CONFIG_CPU_32v7=y
++CONFIG_CPU_ABRT_EV7=y
++CONFIG_CPU_PABRT_V7=y
++CONFIG_CPU_CACHE_V7=y
++CONFIG_CPU_CACHE_VIPT=y
++CONFIG_CPU_COPY_V6=y
++CONFIG_CPU_TLB_V7=y
++CONFIG_CPU_HAS_ASID=y
++CONFIG_CPU_CP15=y
++CONFIG_CPU_CP15_MMU=y
++
++#
++# Processor Features
++#
++# CONFIG_ARM_LPAE is not set
++# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
++CONFIG_ARM_THUMB=y
++# CONFIG_ARM_THUMBEE is not set
++CONFIG_ARM_VIRT_EXT=y
++CONFIG_SWP_EMULATE=y
++# CONFIG_CPU_ICACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_DISABLE is not set
++# CONFIG_CPU_BPREDICT_DISABLE is not set
++CONFIG_KUSER_HELPERS=y
++CONFIG_OUTER_CACHE=y
++CONFIG_OUTER_CACHE_SYNC=y
++CONFIG_MIGHT_HAVE_CACHE_L2X0=y
++CONFIG_CACHE_L2X0=y
++CONFIG_CACHE_PL310=y
++# CONFIG_PL310_ERRATA_588369 is not set
++# CONFIG_PL310_ERRATA_727915 is not set
++# CONFIG_PL310_ERRATA_753970 is not set
++# CONFIG_PL310_ERRATA_769419 is not set
++CONFIG_ARM_L1_CACHE_SHIFT_6=y
++CONFIG_ARM_L1_CACHE_SHIFT=6
++CONFIG_ARM_DMA_MEM_BUFFERABLE=y
++CONFIG_MULTI_IRQ_HANDLER=y
++# CONFIG_ARM_ERRATA_430973 is not set
++# CONFIG_ARM_ERRATA_643719 is not set
++# CONFIG_ARM_ERRATA_720789 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_ARM_ERRATA_775420 is not set
++# CONFIG_ARM_ERRATA_798181 is not set
++# CONFIG_ARM_ERRATA_773022 is not set
++
++#
++# Bus support
++#
++CONFIG_ARM_AMBA=y
++CONFIG_PCI=y
++CONFIG_PCI_SYSCALL=y
++# CONFIG_PCI_MSI is not set
++# CONFIG_PCI_DEBUG is not set
++# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set
++# CONFIG_PCI_STUB is not set
++# CONFIG_PCI_IOV is not set
++# CONFIG_PCI_PRI is not set
++# CONFIG_PCI_PASID is not set
++
++#
++# PCI host controller drivers
++#
++# CONFIG_PCI_HOST_GENERIC is not set
++CONFIG_PCIEPORTBUS=y
++CONFIG_PCIEAER=y
++# CONFIG_PCIE_ECRC is not set
++# CONFIG_PCIEAER_INJECT is not set
++CONFIG_PCIEASPM=y
++# CONFIG_PCIEASPM_DEBUG is not set
++CONFIG_PCIEASPM_DEFAULT=y
++# CONFIG_PCIEASPM_POWERSAVE is not set
++# CONFIG_PCIEASPM_PERFORMANCE is not set
++# CONFIG_PCCARD is not set
++CONFIG_HIPCIE=y
++
++#
++# PCI Express configs
++#
++CONFIG_PCIE0_SEL=1
++CONFIG_PCIE0_DEVICES_MEM_SIZE=0x8000000
++CONFIG_PCIE0_DEVICES_CONFIG_SIZE=0x8000000
++CONFIG_LIMIT_MAX_RD_REQ_SIZE=y
++CONFIG_PCIE1_SEL=1
++CONFIG_PCIE1_DEVICES_MEM_SIZE=0x7800000
++CONFIG_PCIE1_DEVICES_CONFIG_SIZE=0x800000
++
++#
++# 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_DISABLE_CPU_SCHED_DOMAIN_BALANCE is not set
++CONFIG_HAVE_ARM_SCU=y
++CONFIG_HAVE_ARM_ARCH_TIMER=y
++# CONFIG_MCPM is not set
++# CONFIG_BIG_LITTLE is not set
++CONFIG_VMSPLIT_3G=y
++# CONFIG_VMSPLIT_2G is not set
++# CONFIG_VMSPLIT_1G is not set
++CONFIG_PAGE_OFFSET=0xC0000000
++CONFIG_NR_CPUS=4
++CONFIG_HOTPLUG_CPU=y
++# CONFIG_ARM_PSCI is not set
++CONFIG_ARCH_NR_GPIO=0
++CONFIG_PREEMPT_NONE=y
++# CONFIG_PREEMPT_VOLUNTARY is not set
++# CONFIG_PREEMPT is not set
++CONFIG_HZ_FIXED=0
++CONFIG_HZ_100=y
++# CONFIG_HZ_200 is not set
++# CONFIG_HZ_250 is not set
++# CONFIG_HZ_300 is not set
++# CONFIG_HZ_500 is not set
++# CONFIG_HZ_1000 is not set
++CONFIG_HZ=100
++# CONFIG_SCHED_HRTICK is not set
++# CONFIG_THUMB2_KERNEL is not set
++CONFIG_AEABI=y
++CONFIG_OABI_COMPAT=y
++# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
++# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
++CONFIG_HAVE_ARCH_PFN_VALID=y
++CONFIG_HIGHMEM=y
++# CONFIG_HIGHPTE is not set
++CONFIG_ARCH_WANT_GENERAL_HUGETLB=y
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_HAVE_MEMBLOCK=y
++CONFIG_NO_BOOTMEM=y
++# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=4
++CONFIG_COMPACTION=y
++CONFIG_MIGRATION=y
++# CONFIG_PHYS_ADDR_T_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_BOUNCE=y
++# CONFIG_KSM is not set
++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
++# CONFIG_CLEANCACHE is not set
++# CONFIG_CMA is not set
++# CONFIG_ZPOOL is not set
++# CONFIG_ZBUD is not set
++# CONFIG_ZSMALLOC 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_SWIOTLB=y
++CONFIG_IOMMU_HELPER=y
++# CONFIG_XEN is not set
++# CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART is not set
++
++#
++# Boot options
++#
++CONFIG_USE_OF=y
++CONFIG_ATAGS=y
++# CONFIG_DEPRECATED_PARAM_STRUCT is not set
++# CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE is not set
++CONFIG_ZBOOT_ROM_TEXT=0
++CONFIG_ZBOOT_ROM_BSS=0
++CONFIG_ARM_APPENDED_DTB=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_KEXEC is not set
++# CONFIG_CRASH_DUMP is not set
++CONFIG_AUTO_ZRELADDR=y
++
++#
++# CPU Power Management
++#
++
++#
++# CPU Frequency scaling
++#
++CONFIG_CPU_FREQ=y
++CONFIG_CPU_FREQ_STAT=y
++# CONFIG_CPU_FREQ_STAT_DETAILS is not set
++CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
++# CONFIG_CPU_FREQ_DEFAULT_GOV_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_DEFAULT_GOV_INTERACTIVE is not set
++CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
++# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
++# CONFIG_CPU_FREQ_GOV_USERSPACE is not set
++# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
++# CONFIG_CPU_FREQ_GOV_INTERACTIVE is not set
++# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
++CONFIG_CPUFREQ_DT=y
++
++#
++# ARM CPU frequency scaling drivers
++#
++# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set
++
++#
++# CPU Idle
++#
++# CONFIG_CPU_IDLE is not set
++# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++# CONFIG_FPE_NWFPE is not set
++# CONFIG_FPE_FASTFPE is not set
++CONFIG_VFP=y
++CONFIG_VFPv3=y
++CONFIG_NEON=y
++CONFIG_KERNEL_MODE_NEON=y
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
++CONFIG_BINFMT_SCRIPT=y
++# CONFIG_HAVE_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
++CONFIG_COREDUMP=y
++
++#
++# Power management options
++#
++CONFIG_SUSPEND=y
++CONFIG_SUSPEND_FREEZER=y
++CONFIG_WAKELOCK=y
++# CONFIG_HISI_SNAPSHOT_BOOT is not set
++CONFIG_PM_SLEEP=y
++CONFIG_PM_SLEEP_SMP=y
++# CONFIG_PM_AUTOSLEEP is not set
++# CONFIG_PM_WAKELOCKS is not set
++# CONFIG_PM_RUNTIME is not set
++CONFIG_PM=y
++# CONFIG_PM_DEBUG is not set
++# CONFIG_APM_EMULATION is not set
++CONFIG_PM_OPP=y
++CONFIG_PM_CLK=y
++# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set
++CONFIG_CPU_PM=y
++# CONFIG_SUSPEND_TIME is not set
++CONFIG_ARCH_SUSPEND_POSSIBLE=y
++CONFIG_ARM_CPU_SUSPEND=y
++CONFIG_ARCH_HIBERNATION_POSSIBLE=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=y
++# 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_NET_IP_TUNNEL=m
++# CONFIG_IP_MROUTE is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_NET_UDP_TUNNEL is not set
++# CONFIG_NET_FOU is not set
++# CONFIG_GENEVE 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 is not set
++# CONFIG_INET_XFRM_MODE_TUNNEL is not set
++# CONFIG_INET_XFRM_MODE_BEET is not set
++CONFIG_INET_LRO=y
++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=y
++# 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_VTI 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_ANDROID_PARANOID_NETWORK is not set
++CONFIG_NET_ACTIVITY_STATS=y
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NET_PTP_CLASSIFY 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_NF_TABLES is not set
++# CONFIG_NETFILTER_XTABLES is not set
++# CONFIG_IP_SET is not set
++# CONFIG_IP_VS is not set
++
++#
++# IP: Netfilter Configuration
++#
++# CONFIG_NF_DEFRAG_IPV4 is not set
++# CONFIG_NF_LOG_ARP is not set
++# CONFIG_NF_LOG_IPV4 is not set
++# CONFIG_NF_REJECT_IPV4 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_NF_REJECT_IPV6 is not set
++# CONFIG_NF_LOG_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_HAVE_NET_DSA=y
++# 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_PHONET is not set
++# CONFIG_6LOWPAN 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_VSOCKETS is not set
++# CONFIG_NETLINK_MMAP is not set
++# CONFIG_NETLINK_DIAG is not set
++# CONFIG_NET_MPLS_GSO is not set
++# CONFIG_HSR is not set
++CONFIG_RPS=y
++CONFIG_RFS_ACCEL=y
++CONFIG_XPS=y
++# CONFIG_CGROUP_NET_PRIO is not set
++# CONFIG_CGROUP_NET_CLASSID is not set
++CONFIG_NET_RX_BUSY_POLL=y
++CONFIG_BQL=y
++# CONFIG_BPF_JIT is not set
++CONFIG_NET_FLOW_LIMIT=y
++
++#
++# 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 is not set
++# 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 is not set
++CONFIG_DEVTMPFS=y
++# CONFIG_DEVTMPFS_MOUNT is not set
++CONFIG_STANDALONE=y
++# CONFIG_PREVENT_FIRMWARE_BUILD is not set
++CONFIG_FW_LOADER=y
++CONFIG_FIRMWARE_IN_KERNEL=y
++CONFIG_EXTRA_FIRMWARE=""
++# CONFIG_FW_LOADER_USER_HELPER_FALLBACK is not set
++CONFIG_ALLOW_DEV_COREDUMP=y
++# 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_HAVE_CPU_AUTOPROBE is not set
++CONFIG_REGMAP=y
++CONFIG_REGMAP_MMIO=y
++# CONFIG_DMA_SHARED_BUFFER is not set
++
++#
++# Bus devices
++#
++# CONFIG_BRCMSTB_GISB_ARB is not set
++# CONFIG_ARM_CCI is not set
++# CONFIG_VEXPRESS_CONFIG 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=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_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_HIFMC=y
++CONFIG_HIFMC_SPI_NAND=y
++# CONFIG_HIFMC_NAND 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_INTEL_VR_NOR is not set
++# CONFIG_MTD_PLATRAM is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_PMC551 is not set
++# CONFIG_MTD_DATAFLASH is not set
++# CONFIG_MTD_M25P80 is not set
++# CONFIG_MTD_SST25L is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_PHRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++# CONFIG_MTD_BLOCK2MTD is not set
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOCG3 is not set
++CONFIG_MTD_NAND_IDS=y
++CONFIG_MTD_NAND_ECC=y
++# CONFIG_MTD_NAND_ECC_SMC is not set
++CONFIG_MTD_NAND=y
++# CONFIG_MTD_NAND_ECC_BCH is not set
++# CONFIG_MTD_SM_COMMON is not set
++# CONFIG_MTD_NAND_DENALI is not set
++# CONFIG_MTD_NAND_OMAP_BCH_BUILD is not set
++# CONFIG_MTD_NAND_RICOH is not set
++# CONFIG_MTD_NAND_DISKONCHIP is not set
++# CONFIG_MTD_NAND_DOCG4 is not set
++# CONFIG_MTD_NAND_CAFE is not set
++# CONFIG_MTD_NAND_NANDSIM is not set
++# CONFIG_MTD_NAND_PLATFORM is not set
++# CONFIG_HISI_NAND_FS_MAY_NO_YAFFS2 is not set
++# CONFIG_HISI_NAND_ECC_STATUS_REPORT is not set
++# CONFIG_MTD_NAND_HINFC610 is not set
++# CONFIG_HIFMC100_NAND is not set
++CONFIG_HIFMC100_SPI_NAND=y
++CONFIG_SPI_NAND_MAX_CHIP_NUM=1
++# CONFIG_HIFMC100_HARDWARE_PAGESIZE_ECC is not set
++CONFIG_HIFMC100_AUTO_PAGESIZE_ECC=y
++# CONFIG_HIFMC100_PAGESIZE_AUTO_ECC_NONE is not set
++# CONFIG_MTD_ONENAND is not set
++
++#
++# LPDDR & LPDDR2 PCM memory drivers
++#
++# CONFIG_MTD_LPDDR is not set
++# CONFIG_MTD_LPDDR2_NVM is not set
++CONFIG_MTD_SPI_NOR=y
++# CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set
++CONFIG_SPI_HISI_SFC=y
++# CONFIG_CLOSE_SPI_8PIN_4IO is not set
++CONFIG_HISI_SPI_BLOCK_PROTECT=y
++# CONFIG_MTD_UBI is not set
++CONFIG_DTC=y
++CONFIG_OF=y
++
++#
++# Device Tree and Open Firmware support
++#
++# CONFIG_OF_SELFTEST is not set
++CONFIG_OF_FLATTREE=y
++CONFIG_OF_EARLY_FLATTREE=y
++CONFIG_OF_ADDRESS=y
++CONFIG_OF_ADDRESS_PCI=y
++CONFIG_OF_IRQ=y
++CONFIG_OF_NET=y
++CONFIG_OF_MDIO=y
++CONFIG_OF_PCI=y
++CONFIG_OF_PCI_IRQ=y
++CONFIG_OF_MTD=y
++CONFIG_OF_RESERVED_MEM=y
++CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
++# CONFIG_PARPORT is not set
++CONFIG_BLK_DEV=y
++# CONFIG_BLK_DEV_NULL_BLK is not set
++# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set
++# CONFIG_BLK_CPQ_CISS_DA is not set
++# CONFIG_BLK_DEV_DAC960 is not set
++# CONFIG_BLK_DEV_UMEM is not set
++# CONFIG_BLK_DEV_COW_COMMON is not set
++# CONFIG_BLK_DEV_LOOP is not set
++# CONFIG_BLK_DEV_DRBD is not set
++# CONFIG_BLK_DEV_NBD is not set
++# CONFIG_BLK_DEV_NVME is not set
++# CONFIG_BLK_DEV_SX8 is not set
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_COUNT=16
++CONFIG_BLK_DEV_RAM_SIZE=65536
++# CONFIG_BLK_DEV_XIP is not set
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH is not set
++# CONFIG_BLK_DEV_RBD is not set
++# CONFIG_BLK_DEV_RSXX is not set
++
++#
++# Misc devices
++#
++# CONFIG_SENSORS_LIS3LV02D is not set
++# CONFIG_AD525X_DPOT is not set
++# CONFIG_DUMMY_IRQ is not set
++# CONFIG_PHANTOM is not set
++# CONFIG_SGI_IOC4 is not set
++# CONFIG_TIFM_CORE is not set
++# CONFIG_ICS932S401 is not set
++# CONFIG_ENCLOSURE_SERVICES is not set
++# CONFIG_HP_ILO is not set
++# CONFIG_APDS9802ALS is not set
++# CONFIG_ISL29003 is not set
++# CONFIG_ISL29020 is not set
++# CONFIG_SENSORS_TSL2550 is not set
++# CONFIG_SENSORS_BH1780 is not set
++# CONFIG_SENSORS_BH1770 is not set
++# CONFIG_SENSORS_APDS990X is not set
++# CONFIG_HMC6352 is not set
++# CONFIG_DS1682 is not set
++# CONFIG_TI_DAC7512 is not set
++# CONFIG_UID_STAT is not set
++# CONFIG_BMP085_I2C is not set
++# CONFIG_BMP085_SPI is not set
++# CONFIG_USB_SWITCH_FSA9480 is not set
++# CONFIG_LATTICE_ECP3_CONFIG is not set
++# CONFIG_SRAM is not set
++# CONFIG_C2PORT is not set
++
++#
++# EEPROM support
++#
++# CONFIG_EEPROM_AT24 is not set
++# CONFIG_EEPROM_AT25 is not set
++# CONFIG_EEPROM_LEGACY is not set
++# CONFIG_EEPROM_MAX6875 is not set
++# CONFIG_EEPROM_93CX6 is not set
++# CONFIG_EEPROM_93XX46 is not set
++# CONFIG_CB710_CORE is not set
++
++#
++# Texas Instruments shared transport line discipline
++#
++# 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
++
++#
++# Intel MIC Bus Driver
++#
++
++#
++# Intel MIC Host Driver
++#
++
++#
++# Intel MIC Card Driver
++#
++# CONFIG_ECHO is not set
++# CONFIG_CXL_BASE is not set
++
++#
++# hisi 'himm/himd.l/himc'support
++#
++# CONFIG_HISI_REG is not set
++CONFIG_HAVE_IDE=y
++# CONFIG_IDE 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_NETLINK is not set
++# CONFIG_SCSI_MQ_DEFAULT is not set
++CONFIG_SCSI_PROC_FS=y
++
++#
++# SCSI support type (disk, tape, CD-ROM)
++#
++CONFIG_BLK_DEV_SD=y
++# CONFIG_CHR_DEV_ST is not set
++# CONFIG_CHR_DEV_OSST is not set
++CONFIG_BLK_DEV_SR=y
++# CONFIG_BLK_DEV_SR_VENDOR is not set
++# CONFIG_CHR_DEV_SG is not set
++# CONFIG_CHR_DEV_SCH is not set
++# CONFIG_SCSI_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 is not set
++# CONFIG_SCSI_DH is not set
++# CONFIG_SCSI_OSD_INITIATOR is not set
++CONFIG_HI_SATA=y
++CONFIG_HI_SATA_IOBASE=0x11010000
++CONFIG_HI_SATA_FBS=1
++CONFIG_HI_SATA_NCQ=1
++CONFIG_ATA=y
++# CONFIG_ATA_NONSTANDARD is not set
++CONFIG_ATA_VERBOSE_ERROR=y
++CONFIG_SATA_PMP=y
++
++#
++# Controllers with non-SFF native interface
++#
++# CONFIG_SATA_AHCI is not set
++CONFIG_SATA_AHCI_PLATFORM=y
++# CONFIG_SATA_INIC162X is not set
++# CONFIG_SATA_ACARD_AHCI is not set
++# CONFIG_SATA_SIL24 is not set
++# CONFIG_ATA_SFF is not set
++# CONFIG_MD is not set
++# CONFIG_TARGET_CORE is not set
++# CONFIG_FUSION is not set
++
++#
++# IEEE 1394 (FireWire) support
++#
++# CONFIG_FIREWIRE is not set
++# CONFIG_FIREWIRE_NOSY is not set
++# CONFIG_I2O 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_NET_FC is not set
++# CONFIG_NET_TEAM is not set
++# CONFIG_MACVLAN is not set
++# CONFIG_VXLAN is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_TUN is not set
++# CONFIG_VETH is not set
++# CONFIG_NLMON is not set
++# CONFIG_ARCNET is not set
++
++#
++# 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_NET_DSA_MV88E6171 is not set
++# CONFIG_NET_DSA_BCM_SF2 is not set
++CONFIG_ETHERNET=y
++# CONFIG_NET_VENDOR_3COM is not set
++# CONFIG_NET_VENDOR_ADAPTEC is not set
++# CONFIG_NET_VENDOR_AGERE is not set
++# CONFIG_NET_VENDOR_ALTEON is not set
++# CONFIG_ALTERA_TSE is not set
++# CONFIG_NET_VENDOR_AMD is not set
++# CONFIG_NET_XGENE is not set
++# CONFIG_NET_VENDOR_ARC is not set
++# CONFIG_NET_VENDOR_ATHEROS is not set
++# CONFIG_NET_CADENCE is not set
++# CONFIG_NET_VENDOR_BROADCOM is not set
++# CONFIG_NET_VENDOR_BROCADE is not set
++# CONFIG_NET_VENDOR_CHELSIO is not set
++# CONFIG_NET_VENDOR_CIRRUS is not set
++# CONFIG_NET_VENDOR_CISCO is not set
++# CONFIG_DM9000 is not set
++# CONFIG_DNET is not set
++# CONFIG_NET_VENDOR_DEC is not set
++# CONFIG_NET_VENDOR_DLINK is not set
++# CONFIG_NET_VENDOR_EMULEX is not set
++# CONFIG_NET_VENDOR_EXAR is not set
++# CONFIG_NET_VENDOR_FARADAY is not set
++CONFIG_NET_VENDOR_HISILICON=y
++# CONFIG_HIX5HD2_GMAC is not set
++# CONFIG_HISI_FEMAC is not set
++CONFIG_HIETH_GMAC=y
++CONFIG_HIGMAC_DESC_4WORD=y
++CONFIG_HIGMAC_RXCSUM=y
++CONFIG_RX_FLOW_CTRL_SUPPORT=y
++CONFIG_TX_FLOW_CTRL_SUPPORT=y
++CONFIG_TX_FLOW_CTRL_PAUSE_TIME=0xFFFF
++CONFIG_TX_FLOW_CTRL_PAUSE_INTERVAL=0xFFFF
++CONFIG_TX_FLOW_CTRL_ACTIVE_THRESHOLD=16
++CONFIG_TX_FLOW_CTRL_DEACTIVE_THRESHOLD=32
++# CONFIG_HIETH_SWITCH_FABRIC is not set
++# CONFIG_NET_VENDOR_HP is not set
++# CONFIG_NET_VENDOR_INTEL is not set
++# CONFIG_IP1000 is not set
++# CONFIG_JME is not set
++# CONFIG_NET_VENDOR_MARVELL is not set
++# CONFIG_NET_VENDOR_MELLANOX is not set
++# CONFIG_NET_VENDOR_MICREL is not set
++# CONFIG_NET_VENDOR_MICROCHIP is not set
++# CONFIG_NET_VENDOR_MYRI is not set
++# CONFIG_FEALNX is not set
++# CONFIG_NET_VENDOR_NATSEMI is not set
++# CONFIG_NET_VENDOR_NVIDIA is not set
++# CONFIG_NET_VENDOR_OKI is not set
++# CONFIG_ETHOC is not set
++# CONFIG_NET_PACKET_ENGINE is not set
++# CONFIG_NET_VENDOR_QLOGIC is not set
++# CONFIG_NET_VENDOR_QUALCOMM is not set
++# CONFIG_NET_VENDOR_REALTEK is not set
++# CONFIG_NET_VENDOR_RDC is not set
++# CONFIG_NET_VENDOR_SAMSUNG is not set
++# CONFIG_NET_VENDOR_SEEQ is not set
++# CONFIG_NET_VENDOR_SILAN is not set
++# CONFIG_NET_VENDOR_SIS is not set
++# CONFIG_SFC is not set
++# CONFIG_NET_VENDOR_SMSC is not set
++# CONFIG_NET_VENDOR_STMICRO is not set
++# CONFIG_NET_VENDOR_SUN is not set
++# CONFIG_NET_VENDOR_TEHUTI is not set
++# CONFIG_NET_VENDOR_TI is not set
++# CONFIG_NET_VENDOR_VIA is not set
++# CONFIG_NET_VENDOR_WIZNET is not set
++# CONFIG_FDDI is not set
++# CONFIG_HIPPI is not set
++CONFIG_PHYLIB=y
++
++#
++# MII PHY device drivers
++#
++# CONFIG_AT803X_PHY is not set
++# CONFIG_AMD_PHY is not set
++# CONFIG_AMD_XGBE_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 is not set
++# CONFIG_BROADCOM_PHY is not set
++# CONFIG_BCM7XXX_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_MMIOREG is not set
++# CONFIG_MDIO_BCM_UNIMAC is not set
++# CONFIG_MDIO_HISI_FEMAC is not set
++CONFIG_MDIO_HISI_GEMAC=y
++# CONFIG_MICREL_KS8995MA is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++CONFIG_USB_NET_DRIVERS=y
++# 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_RTL8152 is not set
++# CONFIG_USB_USBNET is not set
++# CONFIG_USB_IPHETH is not set
++# CONFIG_WLAN is not set
++
++#
++# Enable WiMAX (Networking options) to see the WiMAX drivers
++#
++# CONFIG_WAN is not set
++# CONFIG_VMXNET3 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 is not set
++
++#
++# Userland interfaces
++#
++CONFIG_INPUT_MOUSEDEV=y
++CONFIG_INPUT_MOUSEDEV_PSAUX=y
++CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
++CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
++CONFIG_INPUT_JOYDEV=y
++CONFIG_INPUT_EVDEV=y
++# CONFIG_INPUT_EVBUG is not set
++# CONFIG_INPUT_KEYRESET is not set
++# CONFIG_INPUT_KEYCOMBO 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_TCA6416 is not set
++# CONFIG_KEYBOARD_TCA8418 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 is not set
++# CONFIG_KEYBOARD_CAP1106 is not set
++CONFIG_INPUT_MOUSE=y
++CONFIG_MOUSE_PS2=y
++CONFIG_MOUSE_PS2_ALPS=y
++CONFIG_MOUSE_PS2_LOGIPS2PP=y
++CONFIG_MOUSE_PS2_SYNAPTICS=y
++CONFIG_MOUSE_PS2_CYPRESS=y
++CONFIG_MOUSE_PS2_TRACKPOINT=y
++# CONFIG_MOUSE_PS2_ELANTECH is not set
++# CONFIG_MOUSE_PS2_SENTELIC is not set
++# CONFIG_MOUSE_PS2_TOUCHKIT is not set
++# CONFIG_MOUSE_SERIAL is not set
++# CONFIG_MOUSE_APPLETOUCH is not set
++# CONFIG_MOUSE_BCM5974 is not set
++# CONFIG_MOUSE_CYAPA is not set
++# CONFIG_MOUSE_VSXXXAA is not set
++# CONFIG_MOUSE_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 is not set
++# CONFIG_INPUT_MISC is not set
++
++#
++# Hardware I/O ports
++#
++CONFIG_SERIO=y
++CONFIG_SERIO_SERPORT=y
++# CONFIG_SERIO_AMBAKMI is not set
++# CONFIG_SERIO_PCIPS2 is not set
++CONFIG_SERIO_LIBPS2=y
++# CONFIG_SERIO_RAW is not set
++# CONFIG_SERIO_ALTERA_PS2 is not set
++# CONFIG_SERIO_PS2MULT is not set
++# CONFIG_SERIO_ARC_PS2 is not set
++# CONFIG_SERIO_APBPS2 is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++CONFIG_TTY=y
++CONFIG_VT=y
++CONFIG_CONSOLE_TRANSLATIONS=y
++CONFIG_VT_CONSOLE=y
++CONFIG_VT_CONSOLE_SLEEP=y
++CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
++CONFIG_UNIX98_PTYS=y
++# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
++# CONFIG_LEGACY_PTYS is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
++# CONFIG_NOZOMI is not set
++# CONFIG_N_GSM is not set
++# CONFIG_TRACE_SINK is not set
++CONFIG_DEVMEM=y
++CONFIG_DEVKMEM=y
++
++#
++# Serial drivers
++#
++CONFIG_SERIAL_EARLYCON=y
++# CONFIG_SERIAL_8250 is not set
++
++#
++# Non-8250 serial port support
++#
++# CONFIG_SERIAL_AMBA_PL010 is not set
++CONFIG_SERIAL_AMBA_PL011=y
++CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
++# CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST is not set
++# CONFIG_SERIAL_MAX3100 is not set
++# CONFIG_SERIAL_MAX310X is not set
++# CONFIG_SERIAL_MFD_HSU is not set
++CONFIG_SERIAL_CORE=y
++CONFIG_SERIAL_CORE_CONSOLE=y
++# CONFIG_SERIAL_JSM is not set
++# CONFIG_SERIAL_SCCNXP is not set
++# CONFIG_SERIAL_SC16IS7XX is not set
++# CONFIG_SERIAL_ALTERA_JTAGUART is not set
++# CONFIG_SERIAL_ALTERA_UART is not set
++# CONFIG_SERIAL_XILINX_PS_UART is not set
++# CONFIG_SERIAL_ARC is not set
++# CONFIG_SERIAL_RP2 is not set
++# CONFIG_SERIAL_FSL_LPUART is not set
++# CONFIG_SERIAL_ST_ASC is not set
++# CONFIG_HVC_DCC is not set
++# CONFIG_IPMI_HANDLER is not set
++# CONFIG_HW_RANDOM is not set
++# CONFIG_R3964 is not set
++# CONFIG_APPLICOM is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++CONFIG_DEVPORT=y
++# CONFIG_DCC_TTY is not set
++# CONFIG_XILLYBUS is not set
++
++#
++# I2C support
++#
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++CONFIG_I2C_COMPAT=y
++CONFIG_I2C_CHARDEV=y
++CONFIG_I2C_MUX=y
++
++#
++# Multiplexer I2C Chip support
++#
++# CONFIG_I2C_MUX_PCA9541 is not set
++# CONFIG_I2C_MUX_PINCTRL is not set
++CONFIG_I2C_HELPER_AUTO=y
++
++#
++# I2C Hardware Bus support
++#
++
++#
++# PC SMBus host controller drivers
++#
++# CONFIG_I2C_ALI1535 is not set
++# CONFIG_I2C_ALI1563 is not set
++# CONFIG_I2C_ALI15X3 is not set
++# CONFIG_I2C_AMD756 is not set
++# CONFIG_I2C_AMD8111 is not set
++# CONFIG_I2C_I801 is not set
++# CONFIG_I2C_ISCH is not set
++# CONFIG_I2C_PIIX4 is not set
++# CONFIG_I2C_NFORCE2 is not set
++# CONFIG_I2C_SIS5595 is not set
++# CONFIG_I2C_SIS630 is not set
++# CONFIG_I2C_SIS96X is not set
++# CONFIG_I2C_VIA is not set
++# CONFIG_I2C_VIAPRO is not set
++
++#
++# I2C system bus drivers (mostly embedded / system-on-chip)
++#
++# CONFIG_I2C_DESIGNWARE_PLATFORM is not set
++# CONFIG_I2C_DESIGNWARE_PCI is not set
++# CONFIG_I2C_HIBVT is not set
++# CONFIG_I2C_HISI_V110 is not set
++# CONFIG_I2C_NOMADIK 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_RK3X 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_ROBOTFUZZ_OSIF is not set
++# CONFIG_I2C_TAOS_EVM is not set
++# CONFIG_I2C_TINY_USB is not set
++
++#
++# Other I2C/SMBus bus drivers
++#
++CONFIG_HI_I2C=y
++CONFIG_HI_I2C0_IO_BASE=0x120c0000
++CONFIG_HI_I2C0_IO_SIZE=0x1000
++CONFIG_HI_I2C1_IO_BASE=0x122e0000
++CONFIG_HI_I2C1_IO_SIZE=0x1000
++CONFIG_HI_I2C_RETRIES=0x1
++CONFIG_HI_I2C_TX_FIFO=0x8
++CONFIG_HI_I2C_RX_FIFO=0x8
++CONFIG_HI_I2C0_CLK_LIMIT=100000
++CONFIG_HI_I2C1_CLK_LIMIT=100000
++# 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_CADENCE is not set
++# CONFIG_SPI_FSL_SPI is not set
++CONFIG_SPI_PL022=y
++# CONFIG_SPI_PXA2XX is not set
++# CONFIG_SPI_PXA2XX_PCI is not set
++# CONFIG_SPI_ROCKCHIP 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=y
++# CONFIG_SPI_TLE62X0 is not set
++# CONFIG_SPMI is not set
++# CONFIG_HSI is not set
++
++#
++# PPS support
++#
++# CONFIG_PPS is not set
++
++#
++# PPS generators support
++#
++
++#
++# PTP clock support
++#
++# CONFIG_PTP_1588_CLOCK is not set
++
++#
++# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
++#
++CONFIG_PINCTRL=y
++
++#
++# Pin controllers
++#
++CONFIG_PINMUX=y
++CONFIG_PINCONF=y
++CONFIG_GENERIC_PINCONF=y
++# CONFIG_DEBUG_PINCTRL is not set
++CONFIG_PINCTRL_SINGLE=y
++CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
++CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
++# CONFIG_GPIOLIB is not set
++# CONFIG_W1 is not set
++CONFIG_POWER_SUPPLY=y
++# CONFIG_POWER_SUPPLY_DEBUG is not set
++# CONFIG_PDA_POWER is not set
++# CONFIG_TEST_POWER is not set
++# CONFIG_BATTERY_DS2780 is not set
++# CONFIG_BATTERY_DS2781 is not set
++# CONFIG_BATTERY_DS2782 is not set
++# CONFIG_BATTERY_SBS is not set
++# CONFIG_BATTERY_BQ27x00 is not set
++# CONFIG_BATTERY_MAX17040 is not set
++# CONFIG_BATTERY_MAX17042 is not set
++# CONFIG_CHARGER_MAX8903 is not set
++# CONFIG_CHARGER_LP8727 is not set
++# CONFIG_CHARGER_BQ2415X is not set
++# CONFIG_CHARGER_SMB347 is not set
++CONFIG_POWER_RESET=y
++# CONFIG_POWER_RESET_BRCMSTB is not set
++CONFIG_POWER_RESET_HISI=y
++# CONFIG_POWER_RESET_RESTART is not set
++# CONFIG_POWER_RESET_VERSATILE is not set
++# CONFIG_POWER_RESET_SYSCON is not set
++# CONFIG_POWER_AVS is not set
++# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
++# CONFIG_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=y
++# CONFIG_MFD_AS3711 is not set
++# CONFIG_MFD_AS3722 is not set
++# CONFIG_PMIC_ADP5520 is not set
++# CONFIG_MFD_BCM590XX is not set
++# CONFIG_MFD_AXP20X is not set
++# CONFIG_MFD_CROS_EC is not set
++# CONFIG_PMIC_DA903X is not set
++# CONFIG_MFD_DA9052_SPI is not set
++# CONFIG_MFD_DA9052_I2C is not set
++# CONFIG_MFD_DA9055 is not set
++# CONFIG_MFD_DA9063 is not set
++# CONFIG_MFD_MC13XXX_SPI is not set
++# CONFIG_MFD_MC13XXX_I2C is not set
++# CONFIG_MFD_HI6421_PMIC is not set
++CONFIG_MFD_HISI_FMC=y
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_LPC_ICH is not set
++# CONFIG_LPC_SCH is not set
++# CONFIG_INTEL_SOC_PMIC is not set
++# CONFIG_MFD_JANZ_CMODIO is not set
++# CONFIG_MFD_KEMPLD is not set
++# CONFIG_MFD_88PM800 is not set
++# CONFIG_MFD_88PM805 is not set
++# CONFIG_MFD_88PM860X is not set
++# CONFIG_MFD_MAX14577 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_MENF21BMC is not set
++# CONFIG_EZX_PCAP is not set
++# CONFIG_MFD_VIPERBOARD is not set
++# CONFIG_MFD_RETU is not set
++# CONFIG_MFD_PCF50633 is not set
++# CONFIG_MFD_PM8921_CORE is not set
++# CONFIG_MFD_RDC321X is not set
++# CONFIG_MFD_RTSX_PCI is not set
++# CONFIG_MFD_RTSX_USB is not set
++# CONFIG_MFD_RC5T583 is not set
++# CONFIG_MFD_RK808 is not set
++# CONFIG_MFD_RN5T618 is not set
++# CONFIG_MFD_SEC_CORE is not set
++# CONFIG_MFD_SI476X_CORE is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_MFD_SMSC is not set
++# CONFIG_ABX500_CORE is not set
++# CONFIG_MFD_STMPE is not set
++CONFIG_MFD_SYSCON=y
++# CONFIG_MFD_TI_AM335X_TSCADC is not set
++# CONFIG_MFD_LP3943 is not set
++# CONFIG_MFD_LP8788 is not set
++# CONFIG_MFD_PALMAS is not set
++# CONFIG_TPS6105X is not set
++# CONFIG_TPS6507X is not set
++# CONFIG_MFD_TPS65090 is not set
++# CONFIG_MFD_TPS65217 is not set
++# CONFIG_MFD_TPS65218 is not set
++# CONFIG_MFD_TPS6586X is not set
++# CONFIG_MFD_TPS80031 is not set
++# CONFIG_TWL4030_CORE is not set
++# CONFIG_TWL6040_CORE is not set
++# CONFIG_MFD_WL1273_CORE is not set
++# CONFIG_MFD_LM3533 is not set
++# CONFIG_MFD_TC3589X is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_MFD_T7L66XB is not set
++# CONFIG_MFD_TC6387XB is not set
++# CONFIG_MFD_TC6393XB is not set
++# CONFIG_MFD_VX855 is not set
++# CONFIG_MFD_ARIZONA_I2C is not set
++# CONFIG_MFD_ARIZONA_SPI is not set
++# CONFIG_MFD_WM8400 is not set
++# CONFIG_MFD_WM831X_I2C is not set
++# CONFIG_MFD_WM831X_SPI is not set
++# CONFIG_MFD_WM8350_I2C is not set
++# CONFIG_MFD_WM8994 is not set
++CONFIG_REGULATOR=y
++# CONFIG_REGULATOR_DEBUG is not set
++# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
++# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
++# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
++# CONFIG_REGULATOR_ACT8865 is not set
++# CONFIG_REGULATOR_AD5398 is not set
++# CONFIG_REGULATOR_ANATOP is not set
++# CONFIG_REGULATOR_DA9210 is not set
++# CONFIG_REGULATOR_DA9211 is not set
++# CONFIG_REGULATOR_FAN53555 is not set
++# CONFIG_REGULATOR_ISL9305 is not set
++# CONFIG_REGULATOR_ISL6271A is not set
++# CONFIG_REGULATOR_LP3971 is not set
++# CONFIG_REGULATOR_LP3972 is not set
++# CONFIG_REGULATOR_LP872X is not set
++# CONFIG_REGULATOR_LP8755 is not set
++# CONFIG_REGULATOR_LTC3589 is not set
++# CONFIG_REGULATOR_MAX1586 is not set
++# CONFIG_REGULATOR_MAX8649 is not set
++# CONFIG_REGULATOR_MAX8660 is not set
++# CONFIG_REGULATOR_MAX8952 is not set
++# CONFIG_REGULATOR_MAX8973 is not set
++# CONFIG_REGULATOR_PFUZE100 is not set
++# CONFIG_REGULATOR_TPS51632 is not set
++# CONFIG_REGULATOR_TPS62360 is not set
++# CONFIG_REGULATOR_TPS65023 is not set
++# CONFIG_REGULATOR_TPS6507X is not set
++# CONFIG_REGULATOR_TPS6524X is not set
++# CONFIG_MEDIA_SUPPORT is not set
++
++#
++# Graphics support
++#
++CONFIG_VGA_ARB=y
++CONFIG_VGA_ARB_MAX_GPUS=16
++# CONFIG_IMX_IPUV3_CORE is not set
++
++#
++# Direct Rendering Manager
++#
++# CONFIG_DRM is not set
++
++#
++# Frame buffer Devices
++#
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++CONFIG_FB_CMDLINE=y
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++# CONFIG_FB_CFB_FILLRECT is not set
++# CONFIG_FB_CFB_COPYAREA is not set
++# CONFIG_FB_CFB_IMAGEBLIT is not set
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# 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_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_CIRRUS is not set
++# CONFIG_FB_PM2 is not set
++# CONFIG_FB_ARMCLCD is not set
++# CONFIG_FB_CYBER2000 is not set
++# CONFIG_FB_ASILIANT is not set
++# CONFIG_FB_IMSTT is not set
++# CONFIG_FB_OPENCORES is not set
++# CONFIG_FB_S1D13XXX is not set
++# CONFIG_FB_NVIDIA is not set
++# CONFIG_FB_RIVA is not set
++# CONFIG_FB_I740 is not set
++# CONFIG_FB_MATROX is not set
++# CONFIG_FB_RADEON is not set
++# CONFIG_FB_ATY128 is not set
++# CONFIG_FB_ATY is not set
++# CONFIG_FB_S3 is not set
++# CONFIG_FB_SAVAGE is not set
++# CONFIG_FB_SIS is not set
++# CONFIG_FB_NEOMAGIC is not set
++# CONFIG_FB_KYRO is not set
++# CONFIG_FB_3DFX is not set
++# CONFIG_FB_VOODOO1 is not set
++# CONFIG_FB_VT8623 is not set
++# CONFIG_FB_TRIDENT is not set
++# CONFIG_FB_ARK is not set
++# CONFIG_FB_PM3 is not set
++# CONFIG_FB_CARMINE is not set
++# CONFIG_FB_SMSCUFX is not set
++# CONFIG_FB_UDL is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_MB862XX is not set
++# CONFIG_FB_BROADSHEET is not set
++# CONFIG_FB_AUO_K190X is not set
++# CONFIG_FB_SIMPLE is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++# CONFIG_VGASTATE is not set
++
++#
++# Console display driver support
++#
++CONFIG_DUMMY_CONSOLE=y
++# CONFIG_FRAMEBUFFER_CONSOLE is not set
++# CONFIG_LOGO is not set
++# CONFIG_SOUND is not set
++
++#
++# HID support
++#
++CONFIG_HID=y
++# CONFIG_HID_BATTERY_STRENGTH is not set
++# CONFIG_HIDRAW is not set
++# CONFIG_UHID is not set
++CONFIG_HID_GENERIC=y
++
++#
++# Special HID drivers
++#
++CONFIG_HID_A4TECH=y
++# CONFIG_HID_ACRUX is not set
++CONFIG_HID_APPLE=y
++# CONFIG_HID_APPLEIR is not set
++# CONFIG_HID_AUREAL is not set
++CONFIG_HID_BELKIN=y
++CONFIG_HID_CHERRY=y
++CONFIG_HID_CHICONY=y
++CONFIG_HID_CYPRESS=y
++# CONFIG_HID_DRAGONRISE is not set
++# CONFIG_HID_EMS_FF is not set
++# CONFIG_HID_ELECOM is not set
++# CONFIG_HID_ELO is not set
++CONFIG_HID_EZKEY=y
++# CONFIG_HID_HOLTEK is not set
++# CONFIG_HID_HUION 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_ICADE is not set
++# CONFIG_HID_TWINHAN is not set
++CONFIG_HID_KENSINGTON=y
++# CONFIG_HID_LCPOWER is not set
++# CONFIG_HID_LENOVO is not set
++CONFIG_HID_LOGITECH=y
++# CONFIG_HID_LOGITECH_HIDPP is not set
++# CONFIG_LOGITECH_FF is not set
++# CONFIG_LOGIRUMBLEPAD2_FF is not set
++# CONFIG_LOGIG940_FF is not set
++# CONFIG_LOGIWHEELS_FF is not set
++# CONFIG_HID_MAGICMOUSE is not set
++CONFIG_HID_MICROSOFT=y
++CONFIG_HID_MONTEREY=y
++# 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_PENMOUNT is not set
++# CONFIG_HID_PETALYNX is not set
++# CONFIG_HID_PICOLCD is not set
++# CONFIG_HID_PRIMAX is not set
++# CONFIG_HID_ROCCAT is not set
++# CONFIG_HID_SAITEK is not set
++# CONFIG_HID_SAMSUNG is not set
++# CONFIG_HID_SPEEDLINK is not set
++# CONFIG_HID_STEELSERIES is not set
++# CONFIG_HID_SUNPLUS is not set
++# CONFIG_HID_RMI 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_XINMO is not set
++# CONFIG_HID_ZEROPLUS is not set
++# CONFIG_HID_ZYDACRON is not set
++# CONFIG_HID_SENSOR_HUB is not set
++
++#
++# USB HID support
++#
++CONFIG_USB_HID=y
++# CONFIG_HID_PID is not set
++# CONFIG_USB_HIDDEV is not set
++
++#
++# I2C HID support
++#
++# CONFIG_I2C_HID is not set
++CONFIG_USB_OHCI_LITTLE_ENDIAN=y
++CONFIG_USB_SUPPORT=y
++CONFIG_USB_COMMON=y
++CONFIG_USB_ARCH_HAS_HCD=y
++CONFIG_USB=y
++# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
++
++#
++# Miscellaneous USB options
++#
++CONFIG_USB_DEFAULT_PERSIST=y
++# CONFIG_USB_DYNAMIC_MINORS is not set
++# CONFIG_USB_OTG_WHITELIST is not set
++# CONFIG_USB_OTG_FSM is not set
++# CONFIG_USB_MON is not set
++# CONFIG_USB_WUSB_CBAF is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_C67X00_HCD is not set
++CONFIG_USB_XHCI_HCD=y
++CONFIG_USB_XHCI_PCI=y
++CONFIG_USB_XHCI_PLATFORM=y
++CONFIG_USB_XHCI_HISILICON=y
++CONFIG_USB_EHCI_HCD=y
++# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
++CONFIG_USB_EHCI_TT_NEWSCHED=y
++CONFIG_USB_EHCI_PCI=y
++CONFIG_USB_EHCI_HCD_PLATFORM=y
++# 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_FUSBH200_HCD is not set
++# CONFIG_USB_FOTG210_HCD is not set
++# CONFIG_USB_MAX3421_HCD is not set
++CONFIG_USB_OHCI_HCD=y
++CONFIG_USB_OHCI_HCD_PCI=y
++CONFIG_USB_OHCI_HCD_PLATFORM=y
++# CONFIG_USB_UHCI_HCD is not set
++# CONFIG_USB_SL811_HCD is not set
++# CONFIG_USB_R8A66597_HCD is not set
++# CONFIG_USB_HCD_TEST_MODE is not set
++
++#
++# USB Device Class drivers
++#
++# CONFIG_USB_ACM is not set
++# CONFIG_USB_PRINTER is not set
++# CONFIG_USB_WDM is not set
++# CONFIG_USB_TMC is not set
++
++#
++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
++#
++
++#
++# also be needed; see USB_STORAGE Help for more info
++#
++CONFIG_USB_STORAGE=y
++# CONFIG_USB_STORAGE_DEBUG is not set
++# CONFIG_USB_STORAGE_REALTEK is not set
++# CONFIG_USB_STORAGE_DATAFAB is not set
++# CONFIG_USB_STORAGE_FREECOM is not set
++# CONFIG_USB_STORAGE_ISD200 is not set
++# CONFIG_USB_STORAGE_USBAT is not set
++# CONFIG_USB_STORAGE_SDDR09 is not set
++# CONFIG_USB_STORAGE_SDDR55 is not set
++# CONFIG_USB_STORAGE_JUMPSHOT is not set
++# CONFIG_USB_STORAGE_ALAUDA is not set
++# CONFIG_USB_STORAGE_ONETOUCH is not set
++# CONFIG_USB_STORAGE_KARMA is not set
++# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
++# CONFIG_USB_STORAGE_ENE_UB6250 is not set
++# CONFIG_USB_UAS is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++# CONFIG_USBIP_CORE is not set
++# CONFIG_USB_MUSB_HDRC is not set
++# CONFIG_USB_DWC3 is not set
++# CONFIG_USB_DWC2 is not set
++# CONFIG_USB_CHIPIDEA is not set
++
++#
++# USB port drivers
++#
++# CONFIG_USB_SERIAL is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
++# CONFIG_USB_SEVSEG is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
++# CONFIG_USB_APPLEDISPLAY is not set
++# CONFIG_USB_SISUSBVGA is not set
++# CONFIG_USB_LD is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
++# CONFIG_USB_IOWARRIOR is not set
++# CONFIG_USB_TEST is not set
++# CONFIG_USB_EHSET_TEST_FIXTURE is not set
++# CONFIG_USB_ISIGHTFW is not set
++# CONFIG_USB_YUREX is not set
++# CONFIG_USB_EZUSB_FX2 is not set
++# CONFIG_USB_HSIC_USB3503 is not set
++# CONFIG_USB_LINK_LAYER_TEST is not set
++
++#
++# USB Physical Layer drivers
++#
++# CONFIG_USB_PHY is not set
++# CONFIG_USB_OTG_WAKELOCK is not set
++# CONFIG_NOP_USB_XCEIV is not set
++# CONFIG_AM335X_PHY_USB is not set
++# CONFIG_USB_ISP1301 is not set
++# CONFIG_USB_ULPI is not set
++# CONFIG_USB_GADGET is not set
++# CONFIG_UWB is not set
++# CONFIG_MMC is not set
++# CONFIG_MEMSTICK is not set
++# CONFIG_NEW_LEDS is not set
++# CONFIG_SWITCH is not set
++# CONFIG_ACCESSIBILITY is not set
++# CONFIG_INFINIBAND is not set
++# CONFIG_EDAC is not set
++CONFIG_RTC_LIB=y
++# CONFIG_RTC_CLASS is not set
++# CONFIG_DMADEVICES is not set
++# CONFIG_AUXDISPLAY is not set
++# CONFIG_UIO is not set
++# CONFIG_VIRT_DRIVERS is not set
++
++#
++# Virtio drivers
++#
++# CONFIG_VIRTIO_PCI is not set
++# CONFIG_VIRTIO_MMIO is not set
++
++#
++# Microsoft Hyper-V guest support
++#
++# CONFIG_STAGING is not set
++
++#
++# SOC (System On Chip) specific Drivers
++#
++# CONFIG_SOC_TI is not set
++CONFIG_CLKDEV_LOOKUP=y
++CONFIG_HAVE_CLK_PREPARE=y
++CONFIG_COMMON_CLK=y
++
++#
++# Common Clock Framework
++#
++# CONFIG_COMMON_CLK_SI5351 is not set
++# CONFIG_COMMON_CLK_SI570 is not set
++# CONFIG_COMMON_CLK_PXA is not set
++# CONFIG_COMMON_CLK_QCOM is not set
++
++#
++# Hardware Spinlock drivers
++#
++
++#
++# Clock Source drivers
++#
++CONFIG_CLKSRC_OF=y
++CONFIG_CLKSRC_MMIO=y
++CONFIG_ARM_ARCH_TIMER=y
++CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y
++# CONFIG_ARM_ARCH_TIMER_VCT_ACCESS is not set
++# CONFIG_ATMEL_PIT is not set
++# CONFIG_SH_TIMER_CMT is not set
++# CONFIG_SH_TIMER_MTU2 is not set
++# CONFIG_SH_TIMER_TMU is not set
++# CONFIG_EM_TIMER_STI is not set
++# CONFIG_CLKSRC_VERSATILE is not set
++# CONFIG_MAILBOX is not set
++# CONFIG_IOMMU_SUPPORT is not set
++
++#
++# Remoteproc drivers
++#
++# CONFIG_STE_MODEM_RPROC is not set
++
++#
++# Rpmsg drivers
++#
++
++#
++# SOC (System On Chip) specific Drivers
++#
++# CONFIG_PM_DEVFREQ is not set
++# CONFIG_EXTCON is not set
++# CONFIG_MEMORY is not set
++# CONFIG_IIO is not set
++# CONFIG_VME_BUS is not set
++# CONFIG_PWM is not set
++CONFIG_IRQCHIP=y
++CONFIG_ARM_GIC=y
++# CONFIG_IPACK_BUS is not set
++CONFIG_ARCH_HAS_RESET_CONTROLLER=y
++CONFIG_RESET_CONTROLLER=y
++# CONFIG_FMC is not set
++
++#
++# PHY Subsystem
++#
++CONFIG_GENERIC_PHY=y
++# CONFIG_BCM_KONA_USB2_PHY is not set
++# CONFIG_PHY_HISI_INNO_USB2 is not set
++CONFIG_PHY_HI35x1D_INNO_USB2=y
++CONFIG_PHY_HI3531D_USB3=y
++CONFIG_HI_NANO_PHY_SATA=y
++CONFIG_HI_SATA_PORTS=4
++CONFIG_HI_SATA_MODE=1
++# CONFIG_POWERCAP is not set
++# CONFIG_MCB is not set
++CONFIG_RAS=y
++# CONFIG_THUNDERBOLT is not set
++CONFIG_HI_DMAC=y
++CONFIG_HI_DMAC_CHANNEL_NUM=4
++
++#
++# Hisilicon driver support
++#
++
++#
++# File systems
++#
++CONFIG_DCACHE_WORD_ACCESS=y
++# CONFIG_EXT2_FS is not set
++# CONFIG_EXT3_FS is not set
++CONFIG_EXT4_FS=y
++CONFIG_EXT4_USE_FOR_EXT23=y
++# CONFIG_EXT4_FS_POSIX_ACL is not set
++# CONFIG_EXT4_FS_SECURITY is not set
++# CONFIG_EXT4_DEBUG is not set
++CONFIG_JBD2=y
++# CONFIG_JBD2_DEBUG is not set
++CONFIG_FS_MBCACHE=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_BTRFS_FS is not set
++# CONFIG_NILFS2_FS is not set
++CONFIG_FS_POSIX_ACL=y
++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 is not set
++# CONFIG_FUSE_FS is not set
++# CONFIG_OVERLAY_FS is not set
++
++#
++# Caches
++#
++# CONFIG_FSCACHE is not set
++
++#
++# CD-ROM/DVD Filesystems
++#
++CONFIG_ISO9660_FS=y
++# CONFIG_JOLIET is not set
++# CONFIG_ZISOFS is not set
++CONFIG_UDF_FS=y
++CONFIG_UDF_NLS=y
++
++#
++# DOS/FAT/NT Filesystems
++#
++CONFIG_FAT_FS=y
++CONFIG_MSDOS_FS=y
++CONFIG_VFAT_FS=y
++CONFIG_FAT_DEFAULT_CODEPAGE=437
++CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
++# CONFIG_NTFS_FS is not set
++
++#
++# Pseudo filesystems
++#
++CONFIG_PROC_FS=y
++CONFIG_PROC_SYSCTL=y
++CONFIG_PROC_PAGE_MONITOR=y
++CONFIG_KERNFS=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=m
++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_YAFFS_FS=y
++CONFIG_YAFFS_YAFFS1=y
++# CONFIG_YAFFS_9BYTE_TAGS is not set
++# CONFIG_YAFFS_DOES_ECC is not set
++CONFIG_YAFFS_YAFFS2=y
++CONFIG_YAFFS_AUTO_YAFFS2=y
++# CONFIG_YAFFS_DISABLE_TAGS_ECC is not set
++# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
++# CONFIG_YAFFS_EMPTY_LOST_AND_FOUND is not set
++# CONFIG_YAFFS_DISABLE_BLOCK_REFRESHING is not set
++# CONFIG_YAFFS_DISABLE_BACKGROUND is not set
++# CONFIG_YAFFS_DISABLE_BAD_BLOCK_MARKING is not set
++CONFIG_YAFFS_XATTR=y
++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 is not set
++# CONFIG_JFFS2_FS_XATTR is not set
++# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
++CONFIG_JFFS2_ZLIB=y
++# CONFIG_JFFS2_LZO is not set
++CONFIG_JFFS2_RTIME=y
++# CONFIG_JFFS2_RUBIN 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 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 is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V2=y
++CONFIG_NFS_V3=y
++CONFIG_NFS_V3_ACL=y
++# CONFIG_NFS_V4 is not set
++# CONFIG_NFS_SWAP is not set
++# CONFIG_ROOT_NFS is not set
++# CONFIG_NFSD is not set
++CONFIG_GRACE_PERIOD=y
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_ACL_SUPPORT=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 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=y
++# CONFIG_DLM is not set
++
++#
++# Kernel hacking
++#
++
++#
++# printk and dmesg options
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4
++# CONFIG_BOOT_PRINTK_DELAY is not set
++
++#
++# Compile-time checks and compiler options
++#
++# CONFIG_DEBUG_INFO is not set
++# CONFIG_ENABLE_WARN_DEPRECATED is not set
++# CONFIG_ENABLE_MUST_CHECK is not set
++CONFIG_FRAME_WARN=1024
++# CONFIG_STRIP_ASM_SYMS is not set
++# CONFIG_READABLE_ASM is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++# CONFIG_DEBUG_FS is not set
++# CONFIG_HEADERS_CHECK is not set
++# CONFIG_DEBUG_SECTION_MISMATCH is not set
++# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
++# CONFIG_MAGIC_SYSRQ is not set
++CONFIG_DEBUG_KERNEL=y
++
++#
++# Memory Debugging
++#
++# CONFIG_DEBUG_PAGEALLOC is not set
++# 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_STACK_USAGE is not set
++# CONFIG_DEBUG_VM is not set
++CONFIG_DEBUG_MEMORY_INIT=y
++# CONFIG_DEBUG_PER_CPU_MAPS is not set
++# CONFIG_DEBUG_HIGHMEM is not set
++# CONFIG_DEBUG_SHIRQ is not set
++
++#
++# Debug Lockups and Hangs
++#
++# CONFIG_LOCKUP_DETECTOR is not set
++# CONFIG_DETECT_HUNG_TASK is not set
++# CONFIG_PANIC_ON_OOPS is not set
++CONFIG_PANIC_ON_OOPS_VALUE=0
++CONFIG_PANIC_TIMEOUT=0
++CONFIG_SCHED_DEBUG=y
++# CONFIG_SCHEDSTATS is not set
++# CONFIG_SCHED_STACK_END_CHECK is not set
++# CONFIG_TIMER_STATS is not set
++
++#
++# Lock Debugging (spinlocks, mutexes, etc...)
++#
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_LOCK_STAT is not set
++# CONFIG_DEBUG_ATOMIC_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_LOCK_TORTURE_TEST is not set
++CONFIG_STACKTRACE=y
++# CONFIG_DEBUG_KOBJECT is not set
++CONFIG_DEBUG_BUGVERBOSE=y
++# CONFIG_DEBUG_LIST is not set
++# CONFIG_DEBUG_PI_LIST is not set
++# CONFIG_DEBUG_SG is not set
++# CONFIG_DEBUG_NOTIFIERS is not set
++# CONFIG_DEBUG_CREDENTIALS is not set
++
++#
++# RCU Debugging
++#
++# CONFIG_SPARSE_RCU_POINTER is not set
++# CONFIG_TORTURE_TEST 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_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_NOTIFIER_ERROR_INJECTION is not set
++# CONFIG_FAULT_INJECTION 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 is not set
++
++#
++# Runtime Testing
++#
++# CONFIG_TEST_LIST_SORT is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_RBTREE_TEST is not set
++# CONFIG_INTERVAL_TREE_TEST is not set
++# CONFIG_PERCPU_TEST is not set
++# CONFIG_ATOMIC64_SELFTEST is not set
++# CONFIG_TEST_STRING_HELPERS is not set
++# CONFIG_TEST_KSTRTOX is not set
++# CONFIG_TEST_RHASHTABLE is not set
++# CONFIG_DMA_API_DEBUG is not set
++# CONFIG_TEST_LKM is not set
++# CONFIG_TEST_USER_COPY is not set
++# CONFIG_TEST_BPF is not set
++# CONFIG_TEST_FIRMWARE is not set
++# CONFIG_TEST_UDELAY is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_KGDB is not set
++# CONFIG_ARM_PTDUMP is not set
++CONFIG_STRICT_DEVMEM=y
++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_DEBUG_UART_PL01X is not set
++# CONFIG_DEBUG_UART_8250 is not set
++# CONFIG_DEBUG_UART_BCM63XX is not set
++CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"
++# CONFIG_OC_ETM is not set
++# CONFIG_PID_IN_CONTEXTIDR is not set
++# CONFIG_DEBUG_SET_MODULE_RONX is not set
++# CONFIG_CORESIGHT is not set
++
++#
++# 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_HASH=y
++CONFIG_CRYPTO_HASH2=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_PCRYPT is not set
++# CONFIG_CRYPTO_CRYPTD is not set
++# CONFIG_CRYPTO_MCRYPTD 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_CMAC is not set
++# CONFIG_CRYPTO_HMAC is not set
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_VMAC is not set
++
++#
++# Digest
++#
++CONFIG_CRYPTO_CRC32C=y
++# CONFIG_CRYPTO_CRC32 is not set
++# CONFIG_CRYPTO_CRCT10DIF 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_SHA1_ARM_NEON is not set
++# CONFIG_CRYPTO_SHA256 is not set
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_SHA512_ARM_NEON 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_AES_ARM_BS 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
++# CONFIG_CRYPTO_LZ4 is not set
++# CONFIG_CRYPTO_LZ4HC is not set
++
++#
++# Random Number Generation
++#
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++# CONFIG_CRYPTO_DRBG_MENU 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_HIFN_795X 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_NET_UTILS=y
++CONFIG_GENERIC_PCI_IOMAP=y
++CONFIG_GENERIC_IO=y
++CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
++# CONFIG_CRC_CCITT is not set
++CONFIG_CRC16=y
++# CONFIG_CRC_T10DIF is not set
++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 is not set
++# CONFIG_LIBCRC32C is not set
++# CONFIG_CRC8 is not set
++# CONFIG_AUDIT_ARCH_COMPAT_GENERIC is not set
++# CONFIG_RANDOM32_SELFTEST is not set
++CONFIG_ZLIB_INFLATE=y
++CONFIG_ZLIB_DEFLATE=y
++CONFIG_LZO_COMPRESS=y
++CONFIG_LZO_DECOMPRESS=y
++CONFIG_LZ4_DECOMPRESS=y
++CONFIG_XZ_DEC=y
++CONFIG_XZ_DEC_X86=y
++CONFIG_XZ_DEC_POWERPC=y
++CONFIG_XZ_DEC_IA64=y
++CONFIG_XZ_DEC_ARM=y
++CONFIG_XZ_DEC_ARMTHUMB=y
++CONFIG_XZ_DEC_SPARC=y
++CONFIG_XZ_DEC_BCJ=y
++# CONFIG_XZ_DEC_TEST is not set
++CONFIG_DECOMPRESS_GZIP=y
++CONFIG_DECOMPRESS_BZIP2=y
++CONFIG_DECOMPRESS_LZMA=y
++CONFIG_DECOMPRESS_XZ=y
++CONFIG_DECOMPRESS_LZO=y
++CONFIG_DECOMPRESS_LZ4=y
++CONFIG_GENERIC_ALLOCATOR=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT_MAP=y
++CONFIG_HAS_DMA=y
++CONFIG_CPU_RMAP=y
++CONFIG_DQL=y
++CONFIG_GLOB=y
++# CONFIG_GLOB_SELFTEST is not set
++CONFIG_NLATTR=y
++CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
++# CONFIG_AVERAGE is not set
++# CONFIG_CORDIC is not set
++# CONFIG_DDR is not set
++CONFIG_LIBFDT=y
++CONFIG_ARCH_HAS_SG_CHAIN=y
++# CONFIG_VIRTUALIZATION is not set
+diff --git a/arch/arm/configs/hi3531d_full_slave_defconfig b/arch/arm/configs/hi3531d_full_slave_defconfig
+new file mode 100644
+index 0000000..30e6c6f
+--- /dev/null
++++ b/arch/arm/configs/hi3531d_full_slave_defconfig
+@@ -0,0 +1,2437 @@
++#
++# Automatically generated file; DO NOT EDIT.
++# Linux/arm 3.18.20 Kernel Configuration
++#
++CONFIG_ARM=y
++CONFIG_ARM_HAS_SG_CHAIN=y
++CONFIG_MIGHT_HAVE_PCI=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=y
++CONFIG_HAVE_PROC_CPU=y
++CONFIG_STACKTRACE_SUPPORT=y
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
++CONFIG_RWSEM_XCHGADD_ALGORITHM=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_NEED_DMA_MAP_STATE=y
++CONFIG_ARCH_SUPPORTS_UPROBES=y
++CONFIG_VECTORS_BASE=0xffff0000
++CONFIG_ARM_PATCH_PHYS_VIRT=y
++CONFIG_GENERIC_BUG=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++CONFIG_IRQ_WORK=y
++CONFIG_BUILDTIME_EXTABLE_SORT=y
++
++#
++# General setup
++#
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_CROSS_COMPILE=""
++# CONFIG_COMPILE_TEST is not set
++CONFIG_LOCALVERSION=""
++# CONFIG_LOCALVERSION_AUTO is not set
++CONFIG_HAVE_KERNEL_GZIP=y
++CONFIG_HAVE_KERNEL_LZMA=y
++CONFIG_HAVE_KERNEL_XZ=y
++CONFIG_HAVE_KERNEL_LZO=y
++CONFIG_HAVE_KERNEL_LZ4=y
++CONFIG_KERNEL_GZIP=y
++# CONFIG_KERNEL_LZMA is not set
++# CONFIG_KERNEL_XZ is not set
++# CONFIG_KERNEL_LZO is not set
++# CONFIG_KERNEL_LZ4 is not set
++CONFIG_DEFAULT_HOSTNAME="(none)"
++# CONFIG_SWAP is not set
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++# CONFIG_POSIX_MQUEUE is not set
++CONFIG_CROSS_MEMORY_ATTACH=y
++# CONFIG_FHANDLE is not set
++CONFIG_USELIB=y
++# CONFIG_AUDIT is not set
++
++#
++# IRQ subsystem
++#
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_GENERIC_IRQ_SHOW=y
++CONFIG_HARDIRQS_SW_RESEND=y
++CONFIG_IRQ_DOMAIN=y
++CONFIG_HANDLE_DOMAIN_IRQ=y
++CONFIG_IRQ_FORCED_THREADING=y
++CONFIG_SPARSE_IRQ=y
++CONFIG_GENERIC_CLOCKEVENTS=y
++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
++CONFIG_ARCH_HAS_TICK_BROADCAST=y
++CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
++
++#
++# Timers subsystem
++#
++CONFIG_HZ_PERIODIC=y
++# CONFIG_NO_HZ_IDLE is not set
++# CONFIG_NO_HZ_FULL is not set
++# CONFIG_NO_HZ is not set
++# CONFIG_HIGH_RES_TIMERS is not set
++
++#
++# CPU/Task time and stats accounting
++#
++CONFIG_TICK_CPU_ACCOUNTING=y
++# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set
++# CONFIG_IRQ_TIME_ACCOUNTING is not set
++# CONFIG_BSD_PROCESS_ACCT is not set
++# CONFIG_TASKSTATS is not set
++
++#
++# RCU Subsystem
++#
++CONFIG_TREE_RCU=y
++# CONFIG_PREEMPT_RCU is not set
++# CONFIG_TASKS_RCU is not set
++CONFIG_RCU_STALL_COMMON=y
++# CONFIG_RCU_USER_QS is not set
++CONFIG_RCU_FANOUT=32
++CONFIG_RCU_FANOUT_LEAF=16
++# CONFIG_RCU_FANOUT_EXACT is not set
++# CONFIG_TREE_RCU_TRACE is not set
++# CONFIG_RCU_NOCB_CPU is not set
++# CONFIG_BUILD_BIN2C is not set
++# CONFIG_IKCONFIG is not set
++CONFIG_LOG_BUF_SHIFT=17
++CONFIG_LOG_CPU_MAX_BUF_SHIFT=12
++CONFIG_GENERIC_SCHED_CLOCK=y
++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_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_USER_NS is not set
++CONFIG_PID_NS=y
++CONFIG_NET_NS=y
++# 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=y
++CONFIG_RD_LZMA=y
++CONFIG_RD_XZ=y
++CONFIG_RD_LZO=y
++CONFIG_RD_LZ4=y
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++CONFIG_HAVE_UID16=y
++CONFIG_BPF=y
++# CONFIG_EXPERT is not set
++CONFIG_UID16=y
++# CONFIG_SGETMASK_SYSCALL is not set
++CONFIG_SYSFS_SYSCALL=y
++# CONFIG_SYSCTL_SYSCALL is not set
++CONFIG_KALLSYMS=y
++# CONFIG_KALLSYMS_ALL is not set
++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_BPF_SYSCALL is not set
++CONFIG_SHMEM=y
++CONFIG_AIO=y
++CONFIG_ADVISE_SYSCALLS=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 is not set
++# CONFIG_SLAB is not set
++CONFIG_SLUB=y
++CONFIG_SLUB_CPU_PARTIAL=y
++# CONFIG_PROFILING is not set
++CONFIG_HAVE_OPROFILE=y
++# CONFIG_KPROBES is not set
++# CONFIG_JUMP_LABEL is not set
++# CONFIG_UPROBES is not set
++# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
++CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
++CONFIG_ARCH_USE_BUILTIN_BSWAP=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_GENERIC_SMP_IDLE_THREAD=y
++CONFIG_GENERIC_IDLE_POLL_SETUP=y
++CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
++CONFIG_HAVE_CLK=y
++CONFIG_HAVE_DMA_API_DEBUG=y
++CONFIG_HAVE_PERF_REGS=y
++CONFIG_HAVE_PERF_USER_STACK_DUMP=y
++CONFIG_HAVE_ARCH_JUMP_LABEL=y
++CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
++CONFIG_HAVE_CC_STACKPROTECTOR=y
++# CONFIG_CC_STACKPROTECTOR is not set
++CONFIG_CC_STACKPROTECTOR_NONE=y
++# CONFIG_CC_STACKPROTECTOR_REGULAR is not set
++# CONFIG_CC_STACKPROTECTOR_STRONG is not set
++CONFIG_HAVE_CONTEXT_TRACKING=y
++CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
++CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
++CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
++CONFIG_MODULES_USE_ELF_REL=y
++CONFIG_CLONE_BACKWARDS=y
++CONFIG_OLD_SIGSUSPEND3=y
++CONFIG_OLD_SIGACTION=y
++
++#
++# GCOV-based kernel profiling
++#
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_SLABINFO=y
++CONFIG_RT_MUTEXES=y
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++# CONFIG_MODULE_FORCE_LOAD is not set
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++# CONFIG_MODULE_SIG is not set
++# CONFIG_MODULE_COMPRESS is not set
++CONFIG_STOP_MACHINE=y
++CONFIG_BLOCK=y
++CONFIG_LBDAF=y
++CONFIG_BLK_DEV_BSG=y
++# CONFIG_BLK_DEV_BSGLIB is not set
++# CONFIG_BLK_DEV_INTEGRITY is not set
++CONFIG_BLK_CMDLINE_PARSER=y
++
++#
++# Partition Types
++#
++CONFIG_PARTITION_ADVANCED=y
++# CONFIG_ACORN_PARTITION is not set
++# CONFIG_AIX_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=y
++# CONFIG_SYSV68_PARTITION is not set
++CONFIG_CMDLINE_PARTITION=y
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++CONFIG_DEFAULT_DEADLINE=y
++# CONFIG_DEFAULT_CFQ is not set
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="deadline"
++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_ARCH_SUPPORTS_ATOMIC_RMW=y
++CONFIG_MUTEX_SPIN_ON_OWNER=y
++CONFIG_RWSEM_SPIN_ON_OWNER=y
++CONFIG_FREEZER=y
++
++#
++# System Type
++#
++CONFIG_MMU=y
++CONFIG_ARCH_MULTIPLATFORM=y
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_AT91 is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_GEMINI is not set
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_IOP13XX is not set
++# CONFIG_ARCH_IOP32X is not set
++# CONFIG_ARCH_IOP33X is not set
++# CONFIG_ARCH_IXP4XX is not set
++# CONFIG_ARCH_DOVE is not set
++# CONFIG_ARCH_MV78XX0 is not set
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_MMP is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_W90X900 is not set
++# CONFIG_ARCH_LPC32XX is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_MSM is not set
++# CONFIG_ARCH_SHMOBILE_LEGACY 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_DAVINCI is not set
++# CONFIG_ARCH_OMAP1 is not set
++
++#
++# Multiple platform selection
++#
++
++#
++# CPU Core family selection
++#
++# CONFIG_ARCH_MULTI_V6 is not set
++CONFIG_ARCH_MULTI_V7=y
++CONFIG_ARCH_MULTI_V6_V7=y
++# CONFIG_ARCH_MULTI_CPU_AUTO is not set
++# CONFIG_ARCH_VIRT is not set
++# CONFIG_ARCH_MVEBU is not set
++# CONFIG_ARCH_BCM is not set
++# CONFIG_ARCH_BERLIN is not set
++# CONFIG_ARCH_HIGHBANK is not set
++CONFIG_ARCH_HISI=y
++
++#
++# Hisilicon platform type
++#
++# CONFIG_ARCH_HI3xxx is not set
++# CONFIG_ARCH_HIP04 is not set
++# CONFIG_ARCH_HIX5HD2 is not set
++# CONFIG_ARCH_HI3519 is not set
++# CONFIG_ARCH_HI3519V101 is not set
++# CONFIG_ARCH_HI3516AV200 is not set
++# CONFIG_ARCH_HI3559 is not set
++# CONFIG_ARCH_HI3556 is not set
++# CONFIG_ARCH_HI3536C is not set
++CONFIG_ARCH_HI3531D=y
++# CONFIG_ARCH_HI3521D is not set
++# CONFIG_ARCH_KEYSTONE is not set
++# CONFIG_ARCH_MESON is not set
++# CONFIG_ARCH_MXC is not set
++# CONFIG_ARCH_MEDIATEK is not set
++
++#
++# TI OMAP/AM/DM/DRA Family
++#
++# CONFIG_ARCH_OMAP3 is not set
++# CONFIG_ARCH_OMAP4 is not set
++# CONFIG_SOC_OMAP5 is not set
++# CONFIG_SOC_AM33XX is not set
++# CONFIG_SOC_AM43XX is not set
++# CONFIG_SOC_DRA7XX is not set
++# CONFIG_ARCH_QCOM is not set
++# CONFIG_ARCH_ROCKCHIP is not set
++# CONFIG_ARCH_SOCFPGA is not set
++# CONFIG_PLAT_SPEAR is not set
++# CONFIG_ARCH_STI is not set
++# CONFIG_ARCH_S5PV210 is not set
++# CONFIG_ARCH_EXYNOS is not set
++# CONFIG_ARCH_SHMOBILE_MULTI is not set
++# CONFIG_ARCH_SUNXI is not set
++# CONFIG_ARCH_SIRF is not set
++# CONFIG_ARCH_TEGRA is not set
++# CONFIG_ARCH_U8500 is not set
++# CONFIG_ARCH_VEXPRESS is not set
++# CONFIG_ARCH_WM8850 is not set
++# CONFIG_ARCH_ZYNQ is not set
++CONFIG_ARM_TIMER_SP804=y
++
++#
++# Processor Type
++#
++CONFIG_CPU_V7=y
++CONFIG_CPU_32v6K=y
++CONFIG_CPU_32v7=y
++CONFIG_CPU_ABRT_EV7=y
++CONFIG_CPU_PABRT_V7=y
++CONFIG_CPU_CACHE_V7=y
++CONFIG_CPU_CACHE_VIPT=y
++CONFIG_CPU_COPY_V6=y
++CONFIG_CPU_TLB_V7=y
++CONFIG_CPU_HAS_ASID=y
++CONFIG_CPU_CP15=y
++CONFIG_CPU_CP15_MMU=y
++
++#
++# Processor Features
++#
++# CONFIG_ARM_LPAE is not set
++# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
++CONFIG_ARM_THUMB=y
++# CONFIG_ARM_THUMBEE is not set
++CONFIG_ARM_VIRT_EXT=y
++CONFIG_SWP_EMULATE=y
++# CONFIG_CPU_ICACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_DISABLE is not set
++# CONFIG_CPU_BPREDICT_DISABLE is not set
++CONFIG_KUSER_HELPERS=y
++CONFIG_OUTER_CACHE=y
++CONFIG_OUTER_CACHE_SYNC=y
++CONFIG_MIGHT_HAVE_CACHE_L2X0=y
++CONFIG_CACHE_L2X0=y
++CONFIG_CACHE_PL310=y
++# CONFIG_PL310_ERRATA_588369 is not set
++# CONFIG_PL310_ERRATA_727915 is not set
++# CONFIG_PL310_ERRATA_753970 is not set
++# CONFIG_PL310_ERRATA_769419 is not set
++CONFIG_ARM_L1_CACHE_SHIFT_6=y
++CONFIG_ARM_L1_CACHE_SHIFT=6
++CONFIG_ARM_DMA_MEM_BUFFERABLE=y
++CONFIG_MULTI_IRQ_HANDLER=y
++# CONFIG_ARM_ERRATA_430973 is not set
++# CONFIG_ARM_ERRATA_643719 is not set
++# CONFIG_ARM_ERRATA_720789 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_ARM_ERRATA_775420 is not set
++# CONFIG_ARM_ERRATA_798181 is not set
++# CONFIG_ARM_ERRATA_773022 is not set
++
++#
++# Bus support
++#
++CONFIG_ARM_AMBA=y
++# CONFIG_PCI is not set
++# 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_DISABLE_CPU_SCHED_DOMAIN_BALANCE is not set
++CONFIG_HAVE_ARM_SCU=y
++CONFIG_HAVE_ARM_ARCH_TIMER=y
++# CONFIG_MCPM is not set
++# CONFIG_BIG_LITTLE is not set
++CONFIG_VMSPLIT_3G=y
++# CONFIG_VMSPLIT_2G is not set
++# CONFIG_VMSPLIT_1G is not set
++CONFIG_PAGE_OFFSET=0xC0000000
++CONFIG_NR_CPUS=4
++CONFIG_HOTPLUG_CPU=y
++# CONFIG_ARM_PSCI is not set
++CONFIG_ARCH_NR_GPIO=0
++CONFIG_PREEMPT_NONE=y
++# CONFIG_PREEMPT_VOLUNTARY is not set
++# CONFIG_PREEMPT is not set
++CONFIG_HZ_FIXED=0
++CONFIG_HZ_100=y
++# CONFIG_HZ_200 is not set
++# CONFIG_HZ_250 is not set
++# CONFIG_HZ_300 is not set
++# CONFIG_HZ_500 is not set
++# CONFIG_HZ_1000 is not set
++CONFIG_HZ=100
++# CONFIG_SCHED_HRTICK is not set
++# CONFIG_THUMB2_KERNEL is not set
++CONFIG_AEABI=y
++CONFIG_OABI_COMPAT=y
++# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
++# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
++CONFIG_HAVE_ARCH_PFN_VALID=y
++CONFIG_HIGHMEM=y
++# CONFIG_HIGHPTE is not set
++CONFIG_ARCH_WANT_GENERAL_HUGETLB=y
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_HAVE_MEMBLOCK=y
++CONFIG_NO_BOOTMEM=y
++# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=4
++CONFIG_COMPACTION=y
++CONFIG_MIGRATION=y
++# CONFIG_PHYS_ADDR_T_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_BOUNCE=y
++# CONFIG_KSM is not set
++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
++# CONFIG_CLEANCACHE is not set
++# CONFIG_CMA is not set
++# CONFIG_ZPOOL is not set
++# CONFIG_ZBUD is not set
++# CONFIG_ZSMALLOC 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_SWIOTLB=y
++CONFIG_IOMMU_HELPER=y
++# CONFIG_XEN is not set
++# CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART is not set
++
++#
++# Boot options
++#
++CONFIG_USE_OF=y
++CONFIG_ATAGS=y
++# CONFIG_DEPRECATED_PARAM_STRUCT is not set
++# CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE is not set
++CONFIG_ZBOOT_ROM_TEXT=0
++CONFIG_ZBOOT_ROM_BSS=0
++CONFIG_ARM_APPENDED_DTB=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_KEXEC is not set
++# CONFIG_CRASH_DUMP is not set
++CONFIG_AUTO_ZRELADDR=y
++
++#
++# CPU Power Management
++#
++
++#
++# CPU Frequency scaling
++#
++CONFIG_CPU_FREQ=y
++CONFIG_CPU_FREQ_STAT=y
++# CONFIG_CPU_FREQ_STAT_DETAILS is not set
++CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
++# CONFIG_CPU_FREQ_DEFAULT_GOV_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_DEFAULT_GOV_INTERACTIVE is not set
++CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
++# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
++# CONFIG_CPU_FREQ_GOV_USERSPACE is not set
++# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
++# CONFIG_CPU_FREQ_GOV_INTERACTIVE is not set
++# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
++CONFIG_CPUFREQ_DT=y
++
++#
++# ARM CPU frequency scaling drivers
++#
++# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set
++
++#
++# CPU Idle
++#
++# CONFIG_CPU_IDLE is not set
++# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++# CONFIG_FPE_NWFPE is not set
++# CONFIG_FPE_FASTFPE is not set
++CONFIG_VFP=y
++CONFIG_VFPv3=y
++CONFIG_NEON=y
++CONFIG_KERNEL_MODE_NEON=y
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
++CONFIG_BINFMT_SCRIPT=y
++# CONFIG_HAVE_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
++CONFIG_COREDUMP=y
++
++#
++# Power management options
++#
++CONFIG_SUSPEND=y
++CONFIG_SUSPEND_FREEZER=y
++CONFIG_WAKELOCK=y
++# CONFIG_HISI_SNAPSHOT_BOOT is not set
++CONFIG_PM_SLEEP=y
++CONFIG_PM_SLEEP_SMP=y
++# CONFIG_PM_AUTOSLEEP is not set
++# CONFIG_PM_WAKELOCKS is not set
++# CONFIG_PM_RUNTIME is not set
++CONFIG_PM=y
++# CONFIG_PM_DEBUG is not set
++# CONFIG_APM_EMULATION is not set
++CONFIG_PM_OPP=y
++CONFIG_PM_CLK=y
++# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set
++CONFIG_CPU_PM=y
++# CONFIG_SUSPEND_TIME is not set
++CONFIG_ARCH_SUSPEND_POSSIBLE=y
++CONFIG_ARM_CPU_SUSPEND=y
++CONFIG_ARCH_HIBERNATION_POSSIBLE=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=y
++# 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_NET_IP_TUNNEL=m
++# CONFIG_IP_MROUTE is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_NET_UDP_TUNNEL is not set
++# CONFIG_NET_FOU is not set
++# CONFIG_GENEVE 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 is not set
++# CONFIG_INET_XFRM_MODE_TUNNEL is not set
++# CONFIG_INET_XFRM_MODE_BEET is not set
++CONFIG_INET_LRO=y
++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=y
++# 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_VTI 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_ANDROID_PARANOID_NETWORK is not set
++CONFIG_NET_ACTIVITY_STATS=y
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NET_PTP_CLASSIFY 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_NF_TABLES is not set
++# CONFIG_NETFILTER_XTABLES is not set
++# CONFIG_IP_SET is not set
++# CONFIG_IP_VS is not set
++
++#
++# IP: Netfilter Configuration
++#
++# CONFIG_NF_DEFRAG_IPV4 is not set
++# CONFIG_NF_LOG_ARP is not set
++# CONFIG_NF_LOG_IPV4 is not set
++# CONFIG_NF_REJECT_IPV4 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_NF_REJECT_IPV6 is not set
++# CONFIG_NF_LOG_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_HAVE_NET_DSA=y
++# 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_PHONET is not set
++# CONFIG_6LOWPAN 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_VSOCKETS is not set
++# CONFIG_NETLINK_MMAP is not set
++# CONFIG_NETLINK_DIAG is not set
++# CONFIG_NET_MPLS_GSO is not set
++# CONFIG_HSR is not set
++CONFIG_RPS=y
++CONFIG_RFS_ACCEL=y
++CONFIG_XPS=y
++# CONFIG_CGROUP_NET_PRIO is not set
++# CONFIG_CGROUP_NET_CLASSID is not set
++CONFIG_NET_RX_BUSY_POLL=y
++CONFIG_BQL=y
++# CONFIG_BPF_JIT is not set
++CONFIG_NET_FLOW_LIMIT=y
++
++#
++# 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 is not set
++# 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 is not set
++CONFIG_DEVTMPFS=y
++# CONFIG_DEVTMPFS_MOUNT is not set
++CONFIG_STANDALONE=y
++# CONFIG_PREVENT_FIRMWARE_BUILD is not set
++CONFIG_FW_LOADER=y
++CONFIG_FIRMWARE_IN_KERNEL=y
++CONFIG_EXTRA_FIRMWARE=""
++# CONFIG_FW_LOADER_USER_HELPER_FALLBACK is not set
++CONFIG_ALLOW_DEV_COREDUMP=y
++# 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_HAVE_CPU_AUTOPROBE is not set
++CONFIG_REGMAP=y
++CONFIG_REGMAP_MMIO=y
++# CONFIG_DMA_SHARED_BUFFER is not set
++
++#
++# Bus devices
++#
++# CONFIG_BRCMSTB_GISB_ARB is not set
++# CONFIG_ARM_CCI is not set
++# CONFIG_VEXPRESS_CONFIG 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=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_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_HIFMC=y
++CONFIG_HIFMC_SPI_NAND=y
++# CONFIG_HIFMC_NAND is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++# CONFIG_MTD_CFI is not set
++# CONFIG_MTD_JEDECPROBE is not set
++CONFIG_MTD_MAP_BANK_WIDTH_1=y
++CONFIG_MTD_MAP_BANK_WIDTH_2=y
++CONFIG_MTD_MAP_BANK_WIDTH_4=y
++# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
++CONFIG_MTD_CFI_I1=y
++CONFIG_MTD_CFI_I2=y
++# CONFIG_MTD_CFI_I4 is not set
++# CONFIG_MTD_CFI_I8 is not set
++# CONFIG_MTD_RAM is not set
++# CONFIG_MTD_ROM is not set
++# CONFIG_MTD_ABSENT is not set
++
++#
++# Mapping drivers for chip access
++#
++# CONFIG_MTD_COMPLEX_MAPPINGS is not set
++# CONFIG_MTD_PLATRAM is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_DATAFLASH is not set
++# CONFIG_MTD_M25P80 is not set
++# CONFIG_MTD_SST25L is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_PHRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++# CONFIG_MTD_BLOCK2MTD is not set
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOCG3 is not set
++CONFIG_MTD_NAND_IDS=y
++CONFIG_MTD_NAND_ECC=y
++# CONFIG_MTD_NAND_ECC_SMC is not set
++CONFIG_MTD_NAND=y
++# CONFIG_MTD_NAND_ECC_BCH is not set
++# CONFIG_MTD_SM_COMMON is not set
++# CONFIG_MTD_NAND_DENALI is not set
++# CONFIG_MTD_NAND_OMAP_BCH_BUILD is not set
++# CONFIG_MTD_NAND_DISKONCHIP is not set
++# CONFIG_MTD_NAND_DOCG4 is not set
++# CONFIG_MTD_NAND_NANDSIM is not set
++# CONFIG_MTD_NAND_PLATFORM is not set
++# CONFIG_HISI_NAND_FS_MAY_NO_YAFFS2 is not set
++# CONFIG_HISI_NAND_ECC_STATUS_REPORT is not set
++# CONFIG_MTD_NAND_HINFC610 is not set
++# CONFIG_HIFMC100_NAND is not set
++CONFIG_HIFMC100_SPI_NAND=y
++CONFIG_SPI_NAND_MAX_CHIP_NUM=1
++# CONFIG_HIFMC100_HARDWARE_PAGESIZE_ECC is not set
++CONFIG_HIFMC100_AUTO_PAGESIZE_ECC=y
++# CONFIG_HIFMC100_PAGESIZE_AUTO_ECC_NONE is not set
++# CONFIG_MTD_ONENAND is not set
++
++#
++# LPDDR & LPDDR2 PCM memory drivers
++#
++# CONFIG_MTD_LPDDR is not set
++# CONFIG_MTD_LPDDR2_NVM is not set
++CONFIG_MTD_SPI_NOR=y
++# CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set
++CONFIG_SPI_HISI_SFC=y
++# CONFIG_CLOSE_SPI_8PIN_4IO is not set
++CONFIG_HISI_SPI_BLOCK_PROTECT=y
++# CONFIG_MTD_UBI is not set
++CONFIG_DTC=y
++CONFIG_OF=y
++
++#
++# Device Tree and Open Firmware support
++#
++# 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_NET=y
++CONFIG_OF_MDIO=y
++CONFIG_OF_MTD=y
++CONFIG_OF_RESERVED_MEM=y
++CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
++# CONFIG_PARPORT is not set
++CONFIG_BLK_DEV=y
++# CONFIG_BLK_DEV_NULL_BLK is not set
++# CONFIG_BLK_DEV_COW_COMMON is not set
++# CONFIG_BLK_DEV_LOOP 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=65536
++# CONFIG_BLK_DEV_XIP is not set
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH 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_DUMMY_IRQ 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_UID_STAT is not set
++# CONFIG_BMP085_I2C is not set
++# CONFIG_BMP085_SPI is not set
++# CONFIG_USB_SWITCH_FSA9480 is not set
++# CONFIG_LATTICE_ECP3_CONFIG is not set
++# CONFIG_SRAM is not set
++# CONFIG_C2PORT is not set
++
++#
++# EEPROM support
++#
++# CONFIG_EEPROM_AT24 is not set
++# CONFIG_EEPROM_AT25 is not set
++# CONFIG_EEPROM_LEGACY is not set
++# CONFIG_EEPROM_MAX6875 is not set
++# CONFIG_EEPROM_93CX6 is not set
++# CONFIG_EEPROM_93XX46 is not set
++
++#
++# Texas Instruments shared transport line discipline
++#
++# 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
++
++#
++# Intel MIC Bus Driver
++#
++
++#
++# Intel MIC Host Driver
++#
++
++#
++# Intel MIC Card Driver
++#
++# CONFIG_ECHO is not set
++# CONFIG_CXL_BASE is not set
++
++#
++# hisi 'himm/himd.l/himc'support
++#
++# CONFIG_HISI_REG 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_NETLINK is not set
++# CONFIG_SCSI_MQ_DEFAULT is not set
++CONFIG_SCSI_PROC_FS=y
++
++#
++# SCSI support type (disk, tape, CD-ROM)
++#
++CONFIG_BLK_DEV_SD=y
++# CONFIG_CHR_DEV_ST is not set
++# CONFIG_CHR_DEV_OSST is not set
++CONFIG_BLK_DEV_SR=y
++# CONFIG_BLK_DEV_SR_VENDOR is not set
++# CONFIG_CHR_DEV_SG is not set
++# CONFIG_CHR_DEV_SCH is not set
++# CONFIG_SCSI_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 is not set
++# CONFIG_SCSI_DH is not set
++# CONFIG_SCSI_OSD_INITIATOR is not set
++CONFIG_HI_SATA=y
++CONFIG_HI_SATA_IOBASE=0x11010000
++CONFIG_HI_SATA_FBS=1
++CONFIG_HI_SATA_NCQ=1
++CONFIG_ATA=y
++# CONFIG_ATA_NONSTANDARD is not set
++CONFIG_ATA_VERBOSE_ERROR=y
++CONFIG_SATA_PMP=y
++
++#
++# Controllers with non-SFF native interface
++#
++CONFIG_SATA_AHCI_PLATFORM=y
++# CONFIG_ATA_SFF is not set
++# CONFIG_MD 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_NET_TEAM is not set
++# CONFIG_MACVLAN is not set
++# CONFIG_VXLAN is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_TUN is not set
++# CONFIG_VETH is not set
++# CONFIG_NLMON is not set
++
++#
++# 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_NET_DSA_MV88E6171 is not set
++# CONFIG_NET_DSA_BCM_SF2 is not set
++CONFIG_ETHERNET=y
++# CONFIG_ALTERA_TSE is not set
++# CONFIG_NET_XGENE is not set
++# CONFIG_NET_VENDOR_ARC is not set
++# CONFIG_NET_CADENCE is not set
++# CONFIG_NET_VENDOR_BROADCOM is not set
++# CONFIG_NET_VENDOR_CIRRUS is not set
++# CONFIG_DM9000 is not set
++# CONFIG_DNET is not set
++# CONFIG_NET_VENDOR_FARADAY is not set
++CONFIG_NET_VENDOR_HISILICON=y
++# CONFIG_HIX5HD2_GMAC is not set
++# CONFIG_HISI_FEMAC is not set
++CONFIG_HIETH_GMAC=y
++CONFIG_HIGMAC_DESC_4WORD=y
++CONFIG_HIGMAC_RXCSUM=y
++CONFIG_RX_FLOW_CTRL_SUPPORT=y
++CONFIG_TX_FLOW_CTRL_SUPPORT=y
++CONFIG_TX_FLOW_CTRL_PAUSE_TIME=0xFFFF
++CONFIG_TX_FLOW_CTRL_PAUSE_INTERVAL=0xFFFF
++CONFIG_TX_FLOW_CTRL_ACTIVE_THRESHOLD=16
++CONFIG_TX_FLOW_CTRL_DEACTIVE_THRESHOLD=32
++# CONFIG_HIETH_SWITCH_FABRIC is not set
++# CONFIG_NET_VENDOR_INTEL is not set
++# CONFIG_NET_VENDOR_MARVELL is not set
++# CONFIG_NET_VENDOR_MICREL is not set
++# CONFIG_NET_VENDOR_MICROCHIP is not set
++# CONFIG_NET_VENDOR_NATSEMI is not set
++# CONFIG_ETHOC is not set
++# CONFIG_NET_VENDOR_QUALCOMM is not set
++# CONFIG_NET_VENDOR_SAMSUNG is not set
++# CONFIG_NET_VENDOR_SEEQ is not set
++# CONFIG_NET_VENDOR_SMSC is not set
++# CONFIG_NET_VENDOR_STMICRO is not set
++# CONFIG_NET_VENDOR_VIA is not set
++# CONFIG_NET_VENDOR_WIZNET is not set
++CONFIG_PHYLIB=y
++
++#
++# MII PHY device drivers
++#
++# CONFIG_AT803X_PHY is not set
++# CONFIG_AMD_PHY is not set
++# CONFIG_AMD_XGBE_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 is not set
++# CONFIG_BROADCOM_PHY is not set
++# CONFIG_BCM7XXX_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_MMIOREG is not set
++# CONFIG_MDIO_BCM_UNIMAC is not set
++# CONFIG_MDIO_HISI_FEMAC is not set
++CONFIG_MDIO_HISI_GEMAC=y
++# CONFIG_MICREL_KS8995MA is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++CONFIG_USB_NET_DRIVERS=y
++# 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_RTL8152 is not set
++# CONFIG_USB_USBNET is not set
++# CONFIG_USB_IPHETH is not set
++# CONFIG_WLAN is not set
++
++#
++# Enable WiMAX (Networking options) to see the WiMAX drivers
++#
++# CONFIG_WAN is not set
++# CONFIG_ISDN is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
++# CONFIG_INPUT_POLLDEV is not set
++# CONFIG_INPUT_SPARSEKMAP is not set
++# CONFIG_INPUT_MATRIXKMAP is not set
++
++#
++# Userland interfaces
++#
++CONFIG_INPUT_MOUSEDEV=y
++CONFIG_INPUT_MOUSEDEV_PSAUX=y
++CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
++CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
++CONFIG_INPUT_JOYDEV=y
++CONFIG_INPUT_EVDEV=y
++# CONFIG_INPUT_EVBUG is not set
++# CONFIG_INPUT_KEYRESET is not set
++# CONFIG_INPUT_KEYCOMBO 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_TCA6416 is not set
++# CONFIG_KEYBOARD_TCA8418 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 is not set
++# CONFIG_KEYBOARD_CAP1106 is not set
++CONFIG_INPUT_MOUSE=y
++CONFIG_MOUSE_PS2=y
++CONFIG_MOUSE_PS2_ALPS=y
++CONFIG_MOUSE_PS2_LOGIPS2PP=y
++CONFIG_MOUSE_PS2_SYNAPTICS=y
++CONFIG_MOUSE_PS2_CYPRESS=y
++CONFIG_MOUSE_PS2_TRACKPOINT=y
++# CONFIG_MOUSE_PS2_ELANTECH is not set
++# CONFIG_MOUSE_PS2_SENTELIC is not set
++# CONFIG_MOUSE_PS2_TOUCHKIT is not set
++# CONFIG_MOUSE_SERIAL is not set
++# CONFIG_MOUSE_APPLETOUCH is not set
++# CONFIG_MOUSE_BCM5974 is not set
++# CONFIG_MOUSE_CYAPA is not set
++# CONFIG_MOUSE_VSXXXAA is not set
++# CONFIG_MOUSE_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 is not set
++# CONFIG_INPUT_MISC is not set
++
++#
++# Hardware I/O ports
++#
++CONFIG_SERIO=y
++CONFIG_SERIO_SERPORT=y
++# CONFIG_SERIO_AMBAKMI is not set
++CONFIG_SERIO_LIBPS2=y
++# CONFIG_SERIO_RAW is not set
++# CONFIG_SERIO_ALTERA_PS2 is not set
++# CONFIG_SERIO_PS2MULT is not set
++# CONFIG_SERIO_ARC_PS2 is not set
++# CONFIG_SERIO_APBPS2 is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++CONFIG_TTY=y
++CONFIG_VT=y
++CONFIG_CONSOLE_TRANSLATIONS=y
++CONFIG_VT_CONSOLE=y
++CONFIG_VT_CONSOLE_SLEEP=y
++CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
++CONFIG_UNIX98_PTYS=y
++# CONFIG_DEVPTS_MULTIPLE_INSTANCES 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_DEVMEM=y
++CONFIG_DEVKMEM=y
++
++#
++# Serial drivers
++#
++CONFIG_SERIAL_EARLYCON=y
++# CONFIG_SERIAL_8250 is not set
++
++#
++# Non-8250 serial port support
++#
++# CONFIG_SERIAL_AMBA_PL010 is not set
++CONFIG_SERIAL_AMBA_PL011=y
++CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
++# CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST is not set
++# 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_SC16IS7XX is not set
++# CONFIG_SERIAL_ALTERA_JTAGUART is not set
++# CONFIG_SERIAL_ALTERA_UART is not set
++# CONFIG_SERIAL_XILINX_PS_UART is not set
++# CONFIG_SERIAL_ARC is not set
++# CONFIG_SERIAL_FSL_LPUART is not set
++# CONFIG_SERIAL_ST_ASC is not set
++# CONFIG_HVC_DCC is not set
++# CONFIG_IPMI_HANDLER is not set
++# CONFIG_HW_RANDOM is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++# CONFIG_DCC_TTY is not set
++# CONFIG_XILLYBUS is not set
++
++#
++# I2C support
++#
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++CONFIG_I2C_COMPAT=y
++CONFIG_I2C_CHARDEV=y
++CONFIG_I2C_MUX=y
++
++#
++# Multiplexer I2C Chip support
++#
++# CONFIG_I2C_MUX_PCA9541 is not set
++# CONFIG_I2C_MUX_PINCTRL is not set
++CONFIG_I2C_HELPER_AUTO=y
++
++#
++# I2C Hardware Bus support
++#
++
++#
++# I2C system bus drivers (mostly embedded / system-on-chip)
++#
++# CONFIG_I2C_DESIGNWARE_PLATFORM is not set
++# CONFIG_I2C_HIBVT is not set
++# CONFIG_I2C_HISI_V110 is not set
++# CONFIG_I2C_NOMADIK 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_RK3X 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_ROBOTFUZZ_OSIF is not set
++# CONFIG_I2C_TAOS_EVM is not set
++# CONFIG_I2C_TINY_USB is not set
++
++#
++# Other I2C/SMBus bus drivers
++#
++CONFIG_HI_I2C=y
++CONFIG_HI_I2C0_IO_BASE=0x120c0000
++CONFIG_HI_I2C0_IO_SIZE=0x1000
++CONFIG_HI_I2C1_IO_BASE=0x122e0000
++CONFIG_HI_I2C1_IO_SIZE=0x1000
++CONFIG_HI_I2C_RETRIES=0x1
++CONFIG_HI_I2C_TX_FIFO=0x8
++CONFIG_HI_I2C_RX_FIFO=0x8
++CONFIG_HI_I2C0_CLK_LIMIT=100000
++CONFIG_HI_I2C1_CLK_LIMIT=100000
++# 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_CADENCE is not set
++# CONFIG_SPI_FSL_SPI is not set
++CONFIG_SPI_PL022=y
++# CONFIG_SPI_PXA2XX_PCI is not set
++# CONFIG_SPI_ROCKCHIP 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=y
++# CONFIG_SPI_TLE62X0 is not set
++# CONFIG_SPMI is not set
++# CONFIG_HSI is not set
++
++#
++# PPS support
++#
++# CONFIG_PPS is not set
++
++#
++# PPS generators support
++#
++
++#
++# PTP clock support
++#
++# CONFIG_PTP_1588_CLOCK is not set
++
++#
++# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
++#
++CONFIG_PINCTRL=y
++
++#
++# Pin controllers
++#
++CONFIG_PINMUX=y
++CONFIG_PINCONF=y
++CONFIG_GENERIC_PINCONF=y
++# CONFIG_DEBUG_PINCTRL is not set
++CONFIG_PINCTRL_SINGLE=y
++CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
++CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
++# CONFIG_GPIOLIB is not set
++# CONFIG_W1 is not set
++CONFIG_POWER_SUPPLY=y
++# CONFIG_POWER_SUPPLY_DEBUG is not set
++# CONFIG_PDA_POWER is not set
++# CONFIG_TEST_POWER is not set
++# CONFIG_BATTERY_DS2780 is not set
++# CONFIG_BATTERY_DS2781 is not set
++# CONFIG_BATTERY_DS2782 is not set
++# CONFIG_BATTERY_SBS is not set
++# CONFIG_BATTERY_BQ27x00 is not set
++# CONFIG_BATTERY_MAX17040 is not set
++# CONFIG_BATTERY_MAX17042 is not set
++# CONFIG_CHARGER_MAX8903 is not set
++# CONFIG_CHARGER_LP8727 is not set
++# CONFIG_CHARGER_BQ2415X is not set
++# CONFIG_CHARGER_SMB347 is not set
++CONFIG_POWER_RESET=y
++# CONFIG_POWER_RESET_BRCMSTB is not set
++CONFIG_POWER_RESET_HISI=y
++# CONFIG_POWER_RESET_RESTART is not set
++# CONFIG_POWER_RESET_VERSATILE is not set
++# CONFIG_POWER_RESET_SYSCON is not set
++# CONFIG_POWER_AVS is not set
++# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
++# CONFIG_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=y
++# CONFIG_MFD_AS3711 is not set
++# CONFIG_MFD_AS3722 is not set
++# CONFIG_PMIC_ADP5520 is not set
++# CONFIG_MFD_BCM590XX is not set
++# CONFIG_MFD_AXP20X is not set
++# CONFIG_MFD_CROS_EC is not set
++# CONFIG_PMIC_DA903X is not set
++# CONFIG_MFD_DA9052_SPI is not set
++# CONFIG_MFD_DA9052_I2C is not set
++# CONFIG_MFD_DA9055 is not set
++# CONFIG_MFD_DA9063 is not set
++# CONFIG_MFD_MC13XXX_SPI is not set
++# CONFIG_MFD_MC13XXX_I2C is not set
++# CONFIG_MFD_HI6421_PMIC is not set
++CONFIG_MFD_HISI_FMC=y
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_INTEL_SOC_PMIC is not set
++# CONFIG_MFD_KEMPLD is not set
++# CONFIG_MFD_88PM800 is not set
++# CONFIG_MFD_88PM805 is not set
++# CONFIG_MFD_88PM860X is not set
++# CONFIG_MFD_MAX14577 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_MENF21BMC is not set
++# CONFIG_EZX_PCAP is not set
++# CONFIG_MFD_VIPERBOARD is not set
++# CONFIG_MFD_RETU is not set
++# CONFIG_MFD_PCF50633 is not set
++# CONFIG_MFD_PM8921_CORE is not set
++# CONFIG_MFD_RTSX_USB is not set
++# CONFIG_MFD_RC5T583 is not set
++# CONFIG_MFD_RK808 is not set
++# CONFIG_MFD_RN5T618 is not set
++# CONFIG_MFD_SEC_CORE is not set
++# CONFIG_MFD_SI476X_CORE is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_MFD_SMSC is not set
++# CONFIG_ABX500_CORE is not set
++# CONFIG_MFD_STMPE is not set
++CONFIG_MFD_SYSCON=y
++# CONFIG_MFD_TI_AM335X_TSCADC is not set
++# CONFIG_MFD_LP3943 is not set
++# CONFIG_MFD_LP8788 is not set
++# CONFIG_MFD_PALMAS is not set
++# CONFIG_TPS6105X is not set
++# CONFIG_TPS6507X is not set
++# CONFIG_MFD_TPS65090 is not set
++# CONFIG_MFD_TPS65217 is not set
++# CONFIG_MFD_TPS65218 is not set
++# CONFIG_MFD_TPS6586X is not set
++# CONFIG_MFD_TPS80031 is not set
++# CONFIG_TWL4030_CORE is not set
++# CONFIG_TWL6040_CORE is not set
++# CONFIG_MFD_WL1273_CORE is not set
++# CONFIG_MFD_LM3533 is not set
++# CONFIG_MFD_TC3589X is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_MFD_T7L66XB is not set
++# CONFIG_MFD_TC6387XB is not set
++# CONFIG_MFD_TC6393XB is not set
++# CONFIG_MFD_ARIZONA_I2C is not set
++# CONFIG_MFD_ARIZONA_SPI is not set
++# CONFIG_MFD_WM8400 is not set
++# CONFIG_MFD_WM831X_I2C is not set
++# CONFIG_MFD_WM831X_SPI is not set
++# CONFIG_MFD_WM8350_I2C is not set
++# CONFIG_MFD_WM8994 is not set
++CONFIG_REGULATOR=y
++# CONFIG_REGULATOR_DEBUG is not set
++# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
++# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
++# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
++# CONFIG_REGULATOR_ACT8865 is not set
++# CONFIG_REGULATOR_AD5398 is not set
++# CONFIG_REGULATOR_ANATOP is not set
++# CONFIG_REGULATOR_DA9210 is not set
++# CONFIG_REGULATOR_DA9211 is not set
++# CONFIG_REGULATOR_FAN53555 is not set
++# CONFIG_REGULATOR_ISL9305 is not set
++# CONFIG_REGULATOR_ISL6271A is not set
++# CONFIG_REGULATOR_LP3971 is not set
++# CONFIG_REGULATOR_LP3972 is not set
++# CONFIG_REGULATOR_LP872X is not set
++# CONFIG_REGULATOR_LP8755 is not set
++# CONFIG_REGULATOR_LTC3589 is not set
++# CONFIG_REGULATOR_MAX1586 is not set
++# CONFIG_REGULATOR_MAX8649 is not set
++# CONFIG_REGULATOR_MAX8660 is not set
++# CONFIG_REGULATOR_MAX8952 is not set
++# CONFIG_REGULATOR_MAX8973 is not set
++# CONFIG_REGULATOR_PFUZE100 is not set
++# CONFIG_REGULATOR_TPS51632 is not set
++# CONFIG_REGULATOR_TPS62360 is not set
++# CONFIG_REGULATOR_TPS65023 is not set
++# CONFIG_REGULATOR_TPS6507X is not set
++# CONFIG_REGULATOR_TPS6524X is not set
++# CONFIG_MEDIA_SUPPORT is not set
++
++#
++# Graphics support
++#
++# CONFIG_IMX_IPUV3_CORE is not set
++
++#
++# Direct Rendering Manager
++#
++# CONFIG_DRM is not set
++
++#
++# Frame buffer Devices
++#
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++CONFIG_FB_CMDLINE=y
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++# CONFIG_FB_CFB_FILLRECT is not set
++# CONFIG_FB_CFB_COPYAREA is not set
++# CONFIG_FB_CFB_IMAGEBLIT is not set
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# 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_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_ARMCLCD is not set
++# CONFIG_FB_OPENCORES is not set
++# CONFIG_FB_S1D13XXX is not set
++# CONFIG_FB_SMSCUFX is not set
++# CONFIG_FB_UDL is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_BROADSHEET is not set
++# CONFIG_FB_AUO_K190X is not set
++# CONFIG_FB_SIMPLE is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++# CONFIG_VGASTATE is not set
++
++#
++# Console display driver support
++#
++CONFIG_DUMMY_CONSOLE=y
++# CONFIG_FRAMEBUFFER_CONSOLE is not set
++# CONFIG_LOGO is not set
++# CONFIG_SOUND is not set
++
++#
++# HID support
++#
++CONFIG_HID=y
++# CONFIG_HID_BATTERY_STRENGTH is not set
++# CONFIG_HIDRAW is not set
++# CONFIG_UHID is not set
++CONFIG_HID_GENERIC=y
++
++#
++# Special HID drivers
++#
++CONFIG_HID_A4TECH=y
++# CONFIG_HID_ACRUX is not set
++CONFIG_HID_APPLE=y
++# CONFIG_HID_APPLEIR is not set
++# CONFIG_HID_AUREAL is not set
++CONFIG_HID_BELKIN=y
++CONFIG_HID_CHERRY=y
++CONFIG_HID_CHICONY=y
++CONFIG_HID_CYPRESS=y
++# CONFIG_HID_DRAGONRISE is not set
++# CONFIG_HID_EMS_FF is not set
++# CONFIG_HID_ELECOM is not set
++# CONFIG_HID_ELO is not set
++CONFIG_HID_EZKEY=y
++# CONFIG_HID_HOLTEK is not set
++# CONFIG_HID_HUION 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_ICADE is not set
++# CONFIG_HID_TWINHAN is not set
++CONFIG_HID_KENSINGTON=y
++# CONFIG_HID_LCPOWER is not set
++# CONFIG_HID_LENOVO is not set
++CONFIG_HID_LOGITECH=y
++# CONFIG_HID_LOGITECH_HIDPP is not set
++# CONFIG_LOGITECH_FF is not set
++# CONFIG_LOGIRUMBLEPAD2_FF is not set
++# CONFIG_LOGIG940_FF is not set
++# CONFIG_LOGIWHEELS_FF is not set
++# CONFIG_HID_MAGICMOUSE is not set
++CONFIG_HID_MICROSOFT=y
++CONFIG_HID_MONTEREY=y
++# 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_PENMOUNT is not set
++# CONFIG_HID_PETALYNX is not set
++# CONFIG_HID_PICOLCD is not set
++# CONFIG_HID_PRIMAX is not set
++# CONFIG_HID_ROCCAT is not set
++# CONFIG_HID_SAITEK is not set
++# CONFIG_HID_SAMSUNG is not set
++# CONFIG_HID_SPEEDLINK is not set
++# CONFIG_HID_STEELSERIES is not set
++# CONFIG_HID_SUNPLUS is not set
++# CONFIG_HID_RMI 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_XINMO is not set
++# CONFIG_HID_ZEROPLUS is not set
++# CONFIG_HID_ZYDACRON is not set
++# CONFIG_HID_SENSOR_HUB is not set
++
++#
++# USB HID support
++#
++CONFIG_USB_HID=y
++# CONFIG_HID_PID is not set
++# CONFIG_USB_HIDDEV is not set
++
++#
++# I2C HID support
++#
++# CONFIG_I2C_HID is not set
++CONFIG_USB_OHCI_LITTLE_ENDIAN=y
++CONFIG_USB_SUPPORT=y
++CONFIG_USB_COMMON=y
++CONFIG_USB_ARCH_HAS_HCD=y
++CONFIG_USB=y
++# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
++
++#
++# Miscellaneous USB options
++#
++CONFIG_USB_DEFAULT_PERSIST=y
++# CONFIG_USB_DYNAMIC_MINORS is not set
++# CONFIG_USB_OTG_WHITELIST is not set
++# CONFIG_USB_OTG_FSM is not set
++# CONFIG_USB_MON is not set
++# CONFIG_USB_WUSB_CBAF is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_C67X00_HCD is not set
++CONFIG_USB_XHCI_HCD=y
++CONFIG_USB_XHCI_PLATFORM=y
++CONFIG_USB_XHCI_HISILICON=y
++CONFIG_USB_EHCI_HCD=y
++# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
++CONFIG_USB_EHCI_TT_NEWSCHED=y
++CONFIG_USB_EHCI_HCD_PLATFORM=y
++# 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_FUSBH200_HCD is not set
++# CONFIG_USB_FOTG210_HCD is not set
++# CONFIG_USB_MAX3421_HCD is not set
++CONFIG_USB_OHCI_HCD=y
++CONFIG_USB_OHCI_HCD_PLATFORM=y
++# CONFIG_USB_SL811_HCD is not set
++# CONFIG_USB_R8A66597_HCD is not set
++# CONFIG_USB_HCD_TEST_MODE is not set
++
++#
++# USB Device Class drivers
++#
++# CONFIG_USB_ACM is not set
++# CONFIG_USB_PRINTER is not set
++# CONFIG_USB_WDM is not set
++# CONFIG_USB_TMC is not set
++
++#
++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
++#
++
++#
++# also be needed; see USB_STORAGE Help for more info
++#
++CONFIG_USB_STORAGE=y
++# CONFIG_USB_STORAGE_DEBUG is not set
++# CONFIG_USB_STORAGE_REALTEK is not set
++# CONFIG_USB_STORAGE_DATAFAB is not set
++# CONFIG_USB_STORAGE_FREECOM is not set
++# CONFIG_USB_STORAGE_ISD200 is not set
++# CONFIG_USB_STORAGE_USBAT is not set
++# CONFIG_USB_STORAGE_SDDR09 is not set
++# CONFIG_USB_STORAGE_SDDR55 is not set
++# CONFIG_USB_STORAGE_JUMPSHOT is not set
++# CONFIG_USB_STORAGE_ALAUDA is not set
++# CONFIG_USB_STORAGE_ONETOUCH is not set
++# CONFIG_USB_STORAGE_KARMA is not set
++# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
++# CONFIG_USB_STORAGE_ENE_UB6250 is not set
++# CONFIG_USB_UAS is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++# CONFIG_USBIP_CORE is not set
++# CONFIG_USB_MUSB_HDRC is not set
++# CONFIG_USB_DWC3 is not set
++# CONFIG_USB_DWC2 is not set
++# CONFIG_USB_CHIPIDEA is not set
++
++#
++# USB port drivers
++#
++# CONFIG_USB_SERIAL is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
++# CONFIG_USB_SEVSEG is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
++# CONFIG_USB_APPLEDISPLAY is not set
++# CONFIG_USB_SISUSBVGA is not set
++# CONFIG_USB_LD is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
++# CONFIG_USB_IOWARRIOR is not set
++# CONFIG_USB_TEST is not set
++# CONFIG_USB_EHSET_TEST_FIXTURE is not set
++# CONFIG_USB_ISIGHTFW is not set
++# CONFIG_USB_YUREX is not set
++# CONFIG_USB_EZUSB_FX2 is not set
++# CONFIG_USB_HSIC_USB3503 is not set
++# CONFIG_USB_LINK_LAYER_TEST is not set
++
++#
++# USB Physical Layer drivers
++#
++# CONFIG_USB_PHY is not set
++# CONFIG_USB_OTG_WAKELOCK is not set
++# CONFIG_NOP_USB_XCEIV is not set
++# CONFIG_AM335X_PHY_USB is not set
++# CONFIG_USB_ISP1301 is not set
++# CONFIG_USB_ULPI is not set
++# CONFIG_USB_GADGET is not set
++# CONFIG_UWB is not set
++# CONFIG_MMC is not set
++# CONFIG_MEMSTICK is not set
++# CONFIG_NEW_LEDS is not set
++# CONFIG_SWITCH is not set
++# CONFIG_ACCESSIBILITY is not set
++# CONFIG_EDAC is not set
++CONFIG_RTC_LIB=y
++# CONFIG_RTC_CLASS is not set
++# CONFIG_DMADEVICES is not set
++# CONFIG_AUXDISPLAY is not set
++# CONFIG_UIO is not set
++# CONFIG_VIRT_DRIVERS is not set
++
++#
++# Virtio drivers
++#
++# CONFIG_VIRTIO_MMIO is not set
++
++#
++# Microsoft Hyper-V guest support
++#
++# CONFIG_STAGING is not set
++
++#
++# SOC (System On Chip) specific Drivers
++#
++# CONFIG_SOC_TI is not set
++CONFIG_CLKDEV_LOOKUP=y
++CONFIG_HAVE_CLK_PREPARE=y
++CONFIG_COMMON_CLK=y
++
++#
++# Common Clock Framework
++#
++# CONFIG_COMMON_CLK_SI5351 is not set
++# CONFIG_COMMON_CLK_SI570 is not set
++# CONFIG_COMMON_CLK_PXA is not set
++# CONFIG_COMMON_CLK_QCOM is not set
++
++#
++# Hardware Spinlock drivers
++#
++
++#
++# Clock Source drivers
++#
++CONFIG_CLKSRC_OF=y
++CONFIG_CLKSRC_MMIO=y
++CONFIG_ARM_ARCH_TIMER=y
++CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y
++# CONFIG_ARM_ARCH_TIMER_VCT_ACCESS is not set
++# CONFIG_ATMEL_PIT is not set
++# CONFIG_SH_TIMER_CMT is not set
++# CONFIG_SH_TIMER_MTU2 is not set
++# CONFIG_SH_TIMER_TMU is not set
++# CONFIG_EM_TIMER_STI is not set
++# CONFIG_CLKSRC_VERSATILE is not set
++# CONFIG_MAILBOX is not set
++# CONFIG_IOMMU_SUPPORT is not set
++
++#
++# Remoteproc drivers
++#
++# CONFIG_STE_MODEM_RPROC is not set
++
++#
++# Rpmsg drivers
++#
++
++#
++# SOC (System On Chip) specific Drivers
++#
++# 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
++CONFIG_IRQCHIP=y
++CONFIG_ARM_GIC=y
++# CONFIG_IPACK_BUS is not set
++CONFIG_ARCH_HAS_RESET_CONTROLLER=y
++CONFIG_RESET_CONTROLLER=y
++# CONFIG_FMC is not set
++
++#
++# PHY Subsystem
++#
++CONFIG_GENERIC_PHY=y
++# CONFIG_BCM_KONA_USB2_PHY is not set
++# CONFIG_PHY_HISI_INNO_USB2 is not set
++CONFIG_PHY_HI35x1D_INNO_USB2=y
++CONFIG_PHY_HI3531D_USB3=y
++CONFIG_HI_NANO_PHY_SATA=y
++CONFIG_HI_SATA_PORTS=4
++CONFIG_HI_SATA_MODE=1
++# CONFIG_POWERCAP is not set
++# CONFIG_MCB is not set
++CONFIG_HI_DMAC=y
++CONFIG_HI_DMAC_CHANNEL_NUM=4
++
++#
++# Hisilicon driver support
++#
++
++#
++# File systems
++#
++CONFIG_DCACHE_WORD_ACCESS=y
++# CONFIG_EXT2_FS is not set
++# CONFIG_EXT3_FS is not set
++CONFIG_EXT4_FS=y
++CONFIG_EXT4_USE_FOR_EXT23=y
++# CONFIG_EXT4_FS_POSIX_ACL is not set
++# CONFIG_EXT4_FS_SECURITY is not set
++# CONFIG_EXT4_DEBUG is not set
++CONFIG_JBD2=y
++# CONFIG_JBD2_DEBUG is not set
++CONFIG_FS_MBCACHE=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_BTRFS_FS is not set
++# CONFIG_NILFS2_FS is not set
++CONFIG_FS_POSIX_ACL=y
++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 is not set
++# CONFIG_FUSE_FS is not set
++# CONFIG_OVERLAY_FS is not set
++
++#
++# Caches
++#
++# CONFIG_FSCACHE is not set
++
++#
++# CD-ROM/DVD Filesystems
++#
++CONFIG_ISO9660_FS=y
++# CONFIG_JOLIET is not set
++# CONFIG_ZISOFS is not set
++CONFIG_UDF_FS=y
++CONFIG_UDF_NLS=y
++
++#
++# DOS/FAT/NT Filesystems
++#
++CONFIG_FAT_FS=y
++CONFIG_MSDOS_FS=y
++CONFIG_VFAT_FS=y
++CONFIG_FAT_DEFAULT_CODEPAGE=437
++CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
++# CONFIG_NTFS_FS is not set
++
++#
++# Pseudo filesystems
++#
++CONFIG_PROC_FS=y
++CONFIG_PROC_SYSCTL=y
++CONFIG_PROC_PAGE_MONITOR=y
++CONFIG_KERNFS=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=m
++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_YAFFS_FS=y
++CONFIG_YAFFS_YAFFS1=y
++# CONFIG_YAFFS_9BYTE_TAGS is not set
++# CONFIG_YAFFS_DOES_ECC is not set
++CONFIG_YAFFS_YAFFS2=y
++CONFIG_YAFFS_AUTO_YAFFS2=y
++# CONFIG_YAFFS_DISABLE_TAGS_ECC is not set
++# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
++# CONFIG_YAFFS_EMPTY_LOST_AND_FOUND is not set
++# CONFIG_YAFFS_DISABLE_BLOCK_REFRESHING is not set
++# CONFIG_YAFFS_DISABLE_BACKGROUND is not set
++# CONFIG_YAFFS_DISABLE_BAD_BLOCK_MARKING is not set
++CONFIG_YAFFS_XATTR=y
++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 is not set
++# CONFIG_JFFS2_FS_XATTR is not set
++# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
++CONFIG_JFFS2_ZLIB=y
++# CONFIG_JFFS2_LZO is not set
++CONFIG_JFFS2_RTIME=y
++# CONFIG_JFFS2_RUBIN 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 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 is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V2=y
++CONFIG_NFS_V3=y
++CONFIG_NFS_V3_ACL=y
++# CONFIG_NFS_V4 is not set
++# CONFIG_NFS_SWAP is not set
++# CONFIG_ROOT_NFS is not set
++# CONFIG_NFSD is not set
++CONFIG_GRACE_PERIOD=y
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_ACL_SUPPORT=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 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=y
++# CONFIG_DLM is not set
++
++#
++# Kernel hacking
++#
++
++#
++# printk and dmesg options
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4
++# CONFIG_BOOT_PRINTK_DELAY is not set
++
++#
++# Compile-time checks and compiler options
++#
++# CONFIG_DEBUG_INFO is not set
++# CONFIG_ENABLE_WARN_DEPRECATED is not set
++# CONFIG_ENABLE_MUST_CHECK is not set
++CONFIG_FRAME_WARN=1024
++# CONFIG_STRIP_ASM_SYMS is not set
++# CONFIG_READABLE_ASM is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++# CONFIG_DEBUG_FS is not set
++# CONFIG_HEADERS_CHECK is not set
++# CONFIG_DEBUG_SECTION_MISMATCH is not set
++# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
++# CONFIG_MAGIC_SYSRQ is not set
++CONFIG_DEBUG_KERNEL=y
++
++#
++# Memory Debugging
++#
++# CONFIG_DEBUG_PAGEALLOC is not set
++# 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_STACK_USAGE is not set
++# CONFIG_DEBUG_VM is not set
++CONFIG_DEBUG_MEMORY_INIT=y
++# CONFIG_DEBUG_PER_CPU_MAPS is not set
++# CONFIG_DEBUG_HIGHMEM is not set
++# CONFIG_DEBUG_SHIRQ is not set
++
++#
++# Debug Lockups and Hangs
++#
++# CONFIG_LOCKUP_DETECTOR is not set
++# CONFIG_DETECT_HUNG_TASK is not set
++# CONFIG_PANIC_ON_OOPS is not set
++CONFIG_PANIC_ON_OOPS_VALUE=0
++CONFIG_PANIC_TIMEOUT=0
++CONFIG_SCHED_DEBUG=y
++# CONFIG_SCHEDSTATS is not set
++# CONFIG_SCHED_STACK_END_CHECK is not set
++# CONFIG_TIMER_STATS is not set
++
++#
++# Lock Debugging (spinlocks, mutexes, etc...)
++#
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_LOCK_STAT is not set
++# CONFIG_DEBUG_ATOMIC_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_LOCK_TORTURE_TEST is not set
++CONFIG_STACKTRACE=y
++# CONFIG_DEBUG_KOBJECT is not set
++CONFIG_DEBUG_BUGVERBOSE=y
++# CONFIG_DEBUG_LIST is not set
++# CONFIG_DEBUG_PI_LIST is not set
++# CONFIG_DEBUG_SG is not set
++# CONFIG_DEBUG_NOTIFIERS is not set
++# CONFIG_DEBUG_CREDENTIALS is not set
++
++#
++# RCU Debugging
++#
++# CONFIG_SPARSE_RCU_POINTER is not set
++# CONFIG_TORTURE_TEST 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_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_NOTIFIER_ERROR_INJECTION is not set
++# CONFIG_FAULT_INJECTION 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 is not set
++
++#
++# Runtime Testing
++#
++# CONFIG_TEST_LIST_SORT is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_RBTREE_TEST is not set
++# CONFIG_INTERVAL_TREE_TEST is not set
++# CONFIG_PERCPU_TEST is not set
++# CONFIG_ATOMIC64_SELFTEST is not set
++# CONFIG_TEST_STRING_HELPERS is not set
++# CONFIG_TEST_KSTRTOX is not set
++# CONFIG_TEST_RHASHTABLE is not set
++# CONFIG_DMA_API_DEBUG is not set
++# CONFIG_TEST_LKM is not set
++# CONFIG_TEST_USER_COPY is not set
++# CONFIG_TEST_BPF is not set
++# CONFIG_TEST_FIRMWARE is not set
++# CONFIG_TEST_UDELAY is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_KGDB is not set
++# CONFIG_ARM_PTDUMP is not set
++CONFIG_STRICT_DEVMEM=y
++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_DEBUG_UART_PL01X is not set
++# CONFIG_DEBUG_UART_8250 is not set
++# CONFIG_DEBUG_UART_BCM63XX is not set
++CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"
++# CONFIG_OC_ETM is not set
++# CONFIG_PID_IN_CONTEXTIDR is not set
++# CONFIG_DEBUG_SET_MODULE_RONX is not set
++# CONFIG_CORESIGHT is not set
++
++#
++# 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_HASH=y
++CONFIG_CRYPTO_HASH2=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_PCRYPT is not set
++# CONFIG_CRYPTO_CRYPTD is not set
++# CONFIG_CRYPTO_MCRYPTD 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_CMAC is not set
++# CONFIG_CRYPTO_HMAC is not set
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_VMAC is not set
++
++#
++# Digest
++#
++CONFIG_CRYPTO_CRC32C=y
++# CONFIG_CRYPTO_CRC32 is not set
++# CONFIG_CRYPTO_CRCT10DIF 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_SHA1_ARM_NEON is not set
++# CONFIG_CRYPTO_SHA256 is not set
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_SHA512_ARM_NEON 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_AES_ARM_BS 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
++# CONFIG_CRYPTO_LZ4 is not set
++# CONFIG_CRYPTO_LZ4HC is not set
++
++#
++# Random Number Generation
++#
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++# CONFIG_CRYPTO_DRBG_MENU is not set
++# CONFIG_CRYPTO_USER_API_HASH is not set
++# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
++CONFIG_CRYPTO_HW=y
++# CONFIG_BINARY_PRINTF is not set
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++CONFIG_GENERIC_STRNCPY_FROM_USER=y
++CONFIG_GENERIC_STRNLEN_USER=y
++CONFIG_GENERIC_NET_UTILS=y
++CONFIG_GENERIC_PCI_IOMAP=y
++CONFIG_GENERIC_IO=y
++CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
++# CONFIG_CRC_CCITT is not set
++CONFIG_CRC16=y
++# CONFIG_CRC_T10DIF is not set
++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 is not set
++# CONFIG_LIBCRC32C is not set
++# CONFIG_CRC8 is not set
++# CONFIG_AUDIT_ARCH_COMPAT_GENERIC is not set
++# CONFIG_RANDOM32_SELFTEST is not set
++CONFIG_ZLIB_INFLATE=y
++CONFIG_ZLIB_DEFLATE=y
++CONFIG_LZO_COMPRESS=y
++CONFIG_LZO_DECOMPRESS=y
++CONFIG_LZ4_DECOMPRESS=y
++CONFIG_XZ_DEC=y
++CONFIG_XZ_DEC_X86=y
++CONFIG_XZ_DEC_POWERPC=y
++CONFIG_XZ_DEC_IA64=y
++CONFIG_XZ_DEC_ARM=y
++CONFIG_XZ_DEC_ARMTHUMB=y
++CONFIG_XZ_DEC_SPARC=y
++CONFIG_XZ_DEC_BCJ=y
++# CONFIG_XZ_DEC_TEST is not set
++CONFIG_DECOMPRESS_GZIP=y
++CONFIG_DECOMPRESS_BZIP2=y
++CONFIG_DECOMPRESS_LZMA=y
++CONFIG_DECOMPRESS_XZ=y
++CONFIG_DECOMPRESS_LZO=y
++CONFIG_DECOMPRESS_LZ4=y
++CONFIG_GENERIC_ALLOCATOR=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT_MAP=y
++CONFIG_HAS_DMA=y
++CONFIG_CPU_RMAP=y
++CONFIG_DQL=y
++CONFIG_GLOB=y
++# CONFIG_GLOB_SELFTEST is not set
++CONFIG_NLATTR=y
++CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
++# CONFIG_AVERAGE is not set
++# CONFIG_CORDIC is not set
++# CONFIG_DDR is not set
++CONFIG_LIBFDT=y
++CONFIG_ARCH_HAS_SG_CHAIN=y
++# CONFIG_VIRTUALIZATION is not set
+diff --git a/arch/arm/configs/hi3531d_nand_defconfig b/arch/arm/configs/hi3531d_nand_defconfig
+new file mode 100644
+index 0000000..a88a13d
+--- /dev/null
++++ b/arch/arm/configs/hi3531d_nand_defconfig
+@@ -0,0 +1,2603 @@
++#
++# Automatically generated file; DO NOT EDIT.
++# Linux/arm 3.18.20 Kernel Configuration
++#
++CONFIG_ARM=y
++CONFIG_ARM_HAS_SG_CHAIN=y
++CONFIG_MIGHT_HAVE_PCI=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=y
++CONFIG_HAVE_PROC_CPU=y
++CONFIG_STACKTRACE_SUPPORT=y
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
++CONFIG_RWSEM_XCHGADD_ALGORITHM=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_NEED_DMA_MAP_STATE=y
++CONFIG_ARCH_SUPPORTS_UPROBES=y
++CONFIG_VECTORS_BASE=0xffff0000
++CONFIG_ARM_PATCH_PHYS_VIRT=y
++CONFIG_NEED_MACH_IO_H=y
++CONFIG_GENERIC_BUG=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++CONFIG_IRQ_WORK=y
++CONFIG_BUILDTIME_EXTABLE_SORT=y
++
++#
++# General setup
++#
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_CROSS_COMPILE=""
++# CONFIG_COMPILE_TEST is not set
++CONFIG_LOCALVERSION=""
++# CONFIG_LOCALVERSION_AUTO is not set
++CONFIG_HAVE_KERNEL_GZIP=y
++CONFIG_HAVE_KERNEL_LZMA=y
++CONFIG_HAVE_KERNEL_XZ=y
++CONFIG_HAVE_KERNEL_LZO=y
++CONFIG_HAVE_KERNEL_LZ4=y
++CONFIG_KERNEL_GZIP=y
++# CONFIG_KERNEL_LZMA is not set
++# CONFIG_KERNEL_XZ is not set
++# CONFIG_KERNEL_LZO is not set
++# CONFIG_KERNEL_LZ4 is not set
++CONFIG_DEFAULT_HOSTNAME="(none)"
++# CONFIG_SWAP is not set
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++# CONFIG_POSIX_MQUEUE is not set
++CONFIG_CROSS_MEMORY_ATTACH=y
++# CONFIG_FHANDLE is not set
++CONFIG_USELIB=y
++# CONFIG_AUDIT is not set
++
++#
++# IRQ subsystem
++#
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_GENERIC_IRQ_SHOW=y
++CONFIG_HARDIRQS_SW_RESEND=y
++CONFIG_IRQ_DOMAIN=y
++CONFIG_HANDLE_DOMAIN_IRQ=y
++CONFIG_IRQ_FORCED_THREADING=y
++CONFIG_SPARSE_IRQ=y
++CONFIG_GENERIC_CLOCKEVENTS=y
++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
++CONFIG_ARCH_HAS_TICK_BROADCAST=y
++CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
++
++#
++# Timers subsystem
++#
++CONFIG_HZ_PERIODIC=y
++# CONFIG_NO_HZ_IDLE is not set
++# CONFIG_NO_HZ_FULL is not set
++# CONFIG_NO_HZ is not set
++# CONFIG_HIGH_RES_TIMERS is not set
++
++#
++# CPU/Task time and stats accounting
++#
++CONFIG_TICK_CPU_ACCOUNTING=y
++# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set
++# CONFIG_IRQ_TIME_ACCOUNTING is not set
++# CONFIG_BSD_PROCESS_ACCT is not set
++# CONFIG_TASKSTATS is not set
++
++#
++# RCU Subsystem
++#
++CONFIG_TREE_RCU=y
++# CONFIG_PREEMPT_RCU is not set
++# CONFIG_TASKS_RCU is not set
++CONFIG_RCU_STALL_COMMON=y
++# CONFIG_RCU_USER_QS is not set
++CONFIG_RCU_FANOUT=32
++CONFIG_RCU_FANOUT_LEAF=16
++# CONFIG_RCU_FANOUT_EXACT is not set
++# CONFIG_TREE_RCU_TRACE is not set
++# CONFIG_RCU_NOCB_CPU is not set
++# CONFIG_BUILD_BIN2C is not set
++# CONFIG_IKCONFIG is not set
++CONFIG_LOG_BUF_SHIFT=17
++CONFIG_LOG_CPU_MAX_BUF_SHIFT=12
++CONFIG_GENERIC_SCHED_CLOCK=y
++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_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_USER_NS is not set
++CONFIG_PID_NS=y
++CONFIG_NET_NS=y
++# 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=y
++CONFIG_RD_LZMA=y
++CONFIG_RD_XZ=y
++CONFIG_RD_LZO=y
++CONFIG_RD_LZ4=y
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++CONFIG_HAVE_UID16=y
++CONFIG_BPF=y
++# CONFIG_EXPERT is not set
++CONFIG_UID16=y
++# CONFIG_SGETMASK_SYSCALL is not set
++CONFIG_SYSFS_SYSCALL=y
++# CONFIG_SYSCTL_SYSCALL is not set
++CONFIG_KALLSYMS=y
++# CONFIG_KALLSYMS_ALL is not set
++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_BPF_SYSCALL is not set
++CONFIG_SHMEM=y
++CONFIG_AIO=y
++CONFIG_ADVISE_SYSCALLS=y
++CONFIG_PCI_QUIRKS=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 is not set
++# CONFIG_SLAB is not set
++CONFIG_SLUB=y
++CONFIG_SLUB_CPU_PARTIAL=y
++# CONFIG_PROFILING is not set
++CONFIG_HAVE_OPROFILE=y
++# CONFIG_KPROBES is not set
++# CONFIG_JUMP_LABEL is not set
++# CONFIG_UPROBES is not set
++# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
++CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
++CONFIG_ARCH_USE_BUILTIN_BSWAP=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_GENERIC_SMP_IDLE_THREAD=y
++CONFIG_GENERIC_IDLE_POLL_SETUP=y
++CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
++CONFIG_HAVE_CLK=y
++CONFIG_HAVE_DMA_API_DEBUG=y
++CONFIG_HAVE_PERF_REGS=y
++CONFIG_HAVE_PERF_USER_STACK_DUMP=y
++CONFIG_HAVE_ARCH_JUMP_LABEL=y
++CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
++CONFIG_HAVE_CC_STACKPROTECTOR=y
++# CONFIG_CC_STACKPROTECTOR is not set
++CONFIG_CC_STACKPROTECTOR_NONE=y
++# CONFIG_CC_STACKPROTECTOR_REGULAR is not set
++# CONFIG_CC_STACKPROTECTOR_STRONG is not set
++CONFIG_HAVE_CONTEXT_TRACKING=y
++CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
++CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
++CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
++CONFIG_MODULES_USE_ELF_REL=y
++CONFIG_CLONE_BACKWARDS=y
++CONFIG_OLD_SIGSUSPEND3=y
++CONFIG_OLD_SIGACTION=y
++
++#
++# GCOV-based kernel profiling
++#
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_SLABINFO=y
++CONFIG_RT_MUTEXES=y
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++# CONFIG_MODULE_FORCE_LOAD is not set
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++# CONFIG_MODULE_SIG is not set
++# CONFIG_MODULE_COMPRESS is not set
++CONFIG_STOP_MACHINE=y
++CONFIG_BLOCK=y
++CONFIG_LBDAF=y
++CONFIG_BLK_DEV_BSG=y
++# CONFIG_BLK_DEV_BSGLIB is not set
++# CONFIG_BLK_DEV_INTEGRITY is not set
++CONFIG_BLK_CMDLINE_PARSER=y
++
++#
++# Partition Types
++#
++CONFIG_PARTITION_ADVANCED=y
++# CONFIG_ACORN_PARTITION is not set
++# CONFIG_AIX_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=y
++# CONFIG_SYSV68_PARTITION is not set
++CONFIG_CMDLINE_PARTITION=y
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++CONFIG_DEFAULT_DEADLINE=y
++# CONFIG_DEFAULT_CFQ is not set
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="deadline"
++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_ARCH_SUPPORTS_ATOMIC_RMW=y
++CONFIG_MUTEX_SPIN_ON_OWNER=y
++CONFIG_RWSEM_SPIN_ON_OWNER=y
++CONFIG_FREEZER=y
++
++#
++# System Type
++#
++CONFIG_MMU=y
++CONFIG_ARCH_MULTIPLATFORM=y
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_AT91 is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_GEMINI is not set
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_IOP13XX is not set
++# CONFIG_ARCH_IOP32X is not set
++# CONFIG_ARCH_IOP33X is not set
++# CONFIG_ARCH_IXP4XX is not set
++# CONFIG_ARCH_DOVE is not set
++# CONFIG_ARCH_MV78XX0 is not set
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_MMP is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_W90X900 is not set
++# CONFIG_ARCH_LPC32XX is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_MSM is not set
++# CONFIG_ARCH_SHMOBILE_LEGACY 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_DAVINCI is not set
++# CONFIG_ARCH_OMAP1 is not set
++
++#
++# Multiple platform selection
++#
++
++#
++# CPU Core family selection
++#
++# CONFIG_ARCH_MULTI_V6 is not set
++CONFIG_ARCH_MULTI_V7=y
++CONFIG_ARCH_MULTI_V6_V7=y
++# CONFIG_ARCH_MULTI_CPU_AUTO is not set
++# CONFIG_ARCH_VIRT is not set
++# CONFIG_ARCH_MVEBU is not set
++# CONFIG_ARCH_BCM is not set
++# CONFIG_ARCH_BERLIN is not set
++# CONFIG_ARCH_HIGHBANK is not set
++CONFIG_ARCH_HISI=y
++
++#
++# Hisilicon platform type
++#
++# CONFIG_ARCH_HI3xxx is not set
++# CONFIG_ARCH_HIP04 is not set
++# CONFIG_ARCH_HIX5HD2 is not set
++# CONFIG_ARCH_HI3519 is not set
++# CONFIG_ARCH_HI3519V101 is not set
++# CONFIG_ARCH_HI3516AV200 is not set
++# CONFIG_ARCH_HI3559 is not set
++# CONFIG_ARCH_HI3556 is not set
++# CONFIG_ARCH_HI3536C is not set
++CONFIG_ARCH_HI3531D=y
++# CONFIG_ARCH_HI3521D is not set
++# CONFIG_ARCH_KEYSTONE is not set
++# CONFIG_ARCH_MESON is not set
++# CONFIG_ARCH_MXC is not set
++# CONFIG_ARCH_MEDIATEK is not set
++
++#
++# TI OMAP/AM/DM/DRA Family
++#
++# CONFIG_ARCH_OMAP3 is not set
++# CONFIG_ARCH_OMAP4 is not set
++# CONFIG_SOC_OMAP5 is not set
++# CONFIG_SOC_AM33XX is not set
++# CONFIG_SOC_AM43XX is not set
++# CONFIG_SOC_DRA7XX is not set
++# CONFIG_ARCH_QCOM is not set
++# CONFIG_ARCH_ROCKCHIP is not set
++# CONFIG_ARCH_SOCFPGA is not set
++# CONFIG_PLAT_SPEAR is not set
++# CONFIG_ARCH_STI is not set
++# CONFIG_ARCH_S5PV210 is not set
++# CONFIG_ARCH_EXYNOS is not set
++# CONFIG_ARCH_SHMOBILE_MULTI is not set
++# CONFIG_ARCH_SUNXI is not set
++# CONFIG_ARCH_SIRF is not set
++# CONFIG_ARCH_TEGRA is not set
++# CONFIG_ARCH_U8500 is not set
++# CONFIG_ARCH_VEXPRESS is not set
++# CONFIG_ARCH_WM8850 is not set
++# CONFIG_ARCH_ZYNQ is not set
++CONFIG_ARM_TIMER_SP804=y
++
++#
++# Processor Type
++#
++CONFIG_CPU_V7=y
++CONFIG_CPU_32v6K=y
++CONFIG_CPU_32v7=y
++CONFIG_CPU_ABRT_EV7=y
++CONFIG_CPU_PABRT_V7=y
++CONFIG_CPU_CACHE_V7=y
++CONFIG_CPU_CACHE_VIPT=y
++CONFIG_CPU_COPY_V6=y
++CONFIG_CPU_TLB_V7=y
++CONFIG_CPU_HAS_ASID=y
++CONFIG_CPU_CP15=y
++CONFIG_CPU_CP15_MMU=y
++
++#
++# Processor Features
++#
++# CONFIG_ARM_LPAE is not set
++# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
++CONFIG_ARM_THUMB=y
++# CONFIG_ARM_THUMBEE is not set
++CONFIG_ARM_VIRT_EXT=y
++CONFIG_SWP_EMULATE=y
++# CONFIG_CPU_ICACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_DISABLE is not set
++# CONFIG_CPU_BPREDICT_DISABLE is not set
++CONFIG_KUSER_HELPERS=y
++CONFIG_OUTER_CACHE=y
++CONFIG_OUTER_CACHE_SYNC=y
++CONFIG_MIGHT_HAVE_CACHE_L2X0=y
++CONFIG_CACHE_L2X0=y
++CONFIG_CACHE_PL310=y
++# CONFIG_PL310_ERRATA_588369 is not set
++# CONFIG_PL310_ERRATA_727915 is not set
++# CONFIG_PL310_ERRATA_753970 is not set
++# CONFIG_PL310_ERRATA_769419 is not set
++CONFIG_ARM_L1_CACHE_SHIFT_6=y
++CONFIG_ARM_L1_CACHE_SHIFT=6
++CONFIG_ARM_DMA_MEM_BUFFERABLE=y
++CONFIG_MULTI_IRQ_HANDLER=y
++# CONFIG_ARM_ERRATA_430973 is not set
++# CONFIG_ARM_ERRATA_643719 is not set
++# CONFIG_ARM_ERRATA_720789 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_ARM_ERRATA_775420 is not set
++# CONFIG_ARM_ERRATA_798181 is not set
++# CONFIG_ARM_ERRATA_773022 is not set
++
++#
++# Bus support
++#
++CONFIG_ARM_AMBA=y
++CONFIG_PCI=y
++CONFIG_PCI_SYSCALL=y
++# CONFIG_PCI_MSI is not set
++# CONFIG_PCI_DEBUG is not set
++# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set
++# CONFIG_PCI_STUB is not set
++# CONFIG_PCI_IOV is not set
++# CONFIG_PCI_PRI is not set
++# CONFIG_PCI_PASID is not set
++
++#
++# PCI host controller drivers
++#
++# CONFIG_PCI_HOST_GENERIC is not set
++CONFIG_PCIEPORTBUS=y
++CONFIG_PCIEAER=y
++# CONFIG_PCIE_ECRC is not set
++# CONFIG_PCIEAER_INJECT is not set
++CONFIG_PCIEASPM=y
++# CONFIG_PCIEASPM_DEBUG is not set
++CONFIG_PCIEASPM_DEFAULT=y
++# CONFIG_PCIEASPM_POWERSAVE is not set
++# CONFIG_PCIEASPM_PERFORMANCE is not set
++# CONFIG_PCCARD is not set
++CONFIG_HIPCIE=y
++
++#
++# PCI Express configs
++#
++CONFIG_PCIE0_SEL=1
++CONFIG_PCIE0_DEVICES_MEM_SIZE=0x8000000
++CONFIG_PCIE0_DEVICES_CONFIG_SIZE=0x8000000
++CONFIG_LIMIT_MAX_RD_REQ_SIZE=y
++CONFIG_PCIE1_SEL=1
++CONFIG_PCIE1_DEVICES_MEM_SIZE=0x8000000
++CONFIG_PCIE1_DEVICES_CONFIG_SIZE=0x8000000
++
++#
++# 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_DISABLE_CPU_SCHED_DOMAIN_BALANCE is not set
++CONFIG_HAVE_ARM_SCU=y
++CONFIG_HAVE_ARM_ARCH_TIMER=y
++# CONFIG_MCPM is not set
++# CONFIG_BIG_LITTLE is not set
++CONFIG_VMSPLIT_3G=y
++# CONFIG_VMSPLIT_2G is not set
++# CONFIG_VMSPLIT_1G is not set
++CONFIG_PAGE_OFFSET=0xC0000000
++CONFIG_NR_CPUS=4
++CONFIG_HOTPLUG_CPU=y
++# CONFIG_ARM_PSCI is not set
++CONFIG_ARCH_NR_GPIO=0
++CONFIG_PREEMPT_NONE=y
++# CONFIG_PREEMPT_VOLUNTARY is not set
++# CONFIG_PREEMPT is not set
++CONFIG_HZ_FIXED=0
++CONFIG_HZ_100=y
++# CONFIG_HZ_200 is not set
++# CONFIG_HZ_250 is not set
++# CONFIG_HZ_300 is not set
++# CONFIG_HZ_500 is not set
++# CONFIG_HZ_1000 is not set
++CONFIG_HZ=100
++# CONFIG_SCHED_HRTICK is not set
++# CONFIG_THUMB2_KERNEL is not set
++CONFIG_AEABI=y
++CONFIG_OABI_COMPAT=y
++# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
++# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
++CONFIG_HAVE_ARCH_PFN_VALID=y
++CONFIG_HIGHMEM=y
++# CONFIG_HIGHPTE is not set
++CONFIG_ARCH_WANT_GENERAL_HUGETLB=y
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_HAVE_MEMBLOCK=y
++CONFIG_NO_BOOTMEM=y
++# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=4
++CONFIG_COMPACTION=y
++CONFIG_MIGRATION=y
++# CONFIG_PHYS_ADDR_T_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_BOUNCE=y
++# CONFIG_KSM is not set
++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
++# CONFIG_CLEANCACHE is not set
++# CONFIG_CMA is not set
++# CONFIG_ZPOOL is not set
++# CONFIG_ZBUD is not set
++# CONFIG_ZSMALLOC 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_SWIOTLB=y
++CONFIG_IOMMU_HELPER=y
++# CONFIG_XEN is not set
++# CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART is not set
++
++#
++# Boot options
++#
++CONFIG_USE_OF=y
++CONFIG_ATAGS=y
++# CONFIG_DEPRECATED_PARAM_STRUCT is not set
++# CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE is not set
++CONFIG_ZBOOT_ROM_TEXT=0
++CONFIG_ZBOOT_ROM_BSS=0
++CONFIG_ARM_APPENDED_DTB=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_KEXEC is not set
++# CONFIG_CRASH_DUMP is not set
++CONFIG_AUTO_ZRELADDR=y
++
++#
++# CPU Power Management
++#
++
++#
++# CPU Frequency scaling
++#
++CONFIG_CPU_FREQ=y
++CONFIG_CPU_FREQ_STAT=y
++# CONFIG_CPU_FREQ_STAT_DETAILS is not set
++CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
++# CONFIG_CPU_FREQ_DEFAULT_GOV_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_DEFAULT_GOV_INTERACTIVE is not set
++CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
++# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
++# CONFIG_CPU_FREQ_GOV_USERSPACE is not set
++# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
++# CONFIG_CPU_FREQ_GOV_INTERACTIVE is not set
++# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
++CONFIG_CPUFREQ_DT=y
++
++#
++# ARM CPU frequency scaling drivers
++#
++# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set
++
++#
++# CPU Idle
++#
++# CONFIG_CPU_IDLE is not set
++# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++# CONFIG_FPE_NWFPE is not set
++# CONFIG_FPE_FASTFPE is not set
++CONFIG_VFP=y
++CONFIG_VFPv3=y
++CONFIG_NEON=y
++CONFIG_KERNEL_MODE_NEON=y
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
++CONFIG_BINFMT_SCRIPT=y
++# CONFIG_HAVE_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
++CONFIG_COREDUMP=y
++
++#
++# Power management options
++#
++CONFIG_SUSPEND=y
++CONFIG_SUSPEND_FREEZER=y
++CONFIG_WAKELOCK=y
++# CONFIG_HISI_SNAPSHOT_BOOT is not set
++CONFIG_PM_SLEEP=y
++CONFIG_PM_SLEEP_SMP=y
++# CONFIG_PM_AUTOSLEEP is not set
++# CONFIG_PM_WAKELOCKS is not set
++# CONFIG_PM_RUNTIME is not set
++CONFIG_PM=y
++# CONFIG_PM_DEBUG is not set
++# CONFIG_APM_EMULATION is not set
++CONFIG_PM_OPP=y
++CONFIG_PM_CLK=y
++# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set
++CONFIG_CPU_PM=y
++# CONFIG_SUSPEND_TIME is not set
++CONFIG_ARCH_SUSPEND_POSSIBLE=y
++CONFIG_ARM_CPU_SUSPEND=y
++CONFIG_ARCH_HIBERNATION_POSSIBLE=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=y
++# 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_NET_IP_TUNNEL=m
++# CONFIG_IP_MROUTE is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_NET_UDP_TUNNEL is not set
++# CONFIG_NET_FOU is not set
++# CONFIG_GENEVE 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 is not set
++# CONFIG_INET_XFRM_MODE_TUNNEL is not set
++# CONFIG_INET_XFRM_MODE_BEET is not set
++CONFIG_INET_LRO=y
++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=y
++# 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_VTI 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_ANDROID_PARANOID_NETWORK is not set
++CONFIG_NET_ACTIVITY_STATS=y
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NET_PTP_CLASSIFY 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_NF_TABLES is not set
++# CONFIG_NETFILTER_XTABLES is not set
++# CONFIG_IP_SET is not set
++# CONFIG_IP_VS is not set
++
++#
++# IP: Netfilter Configuration
++#
++# CONFIG_NF_DEFRAG_IPV4 is not set
++# CONFIG_NF_LOG_ARP is not set
++# CONFIG_NF_LOG_IPV4 is not set
++# CONFIG_NF_REJECT_IPV4 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_NF_REJECT_IPV6 is not set
++# CONFIG_NF_LOG_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_HAVE_NET_DSA=y
++# 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_PHONET is not set
++# CONFIG_6LOWPAN 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_VSOCKETS is not set
++# CONFIG_NETLINK_MMAP is not set
++# CONFIG_NETLINK_DIAG is not set
++# CONFIG_NET_MPLS_GSO is not set
++# CONFIG_HSR is not set
++CONFIG_RPS=y
++CONFIG_RFS_ACCEL=y
++CONFIG_XPS=y
++# CONFIG_CGROUP_NET_PRIO is not set
++# CONFIG_CGROUP_NET_CLASSID is not set
++CONFIG_NET_RX_BUSY_POLL=y
++CONFIG_BQL=y
++# CONFIG_BPF_JIT is not set
++CONFIG_NET_FLOW_LIMIT=y
++
++#
++# 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 is not set
++# 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 is not set
++CONFIG_DEVTMPFS=y
++# CONFIG_DEVTMPFS_MOUNT is not set
++CONFIG_STANDALONE=y
++# CONFIG_PREVENT_FIRMWARE_BUILD is not set
++CONFIG_FW_LOADER=y
++CONFIG_FIRMWARE_IN_KERNEL=y
++CONFIG_EXTRA_FIRMWARE=""
++# CONFIG_FW_LOADER_USER_HELPER_FALLBACK is not set
++CONFIG_ALLOW_DEV_COREDUMP=y
++# 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_HAVE_CPU_AUTOPROBE is not set
++CONFIG_REGMAP=y
++CONFIG_REGMAP_MMIO=y
++# CONFIG_DMA_SHARED_BUFFER is not set
++
++#
++# Bus devices
++#
++# CONFIG_BRCMSTB_GISB_ARB is not set
++# CONFIG_ARM_CCI is not set
++# CONFIG_VEXPRESS_CONFIG 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=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_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_HIFMC 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_INTEL_VR_NOR is not set
++# CONFIG_MTD_PLATRAM is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_PMC551 is not set
++# CONFIG_MTD_DATAFLASH is not set
++# CONFIG_MTD_SST25L is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_PHRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++# CONFIG_MTD_BLOCK2MTD is not set
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOCG3 is not set
++CONFIG_MTD_NAND_IDS=y
++CONFIG_MTD_NAND_ECC=y
++# CONFIG_MTD_NAND_ECC_SMC is not set
++CONFIG_MTD_NAND=y
++# CONFIG_MTD_NAND_ECC_BCH is not set
++# CONFIG_MTD_SM_COMMON is not set
++# CONFIG_MTD_NAND_DENALI is not set
++# CONFIG_MTD_NAND_OMAP_BCH_BUILD is not set
++# CONFIG_MTD_NAND_RICOH is not set
++# CONFIG_MTD_NAND_DISKONCHIP is not set
++# CONFIG_MTD_NAND_DOCG4 is not set
++# CONFIG_MTD_NAND_CAFE is not set
++# CONFIG_MTD_NAND_NANDSIM is not set
++# CONFIG_MTD_NAND_PLATFORM is not set
++# CONFIG_HISI_NAND_FS_MAY_NO_YAFFS2 is not set
++# CONFIG_HISI_NAND_ECC_STATUS_REPORT is not set
++CONFIG_MTD_NAND_HINFC610=y
++# CONFIG_MTD_PARTITION_FROM_DTS is not set
++CONFIG_HINFC610_MAX_CHIP=1
++# CONFIG_HINFC610_DBG_NAND_DEBUG is not set
++CONFIG_HINFC610_AUTO_PAGESIZE_ECC=y
++# CONFIG_HINFC610_PAGESIZE_AUTO_ECC_NONE is not set
++# CONFIG_MTD_ONENAND is not set
++
++#
++# LPDDR & LPDDR2 PCM memory drivers
++#
++# CONFIG_MTD_LPDDR is not set
++# CONFIG_MTD_LPDDR2_NVM is not set
++# CONFIG_MTD_SPI_NOR is not set
++# CONFIG_MTD_UBI is not set
++CONFIG_DTC=y
++CONFIG_OF=y
++
++#
++# Device Tree and Open Firmware support
++#
++# CONFIG_OF_SELFTEST is not set
++CONFIG_OF_FLATTREE=y
++CONFIG_OF_EARLY_FLATTREE=y
++CONFIG_OF_ADDRESS=y
++CONFIG_OF_ADDRESS_PCI=y
++CONFIG_OF_IRQ=y
++CONFIG_OF_NET=y
++CONFIG_OF_MDIO=y
++CONFIG_OF_PCI=y
++CONFIG_OF_PCI_IRQ=y
++CONFIG_OF_MTD=y
++CONFIG_OF_RESERVED_MEM=y
++CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
++# CONFIG_PARPORT is not set
++CONFIG_BLK_DEV=y
++# CONFIG_BLK_DEV_NULL_BLK is not set
++# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set
++# CONFIG_BLK_CPQ_CISS_DA is not set
++# CONFIG_BLK_DEV_DAC960 is not set
++# CONFIG_BLK_DEV_UMEM is not set
++# CONFIG_BLK_DEV_COW_COMMON is not set
++# CONFIG_BLK_DEV_LOOP is not set
++# CONFIG_BLK_DEV_DRBD is not set
++# CONFIG_BLK_DEV_NBD is not set
++# CONFIG_BLK_DEV_NVME is not set
++# CONFIG_BLK_DEV_SX8 is not set
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_COUNT=16
++CONFIG_BLK_DEV_RAM_SIZE=65536
++# CONFIG_BLK_DEV_XIP is not set
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH is not set
++# CONFIG_BLK_DEV_RBD is not set
++# CONFIG_BLK_DEV_RSXX is not set
++
++#
++# Misc devices
++#
++# CONFIG_SENSORS_LIS3LV02D is not set
++# CONFIG_AD525X_DPOT is not set
++# CONFIG_DUMMY_IRQ is not set
++# CONFIG_PHANTOM is not set
++# CONFIG_SGI_IOC4 is not set
++# CONFIG_TIFM_CORE is not set
++# CONFIG_ICS932S401 is not set
++# CONFIG_ENCLOSURE_SERVICES is not set
++# CONFIG_HP_ILO is not set
++# CONFIG_APDS9802ALS is not set
++# CONFIG_ISL29003 is not set
++# CONFIG_ISL29020 is not set
++# CONFIG_SENSORS_TSL2550 is not set
++# CONFIG_SENSORS_BH1780 is not set
++# CONFIG_SENSORS_BH1770 is not set
++# CONFIG_SENSORS_APDS990X is not set
++# CONFIG_HMC6352 is not set
++# CONFIG_DS1682 is not set
++# CONFIG_TI_DAC7512 is not set
++# CONFIG_UID_STAT is not set
++# CONFIG_BMP085_I2C is not set
++# CONFIG_BMP085_SPI is not set
++# CONFIG_USB_SWITCH_FSA9480 is not set
++# CONFIG_LATTICE_ECP3_CONFIG is not set
++# CONFIG_SRAM is not set
++# CONFIG_C2PORT is not set
++
++#
++# EEPROM support
++#
++# CONFIG_EEPROM_AT24 is not set
++# CONFIG_EEPROM_AT25 is not set
++# CONFIG_EEPROM_LEGACY is not set
++# CONFIG_EEPROM_MAX6875 is not set
++# CONFIG_EEPROM_93CX6 is not set
++# CONFIG_EEPROM_93XX46 is not set
++# CONFIG_CB710_CORE is not set
++
++#
++# Texas Instruments shared transport line discipline
++#
++# 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
++
++#
++# Intel MIC Bus Driver
++#
++
++#
++# Intel MIC Host Driver
++#
++
++#
++# Intel MIC Card Driver
++#
++# CONFIG_ECHO is not set
++# CONFIG_CXL_BASE is not set
++
++#
++# hisi 'himm/himd.l/himc'support
++#
++# CONFIG_HISI_REG is not set
++CONFIG_HAVE_IDE=y
++# CONFIG_IDE 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_NETLINK is not set
++# CONFIG_SCSI_MQ_DEFAULT is not set
++CONFIG_SCSI_PROC_FS=y
++
++#
++# SCSI support type (disk, tape, CD-ROM)
++#
++CONFIG_BLK_DEV_SD=y
++# CONFIG_CHR_DEV_ST is not set
++# CONFIG_CHR_DEV_OSST is not set
++CONFIG_BLK_DEV_SR=y
++# CONFIG_BLK_DEV_SR_VENDOR is not set
++# CONFIG_CHR_DEV_SG is not set
++# CONFIG_CHR_DEV_SCH is not set
++# CONFIG_SCSI_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 is not set
++# CONFIG_SCSI_DH is not set
++# CONFIG_SCSI_OSD_INITIATOR is not set
++CONFIG_HI_SATA=y
++CONFIG_HI_SATA_IOBASE=0x11010000
++CONFIG_HI_SATA_FBS=1
++CONFIG_HI_SATA_NCQ=1
++CONFIG_ATA=y
++# CONFIG_ATA_NONSTANDARD is not set
++CONFIG_ATA_VERBOSE_ERROR=y
++CONFIG_SATA_PMP=y
++
++#
++# Controllers with non-SFF native interface
++#
++# CONFIG_SATA_AHCI is not set
++CONFIG_SATA_AHCI_PLATFORM=y
++# CONFIG_SATA_INIC162X is not set
++# CONFIG_SATA_ACARD_AHCI is not set
++# CONFIG_SATA_SIL24 is not set
++# CONFIG_ATA_SFF is not set
++# CONFIG_MD is not set
++# CONFIG_TARGET_CORE is not set
++# CONFIG_FUSION is not set
++
++#
++# IEEE 1394 (FireWire) support
++#
++# CONFIG_FIREWIRE is not set
++# CONFIG_FIREWIRE_NOSY is not set
++# CONFIG_I2O 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_NET_FC is not set
++# CONFIG_NET_TEAM is not set
++# CONFIG_MACVLAN is not set
++# CONFIG_VXLAN is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_TUN is not set
++# CONFIG_VETH is not set
++# CONFIG_NLMON is not set
++# CONFIG_ARCNET is not set
++
++#
++# 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_NET_DSA_MV88E6171 is not set
++# CONFIG_NET_DSA_BCM_SF2 is not set
++CONFIG_ETHERNET=y
++# CONFIG_NET_VENDOR_3COM is not set
++# CONFIG_NET_VENDOR_ADAPTEC is not set
++# CONFIG_NET_VENDOR_AGERE is not set
++# CONFIG_NET_VENDOR_ALTEON is not set
++# CONFIG_ALTERA_TSE is not set
++# CONFIG_NET_VENDOR_AMD is not set
++# CONFIG_NET_XGENE is not set
++# CONFIG_NET_VENDOR_ARC is not set
++# CONFIG_NET_VENDOR_ATHEROS is not set
++# CONFIG_NET_CADENCE is not set
++# CONFIG_NET_VENDOR_BROADCOM is not set
++# CONFIG_NET_VENDOR_BROCADE is not set
++# CONFIG_NET_VENDOR_CHELSIO is not set
++# CONFIG_NET_VENDOR_CIRRUS is not set
++# CONFIG_NET_VENDOR_CISCO is not set
++# CONFIG_DM9000 is not set
++# CONFIG_DNET is not set
++# CONFIG_NET_VENDOR_DEC is not set
++# CONFIG_NET_VENDOR_DLINK is not set
++# CONFIG_NET_VENDOR_EMULEX is not set
++# CONFIG_NET_VENDOR_EXAR is not set
++# CONFIG_NET_VENDOR_FARADAY is not set
++CONFIG_NET_VENDOR_HISILICON=y
++# CONFIG_HIX5HD2_GMAC is not set
++# CONFIG_HISI_FEMAC is not set
++CONFIG_HIETH_GMAC=y
++CONFIG_HIGMAC_DESC_4WORD=y
++CONFIG_HIGMAC_RXCSUM=y
++CONFIG_RX_FLOW_CTRL_SUPPORT=y
++CONFIG_TX_FLOW_CTRL_SUPPORT=y
++CONFIG_TX_FLOW_CTRL_PAUSE_TIME=0xFFFF
++CONFIG_TX_FLOW_CTRL_PAUSE_INTERVAL=0xFFFF
++CONFIG_TX_FLOW_CTRL_ACTIVE_THRESHOLD=16
++CONFIG_TX_FLOW_CTRL_DEACTIVE_THRESHOLD=32
++# CONFIG_HIETH_SWITCH_FABRIC is not set
++# CONFIG_NET_VENDOR_HP is not set
++# CONFIG_NET_VENDOR_INTEL is not set
++# CONFIG_IP1000 is not set
++# CONFIG_JME is not set
++# CONFIG_NET_VENDOR_MARVELL is not set
++# CONFIG_NET_VENDOR_MELLANOX is not set
++# CONFIG_NET_VENDOR_MICREL is not set
++# CONFIG_NET_VENDOR_MICROCHIP is not set
++# CONFIG_NET_VENDOR_MYRI is not set
++# CONFIG_FEALNX is not set
++# CONFIG_NET_VENDOR_NATSEMI is not set
++# CONFIG_NET_VENDOR_NVIDIA is not set
++# CONFIG_NET_VENDOR_OKI is not set
++# CONFIG_ETHOC is not set
++# CONFIG_NET_PACKET_ENGINE is not set
++# CONFIG_NET_VENDOR_QLOGIC is not set
++# CONFIG_NET_VENDOR_QUALCOMM is not set
++# CONFIG_NET_VENDOR_REALTEK is not set
++# CONFIG_NET_VENDOR_RDC is not set
++# CONFIG_NET_VENDOR_SAMSUNG is not set
++# CONFIG_NET_VENDOR_SEEQ is not set
++# CONFIG_NET_VENDOR_SILAN is not set
++# CONFIG_NET_VENDOR_SIS is not set
++# CONFIG_SFC is not set
++# CONFIG_NET_VENDOR_SMSC is not set
++# CONFIG_NET_VENDOR_STMICRO is not set
++# CONFIG_NET_VENDOR_SUN is not set
++# CONFIG_NET_VENDOR_TEHUTI is not set
++# CONFIG_NET_VENDOR_TI is not set
++# CONFIG_NET_VENDOR_VIA is not set
++# CONFIG_NET_VENDOR_WIZNET is not set
++# CONFIG_FDDI is not set
++# CONFIG_HIPPI is not set
++CONFIG_PHYLIB=y
++
++#
++# MII PHY device drivers
++#
++# CONFIG_AT803X_PHY is not set
++# CONFIG_AMD_PHY is not set
++# CONFIG_AMD_XGBE_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 is not set
++# CONFIG_BROADCOM_PHY is not set
++# CONFIG_BCM7XXX_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_MMIOREG is not set
++# CONFIG_MDIO_BCM_UNIMAC is not set
++# CONFIG_MDIO_HISI_FEMAC is not set
++CONFIG_MDIO_HISI_GEMAC=y
++# CONFIG_MICREL_KS8995MA is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++CONFIG_USB_NET_DRIVERS=y
++# 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_RTL8152 is not set
++# CONFIG_USB_USBNET is not set
++# CONFIG_USB_IPHETH is not set
++# CONFIG_WLAN is not set
++
++#
++# Enable WiMAX (Networking options) to see the WiMAX drivers
++#
++# CONFIG_WAN is not set
++# CONFIG_VMXNET3 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 is not set
++
++#
++# Userland interfaces
++#
++CONFIG_INPUT_MOUSEDEV=y
++CONFIG_INPUT_MOUSEDEV_PSAUX=y
++CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
++CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
++CONFIG_INPUT_JOYDEV=y
++CONFIG_INPUT_EVDEV=y
++# CONFIG_INPUT_EVBUG is not set
++# CONFIG_INPUT_KEYRESET is not set
++# CONFIG_INPUT_KEYCOMBO 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_TCA6416 is not set
++# CONFIG_KEYBOARD_TCA8418 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 is not set
++# CONFIG_KEYBOARD_CAP1106 is not set
++CONFIG_INPUT_MOUSE=y
++CONFIG_MOUSE_PS2=y
++CONFIG_MOUSE_PS2_ALPS=y
++CONFIG_MOUSE_PS2_LOGIPS2PP=y
++CONFIG_MOUSE_PS2_SYNAPTICS=y
++CONFIG_MOUSE_PS2_CYPRESS=y
++CONFIG_MOUSE_PS2_TRACKPOINT=y
++# CONFIG_MOUSE_PS2_ELANTECH is not set
++# CONFIG_MOUSE_PS2_SENTELIC is not set
++# CONFIG_MOUSE_PS2_TOUCHKIT is not set
++# CONFIG_MOUSE_SERIAL is not set
++# CONFIG_MOUSE_APPLETOUCH is not set
++# CONFIG_MOUSE_BCM5974 is not set
++# CONFIG_MOUSE_CYAPA is not set
++# CONFIG_MOUSE_VSXXXAA is not set
++# CONFIG_MOUSE_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 is not set
++# CONFIG_INPUT_MISC is not set
++
++#
++# Hardware I/O ports
++#
++CONFIG_SERIO=y
++CONFIG_SERIO_SERPORT=y
++# CONFIG_SERIO_AMBAKMI is not set
++# CONFIG_SERIO_PCIPS2 is not set
++CONFIG_SERIO_LIBPS2=y
++# CONFIG_SERIO_RAW is not set
++# CONFIG_SERIO_ALTERA_PS2 is not set
++# CONFIG_SERIO_PS2MULT is not set
++# CONFIG_SERIO_ARC_PS2 is not set
++# CONFIG_SERIO_APBPS2 is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++CONFIG_TTY=y
++CONFIG_VT=y
++CONFIG_CONSOLE_TRANSLATIONS=y
++CONFIG_VT_CONSOLE=y
++CONFIG_VT_CONSOLE_SLEEP=y
++CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
++CONFIG_UNIX98_PTYS=y
++# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
++# CONFIG_LEGACY_PTYS is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
++# CONFIG_NOZOMI is not set
++# CONFIG_N_GSM is not set
++# CONFIG_TRACE_SINK is not set
++CONFIG_DEVMEM=y
++CONFIG_DEVKMEM=y
++
++#
++# Serial drivers
++#
++CONFIG_SERIAL_EARLYCON=y
++# CONFIG_SERIAL_8250 is not set
++
++#
++# Non-8250 serial port support
++#
++# CONFIG_SERIAL_AMBA_PL010 is not set
++CONFIG_SERIAL_AMBA_PL011=y
++CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
++# CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST is not set
++# CONFIG_SERIAL_MAX3100 is not set
++# CONFIG_SERIAL_MAX310X is not set
++# CONFIG_SERIAL_MFD_HSU is not set
++CONFIG_SERIAL_CORE=y
++CONFIG_SERIAL_CORE_CONSOLE=y
++# CONFIG_SERIAL_JSM is not set
++# CONFIG_SERIAL_SCCNXP is not set
++# CONFIG_SERIAL_SC16IS7XX is not set
++# CONFIG_SERIAL_ALTERA_JTAGUART is not set
++# CONFIG_SERIAL_ALTERA_UART is not set
++# CONFIG_SERIAL_XILINX_PS_UART is not set
++# CONFIG_SERIAL_ARC is not set
++# CONFIG_SERIAL_RP2 is not set
++# CONFIG_SERIAL_FSL_LPUART is not set
++# CONFIG_SERIAL_ST_ASC is not set
++# CONFIG_HVC_DCC is not set
++# CONFIG_IPMI_HANDLER is not set
++# CONFIG_HW_RANDOM is not set
++# CONFIG_R3964 is not set
++# CONFIG_APPLICOM is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++CONFIG_DEVPORT=y
++# CONFIG_DCC_TTY is not set
++# CONFIG_XILLYBUS is not set
++
++#
++# I2C support
++#
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++CONFIG_I2C_COMPAT=y
++CONFIG_I2C_CHARDEV=y
++CONFIG_I2C_MUX=y
++
++#
++# Multiplexer I2C Chip support
++#
++# CONFIG_I2C_MUX_PCA9541 is not set
++# CONFIG_I2C_MUX_PINCTRL is not set
++CONFIG_I2C_HELPER_AUTO=y
++
++#
++# I2C Hardware Bus support
++#
++
++#
++# PC SMBus host controller drivers
++#
++# CONFIG_I2C_ALI1535 is not set
++# CONFIG_I2C_ALI1563 is not set
++# CONFIG_I2C_ALI15X3 is not set
++# CONFIG_I2C_AMD756 is not set
++# CONFIG_I2C_AMD8111 is not set
++# CONFIG_I2C_I801 is not set
++# CONFIG_I2C_ISCH is not set
++# CONFIG_I2C_PIIX4 is not set
++# CONFIG_I2C_NFORCE2 is not set
++# CONFIG_I2C_SIS5595 is not set
++# CONFIG_I2C_SIS630 is not set
++# CONFIG_I2C_SIS96X is not set
++# CONFIG_I2C_VIA is not set
++# CONFIG_I2C_VIAPRO is not set
++
++#
++# I2C system bus drivers (mostly embedded / system-on-chip)
++#
++# CONFIG_I2C_DESIGNWARE_PLATFORM is not set
++# CONFIG_I2C_DESIGNWARE_PCI is not set
++# CONFIG_I2C_HIBVT is not set
++# CONFIG_I2C_HISI_V110 is not set
++# CONFIG_I2C_NOMADIK 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_RK3X 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_ROBOTFUZZ_OSIF is not set
++# CONFIG_I2C_TAOS_EVM is not set
++# CONFIG_I2C_TINY_USB is not set
++
++#
++# Other I2C/SMBus bus drivers
++#
++CONFIG_HI_I2C=y
++CONFIG_HI_I2C0_IO_BASE=0x120c0000
++CONFIG_HI_I2C0_IO_SIZE=0x1000
++CONFIG_HI_I2C1_IO_BASE=0x122e0000
++CONFIG_HI_I2C1_IO_SIZE=0x1000
++CONFIG_HI_I2C_RETRIES=0x1
++CONFIG_HI_I2C_TX_FIFO=0x8
++CONFIG_HI_I2C_RX_FIFO=0x8
++CONFIG_HI_I2C0_CLK_LIMIT=100000
++CONFIG_HI_I2C1_CLK_LIMIT=100000
++# 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_CADENCE is not set
++# CONFIG_SPI_FSL_SPI is not set
++CONFIG_SPI_PL022=y
++# CONFIG_SPI_PXA2XX is not set
++# CONFIG_SPI_PXA2XX_PCI is not set
++# CONFIG_SPI_ROCKCHIP 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=y
++# CONFIG_SPI_TLE62X0 is not set
++# CONFIG_SPMI is not set
++# CONFIG_HSI is not set
++
++#
++# PPS support
++#
++# CONFIG_PPS is not set
++
++#
++# PPS generators support
++#
++
++#
++# PTP clock support
++#
++# CONFIG_PTP_1588_CLOCK is not set
++
++#
++# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
++#
++CONFIG_PINCTRL=y
++
++#
++# Pin controllers
++#
++CONFIG_PINMUX=y
++CONFIG_PINCONF=y
++CONFIG_GENERIC_PINCONF=y
++# CONFIG_DEBUG_PINCTRL is not set
++CONFIG_PINCTRL_SINGLE=y
++CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
++CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
++# CONFIG_GPIOLIB is not set
++# CONFIG_W1 is not set
++CONFIG_POWER_SUPPLY=y
++# CONFIG_POWER_SUPPLY_DEBUG is not set
++# CONFIG_PDA_POWER is not set
++# CONFIG_TEST_POWER is not set
++# CONFIG_BATTERY_DS2780 is not set
++# CONFIG_BATTERY_DS2781 is not set
++# CONFIG_BATTERY_DS2782 is not set
++# CONFIG_BATTERY_SBS is not set
++# CONFIG_BATTERY_BQ27x00 is not set
++# CONFIG_BATTERY_MAX17040 is not set
++# CONFIG_BATTERY_MAX17042 is not set
++# CONFIG_CHARGER_MAX8903 is not set
++# CONFIG_CHARGER_LP8727 is not set
++# CONFIG_CHARGER_BQ2415X is not set
++# CONFIG_CHARGER_SMB347 is not set
++CONFIG_POWER_RESET=y
++# CONFIG_POWER_RESET_BRCMSTB is not set
++CONFIG_POWER_RESET_HISI=y
++# CONFIG_POWER_RESET_RESTART is not set
++# CONFIG_POWER_RESET_VERSATILE is not set
++# CONFIG_POWER_RESET_SYSCON is not set
++# CONFIG_POWER_AVS is not set
++# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
++# CONFIG_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=y
++# CONFIG_MFD_AS3711 is not set
++# CONFIG_MFD_AS3722 is not set
++# CONFIG_PMIC_ADP5520 is not set
++# CONFIG_MFD_BCM590XX is not set
++# CONFIG_MFD_AXP20X is not set
++# CONFIG_MFD_CROS_EC is not set
++# CONFIG_PMIC_DA903X is not set
++# CONFIG_MFD_DA9052_SPI is not set
++# CONFIG_MFD_DA9052_I2C is not set
++# CONFIG_MFD_DA9055 is not set
++# CONFIG_MFD_DA9063 is not set
++# CONFIG_MFD_MC13XXX_SPI is not set
++# CONFIG_MFD_MC13XXX_I2C is not set
++# CONFIG_MFD_HI6421_PMIC is not set
++CONFIG_MFD_HISI_FMC=y
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_LPC_ICH is not set
++# CONFIG_LPC_SCH is not set
++# CONFIG_INTEL_SOC_PMIC is not set
++# CONFIG_MFD_JANZ_CMODIO is not set
++# CONFIG_MFD_KEMPLD is not set
++# CONFIG_MFD_88PM800 is not set
++# CONFIG_MFD_88PM805 is not set
++# CONFIG_MFD_88PM860X is not set
++# CONFIG_MFD_MAX14577 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_MENF21BMC is not set
++# CONFIG_EZX_PCAP is not set
++# CONFIG_MFD_VIPERBOARD is not set
++# CONFIG_MFD_RETU is not set
++# CONFIG_MFD_PCF50633 is not set
++# CONFIG_MFD_PM8921_CORE is not set
++# CONFIG_MFD_RDC321X is not set
++# CONFIG_MFD_RTSX_PCI is not set
++# CONFIG_MFD_RTSX_USB is not set
++# CONFIG_MFD_RC5T583 is not set
++# CONFIG_MFD_RK808 is not set
++# CONFIG_MFD_RN5T618 is not set
++# CONFIG_MFD_SEC_CORE is not set
++# CONFIG_MFD_SI476X_CORE is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_MFD_SMSC is not set
++# CONFIG_ABX500_CORE is not set
++# CONFIG_MFD_STMPE is not set
++CONFIG_MFD_SYSCON=y
++# CONFIG_MFD_TI_AM335X_TSCADC is not set
++# CONFIG_MFD_LP3943 is not set
++# CONFIG_MFD_LP8788 is not set
++# CONFIG_MFD_PALMAS is not set
++# CONFIG_TPS6105X is not set
++# CONFIG_TPS6507X is not set
++# CONFIG_MFD_TPS65090 is not set
++# CONFIG_MFD_TPS65217 is not set
++# CONFIG_MFD_TPS65218 is not set
++# CONFIG_MFD_TPS6586X is not set
++# CONFIG_MFD_TPS80031 is not set
++# CONFIG_TWL4030_CORE is not set
++# CONFIG_TWL6040_CORE is not set
++# CONFIG_MFD_WL1273_CORE is not set
++# CONFIG_MFD_LM3533 is not set
++# CONFIG_MFD_TC3589X is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_MFD_T7L66XB is not set
++# CONFIG_MFD_TC6387XB is not set
++# CONFIG_MFD_TC6393XB is not set
++# CONFIG_MFD_VX855 is not set
++# CONFIG_MFD_ARIZONA_I2C is not set
++# CONFIG_MFD_ARIZONA_SPI is not set
++# CONFIG_MFD_WM8400 is not set
++# CONFIG_MFD_WM831X_I2C is not set
++# CONFIG_MFD_WM831X_SPI is not set
++# CONFIG_MFD_WM8350_I2C is not set
++# CONFIG_MFD_WM8994 is not set
++CONFIG_REGULATOR=y
++# CONFIG_REGULATOR_DEBUG is not set
++# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
++# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
++# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
++# CONFIG_REGULATOR_ACT8865 is not set
++# CONFIG_REGULATOR_AD5398 is not set
++# CONFIG_REGULATOR_ANATOP is not set
++# CONFIG_REGULATOR_DA9210 is not set
++# CONFIG_REGULATOR_DA9211 is not set
++# CONFIG_REGULATOR_FAN53555 is not set
++# CONFIG_REGULATOR_ISL9305 is not set
++# CONFIG_REGULATOR_ISL6271A is not set
++# CONFIG_REGULATOR_LP3971 is not set
++# CONFIG_REGULATOR_LP3972 is not set
++# CONFIG_REGULATOR_LP872X is not set
++# CONFIG_REGULATOR_LP8755 is not set
++# CONFIG_REGULATOR_LTC3589 is not set
++# CONFIG_REGULATOR_MAX1586 is not set
++# CONFIG_REGULATOR_MAX8649 is not set
++# CONFIG_REGULATOR_MAX8660 is not set
++# CONFIG_REGULATOR_MAX8952 is not set
++# CONFIG_REGULATOR_MAX8973 is not set
++# CONFIG_REGULATOR_PFUZE100 is not set
++# CONFIG_REGULATOR_TPS51632 is not set
++# CONFIG_REGULATOR_TPS62360 is not set
++# CONFIG_REGULATOR_TPS65023 is not set
++# CONFIG_REGULATOR_TPS6507X is not set
++# CONFIG_REGULATOR_TPS6524X is not set
++# CONFIG_MEDIA_SUPPORT is not set
++
++#
++# Graphics support
++#
++CONFIG_VGA_ARB=y
++CONFIG_VGA_ARB_MAX_GPUS=16
++# CONFIG_IMX_IPUV3_CORE is not set
++
++#
++# Direct Rendering Manager
++#
++# CONFIG_DRM is not set
++
++#
++# Frame buffer Devices
++#
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++CONFIG_FB_CMDLINE=y
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++# CONFIG_FB_CFB_FILLRECT is not set
++# CONFIG_FB_CFB_COPYAREA is not set
++# CONFIG_FB_CFB_IMAGEBLIT is not set
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# 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_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_CIRRUS is not set
++# CONFIG_FB_PM2 is not set
++# CONFIG_FB_ARMCLCD is not set
++# CONFIG_FB_CYBER2000 is not set
++# CONFIG_FB_ASILIANT is not set
++# CONFIG_FB_IMSTT is not set
++# CONFIG_FB_OPENCORES is not set
++# CONFIG_FB_S1D13XXX is not set
++# CONFIG_FB_NVIDIA is not set
++# CONFIG_FB_RIVA is not set
++# CONFIG_FB_I740 is not set
++# CONFIG_FB_MATROX is not set
++# CONFIG_FB_RADEON is not set
++# CONFIG_FB_ATY128 is not set
++# CONFIG_FB_ATY is not set
++# CONFIG_FB_S3 is not set
++# CONFIG_FB_SAVAGE is not set
++# CONFIG_FB_SIS is not set
++# CONFIG_FB_NEOMAGIC is not set
++# CONFIG_FB_KYRO is not set
++# CONFIG_FB_3DFX is not set
++# CONFIG_FB_VOODOO1 is not set
++# CONFIG_FB_VT8623 is not set
++# CONFIG_FB_TRIDENT is not set
++# CONFIG_FB_ARK is not set
++# CONFIG_FB_PM3 is not set
++# CONFIG_FB_CARMINE is not set
++# CONFIG_FB_SMSCUFX is not set
++# CONFIG_FB_UDL is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_MB862XX is not set
++# CONFIG_FB_BROADSHEET is not set
++# CONFIG_FB_AUO_K190X is not set
++# CONFIG_FB_SIMPLE is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++# CONFIG_VGASTATE is not set
++
++#
++# Console display driver support
++#
++CONFIG_DUMMY_CONSOLE=y
++# CONFIG_FRAMEBUFFER_CONSOLE is not set
++# CONFIG_LOGO is not set
++# CONFIG_SOUND is not set
++
++#
++# HID support
++#
++CONFIG_HID=y
++# CONFIG_HID_BATTERY_STRENGTH is not set
++# CONFIG_HIDRAW is not set
++# CONFIG_UHID is not set
++CONFIG_HID_GENERIC=y
++
++#
++# Special HID drivers
++#
++CONFIG_HID_A4TECH=y
++# CONFIG_HID_ACRUX is not set
++CONFIG_HID_APPLE=y
++# CONFIG_HID_APPLEIR is not set
++# CONFIG_HID_AUREAL is not set
++CONFIG_HID_BELKIN=y
++CONFIG_HID_CHERRY=y
++CONFIG_HID_CHICONY=y
++CONFIG_HID_CYPRESS=y
++# CONFIG_HID_DRAGONRISE is not set
++# CONFIG_HID_EMS_FF is not set
++# CONFIG_HID_ELECOM is not set
++# CONFIG_HID_ELO is not set
++CONFIG_HID_EZKEY=y
++# CONFIG_HID_HOLTEK is not set
++# CONFIG_HID_HUION 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_ICADE is not set
++# CONFIG_HID_TWINHAN is not set
++CONFIG_HID_KENSINGTON=y
++# CONFIG_HID_LCPOWER is not set
++# CONFIG_HID_LENOVO is not set
++CONFIG_HID_LOGITECH=y
++# CONFIG_HID_LOGITECH_HIDPP is not set
++# CONFIG_LOGITECH_FF is not set
++# CONFIG_LOGIRUMBLEPAD2_FF is not set
++# CONFIG_LOGIG940_FF is not set
++# CONFIG_LOGIWHEELS_FF is not set
++# CONFIG_HID_MAGICMOUSE is not set
++CONFIG_HID_MICROSOFT=y
++CONFIG_HID_MONTEREY=y
++# 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_PENMOUNT is not set
++# CONFIG_HID_PETALYNX is not set
++# CONFIG_HID_PICOLCD is not set
++# CONFIG_HID_PRIMAX is not set
++# CONFIG_HID_ROCCAT is not set
++# CONFIG_HID_SAITEK is not set
++# CONFIG_HID_SAMSUNG is not set
++# CONFIG_HID_SPEEDLINK is not set
++# CONFIG_HID_STEELSERIES is not set
++# CONFIG_HID_SUNPLUS is not set
++# CONFIG_HID_RMI 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_XINMO is not set
++# CONFIG_HID_ZEROPLUS is not set
++# CONFIG_HID_ZYDACRON is not set
++# CONFIG_HID_SENSOR_HUB is not set
++
++#
++# USB HID support
++#
++CONFIG_USB_HID=y
++# CONFIG_HID_PID is not set
++# CONFIG_USB_HIDDEV is not set
++
++#
++# I2C HID support
++#
++# CONFIG_I2C_HID is not set
++CONFIG_USB_OHCI_LITTLE_ENDIAN=y
++CONFIG_USB_SUPPORT=y
++CONFIG_USB_COMMON=y
++CONFIG_USB_ARCH_HAS_HCD=y
++CONFIG_USB=y
++# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
++
++#
++# Miscellaneous USB options
++#
++CONFIG_USB_DEFAULT_PERSIST=y
++# CONFIG_USB_DYNAMIC_MINORS is not set
++# CONFIG_USB_OTG_WHITELIST is not set
++# CONFIG_USB_OTG_FSM is not set
++# CONFIG_USB_MON is not set
++# CONFIG_USB_WUSB_CBAF is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_C67X00_HCD is not set
++CONFIG_USB_XHCI_HCD=y
++CONFIG_USB_XHCI_PCI=y
++CONFIG_USB_XHCI_PLATFORM=y
++CONFIG_USB_XHCI_HISILICON=y
++CONFIG_USB_EHCI_HCD=y
++# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
++CONFIG_USB_EHCI_TT_NEWSCHED=y
++CONFIG_USB_EHCI_PCI=y
++CONFIG_USB_EHCI_HCD_PLATFORM=y
++# 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_FUSBH200_HCD is not set
++# CONFIG_USB_FOTG210_HCD is not set
++# CONFIG_USB_MAX3421_HCD is not set
++CONFIG_USB_OHCI_HCD=y
++CONFIG_USB_OHCI_HCD_PCI=y
++CONFIG_USB_OHCI_HCD_PLATFORM=y
++# CONFIG_USB_UHCI_HCD is not set
++# CONFIG_USB_SL811_HCD is not set
++# CONFIG_USB_R8A66597_HCD is not set
++# CONFIG_USB_HCD_TEST_MODE is not set
++
++#
++# USB Device Class drivers
++#
++# CONFIG_USB_ACM is not set
++# CONFIG_USB_PRINTER is not set
++# CONFIG_USB_WDM is not set
++# CONFIG_USB_TMC is not set
++
++#
++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
++#
++
++#
++# also be needed; see USB_STORAGE Help for more info
++#
++CONFIG_USB_STORAGE=y
++# CONFIG_USB_STORAGE_DEBUG is not set
++# CONFIG_USB_STORAGE_REALTEK is not set
++# CONFIG_USB_STORAGE_DATAFAB is not set
++# CONFIG_USB_STORAGE_FREECOM is not set
++# CONFIG_USB_STORAGE_ISD200 is not set
++# CONFIG_USB_STORAGE_USBAT is not set
++# CONFIG_USB_STORAGE_SDDR09 is not set
++# CONFIG_USB_STORAGE_SDDR55 is not set
++# CONFIG_USB_STORAGE_JUMPSHOT is not set
++# CONFIG_USB_STORAGE_ALAUDA is not set
++# CONFIG_USB_STORAGE_ONETOUCH is not set
++# CONFIG_USB_STORAGE_KARMA is not set
++# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
++# CONFIG_USB_STORAGE_ENE_UB6250 is not set
++# CONFIG_USB_UAS is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++# CONFIG_USBIP_CORE is not set
++# CONFIG_USB_MUSB_HDRC is not set
++# CONFIG_USB_DWC3 is not set
++# CONFIG_USB_DWC2 is not set
++# CONFIG_USB_CHIPIDEA is not set
++
++#
++# USB port drivers
++#
++# CONFIG_USB_SERIAL is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
++# CONFIG_USB_SEVSEG is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
++# CONFIG_USB_APPLEDISPLAY is not set
++# CONFIG_USB_SISUSBVGA is not set
++# CONFIG_USB_LD is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
++# CONFIG_USB_IOWARRIOR is not set
++# CONFIG_USB_TEST is not set
++# CONFIG_USB_EHSET_TEST_FIXTURE is not set
++# CONFIG_USB_ISIGHTFW is not set
++# CONFIG_USB_YUREX is not set
++# CONFIG_USB_EZUSB_FX2 is not set
++# CONFIG_USB_HSIC_USB3503 is not set
++# CONFIG_USB_LINK_LAYER_TEST is not set
++
++#
++# USB Physical Layer drivers
++#
++# CONFIG_USB_PHY is not set
++# CONFIG_USB_OTG_WAKELOCK is not set
++# CONFIG_NOP_USB_XCEIV is not set
++# CONFIG_AM335X_PHY_USB is not set
++# CONFIG_USB_ISP1301 is not set
++# CONFIG_USB_ULPI is not set
++# CONFIG_USB_GADGET is not set
++# CONFIG_UWB is not set
++# CONFIG_MMC is not set
++# CONFIG_MEMSTICK is not set
++# CONFIG_NEW_LEDS is not set
++# CONFIG_SWITCH is not set
++# CONFIG_ACCESSIBILITY is not set
++# CONFIG_INFINIBAND is not set
++# CONFIG_EDAC is not set
++CONFIG_RTC_LIB=y
++# CONFIG_RTC_CLASS is not set
++# CONFIG_DMADEVICES is not set
++# CONFIG_AUXDISPLAY is not set
++# CONFIG_UIO is not set
++# CONFIG_VIRT_DRIVERS is not set
++
++#
++# Virtio drivers
++#
++# CONFIG_VIRTIO_PCI is not set
++# CONFIG_VIRTIO_MMIO is not set
++
++#
++# Microsoft Hyper-V guest support
++#
++# CONFIG_STAGING is not set
++
++#
++# SOC (System On Chip) specific Drivers
++#
++# CONFIG_SOC_TI is not set
++CONFIG_CLKDEV_LOOKUP=y
++CONFIG_HAVE_CLK_PREPARE=y
++CONFIG_COMMON_CLK=y
++
++#
++# Common Clock Framework
++#
++# CONFIG_COMMON_CLK_SI5351 is not set
++# CONFIG_COMMON_CLK_SI570 is not set
++# CONFIG_COMMON_CLK_PXA is not set
++# CONFIG_COMMON_CLK_QCOM is not set
++
++#
++# Hardware Spinlock drivers
++#
++
++#
++# Clock Source drivers
++#
++CONFIG_CLKSRC_OF=y
++CONFIG_CLKSRC_MMIO=y
++CONFIG_ARM_ARCH_TIMER=y
++CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y
++# CONFIG_ARM_ARCH_TIMER_VCT_ACCESS is not set
++# CONFIG_ATMEL_PIT is not set
++# CONFIG_SH_TIMER_CMT is not set
++# CONFIG_SH_TIMER_MTU2 is not set
++# CONFIG_SH_TIMER_TMU is not set
++# CONFIG_EM_TIMER_STI is not set
++# CONFIG_CLKSRC_VERSATILE is not set
++# CONFIG_MAILBOX is not set
++# CONFIG_IOMMU_SUPPORT is not set
++
++#
++# Remoteproc drivers
++#
++# CONFIG_STE_MODEM_RPROC is not set
++
++#
++# Rpmsg drivers
++#
++
++#
++# SOC (System On Chip) specific Drivers
++#
++# CONFIG_PM_DEVFREQ is not set
++# CONFIG_EXTCON is not set
++# CONFIG_MEMORY is not set
++# CONFIG_IIO is not set
++# CONFIG_VME_BUS is not set
++# CONFIG_PWM is not set
++CONFIG_IRQCHIP=y
++CONFIG_ARM_GIC=y
++# CONFIG_IPACK_BUS is not set
++CONFIG_ARCH_HAS_RESET_CONTROLLER=y
++CONFIG_RESET_CONTROLLER=y
++# CONFIG_FMC is not set
++
++#
++# PHY Subsystem
++#
++CONFIG_GENERIC_PHY=y
++# CONFIG_BCM_KONA_USB2_PHY is not set
++# CONFIG_PHY_HISI_INNO_USB2 is not set
++CONFIG_PHY_HI35x1D_INNO_USB2=y
++CONFIG_PHY_HI3531D_USB3=y
++CONFIG_HI_NANO_PHY_SATA=y
++CONFIG_HI_SATA_PORTS=4
++CONFIG_HI_SATA_MODE=1
++# CONFIG_POWERCAP is not set
++# CONFIG_MCB is not set
++CONFIG_RAS=y
++# CONFIG_THUNDERBOLT is not set
++CONFIG_HI_DMAC=y
++CONFIG_HI_DMAC_CHANNEL_NUM=4
++
++#
++# Hisilicon driver support
++#
++
++#
++# File systems
++#
++CONFIG_DCACHE_WORD_ACCESS=y
++# CONFIG_EXT2_FS is not set
++# CONFIG_EXT3_FS is not set
++CONFIG_EXT4_FS=y
++CONFIG_EXT4_USE_FOR_EXT23=y
++# CONFIG_EXT4_FS_POSIX_ACL is not set
++# CONFIG_EXT4_FS_SECURITY is not set
++# CONFIG_EXT4_DEBUG is not set
++CONFIG_JBD2=y
++# CONFIG_JBD2_DEBUG is not set
++CONFIG_FS_MBCACHE=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_BTRFS_FS is not set
++# CONFIG_NILFS2_FS is not set
++CONFIG_FS_POSIX_ACL=y
++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 is not set
++# CONFIG_FUSE_FS is not set
++# CONFIG_OVERLAY_FS is not set
++
++#
++# Caches
++#
++# CONFIG_FSCACHE is not set
++
++#
++# CD-ROM/DVD Filesystems
++#
++CONFIG_ISO9660_FS=y
++# CONFIG_JOLIET is not set
++# CONFIG_ZISOFS is not set
++CONFIG_UDF_FS=y
++CONFIG_UDF_NLS=y
++
++#
++# DOS/FAT/NT Filesystems
++#
++CONFIG_FAT_FS=y
++CONFIG_MSDOS_FS=y
++CONFIG_VFAT_FS=y
++CONFIG_FAT_DEFAULT_CODEPAGE=437
++CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
++# CONFIG_NTFS_FS is not set
++
++#
++# Pseudo filesystems
++#
++CONFIG_PROC_FS=y
++CONFIG_PROC_SYSCTL=y
++CONFIG_PROC_PAGE_MONITOR=y
++CONFIG_KERNFS=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=m
++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_YAFFS_FS=y
++CONFIG_YAFFS_YAFFS1=y
++# CONFIG_YAFFS_9BYTE_TAGS is not set
++# CONFIG_YAFFS_DOES_ECC is not set
++CONFIG_YAFFS_YAFFS2=y
++CONFIG_YAFFS_AUTO_YAFFS2=y
++# CONFIG_YAFFS_DISABLE_TAGS_ECC is not set
++# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
++# CONFIG_YAFFS_EMPTY_LOST_AND_FOUND is not set
++# CONFIG_YAFFS_DISABLE_BLOCK_REFRESHING is not set
++# CONFIG_YAFFS_DISABLE_BACKGROUND is not set
++# CONFIG_YAFFS_DISABLE_BAD_BLOCK_MARKING is not set
++CONFIG_YAFFS_XATTR=y
++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 is not set
++# CONFIG_JFFS2_FS_XATTR is not set
++# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
++CONFIG_JFFS2_ZLIB=y
++# CONFIG_JFFS2_LZO is not set
++CONFIG_JFFS2_RTIME=y
++# CONFIG_JFFS2_RUBIN 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 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 is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V2=y
++CONFIG_NFS_V3=y
++CONFIG_NFS_V3_ACL=y
++# CONFIG_NFS_V4 is not set
++# CONFIG_NFS_SWAP is not set
++# CONFIG_ROOT_NFS is not set
++# CONFIG_NFSD is not set
++CONFIG_GRACE_PERIOD=y
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_ACL_SUPPORT=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 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=y
++# CONFIG_DLM is not set
++
++#
++# Kernel hacking
++#
++
++#
++# printk and dmesg options
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4
++# CONFIG_BOOT_PRINTK_DELAY is not set
++
++#
++# Compile-time checks and compiler options
++#
++# CONFIG_DEBUG_INFO is not set
++# CONFIG_ENABLE_WARN_DEPRECATED is not set
++# CONFIG_ENABLE_MUST_CHECK is not set
++CONFIG_FRAME_WARN=1024
++# CONFIG_STRIP_ASM_SYMS is not set
++# CONFIG_READABLE_ASM is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++# CONFIG_DEBUG_FS is not set
++# CONFIG_HEADERS_CHECK is not set
++# CONFIG_DEBUG_SECTION_MISMATCH is not set
++# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
++# CONFIG_MAGIC_SYSRQ is not set
++CONFIG_DEBUG_KERNEL=y
++
++#
++# Memory Debugging
++#
++# CONFIG_DEBUG_PAGEALLOC is not set
++# 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_STACK_USAGE is not set
++# CONFIG_DEBUG_VM is not set
++CONFIG_DEBUG_MEMORY_INIT=y
++# CONFIG_DEBUG_PER_CPU_MAPS is not set
++# CONFIG_DEBUG_HIGHMEM is not set
++# CONFIG_DEBUG_SHIRQ is not set
++
++#
++# Debug Lockups and Hangs
++#
++# CONFIG_LOCKUP_DETECTOR is not set
++# CONFIG_DETECT_HUNG_TASK is not set
++# CONFIG_PANIC_ON_OOPS is not set
++CONFIG_PANIC_ON_OOPS_VALUE=0
++CONFIG_PANIC_TIMEOUT=0
++CONFIG_SCHED_DEBUG=y
++# CONFIG_SCHEDSTATS is not set
++# CONFIG_SCHED_STACK_END_CHECK is not set
++# CONFIG_TIMER_STATS is not set
++
++#
++# Lock Debugging (spinlocks, mutexes, etc...)
++#
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_LOCK_STAT is not set
++# CONFIG_DEBUG_ATOMIC_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_LOCK_TORTURE_TEST is not set
++CONFIG_STACKTRACE=y
++# CONFIG_DEBUG_KOBJECT is not set
++CONFIG_DEBUG_BUGVERBOSE=y
++# CONFIG_DEBUG_LIST is not set
++# CONFIG_DEBUG_PI_LIST is not set
++# CONFIG_DEBUG_SG is not set
++# CONFIG_DEBUG_NOTIFIERS is not set
++# CONFIG_DEBUG_CREDENTIALS is not set
++
++#
++# RCU Debugging
++#
++# CONFIG_SPARSE_RCU_POINTER is not set
++# CONFIG_TORTURE_TEST 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_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_NOTIFIER_ERROR_INJECTION is not set
++# CONFIG_FAULT_INJECTION 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 is not set
++
++#
++# Runtime Testing
++#
++# CONFIG_TEST_LIST_SORT is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_RBTREE_TEST is not set
++# CONFIG_INTERVAL_TREE_TEST is not set
++# CONFIG_PERCPU_TEST is not set
++# CONFIG_ATOMIC64_SELFTEST is not set
++# CONFIG_TEST_STRING_HELPERS is not set
++# CONFIG_TEST_KSTRTOX is not set
++# CONFIG_TEST_RHASHTABLE is not set
++# CONFIG_DMA_API_DEBUG is not set
++# CONFIG_TEST_LKM is not set
++# CONFIG_TEST_USER_COPY is not set
++# CONFIG_TEST_BPF is not set
++# CONFIG_TEST_FIRMWARE is not set
++# CONFIG_TEST_UDELAY is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_KGDB is not set
++# CONFIG_ARM_PTDUMP is not set
++CONFIG_STRICT_DEVMEM=y
++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_DEBUG_UART_PL01X is not set
++# CONFIG_DEBUG_UART_8250 is not set
++# CONFIG_DEBUG_UART_BCM63XX is not set
++CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"
++# CONFIG_OC_ETM is not set
++# CONFIG_PID_IN_CONTEXTIDR is not set
++# CONFIG_DEBUG_SET_MODULE_RONX is not set
++# CONFIG_CORESIGHT is not set
++
++#
++# 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_HASH=y
++CONFIG_CRYPTO_HASH2=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_PCRYPT is not set
++# CONFIG_CRYPTO_CRYPTD is not set
++# CONFIG_CRYPTO_MCRYPTD 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_CMAC is not set
++# CONFIG_CRYPTO_HMAC is not set
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_VMAC is not set
++
++#
++# Digest
++#
++CONFIG_CRYPTO_CRC32C=y
++# CONFIG_CRYPTO_CRC32 is not set
++# CONFIG_CRYPTO_CRCT10DIF 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_SHA1_ARM_NEON is not set
++# CONFIG_CRYPTO_SHA256 is not set
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_SHA512_ARM_NEON 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_AES_ARM_BS 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
++# CONFIG_CRYPTO_LZ4 is not set
++# CONFIG_CRYPTO_LZ4HC is not set
++
++#
++# Random Number Generation
++#
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++# CONFIG_CRYPTO_DRBG_MENU 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_HIFN_795X 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_NET_UTILS=y
++CONFIG_GENERIC_PCI_IOMAP=y
++CONFIG_GENERIC_IO=y
++CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
++# CONFIG_CRC_CCITT is not set
++CONFIG_CRC16=y
++# CONFIG_CRC_T10DIF is not set
++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 is not set
++# CONFIG_LIBCRC32C is not set
++# CONFIG_CRC8 is not set
++# CONFIG_AUDIT_ARCH_COMPAT_GENERIC is not set
++# CONFIG_RANDOM32_SELFTEST is not set
++CONFIG_ZLIB_INFLATE=y
++CONFIG_ZLIB_DEFLATE=y
++CONFIG_LZO_COMPRESS=y
++CONFIG_LZO_DECOMPRESS=y
++CONFIG_LZ4_DECOMPRESS=y
++CONFIG_XZ_DEC=y
++CONFIG_XZ_DEC_X86=y
++CONFIG_XZ_DEC_POWERPC=y
++CONFIG_XZ_DEC_IA64=y
++CONFIG_XZ_DEC_ARM=y
++CONFIG_XZ_DEC_ARMTHUMB=y
++CONFIG_XZ_DEC_SPARC=y
++CONFIG_XZ_DEC_BCJ=y
++# CONFIG_XZ_DEC_TEST is not set
++CONFIG_DECOMPRESS_GZIP=y
++CONFIG_DECOMPRESS_BZIP2=y
++CONFIG_DECOMPRESS_LZMA=y
++CONFIG_DECOMPRESS_XZ=y
++CONFIG_DECOMPRESS_LZO=y
++CONFIG_DECOMPRESS_LZ4=y
++CONFIG_GENERIC_ALLOCATOR=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT_MAP=y
++CONFIG_HAS_DMA=y
++CONFIG_CPU_RMAP=y
++CONFIG_DQL=y
++CONFIG_GLOB=y
++# CONFIG_GLOB_SELFTEST is not set
++CONFIG_NLATTR=y
++CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
++# CONFIG_AVERAGE is not set
++# CONFIG_CORDIC is not set
++# CONFIG_DDR is not set
++CONFIG_LIBFDT=y
++CONFIG_ARCH_HAS_SG_CHAIN=y
++# CONFIG_VIRTUALIZATION is not set
+diff --git a/arch/arm/configs/hi3531d_nand_slave_defconfig b/arch/arm/configs/hi3531d_nand_slave_defconfig
+new file mode 100644
+index 0000000..aa7138a
+--- /dev/null
++++ b/arch/arm/configs/hi3531d_nand_slave_defconfig
+@@ -0,0 +1,2429 @@
++#
++# Automatically generated file; DO NOT EDIT.
++# Linux/arm 3.18.20 Kernel Configuration
++#
++CONFIG_ARM=y
++CONFIG_ARM_HAS_SG_CHAIN=y
++CONFIG_MIGHT_HAVE_PCI=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=y
++CONFIG_HAVE_PROC_CPU=y
++CONFIG_STACKTRACE_SUPPORT=y
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
++CONFIG_RWSEM_XCHGADD_ALGORITHM=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_NEED_DMA_MAP_STATE=y
++CONFIG_ARCH_SUPPORTS_UPROBES=y
++CONFIG_VECTORS_BASE=0xffff0000
++CONFIG_ARM_PATCH_PHYS_VIRT=y
++CONFIG_GENERIC_BUG=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++CONFIG_IRQ_WORK=y
++CONFIG_BUILDTIME_EXTABLE_SORT=y
++
++#
++# General setup
++#
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_CROSS_COMPILE=""
++# CONFIG_COMPILE_TEST is not set
++CONFIG_LOCALVERSION=""
++# CONFIG_LOCALVERSION_AUTO is not set
++CONFIG_HAVE_KERNEL_GZIP=y
++CONFIG_HAVE_KERNEL_LZMA=y
++CONFIG_HAVE_KERNEL_XZ=y
++CONFIG_HAVE_KERNEL_LZO=y
++CONFIG_HAVE_KERNEL_LZ4=y
++CONFIG_KERNEL_GZIP=y
++# CONFIG_KERNEL_LZMA is not set
++# CONFIG_KERNEL_XZ is not set
++# CONFIG_KERNEL_LZO is not set
++# CONFIG_KERNEL_LZ4 is not set
++CONFIG_DEFAULT_HOSTNAME="(none)"
++# CONFIG_SWAP is not set
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++# CONFIG_POSIX_MQUEUE is not set
++CONFIG_CROSS_MEMORY_ATTACH=y
++# CONFIG_FHANDLE is not set
++CONFIG_USELIB=y
++# CONFIG_AUDIT is not set
++
++#
++# IRQ subsystem
++#
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_GENERIC_IRQ_SHOW=y
++CONFIG_HARDIRQS_SW_RESEND=y
++CONFIG_IRQ_DOMAIN=y
++CONFIG_HANDLE_DOMAIN_IRQ=y
++CONFIG_IRQ_FORCED_THREADING=y
++CONFIG_SPARSE_IRQ=y
++CONFIG_GENERIC_CLOCKEVENTS=y
++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
++CONFIG_ARCH_HAS_TICK_BROADCAST=y
++CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
++
++#
++# Timers subsystem
++#
++CONFIG_HZ_PERIODIC=y
++# CONFIG_NO_HZ_IDLE is not set
++# CONFIG_NO_HZ_FULL is not set
++# CONFIG_NO_HZ is not set
++# CONFIG_HIGH_RES_TIMERS is not set
++
++#
++# CPU/Task time and stats accounting
++#
++CONFIG_TICK_CPU_ACCOUNTING=y
++# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set
++# CONFIG_IRQ_TIME_ACCOUNTING is not set
++# CONFIG_BSD_PROCESS_ACCT is not set
++# CONFIG_TASKSTATS is not set
++
++#
++# RCU Subsystem
++#
++CONFIG_TREE_RCU=y
++# CONFIG_PREEMPT_RCU is not set
++# CONFIG_TASKS_RCU is not set
++CONFIG_RCU_STALL_COMMON=y
++# CONFIG_RCU_USER_QS is not set
++CONFIG_RCU_FANOUT=32
++CONFIG_RCU_FANOUT_LEAF=16
++# CONFIG_RCU_FANOUT_EXACT is not set
++# CONFIG_TREE_RCU_TRACE is not set
++# CONFIG_RCU_NOCB_CPU is not set
++# CONFIG_BUILD_BIN2C is not set
++# CONFIG_IKCONFIG is not set
++CONFIG_LOG_BUF_SHIFT=17
++CONFIG_LOG_CPU_MAX_BUF_SHIFT=12
++CONFIG_GENERIC_SCHED_CLOCK=y
++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_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_USER_NS is not set
++CONFIG_PID_NS=y
++CONFIG_NET_NS=y
++# 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=y
++CONFIG_RD_LZMA=y
++CONFIG_RD_XZ=y
++CONFIG_RD_LZO=y
++CONFIG_RD_LZ4=y
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++CONFIG_HAVE_UID16=y
++CONFIG_BPF=y
++# CONFIG_EXPERT is not set
++CONFIG_UID16=y
++# CONFIG_SGETMASK_SYSCALL is not set
++CONFIG_SYSFS_SYSCALL=y
++# CONFIG_SYSCTL_SYSCALL is not set
++CONFIG_KALLSYMS=y
++# CONFIG_KALLSYMS_ALL is not set
++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_BPF_SYSCALL is not set
++CONFIG_SHMEM=y
++CONFIG_AIO=y
++CONFIG_ADVISE_SYSCALLS=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 is not set
++# CONFIG_SLAB is not set
++CONFIG_SLUB=y
++CONFIG_SLUB_CPU_PARTIAL=y
++# CONFIG_PROFILING is not set
++CONFIG_HAVE_OPROFILE=y
++# CONFIG_KPROBES is not set
++# CONFIG_JUMP_LABEL is not set
++# CONFIG_UPROBES is not set
++# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
++CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
++CONFIG_ARCH_USE_BUILTIN_BSWAP=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_GENERIC_SMP_IDLE_THREAD=y
++CONFIG_GENERIC_IDLE_POLL_SETUP=y
++CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
++CONFIG_HAVE_CLK=y
++CONFIG_HAVE_DMA_API_DEBUG=y
++CONFIG_HAVE_PERF_REGS=y
++CONFIG_HAVE_PERF_USER_STACK_DUMP=y
++CONFIG_HAVE_ARCH_JUMP_LABEL=y
++CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
++CONFIG_HAVE_CC_STACKPROTECTOR=y
++# CONFIG_CC_STACKPROTECTOR is not set
++CONFIG_CC_STACKPROTECTOR_NONE=y
++# CONFIG_CC_STACKPROTECTOR_REGULAR is not set
++# CONFIG_CC_STACKPROTECTOR_STRONG is not set
++CONFIG_HAVE_CONTEXT_TRACKING=y
++CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
++CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
++CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
++CONFIG_MODULES_USE_ELF_REL=y
++CONFIG_CLONE_BACKWARDS=y
++CONFIG_OLD_SIGSUSPEND3=y
++CONFIG_OLD_SIGACTION=y
++
++#
++# GCOV-based kernel profiling
++#
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_SLABINFO=y
++CONFIG_RT_MUTEXES=y
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++# CONFIG_MODULE_FORCE_LOAD is not set
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++# CONFIG_MODULE_SIG is not set
++# CONFIG_MODULE_COMPRESS is not set
++CONFIG_STOP_MACHINE=y
++CONFIG_BLOCK=y
++CONFIG_LBDAF=y
++CONFIG_BLK_DEV_BSG=y
++# CONFIG_BLK_DEV_BSGLIB is not set
++# CONFIG_BLK_DEV_INTEGRITY is not set
++CONFIG_BLK_CMDLINE_PARSER=y
++
++#
++# Partition Types
++#
++CONFIG_PARTITION_ADVANCED=y
++# CONFIG_ACORN_PARTITION is not set
++# CONFIG_AIX_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=y
++# CONFIG_SYSV68_PARTITION is not set
++CONFIG_CMDLINE_PARTITION=y
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++CONFIG_DEFAULT_DEADLINE=y
++# CONFIG_DEFAULT_CFQ is not set
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="deadline"
++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_ARCH_SUPPORTS_ATOMIC_RMW=y
++CONFIG_MUTEX_SPIN_ON_OWNER=y
++CONFIG_RWSEM_SPIN_ON_OWNER=y
++CONFIG_FREEZER=y
++
++#
++# System Type
++#
++CONFIG_MMU=y
++CONFIG_ARCH_MULTIPLATFORM=y
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_AT91 is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_GEMINI is not set
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_IOP13XX is not set
++# CONFIG_ARCH_IOP32X is not set
++# CONFIG_ARCH_IOP33X is not set
++# CONFIG_ARCH_IXP4XX is not set
++# CONFIG_ARCH_DOVE is not set
++# CONFIG_ARCH_MV78XX0 is not set
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_MMP is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_W90X900 is not set
++# CONFIG_ARCH_LPC32XX is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_MSM is not set
++# CONFIG_ARCH_SHMOBILE_LEGACY 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_DAVINCI is not set
++# CONFIG_ARCH_OMAP1 is not set
++
++#
++# Multiple platform selection
++#
++
++#
++# CPU Core family selection
++#
++# CONFIG_ARCH_MULTI_V6 is not set
++CONFIG_ARCH_MULTI_V7=y
++CONFIG_ARCH_MULTI_V6_V7=y
++# CONFIG_ARCH_MULTI_CPU_AUTO is not set
++# CONFIG_ARCH_VIRT is not set
++# CONFIG_ARCH_MVEBU is not set
++# CONFIG_ARCH_BCM is not set
++# CONFIG_ARCH_BERLIN is not set
++# CONFIG_ARCH_HIGHBANK is not set
++CONFIG_ARCH_HISI=y
++
++#
++# Hisilicon platform type
++#
++# CONFIG_ARCH_HI3xxx is not set
++# CONFIG_ARCH_HIP04 is not set
++# CONFIG_ARCH_HIX5HD2 is not set
++# CONFIG_ARCH_HI3519 is not set
++# CONFIG_ARCH_HI3519V101 is not set
++# CONFIG_ARCH_HI3516AV200 is not set
++# CONFIG_ARCH_HI3559 is not set
++# CONFIG_ARCH_HI3556 is not set
++# CONFIG_ARCH_HI3536C is not set
++CONFIG_ARCH_HI3531D=y
++# CONFIG_ARCH_HI3521D is not set
++# CONFIG_ARCH_KEYSTONE is not set
++# CONFIG_ARCH_MESON is not set
++# CONFIG_ARCH_MXC is not set
++# CONFIG_ARCH_MEDIATEK is not set
++
++#
++# TI OMAP/AM/DM/DRA Family
++#
++# CONFIG_ARCH_OMAP3 is not set
++# CONFIG_ARCH_OMAP4 is not set
++# CONFIG_SOC_OMAP5 is not set
++# CONFIG_SOC_AM33XX is not set
++# CONFIG_SOC_AM43XX is not set
++# CONFIG_SOC_DRA7XX is not set
++# CONFIG_ARCH_QCOM is not set
++# CONFIG_ARCH_ROCKCHIP is not set
++# CONFIG_ARCH_SOCFPGA is not set
++# CONFIG_PLAT_SPEAR is not set
++# CONFIG_ARCH_STI is not set
++# CONFIG_ARCH_S5PV210 is not set
++# CONFIG_ARCH_EXYNOS is not set
++# CONFIG_ARCH_SHMOBILE_MULTI is not set
++# CONFIG_ARCH_SUNXI is not set
++# CONFIG_ARCH_SIRF is not set
++# CONFIG_ARCH_TEGRA is not set
++# CONFIG_ARCH_U8500 is not set
++# CONFIG_ARCH_VEXPRESS is not set
++# CONFIG_ARCH_WM8850 is not set
++# CONFIG_ARCH_ZYNQ is not set
++CONFIG_ARM_TIMER_SP804=y
++
++#
++# Processor Type
++#
++CONFIG_CPU_V7=y
++CONFIG_CPU_32v6K=y
++CONFIG_CPU_32v7=y
++CONFIG_CPU_ABRT_EV7=y
++CONFIG_CPU_PABRT_V7=y
++CONFIG_CPU_CACHE_V7=y
++CONFIG_CPU_CACHE_VIPT=y
++CONFIG_CPU_COPY_V6=y
++CONFIG_CPU_TLB_V7=y
++CONFIG_CPU_HAS_ASID=y
++CONFIG_CPU_CP15=y
++CONFIG_CPU_CP15_MMU=y
++
++#
++# Processor Features
++#
++# CONFIG_ARM_LPAE is not set
++# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
++CONFIG_ARM_THUMB=y
++# CONFIG_ARM_THUMBEE is not set
++CONFIG_ARM_VIRT_EXT=y
++CONFIG_SWP_EMULATE=y
++# CONFIG_CPU_ICACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_DISABLE is not set
++# CONFIG_CPU_BPREDICT_DISABLE is not set
++CONFIG_KUSER_HELPERS=y
++CONFIG_OUTER_CACHE=y
++CONFIG_OUTER_CACHE_SYNC=y
++CONFIG_MIGHT_HAVE_CACHE_L2X0=y
++CONFIG_CACHE_L2X0=y
++CONFIG_CACHE_PL310=y
++# CONFIG_PL310_ERRATA_588369 is not set
++# CONFIG_PL310_ERRATA_727915 is not set
++# CONFIG_PL310_ERRATA_753970 is not set
++# CONFIG_PL310_ERRATA_769419 is not set
++CONFIG_ARM_L1_CACHE_SHIFT_6=y
++CONFIG_ARM_L1_CACHE_SHIFT=6
++CONFIG_ARM_DMA_MEM_BUFFERABLE=y
++CONFIG_MULTI_IRQ_HANDLER=y
++# CONFIG_ARM_ERRATA_430973 is not set
++# CONFIG_ARM_ERRATA_643719 is not set
++# CONFIG_ARM_ERRATA_720789 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_ARM_ERRATA_775420 is not set
++# CONFIG_ARM_ERRATA_798181 is not set
++# CONFIG_ARM_ERRATA_773022 is not set
++
++#
++# Bus support
++#
++CONFIG_ARM_AMBA=y
++# CONFIG_PCI is not set
++# 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_DISABLE_CPU_SCHED_DOMAIN_BALANCE is not set
++CONFIG_HAVE_ARM_SCU=y
++CONFIG_HAVE_ARM_ARCH_TIMER=y
++# CONFIG_MCPM is not set
++# CONFIG_BIG_LITTLE is not set
++CONFIG_VMSPLIT_3G=y
++# CONFIG_VMSPLIT_2G is not set
++# CONFIG_VMSPLIT_1G is not set
++CONFIG_PAGE_OFFSET=0xC0000000
++CONFIG_NR_CPUS=4
++CONFIG_HOTPLUG_CPU=y
++# CONFIG_ARM_PSCI is not set
++CONFIG_ARCH_NR_GPIO=0
++CONFIG_PREEMPT_NONE=y
++# CONFIG_PREEMPT_VOLUNTARY is not set
++# CONFIG_PREEMPT is not set
++CONFIG_HZ_FIXED=0
++CONFIG_HZ_100=y
++# CONFIG_HZ_200 is not set
++# CONFIG_HZ_250 is not set
++# CONFIG_HZ_300 is not set
++# CONFIG_HZ_500 is not set
++# CONFIG_HZ_1000 is not set
++CONFIG_HZ=100
++# CONFIG_SCHED_HRTICK is not set
++# CONFIG_THUMB2_KERNEL is not set
++CONFIG_AEABI=y
++CONFIG_OABI_COMPAT=y
++# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
++# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
++CONFIG_HAVE_ARCH_PFN_VALID=y
++CONFIG_HIGHMEM=y
++# CONFIG_HIGHPTE is not set
++CONFIG_ARCH_WANT_GENERAL_HUGETLB=y
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_HAVE_MEMBLOCK=y
++CONFIG_NO_BOOTMEM=y
++# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=4
++CONFIG_COMPACTION=y
++CONFIG_MIGRATION=y
++# CONFIG_PHYS_ADDR_T_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_BOUNCE=y
++# CONFIG_KSM is not set
++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
++# CONFIG_CLEANCACHE is not set
++# CONFIG_CMA is not set
++# CONFIG_ZPOOL is not set
++# CONFIG_ZBUD is not set
++# CONFIG_ZSMALLOC 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_SWIOTLB=y
++CONFIG_IOMMU_HELPER=y
++# CONFIG_XEN is not set
++# CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART is not set
++
++#
++# Boot options
++#
++CONFIG_USE_OF=y
++CONFIG_ATAGS=y
++# CONFIG_DEPRECATED_PARAM_STRUCT is not set
++# CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE is not set
++CONFIG_ZBOOT_ROM_TEXT=0
++CONFIG_ZBOOT_ROM_BSS=0
++CONFIG_ARM_APPENDED_DTB=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_KEXEC is not set
++# CONFIG_CRASH_DUMP is not set
++CONFIG_AUTO_ZRELADDR=y
++
++#
++# CPU Power Management
++#
++
++#
++# CPU Frequency scaling
++#
++CONFIG_CPU_FREQ=y
++CONFIG_CPU_FREQ_STAT=y
++# CONFIG_CPU_FREQ_STAT_DETAILS is not set
++CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
++# CONFIG_CPU_FREQ_DEFAULT_GOV_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_DEFAULT_GOV_INTERACTIVE is not set
++CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
++# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
++# CONFIG_CPU_FREQ_GOV_USERSPACE is not set
++# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
++# CONFIG_CPU_FREQ_GOV_INTERACTIVE is not set
++# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
++CONFIG_CPUFREQ_DT=y
++
++#
++# ARM CPU frequency scaling drivers
++#
++# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set
++
++#
++# CPU Idle
++#
++# CONFIG_CPU_IDLE is not set
++# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++# CONFIG_FPE_NWFPE is not set
++# CONFIG_FPE_FASTFPE is not set
++CONFIG_VFP=y
++CONFIG_VFPv3=y
++CONFIG_NEON=y
++CONFIG_KERNEL_MODE_NEON=y
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
++CONFIG_BINFMT_SCRIPT=y
++# CONFIG_HAVE_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
++CONFIG_COREDUMP=y
++
++#
++# Power management options
++#
++CONFIG_SUSPEND=y
++CONFIG_SUSPEND_FREEZER=y
++CONFIG_WAKELOCK=y
++# CONFIG_HISI_SNAPSHOT_BOOT is not set
++CONFIG_PM_SLEEP=y
++CONFIG_PM_SLEEP_SMP=y
++# CONFIG_PM_AUTOSLEEP is not set
++# CONFIG_PM_WAKELOCKS is not set
++# CONFIG_PM_RUNTIME is not set
++CONFIG_PM=y
++# CONFIG_PM_DEBUG is not set
++# CONFIG_APM_EMULATION is not set
++CONFIG_PM_OPP=y
++CONFIG_PM_CLK=y
++# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set
++CONFIG_CPU_PM=y
++# CONFIG_SUSPEND_TIME is not set
++CONFIG_ARCH_SUSPEND_POSSIBLE=y
++CONFIG_ARM_CPU_SUSPEND=y
++CONFIG_ARCH_HIBERNATION_POSSIBLE=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=y
++# 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_NET_IP_TUNNEL=m
++# CONFIG_IP_MROUTE is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_NET_UDP_TUNNEL is not set
++# CONFIG_NET_FOU is not set
++# CONFIG_GENEVE 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 is not set
++# CONFIG_INET_XFRM_MODE_TUNNEL is not set
++# CONFIG_INET_XFRM_MODE_BEET is not set
++CONFIG_INET_LRO=y
++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=y
++# 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_VTI 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_ANDROID_PARANOID_NETWORK is not set
++CONFIG_NET_ACTIVITY_STATS=y
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NET_PTP_CLASSIFY 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_NF_TABLES is not set
++# CONFIG_NETFILTER_XTABLES is not set
++# CONFIG_IP_SET is not set
++# CONFIG_IP_VS is not set
++
++#
++# IP: Netfilter Configuration
++#
++# CONFIG_NF_DEFRAG_IPV4 is not set
++# CONFIG_NF_LOG_ARP is not set
++# CONFIG_NF_LOG_IPV4 is not set
++# CONFIG_NF_REJECT_IPV4 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_NF_REJECT_IPV6 is not set
++# CONFIG_NF_LOG_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_HAVE_NET_DSA=y
++# 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_PHONET is not set
++# CONFIG_6LOWPAN 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_VSOCKETS is not set
++# CONFIG_NETLINK_MMAP is not set
++# CONFIG_NETLINK_DIAG is not set
++# CONFIG_NET_MPLS_GSO is not set
++# CONFIG_HSR is not set
++CONFIG_RPS=y
++CONFIG_RFS_ACCEL=y
++CONFIG_XPS=y
++# CONFIG_CGROUP_NET_PRIO is not set
++# CONFIG_CGROUP_NET_CLASSID is not set
++CONFIG_NET_RX_BUSY_POLL=y
++CONFIG_BQL=y
++# CONFIG_BPF_JIT is not set
++CONFIG_NET_FLOW_LIMIT=y
++
++#
++# 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 is not set
++# 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 is not set
++CONFIG_DEVTMPFS=y
++# CONFIG_DEVTMPFS_MOUNT is not set
++CONFIG_STANDALONE=y
++# CONFIG_PREVENT_FIRMWARE_BUILD is not set
++CONFIG_FW_LOADER=y
++CONFIG_FIRMWARE_IN_KERNEL=y
++CONFIG_EXTRA_FIRMWARE=""
++# CONFIG_FW_LOADER_USER_HELPER_FALLBACK is not set
++CONFIG_ALLOW_DEV_COREDUMP=y
++# 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_HAVE_CPU_AUTOPROBE is not set
++CONFIG_REGMAP=y
++CONFIG_REGMAP_MMIO=y
++# CONFIG_DMA_SHARED_BUFFER is not set
++
++#
++# Bus devices
++#
++# CONFIG_BRCMSTB_GISB_ARB is not set
++# CONFIG_ARM_CCI is not set
++# CONFIG_VEXPRESS_CONFIG 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=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_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_HIFMC 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_SST25L is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_PHRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++# CONFIG_MTD_BLOCK2MTD is not set
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOCG3 is not set
++CONFIG_MTD_NAND_IDS=y
++CONFIG_MTD_NAND_ECC=y
++# CONFIG_MTD_NAND_ECC_SMC is not set
++CONFIG_MTD_NAND=y
++# CONFIG_MTD_NAND_ECC_BCH is not set
++# CONFIG_MTD_SM_COMMON is not set
++# CONFIG_MTD_NAND_DENALI is not set
++# CONFIG_MTD_NAND_OMAP_BCH_BUILD is not set
++# CONFIG_MTD_NAND_DISKONCHIP is not set
++# CONFIG_MTD_NAND_DOCG4 is not set
++# CONFIG_MTD_NAND_NANDSIM is not set
++# CONFIG_MTD_NAND_PLATFORM is not set
++# CONFIG_HISI_NAND_FS_MAY_NO_YAFFS2 is not set
++# CONFIG_HISI_NAND_ECC_STATUS_REPORT is not set
++CONFIG_MTD_NAND_HINFC610=y
++# CONFIG_MTD_PARTITION_FROM_DTS is not set
++CONFIG_HINFC610_MAX_CHIP=1
++# CONFIG_HINFC610_DBG_NAND_DEBUG is not set
++CONFIG_HINFC610_AUTO_PAGESIZE_ECC=y
++# CONFIG_HINFC610_PAGESIZE_AUTO_ECC_NONE is not set
++# CONFIG_MTD_ONENAND is not set
++
++#
++# LPDDR & LPDDR2 PCM memory drivers
++#
++# CONFIG_MTD_LPDDR is not set
++# CONFIG_MTD_LPDDR2_NVM is not set
++# CONFIG_MTD_SPI_NOR is not set
++# CONFIG_MTD_UBI is not set
++CONFIG_DTC=y
++CONFIG_OF=y
++
++#
++# Device Tree and Open Firmware support
++#
++# 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_NET=y
++CONFIG_OF_MDIO=y
++CONFIG_OF_MTD=y
++CONFIG_OF_RESERVED_MEM=y
++CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
++# CONFIG_PARPORT is not set
++CONFIG_BLK_DEV=y
++# CONFIG_BLK_DEV_NULL_BLK is not set
++# CONFIG_BLK_DEV_COW_COMMON is not set
++# CONFIG_BLK_DEV_LOOP 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=65536
++# CONFIG_BLK_DEV_XIP is not set
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH 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_DUMMY_IRQ 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_UID_STAT is not set
++# CONFIG_BMP085_I2C is not set
++# CONFIG_BMP085_SPI is not set
++# CONFIG_USB_SWITCH_FSA9480 is not set
++# CONFIG_LATTICE_ECP3_CONFIG is not set
++# CONFIG_SRAM is not set
++# CONFIG_C2PORT is not set
++
++#
++# EEPROM support
++#
++# CONFIG_EEPROM_AT24 is not set
++# CONFIG_EEPROM_AT25 is not set
++# CONFIG_EEPROM_LEGACY is not set
++# CONFIG_EEPROM_MAX6875 is not set
++# CONFIG_EEPROM_93CX6 is not set
++# CONFIG_EEPROM_93XX46 is not set
++
++#
++# Texas Instruments shared transport line discipline
++#
++# 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
++
++#
++# Intel MIC Bus Driver
++#
++
++#
++# Intel MIC Host Driver
++#
++
++#
++# Intel MIC Card Driver
++#
++# CONFIG_ECHO is not set
++# CONFIG_CXL_BASE is not set
++
++#
++# hisi 'himm/himd.l/himc'support
++#
++# CONFIG_HISI_REG 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_NETLINK is not set
++# CONFIG_SCSI_MQ_DEFAULT is not set
++CONFIG_SCSI_PROC_FS=y
++
++#
++# SCSI support type (disk, tape, CD-ROM)
++#
++CONFIG_BLK_DEV_SD=y
++# CONFIG_CHR_DEV_ST is not set
++# CONFIG_CHR_DEV_OSST is not set
++CONFIG_BLK_DEV_SR=y
++# CONFIG_BLK_DEV_SR_VENDOR is not set
++# CONFIG_CHR_DEV_SG is not set
++# CONFIG_CHR_DEV_SCH is not set
++# CONFIG_SCSI_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 is not set
++# CONFIG_SCSI_DH is not set
++# CONFIG_SCSI_OSD_INITIATOR is not set
++CONFIG_HI_SATA=y
++CONFIG_HI_SATA_IOBASE=0x11010000
++CONFIG_HI_SATA_FBS=1
++CONFIG_HI_SATA_NCQ=1
++CONFIG_ATA=y
++# CONFIG_ATA_NONSTANDARD is not set
++CONFIG_ATA_VERBOSE_ERROR=y
++CONFIG_SATA_PMP=y
++
++#
++# Controllers with non-SFF native interface
++#
++CONFIG_SATA_AHCI_PLATFORM=y
++# CONFIG_ATA_SFF is not set
++# CONFIG_MD 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_NET_TEAM is not set
++# CONFIG_MACVLAN is not set
++# CONFIG_VXLAN is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_TUN is not set
++# CONFIG_VETH is not set
++# CONFIG_NLMON is not set
++
++#
++# 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_NET_DSA_MV88E6171 is not set
++# CONFIG_NET_DSA_BCM_SF2 is not set
++CONFIG_ETHERNET=y
++# CONFIG_ALTERA_TSE is not set
++# CONFIG_NET_XGENE is not set
++# CONFIG_NET_VENDOR_ARC is not set
++# CONFIG_NET_CADENCE is not set
++# CONFIG_NET_VENDOR_BROADCOM is not set
++# CONFIG_NET_VENDOR_CIRRUS is not set
++# CONFIG_DM9000 is not set
++# CONFIG_DNET is not set
++# CONFIG_NET_VENDOR_FARADAY is not set
++CONFIG_NET_VENDOR_HISILICON=y
++# CONFIG_HIX5HD2_GMAC is not set
++# CONFIG_HISI_FEMAC is not set
++CONFIG_HIETH_GMAC=y
++CONFIG_HIGMAC_DESC_4WORD=y
++CONFIG_HIGMAC_RXCSUM=y
++CONFIG_RX_FLOW_CTRL_SUPPORT=y
++CONFIG_TX_FLOW_CTRL_SUPPORT=y
++CONFIG_TX_FLOW_CTRL_PAUSE_TIME=0xFFFF
++CONFIG_TX_FLOW_CTRL_PAUSE_INTERVAL=0xFFFF
++CONFIG_TX_FLOW_CTRL_ACTIVE_THRESHOLD=16
++CONFIG_TX_FLOW_CTRL_DEACTIVE_THRESHOLD=32
++# CONFIG_HIETH_SWITCH_FABRIC is not set
++# CONFIG_NET_VENDOR_INTEL is not set
++# CONFIG_NET_VENDOR_MARVELL is not set
++# CONFIG_NET_VENDOR_MICREL is not set
++# CONFIG_NET_VENDOR_MICROCHIP is not set
++# CONFIG_NET_VENDOR_NATSEMI is not set
++# CONFIG_ETHOC is not set
++# CONFIG_NET_VENDOR_QUALCOMM is not set
++# CONFIG_NET_VENDOR_SAMSUNG is not set
++# CONFIG_NET_VENDOR_SEEQ is not set
++# CONFIG_NET_VENDOR_SMSC is not set
++# CONFIG_NET_VENDOR_STMICRO is not set
++# CONFIG_NET_VENDOR_VIA is not set
++# CONFIG_NET_VENDOR_WIZNET is not set
++CONFIG_PHYLIB=y
++
++#
++# MII PHY device drivers
++#
++# CONFIG_AT803X_PHY is not set
++# CONFIG_AMD_PHY is not set
++# CONFIG_AMD_XGBE_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 is not set
++# CONFIG_BROADCOM_PHY is not set
++# CONFIG_BCM7XXX_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_MMIOREG is not set
++# CONFIG_MDIO_BCM_UNIMAC is not set
++# CONFIG_MDIO_HISI_FEMAC is not set
++CONFIG_MDIO_HISI_GEMAC=y
++# CONFIG_MICREL_KS8995MA is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++CONFIG_USB_NET_DRIVERS=y
++# 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_RTL8152 is not set
++# CONFIG_USB_USBNET is not set
++# CONFIG_USB_IPHETH is not set
++# CONFIG_WLAN is not set
++
++#
++# Enable WiMAX (Networking options) to see the WiMAX drivers
++#
++# CONFIG_WAN is not set
++# CONFIG_ISDN is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
++# CONFIG_INPUT_POLLDEV is not set
++# CONFIG_INPUT_SPARSEKMAP is not set
++# CONFIG_INPUT_MATRIXKMAP is not set
++
++#
++# Userland interfaces
++#
++CONFIG_INPUT_MOUSEDEV=y
++CONFIG_INPUT_MOUSEDEV_PSAUX=y
++CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
++CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
++CONFIG_INPUT_JOYDEV=y
++CONFIG_INPUT_EVDEV=y
++# CONFIG_INPUT_EVBUG is not set
++# CONFIG_INPUT_KEYRESET is not set
++# CONFIG_INPUT_KEYCOMBO 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_TCA6416 is not set
++# CONFIG_KEYBOARD_TCA8418 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 is not set
++# CONFIG_KEYBOARD_CAP1106 is not set
++CONFIG_INPUT_MOUSE=y
++CONFIG_MOUSE_PS2=y
++CONFIG_MOUSE_PS2_ALPS=y
++CONFIG_MOUSE_PS2_LOGIPS2PP=y
++CONFIG_MOUSE_PS2_SYNAPTICS=y
++CONFIG_MOUSE_PS2_CYPRESS=y
++CONFIG_MOUSE_PS2_TRACKPOINT=y
++# CONFIG_MOUSE_PS2_ELANTECH is not set
++# CONFIG_MOUSE_PS2_SENTELIC is not set
++# CONFIG_MOUSE_PS2_TOUCHKIT is not set
++# CONFIG_MOUSE_SERIAL is not set
++# CONFIG_MOUSE_APPLETOUCH is not set
++# CONFIG_MOUSE_BCM5974 is not set
++# CONFIG_MOUSE_CYAPA is not set
++# CONFIG_MOUSE_VSXXXAA is not set
++# CONFIG_MOUSE_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 is not set
++# CONFIG_INPUT_MISC is not set
++
++#
++# Hardware I/O ports
++#
++CONFIG_SERIO=y
++CONFIG_SERIO_SERPORT=y
++# CONFIG_SERIO_AMBAKMI is not set
++CONFIG_SERIO_LIBPS2=y
++# CONFIG_SERIO_RAW is not set
++# CONFIG_SERIO_ALTERA_PS2 is not set
++# CONFIG_SERIO_PS2MULT is not set
++# CONFIG_SERIO_ARC_PS2 is not set
++# CONFIG_SERIO_APBPS2 is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++CONFIG_TTY=y
++CONFIG_VT=y
++CONFIG_CONSOLE_TRANSLATIONS=y
++CONFIG_VT_CONSOLE=y
++CONFIG_VT_CONSOLE_SLEEP=y
++CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
++CONFIG_UNIX98_PTYS=y
++# CONFIG_DEVPTS_MULTIPLE_INSTANCES 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_DEVMEM=y
++CONFIG_DEVKMEM=y
++
++#
++# Serial drivers
++#
++CONFIG_SERIAL_EARLYCON=y
++# CONFIG_SERIAL_8250 is not set
++
++#
++# Non-8250 serial port support
++#
++# CONFIG_SERIAL_AMBA_PL010 is not set
++CONFIG_SERIAL_AMBA_PL011=y
++CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
++# CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST is not set
++# 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_SC16IS7XX is not set
++# CONFIG_SERIAL_ALTERA_JTAGUART is not set
++# CONFIG_SERIAL_ALTERA_UART is not set
++# CONFIG_SERIAL_XILINX_PS_UART is not set
++# CONFIG_SERIAL_ARC is not set
++# CONFIG_SERIAL_FSL_LPUART is not set
++# CONFIG_SERIAL_ST_ASC is not set
++# CONFIG_HVC_DCC is not set
++# CONFIG_IPMI_HANDLER is not set
++# CONFIG_HW_RANDOM is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++# CONFIG_DCC_TTY is not set
++# CONFIG_XILLYBUS is not set
++
++#
++# I2C support
++#
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++CONFIG_I2C_COMPAT=y
++CONFIG_I2C_CHARDEV=y
++CONFIG_I2C_MUX=y
++
++#
++# Multiplexer I2C Chip support
++#
++# CONFIG_I2C_MUX_PCA9541 is not set
++# CONFIG_I2C_MUX_PINCTRL is not set
++CONFIG_I2C_HELPER_AUTO=y
++
++#
++# I2C Hardware Bus support
++#
++
++#
++# I2C system bus drivers (mostly embedded / system-on-chip)
++#
++# CONFIG_I2C_DESIGNWARE_PLATFORM is not set
++# CONFIG_I2C_HIBVT is not set
++# CONFIG_I2C_HISI_V110 is not set
++# CONFIG_I2C_NOMADIK 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_RK3X 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_ROBOTFUZZ_OSIF is not set
++# CONFIG_I2C_TAOS_EVM is not set
++# CONFIG_I2C_TINY_USB is not set
++
++#
++# Other I2C/SMBus bus drivers
++#
++CONFIG_HI_I2C=y
++CONFIG_HI_I2C0_IO_BASE=0x120c0000
++CONFIG_HI_I2C0_IO_SIZE=0x1000
++CONFIG_HI_I2C1_IO_BASE=0x122e0000
++CONFIG_HI_I2C1_IO_SIZE=0x1000
++CONFIG_HI_I2C_RETRIES=0x1
++CONFIG_HI_I2C_TX_FIFO=0x8
++CONFIG_HI_I2C_RX_FIFO=0x8
++CONFIG_HI_I2C0_CLK_LIMIT=100000
++CONFIG_HI_I2C1_CLK_LIMIT=100000
++# 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_CADENCE is not set
++# CONFIG_SPI_FSL_SPI is not set
++CONFIG_SPI_PL022=y
++# CONFIG_SPI_PXA2XX_PCI is not set
++# CONFIG_SPI_ROCKCHIP 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=y
++# CONFIG_SPI_TLE62X0 is not set
++# CONFIG_SPMI is not set
++# CONFIG_HSI is not set
++
++#
++# PPS support
++#
++# CONFIG_PPS is not set
++
++#
++# PPS generators support
++#
++
++#
++# PTP clock support
++#
++# CONFIG_PTP_1588_CLOCK is not set
++
++#
++# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
++#
++CONFIG_PINCTRL=y
++
++#
++# Pin controllers
++#
++CONFIG_PINMUX=y
++CONFIG_PINCONF=y
++CONFIG_GENERIC_PINCONF=y
++# CONFIG_DEBUG_PINCTRL is not set
++CONFIG_PINCTRL_SINGLE=y
++CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
++CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
++# CONFIG_GPIOLIB is not set
++# CONFIG_W1 is not set
++CONFIG_POWER_SUPPLY=y
++# CONFIG_POWER_SUPPLY_DEBUG is not set
++# CONFIG_PDA_POWER is not set
++# CONFIG_TEST_POWER is not set
++# CONFIG_BATTERY_DS2780 is not set
++# CONFIG_BATTERY_DS2781 is not set
++# CONFIG_BATTERY_DS2782 is not set
++# CONFIG_BATTERY_SBS is not set
++# CONFIG_BATTERY_BQ27x00 is not set
++# CONFIG_BATTERY_MAX17040 is not set
++# CONFIG_BATTERY_MAX17042 is not set
++# CONFIG_CHARGER_MAX8903 is not set
++# CONFIG_CHARGER_LP8727 is not set
++# CONFIG_CHARGER_BQ2415X is not set
++# CONFIG_CHARGER_SMB347 is not set
++CONFIG_POWER_RESET=y
++# CONFIG_POWER_RESET_BRCMSTB is not set
++CONFIG_POWER_RESET_HISI=y
++# CONFIG_POWER_RESET_RESTART is not set
++# CONFIG_POWER_RESET_VERSATILE is not set
++# CONFIG_POWER_RESET_SYSCON is not set
++# CONFIG_POWER_AVS is not set
++# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
++# CONFIG_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=y
++# CONFIG_MFD_AS3711 is not set
++# CONFIG_MFD_AS3722 is not set
++# CONFIG_PMIC_ADP5520 is not set
++# CONFIG_MFD_BCM590XX is not set
++# CONFIG_MFD_AXP20X is not set
++# CONFIG_MFD_CROS_EC is not set
++# CONFIG_PMIC_DA903X is not set
++# CONFIG_MFD_DA9052_SPI is not set
++# CONFIG_MFD_DA9052_I2C is not set
++# CONFIG_MFD_DA9055 is not set
++# CONFIG_MFD_DA9063 is not set
++# CONFIG_MFD_MC13XXX_SPI is not set
++# CONFIG_MFD_MC13XXX_I2C is not set
++# CONFIG_MFD_HI6421_PMIC is not set
++CONFIG_MFD_HISI_FMC=y
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_INTEL_SOC_PMIC is not set
++# CONFIG_MFD_KEMPLD is not set
++# CONFIG_MFD_88PM800 is not set
++# CONFIG_MFD_88PM805 is not set
++# CONFIG_MFD_88PM860X is not set
++# CONFIG_MFD_MAX14577 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_MENF21BMC is not set
++# CONFIG_EZX_PCAP is not set
++# CONFIG_MFD_VIPERBOARD is not set
++# CONFIG_MFD_RETU is not set
++# CONFIG_MFD_PCF50633 is not set
++# CONFIG_MFD_PM8921_CORE is not set
++# CONFIG_MFD_RTSX_USB is not set
++# CONFIG_MFD_RC5T583 is not set
++# CONFIG_MFD_RK808 is not set
++# CONFIG_MFD_RN5T618 is not set
++# CONFIG_MFD_SEC_CORE is not set
++# CONFIG_MFD_SI476X_CORE is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_MFD_SMSC is not set
++# CONFIG_ABX500_CORE is not set
++# CONFIG_MFD_STMPE is not set
++CONFIG_MFD_SYSCON=y
++# CONFIG_MFD_TI_AM335X_TSCADC is not set
++# CONFIG_MFD_LP3943 is not set
++# CONFIG_MFD_LP8788 is not set
++# CONFIG_MFD_PALMAS is not set
++# CONFIG_TPS6105X is not set
++# CONFIG_TPS6507X is not set
++# CONFIG_MFD_TPS65090 is not set
++# CONFIG_MFD_TPS65217 is not set
++# CONFIG_MFD_TPS65218 is not set
++# CONFIG_MFD_TPS6586X is not set
++# CONFIG_MFD_TPS80031 is not set
++# CONFIG_TWL4030_CORE is not set
++# CONFIG_TWL6040_CORE is not set
++# CONFIG_MFD_WL1273_CORE is not set
++# CONFIG_MFD_LM3533 is not set
++# CONFIG_MFD_TC3589X is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_MFD_T7L66XB is not set
++# CONFIG_MFD_TC6387XB is not set
++# CONFIG_MFD_TC6393XB is not set
++# CONFIG_MFD_ARIZONA_I2C is not set
++# CONFIG_MFD_ARIZONA_SPI is not set
++# CONFIG_MFD_WM8400 is not set
++# CONFIG_MFD_WM831X_I2C is not set
++# CONFIG_MFD_WM831X_SPI is not set
++# CONFIG_MFD_WM8350_I2C is not set
++# CONFIG_MFD_WM8994 is not set
++CONFIG_REGULATOR=y
++# CONFIG_REGULATOR_DEBUG is not set
++# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
++# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
++# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
++# CONFIG_REGULATOR_ACT8865 is not set
++# CONFIG_REGULATOR_AD5398 is not set
++# CONFIG_REGULATOR_ANATOP is not set
++# CONFIG_REGULATOR_DA9210 is not set
++# CONFIG_REGULATOR_DA9211 is not set
++# CONFIG_REGULATOR_FAN53555 is not set
++# CONFIG_REGULATOR_ISL9305 is not set
++# CONFIG_REGULATOR_ISL6271A is not set
++# CONFIG_REGULATOR_LP3971 is not set
++# CONFIG_REGULATOR_LP3972 is not set
++# CONFIG_REGULATOR_LP872X is not set
++# CONFIG_REGULATOR_LP8755 is not set
++# CONFIG_REGULATOR_LTC3589 is not set
++# CONFIG_REGULATOR_MAX1586 is not set
++# CONFIG_REGULATOR_MAX8649 is not set
++# CONFIG_REGULATOR_MAX8660 is not set
++# CONFIG_REGULATOR_MAX8952 is not set
++# CONFIG_REGULATOR_MAX8973 is not set
++# CONFIG_REGULATOR_PFUZE100 is not set
++# CONFIG_REGULATOR_TPS51632 is not set
++# CONFIG_REGULATOR_TPS62360 is not set
++# CONFIG_REGULATOR_TPS65023 is not set
++# CONFIG_REGULATOR_TPS6507X is not set
++# CONFIG_REGULATOR_TPS6524X is not set
++# CONFIG_MEDIA_SUPPORT is not set
++
++#
++# Graphics support
++#
++# CONFIG_IMX_IPUV3_CORE is not set
++
++#
++# Direct Rendering Manager
++#
++# CONFIG_DRM is not set
++
++#
++# Frame buffer Devices
++#
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++CONFIG_FB_CMDLINE=y
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++# CONFIG_FB_CFB_FILLRECT is not set
++# CONFIG_FB_CFB_COPYAREA is not set
++# CONFIG_FB_CFB_IMAGEBLIT is not set
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# 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_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_ARMCLCD is not set
++# CONFIG_FB_OPENCORES is not set
++# CONFIG_FB_S1D13XXX is not set
++# CONFIG_FB_SMSCUFX is not set
++# CONFIG_FB_UDL is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_BROADSHEET is not set
++# CONFIG_FB_AUO_K190X is not set
++# CONFIG_FB_SIMPLE is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++# CONFIG_VGASTATE is not set
++
++#
++# Console display driver support
++#
++CONFIG_DUMMY_CONSOLE=y
++# CONFIG_FRAMEBUFFER_CONSOLE is not set
++# CONFIG_LOGO is not set
++# CONFIG_SOUND is not set
++
++#
++# HID support
++#
++CONFIG_HID=y
++# CONFIG_HID_BATTERY_STRENGTH is not set
++# CONFIG_HIDRAW is not set
++# CONFIG_UHID is not set
++CONFIG_HID_GENERIC=y
++
++#
++# Special HID drivers
++#
++CONFIG_HID_A4TECH=y
++# CONFIG_HID_ACRUX is not set
++CONFIG_HID_APPLE=y
++# CONFIG_HID_APPLEIR is not set
++# CONFIG_HID_AUREAL is not set
++CONFIG_HID_BELKIN=y
++CONFIG_HID_CHERRY=y
++CONFIG_HID_CHICONY=y
++CONFIG_HID_CYPRESS=y
++# CONFIG_HID_DRAGONRISE is not set
++# CONFIG_HID_EMS_FF is not set
++# CONFIG_HID_ELECOM is not set
++# CONFIG_HID_ELO is not set
++CONFIG_HID_EZKEY=y
++# CONFIG_HID_HOLTEK is not set
++# CONFIG_HID_HUION 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_ICADE is not set
++# CONFIG_HID_TWINHAN is not set
++CONFIG_HID_KENSINGTON=y
++# CONFIG_HID_LCPOWER is not set
++# CONFIG_HID_LENOVO is not set
++CONFIG_HID_LOGITECH=y
++# CONFIG_HID_LOGITECH_HIDPP is not set
++# CONFIG_LOGITECH_FF is not set
++# CONFIG_LOGIRUMBLEPAD2_FF is not set
++# CONFIG_LOGIG940_FF is not set
++# CONFIG_LOGIWHEELS_FF is not set
++# CONFIG_HID_MAGICMOUSE is not set
++CONFIG_HID_MICROSOFT=y
++CONFIG_HID_MONTEREY=y
++# 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_PENMOUNT is not set
++# CONFIG_HID_PETALYNX is not set
++# CONFIG_HID_PICOLCD is not set
++# CONFIG_HID_PRIMAX is not set
++# CONFIG_HID_ROCCAT is not set
++# CONFIG_HID_SAITEK is not set
++# CONFIG_HID_SAMSUNG is not set
++# CONFIG_HID_SPEEDLINK is not set
++# CONFIG_HID_STEELSERIES is not set
++# CONFIG_HID_SUNPLUS is not set
++# CONFIG_HID_RMI 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_XINMO is not set
++# CONFIG_HID_ZEROPLUS is not set
++# CONFIG_HID_ZYDACRON is not set
++# CONFIG_HID_SENSOR_HUB is not set
++
++#
++# USB HID support
++#
++CONFIG_USB_HID=y
++# CONFIG_HID_PID is not set
++# CONFIG_USB_HIDDEV is not set
++
++#
++# I2C HID support
++#
++# CONFIG_I2C_HID is not set
++CONFIG_USB_OHCI_LITTLE_ENDIAN=y
++CONFIG_USB_SUPPORT=y
++CONFIG_USB_COMMON=y
++CONFIG_USB_ARCH_HAS_HCD=y
++CONFIG_USB=y
++# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
++
++#
++# Miscellaneous USB options
++#
++CONFIG_USB_DEFAULT_PERSIST=y
++# CONFIG_USB_DYNAMIC_MINORS is not set
++# CONFIG_USB_OTG_WHITELIST is not set
++# CONFIG_USB_OTG_FSM is not set
++# CONFIG_USB_MON is not set
++# CONFIG_USB_WUSB_CBAF is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_C67X00_HCD is not set
++CONFIG_USB_XHCI_HCD=y
++CONFIG_USB_XHCI_PLATFORM=y
++CONFIG_USB_XHCI_HISILICON=y
++CONFIG_USB_EHCI_HCD=y
++# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
++CONFIG_USB_EHCI_TT_NEWSCHED=y
++CONFIG_USB_EHCI_HCD_PLATFORM=y
++# 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_FUSBH200_HCD is not set
++# CONFIG_USB_FOTG210_HCD is not set
++# CONFIG_USB_MAX3421_HCD is not set
++CONFIG_USB_OHCI_HCD=y
++CONFIG_USB_OHCI_HCD_PLATFORM=y
++# CONFIG_USB_SL811_HCD is not set
++# CONFIG_USB_R8A66597_HCD is not set
++# CONFIG_USB_HCD_TEST_MODE is not set
++
++#
++# USB Device Class drivers
++#
++# CONFIG_USB_ACM is not set
++# CONFIG_USB_PRINTER is not set
++# CONFIG_USB_WDM is not set
++# CONFIG_USB_TMC is not set
++
++#
++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
++#
++
++#
++# also be needed; see USB_STORAGE Help for more info
++#
++CONFIG_USB_STORAGE=y
++# CONFIG_USB_STORAGE_DEBUG is not set
++# CONFIG_USB_STORAGE_REALTEK is not set
++# CONFIG_USB_STORAGE_DATAFAB is not set
++# CONFIG_USB_STORAGE_FREECOM is not set
++# CONFIG_USB_STORAGE_ISD200 is not set
++# CONFIG_USB_STORAGE_USBAT is not set
++# CONFIG_USB_STORAGE_SDDR09 is not set
++# CONFIG_USB_STORAGE_SDDR55 is not set
++# CONFIG_USB_STORAGE_JUMPSHOT is not set
++# CONFIG_USB_STORAGE_ALAUDA is not set
++# CONFIG_USB_STORAGE_ONETOUCH is not set
++# CONFIG_USB_STORAGE_KARMA is not set
++# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
++# CONFIG_USB_STORAGE_ENE_UB6250 is not set
++# CONFIG_USB_UAS is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++# CONFIG_USBIP_CORE is not set
++# CONFIG_USB_MUSB_HDRC is not set
++# CONFIG_USB_DWC3 is not set
++# CONFIG_USB_DWC2 is not set
++# CONFIG_USB_CHIPIDEA is not set
++
++#
++# USB port drivers
++#
++# CONFIG_USB_SERIAL is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
++# CONFIG_USB_SEVSEG is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
++# CONFIG_USB_APPLEDISPLAY is not set
++# CONFIG_USB_SISUSBVGA is not set
++# CONFIG_USB_LD is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
++# CONFIG_USB_IOWARRIOR is not set
++# CONFIG_USB_TEST is not set
++# CONFIG_USB_EHSET_TEST_FIXTURE is not set
++# CONFIG_USB_ISIGHTFW is not set
++# CONFIG_USB_YUREX is not set
++# CONFIG_USB_EZUSB_FX2 is not set
++# CONFIG_USB_HSIC_USB3503 is not set
++# CONFIG_USB_LINK_LAYER_TEST is not set
++
++#
++# USB Physical Layer drivers
++#
++# CONFIG_USB_PHY is not set
++# CONFIG_USB_OTG_WAKELOCK is not set
++# CONFIG_NOP_USB_XCEIV is not set
++# CONFIG_AM335X_PHY_USB is not set
++# CONFIG_USB_ISP1301 is not set
++# CONFIG_USB_ULPI is not set
++# CONFIG_USB_GADGET is not set
++# CONFIG_UWB is not set
++# CONFIG_MMC is not set
++# CONFIG_MEMSTICK is not set
++# CONFIG_NEW_LEDS is not set
++# CONFIG_SWITCH is not set
++# CONFIG_ACCESSIBILITY is not set
++# CONFIG_EDAC is not set
++CONFIG_RTC_LIB=y
++# CONFIG_RTC_CLASS is not set
++# CONFIG_DMADEVICES is not set
++# CONFIG_AUXDISPLAY is not set
++# CONFIG_UIO is not set
++# CONFIG_VIRT_DRIVERS is not set
++
++#
++# Virtio drivers
++#
++# CONFIG_VIRTIO_MMIO is not set
++
++#
++# Microsoft Hyper-V guest support
++#
++# CONFIG_STAGING is not set
++
++#
++# SOC (System On Chip) specific Drivers
++#
++# CONFIG_SOC_TI is not set
++CONFIG_CLKDEV_LOOKUP=y
++CONFIG_HAVE_CLK_PREPARE=y
++CONFIG_COMMON_CLK=y
++
++#
++# Common Clock Framework
++#
++# CONFIG_COMMON_CLK_SI5351 is not set
++# CONFIG_COMMON_CLK_SI570 is not set
++# CONFIG_COMMON_CLK_PXA is not set
++# CONFIG_COMMON_CLK_QCOM is not set
++
++#
++# Hardware Spinlock drivers
++#
++
++#
++# Clock Source drivers
++#
++CONFIG_CLKSRC_OF=y
++CONFIG_CLKSRC_MMIO=y
++CONFIG_ARM_ARCH_TIMER=y
++CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y
++# CONFIG_ARM_ARCH_TIMER_VCT_ACCESS is not set
++# CONFIG_ATMEL_PIT is not set
++# CONFIG_SH_TIMER_CMT is not set
++# CONFIG_SH_TIMER_MTU2 is not set
++# CONFIG_SH_TIMER_TMU is not set
++# CONFIG_EM_TIMER_STI is not set
++# CONFIG_CLKSRC_VERSATILE is not set
++# CONFIG_MAILBOX is not set
++# CONFIG_IOMMU_SUPPORT is not set
++
++#
++# Remoteproc drivers
++#
++# CONFIG_STE_MODEM_RPROC is not set
++
++#
++# Rpmsg drivers
++#
++
++#
++# SOC (System On Chip) specific Drivers
++#
++# 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
++CONFIG_IRQCHIP=y
++CONFIG_ARM_GIC=y
++# CONFIG_IPACK_BUS is not set
++CONFIG_ARCH_HAS_RESET_CONTROLLER=y
++CONFIG_RESET_CONTROLLER=y
++# CONFIG_FMC is not set
++
++#
++# PHY Subsystem
++#
++CONFIG_GENERIC_PHY=y
++# CONFIG_BCM_KONA_USB2_PHY is not set
++# CONFIG_PHY_HISI_INNO_USB2 is not set
++CONFIG_PHY_HI35x1D_INNO_USB2=y
++CONFIG_PHY_HI3531D_USB3=y
++CONFIG_HI_NANO_PHY_SATA=y
++CONFIG_HI_SATA_PORTS=4
++CONFIG_HI_SATA_MODE=1
++# CONFIG_POWERCAP is not set
++# CONFIG_MCB is not set
++CONFIG_HI_DMAC=y
++CONFIG_HI_DMAC_CHANNEL_NUM=4
++
++#
++# Hisilicon driver support
++#
++
++#
++# File systems
++#
++CONFIG_DCACHE_WORD_ACCESS=y
++# CONFIG_EXT2_FS is not set
++# CONFIG_EXT3_FS is not set
++CONFIG_EXT4_FS=y
++CONFIG_EXT4_USE_FOR_EXT23=y
++# CONFIG_EXT4_FS_POSIX_ACL is not set
++# CONFIG_EXT4_FS_SECURITY is not set
++# CONFIG_EXT4_DEBUG is not set
++CONFIG_JBD2=y
++# CONFIG_JBD2_DEBUG is not set
++CONFIG_FS_MBCACHE=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_BTRFS_FS is not set
++# CONFIG_NILFS2_FS is not set
++CONFIG_FS_POSIX_ACL=y
++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 is not set
++# CONFIG_FUSE_FS is not set
++# CONFIG_OVERLAY_FS is not set
++
++#
++# Caches
++#
++# CONFIG_FSCACHE is not set
++
++#
++# CD-ROM/DVD Filesystems
++#
++CONFIG_ISO9660_FS=y
++# CONFIG_JOLIET is not set
++# CONFIG_ZISOFS is not set
++CONFIG_UDF_FS=y
++CONFIG_UDF_NLS=y
++
++#
++# DOS/FAT/NT Filesystems
++#
++CONFIG_FAT_FS=y
++CONFIG_MSDOS_FS=y
++CONFIG_VFAT_FS=y
++CONFIG_FAT_DEFAULT_CODEPAGE=437
++CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
++# CONFIG_NTFS_FS is not set
++
++#
++# Pseudo filesystems
++#
++CONFIG_PROC_FS=y
++CONFIG_PROC_SYSCTL=y
++CONFIG_PROC_PAGE_MONITOR=y
++CONFIG_KERNFS=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=m
++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_YAFFS_FS=y
++CONFIG_YAFFS_YAFFS1=y
++# CONFIG_YAFFS_9BYTE_TAGS is not set
++# CONFIG_YAFFS_DOES_ECC is not set
++CONFIG_YAFFS_YAFFS2=y
++CONFIG_YAFFS_AUTO_YAFFS2=y
++# CONFIG_YAFFS_DISABLE_TAGS_ECC is not set
++# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
++# CONFIG_YAFFS_EMPTY_LOST_AND_FOUND is not set
++# CONFIG_YAFFS_DISABLE_BLOCK_REFRESHING is not set
++# CONFIG_YAFFS_DISABLE_BACKGROUND is not set
++# CONFIG_YAFFS_DISABLE_BAD_BLOCK_MARKING is not set
++CONFIG_YAFFS_XATTR=y
++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 is not set
++# CONFIG_JFFS2_FS_XATTR is not set
++# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
++CONFIG_JFFS2_ZLIB=y
++# CONFIG_JFFS2_LZO is not set
++CONFIG_JFFS2_RTIME=y
++# CONFIG_JFFS2_RUBIN 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 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 is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V2=y
++CONFIG_NFS_V3=y
++CONFIG_NFS_V3_ACL=y
++# CONFIG_NFS_V4 is not set
++# CONFIG_NFS_SWAP is not set
++# CONFIG_ROOT_NFS is not set
++# CONFIG_NFSD is not set
++CONFIG_GRACE_PERIOD=y
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_ACL_SUPPORT=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 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=y
++# CONFIG_DLM is not set
++
++#
++# Kernel hacking
++#
++
++#
++# printk and dmesg options
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4
++# CONFIG_BOOT_PRINTK_DELAY is not set
++
++#
++# Compile-time checks and compiler options
++#
++# CONFIG_DEBUG_INFO is not set
++# CONFIG_ENABLE_WARN_DEPRECATED is not set
++# CONFIG_ENABLE_MUST_CHECK is not set
++CONFIG_FRAME_WARN=1024
++# CONFIG_STRIP_ASM_SYMS is not set
++# CONFIG_READABLE_ASM is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++# CONFIG_DEBUG_FS is not set
++# CONFIG_HEADERS_CHECK is not set
++# CONFIG_DEBUG_SECTION_MISMATCH is not set
++# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
++# CONFIG_MAGIC_SYSRQ is not set
++CONFIG_DEBUG_KERNEL=y
++
++#
++# Memory Debugging
++#
++# CONFIG_DEBUG_PAGEALLOC is not set
++# 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_STACK_USAGE is not set
++# CONFIG_DEBUG_VM is not set
++CONFIG_DEBUG_MEMORY_INIT=y
++# CONFIG_DEBUG_PER_CPU_MAPS is not set
++# CONFIG_DEBUG_HIGHMEM is not set
++# CONFIG_DEBUG_SHIRQ is not set
++
++#
++# Debug Lockups and Hangs
++#
++# CONFIG_LOCKUP_DETECTOR is not set
++# CONFIG_DETECT_HUNG_TASK is not set
++# CONFIG_PANIC_ON_OOPS is not set
++CONFIG_PANIC_ON_OOPS_VALUE=0
++CONFIG_PANIC_TIMEOUT=0
++CONFIG_SCHED_DEBUG=y
++# CONFIG_SCHEDSTATS is not set
++# CONFIG_SCHED_STACK_END_CHECK is not set
++# CONFIG_TIMER_STATS is not set
++
++#
++# Lock Debugging (spinlocks, mutexes, etc...)
++#
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_LOCK_STAT is not set
++# CONFIG_DEBUG_ATOMIC_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_LOCK_TORTURE_TEST is not set
++CONFIG_STACKTRACE=y
++# CONFIG_DEBUG_KOBJECT is not set
++CONFIG_DEBUG_BUGVERBOSE=y
++# CONFIG_DEBUG_LIST is not set
++# CONFIG_DEBUG_PI_LIST is not set
++# CONFIG_DEBUG_SG is not set
++# CONFIG_DEBUG_NOTIFIERS is not set
++# CONFIG_DEBUG_CREDENTIALS is not set
++
++#
++# RCU Debugging
++#
++# CONFIG_SPARSE_RCU_POINTER is not set
++# CONFIG_TORTURE_TEST 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_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_NOTIFIER_ERROR_INJECTION is not set
++# CONFIG_FAULT_INJECTION 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 is not set
++
++#
++# Runtime Testing
++#
++# CONFIG_TEST_LIST_SORT is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_RBTREE_TEST is not set
++# CONFIG_INTERVAL_TREE_TEST is not set
++# CONFIG_PERCPU_TEST is not set
++# CONFIG_ATOMIC64_SELFTEST is not set
++# CONFIG_TEST_STRING_HELPERS is not set
++# CONFIG_TEST_KSTRTOX is not set
++# CONFIG_TEST_RHASHTABLE is not set
++# CONFIG_DMA_API_DEBUG is not set
++# CONFIG_TEST_LKM is not set
++# CONFIG_TEST_USER_COPY is not set
++# CONFIG_TEST_BPF is not set
++# CONFIG_TEST_FIRMWARE is not set
++# CONFIG_TEST_UDELAY is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_KGDB is not set
++# CONFIG_ARM_PTDUMP is not set
++CONFIG_STRICT_DEVMEM=y
++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_DEBUG_UART_PL01X is not set
++# CONFIG_DEBUG_UART_8250 is not set
++# CONFIG_DEBUG_UART_BCM63XX is not set
++CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"
++# CONFIG_OC_ETM is not set
++# CONFIG_PID_IN_CONTEXTIDR is not set
++# CONFIG_DEBUG_SET_MODULE_RONX is not set
++# CONFIG_CORESIGHT is not set
++
++#
++# 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_HASH=y
++CONFIG_CRYPTO_HASH2=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_PCRYPT is not set
++# CONFIG_CRYPTO_CRYPTD is not set
++# CONFIG_CRYPTO_MCRYPTD 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_CMAC is not set
++# CONFIG_CRYPTO_HMAC is not set
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_VMAC is not set
++
++#
++# Digest
++#
++CONFIG_CRYPTO_CRC32C=y
++# CONFIG_CRYPTO_CRC32 is not set
++# CONFIG_CRYPTO_CRCT10DIF 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_SHA1_ARM_NEON is not set
++# CONFIG_CRYPTO_SHA256 is not set
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_SHA512_ARM_NEON 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_AES_ARM_BS 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
++# CONFIG_CRYPTO_LZ4 is not set
++# CONFIG_CRYPTO_LZ4HC is not set
++
++#
++# Random Number Generation
++#
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++# CONFIG_CRYPTO_DRBG_MENU is not set
++# CONFIG_CRYPTO_USER_API_HASH is not set
++# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
++CONFIG_CRYPTO_HW=y
++# CONFIG_BINARY_PRINTF is not set
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++CONFIG_GENERIC_STRNCPY_FROM_USER=y
++CONFIG_GENERIC_STRNLEN_USER=y
++CONFIG_GENERIC_NET_UTILS=y
++CONFIG_GENERIC_PCI_IOMAP=y
++CONFIG_GENERIC_IO=y
++CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
++# CONFIG_CRC_CCITT is not set
++CONFIG_CRC16=y
++# CONFIG_CRC_T10DIF is not set
++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 is not set
++# CONFIG_LIBCRC32C is not set
++# CONFIG_CRC8 is not set
++# CONFIG_AUDIT_ARCH_COMPAT_GENERIC is not set
++# CONFIG_RANDOM32_SELFTEST is not set
++CONFIG_ZLIB_INFLATE=y
++CONFIG_ZLIB_DEFLATE=y
++CONFIG_LZO_COMPRESS=y
++CONFIG_LZO_DECOMPRESS=y
++CONFIG_LZ4_DECOMPRESS=y
++CONFIG_XZ_DEC=y
++CONFIG_XZ_DEC_X86=y
++CONFIG_XZ_DEC_POWERPC=y
++CONFIG_XZ_DEC_IA64=y
++CONFIG_XZ_DEC_ARM=y
++CONFIG_XZ_DEC_ARMTHUMB=y
++CONFIG_XZ_DEC_SPARC=y
++CONFIG_XZ_DEC_BCJ=y
++# CONFIG_XZ_DEC_TEST is not set
++CONFIG_DECOMPRESS_GZIP=y
++CONFIG_DECOMPRESS_BZIP2=y
++CONFIG_DECOMPRESS_LZMA=y
++CONFIG_DECOMPRESS_XZ=y
++CONFIG_DECOMPRESS_LZO=y
++CONFIG_DECOMPRESS_LZ4=y
++CONFIG_GENERIC_ALLOCATOR=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT_MAP=y
++CONFIG_HAS_DMA=y
++CONFIG_CPU_RMAP=y
++CONFIG_DQL=y
++CONFIG_GLOB=y
++# CONFIG_GLOB_SELFTEST is not set
++CONFIG_NLATTR=y
++CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
++# CONFIG_AVERAGE is not set
++# CONFIG_CORDIC is not set
++# CONFIG_DDR is not set
++CONFIG_LIBFDT=y
++CONFIG_ARCH_HAS_SG_CHAIN=y
++# CONFIG_VIRTUALIZATION is not set
+diff --git a/arch/arm/configs/hi3536c_full_defconfig b/arch/arm/configs/hi3536c_full_defconfig
+new file mode 100644
+index 0000000..9f8b73a
+--- /dev/null
++++ b/arch/arm/configs/hi3536c_full_defconfig
+@@ -0,0 +1,2522 @@
++#
++# Automatically generated file; DO NOT EDIT.
++# Linux/arm 3.18.20 Kernel Configuration
++#
++CONFIG_ARM=y
++CONFIG_ARM_HAS_SG_CHAIN=y
++CONFIG_MIGHT_HAVE_PCI=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=y
++CONFIG_HAVE_PROC_CPU=y
++CONFIG_STACKTRACE_SUPPORT=y
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
++CONFIG_RWSEM_XCHGADD_ALGORITHM=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_NEED_DMA_MAP_STATE=y
++CONFIG_ARCH_SUPPORTS_UPROBES=y
++CONFIG_VECTORS_BASE=0xffff0000
++CONFIG_ARM_PATCH_PHYS_VIRT=y
++CONFIG_GENERIC_BUG=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++CONFIG_IRQ_WORK=y
++CONFIG_BUILDTIME_EXTABLE_SORT=y
++
++#
++# General setup
++#
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_CROSS_COMPILE=""
++# CONFIG_COMPILE_TEST is not set
++CONFIG_LOCALVERSION=""
++# CONFIG_LOCALVERSION_AUTO is not set
++CONFIG_HAVE_KERNEL_GZIP=y
++CONFIG_HAVE_KERNEL_LZMA=y
++CONFIG_HAVE_KERNEL_XZ=y
++CONFIG_HAVE_KERNEL_LZO=y
++CONFIG_HAVE_KERNEL_LZ4=y
++CONFIG_KERNEL_GZIP=y
++# CONFIG_KERNEL_LZMA is not set
++# CONFIG_KERNEL_XZ is not set
++# CONFIG_KERNEL_LZO is not set
++# CONFIG_KERNEL_LZ4 is not set
++CONFIG_DEFAULT_HOSTNAME="(none)"
++# CONFIG_SWAP is not set
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++# CONFIG_POSIX_MQUEUE is not set
++CONFIG_CROSS_MEMORY_ATTACH=y
++# CONFIG_FHANDLE is not set
++CONFIG_USELIB=y
++# CONFIG_AUDIT is not set
++
++#
++# IRQ subsystem
++#
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_GENERIC_IRQ_SHOW=y
++CONFIG_HARDIRQS_SW_RESEND=y
++CONFIG_IRQ_DOMAIN=y
++CONFIG_HANDLE_DOMAIN_IRQ=y
++CONFIG_IRQ_FORCED_THREADING=y
++CONFIG_SPARSE_IRQ=y
++CONFIG_GENERIC_CLOCKEVENTS=y
++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
++CONFIG_ARCH_HAS_TICK_BROADCAST=y
++CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
++
++#
++# Timers subsystem
++#
++CONFIG_HZ_PERIODIC=y
++# CONFIG_NO_HZ_IDLE is not set
++# CONFIG_NO_HZ_FULL is not set
++# CONFIG_NO_HZ is not set
++# CONFIG_HIGH_RES_TIMERS is not set
++
++#
++# CPU/Task time and stats accounting
++#
++CONFIG_TICK_CPU_ACCOUNTING=y
++# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set
++# CONFIG_IRQ_TIME_ACCOUNTING is not set
++# CONFIG_BSD_PROCESS_ACCT is not set
++# CONFIG_TASKSTATS is not set
++
++#
++# RCU Subsystem
++#
++CONFIG_TREE_RCU=y
++# CONFIG_PREEMPT_RCU is not set
++# CONFIG_TASKS_RCU is not set
++CONFIG_RCU_STALL_COMMON=y
++# CONFIG_RCU_USER_QS is not set
++CONFIG_RCU_FANOUT=32
++CONFIG_RCU_FANOUT_LEAF=16
++# CONFIG_RCU_FANOUT_EXACT is not set
++# CONFIG_TREE_RCU_TRACE is not set
++# CONFIG_RCU_NOCB_CPU is not set
++# CONFIG_BUILD_BIN2C is not set
++# CONFIG_IKCONFIG is not set
++CONFIG_LOG_BUF_SHIFT=17
++CONFIG_LOG_CPU_MAX_BUF_SHIFT=12
++CONFIG_GENERIC_SCHED_CLOCK=y
++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_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_USER_NS is not set
++CONFIG_PID_NS=y
++CONFIG_NET_NS=y
++# 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=y
++CONFIG_RD_LZMA=y
++CONFIG_RD_XZ=y
++CONFIG_RD_LZO=y
++CONFIG_RD_LZ4=y
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++CONFIG_HAVE_UID16=y
++CONFIG_BPF=y
++# CONFIG_EXPERT is not set
++CONFIG_UID16=y
++# CONFIG_SGETMASK_SYSCALL is not set
++CONFIG_SYSFS_SYSCALL=y
++# CONFIG_SYSCTL_SYSCALL is not set
++CONFIG_KALLSYMS=y
++# CONFIG_KALLSYMS_ALL is not set
++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_BPF_SYSCALL is not set
++CONFIG_SHMEM=y
++CONFIG_AIO=y
++CONFIG_ADVISE_SYSCALLS=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 is not set
++# CONFIG_SLAB is not set
++CONFIG_SLUB=y
++CONFIG_SLUB_CPU_PARTIAL=y
++# CONFIG_PROFILING is not set
++CONFIG_HAVE_OPROFILE=y
++# CONFIG_KPROBES is not set
++# CONFIG_JUMP_LABEL is not set
++# CONFIG_UPROBES is not set
++# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
++CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
++CONFIG_ARCH_USE_BUILTIN_BSWAP=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_GENERIC_SMP_IDLE_THREAD=y
++CONFIG_GENERIC_IDLE_POLL_SETUP=y
++CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
++CONFIG_HAVE_CLK=y
++CONFIG_HAVE_DMA_API_DEBUG=y
++CONFIG_HAVE_PERF_REGS=y
++CONFIG_HAVE_PERF_USER_STACK_DUMP=y
++CONFIG_HAVE_ARCH_JUMP_LABEL=y
++CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
++CONFIG_HAVE_CC_STACKPROTECTOR=y
++# CONFIG_CC_STACKPROTECTOR is not set
++CONFIG_CC_STACKPROTECTOR_NONE=y
++# CONFIG_CC_STACKPROTECTOR_REGULAR is not set
++# CONFIG_CC_STACKPROTECTOR_STRONG is not set
++CONFIG_HAVE_CONTEXT_TRACKING=y
++CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
++CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
++CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
++CONFIG_MODULES_USE_ELF_REL=y
++CONFIG_CLONE_BACKWARDS=y
++CONFIG_OLD_SIGSUSPEND3=y
++CONFIG_OLD_SIGACTION=y
++
++#
++# GCOV-based kernel profiling
++#
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_SLABINFO=y
++CONFIG_RT_MUTEXES=y
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++# CONFIG_MODULE_FORCE_LOAD is not set
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++# CONFIG_MODULE_SIG is not set
++# CONFIG_MODULE_COMPRESS is not set
++CONFIG_STOP_MACHINE=y
++CONFIG_BLOCK=y
++CONFIG_LBDAF=y
++CONFIG_BLK_DEV_BSG=y
++# CONFIG_BLK_DEV_BSGLIB is not set
++# CONFIG_BLK_DEV_INTEGRITY is not set
++CONFIG_BLK_CMDLINE_PARSER=y
++
++#
++# Partition Types
++#
++CONFIG_PARTITION_ADVANCED=y
++# CONFIG_ACORN_PARTITION is not set
++# CONFIG_AIX_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=y
++# CONFIG_SYSV68_PARTITION is not set
++CONFIG_CMDLINE_PARTITION=y
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++CONFIG_DEFAULT_DEADLINE=y
++# CONFIG_DEFAULT_CFQ is not set
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="deadline"
++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_ARCH_SUPPORTS_ATOMIC_RMW=y
++CONFIG_MUTEX_SPIN_ON_OWNER=y
++CONFIG_RWSEM_SPIN_ON_OWNER=y
++CONFIG_FREEZER=y
++
++#
++# System Type
++#
++CONFIG_MMU=y
++CONFIG_ARCH_MULTIPLATFORM=y
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_AT91 is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_GEMINI is not set
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_IOP13XX is not set
++# CONFIG_ARCH_IOP32X is not set
++# CONFIG_ARCH_IOP33X is not set
++# CONFIG_ARCH_IXP4XX is not set
++# CONFIG_ARCH_DOVE is not set
++# CONFIG_ARCH_MV78XX0 is not set
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_MMP is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_W90X900 is not set
++# CONFIG_ARCH_LPC32XX is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_MSM is not set
++# CONFIG_ARCH_SHMOBILE_LEGACY 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_DAVINCI is not set
++# CONFIG_ARCH_OMAP1 is not set
++
++#
++# Multiple platform selection
++#
++
++#
++# CPU Core family selection
++#
++# CONFIG_ARCH_MULTI_V6 is not set
++CONFIG_ARCH_MULTI_V7=y
++CONFIG_ARCH_MULTI_V6_V7=y
++# CONFIG_ARCH_MULTI_CPU_AUTO is not set
++# CONFIG_ARCH_VIRT is not set
++# CONFIG_ARCH_MVEBU is not set
++# CONFIG_ARCH_BCM is not set
++# CONFIG_ARCH_BERLIN is not set
++# CONFIG_ARCH_HIGHBANK is not set
++CONFIG_ARCH_HISI=y
++
++#
++# Hisilicon platform type
++#
++# CONFIG_ARCH_HI3xxx is not set
++# CONFIG_ARCH_HIP04 is not set
++# CONFIG_ARCH_HIX5HD2 is not set
++# CONFIG_ARCH_HI3519 is not set
++# CONFIG_ARCH_HI3519V101 is not set
++# CONFIG_ARCH_HI3516AV200 is not set
++# CONFIG_ARCH_HI3559 is not set
++# CONFIG_ARCH_HI3556 is not set
++CONFIG_ARCH_HI3536C=y
++# CONFIG_ARCH_HI3531D is not set
++# CONFIG_ARCH_HI3521D is not set
++# CONFIG_ARCH_KEYSTONE is not set
++# CONFIG_ARCH_MESON is not set
++# CONFIG_ARCH_MXC is not set
++# CONFIG_ARCH_MEDIATEK is not set
++
++#
++# TI OMAP/AM/DM/DRA Family
++#
++# CONFIG_ARCH_OMAP3 is not set
++# CONFIG_ARCH_OMAP4 is not set
++# CONFIG_SOC_OMAP5 is not set
++# CONFIG_SOC_AM33XX is not set
++# CONFIG_SOC_AM43XX is not set
++# CONFIG_SOC_DRA7XX is not set
++# CONFIG_ARCH_QCOM is not set
++# CONFIG_ARCH_ROCKCHIP is not set
++# CONFIG_ARCH_SOCFPGA is not set
++# CONFIG_PLAT_SPEAR is not set
++# CONFIG_ARCH_STI is not set
++# CONFIG_ARCH_S5PV210 is not set
++# CONFIG_ARCH_EXYNOS is not set
++# CONFIG_ARCH_SHMOBILE_MULTI is not set
++# CONFIG_ARCH_SUNXI is not set
++# CONFIG_ARCH_SIRF is not set
++# CONFIG_ARCH_TEGRA is not set
++# CONFIG_ARCH_U8500 is not set
++# CONFIG_ARCH_VEXPRESS is not set
++# CONFIG_ARCH_WM8850 is not set
++# CONFIG_ARCH_ZYNQ is not set
++CONFIG_ARM_TIMER_SP804=y
++
++#
++# Processor Type
++#
++CONFIG_CPU_V7=y
++CONFIG_CPU_32v6K=y
++CONFIG_CPU_32v7=y
++CONFIG_CPU_ABRT_EV7=y
++CONFIG_CPU_PABRT_V7=y
++CONFIG_CPU_CACHE_V7=y
++CONFIG_CPU_CACHE_VIPT=y
++CONFIG_CPU_COPY_V6=y
++CONFIG_CPU_TLB_V7=y
++CONFIG_CPU_HAS_ASID=y
++CONFIG_CPU_CP15=y
++CONFIG_CPU_CP15_MMU=y
++
++#
++# Processor Features
++#
++# CONFIG_ARM_LPAE is not set
++# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
++CONFIG_ARM_THUMB=y
++# CONFIG_ARM_THUMBEE is not set
++CONFIG_ARM_VIRT_EXT=y
++CONFIG_SWP_EMULATE=y
++# CONFIG_CPU_ICACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_DISABLE is not set
++# CONFIG_CPU_BPREDICT_DISABLE is not set
++CONFIG_KUSER_HELPERS=y
++CONFIG_MIGHT_HAVE_CACHE_L2X0=y
++# CONFIG_CACHE_L2X0 is not set
++CONFIG_ARM_L1_CACHE_SHIFT_6=y
++CONFIG_ARM_L1_CACHE_SHIFT=6
++CONFIG_ARM_DMA_MEM_BUFFERABLE=y
++CONFIG_MULTI_IRQ_HANDLER=y
++# CONFIG_ARM_ERRATA_430973 is not set
++# CONFIG_ARM_ERRATA_643719 is not set
++# CONFIG_ARM_ERRATA_720789 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_ARM_ERRATA_775420 is not set
++# CONFIG_ARM_ERRATA_798181 is not set
++# CONFIG_ARM_ERRATA_773022 is not set
++
++#
++# Bus support
++#
++CONFIG_ARM_AMBA=y
++# CONFIG_PCI is not set
++# 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_DISABLE_CPU_SCHED_DOMAIN_BALANCE is not set
++CONFIG_HAVE_ARM_SCU=y
++CONFIG_HAVE_ARM_ARCH_TIMER=y
++# CONFIG_MCPM is not set
++# CONFIG_BIG_LITTLE is not set
++CONFIG_VMSPLIT_3G=y
++# CONFIG_VMSPLIT_2G is not set
++# CONFIG_VMSPLIT_1G is not set
++CONFIG_PAGE_OFFSET=0xC0000000
++CONFIG_NR_CPUS=4
++CONFIG_HOTPLUG_CPU=y
++# CONFIG_ARM_PSCI is not set
++CONFIG_ARCH_NR_GPIO=0
++CONFIG_PREEMPT_NONE=y
++# CONFIG_PREEMPT_VOLUNTARY is not set
++# CONFIG_PREEMPT is not set
++CONFIG_HZ_FIXED=0
++CONFIG_HZ_100=y
++# CONFIG_HZ_200 is not set
++# CONFIG_HZ_250 is not set
++# CONFIG_HZ_300 is not set
++# CONFIG_HZ_500 is not set
++# CONFIG_HZ_1000 is not set
++CONFIG_HZ=100
++# CONFIG_SCHED_HRTICK is not set
++# CONFIG_THUMB2_KERNEL is not set
++CONFIG_AEABI=y
++CONFIG_OABI_COMPAT=y
++# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
++# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
++CONFIG_HAVE_ARCH_PFN_VALID=y
++CONFIG_HIGHMEM=y
++# CONFIG_HIGHPTE is not set
++CONFIG_ARCH_WANT_GENERAL_HUGETLB=y
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_HAVE_MEMBLOCK=y
++CONFIG_NO_BOOTMEM=y
++# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=4
++CONFIG_COMPACTION=y
++CONFIG_MIGRATION=y
++# CONFIG_PHYS_ADDR_T_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_BOUNCE=y
++# CONFIG_KSM is not set
++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
++# CONFIG_CLEANCACHE is not set
++# CONFIG_CMA is not set
++# CONFIG_ZPOOL is not set
++# CONFIG_ZBUD is not set
++# CONFIG_ZSMALLOC 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_SWIOTLB=y
++CONFIG_IOMMU_HELPER=y
++# CONFIG_XEN is not set
++# CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART is not set
++
++#
++# Boot options
++#
++CONFIG_USE_OF=y
++CONFIG_ATAGS=y
++# CONFIG_DEPRECATED_PARAM_STRUCT is not set
++# CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE is not set
++CONFIG_ZBOOT_ROM_TEXT=0
++CONFIG_ZBOOT_ROM_BSS=0
++CONFIG_ARM_APPENDED_DTB=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_KEXEC is not set
++# CONFIG_CRASH_DUMP is not set
++CONFIG_AUTO_ZRELADDR=y
++
++#
++# CPU Power Management
++#
++
++#
++# CPU Frequency scaling
++#
++CONFIG_CPU_FREQ=y
++CONFIG_CPU_FREQ_STAT=y
++# CONFIG_CPU_FREQ_STAT_DETAILS is not set
++CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
++# CONFIG_CPU_FREQ_DEFAULT_GOV_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_DEFAULT_GOV_INTERACTIVE is not set
++CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
++# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
++# CONFIG_CPU_FREQ_GOV_USERSPACE is not set
++# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
++# CONFIG_CPU_FREQ_GOV_INTERACTIVE is not set
++# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
++CONFIG_CPUFREQ_DT=y
++
++#
++# ARM CPU frequency scaling drivers
++#
++# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set
++
++#
++# CPU Idle
++#
++# CONFIG_CPU_IDLE is not set
++# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++# CONFIG_FPE_NWFPE is not set
++# CONFIG_FPE_FASTFPE is not set
++CONFIG_VFP=y
++CONFIG_VFPv3=y
++CONFIG_NEON=y
++CONFIG_KERNEL_MODE_NEON=y
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
++CONFIG_BINFMT_SCRIPT=y
++# CONFIG_HAVE_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
++CONFIG_COREDUMP=y
++
++#
++# Power management options
++#
++CONFIG_SUSPEND=y
++CONFIG_SUSPEND_FREEZER=y
++CONFIG_WAKELOCK=y
++# CONFIG_HISI_SNAPSHOT_BOOT is not set
++CONFIG_PM_SLEEP=y
++CONFIG_PM_SLEEP_SMP=y
++# CONFIG_PM_AUTOSLEEP is not set
++# CONFIG_PM_WAKELOCKS is not set
++# CONFIG_PM_RUNTIME is not set
++CONFIG_PM=y
++# CONFIG_PM_DEBUG is not set
++# CONFIG_APM_EMULATION is not set
++CONFIG_PM_OPP=y
++CONFIG_PM_CLK=y
++# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set
++CONFIG_CPU_PM=y
++# CONFIG_SUSPEND_TIME is not set
++CONFIG_ARCH_SUSPEND_POSSIBLE=y
++CONFIG_ARM_CPU_SUSPEND=y
++CONFIG_ARCH_HIBERNATION_POSSIBLE=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=y
++# 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_NET_IP_TUNNEL=m
++# CONFIG_IP_MROUTE is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_NET_UDP_TUNNEL is not set
++# CONFIG_NET_FOU is not set
++# CONFIG_GENEVE 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 is not set
++# CONFIG_INET_XFRM_MODE_TUNNEL is not set
++# CONFIG_INET_XFRM_MODE_BEET is not set
++CONFIG_INET_LRO=y
++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=y
++# 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_VTI 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_ANDROID_PARANOID_NETWORK is not set
++CONFIG_NET_ACTIVITY_STATS=y
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NET_PTP_CLASSIFY 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_NF_TABLES is not set
++# CONFIG_NETFILTER_XTABLES is not set
++# CONFIG_IP_SET is not set
++# CONFIG_IP_VS is not set
++
++#
++# IP: Netfilter Configuration
++#
++# CONFIG_NF_DEFRAG_IPV4 is not set
++# CONFIG_NF_LOG_ARP is not set
++# CONFIG_NF_LOG_IPV4 is not set
++# CONFIG_NF_REJECT_IPV4 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_NF_REJECT_IPV6 is not set
++# CONFIG_NF_LOG_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_HAVE_NET_DSA=y
++# 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_PHONET is not set
++# CONFIG_6LOWPAN 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_VSOCKETS is not set
++# CONFIG_NETLINK_MMAP is not set
++# CONFIG_NETLINK_DIAG is not set
++# CONFIG_NET_MPLS_GSO is not set
++# CONFIG_HSR is not set
++CONFIG_RPS=y
++CONFIG_RFS_ACCEL=y
++CONFIG_XPS=y
++# CONFIG_CGROUP_NET_PRIO is not set
++# CONFIG_CGROUP_NET_CLASSID is not set
++CONFIG_NET_RX_BUSY_POLL=y
++CONFIG_BQL=y
++# CONFIG_BPF_JIT is not set
++CONFIG_NET_FLOW_LIMIT=y
++
++#
++# 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 is not set
++# 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 is not set
++CONFIG_DEVTMPFS=y
++# CONFIG_DEVTMPFS_MOUNT is not set
++CONFIG_STANDALONE=y
++# CONFIG_PREVENT_FIRMWARE_BUILD is not set
++CONFIG_FW_LOADER=y
++CONFIG_FIRMWARE_IN_KERNEL=y
++CONFIG_EXTRA_FIRMWARE=""
++# CONFIG_FW_LOADER_USER_HELPER_FALLBACK is not set
++CONFIG_ALLOW_DEV_COREDUMP=y
++# 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_HAVE_CPU_AUTOPROBE is not set
++CONFIG_REGMAP=y
++CONFIG_REGMAP_MMIO=y
++# CONFIG_DMA_SHARED_BUFFER is not set
++
++#
++# Bus devices
++#
++# CONFIG_BRCMSTB_GISB_ARB is not set
++# CONFIG_ARM_CCI is not set
++# CONFIG_VEXPRESS_CONFIG 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=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_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_HIFMC=y
++CONFIG_HIFMC_SPI_NAND=y
++# CONFIG_HIFMC_NAND is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++# CONFIG_MTD_CFI is not set
++# CONFIG_MTD_JEDECPROBE is not set
++CONFIG_MTD_MAP_BANK_WIDTH_1=y
++CONFIG_MTD_MAP_BANK_WIDTH_2=y
++CONFIG_MTD_MAP_BANK_WIDTH_4=y
++# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
++CONFIG_MTD_CFI_I1=y
++CONFIG_MTD_CFI_I2=y
++# CONFIG_MTD_CFI_I4 is not set
++# CONFIG_MTD_CFI_I8 is not set
++# CONFIG_MTD_RAM is not set
++# CONFIG_MTD_ROM is not set
++# CONFIG_MTD_ABSENT is not set
++
++#
++# Mapping drivers for chip access
++#
++# CONFIG_MTD_COMPLEX_MAPPINGS is not set
++# CONFIG_MTD_PLATRAM is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_DATAFLASH is not set
++# CONFIG_MTD_M25P80 is not set
++# CONFIG_MTD_SST25L is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_PHRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++CONFIG_MTD_BLOCK2MTD=y
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOCG3 is not set
++CONFIG_MTD_NAND_IDS=y
++CONFIG_MTD_NAND_ECC=y
++# CONFIG_MTD_NAND_ECC_SMC is not set
++CONFIG_MTD_NAND=y
++# CONFIG_MTD_NAND_ECC_BCH is not set
++# CONFIG_MTD_SM_COMMON is not set
++# CONFIG_MTD_NAND_DENALI is not set
++# CONFIG_MTD_NAND_OMAP_BCH_BUILD is not set
++# CONFIG_MTD_NAND_DISKONCHIP is not set
++# CONFIG_MTD_NAND_DOCG4 is not set
++# CONFIG_MTD_NAND_NANDSIM is not set
++# CONFIG_MTD_NAND_PLATFORM is not set
++# CONFIG_HISI_NAND_FS_MAY_NO_YAFFS2 is not set
++# CONFIG_HISI_NAND_ECC_STATUS_REPORT is not set
++# CONFIG_MTD_NAND_HINFC610 is not set
++# CONFIG_HIFMC100_NAND is not set
++CONFIG_HIFMC100_SPI_NAND=y
++CONFIG_SPI_NAND_MAX_CHIP_NUM=1
++# CONFIG_HIFMC100_HARDWARE_PAGESIZE_ECC is not set
++CONFIG_HIFMC100_AUTO_PAGESIZE_ECC=y
++# CONFIG_HIFMC100_PAGESIZE_AUTO_ECC_NONE is not set
++# CONFIG_MTD_ONENAND is not set
++
++#
++# LPDDR & LPDDR2 PCM memory drivers
++#
++# CONFIG_MTD_LPDDR is not set
++# CONFIG_MTD_LPDDR2_NVM is not set
++CONFIG_MTD_SPI_NOR=y
++# CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set
++CONFIG_SPI_HISI_SFC=y
++CONFIG_CLOSE_SPI_8PIN_4IO=y
++CONFIG_HISI_SPI_BLOCK_PROTECT=y
++CONFIG_MTD_UBI=y
++CONFIG_MTD_UBI_WL_THRESHOLD=4096
++CONFIG_MTD_UBI_BEB_LIMIT=20
++# CONFIG_MTD_UBI_FASTMAP is not set
++# CONFIG_MTD_UBI_GLUEBI is not set
++# CONFIG_MTD_UBI_BLOCK is not set
++CONFIG_DTC=y
++CONFIG_OF=y
++
++#
++# Device Tree and Open Firmware support
++#
++# 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_NET=y
++CONFIG_OF_MDIO=y
++CONFIG_OF_MTD=y
++CONFIG_OF_RESERVED_MEM=y
++CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
++# CONFIG_PARPORT is not set
++CONFIG_BLK_DEV=y
++# CONFIG_BLK_DEV_NULL_BLK is not set
++# CONFIG_BLK_DEV_COW_COMMON is not set
++# CONFIG_BLK_DEV_LOOP 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=65536
++# CONFIG_BLK_DEV_XIP is not set
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH 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_DUMMY_IRQ 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_UID_STAT is not set
++# CONFIG_BMP085_I2C is not set
++# CONFIG_BMP085_SPI is not set
++# CONFIG_USB_SWITCH_FSA9480 is not set
++# CONFIG_LATTICE_ECP3_CONFIG is not set
++# CONFIG_SRAM is not set
++# CONFIG_C2PORT is not set
++
++#
++# EEPROM support
++#
++# CONFIG_EEPROM_AT24 is not set
++# CONFIG_EEPROM_AT25 is not set
++# CONFIG_EEPROM_LEGACY is not set
++# CONFIG_EEPROM_MAX6875 is not set
++# CONFIG_EEPROM_93CX6 is not set
++# CONFIG_EEPROM_93XX46 is not set
++
++#
++# Texas Instruments shared transport line discipline
++#
++# 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
++
++#
++# Intel MIC Bus Driver
++#
++
++#
++# Intel MIC Host Driver
++#
++
++#
++# Intel MIC Card Driver
++#
++# CONFIG_ECHO is not set
++# CONFIG_CXL_BASE is not set
++
++#
++# hisi 'himm/himd.l/himc'support
++#
++# CONFIG_HISI_REG 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_NETLINK is not set
++# CONFIG_SCSI_MQ_DEFAULT is not set
++CONFIG_SCSI_PROC_FS=y
++
++#
++# SCSI support type (disk, tape, CD-ROM)
++#
++CONFIG_BLK_DEV_SD=y
++# CONFIG_CHR_DEV_ST is not set
++# CONFIG_CHR_DEV_OSST is not set
++CONFIG_BLK_DEV_SR=y
++# CONFIG_BLK_DEV_SR_VENDOR is not set
++# CONFIG_CHR_DEV_SG is not set
++# CONFIG_CHR_DEV_SCH is not set
++# CONFIG_SCSI_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 is not set
++# CONFIG_SCSI_DH is not set
++# CONFIG_SCSI_OSD_INITIATOR is not set
++CONFIG_HI_SATA=y
++CONFIG_HI_SATA_IOBASE=0x11010000
++CONFIG_HI_SATA_FBS=1
++CONFIG_HI_SATA_NCQ=1
++CONFIG_ATA=y
++# CONFIG_ATA_NONSTANDARD is not set
++CONFIG_ATA_VERBOSE_ERROR=y
++CONFIG_SATA_PMP=y
++
++#
++# Controllers with non-SFF native interface
++#
++CONFIG_SATA_AHCI_PLATFORM=y
++# CONFIG_ATA_SFF is not set
++# CONFIG_MD 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_NET_TEAM is not set
++# CONFIG_MACVLAN is not set
++# CONFIG_VXLAN is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_TUN is not set
++# CONFIG_VETH is not set
++# CONFIG_NLMON is not set
++
++#
++# 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_NET_DSA_MV88E6171 is not set
++# CONFIG_NET_DSA_BCM_SF2 is not set
++CONFIG_ETHERNET=y
++# CONFIG_ALTERA_TSE is not set
++# CONFIG_NET_XGENE is not set
++# CONFIG_NET_VENDOR_ARC is not set
++# CONFIG_NET_CADENCE is not set
++# CONFIG_NET_VENDOR_BROADCOM is not set
++# CONFIG_NET_VENDOR_CIRRUS is not set
++# CONFIG_DM9000 is not set
++# CONFIG_DNET is not set
++# CONFIG_NET_VENDOR_FARADAY is not set
++CONFIG_NET_VENDOR_HISILICON=y
++# CONFIG_HIX5HD2_GMAC is not set
++# CONFIG_HISI_FEMAC is not set
++CONFIG_HIETH_GMAC=y
++CONFIG_HIGMAC_DESC_4WORD=y
++CONFIG_HIGMAC_RXCSUM=y
++CONFIG_RX_FLOW_CTRL_SUPPORT=y
++CONFIG_TX_FLOW_CTRL_SUPPORT=y
++CONFIG_TX_FLOW_CTRL_PAUSE_TIME=0xFFFF
++CONFIG_TX_FLOW_CTRL_PAUSE_INTERVAL=0xFFFF
++CONFIG_TX_FLOW_CTRL_ACTIVE_THRESHOLD=16
++CONFIG_TX_FLOW_CTRL_DEACTIVE_THRESHOLD=32
++# CONFIG_HIETH_SWITCH_FABRIC is not set
++# CONFIG_NET_VENDOR_INTEL is not set
++# CONFIG_NET_VENDOR_MARVELL is not set
++# CONFIG_NET_VENDOR_MICREL is not set
++# CONFIG_NET_VENDOR_MICROCHIP is not set
++# CONFIG_NET_VENDOR_NATSEMI is not set
++# CONFIG_ETHOC is not set
++# CONFIG_NET_VENDOR_QUALCOMM is not set
++# CONFIG_NET_VENDOR_SAMSUNG is not set
++# CONFIG_NET_VENDOR_SEEQ is not set
++# CONFIG_NET_VENDOR_SMSC is not set
++# CONFIG_NET_VENDOR_STMICRO is not set
++# CONFIG_NET_VENDOR_VIA is not set
++# CONFIG_NET_VENDOR_WIZNET is not set
++CONFIG_PHYLIB=y
++
++#
++# MII PHY device drivers
++#
++# CONFIG_AT803X_PHY is not set
++# CONFIG_AMD_PHY is not set
++# CONFIG_AMD_XGBE_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 is not set
++# CONFIG_BROADCOM_PHY is not set
++# CONFIG_BCM7XXX_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_MMIOREG is not set
++# CONFIG_MDIO_BCM_UNIMAC is not set
++# CONFIG_MDIO_HISI_FEMAC is not set
++CONFIG_MDIO_HISI_GEMAC=y
++# CONFIG_MICREL_KS8995MA is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++CONFIG_USB_NET_DRIVERS=y
++# 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_RTL8152 is not set
++# CONFIG_USB_USBNET is not set
++# CONFIG_USB_IPHETH is not set
++# CONFIG_WLAN is not set
++
++#
++# Enable WiMAX (Networking options) to see the WiMAX drivers
++#
++# CONFIG_WAN is not set
++# CONFIG_ISDN is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
++# CONFIG_INPUT_POLLDEV is not set
++# CONFIG_INPUT_SPARSEKMAP is not set
++# CONFIG_INPUT_MATRIXKMAP is not set
++
++#
++# Userland interfaces
++#
++CONFIG_INPUT_MOUSEDEV=y
++CONFIG_INPUT_MOUSEDEV_PSAUX=y
++CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
++CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
++CONFIG_INPUT_JOYDEV=y
++CONFIG_INPUT_EVDEV=y
++# CONFIG_INPUT_EVBUG is not set
++# CONFIG_INPUT_KEYRESET is not set
++# CONFIG_INPUT_KEYCOMBO 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_TCA6416 is not set
++# CONFIG_KEYBOARD_TCA8418 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 is not set
++# CONFIG_KEYBOARD_CAP1106 is not set
++CONFIG_INPUT_MOUSE=y
++CONFIG_MOUSE_PS2=y
++CONFIG_MOUSE_PS2_ALPS=y
++CONFIG_MOUSE_PS2_LOGIPS2PP=y
++CONFIG_MOUSE_PS2_SYNAPTICS=y
++CONFIG_MOUSE_PS2_CYPRESS=y
++CONFIG_MOUSE_PS2_TRACKPOINT=y
++# CONFIG_MOUSE_PS2_ELANTECH is not set
++# CONFIG_MOUSE_PS2_SENTELIC is not set
++# CONFIG_MOUSE_PS2_TOUCHKIT is not set
++# CONFIG_MOUSE_SERIAL is not set
++# CONFIG_MOUSE_APPLETOUCH is not set
++# CONFIG_MOUSE_BCM5974 is not set
++# CONFIG_MOUSE_CYAPA is not set
++# CONFIG_MOUSE_VSXXXAA is not set
++# CONFIG_MOUSE_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 is not set
++# CONFIG_INPUT_MISC is not set
++
++#
++# Hardware I/O ports
++#
++CONFIG_SERIO=y
++CONFIG_SERIO_SERPORT=y
++# CONFIG_SERIO_AMBAKMI is not set
++CONFIG_SERIO_LIBPS2=y
++# CONFIG_SERIO_RAW is not set
++# CONFIG_SERIO_ALTERA_PS2 is not set
++# CONFIG_SERIO_PS2MULT is not set
++# CONFIG_SERIO_ARC_PS2 is not set
++# CONFIG_SERIO_APBPS2 is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++CONFIG_TTY=y
++CONFIG_VT=y
++CONFIG_CONSOLE_TRANSLATIONS=y
++CONFIG_VT_CONSOLE=y
++CONFIG_VT_CONSOLE_SLEEP=y
++CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
++CONFIG_UNIX98_PTYS=y
++# CONFIG_DEVPTS_MULTIPLE_INSTANCES 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_DEVMEM=y
++# CONFIG_DEVKMEM is not set
++
++#
++# Serial drivers
++#
++CONFIG_SERIAL_EARLYCON=y
++# CONFIG_SERIAL_8250 is not set
++
++#
++# Non-8250 serial port support
++#
++# CONFIG_SERIAL_AMBA_PL010 is not set
++CONFIG_SERIAL_AMBA_PL011=y
++CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
++# CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST is not set
++# 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_SC16IS7XX is not set
++# CONFIG_SERIAL_ALTERA_JTAGUART is not set
++# CONFIG_SERIAL_ALTERA_UART is not set
++# CONFIG_SERIAL_XILINX_PS_UART is not set
++# CONFIG_SERIAL_ARC is not set
++# CONFIG_SERIAL_FSL_LPUART is not set
++# CONFIG_SERIAL_ST_ASC is not set
++# CONFIG_HVC_DCC is not set
++# CONFIG_IPMI_HANDLER is not set
++# CONFIG_HW_RANDOM is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++# CONFIG_DCC_TTY is not set
++# CONFIG_XILLYBUS is not set
++
++#
++# I2C support
++#
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++CONFIG_I2C_COMPAT=y
++CONFIG_I2C_CHARDEV=y
++CONFIG_I2C_MUX=y
++
++#
++# Multiplexer I2C Chip support
++#
++# CONFIG_I2C_MUX_PCA9541 is not set
++# CONFIG_I2C_MUX_PINCTRL is not set
++CONFIG_I2C_HELPER_AUTO=y
++
++#
++# I2C Hardware Bus support
++#
++
++#
++# I2C system bus drivers (mostly embedded / system-on-chip)
++#
++# CONFIG_I2C_DESIGNWARE_PLATFORM is not set
++# CONFIG_I2C_HIBVT is not set
++# CONFIG_I2C_HISI_V110 is not set
++# CONFIG_I2C_NOMADIK 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_RK3X 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_ROBOTFUZZ_OSIF is not set
++# CONFIG_I2C_TAOS_EVM is not set
++# CONFIG_I2C_TINY_USB is not set
++
++#
++# Other I2C/SMBus bus drivers
++#
++CONFIG_HI_I2C=y
++CONFIG_HI_I2C0_IO_BASE=0x120c0000
++CONFIG_HI_I2C0_IO_SIZE=0x1000
++CONFIG_HI_I2C_RETRIES=0x1
++CONFIG_HI_I2C_TX_FIFO=0x8
++CONFIG_HI_I2C_RX_FIFO=0x8
++CONFIG_HI_I2C0_CLK_LIMIT=100000
++# 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_CADENCE is not set
++# CONFIG_SPI_FSL_SPI is not set
++CONFIG_SPI_PL022=y
++# CONFIG_SPI_PXA2XX_PCI is not set
++# CONFIG_SPI_ROCKCHIP 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=y
++# CONFIG_SPI_TLE62X0 is not set
++# CONFIG_SPMI is not set
++# CONFIG_HSI is not set
++
++#
++# PPS support
++#
++# CONFIG_PPS is not set
++
++#
++# PPS generators support
++#
++
++#
++# PTP clock support
++#
++# CONFIG_PTP_1588_CLOCK is not set
++
++#
++# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
++#
++CONFIG_PINCTRL=y
++
++#
++# Pin controllers
++#
++CONFIG_PINMUX=y
++CONFIG_PINCONF=y
++CONFIG_GENERIC_PINCONF=y
++# CONFIG_DEBUG_PINCTRL is not set
++CONFIG_PINCTRL_SINGLE=y
++CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
++CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
++# CONFIG_GPIOLIB is not set
++# CONFIG_W1 is not set
++CONFIG_POWER_SUPPLY=y
++# CONFIG_POWER_SUPPLY_DEBUG is not set
++# CONFIG_PDA_POWER is not set
++# CONFIG_TEST_POWER is not set
++# CONFIG_BATTERY_DS2780 is not set
++# CONFIG_BATTERY_DS2781 is not set
++# CONFIG_BATTERY_DS2782 is not set
++# CONFIG_BATTERY_SBS is not set
++# CONFIG_BATTERY_BQ27x00 is not set
++# CONFIG_BATTERY_MAX17040 is not set
++# CONFIG_BATTERY_MAX17042 is not set
++# CONFIG_CHARGER_MAX8903 is not set
++# CONFIG_CHARGER_LP8727 is not set
++# CONFIG_CHARGER_MANAGER is not set
++# CONFIG_CHARGER_BQ2415X is not set
++# CONFIG_CHARGER_SMB347 is not set
++CONFIG_POWER_RESET=y
++# CONFIG_POWER_RESET_BRCMSTB is not set
++CONFIG_POWER_RESET_HISI=y
++# CONFIG_POWER_RESET_RESTART is not set
++# CONFIG_POWER_RESET_VERSATILE is not set
++# CONFIG_POWER_RESET_SYSCON is not set
++# CONFIG_POWER_AVS is not set
++# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
++# CONFIG_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=y
++# CONFIG_MFD_AS3711 is not set
++# CONFIG_MFD_AS3722 is not set
++# CONFIG_PMIC_ADP5520 is not set
++# CONFIG_MFD_BCM590XX is not set
++# CONFIG_MFD_AXP20X is not set
++# CONFIG_MFD_CROS_EC is not set
++# CONFIG_PMIC_DA903X is not set
++# CONFIG_MFD_DA9052_SPI is not set
++# CONFIG_MFD_DA9052_I2C is not set
++# CONFIG_MFD_DA9055 is not set
++# CONFIG_MFD_DA9063 is not set
++# CONFIG_MFD_MC13XXX_SPI is not set
++# CONFIG_MFD_MC13XXX_I2C is not set
++# CONFIG_MFD_HI6421_PMIC is not set
++CONFIG_MFD_HISI_FMC=y
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_INTEL_SOC_PMIC is not set
++# CONFIG_MFD_KEMPLD is not set
++# CONFIG_MFD_88PM800 is not set
++# CONFIG_MFD_88PM805 is not set
++# CONFIG_MFD_88PM860X is not set
++# CONFIG_MFD_MAX14577 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_MENF21BMC is not set
++# CONFIG_EZX_PCAP is not set
++# CONFIG_MFD_VIPERBOARD is not set
++# CONFIG_MFD_RETU is not set
++# CONFIG_MFD_PCF50633 is not set
++# CONFIG_MFD_PM8921_CORE is not set
++# CONFIG_MFD_RTSX_USB is not set
++# CONFIG_MFD_RC5T583 is not set
++# CONFIG_MFD_RK808 is not set
++# CONFIG_MFD_RN5T618 is not set
++# CONFIG_MFD_SEC_CORE is not set
++# CONFIG_MFD_SI476X_CORE is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_MFD_SMSC is not set
++# CONFIG_ABX500_CORE is not set
++# CONFIG_MFD_STMPE is not set
++CONFIG_MFD_SYSCON=y
++# CONFIG_MFD_TI_AM335X_TSCADC is not set
++# CONFIG_MFD_LP3943 is not set
++# CONFIG_MFD_LP8788 is not set
++# CONFIG_MFD_PALMAS is not set
++# CONFIG_TPS6105X is not set
++# CONFIG_TPS6507X is not set
++# CONFIG_MFD_TPS65090 is not set
++# CONFIG_MFD_TPS65217 is not set
++# CONFIG_MFD_TPS65218 is not set
++# CONFIG_MFD_TPS6586X is not set
++# CONFIG_MFD_TPS80031 is not set
++# CONFIG_TWL4030_CORE is not set
++# CONFIG_TWL6040_CORE is not set
++# CONFIG_MFD_WL1273_CORE is not set
++# CONFIG_MFD_LM3533 is not set
++# CONFIG_MFD_TC3589X is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_MFD_T7L66XB is not set
++# CONFIG_MFD_TC6387XB is not set
++# CONFIG_MFD_TC6393XB is not set
++# CONFIG_MFD_ARIZONA_I2C is not set
++# CONFIG_MFD_ARIZONA_SPI is not set
++# CONFIG_MFD_WM8400 is not set
++# CONFIG_MFD_WM831X_I2C is not set
++# CONFIG_MFD_WM831X_SPI is not set
++# CONFIG_MFD_WM8350_I2C is not set
++# CONFIG_MFD_WM8994 is not set
++CONFIG_REGULATOR=y
++# CONFIG_REGULATOR_DEBUG is not set
++# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
++# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
++# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
++# CONFIG_REGULATOR_ACT8865 is not set
++# CONFIG_REGULATOR_AD5398 is not set
++# CONFIG_REGULATOR_ANATOP is not set
++# CONFIG_REGULATOR_DA9210 is not set
++# CONFIG_REGULATOR_DA9211 is not set
++# CONFIG_REGULATOR_FAN53555 is not set
++# CONFIG_REGULATOR_ISL9305 is not set
++# CONFIG_REGULATOR_ISL6271A is not set
++# CONFIG_REGULATOR_LP3971 is not set
++# CONFIG_REGULATOR_LP3972 is not set
++# CONFIG_REGULATOR_LP872X is not set
++# CONFIG_REGULATOR_LP8755 is not set
++# CONFIG_REGULATOR_LTC3589 is not set
++# CONFIG_REGULATOR_MAX1586 is not set
++# CONFIG_REGULATOR_MAX8649 is not set
++# CONFIG_REGULATOR_MAX8660 is not set
++# CONFIG_REGULATOR_MAX8952 is not set
++# CONFIG_REGULATOR_MAX8973 is not set
++# CONFIG_REGULATOR_PFUZE100 is not set
++# CONFIG_REGULATOR_TPS51632 is not set
++# CONFIG_REGULATOR_TPS62360 is not set
++# CONFIG_REGULATOR_TPS65023 is not set
++# CONFIG_REGULATOR_TPS6507X is not set
++# CONFIG_REGULATOR_TPS6524X is not set
++# CONFIG_MEDIA_SUPPORT is not set
++
++#
++# Graphics support
++#
++# CONFIG_IMX_IPUV3_CORE is not set
++
++#
++# Direct Rendering Manager
++#
++# CONFIG_DRM is not set
++
++#
++# Frame buffer Devices
++#
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++CONFIG_FB_CMDLINE=y
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++# CONFIG_FB_CFB_FILLRECT is not set
++# CONFIG_FB_CFB_COPYAREA is not set
++# CONFIG_FB_CFB_IMAGEBLIT is not set
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# 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_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_ARMCLCD is not set
++# CONFIG_FB_OPENCORES is not set
++# CONFIG_FB_S1D13XXX is not set
++# CONFIG_FB_SMSCUFX is not set
++# CONFIG_FB_UDL is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_BROADSHEET is not set
++# CONFIG_FB_AUO_K190X is not set
++# CONFIG_FB_SIMPLE is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++# CONFIG_VGASTATE is not set
++
++#
++# Console display driver support
++#
++CONFIG_DUMMY_CONSOLE=y
++# CONFIG_FRAMEBUFFER_CONSOLE is not set
++# CONFIG_LOGO is not set
++# CONFIG_SOUND is not set
++
++#
++# HID support
++#
++CONFIG_HID=y
++# CONFIG_HID_BATTERY_STRENGTH is not set
++# CONFIG_HIDRAW is not set
++# CONFIG_UHID is not set
++CONFIG_HID_GENERIC=y
++
++#
++# Special HID drivers
++#
++CONFIG_HID_A4TECH=y
++# CONFIG_HID_ACRUX is not set
++CONFIG_HID_APPLE=y
++# CONFIG_HID_APPLEIR is not set
++# CONFIG_HID_AUREAL is not set
++CONFIG_HID_BELKIN=y
++CONFIG_HID_CHERRY=y
++CONFIG_HID_CHICONY=y
++CONFIG_HID_CYPRESS=y
++# CONFIG_HID_DRAGONRISE is not set
++# CONFIG_HID_EMS_FF is not set
++# CONFIG_HID_ELECOM is not set
++# CONFIG_HID_ELO is not set
++CONFIG_HID_EZKEY=y
++# CONFIG_HID_HOLTEK is not set
++# CONFIG_HID_HUION 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_ICADE is not set
++# CONFIG_HID_TWINHAN is not set
++CONFIG_HID_KENSINGTON=y
++# CONFIG_HID_LCPOWER is not set
++# CONFIG_HID_LENOVO is not set
++CONFIG_HID_LOGITECH=y
++# CONFIG_HID_LOGITECH_HIDPP is not set
++# CONFIG_LOGITECH_FF is not set
++# CONFIG_LOGIRUMBLEPAD2_FF is not set
++# CONFIG_LOGIG940_FF is not set
++# CONFIG_LOGIWHEELS_FF is not set
++# CONFIG_HID_MAGICMOUSE is not set
++CONFIG_HID_MICROSOFT=y
++CONFIG_HID_MONTEREY=y
++# 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_PENMOUNT is not set
++# CONFIG_HID_PETALYNX is not set
++# CONFIG_HID_PICOLCD is not set
++# CONFIG_HID_PRIMAX is not set
++# CONFIG_HID_ROCCAT is not set
++# CONFIG_HID_SAITEK is not set
++# CONFIG_HID_SAMSUNG is not set
++# CONFIG_HID_SPEEDLINK is not set
++# CONFIG_HID_STEELSERIES is not set
++# CONFIG_HID_SUNPLUS is not set
++# CONFIG_HID_RMI 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_XINMO is not set
++# CONFIG_HID_ZEROPLUS is not set
++# CONFIG_HID_ZYDACRON is not set
++# CONFIG_HID_SENSOR_HUB is not set
++
++#
++# USB HID support
++#
++CONFIG_USB_HID=y
++# CONFIG_HID_PID is not set
++# CONFIG_USB_HIDDEV is not set
++
++#
++# I2C HID support
++#
++# CONFIG_I2C_HID is not set
++CONFIG_USB_OHCI_LITTLE_ENDIAN=y
++CONFIG_USB_SUPPORT=y
++CONFIG_USB_COMMON=y
++CONFIG_USB_ARCH_HAS_HCD=y
++CONFIG_USB=y
++# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
++
++#
++# Miscellaneous USB options
++#
++CONFIG_USB_DEFAULT_PERSIST=y
++# CONFIG_USB_DYNAMIC_MINORS is not set
++# CONFIG_USB_OTG_WHITELIST is not set
++# CONFIG_USB_OTG_FSM is not set
++# CONFIG_USB_MON is not set
++# CONFIG_USB_WUSB_CBAF is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_C67X00_HCD is not set
++# CONFIG_USB_XHCI_HCD is not set
++CONFIG_USB_EHCI_HCD=y
++# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
++CONFIG_USB_EHCI_TT_NEWSCHED=y
++CONFIG_USB_EHCI_HCD_PLATFORM=y
++# 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_FUSBH200_HCD is not set
++# CONFIG_USB_FOTG210_HCD is not set
++# CONFIG_USB_MAX3421_HCD is not set
++CONFIG_USB_OHCI_HCD=y
++CONFIG_USB_OHCI_HCD_PLATFORM=y
++# CONFIG_USB_SL811_HCD is not set
++# CONFIG_USB_R8A66597_HCD is not set
++# CONFIG_USB_HCD_TEST_MODE is not set
++
++#
++# USB Device Class drivers
++#
++# CONFIG_USB_ACM is not set
++# CONFIG_USB_PRINTER is not set
++# CONFIG_USB_WDM is not set
++# CONFIG_USB_TMC is not set
++
++#
++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
++#
++
++#
++# also be needed; see USB_STORAGE Help for more info
++#
++CONFIG_USB_STORAGE=y
++# CONFIG_USB_STORAGE_DEBUG is not set
++# CONFIG_USB_STORAGE_REALTEK is not set
++# CONFIG_USB_STORAGE_DATAFAB is not set
++# CONFIG_USB_STORAGE_FREECOM is not set
++# CONFIG_USB_STORAGE_ISD200 is not set
++# CONFIG_USB_STORAGE_USBAT is not set
++# CONFIG_USB_STORAGE_SDDR09 is not set
++# CONFIG_USB_STORAGE_SDDR55 is not set
++# CONFIG_USB_STORAGE_JUMPSHOT is not set
++# CONFIG_USB_STORAGE_ALAUDA is not set
++# CONFIG_USB_STORAGE_ONETOUCH is not set
++# CONFIG_USB_STORAGE_KARMA is not set
++# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
++# CONFIG_USB_STORAGE_ENE_UB6250 is not set
++# CONFIG_USB_UAS is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++# CONFIG_USBIP_CORE is not set
++# CONFIG_USB_MUSB_HDRC is not set
++# CONFIG_USB_DWC3 is not set
++# CONFIG_USB_DWC2 is not set
++# CONFIG_USB_CHIPIDEA is not set
++
++#
++# USB port drivers
++#
++# CONFIG_USB_SERIAL is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
++# CONFIG_USB_SEVSEG is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
++# CONFIG_USB_APPLEDISPLAY is not set
++# CONFIG_USB_SISUSBVGA is not set
++# CONFIG_USB_LD is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
++# CONFIG_USB_IOWARRIOR is not set
++# CONFIG_USB_TEST is not set
++# CONFIG_USB_EHSET_TEST_FIXTURE is not set
++# CONFIG_USB_ISIGHTFW is not set
++# CONFIG_USB_YUREX is not set
++# CONFIG_USB_EZUSB_FX2 is not set
++# CONFIG_USB_HSIC_USB3503 is not set
++# CONFIG_USB_LINK_LAYER_TEST is not set
++
++#
++# USB Physical Layer drivers
++#
++# CONFIG_USB_PHY is not set
++# CONFIG_USB_OTG_WAKELOCK is not set
++# CONFIG_NOP_USB_XCEIV is not set
++# CONFIG_AM335X_PHY_USB is not set
++# CONFIG_USB_ISP1301 is not set
++# CONFIG_USB_ULPI is not set
++# CONFIG_USB_GADGET is not set
++# CONFIG_UWB is not set
++# CONFIG_MMC is not set
++# CONFIG_MEMSTICK is not set
++# CONFIG_NEW_LEDS is not set
++# CONFIG_SWITCH is not set
++# CONFIG_ACCESSIBILITY is not set
++# CONFIG_EDAC is not set
++CONFIG_RTC_LIB=y
++CONFIG_RTC_CLASS=y
++CONFIG_RTC_HCTOSYS=y
++CONFIG_RTC_SYSTOHC=y
++CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
++# CONFIG_RTC_DEBUG is not set
++
++#
++# RTC interfaces
++#
++CONFIG_RTC_INTF_SYSFS=y
++CONFIG_RTC_INTF_PROC=y
++CONFIG_RTC_INTF_DEV=y
++# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
++# CONFIG_RTC_DRV_TEST is not set
++
++#
++# I2C RTC drivers
++#
++# CONFIG_RTC_DRV_DS1307 is not set
++# CONFIG_RTC_DRV_DS1374 is not set
++# CONFIG_RTC_DRV_DS1672 is not set
++# CONFIG_RTC_DRV_DS3232 is not set
++# CONFIG_RTC_DRV_HYM8563 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_ISL12057 is not set
++# CONFIG_RTC_DRV_X1205 is not set
++# CONFIG_RTC_DRV_PCF2127 is not set
++# CONFIG_RTC_DRV_PCF8523 is not set
++# CONFIG_RTC_DRV_PCF8563 is not set
++# CONFIG_RTC_DRV_PCF85063 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_DS1343 is not set
++# CONFIG_RTC_DRV_DS1347 is not set
++# CONFIG_RTC_DRV_DS1390 is not set
++# CONFIG_RTC_DRV_MAX6902 is not set
++# CONFIG_RTC_DRV_R9701 is not set
++# CONFIG_RTC_DRV_RS5C348 is not set
++# CONFIG_RTC_DRV_DS3234 is not set
++# CONFIG_RTC_DRV_PCF2123 is not set
++# CONFIG_RTC_DRV_RX4581 is not set
++# CONFIG_RTC_DRV_MCP795 is not set
++
++#
++# Platform RTC drivers
++#
++CONFIG_RTC_DRV_HIBVT=y
++# 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_DS2404 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
++
++#
++# on-CPU RTC drivers
++#
++# CONFIG_RTC_DRV_PL030 is not set
++# CONFIG_RTC_DRV_PL031 is not set
++# CONFIG_RTC_DRV_SNVS is not set
++# CONFIG_RTC_DRV_XGENE is not set
++
++#
++# HID Sensor RTC drivers
++#
++# CONFIG_RTC_DRV_HID_SENSOR_TIME is not set
++# CONFIG_DMADEVICES is not set
++# CONFIG_AUXDISPLAY is not set
++# CONFIG_UIO is not set
++# CONFIG_VIRT_DRIVERS is not set
++
++#
++# Virtio drivers
++#
++# CONFIG_VIRTIO_MMIO is not set
++
++#
++# Microsoft Hyper-V guest support
++#
++# CONFIG_STAGING is not set
++
++#
++# SOC (System On Chip) specific Drivers
++#
++# CONFIG_SOC_TI is not set
++CONFIG_CLKDEV_LOOKUP=y
++CONFIG_HAVE_CLK_PREPARE=y
++CONFIG_COMMON_CLK=y
++
++#
++# Common Clock Framework
++#
++# CONFIG_COMMON_CLK_SI5351 is not set
++# CONFIG_COMMON_CLK_SI570 is not set
++# CONFIG_COMMON_CLK_PXA is not set
++# CONFIG_COMMON_CLK_QCOM is not set
++
++#
++# Hardware Spinlock drivers
++#
++
++#
++# Clock Source drivers
++#
++CONFIG_CLKSRC_OF=y
++CONFIG_CLKSRC_MMIO=y
++CONFIG_ARM_ARCH_TIMER=y
++CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y
++# CONFIG_ARM_ARCH_TIMER_VCT_ACCESS is not set
++# CONFIG_ATMEL_PIT is not set
++# CONFIG_SH_TIMER_CMT is not set
++# CONFIG_SH_TIMER_MTU2 is not set
++# CONFIG_SH_TIMER_TMU is not set
++# CONFIG_EM_TIMER_STI is not set
++# CONFIG_CLKSRC_VERSATILE is not set
++# CONFIG_MAILBOX is not set
++# CONFIG_IOMMU_SUPPORT is not set
++
++#
++# Remoteproc drivers
++#
++# CONFIG_STE_MODEM_RPROC is not set
++
++#
++# Rpmsg drivers
++#
++
++#
++# SOC (System On Chip) specific Drivers
++#
++# 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
++CONFIG_IRQCHIP=y
++CONFIG_ARM_GIC=y
++# CONFIG_IPACK_BUS is not set
++CONFIG_ARCH_HAS_RESET_CONTROLLER=y
++CONFIG_RESET_CONTROLLER=y
++# CONFIG_FMC is not set
++
++#
++# PHY Subsystem
++#
++CONFIG_GENERIC_PHY=y
++# CONFIG_BCM_KONA_USB2_PHY is not set
++CONFIG_PHY_HISI_INNO_USB2=y
++CONFIG_HI_NANO_PHY_SATA=y
++CONFIG_HI_SATA_PORTS=2
++CONFIG_HI_SATA_MODE=1
++# CONFIG_POWERCAP is not set
++# CONFIG_MCB is not set
++CONFIG_HI_DMAC=y
++CONFIG_HI_DMAC_CHANNEL_NUM=4
++
++#
++# Hisilicon driver support
++#
++
++#
++# File systems
++#
++CONFIG_DCACHE_WORD_ACCESS=y
++# CONFIG_EXT2_FS is not set
++# CONFIG_EXT3_FS is not set
++CONFIG_EXT4_FS=y
++CONFIG_EXT4_USE_FOR_EXT23=y
++# CONFIG_EXT4_FS_POSIX_ACL is not set
++# CONFIG_EXT4_FS_SECURITY is not set
++# CONFIG_EXT4_DEBUG is not set
++CONFIG_JBD2=y
++# CONFIG_JBD2_DEBUG is not set
++CONFIG_FS_MBCACHE=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_BTRFS_FS is not set
++# CONFIG_NILFS2_FS is not set
++CONFIG_FS_POSIX_ACL=y
++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 is not set
++# CONFIG_FUSE_FS is not set
++# CONFIG_OVERLAY_FS is not set
++
++#
++# Caches
++#
++# CONFIG_FSCACHE is not set
++
++#
++# CD-ROM/DVD Filesystems
++#
++CONFIG_ISO9660_FS=y
++# CONFIG_JOLIET is not set
++# CONFIG_ZISOFS 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_KERNFS=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=m
++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_YAFFS_FS=y
++CONFIG_YAFFS_YAFFS1=y
++# CONFIG_YAFFS_9BYTE_TAGS is not set
++# CONFIG_YAFFS_DOES_ECC is not set
++CONFIG_YAFFS_YAFFS2=y
++CONFIG_YAFFS_AUTO_YAFFS2=y
++# CONFIG_YAFFS_DISABLE_TAGS_ECC is not set
++# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
++# CONFIG_YAFFS_EMPTY_LOST_AND_FOUND is not set
++# CONFIG_YAFFS_DISABLE_BLOCK_REFRESHING is not set
++# CONFIG_YAFFS_DISABLE_BACKGROUND is not set
++# CONFIG_YAFFS_DISABLE_BAD_BLOCK_MARKING is not set
++CONFIG_YAFFS_XATTR=y
++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 is not set
++# CONFIG_JFFS2_FS_XATTR is not set
++# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
++CONFIG_JFFS2_ZLIB=y
++# CONFIG_JFFS2_LZO is not set
++CONFIG_JFFS2_RTIME=y
++# CONFIG_JFFS2_RUBIN 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 is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V2=y
++CONFIG_NFS_V3=y
++CONFIG_NFS_V3_ACL=y
++# CONFIG_NFS_V4 is not set
++# CONFIG_NFS_SWAP is not set
++# CONFIG_ROOT_NFS is not set
++# CONFIG_NFSD is not set
++CONFIG_GRACE_PERIOD=y
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_ACL_SUPPORT=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 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=y
++# CONFIG_DLM is not set
++
++#
++# Kernel hacking
++#
++
++#
++# printk and dmesg options
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4
++# CONFIG_BOOT_PRINTK_DELAY is not set
++
++#
++# Compile-time checks and compiler options
++#
++# CONFIG_DEBUG_INFO is not set
++# CONFIG_ENABLE_WARN_DEPRECATED is not set
++# CONFIG_ENABLE_MUST_CHECK is not set
++CONFIG_FRAME_WARN=1024
++# CONFIG_STRIP_ASM_SYMS is not set
++# CONFIG_READABLE_ASM is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++# CONFIG_DEBUG_FS is not set
++# CONFIG_HEADERS_CHECK is not set
++# CONFIG_DEBUG_SECTION_MISMATCH is not set
++# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
++# CONFIG_MAGIC_SYSRQ is not set
++CONFIG_DEBUG_KERNEL=y
++
++#
++# Memory Debugging
++#
++# CONFIG_DEBUG_PAGEALLOC is not set
++# 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_STACK_USAGE is not set
++# CONFIG_DEBUG_VM is not set
++CONFIG_DEBUG_MEMORY_INIT=y
++# CONFIG_DEBUG_PER_CPU_MAPS is not set
++# CONFIG_DEBUG_HIGHMEM is not set
++# CONFIG_DEBUG_SHIRQ is not set
++
++#
++# Debug Lockups and Hangs
++#
++# CONFIG_LOCKUP_DETECTOR is not set
++# CONFIG_DETECT_HUNG_TASK is not set
++# CONFIG_PANIC_ON_OOPS is not set
++CONFIG_PANIC_ON_OOPS_VALUE=0
++CONFIG_PANIC_TIMEOUT=0
++CONFIG_SCHED_DEBUG=y
++# CONFIG_SCHEDSTATS is not set
++# CONFIG_SCHED_STACK_END_CHECK is not set
++# CONFIG_TIMER_STATS is not set
++
++#
++# Lock Debugging (spinlocks, mutexes, etc...)
++#
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_LOCK_STAT is not set
++# CONFIG_DEBUG_ATOMIC_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_LOCK_TORTURE_TEST is not set
++CONFIG_STACKTRACE=y
++# CONFIG_DEBUG_KOBJECT is not set
++CONFIG_DEBUG_BUGVERBOSE=y
++# CONFIG_DEBUG_LIST is not set
++# CONFIG_DEBUG_PI_LIST is not set
++# CONFIG_DEBUG_SG is not set
++# CONFIG_DEBUG_NOTIFIERS is not set
++# CONFIG_DEBUG_CREDENTIALS is not set
++
++#
++# RCU Debugging
++#
++# CONFIG_SPARSE_RCU_POINTER is not set
++# CONFIG_TORTURE_TEST 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_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_NOTIFIER_ERROR_INJECTION is not set
++# CONFIG_FAULT_INJECTION 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 is not set
++
++#
++# Runtime Testing
++#
++# CONFIG_TEST_LIST_SORT is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_RBTREE_TEST is not set
++# CONFIG_INTERVAL_TREE_TEST is not set
++# CONFIG_PERCPU_TEST is not set
++# CONFIG_ATOMIC64_SELFTEST is not set
++# CONFIG_TEST_STRING_HELPERS is not set
++# CONFIG_TEST_KSTRTOX is not set
++# CONFIG_TEST_RHASHTABLE is not set
++# CONFIG_DMA_API_DEBUG is not set
++# CONFIG_TEST_LKM is not set
++# CONFIG_TEST_USER_COPY is not set
++# CONFIG_TEST_BPF is not set
++# CONFIG_TEST_FIRMWARE is not set
++# CONFIG_TEST_UDELAY is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_KGDB is not set
++# CONFIG_ARM_PTDUMP is not set
++CONFIG_STRICT_DEVMEM=y
++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_DEBUG_UART_PL01X is not set
++# CONFIG_DEBUG_UART_8250 is not set
++# CONFIG_DEBUG_UART_BCM63XX is not set
++CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"
++# CONFIG_OC_ETM is not set
++# CONFIG_PID_IN_CONTEXTIDR is not set
++# CONFIG_DEBUG_SET_MODULE_RONX is not set
++# CONFIG_CORESIGHT is not set
++
++#
++# 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_HASH=y
++CONFIG_CRYPTO_HASH2=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_PCRYPT is not set
++# CONFIG_CRYPTO_CRYPTD is not set
++# CONFIG_CRYPTO_MCRYPTD 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_CMAC is not set
++# CONFIG_CRYPTO_HMAC is not set
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_VMAC is not set
++
++#
++# Digest
++#
++CONFIG_CRYPTO_CRC32C=y
++# CONFIG_CRYPTO_CRC32 is not set
++# CONFIG_CRYPTO_CRCT10DIF 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_SHA1_ARM_NEON is not set
++# CONFIG_CRYPTO_SHA256 is not set
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_SHA512_ARM_NEON 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_AES_ARM_BS 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=y
++# CONFIG_CRYPTO_ZLIB is not set
++CONFIG_CRYPTO_LZO=y
++# CONFIG_CRYPTO_LZ4 is not set
++# CONFIG_CRYPTO_LZ4HC is not set
++
++#
++# Random Number Generation
++#
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++# CONFIG_CRYPTO_DRBG_MENU is not set
++# CONFIG_CRYPTO_USER_API_HASH is not set
++# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
++CONFIG_CRYPTO_HW=y
++# CONFIG_BINARY_PRINTF is not set
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++CONFIG_GENERIC_STRNCPY_FROM_USER=y
++CONFIG_GENERIC_STRNLEN_USER=y
++CONFIG_GENERIC_NET_UTILS=y
++CONFIG_GENERIC_PCI_IOMAP=y
++CONFIG_GENERIC_IO=y
++CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
++# CONFIG_CRC_CCITT is not set
++CONFIG_CRC16=y
++# CONFIG_CRC_T10DIF is not set
++# 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_AUDIT_ARCH_COMPAT_GENERIC is not set
++# CONFIG_RANDOM32_SELFTEST is not set
++CONFIG_ZLIB_INFLATE=y
++CONFIG_ZLIB_DEFLATE=y
++CONFIG_LZO_COMPRESS=y
++CONFIG_LZO_DECOMPRESS=y
++CONFIG_LZ4_DECOMPRESS=y
++CONFIG_XZ_DEC=y
++CONFIG_XZ_DEC_X86=y
++CONFIG_XZ_DEC_POWERPC=y
++CONFIG_XZ_DEC_IA64=y
++CONFIG_XZ_DEC_ARM=y
++CONFIG_XZ_DEC_ARMTHUMB=y
++CONFIG_XZ_DEC_SPARC=y
++CONFIG_XZ_DEC_BCJ=y
++# CONFIG_XZ_DEC_TEST is not set
++CONFIG_DECOMPRESS_GZIP=y
++CONFIG_DECOMPRESS_BZIP2=y
++CONFIG_DECOMPRESS_LZMA=y
++CONFIG_DECOMPRESS_XZ=y
++CONFIG_DECOMPRESS_LZO=y
++CONFIG_DECOMPRESS_LZ4=y
++CONFIG_GENERIC_ALLOCATOR=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT_MAP=y
++CONFIG_HAS_DMA=y
++CONFIG_CPU_RMAP=y
++CONFIG_DQL=y
++CONFIG_GLOB=y
++# CONFIG_GLOB_SELFTEST is not set
++CONFIG_NLATTR=y
++CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
++# CONFIG_AVERAGE is not set
++# CONFIG_CORDIC is not set
++# CONFIG_DDR is not set
++CONFIG_LIBFDT=y
++CONFIG_ARCH_HAS_SG_CHAIN=y
++# CONFIG_VIRTUALIZATION is not set
+diff --git a/arch/arm/configs/hi3556_single_defconfig b/arch/arm/configs/hi3556_single_defconfig
+new file mode 100644
+index 0000000..1260690
+--- /dev/null
++++ b/arch/arm/configs/hi3556_single_defconfig
+@@ -0,0 +1,2617 @@
++#
++# Automatically generated file; DO NOT EDIT.
++# Linux/arm 3.18.20 Kernel Configuration
++#
++CONFIG_ARM=y
++CONFIG_ARM_HAS_SG_CHAIN=y
++CONFIG_MIGHT_HAVE_PCI=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=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_XCHGADD_ALGORITHM=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_NEED_DMA_MAP_STATE=y
++CONFIG_ARCH_SUPPORTS_UPROBES=y
++CONFIG_VECTORS_BASE=0xffff0000
++CONFIG_ARM_PATCH_PHYS_VIRT=y
++CONFIG_GENERIC_BUG=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++CONFIG_IRQ_WORK=y
++CONFIG_BUILDTIME_EXTABLE_SORT=y
++
++#
++# General setup
++#
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_CROSS_COMPILE=""
++# CONFIG_COMPILE_TEST is not set
++CONFIG_LOCALVERSION=""
++# CONFIG_LOCALVERSION_AUTO is not set
++CONFIG_HAVE_KERNEL_GZIP=y
++CONFIG_HAVE_KERNEL_LZMA=y
++CONFIG_HAVE_KERNEL_XZ=y
++CONFIG_HAVE_KERNEL_LZO=y
++CONFIG_HAVE_KERNEL_LZ4=y
++CONFIG_KERNEL_GZIP=y
++# CONFIG_KERNEL_LZMA is not set
++# CONFIG_KERNEL_XZ is not set
++# CONFIG_KERNEL_LZO is not set
++# CONFIG_KERNEL_LZ4 is not set
++# CONFIG_HW_DECOMPRESS is not set
++CONFIG_SOFT_DECOMPRESS=y
++CONFIG_DEFAULT_HOSTNAME="(none)"
++CONFIG_SWAP=y
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++# CONFIG_POSIX_MQUEUE is not set
++CONFIG_CROSS_MEMORY_ATTACH=y
++# CONFIG_FHANDLE is not set
++CONFIG_USELIB=y
++# CONFIG_AUDIT is not set
++CONFIG_HAVE_ARCH_AUDITSYSCALL=y
++
++#
++# IRQ subsystem
++#
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_GENERIC_IRQ_SHOW=y
++CONFIG_HARDIRQS_SW_RESEND=y
++CONFIG_IRQ_DOMAIN=y
++CONFIG_HANDLE_DOMAIN_IRQ=y
++CONFIG_IRQ_FORCED_THREADING=y
++CONFIG_SPARSE_IRQ=y
++CONFIG_GENERIC_CLOCKEVENTS=y
++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
++
++#
++# Timers subsystem
++#
++CONFIG_TICK_ONESHOT=y
++CONFIG_NO_HZ_COMMON=y
++# CONFIG_HZ_PERIODIC is not set
++CONFIG_NO_HZ_IDLE=y
++CONFIG_NO_HZ=y
++# CONFIG_HIGH_RES_TIMERS is not set
++
++#
++# CPU/Task time and stats accounting
++#
++CONFIG_TICK_CPU_ACCOUNTING=y
++# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set
++# CONFIG_IRQ_TIME_ACCOUNTING is not set
++# CONFIG_BSD_PROCESS_ACCT is not set
++# CONFIG_TASKSTATS is not set
++
++#
++# RCU Subsystem
++#
++CONFIG_TINY_RCU=y
++# CONFIG_PREEMPT_RCU is not set
++# CONFIG_TASKS_RCU is not set
++# CONFIG_RCU_STALL_COMMON is not set
++# CONFIG_TREE_RCU_TRACE is not set
++# CONFIG_BUILD_BIN2C is not set
++# CONFIG_IKCONFIG is not set
++CONFIG_LOG_BUF_SHIFT=17
++CONFIG_GENERIC_SCHED_CLOCK=y
++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_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_USER_NS is not set
++CONFIG_PID_NS=y
++CONFIG_NET_NS=y
++# 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=y
++CONFIG_RD_LZMA=y
++CONFIG_RD_XZ=y
++CONFIG_RD_LZO=y
++CONFIG_RD_LZ4=y
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++CONFIG_HAVE_UID16=y
++CONFIG_BPF=y
++# CONFIG_EXPERT is not set
++CONFIG_UID16=y
++# CONFIG_SGETMASK_SYSCALL is not set
++CONFIG_SYSFS_SYSCALL=y
++# CONFIG_SYSCTL_SYSCALL is not set
++CONFIG_KALLSYMS=y
++# CONFIG_KALLSYMS_ALL is not set
++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_BPF_SYSCALL is not set
++CONFIG_SHMEM=y
++CONFIG_AIO=y
++CONFIG_ADVISE_SYSCALLS=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 is not set
++# CONFIG_SLAB is not set
++CONFIG_SLUB=y
++# CONFIG_PROFILING is not set
++CONFIG_HAVE_OPROFILE=y
++# CONFIG_KPROBES is not set
++# CONFIG_JUMP_LABEL is not set
++# CONFIG_UPROBES is not set
++# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
++CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
++CONFIG_ARCH_USE_BUILTIN_BSWAP=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_GENERIC_SMP_IDLE_THREAD=y
++CONFIG_GENERIC_IDLE_POLL_SETUP=y
++CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
++CONFIG_HAVE_CLK=y
++CONFIG_HAVE_DMA_API_DEBUG=y
++CONFIG_HAVE_PERF_REGS=y
++CONFIG_HAVE_PERF_USER_STACK_DUMP=y
++CONFIG_HAVE_ARCH_JUMP_LABEL=y
++CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
++CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
++CONFIG_HAVE_CC_STACKPROTECTOR=y
++# CONFIG_CC_STACKPROTECTOR is not set
++CONFIG_CC_STACKPROTECTOR_NONE=y
++# CONFIG_CC_STACKPROTECTOR_REGULAR is not set
++# CONFIG_CC_STACKPROTECTOR_STRONG is not set
++CONFIG_HAVE_CONTEXT_TRACKING=y
++CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
++CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
++CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
++CONFIG_MODULES_USE_ELF_REL=y
++CONFIG_CLONE_BACKWARDS=y
++CONFIG_OLD_SIGSUSPEND3=y
++CONFIG_OLD_SIGACTION=y
++
++#
++# GCOV-based kernel profiling
++#
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_SLABINFO=y
++CONFIG_RT_MUTEXES=y
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++# CONFIG_MODULE_FORCE_LOAD is not set
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++# CONFIG_MODULE_SIG is not set
++# CONFIG_MODULE_COMPRESS is not set
++CONFIG_BLOCK=y
++CONFIG_LBDAF=y
++CONFIG_BLK_DEV_BSG=y
++# CONFIG_BLK_DEV_BSGLIB is not set
++# CONFIG_BLK_DEV_INTEGRITY is not set
++CONFIG_BLK_CMDLINE_PARSER=y
++
++#
++# Partition Types
++#
++CONFIG_PARTITION_ADVANCED=y
++# CONFIG_ACORN_PARTITION is not set
++# CONFIG_AIX_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=y
++# CONFIG_SYSV68_PARTITION is not set
++CONFIG_CMDLINE_PARTITION=y
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++CONFIG_DEFAULT_DEADLINE=y
++# CONFIG_DEFAULT_CFQ is not set
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="deadline"
++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_ARCH_SUPPORTS_ATOMIC_RMW=y
++CONFIG_FREEZER=y
++
++#
++# System Type
++#
++CONFIG_MMU=y
++CONFIG_ARCH_MULTIPLATFORM=y
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_AT91 is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_GEMINI is not set
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_IOP13XX is not set
++# CONFIG_ARCH_IOP32X is not set
++# CONFIG_ARCH_IOP33X is not set
++# CONFIG_ARCH_IXP4XX is not set
++# CONFIG_ARCH_DOVE is not set
++# CONFIG_ARCH_MV78XX0 is not set
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_MMP is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_W90X900 is not set
++# CONFIG_ARCH_LPC32XX is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_MSM is not set
++# CONFIG_ARCH_SHMOBILE_LEGACY 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_DAVINCI is not set
++# CONFIG_ARCH_OMAP1 is not set
++
++#
++# Multiple platform selection
++#
++
++#
++# CPU Core family selection
++#
++# CONFIG_ARCH_MULTI_V6 is not set
++CONFIG_ARCH_MULTI_V7=y
++CONFIG_ARCH_MULTI_V6_V7=y
++# CONFIG_ARCH_MULTI_CPU_AUTO is not set
++# CONFIG_ARCH_VIRT is not set
++# CONFIG_ARCH_MVEBU is not set
++# CONFIG_ARCH_BCM is not set
++# CONFIG_ARCH_BERLIN is not set
++# CONFIG_ARCH_HIGHBANK is not set
++CONFIG_ARCH_HISI=y
++
++#
++# Hisilicon platform type
++#
++# CONFIG_ARCH_HI3xxx is not set
++# CONFIG_ARCH_HIP04 is not set
++# CONFIG_ARCH_HIX5HD2 is not set
++# CONFIG_ARCH_HI3519 is not set
++# CONFIG_ARCH_HI3519V101 is not set
++# CONFIG_ARCH_HI3516AV200 is not set
++# CONFIG_ARCH_HI3559 is not set
++CONFIG_ARCH_HI3556=y
++# CONFIG_ARCH_HI3536C is not set
++# CONFIG_ARCH_HI3531D is not set
++# CONFIG_ARCH_HI3521D is not set
++# CONFIG_ARCH_KEYSTONE is not set
++# CONFIG_ARCH_MESON is not set
++# CONFIG_ARCH_MXC is not set
++# CONFIG_ARCH_MEDIATEK is not set
++
++#
++# TI OMAP/AM/DM/DRA Family
++#
++# CONFIG_ARCH_OMAP3 is not set
++# CONFIG_ARCH_OMAP4 is not set
++# CONFIG_SOC_OMAP5 is not set
++# CONFIG_SOC_AM33XX is not set
++# CONFIG_SOC_AM43XX is not set
++# CONFIG_SOC_DRA7XX is not set
++# CONFIG_ARCH_QCOM is not set
++# CONFIG_ARCH_ROCKCHIP is not set
++# CONFIG_ARCH_SOCFPGA is not set
++# CONFIG_PLAT_SPEAR is not set
++# CONFIG_ARCH_STI is not set
++# CONFIG_ARCH_S5PV210 is not set
++# CONFIG_ARCH_EXYNOS is not set
++# CONFIG_ARCH_SHMOBILE_MULTI is not set
++# CONFIG_ARCH_SUNXI is not set
++# CONFIG_ARCH_SIRF is not set
++# CONFIG_ARCH_TEGRA is not set
++# CONFIG_ARCH_U8500 is not set
++# CONFIG_ARCH_VEXPRESS is not set
++# CONFIG_ARCH_WM8850 is not set
++# CONFIG_ARCH_ZYNQ is not set
++CONFIG_ARM_TIMER_SP804=y
++
++#
++# Processor Type
++#
++CONFIG_CPU_V7=y
++CONFIG_CPU_32v6K=y
++CONFIG_CPU_32v7=y
++CONFIG_CPU_ABRT_EV7=y
++CONFIG_CPU_PABRT_V7=y
++CONFIG_CPU_CACHE_V7=y
++CONFIG_CPU_CACHE_VIPT=y
++CONFIG_CPU_COPY_V6=y
++CONFIG_CPU_TLB_V7=y
++CONFIG_CPU_HAS_ASID=y
++CONFIG_CPU_CP15=y
++CONFIG_CPU_CP15_MMU=y
++
++#
++# Processor Features
++#
++# CONFIG_ARM_LPAE is not set
++# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
++CONFIG_ARM_THUMB=y
++# CONFIG_ARM_THUMBEE is not set
++CONFIG_ARM_VIRT_EXT=y
++CONFIG_SWP_EMULATE=y
++# CONFIG_CPU_ICACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_DISABLE is not set
++# CONFIG_CPU_BPREDICT_DISABLE is not set
++CONFIG_KUSER_HELPERS=y
++CONFIG_MIGHT_HAVE_CACHE_L2X0=y
++# CONFIG_CACHE_L2X0 is not set
++CONFIG_ARM_L1_CACHE_SHIFT_6=y
++CONFIG_ARM_L1_CACHE_SHIFT=6
++CONFIG_ARM_DMA_MEM_BUFFERABLE=y
++CONFIG_MULTI_IRQ_HANDLER=y
++# CONFIG_ARM_ERRATA_430973 is not set
++# CONFIG_ARM_ERRATA_720789 is not set
++# CONFIG_ARM_ERRATA_754322 is not set
++# CONFIG_ARM_ERRATA_775420 is not set
++# CONFIG_ARM_ERRATA_773022 is not set
++
++#
++# Bus support
++#
++CONFIG_ARM_AMBA=y
++# CONFIG_PCI is not set
++# CONFIG_PCI_SYSCALL is not set
++# CONFIG_PCCARD is not set
++
++#
++# Kernel Features
++#
++CONFIG_HAVE_SMP=y
++# CONFIG_SMP is not set
++CONFIG_DISABLE_CPU_SCHED_DOMAIN_BALANCE=y
++CONFIG_HAVE_ARM_ARCH_TIMER=y
++CONFIG_VMSPLIT_3G=y
++# CONFIG_VMSPLIT_2G is not set
++# CONFIG_VMSPLIT_1G is not set
++CONFIG_PAGE_OFFSET=0xC0000000
++# CONFIG_ARM_PSCI is not set
++CONFIG_ARCH_NR_GPIO=0
++CONFIG_PREEMPT_NONE=y
++# CONFIG_PREEMPT_VOLUNTARY is not set
++# CONFIG_PREEMPT is not set
++CONFIG_HZ_FIXED=0
++# CONFIG_HZ_100 is not set
++# CONFIG_HZ_200 is not set
++# CONFIG_HZ_250 is not set
++# CONFIG_HZ_300 is not set
++# CONFIG_HZ_500 is not set
++CONFIG_HZ_1000=y
++CONFIG_HZ=1000
++# CONFIG_SCHED_HRTICK is not set
++# CONFIG_THUMB2_KERNEL is not set
++CONFIG_AEABI=y
++# CONFIG_OABI_COMPAT is not set
++# 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_ARCH_WANT_GENERAL_HUGETLB=y
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_HAVE_MEMBLOCK=y
++CONFIG_NO_BOOTMEM=y
++CONFIG_MEMORY_ISOLATION=y
++# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=4
++CONFIG_COMPACTION=y
++CONFIG_MIGRATION=y
++# CONFIG_PHYS_ADDR_T_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_BOUNCE=y
++# CONFIG_KSM is not set
++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
++CONFIG_NEED_PER_CPU_KM=y
++# CONFIG_CLEANCACHE is not set
++# CONFIG_FRONTSWAP is not set
++CONFIG_CMA=y
++# CONFIG_CMA_DEBUG is not set
++CONFIG_CMA_AREAS=7
++# CONFIG_ZPOOL is not set
++# CONFIG_ZBUD is not set
++# CONFIG_ZSMALLOC 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_SWIOTLB=y
++CONFIG_IOMMU_HELPER=y
++# CONFIG_XEN is not set
++# CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART is not set
++
++#
++# Boot options
++#
++CONFIG_USE_OF=y
++CONFIG_ATAGS=y
++# CONFIG_DEPRECATED_PARAM_STRUCT is not set
++# CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE is not set
++CONFIG_ZBOOT_ROM_TEXT=0
++CONFIG_ZBOOT_ROM_BSS=0
++CONFIG_ARM_APPENDED_DTB=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_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_GOV_COMMON=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_USERSPACE is not set
++CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
++# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE is not set
++CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
++CONFIG_CPU_FREQ_GOV_POWERSAVE=y
++CONFIG_CPU_FREQ_GOV_USERSPACE=y
++CONFIG_CPU_FREQ_GOV_ONDEMAND=y
++CONFIG_CPU_FREQ_GOV_INTERACTIVE=y
++# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
++# CONFIG_CPUFREQ_DT is not set
++
++#
++# ARM CPU frequency scaling drivers
++#
++# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set
++
++#
++# CPU Idle
++#
++# CONFIG_CPU_IDLE is not set
++# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++CONFIG_VFP=y
++CONFIG_VFPv3=y
++CONFIG_NEON=y
++CONFIG_KERNEL_MODE_NEON=y
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
++CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
++CONFIG_BINFMT_SCRIPT=y
++# CONFIG_HAVE_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
++CONFIG_COREDUMP=y
++
++#
++# Power management options
++#
++CONFIG_SUSPEND=y
++CONFIG_SUSPEND_FREEZER=y
++CONFIG_WAKELOCK=y
++CONFIG_HIBERNATE_CALLBACKS=y
++CONFIG_HISI_SNAPSHOT_BOOT=y
++# CONFIG_DEFAULT_MTD is not set
++CONFIG_DEFAULT_DDR=y
++CONFIG_SNAPSHOT_BUF_START=0x8a000000
++CONFIG_SNAPSHOT_BUF_SIZE=0x4000000
++CONFIG_HIBERNATION=y
++CONFIG_GZIP_COMPRESS=y
++CONFIG_PM_STD_PARTITION=""
++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_OPP=y
++CONFIG_PM_CLK=y
++# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set
++CONFIG_CPU_PM=y
++# CONFIG_SUSPEND_TIME is not set
++CONFIG_ARCH_SUSPEND_POSSIBLE=y
++CONFIG_ARM_CPU_SUSPEND=y
++CONFIG_ARCH_HIBERNATION_POSSIBLE=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_NET_IP_TUNNEL=m
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_NET_IPVTI is not set
++# CONFIG_NET_UDP_TUNNEL is not set
++# CONFIG_NET_FOU is not set
++# CONFIG_GENEVE 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=y
++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=y
++# 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_VTI 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_ANDROID_PARANOID_NETWORK is not set
++CONFIG_NET_ACTIVITY_STATS=y
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NET_PTP_CLASSIFY 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_NF_TABLES is not set
++# CONFIG_NETFILTER_XTABLES is not set
++# CONFIG_IP_SET is not set
++# CONFIG_IP_VS is not set
++
++#
++# IP: Netfilter Configuration
++#
++# CONFIG_NF_DEFRAG_IPV4 is not set
++# CONFIG_NF_LOG_ARP is not set
++# CONFIG_NF_LOG_IPV4 is not set
++# CONFIG_NF_REJECT_IPV4 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_NF_REJECT_IPV6 is not set
++# CONFIG_NF_LOG_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_HAVE_NET_DSA=y
++# 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_PHONET is not set
++# CONFIG_6LOWPAN 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_VSOCKETS is not set
++# CONFIG_NETLINK_MMAP is not set
++# CONFIG_NETLINK_DIAG is not set
++# CONFIG_NET_MPLS_GSO is not set
++# CONFIG_HSR is not set
++# CONFIG_CGROUP_NET_PRIO is not set
++# CONFIG_CGROUP_NET_CLASSID is not set
++CONFIG_NET_RX_BUSY_POLL=y
++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 is not set
++CONFIG_DEVTMPFS=y
++CONFIG_DEVTMPFS_MOUNT=y
++CONFIG_STANDALONE=y
++# CONFIG_PREVENT_FIRMWARE_BUILD is not set
++CONFIG_FW_LOADER=y
++# CONFIG_FIRMWARE_IN_KERNEL is not set
++CONFIG_EXTRA_FIRMWARE=""
++# CONFIG_FW_LOADER_USER_HELPER_FALLBACK is not set
++CONFIG_ALLOW_DEV_COREDUMP=y
++# 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_HAVE_CPU_AUTOPROBE is not set
++CONFIG_REGMAP=y
++CONFIG_REGMAP_MMIO=y
++CONFIG_DMA_SHARED_BUFFER=y
++# CONFIG_FENCE_TRACE is not set
++CONFIG_DMA_CMA=y
++
++#
++# Default contiguous memory area size:
++#
++CONFIG_CMA_SIZE_MBYTES=16
++CONFIG_CMA_SIZE_SEL_MBYTES=y
++# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set
++# CONFIG_CMA_SIZE_SEL_MIN is not set
++# CONFIG_CMA_SIZE_SEL_MAX is not set
++CONFIG_CMA_ALIGNMENT=8
++
++#
++# Bus devices
++#
++# CONFIG_BRCMSTB_GISB_ARB is not set
++CONFIG_ARM_CCI=y
++# CONFIG_VEXPRESS_CONFIG 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=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_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
++CONFIG_HIFMC=y
++CONFIG_HIFMC_SPI_NAND=y
++# CONFIG_HIFMC_NAND is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++# CONFIG_MTD_CFI is not set
++# CONFIG_MTD_JEDECPROBE is not set
++CONFIG_MTD_MAP_BANK_WIDTH_1=y
++CONFIG_MTD_MAP_BANK_WIDTH_2=y
++CONFIG_MTD_MAP_BANK_WIDTH_4=y
++# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
++CONFIG_MTD_CFI_I1=y
++CONFIG_MTD_CFI_I2=y
++# CONFIG_MTD_CFI_I4 is not set
++# CONFIG_MTD_CFI_I8 is not set
++# CONFIG_MTD_RAM is not set
++# CONFIG_MTD_ROM is not set
++# CONFIG_MTD_ABSENT is not set
++
++#
++# Mapping drivers for chip access
++#
++# CONFIG_MTD_COMPLEX_MAPPINGS is not set
++# CONFIG_MTD_PLATRAM is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_DATAFLASH is not set
++# CONFIG_MTD_M25P80 is not set
++# CONFIG_MTD_SST25L is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_PHRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++# CONFIG_MTD_BLOCK2MTD is not set
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOCG3 is not set
++CONFIG_MTD_NAND_IDS=y
++CONFIG_MTD_NAND_ECC=y
++# CONFIG_MTD_NAND_ECC_SMC is not set
++CONFIG_MTD_NAND=y
++# CONFIG_MTD_NAND_ECC_BCH is not set
++# CONFIG_MTD_SM_COMMON is not set
++# CONFIG_MTD_NAND_DENALI is not set
++# CONFIG_MTD_NAND_GPIO is not set
++# CONFIG_MTD_NAND_OMAP_BCH_BUILD is not set
++# CONFIG_MTD_NAND_DISKONCHIP is not set
++# CONFIG_MTD_NAND_DOCG4 is not set
++# CONFIG_MTD_NAND_NANDSIM is not set
++# CONFIG_MTD_NAND_PLATFORM is not set
++# CONFIG_HISI_NAND_FS_MAY_NO_YAFFS2 is not set
++# CONFIG_HISI_NAND_ECC_STATUS_REPORT is not set
++# CONFIG_MTD_NAND_HINFC610 is not set
++# CONFIG_HIFMC100_NAND is not set
++CONFIG_HIFMC100_SPI_NAND=y
++CONFIG_SPI_NAND_MAX_CHIP_NUM=1
++# CONFIG_HIFMC100_HARDWARE_PAGESIZE_ECC is not set
++CONFIG_HIFMC100_AUTO_PAGESIZE_ECC=y
++# CONFIG_HIFMC100_PAGESIZE_AUTO_ECC_NONE is not set
++# CONFIG_MTD_ONENAND is not set
++
++#
++# LPDDR & LPDDR2 PCM memory drivers
++#
++# CONFIG_MTD_LPDDR is not set
++# CONFIG_MTD_LPDDR2_NVM is not set
++CONFIG_MTD_SPI_NOR=y
++# CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set
++CONFIG_SPI_HISI_SFC=y
++CONFIG_CLOSE_SPI_8PIN_4IO=y
++CONFIG_HISI_SPI_BLOCK_PROTECT=y
++CONFIG_MTD_UBI=y
++CONFIG_MTD_UBI_WL_THRESHOLD=4096
++CONFIG_MTD_UBI_BEB_LIMIT=20
++# CONFIG_MTD_UBI_FASTMAP is not set
++# CONFIG_MTD_UBI_GLUEBI is not set
++# CONFIG_MTD_UBI_BLOCK is not set
++CONFIG_DTC=y
++CONFIG_OF=y
++
++#
++# Device Tree and Open Firmware support
++#
++# 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_NET=y
++CONFIG_OF_MDIO=y
++CONFIG_OF_MTD=y
++CONFIG_OF_RESERVED_MEM=y
++CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
++# CONFIG_PARPORT is not set
++CONFIG_BLK_DEV=y
++# CONFIG_BLK_DEV_NULL_BLK is not set
++# CONFIG_BLK_DEV_COW_COMMON is not set
++# CONFIG_BLK_DEV_LOOP 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=65536
++# 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_DUMMY_IRQ 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_UID_STAT is not set
++# CONFIG_BMP085_I2C is not set
++# CONFIG_BMP085_SPI is not set
++# CONFIG_USB_SWITCH_FSA9480 is not set
++# CONFIG_LATTICE_ECP3_CONFIG is not set
++# CONFIG_SRAM is not set
++# CONFIG_C2PORT is not set
++
++#
++# EEPROM support
++#
++# CONFIG_EEPROM_AT24 is not set
++# CONFIG_EEPROM_AT25 is not set
++# CONFIG_EEPROM_LEGACY is not set
++# CONFIG_EEPROM_MAX6875 is not set
++# CONFIG_EEPROM_93CX6 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
++
++#
++# Intel MIC Bus Driver
++#
++
++#
++# Intel MIC Host Driver
++#
++
++#
++# Intel MIC Card Driver
++#
++# CONFIG_ECHO is not set
++# CONFIG_CXL_BASE is not set
++
++#
++# hisi 'himm/himd.l/himc'support
++#
++# CONFIG_HISI_REG 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_NETLINK is not set
++# CONFIG_SCSI_MQ_DEFAULT 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_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 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_NET_CORE=y
++# CONFIG_BONDING is not set
++# CONFIG_DUMMY is not set
++# CONFIG_EQUALIZER is not set
++# CONFIG_NET_TEAM is not set
++# CONFIG_MACVLAN is not set
++# CONFIG_VXLAN is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_TUN is not set
++# CONFIG_VETH is not set
++# CONFIG_NLMON is not set
++
++#
++# 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_NET_DSA_MV88E6171 is not set
++# CONFIG_NET_DSA_BCM_SF2 is not set
++# CONFIG_ETHERNET is not set
++CONFIG_PHYLIB=y
++
++#
++# MII PHY device drivers
++#
++# CONFIG_AT803X_PHY is not set
++# CONFIG_AMD_PHY is not set
++# CONFIG_AMD_XGBE_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 is not set
++# CONFIG_BROADCOM_PHY is not set
++# CONFIG_BCM7XXX_PHY is not set
++# CONFIG_BCM87XX_PHY is not set
++# CONFIG_ICPLUS_PHY is not set
++# CONFIG_REALTEK_PHY is not set
++# CONFIG_NATIONAL_PHY is not set
++# CONFIG_STE10XP is not set
++# CONFIG_LSI_ET1011C_PHY is not set
++# CONFIG_MICREL_PHY is not set
++# CONFIG_FIXED_PHY is not set
++# CONFIG_MDIO_BITBANG is not set
++# CONFIG_MDIO_BUS_MUX_GPIO is not set
++# CONFIG_MDIO_BUS_MUX_MMIOREG is not set
++# CONFIG_MDIO_BCM_UNIMAC is not set
++# CONFIG_MDIO_HISI_FEMAC is not set
++# CONFIG_MDIO_HISI_GEMAC is not set
++# CONFIG_MICREL_KS8995MA is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++CONFIG_USB_NET_DRIVERS=y
++# 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_RTL8152 is not set
++# CONFIG_USB_USBNET is not set
++# CONFIG_USB_IPHETH is not set
++CONFIG_WLAN=y
++# CONFIG_WIFI_CONTROL_FUNC is not set
++# 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 is not set
++# CONFIG_INPUT_SPARSEKMAP is not set
++# CONFIG_INPUT_MATRIXKMAP is not set
++
++#
++# Userland interfaces
++#
++CONFIG_INPUT_MOUSEDEV=y
++CONFIG_INPUT_MOUSEDEV_PSAUX=y
++CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
++CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
++# CONFIG_INPUT_JOYDEV is not set
++CONFIG_INPUT_EVDEV=y
++# CONFIG_INPUT_EVBUG is not set
++# CONFIG_INPUT_KEYRESET is not set
++# CONFIG_INPUT_KEYCOMBO is not set
++
++#
++# Input Device Drivers
++#
++CONFIG_INPUT_KEYBOARD=y
++# CONFIG_KEYBOARD_ADP5588 is not set
++# CONFIG_KEYBOARD_ADP5589 is not set
++CONFIG_KEYBOARD_ATKBD=y
++# CONFIG_KEYBOARD_QT1070 is not set
++# CONFIG_KEYBOARD_QT2160 is not set
++# CONFIG_KEYBOARD_LKKBD is not set
++# CONFIG_KEYBOARD_GPIO is not set
++# CONFIG_KEYBOARD_GPIO_POLLED is not set
++# 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 is not set
++# CONFIG_KEYBOARD_CAP1106 is not set
++CONFIG_INPUT_MOUSE=y
++CONFIG_MOUSE_PS2=y
++CONFIG_MOUSE_PS2_ALPS=y
++CONFIG_MOUSE_PS2_LOGIPS2PP=y
++CONFIG_MOUSE_PS2_SYNAPTICS=y
++CONFIG_MOUSE_PS2_CYPRESS=y
++CONFIG_MOUSE_PS2_TRACKPOINT=y
++# CONFIG_MOUSE_PS2_ELANTECH is not set
++# CONFIG_MOUSE_PS2_SENTELIC is not set
++# CONFIG_MOUSE_PS2_TOUCHKIT is not set
++# CONFIG_MOUSE_SERIAL is not set
++# CONFIG_MOUSE_APPLETOUCH is not set
++# CONFIG_MOUSE_BCM5974 is not set
++# CONFIG_MOUSE_CYAPA is not set
++# CONFIG_MOUSE_VSXXXAA is not set
++# CONFIG_MOUSE_GPIO is not set
++# CONFIG_MOUSE_SYNAPTICS_I2C is not set
++# CONFIG_MOUSE_SYNAPTICS_USB is not set
++# CONFIG_INPUT_JOYSTICK is not set
++# CONFIG_INPUT_TABLET is not set
++# CONFIG_INPUT_TOUCHSCREEN is not set
++# CONFIG_INPUT_MISC is not set
++
++#
++# Hardware I/O ports
++#
++CONFIG_SERIO=y
++CONFIG_SERIO_SERPORT=y
++# CONFIG_SERIO_AMBAKMI is not set
++CONFIG_SERIO_LIBPS2=y
++# CONFIG_SERIO_RAW is not set
++# CONFIG_SERIO_ALTERA_PS2 is not set
++# CONFIG_SERIO_PS2MULT is not set
++# CONFIG_SERIO_ARC_PS2 is not set
++# CONFIG_SERIO_APBPS2 is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++CONFIG_TTY=y
++CONFIG_VT=y
++CONFIG_CONSOLE_TRANSLATIONS=y
++CONFIG_VT_CONSOLE=y
++CONFIG_VT_CONSOLE_SLEEP=y
++CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
++CONFIG_UNIX98_PTYS=y
++# CONFIG_DEVPTS_MULTIPLE_INSTANCES 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_DEVMEM=y
++CONFIG_DEVKMEM=y
++
++#
++# Serial drivers
++#
++CONFIG_SERIAL_EARLYCON=y
++# CONFIG_SERIAL_8250 is not set
++
++#
++# Non-8250 serial port support
++#
++# CONFIG_SERIAL_AMBA_PL010 is not set
++CONFIG_SERIAL_AMBA_PL011=y
++CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
++# CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST is not set
++# 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_SC16IS7XX is not set
++# CONFIG_SERIAL_ALTERA_JTAGUART is not set
++# CONFIG_SERIAL_ALTERA_UART is not set
++# CONFIG_SERIAL_IFX6X60 is not set
++# CONFIG_SERIAL_XILINX_PS_UART is not set
++# CONFIG_SERIAL_ARC is not set
++# CONFIG_SERIAL_FSL_LPUART is not set
++# CONFIG_SERIAL_ST_ASC is not set
++# CONFIG_HVC_DCC is not set
++# CONFIG_IPMI_HANDLER is not set
++CONFIG_HW_RANDOM=y
++# CONFIG_HW_RANDOM_TIMERIOMEM is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++# CONFIG_DCC_TTY is not set
++# CONFIG_XILLYBUS is not set
++
++#
++# I2C support
++#
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++# CONFIG_I2C_COMPAT is not set
++CONFIG_I2C_CHARDEV=y
++CONFIG_I2C_MUX=m
++
++#
++# Multiplexer I2C Chip support
++#
++# CONFIG_I2C_ARB_GPIO_CHALLENGE is not set
++# CONFIG_I2C_MUX_GPIO is not set
++# CONFIG_I2C_MUX_PCA9541 is not set
++# CONFIG_I2C_MUX_PCA954x is not set
++# CONFIG_I2C_HELPER_AUTO is not set
++# CONFIG_I2C_SMBUS is not set
++
++#
++# I2C Algorithms
++#
++# CONFIG_I2C_ALGOBIT is not set
++# CONFIG_I2C_ALGOPCF is not set
++# CONFIG_I2C_ALGOPCA is not set
++
++#
++# I2C Hardware Bus support
++#
++
++#
++# I2C system bus drivers (mostly embedded / system-on-chip)
++#
++# CONFIG_I2C_CBUS_GPIO is not set
++# CONFIG_I2C_DESIGNWARE_PLATFORM is not set
++# CONFIG_I2C_GPIO is not set
++# CONFIG_I2C_HIBVT is not set
++CONFIG_I2C_HISI_V110=y
++# CONFIG_I2C_NOMADIK 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_RK3X 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_ROBOTFUZZ_OSIF 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_CADENCE is not set
++# CONFIG_SPI_GPIO is not set
++# CONFIG_SPI_FSL_SPI is not set
++# CONFIG_SPI_OC_TINY is not set
++CONFIG_SPI_PL022=y
++# CONFIG_SPI_PXA2XX_PCI is not set
++# CONFIG_SPI_ROCKCHIP 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=y
++# CONFIG_SPI_TLE62X0 is not set
++# CONFIG_SPMI is not set
++# CONFIG_HSI is not set
++
++#
++# PPS support
++#
++# CONFIG_PPS is not set
++
++#
++# PPS generators support
++#
++
++#
++# PTP clock support
++#
++# CONFIG_PTP_1588_CLOCK is not set
++
++#
++# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
++#
++CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
++CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
++CONFIG_GPIOLIB=y
++CONFIG_GPIO_DEVRES=y
++CONFIG_OF_GPIO=y
++CONFIG_GPIOLIB_IRQCHIP=y
++# CONFIG_DEBUG_GPIO is not set
++CONFIG_GPIO_SYSFS=y
++
++#
++# Memory mapped GPIO drivers:
++#
++# CONFIG_GPIO_GENERIC_PLATFORM is not set
++# CONFIG_GPIO_DWAPB is not set
++# CONFIG_GPIO_EM is not set
++# CONFIG_GPIO_ZEVIO is not set
++CONFIG_GPIO_PL061=y
++# CONFIG_GPIO_SCH311X is not set
++# CONFIG_GPIO_SYSCON is not set
++# CONFIG_GPIO_GRGPIO is not set
++
++#
++# I2C GPIO expanders:
++#
++# CONFIG_GPIO_MAX7300 is not set
++# CONFIG_GPIO_MAX732X is not set
++# CONFIG_GPIO_PCA953X is not set
++# CONFIG_GPIO_PCF857X is not set
++# CONFIG_GPIO_SX150X is not set
++# CONFIG_GPIO_ADP5588 is not set
++# CONFIG_GPIO_ADNP is not set
++
++#
++# PCI GPIO expanders:
++#
++
++#
++# SPI GPIO expanders:
++#
++# CONFIG_GPIO_MAX7301 is not set
++# CONFIG_GPIO_MCP23S08 is not set
++# CONFIG_GPIO_MC33880 is not set
++# CONFIG_GPIO_74X164 is not set
++
++#
++# AC97 GPIO expanders:
++#
++
++#
++# LPC GPIO expanders:
++#
++
++#
++# MODULbus GPIO expanders:
++#
++
++#
++# USB GPIO expanders:
++#
++# CONFIG_W1 is not set
++CONFIG_POWER_SUPPLY=y
++# CONFIG_POWER_SUPPLY_DEBUG is not set
++# CONFIG_PDA_POWER is not set
++# CONFIG_TEST_POWER is not set
++# CONFIG_BATTERY_DS2780 is not set
++# CONFIG_BATTERY_DS2781 is not set
++# CONFIG_BATTERY_DS2782 is not set
++# CONFIG_BATTERY_SBS is not set
++# CONFIG_BATTERY_BQ27x00 is not set
++# CONFIG_BATTERY_MAX17040 is not set
++# CONFIG_BATTERY_MAX17042 is not set
++# CONFIG_CHARGER_MAX8903 is not set
++# CONFIG_CHARGER_LP8727 is not set
++# CONFIG_CHARGER_GPIO is not set
++# CONFIG_CHARGER_BQ2415X is not set
++# CONFIG_CHARGER_BQ24190 is not set
++# CONFIG_CHARGER_BQ24735 is not set
++# CONFIG_CHARGER_SMB347 is not set
++CONFIG_POWER_RESET=y
++# CONFIG_POWER_RESET_BRCMSTB is not set
++# CONFIG_POWER_RESET_GPIO is not set
++# CONFIG_POWER_RESET_GPIO_RESTART is not set
++CONFIG_POWER_RESET_HISI=y
++# CONFIG_POWER_RESET_LTC2952 is not set
++# CONFIG_POWER_RESET_RESTART is not set
++# CONFIG_POWER_RESET_VERSATILE is not set
++# CONFIG_POWER_RESET_SYSCON is not set
++# CONFIG_POWER_AVS is not set
++# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
++# CONFIG_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=y
++# CONFIG_MFD_AS3711 is not set
++# CONFIG_MFD_AS3722 is not set
++# CONFIG_PMIC_ADP5520 is not set
++# CONFIG_MFD_AAT2870_CORE is not set
++# CONFIG_MFD_BCM590XX is not set
++# CONFIG_MFD_AXP20X is not set
++# CONFIG_MFD_CROS_EC is not set
++# CONFIG_MFD_ASIC3 is not set
++# CONFIG_PMIC_DA903X is not set
++# CONFIG_MFD_DA9052_SPI is not set
++# CONFIG_MFD_DA9052_I2C is not set
++# CONFIG_MFD_DA9055 is not set
++# CONFIG_MFD_DA9063 is not set
++# CONFIG_MFD_MC13XXX_SPI is not set
++# CONFIG_MFD_MC13XXX_I2C is not set
++# CONFIG_MFD_HI6421_PMIC is not set
++CONFIG_MFD_HISI_FMC=y
++# CONFIG_HTC_EGPIO is not set
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_HTC_I2CPLD is not set
++# CONFIG_INTEL_SOC_PMIC is not set
++# CONFIG_MFD_KEMPLD is not set
++# CONFIG_MFD_88PM800 is not set
++# CONFIG_MFD_88PM805 is not set
++# CONFIG_MFD_88PM860X is not set
++# CONFIG_MFD_MAX14577 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_MENF21BMC is not set
++# CONFIG_EZX_PCAP is not set
++# CONFIG_MFD_VIPERBOARD is not set
++# CONFIG_MFD_RETU is not set
++# CONFIG_MFD_PCF50633 is not set
++# CONFIG_MFD_PM8921_CORE is not set
++# CONFIG_MFD_RTSX_USB is not set
++# CONFIG_MFD_RC5T583 is not set
++# CONFIG_MFD_RK808 is not set
++# CONFIG_MFD_RN5T618 is not set
++# CONFIG_MFD_SEC_CORE is not set
++# CONFIG_MFD_SI476X_CORE is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_MFD_SMSC is not set
++# CONFIG_ABX500_CORE is not set
++# CONFIG_MFD_STMPE is not set
++CONFIG_MFD_SYSCON=y
++# CONFIG_MFD_TI_AM335X_TSCADC is not set
++# CONFIG_MFD_LP3943 is not set
++# CONFIG_MFD_LP8788 is not set
++# CONFIG_MFD_PALMAS is not set
++# CONFIG_TPS6105X is not set
++# CONFIG_TPS65010 is not set
++# CONFIG_TPS6507X is not set
++# CONFIG_MFD_TPS65090 is not set
++# CONFIG_MFD_TPS65217 is not set
++# CONFIG_MFD_TPS65218 is not set
++# CONFIG_MFD_TPS6586X is not set
++# CONFIG_MFD_TPS65910 is not set
++# CONFIG_MFD_TPS65912 is not set
++# CONFIG_MFD_TPS65912_I2C is not set
++# CONFIG_MFD_TPS65912_SPI is not set
++# CONFIG_MFD_TPS80031 is not set
++# CONFIG_TWL4030_CORE is not set
++# CONFIG_TWL6040_CORE is not set
++# CONFIG_MFD_WL1273_CORE is not set
++# CONFIG_MFD_LM3533 is not set
++# CONFIG_MFD_TC3589X is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_MFD_T7L66XB is not set
++# CONFIG_MFD_TC6387XB is not set
++# CONFIG_MFD_TC6393XB is not set
++# CONFIG_MFD_ARIZONA_I2C is not set
++# CONFIG_MFD_ARIZONA_SPI is not set
++# CONFIG_MFD_WM8400 is not set
++# CONFIG_MFD_WM831X_I2C is not set
++# CONFIG_MFD_WM831X_SPI is not set
++# CONFIG_MFD_WM8350_I2C is not set
++# CONFIG_MFD_WM8994 is not set
++CONFIG_REGULATOR=y
++# CONFIG_REGULATOR_DEBUG is not set
++# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
++# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
++# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
++# CONFIG_REGULATOR_ACT8865 is not set
++# CONFIG_REGULATOR_AD5398 is not set
++# CONFIG_REGULATOR_ANATOP is not set
++# CONFIG_REGULATOR_DA9210 is not set
++# CONFIG_REGULATOR_DA9211 is not set
++# CONFIG_REGULATOR_FAN53555 is not set
++# CONFIG_REGULATOR_GPIO is not set
++# CONFIG_REGULATOR_ISL9305 is not set
++# CONFIG_REGULATOR_ISL6271A is not set
++# CONFIG_REGULATOR_LP3971 is not set
++# CONFIG_REGULATOR_LP3972 is not set
++# CONFIG_REGULATOR_LP872X is not set
++# CONFIG_REGULATOR_LP8755 is not set
++# CONFIG_REGULATOR_LTC3589 is not set
++# CONFIG_REGULATOR_MAX1586 is not set
++# CONFIG_REGULATOR_MAX8649 is not set
++# CONFIG_REGULATOR_MAX8660 is not set
++# CONFIG_REGULATOR_MAX8952 is not set
++# CONFIG_REGULATOR_MAX8973 is not set
++# CONFIG_REGULATOR_PFUZE100 is not set
++# CONFIG_REGULATOR_TPS51632 is not set
++# CONFIG_REGULATOR_TPS62360 is not set
++# CONFIG_REGULATOR_TPS65023 is not set
++# CONFIG_REGULATOR_TPS6507X is not set
++# CONFIG_REGULATOR_TPS6524X is not set
++CONFIG_MEDIA_SUPPORT=m
++
++#
++# Multimedia core support
++#
++CONFIG_MEDIA_CAMERA_SUPPORT=y
++# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set
++# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set
++# CONFIG_MEDIA_RADIO_SUPPORT is not set
++# CONFIG_MEDIA_SDR_SUPPORT is not set
++# CONFIG_MEDIA_RC_SUPPORT is not set
++# CONFIG_MEDIA_CONTROLLER is not set
++CONFIG_VIDEO_DEV=m
++CONFIG_VIDEO_V4L2=m
++# CONFIG_VIDEO_ADV_DEBUG is not set
++# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
++CONFIG_VIDEOBUF2_CORE=m
++CONFIG_VIDEOBUF2_MEMOPS=m
++CONFIG_VIDEOBUF2_VMALLOC=m
++# CONFIG_TTPCI_EEPROM is not set
++
++#
++# Media drivers
++#
++# CONFIG_MEDIA_USB_SUPPORT is not set
++# CONFIG_V4L_PLATFORM_DRIVERS is not set
++# CONFIG_V4L_MEM2MEM_DRIVERS is not set
++# CONFIG_V4L_TEST_DRIVERS is not set
++
++#
++# Supported MMC/SDIO adapters
++#
++# CONFIG_CYPRESS_FIRMWARE is not set
++
++#
++# Media ancillary drivers (tuners, sensors, i2c, frontends)
++#
++CONFIG_MEDIA_SUBDRV_AUTOSELECT=y
++
++#
++# Audio decoders, processors and mixers
++#
++
++#
++# RDS decoders
++#
++
++#
++# Video decoders
++#
++
++#
++# Video and audio decoders
++#
++
++#
++# Video encoders
++#
++
++#
++# Camera sensor devices
++#
++
++#
++# Flash devices
++#
++
++#
++# Video improvement chips
++#
++
++#
++# Audio/Video compression chips
++#
++
++#
++# Miscellaneous helper chips
++#
++
++#
++# Sensors used on soc_camera driver
++#
++
++#
++# Tools to develop new frontends
++#
++# CONFIG_DVB_DUMMY_FE is not set
++
++#
++# Graphics support
++#
++# CONFIG_IMX_IPUV3_CORE is not set
++
++#
++# Direct Rendering Manager
++#
++# CONFIG_DRM is not set
++
++#
++# Frame buffer Devices
++#
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++CONFIG_FB_CMDLINE=y
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++# CONFIG_FB_CFB_FILLRECT is not set
++# CONFIG_FB_CFB_COPYAREA is not set
++# CONFIG_FB_CFB_IMAGEBLIT is not set
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# 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_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_ARMCLCD is not set
++# CONFIG_FB_OPENCORES is not set
++# CONFIG_FB_S1D13XXX is not set
++# CONFIG_FB_SMSCUFX is not set
++# CONFIG_FB_UDL is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_BROADSHEET is not set
++# CONFIG_FB_AUO_K190X is not set
++# CONFIG_FB_SIMPLE is not set
++# CONFIG_FB_SSD1307 is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++# CONFIG_VGASTATE is not set
++
++#
++# Console display driver support
++#
++CONFIG_DUMMY_CONSOLE=y
++# CONFIG_FRAMEBUFFER_CONSOLE is not set
++# CONFIG_LOGO is not set
++# CONFIG_SOUND is not set
++
++#
++# HID support
++#
++CONFIG_HID=y
++# CONFIG_HID_BATTERY_STRENGTH is not set
++# CONFIG_HIDRAW is not set
++# CONFIG_UHID is not set
++CONFIG_HID_GENERIC=y
++
++#
++# Special HID drivers
++#
++CONFIG_HID_A4TECH=y
++# CONFIG_HID_ACRUX is not set
++CONFIG_HID_APPLE=y
++# CONFIG_HID_APPLEIR is not set
++# CONFIG_HID_AUREAL is not set
++CONFIG_HID_BELKIN=y
++CONFIG_HID_CHERRY=y
++CONFIG_HID_CHICONY=y
++# CONFIG_HID_CP2112 is not set
++CONFIG_HID_CYPRESS=y
++# CONFIG_HID_DRAGONRISE is not set
++# CONFIG_HID_EMS_FF is not set
++# CONFIG_HID_ELECOM is not set
++# CONFIG_HID_ELO is not set
++CONFIG_HID_EZKEY=y
++# CONFIG_HID_HOLTEK is not set
++# CONFIG_HID_HUION 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_ICADE is not set
++# CONFIG_HID_TWINHAN is not set
++CONFIG_HID_KENSINGTON=y
++# CONFIG_HID_LCPOWER is not set
++# CONFIG_HID_LENOVO is not set
++CONFIG_HID_LOGITECH=y
++# CONFIG_HID_LOGITECH_HIDPP is not set
++# CONFIG_LOGITECH_FF is not set
++# CONFIG_LOGIRUMBLEPAD2_FF is not set
++# CONFIG_LOGIG940_FF is not set
++# CONFIG_LOGIWHEELS_FF is not set
++# CONFIG_HID_MAGICMOUSE is not set
++CONFIG_HID_MICROSOFT=y
++CONFIG_HID_MONTEREY=y
++# 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_PENMOUNT is not set
++# CONFIG_HID_PETALYNX is not set
++# CONFIG_HID_PICOLCD is not set
++# CONFIG_HID_PRIMAX is not set
++# CONFIG_HID_ROCCAT is not set
++# CONFIG_HID_SAITEK is not set
++# CONFIG_HID_SAMSUNG is not set
++# CONFIG_HID_SPEEDLINK is not set
++# CONFIG_HID_STEELSERIES is not set
++# CONFIG_HID_SUNPLUS is not set
++# CONFIG_HID_RMI 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_XINMO is not set
++# CONFIG_HID_ZEROPLUS is not set
++# CONFIG_HID_ZYDACRON is not set
++# CONFIG_HID_SENSOR_HUB is not set
++
++#
++# USB HID support
++#
++CONFIG_USB_HID=y
++# CONFIG_HID_PID is not set
++# CONFIG_USB_HIDDEV is not set
++
++#
++# I2C HID support
++#
++# CONFIG_I2C_HID is not set
++CONFIG_USB_OHCI_LITTLE_ENDIAN=y
++CONFIG_USB_SUPPORT=y
++CONFIG_USB_COMMON=y
++CONFIG_USB_ARCH_HAS_HCD=y
++CONFIG_USB=y
++# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
++
++#
++# Miscellaneous USB options
++#
++# CONFIG_USB_DEFAULT_PERSIST is not set
++# CONFIG_USB_DYNAMIC_MINORS is not set
++# CONFIG_USB_OTG_WHITELIST is not set
++# CONFIG_USB_OTG_FSM is not set
++# CONFIG_USB_MON is not set
++# CONFIG_USB_WUSB_CBAF is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_C67X00_HCD is not set
++# CONFIG_USB_XHCI_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_FUSBH200_HCD is not set
++# CONFIG_USB_FOTG210_HCD is not set
++# CONFIG_USB_MAX3421_HCD is not set
++# CONFIG_USB_OHCI_HCD is not set
++# CONFIG_USB_SL811_HCD is not set
++# CONFIG_USB_R8A66597_HCD is not set
++# CONFIG_USB_HCD_TEST_MODE is not set
++
++#
++# USB Device Class drivers
++#
++# CONFIG_USB_ACM is not set
++# CONFIG_USB_PRINTER is not set
++# CONFIG_USB_WDM is not set
++# CONFIG_USB_TMC is not set
++
++#
++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
++#
++
++#
++# also be needed; see USB_STORAGE Help for more info
++#
++# CONFIG_USB_STORAGE is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++# CONFIG_USBIP_CORE is not set
++# CONFIG_USB_MUSB_HDRC is not set
++# CONFIG_USB_DWC3 is not set
++# CONFIG_USB_DWC2 is not set
++# CONFIG_USB_CHIPIDEA is not set
++
++#
++# USB port drivers
++#
++# CONFIG_USB_SERIAL is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
++# CONFIG_USB_SEVSEG is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
++# CONFIG_USB_APPLEDISPLAY is not set
++# CONFIG_USB_LD is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
++# CONFIG_USB_IOWARRIOR is not set
++# CONFIG_USB_TEST is not set
++# CONFIG_USB_EHSET_TEST_FIXTURE is not set
++# CONFIG_USB_ISIGHTFW is not set
++# CONFIG_USB_YUREX is not set
++# CONFIG_USB_EZUSB_FX2 is not set
++# CONFIG_USB_HSIC_USB3503 is not set
++# CONFIG_USB_LINK_LAYER_TEST is not set
++
++#
++# USB Physical Layer drivers
++#
++# CONFIG_USB_PHY is not set
++# CONFIG_USB_OTG_WAKELOCK is not set
++# CONFIG_NOP_USB_XCEIV is not set
++# CONFIG_AM335X_PHY_USB is not set
++# CONFIG_USB_GPIO_VBUS is not set
++# CONFIG_USB_ISP1301 is not set
++# CONFIG_USB_ULPI is not set
++CONFIG_USB_GADGET=y
++# CONFIG_USB_GADGET_DEBUG is not set
++# CONFIG_USB_GADGET_DEBUG_FILES is not set
++CONFIG_USB_GADGET_VBUS_DRAW=2
++CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2
++
++#
++# USB Peripheral Controller
++#
++# CONFIG_USB_FUSB300 is not set
++# CONFIG_USB_FOTG210_UDC is not set
++# CONFIG_USB_GR_UDC is not set
++# CONFIG_USB_R8A66597 is not set
++# CONFIG_USB_PXA27X is not set
++# CONFIG_USB_MV_UDC is not set
++CONFIG_HIUSB_DEVICE2_0=y
++CONFIG_USB_HISI_UDC=m
++# CONFIG_USB_AUTO_SWITCH is not set
++# CONFIG_HIUSB_DEVICE3_0 is not set
++# CONFIG_USB_MV_U3D is not set
++# CONFIG_USB_M66592 is not set
++# CONFIG_USB_NET2272 is not set
++# CONFIG_USB_GADGET_XILINX is not set
++# CONFIG_USB_DUMMY_HCD is not set
++CONFIG_USB_LIBCOMPOSITE=m
++CONFIG_USB_F_ACM=m
++CONFIG_USB_U_SERIAL=m
++CONFIG_USB_U_ETHER=m
++CONFIG_USB_F_RNDIS=m
++CONFIG_USB_F_MASS_STORAGE=m
++CONFIG_USB_F_UAC1=m
++CONFIG_USB_F_UVC=m
++# CONFIG_USB_CONFIGFS is not set
++# CONFIG_USB_ZERO is not set
++CONFIG_USB_AUDIO=m
++CONFIG_GADGET_UAC1=y
++# CONFIG_USB_ETH is not set
++# CONFIG_USB_G_NCM is not set
++# CONFIG_USB_GADGETFS is not set
++# CONFIG_USB_FUNCTIONFS is not set
++CONFIG_USB_MASS_STORAGE=m
++# CONFIG_USB_G_SERIAL is not set
++# CONFIG_USB_G_PRINTER is not set
++# CONFIG_USB_CDC_COMPOSITE is not set
++# CONFIG_USB_G_ACM_MS is not set
++CONFIG_USB_G_MULTI=m
++CONFIG_USB_G_MULTI_RNDIS=y
++# CONFIG_USB_G_MULTI_CDC is not set
++# CONFIG_USB_G_HID is not set
++# CONFIG_USB_G_DBGP is not set
++# CONFIG_USB_G_WEBCAM is not set
++CONFIG_USB_G_WEBCAM_AUDIO=m
++# CONFIG_UWB is not set
++CONFIG_MMC=y
++# CONFIG_MMC_DEBUG is not set
++# CONFIG_MMC_CLKGATE is not set
++CONFIG_MMC_EMBEDDED_SDIO=y
++# CONFIG_MMC_PARANOID_SD_INIT is not set
++
++#
++# MMC/SD/SDIO Card Drivers
++#
++CONFIG_MMC_BLOCK=y
++CONFIG_MMC_BLOCK_MINORS=8
++CONFIG_MMC_BLOCK_BOUNCE=y
++# CONFIG_MMC_BLOCK_DEFERRED_RESUME is not set
++# CONFIG_SDIO_UART is not set
++# CONFIG_MMC_TEST is not set
++
++#
++# MMC/SD/SDIO Host Controller Drivers
++#
++# CONFIG_MMC_ARMMMCI is not set
++# CONFIG_MMC_SDHCI is not set
++# CONFIG_MMC_DW is not set
++# CONFIG_MMC_VUB300 is not set
++# CONFIG_MMC_USHC is not set
++# CONFIG_MMC_USDHI6ROL0 is not set
++CONFIG_HIMCIV200=y
++CONFIG_SEND_AUTO_STOP=y
++CONFIG_DETECT_CARD_TIME=200
++# CONFIG_MEMSTICK is not set
++# CONFIG_NEW_LEDS is not set
++# CONFIG_SWITCH is not set
++# CONFIG_ACCESSIBILITY is not set
++# CONFIG_EDAC is not set
++CONFIG_RTC_LIB=y
++# CONFIG_RTC_CLASS is not set
++# CONFIG_DMADEVICES is not set
++# CONFIG_AUXDISPLAY is not set
++# CONFIG_UIO is not set
++# CONFIG_VIRT_DRIVERS is not set
++
++#
++# Virtio drivers
++#
++# CONFIG_VIRTIO_MMIO is not set
++
++#
++# Microsoft Hyper-V guest support
++#
++# CONFIG_STAGING is not set
++
++#
++# SOC (System On Chip) specific Drivers
++#
++# CONFIG_SOC_TI is not set
++CONFIG_CLKDEV_LOOKUP=y
++CONFIG_HAVE_CLK_PREPARE=y
++CONFIG_COMMON_CLK=y
++
++#
++# Common Clock Framework
++#
++# CONFIG_COMMON_CLK_SI5351 is not set
++# CONFIG_COMMON_CLK_SI570 is not set
++# CONFIG_COMMON_CLK_PXA is not set
++# CONFIG_COMMON_CLK_QCOM is not set
++
++#
++# Hardware Spinlock drivers
++#
++
++#
++# Clock Source drivers
++#
++CONFIG_CLKSRC_OF=y
++CONFIG_CLKSRC_MMIO=y
++CONFIG_ARM_ARCH_TIMER=y
++CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y
++# CONFIG_ARM_ARCH_TIMER_VCT_ACCESS is not set
++# CONFIG_ATMEL_PIT is not set
++# CONFIG_SH_TIMER_CMT is not set
++# CONFIG_SH_TIMER_MTU2 is not set
++# CONFIG_SH_TIMER_TMU is not set
++# CONFIG_EM_TIMER_STI is not set
++# CONFIG_CLKSRC_VERSATILE is not set
++# CONFIG_MAILBOX is not set
++# CONFIG_IOMMU_SUPPORT is not set
++
++#
++# Remoteproc drivers
++#
++# CONFIG_STE_MODEM_RPROC is not set
++
++#
++# Rpmsg drivers
++#
++
++#
++# SOC (System On Chip) specific Drivers
++#
++# 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
++CONFIG_IRQCHIP=y
++CONFIG_ARM_GIC=y
++# CONFIG_IPACK_BUS is not set
++CONFIG_ARCH_HAS_RESET_CONTROLLER=y
++CONFIG_RESET_CONTROLLER=y
++# CONFIG_FMC is not set
++
++#
++# PHY Subsystem
++#
++CONFIG_GENERIC_PHY=y
++# CONFIG_BCM_KONA_USB2_PHY is not set
++CONFIG_PHY_HISI_INNO_USB2=y
++# CONFIG_POWERCAP is not set
++# CONFIG_MCB is not set
++# CONFIG_HI_DMAC is not set
++
++#
++# Hisilicon driver support
++#
++# CONFIG_CMA_MEM_SHARED is not set
++# CONFIG_CMA_ADVANCE_SHARE is not set
++
++#
++# File systems
++#
++CONFIG_DCACHE_WORD_ACCESS=y
++# CONFIG_EXT2_FS is not set
++# CONFIG_EXT3_FS is not set
++CONFIG_EXT4_FS=y
++CONFIG_EXT4_USE_FOR_EXT23=y
++# CONFIG_EXT4_FS_POSIX_ACL is not set
++# CONFIG_EXT4_FS_SECURITY is not set
++# CONFIG_EXT4_DEBUG is not set
++CONFIG_JBD2=y
++# CONFIG_JBD2_DEBUG is not set
++CONFIG_FS_MBCACHE=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_BTRFS_FS is not set
++# CONFIG_NILFS2_FS is not set
++CONFIG_FS_POSIX_ACL=y
++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 is not set
++# CONFIG_FUSE_FS is not set
++# CONFIG_OVERLAY_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_KERNFS=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=m
++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_YAFFS_FS=y
++CONFIG_YAFFS_YAFFS1=y
++# CONFIG_YAFFS_9BYTE_TAGS is not set
++# CONFIG_YAFFS_DOES_ECC is not set
++CONFIG_YAFFS_YAFFS2=y
++CONFIG_YAFFS_AUTO_YAFFS2=y
++# CONFIG_YAFFS_DISABLE_TAGS_ECC is not set
++# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
++# CONFIG_YAFFS_EMPTY_LOST_AND_FOUND is not set
++# CONFIG_YAFFS_DISABLE_BLOCK_REFRESHING is not set
++# CONFIG_YAFFS_DISABLE_BACKGROUND is not set
++# CONFIG_YAFFS_DISABLE_BAD_BLOCK_MARKING is not set
++CONFIG_YAFFS_XATTR=y
++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 is not set
++# CONFIG_JFFS2_FS_XATTR is not set
++# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
++CONFIG_JFFS2_ZLIB=y
++# CONFIG_JFFS2_LZO is not set
++CONFIG_JFFS2_RTIME=y
++# CONFIG_JFFS2_RUBIN 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 is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V2=y
++CONFIG_NFS_V3=y
++CONFIG_NFS_V3_ACL=y
++# CONFIG_NFS_V4 is not set
++# CONFIG_NFS_SWAP is not set
++# CONFIG_ROOT_NFS is not set
++# CONFIG_NFSD is not set
++CONFIG_GRACE_PERIOD=y
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_ACL_SUPPORT=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 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=y
++# CONFIG_DLM is not set
++
++#
++# Kernel hacking
++#
++
++#
++# printk and dmesg options
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4
++# CONFIG_BOOT_PRINTK_DELAY is not set
++
++#
++# Compile-time checks and compiler options
++#
++# CONFIG_DEBUG_INFO is not set
++# CONFIG_ENABLE_WARN_DEPRECATED is not set
++# CONFIG_ENABLE_MUST_CHECK is not set
++CONFIG_FRAME_WARN=1024
++# CONFIG_STRIP_ASM_SYMS is not set
++# CONFIG_READABLE_ASM is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++# CONFIG_DEBUG_FS is not set
++# CONFIG_HEADERS_CHECK is not set
++# CONFIG_DEBUG_SECTION_MISMATCH is not set
++# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
++# CONFIG_MAGIC_SYSRQ is not set
++CONFIG_DEBUG_KERNEL=y
++
++#
++# Memory Debugging
++#
++# 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_STACK_USAGE is not set
++# CONFIG_DEBUG_VM is not set
++CONFIG_DEBUG_MEMORY_INIT=y
++# CONFIG_DEBUG_HIGHMEM is not set
++# CONFIG_DEBUG_SHIRQ is not set
++
++#
++# Debug Lockups and Hangs
++#
++# CONFIG_LOCKUP_DETECTOR is not set
++# CONFIG_DETECT_HUNG_TASK is not set
++CONFIG_PANIC_ON_OOPS=y
++CONFIG_PANIC_ON_OOPS_VALUE=1
++CONFIG_PANIC_TIMEOUT=0
++CONFIG_SCHED_DEBUG=y
++# CONFIG_SCHEDSTATS is not set
++# CONFIG_SCHED_STACK_END_CHECK is not set
++# CONFIG_TIMER_STATS is not set
++
++#
++# Lock Debugging (spinlocks, mutexes, etc...)
++#
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_LOCK_STAT is not set
++# CONFIG_DEBUG_ATOMIC_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_LOCK_TORTURE_TEST is not set
++CONFIG_STACKTRACE=y
++# CONFIG_DEBUG_KOBJECT is not set
++CONFIG_DEBUG_BUGVERBOSE=y
++# CONFIG_DEBUG_LIST is not set
++# CONFIG_DEBUG_PI_LIST is not set
++# CONFIG_DEBUG_SG is not set
++# CONFIG_DEBUG_NOTIFIERS is not set
++# CONFIG_DEBUG_CREDENTIALS is not set
++
++#
++# RCU Debugging
++#
++# CONFIG_SPARSE_RCU_POINTER is not set
++# CONFIG_TORTURE_TEST is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_RCU_TRACE is not set
++# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_NOTIFIER_ERROR_INJECTION is not set
++# CONFIG_FAULT_INJECTION is not set
++# CONFIG_LATENCYTOP 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 is not set
++
++#
++# Runtime Testing
++#
++# CONFIG_TEST_LIST_SORT is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_RBTREE_TEST is not set
++# CONFIG_INTERVAL_TREE_TEST is not set
++# CONFIG_PERCPU_TEST is not set
++# CONFIG_ATOMIC64_SELFTEST is not set
++# CONFIG_TEST_STRING_HELPERS is not set
++# CONFIG_TEST_KSTRTOX is not set
++# CONFIG_TEST_RHASHTABLE is not set
++# CONFIG_DMA_API_DEBUG is not set
++# CONFIG_TEST_LKM is not set
++# CONFIG_TEST_USER_COPY is not set
++# CONFIG_TEST_BPF is not set
++# CONFIG_TEST_FIRMWARE is not set
++# CONFIG_TEST_UDELAY is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_KGDB is not set
++# CONFIG_ARM_PTDUMP is not set
++CONFIG_STRICT_DEVMEM=y
++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_DEBUG_UART_PL01X is not set
++# CONFIG_DEBUG_UART_8250 is not set
++# CONFIG_DEBUG_UART_BCM63XX is not set
++CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"
++# CONFIG_OC_ETM is not set
++# CONFIG_PID_IN_CONTEXTIDR is not set
++# CONFIG_DEBUG_SET_MODULE_RONX is not set
++# CONFIG_CORESIGHT is not set
++
++#
++# 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_AEAD=y
++CONFIG_CRYPTO_AEAD2=y
++CONFIG_CRYPTO_BLKCIPHER=y
++CONFIG_CRYPTO_BLKCIPHER2=y
++CONFIG_CRYPTO_HASH=y
++CONFIG_CRYPTO_HASH2=y
++CONFIG_CRYPTO_RNG=y
++CONFIG_CRYPTO_RNG2=y
++CONFIG_CRYPTO_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_WORKQUEUE=y
++# CONFIG_CRYPTO_CRYPTD is not set
++# CONFIG_CRYPTO_MCRYPTD is not set
++# CONFIG_CRYPTO_AUTHENC is not set
++# CONFIG_CRYPTO_TEST is not set
++
++#
++# Authenticated Encryption with Associated Data
++#
++CONFIG_CRYPTO_CCM=y
++# CONFIG_CRYPTO_GCM is not set
++CONFIG_CRYPTO_SEQIV=y
++
++#
++# Block modes
++#
++# CONFIG_CRYPTO_CBC is not set
++CONFIG_CRYPTO_CTR=y
++# 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_CMAC is not set
++# CONFIG_CRYPTO_HMAC is not set
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_VMAC is not set
++
++#
++# Digest
++#
++CONFIG_CRYPTO_CRC32C=y
++# CONFIG_CRYPTO_CRC32 is not set
++# CONFIG_CRYPTO_CRCT10DIF 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_SHA1_ARM_NEON is not set
++# CONFIG_CRYPTO_SHA256 is not set
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_SHA512_ARM_NEON 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_AES_ARM_BS is not set
++# CONFIG_CRYPTO_ANUBIS is not set
++CONFIG_CRYPTO_ARC4=y
++# 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=y
++# CONFIG_CRYPTO_ZLIB is not set
++CONFIG_CRYPTO_LZO=y
++# CONFIG_CRYPTO_LZ4 is not set
++# CONFIG_CRYPTO_LZ4HC is not set
++
++#
++# Random Number Generation
++#
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++# CONFIG_CRYPTO_DRBG_MENU is not set
++# CONFIG_CRYPTO_USER_API_HASH is not set
++# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
++CONFIG_CRYPTO_HW=y
++# CONFIG_BINARY_PRINTF is not set
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++CONFIG_GENERIC_STRNCPY_FROM_USER=y
++CONFIG_GENERIC_STRNLEN_USER=y
++CONFIG_GENERIC_NET_UTILS=y
++CONFIG_GENERIC_PCI_IOMAP=y
++CONFIG_GENERIC_IO=y
++CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
++# CONFIG_CRC_CCITT is not set
++CONFIG_CRC16=y
++# CONFIG_CRC_T10DIF is not set
++# 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=y
++# CONFIG_CRC8 is not set
++# CONFIG_AUDIT_ARCH_COMPAT_GENERIC is not set
++# CONFIG_RANDOM32_SELFTEST is not set
++CONFIG_ZLIB_INFLATE=y
++CONFIG_ZLIB_DEFLATE=y
++CONFIG_LZO_COMPRESS=y
++CONFIG_LZO_DECOMPRESS=y
++CONFIG_LZ4_DECOMPRESS=y
++CONFIG_XZ_DEC=y
++CONFIG_XZ_DEC_X86=y
++CONFIG_XZ_DEC_POWERPC=y
++CONFIG_XZ_DEC_IA64=y
++CONFIG_XZ_DEC_ARM=y
++CONFIG_XZ_DEC_ARMTHUMB=y
++CONFIG_XZ_DEC_SPARC=y
++CONFIG_XZ_DEC_BCJ=y
++# CONFIG_XZ_DEC_TEST is not set
++CONFIG_DECOMPRESS_GZIP=y
++CONFIG_DECOMPRESS_BZIP2=y
++CONFIG_DECOMPRESS_LZMA=y
++CONFIG_DECOMPRESS_XZ=y
++CONFIG_DECOMPRESS_LZO=y
++CONFIG_DECOMPRESS_LZ4=y
++CONFIG_GENERIC_ALLOCATOR=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT_MAP=y
++CONFIG_HAS_DMA=y
++CONFIG_DQL=y
++CONFIG_NLATTR=y
++CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
++CONFIG_AVERAGE=y
++# CONFIG_CORDIC is not set
++# CONFIG_DDR is not set
++CONFIG_LIBFDT=y
++CONFIG_ARCH_HAS_SG_CHAIN=y
++# CONFIG_VIRTUALIZATION is not set
+diff --git a/arch/arm/configs/hi3556_single_nand_defconfig b/arch/arm/configs/hi3556_single_nand_defconfig
+new file mode 100644
+index 0000000..03eae71
+--- /dev/null
++++ b/arch/arm/configs/hi3556_single_nand_defconfig
+@@ -0,0 +1,2614 @@
++#
++# Automatically generated file; DO NOT EDIT.
++# Linux/arm 3.18.20 Kernel Configuration
++#
++CONFIG_ARM=y
++CONFIG_ARM_HAS_SG_CHAIN=y
++CONFIG_MIGHT_HAVE_PCI=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=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_XCHGADD_ALGORITHM=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_NEED_DMA_MAP_STATE=y
++CONFIG_ARCH_SUPPORTS_UPROBES=y
++CONFIG_VECTORS_BASE=0xffff0000
++CONFIG_ARM_PATCH_PHYS_VIRT=y
++CONFIG_GENERIC_BUG=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++CONFIG_IRQ_WORK=y
++CONFIG_BUILDTIME_EXTABLE_SORT=y
++
++#
++# General setup
++#
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_CROSS_COMPILE=""
++# CONFIG_COMPILE_TEST is not set
++CONFIG_LOCALVERSION=""
++# CONFIG_LOCALVERSION_AUTO is not set
++CONFIG_HAVE_KERNEL_GZIP=y
++CONFIG_HAVE_KERNEL_LZMA=y
++CONFIG_HAVE_KERNEL_XZ=y
++CONFIG_HAVE_KERNEL_LZO=y
++CONFIG_HAVE_KERNEL_LZ4=y
++CONFIG_KERNEL_GZIP=y
++# CONFIG_KERNEL_LZMA is not set
++# CONFIG_KERNEL_XZ is not set
++# CONFIG_KERNEL_LZO is not set
++# CONFIG_KERNEL_LZ4 is not set
++# CONFIG_HW_DECOMPRESS is not set
++CONFIG_SOFT_DECOMPRESS=y
++CONFIG_DEFAULT_HOSTNAME="(none)"
++CONFIG_SWAP=y
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++# CONFIG_POSIX_MQUEUE is not set
++CONFIG_CROSS_MEMORY_ATTACH=y
++# CONFIG_FHANDLE is not set
++CONFIG_USELIB=y
++# CONFIG_AUDIT is not set
++CONFIG_HAVE_ARCH_AUDITSYSCALL=y
++
++#
++# IRQ subsystem
++#
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_GENERIC_IRQ_SHOW=y
++CONFIG_HARDIRQS_SW_RESEND=y
++CONFIG_IRQ_DOMAIN=y
++CONFIG_HANDLE_DOMAIN_IRQ=y
++CONFIG_IRQ_FORCED_THREADING=y
++CONFIG_SPARSE_IRQ=y
++CONFIG_GENERIC_CLOCKEVENTS=y
++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
++
++#
++# Timers subsystem
++#
++CONFIG_TICK_ONESHOT=y
++CONFIG_NO_HZ_COMMON=y
++# CONFIG_HZ_PERIODIC is not set
++CONFIG_NO_HZ_IDLE=y
++CONFIG_NO_HZ=y
++# CONFIG_HIGH_RES_TIMERS is not set
++
++#
++# CPU/Task time and stats accounting
++#
++CONFIG_TICK_CPU_ACCOUNTING=y
++# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set
++# CONFIG_IRQ_TIME_ACCOUNTING is not set
++# CONFIG_BSD_PROCESS_ACCT is not set
++# CONFIG_TASKSTATS is not set
++
++#
++# RCU Subsystem
++#
++CONFIG_TINY_RCU=y
++# CONFIG_PREEMPT_RCU is not set
++# CONFIG_TASKS_RCU is not set
++# CONFIG_RCU_STALL_COMMON is not set
++# CONFIG_TREE_RCU_TRACE is not set
++# CONFIG_BUILD_BIN2C is not set
++# CONFIG_IKCONFIG is not set
++CONFIG_LOG_BUF_SHIFT=17
++CONFIG_GENERIC_SCHED_CLOCK=y
++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_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_USER_NS is not set
++CONFIG_PID_NS=y
++CONFIG_NET_NS=y
++# 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=y
++CONFIG_RD_LZMA=y
++CONFIG_RD_XZ=y
++CONFIG_RD_LZO=y
++CONFIG_RD_LZ4=y
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++CONFIG_HAVE_UID16=y
++CONFIG_BPF=y
++# CONFIG_EXPERT is not set
++CONFIG_UID16=y
++# CONFIG_SGETMASK_SYSCALL is not set
++CONFIG_SYSFS_SYSCALL=y
++# CONFIG_SYSCTL_SYSCALL is not set
++CONFIG_KALLSYMS=y
++# CONFIG_KALLSYMS_ALL is not set
++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_BPF_SYSCALL is not set
++CONFIG_SHMEM=y
++CONFIG_AIO=y
++CONFIG_ADVISE_SYSCALLS=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 is not set
++# CONFIG_SLAB is not set
++CONFIG_SLUB=y
++# CONFIG_PROFILING is not set
++CONFIG_HAVE_OPROFILE=y
++# CONFIG_KPROBES is not set
++# CONFIG_JUMP_LABEL is not set
++# CONFIG_UPROBES is not set
++# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
++CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
++CONFIG_ARCH_USE_BUILTIN_BSWAP=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_GENERIC_SMP_IDLE_THREAD=y
++CONFIG_GENERIC_IDLE_POLL_SETUP=y
++CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
++CONFIG_HAVE_CLK=y
++CONFIG_HAVE_DMA_API_DEBUG=y
++CONFIG_HAVE_PERF_REGS=y
++CONFIG_HAVE_PERF_USER_STACK_DUMP=y
++CONFIG_HAVE_ARCH_JUMP_LABEL=y
++CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
++CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
++CONFIG_HAVE_CC_STACKPROTECTOR=y
++# CONFIG_CC_STACKPROTECTOR is not set
++CONFIG_CC_STACKPROTECTOR_NONE=y
++# CONFIG_CC_STACKPROTECTOR_REGULAR is not set
++# CONFIG_CC_STACKPROTECTOR_STRONG is not set
++CONFIG_HAVE_CONTEXT_TRACKING=y
++CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
++CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
++CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
++CONFIG_MODULES_USE_ELF_REL=y
++CONFIG_CLONE_BACKWARDS=y
++CONFIG_OLD_SIGSUSPEND3=y
++CONFIG_OLD_SIGACTION=y
++
++#
++# GCOV-based kernel profiling
++#
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_SLABINFO=y
++CONFIG_RT_MUTEXES=y
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++# CONFIG_MODULE_FORCE_LOAD is not set
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++# CONFIG_MODULE_SIG is not set
++# CONFIG_MODULE_COMPRESS is not set
++CONFIG_BLOCK=y
++CONFIG_LBDAF=y
++CONFIG_BLK_DEV_BSG=y
++# CONFIG_BLK_DEV_BSGLIB is not set
++# CONFIG_BLK_DEV_INTEGRITY is not set
++CONFIG_BLK_CMDLINE_PARSER=y
++
++#
++# Partition Types
++#
++CONFIG_PARTITION_ADVANCED=y
++# CONFIG_ACORN_PARTITION is not set
++# CONFIG_AIX_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=y
++# CONFIG_SYSV68_PARTITION is not set
++CONFIG_CMDLINE_PARTITION=y
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++CONFIG_DEFAULT_DEADLINE=y
++# CONFIG_DEFAULT_CFQ is not set
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="deadline"
++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_ARCH_SUPPORTS_ATOMIC_RMW=y
++CONFIG_FREEZER=y
++
++#
++# System Type
++#
++CONFIG_MMU=y
++CONFIG_ARCH_MULTIPLATFORM=y
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_AT91 is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_GEMINI is not set
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_IOP13XX is not set
++# CONFIG_ARCH_IOP32X is not set
++# CONFIG_ARCH_IOP33X is not set
++# CONFIG_ARCH_IXP4XX is not set
++# CONFIG_ARCH_DOVE is not set
++# CONFIG_ARCH_MV78XX0 is not set
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_MMP is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_W90X900 is not set
++# CONFIG_ARCH_LPC32XX is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_MSM is not set
++# CONFIG_ARCH_SHMOBILE_LEGACY 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_DAVINCI is not set
++# CONFIG_ARCH_OMAP1 is not set
++
++#
++# Multiple platform selection
++#
++
++#
++# CPU Core family selection
++#
++# CONFIG_ARCH_MULTI_V6 is not set
++CONFIG_ARCH_MULTI_V7=y
++CONFIG_ARCH_MULTI_V6_V7=y
++# CONFIG_ARCH_MULTI_CPU_AUTO is not set
++# CONFIG_ARCH_VIRT is not set
++# CONFIG_ARCH_MVEBU is not set
++# CONFIG_ARCH_BCM is not set
++# CONFIG_ARCH_BERLIN is not set
++# CONFIG_ARCH_HIGHBANK is not set
++CONFIG_ARCH_HISI=y
++
++#
++# Hisilicon platform type
++#
++# CONFIG_ARCH_HI3xxx is not set
++# CONFIG_ARCH_HIP04 is not set
++# CONFIG_ARCH_HIX5HD2 is not set
++# CONFIG_ARCH_HI3519 is not set
++# CONFIG_ARCH_HI3519V101 is not set
++# CONFIG_ARCH_HI3516AV200 is not set
++# CONFIG_ARCH_HI3559 is not set
++CONFIG_ARCH_HI3556=y
++# CONFIG_ARCH_HI3536C is not set
++# CONFIG_ARCH_HI3531D is not set
++# CONFIG_ARCH_HI3521D is not set
++# CONFIG_ARCH_KEYSTONE is not set
++# CONFIG_ARCH_MESON is not set
++# CONFIG_ARCH_MXC is not set
++# CONFIG_ARCH_MEDIATEK is not set
++
++#
++# TI OMAP/AM/DM/DRA Family
++#
++# CONFIG_ARCH_OMAP3 is not set
++# CONFIG_ARCH_OMAP4 is not set
++# CONFIG_SOC_OMAP5 is not set
++# CONFIG_SOC_AM33XX is not set
++# CONFIG_SOC_AM43XX is not set
++# CONFIG_SOC_DRA7XX is not set
++# CONFIG_ARCH_QCOM is not set
++# CONFIG_ARCH_ROCKCHIP is not set
++# CONFIG_ARCH_SOCFPGA is not set
++# CONFIG_PLAT_SPEAR is not set
++# CONFIG_ARCH_STI is not set
++# CONFIG_ARCH_S5PV210 is not set
++# CONFIG_ARCH_EXYNOS is not set
++# CONFIG_ARCH_SHMOBILE_MULTI is not set
++# CONFIG_ARCH_SUNXI is not set
++# CONFIG_ARCH_SIRF is not set
++# CONFIG_ARCH_TEGRA is not set
++# CONFIG_ARCH_U8500 is not set
++# CONFIG_ARCH_VEXPRESS is not set
++# CONFIG_ARCH_WM8850 is not set
++# CONFIG_ARCH_ZYNQ is not set
++CONFIG_ARM_TIMER_SP804=y
++
++#
++# Processor Type
++#
++CONFIG_CPU_V7=y
++CONFIG_CPU_32v6K=y
++CONFIG_CPU_32v7=y
++CONFIG_CPU_ABRT_EV7=y
++CONFIG_CPU_PABRT_V7=y
++CONFIG_CPU_CACHE_V7=y
++CONFIG_CPU_CACHE_VIPT=y
++CONFIG_CPU_COPY_V6=y
++CONFIG_CPU_TLB_V7=y
++CONFIG_CPU_HAS_ASID=y
++CONFIG_CPU_CP15=y
++CONFIG_CPU_CP15_MMU=y
++
++#
++# Processor Features
++#
++# CONFIG_ARM_LPAE is not set
++# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
++CONFIG_ARM_THUMB=y
++# CONFIG_ARM_THUMBEE is not set
++CONFIG_ARM_VIRT_EXT=y
++CONFIG_SWP_EMULATE=y
++# CONFIG_CPU_ICACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_DISABLE is not set
++# CONFIG_CPU_BPREDICT_DISABLE is not set
++CONFIG_KUSER_HELPERS=y
++CONFIG_MIGHT_HAVE_CACHE_L2X0=y
++# CONFIG_CACHE_L2X0 is not set
++CONFIG_ARM_L1_CACHE_SHIFT_6=y
++CONFIG_ARM_L1_CACHE_SHIFT=6
++CONFIG_ARM_DMA_MEM_BUFFERABLE=y
++CONFIG_MULTI_IRQ_HANDLER=y
++# CONFIG_ARM_ERRATA_430973 is not set
++# CONFIG_ARM_ERRATA_720789 is not set
++# CONFIG_ARM_ERRATA_754322 is not set
++# CONFIG_ARM_ERRATA_775420 is not set
++# CONFIG_ARM_ERRATA_773022 is not set
++
++#
++# Bus support
++#
++CONFIG_ARM_AMBA=y
++# CONFIG_PCI is not set
++# CONFIG_PCI_SYSCALL is not set
++# CONFIG_PCCARD is not set
++
++#
++# Kernel Features
++#
++CONFIG_HAVE_SMP=y
++# CONFIG_SMP is not set
++CONFIG_DISABLE_CPU_SCHED_DOMAIN_BALANCE=y
++CONFIG_HAVE_ARM_ARCH_TIMER=y
++CONFIG_VMSPLIT_3G=y
++# CONFIG_VMSPLIT_2G is not set
++# CONFIG_VMSPLIT_1G is not set
++CONFIG_PAGE_OFFSET=0xC0000000
++# CONFIG_ARM_PSCI is not set
++CONFIG_ARCH_NR_GPIO=0
++CONFIG_PREEMPT_NONE=y
++# CONFIG_PREEMPT_VOLUNTARY is not set
++# CONFIG_PREEMPT is not set
++CONFIG_HZ_FIXED=0
++# CONFIG_HZ_100 is not set
++# CONFIG_HZ_200 is not set
++# CONFIG_HZ_250 is not set
++# CONFIG_HZ_300 is not set
++# CONFIG_HZ_500 is not set
++CONFIG_HZ_1000=y
++CONFIG_HZ=1000
++# CONFIG_SCHED_HRTICK is not set
++# CONFIG_THUMB2_KERNEL is not set
++CONFIG_AEABI=y
++# CONFIG_OABI_COMPAT is not set
++# 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_ARCH_WANT_GENERAL_HUGETLB=y
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_HAVE_MEMBLOCK=y
++CONFIG_NO_BOOTMEM=y
++CONFIG_MEMORY_ISOLATION=y
++# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=4
++CONFIG_COMPACTION=y
++CONFIG_MIGRATION=y
++# CONFIG_PHYS_ADDR_T_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_BOUNCE=y
++# CONFIG_KSM is not set
++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
++CONFIG_NEED_PER_CPU_KM=y
++# CONFIG_CLEANCACHE is not set
++# CONFIG_FRONTSWAP is not set
++CONFIG_CMA=y
++# CONFIG_CMA_DEBUG is not set
++CONFIG_CMA_AREAS=7
++# CONFIG_ZPOOL is not set
++# CONFIG_ZBUD is not set
++# CONFIG_ZSMALLOC 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_SWIOTLB=y
++CONFIG_IOMMU_HELPER=y
++# CONFIG_XEN is not set
++# CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART is not set
++
++#
++# Boot options
++#
++CONFIG_USE_OF=y
++CONFIG_ATAGS=y
++# CONFIG_DEPRECATED_PARAM_STRUCT is not set
++# CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE is not set
++CONFIG_ZBOOT_ROM_TEXT=0
++CONFIG_ZBOOT_ROM_BSS=0
++CONFIG_ARM_APPENDED_DTB=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_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_GOV_COMMON=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_USERSPACE is not set
++CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
++# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE is not set
++CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
++CONFIG_CPU_FREQ_GOV_POWERSAVE=y
++CONFIG_CPU_FREQ_GOV_USERSPACE=y
++CONFIG_CPU_FREQ_GOV_ONDEMAND=y
++CONFIG_CPU_FREQ_GOV_INTERACTIVE=y
++# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
++# CONFIG_CPUFREQ_DT is not set
++
++#
++# ARM CPU frequency scaling drivers
++#
++# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set
++
++#
++# CPU Idle
++#
++# CONFIG_CPU_IDLE is not set
++# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++CONFIG_VFP=y
++CONFIG_VFPv3=y
++CONFIG_NEON=y
++CONFIG_KERNEL_MODE_NEON=y
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
++CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
++CONFIG_BINFMT_SCRIPT=y
++# CONFIG_HAVE_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
++CONFIG_COREDUMP=y
++
++#
++# Power management options
++#
++CONFIG_SUSPEND=y
++CONFIG_SUSPEND_FREEZER=y
++CONFIG_WAKELOCK=y
++CONFIG_HIBERNATE_CALLBACKS=y
++CONFIG_HISI_SNAPSHOT_BOOT=y
++# CONFIG_DEFAULT_MTD is not set
++CONFIG_DEFAULT_DDR=y
++CONFIG_SNAPSHOT_BUF_START=0x8a000000
++CONFIG_SNAPSHOT_BUF_SIZE=0x4000000
++CONFIG_HIBERNATION=y
++CONFIG_GZIP_COMPRESS=y
++CONFIG_PM_STD_PARTITION=""
++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_OPP=y
++CONFIG_PM_CLK=y
++# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set
++CONFIG_CPU_PM=y
++# CONFIG_SUSPEND_TIME is not set
++CONFIG_ARCH_SUSPEND_POSSIBLE=y
++CONFIG_ARM_CPU_SUSPEND=y
++CONFIG_ARCH_HIBERNATION_POSSIBLE=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_NET_IP_TUNNEL=m
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_NET_IPVTI is not set
++# CONFIG_NET_UDP_TUNNEL is not set
++# CONFIG_NET_FOU is not set
++# CONFIG_GENEVE 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=y
++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=y
++# 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_VTI 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_ANDROID_PARANOID_NETWORK is not set
++CONFIG_NET_ACTIVITY_STATS=y
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NET_PTP_CLASSIFY 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_NF_TABLES is not set
++# CONFIG_NETFILTER_XTABLES is not set
++# CONFIG_IP_SET is not set
++# CONFIG_IP_VS is not set
++
++#
++# IP: Netfilter Configuration
++#
++# CONFIG_NF_DEFRAG_IPV4 is not set
++# CONFIG_NF_LOG_ARP is not set
++# CONFIG_NF_LOG_IPV4 is not set
++# CONFIG_NF_REJECT_IPV4 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_NF_REJECT_IPV6 is not set
++# CONFIG_NF_LOG_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_HAVE_NET_DSA=y
++# 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_PHONET is not set
++# CONFIG_6LOWPAN 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_VSOCKETS is not set
++# CONFIG_NETLINK_MMAP is not set
++# CONFIG_NETLINK_DIAG is not set
++# CONFIG_NET_MPLS_GSO is not set
++# CONFIG_HSR is not set
++# CONFIG_CGROUP_NET_PRIO is not set
++# CONFIG_CGROUP_NET_CLASSID is not set
++CONFIG_NET_RX_BUSY_POLL=y
++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 is not set
++CONFIG_DEVTMPFS=y
++CONFIG_DEVTMPFS_MOUNT=y
++CONFIG_STANDALONE=y
++# CONFIG_PREVENT_FIRMWARE_BUILD is not set
++CONFIG_FW_LOADER=y
++# CONFIG_FIRMWARE_IN_KERNEL is not set
++CONFIG_EXTRA_FIRMWARE=""
++# CONFIG_FW_LOADER_USER_HELPER_FALLBACK is not set
++CONFIG_ALLOW_DEV_COREDUMP=y
++# 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_HAVE_CPU_AUTOPROBE is not set
++CONFIG_REGMAP=y
++CONFIG_REGMAP_MMIO=y
++CONFIG_DMA_SHARED_BUFFER=y
++# CONFIG_FENCE_TRACE is not set
++CONFIG_DMA_CMA=y
++
++#
++# Default contiguous memory area size:
++#
++CONFIG_CMA_SIZE_MBYTES=16
++CONFIG_CMA_SIZE_SEL_MBYTES=y
++# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set
++# CONFIG_CMA_SIZE_SEL_MIN is not set
++# CONFIG_CMA_SIZE_SEL_MAX is not set
++CONFIG_CMA_ALIGNMENT=8
++
++#
++# Bus devices
++#
++# CONFIG_BRCMSTB_GISB_ARB is not set
++CONFIG_ARM_CCI=y
++# CONFIG_VEXPRESS_CONFIG 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=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_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
++CONFIG_HIFMC=y
++# CONFIG_HIFMC_SPI_NAND is not set
++CONFIG_HIFMC_NAND=y
++
++#
++# 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_SST25L is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_PHRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++# CONFIG_MTD_BLOCK2MTD is not set
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOCG3 is not set
++CONFIG_MTD_NAND_IDS=y
++CONFIG_MTD_NAND_ECC=y
++# CONFIG_MTD_NAND_ECC_SMC is not set
++CONFIG_MTD_NAND=y
++# CONFIG_MTD_NAND_ECC_BCH is not set
++# CONFIG_MTD_SM_COMMON is not set
++# CONFIG_MTD_NAND_DENALI is not set
++# CONFIG_MTD_NAND_GPIO is not set
++# CONFIG_MTD_NAND_OMAP_BCH_BUILD is not set
++# CONFIG_MTD_NAND_DISKONCHIP is not set
++# CONFIG_MTD_NAND_DOCG4 is not set
++# CONFIG_MTD_NAND_NANDSIM is not set
++# CONFIG_MTD_NAND_PLATFORM is not set
++# CONFIG_HISI_NAND_FS_MAY_NO_YAFFS2 is not set
++# CONFIG_HISI_NAND_ECC_STATUS_REPORT is not set
++# CONFIG_MTD_NAND_HINFC610 is not set
++CONFIG_HIFMC100_NAND=y
++CONFIG_HIFMC100_MAX_NAND_CHIP=1
++# CONFIG_HIFMC100_NAND_EDO_MODE is not set
++CONFIG_RW_H_WIDTH=10
++CONFIG_R_L_WIDTH=10
++CONFIG_W_L_WIDTH=10
++# CONFIG_HIFMC100_NAND_HARDWARE_PAGESIZE_ECC is not set
++CONFIG_HIFMC100_NAND_AUTO_PAGESIZE_ECC=y
++# CONFIG_HIFMC100_NAND_PAGESIZE_AUTO_ECC_NONE is not set
++# CONFIG_MTD_ONENAND is not set
++
++#
++# LPDDR & LPDDR2 PCM memory drivers
++#
++# CONFIG_MTD_LPDDR is not set
++# CONFIG_MTD_LPDDR2_NVM is not set
++# CONFIG_MTD_SPI_NOR is not set
++CONFIG_MTD_UBI=y
++CONFIG_MTD_UBI_WL_THRESHOLD=4096
++CONFIG_MTD_UBI_BEB_LIMIT=20
++# CONFIG_MTD_UBI_FASTMAP is not set
++# CONFIG_MTD_UBI_GLUEBI is not set
++# CONFIG_MTD_UBI_BLOCK is not set
++CONFIG_DTC=y
++CONFIG_OF=y
++
++#
++# Device Tree and Open Firmware support
++#
++# 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_NET=y
++CONFIG_OF_MDIO=y
++CONFIG_OF_MTD=y
++CONFIG_OF_RESERVED_MEM=y
++CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
++# CONFIG_PARPORT is not set
++CONFIG_BLK_DEV=y
++# CONFIG_BLK_DEV_NULL_BLK is not set
++# CONFIG_BLK_DEV_COW_COMMON is not set
++# CONFIG_BLK_DEV_LOOP 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=65536
++# 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_DUMMY_IRQ 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_UID_STAT is not set
++# CONFIG_BMP085_I2C is not set
++# CONFIG_BMP085_SPI is not set
++# CONFIG_USB_SWITCH_FSA9480 is not set
++# CONFIG_LATTICE_ECP3_CONFIG is not set
++# CONFIG_SRAM is not set
++# CONFIG_C2PORT is not set
++
++#
++# EEPROM support
++#
++# CONFIG_EEPROM_AT24 is not set
++# CONFIG_EEPROM_AT25 is not set
++# CONFIG_EEPROM_LEGACY is not set
++# CONFIG_EEPROM_MAX6875 is not set
++# CONFIG_EEPROM_93CX6 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
++
++#
++# Intel MIC Bus Driver
++#
++
++#
++# Intel MIC Host Driver
++#
++
++#
++# Intel MIC Card Driver
++#
++# CONFIG_ECHO is not set
++# CONFIG_CXL_BASE is not set
++
++#
++# hisi 'himm/himd.l/himc'support
++#
++# CONFIG_HISI_REG 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_NETLINK is not set
++# CONFIG_SCSI_MQ_DEFAULT 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_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 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_NET_CORE=y
++# CONFIG_BONDING is not set
++# CONFIG_DUMMY is not set
++# CONFIG_EQUALIZER is not set
++# CONFIG_NET_TEAM is not set
++# CONFIG_MACVLAN is not set
++# CONFIG_VXLAN is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_TUN is not set
++# CONFIG_VETH is not set
++# CONFIG_NLMON is not set
++
++#
++# 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_NET_DSA_MV88E6171 is not set
++# CONFIG_NET_DSA_BCM_SF2 is not set
++# CONFIG_ETHERNET is not set
++CONFIG_PHYLIB=y
++
++#
++# MII PHY device drivers
++#
++# CONFIG_AT803X_PHY is not set
++# CONFIG_AMD_PHY is not set
++# CONFIG_AMD_XGBE_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 is not set
++# CONFIG_BROADCOM_PHY is not set
++# CONFIG_BCM7XXX_PHY is not set
++# CONFIG_BCM87XX_PHY is not set
++# CONFIG_ICPLUS_PHY is not set
++# CONFIG_REALTEK_PHY is not set
++# CONFIG_NATIONAL_PHY is not set
++# CONFIG_STE10XP is not set
++# CONFIG_LSI_ET1011C_PHY is not set
++# CONFIG_MICREL_PHY is not set
++# CONFIG_FIXED_PHY is not set
++# CONFIG_MDIO_BITBANG is not set
++# CONFIG_MDIO_BUS_MUX_GPIO is not set
++# CONFIG_MDIO_BUS_MUX_MMIOREG is not set
++# CONFIG_MDIO_BCM_UNIMAC is not set
++# CONFIG_MDIO_HISI_FEMAC is not set
++# CONFIG_MDIO_HISI_GEMAC is not set
++# CONFIG_MICREL_KS8995MA is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++CONFIG_USB_NET_DRIVERS=y
++# 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_RTL8152 is not set
++# CONFIG_USB_USBNET is not set
++# CONFIG_USB_IPHETH is not set
++CONFIG_WLAN=y
++# CONFIG_WIFI_CONTROL_FUNC is not set
++# 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 is not set
++# CONFIG_INPUT_SPARSEKMAP is not set
++# CONFIG_INPUT_MATRIXKMAP is not set
++
++#
++# Userland interfaces
++#
++CONFIG_INPUT_MOUSEDEV=y
++CONFIG_INPUT_MOUSEDEV_PSAUX=y
++CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
++CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
++# CONFIG_INPUT_JOYDEV is not set
++CONFIG_INPUT_EVDEV=y
++# CONFIG_INPUT_EVBUG is not set
++# CONFIG_INPUT_KEYRESET is not set
++# CONFIG_INPUT_KEYCOMBO is not set
++
++#
++# Input Device Drivers
++#
++CONFIG_INPUT_KEYBOARD=y
++# CONFIG_KEYBOARD_ADP5588 is not set
++# CONFIG_KEYBOARD_ADP5589 is not set
++CONFIG_KEYBOARD_ATKBD=y
++# CONFIG_KEYBOARD_QT1070 is not set
++# CONFIG_KEYBOARD_QT2160 is not set
++# CONFIG_KEYBOARD_LKKBD is not set
++# CONFIG_KEYBOARD_GPIO is not set
++# CONFIG_KEYBOARD_GPIO_POLLED is not set
++# 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 is not set
++# CONFIG_KEYBOARD_CAP1106 is not set
++CONFIG_INPUT_MOUSE=y
++CONFIG_MOUSE_PS2=y
++CONFIG_MOUSE_PS2_ALPS=y
++CONFIG_MOUSE_PS2_LOGIPS2PP=y
++CONFIG_MOUSE_PS2_SYNAPTICS=y
++CONFIG_MOUSE_PS2_CYPRESS=y
++CONFIG_MOUSE_PS2_TRACKPOINT=y
++# CONFIG_MOUSE_PS2_ELANTECH is not set
++# CONFIG_MOUSE_PS2_SENTELIC is not set
++# CONFIG_MOUSE_PS2_TOUCHKIT is not set
++# CONFIG_MOUSE_SERIAL is not set
++# CONFIG_MOUSE_APPLETOUCH is not set
++# CONFIG_MOUSE_BCM5974 is not set
++# CONFIG_MOUSE_CYAPA is not set
++# CONFIG_MOUSE_VSXXXAA is not set
++# CONFIG_MOUSE_GPIO is not set
++# CONFIG_MOUSE_SYNAPTICS_I2C is not set
++# CONFIG_MOUSE_SYNAPTICS_USB is not set
++# CONFIG_INPUT_JOYSTICK is not set
++# CONFIG_INPUT_TABLET is not set
++# CONFIG_INPUT_TOUCHSCREEN is not set
++# CONFIG_INPUT_MISC is not set
++
++#
++# Hardware I/O ports
++#
++CONFIG_SERIO=y
++CONFIG_SERIO_SERPORT=y
++# CONFIG_SERIO_AMBAKMI is not set
++CONFIG_SERIO_LIBPS2=y
++# CONFIG_SERIO_RAW is not set
++# CONFIG_SERIO_ALTERA_PS2 is not set
++# CONFIG_SERIO_PS2MULT is not set
++# CONFIG_SERIO_ARC_PS2 is not set
++# CONFIG_SERIO_APBPS2 is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++CONFIG_TTY=y
++CONFIG_VT=y
++CONFIG_CONSOLE_TRANSLATIONS=y
++CONFIG_VT_CONSOLE=y
++CONFIG_VT_CONSOLE_SLEEP=y
++CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
++CONFIG_UNIX98_PTYS=y
++# CONFIG_DEVPTS_MULTIPLE_INSTANCES 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_DEVMEM=y
++CONFIG_DEVKMEM=y
++
++#
++# Serial drivers
++#
++CONFIG_SERIAL_EARLYCON=y
++# CONFIG_SERIAL_8250 is not set
++
++#
++# Non-8250 serial port support
++#
++# CONFIG_SERIAL_AMBA_PL010 is not set
++CONFIG_SERIAL_AMBA_PL011=y
++CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
++# CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST is not set
++# 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_SC16IS7XX is not set
++# CONFIG_SERIAL_ALTERA_JTAGUART is not set
++# CONFIG_SERIAL_ALTERA_UART is not set
++# CONFIG_SERIAL_IFX6X60 is not set
++# CONFIG_SERIAL_XILINX_PS_UART is not set
++# CONFIG_SERIAL_ARC is not set
++# CONFIG_SERIAL_FSL_LPUART is not set
++# CONFIG_SERIAL_ST_ASC is not set
++# CONFIG_HVC_DCC is not set
++# CONFIG_IPMI_HANDLER is not set
++CONFIG_HW_RANDOM=y
++# CONFIG_HW_RANDOM_TIMERIOMEM is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++# CONFIG_DCC_TTY is not set
++# CONFIG_XILLYBUS is not set
++
++#
++# I2C support
++#
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++# CONFIG_I2C_COMPAT is not set
++CONFIG_I2C_CHARDEV=y
++CONFIG_I2C_MUX=m
++
++#
++# Multiplexer I2C Chip support
++#
++# CONFIG_I2C_ARB_GPIO_CHALLENGE is not set
++# CONFIG_I2C_MUX_GPIO is not set
++# CONFIG_I2C_MUX_PCA9541 is not set
++# CONFIG_I2C_MUX_PCA954x is not set
++# CONFIG_I2C_HELPER_AUTO is not set
++# CONFIG_I2C_SMBUS is not set
++
++#
++# I2C Algorithms
++#
++# CONFIG_I2C_ALGOBIT is not set
++# CONFIG_I2C_ALGOPCF is not set
++# CONFIG_I2C_ALGOPCA is not set
++
++#
++# I2C Hardware Bus support
++#
++
++#
++# I2C system bus drivers (mostly embedded / system-on-chip)
++#
++# CONFIG_I2C_CBUS_GPIO is not set
++# CONFIG_I2C_DESIGNWARE_PLATFORM is not set
++# CONFIG_I2C_GPIO is not set
++# CONFIG_I2C_HIBVT is not set
++CONFIG_I2C_HISI_V110=y
++# CONFIG_I2C_NOMADIK 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_RK3X 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_ROBOTFUZZ_OSIF 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_CADENCE is not set
++# CONFIG_SPI_GPIO is not set
++# CONFIG_SPI_FSL_SPI is not set
++# CONFIG_SPI_OC_TINY is not set
++CONFIG_SPI_PL022=y
++# CONFIG_SPI_PXA2XX_PCI is not set
++# CONFIG_SPI_ROCKCHIP 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=y
++# CONFIG_SPI_TLE62X0 is not set
++# CONFIG_SPMI is not set
++# CONFIG_HSI is not set
++
++#
++# PPS support
++#
++# CONFIG_PPS is not set
++
++#
++# PPS generators support
++#
++
++#
++# PTP clock support
++#
++# CONFIG_PTP_1588_CLOCK is not set
++
++#
++# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
++#
++CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
++CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
++CONFIG_GPIOLIB=y
++CONFIG_GPIO_DEVRES=y
++CONFIG_OF_GPIO=y
++CONFIG_GPIOLIB_IRQCHIP=y
++# CONFIG_DEBUG_GPIO is not set
++CONFIG_GPIO_SYSFS=y
++
++#
++# Memory mapped GPIO drivers:
++#
++# CONFIG_GPIO_GENERIC_PLATFORM is not set
++# CONFIG_GPIO_DWAPB is not set
++# CONFIG_GPIO_EM is not set
++# CONFIG_GPIO_ZEVIO is not set
++CONFIG_GPIO_PL061=y
++# CONFIG_GPIO_SCH311X is not set
++# CONFIG_GPIO_SYSCON is not set
++# CONFIG_GPIO_GRGPIO is not set
++
++#
++# I2C GPIO expanders:
++#
++# CONFIG_GPIO_MAX7300 is not set
++# CONFIG_GPIO_MAX732X is not set
++# CONFIG_GPIO_PCA953X is not set
++# CONFIG_GPIO_PCF857X is not set
++# CONFIG_GPIO_SX150X is not set
++# CONFIG_GPIO_ADP5588 is not set
++# CONFIG_GPIO_ADNP is not set
++
++#
++# PCI GPIO expanders:
++#
++
++#
++# SPI GPIO expanders:
++#
++# CONFIG_GPIO_MAX7301 is not set
++# CONFIG_GPIO_MCP23S08 is not set
++# CONFIG_GPIO_MC33880 is not set
++# CONFIG_GPIO_74X164 is not set
++
++#
++# AC97 GPIO expanders:
++#
++
++#
++# LPC GPIO expanders:
++#
++
++#
++# MODULbus GPIO expanders:
++#
++
++#
++# USB GPIO expanders:
++#
++# CONFIG_W1 is not set
++CONFIG_POWER_SUPPLY=y
++# CONFIG_POWER_SUPPLY_DEBUG is not set
++# CONFIG_PDA_POWER is not set
++# CONFIG_TEST_POWER is not set
++# CONFIG_BATTERY_DS2780 is not set
++# CONFIG_BATTERY_DS2781 is not set
++# CONFIG_BATTERY_DS2782 is not set
++# CONFIG_BATTERY_SBS is not set
++# CONFIG_BATTERY_BQ27x00 is not set
++# CONFIG_BATTERY_MAX17040 is not set
++# CONFIG_BATTERY_MAX17042 is not set
++# CONFIG_CHARGER_MAX8903 is not set
++# CONFIG_CHARGER_LP8727 is not set
++# CONFIG_CHARGER_GPIO is not set
++# CONFIG_CHARGER_BQ2415X is not set
++# CONFIG_CHARGER_BQ24190 is not set
++# CONFIG_CHARGER_BQ24735 is not set
++# CONFIG_CHARGER_SMB347 is not set
++CONFIG_POWER_RESET=y
++# CONFIG_POWER_RESET_BRCMSTB is not set
++# CONFIG_POWER_RESET_GPIO is not set
++# CONFIG_POWER_RESET_GPIO_RESTART is not set
++CONFIG_POWER_RESET_HISI=y
++# CONFIG_POWER_RESET_LTC2952 is not set
++# CONFIG_POWER_RESET_RESTART is not set
++# CONFIG_POWER_RESET_VERSATILE is not set
++# CONFIG_POWER_RESET_SYSCON is not set
++# CONFIG_POWER_AVS is not set
++# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
++# CONFIG_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=y
++# CONFIG_MFD_AS3711 is not set
++# CONFIG_MFD_AS3722 is not set
++# CONFIG_PMIC_ADP5520 is not set
++# CONFIG_MFD_AAT2870_CORE is not set
++# CONFIG_MFD_BCM590XX is not set
++# CONFIG_MFD_AXP20X is not set
++# CONFIG_MFD_CROS_EC is not set
++# CONFIG_MFD_ASIC3 is not set
++# CONFIG_PMIC_DA903X is not set
++# CONFIG_MFD_DA9052_SPI is not set
++# CONFIG_MFD_DA9052_I2C is not set
++# CONFIG_MFD_DA9055 is not set
++# CONFIG_MFD_DA9063 is not set
++# CONFIG_MFD_MC13XXX_SPI is not set
++# CONFIG_MFD_MC13XXX_I2C is not set
++# CONFIG_MFD_HI6421_PMIC is not set
++CONFIG_MFD_HISI_FMC=y
++# CONFIG_HTC_EGPIO is not set
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_HTC_I2CPLD is not set
++# CONFIG_INTEL_SOC_PMIC is not set
++# CONFIG_MFD_KEMPLD is not set
++# CONFIG_MFD_88PM800 is not set
++# CONFIG_MFD_88PM805 is not set
++# CONFIG_MFD_88PM860X is not set
++# CONFIG_MFD_MAX14577 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_MENF21BMC is not set
++# CONFIG_EZX_PCAP is not set
++# CONFIG_MFD_VIPERBOARD is not set
++# CONFIG_MFD_RETU is not set
++# CONFIG_MFD_PCF50633 is not set
++# CONFIG_MFD_PM8921_CORE is not set
++# CONFIG_MFD_RTSX_USB is not set
++# CONFIG_MFD_RC5T583 is not set
++# CONFIG_MFD_RK808 is not set
++# CONFIG_MFD_RN5T618 is not set
++# CONFIG_MFD_SEC_CORE is not set
++# CONFIG_MFD_SI476X_CORE is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_MFD_SMSC is not set
++# CONFIG_ABX500_CORE is not set
++# CONFIG_MFD_STMPE is not set
++CONFIG_MFD_SYSCON=y
++# CONFIG_MFD_TI_AM335X_TSCADC is not set
++# CONFIG_MFD_LP3943 is not set
++# CONFIG_MFD_LP8788 is not set
++# CONFIG_MFD_PALMAS is not set
++# CONFIG_TPS6105X is not set
++# CONFIG_TPS65010 is not set
++# CONFIG_TPS6507X is not set
++# CONFIG_MFD_TPS65090 is not set
++# CONFIG_MFD_TPS65217 is not set
++# CONFIG_MFD_TPS65218 is not set
++# CONFIG_MFD_TPS6586X is not set
++# CONFIG_MFD_TPS65910 is not set
++# CONFIG_MFD_TPS65912 is not set
++# CONFIG_MFD_TPS65912_I2C is not set
++# CONFIG_MFD_TPS65912_SPI is not set
++# CONFIG_MFD_TPS80031 is not set
++# CONFIG_TWL4030_CORE is not set
++# CONFIG_TWL6040_CORE is not set
++# CONFIG_MFD_WL1273_CORE is not set
++# CONFIG_MFD_LM3533 is not set
++# CONFIG_MFD_TC3589X is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_MFD_T7L66XB is not set
++# CONFIG_MFD_TC6387XB is not set
++# CONFIG_MFD_TC6393XB is not set
++# CONFIG_MFD_ARIZONA_I2C is not set
++# CONFIG_MFD_ARIZONA_SPI is not set
++# CONFIG_MFD_WM8400 is not set
++# CONFIG_MFD_WM831X_I2C is not set
++# CONFIG_MFD_WM831X_SPI is not set
++# CONFIG_MFD_WM8350_I2C is not set
++# CONFIG_MFD_WM8994 is not set
++CONFIG_REGULATOR=y
++# CONFIG_REGULATOR_DEBUG is not set
++# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
++# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
++# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
++# CONFIG_REGULATOR_ACT8865 is not set
++# CONFIG_REGULATOR_AD5398 is not set
++# CONFIG_REGULATOR_ANATOP is not set
++# CONFIG_REGULATOR_DA9210 is not set
++# CONFIG_REGULATOR_DA9211 is not set
++# CONFIG_REGULATOR_FAN53555 is not set
++# CONFIG_REGULATOR_GPIO is not set
++# CONFIG_REGULATOR_ISL9305 is not set
++# CONFIG_REGULATOR_ISL6271A is not set
++# CONFIG_REGULATOR_LP3971 is not set
++# CONFIG_REGULATOR_LP3972 is not set
++# CONFIG_REGULATOR_LP872X is not set
++# CONFIG_REGULATOR_LP8755 is not set
++# CONFIG_REGULATOR_LTC3589 is not set
++# CONFIG_REGULATOR_MAX1586 is not set
++# CONFIG_REGULATOR_MAX8649 is not set
++# CONFIG_REGULATOR_MAX8660 is not set
++# CONFIG_REGULATOR_MAX8952 is not set
++# CONFIG_REGULATOR_MAX8973 is not set
++# CONFIG_REGULATOR_PFUZE100 is not set
++# CONFIG_REGULATOR_TPS51632 is not set
++# CONFIG_REGULATOR_TPS62360 is not set
++# CONFIG_REGULATOR_TPS65023 is not set
++# CONFIG_REGULATOR_TPS6507X is not set
++# CONFIG_REGULATOR_TPS6524X is not set
++CONFIG_MEDIA_SUPPORT=m
++
++#
++# Multimedia core support
++#
++CONFIG_MEDIA_CAMERA_SUPPORT=y
++# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set
++# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set
++# CONFIG_MEDIA_RADIO_SUPPORT is not set
++# CONFIG_MEDIA_SDR_SUPPORT is not set
++# CONFIG_MEDIA_RC_SUPPORT is not set
++# CONFIG_MEDIA_CONTROLLER is not set
++CONFIG_VIDEO_DEV=m
++CONFIG_VIDEO_V4L2=m
++# CONFIG_VIDEO_ADV_DEBUG is not set
++# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
++CONFIG_VIDEOBUF2_CORE=m
++CONFIG_VIDEOBUF2_MEMOPS=m
++CONFIG_VIDEOBUF2_VMALLOC=m
++# CONFIG_TTPCI_EEPROM is not set
++
++#
++# Media drivers
++#
++# CONFIG_MEDIA_USB_SUPPORT is not set
++# CONFIG_V4L_PLATFORM_DRIVERS is not set
++# CONFIG_V4L_MEM2MEM_DRIVERS is not set
++# CONFIG_V4L_TEST_DRIVERS is not set
++
++#
++# Supported MMC/SDIO adapters
++#
++# CONFIG_CYPRESS_FIRMWARE is not set
++
++#
++# Media ancillary drivers (tuners, sensors, i2c, frontends)
++#
++CONFIG_MEDIA_SUBDRV_AUTOSELECT=y
++
++#
++# Audio decoders, processors and mixers
++#
++
++#
++# RDS decoders
++#
++
++#
++# Video decoders
++#
++
++#
++# Video and audio decoders
++#
++
++#
++# Video encoders
++#
++
++#
++# Camera sensor devices
++#
++
++#
++# Flash devices
++#
++
++#
++# Video improvement chips
++#
++
++#
++# Audio/Video compression chips
++#
++
++#
++# Miscellaneous helper chips
++#
++
++#
++# Sensors used on soc_camera driver
++#
++
++#
++# Tools to develop new frontends
++#
++# CONFIG_DVB_DUMMY_FE is not set
++
++#
++# Graphics support
++#
++# CONFIG_IMX_IPUV3_CORE is not set
++
++#
++# Direct Rendering Manager
++#
++# CONFIG_DRM is not set
++
++#
++# Frame buffer Devices
++#
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++CONFIG_FB_CMDLINE=y
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++# CONFIG_FB_CFB_FILLRECT is not set
++# CONFIG_FB_CFB_COPYAREA is not set
++# CONFIG_FB_CFB_IMAGEBLIT is not set
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# 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_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_ARMCLCD is not set
++# CONFIG_FB_OPENCORES is not set
++# CONFIG_FB_S1D13XXX is not set
++# CONFIG_FB_SMSCUFX is not set
++# CONFIG_FB_UDL is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_BROADSHEET is not set
++# CONFIG_FB_AUO_K190X is not set
++# CONFIG_FB_SIMPLE is not set
++# CONFIG_FB_SSD1307 is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++# CONFIG_VGASTATE is not set
++
++#
++# Console display driver support
++#
++CONFIG_DUMMY_CONSOLE=y
++# CONFIG_FRAMEBUFFER_CONSOLE is not set
++# CONFIG_LOGO is not set
++# CONFIG_SOUND is not set
++
++#
++# HID support
++#
++CONFIG_HID=y
++# CONFIG_HID_BATTERY_STRENGTH is not set
++# CONFIG_HIDRAW is not set
++# CONFIG_UHID is not set
++CONFIG_HID_GENERIC=y
++
++#
++# Special HID drivers
++#
++CONFIG_HID_A4TECH=y
++# CONFIG_HID_ACRUX is not set
++CONFIG_HID_APPLE=y
++# CONFIG_HID_APPLEIR is not set
++# CONFIG_HID_AUREAL is not set
++CONFIG_HID_BELKIN=y
++CONFIG_HID_CHERRY=y
++CONFIG_HID_CHICONY=y
++# CONFIG_HID_CP2112 is not set
++CONFIG_HID_CYPRESS=y
++# CONFIG_HID_DRAGONRISE is not set
++# CONFIG_HID_EMS_FF is not set
++# CONFIG_HID_ELECOM is not set
++# CONFIG_HID_ELO is not set
++CONFIG_HID_EZKEY=y
++# CONFIG_HID_HOLTEK is not set
++# CONFIG_HID_HUION 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_ICADE is not set
++# CONFIG_HID_TWINHAN is not set
++CONFIG_HID_KENSINGTON=y
++# CONFIG_HID_LCPOWER is not set
++# CONFIG_HID_LENOVO is not set
++CONFIG_HID_LOGITECH=y
++# CONFIG_HID_LOGITECH_HIDPP is not set
++# CONFIG_LOGITECH_FF is not set
++# CONFIG_LOGIRUMBLEPAD2_FF is not set
++# CONFIG_LOGIG940_FF is not set
++# CONFIG_LOGIWHEELS_FF is not set
++# CONFIG_HID_MAGICMOUSE is not set
++CONFIG_HID_MICROSOFT=y
++CONFIG_HID_MONTEREY=y
++# 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_PENMOUNT is not set
++# CONFIG_HID_PETALYNX is not set
++# CONFIG_HID_PICOLCD is not set
++# CONFIG_HID_PRIMAX is not set
++# CONFIG_HID_ROCCAT is not set
++# CONFIG_HID_SAITEK is not set
++# CONFIG_HID_SAMSUNG is not set
++# CONFIG_HID_SPEEDLINK is not set
++# CONFIG_HID_STEELSERIES is not set
++# CONFIG_HID_SUNPLUS is not set
++# CONFIG_HID_RMI 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_XINMO is not set
++# CONFIG_HID_ZEROPLUS is not set
++# CONFIG_HID_ZYDACRON is not set
++# CONFIG_HID_SENSOR_HUB is not set
++
++#
++# USB HID support
++#
++CONFIG_USB_HID=y
++# CONFIG_HID_PID is not set
++# CONFIG_USB_HIDDEV is not set
++
++#
++# I2C HID support
++#
++# CONFIG_I2C_HID is not set
++CONFIG_USB_OHCI_LITTLE_ENDIAN=y
++CONFIG_USB_SUPPORT=y
++CONFIG_USB_COMMON=y
++CONFIG_USB_ARCH_HAS_HCD=y
++CONFIG_USB=y
++# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
++
++#
++# Miscellaneous USB options
++#
++# CONFIG_USB_DEFAULT_PERSIST is not set
++# CONFIG_USB_DYNAMIC_MINORS is not set
++# CONFIG_USB_OTG_WHITELIST is not set
++# CONFIG_USB_OTG_FSM is not set
++# CONFIG_USB_MON is not set
++# CONFIG_USB_WUSB_CBAF is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_C67X00_HCD is not set
++# CONFIG_USB_XHCI_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_FUSBH200_HCD is not set
++# CONFIG_USB_FOTG210_HCD is not set
++# CONFIG_USB_MAX3421_HCD is not set
++# CONFIG_USB_OHCI_HCD is not set
++# CONFIG_USB_SL811_HCD is not set
++# CONFIG_USB_R8A66597_HCD is not set
++# CONFIG_USB_HCD_TEST_MODE is not set
++
++#
++# USB Device Class drivers
++#
++# CONFIG_USB_ACM is not set
++# CONFIG_USB_PRINTER is not set
++# CONFIG_USB_WDM is not set
++# CONFIG_USB_TMC is not set
++
++#
++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
++#
++
++#
++# also be needed; see USB_STORAGE Help for more info
++#
++# CONFIG_USB_STORAGE is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++# CONFIG_USBIP_CORE is not set
++# CONFIG_USB_MUSB_HDRC is not set
++# CONFIG_USB_DWC3 is not set
++# CONFIG_USB_DWC2 is not set
++# CONFIG_USB_CHIPIDEA is not set
++
++#
++# USB port drivers
++#
++# CONFIG_USB_SERIAL is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
++# CONFIG_USB_SEVSEG is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
++# CONFIG_USB_APPLEDISPLAY is not set
++# CONFIG_USB_LD is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
++# CONFIG_USB_IOWARRIOR is not set
++# CONFIG_USB_TEST is not set
++# CONFIG_USB_EHSET_TEST_FIXTURE is not set
++# CONFIG_USB_ISIGHTFW is not set
++# CONFIG_USB_YUREX is not set
++# CONFIG_USB_EZUSB_FX2 is not set
++# CONFIG_USB_HSIC_USB3503 is not set
++# CONFIG_USB_LINK_LAYER_TEST is not set
++
++#
++# USB Physical Layer drivers
++#
++# CONFIG_USB_PHY is not set
++# CONFIG_USB_OTG_WAKELOCK is not set
++# CONFIG_NOP_USB_XCEIV is not set
++# CONFIG_AM335X_PHY_USB is not set
++# CONFIG_USB_GPIO_VBUS is not set
++# CONFIG_USB_ISP1301 is not set
++# CONFIG_USB_ULPI is not set
++CONFIG_USB_GADGET=y
++# CONFIG_USB_GADGET_DEBUG is not set
++# CONFIG_USB_GADGET_DEBUG_FILES is not set
++CONFIG_USB_GADGET_VBUS_DRAW=2
++CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2
++
++#
++# USB Peripheral Controller
++#
++# CONFIG_USB_FUSB300 is not set
++# CONFIG_USB_FOTG210_UDC is not set
++# CONFIG_USB_GR_UDC is not set
++# CONFIG_USB_R8A66597 is not set
++# CONFIG_USB_PXA27X is not set
++# CONFIG_USB_MV_UDC is not set
++CONFIG_HIUSB_DEVICE2_0=y
++CONFIG_USB_HISI_UDC=m
++# CONFIG_USB_AUTO_SWITCH is not set
++# CONFIG_HIUSB_DEVICE3_0 is not set
++# CONFIG_USB_MV_U3D is not set
++# CONFIG_USB_M66592 is not set
++# CONFIG_USB_NET2272 is not set
++# CONFIG_USB_GADGET_XILINX is not set
++# CONFIG_USB_DUMMY_HCD is not set
++CONFIG_USB_LIBCOMPOSITE=m
++CONFIG_USB_F_ACM=m
++CONFIG_USB_U_SERIAL=m
++CONFIG_USB_U_ETHER=m
++CONFIG_USB_F_RNDIS=m
++CONFIG_USB_F_MASS_STORAGE=m
++CONFIG_USB_F_UAC1=m
++CONFIG_USB_F_UVC=m
++# CONFIG_USB_CONFIGFS is not set
++# CONFIG_USB_ZERO is not set
++CONFIG_USB_AUDIO=m
++CONFIG_GADGET_UAC1=y
++# CONFIG_USB_ETH is not set
++# CONFIG_USB_G_NCM is not set
++# CONFIG_USB_GADGETFS is not set
++# CONFIG_USB_FUNCTIONFS is not set
++CONFIG_USB_MASS_STORAGE=m
++# CONFIG_USB_G_SERIAL is not set
++# CONFIG_USB_G_PRINTER is not set
++# CONFIG_USB_CDC_COMPOSITE is not set
++# CONFIG_USB_G_ACM_MS is not set
++CONFIG_USB_G_MULTI=m
++CONFIG_USB_G_MULTI_RNDIS=y
++# CONFIG_USB_G_MULTI_CDC is not set
++# CONFIG_USB_G_HID is not set
++# CONFIG_USB_G_DBGP is not set
++# CONFIG_USB_G_WEBCAM is not set
++CONFIG_USB_G_WEBCAM_AUDIO=m
++# CONFIG_UWB is not set
++CONFIG_MMC=y
++# CONFIG_MMC_DEBUG is not set
++# CONFIG_MMC_CLKGATE is not set
++CONFIG_MMC_EMBEDDED_SDIO=y
++# CONFIG_MMC_PARANOID_SD_INIT is not set
++
++#
++# MMC/SD/SDIO Card Drivers
++#
++CONFIG_MMC_BLOCK=y
++CONFIG_MMC_BLOCK_MINORS=8
++CONFIG_MMC_BLOCK_BOUNCE=y
++# CONFIG_MMC_BLOCK_DEFERRED_RESUME is not set
++# CONFIG_SDIO_UART is not set
++# CONFIG_MMC_TEST is not set
++
++#
++# MMC/SD/SDIO Host Controller Drivers
++#
++# CONFIG_MMC_ARMMMCI is not set
++# CONFIG_MMC_SDHCI is not set
++# CONFIG_MMC_DW is not set
++# CONFIG_MMC_VUB300 is not set
++# CONFIG_MMC_USHC is not set
++# CONFIG_MMC_USDHI6ROL0 is not set
++CONFIG_HIMCIV200=y
++CONFIG_SEND_AUTO_STOP=y
++CONFIG_DETECT_CARD_TIME=200
++# CONFIG_MEMSTICK is not set
++# CONFIG_NEW_LEDS is not set
++# CONFIG_SWITCH is not set
++# CONFIG_ACCESSIBILITY is not set
++# CONFIG_EDAC is not set
++CONFIG_RTC_LIB=y
++# CONFIG_RTC_CLASS is not set
++# CONFIG_DMADEVICES is not set
++# CONFIG_AUXDISPLAY is not set
++# CONFIG_UIO is not set
++# CONFIG_VIRT_DRIVERS is not set
++
++#
++# Virtio drivers
++#
++# CONFIG_VIRTIO_MMIO is not set
++
++#
++# Microsoft Hyper-V guest support
++#
++# CONFIG_STAGING is not set
++
++#
++# SOC (System On Chip) specific Drivers
++#
++# CONFIG_SOC_TI is not set
++CONFIG_CLKDEV_LOOKUP=y
++CONFIG_HAVE_CLK_PREPARE=y
++CONFIG_COMMON_CLK=y
++
++#
++# Common Clock Framework
++#
++# CONFIG_COMMON_CLK_SI5351 is not set
++# CONFIG_COMMON_CLK_SI570 is not set
++# CONFIG_COMMON_CLK_PXA is not set
++# CONFIG_COMMON_CLK_QCOM is not set
++
++#
++# Hardware Spinlock drivers
++#
++
++#
++# Clock Source drivers
++#
++CONFIG_CLKSRC_OF=y
++CONFIG_CLKSRC_MMIO=y
++CONFIG_ARM_ARCH_TIMER=y
++CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y
++# CONFIG_ATMEL_PIT is not set
++# CONFIG_SH_TIMER_CMT is not set
++# CONFIG_SH_TIMER_MTU2 is not set
++# CONFIG_SH_TIMER_TMU is not set
++# CONFIG_EM_TIMER_STI is not set
++# CONFIG_CLKSRC_VERSATILE is not set
++# CONFIG_MAILBOX is not set
++# CONFIG_IOMMU_SUPPORT is not set
++
++#
++# Remoteproc drivers
++#
++# CONFIG_STE_MODEM_RPROC is not set
++
++#
++# Rpmsg drivers
++#
++
++#
++# SOC (System On Chip) specific Drivers
++#
++# 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
++CONFIG_IRQCHIP=y
++CONFIG_ARM_GIC=y
++# CONFIG_IPACK_BUS is not set
++CONFIG_ARCH_HAS_RESET_CONTROLLER=y
++CONFIG_RESET_CONTROLLER=y
++# CONFIG_FMC is not set
++
++#
++# PHY Subsystem
++#
++CONFIG_GENERIC_PHY=y
++# CONFIG_BCM_KONA_USB2_PHY is not set
++CONFIG_PHY_HISI_INNO_USB2=y
++# CONFIG_POWERCAP is not set
++# CONFIG_MCB is not set
++# CONFIG_HI_DMAC is not set
++
++#
++# Hisilicon driver support
++#
++# CONFIG_CMA_MEM_SHARED is not set
++# CONFIG_CMA_ADVANCE_SHARE is not set
++
++#
++# File systems
++#
++CONFIG_DCACHE_WORD_ACCESS=y
++# CONFIG_EXT2_FS is not set
++# CONFIG_EXT3_FS is not set
++CONFIG_EXT4_FS=y
++CONFIG_EXT4_USE_FOR_EXT23=y
++# CONFIG_EXT4_FS_POSIX_ACL is not set
++# CONFIG_EXT4_FS_SECURITY is not set
++# CONFIG_EXT4_DEBUG is not set
++CONFIG_JBD2=y
++# CONFIG_JBD2_DEBUG is not set
++CONFIG_FS_MBCACHE=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_BTRFS_FS is not set
++# CONFIG_NILFS2_FS is not set
++CONFIG_FS_POSIX_ACL=y
++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 is not set
++# CONFIG_FUSE_FS is not set
++# CONFIG_OVERLAY_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_KERNFS=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=m
++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_YAFFS_FS=y
++CONFIG_YAFFS_YAFFS1=y
++# CONFIG_YAFFS_9BYTE_TAGS is not set
++# CONFIG_YAFFS_DOES_ECC is not set
++CONFIG_YAFFS_YAFFS2=y
++CONFIG_YAFFS_AUTO_YAFFS2=y
++# CONFIG_YAFFS_DISABLE_TAGS_ECC is not set
++# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
++# CONFIG_YAFFS_EMPTY_LOST_AND_FOUND is not set
++# CONFIG_YAFFS_DISABLE_BLOCK_REFRESHING is not set
++# CONFIG_YAFFS_DISABLE_BACKGROUND is not set
++# CONFIG_YAFFS_DISABLE_BAD_BLOCK_MARKING is not set
++CONFIG_YAFFS_XATTR=y
++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 is not set
++# CONFIG_JFFS2_FS_XATTR is not set
++# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
++CONFIG_JFFS2_ZLIB=y
++# CONFIG_JFFS2_LZO is not set
++CONFIG_JFFS2_RTIME=y
++# CONFIG_JFFS2_RUBIN 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 is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V2=y
++CONFIG_NFS_V3=y
++CONFIG_NFS_V3_ACL=y
++# CONFIG_NFS_V4 is not set
++# CONFIG_NFS_SWAP is not set
++# CONFIG_ROOT_NFS is not set
++# CONFIG_NFSD is not set
++CONFIG_GRACE_PERIOD=y
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_ACL_SUPPORT=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 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=y
++# CONFIG_DLM is not set
++
++#
++# Kernel hacking
++#
++
++#
++# printk and dmesg options
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4
++# CONFIG_BOOT_PRINTK_DELAY is not set
++
++#
++# Compile-time checks and compiler options
++#
++# CONFIG_DEBUG_INFO is not set
++# CONFIG_ENABLE_WARN_DEPRECATED is not set
++# CONFIG_ENABLE_MUST_CHECK is not set
++CONFIG_FRAME_WARN=1024
++# CONFIG_STRIP_ASM_SYMS is not set
++# CONFIG_READABLE_ASM is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++# CONFIG_DEBUG_FS is not set
++# CONFIG_HEADERS_CHECK is not set
++# CONFIG_DEBUG_SECTION_MISMATCH is not set
++# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
++# CONFIG_MAGIC_SYSRQ is not set
++CONFIG_DEBUG_KERNEL=y
++
++#
++# Memory Debugging
++#
++# 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_STACK_USAGE is not set
++# CONFIG_DEBUG_VM is not set
++CONFIG_DEBUG_MEMORY_INIT=y
++# CONFIG_DEBUG_HIGHMEM is not set
++# CONFIG_DEBUG_SHIRQ is not set
++
++#
++# Debug Lockups and Hangs
++#
++# CONFIG_LOCKUP_DETECTOR is not set
++# CONFIG_DETECT_HUNG_TASK is not set
++CONFIG_PANIC_ON_OOPS=y
++CONFIG_PANIC_ON_OOPS_VALUE=1
++CONFIG_PANIC_TIMEOUT=0
++CONFIG_SCHED_DEBUG=y
++# CONFIG_SCHEDSTATS is not set
++# CONFIG_SCHED_STACK_END_CHECK is not set
++# CONFIG_TIMER_STATS is not set
++
++#
++# Lock Debugging (spinlocks, mutexes, etc...)
++#
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_LOCK_STAT is not set
++# CONFIG_DEBUG_ATOMIC_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_LOCK_TORTURE_TEST is not set
++CONFIG_STACKTRACE=y
++# CONFIG_DEBUG_KOBJECT is not set
++CONFIG_DEBUG_BUGVERBOSE=y
++# CONFIG_DEBUG_LIST is not set
++# CONFIG_DEBUG_PI_LIST is not set
++# CONFIG_DEBUG_SG is not set
++# CONFIG_DEBUG_NOTIFIERS is not set
++# CONFIG_DEBUG_CREDENTIALS is not set
++
++#
++# RCU Debugging
++#
++# CONFIG_SPARSE_RCU_POINTER is not set
++# CONFIG_TORTURE_TEST is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_RCU_TRACE is not set
++# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_NOTIFIER_ERROR_INJECTION is not set
++# CONFIG_FAULT_INJECTION is not set
++# CONFIG_LATENCYTOP 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 is not set
++
++#
++# Runtime Testing
++#
++# CONFIG_TEST_LIST_SORT is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_RBTREE_TEST is not set
++# CONFIG_INTERVAL_TREE_TEST is not set
++# CONFIG_PERCPU_TEST is not set
++# CONFIG_ATOMIC64_SELFTEST is not set
++# CONFIG_TEST_STRING_HELPERS is not set
++# CONFIG_TEST_KSTRTOX is not set
++# CONFIG_TEST_RHASHTABLE is not set
++# CONFIG_DMA_API_DEBUG is not set
++# CONFIG_TEST_LKM is not set
++# CONFIG_TEST_USER_COPY is not set
++# CONFIG_TEST_BPF is not set
++# CONFIG_TEST_FIRMWARE is not set
++# CONFIG_TEST_UDELAY is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_KGDB is not set
++# CONFIG_ARM_PTDUMP is not set
++CONFIG_STRICT_DEVMEM=y
++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_DEBUG_UART_PL01X is not set
++# CONFIG_DEBUG_UART_8250 is not set
++# CONFIG_DEBUG_UART_BCM63XX is not set
++CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"
++# CONFIG_OC_ETM is not set
++# CONFIG_PID_IN_CONTEXTIDR is not set
++# CONFIG_DEBUG_SET_MODULE_RONX is not set
++# CONFIG_CORESIGHT is not set
++
++#
++# 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_AEAD=y
++CONFIG_CRYPTO_AEAD2=y
++CONFIG_CRYPTO_BLKCIPHER=y
++CONFIG_CRYPTO_BLKCIPHER2=y
++CONFIG_CRYPTO_HASH=y
++CONFIG_CRYPTO_HASH2=y
++CONFIG_CRYPTO_RNG=y
++CONFIG_CRYPTO_RNG2=y
++CONFIG_CRYPTO_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_WORKQUEUE=y
++# CONFIG_CRYPTO_CRYPTD is not set
++# CONFIG_CRYPTO_MCRYPTD is not set
++# CONFIG_CRYPTO_AUTHENC is not set
++# CONFIG_CRYPTO_TEST is not set
++
++#
++# Authenticated Encryption with Associated Data
++#
++CONFIG_CRYPTO_CCM=y
++# CONFIG_CRYPTO_GCM is not set
++CONFIG_CRYPTO_SEQIV=y
++
++#
++# Block modes
++#
++# CONFIG_CRYPTO_CBC is not set
++CONFIG_CRYPTO_CTR=y
++# 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_CMAC is not set
++# CONFIG_CRYPTO_HMAC is not set
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_VMAC is not set
++
++#
++# Digest
++#
++CONFIG_CRYPTO_CRC32C=y
++# CONFIG_CRYPTO_CRC32 is not set
++# CONFIG_CRYPTO_CRCT10DIF 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_SHA1_ARM_NEON is not set
++# CONFIG_CRYPTO_SHA256 is not set
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_SHA512_ARM_NEON 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_AES_ARM_BS is not set
++# CONFIG_CRYPTO_ANUBIS is not set
++CONFIG_CRYPTO_ARC4=y
++# 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=y
++# CONFIG_CRYPTO_ZLIB is not set
++CONFIG_CRYPTO_LZO=y
++# CONFIG_CRYPTO_LZ4 is not set
++# CONFIG_CRYPTO_LZ4HC is not set
++
++#
++# Random Number Generation
++#
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++# CONFIG_CRYPTO_DRBG_MENU is not set
++# CONFIG_CRYPTO_USER_API_HASH is not set
++# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
++CONFIG_CRYPTO_HW=y
++# CONFIG_BINARY_PRINTF is not set
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++CONFIG_GENERIC_STRNCPY_FROM_USER=y
++CONFIG_GENERIC_STRNLEN_USER=y
++CONFIG_GENERIC_NET_UTILS=y
++CONFIG_GENERIC_PCI_IOMAP=y
++CONFIG_GENERIC_IO=y
++CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
++# CONFIG_CRC_CCITT is not set
++CONFIG_CRC16=y
++# CONFIG_CRC_T10DIF is not set
++# 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=y
++# CONFIG_CRC8 is not set
++# CONFIG_AUDIT_ARCH_COMPAT_GENERIC is not set
++# CONFIG_RANDOM32_SELFTEST is not set
++CONFIG_ZLIB_INFLATE=y
++CONFIG_ZLIB_DEFLATE=y
++CONFIG_LZO_COMPRESS=y
++CONFIG_LZO_DECOMPRESS=y
++CONFIG_LZ4_DECOMPRESS=y
++CONFIG_XZ_DEC=y
++CONFIG_XZ_DEC_X86=y
++CONFIG_XZ_DEC_POWERPC=y
++CONFIG_XZ_DEC_IA64=y
++CONFIG_XZ_DEC_ARM=y
++CONFIG_XZ_DEC_ARMTHUMB=y
++CONFIG_XZ_DEC_SPARC=y
++CONFIG_XZ_DEC_BCJ=y
++# CONFIG_XZ_DEC_TEST is not set
++CONFIG_DECOMPRESS_GZIP=y
++CONFIG_DECOMPRESS_BZIP2=y
++CONFIG_DECOMPRESS_LZMA=y
++CONFIG_DECOMPRESS_XZ=y
++CONFIG_DECOMPRESS_LZO=y
++CONFIG_DECOMPRESS_LZ4=y
++CONFIG_GENERIC_ALLOCATOR=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT_MAP=y
++CONFIG_HAS_DMA=y
++CONFIG_DQL=y
++CONFIG_NLATTR=y
++CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
++CONFIG_AVERAGE=y
++# CONFIG_CORDIC is not set
++# CONFIG_DDR is not set
++CONFIG_LIBFDT=y
++CONFIG_ARCH_HAS_SG_CHAIN=y
++# CONFIG_VIRTUALIZATION is not set
+diff --git a/arch/arm/configs/hi3556_single_nand_mini_defconfig b/arch/arm/configs/hi3556_single_nand_mini_defconfig
+new file mode 100644
+index 0000000..b56c7ef
+--- /dev/null
++++ b/arch/arm/configs/hi3556_single_nand_mini_defconfig
+@@ -0,0 +1,2396 @@
++#
++# Automatically generated file; DO NOT EDIT.
++# Linux/arm 3.18.20 Kernel Configuration
++#
++CONFIG_ARM=y
++CONFIG_ARM_HAS_SG_CHAIN=y
++CONFIG_MIGHT_HAVE_PCI=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=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_XCHGADD_ALGORITHM=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_NEED_DMA_MAP_STATE=y
++CONFIG_ARCH_SUPPORTS_UPROBES=y
++CONFIG_VECTORS_BASE=0xffff0000
++CONFIG_ARM_PATCH_PHYS_VIRT=y
++CONFIG_GENERIC_BUG=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++CONFIG_IRQ_WORK=y
++CONFIG_BUILDTIME_EXTABLE_SORT=y
++
++#
++# General setup
++#
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_CROSS_COMPILE=""
++# CONFIG_COMPILE_TEST is not set
++CONFIG_LOCALVERSION=""
++# CONFIG_LOCALVERSION_AUTO is not set
++CONFIG_HAVE_KERNEL_GZIP=y
++CONFIG_HAVE_KERNEL_LZMA=y
++CONFIG_HAVE_KERNEL_XZ=y
++CONFIG_HAVE_KERNEL_LZO=y
++CONFIG_HAVE_KERNEL_LZ4=y
++CONFIG_KERNEL_GZIP=y
++# CONFIG_KERNEL_LZMA is not set
++# CONFIG_KERNEL_XZ is not set
++# CONFIG_KERNEL_LZO is not set
++# CONFIG_KERNEL_LZ4 is not set
++CONFIG_HW_DECOMPRESS=y
++# CONFIG_SOFT_DECOMPRESS is not set
++CONFIG_DEFAULT_HOSTNAME="(none)"
++# CONFIG_SWAP is not set
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++# CONFIG_POSIX_MQUEUE is not set
++CONFIG_CROSS_MEMORY_ATTACH=y
++# CONFIG_FHANDLE is not set
++CONFIG_USELIB=y
++# CONFIG_AUDIT is not set
++CONFIG_HAVE_ARCH_AUDITSYSCALL=y
++
++#
++# IRQ subsystem
++#
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_GENERIC_IRQ_SHOW=y
++CONFIG_HARDIRQS_SW_RESEND=y
++CONFIG_IRQ_DOMAIN=y
++CONFIG_HANDLE_DOMAIN_IRQ=y
++CONFIG_IRQ_FORCED_THREADING=y
++CONFIG_SPARSE_IRQ=y
++CONFIG_GENERIC_CLOCKEVENTS=y
++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
++
++#
++# Timers subsystem
++#
++CONFIG_TICK_ONESHOT=y
++CONFIG_NO_HZ_COMMON=y
++# CONFIG_HZ_PERIODIC is not set
++CONFIG_NO_HZ_IDLE=y
++CONFIG_NO_HZ=y
++# CONFIG_HIGH_RES_TIMERS is not set
++
++#
++# CPU/Task time and stats accounting
++#
++CONFIG_TICK_CPU_ACCOUNTING=y
++# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set
++# CONFIG_IRQ_TIME_ACCOUNTING is not set
++# CONFIG_BSD_PROCESS_ACCT is not set
++# CONFIG_TASKSTATS is not set
++
++#
++# RCU Subsystem
++#
++CONFIG_TINY_RCU=y
++# CONFIG_PREEMPT_RCU is not set
++# CONFIG_TASKS_RCU is not set
++# CONFIG_RCU_STALL_COMMON is not set
++# CONFIG_TREE_RCU_TRACE is not set
++# CONFIG_BUILD_BIN2C is not set
++# CONFIG_IKCONFIG is not set
++CONFIG_LOG_BUF_SHIFT=17
++CONFIG_GENERIC_SCHED_CLOCK=y
++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_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 is not set
++# CONFIG_SCHED_AUTOGROUP is not set
++# CONFIG_SYSFS_DEPRECATED is not set
++# CONFIG_RELAY is not set
++# CONFIG_BLK_DEV_INITRD is not set
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++CONFIG_HAVE_UID16=y
++CONFIG_BPF=y
++CONFIG_EXPERT=y
++# CONFIG_UID16 is not set
++# CONFIG_SGETMASK_SYSCALL is not set
++CONFIG_SYSFS_SYSCALL=y
++# CONFIG_SYSCTL_SYSCALL is not set
++CONFIG_KALLSYMS=y
++# CONFIG_KALLSYMS_ALL is not set
++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_BPF_SYSCALL is not set
++CONFIG_SHMEM=y
++CONFIG_AIO=y
++CONFIG_ADVISE_SYSCALLS=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 is not set
++# CONFIG_SLUB_DEBUG is not set
++# CONFIG_COMPAT_BRK is not set
++# 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_UPROBES is not set
++# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
++CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
++CONFIG_ARCH_USE_BUILTIN_BSWAP=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_GENERIC_SMP_IDLE_THREAD=y
++CONFIG_GENERIC_IDLE_POLL_SETUP=y
++CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
++CONFIG_HAVE_CLK=y
++CONFIG_HAVE_DMA_API_DEBUG=y
++CONFIG_HAVE_PERF_REGS=y
++CONFIG_HAVE_PERF_USER_STACK_DUMP=y
++CONFIG_HAVE_ARCH_JUMP_LABEL=y
++CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
++CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
++CONFIG_HAVE_CC_STACKPROTECTOR=y
++# CONFIG_CC_STACKPROTECTOR is not set
++CONFIG_CC_STACKPROTECTOR_NONE=y
++# CONFIG_CC_STACKPROTECTOR_REGULAR is not set
++# CONFIG_CC_STACKPROTECTOR_STRONG is not set
++CONFIG_HAVE_CONTEXT_TRACKING=y
++CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
++CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
++CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
++CONFIG_MODULES_USE_ELF_REL=y
++CONFIG_CLONE_BACKWARDS=y
++CONFIG_OLD_SIGSUSPEND3=y
++CONFIG_OLD_SIGACTION=y
++
++#
++# GCOV-based kernel profiling
++#
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_RT_MUTEXES=y
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++# CONFIG_MODULE_FORCE_LOAD is not set
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++# CONFIG_MODULE_SIG is not set
++# CONFIG_MODULE_COMPRESS is not set
++CONFIG_BLOCK=y
++CONFIG_LBDAF=y
++CONFIG_BLK_DEV_BSG=y
++# CONFIG_BLK_DEV_BSGLIB is not set
++# CONFIG_BLK_DEV_INTEGRITY is not set
++CONFIG_BLK_CMDLINE_PARSER=y
++
++#
++# Partition Types
++#
++CONFIG_PARTITION_ADVANCED=y
++# CONFIG_ACORN_PARTITION is not set
++# CONFIG_AIX_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=y
++# CONFIG_SYSV68_PARTITION is not set
++CONFIG_CMDLINE_PARTITION=y
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++CONFIG_DEFAULT_DEADLINE=y
++# CONFIG_DEFAULT_CFQ is not set
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="deadline"
++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_ARCH_SUPPORTS_ATOMIC_RMW=y
++CONFIG_FREEZER=y
++
++#
++# System Type
++#
++CONFIG_MMU=y
++CONFIG_ARCH_MULTIPLATFORM=y
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_AT91 is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_GEMINI is not set
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_IOP13XX is not set
++# CONFIG_ARCH_IOP32X is not set
++# CONFIG_ARCH_IOP33X is not set
++# CONFIG_ARCH_IXP4XX is not set
++# CONFIG_ARCH_DOVE is not set
++# CONFIG_ARCH_MV78XX0 is not set
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_MMP is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_W90X900 is not set
++# CONFIG_ARCH_LPC32XX is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_MSM is not set
++# CONFIG_ARCH_SHMOBILE_LEGACY 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_DAVINCI is not set
++# CONFIG_ARCH_OMAP1 is not set
++
++#
++# Multiple platform selection
++#
++
++#
++# CPU Core family selection
++#
++# CONFIG_ARCH_MULTI_V6 is not set
++CONFIG_ARCH_MULTI_V7=y
++CONFIG_ARCH_MULTI_V6_V7=y
++# CONFIG_ARCH_MULTI_CPU_AUTO is not set
++# CONFIG_ARCH_VIRT is not set
++# CONFIG_ARCH_MVEBU is not set
++# CONFIG_ARCH_BCM is not set
++# CONFIG_ARCH_BERLIN is not set
++# CONFIG_ARCH_HIGHBANK is not set
++CONFIG_ARCH_HISI=y
++
++#
++# Hisilicon platform type
++#
++# CONFIG_ARCH_HI3xxx is not set
++# CONFIG_ARCH_HIP04 is not set
++# CONFIG_ARCH_HIX5HD2 is not set
++# CONFIG_ARCH_HI3519 is not set
++# CONFIG_ARCH_HI3519V101 is not set
++# CONFIG_ARCH_HI3516AV200 is not set
++# CONFIG_ARCH_HI3559 is not set
++CONFIG_ARCH_HI3556=y
++# CONFIG_ARCH_HI3536C is not set
++# CONFIG_ARCH_HI3531D is not set
++# CONFIG_ARCH_HI3521D is not set
++# CONFIG_ARCH_KEYSTONE is not set
++# CONFIG_ARCH_MESON is not set
++# CONFIG_ARCH_MXC is not set
++# CONFIG_ARCH_MEDIATEK is not set
++
++#
++# TI OMAP/AM/DM/DRA Family
++#
++# CONFIG_ARCH_OMAP3 is not set
++# CONFIG_ARCH_OMAP4 is not set
++# CONFIG_SOC_OMAP5 is not set
++# CONFIG_SOC_AM33XX is not set
++# CONFIG_SOC_AM43XX is not set
++# CONFIG_SOC_DRA7XX is not set
++# CONFIG_ARCH_QCOM is not set
++# CONFIG_ARCH_ROCKCHIP is not set
++# CONFIG_ARCH_SOCFPGA is not set
++# CONFIG_PLAT_SPEAR is not set
++# CONFIG_ARCH_STI is not set
++# CONFIG_ARCH_S5PV210 is not set
++# CONFIG_ARCH_EXYNOS is not set
++# CONFIG_ARCH_SHMOBILE_MULTI is not set
++# CONFIG_ARCH_SUNXI is not set
++# CONFIG_ARCH_SIRF is not set
++# CONFIG_ARCH_TEGRA is not set
++# CONFIG_ARCH_U8500 is not set
++# CONFIG_ARCH_VEXPRESS is not set
++# CONFIG_ARCH_WM8850 is not set
++# CONFIG_ARCH_ZYNQ is not set
++CONFIG_ARM_TIMER_SP804=y
++
++#
++# Processor Type
++#
++CONFIG_CPU_V7=y
++CONFIG_CPU_32v6K=y
++CONFIG_CPU_32v7=y
++CONFIG_CPU_ABRT_EV7=y
++CONFIG_CPU_PABRT_V7=y
++CONFIG_CPU_CACHE_V7=y
++CONFIG_CPU_CACHE_VIPT=y
++CONFIG_CPU_COPY_V6=y
++CONFIG_CPU_TLB_V7=y
++CONFIG_CPU_HAS_ASID=y
++CONFIG_CPU_CP15=y
++CONFIG_CPU_CP15_MMU=y
++
++#
++# Processor Features
++#
++# CONFIG_ARM_LPAE is not set
++# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
++CONFIG_ARM_THUMB=y
++# CONFIG_ARM_THUMBEE is not set
++CONFIG_ARM_VIRT_EXT=y
++CONFIG_SWP_EMULATE=y
++# CONFIG_CPU_ICACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_DISABLE is not set
++# CONFIG_CPU_BPREDICT_DISABLE is not set
++CONFIG_KUSER_HELPERS=y
++CONFIG_MIGHT_HAVE_CACHE_L2X0=y
++# CONFIG_CACHE_L2X0 is not set
++CONFIG_ARM_L1_CACHE_SHIFT_6=y
++CONFIG_ARM_L1_CACHE_SHIFT=6
++CONFIG_ARM_DMA_MEM_BUFFERABLE=y
++CONFIG_MULTI_IRQ_HANDLER=y
++# CONFIG_ARM_ERRATA_430973 is not set
++# CONFIG_ARM_ERRATA_720789 is not set
++# CONFIG_ARM_ERRATA_754322 is not set
++# CONFIG_ARM_ERRATA_775420 is not set
++# CONFIG_ARM_ERRATA_773022 is not set
++
++#
++# Bus support
++#
++CONFIG_ARM_AMBA=y
++# CONFIG_PCI is not set
++# CONFIG_PCI_SYSCALL is not set
++# CONFIG_PCCARD is not set
++
++#
++# Kernel Features
++#
++CONFIG_HAVE_SMP=y
++# CONFIG_SMP is not set
++CONFIG_DISABLE_CPU_SCHED_DOMAIN_BALANCE=y
++CONFIG_HAVE_ARM_ARCH_TIMER=y
++CONFIG_VMSPLIT_3G=y
++# CONFIG_VMSPLIT_2G is not set
++# CONFIG_VMSPLIT_1G is not set
++CONFIG_PAGE_OFFSET=0xC0000000
++# CONFIG_ARM_PSCI is not set
++CONFIG_ARCH_NR_GPIO=0
++CONFIG_PREEMPT_NONE=y
++# CONFIG_PREEMPT_VOLUNTARY is not set
++# CONFIG_PREEMPT is not set
++CONFIG_HZ_FIXED=0
++# CONFIG_HZ_100 is not set
++# CONFIG_HZ_200 is not set
++# CONFIG_HZ_250 is not set
++# CONFIG_HZ_300 is not set
++# CONFIG_HZ_500 is not set
++CONFIG_HZ_1000=y
++CONFIG_HZ=1000
++# CONFIG_SCHED_HRTICK is not set
++# CONFIG_THUMB2_KERNEL is not set
++CONFIG_AEABI=y
++# CONFIG_OABI_COMPAT is not set
++# 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_ARCH_WANT_GENERAL_HUGETLB=y
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_HAVE_MEMBLOCK=y
++CONFIG_NO_BOOTMEM=y
++CONFIG_MEMORY_ISOLATION=y
++# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=4
++CONFIG_COMPACTION=y
++CONFIG_MIGRATION=y
++# CONFIG_PHYS_ADDR_T_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_BOUNCE=y
++# CONFIG_KSM is not set
++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
++CONFIG_NEED_PER_CPU_KM=y
++# CONFIG_CLEANCACHE is not set
++CONFIG_CMA=y
++# CONFIG_CMA_DEBUG is not set
++CONFIG_CMA_AREAS=7
++# CONFIG_ZPOOL is not set
++# CONFIG_ZBUD is not set
++# CONFIG_ZSMALLOC 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_SWIOTLB=y
++CONFIG_IOMMU_HELPER=y
++# CONFIG_XEN is not set
++# CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART is not set
++
++#
++# Boot options
++#
++CONFIG_USE_OF=y
++CONFIG_ATAGS=y
++# CONFIG_DEPRECATED_PARAM_STRUCT is not set
++# CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE is not set
++CONFIG_ZBOOT_ROM_TEXT=0
++CONFIG_ZBOOT_ROM_BSS=0
++CONFIG_ARM_APPENDED_DTB=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_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_GOV_COMMON=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 is not set
++CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
++# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE is not set
++CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
++CONFIG_CPU_FREQ_GOV_POWERSAVE=y
++CONFIG_CPU_FREQ_GOV_USERSPACE=y
++CONFIG_CPU_FREQ_GOV_ONDEMAND=y
++CONFIG_CPU_FREQ_GOV_INTERACTIVE=y
++# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
++# CONFIG_CPUFREQ_DT is not set
++
++#
++# ARM CPU frequency scaling drivers
++#
++# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set
++
++#
++# CPU Idle
++#
++# CONFIG_CPU_IDLE is not set
++# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++CONFIG_VFP=y
++CONFIG_VFPv3=y
++CONFIG_NEON=y
++CONFIG_KERNEL_MODE_NEON=y
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
++CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
++CONFIG_BINFMT_SCRIPT=y
++# CONFIG_HAVE_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
++CONFIG_COREDUMP=y
++
++#
++# Power management options
++#
++CONFIG_SUSPEND=y
++CONFIG_SUSPEND_FREEZER=y
++# CONFIG_WAKELOCK is not set
++# CONFIG_HISI_SNAPSHOT_BOOT is not set
++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_OPP=y
++CONFIG_PM_CLK=y
++# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set
++CONFIG_CPU_PM=y
++# CONFIG_SUSPEND_TIME is not set
++CONFIG_ARCH_SUSPEND_POSSIBLE=y
++CONFIG_ARM_CPU_SUSPEND=y
++CONFIG_ARCH_HIBERNATION_POSSIBLE=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_NET_IP_TUNNEL is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_NET_IPVTI is not set
++# CONFIG_NET_UDP_TUNNEL is not set
++# CONFIG_NET_FOU is not set
++# CONFIG_GENEVE 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 is not set
++CONFIG_INET_XFRM_MODE_TRANSPORT=y
++CONFIG_INET_XFRM_MODE_TUNNEL=y
++CONFIG_INET_XFRM_MODE_BEET=y
++CONFIG_INET_LRO=y
++CONFIG_INET_DIAG=y
++CONFIG_INET_TCP_DIAG=y
++# CONFIG_INET_UDP_DIAG is not set
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++# CONFIG_TCP_MD5SIG is not set
++# CONFIG_IPV6 is not set
++# CONFIG_ANDROID_PARANOID_NETWORK is not set
++CONFIG_NET_ACTIVITY_STATS=y
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NET_PTP_CLASSIFY 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_NF_TABLES is not set
++# CONFIG_NETFILTER_XTABLES is not set
++# CONFIG_IP_SET is not set
++# CONFIG_IP_VS is not set
++
++#
++# IP: Netfilter Configuration
++#
++# CONFIG_NF_DEFRAG_IPV4 is not set
++# CONFIG_NF_LOG_ARP is not set
++# CONFIG_NF_LOG_IPV4 is not set
++# CONFIG_NF_REJECT_IPV4 is not set
++# CONFIG_IP_NF_IPTABLES is not set
++# CONFIG_IP_NF_ARPTABLES 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_HAVE_NET_DSA=y
++# 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_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_VSOCKETS is not set
++# CONFIG_NETLINK_MMAP is not set
++# CONFIG_NETLINK_DIAG is not set
++# CONFIG_NET_MPLS_GSO is not set
++# CONFIG_HSR is not set
++# CONFIG_CGROUP_NET_PRIO is not set
++# CONFIG_CGROUP_NET_CLASSID is not set
++CONFIG_NET_RX_BUSY_POLL=y
++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 is not set
++CONFIG_DEVTMPFS=y
++CONFIG_DEVTMPFS_MOUNT=y
++CONFIG_STANDALONE=y
++# CONFIG_PREVENT_FIRMWARE_BUILD is not set
++CONFIG_FW_LOADER=y
++# CONFIG_FIRMWARE_IN_KERNEL is not set
++CONFIG_EXTRA_FIRMWARE=""
++# CONFIG_FW_LOADER_USER_HELPER_FALLBACK is not set
++CONFIG_ALLOW_DEV_COREDUMP=y
++# 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_HAVE_CPU_AUTOPROBE is not set
++CONFIG_REGMAP=y
++CONFIG_REGMAP_MMIO=y
++CONFIG_DMA_SHARED_BUFFER=y
++# CONFIG_FENCE_TRACE is not set
++CONFIG_DMA_CMA=y
++
++#
++# Default contiguous memory area size:
++#
++CONFIG_CMA_SIZE_MBYTES=16
++CONFIG_CMA_SIZE_SEL_MBYTES=y
++# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set
++# CONFIG_CMA_SIZE_SEL_MIN is not set
++# CONFIG_CMA_SIZE_SEL_MAX is not set
++CONFIG_CMA_ALIGNMENT=8
++
++#
++# Bus devices
++#
++# CONFIG_BRCMSTB_GISB_ARB is not set
++CONFIG_ARM_CCI=y
++# CONFIG_VEXPRESS_CONFIG 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=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_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_HIFMC=y
++# CONFIG_HIFMC_SPI_NAND is not set
++CONFIG_HIFMC_NAND=y
++
++#
++# 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_SST25L is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_PHRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++# CONFIG_MTD_BLOCK2MTD is not set
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOCG3 is not set
++CONFIG_MTD_NAND_IDS=y
++CONFIG_MTD_NAND_ECC=y
++# CONFIG_MTD_NAND_ECC_SMC is not set
++CONFIG_MTD_NAND=y
++# CONFIG_MTD_NAND_ECC_BCH is not set
++# CONFIG_MTD_SM_COMMON is not set
++# CONFIG_MTD_NAND_DENALI is not set
++# CONFIG_MTD_NAND_OMAP_BCH_BUILD is not set
++# CONFIG_MTD_NAND_DISKONCHIP is not set
++# CONFIG_MTD_NAND_DOCG4 is not set
++# CONFIG_MTD_NAND_NANDSIM is not set
++# CONFIG_MTD_NAND_PLATFORM is not set
++# CONFIG_HISI_NAND_FS_MAY_NO_YAFFS2 is not set
++# CONFIG_HISI_NAND_ECC_STATUS_REPORT is not set
++# CONFIG_MTD_NAND_HINFC610 is not set
++CONFIG_HIFMC100_NAND=y
++CONFIG_HIFMC100_MAX_NAND_CHIP=1
++CONFIG_HIFMC100_NAND_EDO_MODE=y
++CONFIG_RW_H_WIDTH=3
++CONFIG_R_L_WIDTH=2
++CONFIG_W_L_WIDTH=2
++# CONFIG_HIFMC100_NAND_HARDWARE_PAGESIZE_ECC is not set
++CONFIG_HIFMC100_NAND_AUTO_PAGESIZE_ECC=y
++# CONFIG_HIFMC100_NAND_PAGESIZE_AUTO_ECC_NONE is not set
++# CONFIG_MTD_ONENAND is not set
++
++#
++# LPDDR & LPDDR2 PCM memory drivers
++#
++# CONFIG_MTD_LPDDR is not set
++# CONFIG_MTD_LPDDR2_NVM is not set
++# CONFIG_MTD_SPI_NOR is not set
++CONFIG_MTD_UBI=y
++CONFIG_MTD_UBI_WL_THRESHOLD=4096
++CONFIG_MTD_UBI_BEB_LIMIT=20
++# CONFIG_MTD_UBI_FASTMAP is not set
++# CONFIG_MTD_UBI_GLUEBI is not set
++# CONFIG_MTD_UBI_BLOCK is not set
++CONFIG_DTC=y
++CONFIG_OF=y
++
++#
++# Device Tree and Open Firmware support
++#
++# 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_NET=y
++CONFIG_OF_MDIO=y
++CONFIG_OF_MTD=y
++CONFIG_OF_RESERVED_MEM=y
++CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
++# CONFIG_PARPORT is not set
++CONFIG_BLK_DEV=y
++# CONFIG_BLK_DEV_NULL_BLK is not set
++# CONFIG_BLK_DEV_COW_COMMON is not set
++# CONFIG_BLK_DEV_LOOP 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=65536
++# CONFIG_BLK_DEV_XIP is not set
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH 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_DUMMY_IRQ 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_UID_STAT is not set
++# CONFIG_BMP085_I2C is not set
++# CONFIG_BMP085_SPI is not set
++# CONFIG_USB_SWITCH_FSA9480 is not set
++# CONFIG_LATTICE_ECP3_CONFIG is not set
++# CONFIG_SRAM is not set
++# CONFIG_C2PORT is not set
++
++#
++# EEPROM support
++#
++# CONFIG_EEPROM_AT24 is not set
++# CONFIG_EEPROM_AT25 is not set
++# CONFIG_EEPROM_LEGACY is not set
++# CONFIG_EEPROM_MAX6875 is not set
++# CONFIG_EEPROM_93CX6 is not set
++# CONFIG_EEPROM_93XX46 is not set
++
++#
++# Texas Instruments shared transport line discipline
++#
++# 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
++
++#
++# Intel MIC Bus Driver
++#
++
++#
++# Intel MIC Host Driver
++#
++
++#
++# Intel MIC Card Driver
++#
++# CONFIG_ECHO is not set
++# CONFIG_CXL_BASE is not set
++
++#
++# hisi 'himm/himd.l/himc'support
++#
++# CONFIG_HISI_REG 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_NETLINK is not set
++# CONFIG_SCSI_MQ_DEFAULT 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_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 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_NET_CORE=y
++# CONFIG_BONDING is not set
++# CONFIG_DUMMY is not set
++# CONFIG_EQUALIZER is not set
++# CONFIG_NET_TEAM is not set
++# CONFIG_MACVLAN is not set
++# CONFIG_VXLAN is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_TUN is not set
++# CONFIG_VETH is not set
++# CONFIG_NLMON is not set
++
++#
++# 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_NET_DSA_MV88E6171 is not set
++# CONFIG_NET_DSA_BCM_SF2 is not set
++# CONFIG_ETHERNET is not set
++CONFIG_PHYLIB=y
++
++#
++# MII PHY device drivers
++#
++# CONFIG_AT803X_PHY is not set
++# CONFIG_AMD_PHY is not set
++# CONFIG_AMD_XGBE_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 is not set
++# CONFIG_BROADCOM_PHY is not set
++# CONFIG_BCM7XXX_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_MMIOREG is not set
++# CONFIG_MDIO_BCM_UNIMAC is not set
++# CONFIG_MDIO_HISI_FEMAC is not set
++# CONFIG_MDIO_HISI_GEMAC is not set
++# CONFIG_MICREL_KS8995MA is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++
++#
++# Host-side USB support is needed for USB Network Adapter support
++#
++CONFIG_USB_NET_DRIVERS=m
++# 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_RTL8152 is not set
++# CONFIG_USB_USBNET is not set
++# CONFIG_USB_IPHETH is not set
++CONFIG_WLAN=y
++# CONFIG_WIFI_CONTROL_FUNC is not set
++# 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 is not set
++# CONFIG_INPUT_SPARSEKMAP is not set
++# CONFIG_INPUT_MATRIXKMAP is not set
++
++#
++# Userland interfaces
++#
++# CONFIG_INPUT_MOUSEDEV is not set
++# CONFIG_INPUT_JOYDEV is not set
++CONFIG_INPUT_EVDEV=y
++# CONFIG_INPUT_EVBUG is not set
++# CONFIG_INPUT_KEYRESET is not set
++# CONFIG_INPUT_KEYCOMBO is not set
++
++#
++# Input Device Drivers
++#
++# CONFIG_INPUT_KEYBOARD is not set
++# CONFIG_INPUT_MOUSE is not set
++# CONFIG_INPUT_JOYSTICK is not set
++# CONFIG_INPUT_TABLET is not set
++# CONFIG_INPUT_TOUCHSCREEN is not set
++# CONFIG_INPUT_MISC is not set
++
++#
++# Hardware I/O ports
++#
++# CONFIG_SERIO is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++CONFIG_TTY=y
++CONFIG_VT=y
++CONFIG_CONSOLE_TRANSLATIONS=y
++CONFIG_VT_CONSOLE=y
++CONFIG_VT_CONSOLE_SLEEP=y
++CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
++CONFIG_UNIX98_PTYS=y
++# CONFIG_DEVPTS_MULTIPLE_INSTANCES 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_DEVMEM=y
++CONFIG_DEVKMEM=y
++
++#
++# Serial drivers
++#
++CONFIG_SERIAL_EARLYCON=y
++# CONFIG_SERIAL_8250 is not set
++
++#
++# Non-8250 serial port support
++#
++# CONFIG_SERIAL_AMBA_PL010 is not set
++CONFIG_SERIAL_AMBA_PL011=y
++CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
++# CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST is not set
++# 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_SC16IS7XX is not set
++# CONFIG_SERIAL_ALTERA_JTAGUART is not set
++# CONFIG_SERIAL_ALTERA_UART is not set
++# CONFIG_SERIAL_XILINX_PS_UART is not set
++# CONFIG_SERIAL_ARC is not set
++# CONFIG_SERIAL_FSL_LPUART is not set
++# CONFIG_SERIAL_ST_ASC is not set
++# CONFIG_TTY_PRINTK is not set
++# CONFIG_HVC_DCC is not set
++# CONFIG_IPMI_HANDLER is not set
++CONFIG_HW_RANDOM=y
++# CONFIG_HW_RANDOM_TIMERIOMEM is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++# CONFIG_DCC_TTY is not set
++# CONFIG_XILLYBUS is not set
++
++#
++# I2C support
++#
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++# CONFIG_I2C_COMPAT is not set
++CONFIG_I2C_CHARDEV=y
++CONFIG_I2C_MUX=m
++
++#
++# Multiplexer I2C Chip support
++#
++# CONFIG_I2C_MUX_PCA9541 is not set
++# CONFIG_I2C_HELPER_AUTO is not set
++# CONFIG_I2C_SMBUS is not set
++
++#
++# I2C Algorithms
++#
++# CONFIG_I2C_ALGOBIT is not set
++# CONFIG_I2C_ALGOPCF is not set
++# CONFIG_I2C_ALGOPCA is not set
++
++#
++# I2C Hardware Bus support
++#
++
++#
++# I2C system bus drivers (mostly embedded / system-on-chip)
++#
++# CONFIG_I2C_DESIGNWARE_PLATFORM is not set
++# CONFIG_I2C_HIBVT is not set
++CONFIG_I2C_HISI_V110=y
++# CONFIG_I2C_NOMADIK 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_RK3X 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_ROBOTFUZZ_OSIF 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_CADENCE is not set
++# CONFIG_SPI_FSL_SPI is not set
++CONFIG_SPI_PL022=y
++# CONFIG_SPI_PXA2XX_PCI is not set
++# CONFIG_SPI_ROCKCHIP 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=y
++# CONFIG_SPI_TLE62X0 is not set
++# CONFIG_SPMI is not set
++# CONFIG_HSI is not set
++
++#
++# PPS support
++#
++# CONFIG_PPS is not set
++
++#
++# PPS generators support
++#
++
++#
++# PTP clock support
++#
++# CONFIG_PTP_1588_CLOCK is not set
++
++#
++# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
++#
++CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
++CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
++# CONFIG_GPIOLIB is not set
++# CONFIG_W1 is not set
++CONFIG_POWER_SUPPLY=y
++# CONFIG_POWER_SUPPLY_DEBUG is not set
++# CONFIG_PDA_POWER is not set
++# CONFIG_TEST_POWER is not set
++# CONFIG_BATTERY_DS2780 is not set
++# CONFIG_BATTERY_DS2781 is not set
++# CONFIG_BATTERY_DS2782 is not set
++# CONFIG_BATTERY_SBS is not set
++# CONFIG_BATTERY_BQ27x00 is not set
++# CONFIG_BATTERY_MAX17040 is not set
++# CONFIG_BATTERY_MAX17042 is not set
++# CONFIG_CHARGER_MAX8903 is not set
++# CONFIG_CHARGER_LP8727 is not set
++# CONFIG_CHARGER_BQ2415X is not set
++# CONFIG_CHARGER_SMB347 is not set
++CONFIG_POWER_RESET=y
++# CONFIG_POWER_RESET_BRCMSTB is not set
++CONFIG_POWER_RESET_HISI=y
++# CONFIG_POWER_RESET_RESTART is not set
++# CONFIG_POWER_RESET_VERSATILE is not set
++# CONFIG_POWER_RESET_SYSCON is not set
++# CONFIG_POWER_AVS is not set
++# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
++# CONFIG_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=y
++# CONFIG_MFD_AS3711 is not set
++# CONFIG_MFD_AS3722 is not set
++# CONFIG_PMIC_ADP5520 is not set
++# CONFIG_MFD_BCM590XX is not set
++# CONFIG_MFD_AXP20X is not set
++# CONFIG_MFD_CROS_EC is not set
++# CONFIG_PMIC_DA903X is not set
++# CONFIG_MFD_DA9052_SPI is not set
++# CONFIG_MFD_DA9052_I2C is not set
++# CONFIG_MFD_DA9055 is not set
++# CONFIG_MFD_DA9063 is not set
++# CONFIG_MFD_MC13XXX_SPI is not set
++# CONFIG_MFD_MC13XXX_I2C is not set
++# CONFIG_MFD_HI6421_PMIC is not set
++CONFIG_MFD_HISI_FMC=y
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_INTEL_SOC_PMIC is not set
++# CONFIG_MFD_KEMPLD is not set
++# CONFIG_MFD_88PM800 is not set
++# CONFIG_MFD_88PM805 is not set
++# CONFIG_MFD_88PM860X is not set
++# CONFIG_MFD_MAX14577 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_MENF21BMC is not set
++# CONFIG_EZX_PCAP is not set
++# CONFIG_MFD_VIPERBOARD is not set
++# CONFIG_MFD_RETU is not set
++# CONFIG_MFD_PCF50633 is not set
++# CONFIG_MFD_PM8921_CORE is not set
++# CONFIG_MFD_RTSX_USB is not set
++# CONFIG_MFD_RC5T583 is not set
++# CONFIG_MFD_RK808 is not set
++# CONFIG_MFD_RN5T618 is not set
++# CONFIG_MFD_SEC_CORE is not set
++# CONFIG_MFD_SI476X_CORE is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_MFD_SMSC is not set
++# CONFIG_ABX500_CORE is not set
++# CONFIG_MFD_STMPE is not set
++CONFIG_MFD_SYSCON=y
++# CONFIG_MFD_TI_AM335X_TSCADC is not set
++# CONFIG_MFD_LP3943 is not set
++# CONFIG_MFD_LP8788 is not set
++# CONFIG_MFD_PALMAS is not set
++# CONFIG_TPS6105X is not set
++# CONFIG_TPS6507X is not set
++# CONFIG_MFD_TPS65090 is not set
++# CONFIG_MFD_TPS65217 is not set
++# CONFIG_MFD_TPS65218 is not set
++# CONFIG_MFD_TPS6586X is not set
++# CONFIG_MFD_TPS80031 is not set
++# CONFIG_TWL4030_CORE is not set
++# CONFIG_TWL6040_CORE is not set
++# CONFIG_MFD_WL1273_CORE is not set
++# CONFIG_MFD_LM3533 is not set
++# CONFIG_MFD_TC3589X is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_MFD_T7L66XB is not set
++# CONFIG_MFD_TC6387XB is not set
++# CONFIG_MFD_TC6393XB is not set
++# CONFIG_MFD_ARIZONA_I2C is not set
++# CONFIG_MFD_ARIZONA_SPI is not set
++# CONFIG_MFD_WM8400 is not set
++# CONFIG_MFD_WM831X_I2C is not set
++# CONFIG_MFD_WM831X_SPI is not set
++# CONFIG_MFD_WM8350_I2C is not set
++# CONFIG_MFD_WM8994 is not set
++CONFIG_REGULATOR=y
++# CONFIG_REGULATOR_DEBUG is not set
++# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
++# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
++# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
++# CONFIG_REGULATOR_ACT8865 is not set
++# CONFIG_REGULATOR_AD5398 is not set
++# CONFIG_REGULATOR_ANATOP is not set
++# CONFIG_REGULATOR_DA9210 is not set
++# CONFIG_REGULATOR_DA9211 is not set
++# CONFIG_REGULATOR_FAN53555 is not set
++# CONFIG_REGULATOR_ISL9305 is not set
++# CONFIG_REGULATOR_ISL6271A is not set
++# CONFIG_REGULATOR_LP3971 is not set
++# CONFIG_REGULATOR_LP3972 is not set
++# CONFIG_REGULATOR_LP872X is not set
++# CONFIG_REGULATOR_LP8755 is not set
++# CONFIG_REGULATOR_LTC3589 is not set
++# CONFIG_REGULATOR_MAX1586 is not set
++# CONFIG_REGULATOR_MAX8649 is not set
++# CONFIG_REGULATOR_MAX8660 is not set
++# CONFIG_REGULATOR_MAX8952 is not set
++# CONFIG_REGULATOR_MAX8973 is not set
++# CONFIG_REGULATOR_PFUZE100 is not set
++# CONFIG_REGULATOR_TPS51632 is not set
++# CONFIG_REGULATOR_TPS62360 is not set
++# CONFIG_REGULATOR_TPS65023 is not set
++# CONFIG_REGULATOR_TPS6507X is not set
++# CONFIG_REGULATOR_TPS6524X is not set
++CONFIG_MEDIA_SUPPORT=m
++
++#
++# Multimedia core support
++#
++CONFIG_MEDIA_CAMERA_SUPPORT=y
++# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set
++# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set
++# CONFIG_MEDIA_RADIO_SUPPORT is not set
++# CONFIG_MEDIA_SDR_SUPPORT is not set
++# CONFIG_MEDIA_RC_SUPPORT is not set
++# CONFIG_MEDIA_CONTROLLER is not set
++CONFIG_VIDEO_DEV=m
++CONFIG_VIDEO_V4L2=m
++# CONFIG_VIDEO_ADV_DEBUG is not set
++# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
++CONFIG_VIDEOBUF2_CORE=m
++CONFIG_VIDEOBUF2_MEMOPS=m
++CONFIG_VIDEOBUF2_VMALLOC=m
++# CONFIG_TTPCI_EEPROM is not set
++
++#
++# Media drivers
++#
++# CONFIG_MEDIA_USB_SUPPORT is not set
++# CONFIG_V4L_PLATFORM_DRIVERS is not set
++# CONFIG_V4L_MEM2MEM_DRIVERS is not set
++# CONFIG_V4L_TEST_DRIVERS is not set
++
++#
++# Supported MMC/SDIO adapters
++#
++# CONFIG_CYPRESS_FIRMWARE is not set
++
++#
++# Media ancillary drivers (tuners, sensors, i2c, frontends)
++#
++CONFIG_MEDIA_SUBDRV_AUTOSELECT=y
++
++#
++# Audio decoders, processors and mixers
++#
++
++#
++# RDS decoders
++#
++
++#
++# Video decoders
++#
++
++#
++# Video and audio decoders
++#
++
++#
++# Video encoders
++#
++
++#
++# Camera sensor devices
++#
++
++#
++# Flash devices
++#
++
++#
++# Video improvement chips
++#
++
++#
++# Audio/Video compression chips
++#
++
++#
++# Miscellaneous helper chips
++#
++
++#
++# Sensors used on soc_camera driver
++#
++
++#
++# Tools to develop new frontends
++#
++# CONFIG_DVB_DUMMY_FE is not set
++
++#
++# Graphics support
++#
++# CONFIG_IMX_IPUV3_CORE is not set
++
++#
++# Direct Rendering Manager
++#
++# CONFIG_DRM is not set
++
++#
++# Frame buffer Devices
++#
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++CONFIG_FB_CMDLINE=y
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++# CONFIG_FB_CFB_FILLRECT is not set
++# CONFIG_FB_CFB_COPYAREA is not set
++# CONFIG_FB_CFB_IMAGEBLIT is not set
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# 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_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_ARMCLCD is not set
++# CONFIG_FB_OPENCORES is not set
++# CONFIG_FB_S1D13XXX is not set
++# CONFIG_FB_SMSCUFX is not set
++# CONFIG_FB_UDL is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_BROADSHEET is not set
++# CONFIG_FB_AUO_K190X is not set
++# CONFIG_FB_SIMPLE is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++# CONFIG_VGASTATE is not set
++
++#
++# Console display driver support
++#
++CONFIG_DUMMY_CONSOLE=y
++# CONFIG_FRAMEBUFFER_CONSOLE is not set
++# CONFIG_LOGO is not set
++# CONFIG_SOUND is not set
++
++#
++# HID support
++#
++CONFIG_HID=y
++# CONFIG_HID_BATTERY_STRENGTH is not set
++# CONFIG_HIDRAW is not set
++# CONFIG_UHID is not set
++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_APPLEIR 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_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_ELO is not set
++# CONFIG_HID_EZKEY is not set
++# CONFIG_HID_HOLTEK is not set
++# CONFIG_HID_HUION 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_ICADE is not set
++# CONFIG_HID_TWINHAN is not set
++# CONFIG_HID_KENSINGTON is not set
++# CONFIG_HID_LCPOWER is not set
++# CONFIG_HID_LENOVO is not set
++# 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_PENMOUNT is not set
++# CONFIG_HID_PETALYNX is not set
++# CONFIG_HID_PICOLCD is not set
++# CONFIG_HID_PRIMAX is not set
++# CONFIG_HID_ROCCAT is not set
++# CONFIG_HID_SAITEK is not set
++# CONFIG_HID_SAMSUNG is not set
++# CONFIG_HID_SPEEDLINK is not set
++# CONFIG_HID_STEELSERIES is not set
++# CONFIG_HID_SUNPLUS is not set
++# CONFIG_HID_RMI 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_XINMO is not set
++# CONFIG_HID_ZEROPLUS is not set
++# CONFIG_HID_ZYDACRON is not set
++# CONFIG_HID_SENSOR_HUB is not set
++
++#
++# USB HID support
++#
++CONFIG_USB_HID=m
++# CONFIG_HID_PID is not set
++# CONFIG_USB_HIDDEV is not set
++
++#
++# USB HID Boot Protocol drivers
++#
++# CONFIG_USB_KBD is not set
++# CONFIG_USB_MOUSE is not set
++
++#
++# I2C HID support
++#
++# CONFIG_I2C_HID is not set
++CONFIG_USB_OHCI_LITTLE_ENDIAN=y
++CONFIG_USB_SUPPORT=y
++CONFIG_USB_COMMON=y
++CONFIG_USB_ARCH_HAS_HCD=y
++CONFIG_USB=m
++# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
++
++#
++# Miscellaneous USB options
++#
++# CONFIG_USB_DEFAULT_PERSIST is not set
++# CONFIG_USB_DYNAMIC_MINORS is not set
++# CONFIG_USB_OTG_WHITELIST is not set
++# CONFIG_USB_OTG_BLACKLIST_HUB is not set
++# CONFIG_USB_OTG_FSM is not set
++# CONFIG_USB_MON is not set
++# CONFIG_USB_WUSB_CBAF is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_C67X00_HCD is not set
++# CONFIG_USB_XHCI_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_FUSBH200_HCD is not set
++# CONFIG_USB_FOTG210_HCD is not set
++# CONFIG_USB_MAX3421_HCD is not set
++# CONFIG_USB_OHCI_HCD is not set
++# CONFIG_USB_SL811_HCD is not set
++# CONFIG_USB_R8A66597_HCD is not set
++# CONFIG_USB_HCD_TEST_MODE is not set
++
++#
++# USB Device Class drivers
++#
++# CONFIG_USB_ACM is not set
++# CONFIG_USB_PRINTER is not set
++# CONFIG_USB_WDM is not set
++# CONFIG_USB_TMC is not set
++
++#
++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
++#
++
++#
++# also be needed; see USB_STORAGE Help for more info
++#
++# CONFIG_USB_STORAGE is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++# CONFIG_USBIP_CORE is not set
++# CONFIG_USB_MUSB_HDRC is not set
++# CONFIG_USB_DWC3 is not set
++# CONFIG_USB_DWC2 is not set
++# CONFIG_USB_CHIPIDEA is not set
++
++#
++# USB port drivers
++#
++# CONFIG_USB_SERIAL is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
++# CONFIG_USB_SEVSEG is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
++# CONFIG_USB_APPLEDISPLAY is not set
++# CONFIG_USB_LD is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
++# CONFIG_USB_IOWARRIOR is not set
++# CONFIG_USB_TEST is not set
++# CONFIG_USB_EHSET_TEST_FIXTURE is not set
++# CONFIG_USB_ISIGHTFW is not set
++# CONFIG_USB_YUREX is not set
++# CONFIG_USB_EZUSB_FX2 is not set
++# CONFIG_USB_HSIC_USB3503 is not set
++# CONFIG_USB_LINK_LAYER_TEST is not set
++
++#
++# USB Physical Layer drivers
++#
++# CONFIG_USB_PHY is not set
++# CONFIG_NOP_USB_XCEIV is not set
++# CONFIG_AM335X_PHY_USB is not set
++# CONFIG_USB_ISP1301 is not set
++# CONFIG_USB_ULPI is not set
++CONFIG_USB_GADGET=y
++# CONFIG_USB_GADGET_DEBUG is not set
++# CONFIG_USB_GADGET_DEBUG_FILES is not set
++CONFIG_USB_GADGET_VBUS_DRAW=2
++CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2
++
++#
++# USB Peripheral Controller
++#
++# CONFIG_USB_FUSB300 is not set
++# CONFIG_USB_FOTG210_UDC is not set
++# CONFIG_USB_GR_UDC is not set
++# CONFIG_USB_R8A66597 is not set
++# CONFIG_USB_PXA27X is not set
++# CONFIG_USB_MV_UDC is not set
++CONFIG_HIUSB_DEVICE2_0=y
++CONFIG_USB_HISI_UDC=m
++# CONFIG_USB_AUTO_SWITCH is not set
++# CONFIG_HIUSB_DEVICE3_0 is not set
++# CONFIG_USB_MV_U3D is not set
++# CONFIG_USB_M66592 is not set
++# CONFIG_USB_NET2272 is not set
++# CONFIG_USB_GADGET_XILINX is not set
++CONFIG_USB_LIBCOMPOSITE=m
++CONFIG_USB_F_ACM=m
++CONFIG_USB_U_SERIAL=m
++CONFIG_USB_U_ETHER=m
++CONFIG_USB_F_RNDIS=m
++CONFIG_USB_F_MASS_STORAGE=m
++CONFIG_USB_F_UAC1=m
++CONFIG_USB_F_UVC=m
++# CONFIG_USB_CONFIGFS is not set
++# CONFIG_USB_ZERO is not set
++CONFIG_USB_AUDIO=m
++CONFIG_GADGET_UAC1=y
++# CONFIG_USB_ETH is not set
++# CONFIG_USB_G_NCM is not set
++# CONFIG_USB_GADGETFS is not set
++# CONFIG_USB_FUNCTIONFS is not set
++CONFIG_USB_MASS_STORAGE=m
++# CONFIG_USB_G_SERIAL is not set
++# CONFIG_USB_G_PRINTER is not set
++# CONFIG_USB_CDC_COMPOSITE is not set
++# CONFIG_USB_G_ACM_MS is not set
++CONFIG_USB_G_MULTI=m
++CONFIG_USB_G_MULTI_RNDIS=y
++# CONFIG_USB_G_MULTI_CDC is not set
++# CONFIG_USB_G_HID is not set
++# CONFIG_USB_G_DBGP is not set
++# CONFIG_USB_G_WEBCAM is not set
++CONFIG_USB_G_WEBCAM_AUDIO=m
++# CONFIG_UWB is not set
++CONFIG_MMC=m
++# CONFIG_MMC_DEBUG is not set
++# CONFIG_MMC_CLKGATE is not set
++CONFIG_MMC_EMBEDDED_SDIO=y
++# CONFIG_MMC_PARANOID_SD_INIT is not set
++
++#
++# MMC/SD/SDIO Card Drivers
++#
++CONFIG_MMC_BLOCK=m
++CONFIG_MMC_BLOCK_MINORS=8
++CONFIG_MMC_BLOCK_BOUNCE=y
++# CONFIG_MMC_BLOCK_DEFERRED_RESUME is not set
++# CONFIG_SDIO_UART is not set
++# CONFIG_MMC_TEST is not set
++
++#
++# MMC/SD/SDIO Host Controller Drivers
++#
++# CONFIG_MMC_ARMMMCI is not set
++# CONFIG_MMC_SDHCI is not set
++# CONFIG_MMC_DW is not set
++# CONFIG_MMC_VUB300 is not set
++# CONFIG_MMC_USHC is not set
++# CONFIG_MMC_USDHI6ROL0 is not set
++CONFIG_HIMCIV200=m
++CONFIG_SEND_AUTO_STOP=y
++CONFIG_DETECT_CARD_TIME=200
++# CONFIG_MEMSTICK is not set
++# CONFIG_NEW_LEDS is not set
++# CONFIG_SWITCH is not set
++# CONFIG_ACCESSIBILITY is not set
++# CONFIG_EDAC is not set
++CONFIG_RTC_LIB=y
++# CONFIG_RTC_CLASS is not set
++# CONFIG_DMADEVICES is not set
++# CONFIG_AUXDISPLAY is not set
++# CONFIG_UIO is not set
++# CONFIG_VIRT_DRIVERS is not set
++
++#
++# Virtio drivers
++#
++# CONFIG_VIRTIO_MMIO is not set
++
++#
++# Microsoft Hyper-V guest support
++#
++# CONFIG_STAGING is not set
++
++#
++# SOC (System On Chip) specific Drivers
++#
++# CONFIG_SOC_TI is not set
++CONFIG_CLKDEV_LOOKUP=y
++CONFIG_HAVE_CLK_PREPARE=y
++CONFIG_COMMON_CLK=y
++
++#
++# Common Clock Framework
++#
++# CONFIG_COMMON_CLK_SI5351 is not set
++# CONFIG_COMMON_CLK_SI570 is not set
++# CONFIG_COMMON_CLK_PXA is not set
++# CONFIG_COMMON_CLK_QCOM is not set
++
++#
++# Hardware Spinlock drivers
++#
++
++#
++# Clock Source drivers
++#
++CONFIG_CLKSRC_OF=y
++CONFIG_CLKSRC_MMIO=y
++CONFIG_ARM_ARCH_TIMER=y
++CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y
++# CONFIG_ARM_ARCH_TIMER_VCT_ACCESS is not set
++# CONFIG_ATMEL_PIT is not set
++# CONFIG_SH_TIMER_CMT is not set
++# CONFIG_SH_TIMER_MTU2 is not set
++# CONFIG_SH_TIMER_TMU is not set
++# CONFIG_EM_TIMER_STI is not set
++# CONFIG_CLKSRC_VERSATILE is not set
++# CONFIG_MAILBOX is not set
++# CONFIG_IOMMU_SUPPORT is not set
++
++#
++# Remoteproc drivers
++#
++# CONFIG_STE_MODEM_RPROC is not set
++
++#
++# Rpmsg drivers
++#
++
++#
++# SOC (System On Chip) specific Drivers
++#
++# 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
++CONFIG_IRQCHIP=y
++CONFIG_ARM_GIC=y
++# CONFIG_IPACK_BUS is not set
++CONFIG_ARCH_HAS_RESET_CONTROLLER=y
++CONFIG_RESET_CONTROLLER=y
++# CONFIG_FMC is not set
++
++#
++# PHY Subsystem
++#
++CONFIG_GENERIC_PHY=y
++# CONFIG_BCM_KONA_USB2_PHY is not set
++CONFIG_PHY_HISI_INNO_USB2=m
++# CONFIG_POWERCAP is not set
++# CONFIG_MCB is not set
++# CONFIG_HI_DMAC is not set
++
++#
++# Hisilicon driver support
++#
++# CONFIG_CMA_MEM_SHARED is not set
++# CONFIG_CMA_ADVANCE_SHARE is not set
++
++#
++# File systems
++#
++CONFIG_DCACHE_WORD_ACCESS=y
++# CONFIG_EXT2_FS is not set
++# CONFIG_EXT3_FS is not set
++# CONFIG_EXT4_FS is not set
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_BTRFS_FS is not set
++# CONFIG_NILFS2_FS is not set
++CONFIG_FS_POSIX_ACL=y
++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 is not set
++# CONFIG_FUSE_FS is not set
++# CONFIG_OVERLAY_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_KERNFS=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=m
++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_YAFFS_FS is not set
++# CONFIG_JFFS2_FS 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 is not set
++# 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 is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V2=y
++CONFIG_NFS_V3=y
++CONFIG_NFS_V3_ACL=y
++# CONFIG_NFS_V4 is not set
++# CONFIG_NFS_SWAP is not set
++# CONFIG_ROOT_NFS is not set
++# CONFIG_NFSD is not set
++CONFIG_GRACE_PERIOD=y
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_ACL_SUPPORT=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 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=y
++# CONFIG_DLM is not set
++
++#
++# Kernel hacking
++#
++
++#
++# printk and dmesg options
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4
++# CONFIG_BOOT_PRINTK_DELAY is not set
++
++#
++# Compile-time checks and compiler options
++#
++# CONFIG_DEBUG_INFO is not set
++# CONFIG_ENABLE_WARN_DEPRECATED is not set
++# CONFIG_ENABLE_MUST_CHECK is not set
++CONFIG_FRAME_WARN=1024
++# CONFIG_STRIP_ASM_SYMS is not set
++# CONFIG_READABLE_ASM is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++# CONFIG_DEBUG_FS is not set
++# CONFIG_HEADERS_CHECK is not set
++# CONFIG_DEBUG_SECTION_MISMATCH is not set
++# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
++# CONFIG_MAGIC_SYSRQ is not set
++CONFIG_DEBUG_KERNEL=y
++
++#
++# Memory Debugging
++#
++# CONFIG_DEBUG_PAGEALLOC is not set
++# CONFIG_DEBUG_OBJECTS is not set
++# CONFIG_SLUB_STATS is not set
++CONFIG_HAVE_DEBUG_KMEMLEAK=y
++# CONFIG_DEBUG_KMEMLEAK is not set
++# CONFIG_DEBUG_STACK_USAGE is not set
++# CONFIG_DEBUG_VM is not set
++# CONFIG_DEBUG_MEMORY_INIT is not set
++# CONFIG_DEBUG_HIGHMEM is not set
++# CONFIG_DEBUG_SHIRQ is not set
++
++#
++# Debug Lockups and Hangs
++#
++# CONFIG_LOCKUP_DETECTOR is not set
++# CONFIG_DETECT_HUNG_TASK is not set
++CONFIG_PANIC_ON_OOPS=y
++CONFIG_PANIC_ON_OOPS_VALUE=1
++CONFIG_PANIC_TIMEOUT=0
++CONFIG_SCHED_DEBUG=y
++# CONFIG_SCHEDSTATS is not set
++# CONFIG_SCHED_STACK_END_CHECK is not set
++# CONFIG_TIMER_STATS is not set
++
++#
++# Lock Debugging (spinlocks, mutexes, etc...)
++#
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_LOCK_STAT is not set
++# CONFIG_DEBUG_ATOMIC_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_LOCK_TORTURE_TEST is not set
++CONFIG_STACKTRACE=y
++# CONFIG_DEBUG_KOBJECT is not set
++CONFIG_DEBUG_BUGVERBOSE=y
++# CONFIG_DEBUG_LIST is not set
++# CONFIG_DEBUG_PI_LIST is not set
++# CONFIG_DEBUG_SG is not set
++# CONFIG_DEBUG_NOTIFIERS is not set
++# CONFIG_DEBUG_CREDENTIALS is not set
++
++#
++# RCU Debugging
++#
++# CONFIG_SPARSE_RCU_POINTER is not set
++# CONFIG_TORTURE_TEST is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_RCU_TRACE is not set
++# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_NOTIFIER_ERROR_INJECTION is not set
++# CONFIG_FAULT_INJECTION is not set
++# CONFIG_LATENCYTOP 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 is not set
++
++#
++# Runtime Testing
++#
++# CONFIG_TEST_LIST_SORT is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_RBTREE_TEST is not set
++# CONFIG_INTERVAL_TREE_TEST is not set
++# CONFIG_PERCPU_TEST is not set
++# CONFIG_ATOMIC64_SELFTEST is not set
++# CONFIG_TEST_STRING_HELPERS is not set
++# CONFIG_TEST_KSTRTOX is not set
++# CONFIG_TEST_RHASHTABLE is not set
++# CONFIG_DMA_API_DEBUG is not set
++# CONFIG_TEST_LKM is not set
++# CONFIG_TEST_USER_COPY is not set
++# CONFIG_TEST_BPF is not set
++# CONFIG_TEST_FIRMWARE is not set
++# CONFIG_TEST_UDELAY is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_KGDB is not set
++# CONFIG_ARM_PTDUMP is not set
++CONFIG_STRICT_DEVMEM=y
++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_DEBUG_UART_PL01X is not set
++# CONFIG_DEBUG_UART_8250 is not set
++# CONFIG_DEBUG_UART_BCM63XX is not set
++CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"
++# CONFIG_OC_ETM is not set
++# CONFIG_PID_IN_CONTEXTIDR is not set
++# CONFIG_DEBUG_SET_MODULE_RONX is not set
++# CONFIG_CORESIGHT is not set
++
++#
++# 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_AEAD=y
++CONFIG_CRYPTO_AEAD2=y
++CONFIG_CRYPTO_BLKCIPHER=y
++CONFIG_CRYPTO_BLKCIPHER2=y
++CONFIG_CRYPTO_HASH=y
++CONFIG_CRYPTO_HASH2=y
++CONFIG_CRYPTO_RNG=y
++CONFIG_CRYPTO_RNG2=y
++CONFIG_CRYPTO_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_WORKQUEUE=y
++# CONFIG_CRYPTO_CRYPTD is not set
++# CONFIG_CRYPTO_MCRYPTD is not set
++# CONFIG_CRYPTO_AUTHENC is not set
++# CONFIG_CRYPTO_TEST is not set
++
++#
++# Authenticated Encryption with Associated Data
++#
++CONFIG_CRYPTO_CCM=y
++# CONFIG_CRYPTO_GCM is not set
++CONFIG_CRYPTO_SEQIV=y
++
++#
++# Block modes
++#
++# CONFIG_CRYPTO_CBC is not set
++CONFIG_CRYPTO_CTR=y
++# 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_CMAC is not set
++# CONFIG_CRYPTO_HMAC is not set
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_VMAC is not set
++
++#
++# Digest
++#
++CONFIG_CRYPTO_CRC32C=y
++# CONFIG_CRYPTO_CRC32 is not set
++# CONFIG_CRYPTO_CRCT10DIF 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_SHA1_ARM_NEON is not set
++# CONFIG_CRYPTO_SHA256 is not set
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_SHA512_ARM_NEON 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_AES_ARM_BS is not set
++# CONFIG_CRYPTO_ANUBIS is not set
++CONFIG_CRYPTO_ARC4=y
++# 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=y
++# CONFIG_CRYPTO_ZLIB is not set
++CONFIG_CRYPTO_LZO=y
++# CONFIG_CRYPTO_LZ4 is not set
++# CONFIG_CRYPTO_LZ4HC is not set
++
++#
++# Random Number Generation
++#
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++# CONFIG_CRYPTO_DRBG_MENU is not set
++# CONFIG_CRYPTO_USER_API_HASH is not set
++# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
++CONFIG_CRYPTO_HW=y
++# CONFIG_BINARY_PRINTF is not set
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++CONFIG_GENERIC_STRNCPY_FROM_USER=y
++CONFIG_GENERIC_STRNLEN_USER=y
++CONFIG_GENERIC_NET_UTILS=y
++CONFIG_GENERIC_PCI_IOMAP=y
++CONFIG_GENERIC_IO=y
++CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
++# CONFIG_CRC_CCITT is not set
++CONFIG_CRC16=y
++# CONFIG_CRC_T10DIF is not set
++# 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=y
++# CONFIG_CRC8 is not set
++# CONFIG_AUDIT_ARCH_COMPAT_GENERIC is not set
++# CONFIG_RANDOM32_SELFTEST is not set
++CONFIG_ZLIB_INFLATE=y
++CONFIG_ZLIB_DEFLATE=y
++CONFIG_LZO_COMPRESS=y
++CONFIG_LZO_DECOMPRESS=y
++CONFIG_XZ_DEC=y
++CONFIG_XZ_DEC_X86=y
++CONFIG_XZ_DEC_POWERPC=y
++CONFIG_XZ_DEC_IA64=y
++CONFIG_XZ_DEC_ARM=y
++CONFIG_XZ_DEC_ARMTHUMB=y
++CONFIG_XZ_DEC_SPARC=y
++CONFIG_XZ_DEC_BCJ=y
++# CONFIG_XZ_DEC_TEST is not set
++CONFIG_GENERIC_ALLOCATOR=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT_MAP=y
++CONFIG_HAS_DMA=y
++CONFIG_DQL=y
++CONFIG_NLATTR=y
++CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
++CONFIG_AVERAGE=y
++# CONFIG_CORDIC is not set
++# CONFIG_DDR is not set
++CONFIG_LIBFDT=y
++CONFIG_ARCH_HAS_SG_CHAIN=y
++# CONFIG_VIRTUALIZATION is not set
+diff --git a/arch/arm/configs/hi3556_single_spinand_mini_defconfig b/arch/arm/configs/hi3556_single_spinand_mini_defconfig
+new file mode 100644
+index 0000000..6cf319c
+--- /dev/null
++++ b/arch/arm/configs/hi3556_single_spinand_mini_defconfig
+@@ -0,0 +1,2398 @@
++#
++# Automatically generated file; DO NOT EDIT.
++# Linux/arm 3.18.20 Kernel Configuration
++#
++CONFIG_ARM=y
++CONFIG_ARM_HAS_SG_CHAIN=y
++CONFIG_MIGHT_HAVE_PCI=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=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_XCHGADD_ALGORITHM=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_NEED_DMA_MAP_STATE=y
++CONFIG_ARCH_SUPPORTS_UPROBES=y
++CONFIG_VECTORS_BASE=0xffff0000
++CONFIG_ARM_PATCH_PHYS_VIRT=y
++CONFIG_GENERIC_BUG=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++CONFIG_IRQ_WORK=y
++CONFIG_BUILDTIME_EXTABLE_SORT=y
++
++#
++# General setup
++#
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_CROSS_COMPILE=""
++# CONFIG_COMPILE_TEST is not set
++CONFIG_LOCALVERSION=""
++# CONFIG_LOCALVERSION_AUTO is not set
++CONFIG_HAVE_KERNEL_GZIP=y
++CONFIG_HAVE_KERNEL_LZMA=y
++CONFIG_HAVE_KERNEL_XZ=y
++CONFIG_HAVE_KERNEL_LZO=y
++CONFIG_HAVE_KERNEL_LZ4=y
++CONFIG_KERNEL_GZIP=y
++# CONFIG_KERNEL_LZMA is not set
++# CONFIG_KERNEL_XZ is not set
++# CONFIG_KERNEL_LZO is not set
++# CONFIG_KERNEL_LZ4 is not set
++CONFIG_HW_DECOMPRESS=y
++# CONFIG_SOFT_DECOMPRESS is not set
++CONFIG_DEFAULT_HOSTNAME="(none)"
++# CONFIG_SWAP is not set
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++# CONFIG_POSIX_MQUEUE is not set
++CONFIG_CROSS_MEMORY_ATTACH=y
++# CONFIG_FHANDLE is not set
++CONFIG_USELIB=y
++# CONFIG_AUDIT is not set
++CONFIG_HAVE_ARCH_AUDITSYSCALL=y
++
++#
++# IRQ subsystem
++#
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_GENERIC_IRQ_SHOW=y
++CONFIG_HARDIRQS_SW_RESEND=y
++CONFIG_IRQ_DOMAIN=y
++CONFIG_HANDLE_DOMAIN_IRQ=y
++CONFIG_IRQ_FORCED_THREADING=y
++CONFIG_SPARSE_IRQ=y
++CONFIG_GENERIC_CLOCKEVENTS=y
++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
++
++#
++# Timers subsystem
++#
++CONFIG_TICK_ONESHOT=y
++CONFIG_NO_HZ_COMMON=y
++# CONFIG_HZ_PERIODIC is not set
++CONFIG_NO_HZ_IDLE=y
++CONFIG_NO_HZ=y
++# CONFIG_HIGH_RES_TIMERS is not set
++
++#
++# CPU/Task time and stats accounting
++#
++CONFIG_TICK_CPU_ACCOUNTING=y
++# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set
++# CONFIG_IRQ_TIME_ACCOUNTING is not set
++# CONFIG_BSD_PROCESS_ACCT is not set
++# CONFIG_TASKSTATS is not set
++
++#
++# RCU Subsystem
++#
++CONFIG_TINY_RCU=y
++# CONFIG_PREEMPT_RCU is not set
++# CONFIG_TASKS_RCU is not set
++# CONFIG_RCU_STALL_COMMON is not set
++# CONFIG_TREE_RCU_TRACE is not set
++# CONFIG_BUILD_BIN2C is not set
++# CONFIG_IKCONFIG is not set
++CONFIG_LOG_BUF_SHIFT=17
++CONFIG_GENERIC_SCHED_CLOCK=y
++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_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 is not set
++# CONFIG_SCHED_AUTOGROUP is not set
++# CONFIG_SYSFS_DEPRECATED is not set
++# CONFIG_RELAY is not set
++# CONFIG_BLK_DEV_INITRD is not set
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++CONFIG_HAVE_UID16=y
++CONFIG_BPF=y
++CONFIG_EXPERT=y
++# CONFIG_UID16 is not set
++# CONFIG_SGETMASK_SYSCALL is not set
++CONFIG_SYSFS_SYSCALL=y
++# CONFIG_SYSCTL_SYSCALL is not set
++CONFIG_KALLSYMS=y
++# CONFIG_KALLSYMS_ALL is not set
++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_BPF_SYSCALL is not set
++CONFIG_SHMEM=y
++CONFIG_AIO=y
++CONFIG_ADVISE_SYSCALLS=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 is not set
++# CONFIG_SLUB_DEBUG is not set
++# CONFIG_COMPAT_BRK is not set
++# 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_UPROBES is not set
++# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
++CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
++CONFIG_ARCH_USE_BUILTIN_BSWAP=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_GENERIC_SMP_IDLE_THREAD=y
++CONFIG_GENERIC_IDLE_POLL_SETUP=y
++CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
++CONFIG_HAVE_CLK=y
++CONFIG_HAVE_DMA_API_DEBUG=y
++CONFIG_HAVE_PERF_REGS=y
++CONFIG_HAVE_PERF_USER_STACK_DUMP=y
++CONFIG_HAVE_ARCH_JUMP_LABEL=y
++CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
++CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
++CONFIG_HAVE_CC_STACKPROTECTOR=y
++# CONFIG_CC_STACKPROTECTOR is not set
++CONFIG_CC_STACKPROTECTOR_NONE=y
++# CONFIG_CC_STACKPROTECTOR_REGULAR is not set
++# CONFIG_CC_STACKPROTECTOR_STRONG is not set
++CONFIG_HAVE_CONTEXT_TRACKING=y
++CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
++CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
++CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
++CONFIG_MODULES_USE_ELF_REL=y
++CONFIG_CLONE_BACKWARDS=y
++CONFIG_OLD_SIGSUSPEND3=y
++CONFIG_OLD_SIGACTION=y
++
++#
++# GCOV-based kernel profiling
++#
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_RT_MUTEXES=y
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++# CONFIG_MODULE_FORCE_LOAD is not set
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++# CONFIG_MODULE_SIG is not set
++# CONFIG_MODULE_COMPRESS is not set
++CONFIG_BLOCK=y
++CONFIG_LBDAF=y
++CONFIG_BLK_DEV_BSG=y
++# CONFIG_BLK_DEV_BSGLIB is not set
++# CONFIG_BLK_DEV_INTEGRITY is not set
++CONFIG_BLK_CMDLINE_PARSER=y
++
++#
++# Partition Types
++#
++CONFIG_PARTITION_ADVANCED=y
++# CONFIG_ACORN_PARTITION is not set
++# CONFIG_AIX_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=y
++# CONFIG_SYSV68_PARTITION is not set
++CONFIG_CMDLINE_PARTITION=y
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++CONFIG_DEFAULT_DEADLINE=y
++# CONFIG_DEFAULT_CFQ is not set
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="deadline"
++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_ARCH_SUPPORTS_ATOMIC_RMW=y
++CONFIG_FREEZER=y
++
++#
++# System Type
++#
++CONFIG_MMU=y
++CONFIG_ARCH_MULTIPLATFORM=y
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_AT91 is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_GEMINI is not set
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_IOP13XX is not set
++# CONFIG_ARCH_IOP32X is not set
++# CONFIG_ARCH_IOP33X is not set
++# CONFIG_ARCH_IXP4XX is not set
++# CONFIG_ARCH_DOVE is not set
++# CONFIG_ARCH_MV78XX0 is not set
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_MMP is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_W90X900 is not set
++# CONFIG_ARCH_LPC32XX is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_MSM is not set
++# CONFIG_ARCH_SHMOBILE_LEGACY 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_DAVINCI is not set
++# CONFIG_ARCH_OMAP1 is not set
++
++#
++# Multiple platform selection
++#
++
++#
++# CPU Core family selection
++#
++# CONFIG_ARCH_MULTI_V6 is not set
++CONFIG_ARCH_MULTI_V7=y
++CONFIG_ARCH_MULTI_V6_V7=y
++# CONFIG_ARCH_MULTI_CPU_AUTO is not set
++# CONFIG_ARCH_VIRT is not set
++# CONFIG_ARCH_MVEBU is not set
++# CONFIG_ARCH_BCM is not set
++# CONFIG_ARCH_BERLIN is not set
++# CONFIG_ARCH_HIGHBANK is not set
++CONFIG_ARCH_HISI=y
++
++#
++# Hisilicon platform type
++#
++# CONFIG_ARCH_HI3xxx is not set
++# CONFIG_ARCH_HIP04 is not set
++# CONFIG_ARCH_HIX5HD2 is not set
++# CONFIG_ARCH_HI3519 is not set
++# CONFIG_ARCH_HI3519V101 is not set
++# CONFIG_ARCH_HI3516AV200 is not set
++# CONFIG_ARCH_HI3559 is not set
++CONFIG_ARCH_HI3556=y
++# CONFIG_ARCH_HI3536C is not set
++# CONFIG_ARCH_HI3531D is not set
++# CONFIG_ARCH_HI3521D is not set
++# CONFIG_ARCH_KEYSTONE is not set
++# CONFIG_ARCH_MESON is not set
++# CONFIG_ARCH_MXC is not set
++# CONFIG_ARCH_MEDIATEK is not set
++
++#
++# TI OMAP/AM/DM/DRA Family
++#
++# CONFIG_ARCH_OMAP3 is not set
++# CONFIG_ARCH_OMAP4 is not set
++# CONFIG_SOC_OMAP5 is not set
++# CONFIG_SOC_AM33XX is not set
++# CONFIG_SOC_AM43XX is not set
++# CONFIG_SOC_DRA7XX is not set
++# CONFIG_ARCH_QCOM is not set
++# CONFIG_ARCH_ROCKCHIP is not set
++# CONFIG_ARCH_SOCFPGA is not set
++# CONFIG_PLAT_SPEAR is not set
++# CONFIG_ARCH_STI is not set
++# CONFIG_ARCH_S5PV210 is not set
++# CONFIG_ARCH_EXYNOS is not set
++# CONFIG_ARCH_SHMOBILE_MULTI is not set
++# CONFIG_ARCH_SUNXI is not set
++# CONFIG_ARCH_SIRF is not set
++# CONFIG_ARCH_TEGRA is not set
++# CONFIG_ARCH_U8500 is not set
++# CONFIG_ARCH_VEXPRESS is not set
++# CONFIG_ARCH_WM8850 is not set
++# CONFIG_ARCH_ZYNQ is not set
++CONFIG_ARM_TIMER_SP804=y
++
++#
++# Processor Type
++#
++CONFIG_CPU_V7=y
++CONFIG_CPU_32v6K=y
++CONFIG_CPU_32v7=y
++CONFIG_CPU_ABRT_EV7=y
++CONFIG_CPU_PABRT_V7=y
++CONFIG_CPU_CACHE_V7=y
++CONFIG_CPU_CACHE_VIPT=y
++CONFIG_CPU_COPY_V6=y
++CONFIG_CPU_TLB_V7=y
++CONFIG_CPU_HAS_ASID=y
++CONFIG_CPU_CP15=y
++CONFIG_CPU_CP15_MMU=y
++
++#
++# Processor Features
++#
++# CONFIG_ARM_LPAE is not set
++# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
++CONFIG_ARM_THUMB=y
++# CONFIG_ARM_THUMBEE is not set
++CONFIG_ARM_VIRT_EXT=y
++CONFIG_SWP_EMULATE=y
++# CONFIG_CPU_ICACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_DISABLE is not set
++# CONFIG_CPU_BPREDICT_DISABLE is not set
++CONFIG_KUSER_HELPERS=y
++CONFIG_MIGHT_HAVE_CACHE_L2X0=y
++# CONFIG_CACHE_L2X0 is not set
++CONFIG_ARM_L1_CACHE_SHIFT_6=y
++CONFIG_ARM_L1_CACHE_SHIFT=6
++CONFIG_ARM_DMA_MEM_BUFFERABLE=y
++CONFIG_MULTI_IRQ_HANDLER=y
++# CONFIG_ARM_ERRATA_430973 is not set
++# CONFIG_ARM_ERRATA_720789 is not set
++# CONFIG_ARM_ERRATA_754322 is not set
++# CONFIG_ARM_ERRATA_775420 is not set
++# CONFIG_ARM_ERRATA_773022 is not set
++
++#
++# Bus support
++#
++CONFIG_ARM_AMBA=y
++# CONFIG_PCI is not set
++# CONFIG_PCI_SYSCALL is not set
++# CONFIG_PCCARD is not set
++
++#
++# Kernel Features
++#
++CONFIG_HAVE_SMP=y
++# CONFIG_SMP is not set
++CONFIG_DISABLE_CPU_SCHED_DOMAIN_BALANCE=y
++CONFIG_HAVE_ARM_ARCH_TIMER=y
++CONFIG_VMSPLIT_3G=y
++# CONFIG_VMSPLIT_2G is not set
++# CONFIG_VMSPLIT_1G is not set
++CONFIG_PAGE_OFFSET=0xC0000000
++# CONFIG_ARM_PSCI is not set
++CONFIG_ARCH_NR_GPIO=0
++CONFIG_PREEMPT_NONE=y
++# CONFIG_PREEMPT_VOLUNTARY is not set
++# CONFIG_PREEMPT is not set
++CONFIG_HZ_FIXED=0
++# CONFIG_HZ_100 is not set
++# CONFIG_HZ_200 is not set
++# CONFIG_HZ_250 is not set
++# CONFIG_HZ_300 is not set
++# CONFIG_HZ_500 is not set
++CONFIG_HZ_1000=y
++CONFIG_HZ=1000
++# CONFIG_SCHED_HRTICK is not set
++# CONFIG_THUMB2_KERNEL is not set
++CONFIG_AEABI=y
++# CONFIG_OABI_COMPAT is not set
++# 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_ARCH_WANT_GENERAL_HUGETLB=y
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_HAVE_MEMBLOCK=y
++CONFIG_NO_BOOTMEM=y
++CONFIG_MEMORY_ISOLATION=y
++# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=4
++CONFIG_COMPACTION=y
++CONFIG_MIGRATION=y
++# CONFIG_PHYS_ADDR_T_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_BOUNCE=y
++# CONFIG_KSM is not set
++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
++CONFIG_NEED_PER_CPU_KM=y
++# CONFIG_CLEANCACHE is not set
++CONFIG_CMA=y
++# CONFIG_CMA_DEBUG is not set
++CONFIG_CMA_AREAS=7
++# CONFIG_ZPOOL is not set
++# CONFIG_ZBUD is not set
++# CONFIG_ZSMALLOC 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_SWIOTLB=y
++CONFIG_IOMMU_HELPER=y
++# CONFIG_XEN is not set
++# CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART is not set
++
++#
++# Boot options
++#
++CONFIG_USE_OF=y
++CONFIG_ATAGS=y
++# CONFIG_DEPRECATED_PARAM_STRUCT is not set
++# CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE is not set
++CONFIG_ZBOOT_ROM_TEXT=0
++CONFIG_ZBOOT_ROM_BSS=0
++CONFIG_ARM_APPENDED_DTB=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_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_GOV_COMMON=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 is not set
++CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
++# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE is not set
++CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
++CONFIG_CPU_FREQ_GOV_POWERSAVE=y
++CONFIG_CPU_FREQ_GOV_USERSPACE=y
++CONFIG_CPU_FREQ_GOV_ONDEMAND=y
++CONFIG_CPU_FREQ_GOV_INTERACTIVE=y
++# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
++# CONFIG_CPUFREQ_DT is not set
++
++#
++# ARM CPU frequency scaling drivers
++#
++# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set
++
++#
++# CPU Idle
++#
++# CONFIG_CPU_IDLE is not set
++# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++CONFIG_VFP=y
++CONFIG_VFPv3=y
++CONFIG_NEON=y
++CONFIG_KERNEL_MODE_NEON=y
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
++CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
++CONFIG_BINFMT_SCRIPT=y
++# CONFIG_HAVE_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
++CONFIG_COREDUMP=y
++
++#
++# Power management options
++#
++CONFIG_SUSPEND=y
++CONFIG_SUSPEND_FREEZER=y
++# CONFIG_WAKELOCK is not set
++# CONFIG_HISI_SNAPSHOT_BOOT is not set
++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_OPP=y
++CONFIG_PM_CLK=y
++# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set
++CONFIG_CPU_PM=y
++# CONFIG_SUSPEND_TIME is not set
++CONFIG_ARCH_SUSPEND_POSSIBLE=y
++CONFIG_ARM_CPU_SUSPEND=y
++CONFIG_ARCH_HIBERNATION_POSSIBLE=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_NET_IP_TUNNEL is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_NET_IPVTI is not set
++# CONFIG_NET_UDP_TUNNEL is not set
++# CONFIG_NET_FOU is not set
++# CONFIG_GENEVE 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 is not set
++CONFIG_INET_XFRM_MODE_TRANSPORT=y
++CONFIG_INET_XFRM_MODE_TUNNEL=y
++CONFIG_INET_XFRM_MODE_BEET=y
++CONFIG_INET_LRO=y
++CONFIG_INET_DIAG=y
++CONFIG_INET_TCP_DIAG=y
++# CONFIG_INET_UDP_DIAG is not set
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++# CONFIG_TCP_MD5SIG is not set
++# CONFIG_IPV6 is not set
++# CONFIG_ANDROID_PARANOID_NETWORK is not set
++CONFIG_NET_ACTIVITY_STATS=y
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NET_PTP_CLASSIFY 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_NF_TABLES is not set
++# CONFIG_NETFILTER_XTABLES is not set
++# CONFIG_IP_SET is not set
++# CONFIG_IP_VS is not set
++
++#
++# IP: Netfilter Configuration
++#
++# CONFIG_NF_DEFRAG_IPV4 is not set
++# CONFIG_NF_LOG_ARP is not set
++# CONFIG_NF_LOG_IPV4 is not set
++# CONFIG_NF_REJECT_IPV4 is not set
++# CONFIG_IP_NF_IPTABLES is not set
++# CONFIG_IP_NF_ARPTABLES 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_HAVE_NET_DSA=y
++# 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_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_VSOCKETS is not set
++# CONFIG_NETLINK_MMAP is not set
++# CONFIG_NETLINK_DIAG is not set
++# CONFIG_NET_MPLS_GSO is not set
++# CONFIG_HSR is not set
++# CONFIG_CGROUP_NET_PRIO is not set
++# CONFIG_CGROUP_NET_CLASSID is not set
++CONFIG_NET_RX_BUSY_POLL=y
++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 is not set
++CONFIG_DEVTMPFS=y
++CONFIG_DEVTMPFS_MOUNT=y
++CONFIG_STANDALONE=y
++# CONFIG_PREVENT_FIRMWARE_BUILD is not set
++CONFIG_FW_LOADER=y
++# CONFIG_FIRMWARE_IN_KERNEL is not set
++CONFIG_EXTRA_FIRMWARE=""
++# CONFIG_FW_LOADER_USER_HELPER_FALLBACK is not set
++CONFIG_ALLOW_DEV_COREDUMP=y
++# 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_HAVE_CPU_AUTOPROBE is not set
++CONFIG_REGMAP=y
++CONFIG_REGMAP_MMIO=y
++CONFIG_DMA_SHARED_BUFFER=y
++# CONFIG_FENCE_TRACE is not set
++CONFIG_DMA_CMA=y
++
++#
++# Default contiguous memory area size:
++#
++CONFIG_CMA_SIZE_MBYTES=16
++CONFIG_CMA_SIZE_SEL_MBYTES=y
++# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set
++# CONFIG_CMA_SIZE_SEL_MIN is not set
++# CONFIG_CMA_SIZE_SEL_MAX is not set
++CONFIG_CMA_ALIGNMENT=8
++
++#
++# Bus devices
++#
++# CONFIG_BRCMSTB_GISB_ARB is not set
++CONFIG_ARM_CCI=y
++# CONFIG_VEXPRESS_CONFIG 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=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_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_HIFMC=y
++CONFIG_HIFMC_SPI_NAND=y
++# CONFIG_HIFMC_NAND 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_SST25L is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_PHRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++# CONFIG_MTD_BLOCK2MTD is not set
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOCG3 is not set
++CONFIG_MTD_NAND_IDS=y
++CONFIG_MTD_NAND_ECC=y
++# CONFIG_MTD_NAND_ECC_SMC is not set
++CONFIG_MTD_NAND=y
++# CONFIG_MTD_NAND_ECC_BCH is not set
++# CONFIG_MTD_SM_COMMON is not set
++# CONFIG_MTD_NAND_DENALI is not set
++# CONFIG_MTD_NAND_OMAP_BCH_BUILD is not set
++# CONFIG_MTD_NAND_DISKONCHIP is not set
++# CONFIG_MTD_NAND_DOCG4 is not set
++# CONFIG_MTD_NAND_NANDSIM is not set
++# CONFIG_MTD_NAND_PLATFORM is not set
++# CONFIG_HISI_NAND_FS_MAY_NO_YAFFS2 is not set
++# CONFIG_HISI_NAND_ECC_STATUS_REPORT is not set
++# CONFIG_MTD_NAND_HINFC610 is not set
++# CONFIG_HIFMC100_NAND is not set
++CONFIG_HIFMC100_SPI_NAND=y
++CONFIG_SPI_NAND_MAX_CHIP_NUM=1
++# CONFIG_HIFMC100_HARDWARE_PAGESIZE_ECC is not set
++CONFIG_HIFMC100_AUTO_PAGESIZE_ECC=y
++# CONFIG_HIFMC100_PAGESIZE_AUTO_ECC_NONE is not set
++# CONFIG_MTD_ONENAND is not set
++
++#
++# LPDDR & LPDDR2 PCM memory drivers
++#
++# CONFIG_MTD_LPDDR is not set
++# CONFIG_MTD_LPDDR2_NVM is not set
++# CONFIG_MTD_SPI_NOR is not set
++CONFIG_MTD_UBI=y
++CONFIG_MTD_UBI_WL_THRESHOLD=4096
++CONFIG_MTD_UBI_BEB_LIMIT=20
++# CONFIG_MTD_UBI_FASTMAP is not set
++# CONFIG_MTD_UBI_GLUEBI is not set
++# CONFIG_MTD_UBI_BLOCK is not set
++CONFIG_DTC=y
++CONFIG_OF=y
++
++#
++# Device Tree and Open Firmware support
++#
++# 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_NET=y
++CONFIG_OF_MDIO=y
++CONFIG_OF_MTD=y
++CONFIG_OF_RESERVED_MEM=y
++CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
++# CONFIG_PARPORT is not set
++CONFIG_BLK_DEV=y
++# CONFIG_BLK_DEV_NULL_BLK is not set
++# CONFIG_BLK_DEV_COW_COMMON is not set
++# CONFIG_BLK_DEV_LOOP 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=65536
++# CONFIG_BLK_DEV_XIP is not set
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH 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_DUMMY_IRQ 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_UID_STAT is not set
++# CONFIG_BMP085_I2C is not set
++# CONFIG_BMP085_SPI is not set
++# CONFIG_USB_SWITCH_FSA9480 is not set
++# CONFIG_LATTICE_ECP3_CONFIG is not set
++# CONFIG_SRAM is not set
++# CONFIG_C2PORT is not set
++
++#
++# EEPROM support
++#
++# CONFIG_EEPROM_AT24 is not set
++# CONFIG_EEPROM_AT25 is not set
++# CONFIG_EEPROM_LEGACY is not set
++# CONFIG_EEPROM_MAX6875 is not set
++# CONFIG_EEPROM_93CX6 is not set
++# CONFIG_EEPROM_93XX46 is not set
++
++#
++# Texas Instruments shared transport line discipline
++#
++# 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
++
++#
++# Intel MIC Bus Driver
++#
++
++#
++# Intel MIC Host Driver
++#
++
++#
++# Intel MIC Card Driver
++#
++# CONFIG_ECHO is not set
++# CONFIG_CXL_BASE is not set
++
++#
++# hisi 'himm/himd.l/himc'support
++#
++# CONFIG_HISI_REG 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_NETLINK is not set
++# CONFIG_SCSI_MQ_DEFAULT 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_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 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_NET_CORE=y
++# CONFIG_BONDING is not set
++# CONFIG_DUMMY is not set
++# CONFIG_EQUALIZER is not set
++# CONFIG_NET_TEAM is not set
++# CONFIG_MACVLAN is not set
++# CONFIG_VXLAN is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_TUN is not set
++# CONFIG_VETH is not set
++# CONFIG_NLMON is not set
++
++#
++# 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_NET_DSA_MV88E6171 is not set
++# CONFIG_NET_DSA_BCM_SF2 is not set
++# CONFIG_ETHERNET is not set
++CONFIG_PHYLIB=y
++
++#
++# MII PHY device drivers
++#
++# CONFIG_AT803X_PHY is not set
++# CONFIG_AMD_PHY is not set
++# CONFIG_AMD_XGBE_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 is not set
++# CONFIG_BROADCOM_PHY is not set
++# CONFIG_BCM7XXX_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_MMIOREG is not set
++# CONFIG_MDIO_BCM_UNIMAC is not set
++# CONFIG_MDIO_HISI_FEMAC is not set
++# CONFIG_MDIO_HISI_GEMAC is not set
++# CONFIG_MICREL_KS8995MA is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++
++#
++# Host-side USB support is needed for USB Network Adapter support
++#
++CONFIG_USB_NET_DRIVERS=m
++# 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_RTL8152 is not set
++# CONFIG_USB_USBNET is not set
++# CONFIG_USB_IPHETH is not set
++CONFIG_WLAN=y
++# CONFIG_WIFI_CONTROL_FUNC is not set
++# 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 is not set
++# CONFIG_INPUT_SPARSEKMAP is not set
++# CONFIG_INPUT_MATRIXKMAP is not set
++
++#
++# Userland interfaces
++#
++# CONFIG_INPUT_MOUSEDEV is not set
++# CONFIG_INPUT_JOYDEV is not set
++CONFIG_INPUT_EVDEV=y
++# CONFIG_INPUT_EVBUG is not set
++# CONFIG_INPUT_KEYRESET is not set
++# CONFIG_INPUT_KEYCOMBO is not set
++
++#
++# Input Device Drivers
++#
++# CONFIG_INPUT_KEYBOARD is not set
++# CONFIG_INPUT_MOUSE is not set
++# CONFIG_INPUT_JOYSTICK is not set
++# CONFIG_INPUT_TABLET is not set
++# CONFIG_INPUT_TOUCHSCREEN is not set
++# CONFIG_INPUT_MISC is not set
++
++#
++# Hardware I/O ports
++#
++# CONFIG_SERIO is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++CONFIG_TTY=y
++CONFIG_VT=y
++CONFIG_CONSOLE_TRANSLATIONS=y
++CONFIG_VT_CONSOLE=y
++CONFIG_VT_CONSOLE_SLEEP=y
++CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
++CONFIG_UNIX98_PTYS=y
++# CONFIG_DEVPTS_MULTIPLE_INSTANCES 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_DEVMEM=y
++CONFIG_DEVKMEM=y
++
++#
++# Serial drivers
++#
++CONFIG_SERIAL_EARLYCON=y
++# CONFIG_SERIAL_8250 is not set
++
++#
++# Non-8250 serial port support
++#
++# CONFIG_SERIAL_AMBA_PL010 is not set
++CONFIG_SERIAL_AMBA_PL011=y
++CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
++# CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST is not set
++# 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_SC16IS7XX is not set
++# CONFIG_SERIAL_ALTERA_JTAGUART is not set
++# CONFIG_SERIAL_ALTERA_UART is not set
++# CONFIG_SERIAL_XILINX_PS_UART is not set
++# CONFIG_SERIAL_ARC is not set
++# CONFIG_SERIAL_FSL_LPUART is not set
++# CONFIG_SERIAL_ST_ASC is not set
++# CONFIG_TTY_PRINTK is not set
++# CONFIG_HVC_DCC is not set
++# CONFIG_IPMI_HANDLER is not set
++CONFIG_HW_RANDOM=y
++# CONFIG_HW_RANDOM_TIMERIOMEM is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++# CONFIG_DCC_TTY is not set
++# CONFIG_XILLYBUS is not set
++
++#
++# I2C support
++#
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++# CONFIG_I2C_COMPAT is not set
++CONFIG_I2C_CHARDEV=y
++CONFIG_I2C_MUX=m
++
++#
++# Multiplexer I2C Chip support
++#
++# CONFIG_I2C_MUX_PCA9541 is not set
++# CONFIG_I2C_HELPER_AUTO is not set
++# CONFIG_I2C_SMBUS is not set
++
++#
++# I2C Algorithms
++#
++# CONFIG_I2C_ALGOBIT is not set
++# CONFIG_I2C_ALGOPCF is not set
++# CONFIG_I2C_ALGOPCA is not set
++
++#
++# I2C Hardware Bus support
++#
++
++#
++# I2C system bus drivers (mostly embedded / system-on-chip)
++#
++# CONFIG_I2C_DESIGNWARE_PLATFORM is not set
++# CONFIG_I2C_HIBVT is not set
++CONFIG_I2C_HISI_V110=y
++# CONFIG_I2C_NOMADIK 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_RK3X 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_ROBOTFUZZ_OSIF 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_CADENCE is not set
++# CONFIG_SPI_FSL_SPI is not set
++CONFIG_SPI_PL022=y
++# CONFIG_SPI_PXA2XX_PCI is not set
++# CONFIG_SPI_ROCKCHIP 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=y
++# CONFIG_SPI_TLE62X0 is not set
++# CONFIG_SPMI is not set
++# CONFIG_HSI is not set
++
++#
++# PPS support
++#
++# CONFIG_PPS is not set
++
++#
++# PPS generators support
++#
++
++#
++# PTP clock support
++#
++# CONFIG_PTP_1588_CLOCK is not set
++
++#
++# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
++#
++CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
++CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
++# CONFIG_GPIOLIB is not set
++# CONFIG_W1 is not set
++CONFIG_POWER_SUPPLY=y
++# CONFIG_POWER_SUPPLY_DEBUG is not set
++# CONFIG_PDA_POWER is not set
++# CONFIG_TEST_POWER is not set
++# CONFIG_BATTERY_DS2780 is not set
++# CONFIG_BATTERY_DS2781 is not set
++# CONFIG_BATTERY_DS2782 is not set
++# CONFIG_BATTERY_SBS is not set
++# CONFIG_BATTERY_BQ27x00 is not set
++# CONFIG_BATTERY_MAX17040 is not set
++# CONFIG_BATTERY_MAX17042 is not set
++# CONFIG_CHARGER_MAX8903 is not set
++# CONFIG_CHARGER_LP8727 is not set
++# CONFIG_CHARGER_BQ2415X is not set
++# CONFIG_CHARGER_SMB347 is not set
++CONFIG_POWER_RESET=y
++# CONFIG_POWER_RESET_BRCMSTB is not set
++CONFIG_POWER_RESET_HISI=y
++# CONFIG_POWER_RESET_RESTART is not set
++# CONFIG_POWER_RESET_VERSATILE is not set
++# CONFIG_POWER_RESET_SYSCON is not set
++# CONFIG_POWER_AVS is not set
++# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
++# CONFIG_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=y
++# CONFIG_MFD_AS3711 is not set
++# CONFIG_MFD_AS3722 is not set
++# CONFIG_PMIC_ADP5520 is not set
++# CONFIG_MFD_BCM590XX is not set
++# CONFIG_MFD_AXP20X is not set
++# CONFIG_MFD_CROS_EC is not set
++# CONFIG_PMIC_DA903X is not set
++# CONFIG_MFD_DA9052_SPI is not set
++# CONFIG_MFD_DA9052_I2C is not set
++# CONFIG_MFD_DA9055 is not set
++# CONFIG_MFD_DA9063 is not set
++# CONFIG_MFD_MC13XXX_SPI is not set
++# CONFIG_MFD_MC13XXX_I2C is not set
++# CONFIG_MFD_HI6421_PMIC is not set
++CONFIG_MFD_HISI_FMC=y
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_INTEL_SOC_PMIC is not set
++# CONFIG_MFD_KEMPLD is not set
++# CONFIG_MFD_88PM800 is not set
++# CONFIG_MFD_88PM805 is not set
++# CONFIG_MFD_88PM860X is not set
++# CONFIG_MFD_MAX14577 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_MENF21BMC is not set
++# CONFIG_EZX_PCAP is not set
++# CONFIG_MFD_VIPERBOARD is not set
++# CONFIG_MFD_RETU is not set
++# CONFIG_MFD_PCF50633 is not set
++# CONFIG_MFD_PM8921_CORE is not set
++# CONFIG_MFD_RTSX_USB is not set
++# CONFIG_MFD_RC5T583 is not set
++# CONFIG_MFD_RK808 is not set
++# CONFIG_MFD_RN5T618 is not set
++# CONFIG_MFD_SEC_CORE is not set
++# CONFIG_MFD_SI476X_CORE is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_MFD_SMSC is not set
++# CONFIG_ABX500_CORE is not set
++# CONFIG_MFD_STMPE is not set
++CONFIG_MFD_SYSCON=y
++# CONFIG_MFD_TI_AM335X_TSCADC is not set
++# CONFIG_MFD_LP3943 is not set
++# CONFIG_MFD_LP8788 is not set
++# CONFIG_MFD_PALMAS is not set
++# CONFIG_TPS6105X is not set
++# CONFIG_TPS6507X is not set
++# CONFIG_MFD_TPS65090 is not set
++# CONFIG_MFD_TPS65217 is not set
++# CONFIG_MFD_TPS65218 is not set
++# CONFIG_MFD_TPS6586X is not set
++# CONFIG_MFD_TPS80031 is not set
++# CONFIG_TWL4030_CORE is not set
++# CONFIG_TWL6040_CORE is not set
++# CONFIG_MFD_WL1273_CORE is not set
++# CONFIG_MFD_LM3533 is not set
++# CONFIG_MFD_TC3589X is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_MFD_T7L66XB is not set
++# CONFIG_MFD_TC6387XB is not set
++# CONFIG_MFD_TC6393XB is not set
++# CONFIG_MFD_ARIZONA_I2C is not set
++# CONFIG_MFD_ARIZONA_SPI is not set
++# CONFIG_MFD_WM8400 is not set
++# CONFIG_MFD_WM831X_I2C is not set
++# CONFIG_MFD_WM831X_SPI is not set
++# CONFIG_MFD_WM8350_I2C is not set
++# CONFIG_MFD_WM8994 is not set
++CONFIG_REGULATOR=y
++# CONFIG_REGULATOR_DEBUG is not set
++# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
++# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
++# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
++# CONFIG_REGULATOR_ACT8865 is not set
++# CONFIG_REGULATOR_AD5398 is not set
++# CONFIG_REGULATOR_ANATOP is not set
++# CONFIG_REGULATOR_DA9210 is not set
++# CONFIG_REGULATOR_DA9211 is not set
++# CONFIG_REGULATOR_FAN53555 is not set
++# CONFIG_REGULATOR_ISL9305 is not set
++# CONFIG_REGULATOR_ISL6271A is not set
++# CONFIG_REGULATOR_LP3971 is not set
++# CONFIG_REGULATOR_LP3972 is not set
++# CONFIG_REGULATOR_LP872X is not set
++# CONFIG_REGULATOR_LP8755 is not set
++# CONFIG_REGULATOR_LTC3589 is not set
++# CONFIG_REGULATOR_MAX1586 is not set
++# CONFIG_REGULATOR_MAX8649 is not set
++# CONFIG_REGULATOR_MAX8660 is not set
++# CONFIG_REGULATOR_MAX8952 is not set
++# CONFIG_REGULATOR_MAX8973 is not set
++# CONFIG_REGULATOR_PFUZE100 is not set
++# CONFIG_REGULATOR_TPS51632 is not set
++# CONFIG_REGULATOR_TPS62360 is not set
++# CONFIG_REGULATOR_TPS65023 is not set
++# CONFIG_REGULATOR_TPS6507X is not set
++# CONFIG_REGULATOR_TPS6524X is not set
++CONFIG_MEDIA_SUPPORT=m
++
++#
++# Multimedia core support
++#
++CONFIG_MEDIA_CAMERA_SUPPORT=y
++# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set
++# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set
++# CONFIG_MEDIA_RADIO_SUPPORT is not set
++# CONFIG_MEDIA_SDR_SUPPORT is not set
++# CONFIG_MEDIA_RC_SUPPORT is not set
++# CONFIG_MEDIA_CONTROLLER is not set
++CONFIG_VIDEO_DEV=m
++CONFIG_VIDEO_V4L2=m
++# CONFIG_VIDEO_ADV_DEBUG is not set
++# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
++CONFIG_VIDEOBUF2_CORE=m
++CONFIG_VIDEOBUF2_MEMOPS=m
++CONFIG_VIDEOBUF2_VMALLOC=m
++# CONFIG_TTPCI_EEPROM is not set
++
++#
++# Media drivers
++#
++# CONFIG_MEDIA_USB_SUPPORT is not set
++# CONFIG_V4L_PLATFORM_DRIVERS is not set
++# CONFIG_V4L_MEM2MEM_DRIVERS is not set
++# CONFIG_V4L_TEST_DRIVERS is not set
++
++#
++# Supported MMC/SDIO adapters
++#
++# CONFIG_CYPRESS_FIRMWARE is not set
++
++#
++# Media ancillary drivers (tuners, sensors, i2c, frontends)
++#
++CONFIG_MEDIA_SUBDRV_AUTOSELECT=y
++
++#
++# Audio decoders, processors and mixers
++#
++
++#
++# RDS decoders
++#
++
++#
++# Video decoders
++#
++
++#
++# Video and audio decoders
++#
++
++#
++# Video encoders
++#
++
++#
++# Camera sensor devices
++#
++
++#
++# Flash devices
++#
++
++#
++# Video improvement chips
++#
++
++#
++# Audio/Video compression chips
++#
++
++#
++# Miscellaneous helper chips
++#
++
++#
++# Sensors used on soc_camera driver
++#
++
++#
++# Tools to develop new frontends
++#
++# CONFIG_DVB_DUMMY_FE is not set
++
++#
++# Graphics support
++#
++# CONFIG_IMX_IPUV3_CORE is not set
++
++#
++# Direct Rendering Manager
++#
++# CONFIG_DRM is not set
++
++#
++# Frame buffer Devices
++#
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++CONFIG_FB_CMDLINE=y
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++# CONFIG_FB_CFB_FILLRECT is not set
++# CONFIG_FB_CFB_COPYAREA is not set
++# CONFIG_FB_CFB_IMAGEBLIT is not set
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# 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_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_ARMCLCD is not set
++# CONFIG_FB_OPENCORES is not set
++# CONFIG_FB_S1D13XXX is not set
++# CONFIG_FB_SMSCUFX is not set
++# CONFIG_FB_UDL is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_BROADSHEET is not set
++# CONFIG_FB_AUO_K190X is not set
++# CONFIG_FB_SIMPLE is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++# CONFIG_VGASTATE is not set
++
++#
++# Console display driver support
++#
++CONFIG_DUMMY_CONSOLE=y
++# CONFIG_FRAMEBUFFER_CONSOLE is not set
++# CONFIG_LOGO is not set
++# CONFIG_SOUND is not set
++
++#
++# HID support
++#
++CONFIG_HID=y
++# CONFIG_HID_BATTERY_STRENGTH is not set
++# CONFIG_HIDRAW is not set
++# CONFIG_UHID is not set
++CONFIG_HID_GENERIC=y
++
++#
++# Special HID drivers
++#
++CONFIG_HID_A4TECH=y
++# CONFIG_HID_ACRUX is not set
++CONFIG_HID_APPLE=y
++# CONFIG_HID_APPLEIR is not set
++# CONFIG_HID_AUREAL is not set
++CONFIG_HID_BELKIN=y
++CONFIG_HID_CHERRY=y
++CONFIG_HID_CHICONY=y
++CONFIG_HID_CYPRESS=y
++# CONFIG_HID_DRAGONRISE is not set
++# CONFIG_HID_EMS_FF is not set
++# CONFIG_HID_ELECOM is not set
++# CONFIG_HID_ELO is not set
++CONFIG_HID_EZKEY=y
++# CONFIG_HID_HOLTEK is not set
++# CONFIG_HID_HUION 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_ICADE is not set
++# CONFIG_HID_TWINHAN is not set
++CONFIG_HID_KENSINGTON=y
++# CONFIG_HID_LCPOWER is not set
++# CONFIG_HID_LENOVO is not set
++CONFIG_HID_LOGITECH=y
++# CONFIG_HID_LOGITECH_HIDPP is not set
++# CONFIG_LOGITECH_FF is not set
++# CONFIG_LOGIRUMBLEPAD2_FF is not set
++# CONFIG_LOGIG940_FF is not set
++# CONFIG_LOGIWHEELS_FF is not set
++# CONFIG_HID_MAGICMOUSE is not set
++CONFIG_HID_MICROSOFT=y
++CONFIG_HID_MONTEREY=y
++# 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_PENMOUNT is not set
++# CONFIG_HID_PETALYNX is not set
++# CONFIG_HID_PICOLCD is not set
++# CONFIG_HID_PRIMAX is not set
++# CONFIG_HID_ROCCAT is not set
++# CONFIG_HID_SAITEK is not set
++# CONFIG_HID_SAMSUNG is not set
++# CONFIG_HID_SPEEDLINK is not set
++# CONFIG_HID_STEELSERIES is not set
++# CONFIG_HID_SUNPLUS is not set
++# CONFIG_HID_RMI 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_XINMO is not set
++# CONFIG_HID_ZEROPLUS is not set
++# CONFIG_HID_ZYDACRON is not set
++# CONFIG_HID_SENSOR_HUB is not set
++
++#
++# USB HID support
++#
++CONFIG_USB_HID=m
++# CONFIG_HID_PID is not set
++# CONFIG_USB_HIDDEV is not set
++
++#
++# USB HID Boot Protocol drivers
++#
++# CONFIG_USB_KBD is not set
++# CONFIG_USB_MOUSE is not set
++
++#
++# I2C HID support
++#
++# CONFIG_I2C_HID is not set
++CONFIG_USB_OHCI_LITTLE_ENDIAN=y
++CONFIG_USB_SUPPORT=y
++CONFIG_USB_COMMON=y
++CONFIG_USB_ARCH_HAS_HCD=y
++CONFIG_USB=m
++# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
++
++#
++# Miscellaneous USB options
++#
++# CONFIG_USB_DEFAULT_PERSIST is not set
++# CONFIG_USB_DYNAMIC_MINORS is not set
++# CONFIG_USB_OTG_WHITELIST is not set
++# CONFIG_USB_OTG_BLACKLIST_HUB is not set
++# CONFIG_USB_OTG_FSM is not set
++# CONFIG_USB_MON is not set
++# CONFIG_USB_WUSB_CBAF is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_C67X00_HCD is not set
++# CONFIG_USB_XHCI_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_FUSBH200_HCD is not set
++# CONFIG_USB_FOTG210_HCD is not set
++# CONFIG_USB_MAX3421_HCD is not set
++# CONFIG_USB_OHCI_HCD is not set
++# CONFIG_USB_SL811_HCD is not set
++# CONFIG_USB_R8A66597_HCD is not set
++# CONFIG_USB_HCD_TEST_MODE is not set
++
++#
++# USB Device Class drivers
++#
++# CONFIG_USB_ACM is not set
++# CONFIG_USB_PRINTER is not set
++# CONFIG_USB_WDM is not set
++# CONFIG_USB_TMC is not set
++
++#
++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
++#
++
++#
++# also be needed; see USB_STORAGE Help for more info
++#
++# CONFIG_USB_STORAGE is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++# CONFIG_USBIP_CORE is not set
++# CONFIG_USB_MUSB_HDRC is not set
++# CONFIG_USB_DWC3 is not set
++# CONFIG_USB_DWC2 is not set
++# CONFIG_USB_CHIPIDEA is not set
++
++#
++# USB port drivers
++#
++# CONFIG_USB_SERIAL is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
++# CONFIG_USB_SEVSEG is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
++# CONFIG_USB_APPLEDISPLAY is not set
++# CONFIG_USB_LD is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
++# CONFIG_USB_IOWARRIOR is not set
++# CONFIG_USB_TEST is not set
++# CONFIG_USB_EHSET_TEST_FIXTURE is not set
++# CONFIG_USB_ISIGHTFW is not set
++# CONFIG_USB_YUREX is not set
++# CONFIG_USB_EZUSB_FX2 is not set
++# CONFIG_USB_HSIC_USB3503 is not set
++# CONFIG_USB_LINK_LAYER_TEST is not set
++
++#
++# USB Physical Layer drivers
++#
++# CONFIG_USB_PHY is not set
++# CONFIG_NOP_USB_XCEIV is not set
++# CONFIG_AM335X_PHY_USB is not set
++# CONFIG_USB_ISP1301 is not set
++# CONFIG_USB_ULPI is not set
++CONFIG_USB_GADGET=y
++# CONFIG_USB_GADGET_DEBUG is not set
++# CONFIG_USB_GADGET_DEBUG_FILES is not set
++CONFIG_USB_GADGET_VBUS_DRAW=2
++CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2
++
++#
++# USB Peripheral Controller
++#
++# CONFIG_USB_FUSB300 is not set
++# CONFIG_USB_FOTG210_UDC is not set
++# CONFIG_USB_GR_UDC is not set
++# CONFIG_USB_R8A66597 is not set
++# CONFIG_USB_PXA27X is not set
++# CONFIG_USB_MV_UDC is not set
++CONFIG_HIUSB_DEVICE2_0=y
++CONFIG_USB_HISI_UDC=m
++# CONFIG_USB_AUTO_SWITCH is not set
++# CONFIG_HIUSB_DEVICE3_0 is not set
++# CONFIG_USB_MV_U3D is not set
++# CONFIG_USB_M66592 is not set
++# CONFIG_USB_NET2272 is not set
++# CONFIG_USB_GADGET_XILINX is not set
++CONFIG_USB_LIBCOMPOSITE=m
++CONFIG_USB_F_ACM=m
++CONFIG_USB_U_SERIAL=m
++CONFIG_USB_U_ETHER=m
++CONFIG_USB_F_RNDIS=m
++CONFIG_USB_F_MASS_STORAGE=m
++CONFIG_USB_F_UAC1=m
++CONFIG_USB_F_UVC=m
++# CONFIG_USB_CONFIGFS is not set
++# CONFIG_USB_ZERO is not set
++CONFIG_USB_AUDIO=m
++CONFIG_GADGET_UAC1=y
++# CONFIG_USB_ETH is not set
++# CONFIG_USB_G_NCM is not set
++# CONFIG_USB_GADGETFS is not set
++# CONFIG_USB_FUNCTIONFS is not set
++CONFIG_USB_MASS_STORAGE=m
++# CONFIG_USB_G_SERIAL is not set
++# CONFIG_USB_G_PRINTER is not set
++# CONFIG_USB_CDC_COMPOSITE is not set
++# CONFIG_USB_G_ACM_MS is not set
++CONFIG_USB_G_MULTI=m
++CONFIG_USB_G_MULTI_RNDIS=y
++# CONFIG_USB_G_MULTI_CDC is not set
++# CONFIG_USB_G_HID is not set
++# CONFIG_USB_G_DBGP is not set
++# CONFIG_USB_G_WEBCAM is not set
++CONFIG_USB_G_WEBCAM_AUDIO=m
++# CONFIG_UWB is not set
++CONFIG_MMC=m
++# CONFIG_MMC_DEBUG is not set
++# CONFIG_MMC_CLKGATE is not set
++CONFIG_MMC_EMBEDDED_SDIO=y
++# CONFIG_MMC_PARANOID_SD_INIT is not set
++
++#
++# MMC/SD/SDIO Card Drivers
++#
++CONFIG_MMC_BLOCK=m
++CONFIG_MMC_BLOCK_MINORS=8
++CONFIG_MMC_BLOCK_BOUNCE=y
++# CONFIG_MMC_BLOCK_DEFERRED_RESUME is not set
++# CONFIG_SDIO_UART is not set
++# CONFIG_MMC_TEST is not set
++
++#
++# MMC/SD/SDIO Host Controller Drivers
++#
++# CONFIG_MMC_ARMMMCI is not set
++# CONFIG_MMC_SDHCI is not set
++# CONFIG_MMC_DW is not set
++# CONFIG_MMC_VUB300 is not set
++# CONFIG_MMC_USHC is not set
++# CONFIG_MMC_USDHI6ROL0 is not set
++CONFIG_HIMCIV200=m
++CONFIG_SEND_AUTO_STOP=y
++CONFIG_DETECT_CARD_TIME=200
++# CONFIG_MEMSTICK is not set
++# CONFIG_NEW_LEDS is not set
++# CONFIG_SWITCH is not set
++# CONFIG_ACCESSIBILITY is not set
++# CONFIG_EDAC is not set
++CONFIG_RTC_LIB=y
++# CONFIG_RTC_CLASS is not set
++# CONFIG_DMADEVICES is not set
++# CONFIG_AUXDISPLAY is not set
++# CONFIG_UIO is not set
++# CONFIG_VIRT_DRIVERS is not set
++
++#
++# Virtio drivers
++#
++# CONFIG_VIRTIO_MMIO is not set
++
++#
++# Microsoft Hyper-V guest support
++#
++# CONFIG_STAGING is not set
++
++#
++# SOC (System On Chip) specific Drivers
++#
++# CONFIG_SOC_TI is not set
++CONFIG_CLKDEV_LOOKUP=y
++CONFIG_HAVE_CLK_PREPARE=y
++CONFIG_COMMON_CLK=y
++
++#
++# Common Clock Framework
++#
++# CONFIG_COMMON_CLK_SI5351 is not set
++# CONFIG_COMMON_CLK_SI570 is not set
++# CONFIG_COMMON_CLK_PXA is not set
++# CONFIG_COMMON_CLK_QCOM is not set
++
++#
++# Hardware Spinlock drivers
++#
++
++#
++# Clock Source drivers
++#
++CONFIG_CLKSRC_OF=y
++CONFIG_CLKSRC_MMIO=y
++CONFIG_ARM_ARCH_TIMER=y
++CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y
++# CONFIG_ARM_ARCH_TIMER_VCT_ACCESS is not set
++# CONFIG_ATMEL_PIT is not set
++# CONFIG_SH_TIMER_CMT is not set
++# CONFIG_SH_TIMER_MTU2 is not set
++# CONFIG_SH_TIMER_TMU is not set
++# CONFIG_EM_TIMER_STI is not set
++# CONFIG_CLKSRC_VERSATILE is not set
++# CONFIG_MAILBOX is not set
++# CONFIG_IOMMU_SUPPORT is not set
++
++#
++# Remoteproc drivers
++#
++# CONFIG_STE_MODEM_RPROC is not set
++
++#
++# Rpmsg drivers
++#
++
++#
++# SOC (System On Chip) specific Drivers
++#
++# 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
++CONFIG_IRQCHIP=y
++CONFIG_ARM_GIC=y
++# CONFIG_IPACK_BUS is not set
++CONFIG_ARCH_HAS_RESET_CONTROLLER=y
++CONFIG_RESET_CONTROLLER=y
++# CONFIG_FMC is not set
++
++#
++# PHY Subsystem
++#
++CONFIG_GENERIC_PHY=y
++# CONFIG_BCM_KONA_USB2_PHY is not set
++CONFIG_PHY_HISI_INNO_USB2=m
++# CONFIG_POWERCAP is not set
++# CONFIG_MCB is not set
++# CONFIG_HI_DMAC is not set
++
++#
++# Hisilicon driver support
++#
++# CONFIG_CMA_MEM_SHARED is not set
++# CONFIG_CMA_ADVANCE_SHARE is not set
++
++#
++# File systems
++#
++CONFIG_DCACHE_WORD_ACCESS=y
++# CONFIG_EXT2_FS is not set
++# CONFIG_EXT3_FS is not set
++# CONFIG_EXT4_FS is not set
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_BTRFS_FS is not set
++# CONFIG_NILFS2_FS is not set
++CONFIG_FS_POSIX_ACL=y
++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 is not set
++# CONFIG_FUSE_FS is not set
++# CONFIG_OVERLAY_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_KERNFS=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=m
++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_YAFFS_FS is not set
++# CONFIG_JFFS2_FS 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 is not set
++# 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 is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V2=y
++CONFIG_NFS_V3=y
++CONFIG_NFS_V3_ACL=y
++# CONFIG_NFS_V4 is not set
++# CONFIG_NFS_SWAP is not set
++# CONFIG_ROOT_NFS is not set
++# CONFIG_NFSD is not set
++CONFIG_GRACE_PERIOD=y
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_ACL_SUPPORT=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 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=y
++# CONFIG_DLM is not set
++
++#
++# Kernel hacking
++#
++
++#
++# printk and dmesg options
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4
++# CONFIG_BOOT_PRINTK_DELAY is not set
++
++#
++# Compile-time checks and compiler options
++#
++# CONFIG_DEBUG_INFO is not set
++# CONFIG_ENABLE_WARN_DEPRECATED is not set
++# CONFIG_ENABLE_MUST_CHECK is not set
++CONFIG_FRAME_WARN=1024
++# CONFIG_STRIP_ASM_SYMS is not set
++# CONFIG_READABLE_ASM is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++# CONFIG_DEBUG_FS is not set
++# CONFIG_HEADERS_CHECK is not set
++# CONFIG_DEBUG_SECTION_MISMATCH is not set
++# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
++# CONFIG_MAGIC_SYSRQ is not set
++CONFIG_DEBUG_KERNEL=y
++
++#
++# Memory Debugging
++#
++# CONFIG_DEBUG_PAGEALLOC is not set
++# CONFIG_DEBUG_OBJECTS is not set
++# CONFIG_SLUB_STATS is not set
++CONFIG_HAVE_DEBUG_KMEMLEAK=y
++# CONFIG_DEBUG_KMEMLEAK is not set
++# CONFIG_DEBUG_STACK_USAGE is not set
++# CONFIG_DEBUG_VM is not set
++CONFIG_DEBUG_MEMORY_INIT=y
++# CONFIG_DEBUG_HIGHMEM is not set
++# CONFIG_DEBUG_SHIRQ is not set
++
++#
++# Debug Lockups and Hangs
++#
++# CONFIG_LOCKUP_DETECTOR is not set
++# CONFIG_DETECT_HUNG_TASK is not set
++CONFIG_PANIC_ON_OOPS=y
++CONFIG_PANIC_ON_OOPS_VALUE=1
++CONFIG_PANIC_TIMEOUT=0
++CONFIG_SCHED_DEBUG=y
++# CONFIG_SCHEDSTATS is not set
++# CONFIG_SCHED_STACK_END_CHECK is not set
++# CONFIG_TIMER_STATS is not set
++
++#
++# Lock Debugging (spinlocks, mutexes, etc...)
++#
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_LOCK_STAT is not set
++# CONFIG_DEBUG_ATOMIC_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_LOCK_TORTURE_TEST is not set
++CONFIG_STACKTRACE=y
++# CONFIG_DEBUG_KOBJECT is not set
++CONFIG_DEBUG_BUGVERBOSE=y
++# CONFIG_DEBUG_LIST is not set
++# CONFIG_DEBUG_PI_LIST is not set
++# CONFIG_DEBUG_SG is not set
++# CONFIG_DEBUG_NOTIFIERS is not set
++# CONFIG_DEBUG_CREDENTIALS is not set
++
++#
++# RCU Debugging
++#
++# CONFIG_SPARSE_RCU_POINTER is not set
++# CONFIG_TORTURE_TEST is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_RCU_TRACE is not set
++# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_NOTIFIER_ERROR_INJECTION is not set
++# CONFIG_FAULT_INJECTION is not set
++# CONFIG_LATENCYTOP 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 is not set
++
++#
++# Runtime Testing
++#
++# CONFIG_TEST_LIST_SORT is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_RBTREE_TEST is not set
++# CONFIG_INTERVAL_TREE_TEST is not set
++# CONFIG_PERCPU_TEST is not set
++# CONFIG_ATOMIC64_SELFTEST is not set
++# CONFIG_TEST_STRING_HELPERS is not set
++# CONFIG_TEST_KSTRTOX is not set
++# CONFIG_TEST_RHASHTABLE is not set
++# CONFIG_DMA_API_DEBUG is not set
++# CONFIG_TEST_LKM is not set
++# CONFIG_TEST_USER_COPY is not set
++# CONFIG_TEST_BPF is not set
++# CONFIG_TEST_FIRMWARE is not set
++# CONFIG_TEST_UDELAY is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_KGDB is not set
++# CONFIG_ARM_PTDUMP is not set
++CONFIG_STRICT_DEVMEM=y
++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_DEBUG_UART_PL01X is not set
++# CONFIG_DEBUG_UART_8250 is not set
++# CONFIG_DEBUG_UART_BCM63XX is not set
++CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"
++# CONFIG_OC_ETM is not set
++# CONFIG_PID_IN_CONTEXTIDR is not set
++# CONFIG_DEBUG_SET_MODULE_RONX is not set
++# CONFIG_CORESIGHT is not set
++
++#
++# 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_AEAD=y
++CONFIG_CRYPTO_AEAD2=y
++CONFIG_CRYPTO_BLKCIPHER=y
++CONFIG_CRYPTO_BLKCIPHER2=y
++CONFIG_CRYPTO_HASH=y
++CONFIG_CRYPTO_HASH2=y
++CONFIG_CRYPTO_RNG=y
++CONFIG_CRYPTO_RNG2=y
++CONFIG_CRYPTO_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_WORKQUEUE=y
++# CONFIG_CRYPTO_CRYPTD is not set
++# CONFIG_CRYPTO_MCRYPTD is not set
++# CONFIG_CRYPTO_AUTHENC is not set
++# CONFIG_CRYPTO_TEST is not set
++
++#
++# Authenticated Encryption with Associated Data
++#
++CONFIG_CRYPTO_CCM=y
++# CONFIG_CRYPTO_GCM is not set
++CONFIG_CRYPTO_SEQIV=y
++
++#
++# Block modes
++#
++# CONFIG_CRYPTO_CBC is not set
++CONFIG_CRYPTO_CTR=y
++# 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_CMAC is not set
++# CONFIG_CRYPTO_HMAC is not set
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_VMAC is not set
++
++#
++# Digest
++#
++CONFIG_CRYPTO_CRC32C=y
++# CONFIG_CRYPTO_CRC32 is not set
++# CONFIG_CRYPTO_CRCT10DIF 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_SHA1_ARM_NEON is not set
++# CONFIG_CRYPTO_SHA256 is not set
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_SHA512_ARM_NEON 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_AES_ARM_BS is not set
++# CONFIG_CRYPTO_ANUBIS is not set
++CONFIG_CRYPTO_ARC4=y
++# 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=y
++# CONFIG_CRYPTO_ZLIB is not set
++CONFIG_CRYPTO_LZO=y
++# CONFIG_CRYPTO_LZ4 is not set
++# CONFIG_CRYPTO_LZ4HC is not set
++
++#
++# Random Number Generation
++#
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++# CONFIG_CRYPTO_DRBG_MENU is not set
++# CONFIG_CRYPTO_USER_API_HASH is not set
++# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
++CONFIG_CRYPTO_HW=y
++# CONFIG_BINARY_PRINTF is not set
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++CONFIG_GENERIC_STRNCPY_FROM_USER=y
++CONFIG_GENERIC_STRNLEN_USER=y
++CONFIG_GENERIC_NET_UTILS=y
++CONFIG_GENERIC_PCI_IOMAP=y
++CONFIG_GENERIC_IO=y
++CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
++# CONFIG_CRC_CCITT is not set
++CONFIG_CRC16=y
++# CONFIG_CRC_T10DIF is not set
++# 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=y
++# CONFIG_CRC8 is not set
++# CONFIG_AUDIT_ARCH_COMPAT_GENERIC is not set
++# CONFIG_RANDOM32_SELFTEST is not set
++CONFIG_ZLIB_INFLATE=y
++CONFIG_ZLIB_DEFLATE=y
++CONFIG_LZO_COMPRESS=y
++CONFIG_LZO_DECOMPRESS=y
++CONFIG_XZ_DEC=y
++CONFIG_XZ_DEC_X86=y
++CONFIG_XZ_DEC_POWERPC=y
++CONFIG_XZ_DEC_IA64=y
++CONFIG_XZ_DEC_ARM=y
++CONFIG_XZ_DEC_ARMTHUMB=y
++CONFIG_XZ_DEC_SPARC=y
++CONFIG_XZ_DEC_BCJ=y
++# CONFIG_XZ_DEC_TEST is not set
++CONFIG_GENERIC_ALLOCATOR=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT_MAP=y
++CONFIG_HAS_DMA=y
++CONFIG_DQL=y
++CONFIG_NLATTR=y
++CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
++CONFIG_AVERAGE=y
++# CONFIG_CORDIC is not set
++# CONFIG_DDR is not set
++CONFIG_LIBFDT=y
++CONFIG_ARCH_HAS_SG_CHAIN=y
++# CONFIG_VIRTUALIZATION is not set
+diff --git a/arch/arm/configs/hi3556_single_spinor_mini_defconfig b/arch/arm/configs/hi3556_single_spinor_mini_defconfig
+new file mode 100644
+index 0000000..31cd1bb
+--- /dev/null
++++ b/arch/arm/configs/hi3556_single_spinor_mini_defconfig
+@@ -0,0 +1,2399 @@
++#
++# Automatically generated file; DO NOT EDIT.
++# Linux/arm 3.18.20 Kernel Configuration
++#
++CONFIG_ARM=y
++CONFIG_ARM_HAS_SG_CHAIN=y
++CONFIG_MIGHT_HAVE_PCI=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=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_XCHGADD_ALGORITHM=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_NEED_DMA_MAP_STATE=y
++CONFIG_ARCH_SUPPORTS_UPROBES=y
++CONFIG_VECTORS_BASE=0xffff0000
++CONFIG_ARM_PATCH_PHYS_VIRT=y
++CONFIG_GENERIC_BUG=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++CONFIG_IRQ_WORK=y
++CONFIG_BUILDTIME_EXTABLE_SORT=y
++
++#
++# General setup
++#
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_CROSS_COMPILE=""
++# CONFIG_COMPILE_TEST is not set
++CONFIG_LOCALVERSION=""
++# CONFIG_LOCALVERSION_AUTO is not set
++CONFIG_HAVE_KERNEL_GZIP=y
++CONFIG_HAVE_KERNEL_LZMA=y
++CONFIG_HAVE_KERNEL_XZ=y
++CONFIG_HAVE_KERNEL_LZO=y
++CONFIG_HAVE_KERNEL_LZ4=y
++CONFIG_KERNEL_GZIP=y
++# CONFIG_KERNEL_LZMA is not set
++# CONFIG_KERNEL_XZ is not set
++# CONFIG_KERNEL_LZO is not set
++# CONFIG_KERNEL_LZ4 is not set
++CONFIG_HW_DECOMPRESS=y
++# CONFIG_SOFT_DECOMPRESS is not set
++CONFIG_DEFAULT_HOSTNAME="(none)"
++# CONFIG_SWAP is not set
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++# CONFIG_POSIX_MQUEUE is not set
++CONFIG_CROSS_MEMORY_ATTACH=y
++# CONFIG_FHANDLE is not set
++CONFIG_USELIB=y
++# CONFIG_AUDIT is not set
++CONFIG_HAVE_ARCH_AUDITSYSCALL=y
++
++#
++# IRQ subsystem
++#
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_GENERIC_IRQ_SHOW=y
++CONFIG_HARDIRQS_SW_RESEND=y
++CONFIG_IRQ_DOMAIN=y
++CONFIG_HANDLE_DOMAIN_IRQ=y
++CONFIG_IRQ_FORCED_THREADING=y
++CONFIG_SPARSE_IRQ=y
++CONFIG_GENERIC_CLOCKEVENTS=y
++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
++
++#
++# Timers subsystem
++#
++CONFIG_TICK_ONESHOT=y
++CONFIG_NO_HZ_COMMON=y
++# CONFIG_HZ_PERIODIC is not set
++CONFIG_NO_HZ_IDLE=y
++CONFIG_NO_HZ=y
++# CONFIG_HIGH_RES_TIMERS is not set
++
++#
++# CPU/Task time and stats accounting
++#
++CONFIG_TICK_CPU_ACCOUNTING=y
++# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set
++# CONFIG_IRQ_TIME_ACCOUNTING is not set
++# CONFIG_BSD_PROCESS_ACCT is not set
++# CONFIG_TASKSTATS is not set
++
++#
++# RCU Subsystem
++#
++CONFIG_TINY_RCU=y
++# CONFIG_PREEMPT_RCU is not set
++# CONFIG_TASKS_RCU is not set
++# CONFIG_RCU_STALL_COMMON is not set
++# CONFIG_TREE_RCU_TRACE is not set
++# CONFIG_BUILD_BIN2C is not set
++# CONFIG_IKCONFIG is not set
++CONFIG_LOG_BUF_SHIFT=17
++CONFIG_GENERIC_SCHED_CLOCK=y
++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_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 is not set
++# CONFIG_SCHED_AUTOGROUP is not set
++# CONFIG_SYSFS_DEPRECATED is not set
++# CONFIG_RELAY is not set
++# CONFIG_BLK_DEV_INITRD is not set
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++CONFIG_HAVE_UID16=y
++CONFIG_BPF=y
++CONFIG_EXPERT=y
++# CONFIG_UID16 is not set
++# CONFIG_SGETMASK_SYSCALL is not set
++CONFIG_SYSFS_SYSCALL=y
++# CONFIG_SYSCTL_SYSCALL is not set
++CONFIG_KALLSYMS=y
++# CONFIG_KALLSYMS_ALL is not set
++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_BPF_SYSCALL is not set
++CONFIG_SHMEM=y
++CONFIG_AIO=y
++CONFIG_ADVISE_SYSCALLS=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 is not set
++# CONFIG_SLUB_DEBUG is not set
++# CONFIG_COMPAT_BRK is not set
++# 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_UPROBES is not set
++# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
++CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
++CONFIG_ARCH_USE_BUILTIN_BSWAP=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_GENERIC_SMP_IDLE_THREAD=y
++CONFIG_GENERIC_IDLE_POLL_SETUP=y
++CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
++CONFIG_HAVE_CLK=y
++CONFIG_HAVE_DMA_API_DEBUG=y
++CONFIG_HAVE_PERF_REGS=y
++CONFIG_HAVE_PERF_USER_STACK_DUMP=y
++CONFIG_HAVE_ARCH_JUMP_LABEL=y
++CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
++CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
++CONFIG_HAVE_CC_STACKPROTECTOR=y
++# CONFIG_CC_STACKPROTECTOR is not set
++CONFIG_CC_STACKPROTECTOR_NONE=y
++# CONFIG_CC_STACKPROTECTOR_REGULAR is not set
++# CONFIG_CC_STACKPROTECTOR_STRONG is not set
++CONFIG_HAVE_CONTEXT_TRACKING=y
++CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
++CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
++CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
++CONFIG_MODULES_USE_ELF_REL=y
++CONFIG_CLONE_BACKWARDS=y
++CONFIG_OLD_SIGSUSPEND3=y
++CONFIG_OLD_SIGACTION=y
++
++#
++# GCOV-based kernel profiling
++#
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_RT_MUTEXES=y
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++# CONFIG_MODULE_FORCE_LOAD is not set
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++# CONFIG_MODULE_SIG is not set
++# CONFIG_MODULE_COMPRESS is not set
++CONFIG_BLOCK=y
++CONFIG_LBDAF=y
++CONFIG_BLK_DEV_BSG=y
++# CONFIG_BLK_DEV_BSGLIB is not set
++# CONFIG_BLK_DEV_INTEGRITY is not set
++CONFIG_BLK_CMDLINE_PARSER=y
++
++#
++# Partition Types
++#
++CONFIG_PARTITION_ADVANCED=y
++# CONFIG_ACORN_PARTITION is not set
++# CONFIG_AIX_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=y
++# CONFIG_SYSV68_PARTITION is not set
++CONFIG_CMDLINE_PARTITION=y
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++CONFIG_DEFAULT_DEADLINE=y
++# CONFIG_DEFAULT_CFQ is not set
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="deadline"
++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_ARCH_SUPPORTS_ATOMIC_RMW=y
++CONFIG_FREEZER=y
++
++#
++# System Type
++#
++CONFIG_MMU=y
++CONFIG_ARCH_MULTIPLATFORM=y
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_AT91 is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_GEMINI is not set
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_IOP13XX is not set
++# CONFIG_ARCH_IOP32X is not set
++# CONFIG_ARCH_IOP33X is not set
++# CONFIG_ARCH_IXP4XX is not set
++# CONFIG_ARCH_DOVE is not set
++# CONFIG_ARCH_MV78XX0 is not set
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_MMP is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_W90X900 is not set
++# CONFIG_ARCH_LPC32XX is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_MSM is not set
++# CONFIG_ARCH_SHMOBILE_LEGACY 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_DAVINCI is not set
++# CONFIG_ARCH_OMAP1 is not set
++
++#
++# Multiple platform selection
++#
++
++#
++# CPU Core family selection
++#
++# CONFIG_ARCH_MULTI_V6 is not set
++CONFIG_ARCH_MULTI_V7=y
++CONFIG_ARCH_MULTI_V6_V7=y
++# CONFIG_ARCH_MULTI_CPU_AUTO is not set
++# CONFIG_ARCH_VIRT is not set
++# CONFIG_ARCH_MVEBU is not set
++# CONFIG_ARCH_BCM is not set
++# CONFIG_ARCH_BERLIN is not set
++# CONFIG_ARCH_HIGHBANK is not set
++CONFIG_ARCH_HISI=y
++
++#
++# Hisilicon platform type
++#
++# CONFIG_ARCH_HI3xxx is not set
++# CONFIG_ARCH_HIP04 is not set
++# CONFIG_ARCH_HIX5HD2 is not set
++# CONFIG_ARCH_HI3519 is not set
++# CONFIG_ARCH_HI3519V101 is not set
++# CONFIG_ARCH_HI3516AV200 is not set
++# CONFIG_ARCH_HI3559 is not set
++CONFIG_ARCH_HI3556=y
++# CONFIG_ARCH_HI3536C is not set
++# CONFIG_ARCH_HI3531D is not set
++# CONFIG_ARCH_HI3521D is not set
++# CONFIG_ARCH_KEYSTONE is not set
++# CONFIG_ARCH_MESON is not set
++# CONFIG_ARCH_MXC is not set
++# CONFIG_ARCH_MEDIATEK is not set
++
++#
++# TI OMAP/AM/DM/DRA Family
++#
++# CONFIG_ARCH_OMAP3 is not set
++# CONFIG_ARCH_OMAP4 is not set
++# CONFIG_SOC_OMAP5 is not set
++# CONFIG_SOC_AM33XX is not set
++# CONFIG_SOC_AM43XX is not set
++# CONFIG_SOC_DRA7XX is not set
++# CONFIG_ARCH_QCOM is not set
++# CONFIG_ARCH_ROCKCHIP is not set
++# CONFIG_ARCH_SOCFPGA is not set
++# CONFIG_PLAT_SPEAR is not set
++# CONFIG_ARCH_STI is not set
++# CONFIG_ARCH_S5PV210 is not set
++# CONFIG_ARCH_EXYNOS is not set
++# CONFIG_ARCH_SHMOBILE_MULTI is not set
++# CONFIG_ARCH_SUNXI is not set
++# CONFIG_ARCH_SIRF is not set
++# CONFIG_ARCH_TEGRA is not set
++# CONFIG_ARCH_U8500 is not set
++# CONFIG_ARCH_VEXPRESS is not set
++# CONFIG_ARCH_WM8850 is not set
++# CONFIG_ARCH_ZYNQ is not set
++CONFIG_ARM_TIMER_SP804=y
++
++#
++# Processor Type
++#
++CONFIG_CPU_V7=y
++CONFIG_CPU_32v6K=y
++CONFIG_CPU_32v7=y
++CONFIG_CPU_ABRT_EV7=y
++CONFIG_CPU_PABRT_V7=y
++CONFIG_CPU_CACHE_V7=y
++CONFIG_CPU_CACHE_VIPT=y
++CONFIG_CPU_COPY_V6=y
++CONFIG_CPU_TLB_V7=y
++CONFIG_CPU_HAS_ASID=y
++CONFIG_CPU_CP15=y
++CONFIG_CPU_CP15_MMU=y
++
++#
++# Processor Features
++#
++# CONFIG_ARM_LPAE is not set
++# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
++CONFIG_ARM_THUMB=y
++# CONFIG_ARM_THUMBEE is not set
++CONFIG_ARM_VIRT_EXT=y
++CONFIG_SWP_EMULATE=y
++# CONFIG_CPU_ICACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_DISABLE is not set
++# CONFIG_CPU_BPREDICT_DISABLE is not set
++CONFIG_KUSER_HELPERS=y
++CONFIG_MIGHT_HAVE_CACHE_L2X0=y
++# CONFIG_CACHE_L2X0 is not set
++CONFIG_ARM_L1_CACHE_SHIFT_6=y
++CONFIG_ARM_L1_CACHE_SHIFT=6
++CONFIG_ARM_DMA_MEM_BUFFERABLE=y
++CONFIG_MULTI_IRQ_HANDLER=y
++# CONFIG_ARM_ERRATA_430973 is not set
++# CONFIG_ARM_ERRATA_720789 is not set
++# CONFIG_ARM_ERRATA_754322 is not set
++# CONFIG_ARM_ERRATA_775420 is not set
++# CONFIG_ARM_ERRATA_773022 is not set
++
++#
++# Bus support
++#
++CONFIG_ARM_AMBA=y
++# CONFIG_PCI is not set
++# CONFIG_PCI_SYSCALL is not set
++# CONFIG_PCCARD is not set
++
++#
++# Kernel Features
++#
++CONFIG_HAVE_SMP=y
++# CONFIG_SMP is not set
++CONFIG_DISABLE_CPU_SCHED_DOMAIN_BALANCE=y
++CONFIG_HAVE_ARM_ARCH_TIMER=y
++CONFIG_VMSPLIT_3G=y
++# CONFIG_VMSPLIT_2G is not set
++# CONFIG_VMSPLIT_1G is not set
++CONFIG_PAGE_OFFSET=0xC0000000
++# CONFIG_ARM_PSCI is not set
++CONFIG_ARCH_NR_GPIO=0
++CONFIG_PREEMPT_NONE=y
++# CONFIG_PREEMPT_VOLUNTARY is not set
++# CONFIG_PREEMPT is not set
++CONFIG_HZ_FIXED=0
++# CONFIG_HZ_100 is not set
++# CONFIG_HZ_200 is not set
++# CONFIG_HZ_250 is not set
++# CONFIG_HZ_300 is not set
++# CONFIG_HZ_500 is not set
++CONFIG_HZ_1000=y
++CONFIG_HZ=1000
++# CONFIG_SCHED_HRTICK is not set
++# CONFIG_THUMB2_KERNEL is not set
++CONFIG_AEABI=y
++# CONFIG_OABI_COMPAT is not set
++# 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_ARCH_WANT_GENERAL_HUGETLB=y
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_HAVE_MEMBLOCK=y
++CONFIG_NO_BOOTMEM=y
++CONFIG_MEMORY_ISOLATION=y
++# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=4
++CONFIG_COMPACTION=y
++CONFIG_MIGRATION=y
++# CONFIG_PHYS_ADDR_T_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_BOUNCE=y
++# CONFIG_KSM is not set
++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
++CONFIG_NEED_PER_CPU_KM=y
++# CONFIG_CLEANCACHE is not set
++CONFIG_CMA=y
++# CONFIG_CMA_DEBUG is not set
++CONFIG_CMA_AREAS=7
++# CONFIG_ZPOOL is not set
++# CONFIG_ZBUD is not set
++# CONFIG_ZSMALLOC 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_SWIOTLB=y
++CONFIG_IOMMU_HELPER=y
++# CONFIG_XEN is not set
++# CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART is not set
++
++#
++# Boot options
++#
++CONFIG_USE_OF=y
++CONFIG_ATAGS=y
++# CONFIG_DEPRECATED_PARAM_STRUCT is not set
++# CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE is not set
++CONFIG_ZBOOT_ROM_TEXT=0
++CONFIG_ZBOOT_ROM_BSS=0
++CONFIG_ARM_APPENDED_DTB=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_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_GOV_COMMON=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 is not set
++CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
++# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE is not set
++CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
++CONFIG_CPU_FREQ_GOV_POWERSAVE=y
++CONFIG_CPU_FREQ_GOV_USERSPACE=y
++CONFIG_CPU_FREQ_GOV_ONDEMAND=y
++CONFIG_CPU_FREQ_GOV_INTERACTIVE=y
++# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
++# CONFIG_CPUFREQ_DT is not set
++
++#
++# ARM CPU frequency scaling drivers
++#
++# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set
++
++#
++# CPU Idle
++#
++# CONFIG_CPU_IDLE is not set
++# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++CONFIG_VFP=y
++CONFIG_VFPv3=y
++CONFIG_NEON=y
++CONFIG_KERNEL_MODE_NEON=y
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
++CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
++CONFIG_BINFMT_SCRIPT=y
++# CONFIG_HAVE_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
++CONFIG_COREDUMP=y
++
++#
++# Power management options
++#
++CONFIG_SUSPEND=y
++CONFIG_SUSPEND_FREEZER=y
++# CONFIG_WAKELOCK is not set
++# CONFIG_HISI_SNAPSHOT_BOOT is not set
++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_OPP=y
++CONFIG_PM_CLK=y
++# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set
++CONFIG_CPU_PM=y
++# CONFIG_SUSPEND_TIME is not set
++CONFIG_ARCH_SUSPEND_POSSIBLE=y
++CONFIG_ARM_CPU_SUSPEND=y
++CONFIG_ARCH_HIBERNATION_POSSIBLE=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_NET_IP_TUNNEL is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_NET_IPVTI is not set
++# CONFIG_NET_UDP_TUNNEL is not set
++# CONFIG_NET_FOU is not set
++# CONFIG_GENEVE 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 is not set
++CONFIG_INET_XFRM_MODE_TRANSPORT=y
++CONFIG_INET_XFRM_MODE_TUNNEL=y
++CONFIG_INET_XFRM_MODE_BEET=y
++CONFIG_INET_LRO=y
++CONFIG_INET_DIAG=y
++CONFIG_INET_TCP_DIAG=y
++# CONFIG_INET_UDP_DIAG is not set
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++# CONFIG_TCP_MD5SIG is not set
++# CONFIG_IPV6 is not set
++# CONFIG_ANDROID_PARANOID_NETWORK is not set
++CONFIG_NET_ACTIVITY_STATS=y
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NET_PTP_CLASSIFY 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_NF_TABLES is not set
++# CONFIG_NETFILTER_XTABLES is not set
++# CONFIG_IP_SET is not set
++# CONFIG_IP_VS is not set
++
++#
++# IP: Netfilter Configuration
++#
++# CONFIG_NF_DEFRAG_IPV4 is not set
++# CONFIG_NF_LOG_ARP is not set
++# CONFIG_NF_LOG_IPV4 is not set
++# CONFIG_NF_REJECT_IPV4 is not set
++# CONFIG_IP_NF_IPTABLES is not set
++# CONFIG_IP_NF_ARPTABLES 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_HAVE_NET_DSA=y
++# 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_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_VSOCKETS is not set
++# CONFIG_NETLINK_MMAP is not set
++# CONFIG_NETLINK_DIAG is not set
++# CONFIG_NET_MPLS_GSO is not set
++# CONFIG_HSR is not set
++# CONFIG_CGROUP_NET_PRIO is not set
++# CONFIG_CGROUP_NET_CLASSID is not set
++CONFIG_NET_RX_BUSY_POLL=y
++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 is not set
++CONFIG_DEVTMPFS=y
++CONFIG_DEVTMPFS_MOUNT=y
++CONFIG_STANDALONE=y
++# CONFIG_PREVENT_FIRMWARE_BUILD is not set
++CONFIG_FW_LOADER=y
++# CONFIG_FIRMWARE_IN_KERNEL is not set
++CONFIG_EXTRA_FIRMWARE=""
++# CONFIG_FW_LOADER_USER_HELPER_FALLBACK is not set
++CONFIG_ALLOW_DEV_COREDUMP=y
++# 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_HAVE_CPU_AUTOPROBE is not set
++CONFIG_REGMAP=y
++CONFIG_REGMAP_MMIO=y
++CONFIG_DMA_SHARED_BUFFER=y
++# CONFIG_FENCE_TRACE is not set
++CONFIG_DMA_CMA=y
++
++#
++# Default contiguous memory area size:
++#
++CONFIG_CMA_SIZE_MBYTES=16
++CONFIG_CMA_SIZE_SEL_MBYTES=y
++# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set
++# CONFIG_CMA_SIZE_SEL_MIN is not set
++# CONFIG_CMA_SIZE_SEL_MAX is not set
++CONFIG_CMA_ALIGNMENT=8
++
++#
++# Bus devices
++#
++# CONFIG_BRCMSTB_GISB_ARB is not set
++CONFIG_ARM_CCI=y
++# CONFIG_VEXPRESS_CONFIG 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=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_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_HIFMC is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++# CONFIG_MTD_CFI is not set
++# CONFIG_MTD_JEDECPROBE is not set
++CONFIG_MTD_MAP_BANK_WIDTH_1=y
++CONFIG_MTD_MAP_BANK_WIDTH_2=y
++CONFIG_MTD_MAP_BANK_WIDTH_4=y
++# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
++CONFIG_MTD_CFI_I1=y
++CONFIG_MTD_CFI_I2=y
++# CONFIG_MTD_CFI_I4 is not set
++# CONFIG_MTD_CFI_I8 is not set
++# CONFIG_MTD_RAM is not set
++# CONFIG_MTD_ROM is not set
++# CONFIG_MTD_ABSENT is not set
++
++#
++# Mapping drivers for chip access
++#
++# CONFIG_MTD_COMPLEX_MAPPINGS is not set
++# CONFIG_MTD_PLATRAM is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_DATAFLASH is not set
++# CONFIG_MTD_M25P80 is not set
++# CONFIG_MTD_SST25L is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_PHRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++# CONFIG_MTD_BLOCK2MTD is not set
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOCG3 is not set
++# CONFIG_MTD_NAND_IDS is not set
++# CONFIG_MTD_NAND is not set
++# CONFIG_MTD_ONENAND is not set
++
++#
++# LPDDR & LPDDR2 PCM memory drivers
++#
++# CONFIG_MTD_LPDDR is not set
++# CONFIG_MTD_LPDDR2_NVM is not set
++CONFIG_MTD_SPI_NOR=y
++# CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set
++CONFIG_SPI_HISI_SFC=y
++CONFIG_CLOSE_SPI_8PIN_4IO=y
++CONFIG_HISI_SPI_BLOCK_PROTECT=y
++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_MTD_UBI_BLOCK is not set
++CONFIG_DTC=y
++CONFIG_OF=y
++
++#
++# Device Tree and Open Firmware support
++#
++# 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_NET=y
++CONFIG_OF_MDIO=y
++CONFIG_OF_MTD=y
++CONFIG_OF_RESERVED_MEM=y
++CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
++# CONFIG_PARPORT is not set
++CONFIG_BLK_DEV=y
++# CONFIG_BLK_DEV_NULL_BLK is not set
++# CONFIG_BLK_DEV_COW_COMMON is not set
++# CONFIG_BLK_DEV_LOOP 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=65536
++# CONFIG_BLK_DEV_XIP is not set
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH 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_DUMMY_IRQ 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_UID_STAT is not set
++# CONFIG_BMP085_I2C is not set
++# CONFIG_BMP085_SPI is not set
++# CONFIG_USB_SWITCH_FSA9480 is not set
++# CONFIG_LATTICE_ECP3_CONFIG is not set
++# CONFIG_SRAM is not set
++# CONFIG_C2PORT is not set
++
++#
++# EEPROM support
++#
++# CONFIG_EEPROM_AT24 is not set
++# CONFIG_EEPROM_AT25 is not set
++# CONFIG_EEPROM_LEGACY is not set
++# CONFIG_EEPROM_MAX6875 is not set
++# CONFIG_EEPROM_93CX6 is not set
++# CONFIG_EEPROM_93XX46 is not set
++
++#
++# Texas Instruments shared transport line discipline
++#
++# 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
++
++#
++# Intel MIC Bus Driver
++#
++
++#
++# Intel MIC Host Driver
++#
++
++#
++# Intel MIC Card Driver
++#
++# CONFIG_ECHO is not set
++# CONFIG_CXL_BASE is not set
++
++#
++# hisi 'himm/himd.l/himc'support
++#
++# CONFIG_HISI_REG 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_NETLINK is not set
++# CONFIG_SCSI_MQ_DEFAULT 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_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 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_NET_CORE=y
++# CONFIG_BONDING is not set
++# CONFIG_DUMMY is not set
++# CONFIG_EQUALIZER is not set
++# CONFIG_NET_TEAM is not set
++# CONFIG_MACVLAN is not set
++# CONFIG_VXLAN is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_TUN is not set
++# CONFIG_VETH is not set
++# CONFIG_NLMON is not set
++
++#
++# 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_NET_DSA_MV88E6171 is not set
++# CONFIG_NET_DSA_BCM_SF2 is not set
++# CONFIG_ETHERNET is not set
++CONFIG_PHYLIB=y
++
++#
++# MII PHY device drivers
++#
++# CONFIG_AT803X_PHY is not set
++# CONFIG_AMD_PHY is not set
++# CONFIG_AMD_XGBE_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 is not set
++# CONFIG_BROADCOM_PHY is not set
++# CONFIG_BCM7XXX_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_MMIOREG is not set
++# CONFIG_MDIO_BCM_UNIMAC is not set
++# CONFIG_MDIO_HISI_FEMAC is not set
++# CONFIG_MDIO_HISI_GEMAC is not set
++# CONFIG_MICREL_KS8995MA is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++
++#
++# Host-side USB support is needed for USB Network Adapter support
++#
++CONFIG_USB_NET_DRIVERS=m
++# 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_RTL8152 is not set
++# CONFIG_USB_USBNET is not set
++# CONFIG_USB_IPHETH is not set
++CONFIG_WLAN=y
++# CONFIG_WIFI_CONTROL_FUNC is not set
++# 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 is not set
++# CONFIG_INPUT_SPARSEKMAP is not set
++# CONFIG_INPUT_MATRIXKMAP is not set
++
++#
++# Userland interfaces
++#
++# CONFIG_INPUT_MOUSEDEV is not set
++# CONFIG_INPUT_JOYDEV is not set
++CONFIG_INPUT_EVDEV=y
++# CONFIG_INPUT_EVBUG is not set
++# CONFIG_INPUT_KEYRESET is not set
++# CONFIG_INPUT_KEYCOMBO is not set
++
++#
++# Input Device Drivers
++#
++# CONFIG_INPUT_KEYBOARD is not set
++# CONFIG_INPUT_MOUSE is not set
++# CONFIG_INPUT_JOYSTICK is not set
++# CONFIG_INPUT_TABLET is not set
++# CONFIG_INPUT_TOUCHSCREEN is not set
++# CONFIG_INPUT_MISC is not set
++
++#
++# Hardware I/O ports
++#
++# CONFIG_SERIO is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++CONFIG_TTY=y
++CONFIG_VT=y
++CONFIG_CONSOLE_TRANSLATIONS=y
++CONFIG_VT_CONSOLE=y
++CONFIG_VT_CONSOLE_SLEEP=y
++CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
++CONFIG_UNIX98_PTYS=y
++# CONFIG_DEVPTS_MULTIPLE_INSTANCES 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_DEVMEM=y
++CONFIG_DEVKMEM=y
++
++#
++# Serial drivers
++#
++CONFIG_SERIAL_EARLYCON=y
++# CONFIG_SERIAL_8250 is not set
++
++#
++# Non-8250 serial port support
++#
++# CONFIG_SERIAL_AMBA_PL010 is not set
++CONFIG_SERIAL_AMBA_PL011=y
++CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
++# CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST is not set
++# 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_SC16IS7XX is not set
++# CONFIG_SERIAL_ALTERA_JTAGUART is not set
++# CONFIG_SERIAL_ALTERA_UART is not set
++# CONFIG_SERIAL_XILINX_PS_UART is not set
++# CONFIG_SERIAL_ARC is not set
++# CONFIG_SERIAL_FSL_LPUART is not set
++# CONFIG_SERIAL_ST_ASC is not set
++# CONFIG_TTY_PRINTK is not set
++# CONFIG_HVC_DCC is not set
++# CONFIG_IPMI_HANDLER is not set
++CONFIG_HW_RANDOM=y
++# CONFIG_HW_RANDOM_TIMERIOMEM is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++# CONFIG_DCC_TTY is not set
++# CONFIG_XILLYBUS is not set
++
++#
++# I2C support
++#
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++# CONFIG_I2C_COMPAT is not set
++CONFIG_I2C_CHARDEV=y
++CONFIG_I2C_MUX=m
++
++#
++# Multiplexer I2C Chip support
++#
++# CONFIG_I2C_MUX_PCA9541 is not set
++# CONFIG_I2C_HELPER_AUTO is not set
++# CONFIG_I2C_SMBUS is not set
++
++#
++# I2C Algorithms
++#
++# CONFIG_I2C_ALGOBIT is not set
++# CONFIG_I2C_ALGOPCF is not set
++# CONFIG_I2C_ALGOPCA is not set
++
++#
++# I2C Hardware Bus support
++#
++
++#
++# I2C system bus drivers (mostly embedded / system-on-chip)
++#
++# CONFIG_I2C_DESIGNWARE_PLATFORM is not set
++# CONFIG_I2C_HIBVT is not set
++CONFIG_I2C_HISI_V110=y
++# CONFIG_I2C_NOMADIK 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_RK3X 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_ROBOTFUZZ_OSIF 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_CADENCE is not set
++# CONFIG_SPI_FSL_SPI is not set
++CONFIG_SPI_PL022=y
++# CONFIG_SPI_PXA2XX_PCI is not set
++# CONFIG_SPI_ROCKCHIP 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=y
++# CONFIG_SPI_TLE62X0 is not set
++# CONFIG_SPMI is not set
++# CONFIG_HSI is not set
++
++#
++# PPS support
++#
++# CONFIG_PPS is not set
++
++#
++# PPS generators support
++#
++
++#
++# PTP clock support
++#
++# CONFIG_PTP_1588_CLOCK is not set
++
++#
++# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
++#
++CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
++CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
++# CONFIG_GPIOLIB is not set
++# CONFIG_W1 is not set
++CONFIG_POWER_SUPPLY=y
++# CONFIG_POWER_SUPPLY_DEBUG is not set
++# CONFIG_PDA_POWER is not set
++# CONFIG_TEST_POWER is not set
++# CONFIG_BATTERY_DS2780 is not set
++# CONFIG_BATTERY_DS2781 is not set
++# CONFIG_BATTERY_DS2782 is not set
++# CONFIG_BATTERY_SBS is not set
++# CONFIG_BATTERY_BQ27x00 is not set
++# CONFIG_BATTERY_MAX17040 is not set
++# CONFIG_BATTERY_MAX17042 is not set
++# CONFIG_CHARGER_MAX8903 is not set
++# CONFIG_CHARGER_LP8727 is not set
++# CONFIG_CHARGER_BQ2415X is not set
++# CONFIG_CHARGER_SMB347 is not set
++CONFIG_POWER_RESET=y
++# CONFIG_POWER_RESET_BRCMSTB is not set
++CONFIG_POWER_RESET_HISI=y
++# CONFIG_POWER_RESET_RESTART is not set
++# CONFIG_POWER_RESET_VERSATILE is not set
++# CONFIG_POWER_RESET_SYSCON is not set
++# CONFIG_POWER_AVS is not set
++# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
++# CONFIG_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=y
++# CONFIG_MFD_AS3711 is not set
++# CONFIG_MFD_AS3722 is not set
++# CONFIG_PMIC_ADP5520 is not set
++# CONFIG_MFD_BCM590XX is not set
++# CONFIG_MFD_AXP20X is not set
++# CONFIG_MFD_CROS_EC is not set
++# CONFIG_PMIC_DA903X is not set
++# CONFIG_MFD_DA9052_SPI is not set
++# CONFIG_MFD_DA9052_I2C is not set
++# CONFIG_MFD_DA9055 is not set
++# CONFIG_MFD_DA9063 is not set
++# CONFIG_MFD_MC13XXX_SPI is not set
++# CONFIG_MFD_MC13XXX_I2C is not set
++# CONFIG_MFD_HI6421_PMIC is not set
++CONFIG_MFD_HISI_FMC=y
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_INTEL_SOC_PMIC is not set
++# CONFIG_MFD_KEMPLD is not set
++# CONFIG_MFD_88PM800 is not set
++# CONFIG_MFD_88PM805 is not set
++# CONFIG_MFD_88PM860X is not set
++# CONFIG_MFD_MAX14577 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_MENF21BMC is not set
++# CONFIG_EZX_PCAP is not set
++# CONFIG_MFD_VIPERBOARD is not set
++# CONFIG_MFD_RETU is not set
++# CONFIG_MFD_PCF50633 is not set
++# CONFIG_MFD_PM8921_CORE is not set
++# CONFIG_MFD_RTSX_USB is not set
++# CONFIG_MFD_RC5T583 is not set
++# CONFIG_MFD_RK808 is not set
++# CONFIG_MFD_RN5T618 is not set
++# CONFIG_MFD_SEC_CORE is not set
++# CONFIG_MFD_SI476X_CORE is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_MFD_SMSC is not set
++# CONFIG_ABX500_CORE is not set
++# CONFIG_MFD_STMPE is not set
++CONFIG_MFD_SYSCON=y
++# CONFIG_MFD_TI_AM335X_TSCADC is not set
++# CONFIG_MFD_LP3943 is not set
++# CONFIG_MFD_LP8788 is not set
++# CONFIG_MFD_PALMAS is not set
++# CONFIG_TPS6105X is not set
++# CONFIG_TPS6507X is not set
++# CONFIG_MFD_TPS65090 is not set
++# CONFIG_MFD_TPS65217 is not set
++# CONFIG_MFD_TPS65218 is not set
++# CONFIG_MFD_TPS6586X is not set
++# CONFIG_MFD_TPS80031 is not set
++# CONFIG_TWL4030_CORE is not set
++# CONFIG_TWL6040_CORE is not set
++# CONFIG_MFD_WL1273_CORE is not set
++# CONFIG_MFD_LM3533 is not set
++# CONFIG_MFD_TC3589X is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_MFD_T7L66XB is not set
++# CONFIG_MFD_TC6387XB is not set
++# CONFIG_MFD_TC6393XB is not set
++# CONFIG_MFD_ARIZONA_I2C is not set
++# CONFIG_MFD_ARIZONA_SPI is not set
++# CONFIG_MFD_WM8400 is not set
++# CONFIG_MFD_WM831X_I2C is not set
++# CONFIG_MFD_WM831X_SPI is not set
++# CONFIG_MFD_WM8350_I2C is not set
++# CONFIG_MFD_WM8994 is not set
++CONFIG_REGULATOR=y
++# CONFIG_REGULATOR_DEBUG is not set
++# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
++# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
++# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
++# CONFIG_REGULATOR_ACT8865 is not set
++# CONFIG_REGULATOR_AD5398 is not set
++# CONFIG_REGULATOR_ANATOP is not set
++# CONFIG_REGULATOR_DA9210 is not set
++# CONFIG_REGULATOR_DA9211 is not set
++# CONFIG_REGULATOR_FAN53555 is not set
++# CONFIG_REGULATOR_ISL9305 is not set
++# CONFIG_REGULATOR_ISL6271A is not set
++# CONFIG_REGULATOR_LP3971 is not set
++# CONFIG_REGULATOR_LP3972 is not set
++# CONFIG_REGULATOR_LP872X is not set
++# CONFIG_REGULATOR_LP8755 is not set
++# CONFIG_REGULATOR_LTC3589 is not set
++# CONFIG_REGULATOR_MAX1586 is not set
++# CONFIG_REGULATOR_MAX8649 is not set
++# CONFIG_REGULATOR_MAX8660 is not set
++# CONFIG_REGULATOR_MAX8952 is not set
++# CONFIG_REGULATOR_MAX8973 is not set
++# CONFIG_REGULATOR_PFUZE100 is not set
++# CONFIG_REGULATOR_TPS51632 is not set
++# CONFIG_REGULATOR_TPS62360 is not set
++# CONFIG_REGULATOR_TPS65023 is not set
++# CONFIG_REGULATOR_TPS6507X is not set
++# CONFIG_REGULATOR_TPS6524X is not set
++CONFIG_MEDIA_SUPPORT=m
++
++#
++# Multimedia core support
++#
++CONFIG_MEDIA_CAMERA_SUPPORT=y
++# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set
++# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set
++# CONFIG_MEDIA_RADIO_SUPPORT is not set
++# CONFIG_MEDIA_SDR_SUPPORT is not set
++# CONFIG_MEDIA_RC_SUPPORT is not set
++# CONFIG_MEDIA_CONTROLLER is not set
++CONFIG_VIDEO_DEV=m
++CONFIG_VIDEO_V4L2=m
++# CONFIG_VIDEO_ADV_DEBUG is not set
++# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
++CONFIG_VIDEOBUF2_CORE=m
++CONFIG_VIDEOBUF2_MEMOPS=m
++CONFIG_VIDEOBUF2_VMALLOC=m
++# CONFIG_TTPCI_EEPROM is not set
++
++#
++# Media drivers
++#
++# CONFIG_MEDIA_USB_SUPPORT is not set
++# CONFIG_V4L_PLATFORM_DRIVERS is not set
++# CONFIG_V4L_MEM2MEM_DRIVERS is not set
++# CONFIG_V4L_TEST_DRIVERS is not set
++
++#
++# Supported MMC/SDIO adapters
++#
++# CONFIG_CYPRESS_FIRMWARE is not set
++
++#
++# Media ancillary drivers (tuners, sensors, i2c, frontends)
++#
++CONFIG_MEDIA_SUBDRV_AUTOSELECT=y
++
++#
++# Audio decoders, processors and mixers
++#
++
++#
++# RDS decoders
++#
++
++#
++# Video decoders
++#
++
++#
++# Video and audio decoders
++#
++
++#
++# Video encoders
++#
++
++#
++# Camera sensor devices
++#
++
++#
++# Flash devices
++#
++
++#
++# Video improvement chips
++#
++
++#
++# Audio/Video compression chips
++#
++
++#
++# Miscellaneous helper chips
++#
++
++#
++# Sensors used on soc_camera driver
++#
++
++#
++# Tools to develop new frontends
++#
++# CONFIG_DVB_DUMMY_FE is not set
++
++#
++# Graphics support
++#
++# CONFIG_IMX_IPUV3_CORE is not set
++
++#
++# Direct Rendering Manager
++#
++# CONFIG_DRM is not set
++
++#
++# Frame buffer Devices
++#
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++CONFIG_FB_CMDLINE=y
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++# CONFIG_FB_CFB_FILLRECT is not set
++# CONFIG_FB_CFB_COPYAREA is not set
++# CONFIG_FB_CFB_IMAGEBLIT is not set
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# 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_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_ARMCLCD is not set
++# CONFIG_FB_OPENCORES is not set
++# CONFIG_FB_S1D13XXX is not set
++# CONFIG_FB_SMSCUFX is not set
++# CONFIG_FB_UDL is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_BROADSHEET is not set
++# CONFIG_FB_AUO_K190X is not set
++# CONFIG_FB_SIMPLE is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++# CONFIG_VGASTATE is not set
++
++#
++# Console display driver support
++#
++CONFIG_DUMMY_CONSOLE=y
++# CONFIG_FRAMEBUFFER_CONSOLE is not set
++# CONFIG_LOGO is not set
++# CONFIG_SOUND is not set
++
++#
++# HID support
++#
++CONFIG_HID=y
++# CONFIG_HID_BATTERY_STRENGTH is not set
++# CONFIG_HIDRAW is not set
++# CONFIG_UHID is not set
++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_APPLEIR 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_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_ELO is not set
++# CONFIG_HID_EZKEY is not set
++# CONFIG_HID_HOLTEK is not set
++# CONFIG_HID_HUION 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_ICADE is not set
++# CONFIG_HID_TWINHAN is not set
++# CONFIG_HID_KENSINGTON is not set
++# CONFIG_HID_LCPOWER is not set
++# CONFIG_HID_LENOVO is not set
++# 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_PENMOUNT is not set
++# CONFIG_HID_PETALYNX is not set
++# CONFIG_HID_PICOLCD is not set
++# CONFIG_HID_PRIMAX is not set
++# CONFIG_HID_ROCCAT is not set
++# CONFIG_HID_SAITEK is not set
++# CONFIG_HID_SAMSUNG is not set
++# CONFIG_HID_SPEEDLINK is not set
++# CONFIG_HID_STEELSERIES is not set
++# CONFIG_HID_SUNPLUS is not set
++# CONFIG_HID_RMI 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_XINMO is not set
++# CONFIG_HID_ZEROPLUS is not set
++# CONFIG_HID_ZYDACRON is not set
++# CONFIG_HID_SENSOR_HUB is not set
++
++#
++# USB HID support
++#
++CONFIG_USB_HID=m
++# CONFIG_HID_PID is not set
++# CONFIG_USB_HIDDEV is not set
++
++#
++# USB HID Boot Protocol drivers
++#
++# CONFIG_USB_KBD is not set
++# CONFIG_USB_MOUSE is not set
++
++#
++# I2C HID support
++#
++# CONFIG_I2C_HID is not set
++CONFIG_USB_OHCI_LITTLE_ENDIAN=y
++CONFIG_USB_SUPPORT=y
++CONFIG_USB_COMMON=y
++CONFIG_USB_ARCH_HAS_HCD=y
++CONFIG_USB=m
++# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
++
++#
++# Miscellaneous USB options
++#
++# CONFIG_USB_DEFAULT_PERSIST is not set
++# CONFIG_USB_DYNAMIC_MINORS is not set
++# CONFIG_USB_OTG_WHITELIST is not set
++# CONFIG_USB_OTG_BLACKLIST_HUB is not set
++# CONFIG_USB_OTG_FSM is not set
++# CONFIG_USB_MON is not set
++# CONFIG_USB_WUSB_CBAF is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_C67X00_HCD is not set
++# CONFIG_USB_XHCI_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_FUSBH200_HCD is not set
++# CONFIG_USB_FOTG210_HCD is not set
++# CONFIG_USB_MAX3421_HCD is not set
++# CONFIG_USB_OHCI_HCD is not set
++# CONFIG_USB_SL811_HCD is not set
++# CONFIG_USB_R8A66597_HCD is not set
++# CONFIG_USB_HCD_TEST_MODE is not set
++
++#
++# USB Device Class drivers
++#
++# CONFIG_USB_ACM is not set
++# CONFIG_USB_PRINTER is not set
++# CONFIG_USB_WDM is not set
++# CONFIG_USB_TMC is not set
++
++#
++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
++#
++
++#
++# also be needed; see USB_STORAGE Help for more info
++#
++# CONFIG_USB_STORAGE is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++# CONFIG_USBIP_CORE is not set
++# CONFIG_USB_MUSB_HDRC is not set
++# CONFIG_USB_DWC3 is not set
++# CONFIG_USB_DWC2 is not set
++# CONFIG_USB_CHIPIDEA is not set
++
++#
++# USB port drivers
++#
++# CONFIG_USB_SERIAL is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
++# CONFIG_USB_SEVSEG is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
++# CONFIG_USB_APPLEDISPLAY is not set
++# CONFIG_USB_LD is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
++# CONFIG_USB_IOWARRIOR is not set
++# CONFIG_USB_TEST is not set
++# CONFIG_USB_EHSET_TEST_FIXTURE is not set
++# CONFIG_USB_ISIGHTFW is not set
++# CONFIG_USB_YUREX is not set
++# CONFIG_USB_EZUSB_FX2 is not set
++# CONFIG_USB_HSIC_USB3503 is not set
++# CONFIG_USB_LINK_LAYER_TEST is not set
++
++#
++# USB Physical Layer drivers
++#
++# CONFIG_USB_PHY is not set
++# CONFIG_NOP_USB_XCEIV is not set
++# CONFIG_AM335X_PHY_USB is not set
++# CONFIG_USB_ISP1301 is not set
++# CONFIG_USB_ULPI is not set
++CONFIG_USB_GADGET=y
++# CONFIG_USB_GADGET_DEBUG is not set
++# CONFIG_USB_GADGET_DEBUG_FILES is not set
++CONFIG_USB_GADGET_VBUS_DRAW=2
++CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2
++
++#
++# USB Peripheral Controller
++#
++# CONFIG_USB_FUSB300 is not set
++# CONFIG_USB_FOTG210_UDC is not set
++# CONFIG_USB_GR_UDC is not set
++# CONFIG_USB_R8A66597 is not set
++# CONFIG_USB_PXA27X is not set
++# CONFIG_USB_MV_UDC is not set
++CONFIG_HIUSB_DEVICE2_0=y
++CONFIG_USB_HISI_UDC=m
++# CONFIG_USB_AUTO_SWITCH is not set
++# CONFIG_HIUSB_DEVICE3_0 is not set
++# CONFIG_USB_MV_U3D is not set
++# CONFIG_USB_M66592 is not set
++# CONFIG_USB_NET2272 is not set
++# CONFIG_USB_GADGET_XILINX is not set
++CONFIG_USB_LIBCOMPOSITE=m
++CONFIG_USB_F_ACM=m
++CONFIG_USB_U_SERIAL=m
++CONFIG_USB_U_ETHER=m
++CONFIG_USB_F_RNDIS=m
++CONFIG_USB_F_MASS_STORAGE=m
++CONFIG_USB_F_UAC1=m
++CONFIG_USB_F_UVC=m
++# CONFIG_USB_CONFIGFS is not set
++# CONFIG_USB_ZERO is not set
++CONFIG_USB_AUDIO=m
++CONFIG_GADGET_UAC1=y
++# CONFIG_USB_ETH is not set
++# CONFIG_USB_G_NCM is not set
++# CONFIG_USB_GADGETFS is not set
++# CONFIG_USB_FUNCTIONFS is not set
++CONFIG_USB_MASS_STORAGE=m
++# CONFIG_USB_G_SERIAL is not set
++# CONFIG_USB_G_PRINTER is not set
++# CONFIG_USB_CDC_COMPOSITE is not set
++# CONFIG_USB_G_ACM_MS is not set
++CONFIG_USB_G_MULTI=m
++CONFIG_USB_G_MULTI_RNDIS=y
++# CONFIG_USB_G_MULTI_CDC is not set
++# CONFIG_USB_G_HID is not set
++# CONFIG_USB_G_DBGP is not set
++# CONFIG_USB_G_WEBCAM is not set
++CONFIG_USB_G_WEBCAM_AUDIO=m
++# CONFIG_UWB is not set
++CONFIG_MMC=m
++# CONFIG_MMC_DEBUG is not set
++# CONFIG_MMC_CLKGATE is not set
++CONFIG_MMC_EMBEDDED_SDIO=y
++# CONFIG_MMC_PARANOID_SD_INIT is not set
++
++#
++# MMC/SD/SDIO Card Drivers
++#
++CONFIG_MMC_BLOCK=m
++CONFIG_MMC_BLOCK_MINORS=8
++CONFIG_MMC_BLOCK_BOUNCE=y
++# CONFIG_MMC_BLOCK_DEFERRED_RESUME is not set
++# CONFIG_SDIO_UART is not set
++# CONFIG_MMC_TEST is not set
++
++#
++# MMC/SD/SDIO Host Controller Drivers
++#
++# CONFIG_MMC_ARMMMCI is not set
++# CONFIG_MMC_SDHCI is not set
++# CONFIG_MMC_DW is not set
++# CONFIG_MMC_VUB300 is not set
++# CONFIG_MMC_USHC is not set
++# CONFIG_MMC_USDHI6ROL0 is not set
++CONFIG_HIMCIV200=m
++CONFIG_SEND_AUTO_STOP=y
++CONFIG_DETECT_CARD_TIME=200
++# CONFIG_MEMSTICK is not set
++# CONFIG_NEW_LEDS is not set
++# CONFIG_SWITCH is not set
++# CONFIG_ACCESSIBILITY is not set
++# CONFIG_EDAC is not set
++CONFIG_RTC_LIB=y
++# CONFIG_RTC_CLASS is not set
++# CONFIG_DMADEVICES is not set
++# CONFIG_AUXDISPLAY is not set
++# CONFIG_UIO is not set
++# CONFIG_VIRT_DRIVERS is not set
++
++#
++# Virtio drivers
++#
++# CONFIG_VIRTIO_MMIO is not set
++
++#
++# Microsoft Hyper-V guest support
++#
++# CONFIG_STAGING is not set
++
++#
++# SOC (System On Chip) specific Drivers
++#
++# CONFIG_SOC_TI is not set
++CONFIG_CLKDEV_LOOKUP=y
++CONFIG_HAVE_CLK_PREPARE=y
++CONFIG_COMMON_CLK=y
++
++#
++# Common Clock Framework
++#
++# CONFIG_COMMON_CLK_SI5351 is not set
++# CONFIG_COMMON_CLK_SI570 is not set
++# CONFIG_COMMON_CLK_PXA is not set
++# CONFIG_COMMON_CLK_QCOM is not set
++
++#
++# Hardware Spinlock drivers
++#
++
++#
++# Clock Source drivers
++#
++CONFIG_CLKSRC_OF=y
++CONFIG_CLKSRC_MMIO=y
++CONFIG_ARM_ARCH_TIMER=y
++CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y
++# CONFIG_ARM_ARCH_TIMER_VCT_ACCESS is not set
++# CONFIG_ATMEL_PIT is not set
++# CONFIG_SH_TIMER_CMT is not set
++# CONFIG_SH_TIMER_MTU2 is not set
++# CONFIG_SH_TIMER_TMU is not set
++# CONFIG_EM_TIMER_STI is not set
++# CONFIG_CLKSRC_VERSATILE is not set
++# CONFIG_MAILBOX is not set
++# CONFIG_IOMMU_SUPPORT is not set
++
++#
++# Remoteproc drivers
++#
++# CONFIG_STE_MODEM_RPROC is not set
++
++#
++# Rpmsg drivers
++#
++
++#
++# SOC (System On Chip) specific Drivers
++#
++# 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
++CONFIG_IRQCHIP=y
++CONFIG_ARM_GIC=y
++# CONFIG_IPACK_BUS is not set
++CONFIG_ARCH_HAS_RESET_CONTROLLER=y
++CONFIG_RESET_CONTROLLER=y
++# CONFIG_FMC is not set
++
++#
++# PHY Subsystem
++#
++CONFIG_GENERIC_PHY=y
++# CONFIG_BCM_KONA_USB2_PHY is not set
++CONFIG_PHY_HISI_INNO_USB2=m
++# CONFIG_POWERCAP is not set
++# CONFIG_MCB is not set
++# CONFIG_HI_DMAC is not set
++
++#
++# Hisilicon driver support
++#
++# CONFIG_CMA_MEM_SHARED is not set
++# CONFIG_CMA_ADVANCE_SHARE is not set
++
++#
++# File systems
++#
++CONFIG_DCACHE_WORD_ACCESS=y
++# CONFIG_EXT2_FS is not set
++# CONFIG_EXT3_FS is not set
++# CONFIG_EXT4_FS is not set
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_BTRFS_FS is not set
++# CONFIG_NILFS2_FS is not set
++CONFIG_FS_POSIX_ACL=y
++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 is not set
++# CONFIG_FUSE_FS is not set
++# CONFIG_OVERLAY_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_KERNFS=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=m
++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_YAFFS_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 is not set
++# CONFIG_JFFS2_FS_XATTR is not set
++# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
++CONFIG_JFFS2_ZLIB=y
++# CONFIG_JFFS2_LZO is not set
++CONFIG_JFFS2_RTIME=y
++# CONFIG_JFFS2_RUBIN 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 is not set
++CONFIG_SQUASHFS=y
++CONFIG_SQUASHFS_FILE_CACHE=y
++# CONFIG_SQUASHFS_FILE_DIRECT is not set
++CONFIG_SQUASHFS_DECOMP_SINGLE=y
++# CONFIG_SQUASHFS_DECOMP_MULTI is not set
++# CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU is not set
++# CONFIG_SQUASHFS_XATTR is not set
++CONFIG_SQUASHFS_ZLIB=y
++CONFIG_SQUASHFS_LZO=y
++# CONFIG_SQUASHFS_XZ is not set
++# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set
++# CONFIG_SQUASHFS_EMBEDDED is not set
++CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
++# CONFIG_VXFS_FS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_OMFS_FS is not set
++# CONFIG_HPFS_FS is not set
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_QNX6FS_FS is not set
++# CONFIG_ROMFS_FS is not set
++# CONFIG_PSTORE is not set
++# CONFIG_SYSV_FS is not set
++# CONFIG_UFS_FS is not set
++# CONFIG_F2FS_FS is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V2=y
++CONFIG_NFS_V3=y
++CONFIG_NFS_V3_ACL=y
++# CONFIG_NFS_V4 is not set
++# CONFIG_NFS_SWAP is not set
++# CONFIG_ROOT_NFS is not set
++# CONFIG_NFSD is not set
++CONFIG_GRACE_PERIOD=y
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_ACL_SUPPORT=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 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=y
++# CONFIG_DLM is not set
++
++#
++# Kernel hacking
++#
++
++#
++# printk and dmesg options
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4
++# CONFIG_BOOT_PRINTK_DELAY is not set
++
++#
++# Compile-time checks and compiler options
++#
++# CONFIG_DEBUG_INFO is not set
++# CONFIG_ENABLE_WARN_DEPRECATED is not set
++# CONFIG_ENABLE_MUST_CHECK is not set
++CONFIG_FRAME_WARN=1024
++# CONFIG_STRIP_ASM_SYMS is not set
++# CONFIG_READABLE_ASM is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++# CONFIG_DEBUG_FS is not set
++# CONFIG_HEADERS_CHECK is not set
++# CONFIG_DEBUG_SECTION_MISMATCH is not set
++# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
++# CONFIG_MAGIC_SYSRQ is not set
++CONFIG_DEBUG_KERNEL=y
++
++#
++# Memory Debugging
++#
++# CONFIG_DEBUG_PAGEALLOC is not set
++# CONFIG_DEBUG_OBJECTS is not set
++# CONFIG_SLUB_STATS is not set
++CONFIG_HAVE_DEBUG_KMEMLEAK=y
++# CONFIG_DEBUG_KMEMLEAK is not set
++# CONFIG_DEBUG_STACK_USAGE is not set
++# CONFIG_DEBUG_VM is not set
++CONFIG_DEBUG_MEMORY_INIT=y
++# CONFIG_DEBUG_HIGHMEM is not set
++# CONFIG_DEBUG_SHIRQ is not set
++
++#
++# Debug Lockups and Hangs
++#
++# CONFIG_LOCKUP_DETECTOR is not set
++# CONFIG_DETECT_HUNG_TASK is not set
++CONFIG_PANIC_ON_OOPS=y
++CONFIG_PANIC_ON_OOPS_VALUE=1
++CONFIG_PANIC_TIMEOUT=0
++CONFIG_SCHED_DEBUG=y
++# CONFIG_SCHEDSTATS is not set
++# CONFIG_SCHED_STACK_END_CHECK is not set
++# CONFIG_TIMER_STATS is not set
++
++#
++# Lock Debugging (spinlocks, mutexes, etc...)
++#
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_LOCK_STAT is not set
++# CONFIG_DEBUG_ATOMIC_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_LOCK_TORTURE_TEST is not set
++CONFIG_STACKTRACE=y
++# CONFIG_DEBUG_KOBJECT is not set
++CONFIG_DEBUG_BUGVERBOSE=y
++# CONFIG_DEBUG_LIST is not set
++# CONFIG_DEBUG_PI_LIST is not set
++# CONFIG_DEBUG_SG is not set
++# CONFIG_DEBUG_NOTIFIERS is not set
++# CONFIG_DEBUG_CREDENTIALS is not set
++
++#
++# RCU Debugging
++#
++# CONFIG_SPARSE_RCU_POINTER is not set
++# CONFIG_TORTURE_TEST is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_RCU_TRACE is not set
++# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_NOTIFIER_ERROR_INJECTION is not set
++# CONFIG_FAULT_INJECTION is not set
++# CONFIG_LATENCYTOP 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 is not set
++
++#
++# Runtime Testing
++#
++# CONFIG_TEST_LIST_SORT is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_RBTREE_TEST is not set
++# CONFIG_INTERVAL_TREE_TEST is not set
++# CONFIG_PERCPU_TEST is not set
++# CONFIG_ATOMIC64_SELFTEST is not set
++# CONFIG_TEST_STRING_HELPERS is not set
++# CONFIG_TEST_KSTRTOX is not set
++# CONFIG_TEST_RHASHTABLE is not set
++# CONFIG_DMA_API_DEBUG is not set
++# CONFIG_TEST_LKM is not set
++# CONFIG_TEST_USER_COPY is not set
++# CONFIG_TEST_BPF is not set
++# CONFIG_TEST_FIRMWARE is not set
++# CONFIG_TEST_UDELAY is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_KGDB is not set
++# CONFIG_ARM_PTDUMP is not set
++CONFIG_STRICT_DEVMEM=y
++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_DEBUG_UART_PL01X is not set
++# CONFIG_DEBUG_UART_8250 is not set
++# CONFIG_DEBUG_UART_BCM63XX is not set
++CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"
++# CONFIG_OC_ETM is not set
++# CONFIG_PID_IN_CONTEXTIDR is not set
++# CONFIG_DEBUG_SET_MODULE_RONX is not set
++# CONFIG_CORESIGHT is not set
++
++#
++# 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_AEAD=y
++CONFIG_CRYPTO_AEAD2=y
++CONFIG_CRYPTO_BLKCIPHER=y
++CONFIG_CRYPTO_BLKCIPHER2=y
++CONFIG_CRYPTO_HASH=y
++CONFIG_CRYPTO_HASH2=y
++CONFIG_CRYPTO_RNG=y
++CONFIG_CRYPTO_RNG2=y
++CONFIG_CRYPTO_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_WORKQUEUE=y
++# CONFIG_CRYPTO_CRYPTD is not set
++# CONFIG_CRYPTO_MCRYPTD is not set
++# CONFIG_CRYPTO_AUTHENC is not set
++# CONFIG_CRYPTO_TEST is not set
++
++#
++# Authenticated Encryption with Associated Data
++#
++CONFIG_CRYPTO_CCM=y
++# CONFIG_CRYPTO_GCM is not set
++CONFIG_CRYPTO_SEQIV=y
++
++#
++# Block modes
++#
++# CONFIG_CRYPTO_CBC is not set
++CONFIG_CRYPTO_CTR=y
++# 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_CMAC is not set
++# CONFIG_CRYPTO_HMAC is not set
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_VMAC is not set
++
++#
++# Digest
++#
++CONFIG_CRYPTO_CRC32C=y
++# CONFIG_CRYPTO_CRC32 is not set
++# CONFIG_CRYPTO_CRCT10DIF 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_SHA1_ARM_NEON is not set
++# CONFIG_CRYPTO_SHA256 is not set
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_SHA512_ARM_NEON 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_AES_ARM_BS is not set
++# CONFIG_CRYPTO_ANUBIS is not set
++CONFIG_CRYPTO_ARC4=y
++# 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=y
++# CONFIG_CRYPTO_ZLIB is not set
++CONFIG_CRYPTO_LZO=y
++# CONFIG_CRYPTO_LZ4 is not set
++# CONFIG_CRYPTO_LZ4HC is not set
++
++#
++# Random Number Generation
++#
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++# CONFIG_CRYPTO_DRBG_MENU is not set
++# CONFIG_CRYPTO_USER_API_HASH is not set
++# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
++CONFIG_CRYPTO_HW=y
++# CONFIG_BINARY_PRINTF is not set
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++CONFIG_GENERIC_STRNCPY_FROM_USER=y
++CONFIG_GENERIC_STRNLEN_USER=y
++CONFIG_GENERIC_NET_UTILS=y
++CONFIG_GENERIC_PCI_IOMAP=y
++CONFIG_GENERIC_IO=y
++CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
++# CONFIG_CRC_CCITT is not set
++CONFIG_CRC16=y
++# CONFIG_CRC_T10DIF is not set
++# 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=y
++# CONFIG_CRC8 is not set
++# CONFIG_AUDIT_ARCH_COMPAT_GENERIC is not set
++# CONFIG_RANDOM32_SELFTEST is not set
++CONFIG_ZLIB_INFLATE=y
++CONFIG_ZLIB_DEFLATE=y
++CONFIG_LZO_COMPRESS=y
++CONFIG_LZO_DECOMPRESS=y
++CONFIG_XZ_DEC=y
++CONFIG_XZ_DEC_X86=y
++CONFIG_XZ_DEC_POWERPC=y
++CONFIG_XZ_DEC_IA64=y
++CONFIG_XZ_DEC_ARM=y
++CONFIG_XZ_DEC_ARMTHUMB=y
++CONFIG_XZ_DEC_SPARC=y
++CONFIG_XZ_DEC_BCJ=y
++# CONFIG_XZ_DEC_TEST is not set
++CONFIG_GENERIC_ALLOCATOR=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT_MAP=y
++CONFIG_HAS_DMA=y
++CONFIG_DQL=y
++CONFIG_NLATTR=y
++CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
++CONFIG_AVERAGE=y
++# CONFIG_CORDIC is not set
++# CONFIG_DDR is not set
++CONFIG_LIBFDT=y
++CONFIG_ARCH_HAS_SG_CHAIN=y
++# CONFIG_VIRTUALIZATION is not set
+diff --git a/arch/arm/configs/hi3559_single_defconfig b/arch/arm/configs/hi3559_single_defconfig
+new file mode 100644
+index 0000000..0b5f028
+--- /dev/null
++++ b/arch/arm/configs/hi3559_single_defconfig
+@@ -0,0 +1,2617 @@
++#
++# Automatically generated file; DO NOT EDIT.
++# Linux/arm 3.18.20 Kernel Configuration
++#
++CONFIG_ARM=y
++CONFIG_ARM_HAS_SG_CHAIN=y
++CONFIG_MIGHT_HAVE_PCI=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=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_XCHGADD_ALGORITHM=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_NEED_DMA_MAP_STATE=y
++CONFIG_ARCH_SUPPORTS_UPROBES=y
++CONFIG_VECTORS_BASE=0xffff0000
++CONFIG_ARM_PATCH_PHYS_VIRT=y
++CONFIG_GENERIC_BUG=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++CONFIG_IRQ_WORK=y
++CONFIG_BUILDTIME_EXTABLE_SORT=y
++
++#
++# General setup
++#
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_CROSS_COMPILE=""
++# CONFIG_COMPILE_TEST is not set
++CONFIG_LOCALVERSION=""
++# CONFIG_LOCALVERSION_AUTO is not set
++CONFIG_HAVE_KERNEL_GZIP=y
++CONFIG_HAVE_KERNEL_LZMA=y
++CONFIG_HAVE_KERNEL_XZ=y
++CONFIG_HAVE_KERNEL_LZO=y
++CONFIG_HAVE_KERNEL_LZ4=y
++CONFIG_KERNEL_GZIP=y
++# CONFIG_KERNEL_LZMA is not set
++# CONFIG_KERNEL_XZ is not set
++# CONFIG_KERNEL_LZO is not set
++# CONFIG_KERNEL_LZ4 is not set
++# CONFIG_HW_DECOMPRESS is not set
++CONFIG_SOFT_DECOMPRESS=y
++CONFIG_DEFAULT_HOSTNAME="(none)"
++CONFIG_SWAP=y
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++# CONFIG_POSIX_MQUEUE is not set
++CONFIG_CROSS_MEMORY_ATTACH=y
++# CONFIG_FHANDLE is not set
++CONFIG_USELIB=y
++# CONFIG_AUDIT is not set
++CONFIG_HAVE_ARCH_AUDITSYSCALL=y
++
++#
++# IRQ subsystem
++#
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_GENERIC_IRQ_SHOW=y
++CONFIG_HARDIRQS_SW_RESEND=y
++CONFIG_IRQ_DOMAIN=y
++CONFIG_HANDLE_DOMAIN_IRQ=y
++CONFIG_IRQ_FORCED_THREADING=y
++CONFIG_SPARSE_IRQ=y
++CONFIG_GENERIC_CLOCKEVENTS=y
++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
++
++#
++# Timers subsystem
++#
++CONFIG_TICK_ONESHOT=y
++CONFIG_NO_HZ_COMMON=y
++# CONFIG_HZ_PERIODIC is not set
++CONFIG_NO_HZ_IDLE=y
++CONFIG_NO_HZ=y
++# CONFIG_HIGH_RES_TIMERS is not set
++
++#
++# CPU/Task time and stats accounting
++#
++CONFIG_TICK_CPU_ACCOUNTING=y
++# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set
++# CONFIG_IRQ_TIME_ACCOUNTING is not set
++# CONFIG_BSD_PROCESS_ACCT is not set
++# CONFIG_TASKSTATS is not set
++
++#
++# RCU Subsystem
++#
++CONFIG_TINY_RCU=y
++# CONFIG_PREEMPT_RCU is not set
++# CONFIG_TASKS_RCU is not set
++# CONFIG_RCU_STALL_COMMON is not set
++# CONFIG_TREE_RCU_TRACE is not set
++# CONFIG_BUILD_BIN2C is not set
++# CONFIG_IKCONFIG is not set
++CONFIG_LOG_BUF_SHIFT=17
++CONFIG_GENERIC_SCHED_CLOCK=y
++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_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_USER_NS is not set
++CONFIG_PID_NS=y
++CONFIG_NET_NS=y
++# 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=y
++CONFIG_RD_LZMA=y
++CONFIG_RD_XZ=y
++CONFIG_RD_LZO=y
++CONFIG_RD_LZ4=y
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++CONFIG_HAVE_UID16=y
++CONFIG_BPF=y
++# CONFIG_EXPERT is not set
++CONFIG_UID16=y
++# CONFIG_SGETMASK_SYSCALL is not set
++CONFIG_SYSFS_SYSCALL=y
++# CONFIG_SYSCTL_SYSCALL is not set
++CONFIG_KALLSYMS=y
++# CONFIG_KALLSYMS_ALL is not set
++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_BPF_SYSCALL is not set
++CONFIG_SHMEM=y
++CONFIG_AIO=y
++CONFIG_ADVISE_SYSCALLS=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 is not set
++# CONFIG_SLAB is not set
++CONFIG_SLUB=y
++# CONFIG_PROFILING is not set
++CONFIG_HAVE_OPROFILE=y
++# CONFIG_KPROBES is not set
++# CONFIG_JUMP_LABEL is not set
++# CONFIG_UPROBES is not set
++# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
++CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
++CONFIG_ARCH_USE_BUILTIN_BSWAP=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_GENERIC_SMP_IDLE_THREAD=y
++CONFIG_GENERIC_IDLE_POLL_SETUP=y
++CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
++CONFIG_HAVE_CLK=y
++CONFIG_HAVE_DMA_API_DEBUG=y
++CONFIG_HAVE_PERF_REGS=y
++CONFIG_HAVE_PERF_USER_STACK_DUMP=y
++CONFIG_HAVE_ARCH_JUMP_LABEL=y
++CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
++CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
++CONFIG_HAVE_CC_STACKPROTECTOR=y
++# CONFIG_CC_STACKPROTECTOR is not set
++CONFIG_CC_STACKPROTECTOR_NONE=y
++# CONFIG_CC_STACKPROTECTOR_REGULAR is not set
++# CONFIG_CC_STACKPROTECTOR_STRONG is not set
++CONFIG_HAVE_CONTEXT_TRACKING=y
++CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
++CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
++CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
++CONFIG_MODULES_USE_ELF_REL=y
++CONFIG_CLONE_BACKWARDS=y
++CONFIG_OLD_SIGSUSPEND3=y
++CONFIG_OLD_SIGACTION=y
++
++#
++# GCOV-based kernel profiling
++#
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_SLABINFO=y
++CONFIG_RT_MUTEXES=y
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++# CONFIG_MODULE_FORCE_LOAD is not set
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++# CONFIG_MODULE_SIG is not set
++# CONFIG_MODULE_COMPRESS is not set
++CONFIG_BLOCK=y
++CONFIG_LBDAF=y
++CONFIG_BLK_DEV_BSG=y
++# CONFIG_BLK_DEV_BSGLIB is not set
++# CONFIG_BLK_DEV_INTEGRITY is not set
++CONFIG_BLK_CMDLINE_PARSER=y
++
++#
++# Partition Types
++#
++CONFIG_PARTITION_ADVANCED=y
++# CONFIG_ACORN_PARTITION is not set
++# CONFIG_AIX_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=y
++# CONFIG_SYSV68_PARTITION is not set
++CONFIG_CMDLINE_PARTITION=y
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++CONFIG_DEFAULT_DEADLINE=y
++# CONFIG_DEFAULT_CFQ is not set
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="deadline"
++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_ARCH_SUPPORTS_ATOMIC_RMW=y
++CONFIG_FREEZER=y
++
++#
++# System Type
++#
++CONFIG_MMU=y
++CONFIG_ARCH_MULTIPLATFORM=y
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_AT91 is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_GEMINI is not set
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_IOP13XX is not set
++# CONFIG_ARCH_IOP32X is not set
++# CONFIG_ARCH_IOP33X is not set
++# CONFIG_ARCH_IXP4XX is not set
++# CONFIG_ARCH_DOVE is not set
++# CONFIG_ARCH_MV78XX0 is not set
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_MMP is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_W90X900 is not set
++# CONFIG_ARCH_LPC32XX is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_MSM is not set
++# CONFIG_ARCH_SHMOBILE_LEGACY 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_DAVINCI is not set
++# CONFIG_ARCH_OMAP1 is not set
++
++#
++# Multiple platform selection
++#
++
++#
++# CPU Core family selection
++#
++# CONFIG_ARCH_MULTI_V6 is not set
++CONFIG_ARCH_MULTI_V7=y
++CONFIG_ARCH_MULTI_V6_V7=y
++# CONFIG_ARCH_MULTI_CPU_AUTO is not set
++# CONFIG_ARCH_VIRT is not set
++# CONFIG_ARCH_MVEBU is not set
++# CONFIG_ARCH_BCM is not set
++# CONFIG_ARCH_BERLIN is not set
++# CONFIG_ARCH_HIGHBANK is not set
++CONFIG_ARCH_HISI=y
++
++#
++# Hisilicon platform type
++#
++# CONFIG_ARCH_HI3xxx is not set
++# CONFIG_ARCH_HIP04 is not set
++# CONFIG_ARCH_HIX5HD2 is not set
++# CONFIG_ARCH_HI3519 is not set
++# CONFIG_ARCH_HI3519V101 is not set
++# CONFIG_ARCH_HI3516AV200 is not set
++CONFIG_ARCH_HI3559=y
++# CONFIG_ARCH_HI3556 is not set
++# CONFIG_ARCH_HI3536C is not set
++# CONFIG_ARCH_HI3531D is not set
++# CONFIG_ARCH_HI3521D is not set
++# CONFIG_ARCH_KEYSTONE is not set
++# CONFIG_ARCH_MESON is not set
++# CONFIG_ARCH_MXC is not set
++# CONFIG_ARCH_MEDIATEK is not set
++
++#
++# TI OMAP/AM/DM/DRA Family
++#
++# CONFIG_ARCH_OMAP3 is not set
++# CONFIG_ARCH_OMAP4 is not set
++# CONFIG_SOC_OMAP5 is not set
++# CONFIG_SOC_AM33XX is not set
++# CONFIG_SOC_AM43XX is not set
++# CONFIG_SOC_DRA7XX is not set
++# CONFIG_ARCH_QCOM is not set
++# CONFIG_ARCH_ROCKCHIP is not set
++# CONFIG_ARCH_SOCFPGA is not set
++# CONFIG_PLAT_SPEAR is not set
++# CONFIG_ARCH_STI is not set
++# CONFIG_ARCH_S5PV210 is not set
++# CONFIG_ARCH_EXYNOS is not set
++# CONFIG_ARCH_SHMOBILE_MULTI is not set
++# CONFIG_ARCH_SUNXI is not set
++# CONFIG_ARCH_SIRF is not set
++# CONFIG_ARCH_TEGRA is not set
++# CONFIG_ARCH_U8500 is not set
++# CONFIG_ARCH_VEXPRESS is not set
++# CONFIG_ARCH_WM8850 is not set
++# CONFIG_ARCH_ZYNQ is not set
++CONFIG_ARM_TIMER_SP804=y
++
++#
++# Processor Type
++#
++CONFIG_CPU_V7=y
++CONFIG_CPU_32v6K=y
++CONFIG_CPU_32v7=y
++CONFIG_CPU_ABRT_EV7=y
++CONFIG_CPU_PABRT_V7=y
++CONFIG_CPU_CACHE_V7=y
++CONFIG_CPU_CACHE_VIPT=y
++CONFIG_CPU_COPY_V6=y
++CONFIG_CPU_TLB_V7=y
++CONFIG_CPU_HAS_ASID=y
++CONFIG_CPU_CP15=y
++CONFIG_CPU_CP15_MMU=y
++
++#
++# Processor Features
++#
++# CONFIG_ARM_LPAE is not set
++# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
++CONFIG_ARM_THUMB=y
++# CONFIG_ARM_THUMBEE is not set
++CONFIG_ARM_VIRT_EXT=y
++CONFIG_SWP_EMULATE=y
++# CONFIG_CPU_ICACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_DISABLE is not set
++# CONFIG_CPU_BPREDICT_DISABLE is not set
++CONFIG_KUSER_HELPERS=y
++CONFIG_MIGHT_HAVE_CACHE_L2X0=y
++# CONFIG_CACHE_L2X0 is not set
++CONFIG_ARM_L1_CACHE_SHIFT_6=y
++CONFIG_ARM_L1_CACHE_SHIFT=6
++CONFIG_ARM_DMA_MEM_BUFFERABLE=y
++CONFIG_MULTI_IRQ_HANDLER=y
++# CONFIG_ARM_ERRATA_430973 is not set
++# CONFIG_ARM_ERRATA_720789 is not set
++# CONFIG_ARM_ERRATA_754322 is not set
++# CONFIG_ARM_ERRATA_775420 is not set
++# CONFIG_ARM_ERRATA_773022 is not set
++
++#
++# Bus support
++#
++CONFIG_ARM_AMBA=y
++# CONFIG_PCI is not set
++# CONFIG_PCI_SYSCALL is not set
++# CONFIG_PCCARD is not set
++
++#
++# Kernel Features
++#
++CONFIG_HAVE_SMP=y
++# CONFIG_SMP is not set
++CONFIG_DISABLE_CPU_SCHED_DOMAIN_BALANCE=y
++CONFIG_HAVE_ARM_ARCH_TIMER=y
++CONFIG_VMSPLIT_3G=y
++# CONFIG_VMSPLIT_2G is not set
++# CONFIG_VMSPLIT_1G is not set
++CONFIG_PAGE_OFFSET=0xC0000000
++# CONFIG_ARM_PSCI is not set
++CONFIG_ARCH_NR_GPIO=0
++CONFIG_PREEMPT_NONE=y
++# CONFIG_PREEMPT_VOLUNTARY is not set
++# CONFIG_PREEMPT is not set
++CONFIG_HZ_FIXED=0
++# CONFIG_HZ_100 is not set
++# CONFIG_HZ_200 is not set
++# CONFIG_HZ_250 is not set
++# CONFIG_HZ_300 is not set
++# CONFIG_HZ_500 is not set
++CONFIG_HZ_1000=y
++CONFIG_HZ=1000
++# CONFIG_SCHED_HRTICK is not set
++# CONFIG_THUMB2_KERNEL is not set
++CONFIG_AEABI=y
++# CONFIG_OABI_COMPAT is not set
++# 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_ARCH_WANT_GENERAL_HUGETLB=y
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_HAVE_MEMBLOCK=y
++CONFIG_NO_BOOTMEM=y
++CONFIG_MEMORY_ISOLATION=y
++# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=4
++CONFIG_COMPACTION=y
++CONFIG_MIGRATION=y
++# CONFIG_PHYS_ADDR_T_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_BOUNCE=y
++# CONFIG_KSM is not set
++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
++CONFIG_NEED_PER_CPU_KM=y
++# CONFIG_CLEANCACHE is not set
++# CONFIG_FRONTSWAP is not set
++CONFIG_CMA=y
++# CONFIG_CMA_DEBUG is not set
++CONFIG_CMA_AREAS=7
++# CONFIG_ZPOOL is not set
++# CONFIG_ZBUD is not set
++# CONFIG_ZSMALLOC 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_SWIOTLB=y
++CONFIG_IOMMU_HELPER=y
++# CONFIG_XEN is not set
++# CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART is not set
++
++#
++# Boot options
++#
++CONFIG_USE_OF=y
++CONFIG_ATAGS=y
++# CONFIG_DEPRECATED_PARAM_STRUCT is not set
++# CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE is not set
++CONFIG_ZBOOT_ROM_TEXT=0
++CONFIG_ZBOOT_ROM_BSS=0
++CONFIG_ARM_APPENDED_DTB=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_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_GOV_COMMON=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_USERSPACE is not set
++CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
++# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE is not set
++CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
++CONFIG_CPU_FREQ_GOV_POWERSAVE=y
++CONFIG_CPU_FREQ_GOV_USERSPACE=y
++CONFIG_CPU_FREQ_GOV_ONDEMAND=y
++CONFIG_CPU_FREQ_GOV_INTERACTIVE=y
++# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
++# CONFIG_CPUFREQ_DT is not set
++
++#
++# ARM CPU frequency scaling drivers
++#
++# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set
++
++#
++# CPU Idle
++#
++# CONFIG_CPU_IDLE is not set
++# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++CONFIG_VFP=y
++CONFIG_VFPv3=y
++CONFIG_NEON=y
++CONFIG_KERNEL_MODE_NEON=y
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
++CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
++CONFIG_BINFMT_SCRIPT=y
++# CONFIG_HAVE_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
++CONFIG_COREDUMP=y
++
++#
++# Power management options
++#
++CONFIG_SUSPEND=y
++CONFIG_SUSPEND_FREEZER=y
++CONFIG_WAKELOCK=y
++CONFIG_HIBERNATE_CALLBACKS=y
++CONFIG_HISI_SNAPSHOT_BOOT=y
++# CONFIG_DEFAULT_MTD is not set
++CONFIG_DEFAULT_DDR=y
++CONFIG_SNAPSHOT_BUF_START=0x8a000000
++CONFIG_SNAPSHOT_BUF_SIZE=0x4000000
++CONFIG_HIBERNATION=y
++CONFIG_GZIP_COMPRESS=y
++CONFIG_PM_STD_PARTITION=""
++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_OPP=y
++CONFIG_PM_CLK=y
++# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set
++CONFIG_CPU_PM=y
++# CONFIG_SUSPEND_TIME is not set
++CONFIG_ARCH_SUSPEND_POSSIBLE=y
++CONFIG_ARM_CPU_SUSPEND=y
++CONFIG_ARCH_HIBERNATION_POSSIBLE=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_NET_IP_TUNNEL=m
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_NET_IPVTI is not set
++# CONFIG_NET_UDP_TUNNEL is not set
++# CONFIG_NET_FOU is not set
++# CONFIG_GENEVE 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=y
++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=y
++# 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_VTI 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_ANDROID_PARANOID_NETWORK is not set
++CONFIG_NET_ACTIVITY_STATS=y
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NET_PTP_CLASSIFY 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_NF_TABLES is not set
++# CONFIG_NETFILTER_XTABLES is not set
++# CONFIG_IP_SET is not set
++# CONFIG_IP_VS is not set
++
++#
++# IP: Netfilter Configuration
++#
++# CONFIG_NF_DEFRAG_IPV4 is not set
++# CONFIG_NF_LOG_ARP is not set
++# CONFIG_NF_LOG_IPV4 is not set
++# CONFIG_NF_REJECT_IPV4 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_NF_REJECT_IPV6 is not set
++# CONFIG_NF_LOG_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_HAVE_NET_DSA=y
++# 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_PHONET is not set
++# CONFIG_6LOWPAN 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_VSOCKETS is not set
++# CONFIG_NETLINK_MMAP is not set
++# CONFIG_NETLINK_DIAG is not set
++# CONFIG_NET_MPLS_GSO is not set
++# CONFIG_HSR is not set
++# CONFIG_CGROUP_NET_PRIO is not set
++# CONFIG_CGROUP_NET_CLASSID is not set
++CONFIG_NET_RX_BUSY_POLL=y
++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 is not set
++CONFIG_DEVTMPFS=y
++CONFIG_DEVTMPFS_MOUNT=y
++CONFIG_STANDALONE=y
++# CONFIG_PREVENT_FIRMWARE_BUILD is not set
++CONFIG_FW_LOADER=y
++# CONFIG_FIRMWARE_IN_KERNEL is not set
++CONFIG_EXTRA_FIRMWARE=""
++# CONFIG_FW_LOADER_USER_HELPER_FALLBACK is not set
++CONFIG_ALLOW_DEV_COREDUMP=y
++# 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_HAVE_CPU_AUTOPROBE is not set
++CONFIG_REGMAP=y
++CONFIG_REGMAP_MMIO=y
++CONFIG_DMA_SHARED_BUFFER=y
++# CONFIG_FENCE_TRACE is not set
++CONFIG_DMA_CMA=y
++
++#
++# Default contiguous memory area size:
++#
++CONFIG_CMA_SIZE_MBYTES=16
++CONFIG_CMA_SIZE_SEL_MBYTES=y
++# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set
++# CONFIG_CMA_SIZE_SEL_MIN is not set
++# CONFIG_CMA_SIZE_SEL_MAX is not set
++CONFIG_CMA_ALIGNMENT=8
++
++#
++# Bus devices
++#
++# CONFIG_BRCMSTB_GISB_ARB is not set
++CONFIG_ARM_CCI=y
++# CONFIG_VEXPRESS_CONFIG 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=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_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
++CONFIG_HIFMC=y
++CONFIG_HIFMC_SPI_NAND=y
++# CONFIG_HIFMC_NAND is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++# CONFIG_MTD_CFI is not set
++# CONFIG_MTD_JEDECPROBE is not set
++CONFIG_MTD_MAP_BANK_WIDTH_1=y
++CONFIG_MTD_MAP_BANK_WIDTH_2=y
++CONFIG_MTD_MAP_BANK_WIDTH_4=y
++# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
++CONFIG_MTD_CFI_I1=y
++CONFIG_MTD_CFI_I2=y
++# CONFIG_MTD_CFI_I4 is not set
++# CONFIG_MTD_CFI_I8 is not set
++# CONFIG_MTD_RAM is not set
++# CONFIG_MTD_ROM is not set
++# CONFIG_MTD_ABSENT is not set
++
++#
++# Mapping drivers for chip access
++#
++# CONFIG_MTD_COMPLEX_MAPPINGS is not set
++# CONFIG_MTD_PLATRAM is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_DATAFLASH is not set
++# CONFIG_MTD_M25P80 is not set
++# CONFIG_MTD_SST25L is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_PHRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++# CONFIG_MTD_BLOCK2MTD is not set
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOCG3 is not set
++CONFIG_MTD_NAND_IDS=y
++CONFIG_MTD_NAND_ECC=y
++# CONFIG_MTD_NAND_ECC_SMC is not set
++CONFIG_MTD_NAND=y
++# CONFIG_MTD_NAND_ECC_BCH is not set
++# CONFIG_MTD_SM_COMMON is not set
++# CONFIG_MTD_NAND_DENALI is not set
++# CONFIG_MTD_NAND_GPIO is not set
++# CONFIG_MTD_NAND_OMAP_BCH_BUILD is not set
++# CONFIG_MTD_NAND_DISKONCHIP is not set
++# CONFIG_MTD_NAND_DOCG4 is not set
++# CONFIG_MTD_NAND_NANDSIM is not set
++# CONFIG_MTD_NAND_PLATFORM is not set
++# CONFIG_HISI_NAND_FS_MAY_NO_YAFFS2 is not set
++# CONFIG_HISI_NAND_ECC_STATUS_REPORT is not set
++# CONFIG_MTD_NAND_HINFC610 is not set
++# CONFIG_HIFMC100_NAND is not set
++CONFIG_HIFMC100_SPI_NAND=y
++CONFIG_SPI_NAND_MAX_CHIP_NUM=1
++# CONFIG_HIFMC100_HARDWARE_PAGESIZE_ECC is not set
++CONFIG_HIFMC100_AUTO_PAGESIZE_ECC=y
++# CONFIG_HIFMC100_PAGESIZE_AUTO_ECC_NONE is not set
++# CONFIG_MTD_ONENAND is not set
++
++#
++# LPDDR & LPDDR2 PCM memory drivers
++#
++# CONFIG_MTD_LPDDR is not set
++# CONFIG_MTD_LPDDR2_NVM is not set
++CONFIG_MTD_SPI_NOR=y
++# CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set
++CONFIG_SPI_HISI_SFC=y
++CONFIG_CLOSE_SPI_8PIN_4IO=y
++CONFIG_HISI_SPI_BLOCK_PROTECT=y
++CONFIG_MTD_UBI=y
++CONFIG_MTD_UBI_WL_THRESHOLD=4096
++CONFIG_MTD_UBI_BEB_LIMIT=20
++# CONFIG_MTD_UBI_FASTMAP is not set
++# CONFIG_MTD_UBI_GLUEBI is not set
++# CONFIG_MTD_UBI_BLOCK is not set
++CONFIG_DTC=y
++CONFIG_OF=y
++
++#
++# Device Tree and Open Firmware support
++#
++# 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_NET=y
++CONFIG_OF_MDIO=y
++CONFIG_OF_MTD=y
++CONFIG_OF_RESERVED_MEM=y
++CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
++# CONFIG_PARPORT is not set
++CONFIG_BLK_DEV=y
++# CONFIG_BLK_DEV_NULL_BLK is not set
++# CONFIG_BLK_DEV_COW_COMMON is not set
++# CONFIG_BLK_DEV_LOOP 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=65536
++# 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_DUMMY_IRQ 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_UID_STAT is not set
++# CONFIG_BMP085_I2C is not set
++# CONFIG_BMP085_SPI is not set
++# CONFIG_USB_SWITCH_FSA9480 is not set
++# CONFIG_LATTICE_ECP3_CONFIG is not set
++# CONFIG_SRAM is not set
++# CONFIG_C2PORT is not set
++
++#
++# EEPROM support
++#
++# CONFIG_EEPROM_AT24 is not set
++# CONFIG_EEPROM_AT25 is not set
++# CONFIG_EEPROM_LEGACY is not set
++# CONFIG_EEPROM_MAX6875 is not set
++# CONFIG_EEPROM_93CX6 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
++
++#
++# Intel MIC Bus Driver
++#
++
++#
++# Intel MIC Host Driver
++#
++
++#
++# Intel MIC Card Driver
++#
++# CONFIG_ECHO is not set
++# CONFIG_CXL_BASE is not set
++
++#
++# hisi 'himm/himd.l/himc'support
++#
++# CONFIG_HISI_REG 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_NETLINK is not set
++# CONFIG_SCSI_MQ_DEFAULT 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_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 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_NET_CORE=y
++# CONFIG_BONDING is not set
++# CONFIG_DUMMY is not set
++# CONFIG_EQUALIZER is not set
++# CONFIG_NET_TEAM is not set
++# CONFIG_MACVLAN is not set
++# CONFIG_VXLAN is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_TUN is not set
++# CONFIG_VETH is not set
++# CONFIG_NLMON is not set
++
++#
++# 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_NET_DSA_MV88E6171 is not set
++# CONFIG_NET_DSA_BCM_SF2 is not set
++# CONFIG_ETHERNET is not set
++CONFIG_PHYLIB=y
++
++#
++# MII PHY device drivers
++#
++# CONFIG_AT803X_PHY is not set
++# CONFIG_AMD_PHY is not set
++# CONFIG_AMD_XGBE_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 is not set
++# CONFIG_BROADCOM_PHY is not set
++# CONFIG_BCM7XXX_PHY is not set
++# CONFIG_BCM87XX_PHY is not set
++# CONFIG_ICPLUS_PHY is not set
++# CONFIG_REALTEK_PHY is not set
++# CONFIG_NATIONAL_PHY is not set
++# CONFIG_STE10XP is not set
++# CONFIG_LSI_ET1011C_PHY is not set
++# CONFIG_MICREL_PHY is not set
++# CONFIG_FIXED_PHY is not set
++# CONFIG_MDIO_BITBANG is not set
++# CONFIG_MDIO_BUS_MUX_GPIO is not set
++# CONFIG_MDIO_BUS_MUX_MMIOREG is not set
++# CONFIG_MDIO_BCM_UNIMAC is not set
++# CONFIG_MDIO_HISI_FEMAC is not set
++# CONFIG_MDIO_HISI_GEMAC is not set
++# CONFIG_MICREL_KS8995MA is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++CONFIG_USB_NET_DRIVERS=y
++# 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_RTL8152 is not set
++# CONFIG_USB_USBNET is not set
++# CONFIG_USB_IPHETH is not set
++CONFIG_WLAN=y
++# CONFIG_WIFI_CONTROL_FUNC is not set
++# 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 is not set
++# CONFIG_INPUT_SPARSEKMAP is not set
++# CONFIG_INPUT_MATRIXKMAP is not set
++
++#
++# Userland interfaces
++#
++CONFIG_INPUT_MOUSEDEV=y
++CONFIG_INPUT_MOUSEDEV_PSAUX=y
++CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
++CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
++# CONFIG_INPUT_JOYDEV is not set
++CONFIG_INPUT_EVDEV=y
++# CONFIG_INPUT_EVBUG is not set
++# CONFIG_INPUT_KEYRESET is not set
++# CONFIG_INPUT_KEYCOMBO is not set
++
++#
++# Input Device Drivers
++#
++CONFIG_INPUT_KEYBOARD=y
++# CONFIG_KEYBOARD_ADP5588 is not set
++# CONFIG_KEYBOARD_ADP5589 is not set
++CONFIG_KEYBOARD_ATKBD=y
++# CONFIG_KEYBOARD_QT1070 is not set
++# CONFIG_KEYBOARD_QT2160 is not set
++# CONFIG_KEYBOARD_LKKBD is not set
++# CONFIG_KEYBOARD_GPIO is not set
++# CONFIG_KEYBOARD_GPIO_POLLED is not set
++# 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 is not set
++# CONFIG_KEYBOARD_CAP1106 is not set
++CONFIG_INPUT_MOUSE=y
++CONFIG_MOUSE_PS2=y
++CONFIG_MOUSE_PS2_ALPS=y
++CONFIG_MOUSE_PS2_LOGIPS2PP=y
++CONFIG_MOUSE_PS2_SYNAPTICS=y
++CONFIG_MOUSE_PS2_CYPRESS=y
++CONFIG_MOUSE_PS2_TRACKPOINT=y
++# CONFIG_MOUSE_PS2_ELANTECH is not set
++# CONFIG_MOUSE_PS2_SENTELIC is not set
++# CONFIG_MOUSE_PS2_TOUCHKIT is not set
++# CONFIG_MOUSE_SERIAL is not set
++# CONFIG_MOUSE_APPLETOUCH is not set
++# CONFIG_MOUSE_BCM5974 is not set
++# CONFIG_MOUSE_CYAPA is not set
++# CONFIG_MOUSE_VSXXXAA is not set
++# CONFIG_MOUSE_GPIO is not set
++# CONFIG_MOUSE_SYNAPTICS_I2C is not set
++# CONFIG_MOUSE_SYNAPTICS_USB is not set
++# CONFIG_INPUT_JOYSTICK is not set
++# CONFIG_INPUT_TABLET is not set
++# CONFIG_INPUT_TOUCHSCREEN is not set
++# CONFIG_INPUT_MISC is not set
++
++#
++# Hardware I/O ports
++#
++CONFIG_SERIO=y
++CONFIG_SERIO_SERPORT=y
++# CONFIG_SERIO_AMBAKMI is not set
++CONFIG_SERIO_LIBPS2=y
++# CONFIG_SERIO_RAW is not set
++# CONFIG_SERIO_ALTERA_PS2 is not set
++# CONFIG_SERIO_PS2MULT is not set
++# CONFIG_SERIO_ARC_PS2 is not set
++# CONFIG_SERIO_APBPS2 is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++CONFIG_TTY=y
++CONFIG_VT=y
++CONFIG_CONSOLE_TRANSLATIONS=y
++CONFIG_VT_CONSOLE=y
++CONFIG_VT_CONSOLE_SLEEP=y
++CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
++CONFIG_UNIX98_PTYS=y
++# CONFIG_DEVPTS_MULTIPLE_INSTANCES 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_DEVMEM=y
++CONFIG_DEVKMEM=y
++
++#
++# Serial drivers
++#
++CONFIG_SERIAL_EARLYCON=y
++# CONFIG_SERIAL_8250 is not set
++
++#
++# Non-8250 serial port support
++#
++# CONFIG_SERIAL_AMBA_PL010 is not set
++CONFIG_SERIAL_AMBA_PL011=y
++CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
++# CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST is not set
++# 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_SC16IS7XX is not set
++# CONFIG_SERIAL_ALTERA_JTAGUART is not set
++# CONFIG_SERIAL_ALTERA_UART is not set
++# CONFIG_SERIAL_IFX6X60 is not set
++# CONFIG_SERIAL_XILINX_PS_UART is not set
++# CONFIG_SERIAL_ARC is not set
++# CONFIG_SERIAL_FSL_LPUART is not set
++# CONFIG_SERIAL_ST_ASC is not set
++# CONFIG_HVC_DCC is not set
++# CONFIG_IPMI_HANDLER is not set
++CONFIG_HW_RANDOM=y
++# CONFIG_HW_RANDOM_TIMERIOMEM is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++# CONFIG_DCC_TTY is not set
++# CONFIG_XILLYBUS is not set
++
++#
++# I2C support
++#
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++# CONFIG_I2C_COMPAT is not set
++CONFIG_I2C_CHARDEV=y
++CONFIG_I2C_MUX=m
++
++#
++# Multiplexer I2C Chip support
++#
++# CONFIG_I2C_ARB_GPIO_CHALLENGE is not set
++# CONFIG_I2C_MUX_GPIO is not set
++# CONFIG_I2C_MUX_PCA9541 is not set
++# CONFIG_I2C_MUX_PCA954x is not set
++# CONFIG_I2C_HELPER_AUTO is not set
++# CONFIG_I2C_SMBUS is not set
++
++#
++# I2C Algorithms
++#
++# CONFIG_I2C_ALGOBIT is not set
++# CONFIG_I2C_ALGOPCF is not set
++# CONFIG_I2C_ALGOPCA is not set
++
++#
++# I2C Hardware Bus support
++#
++
++#
++# I2C system bus drivers (mostly embedded / system-on-chip)
++#
++# CONFIG_I2C_CBUS_GPIO is not set
++# CONFIG_I2C_DESIGNWARE_PLATFORM is not set
++# CONFIG_I2C_GPIO is not set
++# CONFIG_I2C_HIBVT is not set
++CONFIG_I2C_HISI_V110=y
++# CONFIG_I2C_NOMADIK 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_RK3X 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_ROBOTFUZZ_OSIF 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_CADENCE is not set
++# CONFIG_SPI_GPIO is not set
++# CONFIG_SPI_FSL_SPI is not set
++# CONFIG_SPI_OC_TINY is not set
++CONFIG_SPI_PL022=y
++# CONFIG_SPI_PXA2XX_PCI is not set
++# CONFIG_SPI_ROCKCHIP 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=y
++# CONFIG_SPI_TLE62X0 is not set
++# CONFIG_SPMI is not set
++# CONFIG_HSI is not set
++
++#
++# PPS support
++#
++# CONFIG_PPS is not set
++
++#
++# PPS generators support
++#
++
++#
++# PTP clock support
++#
++# CONFIG_PTP_1588_CLOCK is not set
++
++#
++# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
++#
++CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
++CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
++CONFIG_GPIOLIB=y
++CONFIG_GPIO_DEVRES=y
++CONFIG_OF_GPIO=y
++CONFIG_GPIOLIB_IRQCHIP=y
++# CONFIG_DEBUG_GPIO is not set
++CONFIG_GPIO_SYSFS=y
++
++#
++# Memory mapped GPIO drivers:
++#
++# CONFIG_GPIO_GENERIC_PLATFORM is not set
++# CONFIG_GPIO_DWAPB is not set
++# CONFIG_GPIO_EM is not set
++# CONFIG_GPIO_ZEVIO is not set
++CONFIG_GPIO_PL061=y
++# CONFIG_GPIO_SCH311X is not set
++# CONFIG_GPIO_SYSCON is not set
++# CONFIG_GPIO_GRGPIO is not set
++
++#
++# I2C GPIO expanders:
++#
++# CONFIG_GPIO_MAX7300 is not set
++# CONFIG_GPIO_MAX732X is not set
++# CONFIG_GPIO_PCA953X is not set
++# CONFIG_GPIO_PCF857X is not set
++# CONFIG_GPIO_SX150X is not set
++# CONFIG_GPIO_ADP5588 is not set
++# CONFIG_GPIO_ADNP is not set
++
++#
++# PCI GPIO expanders:
++#
++
++#
++# SPI GPIO expanders:
++#
++# CONFIG_GPIO_MAX7301 is not set
++# CONFIG_GPIO_MCP23S08 is not set
++# CONFIG_GPIO_MC33880 is not set
++# CONFIG_GPIO_74X164 is not set
++
++#
++# AC97 GPIO expanders:
++#
++
++#
++# LPC GPIO expanders:
++#
++
++#
++# MODULbus GPIO expanders:
++#
++
++#
++# USB GPIO expanders:
++#
++# CONFIG_W1 is not set
++CONFIG_POWER_SUPPLY=y
++# CONFIG_POWER_SUPPLY_DEBUG is not set
++# CONFIG_PDA_POWER is not set
++# CONFIG_TEST_POWER is not set
++# CONFIG_BATTERY_DS2780 is not set
++# CONFIG_BATTERY_DS2781 is not set
++# CONFIG_BATTERY_DS2782 is not set
++# CONFIG_BATTERY_SBS is not set
++# CONFIG_BATTERY_BQ27x00 is not set
++# CONFIG_BATTERY_MAX17040 is not set
++# CONFIG_BATTERY_MAX17042 is not set
++# CONFIG_CHARGER_MAX8903 is not set
++# CONFIG_CHARGER_LP8727 is not set
++# CONFIG_CHARGER_GPIO is not set
++# CONFIG_CHARGER_BQ2415X is not set
++# CONFIG_CHARGER_BQ24190 is not set
++# CONFIG_CHARGER_BQ24735 is not set
++# CONFIG_CHARGER_SMB347 is not set
++CONFIG_POWER_RESET=y
++# CONFIG_POWER_RESET_BRCMSTB is not set
++# CONFIG_POWER_RESET_GPIO is not set
++# CONFIG_POWER_RESET_GPIO_RESTART is not set
++CONFIG_POWER_RESET_HISI=y
++# CONFIG_POWER_RESET_LTC2952 is not set
++# CONFIG_POWER_RESET_RESTART is not set
++# CONFIG_POWER_RESET_VERSATILE is not set
++# CONFIG_POWER_RESET_SYSCON is not set
++# CONFIG_POWER_AVS is not set
++# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
++# CONFIG_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=y
++# CONFIG_MFD_AS3711 is not set
++# CONFIG_MFD_AS3722 is not set
++# CONFIG_PMIC_ADP5520 is not set
++# CONFIG_MFD_AAT2870_CORE is not set
++# CONFIG_MFD_BCM590XX is not set
++# CONFIG_MFD_AXP20X is not set
++# CONFIG_MFD_CROS_EC is not set
++# CONFIG_MFD_ASIC3 is not set
++# CONFIG_PMIC_DA903X is not set
++# CONFIG_MFD_DA9052_SPI is not set
++# CONFIG_MFD_DA9052_I2C is not set
++# CONFIG_MFD_DA9055 is not set
++# CONFIG_MFD_DA9063 is not set
++# CONFIG_MFD_MC13XXX_SPI is not set
++# CONFIG_MFD_MC13XXX_I2C is not set
++# CONFIG_MFD_HI6421_PMIC is not set
++CONFIG_MFD_HISI_FMC=y
++# CONFIG_HTC_EGPIO is not set
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_HTC_I2CPLD is not set
++# CONFIG_INTEL_SOC_PMIC is not set
++# CONFIG_MFD_KEMPLD is not set
++# CONFIG_MFD_88PM800 is not set
++# CONFIG_MFD_88PM805 is not set
++# CONFIG_MFD_88PM860X is not set
++# CONFIG_MFD_MAX14577 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_MENF21BMC is not set
++# CONFIG_EZX_PCAP is not set
++# CONFIG_MFD_VIPERBOARD is not set
++# CONFIG_MFD_RETU is not set
++# CONFIG_MFD_PCF50633 is not set
++# CONFIG_MFD_PM8921_CORE is not set
++# CONFIG_MFD_RTSX_USB is not set
++# CONFIG_MFD_RC5T583 is not set
++# CONFIG_MFD_RK808 is not set
++# CONFIG_MFD_RN5T618 is not set
++# CONFIG_MFD_SEC_CORE is not set
++# CONFIG_MFD_SI476X_CORE is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_MFD_SMSC is not set
++# CONFIG_ABX500_CORE is not set
++# CONFIG_MFD_STMPE is not set
++CONFIG_MFD_SYSCON=y
++# CONFIG_MFD_TI_AM335X_TSCADC is not set
++# CONFIG_MFD_LP3943 is not set
++# CONFIG_MFD_LP8788 is not set
++# CONFIG_MFD_PALMAS is not set
++# CONFIG_TPS6105X is not set
++# CONFIG_TPS65010 is not set
++# CONFIG_TPS6507X is not set
++# CONFIG_MFD_TPS65090 is not set
++# CONFIG_MFD_TPS65217 is not set
++# CONFIG_MFD_TPS65218 is not set
++# CONFIG_MFD_TPS6586X is not set
++# CONFIG_MFD_TPS65910 is not set
++# CONFIG_MFD_TPS65912 is not set
++# CONFIG_MFD_TPS65912_I2C is not set
++# CONFIG_MFD_TPS65912_SPI is not set
++# CONFIG_MFD_TPS80031 is not set
++# CONFIG_TWL4030_CORE is not set
++# CONFIG_TWL6040_CORE is not set
++# CONFIG_MFD_WL1273_CORE is not set
++# CONFIG_MFD_LM3533 is not set
++# CONFIG_MFD_TC3589X is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_MFD_T7L66XB is not set
++# CONFIG_MFD_TC6387XB is not set
++# CONFIG_MFD_TC6393XB is not set
++# CONFIG_MFD_ARIZONA_I2C is not set
++# CONFIG_MFD_ARIZONA_SPI is not set
++# CONFIG_MFD_WM8400 is not set
++# CONFIG_MFD_WM831X_I2C is not set
++# CONFIG_MFD_WM831X_SPI is not set
++# CONFIG_MFD_WM8350_I2C is not set
++# CONFIG_MFD_WM8994 is not set
++CONFIG_REGULATOR=y
++# CONFIG_REGULATOR_DEBUG is not set
++# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
++# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
++# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
++# CONFIG_REGULATOR_ACT8865 is not set
++# CONFIG_REGULATOR_AD5398 is not set
++# CONFIG_REGULATOR_ANATOP is not set
++# CONFIG_REGULATOR_DA9210 is not set
++# CONFIG_REGULATOR_DA9211 is not set
++# CONFIG_REGULATOR_FAN53555 is not set
++# CONFIG_REGULATOR_GPIO is not set
++# CONFIG_REGULATOR_ISL9305 is not set
++# CONFIG_REGULATOR_ISL6271A is not set
++# CONFIG_REGULATOR_LP3971 is not set
++# CONFIG_REGULATOR_LP3972 is not set
++# CONFIG_REGULATOR_LP872X is not set
++# CONFIG_REGULATOR_LP8755 is not set
++# CONFIG_REGULATOR_LTC3589 is not set
++# CONFIG_REGULATOR_MAX1586 is not set
++# CONFIG_REGULATOR_MAX8649 is not set
++# CONFIG_REGULATOR_MAX8660 is not set
++# CONFIG_REGULATOR_MAX8952 is not set
++# CONFIG_REGULATOR_MAX8973 is not set
++# CONFIG_REGULATOR_PFUZE100 is not set
++# CONFIG_REGULATOR_TPS51632 is not set
++# CONFIG_REGULATOR_TPS62360 is not set
++# CONFIG_REGULATOR_TPS65023 is not set
++# CONFIG_REGULATOR_TPS6507X is not set
++# CONFIG_REGULATOR_TPS6524X is not set
++CONFIG_MEDIA_SUPPORT=m
++
++#
++# Multimedia core support
++#
++CONFIG_MEDIA_CAMERA_SUPPORT=y
++# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set
++# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set
++# CONFIG_MEDIA_RADIO_SUPPORT is not set
++# CONFIG_MEDIA_SDR_SUPPORT is not set
++# CONFIG_MEDIA_RC_SUPPORT is not set
++# CONFIG_MEDIA_CONTROLLER is not set
++CONFIG_VIDEO_DEV=m
++CONFIG_VIDEO_V4L2=m
++# CONFIG_VIDEO_ADV_DEBUG is not set
++# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
++CONFIG_VIDEOBUF2_CORE=m
++CONFIG_VIDEOBUF2_MEMOPS=m
++CONFIG_VIDEOBUF2_VMALLOC=m
++# CONFIG_TTPCI_EEPROM is not set
++
++#
++# Media drivers
++#
++# CONFIG_MEDIA_USB_SUPPORT is not set
++# CONFIG_V4L_PLATFORM_DRIVERS is not set
++# CONFIG_V4L_MEM2MEM_DRIVERS is not set
++# CONFIG_V4L_TEST_DRIVERS is not set
++
++#
++# Supported MMC/SDIO adapters
++#
++# CONFIG_CYPRESS_FIRMWARE is not set
++
++#
++# Media ancillary drivers (tuners, sensors, i2c, frontends)
++#
++CONFIG_MEDIA_SUBDRV_AUTOSELECT=y
++
++#
++# Audio decoders, processors and mixers
++#
++
++#
++# RDS decoders
++#
++
++#
++# Video decoders
++#
++
++#
++# Video and audio decoders
++#
++
++#
++# Video encoders
++#
++
++#
++# Camera sensor devices
++#
++
++#
++# Flash devices
++#
++
++#
++# Video improvement chips
++#
++
++#
++# Audio/Video compression chips
++#
++
++#
++# Miscellaneous helper chips
++#
++
++#
++# Sensors used on soc_camera driver
++#
++
++#
++# Tools to develop new frontends
++#
++# CONFIG_DVB_DUMMY_FE is not set
++
++#
++# Graphics support
++#
++# CONFIG_IMX_IPUV3_CORE is not set
++
++#
++# Direct Rendering Manager
++#
++# CONFIG_DRM is not set
++
++#
++# Frame buffer Devices
++#
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++CONFIG_FB_CMDLINE=y
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++# CONFIG_FB_CFB_FILLRECT is not set
++# CONFIG_FB_CFB_COPYAREA is not set
++# CONFIG_FB_CFB_IMAGEBLIT is not set
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# 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_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_ARMCLCD is not set
++# CONFIG_FB_OPENCORES is not set
++# CONFIG_FB_S1D13XXX is not set
++# CONFIG_FB_SMSCUFX is not set
++# CONFIG_FB_UDL is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_BROADSHEET is not set
++# CONFIG_FB_AUO_K190X is not set
++# CONFIG_FB_SIMPLE is not set
++# CONFIG_FB_SSD1307 is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++# CONFIG_VGASTATE is not set
++
++#
++# Console display driver support
++#
++CONFIG_DUMMY_CONSOLE=y
++# CONFIG_FRAMEBUFFER_CONSOLE is not set
++# CONFIG_LOGO is not set
++# CONFIG_SOUND is not set
++
++#
++# HID support
++#
++CONFIG_HID=y
++# CONFIG_HID_BATTERY_STRENGTH is not set
++# CONFIG_HIDRAW is not set
++# CONFIG_UHID is not set
++CONFIG_HID_GENERIC=y
++
++#
++# Special HID drivers
++#
++CONFIG_HID_A4TECH=y
++# CONFIG_HID_ACRUX is not set
++CONFIG_HID_APPLE=y
++# CONFIG_HID_APPLEIR is not set
++# CONFIG_HID_AUREAL is not set
++CONFIG_HID_BELKIN=y
++CONFIG_HID_CHERRY=y
++CONFIG_HID_CHICONY=y
++# CONFIG_HID_CP2112 is not set
++CONFIG_HID_CYPRESS=y
++# CONFIG_HID_DRAGONRISE is not set
++# CONFIG_HID_EMS_FF is not set
++# CONFIG_HID_ELECOM is not set
++# CONFIG_HID_ELO is not set
++CONFIG_HID_EZKEY=y
++# CONFIG_HID_HOLTEK is not set
++# CONFIG_HID_HUION 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_ICADE is not set
++# CONFIG_HID_TWINHAN is not set
++CONFIG_HID_KENSINGTON=y
++# CONFIG_HID_LCPOWER is not set
++# CONFIG_HID_LENOVO is not set
++CONFIG_HID_LOGITECH=y
++# CONFIG_HID_LOGITECH_HIDPP is not set
++# CONFIG_LOGITECH_FF is not set
++# CONFIG_LOGIRUMBLEPAD2_FF is not set
++# CONFIG_LOGIG940_FF is not set
++# CONFIG_LOGIWHEELS_FF is not set
++# CONFIG_HID_MAGICMOUSE is not set
++CONFIG_HID_MICROSOFT=y
++CONFIG_HID_MONTEREY=y
++# 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_PENMOUNT is not set
++# CONFIG_HID_PETALYNX is not set
++# CONFIG_HID_PICOLCD is not set
++# CONFIG_HID_PRIMAX is not set
++# CONFIG_HID_ROCCAT is not set
++# CONFIG_HID_SAITEK is not set
++# CONFIG_HID_SAMSUNG is not set
++# CONFIG_HID_SPEEDLINK is not set
++# CONFIG_HID_STEELSERIES is not set
++# CONFIG_HID_SUNPLUS is not set
++# CONFIG_HID_RMI 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_XINMO is not set
++# CONFIG_HID_ZEROPLUS is not set
++# CONFIG_HID_ZYDACRON is not set
++# CONFIG_HID_SENSOR_HUB is not set
++
++#
++# USB HID support
++#
++CONFIG_USB_HID=y
++# CONFIG_HID_PID is not set
++# CONFIG_USB_HIDDEV is not set
++
++#
++# I2C HID support
++#
++# CONFIG_I2C_HID is not set
++CONFIG_USB_OHCI_LITTLE_ENDIAN=y
++CONFIG_USB_SUPPORT=y
++CONFIG_USB_COMMON=y
++CONFIG_USB_ARCH_HAS_HCD=y
++CONFIG_USB=y
++# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
++
++#
++# Miscellaneous USB options
++#
++# CONFIG_USB_DEFAULT_PERSIST is not set
++# CONFIG_USB_DYNAMIC_MINORS is not set
++# CONFIG_USB_OTG_WHITELIST is not set
++# CONFIG_USB_OTG_FSM is not set
++# CONFIG_USB_MON is not set
++# CONFIG_USB_WUSB_CBAF is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_C67X00_HCD is not set
++# CONFIG_USB_XHCI_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_FUSBH200_HCD is not set
++# CONFIG_USB_FOTG210_HCD is not set
++# CONFIG_USB_MAX3421_HCD is not set
++# CONFIG_USB_OHCI_HCD is not set
++# CONFIG_USB_SL811_HCD is not set
++# CONFIG_USB_R8A66597_HCD is not set
++# CONFIG_USB_HCD_TEST_MODE is not set
++
++#
++# USB Device Class drivers
++#
++# CONFIG_USB_ACM is not set
++# CONFIG_USB_PRINTER is not set
++# CONFIG_USB_WDM is not set
++# CONFIG_USB_TMC is not set
++
++#
++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
++#
++
++#
++# also be needed; see USB_STORAGE Help for more info
++#
++# CONFIG_USB_STORAGE is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++# CONFIG_USBIP_CORE is not set
++# CONFIG_USB_MUSB_HDRC is not set
++# CONFIG_USB_DWC3 is not set
++# CONFIG_USB_DWC2 is not set
++# CONFIG_USB_CHIPIDEA is not set
++
++#
++# USB port drivers
++#
++# CONFIG_USB_SERIAL is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
++# CONFIG_USB_SEVSEG is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
++# CONFIG_USB_APPLEDISPLAY is not set
++# CONFIG_USB_LD is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
++# CONFIG_USB_IOWARRIOR is not set
++# CONFIG_USB_TEST is not set
++# CONFIG_USB_EHSET_TEST_FIXTURE is not set
++# CONFIG_USB_ISIGHTFW is not set
++# CONFIG_USB_YUREX is not set
++# CONFIG_USB_EZUSB_FX2 is not set
++# CONFIG_USB_HSIC_USB3503 is not set
++# CONFIG_USB_LINK_LAYER_TEST is not set
++
++#
++# USB Physical Layer drivers
++#
++# CONFIG_USB_PHY is not set
++# CONFIG_USB_OTG_WAKELOCK is not set
++# CONFIG_NOP_USB_XCEIV is not set
++# CONFIG_AM335X_PHY_USB is not set
++# CONFIG_USB_GPIO_VBUS is not set
++# CONFIG_USB_ISP1301 is not set
++# CONFIG_USB_ULPI is not set
++CONFIG_USB_GADGET=y
++# CONFIG_USB_GADGET_DEBUG is not set
++# CONFIG_USB_GADGET_DEBUG_FILES is not set
++CONFIG_USB_GADGET_VBUS_DRAW=2
++CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2
++
++#
++# USB Peripheral Controller
++#
++# CONFIG_USB_FUSB300 is not set
++# CONFIG_USB_FOTG210_UDC is not set
++# CONFIG_USB_GR_UDC is not set
++# CONFIG_USB_R8A66597 is not set
++# CONFIG_USB_PXA27X is not set
++# CONFIG_USB_MV_UDC is not set
++CONFIG_HIUSB_DEVICE2_0=y
++CONFIG_USB_HISI_UDC=m
++# CONFIG_USB_AUTO_SWITCH is not set
++# CONFIG_HIUSB_DEVICE3_0 is not set
++# CONFIG_USB_MV_U3D is not set
++# CONFIG_USB_M66592 is not set
++# CONFIG_USB_NET2272 is not set
++# CONFIG_USB_GADGET_XILINX is not set
++# CONFIG_USB_DUMMY_HCD is not set
++CONFIG_USB_LIBCOMPOSITE=m
++CONFIG_USB_F_ACM=m
++CONFIG_USB_U_SERIAL=m
++CONFIG_USB_U_ETHER=m
++CONFIG_USB_F_RNDIS=m
++CONFIG_USB_F_MASS_STORAGE=m
++CONFIG_USB_F_UAC1=m
++CONFIG_USB_F_UVC=m
++# CONFIG_USB_CONFIGFS is not set
++# CONFIG_USB_ZERO is not set
++CONFIG_USB_AUDIO=m
++CONFIG_GADGET_UAC1=y
++# CONFIG_USB_ETH is not set
++# CONFIG_USB_G_NCM is not set
++# CONFIG_USB_GADGETFS is not set
++# CONFIG_USB_FUNCTIONFS is not set
++CONFIG_USB_MASS_STORAGE=m
++# CONFIG_USB_G_SERIAL is not set
++# CONFIG_USB_G_PRINTER is not set
++# CONFIG_USB_CDC_COMPOSITE is not set
++# CONFIG_USB_G_ACM_MS is not set
++CONFIG_USB_G_MULTI=m
++CONFIG_USB_G_MULTI_RNDIS=y
++# CONFIG_USB_G_MULTI_CDC is not set
++# CONFIG_USB_G_HID is not set
++# CONFIG_USB_G_DBGP is not set
++# CONFIG_USB_G_WEBCAM is not set
++CONFIG_USB_G_WEBCAM_AUDIO=m
++# CONFIG_UWB is not set
++CONFIG_MMC=y
++# CONFIG_MMC_DEBUG is not set
++# CONFIG_MMC_CLKGATE is not set
++CONFIG_MMC_EMBEDDED_SDIO=y
++# CONFIG_MMC_PARANOID_SD_INIT is not set
++
++#
++# MMC/SD/SDIO Card Drivers
++#
++CONFIG_MMC_BLOCK=y
++CONFIG_MMC_BLOCK_MINORS=8
++CONFIG_MMC_BLOCK_BOUNCE=y
++# CONFIG_MMC_BLOCK_DEFERRED_RESUME is not set
++# CONFIG_SDIO_UART is not set
++# CONFIG_MMC_TEST is not set
++
++#
++# MMC/SD/SDIO Host Controller Drivers
++#
++# CONFIG_MMC_ARMMMCI is not set
++# CONFIG_MMC_SDHCI is not set
++# CONFIG_MMC_DW is not set
++# CONFIG_MMC_VUB300 is not set
++# CONFIG_MMC_USHC is not set
++# CONFIG_MMC_USDHI6ROL0 is not set
++CONFIG_HIMCIV200=y
++CONFIG_SEND_AUTO_STOP=y
++CONFIG_DETECT_CARD_TIME=200
++# CONFIG_MEMSTICK is not set
++# CONFIG_NEW_LEDS is not set
++# CONFIG_SWITCH is not set
++# CONFIG_ACCESSIBILITY is not set
++# CONFIG_EDAC is not set
++CONFIG_RTC_LIB=y
++# CONFIG_RTC_CLASS is not set
++# CONFIG_DMADEVICES is not set
++# CONFIG_AUXDISPLAY is not set
++# CONFIG_UIO is not set
++# CONFIG_VIRT_DRIVERS is not set
++
++#
++# Virtio drivers
++#
++# CONFIG_VIRTIO_MMIO is not set
++
++#
++# Microsoft Hyper-V guest support
++#
++# CONFIG_STAGING is not set
++
++#
++# SOC (System On Chip) specific Drivers
++#
++# CONFIG_SOC_TI is not set
++CONFIG_CLKDEV_LOOKUP=y
++CONFIG_HAVE_CLK_PREPARE=y
++CONFIG_COMMON_CLK=y
++
++#
++# Common Clock Framework
++#
++# CONFIG_COMMON_CLK_SI5351 is not set
++# CONFIG_COMMON_CLK_SI570 is not set
++# CONFIG_COMMON_CLK_PXA is not set
++# CONFIG_COMMON_CLK_QCOM is not set
++
++#
++# Hardware Spinlock drivers
++#
++
++#
++# Clock Source drivers
++#
++CONFIG_CLKSRC_OF=y
++CONFIG_CLKSRC_MMIO=y
++CONFIG_ARM_ARCH_TIMER=y
++CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y
++# CONFIG_ARM_ARCH_TIMER_VCT_ACCESS is not set
++# CONFIG_ATMEL_PIT is not set
++# CONFIG_SH_TIMER_CMT is not set
++# CONFIG_SH_TIMER_MTU2 is not set
++# CONFIG_SH_TIMER_TMU is not set
++# CONFIG_EM_TIMER_STI is not set
++# CONFIG_CLKSRC_VERSATILE is not set
++# CONFIG_MAILBOX is not set
++# CONFIG_IOMMU_SUPPORT is not set
++
++#
++# Remoteproc drivers
++#
++# CONFIG_STE_MODEM_RPROC is not set
++
++#
++# Rpmsg drivers
++#
++
++#
++# SOC (System On Chip) specific Drivers
++#
++# 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
++CONFIG_IRQCHIP=y
++CONFIG_ARM_GIC=y
++# CONFIG_IPACK_BUS is not set
++CONFIG_ARCH_HAS_RESET_CONTROLLER=y
++CONFIG_RESET_CONTROLLER=y
++# CONFIG_FMC is not set
++
++#
++# PHY Subsystem
++#
++CONFIG_GENERIC_PHY=y
++# CONFIG_BCM_KONA_USB2_PHY is not set
++CONFIG_PHY_HISI_INNO_USB2=y
++# CONFIG_POWERCAP is not set
++# CONFIG_MCB is not set
++# CONFIG_HI_DMAC is not set
++
++#
++# Hisilicon driver support
++#
++# CONFIG_CMA_MEM_SHARED is not set
++# CONFIG_CMA_ADVANCE_SHARE is not set
++
++#
++# File systems
++#
++CONFIG_DCACHE_WORD_ACCESS=y
++# CONFIG_EXT2_FS is not set
++# CONFIG_EXT3_FS is not set
++CONFIG_EXT4_FS=y
++CONFIG_EXT4_USE_FOR_EXT23=y
++# CONFIG_EXT4_FS_POSIX_ACL is not set
++# CONFIG_EXT4_FS_SECURITY is not set
++# CONFIG_EXT4_DEBUG is not set
++CONFIG_JBD2=y
++# CONFIG_JBD2_DEBUG is not set
++CONFIG_FS_MBCACHE=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_BTRFS_FS is not set
++# CONFIG_NILFS2_FS is not set
++CONFIG_FS_POSIX_ACL=y
++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 is not set
++# CONFIG_FUSE_FS is not set
++# CONFIG_OVERLAY_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_KERNFS=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=m
++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_YAFFS_FS=y
++CONFIG_YAFFS_YAFFS1=y
++# CONFIG_YAFFS_9BYTE_TAGS is not set
++# CONFIG_YAFFS_DOES_ECC is not set
++CONFIG_YAFFS_YAFFS2=y
++CONFIG_YAFFS_AUTO_YAFFS2=y
++# CONFIG_YAFFS_DISABLE_TAGS_ECC is not set
++# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
++# CONFIG_YAFFS_EMPTY_LOST_AND_FOUND is not set
++# CONFIG_YAFFS_DISABLE_BLOCK_REFRESHING is not set
++# CONFIG_YAFFS_DISABLE_BACKGROUND is not set
++# CONFIG_YAFFS_DISABLE_BAD_BLOCK_MARKING is not set
++CONFIG_YAFFS_XATTR=y
++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 is not set
++# CONFIG_JFFS2_FS_XATTR is not set
++# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
++CONFIG_JFFS2_ZLIB=y
++# CONFIG_JFFS2_LZO is not set
++CONFIG_JFFS2_RTIME=y
++# CONFIG_JFFS2_RUBIN 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 is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V2=y
++CONFIG_NFS_V3=y
++CONFIG_NFS_V3_ACL=y
++# CONFIG_NFS_V4 is not set
++# CONFIG_NFS_SWAP is not set
++# CONFIG_ROOT_NFS is not set
++# CONFIG_NFSD is not set
++CONFIG_GRACE_PERIOD=y
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_ACL_SUPPORT=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 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=y
++# CONFIG_DLM is not set
++
++#
++# Kernel hacking
++#
++
++#
++# printk and dmesg options
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4
++# CONFIG_BOOT_PRINTK_DELAY is not set
++
++#
++# Compile-time checks and compiler options
++#
++# CONFIG_DEBUG_INFO is not set
++# CONFIG_ENABLE_WARN_DEPRECATED is not set
++# CONFIG_ENABLE_MUST_CHECK is not set
++CONFIG_FRAME_WARN=1024
++# CONFIG_STRIP_ASM_SYMS is not set
++# CONFIG_READABLE_ASM is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++# CONFIG_DEBUG_FS is not set
++# CONFIG_HEADERS_CHECK is not set
++# CONFIG_DEBUG_SECTION_MISMATCH is not set
++# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
++# CONFIG_MAGIC_SYSRQ is not set
++CONFIG_DEBUG_KERNEL=y
++
++#
++# Memory Debugging
++#
++# 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_STACK_USAGE is not set
++# CONFIG_DEBUG_VM is not set
++CONFIG_DEBUG_MEMORY_INIT=y
++# CONFIG_DEBUG_HIGHMEM is not set
++# CONFIG_DEBUG_SHIRQ is not set
++
++#
++# Debug Lockups and Hangs
++#
++# CONFIG_LOCKUP_DETECTOR is not set
++# CONFIG_DETECT_HUNG_TASK is not set
++CONFIG_PANIC_ON_OOPS=y
++CONFIG_PANIC_ON_OOPS_VALUE=1
++CONFIG_PANIC_TIMEOUT=0
++CONFIG_SCHED_DEBUG=y
++# CONFIG_SCHEDSTATS is not set
++# CONFIG_SCHED_STACK_END_CHECK is not set
++# CONFIG_TIMER_STATS is not set
++
++#
++# Lock Debugging (spinlocks, mutexes, etc...)
++#
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_LOCK_STAT is not set
++# CONFIG_DEBUG_ATOMIC_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_LOCK_TORTURE_TEST is not set
++CONFIG_STACKTRACE=y
++# CONFIG_DEBUG_KOBJECT is not set
++CONFIG_DEBUG_BUGVERBOSE=y
++# CONFIG_DEBUG_LIST is not set
++# CONFIG_DEBUG_PI_LIST is not set
++# CONFIG_DEBUG_SG is not set
++# CONFIG_DEBUG_NOTIFIERS is not set
++# CONFIG_DEBUG_CREDENTIALS is not set
++
++#
++# RCU Debugging
++#
++# CONFIG_SPARSE_RCU_POINTER is not set
++# CONFIG_TORTURE_TEST is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_RCU_TRACE is not set
++# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_NOTIFIER_ERROR_INJECTION is not set
++# CONFIG_FAULT_INJECTION is not set
++# CONFIG_LATENCYTOP 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 is not set
++
++#
++# Runtime Testing
++#
++# CONFIG_TEST_LIST_SORT is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_RBTREE_TEST is not set
++# CONFIG_INTERVAL_TREE_TEST is not set
++# CONFIG_PERCPU_TEST is not set
++# CONFIG_ATOMIC64_SELFTEST is not set
++# CONFIG_TEST_STRING_HELPERS is not set
++# CONFIG_TEST_KSTRTOX is not set
++# CONFIG_TEST_RHASHTABLE is not set
++# CONFIG_DMA_API_DEBUG is not set
++# CONFIG_TEST_LKM is not set
++# CONFIG_TEST_USER_COPY is not set
++# CONFIG_TEST_BPF is not set
++# CONFIG_TEST_FIRMWARE is not set
++# CONFIG_TEST_UDELAY is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_KGDB is not set
++# CONFIG_ARM_PTDUMP is not set
++CONFIG_STRICT_DEVMEM=y
++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_DEBUG_UART_PL01X is not set
++# CONFIG_DEBUG_UART_8250 is not set
++# CONFIG_DEBUG_UART_BCM63XX is not set
++CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"
++# CONFIG_OC_ETM is not set
++# CONFIG_PID_IN_CONTEXTIDR is not set
++# CONFIG_DEBUG_SET_MODULE_RONX is not set
++# CONFIG_CORESIGHT is not set
++
++#
++# 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_AEAD=y
++CONFIG_CRYPTO_AEAD2=y
++CONFIG_CRYPTO_BLKCIPHER=y
++CONFIG_CRYPTO_BLKCIPHER2=y
++CONFIG_CRYPTO_HASH=y
++CONFIG_CRYPTO_HASH2=y
++CONFIG_CRYPTO_RNG=y
++CONFIG_CRYPTO_RNG2=y
++CONFIG_CRYPTO_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_WORKQUEUE=y
++# CONFIG_CRYPTO_CRYPTD is not set
++# CONFIG_CRYPTO_MCRYPTD is not set
++# CONFIG_CRYPTO_AUTHENC is not set
++# CONFIG_CRYPTO_TEST is not set
++
++#
++# Authenticated Encryption with Associated Data
++#
++CONFIG_CRYPTO_CCM=y
++# CONFIG_CRYPTO_GCM is not set
++CONFIG_CRYPTO_SEQIV=y
++
++#
++# Block modes
++#
++# CONFIG_CRYPTO_CBC is not set
++CONFIG_CRYPTO_CTR=y
++# 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_CMAC is not set
++# CONFIG_CRYPTO_HMAC is not set
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_VMAC is not set
++
++#
++# Digest
++#
++CONFIG_CRYPTO_CRC32C=y
++# CONFIG_CRYPTO_CRC32 is not set
++# CONFIG_CRYPTO_CRCT10DIF 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_SHA1_ARM_NEON is not set
++# CONFIG_CRYPTO_SHA256 is not set
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_SHA512_ARM_NEON 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_AES_ARM_BS is not set
++# CONFIG_CRYPTO_ANUBIS is not set
++CONFIG_CRYPTO_ARC4=y
++# 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=y
++# CONFIG_CRYPTO_ZLIB is not set
++CONFIG_CRYPTO_LZO=y
++# CONFIG_CRYPTO_LZ4 is not set
++# CONFIG_CRYPTO_LZ4HC is not set
++
++#
++# Random Number Generation
++#
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++# CONFIG_CRYPTO_DRBG_MENU is not set
++# CONFIG_CRYPTO_USER_API_HASH is not set
++# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
++CONFIG_CRYPTO_HW=y
++# CONFIG_BINARY_PRINTF is not set
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++CONFIG_GENERIC_STRNCPY_FROM_USER=y
++CONFIG_GENERIC_STRNLEN_USER=y
++CONFIG_GENERIC_NET_UTILS=y
++CONFIG_GENERIC_PCI_IOMAP=y
++CONFIG_GENERIC_IO=y
++CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
++# CONFIG_CRC_CCITT is not set
++CONFIG_CRC16=y
++# CONFIG_CRC_T10DIF is not set
++# 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=y
++# CONFIG_CRC8 is not set
++# CONFIG_AUDIT_ARCH_COMPAT_GENERIC is not set
++# CONFIG_RANDOM32_SELFTEST is not set
++CONFIG_ZLIB_INFLATE=y
++CONFIG_ZLIB_DEFLATE=y
++CONFIG_LZO_COMPRESS=y
++CONFIG_LZO_DECOMPRESS=y
++CONFIG_LZ4_DECOMPRESS=y
++CONFIG_XZ_DEC=y
++CONFIG_XZ_DEC_X86=y
++CONFIG_XZ_DEC_POWERPC=y
++CONFIG_XZ_DEC_IA64=y
++CONFIG_XZ_DEC_ARM=y
++CONFIG_XZ_DEC_ARMTHUMB=y
++CONFIG_XZ_DEC_SPARC=y
++CONFIG_XZ_DEC_BCJ=y
++# CONFIG_XZ_DEC_TEST is not set
++CONFIG_DECOMPRESS_GZIP=y
++CONFIG_DECOMPRESS_BZIP2=y
++CONFIG_DECOMPRESS_LZMA=y
++CONFIG_DECOMPRESS_XZ=y
++CONFIG_DECOMPRESS_LZO=y
++CONFIG_DECOMPRESS_LZ4=y
++CONFIG_GENERIC_ALLOCATOR=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT_MAP=y
++CONFIG_HAS_DMA=y
++CONFIG_DQL=y
++CONFIG_NLATTR=y
++CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
++CONFIG_AVERAGE=y
++# CONFIG_CORDIC is not set
++# CONFIG_DDR is not set
++CONFIG_LIBFDT=y
++CONFIG_ARCH_HAS_SG_CHAIN=y
++# CONFIG_VIRTUALIZATION is not set
+diff --git a/arch/arm/configs/hi3559_single_nand_defconfig b/arch/arm/configs/hi3559_single_nand_defconfig
+new file mode 100644
+index 0000000..02fae8f
+--- /dev/null
++++ b/arch/arm/configs/hi3559_single_nand_defconfig
+@@ -0,0 +1,2615 @@
++#
++# Automatically generated file; DO NOT EDIT.
++# Linux/arm 3.18.20 Kernel Configuration
++#
++CONFIG_ARM=y
++CONFIG_ARM_HAS_SG_CHAIN=y
++CONFIG_MIGHT_HAVE_PCI=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=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_XCHGADD_ALGORITHM=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_NEED_DMA_MAP_STATE=y
++CONFIG_ARCH_SUPPORTS_UPROBES=y
++CONFIG_VECTORS_BASE=0xffff0000
++CONFIG_ARM_PATCH_PHYS_VIRT=y
++CONFIG_GENERIC_BUG=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++CONFIG_IRQ_WORK=y
++CONFIG_BUILDTIME_EXTABLE_SORT=y
++
++#
++# General setup
++#
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_CROSS_COMPILE=""
++# CONFIG_COMPILE_TEST is not set
++CONFIG_LOCALVERSION=""
++# CONFIG_LOCALVERSION_AUTO is not set
++CONFIG_HAVE_KERNEL_GZIP=y
++CONFIG_HAVE_KERNEL_LZMA=y
++CONFIG_HAVE_KERNEL_XZ=y
++CONFIG_HAVE_KERNEL_LZO=y
++CONFIG_HAVE_KERNEL_LZ4=y
++CONFIG_KERNEL_GZIP=y
++# CONFIG_KERNEL_LZMA is not set
++# CONFIG_KERNEL_XZ is not set
++# CONFIG_KERNEL_LZO is not set
++# CONFIG_KERNEL_LZ4 is not set
++# CONFIG_HW_DECOMPRESS is not set
++CONFIG_SOFT_DECOMPRESS=y
++CONFIG_DEFAULT_HOSTNAME="(none)"
++CONFIG_SWAP=y
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++# CONFIG_POSIX_MQUEUE is not set
++CONFIG_CROSS_MEMORY_ATTACH=y
++# CONFIG_FHANDLE is not set
++CONFIG_USELIB=y
++# CONFIG_AUDIT is not set
++CONFIG_HAVE_ARCH_AUDITSYSCALL=y
++
++#
++# IRQ subsystem
++#
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_GENERIC_IRQ_SHOW=y
++CONFIG_HARDIRQS_SW_RESEND=y
++CONFIG_IRQ_DOMAIN=y
++CONFIG_HANDLE_DOMAIN_IRQ=y
++CONFIG_IRQ_FORCED_THREADING=y
++CONFIG_SPARSE_IRQ=y
++CONFIG_GENERIC_CLOCKEVENTS=y
++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
++
++#
++# Timers subsystem
++#
++CONFIG_TICK_ONESHOT=y
++CONFIG_NO_HZ_COMMON=y
++# CONFIG_HZ_PERIODIC is not set
++CONFIG_NO_HZ_IDLE=y
++CONFIG_NO_HZ=y
++# CONFIG_HIGH_RES_TIMERS is not set
++
++#
++# CPU/Task time and stats accounting
++#
++CONFIG_TICK_CPU_ACCOUNTING=y
++# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set
++# CONFIG_IRQ_TIME_ACCOUNTING is not set
++# CONFIG_BSD_PROCESS_ACCT is not set
++# CONFIG_TASKSTATS is not set
++
++#
++# RCU Subsystem
++#
++CONFIG_TINY_RCU=y
++# CONFIG_PREEMPT_RCU is not set
++# CONFIG_TASKS_RCU is not set
++# CONFIG_RCU_STALL_COMMON is not set
++# CONFIG_TREE_RCU_TRACE is not set
++# CONFIG_BUILD_BIN2C is not set
++# CONFIG_IKCONFIG is not set
++CONFIG_LOG_BUF_SHIFT=17
++CONFIG_GENERIC_SCHED_CLOCK=y
++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_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_USER_NS is not set
++CONFIG_PID_NS=y
++CONFIG_NET_NS=y
++# 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=y
++CONFIG_RD_LZMA=y
++CONFIG_RD_XZ=y
++CONFIG_RD_LZO=y
++CONFIG_RD_LZ4=y
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++CONFIG_HAVE_UID16=y
++CONFIG_BPF=y
++# CONFIG_EXPERT is not set
++CONFIG_UID16=y
++# CONFIG_SGETMASK_SYSCALL is not set
++CONFIG_SYSFS_SYSCALL=y
++# CONFIG_SYSCTL_SYSCALL is not set
++CONFIG_KALLSYMS=y
++# CONFIG_KALLSYMS_ALL is not set
++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_BPF_SYSCALL is not set
++CONFIG_SHMEM=y
++CONFIG_AIO=y
++CONFIG_ADVISE_SYSCALLS=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 is not set
++# CONFIG_SLAB is not set
++CONFIG_SLUB=y
++# CONFIG_PROFILING is not set
++CONFIG_HAVE_OPROFILE=y
++# CONFIG_KPROBES is not set
++# CONFIG_JUMP_LABEL is not set
++# CONFIG_UPROBES is not set
++# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
++CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
++CONFIG_ARCH_USE_BUILTIN_BSWAP=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_GENERIC_SMP_IDLE_THREAD=y
++CONFIG_GENERIC_IDLE_POLL_SETUP=y
++CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
++CONFIG_HAVE_CLK=y
++CONFIG_HAVE_DMA_API_DEBUG=y
++CONFIG_HAVE_PERF_REGS=y
++CONFIG_HAVE_PERF_USER_STACK_DUMP=y
++CONFIG_HAVE_ARCH_JUMP_LABEL=y
++CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
++CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
++CONFIG_HAVE_CC_STACKPROTECTOR=y
++# CONFIG_CC_STACKPROTECTOR is not set
++CONFIG_CC_STACKPROTECTOR_NONE=y
++# CONFIG_CC_STACKPROTECTOR_REGULAR is not set
++# CONFIG_CC_STACKPROTECTOR_STRONG is not set
++CONFIG_HAVE_CONTEXT_TRACKING=y
++CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
++CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
++CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
++CONFIG_MODULES_USE_ELF_REL=y
++CONFIG_CLONE_BACKWARDS=y
++CONFIG_OLD_SIGSUSPEND3=y
++CONFIG_OLD_SIGACTION=y
++
++#
++# GCOV-based kernel profiling
++#
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_SLABINFO=y
++CONFIG_RT_MUTEXES=y
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++# CONFIG_MODULE_FORCE_LOAD is not set
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++# CONFIG_MODULE_SIG is not set
++# CONFIG_MODULE_COMPRESS is not set
++CONFIG_BLOCK=y
++CONFIG_LBDAF=y
++CONFIG_BLK_DEV_BSG=y
++# CONFIG_BLK_DEV_BSGLIB is not set
++# CONFIG_BLK_DEV_INTEGRITY is not set
++CONFIG_BLK_CMDLINE_PARSER=y
++
++#
++# Partition Types
++#
++CONFIG_PARTITION_ADVANCED=y
++# CONFIG_ACORN_PARTITION is not set
++# CONFIG_AIX_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=y
++# CONFIG_SYSV68_PARTITION is not set
++CONFIG_CMDLINE_PARTITION=y
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++CONFIG_DEFAULT_DEADLINE=y
++# CONFIG_DEFAULT_CFQ is not set
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="deadline"
++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_ARCH_SUPPORTS_ATOMIC_RMW=y
++CONFIG_FREEZER=y
++
++#
++# System Type
++#
++CONFIG_MMU=y
++CONFIG_ARCH_MULTIPLATFORM=y
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_AT91 is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_GEMINI is not set
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_IOP13XX is not set
++# CONFIG_ARCH_IOP32X is not set
++# CONFIG_ARCH_IOP33X is not set
++# CONFIG_ARCH_IXP4XX is not set
++# CONFIG_ARCH_DOVE is not set
++# CONFIG_ARCH_MV78XX0 is not set
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_MMP is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_W90X900 is not set
++# CONFIG_ARCH_LPC32XX is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_MSM is not set
++# CONFIG_ARCH_SHMOBILE_LEGACY 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_DAVINCI is not set
++# CONFIG_ARCH_OMAP1 is not set
++
++#
++# Multiple platform selection
++#
++
++#
++# CPU Core family selection
++#
++# CONFIG_ARCH_MULTI_V6 is not set
++CONFIG_ARCH_MULTI_V7=y
++CONFIG_ARCH_MULTI_V6_V7=y
++# CONFIG_ARCH_MULTI_CPU_AUTO is not set
++# CONFIG_ARCH_VIRT is not set
++# CONFIG_ARCH_MVEBU is not set
++# CONFIG_ARCH_BCM is not set
++# CONFIG_ARCH_BERLIN is not set
++# CONFIG_ARCH_HIGHBANK is not set
++CONFIG_ARCH_HISI=y
++
++#
++# Hisilicon platform type
++#
++# CONFIG_ARCH_HI3xxx is not set
++# CONFIG_ARCH_HIP04 is not set
++# CONFIG_ARCH_HIX5HD2 is not set
++# CONFIG_ARCH_HI3519 is not set
++# CONFIG_ARCH_HI3519V101 is not set
++# CONFIG_ARCH_HI3516AV200 is not set
++CONFIG_ARCH_HI3559=y
++# CONFIG_ARCH_HI3556 is not set
++# CONFIG_ARCH_HI3536C is not set
++# CONFIG_ARCH_HI3531D is not set
++# CONFIG_ARCH_HI3521D is not set
++# CONFIG_ARCH_KEYSTONE is not set
++# CONFIG_ARCH_MESON is not set
++# CONFIG_ARCH_MXC is not set
++# CONFIG_ARCH_MEDIATEK is not set
++
++#
++# TI OMAP/AM/DM/DRA Family
++#
++# CONFIG_ARCH_OMAP3 is not set
++# CONFIG_ARCH_OMAP4 is not set
++# CONFIG_SOC_OMAP5 is not set
++# CONFIG_SOC_AM33XX is not set
++# CONFIG_SOC_AM43XX is not set
++# CONFIG_SOC_DRA7XX is not set
++# CONFIG_ARCH_QCOM is not set
++# CONFIG_ARCH_ROCKCHIP is not set
++# CONFIG_ARCH_SOCFPGA is not set
++# CONFIG_PLAT_SPEAR is not set
++# CONFIG_ARCH_STI is not set
++# CONFIG_ARCH_S5PV210 is not set
++# CONFIG_ARCH_EXYNOS is not set
++# CONFIG_ARCH_SHMOBILE_MULTI is not set
++# CONFIG_ARCH_SUNXI is not set
++# CONFIG_ARCH_SIRF is not set
++# CONFIG_ARCH_TEGRA is not set
++# CONFIG_ARCH_U8500 is not set
++# CONFIG_ARCH_VEXPRESS is not set
++# CONFIG_ARCH_WM8850 is not set
++# CONFIG_ARCH_ZYNQ is not set
++CONFIG_ARM_TIMER_SP804=y
++
++#
++# Processor Type
++#
++CONFIG_CPU_V7=y
++CONFIG_CPU_32v6K=y
++CONFIG_CPU_32v7=y
++CONFIG_CPU_ABRT_EV7=y
++CONFIG_CPU_PABRT_V7=y
++CONFIG_CPU_CACHE_V7=y
++CONFIG_CPU_CACHE_VIPT=y
++CONFIG_CPU_COPY_V6=y
++CONFIG_CPU_TLB_V7=y
++CONFIG_CPU_HAS_ASID=y
++CONFIG_CPU_CP15=y
++CONFIG_CPU_CP15_MMU=y
++
++#
++# Processor Features
++#
++# CONFIG_ARM_LPAE is not set
++# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
++CONFIG_ARM_THUMB=y
++# CONFIG_ARM_THUMBEE is not set
++CONFIG_ARM_VIRT_EXT=y
++CONFIG_SWP_EMULATE=y
++# CONFIG_CPU_ICACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_DISABLE is not set
++# CONFIG_CPU_BPREDICT_DISABLE is not set
++CONFIG_KUSER_HELPERS=y
++CONFIG_MIGHT_HAVE_CACHE_L2X0=y
++# CONFIG_CACHE_L2X0 is not set
++CONFIG_ARM_L1_CACHE_SHIFT_6=y
++CONFIG_ARM_L1_CACHE_SHIFT=6
++CONFIG_ARM_DMA_MEM_BUFFERABLE=y
++CONFIG_MULTI_IRQ_HANDLER=y
++# CONFIG_ARM_ERRATA_430973 is not set
++# CONFIG_ARM_ERRATA_720789 is not set
++# CONFIG_ARM_ERRATA_754322 is not set
++# CONFIG_ARM_ERRATA_775420 is not set
++# CONFIG_ARM_ERRATA_773022 is not set
++
++#
++# Bus support
++#
++CONFIG_ARM_AMBA=y
++# CONFIG_PCI is not set
++# CONFIG_PCI_SYSCALL is not set
++# CONFIG_PCCARD is not set
++
++#
++# Kernel Features
++#
++CONFIG_HAVE_SMP=y
++# CONFIG_SMP is not set
++CONFIG_DISABLE_CPU_SCHED_DOMAIN_BALANCE=y
++CONFIG_HAVE_ARM_ARCH_TIMER=y
++CONFIG_VMSPLIT_3G=y
++# CONFIG_VMSPLIT_2G is not set
++# CONFIG_VMSPLIT_1G is not set
++CONFIG_PAGE_OFFSET=0xC0000000
++# CONFIG_ARM_PSCI is not set
++CONFIG_ARCH_NR_GPIO=0
++CONFIG_PREEMPT_NONE=y
++# CONFIG_PREEMPT_VOLUNTARY is not set
++# CONFIG_PREEMPT is not set
++CONFIG_HZ_FIXED=0
++# CONFIG_HZ_100 is not set
++# CONFIG_HZ_200 is not set
++# CONFIG_HZ_250 is not set
++# CONFIG_HZ_300 is not set
++# CONFIG_HZ_500 is not set
++CONFIG_HZ_1000=y
++CONFIG_HZ=1000
++# CONFIG_SCHED_HRTICK is not set
++# CONFIG_THUMB2_KERNEL is not set
++CONFIG_AEABI=y
++# CONFIG_OABI_COMPAT is not set
++# 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_ARCH_WANT_GENERAL_HUGETLB=y
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_HAVE_MEMBLOCK=y
++CONFIG_NO_BOOTMEM=y
++CONFIG_MEMORY_ISOLATION=y
++# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=4
++CONFIG_COMPACTION=y
++CONFIG_MIGRATION=y
++# CONFIG_PHYS_ADDR_T_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_BOUNCE=y
++# CONFIG_KSM is not set
++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
++CONFIG_NEED_PER_CPU_KM=y
++# CONFIG_CLEANCACHE is not set
++# CONFIG_FRONTSWAP is not set
++CONFIG_CMA=y
++# CONFIG_CMA_DEBUG is not set
++CONFIG_CMA_AREAS=7
++# CONFIG_ZPOOL is not set
++# CONFIG_ZBUD is not set
++# CONFIG_ZSMALLOC 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_SWIOTLB=y
++CONFIG_IOMMU_HELPER=y
++# CONFIG_XEN is not set
++# CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART is not set
++
++#
++# Boot options
++#
++CONFIG_USE_OF=y
++CONFIG_ATAGS=y
++# CONFIG_DEPRECATED_PARAM_STRUCT is not set
++# CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE is not set
++CONFIG_ZBOOT_ROM_TEXT=0
++CONFIG_ZBOOT_ROM_BSS=0
++CONFIG_ARM_APPENDED_DTB=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_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_GOV_COMMON=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_USERSPACE is not set
++CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
++# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE is not set
++CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
++CONFIG_CPU_FREQ_GOV_POWERSAVE=y
++CONFIG_CPU_FREQ_GOV_USERSPACE=y
++CONFIG_CPU_FREQ_GOV_ONDEMAND=y
++CONFIG_CPU_FREQ_GOV_INTERACTIVE=y
++# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
++# CONFIG_CPUFREQ_DT is not set
++
++#
++# ARM CPU frequency scaling drivers
++#
++# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set
++
++#
++# CPU Idle
++#
++# CONFIG_CPU_IDLE is not set
++# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++CONFIG_VFP=y
++CONFIG_VFPv3=y
++CONFIG_NEON=y
++CONFIG_KERNEL_MODE_NEON=y
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
++CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
++CONFIG_BINFMT_SCRIPT=y
++# CONFIG_HAVE_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
++CONFIG_COREDUMP=y
++
++#
++# Power management options
++#
++CONFIG_SUSPEND=y
++CONFIG_SUSPEND_FREEZER=y
++CONFIG_WAKELOCK=y
++CONFIG_HIBERNATE_CALLBACKS=y
++CONFIG_HISI_SNAPSHOT_BOOT=y
++# CONFIG_DEFAULT_MTD is not set
++CONFIG_DEFAULT_DDR=y
++CONFIG_SNAPSHOT_BUF_START=0x8a000000
++CONFIG_SNAPSHOT_BUF_SIZE=0x4000000
++CONFIG_HIBERNATION=y
++CONFIG_GZIP_COMPRESS=y
++CONFIG_PM_STD_PARTITION=""
++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_OPP=y
++CONFIG_PM_CLK=y
++# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set
++CONFIG_CPU_PM=y
++# CONFIG_SUSPEND_TIME is not set
++CONFIG_ARCH_SUSPEND_POSSIBLE=y
++CONFIG_ARM_CPU_SUSPEND=y
++CONFIG_ARCH_HIBERNATION_POSSIBLE=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_NET_IP_TUNNEL=m
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_NET_IPVTI is not set
++# CONFIG_NET_UDP_TUNNEL is not set
++# CONFIG_NET_FOU is not set
++# CONFIG_GENEVE 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=y
++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=y
++# 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_VTI 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_ANDROID_PARANOID_NETWORK is not set
++CONFIG_NET_ACTIVITY_STATS=y
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NET_PTP_CLASSIFY 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_NF_TABLES is not set
++# CONFIG_NETFILTER_XTABLES is not set
++# CONFIG_IP_SET is not set
++# CONFIG_IP_VS is not set
++
++#
++# IP: Netfilter Configuration
++#
++# CONFIG_NF_DEFRAG_IPV4 is not set
++# CONFIG_NF_LOG_ARP is not set
++# CONFIG_NF_LOG_IPV4 is not set
++# CONFIG_NF_REJECT_IPV4 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_NF_REJECT_IPV6 is not set
++# CONFIG_NF_LOG_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_HAVE_NET_DSA=y
++# 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_PHONET is not set
++# CONFIG_6LOWPAN 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_VSOCKETS is not set
++# CONFIG_NETLINK_MMAP is not set
++# CONFIG_NETLINK_DIAG is not set
++# CONFIG_NET_MPLS_GSO is not set
++# CONFIG_HSR is not set
++# CONFIG_CGROUP_NET_PRIO is not set
++# CONFIG_CGROUP_NET_CLASSID is not set
++CONFIG_NET_RX_BUSY_POLL=y
++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 is not set
++CONFIG_DEVTMPFS=y
++CONFIG_DEVTMPFS_MOUNT=y
++CONFIG_STANDALONE=y
++# CONFIG_PREVENT_FIRMWARE_BUILD is not set
++CONFIG_FW_LOADER=y
++# CONFIG_FIRMWARE_IN_KERNEL is not set
++CONFIG_EXTRA_FIRMWARE=""
++# CONFIG_FW_LOADER_USER_HELPER_FALLBACK is not set
++CONFIG_ALLOW_DEV_COREDUMP=y
++# 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_HAVE_CPU_AUTOPROBE is not set
++CONFIG_REGMAP=y
++CONFIG_REGMAP_MMIO=y
++CONFIG_DMA_SHARED_BUFFER=y
++# CONFIG_FENCE_TRACE is not set
++CONFIG_DMA_CMA=y
++
++#
++# Default contiguous memory area size:
++#
++CONFIG_CMA_SIZE_MBYTES=16
++CONFIG_CMA_SIZE_SEL_MBYTES=y
++# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set
++# CONFIG_CMA_SIZE_SEL_MIN is not set
++# CONFIG_CMA_SIZE_SEL_MAX is not set
++CONFIG_CMA_ALIGNMENT=8
++
++#
++# Bus devices
++#
++# CONFIG_BRCMSTB_GISB_ARB is not set
++CONFIG_ARM_CCI=y
++# CONFIG_VEXPRESS_CONFIG 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=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_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
++CONFIG_HIFMC=y
++# CONFIG_HIFMC_SPI_NAND is not set
++CONFIG_HIFMC_NAND=y
++
++#
++# 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_SST25L is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_PHRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++# CONFIG_MTD_BLOCK2MTD is not set
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOCG3 is not set
++CONFIG_MTD_NAND_IDS=y
++CONFIG_MTD_NAND_ECC=y
++# CONFIG_MTD_NAND_ECC_SMC is not set
++CONFIG_MTD_NAND=y
++# CONFIG_MTD_NAND_ECC_BCH is not set
++# CONFIG_MTD_SM_COMMON is not set
++# CONFIG_MTD_NAND_DENALI is not set
++# CONFIG_MTD_NAND_GPIO is not set
++# CONFIG_MTD_NAND_OMAP_BCH_BUILD is not set
++# CONFIG_MTD_NAND_DISKONCHIP is not set
++# CONFIG_MTD_NAND_DOCG4 is not set
++# CONFIG_MTD_NAND_NANDSIM is not set
++# CONFIG_MTD_NAND_PLATFORM is not set
++# CONFIG_HISI_NAND_FS_MAY_NO_YAFFS2 is not set
++# CONFIG_HISI_NAND_ECC_STATUS_REPORT is not set
++# CONFIG_MTD_NAND_HINFC610 is not set
++CONFIG_HIFMC100_NAND=y
++CONFIG_HIFMC100_MAX_NAND_CHIP=1
++# CONFIG_HIFMC100_NAND_EDO_MODE is not set
++CONFIG_RW_H_WIDTH=10
++CONFIG_R_L_WIDTH=10
++CONFIG_W_L_WIDTH=10
++# CONFIG_HIFMC100_NAND_HARDWARE_PAGESIZE_ECC is not set
++CONFIG_HIFMC100_NAND_AUTO_PAGESIZE_ECC=y
++# CONFIG_HIFMC100_NAND_PAGESIZE_AUTO_ECC_NONE is not set
++# CONFIG_MTD_ONENAND is not set
++
++#
++# LPDDR & LPDDR2 PCM memory drivers
++#
++# CONFIG_MTD_LPDDR is not set
++# CONFIG_MTD_LPDDR2_NVM is not set
++# CONFIG_MTD_SPI_NOR is not set
++CONFIG_MTD_UBI=y
++CONFIG_MTD_UBI_WL_THRESHOLD=4096
++CONFIG_MTD_UBI_BEB_LIMIT=20
++# CONFIG_MTD_UBI_FASTMAP is not set
++# CONFIG_MTD_UBI_GLUEBI is not set
++# CONFIG_MTD_UBI_BLOCK is not set
++CONFIG_DTC=y
++CONFIG_OF=y
++
++#
++# Device Tree and Open Firmware support
++#
++# 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_NET=y
++CONFIG_OF_MDIO=y
++CONFIG_OF_MTD=y
++CONFIG_OF_RESERVED_MEM=y
++CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
++# CONFIG_PARPORT is not set
++CONFIG_BLK_DEV=y
++# CONFIG_BLK_DEV_NULL_BLK is not set
++# CONFIG_BLK_DEV_COW_COMMON is not set
++# CONFIG_BLK_DEV_LOOP 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=65536
++# 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_DUMMY_IRQ 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_UID_STAT is not set
++# CONFIG_BMP085_I2C is not set
++# CONFIG_BMP085_SPI is not set
++# CONFIG_USB_SWITCH_FSA9480 is not set
++# CONFIG_LATTICE_ECP3_CONFIG is not set
++# CONFIG_SRAM is not set
++# CONFIG_C2PORT is not set
++
++#
++# EEPROM support
++#
++# CONFIG_EEPROM_AT24 is not set
++# CONFIG_EEPROM_AT25 is not set
++# CONFIG_EEPROM_LEGACY is not set
++# CONFIG_EEPROM_MAX6875 is not set
++# CONFIG_EEPROM_93CX6 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
++
++#
++# Intel MIC Bus Driver
++#
++
++#
++# Intel MIC Host Driver
++#
++
++#
++# Intel MIC Card Driver
++#
++# CONFIG_ECHO is not set
++# CONFIG_CXL_BASE is not set
++
++#
++# hisi 'himm/himd.l/himc'support
++#
++# CONFIG_HISI_REG 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_NETLINK is not set
++# CONFIG_SCSI_MQ_DEFAULT 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_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 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_NET_CORE=y
++# CONFIG_BONDING is not set
++# CONFIG_DUMMY is not set
++# CONFIG_EQUALIZER is not set
++# CONFIG_NET_TEAM is not set
++# CONFIG_MACVLAN is not set
++# CONFIG_VXLAN is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_TUN is not set
++# CONFIG_VETH is not set
++# CONFIG_NLMON is not set
++
++#
++# 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_NET_DSA_MV88E6171 is not set
++# CONFIG_NET_DSA_BCM_SF2 is not set
++# CONFIG_ETHERNET is not set
++CONFIG_PHYLIB=y
++
++#
++# MII PHY device drivers
++#
++# CONFIG_AT803X_PHY is not set
++# CONFIG_AMD_PHY is not set
++# CONFIG_AMD_XGBE_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 is not set
++# CONFIG_BROADCOM_PHY is not set
++# CONFIG_BCM7XXX_PHY is not set
++# CONFIG_BCM87XX_PHY is not set
++# CONFIG_ICPLUS_PHY is not set
++# CONFIG_REALTEK_PHY is not set
++# CONFIG_NATIONAL_PHY is not set
++# CONFIG_STE10XP is not set
++# CONFIG_LSI_ET1011C_PHY is not set
++# CONFIG_MICREL_PHY is not set
++# CONFIG_FIXED_PHY is not set
++# CONFIG_MDIO_BITBANG is not set
++# CONFIG_MDIO_BUS_MUX_GPIO is not set
++# CONFIG_MDIO_BUS_MUX_MMIOREG is not set
++# CONFIG_MDIO_BCM_UNIMAC is not set
++# CONFIG_MDIO_HISI_FEMAC is not set
++# CONFIG_MDIO_HISI_GEMAC is not set
++# CONFIG_MICREL_KS8995MA is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++CONFIG_USB_NET_DRIVERS=y
++# 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_RTL8152 is not set
++# CONFIG_USB_USBNET is not set
++# CONFIG_USB_IPHETH is not set
++CONFIG_WLAN=y
++# CONFIG_WIFI_CONTROL_FUNC is not set
++# 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 is not set
++# CONFIG_INPUT_SPARSEKMAP is not set
++# CONFIG_INPUT_MATRIXKMAP is not set
++
++#
++# Userland interfaces
++#
++CONFIG_INPUT_MOUSEDEV=y
++CONFIG_INPUT_MOUSEDEV_PSAUX=y
++CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
++CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
++# CONFIG_INPUT_JOYDEV is not set
++CONFIG_INPUT_EVDEV=y
++# CONFIG_INPUT_EVBUG is not set
++# CONFIG_INPUT_KEYRESET is not set
++# CONFIG_INPUT_KEYCOMBO is not set
++
++#
++# Input Device Drivers
++#
++CONFIG_INPUT_KEYBOARD=y
++# CONFIG_KEYBOARD_ADP5588 is not set
++# CONFIG_KEYBOARD_ADP5589 is not set
++CONFIG_KEYBOARD_ATKBD=y
++# CONFIG_KEYBOARD_QT1070 is not set
++# CONFIG_KEYBOARD_QT2160 is not set
++# CONFIG_KEYBOARD_LKKBD is not set
++# CONFIG_KEYBOARD_GPIO is not set
++# CONFIG_KEYBOARD_GPIO_POLLED is not set
++# 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 is not set
++# CONFIG_KEYBOARD_CAP1106 is not set
++CONFIG_INPUT_MOUSE=y
++CONFIG_MOUSE_PS2=y
++CONFIG_MOUSE_PS2_ALPS=y
++CONFIG_MOUSE_PS2_LOGIPS2PP=y
++CONFIG_MOUSE_PS2_SYNAPTICS=y
++CONFIG_MOUSE_PS2_CYPRESS=y
++CONFIG_MOUSE_PS2_TRACKPOINT=y
++# CONFIG_MOUSE_PS2_ELANTECH is not set
++# CONFIG_MOUSE_PS2_SENTELIC is not set
++# CONFIG_MOUSE_PS2_TOUCHKIT is not set
++# CONFIG_MOUSE_SERIAL is not set
++# CONFIG_MOUSE_APPLETOUCH is not set
++# CONFIG_MOUSE_BCM5974 is not set
++# CONFIG_MOUSE_CYAPA is not set
++# CONFIG_MOUSE_VSXXXAA is not set
++# CONFIG_MOUSE_GPIO is not set
++# CONFIG_MOUSE_SYNAPTICS_I2C is not set
++# CONFIG_MOUSE_SYNAPTICS_USB is not set
++# CONFIG_INPUT_JOYSTICK is not set
++# CONFIG_INPUT_TABLET is not set
++# CONFIG_INPUT_TOUCHSCREEN is not set
++# CONFIG_INPUT_MISC is not set
++
++#
++# Hardware I/O ports
++#
++CONFIG_SERIO=y
++CONFIG_SERIO_SERPORT=y
++# CONFIG_SERIO_AMBAKMI is not set
++CONFIG_SERIO_LIBPS2=y
++# CONFIG_SERIO_RAW is not set
++# CONFIG_SERIO_ALTERA_PS2 is not set
++# CONFIG_SERIO_PS2MULT is not set
++# CONFIG_SERIO_ARC_PS2 is not set
++# CONFIG_SERIO_APBPS2 is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++CONFIG_TTY=y
++CONFIG_VT=y
++CONFIG_CONSOLE_TRANSLATIONS=y
++CONFIG_VT_CONSOLE=y
++CONFIG_VT_CONSOLE_SLEEP=y
++CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
++CONFIG_UNIX98_PTYS=y
++# CONFIG_DEVPTS_MULTIPLE_INSTANCES 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_DEVMEM=y
++CONFIG_DEVKMEM=y
++
++#
++# Serial drivers
++#
++CONFIG_SERIAL_EARLYCON=y
++# CONFIG_SERIAL_8250 is not set
++
++#
++# Non-8250 serial port support
++#
++# CONFIG_SERIAL_AMBA_PL010 is not set
++CONFIG_SERIAL_AMBA_PL011=y
++CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
++# CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST is not set
++# 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_SC16IS7XX is not set
++# CONFIG_SERIAL_ALTERA_JTAGUART is not set
++# CONFIG_SERIAL_ALTERA_UART is not set
++# CONFIG_SERIAL_IFX6X60 is not set
++# CONFIG_SERIAL_XILINX_PS_UART is not set
++# CONFIG_SERIAL_ARC is not set
++# CONFIG_SERIAL_FSL_LPUART is not set
++# CONFIG_SERIAL_ST_ASC is not set
++# CONFIG_HVC_DCC is not set
++# CONFIG_IPMI_HANDLER is not set
++CONFIG_HW_RANDOM=y
++# CONFIG_HW_RANDOM_TIMERIOMEM is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++# CONFIG_DCC_TTY is not set
++# CONFIG_XILLYBUS is not set
++
++#
++# I2C support
++#
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++# CONFIG_I2C_COMPAT is not set
++CONFIG_I2C_CHARDEV=y
++CONFIG_I2C_MUX=m
++
++#
++# Multiplexer I2C Chip support
++#
++# CONFIG_I2C_ARB_GPIO_CHALLENGE is not set
++# CONFIG_I2C_MUX_GPIO is not set
++# CONFIG_I2C_MUX_PCA9541 is not set
++# CONFIG_I2C_MUX_PCA954x is not set
++# CONFIG_I2C_HELPER_AUTO is not set
++# CONFIG_I2C_SMBUS is not set
++
++#
++# I2C Algorithms
++#
++# CONFIG_I2C_ALGOBIT is not set
++# CONFIG_I2C_ALGOPCF is not set
++# CONFIG_I2C_ALGOPCA is not set
++
++#
++# I2C Hardware Bus support
++#
++
++#
++# I2C system bus drivers (mostly embedded / system-on-chip)
++#
++# CONFIG_I2C_CBUS_GPIO is not set
++# CONFIG_I2C_DESIGNWARE_PLATFORM is not set
++# CONFIG_I2C_GPIO is not set
++# CONFIG_I2C_HIBVT is not set
++CONFIG_I2C_HISI_V110=y
++# CONFIG_I2C_NOMADIK 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_RK3X 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_ROBOTFUZZ_OSIF 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_CADENCE is not set
++# CONFIG_SPI_GPIO is not set
++# CONFIG_SPI_FSL_SPI is not set
++# CONFIG_SPI_OC_TINY is not set
++CONFIG_SPI_PL022=y
++# CONFIG_SPI_PXA2XX_PCI is not set
++# CONFIG_SPI_ROCKCHIP 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=y
++# CONFIG_SPI_TLE62X0 is not set
++# CONFIG_SPMI is not set
++# CONFIG_HSI is not set
++
++#
++# PPS support
++#
++# CONFIG_PPS is not set
++
++#
++# PPS generators support
++#
++
++#
++# PTP clock support
++#
++# CONFIG_PTP_1588_CLOCK is not set
++
++#
++# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
++#
++CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
++CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
++CONFIG_GPIOLIB=y
++CONFIG_GPIO_DEVRES=y
++CONFIG_OF_GPIO=y
++CONFIG_GPIOLIB_IRQCHIP=y
++# CONFIG_DEBUG_GPIO is not set
++CONFIG_GPIO_SYSFS=y
++
++#
++# Memory mapped GPIO drivers:
++#
++# CONFIG_GPIO_GENERIC_PLATFORM is not set
++# CONFIG_GPIO_DWAPB is not set
++# CONFIG_GPIO_EM is not set
++# CONFIG_GPIO_ZEVIO is not set
++CONFIG_GPIO_PL061=y
++# CONFIG_GPIO_SCH311X is not set
++# CONFIG_GPIO_SYSCON is not set
++# CONFIG_GPIO_GRGPIO is not set
++
++#
++# I2C GPIO expanders:
++#
++# CONFIG_GPIO_MAX7300 is not set
++# CONFIG_GPIO_MAX732X is not set
++# CONFIG_GPIO_PCA953X is not set
++# CONFIG_GPIO_PCF857X is not set
++# CONFIG_GPIO_SX150X is not set
++# CONFIG_GPIO_ADP5588 is not set
++# CONFIG_GPIO_ADNP is not set
++
++#
++# PCI GPIO expanders:
++#
++
++#
++# SPI GPIO expanders:
++#
++# CONFIG_GPIO_MAX7301 is not set
++# CONFIG_GPIO_MCP23S08 is not set
++# CONFIG_GPIO_MC33880 is not set
++# CONFIG_GPIO_74X164 is not set
++
++#
++# AC97 GPIO expanders:
++#
++
++#
++# LPC GPIO expanders:
++#
++
++#
++# MODULbus GPIO expanders:
++#
++
++#
++# USB GPIO expanders:
++#
++# CONFIG_W1 is not set
++CONFIG_POWER_SUPPLY=y
++# CONFIG_POWER_SUPPLY_DEBUG is not set
++# CONFIG_PDA_POWER is not set
++# CONFIG_TEST_POWER is not set
++# CONFIG_BATTERY_DS2780 is not set
++# CONFIG_BATTERY_DS2781 is not set
++# CONFIG_BATTERY_DS2782 is not set
++# CONFIG_BATTERY_SBS is not set
++# CONFIG_BATTERY_BQ27x00 is not set
++# CONFIG_BATTERY_MAX17040 is not set
++# CONFIG_BATTERY_MAX17042 is not set
++# CONFIG_CHARGER_MAX8903 is not set
++# CONFIG_CHARGER_LP8727 is not set
++# CONFIG_CHARGER_GPIO is not set
++# CONFIG_CHARGER_BQ2415X is not set
++# CONFIG_CHARGER_BQ24190 is not set
++# CONFIG_CHARGER_BQ24735 is not set
++# CONFIG_CHARGER_SMB347 is not set
++CONFIG_POWER_RESET=y
++# CONFIG_POWER_RESET_BRCMSTB is not set
++# CONFIG_POWER_RESET_GPIO is not set
++# CONFIG_POWER_RESET_GPIO_RESTART is not set
++CONFIG_POWER_RESET_HISI=y
++# CONFIG_POWER_RESET_LTC2952 is not set
++# CONFIG_POWER_RESET_RESTART is not set
++# CONFIG_POWER_RESET_VERSATILE is not set
++# CONFIG_POWER_RESET_SYSCON is not set
++# CONFIG_POWER_AVS is not set
++# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
++# CONFIG_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=y
++# CONFIG_MFD_AS3711 is not set
++# CONFIG_MFD_AS3722 is not set
++# CONFIG_PMIC_ADP5520 is not set
++# CONFIG_MFD_AAT2870_CORE is not set
++# CONFIG_MFD_BCM590XX is not set
++# CONFIG_MFD_AXP20X is not set
++# CONFIG_MFD_CROS_EC is not set
++# CONFIG_MFD_ASIC3 is not set
++# CONFIG_PMIC_DA903X is not set
++# CONFIG_MFD_DA9052_SPI is not set
++# CONFIG_MFD_DA9052_I2C is not set
++# CONFIG_MFD_DA9055 is not set
++# CONFIG_MFD_DA9063 is not set
++# CONFIG_MFD_MC13XXX_SPI is not set
++# CONFIG_MFD_MC13XXX_I2C is not set
++# CONFIG_MFD_HI6421_PMIC is not set
++CONFIG_MFD_HISI_FMC=y
++# CONFIG_HTC_EGPIO is not set
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_HTC_I2CPLD is not set
++# CONFIG_INTEL_SOC_PMIC is not set
++# CONFIG_MFD_KEMPLD is not set
++# CONFIG_MFD_88PM800 is not set
++# CONFIG_MFD_88PM805 is not set
++# CONFIG_MFD_88PM860X is not set
++# CONFIG_MFD_MAX14577 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_MENF21BMC is not set
++# CONFIG_EZX_PCAP is not set
++# CONFIG_MFD_VIPERBOARD is not set
++# CONFIG_MFD_RETU is not set
++# CONFIG_MFD_PCF50633 is not set
++# CONFIG_MFD_PM8921_CORE is not set
++# CONFIG_MFD_RTSX_USB is not set
++# CONFIG_MFD_RC5T583 is not set
++# CONFIG_MFD_RK808 is not set
++# CONFIG_MFD_RN5T618 is not set
++# CONFIG_MFD_SEC_CORE is not set
++# CONFIG_MFD_SI476X_CORE is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_MFD_SMSC is not set
++# CONFIG_ABX500_CORE is not set
++# CONFIG_MFD_STMPE is not set
++CONFIG_MFD_SYSCON=y
++# CONFIG_MFD_TI_AM335X_TSCADC is not set
++# CONFIG_MFD_LP3943 is not set
++# CONFIG_MFD_LP8788 is not set
++# CONFIG_MFD_PALMAS is not set
++# CONFIG_TPS6105X is not set
++# CONFIG_TPS65010 is not set
++# CONFIG_TPS6507X is not set
++# CONFIG_MFD_TPS65090 is not set
++# CONFIG_MFD_TPS65217 is not set
++# CONFIG_MFD_TPS65218 is not set
++# CONFIG_MFD_TPS6586X is not set
++# CONFIG_MFD_TPS65910 is not set
++# CONFIG_MFD_TPS65912 is not set
++# CONFIG_MFD_TPS65912_I2C is not set
++# CONFIG_MFD_TPS65912_SPI is not set
++# CONFIG_MFD_TPS80031 is not set
++# CONFIG_TWL4030_CORE is not set
++# CONFIG_TWL6040_CORE is not set
++# CONFIG_MFD_WL1273_CORE is not set
++# CONFIG_MFD_LM3533 is not set
++# CONFIG_MFD_TC3589X is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_MFD_T7L66XB is not set
++# CONFIG_MFD_TC6387XB is not set
++# CONFIG_MFD_TC6393XB is not set
++# CONFIG_MFD_ARIZONA_I2C is not set
++# CONFIG_MFD_ARIZONA_SPI is not set
++# CONFIG_MFD_WM8400 is not set
++# CONFIG_MFD_WM831X_I2C is not set
++# CONFIG_MFD_WM831X_SPI is not set
++# CONFIG_MFD_WM8350_I2C is not set
++# CONFIG_MFD_WM8994 is not set
++CONFIG_REGULATOR=y
++# CONFIG_REGULATOR_DEBUG is not set
++# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
++# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
++# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
++# CONFIG_REGULATOR_ACT8865 is not set
++# CONFIG_REGULATOR_AD5398 is not set
++# CONFIG_REGULATOR_ANATOP is not set
++# CONFIG_REGULATOR_DA9210 is not set
++# CONFIG_REGULATOR_DA9211 is not set
++# CONFIG_REGULATOR_FAN53555 is not set
++# CONFIG_REGULATOR_GPIO is not set
++# CONFIG_REGULATOR_ISL9305 is not set
++# CONFIG_REGULATOR_ISL6271A is not set
++# CONFIG_REGULATOR_LP3971 is not set
++# CONFIG_REGULATOR_LP3972 is not set
++# CONFIG_REGULATOR_LP872X is not set
++# CONFIG_REGULATOR_LP8755 is not set
++# CONFIG_REGULATOR_LTC3589 is not set
++# CONFIG_REGULATOR_MAX1586 is not set
++# CONFIG_REGULATOR_MAX8649 is not set
++# CONFIG_REGULATOR_MAX8660 is not set
++# CONFIG_REGULATOR_MAX8952 is not set
++# CONFIG_REGULATOR_MAX8973 is not set
++# CONFIG_REGULATOR_PFUZE100 is not set
++# CONFIG_REGULATOR_TPS51632 is not set
++# CONFIG_REGULATOR_TPS62360 is not set
++# CONFIG_REGULATOR_TPS65023 is not set
++# CONFIG_REGULATOR_TPS6507X is not set
++# CONFIG_REGULATOR_TPS6524X is not set
++CONFIG_MEDIA_SUPPORT=m
++
++#
++# Multimedia core support
++#
++CONFIG_MEDIA_CAMERA_SUPPORT=y
++# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set
++# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set
++# CONFIG_MEDIA_RADIO_SUPPORT is not set
++# CONFIG_MEDIA_SDR_SUPPORT is not set
++# CONFIG_MEDIA_RC_SUPPORT is not set
++# CONFIG_MEDIA_CONTROLLER is not set
++CONFIG_VIDEO_DEV=m
++CONFIG_VIDEO_V4L2=m
++# CONFIG_VIDEO_ADV_DEBUG is not set
++# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
++CONFIG_VIDEOBUF2_CORE=m
++CONFIG_VIDEOBUF2_MEMOPS=m
++CONFIG_VIDEOBUF2_VMALLOC=m
++# CONFIG_TTPCI_EEPROM is not set
++
++#
++# Media drivers
++#
++# CONFIG_MEDIA_USB_SUPPORT is not set
++# CONFIG_V4L_PLATFORM_DRIVERS is not set
++# CONFIG_V4L_MEM2MEM_DRIVERS is not set
++# CONFIG_V4L_TEST_DRIVERS is not set
++
++#
++# Supported MMC/SDIO adapters
++#
++# CONFIG_CYPRESS_FIRMWARE is not set
++
++#
++# Media ancillary drivers (tuners, sensors, i2c, frontends)
++#
++CONFIG_MEDIA_SUBDRV_AUTOSELECT=y
++
++#
++# Audio decoders, processors and mixers
++#
++
++#
++# RDS decoders
++#
++
++#
++# Video decoders
++#
++
++#
++# Video and audio decoders
++#
++
++#
++# Video encoders
++#
++
++#
++# Camera sensor devices
++#
++
++#
++# Flash devices
++#
++
++#
++# Video improvement chips
++#
++
++#
++# Audio/Video compression chips
++#
++
++#
++# Miscellaneous helper chips
++#
++
++#
++# Sensors used on soc_camera driver
++#
++
++#
++# Tools to develop new frontends
++#
++# CONFIG_DVB_DUMMY_FE is not set
++
++#
++# Graphics support
++#
++# CONFIG_IMX_IPUV3_CORE is not set
++
++#
++# Direct Rendering Manager
++#
++# CONFIG_DRM is not set
++
++#
++# Frame buffer Devices
++#
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++CONFIG_FB_CMDLINE=y
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++# CONFIG_FB_CFB_FILLRECT is not set
++# CONFIG_FB_CFB_COPYAREA is not set
++# CONFIG_FB_CFB_IMAGEBLIT is not set
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# 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_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_ARMCLCD is not set
++# CONFIG_FB_OPENCORES is not set
++# CONFIG_FB_S1D13XXX is not set
++# CONFIG_FB_SMSCUFX is not set
++# CONFIG_FB_UDL is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_BROADSHEET is not set
++# CONFIG_FB_AUO_K190X is not set
++# CONFIG_FB_SIMPLE is not set
++# CONFIG_FB_SSD1307 is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++# CONFIG_VGASTATE is not set
++
++#
++# Console display driver support
++#
++CONFIG_DUMMY_CONSOLE=y
++# CONFIG_FRAMEBUFFER_CONSOLE is not set
++# CONFIG_LOGO is not set
++# CONFIG_SOUND is not set
++
++#
++# HID support
++#
++CONFIG_HID=y
++# CONFIG_HID_BATTERY_STRENGTH is not set
++# CONFIG_HIDRAW is not set
++# CONFIG_UHID is not set
++CONFIG_HID_GENERIC=y
++
++#
++# Special HID drivers
++#
++CONFIG_HID_A4TECH=y
++# CONFIG_HID_ACRUX is not set
++CONFIG_HID_APPLE=y
++# CONFIG_HID_APPLEIR is not set
++# CONFIG_HID_AUREAL is not set
++CONFIG_HID_BELKIN=y
++CONFIG_HID_CHERRY=y
++CONFIG_HID_CHICONY=y
++# CONFIG_HID_CP2112 is not set
++CONFIG_HID_CYPRESS=y
++# CONFIG_HID_DRAGONRISE is not set
++# CONFIG_HID_EMS_FF is not set
++# CONFIG_HID_ELECOM is not set
++# CONFIG_HID_ELO is not set
++CONFIG_HID_EZKEY=y
++# CONFIG_HID_HOLTEK is not set
++# CONFIG_HID_HUION 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_ICADE is not set
++# CONFIG_HID_TWINHAN is not set
++CONFIG_HID_KENSINGTON=y
++# CONFIG_HID_LCPOWER is not set
++# CONFIG_HID_LENOVO is not set
++CONFIG_HID_LOGITECH=y
++# CONFIG_HID_LOGITECH_HIDPP is not set
++# CONFIG_LOGITECH_FF is not set
++# CONFIG_LOGIRUMBLEPAD2_FF is not set
++# CONFIG_LOGIG940_FF is not set
++# CONFIG_LOGIWHEELS_FF is not set
++# CONFIG_HID_MAGICMOUSE is not set
++CONFIG_HID_MICROSOFT=y
++CONFIG_HID_MONTEREY=y
++# 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_PENMOUNT is not set
++# CONFIG_HID_PETALYNX is not set
++# CONFIG_HID_PICOLCD is not set
++# CONFIG_HID_PRIMAX is not set
++# CONFIG_HID_ROCCAT is not set
++# CONFIG_HID_SAITEK is not set
++# CONFIG_HID_SAMSUNG is not set
++# CONFIG_HID_SPEEDLINK is not set
++# CONFIG_HID_STEELSERIES is not set
++# CONFIG_HID_SUNPLUS is not set
++# CONFIG_HID_RMI 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_XINMO is not set
++# CONFIG_HID_ZEROPLUS is not set
++# CONFIG_HID_ZYDACRON is not set
++# CONFIG_HID_SENSOR_HUB is not set
++
++#
++# USB HID support
++#
++CONFIG_USB_HID=y
++# CONFIG_HID_PID is not set
++# CONFIG_USB_HIDDEV is not set
++
++#
++# I2C HID support
++#
++# CONFIG_I2C_HID is not set
++CONFIG_USB_OHCI_LITTLE_ENDIAN=y
++CONFIG_USB_SUPPORT=y
++CONFIG_USB_COMMON=y
++CONFIG_USB_ARCH_HAS_HCD=y
++CONFIG_USB=y
++# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
++
++#
++# Miscellaneous USB options
++#
++# CONFIG_USB_DEFAULT_PERSIST is not set
++# CONFIG_USB_DYNAMIC_MINORS is not set
++# CONFIG_USB_OTG_WHITELIST is not set
++# CONFIG_USB_OTG_FSM is not set
++# CONFIG_USB_MON is not set
++# CONFIG_USB_WUSB_CBAF is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_C67X00_HCD is not set
++# CONFIG_USB_XHCI_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_FUSBH200_HCD is not set
++# CONFIG_USB_FOTG210_HCD is not set
++# CONFIG_USB_MAX3421_HCD is not set
++# CONFIG_USB_OHCI_HCD is not set
++# CONFIG_USB_SL811_HCD is not set
++# CONFIG_USB_R8A66597_HCD is not set
++# CONFIG_USB_HCD_TEST_MODE is not set
++
++#
++# USB Device Class drivers
++#
++# CONFIG_USB_ACM is not set
++# CONFIG_USB_PRINTER is not set
++# CONFIG_USB_WDM is not set
++# CONFIG_USB_TMC is not set
++
++#
++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
++#
++
++#
++# also be needed; see USB_STORAGE Help for more info
++#
++# CONFIG_USB_STORAGE is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++# CONFIG_USBIP_CORE is not set
++# CONFIG_USB_MUSB_HDRC is not set
++# CONFIG_USB_DWC3 is not set
++# CONFIG_USB_DWC2 is not set
++# CONFIG_USB_CHIPIDEA is not set
++
++#
++# USB port drivers
++#
++# CONFIG_USB_SERIAL is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
++# CONFIG_USB_SEVSEG is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
++# CONFIG_USB_APPLEDISPLAY is not set
++# CONFIG_USB_LD is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
++# CONFIG_USB_IOWARRIOR is not set
++# CONFIG_USB_TEST is not set
++# CONFIG_USB_EHSET_TEST_FIXTURE is not set
++# CONFIG_USB_ISIGHTFW is not set
++# CONFIG_USB_YUREX is not set
++# CONFIG_USB_EZUSB_FX2 is not set
++# CONFIG_USB_HSIC_USB3503 is not set
++# CONFIG_USB_LINK_LAYER_TEST is not set
++
++#
++# USB Physical Layer drivers
++#
++# CONFIG_USB_PHY is not set
++# CONFIG_USB_OTG_WAKELOCK is not set
++# CONFIG_NOP_USB_XCEIV is not set
++# CONFIG_AM335X_PHY_USB is not set
++# CONFIG_USB_GPIO_VBUS is not set
++# CONFIG_USB_ISP1301 is not set
++# CONFIG_USB_ULPI is not set
++CONFIG_USB_GADGET=y
++# CONFIG_USB_GADGET_DEBUG is not set
++# CONFIG_USB_GADGET_DEBUG_FILES is not set
++CONFIG_USB_GADGET_VBUS_DRAW=2
++CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2
++
++#
++# USB Peripheral Controller
++#
++# CONFIG_USB_FUSB300 is not set
++# CONFIG_USB_FOTG210_UDC is not set
++# CONFIG_USB_GR_UDC is not set
++# CONFIG_USB_R8A66597 is not set
++# CONFIG_USB_PXA27X is not set
++# CONFIG_USB_MV_UDC is not set
++CONFIG_HIUSB_DEVICE2_0=y
++CONFIG_USB_HISI_UDC=m
++# CONFIG_USB_AUTO_SWITCH is not set
++# CONFIG_HIUSB_DEVICE3_0 is not set
++# CONFIG_USB_MV_U3D is not set
++# CONFIG_USB_M66592 is not set
++# CONFIG_USB_NET2272 is not set
++# CONFIG_USB_GADGET_XILINX is not set
++# CONFIG_USB_DUMMY_HCD is not set
++CONFIG_USB_LIBCOMPOSITE=m
++CONFIG_USB_F_ACM=m
++CONFIG_USB_U_SERIAL=m
++CONFIG_USB_U_ETHER=m
++CONFIG_USB_F_RNDIS=m
++CONFIG_USB_F_MASS_STORAGE=m
++CONFIG_USB_F_UAC1=m
++CONFIG_USB_F_UVC=m
++# CONFIG_USB_CONFIGFS is not set
++# CONFIG_USB_ZERO is not set
++CONFIG_USB_AUDIO=m
++CONFIG_GADGET_UAC1=y
++# CONFIG_USB_ETH is not set
++# CONFIG_USB_G_NCM is not set
++# CONFIG_USB_GADGETFS is not set
++# CONFIG_USB_FUNCTIONFS is not set
++CONFIG_USB_MASS_STORAGE=m
++# CONFIG_USB_G_SERIAL is not set
++# CONFIG_USB_G_PRINTER is not set
++# CONFIG_USB_CDC_COMPOSITE is not set
++# CONFIG_USB_G_ACM_MS is not set
++CONFIG_USB_G_MULTI=m
++CONFIG_USB_G_MULTI_RNDIS=y
++# CONFIG_USB_G_MULTI_CDC is not set
++# CONFIG_USB_G_HID is not set
++# CONFIG_USB_G_DBGP is not set
++# CONFIG_USB_G_WEBCAM is not set
++CONFIG_USB_G_WEBCAM_AUDIO=m
++# CONFIG_UWB is not set
++CONFIG_MMC=y
++# CONFIG_MMC_DEBUG is not set
++# CONFIG_MMC_CLKGATE is not set
++CONFIG_MMC_EMBEDDED_SDIO=y
++# CONFIG_MMC_PARANOID_SD_INIT is not set
++
++#
++# MMC/SD/SDIO Card Drivers
++#
++CONFIG_MMC_BLOCK=y
++CONFIG_MMC_BLOCK_MINORS=8
++CONFIG_MMC_BLOCK_BOUNCE=y
++# CONFIG_MMC_BLOCK_DEFERRED_RESUME is not set
++# CONFIG_SDIO_UART is not set
++# CONFIG_MMC_TEST is not set
++
++#
++# MMC/SD/SDIO Host Controller Drivers
++#
++# CONFIG_MMC_ARMMMCI is not set
++# CONFIG_MMC_SDHCI is not set
++# CONFIG_MMC_DW is not set
++# CONFIG_MMC_VUB300 is not set
++# CONFIG_MMC_USHC is not set
++# CONFIG_MMC_USDHI6ROL0 is not set
++CONFIG_HIMCIV200=y
++CONFIG_SEND_AUTO_STOP=y
++CONFIG_DETECT_CARD_TIME=200
++# CONFIG_MEMSTICK is not set
++# CONFIG_NEW_LEDS is not set
++# CONFIG_SWITCH is not set
++# CONFIG_ACCESSIBILITY is not set
++# CONFIG_EDAC is not set
++CONFIG_RTC_LIB=y
++# CONFIG_RTC_CLASS is not set
++# CONFIG_DMADEVICES is not set
++# CONFIG_AUXDISPLAY is not set
++# CONFIG_UIO is not set
++# CONFIG_VIRT_DRIVERS is not set
++
++#
++# Virtio drivers
++#
++# CONFIG_VIRTIO_MMIO is not set
++
++#
++# Microsoft Hyper-V guest support
++#
++# CONFIG_STAGING is not set
++
++#
++# SOC (System On Chip) specific Drivers
++#
++# CONFIG_SOC_TI is not set
++CONFIG_CLKDEV_LOOKUP=y
++CONFIG_HAVE_CLK_PREPARE=y
++CONFIG_COMMON_CLK=y
++
++#
++# Common Clock Framework
++#
++# CONFIG_COMMON_CLK_SI5351 is not set
++# CONFIG_COMMON_CLK_SI570 is not set
++# CONFIG_COMMON_CLK_PXA is not set
++# CONFIG_COMMON_CLK_QCOM is not set
++
++#
++# Hardware Spinlock drivers
++#
++
++#
++# Clock Source drivers
++#
++CONFIG_CLKSRC_OF=y
++CONFIG_CLKSRC_MMIO=y
++CONFIG_ARM_ARCH_TIMER=y
++CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y
++# CONFIG_ARM_ARCH_TIMER_VCT_ACCESS is not set
++# CONFIG_ATMEL_PIT is not set
++# CONFIG_SH_TIMER_CMT is not set
++# CONFIG_SH_TIMER_MTU2 is not set
++# CONFIG_SH_TIMER_TMU is not set
++# CONFIG_EM_TIMER_STI is not set
++# CONFIG_CLKSRC_VERSATILE is not set
++# CONFIG_MAILBOX is not set
++# CONFIG_IOMMU_SUPPORT is not set
++
++#
++# Remoteproc drivers
++#
++# CONFIG_STE_MODEM_RPROC is not set
++
++#
++# Rpmsg drivers
++#
++
++#
++# SOC (System On Chip) specific Drivers
++#
++# 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
++CONFIG_IRQCHIP=y
++CONFIG_ARM_GIC=y
++# CONFIG_IPACK_BUS is not set
++CONFIG_ARCH_HAS_RESET_CONTROLLER=y
++CONFIG_RESET_CONTROLLER=y
++# CONFIG_FMC is not set
++
++#
++# PHY Subsystem
++#
++CONFIG_GENERIC_PHY=y
++# CONFIG_BCM_KONA_USB2_PHY is not set
++CONFIG_PHY_HISI_INNO_USB2=y
++# CONFIG_POWERCAP is not set
++# CONFIG_MCB is not set
++# CONFIG_HI_DMAC is not set
++
++#
++# Hisilicon driver support
++#
++# CONFIG_CMA_MEM_SHARED is not set
++# CONFIG_CMA_ADVANCE_SHARE is not set
++
++#
++# File systems
++#
++CONFIG_DCACHE_WORD_ACCESS=y
++# CONFIG_EXT2_FS is not set
++# CONFIG_EXT3_FS is not set
++CONFIG_EXT4_FS=y
++CONFIG_EXT4_USE_FOR_EXT23=y
++# CONFIG_EXT4_FS_POSIX_ACL is not set
++# CONFIG_EXT4_FS_SECURITY is not set
++# CONFIG_EXT4_DEBUG is not set
++CONFIG_JBD2=y
++# CONFIG_JBD2_DEBUG is not set
++CONFIG_FS_MBCACHE=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_BTRFS_FS is not set
++# CONFIG_NILFS2_FS is not set
++CONFIG_FS_POSIX_ACL=y
++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 is not set
++# CONFIG_FUSE_FS is not set
++# CONFIG_OVERLAY_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_KERNFS=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=m
++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_YAFFS_FS=y
++CONFIG_YAFFS_YAFFS1=y
++# CONFIG_YAFFS_9BYTE_TAGS is not set
++# CONFIG_YAFFS_DOES_ECC is not set
++CONFIG_YAFFS_YAFFS2=y
++CONFIG_YAFFS_AUTO_YAFFS2=y
++# CONFIG_YAFFS_DISABLE_TAGS_ECC is not set
++# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
++# CONFIG_YAFFS_EMPTY_LOST_AND_FOUND is not set
++# CONFIG_YAFFS_DISABLE_BLOCK_REFRESHING is not set
++# CONFIG_YAFFS_DISABLE_BACKGROUND is not set
++# CONFIG_YAFFS_DISABLE_BAD_BLOCK_MARKING is not set
++CONFIG_YAFFS_XATTR=y
++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 is not set
++# CONFIG_JFFS2_FS_XATTR is not set
++# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
++CONFIG_JFFS2_ZLIB=y
++# CONFIG_JFFS2_LZO is not set
++CONFIG_JFFS2_RTIME=y
++# CONFIG_JFFS2_RUBIN 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 is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V2=y
++CONFIG_NFS_V3=y
++CONFIG_NFS_V3_ACL=y
++# CONFIG_NFS_V4 is not set
++# CONFIG_NFS_SWAP is not set
++# CONFIG_ROOT_NFS is not set
++# CONFIG_NFSD is not set
++CONFIG_GRACE_PERIOD=y
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_ACL_SUPPORT=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 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=y
++# CONFIG_DLM is not set
++
++#
++# Kernel hacking
++#
++
++#
++# printk and dmesg options
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4
++# CONFIG_BOOT_PRINTK_DELAY is not set
++
++#
++# Compile-time checks and compiler options
++#
++# CONFIG_DEBUG_INFO is not set
++# CONFIG_ENABLE_WARN_DEPRECATED is not set
++# CONFIG_ENABLE_MUST_CHECK is not set
++CONFIG_FRAME_WARN=1024
++# CONFIG_STRIP_ASM_SYMS is not set
++# CONFIG_READABLE_ASM is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++# CONFIG_DEBUG_FS is not set
++# CONFIG_HEADERS_CHECK is not set
++# CONFIG_DEBUG_SECTION_MISMATCH is not set
++# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
++# CONFIG_MAGIC_SYSRQ is not set
++CONFIG_DEBUG_KERNEL=y
++
++#
++# Memory Debugging
++#
++# 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_STACK_USAGE is not set
++# CONFIG_DEBUG_VM is not set
++CONFIG_DEBUG_MEMORY_INIT=y
++# CONFIG_DEBUG_HIGHMEM is not set
++# CONFIG_DEBUG_SHIRQ is not set
++
++#
++# Debug Lockups and Hangs
++#
++# CONFIG_LOCKUP_DETECTOR is not set
++# CONFIG_DETECT_HUNG_TASK is not set
++CONFIG_PANIC_ON_OOPS=y
++CONFIG_PANIC_ON_OOPS_VALUE=1
++CONFIG_PANIC_TIMEOUT=0
++CONFIG_SCHED_DEBUG=y
++# CONFIG_SCHEDSTATS is not set
++# CONFIG_SCHED_STACK_END_CHECK is not set
++# CONFIG_TIMER_STATS is not set
++
++#
++# Lock Debugging (spinlocks, mutexes, etc...)
++#
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_LOCK_STAT is not set
++# CONFIG_DEBUG_ATOMIC_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_LOCK_TORTURE_TEST is not set
++CONFIG_STACKTRACE=y
++# CONFIG_DEBUG_KOBJECT is not set
++CONFIG_DEBUG_BUGVERBOSE=y
++# CONFIG_DEBUG_LIST is not set
++# CONFIG_DEBUG_PI_LIST is not set
++# CONFIG_DEBUG_SG is not set
++# CONFIG_DEBUG_NOTIFIERS is not set
++# CONFIG_DEBUG_CREDENTIALS is not set
++
++#
++# RCU Debugging
++#
++# CONFIG_SPARSE_RCU_POINTER is not set
++# CONFIG_TORTURE_TEST is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_RCU_TRACE is not set
++# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_NOTIFIER_ERROR_INJECTION is not set
++# CONFIG_FAULT_INJECTION is not set
++# CONFIG_LATENCYTOP 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 is not set
++
++#
++# Runtime Testing
++#
++# CONFIG_TEST_LIST_SORT is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_RBTREE_TEST is not set
++# CONFIG_INTERVAL_TREE_TEST is not set
++# CONFIG_PERCPU_TEST is not set
++# CONFIG_ATOMIC64_SELFTEST is not set
++# CONFIG_TEST_STRING_HELPERS is not set
++# CONFIG_TEST_KSTRTOX is not set
++# CONFIG_TEST_RHASHTABLE is not set
++# CONFIG_DMA_API_DEBUG is not set
++# CONFIG_TEST_LKM is not set
++# CONFIG_TEST_USER_COPY is not set
++# CONFIG_TEST_BPF is not set
++# CONFIG_TEST_FIRMWARE is not set
++# CONFIG_TEST_UDELAY is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_KGDB is not set
++# CONFIG_ARM_PTDUMP is not set
++CONFIG_STRICT_DEVMEM=y
++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_DEBUG_UART_PL01X is not set
++# CONFIG_DEBUG_UART_8250 is not set
++# CONFIG_DEBUG_UART_BCM63XX is not set
++CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"
++# CONFIG_OC_ETM is not set
++# CONFIG_PID_IN_CONTEXTIDR is not set
++# CONFIG_DEBUG_SET_MODULE_RONX is not set
++# CONFIG_CORESIGHT is not set
++
++#
++# 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_AEAD=y
++CONFIG_CRYPTO_AEAD2=y
++CONFIG_CRYPTO_BLKCIPHER=y
++CONFIG_CRYPTO_BLKCIPHER2=y
++CONFIG_CRYPTO_HASH=y
++CONFIG_CRYPTO_HASH2=y
++CONFIG_CRYPTO_RNG=y
++CONFIG_CRYPTO_RNG2=y
++CONFIG_CRYPTO_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_WORKQUEUE=y
++# CONFIG_CRYPTO_CRYPTD is not set
++# CONFIG_CRYPTO_MCRYPTD is not set
++# CONFIG_CRYPTO_AUTHENC is not set
++# CONFIG_CRYPTO_TEST is not set
++
++#
++# Authenticated Encryption with Associated Data
++#
++CONFIG_CRYPTO_CCM=y
++# CONFIG_CRYPTO_GCM is not set
++CONFIG_CRYPTO_SEQIV=y
++
++#
++# Block modes
++#
++# CONFIG_CRYPTO_CBC is not set
++CONFIG_CRYPTO_CTR=y
++# 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_CMAC is not set
++# CONFIG_CRYPTO_HMAC is not set
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_VMAC is not set
++
++#
++# Digest
++#
++CONFIG_CRYPTO_CRC32C=y
++# CONFIG_CRYPTO_CRC32 is not set
++# CONFIG_CRYPTO_CRCT10DIF 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_SHA1_ARM_NEON is not set
++# CONFIG_CRYPTO_SHA256 is not set
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_SHA512_ARM_NEON 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_AES_ARM_BS is not set
++# CONFIG_CRYPTO_ANUBIS is not set
++CONFIG_CRYPTO_ARC4=y
++# 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=y
++# CONFIG_CRYPTO_ZLIB is not set
++CONFIG_CRYPTO_LZO=y
++# CONFIG_CRYPTO_LZ4 is not set
++# CONFIG_CRYPTO_LZ4HC is not set
++
++#
++# Random Number Generation
++#
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++# CONFIG_CRYPTO_DRBG_MENU is not set
++# CONFIG_CRYPTO_USER_API_HASH is not set
++# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
++CONFIG_CRYPTO_HW=y
++# CONFIG_BINARY_PRINTF is not set
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++CONFIG_GENERIC_STRNCPY_FROM_USER=y
++CONFIG_GENERIC_STRNLEN_USER=y
++CONFIG_GENERIC_NET_UTILS=y
++CONFIG_GENERIC_PCI_IOMAP=y
++CONFIG_GENERIC_IO=y
++CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
++# CONFIG_CRC_CCITT is not set
++CONFIG_CRC16=y
++# CONFIG_CRC_T10DIF is not set
++# 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=y
++# CONFIG_CRC8 is not set
++# CONFIG_AUDIT_ARCH_COMPAT_GENERIC is not set
++# CONFIG_RANDOM32_SELFTEST is not set
++CONFIG_ZLIB_INFLATE=y
++CONFIG_ZLIB_DEFLATE=y
++CONFIG_LZO_COMPRESS=y
++CONFIG_LZO_DECOMPRESS=y
++CONFIG_LZ4_DECOMPRESS=y
++CONFIG_XZ_DEC=y
++CONFIG_XZ_DEC_X86=y
++CONFIG_XZ_DEC_POWERPC=y
++CONFIG_XZ_DEC_IA64=y
++CONFIG_XZ_DEC_ARM=y
++CONFIG_XZ_DEC_ARMTHUMB=y
++CONFIG_XZ_DEC_SPARC=y
++CONFIG_XZ_DEC_BCJ=y
++# CONFIG_XZ_DEC_TEST is not set
++CONFIG_DECOMPRESS_GZIP=y
++CONFIG_DECOMPRESS_BZIP2=y
++CONFIG_DECOMPRESS_LZMA=y
++CONFIG_DECOMPRESS_XZ=y
++CONFIG_DECOMPRESS_LZO=y
++CONFIG_DECOMPRESS_LZ4=y
++CONFIG_GENERIC_ALLOCATOR=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT_MAP=y
++CONFIG_HAS_DMA=y
++CONFIG_DQL=y
++CONFIG_NLATTR=y
++CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
++CONFIG_AVERAGE=y
++# CONFIG_CORDIC is not set
++# CONFIG_DDR is not set
++CONFIG_LIBFDT=y
++CONFIG_ARCH_HAS_SG_CHAIN=y
++# CONFIG_VIRTUALIZATION is not set
+diff --git a/arch/arm/configs/hi3559_single_nand_mini_defconfig b/arch/arm/configs/hi3559_single_nand_mini_defconfig
+new file mode 100644
+index 0000000..d1101a1
+--- /dev/null
++++ b/arch/arm/configs/hi3559_single_nand_mini_defconfig
+@@ -0,0 +1,2396 @@
++#
++# Automatically generated file; DO NOT EDIT.
++# Linux/arm 3.18.20 Kernel Configuration
++#
++CONFIG_ARM=y
++CONFIG_ARM_HAS_SG_CHAIN=y
++CONFIG_MIGHT_HAVE_PCI=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=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_XCHGADD_ALGORITHM=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_NEED_DMA_MAP_STATE=y
++CONFIG_ARCH_SUPPORTS_UPROBES=y
++CONFIG_VECTORS_BASE=0xffff0000
++CONFIG_ARM_PATCH_PHYS_VIRT=y
++CONFIG_GENERIC_BUG=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++CONFIG_IRQ_WORK=y
++CONFIG_BUILDTIME_EXTABLE_SORT=y
++
++#
++# General setup
++#
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_CROSS_COMPILE=""
++# CONFIG_COMPILE_TEST is not set
++CONFIG_LOCALVERSION=""
++# CONFIG_LOCALVERSION_AUTO is not set
++CONFIG_HAVE_KERNEL_GZIP=y
++CONFIG_HAVE_KERNEL_LZMA=y
++CONFIG_HAVE_KERNEL_XZ=y
++CONFIG_HAVE_KERNEL_LZO=y
++CONFIG_HAVE_KERNEL_LZ4=y
++CONFIG_KERNEL_GZIP=y
++# CONFIG_KERNEL_LZMA is not set
++# CONFIG_KERNEL_XZ is not set
++# CONFIG_KERNEL_LZO is not set
++# CONFIG_KERNEL_LZ4 is not set
++CONFIG_HW_DECOMPRESS=y
++# CONFIG_SOFT_DECOMPRESS is not set
++CONFIG_DEFAULT_HOSTNAME="(none)"
++# CONFIG_SWAP is not set
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++# CONFIG_POSIX_MQUEUE is not set
++CONFIG_CROSS_MEMORY_ATTACH=y
++# CONFIG_FHANDLE is not set
++CONFIG_USELIB=y
++# CONFIG_AUDIT is not set
++CONFIG_HAVE_ARCH_AUDITSYSCALL=y
++
++#
++# IRQ subsystem
++#
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_GENERIC_IRQ_SHOW=y
++CONFIG_HARDIRQS_SW_RESEND=y
++CONFIG_IRQ_DOMAIN=y
++CONFIG_HANDLE_DOMAIN_IRQ=y
++CONFIG_IRQ_FORCED_THREADING=y
++CONFIG_SPARSE_IRQ=y
++CONFIG_GENERIC_CLOCKEVENTS=y
++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
++
++#
++# Timers subsystem
++#
++CONFIG_TICK_ONESHOT=y
++CONFIG_NO_HZ_COMMON=y
++# CONFIG_HZ_PERIODIC is not set
++CONFIG_NO_HZ_IDLE=y
++CONFIG_NO_HZ=y
++# CONFIG_HIGH_RES_TIMERS is not set
++
++#
++# CPU/Task time and stats accounting
++#
++CONFIG_TICK_CPU_ACCOUNTING=y
++# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set
++# CONFIG_IRQ_TIME_ACCOUNTING is not set
++# CONFIG_BSD_PROCESS_ACCT is not set
++# CONFIG_TASKSTATS is not set
++
++#
++# RCU Subsystem
++#
++CONFIG_TINY_RCU=y
++# CONFIG_PREEMPT_RCU is not set
++# CONFIG_TASKS_RCU is not set
++# CONFIG_RCU_STALL_COMMON is not set
++# CONFIG_TREE_RCU_TRACE is not set
++# CONFIG_BUILD_BIN2C is not set
++# CONFIG_IKCONFIG is not set
++CONFIG_LOG_BUF_SHIFT=17
++CONFIG_GENERIC_SCHED_CLOCK=y
++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_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 is not set
++# CONFIG_SCHED_AUTOGROUP is not set
++# CONFIG_SYSFS_DEPRECATED is not set
++# CONFIG_RELAY is not set
++# CONFIG_BLK_DEV_INITRD is not set
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++CONFIG_HAVE_UID16=y
++CONFIG_BPF=y
++CONFIG_EXPERT=y
++# CONFIG_UID16 is not set
++# CONFIG_SGETMASK_SYSCALL is not set
++CONFIG_SYSFS_SYSCALL=y
++# CONFIG_SYSCTL_SYSCALL is not set
++CONFIG_KALLSYMS=y
++# CONFIG_KALLSYMS_ALL is not set
++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_BPF_SYSCALL is not set
++CONFIG_SHMEM=y
++CONFIG_AIO=y
++CONFIG_ADVISE_SYSCALLS=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 is not set
++# CONFIG_SLUB_DEBUG is not set
++# CONFIG_COMPAT_BRK is not set
++# 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_UPROBES is not set
++# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
++CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
++CONFIG_ARCH_USE_BUILTIN_BSWAP=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_GENERIC_SMP_IDLE_THREAD=y
++CONFIG_GENERIC_IDLE_POLL_SETUP=y
++CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
++CONFIG_HAVE_CLK=y
++CONFIG_HAVE_DMA_API_DEBUG=y
++CONFIG_HAVE_PERF_REGS=y
++CONFIG_HAVE_PERF_USER_STACK_DUMP=y
++CONFIG_HAVE_ARCH_JUMP_LABEL=y
++CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
++CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
++CONFIG_HAVE_CC_STACKPROTECTOR=y
++# CONFIG_CC_STACKPROTECTOR is not set
++CONFIG_CC_STACKPROTECTOR_NONE=y
++# CONFIG_CC_STACKPROTECTOR_REGULAR is not set
++# CONFIG_CC_STACKPROTECTOR_STRONG is not set
++CONFIG_HAVE_CONTEXT_TRACKING=y
++CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
++CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
++CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
++CONFIG_MODULES_USE_ELF_REL=y
++CONFIG_CLONE_BACKWARDS=y
++CONFIG_OLD_SIGSUSPEND3=y
++CONFIG_OLD_SIGACTION=y
++
++#
++# GCOV-based kernel profiling
++#
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_RT_MUTEXES=y
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++# CONFIG_MODULE_FORCE_LOAD is not set
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++# CONFIG_MODULE_SIG is not set
++# CONFIG_MODULE_COMPRESS is not set
++CONFIG_BLOCK=y
++CONFIG_LBDAF=y
++CONFIG_BLK_DEV_BSG=y
++# CONFIG_BLK_DEV_BSGLIB is not set
++# CONFIG_BLK_DEV_INTEGRITY is not set
++CONFIG_BLK_CMDLINE_PARSER=y
++
++#
++# Partition Types
++#
++CONFIG_PARTITION_ADVANCED=y
++# CONFIG_ACORN_PARTITION is not set
++# CONFIG_AIX_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=y
++# CONFIG_SYSV68_PARTITION is not set
++CONFIG_CMDLINE_PARTITION=y
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++CONFIG_DEFAULT_DEADLINE=y
++# CONFIG_DEFAULT_CFQ is not set
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="deadline"
++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_ARCH_SUPPORTS_ATOMIC_RMW=y
++CONFIG_FREEZER=y
++
++#
++# System Type
++#
++CONFIG_MMU=y
++CONFIG_ARCH_MULTIPLATFORM=y
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_AT91 is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_GEMINI is not set
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_IOP13XX is not set
++# CONFIG_ARCH_IOP32X is not set
++# CONFIG_ARCH_IOP33X is not set
++# CONFIG_ARCH_IXP4XX is not set
++# CONFIG_ARCH_DOVE is not set
++# CONFIG_ARCH_MV78XX0 is not set
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_MMP is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_W90X900 is not set
++# CONFIG_ARCH_LPC32XX is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_MSM is not set
++# CONFIG_ARCH_SHMOBILE_LEGACY 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_DAVINCI is not set
++# CONFIG_ARCH_OMAP1 is not set
++
++#
++# Multiple platform selection
++#
++
++#
++# CPU Core family selection
++#
++# CONFIG_ARCH_MULTI_V6 is not set
++CONFIG_ARCH_MULTI_V7=y
++CONFIG_ARCH_MULTI_V6_V7=y
++# CONFIG_ARCH_MULTI_CPU_AUTO is not set
++# CONFIG_ARCH_VIRT is not set
++# CONFIG_ARCH_MVEBU is not set
++# CONFIG_ARCH_BCM is not set
++# CONFIG_ARCH_BERLIN is not set
++# CONFIG_ARCH_HIGHBANK is not set
++CONFIG_ARCH_HISI=y
++
++#
++# Hisilicon platform type
++#
++# CONFIG_ARCH_HI3xxx is not set
++# CONFIG_ARCH_HIP04 is not set
++# CONFIG_ARCH_HIX5HD2 is not set
++# CONFIG_ARCH_HI3519 is not set
++# CONFIG_ARCH_HI3519V101 is not set
++# CONFIG_ARCH_HI3516AV200 is not set
++CONFIG_ARCH_HI3559=y
++# CONFIG_ARCH_HI3556 is not set
++# CONFIG_ARCH_HI3536C is not set
++# CONFIG_ARCH_HI3531D is not set
++# CONFIG_ARCH_HI3521D is not set
++# CONFIG_ARCH_KEYSTONE is not set
++# CONFIG_ARCH_MESON is not set
++# CONFIG_ARCH_MXC is not set
++# CONFIG_ARCH_MEDIATEK is not set
++
++#
++# TI OMAP/AM/DM/DRA Family
++#
++# CONFIG_ARCH_OMAP3 is not set
++# CONFIG_ARCH_OMAP4 is not set
++# CONFIG_SOC_OMAP5 is not set
++# CONFIG_SOC_AM33XX is not set
++# CONFIG_SOC_AM43XX is not set
++# CONFIG_SOC_DRA7XX is not set
++# CONFIG_ARCH_QCOM is not set
++# CONFIG_ARCH_ROCKCHIP is not set
++# CONFIG_ARCH_SOCFPGA is not set
++# CONFIG_PLAT_SPEAR is not set
++# CONFIG_ARCH_STI is not set
++# CONFIG_ARCH_S5PV210 is not set
++# CONFIG_ARCH_EXYNOS is not set
++# CONFIG_ARCH_SHMOBILE_MULTI is not set
++# CONFIG_ARCH_SUNXI is not set
++# CONFIG_ARCH_SIRF is not set
++# CONFIG_ARCH_TEGRA is not set
++# CONFIG_ARCH_U8500 is not set
++# CONFIG_ARCH_VEXPRESS is not set
++# CONFIG_ARCH_WM8850 is not set
++# CONFIG_ARCH_ZYNQ is not set
++CONFIG_ARM_TIMER_SP804=y
++
++#
++# Processor Type
++#
++CONFIG_CPU_V7=y
++CONFIG_CPU_32v6K=y
++CONFIG_CPU_32v7=y
++CONFIG_CPU_ABRT_EV7=y
++CONFIG_CPU_PABRT_V7=y
++CONFIG_CPU_CACHE_V7=y
++CONFIG_CPU_CACHE_VIPT=y
++CONFIG_CPU_COPY_V6=y
++CONFIG_CPU_TLB_V7=y
++CONFIG_CPU_HAS_ASID=y
++CONFIG_CPU_CP15=y
++CONFIG_CPU_CP15_MMU=y
++
++#
++# Processor Features
++#
++# CONFIG_ARM_LPAE is not set
++# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
++CONFIG_ARM_THUMB=y
++# CONFIG_ARM_THUMBEE is not set
++CONFIG_ARM_VIRT_EXT=y
++CONFIG_SWP_EMULATE=y
++# CONFIG_CPU_ICACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_DISABLE is not set
++# CONFIG_CPU_BPREDICT_DISABLE is not set
++CONFIG_KUSER_HELPERS=y
++CONFIG_MIGHT_HAVE_CACHE_L2X0=y
++# CONFIG_CACHE_L2X0 is not set
++CONFIG_ARM_L1_CACHE_SHIFT_6=y
++CONFIG_ARM_L1_CACHE_SHIFT=6
++CONFIG_ARM_DMA_MEM_BUFFERABLE=y
++CONFIG_MULTI_IRQ_HANDLER=y
++# CONFIG_ARM_ERRATA_430973 is not set
++# CONFIG_ARM_ERRATA_720789 is not set
++# CONFIG_ARM_ERRATA_754322 is not set
++# CONFIG_ARM_ERRATA_775420 is not set
++# CONFIG_ARM_ERRATA_773022 is not set
++
++#
++# Bus support
++#
++CONFIG_ARM_AMBA=y
++# CONFIG_PCI is not set
++# CONFIG_PCI_SYSCALL is not set
++# CONFIG_PCCARD is not set
++
++#
++# Kernel Features
++#
++CONFIG_HAVE_SMP=y
++# CONFIG_SMP is not set
++CONFIG_DISABLE_CPU_SCHED_DOMAIN_BALANCE=y
++CONFIG_HAVE_ARM_ARCH_TIMER=y
++CONFIG_VMSPLIT_3G=y
++# CONFIG_VMSPLIT_2G is not set
++# CONFIG_VMSPLIT_1G is not set
++CONFIG_PAGE_OFFSET=0xC0000000
++# CONFIG_ARM_PSCI is not set
++CONFIG_ARCH_NR_GPIO=0
++CONFIG_PREEMPT_NONE=y
++# CONFIG_PREEMPT_VOLUNTARY is not set
++# CONFIG_PREEMPT is not set
++CONFIG_HZ_FIXED=0
++# CONFIG_HZ_100 is not set
++# CONFIG_HZ_200 is not set
++# CONFIG_HZ_250 is not set
++# CONFIG_HZ_300 is not set
++# CONFIG_HZ_500 is not set
++CONFIG_HZ_1000=y
++CONFIG_HZ=1000
++# CONFIG_SCHED_HRTICK is not set
++# CONFIG_THUMB2_KERNEL is not set
++CONFIG_AEABI=y
++# CONFIG_OABI_COMPAT is not set
++# 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_ARCH_WANT_GENERAL_HUGETLB=y
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_HAVE_MEMBLOCK=y
++CONFIG_NO_BOOTMEM=y
++CONFIG_MEMORY_ISOLATION=y
++# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=4
++CONFIG_COMPACTION=y
++CONFIG_MIGRATION=y
++# CONFIG_PHYS_ADDR_T_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_BOUNCE=y
++# CONFIG_KSM is not set
++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
++CONFIG_NEED_PER_CPU_KM=y
++# CONFIG_CLEANCACHE is not set
++CONFIG_CMA=y
++# CONFIG_CMA_DEBUG is not set
++CONFIG_CMA_AREAS=7
++# CONFIG_ZPOOL is not set
++# CONFIG_ZBUD is not set
++# CONFIG_ZSMALLOC 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_SWIOTLB=y
++CONFIG_IOMMU_HELPER=y
++# CONFIG_XEN is not set
++# CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART is not set
++
++#
++# Boot options
++#
++CONFIG_USE_OF=y
++CONFIG_ATAGS=y
++# CONFIG_DEPRECATED_PARAM_STRUCT is not set
++# CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE is not set
++CONFIG_ZBOOT_ROM_TEXT=0
++CONFIG_ZBOOT_ROM_BSS=0
++CONFIG_ARM_APPENDED_DTB=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_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_GOV_COMMON=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 is not set
++CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
++# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE is not set
++CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
++CONFIG_CPU_FREQ_GOV_POWERSAVE=y
++CONFIG_CPU_FREQ_GOV_USERSPACE=y
++CONFIG_CPU_FREQ_GOV_ONDEMAND=y
++CONFIG_CPU_FREQ_GOV_INTERACTIVE=y
++# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
++# CONFIG_CPUFREQ_DT is not set
++
++#
++# ARM CPU frequency scaling drivers
++#
++# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set
++
++#
++# CPU Idle
++#
++# CONFIG_CPU_IDLE is not set
++# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++CONFIG_VFP=y
++CONFIG_VFPv3=y
++CONFIG_NEON=y
++CONFIG_KERNEL_MODE_NEON=y
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
++CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
++CONFIG_BINFMT_SCRIPT=y
++# CONFIG_HAVE_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
++CONFIG_COREDUMP=y
++
++#
++# Power management options
++#
++CONFIG_SUSPEND=y
++CONFIG_SUSPEND_FREEZER=y
++# CONFIG_WAKELOCK is not set
++# CONFIG_HISI_SNAPSHOT_BOOT is not set
++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_OPP=y
++CONFIG_PM_CLK=y
++# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set
++CONFIG_CPU_PM=y
++# CONFIG_SUSPEND_TIME is not set
++CONFIG_ARCH_SUSPEND_POSSIBLE=y
++CONFIG_ARM_CPU_SUSPEND=y
++CONFIG_ARCH_HIBERNATION_POSSIBLE=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_NET_IP_TUNNEL is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_NET_IPVTI is not set
++# CONFIG_NET_UDP_TUNNEL is not set
++# CONFIG_NET_FOU is not set
++# CONFIG_GENEVE 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 is not set
++CONFIG_INET_XFRM_MODE_TRANSPORT=y
++CONFIG_INET_XFRM_MODE_TUNNEL=y
++CONFIG_INET_XFRM_MODE_BEET=y
++CONFIG_INET_LRO=y
++CONFIG_INET_DIAG=y
++CONFIG_INET_TCP_DIAG=y
++# CONFIG_INET_UDP_DIAG is not set
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++# CONFIG_TCP_MD5SIG is not set
++# CONFIG_IPV6 is not set
++# CONFIG_ANDROID_PARANOID_NETWORK is not set
++CONFIG_NET_ACTIVITY_STATS=y
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NET_PTP_CLASSIFY 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_NF_TABLES is not set
++# CONFIG_NETFILTER_XTABLES is not set
++# CONFIG_IP_SET is not set
++# CONFIG_IP_VS is not set
++
++#
++# IP: Netfilter Configuration
++#
++# CONFIG_NF_DEFRAG_IPV4 is not set
++# CONFIG_NF_LOG_ARP is not set
++# CONFIG_NF_LOG_IPV4 is not set
++# CONFIG_NF_REJECT_IPV4 is not set
++# CONFIG_IP_NF_IPTABLES is not set
++# CONFIG_IP_NF_ARPTABLES 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_HAVE_NET_DSA=y
++# 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_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_VSOCKETS is not set
++# CONFIG_NETLINK_MMAP is not set
++# CONFIG_NETLINK_DIAG is not set
++# CONFIG_NET_MPLS_GSO is not set
++# CONFIG_HSR is not set
++# CONFIG_CGROUP_NET_PRIO is not set
++# CONFIG_CGROUP_NET_CLASSID is not set
++CONFIG_NET_RX_BUSY_POLL=y
++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 is not set
++CONFIG_DEVTMPFS=y
++CONFIG_DEVTMPFS_MOUNT=y
++CONFIG_STANDALONE=y
++# CONFIG_PREVENT_FIRMWARE_BUILD is not set
++CONFIG_FW_LOADER=y
++# CONFIG_FIRMWARE_IN_KERNEL is not set
++CONFIG_EXTRA_FIRMWARE=""
++# CONFIG_FW_LOADER_USER_HELPER_FALLBACK is not set
++CONFIG_ALLOW_DEV_COREDUMP=y
++# 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_HAVE_CPU_AUTOPROBE is not set
++CONFIG_REGMAP=y
++CONFIG_REGMAP_MMIO=y
++CONFIG_DMA_SHARED_BUFFER=y
++# CONFIG_FENCE_TRACE is not set
++CONFIG_DMA_CMA=y
++
++#
++# Default contiguous memory area size:
++#
++CONFIG_CMA_SIZE_MBYTES=16
++CONFIG_CMA_SIZE_SEL_MBYTES=y
++# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set
++# CONFIG_CMA_SIZE_SEL_MIN is not set
++# CONFIG_CMA_SIZE_SEL_MAX is not set
++CONFIG_CMA_ALIGNMENT=8
++
++#
++# Bus devices
++#
++# CONFIG_BRCMSTB_GISB_ARB is not set
++CONFIG_ARM_CCI=y
++# CONFIG_VEXPRESS_CONFIG 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=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_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_HIFMC=y
++# CONFIG_HIFMC_SPI_NAND is not set
++CONFIG_HIFMC_NAND=y
++
++#
++# 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_SST25L is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_PHRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++# CONFIG_MTD_BLOCK2MTD is not set
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOCG3 is not set
++CONFIG_MTD_NAND_IDS=y
++CONFIG_MTD_NAND_ECC=y
++# CONFIG_MTD_NAND_ECC_SMC is not set
++CONFIG_MTD_NAND=y
++# CONFIG_MTD_NAND_ECC_BCH is not set
++# CONFIG_MTD_SM_COMMON is not set
++# CONFIG_MTD_NAND_DENALI is not set
++# CONFIG_MTD_NAND_OMAP_BCH_BUILD is not set
++# CONFIG_MTD_NAND_DISKONCHIP is not set
++# CONFIG_MTD_NAND_DOCG4 is not set
++# CONFIG_MTD_NAND_NANDSIM is not set
++# CONFIG_MTD_NAND_PLATFORM is not set
++# CONFIG_HISI_NAND_FS_MAY_NO_YAFFS2 is not set
++# CONFIG_HISI_NAND_ECC_STATUS_REPORT is not set
++# CONFIG_MTD_NAND_HINFC610 is not set
++CONFIG_HIFMC100_NAND=y
++CONFIG_HIFMC100_MAX_NAND_CHIP=1
++CONFIG_HIFMC100_NAND_EDO_MODE=y
++CONFIG_RW_H_WIDTH=3
++CONFIG_R_L_WIDTH=2
++CONFIG_W_L_WIDTH=2
++# CONFIG_HIFMC100_NAND_HARDWARE_PAGESIZE_ECC is not set
++CONFIG_HIFMC100_NAND_AUTO_PAGESIZE_ECC=y
++# CONFIG_HIFMC100_NAND_PAGESIZE_AUTO_ECC_NONE is not set
++# CONFIG_MTD_ONENAND is not set
++
++#
++# LPDDR & LPDDR2 PCM memory drivers
++#
++# CONFIG_MTD_LPDDR is not set
++# CONFIG_MTD_LPDDR2_NVM is not set
++# CONFIG_MTD_SPI_NOR is not set
++CONFIG_MTD_UBI=y
++CONFIG_MTD_UBI_WL_THRESHOLD=4096
++CONFIG_MTD_UBI_BEB_LIMIT=20
++# CONFIG_MTD_UBI_FASTMAP is not set
++# CONFIG_MTD_UBI_GLUEBI is not set
++# CONFIG_MTD_UBI_BLOCK is not set
++CONFIG_DTC=y
++CONFIG_OF=y
++
++#
++# Device Tree and Open Firmware support
++#
++# 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_NET=y
++CONFIG_OF_MDIO=y
++CONFIG_OF_MTD=y
++CONFIG_OF_RESERVED_MEM=y
++CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
++# CONFIG_PARPORT is not set
++CONFIG_BLK_DEV=y
++# CONFIG_BLK_DEV_NULL_BLK is not set
++# CONFIG_BLK_DEV_COW_COMMON is not set
++# CONFIG_BLK_DEV_LOOP 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=65536
++# CONFIG_BLK_DEV_XIP is not set
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH 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_DUMMY_IRQ 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_UID_STAT is not set
++# CONFIG_BMP085_I2C is not set
++# CONFIG_BMP085_SPI is not set
++# CONFIG_USB_SWITCH_FSA9480 is not set
++# CONFIG_LATTICE_ECP3_CONFIG is not set
++# CONFIG_SRAM is not set
++# CONFIG_C2PORT is not set
++
++#
++# EEPROM support
++#
++# CONFIG_EEPROM_AT24 is not set
++# CONFIG_EEPROM_AT25 is not set
++# CONFIG_EEPROM_LEGACY is not set
++# CONFIG_EEPROM_MAX6875 is not set
++# CONFIG_EEPROM_93CX6 is not set
++# CONFIG_EEPROM_93XX46 is not set
++
++#
++# Texas Instruments shared transport line discipline
++#
++# 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
++
++#
++# Intel MIC Bus Driver
++#
++
++#
++# Intel MIC Host Driver
++#
++
++#
++# Intel MIC Card Driver
++#
++# CONFIG_ECHO is not set
++# CONFIG_CXL_BASE is not set
++
++#
++# hisi 'himm/himd.l/himc'support
++#
++# CONFIG_HISI_REG 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_NETLINK is not set
++# CONFIG_SCSI_MQ_DEFAULT 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_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 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_NET_CORE=y
++# CONFIG_BONDING is not set
++# CONFIG_DUMMY is not set
++# CONFIG_EQUALIZER is not set
++# CONFIG_NET_TEAM is not set
++# CONFIG_MACVLAN is not set
++# CONFIG_VXLAN is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_TUN is not set
++# CONFIG_VETH is not set
++# CONFIG_NLMON is not set
++
++#
++# 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_NET_DSA_MV88E6171 is not set
++# CONFIG_NET_DSA_BCM_SF2 is not set
++# CONFIG_ETHERNET is not set
++CONFIG_PHYLIB=y
++
++#
++# MII PHY device drivers
++#
++# CONFIG_AT803X_PHY is not set
++# CONFIG_AMD_PHY is not set
++# CONFIG_AMD_XGBE_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 is not set
++# CONFIG_BROADCOM_PHY is not set
++# CONFIG_BCM7XXX_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_MMIOREG is not set
++# CONFIG_MDIO_BCM_UNIMAC is not set
++# CONFIG_MDIO_HISI_FEMAC is not set
++# CONFIG_MDIO_HISI_GEMAC is not set
++# CONFIG_MICREL_KS8995MA is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++
++#
++# Host-side USB support is needed for USB Network Adapter support
++#
++CONFIG_USB_NET_DRIVERS=m
++# 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_RTL8152 is not set
++# CONFIG_USB_USBNET is not set
++# CONFIG_USB_IPHETH is not set
++CONFIG_WLAN=y
++# CONFIG_WIFI_CONTROL_FUNC is not set
++# 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 is not set
++# CONFIG_INPUT_SPARSEKMAP is not set
++# CONFIG_INPUT_MATRIXKMAP is not set
++
++#
++# Userland interfaces
++#
++# CONFIG_INPUT_MOUSEDEV is not set
++# CONFIG_INPUT_JOYDEV is not set
++CONFIG_INPUT_EVDEV=y
++# CONFIG_INPUT_EVBUG is not set
++# CONFIG_INPUT_KEYRESET is not set
++# CONFIG_INPUT_KEYCOMBO is not set
++
++#
++# Input Device Drivers
++#
++# CONFIG_INPUT_KEYBOARD is not set
++# CONFIG_INPUT_MOUSE is not set
++# CONFIG_INPUT_JOYSTICK is not set
++# CONFIG_INPUT_TABLET is not set
++# CONFIG_INPUT_TOUCHSCREEN is not set
++# CONFIG_INPUT_MISC is not set
++
++#
++# Hardware I/O ports
++#
++# CONFIG_SERIO is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++CONFIG_TTY=y
++CONFIG_VT=y
++CONFIG_CONSOLE_TRANSLATIONS=y
++CONFIG_VT_CONSOLE=y
++CONFIG_VT_CONSOLE_SLEEP=y
++CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
++CONFIG_UNIX98_PTYS=y
++# CONFIG_DEVPTS_MULTIPLE_INSTANCES 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_DEVMEM=y
++CONFIG_DEVKMEM=y
++
++#
++# Serial drivers
++#
++CONFIG_SERIAL_EARLYCON=y
++# CONFIG_SERIAL_8250 is not set
++
++#
++# Non-8250 serial port support
++#
++# CONFIG_SERIAL_AMBA_PL010 is not set
++CONFIG_SERIAL_AMBA_PL011=y
++CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
++# CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST is not set
++# 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_SC16IS7XX is not set
++# CONFIG_SERIAL_ALTERA_JTAGUART is not set
++# CONFIG_SERIAL_ALTERA_UART is not set
++# CONFIG_SERIAL_XILINX_PS_UART is not set
++# CONFIG_SERIAL_ARC is not set
++# CONFIG_SERIAL_FSL_LPUART is not set
++# CONFIG_SERIAL_ST_ASC is not set
++# CONFIG_TTY_PRINTK is not set
++# CONFIG_HVC_DCC is not set
++# CONFIG_IPMI_HANDLER is not set
++CONFIG_HW_RANDOM=y
++# CONFIG_HW_RANDOM_TIMERIOMEM is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++# CONFIG_DCC_TTY is not set
++# CONFIG_XILLYBUS is not set
++
++#
++# I2C support
++#
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++# CONFIG_I2C_COMPAT is not set
++CONFIG_I2C_CHARDEV=y
++CONFIG_I2C_MUX=m
++
++#
++# Multiplexer I2C Chip support
++#
++# CONFIG_I2C_MUX_PCA9541 is not set
++# CONFIG_I2C_HELPER_AUTO is not set
++# CONFIG_I2C_SMBUS is not set
++
++#
++# I2C Algorithms
++#
++# CONFIG_I2C_ALGOBIT is not set
++# CONFIG_I2C_ALGOPCF is not set
++# CONFIG_I2C_ALGOPCA is not set
++
++#
++# I2C Hardware Bus support
++#
++
++#
++# I2C system bus drivers (mostly embedded / system-on-chip)
++#
++# CONFIG_I2C_DESIGNWARE_PLATFORM is not set
++# CONFIG_I2C_HIBVT is not set
++CONFIG_I2C_HISI_V110=y
++# CONFIG_I2C_NOMADIK 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_RK3X 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_ROBOTFUZZ_OSIF 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_CADENCE is not set
++# CONFIG_SPI_FSL_SPI is not set
++CONFIG_SPI_PL022=y
++# CONFIG_SPI_PXA2XX_PCI is not set
++# CONFIG_SPI_ROCKCHIP 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=y
++# CONFIG_SPI_TLE62X0 is not set
++# CONFIG_SPMI is not set
++# CONFIG_HSI is not set
++
++#
++# PPS support
++#
++# CONFIG_PPS is not set
++
++#
++# PPS generators support
++#
++
++#
++# PTP clock support
++#
++# CONFIG_PTP_1588_CLOCK is not set
++
++#
++# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
++#
++CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
++CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
++# CONFIG_GPIOLIB is not set
++# CONFIG_W1 is not set
++CONFIG_POWER_SUPPLY=y
++# CONFIG_POWER_SUPPLY_DEBUG is not set
++# CONFIG_PDA_POWER is not set
++# CONFIG_TEST_POWER is not set
++# CONFIG_BATTERY_DS2780 is not set
++# CONFIG_BATTERY_DS2781 is not set
++# CONFIG_BATTERY_DS2782 is not set
++# CONFIG_BATTERY_SBS is not set
++# CONFIG_BATTERY_BQ27x00 is not set
++# CONFIG_BATTERY_MAX17040 is not set
++# CONFIG_BATTERY_MAX17042 is not set
++# CONFIG_CHARGER_MAX8903 is not set
++# CONFIG_CHARGER_LP8727 is not set
++# CONFIG_CHARGER_BQ2415X is not set
++# CONFIG_CHARGER_SMB347 is not set
++CONFIG_POWER_RESET=y
++# CONFIG_POWER_RESET_BRCMSTB is not set
++CONFIG_POWER_RESET_HISI=y
++# CONFIG_POWER_RESET_RESTART is not set
++# CONFIG_POWER_RESET_VERSATILE is not set
++# CONFIG_POWER_RESET_SYSCON is not set
++# CONFIG_POWER_AVS is not set
++# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
++# CONFIG_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=y
++# CONFIG_MFD_AS3711 is not set
++# CONFIG_MFD_AS3722 is not set
++# CONFIG_PMIC_ADP5520 is not set
++# CONFIG_MFD_BCM590XX is not set
++# CONFIG_MFD_AXP20X is not set
++# CONFIG_MFD_CROS_EC is not set
++# CONFIG_PMIC_DA903X is not set
++# CONFIG_MFD_DA9052_SPI is not set
++# CONFIG_MFD_DA9052_I2C is not set
++# CONFIG_MFD_DA9055 is not set
++# CONFIG_MFD_DA9063 is not set
++# CONFIG_MFD_MC13XXX_SPI is not set
++# CONFIG_MFD_MC13XXX_I2C is not set
++# CONFIG_MFD_HI6421_PMIC is not set
++CONFIG_MFD_HISI_FMC=y
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_INTEL_SOC_PMIC is not set
++# CONFIG_MFD_KEMPLD is not set
++# CONFIG_MFD_88PM800 is not set
++# CONFIG_MFD_88PM805 is not set
++# CONFIG_MFD_88PM860X is not set
++# CONFIG_MFD_MAX14577 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_MENF21BMC is not set
++# CONFIG_EZX_PCAP is not set
++# CONFIG_MFD_VIPERBOARD is not set
++# CONFIG_MFD_RETU is not set
++# CONFIG_MFD_PCF50633 is not set
++# CONFIG_MFD_PM8921_CORE is not set
++# CONFIG_MFD_RTSX_USB is not set
++# CONFIG_MFD_RC5T583 is not set
++# CONFIG_MFD_RK808 is not set
++# CONFIG_MFD_RN5T618 is not set
++# CONFIG_MFD_SEC_CORE is not set
++# CONFIG_MFD_SI476X_CORE is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_MFD_SMSC is not set
++# CONFIG_ABX500_CORE is not set
++# CONFIG_MFD_STMPE is not set
++CONFIG_MFD_SYSCON=y
++# CONFIG_MFD_TI_AM335X_TSCADC is not set
++# CONFIG_MFD_LP3943 is not set
++# CONFIG_MFD_LP8788 is not set
++# CONFIG_MFD_PALMAS is not set
++# CONFIG_TPS6105X is not set
++# CONFIG_TPS6507X is not set
++# CONFIG_MFD_TPS65090 is not set
++# CONFIG_MFD_TPS65217 is not set
++# CONFIG_MFD_TPS65218 is not set
++# CONFIG_MFD_TPS6586X is not set
++# CONFIG_MFD_TPS80031 is not set
++# CONFIG_TWL4030_CORE is not set
++# CONFIG_TWL6040_CORE is not set
++# CONFIG_MFD_WL1273_CORE is not set
++# CONFIG_MFD_LM3533 is not set
++# CONFIG_MFD_TC3589X is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_MFD_T7L66XB is not set
++# CONFIG_MFD_TC6387XB is not set
++# CONFIG_MFD_TC6393XB is not set
++# CONFIG_MFD_ARIZONA_I2C is not set
++# CONFIG_MFD_ARIZONA_SPI is not set
++# CONFIG_MFD_WM8400 is not set
++# CONFIG_MFD_WM831X_I2C is not set
++# CONFIG_MFD_WM831X_SPI is not set
++# CONFIG_MFD_WM8350_I2C is not set
++# CONFIG_MFD_WM8994 is not set
++CONFIG_REGULATOR=y
++# CONFIG_REGULATOR_DEBUG is not set
++# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
++# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
++# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
++# CONFIG_REGULATOR_ACT8865 is not set
++# CONFIG_REGULATOR_AD5398 is not set
++# CONFIG_REGULATOR_ANATOP is not set
++# CONFIG_REGULATOR_DA9210 is not set
++# CONFIG_REGULATOR_DA9211 is not set
++# CONFIG_REGULATOR_FAN53555 is not set
++# CONFIG_REGULATOR_ISL9305 is not set
++# CONFIG_REGULATOR_ISL6271A is not set
++# CONFIG_REGULATOR_LP3971 is not set
++# CONFIG_REGULATOR_LP3972 is not set
++# CONFIG_REGULATOR_LP872X is not set
++# CONFIG_REGULATOR_LP8755 is not set
++# CONFIG_REGULATOR_LTC3589 is not set
++# CONFIG_REGULATOR_MAX1586 is not set
++# CONFIG_REGULATOR_MAX8649 is not set
++# CONFIG_REGULATOR_MAX8660 is not set
++# CONFIG_REGULATOR_MAX8952 is not set
++# CONFIG_REGULATOR_MAX8973 is not set
++# CONFIG_REGULATOR_PFUZE100 is not set
++# CONFIG_REGULATOR_TPS51632 is not set
++# CONFIG_REGULATOR_TPS62360 is not set
++# CONFIG_REGULATOR_TPS65023 is not set
++# CONFIG_REGULATOR_TPS6507X is not set
++# CONFIG_REGULATOR_TPS6524X is not set
++CONFIG_MEDIA_SUPPORT=m
++
++#
++# Multimedia core support
++#
++CONFIG_MEDIA_CAMERA_SUPPORT=y
++# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set
++# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set
++# CONFIG_MEDIA_RADIO_SUPPORT is not set
++# CONFIG_MEDIA_SDR_SUPPORT is not set
++# CONFIG_MEDIA_RC_SUPPORT is not set
++# CONFIG_MEDIA_CONTROLLER is not set
++CONFIG_VIDEO_DEV=m
++CONFIG_VIDEO_V4L2=m
++# CONFIG_VIDEO_ADV_DEBUG is not set
++# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
++CONFIG_VIDEOBUF2_CORE=m
++CONFIG_VIDEOBUF2_MEMOPS=m
++CONFIG_VIDEOBUF2_VMALLOC=m
++# CONFIG_TTPCI_EEPROM is not set
++
++#
++# Media drivers
++#
++# CONFIG_MEDIA_USB_SUPPORT is not set
++# CONFIG_V4L_PLATFORM_DRIVERS is not set
++# CONFIG_V4L_MEM2MEM_DRIVERS is not set
++# CONFIG_V4L_TEST_DRIVERS is not set
++
++#
++# Supported MMC/SDIO adapters
++#
++# CONFIG_CYPRESS_FIRMWARE is not set
++
++#
++# Media ancillary drivers (tuners, sensors, i2c, frontends)
++#
++CONFIG_MEDIA_SUBDRV_AUTOSELECT=y
++
++#
++# Audio decoders, processors and mixers
++#
++
++#
++# RDS decoders
++#
++
++#
++# Video decoders
++#
++
++#
++# Video and audio decoders
++#
++
++#
++# Video encoders
++#
++
++#
++# Camera sensor devices
++#
++
++#
++# Flash devices
++#
++
++#
++# Video improvement chips
++#
++
++#
++# Audio/Video compression chips
++#
++
++#
++# Miscellaneous helper chips
++#
++
++#
++# Sensors used on soc_camera driver
++#
++
++#
++# Tools to develop new frontends
++#
++# CONFIG_DVB_DUMMY_FE is not set
++
++#
++# Graphics support
++#
++# CONFIG_IMX_IPUV3_CORE is not set
++
++#
++# Direct Rendering Manager
++#
++# CONFIG_DRM is not set
++
++#
++# Frame buffer Devices
++#
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++CONFIG_FB_CMDLINE=y
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++# CONFIG_FB_CFB_FILLRECT is not set
++# CONFIG_FB_CFB_COPYAREA is not set
++# CONFIG_FB_CFB_IMAGEBLIT is not set
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# 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_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_ARMCLCD is not set
++# CONFIG_FB_OPENCORES is not set
++# CONFIG_FB_S1D13XXX is not set
++# CONFIG_FB_SMSCUFX is not set
++# CONFIG_FB_UDL is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_BROADSHEET is not set
++# CONFIG_FB_AUO_K190X is not set
++# CONFIG_FB_SIMPLE is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++# CONFIG_VGASTATE is not set
++
++#
++# Console display driver support
++#
++CONFIG_DUMMY_CONSOLE=y
++# CONFIG_FRAMEBUFFER_CONSOLE is not set
++# CONFIG_LOGO is not set
++# CONFIG_SOUND is not set
++
++#
++# HID support
++#
++CONFIG_HID=y
++# CONFIG_HID_BATTERY_STRENGTH is not set
++# CONFIG_HIDRAW is not set
++# CONFIG_UHID is not set
++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_APPLEIR 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_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_ELO is not set
++# CONFIG_HID_EZKEY is not set
++# CONFIG_HID_HOLTEK is not set
++# CONFIG_HID_HUION 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_ICADE is not set
++# CONFIG_HID_TWINHAN is not set
++# CONFIG_HID_KENSINGTON is not set
++# CONFIG_HID_LCPOWER is not set
++# CONFIG_HID_LENOVO is not set
++# 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_PENMOUNT is not set
++# CONFIG_HID_PETALYNX is not set
++# CONFIG_HID_PICOLCD is not set
++# CONFIG_HID_PRIMAX is not set
++# CONFIG_HID_ROCCAT is not set
++# CONFIG_HID_SAITEK is not set
++# CONFIG_HID_SAMSUNG is not set
++# CONFIG_HID_SPEEDLINK is not set
++# CONFIG_HID_STEELSERIES is not set
++# CONFIG_HID_SUNPLUS is not set
++# CONFIG_HID_RMI 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_XINMO is not set
++# CONFIG_HID_ZEROPLUS is not set
++# CONFIG_HID_ZYDACRON is not set
++# CONFIG_HID_SENSOR_HUB is not set
++
++#
++# USB HID support
++#
++CONFIG_USB_HID=m
++# CONFIG_HID_PID is not set
++# CONFIG_USB_HIDDEV is not set
++
++#
++# USB HID Boot Protocol drivers
++#
++# CONFIG_USB_KBD is not set
++# CONFIG_USB_MOUSE is not set
++
++#
++# I2C HID support
++#
++# CONFIG_I2C_HID is not set
++CONFIG_USB_OHCI_LITTLE_ENDIAN=y
++CONFIG_USB_SUPPORT=y
++CONFIG_USB_COMMON=y
++CONFIG_USB_ARCH_HAS_HCD=y
++CONFIG_USB=m
++# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
++
++#
++# Miscellaneous USB options
++#
++# CONFIG_USB_DEFAULT_PERSIST is not set
++# CONFIG_USB_DYNAMIC_MINORS is not set
++# CONFIG_USB_OTG_WHITELIST is not set
++# CONFIG_USB_OTG_BLACKLIST_HUB is not set
++# CONFIG_USB_OTG_FSM is not set
++# CONFIG_USB_MON is not set
++# CONFIG_USB_WUSB_CBAF is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_C67X00_HCD is not set
++# CONFIG_USB_XHCI_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_FUSBH200_HCD is not set
++# CONFIG_USB_FOTG210_HCD is not set
++# CONFIG_USB_MAX3421_HCD is not set
++# CONFIG_USB_OHCI_HCD is not set
++# CONFIG_USB_SL811_HCD is not set
++# CONFIG_USB_R8A66597_HCD is not set
++# CONFIG_USB_HCD_TEST_MODE is not set
++
++#
++# USB Device Class drivers
++#
++# CONFIG_USB_ACM is not set
++# CONFIG_USB_PRINTER is not set
++# CONFIG_USB_WDM is not set
++# CONFIG_USB_TMC is not set
++
++#
++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
++#
++
++#
++# also be needed; see USB_STORAGE Help for more info
++#
++# CONFIG_USB_STORAGE is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++# CONFIG_USBIP_CORE is not set
++# CONFIG_USB_MUSB_HDRC is not set
++# CONFIG_USB_DWC3 is not set
++# CONFIG_USB_DWC2 is not set
++# CONFIG_USB_CHIPIDEA is not set
++
++#
++# USB port drivers
++#
++# CONFIG_USB_SERIAL is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
++# CONFIG_USB_SEVSEG is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
++# CONFIG_USB_APPLEDISPLAY is not set
++# CONFIG_USB_LD is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
++# CONFIG_USB_IOWARRIOR is not set
++# CONFIG_USB_TEST is not set
++# CONFIG_USB_EHSET_TEST_FIXTURE is not set
++# CONFIG_USB_ISIGHTFW is not set
++# CONFIG_USB_YUREX is not set
++# CONFIG_USB_EZUSB_FX2 is not set
++# CONFIG_USB_HSIC_USB3503 is not set
++# CONFIG_USB_LINK_LAYER_TEST is not set
++
++#
++# USB Physical Layer drivers
++#
++# CONFIG_USB_PHY is not set
++# CONFIG_NOP_USB_XCEIV is not set
++# CONFIG_AM335X_PHY_USB is not set
++# CONFIG_USB_ISP1301 is not set
++# CONFIG_USB_ULPI is not set
++CONFIG_USB_GADGET=y
++# CONFIG_USB_GADGET_DEBUG is not set
++# CONFIG_USB_GADGET_DEBUG_FILES is not set
++CONFIG_USB_GADGET_VBUS_DRAW=2
++CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2
++
++#
++# USB Peripheral Controller
++#
++# CONFIG_USB_FUSB300 is not set
++# CONFIG_USB_FOTG210_UDC is not set
++# CONFIG_USB_GR_UDC is not set
++# CONFIG_USB_R8A66597 is not set
++# CONFIG_USB_PXA27X is not set
++# CONFIG_USB_MV_UDC is not set
++CONFIG_HIUSB_DEVICE2_0=y
++CONFIG_USB_HISI_UDC=m
++# CONFIG_USB_AUTO_SWITCH is not set
++# CONFIG_HIUSB_DEVICE3_0 is not set
++# CONFIG_USB_MV_U3D is not set
++# CONFIG_USB_M66592 is not set
++# CONFIG_USB_NET2272 is not set
++# CONFIG_USB_GADGET_XILINX is not set
++CONFIG_USB_LIBCOMPOSITE=m
++CONFIG_USB_F_ACM=m
++CONFIG_USB_U_SERIAL=m
++CONFIG_USB_U_ETHER=m
++CONFIG_USB_F_RNDIS=m
++CONFIG_USB_F_MASS_STORAGE=m
++CONFIG_USB_F_UAC1=m
++CONFIG_USB_F_UVC=m
++# CONFIG_USB_CONFIGFS is not set
++# CONFIG_USB_ZERO is not set
++CONFIG_USB_AUDIO=m
++CONFIG_GADGET_UAC1=y
++# CONFIG_USB_ETH is not set
++# CONFIG_USB_G_NCM is not set
++# CONFIG_USB_GADGETFS is not set
++# CONFIG_USB_FUNCTIONFS is not set
++CONFIG_USB_MASS_STORAGE=m
++# CONFIG_USB_G_SERIAL is not set
++# CONFIG_USB_G_PRINTER is not set
++# CONFIG_USB_CDC_COMPOSITE is not set
++# CONFIG_USB_G_ACM_MS is not set
++CONFIG_USB_G_MULTI=m
++CONFIG_USB_G_MULTI_RNDIS=y
++# CONFIG_USB_G_MULTI_CDC is not set
++# CONFIG_USB_G_HID is not set
++# CONFIG_USB_G_DBGP is not set
++# CONFIG_USB_G_WEBCAM is not set
++CONFIG_USB_G_WEBCAM_AUDIO=m
++# CONFIG_UWB is not set
++CONFIG_MMC=m
++# CONFIG_MMC_DEBUG is not set
++# CONFIG_MMC_CLKGATE is not set
++CONFIG_MMC_EMBEDDED_SDIO=y
++# CONFIG_MMC_PARANOID_SD_INIT is not set
++
++#
++# MMC/SD/SDIO Card Drivers
++#
++CONFIG_MMC_BLOCK=m
++CONFIG_MMC_BLOCK_MINORS=8
++CONFIG_MMC_BLOCK_BOUNCE=y
++# CONFIG_MMC_BLOCK_DEFERRED_RESUME is not set
++# CONFIG_SDIO_UART is not set
++# CONFIG_MMC_TEST is not set
++
++#
++# MMC/SD/SDIO Host Controller Drivers
++#
++# CONFIG_MMC_ARMMMCI is not set
++# CONFIG_MMC_SDHCI is not set
++# CONFIG_MMC_DW is not set
++# CONFIG_MMC_VUB300 is not set
++# CONFIG_MMC_USHC is not set
++# CONFIG_MMC_USDHI6ROL0 is not set
++CONFIG_HIMCIV200=m
++CONFIG_SEND_AUTO_STOP=y
++CONFIG_DETECT_CARD_TIME=200
++# CONFIG_MEMSTICK is not set
++# CONFIG_NEW_LEDS is not set
++# CONFIG_SWITCH is not set
++# CONFIG_ACCESSIBILITY is not set
++# CONFIG_EDAC is not set
++CONFIG_RTC_LIB=y
++# CONFIG_RTC_CLASS is not set
++# CONFIG_DMADEVICES is not set
++# CONFIG_AUXDISPLAY is not set
++# CONFIG_UIO is not set
++# CONFIG_VIRT_DRIVERS is not set
++
++#
++# Virtio drivers
++#
++# CONFIG_VIRTIO_MMIO is not set
++
++#
++# Microsoft Hyper-V guest support
++#
++# CONFIG_STAGING is not set
++
++#
++# SOC (System On Chip) specific Drivers
++#
++# CONFIG_SOC_TI is not set
++CONFIG_CLKDEV_LOOKUP=y
++CONFIG_HAVE_CLK_PREPARE=y
++CONFIG_COMMON_CLK=y
++
++#
++# Common Clock Framework
++#
++# CONFIG_COMMON_CLK_SI5351 is not set
++# CONFIG_COMMON_CLK_SI570 is not set
++# CONFIG_COMMON_CLK_PXA is not set
++# CONFIG_COMMON_CLK_QCOM is not set
++
++#
++# Hardware Spinlock drivers
++#
++
++#
++# Clock Source drivers
++#
++CONFIG_CLKSRC_OF=y
++CONFIG_CLKSRC_MMIO=y
++CONFIG_ARM_ARCH_TIMER=y
++CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y
++# CONFIG_ARM_ARCH_TIMER_VCT_ACCESS is not set
++# CONFIG_ATMEL_PIT is not set
++# CONFIG_SH_TIMER_CMT is not set
++# CONFIG_SH_TIMER_MTU2 is not set
++# CONFIG_SH_TIMER_TMU is not set
++# CONFIG_EM_TIMER_STI is not set
++# CONFIG_CLKSRC_VERSATILE is not set
++# CONFIG_MAILBOX is not set
++# CONFIG_IOMMU_SUPPORT is not set
++
++#
++# Remoteproc drivers
++#
++# CONFIG_STE_MODEM_RPROC is not set
++
++#
++# Rpmsg drivers
++#
++
++#
++# SOC (System On Chip) specific Drivers
++#
++# 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
++CONFIG_IRQCHIP=y
++CONFIG_ARM_GIC=y
++# CONFIG_IPACK_BUS is not set
++CONFIG_ARCH_HAS_RESET_CONTROLLER=y
++CONFIG_RESET_CONTROLLER=y
++# CONFIG_FMC is not set
++
++#
++# PHY Subsystem
++#
++CONFIG_GENERIC_PHY=y
++# CONFIG_BCM_KONA_USB2_PHY is not set
++CONFIG_PHY_HISI_INNO_USB2=m
++# CONFIG_POWERCAP is not set
++# CONFIG_MCB is not set
++# CONFIG_HI_DMAC is not set
++
++#
++# Hisilicon driver support
++#
++# CONFIG_CMA_MEM_SHARED is not set
++# CONFIG_CMA_ADVANCE_SHARE is not set
++
++#
++# File systems
++#
++CONFIG_DCACHE_WORD_ACCESS=y
++# CONFIG_EXT2_FS is not set
++# CONFIG_EXT3_FS is not set
++# CONFIG_EXT4_FS is not set
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_BTRFS_FS is not set
++# CONFIG_NILFS2_FS is not set
++CONFIG_FS_POSIX_ACL=y
++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 is not set
++# CONFIG_FUSE_FS is not set
++# CONFIG_OVERLAY_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_KERNFS=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=m
++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_YAFFS_FS is not set
++# CONFIG_JFFS2_FS 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 is not set
++# 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 is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V2=y
++CONFIG_NFS_V3=y
++CONFIG_NFS_V3_ACL=y
++# CONFIG_NFS_V4 is not set
++# CONFIG_NFS_SWAP is not set
++# CONFIG_ROOT_NFS is not set
++# CONFIG_NFSD is not set
++CONFIG_GRACE_PERIOD=y
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_ACL_SUPPORT=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 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=y
++# CONFIG_DLM is not set
++
++#
++# Kernel hacking
++#
++
++#
++# printk and dmesg options
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4
++# CONFIG_BOOT_PRINTK_DELAY is not set
++
++#
++# Compile-time checks and compiler options
++#
++# CONFIG_DEBUG_INFO is not set
++# CONFIG_ENABLE_WARN_DEPRECATED is not set
++# CONFIG_ENABLE_MUST_CHECK is not set
++CONFIG_FRAME_WARN=1024
++# CONFIG_STRIP_ASM_SYMS is not set
++# CONFIG_READABLE_ASM is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++# CONFIG_DEBUG_FS is not set
++# CONFIG_HEADERS_CHECK is not set
++# CONFIG_DEBUG_SECTION_MISMATCH is not set
++# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
++# CONFIG_MAGIC_SYSRQ is not set
++CONFIG_DEBUG_KERNEL=y
++
++#
++# Memory Debugging
++#
++# CONFIG_DEBUG_PAGEALLOC is not set
++# CONFIG_DEBUG_OBJECTS is not set
++# CONFIG_SLUB_STATS is not set
++CONFIG_HAVE_DEBUG_KMEMLEAK=y
++# CONFIG_DEBUG_KMEMLEAK is not set
++# CONFIG_DEBUG_STACK_USAGE is not set
++# CONFIG_DEBUG_VM is not set
++# CONFIG_DEBUG_MEMORY_INIT is not set
++# CONFIG_DEBUG_HIGHMEM is not set
++# CONFIG_DEBUG_SHIRQ is not set
++
++#
++# Debug Lockups and Hangs
++#
++# CONFIG_LOCKUP_DETECTOR is not set
++# CONFIG_DETECT_HUNG_TASK is not set
++CONFIG_PANIC_ON_OOPS=y
++CONFIG_PANIC_ON_OOPS_VALUE=1
++CONFIG_PANIC_TIMEOUT=0
++CONFIG_SCHED_DEBUG=y
++# CONFIG_SCHEDSTATS is not set
++# CONFIG_SCHED_STACK_END_CHECK is not set
++# CONFIG_TIMER_STATS is not set
++
++#
++# Lock Debugging (spinlocks, mutexes, etc...)
++#
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_LOCK_STAT is not set
++# CONFIG_DEBUG_ATOMIC_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_LOCK_TORTURE_TEST is not set
++CONFIG_STACKTRACE=y
++# CONFIG_DEBUG_KOBJECT is not set
++CONFIG_DEBUG_BUGVERBOSE=y
++# CONFIG_DEBUG_LIST is not set
++# CONFIG_DEBUG_PI_LIST is not set
++# CONFIG_DEBUG_SG is not set
++# CONFIG_DEBUG_NOTIFIERS is not set
++# CONFIG_DEBUG_CREDENTIALS is not set
++
++#
++# RCU Debugging
++#
++# CONFIG_SPARSE_RCU_POINTER is not set
++# CONFIG_TORTURE_TEST is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_RCU_TRACE is not set
++# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_NOTIFIER_ERROR_INJECTION is not set
++# CONFIG_FAULT_INJECTION is not set
++# CONFIG_LATENCYTOP 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 is not set
++
++#
++# Runtime Testing
++#
++# CONFIG_TEST_LIST_SORT is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_RBTREE_TEST is not set
++# CONFIG_INTERVAL_TREE_TEST is not set
++# CONFIG_PERCPU_TEST is not set
++# CONFIG_ATOMIC64_SELFTEST is not set
++# CONFIG_TEST_STRING_HELPERS is not set
++# CONFIG_TEST_KSTRTOX is not set
++# CONFIG_TEST_RHASHTABLE is not set
++# CONFIG_DMA_API_DEBUG is not set
++# CONFIG_TEST_LKM is not set
++# CONFIG_TEST_USER_COPY is not set
++# CONFIG_TEST_BPF is not set
++# CONFIG_TEST_FIRMWARE is not set
++# CONFIG_TEST_UDELAY is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_KGDB is not set
++# CONFIG_ARM_PTDUMP is not set
++CONFIG_STRICT_DEVMEM=y
++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_DEBUG_UART_PL01X is not set
++# CONFIG_DEBUG_UART_8250 is not set
++# CONFIG_DEBUG_UART_BCM63XX is not set
++CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"
++# CONFIG_OC_ETM is not set
++# CONFIG_PID_IN_CONTEXTIDR is not set
++# CONFIG_DEBUG_SET_MODULE_RONX is not set
++# CONFIG_CORESIGHT is not set
++
++#
++# 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_AEAD=y
++CONFIG_CRYPTO_AEAD2=y
++CONFIG_CRYPTO_BLKCIPHER=y
++CONFIG_CRYPTO_BLKCIPHER2=y
++CONFIG_CRYPTO_HASH=y
++CONFIG_CRYPTO_HASH2=y
++CONFIG_CRYPTO_RNG=y
++CONFIG_CRYPTO_RNG2=y
++CONFIG_CRYPTO_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_WORKQUEUE=y
++# CONFIG_CRYPTO_CRYPTD is not set
++# CONFIG_CRYPTO_MCRYPTD is not set
++# CONFIG_CRYPTO_AUTHENC is not set
++# CONFIG_CRYPTO_TEST is not set
++
++#
++# Authenticated Encryption with Associated Data
++#
++CONFIG_CRYPTO_CCM=y
++# CONFIG_CRYPTO_GCM is not set
++CONFIG_CRYPTO_SEQIV=y
++
++#
++# Block modes
++#
++# CONFIG_CRYPTO_CBC is not set
++CONFIG_CRYPTO_CTR=y
++# 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_CMAC is not set
++# CONFIG_CRYPTO_HMAC is not set
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_VMAC is not set
++
++#
++# Digest
++#
++CONFIG_CRYPTO_CRC32C=y
++# CONFIG_CRYPTO_CRC32 is not set
++# CONFIG_CRYPTO_CRCT10DIF 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_SHA1_ARM_NEON is not set
++# CONFIG_CRYPTO_SHA256 is not set
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_SHA512_ARM_NEON 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_AES_ARM_BS is not set
++# CONFIG_CRYPTO_ANUBIS is not set
++CONFIG_CRYPTO_ARC4=y
++# 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=y
++# CONFIG_CRYPTO_ZLIB is not set
++CONFIG_CRYPTO_LZO=y
++# CONFIG_CRYPTO_LZ4 is not set
++# CONFIG_CRYPTO_LZ4HC is not set
++
++#
++# Random Number Generation
++#
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++# CONFIG_CRYPTO_DRBG_MENU is not set
++# CONFIG_CRYPTO_USER_API_HASH is not set
++# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
++CONFIG_CRYPTO_HW=y
++# CONFIG_BINARY_PRINTF is not set
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++CONFIG_GENERIC_STRNCPY_FROM_USER=y
++CONFIG_GENERIC_STRNLEN_USER=y
++CONFIG_GENERIC_NET_UTILS=y
++CONFIG_GENERIC_PCI_IOMAP=y
++CONFIG_GENERIC_IO=y
++CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
++# CONFIG_CRC_CCITT is not set
++CONFIG_CRC16=y
++# CONFIG_CRC_T10DIF is not set
++# 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=y
++# CONFIG_CRC8 is not set
++# CONFIG_AUDIT_ARCH_COMPAT_GENERIC is not set
++# CONFIG_RANDOM32_SELFTEST is not set
++CONFIG_ZLIB_INFLATE=y
++CONFIG_ZLIB_DEFLATE=y
++CONFIG_LZO_COMPRESS=y
++CONFIG_LZO_DECOMPRESS=y
++CONFIG_XZ_DEC=y
++CONFIG_XZ_DEC_X86=y
++CONFIG_XZ_DEC_POWERPC=y
++CONFIG_XZ_DEC_IA64=y
++CONFIG_XZ_DEC_ARM=y
++CONFIG_XZ_DEC_ARMTHUMB=y
++CONFIG_XZ_DEC_SPARC=y
++CONFIG_XZ_DEC_BCJ=y
++# CONFIG_XZ_DEC_TEST is not set
++CONFIG_GENERIC_ALLOCATOR=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT_MAP=y
++CONFIG_HAS_DMA=y
++CONFIG_DQL=y
++CONFIG_NLATTR=y
++CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
++CONFIG_AVERAGE=y
++# CONFIG_CORDIC is not set
++# CONFIG_DDR is not set
++CONFIG_LIBFDT=y
++CONFIG_ARCH_HAS_SG_CHAIN=y
++# CONFIG_VIRTUALIZATION is not set
+diff --git a/arch/arm/configs/hi3559_single_spinand_mini_defconfig b/arch/arm/configs/hi3559_single_spinand_mini_defconfig
+new file mode 100644
+index 0000000..36d3e93
+--- /dev/null
++++ b/arch/arm/configs/hi3559_single_spinand_mini_defconfig
+@@ -0,0 +1,2398 @@
++#
++# Automatically generated file; DO NOT EDIT.
++# Linux/arm 3.18.20 Kernel Configuration
++#
++CONFIG_ARM=y
++CONFIG_ARM_HAS_SG_CHAIN=y
++CONFIG_MIGHT_HAVE_PCI=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=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_XCHGADD_ALGORITHM=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_NEED_DMA_MAP_STATE=y
++CONFIG_ARCH_SUPPORTS_UPROBES=y
++CONFIG_VECTORS_BASE=0xffff0000
++CONFIG_ARM_PATCH_PHYS_VIRT=y
++CONFIG_GENERIC_BUG=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++CONFIG_IRQ_WORK=y
++CONFIG_BUILDTIME_EXTABLE_SORT=y
++
++#
++# General setup
++#
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_CROSS_COMPILE=""
++# CONFIG_COMPILE_TEST is not set
++CONFIG_LOCALVERSION=""
++# CONFIG_LOCALVERSION_AUTO is not set
++CONFIG_HAVE_KERNEL_GZIP=y
++CONFIG_HAVE_KERNEL_LZMA=y
++CONFIG_HAVE_KERNEL_XZ=y
++CONFIG_HAVE_KERNEL_LZO=y
++CONFIG_HAVE_KERNEL_LZ4=y
++CONFIG_KERNEL_GZIP=y
++# CONFIG_KERNEL_LZMA is not set
++# CONFIG_KERNEL_XZ is not set
++# CONFIG_KERNEL_LZO is not set
++# CONFIG_KERNEL_LZ4 is not set
++CONFIG_HW_DECOMPRESS=y
++# CONFIG_SOFT_DECOMPRESS is not set
++CONFIG_DEFAULT_HOSTNAME="(none)"
++# CONFIG_SWAP is not set
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++# CONFIG_POSIX_MQUEUE is not set
++CONFIG_CROSS_MEMORY_ATTACH=y
++# CONFIG_FHANDLE is not set
++CONFIG_USELIB=y
++# CONFIG_AUDIT is not set
++CONFIG_HAVE_ARCH_AUDITSYSCALL=y
++
++#
++# IRQ subsystem
++#
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_GENERIC_IRQ_SHOW=y
++CONFIG_HARDIRQS_SW_RESEND=y
++CONFIG_IRQ_DOMAIN=y
++CONFIG_HANDLE_DOMAIN_IRQ=y
++CONFIG_IRQ_FORCED_THREADING=y
++CONFIG_SPARSE_IRQ=y
++CONFIG_GENERIC_CLOCKEVENTS=y
++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
++
++#
++# Timers subsystem
++#
++CONFIG_TICK_ONESHOT=y
++CONFIG_NO_HZ_COMMON=y
++# CONFIG_HZ_PERIODIC is not set
++CONFIG_NO_HZ_IDLE=y
++CONFIG_NO_HZ=y
++# CONFIG_HIGH_RES_TIMERS is not set
++
++#
++# CPU/Task time and stats accounting
++#
++CONFIG_TICK_CPU_ACCOUNTING=y
++# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set
++# CONFIG_IRQ_TIME_ACCOUNTING is not set
++# CONFIG_BSD_PROCESS_ACCT is not set
++# CONFIG_TASKSTATS is not set
++
++#
++# RCU Subsystem
++#
++CONFIG_TINY_RCU=y
++# CONFIG_PREEMPT_RCU is not set
++# CONFIG_TASKS_RCU is not set
++# CONFIG_RCU_STALL_COMMON is not set
++# CONFIG_TREE_RCU_TRACE is not set
++# CONFIG_BUILD_BIN2C is not set
++# CONFIG_IKCONFIG is not set
++CONFIG_LOG_BUF_SHIFT=17
++CONFIG_GENERIC_SCHED_CLOCK=y
++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_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 is not set
++# CONFIG_SCHED_AUTOGROUP is not set
++# CONFIG_SYSFS_DEPRECATED is not set
++# CONFIG_RELAY is not set
++# CONFIG_BLK_DEV_INITRD is not set
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++CONFIG_HAVE_UID16=y
++CONFIG_BPF=y
++CONFIG_EXPERT=y
++# CONFIG_UID16 is not set
++# CONFIG_SGETMASK_SYSCALL is not set
++CONFIG_SYSFS_SYSCALL=y
++# CONFIG_SYSCTL_SYSCALL is not set
++CONFIG_KALLSYMS=y
++# CONFIG_KALLSYMS_ALL is not set
++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_BPF_SYSCALL is not set
++CONFIG_SHMEM=y
++CONFIG_AIO=y
++CONFIG_ADVISE_SYSCALLS=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 is not set
++# CONFIG_SLUB_DEBUG is not set
++# CONFIG_COMPAT_BRK is not set
++# 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_UPROBES is not set
++# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
++CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
++CONFIG_ARCH_USE_BUILTIN_BSWAP=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_GENERIC_SMP_IDLE_THREAD=y
++CONFIG_GENERIC_IDLE_POLL_SETUP=y
++CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
++CONFIG_HAVE_CLK=y
++CONFIG_HAVE_DMA_API_DEBUG=y
++CONFIG_HAVE_PERF_REGS=y
++CONFIG_HAVE_PERF_USER_STACK_DUMP=y
++CONFIG_HAVE_ARCH_JUMP_LABEL=y
++CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
++CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
++CONFIG_HAVE_CC_STACKPROTECTOR=y
++# CONFIG_CC_STACKPROTECTOR is not set
++CONFIG_CC_STACKPROTECTOR_NONE=y
++# CONFIG_CC_STACKPROTECTOR_REGULAR is not set
++# CONFIG_CC_STACKPROTECTOR_STRONG is not set
++CONFIG_HAVE_CONTEXT_TRACKING=y
++CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
++CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
++CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
++CONFIG_MODULES_USE_ELF_REL=y
++CONFIG_CLONE_BACKWARDS=y
++CONFIG_OLD_SIGSUSPEND3=y
++CONFIG_OLD_SIGACTION=y
++
++#
++# GCOV-based kernel profiling
++#
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_RT_MUTEXES=y
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++# CONFIG_MODULE_FORCE_LOAD is not set
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++# CONFIG_MODULE_SIG is not set
++# CONFIG_MODULE_COMPRESS is not set
++CONFIG_BLOCK=y
++CONFIG_LBDAF=y
++CONFIG_BLK_DEV_BSG=y
++# CONFIG_BLK_DEV_BSGLIB is not set
++# CONFIG_BLK_DEV_INTEGRITY is not set
++CONFIG_BLK_CMDLINE_PARSER=y
++
++#
++# Partition Types
++#
++CONFIG_PARTITION_ADVANCED=y
++# CONFIG_ACORN_PARTITION is not set
++# CONFIG_AIX_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=y
++# CONFIG_SYSV68_PARTITION is not set
++CONFIG_CMDLINE_PARTITION=y
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++CONFIG_DEFAULT_DEADLINE=y
++# CONFIG_DEFAULT_CFQ is not set
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="deadline"
++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_ARCH_SUPPORTS_ATOMIC_RMW=y
++CONFIG_FREEZER=y
++
++#
++# System Type
++#
++CONFIG_MMU=y
++CONFIG_ARCH_MULTIPLATFORM=y
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_AT91 is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_GEMINI is not set
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_IOP13XX is not set
++# CONFIG_ARCH_IOP32X is not set
++# CONFIG_ARCH_IOP33X is not set
++# CONFIG_ARCH_IXP4XX is not set
++# CONFIG_ARCH_DOVE is not set
++# CONFIG_ARCH_MV78XX0 is not set
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_MMP is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_W90X900 is not set
++# CONFIG_ARCH_LPC32XX is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_MSM is not set
++# CONFIG_ARCH_SHMOBILE_LEGACY 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_DAVINCI is not set
++# CONFIG_ARCH_OMAP1 is not set
++
++#
++# Multiple platform selection
++#
++
++#
++# CPU Core family selection
++#
++# CONFIG_ARCH_MULTI_V6 is not set
++CONFIG_ARCH_MULTI_V7=y
++CONFIG_ARCH_MULTI_V6_V7=y
++# CONFIG_ARCH_MULTI_CPU_AUTO is not set
++# CONFIG_ARCH_VIRT is not set
++# CONFIG_ARCH_MVEBU is not set
++# CONFIG_ARCH_BCM is not set
++# CONFIG_ARCH_BERLIN is not set
++# CONFIG_ARCH_HIGHBANK is not set
++CONFIG_ARCH_HISI=y
++
++#
++# Hisilicon platform type
++#
++# CONFIG_ARCH_HI3xxx is not set
++# CONFIG_ARCH_HIP04 is not set
++# CONFIG_ARCH_HIX5HD2 is not set
++# CONFIG_ARCH_HI3519 is not set
++# CONFIG_ARCH_HI3519V101 is not set
++# CONFIG_ARCH_HI3516AV200 is not set
++CONFIG_ARCH_HI3559=y
++# CONFIG_ARCH_HI3556 is not set
++# CONFIG_ARCH_HI3536C is not set
++# CONFIG_ARCH_HI3531D is not set
++# CONFIG_ARCH_HI3521D is not set
++# CONFIG_ARCH_KEYSTONE is not set
++# CONFIG_ARCH_MESON is not set
++# CONFIG_ARCH_MXC is not set
++# CONFIG_ARCH_MEDIATEK is not set
++
++#
++# TI OMAP/AM/DM/DRA Family
++#
++# CONFIG_ARCH_OMAP3 is not set
++# CONFIG_ARCH_OMAP4 is not set
++# CONFIG_SOC_OMAP5 is not set
++# CONFIG_SOC_AM33XX is not set
++# CONFIG_SOC_AM43XX is not set
++# CONFIG_SOC_DRA7XX is not set
++# CONFIG_ARCH_QCOM is not set
++# CONFIG_ARCH_ROCKCHIP is not set
++# CONFIG_ARCH_SOCFPGA is not set
++# CONFIG_PLAT_SPEAR is not set
++# CONFIG_ARCH_STI is not set
++# CONFIG_ARCH_S5PV210 is not set
++# CONFIG_ARCH_EXYNOS is not set
++# CONFIG_ARCH_SHMOBILE_MULTI is not set
++# CONFIG_ARCH_SUNXI is not set
++# CONFIG_ARCH_SIRF is not set
++# CONFIG_ARCH_TEGRA is not set
++# CONFIG_ARCH_U8500 is not set
++# CONFIG_ARCH_VEXPRESS is not set
++# CONFIG_ARCH_WM8850 is not set
++# CONFIG_ARCH_ZYNQ is not set
++CONFIG_ARM_TIMER_SP804=y
++
++#
++# Processor Type
++#
++CONFIG_CPU_V7=y
++CONFIG_CPU_32v6K=y
++CONFIG_CPU_32v7=y
++CONFIG_CPU_ABRT_EV7=y
++CONFIG_CPU_PABRT_V7=y
++CONFIG_CPU_CACHE_V7=y
++CONFIG_CPU_CACHE_VIPT=y
++CONFIG_CPU_COPY_V6=y
++CONFIG_CPU_TLB_V7=y
++CONFIG_CPU_HAS_ASID=y
++CONFIG_CPU_CP15=y
++CONFIG_CPU_CP15_MMU=y
++
++#
++# Processor Features
++#
++# CONFIG_ARM_LPAE is not set
++# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
++CONFIG_ARM_THUMB=y
++# CONFIG_ARM_THUMBEE is not set
++CONFIG_ARM_VIRT_EXT=y
++CONFIG_SWP_EMULATE=y
++# CONFIG_CPU_ICACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_DISABLE is not set
++# CONFIG_CPU_BPREDICT_DISABLE is not set
++CONFIG_KUSER_HELPERS=y
++CONFIG_MIGHT_HAVE_CACHE_L2X0=y
++# CONFIG_CACHE_L2X0 is not set
++CONFIG_ARM_L1_CACHE_SHIFT_6=y
++CONFIG_ARM_L1_CACHE_SHIFT=6
++CONFIG_ARM_DMA_MEM_BUFFERABLE=y
++CONFIG_MULTI_IRQ_HANDLER=y
++# CONFIG_ARM_ERRATA_430973 is not set
++# CONFIG_ARM_ERRATA_720789 is not set
++# CONFIG_ARM_ERRATA_754322 is not set
++# CONFIG_ARM_ERRATA_775420 is not set
++# CONFIG_ARM_ERRATA_773022 is not set
++
++#
++# Bus support
++#
++CONFIG_ARM_AMBA=y
++# CONFIG_PCI is not set
++# CONFIG_PCI_SYSCALL is not set
++# CONFIG_PCCARD is not set
++
++#
++# Kernel Features
++#
++CONFIG_HAVE_SMP=y
++# CONFIG_SMP is not set
++CONFIG_DISABLE_CPU_SCHED_DOMAIN_BALANCE=y
++CONFIG_HAVE_ARM_ARCH_TIMER=y
++CONFIG_VMSPLIT_3G=y
++# CONFIG_VMSPLIT_2G is not set
++# CONFIG_VMSPLIT_1G is not set
++CONFIG_PAGE_OFFSET=0xC0000000
++# CONFIG_ARM_PSCI is not set
++CONFIG_ARCH_NR_GPIO=0
++CONFIG_PREEMPT_NONE=y
++# CONFIG_PREEMPT_VOLUNTARY is not set
++# CONFIG_PREEMPT is not set
++CONFIG_HZ_FIXED=0
++# CONFIG_HZ_100 is not set
++# CONFIG_HZ_200 is not set
++# CONFIG_HZ_250 is not set
++# CONFIG_HZ_300 is not set
++# CONFIG_HZ_500 is not set
++CONFIG_HZ_1000=y
++CONFIG_HZ=1000
++# CONFIG_SCHED_HRTICK is not set
++# CONFIG_THUMB2_KERNEL is not set
++CONFIG_AEABI=y
++# CONFIG_OABI_COMPAT is not set
++# 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_ARCH_WANT_GENERAL_HUGETLB=y
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_HAVE_MEMBLOCK=y
++CONFIG_NO_BOOTMEM=y
++CONFIG_MEMORY_ISOLATION=y
++# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=4
++CONFIG_COMPACTION=y
++CONFIG_MIGRATION=y
++# CONFIG_PHYS_ADDR_T_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_BOUNCE=y
++# CONFIG_KSM is not set
++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
++CONFIG_NEED_PER_CPU_KM=y
++# CONFIG_CLEANCACHE is not set
++CONFIG_CMA=y
++# CONFIG_CMA_DEBUG is not set
++CONFIG_CMA_AREAS=7
++# CONFIG_ZPOOL is not set
++# CONFIG_ZBUD is not set
++# CONFIG_ZSMALLOC 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_SWIOTLB=y
++CONFIG_IOMMU_HELPER=y
++# CONFIG_XEN is not set
++# CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART is not set
++
++#
++# Boot options
++#
++CONFIG_USE_OF=y
++CONFIG_ATAGS=y
++# CONFIG_DEPRECATED_PARAM_STRUCT is not set
++# CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE is not set
++CONFIG_ZBOOT_ROM_TEXT=0
++CONFIG_ZBOOT_ROM_BSS=0
++CONFIG_ARM_APPENDED_DTB=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_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_GOV_COMMON=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 is not set
++CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
++# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE is not set
++CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
++CONFIG_CPU_FREQ_GOV_POWERSAVE=y
++CONFIG_CPU_FREQ_GOV_USERSPACE=y
++CONFIG_CPU_FREQ_GOV_ONDEMAND=y
++CONFIG_CPU_FREQ_GOV_INTERACTIVE=y
++# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
++# CONFIG_CPUFREQ_DT is not set
++
++#
++# ARM CPU frequency scaling drivers
++#
++# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set
++
++#
++# CPU Idle
++#
++# CONFIG_CPU_IDLE is not set
++# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++CONFIG_VFP=y
++CONFIG_VFPv3=y
++CONFIG_NEON=y
++CONFIG_KERNEL_MODE_NEON=y
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
++CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
++CONFIG_BINFMT_SCRIPT=y
++# CONFIG_HAVE_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
++CONFIG_COREDUMP=y
++
++#
++# Power management options
++#
++CONFIG_SUSPEND=y
++CONFIG_SUSPEND_FREEZER=y
++# CONFIG_WAKELOCK is not set
++# CONFIG_HISI_SNAPSHOT_BOOT is not set
++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_OPP=y
++CONFIG_PM_CLK=y
++# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set
++CONFIG_CPU_PM=y
++# CONFIG_SUSPEND_TIME is not set
++CONFIG_ARCH_SUSPEND_POSSIBLE=y
++CONFIG_ARM_CPU_SUSPEND=y
++CONFIG_ARCH_HIBERNATION_POSSIBLE=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_NET_IP_TUNNEL is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_NET_IPVTI is not set
++# CONFIG_NET_UDP_TUNNEL is not set
++# CONFIG_NET_FOU is not set
++# CONFIG_GENEVE 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 is not set
++CONFIG_INET_XFRM_MODE_TRANSPORT=y
++CONFIG_INET_XFRM_MODE_TUNNEL=y
++CONFIG_INET_XFRM_MODE_BEET=y
++CONFIG_INET_LRO=y
++CONFIG_INET_DIAG=y
++CONFIG_INET_TCP_DIAG=y
++# CONFIG_INET_UDP_DIAG is not set
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++# CONFIG_TCP_MD5SIG is not set
++# CONFIG_IPV6 is not set
++# CONFIG_ANDROID_PARANOID_NETWORK is not set
++CONFIG_NET_ACTIVITY_STATS=y
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NET_PTP_CLASSIFY 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_NF_TABLES is not set
++# CONFIG_NETFILTER_XTABLES is not set
++# CONFIG_IP_SET is not set
++# CONFIG_IP_VS is not set
++
++#
++# IP: Netfilter Configuration
++#
++# CONFIG_NF_DEFRAG_IPV4 is not set
++# CONFIG_NF_LOG_ARP is not set
++# CONFIG_NF_LOG_IPV4 is not set
++# CONFIG_NF_REJECT_IPV4 is not set
++# CONFIG_IP_NF_IPTABLES is not set
++# CONFIG_IP_NF_ARPTABLES 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_HAVE_NET_DSA=y
++# 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_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_VSOCKETS is not set
++# CONFIG_NETLINK_MMAP is not set
++# CONFIG_NETLINK_DIAG is not set
++# CONFIG_NET_MPLS_GSO is not set
++# CONFIG_HSR is not set
++# CONFIG_CGROUP_NET_PRIO is not set
++# CONFIG_CGROUP_NET_CLASSID is not set
++CONFIG_NET_RX_BUSY_POLL=y
++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 is not set
++CONFIG_DEVTMPFS=y
++CONFIG_DEVTMPFS_MOUNT=y
++CONFIG_STANDALONE=y
++# CONFIG_PREVENT_FIRMWARE_BUILD is not set
++CONFIG_FW_LOADER=y
++# CONFIG_FIRMWARE_IN_KERNEL is not set
++CONFIG_EXTRA_FIRMWARE=""
++# CONFIG_FW_LOADER_USER_HELPER_FALLBACK is not set
++CONFIG_ALLOW_DEV_COREDUMP=y
++# 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_HAVE_CPU_AUTOPROBE is not set
++CONFIG_REGMAP=y
++CONFIG_REGMAP_MMIO=y
++CONFIG_DMA_SHARED_BUFFER=y
++# CONFIG_FENCE_TRACE is not set
++CONFIG_DMA_CMA=y
++
++#
++# Default contiguous memory area size:
++#
++CONFIG_CMA_SIZE_MBYTES=16
++CONFIG_CMA_SIZE_SEL_MBYTES=y
++# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set
++# CONFIG_CMA_SIZE_SEL_MIN is not set
++# CONFIG_CMA_SIZE_SEL_MAX is not set
++CONFIG_CMA_ALIGNMENT=8
++
++#
++# Bus devices
++#
++# CONFIG_BRCMSTB_GISB_ARB is not set
++CONFIG_ARM_CCI=y
++# CONFIG_VEXPRESS_CONFIG 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=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_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_HIFMC=y
++CONFIG_HIFMC_SPI_NAND=y
++# CONFIG_HIFMC_NAND 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_SST25L is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_PHRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++# CONFIG_MTD_BLOCK2MTD is not set
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOCG3 is not set
++CONFIG_MTD_NAND_IDS=y
++CONFIG_MTD_NAND_ECC=y
++# CONFIG_MTD_NAND_ECC_SMC is not set
++CONFIG_MTD_NAND=y
++# CONFIG_MTD_NAND_ECC_BCH is not set
++# CONFIG_MTD_SM_COMMON is not set
++# CONFIG_MTD_NAND_DENALI is not set
++# CONFIG_MTD_NAND_OMAP_BCH_BUILD is not set
++# CONFIG_MTD_NAND_DISKONCHIP is not set
++# CONFIG_MTD_NAND_DOCG4 is not set
++# CONFIG_MTD_NAND_NANDSIM is not set
++# CONFIG_MTD_NAND_PLATFORM is not set
++# CONFIG_HISI_NAND_FS_MAY_NO_YAFFS2 is not set
++# CONFIG_HISI_NAND_ECC_STATUS_REPORT is not set
++# CONFIG_MTD_NAND_HINFC610 is not set
++# CONFIG_HIFMC100_NAND is not set
++CONFIG_HIFMC100_SPI_NAND=y
++CONFIG_SPI_NAND_MAX_CHIP_NUM=1
++# CONFIG_HIFMC100_HARDWARE_PAGESIZE_ECC is not set
++CONFIG_HIFMC100_AUTO_PAGESIZE_ECC=y
++# CONFIG_HIFMC100_PAGESIZE_AUTO_ECC_NONE is not set
++# CONFIG_MTD_ONENAND is not set
++
++#
++# LPDDR & LPDDR2 PCM memory drivers
++#
++# CONFIG_MTD_LPDDR is not set
++# CONFIG_MTD_LPDDR2_NVM is not set
++# CONFIG_MTD_SPI_NOR is not set
++CONFIG_MTD_UBI=y
++CONFIG_MTD_UBI_WL_THRESHOLD=4096
++CONFIG_MTD_UBI_BEB_LIMIT=20
++# CONFIG_MTD_UBI_FASTMAP is not set
++# CONFIG_MTD_UBI_GLUEBI is not set
++# CONFIG_MTD_UBI_BLOCK is not set
++CONFIG_DTC=y
++CONFIG_OF=y
++
++#
++# Device Tree and Open Firmware support
++#
++# 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_NET=y
++CONFIG_OF_MDIO=y
++CONFIG_OF_MTD=y
++CONFIG_OF_RESERVED_MEM=y
++CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
++# CONFIG_PARPORT is not set
++CONFIG_BLK_DEV=y
++# CONFIG_BLK_DEV_NULL_BLK is not set
++# CONFIG_BLK_DEV_COW_COMMON is not set
++# CONFIG_BLK_DEV_LOOP 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=65536
++# CONFIG_BLK_DEV_XIP is not set
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH 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_DUMMY_IRQ 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_UID_STAT is not set
++# CONFIG_BMP085_I2C is not set
++# CONFIG_BMP085_SPI is not set
++# CONFIG_USB_SWITCH_FSA9480 is not set
++# CONFIG_LATTICE_ECP3_CONFIG is not set
++# CONFIG_SRAM is not set
++# CONFIG_C2PORT is not set
++
++#
++# EEPROM support
++#
++# CONFIG_EEPROM_AT24 is not set
++# CONFIG_EEPROM_AT25 is not set
++# CONFIG_EEPROM_LEGACY is not set
++# CONFIG_EEPROM_MAX6875 is not set
++# CONFIG_EEPROM_93CX6 is not set
++# CONFIG_EEPROM_93XX46 is not set
++
++#
++# Texas Instruments shared transport line discipline
++#
++# 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
++
++#
++# Intel MIC Bus Driver
++#
++
++#
++# Intel MIC Host Driver
++#
++
++#
++# Intel MIC Card Driver
++#
++# CONFIG_ECHO is not set
++# CONFIG_CXL_BASE is not set
++
++#
++# hisi 'himm/himd.l/himc'support
++#
++# CONFIG_HISI_REG 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_NETLINK is not set
++# CONFIG_SCSI_MQ_DEFAULT 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_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 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_NET_CORE=y
++# CONFIG_BONDING is not set
++# CONFIG_DUMMY is not set
++# CONFIG_EQUALIZER is not set
++# CONFIG_NET_TEAM is not set
++# CONFIG_MACVLAN is not set
++# CONFIG_VXLAN is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_TUN is not set
++# CONFIG_VETH is not set
++# CONFIG_NLMON is not set
++
++#
++# 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_NET_DSA_MV88E6171 is not set
++# CONFIG_NET_DSA_BCM_SF2 is not set
++# CONFIG_ETHERNET is not set
++CONFIG_PHYLIB=y
++
++#
++# MII PHY device drivers
++#
++# CONFIG_AT803X_PHY is not set
++# CONFIG_AMD_PHY is not set
++# CONFIG_AMD_XGBE_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 is not set
++# CONFIG_BROADCOM_PHY is not set
++# CONFIG_BCM7XXX_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_MMIOREG is not set
++# CONFIG_MDIO_BCM_UNIMAC is not set
++# CONFIG_MDIO_HISI_FEMAC is not set
++# CONFIG_MDIO_HISI_GEMAC is not set
++# CONFIG_MICREL_KS8995MA is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++
++#
++# Host-side USB support is needed for USB Network Adapter support
++#
++CONFIG_USB_NET_DRIVERS=m
++# 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_RTL8152 is not set
++# CONFIG_USB_USBNET is not set
++# CONFIG_USB_IPHETH is not set
++CONFIG_WLAN=y
++# CONFIG_WIFI_CONTROL_FUNC is not set
++# 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 is not set
++# CONFIG_INPUT_SPARSEKMAP is not set
++# CONFIG_INPUT_MATRIXKMAP is not set
++
++#
++# Userland interfaces
++#
++# CONFIG_INPUT_MOUSEDEV is not set
++# CONFIG_INPUT_JOYDEV is not set
++CONFIG_INPUT_EVDEV=y
++# CONFIG_INPUT_EVBUG is not set
++# CONFIG_INPUT_KEYRESET is not set
++# CONFIG_INPUT_KEYCOMBO is not set
++
++#
++# Input Device Drivers
++#
++# CONFIG_INPUT_KEYBOARD is not set
++# CONFIG_INPUT_MOUSE is not set
++# CONFIG_INPUT_JOYSTICK is not set
++# CONFIG_INPUT_TABLET is not set
++# CONFIG_INPUT_TOUCHSCREEN is not set
++# CONFIG_INPUT_MISC is not set
++
++#
++# Hardware I/O ports
++#
++# CONFIG_SERIO is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++CONFIG_TTY=y
++CONFIG_VT=y
++CONFIG_CONSOLE_TRANSLATIONS=y
++CONFIG_VT_CONSOLE=y
++CONFIG_VT_CONSOLE_SLEEP=y
++CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
++CONFIG_UNIX98_PTYS=y
++# CONFIG_DEVPTS_MULTIPLE_INSTANCES 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_DEVMEM=y
++CONFIG_DEVKMEM=y
++
++#
++# Serial drivers
++#
++CONFIG_SERIAL_EARLYCON=y
++# CONFIG_SERIAL_8250 is not set
++
++#
++# Non-8250 serial port support
++#
++# CONFIG_SERIAL_AMBA_PL010 is not set
++CONFIG_SERIAL_AMBA_PL011=y
++CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
++# CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST is not set
++# 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_SC16IS7XX is not set
++# CONFIG_SERIAL_ALTERA_JTAGUART is not set
++# CONFIG_SERIAL_ALTERA_UART is not set
++# CONFIG_SERIAL_XILINX_PS_UART is not set
++# CONFIG_SERIAL_ARC is not set
++# CONFIG_SERIAL_FSL_LPUART is not set
++# CONFIG_SERIAL_ST_ASC is not set
++# CONFIG_TTY_PRINTK is not set
++# CONFIG_HVC_DCC is not set
++# CONFIG_IPMI_HANDLER is not set
++CONFIG_HW_RANDOM=y
++# CONFIG_HW_RANDOM_TIMERIOMEM is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++# CONFIG_DCC_TTY is not set
++# CONFIG_XILLYBUS is not set
++
++#
++# I2C support
++#
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++# CONFIG_I2C_COMPAT is not set
++CONFIG_I2C_CHARDEV=y
++CONFIG_I2C_MUX=m
++
++#
++# Multiplexer I2C Chip support
++#
++# CONFIG_I2C_MUX_PCA9541 is not set
++# CONFIG_I2C_HELPER_AUTO is not set
++# CONFIG_I2C_SMBUS is not set
++
++#
++# I2C Algorithms
++#
++# CONFIG_I2C_ALGOBIT is not set
++# CONFIG_I2C_ALGOPCF is not set
++# CONFIG_I2C_ALGOPCA is not set
++
++#
++# I2C Hardware Bus support
++#
++
++#
++# I2C system bus drivers (mostly embedded / system-on-chip)
++#
++# CONFIG_I2C_DESIGNWARE_PLATFORM is not set
++# CONFIG_I2C_HIBVT is not set
++CONFIG_I2C_HISI_V110=y
++# CONFIG_I2C_NOMADIK 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_RK3X 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_ROBOTFUZZ_OSIF 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_CADENCE is not set
++# CONFIG_SPI_FSL_SPI is not set
++CONFIG_SPI_PL022=y
++# CONFIG_SPI_PXA2XX_PCI is not set
++# CONFIG_SPI_ROCKCHIP 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=y
++# CONFIG_SPI_TLE62X0 is not set
++# CONFIG_SPMI is not set
++# CONFIG_HSI is not set
++
++#
++# PPS support
++#
++# CONFIG_PPS is not set
++
++#
++# PPS generators support
++#
++
++#
++# PTP clock support
++#
++# CONFIG_PTP_1588_CLOCK is not set
++
++#
++# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
++#
++CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
++CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
++# CONFIG_GPIOLIB is not set
++# CONFIG_W1 is not set
++CONFIG_POWER_SUPPLY=y
++# CONFIG_POWER_SUPPLY_DEBUG is not set
++# CONFIG_PDA_POWER is not set
++# CONFIG_TEST_POWER is not set
++# CONFIG_BATTERY_DS2780 is not set
++# CONFIG_BATTERY_DS2781 is not set
++# CONFIG_BATTERY_DS2782 is not set
++# CONFIG_BATTERY_SBS is not set
++# CONFIG_BATTERY_BQ27x00 is not set
++# CONFIG_BATTERY_MAX17040 is not set
++# CONFIG_BATTERY_MAX17042 is not set
++# CONFIG_CHARGER_MAX8903 is not set
++# CONFIG_CHARGER_LP8727 is not set
++# CONFIG_CHARGER_BQ2415X is not set
++# CONFIG_CHARGER_SMB347 is not set
++CONFIG_POWER_RESET=y
++# CONFIG_POWER_RESET_BRCMSTB is not set
++CONFIG_POWER_RESET_HISI=y
++# CONFIG_POWER_RESET_RESTART is not set
++# CONFIG_POWER_RESET_VERSATILE is not set
++# CONFIG_POWER_RESET_SYSCON is not set
++# CONFIG_POWER_AVS is not set
++# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
++# CONFIG_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=y
++# CONFIG_MFD_AS3711 is not set
++# CONFIG_MFD_AS3722 is not set
++# CONFIG_PMIC_ADP5520 is not set
++# CONFIG_MFD_BCM590XX is not set
++# CONFIG_MFD_AXP20X is not set
++# CONFIG_MFD_CROS_EC is not set
++# CONFIG_PMIC_DA903X is not set
++# CONFIG_MFD_DA9052_SPI is not set
++# CONFIG_MFD_DA9052_I2C is not set
++# CONFIG_MFD_DA9055 is not set
++# CONFIG_MFD_DA9063 is not set
++# CONFIG_MFD_MC13XXX_SPI is not set
++# CONFIG_MFD_MC13XXX_I2C is not set
++# CONFIG_MFD_HI6421_PMIC is not set
++CONFIG_MFD_HISI_FMC=y
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_INTEL_SOC_PMIC is not set
++# CONFIG_MFD_KEMPLD is not set
++# CONFIG_MFD_88PM800 is not set
++# CONFIG_MFD_88PM805 is not set
++# CONFIG_MFD_88PM860X is not set
++# CONFIG_MFD_MAX14577 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_MENF21BMC is not set
++# CONFIG_EZX_PCAP is not set
++# CONFIG_MFD_VIPERBOARD is not set
++# CONFIG_MFD_RETU is not set
++# CONFIG_MFD_PCF50633 is not set
++# CONFIG_MFD_PM8921_CORE is not set
++# CONFIG_MFD_RTSX_USB is not set
++# CONFIG_MFD_RC5T583 is not set
++# CONFIG_MFD_RK808 is not set
++# CONFIG_MFD_RN5T618 is not set
++# CONFIG_MFD_SEC_CORE is not set
++# CONFIG_MFD_SI476X_CORE is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_MFD_SMSC is not set
++# CONFIG_ABX500_CORE is not set
++# CONFIG_MFD_STMPE is not set
++CONFIG_MFD_SYSCON=y
++# CONFIG_MFD_TI_AM335X_TSCADC is not set
++# CONFIG_MFD_LP3943 is not set
++# CONFIG_MFD_LP8788 is not set
++# CONFIG_MFD_PALMAS is not set
++# CONFIG_TPS6105X is not set
++# CONFIG_TPS6507X is not set
++# CONFIG_MFD_TPS65090 is not set
++# CONFIG_MFD_TPS65217 is not set
++# CONFIG_MFD_TPS65218 is not set
++# CONFIG_MFD_TPS6586X is not set
++# CONFIG_MFD_TPS80031 is not set
++# CONFIG_TWL4030_CORE is not set
++# CONFIG_TWL6040_CORE is not set
++# CONFIG_MFD_WL1273_CORE is not set
++# CONFIG_MFD_LM3533 is not set
++# CONFIG_MFD_TC3589X is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_MFD_T7L66XB is not set
++# CONFIG_MFD_TC6387XB is not set
++# CONFIG_MFD_TC6393XB is not set
++# CONFIG_MFD_ARIZONA_I2C is not set
++# CONFIG_MFD_ARIZONA_SPI is not set
++# CONFIG_MFD_WM8400 is not set
++# CONFIG_MFD_WM831X_I2C is not set
++# CONFIG_MFD_WM831X_SPI is not set
++# CONFIG_MFD_WM8350_I2C is not set
++# CONFIG_MFD_WM8994 is not set
++CONFIG_REGULATOR=y
++# CONFIG_REGULATOR_DEBUG is not set
++# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
++# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
++# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
++# CONFIG_REGULATOR_ACT8865 is not set
++# CONFIG_REGULATOR_AD5398 is not set
++# CONFIG_REGULATOR_ANATOP is not set
++# CONFIG_REGULATOR_DA9210 is not set
++# CONFIG_REGULATOR_DA9211 is not set
++# CONFIG_REGULATOR_FAN53555 is not set
++# CONFIG_REGULATOR_ISL9305 is not set
++# CONFIG_REGULATOR_ISL6271A is not set
++# CONFIG_REGULATOR_LP3971 is not set
++# CONFIG_REGULATOR_LP3972 is not set
++# CONFIG_REGULATOR_LP872X is not set
++# CONFIG_REGULATOR_LP8755 is not set
++# CONFIG_REGULATOR_LTC3589 is not set
++# CONFIG_REGULATOR_MAX1586 is not set
++# CONFIG_REGULATOR_MAX8649 is not set
++# CONFIG_REGULATOR_MAX8660 is not set
++# CONFIG_REGULATOR_MAX8952 is not set
++# CONFIG_REGULATOR_MAX8973 is not set
++# CONFIG_REGULATOR_PFUZE100 is not set
++# CONFIG_REGULATOR_TPS51632 is not set
++# CONFIG_REGULATOR_TPS62360 is not set
++# CONFIG_REGULATOR_TPS65023 is not set
++# CONFIG_REGULATOR_TPS6507X is not set
++# CONFIG_REGULATOR_TPS6524X is not set
++CONFIG_MEDIA_SUPPORT=m
++
++#
++# Multimedia core support
++#
++CONFIG_MEDIA_CAMERA_SUPPORT=y
++# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set
++# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set
++# CONFIG_MEDIA_RADIO_SUPPORT is not set
++# CONFIG_MEDIA_SDR_SUPPORT is not set
++# CONFIG_MEDIA_RC_SUPPORT is not set
++# CONFIG_MEDIA_CONTROLLER is not set
++CONFIG_VIDEO_DEV=m
++CONFIG_VIDEO_V4L2=m
++# CONFIG_VIDEO_ADV_DEBUG is not set
++# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
++CONFIG_VIDEOBUF2_CORE=m
++CONFIG_VIDEOBUF2_MEMOPS=m
++CONFIG_VIDEOBUF2_VMALLOC=m
++# CONFIG_TTPCI_EEPROM is not set
++
++#
++# Media drivers
++#
++# CONFIG_MEDIA_USB_SUPPORT is not set
++# CONFIG_V4L_PLATFORM_DRIVERS is not set
++# CONFIG_V4L_MEM2MEM_DRIVERS is not set
++# CONFIG_V4L_TEST_DRIVERS is not set
++
++#
++# Supported MMC/SDIO adapters
++#
++# CONFIG_CYPRESS_FIRMWARE is not set
++
++#
++# Media ancillary drivers (tuners, sensors, i2c, frontends)
++#
++CONFIG_MEDIA_SUBDRV_AUTOSELECT=y
++
++#
++# Audio decoders, processors and mixers
++#
++
++#
++# RDS decoders
++#
++
++#
++# Video decoders
++#
++
++#
++# Video and audio decoders
++#
++
++#
++# Video encoders
++#
++
++#
++# Camera sensor devices
++#
++
++#
++# Flash devices
++#
++
++#
++# Video improvement chips
++#
++
++#
++# Audio/Video compression chips
++#
++
++#
++# Miscellaneous helper chips
++#
++
++#
++# Sensors used on soc_camera driver
++#
++
++#
++# Tools to develop new frontends
++#
++# CONFIG_DVB_DUMMY_FE is not set
++
++#
++# Graphics support
++#
++# CONFIG_IMX_IPUV3_CORE is not set
++
++#
++# Direct Rendering Manager
++#
++# CONFIG_DRM is not set
++
++#
++# Frame buffer Devices
++#
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++CONFIG_FB_CMDLINE=y
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++# CONFIG_FB_CFB_FILLRECT is not set
++# CONFIG_FB_CFB_COPYAREA is not set
++# CONFIG_FB_CFB_IMAGEBLIT is not set
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# 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_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_ARMCLCD is not set
++# CONFIG_FB_OPENCORES is not set
++# CONFIG_FB_S1D13XXX is not set
++# CONFIG_FB_SMSCUFX is not set
++# CONFIG_FB_UDL is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_BROADSHEET is not set
++# CONFIG_FB_AUO_K190X is not set
++# CONFIG_FB_SIMPLE is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++# CONFIG_VGASTATE is not set
++
++#
++# Console display driver support
++#
++CONFIG_DUMMY_CONSOLE=y
++# CONFIG_FRAMEBUFFER_CONSOLE is not set
++# CONFIG_LOGO is not set
++# CONFIG_SOUND is not set
++
++#
++# HID support
++#
++CONFIG_HID=y
++# CONFIG_HID_BATTERY_STRENGTH is not set
++# CONFIG_HIDRAW is not set
++# CONFIG_UHID is not set
++CONFIG_HID_GENERIC=y
++
++#
++# Special HID drivers
++#
++CONFIG_HID_A4TECH=y
++# CONFIG_HID_ACRUX is not set
++CONFIG_HID_APPLE=y
++# CONFIG_HID_APPLEIR is not set
++# CONFIG_HID_AUREAL is not set
++CONFIG_HID_BELKIN=y
++CONFIG_HID_CHERRY=y
++CONFIG_HID_CHICONY=y
++CONFIG_HID_CYPRESS=y
++# CONFIG_HID_DRAGONRISE is not set
++# CONFIG_HID_EMS_FF is not set
++# CONFIG_HID_ELECOM is not set
++# CONFIG_HID_ELO is not set
++CONFIG_HID_EZKEY=y
++# CONFIG_HID_HOLTEK is not set
++# CONFIG_HID_HUION 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_ICADE is not set
++# CONFIG_HID_TWINHAN is not set
++CONFIG_HID_KENSINGTON=y
++# CONFIG_HID_LCPOWER is not set
++# CONFIG_HID_LENOVO is not set
++CONFIG_HID_LOGITECH=y
++# CONFIG_HID_LOGITECH_HIDPP is not set
++# CONFIG_LOGITECH_FF is not set
++# CONFIG_LOGIRUMBLEPAD2_FF is not set
++# CONFIG_LOGIG940_FF is not set
++# CONFIG_LOGIWHEELS_FF is not set
++# CONFIG_HID_MAGICMOUSE is not set
++CONFIG_HID_MICROSOFT=y
++CONFIG_HID_MONTEREY=y
++# 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_PENMOUNT is not set
++# CONFIG_HID_PETALYNX is not set
++# CONFIG_HID_PICOLCD is not set
++# CONFIG_HID_PRIMAX is not set
++# CONFIG_HID_ROCCAT is not set
++# CONFIG_HID_SAITEK is not set
++# CONFIG_HID_SAMSUNG is not set
++# CONFIG_HID_SPEEDLINK is not set
++# CONFIG_HID_STEELSERIES is not set
++# CONFIG_HID_SUNPLUS is not set
++# CONFIG_HID_RMI 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_XINMO is not set
++# CONFIG_HID_ZEROPLUS is not set
++# CONFIG_HID_ZYDACRON is not set
++# CONFIG_HID_SENSOR_HUB is not set
++
++#
++# USB HID support
++#
++CONFIG_USB_HID=m
++# CONFIG_HID_PID is not set
++# CONFIG_USB_HIDDEV is not set
++
++#
++# USB HID Boot Protocol drivers
++#
++# CONFIG_USB_KBD is not set
++# CONFIG_USB_MOUSE is not set
++
++#
++# I2C HID support
++#
++# CONFIG_I2C_HID is not set
++CONFIG_USB_OHCI_LITTLE_ENDIAN=y
++CONFIG_USB_SUPPORT=y
++CONFIG_USB_COMMON=y
++CONFIG_USB_ARCH_HAS_HCD=y
++CONFIG_USB=m
++# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
++
++#
++# Miscellaneous USB options
++#
++# CONFIG_USB_DEFAULT_PERSIST is not set
++# CONFIG_USB_DYNAMIC_MINORS is not set
++# CONFIG_USB_OTG_WHITELIST is not set
++# CONFIG_USB_OTG_BLACKLIST_HUB is not set
++# CONFIG_USB_OTG_FSM is not set
++# CONFIG_USB_MON is not set
++# CONFIG_USB_WUSB_CBAF is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_C67X00_HCD is not set
++# CONFIG_USB_XHCI_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_FUSBH200_HCD is not set
++# CONFIG_USB_FOTG210_HCD is not set
++# CONFIG_USB_MAX3421_HCD is not set
++# CONFIG_USB_OHCI_HCD is not set
++# CONFIG_USB_SL811_HCD is not set
++# CONFIG_USB_R8A66597_HCD is not set
++# CONFIG_USB_HCD_TEST_MODE is not set
++
++#
++# USB Device Class drivers
++#
++# CONFIG_USB_ACM is not set
++# CONFIG_USB_PRINTER is not set
++# CONFIG_USB_WDM is not set
++# CONFIG_USB_TMC is not set
++
++#
++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
++#
++
++#
++# also be needed; see USB_STORAGE Help for more info
++#
++# CONFIG_USB_STORAGE is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++# CONFIG_USBIP_CORE is not set
++# CONFIG_USB_MUSB_HDRC is not set
++# CONFIG_USB_DWC3 is not set
++# CONFIG_USB_DWC2 is not set
++# CONFIG_USB_CHIPIDEA is not set
++
++#
++# USB port drivers
++#
++# CONFIG_USB_SERIAL is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
++# CONFIG_USB_SEVSEG is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
++# CONFIG_USB_APPLEDISPLAY is not set
++# CONFIG_USB_LD is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
++# CONFIG_USB_IOWARRIOR is not set
++# CONFIG_USB_TEST is not set
++# CONFIG_USB_EHSET_TEST_FIXTURE is not set
++# CONFIG_USB_ISIGHTFW is not set
++# CONFIG_USB_YUREX is not set
++# CONFIG_USB_EZUSB_FX2 is not set
++# CONFIG_USB_HSIC_USB3503 is not set
++# CONFIG_USB_LINK_LAYER_TEST is not set
++
++#
++# USB Physical Layer drivers
++#
++# CONFIG_USB_PHY is not set
++# CONFIG_NOP_USB_XCEIV is not set
++# CONFIG_AM335X_PHY_USB is not set
++# CONFIG_USB_ISP1301 is not set
++# CONFIG_USB_ULPI is not set
++CONFIG_USB_GADGET=y
++# CONFIG_USB_GADGET_DEBUG is not set
++# CONFIG_USB_GADGET_DEBUG_FILES is not set
++CONFIG_USB_GADGET_VBUS_DRAW=2
++CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2
++
++#
++# USB Peripheral Controller
++#
++# CONFIG_USB_FUSB300 is not set
++# CONFIG_USB_FOTG210_UDC is not set
++# CONFIG_USB_GR_UDC is not set
++# CONFIG_USB_R8A66597 is not set
++# CONFIG_USB_PXA27X is not set
++# CONFIG_USB_MV_UDC is not set
++CONFIG_HIUSB_DEVICE2_0=y
++CONFIG_USB_HISI_UDC=m
++# CONFIG_USB_AUTO_SWITCH is not set
++# CONFIG_HIUSB_DEVICE3_0 is not set
++# CONFIG_USB_MV_U3D is not set
++# CONFIG_USB_M66592 is not set
++# CONFIG_USB_NET2272 is not set
++# CONFIG_USB_GADGET_XILINX is not set
++CONFIG_USB_LIBCOMPOSITE=m
++CONFIG_USB_F_ACM=m
++CONFIG_USB_U_SERIAL=m
++CONFIG_USB_U_ETHER=m
++CONFIG_USB_F_RNDIS=m
++CONFIG_USB_F_MASS_STORAGE=m
++CONFIG_USB_F_UAC1=m
++CONFIG_USB_F_UVC=m
++# CONFIG_USB_CONFIGFS is not set
++# CONFIG_USB_ZERO is not set
++CONFIG_USB_AUDIO=m
++CONFIG_GADGET_UAC1=y
++# CONFIG_USB_ETH is not set
++# CONFIG_USB_G_NCM is not set
++# CONFIG_USB_GADGETFS is not set
++# CONFIG_USB_FUNCTIONFS is not set
++CONFIG_USB_MASS_STORAGE=m
++# CONFIG_USB_G_SERIAL is not set
++# CONFIG_USB_G_PRINTER is not set
++# CONFIG_USB_CDC_COMPOSITE is not set
++# CONFIG_USB_G_ACM_MS is not set
++CONFIG_USB_G_MULTI=m
++CONFIG_USB_G_MULTI_RNDIS=y
++# CONFIG_USB_G_MULTI_CDC is not set
++# CONFIG_USB_G_HID is not set
++# CONFIG_USB_G_DBGP is not set
++# CONFIG_USB_G_WEBCAM is not set
++CONFIG_USB_G_WEBCAM_AUDIO=m
++# CONFIG_UWB is not set
++CONFIG_MMC=m
++# CONFIG_MMC_DEBUG is not set
++# CONFIG_MMC_CLKGATE is not set
++CONFIG_MMC_EMBEDDED_SDIO=y
++# CONFIG_MMC_PARANOID_SD_INIT is not set
++
++#
++# MMC/SD/SDIO Card Drivers
++#
++CONFIG_MMC_BLOCK=m
++CONFIG_MMC_BLOCK_MINORS=8
++CONFIG_MMC_BLOCK_BOUNCE=y
++# CONFIG_MMC_BLOCK_DEFERRED_RESUME is not set
++# CONFIG_SDIO_UART is not set
++# CONFIG_MMC_TEST is not set
++
++#
++# MMC/SD/SDIO Host Controller Drivers
++#
++# CONFIG_MMC_ARMMMCI is not set
++# CONFIG_MMC_SDHCI is not set
++# CONFIG_MMC_DW is not set
++# CONFIG_MMC_VUB300 is not set
++# CONFIG_MMC_USHC is not set
++# CONFIG_MMC_USDHI6ROL0 is not set
++CONFIG_HIMCIV200=m
++CONFIG_SEND_AUTO_STOP=y
++CONFIG_DETECT_CARD_TIME=200
++# CONFIG_MEMSTICK is not set
++# CONFIG_NEW_LEDS is not set
++# CONFIG_SWITCH is not set
++# CONFIG_ACCESSIBILITY is not set
++# CONFIG_EDAC is not set
++CONFIG_RTC_LIB=y
++# CONFIG_RTC_CLASS is not set
++# CONFIG_DMADEVICES is not set
++# CONFIG_AUXDISPLAY is not set
++# CONFIG_UIO is not set
++# CONFIG_VIRT_DRIVERS is not set
++
++#
++# Virtio drivers
++#
++# CONFIG_VIRTIO_MMIO is not set
++
++#
++# Microsoft Hyper-V guest support
++#
++# CONFIG_STAGING is not set
++
++#
++# SOC (System On Chip) specific Drivers
++#
++# CONFIG_SOC_TI is not set
++CONFIG_CLKDEV_LOOKUP=y
++CONFIG_HAVE_CLK_PREPARE=y
++CONFIG_COMMON_CLK=y
++
++#
++# Common Clock Framework
++#
++# CONFIG_COMMON_CLK_SI5351 is not set
++# CONFIG_COMMON_CLK_SI570 is not set
++# CONFIG_COMMON_CLK_PXA is not set
++# CONFIG_COMMON_CLK_QCOM is not set
++
++#
++# Hardware Spinlock drivers
++#
++
++#
++# Clock Source drivers
++#
++CONFIG_CLKSRC_OF=y
++CONFIG_CLKSRC_MMIO=y
++CONFIG_ARM_ARCH_TIMER=y
++CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y
++# CONFIG_ARM_ARCH_TIMER_VCT_ACCESS is not set
++# CONFIG_ATMEL_PIT is not set
++# CONFIG_SH_TIMER_CMT is not set
++# CONFIG_SH_TIMER_MTU2 is not set
++# CONFIG_SH_TIMER_TMU is not set
++# CONFIG_EM_TIMER_STI is not set
++# CONFIG_CLKSRC_VERSATILE is not set
++# CONFIG_MAILBOX is not set
++# CONFIG_IOMMU_SUPPORT is not set
++
++#
++# Remoteproc drivers
++#
++# CONFIG_STE_MODEM_RPROC is not set
++
++#
++# Rpmsg drivers
++#
++
++#
++# SOC (System On Chip) specific Drivers
++#
++# 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
++CONFIG_IRQCHIP=y
++CONFIG_ARM_GIC=y
++# CONFIG_IPACK_BUS is not set
++CONFIG_ARCH_HAS_RESET_CONTROLLER=y
++CONFIG_RESET_CONTROLLER=y
++# CONFIG_FMC is not set
++
++#
++# PHY Subsystem
++#
++CONFIG_GENERIC_PHY=y
++# CONFIG_BCM_KONA_USB2_PHY is not set
++CONFIG_PHY_HISI_INNO_USB2=m
++# CONFIG_POWERCAP is not set
++# CONFIG_MCB is not set
++# CONFIG_HI_DMAC is not set
++
++#
++# Hisilicon driver support
++#
++# CONFIG_CMA_MEM_SHARED is not set
++# CONFIG_CMA_ADVANCE_SHARE is not set
++
++#
++# File systems
++#
++CONFIG_DCACHE_WORD_ACCESS=y
++# CONFIG_EXT2_FS is not set
++# CONFIG_EXT3_FS is not set
++# CONFIG_EXT4_FS is not set
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_BTRFS_FS is not set
++# CONFIG_NILFS2_FS is not set
++CONFIG_FS_POSIX_ACL=y
++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 is not set
++# CONFIG_FUSE_FS is not set
++# CONFIG_OVERLAY_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_KERNFS=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=m
++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_YAFFS_FS is not set
++# CONFIG_JFFS2_FS 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 is not set
++# 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 is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V2=y
++CONFIG_NFS_V3=y
++CONFIG_NFS_V3_ACL=y
++# CONFIG_NFS_V4 is not set
++# CONFIG_NFS_SWAP is not set
++# CONFIG_ROOT_NFS is not set
++# CONFIG_NFSD is not set
++CONFIG_GRACE_PERIOD=y
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_ACL_SUPPORT=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 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=y
++# CONFIG_DLM is not set
++
++#
++# Kernel hacking
++#
++
++#
++# printk and dmesg options
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4
++# CONFIG_BOOT_PRINTK_DELAY is not set
++
++#
++# Compile-time checks and compiler options
++#
++# CONFIG_DEBUG_INFO is not set
++# CONFIG_ENABLE_WARN_DEPRECATED is not set
++# CONFIG_ENABLE_MUST_CHECK is not set
++CONFIG_FRAME_WARN=1024
++# CONFIG_STRIP_ASM_SYMS is not set
++# CONFIG_READABLE_ASM is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++# CONFIG_DEBUG_FS is not set
++# CONFIG_HEADERS_CHECK is not set
++# CONFIG_DEBUG_SECTION_MISMATCH is not set
++# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
++# CONFIG_MAGIC_SYSRQ is not set
++CONFIG_DEBUG_KERNEL=y
++
++#
++# Memory Debugging
++#
++# CONFIG_DEBUG_PAGEALLOC is not set
++# CONFIG_DEBUG_OBJECTS is not set
++# CONFIG_SLUB_STATS is not set
++CONFIG_HAVE_DEBUG_KMEMLEAK=y
++# CONFIG_DEBUG_KMEMLEAK is not set
++# CONFIG_DEBUG_STACK_USAGE is not set
++# CONFIG_DEBUG_VM is not set
++CONFIG_DEBUG_MEMORY_INIT=y
++# CONFIG_DEBUG_HIGHMEM is not set
++# CONFIG_DEBUG_SHIRQ is not set
++
++#
++# Debug Lockups and Hangs
++#
++# CONFIG_LOCKUP_DETECTOR is not set
++# CONFIG_DETECT_HUNG_TASK is not set
++CONFIG_PANIC_ON_OOPS=y
++CONFIG_PANIC_ON_OOPS_VALUE=1
++CONFIG_PANIC_TIMEOUT=0
++CONFIG_SCHED_DEBUG=y
++# CONFIG_SCHEDSTATS is not set
++# CONFIG_SCHED_STACK_END_CHECK is not set
++# CONFIG_TIMER_STATS is not set
++
++#
++# Lock Debugging (spinlocks, mutexes, etc...)
++#
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_LOCK_STAT is not set
++# CONFIG_DEBUG_ATOMIC_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_LOCK_TORTURE_TEST is not set
++CONFIG_STACKTRACE=y
++# CONFIG_DEBUG_KOBJECT is not set
++CONFIG_DEBUG_BUGVERBOSE=y
++# CONFIG_DEBUG_LIST is not set
++# CONFIG_DEBUG_PI_LIST is not set
++# CONFIG_DEBUG_SG is not set
++# CONFIG_DEBUG_NOTIFIERS is not set
++# CONFIG_DEBUG_CREDENTIALS is not set
++
++#
++# RCU Debugging
++#
++# CONFIG_SPARSE_RCU_POINTER is not set
++# CONFIG_TORTURE_TEST is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_RCU_TRACE is not set
++# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_NOTIFIER_ERROR_INJECTION is not set
++# CONFIG_FAULT_INJECTION is not set
++# CONFIG_LATENCYTOP 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 is not set
++
++#
++# Runtime Testing
++#
++# CONFIG_TEST_LIST_SORT is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_RBTREE_TEST is not set
++# CONFIG_INTERVAL_TREE_TEST is not set
++# CONFIG_PERCPU_TEST is not set
++# CONFIG_ATOMIC64_SELFTEST is not set
++# CONFIG_TEST_STRING_HELPERS is not set
++# CONFIG_TEST_KSTRTOX is not set
++# CONFIG_TEST_RHASHTABLE is not set
++# CONFIG_DMA_API_DEBUG is not set
++# CONFIG_TEST_LKM is not set
++# CONFIG_TEST_USER_COPY is not set
++# CONFIG_TEST_BPF is not set
++# CONFIG_TEST_FIRMWARE is not set
++# CONFIG_TEST_UDELAY is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_KGDB is not set
++# CONFIG_ARM_PTDUMP is not set
++CONFIG_STRICT_DEVMEM=y
++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_DEBUG_UART_PL01X is not set
++# CONFIG_DEBUG_UART_8250 is not set
++# CONFIG_DEBUG_UART_BCM63XX is not set
++CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"
++# CONFIG_OC_ETM is not set
++# CONFIG_PID_IN_CONTEXTIDR is not set
++# CONFIG_DEBUG_SET_MODULE_RONX is not set
++# CONFIG_CORESIGHT is not set
++
++#
++# 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_AEAD=y
++CONFIG_CRYPTO_AEAD2=y
++CONFIG_CRYPTO_BLKCIPHER=y
++CONFIG_CRYPTO_BLKCIPHER2=y
++CONFIG_CRYPTO_HASH=y
++CONFIG_CRYPTO_HASH2=y
++CONFIG_CRYPTO_RNG=y
++CONFIG_CRYPTO_RNG2=y
++CONFIG_CRYPTO_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_WORKQUEUE=y
++# CONFIG_CRYPTO_CRYPTD is not set
++# CONFIG_CRYPTO_MCRYPTD is not set
++# CONFIG_CRYPTO_AUTHENC is not set
++# CONFIG_CRYPTO_TEST is not set
++
++#
++# Authenticated Encryption with Associated Data
++#
++CONFIG_CRYPTO_CCM=y
++# CONFIG_CRYPTO_GCM is not set
++CONFIG_CRYPTO_SEQIV=y
++
++#
++# Block modes
++#
++# CONFIG_CRYPTO_CBC is not set
++CONFIG_CRYPTO_CTR=y
++# 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_CMAC is not set
++# CONFIG_CRYPTO_HMAC is not set
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_VMAC is not set
++
++#
++# Digest
++#
++CONFIG_CRYPTO_CRC32C=y
++# CONFIG_CRYPTO_CRC32 is not set
++# CONFIG_CRYPTO_CRCT10DIF 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_SHA1_ARM_NEON is not set
++# CONFIG_CRYPTO_SHA256 is not set
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_SHA512_ARM_NEON 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_AES_ARM_BS is not set
++# CONFIG_CRYPTO_ANUBIS is not set
++CONFIG_CRYPTO_ARC4=y
++# 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=y
++# CONFIG_CRYPTO_ZLIB is not set
++CONFIG_CRYPTO_LZO=y
++# CONFIG_CRYPTO_LZ4 is not set
++# CONFIG_CRYPTO_LZ4HC is not set
++
++#
++# Random Number Generation
++#
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++# CONFIG_CRYPTO_DRBG_MENU is not set
++# CONFIG_CRYPTO_USER_API_HASH is not set
++# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
++CONFIG_CRYPTO_HW=y
++# CONFIG_BINARY_PRINTF is not set
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++CONFIG_GENERIC_STRNCPY_FROM_USER=y
++CONFIG_GENERIC_STRNLEN_USER=y
++CONFIG_GENERIC_NET_UTILS=y
++CONFIG_GENERIC_PCI_IOMAP=y
++CONFIG_GENERIC_IO=y
++CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
++# CONFIG_CRC_CCITT is not set
++CONFIG_CRC16=y
++# CONFIG_CRC_T10DIF is not set
++# 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=y
++# CONFIG_CRC8 is not set
++# CONFIG_AUDIT_ARCH_COMPAT_GENERIC is not set
++# CONFIG_RANDOM32_SELFTEST is not set
++CONFIG_ZLIB_INFLATE=y
++CONFIG_ZLIB_DEFLATE=y
++CONFIG_LZO_COMPRESS=y
++CONFIG_LZO_DECOMPRESS=y
++CONFIG_XZ_DEC=y
++CONFIG_XZ_DEC_X86=y
++CONFIG_XZ_DEC_POWERPC=y
++CONFIG_XZ_DEC_IA64=y
++CONFIG_XZ_DEC_ARM=y
++CONFIG_XZ_DEC_ARMTHUMB=y
++CONFIG_XZ_DEC_SPARC=y
++CONFIG_XZ_DEC_BCJ=y
++# CONFIG_XZ_DEC_TEST is not set
++CONFIG_GENERIC_ALLOCATOR=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT_MAP=y
++CONFIG_HAS_DMA=y
++CONFIG_DQL=y
++CONFIG_NLATTR=y
++CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
++CONFIG_AVERAGE=y
++# CONFIG_CORDIC is not set
++# CONFIG_DDR is not set
++CONFIG_LIBFDT=y
++CONFIG_ARCH_HAS_SG_CHAIN=y
++# CONFIG_VIRTUALIZATION is not set
+diff --git a/arch/arm/configs/hi3559_single_spinor_mini_defconfig b/arch/arm/configs/hi3559_single_spinor_mini_defconfig
+new file mode 100644
+index 0000000..5d582ae
+--- /dev/null
++++ b/arch/arm/configs/hi3559_single_spinor_mini_defconfig
+@@ -0,0 +1,2399 @@
++#
++# Automatically generated file; DO NOT EDIT.
++# Linux/arm 3.18.20 Kernel Configuration
++#
++CONFIG_ARM=y
++CONFIG_ARM_HAS_SG_CHAIN=y
++CONFIG_MIGHT_HAVE_PCI=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=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_XCHGADD_ALGORITHM=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_NEED_DMA_MAP_STATE=y
++CONFIG_ARCH_SUPPORTS_UPROBES=y
++CONFIG_VECTORS_BASE=0xffff0000
++CONFIG_ARM_PATCH_PHYS_VIRT=y
++CONFIG_GENERIC_BUG=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++CONFIG_IRQ_WORK=y
++CONFIG_BUILDTIME_EXTABLE_SORT=y
++
++#
++# General setup
++#
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_CROSS_COMPILE=""
++# CONFIG_COMPILE_TEST is not set
++CONFIG_LOCALVERSION=""
++# CONFIG_LOCALVERSION_AUTO is not set
++CONFIG_HAVE_KERNEL_GZIP=y
++CONFIG_HAVE_KERNEL_LZMA=y
++CONFIG_HAVE_KERNEL_XZ=y
++CONFIG_HAVE_KERNEL_LZO=y
++CONFIG_HAVE_KERNEL_LZ4=y
++CONFIG_KERNEL_GZIP=y
++# CONFIG_KERNEL_LZMA is not set
++# CONFIG_KERNEL_XZ is not set
++# CONFIG_KERNEL_LZO is not set
++# CONFIG_KERNEL_LZ4 is not set
++CONFIG_HW_DECOMPRESS=y
++# CONFIG_SOFT_DECOMPRESS is not set
++CONFIG_DEFAULT_HOSTNAME="(none)"
++# CONFIG_SWAP is not set
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++# CONFIG_POSIX_MQUEUE is not set
++CONFIG_CROSS_MEMORY_ATTACH=y
++# CONFIG_FHANDLE is not set
++CONFIG_USELIB=y
++# CONFIG_AUDIT is not set
++CONFIG_HAVE_ARCH_AUDITSYSCALL=y
++
++#
++# IRQ subsystem
++#
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_GENERIC_IRQ_SHOW=y
++CONFIG_HARDIRQS_SW_RESEND=y
++CONFIG_IRQ_DOMAIN=y
++CONFIG_HANDLE_DOMAIN_IRQ=y
++CONFIG_IRQ_FORCED_THREADING=y
++CONFIG_SPARSE_IRQ=y
++CONFIG_GENERIC_CLOCKEVENTS=y
++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
++
++#
++# Timers subsystem
++#
++CONFIG_TICK_ONESHOT=y
++CONFIG_NO_HZ_COMMON=y
++# CONFIG_HZ_PERIODIC is not set
++CONFIG_NO_HZ_IDLE=y
++CONFIG_NO_HZ=y
++# CONFIG_HIGH_RES_TIMERS is not set
++
++#
++# CPU/Task time and stats accounting
++#
++CONFIG_TICK_CPU_ACCOUNTING=y
++# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set
++# CONFIG_IRQ_TIME_ACCOUNTING is not set
++# CONFIG_BSD_PROCESS_ACCT is not set
++# CONFIG_TASKSTATS is not set
++
++#
++# RCU Subsystem
++#
++CONFIG_TINY_RCU=y
++# CONFIG_PREEMPT_RCU is not set
++# CONFIG_TASKS_RCU is not set
++# CONFIG_RCU_STALL_COMMON is not set
++# CONFIG_TREE_RCU_TRACE is not set
++# CONFIG_BUILD_BIN2C is not set
++# CONFIG_IKCONFIG is not set
++CONFIG_LOG_BUF_SHIFT=17
++CONFIG_GENERIC_SCHED_CLOCK=y
++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_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 is not set
++# CONFIG_SCHED_AUTOGROUP is not set
++# CONFIG_SYSFS_DEPRECATED is not set
++# CONFIG_RELAY is not set
++# CONFIG_BLK_DEV_INITRD is not set
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++CONFIG_HAVE_UID16=y
++CONFIG_BPF=y
++CONFIG_EXPERT=y
++# CONFIG_UID16 is not set
++# CONFIG_SGETMASK_SYSCALL is not set
++CONFIG_SYSFS_SYSCALL=y
++# CONFIG_SYSCTL_SYSCALL is not set
++CONFIG_KALLSYMS=y
++# CONFIG_KALLSYMS_ALL is not set
++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_BPF_SYSCALL is not set
++CONFIG_SHMEM=y
++CONFIG_AIO=y
++CONFIG_ADVISE_SYSCALLS=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 is not set
++# CONFIG_SLUB_DEBUG is not set
++# CONFIG_COMPAT_BRK is not set
++# 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_UPROBES is not set
++# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
++CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
++CONFIG_ARCH_USE_BUILTIN_BSWAP=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_GENERIC_SMP_IDLE_THREAD=y
++CONFIG_GENERIC_IDLE_POLL_SETUP=y
++CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
++CONFIG_HAVE_CLK=y
++CONFIG_HAVE_DMA_API_DEBUG=y
++CONFIG_HAVE_PERF_REGS=y
++CONFIG_HAVE_PERF_USER_STACK_DUMP=y
++CONFIG_HAVE_ARCH_JUMP_LABEL=y
++CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
++CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
++CONFIG_HAVE_CC_STACKPROTECTOR=y
++# CONFIG_CC_STACKPROTECTOR is not set
++CONFIG_CC_STACKPROTECTOR_NONE=y
++# CONFIG_CC_STACKPROTECTOR_REGULAR is not set
++# CONFIG_CC_STACKPROTECTOR_STRONG is not set
++CONFIG_HAVE_CONTEXT_TRACKING=y
++CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
++CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
++CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
++CONFIG_MODULES_USE_ELF_REL=y
++CONFIG_CLONE_BACKWARDS=y
++CONFIG_OLD_SIGSUSPEND3=y
++CONFIG_OLD_SIGACTION=y
++
++#
++# GCOV-based kernel profiling
++#
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_RT_MUTEXES=y
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++# CONFIG_MODULE_FORCE_LOAD is not set
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++# CONFIG_MODULE_SIG is not set
++# CONFIG_MODULE_COMPRESS is not set
++CONFIG_BLOCK=y
++CONFIG_LBDAF=y
++CONFIG_BLK_DEV_BSG=y
++# CONFIG_BLK_DEV_BSGLIB is not set
++# CONFIG_BLK_DEV_INTEGRITY is not set
++CONFIG_BLK_CMDLINE_PARSER=y
++
++#
++# Partition Types
++#
++CONFIG_PARTITION_ADVANCED=y
++# CONFIG_ACORN_PARTITION is not set
++# CONFIG_AIX_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=y
++# CONFIG_SYSV68_PARTITION is not set
++CONFIG_CMDLINE_PARTITION=y
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++CONFIG_DEFAULT_DEADLINE=y
++# CONFIG_DEFAULT_CFQ is not set
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="deadline"
++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_ARCH_SUPPORTS_ATOMIC_RMW=y
++CONFIG_FREEZER=y
++
++#
++# System Type
++#
++CONFIG_MMU=y
++CONFIG_ARCH_MULTIPLATFORM=y
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_AT91 is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_GEMINI is not set
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_IOP13XX is not set
++# CONFIG_ARCH_IOP32X is not set
++# CONFIG_ARCH_IOP33X is not set
++# CONFIG_ARCH_IXP4XX is not set
++# CONFIG_ARCH_DOVE is not set
++# CONFIG_ARCH_MV78XX0 is not set
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_MMP is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_W90X900 is not set
++# CONFIG_ARCH_LPC32XX is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_MSM is not set
++# CONFIG_ARCH_SHMOBILE_LEGACY 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_DAVINCI is not set
++# CONFIG_ARCH_OMAP1 is not set
++
++#
++# Multiple platform selection
++#
++
++#
++# CPU Core family selection
++#
++# CONFIG_ARCH_MULTI_V6 is not set
++CONFIG_ARCH_MULTI_V7=y
++CONFIG_ARCH_MULTI_V6_V7=y
++# CONFIG_ARCH_MULTI_CPU_AUTO is not set
++# CONFIG_ARCH_VIRT is not set
++# CONFIG_ARCH_MVEBU is not set
++# CONFIG_ARCH_BCM is not set
++# CONFIG_ARCH_BERLIN is not set
++# CONFIG_ARCH_HIGHBANK is not set
++CONFIG_ARCH_HISI=y
++
++#
++# Hisilicon platform type
++#
++# CONFIG_ARCH_HI3xxx is not set
++# CONFIG_ARCH_HIP04 is not set
++# CONFIG_ARCH_HIX5HD2 is not set
++# CONFIG_ARCH_HI3519 is not set
++# CONFIG_ARCH_HI3519V101 is not set
++# CONFIG_ARCH_HI3516AV200 is not set
++CONFIG_ARCH_HI3559=y
++# CONFIG_ARCH_HI3556 is not set
++# CONFIG_ARCH_HI3536C is not set
++# CONFIG_ARCH_HI3531D is not set
++# CONFIG_ARCH_HI3521D is not set
++# CONFIG_ARCH_KEYSTONE is not set
++# CONFIG_ARCH_MESON is not set
++# CONFIG_ARCH_MXC is not set
++# CONFIG_ARCH_MEDIATEK is not set
++
++#
++# TI OMAP/AM/DM/DRA Family
++#
++# CONFIG_ARCH_OMAP3 is not set
++# CONFIG_ARCH_OMAP4 is not set
++# CONFIG_SOC_OMAP5 is not set
++# CONFIG_SOC_AM33XX is not set
++# CONFIG_SOC_AM43XX is not set
++# CONFIG_SOC_DRA7XX is not set
++# CONFIG_ARCH_QCOM is not set
++# CONFIG_ARCH_ROCKCHIP is not set
++# CONFIG_ARCH_SOCFPGA is not set
++# CONFIG_PLAT_SPEAR is not set
++# CONFIG_ARCH_STI is not set
++# CONFIG_ARCH_S5PV210 is not set
++# CONFIG_ARCH_EXYNOS is not set
++# CONFIG_ARCH_SHMOBILE_MULTI is not set
++# CONFIG_ARCH_SUNXI is not set
++# CONFIG_ARCH_SIRF is not set
++# CONFIG_ARCH_TEGRA is not set
++# CONFIG_ARCH_U8500 is not set
++# CONFIG_ARCH_VEXPRESS is not set
++# CONFIG_ARCH_WM8850 is not set
++# CONFIG_ARCH_ZYNQ is not set
++CONFIG_ARM_TIMER_SP804=y
++
++#
++# Processor Type
++#
++CONFIG_CPU_V7=y
++CONFIG_CPU_32v6K=y
++CONFIG_CPU_32v7=y
++CONFIG_CPU_ABRT_EV7=y
++CONFIG_CPU_PABRT_V7=y
++CONFIG_CPU_CACHE_V7=y
++CONFIG_CPU_CACHE_VIPT=y
++CONFIG_CPU_COPY_V6=y
++CONFIG_CPU_TLB_V7=y
++CONFIG_CPU_HAS_ASID=y
++CONFIG_CPU_CP15=y
++CONFIG_CPU_CP15_MMU=y
++
++#
++# Processor Features
++#
++# CONFIG_ARM_LPAE is not set
++# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
++CONFIG_ARM_THUMB=y
++# CONFIG_ARM_THUMBEE is not set
++CONFIG_ARM_VIRT_EXT=y
++CONFIG_SWP_EMULATE=y
++# CONFIG_CPU_ICACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_DISABLE is not set
++# CONFIG_CPU_BPREDICT_DISABLE is not set
++CONFIG_KUSER_HELPERS=y
++CONFIG_MIGHT_HAVE_CACHE_L2X0=y
++# CONFIG_CACHE_L2X0 is not set
++CONFIG_ARM_L1_CACHE_SHIFT_6=y
++CONFIG_ARM_L1_CACHE_SHIFT=6
++CONFIG_ARM_DMA_MEM_BUFFERABLE=y
++CONFIG_MULTI_IRQ_HANDLER=y
++# CONFIG_ARM_ERRATA_430973 is not set
++# CONFIG_ARM_ERRATA_720789 is not set
++# CONFIG_ARM_ERRATA_754322 is not set
++# CONFIG_ARM_ERRATA_775420 is not set
++# CONFIG_ARM_ERRATA_773022 is not set
++
++#
++# Bus support
++#
++CONFIG_ARM_AMBA=y
++# CONFIG_PCI is not set
++# CONFIG_PCI_SYSCALL is not set
++# CONFIG_PCCARD is not set
++
++#
++# Kernel Features
++#
++CONFIG_HAVE_SMP=y
++# CONFIG_SMP is not set
++CONFIG_DISABLE_CPU_SCHED_DOMAIN_BALANCE=y
++CONFIG_HAVE_ARM_ARCH_TIMER=y
++CONFIG_VMSPLIT_3G=y
++# CONFIG_VMSPLIT_2G is not set
++# CONFIG_VMSPLIT_1G is not set
++CONFIG_PAGE_OFFSET=0xC0000000
++# CONFIG_ARM_PSCI is not set
++CONFIG_ARCH_NR_GPIO=0
++CONFIG_PREEMPT_NONE=y
++# CONFIG_PREEMPT_VOLUNTARY is not set
++# CONFIG_PREEMPT is not set
++CONFIG_HZ_FIXED=0
++# CONFIG_HZ_100 is not set
++# CONFIG_HZ_200 is not set
++# CONFIG_HZ_250 is not set
++# CONFIG_HZ_300 is not set
++# CONFIG_HZ_500 is not set
++CONFIG_HZ_1000=y
++CONFIG_HZ=1000
++# CONFIG_SCHED_HRTICK is not set
++# CONFIG_THUMB2_KERNEL is not set
++CONFIG_AEABI=y
++# CONFIG_OABI_COMPAT is not set
++# 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_ARCH_WANT_GENERAL_HUGETLB=y
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_HAVE_MEMBLOCK=y
++CONFIG_NO_BOOTMEM=y
++CONFIG_MEMORY_ISOLATION=y
++# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=4
++CONFIG_COMPACTION=y
++CONFIG_MIGRATION=y
++# CONFIG_PHYS_ADDR_T_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_BOUNCE=y
++# CONFIG_KSM is not set
++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
++CONFIG_NEED_PER_CPU_KM=y
++# CONFIG_CLEANCACHE is not set
++CONFIG_CMA=y
++# CONFIG_CMA_DEBUG is not set
++CONFIG_CMA_AREAS=7
++# CONFIG_ZPOOL is not set
++# CONFIG_ZBUD is not set
++# CONFIG_ZSMALLOC 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_SWIOTLB=y
++CONFIG_IOMMU_HELPER=y
++# CONFIG_XEN is not set
++# CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART is not set
++
++#
++# Boot options
++#
++CONFIG_USE_OF=y
++CONFIG_ATAGS=y
++# CONFIG_DEPRECATED_PARAM_STRUCT is not set
++# CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE is not set
++CONFIG_ZBOOT_ROM_TEXT=0
++CONFIG_ZBOOT_ROM_BSS=0
++CONFIG_ARM_APPENDED_DTB=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_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_GOV_COMMON=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 is not set
++CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
++# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE is not set
++CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
++CONFIG_CPU_FREQ_GOV_POWERSAVE=y
++CONFIG_CPU_FREQ_GOV_USERSPACE=y
++CONFIG_CPU_FREQ_GOV_ONDEMAND=y
++CONFIG_CPU_FREQ_GOV_INTERACTIVE=y
++# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
++# CONFIG_CPUFREQ_DT is not set
++
++#
++# ARM CPU frequency scaling drivers
++#
++# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set
++
++#
++# CPU Idle
++#
++# CONFIG_CPU_IDLE is not set
++# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++CONFIG_VFP=y
++CONFIG_VFPv3=y
++CONFIG_NEON=y
++CONFIG_KERNEL_MODE_NEON=y
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
++CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
++CONFIG_BINFMT_SCRIPT=y
++# CONFIG_HAVE_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
++CONFIG_COREDUMP=y
++
++#
++# Power management options
++#
++CONFIG_SUSPEND=y
++CONFIG_SUSPEND_FREEZER=y
++# CONFIG_WAKELOCK is not set
++# CONFIG_HISI_SNAPSHOT_BOOT is not set
++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_OPP=y
++CONFIG_PM_CLK=y
++# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set
++CONFIG_CPU_PM=y
++# CONFIG_SUSPEND_TIME is not set
++CONFIG_ARCH_SUSPEND_POSSIBLE=y
++CONFIG_ARM_CPU_SUSPEND=y
++CONFIG_ARCH_HIBERNATION_POSSIBLE=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_NET_IP_TUNNEL is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_NET_IPVTI is not set
++# CONFIG_NET_UDP_TUNNEL is not set
++# CONFIG_NET_FOU is not set
++# CONFIG_GENEVE 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 is not set
++CONFIG_INET_XFRM_MODE_TRANSPORT=y
++CONFIG_INET_XFRM_MODE_TUNNEL=y
++CONFIG_INET_XFRM_MODE_BEET=y
++CONFIG_INET_LRO=y
++CONFIG_INET_DIAG=y
++CONFIG_INET_TCP_DIAG=y
++# CONFIG_INET_UDP_DIAG is not set
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++# CONFIG_TCP_MD5SIG is not set
++# CONFIG_IPV6 is not set
++# CONFIG_ANDROID_PARANOID_NETWORK is not set
++CONFIG_NET_ACTIVITY_STATS=y
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NET_PTP_CLASSIFY 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_NF_TABLES is not set
++# CONFIG_NETFILTER_XTABLES is not set
++# CONFIG_IP_SET is not set
++# CONFIG_IP_VS is not set
++
++#
++# IP: Netfilter Configuration
++#
++# CONFIG_NF_DEFRAG_IPV4 is not set
++# CONFIG_NF_LOG_ARP is not set
++# CONFIG_NF_LOG_IPV4 is not set
++# CONFIG_NF_REJECT_IPV4 is not set
++# CONFIG_IP_NF_IPTABLES is not set
++# CONFIG_IP_NF_ARPTABLES 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_HAVE_NET_DSA=y
++# 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_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_VSOCKETS is not set
++# CONFIG_NETLINK_MMAP is not set
++# CONFIG_NETLINK_DIAG is not set
++# CONFIG_NET_MPLS_GSO is not set
++# CONFIG_HSR is not set
++# CONFIG_CGROUP_NET_PRIO is not set
++# CONFIG_CGROUP_NET_CLASSID is not set
++CONFIG_NET_RX_BUSY_POLL=y
++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 is not set
++CONFIG_DEVTMPFS=y
++CONFIG_DEVTMPFS_MOUNT=y
++CONFIG_STANDALONE=y
++# CONFIG_PREVENT_FIRMWARE_BUILD is not set
++CONFIG_FW_LOADER=y
++# CONFIG_FIRMWARE_IN_KERNEL is not set
++CONFIG_EXTRA_FIRMWARE=""
++# CONFIG_FW_LOADER_USER_HELPER_FALLBACK is not set
++CONFIG_ALLOW_DEV_COREDUMP=y
++# 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_HAVE_CPU_AUTOPROBE is not set
++CONFIG_REGMAP=y
++CONFIG_REGMAP_MMIO=y
++CONFIG_DMA_SHARED_BUFFER=y
++# CONFIG_FENCE_TRACE is not set
++CONFIG_DMA_CMA=y
++
++#
++# Default contiguous memory area size:
++#
++CONFIG_CMA_SIZE_MBYTES=16
++CONFIG_CMA_SIZE_SEL_MBYTES=y
++# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set
++# CONFIG_CMA_SIZE_SEL_MIN is not set
++# CONFIG_CMA_SIZE_SEL_MAX is not set
++CONFIG_CMA_ALIGNMENT=8
++
++#
++# Bus devices
++#
++# CONFIG_BRCMSTB_GISB_ARB is not set
++CONFIG_ARM_CCI=y
++# CONFIG_VEXPRESS_CONFIG 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=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_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_HIFMC is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++# CONFIG_MTD_CFI is not set
++# CONFIG_MTD_JEDECPROBE is not set
++CONFIG_MTD_MAP_BANK_WIDTH_1=y
++CONFIG_MTD_MAP_BANK_WIDTH_2=y
++CONFIG_MTD_MAP_BANK_WIDTH_4=y
++# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
++CONFIG_MTD_CFI_I1=y
++CONFIG_MTD_CFI_I2=y
++# CONFIG_MTD_CFI_I4 is not set
++# CONFIG_MTD_CFI_I8 is not set
++# CONFIG_MTD_RAM is not set
++# CONFIG_MTD_ROM is not set
++# CONFIG_MTD_ABSENT is not set
++
++#
++# Mapping drivers for chip access
++#
++# CONFIG_MTD_COMPLEX_MAPPINGS is not set
++# CONFIG_MTD_PLATRAM is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_DATAFLASH is not set
++# CONFIG_MTD_M25P80 is not set
++# CONFIG_MTD_SST25L is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_PHRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++# CONFIG_MTD_BLOCK2MTD is not set
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOCG3 is not set
++# CONFIG_MTD_NAND_IDS is not set
++# CONFIG_MTD_NAND is not set
++# CONFIG_MTD_ONENAND is not set
++
++#
++# LPDDR & LPDDR2 PCM memory drivers
++#
++# CONFIG_MTD_LPDDR is not set
++# CONFIG_MTD_LPDDR2_NVM is not set
++CONFIG_MTD_SPI_NOR=y
++# CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set
++CONFIG_SPI_HISI_SFC=y
++CONFIG_CLOSE_SPI_8PIN_4IO=y
++CONFIG_HISI_SPI_BLOCK_PROTECT=y
++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_MTD_UBI_BLOCK is not set
++CONFIG_DTC=y
++CONFIG_OF=y
++
++#
++# Device Tree and Open Firmware support
++#
++# 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_NET=y
++CONFIG_OF_MDIO=y
++CONFIG_OF_MTD=y
++CONFIG_OF_RESERVED_MEM=y
++CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
++# CONFIG_PARPORT is not set
++CONFIG_BLK_DEV=y
++# CONFIG_BLK_DEV_NULL_BLK is not set
++# CONFIG_BLK_DEV_COW_COMMON is not set
++# CONFIG_BLK_DEV_LOOP 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=65536
++# CONFIG_BLK_DEV_XIP is not set
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH 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_DUMMY_IRQ 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_UID_STAT is not set
++# CONFIG_BMP085_I2C is not set
++# CONFIG_BMP085_SPI is not set
++# CONFIG_USB_SWITCH_FSA9480 is not set
++# CONFIG_LATTICE_ECP3_CONFIG is not set
++# CONFIG_SRAM is not set
++# CONFIG_C2PORT is not set
++
++#
++# EEPROM support
++#
++# CONFIG_EEPROM_AT24 is not set
++# CONFIG_EEPROM_AT25 is not set
++# CONFIG_EEPROM_LEGACY is not set
++# CONFIG_EEPROM_MAX6875 is not set
++# CONFIG_EEPROM_93CX6 is not set
++# CONFIG_EEPROM_93XX46 is not set
++
++#
++# Texas Instruments shared transport line discipline
++#
++# 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
++
++#
++# Intel MIC Bus Driver
++#
++
++#
++# Intel MIC Host Driver
++#
++
++#
++# Intel MIC Card Driver
++#
++# CONFIG_ECHO is not set
++# CONFIG_CXL_BASE is not set
++
++#
++# hisi 'himm/himd.l/himc'support
++#
++# CONFIG_HISI_REG 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_NETLINK is not set
++# CONFIG_SCSI_MQ_DEFAULT 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_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 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_NET_CORE=y
++# CONFIG_BONDING is not set
++# CONFIG_DUMMY is not set
++# CONFIG_EQUALIZER is not set
++# CONFIG_NET_TEAM is not set
++# CONFIG_MACVLAN is not set
++# CONFIG_VXLAN is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_TUN is not set
++# CONFIG_VETH is not set
++# CONFIG_NLMON is not set
++
++#
++# 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_NET_DSA_MV88E6171 is not set
++# CONFIG_NET_DSA_BCM_SF2 is not set
++# CONFIG_ETHERNET is not set
++CONFIG_PHYLIB=y
++
++#
++# MII PHY device drivers
++#
++# CONFIG_AT803X_PHY is not set
++# CONFIG_AMD_PHY is not set
++# CONFIG_AMD_XGBE_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 is not set
++# CONFIG_BROADCOM_PHY is not set
++# CONFIG_BCM7XXX_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_MMIOREG is not set
++# CONFIG_MDIO_BCM_UNIMAC is not set
++# CONFIG_MDIO_HISI_FEMAC is not set
++# CONFIG_MDIO_HISI_GEMAC is not set
++# CONFIG_MICREL_KS8995MA is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++
++#
++# Host-side USB support is needed for USB Network Adapter support
++#
++CONFIG_USB_NET_DRIVERS=m
++# 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_RTL8152 is not set
++# CONFIG_USB_USBNET is not set
++# CONFIG_USB_IPHETH is not set
++CONFIG_WLAN=y
++# CONFIG_WIFI_CONTROL_FUNC is not set
++# 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 is not set
++# CONFIG_INPUT_SPARSEKMAP is not set
++# CONFIG_INPUT_MATRIXKMAP is not set
++
++#
++# Userland interfaces
++#
++# CONFIG_INPUT_MOUSEDEV is not set
++# CONFIG_INPUT_JOYDEV is not set
++CONFIG_INPUT_EVDEV=y
++# CONFIG_INPUT_EVBUG is not set
++# CONFIG_INPUT_KEYRESET is not set
++# CONFIG_INPUT_KEYCOMBO is not set
++
++#
++# Input Device Drivers
++#
++# CONFIG_INPUT_KEYBOARD is not set
++# CONFIG_INPUT_MOUSE is not set
++# CONFIG_INPUT_JOYSTICK is not set
++# CONFIG_INPUT_TABLET is not set
++# CONFIG_INPUT_TOUCHSCREEN is not set
++# CONFIG_INPUT_MISC is not set
++
++#
++# Hardware I/O ports
++#
++# CONFIG_SERIO is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++CONFIG_TTY=y
++CONFIG_VT=y
++CONFIG_CONSOLE_TRANSLATIONS=y
++CONFIG_VT_CONSOLE=y
++CONFIG_VT_CONSOLE_SLEEP=y
++CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
++CONFIG_UNIX98_PTYS=y
++# CONFIG_DEVPTS_MULTIPLE_INSTANCES 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_DEVMEM=y
++CONFIG_DEVKMEM=y
++
++#
++# Serial drivers
++#
++CONFIG_SERIAL_EARLYCON=y
++# CONFIG_SERIAL_8250 is not set
++
++#
++# Non-8250 serial port support
++#
++# CONFIG_SERIAL_AMBA_PL010 is not set
++CONFIG_SERIAL_AMBA_PL011=y
++CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
++# CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST is not set
++# 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_SC16IS7XX is not set
++# CONFIG_SERIAL_ALTERA_JTAGUART is not set
++# CONFIG_SERIAL_ALTERA_UART is not set
++# CONFIG_SERIAL_XILINX_PS_UART is not set
++# CONFIG_SERIAL_ARC is not set
++# CONFIG_SERIAL_FSL_LPUART is not set
++# CONFIG_SERIAL_ST_ASC is not set
++# CONFIG_TTY_PRINTK is not set
++# CONFIG_HVC_DCC is not set
++# CONFIG_IPMI_HANDLER is not set
++CONFIG_HW_RANDOM=y
++# CONFIG_HW_RANDOM_TIMERIOMEM is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++# CONFIG_DCC_TTY is not set
++# CONFIG_XILLYBUS is not set
++
++#
++# I2C support
++#
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++# CONFIG_I2C_COMPAT is not set
++CONFIG_I2C_CHARDEV=y
++CONFIG_I2C_MUX=m
++
++#
++# Multiplexer I2C Chip support
++#
++# CONFIG_I2C_MUX_PCA9541 is not set
++# CONFIG_I2C_HELPER_AUTO is not set
++# CONFIG_I2C_SMBUS is not set
++
++#
++# I2C Algorithms
++#
++# CONFIG_I2C_ALGOBIT is not set
++# CONFIG_I2C_ALGOPCF is not set
++# CONFIG_I2C_ALGOPCA is not set
++
++#
++# I2C Hardware Bus support
++#
++
++#
++# I2C system bus drivers (mostly embedded / system-on-chip)
++#
++# CONFIG_I2C_DESIGNWARE_PLATFORM is not set
++# CONFIG_I2C_HIBVT is not set
++CONFIG_I2C_HISI_V110=y
++# CONFIG_I2C_NOMADIK 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_RK3X 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_ROBOTFUZZ_OSIF 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_CADENCE is not set
++# CONFIG_SPI_FSL_SPI is not set
++CONFIG_SPI_PL022=y
++# CONFIG_SPI_PXA2XX_PCI is not set
++# CONFIG_SPI_ROCKCHIP 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=y
++# CONFIG_SPI_TLE62X0 is not set
++# CONFIG_SPMI is not set
++# CONFIG_HSI is not set
++
++#
++# PPS support
++#
++# CONFIG_PPS is not set
++
++#
++# PPS generators support
++#
++
++#
++# PTP clock support
++#
++# CONFIG_PTP_1588_CLOCK is not set
++
++#
++# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
++#
++CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
++CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
++# CONFIG_GPIOLIB is not set
++# CONFIG_W1 is not set
++CONFIG_POWER_SUPPLY=y
++# CONFIG_POWER_SUPPLY_DEBUG is not set
++# CONFIG_PDA_POWER is not set
++# CONFIG_TEST_POWER is not set
++# CONFIG_BATTERY_DS2780 is not set
++# CONFIG_BATTERY_DS2781 is not set
++# CONFIG_BATTERY_DS2782 is not set
++# CONFIG_BATTERY_SBS is not set
++# CONFIG_BATTERY_BQ27x00 is not set
++# CONFIG_BATTERY_MAX17040 is not set
++# CONFIG_BATTERY_MAX17042 is not set
++# CONFIG_CHARGER_MAX8903 is not set
++# CONFIG_CHARGER_LP8727 is not set
++# CONFIG_CHARGER_BQ2415X is not set
++# CONFIG_CHARGER_SMB347 is not set
++CONFIG_POWER_RESET=y
++# CONFIG_POWER_RESET_BRCMSTB is not set
++CONFIG_POWER_RESET_HISI=y
++# CONFIG_POWER_RESET_RESTART is not set
++# CONFIG_POWER_RESET_VERSATILE is not set
++# CONFIG_POWER_RESET_SYSCON is not set
++# CONFIG_POWER_AVS is not set
++# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
++# CONFIG_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=y
++# CONFIG_MFD_AS3711 is not set
++# CONFIG_MFD_AS3722 is not set
++# CONFIG_PMIC_ADP5520 is not set
++# CONFIG_MFD_BCM590XX is not set
++# CONFIG_MFD_AXP20X is not set
++# CONFIG_MFD_CROS_EC is not set
++# CONFIG_PMIC_DA903X is not set
++# CONFIG_MFD_DA9052_SPI is not set
++# CONFIG_MFD_DA9052_I2C is not set
++# CONFIG_MFD_DA9055 is not set
++# CONFIG_MFD_DA9063 is not set
++# CONFIG_MFD_MC13XXX_SPI is not set
++# CONFIG_MFD_MC13XXX_I2C is not set
++# CONFIG_MFD_HI6421_PMIC is not set
++CONFIG_MFD_HISI_FMC=y
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_INTEL_SOC_PMIC is not set
++# CONFIG_MFD_KEMPLD is not set
++# CONFIG_MFD_88PM800 is not set
++# CONFIG_MFD_88PM805 is not set
++# CONFIG_MFD_88PM860X is not set
++# CONFIG_MFD_MAX14577 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_MENF21BMC is not set
++# CONFIG_EZX_PCAP is not set
++# CONFIG_MFD_VIPERBOARD is not set
++# CONFIG_MFD_RETU is not set
++# CONFIG_MFD_PCF50633 is not set
++# CONFIG_MFD_PM8921_CORE is not set
++# CONFIG_MFD_RTSX_USB is not set
++# CONFIG_MFD_RC5T583 is not set
++# CONFIG_MFD_RK808 is not set
++# CONFIG_MFD_RN5T618 is not set
++# CONFIG_MFD_SEC_CORE is not set
++# CONFIG_MFD_SI476X_CORE is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_MFD_SMSC is not set
++# CONFIG_ABX500_CORE is not set
++# CONFIG_MFD_STMPE is not set
++CONFIG_MFD_SYSCON=y
++# CONFIG_MFD_TI_AM335X_TSCADC is not set
++# CONFIG_MFD_LP3943 is not set
++# CONFIG_MFD_LP8788 is not set
++# CONFIG_MFD_PALMAS is not set
++# CONFIG_TPS6105X is not set
++# CONFIG_TPS6507X is not set
++# CONFIG_MFD_TPS65090 is not set
++# CONFIG_MFD_TPS65217 is not set
++# CONFIG_MFD_TPS65218 is not set
++# CONFIG_MFD_TPS6586X is not set
++# CONFIG_MFD_TPS80031 is not set
++# CONFIG_TWL4030_CORE is not set
++# CONFIG_TWL6040_CORE is not set
++# CONFIG_MFD_WL1273_CORE is not set
++# CONFIG_MFD_LM3533 is not set
++# CONFIG_MFD_TC3589X is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_MFD_T7L66XB is not set
++# CONFIG_MFD_TC6387XB is not set
++# CONFIG_MFD_TC6393XB is not set
++# CONFIG_MFD_ARIZONA_I2C is not set
++# CONFIG_MFD_ARIZONA_SPI is not set
++# CONFIG_MFD_WM8400 is not set
++# CONFIG_MFD_WM831X_I2C is not set
++# CONFIG_MFD_WM831X_SPI is not set
++# CONFIG_MFD_WM8350_I2C is not set
++# CONFIG_MFD_WM8994 is not set
++CONFIG_REGULATOR=y
++# CONFIG_REGULATOR_DEBUG is not set
++# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
++# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
++# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
++# CONFIG_REGULATOR_ACT8865 is not set
++# CONFIG_REGULATOR_AD5398 is not set
++# CONFIG_REGULATOR_ANATOP is not set
++# CONFIG_REGULATOR_DA9210 is not set
++# CONFIG_REGULATOR_DA9211 is not set
++# CONFIG_REGULATOR_FAN53555 is not set
++# CONFIG_REGULATOR_ISL9305 is not set
++# CONFIG_REGULATOR_ISL6271A is not set
++# CONFIG_REGULATOR_LP3971 is not set
++# CONFIG_REGULATOR_LP3972 is not set
++# CONFIG_REGULATOR_LP872X is not set
++# CONFIG_REGULATOR_LP8755 is not set
++# CONFIG_REGULATOR_LTC3589 is not set
++# CONFIG_REGULATOR_MAX1586 is not set
++# CONFIG_REGULATOR_MAX8649 is not set
++# CONFIG_REGULATOR_MAX8660 is not set
++# CONFIG_REGULATOR_MAX8952 is not set
++# CONFIG_REGULATOR_MAX8973 is not set
++# CONFIG_REGULATOR_PFUZE100 is not set
++# CONFIG_REGULATOR_TPS51632 is not set
++# CONFIG_REGULATOR_TPS62360 is not set
++# CONFIG_REGULATOR_TPS65023 is not set
++# CONFIG_REGULATOR_TPS6507X is not set
++# CONFIG_REGULATOR_TPS6524X is not set
++CONFIG_MEDIA_SUPPORT=m
++
++#
++# Multimedia core support
++#
++CONFIG_MEDIA_CAMERA_SUPPORT=y
++# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set
++# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set
++# CONFIG_MEDIA_RADIO_SUPPORT is not set
++# CONFIG_MEDIA_SDR_SUPPORT is not set
++# CONFIG_MEDIA_RC_SUPPORT is not set
++# CONFIG_MEDIA_CONTROLLER is not set
++CONFIG_VIDEO_DEV=m
++CONFIG_VIDEO_V4L2=m
++# CONFIG_VIDEO_ADV_DEBUG is not set
++# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
++CONFIG_VIDEOBUF2_CORE=m
++CONFIG_VIDEOBUF2_MEMOPS=m
++CONFIG_VIDEOBUF2_VMALLOC=m
++# CONFIG_TTPCI_EEPROM is not set
++
++#
++# Media drivers
++#
++# CONFIG_MEDIA_USB_SUPPORT is not set
++# CONFIG_V4L_PLATFORM_DRIVERS is not set
++# CONFIG_V4L_MEM2MEM_DRIVERS is not set
++# CONFIG_V4L_TEST_DRIVERS is not set
++
++#
++# Supported MMC/SDIO adapters
++#
++# CONFIG_CYPRESS_FIRMWARE is not set
++
++#
++# Media ancillary drivers (tuners, sensors, i2c, frontends)
++#
++CONFIG_MEDIA_SUBDRV_AUTOSELECT=y
++
++#
++# Audio decoders, processors and mixers
++#
++
++#
++# RDS decoders
++#
++
++#
++# Video decoders
++#
++
++#
++# Video and audio decoders
++#
++
++#
++# Video encoders
++#
++
++#
++# Camera sensor devices
++#
++
++#
++# Flash devices
++#
++
++#
++# Video improvement chips
++#
++
++#
++# Audio/Video compression chips
++#
++
++#
++# Miscellaneous helper chips
++#
++
++#
++# Sensors used on soc_camera driver
++#
++
++#
++# Tools to develop new frontends
++#
++# CONFIG_DVB_DUMMY_FE is not set
++
++#
++# Graphics support
++#
++# CONFIG_IMX_IPUV3_CORE is not set
++
++#
++# Direct Rendering Manager
++#
++# CONFIG_DRM is not set
++
++#
++# Frame buffer Devices
++#
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++CONFIG_FB_CMDLINE=y
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++# CONFIG_FB_CFB_FILLRECT is not set
++# CONFIG_FB_CFB_COPYAREA is not set
++# CONFIG_FB_CFB_IMAGEBLIT is not set
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# 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_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_ARMCLCD is not set
++# CONFIG_FB_OPENCORES is not set
++# CONFIG_FB_S1D13XXX is not set
++# CONFIG_FB_SMSCUFX is not set
++# CONFIG_FB_UDL is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_BROADSHEET is not set
++# CONFIG_FB_AUO_K190X is not set
++# CONFIG_FB_SIMPLE is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++# CONFIG_VGASTATE is not set
++
++#
++# Console display driver support
++#
++CONFIG_DUMMY_CONSOLE=y
++# CONFIG_FRAMEBUFFER_CONSOLE is not set
++# CONFIG_LOGO is not set
++# CONFIG_SOUND is not set
++
++#
++# HID support
++#
++CONFIG_HID=y
++# CONFIG_HID_BATTERY_STRENGTH is not set
++# CONFIG_HIDRAW is not set
++# CONFIG_UHID is not set
++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_APPLEIR 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_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_ELO is not set
++# CONFIG_HID_EZKEY is not set
++# CONFIG_HID_HOLTEK is not set
++# CONFIG_HID_HUION 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_ICADE is not set
++# CONFIG_HID_TWINHAN is not set
++# CONFIG_HID_KENSINGTON is not set
++# CONFIG_HID_LCPOWER is not set
++# CONFIG_HID_LENOVO is not set
++# 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_PENMOUNT is not set
++# CONFIG_HID_PETALYNX is not set
++# CONFIG_HID_PICOLCD is not set
++# CONFIG_HID_PRIMAX is not set
++# CONFIG_HID_ROCCAT is not set
++# CONFIG_HID_SAITEK is not set
++# CONFIG_HID_SAMSUNG is not set
++# CONFIG_HID_SPEEDLINK is not set
++# CONFIG_HID_STEELSERIES is not set
++# CONFIG_HID_SUNPLUS is not set
++# CONFIG_HID_RMI 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_XINMO is not set
++# CONFIG_HID_ZEROPLUS is not set
++# CONFIG_HID_ZYDACRON is not set
++# CONFIG_HID_SENSOR_HUB is not set
++
++#
++# USB HID support
++#
++CONFIG_USB_HID=m
++# CONFIG_HID_PID is not set
++# CONFIG_USB_HIDDEV is not set
++
++#
++# USB HID Boot Protocol drivers
++#
++# CONFIG_USB_KBD is not set
++# CONFIG_USB_MOUSE is not set
++
++#
++# I2C HID support
++#
++# CONFIG_I2C_HID is not set
++CONFIG_USB_OHCI_LITTLE_ENDIAN=y
++CONFIG_USB_SUPPORT=y
++CONFIG_USB_COMMON=y
++CONFIG_USB_ARCH_HAS_HCD=y
++CONFIG_USB=m
++# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
++
++#
++# Miscellaneous USB options
++#
++# CONFIG_USB_DEFAULT_PERSIST is not set
++# CONFIG_USB_DYNAMIC_MINORS is not set
++# CONFIG_USB_OTG_WHITELIST is not set
++# CONFIG_USB_OTG_BLACKLIST_HUB is not set
++# CONFIG_USB_OTG_FSM is not set
++# CONFIG_USB_MON is not set
++# CONFIG_USB_WUSB_CBAF is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_C67X00_HCD is not set
++# CONFIG_USB_XHCI_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_FUSBH200_HCD is not set
++# CONFIG_USB_FOTG210_HCD is not set
++# CONFIG_USB_MAX3421_HCD is not set
++# CONFIG_USB_OHCI_HCD is not set
++# CONFIG_USB_SL811_HCD is not set
++# CONFIG_USB_R8A66597_HCD is not set
++# CONFIG_USB_HCD_TEST_MODE is not set
++
++#
++# USB Device Class drivers
++#
++# CONFIG_USB_ACM is not set
++# CONFIG_USB_PRINTER is not set
++# CONFIG_USB_WDM is not set
++# CONFIG_USB_TMC is not set
++
++#
++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
++#
++
++#
++# also be needed; see USB_STORAGE Help for more info
++#
++# CONFIG_USB_STORAGE is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++# CONFIG_USBIP_CORE is not set
++# CONFIG_USB_MUSB_HDRC is not set
++# CONFIG_USB_DWC3 is not set
++# CONFIG_USB_DWC2 is not set
++# CONFIG_USB_CHIPIDEA is not set
++
++#
++# USB port drivers
++#
++# CONFIG_USB_SERIAL is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
++# CONFIG_USB_SEVSEG is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
++# CONFIG_USB_APPLEDISPLAY is not set
++# CONFIG_USB_LD is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
++# CONFIG_USB_IOWARRIOR is not set
++# CONFIG_USB_TEST is not set
++# CONFIG_USB_EHSET_TEST_FIXTURE is not set
++# CONFIG_USB_ISIGHTFW is not set
++# CONFIG_USB_YUREX is not set
++# CONFIG_USB_EZUSB_FX2 is not set
++# CONFIG_USB_HSIC_USB3503 is not set
++# CONFIG_USB_LINK_LAYER_TEST is not set
++
++#
++# USB Physical Layer drivers
++#
++# CONFIG_USB_PHY is not set
++# CONFIG_NOP_USB_XCEIV is not set
++# CONFIG_AM335X_PHY_USB is not set
++# CONFIG_USB_ISP1301 is not set
++# CONFIG_USB_ULPI is not set
++CONFIG_USB_GADGET=y
++# CONFIG_USB_GADGET_DEBUG is not set
++# CONFIG_USB_GADGET_DEBUG_FILES is not set
++CONFIG_USB_GADGET_VBUS_DRAW=2
++CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2
++
++#
++# USB Peripheral Controller
++#
++# CONFIG_USB_FUSB300 is not set
++# CONFIG_USB_FOTG210_UDC is not set
++# CONFIG_USB_GR_UDC is not set
++# CONFIG_USB_R8A66597 is not set
++# CONFIG_USB_PXA27X is not set
++# CONFIG_USB_MV_UDC is not set
++CONFIG_HIUSB_DEVICE2_0=y
++CONFIG_USB_HISI_UDC=m
++# CONFIG_USB_AUTO_SWITCH is not set
++# CONFIG_HIUSB_DEVICE3_0 is not set
++# CONFIG_USB_MV_U3D is not set
++# CONFIG_USB_M66592 is not set
++# CONFIG_USB_NET2272 is not set
++# CONFIG_USB_GADGET_XILINX is not set
++CONFIG_USB_LIBCOMPOSITE=m
++CONFIG_USB_F_ACM=m
++CONFIG_USB_U_SERIAL=m
++CONFIG_USB_U_ETHER=m
++CONFIG_USB_F_RNDIS=m
++CONFIG_USB_F_MASS_STORAGE=m
++CONFIG_USB_F_UAC1=m
++CONFIG_USB_F_UVC=m
++# CONFIG_USB_CONFIGFS is not set
++# CONFIG_USB_ZERO is not set
++CONFIG_USB_AUDIO=m
++CONFIG_GADGET_UAC1=y
++# CONFIG_USB_ETH is not set
++# CONFIG_USB_G_NCM is not set
++# CONFIG_USB_GADGETFS is not set
++# CONFIG_USB_FUNCTIONFS is not set
++CONFIG_USB_MASS_STORAGE=m
++# CONFIG_USB_G_SERIAL is not set
++# CONFIG_USB_G_PRINTER is not set
++# CONFIG_USB_CDC_COMPOSITE is not set
++# CONFIG_USB_G_ACM_MS is not set
++CONFIG_USB_G_MULTI=m
++CONFIG_USB_G_MULTI_RNDIS=y
++# CONFIG_USB_G_MULTI_CDC is not set
++# CONFIG_USB_G_HID is not set
++# CONFIG_USB_G_DBGP is not set
++# CONFIG_USB_G_WEBCAM is not set
++CONFIG_USB_G_WEBCAM_AUDIO=m
++# CONFIG_UWB is not set
++CONFIG_MMC=m
++# CONFIG_MMC_DEBUG is not set
++# CONFIG_MMC_CLKGATE is not set
++CONFIG_MMC_EMBEDDED_SDIO=y
++# CONFIG_MMC_PARANOID_SD_INIT is not set
++
++#
++# MMC/SD/SDIO Card Drivers
++#
++CONFIG_MMC_BLOCK=m
++CONFIG_MMC_BLOCK_MINORS=8
++CONFIG_MMC_BLOCK_BOUNCE=y
++# CONFIG_MMC_BLOCK_DEFERRED_RESUME is not set
++# CONFIG_SDIO_UART is not set
++# CONFIG_MMC_TEST is not set
++
++#
++# MMC/SD/SDIO Host Controller Drivers
++#
++# CONFIG_MMC_ARMMMCI is not set
++# CONFIG_MMC_SDHCI is not set
++# CONFIG_MMC_DW is not set
++# CONFIG_MMC_VUB300 is not set
++# CONFIG_MMC_USHC is not set
++# CONFIG_MMC_USDHI6ROL0 is not set
++CONFIG_HIMCIV200=m
++CONFIG_SEND_AUTO_STOP=y
++CONFIG_DETECT_CARD_TIME=200
++# CONFIG_MEMSTICK is not set
++# CONFIG_NEW_LEDS is not set
++# CONFIG_SWITCH is not set
++# CONFIG_ACCESSIBILITY is not set
++# CONFIG_EDAC is not set
++CONFIG_RTC_LIB=y
++# CONFIG_RTC_CLASS is not set
++# CONFIG_DMADEVICES is not set
++# CONFIG_AUXDISPLAY is not set
++# CONFIG_UIO is not set
++# CONFIG_VIRT_DRIVERS is not set
++
++#
++# Virtio drivers
++#
++# CONFIG_VIRTIO_MMIO is not set
++
++#
++# Microsoft Hyper-V guest support
++#
++# CONFIG_STAGING is not set
++
++#
++# SOC (System On Chip) specific Drivers
++#
++# CONFIG_SOC_TI is not set
++CONFIG_CLKDEV_LOOKUP=y
++CONFIG_HAVE_CLK_PREPARE=y
++CONFIG_COMMON_CLK=y
++
++#
++# Common Clock Framework
++#
++# CONFIG_COMMON_CLK_SI5351 is not set
++# CONFIG_COMMON_CLK_SI570 is not set
++# CONFIG_COMMON_CLK_PXA is not set
++# CONFIG_COMMON_CLK_QCOM is not set
++
++#
++# Hardware Spinlock drivers
++#
++
++#
++# Clock Source drivers
++#
++CONFIG_CLKSRC_OF=y
++CONFIG_CLKSRC_MMIO=y
++CONFIG_ARM_ARCH_TIMER=y
++CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y
++# CONFIG_ARM_ARCH_TIMER_VCT_ACCESS is not set
++# CONFIG_ATMEL_PIT is not set
++# CONFIG_SH_TIMER_CMT is not set
++# CONFIG_SH_TIMER_MTU2 is not set
++# CONFIG_SH_TIMER_TMU is not set
++# CONFIG_EM_TIMER_STI is not set
++# CONFIG_CLKSRC_VERSATILE is not set
++# CONFIG_MAILBOX is not set
++# CONFIG_IOMMU_SUPPORT is not set
++
++#
++# Remoteproc drivers
++#
++# CONFIG_STE_MODEM_RPROC is not set
++
++#
++# Rpmsg drivers
++#
++
++#
++# SOC (System On Chip) specific Drivers
++#
++# 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
++CONFIG_IRQCHIP=y
++CONFIG_ARM_GIC=y
++# CONFIG_IPACK_BUS is not set
++CONFIG_ARCH_HAS_RESET_CONTROLLER=y
++CONFIG_RESET_CONTROLLER=y
++# CONFIG_FMC is not set
++
++#
++# PHY Subsystem
++#
++CONFIG_GENERIC_PHY=y
++# CONFIG_BCM_KONA_USB2_PHY is not set
++CONFIG_PHY_HISI_INNO_USB2=m
++# CONFIG_POWERCAP is not set
++# CONFIG_MCB is not set
++# CONFIG_HI_DMAC is not set
++
++#
++# Hisilicon driver support
++#
++# CONFIG_CMA_MEM_SHARED is not set
++# CONFIG_CMA_ADVANCE_SHARE is not set
++
++#
++# File systems
++#
++CONFIG_DCACHE_WORD_ACCESS=y
++# CONFIG_EXT2_FS is not set
++# CONFIG_EXT3_FS is not set
++# CONFIG_EXT4_FS is not set
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_BTRFS_FS is not set
++# CONFIG_NILFS2_FS is not set
++CONFIG_FS_POSIX_ACL=y
++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 is not set
++# CONFIG_FUSE_FS is not set
++# CONFIG_OVERLAY_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_KERNFS=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=m
++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_YAFFS_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 is not set
++# CONFIG_JFFS2_FS_XATTR is not set
++# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
++CONFIG_JFFS2_ZLIB=y
++# CONFIG_JFFS2_LZO is not set
++CONFIG_JFFS2_RTIME=y
++# CONFIG_JFFS2_RUBIN 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 is not set
++CONFIG_SQUASHFS=y
++CONFIG_SQUASHFS_FILE_CACHE=y
++# CONFIG_SQUASHFS_FILE_DIRECT is not set
++CONFIG_SQUASHFS_DECOMP_SINGLE=y
++# CONFIG_SQUASHFS_DECOMP_MULTI is not set
++# CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU is not set
++# CONFIG_SQUASHFS_XATTR is not set
++CONFIG_SQUASHFS_ZLIB=y
++CONFIG_SQUASHFS_LZO=y
++# CONFIG_SQUASHFS_XZ is not set
++# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set
++# CONFIG_SQUASHFS_EMBEDDED is not set
++CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
++# CONFIG_VXFS_FS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_OMFS_FS is not set
++# CONFIG_HPFS_FS is not set
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_QNX6FS_FS is not set
++# CONFIG_ROMFS_FS is not set
++# CONFIG_PSTORE is not set
++# CONFIG_SYSV_FS is not set
++# CONFIG_UFS_FS is not set
++# CONFIG_F2FS_FS is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V2=y
++CONFIG_NFS_V3=y
++CONFIG_NFS_V3_ACL=y
++# CONFIG_NFS_V4 is not set
++# CONFIG_NFS_SWAP is not set
++# CONFIG_ROOT_NFS is not set
++# CONFIG_NFSD is not set
++CONFIG_GRACE_PERIOD=y
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_ACL_SUPPORT=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 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=y
++# CONFIG_DLM is not set
++
++#
++# Kernel hacking
++#
++
++#
++# printk and dmesg options
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4
++# CONFIG_BOOT_PRINTK_DELAY is not set
++
++#
++# Compile-time checks and compiler options
++#
++# CONFIG_DEBUG_INFO is not set
++# CONFIG_ENABLE_WARN_DEPRECATED is not set
++# CONFIG_ENABLE_MUST_CHECK is not set
++CONFIG_FRAME_WARN=1024
++# CONFIG_STRIP_ASM_SYMS is not set
++# CONFIG_READABLE_ASM is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++# CONFIG_DEBUG_FS is not set
++# CONFIG_HEADERS_CHECK is not set
++# CONFIG_DEBUG_SECTION_MISMATCH is not set
++# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
++# CONFIG_MAGIC_SYSRQ is not set
++CONFIG_DEBUG_KERNEL=y
++
++#
++# Memory Debugging
++#
++# CONFIG_DEBUG_PAGEALLOC is not set
++# CONFIG_DEBUG_OBJECTS is not set
++# CONFIG_SLUB_STATS is not set
++CONFIG_HAVE_DEBUG_KMEMLEAK=y
++# CONFIG_DEBUG_KMEMLEAK is not set
++# CONFIG_DEBUG_STACK_USAGE is not set
++# CONFIG_DEBUG_VM is not set
++CONFIG_DEBUG_MEMORY_INIT=y
++# CONFIG_DEBUG_HIGHMEM is not set
++# CONFIG_DEBUG_SHIRQ is not set
++
++#
++# Debug Lockups and Hangs
++#
++# CONFIG_LOCKUP_DETECTOR is not set
++# CONFIG_DETECT_HUNG_TASK is not set
++CONFIG_PANIC_ON_OOPS=y
++CONFIG_PANIC_ON_OOPS_VALUE=1
++CONFIG_PANIC_TIMEOUT=0
++CONFIG_SCHED_DEBUG=y
++# CONFIG_SCHEDSTATS is not set
++# CONFIG_SCHED_STACK_END_CHECK is not set
++# CONFIG_TIMER_STATS is not set
++
++#
++# Lock Debugging (spinlocks, mutexes, etc...)
++#
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_LOCK_STAT is not set
++# CONFIG_DEBUG_ATOMIC_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_LOCK_TORTURE_TEST is not set
++CONFIG_STACKTRACE=y
++# CONFIG_DEBUG_KOBJECT is not set
++CONFIG_DEBUG_BUGVERBOSE=y
++# CONFIG_DEBUG_LIST is not set
++# CONFIG_DEBUG_PI_LIST is not set
++# CONFIG_DEBUG_SG is not set
++# CONFIG_DEBUG_NOTIFIERS is not set
++# CONFIG_DEBUG_CREDENTIALS is not set
++
++#
++# RCU Debugging
++#
++# CONFIG_SPARSE_RCU_POINTER is not set
++# CONFIG_TORTURE_TEST is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_RCU_TRACE is not set
++# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_NOTIFIER_ERROR_INJECTION is not set
++# CONFIG_FAULT_INJECTION is not set
++# CONFIG_LATENCYTOP 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 is not set
++
++#
++# Runtime Testing
++#
++# CONFIG_TEST_LIST_SORT is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_RBTREE_TEST is not set
++# CONFIG_INTERVAL_TREE_TEST is not set
++# CONFIG_PERCPU_TEST is not set
++# CONFIG_ATOMIC64_SELFTEST is not set
++# CONFIG_TEST_STRING_HELPERS is not set
++# CONFIG_TEST_KSTRTOX is not set
++# CONFIG_TEST_RHASHTABLE is not set
++# CONFIG_DMA_API_DEBUG is not set
++# CONFIG_TEST_LKM is not set
++# CONFIG_TEST_USER_COPY is not set
++# CONFIG_TEST_BPF is not set
++# CONFIG_TEST_FIRMWARE is not set
++# CONFIG_TEST_UDELAY is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_KGDB is not set
++# CONFIG_ARM_PTDUMP is not set
++CONFIG_STRICT_DEVMEM=y
++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_DEBUG_UART_PL01X is not set
++# CONFIG_DEBUG_UART_8250 is not set
++# CONFIG_DEBUG_UART_BCM63XX is not set
++CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"
++# CONFIG_OC_ETM is not set
++# CONFIG_PID_IN_CONTEXTIDR is not set
++# CONFIG_DEBUG_SET_MODULE_RONX is not set
++# CONFIG_CORESIGHT is not set
++
++#
++# 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_AEAD=y
++CONFIG_CRYPTO_AEAD2=y
++CONFIG_CRYPTO_BLKCIPHER=y
++CONFIG_CRYPTO_BLKCIPHER2=y
++CONFIG_CRYPTO_HASH=y
++CONFIG_CRYPTO_HASH2=y
++CONFIG_CRYPTO_RNG=y
++CONFIG_CRYPTO_RNG2=y
++CONFIG_CRYPTO_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_WORKQUEUE=y
++# CONFIG_CRYPTO_CRYPTD is not set
++# CONFIG_CRYPTO_MCRYPTD is not set
++# CONFIG_CRYPTO_AUTHENC is not set
++# CONFIG_CRYPTO_TEST is not set
++
++#
++# Authenticated Encryption with Associated Data
++#
++CONFIG_CRYPTO_CCM=y
++# CONFIG_CRYPTO_GCM is not set
++CONFIG_CRYPTO_SEQIV=y
++
++#
++# Block modes
++#
++# CONFIG_CRYPTO_CBC is not set
++CONFIG_CRYPTO_CTR=y
++# 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_CMAC is not set
++# CONFIG_CRYPTO_HMAC is not set
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_VMAC is not set
++
++#
++# Digest
++#
++CONFIG_CRYPTO_CRC32C=y
++# CONFIG_CRYPTO_CRC32 is not set
++# CONFIG_CRYPTO_CRCT10DIF 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_SHA1_ARM_NEON is not set
++# CONFIG_CRYPTO_SHA256 is not set
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_SHA512_ARM_NEON 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_AES_ARM_BS is not set
++# CONFIG_CRYPTO_ANUBIS is not set
++CONFIG_CRYPTO_ARC4=y
++# 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=y
++# CONFIG_CRYPTO_ZLIB is not set
++CONFIG_CRYPTO_LZO=y
++# CONFIG_CRYPTO_LZ4 is not set
++# CONFIG_CRYPTO_LZ4HC is not set
++
++#
++# Random Number Generation
++#
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++# CONFIG_CRYPTO_DRBG_MENU is not set
++# CONFIG_CRYPTO_USER_API_HASH is not set
++# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
++CONFIG_CRYPTO_HW=y
++# CONFIG_BINARY_PRINTF is not set
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++CONFIG_GENERIC_STRNCPY_FROM_USER=y
++CONFIG_GENERIC_STRNLEN_USER=y
++CONFIG_GENERIC_NET_UTILS=y
++CONFIG_GENERIC_PCI_IOMAP=y
++CONFIG_GENERIC_IO=y
++CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
++# CONFIG_CRC_CCITT is not set
++CONFIG_CRC16=y
++# CONFIG_CRC_T10DIF is not set
++# 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=y
++# CONFIG_CRC8 is not set
++# CONFIG_AUDIT_ARCH_COMPAT_GENERIC is not set
++# CONFIG_RANDOM32_SELFTEST is not set
++CONFIG_ZLIB_INFLATE=y
++CONFIG_ZLIB_DEFLATE=y
++CONFIG_LZO_COMPRESS=y
++CONFIG_LZO_DECOMPRESS=y
++CONFIG_XZ_DEC=y
++CONFIG_XZ_DEC_X86=y
++CONFIG_XZ_DEC_POWERPC=y
++CONFIG_XZ_DEC_IA64=y
++CONFIG_XZ_DEC_ARM=y
++CONFIG_XZ_DEC_ARMTHUMB=y
++CONFIG_XZ_DEC_SPARC=y
++CONFIG_XZ_DEC_BCJ=y
++# CONFIG_XZ_DEC_TEST is not set
++CONFIG_GENERIC_ALLOCATOR=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT_MAP=y
++CONFIG_HAS_DMA=y
++CONFIG_DQL=y
++CONFIG_NLATTR=y
++CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
++CONFIG_AVERAGE=y
++# CONFIG_CORDIC is not set
++# CONFIG_DDR is not set
++CONFIG_LIBFDT=y
++CONFIG_ARCH_HAS_SG_CHAIN=y
++# CONFIG_VIRTUALIZATION is not set
+diff --git a/arch/arm/configs/hisi_defconfig b/arch/arm/configs/hisi_defconfig
+index 1772505..9e35ff8 100644
+--- a/arch/arm/configs/hisi_defconfig
++++ b/arch/arm/configs/hisi_defconfig
+@@ -7,6 +7,7 @@ CONFIG_ARCH_HISI=y
+ CONFIG_ARCH_HI3xxx=y
+ CONFIG_ARCH_HIX5HD2=y
+ CONFIG_ARCH_HIP04=y
++CONFIG_ARCH_HI3519=y
+ CONFIG_SMP=y
+ CONFIG_NR_CPUS=16
+ CONFIG_PREEMPT=y
+diff --git a/arch/arm/include/asm/fiq_glue.h b/arch/arm/include/asm/fiq_glue.h
+new file mode 100644
+index 0000000..a9e244f
+--- /dev/null
++++ b/arch/arm/include/asm/fiq_glue.h
+@@ -0,0 +1,33 @@
++/*
++ * Copyright (C) 2010 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#ifndef __ASM_FIQ_GLUE_H
++#define __ASM_FIQ_GLUE_H
++
++struct fiq_glue_handler {
++	void (*fiq)(struct fiq_glue_handler *h, void *regs, void *svc_sp);
++	void (*resume)(struct fiq_glue_handler *h);
++};
++typedef void (*fiq_return_handler_t)(void);
++
++int fiq_glue_register_handler(struct fiq_glue_handler *handler);
++int fiq_glue_set_return_handler(fiq_return_handler_t fiq_return);
++int fiq_glue_clear_return_handler(fiq_return_handler_t fiq_return);
++
++#ifdef CONFIG_FIQ_GLUE
++void fiq_glue_resume(void);
++#else
++static inline void fiq_glue_resume(void) {}
++#endif
++
++#endif
+diff --git a/arch/arm/include/asm/hardirq.h b/arch/arm/include/asm/hardirq.h
+index fe3ea77..5df33e3 100644
+--- a/arch/arm/include/asm/hardirq.h
++++ b/arch/arm/include/asm/hardirq.h
+@@ -5,7 +5,7 @@
+ #include <linux/threads.h>
+ #include <asm/irq.h>
+ 
+-#define NR_IPI	8
++#define NR_IPI	9
+ 
+ typedef struct {
+ 	unsigned int __softirq_pending;
+diff --git a/arch/arm/include/asm/hardware/coresight.h b/arch/arm/include/asm/hardware/coresight.h
+index ad774f3..b350765 100644
+--- a/arch/arm/include/asm/hardware/coresight.h
++++ b/arch/arm/include/asm/hardware/coresight.h
+@@ -17,15 +17,23 @@
+ #define TRACER_ACCESSED_BIT	0
+ #define TRACER_RUNNING_BIT	1
+ #define TRACER_CYCLE_ACC_BIT	2
++#define TRACER_TRACE_DATA_BIT	3
++#define TRACER_TIMESTAMP_BIT	4
++#define TRACER_BRANCHOUTPUT_BIT	5
++#define TRACER_RETURN_STACK_BIT	6
+ #define TRACER_ACCESSED		BIT(TRACER_ACCESSED_BIT)
+ #define TRACER_RUNNING		BIT(TRACER_RUNNING_BIT)
+ #define TRACER_CYCLE_ACC	BIT(TRACER_CYCLE_ACC_BIT)
++#define TRACER_TRACE_DATA	BIT(TRACER_TRACE_DATA_BIT)
++#define TRACER_TIMESTAMP	BIT(TRACER_TIMESTAMP_BIT)
++#define TRACER_BRANCHOUTPUT	BIT(TRACER_BRANCHOUTPUT_BIT)
++#define TRACER_RETURN_STACK	BIT(TRACER_RETURN_STACK_BIT)
+ 
+ #define TRACER_TIMEOUT 10000
+ 
+-#define etm_writel(t, v, x) \
+-	(writel_relaxed((v), (t)->etm_regs + (x)))
+-#define etm_readl(t, x) (readl_relaxed((t)->etm_regs + (x)))
++#define etm_writel(t, id, v, x) \
++	(writel_relaxed((v), (t)->etm_regs[(id)] + (x)))
++#define etm_readl(t, id, x) (readl_relaxed((t)->etm_regs[(id)] + (x)))
+ 
+ /* CoreSight Management Registers */
+ #define CSMR_LOCKACCESS 0xfb0
+@@ -43,7 +51,7 @@
+ #define ETMCTRL_POWERDOWN	1
+ #define ETMCTRL_PROGRAM		(1 << 10)
+ #define ETMCTRL_PORTSEL		(1 << 11)
+-#define ETMCTRL_DO_CONTEXTID	(3 << 14)
++#define ETMCTRL_CONTEXTIDSIZE(x) (((x) & 3) << 14)
+ #define ETMCTRL_PORTMASK1	(7 << 4)
+ #define ETMCTRL_PORTMASK2	(1 << 21)
+ #define ETMCTRL_PORTMASK	(ETMCTRL_PORTMASK1 | ETMCTRL_PORTMASK2)
+@@ -55,9 +63,12 @@
+ #define ETMCTRL_DATA_DO_BOTH	(ETMCTRL_DATA_DO_DATA | ETMCTRL_DATA_DO_ADDR)
+ #define ETMCTRL_BRANCH_OUTPUT	(1 << 8)
+ #define ETMCTRL_CYCLEACCURATE	(1 << 12)
++#define ETMCTRL_TIMESTAMP_EN	(1 << 28)
++#define ETMCTRL_RETURN_STACK_EN	(1 << 29)
+ 
+ /* ETM configuration code register */
+ #define ETMR_CONFCODE		(0x04)
++#define ETMCCR_ETMIDR_PRESENT	BIT(31)
+ 
+ /* ETM trace start/stop resource control register */
+ #define ETMR_TRACESSCTRL	(0x18)
+@@ -113,10 +124,25 @@
+ #define ETMR_TRACEENCTRL	0x24
+ #define ETMTE_INCLEXCL		BIT(24)
+ #define ETMR_TRACEENEVT		0x20
+-#define ETMCTRL_OPTS		(ETMCTRL_DO_CPRT | \
+-				ETMCTRL_DATA_DO_ADDR | \
+-				ETMCTRL_BRANCH_OUTPUT | \
+-				ETMCTRL_DO_CONTEXTID)
++
++#define ETMR_VIEWDATAEVT	0x30
++#define ETMR_VIEWDATACTRL1	0x34
++#define ETMR_VIEWDATACTRL2	0x38
++#define ETMR_VIEWDATACTRL3	0x3c
++#define ETMVDC3_EXCLONLY	BIT(16)
++
++#define ETMCTRL_OPTS		(ETMCTRL_DO_CPRT)
++
++#define ETMR_ID			0x1e4
++#define ETMIDR_VERSION(x)	(((x) >> 4) & 0xff)
++#define ETMIDR_VERSION_3_1	0x21
++#define ETMIDR_VERSION_PFT_1_0	0x30
++
++#define ETMR_CCE		0x1e8
++#define ETMCCER_RETURN_STACK_IMPLEMENTED	BIT(23)
++#define ETMCCER_TIMESTAMPING_IMPLEMENTED	BIT(22)
++
++#define ETMR_TRACEIDR		0x200
+ 
+ /* ETM management registers, "ETM Architecture", 3.5.24 */
+ #define ETMMR_OSLAR	0x300
+@@ -140,14 +166,16 @@
+ #define ETBFF_TRIGIN		BIT(8)
+ #define ETBFF_TRIGEVT		BIT(9)
+ #define ETBFF_TRIGFL		BIT(10)
++#define ETBFF_STOPFL		BIT(12)
+ 
+ #define etb_writel(t, v, x) \
+ 	(writel_relaxed((v), (t)->etb_regs + (x)))
+ #define etb_readl(t, x) (readl_relaxed((t)->etb_regs + (x)))
+ 
+-#define etm_lock(t) do { etm_writel((t), 0, CSMR_LOCKACCESS); } while (0)
+-#define etm_unlock(t) \
+-	do { etm_writel((t), CS_LAR_KEY, CSMR_LOCKACCESS); } while (0)
++#define etm_lock(t, id) \
++	do { etm_writel((t), (id), 0, CSMR_LOCKACCESS); } while (0)
++#define etm_unlock(t, id) \
++	do { etm_writel((t), (id), CS_LAR_KEY, CSMR_LOCKACCESS); } while (0)
+ 
+ #define etb_lock(t) do { etb_writel((t), 0, CSMR_LOCKACCESS); } while (0)
+ #define etb_unlock(t) \
+diff --git a/arch/arm/include/asm/hardware/cp14.h b/arch/arm/include/asm/hardware/cp14.h
+new file mode 100644
+index 0000000..61576dc
+--- /dev/null
++++ b/arch/arm/include/asm/hardware/cp14.h
+@@ -0,0 +1,542 @@
++/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#ifndef __ASM_HARDWARE_CP14_H
++#define __ASM_HARDWARE_CP14_H
++
++#include <linux/types.h>
++
++/* Accessors for CP14 registers */
++#define dbg_read(reg)			RCP14_##reg()
++#define dbg_write(val, reg)		WCP14_##reg(val)
++#define etm_read(reg)			RCP14_##reg()
++#define etm_write(val, reg)		WCP14_##reg(val)
++
++/* MRC14 and MCR14 */
++#define MRC14(op1, crn, crm, op2)					\
++({									\
++u32 val;								\
++asm volatile("mrc p14, "#op1", %0, "#crn", "#crm", "#op2 : "=r" (val));	\
++val;									\
++})
++
++#define MCR14(val, op1, crn, crm, op2)					\
++({									\
++asm volatile("mcr p14, "#op1", %0, "#crn", "#crm", "#op2 : : "r" (val));\
++})
++
++/*
++ * Debug Registers
++ *
++ * Available only in DBGv7
++ * DBGECR, DBGDSCCR, DBGDSMCR, DBGDRCR
++ *
++ * Available only in DBGv7.1
++ * DBGBXVRm, DBGOSDLR, DBGDEVID2, DBGDEVID1
++ *
++ * Read only
++ * DBGDIDR, DBGDSCRint, DBGDTRRXint, DBGDRAR, DBGOSLSR, DBGOSSRR, DBGPRSR,
++ * DBGPRSR, DBGDSAR, DBGAUTHSTATUS, DBGDEVID2, DBGDEVID1, DBGDEVID
++ *
++ * Write only
++ * DBGDTRTXint, DBGOSLAR
++ */
++#define RCP14_DBGDIDR()			MRC14(0, c0, c0, 0)
++#define RCP14_DBGDSCRint()		MRC14(0, c0, c1, 0)
++#define RCP14_DBGDTRRXint()		MRC14(0, c0, c5, 0)
++#define RCP14_DBGWFAR()			MRC14(0, c0, c6, 0)
++#define RCP14_DBGVCR()			MRC14(0, c0, c7, 0)
++#define RCP14_DBGECR()			MRC14(0, c0, c9, 0)
++#define RCP14_DBGDSCCR()		MRC14(0, c0, c10, 0)
++#define RCP14_DBGDSMCR()		MRC14(0, c0, c11, 0)
++#define RCP14_DBGDTRRXext()		MRC14(0, c0, c0, 2)
++#define RCP14_DBGDSCRext()		MRC14(0, c0, c2, 2)
++#define RCP14_DBGDTRTXext()		MRC14(0, c0, c3, 2)
++#define RCP14_DBGDRCR()			MRC14(0, c0, c4, 2)
++#define RCP14_DBGBVR0()			MRC14(0, c0, c0, 4)
++#define RCP14_DBGBVR1()			MRC14(0, c0, c1, 4)
++#define RCP14_DBGBVR2()			MRC14(0, c0, c2, 4)
++#define RCP14_DBGBVR3()			MRC14(0, c0, c3, 4)
++#define RCP14_DBGBVR4()			MRC14(0, c0, c4, 4)
++#define RCP14_DBGBVR5()			MRC14(0, c0, c5, 4)
++#define RCP14_DBGBVR6()			MRC14(0, c0, c6, 4)
++#define RCP14_DBGBVR7()			MRC14(0, c0, c7, 4)
++#define RCP14_DBGBVR8()			MRC14(0, c0, c8, 4)
++#define RCP14_DBGBVR9()			MRC14(0, c0, c9, 4)
++#define RCP14_DBGBVR10()		MRC14(0, c0, c10, 4)
++#define RCP14_DBGBVR11()		MRC14(0, c0, c11, 4)
++#define RCP14_DBGBVR12()		MRC14(0, c0, c12, 4)
++#define RCP14_DBGBVR13()		MRC14(0, c0, c13, 4)
++#define RCP14_DBGBVR14()		MRC14(0, c0, c14, 4)
++#define RCP14_DBGBVR15()		MRC14(0, c0, c15, 4)
++#define RCP14_DBGBCR0()			MRC14(0, c0, c0, 5)
++#define RCP14_DBGBCR1()			MRC14(0, c0, c1, 5)
++#define RCP14_DBGBCR2()			MRC14(0, c0, c2, 5)
++#define RCP14_DBGBCR3()			MRC14(0, c0, c3, 5)
++#define RCP14_DBGBCR4()			MRC14(0, c0, c4, 5)
++#define RCP14_DBGBCR5()			MRC14(0, c0, c5, 5)
++#define RCP14_DBGBCR6()			MRC14(0, c0, c6, 5)
++#define RCP14_DBGBCR7()			MRC14(0, c0, c7, 5)
++#define RCP14_DBGBCR8()			MRC14(0, c0, c8, 5)
++#define RCP14_DBGBCR9()			MRC14(0, c0, c9, 5)
++#define RCP14_DBGBCR10()		MRC14(0, c0, c10, 5)
++#define RCP14_DBGBCR11()		MRC14(0, c0, c11, 5)
++#define RCP14_DBGBCR12()		MRC14(0, c0, c12, 5)
++#define RCP14_DBGBCR13()		MRC14(0, c0, c13, 5)
++#define RCP14_DBGBCR14()		MRC14(0, c0, c14, 5)
++#define RCP14_DBGBCR15()		MRC14(0, c0, c15, 5)
++#define RCP14_DBGWVR0()			MRC14(0, c0, c0, 6)
++#define RCP14_DBGWVR1()			MRC14(0, c0, c1, 6)
++#define RCP14_DBGWVR2()			MRC14(0, c0, c2, 6)
++#define RCP14_DBGWVR3()			MRC14(0, c0, c3, 6)
++#define RCP14_DBGWVR4()			MRC14(0, c0, c4, 6)
++#define RCP14_DBGWVR5()			MRC14(0, c0, c5, 6)
++#define RCP14_DBGWVR6()			MRC14(0, c0, c6, 6)
++#define RCP14_DBGWVR7()			MRC14(0, c0, c7, 6)
++#define RCP14_DBGWVR8()			MRC14(0, c0, c8, 6)
++#define RCP14_DBGWVR9()			MRC14(0, c0, c9, 6)
++#define RCP14_DBGWVR10()		MRC14(0, c0, c10, 6)
++#define RCP14_DBGWVR11()		MRC14(0, c0, c11, 6)
++#define RCP14_DBGWVR12()		MRC14(0, c0, c12, 6)
++#define RCP14_DBGWVR13()		MRC14(0, c0, c13, 6)
++#define RCP14_DBGWVR14()		MRC14(0, c0, c14, 6)
++#define RCP14_DBGWVR15()		MRC14(0, c0, c15, 6)
++#define RCP14_DBGWCR0()			MRC14(0, c0, c0, 7)
++#define RCP14_DBGWCR1()			MRC14(0, c0, c1, 7)
++#define RCP14_DBGWCR2()			MRC14(0, c0, c2, 7)
++#define RCP14_DBGWCR3()			MRC14(0, c0, c3, 7)
++#define RCP14_DBGWCR4()			MRC14(0, c0, c4, 7)
++#define RCP14_DBGWCR5()			MRC14(0, c0, c5, 7)
++#define RCP14_DBGWCR6()			MRC14(0, c0, c6, 7)
++#define RCP14_DBGWCR7()			MRC14(0, c0, c7, 7)
++#define RCP14_DBGWCR8()			MRC14(0, c0, c8, 7)
++#define RCP14_DBGWCR9()			MRC14(0, c0, c9, 7)
++#define RCP14_DBGWCR10()		MRC14(0, c0, c10, 7)
++#define RCP14_DBGWCR11()		MRC14(0, c0, c11, 7)
++#define RCP14_DBGWCR12()		MRC14(0, c0, c12, 7)
++#define RCP14_DBGWCR13()		MRC14(0, c0, c13, 7)
++#define RCP14_DBGWCR14()		MRC14(0, c0, c14, 7)
++#define RCP14_DBGWCR15()		MRC14(0, c0, c15, 7)
++#define RCP14_DBGDRAR()			MRC14(0, c1, c0, 0)
++#define RCP14_DBGBXVR0()		MRC14(0, c1, c0, 1)
++#define RCP14_DBGBXVR1()		MRC14(0, c1, c1, 1)
++#define RCP14_DBGBXVR2()		MRC14(0, c1, c2, 1)
++#define RCP14_DBGBXVR3()		MRC14(0, c1, c3, 1)
++#define RCP14_DBGBXVR4()		MRC14(0, c1, c4, 1)
++#define RCP14_DBGBXVR5()		MRC14(0, c1, c5, 1)
++#define RCP14_DBGBXVR6()		MRC14(0, c1, c6, 1)
++#define RCP14_DBGBXVR7()		MRC14(0, c1, c7, 1)
++#define RCP14_DBGBXVR8()		MRC14(0, c1, c8, 1)
++#define RCP14_DBGBXVR9()		MRC14(0, c1, c9, 1)
++#define RCP14_DBGBXVR10()		MRC14(0, c1, c10, 1)
++#define RCP14_DBGBXVR11()		MRC14(0, c1, c11, 1)
++#define RCP14_DBGBXVR12()		MRC14(0, c1, c12, 1)
++#define RCP14_DBGBXVR13()		MRC14(0, c1, c13, 1)
++#define RCP14_DBGBXVR14()		MRC14(0, c1, c14, 1)
++#define RCP14_DBGBXVR15()		MRC14(0, c1, c15, 1)
++#define RCP14_DBGOSLSR()		MRC14(0, c1, c1, 4)
++#define RCP14_DBGOSSRR()		MRC14(0, c1, c2, 4)
++#define RCP14_DBGOSDLR()		MRC14(0, c1, c3, 4)
++#define RCP14_DBGPRCR()			MRC14(0, c1, c4, 4)
++#define RCP14_DBGPRSR()			MRC14(0, c1, c5, 4)
++#define RCP14_DBGDSAR()			MRC14(0, c2, c0, 0)
++#define RCP14_DBGITCTRL()		MRC14(0, c7, c0, 4)
++#define RCP14_DBGCLAIMSET()		MRC14(0, c7, c8, 6)
++#define RCP14_DBGCLAIMCLR()		MRC14(0, c7, c9, 6)
++#define RCP14_DBGAUTHSTATUS()		MRC14(0, c7, c14, 6)
++#define RCP14_DBGDEVID2()		MRC14(0, c7, c0, 7)
++#define RCP14_DBGDEVID1()		MRC14(0, c7, c1, 7)
++#define RCP14_DBGDEVID()		MRC14(0, c7, c2, 7)
++
++#define WCP14_DBGDTRTXint(val)		MCR14(val, 0, c0, c5, 0)
++#define WCP14_DBGWFAR(val)		MCR14(val, 0, c0, c6, 0)
++#define WCP14_DBGVCR(val)		MCR14(val, 0, c0, c7, 0)
++#define WCP14_DBGECR(val)		MCR14(val, 0, c0, c9, 0)
++#define WCP14_DBGDSCCR(val)		MCR14(val, 0, c0, c10, 0)
++#define WCP14_DBGDSMCR(val)		MCR14(val, 0, c0, c11, 0)
++#define WCP14_DBGDTRRXext(val)		MCR14(val, 0, c0, c0, 2)
++#define WCP14_DBGDSCRext(val)		MCR14(val, 0, c0, c2, 2)
++#define WCP14_DBGDTRTXext(val)		MCR14(val, 0, c0, c3, 2)
++#define WCP14_DBGDRCR(val)		MCR14(val, 0, c0, c4, 2)
++#define WCP14_DBGBVR0(val)		MCR14(val, 0, c0, c0, 4)
++#define WCP14_DBGBVR1(val)		MCR14(val, 0, c0, c1, 4)
++#define WCP14_DBGBVR2(val)		MCR14(val, 0, c0, c2, 4)
++#define WCP14_DBGBVR3(val)		MCR14(val, 0, c0, c3, 4)
++#define WCP14_DBGBVR4(val)		MCR14(val, 0, c0, c4, 4)
++#define WCP14_DBGBVR5(val)		MCR14(val, 0, c0, c5, 4)
++#define WCP14_DBGBVR6(val)		MCR14(val, 0, c0, c6, 4)
++#define WCP14_DBGBVR7(val)		MCR14(val, 0, c0, c7, 4)
++#define WCP14_DBGBVR8(val)		MCR14(val, 0, c0, c8, 4)
++#define WCP14_DBGBVR9(val)		MCR14(val, 0, c0, c9, 4)
++#define WCP14_DBGBVR10(val)		MCR14(val, 0, c0, c10, 4)
++#define WCP14_DBGBVR11(val)		MCR14(val, 0, c0, c11, 4)
++#define WCP14_DBGBVR12(val)		MCR14(val, 0, c0, c12, 4)
++#define WCP14_DBGBVR13(val)		MCR14(val, 0, c0, c13, 4)
++#define WCP14_DBGBVR14(val)		MCR14(val, 0, c0, c14, 4)
++#define WCP14_DBGBVR15(val)		MCR14(val, 0, c0, c15, 4)
++#define WCP14_DBGBCR0(val)		MCR14(val, 0, c0, c0, 5)
++#define WCP14_DBGBCR1(val)		MCR14(val, 0, c0, c1, 5)
++#define WCP14_DBGBCR2(val)		MCR14(val, 0, c0, c2, 5)
++#define WCP14_DBGBCR3(val)		MCR14(val, 0, c0, c3, 5)
++#define WCP14_DBGBCR4(val)		MCR14(val, 0, c0, c4, 5)
++#define WCP14_DBGBCR5(val)		MCR14(val, 0, c0, c5, 5)
++#define WCP14_DBGBCR6(val)		MCR14(val, 0, c0, c6, 5)
++#define WCP14_DBGBCR7(val)		MCR14(val, 0, c0, c7, 5)
++#define WCP14_DBGBCR8(val)		MCR14(val, 0, c0, c8, 5)
++#define WCP14_DBGBCR9(val)		MCR14(val, 0, c0, c9, 5)
++#define WCP14_DBGBCR10(val)		MCR14(val, 0, c0, c10, 5)
++#define WCP14_DBGBCR11(val)		MCR14(val, 0, c0, c11, 5)
++#define WCP14_DBGBCR12(val)		MCR14(val, 0, c0, c12, 5)
++#define WCP14_DBGBCR13(val)		MCR14(val, 0, c0, c13, 5)
++#define WCP14_DBGBCR14(val)		MCR14(val, 0, c0, c14, 5)
++#define WCP14_DBGBCR15(val)		MCR14(val, 0, c0, c15, 5)
++#define WCP14_DBGWVR0(val)		MCR14(val, 0, c0, c0, 6)
++#define WCP14_DBGWVR1(val)		MCR14(val, 0, c0, c1, 6)
++#define WCP14_DBGWVR2(val)		MCR14(val, 0, c0, c2, 6)
++#define WCP14_DBGWVR3(val)		MCR14(val, 0, c0, c3, 6)
++#define WCP14_DBGWVR4(val)		MCR14(val, 0, c0, c4, 6)
++#define WCP14_DBGWVR5(val)		MCR14(val, 0, c0, c5, 6)
++#define WCP14_DBGWVR6(val)		MCR14(val, 0, c0, c6, 6)
++#define WCP14_DBGWVR7(val)		MCR14(val, 0, c0, c7, 6)
++#define WCP14_DBGWVR8(val)		MCR14(val, 0, c0, c8, 6)
++#define WCP14_DBGWVR9(val)		MCR14(val, 0, c0, c9, 6)
++#define WCP14_DBGWVR10(val)		MCR14(val, 0, c0, c10, 6)
++#define WCP14_DBGWVR11(val)		MCR14(val, 0, c0, c11, 6)
++#define WCP14_DBGWVR12(val)		MCR14(val, 0, c0, c12, 6)
++#define WCP14_DBGWVR13(val)		MCR14(val, 0, c0, c13, 6)
++#define WCP14_DBGWVR14(val)		MCR14(val, 0, c0, c14, 6)
++#define WCP14_DBGWVR15(val)		MCR14(val, 0, c0, c15, 6)
++#define WCP14_DBGWCR0(val)		MCR14(val, 0, c0, c0, 7)
++#define WCP14_DBGWCR1(val)		MCR14(val, 0, c0, c1, 7)
++#define WCP14_DBGWCR2(val)		MCR14(val, 0, c0, c2, 7)
++#define WCP14_DBGWCR3(val)		MCR14(val, 0, c0, c3, 7)
++#define WCP14_DBGWCR4(val)		MCR14(val, 0, c0, c4, 7)
++#define WCP14_DBGWCR5(val)		MCR14(val, 0, c0, c5, 7)
++#define WCP14_DBGWCR6(val)		MCR14(val, 0, c0, c6, 7)
++#define WCP14_DBGWCR7(val)		MCR14(val, 0, c0, c7, 7)
++#define WCP14_DBGWCR8(val)		MCR14(val, 0, c0, c8, 7)
++#define WCP14_DBGWCR9(val)		MCR14(val, 0, c0, c9, 7)
++#define WCP14_DBGWCR10(val)		MCR14(val, 0, c0, c10, 7)
++#define WCP14_DBGWCR11(val)		MCR14(val, 0, c0, c11, 7)
++#define WCP14_DBGWCR12(val)		MCR14(val, 0, c0, c12, 7)
++#define WCP14_DBGWCR13(val)		MCR14(val, 0, c0, c13, 7)
++#define WCP14_DBGWCR14(val)		MCR14(val, 0, c0, c14, 7)
++#define WCP14_DBGWCR15(val)		MCR14(val, 0, c0, c15, 7)
++#define WCP14_DBGBXVR0(val)		MCR14(val, 0, c1, c0, 1)
++#define WCP14_DBGBXVR1(val)		MCR14(val, 0, c1, c1, 1)
++#define WCP14_DBGBXVR2(val)		MCR14(val, 0, c1, c2, 1)
++#define WCP14_DBGBXVR3(val)		MCR14(val, 0, c1, c3, 1)
++#define WCP14_DBGBXVR4(val)		MCR14(val, 0, c1, c4, 1)
++#define WCP14_DBGBXVR5(val)		MCR14(val, 0, c1, c5, 1)
++#define WCP14_DBGBXVR6(val)		MCR14(val, 0, c1, c6, 1)
++#define WCP14_DBGBXVR7(val)		MCR14(val, 0, c1, c7, 1)
++#define WCP14_DBGBXVR8(val)		MCR14(val, 0, c1, c8, 1)
++#define WCP14_DBGBXVR9(val)		MCR14(val, 0, c1, c9, 1)
++#define WCP14_DBGBXVR10(val)		MCR14(val, 0, c1, c10, 1)
++#define WCP14_DBGBXVR11(val)		MCR14(val, 0, c1, c11, 1)
++#define WCP14_DBGBXVR12(val)		MCR14(val, 0, c1, c12, 1)
++#define WCP14_DBGBXVR13(val)		MCR14(val, 0, c1, c13, 1)
++#define WCP14_DBGBXVR14(val)		MCR14(val, 0, c1, c14, 1)
++#define WCP14_DBGBXVR15(val)		MCR14(val, 0, c1, c15, 1)
++#define WCP14_DBGOSLAR(val)		MCR14(val, 0, c1, c0, 4)
++#define WCP14_DBGOSSRR(val)		MCR14(val, 0, c1, c2, 4)
++#define WCP14_DBGOSDLR(val)		MCR14(val, 0, c1, c3, 4)
++#define WCP14_DBGPRCR(val)		MCR14(val, 0, c1, c4, 4)
++#define WCP14_DBGITCTRL(val)		MCR14(val, 0, c7, c0, 4)
++#define WCP14_DBGCLAIMSET(val)		MCR14(val, 0, c7, c8, 6)
++#define WCP14_DBGCLAIMCLR(val)		MCR14(val, 0, c7, c9, 6)
++
++/*
++ * ETM Registers
++ *
++ * Available only in ETMv3.3, 3.4, 3.5
++ * ETMASICCR, ETMTECR2, ETMFFRR, ETMVDEVR, ETMVDCR1, ETMVDCR2, ETMVDCR3,
++ * ETMDCVRn, ETMDCMRn
++ *
++ * Available only in ETMv3.5 as read only
++ * ETMIDR2
++ *
++ * Available only in ETMv3.5, PFTv1.0, 1.1
++ * ETMTSEVR, ETMVMIDCVR, ETMPDCR
++ *
++ * Read only
++ * ETMCCR, ETMSCR, ETMIDR, ETMCCER, ETMOSLSR
++ * ETMLSR, ETMAUTHSTATUS, ETMDEVID, ETMDEVTYPE, ETMPIDR4, ETMPIDR5, ETMPIDR6,
++ * ETMPIDR7, ETMPIDR0, ETMPIDR1, ETMPIDR2, ETMPIDR2, ETMPIDR3, ETMCIDR0,
++ * ETMCIDR1, ETMCIDR2, ETMCIDR3
++ *
++ * Write only
++ * ETMOSLAR, ETMLAR
++ * Note: ETMCCER[11] controls WO nature of certain regs. Refer ETM arch spec.
++ */
++#define RCP14_ETMCR()			MRC14(1, c0, c0, 0)
++#define RCP14_ETMCCR()			MRC14(1, c0, c1, 0)
++#define RCP14_ETMTRIGGER()		MRC14(1, c0, c2, 0)
++#define RCP14_ETMASICCR()		MRC14(1, c0, c3, 0)
++#define RCP14_ETMSR()			MRC14(1, c0, c4, 0)
++#define RCP14_ETMSCR()			MRC14(1, c0, c5, 0)
++#define RCP14_ETMTSSCR()		MRC14(1, c0, c6, 0)
++#define RCP14_ETMTECR2()		MRC14(1, c0, c7, 0)
++#define RCP14_ETMTEEVR()		MRC14(1, c0, c8, 0)
++#define RCP14_ETMTECR1()		MRC14(1, c0, c9, 0)
++#define RCP14_ETMFFRR()			MRC14(1, c0, c10, 0)
++#define RCP14_ETMFFLR()			MRC14(1, c0, c11, 0)
++#define RCP14_ETMVDEVR()		MRC14(1, c0, c12, 0)
++#define RCP14_ETMVDCR1()		MRC14(1, c0, c13, 0)
++#define RCP14_ETMVDCR2()		MRC14(1, c0, c14, 0)
++#define RCP14_ETMVDCR3()		MRC14(1, c0, c15, 0)
++#define RCP14_ETMACVR0()		MRC14(1, c0, c0, 1)
++#define RCP14_ETMACVR1()		MRC14(1, c0, c1, 1)
++#define RCP14_ETMACVR2()		MRC14(1, c0, c2, 1)
++#define RCP14_ETMACVR3()		MRC14(1, c0, c3, 1)
++#define RCP14_ETMACVR4()		MRC14(1, c0, c4, 1)
++#define RCP14_ETMACVR5()		MRC14(1, c0, c5, 1)
++#define RCP14_ETMACVR6()		MRC14(1, c0, c6, 1)
++#define RCP14_ETMACVR7()		MRC14(1, c0, c7, 1)
++#define RCP14_ETMACVR8()		MRC14(1, c0, c8, 1)
++#define RCP14_ETMACVR9()		MRC14(1, c0, c9, 1)
++#define RCP14_ETMACVR10()		MRC14(1, c0, c10, 1)
++#define RCP14_ETMACVR11()		MRC14(1, c0, c11, 1)
++#define RCP14_ETMACVR12()		MRC14(1, c0, c12, 1)
++#define RCP14_ETMACVR13()		MRC14(1, c0, c13, 1)
++#define RCP14_ETMACVR14()		MRC14(1, c0, c14, 1)
++#define RCP14_ETMACVR15()		MRC14(1, c0, c15, 1)
++#define RCP14_ETMACTR0()		MRC14(1, c0, c0, 2)
++#define RCP14_ETMACTR1()		MRC14(1, c0, c1, 2)
++#define RCP14_ETMACTR2()		MRC14(1, c0, c2, 2)
++#define RCP14_ETMACTR3()		MRC14(1, c0, c3, 2)
++#define RCP14_ETMACTR4()		MRC14(1, c0, c4, 2)
++#define RCP14_ETMACTR5()		MRC14(1, c0, c5, 2)
++#define RCP14_ETMACTR6()		MRC14(1, c0, c6, 2)
++#define RCP14_ETMACTR7()		MRC14(1, c0, c7, 2)
++#define RCP14_ETMACTR8()		MRC14(1, c0, c8, 2)
++#define RCP14_ETMACTR9()		MRC14(1, c0, c9, 2)
++#define RCP14_ETMACTR10()		MRC14(1, c0, c10, 2)
++#define RCP14_ETMACTR11()		MRC14(1, c0, c11, 2)
++#define RCP14_ETMACTR12()		MRC14(1, c0, c12, 2)
++#define RCP14_ETMACTR13()		MRC14(1, c0, c13, 2)
++#define RCP14_ETMACTR14()		MRC14(1, c0, c14, 2)
++#define RCP14_ETMACTR15()		MRC14(1, c0, c15, 2)
++#define RCP14_ETMDCVR0()		MRC14(1, c0, c0, 3)
++#define RCP14_ETMDCVR2()		MRC14(1, c0, c2, 3)
++#define RCP14_ETMDCVR4()		MRC14(1, c0, c4, 3)
++#define RCP14_ETMDCVR6()		MRC14(1, c0, c6, 3)
++#define RCP14_ETMDCVR8()		MRC14(1, c0, c8, 3)
++#define RCP14_ETMDCVR10()		MRC14(1, c0, c10, 3)
++#define RCP14_ETMDCVR12()		MRC14(1, c0, c12, 3)
++#define RCP14_ETMDCVR14()		MRC14(1, c0, c14, 3)
++#define RCP14_ETMDCMR0()		MRC14(1, c0, c0, 4)
++#define RCP14_ETMDCMR2()		MRC14(1, c0, c2, 4)
++#define RCP14_ETMDCMR4()		MRC14(1, c0, c4, 4)
++#define RCP14_ETMDCMR6()		MRC14(1, c0, c6, 4)
++#define RCP14_ETMDCMR8()		MRC14(1, c0, c8, 4)
++#define RCP14_ETMDCMR10()		MRC14(1, c0, c10, 4)
++#define RCP14_ETMDCMR12()		MRC14(1, c0, c12, 4)
++#define RCP14_ETMDCMR14()		MRC14(1, c0, c14, 4)
++#define RCP14_ETMCNTRLDVR0()		MRC14(1, c0, c0, 5)
++#define RCP14_ETMCNTRLDVR1()		MRC14(1, c0, c1, 5)
++#define RCP14_ETMCNTRLDVR2()		MRC14(1, c0, c2, 5)
++#define RCP14_ETMCNTRLDVR3()		MRC14(1, c0, c3, 5)
++#define RCP14_ETMCNTENR0()		MRC14(1, c0, c4, 5)
++#define RCP14_ETMCNTENR1()		MRC14(1, c0, c5, 5)
++#define RCP14_ETMCNTENR2()		MRC14(1, c0, c6, 5)
++#define RCP14_ETMCNTENR3()		MRC14(1, c0, c7, 5)
++#define RCP14_ETMCNTRLDEVR0()		MRC14(1, c0, c8, 5)
++#define RCP14_ETMCNTRLDEVR1()		MRC14(1, c0, c9, 5)
++#define RCP14_ETMCNTRLDEVR2()		MRC14(1, c0, c10, 5)
++#define RCP14_ETMCNTRLDEVR3()		MRC14(1, c0, c11, 5)
++#define RCP14_ETMCNTVR0()		MRC14(1, c0, c12, 5)
++#define RCP14_ETMCNTVR1()		MRC14(1, c0, c13, 5)
++#define RCP14_ETMCNTVR2()		MRC14(1, c0, c14, 5)
++#define RCP14_ETMCNTVR3()		MRC14(1, c0, c15, 5)
++#define RCP14_ETMSQ12EVR()		MRC14(1, c0, c0, 6)
++#define RCP14_ETMSQ21EVR()		MRC14(1, c0, c1, 6)
++#define RCP14_ETMSQ23EVR()		MRC14(1, c0, c2, 6)
++#define RCP14_ETMSQ31EVR()		MRC14(1, c0, c3, 6)
++#define RCP14_ETMSQ32EVR()		MRC14(1, c0, c4, 6)
++#define RCP14_ETMSQ13EVR()		MRC14(1, c0, c5, 6)
++#define RCP14_ETMSQR()			MRC14(1, c0, c7, 6)
++#define RCP14_ETMEXTOUTEVR0()		MRC14(1, c0, c8, 6)
++#define RCP14_ETMEXTOUTEVR1()		MRC14(1, c0, c9, 6)
++#define RCP14_ETMEXTOUTEVR2()		MRC14(1, c0, c10, 6)
++#define RCP14_ETMEXTOUTEVR3()		MRC14(1, c0, c11, 6)
++#define RCP14_ETMCIDCVR0()		MRC14(1, c0, c12, 6)
++#define RCP14_ETMCIDCVR1()		MRC14(1, c0, c13, 6)
++#define RCP14_ETMCIDCVR2()		MRC14(1, c0, c14, 6)
++#define RCP14_ETMCIDCMR()		MRC14(1, c0, c15, 6)
++#define RCP14_ETMIMPSPEC0()		MRC14(1, c0, c0, 7)
++#define RCP14_ETMIMPSPEC1()		MRC14(1, c0, c1, 7)
++#define RCP14_ETMIMPSPEC2()		MRC14(1, c0, c2, 7)
++#define RCP14_ETMIMPSPEC3()		MRC14(1, c0, c3, 7)
++#define RCP14_ETMIMPSPEC4()		MRC14(1, c0, c4, 7)
++#define RCP14_ETMIMPSPEC5()		MRC14(1, c0, c5, 7)
++#define RCP14_ETMIMPSPEC6()		MRC14(1, c0, c6, 7)
++#define RCP14_ETMIMPSPEC7()		MRC14(1, c0, c7, 7)
++#define RCP14_ETMSYNCFR()		MRC14(1, c0, c8, 7)
++#define RCP14_ETMIDR()			MRC14(1, c0, c9, 7)
++#define RCP14_ETMCCER()			MRC14(1, c0, c10, 7)
++#define RCP14_ETMEXTINSELR()		MRC14(1, c0, c11, 7)
++#define RCP14_ETMTESSEICR()		MRC14(1, c0, c12, 7)
++#define RCP14_ETMEIBCR()		MRC14(1, c0, c13, 7)
++#define RCP14_ETMTSEVR()		MRC14(1, c0, c14, 7)
++#define RCP14_ETMAUXCR()		MRC14(1, c0, c15, 7)
++#define RCP14_ETMTRACEIDR()		MRC14(1, c1, c0, 0)
++#define RCP14_ETMIDR2()			MRC14(1, c1, c2, 0)
++#define RCP14_ETMVMIDCVR()		MRC14(1, c1, c0, 1)
++#define RCP14_ETMOSLSR()		MRC14(1, c1, c1, 4)
++/* Not available in PFTv1.1 */
++#define RCP14_ETMOSSRR()		MRC14(1, c1, c2, 4)
++#define RCP14_ETMPDCR()			MRC14(1, c1, c4, 4)
++#define RCP14_ETMPDSR()			MRC14(1, c1, c5, 4)
++#define RCP14_ETMITCTRL()		MRC14(1, c7, c0, 4)
++#define RCP14_ETMCLAIMSET()		MRC14(1, c7, c8, 6)
++#define RCP14_ETMCLAIMCLR()		MRC14(1, c7, c9, 6)
++#define RCP14_ETMLSR()			MRC14(1, c7, c13, 6)
++#define RCP14_ETMAUTHSTATUS()		MRC14(1, c7, c14, 6)
++#define RCP14_ETMDEVID()		MRC14(1, c7, c2, 7)
++#define RCP14_ETMDEVTYPE()		MRC14(1, c7, c3, 7)
++#define RCP14_ETMPIDR4()		MRC14(1, c7, c4, 7)
++#define RCP14_ETMPIDR5()		MRC14(1, c7, c5, 7)
++#define RCP14_ETMPIDR6()		MRC14(1, c7, c6, 7)
++#define RCP14_ETMPIDR7()		MRC14(1, c7, c7, 7)
++#define RCP14_ETMPIDR0()		MRC14(1, c7, c8, 7)
++#define RCP14_ETMPIDR1()		MRC14(1, c7, c9, 7)
++#define RCP14_ETMPIDR2()		MRC14(1, c7, c10, 7)
++#define RCP14_ETMPIDR3()		MRC14(1, c7, c11, 7)
++#define RCP14_ETMCIDR0()		MRC14(1, c7, c12, 7)
++#define RCP14_ETMCIDR1()		MRC14(1, c7, c13, 7)
++#define RCP14_ETMCIDR2()		MRC14(1, c7, c14, 7)
++#define RCP14_ETMCIDR3()		MRC14(1, c7, c15, 7)
++
++#define WCP14_ETMCR(val)		MCR14(val, 1, c0, c0, 0)
++#define WCP14_ETMTRIGGER(val)		MCR14(val, 1, c0, c2, 0)
++#define WCP14_ETMASICCR(val)		MCR14(val, 1, c0, c3, 0)
++#define WCP14_ETMSR(val)		MCR14(val, 1, c0, c4, 0)
++#define WCP14_ETMTSSCR(val)		MCR14(val, 1, c0, c6, 0)
++#define WCP14_ETMTECR2(val)		MCR14(val, 1, c0, c7, 0)
++#define WCP14_ETMTEEVR(val)		MCR14(val, 1, c0, c8, 0)
++#define WCP14_ETMTECR1(val)		MCR14(val, 1, c0, c9, 0)
++#define WCP14_ETMFFRR(val)		MCR14(val, 1, c0, c10, 0)
++#define WCP14_ETMFFLR(val)		MCR14(val, 1, c0, c11, 0)
++#define WCP14_ETMVDEVR(val)		MCR14(val, 1, c0, c12, 0)
++#define WCP14_ETMVDCR1(val)		MCR14(val, 1, c0, c13, 0)
++#define WCP14_ETMVDCR2(val)		MCR14(val, 1, c0, c14, 0)
++#define WCP14_ETMVDCR3(val)		MCR14(val, 1, c0, c15, 0)
++#define WCP14_ETMACVR0(val)		MCR14(val, 1, c0, c0, 1)
++#define WCP14_ETMACVR1(val)		MCR14(val, 1, c0, c1, 1)
++#define WCP14_ETMACVR2(val)		MCR14(val, 1, c0, c2, 1)
++#define WCP14_ETMACVR3(val)		MCR14(val, 1, c0, c3, 1)
++#define WCP14_ETMACVR4(val)		MCR14(val, 1, c0, c4, 1)
++#define WCP14_ETMACVR5(val)		MCR14(val, 1, c0, c5, 1)
++#define WCP14_ETMACVR6(val)		MCR14(val, 1, c0, c6, 1)
++#define WCP14_ETMACVR7(val)		MCR14(val, 1, c0, c7, 1)
++#define WCP14_ETMACVR8(val)		MCR14(val, 1, c0, c8, 1)
++#define WCP14_ETMACVR9(val)		MCR14(val, 1, c0, c9, 1)
++#define WCP14_ETMACVR10(val)		MCR14(val, 1, c0, c10, 1)
++#define WCP14_ETMACVR11(val)		MCR14(val, 1, c0, c11, 1)
++#define WCP14_ETMACVR12(val)		MCR14(val, 1, c0, c12, 1)
++#define WCP14_ETMACVR13(val)		MCR14(val, 1, c0, c13, 1)
++#define WCP14_ETMACVR14(val)		MCR14(val, 1, c0, c14, 1)
++#define WCP14_ETMACVR15(val)		MCR14(val, 1, c0, c15, 1)
++#define WCP14_ETMACTR0(val)		MCR14(val, 1, c0, c0, 2)
++#define WCP14_ETMACTR1(val)		MCR14(val, 1, c0, c1, 2)
++#define WCP14_ETMACTR2(val)		MCR14(val, 1, c0, c2, 2)
++#define WCP14_ETMACTR3(val)		MCR14(val, 1, c0, c3, 2)
++#define WCP14_ETMACTR4(val)		MCR14(val, 1, c0, c4, 2)
++#define WCP14_ETMACTR5(val)		MCR14(val, 1, c0, c5, 2)
++#define WCP14_ETMACTR6(val)		MCR14(val, 1, c0, c6, 2)
++#define WCP14_ETMACTR7(val)		MCR14(val, 1, c0, c7, 2)
++#define WCP14_ETMACTR8(val)		MCR14(val, 1, c0, c8, 2)
++#define WCP14_ETMACTR9(val)		MCR14(val, 1, c0, c9, 2)
++#define WCP14_ETMACTR10(val)		MCR14(val, 1, c0, c10, 2)
++#define WCP14_ETMACTR11(val)		MCR14(val, 1, c0, c11, 2)
++#define WCP14_ETMACTR12(val)		MCR14(val, 1, c0, c12, 2)
++#define WCP14_ETMACTR13(val)		MCR14(val, 1, c0, c13, 2)
++#define WCP14_ETMACTR14(val)		MCR14(val, 1, c0, c14, 2)
++#define WCP14_ETMACTR15(val)		MCR14(val, 1, c0, c15, 2)
++#define WCP14_ETMDCVR0(val)		MCR14(val, 1, c0, c0, 3)
++#define WCP14_ETMDCVR2(val)		MCR14(val, 1, c0, c2, 3)
++#define WCP14_ETMDCVR4(val)		MCR14(val, 1, c0, c4, 3)
++#define WCP14_ETMDCVR6(val)		MCR14(val, 1, c0, c6, 3)
++#define WCP14_ETMDCVR8(val)		MCR14(val, 1, c0, c8, 3)
++#define WCP14_ETMDCVR10(val)		MCR14(val, 1, c0, c10, 3)
++#define WCP14_ETMDCVR12(val)		MCR14(val, 1, c0, c12, 3)
++#define WCP14_ETMDCVR14(val)		MCR14(val, 1, c0, c14, 3)
++#define WCP14_ETMDCMR0(val)		MCR14(val, 1, c0, c0, 4)
++#define WCP14_ETMDCMR2(val)		MCR14(val, 1, c0, c2, 4)
++#define WCP14_ETMDCMR4(val)		MCR14(val, 1, c0, c4, 4)
++#define WCP14_ETMDCMR6(val)		MCR14(val, 1, c0, c6, 4)
++#define WCP14_ETMDCMR8(val)		MCR14(val, 1, c0, c8, 4)
++#define WCP14_ETMDCMR10(val)		MCR14(val, 1, c0, c10, 4)
++#define WCP14_ETMDCMR12(val)		MCR14(val, 1, c0, c12, 4)
++#define WCP14_ETMDCMR14(val)		MCR14(val, 1, c0, c14, 4)
++#define WCP14_ETMCNTRLDVR0(val)		MCR14(val, 1, c0, c0, 5)
++#define WCP14_ETMCNTRLDVR1(val)		MCR14(val, 1, c0, c1, 5)
++#define WCP14_ETMCNTRLDVR2(val)		MCR14(val, 1, c0, c2, 5)
++#define WCP14_ETMCNTRLDVR3(val)		MCR14(val, 1, c0, c3, 5)
++#define WCP14_ETMCNTENR0(val)		MCR14(val, 1, c0, c4, 5)
++#define WCP14_ETMCNTENR1(val)		MCR14(val, 1, c0, c5, 5)
++#define WCP14_ETMCNTENR2(val)		MCR14(val, 1, c0, c6, 5)
++#define WCP14_ETMCNTENR3(val)		MCR14(val, 1, c0, c7, 5)
++#define WCP14_ETMCNTRLDEVR0(val)	MCR14(val, 1, c0, c8, 5)
++#define WCP14_ETMCNTRLDEVR1(val)	MCR14(val, 1, c0, c9, 5)
++#define WCP14_ETMCNTRLDEVR2(val)	MCR14(val, 1, c0, c10, 5)
++#define WCP14_ETMCNTRLDEVR3(val)	MCR14(val, 1, c0, c11, 5)
++#define WCP14_ETMCNTVR0(val)		MCR14(val, 1, c0, c12, 5)
++#define WCP14_ETMCNTVR1(val)		MCR14(val, 1, c0, c13, 5)
++#define WCP14_ETMCNTVR2(val)		MCR14(val, 1, c0, c14, 5)
++#define WCP14_ETMCNTVR3(val)		MCR14(val, 1, c0, c15, 5)
++#define WCP14_ETMSQ12EVR(val)		MCR14(val, 1, c0, c0, 6)
++#define WCP14_ETMSQ21EVR(val)		MCR14(val, 1, c0, c1, 6)
++#define WCP14_ETMSQ23EVR(val)		MCR14(val, 1, c0, c2, 6)
++#define WCP14_ETMSQ31EVR(val)		MCR14(val, 1, c0, c3, 6)
++#define WCP14_ETMSQ32EVR(val)		MCR14(val, 1, c0, c4, 6)
++#define WCP14_ETMSQ13EVR(val)		MCR14(val, 1, c0, c5, 6)
++#define WCP14_ETMSQR(val)		MCR14(val, 1, c0, c7, 6)
++#define WCP14_ETMEXTOUTEVR0(val)	MCR14(val, 1, c0, c8, 6)
++#define WCP14_ETMEXTOUTEVR1(val)	MCR14(val, 1, c0, c9, 6)
++#define WCP14_ETMEXTOUTEVR2(val)	MCR14(val, 1, c0, c10, 6)
++#define WCP14_ETMEXTOUTEVR3(val)	MCR14(val, 1, c0, c11, 6)
++#define WCP14_ETMCIDCVR0(val)		MCR14(val, 1, c0, c12, 6)
++#define WCP14_ETMCIDCVR1(val)		MCR14(val, 1, c0, c13, 6)
++#define WCP14_ETMCIDCVR2(val)		MCR14(val, 1, c0, c14, 6)
++#define WCP14_ETMCIDCMR(val)		MCR14(val, 1, c0, c15, 6)
++#define WCP14_ETMIMPSPEC0(val)		MCR14(val, 1, c0, c0, 7)
++#define WCP14_ETMIMPSPEC1(val)		MCR14(val, 1, c0, c1, 7)
++#define WCP14_ETMIMPSPEC2(val)		MCR14(val, 1, c0, c2, 7)
++#define WCP14_ETMIMPSPEC3(val)		MCR14(val, 1, c0, c3, 7)
++#define WCP14_ETMIMPSPEC4(val)		MCR14(val, 1, c0, c4, 7)
++#define WCP14_ETMIMPSPEC5(val)		MCR14(val, 1, c0, c5, 7)
++#define WCP14_ETMIMPSPEC6(val)		MCR14(val, 1, c0, c6, 7)
++#define WCP14_ETMIMPSPEC7(val)		MCR14(val, 1, c0, c7, 7)
++/* Can be read only in ETMv3.4, ETMv3.5 */
++#define WCP14_ETMSYNCFR(val)		MCR14(val, 1, c0, c8, 7)
++#define WCP14_ETMEXTINSELR(val)		MCR14(val, 1, c0, c11, 7)
++#define WCP14_ETMTESSEICR(val)		MCR14(val, 1, c0, c12, 7)
++#define WCP14_ETMEIBCR(val)		MCR14(val, 1, c0, c13, 7)
++#define WCP14_ETMTSEVR(val)		MCR14(val, 1, c0, c14, 7)
++#define WCP14_ETMAUXCR(val)		MCR14(val, 1, c0, c15, 7)
++#define WCP14_ETMTRACEIDR(val)		MCR14(val, 1, c1, c0, 0)
++#define WCP14_ETMIDR2(val)		MCR14(val, 1, c1, c2, 0)
++#define WCP14_ETMVMIDCVR(val)		MCR14(val, 1, c1, c0, 1)
++#define WCP14_ETMOSLAR(val)		MCR14(val, 1, c1, c0, 4)
++/* Not available in PFTv1.1 */
++#define WCP14_ETMOSSRR(val)		MCR14(val, 1, c1, c2, 4)
++#define WCP14_ETMPDCR(val)		MCR14(val, 1, c1, c4, 4)
++#define WCP14_ETMPDSR(val)		MCR14(val, 1, c1, c5, 4)
++#define WCP14_ETMITCTRL(val)		MCR14(val, 1, c7, c0, 4)
++#define WCP14_ETMCLAIMSET(val)		MCR14(val, 1, c7, c8, 6)
++#define WCP14_ETMCLAIMCLR(val)		MCR14(val, 1, c7, c9, 6)
++/* Writes to this from CP14 interface are ignored */
++#define WCP14_ETMLAR(val)		MCR14(val, 1, c7, c12, 6)
++
++#endif
+diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h
+index 1805674..630a208 100644
+--- a/arch/arm/include/asm/io.h
++++ b/arch/arm/include/asm/io.h
+@@ -29,6 +29,7 @@
+ #include <asm/memory.h>
+ #include <asm-generic/pci_iomap.h>
+ #include <xen/xen.h>
++#include <linux/printk.h>
+ 
+ /*
+  * ISA I/O bus memory addresses are 1:1 with the physical address.
+@@ -37,6 +38,10 @@
+ #define isa_page_to_bus page_to_phys
+ #define isa_bus_to_virt phys_to_virt
+ 
++#include <linux/spinlock_types.h>
++#include <linux/spinlock.h>
++extern raw_spinlock_t hisilcon_lock;
++
+ /*
+  * Atomic MMIO-wide IO modify
+  */
+@@ -63,6 +68,10 @@ extern void __raw_readsl(const void __iomem *addr, void *data, int longlen);
+  */
+ #define __raw_readw(a)         (__chk_io_ptr(a), *(volatile unsigned short __force *)(a))
+ #define __raw_writew(v,a)      ((void)(__chk_io_ptr(a), *(volatile unsigned short __force *)(a) = (v)))
++
++#define __hi_raw_readw(a)	__raw_readw(a)
++#define __hi_raw_writew(v,a)	__raw_writew(v,a)
++
+ #else
+ /*
+  * When running under a hypervisor, we want to avoid I/O accesses with
+@@ -76,6 +85,23 @@ static inline void __raw_writew(u16 val, volatile void __iomem *addr)
+ 		     : "r" (val));
+ }
+ 
++static inline void __hi_raw_writew(u16 val, volatile void __iomem *addr)
++{
++#if (defined CONFIG_ARCH_HI3519 || defined CONFIG_ARCH_HI3519V101)
++        unsigned long flags;
++        raw_spin_lock_irqsave(&hisilcon_lock, flags);
++        dsb();
++        isb();
++#endif
++        asm volatile("strh %1, %0"
++                     : "+Q" (*(volatile u16 __force *)addr)
++                     : "r" (val));
++#if (defined CONFIG_ARCH_HI3519 || defined CONFIG_ARCH_HI3519V101)
++        dsb();
++        isb();
++        raw_spin_unlock_irqrestore(&hisilcon_lock, flags);
++#endif
++}
+ static inline u16 __raw_readw(const volatile void __iomem *addr)
+ {
+ 	u16 val;
+@@ -84,6 +110,27 @@ static inline u16 __raw_readw(const volatile void __iomem *addr)
+ 		       "=r" (val));
+ 	return val;
+ }
++
++static inline u16 __hi_raw_readw(const volatile void __iomem *addr)
++{
++        u16 val;
++#if (defined CONFIG_ARCH_HI3519 || defined CONFIG_ARCH_HI3519V101)
++        unsigned long flags;
++        raw_spin_lock_irqsave(&hisilcon_lock, flags);
++        dsb();
++        isb();
++#endif
++        asm volatile("ldrh %1, %0"
++                     : "+Q" (*(volatile u16 __force *)addr),
++                       "=r" (val));
++#if (defined CONFIG_ARCH_HI3519 || defined CONFIG_ARCH_HI3519V101)
++        dsb();
++        isb();
++        raw_spin_unlock_irqrestore(&hisilcon_lock, flags);
++#endif
++        return val;
++}
++
+ #endif
+ 
+ static inline void __raw_writeb(u8 val, volatile void __iomem *addr)
+@@ -93,6 +140,24 @@ static inline void __raw_writeb(u8 val, volatile void __iomem *addr)
+ 		     : "r" (val));
+ }
+ 
++static inline void __hi_raw_writeb(u8 val, volatile void __iomem *addr)
++{
++#if (defined CONFIG_ARCH_HI3519 || defined CONFIG_ARCH_HI3519V101)
++        unsigned long flags;
++        raw_spin_lock_irqsave(&hisilcon_lock, flags);
++        dsb();
++        isb();
++#endif
++        asm volatile("strb %1, %0"
++                     : "+Qo" (*(volatile u8 __force *)addr)
++                     : "r" (val));
++#if (defined CONFIG_ARCH_HI3519 || defined CONFIG_ARCH_HI3519V101)
++        dsb();
++        isb();
++        raw_spin_unlock_irqrestore(&hisilcon_lock, flags);
++#endif
++}
++
+ static inline void __raw_writel(u32 val, volatile void __iomem *addr)
+ {
+ 	asm volatile("str %1, %0"
+@@ -100,6 +165,24 @@ static inline void __raw_writel(u32 val, volatile void __iomem *addr)
+ 		     : "r" (val));
+ }
+ 
++static inline void __hi_raw_writel(u32 val, volatile void __iomem *addr)
++{
++#if (defined CONFIG_ARCH_HI3519 || defined CONFIG_ARCH_HI3519V101)
++        unsigned long flags;
++        raw_spin_lock_irqsave(&hisilcon_lock, flags);
++        dsb();
++        isb();
++#endif
++        asm volatile("str %1, %0"
++                     : "+Qo" (*(volatile u32 __force *)addr)
++                     : "r" (val));
++#if (defined CONFIG_ARCH_HI3519 || defined CONFIG_ARCH_HI3519V101)
++        dsb();
++        isb();
++        raw_spin_unlock_irqrestore(&hisilcon_lock, flags);
++#endif
++}
++
+ static inline u8 __raw_readb(const volatile void __iomem *addr)
+ {
+ 	u8 val;
+@@ -109,6 +192,26 @@ static inline u8 __raw_readb(const volatile void __iomem *addr)
+ 	return val;
+ }
+ 
++static inline u8 __hi_raw_readb(const volatile void __iomem *addr)
++{
++        u8 val;
++#if (defined CONFIG_ARCH_HI3519 || defined CONFIG_ARCH_HI3519V101)
++        unsigned long flags;
++        raw_spin_lock_irqsave(&hisilcon_lock, flags);
++        dsb();
++        isb();
++#endif
++        asm volatile("ldrb %1, %0"
++                     : "+Qo" (*(volatile u8 __force *)addr),
++                       "=r" (val));
++#if (defined CONFIG_ARCH_HI3519 || defined CONFIG_ARCH_HI3519V101)
++        dsb();
++        isb();
++        raw_spin_unlock_irqrestore(&hisilcon_lock, flags);
++#endif
++        return val;
++}
++
+ static inline u32 __raw_readl(const volatile void __iomem *addr)
+ {
+ 	u32 val;
+@@ -118,6 +221,26 @@ static inline u32 __raw_readl(const volatile void __iomem *addr)
+ 	return val;
+ }
+ 
++static inline u32 __hi_raw_readl(const volatile void __iomem *addr)
++{
++        u32 val;
++#if (defined CONFIG_ARCH_HI3519 || defined CONFIG_ARCH_HI3519V101)
++        unsigned long flags;
++        raw_spin_lock_irqsave(&hisilcon_lock, flags);
++        dsb();
++        isb();
++#endif
++        asm volatile("ldr %1, %0"
++                     : "+Qo" (*(volatile u32 __force *)addr),
++                       "=r" (val));
++#if (defined CONFIG_ARCH_HI3519 || defined CONFIG_ARCH_HI3519V101)
++        dsb();
++        isb();
++        raw_spin_unlock_irqrestore(&hisilcon_lock, flags);
++#endif
++        return val;
++}
++
+ /*
+  * Architecture ioremap implementation.
+  */
+@@ -307,18 +430,36 @@ extern void _memset_io(volatile void __iomem *, int, size_t);
+ #define readl_relaxed(c) ({ u32 __r = le32_to_cpu((__force __le32) \
+ 					__raw_readl(c)); __r; })
+ 
++#define hi_readb_relaxed(c) ({ u8  __r = __hi_raw_readb(c); __r; })
++#define hi_readw_relaxed(c) ({ u16 __r = le16_to_cpu((__force __le16) \
++					__hi_raw_readw(c)); __r; })
++#define hi_readl_relaxed(c) ({ u32 __r = le32_to_cpu((__force __le32) \
++					__hi_raw_readl(c)); __r; })
++
+ #define writeb_relaxed(v,c)	__raw_writeb(v,c)
+ #define writew_relaxed(v,c)	__raw_writew((__force u16) cpu_to_le16(v),c)
+ #define writel_relaxed(v,c)	__raw_writel((__force u32) cpu_to_le32(v),c)
+ 
++#define hi_writeb_relaxed(v,c)	__hi_raw_writeb(v,c)
++#define hi_writew_relaxed(v,c)	__hi_raw_writew((__force u16) cpu_to_le16(v),c)
++#define hi_writel_relaxed(v,c)	__hi_raw_writel((__force u32) cpu_to_le32(v),c)
++
+ #define readb(c)		({ u8  __v = readb_relaxed(c); __iormb(); __v; })
+ #define readw(c)		({ u16 __v = readw_relaxed(c); __iormb(); __v; })
+ #define readl(c)		({ u32 __v = readl_relaxed(c); __iormb(); __v; })
+ 
++#define hi_readb(c)		({ u8  __v = hi_readb_relaxed(c); __iormb(); __v; })
++#define hi_readw(c)		({ u16 __v = hi_readw_relaxed(c); __iormb(); __v; })
++#define hi_readl(c)		({ u32 __v = hi_readl_relaxed(c); __iormb(); __v; })
++
+ #define writeb(v,c)		({ __iowmb(); writeb_relaxed(v,c); })
+ #define writew(v,c)		({ __iowmb(); writew_relaxed(v,c); })
+ #define writel(v,c)		({ __iowmb(); writel_relaxed(v,c); })
+ 
++#define hi_writeb(v,c)		({ __iowmb(); hi_writeb_relaxed(v,c); })
++#define hi_writew(v,c)		({ __iowmb(); hi_writew_relaxed(v,c); })
++#define hi_writel(v,c)		({ __iowmb(); hi_writel_relaxed(v,c); })
++
+ #define readsb(p,d,l)		__raw_readsb(p,d,l)
+ #define readsw(p,d,l)		__raw_readsw(p,d,l)
+ #define readsl(p,d,l)		__raw_readsl(p,d,l)
+diff --git a/arch/arm/include/asm/irq.h b/arch/arm/include/asm/irq.h
+index 53c15de..809203a 100644
+--- a/arch/arm/include/asm/irq.h
++++ b/arch/arm/include/asm/irq.h
+@@ -35,6 +35,9 @@ extern void (*handle_arch_irq)(struct pt_regs *);
+ extern void set_handle_irq(void (*handle_irq)(struct pt_regs *));
+ #endif
+ 
++void arch_trigger_all_cpu_backtrace(void);
++#define arch_trigger_all_cpu_backtrace arch_trigger_all_cpu_backtrace
++
+ #endif
+ 
+ #endif
+diff --git a/arch/arm/include/asm/mach/mmc.h b/arch/arm/include/asm/mach/mmc.h
+new file mode 100644
+index 0000000..bca864a
+--- /dev/null
++++ b/arch/arm/include/asm/mach/mmc.h
+@@ -0,0 +1,28 @@
++/*
++ *  arch/arm/include/asm/mach/mmc.h
++ */
++#ifndef ASMARM_MACH_MMC_H
++#define ASMARM_MACH_MMC_H
++
++#include <linux/mmc/host.h>
++#include <linux/mmc/card.h>
++#include <linux/mmc/sdio_func.h>
++
++struct embedded_sdio_data {
++        struct sdio_cis cis;
++        struct sdio_cccr cccr;
++        struct sdio_embedded_func *funcs;
++        int num_funcs;
++};
++
++struct mmc_platform_data {
++	unsigned int ocr_mask;			/* available voltages */
++	int built_in;				/* built-in device flag */
++	int card_present;			/* card detect state */
++	u32 (*translate_vdd)(struct device *, unsigned int);
++	unsigned int (*status)(struct device *);
++	struct embedded_sdio_data *embedded_sdio;
++	int (*register_status_notify)(void (*callback)(int card_present, void *dev_id), void *dev_id);
++};
++
++#endif
+diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h
+index e731018..c1668d1 100644
+--- a/arch/arm/include/asm/memory.h
++++ b/arch/arm/include/asm/memory.h
+@@ -289,6 +289,9 @@ static inline void *phys_to_virt(phys_addr_t x)
+  */
+ #define __pa(x)			__virt_to_phys((unsigned long)(x))
+ #define __va(x)			((void *)__phys_to_virt((phys_addr_t)(x)))
++#ifdef	CONFIG_HISI_SNAPSHOT_BOOT
++#define __pa_symbol(x)      __pa(RELOC_HIDE((unsigned long)(x), 0))
++#endif
+ #define pfn_to_kaddr(pfn)	__va((pfn) << PAGE_SHIFT)
+ 
+ extern phys_addr_t (*arch_virt_to_idmap)(unsigned long x);
+diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h
+index 18f5a55..7f31b4f 100644
+--- a/arch/arm/include/asm/smp.h
++++ b/arch/arm/include/asm/smp.h
+@@ -81,6 +81,8 @@ extern void arch_send_wakeup_ipi_mask(const struct cpumask *mask);
+ 
+ extern int register_ipi_completion(struct completion *completion, int cpu);
+ 
++extern void smp_send_all_cpu_backtrace(void);
++
+ struct smp_operations {
+ #ifdef CONFIG_SMP
+ 	/*
+diff --git a/arch/arm/include/asm/topology.h b/arch/arm/include/asm/topology.h
+index 2fe85ff..d71d002 100644
+--- a/arch/arm/include/asm/topology.h
++++ b/arch/arm/include/asm/topology.h
+@@ -23,11 +23,45 @@ extern struct cputopo_arm cpu_topology[NR_CPUS];
+ void init_cpu_topology(void);
+ void store_cpu_topology(unsigned int cpuid);
+ const struct cpumask *cpu_coregroup_mask(int cpu);
++int cluster_to_logical_mask(unsigned int socket_id, cpumask_t *cluster_mask);
++
++#ifdef CONFIG_DISABLE_CPU_SCHED_DOMAIN_BALANCE
++/* Common values for CPUs */
++#ifndef SD_CPU_INIT
++#define SD_CPU_INIT (struct sched_domain) {				\
++	.min_interval		= 1,					\
++	.max_interval		= 4,					\
++	.busy_factor		= 64,					\
++	.imbalance_pct		= 125,					\
++	.cache_nice_tries	= 1,					\
++	.busy_idx		= 2,					\
++	.idle_idx		= 1,					\
++	.newidle_idx		= 0,					\
++	.wake_idx		= 0,					\
++	.forkexec_idx		= 0,					\
++									\
++	.flags			= 0*SD_LOAD_BALANCE			\
++				| 1*SD_BALANCE_NEWIDLE			\
++				| 1*SD_BALANCE_EXEC			\
++				| 1*SD_BALANCE_FORK			\
++				| 0*SD_BALANCE_WAKE			\
++				| 1*SD_WAKE_AFFINE			\
++				| 0*SD_SHARE_CPUPOWER			\
++				| 0*SD_SHARE_PKG_RESOURCES		\
++				| 0*SD_SERIALIZE			\
++				,					\
++	.last_balance		 = jiffies,				\
++	.balance_interval	= 1,					\
++}
++#endif
++#endif /* CONFIG_DISABLE_CPU_SCHED_DOMAIN_BALANCE */
+ 
+ #else
+ 
+ static inline void init_cpu_topology(void) { }
+ static inline void store_cpu_topology(unsigned int cpuid) { }
++static inline int cluster_to_logical_mask(unsigned int socket_id,
++	cpumask_t *cluster_mask) { return -EINVAL; }
+ 
+ #endif
+ 
+diff --git a/arch/arm/include/mach/hi3516av200_io.h b/arch/arm/include/mach/hi3516av200_io.h
+new file mode 100644
+index 0000000..eb992fe
+--- /dev/null
++++ b/arch/arm/include/mach/hi3516av200_io.h
+@@ -0,0 +1,46 @@
++#ifndef __HI3516AV200_IO_H
++#define __HI3516AV200_IO_H
++
++#ifdef CONFIG_PCI
++#define IO_SPACE_LIMIT  0xffffffff
++#define __io(a)         __typesafe_io(PCI_IO_VIRT_BASE + ((a) & IO_SPACE_LIMIT))
++#endif
++
++/*  phys_addr		virt_addr
++ * 0x1000_0000 <-----> 0xFE00_0000
++ */
++#define HI3516AV200_IOCH1_VIRT (0xFE000000)
++#define HI3516AV200_IOCH1_PHYS (0x10000000)
++#define HI3516AV200_IOCH1_SIZE (0x00310000)
++
++/*  phys_addr		virt_addr
++ * 0x11000000 <-----> 0xFE400000
++ */
++#define HI3516AV200_IOCH2_VIRT (0xFE400000)
++#define HI3516AV200_IOCH2_PHYS (0x11000000)
++#define HI3516AV200_IOCH2_SIZE (0x004F0000)
++
++/*  phys_addr		virt_addr
++ * 0x12000000 <-----> 0xFE900000
++ */
++#define HI3516AV200_IOCH3_VIRT (0xFE900000)
++#define HI3516AV200_IOCH3_PHYS (0x12000000)
++#define HI3516AV200_IOCH3_SIZE (0x00170000)
++
++
++#define IO_OFFSET_LOW   (0xEC900000)
++#define IO_OFFSET_MID   (0xED400000)
++#define IO_OFFSET_HIGH  (0xEE000000)
++
++#define IO_ADDRESS_LOW(x)  ((x) + IO_OFFSET_LOW)
++#define IO_ADDRESS_MID(x)  ((x) + IO_OFFSET_MID)
++#define IO_ADDRESS_HIGH(x) ((x) + IO_OFFSET_HIGH)
++
++#define __IO_ADDRESS(x) ((x >= HI3516AV200_IOCH2_PHYS) ? IO_ADDRESS_MID(x)\
++		: IO_ADDRESS_HIGH(x))
++#define IO_ADDRESS(x)   ((x) >= HI3516AV200_IOCH3_PHYS ? IO_ADDRESS_LOW(x)\
++		: __IO_ADDRESS(x))
++
++#define __io_address(n) (IOMEM(IO_ADDRESS(n)))
++
++#endif
+diff --git a/arch/arm/include/mach/hi3516av200_platform.h b/arch/arm/include/mach/hi3516av200_platform.h
+new file mode 100644
+index 0000000..a7aaa25
+--- /dev/null
++++ b/arch/arm/include/mach/hi3516av200_platform.h
+@@ -0,0 +1,164 @@
++#ifndef __HI3516AV200_CHIP_REGS_H__
++#define __HI3516AV200_CHIP_REGS_H__
++
++/* SRAM Base Address Register */
++#define SRAM_BASE_ADDRESS                               0x4010000
++
++#define REG_BASE_TIMER01                                0x12000000
++#define REG_BASE_TIMER23                                0x12001000
++
++/* -------------------------------------------------------------------- */
++/* Clock and Reset Generator REG */
++/* -------------------------------------------------------------------- */
++#define CRG_REG_BASE			0x12010000
++#define REG_BASE_CRG			CRG_REG_BASE
++
++#define REG_CRG48			0x00c0
++
++/* FMC CRG register offset */
++#define REG_FMC_CRG			REG_CRG48
++#define FMC_CLK_SEL(_clk)		(((_clk) & 0x7) << 2)
++#define FMC_CLK_SEL_MASK		(0x7 << 2)
++#define GET_FMC_CLK_TYPE(_reg)		(((_reg) >> 2) & 0x7)
++/* SDR/DDR clock */
++#define FMC_CLK_24M			0
++#define FMC_CLK_75M			1
++#define FMC_CLK_125M			2
++#define FMC_CLK_150M			3
++#define FMC_CLK_200M			4
++#define FMC_CLK_250M			5
++/* Only DDR clock */
++#define FMC_CLK_300M			6
++#define FMC_CLK_400M			7
++#define FMC_CLK_ENABLE			(0x1 << 1)
++#define FMC_SOFT_RST_REQ		(0x1 << 0)
++
++#define REG_BASE_UART0                                  0x12100000
++#define REG_BASE_UART1                                  0x12101000
++#define REG_BASE_UART2                                  0x12102000
++#define REG_BASE_UART3                                  0x12103000
++#define REG_BASE_UART4                                  0x12104000
++#define REG_BASE_CUR_UART                               REG_BASE_UART0
++
++#define PMC_BASE					0x120a0000
++
++#define CCI_BASE					0x1ff00000
++#define CCI_PORT0_BASE				        0x1ff01000
++#define CCI_PORT1_BASE				        0x1ff02000
++
++
++#define REG_BASE_A7_PERI                               0x10300000
++
++/*CORTTX-A7 MPCORE MEMORY REGION*/
++#define REG_A7_PERI_SCU                                 0x0000
++#define REG_A7_PERI_GIC_CPU                             0x2000
++#define REG_A7_PERI_GLOBAL_TIMER                        0x0200
++#define REG_A7_PERI_PRI_TIMER_WDT                       0x0600
++#define REG_A7_PERI_GIC_DIST                            0x1000
++/* -------------------------------------------------------------------- */
++/* System Control REG */
++/* -------------------------------------------------------------------- */
++#define SYS_CTRL_BASE                                    0x12020000
++
++/* System Control register offset */
++#define REG_SC_CTRL			0x0000
++
++/* System soft reset register offset */
++#define REG_SC_SYSRES			0x0004
++
++/* System Status register offset */
++#define REG_SC_STAT			0x008c
++
++/* if bit[5:4]=00b: boot form SPI && bit[3]=0: SPI nor flash
++ * bit[7]=0: 3-Byte address mode; bit[7]=1: 4-Byte address mode */
++#define GET_SPI_NOR_ADDR_MODE(_reg)	(((_reg) >> 7) & 0x1)
++#define GET_SYS_BOOT_MODE(_reg)		(((_reg) >> 4) & 0x3)
++#define BOOT_MODE_MASK				((0x3) << 4)
++#define BOOT_FROM_SPI			0
++#define BOOT_FROM_NAND			1
++#define BOOT_FROM_EMMC			2
++#define BOOT_FROM_DDR			3
++/* bit[3]=0; SPI nor flash; bit[3]=1: SPI nand flash */
++#define GET_SPI_DEVICE_TYPE(_reg)	(((_reg) >> 3) & 0x1)
++
++#define REG_SC_XTALCTRL                                 0x0010
++#define REG_SC_APLLCTRL                                 0x0014
++#define REG_SC_APLLFREQCTRL0                            0x0018
++#define REG_SC_APLLFREQCTRL1                            0x001C
++#define REG_SC_VPLL0FREQCTRL0                           0x0020
++#define REG_SC_VPLL0FREQCTRL1                           0x0024
++#define REG_SC_VPLL1FREQCTRL0                           0x0028
++#define REG_SC_VPLL1FREQCTRL1                           0x002C
++#define REG_SC_EPLLFREQCTRL0                            0x0030
++#define REG_SC_EPLLFREQCTRL1                            0x0034
++#define REG_SC_QPLLFREQCTRL0                            0x0038
++#define REG_SC_QPLLFREQCTRL1                            0x003C
++#define REG_SC_LOW_POWER_CTRL                           0x0040
++#define REG_SC_IO_REUSE_SEL                             0x0044
++#define REG_SC_SRST_REQ_CTRL                            0x0048
++#define REG_SC_CA_RST_CTRL                              0x004C
++#define REG_SC_WDG_RST_CTRL                             0x0050
++#define REG_SC_DDRC_DFI_RST_CTRL                        0x0054
++#define REG_SC_PLLLOCK_STAT                             0x0070
++#define REG_SC_GEN0                                     0x0080
++#define REG_SC_GEN1                                     0x0084
++#define REG_SC_GEN2                                     0x0088
++#define REG_SC_GEN3                                     0x008C
++#define REG_SC_GEN4                                     0x0090
++#define REG_SC_GEN5                                     0x0094
++#define REG_SC_GEN6                                     0x0098
++#define REG_SC_GEN7                                     0x009C
++#define REG_SC_GEN8                                     0x00A0
++#define REG_SC_GEN9                                     0x00A4
++#define REG_SC_GEN10                                    0x00A8
++#define REG_SC_GEN11                                    0x00AC
++#define REG_SC_GEN12                                    0x00B0
++#define REG_SC_GEN13                                    0x00B4
++#define REG_SC_GEN14                                    0x00B8
++#define REG_SC_GEN15                                    0x00BC
++#define REG_SC_GEN16                                    0x00C0
++#define REG_SC_GEN17                                    0x00C4
++#define REG_SC_GEN18                                    0x00C8
++#define REG_SC_GEN19                                    0x00CC
++#define REG_SC_GEN20                                    0x00D0
++#define REG_SC_GEN21                                    0x00D4
++#define REG_SC_GEN22                                    0x00D8
++#define REG_SC_GEN23                                    0x00DC
++#define REG_SC_GEN24                                    0x00E0
++#define REG_SC_GEN25                                    0x00E4
++#define REG_SC_GEN26                                    0x00E8
++#define REG_SC_GEN27                                    0x00EC
++#define REG_SC_GEN28                                    0x00F0
++#define REG_SC_GEN29                                    0x00F4
++#define REG_SC_GEN30                                    0x00F8
++#define REG_SC_GEN31                                    0x00FC
++#define REG_SC_LOCKEN                                   0x020C
++#define REG_SC_SYSID0                                   0x0EE0
++#define REG_SC_SYSID1                                   0x0EE4
++#define REG_SC_SYSID2                                   0x0EE8
++#define REG_SC_SYSID3                                   0x0EEC
++
++/*#define REG_BASE_WDG0                                   0xF8A2C000  */
++
++#define REG_PERI_CRG94                                  0x178
++#define REG_PERI_CRG10                                  0x0028
++#define REG_PERI_CRG98					0x0188
++
++#define CFG_GIC_CPU_BASE    (IO_ADDRESS(REG_BASE_A7_PERI)\
++				+ REG_A7_PERI_GIC_CPU)
++#define CFG_GIC_DIST_BASE   (IO_ADDRESS(REG_BASE_A7_PERI)\
++				+ REG_A7_PERI_GIC_DIST)
++
++
++/*********************************************************************/
++/*
++ * 0x1-> init item1
++ * 0x2-> init item2
++ * 0x3->init item1 & item2
++ */
++#define INIT_REG_ITEM1               1
++#define INIT_REG_ITEM2               2
++#define INIT_REG_ITEM1_ITEM2         (INIT_REG_ITEM1 | INIT_REG_ITEM2)
++
++
++#endif /* End of __HI_CHIP_REGS_H__ */
+diff --git a/arch/arm/include/mach/hi3519_io.h b/arch/arm/include/mach/hi3519_io.h
+new file mode 100644
+index 0000000..108d401
+--- /dev/null
++++ b/arch/arm/include/mach/hi3519_io.h
+@@ -0,0 +1,46 @@
++#ifndef __HI3519_IO_H
++#define __HI3519_IO_H
++
++#ifdef CONFIG_PCI
++#define IO_SPACE_LIMIT  0xffffffff
++#define __io(a)         __typesafe_io(PCI_IO_VIRT_BASE + ((a) & IO_SPACE_LIMIT))
++#endif
++
++/*  phys_addr		virt_addr
++ * 0x1000_0000 <-----> 0xFE00_0000
++ */
++#define HI3519_IOCH1_VIRT (0xFE000000)
++#define HI3519_IOCH1_PHYS (0x10000000)
++#define HI3519_IOCH1_SIZE (0x00310000)
++
++/*  phys_addr		virt_addr
++ * 0x11000000 <-----> 0xFE400000
++ */
++#define HI3519_IOCH2_VIRT (0xFE400000)
++#define HI3519_IOCH2_PHYS (0x11000000)
++#define HI3519_IOCH2_SIZE (0x003F0000)
++
++/*  phys_addr		virt_addr
++ * 0x12000000 <-----> 0xFE800000
++ */
++#define HI3519_IOCH3_VIRT (0xFE800000)
++#define HI3519_IOCH3_PHYS (0x12000000)
++#define HI3519_IOCH3_SIZE (0x00170000)
++
++
++#define IO_OFFSET_LOW   (0xEC800000)
++#define IO_OFFSET_MID   (0xED400000)
++#define IO_OFFSET_HIGH  (0xEE000000)
++
++#define IO_ADDRESS_LOW(x)  ((x) + IO_OFFSET_LOW)
++#define IO_ADDRESS_MID(x)  ((x) + IO_OFFSET_MID)
++#define IO_ADDRESS_HIGH(x) ((x) + IO_OFFSET_HIGH)
++
++#define __IO_ADDRESS(x) ((x >= HI3519_IOCH2_PHYS) ? IO_ADDRESS_MID(x)\
++		: IO_ADDRESS_HIGH(x))
++#define IO_ADDRESS(x)   ((x) >= HI3519_IOCH3_PHYS ? IO_ADDRESS_LOW(x)\
++		: __IO_ADDRESS(x))
++
++#define __io_address(n) (IOMEM(IO_ADDRESS(n)))
++
++#endif
+diff --git a/arch/arm/include/mach/hi3519_platform.h b/arch/arm/include/mach/hi3519_platform.h
+new file mode 100644
+index 0000000..b845f33
+--- /dev/null
++++ b/arch/arm/include/mach/hi3519_platform.h
+@@ -0,0 +1,164 @@
++#ifndef __HI3519_CHIP_REGS_H__
++#define __HI3519_CHIP_REGS_H__
++
++/* SRAM Base Address Register */
++#define SRAM_BASE_ADDRESS                               0x4010000
++
++#define REG_BASE_TIMER01                                0x12000000
++#define REG_BASE_TIMER23                                0x12001000
++
++/* -------------------------------------------------------------------- */
++/* Clock and Reset Generator REG */
++/* -------------------------------------------------------------------- */
++#define CRG_REG_BASE			0x12010000
++#define REG_BASE_CRG			CRG_REG_BASE
++
++#define REG_CRG48			0x00c0
++
++/* FMC CRG register offset */
++#define REG_FMC_CRG			REG_CRG48
++#define FMC_CLK_SEL(_clk)		(((_clk) & 0x7) << 2)
++#define FMC_CLK_SEL_MASK		(0x7 << 2)
++#define GET_FMC_CLK_TYPE(_reg)		(((_reg) >> 2) & 0x7)
++/* SDR/DDR clock */
++#define FMC_CLK_24M			0
++#define FMC_CLK_75M			1
++#define FMC_CLK_125M			2
++#define FMC_CLK_150M			3
++#define FMC_CLK_200M			4
++#define FMC_CLK_250M			5
++/* Only DDR clock */
++#define FMC_CLK_300M			6
++#define FMC_CLK_400M			7
++#define FMC_CLK_ENABLE			(0x1 << 1)
++#define FMC_SOFT_RST_REQ		(0x1 << 0)
++
++#define REG_BASE_UART0                                  0x12100000
++#define REG_BASE_UART1                                  0x12101000
++#define REG_BASE_UART2                                  0x12102000
++#define REG_BASE_UART3                                  0x12103000
++#define REG_BASE_UART4                                  0x12104000
++#define REG_BASE_CUR_UART                               REG_BASE_UART0
++
++#define PMC_BASE					0x120a0000
++
++#define CCI_BASE					0x1ff00000
++#define CCI_PORT0_BASE				        0x1ff01000
++#define CCI_PORT1_BASE				        0x1ff02000
++
++
++#define REG_BASE_A7_PERI                               0x10300000
++
++/*CORTTX-A7 MPCORE MEMORY REGION*/
++#define REG_A7_PERI_SCU                                 0x0000
++#define REG_A7_PERI_GIC_CPU                             0x2000
++#define REG_A7_PERI_GLOBAL_TIMER                        0x0200
++#define REG_A7_PERI_PRI_TIMER_WDT                       0x0600
++#define REG_A7_PERI_GIC_DIST                            0x1000
++/* -------------------------------------------------------------------- */
++/* System Control REG */
++/* -------------------------------------------------------------------- */
++#define SYS_CTRL_BASE                                    0x12020000
++
++/* System Control register offset */
++#define REG_SC_CTRL			0x0000
++
++/* System soft reset register offset */
++#define REG_SC_SYSRES			0x0004
++
++/* System Status register offset */
++#define REG_SC_STAT			0x008c
++
++/* if bit[5:4]=00b: boot form SPI && bit[3]=0: SPI nor flash
++ * bit[7]=0: 3-Byte address mode; bit[7]=1: 4-Byte address mode */
++#define GET_SPI_NOR_ADDR_MODE(_reg)	(((_reg) >> 7) & 0x1)
++#define GET_SYS_BOOT_MODE(_reg)		(((_reg) >> 4) & 0x3)
++#define BOOT_MODE_MASK				((0x3) << 4)
++#define BOOT_FROM_SPI			0
++#define BOOT_FROM_NAND			1
++#define BOOT_FROM_EMMC			2
++#define BOOT_FROM_DDR			3
++/* bit[3]=0; SPI nor flash; bit[3]=1: SPI nand flash */
++#define GET_SPI_DEVICE_TYPE(_reg)	(((_reg) >> 3) & 0x1)
++
++#define REG_SC_XTALCTRL                                 0x0010
++#define REG_SC_APLLCTRL                                 0x0014
++#define REG_SC_APLLFREQCTRL0                            0x0018
++#define REG_SC_APLLFREQCTRL1                            0x001C
++#define REG_SC_VPLL0FREQCTRL0                           0x0020
++#define REG_SC_VPLL0FREQCTRL1                           0x0024
++#define REG_SC_VPLL1FREQCTRL0                           0x0028
++#define REG_SC_VPLL1FREQCTRL1                           0x002C
++#define REG_SC_EPLLFREQCTRL0                            0x0030
++#define REG_SC_EPLLFREQCTRL1                            0x0034
++#define REG_SC_QPLLFREQCTRL0                            0x0038
++#define REG_SC_QPLLFREQCTRL1                            0x003C
++#define REG_SC_LOW_POWER_CTRL                           0x0040
++#define REG_SC_IO_REUSE_SEL                             0x0044
++#define REG_SC_SRST_REQ_CTRL                            0x0048
++#define REG_SC_CA_RST_CTRL                              0x004C
++#define REG_SC_WDG_RST_CTRL                             0x0050
++#define REG_SC_DDRC_DFI_RST_CTRL                        0x0054
++#define REG_SC_PLLLOCK_STAT                             0x0070
++#define REG_SC_GEN0                                     0x0080
++#define REG_SC_GEN1                                     0x0084
++#define REG_SC_GEN2                                     0x0088
++#define REG_SC_GEN3                                     0x008C
++#define REG_SC_GEN4                                     0x0090
++#define REG_SC_GEN5                                     0x0094
++#define REG_SC_GEN6                                     0x0098
++#define REG_SC_GEN7                                     0x009C
++#define REG_SC_GEN8                                     0x00A0
++#define REG_SC_GEN9                                     0x00A4
++#define REG_SC_GEN10                                    0x00A8
++#define REG_SC_GEN11                                    0x00AC
++#define REG_SC_GEN12                                    0x00B0
++#define REG_SC_GEN13                                    0x00B4
++#define REG_SC_GEN14                                    0x00B8
++#define REG_SC_GEN15                                    0x00BC
++#define REG_SC_GEN16                                    0x00C0
++#define REG_SC_GEN17                                    0x00C4
++#define REG_SC_GEN18                                    0x00C8
++#define REG_SC_GEN19                                    0x00CC
++#define REG_SC_GEN20                                    0x00D0
++#define REG_SC_GEN21                                    0x00D4
++#define REG_SC_GEN22                                    0x00D8
++#define REG_SC_GEN23                                    0x00DC
++#define REG_SC_GEN24                                    0x00E0
++#define REG_SC_GEN25                                    0x00E4
++#define REG_SC_GEN26                                    0x00E8
++#define REG_SC_GEN27                                    0x00EC
++#define REG_SC_GEN28                                    0x00F0
++#define REG_SC_GEN29                                    0x00F4
++#define REG_SC_GEN30                                    0x00F8
++#define REG_SC_GEN31                                    0x00FC
++#define REG_SC_LOCKEN                                   0x020C
++#define REG_SC_SYSID0                                   0x0EE0
++#define REG_SC_SYSID1                                   0x0EE4
++#define REG_SC_SYSID2                                   0x0EE8
++#define REG_SC_SYSID3                                   0x0EEC
++
++/*#define REG_BASE_WDG0                                   0xF8A2C000  */
++
++#define REG_PERI_CRG94                                  0x178
++#define REG_PERI_CRG10                                  0x0028
++#define REG_PERI_CRG98					0x0188
++
++#define CFG_GIC_CPU_BASE    (IO_ADDRESS(REG_BASE_A7_PERI)\
++				+ REG_A7_PERI_GIC_CPU)
++#define CFG_GIC_DIST_BASE   (IO_ADDRESS(REG_BASE_A7_PERI)\
++				+ REG_A7_PERI_GIC_DIST)
++
++
++/*********************************************************************/
++/*
++ * 0x1-> init item1
++ * 0x2-> init item2
++ * 0x3->init item1 & item2
++ */
++#define INIT_REG_ITEM1               1
++#define INIT_REG_ITEM2               2
++#define INIT_REG_ITEM1_ITEM2         (INIT_REG_ITEM1 | INIT_REG_ITEM2)
++
++
++#endif /* End of __HI_CHIP_REGS_H__ */
+diff --git a/arch/arm/include/mach/hi3519v101_io.h b/arch/arm/include/mach/hi3519v101_io.h
+new file mode 100644
+index 0000000..7083af5
+--- /dev/null
++++ b/arch/arm/include/mach/hi3519v101_io.h
+@@ -0,0 +1,46 @@
++#ifndef __HI3519_IO_H
++#define __HI3519_IO_H
++
++#ifdef CONFIG_PCI
++#define IO_SPACE_LIMIT  0xffffffff
++#define __io(a)         __typesafe_io(PCI_IO_VIRT_BASE + ((a) & IO_SPACE_LIMIT))
++#endif
++
++/*  phys_addr		virt_addr
++ * 0x1000_0000 <-----> 0xFE00_0000
++ */
++#define HI3519_IOCH1_VIRT (0xFE000000)
++#define HI3519_IOCH1_PHYS (0x10000000)
++#define HI3519_IOCH1_SIZE (0x00310000)
++
++/*  phys_addr		virt_addr
++ * 0x11000000 <-----> 0xFE400000
++ */
++#define HI3519_IOCH2_VIRT (0xFE400000)
++#define HI3519_IOCH2_PHYS (0x11000000)
++#define HI3519_IOCH2_SIZE (0x004F0000)
++
++/*  phys_addr		virt_addr
++ * 0x12000000 <-----> 0xFE900000
++ */
++#define HI3519_IOCH3_VIRT (0xFE900000)
++#define HI3519_IOCH3_PHYS (0x12000000)
++#define HI3519_IOCH3_SIZE (0x00170000)
++
++
++#define IO_OFFSET_LOW   (0xEC900000)
++#define IO_OFFSET_MID   (0xED400000)
++#define IO_OFFSET_HIGH  (0xEE000000)
++
++#define IO_ADDRESS_LOW(x)  ((x) + IO_OFFSET_LOW)
++#define IO_ADDRESS_MID(x)  ((x) + IO_OFFSET_MID)
++#define IO_ADDRESS_HIGH(x) ((x) + IO_OFFSET_HIGH)
++
++#define __IO_ADDRESS(x) ((x >= HI3519_IOCH2_PHYS) ? IO_ADDRESS_MID(x)\
++		: IO_ADDRESS_HIGH(x))
++#define IO_ADDRESS(x)   ((x) >= HI3519_IOCH3_PHYS ? IO_ADDRESS_LOW(x)\
++		: __IO_ADDRESS(x))
++
++#define __io_address(n) (IOMEM(IO_ADDRESS(n)))
++
++#endif
+diff --git a/arch/arm/include/mach/hi3521d_io.h b/arch/arm/include/mach/hi3521d_io.h
+new file mode 100644
+index 0000000..ed686f8
+--- /dev/null
++++ b/arch/arm/include/mach/hi3521d_io.h
+@@ -0,0 +1,43 @@
++#ifndef __HI3521D_IO_H
++#define __HI3521D_IO_H
++
++/*  phys_addr		virt_addr
++ * 0x1000_0000 <-----> 0xFE00_0000
++ * 0x1004_0000 <-----> 0xFE04_0000
++ */
++#define HI3521D_IOCH1_VIRT (0xFE000000)
++#define HI3521D_IOCH1_PHYS (0x10000000)
++#define HI3521D_IOCH1_SIZE (0x00400000)
++
++/* phys_addr        virt_addr
++ * 0x1200_0000 <-----> 0xFE4_00000
++ * 0x1223_0000 <-----> 0xFE63_0000
++ */
++#define HI3521D_IOCH2_VIRT (0xFE400000)
++#define HI3521D_IOCH2_PHYS (0x12000000)
++#define HI3521D_IOCH2_SIZE (0x00230000)
++
++/* phys_addr        virt_addr
++ * 0x1300_0000 <-----> 0xFE70_0000
++ * 0x1316_0000 <-----> 0xFE86_0000
++ */
++#define HI3521D_IOCH3_VIRT (0xFE700000)
++#define HI3521D_IOCH3_PHYS (0x13000000)
++#define HI3521D_IOCH3_SIZE (0x00160000)
++
++#define IO_OFFSET_LOW		(0xEB700000)
++#define IO_OFFSET_MID		(0xEC400000)
++#define IO_OFFSET_HIGH		(0xEE000000)
++
++#define IO_ADDRESS_LOW(x)	((x) + IO_OFFSET_LOW)
++#define IO_ADDRESS_MID(x)	((x) + IO_OFFSET_MID)
++#define IO_ADDRESS_HIGH(x)	((x) + IO_OFFSET_HIGH)
++
++#define __IO_ADDRESS_HIGH(x) ((x >= HI3521D_IOCH2_PHYS) ? IO_ADDRESS_MID(x) \
++		: IO_ADDRESS_HIGH(x))
++#define IO_ADDRESS(x)   ((x) >= HI3521D_IOCH3_PHYS ? IO_ADDRESS_LOW(x) \
++		: __IO_ADDRESS_HIGH(x))
++
++#define __io_address(x) (IOMEM(IO_ADDRESS(x)))
++
++#endif
+diff --git a/arch/arm/include/mach/hi3521d_platform.h b/arch/arm/include/mach/hi3521d_platform.h
+new file mode 100644
+index 0000000..ac2d8b6
+--- /dev/null
++++ b/arch/arm/include/mach/hi3521d_platform.h
+@@ -0,0 +1,88 @@
++#ifndef __HI3521D_CHIP_REGS_H__
++#define __HI3521D_CHIP_REGS_H__
++
++/* -------------------------------------------------------------------- */
++/* SRAM Base Address Register */
++#define SRAM_BASE_ADDRESS		0x04010000
++
++/* -------------------------------------------------------------------- */
++/*CORTTX-A7 MPCORE MEMORY REGION*/
++/* -------------------------------------------------------------------- */
++#define REG_BASE_A7_PERI		0x10300000
++#define A7_PERI_BASE			REG_BASE_A7_PERI
++
++#define REG_A7_PERI_SCU			0x0000
++
++/* -------------------------------------------------------------------- */
++/* Clock and Reset Generator REG */
++/* -------------------------------------------------------------------- */
++#define REG_BASE_CRG			0x12040000
++#define CRG_REG_BASE			REG_BASE_CRG
++
++#define REG_CRG32				0x0080
++
++/* A7 soft reset request register offset */
++#define REG_A7_SRST_CRG			REG_CRG32
++#define DBG1_SRST_REQ			BIT(4)
++#define CORE1_SRST_REQ			BIT(2)
++
++/* Ethernet CRG register offset */
++#define REG_ETH_CRG				0x014C
++#define REG_ETH_MAC_IF			0x008C
++
++#define UART_CKSEL_MASK			(0x3 << 18)
++#define UART_CKSEL_24M			(0x2 << 18)
++
++#define REG_BASE_CUR_UART		REG_BASE_UART0
++
++/*********************************************************************/
++#define A7_AXI_SCALE_REG		IO_ADDRESS(REG_BASE_CRG + 0x50)
++
++/* -------------------------------------------------------------------- */
++#define DDR_MEM_BASE			0x80000000
++#define CFG_TIMER_PER 			(4)	/* AXI:APB is 4:1 */
++/* -------------------------------------------------------------------- */
++#define get_bus_clk() ({ \
++	unsigned long tmp_reg, busclk = 0;\
++	tmp_reg = readl((void *)A7_AXI_SCALE_REG);\
++	tmp_reg = (tmp_reg >> 2) & 0x3;\
++	if (0x3 == tmp_reg) {\
++		busclk = 300000000;\
++	} else if (0x1 == tmp_reg) {\
++		busclk = 200000000;\
++	} \
++	busclk;\
++})
++
++/* hisilicon satav200 register */
++#define HI_SATA_PORT_FIFOTH		0x44
++#define HI_SATA_PORT_PHYCTL1	0x48
++#define HI_SATA_PORT_PHYCTL		0x74
++
++#define HI_SATA_PHY_CTL0		0xA0
++#define HI_SATA_PHY_CTL1		0xA4
++#define HI_SATA_PHY_CTL2		0xB0
++#define HI_SATA_PHY_RST_BACK_MASK    0xAC
++
++#define HI_SATA_FIFOTH_VALUE	0xFEED9F24
++
++#define HI_SATA_BIGENDINE       (1 << 3)
++
++#define HI_SATA_PHY_MODE_1_5G	0
++#define HI_SATA_PHY_MODE_3G		1
++#define HI_SATA_PHY_MODE_6G		2
++
++#define HI_SATA_PHY_1_5G		0x0e180000
++#define HI_SATA_PHY_3G			0x0e390000
++#define HI_SATA_PHY_6G			0x0e5a0000
++
++#define HI_SATA_PHY_SG_1_5G		0x50438
++#define HI_SATA_PHY_SG_3G		0x50438
++#define HI_SATA_PHY_SG_6G		0x50438
++
++#define	HI_SATA_MISC_CTRL		IO_ADDRESS(0x12120000)
++#define HI_SATA_MISC_SATA_PHY0	(HI_SATA_MISC_CTRL + 0x58)
++#define HI_SATA_MISC_SATA_PHY1	(HI_SATA_MISC_CTRL + 0x64)
++
++#endif /* End of __HI_CHIP_REGS_H__ */
++
+diff --git a/arch/arm/include/mach/hi3531d_io.h b/arch/arm/include/mach/hi3531d_io.h
+new file mode 100644
+index 0000000..6d2640e
+--- /dev/null
++++ b/arch/arm/include/mach/hi3531d_io.h
+@@ -0,0 +1,61 @@
++#ifndef __HI3531D_IO_H
++#define __HI3531D_IO_H
++
++#ifdef CONFIG_PCI
++#define IO_SPACE_LIMIT  0xffffffff
++#define __io(a)         __typesafe_io(PCI_IO_VIRT_BASE + ((a) & IO_SPACE_LIMIT))
++#endif
++
++/* phys_addr        virt_addr
++ * 0x1000_0000 <-----> 0xFE00_0000
++ * 0x1071_0000 <-----> 0xFE71_0000
++ */
++#define HI3531D_IOCH1_VIRT  (0xFE000000)
++#define HI3531D_IOCH1_PHYS  (0x10000000)
++#define HI3531D_IOCH1_SIZE  (0x00710000)
++#define IO_OFFSET_IOCH1     (0xEE000000)
++
++/* phys_addr        virt_addr
++ * 0x1100_0000 <-----> 0xFE78_0000
++ * 0x1104_0000 <-----> 0xFE7C_0000
++ */
++#define HI3531D_IOCH2_VIRT  (0xFE780000)
++#define HI3531D_IOCH2_PHYS  (0x11000000)
++#define HI3531D_IOCH2_SIZE  (0x00040000)
++#define IO_OFFSET_IOCH2     (0xED780000)
++
++/* phys_addr        virt_addr
++ * 0x1200_0000 <-----> 0xFE80_0000
++ * 0x1230_0000 <-----> 0xFEB0_0000
++ */
++#define HI3531D_IOCH3_VIRT  (0xFE800000)
++#define HI3531D_IOCH3_PHYS  (0x12000000)
++#define HI3531D_IOCH3_SIZE  (0x00300000)
++#define IO_OFFSET_IOCH3     (0xEC800000)
++
++/* phys_addr        virt_addr
++ * 0x1300_0000 <-----> 0xFEB0_0000
++ * 0x131A_0000 <-----> 0xFECA_0000
++ */
++#define HI3531D_IOCH4_VIRT  (0xFEB00000)
++#define HI3531D_IOCH4_PHYS  (0x13000000)
++#define HI3531D_IOCH4_SIZE  (0x001A0000)
++#define IO_OFFSET_IOCH4     (0xEBB00000)
++
++#define IO_ADDR_HIGH_H(n)   ((n) + IO_OFFSET_IOCH4)
++#define IO_ADDR_HIGH_L(n)   ((n) + IO_OFFSET_IOCH3)
++#define IO_ADDR_LOW_H(n)    ((n) + IO_OFFSET_IOCH2)
++#define IO_ADDR_LOW_L(n)    ((n) + IO_OFFSET_IOCH1)
++
++#define __IO_ADDR_HIGH(n) ((n >= HI3531D_IOCH4_PHYS) ? IO_ADDR_HIGH_H(n) \
++		: IO_ADDR_HIGH_L(n))
++
++#define __IO_ADDR_LOW(n) ((n >= HI3531D_IOCH2_PHYS) ? IO_ADDR_LOW_H(n) \
++		: IO_ADDR_LOW_L(n))
++
++#define IO_ADDRESS(n)   ((n) >= HI3531D_IOCH3_PHYS ? __IO_ADDR_HIGH(n) \
++		: __IO_ADDR_LOW(n))
++
++#define __io_address(n) (IOMEM(IO_ADDRESS(n)))
++
++#endif
+diff --git a/arch/arm/include/mach/hi3531d_platform.h b/arch/arm/include/mach/hi3531d_platform.h
+new file mode 100644
+index 0000000..c2ff7c0
+--- /dev/null
++++ b/arch/arm/include/mach/hi3531d_platform.h
+@@ -0,0 +1,279 @@
++#ifndef __HI3531D_CHIP_REGS_H__
++#define __HI3531D_CHIP_REGS_H__
++
++/* -------------------------------------------------------------------- */
++/* SRAM Base Address Register */
++#define SRAM_BASE_ADDRESS       0x04010000
++
++/* -------------------------------------------------------------------- */
++#define FMC_REG_BASE            0x10000000
++#define NFC_REG_BASE            0x10010000
++
++/* -------------------------------------------------------------------- */
++/* CORTTX-A9 internal Register */
++/* -------------------------------------------------------------------- */
++#define A9_PERI_BASE            0x10300000
++
++#define REG_A9_PERI_SCU         0x0000
++#define REG_A9_PERI_GIC_CPU     0x0100
++#define REG_A9_PERI_GLOBAL_TIMER    0x0200
++#define REG_A9_PERI_PRI_TIMER_WDT   0x0600
++#define REG_A9_PERI_GIC_DIST        0x1000
++
++#define CFG_GIC_CPU_BASE        (IO_ADDRESS(A9_PERI_BASE) \
++		+ REG_A9_PERI_GIC_CPU)
++#define CFG_GIC_DIST_BASE       (IO_ADDRESS(A9_PERI_BASE) \
++		+ REG_A9_PERI_GIC_DIST)
++
++ /* -------------------------------------------------------------------- */
++#define GSF_REG_BASE            0x100a0000
++
++/* -------------------------------------------------------------------- */
++#define REG_BASE_L2CACHE        0x10700000
++
++/* -------------------------------------------------------------------- */
++#define TIMER0_REG_BASE         0x12000000
++#define TIMER1_REG_BASE         0x12000020
++#define TIMER2_REG_BASE         0x12010000
++#define TIMER3_REG_BASE         0x12010020
++#define TIMER4_REG_BASE         0x12020000
++#define TIMER5_REG_BASE         0x12020020
++#define TIMER6_REG_BASE         0x12030000
++#define TIMER7_REG_BASE         0x12030020
++
++/* -------------------------------------------------------------------- */
++/* Clock and Reset Generator REG */
++/* -------------------------------------------------------------------- */
++#define CRG_REG_BASE            0x12040000
++#define REG_BASE_CRG            CRG_REG_BASE
++
++#define REG_CRG20           0x0050
++#define REG_CRG32           0x0080
++#define REG_CRG72           0x0120
++#define REG_CRG75           0x012c
++#define REG_CRG76           0x0130
++#define REG_CRG77           0x0134
++#define REG_CRG79           0x013c
++#define REG_CRG81           0x0144
++#define REG_CRG82           0x0148
++#define REG_CRG83           0x014c
++#define REG_CRG85           0x0154
++#define REG_CRG87           0x015c
++#define REG_CRG91           0x016c
++
++/* SOC CRG register offset */
++#define REG_SOC_CRG         REG_CRG20
++#define GET_SYS_BUS_CLK(_reg)       (((_reg) >> 2) & 0x3)
++#define SYS_CLK_XTAL            0
++#define SYS_CLK_324M            1
++#define SYS_CLK_375M            2
++#define GET_PERI_AXI_CLK(_reg)      ((_reg) & 0x3)
++#define PERI_CLK_XTAL           0
++#define PERI_CLK_200M           1
++#define PERI_CLK_300M           2
++
++/* A9 soft reset request register offset */
++#define REG_A9_SRST_CRG         REG_CRG32
++#define WDG1_SRST_REQ           (0x1 << 6)
++#define DBG1_SRST_REQ           (0x1 << 5)
++#define CPU1_SRST_REQ           (0x1 << 4)
++
++/* USB 3.0 CRG PHY register offset */
++#define REG_USB3_PHY0           REG_CRG72
++
++/* USB 3.0 CRG Control register offset */
++#define REG_USB3_CTRL           REG_CRG75
++
++/* USB 2.0 CRG Control register offset */
++#define REG_USB2_CTRL           REG_CRG76
++
++/* USB 2.0 CRG PHY register offset */
++#define REG_USB2_PHY0           REG_CRG77
++#define REG_USB2_PHY1           REG_CRG91
++
++/* NFC CRG register offset */
++#define REG_NFC_CRG         REG_CRG79
++#define NFC_CLK_SEL(_clk)       (((_clk) & 0x3) << 2)
++#define NFC_CLK_24M         0
++#define NFC_CLK_200M            1
++#define NFC_CLK_ENABLE          (1 << 1)
++
++/* DMAC CRG register offset */
++#define REG_DMAC_CRG            REG_CRG81
++#define DMAC_CLK_EN         (0x1 << 1)
++#define DMAC_SRST_REQ           (0x1 << 0)
++
++/* FMC CRG register offset */
++#define REG_FMC_CRG         REG_CRG82
++#define FMC_CLK_SEL(_clk)       (((_clk) & 0x3) << 2)
++#define FMC_CLK_SEL_MASK        (0x3 << 2)
++#define FMC_CLK_24M         0
++#define FMC_CLK_83M         1
++#define FMC_CLK_125M            2
++#define FMC_CLK_150M            3
++#define FMC_CLK_ENABLE          (0x1 << 1)
++
++/* Ethernet CRG register offset */
++#define REG_ETH_CRG         REG_CRG83
++#define REG_ETH_MAC_IF          REG_CRG87
++
++/* Uart CRG register offset */
++#define REG_UART_CRG            REG_CRG85
++#define UART_CLK_SEL(_clk)      (((_clk) & 0x3) << 19)
++#define UART_CLK_SEL_MASK       (0x3 << 19)
++#define UART_CLK_APB            0
++#define UART_CLK_24M            1
++#define UART_CLK_2M         2
++
++/* SSP CRG register offset */
++#define REG_SSP_CRG         REG_CRG85
++#define SSP_CLK_ENABLE          (0x1 << 13)
++#define SSP_SOFT_RESET_REQ      (0x1 << 5)
++
++/* -------------------------------------------------------------------- */
++/* System Control REG */
++/* -------------------------------------------------------------------- */
++#define SYS_CTRL_BASE           0x12050000
++
++/* System Control register offset */
++#define REG_SC_CTRL         0x0000
++#define SC_CTRL_TIMER7_CLK_SEL(_clk)    (((_clk) & 0x1) << 31)
++#define SC_CTRL_TIMER6_CLK_SEL(_clk)    (((_clk) & 0x1) << 29)
++#define SC_CTRL_TIMER5_CLK_SEL(_clk)    (((_clk) & 0x1) << 27)
++#define SC_CTRL_TIMER4_CLK_SEL(_clk)    (((_clk) & 0x1) << 25)
++#define SC_CTRL_TIMER3_CLK_SEL(_clk)    (((_clk) & 0x1) << 22)
++#define SC_CTRL_TIMER2_CLK_SEL(_clk)    (((_clk) & 0x1) << 20)
++#define SC_CTRL_TIMER1_CLK_SEL(_clk)    (((_clk) & 0x1) << 18)
++#define SC_CTRL_TIMER0_CLK_SEL(_clk)    (((_clk) & 0x1) << 16)
++#define TIMER_CLK_3M            0
++#define TIMER_CLK_BUS           1
++
++/* System soft reset register offset */
++#define REG_SC_SYSRES           0x0004
++
++#define REG_SC_SOFT_INT         0x001c
++#define REG_SC_SOFT_TYPE        0x0020
++#define REG_SC_LOCK_EN          0x0044
++
++/* System Status register offset */
++#define REG_SC_STAT         0x008c
++#define SYS_CTRL_SYSSTAT    REG_SC_STAT
++
++/* bit[8]=0; SPI nor flash; bit[8]=1: SPI nand flash */
++#define GET_SPI_DEVICE_TYPE(_reg)   (((_reg) >> 8) & 0x1)
++/* if bit[8]=0 SPI nor flash
++ *  * bit[7]=0: 3-Byte address mode; bit[7]=1: 4-Byte address mode */
++#define GET_SPI_NOR_ADDR_MODE(_reg) (((_reg) >> 7) & 0x1)
++
++#define REG_SC_SYSID0           0x0EE0
++#define REG_SC_SYSID1           0x0EE4
++#define REG_SC_SYSID2           0x0EE8
++#define REG_SC_SYSID3           0x0EEC
++
++/* -------------------------------------------------------------------- */
++/* UART Control REG */
++/* -------------------------------------------------------------------- */
++#define UART0_REG_BASE          0x12080000
++#define UART1_REG_BASE          0x12090000
++#define UART2_REG_BASE          0x120A0000
++#define UART3_REG_BASE          0x12130000
++
++#define REG_UART_DATA           0x0000
++#define REG_UART_FLAG           0x0018
++#define REG_UART_CTRL           0x0030
++#define REG_UART_DMA_CR         0x0048
++
++/* -------------------------------------------------------------------- */
++/* I2C Control REG */
++/* -------------------------------------------------------------------- */
++#define I2C0_REG_BASE           0x120c0000
++#define I2C1_REG_BASE           0x122e0000
++
++#define REG_I2C_DATA            0x0010
++
++/* -------------------------------------------------------------------- */
++/* SSP Control REG */
++/* -------------------------------------------------------------------- */
++#define SSP_REG_BASE            0x120d0000
++
++#define REG_SSP_DATA            0x0008
++
++/* -------------------------------------------------------------------- */
++/* Peripheral Control REG */
++/* -------------------------------------------------------------------- */
++#define MISC_REG_BASE           0x12120000
++
++#define MISC_CTRL5          0x0014
++#define MISC_CTRL36         0x0090
++#define MISC_CTRL37         0x0094
++#define MISC_CTRL74         0x0128
++#define MISC_CTRL75         0x012c
++#define MISC_CTRL78         0x0138
++
++/* SPI Chip Select register offset */
++#define REG_SSP_CS          MISC_CTRL5
++#define SSP_CS_SEL(_cs)         (((_cs) & 0x3) << 0)
++#define SSP_CS_SEL_MASK         (0x3 << 0)
++
++/* USB 2.0 MISC Control register offset */
++#define REG_USB2_CTRL0          MISC_CTRL36
++#define REG_USB2_CTRL1          MISC_CTRL37
++
++/* USB 3.0 MISC Control register offset */
++#define REG_USB3_CTRL0          MISC_CTRL74
++#define REG_USB3_CTRL1          MISC_CTRL75
++
++#define REG_COMB_PHY1           MISC_CTRL78
++
++/* hisilicon satav200 register */
++#define HI_SATA_PORT_FIFOTH	0x44
++#define HI_SATA_PORT_PHYCTL1	0x48
++#define HI_SATA_PORT_PHYCTL	0x74
++
++#define HI_SATA_PHY_CTL0	0xA0
++#define HI_SATA_PHY_CTL1	0xA4
++#define HI_SATA_PHY_CTL2	0xB0
++#define HI_SATA_PHY_RST_BACK_MASK    0xAC
++
++#define HI_SATA_FIFOTH_VALUE	0xFEED9F24
++
++#define HI_SATA_BIGENDINE       (1 << 3)
++
++#define HI_SATA_PHY_MODE_1_5G	0
++#define HI_SATA_PHY_MODE_3G	1
++#define HI_SATA_PHY_MODE_6G	2
++
++#define HI_SATA_PHY_1_5G	0x0e180000
++#define HI_SATA_PHY_3G		0x0e390000
++#define HI_SATA_PHY_6G		0x0e5a0000
++
++#define HI_SATA_PHY_SG_1_5G	0x50438
++#define HI_SATA_PHY_SG_3G	0x50438
++#define HI_SATA_PHY_SG_6G	0x50438
++
++#define	HI_SATA_MISC_CTRL			IO_ADDRESS(0x12120000)
++#define HI_SATA_MISC_COMB_PHY0		(HI_SATA_MISC_CTRL + 0x134)
++#define HI_SATA_MISC_COMB_PHY1		(HI_SATA_MISC_CTRL + 0x138)
++#define HI_SATA_MISC_COMB_PHY2		(HI_SATA_MISC_CTRL + 0x140)
++#define HI_SATA_MISC_COMB_PHY3		(HI_SATA_MISC_CTRL + 0x144)
++
++/* -------------------------------------------------------------------- */
++#define FMC_MEM_BASE            0x14000000
++#define NFC_MEM_BASE            0x15000000
++#define DDR_MEM_BASE            0x40000000
++
++#define CFG_TIMER_PER		(4)	/* AXI:APB is 4:1 */
++/* -------------------------------------------------------------------- */
++#define get_bus_clk() ({ \
++		unsigned int base, regval, busclk = 0; \
++		base = IO_ADDRESS(CRG_REG_BASE + REG_SOC_CRG); \
++		regval = readl((void *)base); \
++		regval = GET_PERI_AXI_CLK(regval); \
++		if (PERI_CLK_200M == regval) \
++			busclk = 200000000; \
++		else if (PERI_CLK_300M == regval) \
++			busclk = 300000000; \
++		busclk; \
++	})
++
++#endif /* End of __HI3531D_CHIP_REGS_H__ */
+diff --git a/arch/arm/include/mach/hi3536c_io.h b/arch/arm/include/mach/hi3536c_io.h
+new file mode 100644
+index 0000000..5e0f34d
+--- /dev/null
++++ b/arch/arm/include/mach/hi3536c_io.h
+@@ -0,0 +1,43 @@
++#ifndef __HI3536C_IO_H
++#define __HI3536C_IO_H
++
++/*  phys_addr		virt_addr
++ * 0x1000_0000 <-----> 0xFE00_0000
++ * 0x1004_0000 <-----> 0xFE04_0000
++ */
++#define HI3536C_IOCH1_VIRT (0xFE000000)
++#define HI3536C_IOCH1_PHYS (0x10000000)
++#define HI3536C_IOCH1_SIZE (0x00400000)
++
++/* phys_addr        virt_addr
++ * 0x1200_0000 <-----> 0xFE4_00000
++ * 0x1223_0000 <-----> 0xFE63_0000
++ */
++#define HI3536C_IOCH2_VIRT (0xFE400000)
++#define HI3536C_IOCH2_PHYS (0x12000000)
++#define HI3536C_IOCH2_SIZE (0x00230000)
++
++/* phys_addr        virt_addr
++ * 0x1300_0000 <-----> 0xFE70_0000
++ * 0x1316_0000 <-----> 0xFE86_0000
++ */
++#define HI3536C_IOCH3_VIRT (0xFE700000)
++#define HI3536C_IOCH3_PHYS (0x13000000)
++#define HI3536C_IOCH3_SIZE (0x00160000)
++
++#define IO_OFFSET_LOW		(0xEB700000)
++#define IO_OFFSET_MID		(0xEC400000)
++#define IO_OFFSET_HIGH		(0xEE000000)
++
++#define IO_ADDRESS_LOW(x)	((x) + IO_OFFSET_LOW)
++#define IO_ADDRESS_MID(x)	((x) + IO_OFFSET_MID)
++#define IO_ADDRESS_HIGH(x)	((x) + IO_OFFSET_HIGH)
++
++#define __IO_ADDRESS_HIGH(x) ((x >= HI3536C_IOCH2_PHYS) ? IO_ADDRESS_MID(x) \
++		: IO_ADDRESS_HIGH(x))
++#define IO_ADDRESS(x)   ((x) >= HI3536C_IOCH3_PHYS ? IO_ADDRESS_LOW(x) \
++		: __IO_ADDRESS_HIGH(x))
++
++#define __io_address(x) (IOMEM(IO_ADDRESS(x)))
++
++#endif
+diff --git a/arch/arm/include/mach/hi3536c_platform.h b/arch/arm/include/mach/hi3536c_platform.h
+new file mode 100644
+index 0000000..5191057
+--- /dev/null
++++ b/arch/arm/include/mach/hi3536c_platform.h
+@@ -0,0 +1,88 @@
++#ifndef __HI3536C_CHIP_REGS_H__
++#define __HI3536C_CHIP_REGS_H__
++
++/* -------------------------------------------------------------------- */
++/* SRAM Base Address Register */
++#define SRAM_BASE_ADDRESS		0x04010000
++
++/* -------------------------------------------------------------------- */
++/*CORTTX-A7 MPCORE MEMORY REGION*/
++/* -------------------------------------------------------------------- */
++#define REG_BASE_A7_PERI		0x10300000
++#define A7_PERI_BASE			REG_BASE_A7_PERI
++
++#define REG_A7_PERI_SCU			0x0000
++
++/* -------------------------------------------------------------------- */
++/* Clock and Reset Generator REG */
++/* -------------------------------------------------------------------- */
++#define REG_BASE_CRG			0x12040000
++#define CRG_REG_BASE			REG_BASE_CRG
++
++#define REG_CRG32				0x0080
++
++/* A7 soft reset request register offset */
++#define REG_A7_SRST_CRG			REG_CRG32
++#define DBG1_SRST_REQ			BIT(4)
++#define CORE1_SRST_REQ			BIT(2)
++
++/* Ethernet CRG register offset */
++#define REG_ETH_CRG				0x014C
++#define REG_ETH_MAC_IF			0x008C
++
++#define UART_CKSEL_MASK			(0x3 << 18)
++#define UART_CKSEL_24M			(0x2 << 18)
++
++#define REG_BASE_CUR_UART		REG_BASE_UART0
++
++/*********************************************************************/
++#define A7_AXI_SCALE_REG		IO_ADDRESS(REG_BASE_CRG + 0x50)
++
++/* -------------------------------------------------------------------- */
++#define DDR_MEM_BASE			0x80000000
++#define CFG_TIMER_PER 			(4)	/* AXI:APB is 4:1 */
++/* -------------------------------------------------------------------- */
++#define get_bus_clk() ({ \
++	unsigned long tmp_reg, busclk = 0;\
++	tmp_reg = readl((void *)A7_AXI_SCALE_REG);\
++	tmp_reg = (tmp_reg >> 2) & 0x3;\
++	if (0x3 == tmp_reg) {\
++		busclk = 300000000;\
++	} else if (0x1 == tmp_reg) {\
++		busclk = 200000000;\
++	} \
++	busclk;\
++})
++
++/* hisilicon satav200 register */
++#define HI_SATA_PORT_FIFOTH		0x44
++#define HI_SATA_PORT_PHYCTL1	0x48
++#define HI_SATA_PORT_PHYCTL		0x74
++
++#define HI_SATA_PHY_CTL0		0xA0
++#define HI_SATA_PHY_CTL1		0xA4
++#define HI_SATA_PHY_CTL2		0xB0
++#define HI_SATA_PHY_RST_BACK_MASK    0xAC
++
++#define HI_SATA_FIFOTH_VALUE	0xFEED9F24
++
++#define HI_SATA_BIGENDINE       (1 << 3)
++
++#define HI_SATA_PHY_MODE_1_5G	0
++#define HI_SATA_PHY_MODE_3G		1
++#define HI_SATA_PHY_MODE_6G		2
++
++#define HI_SATA_PHY_1_5G		0x0e180000
++#define HI_SATA_PHY_3G			0x0e390000
++#define HI_SATA_PHY_6G			0x0e5a0000
++
++#define HI_SATA_PHY_SG_1_5G		0x50438
++#define HI_SATA_PHY_SG_3G		0x50438
++#define HI_SATA_PHY_SG_6G		0x50438
++
++#define	HI_SATA_MISC_CTRL		IO_ADDRESS(0x12120000)
++#define HI_SATA_MISC_SATA_PHY0	(HI_SATA_MISC_CTRL + 0x58)
++#define HI_SATA_MISC_SATA_PHY1	(HI_SATA_MISC_CTRL + 0x64)
++
++#endif /* End of __HI_CHIP_REGS_H__ */
++
+diff --git a/arch/arm/include/mach/hi3559_io.h b/arch/arm/include/mach/hi3559_io.h
+new file mode 100644
+index 0000000..0238699
+--- /dev/null
++++ b/arch/arm/include/mach/hi3559_io.h
+@@ -0,0 +1,46 @@
++#ifndef __HI3559_IO_H
++#define __HI3559_IO_H
++
++#ifdef CONFIG_PCI
++#define IO_SPACE_LIMIT  0xffffffff
++#define __io(a)         __typesafe_io(PCI_IO_VIRT_BASE + ((a) & IO_SPACE_LIMIT))
++#endif
++
++/*  phys_addr		virt_addr
++ * 0x1000_0000 <-----> 0xFE00_0000
++ */
++#define HI3559_IOCH1_VIRT (0xFE000000)
++#define HI3559_IOCH1_PHYS (0x10000000)
++#define HI3559_IOCH1_SIZE (0x00310000)
++
++/*  phys_addr		virt_addr
++ * 0x11000000 <-----> 0xFE400000
++ */
++#define HI3559_IOCH2_VIRT (0xFE400000)
++#define HI3559_IOCH2_PHYS (0x11000000)
++#define HI3559_IOCH2_SIZE (0x004F0000)
++
++/*  phys_addr		virt_addr
++ * 0x12000000 <-----> 0xFE900000
++ */
++#define HI3559_IOCH3_VIRT (0xFE900000)
++#define HI3559_IOCH3_PHYS (0x12000000)
++#define HI3559_IOCH3_SIZE (0x00170000)
++
++
++#define IO_OFFSET_LOW   (0xEC900000)
++#define IO_OFFSET_MID   (0xED400000)
++#define IO_OFFSET_HIGH  (0xEE000000)
++
++#define IO_ADDRESS_LOW(x)  ((x) + IO_OFFSET_LOW)
++#define IO_ADDRESS_MID(x)  ((x) + IO_OFFSET_MID)
++#define IO_ADDRESS_HIGH(x) ((x) + IO_OFFSET_HIGH)
++
++#define __IO_ADDRESS(x) ((x >= HI3559_IOCH2_PHYS) ? IO_ADDRESS_MID(x)\
++		: IO_ADDRESS_HIGH(x))
++#define IO_ADDRESS(x)   ((x) >= HI3559_IOCH3_PHYS ? IO_ADDRESS_LOW(x)\
++		: __IO_ADDRESS(x))
++
++#define __io_address(n) (IOMEM(IO_ADDRESS(n)))
++
++#endif
+diff --git a/arch/arm/include/mach/hi3559_platform.h b/arch/arm/include/mach/hi3559_platform.h
+new file mode 100644
+index 0000000..0e2f4d4
+--- /dev/null
++++ b/arch/arm/include/mach/hi3559_platform.h
+@@ -0,0 +1,164 @@
++#ifndef __HI3559_CHIP_REGS_H__
++#define __HI3559_CHIP_REGS_H__
++
++/* SRAM Base Address Register */
++#define SRAM_BASE_ADDRESS                               0x4010000
++
++#define REG_BASE_TIMER01                                0x12000000
++#define REG_BASE_TIMER23                                0x12001000
++
++/* -------------------------------------------------------------------- */
++/* Clock and Reset Generator REG */
++/* -------------------------------------------------------------------- */
++#define CRG_REG_BASE			0x12010000
++#define REG_BASE_CRG			CRG_REG_BASE
++
++#define REG_CRG48			0x00c0
++
++/* FMC CRG register offset */
++#define REG_FMC_CRG			REG_CRG48
++#define FMC_CLK_SEL(_clk)		(((_clk) & 0x7) << 2)
++#define FMC_CLK_SEL_MASK		(0x7 << 2)
++#define GET_FMC_CLK_TYPE(_reg)		(((_reg) >> 2) & 0x7)
++/* SDR/DDR clock */
++#define FMC_CLK_24M			0
++#define FMC_CLK_75M			1
++#define FMC_CLK_125M			2
++#define FMC_CLK_150M			3
++#define FMC_CLK_200M			4
++#define FMC_CLK_250M			5
++/* Only DDR clock */
++#define FMC_CLK_300M			6
++#define FMC_CLK_400M			7
++#define FMC_CLK_ENABLE			(0x1 << 1)
++#define FMC_SOFT_RST_REQ		(0x1 << 0)
++
++#define REG_BASE_UART0                                  0x12100000
++#define REG_BASE_UART1                                  0x12101000
++#define REG_BASE_UART2                                  0x12102000
++#define REG_BASE_UART3                                  0x12103000
++#define REG_BASE_UART4                                  0x12104000
++#define REG_BASE_CUR_UART                               REG_BASE_UART0
++
++#define PMC_BASE					0x120a0000
++
++#define CCI_BASE					0x1ff00000
++#define CCI_PORT0_BASE				        0x1ff01000
++#define CCI_PORT1_BASE				        0x1ff02000
++
++
++#define REG_BASE_A7_PERI                               0x10300000
++
++/*CORTTX-A7 MPCORE MEMORY REGION*/
++#define REG_A7_PERI_SCU                                 0x0000
++#define REG_A7_PERI_GIC_CPU                             0x2000
++#define REG_A7_PERI_GLOBAL_TIMER                        0x0200
++#define REG_A7_PERI_PRI_TIMER_WDT                       0x0600
++#define REG_A7_PERI_GIC_DIST                            0x1000
++/* -------------------------------------------------------------------- */
++/* System Control REG */
++/* -------------------------------------------------------------------- */
++#define SYS_CTRL_BASE                                    0x12020000
++
++/* System Control register offset */
++#define REG_SC_CTRL			0x0000
++
++/* System soft reset register offset */
++#define REG_SC_SYSRES			0x0004
++
++/* System Status register offset */
++#define REG_SC_STAT			0x008c
++
++/* if bit[5:4]=00b: boot form SPI && bit[3]=0: SPI nor flash
++ * bit[7]=0: 3-Byte address mode; bit[7]=1: 4-Byte address mode */
++#define GET_SPI_NOR_ADDR_MODE(_reg)	(((_reg) >> 7) & 0x1)
++#define GET_SYS_BOOT_MODE(_reg)		(((_reg) >> 4) & 0x3)
++#define BOOT_MODE_MASK				((0x3) << 4)
++#define BOOT_FROM_SPI			0
++#define BOOT_FROM_NAND			1
++#define BOOT_FROM_EMMC			2
++#define BOOT_FROM_DDR			3
++/* bit[3]=0; SPI nor flash; bit[3]=1: SPI nand flash */
++#define GET_SPI_DEVICE_TYPE(_reg)	(((_reg) >> 3) & 0x1)
++
++#define REG_SC_XTALCTRL                                 0x0010
++#define REG_SC_APLLCTRL                                 0x0014
++#define REG_SC_APLLFREQCTRL0                            0x0018
++#define REG_SC_APLLFREQCTRL1                            0x001C
++#define REG_SC_VPLL0FREQCTRL0                           0x0020
++#define REG_SC_VPLL0FREQCTRL1                           0x0024
++#define REG_SC_VPLL1FREQCTRL0                           0x0028
++#define REG_SC_VPLL1FREQCTRL1                           0x002C
++#define REG_SC_EPLLFREQCTRL0                            0x0030
++#define REG_SC_EPLLFREQCTRL1                            0x0034
++#define REG_SC_QPLLFREQCTRL0                            0x0038
++#define REG_SC_QPLLFREQCTRL1                            0x003C
++#define REG_SC_LOW_POWER_CTRL                           0x0040
++#define REG_SC_IO_REUSE_SEL                             0x0044
++#define REG_SC_SRST_REQ_CTRL                            0x0048
++#define REG_SC_CA_RST_CTRL                              0x004C
++#define REG_SC_WDG_RST_CTRL                             0x0050
++#define REG_SC_DDRC_DFI_RST_CTRL                        0x0054
++#define REG_SC_PLLLOCK_STAT                             0x0070
++#define REG_SC_GEN0                                     0x0080
++#define REG_SC_GEN1                                     0x0084
++#define REG_SC_GEN2                                     0x0088
++#define REG_SC_GEN3                                     0x008C
++#define REG_SC_GEN4                                     0x0090
++#define REG_SC_GEN5                                     0x0094
++#define REG_SC_GEN6                                     0x0098
++#define REG_SC_GEN7                                     0x009C
++#define REG_SC_GEN8                                     0x00A0
++#define REG_SC_GEN9                                     0x00A4
++#define REG_SC_GEN10                                    0x00A8
++#define REG_SC_GEN11                                    0x00AC
++#define REG_SC_GEN12                                    0x00B0
++#define REG_SC_GEN13                                    0x00B4
++#define REG_SC_GEN14                                    0x00B8
++#define REG_SC_GEN15                                    0x00BC
++#define REG_SC_GEN16                                    0x00C0
++#define REG_SC_GEN17                                    0x00C4
++#define REG_SC_GEN18                                    0x00C8
++#define REG_SC_GEN19                                    0x00CC
++#define REG_SC_GEN20                                    0x00D0
++#define REG_SC_GEN21                                    0x00D4
++#define REG_SC_GEN22                                    0x00D8
++#define REG_SC_GEN23                                    0x00DC
++#define REG_SC_GEN24                                    0x00E0
++#define REG_SC_GEN25                                    0x00E4
++#define REG_SC_GEN26                                    0x00E8
++#define REG_SC_GEN27                                    0x00EC
++#define REG_SC_GEN28                                    0x00F0
++#define REG_SC_GEN29                                    0x00F4
++#define REG_SC_GEN30                                    0x00F8
++#define REG_SC_GEN31                                    0x00FC
++#define REG_SC_LOCKEN                                   0x020C
++#define REG_SC_SYSID0                                   0x0EE0
++#define REG_SC_SYSID1                                   0x0EE4
++#define REG_SC_SYSID2                                   0x0EE8
++#define REG_SC_SYSID3                                   0x0EEC
++
++/*#define REG_BASE_WDG0                                   0xF8A2C000  */
++
++#define REG_PERI_CRG94                                  0x178
++#define REG_PERI_CRG10                                  0x0028
++#define REG_PERI_CRG98					0x0188
++
++#define CFG_GIC_CPU_BASE    (IO_ADDRESS(REG_BASE_A7_PERI)\
++				+ REG_A7_PERI_GIC_CPU)
++#define CFG_GIC_DIST_BASE   (IO_ADDRESS(REG_BASE_A7_PERI)\
++				+ REG_A7_PERI_GIC_DIST)
++
++
++/*********************************************************************/
++/*
++ * 0x1-> init item1
++ * 0x2-> init item2
++ * 0x3->init item1 & item2
++ */
++#define INIT_REG_ITEM1               1
++#define INIT_REG_ITEM2               2
++#define INIT_REG_ITEM1_ITEM2         (INIT_REG_ITEM1 | INIT_REG_ITEM2)
++
++
++#endif /* End of __HI_CHIP_REGS_H__ */
+diff --git a/arch/arm/include/mach/io.h b/arch/arm/include/mach/io.h
+new file mode 100644
+index 0000000..ae92d98
+--- /dev/null
++++ b/arch/arm/include/mach/io.h
+@@ -0,0 +1,32 @@
++#ifndef __ASM_ARM_ARCH_IO_H
++#define __ASM_ARM_ARCH_IO_H
++
++#ifdef CONFIG_ARCH_HI3519
++#include <mach/hi3519_io.h>
++#endif
++
++#ifdef CONFIG_ARCH_HI3519V101
++#include <mach/hi3519v101_io.h>
++#endif
++
++#if defined(CONFIG_ARCH_HI3559) || defined(CONFIG_ARCH_HI3556)
++#include <mach/hi3559_io.h>
++#endif
++
++#ifdef CONFIG_ARCH_HI3516AV200
++#include <mach/hi3516av200_io.h>
++#endif
++
++#ifdef CONFIG_ARCH_HI3536C
++#include <mach/hi3536c_io.h>
++#endif
++
++#ifdef CONFIG_ARCH_HI3531D
++#include <mach/hi3531d_io.h>
++#endif
++
++#ifdef CONFIG_ARCH_HI3521D
++#include <mach/hi3521d_io.h>
++#endif
++
++#endif
+diff --git a/arch/arm/include/mach/platform.h b/arch/arm/include/mach/platform.h
+new file mode 100644
+index 0000000..ef78a22
+--- /dev/null
++++ b/arch/arm/include/mach/platform.h
+@@ -0,0 +1,28 @@
++#ifndef __HI_CHIP_REGS_H__
++#define __HI_CHIP_REGS_H__
++
++#if (defined CONFIG_ARCH_HI3519 || defined CONFIG_ARCH_HI3519V101)
++#include <mach/hi3519_platform.h>
++#endif
++
++#if defined(CONFIG_ARCH_HI3559) || defined(CONFIG_ARCH_HI3556)
++#include <mach/hi3559_platform.h>
++#endif
++
++#ifdef CONFIG_ARCH_HI3516AV200
++#include <mach/hi3516av200_platform.h>
++#endif
++
++#ifdef CONFIG_ARCH_HI3536C
++#include <mach/hi3536c_platform.h>
++#endif
++
++#ifdef CONFIG_ARCH_HI3531D
++#include <mach/hi3531d_platform.h>
++#endif
++
++#ifdef CONFIG_ARCH_HI3521D
++#include <mach/hi3521d_platform.h>
++#endif
++
++#endif /* End of __HI_CHIP_REGS_H__ */
+diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c
+index a88671c..152a95a 100644
+--- a/arch/arm/kernel/armksyms.c
++++ b/arch/arm/kernel/armksyms.c
+@@ -83,6 +83,7 @@ EXPORT_SYMBOL(__raw_writesl);
+ EXPORT_SYMBOL(strchr);
+ EXPORT_SYMBOL(strrchr);
+ EXPORT_SYMBOL(memset);
++
+ EXPORT_SYMBOL(memcpy);
+ EXPORT_SYMBOL(memmove);
+ EXPORT_SYMBOL(memchr);
+diff --git a/arch/arm/kernel/asm-offsets.c b/arch/arm/kernel/asm-offsets.c
+index 2d2d608..e4d88fa 100644
+--- a/arch/arm/kernel/asm-offsets.c
++++ b/arch/arm/kernel/asm-offsets.c
+@@ -10,9 +10,11 @@
+  * it under the terms of the GNU General Public License version 2 as
+  * published by the Free Software Foundation.
+  */
+-#include <linux/compiler.h>
+ #include <linux/sched.h>
+ #include <linux/mm.h>
++#ifdef	CONFIG_HISI_SNAPSHOT_BOOT
++#include <linux/suspend.h>
++#endif
+ #include <linux/dma-mapping.h>
+ #ifdef CONFIG_KVM_ARM_HOST
+ #include <linux/kvm_host.h>
+@@ -40,19 +42,10 @@
+  * GCC 3.2.x: miscompiles NEW_AUX_ENT in fs/binfmt_elf.c
+  *            (http://gcc.gnu.org/PR8896) and incorrect structure
+  *	      initialisation in fs/jffs2/erase.c
+- * GCC 4.8.0-4.8.2: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58854
+- *	      miscompiles find_get_entry(), and can result in EXT3 and EXT4
+- *	      filesystem corruption (possibly other FS too).
+  */
+-#ifdef __GNUC__
+ #if (__GNUC__ == 3 && __GNUC_MINOR__ < 3)
+ #error Your compiler is too buggy; it is known to miscompile kernels.
+-#error    Known good compilers: 3.3, 4.x
+-#endif
+-#if GCC_VERSION >= 40800 && GCC_VERSION < 40803
+-#error Your compiler is too buggy; it is known to miscompile kernels
+-#error and result in filesystem corruption and oopses.
+-#endif
++#error    Known good compilers: 3.3
+ #endif
+ 
+ int main(void)
+@@ -165,6 +158,11 @@ int main(void)
+   DEFINE(DMA_BIDIRECTIONAL,	DMA_BIDIRECTIONAL);
+   DEFINE(DMA_TO_DEVICE,		DMA_TO_DEVICE);
+   DEFINE(DMA_FROM_DEVICE,	DMA_FROM_DEVICE);
++#ifdef	CONFIG_HISI_SNAPSHOT_BOOT
++	DEFINE(PBE_ADDRESS,		offsetof(struct pbe, address));
++	DEFINE(PBE_ORIG_ADDRESS,	offsetof(struct pbe, orig_address));
++	DEFINE(PBE_NEXT,		offsetof(struct pbe, next));
++#endif
+   BLANK();
+   DEFINE(CACHE_WRITEBACK_ORDER, __CACHE_WRITEBACK_ORDER);
+   DEFINE(CACHE_WRITEBACK_GRANULE, __CACHE_WRITEBACK_GRANULE);
+diff --git a/arch/arm/kernel/etm.c b/arch/arm/kernel/etm.c
+index 131a6ab..a634e0e 100644
+--- a/arch/arm/kernel/etm.c
++++ b/arch/arm/kernel/etm.c
+@@ -15,6 +15,7 @@
+ #include <linux/init.h>
+ #include <linux/types.h>
+ #include <linux/io.h>
++#include <linux/slab.h>
+ #include <linux/sysrq.h>
+ #include <linux/device.h>
+ #include <linux/clk.h>
+@@ -37,26 +38,37 @@ MODULE_AUTHOR("Alexander Shishkin");
+ struct tracectx {
+ 	unsigned int	etb_bufsz;
+ 	void __iomem	*etb_regs;
+-	void __iomem	*etm_regs;
++	void __iomem	**etm_regs;
++	int		etm_regs_count;
+ 	unsigned long	flags;
+ 	int		ncmppairs;
+ 	int		etm_portsz;
++	int		etm_contextid_size;
++	u32		etb_fc;
++	unsigned long	range_start;
++	unsigned long	range_end;
++	unsigned long	data_range_start;
++	unsigned long	data_range_end;
++	bool		dump_initial_etb;
+ 	struct device	*dev;
+ 	struct clk	*emu_clk;
+ 	struct mutex	mutex;
+ };
+ 
+-static struct tracectx tracer;
++static struct tracectx tracer = {
++	.range_start = (unsigned long)_stext,
++	.range_end = (unsigned long)_etext,
++};
+ 
+ static inline bool trace_isrunning(struct tracectx *t)
+ {
+ 	return !!(t->flags & TRACER_RUNNING);
+ }
+ 
+-static int etm_setup_address_range(struct tracectx *t, int n,
++static int etm_setup_address_range(struct tracectx *t, int id, int n,
+ 		unsigned long start, unsigned long end, int exclude, int data)
+ {
+-	u32 flags = ETMAAT_ARM | ETMAAT_IGNCONTEXTID | ETMAAT_NSONLY | \
++	u32 flags = ETMAAT_ARM | ETMAAT_IGNCONTEXTID | ETMAAT_IGNSECURITY |
+ 		    ETMAAT_NOVALCMP;
+ 
+ 	if (n < 1 || n > t->ncmppairs)
+@@ -72,95 +84,185 @@ static int etm_setup_address_range(struct tracectx *t, int n,
+ 		flags |= ETMAAT_IEXEC;
+ 
+ 	/* first comparator for the range */
+-	etm_writel(t, flags, ETMR_COMP_ACC_TYPE(n * 2));
+-	etm_writel(t, start, ETMR_COMP_VAL(n * 2));
++	etm_writel(t, id, flags, ETMR_COMP_ACC_TYPE(n * 2));
++	etm_writel(t, id, start, ETMR_COMP_VAL(n * 2));
+ 
+ 	/* second comparator is right next to it */
+-	etm_writel(t, flags, ETMR_COMP_ACC_TYPE(n * 2 + 1));
+-	etm_writel(t, end, ETMR_COMP_VAL(n * 2 + 1));
+-
+-	flags = exclude ? ETMTE_INCLEXCL : 0;
+-	etm_writel(t, flags | (1 << n), ETMR_TRACEENCTRL);
++	etm_writel(t, id, flags, ETMR_COMP_ACC_TYPE(n * 2 + 1));
++	etm_writel(t, id, end, ETMR_COMP_VAL(n * 2 + 1));
++
++	if (data) {
++		flags = exclude ? ETMVDC3_EXCLONLY : 0;
++		if (exclude)
++			n += 8;
++		etm_writel(t, id, flags | BIT(n), ETMR_VIEWDATACTRL3);
++	} else {
++		flags = exclude ? ETMTE_INCLEXCL : 0;
++		etm_writel(t, id, flags | (1 << n), ETMR_TRACEENCTRL);
++	}
+ 
+ 	return 0;
+ }
+ 
+-static int trace_start(struct tracectx *t)
++static int trace_start_etm(struct tracectx *t, int id)
+ {
+ 	u32 v;
+ 	unsigned long timeout = TRACER_TIMEOUT;
+ 
+-	etb_unlock(t);
+-
+-	etb_writel(t, 0, ETBR_FORMATTERCTRL);
+-	etb_writel(t, 1, ETBR_CTRL);
+-
+-	etb_lock(t);
+-
+-	/* configure etm */
+ 	v = ETMCTRL_OPTS | ETMCTRL_PROGRAM | ETMCTRL_PORTSIZE(t->etm_portsz);
++	v |= ETMCTRL_CONTEXTIDSIZE(t->etm_contextid_size);
+ 
+ 	if (t->flags & TRACER_CYCLE_ACC)
+ 		v |= ETMCTRL_CYCLEACCURATE;
+ 
+-	etm_unlock(t);
++	if (t->flags & TRACER_BRANCHOUTPUT)
++		v |= ETMCTRL_BRANCH_OUTPUT;
++
++	if (t->flags & TRACER_TRACE_DATA)
++		v |= ETMCTRL_DATA_DO_ADDR;
++
++	if (t->flags & TRACER_TIMESTAMP)
++		v |= ETMCTRL_TIMESTAMP_EN;
++
++	if (t->flags & TRACER_RETURN_STACK)
++		v |= ETMCTRL_RETURN_STACK_EN;
+ 
+-	etm_writel(t, v, ETMR_CTRL);
++	etm_unlock(t, id);
+ 
+-	while (!(etm_readl(t, ETMR_CTRL) & ETMCTRL_PROGRAM) && --timeout)
++	etm_writel(t, id, v, ETMR_CTRL);
++
++	while (!(etm_readl(t, id, ETMR_CTRL) & ETMCTRL_PROGRAM) && --timeout)
+ 		;
+ 	if (!timeout) {
+ 		dev_dbg(t->dev, "Waiting for progbit to assert timed out\n");
+-		etm_lock(t);
++		etm_lock(t, id);
+ 		return -EFAULT;
+ 	}
+ 
+-	etm_setup_address_range(t, 1, (unsigned long)_stext,
+-			(unsigned long)_etext, 0, 0);
+-	etm_writel(t, 0, ETMR_TRACEENCTRL2);
+-	etm_writel(t, 0, ETMR_TRACESSCTRL);
+-	etm_writel(t, 0x6f, ETMR_TRACEENEVT);
++	if (t->range_start || t->range_end)
++		etm_setup_address_range(t, id, 1,
++					t->range_start, t->range_end, 0, 0);
++	else
++		etm_writel(t, id, ETMTE_INCLEXCL, ETMR_TRACEENCTRL);
++
++	etm_writel(t, id, 0, ETMR_TRACEENCTRL2);
++	etm_writel(t, id, 0, ETMR_TRACESSCTRL);
++	etm_writel(t, id, 0x6f, ETMR_TRACEENEVT);
++
++	etm_writel(t, id, 0, ETMR_VIEWDATACTRL1);
++	etm_writel(t, id, 0, ETMR_VIEWDATACTRL2);
++
++	if (t->data_range_start || t->data_range_end)
++		etm_setup_address_range(t, id, 2, t->data_range_start,
++					t->data_range_end, 0, 1);
++	else
++		etm_writel(t, id, ETMVDC3_EXCLONLY, ETMR_VIEWDATACTRL3);
++
++	etm_writel(t, id, 0x6f, ETMR_VIEWDATAEVT);
+ 
+ 	v &= ~ETMCTRL_PROGRAM;
+ 	v |= ETMCTRL_PORTSEL;
+ 
+-	etm_writel(t, v, ETMR_CTRL);
++	etm_writel(t, id, v, ETMR_CTRL);
+ 
+ 	timeout = TRACER_TIMEOUT;
+-	while (etm_readl(t, ETMR_CTRL) & ETMCTRL_PROGRAM && --timeout)
++	while (etm_readl(t, id, ETMR_CTRL) & ETMCTRL_PROGRAM && --timeout)
+ 		;
+ 	if (!timeout) {
+ 		dev_dbg(t->dev, "Waiting for progbit to deassert timed out\n");
+-		etm_lock(t);
++		etm_lock(t, id);
+ 		return -EFAULT;
+ 	}
+ 
+-	etm_lock(t);
++	etm_lock(t, id);
++	return 0;
++}
++
++static int trace_start(struct tracectx *t)
++{
++	int ret;
++	int id;
++	u32 etb_fc = t->etb_fc;
++
++	etb_unlock(t);
++
++	t->dump_initial_etb = false;
++	etb_writel(t, 0, ETBR_WRITEADDR);
++	etb_writel(t, etb_fc, ETBR_FORMATTERCTRL);
++	etb_writel(t, 1, ETBR_CTRL);
++
++	etb_lock(t);
++
++	/* configure etm(s) */
++	for (id = 0; id < t->etm_regs_count; id++) {
++		ret = trace_start_etm(t, id);
++		if (ret)
++			return ret;
++	}
+ 
+ 	t->flags |= TRACER_RUNNING;
+ 
+ 	return 0;
+ }
+ 
+-static int trace_stop(struct tracectx *t)
++static int trace_stop_etm(struct tracectx *t, int id)
+ {
+ 	unsigned long timeout = TRACER_TIMEOUT;
+ 
+-	etm_unlock(t);
++	etm_unlock(t, id);
+ 
+-	etm_writel(t, 0x440, ETMR_CTRL);
+-	while (!(etm_readl(t, ETMR_CTRL) & ETMCTRL_PROGRAM) && --timeout)
++	etm_writel(t, id, 0x440, ETMR_CTRL);
++	while (!(etm_readl(t, id, ETMR_CTRL) & ETMCTRL_PROGRAM) && --timeout)
+ 		;
+ 	if (!timeout) {
+-		dev_dbg(t->dev, "Waiting for progbit to assert timed out\n");
+-		etm_lock(t);
++		dev_err(t->dev,
++			"etm%d: Waiting for progbit to assert timed out\n",
++			id);
++		etm_lock(t, id);
+ 		return -EFAULT;
+ 	}
+ 
+-	etm_lock(t);
++	etm_lock(t, id);
++	return 0;
++}
++
++static int trace_power_down_etm(struct tracectx *t, int id)
++{
++	unsigned long timeout = TRACER_TIMEOUT;
++	etm_unlock(t, id);
++	while (!(etm_readl(t, id, ETMR_STATUS) & ETMST_PROGBIT) && --timeout)
++		;
++	if (!timeout) {
++		dev_err(t->dev, "etm%d: Waiting for status progbit to assert timed out\n",
++			id);
++		etm_lock(t, id);
++		return -EFAULT;
++	}
++
++	etm_writel(t, id, 0x441, ETMR_CTRL);
++
++	etm_lock(t, id);
++	return 0;
++}
++
++static int trace_stop(struct tracectx *t)
++{
++	int id;
++	unsigned long timeout = TRACER_TIMEOUT;
++	u32 etb_fc = t->etb_fc;
++
++	for (id = 0; id < t->etm_regs_count; id++)
++		trace_stop_etm(t, id);
++
++	for (id = 0; id < t->etm_regs_count; id++)
++		trace_power_down_etm(t, id);
+ 
+ 	etb_unlock(t);
+-	etb_writel(t, ETBFF_MANUAL_FLUSH, ETBR_FORMATTERCTRL);
++	if (etb_fc) {
++		etb_fc |= ETBFF_STOPFL;
++		etb_writel(t, t->etb_fc, ETBR_FORMATTERCTRL);
++	}
++	etb_writel(t, etb_fc | ETBFF_MANUAL_FLUSH, ETBR_FORMATTERCTRL);
+ 
+ 	timeout = TRACER_TIMEOUT;
+ 	while (etb_readl(t, ETBR_FORMATTERCTRL) &
+@@ -185,24 +287,15 @@ static int trace_stop(struct tracectx *t)
+ static int etb_getdatalen(struct tracectx *t)
+ {
+ 	u32 v;
+-	int rp, wp;
++	int wp;
+ 
+ 	v = etb_readl(t, ETBR_STATUS);
+ 
+ 	if (v & 1)
+ 		return t->etb_bufsz;
+ 
+-	rp = etb_readl(t, ETBR_READADDR);
+ 	wp = etb_readl(t, ETBR_WRITEADDR);
+-
+-	if (rp > wp) {
+-		etb_writel(t, 0, ETBR_READADDR);
+-		etb_writel(t, 0, ETBR_WRITEADDR);
+-
+-		return 0;
+-	}
+-
+-	return wp - rp;
++	return wp;
+ }
+ 
+ /* sysrq+v will always stop the running trace and leave it at that */
+@@ -235,21 +328,18 @@ static void etm_dump(void)
+ 		printk("%08x", cpu_to_be32(etb_readl(t, ETBR_READMEM)));
+ 	printk(KERN_INFO "\n--- ETB buffer end ---\n");
+ 
+-	/* deassert the overflow bit */
+-	etb_writel(t, 1, ETBR_CTRL);
+-	etb_writel(t, 0, ETBR_CTRL);
+-
+-	etb_writel(t, 0, ETBR_TRIGGERCOUNT);
+-	etb_writel(t, 0, ETBR_READADDR);
+-	etb_writel(t, 0, ETBR_WRITEADDR);
+-
+ 	etb_lock(t);
+ }
+ 
+ static void sysrq_etm_dump(int key)
+ {
++	if (!mutex_trylock(&tracer.mutex)) {
++		printk(KERN_INFO "Tracing hardware busy\n");
++		return;
++	}
+ 	dev_dbg(tracer.dev, "Dumping ETB buffer\n");
+ 	etm_dump();
++	mutex_unlock(&tracer.mutex);
+ }
+ 
+ static struct sysrq_key_op sysrq_etm_op = {
+@@ -276,6 +366,10 @@ static ssize_t etb_read(struct file *file, char __user *data,
+ 	struct tracectx *t = file->private_data;
+ 	u32 first = 0;
+ 	u32 *buf;
++	int wpos;
++	int skip;
++	long wlength;
++	loff_t pos = *ppos;
+ 
+ 	mutex_lock(&t->mutex);
+ 
+@@ -287,31 +381,39 @@ static ssize_t etb_read(struct file *file, char __user *data,
+ 	etb_unlock(t);
+ 
+ 	total = etb_getdatalen(t);
++	if (total == 0 && t->dump_initial_etb)
++		total = t->etb_bufsz;
+ 	if (total == t->etb_bufsz)
+ 		first = etb_readl(t, ETBR_WRITEADDR);
+ 
++	if (pos > total * 4) {
++		skip = 0;
++		wpos = total;
++	} else {
++		skip = (int)pos % 4;
++		wpos = (int)pos / 4;
++	}
++	total -= wpos;
++	first = (first + wpos) % t->etb_bufsz;
++
+ 	etb_writel(t, first, ETBR_READADDR);
+ 
+-	length = min(total * 4, (int)len);
+-	buf = vmalloc(length);
++	wlength = min(total, DIV_ROUND_UP(skip + (int)len, 4));
++	length = min(total * 4 - skip, (int)len);
++	buf = vmalloc(wlength * 4);
+ 
+-	dev_dbg(t->dev, "ETB buffer length: %d\n", total);
++	dev_dbg(t->dev, "ETB read %ld bytes to %lld from %ld words at %d\n",
++		length, pos, wlength, first);
++	dev_dbg(t->dev, "ETB buffer length: %d\n", total + wpos);
+ 	dev_dbg(t->dev, "ETB status reg: %x\n", etb_readl(t, ETBR_STATUS));
+-	for (i = 0; i < length / 4; i++)
++	for (i = 0; i < wlength; i++)
+ 		buf[i] = etb_readl(t, ETBR_READMEM);
+ 
+-	/* the only way to deassert overflow bit in ETB status is this */
+-	etb_writel(t, 1, ETBR_CTRL);
+-	etb_writel(t, 0, ETBR_CTRL);
+-
+-	etb_writel(t, 0, ETBR_WRITEADDR);
+-	etb_writel(t, 0, ETBR_READADDR);
+-	etb_writel(t, 0, ETBR_TRIGGERCOUNT);
+-
+ 	etb_lock(t);
+ 
+-	length -= copy_to_user(data, buf, length);
++	length -= copy_to_user(data, (u8 *)buf + skip, length);
+ 	vfree(buf);
++	*ppos = pos + length;
+ 
+ out:
+ 	mutex_unlock(&t->mutex);
+@@ -348,28 +450,17 @@ static int etb_probe(struct amba_device *dev, const struct amba_id *id)
+ 	if (ret)
+ 		goto out;
+ 
++	mutex_lock(&t->mutex);
+ 	t->etb_regs = ioremap_nocache(dev->res.start, resource_size(&dev->res));
+ 	if (!t->etb_regs) {
+ 		ret = -ENOMEM;
+ 		goto out_release;
+ 	}
+ 
++	t->dev = &dev->dev;
++	t->dump_initial_etb = true;
+ 	amba_set_drvdata(dev, t);
+ 
+-	etb_miscdev.parent = &dev->dev;
+-
+-	ret = misc_register(&etb_miscdev);
+-	if (ret)
+-		goto out_unmap;
+-
+-	t->emu_clk = clk_get(&dev->dev, "emu_src_ck");
+-	if (IS_ERR(t->emu_clk)) {
+-		dev_dbg(&dev->dev, "Failed to obtain emu_src_ck.\n");
+-		return -EFAULT;
+-	}
+-
+-	clk_enable(t->emu_clk);
+-
+ 	etb_unlock(t);
+ 	t->etb_bufsz = etb_readl(t, ETBR_DEPTH);
+ 	dev_dbg(&dev->dev, "Size: %x\n", t->etb_bufsz);
+@@ -378,6 +469,20 @@ static int etb_probe(struct amba_device *dev, const struct amba_id *id)
+ 	etb_writel(t, 0, ETBR_CTRL);
+ 	etb_writel(t, 0x1000, ETBR_FORMATTERCTRL);
+ 	etb_lock(t);
++	mutex_unlock(&t->mutex);
++
++	etb_miscdev.parent = &dev->dev;
++
++	ret = misc_register(&etb_miscdev);
++	if (ret)
++		goto out_unmap;
++
++	/* Get optional clock. Currently used to select clock source on omap3 */
++	t->emu_clk = clk_get(&dev->dev, "emu_src_ck");
++	if (IS_ERR(t->emu_clk))
++		dev_dbg(&dev->dev, "Failed to obtain emu_src_ck.\n");
++	else
++		clk_enable(t->emu_clk);
+ 
+ 	dev_dbg(&dev->dev, "ETB AMBA driver initialized.\n");
+ 
+@@ -385,9 +490,12 @@ out:
+ 	return ret;
+ 
+ out_unmap:
++	mutex_lock(&t->mutex);
+ 	iounmap(t->etb_regs);
++	t->etb_regs = NULL;
+ 
+ out_release:
++	mutex_unlock(&t->mutex);
+ 	amba_release_regions(dev);
+ 
+ 	return ret;
+@@ -400,8 +508,10 @@ static int etb_remove(struct amba_device *dev)
+ 	iounmap(t->etb_regs);
+ 	t->etb_regs = NULL;
+ 
+-	clk_disable(t->emu_clk);
+-	clk_put(t->emu_clk);
++	if (!IS_ERR(t->emu_clk)) {
++		clk_disable(t->emu_clk);
++		clk_put(t->emu_clk);
++	}
+ 
+ 	amba_release_regions(dev);
+ 
+@@ -445,7 +555,10 @@ static ssize_t trace_running_store(struct kobject *kobj,
+ 		return -EINVAL;
+ 
+ 	mutex_lock(&tracer.mutex);
+-	ret = value ? trace_start(&tracer) : trace_stop(&tracer);
++	if (!tracer.etb_regs)
++		ret = -ENODEV;
++	else
++		ret = value ? trace_start(&tracer) : trace_stop(&tracer);
+ 	mutex_unlock(&tracer.mutex);
+ 
+ 	return ret ? : n;
+@@ -460,36 +573,50 @@ static ssize_t trace_info_show(struct kobject *kobj,
+ {
+ 	u32 etb_wa, etb_ra, etb_st, etb_fc, etm_ctrl, etm_st;
+ 	int datalen;
++	int id;
++	int ret;
+ 
+-	etb_unlock(&tracer);
+-	datalen = etb_getdatalen(&tracer);
+-	etb_wa = etb_readl(&tracer, ETBR_WRITEADDR);
+-	etb_ra = etb_readl(&tracer, ETBR_READADDR);
+-	etb_st = etb_readl(&tracer, ETBR_STATUS);
+-	etb_fc = etb_readl(&tracer, ETBR_FORMATTERCTRL);
+-	etb_lock(&tracer);
+-
+-	etm_unlock(&tracer);
+-	etm_ctrl = etm_readl(&tracer, ETMR_CTRL);
+-	etm_st = etm_readl(&tracer, ETMR_STATUS);
+-	etm_lock(&tracer);
++	mutex_lock(&tracer.mutex);
++	if (tracer.etb_regs) {
++		etb_unlock(&tracer);
++		datalen = etb_getdatalen(&tracer);
++		etb_wa = etb_readl(&tracer, ETBR_WRITEADDR);
++		etb_ra = etb_readl(&tracer, ETBR_READADDR);
++		etb_st = etb_readl(&tracer, ETBR_STATUS);
++		etb_fc = etb_readl(&tracer, ETBR_FORMATTERCTRL);
++		etb_lock(&tracer);
++	} else {
++		etb_wa = etb_ra = etb_st = etb_fc = ~0;
++		datalen = -1;
++	}
+ 
+-	return sprintf(buf, "Trace buffer len: %d\nComparator pairs: %d\n"
++	ret = sprintf(buf, "Trace buffer len: %d\nComparator pairs: %d\n"
+ 			"ETBR_WRITEADDR:\t%08x\n"
+ 			"ETBR_READADDR:\t%08x\n"
+ 			"ETBR_STATUS:\t%08x\n"
+-			"ETBR_FORMATTERCTRL:\t%08x\n"
+-			"ETMR_CTRL:\t%08x\n"
+-			"ETMR_STATUS:\t%08x\n",
++			"ETBR_FORMATTERCTRL:\t%08x\n",
+ 			datalen,
+ 			tracer.ncmppairs,
+ 			etb_wa,
+ 			etb_ra,
+ 			etb_st,
+-			etb_fc,
++			etb_fc
++			);
++
++	for (id = 0; id < tracer.etm_regs_count; id++) {
++		etm_unlock(&tracer, id);
++		etm_ctrl = etm_readl(&tracer, id, ETMR_CTRL);
++		etm_st = etm_readl(&tracer, id, ETMR_STATUS);
++		etm_lock(&tracer, id);
++		ret += sprintf(buf + ret, "ETMR_CTRL:\t%08x\n"
++			"ETMR_STATUS:\t%08x\n",
+ 			etm_ctrl,
+ 			etm_st
+ 			);
++	}
++	mutex_unlock(&tracer.mutex);
++
++	return ret;
+ }
+ 
+ static struct kobj_attribute trace_info_attr =
+@@ -528,42 +655,260 @@ static ssize_t trace_mode_store(struct kobject *kobj,
+ static struct kobj_attribute trace_mode_attr =
+ 	__ATTR(trace_mode, 0644, trace_mode_show, trace_mode_store);
+ 
++static ssize_t trace_contextid_size_show(struct kobject *kobj,
++					 struct kobj_attribute *attr,
++					 char *buf)
++{
++	/* 0: No context id tracing, 1: One byte, 2: Two bytes, 3: Four bytes */
++	return sprintf(buf, "%d\n", (1 << tracer.etm_contextid_size) >> 1);
++}
++
++static ssize_t trace_contextid_size_store(struct kobject *kobj,
++					  struct kobj_attribute *attr,
++					  const char *buf, size_t n)
++{
++	unsigned int contextid_size;
++
++	if (sscanf(buf, "%u", &contextid_size) != 1)
++		return -EINVAL;
++
++	if (contextid_size == 3 || contextid_size > 4)
++		return -EINVAL;
++
++	mutex_lock(&tracer.mutex);
++	tracer.etm_contextid_size = fls(contextid_size);
++	mutex_unlock(&tracer.mutex);
++
++	return n;
++}
++
++static struct kobj_attribute trace_contextid_size_attr =
++	__ATTR(trace_contextid_size, 0644,
++		trace_contextid_size_show, trace_contextid_size_store);
++
++static ssize_t trace_branch_output_show(struct kobject *kobj,
++					struct kobj_attribute *attr,
++					char *buf)
++{
++	return sprintf(buf, "%d\n", !!(tracer.flags & TRACER_BRANCHOUTPUT));
++}
++
++static ssize_t trace_branch_output_store(struct kobject *kobj,
++					 struct kobj_attribute *attr,
++					 const char *buf, size_t n)
++{
++	unsigned int branch_output;
++
++	if (sscanf(buf, "%u", &branch_output) != 1)
++		return -EINVAL;
++
++	mutex_lock(&tracer.mutex);
++	if (branch_output) {
++		tracer.flags |= TRACER_BRANCHOUTPUT;
++		/* Branch broadcasting is incompatible with the return stack */
++		tracer.flags &= ~TRACER_RETURN_STACK;
++	} else {
++		tracer.flags &= ~TRACER_BRANCHOUTPUT;
++	}
++	mutex_unlock(&tracer.mutex);
++
++	return n;
++}
++
++static struct kobj_attribute trace_branch_output_attr =
++	__ATTR(trace_branch_output, 0644,
++		trace_branch_output_show, trace_branch_output_store);
++
++static ssize_t trace_return_stack_show(struct kobject *kobj,
++				  struct kobj_attribute *attr,
++				  char *buf)
++{
++	return sprintf(buf, "%d\n", !!(tracer.flags & TRACER_RETURN_STACK));
++}
++
++static ssize_t trace_return_stack_store(struct kobject *kobj,
++				   struct kobj_attribute *attr,
++				   const char *buf, size_t n)
++{
++	unsigned int return_stack;
++
++	if (sscanf(buf, "%u", &return_stack) != 1)
++		return -EINVAL;
++
++	mutex_lock(&tracer.mutex);
++	if (return_stack) {
++		tracer.flags |= TRACER_RETURN_STACK;
++		/* Return stack is incompatible with branch broadcasting */
++		tracer.flags &= ~TRACER_BRANCHOUTPUT;
++	} else {
++		tracer.flags &= ~TRACER_RETURN_STACK;
++	}
++	mutex_unlock(&tracer.mutex);
++
++	return n;
++}
++
++static struct kobj_attribute trace_return_stack_attr =
++	__ATTR(trace_return_stack, 0644,
++		trace_return_stack_show, trace_return_stack_store);
++
++static ssize_t trace_timestamp_show(struct kobject *kobj,
++				  struct kobj_attribute *attr,
++				  char *buf)
++{
++	return sprintf(buf, "%d\n", !!(tracer.flags & TRACER_TIMESTAMP));
++}
++
++static ssize_t trace_timestamp_store(struct kobject *kobj,
++				   struct kobj_attribute *attr,
++				   const char *buf, size_t n)
++{
++	unsigned int timestamp;
++
++	if (sscanf(buf, "%u", &timestamp) != 1)
++		return -EINVAL;
++
++	mutex_lock(&tracer.mutex);
++	if (timestamp)
++		tracer.flags |= TRACER_TIMESTAMP;
++	else
++		tracer.flags &= ~TRACER_TIMESTAMP;
++	mutex_unlock(&tracer.mutex);
++
++	return n;
++}
++
++static struct kobj_attribute trace_timestamp_attr =
++	__ATTR(trace_timestamp, 0644,
++		trace_timestamp_show, trace_timestamp_store);
++
++static ssize_t trace_range_show(struct kobject *kobj,
++				  struct kobj_attribute *attr,
++				  char *buf)
++{
++	return sprintf(buf, "%08lx %08lx\n",
++			tracer.range_start, tracer.range_end);
++}
++
++static ssize_t trace_range_store(struct kobject *kobj,
++				   struct kobj_attribute *attr,
++				   const char *buf, size_t n)
++{
++	unsigned long range_start, range_end;
++
++	if (sscanf(buf, "%lx %lx", &range_start, &range_end) != 2)
++		return -EINVAL;
++
++	mutex_lock(&tracer.mutex);
++	tracer.range_start = range_start;
++	tracer.range_end = range_end;
++	mutex_unlock(&tracer.mutex);
++
++	return n;
++}
++
++
++static struct kobj_attribute trace_range_attr =
++	__ATTR(trace_range, 0644, trace_range_show, trace_range_store);
++
++static ssize_t trace_data_range_show(struct kobject *kobj,
++				  struct kobj_attribute *attr,
++				  char *buf)
++{
++	unsigned long range_start;
++	u64 range_end;
++	mutex_lock(&tracer.mutex);
++	range_start = tracer.data_range_start;
++	range_end = tracer.data_range_end;
++	if (!range_end && (tracer.flags & TRACER_TRACE_DATA))
++		range_end = 0x100000000ULL;
++	mutex_unlock(&tracer.mutex);
++	return sprintf(buf, "%08lx %08llx\n", range_start, range_end);
++}
++
++static ssize_t trace_data_range_store(struct kobject *kobj,
++				   struct kobj_attribute *attr,
++				   const char *buf, size_t n)
++{
++	unsigned long range_start;
++	u64 range_end;
++
++	if (sscanf(buf, "%lx %llx", &range_start, &range_end) != 2)
++		return -EINVAL;
++
++	mutex_lock(&tracer.mutex);
++	tracer.data_range_start = range_start;
++	tracer.data_range_end = (unsigned long)range_end;
++	if (range_end)
++		tracer.flags |= TRACER_TRACE_DATA;
++	else
++		tracer.flags &= ~TRACER_TRACE_DATA;
++	mutex_unlock(&tracer.mutex);
++
++	return n;
++}
++
++
++static struct kobj_attribute trace_data_range_attr =
++	__ATTR(trace_data_range, 0644,
++		trace_data_range_show, trace_data_range_store);
++
+ static int etm_probe(struct amba_device *dev, const struct amba_id *id)
+ {
+ 	struct tracectx *t = &tracer;
+ 	int ret = 0;
++	void __iomem **new_regs;
++	int new_count;
++	u32 etmccr;
++	u32 etmidr;
++	u32 etmccer = 0;
++	u8 etm_version = 0;
++
++	mutex_lock(&t->mutex);
++	new_count = t->etm_regs_count + 1;
++	new_regs = krealloc(t->etm_regs,
++				sizeof(t->etm_regs[0]) * new_count, GFP_KERNEL);
+ 
+-	if (t->etm_regs) {
+-		dev_dbg(&dev->dev, "ETM already initialized\n");
+-		ret = -EBUSY;
++	if (!new_regs) {
++		dev_dbg(&dev->dev, "Failed to allocate ETM register array\n");
++		ret = -ENOMEM;
+ 		goto out;
+ 	}
++	t->etm_regs = new_regs;
+ 
+ 	ret = amba_request_regions(dev, NULL);
+ 	if (ret)
+ 		goto out;
+ 
+-	t->etm_regs = ioremap_nocache(dev->res.start, resource_size(&dev->res));
+-	if (!t->etm_regs) {
++	t->etm_regs[t->etm_regs_count] =
++		ioremap_nocache(dev->res.start, resource_size(&dev->res));
++	if (!t->etm_regs[t->etm_regs_count]) {
+ 		ret = -ENOMEM;
+ 		goto out_release;
+ 	}
+ 
+-	amba_set_drvdata(dev, t);
++	amba_set_drvdata(dev, t->etm_regs[t->etm_regs_count]);
+ 
+-	mutex_init(&t->mutex);
+-	t->dev = &dev->dev;
+-	t->flags = TRACER_CYCLE_ACC;
++	t->flags = TRACER_CYCLE_ACC | TRACER_TRACE_DATA | TRACER_BRANCHOUTPUT;
+ 	t->etm_portsz = 1;
++	t->etm_contextid_size = 3;
+ 
+-	etm_unlock(t);
+-	(void)etm_readl(t, ETMMR_PDSR);
++	etm_unlock(t, t->etm_regs_count);
++	(void)etm_readl(t, t->etm_regs_count, ETMMR_PDSR);
+ 	/* dummy first read */
+-	(void)etm_readl(&tracer, ETMMR_OSSRR);
+-
+-	t->ncmppairs = etm_readl(t, ETMR_CONFCODE) & 0xf;
+-	etm_writel(t, 0x440, ETMR_CTRL);
+-	etm_lock(t);
++	(void)etm_readl(&tracer, t->etm_regs_count, ETMMR_OSSRR);
++
++	etmccr = etm_readl(t, t->etm_regs_count, ETMR_CONFCODE);
++	t->ncmppairs = etmccr & 0xf;
++	if (etmccr & ETMCCR_ETMIDR_PRESENT) {
++		etmidr = etm_readl(t, t->etm_regs_count, ETMR_ID);
++		etm_version = ETMIDR_VERSION(etmidr);
++		if (etm_version >= ETMIDR_VERSION_3_1)
++			etmccer = etm_readl(t, t->etm_regs_count, ETMR_CCE);
++	}
++	etm_writel(t, t->etm_regs_count, 0x441, ETMR_CTRL);
++	etm_writel(t, t->etm_regs_count, new_count, ETMR_TRACEIDR);
++	etm_lock(t, t->etm_regs_count);
+ 
+ 	ret = sysfs_create_file(&dev->dev.kobj,
+ 			&trace_running_attr.attr);
+@@ -579,32 +924,97 @@ static int etm_probe(struct amba_device *dev, const struct amba_id *id)
+ 	if (ret)
+ 		dev_dbg(&dev->dev, "Failed to create trace_mode in sysfs\n");
+ 
+-	dev_dbg(t->dev, "ETM AMBA driver initialized.\n");
++	ret = sysfs_create_file(&dev->dev.kobj,
++				&trace_contextid_size_attr.attr);
++	if (ret)
++		dev_dbg(&dev->dev,
++			"Failed to create trace_contextid_size in sysfs\n");
++
++	ret = sysfs_create_file(&dev->dev.kobj,
++				&trace_branch_output_attr.attr);
++	if (ret)
++		dev_dbg(&dev->dev,
++			"Failed to create trace_branch_output in sysfs\n");
++
++	if (etmccer & ETMCCER_RETURN_STACK_IMPLEMENTED) {
++		ret = sysfs_create_file(&dev->dev.kobj,
++					&trace_return_stack_attr.attr);
++		if (ret)
++			dev_dbg(&dev->dev,
++			      "Failed to create trace_return_stack in sysfs\n");
++	}
++
++	if (etmccer & ETMCCER_TIMESTAMPING_IMPLEMENTED) {
++		ret = sysfs_create_file(&dev->dev.kobj,
++					&trace_timestamp_attr.attr);
++		if (ret)
++			dev_dbg(&dev->dev,
++				"Failed to create trace_timestamp in sysfs\n");
++	}
++
++	ret = sysfs_create_file(&dev->dev.kobj, &trace_range_attr.attr);
++	if (ret)
++		dev_dbg(&dev->dev, "Failed to create trace_range in sysfs\n");
++
++	if (etm_version < ETMIDR_VERSION_PFT_1_0) {
++		ret = sysfs_create_file(&dev->dev.kobj,
++					&trace_data_range_attr.attr);
++		if (ret)
++			dev_dbg(&dev->dev,
++				"Failed to create trace_data_range in sysfs\n");
++	} else {
++		tracer.flags &= ~TRACER_TRACE_DATA;
++	}
++
++	dev_dbg(&dev->dev, "ETM AMBA driver initialized.\n");
++
++	/* Enable formatter if there are multiple trace sources */
++	if (new_count > 1)
++		t->etb_fc = ETBFF_ENFCONT | ETBFF_ENFTC;
++
++	t->etm_regs_count = new_count;
+ 
+ out:
++	mutex_unlock(&t->mutex);
+ 	return ret;
+ 
+ out_unmap:
+-	iounmap(t->etm_regs);
++	iounmap(t->etm_regs[t->etm_regs_count]);
+ 
+ out_release:
+ 	amba_release_regions(dev);
+ 
++	mutex_unlock(&t->mutex);
+ 	return ret;
+ }
+ 
+ static int etm_remove(struct amba_device *dev)
+ {
+-	struct tracectx *t = amba_get_drvdata(dev);
+-
+-	iounmap(t->etm_regs);
+-	t->etm_regs = NULL;
+-
+-	amba_release_regions(dev);
++	int i;
++	struct tracectx *t = &tracer;
++	void __iomem	*etm_regs = amba_get_drvdata(dev);
+ 
+ 	sysfs_remove_file(&dev->dev.kobj, &trace_running_attr.attr);
+ 	sysfs_remove_file(&dev->dev.kobj, &trace_info_attr.attr);
+ 	sysfs_remove_file(&dev->dev.kobj, &trace_mode_attr.attr);
++	sysfs_remove_file(&dev->dev.kobj, &trace_range_attr.attr);
++	sysfs_remove_file(&dev->dev.kobj, &trace_data_range_attr.attr);
++
++	mutex_lock(&t->mutex);
++	for (i = 0; i < t->etm_regs_count; i++)
++		if (t->etm_regs[i] == etm_regs)
++			break;
++	for (; i < t->etm_regs_count - 1; i++)
++		t->etm_regs[i] = t->etm_regs[i + 1];
++	t->etm_regs_count--;
++	if (!t->etm_regs_count) {
++		kfree(t->etm_regs);
++		t->etm_regs = NULL;
++	}
++	mutex_unlock(&t->mutex);
++
++	iounmap(etm_regs);
++	amba_release_regions(dev);
+ 
+ 	return 0;
+ }
+@@ -614,6 +1024,10 @@ static struct amba_id etm_ids[] = {
+ 		.id	= 0x0003b921,
+ 		.mask	= 0x0007ffff,
+ 	},
++	{
++		.id	= 0x0003b950,
++		.mask	= 0x0007ffff,
++	},
+ 	{ 0, 0 },
+ };
+ 
+@@ -631,6 +1045,8 @@ static int __init etm_init(void)
+ {
+ 	int retval;
+ 
++	mutex_init(&tracer.mutex);
++
+ 	retval = amba_driver_register(&etb_driver);
+ 	if (retval) {
+ 		printk(KERN_ERR "Failed to register etb\n");
+diff --git a/arch/arm/kernel/hibernate.c b/arch/arm/kernel/hibernate.c
+index cfb354f..785c461 100644
+--- a/arch/arm/kernel/hibernate.c
++++ b/arch/arm/kernel/hibernate.c
+@@ -24,6 +24,7 @@
+ #include <asm/sections.h>
+ #include "reboot.h"
+ 
++#ifndef CONFIG_HISI_SNAPSHOT_BOOT
+ int pfn_is_nosave(unsigned long pfn)
+ {
+ 	unsigned long nosave_begin_pfn = virt_to_pfn(&__nosave_begin);
+@@ -42,7 +43,9 @@ void notrace restore_processor_state(void)
+ {
+ 	local_fiq_enable();
+ }
++#endif
+ 
++#ifndef CONFIG_HISI_SNAPSHOT_BOOT
+ /*
+  * Snapshot kernel memory and reset the system.
+  *
+@@ -105,3 +108,4 @@ int swsusp_arch_resume(void)
+ 		resume_stack + ARRAY_SIZE(resume_stack));
+ 	return 0;
+ }
++#endif
+diff --git a/arch/arm/kernel/io.c b/arch/arm/kernel/io.c
+index 9203cf8..9d5a96f 100644
+--- a/arch/arm/kernel/io.c
++++ b/arch/arm/kernel/io.c
+@@ -79,6 +79,8 @@ void _memset_io(volatile void __iomem *dst, int c, size_t count)
+ 		dst++;
+ 	}
+ }
++DEFINE_RAW_SPINLOCK(hisilcon_lock);
++EXPORT_SYMBOL(hisilcon_lock);
+ 
+ EXPORT_SYMBOL(_memcpy_fromio);
+ EXPORT_SYMBOL(_memcpy_toio);
+diff --git a/arch/arm/kernel/kgdb.c b/arch/arm/kernel/kgdb.c
+index a74b53c..2412558 100644
+--- a/arch/arm/kernel/kgdb.c
++++ b/arch/arm/kernel/kgdb.c
+@@ -144,6 +144,8 @@ int kgdb_arch_handle_exception(int exception_vector, int signo,
+ 
+ static int kgdb_brk_fn(struct pt_regs *regs, unsigned int instr)
+ {
++	if (user_mode(regs))
++		return -1;
+ 	kgdb_handle_exception(1, SIGTRAP, 0, regs);
+ 
+ 	return 0;
+@@ -151,6 +153,8 @@ static int kgdb_brk_fn(struct pt_regs *regs, unsigned int instr)
+ 
+ static int kgdb_compiled_brk_fn(struct pt_regs *regs, unsigned int instr)
+ {
++	if (user_mode(regs))
++		return -1;
+ 	compiled_break = 1;
+ 	kgdb_handle_exception(1, SIGTRAP, 0, regs);
+ 
+diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
+index ecefea4..617ec4a 100644
+--- a/arch/arm/kernel/process.c
++++ b/arch/arm/kernel/process.c
+@@ -32,6 +32,7 @@
+ #include <linux/hw_breakpoint.h>
+ #include <linux/leds.h>
+ #include <linux/reboot.h>
++#include <linux/console.h>
+ 
+ #include <asm/cacheflush.h>
+ #include <asm/idmap.h>
+@@ -60,9 +61,46 @@ static const char *isa_modes[] __maybe_unused = {
+   "ARM" , "Thumb" , "Jazelle", "ThumbEE"
+ };
+ 
++#ifdef CONFIG_SMP
++void arch_trigger_all_cpu_backtrace(void)
++{
++	smp_send_all_cpu_backtrace();
++}
++#else
++void arch_trigger_all_cpu_backtrace(void)
++{
++	dump_stack();
++}
++#endif
++
+ extern void call_with_stack(void (*fn)(void *), void *arg, void *sp);
+ typedef void (*phys_reset_t)(unsigned long);
+ 
++#ifdef CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART
++void arm_machine_flush_console(void)
++{
++	printk("\n");
++	pr_emerg("Restarting %s\n", linux_banner);
++	if (console_trylock()) {
++		console_unlock();
++		return;
++	}
++
++	mdelay(50);
++
++	local_irq_disable();
++	if (!console_trylock())
++		pr_emerg("arm_restart: Console was locked! Busting\n");
++	else
++		pr_emerg("arm_restart: Console was locked!\n");
++	console_unlock();
++}
++#else
++void arm_machine_flush_console(void)
++{
++}
++#endif
++
+ /*
+  * A temporary stack to use for CPU reset. This is static so that we
+  * don't clobber it with the identity mapping. When running with this
+@@ -154,6 +192,7 @@ void arch_cpu_idle_prepare(void)
+ 
+ void arch_cpu_idle_enter(void)
+ {
++	idle_notifier_call_chain(IDLE_START);
+ 	ledtrig_cpu(CPU_LED_IDLE_START);
+ #ifdef CONFIG_PL310_ERRATA_769419
+ 	wmb();
+@@ -163,6 +202,7 @@ void arch_cpu_idle_enter(void)
+ void arch_cpu_idle_exit(void)
+ {
+ 	ledtrig_cpu(CPU_LED_IDLE_END);
++	idle_notifier_call_chain(IDLE_END);
+ }
+ 
+ #ifdef CONFIG_HOTPLUG_CPU
+@@ -183,6 +223,16 @@ void arch_cpu_idle_dead(void)
+  */
+ void machine_shutdown(void)
+ {
++#ifdef CONFIG_SMP
++	/*
++	 * Disable preemption so we're guaranteed to
++	 * run to power off or reboot and prevent
++	 * the possibility of switching to another
++	 * thread that might wind up blocking on
++	 * one of the stopped CPUs.
++	 */
++	preempt_disable();
++#endif
+ 	disable_nonboot_cpus();
+ }
+ 
+@@ -231,6 +281,11 @@ void machine_restart(char *cmd)
+ 	local_irq_disable();
+ 	smp_send_stop();
+ 
++
++	/* Flush the console to make sure all the relevant messages make it
++	 * out to the console drivers */
++	arm_machine_flush_console();
++
+ 	if (arm_pm_restart)
+ 		arm_pm_restart(reboot_mode, cmd);
+ 	else
+@@ -245,6 +300,77 @@ void machine_restart(char *cmd)
+ 	while (1);
+ }
+ 
++/*
++ * dump a block of kernel memory from around the given address
++ */
++static void show_data(unsigned long addr, int nbytes, const char *name)
++{
++	int	i, j;
++	int	nlines;
++	u32	*p;
++
++	/*
++	 * don't attempt to dump non-kernel addresses or
++	 * values that are probably just small negative numbers
++	 */
++	if (addr < PAGE_OFFSET || addr > -256UL)
++		return;
++
++	printk("\n%s: %#lx:\n", name, addr);
++
++	/*
++	 * round address down to a 32 bit boundary
++	 * and always dump a multiple of 32 bytes
++	 */
++	p = (u32 *)(addr & ~(sizeof(u32) - 1));
++	nbytes += (addr & (sizeof(u32) - 1));
++	nlines = (nbytes + 31) / 32;
++
++
++	for (i = 0; i < nlines; i++) {
++		/*
++		 * just display low 16 bits of address to keep
++		 * each line of the dump < 80 characters
++		 */
++		printk("%04lx ", (unsigned long)p & 0xffff);
++		for (j = 0; j < 8; j++) {
++			u32	data;
++			if (probe_kernel_address(p, data)) {
++				printk(" ********");
++			} else {
++				printk(" %08x", data);
++			}
++			++p;
++		}
++		printk("\n");
++	}
++}
++
++static void show_extra_register_data(struct pt_regs *regs, int nbytes)
++{
++	mm_segment_t fs;
++
++	fs = get_fs();
++	set_fs(KERNEL_DS);
++	show_data(regs->ARM_pc - nbytes, nbytes * 2, "PC");
++	show_data(regs->ARM_lr - nbytes, nbytes * 2, "LR");
++	show_data(regs->ARM_sp - nbytes, nbytes * 2, "SP");
++	show_data(regs->ARM_ip - nbytes, nbytes * 2, "IP");
++	show_data(regs->ARM_fp - nbytes, nbytes * 2, "FP");
++	show_data(regs->ARM_r0 - nbytes, nbytes * 2, "R0");
++	show_data(regs->ARM_r1 - nbytes, nbytes * 2, "R1");
++	show_data(regs->ARM_r2 - nbytes, nbytes * 2, "R2");
++	show_data(regs->ARM_r3 - nbytes, nbytes * 2, "R3");
++	show_data(regs->ARM_r4 - nbytes, nbytes * 2, "R4");
++	show_data(regs->ARM_r5 - nbytes, nbytes * 2, "R5");
++	show_data(regs->ARM_r6 - nbytes, nbytes * 2, "R6");
++	show_data(regs->ARM_r7 - nbytes, nbytes * 2, "R7");
++	show_data(regs->ARM_r8 - nbytes, nbytes * 2, "R8");
++	show_data(regs->ARM_r9 - nbytes, nbytes * 2, "R9");
++	show_data(regs->ARM_r10 - nbytes, nbytes * 2, "R10");
++	set_fs(fs);
++}
++
+ void __show_regs(struct pt_regs *regs)
+ {
+ 	unsigned long flags;
+@@ -306,6 +432,8 @@ void __show_regs(struct pt_regs *regs)
+ 		printk("Control: %08x%s\n", ctrl, buf);
+ 	}
+ #endif
++
++	show_extra_register_data(regs, 128);
+ }
+ 
+ void show_regs(struct pt_regs * regs)
+diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
+index a8e32aa..9ce02e6 100644
+--- a/arch/arm/kernel/smp.c
++++ b/arch/arm/kernel/smp.c
+@@ -72,6 +72,7 @@ enum ipi_msg_type {
+ 	IPI_CPU_STOP,
+ 	IPI_IRQ_WORK,
+ 	IPI_COMPLETION,
++	IPI_CPU_BACKTRACE,
+ };
+ 
+ static DECLARE_COMPLETION(cpu_running);
+@@ -456,6 +457,7 @@ static const char *ipi_types[NR_IPI] __tracepoint_string = {
+ 	S(IPI_CPU_STOP, "CPU stop interrupts"),
+ 	S(IPI_IRQ_WORK, "IRQ work interrupts"),
+ 	S(IPI_COMPLETION, "completion interrupts"),
++	S(IPI_CPU_BACKTRACE, "CPU backtrace"),
+ };
+ 
+ static void smp_cross_call(const struct cpumask *target, unsigned int ipinr)
+@@ -557,6 +559,58 @@ static void ipi_complete(unsigned int cpu)
+ 	complete(per_cpu(cpu_completion, cpu));
+ }
+ 
++static cpumask_t backtrace_mask;
++static DEFINE_RAW_SPINLOCK(backtrace_lock);
++
++/* "in progress" flag of arch_trigger_all_cpu_backtrace */
++static unsigned long backtrace_flag;
++
++void smp_send_all_cpu_backtrace(void)
++{
++	unsigned int this_cpu = smp_processor_id();
++	int i;
++
++	if (test_and_set_bit(0, &backtrace_flag))
++		/*
++		 * If there is already a trigger_all_cpu_backtrace() in progress
++		 * (backtrace_flag == 1), don't output double cpu dump infos.
++		 */
++		return;
++
++	cpumask_copy(&backtrace_mask, cpu_online_mask);
++	cpu_clear(this_cpu, backtrace_mask);
++
++	pr_info("Backtrace for cpu %d (current):\n", this_cpu);
++	dump_stack();
++
++	pr_info("\nsending IPI to all other CPUs:\n");
++	smp_cross_call(&backtrace_mask, IPI_CPU_BACKTRACE);
++
++	/* Wait for up to 10 seconds for all other CPUs to do the backtrace */
++	for (i = 0; i < 10 * 1000; i++) {
++		if (cpumask_empty(&backtrace_mask))
++			break;
++		mdelay(1);
++	}
++
++	clear_bit(0, &backtrace_flag);
++	smp_mb__after_atomic();
++}
++
++/*
++ * ipi_cpu_backtrace - handle IPI from smp_send_all_cpu_backtrace()
++ */
++static void ipi_cpu_backtrace(unsigned int cpu, struct pt_regs *regs)
++{
++	if (cpu_isset(cpu, backtrace_mask)) {
++		raw_spin_lock(&backtrace_lock);
++		pr_warning("IPI backtrace for cpu %d\n", cpu);
++		show_regs(regs);
++		raw_spin_unlock(&backtrace_lock);
++		cpu_clear(cpu, backtrace_mask);
++	}
++}
++
+ /*
+  * Main handler for inter-processor interrupts
+  */
+@@ -623,6 +677,10 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
+ 		irq_exit();
+ 		break;
+ 
++	case IPI_CPU_BACKTRACE:
++		ipi_cpu_backtrace(cpu, regs);
++		break;
++
+ 	default:
+ 		printk(KERN_CRIT "CPU%u: Unknown IPI message 0x%x\n",
+ 		       cpu, ipinr);
+diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c
+index 89cfdd6..32782d2 100644
+--- a/arch/arm/kernel/topology.c
++++ b/arch/arm/kernel/topology.c
+@@ -23,6 +23,7 @@
+ #include <linux/slab.h>
+ 
+ #include <asm/cputype.h>
++#include <asm/smp_plat.h>
+ #include <asm/topology.h>
+ 
+ /*
+@@ -290,6 +291,142 @@ static struct sched_domain_topology_level arm_topology[] = {
+ };
+ 
+ /*
++ * cluster_to_logical_mask - return cpu logical mask of CPUs in a cluster
++ * @socket_id:		cluster HW identifier
++ * @cluster_mask:	the cpumask location to be initialized, modified by the
++ *			function only if return value == 0
++ *
++ * Return:
++ *
++ * 0 on success
++ * -EINVAL if cluster_mask is NULL or there is no record matching socket_id
++ */
++int cluster_to_logical_mask(unsigned int socket_id, cpumask_t *cluster_mask)
++{
++	int cpu;
++
++	if (!cluster_mask)
++		return -EINVAL;
++
++	for_each_online_cpu(cpu)
++		if (socket_id == topology_physical_package_id(cpu)) {
++			cpumask_copy(cluster_mask, topology_core_cpumask(cpu));
++			return 0;
++		}
++
++	return -EINVAL;
++}
++
++
++#ifdef CONFIG_SCHED_HMP
++
++static const char * const little_cores[] = {
++	"arm,cortex-a7",
++	NULL,
++};
++
++static bool is_little_cpu(struct device_node *cn)
++{
++	const char * const *lc;
++
++	for (lc = little_cores; *lc; lc++)
++		if (of_device_is_compatible(cn, *lc))
++			return true;
++	return false;
++}
++
++void __init arch_get_fast_and_slow_cpus(struct cpumask *fast,
++					struct cpumask *slow)
++{
++	struct device_node *cn = NULL;
++	int cpu;
++
++	cpumask_clear(fast);
++	cpumask_clear(slow);
++
++	/*
++	 * Use the config options if they are given. This helps testing
++	 * HMP scheduling on systems without a big.LITTLE architecture.
++	 */
++	if (strlen(CONFIG_HMP_FAST_CPU_MASK)
++			&& strlen(CONFIG_HMP_SLOW_CPU_MASK)) {
++		if (cpulist_parse(CONFIG_HMP_FAST_CPU_MASK, fast))
++			WARN(1, "Failed to parse HMP fast cpu mask!\n");
++		if (cpulist_parse(CONFIG_HMP_SLOW_CPU_MASK, slow))
++			WARN(1, "Failed to parse HMP slow cpu mask!\n");
++		return;
++	}
++
++	/*
++	 * Else, parse device tree for little cores.
++	 */
++	while ((cn = of_find_node_by_type(cn, "cpu"))) {
++
++		const u32 *mpidr;
++		int len;
++
++		mpidr = of_get_property(cn, "reg", &len);
++		if (!mpidr || len != 4) {
++			pr_err("* %s missing reg property\n", cn->full_name);
++			continue;
++		}
++
++		cpu = get_logical_index(be32_to_cpup(mpidr));
++		if (cpu == -EINVAL) {
++			pr_err("couldn't get logical index for mpidr %x\n",
++							be32_to_cpup(mpidr));
++			break;
++		}
++
++		if (is_little_cpu(cn))
++			cpumask_set_cpu(cpu, slow);
++		else
++			cpumask_set_cpu(cpu, fast);
++	}
++
++	if (!cpumask_empty(fast) && !cpumask_empty(slow))
++		return;
++
++	/*
++	 * We didn't find both big and little cores so let's call all cores
++	 * fast as this will keep the system running, with all cores being
++	 * treated equal.
++	 */
++	cpumask_setall(fast);
++	cpumask_clear(slow);
++}
++
++void __init arch_get_hmp_domains(struct list_head *hmp_domains_list)
++{
++	struct cpumask hmp_fast_cpu_mask;
++	struct cpumask hmp_slow_cpu_mask;
++	struct hmp_domain *domain;
++
++	arch_get_fast_and_slow_cpus(&hmp_fast_cpu_mask, &hmp_slow_cpu_mask);
++
++	/*
++	 * Initialize hmp_domains
++	 * Must be ordered with respect to compute capacity.
++	 * Fastest domain at head of list.
++	 */
++	if (!cpumask_empty(&hmp_slow_cpu_mask)) {
++		domain = (struct hmp_domain *)
++			kmalloc(sizeof(struct hmp_domain), GFP_KERNEL);
++		cpumask_copy(&domain->possible_cpus, &hmp_slow_cpu_mask);
++		cpumask_and(&domain->cpus, cpu_online_mask,
++				&domain->possible_cpus);
++		list_add(&domain->hmp_domains, hmp_domains_list);
++	}
++	domain = (struct hmp_domain *)
++		kmalloc(sizeof(struct hmp_domain), GFP_KERNEL);
++	cpumask_copy(&domain->possible_cpus, &hmp_fast_cpu_mask);
++	cpumask_and(&domain->cpus, cpu_online_mask, &domain->possible_cpus);
++	list_add(&domain->hmp_domains, hmp_domains_list);
++}
++#endif /* CONFIG_SCHED_HMP */
++
++
++/*
+  * init_cpu_topology is called at boot when only one cpu is running
+  * which prevent simultaneous write access to cpu_topology array
+  */
+diff --git a/arch/arm/lib/memcpy.S b/arch/arm/lib/memcpy.S
+index a9b9e22..3d71892 100644
+--- a/arch/arm/lib/memcpy.S
++++ b/arch/arm/lib/memcpy.S
+@@ -55,7 +55,6 @@
+ 	.text
+ 
+ /* Prototype: void *memcpy(void *dest, const void *src, size_t n); */
+-
+ ENTRY(memcpy)
+ 
+ #include "copy_template.S"
+diff --git a/arch/arm/mach-hisi/Kconfig b/arch/arm/mach-hisi/Kconfig
+index cd19433..cd5b7dc 100644
+--- a/arch/arm/mach-hisi/Kconfig
++++ b/arch/arm/mach-hisi/Kconfig
+@@ -1,8 +1,7 @@
+ config ARCH_HISI
+ 	bool "Hisilicon SoC Support"
+-	depends on ARCH_MULTI_V7
+ 	select ARM_AMBA
+-	select ARM_GIC
++	select ARM_GIC if ARCH_MULTI_V7
+ 	select ARM_TIMER_SP804
+ 	select POWER_RESET
+ 	select POWER_RESET_HISI
+@@ -40,6 +39,124 @@ config ARCH_HIX5HD2
+ 	select PINCTRL_SINGLE
+ 	help
+ 	  Support for Hisilicon HIX5HD2 SoC family
++
++config ARCH_HI3519
++	bool "Hisilicon Hi3519 Cortex-a7.Cortex-a17 family" if ARCH_MULTI_V7
++	select HAVE_ARM_ARCH_TIMER
++	select ARM_CCI
++	select ARCH_HAS_RESET_CONTROLLER
++	select RESET_CONTROLLER
++	select PM_OPP
++	select PMC if SMP
++	select NEED_MACH_IO_H if PCI
++	help
++	  Support for Hisilicon Hi3519 Soc family
++
++config ARCH_HI3519V101
++	bool "Hisilicon Hi3519V101 Cortex-a7.Cortex-a17 family" if ARCH_MULTI_V7
++	select HAVE_ARM_ARCH_TIMER
++	select ARM_CCI
++	select ARCH_HAS_RESET_CONTROLLER
++	select RESET_CONTROLLER
++	select PM_OPP
++	select PMC if SMP
++	select NEED_MACH_IO_H if PCI
++	help
++	  Support for Hisilicon Hi3519V101 Soc family
++
++config ARCH_HI3516AV200
++	bool "Hisilicon Hi3516AV200 Cortex-a7.Cortex-a17 family" if ARCH_MULTI_V7
++	select HAVE_ARM_ARCH_TIMER
++	select ARM_CCI
++	select ARCH_HAS_RESET_CONTROLLER
++	select RESET_CONTROLLER
++	select PM_OPP
++	select PMC if SMP
++	select NEED_MACH_IO_H if PCI
++	help
++	  Support for Hisilicon Hi3516AV200 Soc family
++
++config ARCH_HI3559
++	bool "Hisilicon Hi3559 Cortex-a7.Cortex-a17 family" if ARCH_MULTI_V7
++	select HAVE_ARM_ARCH_TIMER
++	select ARM_CCI
++	select ARCH_HAS_RESET_CONTROLLER
++	select RESET_CONTROLLER
++	select PM_OPP
++	select PMC if SMP
++	select NEED_MACH_IO_H if PCI
++	help
++	  Support for Hisilicon Hi3559 Soc family
++
++config ARCH_HI3556
++	bool "Hisilicon Hi3556 Cortex-a7.Cortex-a17 family" if ARCH_MULTI_V7
++	select HAVE_ARM_ARCH_TIMER
++	select ARM_CCI
++	select ARCH_HAS_RESET_CONTROLLER
++	select RESET_CONTROLLER
++	select PM_OPP
++	select PMC if SMP
++	select NEED_MACH_IO_H if PCI
++	help
++	  Support for Hisilicon Hi3556 Soc family
++
++
++if ARCH_HI3519 || ARCH_HI3519V101 || ARCH_HI3559 || ARCH_HI3556 || ARCH_HI3516AV200
++
++config PMC
++	bool
++	help
++	  support power control for Hi3519 or Hi3519V101 or Hi3516AV200 or HI3559 Cortex-a17 or HI3556 Cortex-a17
++
++endif
++
++config ARCH_HI3516CV300
++	bool "Hisilicon Hi3516cv300 arm926ej-s family" if ARCH_MULTI_V5
++	depends on ARCH_MULTI_V5
++	select ARM_VIC
++	select PINCTRL
++	select PINCTRL_SINGLE
++	help
++	  Support for Hisilicon Hi3516cv300 Soc family
++
++config ARCH_HI3536C
++	bool "Hisilicon Hi3536C Cortex-a7 family" if ARCH_MULTI_V7
++	select HAVE_ARM_ARCH_TIMER
++	select ARM_GIC
++	select ARCH_HAS_RESET_CONTROLLER
++	select RESET_CONTROLLER
++	select PINCTRL
++	select PINCTRL_SINGLE
++	select HAVE_ARM_SCU if SMP
++	help
++	  Support for Hisilicon Hi3536C Soc family
++
++config ARCH_HI3531D
++	bool "Hisilicon Hi3531D Cortex-a9 family" if ARCH_MULTI_V7
++	select HAVE_ARM_ARCH_TIMER
++	select ARM_GIC
++	select ARCH_HAS_RESET_CONTROLLER
++	select RESET_CONTROLLER
++	select PINCTRL
++	select PINCTRL_SINGLE
++	select CACHE_L2X0
++	select HAVE_ARM_SCU if SMP
++	select NEED_MACH_IO_H if PCI
++	help
++	  Support for Hisilicon Hi3531D Soc family
++
++config ARCH_HI3521D
++	bool "Hisilicon Hi3521D Cortex-a7 family" if ARCH_MULTI_V7
++	select HAVE_ARM_ARCH_TIMER
++	select ARM_GIC
++	select ARCH_HAS_RESET_CONTROLLER
++	select RESET_CONTROLLER
++	select PINCTRL
++	select PINCTRL_SINGLE
++	select HAVE_ARM_SCU if SMP
++	help
++	  Support for Hisilicon Hi3521D Soc family
++	  
+ endmenu
+ 
+ endif
+diff --git a/arch/arm/mach-hisi/Makefile b/arch/arm/mach-hisi/Makefile
+index 6b7b303..167c7b9 100644
+--- a/arch/arm/mach-hisi/Makefile
++++ b/arch/arm/mach-hisi/Makefile
+@@ -6,4 +6,33 @@ CFLAGS_platmcpm.o	:= -march=armv7-a
+ 
+ obj-y	+= hisilicon.o
+ obj-$(CONFIG_MCPM)		+= platmcpm.o
++ifdef CONFIG_ARCH_HI3519
++obj-$(CONFIG_PMC)		+= pmc_hi3519.o
++endif
++ifdef CONFIG_ARCH_HI3519V101
++obj-$(CONFIG_PMC)		+= pmc_hi3519v101.o
++endif
++ifdef CONFIG_ARCH_HI3516AV200
++obj-$(CONFIG_PMC)		+= pmc_hi3516av200.o
++endif
++ifdef CONFIG_ARCH_HI3559
++obj-$(CONFIG_PMC)		+= pmc_hi3559.o
++obj-$(CONFIG_PM)		+= pwr_hi3559.o
++endif
++ifdef CONFIG_ARCH_HI3556
++obj-$(CONFIG_PMC)		+= pmc_hi3559.o
++obj-$(CONFIG_PM)		+= pwr_hi3559.o
++endif
++obj-$(CONFIG_ARCH_HI3536C)	+= pmc_hi3536c.o
++obj-$(CONFIG_ARCH_HI3531D)	+= pmc_hi3531d.o
++obj-$(CONFIG_ARCH_HI3521D)	+= pmc_hi3521d.o
++
+ obj-$(CONFIG_SMP)		+= platsmp.o hotplug.o headsmp.o
++obj-$(CONFIG_PM)		+= pm.o
++obj-$(CONFIG_CACHE_L2X0)        += l2cache.o
++obj-$(CONFIG_HISI_SNAPSHOT_BOOT) += fastboot/
++ifdef CONFIG_ARCH_MULTI_V5
++obj-$(CONFIG_HISI_SNAPSHOT_BOOT) += hibernate.o swsusp.o
++else
++obj-$(CONFIG_HISI_SNAPSHOT_BOOT) += hibernate.o swsusp.o cpu_helper_a7.o
++endif
+diff --git a/arch/arm/mach-hisi/Makefile.boot b/arch/arm/mach-hisi/Makefile.boot
+new file mode 100644
+index 0000000..a652afa
+--- /dev/null
++++ b/arch/arm/mach-hisi/Makefile.boot
+@@ -0,0 +1,18 @@
++ifdef CONFIG_ARCH_HI3559
++zreladdr-y      := 0x88008000
++else
++ifdef CONFIG_ARCH_HI3556
++zreladdr-y      := 0x83008000
++else
++zreladdr-y      := 0x80008000
++endif
++
++ifdef CONFIG_ARCH_HI3531D
++zreladdr-y      := 0x40008000
++endif
++
++endif
++
++params_phys-y   := 0x00000100
++initrd_phys-y   := 0x00800000
++#LOADADDR       := 0x88000000
+diff --git a/arch/arm/mach-hisi/core.h b/arch/arm/mach-hisi/core.h
+index 88b1f48..3ad3bec 100644
+--- a/arch/arm/mach-hisi/core.h
++++ b/arch/arm/mach-hisi/core.h
+@@ -17,4 +17,38 @@ extern struct smp_operations hix5hd2_smp_ops;
+ extern void hix5hd2_set_cpu(int cpu, bool enable);
+ extern void hix5hd2_cpu_die(unsigned int cpu);
+ 
++extern void hi3519_secondary_startup(void);
++extern void hi3519_cpu_die(unsigned int cpu);
++extern int  hi3519_cpu_kill(unsigned int cpu);
++
++extern void hi3516av200_secondary_startup(void);
++extern void hi3516av200_cpu_die(unsigned int cpu);
++extern int  hi3516av200_cpu_kill(unsigned int cpu);
++
++extern void hi3559_secondary_startup(void);
++extern void hi3559_cpu_die(unsigned int cpu);
++extern int  hi3559_cpu_kill(unsigned int cpu);
++
++extern void hi3536c_secondary_startup(void);
++extern void hi3536c_cpu_die(unsigned int cpu);
++extern int  hi3536c_cpu_kill(unsigned int cpu);
++void hi3536c_scu_power_up(int cpu);
++
++extern void hi3531d_secondary_startup(void);
++extern void hi3531d_cpu_die(unsigned int cpu);
++extern int  hi3531d_cpu_kill(unsigned int cpu);
++void hi3531d_scu_power_up(int cpu);
++
++extern void hi3521d_secondary_startup(void);
++extern void hi3521d_cpu_die(unsigned int cpu);
++extern int  hi3521d_cpu_kill(unsigned int cpu);
++void hi3521d_scu_power_up(int cpu);
++
++extern void hi_pmc_power_up(void);
++extern void hi_pmc_power_up_done(void);
++extern void hi_pmc_set_ac_inactive(void);
++extern void hi_pmc_power_down(void);
++#ifdef CONFIG_ARCH_HI3519
++extern void hi_pmc_kill_cpu(unsigned int cpu);
++#endif
+ #endif
+diff --git a/arch/arm/mach-hisi/cpu_helper_a7.S b/arch/arm/mach-hisi/cpu_helper_a7.S
+new file mode 100644
+index 0000000..5783ef5
+--- /dev/null
++++ b/arch/arm/mach-hisi/cpu_helper_a7.S
+@@ -0,0 +1,835 @@
++#include <asm/memory.h>
++
++        @ Aliases for mode encodings - do not change
++        .equ MODE_USR, 0x10
++        .equ MODE_FIQ, 0x11
++        .equ MODE_IRQ, 0x12
++        .equ MODE_SVC, 0x13
++        .equ MODE_MON, 0x16  @ A-profile (Security Extensions) only
++        .equ MODE_ABT, 0x17
++        .equ MODE_UND, 0x1B
++        .equ MODE_SYS, 0x1F
++        .equ MODE_HYP, 0x1A
++
++        .equ TTBCR_EAE, (1<<31)    @ Are we using LPAE?
++
++        .equ PFR0_THUMB_EE_SUPPORT, (1<<12)
++
++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++
++
++        @ This function takes three arguments
++        @ r0: Destination start address (must be word aligned)
++        @ r1: Source start address (must be word aligned)
++        @ r2: Number of words to copy
++        @ Return value is updated destination pointer (first unwritten word)
++
++        .global copy_words
++copy_words:
++        .func
++        push    {r3}
++        cmp     r2, #0
++        beq     1f
++2:
++        ldr     r3, [r1], #4
++        str     r3, [r0], #4
++        subs    r2, r2, #1
++        bne     2b
++1:
++        pop     {r3}
++        bx      lr
++
++        .endfunc
++
++
++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++        .global save_performance_monitors
++
++save_performance_monitors:
++	.func
++        push    {r4, r8, r9, r10}
++
++        mrc    p15,0,r8,c9,c12,0    @ PMon: Control Register
++        bic    r1,r8,#1
++        mcr    p15,0,r1,c9,c12,0    @ disable counter updates from here
++        isb                         @ 0b0 => PMCR<0>
++        mrc    p15,0,r9,c9,c12,5    @ PMon: Event Counter Selection Register
++        mrc    p15,0,r10,c9,c12,1   @ PMon: Count Enable Set Reg
++        stm    r0!, {r8-r10}
++        mrc    p15,0,r8,c9,c12,2    @ PMon: Count Enable Clear Register
++        mrc    p15,0,r9,c9,c13,0    @ PMon: Cycle Counter Register
++        mrc    p15,0,r10,c9,c12,3   @ PMon: Overflow flag Status Register
++        stm    r0!, {r8-r10}
++        mrc    p15,0,r8,c9,c14,1    @ PMon: Interrupt Enable Set Registern
++        mrc    p15,0,r9,c9,c14,2    @ PMon: Interrupt Enable Clear Register
++        stm    r0!, {r8-r9}
++        mrc    p15,0,r8,c9,c12,0    @ Read PMon Control Register
++        ubfx   r9,r8,#11,#5         @ extract # of event counters, N
++        tst    r9, r9
++        beq    1f
++
++        mov    r8,#0
++0:
++        mcr    p15,0,r8,c9,c12,5    @ PMon: select CounterN
++        isb
++        mrc    p15,0,r3,c9,c13,1    @ PMon: save Event Type Register
++        mrc    p15,0,r4,c9,c13,2    @ PMon: save Event Counter Register
++        stm    r0!, {r3,r4}
++        add    r8,r8,#1             @ increment index
++        @ cmps   r8,r9
++        cmp    r8,r9
++        bne    0b
++
++1:
++        pop    {r4, r8, r9, r10}
++        bx     lr
++        .endfunc
++
++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++
++        .global restore_performance_monitors
++restore_performance_monitors:
++        .func
++        push    {r4-r6, r8-r10, lr}
++                                        @ NOTE: all counters disabled by PMCR
++					@<0> == 0 on reset
++        ldr    r8,[r0]                  @ r8 = PMCR
++        add    r1,r0,#20                @ r1 now points to saved PMOVSR
++        ldr    r9,[r1]                  @ r9 = PMOVSR
++
++        mvn    r2,#0                    @ generate Register of all 1's
++        mcr    p15,0,r2,c9,c14,2        @ disable all counter related interrupts
++        mcr    p15,0,r2,c9,c12,3        @ clear all overflow flags
++        isb
++
++        ubfx   r12,r8,#11,#5            @ extract # of event counters, N (0-31)
++        tst    r12, r12
++        beq    20f
++
++        add    r1,r0,#32                @ r1 now points to the 1st saved event
++					@counter
++        @@ Restore counters
++        mov    r6,#0
++10:
++        mcr    p15,0,r6,c9,c12,5        @ PMon: select CounterN
++        isb
++        ldm    r1!, {r3,r4}             @ Read saved data
++        mcr    p15,0,r3,c9,c13,1        @ PMon: restore Event Type Register
++        mcr    p15,0,r4,c9,c13,2        @ PMon: restore Event Counter Register
++        add    r6,r6,#1                 @ increment index
++        @ cmps   r6,r12
++        cmp    r6,r12
++        bne    10b
++
++20:
++        tst    r9, #0x80000000          @ check for cycle count overflow flag
++        beq    40f
++        mcr    p15,0,r2,c9,c13,0        @ set Cycle Counter to all 1's
++        isb
++        mov    r3, #1
++        mcr    p15,0,r3,c9,c12,0        @ set the PMCR global enable bit
++        mov    r3, #0x80000000
++        mcr    p15,0,r3,c9,c12,1        @ enable the Cycle Counter
++        isb
++
++30:
++        mrc    p15,0,r4,c9,c12,3        @ check cycle count overflow now set
++        movs   r4,r4                    @ test bit<31>
++        bpl    30b
++        mcr    p15,0,r3,c9,c12,2        @ disable the Cycle Counter
++
++40:
++        mov    r1, #0
++        mcr    p15,0,r1,c9,c12,0        @ clear the PMCR global enable bit
++        isb
++
++        @@ Restore left regs but PMCR
++        add    r1,r0,#4                 @ r1 now points to the PMSELR
++        ldm    r1!,{r3,r4}
++        mcr    p15,0,r3,c9,c12,5        @ PMon: Event Counter Selection Reg
++        mcr    p15,0,r4,c9,c12,1        @ PMon: Count Enable Set Reg
++        ldm    r1!, {r3,r4}
++        mcr    p15,0,r4,c9,c13,0        @ PMon: Cycle Counter Register
++        ldm    r1!,{r3,r4}
++        mcr    p15,0,r3,c9,c14,2        @ PMon: Interrupt Enable Clear Reg
++        mcr    p15,0,r4,c9,c14,1        @ PMon: Interrupt Enable Set Reg
++        ldr    r3,[r1]
++        isb
++        ldr    r0,[r0]
++        mcr    p15,0,r0,c9,c12,0        @ restore the PM Control Register
++        isb
++
++        pop    {r4-r6, r8-r10, pc}
++        .endfunc
++
++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++
++        .global save_banked_registers
++save_banked_registers:
++        .func
++
++	PUSH    {r3, lr}
++
++        mrs    r2, CPSR             @ save current mode
++        and    r3, r2, #0x1f        @ If we are in HYP mode then use the virt.
++        cmp    r3, #MODE_HYP        @ instructions to save the banked registers
++        beq    save_in_hyp          @ without changing the mode
++
++        cps    #MODE_SYS            @ switch to System mode
++        str    sp,[r0], #4          @ save the User SP
++        str    lr,[r0], #4          @ save the User LR
++        cps    #MODE_ABT            @ switch to Abort mode
++        str    sp,[r0], #4          @ save the current SP
++        mrs    r3,SPSR
++        stm    r0!,{r3,lr}          @ save the current SPSR, LR
++        cps    #MODE_UND            @ switch to Undefined mode
++        str    sp,[r0], #4          @ save the current SP
++        mrs    r3,SPSR
++        stm    r0!,{r3,lr}          @ save the current SPSR, LR
++        cps    #MODE_IRQ            @ switch to IRQ mode
++        str    sp,[r0], #4          @ save the current SP
++        mrs    r3,SPSR
++        stm    r0!,{r3,lr}          @ save the current SPSR, LR
++        cps    #MODE_FIQ            @ switch to FIQ mode
++        str    SP,[r0], #4          @ save the current SP
++        mrs    r3,SPSR
++        stm    r0!,{r8-r12,lr}      @ save the current SPSR,r8-r12,LR
++        msr    CPSR_cxsf, r2        @ switch back to original mode
++
++        POP     {r3, lr}
++        STR     SP, [r0], #4                    @ save the current SP
++        MRS     r3, SPSR
++        STM     r0!, {r3, r4-r12, LR}           @ save the current SPSR,
++						@ r4-r12,LR
++        dsb
++
++        bx     lr
++
++save_in_hyp :
++        @ mrs  r1, SP_usr           @ rewrite
++        cps    #MODE_SYS            @ switch to System mode
++        str    sp,[r1], #4          @ save the User SP
++        stm    r0!, {r1}
++
++        @ mrs  r1, SP_und           @ rewrite
++        cps    #MODE_UND            @ switch to Undefined mode
++        str    sp,[r1], #4          @ save the current SP
++        @ mrs  r2, SPSR_und         @ rewrite
++        cps    #MODE_UND            @ switch to Undefined mode
++        mrs    r2,SPSR              @ save the current SPSR
++        @ mrs  r3, LR_und           @ rewrite
++        cps    #MODE_UND            @ switch to Undefined mode
++        str    lr,[r3], #4          @ save the current LR
++        stm    r0!, {r1-r3}
++
++        @ mrs  r1, SP_abt           @ rewrite
++        cps    #MODE_ABT            @ switch to Abort mode
++        str    sp,[r1], #4          @ save the current SP
++        @ mrs  r2, SPSR_abt         @ rewrite
++        cps    #MODE_ABT            @ switch to Abort mode
++        mrs    r2,SPSR              @ save the current SPSR
++        @ mrs  r3, LR_abt           @ rewrite
++        str    lr,[r3], #4          @ save the current LR
++        stm    r0!, {r1-r3}
++
++        @ mrs  r1, SP_svc           @ rewrite
++        cps    #MODE_SVC            @ switch to SVC mode
++        str    sp,[r1], #4          @ save the current SP
++        @ mrs  r2, SPSR_svc         @ rewrite
++        cps    #MODE_SVC            @ switch to SVC mode
++        mrs    r2,SPSR              @ save the current SPSR
++        @ mrs  r3, LR_svc           @ rewrite
++        cps    #MODE_SVC            @ switch to SVC mode
++        str    lr,[r3], #4          @ save the current LR
++        stm    r0!, {r1-r3}
++
++        @ mrs  r1, SP_irq           @ rewrite
++        cps    #MODE_IRQ            @ switch to IRQ mode
++        str    sp,[r1], #4          @ save the current SP
++        @ mrs  r2, SPSR_irq         @ rewrite
++        cps    #MODE_IRQ            @ switch to IRQ mode
++        mrs    r2,SPSR              @ save the current SPSR
++        @ mrs  r3, LR_irq           @ rewrite
++        cps    #MODE_IRQ            @ switch to IRQ mode
++        str    lr,[r3], #4          @ save the current LR
++        stm    r0!, {r1-r3}
++
++        @ mrs  r1, SP_fiq           @ rewrite
++        cps    #MODE_FIQ            @ switch to FIQ mode
++        str    sp,[r1], #4          @ save the current SP
++        @ mrs  r2, SPSR_fiq         @ rewrite
++        cps    #MODE_FIQ            @ switch to FIQ mode
++        mrs    r2,SPSR              @ save the current SPSR
++        @ mrs  r3, LR_fiq           @ rewrite
++        cps    #MODE_FIQ            @ switch to FIQ mode
++        str    lr,[r3], #4          @ save the current LR
++        stm    r0!, {r1-r3}
++
++        @ mrs  r1, r8_fiq           @ rewrite
++        @ mrs  r2, r9_fiq           @ rewrite
++        @ mrs  r3, r10_fiq          @ rewrite
++        @ stm  r0!, {r1-r3}         @ rewrite
++        @ mrs  r1, r11_fiq          @ rewrite
++        @ mrs  r2, r12_fiq          @ rewrite
++        @ stm  r0!, {r1-r2}         @ rewrite
++        cps    #MODE_FIQ            @ switch to FIQ mode
++        stm    r0!,{r8-r12}         @ save the current r8-r12
++
++        bx    lr
++        .endfunc
++
++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++
++        .global restore_banked_registers
++restore_banked_registers:
++        .func
++        mrs    r2, CPSR         @ save current mode
++        and    r3, r2, #0x1f    @ If we are in HYP mode then use the virt.
++        cmp    r3, #MODE_HYP    @ instructions to restore the banked registers
++        beq    rest_in_hyp      @ without changing the mode
++
++        cps    #MODE_SYS        @ switch to System mode
++        ldr    sp,[r0],#4       @ restore the User SP
++        ldr    lr,[r0],#4       @ restore the User LR
++        cps    #MODE_ABT        @ switch to Abort mode
++        ldr    sp,[r0],#4       @ restore the current SP
++        ldm    r0!,{r3,lr}      @ restore the current LR
++        msr    SPSR_fsxc,r3     @ restore the current SPSR
++        cps    #MODE_UND        @ switch to Undefined mode
++        ldr    sp,[r0],#4       @ restore the current SP
++        ldm    r0!,{r3,lr}      @ restore the current LR
++        msr    SPSR_fsxc,r3     @ restore the current SPSR
++        cps    #MODE_IRQ        @ switch to IRQ mode
++        ldr    sp,[r0],#4       @ restore the current SP
++        ldm    r0!,{r3,lr}      @ restore the current LR
++        msr    SPSR_fsxc,r3     @ restore the current SPSR
++        cps    #MODE_FIQ        @ switch to FIQ mode
++        ldr    sp,[r0],#4       @ restore the current SP
++        ldm    r0!,{r8-r12,lr}  @ restore the current r8-r12,LR
++        msr    SPSR_fsxc,r4     @ restore the current SPSR
++        msr    CPSR_cxsf, r2    @ switch back to original mode
++
++        LDR     SP, [r0], #4                    @ restore the current SP
++        LDM     r0!, {r3, r4-r12, LR}           @ restore the current r4-r12,LR
++        MSR     SPSR_fsxc, r3                   @ restore the current SPSR
++        dsb
++0:
++        bx     lr
++
++rest_in_hyp:
++        ldm    r0!, {r1}
++        @ msr  SP_usr, r1       @ rewrite
++        cps    #MODE_SYS        @ switch to System mode
++        ldr    sp,[r1],#4       @ restore the User SP
++
++        ldm    r0!, {r1-r3}
++        @ msr  SP_und, r1       @ rewrite
++        cps    #MODE_UND        @ switch to Undefined mode
++        ldr    sp,[r1],#4       @ restore the User SP
++        @ msr  SPSR_und, r2     @ rewrite
++        cps    #MODE_UND        @ switch to Undefined mode
++        msr    SPSR_fsxc,r2     @ restore the current SPSR
++        @ msr  LR_und, r3       @ rewrite
++        cps    #MODE_UND        @ switch to Undefined mode
++        ldr    lr,[r3],#4       @ restore the User LR
++
++        ldm    r0!, {r1-r3}
++        @ msr  SP_abt, r1       @ rewrite
++        cps    #MODE_ABT        @ switch to Abort mode
++        ldr    sp,[r1],#4       @ restore the User SP
++        @ msr  SPSR_abt, r2     @ rewrite
++        cps    #MODE_ABT        @ switch to Abort mode
++        msr    SPSR_fsxc,r2     @ restore the current SPSR
++        @ msr  LR_abt, r3       @ rewrite
++        cps    #MODE_ABT        @ switch to Abort mode
++        ldr    lr,[r3],#4       @ restore the User LR
++
++        ldm    r0!, {r1-r3}
++        @ msr  SP_svc, r1       @ rewrite
++        cps    #MODE_SVC        @ switch to SVC mode
++        ldr    sp,[r1],#4       @ restore the User SP
++        @ msr  SPSR_svc, r2     @ rewrite
++        cps    #MODE_SVC        @ switch to SVC mode
++        msr    SPSR_fsxc,r2     @ restore the current SPSR
++        @ msr  LR_svc, r3       @ rewrite
++        cps    #MODE_SVC        @ switch to SVC mode
++        ldr    lr,[r3],#4       @ restore the User LR
++
++        ldm    r0!, {r1-r3}
++        @ msr  SP_irq, r1       @ rewrite
++        cps    #MODE_IRQ        @ switch to IRQ mode
++        ldr    sp,[r1],#4       @ restore the User SP
++        @ msr  SPSR_irq, r2     @ rewrite
++        cps    #MODE_IRQ        @ switch to IRQ mode
++        msr    SPSR_fsxc,r2     @ restore the current SPSR
++        @ msr  LR_irq, r3       @ rewrite
++        cps    #MODE_IRQ        @ switch to IRQ mode
++        ldr    lr,[r3],#4       @ restore the User LR
++
++        ldm    r0!, {r1-r3}
++        @ msr  SP_fiq, r1       @ rewrite
++        cps    #MODE_FIQ        @ switch to FIQ mode
++        ldr    sp,[r1],#4       @ restore the User SP
++        @ msr  SPSR_fiq, r2     @ rewrite
++        cps    #MODE_FIQ        @ switch to FIQ mode
++        msr    SPSR_fsxc,r2     @ restore the current SPSR
++        @ msr  LR_fiq, r3       @ rewrite
++        cps    #MODE_FIQ        @ switch to FIQ mode
++        ldr    lr,[r3],#4       @ restore the User LR
++
++        @ ldm  r0!, {r1-r3}
++        @ msr  r8_fiq, r1       @ rewrite
++        @ msr  r9_fiq, r2       @ rewrite
++        @ msr  r10_fiq, r3      @ rewrite
++        @ ldm  r0!, {r1-r2}
++        @ msr  r11_fiq, r1      @ rewrite
++        @ msr  r12_fiq, r2      @ rewrite
++        cps    #MODE_FIQ        @ switch to FIQ mode
++        ldm    r0!,{r8-r12}     @ restore the current r8-r12
++
++        bx     lr
++        .endfunc
++
++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++
++        .global save_cp15
++save_cp15:
++        .func
++        @ CSSELR Cache Size Selection Register
++        mrc    p15,2,r3,c0,c0,0
++        str    r3,[r0], #4
++
++        @ IMPLEMENTATION DEFINED - proprietary features:
++        @ (CP15 register 15, TCM support, lockdown support, etc.)
++
++        @ NOTE: IMP DEF registers might have save and restore order that relate
++        @ to other CP15 registers or logical grouping requirements and can
++        @ therefore occur at any point in this sequence.
++        bx     lr
++        .endfunc
++
++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++
++        .global restore_cp15
++restore_cp15:
++        .func
++        @ CSSELR Cache Size Selection Register
++        ldr    r3,[r0], #4
++        mcr    p15,2,r3,c0,c0,0
++
++        bx     lr
++        .endfunc
++
++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++
++        .global save_vfp
++save_vfp:
++        .func
++                                   @ FPU state save/restore.
++                                   @ FPSID,MVFR0 and MVFR1 don't get
++				   @serialized/saved (Read Only).
++        mrc    p15,0,r3,c1,c0,2    @ CPACR allows CP10 and CP11 access
++        ORR    r2,r3,#0xF00000
++        mcr    p15,0,r2,c1,c0,2
++        isb
++        mrc    p15,0,r2,c1,c0,2
++        and    r2,r2,#0xF00000
++        cmp    r2,#0xF00000
++        beq    0f
++        movs   r2, #0
++        b      2f
++
++        @    Save configuration registers and enable.
++0:
++        FMRX   r12,FPEXC          @ vmrs   r12,FPEXC
++        str    r12,[r0],#4        @ Save the FPEXC
++                                  @ Enable FPU access to
++				  @ save/restore the other registers.
++        ldr    r2,=0x40000000
++        FMXR   FPEXC,r2           @ vmsr   FPEXC,r2
++        FMRX   r2,FPSCR           @ vmrs   r2,FPSCR
++        str    r2,[r0],#4         @ Save the FPSCR
++                                  @ Store the VFP-D16 registers.
++        vstm   r0!, {D0-D15}
++                                  @ Check for Advanced SIMD/VFP-D32 support
++        FMRX   r2,MVFR0           @ vmrs   r2,MVFR0
++        and    r2,r2,#0xF         @ extract the A_SIMD bitfield
++        cmp    r2, #0x2
++        blt    1f
++                                  @ Store the Advanced SIMD/VFP-D32
++				  @ additional registers.
++        @vstm   r0!, {D16-D31}
++
++        @ IMPLEMENTATION DEFINED: save any subarchitecture defined state
++        @ NOTE: Don't change the order of the FPEXC and CPACR restores
++        @ Restore the original En bit of FPU.
++1:
++        FMXR   FPEXC,r12          @ vmsr   FPEXC,r12
++
++        @ Restore the original CPACR value.
++2:
++        mcr    p15,0,r3,c1,c0,2
++        bx     lr
++        .endfunc
++
++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++
++        .global restore_vfp
++restore_vfp:
++        .func
++        @ FPU state save/restore. Obviously FPSID,MVFR0 and MVFR1 don't get
++        @ serialized (RO).
++        @ Modify CPACR to allow CP10 and CP11 access
++        mrc    p15,0,r1,c1,c0,2
++        ORR    r2,r1,#0x00F00000
++        mcr    p15,0,r2,c1,c0,2
++                                @ Enable FPU access to save/restore
++				@ the rest of registers.
++        ldr    r2,=0x40000000
++        FMXR   FPEXC, r2        @ vmsr   FPEXC, r2
++                                @ Recover FPEXC and FPSCR. These will
++				@ be restored later.
++        ldm    r0!,{r3,r12}
++                                @ Restore the VFP-D16 registers.
++        vldm   r0!, {D0-D15}
++                                @ Check for Advanced SIMD/VFP-D32 support
++        FMRX   r2, MVFR0        @ vmrs   r2, MVFR0
++        and    r2,r2,#0xF       @ extract the A_SIMD bitfield
++        cmp    r2, #0x2
++        blt    0f
++
++        @ Store the Advanced SIMD/VFP-D32 additional registers.
++        @vldm    r0!, {D16-D31}
++
++        @ IMPLEMENTATION DEFINED: restore any subarchitecture defined state
++0:
++        @ Restore configuration registers and enable.
++        @ Restore FPSCR _before_ FPEXC since FPEXC could disable FPU
++        @ and make setting FPSCR unpredictable.
++        FMXR    FPSCR,r12       @ vmsr    FPSCR,r12
++                                @ Restore FPEXC after FPSCR
++        FMXR    FPEXC,r3        @ vmsr    FPEXC,r3
++                                @ Restore CPACR
++        @ will restore in mt_restore_control_registers
++        @ mcr     p15,0,r1,c1,c0,2
++
++        bx      lr
++        .endfunc
++
++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++@ Function called with two arguments:
++@    r0 contains address to store control registers
++@    r1 is non-zero if we are Secure
++
++        .global save_control_registers
++save_control_registers:
++        .func
++        cmp    r1, #0              @ Are we Secure?
++        mrc    p15,0,r2,c1,c0,1    @ ACTLR - Auxiliary Control Register
++        mrc    p15,0,r3,c1,c0,0    @ SCTLR - System Control Register
++        mrc    p15,0,r12,c1,c0,2   @ CPACR - Coprocessor Access Control
++					@ Register
++        stm    r0!, {r2-r3, r12}
++
++        mrcne    p15,0,r1,c12,c0,1   @ MVBAR - Monitor Vector Base Address
++					@ Register
++        mrcne    p15,0,r2,c1,c1,0    @ Secure Configuration Register
++        mrcne    p15,0,r3,c1,c1,1    @ Secure Debug Enable Register
++        mrcne    p15,0,r12,c1,c1,2   @ Non-Secure Access Control Register
++        stmne    r0!, {r1-r3,r12}
++
++        mrc    p15,0,r1,c13,c0,1    @ CONTEXTIDR
++        mrc    p15,0,r2,c13,c0,2    @ TPIDRURW
++        mrc    p15,0,r3,c13,c0,3    @ TPIDRURO
++        mrc    p15,0,r12,c13,c0,4   @ TPIDRPRW
++        stm    r0!, {r1-r3,r12}
++
++        @ The next two registers are only present if ThumbEE is implemented
++        mrc    p15, 0, r1, c0, c1, 0    @ Read ID_PFR0
++        tst    r1, #PFR0_THUMB_EE_SUPPORT
++        mrcne    p14,6,r1,c0,c0,0    @ TEECR
++        mrcne    p14,6,r2,c1,c0,0    @ TEEHBR
++        stmne    r0!, {r1, r2}
++
++        mrc    p14,7,r1,c1,c0,0    @ JOSCR
++        mrc    p14,7,r2,c2,c0,0    @ JMCR
++        stm    r0!, {r1, r2}
++        bx     lr
++        .endfunc
++
++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++@ Function called with two arguments:
++@    r0 contains address to read control registers
++@    r1 is non-zero if we are Secure
++
++        .global restore_control_registers
++restore_control_registers:
++        .func
++        cmp    r1, #0              @ Are we Secure?
++        ldm    r0!, {r2-r3, r12}
++        mcr    p15,0,r2,c1,c0,1    @ ACTLR - Auxiliary Control Register
++        mcr    p15,0,r3,c1,c0,0    @ SCTLR - System Control Register
++        mcr    p15,0,r12,c1,c0,2   @ CPACR - Coprocessor Access Control
++					@ Register
++
++        ldmne    r0!, {r1-r3,r12}
++        mcrne    p15,0,r1,c12,c0,1   @ MVBAR - Monitor Vector Base Address
++					@ Register
++        mcrne    p15,0,r2,c1,c1,0    @ Secure Configuration Register
++        mcrne    p15,0,r3,c1,c1,1    @ Secure Debug Enable Register
++        mcrne    p15,0,r12,c1,c1,2   @ Non-Secure Access Control Register
++
++        ldm    r0!, {r1-r3,r12}
++        mcr    p15,0,r1,c13,c0,1    @ CONTEXTIDR
++        mcr    p15,0,r2,c13,c0,2    @ TPIDRURW
++        mcr    p15,0,r3,c13,c0,3    @ TPIDRURO
++        mcr    p15,0,r12,c13,c0,4   @ TPIDRPRW
++
++        @ The next two registers are only present if ThumbEE is implemented
++        mrc    p15, 0, r1, c0, c1, 0    @ Read ID_PFR0
++        tst    r1, #PFR0_THUMB_EE_SUPPORT
++        ldmne    r0!, {r1,r2}
++        mcrne    p14,6,r1,c0,c0,0    @ TEECR
++        mcrne    p14,6,r2,c1,c0,0    @ TEEHBR
++
++        ldm    r0!, {r1, r2}
++        mcr    p14,7,r1,c1,c0,0    @ JOSCR
++        mcr    p14,7,r2,c2,c0,0    @ JMCR
++        isb
++        bx    lr
++        .endfunc
++
++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++
++        .global save_mmu
++save_mmu:
++        .func
++        push    {r4, r5, r6, r7}
++        @ ASSUMPTION: no useful fault address / fault status information
++
++        mrc    p15,0,r4,c12,c0,0   @ VBAR
++        mrc    p15,0,r5,c2,c0,2    @ TTBCR
++        tst    r5, #TTBCR_EAE        @ Are we using LPAE?
++
++        @ save 32 or 64 bit TTBRs
++        mrceq    p15,0,r6,c2,c0,0    @ 32 bit TTBR0
++        mrceq    p15,0,r7,c2,c0,1    @ 32 bit TTBR1
++        mrrcne    p15,0,r6,r7,c2     @ 64 bit TTBR0
++        stm    r0!, {r4-r7}
++        mrrcne    p15,1,r6,r7,c2     @ 64 bit TTBR1
++        stmne    r0!, {r6-r7}
++
++        mrc    p15,0,r4,c3,c0,0     @ DACR
++        mrc    p15,0,r5,c7,c4,0     @ PAR
++        mrc    p15,0,r6,c10,c2,0    @ PRRR
++        mrc    p15,0,r7,c10,c2,1    @ NMRR
++        stm    r0!, {r4-r7}
++
++        pop    {r4, r5, r6, r7}
++        bx    lr
++        .endfunc
++
++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++
++        .global restore_mmu
++restore_mmu:
++        .func
++        push    {r4, r5, r6, r7}
++        ldm    r0!, {r4-r7}
++        mcr    p15,0,r4,c12,c0,0    @ VBAR
++        mcr    p15,0,r5,c2,c0,2     @ TTBCR
++
++        tst    r5, #TTBCR_EAE        @ Are we using LPAE?
++
++        @ restore 32 or 64 bit TTBRs
++        mcreq    p15,0,r6,c2,c0,0    @ 32 bit TTBR0
++        mcreq    p15,0,r7,c2,c0,1    @ 32 bit TTBR1
++        mcrrne    p15,0,r6,r7,c2     @ 64-bit TTBR0
++        ldmne    r0!, {r6-r7}
++        mcrrne    p15,1,r6,r7,c2     @ 64-bit TTBR1
++
++        ldm    r0!, {r4-r7}
++        mcr    p15,0,r4,c3,c0,0     @ DACR
++        mcr    p15,0,r5,c7,c4,0     @ PAR
++        mcr    p15,0,r6,c10,c2,0    @ PRRR
++        mcr    p15,0,r7,c10,c2,1    @ NMRR
++
++        pop    {r4, r5, r6, r7}
++        bx    lr
++        .endfunc
++
++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++
++        .global save_mpu
++save_mpu:
++        .func
++        mrc    p15, 0, r1, c0, c0, 4     @ Read MPUIR
++        and    r1, r1, #0xff00
++        lsr    r1, r1, #8                @ Extract number of MPU regions
++
++        @ Loop over the number of regions
++10:
++        cmp    r1, #0
++        beq    20f
++        sub    r1, r1, #1
++        mcr    p15, 0, r1, c6, c2, 0    @ Write RGNR
++        mrc    p15, 0, r2, c6, c1, 0    @ Read MPU Region Base Address Register
++        mrc    p15, 0, r3, c6, c1, 2    @ Read Data MPU Region Size and Enable
++					@ Register
++        mrc    p15, 0, r12, c6, c1, 4   @ Read Region access control Register
++        stm    r0!, {r2, r3, r12}
++        b      10b
++
++20:
++        bx    lr
++        .endfunc
++
++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++
++        .global restore_mpu
++restore_mpu:
++        .func
++        mrc    p15, 0, r1, c0, c0, 4     @ Read MPUIR
++        and    r1, r1, #0xff00
++        lsr    r1, r1, #8                @ Extract number of MPU regions
++
++        @ Loop over the number of regions
++10:
++        cmp    r1, #0
++        beq    20f
++        ldm    r0!, {r2, r3, r12}
++        sub    r1, r1, #1
++        mcr    p15, 0, r1, c6, c2, 0    @ Write RGNR
++        mcr    p15, 0, r2, c6, c1, 0    @ Write MPU Region Base Address
++					@ Register
++        mcr    p15, 0, r3, c6, c1, 2    @ Write Data MPU Region Size and Enable
++					@ Register
++        mcr    p15, 0, r12, c6, c1, 4   @ Write Region access control Register
++        b      10b
++
++20:
++        bx     lr
++        .endfunc
++
++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++
++
++
++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++@ If r1 is 0, we assume that the OS is not using the Virtualization extensions,
++@ and that the warm boot code will set up CNTHCTL correctly. If r1 is non-zero
++@ then CNTHCTL is saved and restored
++@ CNTP_CVAL will be preserved as it is in the always-on domain.
++
++        .global save_generic_timer
++save_generic_timer:
++        .func
++        mrc    p15,0,r2,c14,c2,1        @ read CNTP_CTL
++        mrc    p15,0,r3,c14,c2,0        @ read CNTP_TVAL
++        mrc    p15,0,r12,c14,c1,0       @ read CNTKCTL
++        stm    r0!, {r2, r3, r12}
++        cmp    r1, #0
++        mrcne  p15,4,r1,c14,c1,0        @ read CNTHCTL
++        strne  r1, [r0], #4
++        bx     lr
++        .endfunc
++
++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++
++        .global restore_generic_timer
++restore_generic_timer:
++        .func
++        ldm    r0!, {r2, r3, r12}
++        mcr    p15,0,r3,c14,c2,0        @ write CNTP_TVAL
++        mcr    p15,0,r12,c14,c1,0       @ write CNTKCTL
++        mcr    p15,0,r2,c14,c2,1        @ write CNTP_CTL
++        cmp    r1, #0
++        ldrne  r1, [r0], #4
++        mcrne  p15,4,r1,c14,c1,0        @ write CNTHCTL
++        bx     lr
++        .endfunc
++
++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++
++        .global save_fault_status
++save_fault_status:
++        .func
++        mrc    p15,0,r1,c6,c0,0    @ read DFAR
++        mrc    p15,0,r2,c6,c0,2    @ read IFAR
++        mrc    p15,0,r3,c5,c0,0    @ read DFSR
++        mrc    p15,0,r12,c5,c0,1   @ read IFSR
++        stm    r0!, {r1,r2,r3,r12}
++        mrc    p15,0,r1,c5,c1,0    @ read ADFSR
++        mrc    p15,0,r2,c5,c1,1    @ read AIFSR
++        stm    r0!, {r1,r2}
++        bx    lr
++        .endfunc
++
++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++
++        .global restore_fault_status
++restore_fault_status:
++        .func
++        ldm    r0!, {r1,r2,r3,r12}
++        mcr    p15,0,r1,c6,c0,0    @ write DFAR
++        mcr    p15,0,r2,c6,c0,2    @ write IFAR
++        mcr    p15,0,r3,c5,c0,0    @ write DFSR
++        mcr    p15,0,r12,c5,c0,1   @ write IFSR
++        ldm    r0!, {r1,r2}
++        mcr    p15,0,r1,c5,c1,0    @ write ADFSR
++        mcr    p15,0,r2,c5,c1,1    @ write AIFSR
++        bx     lr
++        .endfunc
++
++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++
++        .global write_cntp_ctl
++write_cntp_ctl:
++        .func
++        mcr	p15, 0, r0, c14, c2, 1
++        dsb
++        isb
++        bx      lr
++        .endfunc
++
++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++
++        .global read_cpuid
++read_cpuid:
++        .func
++        mrc   p15, 0, r0, c0, c0, 5
++        ands  r0, r0, #0xf
++        bx    lr
++        .endfunc
++
++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++
++        .global read_clusterid
++read_clusterid:
++        .func
++        mrc   p15, 0, r0, c0, c0, 5
++        lsr   r0, r0, #0x8
++        ands  r0, r0, #0xf
++        bx    lr
++        .endfunc
++
++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++
++        .global read_nsacr
++read_nsacr:
++        .func
++        mrc   p15, 0, r0, c1, c1, 2
++        bx    lr
++        .endfunc
++
++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++
++        .global invalidate_unified_TLB_inner_shareable
++invalidate_unified_TLB_inner_shareable:
++        .func
++        mov    r0, #0
++        mcr    p15, 0, r0, c8, c3, 0
++        bx     lr
++        .endfunc
++
++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+diff --git a/arch/arm/mach-hisi/fastboot/Makefile b/arch/arm/mach-hisi/fastboot/Makefile
+new file mode 100644
+index 0000000..99e1a02
+--- /dev/null
++++ b/arch/arm/mach-hisi/fastboot/Makefile
+@@ -0,0 +1,4 @@
++obj-y += hibernate_umh.o
++obj-y += hibernate_misc.o
++obj-y += hibernate_pmmon.o
++#obj-y += hibernate_fs.o
+diff --git a/arch/arm/mach-hisi/fastboot/fastboot_bootldr_info.c b/arch/arm/mach-hisi/fastboot/fastboot_bootldr_info.c
+new file mode 100644
+index 0000000..1d62568
+--- /dev/null
++++ b/arch/arm/mach-hisi/fastboot/fastboot_bootldr_info.c
+@@ -0,0 +1,258 @@
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/proc_fs.h>
++#include <linux/seq_file.h>
++
++/* error message prefix */
++#define ERRP "bootinfo: "
++
++/* debug macro */
++#if 0
++#define dbg(x) do { printk("BOOTINFO-CMDLINE-PART: "); printk x; } while(0)
++#else
++#define dbg(x)
++#endif
++
++struct boot_partition {
++	char *name;
++	uint64_t size;
++	uint64_t offset;
++};
++
++struct cmdline_boot_partition {
++	int num_parts;
++	struct boot_partition *parts;
++};
++
++static char *bootpart_cmdline;
++
++static struct cmdline_boot_partition *boot_partitions;
++
++int __init fastboot_find_bootpartition(const char *name,
++		unsigned long long *offset, unsigned long long *size)
++{
++	struct boot_partition *part;
++	int i;
++
++	if (!boot_partitions) {
++		pr_err("%s: could not found partinfo\n", __func__);
++		return -EFAULT;
++	}
++
++	for (i = 0; i < boot_partitions->num_parts; i++) {
++		part = boot_partitions->parts + i;
++		if (strcmp(name, part->name) == 0) {
++			*offset = part->offset;
++			*size = part->size;
++			return 0;
++		}
++	}
++
++	pr_err("%s: could not found %s\n", __func__, name);
++	return -ENOENT;
++}
++
++/* strongly based on drivers/mtd/cmdlinepart.c */
++static struct boot_partition __init *newbootpart(char *s,
++		char **retptr,
++		int *num_parts,
++		int this_part,
++		unsigned char **extra_mem_ptr,
++		int extra_mem_size)
++{
++	struct boot_partition *parts;
++	unsigned long long size;
++	unsigned long long offset = 0;
++	char *name;
++	int name_len;
++	unsigned char *extra_mem;
++	char delim;
++
++	size = memparse(s, &s);
++
++	/* check for offset */
++	if (*s == '@') {
++		s++;
++		offset = memparse(s, &s);
++	}
++	/* now look for name */
++	delim = 0;
++	if (*s == '(')
++		delim = ')';
++
++	if (delim) {
++		char *p;
++		name = ++s;
++		p = strchr(name, delim);
++		if (!p) {
++			pr_err(ERRP "no closing %c found\n", delim);
++			return NULL;
++		}
++		name_len = p - name;
++		s = p + 1;
++	} else {
++		name = NULL;
++		name_len = 13; /* Partition_000 */
++	}
++
++	/* record name length for memory allocation later */
++	extra_mem_size += name_len + 1;
++
++	/* test if more partitions are following */
++	if (*s == ',') {
++		/* more partitions follow, parse them */
++		parts = newbootpart(s + 1, &s, num_parts, this_part + 1,
++				&extra_mem, extra_mem_size);
++		if (!parts)
++			return NULL;
++	} else {
++		/* this is the last partition: allocate space for all */
++		int alloc_size;
++
++		*num_parts = this_part + 1;
++		alloc_size = *num_parts * sizeof(struct boot_partition)
++				+ extra_mem_size;
++		parts = kzalloc(alloc_size, GFP_KERNEL);
++		if (!parts) {
++			pr_err(ERRP "out of memory\n");
++			return NULL;
++		}
++		extra_mem = (unsigned char *)(parts + *num_parts);
++	}
++
++	/* enter this partition (offset will be calculated later if it is zero at this point) */
++	parts[this_part].size = size;
++	parts[this_part].offset = offset;
++	if (name)
++		strlcpy(extra_mem, name, name_len + 1);
++	else
++		sprintf(extra_mem, "Partition_%03d", this_part);
++	parts[this_part].name = extra_mem;
++	extra_mem += name_len + 1;
++
++	dbg(("partition %d: name <%s>, offset %llx, size %llx\n",
++		this_part,
++		parts[this_part].name,
++		parts[this_part].offset,
++		parts[this_part].size));
++
++	/* return (updated) pointer to extra_mem memory */
++	if (extra_mem_ptr)
++		*extra_mem_ptr = extra_mem;
++
++	/* return (updated) pointer command line string */
++	*retptr = s;
++
++	/* return partition table */
++	return parts;
++}
++
++/* strongly based on drivers/mtd/cmdlinepart.c */
++static int __init bootpart_cmdline_parse(char *s)
++{
++	struct cmdline_boot_partition *this_bootpart = NULL;
++	struct boot_partition *parts = NULL;
++	int num_parts;
++
++	if (!s)
++		return 0;
++
++	parts = newbootpart(s,		/* cmdline */
++			&s,		/* out: updated cmdline ptr */
++			&num_parts,	/* out: number of parts */
++			0,		/* first partition */
++			(unsigned char**)&this_bootpart, /* out: extra mem */
++			sizeof(*this_bootpart) + sizeof(void*)-1 /*alignment*/);
++	if(!parts) {
++		/*
++		 * An error occurred. We're either:
++		 * a) out of memory, or
++		 * b) in the middle of the partition spec
++		 * Either way, this part is hosed and we're
++		 * unlikely to succeed in parsing any more
++		 */
++		 return 0;
++	 }
++
++	/* align this_bootpart */
++	this_bootpart = (struct cmdline_boot_partition *)
++			ALIGN((unsigned long)this_bootpart, sizeof(void*));
++	/* enter results */
++	this_bootpart->parts = parts;
++	this_bootpart->num_parts = num_parts;
++
++	/* does another spec follow? */
++	if (*s != '\0')
++		pr_err(ERRP "bad character after partition (%c)\n", *s);
++
++	boot_partitions = this_bootpart;
++
++	return 0;
++}
++
++static void *bootpartinfo_seq_start(struct seq_file *file, loff_t *index)
++{
++	if (!boot_partitions)
++		return NULL;
++	if (*index >= boot_partitions->num_parts)
++		return NULL;
++	return boot_partitions->parts + *index;
++}
++
++static void *bootpartinfo_seq_next(struct seq_file *file, void *data,
++		loff_t *index)
++{
++	if (data == NULL)
++		return NULL;
++	if (!boot_partitions)
++		return NULL;
++	(*index)++;
++	if (*index >= boot_partitions->num_parts)
++		return NULL;
++	return boot_partitions->parts + *index;
++}
++
++static void bootpartinfo_seq_stop(struct seq_file *file, void *data)
++{
++}
++
++static int bootpartinfo_seq_show(struct seq_file *file, void *data)
++{
++	struct boot_partition *bpart = data;
++	return seq_printf(file, "0x%016llx@0x%016llx: %s\n",
++			bpart->size, bpart->offset, bpart->name);
++}
++
++static const struct seq_operations bootpartinfo_seq_ops = {
++	.start = bootpartinfo_seq_start,
++	.next = bootpartinfo_seq_next,
++	.stop = bootpartinfo_seq_stop,
++	.show = bootpartinfo_seq_show,
++};
++
++static int bootpartinfo_proc_open(struct inode *inode, struct file *file)
++{
++	return seq_open(file, &bootpartinfo_seq_ops);
++}
++
++static const struct file_operations bootpartinfo_proc_fops = {
++	.open = bootpartinfo_proc_open,
++	.read = seq_read,
++	.llseek = seq_lseek,
++	.release = seq_release,
++};
++
++static int __init fastboot_bootloader_info_init(void)
++{
++	bootpart_cmdline_parse(bootpart_cmdline);
++	proc_create("bootpartinfo", 0444, NULL, &bootpartinfo_proc_fops);
++	return 0;
++}
++module_init(fastboot_bootloader_info_init);
++
++static int __init bootpart_setup(char *s)
++{
++	bootpart_cmdline = s;
++	return 1;
++}
++__setup("bootparts=", bootpart_setup);
+diff --git a/arch/arm/mach-hisi/fastboot/fastboot_pm.h b/arch/arm/mach-hisi/fastboot/fastboot_pm.h
+new file mode 100644
+index 0000000..277781c
+--- /dev/null
++++ b/arch/arm/mach-hisi/fastboot/fastboot_pm.h
+@@ -0,0 +1,8 @@
++
++extern int fastboot_pm_call_umh(char *event_str, unsigned long event);
++
++extern void __exit fastboot_hibernation_misc_exit(void);
++extern int __init fastboot_hibernation_misc_init(void);
++
++extern int fastboot_hibernate_fs_suspend(void);
++extern int fastboot_hibernate_fs_resume(void);
+diff --git a/arch/arm/mach-hisi/fastboot/hibernate_bdev.c b/arch/arm/mach-hisi/fastboot/hibernate_bdev.c
+new file mode 100644
+index 0000000..4eee2e6
+--- /dev/null
++++ b/arch/arm/mach-hisi/fastboot/hibernate_bdev.c
+@@ -0,0 +1,261 @@
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/module.h>
++#include <linux/list.h>
++#include <linux/fs.h>
++#include <linux/blkdev.h>
++#include <linux/blkpg.h>
++#include <linux/spinlock.h>
++#include <linux/hdreg.h>
++#include <linux/init.h>
++#include <linux/mutex.h>
++#include <linux/kthread.h>
++#include <asm/uaccess.h>
++
++struct hibernate_bdev {
++	const char *path;
++	struct mutex lock;
++	int devidx;
++	struct gendisk *disk;
++	struct request_queue *rq;
++	spinlock_t queue_lock;
++	struct task_struct *thread;
++	struct file *filp;
++	atomic_t opened;
++	void *priv;
++};
++
++static int HB_BDEV_MAJOR = 0;
++static const char *HB_BDEV_NAME = "hb_bdev";
++
++static sector_t HB_OFFSET;
++static sector_t HB_SIZE;
++
++extern int __init fastboot_find_bootpartition(const char *name,
++		unsigned long long *offset, unsigned long long *size);
++
++static int hb_bdev_thread(void *arg);
++
++static inline int __hb_init_env(void)
++{
++	unsigned long long ofs, sz;
++	int n = fastboot_find_bootpartition("hibernate", &ofs, &sz);
++	if (n < 0)
++		return n;
++	HB_OFFSET = ofs >> 9;
++	HB_SIZE = sz >> 9;
++
++	if (!HB_BDEV_MAJOR)
++		HB_BDEV_MAJOR = register_blkdev(HB_BDEV_MAJOR, HB_BDEV_NAME);
++
++	return 0;
++}
++
++static int hb_bdev_open(struct block_device *bdev, fmode_t mode)
++{
++	struct hibernate_bdev *hb = bdev->bd_disk->private_data;
++
++	int devidx = MINOR(bdev->bd_dev);
++	if (!hb)
++		return -ERESTARTSYS;
++
++	if (IS_ERR_OR_NULL(hb->filp)) {
++		hb->filp = filp_open(hb->path, O_RDWR|O_SYNC | O_LARGEFILE, 0);
++		if (!hb->filp)
++			hb->filp = ERR_PTR(-ERESTARTSYS);
++		if (!IS_ERR(hb->filp)) {
++			hb->thread = kthread_run(hb_bdev_thread, hb,
++					"%s%d", HB_BDEV_NAME, devidx);
++			if (IS_ERR(hb->thread)) {
++				int ret = PTR_ERR(hb->thread);
++				filp_close(hb->filp, current->files);
++				hb->filp = ERR_PTR(-ERESTARTSYS);
++				return ret;
++			}
++		}
++	}
++
++	if (IS_ERR_OR_NULL(hb->filp))
++		return PTR_ERR(hb->filp);
++
++	atomic_inc(&hb->opened);
++	return 0;
++}
++
++static int hb_bdev_release(struct gendisk *disk, fmode_t mode)
++{
++	struct hibernate_bdev *hb = disk->private_data;
++	if (!hb)
++		return -ENXIO;
++	if (atomic_dec_and_test(&hb->opened)) {
++		kthread_stop(hb->thread);
++		if (!IS_ERR_OR_NULL(hb->filp))
++			filp_close(hb->filp, current->files);
++		hb->filp = ERR_PTR(-ENODEV);
++	}
++	return 0;
++}
++
++static const struct block_device_operations hb_bdev_ops = {
++	.owner		= THIS_MODULE,
++	.open		= hb_bdev_open,
++	.release	= hb_bdev_release,
++};
++
++static int hb_bdev_do_request(struct hibernate_bdev *hb,
++			       struct request *req)
++{
++	unsigned long long offset_tmp;
++	unsigned long long offset, len;
++	char *buf;
++	int ret;
++
++	if (!hb->filp)
++		return -ENODEV;
++    /*modify because linux3.x change, --liucan*/
++#if 0
++	if (!blk_fs_request(req))
++		return -EIO;
++#else
++    if (req->cmd_type != REQ_TYPE_FS)
++        return 0;
++#endif
++
++	if (blk_rq_pos(req) + blk_rq_cur_sectors(req) >
++			get_capacity(req->rq_disk))
++		return -ENOSPC;
++
++	offset = (blk_rq_pos(req) + HB_OFFSET) << 9;
++	len = blk_rq_cur_bytes(req);
++	buf = req->buffer;
++
++	offset_tmp = offset;
++
++	switch(rq_data_dir(req)) {
++	case READ:
++		ret = vfs_read(hb->filp, (char __user*)buf, len, &offset_tmp);
++		rq_flush_dcache_pages(req);
++		break;
++	case WRITE:
++		rq_flush_dcache_pages(req);
++		ret = vfs_write(hb->filp, (char __user*)buf, len, &offset_tmp);
++		break;
++	default:
++		pr_err("%s: Unknown request %u\n", __func__, rq_data_dir(req));
++		return -EIO;
++	}
++
++	if (ret < 0)
++		return ret;
++
++	return 0;
++}
++
++static int hb_bdev_thread(void *arg)
++{
++	struct hibernate_bdev *hb = arg;
++	struct request_queue *rq = hb->rq;
++	struct request *req = NULL;
++
++	set_fs(get_ds());
++
++	spin_lock_irq(rq->queue_lock);
++
++	while (!kthread_should_stop()) {
++		int res;
++
++		if (!req && !(req = blk_fetch_request(rq))) {
++			set_current_state(TASK_INTERRUPTIBLE);
++			spin_unlock_irq(rq->queue_lock);
++			schedule();
++			spin_lock_irq(rq->queue_lock);
++			continue;
++		}
++
++		spin_unlock_irq(rq->queue_lock);
++
++		mutex_lock(&hb->lock);
++		res = hb_bdev_do_request(hb, req);
++		mutex_unlock(&hb->lock);
++
++		spin_lock_irq(rq->queue_lock);
++
++		if (!__blk_end_request_cur(req, res))
++			req = NULL;
++	}
++
++	if (req)
++		__blk_end_request_all(req, -EIO);
++
++	spin_unlock_irq(rq->queue_lock);
++
++	return 0;
++}
++
++static void hb_bdev_request(struct request_queue *rq)
++{
++	struct hibernate_bdev *hb;
++	struct request *req = NULL;
++
++	hb = rq->queuedata;
++
++	if (!hb)
++		while ((req = blk_fetch_request(rq)) != NULL)
++			__blk_end_request_all(req, -ENODEV);
++	else
++		wake_up_process(hb->thread);
++}
++
++static int hibernate_add_blkdev(int devidx, const char *path)
++{
++	struct hibernate_bdev *hb;
++	struct gendisk *gd;
++
++	hb = kzalloc(sizeof(*hb), GFP_KERNEL);
++	if (!hb)
++		return -ENOMEM;
++	hb->path = path;
++	mutex_init(&hb->lock);
++	atomic_set(&hb->opened, 0);
++	hb->filp = ERR_PTR(-ENODEV);
++
++	gd = alloc_disk(1);
++	if (!gd) {
++		kfree(hb);
++		return -ENOMEM;
++	}
++
++	hb->disk = gd;
++	gd->private_data = hb;
++	gd->major = HB_BDEV_MAJOR;
++	gd->first_minor = devidx;
++	gd->fops = &hb_bdev_ops;
++	snprintf(gd->disk_name, sizeof(gd->disk_name), "%s%d",
++			HB_BDEV_NAME, devidx);
++
++	set_capacity(gd, HB_SIZE);
++
++	spin_lock_init(&hb->queue_lock);
++	hb->rq = blk_init_queue(hb_bdev_request, &hb->queue_lock);
++	if (!hb->rq) {
++		kfree(gd);
++		kfree(hb);
++		return -ENOMEM;
++	}
++	hb->rq->queuedata = hb;
++	blk_queue_logical_block_size(hb->rq, 4096);
++	gd->queue = hb->rq;
++
++	add_disk(gd);
++
++	return 0;
++}
++
++static int __init hibernate_bdev_init(void)
++{
++	if (__hb_init_env() < 0)
++		return 0;
++	hibernate_add_blkdev(0, "/dev/block/mmcblk0");
++	return 0;
++}
++late_initcall(hibernate_bdev_init);
+diff --git a/arch/arm/mach-hisi/fastboot/hibernate_fs.c b/arch/arm/mach-hisi/fastboot/hibernate_fs.c
+new file mode 100644
+index 0000000..6e179fe
+--- /dev/null
++++ b/arch/arm/mach-hisi/fastboot/hibernate_fs.c
+@@ -0,0 +1,1910 @@
++/*
++ * Todo
++ *  - save & restore inotify kernel space watches
++ *  - save & restore eventpolls
++ *  - save & restore file locks
++ *  - save & restore file mapping
++ */
++
++#include <linux/syscalls.h>
++#include <linux/string.h>
++#include <linux/device.h>
++#include <linux/kmod.h>
++#include <linux/fs.h>
++#include <linux/mount.h>
++#include <linux/pm.h>
++#include <linux/freezer.h>
++#include <linux/slab.h>
++#include <linux/fdtable.h>
++#include <linux/file.h>
++#include <linux/freezer.h>
++#include <linux/namei.h>
++#include <linux/fs_struct.h>
++#include <linux/mnt_namespace.h>
++#include <linux/fsnotify_backend.h>
++#include <linux/inotify.h>
++#include <linux/backing-dev.h>
++#include <linux/anon_inodes.h>
++#include <linux/security.h>
++#include <linux/module.h>
++#include <linux/sysctl.h>
++#include <linux/suspend.h>
++
++#define pr_err_bug_if(condition, fmt, ...)				\
++	do {								\
++		if (unlikely(condition)) {				\
++			printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__);	\
++			BUG();						\
++		}							\
++	} while (0)
++
++#define pr_err_if(condition, fmt, ...)					\
++	do {								\
++		if (unlikely(condition))				\
++			printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__);	\
++	} while (0)
++
++
++struct saved_mountpoint {
++	struct list_head node;
++	char *dev_name;
++	char *dir_name;
++	char *type;
++	char *data;
++#define MNT_MOVED (MNT_INTERNAL	<< 1)
++	unsigned long flags;
++};
++
++static LIST_HEAD(saved_mountpoints);
++
++static char path_buf_a[PATH_MAX];
++static char path_buf_b[PATH_MAX];
++
++static inline char *__d_path_wrapper(struct path *path, bool b)
++{
++	if (!b)
++		return d_path(path, &path_buf_a[0], sizeof(path_buf_a));
++	else
++		return d_path(path, &path_buf_b[0], sizeof(path_buf_b));
++}
++
++static inline char *d_path_wrapper(struct path *path)
++{
++	return __d_path_wrapper(path, 0);
++}
++
++static inline char *d_path_of_file(struct file *file)
++{
++	return d_path_wrapper(&file->f_path);
++}
++
++static inline char *d_path_of_mnt(struct vfsmount *mnt)
++{
++	struct path mntpath = { .dentry = mnt->mnt_root, .mnt = mnt };
++	return d_path_wrapper(&mntpath);
++}
++
++static bool is_rw_bdev(struct vfsmount *mnt)
++{
++	struct super_block *sb;
++	bool rw_bdev = false;
++
++	if (!mnt || !mnt->mnt_sb)
++		goto out;
++
++	spin_lock(&sb_lock);
++	sb = mnt->mnt_sb;
++
++	if (!hlist_unhashed(&sb->s_instances) &&
++	    MAJOR(sb->s_dev) != 0 &&
++	    sb->s_bdi != &noop_backing_dev_info &&
++	    !__mnt_is_readonly(mnt)) {
++		rw_bdev = true;
++	}
++	spin_unlock(&sb_lock);
++
++out:
++	return rw_bdev;
++}
++
++extern spinlock_t vfsmount_lock;
++
++/* self included */
++static bool have_rw_bdev_parent(struct vfsmount *self)
++{
++	struct vfsmount *parent = self;
++	bool have_rw_bdev = true;
++
++	spin_lock(&vfsmount_lock);
++repeat:
++	have_rw_bdev = is_rw_bdev(parent);
++	if (have_rw_bdev)
++		goto out;
++
++	if (!IS_ROOT(parent->mnt_mountpoint)) {
++		parent = parent->mnt_parent;
++		goto repeat;
++	}
++out:
++	spin_unlock(&vfsmount_lock);
++	return have_rw_bdev;
++}
++
++static inline struct mnt_namespace *get_init_mnt_ns(void)
++{
++	struct nsproxy *nsp;
++
++	rcu_read_lock();
++	nsp = task_nsproxy(&init_task);
++	BUG_ON(!(nsp && nsp->mnt_ns));
++	get_mnt_ns(nsp->mnt_ns);
++	rcu_read_unlock();
++
++	return nsp->mnt_ns;
++}
++
++static bool null_check(struct vfsmount *mnt)
++{
++	return true;
++}
++
++static int
++iterate_mounts_safe_reverse(int (*f)(struct vfsmount *, void *),
++			    bool (*check)(struct vfsmount *), void *arg)
++{
++	struct mnt_namespace *mnt_ns;
++	struct vfsmount *mnt, *tmp;
++	int error = 0;
++
++	if (!check)
++		check = null_check;
++
++	mnt_ns = get_init_mnt_ns();
++	list_for_each_entry_safe_reverse(mnt, tmp, &mnt_ns->list, mnt_list) {
++		if (!check(mnt))
++			continue;
++
++		mntget(mnt);
++		error = f(mnt, arg);
++		mntput_no_expire(mnt);
++		if (error)
++			goto out;
++	}
++
++out:
++	put_mnt_ns(mnt_ns);
++	return error;
++}
++
++extern struct dentry *lookup_hash(struct nameidata *nd);
++
++/* copied from do_rmdir */
++static long do_kern_rmdir(const char *pathname)
++{
++	int error = 0;
++	struct dentry *dentry;
++	struct nameidata nd;
++
++	error = path_lookup(pathname, LOOKUP_PARENT, &nd);
++	if (error)
++		return error;
++
++	switch(nd.last_type) {
++	case LAST_DOTDOT:
++		error = -ENOTEMPTY;
++		goto exit1;
++	case LAST_DOT:
++		error = -EINVAL;
++		goto exit1;
++	case LAST_ROOT:
++		error = -EBUSY;
++		goto exit1;
++	}
++
++	nd.flags &= ~LOOKUP_PARENT;
++
++	mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
++	dentry = lookup_hash(&nd);
++	error = PTR_ERR(dentry);
++	if (IS_ERR(dentry))
++		goto exit2;
++	error = mnt_want_write(nd.path.mnt);
++	if (error)
++		goto exit3;
++	error = security_path_rmdir(&nd.path, dentry);
++	if (error)
++		goto exit4;
++	error = vfs_rmdir(nd.path.dentry->d_inode, dentry);
++exit4:
++	mnt_drop_write(nd.path.mnt);
++exit3:
++	dput(dentry);
++exit2:
++	mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
++exit1:
++	path_put(&nd.path);
++	return error;
++}
++
++/* move to /dev/, mostly writable and living on ram */
++#define SAFE_ROOT "/dev/hib_safe/"
++
++static void mount_saved_mountpoints(void)
++{
++	struct saved_mountpoint *saved, *tmp;
++	bool move = false;
++
++	list_for_each_entry_safe(saved, tmp, &saved_mountpoints, node) {
++		int error;
++		char *dir;
++		char *dev;
++
++		pr_info("PM:FS: restore mount [%s:%s]\n",
++			saved->dir_name, saved->dev_name);
++		pr_debug("PM:FS:  type   : %s\n", saved->type);
++		pr_debug("PM:FS:  flags  : 0x%08lx\n", saved->flags);
++		pr_debug("PM:FS:  data   : %s\n",
++			 saved->data ? saved->data : "null");
++
++		error = do_mount(saved->dev_name, saved->dir_name,
++				 saved->type, saved->flags, saved->data);
++		move = saved->flags & MS_MOVE;
++
++		dir = move ? saved->dev_name : saved->dir_name;
++		dev = move ? saved->dir_name : saved->dev_name;
++
++		if (error) {
++			pr_err("PM:FS: %s failed [%s:%s] (%d)\n",
++			       move ? "move mount" : "mount",
++			       dir, dev, error);
++		} else {
++			pr_debug("PM:FS: %s partition [%s:%s]\n",
++				 move ? "moved" : "mounted", dir, dev);
++		}
++
++		if (move) {
++			struct path moved;
++			int error = kern_path(dev, 0, &moved);
++			if (!error) {
++				struct mnt_namespace *ns =
++					get_init_mnt_ns();
++				list_move_tail(&moved.mnt->mnt_list,
++					       &ns->list);
++				put_mnt_ns(ns);
++				path_put(&moved);
++			}
++			do_kern_rmdir(saved->dev_name);
++		}
++
++		list_del(&saved->node);
++		kfree(saved->dir_name);
++		kfree(saved->dev_name);
++		kfree(saved->type);
++		if (saved->data)
++			free_page((unsigned long)saved->data);
++		kfree(saved);
++	}
++}
++
++static inline int get_s_flags_from_mnt(struct vfsmount *mnt)
++{
++	int mnt_flags = mnt->mnt_flags;
++	int s_flags = mnt->mnt_sb->s_flags;
++
++	if (mnt_flags & MNT_RELATIME)
++		s_flags &= ~MS_NOATIME;
++	if (mnt_flags & MNT_NOSUID)
++		s_flags |= MS_NOSUID;
++	if (mnt_flags & MNT_NODEV)
++		s_flags |=  MS_NODEV;
++	if (mnt_flags & MNT_NOEXEC)
++		s_flags |= MS_NOEXEC;
++	if (mnt_flags & MNT_NOATIME)
++		s_flags |= MS_NOATIME;
++	if (mnt_flags & MNT_NODIRATIME)
++		s_flags |=  MS_NODIRATIME;
++	if (mnt_flags & MNT_READONLY)
++		s_flags |= MS_RDONLY;
++	if (!(mnt_flags & (MNT_RELATIME | MNT_NOATIME)))
++		s_flags |= MS_STRICTATIME;
++	if (mnt_flags & MNT_MOVED)
++		s_flags |= MS_MOVE;
++
++	return s_flags;
++}
++
++static int save_mountpoint(struct vfsmount *mnt, const char *dir_name)
++{
++	struct saved_mountpoint *save;
++	const char *options;
++	const char *dev_name;
++	int error = -ENOMEM;
++
++	/* when moved, need to get old path */
++	if (mnt->mnt_flags & MNT_MOVED) {
++		dev_name = d_path_of_mnt(mnt);
++		mnt->mnt_flags &= ~MNT_MOVED;
++	} else {
++		dev_name = mnt->mnt_devname;
++	}
++
++	save = kzalloc(sizeof(*save), GFP_ATOMIC);
++	if (!save)
++		return -ENOMEM;
++
++	pr_info("PM:FS: save partition [%s:%s]\n", dir_name, mnt->mnt_devname);
++	pr_debug("PM:FS:  type   : %s\n", mnt->mnt_sb->s_type->name);
++	pr_debug("PM:FS:  flags  : 0x%08lx\n", mnt->mnt_sb->s_flags);
++	pr_debug("PM:FS:  data   : %s\n", mnt->mnt_sb->s_options);
++
++	INIT_LIST_HEAD(&save->node);
++
++	save->flags = get_s_flags_from_mnt(mnt);
++	save->dir_name = kstrdup(dir_name, GFP_ATOMIC);
++	if (!save->dir_name)
++		goto free_save;
++	save->dev_name = kstrdup(dev_name, GFP_ATOMIC);
++	if (!save->dev_name)
++		goto free_dirname;
++	save->type = kstrdup(mnt->mnt_sb->s_type->name, GFP_ATOMIC);
++	if (!save->type)
++		goto free_devname;
++	rcu_read_lock();
++	options = rcu_dereference(mnt->mnt_sb->s_options);
++	if (options && options[0]) {
++		save->data = (char *)__get_free_page(GFP_ATOMIC);
++		if (!save->data) {
++			rcu_read_unlock();
++			goto free_type;
++		}
++		memset(save->data, 0, PAGE_SIZE);
++		strncpy(save->data, options, PAGE_SIZE);
++	}
++	rcu_read_unlock();
++
++	list_add(&save->node, &saved_mountpoints);
++
++	return 0;
++
++free_type:
++	kfree(save->type);
++free_devname:
++	kfree(save->dev_name);
++free_dirname:
++	kfree(save->dir_name);
++free_save:
++	kfree(save);
++	return error;
++}
++
++static bool check_if_task_running(struct super_block *sb)
++{
++	struct task_struct *task;
++	bool running = false;
++
++	/* check if running process */
++	read_lock(&tasklist_lock);
++	for_each_process(task) {
++		struct fs_struct *fs;
++		task_lock(task);
++		fs = task->fs;
++		if (!fs) {
++			goto next;
++		}
++		read_lock(&fs->lock);
++		if (sb == fs->root.mnt->mnt_sb) {
++			pr_debug("PM:FS: task [%s] is running on [%s] (root)\n",
++				 &task->comm[0], d_path_wrapper(&fs->root));
++			running = true;
++		}
++		if (sb == fs->pwd.mnt->mnt_sb) {
++			pr_debug("PM:FS: task [%s] is running on [%s] (pwd)\n",
++				 &task->comm[0], d_path_wrapper(&fs->pwd));
++			running = true;
++		}
++		read_unlock(&fs->lock);
++	next:
++		task_unlock(task);
++	}
++	read_unlock(&tasklist_lock);
++
++	return running;
++}
++
++static bool check_if_file_opening(struct super_block *sb)
++{
++	bool opening = false;
++
++	file_list_lock();
++	if (!list_empty(&sb->s_files)) {
++#if defined(DEBUG)
++		struct file *file;
++		list_for_each_entry(file, &sb->s_files, f_u.fu_list) {
++			pr_debug("PM:FS: file [%s] is still open\n",
++				 d_path_of_file(file));
++		}
++#endif
++		opening = true;
++	}
++	file_list_unlock();
++
++	return opening;
++}
++
++#ifdef CONFIG_INOTIFY_USER
++
++extern struct srcu_struct fsnotify_grp_srcu;
++extern struct list_head fsnotify_groups;
++extern const struct fsnotify_ops inotify_fsnotify_ops;
++
++static bool check_if_inotify_user_watching(struct super_block *sb)
++{
++	struct fsnotify_group *group;
++	bool watching = false;
++	int idx;
++
++	/* check if inotify_user */
++	idx = srcu_read_lock(&fsnotify_grp_srcu);
++	list_for_each_entry_rcu(group, &fsnotify_groups, group_list) {
++		spin_lock(&group->mark_lock);
++		if (group->ops == &inotify_fsnotify_ops) {
++			struct fsnotify_mark_entry *entry;
++			list_for_each_entry(entry,
++					    &group->mark_entries, g_list) {
++				struct inode *inode = entry->inode;
++#if defined(DEBUG)
++				struct dentry *dentry;
++#endif
++				if (sb != inode->i_sb)
++					continue;
++#if defined(DEBUG)
++				dentry = d_find_alias(inode);
++				pr_debug("PM:FS: inotify [%s] still watching\n",
++					 dentry->d_name.name);
++				dput(dentry);
++#endif
++				watching = true;
++			}
++		}
++		spin_unlock(&group->mark_lock);
++	}
++	srcu_read_unlock(&fsnotify_grp_srcu, idx);
++
++	return watching;
++}
++#else
++static inline bool check_if_inotify_user_watching(struct super_block *sb)
++{
++	return false;
++}
++#endif
++
++extern struct vfsmount *next_mnt(struct vfsmount *p, struct vfsmount *root);
++
++/* copied from may_umount_tree */
++static bool check_if_mnt_holding(struct vfsmount *mnt)
++{
++	bool holding = false;
++	int actual_refs = 0;
++	int minimum_refs = 0;
++	struct vfsmount *p;
++
++	spin_lock(&vfsmount_lock);
++	for (p = mnt; p; p = next_mnt(p, mnt)) {
++		actual_refs += atomic_read(&p->mnt_count);
++		minimum_refs += 2;
++	}
++	spin_unlock(&vfsmount_lock);
++
++	if (actual_refs > minimum_refs) {
++		pr_debug("PM:FS: [%s] actual_refs:%d,minimum_refs:%d\n",
++			 d_path_of_mnt(mnt), actual_refs, minimum_refs);
++		holding = true;
++	}
++
++	return holding;
++}
++
++static bool check_if_unmountable(struct vfsmount *mnt)
++{
++	struct super_block *sb = mnt->mnt_sb;
++	bool opening, running, watching, holding;
++	char *p = d_path_of_mnt(mnt);
++
++	if (!sb) {
++		return false;
++	}
++
++	holding = check_if_mnt_holding(mnt);
++	watching = check_if_inotify_user_watching(sb);
++	opening = check_if_file_opening(sb);
++	running = check_if_task_running(sb);
++
++	pr_err_if(holding, "PM:FS: Still Holding [%s:%s]\n",
++		  p, mnt->mnt_devname);
++	pr_err_if(watching, "PM:FS: Still Watching [%s:%s]\n",
++		  p, mnt->mnt_devname);
++	pr_err_if(opening, "PM:FS: Still Opening [%s:%s]\n",
++		  p, mnt->mnt_devname);
++	pr_err_if(running, "PM:FS: Still Running [%s:%s]\n",
++		  p, mnt->mnt_devname);
++
++	return !holding && !opening && !running && !watching;
++}
++
++static inline void thaw_flusher(void)
++{
++	struct task_struct *task, *g;
++	read_lock(&tasklist_lock);
++	do_each_thread(g, task) {
++		if (task->flags & PF_FLUSHER)
++			thaw_process(task);
++	} while_each_thread(g, task);
++	read_unlock(&tasklist_lock);
++}
++
++static inline void freeze_flusher(void)
++{
++	struct task_struct *task, *g;
++	read_lock(&tasklist_lock);
++	do_each_thread(g, task) {
++		if (task->flags & PF_FLUSHER)
++			freeze_task(task, false);
++	} while_each_thread(g, task);
++	read_unlock(&tasklist_lock);
++}
++
++/* copied from sys_mkdirat */
++static int kern_mkdirat(const char *name, int mode)
++{
++	struct dentry *dentry;
++	struct nameidata nd;
++	int error;
++
++	error = path_lookup(name, LOOKUP_PARENT, &nd);
++	if (error)
++		goto out_err;
++
++	dentry = lookup_create(&nd, 1);
++	error = PTR_ERR(dentry);
++	if (IS_ERR(dentry))
++		goto out_unlock;
++
++	error = mnt_want_write(nd.path.mnt);
++	if (error)
++		goto out_dput;
++	error = security_path_mkdir(&nd.path, dentry, mode);
++	if (error)
++		goto out_drop_write;
++	error = vfs_mkdir(nd.path.dentry->d_inode, dentry, mode);
++out_drop_write:
++	mnt_drop_write(nd.path.mnt);
++out_dput:
++	dput(dentry);
++out_unlock:
++	mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
++	path_put(&nd.path);
++out_err:
++	return error;
++}
++
++static inline int mkdir_safe(void)
++{
++	int error = kern_mkdirat(SAFE_ROOT, 755);
++	if (error != -EEXIST)
++		return error;
++
++	return 0;
++}
++
++static int mkdir_on_safe(const char *name, int mode, char **safe_dir)
++{
++	static char safe_path[PATH_MAX];
++	int error;
++
++	error = mkdir_safe();
++	if (error)
++		return error;
++
++	snprintf(&safe_path[0], sizeof(safe_path), "%s/%s", SAFE_ROOT, name);
++
++	error = kern_mkdirat(&safe_path[0], 755);
++	if (error)
++		return error;
++
++	if (safe_dir)
++		*safe_dir = &safe_path[0];
++
++	return error;
++}
++
++static int do_move_mount_to_safe(struct vfsmount *mnt, char *from)
++{
++	char *to;
++	char temp[9];
++	int error;
++
++	/* FIXME - means nothing */
++	sprintf(&temp[0], "%p", mnt);
++	error = mkdir_on_safe(temp, 755, &to);
++	if (error)
++		return error;
++
++	error = do_mount(from, to, NULL, MS_MOVE, NULL);
++	if (error)
++		return error;
++
++	/* MNT_MOVED set here to pick it up during resumption and cleared. */
++	mnt->mnt_flags |= MNT_MOVED;
++	return error;
++}
++
++/* FIXME - Is it enough ? */
++static inline bool is_on_ram(struct vfsmount *mnt)
++{
++	return MAJOR(mnt->mnt_sb->s_dev) == 0 ? true : false;
++}
++
++struct umount_mnt {
++	struct list_head node;
++	struct vfsmount *mnt;
++};
++
++extern int do_umount(struct vfsmount *mnt, int flags);
++
++static int unmount_rw_backing_dev(struct vfsmount *mnt, void *unused,
++				  int is_on_ram)
++{
++	struct path path = { .dentry = mnt->mnt_root, .mnt = mnt };
++	char *orig = __d_path_wrapper(&path, true /* b */);
++	bool move = false;
++	int error;
++
++	/*
++	 * need to move a mount, it is not neccessary to check_if_unmountable()
++	 */
++	if (is_on_ram) {
++		move = true;
++		error = do_move_mount_to_safe(mnt, orig);
++		/* d_path_mnt() gives different path after here */
++	} else {
++		if (check_if_unmountable(mnt))
++			error = do_umount(mnt, 0);
++		else {
++			pr_err("PM:FS: [%s:%s] is unmountable\n",
++			       d_path_of_mnt(mnt), mnt->mnt_devname);
++			error = -EBUSY;
++		}
++	}
++
++	if (error) {
++		pr_err("PM:FS: %s failed [%s:%s] (%d)\n",
++		       move ? "move mount" : "unmount",
++		       orig,
++		       move ? d_path_of_mnt(mnt) : mnt->mnt_devname,
++		       error);
++	} else {
++#if defined(DEBUG)
++		pr_debug("PM:FS: %s partition [%s:%s]\n",
++			 move ? "moved" : "unmounted",
++			 orig,
++			 move ? d_path_of_mnt(mnt) : mnt->mnt_devname);
++#endif
++		error = save_mountpoint(mnt, orig);
++	}
++
++	return error;
++}
++
++static int collect_mnt_on_rw_backing_devs(struct vfsmount *mnt, void *list)
++{
++	struct list_head *umount_list = list;
++	struct umount_mnt *umount;
++
++	umount = kmalloc(sizeof(*umount), GFP_KERNEL);
++	if (unlikely(!umount))
++		return -ENOMEM;
++
++	INIT_LIST_HEAD(&umount->node);
++	umount->mnt = mntget(mnt);
++
++	list_add_tail(&umount->node, umount_list);
++	return 0;
++}
++
++static int unmount_rw_backing_devs(void)
++{
++	LIST_HEAD(umount_list);
++	struct umount_mnt *umount, *tmp;
++	int error;
++
++	error = iterate_mounts_safe_reverse(collect_mnt_on_rw_backing_devs,
++					    have_rw_bdev_parent, &umount_list);
++
++	thaw_flusher();
++
++	list_for_each_entry_safe(umount, tmp, &umount_list, node) {
++		struct vfsmount *mnt = umount->mnt;
++		int is_ram = 0;
++
++		list_del(&umount->node);
++		kfree(umount);
++
++		if (is_on_ram(mnt)) is_ram = 1;
++		error = unmount_rw_backing_dev(mnt, NULL, is_ram);
++		if (!error && !is_ram /* !-EBUSY */) {
++			pr_err_bug_if(atomic_read(&mnt->mnt_count) != 1,
++				      "PM:FS: "
++				      "mount count should be 1 but %d\n",
++				      atomic_read(&mnt->mnt_count));
++		}
++		/* mnt will be destroyed if no error */
++		mntput_no_expire(mnt);
++	}
++
++	freeze_flusher();
++	return error;
++}
++
++static LIST_HEAD(saved_task_fs_list);
++
++struct saved_task_fs {
++	struct list_head list;
++
++	struct task_struct *task;
++	char *root;
++	char *pwd;
++};
++
++static struct saved_task_fs *alloc_saved_task_fs(struct task_struct *task,
++						 bool move_root, bool move_pwd)
++{
++	struct fs_struct *fs = task->fs;
++	int root_len = 0;
++	int pwd_len = 0;
++	int null_len = 0;
++	struct saved_task_fs *saved;
++
++	read_lock(&fs->lock);
++
++	if (move_root) {
++		root_len = strlen(d_path_wrapper(&fs->root));
++		null_len++;
++	}
++	if (move_pwd) {
++		pwd_len = strlen(d_path_wrapper(&fs->pwd));
++		null_len++;
++	}
++
++	saved = kzalloc(sizeof(*saved) + root_len + pwd_len + null_len,
++			GFP_ATOMIC);
++	if (!saved)
++		goto unlock;
++
++	INIT_LIST_HEAD(&saved->list);
++	saved->task = task;
++
++	if (move_root) {
++		saved->root = (char *)saved + sizeof(*saved);
++		strcpy(saved->root, d_path_wrapper(&fs->root));
++	}
++	if (move_pwd) {
++		if (saved->root)
++			saved->pwd = saved->root + root_len + 1;
++		else
++			saved->pwd = (char *)saved + sizeof(*saved);
++		strcpy(saved->pwd, d_path_wrapper(&fs->pwd));
++	}
++
++unlock:
++	read_unlock(&fs->lock);
++	return saved;
++}
++
++static int move_task_fs_to(struct task_struct *task,
++			   const char *root, const char *pwd)
++{
++	struct path root_path, *old_root = NULL;
++	struct path pwd_path;
++	int error;
++
++	if (root) {
++		error = kern_path(root, LOOKUP_FOLLOW, &root_path);
++		if (error) {
++			pr_err("PM:FS: failed to get root path [%s]\n", root);
++			return error;
++		}
++
++		/* to rollback root when moving pwd fails */
++		old_root = &task->fs->root;
++		path_get(old_root);
++
++		set_fs_root(task->fs, &root_path);
++		path_put(&root_path);
++	}
++	if (pwd) {
++		error = kern_path(pwd, LOOKUP_FOLLOW, &pwd_path);
++		if (error) {
++			pr_err("PM:FS: failed to get pwd path [%s]\n", pwd);
++			goto out;
++		}
++
++		set_fs_pwd(task->fs, &pwd_path);
++		path_put(&pwd_path);
++	}
++
++out:
++	if (old_root) {
++		if (error)
++			set_fs_root(task->fs, old_root);
++		path_put(old_root);
++	}
++
++	return error;
++}
++
++static int move_task_fs_to_safe(struct task_struct *task,
++				bool move_root, bool move_pwd)
++{
++	struct saved_task_fs *saved;
++	char *root = NULL;
++	char *pwd = NULL;
++	int error;
++
++	if (!move_root && !move_pwd)
++		return 0;
++
++	/* sleeping function called from invalid context */
++	error = mkdir_safe();
++	if (error)
++		return error;
++
++	error = -ENOMEM;
++	saved = alloc_saved_task_fs(task, move_root, move_pwd);
++	if (!saved)
++		goto rm_safe;
++
++	if (move_root) {
++		root = SAFE_ROOT;
++		pr_info("PM:FS: move task [%s] on root:%s to %s\n",
++			&task->comm[0],
++			d_path_wrapper(&task->fs->root), root);
++
++	}
++	if (move_pwd) {
++		pwd = SAFE_ROOT;
++		pr_info("PM:FS: move task [%s] on pwd:%s to %s\n",
++			&task->comm[0],
++			d_path_wrapper(&task->fs->pwd), pwd);
++	}
++
++	error = move_task_fs_to(task, root, pwd);
++	if (error)
++		goto free_saved;
++
++	list_add(&saved->list, &saved_task_fs_list);
++	return 0;
++
++free_saved:
++	kfree(saved);
++rm_safe:
++	do_kern_rmdir(SAFE_ROOT);
++	return error;
++}
++
++static int save_task_fs_on_rw_backing_devs(void)
++{
++	struct task_struct *task;
++	int error = 0;
++
++	for_each_process(task) {
++		struct fs_struct *fs;
++		bool move_root = false;
++		bool move_pwd = false;
++
++		fs = task->fs;
++		if (!fs)
++			goto next;
++
++		if (have_rw_bdev_parent(fs->root.mnt))
++			move_root = true;
++		if (have_rw_bdev_parent(fs->pwd.mnt))
++			move_pwd = true;
++
++		if (move_root || move_pwd)
++			error = move_task_fs_to_safe(task, move_root, move_pwd);
++
++	next:
++		if (error)
++			break;
++	}
++
++	return error;
++}
++
++static void restore_saved_task_fs(void)
++{
++	struct saved_task_fs *saved, *n;
++
++	list_for_each_entry_safe(saved, n, &saved_task_fs_list, list) {
++		int error;
++
++		if (saved->root)
++			pr_debug("PM:FS: restore task [%s] on root:%s\n",
++				&saved->task->comm[0], saved->root);
++		if (saved->pwd)
++			pr_debug("PM:FS: restore task [%s] on pwd:%s\n",
++				 &saved->task->comm[0], saved->pwd);
++
++		error = move_task_fs_to(saved->task, saved->root, saved->pwd);
++		if (unlikely(error)) {
++			pr_err("PM:FS: failed to restore fs for task [%s] "
++			       "root:%s pwd:%s (%d)\n",
++			       &saved->task->comm[0],
++			       saved->root ? saved->root : "null",
++			       saved->pwd ? saved->pwd : "null",
++			       error);
++		}
++		list_del(&saved->list);
++		kfree(saved);
++	}
++
++	do_kern_rmdir(SAFE_ROOT);
++}
++
++/*
++ * FIXME
++ *  How can inode-like one be used instead of file_path ?
++ *  in other words, use alternative inode structure and file_path as a dentry
++ */
++static LIST_HEAD(file_path_list);
++
++struct file_path {
++	struct list_head node; /* file_path_list */
++	struct list_head fobj_list;
++
++	char *path;
++
++	//counter
++};
++
++/* one per struct file instance */
++struct file_object {
++	struct list_head same_fpath; /* fobj_list */
++	struct list_head fdesc_list;
++
++	struct file	*file; /* make it null when f_count is zero */
++
++	atomic_long_t	count;
++	unsigned int	flags;
++	fmode_t		mode;
++	loff_t		pos;
++	loff_t		size;
++};
++
++struct file_descriptor {
++	struct list_head same_fobj; /* fdesc_list */
++
++	int fd;
++	struct task_struct *task;
++};
++
++static loff_t noentry_lseek(struct file *file, loff_t offset, int orig)
++{
++	pr_err("PM:FS: [%s] lseek(%lld, %d) on [%s]",
++	       &current->comm[0], offset, orig, d_path_of_file(file));
++	return -EBADF;
++}
++
++static ssize_t noentry_read(struct file *file,
++			    char __user *buf, size_t count, loff_t *ppos)
++{
++	pr_err("PM:FS: [%s] read(%p, %d, %lld) on [%s]\n",
++	       &current->comm[0], buf, count, *ppos, d_path_of_file(file));
++	return -EBADF;
++}
++
++static ssize_t noentry_write(struct file *file,
++			     const char __user *buf, size_t count,
++			     loff_t *ppos)
++{
++	pr_err("PM:FS: [%s] write(%p, %d, %lld) on [%s]\n",
++	       &current->comm[0], buf, count, *ppos, d_path_of_file(file));
++	return -EBADF;
++}
++
++static int noentry_release(struct inode *inode, struct file *file)
++{
++	pr_err("PM:FS: [%s] close() on [%s]\n",
++	       &current->group_leader->comm[0], d_path_of_file(file));
++	return 0;
++}
++
++/*
++ * FIXME
++ *  - check whether more callbacks are necessary.
++ */
++static const struct file_operations noentry_fops = {
++	.llseek		= noentry_lseek,
++	.read		= noentry_read,
++	.write		= noentry_write,
++	.release	= noentry_release,
++};
++
++static inline bool is_noentry_file(const struct file *file)
++{
++	return file->f_op == &noentry_fops;
++}
++
++/*
++ * NOTE
++ *   It's not sufficient to get file path from anon_inodefs for debugging.
++ *  It just gives us short "anon_inode:[kind]". We override anon_inodefs's
++ *  d_dname() so we can get full file path pointed by noentry file.
++ *  This means all d_op is overriden and could be a problem if anon_inodefs
++ *  implements other dentry operations. But it does not at this time.
++ */
++/* copied from dynamic_dname but it uses bigger static buffer */
++static char *__dynamic_dname(struct dentry *dentry,
++			     char *buffer, int buflen, const char *fmt, ...)
++{
++	va_list args;
++	int sz;
++
++	va_start(args, fmt);
++	sz = vsnprintf(path_buf_b, sizeof(path_buf_b), fmt, args) + 1;
++	va_end(args);
++
++	if (sz > sizeof(path_buf_b) || sz > buflen)
++		return ERR_PTR(-ENAMETOOLONG);
++
++	buffer += buflen - sz;
++	return memcpy(buffer, path_buf_b, sz);
++}
++
++static char *noentry_dentry_dname(struct dentry *dentry,
++				  char *buffer, int buflen)
++{
++	char *p =  __dynamic_dname(dentry, buffer, buflen, "noentry:%s",
++				   dentry->d_name.name);
++	if (IS_ERR(p))
++		return "noentry:nofilenameavailble";
++	else
++		return p;
++}
++
++static const struct dentry_operations noentry_dentry_operations = {
++	.d_dname	= noentry_dentry_dname,
++};
++
++static struct file *get_noentry_file(const char *name)
++{
++	struct file *file;
++
++	file = anon_inode_getfile(name, &noentry_fops, NULL, 0);
++	if (IS_ERR(file))
++		goto out;
++
++	/* override d_op to get full filename */
++	file->f_dentry->d_op = &noentry_dentry_operations;
++
++out:
++	return file;
++}
++
++static inline bool is_task_fd_slot_empty(struct task_struct *task, unsigned fd)
++{
++	struct files_struct *files = task->files;
++	struct fdtable *fdt = files_fdtable(files);
++	bool is_empty = true;
++
++	if (fd >= fdt->max_fds) {
++		is_empty = false;
++		goto out;
++	}
++	if (rcu_dereference_raw(fdt->fd[fd]) != NULL) {
++		is_empty = false;
++		goto out;
++	}
++	if (fd <= files->next_fd)
++		files->next_fd = fd + 1;
++out:
++	return is_empty;
++}
++
++static void task_fd_install(struct task_struct *task,
++			    unsigned int fd, int flags, struct file *file)
++{
++	struct files_struct *files = task->files;
++	struct fdtable *fdt;
++
++	spin_lock(&files->file_lock);
++
++	fdt = files_fdtable(files);
++	BUG_ON(!is_task_fd_slot_empty(task, fd));
++
++	FD_SET(fd, fdt->open_fds);
++	if (flags & O_CLOEXEC)
++		FD_SET(fd, fdt->close_on_exec);
++	else
++		FD_CLR(fd, fdt->close_on_exec);
++	rcu_assign_pointer(fdt->fd[fd], file);
++
++	spin_unlock(&files->file_lock);
++}
++
++static off_t filp_lseek(struct file *file, off_t offset, unsigned int origin)
++{
++	off_t retval;
++
++	if (!file)
++		return -EBADF;
++
++	retval = -EINVAL;
++	if (origin <= SEEK_MAX) {
++		loff_t res = vfs_llseek(file, offset, origin);
++		retval = res;
++		if (res != (loff_t)retval)
++			retval = -EOVERFLOW;
++	}
++
++	return retval;
++}
++
++static inline char *get_file_flags_readable(unsigned int flags, fmode_t mode)
++{
++	static char open_flags[64];
++	snprintf(&open_flags[0], sizeof(open_flags),
++		 "%s%s%s",
++		 (flags & O_ACCMODE) == O_RDWR ? "RDWR ":
++		 ((flags & O_ACCMODE) == O_RDONLY ? "RD   ":
++		  ((flags & O_ACCMODE) == O_WRONLY ? "WR ":"     ")),
++		 (mode | flags) & FMODE_EXEC ? "EXEC ":"     ",
++		 flags & O_DIRECTORY ? "DIR ":"");
++	return &open_flags[0];
++}
++
++static void restore_file_descriptors(struct file_object *fobj)
++{
++	struct file_descriptor *fdesc, *tmp;
++
++	list_for_each_entry_safe(fdesc, tmp, &fobj->fdesc_list, same_fobj) {
++		/*
++		 * Failed to open both of the original file and noentry file.
++		 * leave the fd and fdslot empty so that the process's syscalls
++		 * can fail with -EBADF.
++		 */
++		if (unlikely(!fobj->file)) {
++			pr_err("PM:FS: "
++			       "have no file to restore [%s(%d)][fd:%d]\n",
++				&fdesc->task->comm[0], fdesc->task->pid,
++			       fdesc->fd);
++			goto free;
++		}
++		/* install fd and get file instance */
++		task_fd_install(fdesc->task,
++				fdesc->fd, fobj->flags, fobj->file);
++		get_file(fobj->file);
++
++		pr_info("PM:FS: restore fd [%s(%d)][fd:%d]\n",
++			&fdesc->task->comm[0], fdesc->task->pid, fdesc->fd);
++
++free:
++		list_del(&fdesc->same_fobj);
++		kfree(fdesc);
++	}
++}
++
++static void restore_file_objects(struct file_path *fpath)
++{
++	const char *filename = fpath->path;
++	struct file_object *fobj, *tmp;
++
++	list_for_each_entry_safe(fobj, tmp, &fpath->fobj_list, same_fpath) {
++		struct file *file;
++
++		/* in case of error on suspension, file object is alive */
++		if (unlikely(fobj->file))
++			goto restore_fdesc;
++
++		/* we must put the file after all fds are restored */
++		file = filp_open(filename, fobj->flags, fobj->mode);
++		if (unlikely(IS_ERR(file))) {
++			pr_err("PM:FS: opening [%s] failed (%d)\n",
++			       filename, (int)PTR_ERR(file));
++
++			file = get_noentry_file(filename);
++			if (IS_ERR(file)) {
++				pr_err("PM:FS: getting noentry file failed "
++				       "(%ld) not recoverable\n",
++				       PTR_ERR(file));
++				/*
++				 * make it null so we can recognize it during
++				 * fd restoration.
++				 */
++				file = NULL;
++			} else {
++				pr_err("PM:FS: "
++				       "got noentry file instead of [%s]\n",
++				       filename);
++			}
++		} else {
++			/*
++			 * sanity check - if oops, something's wroing, fix !
++			 */
++			pr_err_bug_if(fobj->flags != file->f_flags,
++				      "PM:FS: mismatch file flags, should be "
++				      "%x (but %x)\n",
++				      fobj->flags, file->f_flags);
++			pr_err_bug_if(fobj->mode != file->f_mode,
++				      "PM:FS: mismatch file mode, should be "
++				      "%x (but %x)\n",
++				      fobj->mode, file->f_mode);
++
++			/* size truncated ? */
++			if (unlikely(fobj->pos >
++				     i_size_read(file->f_dentry->d_inode))) {
++				pr_err("PM:FS: file size (%lld) smaller than "
++				       "offset (%lld)\n",
++				       i_size_read(file->f_dentry->d_inode),
++				       fobj->pos);
++				/* set pos with inode's size */
++				fobj->pos =
++					i_size_read(file->f_dentry->d_inode);
++			}
++
++			/* seek offset */
++			BUG_ON(filp_lseek(file, fobj->pos, 0) < 0);
++
++			pr_debug("PM:FS: restore file object [%p:%s]\n",
++				 file, filename);
++			pr_debug("PM:FS:  open flags : %s\n",
++				 get_file_flags_readable(fobj->flags,
++							 fobj->mode));
++			pr_debug("PM:FS:  open mode  : 0x%08x\n", fobj->mode);
++			pr_debug("PM:FS:  offset     : %lld\n", fobj->pos);
++			pr_debug("PM:FS:  size       : %lld\n",
++				 i_size_read(file->f_dentry->d_inode));
++		}
++		fobj->file = file;
++
++	restore_fdesc:
++		/* task's file descriptors */
++		restore_file_descriptors(fobj);
++
++		/* original file or noentry file */
++		if (likely(fobj->file)) {
++			/*
++			 * sanity check - if oops, something's wroing, fix !
++			 * file_count can be 1 (in case someting's wrong), so
++			 * check it before dropping reference.
++			 */
++			pr_err_bug_if(file_count(fobj->file) < 2,
++				      "PM:FS: file count is %ld\n",
++				      file_count(fobj->file));
++			pr_err_bug_if((file_count(fobj->file) - 1) !=
++				      atomic_long_read(&fobj->count),
++				      "PM:FS: mismatch file count, it should "
++				      "be %ld (but %ld)\n",
++				      atomic_long_read(&fobj->count),
++				      file_count(fobj->file) - 1);
++		}
++
++		/*
++		 * we should put the file because additional count is held in
++		 * filp_open().
++		 */
++		if (likely(fobj->file))
++			fput(fobj->file);
++
++		list_del(&fobj->same_fpath);
++		kfree(fobj);
++	}
++}
++
++static void open_saved_files(void)
++{
++	struct file_path *fpath, *tmp;
++
++	list_for_each_entry_safe(fpath, tmp, &file_path_list, node) {
++		pr_info("PM:FS: restore file [%s]", fpath->path);
++		restore_file_objects(fpath);
++		list_del(&fpath->node);
++		kfree(fpath);
++	}
++}
++
++static struct file_path *get_file_path(struct file *file)
++{
++	const char *filename = d_path_of_file(file);
++	struct file_path *fpath;
++
++	/* search first */
++	list_for_each_entry(fpath, &file_path_list, node) {
++		if (!strcmp(fpath->path, filename))
++			return fpath;
++	}
++
++	/* new a file_path */
++	fpath = kmalloc(sizeof(*fpath) + strlen(filename) + 1, GFP_ATOMIC);
++	if (!fpath)
++		return ERR_PTR(-ENOMEM);
++
++	INIT_LIST_HEAD(&fpath->node);
++	INIT_LIST_HEAD(&fpath->fobj_list);
++	fpath->path = (char *)fpath + sizeof(*fpath);
++	strcpy(fpath->path, filename);
++
++	list_add_tail(&fpath->node, &file_path_list);
++
++	pr_info("PM:FS: save file [%s]\n", filename);
++	return fpath;
++}
++
++static struct file_object *get_file_object(struct file *file)
++{
++	struct file_path *fpath;
++	struct file_object *fobj;
++
++	fpath = get_file_path(file);
++	if (IS_ERR(fpath))
++		return ERR_PTR(-ENOMEM);
++
++	/* search first */
++	list_for_each_entry(fobj, &fpath->fobj_list, same_fpath) {
++		if (fobj->file && (fobj->file == file))
++			return fobj;
++	}
++
++	/* new a file_object */
++	fobj = kzalloc(sizeof(*fobj), GFP_ATOMIC);
++	if (!fobj)
++		return ERR_PTR(-ENOMEM);
++
++	INIT_LIST_HEAD(&fobj->same_fpath);
++	INIT_LIST_HEAD(&fobj->fdesc_list);
++	fobj->file = file;
++	atomic_long_set(&fobj->count, file_count(file));
++	fobj->flags = file->f_flags & ~(O_CREAT | O_TRUNC | O_EXCL);
++	fobj->mode = file->f_mode;
++	fobj->pos = file->f_pos;
++	fobj->size = i_size_read(file->f_dentry->d_inode);
++
++	list_add_tail(&fobj->same_fpath, &fpath->fobj_list);
++
++	pr_debug("PM:FS: save file object [%p:%s]\n", file, fpath->path);
++	pr_debug("PM:FS:  open count: %ld\n", file_count(file));
++	pr_debug("PM:FS:  open flags: %s\n",
++		 get_file_flags_readable(file->f_flags, file->f_mode));
++	pr_debug("PM:FS:  open mode : 0x%08x\n", file->f_mode);
++	pr_debug("PM:FS:  offset    : %lld\n", file->f_pos);
++	pr_debug("PM:FS:  size      : %lld\n",
++		 i_size_read(file->f_dentry->d_inode));
++
++	/*
++	 * grab additional 1 ref to prevent it from being destroyed in filp_cl-
++	 * ose() which may sleep.
++	 * file object will be destoryed at the end of close_files_on_rw_backi-
++	 * ng_devs().
++	 */
++	get_file(fobj->file);
++
++	return fobj;
++}
++
++static void __put_unused_fd(struct files_struct *files, unsigned int fd)
++{
++	struct fdtable *fdt = files_fdtable(files);
++	__FD_CLR(fd, fdt->open_fds);
++	if (fd < files->next_fd)
++		files->next_fd = fd;
++}
++
++static int check_file_busy(struct task_struct *task, struct file *file)
++{
++	struct list_head *l;
++	int nr_epolls = 0;
++	struct inode *inode = file->f_path.dentry->d_inode;
++	struct file_lock *flock;
++	int nr_flocks = 0;
++	struct vm_area_struct *vma;
++	struct address_space *mapping;
++	struct prio_tree_iter iter;
++	int nr_mappings = 0;
++	int busy = 0;
++
++	/* FIXME - remove this and save & restore eventpolls */
++	spin_lock(&file->f_lock);
++	list_for_each(l, &file->f_ep_links)
++		nr_epolls++;
++	spin_unlock(&file->f_lock);
++
++	/* lock_kernel(); */
++	for (flock = inode->i_flock; flock != NULL; flock = flock->fl_next)
++		nr_flocks++;
++	/* unlock_kernel(); */
++
++	mapping = file->f_mapping;
++	spin_lock(&mapping->i_mmap_lock);
++	vma_prio_tree_foreach(vma, &iter, &mapping->i_mmap, 0, ULONG_MAX) {
++		nr_mappings++;
++	}
++	spin_unlock(&mapping->i_mmap_lock);
++
++	if (unlikely(nr_epolls)) {
++		busy = 1;
++		pr_err("PM:FS: file [%s] (opened by [%s:%d]) has eventpolls "
++		       "(%d)\n", d_path_of_file(file),
++		       &task->comm[0], task->pid, nr_epolls);
++	}
++	if (unlikely(nr_flocks)) {
++		busy = 1;
++		pr_err("PM:FS: file [%s] (opened by [%s:%d]) has locks (%d)\n",
++		       d_path_of_file(file),
++		       &task->comm[0], task->pid, nr_flocks);
++	}
++	if (unlikely(nr_mappings)) {
++		busy = 1;
++		pr_err("PM:FS: "
++		       "file [%s] (opened by [%s:%d]) has been mmapped (%d)\n",
++		       d_path_of_file(file),
++		       &task->comm[0], task->pid, nr_mappings);
++	}
++
++	return busy;
++}
++
++static int task_save_close_file(struct task_struct *task, int fd)
++{
++	struct files_struct *files = task->files;
++	struct fdtable *fdt = files_fdtable(files);
++	struct file *file = fcheck_files(files, fd);
++	struct file_object *fobj;
++	struct file_descriptor *fdesc;
++
++	if (check_file_busy(task, file))
++		return -EBUSY;
++
++	fobj = get_file_object(file);
++	if (IS_ERR(fobj))
++		return PTR_ERR(fobj);
++
++	fdesc = kmalloc(sizeof(*fdesc), GFP_ATOMIC);
++	if (!fdesc)
++		return -ENOMEM;
++
++	pr_info("PM:FS: save fd [%s(%d)][fd:%d]\n",
++		&task->comm[0], task->pid, fd);
++
++	/* backup fd */
++	INIT_LIST_HEAD(&fdesc->same_fobj);
++	fdesc->fd = fd;
++	fdesc->task = task;
++
++	/*
++	 * decrease count (close),
++	 * it should be 2 at least, 1 held in get_file_object().
++	 */
++	BUG_ON(file_count(file) == 1);
++	fput(file);
++
++	/* free fd slot */
++	rcu_assign_pointer(fdt->fd[fd], NULL);
++	FD_CLR(fd, fdt->close_on_exec);
++	__put_unused_fd(files, fd);
++
++	/* link to fobj */
++	list_add_tail(&fdesc->same_fobj, &fobj->fdesc_list);
++
++	return 0;
++}
++
++static bool is_on_rw_backing_dev(struct file *file)
++{
++	struct vfsmount *mnt = file->f_vfsmnt;
++	return is_rw_bdev(mnt);
++}
++
++static int task_close_file_on_rw_backing_dev(struct task_struct *task, int fd)
++{
++	struct files_struct *files = task->files;
++	struct file *file = fcheck_files(files, fd);
++	int error = 0;
++
++	if (!file) {
++		pr_err("PM:FS: no file structure\n");
++		error = -EBADF;
++		goto out;
++	}
++
++	if (!is_on_rw_backing_dev(file))
++		goto out;
++
++	if (!frozen(task)) {
++		pr_err("PM:FS: task [%s] that opened file [%s] not frozen\n",
++		       &task->comm[0], d_path_of_file(file));
++		error = -EBUSY;
++		goto out;
++	}
++
++	error = task_save_close_file(task, fd);
++	if (error) {
++		pr_err("PM:FS: failed to close file %s on process %s\n",
++		       &task->comm[0], d_path_of_file(file));
++		goto out;
++	}
++
++out:
++	return error;
++}
++
++static int task_close_files_on_rw_backing_devs(struct task_struct *task)
++{
++	struct files_struct *files = task->files;
++	struct fdtable *fdt;
++	int i = 0;
++	int error = 0;
++
++	if (!frozen(task) || !files)
++		return 0;
++
++	spin_lock(&files->file_lock);
++	fdt = files_fdtable(files);
++	for (i = 0; i < fdt->max_fds; i++) {
++		struct file *file = fcheck_files(files, i);
++		if (!file)
++			continue;
++		error = task_close_file_on_rw_backing_dev(task, i);
++		if (error)
++			goto out;
++	}
++out:
++	spin_unlock(&files->file_lock);
++	return error;
++}
++
++static int close_files_on_rw_backing_devs(void)
++{
++	struct task_struct *task;
++	struct file_path *fpath;
++	int error = 0;
++
++	read_lock(&tasklist_lock);
++	for_each_process(task) {
++		task_lock(task);
++		error = task_close_files_on_rw_backing_devs(task);
++		task_unlock(task);
++		if (error) {
++			goto unlock;
++		}
++	}
++unlock:
++	read_unlock(&tasklist_lock);
++
++	/*
++	 * On error, do not free files on file_path_list here.
++	 * They will be restored by simply increasing files' counts not to
++	 * bother closing and reopening files.
++	 */
++	if (unlikely(error))
++		goto out;
++
++	/* free files */
++	list_for_each_entry(fpath, &file_path_list, node) {
++		struct file_object *fobj;
++		list_for_each_entry(fobj, &fpath->fobj_list, same_fpath) {
++			/* sanity check - if oops, something's wroing, fix ! */
++			pr_err_bug_if(file_count(fobj->file) != 1,
++				      "PM:FS: "
++				      "file count is %ld, should be 1\n",
++				      file_count(fobj->file));
++			/* free and nullify, reinstantiated on resumption. */
++			BUG_ON(filp_close(fobj->file, task->files) < 0);
++			fobj->file = NULL;
++		}
++	}
++
++out:
++	return error;
++}
++
++#ifdef CONFIG_INOTIFY_USER
++
++struct saved_inotify_user {
++	struct list_head node;
++	struct fsnotify_group *group;
++	int wd;
++	u32 mask;
++	char *path;
++};
++
++static LIST_HEAD(saved_inotify_users);
++
++extern void inotify_free_mark(struct fsnotify_mark_entry *entry);
++extern struct kmem_cache *inotify_inode_mark_cachep __read_mostly;
++extern int inotify_max_user_watches __read_mostly;
++extern void inotify_remove_from_idr(struct fsnotify_group *group,
++				    struct inotify_inode_mark_entry *ientry);
++
++/* copied from inotify_new_watch() */
++static int restore_saved_inotify_user(struct saved_inotify_user *saved,
++				      struct path *path)
++{
++	struct fsnotify_group *group = saved->group;
++	const char *filepath = saved->path;
++	int wd = saved->wd;
++	u32 mask = saved->mask;
++	struct inotify_inode_mark_entry *tmp_ientry;
++	struct inode *inode;
++	int ret;
++
++	/* don't allow invalid bits: we don't want flags set */
++	if (unlikely(!mask))
++		return -EINVAL;
++
++	inode = path->dentry->d_inode;
++
++	tmp_ientry = kmem_cache_alloc(inotify_inode_mark_cachep, GFP_KERNEL);
++	if (unlikely(!tmp_ientry))
++		return -ENOMEM;
++
++	tmp_ientry->path = kstrdup(filepath, GFP_KERNEL);
++	if (unlikely(!tmp_ientry->path)) {
++		kmem_cache_free(inotify_inode_mark_cachep, tmp_ientry);
++		return -ENOMEM;
++	}
++
++	fsnotify_init_mark(&tmp_ientry->fsn_entry, inotify_free_mark);
++	tmp_ientry->fsn_entry.mask = mask;
++	tmp_ientry->wd = -1;
++
++	ret = -ENOSPC;
++	if (atomic_read(&group->inotify_data.user->inotify_watches) >=
++	    inotify_max_user_watches)
++		goto out_err;
++retry:
++	ret = -ENOMEM;
++	if (unlikely(!idr_pre_get(&group->inotify_data.idr, GFP_KERNEL)))
++		goto out_err;
++
++	/* we are putting the mark on the idr, take a reference */
++	fsnotify_get_mark(&tmp_ientry->fsn_entry);
++
++	spin_lock(&group->inotify_data.idr_lock);
++	ret = idr_get_new_above(&group->inotify_data.idr, &tmp_ientry->fsn_entry,
++				wd, &tmp_ientry->wd);
++	spin_unlock(&group->inotify_data.idr_lock);
++	if (ret) {
++		/* we didn't get on the idr, drop the idr reference */
++		fsnotify_put_mark(&tmp_ientry->fsn_entry);
++
++		/* idr was out of memory allocate and try again */
++		if (ret == -EAGAIN)
++			goto retry;
++		goto out_err;
++	}
++
++	BUG_ON(wd != tmp_ientry->wd);
++
++	/* we are on the idr, now get on the inode */
++	ret = fsnotify_add_mark(&tmp_ientry->fsn_entry, group, inode);
++	if (ret) {
++		/* we failed to get on the inode, get off the idr */
++		inotify_remove_from_idr(group, tmp_ientry);
++		goto out_err;
++	}
++
++	/* update the idr hint, who cares about races, it's just a hint */
++	group->inotify_data.last_wd = tmp_ientry->wd;
++
++	/* increment the number of watches the user has */
++	atomic_inc(&group->inotify_data.user->inotify_watches);
++
++	/* return the watch descriptor for this tmp_ientry entry */
++	ret = tmp_ientry->wd;
++
++	/* if this mark added a new event update the group mask */
++	if (mask & ~group->mask)
++		fsnotify_recalc_group_mask(group);
++
++	pr_info("PM:FS: restore inotify user [%s]\n", filepath);
++	pr_debug("PM:FS:  user   : %p\n", group->inotify_data.user);
++	pr_debug("PM:FS:  watches: %d\n",
++		 atomic_read(&group->inotify_data.user->inotify_watches));
++	pr_debug("PM:FS:  group  : %p\n", group);
++	pr_debug("PM:FS:  mask   : 0x%08x\n", mask);
++	pr_debug("PM:FS:  wd     : %d\n", wd);
++
++out_err:
++	/* match the ref from fsnotify_init_markentry() */
++	fsnotify_put_mark(&tmp_ientry->fsn_entry);
++
++	return ret;
++}
++
++static void restore_saved_inotify_users(void)
++{
++	struct saved_inotify_user *saved, *tmp;
++	struct path path;
++
++	list_for_each_entry_safe(saved, tmp, &saved_inotify_users, node) {
++		int error;
++
++		error = kern_path(saved->path, 0, &path);
++		if (error /* -ENOENT */) {
++			struct file *file;
++
++			pr_err("PM:FS: not found path [%s] (%d)\n",
++			       saved->path, error);
++
++			file = get_noentry_file(saved->path);
++			if (IS_ERR(file)) {
++				error = PTR_ERR(file);
++				pr_err("PM:FS: failed to get noentry file, "
++				       "not recoverable (%d)\n", error);
++				goto next;
++			}
++			pr_err("PM:FS: got noentry file and put inotify user "
++			       "on it\n");
++			path = file->f_path;
++			path_get(&path);
++			/*
++			 * inotify registeration needs only f_path, not file
++			 * itself.
++			 */
++			filp_close(file, NULL);
++		}
++
++		error = restore_saved_inotify_user(saved, &path);
++#if 0
++		if (!error) {
++			/*
++			 * In real world, it's right to regard restored files
++			 * as modified in most cases ?
++			 */
++			fsnotify_enable();
++			fsnotify_modify(path.dentry);
++			fsnotify_disable();
++		}
++#endif
++		path_put(&path);
++	next:
++		list_del(&saved->node);
++		kfree(saved);
++	}
++}
++
++static int save_inotify_user_group_on_mnt(struct fsnotify_group *group,
++					  struct vfsmount *mnt)
++{
++	struct fsnotify_mark_entry *entry, *tmp;
++	int error = 0;
++
++	spin_lock(&group->mark_lock);
++	list_for_each_entry_safe(entry, tmp, &group->mark_entries, g_list) {
++		struct inode *inode = entry->inode;
++		struct inotify_inode_mark_entry *ientry =
++			container_of(entry, struct inotify_inode_mark_entry,
++				     fsn_entry);
++		struct user_struct *user = group->inotify_data.user;
++		struct saved_inotify_user *save;
++		char *path_str = ientry->path;
++
++		if (inode->i_sb != mnt->mnt_sb)
++			continue;
++
++		save = kzalloc(sizeof(*save) + strlen(path_str) + 1,
++			       GFP_ATOMIC);
++		if (!save) {
++			error = -ENOMEM;
++			goto unlock;
++		}
++		INIT_LIST_HEAD(&save->node);
++		save->path = (char *)save + sizeof(*save);
++
++		strcpy(save->path, path_str);
++		save->group = group;
++		save->wd = ientry->wd;
++		save->mask = entry->mask;
++		list_add(&save->node, &saved_inotify_users);
++		pr_info("PM:FS: save inotify user [%s]\n", save->path);
++		pr_debug("PM:FS:  user   : %p\n", user);
++		pr_debug("PM:FS:  watches: %d\n",
++			 atomic_read(&user->inotify_watches));
++		pr_debug("PM:FS:  group  : %p\n", group);
++		pr_debug("PM:FS:  mask   : 0x%08x\n", entry->mask);
++		pr_debug("PM:FS:  wd     : %d\n", ientry->wd);
++
++		fsnotify_get_mark(entry);
++		spin_unlock(&group->mark_lock);
++
++		fsnotify_destroy_mark_by_entry(entry);
++		fsnotify_put_mark(entry);
++
++		spin_lock(&group->mark_lock);
++	}
++
++unlock:
++	spin_unlock(&group->mark_lock);
++	return error;
++}
++
++static int save_inotify_users_on_mnt(struct vfsmount *mnt, void *unused)
++{
++	struct fsnotify_group *group;
++	int idx;
++	int ret = 0;
++
++	idx = srcu_read_lock(&fsnotify_grp_srcu);
++	list_for_each_entry_rcu(group, &fsnotify_groups, group_list) {
++		if (group->ops == &inotify_fsnotify_ops) {
++			ret = save_inotify_user_group_on_mnt(group, mnt);
++			if (ret)
++				goto unlock;
++		}
++	}
++unlock:
++	srcu_read_unlock(&fsnotify_grp_srcu, idx);
++	return ret;
++}
++
++static int save_inotify_users_on_rw_backing_devs(void)
++{
++	return iterate_mounts_safe_reverse(save_inotify_users_on_mnt,
++					   is_rw_bdev, NULL);
++}
++
++#else
++inline static int save_inotify_users_on_rw_partitions(void) { return 0; }
++inline static int restore_saved_inotify_users(void) { return 0; }
++
++#endif /* CONFIG_INOTIFY_USER */
++
++int fastboot_hibernate_fs_suspend(void)
++{
++	int error;
++
++	pr_debug("PM:FS: Got PM_POST_FREEZE_PROCESS event\n");
++
++	error = save_inotify_users_on_rw_backing_devs();
++	if (error)
++		goto restore_inotify_users;
++	error = close_files_on_rw_backing_devs();
++	if (error)
++		goto open;
++	error = save_task_fs_on_rw_backing_devs();
++	if (error)
++		goto restore_task_fs;
++	error = unmount_rw_backing_devs();
++	if (error)
++		goto mount;
++
++	pr_debug("PM:FS: Done with PM_POST_FREEZE_PROCESS event\n");
++	return 0;
++
++mount:
++	mount_saved_mountpoints();
++restore_task_fs:
++	restore_saved_task_fs();
++open:
++	open_saved_files();
++restore_inotify_users:
++	restore_saved_inotify_users();
++
++	pr_err("PM:FS: failure in suspending filesystem (%d)\n", error);
++	return error;
++}
++
++int fastboot_hibernate_fs_resume(void)
++{
++	pr_debug("PM:FS: Got PM_THAW_PROCESS_PREPARE event\n");
++
++	/* no error check for task'fs */
++	mount_saved_mountpoints();
++	restore_saved_task_fs();
++	open_saved_files();
++	restore_saved_inotify_users();
++
++	pr_debug("PM:FS: Done with PM_THAW_PROCESS_PREPARE event\n");
++	return 0;
++}
+diff --git a/arch/arm/mach-hisi/fastboot/hibernate_misc.c b/arch/arm/mach-hisi/fastboot/hibernate_misc.c
+new file mode 100644
+index 0000000..bd8529a
+--- /dev/null
++++ b/arch/arm/mach-hisi/fastboot/hibernate_misc.c
+@@ -0,0 +1,188 @@
++#include <linux/mm.h>
++#include <linux/kernel.h>
++#include <linux/nsproxy.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/rwlock.h>
++#include <linux/sched.h>
++#include <linux/file.h>
++#include <linux/fdtable.h>
++#include <linux/fs.h>
++#include <linux/list.h>
++#include <linux/rculist.h>
++#include <linux/err.h>
++#include <linux/seq_file.h>
++#include <linux/fs_struct.h>
++#include <linux/proc_fs.h>
++#include <linux/mount.h>
++#include <linux/mnt_namespace.h>
++#include <asm/uaccess.h>
++
++static DEFINE_MUTEX(file_mutex);
++
++struct sb_files_mount
++{
++	struct seq_file m;
++	struct path path;
++	struct vfsmount *mnt;
++};
++
++extern int kern_path(const char *, unsigned int, struct path *);
++extern char *get_task_comm(char *, struct task_struct *);
++
++static char mnt_path[64] = {0,};
++
++static inline char *__dpath_of_filp(struct file *filp, char *buf, int len)
++{
++	struct path mnt_path;
++	mnt_path.dentry = filp->f_dentry;
++	mnt_path.mnt = filp->f_vfsmnt;
++	return d_path(&mnt_path, buf, len);
++}
++
++static void *sb_files_seq_start(struct seq_file *m, loff_t *pos)
++{
++	struct sb_files_mount *priv = m->private;
++	mutex_lock(&file_mutex);
++
++	/* fix me */
++/*#ifdef CONFIG_SMP
++	return seq_list_start(priv->mnt->mnt_sb->s_files, *pos);
++#else*/
++	return seq_list_start(&priv->mnt->mnt_sb->s_files, *pos);
++/*#endif*/
++}
++
++static void *m_next(struct seq_file *m, void *v, loff_t *pos)
++{
++	struct sb_files_mount *priv = m->private;
++
++	/* fix me */
++/*#ifdef CONFIG_SMP
++	return seq_list_next(v, priv->mnt->mnt_sb->s_files, pos);
++#else*/
++	return seq_list_next(v, &priv->mnt->mnt_sb->s_files, pos);
++/*#endif*/
++}
++
++static void m_stop(struct seq_file *m, void *v)
++{
++	mutex_unlock(&file_mutex);
++}
++
++static int sb_files_seq_show(struct seq_file *m, void *v)
++{
++	struct file *filp = list_entry(v, struct file, f_u.fu_llist);
++	char buf[128], *path;
++	unsigned int acc;
++	struct vm_area_struct *vma;
++	struct address_space *mapping;
++	int mmap_count = 0;
++
++	path = __dpath_of_filp(filp, buf, sizeof(buf));
++	acc = filp->f_flags & O_ACCMODE;
++	mapping = filp->f_mapping;
++
++	vma_interval_tree_foreach(vma, &mapping->i_mmap, 0, ULONG_MAX) {
++		mmap_count++;
++	}
++
++	seq_printf(m, "[%s]\n", path);
++	seq_printf(m, "\topen count: %ld\n", file_count(filp));
++	seq_printf(m, "\topen flags: %s%s%s%s\n",
++			(filp->f_mode | filp->f_flags) & FMODE_EXEC ? "EXEC ":"     ",
++			filp->f_flags & O_DIRECTORY ? "DIR ":"    ",
++			acc == O_RDWR ? "RDWR ":
++			(acc == O_RDONLY ? "RD   ":
++			 (acc == O_WRONLY ? "  WR ":"     ")),
++			mmap_count ? "MMAP":"");
++
++	return 0;
++}
++
++static const struct seq_operations sb_files_seq_ops = {
++	.start	= sb_files_seq_start,
++	.next	= m_next,
++	.stop	= m_stop,
++	.show	= sb_files_seq_show,
++};
++
++static int sb_files_open(struct inode *inode, struct file *file)
++{
++	struct sb_files_mount *priv;
++	int ret = -1;
++
++	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
++	if (!priv)
++		return -ENOMEM;
++
++	if (mnt_path[0] != 0)
++		ret = kern_path(mnt_path, 0, &priv->path);
++
++	if (ret)
++		ret = kern_path("/", 0, &priv->path);
++
++	priv->mnt = collect_mounts(&priv->path);
++
++	file->private_data = &priv->m;
++	ret = seq_open(file, &sb_files_seq_ops);
++	if (ret) {
++		path_put(&priv->path);
++		drop_collected_mounts(priv->mnt);
++		kfree(priv);
++		return ret;
++	}
++
++	priv->m.private = priv;
++	return 0;
++}
++
++static int sb_files_release(struct inode *inode, struct file *file)
++{
++	struct sb_files_mount *priv = file->private_data;
++	if (priv) {
++		path_put(&priv->path);
++		drop_collected_mounts(priv->mnt);
++		kfree(priv);
++	}
++	return 0;
++}
++
++static ssize_t sb_files_write(struct file *file, const char __user *buf,
++		size_t count, loff_t *ppos)
++{
++	size_t c = sizeof(mnt_path)-1 < count ? sizeof(mnt_path)-1 : count;
++	int ret;
++	if (unlikely((ret = copy_from_user(mnt_path, buf, c)) < 0))
++		return -EFAULT;
++	mnt_path[c] = 0;
++	if (c > 1) {
++		if (mnt_path[c-1] == '\n')
++			mnt_path[c-1] = '\0';
++	}
++	*ppos += c;
++	return c;
++}
++
++static const struct file_operations sb_files_proc_fops = {
++	.open           = sb_files_open,
++	.release        = sb_files_release,
++	.read           = seq_read,
++	.llseek         = seq_lseek,
++
++	/* FIXME */
++	.write		= sb_files_write,
++};
++
++int __init fastboot_hibernation_misc_init(void)
++{
++	proc_create("dump_sb_files", 0444, NULL, &sb_files_proc_fops);
++	return 0;
++}
++
++#ifdef MODULE
++void __exit fastboot_hibernation_misc_exit(void)
++{
++	remove_proc_entry("dump_sb_files", NULL);
++}
++#endif
+diff --git a/arch/arm/mach-hisi/fastboot/hibernate_pmmon.c b/arch/arm/mach-hisi/fastboot/hibernate_pmmon.c
+new file mode 100644
+index 0000000..5add8d7
+--- /dev/null
++++ b/arch/arm/mach-hisi/fastboot/hibernate_pmmon.c
+@@ -0,0 +1,107 @@
++#include <linux/module.h>
++#include <linux/sysctl.h>
++#include <linux/suspend.h>
++
++#include "fastboot_pm.h"
++
++#if defined(CONFIG_PM) && defined(CONFIG_SUSPEND)
++
++static char *pm_umh_str;
++static int fastboot_pm_monitor(struct notifier_block *this,
++		unsigned long event, void *ptr)
++{
++	switch (event) {
++	case PM_HIBERNATION_PREPARE: /* starting pm_suspend_to_hibernation */
++		pm_umh_str = "PM_HIBERNATION_PREPARE";
++		break;
++	case PM_POST_HIBERNATION: /* end of pm_resume_from_hibernation */
++		pm_umh_str = "PM_POST_HIBERNATION";
++		break;
++	case PM_SUSPEND_PREPARE: /* starting pm_suspend */
++		pm_umh_str = "PM_SUSPEND_PREPARE";
++		break;
++	case PM_POST_SUSPEND: /* end of pm_resume */
++		pm_umh_str = "PM_POST_SUSPEND";
++		break;
++	case PM_RESTORE_PREPARE: /* pm_suspend failure ? */
++		pm_umh_str = "PM_RESTORE_PREPARE";
++		break;
++	case PM_POST_RESTORE: /* pm_suspend failure ? */
++		pm_umh_str = "PM_POST_RESTORE";
++		break;
++	case PM_POST_FREEZE_PROCESS:
++		pm_umh_str = "PM_POST_FREEZE_PROCESS";
++		break;
++	case PM_THAW_PROCESS_PREPARE:
++		pm_umh_str = "PM_THAW_PROCESS_PREPARE";
++		/*mark by liucan*/
++        //fastboot_hibernate_fs_resume();
++		break;
++	case PM_POST_DEVICE_SUSPEND:
++		pm_umh_str = "PM_POST_DEVICE_SUSPEND";
++		break;
++	case PM_RESUME_DEVICE_PREPARE:
++		pm_umh_str = "PM_RESUME_DEVICE_PREPARE";
++		break;
++	default:
++		printk("%s: unknown event, ignoring...\n", __func__);
++		return 0;
++	}
++
++	/* FIXME:
++	 *  The callee must be on a initrd in order to handle DEVICE events.
++	 *  Or it will be blocked forever because a storage was suspended.
++	 */
++	if (event != PM_POST_DEVICE_SUSPEND
++			&& event != PM_RESUME_DEVICE_PREPARE) {
++		fastboot_pm_call_umh(pm_umh_str, event);
++	}
++
++	switch (event) {
++		case PM_POST_FREEZE_PROCESS:
++            // mark by liucan.
++			//fastboot_hibernate_fs_suspend();
++			//break;
++		case PM_HIBERNATION_PREPARE:
++		case PM_POST_HIBERNATION:
++		case PM_SUSPEND_PREPARE:
++		case PM_POST_SUSPEND:
++		case PM_RESTORE_PREPARE:
++		case PM_POST_RESTORE:
++		case PM_THAW_PROCESS_PREPARE:
++		case PM_POST_DEVICE_SUSPEND:
++		case PM_RESUME_DEVICE_PREPARE:
++		default:
++			return 0;
++	}
++
++	return 0;
++}
++
++static struct notifier_block fastboot_pm_notifier = {
++	.notifier_call = fastboot_pm_monitor,
++};
++
++static int __init fastboot_pm_monitor_init(void)
++{
++	register_pm_notifier(&fastboot_pm_notifier);
++	return 0;
++}
++#if 0
++#ifdef MODULE
++static void __exit fastboot_pm_monitor_exit(void)
++{
++	printk("hahaha\n");
++	unregister_pm_notifier(&fastboot_pm_notifier);
++}
++
++module_init(fastboot_pm_monitor_init);
++module_exit(fastboot_pm_monitor_exit);
++#else
++late_initcall(fastboot_pm_monitor_init);
++#endif
++#endif
++late_initcall(fastboot_pm_monitor_init);
++#endif /* CONFIG_PM && CONFIG_SUSPEND */
++
++MODULE_LICENSE("GPL");
+diff --git a/arch/arm/mach-hisi/fastboot/hibernate_umh.c b/arch/arm/mach-hisi/fastboot/hibernate_umh.c
+new file mode 100644
+index 0000000..9f56da4
+--- /dev/null
++++ b/arch/arm/mach-hisi/fastboot/hibernate_umh.c
+@@ -0,0 +1,79 @@
++#include <linux/module.h>
++#include <linux/sysctl.h>
++#include <linux/suspend.h>
++
++#include "fastboot_pm.h"
++
++/*
++ * ToDo
++ *  add uevent
++ */
++
++#if defined(CONFIG_PM) && defined(CONFIG_SUSPEND)
++
++#define PM_EVENT_HELPER_LEN (32)
++
++static char pm_umh_helper[PM_EVENT_HELPER_LEN] = { 0, };
++static struct ctl_table_header *ctl;
++
++static struct ctl_table pm_umh_ctl[] = {
++	{
++		.procname	= "pm_notifier",
++		.data		= &pm_umh_helper,
++		.maxlen		= PM_EVENT_HELPER_LEN,
++		.mode		= 0644,
++		.proc_handler	= proc_dostring,
++	},
++	{}
++};
++
++static struct ctl_path pm_umh_root[] = {
++	{
++		.procname	= "kernel",
++	},
++	{}
++};
++
++int fastboot_pm_call_umh(char *event_str, unsigned long event)
++{
++	char *argv[3] = {pm_umh_helper, event_str, NULL};
++	char *envp[3] = {"HOME=/", NULL, NULL };
++	int ret;
++
++	if (!pm_umh_helper[0])
++		return 0;
++
++	/* NOTE: may cannot access to Android's property services. */
++	envp[1] = "PATH=/usr/bin:/usr/sbin:/bin:/sbin";
++	ret = call_usermodehelper_fns_force(argv[0], argv, envp,
++			UMH_WAIT_PROC, NULL, NULL, NULL);
++	if (ret < 0)
++		pr_err("%s: helper failed(%d)\n", __func__, ret);
++
++	return 0;
++}
++EXPORT_SYMBOL_GPL(fastboot_pm_call_umh);
++
++static int __init fastboot_pm_umh_init(void)
++{
++	ctl = register_sysctl_paths(pm_umh_root, pm_umh_ctl);
++	fastboot_hibernation_misc_init();
++	return 0;
++}
++
++#if 0
++#ifdef MODULE
++static void __exit fastboot_pm_umh_exit(void)
++{
++	fastboot_hibernation_misc_exit();
++	unregister_sysctl_table(ctl);
++}
++
++module_init(fastboot_pm_umh_init);
++module_exit(fastboot_pm_umh_exit);
++#else
++late_initcall(fastboot_pm_umh_init);
++#endif
++#endif
++late_initcall(fastboot_pm_umh_init);
++#endif /* CONFIG_PM && CONFIG_SUSPEND */
+diff --git a/arch/arm/mach-hisi/headsmp.S b/arch/arm/mach-hisi/headsmp.S
+index 278889c..0d0abd4 100644
+--- a/arch/arm/mach-hisi/headsmp.S
++++ b/arch/arm/mach-hisi/headsmp.S
+@@ -8,9 +8,292 @@
+  */
+ #include <linux/linkage.h>
+ #include <linux/init.h>
++#include <asm/assembler.h>
+ 
+ 	__CPUINIT
+ 
+ ENTRY(hix5hd2_secondary_startup)
+ 	bl	v7_invalidate_l1
+ 	b	secondary_startup
++ENDPROC(hix5hd2_secondary_startup)
++
++
++ENTRY(hi3519_secondary_startup)
++	/* Set A17 acinactive to 1, bit 8 is acinactive */
++	bl      hi_pmc_clear_a17_ac
++
++	bl	cci_enable_port_for_self
++
++	/* config l2ctl */
++	mrc     p15, 1, r0, c9, c0, 2
++	mov     r2, #0x100000
++	orr     r1, r1, r2
++	mcr     p15, 1, r0, c9, c0, 2
++
++	/*
++	 * set SMP bit ACTLR register for A17 slave core
++	 */
++	mrc     p15, 0, r0, c1, c0, 1
++	orr     r0, #(1 << 6)
++	mcr     p15, 0, r0, c1, c0, 1
++
++	bl      v7_invalidate_l1
++
++	b       secondary_startup
++ENDPROC(hi3519_secondary_startup)
++
++ENTRY(hi3519_cpu_resume)
++	safe_svcmode_maskall    r1
++
++	/* Set A17 acinactive to 0, bit 8 is acinactive */
++	bl      hi_pmc_clear_a17_ac
++
++	bl	cci_enable_port_for_self
++
++        /* config l2ctl, just follow the datasheet why?*/
++        mrc     p15, 1, r0, c9, c0, 2
++        mov     r2, #0x100000
++        orr     r1, r1, r2
++        mcr     p15, 1, r0, c9, c0, 2
++
++        /*
++         * set SMP bit ACTLR register for A17 slave core
++         */
++        mrc     p15, 0, r0, c1, c0, 1
++        orr     r0, #(1 << 6)
++        mcr     p15, 0, r0, c1, c0, 1
++
++        b       cpu_resume
++
++ENDPROC(hi3519_cpu_resume)
++
++ENTRY(hi3516av200_secondary_startup)
++	/* Set A17 acinactive to 1, bit 8 is acinactive */
++	bl      hi_pmc_clear_a17_ac
++
++	bl	cci_enable_port_for_self
++
++	/* config l2ctl */
++	mrc     p15, 1, r0, c9, c0, 2
++	mov     r2, #0x100000
++	orr     r1, r1, r2
++	mcr     p15, 1, r0, c9, c0, 2
++
++	/*
++	 * set SMP bit ACTLR register for A17 slave core
++	 */
++	mrc     p15, 0, r0, c1, c0, 1
++	orr     r0, #(1 << 6)
++	mcr     p15, 0, r0, c1, c0, 1
++
++	bl      v7_invalidate_l1
++
++	b       secondary_startup
++ENDPROC(hi3516av200_secondary_startup)
++
++ENTRY(hi3516av200_cpu_resume)
++	safe_svcmode_maskall    r1
++
++	/* Set A17 acinactive to 0, bit 8 is acinactive */
++	bl      hi_pmc_clear_a17_ac
++
++	bl	cci_enable_port_for_self
++
++        /* config l2ctl, just follow the datasheet why?*/
++        mrc     p15, 1, r0, c9, c0, 2
++        mov     r2, #0x100000
++        orr     r1, r1, r2
++        mcr     p15, 1, r0, c9, c0, 2
++
++        /*
++         * set SMP bit ACTLR register for A17 slave core
++         */
++        mrc     p15, 0, r0, c1, c0, 1
++        orr     r0, #(1 << 6)
++        mcr     p15, 0, r0, c1, c0, 1
++
++        b       cpu_resume
++
++ENDPROC(hi3516av200_cpu_resume)
++
++ENTRY(hi3559_secondary_startup)
++	/* Set A17 acinactive to 1, bit 8 is acinactive */
++	bl      hi_pmc_clear_a17_ac
++
++	bl	cci_enable_port_for_self
++
++	/* config l2ctl */
++	mrc     p15, 1, r0, c9, c0, 2
++	mov     r2, #0x100000
++	orr     r1, r1, r2
++	mcr     p15, 1, r0, c9, c0, 2
++
++	/*
++	 * set SMP bit ACTLR register for A17 slave core
++	 */
++	mrc     p15, 0, r0, c1, c0, 1
++	orr     r0, #(1 << 6)
++	mcr     p15, 0, r0, c1, c0, 1
++
++	bl      v7_invalidate_l1
++
++	b       secondary_startup
++ENDPROC(hi3559_secondary_startup)
++
++ENTRY(hi3559_cpu_resume)
++	safe_svcmode_maskall    r1
++
++	/* Set A17 acinactive to 0, bit 8 is acinactive */
++	bl      hi_pmc_clear_a17_ac
++
++	bl	cci_enable_port_for_self
++
++        /* config l2ctl, just follow the datasheet why?*/
++        mrc     p15, 1, r0, c9, c0, 2
++        mov     r2, #0x100000
++        orr     r1, r1, r2
++        mcr     p15, 1, r0, c9, c0, 2
++
++        /*
++         * set SMP bit ACTLR register for A17 slave core
++         */
++        mrc     p15, 0, r0, c1, c0, 1
++        orr     r0, #(1 << 6)
++        mcr     p15, 0, r0, c1, c0, 1
++
++        b       cpu_resume
++
++ENDPROC(hi3559_cpu_resume)
++
++#ifdef CONFIG_ARCH_HI3531D
++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++@
++@  corrupt: r0, r1, r2, r3
++@
++.align  2
++
++flash_cache_all:
++
++    /* disable MMU stuff and caches */
++    mrc p15, 0, r0, c1, c0, 0
++    orr r0, r0, #0x00002000      /* clear bits 13 (--V-)   */
++    bic r0, r0, #0x00000007      /* clear bits 2:0 (-CAM)  */
++    orr r0, r0, #0x00000002      /* set bit 1 (--A-) Align */
++    orr r0, r0, #0x00000800      /* set bit 12 (Z---) BTB  */
++    mcr p15, 0, r0, c1, c0, 0
++
++    /*
++     * Invalidate L1 I/D
++     */
++    mov r0, #0                   /* set up for MCR */
++    mcr p15, 0, r0, c8, c7, 0    /* invalidate TLBs */
++    mcr p15, 0, r0, c7, c5, 0    /* invalidate icache */
++
++    /* Invalidate L1 D-cache */
++    mcr p15, 2, r0, c0, c0, 0    /* select L1 data cache */
++    /* Read Current Cache Size Identification Register */
++    mrc p15, 1, r3, c0, c0, 0
++    ldr r1, =0x1ff
++    and r3, r1, r3, LSR #13      /* r3 = (number of sets -1) */
++    mov r0, #0
++way_loop:
++    mov r1, #0                  /* r1->set counter */
++line_loop:
++    mov r2, r0, LSL #30
++    orr r2, r1, LSL #5           /* r2->set/way cache-op format */
++    mcr     p15, 0, r2, c7, c6, 2    /* Invalidate line described by r2 */
++    add r1, r1, #1               /* Increment set counter */
++    cmp r1, r3                   /* Check if the last set is reached */
++    ble line_loop                /* if not, continue the set_loop */
++    add r0, r0, #1               /* else, Increment way counter */
++    cmp r0, #4                   /* Check if the last way is reached */
++    blt way_loop                 /* if not, continue the way_loop */
++
++    mov pc, lr
++#endif
++
++ENTRY(hi3536c_secondary_startup)
++    /* set the cpu to SVC32 mode */
++    mrs r0, cpsr
++    bic r0, r0, #0x1f  /* r0 = ((~0x1F) & r0) */
++    orr r0, r0, #0xd3  /* r0 = (0xd3 | r0)    */
++    msr cpsr, r0
++
++    mrc p15, 0, r0, c0, c0, 5
++    and r0, r0, #15
++    adr r4, 1f
++    ldmia   r4, {r5, r6}
++    sub r4, r4, r5
++    add r6, r6, r4
++pen_36c:    ldr r7, [r6]
++    cmp r7, r0
++    bne pen_36c
++
++    /*
++     * we've been released from the holding pen: secondary_stack
++     * should now contain the SVC stack for this core
++     */
++    b   secondary_startup
++
++1:  .long   .
++    .long   pen_release
++ENDPROC(hi3536c_secondary_startup)
++
++ENTRY(hi3531d_secondary_startup)
++    /* set the cpu to SVC32 mode */
++    mrs r0, cpsr
++    bic r0, r0, #0x1f  /* r0 = ((~0x1F) & r0) */
++    orr r0, r0, #0xd3  /* r0 = (0xd3 | r0)    */
++    msr cpsr, r0
++
++#ifdef CONFIG_ARCH_HI3531D
++    bl flash_cache_all
++#endif
++
++    mrc p15, 0, r0, c0, c0, 5
++    and r0, r0, #15
++    adr r4, 1f
++    ldmia   r4, {r5, r6}
++    sub r4, r4, r5
++    add r6, r6, r4
++pen:    ldr r7, [r6]
++    cmp r7, r0
++    bne pen
++
++    /*
++     * we've been released from the holding pen: secondary_stack
++     * should now contain the SVC stack for this core
++     */
++   b   secondary_startup
++
++ 1:  .long   .
++    .long   pen_release
++ENDPROC(hi3531d_secondary_startup)
++
++ENTRY(hi3521d_secondary_startup)
++    /* set the cpu to SVC32 mode */
++    mrs r0, cpsr
++    bic r0, r0, #0x1f  /* r0 = ((~0x1F) & r0) */
++    orr r0, r0, #0xd3  /* r0 = (0xd3 | r0)    */
++    msr cpsr, r0
++
++    mrc p15, 0, r0, c0, c0, 5
++    and r0, r0, #15
++    adr r4, 1f
++    ldmia   r4, {r5, r6}
++    sub r4, r4, r5
++    add r6, r6, r4
++pen_21d:    ldr r7, [r6]
++    cmp r7, r0
++    bne pen_21d
++
++    /*
++     * we've been released from the holding pen: secondary_stack
++     * should now contain the SVC stack for this core
++     */
++    b   secondary_startup
++
++1:  .long   .
++    .long   pen_release
++ENDPROC(hi3521d_secondary_startup)
++
+diff --git a/arch/arm/mach-hisi/hibernate.c b/arch/arm/mach-hisi/hibernate.c
+new file mode 100644
+index 0000000..bd90b23
+--- /dev/null
++++ b/arch/arm/mach-hisi/hibernate.c
+@@ -0,0 +1,220 @@
++/*
++ * ARM Cortex-A7 save/restore for suspend to disk (Hibernation)
++ */
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/types.h>
++#include <linux/spinlock.h>
++#include <linux/poll.h>
++#include <linux/delay.h>
++#include <linux/sysrq.h>
++#include <linux/proc_fs.h>
++#include <linux/pm.h>
++#include <linux/device.h>
++#include <linux/suspend.h>
++#include <asm/irq.h>
++#include <asm/uaccess.h>
++#include <asm/tlbflush.h>
++#include <asm/suspend.h>
++#include <asm/cacheflush.h>
++
++typedef struct fault_regs {
++	unsigned long dfar;
++	unsigned long ifar;
++	unsigned long ifsr;
++	unsigned long dfsr;
++	unsigned long adfsr;
++	unsigned long aifsr;
++} cp15_fault_regs;
++
++typedef struct vfp_context {
++	unsigned long fpexc;
++	unsigned long fpscr;
++	/*we just used low 32bit of d0-d15*/
++	unsigned long d0_15[16];
++} vfp_context;
++
++typedef struct generic_timer_context {
++	unsigned long cntfrq;
++	unsigned long long cntvoff;
++	unsigned long cnthctl;
++	unsigned long cntkctl;
++	unsigned long long cntp_cval;
++	unsigned long cntp_tval;
++	unsigned long cntp_ctl;
++	unsigned long long cntv_cval;
++	unsigned long cntv_tval;
++	unsigned long cntv_ctl;
++	unsigned long long cnthp_cval;
++	unsigned long cnthp_tval;
++	unsigned long cnthp_ctl;
++} gen_timer_context;
++#if __LINUX_ARM_ARCH__ > 5
++typedef struct ns_saved_context {
++	unsigned long cp15_misc_regs[2];     /* cp15 miscellaneous registers */
++	unsigned long cp15_ctrl_regs[20];    /* cp15 control registers */
++	unsigned long cp15_mmu_regs[16];     /* cp15 mmu registers */
++	cp15_fault_regs cp15_fault_regs; /* cp15 fault status registers */
++	gen_timer_context gen_timer_regs;
++	vfp_context vfp_regs;
++} saved_context;
++#else  /* for ARM9 */
++/* image of the saved processor state */
++typedef struct ns_saved_context {
++	/*
++	 * Structure saved_context would be used to hold processor state
++	 * except caller and callee registers, just before suspending.
++	 */
++
++	/* coprocessor 15 registers */
++	//	__u32 ID_code;    /* read only reg */
++	//	__u32 cache_type; /* read only reg */
++	//	__u32 TCM_stat;   /* read only reg */
++	__u32 CR;
++	__u32 TTBR;
++	__u32 DACR;
++	__u32 D_FSR;
++	__u32 I_FSR;
++	__u32 FAR;
++	//	__u32 COR;    /*write only reg */
++	//	__u32 TLBOR;  /*write only reg */
++	__u32 D_CLR;
++	__u32 I_CLR;
++	__u32 D_TCMRR;
++	__u32 I_TCMRR;
++	__u32 TLBLR;
++	__u32 FCSE;
++	__u32 CID;
++} saved_context;
++#endif
++#ifdef CONFIG_DEBUG_LL
++extern void printascii(const char *);
++#endif
++
++extern const void __nosave_begin, __nosave_end;
++
++/*save&restore helper functions*/
++extern asmlinkage void save_cp15(void *pointer);
++extern asmlinkage void save_control_registers(void *pointer, int is_secure);
++extern asmlinkage void save_mmu(void *pointer);
++extern asmlinkage void save_fault_status(void *pointer);
++extern asmlinkage void save_vfp(void *pointer);
++extern asmlinkage void save_generic_timer(void *pointer, int is_hyp);
++extern asmlinkage void restore_control_registers(void *pointer, int is_secure);
++
++extern asmlinkage void restore_vfp(void *pointer);
++extern asmlinkage void restore_cp15(void *pointer);
++extern asmlinkage void restore_mmu(void *pointer);
++extern asmlinkage void restore_fault_status(void *pointer);
++extern asmlinkage void restore_generic_timer(void *pointer, int is_hyp);
++extern asmlinkage void invalidate_unified_TLB_inner_shareable(void);
++
++/*variable define here*/
++saved_context saved_ctx __attribute__((aligned(PAGE_SIZE)));
++
++const void *saved_processor_context = &saved_ctx;
++
++int pfn_is_nosave(unsigned long pfn)
++{
++	unsigned long nosave_begin_pfn = __pa_symbol(&__nosave_begin)
++		>> PAGE_SHIFT;
++	unsigned long nosave_end_pfn = PAGE_ALIGN(__pa_symbol(&__nosave_end))
++		>> PAGE_SHIFT;
++
++	return (pfn >= nosave_begin_pfn) && (pfn < nosave_end_pfn);
++}
++
++
++void __save_processor_state(saved_context *ctxt)
++{
++#ifdef CONFIG_DEBUG_LL
++	printascii("__save_processor_state(): enter\n");
++#endif
++#if __LINUX_ARM_ARCH__ > 5
++	save_cp15(ctxt->cp15_misc_regs);
++
++	save_control_registers(ctxt->cp15_ctrl_regs, 0x0);
++
++	save_mmu(ctxt->cp15_mmu_regs);
++
++	save_fault_status(&ctxt->cp15_fault_regs);
++
++	save_vfp(&ctxt->vfp_regs);
++#else   /* for ARM9 */
++	/* save coprocessor 15 registers */
++	asm volatile ("mrc p15, 0, %0, c1, c0, 0" : "=r" (ctxt->CR));
++	asm volatile ("mrc p15, 0, %0, c3, c0, 0" : "=r" (ctxt->DACR));
++	asm volatile ("mrc p15, 0, %0, c5, c0, 0" : "=r" (ctxt->D_FSR));
++	asm volatile ("mrc p15, 0, %0, c5, c0, 1" : "=r" (ctxt->I_FSR));
++	asm volatile ("mrc p15, 0, %0, c6, c0, 0" : "=r" (ctxt->FAR));
++	asm volatile ("mrc p15, 0, %0, c9, c0, 0" : "=r" (ctxt->D_CLR));
++	asm volatile ("mrc p15, 0, %0, c9, c0, 1" : "=r" (ctxt->I_CLR));
++	asm volatile ("mrc p15, 0, %0, c9, c1, 0" : "=r" (ctxt->D_TCMRR));
++	asm volatile ("mrc p15, 0, %0, c9, c1, 1" : "=r" (ctxt->I_TCMRR));
++	asm volatile ("mrc p15, 0, %0, c10, c0, 0" : "=r" (ctxt->TLBLR));
++	asm volatile ("mrc p15, 0, %0, c13, c0, 0" : "=r" (ctxt->FCSE));
++	asm volatile ("mrc p15, 0, %0, c13, c0, 1" : "=r" (ctxt->CID));
++	asm volatile ("mrc p15, 0, %0, c2, c0, 0" : "=r" (ctxt->TTBR));
++#endif
++
++#ifdef CONFIG_DEBUG_LL
++	printascii("__save_processor_state(): exit\n");
++#endif
++}
++
++
++void __restore_processor_state(saved_context *ctxt)
++{
++#ifdef CONFIG_DEBUG_LL
++	printascii("__restore_processor_state(): enter\n");
++#endif
++#if __LINUX_ARM_ARCH__ > 5
++	restore_vfp(&ctxt->vfp_regs);
++
++	restore_fault_status(&ctxt->cp15_fault_regs);
++
++	restore_mmu(ctxt->cp15_mmu_regs);
++
++	invalidate_unified_TLB_inner_shareable();
++
++	restore_control_registers(ctxt->cp15_ctrl_regs, 0x0);
++	isb();
++	dsb();
++
++	restore_cp15(ctxt->cp15_misc_regs);
++#else  /*for arm9 */
++	/* restore coprocessor 15 registers */
++	asm volatile ("mcr p15, 0, %0, c2, c0, 0" : : "r" (ctxt->TTBR));
++	asm volatile ("mcr p15, 0, %0, c13, c0, 1" : : "r" (ctxt->CID));
++	asm volatile ("mcr p15, 0, %0, c13, c0, 0" : : "r" (ctxt->FCSE));
++	asm volatile ("mcr p15, 0, %0, c10, c0, 0" : : "r" (ctxt->TLBLR));
++	asm volatile ("mcr p15, 0, %0, c9, c1, 1" : : "r" (ctxt->I_TCMRR));
++	asm volatile ("mcr p15, 0, %0, c9, c1, 0" : : "r" (ctxt->D_TCMRR));
++	asm volatile ("mcr p15, 0, %0, c9, c0, 1" : : "r" (ctxt->I_CLR));
++	asm volatile ("mcr p15, 0, %0, c9, c0, 0" : : "r" (ctxt->D_CLR));
++	asm volatile ("mcr p15, 0, %0, c6, c0, 0" : : "r" (ctxt->FAR));
++	asm volatile ("mcr p15, 0, %0, c5, c0, 1" : : "r" (ctxt->I_FSR));
++	asm volatile ("mcr p15, 0, %0, c5, c0, 0" : : "r" (ctxt->D_FSR));
++	asm volatile ("mcr p15, 0, %0, c3, c0, 0" : : "r" (ctxt->DACR));
++	asm volatile ("mcr p15, 0, %0, c1, c0, 0" : : "r" (ctxt->CR));
++#endif
++
++#ifdef CONFIG_DEBUG_LL
++	printascii("__restore_processor_state(): done\n");
++#endif
++}
++
++void save_processor_state(void)
++{
++	preempt_disable();
++	__save_processor_state(&saved_ctx);
++}
++EXPORT_SYMBOL(save_processor_state);
++
++void restore_processor_state(void)
++{
++	__restore_processor_state(&saved_ctx);
++	preempt_enable();
++}
++EXPORT_SYMBOL(restore_processor_state);
+diff --git a/arch/arm/mach-hisi/hisilicon.c b/arch/arm/mach-hisi/hisilicon.c
+index 7744c35..43d9d78 100644
+--- a/arch/arm/mach-hisi/hisilicon.c
++++ b/arch/arm/mach-hisi/hisilicon.c
+@@ -17,6 +17,7 @@
+ 
+ #include <asm/mach/arch.h>
+ #include <asm/mach/map.h>
++#include <mach/io.h>
+ 
+ #define HI3620_SYSCTRL_PHYS_BASE		0xfc802000
+ #define HI3620_SYSCTRL_VIRT_BASE		0xfe802000
+@@ -45,6 +46,268 @@ static void __init hi3620_map_io(void)
+ 	iotable_init(hi3620_io_desc, ARRAY_SIZE(hi3620_io_desc));
+ }
+ 
++extern unsigned long long notrace sched_clock(void);
++unsigned long long hi_sched_clock(void)
++{
++	return sched_clock();
++}
++EXPORT_SYMBOL(hi_sched_clock);
++
++#if (defined CONFIG_ARCH_HI3519 || defined CONFIG_ARCH_HI3519V101)
++static struct map_desc hi3519_io_desc[] __initdata = {
++	/* hi3519_IOCH1 */
++	{
++		.virtual        = HI3519_IOCH1_VIRT,
++		.pfn            = __phys_to_pfn(HI3519_IOCH1_PHYS),
++		.length         = HI3519_IOCH1_SIZE,
++		.type           = MT_DEVICE
++	},
++	/* hi3519_IOCH2 */
++	{
++		.virtual        = HI3519_IOCH2_VIRT,
++		.pfn            = __phys_to_pfn(HI3519_IOCH2_PHYS),
++		.length         = HI3519_IOCH2_SIZE,
++		.type           = MT_DEVICE
++	},
++	/* hi3519_IOCH2 */
++	{
++		.virtual        = HI3519_IOCH3_VIRT,
++		.pfn            = __phys_to_pfn(HI3519_IOCH3_PHYS),
++		.length         = HI3519_IOCH3_SIZE,
++		.type           = MT_DEVICE
++	},
++
++};
++
++static void __init hi3519_reserve(void)
++{
++#ifdef CONFIG_DMA_CMA
++	extern int hisi_declare_heap_memory(void);
++	hisi_declare_heap_memory();
++#endif
++}
++#endif
++
++#ifdef CONFIG_ARCH_HI3516AV200
++static struct map_desc hi3516av200_io_desc[] __initdata = {
++	/* hi3516av200_IOCH1 */
++	{
++		.virtual        = HI3516AV200_IOCH1_VIRT,
++		.pfn            = __phys_to_pfn(HI3516AV200_IOCH1_PHYS),
++		.length         = HI3516AV200_IOCH1_SIZE,
++		.type           = MT_DEVICE
++	},
++	/* hi3516av200_IOCH2 */
++	{
++		.virtual        = HI3516AV200_IOCH2_VIRT,
++		.pfn            = __phys_to_pfn(HI3516AV200_IOCH2_PHYS),
++		.length         = HI3516AV200_IOCH2_SIZE,
++		.type           = MT_DEVICE
++	},
++	/* hi3516av200_IOCH2 */
++	{
++		.virtual        = HI3516AV200_IOCH3_VIRT,
++		.pfn            = __phys_to_pfn(HI3516AV200_IOCH3_PHYS),
++		.length         = HI3516AV200_IOCH3_SIZE,
++		.type           = MT_DEVICE
++	},
++
++};
++
++static void __init hi3516av200_reserve(void)
++{
++#ifdef CONFIG_DMA_CMA
++	extern int hisi_declare_heap_memory(void);
++	hisi_declare_heap_memory();
++#endif
++}
++#endif
++#if defined(CONFIG_ARCH_HI3559) || defined(CONFIG_ARCH_HI3556)
++static struct map_desc hi3559_io_desc[] __initdata = {
++	/* hi3559_IOCH1 */
++	{
++		.virtual        = HI3559_IOCH1_VIRT,
++		.pfn            = __phys_to_pfn(HI3559_IOCH1_PHYS),
++		.length         = HI3559_IOCH1_SIZE,
++		.type           = MT_DEVICE
++	},
++	/* hi3559_IOCH2 */
++	{
++		.virtual        = HI3559_IOCH2_VIRT,
++		.pfn            = __phys_to_pfn(HI3559_IOCH2_PHYS),
++		.length         = HI3559_IOCH2_SIZE,
++		.type           = MT_DEVICE
++	},
++	/* hi3559_IOCH2 */
++	{
++		.virtual        = HI3559_IOCH3_VIRT,
++		.pfn            = __phys_to_pfn(HI3559_IOCH3_PHYS),
++		.length         = HI3559_IOCH3_SIZE,
++		.type           = MT_DEVICE
++	},
++
++};
++#endif
++
++#ifdef CONFIG_ARCH_HI3536C
++static struct map_desc hi3536c_io_desc[] __initdata = {
++	/* hi3536c_IOCH1 */
++	{
++		.virtual    = HI3536C_IOCH1_VIRT,
++		.pfn        = __phys_to_pfn(HI3536C_IOCH1_PHYS),
++		.length     = HI3536C_IOCH1_SIZE,
++		.type       = MT_DEVICE
++	},
++	/* hi3536c_IOCH2 */
++	{
++		.virtual        = HI3536C_IOCH2_VIRT,
++		.pfn            = __phys_to_pfn(HI3536C_IOCH2_PHYS),
++		.length         = HI3536C_IOCH2_SIZE,
++		.type           = MT_DEVICE
++	},
++	/* hi3536c_IOCH3 */
++	{
++		.virtual        = HI3536C_IOCH3_VIRT,
++		.pfn            = __phys_to_pfn(HI3536C_IOCH3_PHYS),
++		.length         = HI3536C_IOCH3_SIZE,
++		.type           = MT_DEVICE
++	},
++};
++
++static void __init hi3536c_map_io(void)
++{
++	iotable_init(hi3536c_io_desc, ARRAY_SIZE(hi3536c_io_desc));
++}
++
++static void __init hi3536c_init_early(void)
++{
++
++}
++#endif /* CONFIG_ARCH_HI3536C */
++
++#ifdef CONFIG_ARCH_HI3531D
++static struct map_desc hi3531d_io_desc[] __initdata = {
++	/* hi3531d_IOCH1 */
++	{
++		.virtual    = HI3531D_IOCH1_VIRT,
++		.pfn        = __phys_to_pfn(HI3531D_IOCH1_PHYS),
++		.length     = HI3531D_IOCH1_SIZE,
++		.type       = MT_DEVICE
++	},
++	/* hi3531d_IOCH2 */
++	{
++		.virtual    = HI3531D_IOCH2_VIRT,
++		.pfn        = __phys_to_pfn(HI3531D_IOCH2_PHYS),
++		.length     = HI3531D_IOCH2_SIZE,
++		.type       = MT_DEVICE
++	},
++	/* hi3531d_IOCH3 */
++	{
++		.virtual    = HI3531D_IOCH3_VIRT,
++		.pfn        = __phys_to_pfn(HI3531D_IOCH3_PHYS),
++		.length     = HI3531D_IOCH3_SIZE,
++		.type       = MT_DEVICE
++	},
++	/* hi3531d_IOCH4 */
++	{
++		.virtual    = HI3531D_IOCH4_VIRT,
++		.pfn        = __phys_to_pfn(HI3531D_IOCH4_PHYS),
++		.length     = HI3531D_IOCH4_SIZE,
++		.type       = MT_DEVICE
++	},
++
++};
++
++void __init hi3531d_map_io(void)
++{
++	iotable_init(hi3531d_io_desc, ARRAY_SIZE(hi3531d_io_desc));
++}
++
++static void __init hi3531d_init_early(void)
++{
++	/*
++	 * 1. enable L1 prefetch                       [2]
++	 * 4. enable allocation in one cache way only. [8]
++	 */
++	asm volatile (
++			"   mrc p15, 0, r0, c1, c0, 1\n"
++			"   orr r0, r0, #0x104\n"
++			"   mcr p15, 0, r0, c1, c0, 1\n"
++			:
++			:
++			: "r0", "cc");
++
++}
++#endif
++
++#ifdef CONFIG_ARCH_HI3521D
++static struct map_desc hi3521d_io_desc[] __initdata = {
++	/* hi3521d_IOCH1 */
++	{
++		.virtual    = HI3521D_IOCH1_VIRT,
++		.pfn        = __phys_to_pfn(HI3521D_IOCH1_PHYS),
++		.length     = HI3521D_IOCH1_SIZE,
++		.type       = MT_DEVICE
++	},
++	/* hi3521d_IOCH2 */
++	{
++		.virtual        = HI3521D_IOCH2_VIRT,
++		.pfn            = __phys_to_pfn(HI3521D_IOCH2_PHYS),
++		.length         = HI3521D_IOCH2_SIZE,
++		.type           = MT_DEVICE
++	},
++	/* hi3521d_IOCH3 */
++	{
++		.virtual        = HI3521D_IOCH3_VIRT,
++		.pfn            = __phys_to_pfn(HI3521D_IOCH3_PHYS),
++		.length         = HI3521D_IOCH3_SIZE,
++		.type           = MT_DEVICE
++	},
++};
++
++static void __init hi3521d_map_io(void)
++{
++	iotable_init(hi3521d_io_desc, ARRAY_SIZE(hi3521d_io_desc));
++}
++
++static void __init hi3521d_init_early(void)
++{
++
++}
++#endif /* CONFIG_ARCH_HI3521D */
++
++#if (defined CONFIG_ARCH_HI3519 || defined CONFIG_ARCH_HI3519V101)
++static void __init hi3519_map_io(void)
++{
++	/* debug_ll_io_init(); */
++	iotable_init(hi3519_io_desc, ARRAY_SIZE(hi3519_io_desc));
++}
++#endif
++
++#ifdef CONFIG_ARCH_HI3516AV200
++static void __init hi3516av200_map_io(void)
++{
++	/* debug_ll_io_init(); */
++	iotable_init(hi3516av200_io_desc, ARRAY_SIZE(hi3516av200_io_desc));
++}
++#endif
++
++#if defined(CONFIG_ARCH_HI3559) || defined(CONFIG_ARCH_HI3556)
++static void __init hi3559_map_io(void)
++{
++	/* debug_ll_io_init(); */
++	iotable_init(hi3559_io_desc, ARRAY_SIZE(hi3559_io_desc));
++}
++
++static void __init hi3559_reserve(void)
++{
++#ifdef CONFIG_DMA_CMA
++	extern int hisi_declare_heap_memory(void);
++	hisi_declare_heap_memory();
++#endif
++}
++#endif
++
+ static const char *hi3xxx_compat[] __initconst = {
+ 	"hisilicon,hi3620-hi4511",
+ 	NULL,
+@@ -72,3 +335,100 @@ static const char *hip04_compat[] __initconst = {
+ DT_MACHINE_START(HIP04, "Hisilicon HiP04 (Flattened Device Tree)")
+ 	.dt_compat	= hip04_compat,
+ MACHINE_END
++
++#if (defined CONFIG_ARCH_HI3519 || defined CONFIG_ARCH_HI3519V101)
++static const char *hi3519_compat[] __initconst = {
++	"hisilicon,hi3519",
++	"hisilicon,hi3519v101",
++	NULL,
++};
++#endif
++
++#ifdef CONFIG_ARCH_HI3516AV200
++static const char *hi3516av200_compat[] __initconst = {
++	"hisilicon,hi3516av200",
++	NULL,
++};
++#endif
++#if defined(CONFIG_ARCH_HI3559) || defined(CONFIG_ARCH_HI3556)
++static const char *hi3559_compat[] __initconst = {
++	"hisilicon,hi3559",
++	"hisilicon,hi3556",
++	NULL,
++};
++#endif
++
++#if (defined CONFIG_ARCH_HI3519 || defined CONFIG_ARCH_HI3519V101)
++DT_MACHINE_START(HI3519_DT, "Hisilicon Hi3519 (Flattened Device Tree)")
++	.map_io		= hi3519_map_io,
++	.dt_compat	= hi3519_compat,
++	.reserve	= hi3519_reserve,
++MACHINE_END
++#endif
++
++#ifdef CONFIG_ARCH_HI3516AV200
++DT_MACHINE_START(HI3516AV200_DT, "Hisilicon Hi3516av200 (Flattened Device Tree)")
++	.map_io		= hi3516av200_map_io,
++	.dt_compat	= hi3516av200_compat,
++	.reserve	= hi3516av200_reserve,
++MACHINE_END
++#endif
++#if defined(CONFIG_ARCH_HI3559) || defined(CONFIG_ARCH_HI3556)
++DT_MACHINE_START(HI3559_DT, "Hisilicon Hi3559/Hi3556 (Flattened Device Tree)")
++	.map_io		= hi3559_map_io,
++	.dt_compat	= hi3559_compat,
++	.reserve	= hi3559_reserve,
++MACHINE_END
++#endif
++
++#ifdef CONFIG_ARCH_HI3516CV300
++static const char *hi3516cv300_compat[] __initconst = {
++	"hisilicon,hi3516cv300",
++	NULL,
++};
++
++DT_MACHINE_START(HI3516CV300_DT,
++		"Hisilicon Hi3516cv300 (Flattened Device Tree)")
++	.dt_compat	= hi3516cv300_compat,
++MACHINE_END
++#endif
++
++#ifdef CONFIG_ARCH_HI3536C
++static const char *hi3536c_compat[] __initconst = {
++	"hisilicon,hi3536c",
++	NULL,
++};
++
++DT_MACHINE_START(HI3536C_DT, "Hisilicon Hi3536C (Flattened Device Tree)")
++	.map_io		= hi3536c_map_io,
++	.dt_compat	= hi3536c_compat,
++	.init_early	= hi3536c_init_early,
++MACHINE_END
++#endif
++
++#ifdef CONFIG_ARCH_HI3531D
++static const char *hi3531d_compat[] __initconst = {
++	"hisilicon,hi3531d",
++	NULL,
++};
++
++DT_MACHINE_START(HI3531D_DT, "Hisilicon Hi3531D (Flattened Device Tree)")
++	.map_io		= hi3531d_map_io,
++	.dt_compat	= hi3531d_compat,
++	.init_early   = hi3531d_init_early,
++MACHINE_END
++#endif
++
++#ifdef CONFIG_ARCH_HI3521D
++static const char *hi3521d_compat[] __initconst = {
++	"hisilicon,hi3521d",
++	NULL,
++};
++
++DT_MACHINE_START(HI3521D_DT, "Hisilicon Hi3521D (Flattened Device Tree)")
++	.map_io		= hi3521d_map_io,
++	.dt_compat	= hi3521d_compat,
++	.init_early	= hi3521d_init_early,
++MACHINE_END
++#endif
++
+diff --git a/arch/arm/mach-hisi/hotplug.c b/arch/arm/mach-hisi/hotplug.c
+index 84e6919..5f3ebf6 100644
+--- a/arch/arm/mach-hisi/hotplug.c
++++ b/arch/arm/mach-hisi/hotplug.c
+@@ -11,11 +11,22 @@
+ #include <linux/delay.h>
+ #include <linux/io.h>
+ #include <linux/of_address.h>
++#include <linux/arm-cci.h>
++#include <linux/irqchip/arm-gic.h>
+ #include <linux/of_platform.h>
+ #include <asm/cacheflush.h>
+ #include <asm/smp_plat.h>
++#include <asm/cp15.h>
++
+ #include "core.h"
+ 
++#if (defined(CONFIG_ARCH_HI3531D) \
++	|| defined(CONFIG_ARCH_HI3536C) \
++	|| defined(CONFIG_ARCH_HI3521D))
++#include <mach/io.h>
++#include <mach/platform.h>
++#endif
++
+ /* Sysctrl registers in Hi3620 SoC */
+ #define SCISOEN				0xc0
+ #define SCISODIS			0xc4
+@@ -257,4 +268,289 @@ void hix5hd2_cpu_die(unsigned int cpu)
+ 	flush_cache_all();
+ 	hix5hd2_set_cpu(cpu, false);
+ }
++
++int hi3519_cpu_kill(unsigned int cpu)
++{
++#ifdef CONFIG_ARCH_HI3519
++	hi_pmc_kill_cpu(cpu);
++#endif
++	return 1;
++}
++
++int hi3559_cpu_kill(unsigned int cpu)
++{
++	return 1;
++}
++
++int hi3516av200_cpu_kill(unsigned int cpu)
++{
++	return 1;
++}
++
++void hi3519_cpu_die(unsigned int cpu)
++{
++	/*avoid interrupt to disturb wfi&&pmc sequence */
++	gic_cpu_if_down();
++	/* disable Dcache */
++	set_cr(get_cr() & ~CR_C);
++	/* CLREX */
++	asm volatile ("clrex");
++
++	/* Clean & Invalidata L1 Data Cache, L2 Cache */
++	/*     flush_cache_all(); */
++
++	/* clean&invalidate l1 cache */
++	asm volatile("mov r0, #0\n");
++	asm volatile("mcr p15, 1, r0, c15, c14, 0\n");
++	asm volatile("dsb\n");
++
++	/* clean&invalidate l2 cache */
++	asm volatile("mov r0, #2\n");
++	asm volatile("mcr p15, 1, r0, c15, c14, 0\n");
++	asm volatile("dsb\n");
++
++	/* Set ACTLR.SMP to 0, AMP -> SMP */
++	asm volatile (
++			"       mrc     p15, 0, r0, c1, c0, 1\n"
++			"       bic     r0,  #0x40\n"
++			"       mcr     p15, 0, r0, c1, c0, 1\n"
++			:
++			:
++			: "r0", "cc");
++
++	/* disable cci snoop */
++	cci_disable_port_by_cpu(cpu_logical_map(cpu));
++
++	/* avoid debug event wake up cpu */
++	/* asm volatile("mcr p14, 0, %0, c1, c3, 0" : : "r" (1)); */
++
++	/* ISB & DSB */
++	isb();
++	dsb();
++
++	/* clear core ac inactive */
++	hi_pmc_set_ac_inactive();
++
++	/* power down  */
++	hi_pmc_power_down();
++
++	dsb();
++	/* wfi */
++	while (1)
++		wfi();
++
++}
++
++void hi3516av200_cpu_die(unsigned int cpu)
++{
++	/*avoid interrupt to disturb wfi&&pmc sequence */
++	gic_cpu_if_down();
++	/* disable Dcache */
++	set_cr(get_cr() & ~CR_C);
++	/* CLREX */
++	asm volatile ("clrex");
++
++	/* Clean & Invalidata L1 Data Cache, L2 Cache */
++	/*     flush_cache_all(); */
++
++	/* clean&invalidate l1 cache */
++	asm volatile("mov r0, #0\n");
++	asm volatile("mcr p15, 1, r0, c15, c14, 0\n");
++	asm volatile("dsb\n");
++
++	/* clean&invalidate l2 cache */
++	asm volatile("mov r0, #2\n");
++	asm volatile("mcr p15, 1, r0, c15, c14, 0\n");
++	asm volatile("dsb\n");
++
++	/* Set ACTLR.SMP to 0, AMP -> SMP */
++	asm volatile (
++			"       mrc     p15, 0, r0, c1, c0, 1\n"
++			"       bic     r0,  #0x40\n"
++			"       mcr     p15, 0, r0, c1, c0, 1\n"
++			:
++			:
++			: "r0", "cc");
++
++	/* disable cci snoop */
++	cci_disable_port_by_cpu(cpu_logical_map(cpu));
++
++	/* avoid debug event wake up cpu */
++	/* asm volatile("mcr p14, 0, %0, c1, c3, 0" : : "r" (1)); */
++
++	/* ISB & DSB */
++	isb();
++	dsb();
++
++	/* clear core ac inactive */
++	hi_pmc_set_ac_inactive();
++
++	/* power down  */
++	hi_pmc_power_down();
++
++	dsb();
++	/* wfi */
++	while (1)
++		wfi();
++
++}
++
++void hi3559_cpu_die(unsigned int cpu)
++{
++	/*avoid interrupt to disturb wfi&&pmc sequence */
++	gic_cpu_if_down();
++	/* disable Dcache */
++	set_cr(get_cr() & ~CR_C);
++	/* CLREX */
++	asm volatile ("clrex");
++
++	/* Clean & Invalidata L1 Data Cache, L2 Cache */
++	/*     flush_cache_all(); */
++
++	/* clean&invalidate l1 cache */
++	asm volatile("mov r0, #0\n");
++	asm volatile("mcr p15, 1, r0, c15, c14, 0\n");
++	asm volatile("dsb\n");
++
++	/* clean&invalidate l2 cache */
++	asm volatile("mov r0, #2\n");
++	asm volatile("mcr p15, 1, r0, c15, c14, 0\n");
++	asm volatile("dsb\n");
++
++	/* Set ACTLR.SMP to 0, AMP -> SMP */
++	asm volatile (
++			"       mrc     p15, 0, r0, c1, c0, 1\n"
++			"       bic     r0,  #0x40\n"
++			"       mcr     p15, 0, r0, c1, c0, 1\n"
++			:
++			:
++			: "r0", "cc");
++
++	/* disable cci snoop */
++	cci_disable_port_by_cpu(cpu_logical_map(cpu));
++
++	/* avoid debug event wake up cpu */
++	/* asm volatile("mcr p14, 0, %0, c1, c3, 0" : : "r" (1)); */
++
++	/* ISB & DSB */
++	isb();
++	dsb();
++
++	/* clear core ac inactive */
++	hi_pmc_set_ac_inactive();
++
++	/* power down  */
++	hi_pmc_power_down();
++
++	dsb();
++	/* wfi */
++	while (1)
++		wfi();
++
++}
++
++int hi3536c_cpu_kill(unsigned int cpu)
++{
++	return 1;
++}
++
++void hi3536c_scu_power_up(int cpu)
++{
++#ifdef CONFIG_ARCH_HI3536C
++	unsigned int regval;
++
++	/* clear the slave cpu reset */
++	regval = readl(__io_address(CRG_REG_BASE + REG_A7_SRST_CRG));
++	regval &= ~CORE1_SRST_REQ;
++	writel(regval, __io_address(CRG_REG_BASE + REG_A7_SRST_CRG));
++#endif
++}
++
++static inline void hi3536c_scu_power_off(int cpu)
++{
++#ifdef CONFIG_ARCH_HI3536C
++	unsigned long regval;
++
++	regval = readl(__io_address(CRG_REG_BASE + REG_A7_SRST_CRG));
++	regval |= (DBG1_SRST_REQ | CORE1_SRST_REQ);
++	writel(regval, __io_address(CRG_REG_BASE + REG_A7_SRST_CRG));
++#endif
++}
++
++void hi3536c_cpu_die(unsigned int cpu)
++{
++	flush_cache_all();
++	hi3536c_scu_power_off(cpu);
++	BUG();
++}
++
++int hi3531d_cpu_kill(unsigned int cpu)
++{
++	return 1;
++}
++
++void hi3531d_scu_power_up(int cpu)
++{
++#ifdef CONFIG_ARCH_HI3531D
++	unsigned int regval;
++
++	/* clear the slave cpu reset */
++	regval = readl(__io_address(CRG_REG_BASE + REG_A9_SRST_CRG));
++	regval &= ~CPU1_SRST_REQ;
++	writel(regval, __io_address(CRG_REG_BASE + REG_A9_SRST_CRG));
++#endif
++}
++
++static inline void hi3531d_scu_power_off(int cpu)
++{
++#ifdef CONFIG_ARCH_HI3531D
++	unsigned long regval;
++
++	regval = readl(__io_address(CRG_REG_BASE + REG_A9_SRST_CRG));
++	regval |= (WDG1_SRST_REQ | DBG1_SRST_REQ | CPU1_SRST_REQ);
++	writel(regval, __io_address(CRG_REG_BASE + REG_A9_SRST_CRG));
++#endif
++}
++
++void hi3531d_cpu_die(unsigned int cpu)
++{
++	flush_cache_all();
++	hi3531d_scu_power_off(cpu);
++	BUG();
++}
++
++int hi3521d_cpu_kill(unsigned int cpu)
++{
++	return 1;
++}
++
++void hi3521d_scu_power_up(int cpu)
++{
++#ifdef CONFIG_ARCH_HI3521D
++	unsigned int regval;
++
++	/* clear the slave cpu reset */
++	regval = readl(__io_address(CRG_REG_BASE + REG_A7_SRST_CRG));
++	regval &= ~CORE1_SRST_REQ;
++	writel(regval, __io_address(CRG_REG_BASE + REG_A7_SRST_CRG));
++#endif
++}
++
++static inline void hi3521d_scu_power_off(int cpu)
++{
++#ifdef CONFIG_ARCH_HI3521D
++	unsigned long regval;
++
++	regval = readl(__io_address(CRG_REG_BASE + REG_A7_SRST_CRG));
++	regval |= (DBG1_SRST_REQ | CORE1_SRST_REQ);
++	writel(regval, __io_address(CRG_REG_BASE + REG_A7_SRST_CRG));
++#endif
++}
++
++void hi3521d_cpu_die(unsigned int cpu)
++{
++	flush_cache_all();
++	hi3521d_scu_power_off(cpu);
++	BUG();
++}
+ #endif
+diff --git a/arch/arm/mach-hisi/l2cache.c b/arch/arm/mach-hisi/l2cache.c
+new file mode 100644
+index 0000000..52aa2ec
+--- /dev/null
++++ b/arch/arm/mach-hisi/l2cache.c
+@@ -0,0 +1,71 @@
++/*
++ * Copyright (c) 2015-2017 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ */
++
++#define pr_fmt(fmt) "l2cache: " fmt
++
++#include <linux/io.h>
++#include <linux/init.h>
++#include <asm/cacheflush.h>
++#include <asm/hardware/cache-l2x0.h>
++#include <mach/io.h>
++#include <mach/platform.h>
++
++static void __iomem *l2x0_virt_base = __io_address(REG_BASE_L2CACHE);
++
++static int __init l2_cache_init(void)
++{
++	u32 val;
++	/*
++	 * Bits  Value Description
++	 * [31]    0 : SBZ
++	 * [30]    1 : Double linefill enable (L3)
++	 * [29]    1 : Instruction prefetching enable
++	 * [28]    1 : Data prefetching enabled
++	 * [27]    0 : Double linefill on WRAP read enabled (L3)
++	 * [26:25] 0 : SBZ
++	 * [24]    1 : Prefetch drop enable (L3)
++	 * [23]    0 : Incr double Linefill enable (L3)
++	 * [22]    0 : SBZ
++	 * [21]    0 : Not same ID on exclusive sequence enable (L3)
++	 * [20:5]  0 : SBZ
++	 * [4:0]   0 : use the Prefetch offset values 0.
++	 */
++	/* writel_relaxed(0x71000000, l2x0_virt_base + L2X0_PREFETCH_CTRL); */
++	writel_relaxed(0x71000000, l2x0_virt_base + L310_PREFETCH_CTRL);
++
++	val = __raw_readl(l2x0_virt_base + L2X0_AUX_CTRL);
++	val |= (1 << 30); /* Early BRESP enabled */
++	val |= (1 << 0);  /* Full Line of Zero Enable */
++	writel_relaxed(val, l2x0_virt_base + L2X0_AUX_CTRL);
++	l2x0_init(l2x0_virt_base, 0x00430000, 0xFFB0FFFF);
++	/*
++	 * 2. enable L2 prefetch hint                  [1]a
++	 * 3. enable write full line of zeros mode.    [3]a
++	 *   a: This feature must be enabled only when the slaves
++	 *      connected on the Cortex-A9 AXI master port support it.
++	 */
++	asm volatile (
++	"	mrc	p15, 0, r0, c1, c0, 1\n"
++	"	orr	r0, r0, #0x02\n"
++	"	mcr	p15, 0, r0, c1, c0, 1\n"
++	  :
++	  :
++	  : "r0", "cc");
++
++	return 0;
++}
++early_initcall(l2_cache_init);
+diff --git a/arch/arm/mach-hisi/platsmp.c b/arch/arm/mach-hisi/platsmp.c
+index 575dd82..da14096 100644
+--- a/arch/arm/mach-hisi/platsmp.c
++++ b/arch/arm/mach-hisi/platsmp.c
+@@ -7,19 +7,48 @@
+  * under the terms and conditions of the GNU General Public License,
+  * version 2, as published by the Free Software Foundation.
+  */
++
++#include <linux/delay.h>
+ #include <linux/smp.h>
+ #include <linux/io.h>
+ #include <linux/of_address.h>
+-
+ #include <asm/cacheflush.h>
+ #include <asm/smp_plat.h>
+ #include <asm/smp_scu.h>
+ 
++#if (defined(CONFIG_ARCH_HI3531D) \
++	|| defined(CONFIG_ARCH_HI3536C) \
++	|| defined(CONFIG_ARCH_HI3521D))
++#include <mach/io.h>
++#include <mach/platform.h>
++#endif
++
+ #include "core.h"
+ 
+ #define HIX5HD2_BOOT_ADDRESS		0xffff0000
++#define HI3519_BOOT_ADDRESS		0x00000000
++#define HI3559_BOOT_ADDRESS		0x00000000
++#define HI3516AV200_BOOT_ADDRESS	0x00000000
++#define HI3536C_BOOT_ADDRESS	0x00000000
++#define HI3531D_BOOT_ADDRESS	0x00000000
++#define HI3521D_BOOT_ADDRESS	0x00000000
+ 
++static void __iomem *hi3519_bootaddr;
++static void __iomem *hi3559_bootaddr;
++static void __iomem *hi3516av200_bootaddr;
++static void __iomem *hi3536c_bootaddr;
++static void __iomem *hi3531d_bootaddr;
++static void __iomem *hi3521d_bootaddr;
+ static void __iomem *ctrl_base;
++static DEFINE_SPINLOCK(boot_lock);
++
++static void __cpuinit hi_write_pen_release(int val)
++{
++	pen_release = val;
++	smp_wmb();
++	__cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release));
++	outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1));
++}
+ 
+ void hi3xxx_set_cpu_jump(int cpu, void *jump_addr)
+ {
+@@ -132,5 +161,620 @@ struct smp_operations hix5hd2_smp_ops __initdata = {
+ #endif
+ };
+ 
++void hi3519_set_cpu_jump(unsigned int cpu, phys_addr_t jumpaddr)
++{
++	/* only cortex-a17 boot from phys 0 address */
++	if (cpu != 1)
++		return;
++	/* ldr pc, [rc, #-4] */
++	writel_relaxed(0xe51ff004, hi3519_bootaddr);
++	/* pc jump phy address */
++	writel_relaxed(jumpaddr, hi3519_bootaddr + 4);
++
++	dsb();
++}
++
++void hi3516av200_set_cpu_jump(unsigned int cpu, phys_addr_t jumpaddr)
++{
++	/* only cortex-a17 boot from phys 0 address */
++	if (cpu != 1)
++		return;
++	/* ldr pc, [rc, #-4] */
++	writel_relaxed(0xe51ff004, hi3516av200_bootaddr);
++	/* pc jump phy address */
++	writel_relaxed(jumpaddr, hi3516av200_bootaddr + 4);
++
++	dsb();
++}
++
++void hi3559_set_cpu_jump(unsigned int cpu, phys_addr_t jumpaddr)
++{
++	/* only cortex-a17 boot from phys 0 address */
++	if (cpu != 1)
++		return;
++	/* ldr pc, [rc, #-4] */
++	writel_relaxed(0xe51ff004, hi3559_bootaddr);
++	/* pc jump phy address */
++	writel_relaxed(jumpaddr, hi3559_bootaddr + 4);
++
++	dsb();
++}
++
++static void __init hi3519_smp_prepare_cpus(unsigned int max_cpus)
++{
++	if (!hi3519_bootaddr)
++		hi3519_bootaddr = ioremap(HI3519_BOOT_ADDRESS, PAGE_SIZE);
++
++	sync_cache_w(&hi3519_bootaddr);
++}
++
++static void __init hi3516av200_smp_prepare_cpus(unsigned int max_cpus)
++{
++	if (!hi3516av200_bootaddr)
++		hi3516av200_bootaddr = ioremap(HI3516AV200_BOOT_ADDRESS, PAGE_SIZE);
++
++	sync_cache_w(&hi3516av200_bootaddr);
++}
++
++static void __init hi3559_smp_prepare_cpus(unsigned int max_cpus)
++{
++	if (!hi3559_bootaddr)
++		hi3559_bootaddr = ioremap(HI3559_BOOT_ADDRESS, PAGE_SIZE);
++
++	sync_cache_w(&hi3559_bootaddr);
++}
++
++static int hi3519_boot_secondary(unsigned int cpu, struct task_struct *idle)
++{
++	flush_cache_all();
++
++	hi3519_set_cpu_jump(cpu, virt_to_phys(hi3519_secondary_startup));
++
++	hi_pmc_power_up();
++
++	return 0;
++}
++
++static int hi3516av200_boot_secondary(unsigned int cpu, struct task_struct *idle)
++{
++	flush_cache_all();
++
++	hi3516av200_set_cpu_jump(cpu, virt_to_phys(hi3516av200_secondary_startup));
++
++	hi_pmc_power_up();
++
++	return 0;
++}
++
++static int hi3559_boot_secondary(unsigned int cpu, struct task_struct *idle)
++{
++	flush_cache_all();
++
++	hi3559_set_cpu_jump(cpu, virt_to_phys(hi3559_secondary_startup));
++
++	hi_pmc_power_up();
++
++	return 0;
++}
++
++static void HI3519_secondary_init(unsigned int cpu)
++{
++/*
++	hi_pmc_power_up_done();
++*/
++}
++
++static void HI3516av200_secondary_init(unsigned int cpu)
++{
++/*
++	hi_pmc_power_up_done();
++*/
++}
++
++static void HI3559_secondary_init(unsigned int cpu)
++{
++/*
++	hi_pmc_power_up_done();
++*/
++}
++
++void hi3536c_set_cpu_jump(unsigned int cpu, phys_addr_t jumpaddr)
++{
++	/* only cortex-a17 boot from phys 0 address */
++	if (cpu != 1)
++		return;
++	/* ldr pc, [rc, #-4] */
++	writel_relaxed(0xe51ff004, hi3536c_bootaddr);
++	/* pc jump phy address */
++	writel_relaxed(jumpaddr, hi3536c_bootaddr + 4);
++
++	dsb();
++}
++
++void hi3531d_set_cpu_jump(unsigned int cpu, phys_addr_t jumpaddr)
++{
++	/* only cortex-a17 boot from phys 0 address */
++	if (cpu != 1)
++		return;
++	/* ldr pc, [rc, #-4] */
++	writel_relaxed(0xe51ff004, hi3531d_bootaddr);
++	/* pc jump phy address */
++	writel_relaxed(jumpaddr, hi3531d_bootaddr + 4);
++
++	dsb();
++}
++
++void hi3521d_set_cpu_jump(unsigned int cpu, phys_addr_t jumpaddr)
++{
++	/* only cortex-a17 boot from phys 0 address */
++	if (cpu != 1)
++		return;
++	/* ldr pc, [rc, #-4] */
++	writel_relaxed(0xe51ff004, hi3521d_bootaddr);
++	/* pc jump phy address */
++	writel_relaxed(jumpaddr, hi3521d_bootaddr + 4);
++
++	dsb();
++}
++
++static void __iomem *scu_base_addr(void)
++{
++#ifdef CONFIG_ARCH_HI3531D
++	return __io_address(A9_PERI_BASE + REG_A9_PERI_SCU);
++#elif (defined(CONFIG_ARCH_HI3536C) \
++	|| defined(CONFIG_ARCH_HI3521D))
++	return __io_address(A7_PERI_BASE + REG_A7_PERI_SCU);
++#endif
++	return NULL;
++}
++
++static void __init hi3536c_smp_prepare_cpus(unsigned int max_cpus)
++{
++	void __iomem *base = NULL;
++
++	base = scu_base_addr();
++	if (!base)
++		return;
++
++	scu_enable(base);
++}
++
++static void __init hi3531d_smp_prepare_cpus(unsigned int max_cpus)
++{
++	scu_enable(scu_base_addr());
++}
++
++static void __init hi3521d_smp_prepare_cpus(unsigned int max_cpus)
++{
++	scu_enable(scu_base_addr());
++}
++
++/*****************************************************************************/
++/*
++ * copy startup code to sram, and flash cache.
++ * @start_addr: slave start phy address
++ * @jump_addr: slave jump phy address
++ */
++static void hi3536c_set_scu_boot_addr(unsigned int start_addr,
++		unsigned int jump_addr)
++{
++	unsigned int *virtaddr;
++	unsigned int *p_virtaddr;
++
++	p_virtaddr = virtaddr = ioremap(start_addr, PAGE_SIZE);
++
++	*p_virtaddr++ = 0xe51ff004; /* ldr  pc, [pc, #-4] */
++	*p_virtaddr++ = jump_addr;  /* pc jump phy address */
++
++	smp_wmb();
++
++	__cpuc_flush_dcache_area((void *)virtaddr,
++			(size_t)((char *)p_virtaddr - (char *)virtaddr));
++	outer_clean_range(__pa(virtaddr), __pa(p_virtaddr));
++
++	iounmap(virtaddr);
++}
++
++/*****************************************************************************/
++/*
++ * copy startup code to sram, and flash cache.
++ * @start_addr: slave start phy address
++ * @jump_addr: slave jump phy address
++ */
++static void hi3531d_set_scu_boot_addr(unsigned int start_addr,
++		unsigned int jump_addr)
++{
++	unsigned int *virtaddr;
++	unsigned int *p_virtaddr;
++
++	p_virtaddr = virtaddr = ioremap(start_addr, PAGE_SIZE);
++
++	*p_virtaddr++ = 0xe51ff004; /* ldr  pc, [pc, #-4] */
++	*p_virtaddr++ = jump_addr;  /* pc jump phy address */
++
++	smp_wmb();
++
++	__cpuc_flush_dcache_area((void *)virtaddr,
++			(size_t)((char *)p_virtaddr - (char *)virtaddr));
++	outer_clean_range(__pa(virtaddr), __pa(p_virtaddr));
++
++	iounmap(virtaddr);
++}
++ 
++static void hi3521d_set_scu_boot_addr(unsigned int start_addr,
++		unsigned int jump_addr)
++{
++	unsigned int *virtaddr;
++	unsigned int *p_virtaddr;
++
++	p_virtaddr = virtaddr = ioremap(start_addr, PAGE_SIZE);
++
++	*p_virtaddr++ = 0xe51ff004; /* ldr  pc, [pc, #-4] */
++	*p_virtaddr++ = jump_addr;  /* pc jump phy address */
++
++	smp_wmb();
++
++	__cpuc_flush_dcache_area((void *)virtaddr,
++			(size_t)((char *)p_virtaddr - (char *)virtaddr));
++	outer_clean_range(__pa(virtaddr), __pa(p_virtaddr));
++
++	iounmap(virtaddr);
++}
++
++static int __cpuinit hi3536c_boot_secondary(unsigned int cpu,
++		struct task_struct *idle)
++{
++	unsigned long timeout;
++
++	hi3536c_set_scu_boot_addr(0x00000000,
++			(unsigned int)virt_to_phys(hi3536c_secondary_startup));
++
++	/*
++	 * set synchronisation state between this boot processor
++	 * and the secondary one
++	 */
++	spin_lock(&boot_lock);
++
++	hi3536c_scu_power_up(cpu);
++	/*
++	 * The secondary processor is waiting to be released from
++	 * the holding pen - release it, then wait for it to flag
++	 * that it has been released by resetting pen_release.
++	 *
++	 * Note that "pen_release" is the hardware CPU ID, whereas
++	 * "cpu" is Linux's internal ID.
++	 */
++	hi_write_pen_release(cpu);
++
++	/*
++	 * Send the secondary CPU a soft interrupt, thereby causing
++	 * the boot monitor to read the system wide flags register,
++	 * and branch to the address found there.
++	 */
++	arch_send_wakeup_ipi_mask(cpumask_of(cpu));
++
++	/*
++	 * Send the secondary CPU a soft interrupt, thereby causing
++	 * the boot monitor to read the system wide flags register,
++	 * and branch to the address found there.
++	 */
++	timeout = jiffies + (5 * HZ);
++	while (time_before(jiffies, timeout)) {
++		smp_rmb();
++		if (pen_release == -1)
++			break;
++
++		udelay(10);
++	}
++
++	/*
++	 * now the secondary core is starting up let it run its
++	 * calibrations, then wait for it to finish
++	 */
++	spin_unlock(&boot_lock);
++
++	return pen_release != -1 ? -ENOSYS : 0;
++}
++
++static int hi3531d_boot_secondary(unsigned int cpu, struct task_struct *idle)
++{
++	unsigned long timeout;
++
++	hi3531d_set_scu_boot_addr(0x00000000,
++			(unsigned int)virt_to_phys(hi3531d_secondary_startup));
++
++	/*
++	 *  * set synchronisation state between this boot processor
++	 *   * and the secondary one
++	 *    */
++	spin_lock(&boot_lock);
++
++	hi3531d_scu_power_up(cpu);
++
++	/*
++	 * The secondary processor is waiting to be released from
++	 * the holding pen - release it, then wait for it to flag
++	 * that it has been released by resetting pen_release.
++	 *
++	 * Note that "pen_release" is the hardware CPU ID, whereas
++	 * "cpu" is Linux's internal ID.
++	 */
++	hi_write_pen_release(cpu);
++
++	/*
++	 * Send the secondary CPU a soft interrupt, thereby causing
++	 * the boot monitor to read the system wide flags register,
++	 * and branch to the address found there.
++	 */
++	arch_send_wakeup_ipi_mask(cpumask_of(cpu));
++
++	/*
++	 * Send the secondary CPU a soft interrupt, thereby causing
++	 * the boot monitor to read the system wide flags register,
++	 * and branch to the address found there.
++	 */
++	timeout = jiffies + (5 * HZ);
++	while (time_before(jiffies, timeout)) {
++		smp_rmb();
++		if (pen_release == -1)
++			break;
++			udelay(10);
++	}
++
++	/*
++	 * now the secondary core is starting up let it run its
++	 * calibrations, then wait for it to finish
++	 */
++	spin_unlock(&boot_lock);
++	return pen_release != -1 ? -ENOSYS : 0;
++}
++
++static int __cpuinit hi3521d_boot_secondary(unsigned int cpu,
++		struct task_struct *idle)
++{
++	unsigned long timeout;
++
++	hi3521d_set_scu_boot_addr(0x00000000,
++			(unsigned int)virt_to_phys(hi3521d_secondary_startup));
++
++	/*
++	 * set synchronisation state between this boot processor
++	 * and the secondary one
++	 */
++	spin_lock(&boot_lock);
++
++	hi3521d_scu_power_up(cpu);
++	/*
++	 * The secondary processor is waiting to be released from
++	 * the holding pen - release it, then wait for it to flag
++	 * that it has been released by resetting pen_release.
++	 *
++	 * Note that "pen_release" is the hardware CPU ID, whereas
++	 * "cpu" is Linux's internal ID.
++	 */
++	hi_write_pen_release(cpu);
++
++	/*
++	 * Send the secondary CPU a soft interrupt, thereby causing
++	 * the boot monitor to read the system wide flags register,
++	 * and branch to the address found there.
++	 */
++	arch_send_wakeup_ipi_mask(cpumask_of(cpu));
++
++	/*
++	 * Send the secondary CPU a soft interrupt, thereby causing
++	 * the boot monitor to read the system wide flags register,
++	 * and branch to the address found there.
++	 */
++	timeout = jiffies + (5 * HZ);
++	while (time_before(jiffies, timeout)) {
++		smp_rmb();
++		if (pen_release == -1)
++			break;
++
++		udelay(10);
++	}
++
++	/*
++	 * now the secondary core is starting up let it run its
++	 * calibrations, then wait for it to finish
++	 */
++	spin_unlock(&boot_lock);
++
++	return pen_release != -1 ? -ENOSYS : 0;
++}
++
++static void __cpuinit hi3536c_secondary_init(unsigned int cpu)
++{
++	/*
++	 * let the primary processor know we're out of the
++	 * pen, then head off into the C entry point
++	 */
++	hi_write_pen_release(-1);
++
++	/*
++	 * Synchronise with the boot thread.
++	 */
++	spin_lock(&boot_lock);
++	spin_unlock(&boot_lock);
++}
++
++static void hi3531d_secondary_init(unsigned int cpu)
++{
++	/*
++	 * 1. enable L1 prefetch                       [2]
++	 * 2. enable L2 prefetch hint                  [1]a
++	 * 3. enable write full line of zeros mode.    [3]a
++	 * 4. enable allocation in one cache way only. [8]
++	 *   a: This feature must be enabled only when the slaves
++	 *      connected on the Cortex-A17 AXI master port support it.
++	 */
++	asm volatile (
++	"   mrc p15, 0, r0, c1, c0, 1\n"
++	"   orr r0, r0, #0x0104\n"
++	"   orr r0, r0, #0x02\n"
++	"   mcr p15, 0, r0, c1, c0, 1\n"
++	  :
++	  :
++	  : "r0", "cc");
++
++	/*
++	 *  * let the primary processor know we're out of the
++	 *   * pen, then head off into the C entry point
++	 *    */
++	hi_write_pen_release(-1);
++
++	/*
++	 * Synchronise with the boot thread.
++	 */
++	spin_lock(&boot_lock);
++	spin_unlock(&boot_lock);
++}
++
++static void __cpuinit hi3521d_secondary_init(unsigned int cpu)
++{
++	/*
++	 * let the primary processor know we're out of the
++	 * pen, then head off into the C entry point
++	 */
++	hi_write_pen_release(-1);
++
++	/*
++	 * Synchronise with the boot thread.
++	 */
++	spin_lock(&boot_lock);
++	spin_unlock(&boot_lock);
++}
++
++static void __init hi3536c_smp_init_cpus(void)
++{
++	unsigned int i, ncores, l2ctlr;
++
++	asm volatile("mrc p15, 1, %0, c9, c0, 2\n" : "=r" (l2ctlr));
++	ncores = ((l2ctlr >> 24) & 0x3) + 1;
++
++	/* sanity check */
++	if (ncores > NR_CPUS) {
++		printk(KERN_WARNING
++				"Realview: no. of cores (%d) greater than configured "
++				"maximum of %d - clipping\n",
++				ncores, NR_CPUS);
++		ncores = NR_CPUS;
++	}
++
++	for (i = 0; i < ncores; i++)
++		set_cpu_possible(i, true);
++}
++
++static void __init hi3531d_smp_init_cpus(void)
++{
++	void __iomem *scu_base = scu_base_addr();
++	unsigned int i, ncores;
++
++	ncores = scu_base ? scu_get_core_count(scu_base) : 1;
++
++	/* sanity check */
++	if (ncores > NR_CPUS) {
++		printk(KERN_WARNING
++				"Realview: no. of cores (%d) greater than configured "
++				"maximum of %d - clipping\n",
++				ncores, NR_CPUS);
++		ncores = NR_CPUS;
++	}
++
++	for (i = 0; i < ncores; i++)
++		set_cpu_possible(i, true);
++}
++
++static void __init hi3521d_smp_init_cpus(void)
++{
++	unsigned int i, ncores, l2ctlr;
++
++	asm volatile("mrc p15, 1, %0, c9, c0, 2\n" : "=r" (l2ctlr));
++	ncores = ((l2ctlr >> 24) & 0x3) + 1;
++
++	/* sanity check */
++	if (ncores > NR_CPUS) {
++		printk(KERN_WARNING
++				"Realview: no. of cores (%d) greater than configured "
++				"maximum of %d - clipping\n",
++				ncores, NR_CPUS);
++		ncores = NR_CPUS;
++	}
++
++	for (i = 0; i < ncores; i++)
++		set_cpu_possible(i, true);
++}
++
++struct smp_operations hi3536c_smp_ops __initdata = {
++	.smp_init_cpus = hi3536c_smp_init_cpus,
++	.smp_prepare_cpus = hi3536c_smp_prepare_cpus,
++	.smp_secondary_init = hi3536c_secondary_init,
++	.smp_boot_secondary = hi3536c_boot_secondary,
++#ifdef CONFIG_HOTPLUG_CPU
++	.cpu_die			= hi3536c_cpu_die,
++	.cpu_kill			= hi3536c_cpu_kill,
++#endif
++};
++
++struct smp_operations hi3531d_smp_ops __initdata = {
++	.smp_init_cpus = hi3531d_smp_init_cpus,
++	.smp_prepare_cpus = hi3531d_smp_prepare_cpus,
++	.smp_secondary_init = hi3531d_secondary_init,
++	.smp_boot_secondary = hi3531d_boot_secondary,
++#ifdef CONFIG_HOTPLUG_CPU
++	.cpu_die			= hi3531d_cpu_die,
++	.cpu_kill			= hi3531d_cpu_kill,
++#endif
++};
++
++struct smp_operations hi3521d_smp_ops __initdata = {
++	.smp_init_cpus = hi3521d_smp_init_cpus,
++	.smp_prepare_cpus = hi3521d_smp_prepare_cpus,
++	.smp_secondary_init = hi3521d_secondary_init,
++	.smp_boot_secondary = hi3521d_boot_secondary,
++#ifdef CONFIG_HOTPLUG_CPU
++	.cpu_die			= hi3521d_cpu_die,
++	.cpu_kill			= hi3521d_cpu_kill,
++#endif
++};
++
++struct smp_operations hi3519_smp_ops __initdata = {
++	.smp_prepare_cpus	= hi3519_smp_prepare_cpus,
++	.smp_boot_secondary	= hi3519_boot_secondary,
++	.smp_secondary_init	= HI3519_secondary_init,
++#ifdef CONFIG_HOTPLUG_CPU
++	.cpu_die		= hi3519_cpu_die,
++	.cpu_kill		= hi3519_cpu_kill,
++#endif
++};
++
++struct smp_operations hi3516av200_smp_ops __initdata = {
++	.smp_prepare_cpus	= hi3516av200_smp_prepare_cpus,
++	.smp_boot_secondary	= hi3516av200_boot_secondary,
++	.smp_secondary_init	= HI3516av200_secondary_init,
++#ifdef CONFIG_HOTPLUG_CPU
++	.cpu_die		= hi3516av200_cpu_die,
++	.cpu_kill		= hi3516av200_cpu_kill,
++#endif
++};
++
++struct smp_operations hi3559_smp_ops __initdata = {
++	.smp_prepare_cpus	= hi3559_smp_prepare_cpus,
++	.smp_boot_secondary	= hi3559_boot_secondary,
++	.smp_secondary_init	= HI3559_secondary_init,
++#ifdef CONFIG_HOTPLUG_CPU
++	.cpu_die		= hi3559_cpu_die,
++	.cpu_kill		= hi3559_cpu_kill,
++#endif
++};
++
++
+ CPU_METHOD_OF_DECLARE(hi3xxx_smp, "hisilicon,hi3620-smp", &hi3xxx_smp_ops);
+ CPU_METHOD_OF_DECLARE(hix5hd2_smp, "hisilicon,hix5hd2-smp", &hix5hd2_smp_ops);
++CPU_METHOD_OF_DECLARE(hi3519_smp, "hisilicon,hi3519-smp", &hi3519_smp_ops);
++CPU_METHOD_OF_DECLARE(hi3559_smp, "hisilicon,hi3559-smp", &hi3559_smp_ops);
++CPU_METHOD_OF_DECLARE(hi3516av200_smp, "hisilicon,hi3516av200-smp", &hi3516av200_smp_ops);
++CPU_METHOD_OF_DECLARE(hi3536c_smp, "hisilicon,hi3536c-smp", &hi3536c_smp_ops);
++CPU_METHOD_OF_DECLARE(hi3531d_smp, "hisilicon,hi3531d-smp", &hi3531d_smp_ops);
++CPU_METHOD_OF_DECLARE(hi3521d_smp, "hisilicon,hi3521d-smp", &hi3521d_smp_ops);
+diff --git a/arch/arm/mach-hisi/pm.c b/arch/arm/mach-hisi/pm.c
+new file mode 100644
+index 0000000..c4b8870
+--- /dev/null
++++ b/arch/arm/mach-hisi/pm.c
+@@ -0,0 +1,288 @@
++/*
++ * power mangager control for hisilicon soc
++ *
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/pm.h>
++#include <linux/suspend.h>
++#include <asm/memory.h>
++#include <mach/io.h>
++#include <mach/platform.h>
++
++#include <linux/delay.h>
++#include <linux/suspend.h>
++#include <linux/syscalls.h>
++#include <asm/mach/time.h>
++#include <linux/slab.h>
++
++#include <asm/mach/time.h>
++#include <asm/hardware/arm_timer.h>
++#include <asm/mach/irq.h>
++
++#include <linux/sched.h>
++#include <linux/mm.h>
++#include <linux/reboot.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/kallsyms.h>
++#include <asm/cacheflush.h>
++#include <asm/processor.h>
++
++#include <asm/mach/map.h>
++#include <linux/of_address.h>
++#include <linux/platform_device.h>
++
++struct hibvt_pm_dev {
++	void __iomem		*sys_ctrl_base;
++	void __iomem		*time0_base;
++};
++
++static struct hibvt_pm_dev g_hibvt_pm;
++
++void (*hi_power_off)(void) = NULL;
++EXPORT_SYMBOL(hi_power_off);
++
++void hi_pm_power_off(void)
++{
++	/* Disable interrupts first */
++	local_irq_disable();
++	local_fiq_disable();
++
++	/* Clean and invalidate caches */
++	flush_cache_all();
++
++	/* Turn off caching */
++	cpu_proc_fin();
++
++	/* Push out any further dirty data, and ensure cache is empty */
++	flush_cache_all();
++
++	/*
++	 * Now call the architecture specific reboot code.
++	 */
++    if(hi_power_off)
++        hi_power_off();
++	/*
++	 * Whoops - the architecture was unable to reboot.
++	 * Tell the user!
++	 */
++	mdelay(1000);
++
++	printk(KERN_EMERG "Poweroff failed -- System halted\n");
++
++	while (1)
++		;
++}
++
++/*hibernate methods*/
++#ifdef CONFIG_HIBERNATION
++unsigned long saved_interrupt_mask[128];
++unsigned long saved_cpu_target_mask[128];
++
++typedef struct __timer_register {
++    unsigned long timer_load;
++    unsigned long timer_value;
++    unsigned long timer_ctrl;
++    unsigned long timer_bgload;
++} timer_register;
++
++static timer_register timer0[2];
++static int timer_init_value;
++static int save_timer0(void)
++{
++	void __iomem *timer0_base_addr = g_hibvt_pm.time0_base;
++
++	timer_init_value = readl(g_hibvt_pm.sys_ctrl_base);
++	/*protect timer0_0*/
++	timer0[0].timer_load   = readl(timer0_base_addr + TIMER_LOAD);
++	timer0[0].timer_value  = readl(timer0_base_addr + TIMER_VALUE);
++	timer0[0].timer_ctrl   = readl(timer0_base_addr + TIMER_CTRL);
++	timer0[0].timer_bgload = readl(timer0_base_addr + TIMER_BGLOAD);
++	/*disable timer0_0  */
++	writel(0, timer0_base_addr + TIMER_CTRL);
++
++	/*protect timer0_1*/
++	timer0[1].timer_load   = readl(timer0_base_addr + 0x20 + TIMER_LOAD);
++	timer0[1].timer_value  = readl(timer0_base_addr + 0x20 + TIMER_VALUE);
++	timer0[1].timer_ctrl   = readl(timer0_base_addr + 0x20 + TIMER_CTRL);
++	timer0[1].timer_bgload = readl(timer0_base_addr + 0x20 + TIMER_BGLOAD);
++	/*disable timer0_1  */
++	writel(0, timer0_base_addr + 0x20 + TIMER_CTRL);
++
++	return 0;
++}
++
++
++static int restore_timer0(void)
++{
++	void __iomem *timer0_base_addr = g_hibvt_pm.time0_base;
++
++	writel(timer_init_value, g_hibvt_pm.sys_ctrl_base);
++	/* restore timer0_0 */
++	writel(0, timer0_base_addr + TIMER_CTRL);
++	writel(1, timer0_base_addr + TIMER_INTCLR);
++
++	writel(timer0[0].timer_value, timer0_base_addr + TIMER_LOAD);
++	writel(timer0[0].timer_ctrl, timer0_base_addr + TIMER_CTRL);
++	writel(timer0[0].timer_bgload, timer0_base_addr + TIMER_BGLOAD);
++
++	/* restore timer0_1  */
++	writel(0, timer0_base_addr + 0x20 + TIMER_CTRL);
++	writel(1, timer0_base_addr + 0x20 + TIMER_INTCLR);
++
++	writel(timer0[1].timer_value, timer0_base_addr + 0x20 + TIMER_LOAD);
++	writel(timer0[1].timer_ctrl, timer0_base_addr + 0x20 + TIMER_CTRL);
++	writel(timer0[1].timer_bgload, timer0_base_addr + 0x20 + TIMER_BGLOAD);
++
++	return 0;
++}
++static int hi_hiber_begin(void)
++{
++	return 0;
++}
++
++static void hi_hiber_end(void)
++{
++}
++
++static int hi_hiber_pre_snapshot(void)
++{
++	save_timer0();
++	return 0;
++}
++
++static void hi_hiber_finish(void)
++{
++	restore_timer0();
++}
++
++static int hi_hiber_prepare(void)
++{
++	return 0;
++}
++
++static void hi_hiber_leave(void)
++{
++}
++
++static int hi_hiber_enter(void)
++{
++#ifdef CONFIG_DEFAULT_MTD
++	hi_pm_power_off();
++#else
++	kernel_restart(NULL);
++#endif
++	return 0;
++}
++
++static int hi_hiber_restore(void)
++{
++	return 0;
++}
++
++static void hi_hiber_restore_cleanup(void)
++{
++}
++
++static void hi_hiber_recover(void)
++{
++}
++
++struct platform_hibernation_ops hi_hibernation_ops = {
++    .begin           = hi_hiber_begin,
++    .end             = hi_hiber_end,
++    .pre_snapshot    = hi_hiber_pre_snapshot,
++    .finish          = hi_hiber_finish,
++    .prepare         = hi_hiber_prepare,
++    .enter           = hi_hiber_enter,
++    .leave           = hi_hiber_leave,
++    .pre_restore     = hi_hiber_restore,
++    .restore_cleanup = hi_hiber_restore_cleanup,
++    .recover         = hi_hiber_recover,
++};
++#endif /* CONFIG_HIBERNATION */
++
++
++/*pm methods*/
++static int hi_pm_enter(suspend_state_t state)
++{
++	return 0;
++}
++
++int hi_pm_valid(suspend_state_t state)
++{
++	return 1;
++}
++
++static const struct platform_suspend_ops hi_pm_ops = {
++	.enter		= hi_pm_enter,
++	.valid		= hi_pm_valid,
++};
++
++static int hi_pm_probe(struct platform_device *pdev)
++{
++	g_hibvt_pm.sys_ctrl_base = of_iomap(pdev->dev.of_node, 0);
++	if (!g_hibvt_pm.sys_ctrl_base) {
++		pr_err("%s: failed to map system controller registers\n",
++				__func__);
++		return -ENOMEM;
++	}
++
++	g_hibvt_pm.time0_base = of_iomap(pdev->dev.of_node, 1);
++	if (!g_hibvt_pm.time0_base) {
++		pr_err("%s: failed to map timer registers\n", __func__);
++		iounmap(g_hibvt_pm.sys_ctrl_base);
++		return -ENOMEM;
++	}
++
++	pm_power_off = hi_pm_power_off;
++
++	suspend_set_ops(&hi_pm_ops);
++
++#ifdef CONFIG_HIBERNATION
++	/* registering hibernation call backs */
++	hibernation_set_ops(&hi_hibernation_ops);
++#endif
++	return 0;
++}
++
++static const struct of_device_id hi_pm_match_table[] = {
++	{ .compatible = "hisilicon,hibvt-pm" },
++	{ }
++};
++MODULE_DEVICE_TABLE(of, hi_pm_match_table);
++
++static struct platform_driver hi_pm_driver = {
++	.probe          = hi_pm_probe,
++	.driver         = {
++		.name   = "hibvt-pm",
++		.of_match_table = hi_pm_match_table,
++	},
++};
++
++static int __init hi_pm_init(void)
++{
++	return platform_driver_register(&hi_pm_driver);
++}
++module_init(hi_pm_init);
++
++MODULE_LICENSE("GPL v2");
++MODULE_DESCRIPTION("HiSilicon BVT PM Driver");
+diff --git a/arch/arm/mach-hisi/pmc_hi3516av200.c b/arch/arm/mach-hisi/pmc_hi3516av200.c
+new file mode 100644
+index 0000000..df36e44
+--- /dev/null
++++ b/arch/arm/mach-hisi/pmc_hi3516av200.c
+@@ -0,0 +1,207 @@
++/*
++ * power mangager control for hisilicon hi3516av200 soc
++ *
++ * Copyright (c) 2015 HiSilicon Technologies Co., Ltd.
++ * Authors: zengtao@hisilicon.com
++ *
++ * This program is free software; you can redistribute  it and/or modify it
++ * under  the terms of  the GNU General  Public License as published by the
++ * Free Software Foundation;  either version 2 of the  License, or (at your
++ * option) any later version.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include <linux/io.h>
++#include <linux/linkage.h>
++#include <linux/bug.h>
++#include <linux/of.h>
++#include <linux/of_address.h>
++#include <linux/resource.h>
++#include <mach/platform.h>
++
++#include <linux/delay.h>
++
++#define PERI_PMC77	(0x134)
++#define PERI_PMC79	(0x13c)
++#define PERI_PMC85	(0x154)
++
++static void __iomem *pmc_base;
++static u32  pmc_phys_addr;
++
++#define PMC_ADDRESS(reg)	(pmc_base + reg)
++/* set bitfield of reg from start bit to end - 1 bit */
++static void reg_bit_set(u32 reg, u32 start, u32 end, u32 val)
++{
++	u32 regval, mask;
++
++	regval = readl((void __iomem *)PMC_ADDRESS(reg));
++	mask = ((0xffffffff << (32 - start)) >> (32 - start))
++	       | ((0xffffffff >> end) << end);
++
++	regval &= mask;
++	regval |= (val << start);
++
++	writel(regval, (void __iomem *)PMC_ADDRESS(reg));
++}
++
++/* get bitfield of reg from start bit to end - 1 bit */
++static u32 reg_bit_get(u32 reg, u32 start, u32 end)
++{
++	u32 regval;
++
++
++	regval = readl((void __iomem *)PMC_ADDRESS(reg));
++	regval = (regval << (32 - end)) >> (32 - end);
++	regval = regval >> start;
++
++
++	return regval;
++}
++
++void hi_pmc_power_up_done(void)
++{
++	writel(0, (void __iomem *)PMC_ADDRESS(PERI_PMC85));
++	writel(1, (void __iomem *)PMC_ADDRESS(PERI_PMC85));
++
++}
++
++/* before power down set ac inactive */
++void hi_pmc_set_ac_inactive(void)
++{
++	reg_bit_set(PERI_PMC79, 8, 9, 1);
++}
++
++/* after powerup clear ac inactive */
++void hi_pmc_clear_ac_inactive(void)
++{
++	reg_bit_set(PERI_PMC79, 8, 9, 0);
++}
++EXPORT_SYMBOL(hi_pmc_clear_ac_inactive);
++
++/* call from assable context */
++asmlinkage void __naked hi_pmc_clear_a17_ac(void)
++{
++	asm volatile("\n"
++		"adr     r2, 1f\n"
++		"ldmia   r2, {r1, r3}\n"
++		"sub     r0, r2, r1\n"
++		"ldr     r2, [r0, r3]\n"
++		"ldr r0, ="__stringify(PERI_PMC79)"\n"
++		"add r0, r0, r2\n"
++		"ldr r1, [r0]\n"
++		"bic r1, #0x100\n"
++		"str r1, [r0]\n"
++		"mov r0, #0\n"
++		"bx  lr\n"
++
++		".align  2\n"
++		"1:     .word   .\n"
++		"       .word   pmc_phys_addr\n"
++		);
++
++	unreachable();
++}
++
++static void hi_pmc_config(void)
++{
++	/* enable pmc timeout */
++	reg_bit_set(PERI_PMC77, 12, 13, 1);
++	/* enable pmc auto mode */
++	reg_bit_set(PERI_PMC79, 0, 2, 0);
++	/* enable irq triger source power on */
++	reg_bit_set(PERI_PMC79, 7, 8, 1);
++}
++
++/* cpu hotplug powerup */
++void hi_pmc_power_up(void)
++{
++	u32 power_state;
++
++	hi_pmc_config();
++
++	/* make sure it powerup state when power up */
++	power_state = reg_bit_get(PERI_PMC79, 12, 16);
++	BUG_ON(power_state != 0);
++
++	/* disable interrupt wakeup */
++	reg_bit_set(PERI_PMC79, 5, 6, 0);
++
++	/* power on */
++	reg_bit_set(PERI_PMC79, 3, 4, 0);
++	reg_bit_set(PERI_PMC79, 3, 4, 1);
++}
++
++/* cpu hotplug powerdown */
++void hi_pmc_power_down(void)
++{
++	u32 power_state;
++
++	power_state = reg_bit_get(PERI_PMC79, 12, 16);
++	BUG_ON(power_state != 6);
++
++	/* disable interrupt wakeup */
++	reg_bit_set(PERI_PMC79, 5, 6, 0);
++
++	/* power off */
++	reg_bit_set(PERI_PMC79, 4, 5, 0);
++	reg_bit_set(PERI_PMC79, 4, 5, 1);
++}
++
++/* cpuidle powerdown */
++void hi_pmc_automode_power_down(void)
++{
++	u32 power_state;
++
++	power_state = reg_bit_get(PERI_PMC79, 12, 16);
++	BUG_ON(power_state != 6);
++
++	/* enable interrupt wakeup */
++	reg_bit_set(PERI_PMC79, 5, 6, 1);
++
++	/* power off */
++	reg_bit_set(PERI_PMC79, 4, 5, 0);
++	reg_bit_set(PERI_PMC79, 4, 5, 1);
++
++}
++EXPORT_SYMBOL(hi_pmc_automode_power_down);
++
++
++/* enable timeout */
++static int hi_pmc_init(void)
++{
++	struct device_node *np;
++	struct resource res;
++	int ret = -ENODEV;
++
++	np = of_find_compatible_node(NULL, NULL, "hisilicon,pmc");
++	if (!np)
++		goto err;
++
++	pmc_base = of_iomap(np, 0);
++	if (!pmc_base) {
++		pr_err("failed to map pmc base\n");
++		ret = -ENOMEM;
++		goto err;
++	}
++
++	ret = of_address_to_resource(np, 0, &res);
++	if (ret) {
++		pr_err("failed to get pmc base phys\n");
++		ret = -ENOMEM;
++		goto err;
++	}
++	pmc_phys_addr = res.start;
++
++err:
++	return ret;
++}
++
++early_initcall(hi_pmc_init);
+diff --git a/arch/arm/mach-hisi/pmc_hi3519.c b/arch/arm/mach-hisi/pmc_hi3519.c
+new file mode 100644
+index 0000000..17689f3
+--- /dev/null
++++ b/arch/arm/mach-hisi/pmc_hi3519.c
+@@ -0,0 +1,281 @@
++/*
++ * power mangager control for hisilicon hi3519 soc
++ *
++ * Copyright (c) 2015 HiSilicon Technologies Co., Ltd.
++ * Authors: zengtao@hisilicon.com
++ *
++ * This program is free software; you can redistribute  it and/or modify it
++ * under  the terms of  the GNU General  Public License as published by the
++ * Free Software Foundation;  either version 2 of the  License, or (at your
++ * option) any later version.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include <linux/io.h>
++#include <linux/linkage.h>
++#include <linux/bug.h>
++#include <linux/of.h>
++#include <linux/of_address.h>
++#include <linux/resource.h>
++#include <mach/io.h>
++#include <mach/platform.h>
++
++#include <linux/delay.h>
++
++#define PERI_PMC77	(0x134)
++#define PERI_PMC79	(0x13c)
++#define PERI_PMC85	(0x154)
++
++static void __iomem *pmc_base;
++static u32  pmc_phys_addr;
++
++#define PMC_ADDRESS(reg)	(pmc_base + reg)
++/* set bitfield of reg from start bit to end - 1 bit */
++static void reg_bit_set(u32 reg, u32 start, u32 end, u32 val)
++{
++	u32 regval, mask;
++
++	regval = readl((void __iomem *)PMC_ADDRESS(reg));
++	mask = ((0xffffffff << (32 - start)) >> (32 - start))
++	       | ((0xffffffff >> end) << end);
++
++	regval &= mask;
++	regval |= (val << start);
++
++	writel(regval, (void __iomem *)PMC_ADDRESS(reg));
++}
++
++/* get bitfield of reg from start bit to end - 1 bit */
++static u32 reg_bit_get(u32 reg, u32 start, u32 end)
++{
++	u32 regval;
++
++	regval = readl((void __iomem *)PMC_ADDRESS(reg));
++	regval = (regval << (32 - end)) >> (32 - end);
++	regval = regval >> start;
++
++	return regval;
++}
++
++void hi_pmc_power_up_done(void)
++{
++	writel(0, (void __iomem *)PMC_ADDRESS(PERI_PMC85));
++	writel(1, (void __iomem *)PMC_ADDRESS(PERI_PMC85));
++
++}
++
++/* before power down set ac inactive */
++void hi_pmc_set_ac_inactive(void)
++{
++	reg_bit_set(PERI_PMC79, 8, 9, 1);
++}
++
++/* after powerup clear ac inactive */
++void hi_pmc_clear_ac_inactive(void)
++{
++	reg_bit_set(PERI_PMC79, 8, 9, 0);
++}
++EXPORT_SYMBOL(hi_pmc_clear_ac_inactive);
++
++/*
++ * call from assable context, same as the
++ * hi_pmc_clear_ac_inactive
++ */
++asmlinkage void __naked hi_pmc_clear_a17_ac(void)
++{
++	asm volatile("\n"
++		"adr     r2, 1f\n"
++		"ldmia   r2, {r1, r3}\n"
++		"sub     r0, r2, r1\n"
++		"ldr     r2, [r0, r3]\n"
++		"ldr r0, ="__stringify(PERI_PMC79)"\n"
++		"add r0, r0, r2\n"
++		"ldr r1, [r0]\n"
++		"bic r1, #0x100\n"
++		"str r1, [r0]\n"
++		"mov r0, #0\n"
++		"bx  lr\n"
++
++		".align  2\n"
++		"1:     .word   .\n"
++		"       .word   pmc_phys_addr\n"
++		);
++
++	unreachable();
++}
++
++/* cpu hotplug powerup */
++void hi_pmc_power_up(void)
++{
++	u32 power_state;
++
++	writel(readl((void *)IO_ADDRESS(0x12030004)) | 0x40000000,
++		 (void *)IO_ADDRESS(0x12030004));
++
++	reg_bit_set(PERI_PMC79, 0, 2, 0x2);
++
++	writel(readl((void *)IO_ADDRESS(CRG_REG_BASE + REG_PERI_CRG10))
++			| (1<<21),
++			(void *)IO_ADDRESS(CRG_REG_BASE + REG_PERI_CRG10));
++
++	reg_bit_set(PERI_PMC77, 1, 2, 0x0);
++
++	mdelay(1);
++	power_state = reg_bit_get(PERI_PMC77, 2, 3);
++	while (power_state)
++		power_state = reg_bit_get(PERI_PMC77, 2, 3);
++
++	reg_bit_set(PERI_PMC77, 0, 1, 0x0);
++	writel(readl((void *)IO_ADDRESS(CRG_REG_BASE + REG_PERI_CRG10))
++			& 0xfff7ffff,
++		 (void *)IO_ADDRESS(CRG_REG_BASE + REG_PERI_CRG10));
++
++	reg_bit_set(PERI_PMC77, 5, 6, 0x1);
++	mdelay(1);
++	power_state = reg_bit_get(PERI_PMC77, 6, 7);
++	while (power_state != 1)
++		power_state = reg_bit_get(PERI_PMC77, 6, 7);
++
++	writel(readl((void *)IO_ADDRESS(CRG_REG_BASE + REG_PERI_CRG10))
++			& 0xfffffffd,
++		(void *)IO_ADDRESS(CRG_REG_BASE + REG_PERI_CRG10));
++}
++
++void hi_pmc_kill_cpu(unsigned int cpu)
++{
++	unsigned int state;
++
++	while (1) {
++		state = readl((void *)IO_ADDRESS(0x12030004)) & 0x40000000;
++		if (!state)
++			break;
++	}
++
++	while (1) {
++		state = reg_bit_get(PERI_PMC77, 7, 9);
++		if (state == 3)
++			break;
++	}
++
++	while (1) {
++		state = reg_bit_get(PERI_PMC77, 3, 5);
++		if (state == 0)
++			break;
++	}
++
++	reg_bit_set(PERI_PMC77, 5, 6, 0x0);
++
++	while (1) {
++		state = reg_bit_get(PERI_PMC77, 6, 7);
++		if (state == 0)
++			break;
++	}
++
++	reg_bit_set(PERI_PMC77, 0, 1, 0x1);
++
++	writel(readl((void *)IO_ADDRESS(CRG_REG_BASE + REG_PERI_CRG10))
++			| (1<<19),
++		 (void *)IO_ADDRESS(CRG_REG_BASE + REG_PERI_CRG10));
++	writel(readl((void *)IO_ADDRESS(CRG_REG_BASE + REG_PERI_CRG10))
++			& 0xffdfffff,
++			(void *)IO_ADDRESS(CRG_REG_BASE + REG_PERI_CRG10));
++
++	reg_bit_set(PERI_PMC77, 1, 2, 0x1);
++
++	while (1) {
++		state = reg_bit_get(PERI_PMC77, 2, 3);
++		if (state == 1)
++			break;
++	}
++}
++
++/* cpu hotplug powerdown */
++void hi_pmc_power_down(void)
++{
++#if 0
++	u32 power_state;
++
++	power_state = reg_bit_get(PERI_PMC79, 12, 16);
++	BUG_ON(power_state != 6);
++
++	/* disable interrupt wakeup */
++	reg_bit_set(PERI_PMC79, 5, 6, 0);
++
++	/* power off */
++	reg_bit_set(PERI_PMC79, 4, 5, 0);
++	reg_bit_set(PERI_PMC79, 4, 5, 1);
++#endif
++	reg_bit_set(PERI_PMC79, 0, 2, 2);
++	writel(readl((void *)IO_ADDRESS(0x12030004)) & 0xbfffffff,
++		(void *)IO_ADDRESS(0x12030004));
++
++}
++
++/* cpuidle powerdown */
++void hi_pmc_automode_power_down(void)
++{
++	u32 power_state;
++
++	power_state = reg_bit_get(PERI_PMC79, 12, 16);
++	BUG_ON(power_state != 6);
++
++	/* enable interrupt wakeup */
++	reg_bit_set(PERI_PMC79, 5, 6, 1);
++
++	/* power off */
++	reg_bit_set(PERI_PMC79, 4, 5, 0);
++	reg_bit_set(PERI_PMC79, 4, 5, 1);
++
++}
++EXPORT_SYMBOL(hi_pmc_automode_power_down);
++
++static void hi_pmc_config(void)
++{
++	/* enable pmc timeout */
++	reg_bit_set(PERI_PMC77, 12, 13, 1);
++	/* enable pmc auto mode */
++	reg_bit_set(PERI_PMC79, 0, 2, 0);
++	/* enable irq triger source power on */
++	reg_bit_set(PERI_PMC79, 7, 8, 1);
++}
++
++/* enable timeout */
++static int hi_pmc_init(void)
++{
++	struct device_node *np;
++	struct resource res;
++	int ret = -ENODEV;
++
++	np = of_find_compatible_node(NULL, NULL, "hisilicon,pmc");
++	if (!np)
++		goto err;
++
++	pmc_base = of_iomap(np, 0);
++	if (!pmc_base) {
++		pr_err("failed to map pmc base\n");
++		ret = -ENOMEM;
++		goto err;
++	}
++
++	ret = of_address_to_resource(np, 0, &res);
++	if (ret) {
++		pr_err("failed to get pmc base phys\n");
++		ret = -ENOMEM;
++		goto err;
++	}
++	pmc_phys_addr = res.start;
++
++	hi_pmc_config();
++err:
++	return ret;
++}
++
++early_initcall(hi_pmc_init);
+diff --git a/arch/arm/mach-hisi/pmc_hi3519v101.c b/arch/arm/mach-hisi/pmc_hi3519v101.c
+new file mode 100644
+index 0000000..e652fb9
+--- /dev/null
++++ b/arch/arm/mach-hisi/pmc_hi3519v101.c
+@@ -0,0 +1,207 @@
++/*
++ * power mangager control for hisilicon hi3519 soc
++ *
++ * Copyright (c) 2015 HiSilicon Technologies Co., Ltd.
++ * Authors: zengtao@hisilicon.com
++ *
++ * This program is free software; you can redistribute  it and/or modify it
++ * under  the terms of  the GNU General  Public License as published by the
++ * Free Software Foundation;  either version 2 of the  License, or (at your
++ * option) any later version.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include <linux/io.h>
++#include <linux/linkage.h>
++#include <linux/bug.h>
++#include <linux/of.h>
++#include <linux/of_address.h>
++#include <linux/resource.h>
++#include <mach/platform.h>
++
++#include <linux/delay.h>
++
++#define PERI_PMC77	(0x134)
++#define PERI_PMC79	(0x13c)
++#define PERI_PMC85	(0x154)
++
++static void __iomem *pmc_base;
++static u32  pmc_phys_addr;
++
++#define PMC_ADDRESS(reg)	(pmc_base + reg)
++/* set bitfield of reg from start bit to end - 1 bit */
++static void reg_bit_set(u32 reg, u32 start, u32 end, u32 val)
++{
++	u32 regval, mask;
++
++	regval = readl((void __iomem *)PMC_ADDRESS(reg));
++	mask = ((0xffffffff << (32 - start)) >> (32 - start))
++	       | ((0xffffffff >> end) << end);
++
++	regval &= mask;
++	regval |= (val << start);
++
++	writel(regval, (void __iomem *)PMC_ADDRESS(reg));
++}
++
++/* get bitfield of reg from start bit to end - 1 bit */
++static u32 reg_bit_get(u32 reg, u32 start, u32 end)
++{
++	u32 regval;
++
++
++	regval = readl((void __iomem *)PMC_ADDRESS(reg));
++	regval = (regval << (32 - end)) >> (32 - end);
++	regval = regval >> start;
++
++
++	return regval;
++}
++
++void hi_pmc_power_up_done(void)
++{
++	writel(0, (void __iomem *)PMC_ADDRESS(PERI_PMC85));
++	writel(1, (void __iomem *)PMC_ADDRESS(PERI_PMC85));
++
++}
++
++/* before power down set ac inactive */
++void hi_pmc_set_ac_inactive(void)
++{
++	reg_bit_set(PERI_PMC79, 8, 9, 1);
++}
++
++/* after powerup clear ac inactive */
++void hi_pmc_clear_ac_inactive(void)
++{
++	reg_bit_set(PERI_PMC79, 8, 9, 0);
++}
++EXPORT_SYMBOL(hi_pmc_clear_ac_inactive);
++
++/* call from assable context */
++asmlinkage void __naked hi_pmc_clear_a17_ac(void)
++{
++	asm volatile("\n"
++		"adr     r2, 1f\n"
++		"ldmia   r2, {r1, r3}\n"
++		"sub     r0, r2, r1\n"
++		"ldr     r2, [r0, r3]\n"
++		"ldr r0, ="__stringify(PERI_PMC79)"\n"
++		"add r0, r0, r2\n"
++		"ldr r1, [r0]\n"
++		"bic r1, #0x100\n"
++		"str r1, [r0]\n"
++		"mov r0, #0\n"
++		"bx  lr\n"
++
++		".align  2\n"
++		"1:     .word   .\n"
++		"       .word   pmc_phys_addr\n"
++		);
++
++	unreachable();
++}
++
++static void hi_pmc_config(void)
++{
++	/* enable pmc timeout */
++	reg_bit_set(PERI_PMC77, 12, 13, 1);
++	/* enable pmc auto mode */
++	reg_bit_set(PERI_PMC79, 0, 2, 0);
++	/* enable irq triger source power on */
++	reg_bit_set(PERI_PMC79, 7, 8, 1);
++}
++
++/* cpu hotplug powerup */
++void hi_pmc_power_up(void)
++{
++	u32 power_state;
++
++	hi_pmc_config();
++
++	/* make sure it powerup state when power up */
++	power_state = reg_bit_get(PERI_PMC79, 12, 16);
++	BUG_ON(power_state != 0);
++
++	/* disable interrupt wakeup */
++	reg_bit_set(PERI_PMC79, 5, 6, 0);
++
++	/* power on */
++	reg_bit_set(PERI_PMC79, 3, 4, 0);
++	reg_bit_set(PERI_PMC79, 3, 4, 1);
++}
++
++/* cpu hotplug powerdown */
++void hi_pmc_power_down(void)
++{
++	u32 power_state;
++
++	power_state = reg_bit_get(PERI_PMC79, 12, 16);
++	BUG_ON(power_state != 6);
++
++	/* disable interrupt wakeup */
++	reg_bit_set(PERI_PMC79, 5, 6, 0);
++
++	/* power off */
++	reg_bit_set(PERI_PMC79, 4, 5, 0);
++	reg_bit_set(PERI_PMC79, 4, 5, 1);
++}
++
++/* cpuidle powerdown */
++void hi_pmc_automode_power_down(void)
++{
++	u32 power_state;
++
++	power_state = reg_bit_get(PERI_PMC79, 12, 16);
++	BUG_ON(power_state != 6);
++
++	/* enable interrupt wakeup */
++	reg_bit_set(PERI_PMC79, 5, 6, 1);
++
++	/* power off */
++	reg_bit_set(PERI_PMC79, 4, 5, 0);
++	reg_bit_set(PERI_PMC79, 4, 5, 1);
++
++}
++EXPORT_SYMBOL(hi_pmc_automode_power_down);
++
++
++/* enable timeout */
++static int hi_pmc_init(void)
++{
++	struct device_node *np;
++	struct resource res;
++	int ret = -ENODEV;
++
++	np = of_find_compatible_node(NULL, NULL, "hisilicon,pmc");
++	if (!np)
++		goto err;
++
++	pmc_base = of_iomap(np, 0);
++	if (!pmc_base) {
++		pr_err("failed to map pmc base\n");
++		ret = -ENOMEM;
++		goto err;
++	}
++
++	ret = of_address_to_resource(np, 0, &res);
++	if (ret) {
++		pr_err("failed to get pmc base phys\n");
++		ret = -ENOMEM;
++		goto err;
++	}
++	pmc_phys_addr = res.start;
++
++err:
++	return ret;
++}
++
++early_initcall(hi_pmc_init);
+diff --git a/arch/arm/mach-hisi/pmc_hi3521d.c b/arch/arm/mach-hisi/pmc_hi3521d.c
+new file mode 100644
+index 0000000..54b9294
+--- /dev/null
++++ b/arch/arm/mach-hisi/pmc_hi3521d.c
+@@ -0,0 +1,40 @@
++/*
++ * Copyright (c) 2015-2017 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include <linux/linkage.h>
++
++asmlinkage void __naked cci_enable_port_for_self(void)
++{
++}
++
++asmlinkage void __naked hi_pmc_clear_a17_ac(void)
++{
++}
++
++void hi_pmc_power_up(void)
++{
++}
++
++void hi_pmc_set_ac_inactive(void)
++{
++}
++
++void hi_pmc_power_down(void)
++{
++}
++
+diff --git a/arch/arm/mach-hisi/pmc_hi3531d.c b/arch/arm/mach-hisi/pmc_hi3531d.c
+new file mode 100644
+index 0000000..54b9294
+--- /dev/null
++++ b/arch/arm/mach-hisi/pmc_hi3531d.c
+@@ -0,0 +1,40 @@
++/*
++ * Copyright (c) 2015-2017 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include <linux/linkage.h>
++
++asmlinkage void __naked cci_enable_port_for_self(void)
++{
++}
++
++asmlinkage void __naked hi_pmc_clear_a17_ac(void)
++{
++}
++
++void hi_pmc_power_up(void)
++{
++}
++
++void hi_pmc_set_ac_inactive(void)
++{
++}
++
++void hi_pmc_power_down(void)
++{
++}
++
+diff --git a/arch/arm/mach-hisi/pmc_hi3536c.c b/arch/arm/mach-hisi/pmc_hi3536c.c
+new file mode 100644
+index 0000000..54b9294
+--- /dev/null
++++ b/arch/arm/mach-hisi/pmc_hi3536c.c
+@@ -0,0 +1,40 @@
++/*
++ * Copyright (c) 2015-2017 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include <linux/linkage.h>
++
++asmlinkage void __naked cci_enable_port_for_self(void)
++{
++}
++
++asmlinkage void __naked hi_pmc_clear_a17_ac(void)
++{
++}
++
++void hi_pmc_power_up(void)
++{
++}
++
++void hi_pmc_set_ac_inactive(void)
++{
++}
++
++void hi_pmc_power_down(void)
++{
++}
++
+diff --git a/arch/arm/mach-hisi/pmc_hi3559.c b/arch/arm/mach-hisi/pmc_hi3559.c
+new file mode 100644
+index 0000000..7767ef2
+--- /dev/null
++++ b/arch/arm/mach-hisi/pmc_hi3559.c
+@@ -0,0 +1,207 @@
++/*
++ * power mangager control for hisilicon hi3559 soc
++ *
++ * Copyright (c) 2015 HiSilicon Technologies Co., Ltd.
++ * Authors: zengtao@hisilicon.com
++ *
++ * This program is free software; you can redistribute  it and/or modify it
++ * under  the terms of  the GNU General  Public License as published by the
++ * Free Software Foundation;  either version 2 of the  License, or (at your
++ * option) any later version.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include <linux/io.h>
++#include <linux/linkage.h>
++#include <linux/bug.h>
++#include <linux/of.h>
++#include <linux/of_address.h>
++#include <linux/resource.h>
++#include <mach/platform.h>
++
++#include <linux/delay.h>
++
++#define PERI_PMC77	(0x134)
++#define PERI_PMC79	(0x13c)
++#define PERI_PMC85	(0x154)
++
++static void __iomem *pmc_base;
++static u32  pmc_phys_addr;
++
++#define PMC_ADDRESS(reg)	(pmc_base + reg)
++/* set bitfield of reg from start bit to end - 1 bit */
++static void reg_bit_set(u32 reg, u32 start, u32 end, u32 val)
++{
++	u32 regval, mask;
++
++	regval = readl((void __iomem *)PMC_ADDRESS(reg));
++	mask = ((0xffffffff << (32 - start)) >> (32 - start))
++	       | ((0xffffffff >> end) << end);
++
++	regval &= mask;
++	regval |= (val << start);
++
++	writel(regval, (void __iomem *)PMC_ADDRESS(reg));
++}
++
++/* get bitfield of reg from start bit to end - 1 bit */
++static u32 reg_bit_get(u32 reg, u32 start, u32 end)
++{
++	u32 regval;
++
++
++	regval = readl((void __iomem *)PMC_ADDRESS(reg));
++	regval = (regval << (32 - end)) >> (32 - end);
++	regval = regval >> start;
++
++
++	return regval;
++}
++
++void hi_pmc_power_up_done(void)
++{
++	writel(0, (void __iomem *)PMC_ADDRESS(PERI_PMC85));
++	writel(1, (void __iomem *)PMC_ADDRESS(PERI_PMC85));
++
++}
++
++/* before power down set ac inactive */
++void hi_pmc_set_ac_inactive(void)
++{
++	reg_bit_set(PERI_PMC79, 8, 9, 1);
++}
++
++/* after powerup clear ac inactive */
++void hi_pmc_clear_ac_inactive(void)
++{
++	reg_bit_set(PERI_PMC79, 8, 9, 0);
++}
++EXPORT_SYMBOL(hi_pmc_clear_ac_inactive);
++
++/* call from assable context */
++asmlinkage void __naked hi_pmc_clear_a17_ac(void)
++{
++	asm volatile("\n"
++		"adr     r2, 1f\n"
++		"ldmia   r2, {r1, r3}\n"
++		"sub     r0, r2, r1\n"
++		"ldr     r2, [r0, r3]\n"
++		"ldr r0, ="__stringify(PERI_PMC79)"\n"
++		"add r0, r0, r2\n"
++		"ldr r1, [r0]\n"
++		"bic r1, #0x100\n"
++		"str r1, [r0]\n"
++		"mov r0, #0\n"
++		"bx  lr\n"
++
++		".align  2\n"
++		"1:     .word   .\n"
++		"       .word   pmc_phys_addr\n"
++		);
++
++	unreachable();
++}
++
++static void hi_pmc_config(void)
++{
++	/* enable pmc timeout */
++	reg_bit_set(PERI_PMC77, 12, 13, 1);
++	/* enable pmc auto mode */
++	reg_bit_set(PERI_PMC79, 0, 2, 0);
++	/* enable irq triger source power on */
++	reg_bit_set(PERI_PMC79, 7, 8, 1);
++}
++
++/* cpu hotplug powerup */
++void hi_pmc_power_up(void)
++{
++	u32 power_state;
++
++	hi_pmc_config();
++
++	/* make sure it powerup state when power up */
++	power_state = reg_bit_get(PERI_PMC79, 12, 16);
++	BUG_ON(power_state != 0);
++
++	/* disable interrupt wakeup */
++	reg_bit_set(PERI_PMC79, 5, 6, 0);
++
++	/* power on */
++	reg_bit_set(PERI_PMC79, 3, 4, 0);
++	reg_bit_set(PERI_PMC79, 3, 4, 1);
++}
++
++/* cpu hotplug powerdown */
++void hi_pmc_power_down(void)
++{
++	u32 power_state;
++
++	power_state = reg_bit_get(PERI_PMC79, 12, 16);
++	BUG_ON(power_state != 6);
++
++	/* disable interrupt wakeup */
++	reg_bit_set(PERI_PMC79, 5, 6, 0);
++
++	/* power off */
++	reg_bit_set(PERI_PMC79, 4, 5, 0);
++	reg_bit_set(PERI_PMC79, 4, 5, 1);
++}
++
++/* cpuidle powerdown */
++void hi_pmc_automode_power_down(void)
++{
++	u32 power_state;
++
++	power_state = reg_bit_get(PERI_PMC79, 12, 16);
++	BUG_ON(power_state != 6);
++
++	/* enable interrupt wakeup */
++	reg_bit_set(PERI_PMC79, 5, 6, 1);
++
++	/* power off */
++	reg_bit_set(PERI_PMC79, 4, 5, 0);
++	reg_bit_set(PERI_PMC79, 4, 5, 1);
++
++}
++EXPORT_SYMBOL(hi_pmc_automode_power_down);
++
++
++/* enable timeout */
++static int hi_pmc_init(void)
++{
++	struct device_node *np;
++	struct resource res;
++	int ret = -ENODEV;
++
++	np = of_find_compatible_node(NULL, NULL, "hisilicon,pmc");
++	if (!np)
++		goto err;
++
++	pmc_base = of_iomap(np, 0);
++	if (!pmc_base) {
++		pr_err("failed to map pmc base\n");
++		ret = -ENOMEM;
++		goto err;
++	}
++
++	ret = of_address_to_resource(np, 0, &res);
++	if (ret) {
++		pr_err("failed to get pmc base phys\n");
++		ret = -ENOMEM;
++		goto err;
++	}
++	pmc_phys_addr = res.start;
++
++err:
++	return ret;
++}
++
++early_initcall(hi_pmc_init);
+diff --git a/arch/arm/mach-hisi/pwr_hi3559.c b/arch/arm/mach-hisi/pwr_hi3559.c
+new file mode 100644
+index 0000000..38a07fb
+--- /dev/null
++++ b/arch/arm/mach-hisi/pwr_hi3559.c
+@@ -0,0 +1,81 @@
++/*
++ * The power mangager control for hisilicon soc
++ *
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include <linux/io.h>
++#include <linux/linkage.h>
++#include <linux/bug.h>
++#include <linux/of.h>
++#include <linux/of_address.h>
++#include <linux/resource.h>
++#include <mach/platform.h>
++
++#define PWR_CTRL0	(0x34)
++
++static void __iomem *pwr_base;
++
++#define PWR_ADDRESS(reg)	(pwr_base + reg)
++/* set bitfield of reg from start bit to end - 1 bit */
++static void reg_bit_set(u32 reg, u32 start, u32 end, u32 val)
++{
++	u32 regval, mask;
++
++	regval = readl((void __iomem *)PWR_ADDRESS(reg));
++	mask = ((0xffffffff << (32 - start)) >> (32 - start))
++	       | ((0xffffffff >> end) << end);
++
++	regval &= mask;
++	regval |= (val << start);
++
++	writel(regval, (void __iomem *)PWR_ADDRESS(reg));
++}
++
++/* power off interface */
++void hi_pwr_off(void)
++{
++	/* set pwr_off_ctrl to 0x1 not 0x2 */
++	/* if set to 0x2, must wait about 2 seconds when power on */
++	reg_bit_set(PWR_CTRL0, 0, 1, 0x1);
++}
++
++extern void (*hi_power_off)(void);
++static int hi_pwr_init(void)
++{
++	struct device_node *np;
++	int ret = 0;
++
++	np = of_find_compatible_node(NULL, NULL, "hisilicon,hi_pwr");
++	if (!np) {
++	    ret = -ENODEV;
++		goto err;
++    }
++
++	pwr_base = of_iomap(np, 0);
++	if (!pwr_base) {
++		pr_err("failed to map pwr base\n");
++		ret = -ENOMEM;
++		goto err;
++	}
++
++    hi_power_off = hi_pwr_off;
++err:
++	return ret;
++}
++early_initcall(hi_pwr_init);
++
+diff --git a/arch/arm/mach-hisi/swsusp.S b/arch/arm/mach-hisi/swsusp.S
+new file mode 100644
+index 0000000..03983bc
+--- /dev/null
++++ b/arch/arm/mach-hisi/swsusp.S
+@@ -0,0 +1,306 @@
++/*
++ * Hibernation support specific for ARM
++ *
++ * Copyright (C) 2010 Nokia Corporation
++ * Copyright (C) 2010 Texas Instruments, Inc.
++ * Copyright (C) 2006 Rafael J. Wysocki <rjw at sisk.pl>
++ *
++ * Contact: Hiroshi DOYU <Hiroshi.DOYU at nokia.com>
++ *
++ * License terms: GNU General Public License (GPL) version 2
++ */
++
++
++#include <linux/linkage.h>
++.text
++
++#define	LOCAL_WORD(x) \
++	.data			; \
++	.p2align 2		; \
++	.type   x, #object	; \
++	.size   x, 4		; \
++x:				; \
++	.long 1
++
++#define WORD_ADDR(x) \
++	.align 2		; \
++.L##x:				; \
++	.word x
++
++/*user*/
++LOCAL_WORD(saved_context_r0)
++LOCAL_WORD(saved_context_r1)
++LOCAL_WORD(saved_context_r2)
++LOCAL_WORD(saved_context_r3)
++LOCAL_WORD(saved_context_r4)
++LOCAL_WORD(saved_context_r5)
++LOCAL_WORD(saved_context_r6)
++LOCAL_WORD(saved_context_r7)
++LOCAL_WORD(saved_context_r8)
++LOCAL_WORD(saved_context_r9)
++LOCAL_WORD(saved_context_r10)
++LOCAL_WORD(saved_context_r11)
++LOCAL_WORD(saved_context_r12)
++LOCAL_WORD(saved_context_r13)
++LOCAL_WORD(saved_context_r14)
++LOCAL_WORD(saved_cpsr)
++
++LOCAL_WORD(saved_context_r8_fiq)
++LOCAL_WORD(saved_context_r9_fiq)
++LOCAL_WORD(saved_context_r10_fiq)
++LOCAL_WORD(saved_context_r11_fiq)
++LOCAL_WORD(saved_context_r12_fiq)
++LOCAL_WORD(saved_context_r13_fiq)
++LOCAL_WORD(saved_context_r14_fiq)
++LOCAL_WORD(saved_spsr_fiq)
++
++LOCAL_WORD(saved_context_r13_irq)
++LOCAL_WORD(saved_context_r14_irq)
++LOCAL_WORD(saved_spsr_irq)
++
++LOCAL_WORD(saved_context_r13_svc)
++LOCAL_WORD(saved_context_r14_svc)
++LOCAL_WORD(saved_spsr_svc)
++
++LOCAL_WORD(saved_context_r13_abt)
++LOCAL_WORD(saved_context_r14_abt)
++LOCAL_WORD(saved_spsr_abt)
++
++LOCAL_WORD(saved_context_r13_und)
++LOCAL_WORD(saved_context_r14_und)
++LOCAL_WORD(saved_spsr_und)
++
++#define CHANGE_MODE(x)        \
++    mov     r1, r0          ; \
++    bic     r1, r1, #0x1f   ; \
++    orr     r1, r1, #0x##x  ; \
++    msr     cpsr_c, r1
++
++ENTRY(swsusp_arch_suspend)
++   /*
++     * Save current program status register
++     */
++    ldr     r3, .Lsaved_cpsr
++    mrs     r0, cpsr
++    str     r0, [r3]
++
++    CHANGE_MODE(1f)  /* Change to system(user) mode*/
++    ldr     r3, .Lsaved_context_r0
++    stmia   r3, {r0-r14}
++
++    CHANGE_MODE(11) /* change to fiq mode */
++    /* save nonvolatile int register */
++    ldr r3, .Lsaved_context_r8_fiq
++    stmia   r3, {r8-r14}
++    /* save spsr_fiq register */
++    ldr r3, .Lsaved_spsr_fiq
++    mrs r1, spsr
++    str r1, [r3]
++
++    CHANGE_MODE(12) /* change to irq mode */
++    /* save nonvolatile int register */
++    ldr r3, .Lsaved_context_r13_irq
++    stmia   r3, {r13-r14}
++    /* save spsr_irq register */
++    ldr r3, .Lsaved_spsr_irq
++    mrs r1, spsr
++    str r1, [r3]
++
++    CHANGE_MODE(13) /* change to svc mode */
++    /* save nonvolatile int register */
++    ldr r3, .Lsaved_context_r13_svc
++    stmia   r3, {r13-r14}
++    /* save spsr_svc register */
++    ldr r3, .Lsaved_spsr_svc
++    mrs r1, spsr
++    str r1, [r3]
++
++    CHANGE_MODE(17) /* change to abt mode */
++    /* save nonvolatile int register */
++    ldr r3, .Lsaved_context_r13_abt
++    stmia   r3, {r13-r14}
++    /* save spsr_abt register */
++    ldr r3, .Lsaved_spsr_abt
++    mrs r1, spsr
++    str r1, [r3]
++
++    CHANGE_MODE(1b) /* change to und mode */
++    /* save nonvolatile int register */
++    ldr r3, .Lsaved_context_r13_und
++    stmia   r3, {r13-r14}
++    /* save spsr_und register */
++    ldr r3, .Lsaved_spsr_und
++    mrs r1, spsr
++    str r1, [r3]
++
++    /*
++     * Go back to original SVC mode
++     */
++    msr     cpsr_c, r0
++
++    bl      swsusp_save
++
++#ifdef CONFIG_DEBUG_LL
++    adr r0, str_marker_1
++    bl  printascii
++    mov r0, #0
++#endif
++
++    /*
++     * Restore return address
++     */
++    ldr     r3, .Lsaved_context_r14_svc
++    ldr     lr, [r3]
++    mov     pc, lr
++
++    WORD_ADDR(saved_context_r0)
++    WORD_ADDR(saved_cpsr)
++
++    WORD_ADDR(saved_context_r8_fiq)
++    WORD_ADDR(saved_spsr_fiq)
++
++    WORD_ADDR(saved_context_r13_irq)
++    WORD_ADDR(saved_spsr_irq)
++
++    WORD_ADDR(saved_context_r13_svc)
++    WORD_ADDR(saved_context_r14_svc)
++    WORD_ADDR(saved_spsr_svc)
++
++    WORD_ADDR(saved_context_r13_abt)
++    WORD_ADDR(saved_spsr_abt)
++
++    WORD_ADDR(saved_context_r13_und)
++    WORD_ADDR(saved_spsr_und)
++
++ENDPROC(swsusp_arch_suspend)
++
++ENTRY(swsusp_arch_resume)
++
++#ifdef CONFIG_DEBUG_LL
++    adr r0, str_marker_1
++    bl  printascii
++    mov r0, #0
++#endif
++
++#ifdef CONFIG_HISI_SNAPSHOT_BOOT
++    /* FIXME: need to check the cp15, c0 #4,
++     *     "Instruction Set Attributes Register 4"
++     */
++    #dsb
++    #isb
++
++#else /* CONFIG_HISI_SNAPSHOT_BOOT */
++
++    /*
++     * Restore_pblist is the starting point for loaded pages
++     */
++    ldr     r0, .Lrestore_pblist
++    ldr     r6, [r0]
++
++    .Lcopy_loop:
++    ldr     r4, [r6]     /* src IOW present address */
++    ldr     r5, [r6, #4] /* dst IOW original address*/
++    mov     r9, #1024    /* No. of entries in one page(4 bytes each entry)*/
++
++    .Lcopy_one_page:
++    /*
++     * This loop could be optimized by using stm and ldm.
++     */
++    ldr     r8, [r4], #4
++    str     r8, [r5], #4
++    subs    r9, r9, #1
++    bne     .Lcopy_one_page
++
++    /* The last field of struct pbe is a pointer to the next pbe struct */
++    ldr     r6, [r6, #8]
++    cmp     r6, #0
++    bne     .Lcopy_loop
++#endif /* CONFIG_HISI_SNAPSHOT_BOOT */
++    /*
++     * Restore SVC context
++     */
++    ldr     r3, .Lsaved_context_r13_svc
++    ldmia   r3, {r13-r14}
++    ldr     r3, .Lsaved_spsr_svc
++    ldr     r1, [r3]
++    msr     spsr_cxsf, r1
++
++    mrs     r0, cpsr    /* Save current mode into r0 */
++
++    CHANGE_MODE(11) /* change to fiq mode */
++    /* restore nonvolatile int register */
++    ldr r3, .Lsaved_context_r8_fiq
++    ldmia   r3, {r8-r14}
++    /* restore spsr_fiq register */
++    ldr r3, .Lsaved_spsr_fiq
++    ldr r1, [r3]
++    msr spsr_cxsf, r1
++
++    CHANGE_MODE(12) /* change to irq mode */
++    /* restore nonvolatile int register */
++    ldr r3, .Lsaved_context_r13_irq
++    ldmia   r3, {r13-r14}
++    /* restore spsr_irq register */
++    ldr r3, .Lsaved_spsr_irq
++    ldr r1, [r3]
++    msr spsr_cxsf, r1
++
++    CHANGE_MODE(17) /* change to abt mode */
++    /* restore nonvolatile int register */
++    ldr r3, .Lsaved_context_r13_abt
++    ldmia   r3, {r13-r14}
++    /* restore spsr_abt register */
++    ldr r3, .Lsaved_spsr_abt
++    ldr r1, [r3]
++    msr spsr_cxsf, r1
++
++    CHANGE_MODE(1b) /* change to und mode */
++    /* restore nonvolatile int register */
++    ldr r3, .Lsaved_context_r13_und
++    ldmia   r3, {r13-r14}
++    /* restore spsr_und register */
++    ldr r3, .Lsaved_spsr_und
++    ldr r1, [r3]
++    msr spsr_cxsf, r1
++
++    CHANGE_MODE(1f) /* Change to system(user) mode */
++
++    /* in_suspend = 0 */
++    ldr     r3,.Lsaved_in_suspend
++    mov     r1,#0
++    str     r1,[r3]
++
++    /*
++     * Restore User context
++     */
++    ldr     r3, .Lsaved_context_r0
++    ldmia   r3, {r0-r14}
++    ldr     r3, .Lsaved_cpsr
++    ldr     r1, [r3]
++    msr     cpsr_cxsf, r1
++
++    /*
++     * Flush TLB (Invalidate unified TLB unlocked entries)
++     */
++    mov     r1, #0
++    mcr     p15, 0, r1, c8, c7, 0
++
++#ifdef CONFIG_DEBUG_LL
++    adr r0, str_marker_1
++    bl  printascii
++    mov r0, #0
++#endif
++
++    /* Set the return value */
++    mov r0, #0
++
++    /* Restore return address */
++    ldr     r3, .Lsaved_context_r14_svc
++    ldr     lr, [r3]
++    mov     pc, lr
++ENDPROC(swsusp_arch_resume)
++
++str_marker_1: .asciz "swsusp_arch_mark!!!\n\0"
++
++    .align  4
++.Lsaved_in_suspend:         .long   in_suspend
+diff --git a/arch/arm/mm/cache-v6.S b/arch/arm/mm/cache-v6.S
+index 2465995..11da0f5 100644
+--- a/arch/arm/mm/cache-v6.S
++++ b/arch/arm/mm/cache-v6.S
+@@ -270,6 +270,11 @@ v6_dma_clean_range:
+  *	- end     - virtual end address of region
+  */
+ ENTRY(v6_dma_flush_range)
++#ifdef CONFIG_CACHE_FLUSH_RANGE_LIMIT
++	sub	r2, r1, r0
++	cmp	r2, #CONFIG_CACHE_FLUSH_RANGE_LIMIT
++	bhi	v6_dma_flush_dcache_all
++#endif
+ #ifdef CONFIG_DMA_CACHE_RWFO
+ 	ldrb	r2, [r0]		@ read for ownership
+ 	strb	r2, [r0]		@ write for ownership
+@@ -292,6 +297,18 @@ ENTRY(v6_dma_flush_range)
+ 	mcr	p15, 0, r0, c7, c10, 4		@ drain write buffer
+ 	ret	lr
+ 
++#ifdef CONFIG_CACHE_FLUSH_RANGE_LIMIT
++v6_dma_flush_dcache_all:
++	mov	r0, #0
++#ifdef HARVARD_CACHE
++	mcr	p15, 0, r0, c7, c14, 0		@ D cache clean+invalidate
++#else
++	mcr	p15, 0, r0, c7, c15, 0		@ Cache clean+invalidate
++#endif
++	mcr	p15, 0, r0, c7, c10, 4		@ drain write buffer
++	mov	pc, lr
++#endif
++
+ /*
+  *	dma_map_area(start, size, dir)
+  *	- start	- kernel virtual start address
+diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
+index e890711..369dc9b 100644
+--- a/arch/arm/mm/dma-mapping.c
++++ b/arch/arm/mm/dma-mapping.c
+@@ -221,7 +221,7 @@ static u64 get_coherent_dma_mask(struct device *dev)
+ 	return mask;
+ }
+ 
+-static void __dma_clear_buffer(struct page *page, size_t size)
++void __dma_clear_buffer(struct page *page, size_t size)
+ {
+ 	/*
+ 	 * Ensure that the allocated pages are zeroed, and that any data
+@@ -246,6 +246,7 @@ static void __dma_clear_buffer(struct page *page, size_t size)
+ 		outer_flush_range(__pa(ptr), __pa(ptr) + size);
+ 	}
+ }
++EXPORT_SYMBOL(__dma_clear_buffer);
+ 
+ /*
+  * Allocate a DMA buffer for 'dev' of size 'size' using the
+@@ -465,6 +466,12 @@ static void __dma_remap(struct page *page, size_t size, pgprot_t prot)
+ 	flush_tlb_kernel_range(start, end);
+ }
+ 
++void hisi_flush_tlb_kernel_range(unsigned long start, unsigned long end)
++{
++	flush_tlb_kernel_range(start, end);
++}
++EXPORT_SYMBOL(hisi_flush_tlb_kernel_range);
++
+ static void *__alloc_remap_buffer(struct device *dev, size_t size, gfp_t gfp,
+ 				 pgprot_t prot, struct page **ret_page,
+ 				 const void *caller)
+diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
+index eb8830a..b784579 100644
+--- a/arch/arm/mm/fault.c
++++ b/arch/arm/mm/fault.c
+@@ -274,10 +274,10 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
+ 		local_irq_enable();
+ 
+ 	/*
+-	 * If we're in an interrupt or have no user
++	 * If we're in an interrupt, or have no irqs, or have no user
+ 	 * context, we must not take the fault..
+ 	 */
+-	if (in_atomic() || !mm)
++	if (in_atomic() || irqs_disabled() || !mm)
+ 		goto no_context;
+ 
+ 	if (user_mode(regs))
+diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
+index dc2d66c..43fe143 100644
+--- a/arch/arm64/Kconfig
++++ b/arch/arm64/Kconfig
+@@ -37,6 +37,7 @@ config ARM64
+ 	select HAVE_ARCH_AUDITSYSCALL
+ 	select HAVE_ARCH_JUMP_LABEL
+ 	select HAVE_ARCH_KGDB
++	select HAVE_ARCH_SECCOMP_FILTER
+ 	select HAVE_ARCH_TRACEHOOK
+ 	select HAVE_BPF_JIT
+ 	select HAVE_C_RECORDMCOUNT
+@@ -88,6 +89,10 @@ config MMU
+ config NO_IOPORT_MAP
+ 	def_bool y if !PCI
+ 
++config ILLEGAL_POINTER_VALUE
++	hex
++	default 0xdead000000000000
++
+ config STACKTRACE_SUPPORT
+ 	def_bool y
+ 
+@@ -474,6 +479,19 @@ config ARCH_HAS_CACHE_LINE_SIZE
+ 
+ source "mm/Kconfig"
+ 
++config SECCOMP
++	bool "Enable seccomp to safely compute untrusted bytecode"
++	---help---
++	  This kernel feature is useful for number crunching applications
++	  that may need to compute untrusted bytecode during their
++	  execution. By using pipes or other transports made available to
++	  the process as file descriptors supporting the read/write
++	  syscalls, it's possible to isolate those applications in
++	  their own address space using seccomp. Once seccomp is
++	  enabled via prctl(PR_SET_SECCOMP), it cannot be disabled
++	  and the task is only allowed to execute a few safe syscalls
++	  defined by each seccomp mode.
++
+ config XEN_DOM0
+ 	def_bool y
+ 	depends on XEN
+@@ -490,6 +508,74 @@ config FORCE_MAX_ZONEORDER
+ 	default "14" if (ARM64_64K_PAGES && TRANSPARENT_HUGEPAGE)
+ 	default "11"
+ 
++menuconfig ARMV8_DEPRECATED
++	bool "Emulate deprecated/obsolete ARMv8 instructions"
++	depends on COMPAT
++	help
++	  Legacy software support may require certain instructions
++	  that have been deprecated or obsoleted in the architecture.
++
++	  Enable this config to enable selective emulation of these
++	  features.
++
++	  If unsure, say Y
++
++if ARMV8_DEPRECATED
++
++config SWP_EMULATION
++	bool "Emulate SWP/SWPB instructions"
++	help
++	  ARMv8 obsoletes the use of A32 SWP/SWPB instructions such that
++	  they are always undefined. Say Y here to enable software
++	  emulation of these instructions for userspace using LDXR/STXR.
++
++	  In some older versions of glibc [<=2.8] SWP is used during futex
++	  trylock() operations with the assumption that the code will not
++	  be preempted. This invalid assumption may be more likely to fail
++	  with SWP emulation enabled, leading to deadlock of the user
++	  application.
++
++	  NOTE: when accessing uncached shared regions, LDXR/STXR rely
++	  on an external transaction monitoring block called a global
++	  monitor to maintain update atomicity. If your system does not
++	  implement a global monitor, this option can cause programs that
++	  perform SWP operations to uncached memory to deadlock.
++
++	  If unsure, say Y
++
++config CP15_BARRIER_EMULATION
++	bool "Emulate CP15 Barrier instructions"
++	help
++	  The CP15 barrier instructions - CP15ISB, CP15DSB, and
++	  CP15DMB - are deprecated in ARMv8 (and ARMv7). It is
++	  strongly recommended to use the ISB, DSB, and DMB
++	  instructions instead.
++
++	  Say Y here to enable software emulation of these
++	  instructions for AArch32 userspace code. When this option is
++	  enabled, CP15 barrier usage is traced which can help
++	  identify software that needs updating.
++
++	  If unsure, say Y
++
++config SETEND_EMULATION
++	bool "Emulate SETEND instruction"
++	help
++	  The SETEND instruction alters the data-endianness of the
++	  AArch32 EL0, and is deprecated in ARMv8.
++
++	  Say Y here to enable software emulation of the instruction
++	  for AArch32 userspace code.
++
++	  Note: All the cpus on the system must have mixed endian support at EL0
++	  for this feature to be enabled. If a new CPU - which doesn't support mixed
++	  endian - is hotplugged in after this feature has been enabled, there could
++	  be unexpected results in the applications.
++
++	  If unsure, say Y
++
++endif
++
+ endmenu
+ 
+ menu "Boot options"
+@@ -502,6 +588,23 @@ config CMDLINE
+ 	  entering them here. As a minimum, you should specify the the
+ 	  root device (e.g. root=/dev/nfs).
+ 
++choice
++	prompt "Kernel command line type" if CMDLINE != ""
++	default CMDLINE_FROM_BOOTLOADER
++
++config CMDLINE_FROM_BOOTLOADER
++	bool "Use bootloader kernel arguments if available"
++	help
++	  Uses the command-line options passed by the boot loader. If
++	  the boot loader doesn't provide any, the default kernel command
++	  string provided in CMDLINE will be used.
++
++config CMDLINE_EXTEND
++	bool "Extend bootloader kernel arguments"
++	help
++	  The command-line arguments provided by the boot loader will be
++	  appended to the default kernel command string.
++
+ config CMDLINE_FORCE
+ 	bool "Always use the default kernel command string"
+ 	help
+@@ -509,6 +612,7 @@ config CMDLINE_FORCE
+ 	  loader passes other arguments to the kernel.
+ 	  This is useful if you cannot or don't want to change the
+ 	  command-line options your boot loader passes to the kernel.
++endchoice
+ 
+ config EFI_STUB
+ 	bool
+@@ -530,6 +634,21 @@ config EFI
+ 	  allow the kernel to be booted as an EFI application. This
+ 	  is only useful on systems that have UEFI firmware.
+ 
++config BUILD_ARM64_APPENDED_DTB_IMAGE
++	bool "Build a concatenated Image.gz/dtb by default"
++	depends on OF
++	help
++	  Enabling this option will cause a concatenated Image.gz and list of
++	  DTBs to be built by default (instead of a standalone Image.gz.)
++	  The image will built in arch/arm64/boot/Image.gz-dtb
++
++config BUILD_ARM64_APPENDED_DTB_IMAGE_NAMES
++	string "Default dtb names"
++	depends on BUILD_ARM64_APPENDED_DTB_IMAGE
++	help
++	  Space separated list of names of dtbs to append when
++	  building a concatenated Image.gz-dtb.
++
+ endmenu
+ 
+ menu "Userspace binary formats"
+diff --git a/arch/arm64/Kconfig.debug b/arch/arm64/Kconfig.debug
+index 0a12933..8dd3a55 100644
+--- a/arch/arm64/Kconfig.debug
++++ b/arch/arm64/Kconfig.debug
+@@ -54,4 +54,6 @@ config DEBUG_SET_MODULE_RONX
+           against certain classes of kernel exploits.
+           If in doubt, say "N".
+ 
++source "drivers/hwtracing/coresight/Kconfig"
++
+ endmenu
+diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile
+index 20901ff..18daa9f 100644
+--- a/arch/arm64/Makefile
++++ b/arch/arm64/Makefile
+@@ -20,6 +20,7 @@ LIBGCC 		:= $(shell $(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name)
+ KBUILD_DEFCONFIG := defconfig
+ 
+ KBUILD_CFLAGS	+= -mgeneral-regs-only
++KBUILD_CFLAGS	+= -fno-pic
+ ifeq ($(CONFIG_CPU_BIG_ENDIAN), y)
+ KBUILD_CPPFLAGS	+= -mbig-endian
+ AS		+= -EB
+@@ -54,7 +55,12 @@ libs-y		+= $(LIBGCC)
+ libs-$(CONFIG_EFI_STUB) += drivers/firmware/efi/libstub/
+ 
+ # Default target when executing plain make
++ifeq ($(CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE),y)
++KBUILD_IMAGE	:= Image.gz-dtb
++else
+ KBUILD_IMAGE	:= Image.gz
++endif
++
+ KBUILD_DTBS	:= dtbs
+ 
+ all:	$(KBUILD_IMAGE) $(KBUILD_DTBS)
+@@ -70,8 +76,16 @@ zinstall install: vmlinux
+ %.dtb: scripts
+ 	$(Q)$(MAKE) $(build)=$(boot)/dts $(boot)/dts/$@
+ 
+-dtbs: scripts
+-	$(Q)$(MAKE) $(build)=$(boot)/dts dtbs
++PHONY += dtbs dtbs_install
++
++dtbs: prepare scripts
++	$(Q)$(MAKE) $(build)=$(boot)/dts
++
++dtbs_install:
++	$(Q)$(MAKE) $(dtbinst)=$(boot)/dts
++
++Image.gz-dtb: vmlinux scripts dtbs
++	$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
+ 
+ PHONY += vdso_install
+ vdso_install:
+@@ -85,6 +99,7 @@ define archhelp
+   echo  '* Image.gz      - Compressed kernel image (arch/$(ARCH)/boot/Image.gz)'
+   echo  '  Image         - Uncompressed kernel image (arch/$(ARCH)/boot/Image)'
+   echo  '* dtbs          - Build device tree blobs for enabled boards'
++  echo  '  dtbs_install  - Install dtbs to $(INSTALL_DTBS_PATH)'
+   echo  '  install       - Install uncompressed kernel'
+   echo  '  zinstall      - Install compressed kernel'
+   echo  '                  Install using (your) ~/bin/installkernel or'
+diff --git a/arch/arm64/boot/.gitignore b/arch/arm64/boot/.gitignore
+index 8dab0bb..eb35511 100644
+--- a/arch/arm64/boot/.gitignore
++++ b/arch/arm64/boot/.gitignore
+@@ -1,2 +1,3 @@
+ Image
+ Image.gz
++Image.gz-dtb
+diff --git a/arch/arm64/boot/Makefile b/arch/arm64/boot/Makefile
+index 5a0e3ab..71f513f 100644
+--- a/arch/arm64/boot/Makefile
++++ b/arch/arm64/boot/Makefile
+@@ -14,14 +14,27 @@
+ # Based on the ia64 boot/Makefile.
+ #
+ 
++include $(srctree)/arch/arm64/boot/dts/Makefile
++
+ targets := Image Image.gz
+ 
++DTB_NAMES := $(subst $\",,$(CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE_NAMES))
++ifneq ($(DTB_NAMES),)
++DTB_LIST := $(addsuffix .dtb,$(DTB_NAMES))
++DTB_OBJS := $(addprefix $(obj)/dts/,$(DTB_LIST))
++else
++DTB_OBJS := $(shell find $(obj)/dts/ -name \*.dtb)
++endif
++
+ $(obj)/Image: vmlinux FORCE
+ 	$(call if_changed,objcopy)
+ 
+ $(obj)/Image.gz: $(obj)/Image FORCE
+ 	$(call if_changed,gzip)
+ 
++$(obj)/Image.gz-dtb: $(obj)/Image.gz $(DTB_OBJS) FORCE
++	$(call if_changed,cat)
++
+ install: $(obj)/Image
+ 	$(CONFIG_SHELL) $(srctree)/$(src)/install.sh $(KERNELRELEASE) \
+ 	$(obj)/Image System.map "$(INSTALL_PATH)"
+diff --git a/arch/arm64/boot/dts/Makefile b/arch/arm64/boot/dts/Makefile
+index f8001a6..68d2567 100644
+--- a/arch/arm64/boot/dts/Makefile
++++ b/arch/arm64/boot/dts/Makefile
+@@ -1,10 +1,6 @@
+-dtb-$(CONFIG_ARCH_THUNDER) += thunder-88xx.dtb
+-dtb-$(CONFIG_ARCH_VEXPRESS) += rtsm_ve-aemv8a.dtb foundation-v8.dtb
+-dtb-$(CONFIG_ARCH_XGENE) += apm-mustang.dtb
++dts-dirs += apm
++dts-dirs += arm
++dts-dirs += cavium
+ 
+-targets += dtbs
+-targets += $(dtb-y)
+-
+-dtbs: $(addprefix $(obj)/, $(dtb-y))
+-
+-clean-files := *.dtb
++always		:= $(dtb-y)
++subdir-y	:= $(dts-dirs)
+diff --git a/arch/arm64/boot/dts/apm-mustang.dts b/arch/arm64/boot/dts/apm-mustang.dts
+deleted file mode 100644
+index 2e25de0..0000000
+--- a/arch/arm64/boot/dts/apm-mustang.dts
++++ /dev/null
+@@ -1,50 +0,0 @@
+-/*
+- * dts file for AppliedMicro (APM) Mustang Board
+- *
+- * Copyright (C) 2013, Applied Micro Circuits Corporation
+- *
+- * This program is free software; you can redistribute it and/or
+- * modify it under the terms of the GNU General Public License as
+- * published by the Free Software Foundation; either version 2 of
+- * the License, or (at your option) any later version.
+- */
+-
+-/dts-v1/;
+-
+-/include/ "apm-storm.dtsi"
+-
+-/ {
+-	model = "APM X-Gene Mustang board";
+-	compatible = "apm,mustang", "apm,xgene-storm";
+-
+-	chosen { };
+-
+-	memory {
+-		device_type = "memory";
+-		reg = < 0x1 0x00000000 0x0 0x80000000 >; /* Updated by bootloader */
+-	};
+-};
+-
+-&pcie0clk {
+-	status = "ok";
+-};
+-
+-&pcie0 {
+-	status = "ok";
+-};
+-
+-&serial0 {
+-	status = "ok";
+-};
+-
+-&menet {
+-	status = "ok";
+-};
+-
+-&sgenet0 {
+-	status = "ok";
+-};
+-
+-&xgenet {
+-	status = "ok";
+-};
+diff --git a/arch/arm64/boot/dts/apm-storm.dtsi b/arch/arm64/boot/dts/apm-storm.dtsi
+deleted file mode 100644
+index f1ad9c2..0000000
+--- a/arch/arm64/boot/dts/apm-storm.dtsi
++++ /dev/null
+@@ -1,660 +0,0 @@
+-/*
+- * dts file for AppliedMicro (APM) X-Gene Storm SOC
+- *
+- * Copyright (C) 2013, Applied Micro Circuits Corporation
+- *
+- * This program is free software; you can redistribute it and/or
+- * modify it under the terms of the GNU General Public License as
+- * published by the Free Software Foundation; either version 2 of
+- * the License, or (at your option) any later version.
+- */
+-
+-/ {
+-	compatible = "apm,xgene-storm";
+-	interrupt-parent = <&gic>;
+-	#address-cells = <2>;
+-	#size-cells = <2>;
+-
+-	cpus {
+-		#address-cells = <2>;
+-		#size-cells = <0>;
+-
+-		cpu@000 {
+-			device_type = "cpu";
+-			compatible = "apm,potenza", "arm,armv8";
+-			reg = <0x0 0x000>;
+-			enable-method = "spin-table";
+-			cpu-release-addr = <0x1 0x0000fff8>;
+-		};
+-		cpu@001 {
+-			device_type = "cpu";
+-			compatible = "apm,potenza", "arm,armv8";
+-			reg = <0x0 0x001>;
+-			enable-method = "spin-table";
+-			cpu-release-addr = <0x1 0x0000fff8>;
+-		};
+-		cpu@100 {
+-			device_type = "cpu";
+-			compatible = "apm,potenza", "arm,armv8";
+-			reg = <0x0 0x100>;
+-			enable-method = "spin-table";
+-			cpu-release-addr = <0x1 0x0000fff8>;
+-		};
+-		cpu@101 {
+-			device_type = "cpu";
+-			compatible = "apm,potenza", "arm,armv8";
+-			reg = <0x0 0x101>;
+-			enable-method = "spin-table";
+-			cpu-release-addr = <0x1 0x0000fff8>;
+-		};
+-		cpu@200 {
+-			device_type = "cpu";
+-			compatible = "apm,potenza", "arm,armv8";
+-			reg = <0x0 0x200>;
+-			enable-method = "spin-table";
+-			cpu-release-addr = <0x1 0x0000fff8>;
+-		};
+-		cpu@201 {
+-			device_type = "cpu";
+-			compatible = "apm,potenza", "arm,armv8";
+-			reg = <0x0 0x201>;
+-			enable-method = "spin-table";
+-			cpu-release-addr = <0x1 0x0000fff8>;
+-		};
+-		cpu@300 {
+-			device_type = "cpu";
+-			compatible = "apm,potenza", "arm,armv8";
+-			reg = <0x0 0x300>;
+-			enable-method = "spin-table";
+-			cpu-release-addr = <0x1 0x0000fff8>;
+-		};
+-		cpu@301 {
+-			device_type = "cpu";
+-			compatible = "apm,potenza", "arm,armv8";
+-			reg = <0x0 0x301>;
+-			enable-method = "spin-table";
+-			cpu-release-addr = <0x1 0x0000fff8>;
+-		};
+-	};
+-
+-	gic: interrupt-controller@78010000 {
+-		compatible = "arm,cortex-a15-gic";
+-		#interrupt-cells = <3>;
+-		interrupt-controller;
+-		reg = <0x0 0x78010000 0x0 0x1000>,	/* GIC Dist */
+-		      <0x0 0x78020000 0x0 0x1000>,	/* GIC CPU */
+-		      <0x0 0x78040000 0x0 0x2000>,	/* GIC VCPU Control */
+-		      <0x0 0x78060000 0x0 0x2000>;	/* GIC VCPU */
+-		interrupts = <1 9 0xf04>;	/* GIC Maintenence IRQ */
+-	};
+-
+-	timer {
+-		compatible = "arm,armv8-timer";
+-		interrupts = <1 0 0xff01>,	/* Secure Phys IRQ */
+-			     <1 13 0xff01>,	/* Non-secure Phys IRQ */
+-			     <1 14 0xff01>,	/* Virt IRQ */
+-			     <1 15 0xff01>;	/* Hyp IRQ */
+-		clock-frequency = <50000000>;
+-	};
+-
+-	soc {
+-		compatible = "simple-bus";
+-		#address-cells = <2>;
+-		#size-cells = <2>;
+-		ranges;
+-
+-		clocks {
+-			#address-cells = <2>;
+-			#size-cells = <2>;
+-			ranges;
+-			refclk: refclk {
+-				compatible = "fixed-clock";
+-				#clock-cells = <1>;
+-				clock-frequency = <100000000>;
+-				clock-output-names = "refclk";
+-			};
+-
+-			pcppll: pcppll@17000100 {
+-				compatible = "apm,xgene-pcppll-clock";
+-				#clock-cells = <1>;
+-				clocks = <&refclk 0>;
+-				clock-names = "pcppll";
+-				reg = <0x0 0x17000100 0x0 0x1000>;
+-				clock-output-names = "pcppll";
+-				type = <0>;
+-			};
+-
+-			socpll: socpll@17000120 {
+-				compatible = "apm,xgene-socpll-clock";
+-				#clock-cells = <1>;
+-				clocks = <&refclk 0>;
+-				clock-names = "socpll";
+-				reg = <0x0 0x17000120 0x0 0x1000>;
+-				clock-output-names = "socpll";
+-				type = <1>;
+-			};
+-
+-			socplldiv2: socplldiv2  {
+-				compatible = "fixed-factor-clock";
+-				#clock-cells = <1>;
+-				clocks = <&socpll 0>;
+-				clock-names = "socplldiv2";
+-				clock-mult = <1>;
+-				clock-div = <2>;
+-				clock-output-names = "socplldiv2";
+-			};
+-
+-			qmlclk: qmlclk {
+-				compatible = "apm,xgene-device-clock";
+-				#clock-cells = <1>;
+-				clocks = <&socplldiv2 0>;
+-				clock-names = "qmlclk";
+-				reg = <0x0 0x1703C000 0x0 0x1000>;
+-				reg-names = "csr-reg";
+-				clock-output-names = "qmlclk";
+-			};
+-
+-			ethclk: ethclk {
+-				compatible = "apm,xgene-device-clock";
+-				#clock-cells = <1>;
+-				clocks = <&socplldiv2 0>;
+-				clock-names = "ethclk";
+-				reg = <0x0 0x17000000 0x0 0x1000>;
+-				reg-names = "div-reg";
+-				divider-offset = <0x238>;
+-				divider-width = <0x9>;
+-				divider-shift = <0x0>;
+-				clock-output-names = "ethclk";
+-			};
+-
+-			menetclk: menetclk {
+-				compatible = "apm,xgene-device-clock";
+-				#clock-cells = <1>;
+-				clocks = <&ethclk 0>;
+-				reg = <0x0 0x1702C000 0x0 0x1000>;
+-				reg-names = "csr-reg";
+-				clock-output-names = "menetclk";
+-			};
+-
+-			sge0clk: sge0clk@1f21c000 {
+-				compatible = "apm,xgene-device-clock";
+-				#clock-cells = <1>;
+-				clocks = <&socplldiv2 0>;
+-				reg = <0x0 0x1f21c000 0x0 0x1000>;
+-				reg-names = "csr-reg";
+-				csr-mask = <0x3>;
+-				clock-output-names = "sge0clk";
+-			};
+-
+-			xge0clk: xge0clk@1f61c000 {
+-				compatible = "apm,xgene-device-clock";
+-				#clock-cells = <1>;
+-				clocks = <&socplldiv2 0>;
+-				reg = <0x0 0x1f61c000 0x0 0x1000>;
+-				reg-names = "csr-reg";
+-				csr-mask = <0x3>;
+-				clock-output-names = "xge0clk";
+-			};
+-
+-			sataphy1clk: sataphy1clk@1f21c000 {
+-				compatible = "apm,xgene-device-clock";
+-				#clock-cells = <1>;
+-				clocks = <&socplldiv2 0>;
+-				reg = <0x0 0x1f21c000 0x0 0x1000>;
+-				reg-names = "csr-reg";
+-				clock-output-names = "sataphy1clk";
+-				status = "disabled";
+-				csr-offset = <0x4>;
+-				csr-mask = <0x00>;
+-				enable-offset = <0x0>;
+-				enable-mask = <0x06>;
+-			};
+-
+-			sataphy2clk: sataphy1clk@1f22c000 {
+-				compatible = "apm,xgene-device-clock";
+-				#clock-cells = <1>;
+-				clocks = <&socplldiv2 0>;
+-				reg = <0x0 0x1f22c000 0x0 0x1000>;
+-				reg-names = "csr-reg";
+-				clock-output-names = "sataphy2clk";
+-				status = "ok";
+-				csr-offset = <0x4>;
+-				csr-mask = <0x3a>;
+-				enable-offset = <0x0>;
+-				enable-mask = <0x06>;
+-			};
+-
+-			sataphy3clk: sataphy1clk@1f23c000 {
+-				compatible = "apm,xgene-device-clock";
+-				#clock-cells = <1>;
+-				clocks = <&socplldiv2 0>;
+-				reg = <0x0 0x1f23c000 0x0 0x1000>;
+-				reg-names = "csr-reg";
+-				clock-output-names = "sataphy3clk";
+-				status = "ok";
+-				csr-offset = <0x4>;
+-				csr-mask = <0x3a>;
+-				enable-offset = <0x0>;
+-				enable-mask = <0x06>;
+-			};
+-
+-			sata01clk: sata01clk@1f21c000 {
+-				compatible = "apm,xgene-device-clock";
+-				#clock-cells = <1>;
+-				clocks = <&socplldiv2 0>;
+-				reg = <0x0 0x1f21c000 0x0 0x1000>;
+-				reg-names = "csr-reg";
+-				clock-output-names = "sata01clk";
+-				csr-offset = <0x4>;
+-				csr-mask = <0x05>;
+-				enable-offset = <0x0>;
+-				enable-mask = <0x39>;
+-			};
+-
+-			sata23clk: sata23clk@1f22c000 {
+-				compatible = "apm,xgene-device-clock";
+-				#clock-cells = <1>;
+-				clocks = <&socplldiv2 0>;
+-				reg = <0x0 0x1f22c000 0x0 0x1000>;
+-				reg-names = "csr-reg";
+-				clock-output-names = "sata23clk";
+-				csr-offset = <0x4>;
+-				csr-mask = <0x05>;
+-				enable-offset = <0x0>;
+-				enable-mask = <0x39>;
+-			};
+-
+-			sata45clk: sata45clk@1f23c000 {
+-				compatible = "apm,xgene-device-clock";
+-				#clock-cells = <1>;
+-				clocks = <&socplldiv2 0>;
+-				reg = <0x0 0x1f23c000 0x0 0x1000>;
+-				reg-names = "csr-reg";
+-				clock-output-names = "sata45clk";
+-				csr-offset = <0x4>;
+-				csr-mask = <0x05>;
+-				enable-offset = <0x0>;
+-				enable-mask = <0x39>;
+-			};
+-
+-			rtcclk: rtcclk@17000000 {
+-				compatible = "apm,xgene-device-clock";
+-				#clock-cells = <1>;
+-				clocks = <&socplldiv2 0>;
+-				reg = <0x0 0x17000000 0x0 0x2000>;
+-				reg-names = "csr-reg";
+-				csr-offset = <0xc>;
+-				csr-mask = <0x2>;
+-				enable-offset = <0x10>;
+-				enable-mask = <0x2>;
+-				clock-output-names = "rtcclk";
+-			};
+-
+-			rngpkaclk: rngpkaclk@17000000 {
+-				compatible = "apm,xgene-device-clock";
+-				#clock-cells = <1>;
+-				clocks = <&socplldiv2 0>;
+-				reg = <0x0 0x17000000 0x0 0x2000>;
+-				reg-names = "csr-reg";
+-				csr-offset = <0xc>;
+-				csr-mask = <0x10>;
+-				enable-offset = <0x10>;
+-				enable-mask = <0x10>;
+-				clock-output-names = "rngpkaclk";
+-			};
+-
+-			pcie0clk: pcie0clk@1f2bc000 {
+-				status = "disabled";
+-				compatible = "apm,xgene-device-clock";
+-				#clock-cells = <1>;
+-				clocks = <&socplldiv2 0>;
+-				reg = <0x0 0x1f2bc000 0x0 0x1000>;
+-				reg-names = "csr-reg";
+-				clock-output-names = "pcie0clk";
+-			};
+-
+-			pcie1clk: pcie1clk@1f2cc000 {
+-				status = "disabled";
+-				compatible = "apm,xgene-device-clock";
+-				#clock-cells = <1>;
+-				clocks = <&socplldiv2 0>;
+-				reg = <0x0 0x1f2cc000 0x0 0x1000>;
+-				reg-names = "csr-reg";
+-				clock-output-names = "pcie1clk";
+-			};
+-
+-			pcie2clk: pcie2clk@1f2dc000 {
+-				status = "disabled";
+-				compatible = "apm,xgene-device-clock";
+-				#clock-cells = <1>;
+-				clocks = <&socplldiv2 0>;
+-				reg = <0x0 0x1f2dc000 0x0 0x1000>;
+-				reg-names = "csr-reg";
+-				clock-output-names = "pcie2clk";
+-			};
+-
+-			pcie3clk: pcie3clk@1f50c000 {
+-				status = "disabled";
+-				compatible = "apm,xgene-device-clock";
+-				#clock-cells = <1>;
+-				clocks = <&socplldiv2 0>;
+-				reg = <0x0 0x1f50c000 0x0 0x1000>;
+-				reg-names = "csr-reg";
+-				clock-output-names = "pcie3clk";
+-			};
+-
+-			pcie4clk: pcie4clk@1f51c000 {
+-				status = "disabled";
+-				compatible = "apm,xgene-device-clock";
+-				#clock-cells = <1>;
+-				clocks = <&socplldiv2 0>;
+-				reg = <0x0 0x1f51c000 0x0 0x1000>;
+-				reg-names = "csr-reg";
+-				clock-output-names = "pcie4clk";
+-			};
+-		};
+-
+-		pcie0: pcie@1f2b0000 {
+-			status = "disabled";
+-			device_type = "pci";
+-			compatible = "apm,xgene-storm-pcie", "apm,xgene-pcie";
+-			#interrupt-cells = <1>;
+-			#size-cells = <2>;
+-			#address-cells = <3>;
+-			reg = < 0x00 0x1f2b0000 0x0 0x00010000   /* Controller registers */
+-				0xe0 0xd0000000 0x0 0x00040000>; /* PCI config space */
+-			reg-names = "csr", "cfg";
+-			ranges = <0x01000000 0x00 0x00000000 0xe0 0x10000000 0x00 0x00010000   /* io */
+-				  0x02000000 0x00 0x80000000 0xe1 0x80000000 0x00 0x80000000>; /* mem */
+-			dma-ranges = <0x42000000 0x80 0x00000000 0x80 0x00000000 0x00 0x80000000
+-				      0x42000000 0x00 0x00000000 0x00 0x00000000 0x80 0x00000000>;
+-			interrupt-map-mask = <0x0 0x0 0x0 0x7>;
+-			interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xc2 0x1
+-					 0x0 0x0 0x0 0x2 &gic 0x0 0xc3 0x1
+-					 0x0 0x0 0x0 0x3 &gic 0x0 0xc4 0x1
+-					 0x0 0x0 0x0 0x4 &gic 0x0 0xc5 0x1>;
+-			dma-coherent;
+-			clocks = <&pcie0clk 0>;
+-		};
+-
+-		pcie1: pcie@1f2c0000 {
+-			status = "disabled";
+-			device_type = "pci";
+-			compatible = "apm,xgene-storm-pcie", "apm,xgene-pcie";
+-			#interrupt-cells = <1>;
+-			#size-cells = <2>;
+-			#address-cells = <3>;
+-			reg = < 0x00 0x1f2c0000 0x0 0x00010000   /* Controller registers */
+-				0xd0 0xd0000000 0x0 0x00040000>; /* PCI config space */
+-			reg-names = "csr", "cfg";
+-			ranges = <0x01000000 0x0 0x00000000 0xd0 0x10000000 0x00 0x00010000   /* io  */
+-				  0x02000000 0x0 0x80000000 0xd1 0x80000000 0x00 0x80000000>; /* mem */
+-			dma-ranges = <0x42000000 0x80 0x00000000 0x80 0x00000000 0x00 0x80000000
+-				      0x42000000 0x00 0x00000000 0x00 0x00000000 0x80 0x00000000>;
+-			interrupt-map-mask = <0x0 0x0 0x0 0x7>;
+-			interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xc8 0x1
+-					 0x0 0x0 0x0 0x2 &gic 0x0 0xc9 0x1
+-					 0x0 0x0 0x0 0x3 &gic 0x0 0xca 0x1
+-					 0x0 0x0 0x0 0x4 &gic 0x0 0xcb 0x1>;
+-			dma-coherent;
+-			clocks = <&pcie1clk 0>;
+-		};
+-
+-		pcie2: pcie@1f2d0000 {
+-			status = "disabled";
+-			device_type = "pci";
+-			compatible = "apm,xgene-storm-pcie", "apm,xgene-pcie";
+-			#interrupt-cells = <1>;
+-			#size-cells = <2>;
+-			#address-cells = <3>;
+-			reg =  < 0x00 0x1f2d0000 0x0 0x00010000   /* Controller registers */
+-				 0x90 0xd0000000 0x0 0x00040000>; /* PCI config space */
+-			reg-names = "csr", "cfg";
+-			ranges = <0x01000000 0x0 0x00000000 0x90 0x10000000 0x0 0x00010000   /* io  */
+-				  0x02000000 0x0 0x80000000 0x91 0x80000000 0x0 0x80000000>; /* mem */
+-			dma-ranges = <0x42000000 0x80 0x00000000 0x80 0x00000000 0x00 0x80000000
+-				      0x42000000 0x00 0x00000000 0x00 0x00000000 0x80 0x00000000>;
+-			interrupt-map-mask = <0x0 0x0 0x0 0x7>;
+-			interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xce 0x1
+-					 0x0 0x0 0x0 0x2 &gic 0x0 0xcf 0x1
+-					 0x0 0x0 0x0 0x3 &gic 0x0 0xd0 0x1
+-					 0x0 0x0 0x0 0x4 &gic 0x0 0xd1 0x1>;
+-			dma-coherent;
+-			clocks = <&pcie2clk 0>;
+-		};
+-
+-		pcie3: pcie@1f500000 {
+-			status = "disabled";
+-			device_type = "pci";
+-			compatible = "apm,xgene-storm-pcie", "apm,xgene-pcie";
+-			#interrupt-cells = <1>;
+-			#size-cells = <2>;
+-			#address-cells = <3>;
+-			reg = < 0x00 0x1f500000 0x0 0x00010000   /* Controller registers */
+-				0xa0 0xd0000000 0x0 0x00040000>; /* PCI config space */
+-			reg-names = "csr", "cfg";
+-			ranges = <0x01000000 0x0 0x00000000 0xa0 0x10000000 0x0 0x00010000   /* io   */
+-				  0x02000000 0x0 0x80000000 0xa1 0x80000000 0x0 0x80000000>; /* mem  */
+-			dma-ranges = <0x42000000 0x80 0x00000000 0x80 0x00000000 0x00 0x80000000
+-				      0x42000000 0x00 0x00000000 0x00 0x00000000 0x80 0x00000000>;
+-			interrupt-map-mask = <0x0 0x0 0x0 0x7>;
+-			interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xd4 0x1
+-					 0x0 0x0 0x0 0x2 &gic 0x0 0xd5 0x1
+-					 0x0 0x0 0x0 0x3 &gic 0x0 0xd6 0x1
+-					 0x0 0x0 0x0 0x4 &gic 0x0 0xd7 0x1>;
+-			dma-coherent;
+-			clocks = <&pcie3clk 0>;
+-		};
+-
+-		pcie4: pcie@1f510000 {
+-			status = "disabled";
+-			device_type = "pci";
+-			compatible = "apm,xgene-storm-pcie", "apm,xgene-pcie";
+-			#interrupt-cells = <1>;
+-			#size-cells = <2>;
+-			#address-cells = <3>;
+-			reg = < 0x00 0x1f510000 0x0 0x00010000   /* Controller registers */
+-				0xc0 0xd0000000 0x0 0x00200000>; /* PCI config space */
+-			reg-names = "csr", "cfg";
+-			ranges = <0x01000000 0x0 0x00000000 0xc0 0x10000000 0x0 0x00010000   /* io  */
+-				  0x02000000 0x0 0x80000000 0xc1 0x80000000 0x0 0x80000000>; /* mem */
+-			dma-ranges = <0x42000000 0x80 0x00000000 0x80 0x00000000 0x00 0x80000000
+-				      0x42000000 0x00 0x00000000 0x00 0x00000000 0x80 0x00000000>;
+-			interrupt-map-mask = <0x0 0x0 0x0 0x7>;
+-			interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xda 0x1
+-					 0x0 0x0 0x0 0x2 &gic 0x0 0xdb 0x1
+-					 0x0 0x0 0x0 0x3 &gic 0x0 0xdc 0x1
+-					 0x0 0x0 0x0 0x4 &gic 0x0 0xdd 0x1>;
+-			dma-coherent;
+-			clocks = <&pcie4clk 0>;
+-		};
+-
+-		serial0: serial@1c020000 {
+-			status = "disabled";
+-			device_type = "serial";
+-			compatible = "ns16550a";
+-			reg = <0 0x1c020000 0x0 0x1000>;
+-			reg-shift = <2>;
+-			clock-frequency = <10000000>; /* Updated by bootloader */
+-			interrupt-parent = <&gic>;
+-			interrupts = <0x0 0x4c 0x4>;
+-		};
+-
+-		serial1: serial@1c021000 {
+-			status = "disabled";
+-			device_type = "serial";
+-			compatible = "ns16550a";
+-			reg = <0 0x1c021000 0x0 0x1000>;
+-			reg-shift = <2>;
+-			clock-frequency = <10000000>; /* Updated by bootloader */
+-			interrupt-parent = <&gic>;
+-			interrupts = <0x0 0x4d 0x4>;
+-		};
+-
+-		serial2: serial@1c022000 {
+-			status = "disabled";
+-			device_type = "serial";
+-			compatible = "ns16550a";
+-			reg = <0 0x1c022000 0x0 0x1000>;
+-			reg-shift = <2>;
+-			clock-frequency = <10000000>; /* Updated by bootloader */
+-			interrupt-parent = <&gic>;
+-			interrupts = <0x0 0x4e 0x4>;
+-		};
+-
+-		serial3: serial@1c023000 {
+-			status = "disabled";
+-			device_type = "serial";
+-			compatible = "ns16550a";
+-			reg = <0 0x1c023000 0x0 0x1000>;
+-			reg-shift = <2>;
+-			clock-frequency = <10000000>; /* Updated by bootloader */
+-			interrupt-parent = <&gic>;
+-			interrupts = <0x0 0x4f 0x4>;
+-		};
+-
+-		phy1: phy@1f21a000 {
+-			compatible = "apm,xgene-phy";
+-			reg = <0x0 0x1f21a000 0x0 0x100>;
+-			#phy-cells = <1>;
+-			clocks = <&sataphy1clk 0>;
+-			status = "disabled";
+-			apm,tx-boost-gain = <30 30 30 30 30 30>;
+-			apm,tx-eye-tuning = <2 10 10 2 10 10>;
+-		};
+-
+-		phy2: phy@1f22a000 {
+-			compatible = "apm,xgene-phy";
+-			reg = <0x0 0x1f22a000 0x0 0x100>;
+-			#phy-cells = <1>;
+-			clocks = <&sataphy2clk 0>;
+-			status = "ok";
+-			apm,tx-boost-gain = <30 30 30 30 30 30>;
+-			apm,tx-eye-tuning = <1 10 10 2 10 10>;
+-		};
+-
+-		phy3: phy@1f23a000 {
+-			compatible = "apm,xgene-phy";
+-			reg = <0x0 0x1f23a000 0x0 0x100>;
+-			#phy-cells = <1>;
+-			clocks = <&sataphy3clk 0>;
+-			status = "ok";
+-			apm,tx-boost-gain = <31 31 31 31 31 31>;
+-			apm,tx-eye-tuning = <2 10 10 2 10 10>;
+-		};
+-
+-		sata1: sata@1a000000 {
+-			compatible = "apm,xgene-ahci";
+-			reg = <0x0 0x1a000000 0x0 0x1000>,
+-			      <0x0 0x1f210000 0x0 0x1000>,
+-			      <0x0 0x1f21d000 0x0 0x1000>,
+-			      <0x0 0x1f21e000 0x0 0x1000>,
+-			      <0x0 0x1f217000 0x0 0x1000>;
+-			interrupts = <0x0 0x86 0x4>;
+-			dma-coherent;
+-			status = "disabled";
+-			clocks = <&sata01clk 0>;
+-			phys = <&phy1 0>;
+-			phy-names = "sata-phy";
+-		};
+-
+-		sata2: sata@1a400000 {
+-			compatible = "apm,xgene-ahci";
+-			reg = <0x0 0x1a400000 0x0 0x1000>,
+-			      <0x0 0x1f220000 0x0 0x1000>,
+-			      <0x0 0x1f22d000 0x0 0x1000>,
+-			      <0x0 0x1f22e000 0x0 0x1000>,
+-			      <0x0 0x1f227000 0x0 0x1000>;
+-			interrupts = <0x0 0x87 0x4>;
+-			dma-coherent;
+-			status = "ok";
+-			clocks = <&sata23clk 0>;
+-			phys = <&phy2 0>;
+-			phy-names = "sata-phy";
+-		};
+-
+-		sata3: sata@1a800000 {
+-			compatible = "apm,xgene-ahci";
+-			reg = <0x0 0x1a800000 0x0 0x1000>,
+-			      <0x0 0x1f230000 0x0 0x1000>,
+-			      <0x0 0x1f23d000 0x0 0x1000>,
+-			      <0x0 0x1f23e000 0x0 0x1000>;
+-			interrupts = <0x0 0x88 0x4>;
+-			dma-coherent;
+-			status = "ok";
+-			clocks = <&sata45clk 0>;
+-			phys = <&phy3 0>;
+-			phy-names = "sata-phy";
+-		};
+-
+-		rtc: rtc@10510000 {
+-			compatible = "apm,xgene-rtc";
+-			reg = <0x0 0x10510000 0x0 0x400>;
+-			interrupts = <0x0 0x46 0x4>;
+-			#clock-cells = <1>;
+-			clocks = <&rtcclk 0>;
+-		};
+-
+-		menet: ethernet@17020000 {
+-			compatible = "apm,xgene-enet";
+-			status = "disabled";
+-			reg = <0x0 0x17020000 0x0 0xd100>,
+-			      <0x0 0X17030000 0x0 0Xc300>,
+-			      <0x0 0X10000000 0x0 0X200>;
+-			reg-names = "enet_csr", "ring_csr", "ring_cmd";
+-			interrupts = <0x0 0x3c 0x4>;
+-			dma-coherent;
+-			clocks = <&menetclk 0>;
+-			/* mac address will be overwritten by the bootloader */
+-			local-mac-address = [00 00 00 00 00 00];
+-			phy-connection-type = "rgmii";
+-			phy-handle = <&menetphy>;
+-			mdio {
+-				compatible = "apm,xgene-mdio";
+-				#address-cells = <1>;
+-				#size-cells = <0>;
+-				menetphy: menetphy@3 {
+-					compatible = "ethernet-phy-id001c.c915";
+-					reg = <0x3>;
+-				};
+-
+-			};
+-		};
+-
+-		sgenet0: ethernet@1f210000 {
+-			compatible = "apm,xgene-enet";
+-			status = "disabled";
+-			reg = <0x0 0x1f210000 0x0 0xd100>,
+-			      <0x0 0x1f200000 0x0 0Xc300>,
+-			      <0x0 0x1B000000 0x0 0X200>;
+-			reg-names = "enet_csr", "ring_csr", "ring_cmd";
+-			interrupts = <0x0 0xA0 0x4>;
+-			dma-coherent;
+-			clocks = <&sge0clk 0>;
+-			local-mac-address = [00 00 00 00 00 00];
+-			phy-connection-type = "sgmii";
+-		};
+-
+-		xgenet: ethernet@1f610000 {
+-			compatible = "apm,xgene-enet";
+-			status = "disabled";
+-			reg = <0x0 0x1f610000 0x0 0xd100>,
+-			      <0x0 0x1f600000 0x0 0Xc300>,
+-			      <0x0 0x18000000 0x0 0X200>;
+-			reg-names = "enet_csr", "ring_csr", "ring_cmd";
+-			interrupts = <0x0 0x60 0x4>;
+-			dma-coherent;
+-			clocks = <&xge0clk 0>;
+-			/* mac address will be overwritten by the bootloader */
+-			local-mac-address = [00 00 00 00 00 00];
+-			phy-connection-type = "xgmii";
+-		};
+-
+-		rng: rng@10520000 {
+-			compatible = "apm,xgene-rng";
+-			reg = <0x0 0x10520000 0x0 0x100>;
+-			interrupts = <0x0 0x41 0x4>;
+-			clocks = <&rngpkaclk 0>;
+-		};
+-	};
+-};
+diff --git a/arch/arm64/boot/dts/apm/Makefile b/arch/arm64/boot/dts/apm/Makefile
+new file mode 100644
+index 0000000..a2afabb
+--- /dev/null
++++ b/arch/arm64/boot/dts/apm/Makefile
+@@ -0,0 +1,5 @@
++dtb-$(CONFIG_ARCH_XGENE) += apm-mustang.dtb
++
++always		:= $(dtb-y)
++subdir-y	:= $(dts-dirs)
++clean-files	:= *.dtb
+diff --git a/arch/arm64/boot/dts/apm/apm-mustang.dts b/arch/arm64/boot/dts/apm/apm-mustang.dts
+new file mode 100644
+index 0000000..2e25de0
+--- /dev/null
++++ b/arch/arm64/boot/dts/apm/apm-mustang.dts
+@@ -0,0 +1,50 @@
++/*
++ * dts file for AppliedMicro (APM) Mustang Board
++ *
++ * Copyright (C) 2013, Applied Micro Circuits Corporation
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation; either version 2 of
++ * the License, or (at your option) any later version.
++ */
++
++/dts-v1/;
++
++/include/ "apm-storm.dtsi"
++
++/ {
++	model = "APM X-Gene Mustang board";
++	compatible = "apm,mustang", "apm,xgene-storm";
++
++	chosen { };
++
++	memory {
++		device_type = "memory";
++		reg = < 0x1 0x00000000 0x0 0x80000000 >; /* Updated by bootloader */
++	};
++};
++
++&pcie0clk {
++	status = "ok";
++};
++
++&pcie0 {
++	status = "ok";
++};
++
++&serial0 {
++	status = "ok";
++};
++
++&menet {
++	status = "ok";
++};
++
++&sgenet0 {
++	status = "ok";
++};
++
++&xgenet {
++	status = "ok";
++};
+diff --git a/arch/arm64/boot/dts/apm/apm-storm.dtsi b/arch/arm64/boot/dts/apm/apm-storm.dtsi
+new file mode 100644
+index 0000000..f1ad9c2
+--- /dev/null
++++ b/arch/arm64/boot/dts/apm/apm-storm.dtsi
+@@ -0,0 +1,660 @@
++/*
++ * dts file for AppliedMicro (APM) X-Gene Storm SOC
++ *
++ * Copyright (C) 2013, Applied Micro Circuits Corporation
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation; either version 2 of
++ * the License, or (at your option) any later version.
++ */
++
++/ {
++	compatible = "apm,xgene-storm";
++	interrupt-parent = <&gic>;
++	#address-cells = <2>;
++	#size-cells = <2>;
++
++	cpus {
++		#address-cells = <2>;
++		#size-cells = <0>;
++
++		cpu@000 {
++			device_type = "cpu";
++			compatible = "apm,potenza", "arm,armv8";
++			reg = <0x0 0x000>;
++			enable-method = "spin-table";
++			cpu-release-addr = <0x1 0x0000fff8>;
++		};
++		cpu@001 {
++			device_type = "cpu";
++			compatible = "apm,potenza", "arm,armv8";
++			reg = <0x0 0x001>;
++			enable-method = "spin-table";
++			cpu-release-addr = <0x1 0x0000fff8>;
++		};
++		cpu@100 {
++			device_type = "cpu";
++			compatible = "apm,potenza", "arm,armv8";
++			reg = <0x0 0x100>;
++			enable-method = "spin-table";
++			cpu-release-addr = <0x1 0x0000fff8>;
++		};
++		cpu@101 {
++			device_type = "cpu";
++			compatible = "apm,potenza", "arm,armv8";
++			reg = <0x0 0x101>;
++			enable-method = "spin-table";
++			cpu-release-addr = <0x1 0x0000fff8>;
++		};
++		cpu@200 {
++			device_type = "cpu";
++			compatible = "apm,potenza", "arm,armv8";
++			reg = <0x0 0x200>;
++			enable-method = "spin-table";
++			cpu-release-addr = <0x1 0x0000fff8>;
++		};
++		cpu@201 {
++			device_type = "cpu";
++			compatible = "apm,potenza", "arm,armv8";
++			reg = <0x0 0x201>;
++			enable-method = "spin-table";
++			cpu-release-addr = <0x1 0x0000fff8>;
++		};
++		cpu@300 {
++			device_type = "cpu";
++			compatible = "apm,potenza", "arm,armv8";
++			reg = <0x0 0x300>;
++			enable-method = "spin-table";
++			cpu-release-addr = <0x1 0x0000fff8>;
++		};
++		cpu@301 {
++			device_type = "cpu";
++			compatible = "apm,potenza", "arm,armv8";
++			reg = <0x0 0x301>;
++			enable-method = "spin-table";
++			cpu-release-addr = <0x1 0x0000fff8>;
++		};
++	};
++
++	gic: interrupt-controller@78010000 {
++		compatible = "arm,cortex-a15-gic";
++		#interrupt-cells = <3>;
++		interrupt-controller;
++		reg = <0x0 0x78010000 0x0 0x1000>,	/* GIC Dist */
++		      <0x0 0x78020000 0x0 0x1000>,	/* GIC CPU */
++		      <0x0 0x78040000 0x0 0x2000>,	/* GIC VCPU Control */
++		      <0x0 0x78060000 0x0 0x2000>;	/* GIC VCPU */
++		interrupts = <1 9 0xf04>;	/* GIC Maintenence IRQ */
++	};
++
++	timer {
++		compatible = "arm,armv8-timer";
++		interrupts = <1 0 0xff01>,	/* Secure Phys IRQ */
++			     <1 13 0xff01>,	/* Non-secure Phys IRQ */
++			     <1 14 0xff01>,	/* Virt IRQ */
++			     <1 15 0xff01>;	/* Hyp IRQ */
++		clock-frequency = <50000000>;
++	};
++
++	soc {
++		compatible = "simple-bus";
++		#address-cells = <2>;
++		#size-cells = <2>;
++		ranges;
++
++		clocks {
++			#address-cells = <2>;
++			#size-cells = <2>;
++			ranges;
++			refclk: refclk {
++				compatible = "fixed-clock";
++				#clock-cells = <1>;
++				clock-frequency = <100000000>;
++				clock-output-names = "refclk";
++			};
++
++			pcppll: pcppll@17000100 {
++				compatible = "apm,xgene-pcppll-clock";
++				#clock-cells = <1>;
++				clocks = <&refclk 0>;
++				clock-names = "pcppll";
++				reg = <0x0 0x17000100 0x0 0x1000>;
++				clock-output-names = "pcppll";
++				type = <0>;
++			};
++
++			socpll: socpll@17000120 {
++				compatible = "apm,xgene-socpll-clock";
++				#clock-cells = <1>;
++				clocks = <&refclk 0>;
++				clock-names = "socpll";
++				reg = <0x0 0x17000120 0x0 0x1000>;
++				clock-output-names = "socpll";
++				type = <1>;
++			};
++
++			socplldiv2: socplldiv2  {
++				compatible = "fixed-factor-clock";
++				#clock-cells = <1>;
++				clocks = <&socpll 0>;
++				clock-names = "socplldiv2";
++				clock-mult = <1>;
++				clock-div = <2>;
++				clock-output-names = "socplldiv2";
++			};
++
++			qmlclk: qmlclk {
++				compatible = "apm,xgene-device-clock";
++				#clock-cells = <1>;
++				clocks = <&socplldiv2 0>;
++				clock-names = "qmlclk";
++				reg = <0x0 0x1703C000 0x0 0x1000>;
++				reg-names = "csr-reg";
++				clock-output-names = "qmlclk";
++			};
++
++			ethclk: ethclk {
++				compatible = "apm,xgene-device-clock";
++				#clock-cells = <1>;
++				clocks = <&socplldiv2 0>;
++				clock-names = "ethclk";
++				reg = <0x0 0x17000000 0x0 0x1000>;
++				reg-names = "div-reg";
++				divider-offset = <0x238>;
++				divider-width = <0x9>;
++				divider-shift = <0x0>;
++				clock-output-names = "ethclk";
++			};
++
++			menetclk: menetclk {
++				compatible = "apm,xgene-device-clock";
++				#clock-cells = <1>;
++				clocks = <&ethclk 0>;
++				reg = <0x0 0x1702C000 0x0 0x1000>;
++				reg-names = "csr-reg";
++				clock-output-names = "menetclk";
++			};
++
++			sge0clk: sge0clk@1f21c000 {
++				compatible = "apm,xgene-device-clock";
++				#clock-cells = <1>;
++				clocks = <&socplldiv2 0>;
++				reg = <0x0 0x1f21c000 0x0 0x1000>;
++				reg-names = "csr-reg";
++				csr-mask = <0x3>;
++				clock-output-names = "sge0clk";
++			};
++
++			xge0clk: xge0clk@1f61c000 {
++				compatible = "apm,xgene-device-clock";
++				#clock-cells = <1>;
++				clocks = <&socplldiv2 0>;
++				reg = <0x0 0x1f61c000 0x0 0x1000>;
++				reg-names = "csr-reg";
++				csr-mask = <0x3>;
++				clock-output-names = "xge0clk";
++			};
++
++			sataphy1clk: sataphy1clk@1f21c000 {
++				compatible = "apm,xgene-device-clock";
++				#clock-cells = <1>;
++				clocks = <&socplldiv2 0>;
++				reg = <0x0 0x1f21c000 0x0 0x1000>;
++				reg-names = "csr-reg";
++				clock-output-names = "sataphy1clk";
++				status = "disabled";
++				csr-offset = <0x4>;
++				csr-mask = <0x00>;
++				enable-offset = <0x0>;
++				enable-mask = <0x06>;
++			};
++
++			sataphy2clk: sataphy1clk@1f22c000 {
++				compatible = "apm,xgene-device-clock";
++				#clock-cells = <1>;
++				clocks = <&socplldiv2 0>;
++				reg = <0x0 0x1f22c000 0x0 0x1000>;
++				reg-names = "csr-reg";
++				clock-output-names = "sataphy2clk";
++				status = "ok";
++				csr-offset = <0x4>;
++				csr-mask = <0x3a>;
++				enable-offset = <0x0>;
++				enable-mask = <0x06>;
++			};
++
++			sataphy3clk: sataphy1clk@1f23c000 {
++				compatible = "apm,xgene-device-clock";
++				#clock-cells = <1>;
++				clocks = <&socplldiv2 0>;
++				reg = <0x0 0x1f23c000 0x0 0x1000>;
++				reg-names = "csr-reg";
++				clock-output-names = "sataphy3clk";
++				status = "ok";
++				csr-offset = <0x4>;
++				csr-mask = <0x3a>;
++				enable-offset = <0x0>;
++				enable-mask = <0x06>;
++			};
++
++			sata01clk: sata01clk@1f21c000 {
++				compatible = "apm,xgene-device-clock";
++				#clock-cells = <1>;
++				clocks = <&socplldiv2 0>;
++				reg = <0x0 0x1f21c000 0x0 0x1000>;
++				reg-names = "csr-reg";
++				clock-output-names = "sata01clk";
++				csr-offset = <0x4>;
++				csr-mask = <0x05>;
++				enable-offset = <0x0>;
++				enable-mask = <0x39>;
++			};
++
++			sata23clk: sata23clk@1f22c000 {
++				compatible = "apm,xgene-device-clock";
++				#clock-cells = <1>;
++				clocks = <&socplldiv2 0>;
++				reg = <0x0 0x1f22c000 0x0 0x1000>;
++				reg-names = "csr-reg";
++				clock-output-names = "sata23clk";
++				csr-offset = <0x4>;
++				csr-mask = <0x05>;
++				enable-offset = <0x0>;
++				enable-mask = <0x39>;
++			};
++
++			sata45clk: sata45clk@1f23c000 {
++				compatible = "apm,xgene-device-clock";
++				#clock-cells = <1>;
++				clocks = <&socplldiv2 0>;
++				reg = <0x0 0x1f23c000 0x0 0x1000>;
++				reg-names = "csr-reg";
++				clock-output-names = "sata45clk";
++				csr-offset = <0x4>;
++				csr-mask = <0x05>;
++				enable-offset = <0x0>;
++				enable-mask = <0x39>;
++			};
++
++			rtcclk: rtcclk@17000000 {
++				compatible = "apm,xgene-device-clock";
++				#clock-cells = <1>;
++				clocks = <&socplldiv2 0>;
++				reg = <0x0 0x17000000 0x0 0x2000>;
++				reg-names = "csr-reg";
++				csr-offset = <0xc>;
++				csr-mask = <0x2>;
++				enable-offset = <0x10>;
++				enable-mask = <0x2>;
++				clock-output-names = "rtcclk";
++			};
++
++			rngpkaclk: rngpkaclk@17000000 {
++				compatible = "apm,xgene-device-clock";
++				#clock-cells = <1>;
++				clocks = <&socplldiv2 0>;
++				reg = <0x0 0x17000000 0x0 0x2000>;
++				reg-names = "csr-reg";
++				csr-offset = <0xc>;
++				csr-mask = <0x10>;
++				enable-offset = <0x10>;
++				enable-mask = <0x10>;
++				clock-output-names = "rngpkaclk";
++			};
++
++			pcie0clk: pcie0clk@1f2bc000 {
++				status = "disabled";
++				compatible = "apm,xgene-device-clock";
++				#clock-cells = <1>;
++				clocks = <&socplldiv2 0>;
++				reg = <0x0 0x1f2bc000 0x0 0x1000>;
++				reg-names = "csr-reg";
++				clock-output-names = "pcie0clk";
++			};
++
++			pcie1clk: pcie1clk@1f2cc000 {
++				status = "disabled";
++				compatible = "apm,xgene-device-clock";
++				#clock-cells = <1>;
++				clocks = <&socplldiv2 0>;
++				reg = <0x0 0x1f2cc000 0x0 0x1000>;
++				reg-names = "csr-reg";
++				clock-output-names = "pcie1clk";
++			};
++
++			pcie2clk: pcie2clk@1f2dc000 {
++				status = "disabled";
++				compatible = "apm,xgene-device-clock";
++				#clock-cells = <1>;
++				clocks = <&socplldiv2 0>;
++				reg = <0x0 0x1f2dc000 0x0 0x1000>;
++				reg-names = "csr-reg";
++				clock-output-names = "pcie2clk";
++			};
++
++			pcie3clk: pcie3clk@1f50c000 {
++				status = "disabled";
++				compatible = "apm,xgene-device-clock";
++				#clock-cells = <1>;
++				clocks = <&socplldiv2 0>;
++				reg = <0x0 0x1f50c000 0x0 0x1000>;
++				reg-names = "csr-reg";
++				clock-output-names = "pcie3clk";
++			};
++
++			pcie4clk: pcie4clk@1f51c000 {
++				status = "disabled";
++				compatible = "apm,xgene-device-clock";
++				#clock-cells = <1>;
++				clocks = <&socplldiv2 0>;
++				reg = <0x0 0x1f51c000 0x0 0x1000>;
++				reg-names = "csr-reg";
++				clock-output-names = "pcie4clk";
++			};
++		};
++
++		pcie0: pcie@1f2b0000 {
++			status = "disabled";
++			device_type = "pci";
++			compatible = "apm,xgene-storm-pcie", "apm,xgene-pcie";
++			#interrupt-cells = <1>;
++			#size-cells = <2>;
++			#address-cells = <3>;
++			reg = < 0x00 0x1f2b0000 0x0 0x00010000   /* Controller registers */
++				0xe0 0xd0000000 0x0 0x00040000>; /* PCI config space */
++			reg-names = "csr", "cfg";
++			ranges = <0x01000000 0x00 0x00000000 0xe0 0x10000000 0x00 0x00010000   /* io */
++				  0x02000000 0x00 0x80000000 0xe1 0x80000000 0x00 0x80000000>; /* mem */
++			dma-ranges = <0x42000000 0x80 0x00000000 0x80 0x00000000 0x00 0x80000000
++				      0x42000000 0x00 0x00000000 0x00 0x00000000 0x80 0x00000000>;
++			interrupt-map-mask = <0x0 0x0 0x0 0x7>;
++			interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xc2 0x1
++					 0x0 0x0 0x0 0x2 &gic 0x0 0xc3 0x1
++					 0x0 0x0 0x0 0x3 &gic 0x0 0xc4 0x1
++					 0x0 0x0 0x0 0x4 &gic 0x0 0xc5 0x1>;
++			dma-coherent;
++			clocks = <&pcie0clk 0>;
++		};
++
++		pcie1: pcie@1f2c0000 {
++			status = "disabled";
++			device_type = "pci";
++			compatible = "apm,xgene-storm-pcie", "apm,xgene-pcie";
++			#interrupt-cells = <1>;
++			#size-cells = <2>;
++			#address-cells = <3>;
++			reg = < 0x00 0x1f2c0000 0x0 0x00010000   /* Controller registers */
++				0xd0 0xd0000000 0x0 0x00040000>; /* PCI config space */
++			reg-names = "csr", "cfg";
++			ranges = <0x01000000 0x0 0x00000000 0xd0 0x10000000 0x00 0x00010000   /* io  */
++				  0x02000000 0x0 0x80000000 0xd1 0x80000000 0x00 0x80000000>; /* mem */
++			dma-ranges = <0x42000000 0x80 0x00000000 0x80 0x00000000 0x00 0x80000000
++				      0x42000000 0x00 0x00000000 0x00 0x00000000 0x80 0x00000000>;
++			interrupt-map-mask = <0x0 0x0 0x0 0x7>;
++			interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xc8 0x1
++					 0x0 0x0 0x0 0x2 &gic 0x0 0xc9 0x1
++					 0x0 0x0 0x0 0x3 &gic 0x0 0xca 0x1
++					 0x0 0x0 0x0 0x4 &gic 0x0 0xcb 0x1>;
++			dma-coherent;
++			clocks = <&pcie1clk 0>;
++		};
++
++		pcie2: pcie@1f2d0000 {
++			status = "disabled";
++			device_type = "pci";
++			compatible = "apm,xgene-storm-pcie", "apm,xgene-pcie";
++			#interrupt-cells = <1>;
++			#size-cells = <2>;
++			#address-cells = <3>;
++			reg =  < 0x00 0x1f2d0000 0x0 0x00010000   /* Controller registers */
++				 0x90 0xd0000000 0x0 0x00040000>; /* PCI config space */
++			reg-names = "csr", "cfg";
++			ranges = <0x01000000 0x0 0x00000000 0x90 0x10000000 0x0 0x00010000   /* io  */
++				  0x02000000 0x0 0x80000000 0x91 0x80000000 0x0 0x80000000>; /* mem */
++			dma-ranges = <0x42000000 0x80 0x00000000 0x80 0x00000000 0x00 0x80000000
++				      0x42000000 0x00 0x00000000 0x00 0x00000000 0x80 0x00000000>;
++			interrupt-map-mask = <0x0 0x0 0x0 0x7>;
++			interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xce 0x1
++					 0x0 0x0 0x0 0x2 &gic 0x0 0xcf 0x1
++					 0x0 0x0 0x0 0x3 &gic 0x0 0xd0 0x1
++					 0x0 0x0 0x0 0x4 &gic 0x0 0xd1 0x1>;
++			dma-coherent;
++			clocks = <&pcie2clk 0>;
++		};
++
++		pcie3: pcie@1f500000 {
++			status = "disabled";
++			device_type = "pci";
++			compatible = "apm,xgene-storm-pcie", "apm,xgene-pcie";
++			#interrupt-cells = <1>;
++			#size-cells = <2>;
++			#address-cells = <3>;
++			reg = < 0x00 0x1f500000 0x0 0x00010000   /* Controller registers */
++				0xa0 0xd0000000 0x0 0x00040000>; /* PCI config space */
++			reg-names = "csr", "cfg";
++			ranges = <0x01000000 0x0 0x00000000 0xa0 0x10000000 0x0 0x00010000   /* io   */
++				  0x02000000 0x0 0x80000000 0xa1 0x80000000 0x0 0x80000000>; /* mem  */
++			dma-ranges = <0x42000000 0x80 0x00000000 0x80 0x00000000 0x00 0x80000000
++				      0x42000000 0x00 0x00000000 0x00 0x00000000 0x80 0x00000000>;
++			interrupt-map-mask = <0x0 0x0 0x0 0x7>;
++			interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xd4 0x1
++					 0x0 0x0 0x0 0x2 &gic 0x0 0xd5 0x1
++					 0x0 0x0 0x0 0x3 &gic 0x0 0xd6 0x1
++					 0x0 0x0 0x0 0x4 &gic 0x0 0xd7 0x1>;
++			dma-coherent;
++			clocks = <&pcie3clk 0>;
++		};
++
++		pcie4: pcie@1f510000 {
++			status = "disabled";
++			device_type = "pci";
++			compatible = "apm,xgene-storm-pcie", "apm,xgene-pcie";
++			#interrupt-cells = <1>;
++			#size-cells = <2>;
++			#address-cells = <3>;
++			reg = < 0x00 0x1f510000 0x0 0x00010000   /* Controller registers */
++				0xc0 0xd0000000 0x0 0x00200000>; /* PCI config space */
++			reg-names = "csr", "cfg";
++			ranges = <0x01000000 0x0 0x00000000 0xc0 0x10000000 0x0 0x00010000   /* io  */
++				  0x02000000 0x0 0x80000000 0xc1 0x80000000 0x0 0x80000000>; /* mem */
++			dma-ranges = <0x42000000 0x80 0x00000000 0x80 0x00000000 0x00 0x80000000
++				      0x42000000 0x00 0x00000000 0x00 0x00000000 0x80 0x00000000>;
++			interrupt-map-mask = <0x0 0x0 0x0 0x7>;
++			interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xda 0x1
++					 0x0 0x0 0x0 0x2 &gic 0x0 0xdb 0x1
++					 0x0 0x0 0x0 0x3 &gic 0x0 0xdc 0x1
++					 0x0 0x0 0x0 0x4 &gic 0x0 0xdd 0x1>;
++			dma-coherent;
++			clocks = <&pcie4clk 0>;
++		};
++
++		serial0: serial@1c020000 {
++			status = "disabled";
++			device_type = "serial";
++			compatible = "ns16550a";
++			reg = <0 0x1c020000 0x0 0x1000>;
++			reg-shift = <2>;
++			clock-frequency = <10000000>; /* Updated by bootloader */
++			interrupt-parent = <&gic>;
++			interrupts = <0x0 0x4c 0x4>;
++		};
++
++		serial1: serial@1c021000 {
++			status = "disabled";
++			device_type = "serial";
++			compatible = "ns16550a";
++			reg = <0 0x1c021000 0x0 0x1000>;
++			reg-shift = <2>;
++			clock-frequency = <10000000>; /* Updated by bootloader */
++			interrupt-parent = <&gic>;
++			interrupts = <0x0 0x4d 0x4>;
++		};
++
++		serial2: serial@1c022000 {
++			status = "disabled";
++			device_type = "serial";
++			compatible = "ns16550a";
++			reg = <0 0x1c022000 0x0 0x1000>;
++			reg-shift = <2>;
++			clock-frequency = <10000000>; /* Updated by bootloader */
++			interrupt-parent = <&gic>;
++			interrupts = <0x0 0x4e 0x4>;
++		};
++
++		serial3: serial@1c023000 {
++			status = "disabled";
++			device_type = "serial";
++			compatible = "ns16550a";
++			reg = <0 0x1c023000 0x0 0x1000>;
++			reg-shift = <2>;
++			clock-frequency = <10000000>; /* Updated by bootloader */
++			interrupt-parent = <&gic>;
++			interrupts = <0x0 0x4f 0x4>;
++		};
++
++		phy1: phy@1f21a000 {
++			compatible = "apm,xgene-phy";
++			reg = <0x0 0x1f21a000 0x0 0x100>;
++			#phy-cells = <1>;
++			clocks = <&sataphy1clk 0>;
++			status = "disabled";
++			apm,tx-boost-gain = <30 30 30 30 30 30>;
++			apm,tx-eye-tuning = <2 10 10 2 10 10>;
++		};
++
++		phy2: phy@1f22a000 {
++			compatible = "apm,xgene-phy";
++			reg = <0x0 0x1f22a000 0x0 0x100>;
++			#phy-cells = <1>;
++			clocks = <&sataphy2clk 0>;
++			status = "ok";
++			apm,tx-boost-gain = <30 30 30 30 30 30>;
++			apm,tx-eye-tuning = <1 10 10 2 10 10>;
++		};
++
++		phy3: phy@1f23a000 {
++			compatible = "apm,xgene-phy";
++			reg = <0x0 0x1f23a000 0x0 0x100>;
++			#phy-cells = <1>;
++			clocks = <&sataphy3clk 0>;
++			status = "ok";
++			apm,tx-boost-gain = <31 31 31 31 31 31>;
++			apm,tx-eye-tuning = <2 10 10 2 10 10>;
++		};
++
++		sata1: sata@1a000000 {
++			compatible = "apm,xgene-ahci";
++			reg = <0x0 0x1a000000 0x0 0x1000>,
++			      <0x0 0x1f210000 0x0 0x1000>,
++			      <0x0 0x1f21d000 0x0 0x1000>,
++			      <0x0 0x1f21e000 0x0 0x1000>,
++			      <0x0 0x1f217000 0x0 0x1000>;
++			interrupts = <0x0 0x86 0x4>;
++			dma-coherent;
++			status = "disabled";
++			clocks = <&sata01clk 0>;
++			phys = <&phy1 0>;
++			phy-names = "sata-phy";
++		};
++
++		sata2: sata@1a400000 {
++			compatible = "apm,xgene-ahci";
++			reg = <0x0 0x1a400000 0x0 0x1000>,
++			      <0x0 0x1f220000 0x0 0x1000>,
++			      <0x0 0x1f22d000 0x0 0x1000>,
++			      <0x0 0x1f22e000 0x0 0x1000>,
++			      <0x0 0x1f227000 0x0 0x1000>;
++			interrupts = <0x0 0x87 0x4>;
++			dma-coherent;
++			status = "ok";
++			clocks = <&sata23clk 0>;
++			phys = <&phy2 0>;
++			phy-names = "sata-phy";
++		};
++
++		sata3: sata@1a800000 {
++			compatible = "apm,xgene-ahci";
++			reg = <0x0 0x1a800000 0x0 0x1000>,
++			      <0x0 0x1f230000 0x0 0x1000>,
++			      <0x0 0x1f23d000 0x0 0x1000>,
++			      <0x0 0x1f23e000 0x0 0x1000>;
++			interrupts = <0x0 0x88 0x4>;
++			dma-coherent;
++			status = "ok";
++			clocks = <&sata45clk 0>;
++			phys = <&phy3 0>;
++			phy-names = "sata-phy";
++		};
++
++		rtc: rtc@10510000 {
++			compatible = "apm,xgene-rtc";
++			reg = <0x0 0x10510000 0x0 0x400>;
++			interrupts = <0x0 0x46 0x4>;
++			#clock-cells = <1>;
++			clocks = <&rtcclk 0>;
++		};
++
++		menet: ethernet@17020000 {
++			compatible = "apm,xgene-enet";
++			status = "disabled";
++			reg = <0x0 0x17020000 0x0 0xd100>,
++			      <0x0 0X17030000 0x0 0Xc300>,
++			      <0x0 0X10000000 0x0 0X200>;
++			reg-names = "enet_csr", "ring_csr", "ring_cmd";
++			interrupts = <0x0 0x3c 0x4>;
++			dma-coherent;
++			clocks = <&menetclk 0>;
++			/* mac address will be overwritten by the bootloader */
++			local-mac-address = [00 00 00 00 00 00];
++			phy-connection-type = "rgmii";
++			phy-handle = <&menetphy>;
++			mdio {
++				compatible = "apm,xgene-mdio";
++				#address-cells = <1>;
++				#size-cells = <0>;
++				menetphy: menetphy@3 {
++					compatible = "ethernet-phy-id001c.c915";
++					reg = <0x3>;
++				};
++
++			};
++		};
++
++		sgenet0: ethernet@1f210000 {
++			compatible = "apm,xgene-enet";
++			status = "disabled";
++			reg = <0x0 0x1f210000 0x0 0xd100>,
++			      <0x0 0x1f200000 0x0 0Xc300>,
++			      <0x0 0x1B000000 0x0 0X200>;
++			reg-names = "enet_csr", "ring_csr", "ring_cmd";
++			interrupts = <0x0 0xA0 0x4>;
++			dma-coherent;
++			clocks = <&sge0clk 0>;
++			local-mac-address = [00 00 00 00 00 00];
++			phy-connection-type = "sgmii";
++		};
++
++		xgenet: ethernet@1f610000 {
++			compatible = "apm,xgene-enet";
++			status = "disabled";
++			reg = <0x0 0x1f610000 0x0 0xd100>,
++			      <0x0 0x1f600000 0x0 0Xc300>,
++			      <0x0 0x18000000 0x0 0X200>;
++			reg-names = "enet_csr", "ring_csr", "ring_cmd";
++			interrupts = <0x0 0x60 0x4>;
++			dma-coherent;
++			clocks = <&xge0clk 0>;
++			/* mac address will be overwritten by the bootloader */
++			local-mac-address = [00 00 00 00 00 00];
++			phy-connection-type = "xgmii";
++		};
++
++		rng: rng@10520000 {
++			compatible = "apm,xgene-rng";
++			reg = <0x0 0x10520000 0x0 0x100>;
++			interrupts = <0x0 0x41 0x4>;
++			clocks = <&rngpkaclk 0>;
++		};
++	};
++};
+diff --git a/arch/arm64/boot/dts/arm/Makefile b/arch/arm64/boot/dts/arm/Makefile
+new file mode 100644
+index 0000000..301a0da
+--- /dev/null
++++ b/arch/arm64/boot/dts/arm/Makefile
+@@ -0,0 +1,7 @@
++dtb-$(CONFIG_ARCH_VEXPRESS) += foundation-v8.dtb
++dtb-$(CONFIG_ARCH_VEXPRESS) += juno.dtb
++dtb-$(CONFIG_ARCH_VEXPRESS) += rtsm_ve-aemv8a.dtb
++
++always		:= $(dtb-y)
++subdir-y	:= $(dts-dirs)
++clean-files	:= *.dtb
+diff --git a/arch/arm64/boot/dts/arm/foundation-v8.dts b/arch/arm64/boot/dts/arm/foundation-v8.dts
+new file mode 100644
+index 0000000..4eac8dc
+--- /dev/null
++++ b/arch/arm64/boot/dts/arm/foundation-v8.dts
+@@ -0,0 +1,240 @@
++/*
++ * ARM Ltd.
++ *
++ * ARMv8 Foundation model DTS
++ */
++
++/dts-v1/;
++
++/memreserve/ 0x80000000 0x00010000;
++
++/ {
++	model = "Foundation-v8A";
++	compatible = "arm,foundation-aarch64", "arm,vexpress";
++	interrupt-parent = <&gic>;
++	#address-cells = <2>;
++	#size-cells = <2>;
++
++	chosen { };
++
++	aliases {
++		serial0 = &v2m_serial0;
++		serial1 = &v2m_serial1;
++		serial2 = &v2m_serial2;
++		serial3 = &v2m_serial3;
++	};
++
++	cpus {
++		#address-cells = <2>;
++		#size-cells = <0>;
++
++		cpu@0 {
++			device_type = "cpu";
++			compatible = "arm,armv8";
++			reg = <0x0 0x0>;
++			enable-method = "spin-table";
++			cpu-release-addr = <0x0 0x8000fff8>;
++			next-level-cache = <&L2_0>;
++		};
++		cpu@1 {
++			device_type = "cpu";
++			compatible = "arm,armv8";
++			reg = <0x0 0x1>;
++			enable-method = "spin-table";
++			cpu-release-addr = <0x0 0x8000fff8>;
++			next-level-cache = <&L2_0>;
++		};
++		cpu@2 {
++			device_type = "cpu";
++			compatible = "arm,armv8";
++			reg = <0x0 0x2>;
++			enable-method = "spin-table";
++			cpu-release-addr = <0x0 0x8000fff8>;
++			next-level-cache = <&L2_0>;
++		};
++		cpu@3 {
++			device_type = "cpu";
++			compatible = "arm,armv8";
++			reg = <0x0 0x3>;
++			enable-method = "spin-table";
++			cpu-release-addr = <0x0 0x8000fff8>;
++			next-level-cache = <&L2_0>;
++		};
++
++		L2_0: l2-cache0 {
++			compatible = "cache";
++		};
++	};
++
++	memory@80000000 {
++		device_type = "memory";
++		reg = <0x00000000 0x80000000 0 0x80000000>,
++		      <0x00000008 0x80000000 0 0x80000000>;
++	};
++
++	gic: interrupt-controller@2c001000 {
++		compatible = "arm,cortex-a15-gic", "arm,cortex-a9-gic";
++		#interrupt-cells = <3>;
++		#address-cells = <0>;
++		interrupt-controller;
++		reg = <0x0 0x2c001000 0 0x1000>,
++		      <0x0 0x2c002000 0 0x1000>,
++		      <0x0 0x2c004000 0 0x2000>,
++		      <0x0 0x2c006000 0 0x2000>;
++		interrupts = <1 9 0xf04>;
++	};
++
++	timer {
++		compatible = "arm,armv8-timer";
++		interrupts = <1 13 0xf08>,
++			     <1 14 0xf08>,
++			     <1 11 0xf08>,
++			     <1 10 0xf08>;
++		clock-frequency = <100000000>;
++	};
++
++	pmu {
++		compatible = "arm,armv8-pmuv3";
++		interrupts = <0 60 4>,
++			     <0 61 4>,
++			     <0 62 4>,
++			     <0 63 4>;
++	};
++
++	smb {
++		compatible = "arm,vexpress,v2m-p1", "simple-bus";
++		arm,v2m-memory-map = "rs1";
++		#address-cells = <2>; /* SMB chipselect number and offset */
++		#size-cells = <1>;
++
++		ranges = <0 0 0 0x08000000 0x04000000>,
++			 <1 0 0 0x14000000 0x04000000>,
++			 <2 0 0 0x18000000 0x04000000>,
++			 <3 0 0 0x1c000000 0x04000000>,
++			 <4 0 0 0x0c000000 0x04000000>,
++			 <5 0 0 0x10000000 0x04000000>;
++
++		#interrupt-cells = <1>;
++		interrupt-map-mask = <0 0 63>;
++		interrupt-map = <0 0  0 &gic 0  0 4>,
++				<0 0  1 &gic 0  1 4>,
++				<0 0  2 &gic 0  2 4>,
++				<0 0  3 &gic 0  3 4>,
++				<0 0  4 &gic 0  4 4>,
++				<0 0  5 &gic 0  5 4>,
++				<0 0  6 &gic 0  6 4>,
++				<0 0  7 &gic 0  7 4>,
++				<0 0  8 &gic 0  8 4>,
++				<0 0  9 &gic 0  9 4>,
++				<0 0 10 &gic 0 10 4>,
++				<0 0 11 &gic 0 11 4>,
++				<0 0 12 &gic 0 12 4>,
++				<0 0 13 &gic 0 13 4>,
++				<0 0 14 &gic 0 14 4>,
++				<0 0 15 &gic 0 15 4>,
++				<0 0 16 &gic 0 16 4>,
++				<0 0 17 &gic 0 17 4>,
++				<0 0 18 &gic 0 18 4>,
++				<0 0 19 &gic 0 19 4>,
++				<0 0 20 &gic 0 20 4>,
++				<0 0 21 &gic 0 21 4>,
++				<0 0 22 &gic 0 22 4>,
++				<0 0 23 &gic 0 23 4>,
++				<0 0 24 &gic 0 24 4>,
++				<0 0 25 &gic 0 25 4>,
++				<0 0 26 &gic 0 26 4>,
++				<0 0 27 &gic 0 27 4>,
++				<0 0 28 &gic 0 28 4>,
++				<0 0 29 &gic 0 29 4>,
++				<0 0 30 &gic 0 30 4>,
++				<0 0 31 &gic 0 31 4>,
++				<0 0 32 &gic 0 32 4>,
++				<0 0 33 &gic 0 33 4>,
++				<0 0 34 &gic 0 34 4>,
++				<0 0 35 &gic 0 35 4>,
++				<0 0 36 &gic 0 36 4>,
++				<0 0 37 &gic 0 37 4>,
++				<0 0 38 &gic 0 38 4>,
++				<0 0 39 &gic 0 39 4>,
++				<0 0 40 &gic 0 40 4>,
++				<0 0 41 &gic 0 41 4>,
++				<0 0 42 &gic 0 42 4>;
++
++		ethernet@2,02000000 {
++			compatible = "smsc,lan91c111";
++			reg = <2 0x02000000 0x10000>;
++			interrupts = <15>;
++		};
++
++		v2m_clk24mhz: clk24mhz {
++			compatible = "fixed-clock";
++			#clock-cells = <0>;
++			clock-frequency = <24000000>;
++			clock-output-names = "v2m:clk24mhz";
++		};
++
++		v2m_refclk1mhz: refclk1mhz {
++			compatible = "fixed-clock";
++			#clock-cells = <0>;
++			clock-frequency = <1000000>;
++			clock-output-names = "v2m:refclk1mhz";
++		};
++
++		v2m_refclk32khz: refclk32khz {
++			compatible = "fixed-clock";
++			#clock-cells = <0>;
++			clock-frequency = <32768>;
++			clock-output-names = "v2m:refclk32khz";
++		};
++
++		iofpga@3,00000000 {
++			compatible = "arm,amba-bus", "simple-bus";
++			#address-cells = <1>;
++			#size-cells = <1>;
++			ranges = <0 3 0 0x200000>;
++
++			v2m_sysreg: sysreg@010000 {
++				compatible = "arm,vexpress-sysreg";
++				reg = <0x010000 0x1000>;
++			};
++
++			v2m_serial0: uart@090000 {
++				compatible = "arm,pl011", "arm,primecell";
++				reg = <0x090000 0x1000>;
++				interrupts = <5>;
++				clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
++				clock-names = "uartclk", "apb_pclk";
++			};
++
++			v2m_serial1: uart@0a0000 {
++				compatible = "arm,pl011", "arm,primecell";
++				reg = <0x0a0000 0x1000>;
++				interrupts = <6>;
++				clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
++				clock-names = "uartclk", "apb_pclk";
++			};
++
++			v2m_serial2: uart@0b0000 {
++				compatible = "arm,pl011", "arm,primecell";
++				reg = <0x0b0000 0x1000>;
++				interrupts = <7>;
++				clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
++				clock-names = "uartclk", "apb_pclk";
++			};
++
++			v2m_serial3: uart@0c0000 {
++				compatible = "arm,pl011", "arm,primecell";
++				reg = <0x0c0000 0x1000>;
++				interrupts = <8>;
++				clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
++				clock-names = "uartclk", "apb_pclk";
++			};
++
++			virtio_block@0130000 {
++				compatible = "virtio,mmio";
++				reg = <0x130000 0x200>;
++				interrupts = <42>;
++			};
++		};
++	};
++};
+diff --git a/arch/arm64/boot/dts/arm/juno-clocks.dtsi b/arch/arm64/boot/dts/arm/juno-clocks.dtsi
+new file mode 100644
+index 0000000..c9b89ef
+--- /dev/null
++++ b/arch/arm64/boot/dts/arm/juno-clocks.dtsi
+@@ -0,0 +1,44 @@
++/*
++ * ARM Juno Platform clocks
++ *
++ * Copyright (c) 2013-2014 ARM Ltd
++ *
++ * This file is licensed under a dual GPLv2 or BSD license.
++ *
++ */
++
++	/* SoC fixed clocks */
++	soc_uartclk: refclk7273800hz {
++		compatible = "fixed-clock";
++		#clock-cells = <0>;
++		clock-frequency = <7273800>;
++		clock-output-names = "juno:uartclk";
++	};
++
++	soc_usb48mhz: clk48mhz {
++		compatible = "fixed-clock";
++		#clock-cells = <0>;
++		clock-frequency = <48000000>;
++		clock-output-names = "clk48mhz";
++	};
++
++	soc_smc50mhz: clk50mhz {
++		compatible = "fixed-clock";
++		#clock-cells = <0>;
++		clock-frequency = <50000000>;
++		clock-output-names = "smc_clk";
++	};
++
++	soc_refclk100mhz: refclk100mhz {
++		compatible = "fixed-clock";
++		#clock-cells = <0>;
++		clock-frequency = <100000000>;
++		clock-output-names = "apb_pclk";
++	};
++
++	soc_faxiclk: refclk533mhz {
++		compatible = "fixed-clock";
++		#clock-cells = <0>;
++		clock-frequency = <533000000>;
++		clock-output-names = "faxi_clk";
++	};
+diff --git a/arch/arm64/boot/dts/arm/juno-motherboard.dtsi b/arch/arm64/boot/dts/arm/juno-motherboard.dtsi
+new file mode 100644
+index 0000000..c138b95
+--- /dev/null
++++ b/arch/arm64/boot/dts/arm/juno-motherboard.dtsi
+@@ -0,0 +1,129 @@
++/*
++ * ARM Juno Platform motherboard peripherals
++ *
++ * Copyright (c) 2013-2014 ARM Ltd
++ *
++ * This file is licensed under a dual GPLv2 or BSD license.
++ *
++ */
++
++		mb_clk24mhz: clk24mhz {
++			compatible = "fixed-clock";
++			#clock-cells = <0>;
++			clock-frequency = <24000000>;
++			clock-output-names = "juno_mb:clk24mhz";
++		};
++
++		mb_clk25mhz: clk25mhz {
++			compatible = "fixed-clock";
++			#clock-cells = <0>;
++			clock-frequency = <25000000>;
++			clock-output-names = "juno_mb:clk25mhz";
++		};
++
++		motherboard {
++			compatible = "arm,vexpress,v2p-p1", "simple-bus";
++			#address-cells = <2>;  /* SMB chipselect number and offset */
++			#size-cells = <1>;
++			#interrupt-cells = <1>;
++			ranges;
++			model = "V2M-Juno";
++			arm,hbi = <0x252>;
++			arm,vexpress,site = <0>;
++			arm,v2m-memory-map = "rs1";
++
++			mb_fixed_3v3: fixedregulator@0 {
++				compatible = "regulator-fixed";
++				regulator-name = "MCC_SB_3V3";
++				regulator-min-microvolt = <3300000>;
++				regulator-max-microvolt = <3300000>;
++				regulator-always-on;
++			};
++
++			ethernet@2,00000000 {
++				compatible = "smsc,lan9118", "smsc,lan9115";
++				reg = <2 0x00000000 0x10000>;
++				interrupts = <3>;
++				phy-mode = "mii";
++				reg-io-width = <4>;
++				smsc,irq-active-high;
++				smsc,irq-push-pull;
++				clocks = <&mb_clk25mhz>;
++				vdd33a-supply = <&mb_fixed_3v3>;
++				vddvario-supply = <&mb_fixed_3v3>;
++			};
++
++			usb@5,00000000 {
++				compatible = "nxp,usb-isp1763";
++				reg = <5 0x00000000 0x20000>;
++				bus-width = <16>;
++				interrupts = <4>;
++			};
++
++			iofpga@3,00000000 {
++				compatible = "arm,amba-bus", "simple-bus";
++				#address-cells = <1>;
++				#size-cells = <1>;
++				ranges = <0 3 0 0x200000>;
++
++				mmci@050000 {
++					compatible = "arm,pl180", "arm,primecell";
++					reg = <0x050000 0x1000>;
++					interrupts = <5>;
++					/* cd-gpios = <&v2m_mmc_gpios 0 0>;
++					wp-gpios = <&v2m_mmc_gpios 1 0>; */
++					max-frequency = <12000000>;
++					vmmc-supply = <&mb_fixed_3v3>;
++					clocks = <&mb_clk24mhz>, <&soc_smc50mhz>;
++					clock-names = "mclk", "apb_pclk";
++				};
++
++				kmi@060000 {
++					compatible = "arm,pl050", "arm,primecell";
++					reg = <0x060000 0x1000>;
++					interrupts = <8>;
++					clocks = <&mb_clk24mhz>, <&soc_smc50mhz>;
++					clock-names = "KMIREFCLK", "apb_pclk";
++				};
++
++				kmi@070000 {
++					compatible = "arm,pl050", "arm,primecell";
++					reg = <0x070000 0x1000>;
++					interrupts = <8>;
++					clocks = <&mb_clk24mhz>, <&soc_smc50mhz>;
++					clock-names = "KMIREFCLK", "apb_pclk";
++				};
++
++				wdt@0f0000 {
++					compatible = "arm,sp805", "arm,primecell";
++					reg = <0x0f0000 0x10000>;
++					interrupts = <7>;
++					clocks = <&mb_clk24mhz>, <&soc_smc50mhz>;
++					clock-names = "wdogclk", "apb_pclk";
++				};
++
++				v2m_timer01: timer@110000 {
++					compatible = "arm,sp804", "arm,primecell";
++					reg = <0x110000 0x10000>;
++					interrupts = <9>;
++					clocks = <&mb_clk24mhz>, <&soc_smc50mhz>;
++					clock-names = "timclken1", "apb_pclk";
++				};
++
++				v2m_timer23: timer@120000 {
++					compatible = "arm,sp804", "arm,primecell";
++					reg = <0x120000 0x10000>;
++					interrupts = <9>;
++					clocks = <&mb_clk24mhz>, <&soc_smc50mhz>;
++					clock-names = "timclken1", "apb_pclk";
++				};
++
++				rtc@170000 {
++					compatible = "arm,pl031", "arm,primecell";
++					reg = <0x170000 0x10000>;
++					interrupts = <0>;
++					clocks = <&soc_smc50mhz>;
++					clock-names = "apb_pclk";
++				};
++			};
++		};
+diff --git a/arch/arm64/boot/dts/arm/juno.dts b/arch/arm64/boot/dts/arm/juno.dts
+new file mode 100644
+index 0000000..5e9110a
+--- /dev/null
++++ b/arch/arm64/boot/dts/arm/juno.dts
+@@ -0,0 +1,238 @@
++/*
++ * ARM Ltd. Juno Platform
++ *
++ * Copyright (c) 2013-2014 ARM Ltd.
++ *
++ * This file is licensed under a dual GPLv2 or BSD license.
++ */
++
++/dts-v1/;
++
++#include <dt-bindings/interrupt-controller/arm-gic.h>
++
++/ {
++	model = "ARM Juno development board (r0)";
++	compatible = "arm,juno", "arm,vexpress";
++	interrupt-parent = <&gic>;
++	#address-cells = <2>;
++	#size-cells = <2>;
++
++	aliases {
++		serial0 = &soc_uart0;
++	};
++
++	chosen {
++		stdout-path = "serial0:115200n8";
++	};
++
++	psci {
++		compatible = "arm,psci-0.2";
++		method = "smc";
++	};
++
++	cpus {
++		#address-cells = <2>;
++		#size-cells = <0>;
++
++		A57_0: cpu@0 {
++			compatible = "arm,cortex-a57","arm,armv8";
++			reg = <0x0 0x0>;
++			device_type = "cpu";
++			enable-method = "psci";
++			next-level-cache = <&A57_L2>;
++		};
++
++		A57_1: cpu@1 {
++			compatible = "arm,cortex-a57","arm,armv8";
++			reg = <0x0 0x1>;
++			device_type = "cpu";
++			enable-method = "psci";
++			next-level-cache = <&A57_L2>;
++		};
++
++		A53_0: cpu@100 {
++			compatible = "arm,cortex-a53","arm,armv8";
++			reg = <0x0 0x100>;
++			device_type = "cpu";
++			enable-method = "psci";
++			next-level-cache = <&A53_L2>;
++		};
++
++		A53_1: cpu@101 {
++			compatible = "arm,cortex-a53","arm,armv8";
++			reg = <0x0 0x101>;
++			device_type = "cpu";
++			enable-method = "psci";
++			next-level-cache = <&A53_L2>;
++		};
++
++		A53_2: cpu@102 {
++			compatible = "arm,cortex-a53","arm,armv8";
++			reg = <0x0 0x102>;
++			device_type = "cpu";
++			enable-method = "psci";
++			next-level-cache = <&A53_L2>;
++		};
++
++		A53_3: cpu@103 {
++			compatible = "arm,cortex-a53","arm,armv8";
++			reg = <0x0 0x103>;
++			device_type = "cpu";
++			enable-method = "psci";
++			next-level-cache = <&A53_L2>;
++		};
++
++		A57_L2: l2-cache0 {
++			compatible = "cache";
++		};
++
++		A53_L2: l2-cache1 {
++			compatible = "cache";
++		};
++	};
++
++	memory@80000000 {
++		device_type = "memory";
++		/* last 16MB of the first memory area is reserved for secure world use by firmware */
++		reg = <0x00000000 0x80000000 0x0 0x7f000000>,
++		      <0x00000008 0x80000000 0x1 0x80000000>;
++	};
++
++	gic: interrupt-controller@2c001000 {
++		compatible = "arm,gic-400", "arm,cortex-a15-gic";
++		reg = <0x0 0x2c010000 0 0x1000>,
++		      <0x0 0x2c02f000 0 0x2000>,
++		      <0x0 0x2c04f000 0 0x2000>,
++		      <0x0 0x2c06f000 0 0x2000>;
++		#address-cells = <0>;
++		#interrupt-cells = <3>;
++		interrupt-controller;
++		interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_HIGH)>;
++	};
++
++	timer {
++		compatible = "arm,armv8-timer";
++		interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_LOW)>,
++			     <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_LOW)>,
++			     <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_LOW)>,
++			     <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_LOW)>;
++	};
++
++	pmu {
++		compatible = "arm,armv8-pmuv3";
++		interrupts = <GIC_SPI 02 IRQ_TYPE_LEVEL_HIGH>,
++			     <GIC_SPI 06 IRQ_TYPE_LEVEL_HIGH>,
++			     <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>,
++			     <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>,
++			     <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>,
++			     <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
++		interrupt-affinity = <&A57_0>,
++				     <&A57_1>,
++				     <&A53_0>,
++				     <&A53_1>,
++				     <&A53_2>,
++				     <&A53_3>;
++	};
++
++	/include/ "juno-clocks.dtsi"
++
++	dma@7ff00000 {
++		compatible = "arm,pl330", "arm,primecell";
++		reg = <0x0 0x7ff00000 0 0x1000>;
++		#dma-cells = <1>;
++		#dma-channels = <8>;
++		#dma-requests = <32>;
++		interrupts = <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>,
++			     <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>,
++			     <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>,
++			     <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>,
++			     <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>,
++			     <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>,
++			     <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>,
++			     <GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&soc_faxiclk>;
++		clock-names = "apb_pclk";
++	};
++
++	soc_uart0: uart@7ff80000 {
++		compatible = "arm,pl011", "arm,primecell";
++		reg = <0x0 0x7ff80000 0x0 0x1000>;
++		interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&soc_uartclk>, <&soc_refclk100mhz>;
++		clock-names = "uartclk", "apb_pclk";
++	};
++
++	i2c@7ffa0000 {
++		compatible = "snps,designware-i2c";
++		reg = <0x0 0x7ffa0000 0x0 0x1000>;
++		#address-cells = <1>;
++		#size-cells = <0>;
++		interrupts = <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>;
++		clock-frequency = <400000>;
++		i2c-sda-hold-time-ns = <500>;
++		clocks = <&soc_smc50mhz>;
++
++		dvi0: dvi-transmitter@70 {
++			compatible = "nxp,tda998x";
++			reg = <0x70>;
++		};
++
++		dvi1: dvi-transmitter@71 {
++			compatible = "nxp,tda998x";
++			reg = <0x71>;
++		};
++	};
++
++	ohci@7ffb0000 {
++		compatible = "generic-ohci";
++		reg = <0x0 0x7ffb0000 0x0 0x10000>;
++		interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&soc_usb48mhz>;
++	};
++
++	ehci@7ffc0000 {
++		compatible = "generic-ehci";
++		reg = <0x0 0x7ffc0000 0x0 0x10000>;
++		interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&soc_usb48mhz>;
++	};
++
++	memory-controller@7ffd0000 {
++		compatible = "arm,pl354", "arm,primecell";
++		reg = <0 0x7ffd0000 0 0x1000>;
++		interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>,
++			     <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&soc_smc50mhz>;
++		clock-names = "apb_pclk";
++	};
++
++	smb {
++		compatible = "simple-bus";
++		#address-cells = <2>;
++		#size-cells = <1>;
++		ranges = <0 0 0 0x08000000 0x04000000>,
++			 <1 0 0 0x14000000 0x04000000>,
++			 <2 0 0 0x18000000 0x04000000>,
++			 <3 0 0 0x1c000000 0x04000000>,
++			 <4 0 0 0x0c000000 0x04000000>,
++			 <5 0 0 0x10000000 0x04000000>;
++
++		#interrupt-cells = <1>;
++		interrupt-map-mask = <0 0 15>;
++		interrupt-map = <0 0  0 &gic 0  68 IRQ_TYPE_LEVEL_HIGH>,
++				<0 0  1 &gic 0  69 IRQ_TYPE_LEVEL_HIGH>,
++				<0 0  2 &gic 0  70 IRQ_TYPE_LEVEL_HIGH>,
++				<0 0  3 &gic 0 160 IRQ_TYPE_LEVEL_HIGH>,
++				<0 0  4 &gic 0 161 IRQ_TYPE_LEVEL_HIGH>,
++				<0 0  5 &gic 0 162 IRQ_TYPE_LEVEL_HIGH>,
++				<0 0  6 &gic 0 163 IRQ_TYPE_LEVEL_HIGH>,
++				<0 0  7 &gic 0 164 IRQ_TYPE_LEVEL_HIGH>,
++				<0 0  8 &gic 0 165 IRQ_TYPE_LEVEL_HIGH>,
++				<0 0  9 &gic 0 166 IRQ_TYPE_LEVEL_HIGH>,
++				<0 0 10 &gic 0 167 IRQ_TYPE_LEVEL_HIGH>,
++				<0 0 11 &gic 0 168 IRQ_TYPE_LEVEL_HIGH>,
++				<0 0 12 &gic 0 169 IRQ_TYPE_LEVEL_HIGH>;
++
++		/include/ "juno-motherboard.dtsi"
++	};
++};
+diff --git a/arch/arm64/boot/dts/arm/rtsm_ve-aemv8a.dts b/arch/arm64/boot/dts/arm/rtsm_ve-aemv8a.dts
+new file mode 100644
+index 0000000..20addab
+--- /dev/null
++++ b/arch/arm64/boot/dts/arm/rtsm_ve-aemv8a.dts
+@@ -0,0 +1,167 @@
++/*
++ * ARM Ltd. Fast Models
++ *
++ * Architecture Envelope Model (AEM) ARMv8-A
++ * ARMAEMv8AMPCT
++ *
++ * RTSM_VE_AEMv8A.lisa
++ */
++
++/dts-v1/;
++
++/memreserve/ 0x80000000 0x00010000;
++
++/ {
++	model = "RTSM_VE_AEMv8A";
++	compatible = "arm,rtsm_ve,aemv8a", "arm,vexpress";
++	interrupt-parent = <&gic>;
++	#address-cells = <2>;
++	#size-cells = <2>;
++
++	chosen { };
++
++	aliases {
++		serial0 = &v2m_serial0;
++		serial1 = &v2m_serial1;
++		serial2 = &v2m_serial2;
++		serial3 = &v2m_serial3;
++	};
++
++	cpus {
++		#address-cells = <2>;
++		#size-cells = <0>;
++
++		cpu@0 {
++			device_type = "cpu";
++			compatible = "arm,armv8";
++			reg = <0x0 0x0>;
++			enable-method = "spin-table";
++			cpu-release-addr = <0x0 0x8000fff8>;
++			next-level-cache = <&L2_0>;
++		};
++		cpu@1 {
++			device_type = "cpu";
++			compatible = "arm,armv8";
++			reg = <0x0 0x1>;
++			enable-method = "spin-table";
++			cpu-release-addr = <0x0 0x8000fff8>;
++			next-level-cache = <&L2_0>;
++		};
++		cpu@2 {
++			device_type = "cpu";
++			compatible = "arm,armv8";
++			reg = <0x0 0x2>;
++			enable-method = "spin-table";
++			cpu-release-addr = <0x0 0x8000fff8>;
++			next-level-cache = <&L2_0>;
++		};
++		cpu@3 {
++			device_type = "cpu";
++			compatible = "arm,armv8";
++			reg = <0x0 0x3>;
++			enable-method = "spin-table";
++			cpu-release-addr = <0x0 0x8000fff8>;
++			next-level-cache = <&L2_0>;
++		};
++
++		L2_0: l2-cache0 {
++			compatible = "cache";
++		};
++	};
++
++	memory@80000000 {
++		device_type = "memory";
++		reg = <0x00000000 0x80000000 0 0x80000000>,
++		      <0x00000008 0x80000000 0 0x80000000>;
++	};
++
++	gic: interrupt-controller@2c001000 {
++		compatible = "arm,cortex-a15-gic", "arm,cortex-a9-gic";
++		#interrupt-cells = <3>;
++		#address-cells = <0>;
++		interrupt-controller;
++		reg = <0x0 0x2c001000 0 0x1000>,
++		      <0x0 0x2c002000 0 0x1000>,
++		      <0x0 0x2c004000 0 0x2000>,
++		      <0x0 0x2c006000 0 0x2000>;
++		interrupts = <1 9 0xf04>;
++	};
++
++	timer {
++		compatible = "arm,armv8-timer";
++		interrupts = <1 13 0xf08>,
++			     <1 14 0xf08>,
++			     <1 11 0xf08>,
++			     <1 10 0xf08>;
++		clock-frequency = <100000000>;
++	};
++
++	pmu {
++		compatible = "arm,armv8-pmuv3";
++		interrupts = <0 60 4>,
++			     <0 61 4>,
++			     <0 62 4>,
++			     <0 63 4>;
++	};
++
++	smb {
++		compatible = "simple-bus";
++
++		#address-cells = <2>;
++		#size-cells = <1>;
++		ranges = <0 0 0 0x08000000 0x04000000>,
++			 <1 0 0 0x14000000 0x04000000>,
++			 <2 0 0 0x18000000 0x04000000>,
++			 <3 0 0 0x1c000000 0x04000000>,
++			 <4 0 0 0x0c000000 0x04000000>,
++			 <5 0 0 0x10000000 0x04000000>;
++
++		#interrupt-cells = <1>;
++		interrupt-map-mask = <0 0 63>;
++		interrupt-map = <0 0  0 &gic 0  0 4>,
++				<0 0  1 &gic 0  1 4>,
++				<0 0  2 &gic 0  2 4>,
++				<0 0  3 &gic 0  3 4>,
++				<0 0  4 &gic 0  4 4>,
++				<0 0  5 &gic 0  5 4>,
++				<0 0  6 &gic 0  6 4>,
++				<0 0  7 &gic 0  7 4>,
++				<0 0  8 &gic 0  8 4>,
++				<0 0  9 &gic 0  9 4>,
++				<0 0 10 &gic 0 10 4>,
++				<0 0 11 &gic 0 11 4>,
++				<0 0 12 &gic 0 12 4>,
++				<0 0 13 &gic 0 13 4>,
++				<0 0 14 &gic 0 14 4>,
++				<0 0 15 &gic 0 15 4>,
++				<0 0 16 &gic 0 16 4>,
++				<0 0 17 &gic 0 17 4>,
++				<0 0 18 &gic 0 18 4>,
++				<0 0 19 &gic 0 19 4>,
++				<0 0 20 &gic 0 20 4>,
++				<0 0 21 &gic 0 21 4>,
++				<0 0 22 &gic 0 22 4>,
++				<0 0 23 &gic 0 23 4>,
++				<0 0 24 &gic 0 24 4>,
++				<0 0 25 &gic 0 25 4>,
++				<0 0 26 &gic 0 26 4>,
++				<0 0 27 &gic 0 27 4>,
++				<0 0 28 &gic 0 28 4>,
++				<0 0 29 &gic 0 29 4>,
++				<0 0 30 &gic 0 30 4>,
++				<0 0 31 &gic 0 31 4>,
++				<0 0 32 &gic 0 32 4>,
++				<0 0 33 &gic 0 33 4>,
++				<0 0 34 &gic 0 34 4>,
++				<0 0 35 &gic 0 35 4>,
++				<0 0 36 &gic 0 36 4>,
++				<0 0 37 &gic 0 37 4>,
++				<0 0 38 &gic 0 38 4>,
++				<0 0 39 &gic 0 39 4>,
++				<0 0 40 &gic 0 40 4>,
++				<0 0 41 &gic 0 41 4>,
++				<0 0 42 &gic 0 42 4>;
++
++		/include/ "rtsm_ve-motherboard.dtsi"
++	};
++};
+diff --git a/arch/arm64/boot/dts/arm/rtsm_ve-motherboard.dtsi b/arch/arm64/boot/dts/arm/rtsm_ve-motherboard.dtsi
+new file mode 100644
+index 0000000..c46cbb2
+--- /dev/null
++++ b/arch/arm64/boot/dts/arm/rtsm_ve-motherboard.dtsi
+@@ -0,0 +1,273 @@
++/*
++ * ARM Ltd. Fast Models
++ *
++ * Versatile Express (VE) system model
++ * Motherboard component
++ *
++ * VEMotherBoard.lisa
++ */
++
++	motherboard {
++		arm,v2m-memory-map = "rs1";
++		compatible = "arm,vexpress,v2m-p1", "simple-bus";
++		#address-cells = <2>; /* SMB chipselect number and offset */
++		#size-cells = <1>;
++		#interrupt-cells = <1>;
++		ranges;
++
++		flash@0,00000000 {
++			compatible = "arm,vexpress-flash", "cfi-flash";
++			reg = <0 0x00000000 0x04000000>,
++			      <4 0x00000000 0x04000000>;
++			bank-width = <4>;
++		};
++
++		v2m_video_ram: vram@2,00000000 {
++			compatible = "arm,vexpress-vram";
++			reg = <2 0x00000000 0x00800000>;
++		};
++
++		ethernet@2,02000000 {
++			compatible = "smsc,lan91c111";
++			reg = <2 0x02000000 0x10000>;
++			interrupts = <15>;
++		};
++
++		v2m_clk24mhz: clk24mhz {
++			compatible = "fixed-clock";
++			#clock-cells = <0>;
++			clock-frequency = <24000000>;
++			clock-output-names = "v2m:clk24mhz";
++		};
++
++		v2m_refclk1mhz: refclk1mhz {
++			compatible = "fixed-clock";
++			#clock-cells = <0>;
++			clock-frequency = <1000000>;
++			clock-output-names = "v2m:refclk1mhz";
++		};
++
++		v2m_refclk32khz: refclk32khz {
++			compatible = "fixed-clock";
++			#clock-cells = <0>;
++			clock-frequency = <32768>;
++			clock-output-names = "v2m:refclk32khz";
++		};
++
++		iofpga@3,00000000 {
++			compatible = "arm,amba-bus", "simple-bus";
++			#address-cells = <1>;
++			#size-cells = <1>;
++			ranges = <0 3 0 0x200000>;
++
++			v2m_sysreg: sysreg@010000 {
++				compatible = "arm,vexpress-sysreg";
++				reg = <0x010000 0x1000>;
++				gpio-controller;
++				#gpio-cells = <2>;
++			};
++
++			v2m_sysctl: sysctl@020000 {
++				compatible = "arm,sp810", "arm,primecell";
++				reg = <0x020000 0x1000>;
++				clocks = <&v2m_refclk32khz>, <&v2m_refclk1mhz>, <&v2m_clk24mhz>;
++				clock-names = "refclk", "timclk", "apb_pclk";
++				#clock-cells = <1>;
++				clock-output-names = "timerclken0", "timerclken1", "timerclken2", "timerclken3";
++			};
++
++			aaci@040000 {
++				compatible = "arm,pl041", "arm,primecell";
++				reg = <0x040000 0x1000>;
++				interrupts = <11>;
++				clocks = <&v2m_clk24mhz>;
++				clock-names = "apb_pclk";
++			};
++
++			mmci@050000 {
++				compatible = "arm,pl180", "arm,primecell";
++				reg = <0x050000 0x1000>;
++				interrupts = <9 10>;
++				cd-gpios = <&v2m_sysreg 0 0>;
++				wp-gpios = <&v2m_sysreg 1 0>;
++				max-frequency = <12000000>;
++				vmmc-supply = <&v2m_fixed_3v3>;
++				clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
++				clock-names = "mclk", "apb_pclk";
++			};
++
++			kmi@060000 {
++				compatible = "arm,pl050", "arm,primecell";
++				reg = <0x060000 0x1000>;
++				interrupts = <12>;
++				clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
++				clock-names = "KMIREFCLK", "apb_pclk";
++			};
++
++			kmi@070000 {
++				compatible = "arm,pl050", "arm,primecell";
++				reg = <0x070000 0x1000>;
++				interrupts = <13>;
++				clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
++				clock-names = "KMIREFCLK", "apb_pclk";
++			};
++
++			v2m_serial0: uart@090000 {
++				compatible = "arm,pl011", "arm,primecell";
++				reg = <0x090000 0x1000>;
++				interrupts = <5>;
++				clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
++				clock-names = "uartclk", "apb_pclk";
++			};
++
++			v2m_serial1: uart@0a0000 {
++				compatible = "arm,pl011", "arm,primecell";
++				reg = <0x0a0000 0x1000>;
++				interrupts = <6>;
++				clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
++				clock-names = "uartclk", "apb_pclk";
++			};
++
++			v2m_serial2: uart@0b0000 {
++				compatible = "arm,pl011", "arm,primecell";
++				reg = <0x0b0000 0x1000>;
++				interrupts = <7>;
++				clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
++				clock-names = "uartclk", "apb_pclk";
++			};
++
++			v2m_serial3: uart@0c0000 {
++				compatible = "arm,pl011", "arm,primecell";
++				reg = <0x0c0000 0x1000>;
++				interrupts = <8>;
++				clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
++				clock-names = "uartclk", "apb_pclk";
++			};
++
++			wdt@0f0000 {
++				compatible = "arm,sp805", "arm,primecell";
++				reg = <0x0f0000 0x1000>;
++				interrupts = <0>;
++				clocks = <&v2m_refclk32khz>, <&v2m_clk24mhz>;
++				clock-names = "wdogclk", "apb_pclk";
++			};
++
++			v2m_timer01: timer@110000 {
++				compatible = "arm,sp804", "arm,primecell";
++				reg = <0x110000 0x1000>;
++				interrupts = <2>;
++				clocks = <&v2m_sysctl 0>, <&v2m_sysctl 1>, <&v2m_clk24mhz>;
++				clock-names = "timclken1", "timclken2", "apb_pclk";
++			};
++
++			v2m_timer23: timer@120000 {
++				compatible = "arm,sp804", "arm,primecell";
++				reg = <0x120000 0x1000>;
++				interrupts = <3>;
++				clocks = <&v2m_sysctl 2>, <&v2m_sysctl 3>, <&v2m_clk24mhz>;
++				clock-names = "timclken1", "timclken2", "apb_pclk";
++			};
++
++			rtc@170000 {
++				compatible = "arm,pl031", "arm,primecell";
++				reg = <0x170000 0x1000>;
++				interrupts = <4>;
++				clocks = <&v2m_clk24mhz>;
++				clock-names = "apb_pclk";
++			};
++
++			clcd@1f0000 {
++				compatible = "arm,pl111", "arm,primecell";
++				reg = <0x1f0000 0x1000>;
++				interrupt-names = "combined";
++				interrupts = <14>;
++				clocks = <&v2m_oscclk1>, <&v2m_clk24mhz>;
++				clock-names = "clcdclk", "apb_pclk";
++				arm,pl11x,framebuffer = <0x18000000 0x00180000>;
++				memory-region = <&v2m_video_ram>;
++				max-memory-bandwidth = <130000000>; /* 16bpp @ 63.5MHz */
++
++				port {
++					v2m_clcd_pads: endpoint {
++						remote-endpoint = <&v2m_clcd_panel>;
++						arm,pl11x,tft-r0g0b0-pads = <0 8 16>;
++					};
++				};
++
++				panel {
++					compatible = "panel-dpi";
++
++					port {
++						v2m_clcd_panel: endpoint {
++							remote-endpoint = <&v2m_clcd_pads>;
++						};
++					};
++
++					panel-timing {
++						clock-frequency = <63500127>;
++						hactive = <1024>;
++						hback-porch = <152>;
++						hfront-porch = <48>;
++						hsync-len = <104>;
++						vactive = <768>;
++						vback-porch = <23>;
++						vfront-porch = <3>;
++						vsync-len = <4>;
++					};
++				};
++			};
++
++			virtio_block@0130000 {
++				compatible = "virtio,mmio";
++				reg = <0x130000 0x200>;
++				interrupts = <42>;
++			};
++		};
++
++		v2m_fixed_3v3: fixedregulator@0 {
++			compatible = "regulator-fixed";
++			regulator-name = "3V3";
++			regulator-min-microvolt = <3300000>;
++			regulator-max-microvolt = <3300000>;
++			regulator-always-on;
++		};
++
++		mcc {
++			compatible = "arm,vexpress,config-bus";
++			arm,vexpress,config-bridge = <&v2m_sysreg>;
++
++			v2m_oscclk1: osc@1 {
++				/* CLCD clock */
++				compatible = "arm,vexpress-osc";
++				arm,vexpress-sysreg,func = <1 1>;
++				freq-range = <23750000 63500000>;
++				#clock-cells = <0>;
++				clock-output-names = "v2m:oscclk1";
++			};
++
++			reset@0 {
++				compatible = "arm,vexpress-reset";
++				arm,vexpress-sysreg,func = <5 0>;
++			};
++
++			muxfpga@0 {
++				compatible = "arm,vexpress-muxfpga";
++				arm,vexpress-sysreg,func = <7 0>;
++			};
++
++			shutdown@0 {
++				compatible = "arm,vexpress-shutdown";
++				arm,vexpress-sysreg,func = <8 0>;
++			};
++
++			reboot@0 {
++				compatible = "arm,vexpress-reboot";
++				arm,vexpress-sysreg,func = <9 0>;
++			};
++
++			dvimode@0 {
++				compatible = "arm,vexpress-dvimode";
++				arm,vexpress-sysreg,func = <11 0>;
++			};
++		};
++	};
+diff --git a/arch/arm64/boot/dts/cavium/Makefile b/arch/arm64/boot/dts/cavium/Makefile
+new file mode 100644
+index 0000000..e34f89d
+--- /dev/null
++++ b/arch/arm64/boot/dts/cavium/Makefile
+@@ -0,0 +1,5 @@
++dtb-$(CONFIG_ARCH_THUNDER) += thunder-88xx.dtb
++
++always		:= $(dtb-y)
++subdir-y	:= $(dts-dirs)
++clean-files	:= *.dtb
+diff --git a/arch/arm64/boot/dts/cavium/thunder-88xx.dts b/arch/arm64/boot/dts/cavium/thunder-88xx.dts
+new file mode 100644
+index 0000000..800ba65
+--- /dev/null
++++ b/arch/arm64/boot/dts/cavium/thunder-88xx.dts
+@@ -0,0 +1,67 @@
++/*
++ * Cavium Thunder DTS file - Thunder board description
++ *
++ * Copyright (C) 2014, Cavium Inc.
++ *
++ * This file is dual-licensed: you can use it either under the terms
++ * of the GPL or the X11 license, at your option. Note that this dual
++ * licensing only applies to this file, and not this project as a
++ * whole.
++ *
++ *  a) This library 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 library 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 library; if not, write to the Free
++ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
++ *     MA 02110-1301 USA
++ *
++ * Or, alternatively,
++ *
++ *  b) Permission is hereby granted, free of charge, to any person
++ *     obtaining a copy of this software and associated documentation
++ *     files (the "Software"), to deal in the Software without
++ *     restriction, including without limitation the rights to use,
++ *     copy, modify, merge, publish, distribute, sublicense, and/or
++ *     sell copies of the Software, and to permit persons to whom the
++ *     Software is furnished to do so, subject to the following
++ *     conditions:
++ *
++ *     The above copyright notice and this permission notice shall be
++ *     included in all copies or substantial portions of the Software.
++ *
++ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
++ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
++ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
++ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
++ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ *     OTHER DEALINGS IN THE SOFTWARE.
++ */
++
++/dts-v1/;
++
++/include/ "thunder-88xx.dtsi"
++
++/ {
++	model = "Cavium ThunderX CN88XX board";
++	compatible = "cavium,thunder-88xx";
++
++	aliases {
++		serial0 = &uaa0;
++		serial1 = &uaa1;
++	};
++
++	memory@00000000 {
++		device_type = "memory";
++		reg = <0x0 0x00000000 0x0 0x80000000>;
++	};
++};
+diff --git a/arch/arm64/boot/dts/cavium/thunder-88xx.dtsi b/arch/arm64/boot/dts/cavium/thunder-88xx.dtsi
+new file mode 100644
+index 0000000..d8c0bdc
+--- /dev/null
++++ b/arch/arm64/boot/dts/cavium/thunder-88xx.dtsi
+@@ -0,0 +1,401 @@
++/*
++ * Cavium Thunder DTS file - Thunder SoC description
++ *
++ * Copyright (C) 2014, Cavium Inc.
++ *
++ * This file is dual-licensed: you can use it either under the terms
++ * of the GPL or the X11 license, at your option. Note that this dual
++ * licensing only applies to this file, and not this project as a
++ * whole.
++ *
++ *  a) This library 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 library 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 library; if not, write to the Free
++ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
++ *     MA 02110-1301 USA
++ *
++ * Or, alternatively,
++ *
++ *  b) Permission is hereby granted, free of charge, to any person
++ *     obtaining a copy of this software and associated documentation
++ *     files (the "Software"), to deal in the Software without
++ *     restriction, including without limitation the rights to use,
++ *     copy, modify, merge, publish, distribute, sublicense, and/or
++ *     sell copies of the Software, and to permit persons to whom the
++ *     Software is furnished to do so, subject to the following
++ *     conditions:
++ *
++ *     The above copyright notice and this permission notice shall be
++ *     included in all copies or substantial portions of the Software.
++ *
++ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
++ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
++ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
++ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
++ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ *     OTHER DEALINGS IN THE SOFTWARE.
++ */
++
++/ {
++	compatible = "cavium,thunder-88xx";
++	interrupt-parent = <&gic0>;
++	#address-cells = <2>;
++	#size-cells = <2>;
++
++	psci {
++		compatible = "arm,psci-0.2";
++		method = "smc";
++	};
++
++	cpus {
++		#address-cells = <2>;
++		#size-cells = <0>;
++
++		cpu@000 {
++			device_type = "cpu";
++			compatible = "cavium,thunder", "arm,armv8";
++			reg = <0x0 0x000>;
++			enable-method = "psci";
++		};
++		cpu@001 {
++			device_type = "cpu";
++			compatible = "cavium,thunder", "arm,armv8";
++			reg = <0x0 0x001>;
++			enable-method = "psci";
++		};
++		cpu@002 {
++			device_type = "cpu";
++			compatible = "cavium,thunder", "arm,armv8";
++			reg = <0x0 0x002>;
++			enable-method = "psci";
++		};
++		cpu@003 {
++			device_type = "cpu";
++			compatible = "cavium,thunder", "arm,armv8";
++			reg = <0x0 0x003>;
++			enable-method = "psci";
++		};
++		cpu@004 {
++			device_type = "cpu";
++			compatible = "cavium,thunder", "arm,armv8";
++			reg = <0x0 0x004>;
++			enable-method = "psci";
++		};
++		cpu@005 {
++			device_type = "cpu";
++			compatible = "cavium,thunder", "arm,armv8";
++			reg = <0x0 0x005>;
++			enable-method = "psci";
++		};
++		cpu@006 {
++			device_type = "cpu";
++			compatible = "cavium,thunder", "arm,armv8";
++			reg = <0x0 0x006>;
++			enable-method = "psci";
++		};
++		cpu@007 {
++			device_type = "cpu";
++			compatible = "cavium,thunder", "arm,armv8";
++			reg = <0x0 0x007>;
++			enable-method = "psci";
++		};
++		cpu@008 {
++			device_type = "cpu";
++			compatible = "cavium,thunder", "arm,armv8";
++			reg = <0x0 0x008>;
++			enable-method = "psci";
++		};
++		cpu@009 {
++			device_type = "cpu";
++			compatible = "cavium,thunder", "arm,armv8";
++			reg = <0x0 0x009>;
++			enable-method = "psci";
++		};
++		cpu@00a {
++			device_type = "cpu";
++			compatible = "cavium,thunder", "arm,armv8";
++			reg = <0x0 0x00a>;
++			enable-method = "psci";
++		};
++		cpu@00b {
++			device_type = "cpu";
++			compatible = "cavium,thunder", "arm,armv8";
++			reg = <0x0 0x00b>;
++			enable-method = "psci";
++		};
++		cpu@00c {
++			device_type = "cpu";
++			compatible = "cavium,thunder", "arm,armv8";
++			reg = <0x0 0x00c>;
++			enable-method = "psci";
++		};
++		cpu@00d {
++			device_type = "cpu";
++			compatible = "cavium,thunder", "arm,armv8";
++			reg = <0x0 0x00d>;
++			enable-method = "psci";
++		};
++		cpu@00e {
++			device_type = "cpu";
++			compatible = "cavium,thunder", "arm,armv8";
++			reg = <0x0 0x00e>;
++			enable-method = "psci";
++		};
++		cpu@00f {
++			device_type = "cpu";
++			compatible = "cavium,thunder", "arm,armv8";
++			reg = <0x0 0x00f>;
++			enable-method = "psci";
++		};
++		cpu@100 {
++			device_type = "cpu";
++			compatible = "cavium,thunder", "arm,armv8";
++			reg = <0x0 0x100>;
++			enable-method = "psci";
++		};
++		cpu@101 {
++			device_type = "cpu";
++			compatible = "cavium,thunder", "arm,armv8";
++			reg = <0x0 0x101>;
++			enable-method = "psci";
++		};
++		cpu@102 {
++			device_type = "cpu";
++			compatible = "cavium,thunder", "arm,armv8";
++			reg = <0x0 0x102>;
++			enable-method = "psci";
++		};
++		cpu@103 {
++			device_type = "cpu";
++			compatible = "cavium,thunder", "arm,armv8";
++			reg = <0x0 0x103>;
++			enable-method = "psci";
++		};
++		cpu@104 {
++			device_type = "cpu";
++			compatible = "cavium,thunder", "arm,armv8";
++			reg = <0x0 0x104>;
++			enable-method = "psci";
++		};
++		cpu@105 {
++			device_type = "cpu";
++			compatible = "cavium,thunder", "arm,armv8";
++			reg = <0x0 0x105>;
++			enable-method = "psci";
++		};
++		cpu@106 {
++			device_type = "cpu";
++			compatible = "cavium,thunder", "arm,armv8";
++			reg = <0x0 0x106>;
++			enable-method = "psci";
++		};
++		cpu@107 {
++			device_type = "cpu";
++			compatible = "cavium,thunder", "arm,armv8";
++			reg = <0x0 0x107>;
++			enable-method = "psci";
++		};
++		cpu@108 {
++			device_type = "cpu";
++			compatible = "cavium,thunder", "arm,armv8";
++			reg = <0x0 0x108>;
++			enable-method = "psci";
++		};
++		cpu@109 {
++			device_type = "cpu";
++			compatible = "cavium,thunder", "arm,armv8";
++			reg = <0x0 0x109>;
++			enable-method = "psci";
++		};
++		cpu@10a {
++			device_type = "cpu";
++			compatible = "cavium,thunder", "arm,armv8";
++			reg = <0x0 0x10a>;
++			enable-method = "psci";
++		};
++		cpu@10b {
++			device_type = "cpu";
++			compatible = "cavium,thunder", "arm,armv8";
++			reg = <0x0 0x10b>;
++			enable-method = "psci";
++		};
++		cpu@10c {
++			device_type = "cpu";
++			compatible = "cavium,thunder", "arm,armv8";
++			reg = <0x0 0x10c>;
++			enable-method = "psci";
++		};
++		cpu@10d {
++			device_type = "cpu";
++			compatible = "cavium,thunder", "arm,armv8";
++			reg = <0x0 0x10d>;
++			enable-method = "psci";
++		};
++		cpu@10e {
++			device_type = "cpu";
++			compatible = "cavium,thunder", "arm,armv8";
++			reg = <0x0 0x10e>;
++			enable-method = "psci";
++		};
++		cpu@10f {
++			device_type = "cpu";
++			compatible = "cavium,thunder", "arm,armv8";
++			reg = <0x0 0x10f>;
++			enable-method = "psci";
++		};
++		cpu@200 {
++			device_type = "cpu";
++			compatible = "cavium,thunder", "arm,armv8";
++			reg = <0x0 0x200>;
++			enable-method = "psci";
++		};
++		cpu@201 {
++			device_type = "cpu";
++			compatible = "cavium,thunder", "arm,armv8";
++			reg = <0x0 0x201>;
++			enable-method = "psci";
++		};
++		cpu@202 {
++			device_type = "cpu";
++			compatible = "cavium,thunder", "arm,armv8";
++			reg = <0x0 0x202>;
++			enable-method = "psci";
++		};
++		cpu@203 {
++			device_type = "cpu";
++			compatible = "cavium,thunder", "arm,armv8";
++			reg = <0x0 0x203>;
++			enable-method = "psci";
++		};
++		cpu@204 {
++			device_type = "cpu";
++			compatible = "cavium,thunder", "arm,armv8";
++			reg = <0x0 0x204>;
++			enable-method = "psci";
++		};
++		cpu@205 {
++			device_type = "cpu";
++			compatible = "cavium,thunder", "arm,armv8";
++			reg = <0x0 0x205>;
++			enable-method = "psci";
++		};
++		cpu@206 {
++			device_type = "cpu";
++			compatible = "cavium,thunder", "arm,armv8";
++			reg = <0x0 0x206>;
++			enable-method = "psci";
++		};
++		cpu@207 {
++			device_type = "cpu";
++			compatible = "cavium,thunder", "arm,armv8";
++			reg = <0x0 0x207>;
++			enable-method = "psci";
++		};
++		cpu@208 {
++			device_type = "cpu";
++			compatible = "cavium,thunder", "arm,armv8";
++			reg = <0x0 0x208>;
++			enable-method = "psci";
++		};
++		cpu@209 {
++			device_type = "cpu";
++			compatible = "cavium,thunder", "arm,armv8";
++			reg = <0x0 0x209>;
++			enable-method = "psci";
++		};
++		cpu@20a {
++			device_type = "cpu";
++			compatible = "cavium,thunder", "arm,armv8";
++			reg = <0x0 0x20a>;
++			enable-method = "psci";
++		};
++		cpu@20b {
++			device_type = "cpu";
++			compatible = "cavium,thunder", "arm,armv8";
++			reg = <0x0 0x20b>;
++			enable-method = "psci";
++		};
++		cpu@20c {
++			device_type = "cpu";
++			compatible = "cavium,thunder", "arm,armv8";
++			reg = <0x0 0x20c>;
++			enable-method = "psci";
++		};
++		cpu@20d {
++			device_type = "cpu";
++			compatible = "cavium,thunder", "arm,armv8";
++			reg = <0x0 0x20d>;
++			enable-method = "psci";
++		};
++		cpu@20e {
++			device_type = "cpu";
++			compatible = "cavium,thunder", "arm,armv8";
++			reg = <0x0 0x20e>;
++			enable-method = "psci";
++		};
++		cpu@20f {
++			device_type = "cpu";
++			compatible = "cavium,thunder", "arm,armv8";
++			reg = <0x0 0x20f>;
++			enable-method = "psci";
++		};
++	};
++
++	timer {
++		compatible = "arm,armv8-timer";
++		interrupts = <1 13 0xff01>,
++		             <1 14 0xff01>,
++		             <1 11 0xff01>,
++		             <1 10 0xff01>;
++	};
++
++	soc {
++		compatible = "simple-bus";
++		#address-cells = <2>;
++		#size-cells = <2>;
++		ranges;
++
++		refclk50mhz: refclk50mhz {
++			compatible = "fixed-clock";
++			#clock-cells = <0>;
++			clock-frequency = <50000000>;
++			clock-output-names = "refclk50mhz";
++		};
++
++		gic0: interrupt-controller@8010,00000000 {
++			compatible = "arm,gic-v3";
++			#interrupt-cells = <3>;
++			interrupt-controller;
++			reg = <0x8010 0x00000000 0x0 0x010000>, /* GICD */
++			      <0x8010 0x80000000 0x0 0x600000>; /* GICR */
++			interrupts = <1 9 0xf04>;
++		};
++
++		uaa0: serial@87e0,24000000 {
++			compatible = "arm,pl011", "arm,primecell";
++			reg = <0x87e0 0x24000000 0x0 0x1000>;
++			interrupts = <1 21 4>;
++			clocks = <&refclk50mhz>;
++			clock-names = "apb_pclk";
++		};
++
++		uaa1: serial@87e0,25000000 {
++			compatible = "arm,pl011", "arm,primecell";
++			reg = <0x87e0 0x25000000 0x0 0x1000>;
++			interrupts = <1 22 4>;
++			clocks = <&refclk50mhz>;
++			clock-names = "apb_pclk";
++		};
++	};
++};
+diff --git a/arch/arm64/boot/dts/foundation-v8.dts b/arch/arm64/boot/dts/foundation-v8.dts
+deleted file mode 100644
+index 4a06090..0000000
+--- a/arch/arm64/boot/dts/foundation-v8.dts
++++ /dev/null
+@@ -1,232 +0,0 @@
+-/*
+- * ARM Ltd.
+- *
+- * ARMv8 Foundation model DTS
+- */
+-
+-/dts-v1/;
+-
+-/memreserve/ 0x80000000 0x00010000;
+-
+-/ {
+-	model = "Foundation-v8A";
+-	compatible = "arm,foundation-aarch64", "arm,vexpress";
+-	interrupt-parent = <&gic>;
+-	#address-cells = <2>;
+-	#size-cells = <2>;
+-
+-	chosen { };
+-
+-	aliases {
+-		serial0 = &v2m_serial0;
+-		serial1 = &v2m_serial1;
+-		serial2 = &v2m_serial2;
+-		serial3 = &v2m_serial3;
+-	};
+-
+-	cpus {
+-		#address-cells = <2>;
+-		#size-cells = <0>;
+-
+-		cpu@0 {
+-			device_type = "cpu";
+-			compatible = "arm,armv8";
+-			reg = <0x0 0x0>;
+-			enable-method = "spin-table";
+-			cpu-release-addr = <0x0 0x8000fff8>;
+-		};
+-		cpu@1 {
+-			device_type = "cpu";
+-			compatible = "arm,armv8";
+-			reg = <0x0 0x1>;
+-			enable-method = "spin-table";
+-			cpu-release-addr = <0x0 0x8000fff8>;
+-		};
+-		cpu@2 {
+-			device_type = "cpu";
+-			compatible = "arm,armv8";
+-			reg = <0x0 0x2>;
+-			enable-method = "spin-table";
+-			cpu-release-addr = <0x0 0x8000fff8>;
+-		};
+-		cpu@3 {
+-			device_type = "cpu";
+-			compatible = "arm,armv8";
+-			reg = <0x0 0x3>;
+-			enable-method = "spin-table";
+-			cpu-release-addr = <0x0 0x8000fff8>;
+-		};
+-	};
+-
+-	memory@80000000 {
+-		device_type = "memory";
+-		reg = <0x00000000 0x80000000 0 0x80000000>,
+-		      <0x00000008 0x80000000 0 0x80000000>;
+-	};
+-
+-	gic: interrupt-controller@2c001000 {
+-		compatible = "arm,cortex-a15-gic", "arm,cortex-a9-gic";
+-		#interrupt-cells = <3>;
+-		#address-cells = <0>;
+-		interrupt-controller;
+-		reg = <0x0 0x2c001000 0 0x1000>,
+-		      <0x0 0x2c002000 0 0x1000>,
+-		      <0x0 0x2c004000 0 0x2000>,
+-		      <0x0 0x2c006000 0 0x2000>;
+-		interrupts = <1 9 0xf04>;
+-	};
+-
+-	timer {
+-		compatible = "arm,armv8-timer";
+-		interrupts = <1 13 0xff01>,
+-			     <1 14 0xff01>,
+-			     <1 11 0xff01>,
+-			     <1 10 0xff01>;
+-		clock-frequency = <100000000>;
+-	};
+-
+-	pmu {
+-		compatible = "arm,armv8-pmuv3";
+-		interrupts = <0 60 4>,
+-			     <0 61 4>,
+-			     <0 62 4>,
+-			     <0 63 4>;
+-	};
+-
+-	smb {
+-		compatible = "arm,vexpress,v2m-p1", "simple-bus";
+-		arm,v2m-memory-map = "rs1";
+-		#address-cells = <2>; /* SMB chipselect number and offset */
+-		#size-cells = <1>;
+-
+-		ranges = <0 0 0 0x08000000 0x04000000>,
+-			 <1 0 0 0x14000000 0x04000000>,
+-			 <2 0 0 0x18000000 0x04000000>,
+-			 <3 0 0 0x1c000000 0x04000000>,
+-			 <4 0 0 0x0c000000 0x04000000>,
+-			 <5 0 0 0x10000000 0x04000000>;
+-
+-		#interrupt-cells = <1>;
+-		interrupt-map-mask = <0 0 63>;
+-		interrupt-map = <0 0  0 &gic 0  0 4>,
+-				<0 0  1 &gic 0  1 4>,
+-				<0 0  2 &gic 0  2 4>,
+-				<0 0  3 &gic 0  3 4>,
+-				<0 0  4 &gic 0  4 4>,
+-				<0 0  5 &gic 0  5 4>,
+-				<0 0  6 &gic 0  6 4>,
+-				<0 0  7 &gic 0  7 4>,
+-				<0 0  8 &gic 0  8 4>,
+-				<0 0  9 &gic 0  9 4>,
+-				<0 0 10 &gic 0 10 4>,
+-				<0 0 11 &gic 0 11 4>,
+-				<0 0 12 &gic 0 12 4>,
+-				<0 0 13 &gic 0 13 4>,
+-				<0 0 14 &gic 0 14 4>,
+-				<0 0 15 &gic 0 15 4>,
+-				<0 0 16 &gic 0 16 4>,
+-				<0 0 17 &gic 0 17 4>,
+-				<0 0 18 &gic 0 18 4>,
+-				<0 0 19 &gic 0 19 4>,
+-				<0 0 20 &gic 0 20 4>,
+-				<0 0 21 &gic 0 21 4>,
+-				<0 0 22 &gic 0 22 4>,
+-				<0 0 23 &gic 0 23 4>,
+-				<0 0 24 &gic 0 24 4>,
+-				<0 0 25 &gic 0 25 4>,
+-				<0 0 26 &gic 0 26 4>,
+-				<0 0 27 &gic 0 27 4>,
+-				<0 0 28 &gic 0 28 4>,
+-				<0 0 29 &gic 0 29 4>,
+-				<0 0 30 &gic 0 30 4>,
+-				<0 0 31 &gic 0 31 4>,
+-				<0 0 32 &gic 0 32 4>,
+-				<0 0 33 &gic 0 33 4>,
+-				<0 0 34 &gic 0 34 4>,
+-				<0 0 35 &gic 0 35 4>,
+-				<0 0 36 &gic 0 36 4>,
+-				<0 0 37 &gic 0 37 4>,
+-				<0 0 38 &gic 0 38 4>,
+-				<0 0 39 &gic 0 39 4>,
+-				<0 0 40 &gic 0 40 4>,
+-				<0 0 41 &gic 0 41 4>,
+-				<0 0 42 &gic 0 42 4>;
+-
+-		ethernet@2,02000000 {
+-			compatible = "smsc,lan91c111";
+-			reg = <2 0x02000000 0x10000>;
+-			interrupts = <15>;
+-		};
+-
+-		v2m_clk24mhz: clk24mhz {
+-			compatible = "fixed-clock";
+-			#clock-cells = <0>;
+-			clock-frequency = <24000000>;
+-			clock-output-names = "v2m:clk24mhz";
+-		};
+-
+-		v2m_refclk1mhz: refclk1mhz {
+-			compatible = "fixed-clock";
+-			#clock-cells = <0>;
+-			clock-frequency = <1000000>;
+-			clock-output-names = "v2m:refclk1mhz";
+-		};
+-
+-		v2m_refclk32khz: refclk32khz {
+-			compatible = "fixed-clock";
+-			#clock-cells = <0>;
+-			clock-frequency = <32768>;
+-			clock-output-names = "v2m:refclk32khz";
+-		};
+-
+-		iofpga@3,00000000 {
+-			compatible = "arm,amba-bus", "simple-bus";
+-			#address-cells = <1>;
+-			#size-cells = <1>;
+-			ranges = <0 3 0 0x200000>;
+-
+-			v2m_sysreg: sysreg@010000 {
+-				compatible = "arm,vexpress-sysreg";
+-				reg = <0x010000 0x1000>;
+-			};
+-
+-			v2m_serial0: uart@090000 {
+-				compatible = "arm,pl011", "arm,primecell";
+-				reg = <0x090000 0x1000>;
+-				interrupts = <5>;
+-				clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
+-				clock-names = "uartclk", "apb_pclk";
+-			};
+-
+-			v2m_serial1: uart@0a0000 {
+-				compatible = "arm,pl011", "arm,primecell";
+-				reg = <0x0a0000 0x1000>;
+-				interrupts = <6>;
+-				clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
+-				clock-names = "uartclk", "apb_pclk";
+-			};
+-
+-			v2m_serial2: uart@0b0000 {
+-				compatible = "arm,pl011", "arm,primecell";
+-				reg = <0x0b0000 0x1000>;
+-				interrupts = <7>;
+-				clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
+-				clock-names = "uartclk", "apb_pclk";
+-			};
+-
+-			v2m_serial3: uart@0c0000 {
+-				compatible = "arm,pl011", "arm,primecell";
+-				reg = <0x0c0000 0x1000>;
+-				interrupts = <8>;
+-				clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
+-				clock-names = "uartclk", "apb_pclk";
+-			};
+-
+-			virtio_block@0130000 {
+-				compatible = "virtio,mmio";
+-				reg = <0x130000 0x200>;
+-				interrupts = <42>;
+-			};
+-		};
+-	};
+-};
+diff --git a/arch/arm64/boot/dts/include/dt-bindings b/arch/arm64/boot/dts/include/dt-bindings
+new file mode 120000
+index 0000000..08c00e4
+--- /dev/null
++++ b/arch/arm64/boot/dts/include/dt-bindings
+@@ -0,0 +1 @@
++../../../../../include/dt-bindings
+\ No newline at end of file
+diff --git a/arch/arm64/boot/dts/rtsm_ve-aemv8a.dts b/arch/arm64/boot/dts/rtsm_ve-aemv8a.dts
+deleted file mode 100644
+index 572005e..0000000
+--- a/arch/arm64/boot/dts/rtsm_ve-aemv8a.dts
++++ /dev/null
+@@ -1,159 +0,0 @@
+-/*
+- * ARM Ltd. Fast Models
+- *
+- * Architecture Envelope Model (AEM) ARMv8-A
+- * ARMAEMv8AMPCT
+- *
+- * RTSM_VE_AEMv8A.lisa
+- */
+-
+-/dts-v1/;
+-
+-/memreserve/ 0x80000000 0x00010000;
+-
+-/ {
+-	model = "RTSM_VE_AEMv8A";
+-	compatible = "arm,rtsm_ve,aemv8a", "arm,vexpress";
+-	interrupt-parent = <&gic>;
+-	#address-cells = <2>;
+-	#size-cells = <2>;
+-
+-	chosen { };
+-
+-	aliases {
+-		serial0 = &v2m_serial0;
+-		serial1 = &v2m_serial1;
+-		serial2 = &v2m_serial2;
+-		serial3 = &v2m_serial3;
+-	};
+-
+-	cpus {
+-		#address-cells = <2>;
+-		#size-cells = <0>;
+-
+-		cpu@0 {
+-			device_type = "cpu";
+-			compatible = "arm,armv8";
+-			reg = <0x0 0x0>;
+-			enable-method = "spin-table";
+-			cpu-release-addr = <0x0 0x8000fff8>;
+-		};
+-		cpu@1 {
+-			device_type = "cpu";
+-			compatible = "arm,armv8";
+-			reg = <0x0 0x1>;
+-			enable-method = "spin-table";
+-			cpu-release-addr = <0x0 0x8000fff8>;
+-		};
+-		cpu@2 {
+-			device_type = "cpu";
+-			compatible = "arm,armv8";
+-			reg = <0x0 0x2>;
+-			enable-method = "spin-table";
+-			cpu-release-addr = <0x0 0x8000fff8>;
+-		};
+-		cpu@3 {
+-			device_type = "cpu";
+-			compatible = "arm,armv8";
+-			reg = <0x0 0x3>;
+-			enable-method = "spin-table";
+-			cpu-release-addr = <0x0 0x8000fff8>;
+-		};
+-	};
+-
+-	memory@80000000 {
+-		device_type = "memory";
+-		reg = <0x00000000 0x80000000 0 0x80000000>,
+-		      <0x00000008 0x80000000 0 0x80000000>;
+-	};
+-
+-	gic: interrupt-controller@2c001000 {
+-		compatible = "arm,cortex-a15-gic", "arm,cortex-a9-gic";
+-		#interrupt-cells = <3>;
+-		#address-cells = <0>;
+-		interrupt-controller;
+-		reg = <0x0 0x2c001000 0 0x1000>,
+-		      <0x0 0x2c002000 0 0x1000>,
+-		      <0x0 0x2c004000 0 0x2000>,
+-		      <0x0 0x2c006000 0 0x2000>;
+-		interrupts = <1 9 0xf04>;
+-	};
+-
+-	timer {
+-		compatible = "arm,armv8-timer";
+-		interrupts = <1 13 0xff01>,
+-			     <1 14 0xff01>,
+-			     <1 11 0xff01>,
+-			     <1 10 0xff01>;
+-		clock-frequency = <100000000>;
+-	};
+-
+-	pmu {
+-		compatible = "arm,armv8-pmuv3";
+-		interrupts = <0 60 4>,
+-			     <0 61 4>,
+-			     <0 62 4>,
+-			     <0 63 4>;
+-	};
+-
+-	smb {
+-		compatible = "simple-bus";
+-
+-		#address-cells = <2>;
+-		#size-cells = <1>;
+-		ranges = <0 0 0 0x08000000 0x04000000>,
+-			 <1 0 0 0x14000000 0x04000000>,
+-			 <2 0 0 0x18000000 0x04000000>,
+-			 <3 0 0 0x1c000000 0x04000000>,
+-			 <4 0 0 0x0c000000 0x04000000>,
+-			 <5 0 0 0x10000000 0x04000000>;
+-
+-		#interrupt-cells = <1>;
+-		interrupt-map-mask = <0 0 63>;
+-		interrupt-map = <0 0  0 &gic 0  0 4>,
+-				<0 0  1 &gic 0  1 4>,
+-				<0 0  2 &gic 0  2 4>,
+-				<0 0  3 &gic 0  3 4>,
+-				<0 0  4 &gic 0  4 4>,
+-				<0 0  5 &gic 0  5 4>,
+-				<0 0  6 &gic 0  6 4>,
+-				<0 0  7 &gic 0  7 4>,
+-				<0 0  8 &gic 0  8 4>,
+-				<0 0  9 &gic 0  9 4>,
+-				<0 0 10 &gic 0 10 4>,
+-				<0 0 11 &gic 0 11 4>,
+-				<0 0 12 &gic 0 12 4>,
+-				<0 0 13 &gic 0 13 4>,
+-				<0 0 14 &gic 0 14 4>,
+-				<0 0 15 &gic 0 15 4>,
+-				<0 0 16 &gic 0 16 4>,
+-				<0 0 17 &gic 0 17 4>,
+-				<0 0 18 &gic 0 18 4>,
+-				<0 0 19 &gic 0 19 4>,
+-				<0 0 20 &gic 0 20 4>,
+-				<0 0 21 &gic 0 21 4>,
+-				<0 0 22 &gic 0 22 4>,
+-				<0 0 23 &gic 0 23 4>,
+-				<0 0 24 &gic 0 24 4>,
+-				<0 0 25 &gic 0 25 4>,
+-				<0 0 26 &gic 0 26 4>,
+-				<0 0 27 &gic 0 27 4>,
+-				<0 0 28 &gic 0 28 4>,
+-				<0 0 29 &gic 0 29 4>,
+-				<0 0 30 &gic 0 30 4>,
+-				<0 0 31 &gic 0 31 4>,
+-				<0 0 32 &gic 0 32 4>,
+-				<0 0 33 &gic 0 33 4>,
+-				<0 0 34 &gic 0 34 4>,
+-				<0 0 35 &gic 0 35 4>,
+-				<0 0 36 &gic 0 36 4>,
+-				<0 0 37 &gic 0 37 4>,
+-				<0 0 38 &gic 0 38 4>,
+-				<0 0 39 &gic 0 39 4>,
+-				<0 0 40 &gic 0 40 4>,
+-				<0 0 41 &gic 0 41 4>,
+-				<0 0 42 &gic 0 42 4>;
+-
+-		/include/ "rtsm_ve-motherboard.dtsi"
+-	};
+-};
+diff --git a/arch/arm64/boot/dts/rtsm_ve-motherboard.dtsi b/arch/arm64/boot/dts/rtsm_ve-motherboard.dtsi
+deleted file mode 100644
+index c46cbb2..0000000
+--- a/arch/arm64/boot/dts/rtsm_ve-motherboard.dtsi
++++ /dev/null
+@@ -1,273 +0,0 @@
+-/*
+- * ARM Ltd. Fast Models
+- *
+- * Versatile Express (VE) system model
+- * Motherboard component
+- *
+- * VEMotherBoard.lisa
+- */
+-
+-	motherboard {
+-		arm,v2m-memory-map = "rs1";
+-		compatible = "arm,vexpress,v2m-p1", "simple-bus";
+-		#address-cells = <2>; /* SMB chipselect number and offset */
+-		#size-cells = <1>;
+-		#interrupt-cells = <1>;
+-		ranges;
+-
+-		flash@0,00000000 {
+-			compatible = "arm,vexpress-flash", "cfi-flash";
+-			reg = <0 0x00000000 0x04000000>,
+-			      <4 0x00000000 0x04000000>;
+-			bank-width = <4>;
+-		};
+-
+-		v2m_video_ram: vram@2,00000000 {
+-			compatible = "arm,vexpress-vram";
+-			reg = <2 0x00000000 0x00800000>;
+-		};
+-
+-		ethernet@2,02000000 {
+-			compatible = "smsc,lan91c111";
+-			reg = <2 0x02000000 0x10000>;
+-			interrupts = <15>;
+-		};
+-
+-		v2m_clk24mhz: clk24mhz {
+-			compatible = "fixed-clock";
+-			#clock-cells = <0>;
+-			clock-frequency = <24000000>;
+-			clock-output-names = "v2m:clk24mhz";
+-		};
+-
+-		v2m_refclk1mhz: refclk1mhz {
+-			compatible = "fixed-clock";
+-			#clock-cells = <0>;
+-			clock-frequency = <1000000>;
+-			clock-output-names = "v2m:refclk1mhz";
+-		};
+-
+-		v2m_refclk32khz: refclk32khz {
+-			compatible = "fixed-clock";
+-			#clock-cells = <0>;
+-			clock-frequency = <32768>;
+-			clock-output-names = "v2m:refclk32khz";
+-		};
+-
+-		iofpga@3,00000000 {
+-			compatible = "arm,amba-bus", "simple-bus";
+-			#address-cells = <1>;
+-			#size-cells = <1>;
+-			ranges = <0 3 0 0x200000>;
+-
+-			v2m_sysreg: sysreg@010000 {
+-				compatible = "arm,vexpress-sysreg";
+-				reg = <0x010000 0x1000>;
+-				gpio-controller;
+-				#gpio-cells = <2>;
+-			};
+-
+-			v2m_sysctl: sysctl@020000 {
+-				compatible = "arm,sp810", "arm,primecell";
+-				reg = <0x020000 0x1000>;
+-				clocks = <&v2m_refclk32khz>, <&v2m_refclk1mhz>, <&v2m_clk24mhz>;
+-				clock-names = "refclk", "timclk", "apb_pclk";
+-				#clock-cells = <1>;
+-				clock-output-names = "timerclken0", "timerclken1", "timerclken2", "timerclken3";
+-			};
+-
+-			aaci@040000 {
+-				compatible = "arm,pl041", "arm,primecell";
+-				reg = <0x040000 0x1000>;
+-				interrupts = <11>;
+-				clocks = <&v2m_clk24mhz>;
+-				clock-names = "apb_pclk";
+-			};
+-
+-			mmci@050000 {
+-				compatible = "arm,pl180", "arm,primecell";
+-				reg = <0x050000 0x1000>;
+-				interrupts = <9 10>;
+-				cd-gpios = <&v2m_sysreg 0 0>;
+-				wp-gpios = <&v2m_sysreg 1 0>;
+-				max-frequency = <12000000>;
+-				vmmc-supply = <&v2m_fixed_3v3>;
+-				clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
+-				clock-names = "mclk", "apb_pclk";
+-			};
+-
+-			kmi@060000 {
+-				compatible = "arm,pl050", "arm,primecell";
+-				reg = <0x060000 0x1000>;
+-				interrupts = <12>;
+-				clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
+-				clock-names = "KMIREFCLK", "apb_pclk";
+-			};
+-
+-			kmi@070000 {
+-				compatible = "arm,pl050", "arm,primecell";
+-				reg = <0x070000 0x1000>;
+-				interrupts = <13>;
+-				clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
+-				clock-names = "KMIREFCLK", "apb_pclk";
+-			};
+-
+-			v2m_serial0: uart@090000 {
+-				compatible = "arm,pl011", "arm,primecell";
+-				reg = <0x090000 0x1000>;
+-				interrupts = <5>;
+-				clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
+-				clock-names = "uartclk", "apb_pclk";
+-			};
+-
+-			v2m_serial1: uart@0a0000 {
+-				compatible = "arm,pl011", "arm,primecell";
+-				reg = <0x0a0000 0x1000>;
+-				interrupts = <6>;
+-				clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
+-				clock-names = "uartclk", "apb_pclk";
+-			};
+-
+-			v2m_serial2: uart@0b0000 {
+-				compatible = "arm,pl011", "arm,primecell";
+-				reg = <0x0b0000 0x1000>;
+-				interrupts = <7>;
+-				clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
+-				clock-names = "uartclk", "apb_pclk";
+-			};
+-
+-			v2m_serial3: uart@0c0000 {
+-				compatible = "arm,pl011", "arm,primecell";
+-				reg = <0x0c0000 0x1000>;
+-				interrupts = <8>;
+-				clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
+-				clock-names = "uartclk", "apb_pclk";
+-			};
+-
+-			wdt@0f0000 {
+-				compatible = "arm,sp805", "arm,primecell";
+-				reg = <0x0f0000 0x1000>;
+-				interrupts = <0>;
+-				clocks = <&v2m_refclk32khz>, <&v2m_clk24mhz>;
+-				clock-names = "wdogclk", "apb_pclk";
+-			};
+-
+-			v2m_timer01: timer@110000 {
+-				compatible = "arm,sp804", "arm,primecell";
+-				reg = <0x110000 0x1000>;
+-				interrupts = <2>;
+-				clocks = <&v2m_sysctl 0>, <&v2m_sysctl 1>, <&v2m_clk24mhz>;
+-				clock-names = "timclken1", "timclken2", "apb_pclk";
+-			};
+-
+-			v2m_timer23: timer@120000 {
+-				compatible = "arm,sp804", "arm,primecell";
+-				reg = <0x120000 0x1000>;
+-				interrupts = <3>;
+-				clocks = <&v2m_sysctl 2>, <&v2m_sysctl 3>, <&v2m_clk24mhz>;
+-				clock-names = "timclken1", "timclken2", "apb_pclk";
+-			};
+-
+-			rtc@170000 {
+-				compatible = "arm,pl031", "arm,primecell";
+-				reg = <0x170000 0x1000>;
+-				interrupts = <4>;
+-				clocks = <&v2m_clk24mhz>;
+-				clock-names = "apb_pclk";
+-			};
+-
+-			clcd@1f0000 {
+-				compatible = "arm,pl111", "arm,primecell";
+-				reg = <0x1f0000 0x1000>;
+-				interrupt-names = "combined";
+-				interrupts = <14>;
+-				clocks = <&v2m_oscclk1>, <&v2m_clk24mhz>;
+-				clock-names = "clcdclk", "apb_pclk";
+-				arm,pl11x,framebuffer = <0x18000000 0x00180000>;
+-				memory-region = <&v2m_video_ram>;
+-				max-memory-bandwidth = <130000000>; /* 16bpp @ 63.5MHz */
+-
+-				port {
+-					v2m_clcd_pads: endpoint {
+-						remote-endpoint = <&v2m_clcd_panel>;
+-						arm,pl11x,tft-r0g0b0-pads = <0 8 16>;
+-					};
+-				};
+-
+-				panel {
+-					compatible = "panel-dpi";
+-
+-					port {
+-						v2m_clcd_panel: endpoint {
+-							remote-endpoint = <&v2m_clcd_pads>;
+-						};
+-					};
+-
+-					panel-timing {
+-						clock-frequency = <63500127>;
+-						hactive = <1024>;
+-						hback-porch = <152>;
+-						hfront-porch = <48>;
+-						hsync-len = <104>;
+-						vactive = <768>;
+-						vback-porch = <23>;
+-						vfront-porch = <3>;
+-						vsync-len = <4>;
+-					};
+-				};
+-			};
+-
+-			virtio_block@0130000 {
+-				compatible = "virtio,mmio";
+-				reg = <0x130000 0x200>;
+-				interrupts = <42>;
+-			};
+-		};
+-
+-		v2m_fixed_3v3: fixedregulator@0 {
+-			compatible = "regulator-fixed";
+-			regulator-name = "3V3";
+-			regulator-min-microvolt = <3300000>;
+-			regulator-max-microvolt = <3300000>;
+-			regulator-always-on;
+-		};
+-
+-		mcc {
+-			compatible = "arm,vexpress,config-bus";
+-			arm,vexpress,config-bridge = <&v2m_sysreg>;
+-
+-			v2m_oscclk1: osc@1 {
+-				/* CLCD clock */
+-				compatible = "arm,vexpress-osc";
+-				arm,vexpress-sysreg,func = <1 1>;
+-				freq-range = <23750000 63500000>;
+-				#clock-cells = <0>;
+-				clock-output-names = "v2m:oscclk1";
+-			};
+-
+-			reset@0 {
+-				compatible = "arm,vexpress-reset";
+-				arm,vexpress-sysreg,func = <5 0>;
+-			};
+-
+-			muxfpga@0 {
+-				compatible = "arm,vexpress-muxfpga";
+-				arm,vexpress-sysreg,func = <7 0>;
+-			};
+-
+-			shutdown@0 {
+-				compatible = "arm,vexpress-shutdown";
+-				arm,vexpress-sysreg,func = <8 0>;
+-			};
+-
+-			reboot@0 {
+-				compatible = "arm,vexpress-reboot";
+-				arm,vexpress-sysreg,func = <9 0>;
+-			};
+-
+-			dvimode@0 {
+-				compatible = "arm,vexpress-dvimode";
+-				arm,vexpress-sysreg,func = <11 0>;
+-			};
+-		};
+-	};
+diff --git a/arch/arm64/boot/dts/thunder-88xx.dts b/arch/arm64/boot/dts/thunder-88xx.dts
+deleted file mode 100644
+index 800ba65..0000000
+--- a/arch/arm64/boot/dts/thunder-88xx.dts
++++ /dev/null
+@@ -1,67 +0,0 @@
+-/*
+- * Cavium Thunder DTS file - Thunder board description
+- *
+- * Copyright (C) 2014, Cavium Inc.
+- *
+- * This file is dual-licensed: you can use it either under the terms
+- * of the GPL or the X11 license, at your option. Note that this dual
+- * licensing only applies to this file, and not this project as a
+- * whole.
+- *
+- *  a) This library 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 library 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 library; if not, write to the Free
+- *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+- *     MA 02110-1301 USA
+- *
+- * Or, alternatively,
+- *
+- *  b) Permission is hereby granted, free of charge, to any person
+- *     obtaining a copy of this software and associated documentation
+- *     files (the "Software"), to deal in the Software without
+- *     restriction, including without limitation the rights to use,
+- *     copy, modify, merge, publish, distribute, sublicense, and/or
+- *     sell copies of the Software, and to permit persons to whom the
+- *     Software is furnished to do so, subject to the following
+- *     conditions:
+- *
+- *     The above copyright notice and this permission notice shall be
+- *     included in all copies or substantial portions of the Software.
+- *
+- *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+- *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+- *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+- *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+- *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+- *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+- *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+- *     OTHER DEALINGS IN THE SOFTWARE.
+- */
+-
+-/dts-v1/;
+-
+-/include/ "thunder-88xx.dtsi"
+-
+-/ {
+-	model = "Cavium ThunderX CN88XX board";
+-	compatible = "cavium,thunder-88xx";
+-
+-	aliases {
+-		serial0 = &uaa0;
+-		serial1 = &uaa1;
+-	};
+-
+-	memory@00000000 {
+-		device_type = "memory";
+-		reg = <0x0 0x00000000 0x0 0x80000000>;
+-	};
+-};
+diff --git a/arch/arm64/boot/dts/thunder-88xx.dtsi b/arch/arm64/boot/dts/thunder-88xx.dtsi
+deleted file mode 100644
+index d8c0bdc..0000000
+--- a/arch/arm64/boot/dts/thunder-88xx.dtsi
++++ /dev/null
+@@ -1,401 +0,0 @@
+-/*
+- * Cavium Thunder DTS file - Thunder SoC description
+- *
+- * Copyright (C) 2014, Cavium Inc.
+- *
+- * This file is dual-licensed: you can use it either under the terms
+- * of the GPL or the X11 license, at your option. Note that this dual
+- * licensing only applies to this file, and not this project as a
+- * whole.
+- *
+- *  a) This library 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 library 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 library; if not, write to the Free
+- *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+- *     MA 02110-1301 USA
+- *
+- * Or, alternatively,
+- *
+- *  b) Permission is hereby granted, free of charge, to any person
+- *     obtaining a copy of this software and associated documentation
+- *     files (the "Software"), to deal in the Software without
+- *     restriction, including without limitation the rights to use,
+- *     copy, modify, merge, publish, distribute, sublicense, and/or
+- *     sell copies of the Software, and to permit persons to whom the
+- *     Software is furnished to do so, subject to the following
+- *     conditions:
+- *
+- *     The above copyright notice and this permission notice shall be
+- *     included in all copies or substantial portions of the Software.
+- *
+- *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+- *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+- *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+- *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+- *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+- *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+- *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+- *     OTHER DEALINGS IN THE SOFTWARE.
+- */
+-
+-/ {
+-	compatible = "cavium,thunder-88xx";
+-	interrupt-parent = <&gic0>;
+-	#address-cells = <2>;
+-	#size-cells = <2>;
+-
+-	psci {
+-		compatible = "arm,psci-0.2";
+-		method = "smc";
+-	};
+-
+-	cpus {
+-		#address-cells = <2>;
+-		#size-cells = <0>;
+-
+-		cpu@000 {
+-			device_type = "cpu";
+-			compatible = "cavium,thunder", "arm,armv8";
+-			reg = <0x0 0x000>;
+-			enable-method = "psci";
+-		};
+-		cpu@001 {
+-			device_type = "cpu";
+-			compatible = "cavium,thunder", "arm,armv8";
+-			reg = <0x0 0x001>;
+-			enable-method = "psci";
+-		};
+-		cpu@002 {
+-			device_type = "cpu";
+-			compatible = "cavium,thunder", "arm,armv8";
+-			reg = <0x0 0x002>;
+-			enable-method = "psci";
+-		};
+-		cpu@003 {
+-			device_type = "cpu";
+-			compatible = "cavium,thunder", "arm,armv8";
+-			reg = <0x0 0x003>;
+-			enable-method = "psci";
+-		};
+-		cpu@004 {
+-			device_type = "cpu";
+-			compatible = "cavium,thunder", "arm,armv8";
+-			reg = <0x0 0x004>;
+-			enable-method = "psci";
+-		};
+-		cpu@005 {
+-			device_type = "cpu";
+-			compatible = "cavium,thunder", "arm,armv8";
+-			reg = <0x0 0x005>;
+-			enable-method = "psci";
+-		};
+-		cpu@006 {
+-			device_type = "cpu";
+-			compatible = "cavium,thunder", "arm,armv8";
+-			reg = <0x0 0x006>;
+-			enable-method = "psci";
+-		};
+-		cpu@007 {
+-			device_type = "cpu";
+-			compatible = "cavium,thunder", "arm,armv8";
+-			reg = <0x0 0x007>;
+-			enable-method = "psci";
+-		};
+-		cpu@008 {
+-			device_type = "cpu";
+-			compatible = "cavium,thunder", "arm,armv8";
+-			reg = <0x0 0x008>;
+-			enable-method = "psci";
+-		};
+-		cpu@009 {
+-			device_type = "cpu";
+-			compatible = "cavium,thunder", "arm,armv8";
+-			reg = <0x0 0x009>;
+-			enable-method = "psci";
+-		};
+-		cpu@00a {
+-			device_type = "cpu";
+-			compatible = "cavium,thunder", "arm,armv8";
+-			reg = <0x0 0x00a>;
+-			enable-method = "psci";
+-		};
+-		cpu@00b {
+-			device_type = "cpu";
+-			compatible = "cavium,thunder", "arm,armv8";
+-			reg = <0x0 0x00b>;
+-			enable-method = "psci";
+-		};
+-		cpu@00c {
+-			device_type = "cpu";
+-			compatible = "cavium,thunder", "arm,armv8";
+-			reg = <0x0 0x00c>;
+-			enable-method = "psci";
+-		};
+-		cpu@00d {
+-			device_type = "cpu";
+-			compatible = "cavium,thunder", "arm,armv8";
+-			reg = <0x0 0x00d>;
+-			enable-method = "psci";
+-		};
+-		cpu@00e {
+-			device_type = "cpu";
+-			compatible = "cavium,thunder", "arm,armv8";
+-			reg = <0x0 0x00e>;
+-			enable-method = "psci";
+-		};
+-		cpu@00f {
+-			device_type = "cpu";
+-			compatible = "cavium,thunder", "arm,armv8";
+-			reg = <0x0 0x00f>;
+-			enable-method = "psci";
+-		};
+-		cpu@100 {
+-			device_type = "cpu";
+-			compatible = "cavium,thunder", "arm,armv8";
+-			reg = <0x0 0x100>;
+-			enable-method = "psci";
+-		};
+-		cpu@101 {
+-			device_type = "cpu";
+-			compatible = "cavium,thunder", "arm,armv8";
+-			reg = <0x0 0x101>;
+-			enable-method = "psci";
+-		};
+-		cpu@102 {
+-			device_type = "cpu";
+-			compatible = "cavium,thunder", "arm,armv8";
+-			reg = <0x0 0x102>;
+-			enable-method = "psci";
+-		};
+-		cpu@103 {
+-			device_type = "cpu";
+-			compatible = "cavium,thunder", "arm,armv8";
+-			reg = <0x0 0x103>;
+-			enable-method = "psci";
+-		};
+-		cpu@104 {
+-			device_type = "cpu";
+-			compatible = "cavium,thunder", "arm,armv8";
+-			reg = <0x0 0x104>;
+-			enable-method = "psci";
+-		};
+-		cpu@105 {
+-			device_type = "cpu";
+-			compatible = "cavium,thunder", "arm,armv8";
+-			reg = <0x0 0x105>;
+-			enable-method = "psci";
+-		};
+-		cpu@106 {
+-			device_type = "cpu";
+-			compatible = "cavium,thunder", "arm,armv8";
+-			reg = <0x0 0x106>;
+-			enable-method = "psci";
+-		};
+-		cpu@107 {
+-			device_type = "cpu";
+-			compatible = "cavium,thunder", "arm,armv8";
+-			reg = <0x0 0x107>;
+-			enable-method = "psci";
+-		};
+-		cpu@108 {
+-			device_type = "cpu";
+-			compatible = "cavium,thunder", "arm,armv8";
+-			reg = <0x0 0x108>;
+-			enable-method = "psci";
+-		};
+-		cpu@109 {
+-			device_type = "cpu";
+-			compatible = "cavium,thunder", "arm,armv8";
+-			reg = <0x0 0x109>;
+-			enable-method = "psci";
+-		};
+-		cpu@10a {
+-			device_type = "cpu";
+-			compatible = "cavium,thunder", "arm,armv8";
+-			reg = <0x0 0x10a>;
+-			enable-method = "psci";
+-		};
+-		cpu@10b {
+-			device_type = "cpu";
+-			compatible = "cavium,thunder", "arm,armv8";
+-			reg = <0x0 0x10b>;
+-			enable-method = "psci";
+-		};
+-		cpu@10c {
+-			device_type = "cpu";
+-			compatible = "cavium,thunder", "arm,armv8";
+-			reg = <0x0 0x10c>;
+-			enable-method = "psci";
+-		};
+-		cpu@10d {
+-			device_type = "cpu";
+-			compatible = "cavium,thunder", "arm,armv8";
+-			reg = <0x0 0x10d>;
+-			enable-method = "psci";
+-		};
+-		cpu@10e {
+-			device_type = "cpu";
+-			compatible = "cavium,thunder", "arm,armv8";
+-			reg = <0x0 0x10e>;
+-			enable-method = "psci";
+-		};
+-		cpu@10f {
+-			device_type = "cpu";
+-			compatible = "cavium,thunder", "arm,armv8";
+-			reg = <0x0 0x10f>;
+-			enable-method = "psci";
+-		};
+-		cpu@200 {
+-			device_type = "cpu";
+-			compatible = "cavium,thunder", "arm,armv8";
+-			reg = <0x0 0x200>;
+-			enable-method = "psci";
+-		};
+-		cpu@201 {
+-			device_type = "cpu";
+-			compatible = "cavium,thunder", "arm,armv8";
+-			reg = <0x0 0x201>;
+-			enable-method = "psci";
+-		};
+-		cpu@202 {
+-			device_type = "cpu";
+-			compatible = "cavium,thunder", "arm,armv8";
+-			reg = <0x0 0x202>;
+-			enable-method = "psci";
+-		};
+-		cpu@203 {
+-			device_type = "cpu";
+-			compatible = "cavium,thunder", "arm,armv8";
+-			reg = <0x0 0x203>;
+-			enable-method = "psci";
+-		};
+-		cpu@204 {
+-			device_type = "cpu";
+-			compatible = "cavium,thunder", "arm,armv8";
+-			reg = <0x0 0x204>;
+-			enable-method = "psci";
+-		};
+-		cpu@205 {
+-			device_type = "cpu";
+-			compatible = "cavium,thunder", "arm,armv8";
+-			reg = <0x0 0x205>;
+-			enable-method = "psci";
+-		};
+-		cpu@206 {
+-			device_type = "cpu";
+-			compatible = "cavium,thunder", "arm,armv8";
+-			reg = <0x0 0x206>;
+-			enable-method = "psci";
+-		};
+-		cpu@207 {
+-			device_type = "cpu";
+-			compatible = "cavium,thunder", "arm,armv8";
+-			reg = <0x0 0x207>;
+-			enable-method = "psci";
+-		};
+-		cpu@208 {
+-			device_type = "cpu";
+-			compatible = "cavium,thunder", "arm,armv8";
+-			reg = <0x0 0x208>;
+-			enable-method = "psci";
+-		};
+-		cpu@209 {
+-			device_type = "cpu";
+-			compatible = "cavium,thunder", "arm,armv8";
+-			reg = <0x0 0x209>;
+-			enable-method = "psci";
+-		};
+-		cpu@20a {
+-			device_type = "cpu";
+-			compatible = "cavium,thunder", "arm,armv8";
+-			reg = <0x0 0x20a>;
+-			enable-method = "psci";
+-		};
+-		cpu@20b {
+-			device_type = "cpu";
+-			compatible = "cavium,thunder", "arm,armv8";
+-			reg = <0x0 0x20b>;
+-			enable-method = "psci";
+-		};
+-		cpu@20c {
+-			device_type = "cpu";
+-			compatible = "cavium,thunder", "arm,armv8";
+-			reg = <0x0 0x20c>;
+-			enable-method = "psci";
+-		};
+-		cpu@20d {
+-			device_type = "cpu";
+-			compatible = "cavium,thunder", "arm,armv8";
+-			reg = <0x0 0x20d>;
+-			enable-method = "psci";
+-		};
+-		cpu@20e {
+-			device_type = "cpu";
+-			compatible = "cavium,thunder", "arm,armv8";
+-			reg = <0x0 0x20e>;
+-			enable-method = "psci";
+-		};
+-		cpu@20f {
+-			device_type = "cpu";
+-			compatible = "cavium,thunder", "arm,armv8";
+-			reg = <0x0 0x20f>;
+-			enable-method = "psci";
+-		};
+-	};
+-
+-	timer {
+-		compatible = "arm,armv8-timer";
+-		interrupts = <1 13 0xff01>,
+-		             <1 14 0xff01>,
+-		             <1 11 0xff01>,
+-		             <1 10 0xff01>;
+-	};
+-
+-	soc {
+-		compatible = "simple-bus";
+-		#address-cells = <2>;
+-		#size-cells = <2>;
+-		ranges;
+-
+-		refclk50mhz: refclk50mhz {
+-			compatible = "fixed-clock";
+-			#clock-cells = <0>;
+-			clock-frequency = <50000000>;
+-			clock-output-names = "refclk50mhz";
+-		};
+-
+-		gic0: interrupt-controller@8010,00000000 {
+-			compatible = "arm,gic-v3";
+-			#interrupt-cells = <3>;
+-			interrupt-controller;
+-			reg = <0x8010 0x00000000 0x0 0x010000>, /* GICD */
+-			      <0x8010 0x80000000 0x0 0x600000>; /* GICR */
+-			interrupts = <1 9 0xf04>;
+-		};
+-
+-		uaa0: serial@87e0,24000000 {
+-			compatible = "arm,pl011", "arm,primecell";
+-			reg = <0x87e0 0x24000000 0x0 0x1000>;
+-			interrupts = <1 21 4>;
+-			clocks = <&refclk50mhz>;
+-			clock-names = "apb_pclk";
+-		};
+-
+-		uaa1: serial@87e0,25000000 {
+-			compatible = "arm,pl011", "arm,primecell";
+-			reg = <0x87e0 0x25000000 0x0 0x1000>;
+-			interrupts = <1 22 4>;
+-			clocks = <&refclk50mhz>;
+-			clock-names = "apb_pclk";
+-		};
+-	};
+-};
+diff --git a/arch/arm64/include/asm/compat.h b/arch/arm64/include/asm/compat.h
+index 56de5aa..3fb053f 100644
+--- a/arch/arm64/include/asm/compat.h
++++ b/arch/arm64/include/asm/compat.h
+@@ -205,6 +205,13 @@ typedef struct compat_siginfo {
+ 			compat_long_t _band;	/* POLL_IN, POLL_OUT, POLL_MSG */
+ 			int _fd;
+ 		} _sigpoll;
++
++		/* SIGSYS */
++		struct {
++			compat_uptr_t _call_addr; /* calling user insn */
++			int _syscall;	/* triggering system call number */
++			compat_uint_t _arch;	/* AUDIT_ARCH_* of syscall */
++		} _sigsys;
+ 	} _sifields;
+ } compat_siginfo_t;
+ 
+diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
+index c008bae..3ae74b5 100644
+--- a/arch/arm64/include/asm/cpufeature.h
++++ b/arch/arm64/include/asm/cpufeature.h
+@@ -54,6 +54,9 @@ static inline void cpus_set_cap(unsigned int num)
+ 
+ void check_local_cpu_errata(void);
+ 
++bool cpu_supports_mixed_endian_el0(void);
++bool system_supports_mixed_endian_el0(void);
++
+ #endif /* __ASSEMBLY__ */
+ 
+ #endif
+diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h
+index 8adb986..a84ec60 100644
+--- a/arch/arm64/include/asm/cputype.h
++++ b/arch/arm64/include/asm/cputype.h
+@@ -72,6 +72,18 @@
+ 
+ #define APM_CPU_PART_POTENZA	0x000
+ 
++#define ID_AA64MMFR0_BIGENDEL0_SHIFT	16
++#define ID_AA64MMFR0_BIGENDEL0_MASK	(0xf << ID_AA64MMFR0_BIGENDEL0_SHIFT)
++#define ID_AA64MMFR0_BIGENDEL0(mmfr0)	\
++	(((mmfr0) & ID_AA64MMFR0_BIGENDEL0_MASK) >> ID_AA64MMFR0_BIGENDEL0_SHIFT)
++#define ID_AA64MMFR0_BIGEND_SHIFT	8
++#define ID_AA64MMFR0_BIGEND_MASK	(0xf << ID_AA64MMFR0_BIGEND_SHIFT)
++#define ID_AA64MMFR0_BIGEND(mmfr0)	\
++	(((mmfr0) & ID_AA64MMFR0_BIGEND_MASK) >> ID_AA64MMFR0_BIGEND_SHIFT)
++
++#define SCTLR_EL1_CP15BEN	(0x1 << 5)
++#define SCTLR_EL1_SED		(0x1 << 8)
++
+ #ifndef __ASSEMBLY__
+ 
+ /*
+@@ -104,6 +116,11 @@ static inline u32 __attribute_const__ read_cpuid_cachetype(void)
+ 	return read_cpuid(CTR_EL0);
+ }
+ 
++static inline bool id_aa64mmfr0_mixed_endian_el0(u64 mmfr0)
++{
++	return (ID_AA64MMFR0_BIGEND(mmfr0) == 0x1) ||
++		(ID_AA64MMFR0_BIGENDEL0(mmfr0) == 0x1);
++}
+ #endif /* __ASSEMBLY__ */
+ 
+ #endif
+diff --git a/arch/arm64/include/asm/insn.h b/arch/arm64/include/asm/insn.h
+index 56a9e63..e2ff32a 100644
+--- a/arch/arm64/include/asm/insn.h
++++ b/arch/arm64/include/asm/insn.h
+@@ -354,6 +354,16 @@ bool aarch64_insn_hotpatch_safe(u32 old_insn, u32 new_insn);
+ int aarch64_insn_patch_text_nosync(void *addr, u32 insn);
+ int aarch64_insn_patch_text_sync(void *addrs[], u32 insns[], int cnt);
+ int aarch64_insn_patch_text(void *addrs[], u32 insns[], int cnt);
++
++bool aarch32_insn_is_wide(u32 insn);
++
++#define A32_RN_OFFSET	16
++#define A32_RT_OFFSET	12
++#define A32_RT2_OFFSET	 0
++
++u32 aarch32_insn_extract_reg_num(u32 insn, int offset);
++u32 aarch32_insn_mcr_extract_opc2(u32 insn);
++u32 aarch32_insn_mcr_extract_crm(u32 insn);
+ #endif /* __ASSEMBLY__ */
+ 
+ #endif	/* __ASM_INSN_H */
+diff --git a/arch/arm64/include/asm/opcodes.h b/arch/arm64/include/asm/opcodes.h
+new file mode 100644
+index 0000000..4e603ea
+--- /dev/null
++++ b/arch/arm64/include/asm/opcodes.h
+@@ -0,0 +1 @@
++#include <../../arm/include/asm/opcodes.h>
+diff --git a/arch/arm64/include/asm/ptrace.h b/arch/arm64/include/asm/ptrace.h
+index 41ed9e1..d6dd9fd 100644
+--- a/arch/arm64/include/asm/ptrace.h
++++ b/arch/arm64/include/asm/ptrace.h
+@@ -58,6 +58,13 @@
+ #define COMPAT_PSR_Z_BIT	0x40000000
+ #define COMPAT_PSR_N_BIT	0x80000000
+ #define COMPAT_PSR_IT_MASK	0x0600fc00	/* If-Then execution state mask */
++
++#ifdef CONFIG_CPU_BIG_ENDIAN
++#define COMPAT_PSR_ENDSTATE	COMPAT_PSR_E_BIT
++#else
++#define COMPAT_PSR_ENDSTATE	0
++#endif
++
+ /*
+  * These are 'magic' values for PTRACE_PEEKUSR that return info about where a
+  * process is located in memory.
+diff --git a/arch/arm64/include/asm/seccomp.h b/arch/arm64/include/asm/seccomp.h
+new file mode 100644
+index 0000000..c76fac9
+--- /dev/null
++++ b/arch/arm64/include/asm/seccomp.h
+@@ -0,0 +1,25 @@
++/*
++ * arch/arm64/include/asm/seccomp.h
++ *
++ * Copyright (C) 2014 Linaro Limited
++ * Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++#ifndef _ASM_SECCOMP_H
++#define _ASM_SECCOMP_H
++
++#include <asm/unistd.h>
++
++#ifdef CONFIG_COMPAT
++#define __NR_seccomp_read_32		__NR_compat_read
++#define __NR_seccomp_write_32		__NR_compat_write
++#define __NR_seccomp_exit_32		__NR_compat_exit
++#define __NR_seccomp_sigreturn_32	__NR_compat_rt_sigreturn
++#endif /* CONFIG_COMPAT */
++
++#include <asm-generic/seccomp.h>
++
++#endif /* _ASM_SECCOMP_H */
+diff --git a/arch/arm64/include/asm/traps.h b/arch/arm64/include/asm/traps.h
+index 10ca8ff..232e4ba 100644
+--- a/arch/arm64/include/asm/traps.h
++++ b/arch/arm64/include/asm/traps.h
+@@ -18,6 +18,22 @@
+ #ifndef __ASM_TRAP_H
+ #define __ASM_TRAP_H
+ 
++#include <linux/list.h>
++
++struct pt_regs;
++
++struct undef_hook {
++	struct list_head node;
++	u32 instr_mask;
++	u32 instr_val;
++	u64 pstate_mask;
++	u64 pstate_val;
++	int (*fn)(struct pt_regs *regs, u32 instr);
++};
++
++void register_undef_hook(struct undef_hook *hook);
++void unregister_undef_hook(struct undef_hook *hook);
++
+ static inline int in_exception_text(unsigned long ptr)
+ {
+ 	extern char __exception_text_start[];
+diff --git a/arch/arm64/include/asm/unistd.h b/arch/arm64/include/asm/unistd.h
+index 6d2bf41..49c9aef 100644
+--- a/arch/arm64/include/asm/unistd.h
++++ b/arch/arm64/include/asm/unistd.h
+@@ -31,6 +31,9 @@
+  * Compat syscall numbers used by the AArch64 kernel.
+  */
+ #define __NR_compat_restart_syscall	0
++#define __NR_compat_exit		1
++#define __NR_compat_read		3
++#define __NR_compat_write		4
+ #define __NR_compat_sigreturn		119
+ #define __NR_compat_rt_sigreturn	173
+ 
+diff --git a/arch/arm64/include/asm/unistd32.h b/arch/arm64/include/asm/unistd32.h
+index 9dfdac4..8893ceb 100644
+--- a/arch/arm64/include/asm/unistd32.h
++++ b/arch/arm64/include/asm/unistd32.h
+@@ -787,7 +787,8 @@ __SYSCALL(__NR_sched_setattr, sys_sched_setattr)
+ __SYSCALL(__NR_sched_getattr, sys_sched_getattr)
+ #define __NR_renameat2 382
+ __SYSCALL(__NR_renameat2, sys_renameat2)
+-			/* 383 for seccomp */
++#define __NR_seccomp 383
++__SYSCALL(__NR_seccomp, sys_seccomp)
+ #define __NR_getrandom 384
+ __SYSCALL(__NR_getrandom, sys_getrandom)
+ #define __NR_memfd_create 385
+diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
+index da22728..0a44aa5 100644
+--- a/arch/arm64/kernel/Makefile
++++ b/arch/arm64/kernel/Makefile
+@@ -5,6 +5,7 @@
+ CPPFLAGS_vmlinux.lds	:= -DTEXT_OFFSET=$(TEXT_OFFSET)
+ AFLAGS_head.o		:= -DTEXT_OFFSET=$(TEXT_OFFSET)
+ CFLAGS_efi-stub.o 	:= -DTEXT_OFFSET=$(TEXT_OFFSET)
++CFLAGS_armv8_deprecated.o := -I$(src)
+ 
+ CFLAGS_REMOVE_ftrace.o = -pg
+ CFLAGS_REMOVE_insn.o = -pg
+@@ -14,11 +15,12 @@ CFLAGS_REMOVE_return_address.o = -pg
+ arm64-obj-y		:= cputable.o debug-monitors.o entry.o irq.o fpsimd.o	\
+ 			   entry-fpsimd.o process.o ptrace.o setup.o signal.o	\
+ 			   sys.o stacktrace.o time.o traps.o io.o vdso.o	\
+-			   hyp-stub.o psci.o cpu_ops.o insn.o return_address.o	\
+-			   cpuinfo.o cpu_errata.o alternative.o
++			   hyp-stub.o psci.o psci-call.o cpu_ops.o insn.o 	\
++			   return_address.o cpuinfo.o cpu_errata.o alternative.o
+ 
+ arm64-obj-$(CONFIG_COMPAT)		+= sys32.o kuser32.o signal32.o 	\
+-					   sys_compat.o
++					   sys_compat.o				\
++					   ../../arm/kernel/opcodes.o
+ arm64-obj-$(CONFIG_FUNCTION_TRACER)	+= ftrace.o entry-ftrace.o
+ arm64-obj-$(CONFIG_MODULES)		+= arm64ksyms.o module.o
+ arm64-obj-$(CONFIG_SMP)			+= smp.o smp_spin_table.o topology.o
+@@ -31,6 +33,7 @@ arm64-obj-$(CONFIG_JUMP_LABEL)		+= jump_label.o
+ arm64-obj-$(CONFIG_KGDB)		+= kgdb.o
+ arm64-obj-$(CONFIG_EFI)			+= efi.o efi-stub.o efi-entry.o
+ arm64-obj-$(CONFIG_PCI)			+= pci.o
++arm64-obj-$(CONFIG_ARMV8_DEPRECATED)	+= armv8_deprecated.o
+ 
+ obj-y					+= $(arm64-obj-y) vdso/
+ obj-m					+= $(arm64-obj-m)
+diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c
+new file mode 100644
+index 0000000..7922c2e
+--- /dev/null
++++ b/arch/arm64/kernel/armv8_deprecated.c
+@@ -0,0 +1,662 @@
++/*
++ *  Copyright (C) 2014 ARM Limited
++ *
++ * 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/cpu.h>
++#include <linux/init.h>
++#include <linux/list.h>
++#include <linux/perf_event.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/sysctl.h>
++
++#include <asm/insn.h>
++#include <asm/opcodes.h>
++#include <asm/system_misc.h>
++#include <asm/traps.h>
++#include <asm/uaccess.h>
++#include <asm/cpufeature.h>
++
++#define CREATE_TRACE_POINTS
++#include "trace-events-emulation.h"
++
++/*
++ * The runtime support for deprecated instruction support can be in one of
++ * following three states -
++ *
++ * 0 = undef
++ * 1 = emulate (software emulation)
++ * 2 = hw (supported in hardware)
++ */
++enum insn_emulation_mode {
++	INSN_UNDEF,
++	INSN_EMULATE,
++	INSN_HW,
++};
++
++enum legacy_insn_status {
++	INSN_DEPRECATED,
++	INSN_OBSOLETE,
++};
++
++struct insn_emulation_ops {
++	const char		*name;
++	enum legacy_insn_status	status;
++	struct undef_hook	*hooks;
++	int			(*set_hw_mode)(bool enable);
++};
++
++struct insn_emulation {
++	struct list_head node;
++	struct insn_emulation_ops *ops;
++	int current_mode;
++	int min;
++	int max;
++};
++
++static LIST_HEAD(insn_emulation);
++static int nr_insn_emulated;
++static DEFINE_RAW_SPINLOCK(insn_emulation_lock);
++
++static void register_emulation_hooks(struct insn_emulation_ops *ops)
++{
++	struct undef_hook *hook;
++
++	BUG_ON(!ops->hooks);
++
++	for (hook = ops->hooks; hook->instr_mask; hook++)
++		register_undef_hook(hook);
++
++	pr_notice("Registered %s emulation handler\n", ops->name);
++}
++
++static void remove_emulation_hooks(struct insn_emulation_ops *ops)
++{
++	struct undef_hook *hook;
++
++	BUG_ON(!ops->hooks);
++
++	for (hook = ops->hooks; hook->instr_mask; hook++)
++		unregister_undef_hook(hook);
++
++	pr_notice("Removed %s emulation handler\n", ops->name);
++}
++
++static void enable_insn_hw_mode(void *data)
++{
++	struct insn_emulation *insn = (struct insn_emulation *)data;
++	if (insn->ops->set_hw_mode)
++		insn->ops->set_hw_mode(true);
++}
++
++static void disable_insn_hw_mode(void *data)
++{
++	struct insn_emulation *insn = (struct insn_emulation *)data;
++	if (insn->ops->set_hw_mode)
++		insn->ops->set_hw_mode(false);
++}
++
++/* Run set_hw_mode(mode) on all active CPUs */
++static int run_all_cpu_set_hw_mode(struct insn_emulation *insn, bool enable)
++{
++	if (!insn->ops->set_hw_mode)
++		return -EINVAL;
++	if (enable)
++		on_each_cpu(enable_insn_hw_mode, (void *)insn, true);
++	else
++		on_each_cpu(disable_insn_hw_mode, (void *)insn, true);
++	return 0;
++}
++
++/*
++ * Run set_hw_mode for all insns on a starting CPU.
++ * Returns:
++ *  0 		- If all the hooks ran successfully.
++ * -EINVAL	- At least one hook is not supported by the CPU.
++ */
++static int run_all_insn_set_hw_mode(unsigned long cpu)
++{
++	int rc = 0;
++	unsigned long flags;
++	struct insn_emulation *insn;
++
++	raw_spin_lock_irqsave(&insn_emulation_lock, flags);
++	list_for_each_entry(insn, &insn_emulation, node) {
++		bool enable = (insn->current_mode == INSN_HW);
++		if (insn->ops->set_hw_mode && insn->ops->set_hw_mode(enable)) {
++			pr_warn("CPU[%ld] cannot support the emulation of %s",
++				cpu, insn->ops->name);
++			rc = -EINVAL;
++		}
++	}
++	raw_spin_unlock_irqrestore(&insn_emulation_lock, flags);
++	return rc;
++}
++
++static int update_insn_emulation_mode(struct insn_emulation *insn,
++				       enum insn_emulation_mode prev)
++{
++	int ret = 0;
++
++	switch (prev) {
++	case INSN_UNDEF: /* Nothing to be done */
++		break;
++	case INSN_EMULATE:
++		remove_emulation_hooks(insn->ops);
++		break;
++	case INSN_HW:
++		if (!run_all_cpu_set_hw_mode(insn, false))
++			pr_notice("Disabled %s support\n", insn->ops->name);
++		break;
++	}
++
++	switch (insn->current_mode) {
++	case INSN_UNDEF:
++		break;
++	case INSN_EMULATE:
++		register_emulation_hooks(insn->ops);
++		break;
++	case INSN_HW:
++		ret = run_all_cpu_set_hw_mode(insn, true);
++		if (!ret)
++			pr_notice("Enabled %s support\n", insn->ops->name);
++		break;
++	}
++
++	return ret;
++}
++
++static void register_insn_emulation(struct insn_emulation_ops *ops)
++{
++	unsigned long flags;
++	struct insn_emulation *insn;
++
++	insn = kzalloc(sizeof(*insn), GFP_KERNEL);
++	insn->ops = ops;
++	insn->min = INSN_UNDEF;
++
++	switch (ops->status) {
++	case INSN_DEPRECATED:
++		insn->current_mode = INSN_EMULATE;
++		/* Disable the HW mode if it was turned on at early boot time */
++		run_all_cpu_set_hw_mode(insn, false);
++		insn->max = INSN_HW;
++		break;
++	case INSN_OBSOLETE:
++		insn->current_mode = INSN_UNDEF;
++		insn->max = INSN_EMULATE;
++		break;
++	}
++
++	raw_spin_lock_irqsave(&insn_emulation_lock, flags);
++	list_add(&insn->node, &insn_emulation);
++	nr_insn_emulated++;
++	raw_spin_unlock_irqrestore(&insn_emulation_lock, flags);
++
++	/* Register any handlers if required */
++	update_insn_emulation_mode(insn, INSN_UNDEF);
++}
++
++static int emulation_proc_handler(struct ctl_table *table, int write,
++				  void __user *buffer, size_t *lenp,
++				  loff_t *ppos)
++{
++	int ret = 0;
++	struct insn_emulation *insn = (struct insn_emulation *) table->data;
++	enum insn_emulation_mode prev_mode = insn->current_mode;
++
++	table->data = &insn->current_mode;
++	ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
++
++	if (ret || !write || prev_mode == insn->current_mode)
++		goto ret;
++
++	ret = update_insn_emulation_mode(insn, prev_mode);
++	if (ret) {
++		/* Mode change failed, revert to previous mode. */
++		insn->current_mode = prev_mode;
++		update_insn_emulation_mode(insn, INSN_UNDEF);
++	}
++ret:
++	table->data = insn;
++	return ret;
++}
++
++static struct ctl_table ctl_abi[] = {
++	{
++		.procname = "abi",
++		.mode = 0555,
++	},
++	{ }
++};
++
++static void register_insn_emulation_sysctl(struct ctl_table *table)
++{
++	unsigned long flags;
++	int i = 0;
++	struct insn_emulation *insn;
++	struct ctl_table *insns_sysctl, *sysctl;
++
++	insns_sysctl = kzalloc(sizeof(*sysctl) * (nr_insn_emulated + 1),
++			      GFP_KERNEL);
++
++	raw_spin_lock_irqsave(&insn_emulation_lock, flags);
++	list_for_each_entry(insn, &insn_emulation, node) {
++		sysctl = &insns_sysctl[i];
++
++		sysctl->mode = 0644;
++		sysctl->maxlen = sizeof(int);
++
++		sysctl->procname = insn->ops->name;
++		sysctl->data = insn;
++		sysctl->extra1 = &insn->min;
++		sysctl->extra2 = &insn->max;
++		sysctl->proc_handler = emulation_proc_handler;
++		i++;
++	}
++	raw_spin_unlock_irqrestore(&insn_emulation_lock, flags);
++
++	table->child = insns_sysctl;
++	register_sysctl_table(table);
++}
++
++/*
++ *  Implement emulation of the SWP/SWPB instructions using load-exclusive and
++ *  store-exclusive.
++ *
++ *  Syntax of SWP{B} instruction: SWP{B}<c> <Rt>, <Rt2>, [<Rn>]
++ *  Where: Rt  = destination
++ *	   Rt2 = source
++ *	   Rn  = address
++ */
++
++/*
++ * Error-checking SWP macros implemented using ldxr{b}/stxr{b}
++ */
++#define __user_swpX_asm(data, addr, res, temp, B)		\
++	__asm__ __volatile__(					\
++	"	mov		%w2, %w1\n"			\
++	"0:	ldxr"B"		%w1, [%3]\n"			\
++	"1:	stxr"B"		%w0, %w2, [%3]\n"		\
++	"	cbz		%w0, 2f\n"			\
++	"	mov		%w0, %w4\n"			\
++	"2:\n"							\
++	"	.pushsection	 .fixup,\"ax\"\n"		\
++	"	.align		2\n"				\
++	"3:	mov		%w0, %w5\n"			\
++	"	b		2b\n"				\
++	"	.popsection"					\
++	"	.pushsection	 __ex_table,\"a\"\n"		\
++	"	.align		3\n"				\
++	"	.quad		0b, 3b\n"			\
++	"	.quad		1b, 3b\n"			\
++	"	.popsection"					\
++	: "=&r" (res), "+r" (data), "=&r" (temp)		\
++	: "r" (addr), "i" (-EAGAIN), "i" (-EFAULT)		\
++	: "memory")
++
++#define __user_swp_asm(data, addr, res, temp) \
++	__user_swpX_asm(data, addr, res, temp, "")
++#define __user_swpb_asm(data, addr, res, temp) \
++	__user_swpX_asm(data, addr, res, temp, "b")
++
++/*
++ * Bit 22 of the instruction encoding distinguishes between
++ * the SWP and SWPB variants (bit set means SWPB).
++ */
++#define TYPE_SWPB (1 << 22)
++
++/*
++ * Set up process info to signal segmentation fault - called on access error.
++ */
++static void set_segfault(struct pt_regs *regs, unsigned long addr)
++{
++	siginfo_t info;
++
++	down_read(&current->mm->mmap_sem);
++	if (find_vma(current->mm, addr) == NULL)
++		info.si_code = SEGV_MAPERR;
++	else
++		info.si_code = SEGV_ACCERR;
++	up_read(&current->mm->mmap_sem);
++
++	info.si_signo = SIGSEGV;
++	info.si_errno = 0;
++	info.si_addr  = (void *) instruction_pointer(regs);
++
++	pr_debug("SWP{B} emulation: access caused memory abort!\n");
++	arm64_notify_die("Illegal memory access", regs, &info, 0);
++}
++
++static int emulate_swpX(unsigned int address, unsigned int *data,
++			unsigned int type)
++{
++	unsigned int res = 0;
++
++	if ((type != TYPE_SWPB) && (address & 0x3)) {
++		/* SWP to unaligned address not permitted */
++		pr_debug("SWP instruction on unaligned pointer!\n");
++		return -EFAULT;
++	}
++
++	while (1) {
++		unsigned long temp;
++
++		if (type == TYPE_SWPB)
++			__user_swpb_asm(*data, address, res, temp);
++		else
++			__user_swp_asm(*data, address, res, temp);
++
++		if (likely(res != -EAGAIN) || signal_pending(current))
++			break;
++
++		cond_resched();
++	}
++
++	return res;
++}
++
++/*
++ * swp_handler logs the id of calling process, dissects the instruction, sanity
++ * checks the memory location, calls emulate_swpX for the actual operation and
++ * deals with fixup/error handling before returning
++ */
++static int swp_handler(struct pt_regs *regs, u32 instr)
++{
++	u32 destreg, data, type, address = 0;
++	int rn, rt2, res = 0;
++
++	perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, regs->pc);
++
++	type = instr & TYPE_SWPB;
++
++	switch (arm_check_condition(instr, regs->pstate)) {
++	case ARM_OPCODE_CONDTEST_PASS:
++		break;
++	case ARM_OPCODE_CONDTEST_FAIL:
++		/* Condition failed - return to next instruction */
++		goto ret;
++	case ARM_OPCODE_CONDTEST_UNCOND:
++		/* If unconditional encoding - not a SWP, undef */
++		return -EFAULT;
++	default:
++		return -EINVAL;
++	}
++
++	rn = aarch32_insn_extract_reg_num(instr, A32_RN_OFFSET);
++	rt2 = aarch32_insn_extract_reg_num(instr, A32_RT2_OFFSET);
++
++	address = (u32)regs->user_regs.regs[rn];
++	data	= (u32)regs->user_regs.regs[rt2];
++	destreg = aarch32_insn_extract_reg_num(instr, A32_RT_OFFSET);
++
++	pr_debug("addr in r%d->0x%08x, dest is r%d, source in r%d->0x%08x)\n",
++		rn, address, destreg,
++		aarch32_insn_extract_reg_num(instr, A32_RT2_OFFSET), data);
++
++	/* Check access in reasonable access range for both SWP and SWPB */
++	if (!access_ok(VERIFY_WRITE, (address & ~3), 4)) {
++		pr_debug("SWP{B} emulation: access to 0x%08x not allowed!\n",
++			address);
++		goto fault;
++	}
++
++	res = emulate_swpX(address, &data, type);
++	if (res == -EFAULT)
++		goto fault;
++	else if (res == 0)
++		regs->user_regs.regs[destreg] = data;
++
++ret:
++	if (type == TYPE_SWPB)
++		trace_instruction_emulation("swpb", regs->pc);
++	else
++		trace_instruction_emulation("swp", regs->pc);
++
++	pr_warn_ratelimited("\"%s\" (%ld) uses obsolete SWP{B} instruction at 0x%llx\n",
++			current->comm, (unsigned long)current->pid, regs->pc);
++
++	regs->pc += 4;
++	return 0;
++
++fault:
++	set_segfault(regs, address);
++
++	return 0;
++}
++
++/*
++ * Only emulate SWP/SWPB executed in ARM state/User mode.
++ * The kernel must be SWP free and SWP{B} does not exist in Thumb.
++ */
++static struct undef_hook swp_hooks[] = {
++	{
++		.instr_mask	= 0x0fb00ff0,
++		.instr_val	= 0x01000090,
++		.pstate_mask	= COMPAT_PSR_MODE_MASK,
++		.pstate_val	= COMPAT_PSR_MODE_USR,
++		.fn		= swp_handler
++	},
++	{ }
++};
++
++static struct insn_emulation_ops swp_ops = {
++	.name = "swp",
++	.status = INSN_OBSOLETE,
++	.hooks = swp_hooks,
++	.set_hw_mode = NULL,
++};
++
++static int cp15barrier_handler(struct pt_regs *regs, u32 instr)
++{
++	perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, regs->pc);
++
++	switch (arm_check_condition(instr, regs->pstate)) {
++	case ARM_OPCODE_CONDTEST_PASS:
++		break;
++	case ARM_OPCODE_CONDTEST_FAIL:
++		/* Condition failed - return to next instruction */
++		goto ret;
++	case ARM_OPCODE_CONDTEST_UNCOND:
++		/* If unconditional encoding - not a barrier instruction */
++		return -EFAULT;
++	default:
++		return -EINVAL;
++	}
++
++	switch (aarch32_insn_mcr_extract_crm(instr)) {
++	case 10:
++		/*
++		 * dmb - mcr p15, 0, Rt, c7, c10, 5
++		 * dsb - mcr p15, 0, Rt, c7, c10, 4
++		 */
++		if (aarch32_insn_mcr_extract_opc2(instr) == 5) {
++			dmb(sy);
++			trace_instruction_emulation(
++				"mcr p15, 0, Rt, c7, c10, 5 ; dmb", regs->pc);
++		} else {
++			dsb(sy);
++			trace_instruction_emulation(
++				"mcr p15, 0, Rt, c7, c10, 4 ; dsb", regs->pc);
++		}
++		break;
++	case 5:
++		/*
++		 * isb - mcr p15, 0, Rt, c7, c5, 4
++		 *
++		 * Taking an exception or returning from one acts as an
++		 * instruction barrier. So no explicit barrier needed here.
++		 */
++		trace_instruction_emulation(
++			"mcr p15, 0, Rt, c7, c5, 4 ; isb", regs->pc);
++		break;
++	}
++
++ret:
++	pr_warn_ratelimited("\"%s\" (%ld) uses deprecated CP15 Barrier instruction at 0x%llx\n",
++			current->comm, (unsigned long)current->pid, regs->pc);
++
++	regs->pc += 4;
++	return 0;
++}
++
++static inline void config_sctlr_el1(u32 clear, u32 set)
++{
++	u32 val;
++
++	asm volatile("mrs %0, sctlr_el1" : "=r" (val));
++	val &= ~clear;
++	val |= set;
++	asm volatile("msr sctlr_el1, %0" : : "r" (val));
++}
++
++static int cp15_barrier_set_hw_mode(bool enable)
++{
++	if (enable)
++		config_sctlr_el1(0, SCTLR_EL1_CP15BEN);
++	else
++		config_sctlr_el1(SCTLR_EL1_CP15BEN, 0);
++	return 0;
++}
++
++static struct undef_hook cp15_barrier_hooks[] = {
++	{
++		.instr_mask	= 0x0fff0fdf,
++		.instr_val	= 0x0e070f9a,
++		.pstate_mask	= COMPAT_PSR_MODE_MASK,
++		.pstate_val	= COMPAT_PSR_MODE_USR,
++		.fn		= cp15barrier_handler,
++	},
++	{
++		.instr_mask	= 0x0fff0fff,
++		.instr_val	= 0x0e070f95,
++		.pstate_mask	= COMPAT_PSR_MODE_MASK,
++		.pstate_val	= COMPAT_PSR_MODE_USR,
++		.fn		= cp15barrier_handler,
++	},
++	{ }
++};
++
++static struct insn_emulation_ops cp15_barrier_ops = {
++	.name = "cp15_barrier",
++	.status = INSN_DEPRECATED,
++	.hooks = cp15_barrier_hooks,
++	.set_hw_mode = cp15_barrier_set_hw_mode,
++};
++
++static int setend_set_hw_mode(bool enable)
++{
++	if (!cpu_supports_mixed_endian_el0())
++		return -EINVAL;
++
++	if (enable)
++		config_sctlr_el1(SCTLR_EL1_SED, 0);
++	else
++		config_sctlr_el1(0, SCTLR_EL1_SED);
++	return 0;
++}
++
++static int compat_setend_handler(struct pt_regs *regs, u32 big_endian)
++{
++	char *insn;
++
++	perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, regs->pc);
++
++	if (big_endian) {
++		insn = "setend be";
++		regs->pstate |= COMPAT_PSR_E_BIT;
++	} else {
++		insn = "setend le";
++		regs->pstate &= ~COMPAT_PSR_E_BIT;
++	}
++
++	trace_instruction_emulation(insn, regs->pc);
++	pr_warn_ratelimited("\"%s\" (%ld) uses deprecated setend instruction at 0x%llx\n",
++			current->comm, (unsigned long)current->pid, regs->pc);
++
++	return 0;
++}
++
++static int a32_setend_handler(struct pt_regs *regs, u32 instr)
++{
++	int rc = compat_setend_handler(regs, (instr >> 9) & 1);
++	regs->pc += 4;
++	return rc;
++}
++
++static int t16_setend_handler(struct pt_regs *regs, u32 instr)
++{
++	int rc = compat_setend_handler(regs, (instr >> 3) & 1);
++	regs->pc += 2;
++	return rc;
++}
++
++static struct undef_hook setend_hooks[] = {
++	{
++		.instr_mask	= 0xfffffdff,
++		.instr_val	= 0xf1010000,
++		.pstate_mask	= COMPAT_PSR_MODE_MASK,
++		.pstate_val	= COMPAT_PSR_MODE_USR,
++		.fn		= a32_setend_handler,
++	},
++	{
++		/* Thumb mode */
++		.instr_mask	= 0x0000fff7,
++		.instr_val	= 0x0000b650,
++		.pstate_mask	= (COMPAT_PSR_T_BIT | COMPAT_PSR_MODE_MASK),
++		.pstate_val	= (COMPAT_PSR_T_BIT | COMPAT_PSR_MODE_USR),
++		.fn		= t16_setend_handler,
++	},
++	{}
++};
++
++static struct insn_emulation_ops setend_ops = {
++	.name = "setend",
++	.status = INSN_DEPRECATED,
++	.hooks = setend_hooks,
++	.set_hw_mode = setend_set_hw_mode,
++};
++
++static int insn_cpu_hotplug_notify(struct notifier_block *b,
++			      unsigned long action, void *hcpu)
++{
++	int rc = 0;
++	if ((action & ~CPU_TASKS_FROZEN) == CPU_STARTING)
++		rc = run_all_insn_set_hw_mode((unsigned long)hcpu);
++
++	return notifier_from_errno(rc);
++}
++
++static struct notifier_block insn_cpu_hotplug_notifier = {
++	.notifier_call = insn_cpu_hotplug_notify,
++};
++
++/*
++ * Invoked as late_initcall, since not needed before init spawned.
++ */
++static int __init armv8_deprecated_init(void)
++{
++	if (IS_ENABLED(CONFIG_SWP_EMULATION))
++		register_insn_emulation(&swp_ops);
++
++	if (IS_ENABLED(CONFIG_CP15_BARRIER_EMULATION))
++		register_insn_emulation(&cp15_barrier_ops);
++
++	if (IS_ENABLED(CONFIG_SETEND_EMULATION)) {
++		if(system_supports_mixed_endian_el0())
++			register_insn_emulation(&setend_ops);
++		else
++			pr_info("setend instruction emulation is not supported on the system");
++	}
++
++	register_cpu_notifier(&insn_cpu_hotplug_notifier);
++	register_insn_emulation_sysctl(ctl_abi);
++
++	return 0;
++}
++
++late_initcall(armv8_deprecated_init);
+diff --git a/arch/arm64/kernel/cpuinfo.c b/arch/arm64/kernel/cpuinfo.c
+index 16d6d03..e86b9b4 100644
+--- a/arch/arm64/kernel/cpuinfo.c
++++ b/arch/arm64/kernel/cpuinfo.c
+@@ -35,6 +35,27 @@
+  */
+ DEFINE_PER_CPU(struct cpuinfo_arm64, cpu_data);
+ static struct cpuinfo_arm64 boot_cpu_data;
++static bool mixed_endian_el0 = true;
++
++bool cpu_supports_mixed_endian_el0(void)
++{
++	return id_aa64mmfr0_mixed_endian_el0(read_cpuid(ID_AA64MMFR0_EL1));
++}
++
++bool system_supports_mixed_endian_el0(void)
++{
++	return mixed_endian_el0;
++}
++
++static void update_mixed_endian_el0_support(struct cpuinfo_arm64 *info)
++{
++	mixed_endian_el0 &= id_aa64mmfr0_mixed_endian_el0(info->reg_id_aa64mmfr0);
++}
++
++static void update_cpu_features(struct cpuinfo_arm64 *info)
++{
++	update_mixed_endian_el0_support(info);
++}
+ 
+ static char *icache_policy_str[] = {
+ 	[ICACHE_POLICY_RESERVED] = "RESERVED/UNKNOWN",
+@@ -189,6 +210,7 @@ static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info)
+ 	cpuinfo_detect_icache_policy(info);
+ 
+ 	check_local_cpu_errata();
++	update_cpu_features(info);
+ }
+ 
+ void cpuinfo_store_cpu(void)
+diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
+index 6c99b46..c19999c 100644
+--- a/arch/arm64/kernel/entry.S
++++ b/arch/arm64/kernel/entry.S
+@@ -475,8 +475,8 @@ el0_da:
+ 	bic	x0, x26, #(0xff << 56)
+ 	mov	x1, x25
+ 	mov	x2, sp
+-	adr	lr, ret_to_user
+-	b	do_mem_abort
++	bl	do_mem_abort
++	b	ret_to_user
+ el0_ia:
+ 	/*
+ 	 * Instruction abort handling
+@@ -488,8 +488,8 @@ el0_ia:
+ 	mov	x0, x26
+ 	orr	x1, x25, #1 << 24		// use reserved ISS bit for instruction aborts
+ 	mov	x2, sp
+-	adr	lr, ret_to_user
+-	b	do_mem_abort
++	bl	do_mem_abort
++	b	ret_to_user
+ el0_fpsimd_acc:
+ 	/*
+ 	 * Floating Point or Advanced SIMD access
+@@ -498,8 +498,8 @@ el0_fpsimd_acc:
+ 	ct_user_exit
+ 	mov	x0, x25
+ 	mov	x1, sp
+-	adr	lr, ret_to_user
+-	b	do_fpsimd_acc
++	bl	do_fpsimd_acc
++	b	ret_to_user
+ el0_fpsimd_exc:
+ 	/*
+ 	 * Floating Point or Advanced SIMD exception
+@@ -508,8 +508,8 @@ el0_fpsimd_exc:
+ 	ct_user_exit
+ 	mov	x0, x25
+ 	mov	x1, sp
+-	adr	lr, ret_to_user
+-	b	do_fpsimd_exc
++	bl	do_fpsimd_exc
++	b	ret_to_user
+ el0_sp_pc:
+ 	/*
+ 	 * Stack or PC alignment exception handling
+@@ -521,8 +521,8 @@ el0_sp_pc:
+ 	mov	x0, x26
+ 	mov	x1, x25
+ 	mov	x2, sp
+-	adr	lr, ret_to_user
+-	b	do_sp_pc_abort
++	bl	do_sp_pc_abort
++	b	ret_to_user
+ el0_undef:
+ 	/*
+ 	 * Undefined instruction
+@@ -531,8 +531,8 @@ el0_undef:
+ 	enable_dbg_and_irq
+ 	ct_user_exit
+ 	mov	x0, sp
+-	adr	lr, ret_to_user
+-	b	do_undefinstr
++	bl	do_undefinstr
++	b	ret_to_user
+ el0_dbg:
+ 	/*
+ 	 * Debug exception handling
+@@ -551,8 +551,8 @@ el0_inv:
+ 	mov	x0, sp
+ 	mov	x1, #BAD_SYNC
+ 	mrs	x2, esr_el1
+-	adr	lr, ret_to_user
+-	b	bad_mode
++	bl	bad_mode
++	b	ret_to_user
+ ENDPROC(el0_sync)
+ 
+ 	.align	6
+@@ -674,14 +674,15 @@ el0_svc_naked:					// compat entry point
+ 	ldr	x16, [tsk, #TI_FLAGS]		// check for syscall hooks
+ 	tst	x16, #_TIF_SYSCALL_WORK
+ 	b.ne	__sys_trace
+-	adr	lr, ret_fast_syscall		// return address
+ 	cmp     scno, sc_nr                     // check upper syscall limit
+ 	b.hs	ni_sys
+ 	ldr	x16, [stbl, scno, lsl #3]	// address in the syscall table
+-	br	x16				// call sys_* routine
++	blr	x16				// call sys_* routine
++	b	ret_fast_syscall
+ ni_sys:
+ 	mov	x0, sp
+-	b	do_ni_syscall
++	bl	do_ni_syscall
++	b	ret_fast_syscall
+ ENDPROC(el0_svc)
+ 
+ 	/*
+@@ -689,26 +690,38 @@ ENDPROC(el0_svc)
+ 	 * switches, and waiting for our parent to respond.
+ 	 */
+ __sys_trace:
+-	mov	x0, sp
++	mov	w0, #-1				// set default errno for
++	cmp     scno, x0			// user-issued syscall(-1)
++	b.ne	1f
++	mov	x0, #-ENOSYS
++	str	x0, [sp, #S_X0]
++1:	mov	x0, sp
+ 	bl	syscall_trace_enter
+-	adr	lr, __sys_trace_return		// return address
++	cmp	w0, #-1				// skip the syscall?
++	b.eq	__sys_trace_return_skipped
+ 	uxtw	scno, w0			// syscall number (possibly new)
+ 	mov	x1, sp				// pointer to regs
+ 	cmp	scno, sc_nr			// check upper syscall limit
+-	b.hs	ni_sys
++	b.hs	__ni_sys_trace
+ 	ldp	x0, x1, [sp]			// restore the syscall args
+ 	ldp	x2, x3, [sp, #S_X2]
+ 	ldp	x4, x5, [sp, #S_X4]
+ 	ldp	x6, x7, [sp, #S_X6]
+ 	ldr	x16, [stbl, scno, lsl #3]	// address in the syscall table
+-	br	x16				// call sys_* routine
++	blr	x16				// call sys_* routine
+ 
+ __sys_trace_return:
+-	str	x0, [sp]			// save returned x0
++	str	x0, [sp, #S_X0]			// save returned x0
++__sys_trace_return_skipped:
+ 	mov	x0, sp
+ 	bl	syscall_trace_exit
+ 	b	ret_to_user
+ 
++__ni_sys_trace:
++	mov	x0, sp
++	bl	do_ni_syscall
++	b	__sys_trace_return
++
+ /*
+  * Special system call wrappers.
+  */
+diff --git a/arch/arm64/kernel/insn.c b/arch/arm64/kernel/insn.c
+index 8cd27fe..7e9327a 100644
+--- a/arch/arm64/kernel/insn.c
++++ b/arch/arm64/kernel/insn.c
+@@ -960,3 +960,29 @@ u32 aarch64_insn_gen_logical_shifted_reg(enum aarch64_insn_register dst,
+ 
+ 	return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_6, insn, shift);
+ }
++
++bool aarch32_insn_is_wide(u32 insn)
++{
++	return insn >= 0xe800;
++}
++
++/*
++ * Macros/defines for extracting register numbers from instruction.
++ */
++u32 aarch32_insn_extract_reg_num(u32 insn, int offset)
++{
++	return (insn & (0xf << offset)) >> offset;
++}
++
++#define OPC2_MASK	0x7
++#define OPC2_OFFSET	5
++u32 aarch32_insn_mcr_extract_opc2(u32 insn)
++{
++	return (insn & (OPC2_MASK << OPC2_OFFSET)) >> OPC2_OFFSET;
++}
++
++#define CRM_MASK	0xf
++u32 aarch32_insn_mcr_extract_crm(u32 insn)
++{
++	return insn & CRM_MASK;
++}
+diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
+index fde9923..07c4c53 100644
+--- a/arch/arm64/kernel/process.c
++++ b/arch/arm64/kernel/process.c
+@@ -163,6 +163,70 @@ void machine_restart(char *cmd)
+ 	while (1);
+ }
+ 
++/*
++ * dump a block of kernel memory from around the given address
++ */
++static void show_data(unsigned long addr, int nbytes, const char *name)
++{
++	int	i, j;
++	int	nlines;
++	u32	*p;
++
++	/*
++	 * don't attempt to dump non-kernel addresses or
++	 * values that are probably just small negative numbers
++	 */
++	if (addr < PAGE_OFFSET || addr > -256UL)
++		return;
++
++	printk("\n%s: %#lx:\n", name, addr);
++
++	/*
++	 * round address down to a 32 bit boundary
++	 * and always dump a multiple of 32 bytes
++	 */
++	p = (u32 *)(addr & ~(sizeof(u32) - 1));
++	nbytes += (addr & (sizeof(u32) - 1));
++	nlines = (nbytes + 31) / 32;
++
++
++	for (i = 0; i < nlines; i++) {
++		/*
++		 * just display low 16 bits of address to keep
++		 * each line of the dump < 80 characters
++		 */
++		printk("%04lx ", (unsigned long)p & 0xffff);
++		for (j = 0; j < 8; j++) {
++			u32	data;
++			if (probe_kernel_address(p, data)) {
++				printk(" ********");
++			} else {
++				printk(" %08x", data);
++			}
++			++p;
++		}
++		printk("\n");
++	}
++}
++
++static void show_extra_register_data(struct pt_regs *regs, int nbytes)
++{
++	mm_segment_t fs;
++	unsigned int i;
++
++	fs = get_fs();
++	set_fs(KERNEL_DS);
++	show_data(regs->pc - nbytes, nbytes * 2, "PC");
++	show_data(regs->regs[30] - nbytes, nbytes * 2, "LR");
++	show_data(regs->sp - nbytes, nbytes * 2, "SP");
++	for (i = 0; i < 30; i++) {
++		char name[4];
++		snprintf(name, sizeof(name), "X%u", i);
++		show_data(regs->regs[i] - nbytes, nbytes * 2, name);
++	}
++	set_fs(fs);
++}
++
+ void __show_regs(struct pt_regs *regs)
+ {
+ 	int i, top_reg;
+@@ -189,6 +253,8 @@ void __show_regs(struct pt_regs *regs)
+ 		if (i % 2 == 0)
+ 			printk("\n");
+ 	}
++	if (!user_mode(regs))
++		show_extra_register_data(regs, 128);
+ 	printk("\n");
+ }
+ 
+diff --git a/arch/arm64/kernel/psci-call.S b/arch/arm64/kernel/psci-call.S
+new file mode 100644
+index 0000000..cf83e61
+--- /dev/null
++++ b/arch/arm64/kernel/psci-call.S
+@@ -0,0 +1,28 @@
++/*
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * Copyright (C) 2015 ARM Limited
++ *
++ * Author: Will Deacon <will.deacon@arm.com>
++ */
++
++#include <linux/linkage.h>
++
++/* int __invoke_psci_fn_hvc(u64 function_id, u64 arg0, u64 arg1, u64 arg2) */
++ENTRY(__invoke_psci_fn_hvc)
++	hvc	#0
++	ret
++ENDPROC(__invoke_psci_fn_hvc)
++
++/* int __invoke_psci_fn_smc(u64 function_id, u64 arg0, u64 arg1, u64 arg2) */
++ENTRY(__invoke_psci_fn_smc)
++	smc	#0
++	ret
++ENDPROC(__invoke_psci_fn_smc)
+diff --git a/arch/arm64/kernel/psci.c b/arch/arm64/kernel/psci.c
+index 663da77..81c081e 100644
+--- a/arch/arm64/kernel/psci.c
++++ b/arch/arm64/kernel/psci.c
+@@ -57,6 +57,9 @@ static struct psci_operations psci_ops;
+ static int (*invoke_psci_fn)(u64, u64, u64, u64);
+ typedef int (*psci_initcall_t)(const struct device_node *);
+ 
++asmlinkage int __invoke_psci_fn_hvc(u64, u64, u64, u64);
++asmlinkage int __invoke_psci_fn_smc(u64, u64, u64, u64);
++
+ enum psci_function {
+ 	PSCI_FN_CPU_SUSPEND,
+ 	PSCI_FN_CPU_ON,
+@@ -109,40 +112,6 @@ static void psci_power_state_unpack(u32 power_state,
+ 			PSCI_0_2_POWER_STATE_AFFL_SHIFT;
+ }
+ 
+-/*
+- * The following two functions are invoked via the invoke_psci_fn pointer
+- * and will not be inlined, allowing us to piggyback on the AAPCS.
+- */
+-static noinline int __invoke_psci_fn_hvc(u64 function_id, u64 arg0, u64 arg1,
+-					 u64 arg2)
+-{
+-	asm volatile(
+-			__asmeq("%0", "x0")
+-			__asmeq("%1", "x1")
+-			__asmeq("%2", "x2")
+-			__asmeq("%3", "x3")
+-			"hvc	#0\n"
+-		: "+r" (function_id)
+-		: "r" (arg0), "r" (arg1), "r" (arg2));
+-
+-	return function_id;
+-}
+-
+-static noinline int __invoke_psci_fn_smc(u64 function_id, u64 arg0, u64 arg1,
+-					 u64 arg2)
+-{
+-	asm volatile(
+-			__asmeq("%0", "x0")
+-			__asmeq("%1", "x1")
+-			__asmeq("%2", "x2")
+-			__asmeq("%3", "x3")
+-			"smc	#0\n"
+-		: "+r" (function_id)
+-		: "r" (arg0), "r" (arg1), "r" (arg2));
+-
+-	return function_id;
+-}
+-
+ static int psci_get_version(void)
+ {
+ 	int err;
+diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
+index 8a4ae8e..d882b83 100644
+--- a/arch/arm64/kernel/ptrace.c
++++ b/arch/arm64/kernel/ptrace.c
+@@ -27,6 +27,7 @@
+ #include <linux/smp.h>
+ #include <linux/ptrace.h>
+ #include <linux/user.h>
++#include <linux/seccomp.h>
+ #include <linux/security.h>
+ #include <linux/init.h>
+ #include <linux/signal.h>
+@@ -551,6 +552,32 @@ static int tls_set(struct task_struct *target, const struct user_regset *regset,
+ 	return ret;
+ }
+ 
++static int system_call_get(struct task_struct *target,
++			   const struct user_regset *regset,
++			   unsigned int pos, unsigned int count,
++			   void *kbuf, void __user *ubuf)
++{
++	int syscallno = task_pt_regs(target)->syscallno;
++
++	return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
++				   &syscallno, 0, -1);
++}
++
++static int system_call_set(struct task_struct *target,
++			   const struct user_regset *regset,
++			   unsigned int pos, unsigned int count,
++			   const void *kbuf, const void __user *ubuf)
++{
++	int syscallno, ret;
++
++	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &syscallno, 0, -1);
++	if (ret)
++		return ret;
++
++	task_pt_regs(target)->syscallno = syscallno;
++	return ret;
++}
++
+ enum aarch64_regset {
+ 	REGSET_GPR,
+ 	REGSET_FPR,
+@@ -559,6 +586,7 @@ enum aarch64_regset {
+ 	REGSET_HW_BREAK,
+ 	REGSET_HW_WATCH,
+ #endif
++	REGSET_SYSTEM_CALL,
+ };
+ 
+ static const struct user_regset aarch64_regsets[] = {
+@@ -608,6 +636,14 @@ static const struct user_regset aarch64_regsets[] = {
+ 		.set = hw_break_set,
+ 	},
+ #endif
++	[REGSET_SYSTEM_CALL] = {
++		.core_note_type = NT_ARM_SYSTEM_CALL,
++		.n = 1,
++		.size = sizeof(int),
++		.align = sizeof(int),
++		.get = system_call_get,
++		.set = system_call_set,
++	},
+ };
+ 
+ static const struct user_regset_view user_aarch64_view = {
+@@ -1114,6 +1150,10 @@ static void tracehook_report_syscall(struct pt_regs *regs,
+ 
+ asmlinkage int syscall_trace_enter(struct pt_regs *regs)
+ {
++	/* Do the secure computing check first; failures should be fast. */
++	if (secure_computing() == -1)
++		return -1;
++
+ 	if (test_thread_flag(TIF_SYSCALL_TRACE))
+ 		tracehook_report_syscall(regs, PTRACE_SYSCALL_ENTER);
+ 
+diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
+index d502a86..ae8be92 100644
+--- a/arch/arm64/kernel/setup.c
++++ b/arch/arm64/kernel/setup.c
+@@ -314,6 +314,8 @@ static void __init setup_machine_fdt(phys_addr_t dt_phys)
+ 		while (true)
+ 			cpu_relax();
+ 	}
++
++	dump_stack_set_arch_desc("%s (DT)", of_flat_dt_get_machine_name());
+ }
+ 
+ /*
+diff --git a/arch/arm64/kernel/signal32.c b/arch/arm64/kernel/signal32.c
+index 76920d4..6acffec 100644
+--- a/arch/arm64/kernel/signal32.c
++++ b/arch/arm64/kernel/signal32.c
+@@ -185,6 +185,12 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
+ 		err |= __put_user(from->si_uid, &to->si_uid);
+ 		err |= __put_user(from->si_int, &to->si_int);
+ 		break;
++	case __SI_SYS:
++		err |= __put_user((compat_uptr_t)(unsigned long)
++				from->si_call_addr, &to->si_call_addr);
++		err |= __put_user(from->si_syscall, &to->si_syscall);
++		err |= __put_user(from->si_arch, &to->si_arch);
++		break;
+ 	default: /* this is just in case for now ... */
+ 		err |= __put_user(from->si_pid, &to->si_pid);
+ 		err |= __put_user(from->si_uid, &to->si_uid);
+@@ -433,7 +439,7 @@ static void compat_setup_return(struct pt_regs *regs, struct k_sigaction *ka,
+ {
+ 	compat_ulong_t handler = ptr_to_compat(ka->sa.sa_handler);
+ 	compat_ulong_t retcode;
+-	compat_ulong_t spsr = regs->pstate & ~PSR_f;
++	compat_ulong_t spsr = regs->pstate & ~(PSR_f | COMPAT_PSR_E_BIT);
+ 	int thumb;
+ 
+ 	/* Check if the handler is written for ARM or Thumb */
+@@ -447,6 +453,9 @@ static void compat_setup_return(struct pt_regs *regs, struct k_sigaction *ka,
+ 	/* The IT state must be cleared for both ARM and Thumb-2 */
+ 	spsr &= ~COMPAT_PSR_IT_MASK;
+ 
++	/* Restore the original endianness */
++	spsr |= COMPAT_PSR_ENDSTATE;
++
+ 	if (ka->sa.sa_flags & SA_RESTORER) {
+ 		retcode = ptr_to_compat(ka->sa.sa_restorer);
+ 	} else {
+diff --git a/arch/arm64/kernel/trace-events-emulation.h b/arch/arm64/kernel/trace-events-emulation.h
+new file mode 100644
+index 0000000..ae1dd59
+--- /dev/null
++++ b/arch/arm64/kernel/trace-events-emulation.h
+@@ -0,0 +1,35 @@
++#undef TRACE_SYSTEM
++#define TRACE_SYSTEM emulation
++
++#if !defined(_TRACE_EMULATION_H) || defined(TRACE_HEADER_MULTI_READ)
++#define _TRACE_EMULATION_H
++
++#include <linux/tracepoint.h>
++
++TRACE_EVENT(instruction_emulation,
++
++	TP_PROTO(const char *instr, u64 addr),
++	TP_ARGS(instr, addr),
++
++	TP_STRUCT__entry(
++		__string(instr, instr)
++		__field(u64, addr)
++	),
++
++	TP_fast_assign(
++		__assign_str(instr, instr);
++		__entry->addr = addr;
++	),
++
++	TP_printk("instr=\"%s\" addr=0x%llx", __get_str(instr), __entry->addr)
++);
++
++#endif /* _TRACE_EMULATION_H */
++
++/* This part must be outside protection */
++#undef TRACE_INCLUDE_PATH
++#undef TRACE_INCLUDE_FILE
++#define TRACE_INCLUDE_PATH .
++
++#define TRACE_INCLUDE_FILE trace-events-emulation
++#include <trace/define_trace.h>
+diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c
+index de1b085..0a801e3 100644
+--- a/arch/arm64/kernel/traps.c
++++ b/arch/arm64/kernel/traps.c
+@@ -259,6 +259,69 @@ void arm64_notify_die(const char *str, struct pt_regs *regs,
+ 	}
+ }
+ 
++static LIST_HEAD(undef_hook);
++static DEFINE_RAW_SPINLOCK(undef_lock);
++
++void register_undef_hook(struct undef_hook *hook)
++{
++	unsigned long flags;
++
++	raw_spin_lock_irqsave(&undef_lock, flags);
++	list_add(&hook->node, &undef_hook);
++	raw_spin_unlock_irqrestore(&undef_lock, flags);
++}
++
++void unregister_undef_hook(struct undef_hook *hook)
++{
++	unsigned long flags;
++
++	raw_spin_lock_irqsave(&undef_lock, flags);
++	list_del(&hook->node);
++	raw_spin_unlock_irqrestore(&undef_lock, flags);
++}
++
++static int call_undef_hook(struct pt_regs *regs)
++{
++	struct undef_hook *hook;
++	unsigned long flags;
++	u32 instr;
++	int (*fn)(struct pt_regs *regs, u32 instr) = NULL;
++	void __user *pc = (void __user *)instruction_pointer(regs);
++
++	if (!user_mode(regs))
++		return 1;
++
++	if (compat_thumb_mode(regs)) {
++		/* 16-bit Thumb instruction */
++		if (get_user(instr, (u16 __user *)pc))
++			goto exit;
++		instr = le16_to_cpu(instr);
++		if (aarch32_insn_is_wide(instr)) {
++			u32 instr2;
++
++			if (get_user(instr2, (u16 __user *)(pc + 2)))
++				goto exit;
++			instr2 = le16_to_cpu(instr2);
++			instr = (instr << 16) | instr2;
++		}
++	} else {
++		/* 32-bit ARM instruction */
++		if (get_user(instr, (u32 __user *)pc))
++			goto exit;
++		instr = le32_to_cpu(instr);
++	}
++
++	raw_spin_lock_irqsave(&undef_lock, flags);
++	list_for_each_entry(hook, &undef_hook, node)
++		if ((instr & hook->instr_mask) == hook->instr_val &&
++			(regs->pstate & hook->pstate_mask) == hook->pstate_val)
++			fn = hook->fn;
++
++	raw_spin_unlock_irqrestore(&undef_lock, flags);
++exit:
++	return fn ? fn(regs, instr) : 1;
++}
++
+ asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
+ {
+ 	siginfo_t info;
+@@ -268,6 +331,9 @@ asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
+ 	if (!aarch32_break_handler(regs))
+ 		return;
+ 
++	if (call_undef_hook(regs) == 0)
++		return;
++
+ 	if (show_unhandled_signals && unhandled_signal(current, SIGILL) &&
+ 	    printk_ratelimit()) {
+ 		pr_info("%s[%d]: undefined instruction: pc=%p\n",
+diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
+index f752943..b45b313 100644
+--- a/arch/arm64/mm/init.c
++++ b/arch/arm64/mm/init.c
+@@ -114,9 +114,11 @@ static void __init zone_sizes_init(unsigned long min, unsigned long max)
+ }
+ 
+ #ifdef CONFIG_HAVE_ARCH_PFN_VALID
++#define PFN_MASK ((1UL << (64 - PAGE_SHIFT)) - 1)
++
+ int pfn_valid(unsigned long pfn)
+ {
+-	return memblock_is_memory(pfn << PAGE_SHIFT);
++	return (pfn & PFN_MASK) == pfn && memblock_is_memory(pfn << PAGE_SHIFT);
+ }
+ EXPORT_SYMBOL(pfn_valid);
+ #endif
+diff --git a/arch/x86/include/asm/idle.h b/arch/x86/include/asm/idle.h
+index c5d1785..02bab09 100644
+--- a/arch/x86/include/asm/idle.h
++++ b/arch/x86/include/asm/idle.h
+@@ -1,13 +1,6 @@
+ #ifndef _ASM_X86_IDLE_H
+ #define _ASM_X86_IDLE_H
+ 
+-#define IDLE_START 1
+-#define IDLE_END 2
+-
+-struct notifier_block;
+-void idle_notifier_register(struct notifier_block *n);
+-void idle_notifier_unregister(struct notifier_block *n);
+-
+ #ifdef CONFIG_X86_64
+ void enter_idle(void);
+ void exit_idle(void);
+diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
+index a388bb8..0885df5 100644
+--- a/arch/x86/kernel/process.c
++++ b/arch/x86/kernel/process.c
+@@ -42,19 +42,6 @@ __visible DEFINE_PER_CPU_SHARED_ALIGNED(struct tss_struct, init_tss) = INIT_TSS;
+ 
+ #ifdef CONFIG_X86_64
+ static DEFINE_PER_CPU(unsigned char, is_idle);
+-static ATOMIC_NOTIFIER_HEAD(idle_notifier);
+-
+-void idle_notifier_register(struct notifier_block *n)
+-{
+-	atomic_notifier_chain_register(&idle_notifier, n);
+-}
+-EXPORT_SYMBOL_GPL(idle_notifier_register);
+-
+-void idle_notifier_unregister(struct notifier_block *n)
+-{
+-	atomic_notifier_chain_unregister(&idle_notifier, n);
+-}
+-EXPORT_SYMBOL_GPL(idle_notifier_unregister);
+ #endif
+ 
+ struct kmem_cache *task_xstate_cachep;
+@@ -262,14 +249,14 @@ static inline void play_dead(void)
+ void enter_idle(void)
+ {
+ 	this_cpu_write(is_idle, 1);
+-	atomic_notifier_call_chain(&idle_notifier, IDLE_START, NULL);
++	idle_notifier_call_chain(IDLE_START);
+ }
+ 
+ static void __exit_idle(void)
+ {
+ 	if (x86_test_and_clear_bit_percpu(0, is_idle) == 0)
+ 		return;
+-	atomic_notifier_call_chain(&idle_notifier, IDLE_END, NULL);
++	idle_notifier_call_chain(IDLE_END);
+ }
+ 
+ /* Called from interrupts to signify idle end */
+diff --git a/block/bsg.c b/block/bsg.c
+index 276e869..fc60769 100644
+--- a/block/bsg.c
++++ b/block/bsg.c
+@@ -677,6 +677,9 @@ bsg_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
+ 
+ 	dprintk("%s: write %Zd bytes\n", bd->name, count);
+ 
++	if (unlikely(segment_eq(get_fs(), KERNEL_DS)))
++		return -EINVAL;
++
+ 	bsg_set_block(bd, file);
+ 
+ 	bytes_written = 0;
+diff --git a/block/genhd.c b/block/genhd.c
+index c2fb3f7..b529e50 100644
+--- a/block/genhd.c
++++ b/block/genhd.c
+@@ -829,6 +829,7 @@ static void disk_seqf_stop(struct seq_file *seqf, void *v)
+ 	if (iter) {
+ 		class_dev_iter_exit(iter);
+ 		kfree(iter);
++		seqf->private = NULL;
+ 	}
+ }
+ 
+@@ -1116,6 +1117,22 @@ static void disk_release(struct device *dev)
+ 		blk_put_queue(disk->queue);
+ 	kfree(disk);
+ }
++
++static int disk_uevent(struct device *dev, struct kobj_uevent_env *env)
++{
++	struct gendisk *disk = dev_to_disk(dev);
++	struct disk_part_iter piter;
++	struct hd_struct *part;
++	int cnt = 0;
++
++	disk_part_iter_init(&piter, disk, 0);
++	while((part = disk_part_iter_next(&piter)))
++		cnt++;
++	disk_part_iter_exit(&piter);
++	add_uevent_var(env, "NPARTS=%u", cnt);
++	return 0;
++}
++
+ struct class block_class = {
+ 	.name		= "block",
+ };
+@@ -1135,6 +1152,7 @@ static struct device_type disk_type = {
+ 	.groups		= disk_attr_groups,
+ 	.release	= disk_release,
+ 	.devnode	= block_devnode,
++	.uevent		= disk_uevent,
+ };
+ 
+ #ifdef CONFIG_PROC_FS
+diff --git a/block/ioprio.c b/block/ioprio.c
+index 31666c9..3cf3ede 100644
+--- a/block/ioprio.c
++++ b/block/ioprio.c
+@@ -148,9 +148,11 @@ static int get_task_ioprio(struct task_struct *p)
+ 	ret = security_task_getioprio(p);
+ 	if (ret)
+ 		goto out;
++	task_lock(p);
+ 	ret = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_NONE, IOPRIO_NORM);
+ 	if (p->io_context)
+ 		ret = p->io_context->ioprio;
++	task_unlock(p);
+ out:
+ 	return ret;
+ }
+diff --git a/block/partition-generic.c b/block/partition-generic.c
+index 0d9e5f9..47284e7 100644
+--- a/block/partition-generic.c
++++ b/block/partition-generic.c
+@@ -217,10 +217,21 @@ static void part_release(struct device *dev)
+ 	kfree(p);
+ }
+ 
++static int part_uevent(struct device *dev, struct kobj_uevent_env *env)
++{
++	struct hd_struct *part = dev_to_part(dev);
++
++	add_uevent_var(env, "PARTN=%u", part->partno);
++	if (part->info && part->info->volname[0])
++		add_uevent_var(env, "PARTNAME=%s", part->info->volname);
++	return 0;
++}
++
+ struct device_type part_type = {
+ 	.name		= "partition",
+ 	.groups		= part_attr_groups,
+ 	.release	= part_release,
++	.uevent		= part_uevent,
+ };
+ 
+ static void delete_partition_rcu_cb(struct rcu_head *head)
+diff --git a/drivers/Kconfig b/drivers/Kconfig
+index 1a693d3..845873a 100644
+--- a/drivers/Kconfig
++++ b/drivers/Kconfig
+@@ -100,6 +100,8 @@ source "drivers/memstick/Kconfig"
+ 
+ source "drivers/leds/Kconfig"
+ 
++source "drivers/switch/Kconfig"
++
+ source "drivers/accessibility/Kconfig"
+ 
+ source "drivers/infiniband/Kconfig"
+@@ -182,4 +184,8 @@ source "drivers/ras/Kconfig"
+ 
+ source "drivers/thunderbolt/Kconfig"
+ 
++source "drivers/hidmac/Kconfig"
++
++source "drivers/hisilicon/Kconfig"
++
+ endmenu
+diff --git a/drivers/Makefile b/drivers/Makefile
+index ebee555..744a120 100644
+--- a/drivers/Makefile
++++ b/drivers/Makefile
+@@ -117,6 +117,7 @@ obj-$(CONFIG_CPU_IDLE)		+= cpuidle/
+ obj-y				+= mmc/
+ obj-$(CONFIG_MEMSTICK)		+= memstick/
+ obj-y				+= leds/
++obj-$(CONFIG_SWITCH)		+= switch/
+ obj-$(CONFIG_INFINIBAND)	+= infiniband/
+ obj-$(CONFIG_SGI_SN)		+= sn/
+ obj-y				+= firmware/
+@@ -161,3 +162,6 @@ obj-$(CONFIG_POWERCAP)		+= powercap/
+ obj-$(CONFIG_MCB)		+= mcb/
+ obj-$(CONFIG_RAS)		+= ras/
+ obj-$(CONFIG_THUNDERBOLT)	+= thunderbolt/
++obj-$(CONFIG_CORESIGHT)		+= hwtracing/coresight/
++obj-$(CONFIG_HI_DMAC)		+= hidmac/
++obj-y                           += hisilicon/
+diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
+index d24fa19..6d4e44e 100644
+--- a/drivers/acpi/thermal.c
++++ b/drivers/acpi/thermal.c
+@@ -800,7 +800,8 @@ static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal,
+ 				result =
+ 					thermal_zone_bind_cooling_device
+ 					(thermal, trip, cdev,
+-					 THERMAL_NO_LIMIT, THERMAL_NO_LIMIT);
++					 THERMAL_NO_LIMIT, THERMAL_NO_LIMIT,
++					 THERMAL_WEIGHT_DEFAULT);
+ 			else
+ 				result =
+ 					thermal_zone_unbind_cooling_device
+@@ -824,7 +825,8 @@ static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal,
+ 			if (bind)
+ 				result = thermal_zone_bind_cooling_device
+ 					(thermal, trip, cdev,
+-					 THERMAL_NO_LIMIT, THERMAL_NO_LIMIT);
++					 THERMAL_NO_LIMIT, THERMAL_NO_LIMIT,
++					 THERMAL_WEIGHT_DEFAULT);
+ 			else
+ 				result = thermal_zone_unbind_cooling_device
+ 					(thermal, trip, cdev);
+@@ -841,7 +843,8 @@ static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal,
+ 				result = thermal_zone_bind_cooling_device
+ 						(thermal, THERMAL_TRIPS_NONE,
+ 						 cdev, THERMAL_NO_LIMIT,
+-						 THERMAL_NO_LIMIT);
++						 THERMAL_NO_LIMIT,
++						 THERMAL_WEIGHT_DEFAULT);
+ 			else
+ 				result = thermal_zone_unbind_cooling_device
+ 						(thermal, THERMAL_TRIPS_NONE,
+diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c
+index 47bbdc1..a4ac490 100644
+--- a/drivers/amba/bus.c
++++ b/drivers/amba/bus.c
+@@ -336,7 +336,7 @@ int amba_device_add(struct amba_device *dev, struct resource *parent)
+ 
+ 		amba_put_disable_pclk(dev);
+ 
+-		if (cid == AMBA_CID)
++		if (cid == AMBA_CID || cid == CORESIGHT_CID)
+ 			dev->periphid = pid;
+ 
+ 		if (!dev->periphid)
+diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
+index cd4cccb..c4d06e0 100644
+--- a/drivers/ata/Kconfig
++++ b/drivers/ata/Kconfig
+@@ -2,6 +2,8 @@
+ # SATA/PATA driver configuration
+ #
+ 
++source "drivers/ata/Kconfig.hiahci"
++
+ config HAVE_PATA_PLATFORM
+ 	bool
+ 	help
+diff --git a/drivers/ata/Kconfig.hiahci b/drivers/ata/Kconfig.hiahci
+new file mode 100644
+index 0000000..ddee693
+--- /dev/null
++++ b/drivers/ata/Kconfig.hiahci
+@@ -0,0 +1,36 @@
++menuconfig HI_SATA
++	bool "hisilicon sata device support"
++	depends on (ARCH_HI3531D || ARCH_HI3521D || ARCH_HI3536C)
++	default y if (ARCH_HI3531D || ARCH_HI3521D || ARCH_HI3536C)
++	select ATA
++	select ATA_VERBOSE_ERROR
++	select SATA_PMP
++	select SATA_AHCI_PLATFORM
++
++if HI_SATA
++config HI_SATA_IOBASE
++	hex "hi sata IO address"
++	default "0x11010000" if (ARCH_HI3531D || ARCH_HI3521D || ARCH_HI3536C)
++	help
++	  hisilicon sata io base address.
++
++config HI_SATA_FBS
++	int "hi sata FIS-Based switching"
++	default 1
++	range 0 1
++	help
++	  Hisatav200 supports FBS.
++	  FBS is FIS-Based switching.
++	  Choose y if you want to use it.
++
++config HI_SATA_NCQ
++	int "hi sata Native Command Queuing"
++	default 1
++	range 0 1
++	help
++	  Hisatav200 supports NCQ.
++	  NCQ is Native Command Queuing.
++	  Choose y if you want to use it.
++
++endif
++
+diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
+index ae41107..d674ff1 100644
+--- a/drivers/ata/Makefile
++++ b/drivers/ata/Makefile
+@@ -1,5 +1,6 @@
+ 
+ obj-$(CONFIG_ATA)		+= libata.o
++obj-$(CONFIG_HI_SATA)		+= hi_sata_dbg.o
+ 
+ # non-SFF interface
+ obj-$(CONFIG_SATA_AHCI)		+= ahci.o libahci.o
+diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
+index 40f0e34..a773f34 100644
+--- a/drivers/ata/ahci.h
++++ b/drivers/ata/ahci.h
+@@ -334,6 +334,9 @@ struct ahci_host_priv {
+ 	bool			got_runtime_pm; /* Did we do pm_runtime_get? */
+ 	struct clk		*clks[AHCI_MAX_CLKS]; /* Optional */
+ 	struct regulator	*target_pwr;	/* Optional */
++#define         PCI_AHCI 0
++#define         ORI_AHCI 1
++	u32         type;
+ 	/*
+ 	 * If platform uses PHYs. There is a 1:1 relation between the port number and
+ 	 * the PHY position in this array.
+diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
+index 06f1d59..590f823 100644
+--- a/drivers/ata/ahci_platform.c
++++ b/drivers/ata/ahci_platform.c
+@@ -22,6 +22,11 @@
+ #include <linux/ahci_platform.h>
+ #include "ahci.h"
+ 
++static unsigned int ncq_en = CONFIG_HI_SATA_NCQ;
++module_param(ncq_en, uint, 0600);
++MODULE_PARM_DESC(ncq_en, "ahci ncq flag (default:1)");
++extern unsigned int sata_port_map;
++
+ static const struct ata_port_info ahci_port_info = {
+ 	.flags		= AHCI_FLAG_COMMON,
+ 	.pio_mask	= ATA_PIO4,
+@@ -31,7 +36,11 @@ static const struct ata_port_info ahci_port_info = {
+ 
+ static int ahci_probe(struct platform_device *pdev)
+ {
++#if (!defined(CONFIG_ARCH_HI3531D) \
++	&& !defined(CONFIG_ARCH_HI3521D) \
++	&& !defined(CONFIG_ARCH_HI3536C))
+ 	struct device *dev = &pdev->dev;
++#endif
+ 	struct ahci_host_priv *hpriv;
+ 	int rc;
+ 
+@@ -43,8 +52,17 @@ static int ahci_probe(struct platform_device *pdev)
+ 	if (rc)
+ 		return rc;
+ 
++#if (defined(CONFIG_ARCH_HI3531D) \
++	|| defined(CONFIG_ARCH_HI3521D) \
++	|| defined(CONFIG_ARCH_HI3536C))
++	hpriv->type = ORI_AHCI;
++	hpriv->force_port_map = sata_port_map;
++	if (!ncq_en)
++		 hpriv->flags |= AHCI_HFLAG_NO_NCQ;
++#else
+ 	if (of_device_is_compatible(dev->of_node, "hisilicon,hisi-ahci"))
+ 		hpriv->flags |= AHCI_HFLAG_NO_FBS | AHCI_HFLAG_NO_NCQ;
++#endif
+ 
+ 	rc = ahci_platform_init_host(pdev, hpriv, &ahci_port_info);
+ 	if (rc)
+diff --git a/drivers/ata/hi_sata_dbg.c b/drivers/ata/hi_sata_dbg.c
+new file mode 100644
+index 0000000..8442fbc
+--- /dev/null
++++ b/drivers/ata/hi_sata_dbg.c
+@@ -0,0 +1,158 @@
++#include <linux/kernel.h>
++#include <linux/delay.h>
++#include <linux/module.h>
++#include <linux/libata.h>
++#include <mach/io.h>
++#include "ahci.h"
++#include "hi_sata_dbg.h"
++
++void hi_sata_mem_dump(unsigned int *addr, unsigned int size)
++{
++	int ix;
++
++	for (ix = 0; ix < size; ix += 0x04, addr++) {
++		if (!(ix & 0x0F))
++			pr_debug("\n0x%08X: ",
++				(unsigned int)virt_to_phys(addr));
++		pr_debug("%08X ", *addr);
++	}
++}
++EXPORT_SYMBOL(hi_sata_mem_dump);
++
++void hi_sata_phys_mem_dump(unsigned int addr, unsigned int size)
++{
++	hi_sata_mem_dump(phys_to_virt(addr), size);
++}
++EXPORT_SYMBOL(hi_sata_phys_mem_dump);
++
++void hi_ahci_reg_dump(void)
++{
++	int ix;
++	unsigned int regbase;
++
++	regbase = CONFIG_HI_SATA_IOBASE;
++	pr_debug("AHCI GHC Register dump:");
++	for (ix = 0; ix <= 0x28; ix += 0x04) {
++		if (!(ix & 0x0F))
++			pr_debug("\n0x%08X: ", (regbase + ix));
++		pr_debug("%08X ", readl(__io_address(regbase + ix)));
++	}
++	pr_debug("\n");
++
++	regbase = CONFIG_HI_SATA_IOBASE + 0x0100;
++	pr_debug("AHCI PORT 0 Register dump:");
++	for (ix = 0; ix <= 0x7F; ix += 0x04) {
++		if (!(ix & 0x0F))
++			pr_debug("\n0x%08X: ", (regbase + ix));
++		pr_debug("%08X ", readl(__io_address(regbase + ix)));
++	}
++	pr_debug("\n");
++}
++EXPORT_SYMBOL(hi_ahci_reg_dump);
++
++void hi_ahci_rx_fis_dump(struct ata_link *link, int pmp_port_num)
++{
++	struct ahci_port_priv *pp = NULL;
++
++	pp = link->ap->private_data;
++	if (NULL == pp) {
++		pr_debug("Error: pp=NULL\n");
++		return;
++	}
++	pr_debug("ACHI Received FIS:");
++	hi_sata_phys_mem_dump((unsigned int)(pp->rx_fis_dma),
++				AHCI_RX_FIS_SZ * pmp_port_num);
++	pr_debug("\n");
++}
++EXPORT_SYMBOL_GPL(hi_ahci_rx_fis_dump);
++
++void hi_ata_taskfile_dump(struct ata_taskfile *tf)
++{
++	if (NULL == tf) {
++		pr_debug("Error: tf=NULL\n");
++		return;
++	}
++
++	pr_debug("Taskfile dump:\n");
++	pr_debug("flags:0x%08lX, protocol:0x%02X, command:0x%02X, device:0x%02X, ctl:0x%02X\n",
++		tf->flags, tf->protocol, tf->command, tf->device, tf->ctl);
++	pr_debug("feature:0x%08X, nsect:0x%02X, lbal:0x%02X, lbam:0x%02X, lbah:0x%02X\n",
++		tf->feature, tf->nsect, tf->lbal, tf->lbam, tf->lbah);
++	pr_debug("hob_feature:0x%08X, hob_nsect:0x%02X, hob_lbal:0x%02X, hob_lbam:0x%02X, hob_lbah:0x%02X\n",
++		tf->hob_feature, tf->hob_nsect, tf->hob_lbal,
++		tf->hob_lbam, tf->hob_lbah);
++}
++EXPORT_SYMBOL_GPL(hi_ata_taskfile_dump);
++
++static void __hi_ahci_st_md(void __iomem *addr)
++{
++	unsigned int *addr_v;
++	unsigned int *tmp;
++	unsigned int i;
++
++	addr_v = (unsigned int *)addr;
++
++	pr_debug("\n\n");
++	for (i = 0; i < 16; i++) {
++		tmp = addr_v + i * 4;
++		pr_debug("%8x: %8x %8x %8x %8x\n",
++			(unsigned int)(addr + i * 16),
++			*tmp, *(tmp + 1), *(tmp + 2), *(tmp + 3));
++	}
++
++	pr_debug("\n");
++}
++
++void hi_ahci_st_dump(void __iomem *port_base)
++{
++	unsigned int tmp;
++
++	pr_debug("\n**********Dmac status**********\n");
++	tmp = readl(port_base + 0x58);
++	pr_debug("txdmac_curr_st:0x%2x\n", (tmp>>24) & 0xf);
++	tmp = readl(port_base + 0x64);
++	pr_debug("rxdmac_curr_st:0x%2x\n", (tmp>>24) & 0xf);
++	tmp = readl(port_base + 0x70);
++	pr_debug("dmac tx fifo:count-0x%x-empty-%x-ful-%x\n",
++			(tmp>>0) & 0xff,
++			(tmp>>16) & 0x1, (tmp>>17) & 0x1);
++	pr_debug("dmac rx fifo:count-0x%x-empty-%x-ful-%x\n",
++			(tmp>>8) & 0xff,
++			(tmp>>18) & 0x1, (tmp>>19) & 0x1);
++
++	pr_debug("\n");
++	pr_debug("**********HBA status**********\n");
++	tmp = readl(port_base + 0x50);
++	pr_debug("pxxx_curr_st:0x%2x      ndrx_curr_st:0x%2x\n",
++			(tmp>>24) & 0xf,
++			(tmp>>16) & 0xff);
++	pr_debug("cfis_curr_st:0x%2x      piox_curr_st:0x%2x\n",
++			(tmp>>12) & 0xf,
++			(tmp>>8) & 0xf);
++	pr_debug("pmxx_curr_st:0x%2x      errx_curr_st:0x%2x\n",
++			(tmp>>4) & 0xf,
++			(tmp>>0) & 0xf);
++
++	pr_debug("\n");
++	pr_debug("**********Link status**********\n");
++	tmp = readl(port_base + 0x54);
++	pr_debug("link_curr_st:0x%2x\n", (tmp>>24) & 0x1f);
++	pr_debug("link tx fifo:count-0x%x-empty-%x-ful-%x\n",
++			(tmp>>0) & 0x1f,
++			(tmp>>5) & 0x1, (tmp>>6) & 0x1);
++	pr_debug("link rx fifo:count-0x%x-empty-%x-ful-%x\n",
++			(tmp>>8) & 0x1f,
++			(tmp>>13) & 0x1, (tmp>>14) & 0x1);
++	pr_debug("link df fifo:count-0x%x-empty-%x-ful-%x\n\n",
++			(tmp>>16) & 0x1f,
++			(tmp>>21) & 0x1, (tmp>>22) & 0x1);
++
++	pr_debug("**********CMD header**********\n");
++	tmp = readl(port_base + 0x0);
++	__hi_ahci_st_md(phys_to_virt(tmp));
++	__hi_ahci_st_md(phys_to_virt(tmp+0x100));
++	__hi_ahci_st_md(phys_to_virt(tmp+0x200));
++	__hi_ahci_st_md(phys_to_virt(tmp+0x300));
++}
++EXPORT_SYMBOL_GPL(hi_ahci_st_dump);
++
+diff --git a/drivers/ata/hi_sata_dbg.h b/drivers/ata/hi_sata_dbg.h
+new file mode 100644
+index 0000000..f8398db
+--- /dev/null
++++ b/drivers/ata/hi_sata_dbg.h
+@@ -0,0 +1,47 @@
++
++#ifndef _HI_SATA_DBG_H
++#define _HI_SATA_DBG_H
++#include <linux/kernel.h>
++#include <linux/delay.h>
++#include <linux/libata.h>
++#include "ahci.h"
++
++
++void hi_sata_mem_dump(unsigned int *addr, unsigned int size);
++void hi_sata_phys_mem_dump(unsigned int addr, unsigned int size);
++void hi_ahci_rx_fis_dump(struct ata_link *link, int pmp_port_num);
++void hi_ata_taskfile_dump(struct ata_taskfile *tf);
++void hi_ahci_st_dump(void __iomem *port_base);
++void hi_ahci_reg_dump(void);
++
++#define HI_AHCI_REG_DUMP(X) \
++do {\
++	pr_debug("------------------[ Start ]--------------------\n"); \
++	pr_debug("Dump AHCI registers at %s %d\n", __func__, __LINE__); \
++	hi_ahci_reg_dump(); \
++	pr_debug("------------------[  End  ]--------------------\n");\
++} while (0)
++
++#define hi_sata_readl(addr) do {\
++		unsigned int reg = readl((unsigned int)addr); \
++		pr_debug("HI_AHCI(REG) %s:%d: readl(0x%08X) = 0x%08X\n",\
++		__func__, __LINE__, (unsigned int)addr, reg); \
++		reg;\
++	} while (0)
++
++#define hi_sata_writel(v, addr) do { writel(v, (unsigned int)addr); \
++	pr_debug("HI_AHCI(REG) %s:%d: writel(0x%08X) = 0x%08X\n",\
++		__func__, __LINE__, (unsigned int)addr, \
++		(unsigned int)(v)); \
++	} while (0)
++
++#undef HI_DUMP_AHCI_REG_OPS
++#ifdef HI_DUMP_AHCI_REG_OPS
++#define readl(addr) hi_sata_readl(addr)
++#define write(v, addr) hi_sata_writel(v, addr)
++#endif
++
++#endif /* _HI_SATA_DBG_H */
++
++
++
+diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
+index de88999..1aefe5c 100644
+--- a/drivers/ata/libahci.c
++++ b/drivers/ata/libahci.c
+@@ -46,6 +46,9 @@
+ #include "ahci.h"
+ #include "libata.h"
+ 
++#include <mach/io.h>
++#include <mach/platform.h>
++
+ static int ahci_skip_host_reset;
+ int ahci_ignore_sss;
+ EXPORT_SYMBOL_GPL(ahci_ignore_sss);
+@@ -56,6 +59,33 @@ MODULE_PARM_DESC(skip_host_reset, "skip global host reset (0=don't skip, 1=skip)
+ module_param_named(ignore_sss, ahci_ignore_sss, int, 0444);
+ MODULE_PARM_DESC(ignore_sss, "Ignore staggered spinup flag (0=don't ignore, 1=ignore)");
+ 
++static int fbs_en = CONFIG_HI_SATA_FBS;
++module_param(fbs_en, uint, 0600);
++MODULE_PARM_DESC(fbs_en, "ahci fbs flags (default:1)");
++
++#ifdef CONFIG_HI_NANO_PHY_SATA
++extern void hisi_sata_reset_rxtx_assert(unsigned int port_no);
++extern void hisi_sata_reset_rxtx_deassert(unsigned int port_no);
++extern void hi_sata_set_eq(unsigned int port_no);
++extern void hi_sata_eq_recovery(unsigned int port_no);
++#endif
++
++#if (defined(CONFIG_ARCH_HI3531D) \
++	|| defined(CONFIG_ARCH_HI3521D) \
++	|| defined(CONFIG_ARCH_HI3536C))
++#define AHCI_TIMEOUT_COUNT	10
++#define AHCI_POLL_TIMER		(20 * HZ)
++
++struct ata_fbs_ctrl {
++	unsigned int fbs_enable_ctrl; /* fbs enable or disable control switch */
++	unsigned int fbs_mode_ctrl;   /* 1.5G: fbs disable, 3G/6G: fbs enable */
++	unsigned int fbs_enable_flag;
++	unsigned int fbs_disable_flag;
++	unsigned int fbs_cmd_issue_flag;
++	struct timer_list poll_timer;
++};
++static struct ata_fbs_ctrl fbs_ctrl[4];
++#endif
+ static int ahci_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
+ 			unsigned hints);
+ static ssize_t ahci_led_show(struct ata_port *ap, char *buf);
+@@ -1295,8 +1325,32 @@ int ahci_do_softreset(struct ata_link *link, unsigned int *class,
+ 	bool fbs_disabled = false;
+ 	int rc;
+ 
++#if (defined(CONFIG_ARCH_HI3531D) \
++	|| defined(CONFIG_ARCH_HI3521D) \
++	|| defined(CONFIG_ARCH_HI3536C))
++	unsigned int port_num = ap->port_no;
++#endif
++
+ 	DPRINTK("ENTER\n");
+ 
++#if (defined(CONFIG_ARCH_HI3531D) \
++	|| defined(CONFIG_ARCH_HI3521D) \
++	|| defined(CONFIG_ARCH_HI3536C))
++	if (fbs_ctrl[port_num].fbs_enable_ctrl &&
++			(link->pmp == SATA_PMP_CTRL_PORT) &&
++			(hpriv->type == ORI_AHCI)) {
++		struct ahci_port_priv *pp = ap->private_data;
++
++		if (pp->fbs_enabled == false)
++			ahci_enable_fbs(ap);
++
++		fbs_ctrl[port_num].fbs_enable_flag = 0;
++		fbs_ctrl[port_num].fbs_disable_flag = 0;
++		fbs_ctrl[port_num].fbs_cmd_issue_flag = 0;
++
++	}
++#endif
++
+ 	/* prepare for SRST (AHCI-1.1 10.4.1) */
+ 	rc = ahci_kick_engine(ap);
+ 	if (rc && rc != -EOPNOTSUPP)
+@@ -1325,6 +1379,10 @@ int ahci_do_softreset(struct ata_link *link, unsigned int *class,
+ 				 AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY, msecs)) {
+ 		rc = -EIO;
+ 		reason = "1st FIS failed";
++#ifdef CONFIG_HI_NANO_PHY_SATA
++		hisi_sata_reset_rxtx_assert(ap->port_no);
++		hisi_sata_reset_rxtx_deassert(ap->port_no);
++#endif
+ 		goto fail;
+ 	}
+ 
+@@ -1471,9 +1529,23 @@ static void ahci_postreset(struct ata_link *link, unsigned int *class)
+ 	struct ata_port *ap = link->ap;
+ 	void __iomem *port_mmio = ahci_port_base(ap);
+ 	u32 new_tmp, tmp;
++#ifdef CONFIG_HI_NANO_PHY_SATA
++	u32 sstatus;
++#endif
+ 
+ 	ata_std_postreset(link, class);
+ 
++#ifdef CONFIG_HI_NANO_PHY_SATA
++	/* recovery EQ, when SATA link up 6Gbps for Nano PHY */
++	if (sata_scr_read(link, SCR_STATUS, &sstatus) == 0 &&
++				((sstatus & 0xf) == 0x3)) { /* link online */
++		if (((sstatus >> 4) & 0xf) == 3) /* 3: 6Gbps, 2: 3Gbps, 1: 1.5Gbps */
++			hi_sata_eq_recovery(ap->port_no);
++	} else
++		hi_sata_set_eq(ap->port_no);
++
++#endif
++
+ 	/* Make sure port's ATAPI bit is set appropriately */
+ 	new_tmp = tmp = readl(port_mmio + PORT_CMD);
+ 	if (*class == ATA_DEV_ATAPI)
+@@ -1514,6 +1586,70 @@ static int ahci_pmp_qc_defer(struct ata_queued_cmd *qc)
+ 	struct ata_port *ap = qc->ap;
+ 	struct ahci_port_priv *pp = ap->private_data;
+ 
++#if (defined(CONFIG_ARCH_HI3531D) \
++	|| defined(CONFIG_ARCH_HI3521D) \
++	|| defined(CONFIG_ARCH_HI3536C))
++	struct ahci_host_priv *hpriv = ap->host->private_data;
++	int is_atapi = ata_is_atapi(qc->tf.protocol);
++	void __iomem *port_mmio = ahci_port_base(ap);
++	unsigned int port_num = ap->port_no;
++	unsigned int cmd_timeout_count;
++
++	if (fbs_ctrl[port_num].fbs_enable_ctrl &&
++			(ap->link.pmp == SATA_PMP_CTRL_PORT) &&
++			(hpriv->type == ORI_AHCI)) {
++		if (is_atapi || fbs_ctrl[ap->port_no].fbs_cmd_issue_flag) {
++			mod_timer(&fbs_ctrl[port_num].poll_timer,
++					jiffies + AHCI_POLL_TIMER);
++
++			if (!fbs_ctrl[port_num].fbs_disable_flag) {
++				cmd_timeout_count = 0;
++				while (readl(port_mmio + PORT_SCR_ACT)
++						|| readl(port_mmio
++							+ PORT_CMD_ISSUE)
++						|| readl(port_mmio
++							+ PORT_IRQ_STAT)) {
++					cmd_timeout_count++;
++					if (cmd_timeout_count >=
++							AHCI_TIMEOUT_COUNT) {
++						fbs_ctrl[ap->port_no].
++							fbs_cmd_issue_flag = 1;
++						return ATA_DEFER_LINK;
++					}
++				}
++
++				if (pp->fbs_enabled == true)
++					ahci_disable_fbs(ap);
++
++				ap->excl_link = NULL;
++				ap->nr_active_links = 0;
++				fbs_ctrl[port_num].fbs_disable_flag = 1;
++				fbs_ctrl[port_num].fbs_enable_flag = 0;
++				fbs_ctrl[ap->port_no].fbs_cmd_issue_flag = 0;
++			}
++		} else {
++			if (fbs_ctrl[port_num].fbs_enable_flag) {
++				cmd_timeout_count = 0;
++				while (readl(port_mmio + PORT_SCR_ACT)
++						|| readl(port_mmio
++							+ PORT_CMD_ISSUE)
++						|| readl(port_mmio
++							+ PORT_IRQ_STAT)) {
++					cmd_timeout_count++;
++					if (cmd_timeout_count >=
++							AHCI_TIMEOUT_COUNT) {
++						return ATA_DEFER_LINK;
++					}
++				}
++
++				if (pp->fbs_enabled == false)
++					ahci_enable_fbs(ap);
++				fbs_ctrl[port_num].fbs_enable_flag = 0;
++				fbs_ctrl[port_num].fbs_disable_flag = 0;
++			}
++		}
++	}
++#endif
+ 	if (!sata_pmp_attached(ap) || pp->fbs_enabled)
+ 		return ata_std_qc_defer(qc);
+ 	else
+@@ -1558,6 +1694,9 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc)
+ 	ahci_fill_cmd_slot(pp, qc->tag, opts);
+ }
+ 
++#if (!defined(CONFIG_ARCH_HI3531D) \
++	&& !defined(CONFIG_ARCH_HI3536C) \
++	&& !defined(CONFIG_ARCH_HI3521D))
+ static void ahci_fbs_dec_intr(struct ata_port *ap)
+ {
+ 	struct ahci_port_priv *pp = ap->private_data;
+@@ -1581,6 +1720,7 @@ static void ahci_fbs_dec_intr(struct ata_port *ap)
+ 	if (fbs & PORT_FBS_DEC)
+ 		dev_err(ap->host->dev, "failed to clear device error\n");
+ }
++#endif
+ 
+ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
+ {
+@@ -1684,11 +1824,24 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
+ 
+ 	/* okay, let's hand over to EH */
+ 
+-	if (irq_stat & PORT_IRQ_FREEZE)
+-		ata_port_freeze(ap);
+-	else if (fbs_need_dec) {
++	if (irq_stat & PORT_IRQ_FREEZE) {
++		if ((irq_stat & PORT_IRQ_IF_ERR) && fbs_need_dec) {
++			ata_link_abort(link);
++#if (!defined(CONFIG_ARCH_HI3531D) \
++	&& !defined(CONFIG_ARCH_HI3536C) \
++	&& !defined(CONFIG_ARCH_HI3521D))
++
++			ahci_fbs_dec_intr(ap);
++#endif
++		} else
++			ata_port_freeze(ap);
++	} else if (fbs_need_dec) {
+ 		ata_link_abort(link);
++#if (!defined(CONFIG_ARCH_HI3531D) \
++	&& !defined(CONFIG_ARCH_HI3536C) \
++	&& !defined(CONFIG_ARCH_HI3521D))
+ 		ahci_fbs_dec_intr(ap);
++#endif
+ 	} else
+ 		ata_port_abort(ap);
+ }
+@@ -2092,7 +2245,11 @@ static void ahci_enable_fbs(struct ata_port *ap)
+ 	writel(fbs | PORT_FBS_EN, port_mmio + PORT_FBS);
+ 	fbs = readl(port_mmio + PORT_FBS);
+ 	if (fbs & PORT_FBS_EN) {
++#if (!defined(CONFIG_ARCH_HI3531D) \
++	&& !defined(CONFIG_ARCH_HI3536C) \
++	&& !defined(CONFIG_ARCH_HI3521D))
+ 		dev_info(ap->host->dev, "FBS is enabled\n");
++#endif
+ 		pp->fbs_enabled = true;
+ 		pp->fbs_last_dev = -1; /* initialization */
+ 	} else
+@@ -2127,11 +2284,20 @@ static void ahci_disable_fbs(struct ata_port *ap)
+ 	if (fbs & PORT_FBS_EN)
+ 		dev_err(ap->host->dev, "Failed to disable FBS\n");
+ 	else {
++#if (defined(CONFIG_ARCH_HI3531D) \
++	|| defined(CONFIG_ARCH_HI3521D) \
++	|| defined(CONFIG_ARCH_HI3536C))
+ 		dev_info(ap->host->dev, "FBS is disabled\n");
++#endif
+ 		pp->fbs_enabled = false;
+ 	}
+ 
+ 	hpriv->start_engine(ap);
++#if (defined(CONFIG_ARCH_HI3531D) \
++	|| defined(CONFIG_ARCH_HI3521D) \
++	|| defined(CONFIG_ARCH_HI3536C))
++	writel(HI_SATA_FIFOTH_VALUE, (port_mmio + HI_SATA_PORT_FIFOTH));
++#endif
+ }
+ 
+ static void ahci_pmp_attach(struct ata_port *ap)
+@@ -2140,11 +2306,26 @@ static void ahci_pmp_attach(struct ata_port *ap)
+ 	struct ahci_port_priv *pp = ap->private_data;
+ 	u32 cmd;
+ 
++#if (defined(CONFIG_ARCH_HI3531D) \
++	|| defined(CONFIG_ARCH_HI3521D) \
++	|| defined(CONFIG_ARCH_HI3536C))
++	struct ahci_host_priv *hpriv = ap->host->private_data;
++	unsigned int port_num = ap->port_no;
++#endif
++
+ 	cmd = readl(port_mmio + PORT_CMD);
+ 	cmd |= PORT_CMD_PMP;
+ 	writel(cmd, port_mmio + PORT_CMD);
+ 
+ 	ahci_enable_fbs(ap);
++#if (defined(CONFIG_ARCH_HI3531D) \
++	|| defined(CONFIG_ARCH_HI3521D) \
++	|| defined(CONFIG_ARCH_HI3536C))
++	if (hpriv->type == ORI_AHCI) {
++		if (!fbs_ctrl[port_num].fbs_enable_ctrl)
++			ahci_disable_fbs(ap);
++	}
++#endif
+ 
+ 	pp->intr_mask |= PORT_IRQ_BAD_PMP;
+ 
+@@ -2211,6 +2392,21 @@ static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg)
+ }
+ #endif
+ 
++#if (defined(CONFIG_ARCH_HI3531D) \
++	|| defined(CONFIG_ARCH_HI3521D) \
++	|| defined(CONFIG_ARCH_HI3536C))
++static void ahci_poll_func(unsigned long arg)
++{
++	struct ata_port *ap = (struct ata_port *)arg;
++	unsigned int port_num = ap->port_no;
++
++	if (ap->link.pmp == SATA_PMP_CTRL_PORT) {
++		fbs_ctrl[port_num].fbs_enable_flag = 1;
++		fbs_ctrl[port_num].fbs_disable_flag = 0;
++	}
++}
++#endif
++
+ static int ahci_port_start(struct ata_port *ap)
+ {
+ 	struct ahci_host_priv *hpriv = ap->host->private_data;
+@@ -2304,6 +2500,22 @@ static int ahci_port_start(struct ata_port *ap)
+ 
+ 	ap->private_data = pp;
+ 
++#if (defined(CONFIG_ARCH_HI3531D) \
++	|| defined(CONFIG_ARCH_HI3521D) \
++	|| defined(CONFIG_ARCH_HI3536C))
++	if (hpriv->type == ORI_AHCI) {
++		fbs_ctrl[ap->port_no].fbs_enable_ctrl = fbs_en;
++		fbs_ctrl[ap->port_no].fbs_enable_flag = 0;
++		fbs_ctrl[ap->port_no].fbs_disable_flag = 0;
++		fbs_ctrl[ap->port_no].fbs_cmd_issue_flag = 0;
++
++		init_timer(&fbs_ctrl[ap->port_no].poll_timer);
++		fbs_ctrl[ap->port_no].poll_timer.function = ahci_poll_func;
++		fbs_ctrl[ap->port_no].poll_timer.data = (unsigned long)ap;
++		fbs_ctrl[ap->port_no].poll_timer.expires = jiffies + AHCI_POLL_TIMER;
++	}
++#endif
++
+ 	/* engage engines, captain */
+ 	return ahci_port_resume(ap);
+ }
+diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c
+index 0b03f90..4ca5f2d 100644
+--- a/drivers/ata/libahci_platform.c
++++ b/drivers/ata/libahci_platform.c
+@@ -24,6 +24,7 @@
+ #include <linux/ahci_platform.h>
+ #include <linux/phy/phy.h>
+ #include <linux/pm_runtime.h>
++#include <mach/io.h>
+ #include "ahci.h"
+ 
+ static void ahci_host_stop(struct ata_host *host);
+diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
+index df04227..c7d273b 100644
+--- a/drivers/base/Kconfig
++++ b/drivers/base/Kconfig
+@@ -220,8 +220,13 @@ config GENERIC_CPU_DEVICES
+ 	bool
+ 	default n
+ 
++config HAVE_CPU_AUTOPROBE
++	def_bool ARCH_HAS_CPU_AUTOPROBE
++
+ config GENERIC_CPU_AUTOPROBE
+ 	bool
++	depends on !ARCH_HAS_CPU_AUTOPROBE
++	select HAVE_CPU_AUTOPROBE
+ 
+ config SOC_BUS
+ 	bool
+diff --git a/drivers/base/core.c b/drivers/base/core.c
+index 842d047..93ad1c7 100644
+--- a/drivers/base/core.c
++++ b/drivers/base/core.c
+@@ -531,6 +531,7 @@ static DEVICE_ATTR_RO(dev);
+ 
+ /* /sys/devices/ */
+ struct kset *devices_kset;
++EXPORT_SYMBOL(devices_kset);
+ 
+ /**
+  * device_create_file - create sysfs attribute file for device.
+diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
+index 006b1bc..8a38bf8 100644
+--- a/drivers/base/cpu.c
++++ b/drivers/base/cpu.c
+@@ -287,6 +287,7 @@ static void cpu_device_release(struct device *dev)
+ 	 */
+ }
+ 
++#ifdef CONFIG_HAVE_CPU_AUTOPROBE
+ #ifdef CONFIG_GENERIC_CPU_AUTOPROBE
+ static ssize_t print_cpu_modalias(struct device *dev,
+ 				  struct device_attribute *attr,
+@@ -309,6 +310,9 @@ static ssize_t print_cpu_modalias(struct device *dev,
+ 	buf[n++] = '\n';
+ 	return n;
+ }
++#else
++#define print_cpu_modalias	arch_print_cpu_modalias
++#endif
+ 
+ static int cpu_uevent(struct device *dev, struct kobj_uevent_env *env)
+ {
+@@ -342,7 +346,7 @@ int register_cpu(struct cpu *cpu, int num)
+ 	cpu->dev.offline_disabled = !cpu->hotpluggable;
+ 	cpu->dev.offline = !cpu_online(num);
+ 	cpu->dev.of_node = of_get_cpu_node(num, NULL);
+-#ifdef CONFIG_GENERIC_CPU_AUTOPROBE
++#ifdef CONFIG_HAVE_CPU_AUTOPROBE
+ 	cpu->dev.bus->uevent = cpu_uevent;
+ #endif
+ 	cpu->dev.groups = common_cpu_attr_groups;
+@@ -366,7 +370,7 @@ struct device *get_cpu_device(unsigned cpu)
+ }
+ EXPORT_SYMBOL_GPL(get_cpu_device);
+ 
+-#ifdef CONFIG_GENERIC_CPU_AUTOPROBE
++#ifdef CONFIG_HAVE_CPU_AUTOPROBE
+ static DEVICE_ATTR(modalias, 0444, print_cpu_modalias, NULL);
+ #endif
+ 
+@@ -380,7 +384,7 @@ static struct attribute *cpu_root_attrs[] = {
+ 	&cpu_attrs[2].attr.attr,
+ 	&dev_attr_kernel_max.attr,
+ 	&dev_attr_offline.attr,
+-#ifdef CONFIG_GENERIC_CPU_AUTOPROBE
++#ifdef CONFIG_HAVE_CPU_AUTOPROBE
+ 	&dev_attr_modalias.attr,
+ #endif
+ 	NULL
+diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c
+index 950fff9..6e57cc1 100644
+--- a/drivers/base/dma-contiguous.c
++++ b/drivers/base/dma-contiguous.c
+@@ -195,6 +195,7 @@ struct page *dma_alloc_from_contiguous(struct device *dev, int count,
+ 
+ 	return cma_alloc(dev_get_cma_area(dev), count, align);
+ }
++EXPORT_SYMBOL(dma_alloc_from_contiguous);
+ 
+ /**
+  * dma_release_from_contiguous() - release allocated pages
+@@ -211,6 +212,7 @@ bool dma_release_from_contiguous(struct device *dev, struct page *pages,
+ {
+ 	return cma_release(dev_get_cma_area(dev), pages, count);
+ }
++EXPORT_SYMBOL(dma_release_from_contiguous);
+ 
+ /*
+  * Support for reserved memory regions defined in device tree
+diff --git a/drivers/base/platform.c b/drivers/base/platform.c
+index 360272c..43d6530 100644
+--- a/drivers/base/platform.c
++++ b/drivers/base/platform.c
+@@ -731,7 +731,7 @@ static ssize_t driver_override_store(struct device *dev,
+ 				     const char *buf, size_t count)
+ {
+ 	struct platform_device *pdev = to_platform_device(dev);
+-	char *driver_override, *old = pdev->driver_override, *cp;
++	char *driver_override, *old, *cp;
+ 
+ 	if (count > PATH_MAX)
+ 		return -EINVAL;
+@@ -744,6 +744,9 @@ static ssize_t driver_override_store(struct device *dev,
+ 	if (cp)
+ 		*cp = '\0';
+ 
++	device_lock(dev);
++	old = pdev->driver_override;
++
+ 	if (strlen(driver_override)) {
+ 		pdev->driver_override = driver_override;
+ 	} else {
+@@ -751,6 +754,8 @@ static ssize_t driver_override_store(struct device *dev,
+ 		pdev->driver_override = NULL;
+ 	}
+ 
++	device_unlock(dev);
++
+ 	kfree(old);
+ 
+ 	return count;
+@@ -760,8 +765,12 @@ static ssize_t driver_override_show(struct device *dev,
+ 				    struct device_attribute *attr, char *buf)
+ {
+ 	struct platform_device *pdev = to_platform_device(dev);
++	ssize_t len;
+ 
+-	return sprintf(buf, "%s\n", pdev->driver_override);
++	device_lock(dev);
++	len = sprintf(buf, "%s\n", pdev->driver_override);
++	device_unlock(dev);
++	return len;
+ }
+ static DEVICE_ATTR_RW(driver_override);
+ 
+diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
+index 9717d5f..bf957ca 100644
+--- a/drivers/base/power/main.c
++++ b/drivers/base/power/main.c
+@@ -32,10 +32,13 @@
+ #include <linux/cpufreq.h>
+ #include <linux/cpuidle.h>
+ #include <linux/timer.h>
++#include <linux/wakeup_reason.h>
+ 
+ #include "../base.h"
+ #include "power.h"
+-
++#ifdef	CONFIG_HISI_SNAPSHOT_BOOT
++extern int pm_notifier_call_chain(unsigned long val);
++#endif
+ typedef int (*pm_callback_t)(struct device *);
+ 
+ /*
+@@ -58,6 +61,12 @@ struct suspend_stats suspend_stats;
+ static DEFINE_MUTEX(dpm_list_mtx);
+ static pm_message_t pm_transition;
+ 
++static void dpm_drv_timeout(unsigned long data);
++struct dpm_drv_wd_data {
++	struct device *dev;
++	struct task_struct *tsk;
++};
++
+ static int async_error;
+ 
+ static char *pm_verb(int event)
+@@ -828,6 +837,30 @@ static void async_resume(void *data, async_cookie_t cookie)
+ }
+ 
+ /**
++ *	dpm_drv_timeout - Driver suspend / resume watchdog handler
++ *	@data: struct device which timed out
++ *
++ * 	Called when a driver has timed out suspending or resuming.
++ * 	There's not much we can do here to recover so
++ * 	BUG() out for a crash-dump
++ *
++ */
++static void dpm_drv_timeout(unsigned long data)
++{
++	struct dpm_drv_wd_data *wd_data = (void *)data;
++	struct device *dev = wd_data->dev;
++	struct task_struct *tsk = wd_data->tsk;
++
++	printk(KERN_EMERG "**** DPM device timeout: %s (%s)\n", dev_name(dev),
++	       (dev->driver ? dev->driver->name : "no driver"));
++
++	printk(KERN_EMERG "dpm suspend stack:\n");
++	show_stack(tsk, NULL);
++
++	BUG();
++}
++
++/**
+  * dpm_resume - Execute "resume" callbacks for non-sysdev devices.
+  * @state: PM transition of the system being carried out.
+  *
+@@ -973,6 +1006,9 @@ void dpm_complete(pm_message_t state)
+  */
+ void dpm_resume_end(pm_message_t state)
+ {
++#ifdef	CONFIG_HISI_SNAPSHOT_BOOT
++	pm_notifier_call_chain(PM_RESUME_DEVICE_PREPARE);
++#endif
+ 	dpm_resume(state);
+ 	dpm_complete(state);
+ }
+@@ -1336,6 +1372,9 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
+ 	pm_callback_t callback = NULL;
+ 	char *info = NULL;
+ 	int error = 0;
++	struct timer_list timer;
++	struct dpm_drv_wd_data data;
++	char suspend_abort[MAX_SUSPEND_ABORT_LEN];
+ 	DECLARE_DPM_WATCHDOG_ON_STACK(wd);
+ 
+ 	dpm_wait_for_children(dev, async);
+@@ -1353,12 +1392,23 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
+ 		pm_wakeup_event(dev, 0);
+ 
+ 	if (pm_wakeup_pending()) {
++		pm_get_active_wakeup_sources(suspend_abort,
++			MAX_SUSPEND_ABORT_LEN);
++		log_suspend_abort_reason(suspend_abort);
+ 		async_error = -EBUSY;
+ 		goto Complete;
+ 	}
+ 
+ 	if (dev->power.syscore)
+ 		goto Complete;
++	
++	data.dev = dev;
++	data.tsk = get_current();
++	init_timer_on_stack(&timer);
++	timer.expires = jiffies + HZ * 12;
++	timer.function = dpm_drv_timeout;
++	timer.data = (unsigned long)&data;
++	add_timer(&timer);
+ 
+ 	if (dev->power.direct_complete) {
+ 		if (pm_runtime_status_suspended(dev)) {
+@@ -1439,6 +1489,9 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
+ 	device_unlock(dev);
+ 	dpm_watchdog_clear(&wd);
+ 
++	del_timer_sync(&timer);
++	destroy_timer_on_stack(&timer);
++
+  Complete:
+ 	complete_all(&dev->power.completion);
+ 	if (error)
+@@ -1661,6 +1714,10 @@ int dpm_suspend_start(pm_message_t state)
+ 		dpm_save_failed_step(SUSPEND_PREPARE);
+ 	} else
+ 		error = dpm_suspend(state);
++#ifdef	CONFIG_HISI_SNAPSHOT_BOOT
++	if (!error)
++		pm_notifier_call_chain(PM_POST_DEVICE_SUSPEND);
++#endif
+ 	return error;
+ }
+ EXPORT_SYMBOL_GPL(dpm_suspend_start);
+diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c
+index c2744b3..f1cf53a 100644
+--- a/drivers/base/power/wakeup.c
++++ b/drivers/base/power/wakeup.c
+@@ -14,6 +14,7 @@
+ #include <linux/suspend.h>
+ #include <linux/seq_file.h>
+ #include <linux/debugfs.h>
++#include <linux/types.h>
+ #include <trace/events/power.h>
+ 
+ #include "power.h"
+@@ -668,6 +669,37 @@ void pm_wakeup_event(struct device *dev, unsigned int msec)
+ }
+ EXPORT_SYMBOL_GPL(pm_wakeup_event);
+ 
++void pm_get_active_wakeup_sources(char *pending_wakeup_source, size_t max)
++{
++	struct wakeup_source *ws, *last_active_ws = NULL;
++	int len = 0;
++	bool active = false;
++
++	rcu_read_lock();
++	list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
++		if (ws->active) {
++			if (!active)
++				len += scnprintf(pending_wakeup_source, max,
++						"Pending Wakeup Sources: ");
++			len += scnprintf(pending_wakeup_source + len, max - len,
++				"%s ", ws->name);
++			active = true;
++		} else if (!active &&
++			   (!last_active_ws ||
++			    ktime_to_ns(ws->last_time) >
++			    ktime_to_ns(last_active_ws->last_time))) {
++			last_active_ws = ws;
++		}
++	}
++	if (!active && last_active_ws) {
++		scnprintf(pending_wakeup_source, max,
++				"Last active Wakeup Source: %s",
++				last_active_ws->name);
++	}
++	rcu_read_unlock();
++}
++EXPORT_SYMBOL_GPL(pm_get_active_wakeup_sources);
++
+ void pm_print_active_wakeup_sources(void)
+ {
+ 	struct wakeup_source *ws;
+diff --git a/drivers/base/syscore.c b/drivers/base/syscore.c
+index 8d98a32..96c34a9 100644
+--- a/drivers/base/syscore.c
++++ b/drivers/base/syscore.c
+@@ -11,6 +11,7 @@
+ #include <linux/module.h>
+ #include <linux/suspend.h>
+ #include <trace/events/power.h>
++#include <linux/wakeup_reason.h>
+ 
+ static LIST_HEAD(syscore_ops_list);
+ static DEFINE_MUTEX(syscore_ops_lock);
+@@ -75,6 +76,8 @@ int syscore_suspend(void)
+ 	return 0;
+ 
+  err_out:
++	log_suspend_abort_reason("System core suspend callback %pF failed",
++		ops->suspend);
+ 	pr_err("PM: System core suspend callback %pF failed.\n", ops->suspend);
+ 
+ 	list_for_each_entry_continue(ops, &syscore_ops_list, node)
+diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
+index efefd12..b96a3a5 100644
+--- a/drivers/char/Kconfig
++++ b/drivers/char/Kconfig
+@@ -6,6 +6,19 @@ menu "Character devices"
+ 
+ source "drivers/tty/Kconfig"
+ 
++config DEVMEM
++	bool "Memory device driver"
++	default y
++	help
++	  The memory driver provides two character devices, mem and kmem, which
++	  provide access to the system's memory. The mem device is a view of
++	  physical memory, and each byte in the device corresponds to the
++	  matching physical address. The kmem device is the same as mem, but
++	  the addresses correspond to the kernel's virtual address space rather
++	  than physical memory. These devices are standard parts of a Linux
++	  system and most users should say Y here. You might say N if very
++	  security conscience or memory is tight.
++
+ config DEVKMEM
+ 	bool "/dev/kmem virtual device support"
+ 	default y
+@@ -579,6 +592,10 @@ config DEVPORT
+ 	depends on ISA || PCI
+ 	default y
+ 
++config DCC_TTY
++	tristate "DCC tty driver"
++	depends on ARM
++
+ source "drivers/s390/char/Kconfig"
+ 
+ config MSM_SMD_PKT
+diff --git a/drivers/char/Makefile b/drivers/char/Makefile
+index d06cde2..e38fb5b 100644
+--- a/drivers/char/Makefile
++++ b/drivers/char/Makefile
+@@ -55,6 +55,7 @@ obj-$(CONFIG_PCMCIA)		+= pcmcia/
+ obj-$(CONFIG_HANGCHECK_TIMER)	+= hangcheck-timer.o
+ obj-$(CONFIG_TCG_TPM)		+= tpm/
+ 
++obj-$(CONFIG_DCC_TTY)		+= dcc_tty.o
+ obj-$(CONFIG_PS3_FLASH)		+= ps3flash.o
+ 
+ obj-$(CONFIG_JS_RTC)		+= js-rtc.o
+diff --git a/drivers/char/dcc_tty.c b/drivers/char/dcc_tty.c
+new file mode 100644
+index 0000000..0a62d41
+--- /dev/null
++++ b/drivers/char/dcc_tty.c
+@@ -0,0 +1,326 @@
++/* drivers/char/dcc_tty.c
++ *
++ * Copyright (C) 2007 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/delay.h>
++#include <linux/console.h>
++#include <linux/hrtimer.h>
++#include <linux/tty.h>
++#include <linux/tty_driver.h>
++#include <linux/tty_flip.h>
++
++MODULE_DESCRIPTION("DCC TTY Driver");
++MODULE_LICENSE("GPL");
++MODULE_VERSION("1.0");
++
++DEFINE_SPINLOCK(g_dcc_tty_lock);
++static struct hrtimer g_dcc_timer;
++static char g_dcc_buffer[16];
++static int g_dcc_buffer_head;
++static int g_dcc_buffer_count;
++static unsigned g_dcc_write_delay_usecs = 1;
++static struct tty_driver *g_dcc_tty_driver;
++static struct tty_struct *g_dcc_tty;
++static int g_dcc_tty_open_count;
++
++static void dcc_poll_locked(void)
++{
++	char ch;
++	int rch;
++	int written;
++
++	while (g_dcc_buffer_count) {
++		ch = g_dcc_buffer[g_dcc_buffer_head];
++		asm(
++			"mrc 14, 0, r15, c0, c1, 0\n"
++			"mcrcc 14, 0, %1, c0, c5, 0\n"
++			"movcc %0, #1\n"
++			"movcs %0, #0\n"
++			: "=r" (written)
++			: "r" (ch)
++		);
++		if (written) {
++			if (ch == '\n')
++				g_dcc_buffer[g_dcc_buffer_head] = '\r';
++			else {
++				g_dcc_buffer_head = (g_dcc_buffer_head + 1) % ARRAY_SIZE(g_dcc_buffer);
++				g_dcc_buffer_count--;
++				if (g_dcc_tty)
++					tty_wakeup(g_dcc_tty);
++			}
++			g_dcc_write_delay_usecs = 1;
++		} else {
++			if (g_dcc_write_delay_usecs > 0x100)
++				break;
++			g_dcc_write_delay_usecs <<= 1;
++			udelay(g_dcc_write_delay_usecs);
++		}
++	}
++
++	if (g_dcc_tty && !test_bit(TTY_THROTTLED, &g_dcc_tty->flags)) {
++		asm(
++			"mrc 14, 0, %0, c0, c1, 0\n"
++			"tst %0, #(1 << 30)\n"
++			"moveq %0, #-1\n"
++			"mrcne 14, 0, %0, c0, c5, 0\n"
++			: "=r" (rch)
++		);
++		if (rch >= 0) {
++			ch = rch;
++			tty_insert_flip_string(g_dcc_tty->port, &ch, 1);
++			tty_flip_buffer_push(g_dcc_tty->port);
++		}
++	}
++
++
++	if (g_dcc_buffer_count)
++		hrtimer_start(&g_dcc_timer, ktime_set(0, g_dcc_write_delay_usecs * NSEC_PER_USEC), HRTIMER_MODE_REL);
++	else
++		hrtimer_start(&g_dcc_timer, ktime_set(0, 20 * NSEC_PER_MSEC), HRTIMER_MODE_REL);
++}
++
++static int dcc_tty_open(struct tty_struct * tty, struct file * filp)
++{
++	int ret;
++	unsigned long irq_flags;
++
++	spin_lock_irqsave(&g_dcc_tty_lock, irq_flags);
++	if (g_dcc_tty == NULL || g_dcc_tty == tty) {
++		g_dcc_tty = tty;
++		g_dcc_tty_open_count++;
++		ret = 0;
++	} else
++		ret = -EBUSY;
++	spin_unlock_irqrestore(&g_dcc_tty_lock, irq_flags);
++
++	printk("dcc_tty_open, tty %p, f_flags %x, returned %d\n", tty, filp->f_flags, ret);
++
++	return ret;
++}
++
++static void dcc_tty_close(struct tty_struct * tty, struct file * filp)
++{
++	printk("dcc_tty_close, tty %p, f_flags %x\n", tty, filp->f_flags);
++	if (g_dcc_tty == tty) {
++		if (--g_dcc_tty_open_count == 0)
++			g_dcc_tty = NULL;
++	}
++}
++
++static int dcc_write(const unsigned char *buf_start, int count)
++{
++	const unsigned char *buf = buf_start;
++	unsigned long irq_flags;
++	int copy_len;
++	int space_left;
++	int tail;
++
++	if (count < 1)
++		return 0;
++
++	spin_lock_irqsave(&g_dcc_tty_lock, irq_flags);
++	do {
++		tail = (g_dcc_buffer_head + g_dcc_buffer_count) % ARRAY_SIZE(g_dcc_buffer);
++		copy_len = ARRAY_SIZE(g_dcc_buffer) - tail;
++		space_left = ARRAY_SIZE(g_dcc_buffer) - g_dcc_buffer_count;
++		if (copy_len > space_left)
++			copy_len = space_left;
++		if (copy_len > count)
++			copy_len = count;
++		memcpy(&g_dcc_buffer[tail], buf, copy_len);
++		g_dcc_buffer_count += copy_len;
++		buf += copy_len;
++		count -= copy_len;
++		if (copy_len < count && copy_len < space_left) {
++			space_left -= copy_len;
++			copy_len = count;
++			if (copy_len > space_left) {
++				copy_len = space_left;
++			}
++			memcpy(g_dcc_buffer, buf, copy_len);
++			buf += copy_len;
++			count -= copy_len;
++			g_dcc_buffer_count += copy_len;
++		}
++		dcc_poll_locked();
++		space_left = ARRAY_SIZE(g_dcc_buffer) - g_dcc_buffer_count;
++	} while(count && space_left);
++	spin_unlock_irqrestore(&g_dcc_tty_lock, irq_flags);
++	return buf - buf_start;
++}
++
++static int dcc_tty_write(struct tty_struct * tty, const unsigned char *buf, int count)
++{
++	int ret;
++	/* printk("dcc_tty_write %p, %d\n", buf, count); */
++	ret = dcc_write(buf, count);
++	if (ret != count)
++		printk("dcc_tty_write %p, %d, returned %d\n", buf, count, ret);
++	return ret;
++}
++
++static int dcc_tty_write_room(struct tty_struct *tty)
++{
++	int space_left;
++	unsigned long irq_flags;
++
++	spin_lock_irqsave(&g_dcc_tty_lock, irq_flags);
++	space_left = ARRAY_SIZE(g_dcc_buffer) - g_dcc_buffer_count;
++	spin_unlock_irqrestore(&g_dcc_tty_lock, irq_flags);
++	return space_left;
++}
++
++static int dcc_tty_chars_in_buffer(struct tty_struct *tty)
++{
++	int ret;
++	asm(
++		"mrc 14, 0, %0, c0, c1, 0\n"
++		"mov %0, %0, LSR #30\n"
++		"and %0, %0, #1\n"
++		: "=r" (ret)
++	);
++	return ret;
++}
++
++static void dcc_tty_unthrottle(struct tty_struct * tty)
++{
++	unsigned long irq_flags;
++
++	spin_lock_irqsave(&g_dcc_tty_lock, irq_flags);
++	dcc_poll_locked();
++	spin_unlock_irqrestore(&g_dcc_tty_lock, irq_flags);
++}
++
++static enum hrtimer_restart dcc_tty_timer_func(struct hrtimer *timer)
++{
++	unsigned long irq_flags;
++
++	spin_lock_irqsave(&g_dcc_tty_lock, irq_flags);
++	dcc_poll_locked();
++	spin_unlock_irqrestore(&g_dcc_tty_lock, irq_flags);
++	return HRTIMER_NORESTART;
++}
++
++void dcc_console_write(struct console *co, const char *b, unsigned count)
++{
++#if 1
++	dcc_write(b, count);
++#else
++	/* blocking printk */
++	while (count > 0) {
++		int written;
++		written = dcc_write(b, count);
++		if (written) {
++			b += written;
++			count -= written;
++		}
++	}
++#endif
++}
++
++static struct tty_driver *dcc_console_device(struct console *c, int *index)
++{
++	*index = 0;
++	return g_dcc_tty_driver;
++}
++
++static int __init dcc_console_setup(struct console *co, char *options)
++{
++	if (co->index != 0)
++		return -ENODEV;
++	return 0;
++}
++
++
++static struct console dcc_console =
++{
++	.name		= "ttyDCC",
++	.write		= dcc_console_write,
++	.device		= dcc_console_device,
++	.setup		= dcc_console_setup,
++	.flags		= CON_PRINTBUFFER,
++	.index		= -1,
++};
++
++static struct tty_operations dcc_tty_ops = {
++	.open = dcc_tty_open,
++	.close = dcc_tty_close,
++	.write = dcc_tty_write,
++	.write_room = dcc_tty_write_room,
++	.chars_in_buffer = dcc_tty_chars_in_buffer,
++	.unthrottle = dcc_tty_unthrottle,
++};
++
++static int __init dcc_tty_init(void)
++{
++	int ret;
++
++	hrtimer_init(&g_dcc_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
++	g_dcc_timer.function = dcc_tty_timer_func;
++
++	g_dcc_tty_driver = alloc_tty_driver(1);
++	if (!g_dcc_tty_driver) {
++		printk(KERN_ERR "dcc_tty_probe: alloc_tty_driver failed\n");
++		ret = -ENOMEM;
++		goto err_alloc_tty_driver_failed;
++	}
++	g_dcc_tty_driver->owner = THIS_MODULE;
++	g_dcc_tty_driver->driver_name = "dcc";
++	g_dcc_tty_driver->name = "ttyDCC";
++	g_dcc_tty_driver->major = 0; // auto assign
++	g_dcc_tty_driver->minor_start = 0;
++	g_dcc_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
++	g_dcc_tty_driver->subtype = SERIAL_TYPE_NORMAL;
++	g_dcc_tty_driver->init_termios = tty_std_termios;
++	g_dcc_tty_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
++	tty_set_operations(g_dcc_tty_driver, &dcc_tty_ops);
++	ret = tty_register_driver(g_dcc_tty_driver);
++	if (ret) {
++		printk(KERN_ERR "dcc_tty_probe: tty_register_driver failed, %d\n", ret);
++		goto err_tty_register_driver_failed;
++	}
++	tty_register_device(g_dcc_tty_driver, 0, NULL);
++
++	register_console(&dcc_console);
++	hrtimer_start(&g_dcc_timer, ktime_set(0, 0), HRTIMER_MODE_REL);
++
++	return 0;
++
++err_tty_register_driver_failed:
++	put_tty_driver(g_dcc_tty_driver);
++	g_dcc_tty_driver = NULL;
++err_alloc_tty_driver_failed:
++	return ret;
++}
++
++static void  __exit dcc_tty_exit(void)
++{
++	int ret;
++
++	tty_unregister_device(g_dcc_tty_driver, 0);
++	ret = tty_unregister_driver(g_dcc_tty_driver);
++	if (ret < 0) {
++		printk(KERN_ERR "dcc_tty_remove: tty_unregister_driver failed, %d\n", ret);
++	} else {
++		put_tty_driver(g_dcc_tty_driver);
++	}
++	g_dcc_tty_driver = NULL;
++}
++
++module_init(dcc_tty_init);
++module_exit(dcc_tty_exit);
++
++
+diff --git a/drivers/char/mem.c b/drivers/char/mem.c
+index 524b707..f6ea960 100644
+--- a/drivers/char/mem.c
++++ b/drivers/char/mem.c
+@@ -58,6 +58,7 @@ static inline int valid_mmap_phys_addr_range(unsigned long pfn, size_t size)
+ }
+ #endif
+ 
++#if defined(CONFIG_DEVMEM) || defined(CONFIG_DEVKMEM)
+ #ifdef CONFIG_STRICT_DEVMEM
+ static inline int range_is_allowed(unsigned long pfn, unsigned long size)
+ {
+@@ -83,7 +84,9 @@ static inline int range_is_allowed(unsigned long pfn, unsigned long size)
+ 	return 1;
+ }
+ #endif
++#endif
+ 
++#ifdef CONFIG_DEVMEM
+ void __weak unxlate_dev_mem_ptr(unsigned long phys, void *addr)
+ {
+ }
+@@ -216,6 +219,9 @@ static ssize_t write_mem(struct file *file, const char __user *buf,
+ 	*ppos += written;
+ 	return written;
+ }
++#endif	/* CONFIG_DEVMEM */
++
++#if defined(CONFIG_DEVMEM) || defined(CONFIG_DEVKMEM)
+ 
+ int __weak phys_mem_access_prot_allowed(struct file *file,
+ 	unsigned long pfn, unsigned long size, pgprot_t *vma_prot)
+@@ -338,6 +344,49 @@ static int mmap_mem(struct file *file, struct vm_area_struct *vma)
+ 	return 0;
+ }
+ 
++static int mmap_venc(struct file *file, struct vm_area_struct *vma)
++{
++	size_t size = (vma->vm_end - vma->vm_start)>>1;
++
++	if (!valid_mmap_phys_addr_range(vma->vm_pgoff, size))
++		return -EINVAL;
++
++	if (!private_mapping_ok(vma))
++		return -ENOSYS;
++
++	if (!range_is_allowed(vma->vm_pgoff, size))
++		return -EPERM;
++
++	if (!phys_mem_access_prot_allowed(file, vma->vm_pgoff, size,
++						&vma->vm_page_prot))
++		return -EINVAL;
++
++	vma->vm_page_prot = phys_mem_access_prot(file, vma->vm_pgoff,
++						 size,
++						 vma->vm_page_prot);
++
++	vma->vm_ops = &mmap_mem_ops;
++
++	/* Remap-pfn-range will mark the range VM_IO and VM_RESERVED */
++	if (remap_pfn_range(vma,
++			vma->vm_start,
++			vma->vm_pgoff,
++			size,
++			vma->vm_page_prot))
++		return -EAGAIN;
++
++	if (remap_pfn_range(vma,
++			vma->vm_start + size,
++			vma->vm_pgoff,
++			size,
++			vma->vm_page_prot))
++		return -EAGAIN;
++
++	return 0;
++}
++
++#endif	/* CONFIG_DEVMEM */
++
+ #ifdef CONFIG_DEVKMEM
+ static int mmap_kmem(struct file *file, struct vm_area_struct *vma)
+ {
+@@ -667,6 +716,8 @@ static loff_t null_lseek(struct file *file, loff_t offset, int orig)
+ 	return file->f_pos = 0;
+ }
+ 
++#if defined(CONFIG_DEVMEM) || defined(CONFIG_DEVKMEM) || defined(CONFIG_DEVPORT)
++
+ /*
+  * The memory devices use the full 32/64 bits of the offset, and so we cannot
+  * check against negative addresses: they are ok. The return value is weird,
+@@ -700,10 +751,14 @@ static loff_t memory_lseek(struct file *file, loff_t offset, int orig)
+ 	return ret;
+ }
+ 
++#endif
++
++#if defined(CONFIG_DEVMEM) || defined(CONFIG_DEVKMEM) || defined(CONFIG_DEVPORT)
+ static int open_port(struct inode *inode, struct file *filp)
+ {
+ 	return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
+ }
++#endif
+ 
+ #define zero_lseek	null_lseek
+ #define full_lseek      null_lseek
+@@ -712,6 +767,7 @@ static int open_port(struct inode *inode, struct file *filp)
+ #define open_mem	open_port
+ #define open_kmem	open_mem
+ 
++#ifdef CONFIG_DEVMEM
+ static const struct file_operations mem_fops = {
+ 	.llseek		= memory_lseek,
+ 	.read		= read_mem,
+@@ -721,6 +777,17 @@ static const struct file_operations mem_fops = {
+ 	.get_unmapped_area = get_unmapped_area_mem,
+ };
+ 
++
++static const struct file_operations venc_fops = {
++	.llseek		= memory_lseek,
++	.read		= read_mem,
++	.write		= write_mem,
++	.mmap		= mmap_venc,
++	.open		= open_mem,
++	.get_unmapped_area = get_unmapped_area_mem,
++};
++#endif
++
+ #ifdef CONFIG_DEVKMEM
+ static const struct file_operations kmem_fops = {
+ 	.llseek		= memory_lseek,
+@@ -782,7 +849,9 @@ static const struct memdev {
+ 	const struct file_operations *fops;
+ 	struct backing_dev_info *dev_info;
+ } devlist[] = {
++#ifdef CONFIG_DEVMEM
+ 	 [1] = { "mem", 0, &mem_fops, &directly_mappable_cdev_bdi },
++#endif
+ #ifdef CONFIG_DEVKMEM
+ 	 [2] = { "kmem", 0, &kmem_fops, &directly_mappable_cdev_bdi },
+ #endif
+@@ -797,6 +866,9 @@ static const struct memdev {
+ #ifdef CONFIG_PRINTK
+ 	[11] = { "kmsg", 0644, &kmsg_fops, NULL },
+ #endif
++#ifdef CONFIG_DEVMEM
++	 [13] = { "vencmem", 0, &venc_fops, &directly_mappable_cdev_bdi },
++#endif
+ };
+ 
+ static int memory_open(struct inode *inode, struct file *filp)
+diff --git a/drivers/char/random.c b/drivers/char/random.c
+index 9cd6968..f41b114 100644
+--- a/drivers/char/random.c
++++ b/drivers/char/random.c
+@@ -661,7 +661,8 @@ retry:
+ 		if (r == &nonblocking_pool) {
+ 			prandom_reseed_late();
+ 			wake_up_interruptible(&urandom_init_wait);
+-			pr_notice("random: %s pool is initialized\n", r->name);
++			/* Don't want to print this sentence and annotate it! 2015-12-23 */
++			/*pr_notice("random: %s pool is initialized\n", r->name);*/
+ 		}
+ 	}
+ 
+diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
+index 455fd17..dd112f0 100644
+--- a/drivers/clk/Kconfig
++++ b/drivers/clk/Kconfig
+@@ -134,6 +134,24 @@ config COMMON_CLK_PXA
+ 	---help---
+ 	  Sypport for the Marvell PXA SoC.
+ 
++config COMMON_CLK_FREQ_STATS_ACCOUNTING
++	bool "Enable clock frequency stats accounting"
++	depends on COMMON_CLK
++	depends on DEBUG_FS
++	---help---
++	 Allows accounting of the time spent by various clocks in each
++	 of its operating frequency. The stats get reported as a part
++	 of clk_summary. Would be be useful in finding out which
++	 components are running at what power states to debug
++	 battery consumption issues.
++
++config COMMON_CLK_BEGIN_ACCOUNTING_FROM_BOOT
++	bool "Start clock frequency stats accounting from boot"
++	depends on COMMON_CLK_FREQ_STATS_ACCOUNTING
++	---help---
++	 Enabling this option starts the frequency accounting right from
++	 the boot.
++
+ source "drivers/clk/qcom/Kconfig"
+ 
+ endmenu
+diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
+index d5fba5b..62d74f2 100644
+--- a/drivers/clk/Makefile
++++ b/drivers/clk/Makefile
+@@ -46,6 +46,10 @@ obj-$(CONFIG_ARCH_BERLIN)		+= berlin/
+ obj-$(CONFIG_ARCH_HI3xxx)		+= hisilicon/
+ obj-$(CONFIG_ARCH_HIP04)		+= hisilicon/
+ obj-$(CONFIG_ARCH_HIX5HD2)		+= hisilicon/
++obj-$(CONFIG_ARCH_HISI)			+= hisilicon/
++obj-$(CONFIG_ARCH_HI3536C)		+= hisilicon/
++obj-$(CONFIG_ARCH_HI3531D)		+= hisilicon/
++obj-$(CONFIG_ARCH_HI3521D)		+= hisilicon/
+ obj-$(CONFIG_COMMON_CLK_KEYSTONE)	+= keystone/
+ ifeq ($(CONFIG_COMMON_CLK), y)
+ obj-$(CONFIG_ARCH_MMP)			+= mmp/
+diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
+index 7d74830..d2f0a56 100644
+--- a/drivers/clk/clk.c
++++ b/drivers/clk/clk.c
+@@ -114,6 +114,134 @@ static struct hlist_head *orphan_list[] = {
+ 	NULL,
+ };
+ 
++#ifdef CONFIG_COMMON_CLK_FREQ_STATS_ACCOUNTING
++
++#ifdef CONFIG_COMMON_CLK_BEGIN_ACCOUNTING_FROM_BOOT
++static bool freq_stats_on = true;
++#else
++static bool freq_stats_on;
++#endif /*CONFIG_COMMON_CLK_BEGIN_ACCOUNTING_FROM_BOOT*/
++
++static void free_tree(struct rb_node *node)
++{
++	struct freq_stats *this;
++
++	if (!node)
++		return;
++
++	free_tree(node->rb_left);
++	free_tree(node->rb_right);
++
++	this = rb_entry(node, struct freq_stats, node);
++	kfree(this);
++}
++
++static struct freq_stats *freq_stats_insert(struct rb_root *freq_stats_table,
++		unsigned long rate)
++{
++	struct rb_node **new = &(freq_stats_table->rb_node), *parent = NULL;
++	struct freq_stats *this;
++
++	/* Figure out where to put new node */
++	while (*new) {
++		this = rb_entry(*new, struct freq_stats, node);
++		parent = *new;
++
++		if (rate < this->rate)
++			new = &((*new)->rb_left);
++		else if (rate > this->rate)
++			new = &((*new)->rb_right);
++		else
++			return this;
++	}
++
++	this = kzalloc(sizeof(*this), GFP_ATOMIC);
++	this->rate = rate;
++
++	/* Add new node and rebalance tree. */
++	rb_link_node(&this->node, parent, new);
++	rb_insert_color(&this->node, freq_stats_table);
++
++	return this;
++}
++
++static void generic_print_freq_stats_table(struct seq_file *m,
++				struct clk *clk,
++				bool indent, int level)
++{
++	struct rb_node *pos;
++	struct freq_stats *cur;
++
++	if (indent)
++		seq_printf(m, "%*s*%s%20s", level * 3 + 1, "",
++			!clk->current_freq_stats ? "[" : "",
++			"default_freq");
++	else
++		seq_printf(m, "%2s%20s", !clk->current_freq_stats ? "[" : "",
++			"default_freq");
++
++	if (!clk->current_freq_stats && !ktime_equal(clk->start_time,
++					ktime_set(0, 0)))
++		seq_printf(m, "%40llu",
++			ktime_to_ms(ktime_add(clk->default_freq_time,
++			ktime_sub(ktime_get(), clk->start_time))));
++	else
++		seq_printf(m, "%40llu", ktime_to_ms(clk->default_freq_time));
++
++	if (!clk->current_freq_stats)
++		seq_puts(m, "]");
++
++	seq_puts(m, "\n");
++
++	for (pos = rb_first(&clk->freq_stats_table); pos; pos = rb_next(pos)) {
++		cur = rb_entry(pos, typeof(*cur), node);
++
++		if (indent)
++			seq_printf(m, "%*s*%s%20lu", level * 3 + 1, "",
++				cur->rate == clk->rate ? "[" : "", cur->rate);
++		else
++			seq_printf(m, "%2s%20lu", cur->rate == clk->rate ?
++				"[" : "", cur->rate);
++
++		if (cur->rate == clk->rate && !ktime_equal(clk->start_time,
++					ktime_set(0, 0)))
++			seq_printf(m, "%40llu",
++			ktime_to_ms(ktime_add(cur->time_spent,
++			ktime_sub(ktime_get(), clk->start_time))));
++		else
++			seq_printf(m, "%40llu", ktime_to_ms(cur->time_spent));
++
++		if (cur->rate == clk->rate)
++			seq_puts(m, "]");
++		seq_puts(m, "\n");
++	}
++}
++
++static int clock_print_freq_stats_table(struct seq_file *m, void *unused)
++{
++	struct clk *clk = m->private;
++
++	if (!(clk->flags & CLK_GET_RATE_NOCACHE))
++		generic_print_freq_stats_table(m, clk, false, 0);
++
++	return 0;
++}
++
++static int freq_stats_table_open(struct inode *inode, struct file *file)
++{
++	return single_open(file, clock_print_freq_stats_table,
++		inode->i_private);
++}
++
++static const struct file_operations freq_stats_table_fops = {
++	.open           = freq_stats_table_open,
++	.read           = seq_read,
++	.llseek         = seq_lseek,
++	.release        = seq_release,
++};
++#endif /*CONFIG_COMMON_CLK_FREQ_STATS_ACCOUNTING*/
++
++
+ static void clk_summary_show_one(struct seq_file *s, struct clk *c, int level)
+ {
+ 	if (!c)
+@@ -124,6 +252,12 @@ static void clk_summary_show_one(struct seq_file *s, struct clk *c, int level)
+ 		   30 - level * 3, c->name,
+ 		   c->enable_count, c->prepare_count, clk_get_rate(c),
+ 		   clk_get_accuracy(c), clk_get_phase(c));
++
++#ifdef CONFIG_COMMON_CLK_FREQ_STATS_ACCOUNTING
++	if (!(c->flags & CLK_GET_RATE_NOCACHE))
++		generic_print_freq_stats_table(s, c, true, level);
++#endif /*CONFIG_COMMON_CLK_FREQ_STATS_ACCOUNTING*/
++
+ }
+ 
+ static void clk_summary_show_subtree(struct seq_file *s, struct clk *c,
+@@ -240,6 +374,78 @@ static const struct file_operations clk_dump_fops = {
+ 	.release	= single_release,
+ };
+ 
++#ifdef CONFIG_COMMON_CLK_FREQ_STATS_ACCOUNTING
++static int freq_stats_get(void *unused, u64 *val)
++{
++	*val = freq_stats_on;
++	return 0;
++}
++
++static void clk_traverse_subtree(struct clk *clk, int freq_stats_on)
++{
++	struct clk *child;
++	struct rb_node *node;
++
++	if (!clk)
++		return;
++
++	if (freq_stats_on) {
++		for (node = rb_first(&clk->freq_stats_table);
++			node; node = rb_next(node))
++			rb_entry(node, struct freq_stats, node)->time_spent =
++							ktime_set(0, 0);
++
++		clk->current_freq_stats = freq_stats_insert(
++						&clk->freq_stats_table,
++						clk_get_rate(clk));
++
++		if (clk->enable_count > 0)
++			clk->start_time = ktime_get();
++	} else {
++		if (clk->enable_count > 0) {
++			if (!clk->current_freq_stats)
++				clk->default_freq_time =
++				ktime_add(clk->default_freq_time,
++				ktime_sub(ktime_get(), clk->start_time));
++			else
++				clk->current_freq_stats->time_spent =
++				ktime_add(clk->current_freq_stats->time_spent,
++				ktime_sub(ktime_get(), clk->start_time));
++
++			clk->start_time = ktime_set(0, 0);
++		}
++	}
++	hlist_for_each_entry(child, &clk->children, child_node)
++		clk_traverse_subtree(child, freq_stats_on);
++}
++
++static int freq_stats_set(void *data, u64 val)
++{
++	struct clk *c;
++	unsigned long flags;
++	struct hlist_head **lists = (struct hlist_head **)data;
++
++	clk_prepare_lock();
++	flags = clk_enable_lock();
++
++	if (val == 0)
++		freq_stats_on = 0;
++	else
++		freq_stats_on = 1;
++
++	for (; *lists; lists++)
++		hlist_for_each_entry(c, *lists, child_node)
++			clk_traverse_subtree(c, freq_stats_on);
++
++	clk_enable_unlock(flags);
++	clk_prepare_unlock();
++
++	return 0;
++}
++DEFINE_SIMPLE_ATTRIBUTE(freq_stats_fops, freq_stats_get,
++			freq_stats_set, "%llu\n");
++#endif /*CONFIG_COMMON_CLK_FREQ_STATS_ACCOUNTING*/
++
+ static int clk_debug_create_one(struct clk *clk, struct dentry *pdentry)
+ {
+ 	struct dentry *d;
+@@ -291,6 +497,14 @@ static int clk_debug_create_one(struct clk *clk, struct dentry *pdentry)
+ 	if (!d)
+ 		goto err_out;
+ 
++#ifdef CONFIG_COMMON_CLK_FREQ_STATS_ACCOUNTING
++	d = debugfs_create_file("frequency_stats_table", S_IRUGO, clk->dentry,
++			clk, &freq_stats_table_fops);
++
++	if (!d)
++		goto err_out;
++#endif /*CONFIG_COMMON_CLK_FREQ_STATS_ACCOUNTING*/
++
+ 	if (clk->ops->debug_init) {
+ 		ret = clk->ops->debug_init(clk->hw, clk->dentry);
+ 		if (ret)
+@@ -403,6 +617,13 @@ static int __init clk_debug_init(void)
+ 	if (!d)
+ 		return -ENOMEM;
+ 
++#ifdef CONFIG_COMMON_CLK_FREQ_STATS_ACCOUNTING
++	d = debugfs_create_file("freq_stats_on", S_IRUGO|S_IWUSR,
++				rootdir, &all_lists, &freq_stats_fops);
++	if (!d)
++		return -ENOMEM;
++#endif /*CONFIG_COMMON_CLK_FREQ_STATS_ACCOUNTING*/
++
+ 	mutex_lock(&clk_debug_lock);
+ 	hlist_for_each_entry(clk, &clk_debug_list, debug_node)
+ 		clk_debug_create_one(clk, rootdir);
+@@ -852,6 +1073,22 @@ static void __clk_disable(struct clk *clk)
+ 	if (clk->ops->disable)
+ 		clk->ops->disable(clk->hw);
+ 
++#ifdef CONFIG_COMMON_CLK_FREQ_STATS_ACCOUNTING
++
++	if (freq_stats_on) {
++		if (!clk->current_freq_stats)
++			clk->default_freq_time =
++			ktime_add(clk->default_freq_time,
++			ktime_sub(ktime_get(), clk->start_time));
++		else
++			clk->current_freq_stats->time_spent =
++			ktime_add(clk->current_freq_stats->time_spent,
++			ktime_sub(ktime_get(), clk->start_time));
++
++		clk->start_time = ktime_set(0, 0);
++	}
++#endif /*CONFIG_COMMON_CLK_FREQ_STATS_ACCOUNTING*/
++
+ 	__clk_disable(clk->parent);
+ }
+ 
+@@ -903,6 +1140,11 @@ static int __clk_enable(struct clk *clk)
+ 				return ret;
+ 			}
+ 		}
++
++#ifdef CONFIG_COMMON_CLK_FREQ_STATS_ACCOUNTING
++	if (freq_stats_on)
++		clk->start_time = ktime_get();
++#endif /*CONFIG_COMMON_CLK_FREQ_STATS_ACCOUNTING*/
+ 	}
+ 
+ 	clk->enable_count++;
+@@ -1483,6 +1725,32 @@ static void clk_change_rate(struct clk *clk)
+ 
+ 	clk->rate = clk_recalc(clk, best_parent_rate);
+ 
++#ifdef CONFIG_COMMON_CLK_FREQ_STATS_ACCOUNTING
++	if (freq_stats_on) {
++		if (!ktime_equal(clk->start_time, ktime_set(0, 0))) {
++			if (!clk->current_freq_stats)
++				clk->default_freq_time =
++					ktime_add(clk->default_freq_time,
++					ktime_sub(ktime_get(),
++					clk->start_time));
++			else
++				clk->current_freq_stats->time_spent =
++					ktime_add(
++					clk->current_freq_stats->time_spent,
++					ktime_sub(ktime_get(),
++					clk->start_time));
++		}
++
++		clk->current_freq_stats = freq_stats_insert(
++						&clk->freq_stats_table,
++						clk->rate);
++
++		if (clk->enable_count > 0)
++			clk->start_time = ktime_get();
++	}
++#endif /*CONFIG_COMMON_CLK_FREQ_STATS_ACCOUNTING*/
++
++
+ 	if (clk->notifier_count && old_rate != clk->rate)
+ 		__clk_notify(clk, POST_RATE_CHANGE, old_rate, clk->rate);
+ 
+@@ -2112,6 +2380,11 @@ static void __clk_release(struct kref *ref)
+ 
+ 	kfree(clk->parent_names);
+ 	kfree(clk->name);
++
++#ifdef CONFIG_COMMON_CLK_FREQ_STATS_ACCOUNTING
++	free_tree(clk->freq_stats_table.rb_node);
++#endif/*CONFIG_COMMON_CLK_FREQ_STATS_ACCOUNTING*/
++
+ 	kfree(clk);
+ }
+ 
+diff --git a/drivers/clk/hisilicon/Makefile b/drivers/clk/hisilicon/Makefile
+index 038c02f..cf455ca 100644
+--- a/drivers/clk/hisilicon/Makefile
++++ b/drivers/clk/hisilicon/Makefile
+@@ -2,8 +2,17 @@
+ # Hisilicon Clock specific Makefile
+ #
+ 
+-obj-y	+= clk.o clkgate-separated.o
++obj-y	+= clk.o clkgate-separated.o clk_ops.o
+ 
+ obj-$(CONFIG_ARCH_HI3xxx)	+= clk-hi3620.o
+ obj-$(CONFIG_ARCH_HIP04)	+= clk-hip04.o
+ obj-$(CONFIG_ARCH_HIX5HD2)	+= clk-hix5hd2.o
++obj-$(CONFIG_ARCH_HI3516CV300)	+= clk-hi3516cv300.o reset.o
++obj-$(CONFIG_ARCH_HI3519)	+= clk-hi3519.o reset.o
++obj-$(CONFIG_ARCH_HI3519V101)	+= clk-hi3519v101.o reset.o
++obj-$(CONFIG_ARCH_HI3516AV200)	+= clk-hi3516av200.o reset.o
++obj-$(CONFIG_ARCH_HI3559)	+= clk-hi3559.o reset.o
++obj-$(CONFIG_ARCH_HI3556)	+= clk-hi3556.o reset.o
++obj-$(CONFIG_ARCH_HI3536C)	+= clk-hi3536c.o reset.o
++obj-$(CONFIG_ARCH_HI3531D)	+= clk-hi3531d.o reset.o
++obj-$(CONFIG_ARCH_HI3521D)	+= clk-hi3521d.o reset.o
+diff --git a/drivers/clk/hisilicon/clk-hi3516av200.c b/drivers/clk/hisilicon/clk-hi3516av200.c
+new file mode 100644
+index 0000000..ca4c165
+--- /dev/null
++++ b/drivers/clk/hisilicon/clk-hi3516av200.c
+@@ -0,0 +1,385 @@
++/*
++ * Copyright (c) 2015 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <linux/of_address.h>
++#include <dt-bindings/clock/hi3516av200-clock.h>
++#include <linux/slab.h>
++#include <linux/delay.h>
++#include <mach/io.h>
++
++#include "clk.h"
++#include "reset.h"
++
++/******************************************************************************/
++struct hi3516av200_pll_clock {
++	u32		id;
++	const char	*name;
++	const char	*parent_name;
++	u32		ctrl_reg1;
++	u8		frac_shift;
++	u8		frac_width;
++	u8		postdiv1_shift;
++	u8		postdiv1_width;
++	u8		postdiv2_shift;
++	u8		postdiv2_width;
++	u32		ctrl_reg2;
++	u8		fbdiv_shift;
++	u8		fbdiv_width;
++	u8		refdiv_shift;
++	u8		refdiv_width;
++};
++
++struct hi3516av200_clk_pll {
++	struct clk_hw	hw;
++	u32		id;
++	void __iomem	*ctrl_reg1;
++	u8		frac_shift;
++	u8		frac_width;
++	u8		postdiv1_shift;
++	u8		postdiv1_width;
++	u8		postdiv2_shift;
++	u8		postdiv2_width;
++	void __iomem	*ctrl_reg2;
++	u8		fbdiv_shift;
++	u8		fbdiv_width;
++	u8		refdiv_shift;
++	u8		refdiv_width;
++};
++
++static struct hisi_fixed_rate_clock hi3516av200_fixed_rate_clks[] __initdata = {
++	{ HI3516AV200_FIXED_2376M, "2376m", NULL, CLK_IS_ROOT, 2376000000UL, },
++	{ HI3516AV200_FIXED_1188M, "1188m", NULL, CLK_IS_ROOT, 1188000000, },
++	{ HI3516AV200_FIXED_594M, "594m", NULL, CLK_IS_ROOT, 594000000, },
++	{ HI3516AV200_FIXED_297M, "297m", NULL, CLK_IS_ROOT, 297000000, },
++	{ HI3516AV200_FIXED_148P5M, "148p5m", NULL, CLK_IS_ROOT, 148500000, },
++	{ HI3516AV200_FIXED_74P25M, "74p25m", NULL, CLK_IS_ROOT, 74250000, },
++	{ HI3516AV200_FIXED_792M, "792m", NULL, CLK_IS_ROOT, 792000000, },
++	{ HI3516AV200_FIXED_475M, "475m", NULL, CLK_IS_ROOT, 475000000, },
++	{ HI3516AV200_FIXED_340M, "340m", NULL, CLK_IS_ROOT, 340000000, },
++	{ HI3516AV200_FIXED_72M, "72m", NULL, CLK_IS_ROOT, 72000000, },
++	{ HI3516AV200_FIXED_400M, "400m", NULL, CLK_IS_ROOT, 400000000, },
++	{ HI3516AV200_FIXED_200M, "200m", NULL, CLK_IS_ROOT, 200000000, },
++	{ HI3516AV200_FIXED_54M, "54m", NULL, CLK_IS_ROOT, 54000000, },
++	{ HI3516AV200_FIXED_27M, "27m", NULL, CLK_IS_ROOT, 1188000000, },
++	{ HI3516AV200_FIXED_37P125M, "37p125m", NULL, CLK_IS_ROOT, 37125000, },
++	{ HI3516AV200_FIXED_3000M, "3000m", NULL, CLK_IS_ROOT, 3000000000UL, },
++	{ HI3516AV200_FIXED_1500M, "1500m", NULL, CLK_IS_ROOT, 1500000000, },
++	{ HI3516AV200_FIXED_500M, "500m", NULL, CLK_IS_ROOT, 500000000, },
++	{ HI3516AV200_FIXED_250M, "250m", NULL, CLK_IS_ROOT, 250000000, },
++	{ HI3516AV200_FIXED_125M, "125m", NULL, CLK_IS_ROOT, 125000000, },
++	{ HI3516AV200_FIXED_1000M, "1000m", NULL, CLK_IS_ROOT, 1000000000, },
++	{ HI3516AV200_FIXED_600M, "600m", NULL, CLK_IS_ROOT, 600000000, },
++	{ HI3516AV200_FIXED_750M, "750m", NULL, CLK_IS_ROOT, 750000000, },
++	{ HI3516AV200_FIXED_150M, "150m", NULL, CLK_IS_ROOT, 150000000, },
++	{ HI3516AV200_FIXED_75M, "75m", NULL, CLK_IS_ROOT, 75000000, },
++	{ HI3516AV200_FIXED_300M, "300m", NULL, CLK_IS_ROOT, 300000000, },
++	{ HI3516AV200_FIXED_60M, "60m", NULL, CLK_IS_ROOT, 60000000, },
++	{ HI3516AV200_FIXED_214M, "214m", NULL, CLK_IS_ROOT, 214000000, },
++	{ HI3516AV200_FIXED_107M, "107m", NULL, CLK_IS_ROOT, 107000000, },
++	{ HI3516AV200_FIXED_100M, "100m", NULL, CLK_IS_ROOT, 100000000, },
++	{ HI3516AV200_FIXED_50M, "50m", NULL, CLK_IS_ROOT, 50000000, },
++	{ HI3516AV200_FIXED_25M, "25m", NULL, CLK_IS_ROOT, 25000000, },
++	{ HI3516AV200_FIXED_24M, "24m", NULL, CLK_IS_ROOT, 24000000, },
++	{ HI3516AV200_FIXED_3M, "3m", NULL, CLK_IS_ROOT, 3000000, },
++	{ HI3516AV200_FIXED_198M, "198m", NULL, CLK_IS_ROOT, 198000000, },
++	{ HI3516AV200_FIXED_396M, "396m", NULL, CLK_IS_ROOT, 396000000, },
++};
++
++static const char *sysaxi_mux_p[] __initconst = {"24m", "198m", };
++static u32 sysaxi_mux_table[] = {0, 1};
++
++static const char *fmc_mux_p[] __initconst = {
++	"24m", "75m", "125m", "150m", "198m", "250m", "300m", "396m", };
++static u32 fmc_mux_table[] = {0, 1, 2, 3, 4, 5, 6, 7};
++
++static const char *mmc_mux_p[] __initconst = {
++	"100m", "198m", "396m", "594m", "792m", "1188m", };
++static u32 mmc_mux_table[] = {0, 1, 3, 4, 5, 7};
++
++static const char *a17_mux_p[] __initconst = {
++	"24m", "apll", "594m", "792m", };
++static u32 a17_mux_table[] = {0, 1, 3, 4};
++
++static const char *i2c_mux_p[] __initconst = {"clk_sysapb", "50m"};
++static u32 i2c_mux_table[] = {0, 1};
++
++static struct hisi_mux_clock hi3516av200_mux_clks[] __initdata = {
++	{ HI3516AV200_SYSAXI_MUX, "sysaxi_mux", sysaxi_mux_p,
++		ARRAY_SIZE(sysaxi_mux_p),
++		CLK_SET_RATE_PARENT, 0x34, 12, 2, 0, sysaxi_mux_table, },
++	{ HI3516AV200_FMC_MUX, "fmc_mux", fmc_mux_p, ARRAY_SIZE(fmc_mux_p),
++		CLK_SET_RATE_PARENT, 0xc0, 2, 3, 0, fmc_mux_table, },
++	{ HI3516AV200_MMC0_MUX, "mmc0_mux", mmc_mux_p, ARRAY_SIZE(mmc_mux_p),
++		CLK_SET_RATE_PARENT, 0xc4, 10, 3, 0, mmc_mux_table, },
++	{ HI3516AV200_MMC1_MUX, "mmc1_mux", mmc_mux_p, ARRAY_SIZE(mmc_mux_p),
++		CLK_SET_RATE_PARENT, 0xc4, 2, 3, 0, mmc_mux_table, },
++	{ HI3516AV200_MMC2_MUX, "mmc2_mux", mmc_mux_p, ARRAY_SIZE(mmc_mux_p),
++		CLK_SET_RATE_PARENT, 0xc4, 18, 3, 0, mmc_mux_table, },
++	{ HI3516AV200_A17_MUX, "a17_mux", a17_mux_p, ARRAY_SIZE(a17_mux_p),
++		CLK_SET_RATE_PARENT, 0x34, 4, 3, 0, a17_mux_table, },
++	{ HI3516AV200_I2C_MUX, "i2c_mux", i2c_mux_p, ARRAY_SIZE(i2c_mux_p),
++		CLK_SET_RATE_PARENT, 0xe4, 26, 1, 0, i2c_mux_table, },
++
++};
++
++static struct hisi_fixed_factor_clock
++	hi3516av200_fixed_factor_clks[] __initdata = {
++	{ HI3516AV200_SYSAPB_CLK, "clk_sysapb", "sysaxi_mux", 1, 4,
++		CLK_SET_RATE_PARENT},
++	{ HI3516AV200_MMC0_FAC_CLK, "mmc0_fac", "mmc0_mux", 1, 8,
++		CLK_SET_RATE_PARENT},
++	{ HI3516AV200_MMC1_FAC_CLK, "mmc1_fac", "mmc1_mux", 1, 8,
++		CLK_SET_RATE_PARENT},
++	{ HI3516AV200_MMC2_FAC_CLK, "mmc2_fac", "mmc2_mux", 1, 8,
++		CLK_SET_RATE_PARENT},
++};
++
++static struct hisi_gate_clock hi3516av200_gate_clks[] __initdata = {
++#ifdef CONFIG_HIFMC
++	/* fmc */
++	{ HI3516AV200_FMC_CLK, "clk_fmc", "fmc_mux",
++		CLK_SET_RATE_PARENT, 0xc0, 1, 0, },
++#endif
++	/* mmc */
++	{ HI3516AV200_MMC0_CLK, "clk_mmc0", "mmc0_fac",
++		CLK_SET_RATE_PARENT, 0xc4, 9, 0, },
++	{ HI3516AV200_MMC1_CLK, "clk_mmc1", "mmc1_fac",
++		CLK_SET_RATE_PARENT, 0xc4, 1, 0, },
++	{ HI3516AV200_MMC2_CLK, "clk_mmc2", "mmc2_fac",
++		CLK_SET_RATE_PARENT, 0xc4, 17, 0, },
++
++	/* usb ctrl */
++	{ HI3516AV200_USB2_CTRL_UTMI0_REQ, "usb2_cttl_utmi0_req", NULL,
++		CLK_SET_RATE_PARENT, 0xb4, 5, 1, },
++	{ HI3516AV200_USB2_HRST_REQ, "usb2_hrst_req", NULL,
++		CLK_SET_RATE_PARENT, 0xb4, 0, 1, },
++	{ HI3516AV200_USB3_CLK, "usb3_vcc_srst_req2", NULL,
++		CLK_SET_RATE_PARENT, 0xb8, 0, 1, },
++
++	/* uart */
++	{ HI3516AV200_UART0_CLK, "clk_uart0", "24m",
++		CLK_SET_RATE_PARENT, 0xe4, 20, 0, },
++	{ HI3516AV200_UART1_CLK, "clk_uart1", "24m",
++		CLK_SET_RATE_PARENT, 0xe4, 21, 0, },
++	{ HI3516AV200_UART2_CLK, "clk_uart2", "24m",
++		CLK_SET_RATE_PARENT, 0xe4, 22, 0, },
++	{ HI3516AV200_UART3_CLK, "clk_uart3", "24m",
++		CLK_SET_RATE_PARENT, 0xe4, 23, 0, },
++	{ HI3516AV200_UART4_CLK, "clk_uart4", "24m",
++		CLK_SET_RATE_PARENT, 0xe4, 24, 0, },
++
++	/* ethernet mac */
++	{ HI3516AV200_ETH_CLK, "clk_eth", NULL,
++		CLK_IS_ROOT, 0xcc, 1, 0, },
++	{ HI3516AV200_ETH_MACIF_CLK, "clk_eth_macif", NULL,
++		CLK_IS_ROOT, 0xcc, 3, 0, },
++
++	/* spi */
++	{ HI3516AV200_SPI0_CLK, "clk_spi0", "clk_sysapb",
++		CLK_SET_RATE_PARENT, 0xe4, 16, 0, },
++	{ HI3516AV200_SPI1_CLK, "clk_spi1", "clk_sysapb",
++		CLK_SET_RATE_PARENT, 0xe4, 17, 0, },
++	{ HI3516AV200_SPI2_CLK, "clk_spi2", "clk_sysapb",
++		CLK_SET_RATE_PARENT, 0xe4, 18, 0, },
++	{ HI3516AV200_SPI3_CLK, "clk_spi3", "clk_sysapb",
++		CLK_SET_RATE_PARENT, 0xe4, 28, 0, },
++};
++
++static struct hi3516av200_pll_clock hi3516av200_pll_clks[] __initdata = {
++	{ HI3516AV200_APLL_CLK, "apll", NULL, 0x0, 0, 24, 24, 3, 28, 3,
++		0x4, 0, 12, 12, 6},
++};
++
++
++#define to_pll_clk(_hw) container_of(_hw, struct hi3516av200_clk_pll, hw)
++
++static void hi3516av200_calc_pll(u32 *frac_val,
++		u32 *postdiv1_val,
++		u32 *postdiv2_val,
++		u32 *fbdiv_val,
++		u32 *refdiv_val,
++		unsigned long rate)
++{
++	u64 rem;
++	*frac_val = 0;
++	rem = do_div(rate, 1000000);
++	*fbdiv_val = rate;
++	*refdiv_val = 24;
++	rem = rem * (1 << 24);
++	do_div(rem, 1000000);
++	*frac_val = rem;
++}
++
++static int clk_pll_set_rate(struct clk_hw *hw,
++			unsigned long rate,
++			unsigned long parent_rate)
++{
++	struct hi3516av200_clk_pll *clk = to_pll_clk(hw);
++	u32 frac_val, postdiv1_val, postdiv2_val, fbdiv_val, refdiv_val;
++	u32 val;
++
++	/*Fixme  ignore postdives now because apll don't use them*/
++	postdiv1_val = postdiv2_val = 0;
++
++	hi3516av200_calc_pll(&frac_val, &postdiv1_val, &postdiv2_val,
++			&fbdiv_val, &refdiv_val, rate);
++
++	val = readl_relaxed(clk->ctrl_reg1);
++	val &= ~(((1 << clk->frac_width) - 1) << clk->frac_shift);
++	val &= ~(((1 << clk->postdiv1_width) - 1) << clk->postdiv1_shift);
++	val &= ~(((1 << clk->postdiv2_width) - 1) << clk->postdiv2_shift);
++
++	val |= frac_val << clk->frac_shift;
++	val |= postdiv1_val << clk->postdiv1_shift;
++	val |= postdiv2_val << clk->postdiv2_shift;
++	writel_relaxed(val, clk->ctrl_reg1);
++
++	val = readl_relaxed(clk->ctrl_reg2);
++	val &= ~(((1 << clk->fbdiv_width) - 1) << clk->fbdiv_shift);
++	val &= ~(((1 << clk->refdiv_width) - 1) << clk->refdiv_shift);
++
++	val |= fbdiv_val << clk->fbdiv_shift;
++	val |= refdiv_val << clk->refdiv_shift;
++	writel_relaxed(val, clk->ctrl_reg2);
++
++	return 0;
++}
++
++static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
++		unsigned long parent_rate)
++{
++	struct hi3516av200_clk_pll *clk = to_pll_clk(hw);
++	u64 frac_val, fbdiv_val, refdiv_val;
++	u32 val;
++	u64 tmp, rate;
++
++	val = readl_relaxed(clk->ctrl_reg1);
++	val = val >> clk->frac_shift;
++	val &= ((1 << clk->frac_width) - 1);
++	frac_val = val;
++
++	val = readl_relaxed(clk->ctrl_reg2);
++	val = val >> clk->fbdiv_shift;
++	val &= ((1 << clk->fbdiv_width) - 1);
++	fbdiv_val = val;
++
++	val = readl_relaxed(clk->ctrl_reg2);
++	val = val >> clk->refdiv_shift;
++	val &= ((1 << clk->refdiv_width) - 1);
++	refdiv_val = val;
++
++	/* rate = 24000000 * (fbdiv + frac / (1<<24) ) / refdiv  */
++	rate = 0;
++	tmp = 24000000 * fbdiv_val;
++	rate += tmp;
++	do_div(rate, refdiv_val);
++
++	return rate;
++}
++
++
++static long clk_pll_determine_rate(struct clk_hw *hw, unsigned long rate,
++		unsigned long *best_parent_rate,
++		struct clk **best_parent_p)
++{
++	return rate;
++}
++
++static struct clk_ops clk_pll_ops = {
++	.set_rate = clk_pll_set_rate,
++	.determine_rate = clk_pll_determine_rate,
++	.recalc_rate = clk_pll_recalc_rate,
++};
++
++void __init hi3516av200_clk_register_pll(struct hi3516av200_pll_clock *clks,
++		int nums, struct hisi_clock_data *data)
++{
++	void __iomem *base = data->base;
++	int i;
++
++	for (i = 0; i < nums; i++) {
++		struct hi3516av200_clk_pll *p_clk;
++		struct clk *clk;
++		struct clk_init_data init;
++
++		p_clk = kzalloc(sizeof(*p_clk), GFP_KERNEL);
++		if (!p_clk)
++			return;
++
++		init.name = clks[i].name;
++		init.flags = CLK_IS_BASIC;
++		init.parent_names =
++			(clks[i].parent_name ? &clks[i].parent_name : NULL);
++		init.num_parents = (clks[i].parent_name ? 1 : 0);
++		init.ops = &clk_pll_ops;
++
++		p_clk->ctrl_reg1 = base + clks[i].ctrl_reg1;
++		p_clk->frac_shift = clks[i].frac_shift;
++		p_clk->frac_width = clks[i].frac_width;
++		p_clk->postdiv1_shift = clks[i].postdiv1_shift;
++		p_clk->postdiv1_width = clks[i].postdiv1_width;
++		p_clk->postdiv2_shift = clks[i].postdiv2_shift;
++		p_clk->postdiv2_width = clks[i].postdiv2_width;
++
++		p_clk->ctrl_reg2 = base + clks[i].ctrl_reg2;
++		p_clk->fbdiv_shift = clks[i].fbdiv_shift;
++		p_clk->fbdiv_width = clks[i].fbdiv_width;
++		p_clk->refdiv_shift = clks[i].refdiv_shift;
++		p_clk->refdiv_width = clks[i].refdiv_width;
++		p_clk->hw.init = &init;
++
++		clk = clk_register(NULL, &p_clk->hw);
++		if (IS_ERR(clk)) {
++			kfree(p_clk);
++			pr_err("%s: failed to register clock %s\n",
++					__func__, clks[i].name);
++			continue;
++		}
++
++		data->clk_data.clks[clks[i].id] = clk;
++	}
++
++
++}
++
++static void __init hi3516av200_clk_init(struct device_node *np)
++{
++	struct hisi_clock_data *clk_data;
++
++	clk_data = hisi_clk_init(np, HI3516AV200_NR_CLKS);
++	if (!clk_data)
++		return;
++	if (IS_ENABLED(CONFIG_RESET_CONTROLLER))
++		hisi_reset_init(np, HI3516AV200_NR_RSTS);
++
++	hisi_clk_register_fixed_rate(hi3516av200_fixed_rate_clks,
++			ARRAY_SIZE(hi3516av200_fixed_rate_clks),
++			clk_data);
++	hi3516av200_clk_register_pll(hi3516av200_pll_clks,
++			ARRAY_SIZE(hi3516av200_pll_clks), clk_data);
++
++	hisi_clk_register_mux(hi3516av200_mux_clks,
++			ARRAY_SIZE(hi3516av200_mux_clks),
++			clk_data);
++	hisi_clk_register_fixed_factor(hi3516av200_fixed_factor_clks,
++			ARRAY_SIZE(hi3516av200_fixed_factor_clks), clk_data);
++	hisi_clk_register_gate(hi3516av200_gate_clks,
++			ARRAY_SIZE(hi3516av200_gate_clks), clk_data);
++}
++
++CLK_OF_DECLARE(hi3516av200_clk, "hisilicon,hi3516av200-clock",
++		hi3516av200_clk_init);
+diff --git a/drivers/clk/hisilicon/clk-hi3516cv300.c b/drivers/clk/hisilicon/clk-hi3516cv300.c
+new file mode 100644
+index 0000000..4d41475
+--- /dev/null
++++ b/drivers/clk/hisilicon/clk-hi3516cv300.c
+@@ -0,0 +1,244 @@
++/*
++ * Hi3516cv300 Clock Driver
++ *
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include <dt-bindings/clock/hi3516cv300-clock.h>
++#include "clk.h"
++#include "reset.h"
++
++static struct
++hisi_fixed_rate_clock hi3516cv300_fixed_rate_clks_crg[] __initdata = {
++	{ HI3516CV300_FIXED_3M, "3m", NULL, CLK_IS_ROOT, 3000000, },
++	{ HI3516CV300_FIXED_6M, "6m", NULL, CLK_IS_ROOT, 6000000, },
++	{ HI3516CV300_FIXED_12M, "12m", NULL, CLK_IS_ROOT, 12000000, },
++	{ HI3516CV300_FIXED_15M, "15m", NULL, CLK_IS_ROOT, 15000000, },
++	{ HI3516CV300_FIXED_24M, "24m", NULL, CLK_IS_ROOT, 24000000, },
++	{ HI3516CV300_FIXED_25M, "25m", NULL, CLK_IS_ROOT, 25000000, },
++	{ HI3516CV300_FIXED_27M, "27m", NULL, CLK_IS_ROOT, 27000000, },
++	{ HI3516CV300_FIXED_37P125M, "37.125m", NULL, CLK_IS_ROOT, 37125000, },
++	{ HI3516CV300_FIXED_44M, "44m", NULL, CLK_IS_ROOT, 44000000, },
++	{ HI3516CV300_FIXED_49P5M, "49.5m", NULL, CLK_IS_ROOT, 49500000, },
++	{ HI3516CV300_FIXED_50M, "50m", NULL, CLK_IS_ROOT, 50000000, },
++	{ HI3516CV300_FIXED_54M, "54m", NULL, CLK_IS_ROOT, 54000000, },
++	{ HI3516CV300_FIXED_74P25M, "74.25m", NULL, CLK_IS_ROOT, 74250000, },
++	{ HI3516CV300_FIXED_75M, "75m", NULL, CLK_IS_ROOT, 75000000, },
++	{ HI3516CV300_FIXED_83P3M, "83.3m", NULL, CLK_IS_ROOT, 83300000, },
++	{ HI3516CV300_FIXED_99M, "99m", NULL, CLK_IS_ROOT, 99000000, },
++	{ HI3516CV300_FIXED_100M, "100m", NULL, CLK_IS_ROOT, 100000000, },
++	{ HI3516CV300_FIXED_125M, "125m", NULL, CLK_IS_ROOT, 125000000, },
++	{ HI3516CV300_FIXED_148P5M, "148.5m", NULL, CLK_IS_ROOT, 148500000, },
++	{ HI3516CV300_FIXED_150M, "150m", NULL, CLK_IS_ROOT, 150000000, },
++	{ HI3516CV300_FIXED_166P6M, "166.6m", NULL, CLK_IS_ROOT, 166600000, },
++	{ HI3516CV300_FIXED_198M, "198m", NULL, CLK_IS_ROOT, 198000000, },
++	{ HI3516CV300_FIXED_200M, "200m", NULL, CLK_IS_ROOT, 200000000, },
++	{ HI3516CV300_FIXED_250M, "250m", NULL, CLK_IS_ROOT, 250000000, },
++	{ HI3516CV300_FIXED_297M, "297m", NULL, CLK_IS_ROOT, 297000000, },
++	{ HI3516CV300_FIXED_300M, "300m", NULL, CLK_IS_ROOT, 300000000, },
++	{ HI3516CV300_FIXED_396M, "396m", NULL, CLK_IS_ROOT, 396000000, },
++	{ HI3516CV300_FIXED_400M, "400m", NULL, CLK_IS_ROOT, 400000000, },
++};
++
++static const char *apb_mux_p[] __initconst = {"24m", "50m"};
++static const char *uart_mux_p[] __initconst = {"24m", "6m"};
++static const char *fmc_mux_p[] __initconst = {
++	"24m", "83.3m", "148.5m", "198m", "297m"
++};
++static const char *mmc_mux_p[] __initconst = {"49.5m"};
++static const char *mmc2_mux_p[] __initconst = {"99m", "49.5m"};
++static const char *sensor_mux_p[] = {"74.25m", "37.125m", "54m", "27m", "24m", "25m", "24m", "25m"};
++static const char *viu_mux_p[] = {"83.3m", "125m", "148.5m", "198m", "250m"};
++static const char *vedu_mux_p[] = {"166.6m", "198m"};
++static const char *vpss_mux_p[] = {"148.5m", "198m", "250m"};
++static const char *vgs_mux_p[] = {"198m", "250m", "297m"};
++static const char *ive_mux_p[] = {"198m", "250m", "297m"};
++static const char *pwm_mux_p[] = {"3m", "50m", "24m", "24m"};
++
++static u32 apb_mux_table[] = {0, 1};
++static u32 uart_mux_table[] = {0, 1};
++static u32 fmc_mux_table[] = {0, 1, 2, 3, 4};
++static u32 mmc_mux_table[] = {0};
++static u32 mmc2_mux_table[] = {0, 2};
++static u32 pwm_mux_table[] = {0, 1, 2, 3};
++
++static u32 sensor_mux_p_table[] = {0, 1, 2, 3, 4, 5, 6, 7};
++static u32 viu_mux_p_table[] = {0, 1, 2, 3, 4};
++static u32 vedu_mux_p_table[] = {0, 1};
++static u32 vpss_mux_p_table[] = {0, 1, 2};
++static u32 vgs_mux_p_table[] = {0, 1, 2};
++static u32 ive_mux_p_table[] = {0, 1, 2};
++static struct hisi_mux_clock hi3516cv300_mux_clks_crg[] __initdata = {
++	{ HI3516CV300_APB_CLK, "apb", apb_mux_p, ARRAY_SIZE(apb_mux_p),
++		CLK_SET_RATE_PARENT, 0x30, 0, 1, 0, apb_mux_table, },
++	{ HI3516CV300_UART_MUX, "uart_mux", uart_mux_p, ARRAY_SIZE(uart_mux_p),
++		CLK_SET_RATE_PARENT, 0xe4, 19, 1, 0, uart_mux_table, },
++	{ HI3516CV300_FMC_MUX, "fmc_mux", fmc_mux_p, ARRAY_SIZE(fmc_mux_p),
++		CLK_SET_RATE_PARENT, 0xc0, 2, 3, 0, fmc_mux_table, },
++	{ HI3516CV300_MMC0_MUX, "mmc0_mux", mmc_mux_p, ARRAY_SIZE(mmc_mux_p),
++		CLK_SET_RATE_PARENT, 0xc4, 4, 2, 0, mmc_mux_table, },
++	{ HI3516CV300_MMC1_MUX, "mmc1_mux", mmc_mux_p, ARRAY_SIZE(mmc_mux_p),
++		CLK_SET_RATE_PARENT, 0xc4, 12, 2, 0, mmc_mux_table, },
++	{ HI3516CV300_MMC2_MUX, "mmc2_mux", mmc2_mux_p, ARRAY_SIZE(mmc2_mux_p),
++		CLK_SET_RATE_PARENT, 0xc4, 20, 2, 0, mmc2_mux_table, },
++	{ HI3516CV300_MMC3_MUX, "mmc3_mux", mmc_mux_p, ARRAY_SIZE(mmc_mux_p),
++		CLK_SET_RATE_PARENT, 0xc8, 4, 2, 0, mmc_mux_table, },
++	{ HI3516CV300_PWM_MUX, "pwm_mux", pwm_mux_p, ARRAY_SIZE(pwm_mux_p),
++		CLK_SET_RATE_PARENT, 0x38, 2, 2, 0, pwm_mux_table, },
++
++	/* media mux clock*/
++	{ HI3516CV300_SENSOR_MUX, "sensor_mux", sensor_mux_p, ARRAY_SIZE(sensor_mux_p),
++		CLK_SET_RATE_PARENT, 0x2c, 23, 3, 0, sensor_mux_p_table, },
++	{ HI3516CV300_VIU_MUX, "viu_mux", viu_mux_p, ARRAY_SIZE(viu_mux_p),
++		CLK_SET_RATE_PARENT, 0x2c, 2, 3, 0, viu_mux_p_table, },
++	{ HI3516CV300_VEDU_MUX, "vedu_mux", vedu_mux_p, ARRAY_SIZE(vedu_mux_p),
++		CLK_SET_RATE_PARENT, 0x40, 10, 2, 0, vedu_mux_p_table, },
++	{ HI3516CV300_VPSS_MUX, "vpss_mux", vpss_mux_p, ARRAY_SIZE(vpss_mux_p),
++		CLK_SET_RATE_PARENT, 0x48, 10, 2, 0, vpss_mux_p_table, },
++	{ HI3516CV300_VGS_MUX, "vgs_mux", vgs_mux_p, ARRAY_SIZE(vgs_mux_p),
++		CLK_SET_RATE_PARENT, 0x5c, 10, 2, 0, vgs_mux_p_table, },
++	{ HI3516CV300_IVE_MUX, "ive_mux", ive_mux_p, ARRAY_SIZE(ive_mux_p),
++		CLK_SET_RATE_PARENT, 0x6c, 2, 2, 0, ive_mux_p_table, },
++};
++
++static struct hisi_divider_clock hi3516cv300_div_clks[] = {
++	{ HI3516CV300_ISP_DIV, "isp_div", "viu_mux", 0, 0x2c, 17, 1, 0, NULL, },
++};
++
++static struct hisi_gate_clock hi3516cv300_gate_clks_crg[] __initdata = {
++	/* uart */
++	{ HI3516CV300_UART0_CLK, "clk_uart0", "uart_mux",
++		CLK_SET_RATE_PARENT, 0xe4, 15, 0, },
++	{ HI3516CV300_UART1_CLK, "clk_uart1", "uart_mux",
++		CLK_SET_RATE_PARENT, 0xe4, 16, 0, },
++	{ HI3516CV300_UART2_CLK, "clk_uart2", "uart_mux",
++		CLK_SET_RATE_PARENT, 0xe4, 17, 0, },
++	/* spi */
++	{ HI3516CV300_SPI0_CLK, "clk_spi0", "100m",
++		CLK_SET_RATE_PARENT, 0xe4, 13, 0, },
++	{ HI3516CV300_SPI1_CLK, "clk_spi1", "100m",
++		CLK_SET_RATE_PARENT, 0xe4, 14, 0, },
++	/* fmc */
++	{ HI3516CV300_FMC_CLK, "clk_fmc", "fmc_mux",
++		CLK_SET_RATE_PARENT, 0xc0, 1, 0, },
++	{ HI3516CV300_MMC0_CLK, "clk_mmc0", "mmc0_mux",
++		CLK_SET_RATE_PARENT, 0xc4, 1, 0, },
++	{ HI3516CV300_MMC1_CLK, "clk_mmc1", "mmc1_mux",
++		CLK_SET_RATE_PARENT, 0xc4, 9, 0, },
++	{ HI3516CV300_MMC2_CLK, "clk_mmc2", "mmc2_mux",
++		CLK_SET_RATE_PARENT, 0xc4, 17, 0, },
++	{ HI3516CV300_MMC3_CLK, "clk_mmc3", "mmc3_mux",
++		CLK_SET_RATE_PARENT, 0xc8, 1, 0, },
++	/* ethernet mac */
++	{ HI3516CV300_ETH_CLK, "clk_eth", NULL, CLK_IS_ROOT, 0xec, 1, 0, },
++	{ HI3516CV300_USB2_BUS_CLK, "clk_usb2_bus", NULL,
++		CLK_SET_RATE_PARENT, 0xb8, 8, 1, },
++	{ HI3516CV300_UTMI0_CLK, "clk_utmi0", NULL,
++		CLK_SET_RATE_PARENT, 0xb8, 11, 1, },
++	{ HI3516CV300_USB2_CLK, "clk_usb2", NULL,
++		CLK_SET_RATE_PARENT, 0xb8, 12, 1, },
++	{ HI3516CV300_DMAC_CLK, "clk_dmac", NULL, CLK_IS_ROOT, 0xd8, 5, 0, },
++
++	{ HI3516CV300_PWM_CLK, "clk_pwm", "pwm_mux", CLK_SET_RATE_PARENT,
++		0x38, 1, 0, },
++
++	/* media gate clock*/
++	{ HI3516CV300_SENSOR_CLK, "clk_sensor", "sensor_mux", CLK_SET_RATE_PARENT,
++		0x2c, 26, 0, },
++	{ HI3516CV300_MIPI_CLK, "clk_mipi", NULL, CLK_SET_RATE_PARENT,
++		0x2c, 15, 0, },
++	{ HI3516CV300_ISP_CLK, "clk_isp", "isp_div", CLK_SET_RATE_PARENT, 0x2c, 18, 0, },
++	{ HI3516CV300_VIU_CLK, "clk_viu", "viu_mux", CLK_SET_RATE_PARENT,
++		0x2c, 0, 0, },
++	{ HI3516CV300_VEDU_CLK, "clk_vedu", "vedu_mux", CLK_SET_RATE_PARENT,
++		0x40, 1, 0, },
++	{ HI3516CV300_VPSS_CLK, "clk_vpss", "vpss_mux", CLK_SET_RATE_PARENT,
++		0x48, 1, 0, },
++	{ HI3516CV300_VGS_CLK, "clk_vgs", "vgs_mux", CLK_SET_RATE_PARENT,
++		0x5c, 1, 0, },
++	{ HI3516CV300_JPGE_CLK, "clk_jpge", NULL, CLK_SET_RATE_PARENT,
++		0x60, 1, 0, },
++	{ HI3516CV300_IVE_CLK, "clk_ive", "ive_mux", CLK_SET_RATE_PARENT,
++		0x6c, 1, 0, },
++	{ HI3516CV300_AIAO_CLK, "clk_aiao", NULL, CLK_SET_RATE_PARENT,
++		0x8c, 1, 0, },
++};
++
++static void __init hi3516cv300_clk_crg_init(struct device_node *np)
++{
++	struct hisi_clock_data *clk_data;
++	unsigned int count = 0;
++
++	clk_data = hisi_clk_init(np, HI3516CV300_CRG_NR_CLKS);
++	if (!clk_data)
++		return;
++
++	hisi_clk_register_fixed_rate(hi3516cv300_fixed_rate_clks_crg,
++			ARRAY_SIZE(hi3516cv300_fixed_rate_clks_crg),
++			clk_data);
++	hisi_clk_register_mux(hi3516cv300_mux_clks_crg,
++			ARRAY_SIZE(hi3516cv300_mux_clks_crg), clk_data);
++	hisi_clk_register_divider(hi3516cv300_div_clks,
++			ARRAY_SIZE(hi3516cv300_div_clks), clk_data);
++	hisi_clk_register_gate(hi3516cv300_gate_clks_crg,
++			ARRAY_SIZE(hi3516cv300_gate_clks_crg), clk_data);
++
++	if (!of_property_read_u32(np, "#reset-cells", &count) && (count == 2))
++		hisi_reset_init(np, HI3516CV300_CRG_NR_RSTS);
++}
++
++static const char *timer_mux_p[] __initconst = { "3m", "apb" };
++static u32 timer_mux_table[] = {0, 1};
++
++static struct hisi_mux_clock hi3516cv300_mux_clks_sys[] __initdata = {
++	{ HI3516CV300_TIME00_CLK, "timer00", timer_mux_p,
++		ARRAY_SIZE(timer_mux_p), CLK_SET_RATE_PARENT,
++		0x0, 16, 1, 0, timer_mux_table, },
++
++	{ HI3516CV300_TIME01_CLK, "timer01", timer_mux_p,
++		ARRAY_SIZE(timer_mux_p), CLK_SET_RATE_PARENT,
++		0x0, 18, 1, 0, timer_mux_table, },
++
++	{ HI3516CV300_TIME10_CLK, "timer10", timer_mux_p,
++		ARRAY_SIZE(timer_mux_p), CLK_SET_RATE_PARENT,
++		0x0, 20, 1, 0, timer_mux_table, },
++
++	{ HI3516CV300_TIME11_CLK, "timer11", timer_mux_p,
++		ARRAY_SIZE(timer_mux_p), CLK_SET_RATE_PARENT,
++		0x0, 22, 1, 0, timer_mux_table, },
++};
++
++static void __init hi3516cv300_clk_sys_init(struct device_node *np)
++{
++	struct hisi_clock_data *clk_data;
++	unsigned int count = 0;
++
++	clk_data = hisi_clk_init(np, HI3516CV300_SYS_NR_CLKS);
++	if (!clk_data)
++		return;
++
++	hisi_clk_register_mux(hi3516cv300_mux_clks_sys,
++			ARRAY_SIZE(hi3516cv300_mux_clks_sys), clk_data);
++
++	if (!of_property_read_u32(np, "#reset-cells", &count) && (count == 2))
++		hisi_reset_init(np, HI3516CV300_SYS_NR_RSTS);
++}
++
++CLK_OF_DECLARE(hi3516cv300_clk, "hisilicon,hi3516cv300-crg",
++		hi3516cv300_clk_crg_init);
++CLK_OF_DECLARE(hi3516cv300_clk_sys, "hisilicon,hi3516cv300-sys",
++		hi3516cv300_clk_sys_init);
+diff --git a/drivers/clk/hisilicon/clk-hi3519.c b/drivers/clk/hisilicon/clk-hi3519.c
+new file mode 100644
+index 0000000..1cd0676
+--- /dev/null
++++ b/drivers/clk/hisilicon/clk-hi3519.c
+@@ -0,0 +1,375 @@
++/*
++ * Copyright (c) 2015 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <linux/of_address.h>
++#include <dt-bindings/clock/hi3519-clock.h>
++#include <linux/slab.h>
++#include <linux/delay.h>
++#include <mach/io.h>
++
++#include "clk.h"
++#include "reset.h"
++
++/******************************************************************************/
++struct hi3519_pll_clock {
++	u32		id;
++	const char	*name;
++	const char	*parent_name;
++	u32		ctrl_reg1;
++	u8		frac_shift;
++	u8		frac_width;
++	u8		postdiv1_shift;
++	u8		postdiv1_width;
++	u8		postdiv2_shift;
++	u8		postdiv2_width;
++	u32		ctrl_reg2;
++	u8		fbdiv_shift;
++	u8		fbdiv_width;
++	u8		refdiv_shift;
++	u8		refdiv_width;
++};
++
++struct hi3519_clk_pll {
++	struct clk_hw	hw;
++	u32		id;
++	void __iomem	*ctrl_reg1;
++	u8		frac_shift;
++	u8		frac_width;
++	u8		postdiv1_shift;
++	u8		postdiv1_width;
++	u8		postdiv2_shift;
++	u8		postdiv2_width;
++	void __iomem	*ctrl_reg2;
++	u8		fbdiv_shift;
++	u8		fbdiv_width;
++	u8		refdiv_shift;
++	u8		refdiv_width;
++};
++
++static struct hisi_fixed_rate_clock hi3519_fixed_rate_clks[] __initdata = {
++	{ HI3519_FIXED_2376M, "2376m", NULL, CLK_IS_ROOT, 2376000000UL, },
++	{ HI3519_FIXED_1188M, "1188m", NULL, CLK_IS_ROOT, 1188000000, },
++	{ HI3519_FIXED_594M, "594m", NULL, CLK_IS_ROOT, 594000000, },
++	{ HI3519_FIXED_297M, "297m", NULL, CLK_IS_ROOT, 297000000, },
++	{ HI3519_FIXED_148P5M, "148p5m", NULL, CLK_IS_ROOT, 148500000, },
++	{ HI3519_FIXED_74P25M, "74p25m", NULL, CLK_IS_ROOT, 74250000, },
++	{ HI3519_FIXED_792M, "792m", NULL, CLK_IS_ROOT, 792000000, },
++	{ HI3519_FIXED_475M, "475m", NULL, CLK_IS_ROOT, 475000000, },
++	{ HI3519_FIXED_340M, "340m", NULL, CLK_IS_ROOT, 340000000, },
++	{ HI3519_FIXED_72M, "72m", NULL, CLK_IS_ROOT, 72000000, },
++	{ HI3519_FIXED_400M, "400m", NULL, CLK_IS_ROOT, 400000000, },
++	{ HI3519_FIXED_200M, "200m", NULL, CLK_IS_ROOT, 200000000, },
++	{ HI3519_FIXED_54M, "54m", NULL, CLK_IS_ROOT, 54000000, },
++	{ HI3519_FIXED_27M, "27m", NULL, CLK_IS_ROOT, 1188000000, },
++	{ HI3519_FIXED_37P125M, "37p125m", NULL, CLK_IS_ROOT, 37125000, },
++	{ HI3519_FIXED_3000M, "3000m", NULL, CLK_IS_ROOT, 3000000000UL, },
++	{ HI3519_FIXED_1500M, "1500m", NULL, CLK_IS_ROOT, 1500000000, },
++	{ HI3519_FIXED_500M, "500m", NULL, CLK_IS_ROOT, 500000000, },
++	{ HI3519_FIXED_250M, "250m", NULL, CLK_IS_ROOT, 250000000, },
++	{ HI3519_FIXED_125M, "125m", NULL, CLK_IS_ROOT, 125000000, },
++	{ HI3519_FIXED_1000M, "1000m", NULL, CLK_IS_ROOT, 1000000000, },
++	{ HI3519_FIXED_600M, "600m", NULL, CLK_IS_ROOT, 600000000, },
++	{ HI3519_FIXED_750M, "750m", NULL, CLK_IS_ROOT, 750000000, },
++	{ HI3519_FIXED_150M, "150m", NULL, CLK_IS_ROOT, 150000000, },
++	{ HI3519_FIXED_75M, "75m", NULL, CLK_IS_ROOT, 75000000, },
++	{ HI3519_FIXED_300M, "300m", NULL, CLK_IS_ROOT, 300000000, },
++	{ HI3519_FIXED_60M, "60m", NULL, CLK_IS_ROOT, 60000000, },
++	{ HI3519_FIXED_214M, "214m", NULL, CLK_IS_ROOT, 214000000, },
++	{ HI3519_FIXED_107M, "107m", NULL, CLK_IS_ROOT, 107000000, },
++	{ HI3519_FIXED_100M, "100m", NULL, CLK_IS_ROOT, 100000000, },
++	{ HI3519_FIXED_50M, "50m", NULL, CLK_IS_ROOT, 50000000, },
++	{ HI3519_FIXED_25M, "25m", NULL, CLK_IS_ROOT, 25000000, },
++	{ HI3519_FIXED_24M, "24m", NULL, CLK_IS_ROOT, 24000000, },
++	{ HI3519_FIXED_3M, "3m", NULL, CLK_IS_ROOT, 3000000, },
++};
++
++static const char *sysaxi_mux_p[] __initconst = {"24m", "200m", };
++static u32 sysaxi_mux_table[] = {0, 1};
++
++static const char *fmc_mux_p[] __initconst = {
++	"24m", "75m", "125m", "150m", "200m", "250m", "300m", "400m", };
++static u32 fmc_mux_table[] = {0, 1, 2, 3, 4, 5, 6, 7};
++
++static const char *mmc_mux_p[] __initconst = {
++	"100m", "200m", "300m", "400m", "594m", "792m", };
++static u32 mmc_mux_table[] = {0, 1, 2, 3, 4, 5};
++
++static const char *a17_mux_p[] __initconst = {
++	"400m", "500m", "594m", "792m", "1000m", "apll"};
++static u32 a17_mux_table[] = {7, 6, 5, 4, 3, 1};
++
++static const char *i2c_mux_p[] __initconst = {"clk_sysapb", "50m"};
++static u32 i2c_mux_table[] = {0, 1};
++
++static struct hisi_mux_clock hi3519_mux_clks[] __initdata = {
++	{ HI3519_SYSAXI_MUX, "sysaxi_mux", sysaxi_mux_p,
++		ARRAY_SIZE(sysaxi_mux_p),
++		CLK_SET_RATE_PARENT, 0x34, 12, 2, 0, sysaxi_mux_table, },
++	{ HI3519_FMC_MUX, "fmc_mux", fmc_mux_p, ARRAY_SIZE(fmc_mux_p),
++		CLK_SET_RATE_PARENT, 0xc0, 2, 3, 0, fmc_mux_table, },
++	{ HI3519_MMC0_MUX, "mmc0_mux", mmc_mux_p, ARRAY_SIZE(mmc_mux_p),
++		CLK_SET_RATE_PARENT, 0xc4, 10, 3, 0, mmc_mux_table, },
++	{ HI3519_MMC1_MUX, "mmc1_mux", mmc_mux_p, ARRAY_SIZE(mmc_mux_p),
++		CLK_SET_RATE_PARENT, 0xc4, 2, 3, 0, mmc_mux_table, },
++	{ HI3519_MMC2_MUX, "mmc2_mux", mmc_mux_p, ARRAY_SIZE(mmc_mux_p),
++		CLK_SET_RATE_PARENT, 0xc4, 18, 3, 0, mmc_mux_table, },
++	{ HI3519_A17_MUX, "a17_mux", a17_mux_p, ARRAY_SIZE(a17_mux_p),
++		CLK_SET_RATE_PARENT, 0x34, 4, 3, 0, a17_mux_table, },
++	{ HI3519_I2C_MUX, "i2c_mux", i2c_mux_p, ARRAY_SIZE(i2c_mux_p),
++		CLK_SET_RATE_PARENT, 0xe4, 26, 1, 0, i2c_mux_table, },
++};
++
++static struct hisi_fixed_factor_clock hi3519_fixed_factor_clks[] __initdata = {
++	{ HI3519_SYSAPB_CLK, "clk_sysapb", "sysaxi_mux", 1, 4,
++		CLK_SET_RATE_PARENT},
++	{ HI3519_MMC0_FAC_CLK, "mmc0_fac", "mmc0_mux", 1, 8,
++		CLK_SET_RATE_PARENT},
++	{ HI3519_MMC1_FAC_CLK, "mmc1_fac", "mmc1_mux", 1, 8,
++		CLK_SET_RATE_PARENT},
++	{ HI3519_MMC2_FAC_CLK, "mmc2_fac", "mmc2_mux", 1, 8,
++		CLK_SET_RATE_PARENT},
++};
++
++static struct hisi_gate_clock hi3519_gate_clks[] __initdata = {
++#ifdef CONFIG_HIFMC
++	/* fmc */
++	{ HI3519_FMC_CLK, "clk_fmc", "fmc_mux",
++		CLK_SET_RATE_PARENT, 0xc0, 1, 0, },
++#endif
++	/* mmc */
++	{ HI3519_MMC0_CLK, "clk_mmc0", "mmc0_fac",
++		CLK_SET_RATE_PARENT, 0xc4, 9, 0, },
++	{ HI3519_MMC1_CLK, "clk_mmc1", "mmc1_fac",
++		CLK_SET_RATE_PARENT, 0xc4, 1, 0, },
++	{ HI3519_MMC2_CLK, "clk_mmc2", "mmc2_fac",
++		CLK_SET_RATE_PARENT, 0xc4, 17, 0, },
++
++	/* usb ctrl */
++	{ HI3519_USB2_CTRL_UTMI0_REQ, "usb2_cttl_utmi0_req", NULL,
++		CLK_SET_RATE_PARENT, 0xb4, 5, 1, },
++	{ HI3519_USB2_HRST_REQ, "usb2_hrst_req", NULL,
++		CLK_SET_RATE_PARENT, 0xb4, 0, 1, },
++	{ HI3519_USB3_CLK, "usb3_vcc_srst_req2", NULL,
++		CLK_SET_RATE_PARENT, 0xb8, 0, 1, },
++	/* uart */
++	{ HI3519_UART0_CLK, "clk_uart0", "24m",
++		CLK_SET_RATE_PARENT, 0xe4, 20, 0, },
++	{ HI3519_UART1_CLK, "clk_uart1", "24m",
++		CLK_SET_RATE_PARENT, 0xe4, 21, 0, },
++	{ HI3519_UART2_CLK, "clk_uart2", "24m",
++		CLK_SET_RATE_PARENT, 0xe4, 22, 0, },
++	{ HI3519_UART3_CLK, "clk_uart3", "24m",
++		CLK_SET_RATE_PARENT, 0xe4, 23, 0, },
++	{ HI3519_UART4_CLK, "clk_uart4", "24m",
++		CLK_SET_RATE_PARENT, 0xe4, 24, 0, },
++	/* ethernet mac */
++	{ HI3519_ETH_CLK, "clk_eth", NULL,
++		CLK_IS_ROOT, 0xcc, 1, 0, },
++	{ HI3519_ETH_MACIF_CLK, "clk_eth_macif", NULL,
++		CLK_IS_ROOT, 0xcc, 3, 0, },
++	/* spi */
++	{ HI3519_SPI0_CLK, "clk_spi0", "clk_sysapb",
++		CLK_SET_RATE_PARENT, 0xe4, 16, 0, },
++	{ HI3519_SPI1_CLK, "clk_spi1", "clk_sysapb",
++		CLK_SET_RATE_PARENT, 0xe4, 17, 0, },
++	{ HI3519_SPI2_CLK, "clk_spi2", "clk_sysapb",
++		CLK_SET_RATE_PARENT, 0xe4, 18, 0, },
++};
++
++static struct hi3519_pll_clock hi3519_pll_clks[] __initdata = {
++	{ HI3519_APLL_CLK, "apll", NULL, 0x0, 0, 24, 24, 3, 28, 3,
++		0x4, 0, 12, 12, 6},
++};
++
++
++#define to_pll_clk(_hw) container_of(_hw, struct hi3519_clk_pll, hw)
++
++static void hi3519_calc_pll(u32 *frac_val, u32 *postdiv1_val, u32 *postdiv2_val,
++		u32 *fbdiv_val, u32 *refdiv_val, unsigned long rate)
++{
++	u64 rem;
++	*frac_val = 0;
++	rem = do_div(rate, 1000000);
++	*fbdiv_val = rate;
++	*refdiv_val = 24;
++	rem = rem * (1 << 24);
++	do_div(rem, 1000000);
++	*frac_val = rem;
++}
++
++static int clk_pll_set_rate(struct clk_hw *hw,
++			unsigned long rate,
++			unsigned long parent_rate)
++{
++	struct hi3519_clk_pll *clk = to_pll_clk(hw);
++	u32 frac_val, postdiv1_val, postdiv2_val, fbdiv_val, refdiv_val;
++	u32 val;
++
++	/*Fixme  ignore postdives now because apll don't use them*/
++	postdiv1_val = postdiv2_val = 0;
++
++	hi3519_calc_pll(&frac_val, &postdiv1_val, &postdiv2_val,
++			&fbdiv_val, &refdiv_val, rate);
++
++	val = readl_relaxed(clk->ctrl_reg1);
++	val &= ~(((1 << clk->frac_width) - 1) << clk->frac_shift);
++	val &= ~(((1 << clk->postdiv1_width) - 1) << clk->postdiv1_shift);
++	val &= ~(((1 << clk->postdiv2_width) - 1) << clk->postdiv2_shift);
++
++	val |= frac_val << clk->frac_shift;
++	val |= postdiv1_val << clk->postdiv1_shift;
++	val |= postdiv2_val << clk->postdiv2_shift;
++	writel_relaxed(val, clk->ctrl_reg1);
++
++	val = readl_relaxed(clk->ctrl_reg2);
++	val &= ~(((1 << clk->fbdiv_width) - 1) << clk->fbdiv_shift);
++	val &= ~(((1 << clk->refdiv_width) - 1) << clk->refdiv_shift);
++
++	val |= fbdiv_val << clk->fbdiv_shift;
++	val |= refdiv_val << clk->refdiv_shift;
++	writel_relaxed(val, clk->ctrl_reg2);
++
++	return 0;
++}
++
++static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
++		unsigned long parent_rate)
++{
++	struct hi3519_clk_pll *clk = to_pll_clk(hw);
++	u64 frac_val, fbdiv_val, refdiv_val;
++	u32 val;
++	u64 tmp, rate;
++
++	val = readl_relaxed(clk->ctrl_reg1);
++	val = val >> clk->frac_shift;
++	val &= ((1 << clk->frac_width) - 1);
++	frac_val = val;
++
++	val = readl_relaxed(clk->ctrl_reg2);
++	val = val >> clk->fbdiv_shift;
++	val &= ((1 << clk->fbdiv_width) - 1);
++	fbdiv_val = val;
++
++	val = readl_relaxed(clk->ctrl_reg2);
++	val = val >> clk->refdiv_shift;
++	val &= ((1 << clk->refdiv_width) - 1) ;
++	refdiv_val = val;
++
++	/* rate = 24000000 * (fbdiv + frac / (1<<24) ) / refdiv  */
++	rate = 0;
++	tmp = 24000000 * fbdiv_val;
++	rate += tmp;
++#if 0
++	tmp = 24000000 * frac_val;
++	do_div(tmp, (1<<24));
++	rate += tmp;
++#endif
++	do_div(rate, refdiv_val);
++
++	return rate;
++}
++
++
++static long clk_pll_determine_rate(struct clk_hw *hw, unsigned long rate,
++		unsigned long *best_parent_rate,
++		struct clk **best_parent_p)
++{
++	return rate;
++}
++
++static struct clk_ops clk_pll_ops = {
++	.set_rate = clk_pll_set_rate,
++	.determine_rate = clk_pll_determine_rate,
++	.recalc_rate = clk_pll_recalc_rate,
++};
++
++void __init hi3519_clk_register_pll(struct hi3519_pll_clock *clks,
++		int nums, struct hisi_clock_data *data)
++{
++	void __iomem *base = data->base;
++	int i;
++
++	for (i = 0; i < nums; i++) {
++		struct hi3519_clk_pll *p_clk;
++		struct clk *clk;
++		struct clk_init_data init;
++
++		p_clk = kzalloc(sizeof(*p_clk), GFP_KERNEL);
++		if (!p_clk)
++			return;
++
++		init.name = clks[i].name;
++		init.flags = CLK_IS_BASIC;
++		init.parent_names =
++			(clks[i].parent_name ? &clks[i].parent_name : NULL);
++		init.num_parents = (clks[i].parent_name ? 1 : 0);
++		init.ops = &clk_pll_ops;
++
++		p_clk->ctrl_reg1 = base + clks[i].ctrl_reg1;
++		p_clk->frac_shift = clks[i].frac_shift;
++		p_clk->frac_width = clks[i].frac_width;
++		p_clk->postdiv1_shift = clks[i].postdiv1_shift;
++		p_clk->postdiv1_width = clks[i].postdiv1_width;
++		p_clk->postdiv2_shift = clks[i].postdiv2_shift;
++		p_clk->postdiv2_width = clks[i].postdiv2_width;
++
++		p_clk->ctrl_reg2 = base + clks[i].ctrl_reg2;
++		p_clk->fbdiv_shift = clks[i].fbdiv_shift;
++		p_clk->fbdiv_width = clks[i].fbdiv_width;
++		p_clk->refdiv_shift = clks[i].refdiv_shift;
++		p_clk->refdiv_width = clks[i].refdiv_width;
++		p_clk->hw.init = &init;
++
++		clk = clk_register(NULL, &p_clk->hw);
++		if (IS_ERR(clk)) {
++			kfree(p_clk);
++			pr_err("%s: failed to register clock %s\n",
++					__func__, clks[i].name);
++			continue;
++		}
++
++		data->clk_data.clks[clks[i].id] = clk;
++	}
++
++
++}
++
++static void __init hi3519_clk_init(struct device_node *np)
++{
++	struct hisi_clock_data *clk_data;
++
++	clk_data = hisi_clk_init(np, HI3519_NR_CLKS);
++	if (!clk_data)
++		return;
++	if (IS_ENABLED(CONFIG_RESET_CONTROLLER))
++		hisi_reset_init(np, HI3519_NR_RSTS);
++
++	hisi_clk_register_fixed_rate(hi3519_fixed_rate_clks,
++			ARRAY_SIZE(hi3519_fixed_rate_clks),
++			clk_data);
++	hi3519_clk_register_pll(hi3519_pll_clks,
++			ARRAY_SIZE(hi3519_pll_clks), clk_data);
++
++	hisi_clk_register_mux(hi3519_mux_clks, ARRAY_SIZE(hi3519_mux_clks),
++			clk_data);
++	hisi_clk_register_fixed_factor(hi3519_fixed_factor_clks,
++			ARRAY_SIZE(hi3519_fixed_factor_clks), clk_data);
++	hisi_clk_register_gate(hi3519_gate_clks,
++			ARRAY_SIZE(hi3519_gate_clks), clk_data);
++}
++
++CLK_OF_DECLARE(hi3519_clk, "hisilicon,hi3519-clock", hi3519_clk_init);
+diff --git a/drivers/clk/hisilicon/clk-hi3519v101.c b/drivers/clk/hisilicon/clk-hi3519v101.c
+new file mode 100644
+index 0000000..1f30e6c
+--- /dev/null
++++ b/drivers/clk/hisilicon/clk-hi3519v101.c
+@@ -0,0 +1,385 @@
++/*
++ * Copyright (c) 2015 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <linux/of_address.h>
++#include <dt-bindings/clock/hi3519-clock.h>
++#include <linux/slab.h>
++#include <linux/delay.h>
++#include <mach/io.h>
++
++#include "clk.h"
++#include "reset.h"
++
++/******************************************************************************/
++struct hi3519v101_pll_clock {
++	u32		id;
++	const char	*name;
++	const char	*parent_name;
++	u32		ctrl_reg1;
++	u8		frac_shift;
++	u8		frac_width;
++	u8		postdiv1_shift;
++	u8		postdiv1_width;
++	u8		postdiv2_shift;
++	u8		postdiv2_width;
++	u32		ctrl_reg2;
++	u8		fbdiv_shift;
++	u8		fbdiv_width;
++	u8		refdiv_shift;
++	u8		refdiv_width;
++};
++
++struct hi3519v101_clk_pll {
++	struct clk_hw	hw;
++	u32		id;
++	void __iomem	*ctrl_reg1;
++	u8		frac_shift;
++	u8		frac_width;
++	u8		postdiv1_shift;
++	u8		postdiv1_width;
++	u8		postdiv2_shift;
++	u8		postdiv2_width;
++	void __iomem	*ctrl_reg2;
++	u8		fbdiv_shift;
++	u8		fbdiv_width;
++	u8		refdiv_shift;
++	u8		refdiv_width;
++};
++
++static struct hisi_fixed_rate_clock hi3519v101_fixed_rate_clks[] __initdata = {
++	{ HI3519_FIXED_2376M, "2376m", NULL, CLK_IS_ROOT, 2376000000UL, },
++	{ HI3519_FIXED_1188M, "1188m", NULL, CLK_IS_ROOT, 1188000000, },
++	{ HI3519_FIXED_594M, "594m", NULL, CLK_IS_ROOT, 594000000, },
++	{ HI3519_FIXED_297M, "297m", NULL, CLK_IS_ROOT, 297000000, },
++	{ HI3519_FIXED_148P5M, "148p5m", NULL, CLK_IS_ROOT, 148500000, },
++	{ HI3519_FIXED_74P25M, "74p25m", NULL, CLK_IS_ROOT, 74250000, },
++	{ HI3519_FIXED_792M, "792m", NULL, CLK_IS_ROOT, 792000000, },
++	{ HI3519_FIXED_475M, "475m", NULL, CLK_IS_ROOT, 475000000, },
++	{ HI3519_FIXED_340M, "340m", NULL, CLK_IS_ROOT, 340000000, },
++	{ HI3519_FIXED_72M, "72m", NULL, CLK_IS_ROOT, 72000000, },
++	{ HI3519_FIXED_400M, "400m", NULL, CLK_IS_ROOT, 400000000, },
++	{ HI3519_FIXED_200M, "200m", NULL, CLK_IS_ROOT, 200000000, },
++	{ HI3519_FIXED_54M, "54m", NULL, CLK_IS_ROOT, 54000000, },
++	{ HI3519_FIXED_27M, "27m", NULL, CLK_IS_ROOT, 1188000000, },
++	{ HI3519_FIXED_37P125M, "37p125m", NULL, CLK_IS_ROOT, 37125000, },
++	{ HI3519_FIXED_3000M, "3000m", NULL, CLK_IS_ROOT, 3000000000UL, },
++	{ HI3519_FIXED_1500M, "1500m", NULL, CLK_IS_ROOT, 1500000000, },
++	{ HI3519_FIXED_500M, "500m", NULL, CLK_IS_ROOT, 500000000, },
++	{ HI3519_FIXED_250M, "250m", NULL, CLK_IS_ROOT, 250000000, },
++	{ HI3519_FIXED_125M, "125m", NULL, CLK_IS_ROOT, 125000000, },
++	{ HI3519_FIXED_1000M, "1000m", NULL, CLK_IS_ROOT, 1000000000, },
++	{ HI3519_FIXED_600M, "600m", NULL, CLK_IS_ROOT, 600000000, },
++	{ HI3519_FIXED_750M, "750m", NULL, CLK_IS_ROOT, 750000000, },
++	{ HI3519_FIXED_150M, "150m", NULL, CLK_IS_ROOT, 150000000, },
++	{ HI3519_FIXED_75M, "75m", NULL, CLK_IS_ROOT, 75000000, },
++	{ HI3519_FIXED_300M, "300m", NULL, CLK_IS_ROOT, 300000000, },
++	{ HI3519_FIXED_60M, "60m", NULL, CLK_IS_ROOT, 60000000, },
++	{ HI3519_FIXED_214M, "214m", NULL, CLK_IS_ROOT, 214000000, },
++	{ HI3519_FIXED_107M, "107m", NULL, CLK_IS_ROOT, 107000000, },
++	{ HI3519_FIXED_100M, "100m", NULL, CLK_IS_ROOT, 100000000, },
++	{ HI3519_FIXED_50M, "50m", NULL, CLK_IS_ROOT, 50000000, },
++	{ HI3519_FIXED_25M, "25m", NULL, CLK_IS_ROOT, 25000000, },
++	{ HI3519_FIXED_24M, "24m", NULL, CLK_IS_ROOT, 24000000, },
++	{ HI3519_FIXED_3M, "3m", NULL, CLK_IS_ROOT, 3000000, },
++	{ HI3519_FIXED_198M, "198m", NULL, CLK_IS_ROOT, 198000000, },
++	{ HI3519_FIXED_396M, "396m", NULL, CLK_IS_ROOT, 396000000, },
++};
++
++static const char *sysaxi_mux_p[] __initconst = {"24m", "198m", };
++static u32 sysaxi_mux_table[] = {0, 1};
++
++static const char *fmc_mux_p[] __initconst = {
++	"24m", "75m", "125m", "150m", "198m", "250m", "300m", "396m", };
++static u32 fmc_mux_table[] = {0, 1, 2, 3, 4, 5, 6, 7};
++
++static const char *mmc_mux_p[] __initconst = {
++	"100m", "198m", "396m", "594m", "792m", "1188m", };
++static u32 mmc_mux_table[] = {0, 1, 3, 4, 5, 7};
++
++static const char *a17_mux_p[] __initconst = {
++	"24m", "apll", "594m", "792m", };
++static u32 a17_mux_table[] = {0, 1, 3, 4};
++
++static const char *i2c_mux_p[] __initconst = {"clk_sysapb", "50m"};
++static u32 i2c_mux_table[] = {0, 1};
++
++static struct hisi_mux_clock hi3519v101_mux_clks[] __initdata = {
++	{ HI3519_SYSAXI_MUX, "sysaxi_mux", sysaxi_mux_p,
++		ARRAY_SIZE(sysaxi_mux_p),
++		CLK_SET_RATE_PARENT, 0x34, 12, 2, 0, sysaxi_mux_table, },
++	{ HI3519_FMC_MUX, "fmc_mux", fmc_mux_p, ARRAY_SIZE(fmc_mux_p),
++		CLK_SET_RATE_PARENT, 0xc0, 2, 3, 0, fmc_mux_table, },
++	{ HI3519_MMC0_MUX, "mmc0_mux", mmc_mux_p, ARRAY_SIZE(mmc_mux_p),
++		CLK_SET_RATE_PARENT, 0xc4, 10, 3, 0, mmc_mux_table, },
++	{ HI3519_MMC1_MUX, "mmc1_mux", mmc_mux_p, ARRAY_SIZE(mmc_mux_p),
++		CLK_SET_RATE_PARENT, 0xc4, 2, 3, 0, mmc_mux_table, },
++	{ HI3519_MMC2_MUX, "mmc2_mux", mmc_mux_p, ARRAY_SIZE(mmc_mux_p),
++		CLK_SET_RATE_PARENT, 0xc4, 18, 3, 0, mmc_mux_table, },
++	{ HI3519_A17_MUX, "a17_mux", a17_mux_p, ARRAY_SIZE(a17_mux_p),
++		CLK_SET_RATE_PARENT, 0x34, 4, 3, 0, a17_mux_table, },
++	{ HI3519_I2C_MUX, "i2c_mux", i2c_mux_p, ARRAY_SIZE(i2c_mux_p),
++		CLK_SET_RATE_PARENT, 0xe4, 26, 1, 0, i2c_mux_table, },
++
++};
++
++static struct hisi_fixed_factor_clock
++	hi3519v101_fixed_factor_clks[] __initdata = {
++	{ HI3519_SYSAPB_CLK, "clk_sysapb", "sysaxi_mux", 1, 4,
++		CLK_SET_RATE_PARENT},
++	{ HI3519_MMC0_FAC_CLK, "mmc0_fac", "mmc0_mux", 1, 8,
++		CLK_SET_RATE_PARENT},
++	{ HI3519_MMC1_FAC_CLK, "mmc1_fac", "mmc1_mux", 1, 8,
++		CLK_SET_RATE_PARENT},
++	{ HI3519_MMC2_FAC_CLK, "mmc2_fac", "mmc2_mux", 1, 8,
++		CLK_SET_RATE_PARENT},
++};
++
++static struct hisi_gate_clock hi3519v101_gate_clks[] __initdata = {
++#ifdef CONFIG_HIFMC
++	/* fmc */
++	{ HI3519_FMC_CLK, "clk_fmc", "fmc_mux",
++		CLK_SET_RATE_PARENT, 0xc0, 1, 0, },
++#endif
++	/* mmc */
++	{ HI3519_MMC0_CLK, "clk_mmc0", "mmc0_fac",
++		CLK_SET_RATE_PARENT, 0xc4, 9, 0, },
++	{ HI3519_MMC1_CLK, "clk_mmc1", "mmc1_fac",
++		CLK_SET_RATE_PARENT, 0xc4, 1, 0, },
++	{ HI3519_MMC2_CLK, "clk_mmc2", "mmc2_fac",
++		CLK_SET_RATE_PARENT, 0xc4, 17, 0, },
++
++	/* usb ctrl */
++	{ HI3519_USB2_CTRL_UTMI0_REQ, "usb2_cttl_utmi0_req", NULL,
++		CLK_SET_RATE_PARENT, 0xb4, 5, 1, },
++	{ HI3519_USB2_HRST_REQ, "usb2_hrst_req", NULL,
++		CLK_SET_RATE_PARENT, 0xb4, 0, 1, },
++	{ HI3519_USB3_CLK, "usb3_vcc_srst_req2", NULL,
++		CLK_SET_RATE_PARENT, 0xb8, 0, 1, },
++
++	/* uart */
++	{ HI3519_UART0_CLK, "clk_uart0", "24m",
++		CLK_SET_RATE_PARENT, 0xe4, 20, 0, },
++	{ HI3519_UART1_CLK, "clk_uart1", "24m",
++		CLK_SET_RATE_PARENT, 0xe4, 21, 0, },
++	{ HI3519_UART2_CLK, "clk_uart2", "24m",
++		CLK_SET_RATE_PARENT, 0xe4, 22, 0, },
++	{ HI3519_UART3_CLK, "clk_uart3", "24m",
++		CLK_SET_RATE_PARENT, 0xe4, 23, 0, },
++	{ HI3519_UART4_CLK, "clk_uart4", "24m",
++		CLK_SET_RATE_PARENT, 0xe4, 24, 0, },
++
++	/* ethernet mac */
++	{ HI3519_ETH_CLK, "clk_eth", NULL,
++		CLK_IS_ROOT, 0xcc, 1, 0, },
++	{ HI3519_ETH_MACIF_CLK, "clk_eth_macif", NULL,
++		CLK_IS_ROOT, 0xcc, 3, 0, },
++
++	/* spi */
++	{ HI3519_SPI0_CLK, "clk_spi0", "clk_sysapb",
++		CLK_SET_RATE_PARENT, 0xe4, 16, 0, },
++	{ HI3519_SPI1_CLK, "clk_spi1", "clk_sysapb",
++		CLK_SET_RATE_PARENT, 0xe4, 17, 0, },
++	{ HI3519_SPI2_CLK, "clk_spi2", "clk_sysapb",
++		CLK_SET_RATE_PARENT, 0xe4, 18, 0, },
++	{ HI3519_SPI3_CLK, "clk_spi3", "clk_sysapb",
++		CLK_SET_RATE_PARENT, 0xe4, 28, 0, },
++};
++
++static struct hi3519v101_pll_clock hi3519v101_pll_clks[] __initdata = {
++	{ HI3519_APLL_CLK, "apll", NULL, 0x0, 0, 24, 24, 3, 28, 3,
++		0x4, 0, 12, 12, 6},
++};
++
++
++#define to_pll_clk(_hw) container_of(_hw, struct hi3519v101_clk_pll, hw)
++
++static void hi3519v101_calc_pll(u32 *frac_val,
++		u32 *postdiv1_val,
++		u32 *postdiv2_val,
++		u32 *fbdiv_val,
++		u32 *refdiv_val,
++		unsigned long rate)
++{
++	u64 rem;
++	*frac_val = 0;
++	rem = do_div(rate, 1000000);
++	*fbdiv_val = rate;
++	*refdiv_val = 24;
++	rem = rem * (1 << 24);
++	do_div(rem, 1000000);
++	*frac_val = rem;
++}
++
++static int clk_pll_set_rate(struct clk_hw *hw,
++			unsigned long rate,
++			unsigned long parent_rate)
++{
++	struct hi3519v101_clk_pll *clk = to_pll_clk(hw);
++	u32 frac_val, postdiv1_val, postdiv2_val, fbdiv_val, refdiv_val;
++	u32 val;
++
++	/*Fixme  ignore postdives now because apll don't use them*/
++	postdiv1_val = postdiv2_val = 0;
++
++	hi3519v101_calc_pll(&frac_val, &postdiv1_val, &postdiv2_val,
++			&fbdiv_val, &refdiv_val, rate);
++
++	val = readl_relaxed(clk->ctrl_reg1);
++	val &= ~(((1 << clk->frac_width) - 1) << clk->frac_shift);
++	val &= ~(((1 << clk->postdiv1_width) - 1) << clk->postdiv1_shift);
++	val &= ~(((1 << clk->postdiv2_width) - 1) << clk->postdiv2_shift);
++
++	val |= frac_val << clk->frac_shift;
++	val |= postdiv1_val << clk->postdiv1_shift;
++	val |= postdiv2_val << clk->postdiv2_shift;
++	writel_relaxed(val, clk->ctrl_reg1);
++
++	val = readl_relaxed(clk->ctrl_reg2);
++	val &= ~(((1 << clk->fbdiv_width) - 1) << clk->fbdiv_shift);
++	val &= ~(((1 << clk->refdiv_width) - 1) << clk->refdiv_shift);
++
++	val |= fbdiv_val << clk->fbdiv_shift;
++	val |= refdiv_val << clk->refdiv_shift;
++	writel_relaxed(val, clk->ctrl_reg2);
++
++	return 0;
++}
++
++static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
++		unsigned long parent_rate)
++{
++	struct hi3519v101_clk_pll *clk = to_pll_clk(hw);
++	u64 frac_val, fbdiv_val, refdiv_val;
++	u32 val;
++	u64 tmp, rate;
++
++	val = readl_relaxed(clk->ctrl_reg1);
++	val = val >> clk->frac_shift;
++	val &= ((1 << clk->frac_width) - 1);
++	frac_val = val;
++
++	val = readl_relaxed(clk->ctrl_reg2);
++	val = val >> clk->fbdiv_shift;
++	val &= ((1 << clk->fbdiv_width) - 1);
++	fbdiv_val = val;
++
++	val = readl_relaxed(clk->ctrl_reg2);
++	val = val >> clk->refdiv_shift;
++	val &= ((1 << clk->refdiv_width) - 1);
++	refdiv_val = val;
++
++	/* rate = 24000000 * (fbdiv + frac / (1<<24) ) / refdiv  */
++	rate = 0;
++	tmp = 24000000 * fbdiv_val;
++	rate += tmp;
++	do_div(rate, refdiv_val);
++
++	return rate;
++}
++
++
++static long clk_pll_determine_rate(struct clk_hw *hw, unsigned long rate,
++		unsigned long *best_parent_rate,
++		struct clk **best_parent_p)
++{
++	return rate;
++}
++
++static struct clk_ops clk_pll_ops = {
++	.set_rate = clk_pll_set_rate,
++	.determine_rate = clk_pll_determine_rate,
++	.recalc_rate = clk_pll_recalc_rate,
++};
++
++void __init hi3519v101_clk_register_pll(struct hi3519v101_pll_clock *clks,
++		int nums, struct hisi_clock_data *data)
++{
++	void __iomem *base = data->base;
++	int i;
++
++	for (i = 0; i < nums; i++) {
++		struct hi3519v101_clk_pll *p_clk;
++		struct clk *clk;
++		struct clk_init_data init;
++
++		p_clk = kzalloc(sizeof(*p_clk), GFP_KERNEL);
++		if (!p_clk)
++			return;
++
++		init.name = clks[i].name;
++		init.flags = CLK_IS_BASIC;
++		init.parent_names =
++			(clks[i].parent_name ? &clks[i].parent_name : NULL);
++		init.num_parents = (clks[i].parent_name ? 1 : 0);
++		init.ops = &clk_pll_ops;
++
++		p_clk->ctrl_reg1 = base + clks[i].ctrl_reg1;
++		p_clk->frac_shift = clks[i].frac_shift;
++		p_clk->frac_width = clks[i].frac_width;
++		p_clk->postdiv1_shift = clks[i].postdiv1_shift;
++		p_clk->postdiv1_width = clks[i].postdiv1_width;
++		p_clk->postdiv2_shift = clks[i].postdiv2_shift;
++		p_clk->postdiv2_width = clks[i].postdiv2_width;
++
++		p_clk->ctrl_reg2 = base + clks[i].ctrl_reg2;
++		p_clk->fbdiv_shift = clks[i].fbdiv_shift;
++		p_clk->fbdiv_width = clks[i].fbdiv_width;
++		p_clk->refdiv_shift = clks[i].refdiv_shift;
++		p_clk->refdiv_width = clks[i].refdiv_width;
++		p_clk->hw.init = &init;
++
++		clk = clk_register(NULL, &p_clk->hw);
++		if (IS_ERR(clk)) {
++			kfree(p_clk);
++			pr_err("%s: failed to register clock %s\n",
++					__func__, clks[i].name);
++			continue;
++		}
++
++		data->clk_data.clks[clks[i].id] = clk;
++	}
++
++
++}
++
++static void __init hi3519v101_clk_init(struct device_node *np)
++{
++	struct hisi_clock_data *clk_data;
++
++	clk_data = hisi_clk_init(np, HI3519_NR_CLKS);
++	if (!clk_data)
++		return;
++	if (IS_ENABLED(CONFIG_RESET_CONTROLLER))
++		hisi_reset_init(np, HI3519_NR_RSTS);
++
++	hisi_clk_register_fixed_rate(hi3519v101_fixed_rate_clks,
++			ARRAY_SIZE(hi3519v101_fixed_rate_clks),
++			clk_data);
++	hi3519v101_clk_register_pll(hi3519v101_pll_clks,
++			ARRAY_SIZE(hi3519v101_pll_clks), clk_data);
++
++	hisi_clk_register_mux(hi3519v101_mux_clks,
++			ARRAY_SIZE(hi3519v101_mux_clks),
++			clk_data);
++	hisi_clk_register_fixed_factor(hi3519v101_fixed_factor_clks,
++			ARRAY_SIZE(hi3519v101_fixed_factor_clks), clk_data);
++	hisi_clk_register_gate(hi3519v101_gate_clks,
++			ARRAY_SIZE(hi3519v101_gate_clks), clk_data);
++}
++
++CLK_OF_DECLARE(hi3519v101_clk, "hisilicon,hi3519v101-clock",
++		hi3519v101_clk_init);
+diff --git a/drivers/clk/hisilicon/clk-hi3521d.c b/drivers/clk/hisilicon/clk-hi3521d.c
+new file mode 100644
+index 0000000..a74cc92
+--- /dev/null
++++ b/drivers/clk/hisilicon/clk-hi3521d.c
+@@ -0,0 +1,179 @@
++/*
++ * Hi3521D Clock Driver
++ *
++ * Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include <dt-bindings/clock/hi3521d-clock.h>
++#include "clk.h"
++#include "reset.h"
++
++static struct
++hisi_fixed_rate_clock hi3521d_fixed_rate_clks_crg[] __initdata = {
++	{ HI3521D_FIXED_3M,		"3m",	NULL, CLK_IS_ROOT, 3000000, },
++	{ HI3521D_FIXED_6M,		"6m",	NULL, CLK_IS_ROOT, 6000000, },
++	{ HI3521D_FIXED_12M,	"12m",	NULL, CLK_IS_ROOT, 12000000, },
++	{ HI3521D_FIXED_24M,	"24m",	NULL, CLK_IS_ROOT, 24000000, },
++	{ HI3521D_FIXED_83P3M,	"83.3m", NULL, CLK_IS_ROOT, 83300000, },
++	{ HI3521D_FIXED_100M,	"100m", NULL, CLK_IS_ROOT, 100000000, },
++	{ HI3521D_FIXED_125M,	"125m", NULL, CLK_IS_ROOT, 125000000, },
++	{ HI3521D_FIXED_150M,	"150m", NULL, CLK_IS_ROOT, 150000000, },
++	{ HI3521D_FIXED_200M,	"200m", NULL, CLK_IS_ROOT, 200000000, },
++	{ HI3521D_FIXED_250M,	"250m", NULL, CLK_IS_ROOT, 250000000, },
++	{ HI3521D_FIXED_300M,	"300m", NULL, CLK_IS_ROOT, 300000000, },
++	{ HI3521D_FIXED_324M,	"324m", NULL, CLK_IS_ROOT, 324000000, },
++	{ HI3521D_FIXED_342M,	"342m", NULL, CLK_IS_ROOT, 342000000, },
++	{ HI3521D_FIXED_342M,	"375m", NULL, CLK_IS_ROOT, 375000000, },
++	{ HI3521D_FIXED_400M,	"400m", NULL, CLK_IS_ROOT, 400000000, },
++	{ HI3521D_FIXED_448M,	"448m", NULL, CLK_IS_ROOT, 448000000, },
++	{ HI3521D_FIXED_500M,	"500m", NULL, CLK_IS_ROOT, 500000000, },
++	{ HI3521D_FIXED_540M,	"540m", NULL, CLK_IS_ROOT, 540000000, },
++	{ HI3521D_FIXED_600M,	"600m", NULL, CLK_IS_ROOT, 600000000, },
++	{ HI3521D_FIXED_750M,	"750m",	NULL, CLK_IS_ROOT, 750000000, },
++	{ HI3521D_FIXED_1500M,	"1500m", NULL, CLK_IS_ROOT, 1500000000UL, },
++};
++
++static const char *sysaxi_mux_p[] __initconst = {
++	"24m", "200m", "250m", "300m"};
++/* If syaaxi bus clock is 200MHz, so the APB clock is 50MHz, factor is 4 */
++static const char *uart_mux_p[] __initconst = {"sysaxi_mux", "24m", "2m"};
++static const char *fmc_mux_p[] __initconst = {
++	"24m", "83.3m", "150m"};
++
++static const char *viu_mux_p[] = {"300m", "200m", "150m"};
++static u32 sysaxi_mux_table[] = {0, 1, 2, 3};
++static u32 uart_mux_table[] = {0, 1, 2};
++static u32 fmc_mux_table[] = {0, 1, 2};
++static u32 viu_mux_p_table[] = {0, 1, 2};
++
++static struct hisi_mux_clock hi3521d_mux_clks_crg[] __initdata = {
++	{ HI3521D_SYSAXI_CLK, "sysaxi_mux", sysaxi_mux_p,
++		ARRAY_SIZE(sysaxi_mux_p),
++		CLK_SET_RATE_PARENT, 0x50, 2, 2, 0, sysaxi_mux_table, },
++	{ HI3521D_FMC_MUX, "fmc_mux", fmc_mux_p, ARRAY_SIZE(fmc_mux_p),
++		CLK_SET_RATE_PARENT, 0x148, 2, 2, 0, fmc_mux_table, },
++	{ HI3521D_UART_MUX, "uart_mux", uart_mux_p,
++		ARRAY_SIZE(uart_mux_p),
++		CLK_SET_RATE_PARENT, 0x154, 19, 2, 0, uart_mux_table, },
++	{ HI3521D_VIU_MUX, "viu_mux", viu_mux_p, ARRAY_SIZE(viu_mux_p),
++		CLK_SET_RATE_PARENT, 0x98, 5, 2, 0, viu_mux_p_table, },
++};
++
++static struct hisi_fixed_factor_clock
++				hi3521d_fixed_factor_clks[] __initdata = {
++	{ HI3521D_SYSAXI_CLK, "clk_sysaxi", "sysaxi_mux", 1, 4,
++		CLK_SET_RATE_PARENT},
++};
++
++static struct hisi_gate_clock hi3521d_gate_clks[] __initdata = {
++#ifdef CONFIG_HIFMC
++	/* fmc */
++	{ HI3521D_FMC_CLK, "clk_fmc", "fmc_mux",
++		CLK_SET_RATE_PARENT, 0x148, 1, 0, },
++#endif
++	/* uart */
++	{ HI3521D_UART0_CLK, "clk_uart0", "24m",
++		CLK_SET_RATE_PARENT, 0x154, 15, 0, },
++	{ HI3521D_UART1_CLK, "clk_uart1", "24m",
++		CLK_SET_RATE_PARENT, 0x154, 16, 0, },
++	{ HI3521D_UART2_CLK, "clk_uart2", "24m",
++		CLK_SET_RATE_PARENT, 0x154, 17, 0, },
++	{ HI3521D_UART3_CLK, "clk_uart3", "24m",
++		CLK_SET_RATE_PARENT, 0x154, 18, 0, },
++	/* ethernet mac */
++	{ HI3521D_ETH_PHY_CLK, "clk_eth_phy", NULL,
++		CLK_SET_RATE_PARENT, 0x14c, 6, 0, },
++	{ HI3521D_ETH_PUB_CLK, "clk_eth_pub", "clk_eth_phy",
++		CLK_SET_RATE_PARENT, 0x14c, 7, 0, },
++	{ HI3521D_ETH_CLK, "clk_eth", "clk_eth_pub",
++		CLK_SET_RATE_PARENT, 0x14c, 1, 0, },
++	{ HI3521D_ETH_MACIF_CLK, "clk_eth_macif", "clk_eth_pub",
++		CLK_SET_RATE_PARENT, 0x14c, 3, 0, },
++	/* spi */
++	{ HI3521D_SPI0_CLK, "clk_spi0", "clk_sysaxi",
++		CLK_SET_RATE_PARENT, 0x154, 13, 0, },
++	{ HI3521D_VIU_CLK, "clk_viu", "viu_mux", CLK_SET_RATE_PARENT,
++		0x98, 2, 0, },
++	/* dma */
++	{ HI3521D_DMAC_CLK, "clk_dmac", "50m", CLK_SET_RATE_PARENT,
++		0x144, 1, 0, },
++};
++
++static void __init hi3521d_clk_crg_init(struct device_node *np)
++{
++	struct hisi_clock_data *clk_data;
++	unsigned int count = 0;
++
++	clk_data = hisi_clk_init(np, HI3521D_CRG_NR_CLKS);
++	if (!clk_data)
++		return;
++
++	hisi_clk_register_fixed_rate(hi3521d_fixed_rate_clks_crg,
++			ARRAY_SIZE(hi3521d_fixed_rate_clks_crg),
++			clk_data);
++	hisi_clk_register_mux(hi3521d_mux_clks_crg,
++			ARRAY_SIZE(hi3521d_mux_clks_crg), clk_data);
++	hisi_clk_register_fixed_factor(hi3521d_fixed_factor_clks,
++			ARRAY_SIZE(hi3521d_fixed_factor_clks), clk_data);
++	hisi_clk_register_gate(hi3521d_gate_clks,
++			ARRAY_SIZE(hi3521d_gate_clks), clk_data);
++
++	if (!of_property_read_u32(np, "#reset-cells", &count) && (count == 2))
++		hisi_reset_init(np, HI3521D_CRG_NR_RSTS);
++}
++
++static const char *timer_mux_p[] __initconst = { "3m", "clk_sysapb" };
++static u32 timer_mux_table[] = {0, 1};
++
++static struct hisi_mux_clock hi3521d_mux_clks_sys[] __initdata = {
++	{ HI3521D_TIME0_0_CLK, "timer00", timer_mux_p,
++		ARRAY_SIZE(timer_mux_p), CLK_SET_RATE_PARENT,
++		0x0, 16, 1, 0, timer_mux_table, },
++
++	{ HI3521D_TIME0_1_CLK, "timer01", timer_mux_p,
++		ARRAY_SIZE(timer_mux_p), CLK_SET_RATE_PARENT,
++		0x0, 18, 1, 0, timer_mux_table, },
++
++	{ HI3521D_TIME1_2_CLK, "timer12", timer_mux_p,
++		ARRAY_SIZE(timer_mux_p), CLK_SET_RATE_PARENT,
++		0x0, 20, 1, 0, timer_mux_table, },
++
++	{ HI3521D_TIME1_3_CLK, "timer13", timer_mux_p,
++		ARRAY_SIZE(timer_mux_p), CLK_SET_RATE_PARENT,
++		0x0, 22, 1, 0, timer_mux_table, },
++};
++
++static void __init hi3521d_clk_sys_init(struct device_node *np)
++{
++	struct hisi_clock_data *clk_data;
++	unsigned int count = 0;
++
++	clk_data = hisi_clk_init(np, HI3521D_SYS_NR_CLKS);
++	if (!clk_data)
++		return;
++
++	hisi_clk_register_mux(hi3521d_mux_clks_sys,
++			ARRAY_SIZE(hi3521d_mux_clks_sys), clk_data);
++
++	if (!of_property_read_u32(np, "#reset-cells", &count) && (count == 2))
++		hisi_reset_init(np, HI3521D_SYS_NR_RSTS);
++}
++
++CLK_OF_DECLARE(hi3521d_clk_crg, "hisilicon,hi3521d-clock",
++							hi3521d_clk_crg_init);
++CLK_OF_DECLARE(hi3521d_clk_sys, "hisilicon,sysctrl", hi3521d_clk_sys_init);
++
+diff --git a/drivers/clk/hisilicon/clk-hi3531d.c b/drivers/clk/hisilicon/clk-hi3531d.c
+new file mode 100644
+index 0000000..5dc519e
+--- /dev/null
++++ b/drivers/clk/hisilicon/clk-hi3531d.c
+@@ -0,0 +1,205 @@
++/*
++ * Hi3531D Clock Driver
++ *
++ * Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include <dt-bindings/clock/hi3531d-clock.h>
++#include "clk.h"
++#include "reset.h"
++
++static struct
++hisi_fixed_rate_clock hi3531d_fixed_rate_clks_crg[] __initdata = {
++	{ HI3531D_FIXED_3M, "3m", NULL, CLK_IS_ROOT, 3000000, },
++	{ HI3531D_FIXED_6M, "6m", NULL, CLK_IS_ROOT, 6000000, },
++	{ HI3531D_FIXED_12M, "12m", NULL, CLK_IS_ROOT, 12000000, },
++	{ HI3531D_FIXED_15M, "15m", NULL, CLK_IS_ROOT, 15000000, },
++	{ HI3531D_FIXED_24M, "24m", NULL, CLK_IS_ROOT, 24000000, },
++	{ HI3531D_FIXED_44M, "44m", NULL, CLK_IS_ROOT, 44000000, },
++	{ HI3531D_FIXED_49P5, "49.5m", NULL, CLK_IS_ROOT, 49500000, },
++	{ HI3531D_FIXED_50M, "50m", NULL, CLK_IS_ROOT, 50000000, },
++	{ HI3531D_FIXED_54M, "54m", NULL, CLK_IS_ROOT, 54000000, },
++	{ HI3531D_FIXED_75M, "75m", NULL, CLK_IS_ROOT, 75000000, },
++	{ HI3531D_FIXED_83P3M, "83.3m", NULL, CLK_IS_ROOT, 83300000, },
++	{ HI3531D_FIXED_99M, "99m", NULL, CLK_IS_ROOT, 99000000, },
++	{ HI3531D_FIXED_100M, "100m", NULL, CLK_IS_ROOT, 100000000, },
++	{ HI3531D_FIXED_125M, "125m", NULL, CLK_IS_ROOT, 125000000, },
++	{ HI3531D_FIXED_150M, "150m", NULL, CLK_IS_ROOT, 150000000, },
++	{ HI3531D_FIXED_200M, "200m", NULL, CLK_IS_ROOT, 200000000, },
++	{ HI3531D_FIXED_250M, "250m", NULL, CLK_IS_ROOT, 250000000, },
++	{ HI3531D_FIXED_300M, "300m", NULL, CLK_IS_ROOT, 300000000, },
++	{ HI3531D_FIXED_324M, "324m", NULL, CLK_IS_ROOT, 324000000, },
++	{ HI3531D_FIXED_342M, "342m", NULL, CLK_IS_ROOT, 342000000, },
++	{ HI3531D_FIXED_342M, "375m", NULL, CLK_IS_ROOT, 375000000, },
++	{ HI3531D_FIXED_400M, "400m", NULL, CLK_IS_ROOT, 400000000, },
++	{ HI3531D_FIXED_448M, "448m", NULL, CLK_IS_ROOT, 448000000, },
++	{ HI3531D_FIXED_500M, "500m", NULL, CLK_IS_ROOT, 500000000, },
++	{ HI3531D_FIXED_540M, "540m", NULL, CLK_IS_ROOT, 540000000, },
++	{ HI3531D_FIXED_600M, "600m", NULL, CLK_IS_ROOT, 600000000, },
++	{ HI3531D_FIXED_750M, "750m", NULL, CLK_IS_ROOT, 750000000, },
++	{ HI3531D_FIXED_1500M, "1500m", NULL, CLK_IS_ROOT, 1500000000UL, },
++};
++
++static const char *periaxi_mux_p[] __initconst = {
++	"24m", "200m", "300m"};
++static const char *sysaxi_mux_p[] __initconst = {
++	"24m", "324m", "375m"};
++/* PERIAXI clock is 200MHz, so the APB clock is 50MHz, factor is 4 */
++static const char *uart_mux_p[] __initconst = {"clk_sysapb", "24m", "2m"};
++static const char *fmc_mux_p[] __initconst = {
++	"24m", "83.3m", "125m", "150m"};
++static const char *nfc_mux_p[] __initconst = {
++	"24m", "200m"};
++
++static const char *viu_mux_p[] = {"300m", "200m", "150m"};
++
++static u32 periaxi_mux_table[] = {0, 1, 2};
++static u32 sysaxi_mux_table[] = {0, 1, 2};
++static u32 uart_mux_table[] = {0, 1, 2};
++static u32 fmc_mux_table[] = {0, 1, 2, 3};
++static u32 nfc_mux_table[] = {0, 1};
++static u32 viu_mux_p_table[] = {0, 1, 2};
++
++static struct hisi_mux_clock hi3531d_mux_clks_crg[] __initdata = {
++	{ HI3531D_PERIAXI_CLK, "periaxi_mux", periaxi_mux_p,
++		ARRAY_SIZE(periaxi_mux_p),
++		CLK_SET_RATE_PARENT, 0x50, 0, 2, 0, periaxi_mux_table, },
++	{ HI3531D_SYSAXI_CLK, "sysaxi_mux", sysaxi_mux_p,
++		ARRAY_SIZE(sysaxi_mux_p),
++		CLK_SET_RATE_PARENT, 0x50, 2, 2, 0, sysaxi_mux_table, },
++	{ HI3531D_NFC_MUX, "nfc_mux", nfc_mux_p, ARRAY_SIZE(nfc_mux_p),
++		CLK_SET_RATE_PARENT, 0x13c, 2, 1, 0, nfc_mux_table, },
++	{ HI3531D_FMC_MUX, "fmc_mux", fmc_mux_p, ARRAY_SIZE(fmc_mux_p),
++		CLK_SET_RATE_PARENT, 0x148, 2, 2, 0, fmc_mux_table, },
++	{ HI3531D_UART_MUX, "uart_mux", uart_mux_p,
++		ARRAY_SIZE(uart_mux_p),
++		CLK_SET_RATE_PARENT, 0x154, 19, 2, 0, uart_mux_table, },
++
++	/* media mux clock*/
++	{ HI3531D_VIU_MUX, "viu_mux", viu_mux_p, ARRAY_SIZE(viu_mux_p),
++		CLK_SET_RATE_PARENT, 0x98, 5, 2, 0, viu_mux_p_table, },
++
++};
++
++static struct hisi_fixed_factor_clock
++				hi3531d_fixed_factor_clks[] __initdata = {
++	{ HI3531D_PERIAXI_CLK, "clk_sysapb", "periaxi_mux", 1, 4,
++		CLK_SET_RATE_PARENT},
++	{ HI3531D_SYSAXI_CLK, "clk_sysaxi", "sysaxi_mux", 1, 4,
++		CLK_SET_RATE_PARENT},
++};
++
++static struct hisi_gate_clock hi3531d_gate_clks[] __initdata = {
++#ifdef CONFIG_HIFMC
++	/* fmc */
++	{ HI3531D_FMC_CLK, "clk_fmc", "fmc_mux",
++		CLK_SET_RATE_PARENT, 0x148, 1, 0, },
++#endif
++#ifdef CONFIG_HINFC
++	/* hinfc610 */
++	{ HI3531D_NFC_CLK, "clk_nfc", "nfc_mux",
++		CLK_SET_RATE_PARENT, 0x13c, 1, 0, },
++#endif
++	/* uart */
++	{ HI3531D_UART0_CLK, "clk_uart0", "24m",
++		CLK_SET_RATE_PARENT, 0x154, 15, 0, },
++	{ HI3531D_UART1_CLK, "clk_uart1", "24m",
++		CLK_SET_RATE_PARENT, 0x154, 16, 0, },
++	{ HI3531D_UART2_CLK, "clk_uart2", "24m",
++		CLK_SET_RATE_PARENT, 0x154, 17, 0, },
++	{ HI3531D_UART3_CLK, "clk_uart3", "24m",
++		CLK_SET_RATE_PARENT, 0x154, 18, 0, },
++	/* ethernet mac */
++	{ HI3531D_ETH_CLK, "clk_eth", NULL,
++		CLK_IS_ROOT, 0x14c, 1, 0, },
++	{ HI3531D_ETH_MACIF_CLK, "clk_eth_macif", NULL,
++		CLK_IS_ROOT, 0x14c, 3, 0, },
++	/* spi */
++	{ HI3531D_SPI0_CLK, "clk_spi0", "clk_sysapb",
++		CLK_SET_RATE_PARENT, 0x154, 13, 0, },
++	/* media gate clock*/
++	{ HI3531D_VIU_CLK, "clk_viu", "viu_mux", CLK_SET_RATE_PARENT,
++		0x98, 2, 0, },
++	/* dma */
++	{ HI3531D_DMAC_CLK, "clk_dmac", "50m", CLK_SET_RATE_PARENT,
++		0x144, 1, 0, },
++};
++
++static void __init hi3531d_clk_crg_init(struct device_node *np)
++{
++	struct hisi_clock_data *clk_data;
++	unsigned int count = 0;
++
++	clk_data = hisi_clk_init(np, HI3531D_CRG_NR_CLKS);
++	if (!clk_data)
++		return;
++
++	hisi_clk_register_fixed_rate(hi3531d_fixed_rate_clks_crg,
++			ARRAY_SIZE(hi3531d_fixed_rate_clks_crg),
++			clk_data);
++	hisi_clk_register_mux(hi3531d_mux_clks_crg,
++			ARRAY_SIZE(hi3531d_mux_clks_crg), clk_data);
++	hisi_clk_register_fixed_factor(hi3531d_fixed_factor_clks,
++			ARRAY_SIZE(hi3531d_fixed_factor_clks), clk_data);
++	hisi_clk_register_gate(hi3531d_gate_clks,
++			ARRAY_SIZE(hi3531d_gate_clks), clk_data);
++
++	if (!of_property_read_u32(np, "#reset-cells", &count) && (count == 2))
++		hisi_reset_init(np, HI3531D_CRG_NR_RSTS);
++}
++
++static const char *timer_mux_p[] __initconst = { "3m", "clk_sysapb" };
++static u32 timer_mux_table[] = {0, 1};
++
++static struct hisi_mux_clock hi3531d_mux_clks_sys[] __initdata = {
++	{ HI3531D_TIME0_0_CLK, "timer00", timer_mux_p,
++		ARRAY_SIZE(timer_mux_p), CLK_SET_RATE_PARENT,
++		0x0, 16, 1, 0, timer_mux_table, },
++
++	{ HI3531D_TIME0_1_CLK, "timer01", timer_mux_p,
++		ARRAY_SIZE(timer_mux_p), CLK_SET_RATE_PARENT,
++		0x0, 18, 1, 0, timer_mux_table, },
++
++	{ HI3531D_TIME1_2_CLK, "timer12", timer_mux_p,
++		ARRAY_SIZE(timer_mux_p), CLK_SET_RATE_PARENT,
++		0x0, 20, 1, 0, timer_mux_table, },
++
++	{ HI3531D_TIME1_3_CLK, "timer13", timer_mux_p,
++		ARRAY_SIZE(timer_mux_p), CLK_SET_RATE_PARENT,
++		0x0, 22, 1, 0, timer_mux_table, },
++};
++
++static void __init hi3531d_clk_sys_init(struct device_node *np)
++{
++	struct hisi_clock_data *clk_data;
++	unsigned int count = 0;
++
++	clk_data = hisi_clk_init(np, HI3531D_SYS_NR_CLKS);
++	if (!clk_data)
++		return;
++
++	hisi_clk_register_mux(hi3531d_mux_clks_sys,
++			ARRAY_SIZE(hi3531d_mux_clks_sys), clk_data);
++
++	if (!of_property_read_u32(np, "#reset-cells", &count) && (count == 2))
++		hisi_reset_init(np, HI3531D_SYS_NR_RSTS);
++}
++
++CLK_OF_DECLARE(hi3531d_clk_crg, "hisilicon,hi3531d-clock",
++							hi3531d_clk_crg_init);
++CLK_OF_DECLARE(hi3531d_clk_sys, "hisilicon,sysctrl", hi3531d_clk_sys_init);
++
+diff --git a/drivers/clk/hisilicon/clk-hi3536c.c b/drivers/clk/hisilicon/clk-hi3536c.c
+new file mode 100644
+index 0000000..e3ebd35
+--- /dev/null
++++ b/drivers/clk/hisilicon/clk-hi3536c.c
+@@ -0,0 +1,178 @@
++/*
++ * Hi3536C Clock Driver
++ *
++ * Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include <dt-bindings/clock/hi3536c-clock.h>
++#include "clk.h"
++#include "reset.h"
++
++static struct
++hisi_fixed_rate_clock hi3536c_fixed_rate_clks_crg[] __initdata = {
++	{ HI3536C_FIXED_3M,		"3m",	NULL, CLK_IS_ROOT, 3000000, },
++	{ HI3536C_FIXED_6M,		"6m",	NULL, CLK_IS_ROOT, 6000000, },
++	{ HI3536C_FIXED_12M,	"12m",	NULL, CLK_IS_ROOT, 12000000, },
++	{ HI3536C_FIXED_24M,	"24m",	NULL, CLK_IS_ROOT, 24000000, },
++	{ HI3536C_FIXED_83P3M,	"83.3m", NULL, CLK_IS_ROOT, 83300000, },
++	{ HI3536C_FIXED_100M,	"100m", NULL, CLK_IS_ROOT, 100000000, },
++	{ HI3536C_FIXED_125M,	"125m", NULL, CLK_IS_ROOT, 125000000, },
++	{ HI3536C_FIXED_150M,	"150m", NULL, CLK_IS_ROOT, 150000000, },
++	{ HI3536C_FIXED_200M,	"200m", NULL, CLK_IS_ROOT, 200000000, },
++	{ HI3536C_FIXED_250M,	"250m", NULL, CLK_IS_ROOT, 250000000, },
++	{ HI3536C_FIXED_300M,	"300m", NULL, CLK_IS_ROOT, 300000000, },
++	{ HI3536C_FIXED_324M,	"324m", NULL, CLK_IS_ROOT, 324000000, },
++	{ HI3536C_FIXED_342M,	"342m", NULL, CLK_IS_ROOT, 342000000, },
++	{ HI3536C_FIXED_342M,	"375m", NULL, CLK_IS_ROOT, 375000000, },
++	{ HI3536C_FIXED_400M,	"400m", NULL, CLK_IS_ROOT, 400000000, },
++	{ HI3536C_FIXED_448M,	"448m", NULL, CLK_IS_ROOT, 448000000, },
++	{ HI3536C_FIXED_500M,	"500m", NULL, CLK_IS_ROOT, 500000000, },
++	{ HI3536C_FIXED_540M,	"540m", NULL, CLK_IS_ROOT, 540000000, },
++	{ HI3536C_FIXED_600M,	"600m", NULL, CLK_IS_ROOT, 600000000, },
++	{ HI3536C_FIXED_750M,	"750m",	NULL, CLK_IS_ROOT, 750000000, },
++	{ HI3536C_FIXED_1500M,	"1500m", NULL, CLK_IS_ROOT, 1500000000UL, },
++};
++
++static const char *sysaxi_mux_p[] __initconst = {
++	"24m", "200m", "250m", "300m"};
++/* If syaaxi bus clock is 200MHz, so the APB clock is 50MHz, factor is 4 */
++static const char *uart_mux_p[] __initconst = {"sysaxi_mux", "24m", "2m"};
++static const char *fmc_mux_p[] __initconst = {
++	"24m", "83.3m", "150m"};
++
++static u32 sysaxi_mux_table[] = {0, 1, 2, 3};
++static u32 uart_mux_table[] = {0, 1, 2};
++static u32 fmc_mux_table[] = {0, 1, 2};
++
++static struct hisi_mux_clock hi3536c_mux_clks_crg[] __initdata = {
++	{ HI3536C_SYSAXI_CLK, "sysaxi_mux", sysaxi_mux_p,
++		ARRAY_SIZE(sysaxi_mux_p),
++		CLK_SET_RATE_PARENT, 0x50, 2, 2, 0, sysaxi_mux_table, },
++	{ HI3536C_FMC_MUX, "fmc_mux", fmc_mux_p, ARRAY_SIZE(fmc_mux_p),
++		CLK_SET_RATE_PARENT, 0x148, 2, 2, 0, fmc_mux_table, },
++	{ HI3536C_UART_MUX, "uart_mux", uart_mux_p,
++		ARRAY_SIZE(uart_mux_p),
++		CLK_SET_RATE_PARENT, 0x154, 19, 2, 0, uart_mux_table, },
++};
++
++static struct hisi_fixed_factor_clock
++				hi3536c_fixed_factor_clks[] __initdata = {
++	{ HI3536C_SYSAXI_CLK, "clk_sysaxi", "sysaxi_mux", 1, 4,
++		CLK_SET_RATE_PARENT},
++};
++
++static struct hisi_gate_clock hi3536c_gate_clks[] __initdata = {
++#ifdef CONFIG_HIFMC
++	/* fmc */
++	{ HI3536C_FMC_CLK, "clk_fmc", "fmc_mux",
++		CLK_SET_RATE_PARENT, 0x148, 1, 0, },
++#endif
++	/* uart */
++	{ HI3536C_UART0_CLK, "clk_uart0", "24m",
++		CLK_SET_RATE_PARENT, 0x154, 15, 0, },
++	{ HI3536C_UART1_CLK, "clk_uart1", "24m",
++		CLK_SET_RATE_PARENT, 0x154, 16, 0, },
++	{ HI3536C_UART2_CLK, "clk_uart2", "24m",
++		CLK_SET_RATE_PARENT, 0x154, 17, 0, },
++	/* ethernet mac */
++	{ HI3536C_ETH_PHY_CLK, "clk_eth_phy", NULL,
++		CLK_SET_RATE_PARENT, 0x14c, 6, 0, },
++	{ HI3536C_ETH_PUB_CLK, "clk_eth_pub", "clk_eth_phy",
++		CLK_SET_RATE_PARENT, 0x14c, 7, 0, },
++	{ HI3536C_ETH_CLK, "clk_eth", "clk_eth_pub",
++		CLK_SET_RATE_PARENT, 0x14c, 1, 0, },
++	{ HI3536C_ETH_MACIF_CLK, "clk_eth_macif", "clk_eth_pub",
++		CLK_SET_RATE_PARENT, 0x14c, 3, 0, },
++	/* ethernet mac1 */
++	{ HI3536C_ETH1_PHY_CLK, "clk_eth1_phy", NULL,
++		CLK_SET_RATE_PARENT, 0x14c, 14, 0, },
++	{ HI3536C_ETH1_CLK, "clk_eth1", "clk_eth1_phy",
++		CLK_SET_RATE_PARENT, 0x14c, 9, 0, },
++	{ HI3536C_ETH_MACIF1_CLK, "clk_eth_macif1", "clk_eth1_phy",
++		CLK_SET_RATE_PARENT, 0x14c, 11, 0, },
++	/* spi */
++	{ HI3536C_SPI0_CLK, "clk_spi0", "clk_sysaxi",
++		CLK_SET_RATE_PARENT, 0x154, 13, 0, },
++	/* dma */
++	{ HI3536C_DMAC_CLK, "clk_dmac", "50m", CLK_SET_RATE_PARENT,
++		0x144, 1, 0, },
++};
++
++static void __init hi3536c_clk_crg_init(struct device_node *np)
++{
++	struct hisi_clock_data *clk_data;
++	unsigned int count = 0;
++
++	clk_data = hisi_clk_init(np, HI3536C_CRG_NR_CLKS);
++	if (!clk_data)
++		return;
++
++	hisi_clk_register_fixed_rate(hi3536c_fixed_rate_clks_crg,
++			ARRAY_SIZE(hi3536c_fixed_rate_clks_crg),
++			clk_data);
++	hisi_clk_register_mux(hi3536c_mux_clks_crg,
++			ARRAY_SIZE(hi3536c_mux_clks_crg), clk_data);
++	hisi_clk_register_fixed_factor(hi3536c_fixed_factor_clks,
++			ARRAY_SIZE(hi3536c_fixed_factor_clks), clk_data);
++	hisi_clk_register_gate(hi3536c_gate_clks,
++			ARRAY_SIZE(hi3536c_gate_clks), clk_data);
++
++	if (!of_property_read_u32(np, "#reset-cells", &count) && (count == 2))
++		hisi_reset_init(np, HI3536C_CRG_NR_RSTS);
++}
++
++static const char *timer_mux_p[] __initconst = { "3m", "clk_sysapb" };
++static u32 timer_mux_table[] = {0, 1};
++
++static struct hisi_mux_clock hi3536c_mux_clks_sys[] __initdata = {
++	{ HI3536C_TIME0_0_CLK, "timer00", timer_mux_p,
++		ARRAY_SIZE(timer_mux_p), CLK_SET_RATE_PARENT,
++		0x0, 16, 1, 0, timer_mux_table, },
++
++	{ HI3536C_TIME0_1_CLK, "timer01", timer_mux_p,
++		ARRAY_SIZE(timer_mux_p), CLK_SET_RATE_PARENT,
++		0x0, 18, 1, 0, timer_mux_table, },
++
++	{ HI3536C_TIME1_2_CLK, "timer12", timer_mux_p,
++		ARRAY_SIZE(timer_mux_p), CLK_SET_RATE_PARENT,
++		0x0, 20, 1, 0, timer_mux_table, },
++
++	{ HI3536C_TIME1_3_CLK, "timer13", timer_mux_p,
++		ARRAY_SIZE(timer_mux_p), CLK_SET_RATE_PARENT,
++		0x0, 22, 1, 0, timer_mux_table, },
++};
++
++static void __init hi3536c_clk_sys_init(struct device_node *np)
++{
++	struct hisi_clock_data *clk_data;
++	unsigned int count = 0;
++
++	clk_data = hisi_clk_init(np, HI3536C_SYS_NR_CLKS);
++	if (!clk_data)
++		return;
++
++	hisi_clk_register_mux(hi3536c_mux_clks_sys,
++			ARRAY_SIZE(hi3536c_mux_clks_sys), clk_data);
++
++	if (!of_property_read_u32(np, "#reset-cells", &count) && (count == 2))
++		hisi_reset_init(np, HI3536C_SYS_NR_RSTS);
++}
++
++CLK_OF_DECLARE(hi3536c_clk_crg, "hisilicon,hi3536c-clock",
++							hi3536c_clk_crg_init);
++CLK_OF_DECLARE(hi3536c_clk_sys, "hisilicon,sysctrl", hi3536c_clk_sys_init);
++
+diff --git a/drivers/clk/hisilicon/clk-hi3556.c b/drivers/clk/hisilicon/clk-hi3556.c
+new file mode 100644
+index 0000000..56e160f
+--- /dev/null
++++ b/drivers/clk/hisilicon/clk-hi3556.c
+@@ -0,0 +1,384 @@
++/*
++ * Copyright (c) 2015 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <linux/of_address.h>
++#include <dt-bindings/clock/hi3556-clock.h>
++#include <linux/slab.h>
++#include <linux/delay.h>
++#include <mach/io.h>
++
++#include "clk.h"
++#include "reset.h"
++
++/******************************************************************************/
++struct hi3556_pll_clock {
++	u32		id;
++	const char	*name;
++	const char	*parent_name;
++	u32		ctrl_reg1;
++	u8		frac_shift;
++	u8		frac_width;
++	u8		postdiv1_shift;
++	u8		postdiv1_width;
++	u8		postdiv2_shift;
++	u8		postdiv2_width;
++	u32		ctrl_reg2;
++	u8		fbdiv_shift;
++	u8		fbdiv_width;
++	u8		refdiv_shift;
++	u8		refdiv_width;
++};
++
++struct hi3556_clk_pll {
++	struct clk_hw	hw;
++	u32		id;
++	void __iomem	*ctrl_reg1;
++	u8		frac_shift;
++	u8		frac_width;
++	u8		postdiv1_shift;
++	u8		postdiv1_width;
++	u8		postdiv2_shift;
++	u8		postdiv2_width;
++	void __iomem	*ctrl_reg2;
++	u8		fbdiv_shift;
++	u8		fbdiv_width;
++	u8		refdiv_shift;
++	u8		refdiv_width;
++};
++
++static struct hisi_fixed_rate_clock hi3556_fixed_rate_clks[] __initdata = {
++	{ HI3556_FIXED_2376M, "2376m", NULL, CLK_IS_ROOT, 2376000000UL, },
++	{ HI3556_FIXED_1188M, "1188m", NULL, CLK_IS_ROOT, 1188000000, },
++	{ HI3556_FIXED_594M, "594m", NULL, CLK_IS_ROOT, 594000000, },
++	{ HI3556_FIXED_297M, "297m", NULL, CLK_IS_ROOT, 297000000, },
++	{ HI3556_FIXED_148P5M, "148p5m", NULL, CLK_IS_ROOT, 148500000, },
++	{ HI3556_FIXED_74P25M, "74p25m", NULL, CLK_IS_ROOT, 74250000, },
++	{ HI3556_FIXED_792M, "792m", NULL, CLK_IS_ROOT, 792000000, },
++	{ HI3556_FIXED_475M, "475m", NULL, CLK_IS_ROOT, 475000000, },
++	{ HI3556_FIXED_340M, "340m", NULL, CLK_IS_ROOT, 340000000, },
++	{ HI3556_FIXED_72M, "72m", NULL, CLK_IS_ROOT, 72000000, },
++	{ HI3556_FIXED_400M, "400m", NULL, CLK_IS_ROOT, 400000000, },
++	{ HI3556_FIXED_200M, "200m", NULL, CLK_IS_ROOT, 200000000, },
++	{ HI3556_FIXED_54M, "54m", NULL, CLK_IS_ROOT, 54000000, },
++	{ HI3556_FIXED_27M, "27m", NULL, CLK_IS_ROOT, 1188000000, },
++	{ HI3556_FIXED_37P125M, "37p125m", NULL, CLK_IS_ROOT, 37125000, },
++	{ HI3556_FIXED_3000M, "3000m", NULL, CLK_IS_ROOT, 3000000000UL, },
++	{ HI3556_FIXED_1500M, "1500m", NULL, CLK_IS_ROOT, 1500000000, },
++	{ HI3556_FIXED_500M, "500m", NULL, CLK_IS_ROOT, 500000000, },
++	{ HI3556_FIXED_250M, "250m", NULL, CLK_IS_ROOT, 250000000, },
++	{ HI3556_FIXED_125M, "125m", NULL, CLK_IS_ROOT, 125000000, },
++	{ HI3556_FIXED_1000M, "1000m", NULL, CLK_IS_ROOT, 1000000000, },
++	{ HI3556_FIXED_600M, "600m", NULL, CLK_IS_ROOT, 600000000, },
++	{ HI3556_FIXED_750M, "750m", NULL, CLK_IS_ROOT, 750000000, },
++	{ HI3556_FIXED_150M, "150m", NULL, CLK_IS_ROOT, 150000000, },
++	{ HI3556_FIXED_75M, "75m", NULL, CLK_IS_ROOT, 75000000, },
++	{ HI3556_FIXED_300M, "300m", NULL, CLK_IS_ROOT, 300000000, },
++	{ HI3556_FIXED_60M, "60m", NULL, CLK_IS_ROOT, 60000000, },
++	{ HI3556_FIXED_214M, "214m", NULL, CLK_IS_ROOT, 214000000, },
++	{ HI3556_FIXED_107M, "107m", NULL, CLK_IS_ROOT, 107000000, },
++	{ HI3556_FIXED_100M, "100m", NULL, CLK_IS_ROOT, 100000000, },
++	{ HI3556_FIXED_50M, "50m", NULL, CLK_IS_ROOT, 50000000, },
++	{ HI3556_FIXED_25M, "25m", NULL, CLK_IS_ROOT, 25000000, },
++	{ HI3556_FIXED_24M, "24m", NULL, CLK_IS_ROOT, 24000000, },
++	{ HI3556_FIXED_3M, "3m", NULL, CLK_IS_ROOT, 3000000, },
++	{ HI3556_FIXED_198M, "198m", NULL, CLK_IS_ROOT, 198000000, },
++	{ HI3556_FIXED_396M, "396m", NULL, CLK_IS_ROOT, 396000000, },
++};
++
++static const char *sysaxi_mux_p[] __initconst = {"24m", "198m", };
++static u32 sysaxi_mux_table[] = {0, 1};
++
++static const char *fmc_mux_p[] __initconst = {
++	"24m", "75m", "125m", "150m", "198m", "250m", "300m", "396m", };
++static u32 fmc_mux_table[] = {0, 1, 2, 3, 4, 5, 6, 7};
++
++static const char *mmc_mux_p[] __initconst = {
++	"100m", "198m", "396m", "594m", "792m", "1188m", };
++static u32 mmc_mux_table[] = {0, 1, 3, 4, 5, 7};
++
++static const char *a17_mux_p[] __initconst = {
++	"24m", "apll", "594m", "792m", };
++static u32 a17_mux_table[] = {0, 1, 3, 4};
++
++static const char *i2c_mux_p[] __initconst = {"clk_sysapb", "50m"};
++static u32 i2c_mux_table[] = {0, 1};
++
++static struct hisi_mux_clock hi3556_mux_clks[] __initdata = {
++	{ HI3556_SYSAXI_MUX, "sysaxi_mux", sysaxi_mux_p,
++		ARRAY_SIZE(sysaxi_mux_p),
++		CLK_SET_RATE_PARENT, 0x34, 12, 2, 0, sysaxi_mux_table, },
++	{ HI3556_FMC_MUX, "fmc_mux", fmc_mux_p, ARRAY_SIZE(fmc_mux_p),
++		CLK_SET_RATE_PARENT, 0xc0, 2, 3, 0, fmc_mux_table, },
++	{ HI3556_MMC0_MUX, "mmc0_mux", mmc_mux_p, ARRAY_SIZE(mmc_mux_p),
++		CLK_SET_RATE_PARENT, 0xc4, 10, 3, 0, mmc_mux_table, },
++	{ HI3556_MMC1_MUX, "mmc1_mux", mmc_mux_p, ARRAY_SIZE(mmc_mux_p),
++		CLK_SET_RATE_PARENT, 0xc4, 2, 3, 0, mmc_mux_table, },
++	{ HI3556_MMC2_MUX, "mmc2_mux", mmc_mux_p, ARRAY_SIZE(mmc_mux_p),
++		CLK_SET_RATE_PARENT, 0xc4, 18, 3, 0, mmc_mux_table, },
++	{ HI3556_A17_MUX, "a17_mux", a17_mux_p, ARRAY_SIZE(a17_mux_p),
++		CLK_SET_RATE_PARENT, 0x34, 4, 3, 0, a17_mux_table, },
++	{ HI3556_I2C_MUX, "i2c_mux", i2c_mux_p, ARRAY_SIZE(i2c_mux_p),
++		CLK_SET_RATE_PARENT, 0xe4, 26, 1, 0, i2c_mux_table, },
++
++};
++
++static struct hisi_fixed_factor_clock
++	hi3556_fixed_factor_clks[] __initdata = {
++	{ HI3556_SYSAPB_CLK, "clk_sysapb", "sysaxi_mux", 1, 4,
++		CLK_SET_RATE_PARENT},
++	{ HI3556_MMC0_FAC_CLK, "mmc0_fac", "mmc0_mux", 1, 8,
++		CLK_SET_RATE_PARENT},
++	{ HI3556_MMC1_FAC_CLK, "mmc1_fac", "mmc1_mux", 1, 8,
++		CLK_SET_RATE_PARENT},
++	{ HI3556_MMC2_FAC_CLK, "mmc2_fac", "mmc2_mux", 1, 8,
++		CLK_SET_RATE_PARENT},
++};
++
++static struct hisi_gate_clock hi3556_gate_clks[] __initdata = {
++#ifdef CONFIG_HIFMC
++	/* fmc */
++	{ HI3556_FMC_CLK, "clk_fmc", "fmc_mux",
++		CLK_SET_RATE_PARENT, 0xc0, 1, 0, },
++#endif
++	/* mmc */
++	{ HI3556_MMC0_CLK, "clk_mmc0", "mmc0_fac",
++		CLK_SET_RATE_PARENT, 0xc4, 9, 0, },
++	{ HI3556_MMC1_CLK, "clk_mmc1", "mmc1_fac",
++		CLK_SET_RATE_PARENT, 0xc4, 1, 0, },
++	{ HI3556_MMC2_CLK, "clk_mmc2", "mmc2_fac",
++		CLK_SET_RATE_PARENT, 0xc4, 17, 0, },
++
++	/* usb ctrl */
++	{ HI3556_USB2_CTRL_UTMI0_REQ, "usb2_cttl_utmi0_req", NULL,
++		CLK_SET_RATE_PARENT, 0xb4, 5, 1, },
++	{ HI3556_USB2_HRST_REQ, "usb2_hrst_req", NULL,
++		CLK_SET_RATE_PARENT, 0xb4, 0, 1, },
++	{ HI3556_USB3_CLK, "usb3_vcc_srst_req2", NULL,
++		CLK_SET_RATE_PARENT, 0xb8, 0, 1, },
++	
++	/* uart */
++	{ HI3556_UART0_CLK, "clk_uart0", "24m",
++		CLK_SET_RATE_PARENT, 0xe4, 20, 0, },
++	{ HI3556_UART1_CLK, "clk_uart1", "24m",
++		CLK_SET_RATE_PARENT, 0xe4, 21, 0, },
++	{ HI3556_UART2_CLK, "clk_uart2", "24m",
++		CLK_SET_RATE_PARENT, 0xe4, 22, 0, },
++	{ HI3556_UART3_CLK, "clk_uart3", "24m",
++		CLK_SET_RATE_PARENT, 0xe4, 23, 0, },
++	{ HI3556_UART4_CLK, "clk_uart4", "24m",
++		CLK_SET_RATE_PARENT, 0xe4, 24, 0, },
++
++	/* ethernet mac */
++	{ HI3556_ETH_CLK, "clk_eth", NULL,
++		CLK_IS_ROOT, 0xcc, 1, 0, },
++	{ HI3556_ETH_MACIF_CLK, "clk_eth_macif", NULL,
++		CLK_IS_ROOT, 0xcc, 3, 0, },
++
++	/* spi */
++	{ HI3556_SPI0_CLK, "clk_spi0", "clk_sysapb",
++		CLK_SET_RATE_PARENT, 0xe4, 16, 0, },
++	{ HI3556_SPI1_CLK, "clk_spi1", "clk_sysapb",
++		CLK_SET_RATE_PARENT, 0xe4, 17, 0, },
++	{ HI3556_SPI2_CLK, "clk_spi2", "clk_sysapb",
++		CLK_SET_RATE_PARENT, 0xe4, 18, 0, },
++	{ HI3556_SPI3_CLK, "clk_spi3", "clk_sysapb",
++		CLK_SET_RATE_PARENT, 0xe4, 28, 0, },
++};
++
++static struct hi3556_pll_clock hi3556_pll_clks[] __initdata = {
++	{ HI3556_APLL_CLK, "apll", NULL, 0x0, 0, 24, 24, 3, 28, 3,
++		0x4, 0, 12, 12, 6},
++};
++
++
++#define to_pll_clk(_hw) container_of(_hw, struct hi3556_clk_pll, hw)
++
++static void hi3556_calc_pll(u32 *frac_val,
++		u32 *postdiv1_val,
++		u32 *postdiv2_val,
++		u32 *fbdiv_val,
++		u32 *refdiv_val,
++		unsigned long rate)
++{
++	u64 rem;
++	*frac_val = 0;
++	rem = do_div(rate, 1000000);
++	*fbdiv_val = rate;
++	*refdiv_val = 24;
++	rem = rem * (1 << 24);
++	do_div(rem, 1000000);
++	*frac_val = rem;
++}
++
++static int clk_pll_set_rate(struct clk_hw *hw,
++			unsigned long rate,
++			unsigned long parent_rate)
++{
++	struct hi3556_clk_pll *clk = to_pll_clk(hw);
++	u32 frac_val, postdiv1_val, postdiv2_val, fbdiv_val, refdiv_val;
++	u32 val;
++
++	/*Fixme  ignore postdives now because apll don't use them*/
++	postdiv1_val = postdiv2_val = 0;
++
++	hi3556_calc_pll(&frac_val, &postdiv1_val, &postdiv2_val,
++			&fbdiv_val, &refdiv_val, rate);
++
++	val = readl_relaxed(clk->ctrl_reg1);
++	val &= ~(((1 << clk->frac_width) - 1) << clk->frac_shift);
++	val &= ~(((1 << clk->postdiv1_width) - 1) << clk->postdiv1_shift);
++	val &= ~(((1 << clk->postdiv2_width) - 1) << clk->postdiv2_shift);
++
++	val |= frac_val << clk->frac_shift;
++	val |= postdiv1_val << clk->postdiv1_shift;
++	val |= postdiv2_val << clk->postdiv2_shift;
++	writel_relaxed(val, clk->ctrl_reg1);
++
++	val = readl_relaxed(clk->ctrl_reg2);
++	val &= ~(((1 << clk->fbdiv_width) - 1) << clk->fbdiv_shift);
++	val &= ~(((1 << clk->refdiv_width) - 1) << clk->refdiv_shift);
++
++	val |= fbdiv_val << clk->fbdiv_shift;
++	val |= refdiv_val << clk->refdiv_shift;
++	writel_relaxed(val, clk->ctrl_reg2);
++
++	return 0;
++}
++
++static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
++		unsigned long parent_rate)
++{
++	struct hi3556_clk_pll *clk = to_pll_clk(hw);
++	u64 frac_val, fbdiv_val, refdiv_val;
++	u32 val;
++	u64 tmp, rate;
++
++	val = readl_relaxed(clk->ctrl_reg1);
++	val = val >> clk->frac_shift;
++	val &= ((1 << clk->frac_width) - 1);
++	frac_val = val;
++
++	val = readl_relaxed(clk->ctrl_reg2);
++	val = val >> clk->fbdiv_shift;
++	val &= ((1 << clk->fbdiv_width) - 1);
++	fbdiv_val = val;
++
++	val = readl_relaxed(clk->ctrl_reg2);
++	val = val >> clk->refdiv_shift;
++	val &= ((1 << clk->refdiv_width) - 1);
++	refdiv_val = val;
++
++	/* rate = 24000000 * (fbdiv + frac / (1<<24) ) / refdiv  */
++	rate = 0;
++	tmp = 24000000 * fbdiv_val;
++	rate += tmp;
++	do_div(rate, refdiv_val);
++
++	return rate;
++}
++
++
++static long clk_pll_determine_rate(struct clk_hw *hw, unsigned long rate,
++		unsigned long *best_parent_rate,
++		struct clk **best_parent_p)
++{
++	return rate;
++}
++
++static struct clk_ops clk_pll_ops = {
++	.set_rate = clk_pll_set_rate,
++	.determine_rate = clk_pll_determine_rate,
++	.recalc_rate = clk_pll_recalc_rate,
++};
++
++void __init hi3556_clk_register_pll(struct hi3556_pll_clock *clks,
++		int nums, struct hisi_clock_data *data)
++{
++	void __iomem *base = data->base;
++	int i;
++
++	for (i = 0; i < nums; i++) {
++		struct hi3556_clk_pll *p_clk;
++		struct clk *clk;
++		struct clk_init_data init;
++
++		p_clk = kzalloc(sizeof(*p_clk), GFP_KERNEL);
++		if (!p_clk)
++			return;
++
++		init.name = clks[i].name;
++		init.flags = CLK_IS_BASIC;
++		init.parent_names =
++			(clks[i].parent_name ? &clks[i].parent_name : NULL);
++		init.num_parents = (clks[i].parent_name ? 1 : 0);
++		init.ops = &clk_pll_ops;
++
++		p_clk->ctrl_reg1 = base + clks[i].ctrl_reg1;
++		p_clk->frac_shift = clks[i].frac_shift;
++		p_clk->frac_width = clks[i].frac_width;
++		p_clk->postdiv1_shift = clks[i].postdiv1_shift;
++		p_clk->postdiv1_width = clks[i].postdiv1_width;
++		p_clk->postdiv2_shift = clks[i].postdiv2_shift;
++		p_clk->postdiv2_width = clks[i].postdiv2_width;
++
++		p_clk->ctrl_reg2 = base + clks[i].ctrl_reg2;
++		p_clk->fbdiv_shift = clks[i].fbdiv_shift;
++		p_clk->fbdiv_width = clks[i].fbdiv_width;
++		p_clk->refdiv_shift = clks[i].refdiv_shift;
++		p_clk->refdiv_width = clks[i].refdiv_width;
++		p_clk->hw.init = &init;
++
++		clk = clk_register(NULL, &p_clk->hw);
++		if (IS_ERR(clk)) {
++			kfree(p_clk);
++			pr_err("%s: failed to register clock %s\n",
++					__func__, clks[i].name);
++			continue;
++		}
++
++		data->clk_data.clks[clks[i].id] = clk;
++	}
++
++
++}
++
++static void __init hi3556_clk_init(struct device_node *np)
++{
++	struct hisi_clock_data *clk_data;
++
++	clk_data = hisi_clk_init(np, HI3556_NR_CLKS);
++	if (!clk_data)
++		return;
++	if (IS_ENABLED(CONFIG_RESET_CONTROLLER))
++		hisi_reset_init(np, HI3556_NR_RSTS);
++
++	hisi_clk_register_fixed_rate(hi3556_fixed_rate_clks,
++			ARRAY_SIZE(hi3556_fixed_rate_clks),
++			clk_data);
++	hi3556_clk_register_pll(hi3556_pll_clks,
++			ARRAY_SIZE(hi3556_pll_clks), clk_data);
++
++	hisi_clk_register_mux(hi3556_mux_clks,
++			ARRAY_SIZE(hi3556_mux_clks),
++			clk_data);
++	hisi_clk_register_fixed_factor(hi3556_fixed_factor_clks,
++			ARRAY_SIZE(hi3556_fixed_factor_clks), clk_data);
++	hisi_clk_register_gate(hi3556_gate_clks,
++			ARRAY_SIZE(hi3556_gate_clks), clk_data);
++}
++
++CLK_OF_DECLARE(hi3556_clk, "hisilicon,hi3556-clock", hi3556_clk_init);
+diff --git a/drivers/clk/hisilicon/clk-hi3559.c b/drivers/clk/hisilicon/clk-hi3559.c
+new file mode 100644
+index 0000000..1ae6f6e
+--- /dev/null
++++ b/drivers/clk/hisilicon/clk-hi3559.c
+@@ -0,0 +1,384 @@
++/*
++ * Copyright (c) 2015 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <linux/of_address.h>
++#include <dt-bindings/clock/hi3559-clock.h>
++#include <linux/slab.h>
++#include <linux/delay.h>
++#include <mach/io.h>
++
++#include "clk.h"
++#include "reset.h"
++
++/******************************************************************************/
++struct hi3559_pll_clock {
++	u32		id;
++	const char	*name;
++	const char	*parent_name;
++	u32		ctrl_reg1;
++	u8		frac_shift;
++	u8		frac_width;
++	u8		postdiv1_shift;
++	u8		postdiv1_width;
++	u8		postdiv2_shift;
++	u8		postdiv2_width;
++	u32		ctrl_reg2;
++	u8		fbdiv_shift;
++	u8		fbdiv_width;
++	u8		refdiv_shift;
++	u8		refdiv_width;
++};
++
++struct hi3559_clk_pll {
++	struct clk_hw	hw;
++	u32		id;
++	void __iomem	*ctrl_reg1;
++	u8		frac_shift;
++	u8		frac_width;
++	u8		postdiv1_shift;
++	u8		postdiv1_width;
++	u8		postdiv2_shift;
++	u8		postdiv2_width;
++	void __iomem	*ctrl_reg2;
++	u8		fbdiv_shift;
++	u8		fbdiv_width;
++	u8		refdiv_shift;
++	u8		refdiv_width;
++};
++
++static struct hisi_fixed_rate_clock hi3559_fixed_rate_clks[] __initdata = {
++	{ HI3559_FIXED_2376M, "2376m", NULL, CLK_IS_ROOT, 2376000000UL, },
++	{ HI3559_FIXED_1188M, "1188m", NULL, CLK_IS_ROOT, 1188000000, },
++	{ HI3559_FIXED_594M, "594m", NULL, CLK_IS_ROOT, 594000000, },
++	{ HI3559_FIXED_297M, "297m", NULL, CLK_IS_ROOT, 297000000, },
++	{ HI3559_FIXED_148P5M, "148p5m", NULL, CLK_IS_ROOT, 148500000, },
++	{ HI3559_FIXED_74P25M, "74p25m", NULL, CLK_IS_ROOT, 74250000, },
++	{ HI3559_FIXED_792M, "792m", NULL, CLK_IS_ROOT, 792000000, },
++	{ HI3559_FIXED_475M, "475m", NULL, CLK_IS_ROOT, 475000000, },
++	{ HI3559_FIXED_340M, "340m", NULL, CLK_IS_ROOT, 340000000, },
++	{ HI3559_FIXED_72M, "72m", NULL, CLK_IS_ROOT, 72000000, },
++	{ HI3559_FIXED_400M, "400m", NULL, CLK_IS_ROOT, 400000000, },
++	{ HI3559_FIXED_200M, "200m", NULL, CLK_IS_ROOT, 200000000, },
++	{ HI3559_FIXED_54M, "54m", NULL, CLK_IS_ROOT, 54000000, },
++	{ HI3559_FIXED_27M, "27m", NULL, CLK_IS_ROOT, 1188000000, },
++	{ HI3559_FIXED_37P125M, "37p125m", NULL, CLK_IS_ROOT, 37125000, },
++	{ HI3559_FIXED_3000M, "3000m", NULL, CLK_IS_ROOT, 3000000000UL, },
++	{ HI3559_FIXED_1500M, "1500m", NULL, CLK_IS_ROOT, 1500000000, },
++	{ HI3559_FIXED_500M, "500m", NULL, CLK_IS_ROOT, 500000000, },
++	{ HI3559_FIXED_250M, "250m", NULL, CLK_IS_ROOT, 250000000, },
++	{ HI3559_FIXED_125M, "125m", NULL, CLK_IS_ROOT, 125000000, },
++	{ HI3559_FIXED_1000M, "1000m", NULL, CLK_IS_ROOT, 1000000000, },
++	{ HI3559_FIXED_600M, "600m", NULL, CLK_IS_ROOT, 600000000, },
++	{ HI3559_FIXED_750M, "750m", NULL, CLK_IS_ROOT, 750000000, },
++	{ HI3559_FIXED_150M, "150m", NULL, CLK_IS_ROOT, 150000000, },
++	{ HI3559_FIXED_75M, "75m", NULL, CLK_IS_ROOT, 75000000, },
++	{ HI3559_FIXED_300M, "300m", NULL, CLK_IS_ROOT, 300000000, },
++	{ HI3559_FIXED_60M, "60m", NULL, CLK_IS_ROOT, 60000000, },
++	{ HI3559_FIXED_214M, "214m", NULL, CLK_IS_ROOT, 214000000, },
++	{ HI3559_FIXED_107M, "107m", NULL, CLK_IS_ROOT, 107000000, },
++	{ HI3559_FIXED_100M, "100m", NULL, CLK_IS_ROOT, 100000000, },
++	{ HI3559_FIXED_50M, "50m", NULL, CLK_IS_ROOT, 50000000, },
++	{ HI3559_FIXED_25M, "25m", NULL, CLK_IS_ROOT, 25000000, },
++	{ HI3559_FIXED_24M, "24m", NULL, CLK_IS_ROOT, 24000000, },
++	{ HI3559_FIXED_3M, "3m", NULL, CLK_IS_ROOT, 3000000, },
++	{ HI3559_FIXED_198M, "198m", NULL, CLK_IS_ROOT, 198000000, },
++	{ HI3559_FIXED_396M, "396m", NULL, CLK_IS_ROOT, 396000000, },
++};
++
++static const char *sysaxi_mux_p[] __initconst = {"24m", "198m", };
++static u32 sysaxi_mux_table[] = {0, 1};
++
++static const char *fmc_mux_p[] __initconst = {
++	"24m", "75m", "125m", "150m", "198m", "250m", "300m", "396m", };
++static u32 fmc_mux_table[] = {0, 1, 2, 3, 4, 5, 6, 7};
++
++static const char *mmc_mux_p[] __initconst = {
++	"100m", "198m", "396m", "594m", "792m", "1188m", };
++static u32 mmc_mux_table[] = {0, 1, 3, 4, 5, 7};
++
++static const char *a17_mux_p[] __initconst = {
++	"24m", "apll", "594m", "792m", };
++static u32 a17_mux_table[] = {0, 1, 3, 4};
++
++static const char *i2c_mux_p[] __initconst = {"clk_sysapb", "50m"};
++static u32 i2c_mux_table[] = {0, 1};
++
++static struct hisi_mux_clock hi3559_mux_clks[] __initdata = {
++	{ HI3559_SYSAXI_MUX, "sysaxi_mux", sysaxi_mux_p,
++		ARRAY_SIZE(sysaxi_mux_p),
++		CLK_SET_RATE_PARENT, 0x34, 12, 2, 0, sysaxi_mux_table, },
++	{ HI3559_FMC_MUX, "fmc_mux", fmc_mux_p, ARRAY_SIZE(fmc_mux_p),
++		CLK_SET_RATE_PARENT, 0xc0, 2, 3, 0, fmc_mux_table, },
++	{ HI3559_MMC0_MUX, "mmc0_mux", mmc_mux_p, ARRAY_SIZE(mmc_mux_p),
++		CLK_SET_RATE_PARENT, 0xc4, 10, 3, 0, mmc_mux_table, },
++	{ HI3559_MMC1_MUX, "mmc1_mux", mmc_mux_p, ARRAY_SIZE(mmc_mux_p),
++		CLK_SET_RATE_PARENT, 0xc4, 2, 3, 0, mmc_mux_table, },
++	{ HI3559_MMC2_MUX, "mmc2_mux", mmc_mux_p, ARRAY_SIZE(mmc_mux_p),
++		CLK_SET_RATE_PARENT, 0xc4, 18, 3, 0, mmc_mux_table, },
++	{ HI3559_A17_MUX, "a17_mux", a17_mux_p, ARRAY_SIZE(a17_mux_p),
++		CLK_SET_RATE_PARENT, 0x34, 4, 3, 0, a17_mux_table, },
++	{ HI3559_I2C_MUX, "i2c_mux", i2c_mux_p, ARRAY_SIZE(i2c_mux_p),
++		CLK_SET_RATE_PARENT, 0xe4, 26, 1, 0, i2c_mux_table, },
++
++};
++
++static struct hisi_fixed_factor_clock
++	hi3559_fixed_factor_clks[] __initdata = {
++	{ HI3559_SYSAPB_CLK, "clk_sysapb", "sysaxi_mux", 1, 4,
++		CLK_SET_RATE_PARENT},
++	{ HI3559_MMC0_FAC_CLK, "mmc0_fac", "mmc0_mux", 1, 8,
++		CLK_SET_RATE_PARENT},
++	{ HI3559_MMC1_FAC_CLK, "mmc1_fac", "mmc1_mux", 1, 8,
++		CLK_SET_RATE_PARENT},
++	{ HI3559_MMC2_FAC_CLK, "mmc2_fac", "mmc2_mux", 1, 8,
++		CLK_SET_RATE_PARENT},
++};
++
++static struct hisi_gate_clock hi3559_gate_clks[] __initdata = {
++#ifdef CONFIG_HIFMC
++	/* fmc */
++	{ HI3559_FMC_CLK, "clk_fmc", "fmc_mux",
++		CLK_SET_RATE_PARENT, 0xc0, 1, 0, },
++#endif
++	/* mmc */
++	{ HI3559_MMC0_CLK, "clk_mmc0", "mmc0_fac",
++		CLK_SET_RATE_PARENT, 0xc4, 9, 0, },
++	{ HI3559_MMC1_CLK, "clk_mmc1", "mmc1_fac",
++		CLK_SET_RATE_PARENT, 0xc4, 1, 0, },
++	{ HI3559_MMC2_CLK, "clk_mmc2", "mmc2_fac",
++		CLK_SET_RATE_PARENT, 0xc4, 17, 0, },
++
++	/* usb ctrl */
++	{ HI3559_USB2_CTRL_UTMI0_REQ, "usb2_cttl_utmi0_req", NULL,
++		CLK_SET_RATE_PARENT, 0xb4, 5, 1, },
++	{ HI3559_USB2_HRST_REQ, "usb2_hrst_req", NULL,
++		CLK_SET_RATE_PARENT, 0xb4, 0, 1, },
++	{ HI3559_USB3_CLK, "usb3_vcc_srst_req2", NULL,
++		CLK_SET_RATE_PARENT, 0xb8, 0, 1, },
++	
++	/* uart */
++	{ HI3559_UART0_CLK, "clk_uart0", "24m",
++		CLK_SET_RATE_PARENT, 0xe4, 20, 0, },
++	{ HI3559_UART1_CLK, "clk_uart1", "24m",
++		CLK_SET_RATE_PARENT, 0xe4, 21, 0, },
++	{ HI3559_UART2_CLK, "clk_uart2", "24m",
++		CLK_SET_RATE_PARENT, 0xe4, 22, 0, },
++	{ HI3559_UART3_CLK, "clk_uart3", "24m",
++		CLK_SET_RATE_PARENT, 0xe4, 23, 0, },
++	{ HI3559_UART4_CLK, "clk_uart4", "24m",
++		CLK_SET_RATE_PARENT, 0xe4, 24, 0, },
++
++	/* ethernet mac */
++	{ HI3559_ETH_CLK, "clk_eth", NULL,
++		CLK_IS_ROOT, 0xcc, 1, 0, },
++	{ HI3559_ETH_MACIF_CLK, "clk_eth_macif", NULL,
++		CLK_IS_ROOT, 0xcc, 3, 0, },
++
++	/* spi */
++	{ HI3559_SPI0_CLK, "clk_spi0", "clk_sysapb",
++		CLK_SET_RATE_PARENT, 0xe4, 16, 0, },
++	{ HI3559_SPI1_CLK, "clk_spi1", "clk_sysapb",
++		CLK_SET_RATE_PARENT, 0xe4, 17, 0, },
++	{ HI3559_SPI2_CLK, "clk_spi2", "clk_sysapb",
++		CLK_SET_RATE_PARENT, 0xe4, 18, 0, },
++	{ HI3559_SPI3_CLK, "clk_spi3", "clk_sysapb",
++		CLK_SET_RATE_PARENT, 0xe4, 28, 0, },
++};
++
++static struct hi3559_pll_clock hi3559_pll_clks[] __initdata = {
++	{ HI3559_APLL_CLK, "apll", NULL, 0x0, 0, 24, 24, 3, 28, 3,
++		0x4, 0, 12, 12, 6},
++};
++
++
++#define to_pll_clk(_hw) container_of(_hw, struct hi3559_clk_pll, hw)
++
++static void hi3559_calc_pll(u32 *frac_val,
++		u32 *postdiv1_val,
++		u32 *postdiv2_val,
++		u32 *fbdiv_val,
++		u32 *refdiv_val,
++		unsigned long rate)
++{
++	u64 rem;
++	*frac_val = 0;
++	rem = do_div(rate, 1000000);
++	*fbdiv_val = rate;
++	*refdiv_val = 24;
++	rem = rem * (1 << 24);
++	do_div(rem, 1000000);
++	*frac_val = rem;
++}
++
++static int clk_pll_set_rate(struct clk_hw *hw,
++			unsigned long rate,
++			unsigned long parent_rate)
++{
++	struct hi3559_clk_pll *clk = to_pll_clk(hw);
++	u32 frac_val, postdiv1_val, postdiv2_val, fbdiv_val, refdiv_val;
++	u32 val;
++
++	/*Fixme  ignore postdives now because apll don't use them*/
++	postdiv1_val = postdiv2_val = 0;
++
++	hi3559_calc_pll(&frac_val, &postdiv1_val, &postdiv2_val,
++			&fbdiv_val, &refdiv_val, rate);
++
++	val = readl_relaxed(clk->ctrl_reg1);
++	val &= ~(((1 << clk->frac_width) - 1) << clk->frac_shift);
++	val &= ~(((1 << clk->postdiv1_width) - 1) << clk->postdiv1_shift);
++	val &= ~(((1 << clk->postdiv2_width) - 1) << clk->postdiv2_shift);
++
++	val |= frac_val << clk->frac_shift;
++	val |= postdiv1_val << clk->postdiv1_shift;
++	val |= postdiv2_val << clk->postdiv2_shift;
++	writel_relaxed(val, clk->ctrl_reg1);
++
++	val = readl_relaxed(clk->ctrl_reg2);
++	val &= ~(((1 << clk->fbdiv_width) - 1) << clk->fbdiv_shift);
++	val &= ~(((1 << clk->refdiv_width) - 1) << clk->refdiv_shift);
++
++	val |= fbdiv_val << clk->fbdiv_shift;
++	val |= refdiv_val << clk->refdiv_shift;
++	writel_relaxed(val, clk->ctrl_reg2);
++
++	return 0;
++}
++
++static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
++		unsigned long parent_rate)
++{
++	struct hi3559_clk_pll *clk = to_pll_clk(hw);
++	u64 frac_val, fbdiv_val, refdiv_val;
++	u32 val;
++	u64 tmp, rate;
++
++	val = readl_relaxed(clk->ctrl_reg1);
++	val = val >> clk->frac_shift;
++	val &= ((1 << clk->frac_width) - 1);
++	frac_val = val;
++
++	val = readl_relaxed(clk->ctrl_reg2);
++	val = val >> clk->fbdiv_shift;
++	val &= ((1 << clk->fbdiv_width) - 1);
++	fbdiv_val = val;
++
++	val = readl_relaxed(clk->ctrl_reg2);
++	val = val >> clk->refdiv_shift;
++	val &= ((1 << clk->refdiv_width) - 1);
++	refdiv_val = val;
++
++	/* rate = 24000000 * (fbdiv + frac / (1<<24) ) / refdiv  */
++	rate = 0;
++	tmp = 24000000 * fbdiv_val;
++	rate += tmp;
++	do_div(rate, refdiv_val);
++
++	return rate;
++}
++
++
++static long clk_pll_determine_rate(struct clk_hw *hw, unsigned long rate,
++		unsigned long *best_parent_rate,
++		struct clk **best_parent_p)
++{
++	return rate;
++}
++
++static struct clk_ops clk_pll_ops = {
++	.set_rate = clk_pll_set_rate,
++	.determine_rate = clk_pll_determine_rate,
++	.recalc_rate = clk_pll_recalc_rate,
++};
++
++void __init hi3559_clk_register_pll(struct hi3559_pll_clock *clks,
++		int nums, struct hisi_clock_data *data)
++{
++	void __iomem *base = data->base;
++	int i;
++
++	for (i = 0; i < nums; i++) {
++		struct hi3559_clk_pll *p_clk;
++		struct clk *clk;
++		struct clk_init_data init;
++
++		p_clk = kzalloc(sizeof(*p_clk), GFP_KERNEL);
++		if (!p_clk)
++			return;
++
++		init.name = clks[i].name;
++		init.flags = CLK_IS_BASIC;
++		init.parent_names =
++			(clks[i].parent_name ? &clks[i].parent_name : NULL);
++		init.num_parents = (clks[i].parent_name ? 1 : 0);
++		init.ops = &clk_pll_ops;
++
++		p_clk->ctrl_reg1 = base + clks[i].ctrl_reg1;
++		p_clk->frac_shift = clks[i].frac_shift;
++		p_clk->frac_width = clks[i].frac_width;
++		p_clk->postdiv1_shift = clks[i].postdiv1_shift;
++		p_clk->postdiv1_width = clks[i].postdiv1_width;
++		p_clk->postdiv2_shift = clks[i].postdiv2_shift;
++		p_clk->postdiv2_width = clks[i].postdiv2_width;
++
++		p_clk->ctrl_reg2 = base + clks[i].ctrl_reg2;
++		p_clk->fbdiv_shift = clks[i].fbdiv_shift;
++		p_clk->fbdiv_width = clks[i].fbdiv_width;
++		p_clk->refdiv_shift = clks[i].refdiv_shift;
++		p_clk->refdiv_width = clks[i].refdiv_width;
++		p_clk->hw.init = &init;
++
++		clk = clk_register(NULL, &p_clk->hw);
++		if (IS_ERR(clk)) {
++			kfree(p_clk);
++			pr_err("%s: failed to register clock %s\n",
++					__func__, clks[i].name);
++			continue;
++		}
++
++		data->clk_data.clks[clks[i].id] = clk;
++	}
++
++
++}
++
++static void __init hi3559_clk_init(struct device_node *np)
++{
++	struct hisi_clock_data *clk_data;
++
++	clk_data = hisi_clk_init(np, HI3559_NR_CLKS);
++	if (!clk_data)
++		return;
++	if (IS_ENABLED(CONFIG_RESET_CONTROLLER))
++		hisi_reset_init(np, HI3559_NR_RSTS);
++
++	hisi_clk_register_fixed_rate(hi3559_fixed_rate_clks,
++			ARRAY_SIZE(hi3559_fixed_rate_clks),
++			clk_data);
++	hi3559_clk_register_pll(hi3559_pll_clks,
++			ARRAY_SIZE(hi3559_pll_clks), clk_data);
++
++	hisi_clk_register_mux(hi3559_mux_clks,
++			ARRAY_SIZE(hi3559_mux_clks),
++			clk_data);
++	hisi_clk_register_fixed_factor(hi3559_fixed_factor_clks,
++			ARRAY_SIZE(hi3559_fixed_factor_clks), clk_data);
++	hisi_clk_register_gate(hi3559_gate_clks,
++			ARRAY_SIZE(hi3559_gate_clks), clk_data);
++}
++
++CLK_OF_DECLARE(hi3559_clk, "hisilicon,hi3559-clock", hi3559_clk_init);
+diff --git a/drivers/clk/hisilicon/clk.c b/drivers/clk/hisilicon/clk.c
+index a078e84..870a505 100644
+--- a/drivers/clk/hisilicon/clk.c
++++ b/drivers/clk/hisilicon/clk.c
+@@ -232,3 +232,25 @@ void __init hisi_clk_register_gate_sep(struct hisi_gate_clock *clks,
+ 		data->clk_data.clks[clks[i].id] = clk;
+ 	}
+ }
++
++void __init hisi_clk_register_ops(struct hiclk_hw *clks,
++				       int nums, struct hisi_clock_data *data)
++{
++	struct clk *clk;
++	int i;
++
++	for (i = 0; i < nums; i++) {
++		struct hiclk_hw *hihw = &clks[i];
++
++		clk = clk_register_ops_table(NULL, hihw, NULL);
++		if (IS_ERR(clk)) {
++			pr_err("%s: failed to register clock %s\n",
++			       __func__, clks[i].name);
++			continue;
++		}
++
++		clk_register_clkdev(clk, clks[i].name, NULL);
++
++		data->clk_data.clks[clks[i].id] = clk;
++	}
++}
+diff --git a/drivers/clk/hisilicon/clk.h b/drivers/clk/hisilicon/clk.h
+index 31083ff..46e7417 100644
+--- a/drivers/clk/hisilicon/clk.h
++++ b/drivers/clk/hisilicon/clk.h
+@@ -30,6 +30,50 @@
+ #include <linux/io.h>
+ #include <linux/spinlock.h>
+ 
++#define CLK(_id, _mask, _value, _rstbit, _rate, _ops) \
++{.id = _id,         \
++	.name = #_id,      \
++	.offset = _id,     \
++	.mask = _mask,     \
++	.value = _value,   \
++	.rstbit = _rstbit, \
++	.rate = _rate,     \
++	.ops = _ops,}
++
++#define CLK_SHARED(_id, _off, _mask, _value, _rstbit, _rate, _ops) \
++{.id = _id,         \
++	.name = #_id,      \
++	.offset = _off,     \
++	.mask = _mask,     \
++	.value = _value,   \
++	.rstbit = _rstbit, \
++	.rate = _rate,     \
++	.ops = _ops,}
++
++struct hiclk_hw {
++	int id;
++	const char *name;
++	u32 offset;
++	u32 mask;
++	u32 value;
++	u32 rstbit;
++
++	unsigned long rate;
++	struct clk_ops *ops;
++	struct clk_hw hw;
++
++#define CLKHW_RESET         (0x01)
++#define CLKHW_ENABLE        (0x02)
++
++	u32 flags;
++};
++
++extern struct clk_ops clk_ops_hiusb2_host;
++extern struct clk_ops clk_ops_hiusb3;
++extern struct clk_ops clk_ops_himci;
++
++#define to_hiclk_hw(_hw) container_of(_hw, struct hiclk_hw, hw)
++
+ struct hisi_clock_data {
+ 	struct clk_onecell_data	clk_data;
+ 	void __iomem		*base;
+@@ -96,6 +140,9 @@ struct clk *hisi_register_clkgate_sep(struct device *, const char *,
+ 				u8, spinlock_t *);
+ 
+ struct hisi_clock_data __init *hisi_clk_init(struct device_node *, int);
++struct clk *clk_register_ops_table(struct device *,
++		struct hiclk_hw *,
++		struct clk_ops *);
+ void __init hisi_clk_register_fixed_rate(struct hisi_fixed_rate_clock *,
+ 					int, struct hisi_clock_data *);
+ void __init hisi_clk_register_fixed_factor(struct hisi_fixed_factor_clock *,
+@@ -108,4 +155,6 @@ void __init hisi_clk_register_gate(struct hisi_gate_clock *,
+ 					int, struct hisi_clock_data *);
+ void __init hisi_clk_register_gate_sep(struct hisi_gate_clock *,
+ 					int, struct hisi_clock_data *);
++void __init hisi_clk_register_ops(struct hiclk_hw *,
++					int, struct hisi_clock_data *);
+ #endif	/* __HISI_CLK_H */
+diff --git a/drivers/clk/hisilicon/clk_ops.c b/drivers/clk/hisilicon/clk_ops.c
+new file mode 100644
+index 0000000..268c232
+--- /dev/null
++++ b/drivers/clk/hisilicon/clk_ops.c
+@@ -0,0 +1,53 @@
++/*
++ * Hisilicon clock separated gate driver
++ *
++ * Copyright (c) 2012-2013 Hisilicon Limited.
++ * Copyright (c) 2012-2013 Linaro Limited.
++ *
++ * Author: Haojian Zhuang <haojian.zhuang@linaro.org>
++ *	   Xin Li <li.xin@linaro.org>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/clk-provider.h>
++#include <linux/clkdev.h>
++#include <linux/io.h>
++#include <linux/slab.h>
++#include <linux/clk.h>
++
++#include "clk.h"
++
++struct clk *clk_register_ops_table(struct device *dev,
++					struct hiclk_hw *hihw,
++					struct clk_ops *clkops)
++{
++	struct clk *clk;
++	struct clk_init_data init;
++
++	init.name = hihw->name;
++	init.flags = CLK_IS_ROOT | CLK_IS_BASIC;
++	init.parent_names = NULL;
++	init.num_parents = 0;
++	init.ops = hihw->ops;
++
++	hihw->hw.init = &init;
++
++	clk = clk_register(dev, &hihw->hw);
++	if (IS_ERR(clk)) {
++		pr_err("%s: register clock fail.\n", __func__);
++		return NULL;
++	}
++
++	return clk;
++}
+diff --git a/drivers/clk/hisilicon/reset.c b/drivers/clk/hisilicon/reset.c
+new file mode 100644
+index 0000000..85b4ae7
+--- /dev/null
++++ b/drivers/clk/hisilicon/reset.c
+@@ -0,0 +1,147 @@
++/*
++ * Hisilicon Reset Controller driver
++ *
++ * Copyright (c) 2015 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <linux/err.h>
++#include <linux/io.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/of_address.h>
++#include <linux/of_platform.h>
++#include <linux/platform_device.h>
++#include <linux/reset-controller.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/types.h>
++
++#define	HISI_RESET_BIT_SHIFT	0
++#define	HISI_RESET_BIT_WIDTH	16
++#define	HISI_RESET_OFFSET_SHIFT	16
++#define	HISI_RESET_OFFSET_WIDTH	16
++
++struct hisi_reset_controller {
++	spinlock_t					lock;
++	void __iomem				*membase;
++	struct reset_controller_dev	rcdev;
++};
++
++
++#define to_hisi_reset_controller(rcdev)  \
++	container_of(rcdev, struct hisi_reset_controller, rcdev)
++
++/*31                        16                         0
++   |---reset_spec->args[0]---|---reset_spec->args[1]---|
++   |-------reg_offset--------|--------reg_bit----------|*/
++static int hisi_reset_of_xlate(struct reset_controller_dev *rcdev,
++			const struct of_phandle_args *reset_spec)
++{
++	unsigned int offset, bit, id;
++	__be32 *addr;
++	u64 size;
++
++	if (WARN_ON(reset_spec->args_count != rcdev->of_reset_n_cells))
++		return -EINVAL;
++
++	addr = (__be32 *)of_get_address(rcdev->of_node, 0, &size, NULL);
++	if (!addr)
++		return -EINVAL;
++
++	if (reset_spec->args[1] >= 32
++		|| reset_spec->args[0] + reset_spec->args[1] / 8 > size)
++		return -EINVAL;
++
++	offset = reset_spec->args[0] & (BIT(HISI_RESET_OFFSET_WIDTH) - 1);
++	bit = (reset_spec->args[1] & (BIT(HISI_RESET_BIT_WIDTH) - 1));
++	id = offset << HISI_RESET_OFFSET_SHIFT | bit;
++
++	return id;
++}
++
++static int hisi_reset_assert(struct reset_controller_dev *rcdev,
++			      unsigned long id)
++{
++	struct hisi_reset_controller *rstc = to_hisi_reset_controller(rcdev);
++	unsigned int offset, bit;
++	unsigned long flags;
++	u32 reg;
++
++	offset = id >> HISI_RESET_OFFSET_SHIFT;
++	offset &= (BIT(HISI_RESET_OFFSET_WIDTH) - 1);
++	bit = id & (BIT(HISI_RESET_BIT_WIDTH) - 1);
++
++	spin_lock_irqsave(&rstc->lock, flags);
++
++	reg = readl(rstc->membase + offset);
++	writel(reg | BIT(bit), rstc->membase + offset);
++
++	spin_unlock_irqrestore(&rstc->lock, flags);
++
++	return 0;
++}
++
++static int hisi_reset_deassert(struct reset_controller_dev *rcdev,
++				unsigned long id)
++{
++	struct hisi_reset_controller *rstc = to_hisi_reset_controller(rcdev);
++	unsigned int offset, bit;
++	unsigned long flags;
++	u32 reg;
++
++	offset = id >> HISI_RESET_OFFSET_SHIFT;
++	offset &= (BIT(HISI_RESET_OFFSET_WIDTH) - 1);
++	bit = id & (BIT(HISI_RESET_BIT_WIDTH) - 1);
++
++	spin_lock_irqsave(&rstc->lock, flags);
++
++	reg = readl(rstc->membase + offset);
++	writel(reg & ~BIT(bit), rstc->membase + offset);
++
++	spin_unlock_irqrestore(&rstc->lock, flags);
++
++	return 0;
++}
++
++static struct reset_control_ops hisi_reset_ops = {
++	.assert		= hisi_reset_assert,
++	.deassert	= hisi_reset_deassert,
++};
++
++int __init hisi_reset_init(struct device_node *np,
++					     int nr_rsts)
++{
++	struct hisi_reset_controller *rstc;
++
++	rstc = kzalloc(sizeof(*rstc), GFP_KERNEL);
++	if (!rstc)
++		return -ENOMEM;
++
++	rstc->membase = of_iomap(np, 0);
++	if (!rstc->membase)
++		return -EINVAL;
++
++	spin_lock_init(&rstc->lock);
++
++	rstc->rcdev.owner = THIS_MODULE;
++	rstc->rcdev.nr_resets = nr_rsts;
++	rstc->rcdev.ops = &hisi_reset_ops;
++	rstc->rcdev.of_node = np;
++	rstc->rcdev.of_reset_n_cells = 2;
++	rstc->rcdev.of_xlate = hisi_reset_of_xlate;
++
++	return reset_controller_register(&rstc->rcdev);
++}
+diff --git a/drivers/clk/hisilicon/reset.h b/drivers/clk/hisilicon/reset.h
+new file mode 100644
+index 0000000..74bea4e
+--- /dev/null
++++ b/drivers/clk/hisilicon/reset.h
+@@ -0,0 +1,25 @@
++/*
++ * Copyright (c) 2015 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef	__HISI_RESET_H
++#define	__HISI_RESET_H
++
++#include <linux/of.h>
++
++int __init hisi_reset_init(struct device_node *np, int nr_rsts);
++
++#endif	/* __HISI_RESET_H */
+diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
+index 9042060..497b2f5 100644
+--- a/drivers/clocksource/Kconfig
++++ b/drivers/clocksource/Kconfig
+@@ -110,6 +110,14 @@ config ARM_ARCH_TIMER_EVTSTREAM
+ 	  This must be disabled for hardware validation purposes to detect any
+ 	  hardware anomalies of missing events.
+ 
++config ARM_ARCH_TIMER_VCT_ACCESS
++	bool "Support for ARM architected timer virtual counter access in userspace"
++	default n
++	depends on ARM_ARCH_TIMER
++	help
++	  This option enables support for reading the ARM architected timer's
++	  virtual counter in userspace.
++
+ config ARM_GLOBAL_TIMER
+ 	bool
+ 	select CLKSRC_OF if OF
+diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
+index 84b4c8b..fdf3959 100644
+--- a/drivers/clocksource/arm_arch_timer.c
++++ b/drivers/clocksource/arm_arch_timer.c
+@@ -339,7 +339,10 @@ static void arch_counter_set_user_access(void)
+ 			| ARCH_TIMER_USR_PCT_ACCESS_EN);
+ 
+ 	/* Enable user access to the virtual counter */
+-	cntkctl |= ARCH_TIMER_USR_VCT_ACCESS_EN;
++	if (IS_ENABLED(CONFIG_ARM_ARCH_TIMER_VCT_ACCESS))
++		cntkctl |= ARCH_TIMER_USR_VCT_ACCESS_EN;
++	else
++		cntkctl &= ~ARCH_TIMER_USR_VCT_ACCESS_EN;
+ 
+ 	arch_timer_set_cntkctl(cntkctl);
+ }
+diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
+index 3489f8f..548311f 100644
+--- a/drivers/cpufreq/Kconfig
++++ b/drivers/cpufreq/Kconfig
+@@ -102,6 +102,16 @@ config CPU_FREQ_DEFAULT_GOV_CONSERVATIVE
+ 	  Be aware that not all cpufreq drivers support the conservative
+ 	  governor. If unsure have a look at the help section of the
+ 	  driver. Fallback governor will be the performance governor.
++
++config CPU_FREQ_DEFAULT_GOV_INTERACTIVE
++	bool "interactive"
++	select CPU_FREQ_GOV_INTERACTIVE
++	help
++	  Use the CPUFreq governor 'interactive' as default. This allows
++	  you to get a full dynamic cpu frequency capable system by simply
++	  loading your cpufreq low-level hardware driver, using the
++	  'interactive' governor for latency-sensitive workloads.
++
+ endchoice
+ 
+ config CPU_FREQ_GOV_PERFORMANCE
+@@ -159,6 +169,23 @@ config CPU_FREQ_GOV_ONDEMAND
+ 
+ 	  If in doubt, say N.
+ 
++config CPU_FREQ_GOV_INTERACTIVE
++	tristate "'interactive' cpufreq policy governor"
++	help
++	  'interactive' - This driver adds a dynamic cpufreq policy governor
++	  designed for latency-sensitive workloads.
++
++	  This governor attempts to reduce the latency of clock
++	  increases so that the system is more responsive to
++	  interactive workloads.
++
++	  To compile this driver as a module, choose M here: the
++	  module will be called cpufreq_interactive.
++
++	  For details, take a look at linux/Documentation/cpu-freq.
++
++	  If in doubt, say N.
++
+ config CPU_FREQ_GOV_CONSERVATIVE
+ 	tristate "'conservative' cpufreq governor"
+ 	depends on CPU_FREQ
+diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
+index 83a75dc..28c9b5f 100644
+--- a/drivers/cpufreq/Kconfig.arm
++++ b/drivers/cpufreq/Kconfig.arm
+@@ -247,3 +247,4 @@ config ARM_TEGRA_CPUFREQ
+ 	default y
+ 	help
+ 	  This adds the CPUFreq driver support for TEGRA SOCs.
++
+diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
+index 40c53dc..b89b1f7 100644
+--- a/drivers/cpufreq/Makefile
++++ b/drivers/cpufreq/Makefile
+@@ -11,6 +11,7 @@ obj-$(CONFIG_CPU_FREQ_GOV_POWERSAVE)	+= cpufreq_powersave.o
+ obj-$(CONFIG_CPU_FREQ_GOV_USERSPACE)	+= cpufreq_userspace.o
+ obj-$(CONFIG_CPU_FREQ_GOV_ONDEMAND)	+= cpufreq_ondemand.o
+ obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE)	+= cpufreq_conservative.o
++obj-$(CONFIG_CPU_FREQ_GOV_INTERACTIVE)	+= cpufreq_interactive.o
+ obj-$(CONFIG_CPU_FREQ_GOV_COMMON)		+= cpufreq_governor.o
+ 
+ obj-$(CONFIG_CPUFREQ_DT)		+= cpufreq-dt.o
+diff --git a/drivers/cpufreq/cpufreq_interactive.c b/drivers/cpufreq/cpufreq_interactive.c
+new file mode 100644
+index 0000000..e569e0b
+--- /dev/null
++++ b/drivers/cpufreq/cpufreq_interactive.c
+@@ -0,0 +1,1338 @@
++/*
++ * drivers/cpufreq/cpufreq_interactive.c
++ *
++ * Copyright (C) 2010 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * 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.
++ *
++ * Author: Mike Chan (mike@android.com)
++ *
++ */
++
++#include <linux/cpu.h>
++#include <linux/cpumask.h>
++#include <linux/cpufreq.h>
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/rwsem.h>
++#include <linux/sched.h>
++#include <linux/sched/rt.h>
++#include <linux/tick.h>
++#include <linux/time.h>
++#include <linux/timer.h>
++#include <linux/workqueue.h>
++#include <linux/kthread.h>
++#include <linux/slab.h>
++
++#define CREATE_TRACE_POINTS
++#include <trace/events/cpufreq_interactive.h>
++
++struct cpufreq_interactive_cpuinfo {
++	struct timer_list cpu_timer;
++	struct timer_list cpu_slack_timer;
++	spinlock_t load_lock; /* protects the next 4 fields */
++	u64 time_in_idle;
++	u64 time_in_idle_timestamp;
++	u64 cputime_speedadj;
++	u64 cputime_speedadj_timestamp;
++	struct cpufreq_policy *policy;
++	struct cpufreq_frequency_table *freq_table;
++	spinlock_t target_freq_lock; /*protects target freq */
++	unsigned int target_freq;
++	unsigned int floor_freq;
++	u64 pol_floor_val_time; /* policy floor_validate_time */
++	u64 loc_floor_val_time; /* per-cpu floor_validate_time */
++	u64 pol_hispeed_val_time; /* policy hispeed_validate_time */
++	u64 loc_hispeed_val_time; /* per-cpu hispeed_validate_time */
++	struct rw_semaphore enable_sem;
++	int governor_enabled;
++};
++
++static DEFINE_PER_CPU(struct cpufreq_interactive_cpuinfo, cpuinfo);
++
++/* realtime thread handles frequency scaling */
++static struct task_struct *speedchange_task;
++static cpumask_t speedchange_cpumask;
++static spinlock_t speedchange_cpumask_lock;
++static struct mutex gov_lock;
++
++/* Target load.  Lower values result in higher CPU speeds. */
++#define DEFAULT_TARGET_LOAD 90
++static unsigned int default_target_loads[] = {DEFAULT_TARGET_LOAD};
++
++#define DEFAULT_TIMER_RATE (20 * USEC_PER_MSEC)
++#define DEFAULT_ABOVE_HISPEED_DELAY DEFAULT_TIMER_RATE
++static unsigned int default_above_hispeed_delay[] = {
++	DEFAULT_ABOVE_HISPEED_DELAY };
++
++struct cpufreq_interactive_tunables {
++	int usage_count;
++	/* Hi speed to bump to from lo speed when load burst (default max) */
++	unsigned int hispeed_freq;
++	/* Go to hi speed when CPU load at or above this value. */
++#define DEFAULT_GO_HISPEED_LOAD 99
++	unsigned long go_hispeed_load;
++	/* Target load. Lower values result in higher CPU speeds. */
++	spinlock_t target_loads_lock;
++	unsigned int *target_loads;
++	int ntarget_loads;
++	/*
++	 * The minimum amount of time to spend at a frequency before we can ramp
++	 * down.
++	 */
++#define DEFAULT_MIN_SAMPLE_TIME (80 * USEC_PER_MSEC)
++	unsigned long min_sample_time;
++	/*
++	 * The sample rate of the timer used to increase frequency
++	 */
++	unsigned long timer_rate;
++	/*
++	 * Wait this long before raising speed above hispeed, by default a
++	 * single timer interval.
++	 */
++	spinlock_t above_hispeed_delay_lock;
++	unsigned int *above_hispeed_delay;
++	int nabove_hispeed_delay;
++	/* Non-zero means indefinite speed boost active */
++	int boost_val;
++	/* Duration of a boot pulse in usecs */
++	int boostpulse_duration_val;
++	/* End time of boost pulse in ktime converted to usecs */
++	u64 boostpulse_endtime;
++	bool boosted;
++	/*
++	 * Max additional time to wait in idle, beyond timer_rate, at speeds
++	 * above minimum before wakeup to reduce speed, or -1 if unnecessary.
++	 */
++#define DEFAULT_TIMER_SLACK (4 * DEFAULT_TIMER_RATE)
++	int timer_slack_val;
++	bool io_is_busy;
++};
++
++/* For cases where we have single governor instance for system */
++static struct cpufreq_interactive_tunables *common_tunables;
++
++static struct attribute_group *get_sysfs_attr(void);
++
++static void cpufreq_interactive_timer_resched(
++	struct cpufreq_interactive_cpuinfo *pcpu)
++{
++	struct cpufreq_interactive_tunables *tunables =
++		pcpu->policy->governor_data;
++	unsigned long expires;
++	unsigned long flags;
++
++	spin_lock_irqsave(&pcpu->load_lock, flags);
++	pcpu->time_in_idle =
++		get_cpu_idle_time(smp_processor_id(),
++				  &pcpu->time_in_idle_timestamp,
++				  tunables->io_is_busy);
++	pcpu->cputime_speedadj = 0;
++	pcpu->cputime_speedadj_timestamp = pcpu->time_in_idle_timestamp;
++	expires = jiffies + usecs_to_jiffies(tunables->timer_rate);
++	mod_timer_pinned(&pcpu->cpu_timer, expires);
++
++	if (tunables->timer_slack_val >= 0 &&
++	    pcpu->target_freq > pcpu->policy->min) {
++		expires += usecs_to_jiffies(tunables->timer_slack_val);
++		mod_timer_pinned(&pcpu->cpu_slack_timer, expires);
++	}
++
++	spin_unlock_irqrestore(&pcpu->load_lock, flags);
++}
++
++/* The caller shall take enable_sem write semaphore to avoid any timer race.
++ * The cpu_timer and cpu_slack_timer must be deactivated when calling this
++ * function.
++ */
++static void cpufreq_interactive_timer_start(
++	struct cpufreq_interactive_tunables *tunables, int cpu)
++{
++	struct cpufreq_interactive_cpuinfo *pcpu = &per_cpu(cpuinfo, cpu);
++	unsigned long expires = jiffies +
++		usecs_to_jiffies(tunables->timer_rate);
++	unsigned long flags;
++
++	pcpu->cpu_timer.expires = expires;
++	add_timer_on(&pcpu->cpu_timer, cpu);
++	if (tunables->timer_slack_val >= 0 &&
++	    pcpu->target_freq > pcpu->policy->min) {
++		expires += usecs_to_jiffies(tunables->timer_slack_val);
++		pcpu->cpu_slack_timer.expires = expires;
++		add_timer_on(&pcpu->cpu_slack_timer, cpu);
++	}
++
++	spin_lock_irqsave(&pcpu->load_lock, flags);
++	pcpu->time_in_idle =
++		get_cpu_idle_time(cpu, &pcpu->time_in_idle_timestamp,
++				  tunables->io_is_busy);
++	pcpu->cputime_speedadj = 0;
++	pcpu->cputime_speedadj_timestamp = pcpu->time_in_idle_timestamp;
++	spin_unlock_irqrestore(&pcpu->load_lock, flags);
++}
++
++static unsigned int freq_to_above_hispeed_delay(
++	struct cpufreq_interactive_tunables *tunables,
++	unsigned int freq)
++{
++	int i;
++	unsigned int ret;
++	unsigned long flags;
++
++	spin_lock_irqsave(&tunables->above_hispeed_delay_lock, flags);
++
++	for (i = 0; i < tunables->nabove_hispeed_delay - 1 &&
++			freq >= tunables->above_hispeed_delay[i+1]; i += 2)
++		;
++
++	ret = tunables->above_hispeed_delay[i];
++	spin_unlock_irqrestore(&tunables->above_hispeed_delay_lock, flags);
++	return ret;
++}
++
++static unsigned int freq_to_targetload(
++	struct cpufreq_interactive_tunables *tunables, unsigned int freq)
++{
++	int i;
++	unsigned int ret;
++	unsigned long flags;
++
++	spin_lock_irqsave(&tunables->target_loads_lock, flags);
++
++	for (i = 0; i < tunables->ntarget_loads - 1 &&
++		    freq >= tunables->target_loads[i+1]; i += 2)
++		;
++
++	ret = tunables->target_loads[i];
++	spin_unlock_irqrestore(&tunables->target_loads_lock, flags);
++	return ret;
++}
++
++/*
++ * If increasing frequencies never map to a lower target load then
++ * choose_freq() will find the minimum frequency that does not exceed its
++ * target load given the current load.
++ */
++static unsigned int choose_freq(struct cpufreq_interactive_cpuinfo *pcpu,
++		unsigned int loadadjfreq)
++{
++	unsigned int freq = pcpu->policy->cur;
++	unsigned int prevfreq, freqmin, freqmax;
++	unsigned int tl;
++	int index;
++
++	freqmin = 0;
++	freqmax = UINT_MAX;
++
++	do {
++		prevfreq = freq;
++		tl = freq_to_targetload(pcpu->policy->governor_data, freq);
++
++		/*
++		 * Find the lowest frequency where the computed load is less
++		 * than or equal to the target load.
++		 */
++
++		if (cpufreq_frequency_table_target(
++			    pcpu->policy, pcpu->freq_table, loadadjfreq / tl,
++			    CPUFREQ_RELATION_L, &index))
++			break;
++		freq = pcpu->freq_table[index].frequency;
++
++		if (freq > prevfreq) {
++			/* The previous frequency is too low. */
++			freqmin = prevfreq;
++
++			if (freq >= freqmax) {
++				/*
++				 * Find the highest frequency that is less
++				 * than freqmax.
++				 */
++				if (cpufreq_frequency_table_target(
++					    pcpu->policy, pcpu->freq_table,
++					    freqmax - 1, CPUFREQ_RELATION_H,
++					    &index))
++					break;
++				freq = pcpu->freq_table[index].frequency;
++
++				if (freq == freqmin) {
++					/*
++					 * The first frequency below freqmax
++					 * has already been found to be too
++					 * low.  freqmax is the lowest speed
++					 * we found that is fast enough.
++					 */
++					freq = freqmax;
++					break;
++				}
++			}
++		} else if (freq < prevfreq) {
++			/* The previous frequency is high enough. */
++			freqmax = prevfreq;
++
++			if (freq <= freqmin) {
++				/*
++				 * Find the lowest frequency that is higher
++				 * than freqmin.
++				 */
++				if (cpufreq_frequency_table_target(
++					    pcpu->policy, pcpu->freq_table,
++					    freqmin + 1, CPUFREQ_RELATION_L,
++					    &index))
++					break;
++				freq = pcpu->freq_table[index].frequency;
++
++				/*
++				 * If freqmax is the first frequency above
++				 * freqmin then we have already found that
++				 * this speed is fast enough.
++				 */
++				if (freq == freqmax)
++					break;
++			}
++		}
++
++		/* If same frequency chosen as previous then done. */
++	} while (freq != prevfreq);
++
++	return freq;
++}
++
++static u64 update_load(int cpu)
++{
++	struct cpufreq_interactive_cpuinfo *pcpu = &per_cpu(cpuinfo, cpu);
++	struct cpufreq_interactive_tunables *tunables =
++		pcpu->policy->governor_data;
++	u64 now;
++	u64 now_idle;
++	unsigned int delta_idle;
++	unsigned int delta_time;
++	u64 active_time;
++
++	now_idle = get_cpu_idle_time(cpu, &now, tunables->io_is_busy);
++	delta_idle = (unsigned int)(now_idle - pcpu->time_in_idle);
++	delta_time = (unsigned int)(now - pcpu->time_in_idle_timestamp);
++
++	if (delta_time <= delta_idle)
++		active_time = 0;
++	else
++		active_time = delta_time - delta_idle;
++
++	pcpu->cputime_speedadj += active_time * pcpu->policy->cur;
++
++	pcpu->time_in_idle = now_idle;
++	pcpu->time_in_idle_timestamp = now;
++	return now;
++}
++
++static void cpufreq_interactive_timer(unsigned long data)
++{
++	u64 now;
++	unsigned int delta_time;
++	u64 cputime_speedadj;
++	int cpu_load;
++	struct cpufreq_interactive_cpuinfo *pcpu =
++		&per_cpu(cpuinfo, data);
++	struct cpufreq_interactive_tunables *tunables =
++		pcpu->policy->governor_data;
++	unsigned int new_freq;
++	unsigned int loadadjfreq;
++	unsigned int index;
++	unsigned long flags;
++	u64 max_fvtime;
++
++	if (!down_read_trylock(&pcpu->enable_sem))
++		return;
++	if (!pcpu->governor_enabled)
++		goto exit;
++
++	spin_lock_irqsave(&pcpu->load_lock, flags);
++	now = update_load(data);
++	delta_time = (unsigned int)(now - pcpu->cputime_speedadj_timestamp);
++	cputime_speedadj = pcpu->cputime_speedadj;
++	spin_unlock_irqrestore(&pcpu->load_lock, flags);
++
++	if (WARN_ON_ONCE(!delta_time))
++		goto rearm;
++
++	spin_lock_irqsave(&pcpu->target_freq_lock, flags);
++	do_div(cputime_speedadj, delta_time);
++	loadadjfreq = (unsigned int)cputime_speedadj * 100;
++	cpu_load = loadadjfreq / pcpu->policy->cur;
++	tunables->boosted = tunables->boost_val || now < tunables->boostpulse_endtime;
++
++	if (cpu_load >= tunables->go_hispeed_load || tunables->boosted) {
++		if (pcpu->policy->cur < tunables->hispeed_freq) {
++			new_freq = tunables->hispeed_freq;
++		} else {
++			new_freq = choose_freq(pcpu, loadadjfreq);
++
++			if (new_freq < tunables->hispeed_freq)
++				new_freq = tunables->hispeed_freq;
++		}
++	} else {
++		new_freq = choose_freq(pcpu, loadadjfreq);
++		if (new_freq > tunables->hispeed_freq &&
++				pcpu->policy->cur < tunables->hispeed_freq)
++			new_freq = tunables->hispeed_freq;
++	}
++
++	if (pcpu->policy->cur >= tunables->hispeed_freq &&
++	    new_freq > pcpu->policy->cur &&
++	    now - pcpu->pol_hispeed_val_time <
++	    freq_to_above_hispeed_delay(tunables, pcpu->policy->cur)) {
++		trace_cpufreq_interactive_notyet(
++			data, cpu_load, pcpu->target_freq,
++			pcpu->policy->cur, new_freq);
++		spin_unlock_irqrestore(&pcpu->target_freq_lock, flags);
++		goto rearm;
++	}
++
++	pcpu->loc_hispeed_val_time = now;
++
++	if (cpufreq_frequency_table_target(pcpu->policy, pcpu->freq_table,
++					   new_freq, CPUFREQ_RELATION_L,
++					   &index)) {
++		spin_unlock_irqrestore(&pcpu->target_freq_lock, flags);
++		goto rearm;
++	}
++
++	new_freq = pcpu->freq_table[index].frequency;
++
++	/*
++	 * Do not scale below floor_freq unless we have been at or above the
++	 * floor frequency for the minimum sample time since last validated.
++	 */
++	max_fvtime = max(pcpu->pol_floor_val_time, pcpu->loc_floor_val_time);
++	if (new_freq < pcpu->floor_freq &&
++	    pcpu->target_freq >= pcpu->policy->cur) {
++		if (now - max_fvtime < tunables->min_sample_time) {
++			trace_cpufreq_interactive_notyet(
++				data, cpu_load, pcpu->target_freq,
++				pcpu->policy->cur, new_freq);
++			spin_unlock_irqrestore(&pcpu->target_freq_lock, flags);
++			goto rearm;
++		}
++	}
++
++	/*
++	 * Update the timestamp for checking whether speed has been held at
++	 * or above the selected frequency for a minimum of min_sample_time,
++	 * if not boosted to hispeed_freq.  If boosted to hispeed_freq then we
++	 * allow the speed to drop as soon as the boostpulse duration expires
++	 * (or the indefinite boost is turned off).
++	 */
++
++	if (!tunables->boosted || new_freq > tunables->hispeed_freq) {
++		pcpu->floor_freq = new_freq;
++		if (pcpu->target_freq >= pcpu->policy->cur ||
++		    new_freq >= pcpu->policy->cur)
++			pcpu->loc_floor_val_time = now;
++	}
++
++	if (pcpu->target_freq == new_freq &&
++			pcpu->target_freq <= pcpu->policy->cur) {
++		trace_cpufreq_interactive_already(
++			data, cpu_load, pcpu->target_freq,
++			pcpu->policy->cur, new_freq);
++		spin_unlock_irqrestore(&pcpu->target_freq_lock, flags);
++		goto rearm;
++	}
++
++	trace_cpufreq_interactive_target(data, cpu_load, pcpu->target_freq,
++					 pcpu->policy->cur, new_freq);
++
++	pcpu->target_freq = new_freq;
++	spin_unlock_irqrestore(&pcpu->target_freq_lock, flags);
++	spin_lock_irqsave(&speedchange_cpumask_lock, flags);
++	cpumask_set_cpu(data, &speedchange_cpumask);
++	spin_unlock_irqrestore(&speedchange_cpumask_lock, flags);
++	wake_up_process(speedchange_task);
++
++rearm:
++	if (!timer_pending(&pcpu->cpu_timer))
++		cpufreq_interactive_timer_resched(pcpu);
++
++exit:
++	up_read(&pcpu->enable_sem);
++	return;
++}
++
++static void cpufreq_interactive_idle_end(void)
++{
++	struct cpufreq_interactive_cpuinfo *pcpu =
++		&per_cpu(cpuinfo, smp_processor_id());
++
++	if (!down_read_trylock(&pcpu->enable_sem))
++		return;
++	if (!pcpu->governor_enabled) {
++		up_read(&pcpu->enable_sem);
++		return;
++	}
++
++	/* Arm the timer for 1-2 ticks later if not already. */
++	if (!timer_pending(&pcpu->cpu_timer)) {
++		cpufreq_interactive_timer_resched(pcpu);
++	} else if (time_after_eq(jiffies, pcpu->cpu_timer.expires)) {
++		del_timer(&pcpu->cpu_timer);
++		del_timer(&pcpu->cpu_slack_timer);
++		cpufreq_interactive_timer(smp_processor_id());
++	}
++
++	up_read(&pcpu->enable_sem);
++}
++
++static int cpufreq_interactive_speedchange_task(void *data)
++{
++	unsigned int cpu;
++	cpumask_t tmp_mask;
++	unsigned long flags;
++	struct cpufreq_interactive_cpuinfo *pcpu;
++
++	while (1) {
++		set_current_state(TASK_INTERRUPTIBLE);
++		spin_lock_irqsave(&speedchange_cpumask_lock, flags);
++
++		if (cpumask_empty(&speedchange_cpumask)) {
++			spin_unlock_irqrestore(&speedchange_cpumask_lock,
++					       flags);
++			schedule();
++
++			if (kthread_should_stop())
++				break;
++
++			spin_lock_irqsave(&speedchange_cpumask_lock, flags);
++		}
++
++		set_current_state(TASK_RUNNING);
++		tmp_mask = speedchange_cpumask;
++		cpumask_clear(&speedchange_cpumask);
++		spin_unlock_irqrestore(&speedchange_cpumask_lock, flags);
++
++		for_each_cpu(cpu, &tmp_mask) {
++			unsigned int j;
++			unsigned int max_freq = 0;
++			struct cpufreq_interactive_cpuinfo *pjcpu;
++			u64 hvt = ~0ULL, fvt = 0;
++
++			pcpu = &per_cpu(cpuinfo, cpu);
++			if (!down_read_trylock(&pcpu->enable_sem))
++				continue;
++			if (!pcpu->governor_enabled) {
++				up_read(&pcpu->enable_sem);
++				continue;
++			}
++
++			for_each_cpu(j, pcpu->policy->cpus) {
++				pjcpu = &per_cpu(cpuinfo, j);
++
++				fvt = max(fvt, pjcpu->loc_floor_val_time);
++				if (pjcpu->target_freq > max_freq) {
++					max_freq = pjcpu->target_freq;
++					hvt = pjcpu->loc_hispeed_val_time;
++				} else if (pjcpu->target_freq == max_freq) {
++					hvt = min(hvt, pjcpu->loc_hispeed_val_time);
++				}
++			}
++			for_each_cpu(j, pcpu->policy->cpus) {
++				pjcpu = &per_cpu(cpuinfo, j);
++				pjcpu->pol_floor_val_time = fvt;
++			}
++
++			if (max_freq != pcpu->policy->cur) {
++				__cpufreq_driver_target(pcpu->policy,
++							max_freq,
++							CPUFREQ_RELATION_H);
++				for_each_cpu(j, pcpu->policy->cpus) {
++					pjcpu = &per_cpu(cpuinfo, j);
++					pjcpu->pol_hispeed_val_time = hvt;
++				}
++			}
++			trace_cpufreq_interactive_setspeed(cpu,
++						     pcpu->target_freq,
++						     pcpu->policy->cur);
++
++			up_read(&pcpu->enable_sem);
++		}
++	}
++
++	return 0;
++}
++
++static void cpufreq_interactive_boost(struct cpufreq_interactive_tunables *tunables)
++{
++	int i;
++	int anyboost = 0;
++	unsigned long flags[2];
++	struct cpufreq_interactive_cpuinfo *pcpu;
++
++	tunables->boosted = true;
++
++	spin_lock_irqsave(&speedchange_cpumask_lock, flags[0]);
++
++	for_each_online_cpu(i) {
++		pcpu = &per_cpu(cpuinfo, i);
++		if (tunables != pcpu->policy->governor_data)
++			continue;
++
++		spin_lock_irqsave(&pcpu->target_freq_lock, flags[1]);
++		if (pcpu->target_freq < tunables->hispeed_freq) {
++			pcpu->target_freq = tunables->hispeed_freq;
++			cpumask_set_cpu(i, &speedchange_cpumask);
++			pcpu->pol_hispeed_val_time =
++				ktime_to_us(ktime_get());
++			anyboost = 1;
++		}
++		spin_unlock_irqrestore(&pcpu->target_freq_lock, flags[1]);
++	}
++
++	spin_unlock_irqrestore(&speedchange_cpumask_lock, flags[0]);
++
++	if (anyboost)
++		wake_up_process(speedchange_task);
++}
++
++static int cpufreq_interactive_notifier(
++	struct notifier_block *nb, unsigned long val, void *data)
++{
++	struct cpufreq_freqs *freq = data;
++	struct cpufreq_interactive_cpuinfo *pcpu;
++	int cpu;
++	unsigned long flags;
++
++	if (val == CPUFREQ_POSTCHANGE) {
++		pcpu = &per_cpu(cpuinfo, freq->cpu);
++		if (!down_read_trylock(&pcpu->enable_sem))
++			return 0;
++		if (!pcpu->governor_enabled) {
++			up_read(&pcpu->enable_sem);
++			return 0;
++		}
++
++		for_each_cpu(cpu, pcpu->policy->cpus) {
++			struct cpufreq_interactive_cpuinfo *pjcpu =
++				&per_cpu(cpuinfo, cpu);
++			if (cpu != freq->cpu) {
++				if (!down_read_trylock(&pjcpu->enable_sem))
++					continue;
++				if (!pjcpu->governor_enabled) {
++					up_read(&pjcpu->enable_sem);
++					continue;
++				}
++			}
++			spin_lock_irqsave(&pjcpu->load_lock, flags);
++			update_load(cpu);
++			spin_unlock_irqrestore(&pjcpu->load_lock, flags);
++			if (cpu != freq->cpu)
++				up_read(&pjcpu->enable_sem);
++		}
++
++		up_read(&pcpu->enable_sem);
++	}
++	return 0;
++}
++
++static struct notifier_block cpufreq_notifier_block = {
++	.notifier_call = cpufreq_interactive_notifier,
++};
++
++static unsigned int *get_tokenized_data(const char *buf, int *num_tokens)
++{
++	const char *cp;
++	int i;
++	int ntokens = 1;
++	unsigned int *tokenized_data;
++	int err = -EINVAL;
++
++	cp = buf;
++	while ((cp = strpbrk(cp + 1, " :")))
++		ntokens++;
++
++	if (!(ntokens & 0x1))
++		goto err;
++
++	tokenized_data = kmalloc(ntokens * sizeof(unsigned int), GFP_KERNEL);
++	if (!tokenized_data) {
++		err = -ENOMEM;
++		goto err;
++	}
++
++	cp = buf;
++	i = 0;
++	while (i < ntokens) {
++		if (sscanf(cp, "%u", &tokenized_data[i++]) != 1)
++			goto err_kfree;
++
++		cp = strpbrk(cp, " :");
++		if (!cp)
++			break;
++		cp++;
++	}
++
++	if (i != ntokens)
++		goto err_kfree;
++
++	*num_tokens = ntokens;
++	return tokenized_data;
++
++err_kfree:
++	kfree(tokenized_data);
++err:
++	return ERR_PTR(err);
++}
++
++static ssize_t show_target_loads(
++	struct cpufreq_interactive_tunables *tunables,
++	char *buf)
++{
++	int i;
++	ssize_t ret = 0;
++	unsigned long flags;
++
++	spin_lock_irqsave(&tunables->target_loads_lock, flags);
++
++	for (i = 0; i < tunables->ntarget_loads; i++)
++		ret += sprintf(buf + ret, "%u%s", tunables->target_loads[i],
++			       i & 0x1 ? ":" : " ");
++
++	sprintf(buf + ret - 1, "\n");
++	spin_unlock_irqrestore(&tunables->target_loads_lock, flags);
++	return ret;
++}
++
++static ssize_t store_target_loads(
++	struct cpufreq_interactive_tunables *tunables,
++	const char *buf, size_t count)
++{
++	int ntokens;
++	unsigned int *new_target_loads = NULL;
++	unsigned long flags;
++
++	new_target_loads = get_tokenized_data(buf, &ntokens);
++	if (IS_ERR(new_target_loads))
++		return PTR_RET(new_target_loads);
++
++	spin_lock_irqsave(&tunables->target_loads_lock, flags);
++	if (tunables->target_loads != default_target_loads)
++		kfree(tunables->target_loads);
++	tunables->target_loads = new_target_loads;
++	tunables->ntarget_loads = ntokens;
++	spin_unlock_irqrestore(&tunables->target_loads_lock, flags);
++	return count;
++}
++
++static ssize_t show_above_hispeed_delay(
++	struct cpufreq_interactive_tunables *tunables, char *buf)
++{
++	int i;
++	ssize_t ret = 0;
++	unsigned long flags;
++
++	spin_lock_irqsave(&tunables->above_hispeed_delay_lock, flags);
++
++	for (i = 0; i < tunables->nabove_hispeed_delay; i++)
++		ret += sprintf(buf + ret, "%u%s",
++			       tunables->above_hispeed_delay[i],
++			       i & 0x1 ? ":" : " ");
++
++	sprintf(buf + ret - 1, "\n");
++	spin_unlock_irqrestore(&tunables->above_hispeed_delay_lock, flags);
++	return ret;
++}
++
++static ssize_t store_above_hispeed_delay(
++	struct cpufreq_interactive_tunables *tunables,
++	const char *buf, size_t count)
++{
++	int ntokens;
++	unsigned int *new_above_hispeed_delay = NULL;
++	unsigned long flags;
++
++	new_above_hispeed_delay = get_tokenized_data(buf, &ntokens);
++	if (IS_ERR(new_above_hispeed_delay))
++		return PTR_RET(new_above_hispeed_delay);
++
++	spin_lock_irqsave(&tunables->above_hispeed_delay_lock, flags);
++	if (tunables->above_hispeed_delay != default_above_hispeed_delay)
++		kfree(tunables->above_hispeed_delay);
++	tunables->above_hispeed_delay = new_above_hispeed_delay;
++	tunables->nabove_hispeed_delay = ntokens;
++	spin_unlock_irqrestore(&tunables->above_hispeed_delay_lock, flags);
++	return count;
++
++}
++
++static ssize_t show_hispeed_freq(struct cpufreq_interactive_tunables *tunables,
++		char *buf)
++{
++	return sprintf(buf, "%u\n", tunables->hispeed_freq);
++}
++
++static ssize_t store_hispeed_freq(struct cpufreq_interactive_tunables *tunables,
++		const char *buf, size_t count)
++{
++	int ret;
++	long unsigned int val;
++
++	ret = kstrtoul(buf, 0, &val);
++	if (ret < 0)
++		return ret;
++	tunables->hispeed_freq = val;
++	return count;
++}
++
++static ssize_t show_go_hispeed_load(struct cpufreq_interactive_tunables
++		*tunables, char *buf)
++{
++	return sprintf(buf, "%lu\n", tunables->go_hispeed_load);
++}
++
++static ssize_t store_go_hispeed_load(struct cpufreq_interactive_tunables
++		*tunables, const char *buf, size_t count)
++{
++	int ret;
++	unsigned long val;
++
++	ret = kstrtoul(buf, 0, &val);
++	if (ret < 0)
++		return ret;
++	tunables->go_hispeed_load = val;
++	return count;
++}
++
++static ssize_t show_min_sample_time(struct cpufreq_interactive_tunables
++		*tunables, char *buf)
++{
++	return sprintf(buf, "%lu\n", tunables->min_sample_time);
++}
++
++static ssize_t store_min_sample_time(struct cpufreq_interactive_tunables
++		*tunables, const char *buf, size_t count)
++{
++	int ret;
++	unsigned long val;
++
++	ret = kstrtoul(buf, 0, &val);
++	if (ret < 0)
++		return ret;
++	tunables->min_sample_time = val;
++	return count;
++}
++
++static ssize_t show_timer_rate(struct cpufreq_interactive_tunables *tunables,
++		char *buf)
++{
++	return sprintf(buf, "%lu\n", tunables->timer_rate);
++}
++
++static ssize_t store_timer_rate(struct cpufreq_interactive_tunables *tunables,
++		const char *buf, size_t count)
++{
++	int ret;
++	unsigned long val, val_round;
++
++	ret = kstrtoul(buf, 0, &val);
++	if (ret < 0)
++		return ret;
++
++	val_round = jiffies_to_usecs(usecs_to_jiffies(val));
++	if (val != val_round)
++		pr_warn("timer_rate not aligned to jiffy. Rounded up to %lu\n",
++			val_round);
++
++	tunables->timer_rate = val_round;
++	return count;
++}
++
++static ssize_t show_timer_slack(struct cpufreq_interactive_tunables *tunables,
++		char *buf)
++{
++	return sprintf(buf, "%d\n", tunables->timer_slack_val);
++}
++
++static ssize_t store_timer_slack(struct cpufreq_interactive_tunables *tunables,
++		const char *buf, size_t count)
++{
++	int ret;
++	unsigned long val;
++
++	ret = kstrtol(buf, 10, &val);
++	if (ret < 0)
++		return ret;
++
++	tunables->timer_slack_val = val;
++	return count;
++}
++
++static ssize_t show_boost(struct cpufreq_interactive_tunables *tunables,
++			  char *buf)
++{
++	return sprintf(buf, "%d\n", tunables->boost_val);
++}
++
++static ssize_t store_boost(struct cpufreq_interactive_tunables *tunables,
++			   const char *buf, size_t count)
++{
++	int ret;
++	unsigned long val;
++
++	ret = kstrtoul(buf, 0, &val);
++	if (ret < 0)
++		return ret;
++
++	tunables->boost_val = val;
++
++	if (tunables->boost_val) {
++		trace_cpufreq_interactive_boost("on");
++		if (!tunables->boosted)
++			cpufreq_interactive_boost(tunables);
++	} else {
++		tunables->boostpulse_endtime = ktime_to_us(ktime_get());
++		trace_cpufreq_interactive_unboost("off");
++	}
++
++	return count;
++}
++
++static ssize_t store_boostpulse(struct cpufreq_interactive_tunables *tunables,
++				const char *buf, size_t count)
++{
++	int ret;
++	unsigned long val;
++
++	ret = kstrtoul(buf, 0, &val);
++	if (ret < 0)
++		return ret;
++
++	tunables->boostpulse_endtime = ktime_to_us(ktime_get()) +
++		tunables->boostpulse_duration_val;
++	trace_cpufreq_interactive_boost("pulse");
++	if (!tunables->boosted)
++		cpufreq_interactive_boost(tunables);
++	return count;
++}
++
++static ssize_t show_boostpulse_duration(struct cpufreq_interactive_tunables
++		*tunables, char *buf)
++{
++	return sprintf(buf, "%d\n", tunables->boostpulse_duration_val);
++}
++
++static ssize_t store_boostpulse_duration(struct cpufreq_interactive_tunables
++		*tunables, const char *buf, size_t count)
++{
++	int ret;
++	unsigned long val;
++
++	ret = kstrtoul(buf, 0, &val);
++	if (ret < 0)
++		return ret;
++
++	tunables->boostpulse_duration_val = val;
++	return count;
++}
++
++static ssize_t show_io_is_busy(struct cpufreq_interactive_tunables *tunables,
++		char *buf)
++{
++	return sprintf(buf, "%u\n", tunables->io_is_busy);
++}
++
++static ssize_t store_io_is_busy(struct cpufreq_interactive_tunables *tunables,
++		const char *buf, size_t count)
++{
++	int ret;
++	unsigned long val;
++
++	ret = kstrtoul(buf, 0, &val);
++	if (ret < 0)
++		return ret;
++	tunables->io_is_busy = val;
++	return count;
++}
++
++/*
++ * Create show/store routines
++ * - sys: One governor instance for complete SYSTEM
++ * - pol: One governor instance per struct cpufreq_policy
++ */
++#define show_gov_pol_sys(file_name)					\
++static ssize_t show_##file_name##_gov_sys				\
++(struct kobject *kobj, struct attribute *attr, char *buf)		\
++{									\
++	return show_##file_name(common_tunables, buf);			\
++}									\
++									\
++static ssize_t show_##file_name##_gov_pol				\
++(struct cpufreq_policy *policy, char *buf)				\
++{									\
++	return show_##file_name(policy->governor_data, buf);		\
++}
++
++#define store_gov_pol_sys(file_name)					\
++static ssize_t store_##file_name##_gov_sys				\
++(struct kobject *kobj, struct attribute *attr, const char *buf,		\
++	size_t count)							\
++{									\
++	return store_##file_name(common_tunables, buf, count);		\
++}									\
++									\
++static ssize_t store_##file_name##_gov_pol				\
++(struct cpufreq_policy *policy, const char *buf, size_t count)		\
++{									\
++	return store_##file_name(policy->governor_data, buf, count);	\
++}
++
++#define show_store_gov_pol_sys(file_name)				\
++show_gov_pol_sys(file_name);						\
++store_gov_pol_sys(file_name)
++
++show_store_gov_pol_sys(target_loads);
++show_store_gov_pol_sys(above_hispeed_delay);
++show_store_gov_pol_sys(hispeed_freq);
++show_store_gov_pol_sys(go_hispeed_load);
++show_store_gov_pol_sys(min_sample_time);
++show_store_gov_pol_sys(timer_rate);
++show_store_gov_pol_sys(timer_slack);
++show_store_gov_pol_sys(boost);
++store_gov_pol_sys(boostpulse);
++show_store_gov_pol_sys(boostpulse_duration);
++show_store_gov_pol_sys(io_is_busy);
++
++#define gov_sys_attr_rw(_name)						\
++static struct global_attr _name##_gov_sys =				\
++__ATTR(_name, 0644, show_##_name##_gov_sys, store_##_name##_gov_sys)
++
++#define gov_pol_attr_rw(_name)						\
++static struct freq_attr _name##_gov_pol =				\
++__ATTR(_name, 0644, show_##_name##_gov_pol, store_##_name##_gov_pol)
++
++#define gov_sys_pol_attr_rw(_name)					\
++	gov_sys_attr_rw(_name);						\
++	gov_pol_attr_rw(_name)
++
++gov_sys_pol_attr_rw(target_loads);
++gov_sys_pol_attr_rw(above_hispeed_delay);
++gov_sys_pol_attr_rw(hispeed_freq);
++gov_sys_pol_attr_rw(go_hispeed_load);
++gov_sys_pol_attr_rw(min_sample_time);
++gov_sys_pol_attr_rw(timer_rate);
++gov_sys_pol_attr_rw(timer_slack);
++gov_sys_pol_attr_rw(boost);
++gov_sys_pol_attr_rw(boostpulse_duration);
++gov_sys_pol_attr_rw(io_is_busy);
++
++static struct global_attr boostpulse_gov_sys =
++	__ATTR(boostpulse, 0200, NULL, store_boostpulse_gov_sys);
++
++static struct freq_attr boostpulse_gov_pol =
++	__ATTR(boostpulse, 0200, NULL, store_boostpulse_gov_pol);
++
++/* One Governor instance for entire system */
++static struct attribute *interactive_attributes_gov_sys[] = {
++	&target_loads_gov_sys.attr,
++	&above_hispeed_delay_gov_sys.attr,
++	&hispeed_freq_gov_sys.attr,
++	&go_hispeed_load_gov_sys.attr,
++	&min_sample_time_gov_sys.attr,
++	&timer_rate_gov_sys.attr,
++	&timer_slack_gov_sys.attr,
++	&boost_gov_sys.attr,
++	&boostpulse_gov_sys.attr,
++	&boostpulse_duration_gov_sys.attr,
++	&io_is_busy_gov_sys.attr,
++	NULL,
++};
++
++static struct attribute_group interactive_attr_group_gov_sys = {
++	.attrs = interactive_attributes_gov_sys,
++	.name = "interactive",
++};
++
++/* Per policy governor instance */
++static struct attribute *interactive_attributes_gov_pol[] = {
++	&target_loads_gov_pol.attr,
++	&above_hispeed_delay_gov_pol.attr,
++	&hispeed_freq_gov_pol.attr,
++	&go_hispeed_load_gov_pol.attr,
++	&min_sample_time_gov_pol.attr,
++	&timer_rate_gov_pol.attr,
++	&timer_slack_gov_pol.attr,
++	&boost_gov_pol.attr,
++	&boostpulse_gov_pol.attr,
++	&boostpulse_duration_gov_pol.attr,
++	&io_is_busy_gov_pol.attr,
++	NULL,
++};
++
++static struct attribute_group interactive_attr_group_gov_pol = {
++	.attrs = interactive_attributes_gov_pol,
++	.name = "interactive",
++};
++
++static struct attribute_group *get_sysfs_attr(void)
++{
++	if (have_governor_per_policy())
++		return &interactive_attr_group_gov_pol;
++	else
++		return &interactive_attr_group_gov_sys;
++}
++
++static int cpufreq_interactive_idle_notifier(struct notifier_block *nb,
++					     unsigned long val,
++					     void *data)
++{
++	if (val == IDLE_END)
++		cpufreq_interactive_idle_end();
++
++	return 0;
++}
++
++static struct notifier_block cpufreq_interactive_idle_nb = {
++	.notifier_call = cpufreq_interactive_idle_notifier,
++};
++
++static int cpufreq_governor_interactive(struct cpufreq_policy *policy,
++		unsigned int event)
++{
++	int rc;
++	unsigned int j;
++	struct cpufreq_interactive_cpuinfo *pcpu;
++	struct cpufreq_frequency_table *freq_table;
++	struct cpufreq_interactive_tunables *tunables;
++	unsigned long flags;
++
++	if (have_governor_per_policy())
++		tunables = policy->governor_data;
++	else
++		tunables = common_tunables;
++
++	WARN_ON(!tunables && (event != CPUFREQ_GOV_POLICY_INIT));
++
++	switch (event) {
++	case CPUFREQ_GOV_POLICY_INIT:
++		if (have_governor_per_policy()) {
++			WARN_ON(tunables);
++		} else if (tunables) {
++			tunables->usage_count++;
++			policy->governor_data = tunables;
++			return 0;
++		}
++
++		tunables = kzalloc(sizeof(*tunables), GFP_KERNEL);
++		if (!tunables) {
++			pr_err("%s: POLICY_INIT: kzalloc failed\n", __func__);
++			return -ENOMEM;
++		}
++
++		tunables->usage_count = 1;
++		tunables->above_hispeed_delay = default_above_hispeed_delay;
++		tunables->nabove_hispeed_delay =
++			ARRAY_SIZE(default_above_hispeed_delay);
++		tunables->go_hispeed_load = DEFAULT_GO_HISPEED_LOAD;
++		tunables->target_loads = default_target_loads;
++		tunables->ntarget_loads = ARRAY_SIZE(default_target_loads);
++		tunables->min_sample_time = DEFAULT_MIN_SAMPLE_TIME;
++		tunables->timer_rate = DEFAULT_TIMER_RATE;
++		tunables->boostpulse_duration_val = DEFAULT_MIN_SAMPLE_TIME;
++		tunables->timer_slack_val = DEFAULT_TIMER_SLACK;
++
++		spin_lock_init(&tunables->target_loads_lock);
++		spin_lock_init(&tunables->above_hispeed_delay_lock);
++
++		policy->governor_data = tunables;
++		if (!have_governor_per_policy()) {
++			common_tunables = tunables;
++			WARN_ON(cpufreq_get_global_kobject());
++		}
++
++		rc = sysfs_create_group(get_governor_parent_kobj(policy),
++				get_sysfs_attr());
++		if (rc) {
++			kfree(tunables);
++			policy->governor_data = NULL;
++			if (!have_governor_per_policy()) {
++				common_tunables = NULL;
++				cpufreq_put_global_kobject();
++			}
++			return rc;
++		}
++
++		if (!policy->governor->initialized) {
++			idle_notifier_register(&cpufreq_interactive_idle_nb);
++			cpufreq_register_notifier(&cpufreq_notifier_block,
++					CPUFREQ_TRANSITION_NOTIFIER);
++		}
++
++		break;
++
++	case CPUFREQ_GOV_POLICY_EXIT:
++		if (!--tunables->usage_count) {
++			if (policy->governor->initialized == 1) {
++				cpufreq_unregister_notifier(&cpufreq_notifier_block,
++						CPUFREQ_TRANSITION_NOTIFIER);
++				idle_notifier_unregister(&cpufreq_interactive_idle_nb);
++			}
++
++			sysfs_remove_group(get_governor_parent_kobj(policy),
++					get_sysfs_attr());
++
++			if (!have_governor_per_policy())
++				cpufreq_put_global_kobject();
++
++			kfree(tunables);
++			common_tunables = NULL;
++		}
++
++		policy->governor_data = NULL;
++		break;
++
++	case CPUFREQ_GOV_START:
++		mutex_lock(&gov_lock);
++
++		freq_table = cpufreq_frequency_get_table(policy->cpu);
++		if (!tunables->hispeed_freq)
++			tunables->hispeed_freq = policy->max;
++
++		for_each_cpu(j, policy->cpus) {
++			pcpu = &per_cpu(cpuinfo, j);
++			pcpu->policy = policy;
++			pcpu->target_freq = policy->cur;
++			pcpu->freq_table = freq_table;
++			pcpu->floor_freq = pcpu->target_freq;
++			pcpu->pol_floor_val_time =
++				ktime_to_us(ktime_get());
++			pcpu->loc_floor_val_time = pcpu->pol_floor_val_time;
++			pcpu->pol_hispeed_val_time = pcpu->pol_floor_val_time;
++			pcpu->loc_hispeed_val_time = pcpu->pol_floor_val_time;
++			down_write(&pcpu->enable_sem);
++			del_timer_sync(&pcpu->cpu_timer);
++			del_timer_sync(&pcpu->cpu_slack_timer);
++			cpufreq_interactive_timer_start(tunables, j);
++			pcpu->governor_enabled = 1;
++			up_write(&pcpu->enable_sem);
++		}
++
++		mutex_unlock(&gov_lock);
++		break;
++
++	case CPUFREQ_GOV_STOP:
++		mutex_lock(&gov_lock);
++		for_each_cpu(j, policy->cpus) {
++			pcpu = &per_cpu(cpuinfo, j);
++			down_write(&pcpu->enable_sem);
++			pcpu->governor_enabled = 0;
++			del_timer_sync(&pcpu->cpu_timer);
++			del_timer_sync(&pcpu->cpu_slack_timer);
++			up_write(&pcpu->enable_sem);
++		}
++
++		mutex_unlock(&gov_lock);
++		break;
++
++	case CPUFREQ_GOV_LIMITS:
++		if (policy->max < policy->cur)
++			__cpufreq_driver_target(policy,
++					policy->max, CPUFREQ_RELATION_H);
++		else if (policy->min > policy->cur)
++			__cpufreq_driver_target(policy,
++					policy->min, CPUFREQ_RELATION_L);
++		for_each_cpu(j, policy->cpus) {
++			pcpu = &per_cpu(cpuinfo, j);
++
++			down_read(&pcpu->enable_sem);
++			if (pcpu->governor_enabled == 0) {
++				up_read(&pcpu->enable_sem);
++				continue;
++			}
++
++			spin_lock_irqsave(&pcpu->target_freq_lock, flags);
++			if (policy->max < pcpu->target_freq)
++				pcpu->target_freq = policy->max;
++			else if (policy->min > pcpu->target_freq)
++				pcpu->target_freq = policy->min;
++
++			spin_unlock_irqrestore(&pcpu->target_freq_lock, flags);
++			up_read(&pcpu->enable_sem);
++		}
++		break;
++	}
++	return 0;
++}
++
++#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE
++static
++#endif
++struct cpufreq_governor cpufreq_gov_interactive = {
++	.name = "interactive",
++	.governor = cpufreq_governor_interactive,
++	.max_transition_latency = 10000000,
++	.owner = THIS_MODULE,
++};
++
++static void cpufreq_interactive_nop_timer(unsigned long data)
++{
++}
++
++static int __init cpufreq_interactive_init(void)
++{
++	unsigned int i;
++	struct cpufreq_interactive_cpuinfo *pcpu;
++	struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
++
++	/* Initalize per-cpu timers */
++	for_each_possible_cpu(i) {
++		pcpu = &per_cpu(cpuinfo, i);
++		init_timer_deferrable(&pcpu->cpu_timer);
++		pcpu->cpu_timer.function = cpufreq_interactive_timer;
++		pcpu->cpu_timer.data = i;
++		init_timer(&pcpu->cpu_slack_timer);
++		pcpu->cpu_slack_timer.function = cpufreq_interactive_nop_timer;
++		spin_lock_init(&pcpu->load_lock);
++		spin_lock_init(&pcpu->target_freq_lock);
++		init_rwsem(&pcpu->enable_sem);
++	}
++
++	spin_lock_init(&speedchange_cpumask_lock);
++	mutex_init(&gov_lock);
++	speedchange_task =
++		kthread_create(cpufreq_interactive_speedchange_task, NULL,
++			       "cfinteractive");
++	if (IS_ERR(speedchange_task))
++		return PTR_ERR(speedchange_task);
++
++	sched_setscheduler_nocheck(speedchange_task, SCHED_FIFO, &param);
++	get_task_struct(speedchange_task);
++
++	/* NB: wake up so the thread does not look hung to the freezer */
++	wake_up_process(speedchange_task);
++
++	return cpufreq_register_governor(&cpufreq_gov_interactive);
++}
++
++#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE
++fs_initcall(cpufreq_interactive_init);
++#else
++module_init(cpufreq_interactive_init);
++#endif
++
++static void __exit cpufreq_interactive_exit(void)
++{
++	cpufreq_unregister_governor(&cpufreq_gov_interactive);
++	kthread_stop(speedchange_task);
++	put_task_struct(speedchange_task);
++}
++
++module_exit(cpufreq_interactive_exit);
++
++MODULE_AUTHOR("Mike Chan <mike@android.com>");
++MODULE_DESCRIPTION("'cpufreq_interactive' - A cpufreq governor for "
++	"Latency sensitive workloads");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
+index 0cd9b4d..a2f1d41 100644
+--- a/drivers/cpufreq/cpufreq_stats.c
++++ b/drivers/cpufreq/cpufreq_stats.c
+@@ -13,6 +13,9 @@
+ #include <linux/cpufreq.h>
+ #include <linux/module.h>
+ #include <linux/slab.h>
++#include <linux/sort.h>
++#include <linux/of.h>
++#include <linux/sched.h>
+ #include <linux/cputime.h>
+ 
+ static spinlock_t cpufreq_stats_lock;
+@@ -31,7 +34,28 @@ struct cpufreq_stats {
+ #endif
+ };
+ 
++struct all_cpufreq_stats {
++	unsigned int state_num;
++	cputime64_t *time_in_state;
++	unsigned int *freq_table;
++};
++
++struct cpufreq_power_stats {
++	unsigned int state_num;
++	unsigned int *curr;
++	unsigned int *freq_table;
++};
++
++struct all_freq_table {
++	unsigned int *freq_table;
++	unsigned int table_size;
++};
++
++static struct all_freq_table *all_freq_table;
++
++static DEFINE_PER_CPU(struct all_cpufreq_stats *, all_cpufreq_stats);
+ static DEFINE_PER_CPU(struct cpufreq_stats *, cpufreq_stats_table);
++static DEFINE_PER_CPU(struct cpufreq_power_stats *, cpufreq_power_stats);
+ 
+ struct cpufreq_stats_attribute {
+ 	struct attribute attr;
+@@ -41,14 +65,24 @@ struct cpufreq_stats_attribute {
+ static int cpufreq_stats_update(unsigned int cpu)
+ {
+ 	struct cpufreq_stats *stat;
++	struct all_cpufreq_stats *all_stat;
+ 	unsigned long long cur_time;
+ 
+ 	cur_time = get_jiffies_64();
+ 	spin_lock(&cpufreq_stats_lock);
+ 	stat = per_cpu(cpufreq_stats_table, cpu);
+-	if (stat->time_in_state)
++	all_stat = per_cpu(all_cpufreq_stats, cpu);
++	if (!stat) {
++		spin_unlock(&cpufreq_stats_lock);
++		return 0;
++	}
++	if (stat->time_in_state) {
+ 		stat->time_in_state[stat->last_index] +=
+ 			cur_time - stat->last_time;
++		if (all_stat)
++			all_stat->time_in_state[stat->last_index] +=
++					cur_time - stat->last_time;
++	}
+ 	stat->last_time = cur_time;
+ 	spin_unlock(&cpufreq_stats_lock);
+ 	return 0;
+@@ -79,6 +113,104 @@ static ssize_t show_time_in_state(struct cpufreq_policy *policy, char *buf)
+ 	return len;
+ }
+ 
++static int get_index_all_cpufreq_stat(struct all_cpufreq_stats *all_stat,
++		unsigned int freq)
++{
++	int i;
++	if (!all_stat)
++		return -1;
++	for (i = 0; i < all_stat->state_num; i++) {
++		if (all_stat->freq_table[i] == freq)
++			return i;
++	}
++	return -1;
++}
++
++void acct_update_power(struct task_struct *task, cputime_t cputime) {
++	struct cpufreq_power_stats *powerstats;
++	struct cpufreq_stats *stats;
++	unsigned int cpu_num, curr;
++
++	if (!task)
++		return;
++	cpu_num = task_cpu(task);
++	powerstats = per_cpu(cpufreq_power_stats, cpu_num);
++	stats = per_cpu(cpufreq_stats_table, cpu_num);
++	if (!powerstats || !stats)
++		return;
++
++	curr = powerstats->curr[stats->last_index];
++	if (task->cpu_power != ULLONG_MAX)
++		task->cpu_power += curr * cputime_to_usecs(cputime);
++}
++EXPORT_SYMBOL_GPL(acct_update_power);
++
++static ssize_t show_current_in_state(struct kobject *kobj,
++		struct kobj_attribute *attr, char *buf)
++{
++	ssize_t len = 0;
++	unsigned int i, cpu;
++	struct cpufreq_power_stats *powerstats;
++
++	spin_lock(&cpufreq_stats_lock);
++	for_each_possible_cpu(cpu) {
++		powerstats = per_cpu(cpufreq_power_stats, cpu);
++		if (!powerstats)
++			continue;
++		len += scnprintf(buf + len, PAGE_SIZE - len, "CPU%d:", cpu);
++		for (i = 0; i < powerstats->state_num; i++)
++			len += scnprintf(buf + len, PAGE_SIZE - len,
++					"%d=%d ", powerstats->freq_table[i],
++					powerstats->curr[i]);
++		len += scnprintf(buf + len, PAGE_SIZE - len, "\n");
++	}
++	spin_unlock(&cpufreq_stats_lock);
++	return len;
++}
++
++static ssize_t show_all_time_in_state(struct kobject *kobj,
++		struct kobj_attribute *attr, char *buf)
++{
++	ssize_t len = 0;
++	unsigned int i, cpu, freq, index;
++	struct all_cpufreq_stats *all_stat;
++	struct cpufreq_policy *policy;
++
++	len += scnprintf(buf + len, PAGE_SIZE - len, "freq\t\t");
++	for_each_possible_cpu(cpu) {
++		len += scnprintf(buf + len, PAGE_SIZE - len, "cpu%d\t\t", cpu);
++		if (cpu_online(cpu))
++			cpufreq_stats_update(cpu);
++	}
++
++	if (!all_freq_table)
++		goto out;
++	for (i = 0; i < all_freq_table->table_size; i++) {
++		freq = all_freq_table->freq_table[i];
++		len += scnprintf(buf + len, PAGE_SIZE - len, "\n%u\t\t", freq);
++		for_each_possible_cpu(cpu) {
++			policy = cpufreq_cpu_get(cpu);
++			if (policy == NULL)
++				continue;
++			all_stat = per_cpu(all_cpufreq_stats, policy->cpu);
++			index = get_index_all_cpufreq_stat(all_stat, freq);
++			if (index != -1) {
++				len += scnprintf(buf + len, PAGE_SIZE - len,
++					"%llu\t\t", (unsigned long long)
++					cputime64_to_clock_t(all_stat->time_in_state[index]));
++			} else {
++				len += scnprintf(buf + len, PAGE_SIZE - len,
++						"N/A\t\t");
++			}
++			cpufreq_cpu_put(policy);
++		}
++	}
++
++out:
++	len += scnprintf(buf + len, PAGE_SIZE - len, "\n");
++	return len;
++}
++
+ #ifdef CONFIG_CPU_FREQ_STAT_DETAILS
+ static ssize_t show_trans_table(struct cpufreq_policy *policy, char *buf)
+ {
+@@ -142,6 +274,12 @@ static struct attribute_group stats_attr_group = {
+ 	.name = "stats"
+ };
+ 
++static struct kobj_attribute _attr_all_time_in_state = __ATTR(all_time_in_state,
++		0444, show_all_time_in_state, NULL);
++
++static struct kobj_attribute _attr_current_in_state = __ATTR(current_in_state,
++		0444, show_current_in_state, NULL);
++
+ static int freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq)
+ {
+ 	int index;
+@@ -180,17 +318,54 @@ static void cpufreq_stats_free_table(unsigned int cpu)
+ 	cpufreq_cpu_put(policy);
+ }
+ 
+-static int __cpufreq_stats_create_table(struct cpufreq_policy *policy)
++static void cpufreq_allstats_free(void)
++{
++	int cpu;
++	struct all_cpufreq_stats *all_stat;
++
++	sysfs_remove_file(cpufreq_global_kobject,
++						&_attr_all_time_in_state.attr);
++
++	for_each_possible_cpu(cpu) {
++		all_stat = per_cpu(all_cpufreq_stats, cpu);
++		if (!all_stat)
++			continue;
++		kfree(all_stat->time_in_state);
++		kfree(all_stat);
++		per_cpu(all_cpufreq_stats, cpu) = NULL;
++	}
++	if (all_freq_table) {
++		kfree(all_freq_table->freq_table);
++		kfree(all_freq_table);
++		all_freq_table = NULL;
++	}
++}
++
++static void cpufreq_powerstats_free(void)
++{
++	int cpu;
++	struct cpufreq_power_stats *powerstats;
++
++	sysfs_remove_file(cpufreq_global_kobject, &_attr_current_in_state.attr);
++
++	for_each_possible_cpu(cpu) {
++		powerstats = per_cpu(cpufreq_power_stats, cpu);
++		if (!powerstats)
++			continue;
++		kfree(powerstats->curr);
++		kfree(powerstats);
++		per_cpu(cpufreq_power_stats, cpu) = NULL;
++	}
++}
++
++static int __cpufreq_stats_create_table(struct cpufreq_policy *policy,
++		struct cpufreq_frequency_table *table, int count)
+ {
+-	unsigned int i, count = 0, ret = 0;
++	unsigned int i, ret = 0;
+ 	struct cpufreq_stats *stat;
+ 	unsigned int alloc_size;
+ 	unsigned int cpu = policy->cpu;
+-	struct cpufreq_frequency_table *pos, *table;
+-
+-	table = cpufreq_frequency_get_table(cpu);
+-	if (unlikely(!table))
+-		return 0;
++	struct cpufreq_frequency_table *pos;
+ 
+ 	if (per_cpu(cpufreq_stats_table, cpu))
+ 		return -EBUSY;
+@@ -205,9 +380,6 @@ static int __cpufreq_stats_create_table(struct cpufreq_policy *policy)
+ 	stat->cpu = cpu;
+ 	per_cpu(cpufreq_stats_table, cpu) = stat;
+ 
+-	cpufreq_for_each_valid_entry(pos, table)
+-		count++;
+-
+ 	alloc_size = count * sizeof(int) + count * sizeof(u64);
+ 
+ #ifdef CONFIG_CPU_FREQ_STAT_DETAILS
+@@ -242,10 +414,159 @@ error_out:
+ 	return ret;
+ }
+ 
++static void cpufreq_stats_update_policy_cpu(struct cpufreq_policy *policy)
++{
++	struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table,
++			policy->last_cpu);
++
++	pr_debug("Updating stats_table for new_cpu %u from last_cpu %u\n",
++			policy->cpu, policy->last_cpu);
++	per_cpu(cpufreq_stats_table, policy->cpu) = per_cpu(cpufreq_stats_table,
++			policy->last_cpu);
++	per_cpu(cpufreq_stats_table, policy->last_cpu) = NULL;
++	stat->cpu = policy->cpu;
++}
++
++static void cpufreq_powerstats_create(unsigned int cpu,
++		struct cpufreq_frequency_table *table, int count) {
++	unsigned int alloc_size, i = 0, ret = 0;
++	struct cpufreq_power_stats *powerstats;
++	struct cpufreq_frequency_table *pos;
++	struct device_node *cpu_node;
++	char device_path[16];
++
++	powerstats = kzalloc(sizeof(struct cpufreq_power_stats),
++			GFP_KERNEL);
++	if (!powerstats)
++		return;
++
++	/* Allocate memory for freq table per cpu as well as clockticks per
++	 * freq*/
++	alloc_size = count * sizeof(unsigned int) +
++		count * sizeof(unsigned int);
++	powerstats->curr = kzalloc(alloc_size, GFP_KERNEL);
++	if (!powerstats->curr) {
++		kfree(powerstats);
++		return;
++	}
++	powerstats->freq_table = powerstats->curr + count;
++
++	spin_lock(&cpufreq_stats_lock);
++	i = 0;
++	cpufreq_for_each_valid_entry(pos, table)
++		powerstats->freq_table[i++] = pos->frequency;
++	powerstats->state_num = i;
++
++	snprintf(device_path, sizeof(device_path), "/cpus/cpu@%d", cpu);
++	cpu_node = of_find_node_by_path(device_path);
++	if (cpu_node) {
++		ret = of_property_read_u32_array(cpu_node, "current",
++				powerstats->curr, count);
++		if (ret) {
++			kfree(powerstats->curr);
++			kfree(powerstats);
++			powerstats = NULL;
++		}
++	}
++	per_cpu(cpufreq_power_stats, cpu) = powerstats;
++	spin_unlock(&cpufreq_stats_lock);
++}
++
++static int compare_for_sort(const void *lhs_ptr, const void *rhs_ptr)
++{
++	unsigned int lhs = *(const unsigned int *)(lhs_ptr);
++	unsigned int rhs = *(const unsigned int *)(rhs_ptr);
++	if (lhs < rhs)
++		return -1;
++	if (lhs > rhs)
++		return 1;
++	return 0;
++}
++
++static bool check_all_freq_table(unsigned int freq)
++{
++	int i;
++	for (i = 0; i < all_freq_table->table_size; i++) {
++		if (freq == all_freq_table->freq_table[i])
++			return true;
++	}
++	return false;
++}
++
++static void create_all_freq_table(void)
++{
++	all_freq_table = kzalloc(sizeof(struct all_freq_table),
++			GFP_KERNEL);
++	if (!all_freq_table)
++		pr_warn("could not allocate memory for all_freq_table\n");
++	return;
++}
++
++static void add_all_freq_table(unsigned int freq)
++{
++	unsigned int size;
++	size = sizeof(unsigned int) * (all_freq_table->table_size + 1);
++	all_freq_table->freq_table = krealloc(all_freq_table->freq_table,
++			size, GFP_ATOMIC);
++	if (IS_ERR(all_freq_table->freq_table)) {
++		pr_warn("Could not reallocate memory for freq_table\n");
++		all_freq_table->freq_table = NULL;
++		return;
++	}
++	all_freq_table->freq_table[all_freq_table->table_size++] = freq;
++}
++
++static void cpufreq_allstats_create(unsigned int cpu,
++		struct cpufreq_frequency_table *table, int count)
++{
++	int i , j = 0;
++	unsigned int alloc_size;
++	struct all_cpufreq_stats *all_stat;
++	bool sort_needed = false;
++
++	all_stat = kzalloc(sizeof(struct all_cpufreq_stats),
++			GFP_KERNEL);
++	if (!all_stat) {
++		pr_warn("Cannot allocate memory for cpufreq stats\n");
++		return;
++	}
++
++	/*Allocate memory for freq table per cpu as well as clockticks per freq*/
++	alloc_size = count * sizeof(int) + count * sizeof(cputime64_t);
++	all_stat->time_in_state = kzalloc(alloc_size, GFP_KERNEL);
++	if (!all_stat->time_in_state) {
++		pr_warn("Cannot allocate memory for cpufreq time_in_state\n");
++		kfree(all_stat);
++		all_stat = NULL;
++		return;
++	}
++	all_stat->freq_table = (unsigned int *)
++		(all_stat->time_in_state + count);
++
++	spin_lock(&cpufreq_stats_lock);
++	for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
++		unsigned int freq = table[i].frequency;
++		if (freq == CPUFREQ_ENTRY_INVALID)
++			continue;
++		all_stat->freq_table[j++] = freq;
++		if (all_freq_table && !check_all_freq_table(freq)) {
++			add_all_freq_table(freq);
++			sort_needed = true;
++		}
++	}
++	if (sort_needed)
++		sort(all_freq_table->freq_table, all_freq_table->table_size,
++				sizeof(unsigned int), &compare_for_sort, NULL);
++	all_stat->state_num = j;
++	per_cpu(all_cpufreq_stats, cpu) = all_stat;
++	spin_unlock(&cpufreq_stats_lock);
++}
++
+ static void cpufreq_stats_create_table(unsigned int cpu)
+ {
+ 	struct cpufreq_policy *policy;
+-
++	struct cpufreq_frequency_table *table, *pos;
++	int count = 0;
+ 	/*
+ 	 * "likely(!policy)" because normally cpufreq_stats will be registered
+ 	 * before cpufreq driver
+@@ -254,37 +575,52 @@ static void cpufreq_stats_create_table(unsigned int cpu)
+ 	if (likely(!policy))
+ 		return;
+ 
+-	__cpufreq_stats_create_table(policy);
++	table = cpufreq_frequency_get_table(policy->cpu);
++	if (likely(table)) {
++		cpufreq_for_each_valid_entry(pos, table)
++			count++;
+ 
+-	cpufreq_cpu_put(policy);
+-}
++		if (!per_cpu(all_cpufreq_stats, cpu))
++			cpufreq_allstats_create(cpu, table, count);
+ 
+-static void cpufreq_stats_update_policy_cpu(struct cpufreq_policy *policy)
+-{
+-	struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table,
+-			policy->last_cpu);
++		if (!per_cpu(cpufreq_power_stats, cpu))
++			cpufreq_powerstats_create(cpu, table, count);
+ 
+-	pr_debug("Updating stats_table for new_cpu %u from last_cpu %u\n",
+-			policy->cpu, policy->last_cpu);
+-	per_cpu(cpufreq_stats_table, policy->cpu) = per_cpu(cpufreq_stats_table,
+-			policy->last_cpu);
+-	per_cpu(cpufreq_stats_table, policy->last_cpu) = NULL;
+-	stat->cpu = policy->cpu;
++		__cpufreq_stats_create_table(policy, table, count);
++	}
++	cpufreq_cpu_put(policy);
+ }
+ 
+ static int cpufreq_stat_notifier_policy(struct notifier_block *nb,
+ 		unsigned long val, void *data)
+ {
+-	int ret = 0;
++	int ret = 0, count = 0;
+ 	struct cpufreq_policy *policy = data;
++	struct cpufreq_frequency_table *table, *pos;
++	unsigned int cpu_num, cpu = policy->cpu;
+ 
+ 	if (val == CPUFREQ_UPDATE_POLICY_CPU) {
+ 		cpufreq_stats_update_policy_cpu(policy);
+ 		return 0;
+ 	}
+ 
++	table = cpufreq_frequency_get_table(cpu);
++	if (!table)
++		return 0;
++
++	cpufreq_for_each_valid_entry(pos, table)
++		count++;
++
++	if (!per_cpu(all_cpufreq_stats, cpu))
++		cpufreq_allstats_create(cpu, table, count);
++
++	for_each_possible_cpu(cpu_num) {
++		if (!per_cpu(cpufreq_power_stats, cpu_num))
++			cpufreq_powerstats_create(cpu_num, table, count);
++	}
++
+ 	if (val == CPUFREQ_CREATE_POLICY)
+-		ret = __cpufreq_stats_create_table(policy);
++		ret = __cpufreq_stats_create_table(policy, table, count);
+ 	else if (val == CPUFREQ_REMOVE_POLICY)
+ 		__cpufreq_stats_free_table(policy);
+ 
+@@ -359,6 +695,18 @@ static int __init cpufreq_stats_init(void)
+ 		return ret;
+ 	}
+ 
++	create_all_freq_table();
++	WARN_ON(cpufreq_get_global_kobject());
++	ret = sysfs_create_file(cpufreq_global_kobject,
++			&_attr_all_time_in_state.attr);
++	if (ret)
++		pr_warn("Cannot create sysfs file for cpufreq stats\n");
++
++	ret = sysfs_create_file(cpufreq_global_kobject,
++			&_attr_current_in_state.attr);
++	if (ret)
++		pr_warn("Cannot create sysfs file for cpufreq current stats\n");
++
+ 	return 0;
+ }
+ static void __exit cpufreq_stats_exit(void)
+@@ -371,6 +719,9 @@ static void __exit cpufreq_stats_exit(void)
+ 			CPUFREQ_TRANSITION_NOTIFIER);
+ 	for_each_online_cpu(cpu)
+ 		cpufreq_stats_free_table(cpu);
++	cpufreq_allstats_free();
++	cpufreq_powerstats_free();
++	cpufreq_put_global_kobject();
+ }
+ 
+ MODULE_AUTHOR("Zou Nan hai <nanhai.zou@intel.com>");
+diff --git a/drivers/cpuidle/Kconfig.arm b/drivers/cpuidle/Kconfig.arm
+index 8c16ab2..289bf08 100644
+--- a/drivers/cpuidle/Kconfig.arm
++++ b/drivers/cpuidle/Kconfig.arm
+@@ -63,3 +63,33 @@ config ARM_MVEBU_V7_CPUIDLE
+ 	depends on ARCH_MVEBU
+ 	help
+ 	  Select this to enable cpuidle on Armada 370, 38x and XP processors.
++
++config ARM_HI3519_CPUIDLE
++	bool "CPU Idle Driver for Hi3519 processors"
++	depends on ARCH_HI3519
++	help
++	  Select this to enable cpuidle on Hi3519 processors.
++
++config ARM_HI3519V101_CPUIDLE
++	bool "CPU Idle Driver for Hi3519v101 processors"
++	depends on ARCH_HI3519V101
++	help
++	  Select this to enable cpuidle on Hi3519v101 processors.
++
++config ARM_HI3516AV200_CPUIDLE
++	bool "CPU Idle Driver for Hi3516av200 processors"
++	depends on ARCH_HI3516AV200
++	help
++	  Select this to enable cpuidle on Hi3516av200 processors.
++
++config ARM_HI3559_CPUIDLE
++	bool "CPU Idle Driver for Hi3559 processors"
++	depends on ARCH_HI3559
++	help
++	  Select this to enable cpuidle on Hi3559 processors.
++
++config ARM_HI3556_CPUIDLE
++	bool "CPU Idle Driver for Hi3556 processors"
++	depends on ARCH_HI3556
++	help
++	  Select this to enable cpuidle on Hi3556 processors.
+diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile
+index 4d177b9..00cda8b 100644
+--- a/drivers/cpuidle/Makefile
++++ b/drivers/cpuidle/Makefile
+@@ -17,7 +17,10 @@ obj-$(CONFIG_ARM_ZYNQ_CPUIDLE)		+= cpuidle-zynq.o
+ obj-$(CONFIG_ARM_U8500_CPUIDLE)         += cpuidle-ux500.o
+ obj-$(CONFIG_ARM_AT91_CPUIDLE)          += cpuidle-at91.o
+ obj-$(CONFIG_ARM_EXYNOS_CPUIDLE)        += cpuidle-exynos.o
+-
++obj-$(CONFIG_ARM_HI3519_CPUIDLE)	+= cpuidle-hi3519.o
++obj-$(CONFIG_ARM_HI3519V101_CPUIDLE)	+= cpuidle-hi3519.o
++obj-$(CONFIG_ARM_HI3516AV200_CPUIDLE)	+= cpuidle-hi3516av200.o
++obj-$(CONFIG_ARM_HI3556_CPUIDLE)	+= cpuidle-hi3559.o
+ ###############################################################################
+ # MIPS drivers
+ obj-$(CONFIG_MIPS_CPS_CPUIDLE)		+= cpuidle-cps.o
+diff --git a/drivers/cpuidle/cpuidle-hi3516av200.c b/drivers/cpuidle/cpuidle-hi3516av200.c
+new file mode 100644
+index 0000000..5d318ad
+--- /dev/null
++++ b/drivers/cpuidle/cpuidle-hi3516av200.c
+@@ -0,0 +1,286 @@
++/*
++ *
++ * Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include <linux/bitmap.h>
++#include <linux/cpuidle.h>
++#include <linux/cpu_pm.h>
++#include <linux/clockchips.h>
++#include <linux/debugfs.h>
++#include <linux/hrtimer.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/tick.h>
++#include <linux/vexpress.h>
++#include <linux/cpuidle.h>
++#include <asm/cputype.h>
++#include <asm/idmap.h>
++#include <asm/proc-fns.h>
++#include <asm/suspend.h>
++#include <linux/of.h>
++#include <asm/smp_plat.h>
++
++#include <asm/cacheflush.h>
++#include <asm/tlbflush.h>
++#include <asm/cp15.h>
++#include <asm/arch_timer.h>
++
++#include <linux/irqchip/arm-gic.h>
++#include <linux/arm-cci.h>
++#include <linux/delay.h>
++
++
++/* extern functions */
++extern void hi3516av200_set_cpu_jump(int cpu, phys_addr_t jumpaddr);
++extern void hi3516av200_cpu_resume(void);
++extern void hi_pmc_set_ac_inactive(void);
++extern void hi_pmc_automode_power_down(void);
++extern void hi_pmc_power_up_done(void);
++
++static int bl_cpuidle_simple_enter(struct cpuidle_device *dev,
++		struct cpuidle_driver *drv, int index);
++
++int bl_cpuidle_simple_enter(struct cpuidle_device *dev,
++		struct cpuidle_driver *drv, int index)
++{
++#if defined(CPUIDLE_DEBUG)
++	int cpuid = smp_processor_id();
++
++	pr_debug("%s cpu:%d enter", __func__, cpuid);
++#endif
++	cpu_do_idle();
++	return index;
++}
++
++static int bl_enter_cpu_powerdown(struct cpuidle_device *dev,
++				struct cpuidle_driver *drv, int idx);
++
++
++static struct cpuidle_state bl_cpuidle_set[] __initdata = {
++	[0] = {
++		.enter                  = bl_cpuidle_simple_enter,
++		.exit_latency           = 1,
++		.target_residency       = 1,
++		.power_usage		= UINT_MAX,
++		.flags                  = CPUIDLE_FLAG_TIME_VALID,
++		.name                   = "WFI",
++		.desc                   = "ARM WFI",
++	},
++	[1] = {
++		.enter			= bl_enter_cpu_powerdown,
++		.exit_latency		= 500,
++		.target_residency	= 1000,
++		.flags			= CPUIDLE_FLAG_TIME_VALID |
++					  CPUIDLE_FLAG_TIMER_STOP,
++		.name			= "C1",
++		.desc			= "ARM cpu A17 Cluster power down",
++	},
++};
++
++static struct cpuidle_driver bl_idle_driver = {
++	.name = "bl_idle",
++	.owner = THIS_MODULE,
++	.safe_state_index = 0
++};
++
++static DEFINE_PER_CPU(struct cpuidle_device, bl_idle_dev);
++
++static void bl_cpu_smp_disable(void)
++{
++	/* Set ACTLR.SMP to 0, AMP -> SMP */
++	asm volatile (
++	"	mrc	p15, 0, r0, c1, c0, 1\n"
++	"	bic	r0,  #0x40\n"
++	"	mcr	p15, 0, r0, c1, c0, 1\n"
++	  :
++	  :
++	  : "r0", "cc");
++}
++
++/*
++ * switch to init_mm, init_mm page table entries must in memory
++ * not in the cpu cache
++ */
++static void setup_mm_for_idle(void)
++{
++	struct mm_struct *mm = &init_mm;
++
++	cpu_switch_mm(mm->pgd, mm);
++	local_flush_bp_all();
++	local_flush_tlb_all();
++}
++
++static void bl_cpu_powerdown(u64 expected_residency)
++{
++	int cpu = smp_processor_id();
++	/* disable irq */
++	if (WARN(!irqs_disabled(), "Interrupts should be disabled\n"))
++		local_irq_disable();
++
++	/*
++	 * Once the Dcache is disabled and the tlb is empty, the ptw will
++	 * fetch page table entries for the code after Dcache disable from
++	 * memory, but the mm is active_mm from last user process's mm, and
++	 * the mm->pgd may located in cpu cache(see dcache_clean_area), so
++	 * switch to init_mm to avoid access fault.
++	 */
++	setup_mm_for_idle();
++	/* move the power code here to measure the idle enter time */
++	hi_pmc_automode_power_down();
++
++	gic_cpu_if_down();
++
++	/* close Dcache */
++	set_cr(get_cr() & ~CR_C);
++	/* CLREX */
++	asm volatile ("clrex");
++
++	/* Clean & Invalidata L1 Data Cache, L2 Cache */
++/*	for cortex a17 just one single instruction is enough
++	flush_cache_all();
++*/
++	/* clean&invalidate l1 cache */
++	asm volatile("mov r0, #0");
++	asm volatile("mcr p15, 1, r0, c15, c14, 0");
++	asm volatile("dsb");
++
++	/* clean&invalidate l2 cache */
++	asm volatile("mov r0, #2");
++	asm volatile("mcr p15, 1, r0, c15, c14, 0");
++	asm volatile("dsb");
++
++	/* switch SMP to AMP(ACTLR.SMP->1'b0) */
++	bl_cpu_smp_disable();
++
++	/* disable cci snoop */
++	cci_disable_port_by_cpu(cpu_logical_map(cpu));
++
++	/* asm volatile("mcr p14, 0, %0, c1, c3, 0" : : "r" (1)); */
++
++	/* ISB & DSB */
++	isb();
++	dsb();
++
++	hi_pmc_set_ac_inactive();
++/*
++	hi_pmc_automode_power_down();
++*/
++	dsb();
++	/* WFI */
++	while (1)
++		wfi();
++
++	BUG();
++}
++
++static int bl_cpu_powered_up(void)
++{
++	/*dcache enble*/
++	set_cr(get_cr() | CR_C);
++
++	hi_pmc_power_up_done();
++
++	return 0;
++}
++
++
++static int notrace bl_cpu_powerdown_finisher(unsigned long arg)
++{
++	hi3516av200_set_cpu_jump(smp_processor_id(),
++				(phys_addr_t)virt_to_phys(hi3516av200_cpu_resume));
++
++	bl_cpu_powerdown(0);
++
++	return 1;
++}
++
++/*
++ * bl_enter_cpu_powerdown - Programs CPU to enter the specified state
++ * @dev: cpuidle device
++ * @drv: The target state to be programmed
++ * @idx: state index
++ *
++ * Called from the CPUidle framework to program the device to the
++ * specified target state selected by the governor.
++ */
++int bl_enter_cpu_powerdown(struct cpuidle_device *dev,
++				struct cpuidle_driver *drv, int idx)
++{
++	int cpuid = smp_processor_id();
++
++	/* A7 can not power down */
++	if (cpuid == 0) {
++		cpu_do_idle();
++		return idx;
++	}
++
++	BUG_ON(!irqs_disabled());
++
++	cpu_pm_enter();
++
++	cpu_suspend((unsigned long) dev, bl_cpu_powerdown_finisher);
++
++	bl_cpu_powered_up();
++
++	cpu_pm_exit();
++
++	return idx;
++}
++/*
++ * bl_idle_init
++ *
++ * Registers the bl specific cpuidle driver with the cpuidle
++ * framework with the valid set of states.
++ */
++
++static int __init bl_idle_init(void)
++{
++	struct cpuidle_device *dev;
++	int i, cpu_id;
++	struct cpuidle_driver *drv = &bl_idle_driver;
++
++	drv->state_count = (sizeof(bl_cpuidle_set) /
++			sizeof(struct cpuidle_state));
++
++
++	for (i = 0; i < drv->state_count; i++) {
++		memcpy(&drv->states[i], &bl_cpuidle_set[i],
++				sizeof(struct cpuidle_state));
++	}
++	cpuidle_register_driver(drv);
++
++	for_each_cpu(cpu_id, cpu_online_mask) {
++		/* cpu 0 use default idle */
++		if (cpu_id == 0)
++			continue;
++		pr_err("CPUidle for CPU%d registered\n", cpu_id);
++		dev = &per_cpu(bl_idle_dev, cpu_id);
++		dev->cpu = cpu_id;
++
++		if (cpuidle_register_device(dev)) {
++			pr_err("%s: Cpuidle register device failed\n",
++					__func__);
++			return -EIO;
++		}
++	}
++
++
++	return 0;
++}
++
++device_initcall(bl_idle_init);
+diff --git a/drivers/cpuidle/cpuidle-hi3519.c b/drivers/cpuidle/cpuidle-hi3519.c
+new file mode 100644
+index 0000000..f3d952c
+--- /dev/null
++++ b/drivers/cpuidle/cpuidle-hi3519.c
+@@ -0,0 +1,274 @@
++/**
++ * cpuidle-hi3519.c
++ *
++ * Copyright (c) 2009-2014, HiSilicon Technologies Co., Ltd.
++ * All rights reserved.
++ */
++
++#include <linux/bitmap.h>
++#include <linux/cpuidle.h>
++#include <linux/cpu_pm.h>
++#include <linux/clockchips.h>
++#include <linux/debugfs.h>
++#include <linux/hrtimer.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/tick.h>
++#include <linux/vexpress.h>
++#include <linux/cpuidle.h>
++#include <asm/cputype.h>
++#include <asm/idmap.h>
++#include <asm/proc-fns.h>
++#include <asm/suspend.h>
++#include <linux/of.h>
++#include <asm/smp_plat.h>
++
++#include <asm/cacheflush.h>
++#include <asm/tlbflush.h>
++#include <asm/cp15.h>
++#include <asm/arch_timer.h>
++
++#include <linux/irqchip/arm-gic.h>
++#include <linux/arm-cci.h>
++#include <linux/delay.h>
++
++
++/* extern functions */
++extern void hi3519_set_cpu_jump(int cpu, phys_addr_t jumpaddr);
++extern void hi3519_cpu_resume(void);
++extern void hi_pmc_set_ac_inactive(void);
++extern void hi_pmc_automode_power_down(void);
++extern void hi_pmc_power_up_done(void);
++
++static int bl_cpuidle_simple_enter(struct cpuidle_device *dev,
++		struct cpuidle_driver *drv, int index);
++
++int bl_cpuidle_simple_enter(struct cpuidle_device *dev,
++		struct cpuidle_driver *drv, int index)
++{
++#if defined(CPUIDLE_DEBUG)
++	int cpuid = smp_processor_id();
++
++	pr_debug("%s cpu:%d enter", __func__, cpuid);
++#endif
++	cpu_do_idle();
++	return index;
++}
++
++static int bl_enter_cpu_powerdown(struct cpuidle_device *dev,
++				struct cpuidle_driver *drv, int idx);
++
++
++static struct cpuidle_state bl_cpuidle_set[] __initdata = {
++	[0] = {
++		.enter                  = bl_cpuidle_simple_enter,
++		.exit_latency           = 1,
++		.target_residency       = 1,
++		.power_usage		= UINT_MAX,
++		.flags                  = CPUIDLE_FLAG_TIME_VALID,
++		.name                   = "WFI",
++		.desc                   = "ARM WFI",
++	},
++	[1] = {
++		.enter			= bl_enter_cpu_powerdown,
++		.exit_latency		= 500,
++		.target_residency	= 1000,
++		.flags			= CPUIDLE_FLAG_TIME_VALID |
++					  CPUIDLE_FLAG_TIMER_STOP,
++		.name			= "C1",
++		.desc			= "ARM cpu A17 Cluster power down",
++	},
++};
++
++static struct cpuidle_driver bl_idle_driver = {
++	.name = "bl_idle",
++	.owner = THIS_MODULE,
++	.safe_state_index = 0
++};
++
++static DEFINE_PER_CPU(struct cpuidle_device, bl_idle_dev);
++
++static void bl_cpu_smp_disable(void)
++{
++	/* Set ACTLR.SMP to 0, AMP -> SMP */
++	asm volatile (
++	"	mrc	p15, 0, r0, c1, c0, 1\n"
++	"	bic	r0,  #0x40\n"
++	"	mcr	p15, 0, r0, c1, c0, 1\n"
++	  :
++	  :
++	  : "r0", "cc");
++}
++
++/*
++ * switch to init_mm, init_mm page table entries must in memory
++ * not in the cpu cache
++ */
++static void setup_mm_for_idle(void)
++{
++	struct mm_struct *mm = &init_mm;
++
++	cpu_switch_mm(mm->pgd, mm);
++	local_flush_bp_all();
++	local_flush_tlb_all();
++}
++
++static void bl_cpu_powerdown(u64 expected_residency)
++{
++	int cpu = smp_processor_id();
++	/* disable irq */
++	if (WARN(!irqs_disabled(), "Interrupts should be disabled\n"))
++		local_irq_disable();
++
++	/*
++	 * Once the Dcache is disabled and the tlb is empty, the ptw will
++	 * fetch page table entries for the code after Dcache disable from
++	 * memory, but the mm is active_mm from last user process's mm, and
++	 * the mm->pgd may located in cpu cache(see dcache_clean_area), so
++	 * switch to init_mm to avoid access fault.
++	 */
++	setup_mm_for_idle();
++	/* move the power code here to measure the idle enter time */
++	hi_pmc_automode_power_down();
++
++	gic_cpu_if_down();
++
++	/* close Dcache */
++	set_cr(get_cr() & ~CR_C);
++	/* CLREX */
++	asm volatile ("clrex");
++
++	/* Clean & Invalidata L1 Data Cache, L2 Cache */
++/*	for cortex a17 just one single instruction is enough
++	flush_cache_all();
++*/
++	/* clean&invalidate l1 cache */
++	asm volatile("mov r0, #0");
++	asm volatile("mcr p15, 1, r0, c15, c14, 0");
++	asm volatile("dsb");
++
++	/* clean&invalidate l2 cache */
++	asm volatile("mov r0, #2");
++	asm volatile("mcr p15, 1, r0, c15, c14, 0");
++	asm volatile("dsb");
++
++	/* switch SMP to AMP(ACTLR.SMP->1'b0) */
++	bl_cpu_smp_disable();
++
++	/* disable cci snoop */
++	cci_disable_port_by_cpu(cpu_logical_map(cpu));
++
++	/* asm volatile("mcr p14, 0, %0, c1, c3, 0" : : "r" (1)); */
++
++	/* ISB & DSB */
++	isb();
++	dsb();
++
++	hi_pmc_set_ac_inactive();
++/*
++	hi_pmc_automode_power_down();
++*/
++	dsb();
++	/* WFI */
++	while (1)
++		wfi();
++
++	BUG();
++}
++
++static int bl_cpu_powered_up(void)
++{
++	/*dcache enble*/
++	set_cr(get_cr() | CR_C);
++
++	hi_pmc_power_up_done();
++
++	return 0;
++}
++
++
++static int notrace bl_cpu_powerdown_finisher(unsigned long arg)
++{
++	hi3519_set_cpu_jump(smp_processor_id(),
++				(phys_addr_t)virt_to_phys(hi3519_cpu_resume));
++
++	bl_cpu_powerdown(0);
++
++	return 1;
++}
++
++/*
++ * bl_enter_cpu_powerdown - Programs CPU to enter the specified state
++ * @dev: cpuidle device
++ * @drv: The target state to be programmed
++ * @idx: state index
++ *
++ * Called from the CPUidle framework to program the device to the
++ * specified target state selected by the governor.
++ */
++int bl_enter_cpu_powerdown(struct cpuidle_device *dev,
++				struct cpuidle_driver *drv, int idx)
++{
++	int cpuid = smp_processor_id();
++
++	/* A7 can not power down */
++	if (cpuid == 0) {
++		cpu_do_idle();
++		return idx;
++	}
++
++	BUG_ON(!irqs_disabled());
++
++	cpu_pm_enter();
++
++	cpu_suspend((unsigned long) dev, bl_cpu_powerdown_finisher);
++
++	bl_cpu_powered_up();
++
++	cpu_pm_exit();
++
++	return idx;
++}
++/*
++ * bl_idle_init
++ *
++ * Registers the bl specific cpuidle driver with the cpuidle
++ * framework with the valid set of states.
++ */
++
++static int __init bl_idle_init(void)
++{
++	struct cpuidle_device *dev;
++	int i, cpu_id;
++	struct cpuidle_driver *drv = &bl_idle_driver;
++
++	drv->state_count = (sizeof(bl_cpuidle_set) /
++			sizeof(struct cpuidle_state));
++
++
++	for (i = 0; i < drv->state_count; i++) {
++		memcpy(&drv->states[i], &bl_cpuidle_set[i],
++				sizeof(struct cpuidle_state));
++	}
++	cpuidle_register_driver(drv);
++
++	for_each_cpu(cpu_id, cpu_online_mask) {
++		/* cpu 0 use default idle */
++		if (cpu_id == 0)
++			continue;
++		pr_err("CPUidle for CPU%d registered\n", cpu_id);
++		dev = &per_cpu(bl_idle_dev, cpu_id);
++		dev->cpu = cpu_id;
++
++		if (cpuidle_register_device(dev)) {
++			pr_err("%s: Cpuidle register device failed\n",
++					__func__);
++			return -EIO;
++		}
++	}
++
++
++	return 0;
++}
++
++device_initcall(bl_idle_init);
+diff --git a/drivers/cpuidle/cpuidle-hi3559.c b/drivers/cpuidle/cpuidle-hi3559.c
+new file mode 100644
+index 0000000..1e18ae4
+--- /dev/null
++++ b/drivers/cpuidle/cpuidle-hi3559.c
+@@ -0,0 +1,253 @@
++/**
++ * cpuidle-hi3559.c
++ *
++ * Copyright (c) 2009-2014, HiSilicon Technologies Co., Ltd.
++ * All rights reserved.
++ */
++
++#include <linux/bitmap.h>
++#include <linux/cpuidle.h>
++#include <linux/cpu_pm.h>
++#include <linux/clockchips.h>
++#include <linux/debugfs.h>
++#include <linux/hrtimer.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/tick.h>
++#include <linux/vexpress.h>
++#include <linux/cpuidle.h>
++#include <asm/cputype.h>
++#include <asm/idmap.h>
++#include <asm/proc-fns.h>
++#include <asm/suspend.h>
++#include <linux/of.h>
++#include <asm/smp_plat.h>
++
++#include <asm/cacheflush.h>
++#include <asm/tlbflush.h>
++#include <asm/cp15.h>
++#include <asm/arch_timer.h>
++
++#include <linux/irqchip/arm-gic.h>
++#include <linux/arm-cci.h>
++#include <linux/delay.h>
++
++
++/* extern functions */
++extern void hi3559_set_cpu_jump(int cpu, phys_addr_t jumpaddr);
++extern void hi3559_cpu_resume(void);
++extern void hi_pmc_set_ac_inactive(void);
++extern void hi_pmc_automode_power_down(void);
++extern void hi_pmc_power_up_done(void);
++
++static int bl_cpuidle_simple_enter(struct cpuidle_device *dev,
++		struct cpuidle_driver *drv, int index);
++
++int bl_cpuidle_simple_enter(struct cpuidle_device *dev,
++		struct cpuidle_driver *drv, int index)
++{
++#if defined(CPUIDLE_DEBUG)
++	int cpuid = smp_processor_id();
++
++	pr_debug("%s cpu:%d enter", __func__, cpuid);
++#endif
++	cpu_do_idle();
++	return index;
++}
++
++static int bl_enter_cpu_powerdown(struct cpuidle_device *dev,
++				struct cpuidle_driver *drv, int idx);
++
++
++static struct cpuidle_state bl_cpuidle_set[] __initdata = {
++	[0] = {
++		.enter                  = bl_cpuidle_simple_enter,
++		.exit_latency           = 1,
++		.target_residency       = 1,
++		.power_usage		= UINT_MAX,
++		.flags                  = CPUIDLE_FLAG_TIME_VALID,
++		.name                   = "WFI",
++		.desc                   = "ARM WFI",
++	},
++	[1] = {
++		.enter			= bl_enter_cpu_powerdown,
++		.exit_latency		= 500,
++		.target_residency	= 1000,
++		.flags			= CPUIDLE_FLAG_TIME_VALID |
++					  CPUIDLE_FLAG_TIMER_STOP,
++		.name			= "C1",
++		.desc			= "ARM cpu A17 Cluster power down",
++	},
++};
++
++static struct cpuidle_driver bl_idle_driver = {
++	.name = "bl_idle",
++	.owner = THIS_MODULE,
++	.safe_state_index = 0
++};
++
++static DEFINE_PER_CPU(struct cpuidle_device, bl_idle_dev);
++
++static void bl_cpu_smp_disable(void)
++{
++	/* Set ACTLR.SMP to 0, AMP -> SMP */
++	asm volatile (
++	"	mrc	p15, 0, r0, c1, c0, 1\n"
++	"	bic	r0,  #0x40\n"
++	"	mcr	p15, 0, r0, c1, c0, 1\n"
++	  :
++	  :
++	  : "r0", "cc");
++}
++
++static void bl_cpu_powerdown(u64 expected_residency)
++{
++	int cpu = smp_processor_id();
++	/* disable irq */
++	if (WARN(!irqs_disabled(), "Interrupts should be disabled\n"))
++		local_irq_disable();
++
++	/* move the power code here to measure the idle enter time */
++	hi_pmc_automode_power_down();
++
++	gic_cpu_if_down();
++
++	/* close Dcache */
++	set_cr(get_cr() & ~CR_C);
++	/* CLREX */
++	asm volatile ("clrex");
++
++	/* Clean & Invalidata L1 Data Cache, L2 Cache */
++/*	for cortex a17 just one single instruction is enough
++	flush_cache_all();
++*/
++	/* clean&invalidate l1 cache */
++	asm volatile("mov r0, #0");
++	asm volatile("mcr p15, 1, r0, c15, c14, 0");
++	asm volatile("dsb");
++
++	/* clean&invalidate l2 cache */
++	asm volatile("mov r0, #2");
++	asm volatile("mcr p15, 1, r0, c15, c14, 0");
++	asm volatile("dsb");
++
++	/* switch SMP to AMP(ACTLR.SMP->1'b0) */
++	bl_cpu_smp_disable();
++
++	/* disable cci snoop */
++	cci_disable_port_by_cpu(cpu_logical_map(cpu));
++
++	/* asm volatile("mcr p14, 0, %0, c1, c3, 0" : : "r" (1)); */
++
++	/* ISB & DSB */
++	isb();
++	dsb();
++
++	hi_pmc_set_ac_inactive();
++/*
++	hi_pmc_automode_power_down();
++*/
++	dsb();
++	/* WFI */
++	while (1)
++		wfi();
++
++	BUG();
++}
++
++static int bl_cpu_powered_up(void)
++{
++	/*dcache enble*/
++	set_cr(get_cr() | CR_C);
++
++	hi_pmc_power_up_done();
++
++	return 0;
++}
++
++
++static int notrace bl_cpu_powerdown_finisher(unsigned long arg)
++{
++	hi3559_set_cpu_jump(smp_processor_id(),
++				(phys_addr_t)virt_to_phys(hi3559_cpu_resume));
++
++	bl_cpu_powerdown(0);
++
++	return 1;
++}
++
++/*
++ * bl_enter_cpu_powerdown - Programs CPU to enter the specified state
++ * @dev: cpuidle device
++ * @drv: The target state to be programmed
++ * @idx: state index
++ *
++ * Called from the CPUidle framework to program the device to the
++ * specified target state selected by the governor.
++ */
++int bl_enter_cpu_powerdown(struct cpuidle_device *dev,
++				struct cpuidle_driver *drv, int idx)
++{
++	int cpuid = smp_processor_id();
++
++	/* A7 can not power down */
++	if (cpuid == 0) {
++		cpu_do_idle();
++		return idx;
++	}
++
++	BUG_ON(!irqs_disabled());
++
++	cpu_pm_enter();
++
++	cpu_suspend((unsigned long) dev, bl_cpu_powerdown_finisher);
++
++	bl_cpu_powered_up();
++
++	cpu_pm_exit();
++
++	return idx;
++}
++/*
++ * bl_idle_init
++ *
++ * Registers the bl specific cpuidle driver with the cpuidle
++ * framework with the valid set of states.
++ */
++
++static int __init bl_idle_init(void)
++{
++	struct cpuidle_device *dev;
++	int i, cpu_id;
++	struct cpuidle_driver *drv = &bl_idle_driver;
++
++	drv->state_count = (sizeof(bl_cpuidle_set) /
++			sizeof(struct cpuidle_state));
++
++
++	for (i = 0; i < drv->state_count; i++) {
++		memcpy(&drv->states[i], &bl_cpuidle_set[i],
++				sizeof(struct cpuidle_state));
++	}
++	cpuidle_register_driver(drv);
++
++	for_each_cpu(cpu_id, cpu_online_mask) {
++		/* cpu 0 use default idle */
++		if (cpu_id == 0)
++			continue;
++		pr_err("CPUidle for CPU%d registered\n", cpu_id);
++		dev = &per_cpu(bl_idle_dev, cpu_id);
++		dev->cpu = cpu_id;
++
++		if (cpuidle_register_device(dev)) {
++			pr_err("%s: Cpuidle register device failed\n",
++					__func__);
++			return -EIO;
++		}
++	}
++
++
++	return 0;
++}
++
++device_initcall(bl_idle_init);
+diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
+index 710a233..386261a 100644
+--- a/drivers/cpuidle/governors/menu.c
++++ b/drivers/cpuidle/governors/menu.c
+@@ -178,7 +178,12 @@ static inline int performance_multiplier(unsigned long nr_iowaiters, unsigned lo
+ 
+ 	/* for higher loadavg, we are more reluctant */
+ 
+-	mult += 2 * get_loadavg(load);
++	/*
++	 * this doesn't work as intended - it is almost always 0, but can
++	 * sometimes, depending on workload, spike very high into the hundreds
++	 * even when the average cpu load is under 10%.
++	 */
++	/* mult += 2 * get_loadavg(); */
+ 
+ 	/* for IO wait tasks (per cpu!) we add 5x each */
+ 	mult += 10 * nr_iowaiters;
+diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
+index e34024b..f2bfbec 100644
+--- a/drivers/dma/amba-pl08x.c
++++ b/drivers/dma/amba-pl08x.c
+@@ -87,6 +87,8 @@
+ #include <linux/init.h>
+ #include <linux/interrupt.h>
+ #include <linux/module.h>
++#include <linux/of.h>
++#include <linux/of_dma.h>
+ #include <linux/pm_runtime.h>
+ #include <linux/seq_file.h>
+ #include <linux/slab.h>
+@@ -103,16 +105,20 @@ struct pl08x_driver_data;
+ /**
+  * struct vendor_data - vendor-specific config parameters for PL08x derivatives
+  * @channels: the number of channels available in this variant
++ * @signals: the number of request signals available from the hardware
+  * @dualmaster: whether this version supports dual AHB masters or not.
+  * @nomadik: whether the channels have Nomadik security extension bits
+  *	that need to be checked for permission before use and some registers are
+  *	missing
+  * @pl080s: whether this version is a PL080S, which has separate register and
+  *	LLI word for transfer size.
++ * @max_transfer_size: the maximum single element transfer size for this
++ *	PL08x variant.
+  */
+ struct vendor_data {
+ 	u8 config_offset;
+ 	u8 channels;
++	u8 signals;
+ 	bool dualmaster;
+ 	bool nomadik;
+ 	bool pl080s;
+@@ -231,7 +237,7 @@ struct pl08x_dma_chan {
+ 	struct virt_dma_chan vc;
+ 	struct pl08x_phy_chan *phychan;
+ 	const char *name;
+-	const struct pl08x_channel_data *cd;
++	struct pl08x_channel_data *cd;
+ 	struct dma_slave_config cfg;
+ 	struct pl08x_txd *at;
+ 	struct pl08x_driver_data *host;
+@@ -472,7 +478,7 @@ static void pl08x_terminate_phy_chan(struct pl08x_driver_data *pl08x,
+ 	u32 val = readl(ch->reg_config);
+ 
+ 	val &= ~(PL080_CONFIG_ENABLE | PL080_CONFIG_ERR_IRQ_MASK |
+-	         PL080_CONFIG_TC_IRQ_MASK);
++		 PL080_CONFIG_TC_IRQ_MASK);
+ 
+ 	writel(val, ch->reg_config);
+ 
+@@ -1354,9 +1360,9 @@ static u32 pl08x_burst(u32 maxburst)
+ 
+ 	for (i = 0; i < ARRAY_SIZE(burst_sizes); i++)
+ 		if (burst_sizes[i].burstwords <= maxburst)
+-			break;
++			return burst_sizes[i].reg;
+ 
+-	return burst_sizes[i].reg;
++	return ~0;
+ }
+ 
+ static u32 pl08x_get_cctl(struct pl08x_dma_chan *plchan,
+@@ -1380,6 +1386,8 @@ static u32 pl08x_get_cctl(struct pl08x_dma_chan *plchan,
+ 		maxburst = 1;
+ 
+ 	burst = pl08x_burst(maxburst);
++	if (burst == ~0)
++		return ~0;
+ 	cctl |= burst << PL080_CONTROL_SB_SIZE_SHIFT;
+ 	cctl |= burst << PL080_CONTROL_DB_SIZE_SHIFT;
+ 
+@@ -1892,6 +1900,12 @@ static int pl08x_dma_init_virtual_channels(struct pl08x_driver_data *pl08x,
+ 
+ 		if (slave) {
+ 			chan->cd = &pl08x->pd->slave_channels[i];
++			/*
++			 * Some implementations have muxed signals, whereas some
++			 * use a mux in front of the signals and need dynamic
++			 * assignment of signals.
++			 */
++			chan->signal = i;
+ 			pl08x_dma_slave_init(chan);
+ 		} else {
+ 			chan->cd = &pl08x->pd->memcpy_channel;
+@@ -2015,10 +2029,204 @@ static inline void init_pl08x_debugfs(struct pl08x_driver_data *pl08x)
+ }
+ #endif
+ 
++#ifdef CONFIG_OF
++static struct dma_chan *pl08x_find_chan_id(struct pl08x_driver_data *pl08x,
++					 u32 id)
++{
++	struct pl08x_dma_chan *chan;
++
++	list_for_each_entry(chan, &pl08x->slave.channels, vc.chan.device_node) {
++		if (chan->signal == id)
++			return &chan->vc.chan;
++	}
++
++	return NULL;
++}
++
++static struct dma_chan *pl08x_of_xlate(struct of_phandle_args *dma_spec,
++				       struct of_dma *ofdma)
++{
++	struct pl08x_driver_data *pl08x = ofdma->of_dma_data;
++	struct dma_chan *dma_chan;
++	struct pl08x_dma_chan *plchan;
++
++	if (!pl08x)
++		return NULL;
++
++	if (dma_spec->args_count != 2) {
++		dev_err(&pl08x->adev->dev,
++			"DMA channel translation requires two cells\n");
++		return NULL;
++	}
++
++	dma_chan = pl08x_find_chan_id(pl08x, dma_spec->args[0]);
++	if (!dma_chan) {
++		dev_err(&pl08x->adev->dev,
++			"DMA slave channel not found\n");
++		return NULL;
++	}
++
++	plchan = to_pl08x_chan(dma_chan);
++	dev_dbg(&pl08x->adev->dev,
++		"translated channel for signal %d\n",
++		dma_spec->args[0]);
++
++	/* Augment channel data for applicable AHB buses */
++	plchan->cd->periph_buses = dma_spec->args[1];
++	return dma_get_slave_channel(dma_chan);
++}
++
++static int pl08x_of_probe(struct amba_device *adev,
++			  struct pl08x_driver_data *pl08x,
++			  struct device_node *np)
++{
++	struct pl08x_platform_data *pd;
++	struct pl08x_channel_data *chanp = NULL;
++	u32 cctl_memcpy = 0;
++	u32 val;
++	int ret;
++	int i;
++
++	pd = devm_kzalloc(&adev->dev, sizeof(*pd), GFP_KERNEL);
++	if (!pd)
++		return -ENOMEM;
++
++	/* Eligible bus masters for fetching LLIs */
++	if (of_property_read_bool(np, "lli-bus-interface-ahb1"))
++		pd->lli_buses |= PL08X_AHB1;
++	if (of_property_read_bool(np, "lli-bus-interface-ahb2"))
++		pd->lli_buses |= PL08X_AHB2;
++	if (!pd->lli_buses) {
++		dev_info(&adev->dev, "no bus masters for LLIs stated, assume all\n");
++		pd->lli_buses |= PL08X_AHB1 | PL08X_AHB2;
++	}
++
++	/* Eligible bus masters for memory access */
++	if (of_property_read_bool(np, "mem-bus-interface-ahb1"))
++		pd->mem_buses |= PL08X_AHB1;
++	if (of_property_read_bool(np, "mem-bus-interface-ahb2"))
++		pd->mem_buses |= PL08X_AHB2;
++	if (!pd->mem_buses) {
++		dev_info(&adev->dev, "no bus masters for memory stated, assume all\n");
++		pd->mem_buses |= PL08X_AHB1 | PL08X_AHB2;
++	}
++
++	/* Parse the memcpy channel properties */
++	ret = of_property_read_u32(np, "memcpy-burst-size", &val);
++	if (ret) {
++		dev_info(&adev->dev, "no memcpy burst size specified, using 1 byte\n");
++		val = 1;
++	}
++	switch (val) {
++	default:
++		dev_err(&adev->dev, "illegal burst size for memcpy, set to 1\n");
++		/* Fall through */
++	case 1:
++		cctl_memcpy |= PL080_BSIZE_1 << PL080_CONTROL_SB_SIZE_SHIFT |
++			       PL080_BSIZE_1 << PL080_CONTROL_DB_SIZE_SHIFT;
++		break;
++	case 4:
++		cctl_memcpy |= PL080_BSIZE_4 << PL080_CONTROL_SB_SIZE_SHIFT |
++			       PL080_BSIZE_4 << PL080_CONTROL_DB_SIZE_SHIFT;
++		break;
++	case 8:
++		cctl_memcpy |= PL080_BSIZE_8 << PL080_CONTROL_SB_SIZE_SHIFT |
++			       PL080_BSIZE_8 << PL080_CONTROL_DB_SIZE_SHIFT;
++		break;
++	case 16:
++		cctl_memcpy |= PL080_BSIZE_16 << PL080_CONTROL_SB_SIZE_SHIFT |
++			       PL080_BSIZE_16 << PL080_CONTROL_DB_SIZE_SHIFT;
++		break;
++	case 32:
++		cctl_memcpy |= PL080_BSIZE_32 << PL080_CONTROL_SB_SIZE_SHIFT |
++			       PL080_BSIZE_32 << PL080_CONTROL_DB_SIZE_SHIFT;
++		break;
++	case 64:
++		cctl_memcpy |= PL080_BSIZE_64 << PL080_CONTROL_SB_SIZE_SHIFT |
++			       PL080_BSIZE_64 << PL080_CONTROL_DB_SIZE_SHIFT;
++		break;
++	case 128:
++		cctl_memcpy |= PL080_BSIZE_128 << PL080_CONTROL_SB_SIZE_SHIFT |
++			       PL080_BSIZE_128 << PL080_CONTROL_DB_SIZE_SHIFT;
++		break;
++	case 256:
++		cctl_memcpy |= PL080_BSIZE_256 << PL080_CONTROL_SB_SIZE_SHIFT |
++			       PL080_BSIZE_256 << PL080_CONTROL_DB_SIZE_SHIFT;
++		break;
++	}
++
++	ret = of_property_read_u32(np, "memcpy-bus-width", &val);
++	if (ret) {
++		dev_info(&adev->dev, "no memcpy bus width specified, using 8 bits\n");
++		val = 8;
++	}
++	switch (val) {
++	default:
++		dev_err(&adev->dev, "illegal bus width for memcpy, set to 8 bits\n");
++		/* Fall through */
++	case 8:
++		cctl_memcpy |= PL080_WIDTH_8BIT << PL080_CONTROL_SWIDTH_SHIFT |
++			       PL080_WIDTH_8BIT << PL080_CONTROL_DWIDTH_SHIFT;
++		break;
++	case 16:
++		cctl_memcpy |= PL080_WIDTH_16BIT << PL080_CONTROL_SWIDTH_SHIFT |
++			       PL080_WIDTH_16BIT << PL080_CONTROL_DWIDTH_SHIFT;
++		break;
++	case 32:
++		cctl_memcpy |= PL080_WIDTH_32BIT << PL080_CONTROL_SWIDTH_SHIFT |
++			       PL080_WIDTH_32BIT << PL080_CONTROL_DWIDTH_SHIFT;
++		break;
++	}
++
++	/* This is currently the only thing making sense */
++	cctl_memcpy |= PL080_CONTROL_PROT_SYS;
++
++	/* Set up memcpy channel */
++	pd->memcpy_channel.bus_id = "memcpy";
++	pd->memcpy_channel.cctl_memcpy = cctl_memcpy;
++	/* Use the buses that can access memory, obviously */
++	pd->memcpy_channel.periph_buses = pd->mem_buses;
++
++	/*
++	 * Allocate channel data for all possible slave channels (one
++	 * for each possible signal), channels will then be allocated
++	 * for a device and have it's AHB interfaces set up at
++	 * translation time.
++	 */
++	chanp = devm_kcalloc(&adev->dev,
++			pl08x->vd->signals,
++			sizeof(struct pl08x_channel_data),
++			GFP_KERNEL);
++	if (!chanp)
++		return -ENOMEM;
++
++	pd->slave_channels = chanp;
++	for (i = 0; i < pl08x->vd->signals; i++) {
++		/* chanp->periph_buses will be assigned at translation */
++		chanp->bus_id = kasprintf(GFP_KERNEL, "slave%d", i);
++		chanp++;
++	}
++	pd->num_slave_channels = pl08x->vd->signals;
++
++	pl08x->pd = pd;
++
++	return of_dma_controller_register(adev->dev.of_node, pl08x_of_xlate,
++					  pl08x);
++}
++#else
++static inline int pl08x_of_probe(struct amba_device *adev,
++				 struct pl08x_driver_data *pl08x,
++				 struct device_node *np)
++{
++	return -EINVAL;
++}
++#endif
++
+ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
+ {
+ 	struct pl08x_driver_data *pl08x;
+ 	const struct vendor_data *vd = id->data;
++	struct device_node *np = adev->dev.of_node;
+ 	u32 tsfr_size;
+ 	int ret = 0;
+ 	int i;
+@@ -2039,6 +2247,10 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
+ 		goto out_no_pl08x;
+ 	}
+ 
++	/* Assign useful pointers to the driver state */
++	pl08x->adev = adev;
++	pl08x->vd = vd;
++
+ 	/* Initialize memcpy engine */
+ 	dma_cap_set(DMA_MEMCPY, pl08x->memcpy.cap_mask);
+ 	pl08x->memcpy.dev = &adev->dev;
+@@ -2066,15 +2278,17 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
+ 	/* Get the platform data */
+ 	pl08x->pd = dev_get_platdata(&adev->dev);
+ 	if (!pl08x->pd) {
+-		dev_err(&adev->dev, "no platform data supplied\n");
+-		ret = -EINVAL;
+-		goto out_no_platdata;
++		if (np) {
++			ret = pl08x_of_probe(adev, pl08x, np);
++			if (ret)
++				goto out_no_platdata;
++		} else {
++			dev_err(&adev->dev, "no platform data supplied\n");
++			ret = -EINVAL;
++			goto out_no_platdata;
++		}
+ 	}
+ 
+-	/* Assign useful pointers to the driver state */
+-	pl08x->adev = adev;
+-	pl08x->vd = vd;
+-
+ 	/* By default, AHB1 only.  If dualmaster, from platform */
+ 	pl08x->lli_buses = PL08X_AHB1;
+ 	pl08x->mem_buses = PL08X_AHB1;
+@@ -2224,9 +2438,18 @@ out_no_pl08x:
+ }
+ 
+ /* PL080 has 8 channels and the PL080 have just 2 */
++static struct vendor_data vendor_pl080_hibvt = {
++	.config_offset = PL080_CH_CONFIG,
++	.channels = 4,
++	.signals = 16,
++	.dualmaster = true,
++	.max_transfer_size = PL080_CONTROL_TRANSFER_SIZE_MASK,
++};
++
+ static struct vendor_data vendor_pl080 = {
+ 	.config_offset = PL080_CH_CONFIG,
+ 	.channels = 8,
++	.signals = 16,
+ 	.dualmaster = true,
+ 	.max_transfer_size = PL080_CONTROL_TRANSFER_SIZE_MASK,
+ };
+@@ -2234,6 +2457,7 @@ static struct vendor_data vendor_pl080 = {
+ static struct vendor_data vendor_nomadik = {
+ 	.config_offset = PL080_CH_CONFIG,
+ 	.channels = 8,
++	.signals = 32,
+ 	.dualmaster = true,
+ 	.nomadik = true,
+ 	.max_transfer_size = PL080_CONTROL_TRANSFER_SIZE_MASK,
+@@ -2242,6 +2466,7 @@ static struct vendor_data vendor_nomadik = {
+ static struct vendor_data vendor_pl080s = {
+ 	.config_offset = PL080S_CH_CONFIG,
+ 	.channels = 8,
++	.signals = 32,
+ 	.pl080s = true,
+ 	.max_transfer_size = PL080S_CONTROL_TRANSFER_SIZE_MASK,
+ };
+@@ -2249,11 +2474,18 @@ static struct vendor_data vendor_pl080s = {
+ static struct vendor_data vendor_pl081 = {
+ 	.config_offset = PL080_CH_CONFIG,
+ 	.channels = 2,
++	.signals = 16,
+ 	.dualmaster = false,
+ 	.max_transfer_size = PL080_CONTROL_TRANSFER_SIZE_MASK,
+ };
+ 
+ static struct amba_id pl08x_ids[] = {
++	/* Hisilicon BVT PL080 variant */
++	{
++		.id	= 0x0a141080,
++		.mask	= 0xffffffff,
++		.data	= &vendor_pl080_hibvt,
++	},
+ 	/* Samsung PL080S variant */
+ 	{
+ 		.id	= 0x0a141080,
+diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c
+index 84b49cf..30b2818 100644
+--- a/drivers/gpio/gpio-pl061.c
++++ b/drivers/gpio/gpio-pl061.c
+@@ -12,6 +12,7 @@
+ #include <linux/spinlock.h>
+ #include <linux/errno.h>
+ #include <linux/module.h>
++#include <linux/interrupt.h>
+ #include <linux/io.h>
+ #include <linux/ioport.h>
+ #include <linux/irq.h>
+@@ -181,15 +182,12 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger)
+ 	return 0;
+ }
+ 
+-static void pl061_irq_handler(unsigned irq, struct irq_desc *desc)
++static irqreturn_t pl061_irq_handler(int irq, void *data)
+ {
+ 	unsigned long pending;
+ 	int offset;
+-	struct gpio_chip *gc = irq_desc_get_handler_data(desc);
++	struct gpio_chip *gc = data;
+ 	struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
+-	struct irq_chip *irqchip = irq_desc_get_chip(desc);
+-
+-	chained_irq_enter(irqchip, desc);
+ 
+ 	pending = readb(chip->base + GPIOMIS);
+ 	writeb(pending, chip->base + GPIOIC);
+@@ -199,7 +197,7 @@ static void pl061_irq_handler(unsigned irq, struct irq_desc *desc)
+ 							    offset));
+ 	}
+ 
+-	chained_irq_exit(irqchip, desc);
++	return IRQ_HANDLED;
+ }
+ 
+ static void pl061_irq_mask(struct irq_data *d)
+@@ -254,7 +252,13 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
+ 			return -ENODEV;
+ 		}
+ 	} else {
+-		chip->gc.base = -1;
++		if (dev->of_node) {
++			i = of_alias_get_id(dev->of_node, "gpio");
++			chip->gc.base = i * PL061_GPIO_NR;
++		}
++
++		if (chip->gc.base < 0)
++			chip->gc.base = -1;
+ 		irq_base = 0;
+ 	}
+ 
+@@ -296,8 +300,19 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
+ 		dev_info(&adev->dev, "could not add irqchip\n");
+ 		return ret;
+ 	}
+-	gpiochip_set_chained_irqchip(&chip->gc, &pl061_irqchip,
+-				     irq, pl061_irq_handler);
++
++	ret = devm_request_irq(dev, irq, pl061_irq_handler, IRQF_SHARED,
++			dev_name(dev), &chip->gc);
++
++	/* Set the parent IRQ for all affected IRQs */
++	for (i = 0; i < chip->gc.ngpio; i++)
++		irq_set_parent(irq_find_mapping(chip->gc.irqdomain, i), irq);
++
++	if (ret) {
++		dev_info(dev, "request irq failed: %d\n", ret);
++		return ret;
++	}
++
+ 
+ 	for (i = 0; i < PL061_GPIO_NR; i++) {
+ 		if (pdata) {
+diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
+index ba71522..07ce046 100644
+--- a/drivers/gpu/drm/i915/intel_drv.h
++++ b/drivers/gpu/drm/i915/intel_drv.h
+@@ -35,9 +35,6 @@
+ #include <drm/drm_fb_helper.h>
+ #include <drm/drm_dp_mst_helper.h>
+ 
+-#define DIV_ROUND_CLOSEST_ULL(ll, d)	\
+-({ unsigned long long _tmp = (ll)+(d)/2; do_div(_tmp, d); _tmp; })
+-
+ /**
+  * _wait_for - magic (register) wait macro
+  *
+diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c
+index 8bc193f..ce5a385 100644
+--- a/drivers/gpu/drm/i915/intel_panel.c
++++ b/drivers/gpu/drm/i915/intel_panel.c
+@@ -30,6 +30,7 @@
+ 
+ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+ 
++#include <linux/kernel.h>
+ #include <linux/moduleparam.h>
+ #include "intel_drv.h"
+ 
+diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
+index 01c7a08..1def4bb 100644
+--- a/drivers/hid/hid-input.c
++++ b/drivers/hid/hid-input.c
+@@ -1468,8 +1468,9 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
+ 				 * UGCI) cram a lot of unrelated inputs into the
+ 				 * same interface. */
+ 				hidinput->report = report;
+-				if (drv->input_configured)
+-					drv->input_configured(hid, hidinput);
++				if (drv->input_configured &&
++				    drv->input_configured(hid, hidinput))
++					goto out_cleanup;
+ 				if (input_register_device(hidinput->input))
+ 					goto out_cleanup;
+ 				hidinput = NULL;
+@@ -1490,8 +1491,9 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
+ 	}
+ 
+ 	if (hidinput) {
+-		if (drv->input_configured)
+-			drv->input_configured(hid, hidinput);
++		if (drv->input_configured &&
++		    drv->input_configured(hid, hidinput))
++			goto out_cleanup;
+ 		if (input_register_device(hidinput->input))
+ 			goto out_cleanup;
+ 	}
+diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
+index 51e25b9..e6cab62 100644
+--- a/drivers/hid/hid-multitouch.c
++++ b/drivers/hid/hid-multitouch.c
+@@ -372,6 +372,16 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+ 		td->inputmode_value = MT_INPUTMODE_TOUCHPAD;
+ 	}
+ 
++	/* Only map fields from TouchScreen or TouchPad collections.
++         * We need to ignore fields that belong to other collections
++         * such as Mouse that might have the same GenericDesktop usages. */
++	if (field->application == HID_DG_TOUCHSCREEN)
++		set_bit(INPUT_PROP_DIRECT, hi->input->propbit);
++	else if (field->application == HID_DG_TOUCHPAD)
++		set_bit(INPUT_PROP_POINTER, hi->input->propbit);
++	else
++		return 0;
++
+ 	if (usage->usage_index)
+ 		prev_usage = &field->usage[usage->usage_index - 1];
+ 
+@@ -701,12 +711,13 @@ static void mt_touch_report(struct hid_device *hid, struct hid_report *report)
+ 		mt_sync_frame(td, report->field[0]->hidinput->input);
+ }
+ 
+-static void mt_touch_input_configured(struct hid_device *hdev,
++static int mt_touch_input_configured(struct hid_device *hdev,
+ 					struct hid_input *hi)
+ {
+ 	struct mt_device *td = hid_get_drvdata(hdev);
+ 	struct mt_class *cls = &td->mtclass;
+ 	struct input_dev *input = hi->input;
++	int ret;
+ 
+ 	if (!td->maxcontacts)
+ 		td->maxcontacts = MT_DEFAULT_MAXCONTACT;
+@@ -721,9 +732,12 @@ static void mt_touch_input_configured(struct hid_device *hdev,
+ 	if (cls->quirks & MT_QUIRK_NOT_SEEN_MEANS_UP)
+ 		td->mt_flags |= INPUT_MT_DROP_UNUSED;
+ 
+-	input_mt_init_slots(input, td->maxcontacts, td->mt_flags);
++	ret = input_mt_init_slots(input, td->maxcontacts, td->mt_flags);
++	if (ret)
++		return ret;
+ 
+ 	td->mt_flags = 0;
++	return 0;
+ }
+ 
+ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+@@ -877,15 +891,16 @@ static void mt_post_parse(struct mt_device *td)
+ 		cls->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE;
+ }
+ 
+-static void mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
++static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
+ {
+ 	struct mt_device *td = hid_get_drvdata(hdev);
+ 	char *name;
+ 	const char *suffix = NULL;
+ 	struct hid_field *field = hi->report->field[0];
++	int ret = 0;
+ 
+ 	if (hi->report->id == td->mt_report_id)
+-		mt_touch_input_configured(hdev, hi);
++		ret = mt_touch_input_configured(hdev, hi);
+ 
+ 	/*
+ 	 * some egalax touchscreens have "application == HID_DG_TOUCHSCREEN"
+@@ -936,6 +951,7 @@ static void mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
+ 			hi->input->name = name;
+ 		}
+ 	}
++	return ret;
+ }
+ 
+ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
+diff --git a/drivers/hid/hid-steelseries.c b/drivers/hid/hid-steelseries.c
+index 29f328f..8060650 100644
+--- a/drivers/hid/hid-steelseries.c
++++ b/drivers/hid/hid-steelseries.c
+@@ -254,6 +254,11 @@ static int steelseries_srws1_probe(struct hid_device *hdev,
+ 		goto err_free;
+ 	}
+ 
++	if (!hid_validate_values(hdev, HID_OUTPUT_REPORT, 0, 0, 16)) {
++		ret = -ENODEV;
++		goto err_free;
++	}
++
+ 	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+ 	if (ret) {
+ 		hid_err(hdev, "hw start failed\n");
+diff --git a/drivers/hidmac/Kconfig b/drivers/hidmac/Kconfig
+new file mode 100644
+index 0000000..3286382
+--- /dev/null
++++ b/drivers/hidmac/Kconfig
+@@ -0,0 +1,27 @@
++#
++# Sensor device configuration
++#
++
++config HI_DMAC
++	tristate "Hisilicon DMAC Controller support"
++	depends on (ARCH_HISI)
++	help
++	  The Direction Memory Access(DMA) is a high-speed data transfer
++	  operation. It supports data read/write between peripherals and
++	  memories without using the CPU.
++	  Hisilicon DMA Controller(DMAC) directly transfers data between
++	  a memory and a peripheral, between peripherals, or between memories.
++	  This avoids the CPU intervention and reduces the interrupt handling
++	  overhead of the CPU.
++
++if HI_DMAC
++config HI_DMAC_IO_BASE
++	hex "hi dmac register base address"
++	depends on ARCH_HI3519 || ARCH_HI3519V101 || ARCH_HI3559 || ARCH_HI3556 || ARCH_HI3516AV200
++	default "0x10030000" if ARCH_HI3519 || ARCH_HI3519V101 || ARCH_HI3559 || ARCH_HI3556 || ARCH_HI3516AV200
++
++config HI_DMAC_CHANNEL_NUM
++	int "hi dmac channel num"
++	default "4" if ARCH_HI3519 || ARCH_HI3519V101 || ARCH_HI3559 || ARCH_HI3556 || ARCH_HI3516AV200
++	default "4" if ARCH_HI3516CV300 || ARCH_HI3531D || ARCH_HI3521D || ARCH_HI3536C
++endif
+diff --git a/drivers/hidmac/Makefile b/drivers/hidmac/Makefile
+new file mode 100644
+index 0000000..3aa24f3
+--- /dev/null
++++ b/drivers/hidmac/Makefile
+@@ -0,0 +1,10 @@
++#
++# Makefile for the hi dmac drivers.
++#
++
++ifdef CONFIG_HI_DMAC_IO_BASE
++obj-$(CONFIG_HI_DMAC)	+= hi_dmac.o
++else
++# get the io resource from DTS
++obj-$(CONFIG_HI_DMAC)	+= hi_pl08x.o
++endif
+diff --git a/drivers/hidmac/hi_dmac.c b/drivers/hidmac/hi_dmac.c
+new file mode 100644
+index 0000000..8e1f226
+--- /dev/null
++++ b/drivers/hidmac/hi_dmac.c
+@@ -0,0 +1,1216 @@
++/*
++ * Copyright (c) 2014 Hisilicon Co., Ltd.
++ *
++ * 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.
++ *
++ * History:
++ *      17-August-2006 create this file
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/i2c.h>
++#include <linux/init.h>
++#include <linux/time.h>
++#include <linux/interrupt.h>
++#include <linux/delay.h>
++#include <linux/errno.h>
++#include <linux/err.h>
++#include <linux/platform_device.h>
++#include <linux/dma-mapping.h>
++#include <linux/pm_runtime.h>
++#include <linux/slab.h>
++#include <mach/io.h>
++#include <linux/hidmac.h>
++#include "hi_dmac.h"
++
++#ifdef CONFIG_ARCH_HI3519
++#include "hidmac_hi3519.h"
++#include "hidmac_hi3519.c"
++#endif
++
++#ifdef CONFIG_ARCH_HI3519V101
++#include "hidmac_hi3519.h"
++#include "hidmac_hi3519v101.c"
++#endif
++
++#if defined(CONFIG_ARCH_HI3559) || defined(CONFIG_ARCH_HI3556)
++#include "hidmac_hi3559.h"
++#include "hidmac_hi3559.c"
++#endif
++
++#ifdef CONFIG_ARCH_HI3516AV200
++#include "hidmac_hi3516av200.h"
++#include "hidmac_hi3516av200.c"
++#endif
++
++void *reg_dmac_base_va;
++#define IO_DMAC_ADDRESS(x) (reg_dmac_base_va + ((x)-(DMAC_BASE_REG)))
++
++#define RX	0
++#define TX	1
++
++static int dmac_channel[CHANNEL_NUM] = {0, 1, 2, 3};
++
++#define CLR_INT(i)	((*(unsigned int *)IO_DMAC_ADDRESS\
++				(DMAC_BASE_REG+0x008)) = (1 << i))
++
++int g_channel_status[CHANNEL_NUM];
++
++/* #define DEBUG */
++
++#define DEBUG
++#ifdef DEBUG
++#define dma_err printk
++#else
++#define dma_err(fmt, ...) do {} while (0)
++#endif
++
++/*
++ *Define Memory range
++ */
++mem_addr mem_num[MEM_MAX_NUM] = {
++	{DDRAM_ADRS, DDRAM_SIZE},
++	{FLASH_BASE, FLASH_SIZE}
++};
++
++typedef void REG_ISR(int *p_dma_chn, int *p_dma_status);
++REG_ISR *function[CHANNEL_NUM];
++
++unsigned int pllihead[2];
++/*
++ *	memory address validity check
++ *
++static int mem_check_valid(unsigned int addr)
++{
++	unsigned int cnt;
++
++	for (cnt = 0; cnt < MEM_MAX_NUM; cnt++) {
++		if ((addr >= mem_num[cnt].addr_base) &&
++			(addr <= (mem_num[cnt].addr_base + mem_num[cnt].size)))
++			return 0;
++	}
++
++	return -1;
++} */
++
++/*
++ * dmac interrupt handle function
++ */
++irqreturn_t dmac_isr(int irq, void *dev_id)
++{
++	unsigned int channel_status;
++	unsigned int channel_tc_status, channel_err_status;
++	unsigned int i;
++
++	/*read the status of current interrupt */
++	dmac_readw(DMAC_INTSTATUS, channel_status);
++
++	/*decide which channel has trigger the interrupt*/
++	for (i = 0; i < DMAC_MAX_CHANNELS; i++) {
++		if ((((channel_status >> i) & 0x1) == 0x01)) {
++			/* [HSCP201306240006],l00181524,20130625 */
++			/* The INT status should be read first then clear it */
++			/* CLR_INT(i); */
++			dmac_readw(DMAC_INTTCSTATUS, channel_tc_status);
++			dmac_readw(DMAC_INTERRORSTATUS, channel_err_status);
++			CLR_INT(i);
++			/*¡¾HSCP201403110002¡¿ l00183122 20140723*/
++			if (g_channel_status[i] == DMAC_CHN_VACANCY
++						&& (function[i]) == NULL) {
++				if ((0x01 == ((channel_tc_status >> i) & 0x01)))
++					dmac_writew(DMAC_INTTCCLEAR,
++								(0x01 << i));
++				else if ((0x01 == ((channel_err_status
++								>> i)&0x01)))
++					dmac_writew(DMAC_INTERRCLR,
++								(0x01 << i));
++				continue;
++			}
++
++			/* save the current channel transfer */
++			/* status to g_channel_status[i] */
++			if ((0x01 == ((channel_tc_status >> i) & 0x01))) {
++				g_channel_status[i] = DMAC_CHN_SUCCESS;
++				dmac_writew(DMAC_INTTCCLEAR, (0x01 << i));
++			} else if ((0x01 == ((channel_err_status >> i)&0x01))) {
++				g_channel_status[i] = -DMAC_CHN_ERROR;
++				dmac_writew(DMAC_INTERRCLR, (0x01 << i));
++			} else
++				pr_err("Isr Error in DMAC_IntHandeler");
++				pr_err("%d! channel\n", i);
++
++			if ((function[i]) != NULL)
++				function[i](&i, &g_channel_status[i]);
++		}
++	}
++
++	return IRQ_RETVAL(1);
++}
++
++/*
++ *	update the state of channels
++ */
++#define HI_DMA_UPDATE_TIMEOUT  (5 * HZ)
++static int dma_update_status(unsigned int channel)
++{
++
++	unsigned int channel_status;
++	unsigned int channel_tc_status[3];
++	unsigned int channel_err_status[3];
++	unsigned int i = channel, j;
++	unsigned long update_jiffies_timeout;
++
++	update_jiffies_timeout = jiffies + HI_DMA_UPDATE_TIMEOUT;
++
++	while (1) {
++		for (j = 0; j < 3; j++) {
++			dmac_readw(DMAC_INTTCSTATUS, channel_status);
++			channel_tc_status[j] = (channel_status >> i) & 0x01;
++			dmac_readw(DMAC_INTERRORSTATUS, channel_status);
++			channel_err_status[j] = (channel_status >> i) & 0x01;
++		}
++
++		if ((channel_tc_status[0] == 0x1) &&
++			(channel_tc_status[1] == 0x1) &&
++				(channel_tc_status[2] == 0x1)) {
++			g_channel_status[i] = DMAC_CHN_SUCCESS;
++			dmac_writew(DMAC_INTTCCLEAR, (0x01 << i));
++			break;
++		} else if ((channel_err_status[0] == 0x1) &&
++			(channel_err_status[1] == 0x1) &&
++				(channel_err_status[2] == 0x1)) {
++			g_channel_status[i] = -DMAC_CHN_ERROR;
++			dma_err("Error in DMAC %d finish!\n", i);
++			dmac_writew(DMAC_INTERRCLR, (0x01 << i));
++			break;
++		}
++
++		if (!time_before(jiffies, update_jiffies_timeout)) {
++			dma_err("Timeout in DMAC %d!\n", i);
++			g_channel_status[i] = -DMAC_CHN_TIMEOUT;
++			break;
++		}
++	}
++
++	return g_channel_status[i];
++}
++
++
++/*
++ *	check the state of channels
++ */
++static int dmac_check_over(unsigned int channel)
++{
++	int status = 0;
++
++	if (-DMAC_CHN_ERROR == g_channel_status[channel]) {
++		dma_err("Error transfer %d finished\n", channel);
++		dmac_writew(DMAC_CxCONFIG(channel), DMAC_CxDISABLE);
++		g_channel_status[channel] = DMAC_CHN_VACANCY;
++		status = -DMAC_CHN_ERROR;
++	} else if (DMAC_NOT_FINISHED == g_channel_status[channel])
++		status = DMAC_NOT_FINISHED;
++	else if (DMAC_CHN_ALLOCAT == g_channel_status[channel])
++		status = DMAC_CHN_ALLOCAT;
++	else if (DMAC_CHN_VACANCY == g_channel_status[channel])
++		status = DMAC_CHN_VACANCY;
++	else if (-DMAC_CHN_TIMEOUT == g_channel_status[channel]) {
++		dma_err("transfer %d timeout!\n", channel);
++		status = -DMAC_CHN_TIMEOUT;
++	} else if (DMAC_CHN_SUCCESS == g_channel_status[channel])
++		/*The transfer of Channel %d has finished successfully!*/
++		status = DMAC_CHN_SUCCESS;
++	else {
++		dmac_writew(DMAC_CxCONFIG(channel), DMAC_CxDISABLE);
++		g_channel_status[channel] = DMAC_CHN_VACANCY;
++		status = -DMAC_CHN_ERROR;
++	}
++	return status;
++}
++
++spinlock_t my_lcok = __SPIN_LOCK_UNLOCKED(old_style_spin_init);
++unsigned long flags;
++
++/*
++ *	allocate channel.
++ */
++int dmac_channel_allocate(void *pisr)
++{
++	unsigned int i, channelinfo, g_channelinfo;
++
++	for (i = 0; i < CHANNEL_NUM; i++)
++		dmac_check_over(dmac_channel[i]);
++
++	dmac_readw(DMAC_ENBLDCHNS, g_channelinfo);
++	g_channelinfo = g_channelinfo & 0x00ff;
++
++	for (i = 0; i < CHANNEL_NUM; i++) {
++		if (g_channel_status[dmac_channel[i]] == DMAC_CHN_VACANCY) {
++			channelinfo = g_channelinfo >> dmac_channel[i];
++			if (0x00 == (channelinfo & 0x01)) {
++				/*clear the interrupt in this channel */
++				dmac_writew(DMAC_INTERRCLR,
++						(0x01 << dmac_channel[i]));
++				dmac_writew(DMAC_INTTCCLEAR,
++						(0x01 << dmac_channel[i]));
++
++				g_channel_status[dmac_channel[i]]
++						= DMAC_CHN_ALLOCAT;
++				return dmac_channel[i];
++			}
++		}
++	}
++
++	dma_err("no to alloc\n");
++	return -EINVAL;
++}
++EXPORT_SYMBOL(dmac_channel_allocate);
++
++int dmac_register_isr(unsigned int channel, void *pisr)
++{
++	if (channel > CHANNEL_NUM - 1) {
++		dma_err("channel which choosed %d is error !\n", channel);
++		return -1;
++	}
++
++	if (g_channel_status[channel] != DMAC_CHN_VACANCY) {
++		dma_err("dma chn %d is in used!\n", channel);
++		return -1;
++	}
++
++	/*clear the interrupt in this channel */
++	dmac_writew(DMAC_INTERRCLR, (0x01 << channel));
++	dmac_writew(DMAC_INTTCCLEAR, (0x01 << channel));
++
++	function[channel] = (void *)pisr;
++	g_channel_status[channel] = DMAC_CHN_ALLOCAT;
++
++	return 0;
++}
++EXPORT_SYMBOL(dmac_register_isr);
++
++/*
++ *	free channel
++ */
++int dmac_channel_free(unsigned int channel)
++{
++
++	if (channel >= DMAC_MAX_CHANNELS) {
++		dma_err("channel larger %d\n", DMAC_MAX_CHANNELS);
++		return -EINVAL;
++	}
++
++	g_channel_status[channel] = DMAC_CHN_VACANCY;
++	return 0;
++}
++EXPORT_SYMBOL(dmac_channel_free);
++
++static unsigned int dmac_check_request(unsigned int peripheral_addr,
++					int direction)
++{
++	int i;
++	/* check request pipe with peripheral_addr */
++	for (i = direction; i < DMAC_MAX_PERIPHERALS; i = i + 2) {
++		if (g_peripheral[i].peri_addr == peripheral_addr)
++			return i;
++	}
++
++	dma_err("Invalid devaddr\n");
++
++	return -1;
++}
++
++/*
++ *	init dmac register
++ *	clear interrupt flags
++ *	called by dma_driver_init
++ */
++int dmac_init(void)
++{
++	unsigned int i, tempvalue;
++
++	hidmac_clk_en();
++	hidmac_unreset();
++
++	dmac_readw(DMAC_CONFIG, tempvalue);
++	if (tempvalue == 0) {
++		dmac_writew(DMAC_CONFIG, DMAC_CONFIG_VAL);
++		dmac_writew(DMAC_INTTCCLEAR, 0xFF);
++		dmac_writew(DMAC_INTERRCLR, 0xFF);
++		for (i = 0; i < DMAC_MAX_CHANNELS; i++)
++			dmac_writew(DMAC_CxCONFIG(i), DMAC_CxDISABLE);
++	}
++
++	return 0;
++}
++
++
++/*
++ *	alloc_dma_lli_space
++ *	output:
++ *             ppheadlli[0]: memory physics address
++ *             ppheadlli[1]: virtual address
++ *
++ */
++int allocate_dmalli_space(unsigned int *ppheadlli, unsigned int page_num)
++{
++	dma_addr_t dma_phys;
++	void *dma_virt;
++
++	dma_virt = dma_alloc_coherent(NULL, page_num*PAGE_SIZE,
++					&dma_phys, GFP_DMA | __GFP_WAIT);
++	if (NULL == dma_virt) {
++		dma_err("can't get dma mem from system\n");
++		return -1;
++	}
++
++	ppheadlli[0] = (unsigned int)(dma_phys);
++	ppheadlli[1] = (unsigned int)(dma_virt);
++
++	return 0;
++}
++EXPORT_SYMBOL(allocate_dmalli_space);
++
++/*
++ *	free_dma_lli_space
++ */
++int free_dmalli_space(unsigned int *ppheadlli, unsigned int page_num)
++{
++	dma_addr_t dma_phys;
++	unsigned int dma_virt;
++
++	dma_phys = (dma_addr_t)(ppheadlli[0]);
++	dma_virt = ppheadlli[1];
++
++	dma_free_coherent(NULL, page_num*PAGE_SIZE,
++				(void *)dma_virt, dma_phys);
++
++	ppheadlli[0] = 0;
++	ppheadlli[1] = 0;
++	return 0;
++}
++EXPORT_SYMBOL(free_dmalli_space);
++
++/*
++ * config register for memory to memory DMA transfer without LLI
++ * note:
++ * it is necessary to call dmac_channelstart for channel enable
++ */
++int dmac_start_m2m(unsigned int  channel, unsigned int psource,
++			unsigned int pdest, unsigned int uwnumtransfers)
++{
++	unsigned int uwchannel_num, tmp_trasnsfer;
++
++	if (uwnumtransfers > (MAXTRANSFERSIZE << 2)) {
++		dma_err("Invalidate transfer size,size=%x\n", uwnumtransfers);
++		return -EINVAL;
++	}
++
++	uwchannel_num = channel;
++
++	if ((uwchannel_num == DMAC_CHANNEL_INVALID)
++			|| (uwchannel_num > CHANNEL_NUM)) {
++		pr_err("failure of DMAC channel allocation in M2M function!\n");
++		return -EFAULT;
++	}
++
++	/* dmac_writew (DMAC_CxCONFIG(uwchannel_num), DMAC_CxDISABLE); */
++	dmac_writew(DMAC_CxSRCADDR(uwchannel_num), psource);
++	dmac_writew(DMAC_CxDESTADDR(uwchannel_num), pdest);
++	dmac_writew(DMAC_CxLLI(uwchannel_num), 0);
++	tmp_trasnsfer = (uwnumtransfers >> 2) & 0xfff;
++	tmp_trasnsfer = tmp_trasnsfer | (DMAC_CxCONTROL_M2M & (~0xfff));
++	dmac_writew(DMAC_CxCONTROL(uwchannel_num), tmp_trasnsfer);
++	dmac_writew(DMAC_CxCONFIG(uwchannel_num), DMAC_CxCONFIG_M2M);
++
++	return 0;
++}
++EXPORT_SYMBOL(dmac_start_m2m);
++
++/*
++ *	channel enable
++ *	start a dma transfer immediately
++ */
++int dmac_channelstart(unsigned int u32channel)
++{
++
++	unsigned int reg_value;
++
++	if (u32channel >= DMAC_MAX_CHANNELS) {
++		dma_err("channel larger %d\n", DMAC_MAX_CHANNELS);
++		return -EINVAL;
++	}
++
++	g_channel_status[u32channel] = DMAC_NOT_FINISHED;
++	dmac_readw(DMAC_CxCONFIG(u32channel), reg_value);
++	dmac_writew(DMAC_CxCONFIG(u32channel),
++			(reg_value | DMAC_CHANNEL_ENABLE));
++
++	return 0;
++}
++EXPORT_SYMBOL(dmac_channelstart);
++
++/*
++ *	wait for transfer end
++ */
++int dmac_wait(int channel)
++{
++	int ret_result, ret = 0;
++
++	if (channel < 0)
++		return -1;
++
++	while (1) {
++		ret_result = dma_update_status(channel);
++		if (ret_result == -DMAC_CHN_ERROR) {
++			dma_err("Transfer Error.\n");
++			ret = -1;
++			goto end;
++		} else  if (ret_result == DMAC_NOT_FINISHED)
++			udelay(10);
++		else if (ret_result == DMAC_CHN_SUCCESS) {
++			ret = DMAC_CHN_SUCCESS;
++			goto end;
++		}
++		else if (ret_result == DMAC_CHN_VACANCY) {
++			ret = DMAC_CHN_SUCCESS;
++			goto end;
++		} else if (ret_result == -DMAC_CHN_TIMEOUT) {
++			dma_err("Timeout.\n");
++			dmac_writew(DMAC_CxCONFIG(channel), DMAC_CxDISABLE);
++			g_channel_status[channel] = DMAC_CHN_VACANCY;
++			ret = -1;
++			goto end;
++		}
++	}
++end:
++	dmac_channelclose(channel);
++	return ret;
++}
++EXPORT_SYMBOL(dmac_wait);
++
++/*
++ *	buile LLI for memory to memory DMA transfer
++ */
++int dmac_buildllim2m_isp(unsigned int *ppheadlli, unsigned int *psource,
++			unsigned int *pdest, unsigned int *length,
++			unsigned int lli_num)
++{
++	unsigned int address, phy_address;
++	unsigned int j;
++
++	if (ppheadlli != NULL) {
++		phy_address = (unsigned int)(ppheadlli[0]);
++		dma_debug("phy_address: 0x%X\n",phy_address);
++		address = (unsigned int)(ppheadlli[1]);
++		dma_debug("address: 0x%X\n",address);
++		for (j = 0; j < lli_num; j++) {
++			dma_debug("psource[%d]: 0x%X\n", j, psource[j]);
++			dmac_writew(address, psource[j]);
++			address += 4;
++			phy_address += 4;
++			dma_debug("pdest[%d]: 0x%X\n", j, pdest[j]);
++			dmac_writew(address, pdest[j]);
++			address += 4;
++			phy_address += 4;
++
++			/* if the last node, next_lli_addr = 0*/
++			if (j == (lli_num - 1))
++				dmac_writew(address, 0);
++			else
++				dmac_writew(address,
++					(((phy_address + 8) & (~0x03))
++					 | DMAC_CxLLI_LM));
++
++			address += 4;
++			phy_address += 4;
++
++			if (j == (lli_num - 1)) {
++				dmac_writew(address, ((DMAC_CxCONTROL_LLIM2M
++					&(~0xfff)) | (length[j] >> 2)
++					| 0x80000000));
++			} else {
++				dmac_writew(address,
++					(((DMAC_CxCONTROL_LLIM2M&(~0xfff)) |
++					 (length[j] >> 2)) & 0x7fffffff));
++			}
++
++			address += 4;
++			phy_address += 4;
++		}
++	}
++
++	return 0;
++}
++EXPORT_SYMBOL(dmac_buildllim2m_isp);
++
++/*
++ *	buile LLI for memory to memory DMA transfer
++ */
++int dmac_buildllim2m(unsigned int *ppheadlli, unsigned int pdest,
++			unsigned int psource, unsigned int totaltransfersize,
++				unsigned int uwnumtransfers)
++{
++	unsigned int lli_num = 0;
++	unsigned int last_lli = 0;
++	unsigned int address , phy_address, srcaddr, denstaddr;
++	unsigned int j;
++
++	lli_num = (totaltransfersize / uwnumtransfers);
++
++	if ((totaltransfersize % uwnumtransfers) != 0)
++		last_lli = 1, ++lli_num;
++
++	if (ppheadlli != NULL) {
++		phy_address = (unsigned int)(ppheadlli[0]);
++		address = (unsigned int)(ppheadlli[1]);
++		for (j = 0; j < lli_num; j++) {
++			srcaddr = (psource + (j*uwnumtransfers));
++			dmac_writew(address, srcaddr);
++			address += 4;
++			phy_address += 4;
++			denstaddr = (pdest + (j*uwnumtransfers));
++			dmac_writew(address, denstaddr);
++			address += 4;
++			phy_address += 4;
++			if (j == (lli_num - 1))
++				dmac_writew(address, 0);
++			else
++				dmac_writew(address,
++					(((phy_address + 8) & (~0x03))
++					 | DMAC_CxLLI_LM));
++
++			address += 4;
++			phy_address += 4;
++
++			if ((j == (lli_num - 1)) && (last_lli == 0))
++				dmac_writew(address, ((DMAC_CxCONTROL_LLIM2M
++					&(~0xfff)) | (uwnumtransfers >> 2)
++					| 0x80000000));
++			else if ((j == (lli_num - 1)) && (last_lli == 1))
++				dmac_writew(address, ((DMAC_CxCONTROL_LLIM2M
++					& (~0xfff)) | ((totaltransfersize
++					% uwnumtransfers) >> 2) | 0x80000000));
++			else
++				dmac_writew(address,
++					(((DMAC_CxCONTROL_LLIM2M&(~0xfff)) |
++					 (uwnumtransfers >> 2)) & 0x7fffffff));
++
++			address += 4;
++			phy_address += 4;
++		}
++	}
++
++	return 0;
++}
++EXPORT_SYMBOL(dmac_buildllim2m);
++
++/*
++ *	disable channel
++ *	used before the operation of register configuration
++ */
++int dmac_channelclose(unsigned int channel)
++{
++	unsigned int reg_value, count;
++
++	if (channel >= DMAC_MAX_CHANNELS) {
++		dma_err("channel larger than total.\n");
++		return -EINVAL;
++	}
++
++	dmac_readw(DMAC_CxCONFIG(channel), reg_value);
++
++#define CHANNEL_CLOSE_IMMEDIATE
++#ifdef CHANNEL_CLOSE_IMMEDIATE
++	reg_value &= 0xFFFFFFFE;
++	dmac_writew(DMAC_CxCONFIG(channel) , reg_value);
++#else
++	reg_value |= DMAC_CONFIGURATIONx_HALT_DMA_ENABLE;
++	/*ignore incoming dma request*/
++	dmac_writew(DMAC_CxCONFIG(channel), reg_value);
++	dmac_readw(DMAC_CxCONFIG(channel), reg_value);
++	/*if FIFO is empty*/
++	while ((reg_value & DMAC_CONFIGURATIONx_ACTIVE)
++			== DMAC_CONFIGURATIONx_ACTIVE)
++		dmac_readw(DMAC_CxCONFIG(channel), reg_value);
++	reg_value &= 0xFFFFFFFE;
++	dmac_writew(DMAC_CxCONFIG(channel), reg_value);
++#endif
++
++	dmac_readw(DMAC_ENBLDCHNS, reg_value);
++	reg_value = reg_value & 0x00ff;
++	count = 0;
++	while (((reg_value >> channel) & 0x1) == 1) {
++		dmac_readw(DMAC_ENBLDCHNS, reg_value);
++		reg_value = reg_value & 0x00ff;
++		if (count++ > 10000) {
++			dma_err("close failure.\n");
++			return -1;
++		}
++	}
++
++	return 0;
++}
++EXPORT_SYMBOL(dmac_channelclose);
++
++/*
++ *	load configuration from LLI for memory to memory
++ */
++int dmac_start_llim2m(unsigned int channel, unsigned int *pfirst_lli)
++{
++	unsigned int uwchannel_num;
++	dmac_lli  plli;
++	unsigned int first_lli;
++
++	if (NULL == pfirst_lli) {
++		dma_err("Invalidate LLI head!\n");
++		return -EFAULT;
++	}
++
++	uwchannel_num = channel;
++	if ((uwchannel_num == DMAC_CHANNEL_INVALID) ||
++				(uwchannel_num > 7)) {
++		dma_err("failure of DMAC channel allocation in");
++		dma_err("LLIM2M function,channel=%x!\n ", uwchannel_num);
++		return -EINVAL;
++	}
++
++	memset(&plli, 0, sizeof(plli));
++	first_lli = (unsigned int)pfirst_lli[1];
++	dmac_readw(first_lli, plli.src_addr);
++	dmac_readw(first_lli+4, plli.dst_addr);
++	dmac_readw(first_lli+8, plli.next_lli);
++	dmac_readw(first_lli+12, plli.lli_transfer_ctrl);
++
++	dmac_channelclose(uwchannel_num);
++	dmac_writew(DMAC_INTTCCLEAR, (0x1 << uwchannel_num));
++	dmac_writew(DMAC_INTERRCLR, (0x1 << uwchannel_num));
++	dmac_writew(DMAC_SYNC, 0x0);
++
++	dmac_writew(DMAC_CxCONFIG(uwchannel_num), DMAC_CxDISABLE);
++	dmac_writew(DMAC_CxSRCADDR(uwchannel_num),
++			(unsigned int)(plli.src_addr));
++	dmac_writew(DMAC_CxDESTADDR(uwchannel_num),
++			(unsigned int)(plli.dst_addr));
++	dmac_writew(DMAC_CxLLI(uwchannel_num), (unsigned int)(plli.next_lli));
++	dmac_writew(DMAC_CxCONTROL(uwchannel_num),
++			(unsigned int)(plli.lli_transfer_ctrl));
++	dmac_writew(DMAC_CxCONFIG(uwchannel_num), DMAC_CxCONFIG_LLIM2M);
++
++	return 0;
++}
++EXPORT_SYMBOL(dmac_start_llim2m);
++
++/*
++ *	load configuration from LLI for memory and peripheral
++ */
++int dmac_start_llim2p(unsigned int channel, unsigned int *pfirst_lli,
++				unsigned int uwperipheralid)
++{
++	unsigned int uwchannel_num;
++	dmac_lli plli;
++	unsigned int first_lli;
++	unsigned int temp = 0;
++
++	if (NULL == pfirst_lli) {
++		dma_err("Invalidate LLI head!\n");
++		return -EINVAL;
++	}
++	uwchannel_num = channel;
++	if ((uwchannel_num == DMAC_CHANNEL_INVALID) ||
++			(uwchannel_num > CHANNEL_NUM)) {
++		dma_err("failure of DMAC channel allocation in");
++		dma_err("LLIM2P function, channel=%x!\n ", uwchannel_num);
++		return -EINVAL;
++	}
++
++	memset(&plli, 0, sizeof(plli));
++	first_lli = (unsigned int)pfirst_lli[1];
++	dmac_readw(first_lli, plli.src_addr);
++	dmac_readw(first_lli+4, plli.dst_addr);
++	dmac_readw(first_lli+8, plli.next_lli);
++	dmac_readw(first_lli+12, plli.lli_transfer_ctrl);
++
++	dmac_channelclose(uwchannel_num);
++	dmac_writew(DMAC_INTTCCLEAR, (0x1<<uwchannel_num));
++	dmac_writew(DMAC_INTERRCLR, (0x1<<uwchannel_num));
++	dmac_writew(DMAC_SYNC, 0x0);
++
++	dmac_readw(DMAC_CxCONFIG(uwchannel_num), temp);
++	dmac_writew(DMAC_CxCONFIG(uwchannel_num), temp|DMAC_CxDISABLE);
++	dmac_writew(DMAC_CxSRCADDR(uwchannel_num), plli.src_addr);
++	dmac_writew(DMAC_CxDESTADDR(uwchannel_num), plli.dst_addr);
++	dmac_writew(DMAC_CxLLI(uwchannel_num), plli.next_lli);
++	dmac_writew(DMAC_CxCONTROL(uwchannel_num), plli.lli_transfer_ctrl);
++
++	return 0;
++}
++EXPORT_SYMBOL(dmac_start_llim2p);
++
++/*
++ *	enable memory and peripheral dma transfer
++ *	note:
++ *	it is necessary to call dmac_channelstart to enable channel
++ */
++int dmac_start_m2p(unsigned int channel, unsigned int memaddr,
++		unsigned int uwperipheralid, unsigned int uwnumtransfers,
++		unsigned int next_lli_addr)
++{
++
++	unsigned int uwtrans_control = 0;
++	unsigned int addtmp, tmp;
++	unsigned int uwdst_addr = 0, uwsrc_addr = 0;
++	unsigned int uwwidth;
++	int uwchannel_num;
++
++	addtmp = memaddr;
++
++	if ((uwperipheralid > 15)) {
++		dma_err("Invalid peripheral id%x\n", uwperipheralid);
++		return -EINVAL;
++	}
++
++	uwchannel_num = (int)channel;
++	if ((uwchannel_num == DMAC_CHANNEL_INVALID)
++		|| (uwchannel_num > CHANNEL_NUM) || (uwchannel_num < 0)) {
++		dma_err("failure alloc\n");
++		return -EFAULT;
++	}
++
++	/* must modified with different peripheral */
++	uwwidth = g_peripheral[uwperipheralid].transfer_width;
++
++	/* check transfer direction *
++	 * even number-->TX, odd number-->RX*/
++	uwsrc_addr = memaddr;
++	uwdst_addr = (unsigned int)(g_peripheral[uwperipheralid].peri_addr);
++
++	tmp = uwnumtransfers >> uwwidth;
++	if (tmp & (~0x0fff)) {
++		dma_err("Invalidate size%x\n", uwnumtransfers);
++		return -EINVAL;
++	}
++
++	tmp = tmp & 0xfff;
++	uwtrans_control = tmp |
++		(g_peripheral[uwperipheralid].transfer_ctrl & (~0xfff));
++	dmac_writew(DMAC_INTTCCLEAR, (0x1<<(unsigned int)uwchannel_num));
++	dmac_writew(DMAC_INTERRCLR, (0x1<<(unsigned int)uwchannel_num));
++	dmac_writew(DMAC_CxSRCADDR(uwchannel_num), (unsigned int)uwsrc_addr);
++	dmac_writew(DMAC_CxDESTADDR(uwchannel_num), (unsigned int)uwdst_addr);
++	dmac_writew(DMAC_CxCONTROL(uwchannel_num),
++			(unsigned int)uwtrans_control);
++	dmac_writew(DMAC_CxCONFIG(uwchannel_num),
++			(g_peripheral[uwperipheralid].transfer_cfg));
++
++	return 0;
++}
++
++/*
++ *	enable memory and peripheral dma transfer
++ *	note:
++ *	it is necessary to call dmac_channelstart to enable channel
++ */
++int dmac_start_p2m(unsigned int channel, unsigned int memaddr,
++		unsigned int uwperipheralid, unsigned int uwnumtransfers,
++		unsigned int next_lli_addr)
++{
++	unsigned int uwtrans_control = 0;
++	unsigned int addtmp, tmp;
++	unsigned int uwdst_addr = 0, uwsrc_addr = 0;
++	unsigned int uwwidth;
++	int uwchannel_num;
++
++	addtmp = memaddr;
++
++	if ((uwperipheralid > 15)) {
++		dma_err("Invalid peripheral id%x\n", uwperipheralid);
++		return -EINVAL;
++	}
++
++	uwchannel_num = (int)channel;
++	if ((uwchannel_num == DMAC_CHANNEL_INVALID)
++		|| (uwchannel_num > 3) || (uwchannel_num < 0)) {
++		dma_err("failure alloc\n");
++		return -EFAULT;
++	}
++
++	/* must modified with different peripheral */
++	uwwidth = g_peripheral[uwperipheralid].transfer_width;
++
++	/* check transfer direction *
++	 * even number-->TX, odd number-->RX*/
++	uwsrc_addr = (unsigned int)(g_peripheral[uwperipheralid].peri_addr);
++	uwdst_addr = memaddr;
++
++	tmp = uwnumtransfers >> uwwidth;
++	if (tmp & (~0x0fff)) {
++		dma_err("Invalidate size%x\n", uwnumtransfers);
++		return -EINVAL;
++	}
++
++	tmp = tmp & 0xfff;
++	uwtrans_control = tmp |
++		(g_peripheral[uwperipheralid].transfer_ctrl & (~0xfff));
++	dmac_writew(DMAC_INTTCCLEAR, (0x1<<(unsigned int)uwchannel_num));
++	dmac_writew(DMAC_INTERRCLR, (0x1<<(unsigned int)uwchannel_num));
++	dmac_writew(DMAC_CxSRCADDR(uwchannel_num), (unsigned int)uwsrc_addr);
++	dmac_writew(DMAC_CxDESTADDR(uwchannel_num), (unsigned int)uwdst_addr);
++	dmac_writew(DMAC_CxCONTROL(uwchannel_num),
++			(unsigned int)uwtrans_control);
++	dmac_writew(DMAC_CxCONFIG(uwchannel_num),
++			(g_peripheral[uwperipheralid].transfer_cfg));
++
++	return 0;
++}
++
++/*
++ *	execute memory to memory dma transfer without LLI
++ */
++int dmac_m2m_transfer(unsigned int source, unsigned int dest,
++						unsigned int length)
++{
++	unsigned int ulchnn, dma_size = 0;
++	unsigned int dma_count, left_size;
++
++	left_size = length;
++	dma_count = 0;
++	ulchnn = dmac_channel_allocate(NULL);
++
++	ulchnn = 2;
++
++	dma_err("use channel %d\n", ulchnn);
++
++	while ((left_size >> 2) >= 0xffc) {
++		dma_size   = 0xffc;
++		left_size -= (dma_size << 2);
++		dma_err("left_size is %x.", left_size);
++		dmac_start_m2m(ulchnn, (unsigned int)(source
++			+ dma_count * (dma_size << 2)),
++			(unsigned int)(dest + dma_count * (dma_size << 2)),
++					(dma_size << 2));
++		if (dmac_channelstart(ulchnn) != 0) {
++			dma_err("start channel error...\n");
++			return -1;
++		}
++
++		if (dmac_wait(ulchnn) != DMAC_CHN_SUCCESS) {
++			dma_err("dma transfer error...\n");
++			return -1;
++		}
++
++		dma_count++;
++	}
++
++	dmac_start_m2m(ulchnn, (source + dma_count * (dma_size << 2)),
++			(dest + dma_count * (dma_size << 2)), (left_size << 2));
++
++	if (dmac_channelstart(ulchnn) != 0)
++		return -1;
++
++	if (dmac_wait(ulchnn) != DMAC_CHN_SUCCESS)
++		return -1;
++
++	return 0;
++}
++EXPORT_SYMBOL(dmac_m2m_transfer);
++
++/*
++ *	execute memory to peripheral dma transfer without LLI
++ */
++int dmac_m2p_transfer(unsigned int memaddr, unsigned int uwperipheralid,
++			unsigned int length)
++{
++	unsigned int ulchnn, dma_size = 0;
++	unsigned int dma_count, left_size;
++	unsigned int uwwidth;
++
++	left_size = length;
++	dma_count = 0;
++
++	ulchnn = dmac_channel_allocate(NULL);
++	if (DMAC_CHANNEL_INVALID == ulchnn)
++		return -1;
++
++	uwwidth = g_peripheral[uwperipheralid].transfer_width;
++
++	while ((left_size >> uwwidth) >= 0xffc) {
++		dma_size = 0xffc;
++		left_size -= (dma_size << uwwidth);
++
++		if (dmac_start_m2p(ulchnn,
++			(unsigned int)(memaddr + dma_count * dma_size),
++			uwperipheralid, (dma_size << uwwidth), 0) < 0)
++			return -1;
++
++		if (dmac_channelstart(ulchnn) != 0)
++			return -1;
++
++		if (dmac_wait(ulchnn) != DMAC_CHN_SUCCESS) {
++			dmac_channel_free(ulchnn);
++			return -1;
++		}
++
++		dma_count++;
++	}
++
++	pr_debug("memaddr=0x%x\n", (unsigned int)(memaddr
++					+ dma_count * dma_size));
++
++	if (dmac_start_m2p(ulchnn,
++		(unsigned int)(memaddr + dma_count * dma_size),
++			uwperipheralid, left_size, 0) < 0)
++		return -1;
++
++	if (dmac_channelstart(ulchnn) != 0)
++		return -1;
++
++	return ulchnn;
++}
++
++/*
++ *	execute memory to peripheral dma transfer without LLI
++ */
++int dmac_p2m_transfer(unsigned int memaddr, unsigned int uwperipheralid,
++			unsigned int length)
++{
++	unsigned int ulchnn, dma_size = 0;
++	unsigned int dma_count, left_size;
++	unsigned int uwwidth;
++
++	left_size = length;
++	dma_count = 0;
++
++	ulchnn = dmac_channel_allocate(NULL);
++	if (DMAC_CHANNEL_INVALID == ulchnn)
++		return -1;
++
++	uwwidth = g_peripheral[uwperipheralid].transfer_width;
++
++	while ((left_size >> uwwidth) >= 0xffc) {
++		dma_size = 0xffc;
++		left_size -= (dma_size << uwwidth);
++
++		if (dmac_start_p2m(ulchnn,
++			(unsigned int)(memaddr + dma_count * dma_size),
++			uwperipheralid, (dma_size << uwwidth), 0) < 0)
++			return -1;
++
++		if (dmac_channelstart(ulchnn) != 0)
++			return -1;
++
++		if (dmac_wait(ulchnn) != DMAC_CHN_SUCCESS) {
++			dmac_channel_free(ulchnn);
++			return -1;
++		}
++
++		dma_count++;
++	}
++
++	pr_debug("memaddr=0x%x\n", (unsigned int)(memaddr
++					+ dma_count * dma_size));
++
++	if (dmac_start_p2m(ulchnn,
++		(unsigned int)(memaddr + dma_count * dma_size),
++			uwperipheralid, left_size, 0) < 0)
++		return -1;
++
++	if (dmac_channelstart(ulchnn) != 0)
++		return -1;
++
++	return ulchnn;
++}
++
++/*
++ * memory to memory dma transfer with LLI
++ *
++ * @source
++ * @dest
++ * @length
++ * @num
++ * */
++int do_dma_llim2m_isp(unsigned int *source,
++		unsigned int *dest,
++		unsigned int *length,
++		unsigned int num)
++{
++	unsigned int chnn;
++	int ret = 0;
++
++	/* the dma channel is default using 2 */
++	chnn = 2;
++
++	ret = dmac_buildllim2m_isp(pllihead, source, dest, length, num);
++
++	if (ret) {
++		dma_err("build lli error...\n");
++		return -1;
++	}
++
++	/* dmac_register_isr(chnn, dmac_channel_close); */
++	ret = dmac_start_llim2m(chnn, pllihead);
++	if (ret)
++		return -1;
++
++	if (dmac_channelstart(chnn) != 0) {
++		dma_err("start channel error...\n");
++		return -1;
++	}
++
++	return ret;
++}
++EXPORT_SYMBOL(do_dma_llim2m_isp);
++
++int do_dma_m2p(unsigned int memaddr, unsigned int peripheral_addr,
++		unsigned int length)
++{
++	int ret = 0;
++	int uwperipheralid;
++
++	uwperipheralid = dmac_check_request(peripheral_addr, TX);
++	if (uwperipheralid < 0) {
++		dma_err("m2p:Invalid devaddr\n");
++		return -1;
++	}
++
++	ret = dmac_m2p_transfer(memaddr, uwperipheralid, length);
++	if (ret == -1) {
++		dma_err("m2p:trans err\n");
++		return -1;
++	}
++
++	return ret;
++}
++
++int do_dma_p2m(unsigned int memaddr, unsigned int peripheral_addr,
++		unsigned int length)
++{
++	int ret = -1;
++	int uwperipheralid;
++
++	uwperipheralid = dmac_check_request(peripheral_addr, RX);
++	if (uwperipheralid < 0) {
++		dma_err("p2m:Invalid devaddr.\n");
++		return -1;
++	}
++
++	ret = dmac_p2m_transfer(memaddr, uwperipheralid, length);
++	if (ret == -1) {
++		dma_err("p2m:trans err\n");
++		return -1;
++	}
++
++	return ret;
++}
++
++/*
++ *	Apply DMA interrupt resource
++ *	init channel state
++ */
++static int hi_dmac_probe(struct platform_device *platdev)
++{
++	unsigned int i;
++
++	reg_dmac_base_va = (void *)IO_ADDRESS(DMAC_BASE_REG);
++
++	dmac_init();
++
++	for (i = 0; i < DMAC_MAX_CHANNELS; i++)
++		g_channel_status[i] = DMAC_CHN_VACANCY;
++
++	return 0;
++}
++
++static int hi_dmac_remove(struct platform_device *platdev)
++{
++	int i;
++
++	for (i = 0; i < DMAC_MAX_CHANNELS; i++)
++		g_channel_status[i] = DMAC_CHN_VACANCY;
++
++	return 0;
++}
++
++static int hi_dmac_suspend(struct platform_device *dev, pm_message_t state)
++{
++	int i;
++
++	for (i = 0; i < DMAC_MAX_CHANNELS; i++)
++		g_channel_status[i] = DMAC_CHN_VACANCY;
++
++	return 0;
++}
++
++static int hi_dmac_resume(struct platform_device *dev)
++{
++	int i;
++
++	dmac_init();
++
++	for (i = 0; i < DMAC_MAX_CHANNELS; i++)
++		g_channel_status[i] = DMAC_CHN_VACANCY;
++
++	return 0;
++}
++
++struct platform_device hi_dmac_device = {
++	.name           = "hisilicon-dmac",
++	.id             = 0,
++};
++
++static struct platform_driver hi_dmac_driver = {
++	.probe          = hi_dmac_probe,
++	.remove         = hi_dmac_remove,
++	.suspend        = hi_dmac_suspend,
++	.resume         = hi_dmac_resume,
++	.driver         = {
++		.owner  = THIS_MODULE,
++		.name   = "hisilicon-dmac",
++	},
++};
++
++int __init dma_driver_init(void)
++{
++	int ret = 0;
++
++	ret = platform_device_register(&hi_dmac_device);
++	if (ret) {
++		pr_err("register netdevice device failed!");
++		goto _error_register_device;
++	}
++
++	ret = platform_driver_register(&hi_dmac_driver);
++	if (ret) {
++		pr_err("register netdevice driver failed!");
++		goto _error_register_driver;
++	}
++
++	return ret;
++
++_error_register_driver:
++	platform_device_unregister(&hi_dmac_device);
++_error_register_device:
++	return -1;
++}
++
++static void __exit dma_driver_exit(void)
++{
++	platform_driver_unregister(&hi_dmac_driver);
++
++	platform_device_unregister(&hi_dmac_device);
++}
++
++module_init(dma_driver_init);
++module_exit(dma_driver_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Hisilicon");
+diff --git a/drivers/hidmac/hi_dmac.h b/drivers/hidmac/hi_dmac.h
+new file mode 100644
+index 0000000..11f2b23
+--- /dev/null
++++ b/drivers/hidmac/hi_dmac.h
+@@ -0,0 +1,79 @@
++/* ./drivers/hidmac/hi_dmac.h
++ *
++ *
++ * History:
++ *      17-August-2006 create this file
++ */
++#ifndef __HI_DMAC_H__
++#define __HI_DMAC_H__
++
++#define  dmac_writew(addr, value)\
++	hi_writel(value, (void *)(addr))
++#define  dmac_readw(addr, v)\
++	v = hi_readl((void *)(addr))
++
++/*#define DMA_DEBUG*/
++#ifdef DMA_DEBUG
++#define dma_debug printk
++#else
++#define dma_debug(fmt, ...) do {} while (0);
++#endif
++
++#define DMAC_CONFIGURATIONx_HALT_DMA_ENABLE	(0x01L<<18)
++#define DMAC_CONFIGURATIONx_ACTIVE		(0x01L<<17)
++#define DMAC_CONFIGURATIONx_CHANNEL_ENABLE	1
++#define DMAC_CONFIGURATIONx_CHANNEL_DISABLE	0
++
++/*definition for the return value*/
++#define DMAC_ERROR_BASE				100
++#define DMAC_CHANNEL_INVALID			(DMAC_ERROR_BASE+1)
++
++#define DMAC_TRXFERSIZE_INVALID			(DMAC_ERROR_BASE+2)
++#define DMAC_SOURCE_ADDRESS_INVALID		(DMAC_ERROR_BASE+3)
++#define DMAC_DESTINATION_ADDRESS_INVALID	(DMAC_ERROR_BASE+4)
++#define DMAC_MEMORY_ADDRESS_INVALID		(DMAC_ERROR_BASE+5)
++#define DMAC_PERIPHERAL_ID_INVALID		(DMAC_ERROR_BASE+6)
++#define DMAC_DIRECTION_ERROR			(DMAC_ERROR_BASE+7)
++#define DMAC_TRXFER_ERROR			(DMAC_ERROR_BASE+8)
++#define DMAC_LLIHEAD_ERROR			(DMAC_ERROR_BASE+9)
++#define DMAC_SWIDTH_ERROR			(DMAC_ERROR_BASE+0xa)
++#define DMAC_LLI_ADDRESS_INVALID		(DMAC_ERROR_BASE+0xb)
++#define DMAC_TRANS_CONTROL_INVALID		(DMAC_ERROR_BASE+0xc)
++#define DMAC_MEMORY_ALLOCATE_ERROR		(DMAC_ERROR_BASE+0xd)
++#define DMAC_NOT_FINISHED			(DMAC_ERROR_BASE+0xe)
++
++#define DMAC_TIMEOUT				(DMAC_ERROR_BASE+0xf)
++#define DMAC_CHN_SUCCESS			(DMAC_ERROR_BASE+0x10)
++#define DMAC_CHN_ERROR				(DMAC_ERROR_BASE+0x11)
++#define DMAC_CHN_TIMEOUT			(DMAC_ERROR_BASE+0x12)
++#define DMAC_CHN_ALLOCAT			(DMAC_ERROR_BASE+0x13)
++#define DMAC_CHN_VACANCY			(DMAC_ERROR_BASE+0x14)
++
++#define DMAC_CONFIGURATIONx_ACTIVE_NOT		0
++
++/*the means the bit in the channel control register*/
++#define DMAC_TRANS_SIZE         0xff0
++
++/*DMAC peripheral structure*/
++typedef struct dmac_peripheral {
++	/* peripherial ID*/
++	unsigned int peri_id;
++	/*peripheral data register address*/
++	unsigned int peri_addr;
++	/*default channel control word*/
++	unsigned int transfer_ctrl;
++	/*default channel configuration word*/
++	unsigned int transfer_cfg;
++	/*default channel configuration word*/
++	unsigned int transfer_width;
++} dmac_peripheral;
++
++typedef struct mem_addr {
++	unsigned int addr_base;
++	unsigned int size;
++} mem_addr;
++
++typedef unsigned int dma_addr_t;
++/* #define PAGE_SIZE 0x1000 */
++
++#endif /* End of #ifndef __HI_INC_ECSDMACC_H__ */
+diff --git a/drivers/hidmac/hi_pl08x.c b/drivers/hidmac/hi_pl08x.c
+new file mode 100644
+index 0000000..7375ed9
+--- /dev/null
++++ b/drivers/hidmac/hi_pl08x.c
+@@ -0,0 +1,1282 @@
++/*
++ *
++ * Copyright (c) 2017 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/i2c.h>
++#include <linux/init.h>
++#include <linux/time.h>
++#include <linux/interrupt.h>
++#include <linux/delay.h>
++#include <linux/errno.h>
++#include <linux/err.h>
++#include <linux/platform_device.h>
++#include <linux/dma-mapping.h>
++#include <linux/pm_runtime.h>
++#include <linux/slab.h>
++#include <linux/of.h>
++#include <linux/clk.h>
++#include <linux/reset.h>
++#include <mach/io.h>
++#include <linux/hidmac.h>
++
++#include "hi_dmac.h"
++
++#ifdef CONFIG_ARCH_HI3516CV300
++#include "hidmac_hi3516cv300.h"
++#endif
++
++#ifdef CONFIG_ARCH_HI3531D
++#include "hidmac_hi3531d.h"
++#endif
++
++#ifdef CONFIG_ARCH_HI3521D
++#include "hidmac_hi3521d.h"
++#endif
++
++#ifdef CONFIG_ARCH_HI3536C
++#include "hidmac_hi3536c.h"
++#endif
++
++#define RX	0
++#define TX	1
++
++static int dmac_channel[CHANNEL_NUM] = {0, 1, 2, 3};
++
++int g_channel_status[CHANNEL_NUM];
++
++/* #define DEBUG */
++
++#define DEBUG
++#ifdef DEBUG
++#define dma_err printk
++#else
++#define dma_err(fmt, ...) do {} while (0)
++#endif
++
++/*
++ *Define Memory range
++ */
++mem_addr mem_num[MEM_MAX_NUM] = {
++	{DDRAM_ADRS, DDRAM_SIZE},
++	{FLASH_BASE, FLASH_SIZE}
++};
++
++typedef void REG_ISR(int *p_dma_chn, int *p_dma_status);
++REG_ISR *function[CHANNEL_NUM];
++
++struct hidmac_host {
++	struct clk *clk;
++	struct reset_control *rstc;
++	void __iomem *regbase;
++
++	int irq;
++};
++
++void __iomem *dma_regbase;
++unsigned int pllihead[2];
++
++#define CLR_INT(i)	((*(unsigned int *)(dma_regbase+0x008)) = (1 << i))
++
++/*
++ *	memory address validity check
++ *
++static int mem_check_valid(unsigned int addr)
++{
++	unsigned int cnt;
++
++	for (cnt = 0; cnt < MEM_MAX_NUM; cnt++) {
++		if ((addr >= mem_num[cnt].addr_base) &&
++			(addr <= (mem_num[cnt].addr_base + mem_num[cnt].size)))
++			return 0;
++	}
++
++	return -1;
++} */
++
++/*
++ * dmac interrupt handle function
++ */
++irqreturn_t dmac_isr(int irq, void *dev_id)
++{
++	struct hidmac_host *dma = dev_id;
++	unsigned int channel_status;
++	unsigned int channel_tc_status, channel_err_status;
++	unsigned int i;
++
++	/*read the status of current interrupt */
++	dmac_readw(dma->regbase + DMAC_INTSTATUS, channel_status);
++
++	/*decide which channel has trigger the interrupt*/
++	for (i = 0; i < DMAC_MAX_CHANNELS; i++) {
++		if ((((channel_status >> i) & 0x1) == 0x01)) {
++			/* [HSCP201306240006],l00181524,20130625 */
++			/* The INT status should be read first then clear it */
++			/* CLR_INT(i); */
++			dmac_readw(dma->regbase + DMAC_INTTCSTATUS, channel_tc_status);
++			dmac_readw(dma->regbase + DMAC_INTERRORSTATUS, channel_err_status);
++			CLR_INT(i);
++			/*??HSCP201403110002?? l00183122 20140723*/
++			if (g_channel_status[i] == DMAC_CHN_VACANCY
++						&& (function[i]) == NULL) {
++				if ((0x01 == ((channel_tc_status >> i) & 0x01)))
++					dmac_writew(dma->regbase + DMAC_INTTCCLEAR,
++								(0x01 << i));
++				else if ((0x01 == ((channel_err_status
++								>> i)&0x01)))
++					dmac_writew(dma->regbase + DMAC_INTERRCLR,
++								(0x01 << i));
++				continue;
++			}
++
++			/* save the current channel transfer */
++			/* status to g_channel_status[i] */
++			if ((0x01 == ((channel_tc_status >> i) & 0x01))) {
++				g_channel_status[i] = DMAC_CHN_SUCCESS;
++				dmac_writew(dma->regbase + DMAC_INTTCCLEAR, (0x01 << i));
++			} else if ((0x01 == ((channel_err_status >> i)&0x01))) {
++				g_channel_status[i] = -DMAC_CHN_ERROR;
++				dmac_writew(dma->regbase + DMAC_INTERRCLR, (0x01 << i));
++			} else {
++				pr_err("Isr Error in DMAC_IntHandeler");
++				pr_err("%d! channel\n", i);
++			}
++
++			if ((function[i]) != NULL)
++				function[i](&i, &g_channel_status[i]);
++		}
++	}
++
++	return IRQ_RETVAL(1);
++}
++
++/*
++ *	update the state of channels
++ */
++#define HI_DMA_UPDATE_TIMEOUT  5000000
++static int dma_update_status(unsigned int channel)
++{
++
++	unsigned int channel_status;
++	unsigned int channel_tc_status[3];
++	unsigned int channel_err_status[3];
++	unsigned int i = channel, j, time = 0;
++
++
++	while (1) {
++		for (j = 0; j < 3; j++) {
++			dmac_readw(dma_regbase + DMAC_RAWINTTCSTATUS,
++						channel_status);
++			channel_tc_status[j] = (channel_status >> i) & 0x01;
++			dmac_readw(dma_regbase + DMAC_RAWINTERRORSTATUS,
++						channel_status);
++			channel_err_status[j] = (channel_status >> i) & 0x01;
++		}
++
++		if ((channel_tc_status[0] == 0x1) &&
++			(channel_tc_status[1] == 0x1) &&
++				(channel_tc_status[2] == 0x1)) {
++			g_channel_status[i] = DMAC_CHN_SUCCESS;
++			dmac_writew(dma_regbase + DMAC_INTTCCLEAR, (0x01 << i));
++			break;
++		} else if ((channel_err_status[0] == 0x1) &&
++			(channel_err_status[1] == 0x1) &&
++				(channel_err_status[2] == 0x1)) {
++			g_channel_status[i] = -DMAC_CHN_ERROR;
++			dma_err("Error in DMAC %d finish!\n", i);
++			dmac_writew(dma_regbase + DMAC_INTERRCLR, (0x01 << i));
++			break;
++		}
++
++		if (++time == HI_DMA_UPDATE_TIMEOUT) {
++			dma_err("Timeout in DMAC %d!\n", i);
++			g_channel_status[i] = -DMAC_CHN_TIMEOUT;
++			break;
++		}
++	}
++
++	return g_channel_status[i];
++}
++
++
++/*
++ *	check the state of channels
++ */
++static int dmac_check_over(unsigned int channel)
++{
++	int status = 0;
++
++	if (-DMAC_CHN_ERROR == g_channel_status[channel]) {
++		dma_err("Error transfer %d finished\n", channel);
++		dmac_writew(dma_regbase + DMAC_CxCONFIG(channel), DMAC_CxDISABLE);
++		g_channel_status[channel] = DMAC_CHN_VACANCY;
++		status = -DMAC_CHN_ERROR;
++	} else if (DMAC_NOT_FINISHED == g_channel_status[channel])
++		status = DMAC_NOT_FINISHED;
++	else if (DMAC_CHN_ALLOCAT == g_channel_status[channel])
++		status = DMAC_CHN_ALLOCAT;
++	else if (DMAC_CHN_VACANCY == g_channel_status[channel])
++		status = DMAC_CHN_VACANCY;
++	else if (-DMAC_CHN_TIMEOUT == g_channel_status[channel]) {
++		dma_err("transfer %d timeout!\n", channel);
++		status = -DMAC_CHN_TIMEOUT;
++	} else if (DMAC_CHN_SUCCESS == g_channel_status[channel])
++		/*The transfer of Channel %d has finished successfully!*/
++		status = DMAC_CHN_SUCCESS;
++	else {
++		dmac_writew(dma_regbase + DMAC_CxCONFIG(channel), DMAC_CxDISABLE);
++		g_channel_status[channel] = DMAC_CHN_VACANCY;
++		status = -DMAC_CHN_ERROR;
++	}
++	return status;
++}
++
++spinlock_t my_lcok = __SPIN_LOCK_UNLOCKED(old_style_spin_init);
++unsigned long flags;
++
++/*
++ *	allocate channel.
++ */
++int dmac_channel_allocate(void *pisr)
++{
++	unsigned int i, channelinfo, g_channelinfo;
++
++	for (i = 0; i < CHANNEL_NUM; i++)
++		dmac_check_over(dmac_channel[i]);
++
++	dmac_readw(dma_regbase + DMAC_ENBLDCHNS, g_channelinfo);
++	g_channelinfo = g_channelinfo & 0x00ff;
++
++	for (i = 0; i < CHANNEL_NUM; i++) {
++		if (g_channel_status[dmac_channel[i]] == DMAC_CHN_VACANCY) {
++			channelinfo = g_channelinfo >> dmac_channel[i];
++			if (0x00 == (channelinfo & 0x01)) {
++				/*clear the interrupt in this channel */
++				dmac_writew(dma_regbase + DMAC_INTERRCLR,
++						(0x01 << dmac_channel[i]));
++				dmac_writew(dma_regbase + DMAC_INTTCCLEAR,
++						(0x01 << dmac_channel[i]));
++
++				g_channel_status[dmac_channel[i]]
++						= DMAC_CHN_ALLOCAT;
++				return dmac_channel[i];
++			}
++		}
++	}
++
++	dma_err("no to alloc\n");
++	return -EINVAL;
++}
++EXPORT_SYMBOL(dmac_channel_allocate);
++
++int dmac_register_isr(unsigned int channel, void *pisr)
++{
++	if (channel > CHANNEL_NUM - 1) {
++		dma_err("channel which choosed %d is error !\n", channel);
++		return -1;
++	}
++
++	if (g_channel_status[channel] != DMAC_CHN_VACANCY) {
++		dma_err("dma chn %d is in used!\n", channel);
++		return -1;
++	}
++
++	/*clear the interrupt in this channel */
++	dmac_writew(dma_regbase + DMAC_INTERRCLR, (0x01 << channel));
++	dmac_writew(dma_regbase + DMAC_INTTCCLEAR, (0x01 << channel));
++
++	function[channel] = (void *)pisr;
++	g_channel_status[channel] = DMAC_CHN_ALLOCAT;
++
++	return 0;
++}
++EXPORT_SYMBOL(dmac_register_isr);
++
++/*
++ *	free channel
++ */
++int dmac_channel_free(unsigned int channel)
++{
++	if (channel >= DMAC_MAX_CHANNELS) {
++		dma_err("channel larger than total.\n");
++		return -EINVAL;
++	}
++
++	g_channel_status[channel] = DMAC_CHN_VACANCY;
++	return 0;
++}
++EXPORT_SYMBOL(dmac_channel_free);
++
++static unsigned int dmac_check_request(unsigned int peripheral_addr,
++					int direction)
++{
++	int i;
++	/* check request pipe with peripheral_addr */
++	for (i = direction; i < DMAC_MAX_PERIPHERALS; i = i + 2) {
++		if (g_peripheral[i].peri_addr == peripheral_addr)
++			return i;
++	}
++
++	dma_err("Invalid devaddr\n");
++
++	return -1;
++}
++
++/*
++ *	init dmac register
++ *	clear interrupt flags
++ *	called by dma_driver_init
++ */
++int dmac_init(struct hidmac_host *dma)
++{
++	unsigned int i, tempvalue;
++	int ret;
++
++	clk_prepare_enable(dma->clk);
++	reset_control_deassert(dma->rstc);
++
++	dmac_readw(dma->regbase + DMAC_CONFIG, tempvalue);
++	if (tempvalue == 0) {
++		dmac_writew(dma->regbase + DMAC_CONFIG,
++				DMAC_CONFIG_VAL);
++		dmac_writew(dma->regbase + DMAC_INTTCCLEAR, 0xFF);
++		dmac_writew(dma->regbase + DMAC_INTERRCLR, 0xFF);
++		for (i = 0; i < DMAC_MAX_CHANNELS; i++) {
++			dmac_writew(dma->regbase + DMAC_CxCONFIG(i),
++				DMAC_CxDISABLE);
++			function[i] = NULL;
++		}
++	}
++
++	/* creat LLI */
++	/* alloc space for dma lli, as the source is uncontinuous, so... */
++	ret = allocate_dmalli_space(pllihead, 1);
++	if (ret < 0)
++		return -1;
++
++	if (request_irq(dma->irq, dmac_isr, 0, "hi_dma", dma)) {
++		dma_err("DMA Irq %d request failed\n", dma->irq);
++		free_dmalli_space(pllihead, 1);
++		return -1;
++	}
++
++	return 0;
++}
++
++
++/*
++ *	alloc_dma_lli_space
++ *	output:
++ *             ppheadlli[0]: memory physics address
++ *             ppheadlli[1]: virtual address
++ *
++ */
++int allocate_dmalli_space(unsigned int *ppheadlli, unsigned int page_num)
++{
++	dma_addr_t dma_phys;
++	void *dma_virt;
++
++	dma_virt = dma_alloc_coherent(NULL, page_num*PAGE_SIZE,
++					&dma_phys, GFP_DMA | __GFP_WAIT);
++	if (NULL == dma_virt) {
++		dma_err("can't get dma mem from system\n");
++		return -1;
++	}
++
++	ppheadlli[0] = (unsigned int)(dma_phys);
++	ppheadlli[1] = (unsigned int)(dma_virt);
++
++	return 0;
++}
++EXPORT_SYMBOL(allocate_dmalli_space);
++
++/*
++ *	free_dma_lli_space
++ */
++int free_dmalli_space(unsigned int *ppheadlli, unsigned int page_num)
++{
++	dma_addr_t dma_phys;
++	unsigned int dma_virt;
++
++	dma_phys = (dma_addr_t)(ppheadlli[0]);
++	dma_virt = ppheadlli[1];
++
++	dma_free_coherent(NULL, page_num*PAGE_SIZE,
++				(void *)dma_virt, dma_phys);
++
++	ppheadlli[0] = 0;
++	ppheadlli[1] = 0;
++	return 0;
++}
++EXPORT_SYMBOL(free_dmalli_space);
++
++/*
++ * config register for memory to memory DMA transfer without LLI
++ * note:
++ * it is necessary to call dmac_channelstart for channel enable
++ */
++int dmac_start_m2m(unsigned int  channel, unsigned int psource,
++			unsigned int pdest, unsigned int uwnumtransfers)
++{
++	unsigned int uwchannel_num, tmp_trasnsfer;
++
++	if (uwnumtransfers > (MAXTRANSFERSIZE << 2)) {
++		dma_err("Invalidate transfer size,size=%x\n", uwnumtransfers);
++		return -EINVAL;
++	}
++
++	uwchannel_num = channel;
++
++	if ((uwchannel_num == DMAC_CHANNEL_INVALID)
++			|| (uwchannel_num > CHANNEL_NUM)) {
++		pr_err("failure of DMAC channel allocation in M2M function!\n");
++		return -EFAULT;
++	}
++
++	/* dmac_writew (DMAC_CxCONFIG(uwchannel_num), DMAC_CxDISABLE); */
++	dmac_writew(dma_regbase + DMAC_CxSRCADDR(uwchannel_num), psource);
++	dmac_writew(dma_regbase + DMAC_CxDESTADDR(uwchannel_num), pdest);
++	dmac_writew(dma_regbase + DMAC_CxLLI(uwchannel_num), 0);
++	tmp_trasnsfer = (uwnumtransfers >> 2) & 0xfff;
++	tmp_trasnsfer = tmp_trasnsfer | (DMAC_CxCONTROL_M2M & (~0xfff));
++	dmac_writew(dma_regbase + DMAC_CxCONTROL(uwchannel_num), tmp_trasnsfer);
++	dmac_writew(dma_regbase + DMAC_CxCONFIG(uwchannel_num), DMAC_CxCONFIG_M2M);
++
++	return 0;
++}
++EXPORT_SYMBOL(dmac_start_m2m);
++
++/*
++ *	channel enable
++ *	start a dma transfer immediately
++ */
++int dmac_channelstart(unsigned int u32channel)
++{
++
++	unsigned int reg_value;
++
++	if (u32channel >= DMAC_MAX_CHANNELS) {
++		dma_err("channel larger %d\n", DMAC_MAX_CHANNELS);
++		return -EINVAL;
++	}
++
++	g_channel_status[u32channel] = DMAC_NOT_FINISHED;
++	dmac_readw(dma_regbase + DMAC_CxCONFIG(u32channel), reg_value);
++	dmac_writew(dma_regbase + DMAC_CxCONFIG(u32channel),
++			(reg_value | DMAC_CHANNEL_ENABLE));
++
++	return 0;
++}
++EXPORT_SYMBOL(dmac_channelstart);
++
++/*
++ *	wait for transfer end
++ */
++int dmac_wait(int channel)
++{
++	int ret_result, ret = 0;
++
++	if (channel < 0)
++		return -1;
++
++	while (1) {
++		ret_result = dma_update_status(channel);
++		if (ret_result == -DMAC_CHN_ERROR) {
++			dma_err("Transfer Error.\n");
++			ret = -1;
++			goto end;
++		} else  if (ret_result == DMAC_NOT_FINISHED)
++			udelay(10);
++		else if (ret_result == DMAC_CHN_SUCCESS) {
++			ret = DMAC_CHN_SUCCESS;
++			goto end;
++		}
++		else if (ret_result == DMAC_CHN_VACANCY) {
++			ret = DMAC_CHN_SUCCESS;
++			goto end;
++		} else if (ret_result == -DMAC_CHN_TIMEOUT) {
++			dma_err("Timeout.\n");
++			dmac_writew(dma_regbase + DMAC_CxCONFIG(channel), DMAC_CxDISABLE);
++			g_channel_status[channel] = DMAC_CHN_VACANCY;
++			ret = -1;
++			goto end;
++		}
++	}
++end:
++	dmac_channelclose(channel);
++	return ret;
++}
++EXPORT_SYMBOL(dmac_wait);
++
++/*
++ *	buile LLI for memory to memory DMA transfer
++ */
++int dmac_buildllim2m_isp(unsigned int *ppheadlli, unsigned int *psource,
++			unsigned int *pdest, unsigned int *length,
++			unsigned int lli_num)
++{
++	unsigned int address, phy_address;
++	unsigned int j;
++
++	if (ppheadlli != NULL) {
++		phy_address = (unsigned int)(ppheadlli[0]);
++		dma_debug("phy_address: 0x%X\n",phy_address);
++		address = (unsigned int)(ppheadlli[1]);
++		dma_debug("address: 0x%X\n",address);
++		for (j = 0; j < lli_num; j++) {
++			dma_debug("psource[%d]: 0x%X\n", j, psource[j]);
++			dmac_writew(address, psource[j]);
++			address += 4;
++			phy_address += 4;
++			dma_debug("pdest[%d]: 0x%X\n", j, pdest[j]);
++			dmac_writew(address, pdest[j]);
++			address += 4;
++			phy_address += 4;
++
++			/* if the last node, next_lli_addr = 0*/
++			if (j == (lli_num - 1))
++				dmac_writew(address, 0);
++			else
++				dmac_writew(address,
++					(((phy_address + 8) & (~0x03))
++					 | DMAC_CxLLI_LM));
++
++			address += 4;
++			phy_address += 4;
++
++			if (j == (lli_num - 1)) {
++				dmac_writew(address, ((DMAC_CxCONTROL_LLIM2M_ISP
++					&(~0xfff)) | (length[j])
++					| 0x80000000));
++			} else {
++				dmac_writew(address,
++					(((DMAC_CxCONTROL_LLIM2M_ISP&(~0xfff)) |
++					 (length[j])) & 0x7fffffff));
++			}
++
++			address += 4;
++			phy_address += 4;
++		}
++	}
++
++	return 0;
++}
++EXPORT_SYMBOL(dmac_buildllim2m_isp);
++
++/*
++ *	buile LLI for memory to memory DMA transfer
++ */
++int dmac_buildllim2m(unsigned int *ppheadlli, unsigned int pdest,
++			unsigned int psource, unsigned int totaltransfersize,
++				unsigned int uwnumtransfers)
++{
++	unsigned int lli_num = 0;
++	unsigned int last_lli = 0;
++	unsigned int address , phy_address, srcaddr, denstaddr;
++	unsigned int j;
++
++	lli_num = (totaltransfersize / uwnumtransfers);
++
++	if ((totaltransfersize % uwnumtransfers) != 0)
++		last_lli = 1, ++lli_num;
++
++	if (ppheadlli != NULL) {
++		phy_address = (unsigned int)(ppheadlli[0]);
++		address = (unsigned int)(ppheadlli[1]);
++		for (j = 0; j < lli_num; j++) {
++			srcaddr = (psource + (j*uwnumtransfers));
++			dmac_writew(address, srcaddr);
++			address += 4;
++			phy_address += 4;
++			denstaddr = (pdest + (j*uwnumtransfers));
++			dmac_writew(address, denstaddr);
++			address += 4;
++			phy_address += 4;
++			if (j == (lli_num - 1))
++				dmac_writew(address, 0);
++			else
++				dmac_writew(address,
++					(((phy_address + 8) & (~0x03))
++					 | DMAC_CxLLI_LM));
++
++			address += 4;
++			phy_address += 4;
++
++			if ((j == (lli_num - 1)) && (last_lli == 0))
++				dmac_writew(address, ((DMAC_CxCONTROL_LLIM2M
++					&(~0xfff)) | (uwnumtransfers >> 2)
++					| 0x80000000));
++			else if ((j == (lli_num - 1)) && (last_lli == 1))
++				dmac_writew(address, ((DMAC_CxCONTROL_LLIM2M
++					& (~0xfff)) | ((totaltransfersize
++					% uwnumtransfers) >> 2) | 0x80000000));
++			else
++				dmac_writew(address,
++					(((DMAC_CxCONTROL_LLIM2M&(~0xfff)) |
++					 (uwnumtransfers >> 2)) & 0x7fffffff));
++
++			address += 4;
++			phy_address += 4;
++		}
++	}
++
++	return 0;
++}
++EXPORT_SYMBOL(dmac_buildllim2m);
++
++/*
++ *	disable channel
++ *	used before the operation of register configuration
++ */
++int dmac_channelclose(unsigned int channel)
++{
++	unsigned int reg_value, count;
++
++	if (channel >= DMAC_MAX_CHANNELS) {
++		dma_err("channel larger than total.\n");
++		return -EINVAL;
++	}
++
++	dmac_readw(dma_regbase + DMAC_CxCONFIG(channel), reg_value);
++
++#define CHANNEL_CLOSE_IMMEDIATE
++#ifdef CHANNEL_CLOSE_IMMEDIATE
++	reg_value &= 0xFFFFFFFE;
++	dmac_writew(dma_regbase + DMAC_CxCONFIG(channel) , reg_value);
++#else
++	reg_value |= DMAC_CONFIGURATIONx_HALT_DMA_ENABLE;
++	/*ignore incoming dma request*/
++	dmac_writew(dma_regbase + DMAC_CxCONFIG(channel), reg_value);
++	dmac_readw(dma_regbase + DMAC_CxCONFIG(channel), reg_value);
++	/*if FIFO is empty*/
++	while ((reg_value & DMAC_CONFIGURATIONx_ACTIVE)
++			== DMAC_CONFIGURATIONx_ACTIVE)
++		dmac_readw(dma_regbase + DMAC_CxCONFIG(channel), reg_value);
++	reg_value &= 0xFFFFFFFE;
++	dmac_writew(dma_regbase + DMAC_CxCONFIG(channel), reg_value);
++#endif
++
++	dmac_readw(dma_regbase + DMAC_ENBLDCHNS, reg_value);
++	reg_value = reg_value & 0x00ff;
++	count = 0;
++	while (((reg_value >> channel) & 0x1) == 1) {
++		dmac_readw(dma_regbase + DMAC_ENBLDCHNS, reg_value);
++		reg_value = reg_value & 0x00ff;
++		if (count++ > 10000) {
++			dma_err("close failure.\n");
++			return -1;
++		}
++	}
++
++	return 0;
++}
++EXPORT_SYMBOL(dmac_channelclose);
++
++/*
++ *	load configuration from LLI for memory to memory
++ */
++int dmac_start_llim2m(unsigned int channel, unsigned int *pfirst_lli)
++{
++	unsigned int uwchannel_num;
++	dmac_lli  plli;
++	unsigned int first_lli;
++
++	if (NULL == pfirst_lli) {
++		dma_err("Invalidate LLI head!\n");
++		return -EFAULT;
++	}
++
++	uwchannel_num = channel;
++	if ((uwchannel_num == DMAC_CHANNEL_INVALID) ||
++				(uwchannel_num > 7)) {
++		dma_err("failure of DMAC channel allocation in");
++		dma_err("LLIM2M function,channel=%x!\n ", uwchannel_num);
++		return -EINVAL;
++	}
++
++	memset(&plli, 0, sizeof(plli));
++	first_lli = (unsigned int)pfirst_lli[1];
++	dmac_readw(first_lli, plli.src_addr);
++	dmac_readw(first_lli+4, plli.dst_addr);
++	dmac_readw(first_lli+8, plli.next_lli);
++	dmac_readw(first_lli+12, plli.lli_transfer_ctrl);
++
++	dmac_channelclose(uwchannel_num);
++	dmac_writew(dma_regbase + DMAC_INTTCCLEAR, (0x1 << uwchannel_num));
++	dmac_writew(dma_regbase + DMAC_INTERRCLR, (0x1 << uwchannel_num));
++	dmac_writew(dma_regbase + DMAC_SYNC, 0x0);
++
++	dmac_writew(dma_regbase + DMAC_CxCONFIG(uwchannel_num),
++			DMAC_CxDISABLE);
++	dmac_writew(dma_regbase + DMAC_CxSRCADDR(uwchannel_num),
++			(unsigned int)(plli.src_addr));
++	dmac_writew(dma_regbase + DMAC_CxDESTADDR(uwchannel_num),
++			(unsigned int)(plli.dst_addr));
++	dmac_writew(dma_regbase + DMAC_CxLLI(uwchannel_num),
++			(unsigned int)(plli.next_lli));
++	dmac_writew(dma_regbase + DMAC_CxCONTROL(uwchannel_num),
++			(unsigned int)(plli.lli_transfer_ctrl));
++	dmac_writew(dma_regbase + DMAC_CxCONFIG(uwchannel_num),
++			DMAC_CxCONFIG_LLIM2M);
++
++	return 0;
++}
++EXPORT_SYMBOL(dmac_start_llim2m);
++
++/*
++ *	load configuration from LLI for memory and peripheral
++ */
++int dmac_start_llim2p(unsigned int channel, unsigned int *pfirst_lli,
++				unsigned int uwperipheralid)
++{
++	unsigned int uwchannel_num;
++	dmac_lli plli;
++	unsigned int first_lli;
++	unsigned int temp = 0;
++
++	if (NULL == pfirst_lli) {
++		dma_err("Invalidate LLI head!\n");
++		return -EINVAL;
++	}
++	uwchannel_num = channel;
++	if ((uwchannel_num == DMAC_CHANNEL_INVALID) ||
++			(uwchannel_num > CHANNEL_NUM)) {
++		dma_err("failure of DMAC channel allocation in");
++		dma_err("LLIM2P function, channel=%x!\n ", uwchannel_num);
++		return -EINVAL;
++	}
++
++	memset(&plli, 0, sizeof(plli));
++	first_lli = (unsigned int)pfirst_lli[1];
++	dmac_readw(first_lli, plli.src_addr);
++	dmac_readw(first_lli+4, plli.dst_addr);
++	dmac_readw(first_lli+8, plli.next_lli);
++	dmac_readw(first_lli+12, plli.lli_transfer_ctrl);
++
++	dmac_channelclose(uwchannel_num);
++	dmac_writew(dma_regbase + DMAC_INTTCCLEAR, (0x1<<uwchannel_num));
++	dmac_writew(dma_regbase + DMAC_INTERRCLR, (0x1<<uwchannel_num));
++	dmac_writew(dma_regbase + DMAC_SYNC, 0x0);
++
++	dmac_readw(dma_regbase + DMAC_CxCONFIG(uwchannel_num), temp);
++	dmac_writew(dma_regbase + DMAC_CxCONFIG(uwchannel_num),
++			temp|DMAC_CxDISABLE);
++	dmac_writew(dma_regbase + DMAC_CxSRCADDR(uwchannel_num),
++			plli.src_addr);
++	dmac_writew(dma_regbase + DMAC_CxDESTADDR(uwchannel_num),
++			plli.dst_addr);
++	dmac_writew(dma_regbase + DMAC_CxLLI(uwchannel_num),
++			plli.next_lli);
++	dmac_writew(dma_regbase + DMAC_CxCONTROL(uwchannel_num),
++			plli.lli_transfer_ctrl);
++
++	return 0;
++}
++EXPORT_SYMBOL(dmac_start_llim2p);
++
++/*
++ *	enable memory and peripheral dma transfer
++ *	note:
++ *	it is necessary to call dmac_channelstart to enable channel
++ */
++int dmac_start_m2p(unsigned int channel, unsigned int memaddr,
++		unsigned int uwperipheralid, unsigned int uwnumtransfers,
++		unsigned int next_lli_addr)
++{
++
++	unsigned int uwtrans_control = 0;
++	unsigned int addtmp, tmp;
++	unsigned int uwdst_addr = 0, uwsrc_addr = 0;
++	unsigned int uwwidth;
++	int uwchannel_num;
++
++	addtmp = memaddr;
++
++	if ((uwperipheralid > 15)) {
++		dma_err("Invalid peripheral id%x\n", uwperipheralid);
++		return -EINVAL;
++	}
++
++	uwchannel_num = (int)channel;
++	if ((uwchannel_num == DMAC_CHANNEL_INVALID)
++		|| (uwchannel_num > CHANNEL_NUM) || (uwchannel_num < 0)) {
++		dma_err("failure alloc\n");
++		return -EFAULT;
++	}
++
++	/* must modified with different peripheral */
++	uwwidth = g_peripheral[uwperipheralid].transfer_width;
++
++	/* check transfer direction *
++	 * even number-->TX, odd number-->RX*/
++	uwsrc_addr = memaddr;
++	uwdst_addr = (unsigned int)(g_peripheral[uwperipheralid].peri_addr);
++
++	tmp = uwnumtransfers >> uwwidth;
++	if (tmp & (~0x0fff)) {
++		dma_err("Invalidate size%x\n", uwnumtransfers);
++		return -EINVAL;
++	}
++
++	tmp = tmp & 0xfff;
++	uwtrans_control = tmp |
++		(g_peripheral[uwperipheralid].transfer_ctrl & (~0xfff));
++	dmac_writew(dma_regbase + DMAC_INTTCCLEAR, (0x1<<(unsigned int)uwchannel_num));
++	dmac_writew(dma_regbase + DMAC_INTERRCLR, (0x1<<(unsigned int)uwchannel_num));
++	dmac_writew(dma_regbase + DMAC_CxSRCADDR(uwchannel_num), (unsigned int)uwsrc_addr);
++	dmac_writew(dma_regbase + DMAC_CxDESTADDR(uwchannel_num), (unsigned int)uwdst_addr);
++	dmac_writew(dma_regbase + DMAC_CxCONTROL(uwchannel_num),
++			(unsigned int)uwtrans_control);
++	dmac_writew(dma_regbase + DMAC_CxCONFIG(uwchannel_num),
++			(g_peripheral[uwperipheralid].transfer_cfg));
++
++	return 0;
++}
++
++/*
++ *	enable memory and peripheral dma transfer
++ *	note:
++ *	it is necessary to call dmac_channelstart to enable channel
++ */
++int dmac_start_p2m(unsigned int channel, unsigned int memaddr,
++		unsigned int uwperipheralid, unsigned int uwnumtransfers,
++		unsigned int next_lli_addr)
++{
++	unsigned int uwtrans_control = 0;
++	unsigned int addtmp, tmp;
++	unsigned int uwdst_addr = 0, uwsrc_addr = 0;
++	unsigned int uwwidth;
++	int uwchannel_num;
++
++	addtmp = memaddr;
++
++	if ((uwperipheralid > 15)) {
++		dma_err("Invalid peripheral id%x\n", uwperipheralid);
++		return -EINVAL;
++	}
++
++	uwchannel_num = (int)channel;
++	if ((uwchannel_num == DMAC_CHANNEL_INVALID)
++		|| (uwchannel_num > 3) || (uwchannel_num < 0)) {
++		dma_err("failure alloc\n");
++		return -EFAULT;
++	}
++
++	/* must modified with different peripheral */
++	uwwidth = g_peripheral[uwperipheralid].transfer_width;
++
++	/* check transfer direction *
++	 * even number-->TX, odd number-->RX*/
++	uwsrc_addr = (unsigned int)(g_peripheral[uwperipheralid].peri_addr);
++	uwdst_addr = memaddr;
++
++	tmp = uwnumtransfers >> uwwidth;
++	if (tmp & (~0x0fff)) {
++		dma_err("Invalidate size%x\n", uwnumtransfers);
++		return -EINVAL;
++	}
++
++	tmp = tmp & 0xfff;
++	uwtrans_control = tmp |
++		(g_peripheral[uwperipheralid].transfer_ctrl & (~0xfff));
++	dmac_writew(dma_regbase + DMAC_INTTCCLEAR, (0x1<<(unsigned int)uwchannel_num));
++	dmac_writew(dma_regbase + DMAC_INTERRCLR, (0x1<<(unsigned int)uwchannel_num));
++	dmac_writew(dma_regbase + DMAC_CxSRCADDR(uwchannel_num),
++			(unsigned int)uwsrc_addr);
++	dmac_writew(dma_regbase + DMAC_CxDESTADDR(uwchannel_num),
++			(unsigned int)uwdst_addr);
++	dmac_writew(dma_regbase + DMAC_CxCONTROL(uwchannel_num),
++			(unsigned int)uwtrans_control);
++	dmac_writew(dma_regbase + DMAC_CxCONFIG(uwchannel_num),
++			(g_peripheral[uwperipheralid].transfer_cfg));
++
++	return 0;
++}
++
++/*
++ *	execute memory to memory dma transfer without LLI
++ */
++int dmac_m2m_transfer(unsigned int source, unsigned int dest,
++						unsigned int length)
++{
++	unsigned int ulchnn, dma_size = 0;
++	unsigned int dma_count, left_size;
++
++	left_size = length;
++	dma_count = 0;
++	ulchnn = dmac_channel_allocate(NULL);
++
++	ulchnn = 2;
++
++	dma_err("use channel %d\n", ulchnn);
++
++	while ((left_size >> 2) >= 0xffc) {
++		dma_size   = 0xffc;
++		left_size -= (dma_size << 2);
++		dma_err("left_size is %x.", left_size);
++		dmac_start_m2m(ulchnn, (unsigned int)(source
++			+ dma_count * (dma_size << 2)),
++			(unsigned int)(dest + dma_count * (dma_size << 2)),
++					(dma_size << 2));
++		if (dmac_channelstart(ulchnn) != 0) {
++			dma_err("start channel error...\n");
++			return -1;
++		}
++
++		if (dmac_wait(ulchnn) != DMAC_CHN_SUCCESS) {
++			dma_err("dma transfer error...\n");
++			return -1;
++		}
++
++		dma_count++;
++	}
++
++	dmac_start_m2m(ulchnn, (source + dma_count * (dma_size << 2)),
++			(dest + dma_count * (dma_size << 2)), (left_size << 2));
++
++	if (dmac_channelstart(ulchnn) != 0)
++		return -1;
++
++	if (dmac_wait(ulchnn) != DMAC_CHN_SUCCESS)
++		return -1;
++
++	return 0;
++}
++EXPORT_SYMBOL(dmac_m2m_transfer);
++
++/*
++ *	execute memory to peripheral dma transfer without LLI
++ */
++int dmac_m2p_transfer(unsigned int memaddr, unsigned int uwperipheralid,
++			unsigned int length)
++{
++	unsigned int ulchnn, dma_size = 0;
++	unsigned int dma_count, left_size;
++	unsigned int uwwidth;
++
++	left_size = length;
++	dma_count = 0;
++
++	ulchnn = dmac_channel_allocate(NULL);
++	if (DMAC_CHANNEL_INVALID == ulchnn)
++		return -1;
++
++	uwwidth = g_peripheral[uwperipheralid].transfer_width;
++
++	while ((left_size >> uwwidth) >= 0xffc) {
++		dma_size = 0xffc;
++		left_size -= (dma_size << uwwidth);
++
++		if (dmac_start_m2p(ulchnn,
++			(unsigned int)(memaddr + dma_count * dma_size),
++			uwperipheralid, (dma_size << uwwidth), 0) < 0)
++			return -1;
++
++		if (dmac_channelstart(ulchnn) != 0)
++			return -1;
++
++		if (dmac_wait(ulchnn) != DMAC_CHN_SUCCESS) {
++			dmac_channel_free(ulchnn);
++			return -1;
++		}
++
++		dma_count++;
++	}
++
++	pr_debug("memaddr=0x%x\n", (unsigned int)(memaddr
++					+ dma_count * dma_size));
++
++	if (dmac_start_m2p(ulchnn,
++		(unsigned int)(memaddr + dma_count * dma_size),
++			uwperipheralid, left_size, 0) < 0)
++		return -1;
++
++	if (dmac_channelstart(ulchnn) != 0)
++		return -1;
++
++	return ulchnn;
++}
++
++/*
++ *	execute memory to peripheral dma transfer without LLI
++ */
++int dmac_p2m_transfer(unsigned int memaddr, unsigned int uwperipheralid,
++			unsigned int length)
++{
++	unsigned int ulchnn, dma_size = 0;
++	unsigned int dma_count, left_size;
++	unsigned int uwwidth;
++
++	left_size = length;
++	dma_count = 0;
++
++	ulchnn = dmac_channel_allocate(NULL);
++	if (DMAC_CHANNEL_INVALID == ulchnn)
++		return -1;
++
++	uwwidth = g_peripheral[uwperipheralid].transfer_width;
++
++	while ((left_size >> uwwidth) >= 0xffc) {
++		dma_size = 0xffc;
++		left_size -= (dma_size << uwwidth);
++
++		if (dmac_start_p2m(ulchnn,
++			(unsigned int)(memaddr + dma_count * dma_size),
++			uwperipheralid, (dma_size << uwwidth), 0) < 0)
++			return -1;
++
++		if (dmac_channelstart(ulchnn) != 0)
++			return -1;
++
++		if (dmac_wait(ulchnn) != DMAC_CHN_SUCCESS) {
++			dmac_channel_free(ulchnn);
++			return -1;
++		}
++
++		dma_count++;
++	}
++
++	pr_debug("memaddr=0x%x\n", (unsigned int)(memaddr
++					+ dma_count * dma_size));
++
++	if (dmac_start_p2m(ulchnn,
++		(unsigned int)(memaddr + dma_count * dma_size),
++			uwperipheralid, left_size, 0) < 0)
++		return -1;
++
++	if (dmac_channelstart(ulchnn) != 0)
++		return -1;
++
++	return ulchnn;
++}
++
++/*
++ * memory to memory dma transfer with LLI
++ *
++ * @source
++ * @dest
++ * @length
++ * @num
++ * */
++int do_dma_llim2m_isp(unsigned int *source,
++		unsigned int *dest,
++		unsigned int *length,
++		unsigned int num)
++{
++	unsigned int chnn;
++	int ret = 0;
++
++	/* the dma channel is default using 2 */
++	chnn = 2;
++
++	ret = dmac_buildllim2m_isp(pllihead, source, dest, length, num);
++
++	if (ret) {
++		dma_err("build lli error...\n");
++		return -1;
++	}
++
++	/* dmac_register_isr(chnn, dmac_channel_close); */
++	ret = dmac_start_llim2m(chnn, pllihead);
++	if (ret)
++		return -1;
++
++	if (dmac_channelstart(chnn) != 0) {
++		dma_err("start channel error...\n");
++		return -1;
++	}
++
++	return ret;
++}
++EXPORT_SYMBOL(do_dma_llim2m_isp);
++
++int do_dma_m2p(unsigned int memaddr, unsigned int peripheral_addr,
++		unsigned int length)
++{
++	int ret = 0;
++	int uwperipheralid;
++
++	uwperipheralid = dmac_check_request(peripheral_addr, TX);
++	if (uwperipheralid < 0) {
++		dma_err("m2p:Invalid devaddr\n");
++		return -1;
++	}
++
++	ret = dmac_m2p_transfer(memaddr, uwperipheralid, length);
++	if (ret == -1) {
++		dma_err("m2p:trans err\n");
++		return -1;
++	}
++
++	return ret;
++}
++
++int do_dma_p2m(unsigned int memaddr, unsigned int peripheral_addr,
++		unsigned int length)
++{
++	int ret = -1;
++	int uwperipheralid;
++
++	uwperipheralid = dmac_check_request(peripheral_addr, RX);
++	if (uwperipheralid < 0) {
++		dma_err("p2m:Invalid devaddr.\n");
++		return -1;
++	}
++
++	ret = dmac_p2m_transfer(memaddr, uwperipheralid, length);
++	if (ret == -1) {
++		dma_err("p2m:trans err\n");
++		return -1;
++	}
++
++	return ret;
++}
++
++/*
++ *	Apply DMA interrupt resource
++ *	init channel state
++ */
++static int hi_dmac_probe(struct platform_device *platdev)
++{
++	unsigned int i;
++	struct hidmac_host *dma;
++	struct resource *res;
++	int ret;
++
++	dma = devm_kzalloc(&platdev->dev, sizeof(*dma), GFP_KERNEL);
++	if (!dma)
++		return -ENOMEM;
++
++	res = platform_get_resource(platdev, IORESOURCE_MEM, 0);
++	if (!res) {
++		dev_err(&platdev->dev, "no mmio resource\n");
++		return -ENODEV;
++	}
++
++	dma->regbase = devm_ioremap_resource(&platdev->dev, res);
++	if (IS_ERR(dma->regbase))
++		return PTR_ERR(dma->regbase);
++
++	dma->clk = devm_clk_get(&platdev->dev, NULL);
++	if (IS_ERR(dma->clk))
++		return PTR_ERR(dma->clk);
++
++	dma->rstc = devm_reset_control_get(&platdev->dev, "dma-reset");
++	if (IS_ERR(dma->rstc))
++		return PTR_ERR(dma->rstc);
++
++	dma->irq = platform_get_irq(platdev, 0);
++	if (unlikely(dma->irq < 0))
++		return -ENODEV;
++
++	dma_regbase = dma->regbase;
++
++	ret = dmac_init(dma);
++	if (ret)
++		return -ENODEV;
++
++	platform_set_drvdata(platdev, dma);
++
++	for (i = 0; i < DMAC_MAX_CHANNELS; i++)
++		g_channel_status[i] = DMAC_CHN_VACANCY;
++
++	return ret;
++}
++
++static int hi_dmac_remove(struct platform_device *platdev)
++{
++	int i;
++	struct hidmac_host *dma = platform_get_drvdata(platdev);
++
++	clk_disable_unprepare(dma->clk);
++
++	for (i = 0; i < DMAC_MAX_CHANNELS; i++)
++		g_channel_status[i] = DMAC_CHN_VACANCY;
++
++	free_dmalli_space(pllihead, 1);
++
++	return 0;
++}
++
++static int hi_dmac_suspend(struct platform_device *platdev,
++		pm_message_t state)
++{
++	int i;
++	struct hidmac_host *dma = platform_get_drvdata(platdev);
++
++	clk_prepare_enable(dma->clk);
++
++	for (i = 0; i < DMAC_MAX_CHANNELS; i++)
++		g_channel_status[i] = DMAC_CHN_VACANCY;
++
++	clk_disable_unprepare(dma->clk);
++
++	return 0;
++}
++
++static int hi_dmac_resume(struct platform_device *platdev)
++{
++	int i;
++	struct hidmac_host *dma = platform_get_drvdata(platdev);
++	unsigned int tempvalue;
++
++	clk_prepare_enable(dma->clk);
++	reset_control_deassert(dma->rstc);
++
++	dmac_readw(dma->regbase + DMAC_CONFIG, tempvalue);
++	if (tempvalue == 0) {
++		dmac_writew(dma->regbase + DMAC_CONFIG,
++				DMAC_CONFIG_VAL);
++		dmac_writew(dma->regbase + DMAC_INTTCCLEAR, 0xFF);
++		dmac_writew(dma->regbase + DMAC_INTERRCLR, 0xFF);
++		for (i = 0; i < DMAC_MAX_CHANNELS; i++) {
++			dmac_writew(dma->regbase + DMAC_CxCONFIG(i),
++				DMAC_CxDISABLE);
++			function[i] = NULL;
++		}
++	}
++
++	for (i = 0; i < DMAC_MAX_CHANNELS; i++)
++		g_channel_status[i] = DMAC_CHN_VACANCY;
++
++	return 0;
++}
++
++static const struct of_device_id hisi_dmac_dt_ids[] = {
++	{ .compatible = "hisilicon,hisi-dmac"},
++	{ /* sentinel */ }
++};
++MODULE_DEVICE_TABLE(of, hisi_dmac_dt_ids);
++
++static struct platform_driver hisi_dmac_driver = {
++	.driver = {
++		.name   = "hisi-dmac",
++		.of_match_table = hisi_dmac_dt_ids,
++	},
++	.probe      = hi_dmac_probe,
++	.remove     = hi_dmac_remove,
++	.suspend    = hi_dmac_suspend,
++	.resume     = hi_dmac_resume,
++};
++
++module_platform_driver(hisi_dmac_driver);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Hisilicon");
++MODULE_DESCRIPTION("HiSilicon DMA Controller driver");
+diff --git a/drivers/hidmac/hidmac_hi3516av200.c b/drivers/hidmac/hidmac_hi3516av200.c
+new file mode 100644
+index 0000000..cf9132a
+--- /dev/null
++++ b/drivers/hidmac/hidmac_hi3516av200.c
+@@ -0,0 +1,90 @@
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/i2c.h>
++#include <linux/init.h>
++#include <linux/time.h>
++#include <linux/interrupt.h>
++#include <linux/delay.h>
++#include <linux/errno.h>
++#include <linux/err.h>
++#include <linux/platform_device.h>
++#include <linux/pm_runtime.h>
++#include <linux/slab.h>
++#include <linux/io.h>
++
++#define SYS_CRG_BASE    IO_ADDRESS(0x12010000)
++#define REG_PERI_CRG56  0xe0
++#define DMAC_CLK_EN     (1 << 1)
++#define DMAC_SRST_REQ   (1 << 0)
++
++/*
++ *	DMA config array!
++ *	DREQ, FIFO, CONTROL, CONFIG, BITWIDTH
++ */
++dmac_peripheral  g_peripheral[DMAC_MAX_PERIPHERALS] = {
++	/* periphal 0: UART0 RX, 8bit width */
++	{0, UART0_DATA_REG, 0x99000000, 0xd000, 0},
++
++	/* periphal 1: UART0 TX, 8bit width */
++	{1, UART0_DATA_REG, 0x96000000, 0xc840, 0},
++
++	/*periphal 2: UART1 RX, 8bit width */
++	{2, UART1_DATA_REG, 0x99000000, 0xd004, 0},
++
++	/*periphal 3: UART1 TX, 8bit width */
++	{3, UART1_DATA_REG, 0x96000000, 0xc8c0, 0},
++
++	/*periphal 4: UART2 RX, 8bit width */
++	{4, UART2_DATA_REG, 0x99000000, 0xd008, 0},
++
++	/*periphal 5: UART2 TX, 8bit width */
++	{5, UART2_DATA_REG, 0x96000000, 0xc940, 0},
++
++	/*periphal 6: UART3 RX, 8bit width */
++	{6, UART3_DATA_REG, 0x99000000, 0xd00c, 0},
++
++	/*periphal 7: UART3 TX, 8bit width */
++	{7, UART3_DATA_REG, 0x96000000, 0xc9c0, 0},
++
++	/*periphal 8: I2C0 RX, 8bit width */
++	{8, I2C0_DATA_REG, 0x99000000, 0xd010, 0},
++
++	/*periphal 9: I2C0 TX, 8bit width */
++	{9, I2C0_DATA_REG, 0x96000000, 0xca40, 0},
++
++	/*periphal 10: I2C1 RX, 8bit width */
++	{10, I2C1_DATA_REG, 0x99000000, 0xd014, 0},
++
++	/*periphal 11: I2C1 TX, 8bit width */
++	{11, I2C1_DATA_REG, 0x96000000, 0xcac0, 0},
++
++	/*periphal 12: I2C2 RX, 8bit width */
++	{12, SPI2_DATA_REG, 0x99000000, 0xd018, 0},
++
++	/*periphal 13: I2C2 TX, 8bit width */
++	{13, SPI2_DATA_REG, 0x96000000, 0xcb40, 0},
++
++	/*periphal 14: I2C3 RX, 8bit width */
++	{14, I2C2_DATA_REG, 0x99000000, 0xd01c, 0},
++
++	/*periphal 15: I2C3 TX, 8bit width */
++	{15, I2C2_DATA_REG, 0x96000000, 0xcbc0, 0},
++};
++
++void hidmac_clk_en(void)
++{
++	unsigned int tmp;
++
++	dmac_readw(SYS_CRG_BASE + REG_PERI_CRG56, tmp);
++	tmp |= DMAC_CLK_EN;
++	dmac_writew(SYS_CRG_BASE + REG_PERI_CRG56, tmp);
++}
++
++void hidmac_unreset(void)
++{
++	unsigned int tmp;
++
++	dmac_readw(SYS_CRG_BASE + REG_PERI_CRG56, tmp);
++	tmp &= ~DMAC_SRST_REQ;
++	dmac_writew(SYS_CRG_BASE + REG_PERI_CRG56, tmp);
++}
+diff --git a/drivers/hidmac/hidmac_hi3516av200.h b/drivers/hidmac/hidmac_hi3516av200.h
+new file mode 100644
+index 0000000..a0e7beb
+--- /dev/null
++++ b/drivers/hidmac/hidmac_hi3516av200.h
+@@ -0,0 +1,99 @@
++#ifndef __HI_DMAC_HI3516AV200_H__
++#define __HI_DMAC_HI3516AV200_H__
++
++#define DDRAM_ADRS	0x80000000      /* fixed */
++#define DDRAM_SIZE	0x3FFFFFFF      /* 1GB DDR. */
++
++#define FLASH_BASE	0x10000000
++#define FLASH_SIZE	0x04000000      /* (32MB) */
++
++#define DMAC_BASE_REG	CONFIG_HI_DMAC_IO_BASE
++#define DMAC_INTTCCLEAR		IO_DMAC_ADDRESS(DMAC_BASE_REG + 0X08)
++
++#define DMAC_INTSTATUS		IO_DMAC_ADDRESS(DMAC_BASE_REG + 0X00)
++#define DMAC_INTTCSTATUS	IO_DMAC_ADDRESS(DMAC_BASE_REG + 0X04)
++#define DMAC_INTERRORSTATUS	IO_DMAC_ADDRESS(DMAC_BASE_REG + 0X0C)
++
++#define DMAC_INTERRCLR		IO_DMAC_ADDRESS(DMAC_BASE_REG + 0X10)
++#define DMAC_RAWINTTCSTATUS	IO_DMAC_ADDRESS(DMAC_BASE_REG + 0X14)
++#define DMAC_RAWINTERRORSTATUS	IO_DMAC_ADDRESS(DMAC_BASE_REG + 0X18)
++#define DMAC_ENBLDCHNS		IO_DMAC_ADDRESS(DMAC_BASE_REG + 0X1C)
++#define DMAC_CONFIG		IO_DMAC_ADDRESS(DMAC_BASE_REG + 0X30)
++#define DMAC_SYNC		IO_DMAC_ADDRESS(DMAC_BASE_REG + 0X34)
++
++#define DMAC_MAXTRANSFERSIZE	0x0fff /*the max length is denoted by 0-11bit*/
++#define MAXTRANSFERSIZE		DMAC_MAXTRANSFERSIZE
++#define DMAC_CxDISABLE		0x00
++#define DMAC_CxENABLE		0x01
++
++/*the definition for DMAC channel register*/
++#define DMAC_CxBASE(i)		IO_DMAC_ADDRESS(DMAC_BASE_REG + 0x100+i*0x20)
++#define DMAC_CxSRCADDR(i)	DMAC_CxBASE(i)
++#define DMAC_CxDESTADDR(i)	(DMAC_CxBASE(i)+0x04)
++#define DMAC_CxLLI(i)		(DMAC_CxBASE(i)+0x08)
++#define DMAC_CxCONTROL(i)	(DMAC_CxBASE(i)+0x0C)
++#define DMAC_CxCONFIG(i)	(DMAC_CxBASE(i)+0x10)
++
++/*the means the bit in the channel control register*/
++#define DMAC_CxCONTROL_M2M	0x9d480000  /* Dwidth=32,burst size=4 */
++#define DMAC_CxCONTROL_LLIM2M	0x0f480000  /* Dwidth=32,burst size=1 */
++#define DMAC_CxLLI_LM		0x01
++
++#define DMAC_CxCONFIG_M2M	0xc000
++#define DMAC_CxCONFIG_LLIM2M	0xc000
++
++/*#define DMAC_CxCONFIG_M2M  0x4001*/
++#define DMAC_CHANNEL_ENABLE	1
++#define DMAC_CHANNEL_DISABLE	0xfffffffe
++
++#define DMAC_CxCONTROL_P2M	0x89409000
++#define DMAC_CxCONFIG_P2M	0xd000
++
++#define DMAC_CxCONTROL_M2P	0x86089000
++#define DMAC_CxCONFIG_M2P	0xc800
++
++#define DMAC_CxCONFIG_SIO_P2M	0x0000d000
++#define DMAC_CxCONFIG_SIO_M2P	0x0000c800
++
++/*default the config and sync regsiter for DMAC controller*/
++/*M1,M2 little endian, enable DMAC*/
++#define DMAC_CONFIG_VAL		0x01
++/*enable the sync logic for the 16 peripheral*/
++#define DMAC_SYNC_VAL		0x0
++
++#define DMAC_MAX_PERIPHERALS	16
++#define MEM_MAX_NUM		2
++#define CHANNEL_NUM		CONFIG_HI_DMAC_CHANNEL_NUM
++#define DMAC_MAX_CHANNELS	CHANNEL_NUM
++
++#define REG_BASE_UART0		0x12100000
++#define UART0_DATA_REG		(REG_BASE_UART0 + 0x0)
++
++#define REG_BASE_UART1		0x12101000
++#define UART1_DATA_REG		(REG_BASE_UART1 + 0x0)
++
++#define REG_BASE_UART2		0x12102000
++#define UART2_DATA_REG		(REG_BASE_UART2 + 0x0)
++
++#define REG_BASE_UART3		0x12103000
++#define UART3_DATA_REG		(REG_BASE_UART3 + 0x0)
++
++#define REG_BASE_I2C0		0x12110000
++#define I2C0_DATA_REG		(REG_BASE_I2C0 + 0x10)
++
++#define REG_BASE_I2C1		0x12111000
++#define I2C1_DATA_REG		(REG_BASE_I2C1 + 0x10)
++
++#define REG_BASE_I2C2		0x12112000
++#define I2C2_DATA_REG		(REG_BASE_I2C2 + 0x10)
++
++#define REG_BASE_I2C3		0x12113000
++#define I2C3_DATA_REG		(REG_BASE_I2C3 + 0x10)
++
++#define REG_BASE_SPI2		0x12122000
++#define SPI2_DATA_REG		(REG_BASE_SPI2 + 0x8)
++
++/*the transfer control and configuration value for different peripheral*/
++
++extern int g_channel_status[CHANNEL_NUM];
++#endif
+diff --git a/drivers/hidmac/hidmac_hi3516cv300.h b/drivers/hidmac/hidmac_hi3516cv300.h
+new file mode 100644
+index 0000000..61fbf09
+--- /dev/null
++++ b/drivers/hidmac/hidmac_hi3516cv300.h
+@@ -0,0 +1,139 @@
++#ifndef __HI_DMAC_HI3516CV300_H__
++#define __HI_DMAC_HI3516CV300_H__
++
++#define DDRAM_ADRS	0x80000000      /* fixed */
++#define DDRAM_SIZE	0x3FFFFFFF      /* 1GB DDR. */
++
++#define FLASH_BASE	0x10000000
++#define FLASH_SIZE	0x04000000      /* (32MB) */
++
++#define DMAC_INTSTATUS		0X00
++#define DMAC_INTTCSTATUS	0X04
++#define DMAC_INTTCCLEAR		0X08
++#define DMAC_INTERRORSTATUS	0X0C
++
++#define DMAC_INTERRCLR		0X10
++#define DMAC_RAWINTTCSTATUS	0X14
++#define DMAC_RAWINTERRORSTATUS	0X18
++#define DMAC_ENBLDCHNS		0X1C
++#define DMAC_CONFIG			0X30
++#define DMAC_SYNC			0X34
++
++#define DMAC_MAXTRANSFERSIZE	0x0fff /*the max length is denoted by 0-11bit*/
++#define MAXTRANSFERSIZE		DMAC_MAXTRANSFERSIZE
++#define DMAC_CxDISABLE		0x00
++#define DMAC_CxENABLE		0x01
++
++/*the definition for DMAC channel register*/
++#define DMAC_CxBASE(i)		(0x100+i*0x20)
++#define DMAC_CxSRCADDR(i)	DMAC_CxBASE(i)
++#define DMAC_CxDESTADDR(i)	(DMAC_CxBASE(i)+0x04)
++#define DMAC_CxLLI(i)		(DMAC_CxBASE(i)+0x08)
++#define DMAC_CxCONTROL(i)	(DMAC_CxBASE(i)+0x0C)
++#define DMAC_CxCONFIG(i)	(DMAC_CxBASE(i)+0x10)
++
++/*the means the bit in the channel control register*/
++#define DMAC_CxCONTROL_M2M	0x9d480000  /* Dwidth=32,burst size=4 */
++#define DMAC_CxCONTROL_LLIM2M		0x0f480000  /* Dwidth=32,burst size=1 */
++#define DMAC_CxCONTROL_LLIM2M_ISP	0x0b489000  /* Dwidth=32,burst size=1 */
++#define DMAC_CxLLI_LM		0x01
++
++#define NUM_HAL_INTERRUPT_DMAC         (14 + 16)
++
++#define DMAC_CxCONFIG_M2M	0xc000
++#define DMAC_CxCONFIG_LLIM2M	0xc000
++
++/*#define DMAC_CxCONFIG_M2M  0x4001*/
++#define DMAC_CHANNEL_ENABLE	1
++#define DMAC_CHANNEL_DISABLE	0xfffffffe
++
++#define DMAC_CxCONTROL_P2M	0x89409000
++#define DMAC_CxCONFIG_P2M	0xd000
++
++#define DMAC_CxCONTROL_M2P	0x86089000
++#define DMAC_CxCONFIG_M2P	0xc800
++
++#define DMAC_CxCONFIG_SIO_P2M	0x0000d000
++#define DMAC_CxCONFIG_SIO_M2P	0x0000c800
++
++/*default the config and sync regsiter for DMAC controller*/
++/*M1,M2 little endian, enable DMAC*/
++#define DMAC_CONFIG_VAL		0x01
++/*enable the sync logic for the 16 peripheral*/
++#define DMAC_SYNC_VAL		0x0
++
++#define DMAC_MAX_PERIPHERALS	16
++#define MEM_MAX_NUM		2
++#define CHANNEL_NUM		CONFIG_HI_DMAC_CHANNEL_NUM
++#define DMAC_MAX_CHANNELS	CHANNEL_NUM
++
++#define REG_BASE_I2C0		0x12110000
++#define I2C0_DATA_REG		(REG_BASE_I2C0 + 0x14)
++
++#define REG_BASE_I2C1		0x12112000
++#define I2C1_DATA_REG		(REG_BASE_I2C1 + 0x14)
++
++#define REG_BASE_UART0		0x12100000
++#define UART0_DATA_REG		(REG_BASE_UART0 + 0x0)
++
++#define REG_BASE_UART1		0x12101000
++#define UART1_DATA_REG		(REG_BASE_UART1 + 0x0)
++
++#define REG_BASE_UART2		0x12102000
++#define UART2_DATA_REG		(REG_BASE_UART2 + 0x0)
++
++#define REG_BASE_SPI0		0x12110000
++#define SPI0_DATA_REG		(REG_BASE_SPI0 + 0x8)
++
++#define REG_BASE_SPI1		0x12121000
++#define SPI1_DATA_REG		(REG_BASE_SPI1 + 0x8)
++
++/*the transfer control and configuration value for different peripheral*/
++
++extern int g_channel_status[CHANNEL_NUM];
++
++dmac_peripheral  g_peripheral[DMAC_MAX_PERIPHERALS] = {
++	/*periphal 0: I2C0 RX, 8bit width */
++	{0, I2C0_DATA_REG, 0x99000000, 0xd010, 0},
++
++	/*periphal 1: I2C0 TX, 8bit width */
++	{1, I2C0_DATA_REG, 0x96000000, 0xca40, 0},
++
++	/*periphal 4: I2C1 RX, 8bit width */
++	{4, I2C1_DATA_REG, 0x99000000, 0xd014, 0},
++
++	/*periphal 5: I2C1 TX, 8bit width */
++	{5, I2C1_DATA_REG, 0x96000000, 0xcac0, 0},
++
++	/*periphal 6: UART0 RX, 8bit width */
++	{6, UART0_DATA_REG, 0x99000000, 0xd000, 0},
++
++	/*periphal 7: UART0 TX, 8bit width */
++	{7, UART0_DATA_REG, 0x96000000, 0xc840, 0},
++
++	/*periphal 8: UART1 RX, 8bit width */
++	{8, UART1_DATA_REG, 0x99000000, 0xd004, 0},
++
++	/*periphal 9: UART1 TX, 8bit width */
++	{9, UART1_DATA_REG, 0x96000000, 0xc8c0, 0},
++
++	/*periphal 10: UART2 RX, 8bit width */
++	{10, UART2_DATA_REG, 0x99000000, 0xd008, 0},
++
++	/*periphal 11: UART2 TX, 8bit width */
++	{11, UART2_DATA_REG, 0x96000000, 0xc940, 0},
++
++	/*periphal 12: I2C2 RX, 8bit width */
++	{12, SPI0_DATA_REG, 0x99000000, 0xd018, 0},
++
++	/*periphal 13: I2C2 TX, 8bit width */
++	{13, SPI0_DATA_REG, 0x96000000, 0xcb40, 0},
++
++	/*periphal 14: I2C3 RX, 8bit width */
++	{14, SPI1_DATA_REG, 0x99000000, 0xd01c, 0},
++
++	/*periphal 15: I2C3 TX, 8bit width */
++	{15, SPI1_DATA_REG, 0x96000000, 0xcbc0, 0},
++};
++
++#endif
+diff --git a/drivers/hidmac/hidmac_hi3519.c b/drivers/hidmac/hidmac_hi3519.c
+new file mode 100644
+index 0000000..c1f0234
+--- /dev/null
++++ b/drivers/hidmac/hidmac_hi3519.c
+@@ -0,0 +1,90 @@
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/i2c.h>
++#include <linux/init.h>
++#include <linux/time.h>
++#include <linux/interrupt.h>
++#include <linux/delay.h>
++#include <linux/errno.h>
++#include <linux/err.h>
++#include <linux/platform_device.h>
++#include <linux/pm_runtime.h>
++#include <linux/slab.h>
++#include <linux/io.h>
++
++#define SYS_CRG_BASE    IO_ADDRESS(0x12010000)
++#define REG_PERI_CRG56  0xe0
++#define DMAC_CLK_EN     (1 << 1)
++#define DMAC_SRST_REQ   (1 << 0)
++
++/*
++ *	DMA config array!
++ *	DREQ, FIFO, CONTROL, CONFIG, BITWIDTH
++ */
++dmac_peripheral  g_peripheral[DMAC_MAX_PERIPHERALS] = {
++	/* periphal 0: UART0 RX, 8bit width */
++	{0, UART0_DATA_REG, 0x99000000, 0xd000, 0},
++
++	/* periphal 1: UART0 TX, 8bit width */
++	{1, UART0_DATA_REG, 0x96000000, 0xc840, 0},
++
++	/*periphal 2: UART1 RX, 8bit width */
++	{2, UART1_DATA_REG, 0x99000000, 0xd004, 0},
++
++	/*periphal 3: UART1 TX, 8bit width */
++	{3, UART1_DATA_REG, 0x96000000, 0xc8c0, 0},
++
++	/*periphal 4: UART2 RX, 8bit width */
++	{4, UART2_DATA_REG, 0x99000000, 0xd008, 0},
++
++	/*periphal 5: UART2 TX, 8bit width */
++	{5, UART2_DATA_REG, 0x96000000, 0xc940, 0},
++
++	/*periphal 6: UART3 RX, 8bit width */
++	{6, UART3_DATA_REG, 0x99000000, 0xd00c, 0},
++
++	/*periphal 7: UART3 TX, 8bit width */
++	{7, UART3_DATA_REG, 0x96000000, 0xc9c0, 0},
++
++	/*periphal 8: I2C0 RX, 8bit width */
++	{8, I2C0_DATA_REG, 0x99000000, 0xd010, 0},
++
++	/*periphal 9: I2C0 TX, 8bit width */
++	{9, I2C0_DATA_REG, 0x96000000, 0xca40, 0},
++
++	/*periphal 10: I2C1 RX, 8bit width */
++	{10, I2C1_DATA_REG, 0x99000000, 0xd014, 0},
++
++	/*periphal 11: I2C1 TX, 8bit width */
++	{11, I2C1_DATA_REG, 0x96000000, 0xcac0, 0},
++
++	/*periphal 12: I2C2 RX, 8bit width */
++	{12, I2C2_DATA_REG, 0x99000000, 0xd018, 0},
++
++	/*periphal 13: I2C2 TX, 8bit width */
++	{13, I2C2_DATA_REG, 0x96000000, 0xcb40, 0},
++
++	/*periphal 14: I2C3 RX, 8bit width */
++	{14, I2C3_DATA_REG, 0x99000000, 0xd01c, 0},
++
++	/*periphal 15: I2C3 TX, 8bit width */
++	{15, I2C3_DATA_REG, 0x96000000, 0xcbc0, 0},
++};
++
++void hidmac_clk_en(void)
++{
++	unsigned int tmp;
++
++	dmac_readw(SYS_CRG_BASE + REG_PERI_CRG56, tmp);
++	tmp |= DMAC_CLK_EN;
++	dmac_writew(SYS_CRG_BASE + REG_PERI_CRG56, tmp);
++}
++
++void hidmac_unreset(void)
++{
++	unsigned int tmp;
++
++	dmac_readw(SYS_CRG_BASE + REG_PERI_CRG56, tmp);
++	tmp &= ~DMAC_SRST_REQ;
++	dmac_writew(SYS_CRG_BASE + REG_PERI_CRG56, tmp);
++}
+diff --git a/drivers/hidmac/hidmac_hi3519.h b/drivers/hidmac/hidmac_hi3519.h
+new file mode 100644
+index 0000000..edd7e0a
+--- /dev/null
++++ b/drivers/hidmac/hidmac_hi3519.h
+@@ -0,0 +1,99 @@
++#ifndef __HI_DMAC_HI3519_H__
++#define __HI_DMAC_HI3519_H__
++
++#define DDRAM_ADRS	0x80000000      /* fixed */
++#define DDRAM_SIZE	0x3FFFFFFF      /* 1GB DDR. */
++
++#define FLASH_BASE	0x10000000
++#define FLASH_SIZE	0x04000000      /* (32MB) */
++
++#define DMAC_BASE_REG	CONFIG_HI_DMAC_IO_BASE
++#define DMAC_INTTCCLEAR		IO_DMAC_ADDRESS(DMAC_BASE_REG + 0X08)
++
++#define DMAC_INTSTATUS		IO_DMAC_ADDRESS(DMAC_BASE_REG + 0X00)
++#define DMAC_INTTCSTATUS	IO_DMAC_ADDRESS(DMAC_BASE_REG + 0X04)
++#define DMAC_INTERRORSTATUS	IO_DMAC_ADDRESS(DMAC_BASE_REG + 0X0C)
++
++#define DMAC_INTERRCLR		IO_DMAC_ADDRESS(DMAC_BASE_REG + 0X10)
++#define DMAC_RAWINTTCSTATUS	IO_DMAC_ADDRESS(DMAC_BASE_REG + 0X14)
++#define DMAC_RAWINTERRORSTATUS	IO_DMAC_ADDRESS(DMAC_BASE_REG + 0X18)
++#define DMAC_ENBLDCHNS		IO_DMAC_ADDRESS(DMAC_BASE_REG + 0X1C)
++#define DMAC_CONFIG		IO_DMAC_ADDRESS(DMAC_BASE_REG + 0X30)
++#define DMAC_SYNC		IO_DMAC_ADDRESS(DMAC_BASE_REG + 0X34)
++
++#define DMAC_MAXTRANSFERSIZE	0x0fff /*the max length is denoted by 0-11bit*/
++#define MAXTRANSFERSIZE		DMAC_MAXTRANSFERSIZE
++#define DMAC_CxDISABLE		0x00
++#define DMAC_CxENABLE		0x01
++
++/*the definition for DMAC channel register*/
++#define DMAC_CxBASE(i)		IO_DMAC_ADDRESS(DMAC_BASE_REG + 0x100+i*0x20)
++#define DMAC_CxSRCADDR(i)	DMAC_CxBASE(i)
++#define DMAC_CxDESTADDR(i)	(DMAC_CxBASE(i)+0x04)
++#define DMAC_CxLLI(i)		(DMAC_CxBASE(i)+0x08)
++#define DMAC_CxCONTROL(i)	(DMAC_CxBASE(i)+0x0C)
++#define DMAC_CxCONFIG(i)	(DMAC_CxBASE(i)+0x10)
++
++/*the means the bit in the channel control register*/
++#define DMAC_CxCONTROL_M2M	0x9d480000  /* Dwidth=32,burst size=4 */
++#define DMAC_CxCONTROL_LLIM2M	0x0f480000  /* Dwidth=32,burst size=1 */
++#define DMAC_CxLLI_LM		0x01
++
++#define DMAC_CxCONFIG_M2M	0xc000
++#define DMAC_CxCONFIG_LLIM2M	0xc000
++
++/*#define DMAC_CxCONFIG_M2M  0x4001*/
++#define DMAC_CHANNEL_ENABLE	1
++#define DMAC_CHANNEL_DISABLE	0xfffffffe
++
++#define DMAC_CxCONTROL_P2M	0x89409000
++#define DMAC_CxCONFIG_P2M	0xd000
++
++#define DMAC_CxCONTROL_M2P	0x86089000
++#define DMAC_CxCONFIG_M2P	0xc800
++
++#define DMAC_CxCONFIG_SIO_P2M	0x0000d000
++#define DMAC_CxCONFIG_SIO_M2P	0x0000c800
++
++/*default the config and sync regsiter for DMAC controller*/
++/*M1,M2 little endian, enable DMAC*/
++#define DMAC_CONFIG_VAL		0x01
++/*enable the sync logic for the 16 peripheral*/
++#define DMAC_SYNC_VAL		0x0
++
++#define DMAC_MAX_PERIPHERALS	16
++#define MEM_MAX_NUM		2
++#define CHANNEL_NUM		CONFIG_HI_DMAC_CHANNEL_NUM
++#define DMAC_MAX_CHANNELS	CHANNEL_NUM
++
++#define REG_BASE_UART0		0x12100000
++#define UART0_DATA_REG		(REG_BASE_UART0 + 0x0)
++
++#define REG_BASE_UART1		0x12101000
++#define UART1_DATA_REG		(REG_BASE_UART1 + 0x0)
++
++#define REG_BASE_UART2		0x12102000
++#define UART2_DATA_REG		(REG_BASE_UART2 + 0x0)
++
++#define REG_BASE_UART3		0x12103000
++#define UART3_DATA_REG		(REG_BASE_UART3 + 0x0)
++
++#define REG_BASE_I2C0		0x12110000
++#define I2C0_DATA_REG		(REG_BASE_I2C0 + 0x10)
++
++#define REG_BASE_I2C1		0x12111000
++#define I2C1_DATA_REG		(REG_BASE_I2C1 + 0x10)
++
++#define REG_BASE_I2C2		0x12112000
++#define I2C2_DATA_REG		(REG_BASE_I2C2 + 0x10)
++
++#define REG_BASE_I2C3		0x12113000
++#define I2C3_DATA_REG		(REG_BASE_I2C3 + 0x10)
++
++#define REG_BASE_SPI2		0x12122000
++#define SPI2_DATA_REG		(REG_BASE_SPI2 + 0x8)
++
++/*the transfer control and configuration value for different peripheral*/
++
++extern int g_channel_status[CHANNEL_NUM];
++#endif
+diff --git a/drivers/hidmac/hidmac_hi3519v101.c b/drivers/hidmac/hidmac_hi3519v101.c
+new file mode 100644
+index 0000000..cf9132a
+--- /dev/null
++++ b/drivers/hidmac/hidmac_hi3519v101.c
+@@ -0,0 +1,90 @@
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/i2c.h>
++#include <linux/init.h>
++#include <linux/time.h>
++#include <linux/interrupt.h>
++#include <linux/delay.h>
++#include <linux/errno.h>
++#include <linux/err.h>
++#include <linux/platform_device.h>
++#include <linux/pm_runtime.h>
++#include <linux/slab.h>
++#include <linux/io.h>
++
++#define SYS_CRG_BASE    IO_ADDRESS(0x12010000)
++#define REG_PERI_CRG56  0xe0
++#define DMAC_CLK_EN     (1 << 1)
++#define DMAC_SRST_REQ   (1 << 0)
++
++/*
++ *	DMA config array!
++ *	DREQ, FIFO, CONTROL, CONFIG, BITWIDTH
++ */
++dmac_peripheral  g_peripheral[DMAC_MAX_PERIPHERALS] = {
++	/* periphal 0: UART0 RX, 8bit width */
++	{0, UART0_DATA_REG, 0x99000000, 0xd000, 0},
++
++	/* periphal 1: UART0 TX, 8bit width */
++	{1, UART0_DATA_REG, 0x96000000, 0xc840, 0},
++
++	/*periphal 2: UART1 RX, 8bit width */
++	{2, UART1_DATA_REG, 0x99000000, 0xd004, 0},
++
++	/*periphal 3: UART1 TX, 8bit width */
++	{3, UART1_DATA_REG, 0x96000000, 0xc8c0, 0},
++
++	/*periphal 4: UART2 RX, 8bit width */
++	{4, UART2_DATA_REG, 0x99000000, 0xd008, 0},
++
++	/*periphal 5: UART2 TX, 8bit width */
++	{5, UART2_DATA_REG, 0x96000000, 0xc940, 0},
++
++	/*periphal 6: UART3 RX, 8bit width */
++	{6, UART3_DATA_REG, 0x99000000, 0xd00c, 0},
++
++	/*periphal 7: UART3 TX, 8bit width */
++	{7, UART3_DATA_REG, 0x96000000, 0xc9c0, 0},
++
++	/*periphal 8: I2C0 RX, 8bit width */
++	{8, I2C0_DATA_REG, 0x99000000, 0xd010, 0},
++
++	/*periphal 9: I2C0 TX, 8bit width */
++	{9, I2C0_DATA_REG, 0x96000000, 0xca40, 0},
++
++	/*periphal 10: I2C1 RX, 8bit width */
++	{10, I2C1_DATA_REG, 0x99000000, 0xd014, 0},
++
++	/*periphal 11: I2C1 TX, 8bit width */
++	{11, I2C1_DATA_REG, 0x96000000, 0xcac0, 0},
++
++	/*periphal 12: I2C2 RX, 8bit width */
++	{12, SPI2_DATA_REG, 0x99000000, 0xd018, 0},
++
++	/*periphal 13: I2C2 TX, 8bit width */
++	{13, SPI2_DATA_REG, 0x96000000, 0xcb40, 0},
++
++	/*periphal 14: I2C3 RX, 8bit width */
++	{14, I2C2_DATA_REG, 0x99000000, 0xd01c, 0},
++
++	/*periphal 15: I2C3 TX, 8bit width */
++	{15, I2C2_DATA_REG, 0x96000000, 0xcbc0, 0},
++};
++
++void hidmac_clk_en(void)
++{
++	unsigned int tmp;
++
++	dmac_readw(SYS_CRG_BASE + REG_PERI_CRG56, tmp);
++	tmp |= DMAC_CLK_EN;
++	dmac_writew(SYS_CRG_BASE + REG_PERI_CRG56, tmp);
++}
++
++void hidmac_unreset(void)
++{
++	unsigned int tmp;
++
++	dmac_readw(SYS_CRG_BASE + REG_PERI_CRG56, tmp);
++	tmp &= ~DMAC_SRST_REQ;
++	dmac_writew(SYS_CRG_BASE + REG_PERI_CRG56, tmp);
++}
+diff --git a/drivers/hidmac/hidmac_hi3521d.h b/drivers/hidmac/hidmac_hi3521d.h
+new file mode 100644
+index 0000000..67877ff
+--- /dev/null
++++ b/drivers/hidmac/hidmac_hi3521d.h
+@@ -0,0 +1,120 @@
++#ifndef __HI_DMAC_HI3521D_H__
++#define __HI_DMAC_HI3521D_H__
++
++#define DDRAM_ADRS	0x80000000      /* fixed */
++#define DDRAM_SIZE	0x1FFFFFFF      /* 512M DDR. */
++
++#define FLASH_BASE	0x10000000
++#define FLASH_SIZE	0x04000000      /* (32MB) */
++
++#define DMAC_INTSTATUS		0X00
++#define DMAC_INTTCSTATUS	0X04
++#define DMAC_INTTCCLEAR		0X08
++#define DMAC_INTERRORSTATUS	0X0C
++
++#define DMAC_INTERRCLR		0X10
++#define DMAC_RAWINTTCSTATUS	0X14
++#define DMAC_RAWINTERRORSTATUS	0X18
++#define DMAC_ENBLDCHNS		0X1C
++#define DMAC_CONFIG			0X30
++#define DMAC_SYNC			0X34
++
++#define DMAC_MAXTRANSFERSIZE	0x0fff /*the max length is denoted by 0-11bit*/
++#define MAXTRANSFERSIZE		DMAC_MAXTRANSFERSIZE
++#define DMAC_CxDISABLE		0x00
++#define DMAC_CxENABLE		0x01
++
++/*the definition for DMAC channel register*/
++#define DMAC_CxBASE(i)		(0x100+i*0x20)
++#define DMAC_CxSRCADDR(i)	DMAC_CxBASE(i)
++#define DMAC_CxDESTADDR(i)	(DMAC_CxBASE(i)+0x04)
++#define DMAC_CxLLI(i)		(DMAC_CxBASE(i)+0x08)
++#define DMAC_CxCONTROL(i)	(DMAC_CxBASE(i)+0x0C)
++#define DMAC_CxCONFIG(i)	(DMAC_CxBASE(i)+0x10)
++
++/*the means the bit in the channel control register*/
++#define DMAC_CxCONTROL_M2M	0x9d480000  /* Dwidth=32,burst size=4 */
++#define DMAC_CxCONTROL_LLIM2M		0x0f480000  /* Dwidth=32,burst size=1 */
++#define DMAC_CxCONTROL_LLIM2M_ISP	0x0b489000  /* Dwidth=32,burst size=1 */
++#define DMAC_CxLLI_LM		0x01
++
++#define NUM_HAL_INTERRUPT_DMAC         (14 + 16)
++
++#define DMAC_CxCONFIG_M2M	0xc000
++#define DMAC_CxCONFIG_LLIM2M	0xc000
++
++/*#define DMAC_CxCONFIG_M2M  0x4001*/
++#define DMAC_CHANNEL_ENABLE	1
++#define DMAC_CHANNEL_DISABLE	0xfffffffe
++
++#define DMAC_CxCONTROL_P2M	0x89409000
++#define DMAC_CxCONFIG_P2M	0xd000
++
++#define DMAC_CxCONTROL_M2P	0x86089000
++#define DMAC_CxCONFIG_M2P	0xc800
++
++#define DMAC_CxCONFIG_SIO_P2M	0x0000d000
++#define DMAC_CxCONFIG_SIO_M2P	0x0000c800
++
++/*default the config and sync regsiter for DMAC controller*/
++/*M1,M2 little endian, enable DMAC*/
++#define DMAC_CONFIG_VAL		0x01
++/*enable the sync logic for the 16 peripheral*/
++#define DMAC_SYNC_VAL		0x0
++
++#define DMAC_MAX_PERIPHERALS	16
++#define MEM_MAX_NUM		2
++#define CHANNEL_NUM		CONFIG_HI_DMAC_CHANNEL_NUM
++#define DMAC_MAX_CHANNELS	CHANNEL_NUM
++
++#define REG_BASE_I2C0		0x120c0000
++#define I2C0_DATA_RXF		(REG_BASE_I2C0 + 0x10)
++#define I2C0_DATA_TXF		(REG_BASE_I2C0 + 0x10)
++
++
++#define REG_BASE_UART0		0x12080000
++#define UART0_DATA_REG		(REG_BASE_UART0 + 0x0)
++
++#define REG_BASE_UART1		0x12090000
++#define UART1_DATA_REG		(REG_BASE_UART1 + 0x0)
++
++#define REG_BASE_UART2		0x120a0000
++#define UART2_DATA_REG		(REG_BASE_UART2 + 0x0)
++
++/*the transfer control and configuration value for different peripheral*/
++
++extern int g_channel_status[CHANNEL_NUM];
++
++dmac_peripheral  g_peripheral[DMAC_MAX_PERIPHERALS] = {
++	/*periphal 0: UART0 RX, 8bit width */
++	{0, UART0_DATA_REG, 0x99000000, 0xd000, 0},
++
++	/*periphal 1: UART0 TX, 8bit width */
++	{1, UART0_DATA_REG, 0x96000000, 0xc840, 0},
++
++	/*periphal 2: UART1 RX, 8bit width */
++	{2, UART1_DATA_REG, 0x99000000, 0xd004, 0},
++
++	/*periphal 3: UART1 TX, 8bit width */
++	{3, UART1_DATA_REG, 0x96000000, 0xc8c0, 0},
++
++	/*periphal 4: UART2 RX, 8bit width */
++	{4, UART2_DATA_REG, 0x99000000, 0xd008, 0},
++
++	/*periphal 5: UART2 TX, 8bit width */
++	{5, UART2_DATA_REG, 0x96000000, 0xc940, 0},
++
++	/*periphal 6: ssp RX, 8bit width */
++	{6, 0, 0x99000000, 0xd00c, 0},
++
++	/*periphal 7: ssp TX, 8bit width */
++	{7, 0, 0x96000000, 0xc9c0, 0},
++
++	/*periphal 8: I2C0 RX, 8bit width */
++	{8, I2C0_DATA_RXF, 0x99000000, 0x1010, 0},
++
++	/*periphal 9: I2C0 TX, 8bit width */
++	{9, I2C0_DATA_TXF, 0x96000000, 0x0a40, 0},
++};
++
++#endif
+diff --git a/drivers/hidmac/hidmac_hi3531d.h b/drivers/hidmac/hidmac_hi3531d.h
+new file mode 100644
+index 0000000..91d00b0
+--- /dev/null
++++ b/drivers/hidmac/hidmac_hi3531d.h
+@@ -0,0 +1,135 @@
++#ifndef __HI_DMAC_HI3531D_H__
++#define __HI_DMAC_HI3531D_H__
++
++#define DDRAM_ADRS	0x80000000      /* fixed */
++#define DDRAM_SIZE	0x1FFFFFFF      /* 512M DDR. */
++
++#define FLASH_BASE	0x10000000
++#define FLASH_SIZE	0x04000000      /* (32MB) */
++
++#define DMAC_INTSTATUS		0X00
++#define DMAC_INTTCSTATUS	0X04
++#define DMAC_INTTCCLEAR		0X08
++#define DMAC_INTERRORSTATUS	0X0C
++
++#define DMAC_INTERRCLR		0X10
++#define DMAC_RAWINTTCSTATUS	0X14
++#define DMAC_RAWINTERRORSTATUS	0X18
++#define DMAC_ENBLDCHNS		0X1C
++#define DMAC_CONFIG			0X30
++#define DMAC_SYNC			0X34
++
++#define DMAC_MAXTRANSFERSIZE	0x0fff /*the max length is denoted by 0-11bit*/
++#define MAXTRANSFERSIZE		DMAC_MAXTRANSFERSIZE
++#define DMAC_CxDISABLE		0x00
++#define DMAC_CxENABLE		0x01
++
++/*the definition for DMAC channel register*/
++#define DMAC_CxBASE(i)		(0x100+i*0x20)
++#define DMAC_CxSRCADDR(i)	DMAC_CxBASE(i)
++#define DMAC_CxDESTADDR(i)	(DMAC_CxBASE(i)+0x04)
++#define DMAC_CxLLI(i)		(DMAC_CxBASE(i)+0x08)
++#define DMAC_CxCONTROL(i)	(DMAC_CxBASE(i)+0x0C)
++#define DMAC_CxCONFIG(i)	(DMAC_CxBASE(i)+0x10)
++
++/*the means the bit in the channel control register*/
++#define DMAC_CxCONTROL_M2M	0x9d480000  /* Dwidth=32,burst size=4 */
++#define DMAC_CxCONTROL_LLIM2M		0x0f480000  /* Dwidth=32,burst size=1 */
++#define DMAC_CxCONTROL_LLIM2M_ISP	0x0b489000  /* Dwidth=32,burst size=1 */
++#define DMAC_CxLLI_LM		0x01
++
++#define NUM_HAL_INTERRUPT_DMAC         (14 + 16)
++
++#define DMAC_CxCONFIG_M2M	0xc000
++#define DMAC_CxCONFIG_LLIM2M	0xc000
++
++/*#define DMAC_CxCONFIG_M2M  0x4001*/
++#define DMAC_CHANNEL_ENABLE	1
++#define DMAC_CHANNEL_DISABLE	0xfffffffe
++
++#define DMAC_CxCONTROL_P2M	0x89409000
++#define DMAC_CxCONFIG_P2M	0xd000
++
++#define DMAC_CxCONTROL_M2P	0x86089000
++#define DMAC_CxCONFIG_M2P	0xc800
++
++#define DMAC_CxCONFIG_SIO_P2M	0x0000d000
++#define DMAC_CxCONFIG_SIO_M2P	0x0000c800
++
++/*default the config and sync regsiter for DMAC controller*/
++/*M1,M2 little endian, enable DMAC*/
++#define DMAC_CONFIG_VAL		0x01
++/*enable the sync logic for the 16 peripheral*/
++#define DMAC_SYNC_VAL		0x0
++
++#define DMAC_MAX_PERIPHERALS	16
++#define MEM_MAX_NUM		2
++#define CHANNEL_NUM		CONFIG_HI_DMAC_CHANNEL_NUM
++#define DMAC_MAX_CHANNELS	CHANNEL_NUM
++
++#define REG_BASE_I2C0		0x120c0000
++#define I2C0_DATA_RXF		(REG_BASE_I2C0 + 0x10)
++#define I2C0_DATA_TXF		(REG_BASE_I2C0 + 0x10)
++
++#define REG_BASE_I2C1       0x120e0000
++#define I2C1_DATA_RXF       (REG_BASE_I2C1 + 0x10)
++#define I2C1_DATA_TXF       (REG_BASE_I2C1 + 0x10)
++
++#define REG_BASE_UART0		0x12080000
++#define UART0_DATA_REG		(REG_BASE_UART0 + 0x0)
++
++#define REG_BASE_UART1		0x12090000
++#define UART1_DATA_REG		(REG_BASE_UART1 + 0x0)
++
++#define REG_BASE_UART2		0x120a0000
++#define UART2_DATA_REG		(REG_BASE_UART2 + 0x0)
++
++/*the transfer control and configuration value for different peripheral*/
++
++extern int g_channel_status[CHANNEL_NUM];
++
++dmac_peripheral  g_peripheral[DMAC_MAX_PERIPHERALS] = {
++	/*periphal 0: UART0 RX, 8bit width */
++	{0, UART0_DATA_REG, 0x99000000, 0xd000, 0},
++
++	/*periphal 1: UART0 TX, 8bit width */
++	{1, UART0_DATA_REG, 0x96000000, 0xc840, 0},
++
++	/*periphal 2: UART1 RX, 8bit width */
++	{2, UART1_DATA_REG, 0x99000000, 0xd004, 0},
++
++	/*periphal 3: UART1 TX, 8bit width */
++	{3, UART1_DATA_REG, 0x96000000, 0xc8c0, 0},
++
++	/*periphal 4: UART2 RX, 8bit width */
++	{4, UART2_DATA_REG, 0x99000000, 0xd008, 0},
++
++	/*periphal 5: UART2 TX, 8bit width */
++	{5, UART2_DATA_REG, 0x96000000, 0xc940, 0},
++
++	/*periphal 6: SSP RX, 8bit width */
++	{6, 0, 0x99000000, 0xd00c, 0},
++
++	/*periphal 7: SSP TX, 8bit width */
++	{7, 0, 0x96000000, 0xc9c0, 0},
++
++	/*periphal 8: I2C0 RX, 8bit width */
++	{8, I2C0_DATA_RXF, 0x99000000, 0x1010, 0},
++
++	/*periphal 9: I2C0 TX, 8bit width */
++	{9, I2C0_DATA_TXF, 0x96000000, 0x0a40, 0},
++
++	/*periphal 10: UART3 RX, 8bit width */
++	{10, 0, 0x99000000, 0xd014, 0},
++
++	/*periphal 11: UART3 TX, 8bit width */
++	{11, 0, 0x96000000, 0xcb00, 0},
++
++	/*periphal 12: I2C1 RX, 8bit width */
++	{12, I2C1_DATA_RXF, 0x99000000, 0x1018, 0},
++
++	/*periphal 13: I2C1 TX, 8bit width */
++	{13, I2C1_DATA_TXF, 0x96000000, 0x0b40, 0},
++};
++
++#endif
+diff --git a/drivers/hidmac/hidmac_hi3536c.h b/drivers/hidmac/hidmac_hi3536c.h
+new file mode 100644
+index 0000000..b34bdf2
+--- /dev/null
++++ b/drivers/hidmac/hidmac_hi3536c.h
+@@ -0,0 +1,121 @@
++#ifndef __HI_DMAC_HI3536C_H__
++#define __HI_DMAC_HI3536C_H__
++
++#define DDRAM_ADRS	0x80000000      /* fixed */
++#define DDRAM_SIZE	0x1FFFFFFF      /* 512M DDR. */
++
++#define FLASH_BASE	0x10000000
++#define FLASH_SIZE	0x04000000      /* (32MB) */
++
++#define DMAC_INTSTATUS		0X00
++#define DMAC_INTTCSTATUS	0X04
++#define DMAC_INTTCCLEAR		0X08
++#define DMAC_INTERRORSTATUS	0X0C
++
++#define DMAC_INTERRCLR		0X10
++#define DMAC_RAWINTTCSTATUS	0X14
++#define DMAC_RAWINTERRORSTATUS	0X18
++#define DMAC_ENBLDCHNS		0X1C
++#define DMAC_CONFIG			0X30
++#define DMAC_SYNC			0X34
++
++#define DMAC_MAXTRANSFERSIZE	0x0fff /*the max length is denoted by 0-11bit*/
++#define MAXTRANSFERSIZE		DMAC_MAXTRANSFERSIZE
++#define DMAC_CxDISABLE		0x00
++#define DMAC_CxENABLE		0x01
++
++/*the definition for DMAC channel register*/
++#define DMAC_CxBASE(i)		(0x100+i*0x20)
++#define DMAC_CxSRCADDR(i)	DMAC_CxBASE(i)
++#define DMAC_CxDESTADDR(i)	(DMAC_CxBASE(i)+0x04)
++#define DMAC_CxLLI(i)		(DMAC_CxBASE(i)+0x08)
++#define DMAC_CxCONTROL(i)	(DMAC_CxBASE(i)+0x0C)
++#define DMAC_CxCONFIG(i)	(DMAC_CxBASE(i)+0x10)
++
++/*the means the bit in the channel control register*/
++#define DMAC_CxCONTROL_M2M	0x9d480000  /* Dwidth=32,burst size=4 */
++#define DMAC_CxCONTROL_LLIM2M		0x0f480000  /* Dwidth=32,burst size=1 */
++#define DMAC_CxCONTROL_LLIM2M_ISP	0x0b489000  /* Dwidth=32,burst size=1 */
++#define DMAC_CxLLI_LM		0x01
++
++#define NUM_HAL_INTERRUPT_DMAC         (14 + 16)
++
++#define DMAC_CxCONFIG_M2M	0xc000
++#define DMAC_CxCONFIG_LLIM2M	0xc000
++
++/*#define DMAC_CxCONFIG_M2M  0x4001*/
++#define DMAC_CHANNEL_ENABLE	1
++#define DMAC_CHANNEL_DISABLE	0xfffffffe
++
++#define DMAC_CxCONTROL_P2M	0x89409000
++#define DMAC_CxCONFIG_P2M	0xd000
++
++#define DMAC_CxCONTROL_M2P	0x86089000
++#define DMAC_CxCONFIG_M2P	0xc800
++
++#define DMAC_CxCONFIG_SIO_P2M	0x0000d000
++#define DMAC_CxCONFIG_SIO_M2P	0x0000c800
++
++/*default the config and sync regsiter for DMAC controller*/
++/*M1,M2 little endian, enable DMAC*/
++#define DMAC_CONFIG_VAL		0x01
++/*enable the sync logic for the 16 peripheral*/
++#define DMAC_SYNC_VAL		0x0
++
++#define DMAC_MAX_PERIPHERALS	16
++#define MEM_MAX_NUM		2
++#define CHANNEL_NUM		CONFIG_HI_DMAC_CHANNEL_NUM
++#define DMAC_MAX_CHANNELS	CHANNEL_NUM
++
++#define REG_BASE_I2C0		0x120c0000
++#define I2C0_DATA_RXF		(REG_BASE_I2C0 + 0x10)
++#define I2C0_DATA_TXF		(REG_BASE_I2C0 + 0x10)
++
++
++#define REG_BASE_UART0		0x12080000
++#define UART0_DATA_REG		(REG_BASE_UART0 + 0x0)
++
++#define REG_BASE_UART1		0x12090000
++#define UART1_DATA_REG		(REG_BASE_UART1 + 0x0)
++
++#define REG_BASE_UART2		0x120a0000
++#define UART2_DATA_REG		(REG_BASE_UART2 + 0x0)
++
++/*the transfer control and configuration value for different peripheral*/
++
++extern int g_channel_status[CHANNEL_NUM];
++
++dmac_peripheral  g_peripheral[DMAC_MAX_PERIPHERALS] = {
++	/*periphal 0: UART0 RX, 8bit width */
++	{0, UART0_DATA_REG, 0x99000000, 0xd000, 0},
++
++	/*periphal 1: UART0 TX, 8bit width */
++	{1, UART0_DATA_REG, 0x96000000, 0xc840, 0},
++
++	/*periphal 2: UART1 RX, 8bit width */
++	{2, UART1_DATA_REG, 0x99000000, 0xd004, 0},
++
++	/*periphal 3: UART1 TX, 8bit width */
++	{3, UART1_DATA_REG, 0x96000000, 0xc8c0, 0},
++
++	/*periphal 4: UART2 RX, 8bit width */
++	{4, UART2_DATA_REG, 0x99000000, 0xd008, 0},
++
++	/*periphal 5: UART2 TX, 8bit width */
++	{5, UART2_DATA_REG, 0x96000000, 0xc940, 0},
++
++	/*periphal 6: SSP RX, 8bit width */
++	{6, 0, 0x99000000, 0xd00c, 0},
++
++	/*periphal 7: SSP TX, 8bit width */
++	{7, 0, 0x96000000, 0xc9c0, 0},
++
++	/*periphal 8: I2C0 RX, 8bit width */
++	{8, I2C0_DATA_RXF, 0x99000000, 0x1010, 0},
++
++	/*periphal 9: I2C0 TX, 8bit width */
++	{9, I2C0_DATA_TXF, 0x96000000, 0x0a40, 0},
++
++};
++
++#endif
+diff --git a/drivers/hidmac/hidmac_hi3559.c b/drivers/hidmac/hidmac_hi3559.c
+new file mode 100644
+index 0000000..3d8df63
+--- /dev/null
++++ b/drivers/hidmac/hidmac_hi3559.c
+@@ -0,0 +1,90 @@
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/i2c.h>
++#include <linux/init.h>
++#include <linux/time.h>
++#include <linux/interrupt.h>
++#include <linux/delay.h>
++#include <linux/errno.h>
++#include <linux/err.h>
++#include <linux/platform_device.h>
++#include <linux/pm_runtime.h>
++#include <linux/slab.h>
++#include <linux/io.h>
++
++#define SYS_CRG_BASE    IO_ADDRESS(0x12010000)
++#define REG_PERI_CRG56  0xe0
++#define DMAC_CLK_EN     (1 << 1)
++#define DMAC_SRST_REQ   (1 << 0)
++
++/*
++ *	DMA config array!
++ *	DREQ, FIFO, CONTROL, CONFIG, BITWIDTH
++ */
++dmac_peripheral  g_peripheral[DMAC_MAX_PERIPHERALS] = {
++	/* periphal 0: UART0 RX, 8bit width */
++	{0, UART0_DATA_REG, 0x99000000, 0xd000, 0},
++
++	/* periphal 1: UART0 TX, 8bit width */
++	{1, UART0_DATA_REG, 0x96000000, 0xc840, 0},
++
++	/*periphal 2: UART1 RX, 8bit width */
++	{2, UART1_DATA_REG, 0x99000000, 0xd004, 0},
++
++	/*periphal 3: UART1 TX, 8bit width */
++	{3, UART1_DATA_REG, 0x96000000, 0xc8c0, 0},
++
++	/*periphal 4: UART2 RX, 8bit width */
++	{4, UART2_DATA_REG, 0x99000000, 0xd008, 0},
++
++	/*periphal 5: UART2 TX, 8bit width */
++	{5, UART2_DATA_REG, 0x96000000, 0xc940, 0},
++
++	/*periphal 6: I2C3 RX, 8bit width */
++	{6, I2C3_DATA_REG, 0x99000000, 0xd00c, 0},
++
++	/*periphal 7: I2C3 TX, 8bit width */
++	{7, I2C3_DATA_REG, 0x96000000, 0xc9c0, 0},
++
++	/*periphal 8: I2C0 RX, 8bit width */
++	{8, I2C0_DATA_REG, 0x99000000, 0xd010, 0},
++
++	/*periphal 9: I2C0 TX, 8bit width */
++	{9, I2C0_DATA_REG, 0x96000000, 0xca40, 0},
++
++	/*periphal 10: I2C1 RX, 8bit width */
++	{10, I2C1_DATA_REG, 0x99000000, 0xd014, 0},
++
++	/*periphal 11: I2C1 TX, 8bit width */
++	{11, I2C1_DATA_REG, 0x96000000, 0xcac0, 0},
++
++	/*periphal 12: SPI2 RX, 8bit width */
++	{12, SPI2_DATA_REG, 0x99000000, 0xd018, 0},
++
++	/*periphal 13: SPI2 TX, 8bit width */
++	{13, SPI2_DATA_REG, 0x96000000, 0xcb40, 0},
++
++	/*periphal 14: I2C2 RX, 8bit width */
++	{14, I2C2_DATA_REG, 0x99000000, 0xd01c, 0},
++
++	/*periphal 15: I2C2 TX, 8bit width */
++	{15, I2C2_DATA_REG, 0x96000000, 0xcbc0, 0},
++};
++
++void hidmac_clk_en(void)
++{
++	unsigned int tmp;
++
++	dmac_readw(SYS_CRG_BASE + REG_PERI_CRG56, tmp);
++	tmp |= DMAC_CLK_EN;
++	dmac_writew(SYS_CRG_BASE + REG_PERI_CRG56, tmp);
++}
++
++void hidmac_unreset(void)
++{
++	unsigned int tmp;
++
++	dmac_readw(SYS_CRG_BASE + REG_PERI_CRG56, tmp);
++	tmp &= ~DMAC_SRST_REQ;
++	dmac_writew(SYS_CRG_BASE + REG_PERI_CRG56, tmp);
++}
+diff --git a/drivers/hidmac/hidmac_hi3559.h b/drivers/hidmac/hidmac_hi3559.h
+new file mode 100644
+index 0000000..cbf943e
+--- /dev/null
++++ b/drivers/hidmac/hidmac_hi3559.h
+@@ -0,0 +1,99 @@
++#ifndef __HI_DMAC_HI3559_H__
++#define __HI_DMAC_HI3559_H__
++
++#define DDRAM_ADRS	0x80000000      /* fixed */
++#define DDRAM_SIZE	0x3FFFFFFF      /* 1GB DDR. */
++
++#define FLASH_BASE	0x10000000
++#define FLASH_SIZE	0x04000000      /* (32MB) */
++
++#define DMAC_BASE_REG	CONFIG_HI_DMAC_IO_BASE
++#define DMAC_INTTCCLEAR		IO_DMAC_ADDRESS(DMAC_BASE_REG + 0X08)
++
++#define DMAC_INTSTATUS		IO_DMAC_ADDRESS(DMAC_BASE_REG + 0X00)
++#define DMAC_INTTCSTATUS	IO_DMAC_ADDRESS(DMAC_BASE_REG + 0X04)
++#define DMAC_INTERRORSTATUS	IO_DMAC_ADDRESS(DMAC_BASE_REG + 0X0C)
++
++#define DMAC_INTERRCLR		IO_DMAC_ADDRESS(DMAC_BASE_REG + 0X10)
++#define DMAC_RAWINTTCSTATUS	IO_DMAC_ADDRESS(DMAC_BASE_REG + 0X14)
++#define DMAC_RAWINTERRORSTATUS	IO_DMAC_ADDRESS(DMAC_BASE_REG + 0X18)
++#define DMAC_ENBLDCHNS		IO_DMAC_ADDRESS(DMAC_BASE_REG + 0X1C)
++#define DMAC_CONFIG		IO_DMAC_ADDRESS(DMAC_BASE_REG + 0X30)
++#define DMAC_SYNC		IO_DMAC_ADDRESS(DMAC_BASE_REG + 0X34)
++
++#define DMAC_MAXTRANSFERSIZE	0x0fff /*the max length is denoted by 0-11bit*/
++#define MAXTRANSFERSIZE		DMAC_MAXTRANSFERSIZE
++#define DMAC_CxDISABLE		0x00
++#define DMAC_CxENABLE		0x01
++
++/*the definition for DMAC channel register*/
++#define DMAC_CxBASE(i)		IO_DMAC_ADDRESS(DMAC_BASE_REG + 0x100+i*0x20)
++#define DMAC_CxSRCADDR(i)	DMAC_CxBASE(i)
++#define DMAC_CxDESTADDR(i)	(DMAC_CxBASE(i)+0x04)
++#define DMAC_CxLLI(i)		(DMAC_CxBASE(i)+0x08)
++#define DMAC_CxCONTROL(i)	(DMAC_CxBASE(i)+0x0C)
++#define DMAC_CxCONFIG(i)	(DMAC_CxBASE(i)+0x10)
++
++/*the means the bit in the channel control register*/
++#define DMAC_CxCONTROL_M2M	0x9d480000  /* Dwidth=32,burst size=4 */
++#define DMAC_CxCONTROL_LLIM2M	0x0f480000  /* Dwidth=32,burst size=1 */
++#define DMAC_CxLLI_LM		0x01
++
++#define DMAC_CxCONFIG_M2M	0xc000
++#define DMAC_CxCONFIG_LLIM2M	0xc000
++
++/*#define DMAC_CxCONFIG_M2M  0x4001*/
++#define DMAC_CHANNEL_ENABLE	1
++#define DMAC_CHANNEL_DISABLE	0xfffffffe
++
++#define DMAC_CxCONTROL_P2M	0x89409000
++#define DMAC_CxCONFIG_P2M	0xd000
++
++#define DMAC_CxCONTROL_M2P	0x86089000
++#define DMAC_CxCONFIG_M2P	0xc800
++
++#define DMAC_CxCONFIG_SIO_P2M	0x0000d000
++#define DMAC_CxCONFIG_SIO_M2P	0x0000c800
++
++/*default the config and sync regsiter for DMAC controller*/
++/*M1,M2 little endian, enable DMAC*/
++#define DMAC_CONFIG_VAL		0x01
++/*enable the sync logic for the 16 peripheral*/
++#define DMAC_SYNC_VAL		0x0
++
++#define DMAC_MAX_PERIPHERALS	16
++#define MEM_MAX_NUM		2
++#define CHANNEL_NUM		CONFIG_HI_DMAC_CHANNEL_NUM
++#define DMAC_MAX_CHANNELS	CHANNEL_NUM
++
++#define REG_BASE_UART0		0x12100000
++#define UART0_DATA_REG		(REG_BASE_UART0 + 0x0)
++
++#define REG_BASE_UART1		0x12101000
++#define UART1_DATA_REG		(REG_BASE_UART1 + 0x0)
++
++#define REG_BASE_UART2		0x12102000
++#define UART2_DATA_REG		(REG_BASE_UART2 + 0x0)
++
++#define REG_BASE_UART3		0x12103000
++#define UART3_DATA_REG		(REG_BASE_UART3 + 0x0)
++
++#define REG_BASE_I2C0		0x12110000
++#define I2C0_DATA_REG		(REG_BASE_I2C0 + 0x10)
++
++#define REG_BASE_I2C1		0x12111000
++#define I2C1_DATA_REG		(REG_BASE_I2C1 + 0x10)
++
++#define REG_BASE_I2C2		0x12112000
++#define I2C2_DATA_REG		(REG_BASE_I2C2 + 0x10)
++
++#define REG_BASE_I2C3		0x12113000
++#define I2C3_DATA_REG		(REG_BASE_I2C3 + 0x10)
++
++#define REG_BASE_SPI2		0x12122000
++#define SPI2_DATA_REG		(REG_BASE_SPI2 + 0x8)
++
++/*the transfer control and configuration value for different peripheral*/
++
++extern int g_channel_status[CHANNEL_NUM];
++#endif
+diff --git a/drivers/hisilicon/Kconfig b/drivers/hisilicon/Kconfig
+new file mode 100644
+index 0000000..df2670b
+--- /dev/null
++++ b/drivers/hisilicon/Kconfig
+@@ -0,0 +1,5 @@
++menu "Hisilicon driver support"
++
++source "drivers/hisilicon/cma/Kconfig"
++
++endmenu
+diff --git a/drivers/hisilicon/Makefile b/drivers/hisilicon/Makefile
+new file mode 100644
+index 0000000..12004b2
+--- /dev/null
++++ b/drivers/hisilicon/Makefile
+@@ -0,0 +1,3 @@
++
++obj-y += clocksource/
++obj-$(CONFIG_CMA)			+= cma/
+diff --git a/drivers/hisilicon/clocksource/Makefile b/drivers/hisilicon/clocksource/Makefile
+new file mode 100644
+index 0000000..2c6bfe5
+--- /dev/null
++++ b/drivers/hisilicon/clocksource/Makefile
+@@ -0,0 +1,4 @@
++#TODO: ARM64 Timer
++ccflags-y += -Iarch/arm/include
++
++obj-y	+= timer.o hrtimer_test.o
+diff --git a/drivers/hisilicon/clocksource/hrtimer_test.c b/drivers/hisilicon/clocksource/hrtimer_test.c
+new file mode 100644
+index 0000000..645b0cf
+--- /dev/null
++++ b/drivers/hisilicon/clocksource/hrtimer_test.c
+@@ -0,0 +1,175 @@
++/*
++ * hrtimer() test kernel module
++ *
++ * Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include <linux/debugfs.h>
++#include <linux/delay.h>
++#include <linux/ktime.h>
++#include <linux/module.h>
++#include <linux/uaccess.h>
++#include <linux/sched.h>
++#include <linux/hrtimer.h>
++ 
++#define DEFAULT_ITERATIONS 100
++
++#define DEBUGFS_FILENAME "hrtimer_test"
++
++
++static DEFINE_MUTEX(hrtimer_test_lock);
++static struct dentry *hrtimer_test_debugfs_file;
++static int hrtimer_test_usecs;
++static int hrtimer_test_iterations = DEFAULT_ITERATIONS;
++
++static int hrtimer_test_single(struct seq_file *s, int usecs, uint32_t iters)
++{
++	int min = 0, max = 0, fail_count = 0;
++	uint64_t sum = 0;
++	uint64_t avg;
++	int i;
++	/* Allow hrtimer to be up to 0.5% fast */
++	int allowed_error_ns = usecs * 5;
++	ktime_t waittime;
++
++	for (i = 0; i < iters; ++i) {
++		struct timespec ts1, ts2;
++		int time_passed;
++		struct sched_param param = { .sched_priority = 99 };
++		sched_setscheduler(current, SCHED_FIFO, &param);
++		waittime = ns_to_ktime(usecs * 1000);
++		set_current_state(TASK_UNINTERRUPTIBLE);
++		ktime_get_ts(&ts1);
++		schedule_hrtimeout(&waittime, HRTIMER_MODE_REL);
++		ktime_get_ts(&ts2);
++		time_passed = timespec_to_ns(&ts2) - timespec_to_ns(&ts1);
++
++		if (i == 0 || time_passed < min)
++			min = time_passed;
++		if (i == 0 || time_passed > max)
++			max = time_passed;
++		if ((time_passed + allowed_error_ns) / 1000 < usecs)
++			++fail_count;
++		WARN_ON(time_passed < 0);
++		sum += time_passed;
++	}
++
++	avg = sum;
++	do_div(avg, iters);
++	seq_printf(s, "%d usecs x %d: exp=%d allowed=%d min=%d avg=%lld max=%d",
++			usecs, iters, usecs * 1000,
++			(usecs * 1000) - allowed_error_ns, min, avg, max);
++	if (fail_count)
++		seq_printf(s, " FAIL=%d", fail_count);
++	seq_puts(s, "\n");
++
++	return 0;
++}
++
++static int hrtimer_test_show(struct seq_file *s, void *v)
++{
++	int usecs;
++	int iters;
++	int ret = 0;
++
++	mutex_lock(&hrtimer_test_lock);
++	usecs = hrtimer_test_usecs;
++	iters = hrtimer_test_iterations;
++	mutex_unlock(&hrtimer_test_lock);
++
++	if (usecs > 0 && iters > 0) {
++		return hrtimer_test_single(s, usecs, iters);
++	} else if (usecs == 0) {
++		struct timespec ts;
++
++		ktime_get_ts(&ts);
++		seq_printf(s, "hrtimer() test (lpj=%ld kt=%ld.%09ld)\n",
++				loops_per_jiffy, ts.tv_sec, ts.tv_nsec);
++		seq_puts(s, "usage:\n");
++		seq_puts(s, "echo usecs [ITERS] > " DEBUGFS_FILENAME "\n");
++		seq_puts(s, "cat " DEBUGFS_FILENAME "\n");
++	}
++
++	return ret;
++}
++
++static int hrtimer_test_open(struct inode *inode, struct file *file)
++{
++	return single_open(file, hrtimer_test_show, inode->i_private);
++}
++
++static ssize_t hrtimer_test_write(struct file *file, const char __user *buf,
++		size_t count, loff_t *pos)
++{
++	char lbuf[32];
++	int ret;
++	int usecs;
++	int iters;
++
++	if (count >= sizeof(lbuf))
++		return -EINVAL;
++
++	if (copy_from_user(lbuf, buf, count))
++		return -EFAULT;
++	lbuf[count] = '\0';
++
++	ret = sscanf(lbuf, "%d %d", &usecs, &iters);
++	if (ret < 1)
++		return -EINVAL;
++	else if (ret < 2)
++		iters = DEFAULT_ITERATIONS;
++
++	mutex_lock(&hrtimer_test_lock);
++	hrtimer_test_usecs = usecs;
++	hrtimer_test_iterations = iters;
++	mutex_unlock(&hrtimer_test_lock);
++
++	return count;
++}
++
++static const struct file_operations hrtimer_test_debugfs_ops = {
++	.owner = THIS_MODULE,
++	.open = hrtimer_test_open,
++	.read = seq_read,
++	.write = hrtimer_test_write,
++	.llseek = seq_lseek,
++	.release = single_release,
++};
++
++static int __init hrtimer_test_init(void)
++{
++	mutex_lock(&hrtimer_test_lock);
++	hrtimer_test_debugfs_file = debugfs_create_file(DEBUGFS_FILENAME,
++			S_IRUSR, NULL, NULL, &hrtimer_test_debugfs_ops);
++	mutex_unlock(&hrtimer_test_lock);
++
++	return 0;
++}
++
++module_init(hrtimer_test_init);
++
++static void __exit hrtimer_test_exit(void)
++{
++	mutex_lock(&hrtimer_test_lock);
++	debugfs_remove(hrtimer_test_debugfs_file);
++	mutex_unlock(&hrtimer_test_lock);
++}
++
++module_exit(hrtimer_test_exit);
++
++MODULE_AUTHOR("David Riley <davidriley@chromium.org>");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/hisilicon/clocksource/timer.c b/drivers/hisilicon/clocksource/timer.c
+new file mode 100644
+index 0000000..53106c1
+--- /dev/null
++++ b/drivers/hisilicon/clocksource/timer.c
+@@ -0,0 +1,356 @@
++/*
++ *
++ * Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
++
++#include <linux/sched.h>
++#include <linux/interrupt.h>
++#include <linux/irq.h>
++#include <linux/err.h>
++#include <linux/clk.h>
++#include <linux/clockchips.h>
++#include <linux/cpu.h>
++#include <linux/platform_device.h>
++#include <linux/delay.h>
++#include <linux/percpu.h>
++#include <linux/clkdev.h>
++#include <linux/clk-private.h>
++#include <linux/sched_clock.h>
++#include <linux/of.h>
++#include <linux/of_address.h>
++#include <linux/of_irq.h>
++#include <asm/hardware/arm_timer.h>
++
++/*****************************************************************************/
++//TODO: ARM64 Timer
++#ifdef CONFIG_ARM64
++#define IOMEM(x)	((void __force __iomem *)(x))
++#endif
++
++struct hisi_clocksource {
++	void __iomem *base;
++	struct clocksource clksrc;
++};
++
++struct hisi_clock_event_device {
++		struct clock_event_device evt;
++		void __iomem *base;
++		char name[10];
++};
++
++static struct hisi_clocksource hisi_clocksource = {0};
++static struct hisi_clock_event_device __percpu *hisi_local_timer_evt;
++static struct irqaction __percpu *hisi_event_irq;
++static void __iomem *hisi_timer_base[NR_CPUS] = {0};
++static int hisi_timer_irqs[NR_CPUS] = {0};
++static unsigned long hisi_clkevt_reload;
++static unsigned long hisi_clk_rate;
++/*****************************************************************************/
++
++static int hisi_set_next_event(unsigned long next,
++		struct clock_event_device *evt)
++{
++	unsigned long ctrl;
++	struct hisi_clock_event_device *hisi_evt;
++
++	hisi_evt = container_of(evt, struct hisi_clock_event_device, evt);
++	ctrl = readl(hisi_evt->base + TIMER_CTRL);
++	writel(next, hisi_evt->base + TIMER_LOAD);
++	writel(ctrl | TIMER_CTRL_ENABLE, hisi_evt->base + TIMER_CTRL);
++
++	return 0;
++}
++/*****************************************************************************/
++
++static void hisi_set_mode(enum clock_event_mode mode,
++		struct clock_event_device *evt)
++{
++	unsigned long ctrl = TIMER_CTRL_32BIT | TIMER_CTRL_IE;
++	struct hisi_clock_event_device *hisi_evt;
++
++	hisi_evt = container_of(evt, struct hisi_clock_event_device, evt);
++
++	writel(ctrl, hisi_evt->base + TIMER_CTRL);
++
++	switch (mode) {
++	case CLOCK_EVT_MODE_PERIODIC:
++		writel(hisi_clkevt_reload, hisi_evt->base + TIMER_LOAD);
++		ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE;
++		break;
++
++	case CLOCK_EVT_MODE_ONESHOT:
++		/* period set, and timer enabled in 'next_event' hook */
++		ctrl |= TIMER_CTRL_ONESHOT;
++		break;
++
++	case CLOCK_EVT_MODE_UNUSED:
++	case CLOCK_EVT_MODE_SHUTDOWN:
++	default:
++		break;
++	}
++
++	writel(ctrl, hisi_evt->base + TIMER_CTRL);
++}
++/*****************************************************************************/
++
++static irqreturn_t hisi_evt_isr(int irq, void *dev_id)
++{
++	struct hisi_clock_event_device *hisi_evt = dev_id;
++	struct clock_event_device *evt = &hisi_evt->evt;
++
++	/* clear the interrupt */
++	writel(1, hisi_evt->base + TIMER_INTCLR);
++
++	evt->event_handler(evt);
++
++	return IRQ_HANDLED;
++}
++/*****************************************************************************/
++
++static inline struct hisi_clocksource *to_hisi_clksrc(struct clocksource *cs)
++{
++	return container_of(cs, struct hisi_clocksource, clksrc);
++}
++/*****************************************************************************/
++
++static void hisi_clocksource_start(void __iomem *base)
++{
++	writel(0, IOMEM(base + TIMER_CTRL));
++	writel(0xffffffff, IOMEM(base + TIMER_LOAD));
++	writel(0xffffffff, IOMEM(base + TIMER_VALUE));
++	writel(TIMER_CTRL_32BIT | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC,
++		IOMEM(base + TIMER_CTRL));
++}
++/*****************************************************************************/
++
++static cycle_t hisi_clocksource_read(struct clocksource *cs)
++{
++	return ~readl_relaxed(to_hisi_clksrc(cs)->base + TIMER_VALUE);
++}
++/*****************************************************************************/
++
++static notrace u64 hisi_sched_clock_read(void)
++{
++	u32 regval = ~readl_relaxed(hisi_clocksource.base + TIMER_VALUE);
++
++	return (u64)regval;
++}
++/*****************************************************************************/
++
++static void hisi_clocksource_resume(struct clocksource *cs)
++{
++	hisi_clocksource_start(to_hisi_clksrc(cs)->base);
++}
++/*****************************************************************************/
++
++static void __init hisi_clocksource_init(void __iomem *base, struct clk *clk)
++{
++	struct clocksource *clksrc = &hisi_clocksource.clksrc;
++
++	clksrc->name   = clk->name;
++	clksrc->rating = 200;
++	clksrc->read   = hisi_clocksource_read;
++	clksrc->mask   = CLOCKSOURCE_MASK(32),
++	clksrc->flags  = CLOCK_SOURCE_IS_CONTINUOUS,
++	clksrc->resume = hisi_clocksource_resume,
++
++	hisi_clocksource.base = base;
++
++	hisi_clocksource_start(base);
++
++	clocksource_register_hz(clksrc, hisi_clk_rate);
++	sched_clock_register(hisi_sched_clock_read, 32, hisi_clk_rate);
++}
++//TODO: ARM64 Timer
++u64 hisi_get_clocksource_val(void)
++{
++	struct clocksource *clksrc = &hisi_clocksource.clksrc;
++	if (!clksrc || !clksrc->read)
++		BUG();
++	return clksrc->read(clksrc);
++}
++/*****************************************************************************/
++
++static int hisi_local_timer_setup(struct clock_event_device *clk)
++{
++	struct hisi_clock_event_device *hisi_evt;
++	unsigned int cpu = smp_processor_id();
++	struct irqaction *action = this_cpu_ptr(hisi_event_irq);
++
++	hisi_evt = container_of(clk, struct hisi_clock_event_device, evt);
++
++	hisi_evt->base = hisi_timer_base[cpu];
++	snprintf(hisi_evt->name, sizeof(hisi_evt->name), "tick%d", cpu);
++
++	clk->name = hisi_evt->name;
++	clk->cpumask = cpumask_of(cpu);
++	clk->set_next_event = hisi_set_next_event;
++	clk->set_mode = hisi_set_mode;
++	clk->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
++	clk->rating = 450;
++	clk->irq = hisi_timer_irqs[cpu];
++	clk->mode = CLOCK_EVT_MODE_UNUSED;
++
++	action->name = clk->name;
++	action->dev_id = hisi_evt;
++	action->irq = clk->irq;
++	action->flags = IRQF_TIMER | IRQF_NOBALANCING;
++	action->handler = hisi_evt_isr;
++	BUG_ON(setup_irq(clk->irq, action));
++	irq_force_affinity(clk->irq, clk->cpumask);
++
++	clockevents_config_and_register(clk, hisi_clk_rate, 0xf, 0x7fffffff);
++
++	return 0;
++}
++/*****************************************************************************/
++
++static void hisi_local_timer_stop(struct clock_event_device *clk)
++{
++	pr_info("hisi_local_timer_teardown disable IRQ%d cpu #%d\n",
++			 clk->irq, smp_processor_id());
++
++	disable_irq(clk->irq);
++	remove_irq(clk->irq, this_cpu_ptr(hisi_event_irq));
++
++	clk->set_mode(CLOCK_EVT_MODE_UNUSED, clk);
++}
++/*****************************************************************************/
++
++static int hisi_local_timer_cpu_notify(struct notifier_block *self,
++				unsigned long action, void *hcpu)
++{
++	struct hisi_clock_event_device *hisi_evt;
++	/*
++	 * Grab cpu pointer in each case to avoid spurious
++	 * preemptible warnings
++	 */
++	switch (action & ~CPU_TASKS_FROZEN) {
++	case CPU_STARTING:
++		hisi_evt = this_cpu_ptr(hisi_local_timer_evt);
++		hisi_local_timer_setup(&hisi_evt->evt);
++		break;
++	case CPU_DYING:
++		hisi_evt = this_cpu_ptr(hisi_local_timer_evt);
++		hisi_local_timer_stop(&hisi_evt->evt);
++		break;
++	}
++
++	return NOTIFY_OK;
++}
++/*****************************************************************************/
++
++static struct notifier_block hisi_local_timer_cpu_nb = {
++	.notifier_call = hisi_local_timer_cpu_notify,
++};
++/*****************************************************************************/
++static int __init hisi_local_timer_register(void)
++{
++	int err;
++	int cpu = smp_processor_id();
++	struct hisi_clock_event_device *hisi_evt;
++
++	hisi_local_timer_evt = alloc_percpu(struct hisi_clock_event_device);
++	if (!hisi_local_timer_evt) {
++		err = -ENOMEM;
++		goto out;
++	}
++
++	hisi_event_irq = alloc_percpu(struct irqaction);
++	if (!hisi_event_irq) {
++		err = -ENOMEM;
++		goto out_event_irq;
++	}
++
++	irq_set_affinity(hisi_timer_irqs[cpu], cpumask_of(0));
++
++	err = register_cpu_notifier(&hisi_local_timer_cpu_nb);
++	if (err)
++		goto out_notifier;
++
++	/* Immediately configure the timer on the boot CPU */
++	hisi_evt = this_cpu_ptr(hisi_local_timer_evt);
++	hisi_local_timer_setup(&hisi_evt->evt);
++
++	return 0;
++
++out_notifier:
++	free_percpu(hisi_event_irq);
++
++out_event_irq:
++	free_percpu(hisi_local_timer_evt);
++
++out:
++	return err;
++}
++
++static void __init hisi_timer_init(struct device_node *node)
++{
++	u32 i, nr_irqs;
++	struct clk *clk;
++	void __iomem *base;
++
++	nr_irqs = of_irq_count(node);
++	if (nr_irqs > num_possible_cpus())
++		nr_irqs = num_possible_cpus();
++
++	for (i = 0; i < nr_irqs; i++) {
++		hisi_timer_irqs[i] = irq_of_parse_and_map(node, i);
++		hisi_timer_base[i] = of_iomap(node, i + 1);
++		if (!hisi_timer_base[i]) {
++			pr_err("can not iomap timer %d\n", i);
++			goto out_unmap;
++		}
++	}
++
++	base = of_iomap(node, 0);
++	if (WARN_ON(!base))
++		goto out_unmap;
++
++	clk = of_clk_get(node, 0);
++	if (IS_ERR(clk))
++		goto out_clk;
++
++	clk_prepare_enable(clk);
++
++	hisi_clk_rate = clk_get_rate(clk);
++	hisi_clkevt_reload = DIV_ROUND_CLOSEST(hisi_clk_rate, HZ);
++
++	hisi_clocksource_init(base, clk);
++	hisi_local_timer_register();
++
++	return;
++
++out_clk:
++	iounmap(base);
++
++out_unmap:
++	for (i = 0; i < nr_irqs; i++) {
++		if (hisi_timer_base[i])
++			iounmap(hisi_timer_base[i]);
++	}
++}
++//TODO: ARM64 Timer
++u32 hisi_timer_get_rate(void)
++{
++	return hisi_clk_rate;
++}
++
++CLOCKSOURCE_OF_DECLARE(hisi_timer, "hisilicon,timer",
++			hisi_timer_init);
+diff --git a/drivers/hisilicon/cma/Kconfig b/drivers/hisilicon/cma/Kconfig
+new file mode 100644
+index 0000000..7472dcc
+--- /dev/null
++++ b/drivers/hisilicon/cma/Kconfig
+@@ -0,0 +1,16 @@
++
++config CMA_MEM_SHARED
++	bool "Support sharing CMA memory with the heap"
++	depends on CMA && DMA_CMA
++	default no
++	help
++	  Support sharing CMA memory with the heap.
++
++config CMA_ADVANCE_SHARE
++	bool "Support cma advance share"
++	depends on CMA && DMA_CMA
++	select CMA_MEM_SHARED
++	default no
++	help
++	  Support advance sharing CMA memory with the heap.
++	  CMA Multiplex Ratio will be improved when this macro defined.
+diff --git a/drivers/hisilicon/cma/Makefile b/drivers/hisilicon/cma/Makefile
+new file mode 100644
+index 0000000..eefda7f
+--- /dev/null
++++ b/drivers/hisilicon/cma/Makefile
+@@ -0,0 +1,2 @@
++
++obj-$(CONFIG_CMA) += hi_cma.o
+diff --git a/drivers/hisilicon/cma/hi_cma.c b/drivers/hisilicon/cma/hi_cma.c
+new file mode 100644
+index 0000000..d0395ed
+--- /dev/null
++++ b/drivers/hisilicon/cma/hi_cma.c
+@@ -0,0 +1,141 @@
++#include <linux/device.h>
++#include <linux/dma-mapping.h>
++#include <linux/dma-contiguous.h>
++#include <linux/module.h>
++#include <linux/string.h>
++#include <linux/cma.h>
++
++#define NAME_LEN_MAX   64
++#define ZONE_MAX       64
++
++struct cma_zone {
++	struct device pdev;
++	char name[NAME_LEN_MAX];
++	u32 gfp;
++	u32 phys_start;
++	u32 nbytes;
++	u32 alloc_type;
++	u32 block_align;
++};
++
++static u32 num_zones;
++static struct cma_zone hisi_zone[ZONE_MAX];
++
++static int use_bootargs;
++
++unsigned int get_cma_size(void)
++{
++	int i;
++	u64 total = 0;
++
++	for (i = 0; i < num_zones; i++)
++		total += hisi_zone[i].nbytes;
++
++	/* unit is M */
++	return (unsigned int)(total >> 20);
++}
++
++static int __init hisi_mmz_parse_cmdline(char *s)
++{
++	char *line, *tmp;
++	char tmpline[256];
++
++	if (NULL == s) {
++		pr_info("There is no cma zone!\n");
++		return 0;
++	}
++	strncpy(tmpline, s, sizeof(tmpline));
++	tmpline[sizeof(tmpline)-1] = '\0';
++	tmp = tmpline;
++
++	while ((line = strsep(&tmp, ":")) != NULL) {
++		int i;
++		char *argv[6];
++
++		for (i = 0; (argv[i] = strsep(&line, ",")) != NULL;)
++			if (++i == ARRAY_SIZE(argv))
++				break;
++
++		hisi_zone[num_zones].pdev.coherent_dma_mask = DMA_BIT_MASK(64);
++		if (i == 4) {
++			strlcpy(hisi_zone[num_zones].name, argv[0], NAME_LEN_MAX);
++			hisi_zone[num_zones].gfp = memparse(argv[1], NULL);
++			hisi_zone[num_zones].phys_start = memparse(argv[2], NULL);
++			hisi_zone[num_zones].nbytes = memparse(argv[3], NULL);
++		}
++
++		else if (i == 6) {
++			strlcpy(hisi_zone[num_zones].name, argv[0], NAME_LEN_MAX);
++			hisi_zone[num_zones].gfp = memparse(argv[1], NULL);
++			hisi_zone[num_zones].phys_start = memparse(argv[2], NULL);
++			hisi_zone[num_zones].nbytes = memparse(argv[3], NULL);
++			hisi_zone[num_zones].alloc_type = memparse(argv[4], NULL);
++			hisi_zone[num_zones].block_align = memparse(argv[5], NULL);
++		} else {
++			pr_err("hisi ion parameter is not correct\n");
++			continue;
++		}
++
++		num_zones++;
++	}
++	if (num_zones != 0)
++		use_bootargs = 1;
++
++	return 0;
++}
++early_param("mmz", hisi_mmz_parse_cmdline);
++
++struct cma_zone *hisi_get_cma_zone(const char *name)
++{
++	int i = 0;
++
++	for (i = 0; i < num_zones; i++)
++		if (strcmp(hisi_zone[i].name, name) == 0)
++			break;
++
++	if (i == num_zones)
++		return NULL;
++
++	return &hisi_zone[i];
++}
++EXPORT_SYMBOL(hisi_get_cma_zone);
++
++struct device *hisi_get_cma_device(const char *name)
++{
++	int i = 0;
++
++	for (i = 0; i < num_zones; i++)
++		if (strcmp(hisi_zone[i].name, name) == 0)
++			break;
++
++	if (i == num_zones)
++		return NULL;
++
++	return &hisi_zone[i].pdev;
++}
++EXPORT_SYMBOL(hisi_get_cma_device);
++
++int hisi_declare_heap_memory(void)
++{
++	int i;
++	int ret = 0;
++
++	if (use_bootargs == 0) {
++		pr_info("cmz zone is not set!\n");
++		return ret;
++	}
++
++	for (i = 0; i < num_zones; i++) {
++		ret = dma_declare_contiguous(&hisi_zone[i].pdev,
++			hisi_zone[i].nbytes, hisi_zone[i].phys_start, 0);
++		if (ret)
++			panic("declare cma zone %s base: %u size:%uMB failed. ret:%d",
++			      hisi_zone[i].name, hisi_zone[i].phys_start,
++			      hisi_zone[i].nbytes>>20, ret);
++		hisi_zone[i].phys_start = cma_get_base(hisi_zone[i].pdev.cma_area);
++		hisi_zone[i].nbytes = cma_get_size(hisi_zone[i].pdev.cma_area);
++
++		/*FIXME need to fix dma_declare_contiguous return value &&value type*/
++	}
++	return ret;
++}
+diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c
+index d16dbb3..e7c8bf9 100644
+--- a/drivers/hwmon/lm75.c
++++ b/drivers/hwmon/lm75.c
+@@ -176,6 +176,10 @@ static struct attribute *lm75_attrs[] = {
+ };
+ ATTRIBUTE_GROUPS(lm75);
+ 
++static const struct thermal_zone_of_device_ops lm75_of_thermal_ops = {
++	.get_temp = lm75_read_temp,
++};
++
+ /*-----------------------------------------------------------------------*/
+ 
+ /* device probe and removal */
+@@ -291,10 +295,9 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id)
+ 	if (IS_ERR(data->hwmon_dev))
+ 		return PTR_ERR(data->hwmon_dev);
+ 
+-	data->tz = thermal_zone_of_sensor_register(data->hwmon_dev,
+-						   0,
++	data->tz = thermal_zone_of_sensor_register(data->hwmon_dev, 0,
+ 						   data->hwmon_dev,
+-						   lm75_read_temp, NULL);
++						   &lm75_of_thermal_ops);
+ 	if (IS_ERR(data->tz))
+ 		data->tz = NULL;
+ 
+diff --git a/drivers/hwmon/ntc_thermistor.c b/drivers/hwmon/ntc_thermistor.c
+index 31597c5..b2c90bd 100644
+--- a/drivers/hwmon/ntc_thermistor.c
++++ b/drivers/hwmon/ntc_thermistor.c
+@@ -495,6 +495,10 @@ static const struct attribute_group ntc_attr_group = {
+ 	.attrs = ntc_attributes,
+ };
+ 
++static const struct thermal_zone_of_device_ops ntc_of_thermal_ops = {
++	.get_temp = ntc_read_temp,
++};
++
+ static int ntc_thermistor_probe(struct platform_device *pdev)
+ {
+ 	const struct of_device_id *of_id =
+@@ -588,7 +592,7 @@ static int ntc_thermistor_probe(struct platform_device *pdev)
+ 								pdev_id->name);
+ 
+ 	data->tz = thermal_zone_of_sensor_register(data->dev, 0, data->dev,
+-						ntc_read_temp, NULL);
++						   &ntc_of_thermal_ops);
+ 	if (IS_ERR(data->tz)) {
+ 		dev_dbg(&pdev->dev, "Failed to register to thermal fw.\n");
+ 		data->tz = NULL;
+diff --git a/drivers/hwmon/tmp102.c b/drivers/hwmon/tmp102.c
+index 5171995..ba9f478 100644
+--- a/drivers/hwmon/tmp102.c
++++ b/drivers/hwmon/tmp102.c
+@@ -158,6 +158,10 @@ ATTRIBUTE_GROUPS(tmp102);
+ #define TMP102_CONFIG  (TMP102_CONF_TM | TMP102_CONF_EM | TMP102_CONF_CR1)
+ #define TMP102_CONFIG_RD_ONLY (TMP102_CONF_R0 | TMP102_CONF_R1 | TMP102_CONF_AL)
+ 
++static const struct thermal_zone_of_device_ops tmp102_of_thermal_ops = {
++	.get_temp = tmp102_read_temp,
++};
++
+ static int tmp102_probe(struct i2c_client *client,
+ 				  const struct i2c_device_id *id)
+ {
+@@ -215,7 +219,7 @@ static int tmp102_probe(struct i2c_client *client,
+ 	}
+ 	tmp102->hwmon_dev = hwmon_dev;
+ 	tmp102->tz = thermal_zone_of_sensor_register(hwmon_dev, 0, hwmon_dev,
+-						     tmp102_read_temp, NULL);
++						     &tmp102_of_thermal_ops);
+ 	if (IS_ERR(tmp102->tz))
+ 		tmp102->tz = NULL;
+ 
+diff --git a/drivers/hwtracing/coresight/Kconfig b/drivers/hwtracing/coresight/Kconfig
+new file mode 100644
+index 0000000..fc1f1ae
+--- /dev/null
++++ b/drivers/hwtracing/coresight/Kconfig
+@@ -0,0 +1,61 @@
++#
++# Coresight configuration
++#
++menuconfig CORESIGHT
++	bool "CoreSight Tracing Support"
++	select ARM_AMBA
++	help
++	  This framework provides a kernel interface for the CoreSight debug
++	  and trace drivers to register themselves with. It's intended to build
++	  a topological view of the CoreSight components based on a DT
++	  specification and configure the right serie of components when a
++	  trace source gets enabled.
++
++if CORESIGHT
++config CORESIGHT_LINKS_AND_SINKS
++	bool "CoreSight Link and Sink drivers"
++	help
++	  This enables support for CoreSight link and sink drivers that are
++	  responsible for transporting and collecting the trace data
++	  respectively.  Link and sinks are dynamically aggregated with a trace
++	  entity at run time to form a complete trace path.
++
++config CORESIGHT_LINK_AND_SINK_TMC
++	bool "Coresight generic TMC driver"
++	depends on CORESIGHT_LINKS_AND_SINKS
++	help
++	  This enables support for the Trace Memory Controller driver.
++	  Depending on its configuration the device can act as a link (embedded
++	  trace router - ETR) or sink (embedded trace FIFO).  The driver
++	  complies with the generic implementation of the component without
++	  special enhancement or added features.
++
++config CORESIGHT_SINK_TPIU
++	bool "Coresight generic TPIU driver"
++	depends on CORESIGHT_LINKS_AND_SINKS
++	help
++	  This enables support for the Trace Port Interface Unit driver,
++	  responsible for bridging the gap between the on-chip coresight
++	  components and a trace for bridging the gap between the on-chip
++	  coresight components and a trace port collection engine, typically
++	  connected to an external host for use case capturing more traces than
++	  the on-board coresight memory can handle.
++
++config CORESIGHT_SINK_ETBV10
++	bool "Coresight ETBv1.0 driver"
++	depends on CORESIGHT_LINKS_AND_SINKS
++	help
++	  This enables support for the Embedded Trace Buffer version 1.0 driver
++	  that complies with the generic implementation of the component without
++	  special enhancement or added features.
++
++config CORESIGHT_SOURCE_ETM3X
++	bool "CoreSight Embedded Trace Macrocell 3.x driver"
++	depends on !ARM64
++	select CORESIGHT_LINKS_AND_SINKS
++	help
++	  This driver provides support for processor ETM3.x and PTM1.x modules,
++	  which allows tracing the instructions that a processor is executing
++	  This is primarily useful for instruction level tracing.  Depending
++	  the ETM version data tracing may also be available.
++endif
+diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile
+new file mode 100644
+index 0000000..4b4bec8
+--- /dev/null
++++ b/drivers/hwtracing/coresight/Makefile
+@@ -0,0 +1,11 @@
++#
++# Makefile for CoreSight drivers.
++#
++obj-$(CONFIG_CORESIGHT) += coresight.o
++obj-$(CONFIG_OF) += of_coresight.o
++obj-$(CONFIG_CORESIGHT_LINK_AND_SINK_TMC) += coresight-tmc.o
++obj-$(CONFIG_CORESIGHT_SINK_TPIU) += coresight-tpiu.o
++obj-$(CONFIG_CORESIGHT_SINK_ETBV10) += coresight-etb10.o
++obj-$(CONFIG_CORESIGHT_LINKS_AND_SINKS) += coresight-funnel.o \
++					   coresight-replicator.o
++obj-$(CONFIG_CORESIGHT_SOURCE_ETM3X) += coresight-etm3x.o coresight-etm-cp14.o
+diff --git a/drivers/hwtracing/coresight/coresight-etb10.c b/drivers/hwtracing/coresight/coresight-etb10.c
+new file mode 100644
+index 0000000..4004986
+--- /dev/null
++++ b/drivers/hwtracing/coresight/coresight-etb10.c
+@@ -0,0 +1,527 @@
++/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/types.h>
++#include <linux/device.h>
++#include <linux/io.h>
++#include <linux/err.h>
++#include <linux/fs.h>
++#include <linux/miscdevice.h>
++#include <linux/uaccess.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/clk.h>
++#include <linux/seq_file.h>
++#include <linux/coresight.h>
++#include <linux/amba/bus.h>
++
++#include "coresight-priv.h"
++
++#define ETB_RAM_DEPTH_REG	0x004
++#define ETB_STATUS_REG		0x00c
++#define ETB_RAM_READ_DATA_REG	0x010
++#define ETB_RAM_READ_POINTER	0x014
++#define ETB_RAM_WRITE_POINTER	0x018
++#define ETB_TRG			0x01c
++#define ETB_CTL_REG		0x020
++#define ETB_RWD_REG		0x024
++#define ETB_FFSR		0x300
++#define ETB_FFCR		0x304
++#define ETB_ITMISCOP0		0xee0
++#define ETB_ITTRFLINACK		0xee4
++#define ETB_ITTRFLIN		0xee8
++#define ETB_ITATBDATA0		0xeeC
++#define ETB_ITATBCTR2		0xef0
++#define ETB_ITATBCTR1		0xef4
++#define ETB_ITATBCTR0		0xef8
++
++/* register description */
++/* STS - 0x00C */
++#define ETB_STATUS_RAM_FULL	BIT(0)
++/* CTL - 0x020 */
++#define ETB_CTL_CAPT_EN		BIT(0)
++/* FFCR - 0x304 */
++#define ETB_FFCR_EN_FTC		BIT(0)
++#define ETB_FFCR_FON_MAN	BIT(6)
++#define ETB_FFCR_STOP_FI	BIT(12)
++#define ETB_FFCR_STOP_TRIGGER	BIT(13)
++
++#define ETB_FFCR_BIT		6
++#define ETB_FFSR_BIT		1
++#define ETB_FRAME_SIZE_WORDS	4
++
++/**
++ * struct etb_drvdata - specifics associated to an ETB component
++ * @base:	memory mapped base address for this component.
++ * @dev:	the device entity associated to this component.
++ * @csdev:	component vitals needed by the framework.
++ * @miscdev:	specifics to handle "/dev/xyz.etb" entry.
++ * @clk:	the clock this component is associated to.
++ * @spinlock:	only one at a time pls.
++ * @in_use:	synchronise user space access to etb buffer.
++ * @buf:	area of memory where ETB buffer content gets sent.
++ * @buffer_depth: size of @buf.
++ * @enable:	this ETB is being used.
++ * @trigger_cntr: amount of words to store after a trigger.
++ */
++struct etb_drvdata {
++	void __iomem		*base;
++	struct device		*dev;
++	struct coresight_device	*csdev;
++	struct miscdevice	miscdev;
++	struct clk		*clk;
++	spinlock_t		spinlock;
++	atomic_t		in_use;
++	u8			*buf;
++	u32			buffer_depth;
++	bool			enable;
++	u32			trigger_cntr;
++};
++
++static unsigned int etb_get_buffer_depth(struct etb_drvdata *drvdata)
++{
++	int ret;
++	u32 depth = 0;
++
++	ret = clk_prepare_enable(drvdata->clk);
++	if (ret)
++		return ret;
++
++	/* RO registers don't need locking */
++	depth = readl_relaxed(drvdata->base + ETB_RAM_DEPTH_REG);
++
++	clk_disable_unprepare(drvdata->clk);
++	return depth;
++}
++
++static void etb_enable_hw(struct etb_drvdata *drvdata)
++{
++	int i;
++	u32 depth;
++
++	CS_UNLOCK(drvdata->base);
++
++	depth = drvdata->buffer_depth;
++	/* reset write RAM pointer address */
++	writel_relaxed(0x0, drvdata->base + ETB_RAM_WRITE_POINTER);
++	/* clear entire RAM buffer */
++	for (i = 0; i < depth; i++)
++		writel_relaxed(0x0, drvdata->base + ETB_RWD_REG);
++
++	/* reset write RAM pointer address */
++	writel_relaxed(0x0, drvdata->base + ETB_RAM_WRITE_POINTER);
++	/* reset read RAM pointer address */
++	writel_relaxed(0x0, drvdata->base + ETB_RAM_READ_POINTER);
++
++	writel_relaxed(drvdata->trigger_cntr, drvdata->base + ETB_TRG);
++	writel_relaxed(ETB_FFCR_EN_FTC | ETB_FFCR_STOP_TRIGGER,
++		       drvdata->base + ETB_FFCR);
++	/* ETB trace capture enable */
++	writel_relaxed(ETB_CTL_CAPT_EN, drvdata->base + ETB_CTL_REG);
++
++	CS_LOCK(drvdata->base);
++}
++
++static int etb_enable(struct coresight_device *csdev)
++{
++	struct etb_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
++	int ret;
++	unsigned long flags;
++
++	ret = clk_prepare_enable(drvdata->clk);
++	if (ret)
++		return ret;
++
++	spin_lock_irqsave(&drvdata->spinlock, flags);
++	etb_enable_hw(drvdata);
++	drvdata->enable = true;
++	spin_unlock_irqrestore(&drvdata->spinlock, flags);
++
++	dev_info(drvdata->dev, "ETB enabled\n");
++	return 0;
++}
++
++static void etb_disable_hw(struct etb_drvdata *drvdata)
++{
++	u32 ffcr;
++
++	CS_UNLOCK(drvdata->base);
++
++	ffcr = readl_relaxed(drvdata->base + ETB_FFCR);
++	/* stop formatter when a stop has completed */
++	ffcr |= ETB_FFCR_STOP_FI;
++	writel_relaxed(ffcr, drvdata->base + ETB_FFCR);
++	/* manually generate a flush of the system */
++	ffcr |= ETB_FFCR_FON_MAN;
++	writel_relaxed(ffcr, drvdata->base + ETB_FFCR);
++
++	if (coresight_timeout(drvdata->base, ETB_FFCR, ETB_FFCR_BIT, 0)) {
++		dev_err(drvdata->dev,
++			"timeout observed when probing at offset %#x\n",
++			ETB_FFCR);
++	}
++
++	/* disable trace capture */
++	writel_relaxed(0x0, drvdata->base + ETB_CTL_REG);
++
++	if (coresight_timeout(drvdata->base, ETB_FFSR, ETB_FFSR_BIT, 1)) {
++		dev_err(drvdata->dev,
++			"timeout observed when probing at offset %#x\n",
++			ETB_FFCR);
++	}
++
++	CS_LOCK(drvdata->base);
++}
++
++static void etb_dump_hw(struct etb_drvdata *drvdata)
++{
++	int i;
++	u8 *buf_ptr;
++	u32 read_data, depth;
++	u32 read_ptr, write_ptr;
++	u32 frame_off, frame_endoff;
++
++	CS_UNLOCK(drvdata->base);
++
++	read_ptr = readl_relaxed(drvdata->base + ETB_RAM_READ_POINTER);
++	write_ptr = readl_relaxed(drvdata->base + ETB_RAM_WRITE_POINTER);
++
++	frame_off = write_ptr % ETB_FRAME_SIZE_WORDS;
++	frame_endoff = ETB_FRAME_SIZE_WORDS - frame_off;
++	if (frame_off) {
++		dev_err(drvdata->dev,
++			"write_ptr: %lu not aligned to formatter frame size\n",
++			(unsigned long)write_ptr);
++		dev_err(drvdata->dev, "frameoff: %lu, frame_endoff: %lu\n",
++			(unsigned long)frame_off, (unsigned long)frame_endoff);
++		write_ptr += frame_endoff;
++	}
++
++	if ((readl_relaxed(drvdata->base + ETB_STATUS_REG)
++		      & ETB_STATUS_RAM_FULL) == 0)
++		writel_relaxed(0x0, drvdata->base + ETB_RAM_READ_POINTER);
++	else
++		writel_relaxed(write_ptr, drvdata->base + ETB_RAM_READ_POINTER);
++
++	depth = drvdata->buffer_depth;
++	buf_ptr = drvdata->buf;
++	for (i = 0; i < depth; i++) {
++		read_data = readl_relaxed(drvdata->base +
++					  ETB_RAM_READ_DATA_REG);
++		*buf_ptr++ = read_data >> 0;
++		*buf_ptr++ = read_data >> 8;
++		*buf_ptr++ = read_data >> 16;
++		*buf_ptr++ = read_data >> 24;
++	}
++
++	if (frame_off) {
++		buf_ptr -= (frame_endoff * 4);
++		for (i = 0; i < frame_endoff; i++) {
++			*buf_ptr++ = 0x0;
++			*buf_ptr++ = 0x0;
++			*buf_ptr++ = 0x0;
++			*buf_ptr++ = 0x0;
++		}
++	}
++
++	writel_relaxed(read_ptr, drvdata->base + ETB_RAM_READ_POINTER);
++
++	CS_LOCK(drvdata->base);
++}
++
++static void etb_disable(struct coresight_device *csdev)
++{
++	struct etb_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
++	unsigned long flags;
++
++	spin_lock_irqsave(&drvdata->spinlock, flags);
++	etb_disable_hw(drvdata);
++	etb_dump_hw(drvdata);
++	drvdata->enable = false;
++	spin_unlock_irqrestore(&drvdata->spinlock, flags);
++
++	clk_disable_unprepare(drvdata->clk);
++
++	dev_info(drvdata->dev, "ETB disabled\n");
++}
++
++static const struct coresight_ops_sink etb_sink_ops = {
++	.enable		= etb_enable,
++	.disable	= etb_disable,
++};
++
++static const struct coresight_ops etb_cs_ops = {
++	.sink_ops	= &etb_sink_ops,
++};
++
++static void etb_dump(struct etb_drvdata *drvdata)
++{
++	unsigned long flags;
++
++	spin_lock_irqsave(&drvdata->spinlock, flags);
++	if (drvdata->enable) {
++		etb_disable_hw(drvdata);
++		etb_dump_hw(drvdata);
++		etb_enable_hw(drvdata);
++	}
++	spin_unlock_irqrestore(&drvdata->spinlock, flags);
++
++	dev_info(drvdata->dev, "ETB dumped\n");
++}
++
++static int etb_open(struct inode *inode, struct file *file)
++{
++	struct etb_drvdata *drvdata = container_of(file->private_data,
++						   struct etb_drvdata, miscdev);
++
++	if (atomic_cmpxchg(&drvdata->in_use, 0, 1))
++		return -EBUSY;
++
++	dev_dbg(drvdata->dev, "%s: successfully opened\n", __func__);
++	return 0;
++}
++
++static ssize_t etb_read(struct file *file, char __user *data,
++				size_t len, loff_t *ppos)
++{
++	u32 depth;
++	struct etb_drvdata *drvdata = container_of(file->private_data,
++						   struct etb_drvdata, miscdev);
++
++	etb_dump(drvdata);
++
++	depth = drvdata->buffer_depth;
++	if (*ppos + len > depth * 4)
++		len = depth * 4 - *ppos;
++
++	if (copy_to_user(data, drvdata->buf + *ppos, len)) {
++		dev_dbg(drvdata->dev, "%s: copy_to_user failed\n", __func__);
++		return -EFAULT;
++	}
++
++	*ppos += len;
++
++	dev_dbg(drvdata->dev, "%s: %zu bytes copied, %d bytes left\n",
++		__func__, len, (int)(depth * 4 - *ppos));
++	return len;
++}
++
++static int etb_release(struct inode *inode, struct file *file)
++{
++	struct etb_drvdata *drvdata = container_of(file->private_data,
++						   struct etb_drvdata, miscdev);
++	atomic_set(&drvdata->in_use, 0);
++
++	dev_dbg(drvdata->dev, "%s: released\n", __func__);
++	return 0;
++}
++
++static const struct file_operations etb_fops = {
++	.owner		= THIS_MODULE,
++	.open		= etb_open,
++	.read		= etb_read,
++	.release	= etb_release,
++	.llseek		= no_llseek,
++};
++
++static ssize_t status_show(struct device *dev,
++			   struct device_attribute *attr, char *buf)
++{
++	int ret;
++	unsigned long flags;
++	u32 etb_rdr, etb_sr, etb_rrp, etb_rwp;
++	u32 etb_trg, etb_cr, etb_ffsr, etb_ffcr;
++	struct etb_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	ret = clk_prepare_enable(drvdata->clk);
++	if (ret)
++		goto out;
++
++	spin_lock_irqsave(&drvdata->spinlock, flags);
++	CS_UNLOCK(drvdata->base);
++
++	etb_rdr = readl_relaxed(drvdata->base + ETB_RAM_DEPTH_REG);
++	etb_sr = readl_relaxed(drvdata->base + ETB_STATUS_REG);
++	etb_rrp = readl_relaxed(drvdata->base + ETB_RAM_READ_POINTER);
++	etb_rwp = readl_relaxed(drvdata->base + ETB_RAM_WRITE_POINTER);
++	etb_trg = readl_relaxed(drvdata->base + ETB_TRG);
++	etb_cr = readl_relaxed(drvdata->base + ETB_CTL_REG);
++	etb_ffsr = readl_relaxed(drvdata->base + ETB_FFSR);
++	etb_ffcr = readl_relaxed(drvdata->base + ETB_FFCR);
++
++	CS_LOCK(drvdata->base);
++	spin_unlock_irqrestore(&drvdata->spinlock, flags);
++
++	clk_disable_unprepare(drvdata->clk);
++
++	return sprintf(buf,
++		       "Depth:\t\t0x%x\n"
++		       "Status:\t\t0x%x\n"
++		       "RAM read ptr:\t0x%x\n"
++		       "RAM wrt ptr:\t0x%x\n"
++		       "Trigger cnt:\t0x%x\n"
++		       "Control:\t0x%x\n"
++		       "Flush status:\t0x%x\n"
++		       "Flush ctrl:\t0x%x\n",
++		       etb_rdr, etb_sr, etb_rrp, etb_rwp,
++		       etb_trg, etb_cr, etb_ffsr, etb_ffcr);
++out:
++	return -EINVAL;
++}
++static DEVICE_ATTR_RO(status);
++
++static ssize_t trigger_cntr_show(struct device *dev,
++			    struct device_attribute *attr, char *buf)
++{
++	struct etb_drvdata *drvdata = dev_get_drvdata(dev->parent);
++	unsigned long val = drvdata->trigger_cntr;
++
++	return sprintf(buf, "%#lx\n", val);
++}
++
++static ssize_t trigger_cntr_store(struct device *dev,
++			     struct device_attribute *attr,
++			     const char *buf, size_t size)
++{
++	int ret;
++	unsigned long val;
++	struct etb_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	ret = kstrtoul(buf, 16, &val);
++	if (ret)
++		return ret;
++
++	drvdata->trigger_cntr = val;
++	return size;
++}
++static DEVICE_ATTR_RW(trigger_cntr);
++
++static struct attribute *coresight_etb_attrs[] = {
++	&dev_attr_trigger_cntr.attr,
++	&dev_attr_status.attr,
++	NULL,
++};
++ATTRIBUTE_GROUPS(coresight_etb);
++
++static int etb_probe(struct amba_device *adev, const struct amba_id *id)
++{
++	int ret;
++	void __iomem *base;
++	struct device *dev = &adev->dev;
++	struct coresight_platform_data *pdata = NULL;
++	struct etb_drvdata *drvdata;
++	struct resource *res = &adev->res;
++	struct coresight_desc *desc;
++	struct device_node *np = adev->dev.of_node;
++
++	if (np) {
++		pdata = of_get_coresight_platform_data(dev, np);
++		if (IS_ERR(pdata))
++			return PTR_ERR(pdata);
++		adev->dev.platform_data = pdata;
++	}
++
++	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
++	if (!drvdata)
++		return -ENOMEM;
++
++	drvdata->dev = &adev->dev;
++	dev_set_drvdata(dev, drvdata);
++
++	/* validity for the resource is already checked by the AMBA core */
++	base = devm_ioremap_resource(dev, res);
++	if (IS_ERR(base))
++		return PTR_ERR(base);
++
++	drvdata->base = base;
++
++	spin_lock_init(&drvdata->spinlock);
++
++	drvdata->clk = adev->pclk;
++	ret = clk_prepare_enable(drvdata->clk);
++	if (ret)
++		return ret;
++
++	drvdata->buffer_depth = etb_get_buffer_depth(drvdata);
++	clk_disable_unprepare(drvdata->clk);
++
++	if (drvdata->buffer_depth < 0)
++		return -EINVAL;
++
++	drvdata->buf = devm_kzalloc(dev,
++				    drvdata->buffer_depth * 4, GFP_KERNEL);
++	if (!drvdata->buf)
++		return -ENOMEM;
++
++	desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
++	if (!desc)
++		return -ENOMEM;
++
++	desc->type = CORESIGHT_DEV_TYPE_SINK;
++	desc->subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER;
++	desc->ops = &etb_cs_ops;
++	desc->pdata = pdata;
++	desc->dev = dev;
++	desc->groups = coresight_etb_groups;
++	drvdata->csdev = coresight_register(desc);
++	if (IS_ERR(drvdata->csdev))
++		return PTR_ERR(drvdata->csdev);
++
++	drvdata->miscdev.name = pdata->name;
++	drvdata->miscdev.minor = MISC_DYNAMIC_MINOR;
++	drvdata->miscdev.fops = &etb_fops;
++	ret = misc_register(&drvdata->miscdev);
++	if (ret)
++		goto err_misc_register;
++
++	dev_info(dev, "ETB initialized\n");
++	return 0;
++
++err_misc_register:
++	coresight_unregister(drvdata->csdev);
++	return ret;
++}
++
++static int etb_remove(struct amba_device *adev)
++{
++	struct etb_drvdata *drvdata = amba_get_drvdata(adev);
++
++	misc_deregister(&drvdata->miscdev);
++	coresight_unregister(drvdata->csdev);
++	return 0;
++}
++
++static struct amba_id etb_ids[] = {
++	{
++		.id	= 0x0003b907,
++		.mask	= 0x0003ffff,
++	},
++	{ 0, 0},
++};
++
++static struct amba_driver etb_driver = {
++	.drv = {
++		.name	= "coresight-etb10",
++		.owner	= THIS_MODULE,
++	},
++	.probe		= etb_probe,
++	.remove		= etb_remove,
++	.id_table	= etb_ids,
++};
++
++module_amba_driver(etb_driver);
++
++MODULE_LICENSE("GPL v2");
++MODULE_DESCRIPTION("CoreSight Embedded Trace Buffer driver");
+diff --git a/drivers/hwtracing/coresight/coresight-etm-cp14.c b/drivers/hwtracing/coresight/coresight-etm-cp14.c
+new file mode 100644
+index 0000000..12a2206
+--- /dev/null
++++ b/drivers/hwtracing/coresight/coresight-etm-cp14.c
+@@ -0,0 +1,591 @@
++/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
++
++#include <linux/kernel.h>
++#include <linux/types.h>
++#include <linux/bug.h>
++#include <asm/hardware/cp14.h>
++
++#include "coresight-etm.h"
++
++int etm_readl_cp14(u32 reg, unsigned int *val)
++{
++	switch (reg) {
++	case ETMCR:
++		*val = etm_read(ETMCR);
++		return 0;
++	case ETMCCR:
++		*val = etm_read(ETMCCR);
++		return 0;
++	case ETMTRIGGER:
++		*val = etm_read(ETMTRIGGER);
++		return 0;
++	case ETMSR:
++		*val = etm_read(ETMSR);
++		return 0;
++	case ETMSCR:
++		*val = etm_read(ETMSCR);
++		return 0;
++	case ETMTSSCR:
++		*val = etm_read(ETMTSSCR);
++		return 0;
++	case ETMTEEVR:
++		*val = etm_read(ETMTEEVR);
++		return 0;
++	case ETMTECR1:
++		*val = etm_read(ETMTECR1);
++		return 0;
++	case ETMFFLR:
++		*val = etm_read(ETMFFLR);
++		return 0;
++	case ETMACVRn(0):
++		*val = etm_read(ETMACVR0);
++		return 0;
++	case ETMACVRn(1):
++		*val = etm_read(ETMACVR1);
++		return 0;
++	case ETMACVRn(2):
++		*val = etm_read(ETMACVR2);
++		return 0;
++	case ETMACVRn(3):
++		*val = etm_read(ETMACVR3);
++		return 0;
++	case ETMACVRn(4):
++		*val = etm_read(ETMACVR4);
++		return 0;
++	case ETMACVRn(5):
++		*val = etm_read(ETMACVR5);
++		return 0;
++	case ETMACVRn(6):
++		*val = etm_read(ETMACVR6);
++		return 0;
++	case ETMACVRn(7):
++		*val = etm_read(ETMACVR7);
++		return 0;
++	case ETMACVRn(8):
++		*val = etm_read(ETMACVR8);
++		return 0;
++	case ETMACVRn(9):
++		*val = etm_read(ETMACVR9);
++		return 0;
++	case ETMACVRn(10):
++		*val = etm_read(ETMACVR10);
++		return 0;
++	case ETMACVRn(11):
++		*val = etm_read(ETMACVR11);
++		return 0;
++	case ETMACVRn(12):
++		*val = etm_read(ETMACVR12);
++		return 0;
++	case ETMACVRn(13):
++		*val = etm_read(ETMACVR13);
++		return 0;
++	case ETMACVRn(14):
++		*val = etm_read(ETMACVR14);
++		return 0;
++	case ETMACVRn(15):
++		*val = etm_read(ETMACVR15);
++		return 0;
++	case ETMACTRn(0):
++		*val = etm_read(ETMACTR0);
++		return 0;
++	case ETMACTRn(1):
++		*val = etm_read(ETMACTR1);
++		return 0;
++	case ETMACTRn(2):
++		*val = etm_read(ETMACTR2);
++		return 0;
++	case ETMACTRn(3):
++		*val = etm_read(ETMACTR3);
++		return 0;
++	case ETMACTRn(4):
++		*val = etm_read(ETMACTR4);
++		return 0;
++	case ETMACTRn(5):
++		*val = etm_read(ETMACTR5);
++		return 0;
++	case ETMACTRn(6):
++		*val = etm_read(ETMACTR6);
++		return 0;
++	case ETMACTRn(7):
++		*val = etm_read(ETMACTR7);
++		return 0;
++	case ETMACTRn(8):
++		*val = etm_read(ETMACTR8);
++		return 0;
++	case ETMACTRn(9):
++		*val = etm_read(ETMACTR9);
++		return 0;
++	case ETMACTRn(10):
++		*val = etm_read(ETMACTR10);
++		return 0;
++	case ETMACTRn(11):
++		*val = etm_read(ETMACTR11);
++		return 0;
++	case ETMACTRn(12):
++		*val = etm_read(ETMACTR12);
++		return 0;
++	case ETMACTRn(13):
++		*val = etm_read(ETMACTR13);
++		return 0;
++	case ETMACTRn(14):
++		*val = etm_read(ETMACTR14);
++		return 0;
++	case ETMACTRn(15):
++		*val = etm_read(ETMACTR15);
++		return 0;
++	case ETMCNTRLDVRn(0):
++		*val = etm_read(ETMCNTRLDVR0);
++		return 0;
++	case ETMCNTRLDVRn(1):
++		*val = etm_read(ETMCNTRLDVR1);
++		return 0;
++	case ETMCNTRLDVRn(2):
++		*val = etm_read(ETMCNTRLDVR2);
++		return 0;
++	case ETMCNTRLDVRn(3):
++		*val = etm_read(ETMCNTRLDVR3);
++		return 0;
++	case ETMCNTENRn(0):
++		*val = etm_read(ETMCNTENR0);
++		return 0;
++	case ETMCNTENRn(1):
++		*val = etm_read(ETMCNTENR1);
++		return 0;
++	case ETMCNTENRn(2):
++		*val = etm_read(ETMCNTENR2);
++		return 0;
++	case ETMCNTENRn(3):
++		*val = etm_read(ETMCNTENR3);
++		return 0;
++	case ETMCNTRLDEVRn(0):
++		*val = etm_read(ETMCNTRLDEVR0);
++		return 0;
++	case ETMCNTRLDEVRn(1):
++		*val = etm_read(ETMCNTRLDEVR1);
++		return 0;
++	case ETMCNTRLDEVRn(2):
++		*val = etm_read(ETMCNTRLDEVR2);
++		return 0;
++	case ETMCNTRLDEVRn(3):
++		*val = etm_read(ETMCNTRLDEVR3);
++		return 0;
++	case ETMCNTVRn(0):
++		*val = etm_read(ETMCNTVR0);
++		return 0;
++	case ETMCNTVRn(1):
++		*val = etm_read(ETMCNTVR1);
++		return 0;
++	case ETMCNTVRn(2):
++		*val = etm_read(ETMCNTVR2);
++		return 0;
++	case ETMCNTVRn(3):
++		*val = etm_read(ETMCNTVR3);
++		return 0;
++	case ETMSQ12EVR:
++		*val = etm_read(ETMSQ12EVR);
++		return 0;
++	case ETMSQ21EVR:
++		*val = etm_read(ETMSQ21EVR);
++		return 0;
++	case ETMSQ23EVR:
++		*val = etm_read(ETMSQ23EVR);
++		return 0;
++	case ETMSQ31EVR:
++		*val = etm_read(ETMSQ31EVR);
++		return 0;
++	case ETMSQ32EVR:
++		*val = etm_read(ETMSQ32EVR);
++		return 0;
++	case ETMSQ13EVR:
++		*val = etm_read(ETMSQ13EVR);
++		return 0;
++	case ETMSQR:
++		*val = etm_read(ETMSQR);
++		return 0;
++	case ETMEXTOUTEVRn(0):
++		*val = etm_read(ETMEXTOUTEVR0);
++		return 0;
++	case ETMEXTOUTEVRn(1):
++		*val = etm_read(ETMEXTOUTEVR1);
++		return 0;
++	case ETMEXTOUTEVRn(2):
++		*val = etm_read(ETMEXTOUTEVR2);
++		return 0;
++	case ETMEXTOUTEVRn(3):
++		*val = etm_read(ETMEXTOUTEVR3);
++		return 0;
++	case ETMCIDCVRn(0):
++		*val = etm_read(ETMCIDCVR0);
++		return 0;
++	case ETMCIDCVRn(1):
++		*val = etm_read(ETMCIDCVR1);
++		return 0;
++	case ETMCIDCVRn(2):
++		*val = etm_read(ETMCIDCVR2);
++		return 0;
++	case ETMCIDCMR:
++		*val = etm_read(ETMCIDCMR);
++		return 0;
++	case ETMIMPSPEC0:
++		*val = etm_read(ETMIMPSPEC0);
++		return 0;
++	case ETMIMPSPEC1:
++		*val = etm_read(ETMIMPSPEC1);
++		return 0;
++	case ETMIMPSPEC2:
++		*val = etm_read(ETMIMPSPEC2);
++		return 0;
++	case ETMIMPSPEC3:
++		*val = etm_read(ETMIMPSPEC3);
++		return 0;
++	case ETMIMPSPEC4:
++		*val = etm_read(ETMIMPSPEC4);
++		return 0;
++	case ETMIMPSPEC5:
++		*val = etm_read(ETMIMPSPEC5);
++		return 0;
++	case ETMIMPSPEC6:
++		*val = etm_read(ETMIMPSPEC6);
++		return 0;
++	case ETMIMPSPEC7:
++		*val = etm_read(ETMIMPSPEC7);
++		return 0;
++	case ETMSYNCFR:
++		*val = etm_read(ETMSYNCFR);
++		return 0;
++	case ETMIDR:
++		*val = etm_read(ETMIDR);
++		return 0;
++	case ETMCCER:
++		*val = etm_read(ETMCCER);
++		return 0;
++	case ETMEXTINSELR:
++		*val = etm_read(ETMEXTINSELR);
++		return 0;
++	case ETMTESSEICR:
++		*val = etm_read(ETMTESSEICR);
++		return 0;
++	case ETMEIBCR:
++		*val = etm_read(ETMEIBCR);
++		return 0;
++	case ETMTSEVR:
++		*val = etm_read(ETMTSEVR);
++		return 0;
++	case ETMAUXCR:
++		*val = etm_read(ETMAUXCR);
++		return 0;
++	case ETMTRACEIDR:
++		*val = etm_read(ETMTRACEIDR);
++		return 0;
++	case ETMVMIDCVR:
++		*val = etm_read(ETMVMIDCVR);
++		return 0;
++	case ETMOSLSR:
++		*val = etm_read(ETMOSLSR);
++		return 0;
++	case ETMOSSRR:
++		*val = etm_read(ETMOSSRR);
++		return 0;
++	case ETMPDCR:
++		*val = etm_read(ETMPDCR);
++		return 0;
++	case ETMPDSR:
++		*val = etm_read(ETMPDSR);
++		return 0;
++	default:
++		*val = 0;
++		return -EINVAL;
++	}
++}
++
++int etm_writel_cp14(u32 reg, u32 val)
++{
++	switch (reg) {
++	case ETMCR:
++		etm_write(val, ETMCR);
++		break;
++	case ETMTRIGGER:
++		etm_write(val, ETMTRIGGER);
++		break;
++	case ETMSR:
++		etm_write(val, ETMSR);
++		break;
++	case ETMTSSCR:
++		etm_write(val, ETMTSSCR);
++		break;
++	case ETMTEEVR:
++		etm_write(val, ETMTEEVR);
++		break;
++	case ETMTECR1:
++		etm_write(val, ETMTECR1);
++		break;
++	case ETMFFLR:
++		etm_write(val, ETMFFLR);
++		break;
++	case ETMACVRn(0):
++		etm_write(val, ETMACVR0);
++		break;
++	case ETMACVRn(1):
++		etm_write(val, ETMACVR1);
++		break;
++	case ETMACVRn(2):
++		etm_write(val, ETMACVR2);
++		break;
++	case ETMACVRn(3):
++		etm_write(val, ETMACVR3);
++		break;
++	case ETMACVRn(4):
++		etm_write(val, ETMACVR4);
++		break;
++	case ETMACVRn(5):
++		etm_write(val, ETMACVR5);
++		break;
++	case ETMACVRn(6):
++		etm_write(val, ETMACVR6);
++		break;
++	case ETMACVRn(7):
++		etm_write(val, ETMACVR7);
++		break;
++	case ETMACVRn(8):
++		etm_write(val, ETMACVR8);
++		break;
++	case ETMACVRn(9):
++		etm_write(val, ETMACVR9);
++		break;
++	case ETMACVRn(10):
++		etm_write(val, ETMACVR10);
++		break;
++	case ETMACVRn(11):
++		etm_write(val, ETMACVR11);
++		break;
++	case ETMACVRn(12):
++		etm_write(val, ETMACVR12);
++		break;
++	case ETMACVRn(13):
++		etm_write(val, ETMACVR13);
++		break;
++	case ETMACVRn(14):
++		etm_write(val, ETMACVR14);
++		break;
++	case ETMACVRn(15):
++		etm_write(val, ETMACVR15);
++		break;
++	case ETMACTRn(0):
++		etm_write(val, ETMACTR0);
++		break;
++	case ETMACTRn(1):
++		etm_write(val, ETMACTR1);
++		break;
++	case ETMACTRn(2):
++		etm_write(val, ETMACTR2);
++		break;
++	case ETMACTRn(3):
++		etm_write(val, ETMACTR3);
++		break;
++	case ETMACTRn(4):
++		etm_write(val, ETMACTR4);
++		break;
++	case ETMACTRn(5):
++		etm_write(val, ETMACTR5);
++		break;
++	case ETMACTRn(6):
++		etm_write(val, ETMACTR6);
++		break;
++	case ETMACTRn(7):
++		etm_write(val, ETMACTR7);
++		break;
++	case ETMACTRn(8):
++		etm_write(val, ETMACTR8);
++		break;
++	case ETMACTRn(9):
++		etm_write(val, ETMACTR9);
++		break;
++	case ETMACTRn(10):
++		etm_write(val, ETMACTR10);
++		break;
++	case ETMACTRn(11):
++		etm_write(val, ETMACTR11);
++		break;
++	case ETMACTRn(12):
++		etm_write(val, ETMACTR12);
++		break;
++	case ETMACTRn(13):
++		etm_write(val, ETMACTR13);
++		break;
++	case ETMACTRn(14):
++		etm_write(val, ETMACTR14);
++		break;
++	case ETMACTRn(15):
++		etm_write(val, ETMACTR15);
++		break;
++	case ETMCNTRLDVRn(0):
++		etm_write(val, ETMCNTRLDVR0);
++		break;
++	case ETMCNTRLDVRn(1):
++		etm_write(val, ETMCNTRLDVR1);
++		break;
++	case ETMCNTRLDVRn(2):
++		etm_write(val, ETMCNTRLDVR2);
++		break;
++	case ETMCNTRLDVRn(3):
++		etm_write(val, ETMCNTRLDVR3);
++		break;
++	case ETMCNTENRn(0):
++		etm_write(val, ETMCNTENR0);
++		break;
++	case ETMCNTENRn(1):
++		etm_write(val, ETMCNTENR1);
++		break;
++	case ETMCNTENRn(2):
++		etm_write(val, ETMCNTENR2);
++		break;
++	case ETMCNTENRn(3):
++		etm_write(val, ETMCNTENR3);
++		break;
++	case ETMCNTRLDEVRn(0):
++		etm_write(val, ETMCNTRLDEVR0);
++		break;
++	case ETMCNTRLDEVRn(1):
++		etm_write(val, ETMCNTRLDEVR1);
++		break;
++	case ETMCNTRLDEVRn(2):
++		etm_write(val, ETMCNTRLDEVR2);
++		break;
++	case ETMCNTRLDEVRn(3):
++		etm_write(val, ETMCNTRLDEVR3);
++		break;
++	case ETMCNTVRn(0):
++		etm_write(val, ETMCNTVR0);
++		break;
++	case ETMCNTVRn(1):
++		etm_write(val, ETMCNTVR1);
++		break;
++	case ETMCNTVRn(2):
++		etm_write(val, ETMCNTVR2);
++		break;
++	case ETMCNTVRn(3):
++		etm_write(val, ETMCNTVR3);
++		break;
++	case ETMSQ12EVR:
++		etm_write(val, ETMSQ12EVR);
++		break;
++	case ETMSQ21EVR:
++		etm_write(val, ETMSQ21EVR);
++		break;
++	case ETMSQ23EVR:
++		etm_write(val, ETMSQ23EVR);
++		break;
++	case ETMSQ31EVR:
++		etm_write(val, ETMSQ31EVR);
++		break;
++	case ETMSQ32EVR:
++		etm_write(val, ETMSQ32EVR);
++		break;
++	case ETMSQ13EVR:
++		etm_write(val, ETMSQ13EVR);
++		break;
++	case ETMSQR:
++		etm_write(val, ETMSQR);
++		break;
++	case ETMEXTOUTEVRn(0):
++		etm_write(val, ETMEXTOUTEVR0);
++		break;
++	case ETMEXTOUTEVRn(1):
++		etm_write(val, ETMEXTOUTEVR1);
++		break;
++	case ETMEXTOUTEVRn(2):
++		etm_write(val, ETMEXTOUTEVR2);
++		break;
++	case ETMEXTOUTEVRn(3):
++		etm_write(val, ETMEXTOUTEVR3);
++		break;
++	case ETMCIDCVRn(0):
++		etm_write(val, ETMCIDCVR0);
++		break;
++	case ETMCIDCVRn(1):
++		etm_write(val, ETMCIDCVR1);
++		break;
++	case ETMCIDCVRn(2):
++		etm_write(val, ETMCIDCVR2);
++		break;
++	case ETMCIDCMR:
++		etm_write(val, ETMCIDCMR);
++		break;
++	case ETMIMPSPEC0:
++		etm_write(val, ETMIMPSPEC0);
++		break;
++	case ETMIMPSPEC1:
++		etm_write(val, ETMIMPSPEC1);
++		break;
++	case ETMIMPSPEC2:
++		etm_write(val, ETMIMPSPEC2);
++		break;
++	case ETMIMPSPEC3:
++		etm_write(val, ETMIMPSPEC3);
++		break;
++	case ETMIMPSPEC4:
++		etm_write(val, ETMIMPSPEC4);
++		break;
++	case ETMIMPSPEC5:
++		etm_write(val, ETMIMPSPEC5);
++		break;
++	case ETMIMPSPEC6:
++		etm_write(val, ETMIMPSPEC6);
++		break;
++	case ETMIMPSPEC7:
++		etm_write(val, ETMIMPSPEC7);
++		break;
++	case ETMSYNCFR:
++		etm_write(val, ETMSYNCFR);
++		break;
++	case ETMEXTINSELR:
++		etm_write(val, ETMEXTINSELR);
++		break;
++	case ETMTESSEICR:
++		etm_write(val, ETMTESSEICR);
++		break;
++	case ETMEIBCR:
++		etm_write(val, ETMEIBCR);
++		break;
++	case ETMTSEVR:
++		etm_write(val, ETMTSEVR);
++		break;
++	case ETMAUXCR:
++		etm_write(val, ETMAUXCR);
++		break;
++	case ETMTRACEIDR:
++		etm_write(val, ETMTRACEIDR);
++		break;
++	case ETMVMIDCVR:
++		etm_write(val, ETMVMIDCVR);
++		break;
++	case ETMOSLAR:
++		etm_write(val, ETMOSLAR);
++		break;
++	case ETMOSSRR:
++		etm_write(val, ETMOSSRR);
++		break;
++	case ETMPDCR:
++		etm_write(val, ETMPDCR);
++		break;
++	case ETMPDSR:
++		etm_write(val, ETMPDSR);
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	return 0;
++}
+diff --git a/drivers/hwtracing/coresight/coresight-etm.h b/drivers/hwtracing/coresight/coresight-etm.h
+new file mode 100644
+index 0000000..501c5fa
+--- /dev/null
++++ b/drivers/hwtracing/coresight/coresight-etm.h
+@@ -0,0 +1,251 @@
++/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#ifndef _CORESIGHT_CORESIGHT_ETM_H
++#define _CORESIGHT_CORESIGHT_ETM_H
++
++#include <linux/spinlock.h>
++#include "coresight-priv.h"
++
++/*
++ * Device registers:
++ * 0x000 - 0x2FC: Trace         registers
++ * 0x300 - 0x314: Management    registers
++ * 0x318 - 0xEFC: Trace         registers
++ *
++ * Coresight registers
++ * 0xF00 - 0xF9C: Management    registers
++ * 0xFA0 - 0xFA4: Management    registers in PFTv1.0
++ *                Trace         registers in PFTv1.1
++ * 0xFA8 - 0xFFC: Management    registers
++ */
++
++/* Trace registers (0x000-0x2FC) */
++#define ETMCR			0x000
++#define ETMCCR			0x004
++#define ETMTRIGGER		0x008
++#define ETMSR			0x010
++#define ETMSCR			0x014
++#define ETMTSSCR		0x018
++#define ETMTECR2		0x01c
++#define ETMTEEVR		0x020
++#define ETMTECR1		0x024
++#define ETMFFLR			0x02c
++#define ETMACVRn(n)		(0x040 + (n * 4))
++#define ETMACTRn(n)		(0x080 + (n * 4))
++#define ETMCNTRLDVRn(n)		(0x140 + (n * 4))
++#define ETMCNTENRn(n)		(0x150 + (n * 4))
++#define ETMCNTRLDEVRn(n)	(0x160 + (n * 4))
++#define ETMCNTVRn(n)		(0x170 + (n * 4))
++#define ETMSQ12EVR		0x180
++#define ETMSQ21EVR		0x184
++#define ETMSQ23EVR		0x188
++#define ETMSQ31EVR		0x18c
++#define ETMSQ32EVR		0x190
++#define ETMSQ13EVR		0x194
++#define ETMSQR			0x19c
++#define ETMEXTOUTEVRn(n)	(0x1a0 + (n * 4))
++#define ETMCIDCVRn(n)		(0x1b0 + (n * 4))
++#define ETMCIDCMR		0x1bc
++#define ETMIMPSPEC0		0x1c0
++#define ETMIMPSPEC1		0x1c4
++#define ETMIMPSPEC2		0x1c8
++#define ETMIMPSPEC3		0x1cc
++#define ETMIMPSPEC4		0x1d0
++#define ETMIMPSPEC5		0x1d4
++#define ETMIMPSPEC6		0x1d8
++#define ETMIMPSPEC7		0x1dc
++#define ETMSYNCFR		0x1e0
++#define ETMIDR			0x1e4
++#define ETMCCER			0x1e8
++#define ETMEXTINSELR		0x1ec
++#define ETMTESSEICR		0x1f0
++#define ETMEIBCR		0x1f4
++#define ETMTSEVR		0x1f8
++#define ETMAUXCR		0x1fc
++#define ETMTRACEIDR		0x200
++#define ETMVMIDCVR		0x240
++/* Management registers (0x300-0x314) */
++#define ETMOSLAR		0x300
++#define ETMOSLSR		0x304
++#define ETMOSSRR		0x308
++#define ETMPDCR			0x310
++#define ETMPDSR			0x314
++#define ETM_MAX_ADDR_CMP	16
++#define ETM_MAX_CNTR		4
++#define ETM_MAX_CTXID_CMP	3
++
++/* Register definition */
++/* ETMCR - 0x00 */
++#define ETMCR_PWD_DWN		BIT(0)
++#define ETMCR_STALL_MODE	BIT(7)
++#define ETMCR_ETM_PRG		BIT(10)
++#define ETMCR_ETM_EN		BIT(11)
++#define ETMCR_CYC_ACC		BIT(12)
++#define ETMCR_CTXID_SIZE	(BIT(14)|BIT(15))
++#define ETMCR_TIMESTAMP_EN	BIT(28)
++/* ETMCCR - 0x04 */
++#define ETMCCR_FIFOFULL		BIT(23)
++/* ETMPDCR - 0x310 */
++#define ETMPDCR_PWD_UP		BIT(3)
++/* ETMTECR1 - 0x024 */
++#define ETMTECR1_ADDR_COMP_1	BIT(0)
++#define ETMTECR1_INC_EXC	BIT(24)
++#define ETMTECR1_START_STOP	BIT(25)
++/* ETMCCER - 0x1E8 */
++#define ETMCCER_TIMESTAMP	BIT(22)
++
++#define ETM_MODE_EXCLUDE	BIT(0)
++#define ETM_MODE_CYCACC		BIT(1)
++#define ETM_MODE_STALL		BIT(2)
++#define ETM_MODE_TIMESTAMP	BIT(3)
++#define ETM_MODE_CTXID		BIT(4)
++#define ETM_MODE_ALL		0x1f
++
++#define ETM_SQR_MASK		0x3
++#define ETM_TRACEID_MASK	0x3f
++#define ETM_EVENT_MASK		0x1ffff
++#define ETM_SYNC_MASK		0xfff
++#define ETM_ALL_MASK		0xffffffff
++
++#define ETMSR_PROG_BIT		1
++#define ETM_SEQ_STATE_MAX_VAL	(0x2)
++#define PORT_SIZE_MASK		(GENMASK(21, 21) | GENMASK(6, 4))
++
++#define ETM_HARD_WIRE_RES_A	/* Hard wired, always true */	\
++				((0x0f << 0)	|		\
++				/* Resource index A */		\
++				(0x06 << 4))
++
++#define ETM_ADD_COMP_0		/* Single addr comparator 1 */	\
++				((0x00 << 7)	|		\
++				/* Resource index B */		\
++				(0x00 << 11))
++
++#define ETM_EVENT_NOT_A		BIT(14) /* NOT(A) */
++
++#define ETM_DEFAULT_EVENT_VAL	(ETM_HARD_WIRE_RES_A	|	\
++				 ETM_ADD_COMP_0		|	\
++				 ETM_EVENT_NOT_A)
++/**
++ * struct etm_drvdata - specifics associated to an ETM component
++ * @base:	memory mapped base address for this component.
++ * @dev:	the device entity associated to this component.
++ * @csdev:	component vitals needed by the framework.
++ * @clk:	the clock this component is associated to.
++ * @spinlock:	only one at a time pls.
++ * @cpu:	the cpu this component is affined to.
++ * @port_size:	port size as reported by ETMCR bit 4-6 and 21.
++ * @arch:	ETM/PTM version number.
++ * @use_cpu14:	true if management registers need to be accessed via CP14.
++ * @enable:	is this ETM/PTM currently tracing.
++ * @sticky_enable: true if ETM base configuration has been done.
++ * @boot_enable:true if we should start tracing at boot time.
++ * @os_unlock:	true if access to management registers is allowed.
++ * @nr_addr_cmp:Number of pairs of address comparators as found in ETMCCR.
++ * @nr_cntr:	Number of counters as found in ETMCCR bit 13-15.
++ * @nr_ext_inp:	Number of external input as found in ETMCCR bit 17-19.
++ * @nr_ext_out:	Number of external output as found in ETMCCR bit 20-22.
++ * @nr_ctxid_cmp: Number of contextID comparators as found in ETMCCR bit 24-25.
++ * @etmccr:	value of register ETMCCR.
++ * @etmccer:	value of register ETMCCER.
++ * @traceid:	value of the current ID for this component.
++ * @mode:	controls various modes supported by this ETM/PTM.
++ * @ctrl:	used in conjunction with @mode.
++ * @trigger_event: setting for register ETMTRIGGER.
++ * @startstop_ctrl: setting for register ETMTSSCR.
++ * @enable_event: setting for register ETMTEEVR.
++ * @enable_ctrl1: setting for register ETMTECR1.
++ * @fifofull_level: setting for register ETMFFLR.
++ * @addr_idx:	index for the address comparator selection.
++ * @addr_val:	value for address comparator register.
++ * @addr_acctype: access type for address comparator register.
++ * @addr_type:	current status of the comparator register.
++ * @cntr_idx:	index for the counter register selection.
++ * @cntr_rld_val: reload value of a counter register.
++ * @cntr_event:	control for counter enable register.
++ * @cntr_rld_event: value for counter reload event register.
++ * @cntr_val:	counter value register.
++ * @seq_12_event: event causing the transition from 1 to 2.
++ * @seq_21_event: event causing the transition from 2 to 1.
++ * @seq_23_event: event causing the transition from 2 to 3.
++ * @seq_31_event: event causing the transition from 3 to 1.
++ * @seq_32_event: event causing the transition from 3 to 2.
++ * @seq_13_event: event causing the transition from 1 to 3.
++ * @seq_curr_state: current value of the sequencer register.
++ * @ctxid_idx: index for the context ID registers.
++ * @ctxid_val: value for the context ID to trigger on.
++ * @ctxid_mask: mask applicable to all the context IDs.
++ * @sync_freq:	Synchronisation frequency.
++ * @timestamp_event: Defines an event that requests the insertion
++		     of a timestamp into the trace stream.
++ */
++struct etm_drvdata {
++	void __iomem			*base;
++	struct device			*dev;
++	struct coresight_device		*csdev;
++	struct clk			*clk;
++	spinlock_t			spinlock;
++	int				cpu;
++	int				port_size;
++	u8				arch;
++	bool				use_cp14;
++	bool				enable;
++	bool				sticky_enable;
++	bool				boot_enable;
++	bool				os_unlock;
++	u8				nr_addr_cmp;
++	u8				nr_cntr;
++	u8				nr_ext_inp;
++	u8				nr_ext_out;
++	u8				nr_ctxid_cmp;
++	u32				etmccr;
++	u32				etmccer;
++	u32				traceid;
++	u32				mode;
++	u32				ctrl;
++	u32				trigger_event;
++	u32				startstop_ctrl;
++	u32				enable_event;
++	u32				enable_ctrl1;
++	u32				fifofull_level;
++	u8				addr_idx;
++	u32				addr_val[ETM_MAX_ADDR_CMP];
++	u32				addr_acctype[ETM_MAX_ADDR_CMP];
++	u32				addr_type[ETM_MAX_ADDR_CMP];
++	u8				cntr_idx;
++	u32				cntr_rld_val[ETM_MAX_CNTR];
++	u32				cntr_event[ETM_MAX_CNTR];
++	u32				cntr_rld_event[ETM_MAX_CNTR];
++	u32				cntr_val[ETM_MAX_CNTR];
++	u32				seq_12_event;
++	u32				seq_21_event;
++	u32				seq_23_event;
++	u32				seq_31_event;
++	u32				seq_32_event;
++	u32				seq_13_event;
++	u32				seq_curr_state;
++	u8				ctxid_idx;
++	u32				ctxid_val[ETM_MAX_CTXID_CMP];
++	u32				ctxid_mask;
++	u32				sync_freq;
++	u32				timestamp_event;
++};
++
++enum etm_addr_type {
++	ETM_ADDR_TYPE_NONE,
++	ETM_ADDR_TYPE_SINGLE,
++	ETM_ADDR_TYPE_RANGE,
++	ETM_ADDR_TYPE_START,
++	ETM_ADDR_TYPE_STOP,
++};
++#endif
+diff --git a/drivers/hwtracing/coresight/coresight-etm3x.c b/drivers/hwtracing/coresight/coresight-etm3x.c
+new file mode 100644
+index 0000000..c965f57
+--- /dev/null
++++ b/drivers/hwtracing/coresight/coresight-etm3x.c
+@@ -0,0 +1,1932 @@
++/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/types.h>
++#include <linux/device.h>
++#include <linux/io.h>
++#include <linux/err.h>
++#include <linux/fs.h>
++#include <linux/slab.h>
++#include <linux/delay.h>
++#include <linux/smp.h>
++#include <linux/sysfs.h>
++#include <linux/stat.h>
++#include <linux/clk.h>
++#include <linux/cpu.h>
++#include <linux/of.h>
++#include <linux/coresight.h>
++#include <linux/amba/bus.h>
++#include <linux/seq_file.h>
++#include <linux/uaccess.h>
++#include <asm/sections.h>
++
++#include "coresight-etm.h"
++
++static int boot_enable;
++module_param_named(boot_enable, boot_enable, int, S_IRUGO);
++
++/* The number of ETM/PTM currently registered */
++static int etm_count;
++static struct etm_drvdata *etmdrvdata[NR_CPUS];
++
++static inline void etm_writel(struct etm_drvdata *drvdata,
++			      u32 val, u32 off)
++{
++	if (drvdata->use_cp14) {
++		if (etm_writel_cp14(off, val)) {
++			dev_err(drvdata->dev,
++				"invalid CP14 access to ETM reg: %#x", off);
++		}
++	} else {
++		writel_relaxed(val, drvdata->base + off);
++	}
++}
++
++static inline unsigned int etm_readl(struct etm_drvdata *drvdata, u32 off)
++{
++	u32 val;
++
++	if (drvdata->use_cp14) {
++		if (etm_readl_cp14(off, &val)) {
++			dev_err(drvdata->dev,
++				"invalid CP14 access to ETM reg: %#x", off);
++		}
++	} else {
++		val = readl_relaxed(drvdata->base + off);
++	}
++
++	return val;
++}
++
++/*
++ * Memory mapped writes to clear os lock are not supported on some processors
++ * and OS lock must be unlocked before any memory mapped access on such
++ * processors, otherwise memory mapped reads/writes will be invalid.
++ */
++static void etm_os_unlock(void *info)
++{
++	struct etm_drvdata *drvdata = (struct etm_drvdata *)info;
++	/* Writing any value to ETMOSLAR unlocks the trace registers */
++	etm_writel(drvdata, 0x0, ETMOSLAR);
++	isb();
++}
++
++static void etm_set_pwrdwn(struct etm_drvdata *drvdata)
++{
++	u32 etmcr;
++
++	/* Ensure pending cp14 accesses complete before setting pwrdwn */
++	mb();
++	isb();
++	etmcr = etm_readl(drvdata, ETMCR);
++	etmcr |= ETMCR_PWD_DWN;
++	etm_writel(drvdata, etmcr, ETMCR);
++}
++
++static void etm_clr_pwrdwn(struct etm_drvdata *drvdata)
++{
++	u32 etmcr;
++
++	etmcr = etm_readl(drvdata, ETMCR);
++	etmcr &= ~ETMCR_PWD_DWN;
++	etm_writel(drvdata, etmcr, ETMCR);
++	/* Ensure pwrup completes before subsequent cp14 accesses */
++	mb();
++	isb();
++}
++
++static void etm_set_pwrup(struct etm_drvdata *drvdata)
++{
++	u32 etmpdcr;
++
++	etmpdcr = readl_relaxed(drvdata->base + ETMPDCR);
++	etmpdcr |= ETMPDCR_PWD_UP;
++	writel_relaxed(etmpdcr, drvdata->base + ETMPDCR);
++	/* Ensure pwrup completes before subsequent cp14 accesses */
++	mb();
++	isb();
++}
++
++static void etm_clr_pwrup(struct etm_drvdata *drvdata)
++{
++	u32 etmpdcr;
++
++	/* Ensure pending cp14 accesses complete before clearing pwrup */
++	mb();
++	isb();
++	etmpdcr = readl_relaxed(drvdata->base + ETMPDCR);
++	etmpdcr &= ~ETMPDCR_PWD_UP;
++	writel_relaxed(etmpdcr, drvdata->base + ETMPDCR);
++}
++
++/**
++ * coresight_timeout_etm - loop until a bit has changed to a specific state.
++ * @drvdata: etm's private data structure.
++ * @offset: address of a register, starting from @addr.
++ * @position: the position of the bit of interest.
++ * @value: the value the bit should have.
++ *
++ * Basically the same as @coresight_timeout except for the register access
++ * method where we have to account for CP14 configurations.
++
++ * Return: 0 as soon as the bit has taken the desired state or -EAGAIN if
++ * TIMEOUT_US has elapsed, which ever happens first.
++ */
++
++static int coresight_timeout_etm(struct etm_drvdata *drvdata, u32 offset,
++				  int position, int value)
++{
++	int i;
++	u32 val;
++
++	for (i = TIMEOUT_US; i > 0; i--) {
++		val = etm_readl(drvdata, offset);
++		/* Waiting on the bit to go from 0 to 1 */
++		if (value) {
++			if (val & BIT(position))
++				return 0;
++		/* Waiting on the bit to go from 1 to 0 */
++		} else {
++			if (!(val & BIT(position)))
++				return 0;
++		}
++
++		/*
++		 * Delay is arbitrary - the specification doesn't say how long
++		 * we are expected to wait.  Extra check required to make sure
++		 * we don't wait needlessly on the last iteration.
++		 */
++		if (i - 1)
++			udelay(1);
++	}
++
++	return -EAGAIN;
++}
++
++
++static void etm_set_prog(struct etm_drvdata *drvdata)
++{
++	u32 etmcr;
++
++	etmcr = etm_readl(drvdata, ETMCR);
++	etmcr |= ETMCR_ETM_PRG;
++	etm_writel(drvdata, etmcr, ETMCR);
++	/*
++	 * Recommended by spec for cp14 accesses to ensure etmcr write is
++	 * complete before polling etmsr
++	 */
++	isb();
++	if (coresight_timeout_etm(drvdata, ETMSR, ETMSR_PROG_BIT, 1)) {
++		dev_err(drvdata->dev,
++			"timeout observed when probing at offset %#x\n", ETMSR);
++	}
++}
++
++static void etm_clr_prog(struct etm_drvdata *drvdata)
++{
++	u32 etmcr;
++
++	etmcr = etm_readl(drvdata, ETMCR);
++	etmcr &= ~ETMCR_ETM_PRG;
++	etm_writel(drvdata, etmcr, ETMCR);
++	/*
++	 * Recommended by spec for cp14 accesses to ensure etmcr write is
++	 * complete before polling etmsr
++	 */
++	isb();
++	if (coresight_timeout_etm(drvdata, ETMSR, ETMSR_PROG_BIT, 0)) {
++		dev_err(drvdata->dev,
++			"timeout observed when probing at offset %#x\n", ETMSR);
++	}
++}
++
++static void etm_set_default(struct etm_drvdata *drvdata)
++{
++	int i;
++
++	drvdata->trigger_event = ETM_DEFAULT_EVENT_VAL;
++	drvdata->enable_event = ETM_HARD_WIRE_RES_A;
++
++	drvdata->seq_12_event = ETM_DEFAULT_EVENT_VAL;
++	drvdata->seq_21_event = ETM_DEFAULT_EVENT_VAL;
++	drvdata->seq_23_event = ETM_DEFAULT_EVENT_VAL;
++	drvdata->seq_31_event = ETM_DEFAULT_EVENT_VAL;
++	drvdata->seq_32_event = ETM_DEFAULT_EVENT_VAL;
++	drvdata->seq_13_event = ETM_DEFAULT_EVENT_VAL;
++	drvdata->timestamp_event = ETM_DEFAULT_EVENT_VAL;
++
++	for (i = 0; i < drvdata->nr_cntr; i++) {
++		drvdata->cntr_rld_val[i] = 0x0;
++		drvdata->cntr_event[i] = ETM_DEFAULT_EVENT_VAL;
++		drvdata->cntr_rld_event[i] = ETM_DEFAULT_EVENT_VAL;
++		drvdata->cntr_val[i] = 0x0;
++	}
++
++	drvdata->seq_curr_state = 0x0;
++	drvdata->ctxid_idx = 0x0;
++	for (i = 0; i < drvdata->nr_ctxid_cmp; i++)
++		drvdata->ctxid_val[i] = 0x0;
++	drvdata->ctxid_mask = 0x0;
++}
++
++static void etm_enable_hw(void *info)
++{
++	int i;
++	u32 etmcr;
++	struct etm_drvdata *drvdata = info;
++
++	CS_UNLOCK(drvdata->base);
++
++	/* Turn engine on */
++	etm_clr_pwrdwn(drvdata);
++	/* Apply power to trace registers */
++	etm_set_pwrup(drvdata);
++	/* Make sure all registers are accessible */
++	etm_os_unlock(drvdata);
++
++	etm_set_prog(drvdata);
++
++	etmcr = etm_readl(drvdata, ETMCR);
++	etmcr &= (ETMCR_PWD_DWN | ETMCR_ETM_PRG);
++	etmcr |= drvdata->port_size;
++	etm_writel(drvdata, drvdata->ctrl | etmcr, ETMCR);
++	etm_writel(drvdata, drvdata->trigger_event, ETMTRIGGER);
++	etm_writel(drvdata, drvdata->startstop_ctrl, ETMTSSCR);
++	etm_writel(drvdata, drvdata->enable_event, ETMTEEVR);
++	etm_writel(drvdata, drvdata->enable_ctrl1, ETMTECR1);
++	etm_writel(drvdata, drvdata->fifofull_level, ETMFFLR);
++	for (i = 0; i < drvdata->nr_addr_cmp; i++) {
++		etm_writel(drvdata, drvdata->addr_val[i], ETMACVRn(i));
++		etm_writel(drvdata, drvdata->addr_acctype[i], ETMACTRn(i));
++	}
++	for (i = 0; i < drvdata->nr_cntr; i++) {
++		etm_writel(drvdata, drvdata->cntr_rld_val[i], ETMCNTRLDVRn(i));
++		etm_writel(drvdata, drvdata->cntr_event[i], ETMCNTENRn(i));
++		etm_writel(drvdata, drvdata->cntr_rld_event[i],
++			   ETMCNTRLDEVRn(i));
++		etm_writel(drvdata, drvdata->cntr_val[i], ETMCNTVRn(i));
++	}
++	etm_writel(drvdata, drvdata->seq_12_event, ETMSQ12EVR);
++	etm_writel(drvdata, drvdata->seq_21_event, ETMSQ21EVR);
++	etm_writel(drvdata, drvdata->seq_23_event, ETMSQ23EVR);
++	etm_writel(drvdata, drvdata->seq_31_event, ETMSQ31EVR);
++	etm_writel(drvdata, drvdata->seq_32_event, ETMSQ32EVR);
++	etm_writel(drvdata, drvdata->seq_13_event, ETMSQ13EVR);
++	etm_writel(drvdata, drvdata->seq_curr_state, ETMSQR);
++	for (i = 0; i < drvdata->nr_ext_out; i++)
++		etm_writel(drvdata, ETM_DEFAULT_EVENT_VAL, ETMEXTOUTEVRn(i));
++	for (i = 0; i < drvdata->nr_ctxid_cmp; i++)
++		etm_writel(drvdata, drvdata->ctxid_val[i], ETMCIDCVRn(i));
++	etm_writel(drvdata, drvdata->ctxid_mask, ETMCIDCMR);
++	etm_writel(drvdata, drvdata->sync_freq, ETMSYNCFR);
++	/* No external input selected */
++	etm_writel(drvdata, 0x0, ETMEXTINSELR);
++	etm_writel(drvdata, drvdata->timestamp_event, ETMTSEVR);
++	/* No auxiliary control selected */
++	etm_writel(drvdata, 0x0, ETMAUXCR);
++	etm_writel(drvdata, drvdata->traceid, ETMTRACEIDR);
++	/* No VMID comparator value selected */
++	etm_writel(drvdata, 0x0, ETMVMIDCVR);
++
++	/* Ensures trace output is enabled from this ETM */
++	etm_writel(drvdata, drvdata->ctrl | ETMCR_ETM_EN | etmcr, ETMCR);
++
++	etm_clr_prog(drvdata);
++	CS_LOCK(drvdata->base);
++
++	dev_dbg(drvdata->dev, "cpu: %d enable smp call done\n", drvdata->cpu);
++}
++
++static int etm_trace_id_simple(struct etm_drvdata *drvdata)
++{
++	if (!drvdata->enable)
++		return drvdata->traceid;
++
++	return (etm_readl(drvdata, ETMTRACEIDR) & ETM_TRACEID_MASK);
++}
++
++static int etm_trace_id(struct coresight_device *csdev)
++{
++	struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
++	unsigned long flags;
++	int trace_id = -1;
++
++	if (!drvdata->enable)
++		return drvdata->traceid;
++
++	if (clk_prepare_enable(drvdata->clk))
++		goto out;
++
++	spin_lock_irqsave(&drvdata->spinlock, flags);
++
++	CS_UNLOCK(drvdata->base);
++	trace_id = (etm_readl(drvdata, ETMTRACEIDR) & ETM_TRACEID_MASK);
++	CS_LOCK(drvdata->base);
++
++	spin_unlock_irqrestore(&drvdata->spinlock, flags);
++	clk_disable_unprepare(drvdata->clk);
++out:
++	return trace_id;
++}
++
++static int etm_enable(struct coresight_device *csdev)
++{
++	struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
++	int ret;
++
++	ret = clk_prepare_enable(drvdata->clk);
++	if (ret)
++		goto err_clk;
++
++	spin_lock(&drvdata->spinlock);
++
++	/*
++	 * Configure the ETM only if the CPU is online.  If it isn't online
++	 * hw configuration will take place when 'CPU_STARTING' is received
++	 * in @etm_cpu_callback.
++	 */
++	if (cpu_online(drvdata->cpu)) {
++		ret = smp_call_function_single(drvdata->cpu,
++					       etm_enable_hw, drvdata, 1);
++		if (ret)
++			goto err;
++	}
++
++	drvdata->enable = true;
++	drvdata->sticky_enable = true;
++
++	spin_unlock(&drvdata->spinlock);
++
++	dev_info(drvdata->dev, "ETM tracing enabled\n");
++	return 0;
++err:
++	spin_unlock(&drvdata->spinlock);
++	clk_disable_unprepare(drvdata->clk);
++err_clk:
++	return ret;
++}
++
++static void etm_disable_hw(void *info)
++{
++	int i;
++	struct etm_drvdata *drvdata = info;
++
++	CS_UNLOCK(drvdata->base);
++	etm_set_prog(drvdata);
++
++	/* Program trace enable to low by using always false event */
++	etm_writel(drvdata, ETM_HARD_WIRE_RES_A | ETM_EVENT_NOT_A, ETMTEEVR);
++
++	/* Read back sequencer and counters for post trace analysis */
++	drvdata->seq_curr_state = (etm_readl(drvdata, ETMSQR) & ETM_SQR_MASK);
++
++	for (i = 0; i < drvdata->nr_cntr; i++)
++		drvdata->cntr_val[i] = etm_readl(drvdata, ETMCNTVRn(i));
++
++	etm_set_pwrdwn(drvdata);
++	CS_LOCK(drvdata->base);
++
++	dev_dbg(drvdata->dev, "cpu: %d disable smp call done\n", drvdata->cpu);
++}
++
++static void etm_disable(struct coresight_device *csdev)
++{
++	struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
++
++	/*
++	 * Taking hotplug lock here protects from clocks getting disabled
++	 * with tracing being left on (crash scenario) if user disable occurs
++	 * after cpu online mask indicates the cpu is offline but before the
++	 * DYING hotplug callback is serviced by the ETM driver.
++	 */
++	get_online_cpus();
++	spin_lock(&drvdata->spinlock);
++
++	/*
++	 * Executing etm_disable_hw on the cpu whose ETM is being disabled
++	 * ensures that register writes occur when cpu is powered.
++	 */
++	smp_call_function_single(drvdata->cpu, etm_disable_hw, drvdata, 1);
++	drvdata->enable = false;
++
++	spin_unlock(&drvdata->spinlock);
++	put_online_cpus();
++
++	clk_disable_unprepare(drvdata->clk);
++
++	dev_info(drvdata->dev, "ETM tracing disabled\n");
++}
++
++static const struct coresight_ops_source etm_source_ops = {
++	.trace_id	= etm_trace_id,
++	.enable		= etm_enable,
++	.disable	= etm_disable,
++};
++
++static const struct coresight_ops etm_cs_ops = {
++	.source_ops	= &etm_source_ops,
++};
++
++static ssize_t nr_addr_cmp_show(struct device *dev,
++				struct device_attribute *attr, char *buf)
++{
++	unsigned long val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	val = drvdata->nr_addr_cmp;
++	return sprintf(buf, "%#lx\n", val);
++}
++static DEVICE_ATTR_RO(nr_addr_cmp);
++
++static ssize_t nr_cntr_show(struct device *dev,
++			    struct device_attribute *attr, char *buf)
++{	unsigned long val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	val = drvdata->nr_cntr;
++	return sprintf(buf, "%#lx\n", val);
++}
++static DEVICE_ATTR_RO(nr_cntr);
++
++static ssize_t nr_ctxid_cmp_show(struct device *dev,
++				 struct device_attribute *attr, char *buf)
++{
++	unsigned long val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	val = drvdata->nr_ctxid_cmp;
++	return sprintf(buf, "%#lx\n", val);
++}
++static DEVICE_ATTR_RO(nr_ctxid_cmp);
++
++static ssize_t etmsr_show(struct device *dev,
++			  struct device_attribute *attr, char *buf)
++{
++	int ret;
++	unsigned long flags, val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	ret = clk_prepare_enable(drvdata->clk);
++	if (ret)
++		return ret;
++
++	spin_lock_irqsave(&drvdata->spinlock, flags);
++	CS_UNLOCK(drvdata->base);
++
++	val = etm_readl(drvdata, ETMSR);
++
++	CS_LOCK(drvdata->base);
++	spin_unlock_irqrestore(&drvdata->spinlock, flags);
++	clk_disable_unprepare(drvdata->clk);
++
++	return sprintf(buf, "%#lx\n", val);
++}
++static DEVICE_ATTR_RO(etmsr);
++
++static ssize_t reset_store(struct device *dev,
++			   struct device_attribute *attr,
++			   const char *buf, size_t size)
++{
++	int i, ret;
++	unsigned long val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	ret = kstrtoul(buf, 16, &val);
++	if (ret)
++		return ret;
++
++	if (val) {
++		spin_lock(&drvdata->spinlock);
++		drvdata->mode = ETM_MODE_EXCLUDE;
++		drvdata->ctrl = 0x0;
++		drvdata->trigger_event = ETM_DEFAULT_EVENT_VAL;
++		drvdata->startstop_ctrl = 0x0;
++		drvdata->addr_idx = 0x0;
++		for (i = 0; i < drvdata->nr_addr_cmp; i++) {
++			drvdata->addr_val[i] = 0x0;
++			drvdata->addr_acctype[i] = 0x0;
++			drvdata->addr_type[i] = ETM_ADDR_TYPE_NONE;
++		}
++		drvdata->cntr_idx = 0x0;
++
++		etm_set_default(drvdata);
++		spin_unlock(&drvdata->spinlock);
++	}
++
++	return size;
++}
++static DEVICE_ATTR_WO(reset);
++
++static ssize_t mode_show(struct device *dev,
++			 struct device_attribute *attr, char *buf)
++{
++	unsigned long val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	val = drvdata->mode;
++	return sprintf(buf, "%#lx\n", val);
++}
++
++static ssize_t mode_store(struct device *dev,
++			  struct device_attribute *attr,
++			  const char *buf, size_t size)
++{
++	int ret;
++	unsigned long val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	ret = kstrtoul(buf, 16, &val);
++	if (ret)
++		return ret;
++
++	spin_lock(&drvdata->spinlock);
++	drvdata->mode = val & ETM_MODE_ALL;
++
++	if (drvdata->mode & ETM_MODE_EXCLUDE)
++		drvdata->enable_ctrl1 |= ETMTECR1_INC_EXC;
++	else
++		drvdata->enable_ctrl1 &= ~ETMTECR1_INC_EXC;
++
++	if (drvdata->mode & ETM_MODE_CYCACC)
++		drvdata->ctrl |= ETMCR_CYC_ACC;
++	else
++		drvdata->ctrl &= ~ETMCR_CYC_ACC;
++
++	if (drvdata->mode & ETM_MODE_STALL) {
++		if (!(drvdata->etmccr & ETMCCR_FIFOFULL)) {
++			dev_warn(drvdata->dev, "stall mode not supported\n");
++			ret = -EINVAL;
++			goto err_unlock;
++		}
++		drvdata->ctrl |= ETMCR_STALL_MODE;
++	 } else
++		drvdata->ctrl &= ~ETMCR_STALL_MODE;
++
++	if (drvdata->mode & ETM_MODE_TIMESTAMP) {
++		if (!(drvdata->etmccer & ETMCCER_TIMESTAMP)) {
++			dev_warn(drvdata->dev, "timestamp not supported\n");
++			ret = -EINVAL;
++			goto err_unlock;
++		}
++		drvdata->ctrl |= ETMCR_TIMESTAMP_EN;
++	} else
++		drvdata->ctrl &= ~ETMCR_TIMESTAMP_EN;
++
++	if (drvdata->mode & ETM_MODE_CTXID)
++		drvdata->ctrl |= ETMCR_CTXID_SIZE;
++	else
++		drvdata->ctrl &= ~ETMCR_CTXID_SIZE;
++	spin_unlock(&drvdata->spinlock);
++
++	return size;
++
++err_unlock:
++	spin_unlock(&drvdata->spinlock);
++	return ret;
++}
++static DEVICE_ATTR_RW(mode);
++
++static ssize_t trigger_event_show(struct device *dev,
++				  struct device_attribute *attr, char *buf)
++{
++	unsigned long val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	val = drvdata->trigger_event;
++	return sprintf(buf, "%#lx\n", val);
++}
++
++static ssize_t trigger_event_store(struct device *dev,
++				   struct device_attribute *attr,
++				   const char *buf, size_t size)
++{
++	int ret;
++	unsigned long val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	ret = kstrtoul(buf, 16, &val);
++	if (ret)
++		return ret;
++
++	drvdata->trigger_event = val & ETM_EVENT_MASK;
++
++	return size;
++}
++static DEVICE_ATTR_RW(trigger_event);
++
++static ssize_t enable_event_show(struct device *dev,
++				 struct device_attribute *attr, char *buf)
++{
++	unsigned long val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	val = drvdata->enable_event;
++	return sprintf(buf, "%#lx\n", val);
++}
++
++static ssize_t enable_event_store(struct device *dev,
++				  struct device_attribute *attr,
++				  const char *buf, size_t size)
++{
++	int ret;
++	unsigned long val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	ret = kstrtoul(buf, 16, &val);
++	if (ret)
++		return ret;
++
++	drvdata->enable_event = val & ETM_EVENT_MASK;
++
++	return size;
++}
++static DEVICE_ATTR_RW(enable_event);
++
++static ssize_t fifofull_level_show(struct device *dev,
++				   struct device_attribute *attr, char *buf)
++{
++	unsigned long val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	val = drvdata->fifofull_level;
++	return sprintf(buf, "%#lx\n", val);
++}
++
++static ssize_t fifofull_level_store(struct device *dev,
++				    struct device_attribute *attr,
++				    const char *buf, size_t size)
++{
++	int ret;
++	unsigned long val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	ret = kstrtoul(buf, 16, &val);
++	if (ret)
++		return ret;
++
++	drvdata->fifofull_level = val;
++
++	return size;
++}
++static DEVICE_ATTR_RW(fifofull_level);
++
++static ssize_t addr_idx_show(struct device *dev,
++			     struct device_attribute *attr, char *buf)
++{
++	unsigned long val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	val = drvdata->addr_idx;
++	return sprintf(buf, "%#lx\n", val);
++}
++
++static ssize_t addr_idx_store(struct device *dev,
++			      struct device_attribute *attr,
++			      const char *buf, size_t size)
++{
++	int ret;
++	unsigned long val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	ret = kstrtoul(buf, 16, &val);
++	if (ret)
++		return ret;
++
++	if (val >= drvdata->nr_addr_cmp)
++		return -EINVAL;
++
++	/*
++	 * Use spinlock to ensure index doesn't change while it gets
++	 * dereferenced multiple times within a spinlock block elsewhere.
++	 */
++	spin_lock(&drvdata->spinlock);
++	drvdata->addr_idx = val;
++	spin_unlock(&drvdata->spinlock);
++
++	return size;
++}
++static DEVICE_ATTR_RW(addr_idx);
++
++static ssize_t addr_single_show(struct device *dev,
++				struct device_attribute *attr, char *buf)
++{
++	u8 idx;
++	unsigned long val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	spin_lock(&drvdata->spinlock);
++	idx = drvdata->addr_idx;
++	if (!(drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
++	      drvdata->addr_type[idx] == ETM_ADDR_TYPE_SINGLE)) {
++		spin_unlock(&drvdata->spinlock);
++		return -EINVAL;
++	}
++
++	val = drvdata->addr_val[idx];
++	spin_unlock(&drvdata->spinlock);
++
++	return sprintf(buf, "%#lx\n", val);
++}
++
++static ssize_t addr_single_store(struct device *dev,
++				 struct device_attribute *attr,
++				 const char *buf, size_t size)
++{
++	u8 idx;
++	int ret;
++	unsigned long val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	ret = kstrtoul(buf, 16, &val);
++	if (ret)
++		return ret;
++
++	spin_lock(&drvdata->spinlock);
++	idx = drvdata->addr_idx;
++	if (!(drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
++	      drvdata->addr_type[idx] == ETM_ADDR_TYPE_SINGLE)) {
++		spin_unlock(&drvdata->spinlock);
++		return -EINVAL;
++	}
++
++	drvdata->addr_val[idx] = val;
++	drvdata->addr_type[idx] = ETM_ADDR_TYPE_SINGLE;
++	spin_unlock(&drvdata->spinlock);
++
++	return size;
++}
++static DEVICE_ATTR_RW(addr_single);
++
++static ssize_t addr_range_show(struct device *dev,
++			       struct device_attribute *attr, char *buf)
++{
++	u8 idx;
++	unsigned long val1, val2;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	spin_lock(&drvdata->spinlock);
++	idx = drvdata->addr_idx;
++	if (idx % 2 != 0) {
++		spin_unlock(&drvdata->spinlock);
++		return -EPERM;
++	}
++	if (!((drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE &&
++	       drvdata->addr_type[idx + 1] == ETM_ADDR_TYPE_NONE) ||
++	      (drvdata->addr_type[idx] == ETM_ADDR_TYPE_RANGE &&
++	       drvdata->addr_type[idx + 1] == ETM_ADDR_TYPE_RANGE))) {
++		spin_unlock(&drvdata->spinlock);
++		return -EPERM;
++	}
++
++	val1 = drvdata->addr_val[idx];
++	val2 = drvdata->addr_val[idx + 1];
++	spin_unlock(&drvdata->spinlock);
++
++	return sprintf(buf, "%#lx %#lx\n", val1, val2);
++}
++
++static ssize_t addr_range_store(struct device *dev,
++			      struct device_attribute *attr,
++			      const char *buf, size_t size)
++{
++	u8 idx;
++	unsigned long val1, val2;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	if (sscanf(buf, "%lx %lx", &val1, &val2) != 2)
++		return -EINVAL;
++	/* Lower address comparator cannot have a higher address value */
++	if (val1 > val2)
++		return -EINVAL;
++
++	spin_lock(&drvdata->spinlock);
++	idx = drvdata->addr_idx;
++	if (idx % 2 != 0) {
++		spin_unlock(&drvdata->spinlock);
++		return -EPERM;
++	}
++	if (!((drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE &&
++	       drvdata->addr_type[idx + 1] == ETM_ADDR_TYPE_NONE) ||
++	      (drvdata->addr_type[idx] == ETM_ADDR_TYPE_RANGE &&
++	       drvdata->addr_type[idx + 1] == ETM_ADDR_TYPE_RANGE))) {
++		spin_unlock(&drvdata->spinlock);
++		return -EPERM;
++	}
++
++	drvdata->addr_val[idx] = val1;
++	drvdata->addr_type[idx] = ETM_ADDR_TYPE_RANGE;
++	drvdata->addr_val[idx + 1] = val2;
++	drvdata->addr_type[idx + 1] = ETM_ADDR_TYPE_RANGE;
++	drvdata->enable_ctrl1 |= (1 << (idx/2));
++	spin_unlock(&drvdata->spinlock);
++
++	return size;
++}
++static DEVICE_ATTR_RW(addr_range);
++
++static ssize_t addr_start_show(struct device *dev,
++			       struct device_attribute *attr, char *buf)
++{
++	u8 idx;
++	unsigned long val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	spin_lock(&drvdata->spinlock);
++	idx = drvdata->addr_idx;
++	if (!(drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
++	      drvdata->addr_type[idx] == ETM_ADDR_TYPE_START)) {
++		spin_unlock(&drvdata->spinlock);
++		return -EPERM;
++	}
++
++	val = drvdata->addr_val[idx];
++	spin_unlock(&drvdata->spinlock);
++
++	return sprintf(buf, "%#lx\n", val);
++}
++
++static ssize_t addr_start_store(struct device *dev,
++				struct device_attribute *attr,
++				const char *buf, size_t size)
++{
++	u8 idx;
++	int ret;
++	unsigned long val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	ret = kstrtoul(buf, 16, &val);
++	if (ret)
++		return ret;
++
++	spin_lock(&drvdata->spinlock);
++	idx = drvdata->addr_idx;
++	if (!(drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
++	      drvdata->addr_type[idx] == ETM_ADDR_TYPE_START)) {
++		spin_unlock(&drvdata->spinlock);
++		return -EPERM;
++	}
++
++	drvdata->addr_val[idx] = val;
++	drvdata->addr_type[idx] = ETM_ADDR_TYPE_START;
++	drvdata->startstop_ctrl |= (1 << idx);
++	drvdata->enable_ctrl1 |= BIT(25);
++	spin_unlock(&drvdata->spinlock);
++
++	return size;
++}
++static DEVICE_ATTR_RW(addr_start);
++
++static ssize_t addr_stop_show(struct device *dev,
++			      struct device_attribute *attr, char *buf)
++{
++	u8 idx;
++	unsigned long val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	spin_lock(&drvdata->spinlock);
++	idx = drvdata->addr_idx;
++	if (!(drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
++	      drvdata->addr_type[idx] == ETM_ADDR_TYPE_STOP)) {
++		spin_unlock(&drvdata->spinlock);
++		return -EPERM;
++	}
++
++	val = drvdata->addr_val[idx];
++	spin_unlock(&drvdata->spinlock);
++
++	return sprintf(buf, "%#lx\n", val);
++}
++
++static ssize_t addr_stop_store(struct device *dev,
++			       struct device_attribute *attr,
++			       const char *buf, size_t size)
++{
++	u8 idx;
++	int ret;
++	unsigned long val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	ret = kstrtoul(buf, 16, &val);
++	if (ret)
++		return ret;
++
++	spin_lock(&drvdata->spinlock);
++	idx = drvdata->addr_idx;
++	if (!(drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
++	      drvdata->addr_type[idx] == ETM_ADDR_TYPE_STOP)) {
++		spin_unlock(&drvdata->spinlock);
++		return -EPERM;
++	}
++
++	drvdata->addr_val[idx] = val;
++	drvdata->addr_type[idx] = ETM_ADDR_TYPE_STOP;
++	drvdata->startstop_ctrl |= (1 << (idx + 16));
++	drvdata->enable_ctrl1 |= ETMTECR1_START_STOP;
++	spin_unlock(&drvdata->spinlock);
++
++	return size;
++}
++static DEVICE_ATTR_RW(addr_stop);
++
++static ssize_t addr_acctype_show(struct device *dev,
++				 struct device_attribute *attr, char *buf)
++{
++	unsigned long val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	spin_lock(&drvdata->spinlock);
++	val = drvdata->addr_acctype[drvdata->addr_idx];
++	spin_unlock(&drvdata->spinlock);
++
++	return sprintf(buf, "%#lx\n", val);
++}
++
++static ssize_t addr_acctype_store(struct device *dev,
++				  struct device_attribute *attr,
++				  const char *buf, size_t size)
++{
++	int ret;
++	unsigned long val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	ret = kstrtoul(buf, 16, &val);
++	if (ret)
++		return ret;
++
++	spin_lock(&drvdata->spinlock);
++	drvdata->addr_acctype[drvdata->addr_idx] = val;
++	spin_unlock(&drvdata->spinlock);
++
++	return size;
++}
++static DEVICE_ATTR_RW(addr_acctype);
++
++static ssize_t cntr_idx_show(struct device *dev,
++			     struct device_attribute *attr, char *buf)
++{
++	unsigned long val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	val = drvdata->cntr_idx;
++	return sprintf(buf, "%#lx\n", val);
++}
++
++static ssize_t cntr_idx_store(struct device *dev,
++			      struct device_attribute *attr,
++			      const char *buf, size_t size)
++{
++	int ret;
++	unsigned long val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	ret = kstrtoul(buf, 16, &val);
++	if (ret)
++		return ret;
++
++	if (val >= drvdata->nr_cntr)
++		return -EINVAL;
++	/*
++	 * Use spinlock to ensure index doesn't change while it gets
++	 * dereferenced multiple times within a spinlock block elsewhere.
++	 */
++	spin_lock(&drvdata->spinlock);
++	drvdata->cntr_idx = val;
++	spin_unlock(&drvdata->spinlock);
++
++	return size;
++}
++static DEVICE_ATTR_RW(cntr_idx);
++
++static ssize_t cntr_rld_val_show(struct device *dev,
++				 struct device_attribute *attr, char *buf)
++{
++	unsigned long val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	spin_lock(&drvdata->spinlock);
++	val = drvdata->cntr_rld_val[drvdata->cntr_idx];
++	spin_unlock(&drvdata->spinlock);
++
++	return sprintf(buf, "%#lx\n", val);
++}
++
++static ssize_t cntr_rld_val_store(struct device *dev,
++				  struct device_attribute *attr,
++				  const char *buf, size_t size)
++{
++	int ret;
++	unsigned long val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	ret = kstrtoul(buf, 16, &val);
++	if (ret)
++		return ret;
++
++	spin_lock(&drvdata->spinlock);
++	drvdata->cntr_rld_val[drvdata->cntr_idx] = val;
++	spin_unlock(&drvdata->spinlock);
++
++	return size;
++}
++static DEVICE_ATTR_RW(cntr_rld_val);
++
++static ssize_t cntr_event_show(struct device *dev,
++			       struct device_attribute *attr, char *buf)
++{
++	unsigned long val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	spin_lock(&drvdata->spinlock);
++	val = drvdata->cntr_event[drvdata->cntr_idx];
++	spin_unlock(&drvdata->spinlock);
++
++	return sprintf(buf, "%#lx\n", val);
++}
++
++static ssize_t cntr_event_store(struct device *dev,
++				struct device_attribute *attr,
++				const char *buf, size_t size)
++{
++	int ret;
++	unsigned long val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	ret = kstrtoul(buf, 16, &val);
++	if (ret)
++		return ret;
++
++	spin_lock(&drvdata->spinlock);
++	drvdata->cntr_event[drvdata->cntr_idx] = val & ETM_EVENT_MASK;
++	spin_unlock(&drvdata->spinlock);
++
++	return size;
++}
++static DEVICE_ATTR_RW(cntr_event);
++
++static ssize_t cntr_rld_event_show(struct device *dev,
++				   struct device_attribute *attr, char *buf)
++{
++	unsigned long val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	spin_lock(&drvdata->spinlock);
++	val = drvdata->cntr_rld_event[drvdata->cntr_idx];
++	spin_unlock(&drvdata->spinlock);
++
++	return sprintf(buf, "%#lx\n", val);
++}
++
++static ssize_t cntr_rld_event_store(struct device *dev,
++				    struct device_attribute *attr,
++				    const char *buf, size_t size)
++{
++	int ret;
++	unsigned long val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	ret = kstrtoul(buf, 16, &val);
++	if (ret)
++		return ret;
++
++	spin_lock(&drvdata->spinlock);
++	drvdata->cntr_rld_event[drvdata->cntr_idx] = val & ETM_EVENT_MASK;
++	spin_unlock(&drvdata->spinlock);
++
++	return size;
++}
++static DEVICE_ATTR_RW(cntr_rld_event);
++
++static ssize_t cntr_val_show(struct device *dev,
++			     struct device_attribute *attr, char *buf)
++{
++	int i, ret = 0;
++	u32 val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	if (!drvdata->enable) {
++		spin_lock(&drvdata->spinlock);
++		for (i = 0; i < drvdata->nr_cntr; i++)
++			ret += sprintf(buf, "counter %d: %x\n",
++				       i, drvdata->cntr_val[i]);
++		spin_unlock(&drvdata->spinlock);
++		return ret;
++	}
++
++	for (i = 0; i < drvdata->nr_cntr; i++) {
++		val = etm_readl(drvdata, ETMCNTVRn(i));
++		ret += sprintf(buf, "counter %d: %x\n", i, val);
++	}
++
++	return ret;
++}
++
++static ssize_t cntr_val_store(struct device *dev,
++			      struct device_attribute *attr,
++			      const char *buf, size_t size)
++{
++	int ret;
++	unsigned long val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	ret = kstrtoul(buf, 16, &val);
++	if (ret)
++		return ret;
++
++	spin_lock(&drvdata->spinlock);
++	drvdata->cntr_val[drvdata->cntr_idx] = val;
++	spin_unlock(&drvdata->spinlock);
++
++	return size;
++}
++static DEVICE_ATTR_RW(cntr_val);
++
++static ssize_t seq_12_event_show(struct device *dev,
++				 struct device_attribute *attr, char *buf)
++{
++	unsigned long val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	val = drvdata->seq_12_event;
++	return sprintf(buf, "%#lx\n", val);
++}
++
++static ssize_t seq_12_event_store(struct device *dev,
++				  struct device_attribute *attr,
++				  const char *buf, size_t size)
++{
++	int ret;
++	unsigned long val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	ret = kstrtoul(buf, 16, &val);
++	if (ret)
++		return ret;
++
++	drvdata->seq_12_event = val & ETM_EVENT_MASK;
++	return size;
++}
++static DEVICE_ATTR_RW(seq_12_event);
++
++static ssize_t seq_21_event_show(struct device *dev,
++				 struct device_attribute *attr, char *buf)
++{
++	unsigned long val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	val = drvdata->seq_21_event;
++	return sprintf(buf, "%#lx\n", val);
++}
++
++static ssize_t seq_21_event_store(struct device *dev,
++				  struct device_attribute *attr,
++				  const char *buf, size_t size)
++{
++	int ret;
++	unsigned long val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	ret = kstrtoul(buf, 16, &val);
++	if (ret)
++		return ret;
++
++	drvdata->seq_21_event = val & ETM_EVENT_MASK;
++	return size;
++}
++static DEVICE_ATTR_RW(seq_21_event);
++
++static ssize_t seq_23_event_show(struct device *dev,
++				 struct device_attribute *attr, char *buf)
++{
++	unsigned long val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	val = drvdata->seq_23_event;
++	return sprintf(buf, "%#lx\n", val);
++}
++
++static ssize_t seq_23_event_store(struct device *dev,
++				  struct device_attribute *attr,
++				  const char *buf, size_t size)
++{
++	int ret;
++	unsigned long val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	ret = kstrtoul(buf, 16, &val);
++	if (ret)
++		return ret;
++
++	drvdata->seq_23_event = val & ETM_EVENT_MASK;
++	return size;
++}
++static DEVICE_ATTR_RW(seq_23_event);
++
++static ssize_t seq_31_event_show(struct device *dev,
++				 struct device_attribute *attr, char *buf)
++{
++	unsigned long val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	val = drvdata->seq_31_event;
++	return sprintf(buf, "%#lx\n", val);
++}
++
++static ssize_t seq_31_event_store(struct device *dev,
++				  struct device_attribute *attr,
++				  const char *buf, size_t size)
++{
++	int ret;
++	unsigned long val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	ret = kstrtoul(buf, 16, &val);
++	if (ret)
++		return ret;
++
++	drvdata->seq_31_event = val & ETM_EVENT_MASK;
++	return size;
++}
++static DEVICE_ATTR_RW(seq_31_event);
++
++static ssize_t seq_32_event_show(struct device *dev,
++				 struct device_attribute *attr, char *buf)
++{
++	unsigned long val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	val = drvdata->seq_32_event;
++	return sprintf(buf, "%#lx\n", val);
++}
++
++static ssize_t seq_32_event_store(struct device *dev,
++				  struct device_attribute *attr,
++				  const char *buf, size_t size)
++{
++	int ret;
++	unsigned long val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	ret = kstrtoul(buf, 16, &val);
++	if (ret)
++		return ret;
++
++	drvdata->seq_32_event = val & ETM_EVENT_MASK;
++	return size;
++}
++static DEVICE_ATTR_RW(seq_32_event);
++
++static ssize_t seq_13_event_show(struct device *dev,
++				 struct device_attribute *attr, char *buf)
++{
++	unsigned long val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	val = drvdata->seq_13_event;
++	return sprintf(buf, "%#lx\n", val);
++}
++
++static ssize_t seq_13_event_store(struct device *dev,
++				  struct device_attribute *attr,
++				  const char *buf, size_t size)
++{
++	int ret;
++	unsigned long val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	ret = kstrtoul(buf, 16, &val);
++	if (ret)
++		return ret;
++
++	drvdata->seq_13_event = val & ETM_EVENT_MASK;
++	return size;
++}
++static DEVICE_ATTR_RW(seq_13_event);
++
++static ssize_t seq_curr_state_show(struct device *dev,
++				   struct device_attribute *attr, char *buf)
++{
++	int ret;
++	unsigned long val, flags;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	if (!drvdata->enable) {
++		val = drvdata->seq_curr_state;
++		goto out;
++	}
++
++	ret = clk_prepare_enable(drvdata->clk);
++	if (ret)
++		return ret;
++
++	spin_lock_irqsave(&drvdata->spinlock, flags);
++
++	CS_UNLOCK(drvdata->base);
++	val = (etm_readl(drvdata, ETMSQR) & ETM_SQR_MASK);
++	CS_LOCK(drvdata->base);
++
++	spin_unlock_irqrestore(&drvdata->spinlock, flags);
++	clk_disable_unprepare(drvdata->clk);
++out:
++	return sprintf(buf, "%#lx\n", val);
++}
++
++static ssize_t seq_curr_state_store(struct device *dev,
++				    struct device_attribute *attr,
++				    const char *buf, size_t size)
++{
++	int ret;
++	unsigned long val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	ret = kstrtoul(buf, 16, &val);
++	if (ret)
++		return ret;
++
++	if (val > ETM_SEQ_STATE_MAX_VAL)
++		return -EINVAL;
++
++	drvdata->seq_curr_state = val;
++
++	return size;
++}
++static DEVICE_ATTR_RW(seq_curr_state);
++
++static ssize_t ctxid_idx_show(struct device *dev,
++			      struct device_attribute *attr, char *buf)
++{
++	unsigned long val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	val = drvdata->ctxid_idx;
++	return sprintf(buf, "%#lx\n", val);
++}
++
++static ssize_t ctxid_idx_store(struct device *dev,
++				struct device_attribute *attr,
++				const char *buf, size_t size)
++{
++	int ret;
++	unsigned long val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	ret = kstrtoul(buf, 16, &val);
++	if (ret)
++		return ret;
++
++	if (val >= drvdata->nr_ctxid_cmp)
++		return -EINVAL;
++
++	/*
++	 * Use spinlock to ensure index doesn't change while it gets
++	 * dereferenced multiple times within a spinlock block elsewhere.
++	 */
++	spin_lock(&drvdata->spinlock);
++	drvdata->ctxid_idx = val;
++	spin_unlock(&drvdata->spinlock);
++
++	return size;
++}
++static DEVICE_ATTR_RW(ctxid_idx);
++
++static ssize_t ctxid_val_show(struct device *dev,
++			      struct device_attribute *attr, char *buf)
++{
++	unsigned long val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	spin_lock(&drvdata->spinlock);
++	val = drvdata->ctxid_val[drvdata->ctxid_idx];
++	spin_unlock(&drvdata->spinlock);
++
++	return sprintf(buf, "%#lx\n", val);
++}
++
++static ssize_t ctxid_val_store(struct device *dev,
++			       struct device_attribute *attr,
++			       const char *buf, size_t size)
++{
++	int ret;
++	unsigned long val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	ret = kstrtoul(buf, 16, &val);
++	if (ret)
++		return ret;
++
++	spin_lock(&drvdata->spinlock);
++	drvdata->ctxid_val[drvdata->ctxid_idx] = val;
++	spin_unlock(&drvdata->spinlock);
++
++	return size;
++}
++static DEVICE_ATTR_RW(ctxid_val);
++
++static ssize_t ctxid_mask_show(struct device *dev,
++			       struct device_attribute *attr, char *buf)
++{
++	unsigned long val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	val = drvdata->ctxid_mask;
++	return sprintf(buf, "%#lx\n", val);
++}
++
++static ssize_t ctxid_mask_store(struct device *dev,
++				struct device_attribute *attr,
++				const char *buf, size_t size)
++{
++	int ret;
++	unsigned long val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	ret = kstrtoul(buf, 16, &val);
++	if (ret)
++		return ret;
++
++	drvdata->ctxid_mask = val;
++	return size;
++}
++static DEVICE_ATTR_RW(ctxid_mask);
++
++static ssize_t sync_freq_show(struct device *dev,
++			      struct device_attribute *attr, char *buf)
++{
++	unsigned long val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	val = drvdata->sync_freq;
++	return sprintf(buf, "%#lx\n", val);
++}
++
++static ssize_t sync_freq_store(struct device *dev,
++			       struct device_attribute *attr,
++			       const char *buf, size_t size)
++{
++	int ret;
++	unsigned long val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	ret = kstrtoul(buf, 16, &val);
++	if (ret)
++		return ret;
++
++	drvdata->sync_freq = val & ETM_SYNC_MASK;
++	return size;
++}
++static DEVICE_ATTR_RW(sync_freq);
++
++static ssize_t timestamp_event_show(struct device *dev,
++				    struct device_attribute *attr, char *buf)
++{
++	unsigned long val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	val = drvdata->timestamp_event;
++	return sprintf(buf, "%#lx\n", val);
++}
++
++static ssize_t timestamp_event_store(struct device *dev,
++				     struct device_attribute *attr,
++				     const char *buf, size_t size)
++{
++	int ret;
++	unsigned long val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	ret = kstrtoul(buf, 16, &val);
++	if (ret)
++		return ret;
++
++	drvdata->timestamp_event = val & ETM_EVENT_MASK;
++	return size;
++}
++static DEVICE_ATTR_RW(timestamp_event);
++
++static ssize_t status_show(struct device *dev,
++			   struct device_attribute *attr, char *buf)
++{
++	int ret;
++	unsigned long flags;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	ret = clk_prepare_enable(drvdata->clk);
++	if (ret)
++		return ret;
++
++	spin_lock_irqsave(&drvdata->spinlock, flags);
++
++	CS_UNLOCK(drvdata->base);
++	ret = sprintf(buf,
++		      "ETMCCR: 0x%08x\n"
++		      "ETMCCER: 0x%08x\n"
++		      "ETMSCR: 0x%08x\n"
++		      "ETMIDR: 0x%08x\n"
++		      "ETMCR: 0x%08x\n"
++		      "ETMTRACEIDR: 0x%08x\n"
++		      "Enable event: 0x%08x\n"
++		      "Enable start/stop: 0x%08x\n"
++		      "Enable control: CR1 0x%08x CR2 0x%08x\n"
++		      "CPU affinity: %d\n",
++		      drvdata->etmccr, drvdata->etmccer,
++		      etm_readl(drvdata, ETMSCR), etm_readl(drvdata, ETMIDR),
++		      etm_readl(drvdata, ETMCR), etm_trace_id_simple(drvdata),
++		      etm_readl(drvdata, ETMTEEVR),
++		      etm_readl(drvdata, ETMTSSCR),
++		      etm_readl(drvdata, ETMTECR1),
++		      etm_readl(drvdata, ETMTECR2),
++		      drvdata->cpu);
++	CS_LOCK(drvdata->base);
++
++	spin_unlock_irqrestore(&drvdata->spinlock, flags);
++	clk_disable_unprepare(drvdata->clk);
++
++	return ret;
++}
++static DEVICE_ATTR_RO(status);
++
++static ssize_t traceid_show(struct device *dev,
++			    struct device_attribute *attr, char *buf)
++{
++	int ret;
++	unsigned long val, flags;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	if (!drvdata->enable) {
++		val = drvdata->traceid;
++		goto out;
++	}
++
++	ret = clk_prepare_enable(drvdata->clk);
++	if (ret)
++		return ret;
++
++	spin_lock_irqsave(&drvdata->spinlock, flags);
++	CS_UNLOCK(drvdata->base);
++
++	val = (etm_readl(drvdata, ETMTRACEIDR) & ETM_TRACEID_MASK);
++
++	CS_LOCK(drvdata->base);
++	spin_unlock_irqrestore(&drvdata->spinlock, flags);
++	clk_disable_unprepare(drvdata->clk);
++out:
++	return sprintf(buf, "%#lx\n", val);
++}
++
++static ssize_t traceid_store(struct device *dev,
++			     struct device_attribute *attr,
++			     const char *buf, size_t size)
++{
++	int ret;
++	unsigned long val;
++	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	ret = kstrtoul(buf, 16, &val);
++	if (ret)
++		return ret;
++
++	drvdata->traceid = val & ETM_TRACEID_MASK;
++	return size;
++}
++static DEVICE_ATTR_RW(traceid);
++
++static struct attribute *coresight_etm_attrs[] = {
++	&dev_attr_nr_addr_cmp.attr,
++	&dev_attr_nr_cntr.attr,
++	&dev_attr_nr_ctxid_cmp.attr,
++	&dev_attr_etmsr.attr,
++	&dev_attr_reset.attr,
++	&dev_attr_mode.attr,
++	&dev_attr_trigger_event.attr,
++	&dev_attr_enable_event.attr,
++	&dev_attr_fifofull_level.attr,
++	&dev_attr_addr_idx.attr,
++	&dev_attr_addr_single.attr,
++	&dev_attr_addr_range.attr,
++	&dev_attr_addr_start.attr,
++	&dev_attr_addr_stop.attr,
++	&dev_attr_addr_acctype.attr,
++	&dev_attr_cntr_idx.attr,
++	&dev_attr_cntr_rld_val.attr,
++	&dev_attr_cntr_event.attr,
++	&dev_attr_cntr_rld_event.attr,
++	&dev_attr_cntr_val.attr,
++	&dev_attr_seq_12_event.attr,
++	&dev_attr_seq_21_event.attr,
++	&dev_attr_seq_23_event.attr,
++	&dev_attr_seq_31_event.attr,
++	&dev_attr_seq_32_event.attr,
++	&dev_attr_seq_13_event.attr,
++	&dev_attr_seq_curr_state.attr,
++	&dev_attr_ctxid_idx.attr,
++	&dev_attr_ctxid_val.attr,
++	&dev_attr_ctxid_mask.attr,
++	&dev_attr_sync_freq.attr,
++	&dev_attr_timestamp_event.attr,
++	&dev_attr_status.attr,
++	&dev_attr_traceid.attr,
++	NULL,
++};
++ATTRIBUTE_GROUPS(coresight_etm);
++
++static int etm_cpu_callback(struct notifier_block *nfb, unsigned long action,
++			    void *hcpu)
++{
++	unsigned int cpu = (unsigned long)hcpu;
++
++	if (!etmdrvdata[cpu])
++		goto out;
++
++	switch (action & (~CPU_TASKS_FROZEN)) {
++	case CPU_STARTING:
++		spin_lock(&etmdrvdata[cpu]->spinlock);
++		if (!etmdrvdata[cpu]->os_unlock) {
++			etm_os_unlock(etmdrvdata[cpu]);
++			etmdrvdata[cpu]->os_unlock = true;
++		}
++
++		if (etmdrvdata[cpu]->enable)
++			etm_enable_hw(etmdrvdata[cpu]);
++		spin_unlock(&etmdrvdata[cpu]->spinlock);
++		break;
++
++	case CPU_ONLINE:
++		if (etmdrvdata[cpu]->boot_enable &&
++		    !etmdrvdata[cpu]->sticky_enable)
++			coresight_enable(etmdrvdata[cpu]->csdev);
++		break;
++
++	case CPU_DYING:
++		spin_lock(&etmdrvdata[cpu]->spinlock);
++		if (etmdrvdata[cpu]->enable)
++			etm_disable_hw(etmdrvdata[cpu]);
++		spin_unlock(&etmdrvdata[cpu]->spinlock);
++		break;
++	}
++out:
++	return NOTIFY_OK;
++}
++
++static struct notifier_block etm_cpu_notifier = {
++	.notifier_call = etm_cpu_callback,
++};
++
++static bool etm_arch_supported(u8 arch)
++{
++	switch (arch) {
++	case ETM_ARCH_V3_3:
++		break;
++	case ETM_ARCH_V3_5:
++		break;
++	case PFT_ARCH_V1_0:
++		break;
++	case PFT_ARCH_V1_1:
++		break;
++	default:
++		return false;
++	}
++	return true;
++}
++
++static void etm_init_arch_data(void *info)
++{
++	u32 etmidr;
++	u32 etmccr;
++	struct etm_drvdata *drvdata = info;
++
++	CS_UNLOCK(drvdata->base);
++
++	/* First dummy read */
++	(void)etm_readl(drvdata, ETMPDSR);
++	/* Provide power to ETM: ETMPDCR[3] == 1 */
++	etm_set_pwrup(drvdata);
++	/*
++	 * Clear power down bit since when this bit is set writes to
++	 * certain registers might be ignored.
++	 */
++	etm_clr_pwrdwn(drvdata);
++	/*
++	 * Set prog bit. It will be set from reset but this is included to
++	 * ensure it is set
++	 */
++	etm_set_prog(drvdata);
++
++	/* Find all capabilities */
++	etmidr = etm_readl(drvdata, ETMIDR);
++	drvdata->arch = BMVAL(etmidr, 4, 11);
++	drvdata->port_size = etm_readl(drvdata, ETMCR) & PORT_SIZE_MASK;
++
++	drvdata->etmccer = etm_readl(drvdata, ETMCCER);
++	etmccr = etm_readl(drvdata, ETMCCR);
++	drvdata->etmccr = etmccr;
++	drvdata->nr_addr_cmp = BMVAL(etmccr, 0, 3) * 2;
++	drvdata->nr_cntr = BMVAL(etmccr, 13, 15);
++	drvdata->nr_ext_inp = BMVAL(etmccr, 17, 19);
++	drvdata->nr_ext_out = BMVAL(etmccr, 20, 22);
++	drvdata->nr_ctxid_cmp = BMVAL(etmccr, 24, 25);
++
++	etm_set_pwrdwn(drvdata);
++	etm_clr_pwrup(drvdata);
++	CS_LOCK(drvdata->base);
++}
++
++static void etm_init_default_data(struct etm_drvdata *drvdata)
++{
++	/*
++	 * A trace ID of value 0 is invalid, so let's start at some
++	 * random value that fits in 7 bits and will be just as good.
++	 */
++	static int etm3x_traceid = 0x10;
++
++	u32 flags = (1 << 0 | /* instruction execute*/
++		     3 << 3 | /* ARM instruction */
++		     0 << 5 | /* No data value comparison */
++		     0 << 7 | /* No exact mach */
++		     0 << 8 | /* Ignore context ID */
++		     0 << 10); /* Security ignored */
++
++	/*
++	 * Initial configuration only - guarantees sources handled by
++	 * this driver have a unique ID at startup time but not between
++	 * all other types of sources.  For that we lean on the core
++	 * framework.
++	 */
++	drvdata->traceid = etm3x_traceid++;
++	drvdata->ctrl = (ETMCR_CYC_ACC | ETMCR_TIMESTAMP_EN);
++	drvdata->enable_ctrl1 = ETMTECR1_ADDR_COMP_1;
++	if (drvdata->nr_addr_cmp >= 2) {
++		drvdata->addr_val[0] = (u32) _stext;
++		drvdata->addr_val[1] = (u32) _etext;
++		drvdata->addr_acctype[0] = flags;
++		drvdata->addr_acctype[1] = flags;
++		drvdata->addr_type[0] = ETM_ADDR_TYPE_RANGE;
++		drvdata->addr_type[1] = ETM_ADDR_TYPE_RANGE;
++	}
++
++	etm_set_default(drvdata);
++}
++
++static int etm_probe(struct amba_device *adev, const struct amba_id *id)
++{
++	int ret;
++	void __iomem *base;
++	struct device *dev = &adev->dev;
++	struct coresight_platform_data *pdata = NULL;
++	struct etm_drvdata *drvdata;
++	struct resource *res = &adev->res;
++	struct coresight_desc *desc;
++	struct device_node *np = adev->dev.of_node;
++
++	desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
++	if (!desc)
++		return -ENOMEM;
++
++	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
++	if (!drvdata)
++		return -ENOMEM;
++
++	if (np) {
++		pdata = of_get_coresight_platform_data(dev, np);
++		if (IS_ERR(pdata))
++			return PTR_ERR(pdata);
++
++		adev->dev.platform_data = pdata;
++		drvdata->use_cp14 = of_property_read_bool(np, "arm,cp14");
++	}
++
++	drvdata->dev = &adev->dev;
++	dev_set_drvdata(dev, drvdata);
++
++	/* Validity for the resource is already checked by the AMBA core */
++	base = devm_ioremap_resource(dev, res);
++	if (IS_ERR(base))
++		return PTR_ERR(base);
++
++	drvdata->base = base;
++
++	spin_lock_init(&drvdata->spinlock);
++
++	drvdata->clk = adev->pclk;
++	ret = clk_prepare_enable(drvdata->clk);
++	if (ret)
++		return ret;
++
++	drvdata->cpu = pdata ? pdata->cpu : 0;
++
++	get_online_cpus();
++	etmdrvdata[drvdata->cpu] = drvdata;
++
++	if (!smp_call_function_single(drvdata->cpu, etm_os_unlock, drvdata, 1))
++		drvdata->os_unlock = true;
++
++	if (smp_call_function_single(drvdata->cpu,
++				     etm_init_arch_data,  drvdata, 1))
++		dev_err(dev, "ETM arch init failed\n");
++
++	if (!etm_count++)
++		register_hotcpu_notifier(&etm_cpu_notifier);
++
++	put_online_cpus();
++
++	if (etm_arch_supported(drvdata->arch) == false) {
++		ret = -EINVAL;
++		goto err_arch_supported;
++	}
++	etm_init_default_data(drvdata);
++
++	clk_disable_unprepare(drvdata->clk);
++
++	desc->type = CORESIGHT_DEV_TYPE_SOURCE;
++	desc->subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_PROC;
++	desc->ops = &etm_cs_ops;
++	desc->pdata = pdata;
++	desc->dev = dev;
++	desc->groups = coresight_etm_groups;
++	drvdata->csdev = coresight_register(desc);
++	if (IS_ERR(drvdata->csdev)) {
++		ret = PTR_ERR(drvdata->csdev);
++		goto err_arch_supported;
++	}
++
++	dev_info(dev, "ETM initialized\n");
++
++	if (boot_enable) {
++		coresight_enable(drvdata->csdev);
++		drvdata->boot_enable = true;
++	}
++
++	return 0;
++
++err_arch_supported:
++	clk_disable_unprepare(drvdata->clk);
++	if (--etm_count == 0)
++		unregister_hotcpu_notifier(&etm_cpu_notifier);
++	return ret;
++}
++
++static int etm_remove(struct amba_device *adev)
++{
++	struct etm_drvdata *drvdata = amba_get_drvdata(adev);
++
++	coresight_unregister(drvdata->csdev);
++	if (--etm_count == 0)
++		unregister_hotcpu_notifier(&etm_cpu_notifier);
++
++	return 0;
++}
++
++static struct amba_id etm_ids[] = {
++	{	/* ETM 3.3 */
++		.id	= 0x0003b921,
++		.mask	= 0x0003ffff,
++	},
++	{	/* ETM 3.5 */
++		.id	= 0x0003b956,
++		.mask	= 0x0003ffff,
++	},
++	{	/* PTM 1.0 */
++		.id	= 0x0003b950,
++		.mask	= 0x0003ffff,
++	},
++	{	/* PTM 1.1 */
++		.id	= 0x0003b95f,
++		.mask	= 0x0003ffff,
++	},
++	{ 0, 0},
++};
++
++static struct amba_driver etm_driver = {
++	.drv = {
++		.name	= "coresight-etm3x",
++		.owner	= THIS_MODULE,
++	},
++	.probe		= etm_probe,
++	.remove		= etm_remove,
++	.id_table	= etm_ids,
++};
++
++int __init etm_init(void)
++{
++	return amba_driver_register(&etm_driver);
++}
++module_init(etm_init);
++
++void __exit etm_exit(void)
++{
++	amba_driver_unregister(&etm_driver);
++}
++module_exit(etm_exit);
++
++MODULE_LICENSE("GPL v2");
++MODULE_DESCRIPTION("CoreSight Program Flow Trace driver");
+diff --git a/drivers/hwtracing/coresight/coresight-funnel.c b/drivers/hwtracing/coresight/coresight-funnel.c
+new file mode 100644
+index 0000000..3db36f7
+--- /dev/null
++++ b/drivers/hwtracing/coresight/coresight-funnel.c
+@@ -0,0 +1,258 @@
++/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/types.h>
++#include <linux/device.h>
++#include <linux/err.h>
++#include <linux/fs.h>
++#include <linux/slab.h>
++#include <linux/clk.h>
++#include <linux/coresight.h>
++#include <linux/amba/bus.h>
++
++#include "coresight-priv.h"
++
++#define FUNNEL_FUNCTL		0x000
++#define FUNNEL_PRICTL		0x004
++
++#define FUNNEL_HOLDTIME_MASK	0xf00
++#define FUNNEL_HOLDTIME_SHFT	0x8
++#define FUNNEL_HOLDTIME		(0x7 << FUNNEL_HOLDTIME_SHFT)
++
++/**
++ * struct funnel_drvdata - specifics associated to a funnel component
++ * @base:	memory mapped base address for this component.
++ * @dev:	the device entity associated to this component.
++ * @csdev:	component vitals needed by the framework.
++ * @clk:	the clock this component is associated to.
++ * @priority:	port selection order.
++ */
++struct funnel_drvdata {
++	void __iomem		*base;
++	struct device		*dev;
++	struct coresight_device	*csdev;
++	struct clk		*clk;
++	unsigned long		priority;
++};
++
++static void funnel_enable_hw(struct funnel_drvdata *drvdata, int port)
++{
++	u32 functl;
++
++	CS_UNLOCK(drvdata->base);
++
++	functl = readl_relaxed(drvdata->base + FUNNEL_FUNCTL);
++	functl &= ~FUNNEL_HOLDTIME_MASK;
++	functl |= FUNNEL_HOLDTIME;
++	functl |= (1 << port);
++	writel_relaxed(functl, drvdata->base + FUNNEL_FUNCTL);
++	writel_relaxed(drvdata->priority, drvdata->base + FUNNEL_PRICTL);
++
++	CS_LOCK(drvdata->base);
++}
++
++static int funnel_enable(struct coresight_device *csdev, int inport,
++			 int outport)
++{
++	struct funnel_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
++	int ret;
++
++	ret = clk_prepare_enable(drvdata->clk);
++	if (ret)
++		return ret;
++
++	funnel_enable_hw(drvdata, inport);
++
++	dev_info(drvdata->dev, "FUNNEL inport %d enabled\n", inport);
++	return 0;
++}
++
++static void funnel_disable_hw(struct funnel_drvdata *drvdata, int inport)
++{
++	u32 functl;
++
++	CS_UNLOCK(drvdata->base);
++
++	functl = readl_relaxed(drvdata->base + FUNNEL_FUNCTL);
++	functl &= ~(1 << inport);
++	writel_relaxed(functl, drvdata->base + FUNNEL_FUNCTL);
++
++	CS_LOCK(drvdata->base);
++}
++
++static void funnel_disable(struct coresight_device *csdev, int inport,
++			   int outport)
++{
++	struct funnel_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
++
++	funnel_disable_hw(drvdata, inport);
++
++	clk_disable_unprepare(drvdata->clk);
++
++	dev_info(drvdata->dev, "FUNNEL inport %d disabled\n", inport);
++}
++
++static const struct coresight_ops_link funnel_link_ops = {
++	.enable		= funnel_enable,
++	.disable	= funnel_disable,
++};
++
++static const struct coresight_ops funnel_cs_ops = {
++	.link_ops	= &funnel_link_ops,
++};
++
++static ssize_t priority_show(struct device *dev,
++			     struct device_attribute *attr, char *buf)
++{
++	struct funnel_drvdata *drvdata = dev_get_drvdata(dev->parent);
++	unsigned long val = drvdata->priority;
++
++	return sprintf(buf, "%#lx\n", val);
++}
++
++static ssize_t priority_store(struct device *dev,
++			      struct device_attribute *attr,
++			      const char *buf, size_t size)
++{
++	int ret;
++	unsigned long val;
++	struct funnel_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	ret = kstrtoul(buf, 16, &val);
++	if (ret)
++		return ret;
++
++	drvdata->priority = val;
++	return size;
++}
++static DEVICE_ATTR_RW(priority);
++
++static u32 get_funnel_ctrl_hw(struct funnel_drvdata *drvdata)
++{
++	u32 functl;
++
++	CS_UNLOCK(drvdata->base);
++	functl = readl_relaxed(drvdata->base + FUNNEL_FUNCTL);
++	CS_LOCK(drvdata->base);
++
++	return functl;
++}
++
++static ssize_t funnel_ctrl_show(struct device *dev,
++			     struct device_attribute *attr, char *buf)
++{
++	int ret;
++	u32 val;
++	struct funnel_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	ret = clk_prepare_enable(drvdata->clk);
++	if (ret)
++		return ret;
++
++	val = get_funnel_ctrl_hw(drvdata);
++	clk_disable_unprepare(drvdata->clk);
++
++	return sprintf(buf, "%#x\n", val);
++}
++static DEVICE_ATTR_RO(funnel_ctrl);
++
++static struct attribute *coresight_funnel_attrs[] = {
++	&dev_attr_funnel_ctrl.attr,
++	&dev_attr_priority.attr,
++	NULL,
++};
++ATTRIBUTE_GROUPS(coresight_funnel);
++
++static int funnel_probe(struct amba_device *adev, const struct amba_id *id)
++{
++	void __iomem *base;
++	struct device *dev = &adev->dev;
++	struct coresight_platform_data *pdata = NULL;
++	struct funnel_drvdata *drvdata;
++	struct resource *res = &adev->res;
++	struct coresight_desc *desc;
++	struct device_node *np = adev->dev.of_node;
++
++	if (np) {
++		pdata = of_get_coresight_platform_data(dev, np);
++		if (IS_ERR(pdata))
++			return PTR_ERR(pdata);
++		adev->dev.platform_data = pdata;
++	}
++
++	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
++	if (!drvdata)
++		return -ENOMEM;
++
++	drvdata->dev = &adev->dev;
++	dev_set_drvdata(dev, drvdata);
++
++	/* Validity for the resource is already checked by the AMBA core */
++	base = devm_ioremap_resource(dev, res);
++	if (IS_ERR(base))
++		return PTR_ERR(base);
++
++	drvdata->base = base;
++
++	drvdata->clk = adev->pclk;
++
++	desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
++	if (!desc)
++		return -ENOMEM;
++
++	desc->type = CORESIGHT_DEV_TYPE_LINK;
++	desc->subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_MERG;
++	desc->ops = &funnel_cs_ops;
++	desc->pdata = pdata;
++	desc->dev = dev;
++	desc->groups = coresight_funnel_groups;
++	drvdata->csdev = coresight_register(desc);
++	if (IS_ERR(drvdata->csdev))
++		return PTR_ERR(drvdata->csdev);
++
++	dev_info(dev, "FUNNEL initialized\n");
++	return 0;
++}
++
++static int funnel_remove(struct amba_device *adev)
++{
++	struct funnel_drvdata *drvdata = amba_get_drvdata(adev);
++
++	coresight_unregister(drvdata->csdev);
++	return 0;
++}
++
++static struct amba_id funnel_ids[] = {
++	{
++		.id     = 0x0003b908,
++		.mask   = 0x0003ffff,
++	},
++	{ 0, 0},
++};
++
++static struct amba_driver funnel_driver = {
++	.drv = {
++		.name	= "coresight-funnel",
++		.owner	= THIS_MODULE,
++	},
++	.probe		= funnel_probe,
++	.remove		= funnel_remove,
++	.id_table	= funnel_ids,
++};
++
++module_amba_driver(funnel_driver);
++
++MODULE_LICENSE("GPL v2");
++MODULE_DESCRIPTION("CoreSight Funnel driver");
+diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h
+new file mode 100644
+index 0000000..62fcd98
+--- /dev/null
++++ b/drivers/hwtracing/coresight/coresight-priv.h
+@@ -0,0 +1,63 @@
++/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#ifndef _CORESIGHT_PRIV_H
++#define _CORESIGHT_PRIV_H
++
++#include <linux/bitops.h>
++#include <linux/io.h>
++#include <linux/coresight.h>
++
++/*
++ * Coresight management registers (0xf00-0xfcc)
++ * 0xfa0 - 0xfa4: Management	registers in PFTv1.0
++ *		  Trace		registers in PFTv1.1
++ */
++#define CORESIGHT_ITCTRL	0xf00
++#define CORESIGHT_CLAIMSET	0xfa0
++#define CORESIGHT_CLAIMCLR	0xfa4
++#define CORESIGHT_LAR		0xfb0
++#define CORESIGHT_LSR		0xfb4
++#define CORESIGHT_AUTHSTATUS	0xfb8
++#define CORESIGHT_DEVID		0xfc8
++#define CORESIGHT_DEVTYPE	0xfcc
++
++#define TIMEOUT_US		100
++#define BMVAL(val, lsb, msb)	((val & GENMASK(msb, lsb)) >> lsb)
++
++static inline void CS_LOCK(void __iomem *addr)
++{
++	do {
++		/* Wait for things to settle */
++		mb();
++		writel_relaxed(0x0, addr + CORESIGHT_LAR);
++	} while (0);
++}
++
++static inline void CS_UNLOCK(void __iomem *addr)
++{
++	do {
++		writel_relaxed(CORESIGHT_UNLOCK, addr + CORESIGHT_LAR);
++		/* Make sure everyone has seen this */
++		mb();
++	} while (0);
++}
++
++#ifdef CONFIG_CORESIGHT_SOURCE_ETM3X
++extern int etm_readl_cp14(u32 off, unsigned int *val);
++extern int etm_writel_cp14(u32 off, u32 val);
++#else
++static inline int etm_readl_cp14(u32 off, unsigned int *val) { return 0; }
++static inline int etm_writel_cp14(u32 off, u32 val) { return 0; }
++#endif
++
++#endif
+diff --git a/drivers/hwtracing/coresight/coresight-replicator.c b/drivers/hwtracing/coresight/coresight-replicator.c
+new file mode 100644
+index 0000000..cdf0553
+--- /dev/null
++++ b/drivers/hwtracing/coresight/coresight-replicator.c
+@@ -0,0 +1,137 @@
++/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/device.h>
++#include <linux/platform_device.h>
++#include <linux/io.h>
++#include <linux/err.h>
++#include <linux/slab.h>
++#include <linux/clk.h>
++#include <linux/of.h>
++#include <linux/coresight.h>
++
++#include "coresight-priv.h"
++
++/**
++ * struct replicator_drvdata - specifics associated to a replicator component
++ * @dev:	the device entity associated with this component
++ * @csdev:	component vitals needed by the framework
++ */
++struct replicator_drvdata {
++	struct device		*dev;
++	struct coresight_device	*csdev;
++};
++
++static int replicator_enable(struct coresight_device *csdev, int inport,
++			     int outport)
++{
++	struct replicator_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
++
++	dev_info(drvdata->dev, "REPLICATOR enabled\n");
++	return 0;
++}
++
++static void replicator_disable(struct coresight_device *csdev, int inport,
++			       int outport)
++{
++	struct replicator_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
++
++	dev_info(drvdata->dev, "REPLICATOR disabled\n");
++}
++
++static const struct coresight_ops_link replicator_link_ops = {
++	.enable		= replicator_enable,
++	.disable	= replicator_disable,
++};
++
++static const struct coresight_ops replicator_cs_ops = {
++	.link_ops	= &replicator_link_ops,
++};
++
++static int replicator_probe(struct platform_device *pdev)
++{
++	struct device *dev = &pdev->dev;
++	struct coresight_platform_data *pdata = NULL;
++	struct replicator_drvdata *drvdata;
++	struct coresight_desc *desc;
++	struct device_node *np = pdev->dev.of_node;
++
++	if (np) {
++		pdata = of_get_coresight_platform_data(dev, np);
++		if (IS_ERR(pdata))
++			return PTR_ERR(pdata);
++		pdev->dev.platform_data = pdata;
++	}
++
++	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
++	if (!drvdata)
++		return -ENOMEM;
++
++	drvdata->dev = &pdev->dev;
++	platform_set_drvdata(pdev, drvdata);
++
++	desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
++	if (!desc)
++		return -ENOMEM;
++
++	desc->type = CORESIGHT_DEV_TYPE_LINK;
++	desc->subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_SPLIT;
++	desc->ops = &replicator_cs_ops;
++	desc->pdata = pdev->dev.platform_data;
++	desc->dev = &pdev->dev;
++	drvdata->csdev = coresight_register(desc);
++	if (IS_ERR(drvdata->csdev))
++		return PTR_ERR(drvdata->csdev);
++
++	dev_info(dev, "REPLICATOR initialized\n");
++	return 0;
++}
++
++static int replicator_remove(struct platform_device *pdev)
++{
++	struct replicator_drvdata *drvdata = platform_get_drvdata(pdev);
++
++	coresight_unregister(drvdata->csdev);
++	return 0;
++}
++
++static struct of_device_id replicator_match[] = {
++	{.compatible = "arm,coresight-replicator"},
++	{}
++};
++
++static struct platform_driver replicator_driver = {
++	.probe          = replicator_probe,
++	.remove         = replicator_remove,
++	.driver         = {
++		.name   = "coresight-replicator",
++		.of_match_table = replicator_match,
++	},
++};
++
++static int __init replicator_init(void)
++{
++	return platform_driver_register(&replicator_driver);
++}
++module_init(replicator_init);
++
++static void __exit replicator_exit(void)
++{
++	platform_driver_unregister(&replicator_driver);
++}
++module_exit(replicator_exit);
++
++MODULE_LICENSE("GPL v2");
++MODULE_DESCRIPTION("CoreSight Replicator driver");
+diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c
+new file mode 100644
+index 0000000..7147f3d
+--- /dev/null
++++ b/drivers/hwtracing/coresight/coresight-tmc.c
+@@ -0,0 +1,822 @@
++/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/types.h>
++#include <linux/device.h>
++#include <linux/io.h>
++#include <linux/err.h>
++#include <linux/fs.h>
++#include <linux/miscdevice.h>
++#include <linux/uaccess.h>
++#include <linux/slab.h>
++#include <linux/dma-mapping.h>
++#include <linux/spinlock.h>
++#include <linux/clk.h>
++#include <linux/of.h>
++#include <linux/coresight.h>
++#include <linux/amba/bus.h>
++
++#include "coresight-priv.h"
++
++#define TMC_RSZ			0x004
++#define TMC_STS			0x00c
++#define TMC_RRD			0x010
++#define TMC_RRP			0x014
++#define TMC_RWP			0x018
++#define TMC_TRG			0x01c
++#define TMC_CTL			0x020
++#define TMC_RWD			0x024
++#define TMC_MODE		0x028
++#define TMC_LBUFLEVEL		0x02c
++#define TMC_CBUFLEVEL		0x030
++#define TMC_BUFWM		0x034
++#define TMC_RRPHI		0x038
++#define TMC_RWPHI		0x03c
++#define TMC_AXICTL		0x110
++#define TMC_DBALO		0x118
++#define TMC_DBAHI		0x11c
++#define TMC_FFSR		0x300
++#define TMC_FFCR		0x304
++#define TMC_PSCR		0x308
++#define TMC_ITMISCOP0		0xee0
++#define TMC_ITTRFLIN		0xee8
++#define TMC_ITATBDATA0		0xeec
++#define TMC_ITATBCTR2		0xef0
++#define TMC_ITATBCTR1		0xef4
++#define TMC_ITATBCTR0		0xef8
++
++/* register description */
++/* TMC_CTL - 0x020 */
++#define TMC_CTL_CAPT_EN		BIT(0)
++/* TMC_STS - 0x00C */
++#define TMC_STS_TRIGGERED	BIT(1)
++/* TMC_AXICTL - 0x110 */
++#define TMC_AXICTL_PROT_CTL_B0	BIT(0)
++#define TMC_AXICTL_PROT_CTL_B1	BIT(1)
++#define TMC_AXICTL_SCT_GAT_MODE	BIT(7)
++#define TMC_AXICTL_WR_BURST_LEN 0xF00
++/* TMC_FFCR - 0x304 */
++#define TMC_FFCR_EN_FMT		BIT(0)
++#define TMC_FFCR_EN_TI		BIT(1)
++#define TMC_FFCR_FON_FLIN	BIT(4)
++#define TMC_FFCR_FON_TRIG_EVT	BIT(5)
++#define TMC_FFCR_FLUSHMAN	BIT(6)
++#define TMC_FFCR_TRIGON_TRIGIN	BIT(8)
++#define TMC_FFCR_STOP_ON_FLUSH	BIT(12)
++
++#define TMC_STS_TRIGGERED_BIT	2
++#define TMC_FFCR_FLUSHMAN_BIT	6
++
++enum tmc_config_type {
++	TMC_CONFIG_TYPE_ETB,
++	TMC_CONFIG_TYPE_ETR,
++	TMC_CONFIG_TYPE_ETF,
++};
++
++enum tmc_mode {
++	TMC_MODE_CIRCULAR_BUFFER,
++	TMC_MODE_SOFTWARE_FIFO,
++	TMC_MODE_HARDWARE_FIFO,
++};
++
++enum tmc_mem_intf_width {
++	TMC_MEM_INTF_WIDTH_32BITS	= 0x2,
++	TMC_MEM_INTF_WIDTH_64BITS	= 0x3,
++	TMC_MEM_INTF_WIDTH_128BITS	= 0x4,
++	TMC_MEM_INTF_WIDTH_256BITS	= 0x5,
++};
++
++/**
++ * struct tmc_drvdata - specifics associated to an TMC component
++ * @base:	memory mapped base address for this component.
++ * @dev:	the device entity associated to this component.
++ * @csdev:	component vitals needed by the framework.
++ * @miscdev:	specifics to handle "/dev/xyz.tmc" entry.
++ * @clk:	the clock this component is associated to.
++ * @spinlock:	only one at a time pls.
++ * @read_count:	manages preparation of buffer for reading.
++ * @buf:	area of memory where trace data get sent.
++ * @paddr:	DMA start location in RAM.
++ * @vaddr:	virtual representation of @paddr.
++ * @size:	@buf size.
++ * @enable:	this TMC is being used.
++ * @config_type: TMC variant, must be of type @tmc_config_type.
++ * @trigger_cntr: amount of words to store after a trigger.
++ */
++struct tmc_drvdata {
++	void __iomem		*base;
++	struct device		*dev;
++	struct coresight_device	*csdev;
++	struct miscdevice	miscdev;
++	struct clk		*clk;
++	spinlock_t		spinlock;
++	int			read_count;
++	bool			reading;
++	char			*buf;
++	dma_addr_t		paddr;
++	void __iomem		*vaddr;
++	u32			size;
++	bool			enable;
++	enum tmc_config_type	config_type;
++	u32			trigger_cntr;
++};
++
++static void tmc_wait_for_ready(struct tmc_drvdata *drvdata)
++{
++	/* Ensure formatter, unformatter and hardware fifo are empty */
++	if (coresight_timeout(drvdata->base,
++			      TMC_STS, TMC_STS_TRIGGERED_BIT, 1)) {
++		dev_err(drvdata->dev,
++			"timeout observed when probing at offset %#x\n",
++			TMC_STS);
++	}
++}
++
++static void tmc_flush_and_stop(struct tmc_drvdata *drvdata)
++{
++	u32 ffcr;
++
++	ffcr = readl_relaxed(drvdata->base + TMC_FFCR);
++	ffcr |= TMC_FFCR_STOP_ON_FLUSH;
++	writel_relaxed(ffcr, drvdata->base + TMC_FFCR);
++	ffcr |= TMC_FFCR_FLUSHMAN;
++	writel_relaxed(ffcr, drvdata->base + TMC_FFCR);
++	/* Ensure flush completes */
++	if (coresight_timeout(drvdata->base,
++			      TMC_FFCR, TMC_FFCR_FLUSHMAN_BIT, 0)) {
++		dev_err(drvdata->dev,
++			"timeout observed when probing at offset %#x\n",
++			TMC_FFCR);
++	}
++
++	tmc_wait_for_ready(drvdata);
++}
++
++static void tmc_enable_hw(struct tmc_drvdata *drvdata)
++{
++	writel_relaxed(TMC_CTL_CAPT_EN, drvdata->base + TMC_CTL);
++}
++
++static void tmc_disable_hw(struct tmc_drvdata *drvdata)
++{
++	writel_relaxed(0x0, drvdata->base + TMC_CTL);
++}
++
++static void tmc_etb_enable_hw(struct tmc_drvdata *drvdata)
++{
++	/* Zero out the memory to help with debug */
++	memset(drvdata->buf, 0, drvdata->size);
++
++	CS_UNLOCK(drvdata->base);
++
++	writel_relaxed(TMC_MODE_CIRCULAR_BUFFER, drvdata->base + TMC_MODE);
++	writel_relaxed(TMC_FFCR_EN_FMT | TMC_FFCR_EN_TI |
++		       TMC_FFCR_FON_FLIN | TMC_FFCR_FON_TRIG_EVT |
++		       TMC_FFCR_TRIGON_TRIGIN,
++		       drvdata->base + TMC_FFCR);
++
++	writel_relaxed(drvdata->trigger_cntr, drvdata->base + TMC_TRG);
++	tmc_enable_hw(drvdata);
++
++	CS_LOCK(drvdata->base);
++}
++
++static void tmc_etr_enable_hw(struct tmc_drvdata *drvdata)
++{
++	u32 axictl;
++
++	/* Zero out the memory to help with debug */
++	memset(drvdata->vaddr, 0, drvdata->size);
++
++	CS_UNLOCK(drvdata->base);
++
++	writel_relaxed(drvdata->size / 4, drvdata->base + TMC_RSZ);
++	writel_relaxed(TMC_MODE_CIRCULAR_BUFFER, drvdata->base + TMC_MODE);
++
++	axictl = readl_relaxed(drvdata->base + TMC_AXICTL);
++	axictl |= TMC_AXICTL_WR_BURST_LEN;
++	writel_relaxed(axictl, drvdata->base + TMC_AXICTL);
++	axictl &= ~TMC_AXICTL_SCT_GAT_MODE;
++	writel_relaxed(axictl, drvdata->base + TMC_AXICTL);
++	axictl = (axictl &
++		  ~(TMC_AXICTL_PROT_CTL_B0 | TMC_AXICTL_PROT_CTL_B1)) |
++		  TMC_AXICTL_PROT_CTL_B1;
++	writel_relaxed(axictl, drvdata->base + TMC_AXICTL);
++
++	writel_relaxed(drvdata->paddr, drvdata->base + TMC_DBALO);
++	writel_relaxed(0x0, drvdata->base + TMC_DBAHI);
++	writel_relaxed(TMC_FFCR_EN_FMT | TMC_FFCR_EN_TI |
++		       TMC_FFCR_FON_FLIN | TMC_FFCR_FON_TRIG_EVT |
++		       TMC_FFCR_TRIGON_TRIGIN,
++		       drvdata->base + TMC_FFCR);
++	writel_relaxed(drvdata->trigger_cntr, drvdata->base + TMC_TRG);
++	tmc_enable_hw(drvdata);
++
++	CS_LOCK(drvdata->base);
++}
++
++static void tmc_etf_enable_hw(struct tmc_drvdata *drvdata)
++{
++	CS_UNLOCK(drvdata->base);
++
++	writel_relaxed(TMC_MODE_HARDWARE_FIFO, drvdata->base + TMC_MODE);
++	writel_relaxed(TMC_FFCR_EN_FMT | TMC_FFCR_EN_TI,
++		       drvdata->base + TMC_FFCR);
++	writel_relaxed(0x0, drvdata->base + TMC_BUFWM);
++	tmc_enable_hw(drvdata);
++
++	CS_LOCK(drvdata->base);
++}
++
++static int tmc_enable(struct tmc_drvdata *drvdata, enum tmc_mode mode)
++{
++	int ret;
++	unsigned long flags;
++
++	ret = clk_prepare_enable(drvdata->clk);
++	if (ret)
++		return ret;
++
++	spin_lock_irqsave(&drvdata->spinlock, flags);
++	if (drvdata->reading) {
++		spin_unlock_irqrestore(&drvdata->spinlock, flags);
++		clk_disable_unprepare(drvdata->clk);
++		return -EBUSY;
++	}
++
++	if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
++		tmc_etb_enable_hw(drvdata);
++	} else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
++		tmc_etr_enable_hw(drvdata);
++	} else {
++		if (mode == TMC_MODE_CIRCULAR_BUFFER)
++			tmc_etb_enable_hw(drvdata);
++		else
++			tmc_etf_enable_hw(drvdata);
++	}
++	drvdata->enable = true;
++	spin_unlock_irqrestore(&drvdata->spinlock, flags);
++
++	dev_info(drvdata->dev, "TMC enabled\n");
++	return 0;
++}
++
++static int tmc_enable_sink(struct coresight_device *csdev)
++{
++	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
++
++	return tmc_enable(drvdata, TMC_MODE_CIRCULAR_BUFFER);
++}
++
++static int tmc_enable_link(struct coresight_device *csdev, int inport,
++			   int outport)
++{
++	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
++
++	return tmc_enable(drvdata, TMC_MODE_HARDWARE_FIFO);
++}
++
++static void tmc_etb_dump_hw(struct tmc_drvdata *drvdata)
++{
++	enum tmc_mem_intf_width memwidth;
++	u8 memwords;
++	char *bufp;
++	u32 read_data;
++	int i;
++
++	memwidth = BMVAL(readl_relaxed(drvdata->base + CORESIGHT_DEVID), 8, 10);
++	if (memwidth == TMC_MEM_INTF_WIDTH_32BITS)
++		memwords = 1;
++	else if (memwidth == TMC_MEM_INTF_WIDTH_64BITS)
++		memwords = 2;
++	else if (memwidth == TMC_MEM_INTF_WIDTH_128BITS)
++		memwords = 4;
++	else
++		memwords = 8;
++
++	bufp = drvdata->buf;
++	while (1) {
++		for (i = 0; i < memwords; i++) {
++			read_data = readl_relaxed(drvdata->base + TMC_RRD);
++			if (read_data == 0xFFFFFFFF)
++				return;
++			memcpy(bufp, &read_data, 4);
++			bufp += 4;
++		}
++	}
++}
++
++static void tmc_etb_disable_hw(struct tmc_drvdata *drvdata)
++{
++	CS_UNLOCK(drvdata->base);
++
++	tmc_flush_and_stop(drvdata);
++	tmc_etb_dump_hw(drvdata);
++	tmc_disable_hw(drvdata);
++
++	CS_LOCK(drvdata->base);
++}
++
++static void tmc_etr_dump_hw(struct tmc_drvdata *drvdata)
++{
++	u32 rwp, val;
++
++	rwp = readl_relaxed(drvdata->base + TMC_RWP);
++	val = readl_relaxed(drvdata->base + TMC_STS);
++
++	/* How much memory do we still have */
++	if (val & BIT(0))
++		drvdata->buf = drvdata->vaddr + rwp - drvdata->paddr;
++	else
++		drvdata->buf = drvdata->vaddr;
++}
++
++static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
++{
++	CS_UNLOCK(drvdata->base);
++
++	tmc_flush_and_stop(drvdata);
++	tmc_etr_dump_hw(drvdata);
++	tmc_disable_hw(drvdata);
++
++	CS_LOCK(drvdata->base);
++}
++
++static void tmc_etf_disable_hw(struct tmc_drvdata *drvdata)
++{
++	CS_UNLOCK(drvdata->base);
++
++	tmc_flush_and_stop(drvdata);
++	tmc_disable_hw(drvdata);
++
++	CS_LOCK(drvdata->base);
++}
++
++static void tmc_disable(struct tmc_drvdata *drvdata, enum tmc_mode mode)
++{
++	unsigned long flags;
++
++	spin_lock_irqsave(&drvdata->spinlock, flags);
++	if (drvdata->reading)
++		goto out;
++
++	if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
++		tmc_etb_disable_hw(drvdata);
++	} else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
++		tmc_etr_disable_hw(drvdata);
++	} else {
++		if (mode == TMC_MODE_CIRCULAR_BUFFER)
++			tmc_etb_disable_hw(drvdata);
++		else
++			tmc_etf_disable_hw(drvdata);
++	}
++out:
++	drvdata->enable = false;
++	spin_unlock_irqrestore(&drvdata->spinlock, flags);
++
++	clk_disable_unprepare(drvdata->clk);
++
++	dev_info(drvdata->dev, "TMC disabled\n");
++}
++
++static void tmc_disable_sink(struct coresight_device *csdev)
++{
++	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
++
++	tmc_disable(drvdata, TMC_MODE_CIRCULAR_BUFFER);
++}
++
++static void tmc_disable_link(struct coresight_device *csdev, int inport,
++			     int outport)
++{
++	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
++
++	tmc_disable(drvdata, TMC_MODE_HARDWARE_FIFO);
++}
++
++static const struct coresight_ops_sink tmc_sink_ops = {
++	.enable		= tmc_enable_sink,
++	.disable	= tmc_disable_sink,
++};
++
++static const struct coresight_ops_link tmc_link_ops = {
++	.enable		= tmc_enable_link,
++	.disable	= tmc_disable_link,
++};
++
++static const struct coresight_ops tmc_etb_cs_ops = {
++	.sink_ops	= &tmc_sink_ops,
++};
++
++static const struct coresight_ops tmc_etr_cs_ops = {
++	.sink_ops	= &tmc_sink_ops,
++};
++
++static const struct coresight_ops tmc_etf_cs_ops = {
++	.sink_ops	= &tmc_sink_ops,
++	.link_ops	= &tmc_link_ops,
++};
++
++static int tmc_read_prepare(struct tmc_drvdata *drvdata)
++{
++	int ret;
++	unsigned long flags;
++	enum tmc_mode mode;
++
++	spin_lock_irqsave(&drvdata->spinlock, flags);
++	if (!drvdata->enable)
++		goto out;
++
++	if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
++		tmc_etb_disable_hw(drvdata);
++	} else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
++		tmc_etr_disable_hw(drvdata);
++	} else {
++		mode = readl_relaxed(drvdata->base + TMC_MODE);
++		if (mode == TMC_MODE_CIRCULAR_BUFFER) {
++			tmc_etb_disable_hw(drvdata);
++		} else {
++			ret = -ENODEV;
++			goto err;
++		}
++	}
++out:
++	drvdata->reading = true;
++	spin_unlock_irqrestore(&drvdata->spinlock, flags);
++
++	dev_info(drvdata->dev, "TMC read start\n");
++	return 0;
++err:
++	spin_unlock_irqrestore(&drvdata->spinlock, flags);
++	return ret;
++}
++
++static void tmc_read_unprepare(struct tmc_drvdata *drvdata)
++{
++	unsigned long flags;
++	enum tmc_mode mode;
++
++	spin_lock_irqsave(&drvdata->spinlock, flags);
++	if (!drvdata->enable)
++		goto out;
++
++	if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
++		tmc_etb_enable_hw(drvdata);
++	} else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
++		tmc_etr_enable_hw(drvdata);
++	} else {
++		mode = readl_relaxed(drvdata->base + TMC_MODE);
++		if (mode == TMC_MODE_CIRCULAR_BUFFER)
++			tmc_etb_enable_hw(drvdata);
++	}
++out:
++	drvdata->reading = false;
++	spin_unlock_irqrestore(&drvdata->spinlock, flags);
++
++	dev_info(drvdata->dev, "TMC read end\n");
++}
++
++static int tmc_open(struct inode *inode, struct file *file)
++{
++	struct tmc_drvdata *drvdata = container_of(file->private_data,
++						   struct tmc_drvdata, miscdev);
++	int ret = 0;
++
++	if (drvdata->read_count++)
++		goto out;
++
++	ret = tmc_read_prepare(drvdata);
++	if (ret)
++		return ret;
++out:
++	nonseekable_open(inode, file);
++
++	dev_dbg(drvdata->dev, "%s: successfully opened\n", __func__);
++	return 0;
++}
++
++static ssize_t tmc_read(struct file *file, char __user *data, size_t len,
++			loff_t *ppos)
++{
++	struct tmc_drvdata *drvdata = container_of(file->private_data,
++						   struct tmc_drvdata, miscdev);
++	char *bufp = drvdata->buf + *ppos;
++
++	if (*ppos + len > drvdata->size)
++		len = drvdata->size - *ppos;
++
++	if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
++		if (bufp == (char *)(drvdata->vaddr + drvdata->size))
++			bufp = drvdata->vaddr;
++		else if (bufp > (char *)(drvdata->vaddr + drvdata->size))
++			bufp -= drvdata->size;
++		if ((bufp + len) > (char *)(drvdata->vaddr + drvdata->size))
++			len = (char *)(drvdata->vaddr + drvdata->size) - bufp;
++	}
++
++	if (copy_to_user(data, bufp, len)) {
++		dev_dbg(drvdata->dev, "%s: copy_to_user failed\n", __func__);
++		return -EFAULT;
++	}
++
++	*ppos += len;
++
++	dev_dbg(drvdata->dev, "%s: %zu bytes copied, %d bytes left\n",
++		__func__, len, (int)(drvdata->size - *ppos));
++	return len;
++}
++
++static int tmc_release(struct inode *inode, struct file *file)
++{
++	struct tmc_drvdata *drvdata = container_of(file->private_data,
++						   struct tmc_drvdata, miscdev);
++
++	if (--drvdata->read_count) {
++		if (drvdata->read_count < 0) {
++			dev_err(drvdata->dev, "mismatched close\n");
++			drvdata->read_count = 0;
++		}
++		goto out;
++	}
++
++	tmc_read_unprepare(drvdata);
++out:
++	dev_dbg(drvdata->dev, "%s: released\n", __func__);
++	return 0;
++}
++
++static const struct file_operations tmc_fops = {
++	.owner		= THIS_MODULE,
++	.open		= tmc_open,
++	.read		= tmc_read,
++	.release	= tmc_release,
++	.llseek		= no_llseek,
++};
++
++static ssize_t status_show(struct device *dev,
++			   struct device_attribute *attr, char *buf)
++{
++	int ret;
++	unsigned long flags;
++	u32 tmc_rsz, tmc_sts, tmc_rrp, tmc_rwp, tmc_trg;
++	u32 tmc_ctl, tmc_ffsr, tmc_ffcr, tmc_mode, tmc_pscr;
++	u32 devid;
++	struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	ret = clk_prepare_enable(drvdata->clk);
++	if (ret)
++		goto out;
++
++	spin_lock_irqsave(&drvdata->spinlock, flags);
++	CS_UNLOCK(drvdata->base);
++
++	tmc_rsz = readl_relaxed(drvdata->base + TMC_RSZ);
++	tmc_sts = readl_relaxed(drvdata->base + TMC_STS);
++	tmc_rrp = readl_relaxed(drvdata->base + TMC_RRP);
++	tmc_rwp = readl_relaxed(drvdata->base + TMC_RWP);
++	tmc_trg = readl_relaxed(drvdata->base + TMC_TRG);
++	tmc_ctl = readl_relaxed(drvdata->base + TMC_CTL);
++	tmc_ffsr = readl_relaxed(drvdata->base + TMC_FFSR);
++	tmc_ffcr = readl_relaxed(drvdata->base + TMC_FFCR);
++	tmc_mode = readl_relaxed(drvdata->base + TMC_MODE);
++	tmc_pscr = readl_relaxed(drvdata->base + TMC_PSCR);
++	devid = readl_relaxed(drvdata->base + CORESIGHT_DEVID);
++
++	CS_LOCK(drvdata->base);
++	spin_unlock_irqrestore(&drvdata->spinlock, flags);
++
++	clk_disable_unprepare(drvdata->clk);
++
++	return sprintf(buf,
++		       "Depth:\t\t0x%x\n"
++		       "Status:\t\t0x%x\n"
++		       "RAM read ptr:\t0x%x\n"
++		       "RAM wrt ptr:\t0x%x\n"
++		       "Trigger cnt:\t0x%x\n"
++		       "Control:\t0x%x\n"
++		       "Flush status:\t0x%x\n"
++		       "Flush ctrl:\t0x%x\n"
++		       "Mode:\t\t0x%x\n"
++		       "PSRC:\t\t0x%x\n"
++		       "DEVID:\t\t0x%x\n",
++			tmc_rsz, tmc_sts, tmc_rrp, tmc_rwp, tmc_trg,
++			tmc_ctl, tmc_ffsr, tmc_ffcr, tmc_mode, tmc_pscr, devid);
++out:
++	return -EINVAL;
++}
++static DEVICE_ATTR_RO(status);
++
++static ssize_t trigger_cntr_show(struct device *dev,
++			    struct device_attribute *attr, char *buf)
++{
++	struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent);
++	unsigned long val = drvdata->trigger_cntr;
++
++	return sprintf(buf, "%#lx\n", val);
++}
++
++static ssize_t trigger_cntr_store(struct device *dev,
++			     struct device_attribute *attr,
++			     const char *buf, size_t size)
++{
++	int ret;
++	unsigned long val;
++	struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent);
++
++	ret = kstrtoul(buf, 16, &val);
++	if (ret)
++		return ret;
++
++	drvdata->trigger_cntr = val;
++	return size;
++}
++static DEVICE_ATTR_RW(trigger_cntr);
++
++static struct attribute *coresight_etb_attrs[] = {
++	&dev_attr_trigger_cntr.attr,
++	&dev_attr_status.attr,
++	NULL,
++};
++ATTRIBUTE_GROUPS(coresight_etb);
++
++static struct attribute *coresight_etr_attrs[] = {
++	&dev_attr_trigger_cntr.attr,
++	&dev_attr_status.attr,
++	NULL,
++};
++ATTRIBUTE_GROUPS(coresight_etr);
++
++static struct attribute *coresight_etf_attrs[] = {
++	&dev_attr_trigger_cntr.attr,
++	&dev_attr_status.attr,
++	NULL,
++};
++ATTRIBUTE_GROUPS(coresight_etf);
++
++static int tmc_probe(struct amba_device *adev, const struct amba_id *id)
++{
++	int ret = 0;
++	u32 devid;
++	void __iomem *base;
++	struct device *dev = &adev->dev;
++	struct coresight_platform_data *pdata = NULL;
++	struct tmc_drvdata *drvdata;
++	struct resource *res = &adev->res;
++	struct coresight_desc *desc;
++	struct device_node *np = adev->dev.of_node;
++
++	if (np) {
++		pdata = of_get_coresight_platform_data(dev, np);
++		if (IS_ERR(pdata))
++			return PTR_ERR(pdata);
++		adev->dev.platform_data = pdata;
++	}
++
++	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
++	if (!drvdata)
++		return -ENOMEM;
++
++	drvdata->dev = &adev->dev;
++	dev_set_drvdata(dev, drvdata);
++
++	/* Validity for the resource is already checked by the AMBA core */
++	base = devm_ioremap_resource(dev, res);
++	if (IS_ERR(base))
++		return PTR_ERR(base);
++
++	drvdata->base = base;
++
++	spin_lock_init(&drvdata->spinlock);
++
++	drvdata->clk = adev->pclk;
++	ret = clk_prepare_enable(drvdata->clk);
++	if (ret)
++		return ret;
++
++	devid = readl_relaxed(drvdata->base + CORESIGHT_DEVID);
++	drvdata->config_type = BMVAL(devid, 6, 7);
++
++	if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
++		if (np)
++			ret = of_property_read_u32(np,
++						   "arm,buffer-size",
++						   &drvdata->size);
++		if (ret)
++			drvdata->size = SZ_1M;
++	} else {
++		drvdata->size = readl_relaxed(drvdata->base + TMC_RSZ) * 4;
++	}
++
++	clk_disable_unprepare(drvdata->clk);
++
++	if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
++		drvdata->vaddr = dma_alloc_coherent(dev, drvdata->size,
++						&drvdata->paddr, GFP_KERNEL);
++		if (!drvdata->vaddr)
++			return -ENOMEM;
++
++		memset(drvdata->vaddr, 0, drvdata->size);
++		drvdata->buf = drvdata->vaddr;
++	} else {
++		drvdata->buf = devm_kzalloc(dev, drvdata->size, GFP_KERNEL);
++		if (!drvdata->buf)
++			return -ENOMEM;
++	}
++
++	desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
++	if (!desc) {
++		ret = -ENOMEM;
++		goto err_devm_kzalloc;
++	}
++
++	desc->pdata = pdata;
++	desc->dev = dev;
++	desc->subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER;
++
++	if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
++		desc->type = CORESIGHT_DEV_TYPE_SINK;
++		desc->ops = &tmc_etb_cs_ops;
++		desc->groups = coresight_etb_groups;
++	} else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
++		desc->type = CORESIGHT_DEV_TYPE_SINK;
++		desc->ops = &tmc_etr_cs_ops;
++		desc->groups = coresight_etr_groups;
++	} else {
++		desc->type = CORESIGHT_DEV_TYPE_LINKSINK;
++		desc->subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_FIFO;
++		desc->ops = &tmc_etf_cs_ops;
++		desc->groups = coresight_etf_groups;
++	}
++
++	drvdata->csdev = coresight_register(desc);
++	if (IS_ERR(drvdata->csdev)) {
++		ret = PTR_ERR(drvdata->csdev);
++		goto err_devm_kzalloc;
++	}
++
++	drvdata->miscdev.name = pdata->name;
++	drvdata->miscdev.minor = MISC_DYNAMIC_MINOR;
++	drvdata->miscdev.fops = &tmc_fops;
++	ret = misc_register(&drvdata->miscdev);
++	if (ret)
++		goto err_misc_register;
++
++	dev_info(dev, "TMC initialized\n");
++	return 0;
++
++err_misc_register:
++	coresight_unregister(drvdata->csdev);
++err_devm_kzalloc:
++	if (drvdata->config_type == TMC_CONFIG_TYPE_ETR)
++		dma_free_coherent(dev, drvdata->size,
++				&drvdata->paddr, GFP_KERNEL);
++	return ret;
++}
++
++static int tmc_remove(struct amba_device *adev)
++{
++	struct tmc_drvdata *drvdata = amba_get_drvdata(adev);
++
++	misc_deregister(&drvdata->miscdev);
++	coresight_unregister(drvdata->csdev);
++	if (drvdata->config_type == TMC_CONFIG_TYPE_ETR)
++		dma_free_coherent(drvdata->dev, drvdata->size,
++				  &drvdata->paddr, GFP_KERNEL);
++
++	return 0;
++}
++
++static struct amba_id tmc_ids[] = {
++	{
++		.id     = 0x0003b961,
++		.mask   = 0x0003ffff,
++	},
++	{ 0, 0},
++};
++
++static struct amba_driver tmc_driver = {
++	.drv = {
++		.name   = "coresight-tmc",
++		.owner  = THIS_MODULE,
++	},
++	.probe		= tmc_probe,
++	.remove		= tmc_remove,
++	.id_table	= tmc_ids,
++};
++
++module_amba_driver(tmc_driver);
++
++MODULE_LICENSE("GPL v2");
++MODULE_DESCRIPTION("CoreSight Trace Memory Controller driver");
+diff --git a/drivers/hwtracing/coresight/coresight-tpiu.c b/drivers/hwtracing/coresight/coresight-tpiu.c
+new file mode 100644
+index 0000000..3b33af2
+--- /dev/null
++++ b/drivers/hwtracing/coresight/coresight-tpiu.c
+@@ -0,0 +1,207 @@
++/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/device.h>
++#include <linux/io.h>
++#include <linux/err.h>
++#include <linux/slab.h>
++#include <linux/clk.h>
++#include <linux/coresight.h>
++#include <linux/amba/bus.h>
++
++#include "coresight-priv.h"
++
++#define TPIU_SUPP_PORTSZ	0x000
++#define TPIU_CURR_PORTSZ	0x004
++#define TPIU_SUPP_TRIGMODES	0x100
++#define TPIU_TRIG_CNTRVAL	0x104
++#define TPIU_TRIG_MULT		0x108
++#define TPIU_SUPP_TESTPATM	0x200
++#define TPIU_CURR_TESTPATM	0x204
++#define TPIU_TEST_PATREPCNTR	0x208
++#define TPIU_FFSR		0x300
++#define TPIU_FFCR		0x304
++#define TPIU_FSYNC_CNTR		0x308
++#define TPIU_EXTCTL_INPORT	0x400
++#define TPIU_EXTCTL_OUTPORT	0x404
++#define TPIU_ITTRFLINACK	0xee4
++#define TPIU_ITTRFLIN		0xee8
++#define TPIU_ITATBDATA0		0xeec
++#define TPIU_ITATBCTR2		0xef0
++#define TPIU_ITATBCTR1		0xef4
++#define TPIU_ITATBCTR0		0xef8
++
++/** register definition **/
++/* FFCR - 0x304 */
++#define FFCR_FON_MAN		BIT(6)
++
++/**
++ * @base:	memory mapped base address for this component.
++ * @dev:	the device entity associated to this component.
++ * @csdev:	component vitals needed by the framework.
++ * @clk:	the clock this component is associated to.
++ */
++struct tpiu_drvdata {
++	void __iomem		*base;
++	struct device		*dev;
++	struct coresight_device	*csdev;
++	struct clk		*clk;
++};
++
++static void tpiu_enable_hw(struct tpiu_drvdata *drvdata)
++{
++	CS_UNLOCK(drvdata->base);
++
++	/* TODO: fill this up */
++
++	CS_LOCK(drvdata->base);
++}
++
++static int tpiu_enable(struct coresight_device *csdev)
++{
++	struct tpiu_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
++	int ret;
++
++	ret = clk_prepare_enable(drvdata->clk);
++	if (ret)
++		return ret;
++
++	tpiu_enable_hw(drvdata);
++
++	dev_info(drvdata->dev, "TPIU enabled\n");
++	return 0;
++}
++
++static void tpiu_disable_hw(struct tpiu_drvdata *drvdata)
++{
++	CS_UNLOCK(drvdata->base);
++
++	/* Clear formatter controle reg. */
++	writel_relaxed(0x0, drvdata->base + TPIU_FFCR);
++	/* Generate manual flush */
++	writel_relaxed(FFCR_FON_MAN, drvdata->base + TPIU_FFCR);
++
++	CS_LOCK(drvdata->base);
++}
++
++static void tpiu_disable(struct coresight_device *csdev)
++{
++	struct tpiu_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
++
++	tpiu_disable_hw(drvdata);
++
++	clk_disable_unprepare(drvdata->clk);
++
++	dev_info(drvdata->dev, "TPIU disabled\n");
++}
++
++static const struct coresight_ops_sink tpiu_sink_ops = {
++	.enable		= tpiu_enable,
++	.disable	= tpiu_disable,
++};
++
++static const struct coresight_ops tpiu_cs_ops = {
++	.sink_ops	= &tpiu_sink_ops,
++};
++
++static int tpiu_probe(struct amba_device *adev, const struct amba_id *id)
++{
++	int ret;
++	void __iomem *base;
++	struct device *dev = &adev->dev;
++	struct coresight_platform_data *pdata = NULL;
++	struct tpiu_drvdata *drvdata;
++	struct resource *res = &adev->res;
++	struct coresight_desc *desc;
++	struct device_node *np = adev->dev.of_node;
++
++	if (np) {
++		pdata = of_get_coresight_platform_data(dev, np);
++		if (IS_ERR(pdata))
++			return PTR_ERR(pdata);
++		adev->dev.platform_data = pdata;
++	}
++
++	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
++	if (!drvdata)
++		return -ENOMEM;
++
++	drvdata->dev = &adev->dev;
++	dev_set_drvdata(dev, drvdata);
++
++	/* Validity for the resource is already checked by the AMBA core */
++	base = devm_ioremap_resource(dev, res);
++	if (IS_ERR(base))
++		return PTR_ERR(base);
++
++	drvdata->base = base;
++
++	drvdata->clk = adev->pclk;
++	ret = clk_prepare_enable(drvdata->clk);
++	if (ret)
++		return ret;
++
++	/* Disable tpiu to support older devices */
++	tpiu_disable_hw(drvdata);
++
++	clk_disable_unprepare(drvdata->clk);
++
++	desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
++	if (!desc)
++		return -ENOMEM;
++
++	desc->type = CORESIGHT_DEV_TYPE_SINK;
++	desc->subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_PORT;
++	desc->ops = &tpiu_cs_ops;
++	desc->pdata = pdata;
++	desc->dev = dev;
++	drvdata->csdev = coresight_register(desc);
++	if (IS_ERR(drvdata->csdev))
++		return PTR_ERR(drvdata->csdev);
++
++	dev_info(dev, "TPIU initialized\n");
++	return 0;
++}
++
++static int tpiu_remove(struct amba_device *adev)
++{
++	struct tpiu_drvdata *drvdata = amba_get_drvdata(adev);
++
++	coresight_unregister(drvdata->csdev);
++	return 0;
++}
++
++static struct amba_id tpiu_ids[] = {
++	{
++		.id	= 0x0003b912,
++		.mask	= 0x0003ffff,
++	},
++	{ 0, 0},
++};
++
++static struct amba_driver tpiu_driver = {
++	.drv = {
++		.name	= "coresight-tpiu",
++		.owner	= THIS_MODULE,
++	},
++	.probe		= tpiu_probe,
++	.remove		= tpiu_remove,
++	.id_table	= tpiu_ids,
++};
++
++module_amba_driver(tpiu_driver);
++
++MODULE_LICENSE("GPL v2");
++MODULE_DESCRIPTION("CoreSight Trace Port Interface Unit driver");
+diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c
+new file mode 100644
+index 0000000..894531d
+--- /dev/null
++++ b/drivers/hwtracing/coresight/coresight.c
+@@ -0,0 +1,720 @@
++/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/types.h>
++#include <linux/device.h>
++#include <linux/io.h>
++#include <linux/err.h>
++#include <linux/export.h>
++#include <linux/slab.h>
++#include <linux/mutex.h>
++#include <linux/clk.h>
++#include <linux/coresight.h>
++#include <linux/of_platform.h>
++#include <linux/delay.h>
++
++#include "coresight-priv.h"
++
++static DEFINE_MUTEX(coresight_mutex);
++
++static int coresight_id_match(struct device *dev, void *data)
++{
++	int trace_id, i_trace_id;
++	struct coresight_device *csdev, *i_csdev;
++
++	csdev = data;
++	i_csdev = to_coresight_device(dev);
++
++	/*
++	 * No need to care about oneself and components that are not
++	 * sources or not enabled
++	 */
++	if (i_csdev == csdev || !i_csdev->enable ||
++	    i_csdev->type != CORESIGHT_DEV_TYPE_SOURCE)
++		return 0;
++
++	/* Get the source ID for both compoment */
++	trace_id = source_ops(csdev)->trace_id(csdev);
++	i_trace_id = source_ops(i_csdev)->trace_id(i_csdev);
++
++	/* All you need is one */
++	if (trace_id == i_trace_id)
++		return 1;
++
++	return 0;
++}
++
++static int coresight_source_is_unique(struct coresight_device *csdev)
++{
++	int trace_id = source_ops(csdev)->trace_id(csdev);
++
++	/* this shouldn't happen */
++	if (trace_id < 0)
++		return 0;
++
++	return !bus_for_each_dev(&coresight_bustype, NULL,
++				 csdev, coresight_id_match);
++}
++
++static int coresight_find_link_inport(struct coresight_device *csdev)
++{
++	int i;
++	struct coresight_device *parent;
++	struct coresight_connection *conn;
++
++	parent = container_of(csdev->path_link.next,
++			      struct coresight_device, path_link);
++
++	for (i = 0; i < parent->nr_outport; i++) {
++		conn = &parent->conns[i];
++		if (conn->child_dev == csdev)
++			return conn->child_port;
++	}
++
++	dev_err(&csdev->dev, "couldn't find inport, parent: %s, child: %s\n",
++		dev_name(&parent->dev), dev_name(&csdev->dev));
++
++	return 0;
++}
++
++static int coresight_find_link_outport(struct coresight_device *csdev)
++{
++	int i;
++	struct coresight_device *child;
++	struct coresight_connection *conn;
++
++	child = container_of(csdev->path_link.prev,
++			     struct coresight_device, path_link);
++
++	for (i = 0; i < csdev->nr_outport; i++) {
++		conn = &csdev->conns[i];
++		if (conn->child_dev == child)
++			return conn->outport;
++	}
++
++	dev_err(&csdev->dev, "couldn't find outport, parent: %s, child: %s\n",
++		dev_name(&csdev->dev), dev_name(&child->dev));
++
++	return 0;
++}
++
++static int coresight_enable_sink(struct coresight_device *csdev)
++{
++	int ret;
++
++	if (!csdev->enable) {
++		if (sink_ops(csdev)->enable) {
++			ret = sink_ops(csdev)->enable(csdev);
++			if (ret)
++				return ret;
++		}
++		csdev->enable = true;
++	}
++
++	atomic_inc(csdev->refcnt);
++
++	return 0;
++}
++
++static void coresight_disable_sink(struct coresight_device *csdev)
++{
++	if (atomic_dec_return(csdev->refcnt) == 0) {
++		if (sink_ops(csdev)->disable) {
++			sink_ops(csdev)->disable(csdev);
++			csdev->enable = false;
++		}
++	}
++}
++
++static int coresight_enable_link(struct coresight_device *csdev)
++{
++	int ret;
++	int link_subtype;
++	int refport, inport, outport;
++
++	inport = coresight_find_link_inport(csdev);
++	outport = coresight_find_link_outport(csdev);
++	link_subtype = csdev->subtype.link_subtype;
++
++	if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG)
++		refport = inport;
++	else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT)
++		refport = outport;
++	else
++		refport = 0;
++
++	if (atomic_inc_return(&csdev->refcnt[refport]) == 1) {
++		if (link_ops(csdev)->enable) {
++			ret = link_ops(csdev)->enable(csdev, inport, outport);
++			if (ret)
++				return ret;
++		}
++	}
++
++	csdev->enable = true;
++
++	return 0;
++}
++
++static void coresight_disable_link(struct coresight_device *csdev)
++{
++	int i, nr_conns;
++	int link_subtype;
++	int refport, inport, outport;
++
++	inport = coresight_find_link_inport(csdev);
++	outport = coresight_find_link_outport(csdev);
++	link_subtype = csdev->subtype.link_subtype;
++
++	if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG) {
++		refport = inport;
++		nr_conns = csdev->nr_inport;
++	} else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT) {
++		refport = outport;
++		nr_conns = csdev->nr_outport;
++	} else {
++		refport = 0;
++		nr_conns = 1;
++	}
++
++	if (atomic_dec_return(&csdev->refcnt[refport]) == 0) {
++		if (link_ops(csdev)->disable)
++			link_ops(csdev)->disable(csdev, inport, outport);
++	}
++
++	for (i = 0; i < nr_conns; i++)
++		if (atomic_read(&csdev->refcnt[i]) != 0)
++			return;
++
++	csdev->enable = false;
++}
++
++static int coresight_enable_source(struct coresight_device *csdev)
++{
++	int ret;
++
++	if (!coresight_source_is_unique(csdev)) {
++		dev_warn(&csdev->dev, "traceID %d not unique\n",
++			 source_ops(csdev)->trace_id(csdev));
++		return -EINVAL;
++	}
++
++	if (!csdev->enable) {
++		if (source_ops(csdev)->enable) {
++			ret = source_ops(csdev)->enable(csdev);
++			if (ret)
++				return ret;
++		}
++		csdev->enable = true;
++	}
++
++	atomic_inc(csdev->refcnt);
++
++	return 0;
++}
++
++static void coresight_disable_source(struct coresight_device *csdev)
++{
++	if (atomic_dec_return(csdev->refcnt) == 0) {
++		if (source_ops(csdev)->disable) {
++			source_ops(csdev)->disable(csdev);
++			csdev->enable = false;
++		}
++	}
++}
++
++static int coresight_enable_path(struct list_head *path)
++{
++	int ret = 0;
++	struct coresight_device *cd;
++
++	list_for_each_entry(cd, path, path_link) {
++		if (cd == list_first_entry(path, struct coresight_device,
++					   path_link)) {
++			ret = coresight_enable_sink(cd);
++		} else if (list_is_last(&cd->path_link, path)) {
++			/*
++			 * Don't enable the source just yet - this needs to
++			 * happen at the very end when all links and sink
++			 * along the path have been configured properly.
++			 */
++			;
++		} else {
++			ret = coresight_enable_link(cd);
++		}
++		if (ret)
++			goto err;
++	}
++
++	return 0;
++err:
++	list_for_each_entry_continue_reverse(cd, path, path_link) {
++		if (cd == list_first_entry(path, struct coresight_device,
++					   path_link)) {
++			coresight_disable_sink(cd);
++		} else if (list_is_last(&cd->path_link, path)) {
++			;
++		} else {
++			coresight_disable_link(cd);
++		}
++	}
++
++	return ret;
++}
++
++static int coresight_disable_path(struct list_head *path)
++{
++	struct coresight_device *cd;
++
++	list_for_each_entry_reverse(cd, path, path_link) {
++		if (cd == list_first_entry(path, struct coresight_device,
++					   path_link)) {
++			coresight_disable_sink(cd);
++		} else if (list_is_last(&cd->path_link, path)) {
++			/*
++			 * The source has already been stopped, no need
++			 * to do it again here.
++			 */
++			;
++		} else {
++			coresight_disable_link(cd);
++		}
++	}
++
++	return 0;
++}
++
++static int coresight_build_paths(struct coresight_device *csdev,
++				 struct list_head *path,
++				 bool enable)
++{
++	int i, ret = -EINVAL;
++	struct coresight_connection *conn;
++
++	list_add(&csdev->path_link, path);
++
++	if ((csdev->type == CORESIGHT_DEV_TYPE_SINK ||
++	    csdev->type == CORESIGHT_DEV_TYPE_LINKSINK) &&
++	    csdev->activated) {
++		if (enable)
++			ret = coresight_enable_path(path);
++		else
++			ret = coresight_disable_path(path);
++	} else {
++		for (i = 0; i < csdev->nr_outport; i++) {
++			conn = &csdev->conns[i];
++			if (coresight_build_paths(conn->child_dev,
++						    path, enable) == 0)
++				ret = 0;
++		}
++	}
++
++	if (list_first_entry(path, struct coresight_device, path_link) != csdev)
++		dev_err(&csdev->dev, "wrong device in %s\n", __func__);
++
++	list_del(&csdev->path_link);
++
++	return ret;
++}
++
++int coresight_enable(struct coresight_device *csdev)
++{
++	int ret = 0;
++	LIST_HEAD(path);
++
++	mutex_lock(&coresight_mutex);
++	if (csdev->type != CORESIGHT_DEV_TYPE_SOURCE) {
++		ret = -EINVAL;
++		dev_err(&csdev->dev, "wrong device type in %s\n", __func__);
++		goto out;
++	}
++	if (csdev->enable)
++		goto out;
++
++	if (coresight_build_paths(csdev, &path, true)) {
++		dev_err(&csdev->dev, "building path(s) failed\n");
++		goto out;
++	}
++
++	if (coresight_enable_source(csdev))
++		dev_err(&csdev->dev, "source enable failed\n");
++out:
++	mutex_unlock(&coresight_mutex);
++	return ret;
++}
++EXPORT_SYMBOL_GPL(coresight_enable);
++
++void coresight_disable(struct coresight_device *csdev)
++{
++	LIST_HEAD(path);
++
++	mutex_lock(&coresight_mutex);
++	if (csdev->type != CORESIGHT_DEV_TYPE_SOURCE) {
++		dev_err(&csdev->dev, "wrong device type in %s\n", __func__);
++		goto out;
++	}
++	if (!csdev->enable)
++		goto out;
++
++	coresight_disable_source(csdev);
++	if (coresight_build_paths(csdev, &path, false))
++		dev_err(&csdev->dev, "releasing path(s) failed\n");
++
++out:
++	mutex_unlock(&coresight_mutex);
++}
++EXPORT_SYMBOL_GPL(coresight_disable);
++
++static ssize_t enable_sink_show(struct device *dev,
++				struct device_attribute *attr, char *buf)
++{
++	struct coresight_device *csdev = to_coresight_device(dev);
++
++	return scnprintf(buf, PAGE_SIZE, "%u\n", (unsigned)csdev->activated);
++}
++
++static ssize_t enable_sink_store(struct device *dev,
++				 struct device_attribute *attr,
++				 const char *buf, size_t size)
++{
++	int ret;
++	unsigned long val;
++	struct coresight_device *csdev = to_coresight_device(dev);
++
++	ret = kstrtoul(buf, 10, &val);
++	if (ret)
++		return ret;
++
++	if (val)
++		csdev->activated = true;
++	else
++		csdev->activated = false;
++
++	return size;
++
++}
++static DEVICE_ATTR_RW(enable_sink);
++
++static ssize_t enable_source_show(struct device *dev,
++				  struct device_attribute *attr, char *buf)
++{
++	struct coresight_device *csdev = to_coresight_device(dev);
++
++	return scnprintf(buf, PAGE_SIZE, "%u\n", (unsigned)csdev->enable);
++}
++
++static ssize_t enable_source_store(struct device *dev,
++				   struct device_attribute *attr,
++				   const char *buf, size_t size)
++{
++	int ret = 0;
++	unsigned long val;
++	struct coresight_device *csdev = to_coresight_device(dev);
++
++	ret = kstrtoul(buf, 10, &val);
++	if (ret)
++		return ret;
++
++	if (val) {
++		ret = coresight_enable(csdev);
++		if (ret)
++			return ret;
++	} else {
++		coresight_disable(csdev);
++	}
++
++	return size;
++}
++static DEVICE_ATTR_RW(enable_source);
++
++static struct attribute *coresight_sink_attrs[] = {
++	&dev_attr_enable_sink.attr,
++	NULL,
++};
++ATTRIBUTE_GROUPS(coresight_sink);
++
++static struct attribute *coresight_source_attrs[] = {
++	&dev_attr_enable_source.attr,
++	NULL,
++};
++ATTRIBUTE_GROUPS(coresight_source);
++
++static struct device_type coresight_dev_type[] = {
++	{
++		.name = "none",
++	},
++	{
++		.name = "sink",
++		.groups = coresight_sink_groups,
++	},
++	{
++		.name = "link",
++	},
++	{
++		.name = "linksink",
++		.groups = coresight_sink_groups,
++	},
++	{
++		.name = "source",
++		.groups = coresight_source_groups,
++	},
++};
++
++static void coresight_device_release(struct device *dev)
++{
++	struct coresight_device *csdev = to_coresight_device(dev);
++
++	kfree(csdev);
++}
++
++static int coresight_orphan_match(struct device *dev, void *data)
++{
++	int i;
++	bool still_orphan = false;
++	struct coresight_device *csdev, *i_csdev;
++	struct coresight_connection *conn;
++
++	csdev = data;
++	i_csdev = to_coresight_device(dev);
++
++	/* No need to check oneself */
++	if (csdev == i_csdev)
++		return 0;
++
++	/* Move on to another component if no connection is orphan */
++	if (!i_csdev->orphan)
++		return 0;
++	/*
++	 * Circle throuch all the connection of that component.  If we find
++	 * an orphan connection whose name matches @csdev, link it.
++	 */
++	for (i = 0; i < i_csdev->nr_outport; i++) {
++		conn = &i_csdev->conns[i];
++
++		/* We have found at least one orphan connection */
++		if (conn->child_dev == NULL) {
++			/* Does it match this newly added device? */
++			if (!strcmp(dev_name(&csdev->dev), conn->child_name)) {
++				conn->child_dev = csdev;
++			} else {
++				/* This component still has an orphan */
++				still_orphan = true;
++			}
++		}
++	}
++
++	i_csdev->orphan = still_orphan;
++
++	/*
++	 * Returning '0' ensures that all known component on the
++	 * bus will be checked.
++	 */
++	return 0;
++}
++
++static void coresight_fixup_orphan_conns(struct coresight_device *csdev)
++{
++	/*
++	 * No need to check for a return value as orphan connection(s)
++	 * are hooked-up with each newly added component.
++	 */
++	bus_for_each_dev(&coresight_bustype, NULL,
++				 csdev, coresight_orphan_match);
++}
++
++
++static int coresight_name_match(struct device *dev, void *data)
++{
++	char *to_match;
++	struct coresight_device *i_csdev;
++
++	to_match = data;
++	i_csdev = to_coresight_device(dev);
++
++	if (!strcmp(to_match, dev_name(&i_csdev->dev)))
++		return 1;
++
++	return 0;
++}
++
++static void coresight_fixup_device_conns(struct coresight_device *csdev)
++{
++	int i;
++	struct device *dev = NULL;
++	struct coresight_connection *conn;
++
++	for (i = 0; i < csdev->nr_outport; i++) {
++		conn = &csdev->conns[i];
++		dev = bus_find_device(&coresight_bustype, NULL,
++				      (void *)conn->child_name,
++				      coresight_name_match);
++
++		if (dev) {
++			conn->child_dev = to_coresight_device(dev);
++		} else {
++			csdev->orphan = true;
++			conn->child_dev = NULL;
++		}
++	}
++}
++
++/**
++ * coresight_timeout - loop until a bit has changed to a specific state.
++ * @addr: base address of the area of interest.
++ * @offset: address of a register, starting from @addr.
++ * @position: the position of the bit of interest.
++ * @value: the value the bit should have.
++ *
++ * Return: 0 as soon as the bit has taken the desired state or -EAGAIN if
++ * TIMEOUT_US has elapsed, which ever happens first.
++ */
++
++int coresight_timeout(void __iomem *addr, u32 offset, int position, int value)
++{
++	int i;
++	u32 val;
++
++	for (i = TIMEOUT_US; i > 0; i--) {
++		val = __raw_readl(addr + offset);
++		/* waiting on the bit to go from 0 to 1 */
++		if (value) {
++			if (val & BIT(position))
++				return 0;
++		/* waiting on the bit to go from 1 to 0 */
++		} else {
++			if (!(val & BIT(position)))
++				return 0;
++		}
++
++		/*
++		 * Delay is arbitrary - the specification doesn't say how long
++		 * we are expected to wait.  Extra check required to make sure
++		 * we don't wait needlessly on the last iteration.
++		 */
++		if (i - 1)
++			udelay(1);
++	}
++
++	return -EAGAIN;
++}
++
++struct bus_type coresight_bustype = {
++	.name	= "coresight",
++};
++
++static int __init coresight_init(void)
++{
++	return bus_register(&coresight_bustype);
++}
++postcore_initcall(coresight_init);
++
++struct coresight_device *coresight_register(struct coresight_desc *desc)
++{
++	int i;
++	int ret;
++	int link_subtype;
++	int nr_refcnts = 1;
++	atomic_t *refcnts = NULL;
++	struct coresight_device *csdev;
++	struct coresight_connection *conns;
++
++	csdev = kzalloc(sizeof(*csdev), GFP_KERNEL);
++	if (!csdev) {
++		ret = -ENOMEM;
++		goto err_kzalloc_csdev;
++	}
++
++	if (desc->type == CORESIGHT_DEV_TYPE_LINK ||
++	    desc->type == CORESIGHT_DEV_TYPE_LINKSINK) {
++		link_subtype = desc->subtype.link_subtype;
++
++		if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG)
++			nr_refcnts = desc->pdata->nr_inport;
++		else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT)
++			nr_refcnts = desc->pdata->nr_outport;
++	}
++
++	refcnts = kcalloc(nr_refcnts, sizeof(*refcnts), GFP_KERNEL);
++	if (!refcnts) {
++		ret = -ENOMEM;
++		goto err_kzalloc_refcnts;
++	}
++
++	csdev->refcnt = refcnts;
++
++	csdev->nr_inport = desc->pdata->nr_inport;
++	csdev->nr_outport = desc->pdata->nr_outport;
++	conns = kcalloc(csdev->nr_outport, sizeof(*conns), GFP_KERNEL);
++	if (!conns) {
++		ret = -ENOMEM;
++		goto err_kzalloc_conns;
++	}
++
++	for (i = 0; i < csdev->nr_outport; i++) {
++		conns[i].outport = desc->pdata->outports[i];
++		conns[i].child_name = desc->pdata->child_names[i];
++		conns[i].child_port = desc->pdata->child_ports[i];
++	}
++
++	csdev->conns = conns;
++
++	csdev->type = desc->type;
++	csdev->subtype = desc->subtype;
++	csdev->ops = desc->ops;
++	csdev->orphan = false;
++
++	csdev->dev.type = &coresight_dev_type[desc->type];
++	csdev->dev.groups = desc->groups;
++	csdev->dev.parent = desc->dev;
++	csdev->dev.release = coresight_device_release;
++	csdev->dev.bus = &coresight_bustype;
++	dev_set_name(&csdev->dev, "%s", desc->pdata->name);
++
++	ret = device_register(&csdev->dev);
++	if (ret)
++		goto err_device_register;
++
++	mutex_lock(&coresight_mutex);
++
++	coresight_fixup_device_conns(csdev);
++	coresight_fixup_orphan_conns(csdev);
++
++	mutex_unlock(&coresight_mutex);
++
++	return csdev;
++
++err_device_register:
++	kfree(conns);
++err_kzalloc_conns:
++	kfree(refcnts);
++err_kzalloc_refcnts:
++	kfree(csdev);
++err_kzalloc_csdev:
++	return ERR_PTR(ret);
++}
++EXPORT_SYMBOL_GPL(coresight_register);
++
++void coresight_unregister(struct coresight_device *csdev)
++{
++	mutex_lock(&coresight_mutex);
++
++	kfree(csdev->conns);
++	device_unregister(&csdev->dev);
++
++	mutex_unlock(&coresight_mutex);
++}
++EXPORT_SYMBOL_GPL(coresight_unregister);
++
++MODULE_LICENSE("GPL v2");
+diff --git a/drivers/hwtracing/coresight/of_coresight.c b/drivers/hwtracing/coresight/of_coresight.c
+new file mode 100644
+index 0000000..f3cc8e9
+--- /dev/null
++++ b/drivers/hwtracing/coresight/of_coresight.c
+@@ -0,0 +1,200 @@
++/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/err.h>
++#include <linux/slab.h>
++#include <linux/clk.h>
++#include <linux/of.h>
++#include <linux/of_address.h>
++#include <linux/of_graph.h>
++#include <linux/of_platform.h>
++#include <linux/platform_device.h>
++#include <linux/amba/bus.h>
++#include <linux/coresight.h>
++#include <linux/cpumask.h>
++#include <asm/smp_plat.h>
++
++
++static int of_dev_node_match(struct device *dev, void *data)
++{
++	return dev->of_node == data;
++}
++
++static struct device *
++of_coresight_get_endpoint_device(struct device_node *endpoint)
++{
++	struct device *dev = NULL;
++
++	/*
++	 * If we have a non-configuable replicator, it will be found on the
++	 * platform bus.
++	 */
++	dev = bus_find_device(&platform_bus_type, NULL,
++			      endpoint, of_dev_node_match);
++	if (dev)
++		return dev;
++
++	/*
++	 * We have a configurable component - circle through the AMBA bus
++	 * looking for the device that matches the endpoint node.
++	 */
++	return bus_find_device(&amba_bustype, NULL,
++			       endpoint, of_dev_node_match);
++}
++
++static struct device_node *of_get_coresight_endpoint(
++		const struct device_node *parent, struct device_node *prev)
++{
++	struct device_node *node = of_graph_get_next_endpoint(parent, prev);
++
++	of_node_put(prev);
++	return node;
++}
++
++static void of_coresight_get_ports(struct device_node *node,
++				   int *nr_inport, int *nr_outport)
++{
++	struct device_node *ep = NULL;
++	int in = 0, out = 0;
++
++	do {
++		ep = of_get_coresight_endpoint(node, ep);
++		if (!ep)
++			break;
++
++		if (of_property_read_bool(ep, "slave-mode"))
++			in++;
++		else
++			out++;
++
++	} while (ep);
++
++	*nr_inport = in;
++	*nr_outport = out;
++}
++
++static int of_coresight_alloc_memory(struct device *dev,
++			struct coresight_platform_data *pdata)
++{
++	/* List of output port on this component */
++	pdata->outports = devm_kzalloc(dev, pdata->nr_outport *
++				       sizeof(*pdata->outports),
++				       GFP_KERNEL);
++	if (!pdata->outports)
++		return -ENOMEM;
++
++	/* Children connected to this component via @outports */
++	 pdata->child_names = devm_kzalloc(dev, pdata->nr_outport *
++					  sizeof(*pdata->child_names),
++					  GFP_KERNEL);
++	if (!pdata->child_names)
++		return -ENOMEM;
++
++	/* Port number on the child this component is connected to */
++	pdata->child_ports = devm_kzalloc(dev, pdata->nr_outport *
++					  sizeof(*pdata->child_ports),
++					  GFP_KERNEL);
++	if (!pdata->child_ports)
++		return -ENOMEM;
++
++	return 0;
++}
++
++struct coresight_platform_data *of_get_coresight_platform_data(
++				struct device *dev, struct device_node *node)
++{
++	int i = 0, ret = 0, cpu;
++	struct coresight_platform_data *pdata;
++	struct of_endpoint endpoint, rendpoint;
++	struct device *rdev;
++	struct device_node *dn;
++	struct device_node *ep = NULL;
++	struct device_node *rparent = NULL;
++	struct device_node *rport = NULL;
++
++	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
++	if (!pdata)
++		return ERR_PTR(-ENOMEM);
++
++	/* Use device name as sysfs handle */
++	pdata->name = dev_name(dev);
++
++	/* Get the number of input and output port for this component */
++	of_coresight_get_ports(node, &pdata->nr_inport, &pdata->nr_outport);
++
++	if (pdata->nr_outport) {
++		ret = of_coresight_alloc_memory(dev, pdata);
++		if (ret)
++			return ERR_PTR(ret);
++
++		/* Iterate through each port to discover topology */
++		do {
++			/* Get a handle on a port */
++			ep = of_get_coresight_endpoint(node, ep);
++			if (!ep)
++				break;
++
++			/*
++			 * No need to deal with input ports, processing for as
++			 * processing for output ports will deal with them.
++			 */
++			if (of_find_property(ep, "slave-mode", NULL))
++				continue;
++
++			/* Get a handle on the local endpoint */
++			ret = of_graph_parse_endpoint(ep, &endpoint);
++
++			if (ret)
++				continue;
++
++			/* The local out port number */
++			pdata->outports[i] = endpoint.id;
++
++			/*
++			 * Get a handle on the remote port and parent
++			 * attached to it.
++			 */
++			rparent = of_graph_get_remote_port_parent(ep);
++			rport = of_graph_get_remote_port(ep);
++
++			if (!rparent || !rport)
++				continue;
++
++			if (of_graph_parse_endpoint(rport, &rendpoint))
++				continue;
++
++			rdev = of_coresight_get_endpoint_device(rparent);
++			if (!rdev)
++				continue;
++
++			pdata->child_names[i] = dev_name(rdev);
++			pdata->child_ports[i] = rendpoint.id;
++
++			i++;
++		} while (ep);
++	}
++
++	/* Affinity defaults to CPU0 */
++	pdata->cpu = 0;
++	dn = of_parse_phandle(node, "cpu", 0);
++	for (cpu = 0; dn && cpu < nr_cpu_ids; cpu++) {
++		if (dn == of_get_cpu_node(cpu, NULL)) {
++			pdata->cpu = cpu;
++			break;
++		}
++	}
++
++	return pdata;
++}
++EXPORT_SYMBOL_GPL(of_get_coresight_platform_data);
+diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
+index 917c358..cec7392 100644
+--- a/drivers/i2c/busses/Kconfig
++++ b/drivers/i2c/busses/Kconfig
+@@ -501,6 +501,16 @@ config I2C_GPIO
+ 	  This is a very simple bitbanging I2C driver utilizing the
+ 	  arch-neutral GPIO API to control the SCL and SDA lines.
+ 
++config I2C_HIBVT
++	tristate "Hisilicon BVT I2C Controller"
++	depends on ARCH_HISI
++	help
++	  Say Y here to include support for Hisilicon BVT I2C controller in the
++	  Hisilicon BVT SoCs.
++
++	  This driver can also be built as a module.  If so, the module
++	  will be called i2c-hibvt.
++
+ config I2C_HIGHLANDER
+ 	tristate "Highlander FPGA SMBus interface"
+ 	depends on SH_HIGHLANDER
+@@ -513,6 +523,16 @@ config I2C_HIGHLANDER
+ 	  This driver can also be built as a module.  If so, the module
+ 	  will be called i2c-highlander.
+ 
++config I2C_HISI_V110
++	  tristate "Hisilicon I2C V110 Controller"
++	  depends on ARCH_HISI
++	  help
++	    Say Y here to include support for Hisilicon I2C V110 controller in the
++	    Hisilicon BVT SoCs.
++
++	    This driver can also be built as a module.  If so, the module
++	    will be called i2c-hisiv110.
++
+ config I2C_IBM_IIC
+ 	tristate "IBM PPC 4xx on-chip I2C interface"
+ 	depends on 4xx
+@@ -1044,4 +1064,84 @@ config SCx200_ACB
+ 	  This support is also available as a module.  If so, the module
+ 	  will be called scx200_acb.
+ 
++config HI_I2C
++	tristate "Hisilicon I2C Controller support"
++	depends on (ARCH_HI3519 || ARCH_HI3531D || ARCH_HI3521D || ARCH_HI3536C)
++	help
++	  Hisilicon I2C controller has 3 buses.
++	  We can access some sensors though it.
++	  This IP is only used in HI3519/HI3531D/HI3521D/HI3536C chip.
++
++if HI_I2C
++config HI_I2C0_IO_BASE
++	hex "hi i2c0 register base address"
++	default "0x12110000" if ARCH_HI3519
++	default "0x120c0000" if (ARCH_HI3531D || ARCH_HI3521D || ARCH_HI3536C)
++
++config HI_I2C0_IO_SIZE
++	hex "hi i2c0 register size"
++	default "0x1000" if (ARCH_HI3519 || ARCH_HI3531D || ARCH_HI3521D|| ARCH_HI3536C)
++
++config HI_I2C1_IO_BASE
++	hex "hi i2c1 register base address"
++	depends on (ARCH_HI3519 || ARCH_HI3531D)
++	default "0x12111000" if ARCH_HI3519
++	default "0x122e0000" if ARCH_HI3531D
++
++config HI_I2C1_IO_SIZE
++	hex "hi i2c1 register size"
++	depends on (ARCH_HI3519 || ARCH_HI3531D)
++	default "0x1000" if (ARCH_HI3519 || ARCH_HI3531D)
++
++config HI_I2C2_IO_BASE
++	hex "hi i2c2 register base address"
++	depends on ARCH_HI3519
++	default "0x12112000" if ARCH_HI3519
++
++config HI_I2C2_IO_SIZE
++	hex "hi i2c2 register size"
++	depends on ARCH_HI3519
++	default "0x1000" if ARCH_HI3519
++
++config HI_I2C3_IO_BASE
++	hex "hi i2c3 register base address"
++	depends on ARCH_HI3519
++	default "0x12113000" if ARCH_HI3519
++
++config HI_I2C3_IO_SIZE
++	hex "hi i2c3 register size"
++	depends on ARCH_HI3519
++	default "0x1000" if ARCH_HI3519
++
++config HI_I2C_RETRIES
++	hex "hi i2c retry times"
++	default "0x1" if (ARCH_HI3519 || ARCH_HI3531D || ARCH_HI3521D || ARCH_HI3536C)
++
++config HI_I2C_TX_FIFO
++	hex "hi i2c tx fifo"
++	default "0x8" if (ARCH_HI3519 || ARCH_HI3531D || ARCH_HI3521D || ARCH_HI3536C)
++
++config HI_I2C_RX_FIFO
++	hex "hi i2c rx fifo"
++	default "0x8" if (ARCH_HI3519 || ARCH_HI3531D || ARCH_HI3521D || ARCH_HI3536C)
++
++config HI_I2C0_CLK_LIMIT
++	int "hi i2c0 clock limit"
++	default "100000" if (ARCH_HI3519 || ARCH_HI3531D || ARCH_HI3521D || ARCH_HI3536C)
++
++config HI_I2C1_CLK_LIMIT
++	int "hi i2c1 clock limit"
++	depends on (ARCH_HI3519 || ARCH_HI3531D)
++	default "100000" if (ARCH_HI3519 || ARCH_HI3531D)
++
++config HI_I2C2_CLK_LIMIT
++	int "hi i2c2 clock limit"
++	depends on ARCH_HI3519
++	default "100000" if ARCH_HI3519
++
++config HI_I2C3_CLK_LIMIT
++	int "hi i2c3 clock limit"
++	depends on ARCH_HI3519
++	default "100000" if ARCH_HI3519
++endif
+ endmenu
+diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
+index 78d56c5..bdc2c01 100644
+--- a/drivers/i2c/busses/Makefile
++++ b/drivers/i2c/busses/Makefile
+@@ -47,7 +47,9 @@ obj-$(CONFIG_I2C_EFM32)		+= i2c-efm32.o
+ obj-$(CONFIG_I2C_EG20T)		+= i2c-eg20t.o
+ obj-$(CONFIG_I2C_EXYNOS5)	+= i2c-exynos5.o
+ obj-$(CONFIG_I2C_GPIO)		+= i2c-gpio.o
++obj-$(CONFIG_I2C_HIBVT)		+= i2c-hibvt.o
+ obj-$(CONFIG_I2C_HIGHLANDER)	+= i2c-highlander.o
++obj-$(CONFIG_I2C_HISI_V110)     += i2c-hisi-v110.o
+ obj-$(CONFIG_I2C_HIX5HD2)	+= i2c-hix5hd2.o
+ obj-$(CONFIG_I2C_IBM_IIC)	+= i2c-ibm_iic.o
+ obj-$(CONFIG_I2C_IMX)		+= i2c-imx.o
+@@ -103,4 +105,5 @@ obj-$(CONFIG_I2C_PCA_ISA)	+= i2c-pca-isa.o
+ obj-$(CONFIG_I2C_SIBYTE)	+= i2c-sibyte.o
+ obj-$(CONFIG_SCx200_ACB)	+= scx200_acb.o
+ 
++obj-$(CONFIG_HI_I2C)		+= i2c-hisilicon.o
+ ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG
+diff --git a/drivers/i2c/busses/i2c-hibvt.c b/drivers/i2c/busses/i2c-hibvt.c
+new file mode 100644
+index 0000000..478478b
+--- /dev/null
++++ b/drivers/i2c/busses/i2c-hibvt.c
+@@ -0,0 +1,920 @@
++/*
++ * Hisilicon BVT I2C Controller Driver
++ *
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * Authors: wenpan@hisilicon.com
++ *
++ * This program is free software; you can redistribute  it and/or modify it
++ * under  the terms of  the GNU General Public License as published by the
++ * Free Software Foundation;  either version 2 of the  License, or (at your
++ * option) any later version.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include <linux/clk.h>
++#include <linux/delay.h>
++#include <linux/i2c.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++
++/*
++ * I2C Registers offsets
++ */
++#define HIBVT_I2C_GLB		0x0
++#define HIBVT_I2C_SCL_H		0x4
++#define HIBVT_I2C_SCL_L		0x8
++#define HIBVT_I2C_DATA1		0x10
++#define HIBVT_I2C_TXF		0x20
++#define HIBVT_I2C_RXF		0x24
++#define HIBVT_I2C_CMD_BASE	0x30
++#define HIBVT_I2C_LOOP1		0xb0
++#define HIBVT_I2C_DST1		0xb4
++#define HIBVT_I2C_TX_WATER	0xc8
++#define HIBVT_I2C_RX_WATER	0xcc
++#define HIBVT_I2C_CTRL1		0xd0
++#define HIBVT_I2C_CTRL2		0xd4
++#define HIBVT_I2C_STAT		0xd8
++#define HIBVT_I2C_INTR_RAW	0xe0
++#define HIBVT_I2C_INTR_EN	0xe4
++#define HIBVT_I2C_INTR_STAT	0xe8
++
++/*
++ * I2C Global Config Register -- HIBVT_I2C_GLB
++ */
++#define GLB_EN_MASK		BIT(0)
++#define GLB_SDA_HOLD_MASK	GENMASK(23, 8)
++#define GLB_SDA_HOLD_SHIFT	(8)
++
++/*
++ * I2C Timing CMD Register -- HIBVT_I2C_CMD_BASE + n * 4 (n = 0, 1, 2, ... 31)
++ */
++#define CMD_EXIT	0x0
++#define CMD_TX_S	0x1
++#define CMD_TX_D1_2	0x4
++#define CMD_TX_D1_1	0x5
++#define CMD_TX_FIFO	0x9
++#define CMD_RX_FIFO	0x12
++#define CMD_RX_ACK	0x13
++#define CMD_IGN_ACK	0x15
++#define CMD_TX_ACK	0x16
++#define CMD_TX_NACK	0x17
++#define CMD_JMP1	0x18
++#define CMD_UP_TXF	0x1d
++#define CMD_TX_RS	0x1e
++#define CMD_TX_P	0x1f
++
++/*
++ * I2C Control Register 1 -- HIBVT_I2C_CTRL1
++ */
++#define CTRL1_CMD_START_MASK	BIT(0)
++
++/*
++ * I2C Status Register -- HIBVT_I2C_STAT
++ */
++#define STAT_RXF_NOE_MASK	BIT(16) /* RX FIFO not empty flag */
++#define STAT_TXF_NOF_MASK	BIT(19) /* TX FIFO not full flag */
++
++
++/*
++ * I2C Interrupt status and mask Register --
++ * HIBVT_I2C_INTR_RAW, HIBVT_I2C_STAT, HIBVT_I2C_INTR_STAT
++ */
++#define INTR_ABORT_MASK		(BIT(0) | BIT(11))
++#define INTR_RX_MASK		BIT(2)
++#define INTR_TX_MASK		BIT(4)
++#define INTR_CMD_DONE_MASK	BIT(12)
++#define INTR_USE_MASK		(INTR_ABORT_MASK \
++				|INTR_RX_MASK \
++				| INTR_TX_MASK \
++				| INTR_CMD_DONE_MASK)
++#define INTR_ALL_MASK		GENMASK(31, 0)
++
++#define I2C_DEFAULT_FREQUENCY	100000
++#define I2C_TXF_DEPTH		64
++#define I2C_RXF_DEPTH		64
++#define I2C_TXF_WATER		32
++#define I2C_RXF_WATER		32
++#define I2C_WAIT_TIMEOUT	0x10000
++#define I2C_IRQ_TIMEOUT		(msecs_to_jiffies(1000))
++
++
++struct hibvt_i2c_dev {
++	struct device		*dev;
++	struct i2c_adapter	adap;
++	void __iomem		*base;
++	struct clk		*clk;
++	int			irq;
++
++	unsigned int		freq;
++	struct i2c_msg		*msg;
++	unsigned int		msg_num;
++	unsigned int		msg_idx;
++	unsigned int		msg_buf_ptr;
++	struct completion	msg_complete;
++
++	spinlock_t		lock;
++	int			status;
++};
++static inline void hibvt_i2c_disable(struct hibvt_i2c_dev *i2c);
++static inline void hibvt_i2c_cfg_irq(struct hibvt_i2c_dev *i2c,
++		unsigned int flag);
++static inline unsigned int hibvt_i2c_clr_irq(struct hibvt_i2c_dev *i2c);
++static inline void hibvt_i2c_enable(struct hibvt_i2c_dev *i2c);
++
++#define CHECK_SDA_IN_SHIFT     (16)
++#define GPIO_MODE_SHIFT        (8)
++#define FORCE_SCL_OEN_SHIFT    (4)
++#define FORCE_SDA_OEN_SHIFT    (0)
++
++static void hibvt_i2c_rescue(struct hibvt_i2c_dev *i2c)
++{
++	unsigned int val;
++	unsigned int time_cnt;
++	int index;
++
++	hibvt_i2c_disable(i2c);
++	hibvt_i2c_cfg_irq(i2c, 0);
++	hibvt_i2c_clr_irq(i2c);
++
++	val = (0x1 << GPIO_MODE_SHIFT) | (0x1 << FORCE_SCL_OEN_SHIFT) | (0x1 << FORCE_SDA_OEN_SHIFT);
++	writel(val, i2c->base + HIBVT_I2C_CTRL2);
++
++	time_cnt = 0;
++	do {
++		for (index = 0; index < 9; index++) {
++			val = (0x1 << GPIO_MODE_SHIFT) | 0x1;
++			writel(val, i2c->base + HIBVT_I2C_CTRL2);
++
++			udelay(5);
++
++			val = (0x1 << GPIO_MODE_SHIFT) | (0x1 << FORCE_SCL_OEN_SHIFT) | (0x1 << FORCE_SDA_OEN_SHIFT);
++			writel(val, i2c->base + HIBVT_I2C_CTRL2);
++
++			udelay(5);
++		}
++
++		time_cnt++;
++		if (time_cnt > I2C_WAIT_TIMEOUT) {
++			dev_err(i2c->dev, "wait Timeout!\n");
++			goto disable_rescue;
++		}
++
++		val = readl(i2c->base + HIBVT_I2C_CTRL2);
++	} while(!(val & (0x1 << CHECK_SDA_IN_SHIFT)));
++
++
++	val = (0x1 << GPIO_MODE_SHIFT) | (0x1 << FORCE_SCL_OEN_SHIFT) | (0x1 << FORCE_SDA_OEN_SHIFT);
++	writel(val, i2c->base + HIBVT_I2C_CTRL2);
++
++	val = (0x1 << GPIO_MODE_SHIFT) | (0x1 << FORCE_SCL_OEN_SHIFT);
++	writel(val, i2c->base + HIBVT_I2C_CTRL2);
++
++	udelay(10);
++
++	val = (0x1 << GPIO_MODE_SHIFT) | (0x1 << FORCE_SCL_OEN_SHIFT) | (0x1 << FORCE_SDA_OEN_SHIFT);
++	writel(val, i2c->base + HIBVT_I2C_CTRL2);
++
++disable_rescue:
++	val = (0x1 << FORCE_SCL_OEN_SHIFT) | 0x1;
++	writel(val, i2c->base + HIBVT_I2C_CTRL2);
++}
++
++static inline void hibvt_i2c_disable(struct hibvt_i2c_dev *i2c)
++{
++	unsigned int val;
++
++	val = readl(i2c->base + HIBVT_I2C_GLB);
++	val &= ~GLB_EN_MASK;
++	writel(val, i2c->base + HIBVT_I2C_GLB);
++}
++
++static inline void hibvt_i2c_enable(struct hibvt_i2c_dev *i2c)
++{
++	unsigned int val;
++
++	val = readl(i2c->base + HIBVT_I2C_GLB);
++	val |= GLB_EN_MASK;
++	writel(val, i2c->base + HIBVT_I2C_GLB);
++}
++
++static inline void hibvt_i2c_cfg_irq(struct hibvt_i2c_dev *i2c,
++		unsigned int flag)
++{
++	writel(flag, i2c->base + HIBVT_I2C_INTR_EN);
++}
++
++static inline void hibvt_i2c_disable_irq(struct hibvt_i2c_dev *i2c,
++		unsigned int flag)
++{
++	unsigned int val;
++
++	val = readl(i2c->base + HIBVT_I2C_INTR_EN);
++	val &= ~flag;
++	writel(val, i2c->base + HIBVT_I2C_INTR_EN);
++}
++
++static inline unsigned int hibvt_i2c_clr_irq(struct hibvt_i2c_dev *i2c)
++{
++	unsigned int val;
++
++	val = readl(i2c->base + HIBVT_I2C_INTR_STAT);
++	writel(INTR_ALL_MASK, i2c->base + HIBVT_I2C_INTR_RAW);
++
++	return val;
++}
++
++static inline void hibvt_i2c_cmdreg_set(struct hibvt_i2c_dev *i2c,
++		unsigned int cmd, unsigned int *offset)
++{
++	dev_dbg(i2c->dev, "hii2c reg: offset=0x%x, cmd=0x%x...\n",
++			*offset * 4, cmd);
++	writel(cmd, i2c->base + HIBVT_I2C_CMD_BASE + *offset * 4);
++	(*offset)++;
++}
++
++/*
++ * config i2c slave addr
++ */
++static inline void hibvt_i2c_set_addr(struct hibvt_i2c_dev *i2c)
++{
++	struct i2c_msg *msg = i2c->msg;
++	u16 addr;
++
++	if (msg->flags & I2C_M_TEN) {
++		/* First byte is 11110XX0 where XX is upper 2 bits */
++		addr = ((msg->addr & 0x300) << 1) | 0xf000;
++		if (msg->flags & I2C_M_RD)
++			addr |= 1 << 8;
++
++		/* Second byte is the remaining 8 bits */
++		addr |= msg->addr & 0xff;
++	} else {
++		addr = (msg->addr & 0x7f) << 1;
++		if (msg->flags & I2C_M_RD)
++			addr |= 1;
++	}
++
++	writel(addr, i2c->base + HIBVT_I2C_DATA1);
++}
++
++/*
++ * Start command sequence
++ */
++static inline void hibvt_i2c_start_cmd(struct hibvt_i2c_dev *i2c)
++{
++	unsigned int val;
++
++	val = readl(i2c->base + HIBVT_I2C_CTRL1);
++	val |= CTRL1_CMD_START_MASK;
++	writel(val, i2c->base + HIBVT_I2C_CTRL1);
++}
++
++static int hibvt_i2c_wait_rx_noempty(struct hibvt_i2c_dev *i2c)
++{
++	unsigned int time_cnt = 0;
++	unsigned int val;
++
++	do {
++		val = readl(i2c->base + HIBVT_I2C_STAT);
++		if (val & STAT_RXF_NOE_MASK)
++			return 0;
++
++		udelay(50);
++	} while (time_cnt++ < I2C_WAIT_TIMEOUT);
++
++	hibvt_i2c_rescue(i2c);
++
++	dev_err(i2c->dev, "wait rx no empty timeout, RIS: 0x%x, SR: 0x%x\n",
++			readl(i2c->base + HIBVT_I2C_INTR_RAW), val);
++	return -EIO;
++}
++
++static int hibvt_i2c_wait_tx_nofull(struct hibvt_i2c_dev *i2c)
++{
++	unsigned int time_cnt = 0;
++	unsigned int val;
++
++	do {
++		val = readl(i2c->base + HIBVT_I2C_STAT);
++		if (val & STAT_TXF_NOF_MASK)
++			return 0;
++
++		udelay(50);
++	} while (time_cnt++ < I2C_WAIT_TIMEOUT);
++
++	hibvt_i2c_rescue(i2c);
++
++	dev_err(i2c->dev, "wait rx no empty timeout, RIS: 0x%x, SR: 0x%x\n",
++			readl(i2c->base + HIBVT_I2C_INTR_RAW), val);
++	return -EIO;
++}
++
++static int hibvt_i2c_wait_idle(struct hibvt_i2c_dev *i2c)
++{
++	unsigned int time_cnt = 0;
++	unsigned int val;
++
++	do {
++		val = readl(i2c->base + HIBVT_I2C_INTR_RAW);
++		if (val & (INTR_ABORT_MASK)) {
++			dev_err(i2c->dev, "wait idle abort!, RIS: 0x%x\n",
++					val);
++			return -EIO;
++		}
++
++		if (val & INTR_CMD_DONE_MASK)
++			return 0;
++
++		udelay(50);
++	} while (time_cnt++ < I2C_WAIT_TIMEOUT);
++
++	hibvt_i2c_rescue(i2c);
++
++	dev_err(i2c->dev, "wait idle timeout, RIS: 0x%x, SR: 0x%x\n",
++			val, readl(i2c->base + HIBVT_I2C_STAT));
++
++	return -EIO;
++}
++
++static void hibvt_i2c_set_freq(struct hibvt_i2c_dev *i2c)
++{
++	unsigned int max_freq, freq;
++	unsigned int clk_rate;
++	unsigned int val;
++
++	freq = i2c->freq;
++	clk_rate = clk_get_rate(i2c->clk);
++	max_freq = clk_rate >> 1;
++
++	if (freq > max_freq) {
++		i2c->freq = max_freq;
++		freq = i2c->freq;
++	}
++
++	if (!freq) {
++		pr_err("hibvt_i2c_set_freq:freq can't be zero!");
++		return;
++	}
++
++	/* set SCLH and SCLL depend on clk_rate and freq */
++	if (freq <= 100000) {
++		/* in normal mode		F_scl: freq
++		   i2c_scl_hcnt = (F_i2c / F_scl) * 0.5
++		   i2c_scl_hcnt = (F_i2c / F_scl) * 0.5
++		*/
++		val = clk_rate / (freq * 2);
++		writel(val, i2c->base + HIBVT_I2C_SCL_H);
++		writel(val, i2c->base + HIBVT_I2C_SCL_L);
++	} else {
++		/* in fast mode		F_scl: freq
++		   i2c_scl_hcnt = (F_i2c / F_scl) * 0.36
++		   i2c_scl_hcnt = (F_i2c / F_scl) * 0.64
++		*/
++		val = ((clk_rate / 100) * 36) / freq;
++		writel(val, i2c->base + HIBVT_I2C_SCL_H);
++		val = ((clk_rate / 100) * 64) / freq;
++		writel(val, i2c->base + HIBVT_I2C_SCL_L);
++	}
++
++	val = readl(i2c->base + HIBVT_I2C_GLB);
++	val &= ~GLB_SDA_HOLD_MASK;
++	val |= ((0xa << GLB_SDA_HOLD_SHIFT) & GLB_SDA_HOLD_MASK);
++	writel(val, i2c->base + HIBVT_I2C_GLB);
++}
++
++/*
++ * set i2c controller TX and RX FIFO water
++ */
++static inline void hibvt_i2c_set_water(struct hibvt_i2c_dev *i2c)
++{
++	writel(I2C_TXF_WATER, i2c->base + HIBVT_I2C_TX_WATER);
++	writel(I2C_RXF_WATER, i2c->base + HIBVT_I2C_RX_WATER);
++}
++
++/*
++ * initialise the controller, set i2c bus interface freq
++ */
++static void hibvt_i2c_hw_init(struct hibvt_i2c_dev *i2c)
++{
++	hibvt_i2c_disable(i2c);
++	hibvt_i2c_disable_irq(i2c, INTR_ALL_MASK);
++	hibvt_i2c_set_freq(i2c);
++	hibvt_i2c_set_water(i2c);
++}
++
++/*
++ * hibvt_i2c_cfg_cmd - config i2c controller command sequence
++ *
++ * After all the timing command is configured,
++ * and then start the command, you can i2c communication,
++ * and then only need to read and write i2c fifo.
++ */
++static void hibvt_i2c_cfg_cmd(struct hibvt_i2c_dev *i2c)
++{
++	struct i2c_msg *msg = i2c->msg;
++	int offset = 0;
++
++	if (i2c->msg_idx == 0)
++		hibvt_i2c_cmdreg_set(i2c, CMD_TX_S, &offset);
++	else
++		hibvt_i2c_cmdreg_set(i2c, CMD_TX_RS, &offset);
++
++	if (msg->flags & I2C_M_TEN) {
++		if (i2c->msg_idx == 0) {
++			hibvt_i2c_cmdreg_set(i2c, CMD_TX_D1_2, &offset);
++			hibvt_i2c_cmdreg_set(i2c, CMD_TX_D1_1, &offset);
++		} else {
++			hibvt_i2c_cmdreg_set(i2c, CMD_TX_D1_2, &offset);
++		}
++	} else {
++		hibvt_i2c_cmdreg_set(i2c, CMD_TX_D1_1, &offset);
++	}
++
++	if (msg->flags & I2C_M_IGNORE_NAK)
++		hibvt_i2c_cmdreg_set(i2c, CMD_IGN_ACK, &offset);
++	else
++		hibvt_i2c_cmdreg_set(i2c, CMD_RX_ACK, &offset);
++
++	if (msg->flags & I2C_M_RD) {
++		if (msg->len >= 2) {
++			writel(offset, i2c->base + HIBVT_I2C_DST1);
++			writel(msg->len - 2, i2c->base + HIBVT_I2C_LOOP1);
++			hibvt_i2c_cmdreg_set(i2c, CMD_RX_FIFO, &offset);
++			hibvt_i2c_cmdreg_set(i2c, CMD_TX_ACK, &offset);
++			hibvt_i2c_cmdreg_set(i2c, CMD_JMP1, &offset);
++		}
++		hibvt_i2c_cmdreg_set(i2c, CMD_RX_FIFO, &offset);
++		hibvt_i2c_cmdreg_set(i2c, CMD_TX_NACK, &offset);
++	} else {
++		writel(offset, i2c->base + HIBVT_I2C_DST1);
++		writel(msg->len - 1, i2c->base + HIBVT_I2C_LOOP1);
++		hibvt_i2c_cmdreg_set(i2c, CMD_UP_TXF, &offset);
++		hibvt_i2c_cmdreg_set(i2c, CMD_TX_FIFO, &offset);
++
++		if (msg->flags & I2C_M_IGNORE_NAK)
++			hibvt_i2c_cmdreg_set(i2c, CMD_IGN_ACK, &offset);
++		else
++			hibvt_i2c_cmdreg_set(i2c, CMD_RX_ACK, &offset);
++
++		hibvt_i2c_cmdreg_set(i2c, CMD_JMP1, &offset);
++	}
++
++	if ((i2c->msg_idx == (i2c->msg_num - 1)) || (msg->flags & I2C_M_STOP)) {
++		dev_dbg(i2c->dev, "run to %s %d...TX STOP\n",
++				__func__, __LINE__);
++		hibvt_i2c_cmdreg_set(i2c, CMD_TX_P, &offset);
++	}
++
++	hibvt_i2c_cmdreg_set(i2c, CMD_EXIT, &offset);
++}
++
++static int hibvt_i2c_polling_xfer_one_msg(struct hibvt_i2c_dev *i2c)
++{
++	int status;
++	unsigned int val;
++	struct i2c_msg *msg = i2c->msg;
++
++	dev_dbg(i2c->dev, "[%s,%d]msg->flags=0x%x, len=0x%x\n",
++			__func__, __LINE__, msg->flags, msg->len);
++
++	hibvt_i2c_enable(i2c);
++	hibvt_i2c_clr_irq(i2c);
++	hibvt_i2c_set_addr(i2c);
++	hibvt_i2c_cfg_cmd(i2c);
++	hibvt_i2c_start_cmd(i2c);
++
++	i2c->msg_buf_ptr = 0;
++
++	if (msg->flags & I2C_M_RD) {
++		while (i2c->msg_buf_ptr < msg->len) {
++			status = hibvt_i2c_wait_rx_noempty(i2c);
++			if (status)
++				goto end;
++
++			val = readl(i2c->base + HIBVT_I2C_RXF);
++			msg->buf[i2c->msg_buf_ptr] = val;
++			i2c->msg_buf_ptr++;
++
++		}
++	} else {
++		while (i2c->msg_buf_ptr < msg->len) {
++			status = hibvt_i2c_wait_tx_nofull(i2c);
++			if (status)
++				goto end;
++
++			val = msg->buf[i2c->msg_buf_ptr];
++			writel(val, i2c->base + HIBVT_I2C_TXF);
++			i2c->msg_buf_ptr++;
++		}
++	}
++
++	status = hibvt_i2c_wait_idle(i2c);
++end:
++	hibvt_i2c_disable(i2c);
++
++	return status;
++}
++
++static irqreturn_t hibvt_i2c_isr(int irq, void *dev_id)
++{
++	struct hibvt_i2c_dev *i2c = dev_id;
++	unsigned int irq_status;
++	struct i2c_msg *msg = i2c->msg;
++
++	spin_lock(&i2c->lock);
++
++	irq_status = hibvt_i2c_clr_irq(i2c);
++	dev_dbg(i2c->dev, "%s RIS:  0x%x\n", __func__, irq_status);
++
++	if (!irq_status) {
++		dev_dbg(i2c->dev, "no irq\n");
++		goto end;
++	}
++
++	if (irq_status & INTR_ABORT_MASK) {
++		dev_err(i2c->dev, "irq handle abort, RIS: 0x%x\n",
++				irq_status);
++		i2c->status = -EIO;
++		hibvt_i2c_disable_irq(i2c, INTR_ALL_MASK);
++
++		complete(&i2c->msg_complete);
++		goto end;
++	}
++
++	if (msg->flags & I2C_M_RD) {
++		while ((readl(i2c->base + HIBVT_I2C_STAT) & STAT_RXF_NOE_MASK)
++				&& (i2c->msg_buf_ptr < msg->len)) {
++			msg->buf[i2c->msg_buf_ptr] =
++				readl(i2c->base + HIBVT_I2C_RXF);
++			i2c->msg_buf_ptr++;
++		}
++	} else {
++		while ((readl(i2c->base + HIBVT_I2C_STAT) & STAT_TXF_NOF_MASK)
++				&& (i2c->msg_buf_ptr < msg->len)) {
++			writel(msg->buf[i2c->msg_buf_ptr],
++					i2c->base + HIBVT_I2C_TXF);
++			i2c->msg_buf_ptr++;
++		}
++	}
++
++	if (i2c->msg_buf_ptr >= msg->len)
++		hibvt_i2c_disable_irq(i2c, INTR_TX_MASK | INTR_RX_MASK);
++
++	if (irq_status & INTR_CMD_DONE_MASK) {
++		dev_dbg(i2c->dev, "cmd done\n");
++		i2c->status =  0;
++		hibvt_i2c_disable_irq(i2c, INTR_ALL_MASK);
++
++		complete(&i2c->msg_complete);
++	}
++
++end:
++	spin_unlock(&i2c->lock);
++
++	return IRQ_HANDLED;
++}
++
++static int hibvt_i2c_interrupt_xfer_one_msg(struct hibvt_i2c_dev *i2c)
++{
++	int status;
++	struct i2c_msg *msg = i2c->msg;
++	unsigned long timeout;
++	unsigned long flags;
++
++	dev_dbg(i2c->dev, "[%s,%d]msg->flags=0x%x, len=0x%x\n",
++			__func__, __LINE__, msg->flags, msg->len);
++
++	reinit_completion(&i2c->msg_complete);
++	i2c->msg_buf_ptr = 0;
++	i2c->status = -EIO;
++
++	spin_lock_irqsave(&i2c->lock, flags);
++	hibvt_i2c_enable(i2c);
++	hibvt_i2c_clr_irq(i2c);
++	if (msg->flags & I2C_M_RD)
++		hibvt_i2c_cfg_irq(i2c, INTR_USE_MASK & ~INTR_TX_MASK);
++	else
++		hibvt_i2c_cfg_irq(i2c, INTR_USE_MASK & ~INTR_RX_MASK);
++
++	hibvt_i2c_set_addr(i2c);
++	hibvt_i2c_cfg_cmd(i2c);
++	hibvt_i2c_start_cmd(i2c);
++	spin_unlock_irqrestore(&i2c->lock, flags);
++
++	timeout = wait_for_completion_timeout(&i2c->msg_complete,
++			I2C_IRQ_TIMEOUT);
++
++	if (timeout == 0) {
++		hibvt_i2c_disable_irq(i2c, INTR_ALL_MASK);
++		status = -EIO;
++		dev_err(i2c->dev, "%s timeout\n",
++			 msg->flags & I2C_M_RD ? "rx" : "tx");
++	} else {
++		status = i2c->status;
++	}
++
++	hibvt_i2c_disable(i2c);
++
++	return status;
++}
++
++/*
++ * Master transfer function
++ */
++static int hibvt_i2c_xfer(struct i2c_adapter *adap,
++			struct i2c_msg *msgs, int num)
++{
++	struct hibvt_i2c_dev *i2c = i2c_get_adapdata(adap);
++	int status = -EINVAL;
++	unsigned long flags;
++
++	if (!msgs || (num <= 0)) {
++		dev_err(i2c->dev, "msgs == NULL || num <= 0, Invalid argument!\n");
++		return -EINVAL;
++	}
++
++	spin_lock_irqsave(&i2c->lock, flags);
++
++	i2c->msg = msgs;
++	i2c->msg_num = num;
++	i2c->msg_idx = 0;
++
++	/* FIXME: The wait_for_completion_timeout in hibvt_i2c_interrupt_xfer_one_msg
++	 * function can not be locked by spin_lock_irqsave. And actually I2C interrupt
++	 * tranfer is rarely used, so we ignore the irq setting to limit the interrupt
++	 * way. But we keep these codes below, reserve for future modifications */
++	i2c->irq = -1;
++
++	if (i2c->irq >= 0) {
++		while (i2c->msg_idx < i2c->msg_num) {
++			status = hibvt_i2c_interrupt_xfer_one_msg(i2c);
++			if (status)
++				break;
++
++			i2c->msg++;
++			i2c->msg_idx++;
++		}
++	} else {
++		while (i2c->msg_idx < i2c->msg_num) {
++			status = hibvt_i2c_polling_xfer_one_msg(i2c);
++			if (status)
++				break;
++
++			i2c->msg++;
++			i2c->msg_idx++;
++		}
++	}
++
++	if (!status || i2c->msg_idx > 0)
++		status = i2c->msg_idx;
++
++	spin_unlock_irqrestore(&i2c->lock, flags);
++
++	return status;
++}
++
++/* HI I2C READ *
++ * hi_i2c_master_recv - issue a single I2C message in master receive mode
++ * @client: Handle to slave device
++ * @buf: Where to store data read from slave
++ * @count: How many bytes to read, must be less than 64k since msg.len is u16
++ *
++ * Returns negative errno, or else the number of bytes read.
++ */
++int hi_i2c_master_recv(const struct i2c_client *client, char *buf,
++		        int count)
++{
++	printk("Wrong interface call."
++			"hi_i2c_transfer is the only interface to i2c read!!!\n");
++
++	return -EIO;
++}
++EXPORT_SYMBOL(hi_i2c_master_recv);
++
++/*HI I2C WRITE*
++ * hi_i2c_master_send - issue a single I2C message in master transmit mode
++ * @client: Handle to slave device
++ * @buf: Data that will be written to the slave
++ * @count: How many bytes to write, must be less than 64k since msg.len is u16
++ *
++ * Returns negative errno, or else the number of bytes written.
++ */
++int hi_i2c_master_send(const struct i2c_client *client,
++		const char *buf, int count)
++{
++	struct i2c_adapter *adap = client->adapter;
++	struct i2c_msg msg;
++	int msgs_count;
++
++	if ((client->addr > 0x3ff)
++		|| (((client->flags & I2C_M_TEN) == 0) && (client->addr > 0x7f))) {
++		printk(KERN_ERR "dev address out of range\n");
++		return -EINVAL;
++	}
++
++	msg.addr = client->addr;
++	msg.flags = client->flags;
++	msg.len = count;
++
++	if (!buf) {
++		printk(KERN_ERR "Invalid buf == NULL!!!\n");
++		return -EINVAL;
++	}
++	msg.buf = (__u8 *)buf;
++
++	msgs_count = hibvt_i2c_xfer(adap, &msg, 1);
++
++	return (msgs_count == 1) ? count : -EIO;
++}
++EXPORT_SYMBOL(hi_i2c_master_send);
++
++/**
++ * hi_i2c_transfer - execute a single or combined I2C message
++ * @adap: Handle to I2C bus
++ * @msgs: One or more messages to execute before STOP is issued to
++ *  terminate the operation; each message begins with a START.
++ * @num: Number of messages to be executed.
++ *
++ * Returns negative errno, else the number of messages executed.
++ *
++ * Note that there is no requirement that each message be sent to
++ * the same slave address, although that is the most common model.
++ */
++int hi_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
++		int num)
++{
++	int msgs_count;
++
++	if ((msgs[0].addr > 0x3ff)
++		|| (((msgs[0].flags & I2C_M_TEN) == 0) && (msgs[0].addr > 0x7f))) {
++		printk(KERN_ERR "msgs[0] dev address out of range\n");
++		return -EINVAL;
++	}
++
++	if ((msgs[1].addr > 0x3ff)
++		|| (((msgs[1].flags & I2C_M_TEN) == 0) && (msgs[1].addr > 0x7f))) {
++		printk(KERN_ERR "msgs[1] dev address out of range\n");
++		return -EINVAL;
++	}
++
++	msgs_count = hibvt_i2c_xfer(adap, msgs, num);
++
++	return msgs_count;
++}
++EXPORT_SYMBOL(hi_i2c_transfer);
++
++static u32 hibvt_i2c_func(struct i2c_adapter *adap)
++{
++	return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR
++		| I2C_FUNC_PROTOCOL_MANGLING;
++}
++
++static const struct i2c_algorithm hibvt_i2c_algo = {
++	.master_xfer		= hibvt_i2c_xfer,
++	.functionality		= hibvt_i2c_func,
++};
++
++static int hibvt_i2c_probe(struct platform_device *pdev)
++{
++	int status;
++	struct hibvt_i2c_dev *i2c;
++	struct i2c_adapter *adap;
++	struct resource *res;
++
++	i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
++	if (!i2c)
++		return -ENOMEM;
++
++	platform_set_drvdata(pdev, i2c);
++	i2c->dev = &pdev->dev;
++	spin_lock_init(&i2c->lock);
++	init_completion(&i2c->msg_complete);
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	i2c->base = devm_ioremap_resource(&pdev->dev, res);
++	if (IS_ERR(i2c->base)) {
++		dev_err(i2c->dev, "cannot ioremap resource\n");
++		return -ENOMEM;
++	}
++
++	i2c->clk = devm_clk_get(&pdev->dev, NULL);
++	if (IS_ERR(i2c->clk)) {
++		dev_err(i2c->dev, "cannot get clock\n");
++		return -ENOENT;
++	}
++	clk_prepare_enable(i2c->clk);
++
++	if (of_property_read_u32(pdev->dev.of_node, "clock-frequency",
++				&i2c->freq)) {
++		dev_warn(i2c->dev, "setting default clock-frequency@%dHz\n",
++				I2C_DEFAULT_FREQUENCY);
++		i2c->freq = I2C_DEFAULT_FREQUENCY;
++	}
++
++	/* i2c controller initialization, disable interrupt */
++	hibvt_i2c_hw_init(i2c);
++
++	i2c->irq = platform_get_irq(pdev, 0);
++	status = devm_request_irq(&pdev->dev, i2c->irq, hibvt_i2c_isr,
++			IRQF_SHARED, dev_name(&pdev->dev), i2c);
++	if (status) {
++		dev_dbg(i2c->dev, "falling back to polling mode");
++		i2c->irq = -1;
++	}
++
++	adap = &i2c->adap;
++	i2c_set_adapdata(adap, i2c);
++	adap->owner = THIS_MODULE;
++	strlcpy(adap->name, "hibvt-i2c", sizeof(adap->name));
++	adap->dev.parent = &pdev->dev;
++	adap->dev.of_node = pdev->dev.of_node;
++	adap->algo = &hibvt_i2c_algo;
++
++	/* Add the i2c adapter */
++	status = i2c_add_adapter(adap);
++	if (status) {
++		dev_err(i2c->dev, "failed to add bus to i2c core\n");
++		goto err_add_adapter;
++	}
++
++	dev_info(i2c->dev, "%s%d@%dhz registered\n",
++			adap->name, adap->nr, i2c->freq);
++
++	return 0;
++
++err_add_adapter:
++	clk_disable_unprepare(i2c->clk);
++	return status;
++}
++
++static int hibvt_i2c_remove(struct platform_device *pdev)
++{
++	struct hibvt_i2c_dev *i2c = platform_get_drvdata(pdev);
++
++	clk_disable_unprepare(i2c->clk);
++	i2c_del_adapter(&i2c->adap);
++
++	return 0;
++}
++
++#ifdef CONFIG_PM_SLEEP
++static int hibvt_i2c_suspend(struct device *dev)
++{
++	struct hibvt_i2c_dev *i2c = dev_get_drvdata(dev);
++
++	i2c_lock_adapter(&i2c->adap);
++	clk_disable_unprepare(i2c->clk);
++	i2c_unlock_adapter(&i2c->adap);
++
++	return 0;
++}
++
++static int hibvt_i2c_resume(struct device *dev)
++{
++	struct hibvt_i2c_dev *i2c = dev_get_drvdata(dev);
++
++	i2c_lock_adapter(&i2c->adap);
++	clk_prepare_enable(i2c->clk);
++	hibvt_i2c_hw_init(i2c);
++	i2c_unlock_adapter(&i2c->adap);
++
++	return 0;
++}
++#endif
++
++static SIMPLE_DEV_PM_OPS(hibvt_i2c_dev_pm, hibvt_i2c_suspend,
++		hibvt_i2c_resume);
++
++static const struct of_device_id hibvt_i2c_match[] = {
++	{ .compatible = "hisilicon,hibvt-i2c"},
++	{ .compatible = "hisilicon,hi3516cv300-i2c"},
++	{},
++};
++MODULE_DEVICE_TABLE(of, hibvt_i2c_match);
++
++static struct platform_driver hibvt_i2c_driver = {
++	.driver		= {
++		.name	= "hibvt-i2c",
++		.of_match_table = hibvt_i2c_match,
++		.pm	= &hibvt_i2c_dev_pm,
++	},
++	.probe		= hibvt_i2c_probe,
++	.remove		= hibvt_i2c_remove,
++};
++
++module_platform_driver(hibvt_i2c_driver);
++
++MODULE_AUTHOR("Pan Wen, <wenpan@hisilicon.com>");
++MODULE_DESCRIPTION("HISILICON BVT I2C Bus driver");
++MODULE_LICENSE("GPL v2");
+diff --git a/drivers/i2c/busses/i2c-hisi-v110.c b/drivers/i2c/busses/i2c-hisi-v110.c
+new file mode 100644
+index 0000000..9e0e4ba
+--- /dev/null
++++ b/drivers/i2c/busses/i2c-hisi-v110.c
+@@ -0,0 +1,1263 @@
++/*
++ * Hisilicon BVT I2C Controller Driver
++ *
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include <linux/clk.h>
++#include <linux/delay.h>
++#include <linux/dma-mapping.h>
++#include <linux/i2c.h>
++#include <linux/io.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++
++#ifdef CONFIG_HI_DMAC
++#include <linux/hidmac.h>
++#include <mach/io.h>
++#endif
++
++/*
++ * I2C Registers offsets
++ */
++#define HII2C_CR		0x00
++#define HII2C_TAR		0x04
++#define I2C_DATA_CMD_REG	0x010
++#define HII2C_SCL_H		0x1C
++#define HII2C_SCL_L		0x20
++#define HII2C_IM		0x30
++#define HII2C_RI		0x34
++#define HII2C_IC		0x40
++#define HII2C_EN		0x6C
++#define HII2C_SR		0x70
++#define HII2C_SDA_HOLD		0x7C
++#define HII2C_TX_ABRT		0x80
++#define I2C_DMA_CTRL_REG	0x088
++#define I2C_DMA_TDLR		0x08C
++#define I2C_DMA_RDLR		0x090
++#define HII2C_LOCK		0xAC
++#define HII2C_CR1		0xB0
++#define HII2C_DATA		0xB4
++#define HII2C_SEQU_CMD0		0xB8
++#define I2C_DMA_CMD0		0x0B8
++#define I2C_DMA_CMD1		0x0BC
++#define I2C_DMA_CMD2		0x0C0
++
++/*
++ * I2C Control Register -- HII2C_CR
++ */
++#define CR_RESTART_EN		(0x1 << 5)
++
++/*
++ * I2C Slave Address Register -- HII2C_TAR
++ */
++#define TAR_10BIT_MODE		(0x1 << 12)
++#define TAR_SPECIAL		(0x1 << 11)
++#define TAR_ADDR		(0x3ff << 0)
++#define TAR_ADDR_SHIFT		0
++
++/*
++ * I2C Interrupt status and mask Register -- HII2C_IM
++ */
++#define INT_TX_ABRT            (1 << 6)
++#define MASK_ALL_INT		0xffffffff
++
++/*
++ * I2C Status Register -- HII2C_SR
++ */
++#define SR_BUSY		(0x1 << 0)
++
++
++/*
++ * I2C Lock Register -- HII2C_LOCK
++ */
++#define UNLOCK_VALUE	0x1ACCE551
++
++/*
++ * I2C Single Control Register -- HII2C_CR1
++ */
++#define CR1_SINGLE_MODE_EN	(0x1 << 31)
++#define	CR1_READ_MODE		(0x1 << 30)
++#define CR1_H_WIDE		(0x1 << 29)
++#define CR1_L_WIDE		(0x1 << 28)
++#define	CR1_STATUS_CLR		(0xf << 24)
++#define	CR1_TX_ABRT		(0x1 << 23)
++#define	CR1_TFNF		(0x1 << 21)
++#define	CR1_TFE			(0x1 << 20)
++#define	CR1_RFF			(0x1 << 9)
++#define	CR1_RFNE		(0x1 << 8)
++
++/*
++ * I2C Single CMD Register -- HII2C_DATA
++ */
++#define DATA_H		(0xffff << 16)
++#define DATA_L		0xffff
++#define DATA_H_SHIFT	16
++#define DATA_L_SHIFT	0
++
++/*
++ * I2C Sequence CMD0 Register -- HII2C_SEQU_CMD0
++ */
++#define SEQU_MODE_EN		(0x1 << 31)
++#define SEQU_MODE_WRITE		(0x1 << 30)
++#define SEQU_ADDR_8BIT		(0x0 << 28)
++#define SEQU_ADDR_16BIT		(0x1 << 28)
++
++#define HII2C_TIMEOUT		0x400
++
++unsigned int clk_rate = 0;
++
++typedef enum i2c_mode {
++	I2C_MODE_SINGLE,
++	I2C_MODE_DMA,
++} i2c_mode_t;
++
++struct hi_i2c {
++	struct platform_device	*pdev;
++	struct i2c_adapter	*adap;
++	struct device		*dev;
++	resource_size_t		phybase;
++	void __iomem		*virtbase;
++	struct clk		*clk;
++
++	struct i2c_msg		*msg;
++
++	unsigned int		frequency;
++
++	__u16			last_slave_addr;
++	i2c_mode_t		last_mode;
++	spinlock_t      lock;
++};
++
++static inline void hi_i2c_disable(struct hi_i2c *i2c)
++{
++	writel(0x0, i2c->virtbase + HII2C_EN);
++}
++
++static inline void hi_i2c_enable(struct hi_i2c *i2c)
++{
++	writel(0x1, i2c->virtbase + HII2C_EN);
++}
++
++static inline void  hi_i2c_disable_irq(struct hi_i2c *i2c, unsigned int flag)
++{
++	unsigned int val;
++
++	val = readl(i2c->virtbase + HII2C_IM);
++	val |= flag;
++	writel(val, i2c->virtbase + HII2C_IM);
++}
++
++static inline void hi_i2c_set_slave_addr(struct hi_i2c *i2c, __u16 addr,
++		unsigned char ten_bit_flag)
++{
++	unsigned int val;
++
++	hi_i2c_disable(i2c);
++
++	val = readl(i2c->virtbase + HII2C_TAR);
++	val &= ~TAR_ADDR;
++	val |= (addr << TAR_ADDR_SHIFT) & TAR_ADDR;
++
++	if (ten_bit_flag)
++		val |= TAR_10BIT_MODE;
++	else
++		val &= ~TAR_10BIT_MODE;
++
++	writel(val, i2c->virtbase + HII2C_TAR);
++
++	i2c->last_slave_addr = addr;
++
++	hi_i2c_enable(i2c);
++}
++
++static inline void hi_i2c_set_mode(struct hi_i2c *i2c, i2c_mode_t mode)
++{
++	unsigned int val;
++
++	hi_i2c_disable(i2c);
++
++	if (mode == I2C_MODE_SINGLE) {
++		val = readl(i2c->virtbase + HII2C_SEQU_CMD0);
++		val &= ~SEQU_MODE_EN;
++		writel(val, i2c->virtbase + HII2C_SEQU_CMD0);
++
++		val = readl(i2c->virtbase + HII2C_CR1);
++		val |= CR1_SINGLE_MODE_EN;
++		writel(val, i2c->virtbase + HII2C_CR1);
++	} else {
++		val = readl(i2c->virtbase + HII2C_CR1);
++		val &= ~CR1_SINGLE_MODE_EN;
++		writel(val, i2c->virtbase + HII2C_CR1);
++	}
++
++	i2c->last_mode = mode;
++
++	hi_i2c_enable(i2c);
++}
++
++static inline int hi_i2c_clr_status(struct hi_i2c *i2c)
++{
++	unsigned int val;
++
++	val = readl(i2c->virtbase + HII2C_CR1);
++	val |= CR1_STATUS_CLR;
++	writel(val & (~CR1_SINGLE_MODE_EN), i2c->virtbase + HII2C_CR1);
++	writel(val, i2c->virtbase + HII2C_CR1);
++
++	writel(0x1, i2c->virtbase + HII2C_IC);
++
++	hi_i2c_disable(i2c);
++
++	hi_i2c_enable(i2c);
++
++	return 0;
++}
++
++static u32 hi_i2c_get_delay_val(struct hi_i2c *i2c)
++{
++	unsigned int scl_l;
++	u32 val;
++
++	scl_l = readl(i2c->virtbase + HII2C_SCL_L);
++
++	/* delay_val = scl_l * 2.5 * 1000 * 1000 / clk_rate   */
++	val = (25 * 100000 / clk_rate) + 1;// +1 is to make the time plenty more
++	val = val * scl_l;
++
++	return val;
++}
++
++static int hi_i2c_wait_idle(struct hi_i2c *i2c)
++{
++	unsigned int time_cnt;
++	unsigned int val;
++	struct device *dev = i2c->dev;
++
++	time_cnt = 0;
++	do {
++		val = readl(i2c->virtbase + HII2C_RI);
++		if (val & INT_TX_ABRT) {
++			dev_err(dev, "%s: wait last fifo is empyt abort!",
++					__func__);
++			dev_err(dev, "RI: %#x\n", val);
++			val = readl(i2c->virtbase + HII2C_TX_ABRT);
++			dev_err(i2c->dev, "TX_ABRT:0x%x\n", val);
++			return -EIO;
++		}
++
++		val = readl(i2c->virtbase + HII2C_CR1);
++		if (val & CR1_RFNE)
++			readl(i2c->virtbase + HII2C_DATA);
++
++		if (val & CR1_TFE & (~CR1_RFNE))
++			break;
++
++		if (time_cnt >= HII2C_TIMEOUT) {
++			dev_err(dev, "%s: wit last fifo is empty timeout!",
++					__func__);
++			dev_err(dev, "CR1:0x%x\n", val);
++			return -EBUSY;
++		}
++		time_cnt++;
++		udelay(50);
++	} while (1);
++
++	udelay(10);
++
++	time_cnt = 0;
++	do {
++		val = readl(i2c->virtbase + HII2C_RI);
++		if (val & INT_TX_ABRT) {
++			dev_err(dev, "%s: wait last i2c is idle abort!",
++					__func__);
++			dev_err(dev, "RI: %#x\n", val);
++			val = readl(i2c->virtbase + HII2C_TX_ABRT);
++			dev_err(i2c->dev, "TX_ABRT:0x%x\n", val);
++			return -EIO;
++		}
++
++		val = readl(i2c->virtbase + HII2C_SR);
++		if (!(val & SR_BUSY))
++			break;
++
++		if (time_cnt >= HII2C_TIMEOUT) {
++			dev_err(dev, "%s: wait last i2c is idle timeout!",
++					__func__);
++			dev_err(dev, "CR1:0x%x\n", val);
++			return -EBUSY;
++		}
++		time_cnt++;
++		udelay(50);
++	} while (1);
++
++	return 0;
++}
++
++static int hi_i2c_wait_tx_nofull(struct hi_i2c *i2c)
++{
++	unsigned int val;
++	unsigned int time_cnt;
++	struct device *dev = i2c->dev;
++
++	time_cnt = 0;
++	do {
++		val = readl(i2c->virtbase + HII2C_RI);
++		if (val & INT_TX_ABRT) {
++			dev_err(dev, "wait tx no full abort, last RI: %#x\n",
++					val);
++			val = readl(i2c->virtbase + HII2C_TX_ABRT);
++			dev_err(i2c->dev, "TX_ABRT:0x%x\n", val);
++			return -EIO;
++		}
++
++		val = readl(i2c->virtbase + HII2C_CR1);
++		if (val & CR1_RFNE)
++			readl(i2c->virtbase + HII2C_DATA);
++
++		if (val & CR1_TFNF)
++			break;
++
++		if (time_cnt >= HII2C_TIMEOUT) {
++			dev_err(dev, "wait tx no full timeout, last CR1: %#x\n",
++					val);
++			return -EBUSY;
++		}
++		time_cnt++;
++		udelay(50);
++	} while (1);
++
++	return 0;
++}
++
++static int hi_i2c_wait_rx_noempty(struct hi_i2c *i2c)
++{
++	unsigned int val;
++	unsigned int time_cnt;
++	struct device *dev = i2c->dev;
++
++	time_cnt = 0;
++	do {
++		val = readl(i2c->virtbase + HII2C_RI);
++		if (val & INT_TX_ABRT) {
++			dev_err(dev, "wait rx no empty abort, RI: %#x\n", val);
++			val = readl(i2c->virtbase + HII2C_TX_ABRT);
++			dev_err(i2c->dev, "TX_ABRT:0x%x\n", val);
++			return -EIO;
++		}
++
++		val = readl(i2c->virtbase + HII2C_CR1);
++		if (val & CR1_RFNE)
++			break;
++
++		if (time_cnt >= HII2C_TIMEOUT) {
++			dev_err(dev, "\nwait rx no empty timeout, CR1: %#x\n",
++					val);
++			return -EBUSY;
++		}
++		time_cnt++;
++		udelay(50);
++	} while (1);
++
++	return 0;
++}
++
++#ifdef CONFIG_HI_DMAC
++#define REVERT_HL_BYTE(value)   ((value >> 8) | ((value & 0xFF) << 8))
++
++void hi_i2c_dma_start(struct hi_i2c *i2c, unsigned int dir)
++{
++	writel((1 << dir), i2c->virtbase + I2C_DMA_CTRL_REG);
++}
++
++void hi_i2c_dmac_config(struct hi_i2c *i2c, unsigned int dir)
++{
++	/* 1. enable RX(0) or TX(1) in DMA mode */
++	hi_i2c_dma_start(i2c, dir);
++
++	/* 2. set dma fifo */
++	writel(4, i2c->virtbase + I2C_DMA_TDLR);
++	writel(4, i2c->virtbase + I2C_DMA_RDLR);
++}
++
++void hi_i2c_start_rx(struct hi_i2c *i2c, unsigned int reg_addr,
++			unsigned int length)
++{
++	unsigned int reg;
++
++	writel(reg_addr, i2c->virtbase + I2C_DMA_CMD1);
++	writel(length, i2c->virtbase + I2C_DMA_CMD2);
++
++	reg = readl(i2c->virtbase + I2C_DMA_CMD0);
++
++	/*start dma rx*/
++	reg |= SEQU_MODE_EN;
++	reg &= ~SEQU_MODE_WRITE;
++	writel(reg, i2c->virtbase + I2C_DMA_CMD0);
++}
++
++void hi_i2c_start_tx(struct hi_i2c *i2c, unsigned int reg_addr,
++			unsigned int length)
++{
++	unsigned int reg;
++
++	writel(reg_addr, i2c->virtbase + I2C_DMA_CMD1);
++	writel(length, i2c->virtbase + I2C_DMA_CMD2);
++
++	reg = readl(i2c->virtbase + I2C_DMA_CMD0);
++
++	/*start dma tx*/
++	reg |= SEQU_MODE_EN;
++	reg |= SEQU_MODE_WRITE;
++	writel(reg, i2c->virtbase + I2C_DMA_CMD0);
++}
++
++int dma_to_i2c(unsigned int src, unsigned int dst, unsigned int length)
++{
++	int chan;
++
++	chan = do_dma_m2p(src, dst, length);
++	if (chan == -1)
++		pr_err("dma_to_i2c error\n");
++
++	return chan;
++}
++
++
++int i2c_to_dma(unsigned int src, unsigned int dst, unsigned int length)
++{
++	int chan;
++
++	chan = do_dma_p2m(dst, src, length);
++	if (chan == -1)
++		pr_err("dma_p2m error...\n");
++
++	return chan;
++}
++
++static int hi_i2c_do_dma_write(struct hi_i2c *i2c,
++		unsigned int reg_addr, unsigned int reg_addr_num,
++		unsigned int dma_buf, unsigned int len)
++{
++	int chan;
++	struct i2c_msg *msg = i2c->msg;
++	unsigned int temp_reg = reg_addr;
++
++	if ((msg->addr != i2c->last_slave_addr)
++			|| (i2c->last_mode != I2C_MODE_DMA)) {
++		hi_i2c_set_slave_addr(i2c, msg->addr, msg->flags & I2C_M_TEN);
++		hi_i2c_set_mode(i2c, I2C_MODE_DMA);
++	}
++
++	if (2 == reg_addr_num) {
++		/* switch high byte and low byte */
++		temp_reg = REVERT_HL_BYTE(reg_addr);
++		writel(SEQU_ADDR_16BIT, i2c->virtbase + I2C_DMA_CMD0);
++	} else {
++		writel(SEQU_ADDR_8BIT, i2c->virtbase + I2C_DMA_CMD0);
++	}
++
++	/* 2. config i2c into DMA mode */
++	hi_i2c_dmac_config(i2c, 0x1);
++
++	/* 3. start i2c logic to write */
++	hi_i2c_start_tx(i2c, temp_reg, len - 1);
++
++	/* 4. transmit DATA from DMAC to I2C in DMA mode */
++	chan = dma_to_i2c(dma_buf, (i2c->phybase + I2C_DATA_CMD_REG),
++				len);
++	if (chan == -1) {
++		return -1;
++	}
++
++	if (dmac_wait(chan) != DMAC_CHN_SUCCESS) {
++		dev_err(i2c->dev, "dma wait failed\n");
++		hi_i2c_clr_status(i2c);
++		dmac_channel_free(chan);
++		return -1;
++	}
++
++	hi_i2c_wait_idle(i2c);
++	hi_i2c_clr_status(i2c);
++
++	dmac_channel_free(chan);
++
++	return 0;
++}
++
++static int hi_i2c_do_dma_read(struct hi_i2c *i2c,
++		unsigned int reg_addr, unsigned int reg_addr_num,
++		unsigned int dma_buf, unsigned int len)
++{
++	int chan;
++	struct i2c_msg *msg = i2c->msg;
++	unsigned int temp_reg = reg_addr;
++
++	if ((msg->addr != i2c->last_slave_addr)
++			|| (I2C_MODE_DMA != i2c->last_mode)) {
++		hi_i2c_set_slave_addr(i2c, msg->addr, msg->flags & I2C_M_TEN);
++		hi_i2c_set_mode(i2c, I2C_MODE_DMA);
++	}
++
++	if (2 == reg_addr_num) {
++		/* switch high byte and low byte */
++		temp_reg = REVERT_HL_BYTE(reg_addr);
++		writel(SEQU_ADDR_16BIT, i2c->virtbase + I2C_DMA_CMD0);
++	} else {
++		writel(SEQU_ADDR_8BIT, i2c->virtbase + I2C_DMA_CMD0);
++	}
++
++	/* 2. config i2c into DMA mode */
++	hi_i2c_dmac_config(i2c, 0x0);
++
++	/* 3. transmit DATA from I2C to DMAC in DMA mode */
++	chan = i2c_to_dma((i2c->phybase + I2C_DATA_CMD_REG),
++				dma_buf, len);
++	if (chan == -1) {
++		return -1;
++	}
++
++	/* 4. start i2c logic to read */
++	hi_i2c_start_rx(i2c, temp_reg, len - 1);
++
++	if (dmac_wait(chan) != DMAC_CHN_SUCCESS) {
++		dev_err(i2c->dev, "dma wait failed\n");
++		hi_i2c_clr_status(i2c);
++		dmac_channel_free(chan);
++		return -1;
++	}
++
++	hi_i2c_wait_idle(i2c);
++	hi_i2c_clr_status(i2c);
++
++	dmac_channel_free(chan);
++
++	return 0;
++}
++#else
++static int hi_i2c_do_dma_write(struct hi_i2c *i2c,
++		unsigned int reg_addr, unsigned int reg_addr_num,
++		unsigned int dma_buf, unsigned int len)
++{
++	dev_err(i2c->dev, "DMA is not enabled!");
++	return -1;
++}
++
++static int hi_i2c_do_dma_read(struct hi_i2c *i2c,
++		unsigned int reg_addr, unsigned int reg_addr_num,
++		unsigned int dma_buf, unsigned int len)
++{
++	dev_err(i2c->dev, "DMA is not enabled!");
++	return -1;
++}
++#endif
++
++int hi_i2c_dma_write(const struct i2c_client *client, unsigned int dma_buf,
++		unsigned int reg_addr, unsigned int reg_addr_num,
++		unsigned int len)
++{
++	struct i2c_adapter *adap = client->adapter;
++	struct hi_i2c *i2c = i2c_get_adapdata(adap);
++	struct i2c_msg msg;
++	int status;
++	unsigned long flags;
++
++	spin_lock_irqsave(&i2c->lock, flags);
++
++	memset(&msg, 0x0, sizeof(struct i2c_msg));
++	msg.addr = client->addr;
++	msg.flags = client->flags;
++	msg.len = len;
++
++	i2c->msg = &msg;
++
++	status = hi_i2c_do_dma_write(i2c, reg_addr, reg_addr_num, dma_buf, len);
++
++	spin_unlock_irqrestore(&i2c->lock, flags);
++
++	return status;
++}
++EXPORT_SYMBOL(hi_i2c_dma_write);
++
++int hi_i2c_dma_read(const struct i2c_client *client, unsigned int dma_buf,
++		unsigned int reg_addr, unsigned int reg_addr_num,
++		unsigned int len)
++{
++	struct i2c_adapter *adap = client->adapter;
++	struct hi_i2c *i2c = i2c_get_adapdata(adap);
++	struct i2c_msg msg;
++	int status;
++	unsigned long flags;
++
++	spin_lock_irqsave(&i2c->lock, flags);
++
++	memset(&msg, 0x0, sizeof(struct i2c_msg));
++	msg.addr = client->addr;
++	msg.flags = client->flags;
++	msg.flags |= I2C_M_RD;
++	msg.len = len;
++
++	i2c->msg = &msg;
++
++	status = hi_i2c_do_dma_read(i2c, reg_addr, reg_addr_num, dma_buf, len);
++
++	spin_unlock_irqrestore(&i2c->lock, flags);
++
++	return status;
++}
++EXPORT_SYMBOL(hi_i2c_dma_read);
++
++static void hi_i2c_set_rate(struct hi_i2c *i2c)
++{
++	unsigned int max_frequency, freq;
++	unsigned int scl_h, scl_l, sda_hold;
++
++	freq = i2c->frequency;
++	clk_rate = clk_get_rate(i2c->clk);
++	BUG_ON(!clk_rate);
++
++	max_frequency = clk_rate >> 1;
++
++	if (freq > max_frequency) {
++		i2c->frequency = max_frequency;
++		freq = i2c->frequency;
++	}
++
++	if (!freq) {
++		pr_err("freq can not be zero...\n");
++		return;
++	}
++	
++	/* set SCLH and SCLL depend on clk_rate and freq */
++	if (freq <= 100000) {
++		/* in normal mode		F_scl: freq
++		   i2c_scl_hcnt = (F_i2c / F_scl) * 0.5
++		   i2c_scl_hcnt = (F_i2c / F_scl) * 0.5
++		*/
++		scl_h = clk_rate / (freq * 2);
++		scl_l = scl_h;
++	} else {
++		/* in fast mode		F_scl: freq
++		   i2c_scl_hcnt = (F_i2c / F_scl) * 0.36
++		   i2c_scl_hcnt = (F_i2c / F_scl) * 0.64
++		*/
++		scl_h = ((clk_rate / 100) * 36) / freq;
++		scl_l = ((clk_rate / 100) * 64) / freq;
++	}
++
++	writel(scl_h, i2c->virtbase + HII2C_SCL_H);
++	writel(scl_l, i2c->virtbase + HII2C_SCL_L);
++
++	sda_hold = scl_h / 2;
++	writel(sda_hold, i2c->virtbase + HII2C_SDA_HOLD);
++}
++
++static void hi_i2c_hw_init(struct hi_i2c *i2c)
++{
++	unsigned int val;
++
++	/* unlock hi_i2c controller to access */
++	writel(UNLOCK_VALUE, i2c->virtbase + HII2C_LOCK);
++
++	hi_i2c_disable(i2c);
++
++	val = readl(i2c->virtbase + HII2C_CR);
++	val |= CR_RESTART_EN;
++	writel(val, i2c->virtbase + HII2C_CR);
++
++	hi_i2c_set_rate(i2c);
++
++	hi_i2c_disable_irq(i2c, MASK_ALL_INT);
++
++	writel(0x0, i2c->virtbase + HII2C_TAR);
++	hi_i2c_set_slave_addr(i2c, 0, 0);
++	hi_i2c_set_mode(i2c, I2C_MODE_SINGLE);
++	i2c->last_slave_addr = 0;
++	i2c->last_mode = I2C_MODE_SINGLE;
++
++	hi_i2c_enable(i2c);
++}
++
++static int hi_i2c_polling_xfer_one_msg(struct hi_i2c *i2c)
++{
++	int status;
++	unsigned val;
++	struct i2c_msg *msg = i2c->msg;
++	unsigned int tmp;
++	unsigned int data_h = 0;
++	unsigned int data_l = 0;
++
++	dev_dbg(i2c->dev, "[%s,%d]\n", __func__, __LINE__);
++
++	tmp = !CR1_READ_MODE;
++	switch (msg->len) {
++	case 2:
++		tmp &= ~CR1_H_WIDE;
++		tmp &= ~CR1_L_WIDE;
++
++		data_h = msg->buf[0];
++		data_l = msg->buf[1];
++		break;
++	case 3:
++		tmp |= CR1_H_WIDE;
++		tmp &= ~CR1_L_WIDE;
++
++		data_h = msg->buf[0];
++		data_h |= msg->buf[1] << 8;
++		data_l = msg->buf[2];
++		break;
++	case 4:
++		tmp |= CR1_H_WIDE;
++		tmp |= CR1_L_WIDE;
++
++		data_h = msg->buf[0];
++		data_h |= msg->buf[1] << 8;
++		data_l = msg->buf[2];
++		data_l |=  msg->buf[3] << 8;
++		break;
++	default:
++		dev_err(i2c->dev, "Unsupported this length: %d!\n", msg->len);
++		return -EIO;
++	}
++
++	if ((msg->addr != i2c->last_slave_addr)
++			|| (I2C_MODE_SINGLE != i2c->last_mode)) {
++		hi_i2c_set_slave_addr(i2c, msg->addr, msg->flags & I2C_M_TEN);
++		hi_i2c_set_mode(i2c, I2C_MODE_SINGLE);
++	}
++
++	val = readl(i2c->virtbase + HII2C_CR1);
++	val &= ~CR1_H_WIDE & ~CR1_L_WIDE & ~CR1_READ_MODE;
++	val |= tmp;
++	writel(val, i2c->virtbase + HII2C_CR1);
++	do {
++		status = hi_i2c_wait_tx_nofull(i2c);
++		if (status)
++			break;
++
++		val = (data_h << DATA_H_SHIFT) | (data_l << DATA_L_SHIFT);
++		writel(val, i2c->virtbase + HII2C_DATA);
++	} while (0);
++
++	udelay(hi_i2c_get_delay_val(i2c));
++
++	if (!status)
++		status = hi_i2c_wait_idle(i2c);
++
++	hi_i2c_clr_status(i2c);
++
++	return status;
++}
++
++static int hi_i2c_polling_xfer_two_msg(struct hi_i2c *i2c)
++{
++	int status;
++	unsigned val;
++	struct i2c_msg *msg = i2c->msg;
++	unsigned int tmp;
++	unsigned int data_h = 0;
++	unsigned int data_l = 0;
++
++
++	dev_dbg(i2c->dev, "[%s,%d]\n", __func__, __LINE__);
++
++	tmp = CR1_READ_MODE;
++	switch (msg->len) {
++	case 1:
++		tmp &= ~CR1_H_WIDE;
++
++		data_h = msg->buf[0];
++		break;
++	case 2:
++		tmp |= CR1_H_WIDE;
++
++		data_h = msg->buf[0];
++		data_h |= msg->buf[1] << 8;
++		break;
++	default:
++		dev_err(i2c->dev, "Unsupported this length: %d!\n", msg->len);
++		return -EIO;
++	}
++
++	msg++;
++
++	switch (msg->len) {
++	case 1:
++		tmp &= ~CR1_L_WIDE;
++		break;
++	case 2:
++		tmp |= CR1_L_WIDE;
++		break;
++	default:
++		dev_err(i2c->dev, "Unsupported this length: %d!\n", msg->len);
++		return -EIO;
++	}
++
++	if ((msg->addr != i2c->last_slave_addr)
++			|| (I2C_MODE_SINGLE != i2c->last_mode)) {
++		hi_i2c_set_slave_addr(i2c, msg->addr, msg->flags & I2C_M_TEN);
++		hi_i2c_set_mode(i2c, I2C_MODE_SINGLE);
++	}
++
++	val = readl(i2c->virtbase + HII2C_CR1);
++	val &= ~CR1_H_WIDE & ~CR1_L_WIDE & ~CR1_READ_MODE;
++	val |= tmp;
++	writel(val, i2c->virtbase + HII2C_CR1);
++	do {
++		status = hi_i2c_wait_tx_nofull(i2c);
++		if (status)
++			break;
++
++		val = data_h << DATA_H_SHIFT;
++		writel(val, i2c->virtbase + HII2C_DATA);
++
++		status = hi_i2c_wait_rx_noempty(i2c);
++		if (status)
++			break;
++
++		data_l = readl(i2c->virtbase + HII2C_DATA) & DATA_L;
++
++		switch (msg->len) {
++		case 1:
++			msg->buf[0] = data_l & 0xff;
++			break;
++		case 2:
++			msg->buf[0] = data_l & 0xff;
++			msg->buf[1] = (data_l >> 8) & 0xff;
++			break;
++		default:
++			status = -EIO;
++			dev_err(i2c->dev, "Unsupported this length: %d!\n",
++					msg->len);
++			break;
++		}
++	} while (0);
++
++	if (!status)
++		status = hi_i2c_wait_idle(i2c);
++
++	hi_i2c_clr_status(i2c);
++
++	return status;
++}
++
++static int hi_i2c_dma_xfer_one_msg(struct hi_i2c *i2c)
++{
++	int status;
++	struct i2c_msg *msg = i2c->msg;
++	dma_addr_t dma_buf;
++	unsigned int reg_addr;
++	unsigned int reg_width;
++
++	dev_dbg(i2c->dev, "[%s,%d]\n", __func__, __LINE__);
++
++	if (msg->len < 2) {
++		dev_err(i2c->dev, "Unsupported this length: %d!\n", msg->len);
++		return -EIO;
++	}
++	reg_addr = msg->buf[0];
++	reg_width = 1;
++
++	dma_buf = dma_map_single(i2c->dev, msg->buf, msg->len, DMA_TO_DEVICE);
++
++	if (dma_mapping_error(i2c->dev, dma_buf)) {
++		dev_err(i2c->dev, "DMA mapping failed\n");
++		return -EINVAL;
++	}
++
++	status = hi_i2c_do_dma_write(i2c, reg_addr, reg_width,
++			dma_buf + reg_width, msg->len - reg_width);
++
++	dma_unmap_single(i2c->dev, dma_buf, msg->len, DMA_TO_DEVICE);
++
++	return status;
++}
++
++static int hi_i2c_dma_xfer_two_msg(struct hi_i2c *i2c)
++{
++	int status;
++	struct i2c_msg *msg = i2c->msg;
++	dma_addr_t dma_buf;
++	unsigned int reg_addr;
++	unsigned int reg_width;
++
++	dev_dbg(i2c->dev, "[%s,%d]\n", __func__, __LINE__);
++
++	switch (msg->len) {
++	case 1:
++		reg_addr = msg->buf[0];
++		reg_width = 1;
++		break;
++	case 2:
++		reg_addr = msg->buf[0] << 8;
++		reg_addr |= msg->buf[1];
++		reg_width = 2;
++		break;
++	default:
++		dev_err(i2c->dev, "Unsupported this length: %d!\n", msg->len);
++		return -EIO;
++	}
++
++	msg++;
++
++	if (msg->len <= 0) {
++		dev_err(i2c->dev, "Unsupported this length: %d!\n", msg->len);
++		return -EIO;
++	}
++
++	dma_buf = dma_map_single(i2c->dev, msg->buf, msg->len, DMA_FROM_DEVICE);
++
++	if (dma_mapping_error(i2c->dev, dma_buf)) {
++		dev_err(i2c->dev, "DMA mapping failed\n");
++		return -EINVAL;
++	}
++
++	status = hi_i2c_do_dma_read(i2c, reg_addr, reg_width, dma_buf,
++			msg->len);
++
++	dma_unmap_single(i2c->dev, dma_buf,  msg->len, DMA_FROM_DEVICE);
++
++	return status;
++}
++
++static int hi_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
++		int num)
++{
++	struct hi_i2c *i2c = i2c_get_adapdata(adap);
++	int status;
++	struct i2c_msg *msg = i2c->msg;
++	unsigned int msg_idx;
++	unsigned long flags;
++
++	if (!msgs || (num <= 0)) {
++		dev_err(i2c->dev, "msgs == NULL || num <= 0, Invalid argument!\n");
++		return -EINVAL;
++	}
++
++	spin_lock_irqsave(&i2c->lock, flags);
++
++	i2c->msg = msgs;
++	msg_idx = 0;
++
++	while (msg_idx < num) {
++		msg = i2c->msg;
++
++		if (msg->flags & I2C_M_RD) {
++			status = -EIO;
++			dev_err(i2c->dev, "Unsupported read-only!\n");
++			break;
++		}
++
++		if ((msg_idx < (num - 1)) && ((msg + 1)->flags & I2C_M_RD)) {
++			if ((msg + 1)->len <= 2)
++				status = hi_i2c_polling_xfer_two_msg(i2c);
++			else
++				status = hi_i2c_dma_xfer_two_msg(i2c);
++
++			if (status)
++				break;
++
++			i2c->msg += 2;
++			msg_idx += 2;
++		} else {
++			if (msg->len <= 4)
++				status = hi_i2c_polling_xfer_one_msg(i2c);
++			else
++				status = hi_i2c_dma_xfer_one_msg(i2c);
++
++			if (status)
++				break;
++
++			i2c->msg++;
++			msg_idx++;
++		}
++	}
++
++	if (!status || msg_idx > 0)
++		status = msg_idx;
++	else
++		status = -EIO;
++
++	spin_unlock_irqrestore(&i2c->lock, flags);
++
++	return status;
++}
++
++/* HI I2C READ *
++ * hi_i2c_master_recv - issue a single I2C message in master receive mode
++ * @client: Handle to slave device
++ * @buf: Where to store data read from slave
++ * @count: How many bytes to read, must be less than 64k since msg.len is u16
++ *
++ * Returns negative errno, or else the number of bytes read.
++ */
++int hi_i2c_master_recv(const struct i2c_client *client, char *buf,
++		int count)
++{
++	printk("Wrong interface call."
++			"hi_i2c_transfer is the only interface to i2c read!!!\n");
++
++	return -EIO;
++}
++EXPORT_SYMBOL(hi_i2c_master_recv);
++
++/*HI I2C WRITE*
++ * hi_i2c_master_send - issue a single I2C message in master transmit mode
++ * @client: Handle to slave device
++ * @buf: Data that will be written to the slave
++ * @count: How many bytes to write, must be less than 64k since msg.len is u16
++ *
++ * Returns negative errno, or else the number of bytes written.
++ */
++int hi_i2c_master_send(const struct i2c_client *client,
++		const char *buf, int count)
++{
++	struct i2c_adapter *adap = client->adapter;
++	struct i2c_msg msg;
++	int msgs_count;
++
++	if ((client->addr > 0x3ff)
++			|| (((client->flags & I2C_M_TEN) == 0) && (client->addr > 0x7f))) {
++		printk(KERN_ERR "dev address out of range\n");
++		return -EINVAL;
++	}
++
++	msg.addr = client->addr;
++	msg.flags = client->flags;
++	msg.len = count;
++
++	if (!buf) {
++		printk(KERN_ERR "Invalid buf == NULL!!!\n");
++		return -EINVAL;
++	}
++	msg.buf = (__u8 *)buf;
++
++	msgs_count = hi_i2c_xfer(adap, &msg, 1);
++
++	return (msgs_count == 1) ? count : -EIO;
++}
++EXPORT_SYMBOL(hi_i2c_master_send);
++
++/**
++ * hi_i2c_transfer - execute a single or combined I2C message
++ * @adap: Handle to I2C bus
++ * @msgs: One or more messages to execute before STOP is issued to
++ *  terminate the operation; each message begins with a START.
++ * @num: Number of messages to be executed.
++ *
++ * Returns negative errno, else the number of messages executed.
++ *
++ * Note that there is no requirement that each message be sent to
++ * the same slave address, although that is the most common model.
++ */
++
++int hi_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
++		int num)
++{
++	int msgs_count;
++
++	if ((msgs[0].addr > 0x3ff)
++			|| (((msgs[0].flags & I2C_M_TEN) == 0) && (msgs[0].addr > 0x7f))) {
++		printk(KERN_ERR "msgs[0] dev address out of range\n");
++		return -EINVAL;
++	}
++
++	if ((msgs[1].addr > 0x3ff)
++			|| (((msgs[1].flags & I2C_M_TEN) == 0) && (msgs[1].addr > 0x7f))) {
++		printk(KERN_ERR "msgs[1] dev address out of range\n");
++		return -EINVAL;
++	}
++
++	msgs_count = hi_i2c_xfer(adap, msgs, num);
++
++	return msgs_count;
++}
++EXPORT_SYMBOL(hi_i2c_transfer);
++
++static u32 hi_i2c_func(struct i2c_adapter *adap)
++{
++	return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR
++		| I2C_FUNC_PROTOCOL_MANGLING;
++}
++
++static const struct i2c_algorithm hi_i2c_algorithm = {
++	.master_xfer		= hi_i2c_xfer,
++	.functionality		= hi_i2c_func,
++};
++
++/* hi_i2c_parse_dt
++ *
++ * Parse the device tree node.
++ */
++static int hi_i2c_parse_dt(struct hi_i2c *i2c)
++{
++	struct device *dev = i2c->dev;
++	struct device_node *np = dev->of_node;
++
++	if (!np) {
++		dev_err(dev, "no dt node defined\n");
++		return -ENODEV;
++	}
++
++	if (of_property_read_u32(np, "clock-frequency", &i2c->frequency)) {
++		dev_dbg(dev, "of read error clock-frequency = %d\n",
++				i2c->frequency);
++		i2c->frequency = 4000000;
++	}
++
++	return 0;
++}
++
++static int hi_i2c_probe(struct platform_device *pdev)
++{
++	struct device *dev = &pdev->dev;
++	struct hi_i2c *i2c;
++	struct i2c_adapter *adap;
++	struct resource *res;
++	int status;
++
++	dev_info(dev, "HISILICON I2C V110 bus driver\n");
++
++	adap = devm_kzalloc(&pdev->dev,
++			sizeof(struct i2c_adapter) + sizeof(struct hi_i2c),
++			GFP_KERNEL);
++	if (!adap)
++		return -ENOMEM;
++
++	adap->dev.parent = dev;
++	adap->dev.of_node = dev->of_node;
++	i2c_set_adapdata(adap,  &adap[1]);
++
++	adap->owner = THIS_MODULE;
++	adap->class = I2C_CLASS_DEPRECATED;
++	adap->algo = &hi_i2c_algorithm;
++	strlcpy(adap->name, "hisi-i2c-v110", sizeof(adap->name));
++
++	i2c = i2c_get_adapdata(adap);
++	platform_set_drvdata(pdev, i2c);
++	spin_lock_init(&i2c->lock);
++
++	i2c->pdev = pdev;
++	i2c->adap = adap;
++	i2c->dev = dev;
++
++	status = hi_i2c_parse_dt(i2c);
++	if (status)
++		goto err_ioremap;
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	if (!res)
++		goto err_ioremap;
++	
++	i2c->virtbase = devm_ioremap_resource(dev, res);
++	if (i2c->virtbase == NULL) {
++		status = PTR_ERR(i2c->virtbase);
++		dev_err(dev, "cannot ioremap resource\n");
++		goto err_ioremap;
++	}
++	i2c->phybase = res->start;
++	dev_info(dev, "mapped registers from 0x%x to 0x%p\n",
++		res->start, i2c->virtbase);
++
++	/* find the clock and enable it */
++	i2c->clk = devm_clk_get(&pdev->dev, NULL);
++	if (IS_ERR(i2c->clk)) {
++		status = PTR_ERR(i2c->clk);
++		dev_err(dev, "cannot get clock\n");
++		goto err_clk;
++	}
++	status = clk_prepare_enable(i2c->clk);
++	if (status) {
++		dev_err(dev, "could not enable clock\n");
++		goto err_clk;
++	}
++
++	hi_i2c_hw_init(i2c);
++
++	status = i2c_add_adapter(i2c->adap);
++	if (status < 0) {
++		dev_err(dev, "failed to add bus to i2c core\n");
++		goto err_add_adapter;
++	}
++
++	return 0;
++
++err_add_adapter:
++	clk_disable_unprepare(i2c->clk);
++err_clk:
++err_ioremap:
++
++	return status;
++}
++
++/* hi_i2c_remove
++ *
++ * called when device is removed from the bus
++ */
++static int hi_i2c_remove(struct platform_device *pdev)
++{
++	struct hi_i2c *i2c = platform_get_drvdata(pdev);
++
++	clk_disable_unprepare(i2c->clk);
++	i2c_del_adapter(i2c->adap);
++
++	return 0;
++}
++
++#ifdef CONFIG_PM
++static int hi_i2c_runtime_suspend(struct device *dev)
++{
++	return 0;
++}
++
++static int hi_i2c_runtime_resume(struct device *dev)
++{
++	struct platform_device *pdev = to_platform_device(dev);
++	struct hi_i2c *i2c = platform_get_drvdata(pdev);
++
++	hi_i2c_hw_init(i2c);
++	return 0;
++}
++#endif
++
++static const struct dev_pm_ops hi_i2c_dev_pm_ops = {
++	SET_SYSTEM_SLEEP_PM_OPS(hi_i2c_runtime_suspend,
++			      hi_i2c_runtime_resume)
++};
++
++static const struct of_device_id hi_i2c_match[] = {
++	{ .compatible = "hisilicon,hisi-i2c-v110"},
++	{},
++};
++MODULE_DEVICE_TABLE(of, hi_i2c_match);
++
++static struct platform_driver hi_i2c_driver = {
++	.probe		= hi_i2c_probe,
++	.remove		= hi_i2c_remove,
++	.driver		= {
++		.owner	= THIS_MODULE,
++		.name	= "hisi-i2c-v110",
++		.pm	= &hi_i2c_dev_pm_ops,
++		.of_match_table = of_match_ptr(hi_i2c_match),
++	},
++};
++
++module_platform_driver(hi_i2c_driver);
++
++MODULE_DESCRIPTION("HISILICON I2C V110 Bus driver");
++MODULE_AUTHOR("BVT OSDRV");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/i2c/busses/i2c-hisilicon.c b/drivers/i2c/busses/i2c-hisilicon.c
+new file mode 100644
+index 0000000..66c5a0a
+--- /dev/null
++++ b/drivers/i2c/busses/i2c-hisilicon.c
+@@ -0,0 +1,1169 @@
++/* linux/drivers/i2c/busses/i2c-hisilicon.c
++ *
++ * HISILICON I2C Controller
++ *
++ * Copyright (c) 2014 Hisilicon Co., Ltd.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/i2c.h>
++#include <linux/init.h>
++#include <linux/time.h>
++#include <linux/interrupt.h>
++#include <linux/delay.h>
++#include <linux/errno.h>
++#include <linux/err.h>
++#include <linux/platform_device.h>
++#include <linux/pm_runtime.h>
++#include <linux/slab.h>
++#include <linux/io.h>
++#include <mach/io.h>
++
++#include "i2c-hisilicon.h"
++#include <linux/dma-mapping.h>
++
++#ifdef CONFIG_HI_DMAC
++#include <linux/hidmac.h>
++#endif
++
++#define HI_I2C	"hisi_i2c"
++
++#define hi_err(x...) \
++	do { \
++		pr_alert("%s->%d: ", __func__, __LINE__); \
++		pr_alert(x); \
++		pr_alert("\n"); \
++	} while (0)
++
++/* #define HI_I2C_DEBUG */
++
++#ifdef HI_I2C_DEBUG
++
++#define hi_msg(x...) \
++	do { \
++		pr_alert("%s (line:%d) ", __func__, __LINE__); \
++		pr_alert(x); \
++	} while (0)
++#else
++#define hi_msg(args...) do { } while (0)
++#endif
++
++#define I2C_WAIT_TIME_OUT	20000
++
++#define I2C_DFT_RATE	(100000)
++
++struct hi_i2c {
++	unsigned char __iomem *regbase;
++	struct device *dev;
++	struct resource *mem;
++	unsigned int irq;
++	struct i2c_adapter adap;
++	struct i2c_msg *msgs;
++	__u16 msg_num;
++	__u16 msg_addr;
++	unsigned int msg_index;
++	struct hi_platform_i2c *pdata;
++	unsigned int g_last_dev_addr;
++	unsigned int g_last_mode;
++	spinlock_t spinlock;
++};
++
++unsigned int get_apb_clk(void);
++
++static int hi_i2c_abortprocess(struct hi_i2c *pinfo)
++{
++	unsigned int auto_status;
++	unsigned int tx_src;
++
++	tx_src = readl(pinfo->regbase + I2C_TX_ABRT_SRC);
++	hi_err("tx_abrt_src is %x.\n", tx_src);
++
++	auto_status = readl(pinfo->regbase + I2C_AUTO_REG);
++
++	/* clear 0xB0 err status */
++	/* auto_mst_tx_abrt_clr
++	   auto_tx_cmd_fifo_over_clr
++	   auto_rx_cmd_fifo_under_clr
++	   auto_rx_cmd_fifo_over_clr
++	 */
++	auto_status |= 0x0f000000;
++	writel(auto_status, pinfo->regbase + I2C_AUTO_REG);
++	writel(0x1, pinfo->regbase + I2C_CLR_INTR_REG);
++
++	/* disable i2c */
++	writel(0, pinfo->regbase + I2C_ENABLE_REG);
++
++	/* enable i2c */
++	writel(0x1, pinfo->regbase + I2C_ENABLE_REG);
++
++	return 0;
++}
++
++void hi_i2c_set_rate(struct hi_i2c *pinfo)
++{
++	unsigned int apb_clk, scl_h, scl_l, hold;
++
++	/* get apb bus clk for diff plat */
++	apb_clk = get_apb_clk();
++
++	/* set SCLH and SCLL depend on apb_clk and def_rate */
++	if (pinfo->pdata->clk_limit <= I2C_DFT_RATE) {
++		/* in normal mode		F_scl: def_rate
++		   i2c_scl_hcnt = (F_i2c / F_scl) * 0.5
++		   i2c_scl_hcnt = (F_i2c / F_scl) * 0.5
++		*/
++		scl_h = (apb_clk / I2C_DFT_RATE) / 2;
++		scl_l = scl_h;
++	} else {
++		/* in fast mode		F_scl: def_rate
++		   i2c_scl_hcnt = (F_i2c / F_scl) * 0.36
++		   i2c_scl_hcnt = (F_i2c / F_scl) * 0.64
++		*/
++		scl_h = ((apb_clk / 100) * 36) / pinfo->pdata->clk_limit;
++		scl_l = ((apb_clk / 100) * 64) / pinfo->pdata->clk_limit;
++	}
++
++	writel(scl_h, pinfo->regbase + I2C_SCL_H_REG);
++	writel(scl_l, pinfo->regbase + I2C_SCL_L_REG);
++
++	/* set hi_i2c hold time */
++	hold = scl_h / 2;
++	writel(hold, pinfo->regbase + I2C_SDA_HOLD_REG);
++}
++
++void hi_i2c_hw_init(struct hi_i2c *pinfo)
++{
++	unsigned int temp, rx_fifo, tx_fifo;
++
++	/* unlock hi_i2c controller to access */
++	writel(HI_I2C_UNLOCK_VALUE, pinfo->regbase + I2C_LOCK_REG);
++
++	/* disable hi_i2c controller */
++	temp = readl(pinfo->regbase + I2C_ENABLE_REG);
++	writel((temp & ~HI_I2C_ENABLE), pinfo->regbase + I2C_ENABLE_REG);
++
++	/* disable hi_i2c auto_mode */
++	writel(HI_I2C_AUTO_MODE_OFF, pinfo->regbase + I2C_AUTO_REG);
++
++	/* set hi_i2c in fast mode */
++	writel(HI_I2C_FAST_MODE, pinfo->regbase + I2C_CON_REG);
++
++	/* set hi_i2c rate */
++	hi_i2c_set_rate(pinfo);
++
++	rx_fifo = CONFIG_HI_I2C_RX_FIFO;
++	tx_fifo = CONFIG_HI_I2C_TX_FIFO;
++
++	/* set hi_i2c fifo */
++	writel(rx_fifo, pinfo->regbase + I2C_RX_TL_REG);
++	writel(tx_fifo, pinfo->regbase + I2C_TX_TL_REG);
++
++	/* enable interrupt mask */
++	writel(DISABLE_ALL_INTERRUPTS, pinfo->regbase + I2C_INTR_MASK_REG);
++
++	/* enable hi_i2c controller */
++	temp = readl(pinfo->regbase + I2C_ENABLE_REG);
++	writel((temp | HI_I2C_ENABLE), pinfo->regbase + I2C_ENABLE_REG);
++
++	pinfo->g_last_dev_addr = 0;
++	pinfo->g_last_mode = I2C_MODE_NONE;
++
++	pinfo->msgs = NULL;
++	pinfo->msg_num = 0;
++}
++
++#define HII2C_IC		0x40
++#define HII2C_CR1		0xB0
++#define HII2C_EN		0x6C
++#define CR1_SINGLE_MODE_EN	(0x1 << 31)
++#define	CR1_STATUS_CLR		(0xf << 24)
++static inline void hi_i2c_disable(struct hi_i2c *i2c)
++{
++	    writel(0x0, i2c->regbase + HII2C_EN);
++}
++
++static inline void hi_i2c_enable(struct hi_i2c *i2c)
++{
++	    writel(0x1, i2c->regbase + HII2C_EN);
++}
++
++static inline int hi_i2c_clr_status(struct hi_i2c *i2c)
++{
++	unsigned int val;
++
++	val = readl(i2c->regbase + HII2C_CR1);
++	val |= CR1_STATUS_CLR;
++	writel(val & (~CR1_SINGLE_MODE_EN), i2c->regbase + HII2C_CR1);
++	writel(val, i2c->regbase + HII2C_CR1);
++
++	writel(0x1, i2c->regbase + HII2C_IC);
++
++	hi_i2c_disable(i2c);
++
++	hi_i2c_enable(i2c);
++
++	return 0;
++}
++
++int hi_i2c_wait_idle(struct hi_i2c *pinfo)
++{
++	unsigned int val;
++	unsigned int time_cnt;
++
++	time_cnt = 0;
++	do {
++		val = readl(pinfo->regbase + I2C_INTR_RAW_REG);
++		if (val & I2C_RAW_TX_ABORT) {
++			hi_err("wait last i2c fifo is empty abort! "\
++					"int_raw_status: %#x!\n", val);
++			return hi_i2c_abortprocess(pinfo);
++		}
++
++		val = readl(pinfo->regbase + I2C_AUTO_REG);
++		if (!IS_RX_FIFO_EMPTY(val))
++			readl(pinfo->regbase + I2C_TX_RX_REG);
++
++		if (IS_FIFO_EMPTY(val))
++			break;
++
++		if (time_cnt > I2C_WAIT_TIME_OUT) {
++			hi_err("wait last i2c fifo is empty timeout! "\
++					"auto_status: %#x\n", val);
++			return -EBUSY;
++		}
++		time_cnt++;
++		udelay(50);
++	} while (1);
++
++	udelay(10);
++
++	time_cnt = 0;
++	do {
++		val = readl(pinfo->regbase + I2C_INTR_RAW_REG);
++		if (val & I2C_RAW_TX_ABORT) {
++			hi_err("wait last i2c is idle abort! "\
++					"int_raw_status: %#x!\n", val);
++			return hi_i2c_abortprocess(pinfo);
++		}
++
++		val = readl(pinfo->regbase + I2C_STATUS_REG);
++		if (IS_I2C_IDLE(val))
++			break;
++
++		if (time_cnt > I2C_WAIT_TIME_OUT) {
++			hi_err("wait last i2c is idle timeout! "\
++					"auto_status: %#x\n", val);
++			return -EBUSY;
++		}
++		time_cnt++;
++		udelay(50);
++	} while (1);
++
++	return 0;
++}
++
++/* wait until tx fifo is not full */
++int hi_i2c_wait_txfifo_notfull(struct hi_i2c *pinfo)
++{
++	unsigned int val;
++	unsigned int time_cnt;
++
++	time_cnt = 0;
++	do {
++		val = readl(pinfo->regbase + I2C_INTR_RAW_REG);
++		if (val & I2C_RAW_TX_ABORT) {
++			hi_err("abort! last int_raw_status: %#x!\n", val);
++			return hi_i2c_abortprocess(pinfo);
++		}
++
++		val = readl(pinfo->regbase + I2C_AUTO_REG);
++		if (!IS_RX_FIFO_EMPTY(val))
++			readl(pinfo->regbase + I2C_TX_RX_REG);
++
++		if (val & I2c_AUTO_TX_FIFO_NOT_FULL)
++			break;
++
++		if (time_cnt > I2C_WAIT_TIME_OUT) {
++			hi_err("timeout! last auto_status: %#x\n", val);
++			return -EBUSY;
++		}
++		time_cnt++;
++		udelay(50);
++	} while (1);
++
++	return 0;
++}
++
++/* wait until tx fifo is not empty */
++int hi_i2c_wait_rxfifo_notempty(struct hi_i2c *pinfo)
++{
++	unsigned int val;
++	unsigned int time_cnt;
++
++	time_cnt = 0;
++	do {
++		val = readl(pinfo->regbase + I2C_INTR_RAW_REG);
++		if ((val & I2C_RAW_TX_ABORT) == I2C_RAW_TX_ABORT) {
++			hi_err("abort! int_raw_status: %#x!\n", val);
++			hi_i2c_abortprocess(pinfo);
++			return -EIO;
++		}
++
++		val = readl(pinfo->regbase + I2C_AUTO_REG);
++		if (!IS_RX_FIFO_EMPTY(val))
++			break;
++
++		if (time_cnt > I2C_WAIT_TIME_OUT) {
++			hi_err("timeout! auto_status: %#x\n", val);
++			hi_i2c_abortprocess(pinfo);
++			return -EBUSY;
++		}
++		time_cnt++;
++		udelay(50);
++	} while (1);
++
++	return 0;
++}
++
++static inline int hi_i2c_set_dev_addr_and_mode(struct hi_i2c *pinfo,
++		unsigned int work_mode)
++{
++	unsigned int dev_addr = pinfo->msgs->addr;
++
++	if ((pinfo->g_last_dev_addr == dev_addr)
++			&& (pinfo->g_last_mode == work_mode))
++		return 0;
++
++	/* wait until all cmd in fifo is finished and i2c is idle */
++	if (hi_i2c_wait_idle(pinfo) < 0)
++		return -1;
++
++	/* disable i2c */
++	writel(0x0, pinfo->regbase + I2C_ENABLE_REG);
++	/* clear interrupt */
++	writel(0x1, pinfo->regbase + I2C_CLR_INTR_REG);
++	/* enable interrupt mask */
++	writel(DISABLE_ALL_INTERRUPTS, pinfo->regbase + I2C_INTR_MASK_REG);
++	/* clear err status */
++	writel(0x0f000000, pinfo->regbase + I2C_AUTO_REG);
++
++	/* different device, need to reinit i2c ctrl */
++	if ((pinfo->g_last_dev_addr) != dev_addr) {
++		/* set slave dev addr */
++		writel((dev_addr & 0xff)>>1, pinfo->regbase + I2C_TAR_REG);
++		pinfo->g_last_dev_addr = dev_addr;
++	}
++
++	if (pinfo->g_last_mode != work_mode) {
++
++		/* set auto mode */
++		if (work_mode == I2C_MODE_AUTO) {
++			writel(0x0, pinfo->regbase + I2C_DMA_CMD0);
++			writel(0x80000000, pinfo->regbase + I2C_AUTO_REG);
++			pinfo->g_last_mode = work_mode;
++		} else if (work_mode == I2C_MODE_DMA) {
++			writel(0x0, pinfo->regbase + I2C_AUTO_REG);
++			pinfo->g_last_mode = work_mode;
++		} else {
++			hi_err("invalid i2c mode\n");
++			return -1;
++		}
++	}
++
++	/*  enable i2c */
++	writel(0x1, pinfo->regbase + I2C_ENABLE_REG);
++
++	hi_msg("\n@@@@@@@@@@\n");
++
++	return 0;
++}
++
++int hi_i2c_write(struct hi_i2c *pinfo)
++{
++	unsigned int reg_val;
++	unsigned int temp_reg;
++	unsigned int temp_data;
++	unsigned int temp_auto_reg;
++        unsigned int min_msgs_len = 0;
++	struct i2c_msg *msgs = pinfo->msgs;
++
++	min_msgs_len = (msgs->flags & I2C_M_16BIT_REG) ? 2 : 1;
++	min_msgs_len += (msgs->flags & I2C_M_16BIT_DATA) ? 2 : 1;
++	if (msgs->len < min_msgs_len){
++		hi_err("Unsupported this length: %d!\n", msgs->len);
++		return -1;
++	}
++
++	if (hi_i2c_set_dev_addr_and_mode(pinfo, I2C_MODE_AUTO) < 0)
++		return -1;
++
++	temp_auto_reg = HI_I2C_WRITE;
++
++	if (msgs->flags & I2C_M_16BIT_REG) {
++		/* 16bit reg addr */
++		temp_auto_reg |= I2C_AUTO_ADDR;
++
++		/* switch high byte and low byte */
++		temp_reg = msgs->buf[pinfo->msg_index] << 8;
++
++		pinfo->msg_index++;
++
++		temp_reg |= msgs->buf[pinfo->msg_index];
++
++		pinfo->msg_index++;
++	} else {
++		temp_reg = msgs->buf[pinfo->msg_index];
++		pinfo->msg_index++;
++	}
++
++	if (msgs->flags & I2C_M_16BIT_DATA) {
++		/* 16bit data */
++		temp_auto_reg |= I2C_AUTO_DATA;
++
++		/* switch high byte and low byte */
++		temp_data =  msgs->buf[pinfo->msg_index] << 8;
++
++		pinfo->msg_index++;
++
++		temp_data |= msgs->buf[pinfo->msg_index];
++
++		pinfo->msg_index++;
++	} else {
++		temp_data = msgs->buf[pinfo->msg_index];
++		pinfo->msg_index++;
++	}
++
++	writel(temp_auto_reg, pinfo->regbase + I2C_AUTO_REG);
++	hi_msg("temp_auto_reg: 0x%x\n", temp_auto_reg);
++
++	/* set write reg&data */
++	reg_val = (temp_reg << REG_SHIFT) | temp_data;
++
++	/* wait until tx fifo not full */
++	if (hi_i2c_wait_txfifo_notfull(pinfo) < 0)
++		return -1;
++
++	hi_msg("reg_val = %x\n", reg_val);
++
++	writel(reg_val, pinfo->regbase + I2C_TX_RX_REG);
++
++	hi_msg("dev_addr =%x, reg_addr = %x, Data = %x\n",
++		pinfo->msgs->addr, pinfo->msgs->buf[0], pinfo->msgs->buf[1]);
++
++	return pinfo->msg_index;
++}
++
++unsigned int hi_i2c_read(struct hi_i2c *pinfo)
++{
++	unsigned int reg_val;
++	unsigned int temp_reg;
++	unsigned int ret_data = 0xffff;
++	unsigned int temp_auto_reg;
++	unsigned int data_num = 0;
++        unsigned int min_msgs_len = 0;
++	struct i2c_msg *msgs = pinfo->msgs;
++
++	min_msgs_len = (msgs->flags & I2C_M_16BIT_REG) ? 2 : 1;
++	if (msgs->len < min_msgs_len){
++		hi_err("Unsupported this length: %d!\n", msgs->len);
++		return -1;
++	}
++
++	if (hi_i2c_set_dev_addr_and_mode(pinfo, I2C_MODE_AUTO) < 0)
++		return -1;
++
++	temp_auto_reg = HI_I2C_READ;
++
++	if (msgs->flags & I2C_M_16BIT_REG) {
++		/* 16bit reg addr */
++		temp_auto_reg |= I2C_AUTO_ADDR;
++
++		/* switch high byte and low byte */
++		temp_reg = msgs->buf[pinfo->msg_index] << 8;
++		pinfo->msg_index++;
++		temp_reg |= msgs->buf[pinfo->msg_index];
++	} else {
++		temp_reg = msgs->buf[pinfo->msg_index];
++		pinfo->msg_index++;
++	}
++
++	if (msgs->flags & I2C_M_16BIT_DATA)
++		/* 16bit data */
++		temp_auto_reg |= I2C_AUTO_DATA;
++
++	writel(temp_auto_reg, pinfo->regbase + I2C_AUTO_REG);
++	hi_msg("temp_auto_reg: 0x%x\n", temp_auto_reg);
++
++	/* 1. write addr */
++	reg_val = temp_reg << REG_SHIFT;
++	hi_msg("reg_val %x\n", reg_val);
++
++	/* wait until tx fifo not full  */
++	if (hi_i2c_wait_txfifo_notfull(pinfo) < 0)
++		return -1;
++
++	/* regaddr */
++	writel(reg_val, pinfo->regbase + I2C_TX_RX_REG);
++
++	/* 2. read return data */
++	/* wait until rx fifo not empty  */
++	if (hi_i2c_wait_rxfifo_notempty(pinfo) < 0)
++		return -1;
++
++	ret_data = readl(pinfo->regbase + I2C_TX_RX_REG) & DATA_16BIT_MASK;
++	hi_msg("ret_data = %x\n", ret_data);
++
++	if (msgs->flags & I2C_M_16BIT_DATA) {
++		pinfo->msgs->buf[0] = ret_data & DATA_8BIT_MASK;
++		pinfo->msgs->buf[1] = (ret_data >> 8) & DATA_8BIT_MASK;
++		data_num = 2;
++	} else {
++		pinfo->msgs->buf[0] = ret_data & DATA_8BIT_MASK;
++		data_num = 1;
++	}
++
++	writel(0x1, pinfo->regbase + I2C_CLR_INTR_REG);
++
++	return data_num;
++}
++
++/************************************
++	* dma functions *
++************************************/
++#ifdef CONFIG_HI_DMAC
++void hi_i2c_dma_start(struct hi_i2c *pinfo, unsigned int dir)
++{
++	writel((1 << dir), pinfo->regbase + I2C_DMA_CTRL_REG);
++}
++
++void hi_i2c_dmac_config(struct hi_i2c *pinfo, unsigned int dir)
++{
++	/* 1. enable RX(0) or TX(1) in DMA mode */
++	hi_i2c_dma_start(pinfo, dir);
++
++	/* 2. set dma fifo */
++	writel(4, pinfo->regbase + I2C_DMA_TDLR);
++	writel(4, pinfo->regbase + I2C_DMA_RDLR);
++}
++
++void hi_i2c_start_rx(struct hi_i2c *pinfo, unsigned int reg_addr,
++			unsigned int length)
++{
++	unsigned int reg;
++
++	writel(reg_addr, pinfo->regbase + I2C_DMA_CMD1);
++	writel(length, pinfo->regbase + I2C_DMA_CMD2);
++
++	reg = readl(pinfo->regbase + I2C_DMA_CMD0);
++
++	/*start tx*/
++	reg &= ~0x40000000;
++	writel((0x80000000 | reg), pinfo->regbase + I2C_DMA_CMD0);
++}
++
++void hi_i2c_start_tx(struct hi_i2c *pinfo, unsigned int reg_addr,
++			unsigned int length)
++{
++	unsigned int reg;
++
++	writel(reg_addr, pinfo->regbase + I2C_DMA_CMD1);
++	writel(length, pinfo->regbase + I2C_DMA_CMD2);
++
++	reg = readl(pinfo->regbase + I2C_DMA_CMD0);
++
++	/*start rx*/
++	writel((0xc0000000 | reg), pinfo->regbase + I2C_DMA_CMD0);
++}
++
++int dma_to_i2c(unsigned int src, unsigned int dst, unsigned int length)
++{
++	int chan;
++
++	chan = do_dma_m2p(src, dst, length);
++	if (chan == -1)
++		hi_err("dma_to_i2c error\n");
++
++	return chan;
++}
++
++
++int i2c_to_dma(unsigned int src, unsigned int dst, unsigned int length)
++{
++	int chan;
++
++	chan = do_dma_p2m(dst, src, length);
++	if (chan == -1)
++		hi_err("dma_p2m error...\n");
++
++	return chan;
++}
++
++static int hi_i2c_do_dma_write(struct hi_i2c *pinfo, unsigned int reg_addr,
++		unsigned int reg_addr_num, unsigned int dma_buf,
++		unsigned int length)
++{
++	unsigned int temp_reg = reg_addr;
++	int chan, ret = 0;
++
++	/* 1. switch i2c devaddr and dma mode*/
++	if (hi_i2c_set_dev_addr_and_mode(pinfo, I2C_MODE_DMA) < 0) {
++		hi_err("HI_I2C_Dma_Write error...\n");
++		ret = -1;
++	}
++
++	if (2 == reg_addr_num) {
++		/* switch high byte and low byte */
++		temp_reg = REVERT_HL_BYTE(reg_addr);
++		writel(0x10000000, pinfo->regbase + I2C_DMA_CMD0);
++	} else {
++		writel(0x0, pinfo->regbase + I2C_DMA_CMD0);
++	}
++
++	/* 2. config i2c into DMA mode */
++	hi_i2c_dmac_config(pinfo, 0x1);
++
++	/* 3. start i2c logic to write */
++	hi_i2c_start_tx(pinfo, temp_reg, length - 1);
++
++	/* 4. transmit DATA from DMAC to I2C in DMA mode */
++	chan = dma_to_i2c(dma_buf, (pinfo->mem->start + I2C_DATA_CMD_REG),
++				length);
++	if (chan == -1) {
++		ret = -1;
++		goto fail_0;
++	}
++
++	if (dmac_wait(chan) != DMAC_CHN_SUCCESS) {
++		hi_err("dma wait failed\n");
++		ret = -1;
++		goto fail_1;
++	}
++
++	ret = hi_i2c_wait_idle(pinfo);
++fail_1:
++	dmac_channel_free(chan);
++fail_0:
++	hi_i2c_clr_status(pinfo);
++	return ret;
++}
++
++static int hi_i2c_do_dma_read(struct hi_i2c *pinfo, unsigned int reg_addr,
++		unsigned int reg_addr_num, unsigned int dma_buf,
++		unsigned int length)
++{
++	unsigned int temp_reg = reg_addr;
++	int chan, ret = 0;
++
++	/* 1. switch i2c devaddr and dma mode*/
++	if (hi_i2c_set_dev_addr_and_mode(pinfo, I2C_MODE_DMA) < 0) {
++		ret = -1;
++	}
++
++	if (2 == reg_addr_num) {
++		/* switch high byte and low byte */
++		temp_reg = REVERT_HL_BYTE(reg_addr);
++		writel(0x10000000, pinfo->regbase + I2C_DMA_CMD0);
++	} else {
++		writel(0x0, pinfo->regbase + I2C_DMA_CMD0);
++	}
++
++	/* 2. config i2c into DMA mode */
++	hi_i2c_dmac_config(pinfo, 0x0);
++
++	/* 3. transmit DATA from I2C to DMAC in DMA mode */
++	chan = i2c_to_dma((pinfo->mem->start + I2C_DATA_CMD_REG),
++				dma_buf, length);
++	if (chan == -1) {
++		ret = -1;
++		goto fail_0;
++	}
++
++	/* 4. start i2c logic to read */
++	hi_i2c_start_rx(pinfo, temp_reg, length - 1);
++
++	if (dmac_wait(chan) != DMAC_CHN_SUCCESS) {
++		hi_err("dma wait failed\n");
++		ret = -1;
++		goto fail_1;
++	}
++
++	ret = hi_i2c_wait_idle(pinfo);
++fail_1:
++	dmac_channel_free(chan);
++fail_0:
++	hi_i2c_clr_status(pinfo);
++	return ret;
++}
++
++#else
++static int hi_i2c_do_dma_write(struct hi_i2c *pinfo,
++		unsigned int reg_addr, unsigned int reg_addr_num,
++		unsigned int dma_buf, unsigned int length)
++{
++	hi_err("DMA is not enabled!");
++	return -1;
++}
++
++static int hi_i2c_do_dma_read(struct hi_i2c *pinfo,
++		unsigned int reg_addr, unsigned int reg_addr_num,
++		unsigned int dma_buf, unsigned int length)
++{
++	hi_err("DMA is not enabled!");
++	return -1;
++}
++#endif
++
++int hi_i2c_dma_write(const struct i2c_client *client, unsigned int dma_buf,
++		unsigned int reg_addr, unsigned int reg_addr_num,
++		unsigned int length)
++{
++	struct i2c_adapter *adap = client->adapter;
++	struct hi_i2c *pinfo = (struct hi_i2c *)i2c_get_adapdata(adap);
++	struct i2c_msg msgs;
++	int ret;
++	unsigned long flags;
++
++	spin_lock_irqsave(&pinfo->spinlock, flags);
++
++	memset(&msgs, 0x0, sizeof(struct i2c_msg));
++	msgs.addr = client->addr;
++	msgs.flags = client->flags;
++	msgs.len = length;
++
++	pinfo->msgs = &msgs;
++	pinfo->msg_num = length;
++	pinfo->msg_index = 0;
++
++	ret = hi_i2c_do_dma_write(pinfo, reg_addr, reg_addr_num, dma_buf,
++			length);
++
++	spin_unlock_irqrestore(&pinfo->spinlock, flags);
++
++	return ret;
++}
++EXPORT_SYMBOL(hi_i2c_dma_write);
++
++int hi_i2c_dma_read(const struct i2c_client *client, unsigned int dma_buf,
++		unsigned int reg_addr, unsigned int reg_addr_num,
++		unsigned int length)
++{
++	struct i2c_adapter *adap = client->adapter;
++	struct hi_i2c *pinfo = (struct hi_i2c *)i2c_get_adapdata(adap);
++	struct i2c_msg msgs;
++	int ret;
++	unsigned long flags;
++
++	spin_lock_irqsave(&pinfo->spinlock, flags);
++
++	memset(&msgs, 0x0, sizeof(struct i2c_msg));
++	msgs.addr = client->addr;
++	msgs.flags = client->flags;
++	msgs.flags |= I2C_M_RD;
++	msgs.len = length;
++
++	pinfo->msgs = &msgs;
++	pinfo->msg_num = length;
++	pinfo->msg_index = 0;
++
++	ret = hi_i2c_do_dma_read(pinfo, reg_addr, reg_addr_num, dma_buf,
++			length);
++
++	spin_unlock_irqrestore(&pinfo->spinlock, flags);
++
++	return ret;
++}
++EXPORT_SYMBOL(hi_i2c_dma_read);
++
++static int hi_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
++		int num)
++{
++	struct hi_i2c *pinfo = (struct hi_i2c *)i2c_get_adapdata(adap);
++	dma_addr_t dma_buf;
++	__u16 len;
++	unsigned int reg_addr;
++	unsigned int reg_width;
++	int ret;
++	unsigned long flags;
++
++	if (!msgs || (num <= 0)) {
++		hi_err("msgs == NULL || num <= 0, Invalid argument!\n");
++		return -EINVAL;
++	}
++
++	spin_lock_irqsave(&pinfo->spinlock, flags);
++
++	pinfo->msgs = msgs;
++	pinfo->msg_num = num;
++	pinfo->msg_index = 0;
++
++	len = pinfo->msgs->len;
++	if (pinfo->msgs->flags & I2C_M_16BIT_REG) {
++		reg_addr = pinfo->msgs->buf[0];
++		reg_addr |= pinfo->msgs->buf[1] << 8;
++		reg_width = 2;
++	} else {
++		reg_addr = pinfo->msgs->buf[0];
++		reg_width = 1;
++	}
++
++	if (pinfo->msgs->flags & I2C_M_DMA) {
++		if (pinfo->msgs->flags & I2C_M_16BIT_DATA) {
++			hi_err("I2C DMA no support I2C_M_16BIT_DATA\n");
++			ret = -EINVAL;
++			goto end;
++		}
++
++		if (((pinfo->msgs->flags & I2C_M_RD) && (len <= 0)) ||
++				(!(pinfo->msgs->flags & I2C_M_RD) &&
++				 (len <= reg_width))) {
++			hi_err("msgs->len == %d, Invalid argument!\n",
++					len);
++			ret = -EINVAL;
++			goto end;
++		}
++
++		dma_buf = dma_map_single(pinfo->dev,
++				pinfo->msgs->buf, len,
++				DMA_BIDIRECTIONAL);
++		if (dma_mapping_error(pinfo->dev, dma_buf)) {
++			hi_err("DMA mapping failed\n");
++			ret = -EINVAL;
++			goto end;
++		}
++		if (pinfo->msgs->flags & I2C_M_RD)
++			ret = hi_i2c_do_dma_read(pinfo, reg_addr,
++					reg_width, dma_buf, len);
++		else
++			ret = hi_i2c_do_dma_write(pinfo, reg_addr,
++					reg_width, dma_buf + reg_width,
++					len - reg_width);
++
++		dma_unmap_single(pinfo->dev, dma_buf, len,
++				DMA_BIDIRECTIONAL);
++
++		/*normally the ret = 0, so forced the return value to 1.*/
++		if (ret)
++			ret = -EIO;
++		else
++			ret = 1;
++	} else {
++		if (pinfo->msgs->flags & I2C_M_RD){
++			ret = hi_i2c_read(pinfo);
++		} else{
++			ret = hi_i2c_write(pinfo);
++		}
++		/*(ret = data_num) or (ret = msg_index),so force the return value to 1,
++		 * docking the upper interface.
++		 */
++		if (ret < 0)
++			ret = -EIO;
++		else
++			ret = 1;
++	}
++
++end:
++	spin_unlock_irqrestore(&pinfo->spinlock, flags);
++
++	/*
++	 * If everything went ok (i.e. 1 msg transmitted), (ret = 1) means return #bytes
++	 * transmitted, else return error code. see i2c-core.c
++	 */
++	return ret;
++}
++
++/* HI I2C READ *
++ * hi_i2c_master_recv - issue a single I2C message in master receive mode
++ * @client: Handle to slave device
++ * @buf: Where to store data read from slave
++ * @count: How many bytes to read, must be less than 64k since msg.len is u16
++ *
++ * Returns negative errno, or else the number of bytes read.
++ */
++int hi_i2c_master_recv(const struct i2c_client *client, char *buf,
++		int count)
++{
++	struct i2c_adapter *adap = client->adapter;
++	struct i2c_msg msgs;
++	unsigned int reg_width, data_width, max_width;
++	int msgs_count;
++
++	memset(&msgs, 0x0, sizeof(struct i2c_msg));
++	msgs.addr = client->addr;
++	msgs.flags = client->flags;
++	msgs.flags |= I2C_M_RD;
++
++	if (client->flags & I2C_M_16BIT_REG)
++		reg_width = 2;
++	else
++		reg_width = 1;
++
++	if (client->flags & I2C_M_16BIT_DATA)
++		data_width = 2;
++	else
++		data_width = 1;
++
++	max_width = max_t(size_t, reg_width, data_width);
++
++	if (count > max_width) {
++		msgs.flags |= I2C_M_DMA;
++		msgs.len = count;
++	} else if (count <= 0 ) {
++		hi_err("ERR. Invalid count: 0x%d!!!\n", count);
++		return -EINVAL;
++	} else
++		msgs.len = max_width;
++
++	if (!buf) {
++		hi_err("ERR. Invalid buf == NULL!!!\n");
++		return -EINVAL;
++	}
++	msgs.buf = buf;
++
++	msgs_count = hi_i2c_xfer(adap, &msgs, 1);
++
++	return (msgs_count == 1) ? count : -EIO;
++}
++EXPORT_SYMBOL(hi_i2c_master_recv);
++
++/*HI I2C WRITE*
++ * hi_i2c_master_send - issue a single I2C message in master transmit mode
++ * @client: Handle to slave device
++ * @buf: Data that will be written to the slave
++ * @count: How many bytes to write, must be less than 64k since msg.len is u16
++ *
++ * Returns negative errno, or else the number of bytes written.
++ */
++int hi_i2c_master_send(const struct i2c_client *client,
++	   const char *buf, int count)
++{
++	struct i2c_adapter *adap = client->adapter;
++	struct i2c_msg msgs;
++	unsigned int reg_width, data_width;
++	int msgs_count;
++
++	memset(&msgs, 0x0, sizeof(struct i2c_msg));
++	msgs.addr = client->addr;
++	msgs.flags = client->flags;
++
++	if (client->flags & I2C_M_16BIT_REG)
++		reg_width = 2;
++	else
++		reg_width = 1;
++
++	if (client->flags & I2C_M_16BIT_DATA)
++		data_width = 2;
++	else
++		data_width = 1;
++
++	if (count - reg_width > data_width)
++		msgs.flags |= I2C_M_DMA;
++	else if (count - reg_width < data_width) {
++		hi_err("ERR. Invalid count!!!\n");
++		return -EINVAL;
++	}
++
++	msgs.len = count;
++
++	if (!buf) {
++		hi_err("ERR. Invalid buf! == NULL!!\n");
++		return -EINVAL;
++	}
++	msgs.buf = (__u8 *)buf;
++
++	msgs_count = hi_i2c_xfer(adap, &msgs, 1);
++
++	return (msgs_count == 1) ? count : -EIO;
++}
++EXPORT_SYMBOL(hi_i2c_master_send);
++
++/**
++ * hi_i2c_transfer - execute a single or combined I2C message
++ * @adap: Handle to I2C bus
++ * @msgs: One or more messages to execute before STOP is issued to
++ *  terminate the operation; each message begins with a START.
++ * @num: Number of messages to be executed.
++ *
++ * Returns negative errno, else the number of messages executed.
++ *
++ * Note that there is no requirement that each message be sent to
++ * the same slave address, although that is the most common model.
++ */
++int hi_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
++		int num)
++{
++	printk("Wrong interface call."
++			"hi_i2c_master_recv is the only interface to i2c read!!!\n");
++
++	return -EIO;
++}
++EXPORT_SYMBOL(hi_i2c_transfer);
++/**************************************************************/
++
++static u32 hi_i2c_func(struct i2c_adapter *adap)
++{
++	return I2C_FUNC_I2C;
++}
++
++static const struct i2c_algorithm hi_i2c_algo = {
++	.master_xfer    = hi_i2c_xfer,
++	.functionality  = hi_i2c_func,
++};
++
++static int hi_i2c_probe(struct platform_device *pdev)
++{
++	int errorcode;
++	struct hi_i2c *pinfo;
++	struct i2c_adapter *adap;
++	struct resource *mem;
++	struct hi_platform_i2c *platform_info;
++
++	platform_info =
++		(struct hi_platform_i2c *)pdev->dev.platform_data;
++	if (platform_info == NULL) {
++		dev_err(&pdev->dev, "%s: Can't get platform_data!\n",
++				__func__);
++		errorcode = -EPERM;
++		goto i2c_errorcode_na;
++	}
++
++	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	if (mem == NULL) {
++		dev_err(&pdev->dev, "Get I2C mem resource failed!\n");
++		errorcode = -ENXIO;
++		goto i2c_errorcode_na;
++	}
++
++	pinfo = kzalloc(sizeof(struct hi_i2c), GFP_KERNEL);
++	if (pinfo == NULL) {
++		dev_err(&pdev->dev, "Out of memory!\n");
++		errorcode = -ENOMEM;
++		goto i2c_errorcode_na;
++	}
++
++	pinfo->regbase = (unsigned char __iomem *)IO_ADDRESS(mem->start);
++	pinfo->mem = mem;
++	pinfo->dev = &pdev->dev;
++	pinfo->pdata = platform_info;
++	pinfo->g_last_dev_addr = 0;
++
++	spin_lock_init(&pinfo->spinlock);
++
++	hi_i2c_hw_init(pinfo);
++
++	platform_set_drvdata(pdev, pinfo);
++
++	adap = &pinfo->adap;
++	i2c_set_adapdata(adap, pinfo);
++	adap->owner = THIS_MODULE;
++	adap->class = platform_info->i2c_class;
++	strlcpy(adap->name, pdev->name, sizeof(adap->name));
++	adap->algo = &hi_i2c_algo;
++	adap->dev.parent = &pdev->dev;
++	adap->nr = pdev->id;
++	adap->retries = CONFIG_HI_I2C_RETRIES;
++	errorcode = i2c_add_numbered_adapter(adap);
++	if (errorcode) {
++		dev_err(&pdev->dev,
++				"%s: Adding I2C adapter failed!\n", __func__);
++		goto i2c_errorcode_free_irq;
++	}
++
++	dev_notice(&pdev->dev,
++			"Hisilicon [%s] probed!\n",
++			dev_name(&pinfo->adap.dev));
++
++	goto i2c_errorcode_na;
++
++i2c_errorcode_free_irq:
++	free_irq(pinfo->irq, pinfo);
++	kfree(pinfo);
++
++i2c_errorcode_na:
++	return errorcode;
++}
++
++static int hi_i2c_remove(struct platform_device *pdev)
++{
++	struct hi_i2c *pinfo = NULL;
++
++	pinfo = platform_get_drvdata(pdev);
++
++	if (pinfo) {
++		i2c_del_adapter(&pinfo->adap);
++
++		free_irq(pinfo->irq, pinfo);
++
++		kfree(pinfo);
++	}
++
++	dev_notice(&pdev->dev,
++			"Remove Hisilicon Media Processor"
++			"I2C adapter.\n");
++
++	return 0;
++}
++
++#ifdef CONFIG_PM
++static int hi_i2c_suspend(struct platform_device *pdev, pm_message_t state)
++{
++	struct hi_i2c *pinfo;
++
++	pinfo = platform_get_drvdata(pdev);
++
++	hi_i2c_abortprocess(pinfo);
++
++	return 0;
++}
++
++static int hi_i2c_resume(struct platform_device *pdev)
++{
++	struct hi_i2c *pinfo;
++
++	pinfo = platform_get_drvdata(pdev);
++
++	hi_i2c_hw_init(pinfo);
++
++	return 0;
++}
++#else
++#define hi_i2c_suspend      NULL
++#define hi_i2c_resume       NULL
++#endif
++
++static struct platform_driver hi_i2c_driver = {
++	.probe		= hi_i2c_probe,
++	.remove		= hi_i2c_remove,
++	.suspend	= hi_i2c_suspend,
++	.resume		= hi_i2c_resume,
++	.driver		= {
++		.owner	= THIS_MODULE,
++		.name	= HI_I2C,
++	},
++};
++
++#ifdef CONFIG_ARCH_HI3519
++#include "i2c_hi3519.c"
++#endif
++#ifdef CONFIG_ARCH_HI3536C
++#include "i2c_hi3536c.c"
++#endif
++#ifdef CONFIG_ARCH_HI3531D
++#include "i2c_hi3531d.c"
++#endif
++#ifdef CONFIG_ARCH_HI3521D
++#include "i2c_hi3521d.c"
++#endif
++
++module_init(hi_i2c_module_init);
++module_exit(hi_i2c_module_exit);
++
++MODULE_DESCRIPTION("HISILICON I2C Bus driver");
++MODULE_AUTHOR("BVT OSDRV");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/i2c/busses/i2c-hisilicon.h b/drivers/i2c/busses/i2c-hisilicon.h
+new file mode 100644
+index 0000000..778fa1f
+--- /dev/null
++++ b/drivers/i2c/busses/i2c-hisilicon.h
+@@ -0,0 +1,108 @@
++#ifndef __HI_I2C_H__
++#define __HI_I2C_H__
++
++#define I2C_CON_REG		0x000
++#define I2C_TAR_REG		0x004
++#define I2C_DATA_CMD_REG	0x010
++#define I2C_SCL_H_REG		0x01C
++#define I2C_SCL_L_REG		0x020
++#define I2C_INTR_STAT_REG	0x02C
++#define I2C_INTR_MASK_REG	0x030
++#define I2C_INTR_RAW_REG	0x034
++#define I2C_RX_TL_REG		0x038
++#define I2C_TX_TL_REG		0x03C
++#define I2C_CLR_INTR_REG	0x040
++#define I2C_CLR_RX_OVER_REG	0x048
++#define I2C_CLR_TX_OVER_REG	0x04C
++#define I2C_ENABLE_REG		0x06C
++#define I2C_STATUS_REG		0x070
++#define I2C_TXFLR_REG		0x074
++#define I2C_RXFLR_REG		0x078
++#define I2C_SDA_HOLD_REG	0x07C
++#define I2C_TX_ABRT_SRC		0x080
++#define I2C_DMA_CTRL_REG	0x088
++#define I2C_DMA_TDLR		0x08C
++#define I2C_DMA_RDLR		0x090
++#define I2C_LPIF_STATE		0x0A8
++#define I2C_LOCK_REG		0x0AC
++#define I2C_AUTO_REG		0x0B0
++#define I2C_TX_RX_REG		0x0B4
++#define I2C_DMA_CMD0		0x0B8
++#define I2C_DMA_CMD1		0x0BC
++#define I2C_DMA_CMD2		0x0C0
++#define I2C_ENABLE_STATUS_REG	0x09C
++
++#define HI_I2C_FAST_MODE	0x65
++
++#define HI_I2C_UNLOCK_VALUE	0x1ACCE551
++
++#define HI_I2C_ENABLE		(1 << 0)
++
++#define HI_I2C_AUTO_MODE_OFF	0x0f000000
++
++#define HI_I2C_WRITE		0x80000000
++#define HI_I2C_READ		0xc0000000
++
++#define READ_OPERATION     (1)
++#define WRITE_OPERATION    0xfe
++
++#define CMD_I2C_WRITE      0x01
++#define CMD_I2C_READ       0x03
++
++/* I2C_COM_REG */
++#define I2C_SEND_ACK (~(1 << 4))
++#define I2C_START        (1 << 3)
++#define I2C_READ         (1 << 2)
++#define I2C_WRITE        (1 << 1)
++#define I2C_STOP (1 << 0)
++
++/* I2C_ENABLE_REG */
++#define I2C_ENABLE                  (1 << 0)
++
++#define I2C_RAW_TX_ABORT            (1 << 6)
++
++/*I2C_INTR_STAT_REG */
++#define I2C_AUTO_RX_FIFO_NOT_EMPTY  (1 << 8)
++#define I2C_AUTO_TX_FIFO_EMPTRY     (1 << 20)
++#define I2c_AUTO_TX_FIFO_NOT_FULL   (1 << 21)
++#define I2C_TX_ABRT                 (1 << 23)
++#define I2C_AUTO_DATA               (1 << 28)
++#define I2C_AUTO_ADDR               (1 << 29)
++
++/* I2C_STATUS */
++#define I2C_STATUS_WORKING          (1 << 0)
++
++#define IS_TX_FIFO_EMPTY(status)        (((status) &\
++			I2C_AUTO_TX_FIFO_EMPTRY) == I2C_AUTO_TX_FIFO_EMPTRY)
++#define IS_RX_FIFO_EMPTY(status)        (((status) &\
++			I2C_AUTO_RX_FIFO_NOT_EMPTY) == 0)
++#define IS_FIFO_EMPTY(status)           (IS_RX_FIFO_EMPTY(status) &&\
++			IS_TX_FIFO_EMPTY(status))
++#define IS_I2C_IDLE(status)             (((status) & I2C_STATUS_WORKING) == 0)
++
++#define REG_SHIFT		16
++#define DATA_16BIT_MASK		0xFFFF
++#define DATA_8BIT_MASK		0xFFFF
++
++#define REVERT_HL_BYTE(value)   ((value >> 8) | ((value & 0xFF) << 8))
++
++/*
++ * I2C Interrupt related Macros
++ */
++#define DEFAULT_I2C_REG_IMSC		0x0UL
++#define DISABLE_ALL_INTERRUPTS		((~DEFAULT_I2C_REG_IMSC) & 0xfff)
++#define ENABLE_ALL_INTERRUPTS		DEFAULT_I2C_REG_IMSC
++
++typedef enum i2c_mode_e {
++	I2C_MODE_AUTO,
++	I2C_MODE_DMA,
++	I2C_MODE_NONE,
++} i2c_mode_e;
++
++struct hi_platform_i2c {
++	int	clk_limit;
++	unsigned int i2c_class;
++	unsigned int clk_rate;
++};
++
++#endif
+diff --git a/drivers/i2c/busses/i2c_hi3519.c b/drivers/i2c/busses/i2c_hi3519.c
+new file mode 100644
+index 0000000..b15ae88
+--- /dev/null
++++ b/drivers/i2c/busses/i2c_hi3519.c
+@@ -0,0 +1,147 @@
++#include "i2c_hi3519.h"
++
++unsigned int get_apb_clk(void)
++{
++	unsigned int apb_clk;
++
++	apb_clk = get_bus_clk() / 4;
++
++	return apb_clk;
++}
++
++static struct resource hi_i2c0_resources[] = {
++	[0] = {
++		.start          = CONFIG_HI_I2C0_IO_BASE,
++		.end            = CONFIG_HI_I2C0_IO_BASE
++			+ CONFIG_HI_I2C0_IO_SIZE  - 1,
++		.flags          = IORESOURCE_MEM,
++	},
++};
++
++struct hi_platform_i2c hi_i2c0_platform_data = {
++	.clk_limit      = CONFIG_HI_I2C0_CLK_LIMIT,
++	.i2c_class      = I2C_CLASS_DDC,
++};
++
++struct platform_device hi_i2c0_device = {
++	.name           = HI_I2C,
++	.id             = 0,
++	.resource       = hi_i2c0_resources,
++	.num_resources  = ARRAY_SIZE(hi_i2c0_resources),
++	.dev            = {
++		.platform_data  = &hi_i2c0_platform_data,
++	}
++};
++
++static struct resource hi_i2c1_resources[] = {
++	[0] = {
++		.start          = CONFIG_HI_I2C1_IO_BASE,
++		.end            = CONFIG_HI_I2C1_IO_BASE
++			+ CONFIG_HI_I2C1_IO_SIZE  - 1,
++		.flags          = IORESOURCE_MEM,
++	},
++};
++
++struct hi_platform_i2c hi_i2c1_platform_data = {
++	.clk_limit      = CONFIG_HI_I2C1_CLK_LIMIT,
++	.i2c_class      = I2C_CLASS_DDC,
++};
++
++struct platform_device hi_i2c1_device = {
++	.name           = HI_I2C,
++	.id             = 1,
++	.resource       = hi_i2c1_resources,
++	.num_resources  = ARRAY_SIZE(hi_i2c1_resources),
++	.dev            = {
++		.platform_data  = &hi_i2c1_platform_data,
++	}
++};
++
++static struct resource hi_i2c2_resources[] = {
++	[0] = {
++		.start          = CONFIG_HI_I2C2_IO_BASE,
++		.end            = CONFIG_HI_I2C2_IO_BASE
++			+ CONFIG_HI_I2C2_IO_SIZE  - 1,
++		.flags          = IORESOURCE_MEM,
++	},
++};
++
++struct hi_platform_i2c hi_i2c2_platform_data = {
++	.clk_limit      = CONFIG_HI_I2C2_CLK_LIMIT,
++	.i2c_class      = I2C_CLASS_DDC,
++};
++
++struct platform_device hi_i2c2_device = {
++	.name           = HI_I2C,
++	.id             = 2,
++	.resource       = hi_i2c2_resources,
++	.num_resources  = ARRAY_SIZE(hi_i2c2_resources),
++	.dev            = {
++		.platform_data  = &hi_i2c2_platform_data,
++	}
++};
++
++static struct resource hi_i2c3_resources[] = {
++	[0] = {
++		.start          = CONFIG_HI_I2C3_IO_BASE,
++		.end            = CONFIG_HI_I2C3_IO_BASE
++			+ CONFIG_HI_I2C3_IO_SIZE  - 1,
++		.flags          = IORESOURCE_MEM,
++	},
++};
++
++struct hi_platform_i2c hi_i2c3_platform_data = {
++	.clk_limit      = CONFIG_HI_I2C3_CLK_LIMIT,
++	.i2c_class      = I2C_CLASS_DDC,
++};
++
++struct platform_device hi_i2c3_device = {
++	.name           = HI_I2C,
++	.id             = 3,
++	.resource       = hi_i2c3_resources,
++	.num_resources  = ARRAY_SIZE(hi_i2c3_resources),
++	.dev            = {
++		.platform_data  = &hi_i2c3_platform_data,
++	}
++};
++
++static struct platform_device *hi_i2c_devices[] __initdata = {
++	&hi_i2c0_device,
++	&hi_i2c1_device,
++	&hi_i2c2_device,
++	&hi_i2c3_device,
++};
++
++static int __init hi_i2c_module_init(void)
++{
++	int ret;
++
++
++	ret = platform_add_devices(hi_i2c_devices, ARRAY_SIZE(hi_i2c_devices));
++	if (ret) {
++		hi_err("i2c device register failed!\n");
++		return ret;
++	}
++
++	ret = platform_driver_register(&hi_i2c_driver);
++	if (ret) {
++		platform_device_unregister(&hi_i2c3_device);
++		platform_device_unregister(&hi_i2c2_device);
++		platform_device_unregister(&hi_i2c1_device);
++		platform_device_unregister(&hi_i2c0_device);
++		hi_err("i2c driver register failed!\n");
++		return ret;
++	}
++
++	return ret;
++}
++
++static void __exit hi_i2c_module_exit(void)
++{
++	platform_driver_unregister(&hi_i2c_driver);
++
++	platform_device_unregister(&hi_i2c3_device);
++	platform_device_unregister(&hi_i2c2_device);
++	platform_device_unregister(&hi_i2c1_device);
++	platform_device_unregister(&hi_i2c0_device);
++}
+diff --git a/drivers/i2c/busses/i2c_hi3519.h b/drivers/i2c/busses/i2c_hi3519.h
+new file mode 100644
+index 0000000..898668e
+--- /dev/null
++++ b/drivers/i2c/busses/i2c_hi3519.h
+@@ -0,0 +1,12 @@
++#include <linux/platform_device.h>
++
++#define CRG_REG_BASE	0x12010000
++#define A7_AXI_SCALE_REG   IO_ADDRESS(CRG_REG_BASE + 0x34)
++
++#define get_bus_clk() ({\
++		unsigned long tmp_reg, busclk = 0;\
++		tmp_reg = readl((void *)A7_AXI_SCALE_REG);\
++		if (0x1 == ((tmp_reg >> 12) & 0x3))\
++			busclk = 200000000;\
++		busclk;\
++	})
+diff --git a/drivers/i2c/busses/i2c_hi3521d.c b/drivers/i2c/busses/i2c_hi3521d.c
+new file mode 100644
+index 0000000..6223a41
+--- /dev/null
++++ b/drivers/i2c/busses/i2c_hi3521d.c
+@@ -0,0 +1,66 @@
++#include <mach/platform.h>
++
++unsigned int get_apb_clk(void)
++{
++	unsigned int apb_clk;
++
++	apb_clk = get_bus_clk() / CFG_TIMER_PER ;
++
++	return apb_clk;
++}
++
++static struct resource hi_i2c0_resources[] = {
++	[0] = {
++		.start          = CONFIG_HI_I2C0_IO_BASE,
++		.end            = CONFIG_HI_I2C0_IO_BASE
++			+ CONFIG_HI_I2C0_IO_SIZE  - 1,
++		.flags          = IORESOURCE_MEM,
++	},
++};
++
++struct hi_platform_i2c hi_i2c0_platform_data = {
++	.clk_limit      = CONFIG_HI_I2C0_CLK_LIMIT,
++	.i2c_class      = I2C_CLASS_DDC,
++};
++
++struct platform_device hi_i2c0_device = {
++	.name           = HI_I2C,
++	.id             = 0,
++	.resource       = hi_i2c0_resources,
++	.num_resources  = ARRAY_SIZE(hi_i2c0_resources),
++	.dev            = {
++		.platform_data  = &hi_i2c0_platform_data,
++	}
++};
++
++static struct platform_device *hi_i2c_devices[] __initdata = {
++	&hi_i2c0_device,
++};
++
++static int __init hi_i2c_module_init(void)
++{
++	int ret;
++
++
++	ret = platform_add_devices(hi_i2c_devices, ARRAY_SIZE(hi_i2c_devices));
++	if (ret) {
++		hi_err("i2c device register failed!\n");
++		return ret;
++	}
++
++	ret = platform_driver_register(&hi_i2c_driver);
++	if (ret) {
++		platform_device_unregister(&hi_i2c0_device);
++		hi_err("i2c driver register failed!\n");
++		return ret;
++	}
++
++	return ret;
++}
++
++static void __exit hi_i2c_module_exit(void)
++{
++	platform_driver_unregister(&hi_i2c_driver);
++
++	platform_device_unregister(&hi_i2c0_device);
++}
+diff --git a/drivers/i2c/busses/i2c_hi3531d.c b/drivers/i2c/busses/i2c_hi3531d.c
+new file mode 100644
+index 0000000..fdabe84
+--- /dev/null
++++ b/drivers/i2c/busses/i2c_hi3531d.c
+@@ -0,0 +1,93 @@
++#include <mach/platform.h>
++
++unsigned int get_apb_clk(void)
++{
++	unsigned int apb_clk;
++
++	apb_clk = get_bus_clk() / CFG_TIMER_PER ;
++
++	return apb_clk;
++}
++
++static struct resource hi_i2c0_resources[] = {
++	[0] = {
++		.start          = CONFIG_HI_I2C0_IO_BASE,
++		.end            = CONFIG_HI_I2C0_IO_BASE
++			+ CONFIG_HI_I2C0_IO_SIZE  - 1,
++		.flags          = IORESOURCE_MEM,
++	},
++};
++
++struct hi_platform_i2c hi_i2c0_platform_data = {
++	.clk_limit      = CONFIG_HI_I2C0_CLK_LIMIT,
++	.i2c_class      = I2C_CLASS_DDC,
++};
++
++struct platform_device hi_i2c0_device = {
++	.name           = HI_I2C,
++	.id             = 0,
++	.resource       = hi_i2c0_resources,
++	.num_resources  = ARRAY_SIZE(hi_i2c0_resources),
++	.dev            = {
++		.platform_data  = &hi_i2c0_platform_data,
++	}
++};
++
++static struct resource hi_i2c1_resources[] = {
++	[0] = {
++		.start          = CONFIG_HI_I2C1_IO_BASE,
++		.end            = CONFIG_HI_I2C1_IO_BASE
++			+ CONFIG_HI_I2C1_IO_SIZE  - 1,
++		.flags          = IORESOURCE_MEM,
++	},
++};
++
++struct hi_platform_i2c hi_i2c1_platform_data = {
++	.clk_limit      = CONFIG_HI_I2C1_CLK_LIMIT,
++	.i2c_class      = I2C_CLASS_DDC,
++};
++
++struct platform_device hi_i2c1_device = {
++	.name           = HI_I2C,
++	.id             = 1,
++	.resource       = hi_i2c1_resources,
++	.num_resources  = ARRAY_SIZE(hi_i2c1_resources),
++	.dev            = {
++		.platform_data  = &hi_i2c1_platform_data,
++	}
++};
++
++static struct platform_device *hi_i2c_devices[] __initdata = {
++	&hi_i2c0_device,
++	&hi_i2c1_device,
++};
++
++static int __init hi_i2c_module_init(void)
++{
++	int ret;
++
++
++	ret = platform_add_devices(hi_i2c_devices, ARRAY_SIZE(hi_i2c_devices));
++	if (ret) {
++		hi_err("i2c device register failed!\n");
++		return ret;
++	}
++
++	ret = platform_driver_register(&hi_i2c_driver);
++	if (ret) {
++		platform_device_unregister(&hi_i2c1_device);
++		platform_device_unregister(&hi_i2c0_device);
++		hi_err("i2c driver register failed!\n");
++		return ret;
++	}
++
++	return ret;
++}
++
++static void __exit hi_i2c_module_exit(void)
++{
++	platform_driver_unregister(&hi_i2c_driver);
++
++	platform_device_unregister(&hi_i2c1_device);
++	platform_device_unregister(&hi_i2c0_device);
++}
+diff --git a/drivers/i2c/busses/i2c_hi3536c.c b/drivers/i2c/busses/i2c_hi3536c.c
+new file mode 100644
+index 0000000..6223a41
+--- /dev/null
++++ b/drivers/i2c/busses/i2c_hi3536c.c
+@@ -0,0 +1,66 @@
++#include <mach/platform.h>
++
++unsigned int get_apb_clk(void)
++{
++	unsigned int apb_clk;
++
++	apb_clk = get_bus_clk() / CFG_TIMER_PER ;
++
++	return apb_clk;
++}
++
++static struct resource hi_i2c0_resources[] = {
++	[0] = {
++		.start          = CONFIG_HI_I2C0_IO_BASE,
++		.end            = CONFIG_HI_I2C0_IO_BASE
++			+ CONFIG_HI_I2C0_IO_SIZE  - 1,
++		.flags          = IORESOURCE_MEM,
++	},
++};
++
++struct hi_platform_i2c hi_i2c0_platform_data = {
++	.clk_limit      = CONFIG_HI_I2C0_CLK_LIMIT,
++	.i2c_class      = I2C_CLASS_DDC,
++};
++
++struct platform_device hi_i2c0_device = {
++	.name           = HI_I2C,
++	.id             = 0,
++	.resource       = hi_i2c0_resources,
++	.num_resources  = ARRAY_SIZE(hi_i2c0_resources),
++	.dev            = {
++		.platform_data  = &hi_i2c0_platform_data,
++	}
++};
++
++static struct platform_device *hi_i2c_devices[] __initdata = {
++	&hi_i2c0_device,
++};
++
++static int __init hi_i2c_module_init(void)
++{
++	int ret;
++
++
++	ret = platform_add_devices(hi_i2c_devices, ARRAY_SIZE(hi_i2c_devices));
++	if (ret) {
++		hi_err("i2c device register failed!\n");
++		return ret;
++	}
++
++	ret = platform_driver_register(&hi_i2c_driver);
++	if (ret) {
++		platform_device_unregister(&hi_i2c0_device);
++		hi_err("i2c driver register failed!\n");
++		return ret;
++	}
++
++	return ret;
++}
++
++static void __exit hi_i2c_module_exit(void)
++{
++	platform_driver_unregister(&hi_i2c_driver);
++
++	platform_device_unregister(&hi_i2c0_device);
++}
+diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
+index 7bd1b5c..b5ec010 100644
+--- a/drivers/i2c/i2c-core.c
++++ b/drivers/i2c/i2c-core.c
+@@ -881,9 +881,14 @@ static int i2c_check_client_addr_validity(const struct i2c_client *client)
+ 		if (client->addr > 0x3ff)
+ 			return -EINVAL;
+ 	} else {
++#ifdef	CONFIG_HI_I2C
+ 		/* 7-bit address, reject the general call address */
++		if (client->addr == 0x00 || client->addr > 0xfe)
++			return -EINVAL;
++#else
+ 		if (client->addr == 0x00 || client->addr > 0x7f)
+ 			return -EINVAL;
++#endif
+ 	}
+ 	return 0;
+ }
+@@ -2123,7 +2128,11 @@ int i2c_master_send(const struct i2c_client *client, const char *buf, int count)
+ 	struct i2c_msg msg;
+ 
+ 	msg.addr = client->addr;
++#ifdef CONFIG_HI_I2C
++	msg.flags = client->flags;
++#else
+ 	msg.flags = client->flags & I2C_M_TEN;
++#endif
+ 	msg.len = count;
+ 	msg.buf = (char *)buf;
+ 
+@@ -2152,7 +2161,11 @@ int i2c_master_recv(const struct i2c_client *client, char *buf, int count)
+ 	int ret;
+ 
+ 	msg.addr = client->addr;
++#ifdef CONFIG_HI_I2C
++	msg.flags = client->flags;
++#else
+ 	msg.flags = client->flags & I2C_M_TEN;
++#endif
+ 	msg.flags |= I2C_M_RD;
+ 	msg.len = count;
+ 	msg.buf = buf;
+diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
+index 71c7a39..d9dd11c 100644
+--- a/drivers/i2c/i2c-dev.c
++++ b/drivers/i2c/i2c-dev.c
+@@ -138,22 +138,69 @@ static ssize_t i2cdev_read(struct file *file, char __user *buf, size_t count,
+ {
+ 	char *tmp;
+ 	int ret;
+-
++#ifdef CONFIG_HI_I2C
++	unsigned reg_width;
++	unsigned data_width;
++#endif
+ 	struct i2c_client *client = file->private_data;
+ 
+ 	if (count > 8192)
+ 		count = 8192;
+ 
++#ifdef CONFIG_HI_I2C
++	if (client->flags & I2C_M_16BIT_REG)
++		reg_width = 2;
++	else
++		reg_width = 1;
++
++	if (client->flags & I2C_M_16BIT_DATA)
++		data_width = 2;
++	else
++		data_width = 1;
++
++	if (client->flags & I2C_M_DMA)
++		tmp = kmalloc(max_t(size_t, reg_width, count),
++				GFP_KERNEL);
++	else
++		tmp = kmalloc(max_t(size_t, reg_width, data_width),
++				GFP_KERNEL);
++
++	if (tmp == NULL)
++		return -ENOMEM;
++
++	if (copy_from_user(tmp, buf, reg_width))
++		return -EFAULT;
++#else
+ 	tmp = kmalloc(count, GFP_KERNEL);
+ 	if (tmp == NULL)
+ 		return -ENOMEM;
++#endif
+ 
+ 	pr_debug("i2c-dev: i2c-%d reading %zu bytes.\n",
+ 		iminor(file_inode(file)), count);
+ 
++#ifdef CONFIG_HI_I2C
++	if (client->flags & I2C_M_DMA)
++		ret = i2c_master_recv(client, tmp,
++				max_t(size_t, reg_width, count));
++	else
++		ret = i2c_master_recv(client, tmp,
++				max_t(size_t, reg_width, data_width));
++#else
+ 	ret = i2c_master_recv(client, tmp, count);
++#endif
++
++#ifdef CONFIG_HI_I2C
++	if (ret >= 0) {
++		if (client->flags & I2C_M_DMA)
++			ret = copy_to_user(buf, tmp, count) ? -EFAULT : ret;
++		else
++			ret = copy_to_user(buf, tmp, data_width) ? -EFAULT : ret;
++	}
++#else
+ 	if (ret >= 0)
+ 		ret = copy_to_user(buf, tmp, count) ? -EFAULT : ret;
++#endif
+ 	kfree(tmp);
+ 	return ret;
+ }
+@@ -168,6 +215,9 @@ static ssize_t i2cdev_write(struct file *file, const char __user *buf,
+ 	if (count > 8192)
+ 		count = 8192;
+ 
++	if (count == 0)
++		return -EINVAL;
++
+ 	tmp = memdup_user(buf, count);
+ 	if (IS_ERR(tmp))
+ 		return PTR_ERR(tmp);
+@@ -272,6 +322,11 @@ static noinline int i2cdev_ioctl_rdrw(struct i2c_client *client,
+ 			break;
+ 		}
+ 
++		if (rdwr_pa[i].len == 0) {
++			res = -EINVAL;
++			break;
++		}
++
+ 		data_ptrs[i] = (u8 __user *)rdwr_pa[i].buf;
+ 		rdwr_pa[i].buf = memdup_user(data_ptrs[i], rdwr_pa[i].len);
+ 		if (IS_ERR(rdwr_pa[i].buf)) {
+@@ -431,8 +486,13 @@ static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+ 		 * the PEC flag already set, the i2c-dev driver won't see
+ 		 * (or use) this setting.
+ 		 */
++#ifdef CONFIG_HI_I2C
++		if ((arg > 0x3ff) ||
++		    (((client->flags & I2C_M_TEN) == 0) && arg > 0xfe))
++#else
+ 		if ((arg > 0x3ff) ||
+ 		    (((client->flags & I2C_M_TEN) == 0) && arg > 0x7f))
++#endif
+ 			return -EINVAL;
+ 		if (cmd == I2C_SLAVE && i2cdev_check_addr(client->adapter, arg))
+ 			return -EBUSY;
+@@ -451,6 +511,26 @@ static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+ 		else
+ 			client->flags &= ~I2C_CLIENT_PEC;
+ 		return 0;
++#ifdef CONFIG_HI_I2C
++	case I2C_16BIT_REG:
++		if (arg)
++			client->flags |= I2C_M_16BIT_REG;
++		else
++			client->flags &= ~I2C_M_16BIT_REG;
++		return 0;
++	case I2C_16BIT_DATA:
++		if (arg)
++			client->flags |= I2C_M_16BIT_DATA;
++		else
++			client->flags &= ~I2C_M_16BIT_DATA;
++		return 0;
++	case I2C_DMA:
++		if (arg)
++			client->flags |= I2C_M_DMA;
++		else
++			client->flags &= ~I2C_M_DMA;
++		return 0;
++#endif
+ 	case I2C_FUNCS:
+ 		funcs = i2c_get_functionality(client->adapter);
+ 		return put_user(funcs, (unsigned long __user *)arg);
+diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c
+index 35c02ae..6da5492 100644
+--- a/drivers/iio/industrialio-event.c
++++ b/drivers/iio/industrialio-event.c
+@@ -492,6 +492,7 @@ int iio_device_register_eventset(struct iio_dev *indio_dev)
+ 
+ error_free_setup_event_lines:
+ 	iio_free_chan_devattr_list(&indio_dev->event_interface->dev_attr_list);
++	mutex_destroy(&indio_dev->event_interface->read_lock);
+ 	kfree(indio_dev->event_interface);
+ 	indio_dev->event_interface = NULL;
+ 	return ret;
+@@ -517,5 +518,6 @@ void iio_device_unregister_eventset(struct iio_dev *indio_dev)
+ 		return;
+ 	iio_free_chan_devattr_list(&indio_dev->event_interface->dev_attr_list);
+ 	kfree(indio_dev->event_interface->group.attrs);
++	mutex_destroy(&indio_dev->event_interface->read_lock);
+ 	kfree(indio_dev->event_interface);
+ }
+diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig
+index a11ff74..518efa2 100644
+--- a/drivers/input/Kconfig
++++ b/drivers/input/Kconfig
+@@ -174,6 +174,25 @@ config INPUT_APMPOWER
+ 	  To compile this driver as a module, choose M here: the
+ 	  module will be called apm-power.
+ 
++config INPUT_KEYRESET
++	tristate "Reset key"
++	depends on INPUT
++	select INPUT_KEYCOMBO
++	---help---
++	  Say Y here if you want to reboot when some keys are pressed;
++
++	  To compile this driver as a module, choose M here: the
++	  module will be called keyreset.
++
++config INPUT_KEYCOMBO
++	tristate "Key combo"
++	depends on INPUT
++	---help---
++	  Say Y here if you want to take action when some keys are pressed;
++
++	  To compile this driver as a module, choose M here: the
++	  module will be called keycombo.
++
+ comment "Input Device Drivers"
+ 
+ source "drivers/input/keyboard/Kconfig"
+diff --git a/drivers/input/Makefile b/drivers/input/Makefile
+index 5ca3f63..ee4c065 100644
+--- a/drivers/input/Makefile
++++ b/drivers/input/Makefile
+@@ -25,3 +25,6 @@ obj-$(CONFIG_INPUT_TOUCHSCREEN)	+= touchscreen/
+ obj-$(CONFIG_INPUT_MISC)	+= misc/
+ 
+ obj-$(CONFIG_INPUT_APMPOWER)	+= apm-power.o
++obj-$(CONFIG_INPUT_KEYRESET)	+= keyreset.o
++obj-$(CONFIG_INPUT_KEYCOMBO)	+= keycombo.o
++
+diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
+index 8afa28e..738a2a3 100644
+--- a/drivers/input/evdev.c
++++ b/drivers/input/evdev.c
+@@ -26,6 +26,7 @@
+ #include <linux/major.h>
+ #include <linux/device.h>
+ #include <linux/cdev.h>
++#include <linux/wakelock.h>
+ #include "input-compat.h"
+ 
+ struct evdev {
+@@ -46,6 +47,9 @@ struct evdev_client {
+ 	unsigned int tail;
+ 	unsigned int packet_head; /* [future] position of the first element of next packet */
+ 	spinlock_t buffer_lock; /* protects access to buffer, head and tail */
++	struct wake_lock wake_lock;
++	bool use_wake_lock;
++	char name[28];
+ 	struct fasync_struct *fasync;
+ 	struct evdev *evdev;
+ 	struct list_head node;
+@@ -149,10 +153,14 @@ static void __pass_event(struct evdev_client *client,
+ 		client->buffer[client->tail].value = 0;
+ 
+ 		client->packet_head = client->tail;
++		if (client->use_wake_lock)
++			wake_unlock(&client->wake_lock);
+ 	}
+ 
+ 	if (event->type == EV_SYN && event->code == SYN_REPORT) {
+ 		client->packet_head = client->head;
++		if (client->use_wake_lock)
++			wake_lock(&client->wake_lock);
+ 		kill_fasync(&client->fasync, SIGIO, POLL_IN);
+ 	}
+ }
+@@ -371,6 +379,9 @@ static int evdev_release(struct inode *inode, struct file *file)
+ 
+ 	evdev_detach_client(evdev, client);
+ 
++	if (client->use_wake_lock)
++		wake_lock_destroy(&client->wake_lock);
++
+ 	if (is_vmalloc_addr(client))
+ 		vfree(client);
+ 	else
+@@ -407,6 +418,8 @@ static int evdev_open(struct inode *inode, struct file *file)
+ 
+ 	client->bufsize = bufsize;
+ 	spin_lock_init(&client->buffer_lock);
++	snprintf(client->name, sizeof(client->name), "%s-%d",
++			dev_name(&evdev->dev), task_tgid_vnr(current));
+ 	client->evdev = evdev;
+ 	evdev_attach_client(evdev, client);
+ 
+@@ -473,6 +486,9 @@ static int evdev_fetch_next_event(struct evdev_client *client,
+ 	if (have_event) {
+ 		*event = client->buffer[client->tail++];
+ 		client->tail &= client->bufsize - 1;
++		if (client->use_wake_lock &&
++		    client->packet_head == client->tail)
++			wake_unlock(&client->wake_lock);
+ 	}
+ 
+ 	spin_unlock_irq(&client->buffer_lock);
+@@ -795,6 +811,11 @@ static int evdev_handle_mt_request(struct input_dev *dev,
+ 	return 0;
+ }
+ 
++/*
++ * HACK: disable conflicting EVIOCREVOKE until Android userspace stops using
++ * EVIOCSSUSPENDBLOCK
++ */
++/*
+ static int evdev_revoke(struct evdev *evdev, struct evdev_client *client,
+ 			struct file *file)
+ {
+@@ -805,6 +826,36 @@ static int evdev_revoke(struct evdev *evdev, struct evdev_client *client,
+ 
+ 	return 0;
+ }
++*/
++
++static int evdev_enable_suspend_block(struct evdev *evdev,
++				      struct evdev_client *client)
++{
++	if (client->use_wake_lock)
++		return 0;
++
++	spin_lock_irq(&client->buffer_lock);
++	wake_lock_init(&client->wake_lock, WAKE_LOCK_SUSPEND, client->name);
++	client->use_wake_lock = true;
++	if (client->packet_head != client->tail)
++		wake_lock(&client->wake_lock);
++	spin_unlock_irq(&client->buffer_lock);
++	return 0;
++}
++
++static int evdev_disable_suspend_block(struct evdev *evdev,
++				       struct evdev_client *client)
++{
++	if (!client->use_wake_lock)
++		return 0;
++
++	spin_lock_irq(&client->buffer_lock);
++	client->use_wake_lock = false;
++	wake_lock_destroy(&client->wake_lock);
++	spin_unlock_irq(&client->buffer_lock);
++
++	return 0;
++}
+ 
+ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
+ 			   void __user *p, int compat_mode)
+@@ -868,12 +919,17 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
+ 		else
+ 			return evdev_ungrab(evdev, client);
+ 
++	/*
++	 * HACK: disable conflicting EVIOCREVOKE until Android userspace stops
++	 * using EVIOCSSUSPENDBLOCK
++	 */
++	/*
+ 	case EVIOCREVOKE:
+ 		if (p)
+ 			return -EINVAL;
+ 		else
+ 			return evdev_revoke(evdev, client, file);
+-
++	*/
+ 	case EVIOCSCLOCKID:
+ 		if (copy_from_user(&i, p, sizeof(unsigned int)))
+ 			return -EFAULT;
+@@ -893,6 +949,15 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
+ 
+ 	case EVIOCSKEYCODE_V2:
+ 		return evdev_handle_set_keycode_v2(dev, p);
++
++	case EVIOCGSUSPENDBLOCK:
++		return put_user(client->use_wake_lock, ip);
++
++	case EVIOCSSUSPENDBLOCK:
++		if (p)
++			return evdev_enable_suspend_block(evdev, client);
++		else
++			return evdev_disable_suspend_block(evdev, client);
+ 	}
+ 
+ 	size = _IOC_SIZE(cmd);
+diff --git a/drivers/input/keycombo.c b/drivers/input/keycombo.c
+new file mode 100644
+index 0000000..2fba451
+--- /dev/null
++++ b/drivers/input/keycombo.c
+@@ -0,0 +1,261 @@
++/* drivers/input/keycombo.c
++ *
++ * Copyright (C) 2014 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#include <linux/input.h>
++#include <linux/keycombo.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/reboot.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++
++struct keycombo_state {
++	struct input_handler input_handler;
++	unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];
++	unsigned long upbit[BITS_TO_LONGS(KEY_CNT)];
++	unsigned long key[BITS_TO_LONGS(KEY_CNT)];
++	spinlock_t lock;
++	struct  workqueue_struct *wq;
++	int key_down_target;
++	int key_down;
++	int key_up;
++	struct delayed_work key_down_work;
++	int delay;
++	struct work_struct key_up_work;
++	void (*key_up_fn)(void *);
++	void (*key_down_fn)(void *);
++	void *priv;
++	int key_is_down;
++	struct wakeup_source combo_held_wake_source;
++	struct wakeup_source combo_up_wake_source;
++};
++
++static void do_key_down(struct work_struct *work)
++{
++	struct delayed_work *dwork = container_of(work, struct delayed_work,
++									work);
++	struct keycombo_state *state = container_of(dwork,
++					struct keycombo_state, key_down_work);
++	if (state->key_down_fn)
++		state->key_down_fn(state->priv);
++}
++
++static void do_key_up(struct work_struct *work)
++{
++	struct keycombo_state *state = container_of(work, struct keycombo_state,
++								key_up_work);
++	if (state->key_up_fn)
++		state->key_up_fn(state->priv);
++	__pm_relax(&state->combo_up_wake_source);
++}
++
++static void keycombo_event(struct input_handle *handle, unsigned int type,
++		unsigned int code, int value)
++{
++	unsigned long flags;
++	struct keycombo_state *state = handle->private;
++
++	if (type != EV_KEY)
++		return;
++
++	if (code >= KEY_MAX)
++		return;
++
++	if (!test_bit(code, state->keybit))
++		return;
++
++	spin_lock_irqsave(&state->lock, flags);
++	if (!test_bit(code, state->key) == !value)
++		goto done;
++	__change_bit(code, state->key);
++	if (test_bit(code, state->upbit)) {
++		if (value)
++			state->key_up++;
++		else
++			state->key_up--;
++	} else {
++		if (value)
++			state->key_down++;
++		else
++			state->key_down--;
++	}
++	if (state->key_down == state->key_down_target && state->key_up == 0) {
++		__pm_stay_awake(&state->combo_held_wake_source);
++		state->key_is_down = 1;
++		if (queue_delayed_work(state->wq, &state->key_down_work,
++								state->delay))
++			pr_debug("Key down work already queued!");
++	} else if (state->key_is_down) {
++		if (!cancel_delayed_work(&state->key_down_work)) {
++			__pm_stay_awake(&state->combo_up_wake_source);
++			queue_work(state->wq, &state->key_up_work);
++		}
++		__pm_relax(&state->combo_held_wake_source);
++		state->key_is_down = 0;
++	}
++done:
++	spin_unlock_irqrestore(&state->lock, flags);
++}
++
++static int keycombo_connect(struct input_handler *handler,
++		struct input_dev *dev,
++		const struct input_device_id *id)
++{
++	int i;
++	int ret;
++	struct input_handle *handle;
++	struct keycombo_state *state =
++		container_of(handler, struct keycombo_state, input_handler);
++	for (i = 0; i < KEY_MAX; i++) {
++		if (test_bit(i, state->keybit) && test_bit(i, dev->keybit))
++			break;
++	}
++	if (i == KEY_MAX)
++		return -ENODEV;
++
++	handle = kzalloc(sizeof(*handle), GFP_KERNEL);
++	if (!handle)
++		return -ENOMEM;
++
++	handle->dev = dev;
++	handle->handler = handler;
++	handle->name = KEYCOMBO_NAME;
++	handle->private = state;
++
++	ret = input_register_handle(handle);
++	if (ret)
++		goto err_input_register_handle;
++
++	ret = input_open_device(handle);
++	if (ret)
++		goto err_input_open_device;
++
++	return 0;
++
++err_input_open_device:
++	input_unregister_handle(handle);
++err_input_register_handle:
++	kfree(handle);
++	return ret;
++}
++
++static void keycombo_disconnect(struct input_handle *handle)
++{
++	input_close_device(handle);
++	input_unregister_handle(handle);
++	kfree(handle);
++}
++
++static const struct input_device_id keycombo_ids[] = {
++		{
++				.flags = INPUT_DEVICE_ID_MATCH_EVBIT,
++				.evbit = { BIT_MASK(EV_KEY) },
++		},
++		{ },
++};
++MODULE_DEVICE_TABLE(input, keycombo_ids);
++
++static int keycombo_probe(struct platform_device *pdev)
++{
++	int ret;
++	int key, *keyp;
++	struct keycombo_state *state;
++	struct keycombo_platform_data *pdata = pdev->dev.platform_data;
++
++	if (!pdata)
++		return -EINVAL;
++
++	state = kzalloc(sizeof(*state), GFP_KERNEL);
++	if (!state)
++		return -ENOMEM;
++
++	spin_lock_init(&state->lock);
++	keyp = pdata->keys_down;
++	while ((key = *keyp++)) {
++		if (key >= KEY_MAX)
++			continue;
++		state->key_down_target++;
++		__set_bit(key, state->keybit);
++	}
++	if (pdata->keys_up) {
++		keyp = pdata->keys_up;
++		while ((key = *keyp++)) {
++			if (key >= KEY_MAX)
++				continue;
++			__set_bit(key, state->keybit);
++			__set_bit(key, state->upbit);
++		}
++	}
++
++	state->wq = alloc_ordered_workqueue("keycombo", 0);
++	if (!state->wq)
++		return -ENOMEM;
++
++	state->priv = pdata->priv;
++
++	if (pdata->key_down_fn)
++		state->key_down_fn = pdata->key_down_fn;
++	INIT_DELAYED_WORK(&state->key_down_work, do_key_down);
++
++	if (pdata->key_up_fn)
++		state->key_up_fn = pdata->key_up_fn;
++	INIT_WORK(&state->key_up_work, do_key_up);
++
++	wakeup_source_init(&state->combo_held_wake_source, "key combo");
++	wakeup_source_init(&state->combo_up_wake_source, "key combo up");
++	state->delay = msecs_to_jiffies(pdata->key_down_delay);
++
++	state->input_handler.event = keycombo_event;
++	state->input_handler.connect = keycombo_connect;
++	state->input_handler.disconnect = keycombo_disconnect;
++	state->input_handler.name = KEYCOMBO_NAME;
++	state->input_handler.id_table = keycombo_ids;
++	ret = input_register_handler(&state->input_handler);
++	if (ret) {
++		kfree(state);
++		return ret;
++	}
++	platform_set_drvdata(pdev, state);
++	return 0;
++}
++
++int keycombo_remove(struct platform_device *pdev)
++{
++	struct keycombo_state *state = platform_get_drvdata(pdev);
++	input_unregister_handler(&state->input_handler);
++	destroy_workqueue(state->wq);
++	kfree(state);
++	return 0;
++}
++
++
++struct platform_driver keycombo_driver = {
++		.driver.name = KEYCOMBO_NAME,
++		.probe = keycombo_probe,
++		.remove = keycombo_remove,
++};
++
++static int __init keycombo_init(void)
++{
++	return platform_driver_register(&keycombo_driver);
++}
++
++static void __exit keycombo_exit(void)
++{
++	return platform_driver_unregister(&keycombo_driver);
++}
++
++module_init(keycombo_init);
++module_exit(keycombo_exit);
+diff --git a/drivers/input/keyreset.c b/drivers/input/keyreset.c
+new file mode 100644
+index 0000000..7fbf724
+--- /dev/null
++++ b/drivers/input/keyreset.c
+@@ -0,0 +1,145 @@
++/* drivers/input/keyreset.c
++ *
++ * Copyright (C) 2014 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#include <linux/input.h>
++#include <linux/keyreset.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/reboot.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/syscalls.h>
++#include <linux/keycombo.h>
++
++struct keyreset_state {
++	int restart_requested;
++	int (*reset_fn)(void);
++	struct platform_device *pdev_child;
++	struct work_struct restart_work;
++};
++
++static void do_restart(struct work_struct *unused)
++{
++	sys_sync();
++	kernel_restart(NULL);
++}
++
++static void do_reset_fn(void *priv)
++{
++	struct keyreset_state *state = priv;
++	if (state->restart_requested)
++		panic("keyboard reset failed, %d", state->restart_requested);
++	if (state->reset_fn) {
++		state->restart_requested = state->reset_fn();
++	} else {
++		pr_info("keyboard reset\n");
++		schedule_work(&state->restart_work);
++		state->restart_requested = 1;
++	}
++}
++
++static int keyreset_probe(struct platform_device *pdev)
++{
++	int ret = -ENOMEM;
++	struct keycombo_platform_data *pdata_child;
++	struct keyreset_platform_data *pdata = pdev->dev.platform_data;
++	int up_size = 0, down_size = 0, size;
++	int key, *keyp;
++	struct keyreset_state *state;
++
++	if (!pdata)
++		return -EINVAL;
++	state = devm_kzalloc(&pdev->dev, sizeof(*state), GFP_KERNEL);
++	if (!state)
++		return -ENOMEM;
++
++	state->pdev_child = platform_device_alloc(KEYCOMBO_NAME,
++							PLATFORM_DEVID_AUTO);
++	if (!state->pdev_child)
++		return -ENOMEM;
++	state->pdev_child->dev.parent = &pdev->dev;
++	INIT_WORK(&state->restart_work, do_restart);
++
++	keyp = pdata->keys_down;
++	while ((key = *keyp++)) {
++		if (key >= KEY_MAX)
++			continue;
++		down_size++;
++	}
++	if (pdata->keys_up) {
++		keyp = pdata->keys_up;
++		while ((key = *keyp++)) {
++			if (key >= KEY_MAX)
++				continue;
++			up_size++;
++		}
++	}
++	size = sizeof(struct keycombo_platform_data)
++			+ sizeof(int) * (down_size + 1);
++	pdata_child = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
++	if (!pdata_child)
++		goto error;
++	memcpy(pdata_child->keys_down, pdata->keys_down,
++						sizeof(int) * down_size);
++	if (up_size > 0) {
++		pdata_child->keys_up = devm_kzalloc(&pdev->dev, up_size + 1,
++								GFP_KERNEL);
++		if (!pdata_child->keys_up)
++			goto error;
++		memcpy(pdata_child->keys_up, pdata->keys_up,
++							sizeof(int) * up_size);
++		if (!pdata_child->keys_up)
++			goto error;
++	}
++	state->reset_fn = pdata->reset_fn;
++	pdata_child->key_down_fn = do_reset_fn;
++	pdata_child->priv = state;
++	pdata_child->key_down_delay = pdata->key_down_delay;
++	ret = platform_device_add_data(state->pdev_child, pdata_child, size);
++	if (ret)
++		goto error;
++	platform_set_drvdata(pdev, state);
++	return platform_device_add(state->pdev_child);
++error:
++	platform_device_put(state->pdev_child);
++	return ret;
++}
++
++int keyreset_remove(struct platform_device *pdev)
++{
++	struct keyreset_state *state = platform_get_drvdata(pdev);
++	platform_device_put(state->pdev_child);
++	return 0;
++}
++
++
++struct platform_driver keyreset_driver = {
++	.driver.name = KEYRESET_NAME,
++	.probe = keyreset_probe,
++	.remove = keyreset_remove,
++};
++
++static int __init keyreset_init(void)
++{
++	return platform_driver_register(&keyreset_driver);
++}
++
++static void __exit keyreset_exit(void)
++{
++	return platform_driver_unregister(&keyreset_driver);
++}
++
++module_init(keyreset_init);
++module_exit(keyreset_exit);
+diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
+index 23297ab..838824b 100644
+--- a/drivers/input/misc/Kconfig
++++ b/drivers/input/misc/Kconfig
+@@ -319,6 +319,17 @@ config INPUT_ATI_REMOTE2
+ 	  To compile this driver as a module, choose M here: the module will be
+ 	  called ati_remote2.
+ 
++config INPUT_KEYCHORD
++	tristate "Key chord input driver support"
++	help
++	  Say Y here if you want to enable the key chord driver
++	  accessible at /dev/keychord.  This driver can be used
++	  for receiving notifications when client specified key
++	  combinations are pressed.
++
++	  To compile this driver as a module, choose M here: the
++	  module will be called keychord.
++
+ config INPUT_KEYSPAN_REMOTE
+ 	tristate "Keyspan DMR USB remote control"
+ 	depends on USB_ARCH_HAS_HCD
+@@ -454,6 +465,11 @@ config INPUT_SGI_BTNS
+ 	  To compile this driver as a module, choose M here: the
+ 	  module will be called sgi_btns.
+ 
++config INPUT_GPIO
++	tristate "GPIO driver support"
++	help
++	  Say Y here if you want to support gpio based keys, wheels etc...
++
+ config HP_SDC_RTC
+ 	tristate "HP SDC Real Time Clock"
+ 	depends on (GSC || HP300) && SERIO
+diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
+index 19c7603..f77268e 100644
+--- a/drivers/input/misc/Makefile
++++ b/drivers/input/misc/Makefile
+@@ -31,9 +31,11 @@ obj-$(CONFIG_INPUT_DRV2667_HAPTICS)	+= drv2667.o
+ obj-$(CONFIG_INPUT_GP2A)		+= gp2ap002a00f.o
+ obj-$(CONFIG_INPUT_GPIO_BEEPER)		+= gpio-beeper.o
+ obj-$(CONFIG_INPUT_GPIO_TILT_POLLED)	+= gpio_tilt_polled.o
++obj-$(CONFIG_INPUT_GPIO)		+= gpio_event.o gpio_matrix.o gpio_input.o gpio_output.o gpio_axis.o
+ obj-$(CONFIG_HP_SDC_RTC)		+= hp_sdc_rtc.o
+ obj-$(CONFIG_INPUT_IMS_PCU)		+= ims-pcu.o
+ obj-$(CONFIG_INPUT_IXP4XX_BEEPER)	+= ixp4xx-beeper.o
++obj-$(CONFIG_INPUT_KEYCHORD)		+= keychord.o
+ obj-$(CONFIG_INPUT_KEYSPAN_REMOTE)	+= keyspan_remote.o
+ obj-$(CONFIG_INPUT_KXTJ9)		+= kxtj9.o
+ obj-$(CONFIG_INPUT_M68K_BEEP)		+= m68kspkr.o
+diff --git a/drivers/input/misc/gpio_axis.c b/drivers/input/misc/gpio_axis.c
+new file mode 100644
+index 0000000..0acf4a5
+--- /dev/null
++++ b/drivers/input/misc/gpio_axis.c
+@@ -0,0 +1,192 @@
++/* drivers/input/misc/gpio_axis.c
++ *
++ * Copyright (C) 2007 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/gpio.h>
++#include <linux/gpio_event.h>
++#include <linux/interrupt.h>
++#include <linux/slab.h>
++
++struct gpio_axis_state {
++	struct gpio_event_input_devs *input_devs;
++	struct gpio_event_axis_info *info;
++	uint32_t pos;
++};
++
++uint16_t gpio_axis_4bit_gray_map_table[] = {
++	[0x0] = 0x0, [0x1] = 0x1, /* 0000 0001 */
++	[0x3] = 0x2, [0x2] = 0x3, /* 0011 0010 */
++	[0x6] = 0x4, [0x7] = 0x5, /* 0110 0111 */
++	[0x5] = 0x6, [0x4] = 0x7, /* 0101 0100 */
++	[0xc] = 0x8, [0xd] = 0x9, /* 1100 1101 */
++	[0xf] = 0xa, [0xe] = 0xb, /* 1111 1110 */
++	[0xa] = 0xc, [0xb] = 0xd, /* 1010 1011 */
++	[0x9] = 0xe, [0x8] = 0xf, /* 1001 1000 */
++};
++uint16_t gpio_axis_4bit_gray_map(struct gpio_event_axis_info *info, uint16_t in)
++{
++	return gpio_axis_4bit_gray_map_table[in];
++}
++
++uint16_t gpio_axis_5bit_singletrack_map_table[] = {
++	[0x10] = 0x00, [0x14] = 0x01, [0x1c] = 0x02, /*     10000 10100 11100 */
++	[0x1e] = 0x03, [0x1a] = 0x04, [0x18] = 0x05, /*     11110 11010 11000 */
++	[0x08] = 0x06, [0x0a] = 0x07, [0x0e] = 0x08, /*    01000 01010 01110  */
++	[0x0f] = 0x09, [0x0d] = 0x0a, [0x0c] = 0x0b, /*    01111 01101 01100  */
++	[0x04] = 0x0c, [0x05] = 0x0d, [0x07] = 0x0e, /*   00100 00101 00111   */
++	[0x17] = 0x0f, [0x16] = 0x10, [0x06] = 0x11, /*   10111 10110 00110   */
++	[0x02] = 0x12, [0x12] = 0x13, [0x13] = 0x14, /*  00010 10010 10011    */
++	[0x1b] = 0x15, [0x0b] = 0x16, [0x03] = 0x17, /*  11011 01011 00011    */
++	[0x01] = 0x18, [0x09] = 0x19, [0x19] = 0x1a, /* 00001 01001 11001     */
++	[0x1d] = 0x1b, [0x15] = 0x1c, [0x11] = 0x1d, /* 11101 10101 10001     */
++};
++uint16_t gpio_axis_5bit_singletrack_map(
++	struct gpio_event_axis_info *info, uint16_t in)
++{
++	return gpio_axis_5bit_singletrack_map_table[in];
++}
++
++static void gpio_event_update_axis(struct gpio_axis_state *as, int report)
++{
++	struct gpio_event_axis_info *ai = as->info;
++	int i;
++	int change;
++	uint16_t state = 0;
++	uint16_t pos;
++	uint16_t old_pos = as->pos;
++	for (i = ai->count - 1; i >= 0; i--)
++		state = (state << 1) | gpio_get_value(ai->gpio[i]);
++	pos = ai->map(ai, state);
++	if (ai->flags & GPIOEAF_PRINT_RAW)
++		pr_info("axis %d-%d raw %x, pos %d -> %d\n",
++			ai->type, ai->code, state, old_pos, pos);
++	if (report && pos != old_pos) {
++		if (ai->type == EV_REL) {
++			change = (ai->decoded_size + pos - old_pos) %
++				  ai->decoded_size;
++			if (change > ai->decoded_size / 2)
++				change -= ai->decoded_size;
++			if (change == ai->decoded_size / 2) {
++				if (ai->flags & GPIOEAF_PRINT_EVENT)
++					pr_info("axis %d-%d unknown direction, "
++						"pos %d -> %d\n", ai->type,
++						ai->code, old_pos, pos);
++				change = 0; /* no closest direction */
++			}
++			if (ai->flags & GPIOEAF_PRINT_EVENT)
++				pr_info("axis %d-%d change %d\n",
++					ai->type, ai->code, change);
++			input_report_rel(as->input_devs->dev[ai->dev],
++						ai->code, change);
++		} else {
++			if (ai->flags & GPIOEAF_PRINT_EVENT)
++				pr_info("axis %d-%d now %d\n",
++					ai->type, ai->code, pos);
++			input_event(as->input_devs->dev[ai->dev],
++					ai->type, ai->code, pos);
++		}
++		input_sync(as->input_devs->dev[ai->dev]);
++	}
++	as->pos = pos;
++}
++
++static irqreturn_t gpio_axis_irq_handler(int irq, void *dev_id)
++{
++	struct gpio_axis_state *as = dev_id;
++	gpio_event_update_axis(as, 1);
++	return IRQ_HANDLED;
++}
++
++int gpio_event_axis_func(struct gpio_event_input_devs *input_devs,
++			 struct gpio_event_info *info, void **data, int func)
++{
++	int ret;
++	int i;
++	int irq;
++	struct gpio_event_axis_info *ai;
++	struct gpio_axis_state *as;
++
++	ai = container_of(info, struct gpio_event_axis_info, info);
++	if (func == GPIO_EVENT_FUNC_SUSPEND) {
++		for (i = 0; i < ai->count; i++)
++			disable_irq(gpio_to_irq(ai->gpio[i]));
++		return 0;
++	}
++	if (func == GPIO_EVENT_FUNC_RESUME) {
++		for (i = 0; i < ai->count; i++)
++			enable_irq(gpio_to_irq(ai->gpio[i]));
++		return 0;
++	}
++
++	if (func == GPIO_EVENT_FUNC_INIT) {
++		*data = as = kmalloc(sizeof(*as), GFP_KERNEL);
++		if (as == NULL) {
++			ret = -ENOMEM;
++			goto err_alloc_axis_state_failed;
++		}
++		as->input_devs = input_devs;
++		as->info = ai;
++		if (ai->dev >= input_devs->count) {
++			pr_err("gpio_event_axis: bad device index %d >= %d "
++				"for %d:%d\n", ai->dev, input_devs->count,
++				ai->type, ai->code);
++			ret = -EINVAL;
++			goto err_bad_device_index;
++		}
++
++		input_set_capability(input_devs->dev[ai->dev],
++				     ai->type, ai->code);
++		if (ai->type == EV_ABS) {
++			input_set_abs_params(input_devs->dev[ai->dev], ai->code,
++					     0, ai->decoded_size - 1, 0, 0);
++		}
++		for (i = 0; i < ai->count; i++) {
++			ret = gpio_request(ai->gpio[i], "gpio_event_axis");
++			if (ret < 0)
++				goto err_request_gpio_failed;
++			ret = gpio_direction_input(ai->gpio[i]);
++			if (ret < 0)
++				goto err_gpio_direction_input_failed;
++			ret = irq = gpio_to_irq(ai->gpio[i]);
++			if (ret < 0)
++				goto err_get_irq_num_failed;
++			ret = request_irq(irq, gpio_axis_irq_handler,
++					  IRQF_TRIGGER_RISING |
++					  IRQF_TRIGGER_FALLING,
++					  "gpio_event_axis", as);
++			if (ret < 0)
++				goto err_request_irq_failed;
++		}
++		gpio_event_update_axis(as, 0);
++		return 0;
++	}
++
++	ret = 0;
++	as = *data;
++	for (i = ai->count - 1; i >= 0; i--) {
++		free_irq(gpio_to_irq(ai->gpio[i]), as);
++err_request_irq_failed:
++err_get_irq_num_failed:
++err_gpio_direction_input_failed:
++		gpio_free(ai->gpio[i]);
++err_request_gpio_failed:
++		;
++	}
++err_bad_device_index:
++	kfree(as);
++	*data = NULL;
++err_alloc_axis_state_failed:
++	return ret;
++}
+diff --git a/drivers/input/misc/gpio_event.c b/drivers/input/misc/gpio_event.c
+new file mode 100644
+index 0000000..90f07eb
+--- /dev/null
++++ b/drivers/input/misc/gpio_event.c
+@@ -0,0 +1,228 @@
++/* drivers/input/misc/gpio_event.c
++ *
++ * Copyright (C) 2007 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/input.h>
++#include <linux/gpio_event.h>
++#include <linux/hrtimer.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++
++struct gpio_event {
++	struct gpio_event_input_devs *input_devs;
++	const struct gpio_event_platform_data *info;
++	void *state[0];
++};
++
++static int gpio_input_event(
++	struct input_dev *dev, unsigned int type, unsigned int code, int value)
++{
++	int i;
++	int devnr;
++	int ret = 0;
++	int tmp_ret;
++	struct gpio_event_info **ii;
++	struct gpio_event *ip = input_get_drvdata(dev);
++
++	for (devnr = 0; devnr < ip->input_devs->count; devnr++)
++		if (ip->input_devs->dev[devnr] == dev)
++			break;
++	if (devnr == ip->input_devs->count) {
++		pr_err("gpio_input_event: unknown device %p\n", dev);
++		return -EIO;
++	}
++
++	for (i = 0, ii = ip->info->info; i < ip->info->info_count; i++, ii++) {
++		if ((*ii)->event) {
++			tmp_ret = (*ii)->event(ip->input_devs, *ii,
++						&ip->state[i],
++						devnr, type, code, value);
++			if (tmp_ret)
++				ret = tmp_ret;
++		}
++	}
++	return ret;
++}
++
++static int gpio_event_call_all_func(struct gpio_event *ip, int func)
++{
++	int i;
++	int ret;
++	struct gpio_event_info **ii;
++
++	if (func == GPIO_EVENT_FUNC_INIT || func == GPIO_EVENT_FUNC_RESUME) {
++		ii = ip->info->info;
++		for (i = 0; i < ip->info->info_count; i++, ii++) {
++			if ((*ii)->func == NULL) {
++				ret = -ENODEV;
++				pr_err("gpio_event_probe: Incomplete pdata, "
++					"no function\n");
++				goto err_no_func;
++			}
++			if (func == GPIO_EVENT_FUNC_RESUME && (*ii)->no_suspend)
++				continue;
++			ret = (*ii)->func(ip->input_devs, *ii, &ip->state[i],
++					  func);
++			if (ret) {
++				pr_err("gpio_event_probe: function failed\n");
++				goto err_func_failed;
++			}
++		}
++		return 0;
++	}
++
++	ret = 0;
++	i = ip->info->info_count;
++	ii = ip->info->info + i;
++	while (i > 0) {
++		i--;
++		ii--;
++		if ((func & ~1) == GPIO_EVENT_FUNC_SUSPEND && (*ii)->no_suspend)
++			continue;
++		(*ii)->func(ip->input_devs, *ii, &ip->state[i], func & ~1);
++err_func_failed:
++err_no_func:
++		;
++	}
++	return ret;
++}
++
++static void __maybe_unused gpio_event_suspend(struct gpio_event *ip)
++{
++	gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_SUSPEND);
++	if (ip->info->power)
++		ip->info->power(ip->info, 0);
++}
++
++static void __maybe_unused gpio_event_resume(struct gpio_event *ip)
++{
++	if (ip->info->power)
++		ip->info->power(ip->info, 1);
++	gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_RESUME);
++}
++
++static int gpio_event_probe(struct platform_device *pdev)
++{
++	int err;
++	struct gpio_event *ip;
++	struct gpio_event_platform_data *event_info;
++	int dev_count = 1;
++	int i;
++	int registered = 0;
++
++	event_info = pdev->dev.platform_data;
++	if (event_info == NULL) {
++		pr_err("gpio_event_probe: No pdata\n");
++		return -ENODEV;
++	}
++	if ((!event_info->name && !event_info->names[0]) ||
++	    !event_info->info || !event_info->info_count) {
++		pr_err("gpio_event_probe: Incomplete pdata\n");
++		return -ENODEV;
++	}
++	if (!event_info->name)
++		while (event_info->names[dev_count])
++			dev_count++;
++	ip = kzalloc(sizeof(*ip) +
++		     sizeof(ip->state[0]) * event_info->info_count +
++		     sizeof(*ip->input_devs) +
++		     sizeof(ip->input_devs->dev[0]) * dev_count, GFP_KERNEL);
++	if (ip == NULL) {
++		err = -ENOMEM;
++		pr_err("gpio_event_probe: Failed to allocate private data\n");
++		goto err_kp_alloc_failed;
++	}
++	ip->input_devs = (void*)&ip->state[event_info->info_count];
++	platform_set_drvdata(pdev, ip);
++
++	for (i = 0; i < dev_count; i++) {
++		struct input_dev *input_dev = input_allocate_device();
++		if (input_dev == NULL) {
++			err = -ENOMEM;
++			pr_err("gpio_event_probe: "
++				"Failed to allocate input device\n");
++			goto err_input_dev_alloc_failed;
++		}
++		input_set_drvdata(input_dev, ip);
++		input_dev->name = event_info->name ?
++					event_info->name : event_info->names[i];
++		input_dev->event = gpio_input_event;
++		ip->input_devs->dev[i] = input_dev;
++	}
++	ip->input_devs->count = dev_count;
++	ip->info = event_info;
++	if (event_info->power)
++		ip->info->power(ip->info, 1);
++
++	err = gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_INIT);
++	if (err)
++		goto err_call_all_func_failed;
++
++	for (i = 0; i < dev_count; i++) {
++		err = input_register_device(ip->input_devs->dev[i]);
++		if (err) {
++			pr_err("gpio_event_probe: Unable to register %s "
++				"input device\n", ip->input_devs->dev[i]->name);
++			goto err_input_register_device_failed;
++		}
++		registered++;
++	}
++
++	return 0;
++
++err_input_register_device_failed:
++	gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_UNINIT);
++err_call_all_func_failed:
++	if (event_info->power)
++		ip->info->power(ip->info, 0);
++	for (i = 0; i < registered; i++)
++		input_unregister_device(ip->input_devs->dev[i]);
++	for (i = dev_count - 1; i >= registered; i--) {
++		input_free_device(ip->input_devs->dev[i]);
++err_input_dev_alloc_failed:
++		;
++	}
++	kfree(ip);
++err_kp_alloc_failed:
++	return err;
++}
++
++static int gpio_event_remove(struct platform_device *pdev)
++{
++	struct gpio_event *ip = platform_get_drvdata(pdev);
++	int i;
++
++	gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_UNINIT);
++	if (ip->info->power)
++		ip->info->power(ip->info, 0);
++	for (i = 0; i < ip->input_devs->count; i++)
++		input_unregister_device(ip->input_devs->dev[i]);
++	kfree(ip);
++	return 0;
++}
++
++static struct platform_driver gpio_event_driver = {
++	.probe		= gpio_event_probe,
++	.remove		= gpio_event_remove,
++	.driver		= {
++		.name	= GPIO_EVENT_DEV_NAME,
++	},
++};
++
++module_platform_driver(gpio_event_driver);
++
++MODULE_DESCRIPTION("GPIO Event Driver");
++MODULE_LICENSE("GPL");
++
+diff --git a/drivers/input/misc/gpio_input.c b/drivers/input/misc/gpio_input.c
+new file mode 100644
+index 0000000..eefd027
+--- /dev/null
++++ b/drivers/input/misc/gpio_input.c
+@@ -0,0 +1,390 @@
++/* drivers/input/misc/gpio_input.c
++ *
++ * Copyright (C) 2007 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/gpio.h>
++#include <linux/gpio_event.h>
++#include <linux/hrtimer.h>
++#include <linux/input.h>
++#include <linux/interrupt.h>
++#include <linux/slab.h>
++#include <linux/pm_wakeup.h>
++
++enum {
++	DEBOUNCE_UNSTABLE     = BIT(0),	/* Got irq, while debouncing */
++	DEBOUNCE_PRESSED      = BIT(1),
++	DEBOUNCE_NOTPRESSED   = BIT(2),
++	DEBOUNCE_WAIT_IRQ     = BIT(3),	/* Stable irq state */
++	DEBOUNCE_POLL         = BIT(4),	/* Stable polling state */
++
++	DEBOUNCE_UNKNOWN =
++		DEBOUNCE_PRESSED | DEBOUNCE_NOTPRESSED,
++};
++
++struct gpio_key_state {
++	struct gpio_input_state *ds;
++	uint8_t debounce;
++};
++
++struct gpio_input_state {
++	struct gpio_event_input_devs *input_devs;
++	const struct gpio_event_input_info *info;
++	struct hrtimer timer;
++	int use_irq;
++	int debounce_count;
++	spinlock_t irq_lock;
++	struct wakeup_source *ws;
++	struct gpio_key_state key_state[0];
++};
++
++static enum hrtimer_restart gpio_event_input_timer_func(struct hrtimer *timer)
++{
++	int i;
++	int pressed;
++	struct gpio_input_state *ds =
++		container_of(timer, struct gpio_input_state, timer);
++	unsigned gpio_flags = ds->info->flags;
++	unsigned npolarity;
++	int nkeys = ds->info->keymap_size;
++	const struct gpio_event_direct_entry *key_entry;
++	struct gpio_key_state *key_state;
++	unsigned long irqflags;
++	uint8_t debounce;
++	bool sync_needed;
++
++#if 0
++	key_entry = kp->keys_info->keymap;
++	key_state = kp->key_state;
++	for (i = 0; i < nkeys; i++, key_entry++, key_state++)
++		pr_info("gpio_read_detect_status %d %d\n", key_entry->gpio,
++			gpio_read_detect_status(key_entry->gpio));
++#endif
++	key_entry = ds->info->keymap;
++	key_state = ds->key_state;
++	sync_needed = false;
++	spin_lock_irqsave(&ds->irq_lock, irqflags);
++	for (i = 0; i < nkeys; i++, key_entry++, key_state++) {
++		debounce = key_state->debounce;
++		if (debounce & DEBOUNCE_WAIT_IRQ)
++			continue;
++		if (key_state->debounce & DEBOUNCE_UNSTABLE) {
++			debounce = key_state->debounce = DEBOUNCE_UNKNOWN;
++			enable_irq(gpio_to_irq(key_entry->gpio));
++			if (gpio_flags & GPIOEDF_PRINT_KEY_UNSTABLE)
++				pr_info("gpio_keys_scan_keys: key %x-%x, %d "
++					"(%d) continue debounce\n",
++					ds->info->type, key_entry->code,
++					i, key_entry->gpio);
++		}
++		npolarity = !(gpio_flags & GPIOEDF_ACTIVE_HIGH);
++		pressed = gpio_get_value(key_entry->gpio) ^ npolarity;
++		if (debounce & DEBOUNCE_POLL) {
++			if (pressed == !(debounce & DEBOUNCE_PRESSED)) {
++				ds->debounce_count++;
++				key_state->debounce = DEBOUNCE_UNKNOWN;
++				if (gpio_flags & GPIOEDF_PRINT_KEY_DEBOUNCE)
++					pr_info("gpio_keys_scan_keys: key %x-"
++						"%x, %d (%d) start debounce\n",
++						ds->info->type, key_entry->code,
++						i, key_entry->gpio);
++			}
++			continue;
++		}
++		if (pressed && (debounce & DEBOUNCE_NOTPRESSED)) {
++			if (gpio_flags & GPIOEDF_PRINT_KEY_DEBOUNCE)
++				pr_info("gpio_keys_scan_keys: key %x-%x, %d "
++					"(%d) debounce pressed 1\n",
++					ds->info->type, key_entry->code,
++					i, key_entry->gpio);
++			key_state->debounce = DEBOUNCE_PRESSED;
++			continue;
++		}
++		if (!pressed && (debounce & DEBOUNCE_PRESSED)) {
++			if (gpio_flags & GPIOEDF_PRINT_KEY_DEBOUNCE)
++				pr_info("gpio_keys_scan_keys: key %x-%x, %d "
++					"(%d) debounce pressed 0\n",
++					ds->info->type, key_entry->code,
++					i, key_entry->gpio);
++			key_state->debounce = DEBOUNCE_NOTPRESSED;
++			continue;
++		}
++		/* key is stable */
++		ds->debounce_count--;
++		if (ds->use_irq)
++			key_state->debounce |= DEBOUNCE_WAIT_IRQ;
++		else
++			key_state->debounce |= DEBOUNCE_POLL;
++		if (gpio_flags & GPIOEDF_PRINT_KEYS)
++			pr_info("gpio_keys_scan_keys: key %x-%x, %d (%d) "
++				"changed to %d\n", ds->info->type,
++				key_entry->code, i, key_entry->gpio, pressed);
++		input_event(ds->input_devs->dev[key_entry->dev], ds->info->type,
++			    key_entry->code, pressed);
++		sync_needed = true;
++	}
++	if (sync_needed) {
++		for (i = 0; i < ds->input_devs->count; i++)
++			input_sync(ds->input_devs->dev[i]);
++	}
++
++#if 0
++	key_entry = kp->keys_info->keymap;
++	key_state = kp->key_state;
++	for (i = 0; i < nkeys; i++, key_entry++, key_state++) {
++		pr_info("gpio_read_detect_status %d %d\n", key_entry->gpio,
++			gpio_read_detect_status(key_entry->gpio));
++	}
++#endif
++
++	if (ds->debounce_count)
++		hrtimer_start(timer, ds->info->debounce_time, HRTIMER_MODE_REL);
++	else if (!ds->use_irq)
++		hrtimer_start(timer, ds->info->poll_time, HRTIMER_MODE_REL);
++	else
++		__pm_relax(ds->ws);
++
++	spin_unlock_irqrestore(&ds->irq_lock, irqflags);
++
++	return HRTIMER_NORESTART;
++}
++
++static irqreturn_t gpio_event_input_irq_handler(int irq, void *dev_id)
++{
++	struct gpio_key_state *ks = dev_id;
++	struct gpio_input_state *ds = ks->ds;
++	int keymap_index = ks - ds->key_state;
++	const struct gpio_event_direct_entry *key_entry;
++	unsigned long irqflags;
++	int pressed;
++
++	if (!ds->use_irq)
++		return IRQ_HANDLED;
++
++	key_entry = &ds->info->keymap[keymap_index];
++
++	if (ds->info->debounce_time.tv64) {
++		spin_lock_irqsave(&ds->irq_lock, irqflags);
++		if (ks->debounce & DEBOUNCE_WAIT_IRQ) {
++			ks->debounce = DEBOUNCE_UNKNOWN;
++			if (ds->debounce_count++ == 0) {
++				__pm_stay_awake(ds->ws);
++				hrtimer_start(
++					&ds->timer, ds->info->debounce_time,
++					HRTIMER_MODE_REL);
++			}
++			if (ds->info->flags & GPIOEDF_PRINT_KEY_DEBOUNCE)
++				pr_info("gpio_event_input_irq_handler: "
++					"key %x-%x, %d (%d) start debounce\n",
++					ds->info->type, key_entry->code,
++					keymap_index, key_entry->gpio);
++		} else {
++			disable_irq_nosync(irq);
++			ks->debounce = DEBOUNCE_UNSTABLE;
++		}
++		spin_unlock_irqrestore(&ds->irq_lock, irqflags);
++	} else {
++		pressed = gpio_get_value(key_entry->gpio) ^
++			!(ds->info->flags & GPIOEDF_ACTIVE_HIGH);
++		if (ds->info->flags & GPIOEDF_PRINT_KEYS)
++			pr_info("gpio_event_input_irq_handler: key %x-%x, %d "
++				"(%d) changed to %d\n",
++				ds->info->type, key_entry->code, keymap_index,
++				key_entry->gpio, pressed);
++		input_event(ds->input_devs->dev[key_entry->dev], ds->info->type,
++			    key_entry->code, pressed);
++		input_sync(ds->input_devs->dev[key_entry->dev]);
++	}
++	return IRQ_HANDLED;
++}
++
++static int gpio_event_input_request_irqs(struct gpio_input_state *ds)
++{
++	int i;
++	int err;
++	unsigned int irq;
++	unsigned long req_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
++
++	for (i = 0; i < ds->info->keymap_size; i++) {
++		err = irq = gpio_to_irq(ds->info->keymap[i].gpio);
++		if (err < 0)
++			goto err_gpio_get_irq_num_failed;
++		err = request_irq(irq, gpio_event_input_irq_handler,
++				  req_flags, "gpio_keys", &ds->key_state[i]);
++		if (err) {
++			pr_err("gpio_event_input_request_irqs: request_irq "
++				"failed for input %d, irq %d\n",
++				ds->info->keymap[i].gpio, irq);
++			goto err_request_irq_failed;
++		}
++		if (ds->info->info.no_suspend) {
++			err = enable_irq_wake(irq);
++			if (err) {
++				pr_err("gpio_event_input_request_irqs: "
++					"enable_irq_wake failed for input %d, "
++					"irq %d\n",
++					ds->info->keymap[i].gpio, irq);
++				goto err_enable_irq_wake_failed;
++			}
++		}
++	}
++	return 0;
++
++	for (i = ds->info->keymap_size - 1; i >= 0; i--) {
++		irq = gpio_to_irq(ds->info->keymap[i].gpio);
++		if (ds->info->info.no_suspend)
++			disable_irq_wake(irq);
++err_enable_irq_wake_failed:
++		free_irq(irq, &ds->key_state[i]);
++err_request_irq_failed:
++err_gpio_get_irq_num_failed:
++		;
++	}
++	return err;
++}
++
++int gpio_event_input_func(struct gpio_event_input_devs *input_devs,
++			struct gpio_event_info *info, void **data, int func)
++{
++	int ret;
++	int i;
++	unsigned long irqflags;
++	struct gpio_event_input_info *di;
++	struct gpio_input_state *ds = *data;
++	char *wlname;
++
++	di = container_of(info, struct gpio_event_input_info, info);
++
++	if (func == GPIO_EVENT_FUNC_SUSPEND) {
++		if (ds->use_irq)
++			for (i = 0; i < di->keymap_size; i++)
++				disable_irq(gpio_to_irq(di->keymap[i].gpio));
++		hrtimer_cancel(&ds->timer);
++		return 0;
++	}
++	if (func == GPIO_EVENT_FUNC_RESUME) {
++		spin_lock_irqsave(&ds->irq_lock, irqflags);
++		if (ds->use_irq)
++			for (i = 0; i < di->keymap_size; i++)
++				enable_irq(gpio_to_irq(di->keymap[i].gpio));
++		hrtimer_start(&ds->timer, ktime_set(0, 0), HRTIMER_MODE_REL);
++		spin_unlock_irqrestore(&ds->irq_lock, irqflags);
++		return 0;
++	}
++
++	if (func == GPIO_EVENT_FUNC_INIT) {
++		if (ktime_to_ns(di->poll_time) <= 0)
++			di->poll_time = ktime_set(0, 20 * NSEC_PER_MSEC);
++
++		*data = ds = kzalloc(sizeof(*ds) + sizeof(ds->key_state[0]) *
++					di->keymap_size, GFP_KERNEL);
++		if (ds == NULL) {
++			ret = -ENOMEM;
++			pr_err("gpio_event_input_func: "
++				"Failed to allocate private data\n");
++			goto err_ds_alloc_failed;
++		}
++		ds->debounce_count = di->keymap_size;
++		ds->input_devs = input_devs;
++		ds->info = di;
++		wlname = kasprintf(GFP_KERNEL, "gpio_input:%s%s",
++				   input_devs->dev[0]->name,
++				   (input_devs->count > 1) ? "..." : "");
++
++		ds->ws = wakeup_source_register(wlname);
++		kfree(wlname);
++		if (!ds->ws) {
++			ret = -ENOMEM;
++			pr_err("gpio_event_input_func: "
++				"Failed to allocate wakeup source\n");
++			goto err_ws_failed;
++		}
++
++		spin_lock_init(&ds->irq_lock);
++
++		for (i = 0; i < di->keymap_size; i++) {
++			int dev = di->keymap[i].dev;
++			if (dev >= input_devs->count) {
++				pr_err("gpio_event_input_func: bad device "
++					"index %d >= %d for key code %d\n",
++					dev, input_devs->count,
++					di->keymap[i].code);
++				ret = -EINVAL;
++				goto err_bad_keymap;
++			}
++			input_set_capability(input_devs->dev[dev], di->type,
++					     di->keymap[i].code);
++			ds->key_state[i].ds = ds;
++			ds->key_state[i].debounce = DEBOUNCE_UNKNOWN;
++		}
++
++		for (i = 0; i < di->keymap_size; i++) {
++			ret = gpio_request(di->keymap[i].gpio, "gpio_kp_in");
++			if (ret) {
++				pr_err("gpio_event_input_func: gpio_request "
++					"failed for %d\n", di->keymap[i].gpio);
++				goto err_gpio_request_failed;
++			}
++			ret = gpio_direction_input(di->keymap[i].gpio);
++			if (ret) {
++				pr_err("gpio_event_input_func: "
++					"gpio_direction_input failed for %d\n",
++					di->keymap[i].gpio);
++				goto err_gpio_configure_failed;
++			}
++		}
++
++		ret = gpio_event_input_request_irqs(ds);
++
++		spin_lock_irqsave(&ds->irq_lock, irqflags);
++		ds->use_irq = ret == 0;
++
++		pr_info("GPIO Input Driver: Start gpio inputs for %s%s in %s "
++			"mode\n", input_devs->dev[0]->name,
++			(input_devs->count > 1) ? "..." : "",
++			ret == 0 ? "interrupt" : "polling");
++
++		hrtimer_init(&ds->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
++		ds->timer.function = gpio_event_input_timer_func;
++		hrtimer_start(&ds->timer, ktime_set(0, 0), HRTIMER_MODE_REL);
++		spin_unlock_irqrestore(&ds->irq_lock, irqflags);
++		return 0;
++	}
++
++	ret = 0;
++	spin_lock_irqsave(&ds->irq_lock, irqflags);
++	hrtimer_cancel(&ds->timer);
++	if (ds->use_irq) {
++		for (i = di->keymap_size - 1; i >= 0; i--) {
++			int irq = gpio_to_irq(di->keymap[i].gpio);
++			if (ds->info->info.no_suspend)
++				disable_irq_wake(irq);
++			free_irq(irq, &ds->key_state[i]);
++		}
++	}
++	spin_unlock_irqrestore(&ds->irq_lock, irqflags);
++
++	for (i = di->keymap_size - 1; i >= 0; i--) {
++err_gpio_configure_failed:
++		gpio_free(di->keymap[i].gpio);
++err_gpio_request_failed:
++		;
++	}
++err_bad_keymap:
++	wakeup_source_unregister(ds->ws);
++err_ws_failed:
++	kfree(ds);
++err_ds_alloc_failed:
++	return ret;
++}
+diff --git a/drivers/input/misc/gpio_matrix.c b/drivers/input/misc/gpio_matrix.c
+new file mode 100644
+index 0000000..eaa9e89
+--- /dev/null
++++ b/drivers/input/misc/gpio_matrix.c
+@@ -0,0 +1,441 @@
++/* drivers/input/misc/gpio_matrix.c
++ *
++ * Copyright (C) 2007 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/gpio.h>
++#include <linux/gpio_event.h>
++#include <linux/hrtimer.h>
++#include <linux/interrupt.h>
++#include <linux/slab.h>
++#include <linux/wakelock.h>
++
++struct gpio_kp {
++	struct gpio_event_input_devs *input_devs;
++	struct gpio_event_matrix_info *keypad_info;
++	struct hrtimer timer;
++	struct wake_lock wake_lock;
++	int current_output;
++	unsigned int use_irq:1;
++	unsigned int key_state_changed:1;
++	unsigned int last_key_state_changed:1;
++	unsigned int some_keys_pressed:2;
++	unsigned int disabled_irq:1;
++	unsigned long keys_pressed[0];
++};
++
++static void clear_phantom_key(struct gpio_kp *kp, int out, int in)
++{
++	struct gpio_event_matrix_info *mi = kp->keypad_info;
++	int key_index = out * mi->ninputs + in;
++	unsigned short keyentry = mi->keymap[key_index];
++	unsigned short keycode = keyentry & MATRIX_KEY_MASK;
++	unsigned short dev = keyentry >> MATRIX_CODE_BITS;
++
++	if (!test_bit(keycode, kp->input_devs->dev[dev]->key)) {
++		if (mi->flags & GPIOKPF_PRINT_PHANTOM_KEYS)
++			pr_info("gpiomatrix: phantom key %x, %d-%d (%d-%d) "
++				"cleared\n", keycode, out, in,
++				mi->output_gpios[out], mi->input_gpios[in]);
++		__clear_bit(key_index, kp->keys_pressed);
++	} else {
++		if (mi->flags & GPIOKPF_PRINT_PHANTOM_KEYS)
++			pr_info("gpiomatrix: phantom key %x, %d-%d (%d-%d) "
++				"not cleared\n", keycode, out, in,
++				mi->output_gpios[out], mi->input_gpios[in]);
++	}
++}
++
++static int restore_keys_for_input(struct gpio_kp *kp, int out, int in)
++{
++	int rv = 0;
++	int key_index;
++
++	key_index = out * kp->keypad_info->ninputs + in;
++	while (out < kp->keypad_info->noutputs) {
++		if (test_bit(key_index, kp->keys_pressed)) {
++			rv = 1;
++			clear_phantom_key(kp, out, in);
++		}
++		key_index += kp->keypad_info->ninputs;
++		out++;
++	}
++	return rv;
++}
++
++static void remove_phantom_keys(struct gpio_kp *kp)
++{
++	int out, in, inp;
++	int key_index;
++
++	if (kp->some_keys_pressed < 3)
++		return;
++
++	for (out = 0; out < kp->keypad_info->noutputs; out++) {
++		inp = -1;
++		key_index = out * kp->keypad_info->ninputs;
++		for (in = 0; in < kp->keypad_info->ninputs; in++, key_index++) {
++			if (test_bit(key_index, kp->keys_pressed)) {
++				if (inp == -1) {
++					inp = in;
++					continue;
++				}
++				if (inp >= 0) {
++					if (!restore_keys_for_input(kp, out + 1,
++									inp))
++						break;
++					clear_phantom_key(kp, out, inp);
++					inp = -2;
++				}
++				restore_keys_for_input(kp, out, in);
++			}
++		}
++	}
++}
++
++static void report_key(struct gpio_kp *kp, int key_index, int out, int in)
++{
++	struct gpio_event_matrix_info *mi = kp->keypad_info;
++	int pressed = test_bit(key_index, kp->keys_pressed);
++	unsigned short keyentry = mi->keymap[key_index];
++	unsigned short keycode = keyentry & MATRIX_KEY_MASK;
++	unsigned short dev = keyentry >> MATRIX_CODE_BITS;
++
++	if (pressed != test_bit(keycode, kp->input_devs->dev[dev]->key)) {
++		if (keycode == KEY_RESERVED) {
++			if (mi->flags & GPIOKPF_PRINT_UNMAPPED_KEYS)
++				pr_info("gpiomatrix: unmapped key, %d-%d "
++					"(%d-%d) changed to %d\n",
++					out, in, mi->output_gpios[out],
++					mi->input_gpios[in], pressed);
++		} else {
++			if (mi->flags & GPIOKPF_PRINT_MAPPED_KEYS)
++				pr_info("gpiomatrix: key %x, %d-%d (%d-%d) "
++					"changed to %d\n", keycode,
++					out, in, mi->output_gpios[out],
++					mi->input_gpios[in], pressed);
++			input_report_key(kp->input_devs->dev[dev], keycode, pressed);
++		}
++	}
++}
++
++static void report_sync(struct gpio_kp *kp)
++{
++	int i;
++
++	for (i = 0; i < kp->input_devs->count; i++)
++		input_sync(kp->input_devs->dev[i]);
++}
++
++static enum hrtimer_restart gpio_keypad_timer_func(struct hrtimer *timer)
++{
++	int out, in;
++	int key_index;
++	int gpio;
++	struct gpio_kp *kp = container_of(timer, struct gpio_kp, timer);
++	struct gpio_event_matrix_info *mi = kp->keypad_info;
++	unsigned gpio_keypad_flags = mi->flags;
++	unsigned polarity = !!(gpio_keypad_flags & GPIOKPF_ACTIVE_HIGH);
++
++	out = kp->current_output;
++	if (out == mi->noutputs) {
++		out = 0;
++		kp->last_key_state_changed = kp->key_state_changed;
++		kp->key_state_changed = 0;
++		kp->some_keys_pressed = 0;
++	} else {
++		key_index = out * mi->ninputs;
++		for (in = 0; in < mi->ninputs; in++, key_index++) {
++			gpio = mi->input_gpios[in];
++			if (gpio_get_value(gpio) ^ !polarity) {
++				if (kp->some_keys_pressed < 3)
++					kp->some_keys_pressed++;
++				kp->key_state_changed |= !__test_and_set_bit(
++						key_index, kp->keys_pressed);
++			} else
++				kp->key_state_changed |= __test_and_clear_bit(
++						key_index, kp->keys_pressed);
++		}
++		gpio = mi->output_gpios[out];
++		if (gpio_keypad_flags & GPIOKPF_DRIVE_INACTIVE)
++			gpio_set_value(gpio, !polarity);
++		else
++			gpio_direction_input(gpio);
++		out++;
++	}
++	kp->current_output = out;
++	if (out < mi->noutputs) {
++		gpio = mi->output_gpios[out];
++		if (gpio_keypad_flags & GPIOKPF_DRIVE_INACTIVE)
++			gpio_set_value(gpio, polarity);
++		else
++			gpio_direction_output(gpio, polarity);
++		hrtimer_start(timer, mi->settle_time, HRTIMER_MODE_REL);
++		return HRTIMER_NORESTART;
++	}
++	if (gpio_keypad_flags & GPIOKPF_DEBOUNCE) {
++		if (kp->key_state_changed) {
++			hrtimer_start(&kp->timer, mi->debounce_delay,
++				      HRTIMER_MODE_REL);
++			return HRTIMER_NORESTART;
++		}
++		kp->key_state_changed = kp->last_key_state_changed;
++	}
++	if (kp->key_state_changed) {
++		if (gpio_keypad_flags & GPIOKPF_REMOVE_SOME_PHANTOM_KEYS)
++			remove_phantom_keys(kp);
++		key_index = 0;
++		for (out = 0; out < mi->noutputs; out++)
++			for (in = 0; in < mi->ninputs; in++, key_index++)
++				report_key(kp, key_index, out, in);
++		report_sync(kp);
++	}
++	if (!kp->use_irq || kp->some_keys_pressed) {
++		hrtimer_start(timer, mi->poll_time, HRTIMER_MODE_REL);
++		return HRTIMER_NORESTART;
++	}
++
++	/* No keys are pressed, reenable interrupt */
++	for (out = 0; out < mi->noutputs; out++) {
++		if (gpio_keypad_flags & GPIOKPF_DRIVE_INACTIVE)
++			gpio_set_value(mi->output_gpios[out], polarity);
++		else
++			gpio_direction_output(mi->output_gpios[out], polarity);
++	}
++	for (in = 0; in < mi->ninputs; in++)
++		enable_irq(gpio_to_irq(mi->input_gpios[in]));
++	wake_unlock(&kp->wake_lock);
++	return HRTIMER_NORESTART;
++}
++
++static irqreturn_t gpio_keypad_irq_handler(int irq_in, void *dev_id)
++{
++	int i;
++	struct gpio_kp *kp = dev_id;
++	struct gpio_event_matrix_info *mi = kp->keypad_info;
++	unsigned gpio_keypad_flags = mi->flags;
++
++	if (!kp->use_irq) {
++		/* ignore interrupt while registering the handler */
++		kp->disabled_irq = 1;
++		disable_irq_nosync(irq_in);
++		return IRQ_HANDLED;
++	}
++
++	for (i = 0; i < mi->ninputs; i++)
++		disable_irq_nosync(gpio_to_irq(mi->input_gpios[i]));
++	for (i = 0; i < mi->noutputs; i++) {
++		if (gpio_keypad_flags & GPIOKPF_DRIVE_INACTIVE)
++			gpio_set_value(mi->output_gpios[i],
++				!(gpio_keypad_flags & GPIOKPF_ACTIVE_HIGH));
++		else
++			gpio_direction_input(mi->output_gpios[i]);
++	}
++	wake_lock(&kp->wake_lock);
++	hrtimer_start(&kp->timer, ktime_set(0, 0), HRTIMER_MODE_REL);
++	return IRQ_HANDLED;
++}
++
++static int gpio_keypad_request_irqs(struct gpio_kp *kp)
++{
++	int i;
++	int err;
++	unsigned int irq;
++	unsigned long request_flags;
++	struct gpio_event_matrix_info *mi = kp->keypad_info;
++
++	switch (mi->flags & (GPIOKPF_ACTIVE_HIGH|GPIOKPF_LEVEL_TRIGGERED_IRQ)) {
++	default:
++		request_flags = IRQF_TRIGGER_FALLING;
++		break;
++	case GPIOKPF_ACTIVE_HIGH:
++		request_flags = IRQF_TRIGGER_RISING;
++		break;
++	case GPIOKPF_LEVEL_TRIGGERED_IRQ:
++		request_flags = IRQF_TRIGGER_LOW;
++		break;
++	case GPIOKPF_LEVEL_TRIGGERED_IRQ | GPIOKPF_ACTIVE_HIGH:
++		request_flags = IRQF_TRIGGER_HIGH;
++		break;
++	}
++
++	for (i = 0; i < mi->ninputs; i++) {
++		err = irq = gpio_to_irq(mi->input_gpios[i]);
++		if (err < 0)
++			goto err_gpio_get_irq_num_failed;
++		err = request_irq(irq, gpio_keypad_irq_handler, request_flags,
++				  "gpio_kp", kp);
++		if (err) {
++			pr_err("gpiomatrix: request_irq failed for input %d, "
++				"irq %d\n", mi->input_gpios[i], irq);
++			goto err_request_irq_failed;
++		}
++		err = enable_irq_wake(irq);
++		if (err) {
++			pr_err("gpiomatrix: set_irq_wake failed for input %d, "
++				"irq %d\n", mi->input_gpios[i], irq);
++		}
++		disable_irq(irq);
++		if (kp->disabled_irq) {
++			kp->disabled_irq = 0;
++			enable_irq(irq);
++		}
++	}
++	return 0;
++
++	for (i = mi->noutputs - 1; i >= 0; i--) {
++		free_irq(gpio_to_irq(mi->input_gpios[i]), kp);
++err_request_irq_failed:
++err_gpio_get_irq_num_failed:
++		;
++	}
++	return err;
++}
++
++int gpio_event_matrix_func(struct gpio_event_input_devs *input_devs,
++	struct gpio_event_info *info, void **data, int func)
++{
++	int i;
++	int err;
++	int key_count;
++	struct gpio_kp *kp;
++	struct gpio_event_matrix_info *mi;
++
++	mi = container_of(info, struct gpio_event_matrix_info, info);
++	if (func == GPIO_EVENT_FUNC_SUSPEND || func == GPIO_EVENT_FUNC_RESUME) {
++		/* TODO: disable scanning */
++		return 0;
++	}
++
++	if (func == GPIO_EVENT_FUNC_INIT) {
++		if (mi->keymap == NULL ||
++		   mi->input_gpios == NULL ||
++		   mi->output_gpios == NULL) {
++			err = -ENODEV;
++			pr_err("gpiomatrix: Incomplete pdata\n");
++			goto err_invalid_platform_data;
++		}
++		key_count = mi->ninputs * mi->noutputs;
++
++		*data = kp = kzalloc(sizeof(*kp) + sizeof(kp->keys_pressed[0]) *
++				     BITS_TO_LONGS(key_count), GFP_KERNEL);
++		if (kp == NULL) {
++			err = -ENOMEM;
++			pr_err("gpiomatrix: Failed to allocate private data\n");
++			goto err_kp_alloc_failed;
++		}
++		kp->input_devs = input_devs;
++		kp->keypad_info = mi;
++		for (i = 0; i < key_count; i++) {
++			unsigned short keyentry = mi->keymap[i];
++			unsigned short keycode = keyentry & MATRIX_KEY_MASK;
++			unsigned short dev = keyentry >> MATRIX_CODE_BITS;
++			if (dev >= input_devs->count) {
++				pr_err("gpiomatrix: bad device index %d >= "
++					"%d for key code %d\n",
++					dev, input_devs->count, keycode);
++				err = -EINVAL;
++				goto err_bad_keymap;
++			}
++			if (keycode && keycode <= KEY_MAX)
++				input_set_capability(input_devs->dev[dev],
++							EV_KEY, keycode);
++		}
++
++		for (i = 0; i < mi->noutputs; i++) {
++			err = gpio_request(mi->output_gpios[i], "gpio_kp_out");
++			if (err) {
++				pr_err("gpiomatrix: gpio_request failed for "
++					"output %d\n", mi->output_gpios[i]);
++				goto err_request_output_gpio_failed;
++			}
++			if (gpio_cansleep(mi->output_gpios[i])) {
++				pr_err("gpiomatrix: unsupported output gpio %d,"
++					" can sleep\n", mi->output_gpios[i]);
++				err = -EINVAL;
++				goto err_output_gpio_configure_failed;
++			}
++			if (mi->flags & GPIOKPF_DRIVE_INACTIVE)
++				err = gpio_direction_output(mi->output_gpios[i],
++					!(mi->flags & GPIOKPF_ACTIVE_HIGH));
++			else
++				err = gpio_direction_input(mi->output_gpios[i]);
++			if (err) {
++				pr_err("gpiomatrix: gpio_configure failed for "
++					"output %d\n", mi->output_gpios[i]);
++				goto err_output_gpio_configure_failed;
++			}
++		}
++		for (i = 0; i < mi->ninputs; i++) {
++			err = gpio_request(mi->input_gpios[i], "gpio_kp_in");
++			if (err) {
++				pr_err("gpiomatrix: gpio_request failed for "
++					"input %d\n", mi->input_gpios[i]);
++				goto err_request_input_gpio_failed;
++			}
++			err = gpio_direction_input(mi->input_gpios[i]);
++			if (err) {
++				pr_err("gpiomatrix: gpio_direction_input failed"
++					" for input %d\n", mi->input_gpios[i]);
++				goto err_gpio_direction_input_failed;
++			}
++		}
++		kp->current_output = mi->noutputs;
++		kp->key_state_changed = 1;
++
++		hrtimer_init(&kp->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
++		kp->timer.function = gpio_keypad_timer_func;
++		wake_lock_init(&kp->wake_lock, WAKE_LOCK_SUSPEND, "gpio_kp");
++		err = gpio_keypad_request_irqs(kp);
++		kp->use_irq = err == 0;
++
++		pr_info("GPIO Matrix Keypad Driver: Start keypad matrix for "
++			"%s%s in %s mode\n", input_devs->dev[0]->name,
++			(input_devs->count > 1) ? "..." : "",
++			kp->use_irq ? "interrupt" : "polling");
++
++		if (kp->use_irq)
++			wake_lock(&kp->wake_lock);
++		hrtimer_start(&kp->timer, ktime_set(0, 0), HRTIMER_MODE_REL);
++
++		return 0;
++	}
++
++	err = 0;
++	kp = *data;
++
++	if (kp->use_irq)
++		for (i = mi->noutputs - 1; i >= 0; i--)
++			free_irq(gpio_to_irq(mi->input_gpios[i]), kp);
++
++	hrtimer_cancel(&kp->timer);
++	wake_lock_destroy(&kp->wake_lock);
++	for (i = mi->noutputs - 1; i >= 0; i--) {
++err_gpio_direction_input_failed:
++		gpio_free(mi->input_gpios[i]);
++err_request_input_gpio_failed:
++		;
++	}
++	for (i = mi->noutputs - 1; i >= 0; i--) {
++err_output_gpio_configure_failed:
++		gpio_free(mi->output_gpios[i]);
++err_request_output_gpio_failed:
++		;
++	}
++err_bad_keymap:
++	kfree(kp);
++err_kp_alloc_failed:
++err_invalid_platform_data:
++	return err;
++}
+diff --git a/drivers/input/misc/gpio_output.c b/drivers/input/misc/gpio_output.c
+new file mode 100644
+index 0000000..2aac2fa
+--- /dev/null
++++ b/drivers/input/misc/gpio_output.c
+@@ -0,0 +1,97 @@
++/* drivers/input/misc/gpio_output.c
++ *
++ * Copyright (C) 2007 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/gpio.h>
++#include <linux/gpio_event.h>
++
++int gpio_event_output_event(
++	struct gpio_event_input_devs *input_devs, struct gpio_event_info *info,
++	void **data, unsigned int dev, unsigned int type,
++	unsigned int code, int value)
++{
++	int i;
++	struct gpio_event_output_info *oi;
++	oi = container_of(info, struct gpio_event_output_info, info);
++	if (type != oi->type)
++		return 0;
++	if (!(oi->flags & GPIOEDF_ACTIVE_HIGH))
++		value = !value;
++	for (i = 0; i < oi->keymap_size; i++)
++		if (dev == oi->keymap[i].dev && code == oi->keymap[i].code)
++			gpio_set_value(oi->keymap[i].gpio, value);
++	return 0;
++}
++
++int gpio_event_output_func(
++	struct gpio_event_input_devs *input_devs, struct gpio_event_info *info,
++	void **data, int func)
++{
++	int ret;
++	int i;
++	struct gpio_event_output_info *oi;
++	oi = container_of(info, struct gpio_event_output_info, info);
++
++	if (func == GPIO_EVENT_FUNC_SUSPEND || func == GPIO_EVENT_FUNC_RESUME)
++		return 0;
++
++	if (func == GPIO_EVENT_FUNC_INIT) {
++		int output_level = !(oi->flags & GPIOEDF_ACTIVE_HIGH);
++
++		for (i = 0; i < oi->keymap_size; i++) {
++			int dev = oi->keymap[i].dev;
++			if (dev >= input_devs->count) {
++				pr_err("gpio_event_output_func: bad device "
++					"index %d >= %d for key code %d\n",
++					dev, input_devs->count,
++					oi->keymap[i].code);
++				ret = -EINVAL;
++				goto err_bad_keymap;
++			}
++			input_set_capability(input_devs->dev[dev], oi->type,
++					     oi->keymap[i].code);
++		}
++
++		for (i = 0; i < oi->keymap_size; i++) {
++			ret = gpio_request(oi->keymap[i].gpio,
++					   "gpio_event_output");
++			if (ret) {
++				pr_err("gpio_event_output_func: gpio_request "
++					"failed for %d\n", oi->keymap[i].gpio);
++				goto err_gpio_request_failed;
++			}
++			ret = gpio_direction_output(oi->keymap[i].gpio,
++						    output_level);
++			if (ret) {
++				pr_err("gpio_event_output_func: "
++					"gpio_direction_output failed for %d\n",
++					oi->keymap[i].gpio);
++				goto err_gpio_direction_output_failed;
++			}
++		}
++		return 0;
++	}
++
++	ret = 0;
++	for (i = oi->keymap_size - 1; i >= 0; i--) {
++err_gpio_direction_output_failed:
++		gpio_free(oi->keymap[i].gpio);
++err_gpio_request_failed:
++		;
++	}
++err_bad_keymap:
++	return ret;
++}
++
+diff --git a/drivers/input/misc/keychord.c b/drivers/input/misc/keychord.c
+new file mode 100644
+index 0000000..a5ea27a
+--- /dev/null
++++ b/drivers/input/misc/keychord.c
+@@ -0,0 +1,391 @@
++/*
++ *  drivers/input/misc/keychord.c
++ *
++ * Copyright (C) 2008 Google, Inc.
++ * Author: Mike Lockwood <lockwood@android.com>
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++*/
++
++#include <linux/poll.h>
++#include <linux/slab.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/spinlock.h>
++#include <linux/fs.h>
++#include <linux/miscdevice.h>
++#include <linux/keychord.h>
++#include <linux/sched.h>
++
++#define KEYCHORD_NAME		"keychord"
++#define BUFFER_SIZE			16
++
++MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>");
++MODULE_DESCRIPTION("Key chord input driver");
++MODULE_SUPPORTED_DEVICE("keychord");
++MODULE_LICENSE("GPL");
++
++#define NEXT_KEYCHORD(kc) ((struct input_keychord *) \
++		((char *)kc + sizeof(struct input_keychord) + \
++		kc->count * sizeof(kc->keycodes[0])))
++
++struct keychord_device {
++	struct input_handler	input_handler;
++	int			registered;
++
++	/* list of keychords to monitor */
++	struct input_keychord	*keychords;
++	int			keychord_count;
++
++	/* bitmask of keys contained in our keychords */
++	unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];
++	/* current state of the keys */
++	unsigned long keystate[BITS_TO_LONGS(KEY_CNT)];
++	/* number of keys that are currently pressed */
++	int key_down;
++
++	/* second input_device_id is needed for null termination */
++	struct input_device_id  device_ids[2];
++
++	spinlock_t		lock;
++	wait_queue_head_t	waitq;
++	unsigned char		head;
++	unsigned char		tail;
++	__u16			buff[BUFFER_SIZE];
++};
++
++static int check_keychord(struct keychord_device *kdev,
++		struct input_keychord *keychord)
++{
++	int i;
++
++	if (keychord->count != kdev->key_down)
++		return 0;
++
++	for (i = 0; i < keychord->count; i++) {
++		if (!test_bit(keychord->keycodes[i], kdev->keystate))
++			return 0;
++	}
++
++	/* we have a match */
++	return 1;
++}
++
++static void keychord_event(struct input_handle *handle, unsigned int type,
++			   unsigned int code, int value)
++{
++	struct keychord_device *kdev = handle->private;
++	struct input_keychord *keychord;
++	unsigned long flags;
++	int i, got_chord = 0;
++
++	if (type != EV_KEY || code >= KEY_MAX)
++		return;
++
++	spin_lock_irqsave(&kdev->lock, flags);
++	/* do nothing if key state did not change */
++	if (!test_bit(code, kdev->keystate) == !value)
++		goto done;
++	__change_bit(code, kdev->keystate);
++	if (value)
++		kdev->key_down++;
++	else
++		kdev->key_down--;
++
++	/* don't notify on key up */
++	if (!value)
++		goto done;
++	/* ignore this event if it is not one of the keys we are monitoring */
++	if (!test_bit(code, kdev->keybit))
++		goto done;
++
++	keychord = kdev->keychords;
++	if (!keychord)
++		goto done;
++
++	/* check to see if the keyboard state matches any keychords */
++	for (i = 0; i < kdev->keychord_count; i++) {
++		if (check_keychord(kdev, keychord)) {
++			kdev->buff[kdev->head] = keychord->id;
++			kdev->head = (kdev->head + 1) % BUFFER_SIZE;
++			got_chord = 1;
++			break;
++		}
++		/* skip to next keychord */
++		keychord = NEXT_KEYCHORD(keychord);
++	}
++
++done:
++	spin_unlock_irqrestore(&kdev->lock, flags);
++
++	if (got_chord) {
++		pr_info("keychord: got keychord id %d. Any tasks: %d\n",
++			keychord->id,
++			!list_empty_careful(&kdev->waitq.task_list));
++		wake_up_interruptible(&kdev->waitq);
++	}
++}
++
++static int keychord_connect(struct input_handler *handler,
++					  struct input_dev *dev,
++					  const struct input_device_id *id)
++{
++	int i, ret;
++	struct input_handle *handle;
++	struct keychord_device *kdev =
++		container_of(handler, struct keychord_device, input_handler);
++
++	/*
++	 * ignore this input device if it does not contain any keycodes
++	 * that we are monitoring
++	 */
++	for (i = 0; i < KEY_MAX; i++) {
++		if (test_bit(i, kdev->keybit) && test_bit(i, dev->keybit))
++			break;
++	}
++	if (i == KEY_MAX)
++		return -ENODEV;
++
++	handle = kzalloc(sizeof(*handle), GFP_KERNEL);
++	if (!handle)
++		return -ENOMEM;
++
++	handle->dev = dev;
++	handle->handler = handler;
++	handle->name = KEYCHORD_NAME;
++	handle->private = kdev;
++
++	ret = input_register_handle(handle);
++	if (ret)
++		goto err_input_register_handle;
++
++	ret = input_open_device(handle);
++	if (ret)
++		goto err_input_open_device;
++
++	pr_info("keychord: using input dev %s for fevent\n", dev->name);
++
++	return 0;
++
++err_input_open_device:
++	input_unregister_handle(handle);
++err_input_register_handle:
++	kfree(handle);
++	return ret;
++}
++
++static void keychord_disconnect(struct input_handle *handle)
++{
++	input_close_device(handle);
++	input_unregister_handle(handle);
++	kfree(handle);
++}
++
++/*
++ * keychord_read is used to read keychord events from the driver
++ */
++static ssize_t keychord_read(struct file *file, char __user *buffer,
++		size_t count, loff_t *ppos)
++{
++	struct keychord_device *kdev = file->private_data;
++	__u16   id;
++	int retval;
++	unsigned long flags;
++
++	if (count < sizeof(id))
++		return -EINVAL;
++	count = sizeof(id);
++
++	if (kdev->head == kdev->tail && (file->f_flags & O_NONBLOCK))
++		return -EAGAIN;
++
++	retval = wait_event_interruptible(kdev->waitq,
++			kdev->head != kdev->tail);
++	if (retval)
++		return retval;
++
++	spin_lock_irqsave(&kdev->lock, flags);
++	/* pop a keychord ID off the queue */
++	id = kdev->buff[kdev->tail];
++	kdev->tail = (kdev->tail + 1) % BUFFER_SIZE;
++	spin_unlock_irqrestore(&kdev->lock, flags);
++
++	if (copy_to_user(buffer, &id, count))
++		return -EFAULT;
++
++	return count;
++}
++
++/*
++ * keychord_write is used to configure the driver
++ */
++static ssize_t keychord_write(struct file *file, const char __user *buffer,
++		size_t count, loff_t *ppos)
++{
++	struct keychord_device *kdev = file->private_data;
++	struct input_keychord *keychords = 0;
++	struct input_keychord *keychord, *next, *end;
++	int ret, i, key;
++	unsigned long flags;
++
++	if (count < sizeof(struct input_keychord))
++		return -EINVAL;
++	keychords = kzalloc(count, GFP_KERNEL);
++	if (!keychords)
++		return -ENOMEM;
++
++	/* read list of keychords from userspace */
++	if (copy_from_user(keychords, buffer, count)) {
++		kfree(keychords);
++		return -EFAULT;
++	}
++
++	/* unregister handler before changing configuration */
++	if (kdev->registered) {
++		input_unregister_handler(&kdev->input_handler);
++		kdev->registered = 0;
++	}
++
++	spin_lock_irqsave(&kdev->lock, flags);
++	/* clear any existing configuration */
++	kfree(kdev->keychords);
++	kdev->keychords = 0;
++	kdev->keychord_count = 0;
++	kdev->key_down = 0;
++	memset(kdev->keybit, 0, sizeof(kdev->keybit));
++	memset(kdev->keystate, 0, sizeof(kdev->keystate));
++	kdev->head = kdev->tail = 0;
++
++	keychord = keychords;
++	end = (struct input_keychord *)((char *)keychord + count);
++
++	while (keychord < end) {
++		next = NEXT_KEYCHORD(keychord);
++		if (keychord->count <= 0 || next > end) {
++			pr_err("keychord: invalid keycode count %d\n",
++				keychord->count);
++			goto err_unlock_return;
++		}
++		if (keychord->version != KEYCHORD_VERSION) {
++			pr_err("keychord: unsupported version %d\n",
++				keychord->version);
++			goto err_unlock_return;
++		}
++
++		/* keep track of the keys we are monitoring in keybit */
++		for (i = 0; i < keychord->count; i++) {
++			key = keychord->keycodes[i];
++			if (key < 0 || key >= KEY_CNT) {
++				pr_err("keychord: keycode %d out of range\n",
++					key);
++				goto err_unlock_return;
++			}
++			__set_bit(key, kdev->keybit);
++		}
++
++		kdev->keychord_count++;
++		keychord = next;
++	}
++
++	kdev->keychords = keychords;
++	spin_unlock_irqrestore(&kdev->lock, flags);
++
++	ret = input_register_handler(&kdev->input_handler);
++	if (ret) {
++		kfree(keychords);
++		kdev->keychords = 0;
++		return ret;
++	}
++	kdev->registered = 1;
++
++	return count;
++
++err_unlock_return:
++	spin_unlock_irqrestore(&kdev->lock, flags);
++	kfree(keychords);
++	return -EINVAL;
++}
++
++static unsigned int keychord_poll(struct file *file, poll_table *wait)
++{
++	struct keychord_device *kdev = file->private_data;
++
++	poll_wait(file, &kdev->waitq, wait);
++
++	if (kdev->head != kdev->tail)
++		return POLLIN | POLLRDNORM;
++
++	return 0;
++}
++
++static int keychord_open(struct inode *inode, struct file *file)
++{
++	struct keychord_device *kdev;
++
++	kdev = kzalloc(sizeof(struct keychord_device), GFP_KERNEL);
++	if (!kdev)
++		return -ENOMEM;
++
++	spin_lock_init(&kdev->lock);
++	init_waitqueue_head(&kdev->waitq);
++
++	kdev->input_handler.event = keychord_event;
++	kdev->input_handler.connect = keychord_connect;
++	kdev->input_handler.disconnect = keychord_disconnect;
++	kdev->input_handler.name = KEYCHORD_NAME;
++	kdev->input_handler.id_table = kdev->device_ids;
++
++	kdev->device_ids[0].flags = INPUT_DEVICE_ID_MATCH_EVBIT;
++	__set_bit(EV_KEY, kdev->device_ids[0].evbit);
++
++	file->private_data = kdev;
++
++	return 0;
++}
++
++static int keychord_release(struct inode *inode, struct file *file)
++{
++	struct keychord_device *kdev = file->private_data;
++
++	if (kdev->registered)
++		input_unregister_handler(&kdev->input_handler);
++	kfree(kdev);
++
++	return 0;
++}
++
++static const struct file_operations keychord_fops = {
++	.owner		= THIS_MODULE,
++	.open		= keychord_open,
++	.release	= keychord_release,
++	.read		= keychord_read,
++	.write		= keychord_write,
++	.poll		= keychord_poll,
++};
++
++static struct miscdevice keychord_misc = {
++	.fops		= &keychord_fops,
++	.name		= KEYCHORD_NAME,
++	.minor		= MISC_DYNAMIC_MINOR,
++};
++
++static int __init keychord_init(void)
++{
++	return misc_register(&keychord_misc);
++}
++
++static void __exit keychord_exit(void)
++{
++	misc_deregister(&keychord_misc);
++}
++
++module_init(keychord_init);
++module_exit(keychord_exit);
+diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
+index 38493ff..7aae78e 100644
+--- a/drivers/irqchip/irq-gic.c
++++ b/drivers/irqchip/irq-gic.c
+@@ -81,6 +81,23 @@ static DEFINE_RAW_SPINLOCK(irq_controller_lock);
+ static u8 gic_cpu_map[NR_GIC_CPU_IF] __read_mostly;
+ 
+ /*
++ *Uesed to process gic sgi interrupt *
++ */
++#if defined(CONFIG_ARCH_HI3559) || defined(CONFIG_ARCH_HI3556)
++#define DIS_IRQ_CNT	6
++#else
++#define DIS_IRQ_CNT	2
++#endif
++struct gic_sgi_handle {
++	unsigned int irq;
++	void (*handle)(unsigned int cpu_intrf,
++			unsigned int irq_num,
++			struct pt_regs *regs);
++};
++struct gic_sgi_handle dis_irq_handle[DIS_IRQ_CNT];
++EXPORT_SYMBOL(dis_irq_handle);
++
++/*
+  * Supported arch specific GIC irq extension.
+  * Default make them NULL.
+  */
+@@ -258,6 +275,22 @@ static int gic_set_wake(struct irq_data *d, unsigned int on)
+ #else
+ #define gic_set_wake	NULL
+ #endif
++/* used to process dis irq */
++int dis_irq_proc(u32 irqnr, u32 irqstat, struct pt_regs *regs)
++{
++	u32 idx;
++
++	for (idx = 0; idx < DIS_IRQ_CNT; idx++) {
++		if ((irqnr == dis_irq_handle[idx].irq)
++				&& (dis_irq_handle[idx].handle)) {
++			dis_irq_handle[idx].handle(((irqstat >> 10) & 0x7),
++					irqnr, regs);
++			return 1;
++		}
++	}
++
++	return 0;
++}
+ 
+ static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
+ {
+@@ -273,13 +306,19 @@ static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
+ 			handle_domain_irq(gic->domain, irqnr, regs);
+ 			continue;
+ 		}
++
+ 		if (irqnr < 16) {
+ 			writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);
++
++			/*Call dis irq  proccess func*/
++			if (dis_irq_proc(irqnr, irqstat, regs))
++				continue;
+ #ifdef CONFIG_SMP
+ 			handle_IPI(irqnr, regs);
+ #endif
+ 			continue;
+ 		}
++
+ 		break;
+ 	} while (1);
+ }
+@@ -366,7 +405,6 @@ static void gic_cpu_if_up(void)
+ 	writel_relaxed(bypass | GICC_ENABLE, cpu_base + GIC_CPU_CTRL);
+ }
+ 
+-
+ static void __init gic_dist_init(struct gic_chip_data *gic)
+ {
+ 	unsigned int i;
+@@ -1001,7 +1039,28 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
+ 	}
+ 
+ 	gic_chip.flags |= gic_arch_extn.flags;
++#if !defined(CONFIG_ARCH_HI3559) && !defined(CONFIG_ARCH_HI3556)
+ 	gic_dist_init(gic);
++#else
++    {
++        /* 0x47444946('G''D''I''F') is abbreviation of GIC_DIST_INIT_FLAG   */
++        /* hi3559/hi3556 runs 2 OS, another OS distributes the IRQ.         */
++        /* when another OS has distributed the IRQ, sysctrl(0x12020130)     */
++        /* register will be set to 0x47444946                               */
++        /* if another OS did not distribute the IRQ, this OS will do it.    */
++
++#define GIC_DIST_INIT_FLAG 0x47444946
++#define GIC_DIST_INIT_FLAG_OFFSET 0x0130
++        struct device_node *np;
++        int gic_dist_init_flag;
++
++        np = of_find_compatible_node(NULL, NULL, "hisilicon,sysctrl");
++        gic_dist_init_flag = readl(of_iomap(np, 0) + GIC_DIST_INIT_FLAG_OFFSET);
++
++        if(gic_dist_init_flag != GIC_DIST_INIT_FLAG)
++            gic_dist_init(gic);
++    }
++#endif
+ 	gic_cpu_init(gic);
+ 	gic_pm_init(gic);
+ }
+diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
+index 08981be..5503e43 100644
+--- a/drivers/md/dm-crypt.c
++++ b/drivers/md/dm-crypt.c
+@@ -18,9 +18,11 @@
+ #include <linux/slab.h>
+ #include <linux/crypto.h>
+ #include <linux/workqueue.h>
++#include <linux/kthread.h>
+ #include <linux/backing-dev.h>
+ #include <linux/atomic.h>
+ #include <linux/scatterlist.h>
++#include <linux/rbtree.h>
+ #include <asm/page.h>
+ #include <asm/unaligned.h>
+ #include <crypto/hash.h>
+@@ -58,7 +60,8 @@ struct dm_crypt_io {
+ 	atomic_t io_pending;
+ 	int error;
+ 	sector_t sector;
+-	struct dm_crypt_io *base_io;
++
++	struct rb_node rb_node;
+ } CRYPTO_MINALIGN_ATTR;
+ 
+ struct dm_crypt_request {
+@@ -108,7 +111,8 @@ struct iv_tcw_private {
+  * Crypt: maps a linear range of a block device
+  * and encrypts / decrypts at the same time.
+  */
+-enum flags { DM_CRYPT_SUSPENDED, DM_CRYPT_KEY_VALID };
++enum flags { DM_CRYPT_SUSPENDED, DM_CRYPT_KEY_VALID,
++	     DM_CRYPT_SAME_CPU, DM_CRYPT_NO_OFFLOAD };
+ 
+ /*
+  * The fields in here must be read only after initialization.
+@@ -121,14 +125,18 @@ struct crypt_config {
+ 	 * pool for per bio private data, crypto requests and
+ 	 * encryption requeusts/buffer pages
+ 	 */
+-	mempool_t *io_pool;
+ 	mempool_t *req_pool;
+ 	mempool_t *page_pool;
+ 	struct bio_set *bs;
++	struct mutex bio_alloc_lock;
+ 
+ 	struct workqueue_struct *io_queue;
+ 	struct workqueue_struct *crypt_queue;
+ 
++	struct task_struct *write_thread;
++	wait_queue_head_t write_thread_wait;
++	struct rb_root write_tree;
++
+ 	char *cipher;
+ 	char *cipher_string;
+ 
+@@ -172,9 +180,6 @@ struct crypt_config {
+ };
+ 
+ #define MIN_IOS        16
+-#define MIN_POOL_PAGES 32
+-
+-static struct kmem_cache *_crypt_io_pool;
+ 
+ static void clone_init(struct dm_crypt_io *, struct bio *);
+ static void kcryptd_queue_crypt(struct dm_crypt_io *io);
+@@ -223,7 +228,7 @@ static struct crypto_ablkcipher *any_tfm(struct crypt_config *cc)
+  *
+  * tcw:  Compatible implementation of the block chaining mode used
+  *       by the TrueCrypt device encryption system (prior to version 4.1).
+- *       For more info see: http://www.truecrypt.org
++ *       For more info see: https://gitlab.com/cryptsetup/cryptsetup/wikis/TrueCryptOnDiskFormat
+  *       It operates on full 512 byte sectors and uses CBC
+  *       with an IV derived from initial key and the sector number.
+  *       In addition, whitening value is applied on every sector, whitening
+@@ -946,57 +951,70 @@ static int crypt_convert(struct crypt_config *cc,
+ 	return 0;
+ }
+ 
++static void crypt_free_buffer_pages(struct crypt_config *cc, struct bio *clone);
++
+ /*
+  * Generate a new unfragmented bio with the given size
+  * This should never violate the device limitations
+- * May return a smaller bio when running out of pages, indicated by
+- * *out_of_pages set to 1.
++ *
++ * This function may be called concurrently. If we allocate from the mempool
++ * concurrently, there is a possibility of deadlock. For example, if we have
++ * mempool of 256 pages, two processes, each wanting 256, pages allocate from
++ * the mempool concurrently, it may deadlock in a situation where both processes
++ * have allocated 128 pages and the mempool is exhausted.
++ *
++ * In order to avoid this scenario we allocate the pages under a mutex.
++ *
++ * In order to not degrade performance with excessive locking, we try
++ * non-blocking allocations without a mutex first but on failure we fallback
++ * to blocking allocations with a mutex.
+  */
+-static struct bio *crypt_alloc_buffer(struct dm_crypt_io *io, unsigned size,
+-				      unsigned *out_of_pages)
++static struct bio *crypt_alloc_buffer(struct dm_crypt_io *io, unsigned size)
+ {
+ 	struct crypt_config *cc = io->cc;
+ 	struct bio *clone;
+ 	unsigned int nr_iovecs = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
+-	gfp_t gfp_mask = GFP_NOIO | __GFP_HIGHMEM;
+-	unsigned i, len;
++	gfp_t gfp_mask = GFP_NOWAIT | __GFP_HIGHMEM;
++	unsigned i, len, remaining_size;
+ 	struct page *page;
++	struct bio_vec *bvec;
++
++retry:
++	if (unlikely(gfp_mask & __GFP_WAIT))
++		mutex_lock(&cc->bio_alloc_lock);
+ 
+ 	clone = bio_alloc_bioset(GFP_NOIO, nr_iovecs, cc->bs);
+ 	if (!clone)
+-		return NULL;
++		goto return_clone;
+ 
+ 	clone_init(io, clone);
+-	*out_of_pages = 0;
++
++	remaining_size = size;
+ 
+ 	for (i = 0; i < nr_iovecs; i++) {
+ 		page = mempool_alloc(cc->page_pool, gfp_mask);
+ 		if (!page) {
+-			*out_of_pages = 1;
+-			break;
++			crypt_free_buffer_pages(cc, clone);
++			bio_put(clone);
++			gfp_mask |= __GFP_WAIT;
++			goto retry;
+ 		}
+ 
+-		/*
+-		 * If additional pages cannot be allocated without waiting,
+-		 * return a partially-allocated bio.  The caller will then try
+-		 * to allocate more bios while submitting this partial bio.
+-		 */
+-		gfp_mask = (gfp_mask | __GFP_NOWARN) & ~__GFP_WAIT;
++		len = (remaining_size > PAGE_SIZE) ? PAGE_SIZE : remaining_size;
+ 
+-		len = (size > PAGE_SIZE) ? PAGE_SIZE : size;
++		bvec = &clone->bi_io_vec[clone->bi_vcnt++];
++		bvec->bv_page = page;
++		bvec->bv_len = len;
++		bvec->bv_offset = 0;
+ 
+-		if (!bio_add_page(clone, page, len, 0)) {
+-			mempool_free(page, cc->page_pool);
+-			break;
+-		}
++		clone->bi_iter.bi_size += len;
+ 
+-		size -= len;
++		remaining_size -= len;
+ 	}
+ 
+-	if (!clone->bi_iter.bi_size) {
+-		bio_put(clone);
+-		return NULL;
+-	}
++return_clone:
++	if (unlikely(gfp_mask & __GFP_WAIT))
++		mutex_unlock(&cc->bio_alloc_lock);
+ 
+ 	return clone;
+ }
+@@ -1020,7 +1038,6 @@ static void crypt_io_init(struct dm_crypt_io *io, struct crypt_config *cc,
+ 	io->base_bio = bio;
+ 	io->sector = sector;
+ 	io->error = 0;
+-	io->base_io = NULL;
+ 	io->ctx.req = NULL;
+ 	atomic_set(&io->io_pending, 0);
+ }
+@@ -1033,13 +1050,11 @@ static void crypt_inc_pending(struct dm_crypt_io *io)
+ /*
+  * One of the bios was finished. Check for completion of
+  * the whole request and correctly clean up the buffer.
+- * If base_io is set, wait for the last fragment to complete.
+  */
+ static void crypt_dec_pending(struct dm_crypt_io *io)
+ {
+ 	struct crypt_config *cc = io->cc;
+ 	struct bio *base_bio = io->base_bio;
+-	struct dm_crypt_io *base_io = io->base_io;
+ 	int error = io->error;
+ 
+ 	if (!atomic_dec_and_test(&io->io_pending))
+@@ -1047,16 +1062,8 @@ static void crypt_dec_pending(struct dm_crypt_io *io)
+ 
+ 	if (io->ctx.req)
+ 		crypt_free_req(cc, io->ctx.req, base_bio);
+-	if (io != dm_per_bio_data(base_bio, cc->per_bio_data_size))
+-		mempool_free(io, cc->io_pool);
+-
+-	if (likely(!base_io))
+-		bio_endio(base_bio, error);
+-	else {
+-		if (error && !base_io->error)
+-			base_io->error = error;
+-		crypt_dec_pending(base_io);
+-	}
++
++	bio_endio(base_bio, error);
+ }
+ 
+ /*
+@@ -1117,15 +1124,15 @@ static void clone_init(struct dm_crypt_io *io, struct bio *clone)
+ static int kcryptd_io_read(struct dm_crypt_io *io, gfp_t gfp)
+ {
+ 	struct crypt_config *cc = io->cc;
+-	struct bio *base_bio = io->base_bio;
+ 	struct bio *clone;
+ 
+ 	/*
+-	 * The block layer might modify the bvec array, so always
+-	 * copy the required bvecs because we need the original
+-	 * one in order to decrypt the whole bio data *afterwards*.
++	 * We need the original biovec array in order to decrypt
++	 * the whole bio data *afterwards* -- thanks to immutable
++	 * biovecs we don't need to worry about the block layer
++	 * modifying the biovec array; so leverage bio_clone_fast().
+ 	 */
+-	clone = bio_clone_bioset(base_bio, gfp, cc->bs);
++	clone = bio_clone_fast(io->base_bio, gfp, cc->bs);
+ 	if (!clone)
+ 		return 1;
+ 
+@@ -1138,37 +1145,97 @@ static int kcryptd_io_read(struct dm_crypt_io *io, gfp_t gfp)
+ 	return 0;
+ }
+ 
++static void kcryptd_io_read_work(struct work_struct *work)
++{
++	struct dm_crypt_io *io = container_of(work, struct dm_crypt_io, work);
++
++	crypt_inc_pending(io);
++	if (kcryptd_io_read(io, GFP_NOIO))
++		io->error = -ENOMEM;
++	crypt_dec_pending(io);
++}
++
++static void kcryptd_queue_read(struct dm_crypt_io *io)
++{
++	struct crypt_config *cc = io->cc;
++
++	INIT_WORK(&io->work, kcryptd_io_read_work);
++	queue_work(cc->io_queue, &io->work);
++}
++
+ static void kcryptd_io_write(struct dm_crypt_io *io)
+ {
+ 	struct bio *clone = io->ctx.bio_out;
++
+ 	generic_make_request(clone);
+ }
+ 
+-static void kcryptd_io(struct work_struct *work)
++#define crypt_io_from_node(node) rb_entry((node), struct dm_crypt_io, rb_node)
++
++static int dmcrypt_write(void *data)
+ {
+-	struct dm_crypt_io *io = container_of(work, struct dm_crypt_io, work);
++	struct crypt_config *cc = data;
++	struct dm_crypt_io *io;
+ 
+-	if (bio_data_dir(io->base_bio) == READ) {
+-		crypt_inc_pending(io);
+-		if (kcryptd_io_read(io, GFP_NOIO))
+-			io->error = -ENOMEM;
+-		crypt_dec_pending(io);
+-	} else
+-		kcryptd_io_write(io);
+-}
++	while (1) {
++		struct rb_root write_tree;
++		struct blk_plug plug;
+ 
+-static void kcryptd_queue_io(struct dm_crypt_io *io)
+-{
+-	struct crypt_config *cc = io->cc;
++		DECLARE_WAITQUEUE(wait, current);
+ 
+-	INIT_WORK(&io->work, kcryptd_io);
+-	queue_work(cc->io_queue, &io->work);
++		spin_lock_irq(&cc->write_thread_wait.lock);
++continue_locked:
++
++		if (!RB_EMPTY_ROOT(&cc->write_tree))
++			goto pop_from_list;
++
++		__set_current_state(TASK_INTERRUPTIBLE);
++		__add_wait_queue(&cc->write_thread_wait, &wait);
++
++		spin_unlock_irq(&cc->write_thread_wait.lock);
++
++		if (unlikely(kthread_should_stop())) {
++			set_task_state(current, TASK_RUNNING);
++			remove_wait_queue(&cc->write_thread_wait, &wait);
++			break;
++		}
++
++		schedule();
++
++		set_task_state(current, TASK_RUNNING);
++		spin_lock_irq(&cc->write_thread_wait.lock);
++		__remove_wait_queue(&cc->write_thread_wait, &wait);
++		goto continue_locked;
++
++pop_from_list:
++		write_tree = cc->write_tree;
++		cc->write_tree = RB_ROOT;
++		spin_unlock_irq(&cc->write_thread_wait.lock);
++
++		BUG_ON(rb_parent(write_tree.rb_node));
++
++		/*
++		 * Note: we cannot walk the tree here with rb_next because
++		 * the structures may be freed when kcryptd_io_write is called.
++		 */
++		blk_start_plug(&plug);
++		do {
++			io = crypt_io_from_node(rb_first(&write_tree));
++			rb_erase(&io->rb_node, &write_tree);
++			kcryptd_io_write(io);
++		} while (!RB_EMPTY_ROOT(&write_tree));
++		blk_finish_plug(&plug);
++	}
++	return 0;
+ }
+ 
+ static void kcryptd_crypt_write_io_submit(struct dm_crypt_io *io, int async)
+ {
+ 	struct bio *clone = io->ctx.bio_out;
+ 	struct crypt_config *cc = io->cc;
++	unsigned long flags;
++	sector_t sector;
++	struct rb_node **rbp, *parent;
+ 
+ 	if (unlikely(io->error < 0)) {
+ 		crypt_free_buffer_pages(cc, clone);
+@@ -1182,20 +1249,34 @@ static void kcryptd_crypt_write_io_submit(struct dm_crypt_io *io, int async)
+ 
+ 	clone->bi_iter.bi_sector = cc->start + io->sector;
+ 
+-	if (async)
+-		kcryptd_queue_io(io);
+-	else
++	if (likely(!async) && test_bit(DM_CRYPT_NO_OFFLOAD, &cc->flags)) {
+ 		generic_make_request(clone);
++		return;
++	}
++
++	spin_lock_irqsave(&cc->write_thread_wait.lock, flags);
++	rbp = &cc->write_tree.rb_node;
++	parent = NULL;
++	sector = io->sector;
++	while (*rbp) {
++		parent = *rbp;
++		if (sector < crypt_io_from_node(parent)->sector)
++			rbp = &(*rbp)->rb_left;
++		else
++			rbp = &(*rbp)->rb_right;
++	}
++	rb_link_node(&io->rb_node, parent, rbp);
++	rb_insert_color(&io->rb_node, &cc->write_tree);
++
++	wake_up_locked(&cc->write_thread_wait);
++	spin_unlock_irqrestore(&cc->write_thread_wait.lock, flags);
+ }
+ 
+ static void kcryptd_crypt_write_convert(struct dm_crypt_io *io)
+ {
+ 	struct crypt_config *cc = io->cc;
+ 	struct bio *clone;
+-	struct dm_crypt_io *new_io;
+ 	int crypt_finished;
+-	unsigned out_of_pages = 0;
+-	unsigned remaining = io->base_bio->bi_iter.bi_size;
+ 	sector_t sector = io->sector;
+ 	int r;
+ 
+@@ -1205,80 +1286,30 @@ static void kcryptd_crypt_write_convert(struct dm_crypt_io *io)
+ 	crypt_inc_pending(io);
+ 	crypt_convert_init(cc, &io->ctx, NULL, io->base_bio, sector);
+ 
+-	/*
+-	 * The allocated buffers can be smaller than the whole bio,
+-	 * so repeat the whole process until all the data can be handled.
+-	 */
+-	while (remaining) {
+-		clone = crypt_alloc_buffer(io, remaining, &out_of_pages);
+-		if (unlikely(!clone)) {
+-			io->error = -ENOMEM;
+-			break;
+-		}
+-
+-		io->ctx.bio_out = clone;
+-		io->ctx.iter_out = clone->bi_iter;
+-
+-		remaining -= clone->bi_iter.bi_size;
+-		sector += bio_sectors(clone);
+-
+-		crypt_inc_pending(io);
+-
+-		r = crypt_convert(cc, &io->ctx);
+-		if (r < 0)
+-			io->error = -EIO;
+-
+-		crypt_finished = atomic_dec_and_test(&io->ctx.cc_pending);
+-
+-		/* Encryption was already finished, submit io now */
+-		if (crypt_finished) {
+-			kcryptd_crypt_write_io_submit(io, 0);
++	clone = crypt_alloc_buffer(io, io->base_bio->bi_iter.bi_size);
++	if (unlikely(!clone)) {
++		io->error = -EIO;
++		goto dec;
++	}
+ 
+-			/*
+-			 * If there was an error, do not try next fragments.
+-			 * For async, error is processed in async handler.
+-			 */
+-			if (unlikely(r < 0))
+-				break;
++	io->ctx.bio_out = clone;
++	io->ctx.iter_out = clone->bi_iter;
+ 
+-			io->sector = sector;
+-		}
++	sector += bio_sectors(clone);
+ 
+-		/*
+-		 * Out of memory -> run queues
+-		 * But don't wait if split was due to the io size restriction
+-		 */
+-		if (unlikely(out_of_pages))
+-			congestion_wait(BLK_RW_ASYNC, HZ/100);
+-
+-		/*
+-		 * With async crypto it is unsafe to share the crypto context
+-		 * between fragments, so switch to a new dm_crypt_io structure.
+-		 */
+-		if (unlikely(!crypt_finished && remaining)) {
+-			new_io = mempool_alloc(cc->io_pool, GFP_NOIO);
+-			crypt_io_init(new_io, io->cc, io->base_bio, sector);
+-			crypt_inc_pending(new_io);
+-			crypt_convert_init(cc, &new_io->ctx, NULL,
+-					   io->base_bio, sector);
+-			new_io->ctx.iter_in = io->ctx.iter_in;
+-
+-			/*
+-			 * Fragments after the first use the base_io
+-			 * pending count.
+-			 */
+-			if (!io->base_io)
+-				new_io->base_io = io;
+-			else {
+-				new_io->base_io = io->base_io;
+-				crypt_inc_pending(io->base_io);
+-				crypt_dec_pending(io);
+-			}
++	crypt_inc_pending(io);
++	r = crypt_convert(cc, &io->ctx);
++	if (r)
++		io->error = -EIO;
++	crypt_finished = atomic_dec_and_test(&io->ctx.cc_pending);
+ 
+-			io = new_io;
+-		}
++	/* Encryption was already finished, submit io now */
++	if (crypt_finished) {
++		kcryptd_crypt_write_io_submit(io, 0);
++		io->sector = sector;
+ 	}
+ 
++dec:
+ 	crypt_dec_pending(io);
+ }
+ 
+@@ -1481,6 +1512,9 @@ static void crypt_dtr(struct dm_target *ti)
+ 	if (!cc)
+ 		return;
+ 
++	if (cc->write_thread)
++		kthread_stop(cc->write_thread);
++
+ 	if (cc->io_queue)
+ 		destroy_workqueue(cc->io_queue);
+ 	if (cc->crypt_queue)
+@@ -1495,8 +1529,6 @@ static void crypt_dtr(struct dm_target *ti)
+ 		mempool_destroy(cc->page_pool);
+ 	if (cc->req_pool)
+ 		mempool_destroy(cc->req_pool);
+-	if (cc->io_pool)
+-		mempool_destroy(cc->io_pool);
+ 
+ 	if (cc->iv_gen_ops && cc->iv_gen_ops->dtr)
+ 		cc->iv_gen_ops->dtr(cc);
+@@ -1688,7 +1720,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
+ 	char dummy;
+ 
+ 	static struct dm_arg _args[] = {
+-		{0, 1, "Invalid number of feature args"},
++		{0, 3, "Invalid number of feature args"},
+ 	};
+ 
+ 	if (argc < 5) {
+@@ -1710,13 +1742,6 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
+ 	if (ret < 0)
+ 		goto bad;
+ 
+-	ret = -ENOMEM;
+-	cc->io_pool = mempool_create_slab_pool(MIN_IOS, _crypt_io_pool);
+-	if (!cc->io_pool) {
+-		ti->error = "Cannot allocate crypt io mempool";
+-		goto bad;
+-	}
+-
+ 	cc->dmreq_start = sizeof(struct ablkcipher_request);
+ 	cc->dmreq_start += crypto_ablkcipher_reqsize(any_tfm(cc));
+ 	cc->dmreq_start = ALIGN(cc->dmreq_start, __alignof__(struct dm_crypt_request));
+@@ -1734,6 +1759,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
+ 		iv_size_padding = crypto_ablkcipher_alignmask(any_tfm(cc));
+ 	}
+ 
++	ret = -ENOMEM;
+ 	cc->req_pool = mempool_create_kmalloc_pool(MIN_IOS, cc->dmreq_start +
+ 			sizeof(struct dm_crypt_request) + iv_size_padding + cc->iv_size);
+ 	if (!cc->req_pool) {
+@@ -1746,7 +1772,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
+ 		      sizeof(struct dm_crypt_request) + iv_size_padding + cc->iv_size,
+ 		      ARCH_KMALLOC_MINALIGN);
+ 
+-	cc->page_pool = mempool_create_page_pool(MIN_POOL_PAGES, 0);
++	cc->page_pool = mempool_create_page_pool(BIO_MAX_PAGES, 0);
+ 	if (!cc->page_pool) {
+ 		ti->error = "Cannot allocate page mempool";
+ 		goto bad;
+@@ -1758,6 +1784,8 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
+ 		goto bad;
+ 	}
+ 
++	mutex_init(&cc->bio_alloc_lock);
++
+ 	ret = -EINVAL;
+ 	if (sscanf(argv[2], "%llu%c", &tmpll, &dummy) != 1) {
+ 		ti->error = "Invalid iv_offset sector";
+@@ -1788,15 +1816,27 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
+ 		if (ret)
+ 			goto bad;
+ 
+-		opt_string = dm_shift_arg(&as);
++		ret = -EINVAL;
++		while (opt_params--) {
++			opt_string = dm_shift_arg(&as);
++			if (!opt_string) {
++				ti->error = "Not enough feature arguments";
++				goto bad;
++			}
+ 
+-		if (opt_params == 1 && opt_string &&
+-		    !strcasecmp(opt_string, "allow_discards"))
+-			ti->num_discard_bios = 1;
+-		else if (opt_params) {
+-			ret = -EINVAL;
+-			ti->error = "Invalid feature arguments";
+-			goto bad;
++			if (!strcasecmp(opt_string, "allow_discards"))
++				ti->num_discard_bios = 1;
++
++			else if (!strcasecmp(opt_string, "same_cpu_crypt"))
++				set_bit(DM_CRYPT_SAME_CPU, &cc->flags);
++
++			else if (!strcasecmp(opt_string, "submit_from_crypt_cpus"))
++				set_bit(DM_CRYPT_NO_OFFLOAD, &cc->flags);
++
++			else {
++				ti->error = "Invalid feature arguments";
++				goto bad;
++			}
+ 		}
+ 	}
+ 
+@@ -1807,13 +1847,28 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
+ 		goto bad;
+ 	}
+ 
+-	cc->crypt_queue = alloc_workqueue("kcryptd",
+-					  WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM, 1);
++	if (test_bit(DM_CRYPT_SAME_CPU, &cc->flags))
++		cc->crypt_queue = alloc_workqueue("kcryptd", WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM, 1);
++	else
++		cc->crypt_queue = alloc_workqueue("kcryptd", WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM | WQ_UNBOUND,
++						  num_online_cpus());
+ 	if (!cc->crypt_queue) {
+ 		ti->error = "Couldn't create kcryptd queue";
+ 		goto bad;
+ 	}
+ 
++	init_waitqueue_head(&cc->write_thread_wait);
++	cc->write_tree = RB_ROOT;
++
++	cc->write_thread = kthread_create(dmcrypt_write, cc, "dmcrypt_write");
++	if (IS_ERR(cc->write_thread)) {
++		ret = PTR_ERR(cc->write_thread);
++		cc->write_thread = NULL;
++		ti->error = "Couldn't spawn write thread";
++		goto bad;
++	}
++	wake_up_process(cc->write_thread);
++
+ 	ti->num_flush_bios = 1;
+ 	ti->discard_zeroes_data_unsupported = true;
+ 
+@@ -1848,7 +1903,7 @@ static int crypt_map(struct dm_target *ti, struct bio *bio)
+ 
+ 	if (bio_data_dir(io->base_bio) == READ) {
+ 		if (kcryptd_io_read(io, GFP_NOWAIT))
+-			kcryptd_queue_io(io);
++			kcryptd_queue_read(io);
+ 	} else
+ 		kcryptd_queue_crypt(io);
+ 
+@@ -1860,6 +1915,7 @@ static void crypt_status(struct dm_target *ti, status_type_t type,
+ {
+ 	struct crypt_config *cc = ti->private;
+ 	unsigned i, sz = 0;
++	int num_feature_args = 0;
+ 
+ 	switch (type) {
+ 	case STATUSTYPE_INFO:
+@@ -1878,8 +1934,18 @@ static void crypt_status(struct dm_target *ti, status_type_t type,
+ 		DMEMIT(" %llu %s %llu", (unsigned long long)cc->iv_offset,
+ 				cc->dev->name, (unsigned long long)cc->start);
+ 
+-		if (ti->num_discard_bios)
+-			DMEMIT(" 1 allow_discards");
++		num_feature_args += !!ti->num_discard_bios;
++		num_feature_args += test_bit(DM_CRYPT_SAME_CPU, &cc->flags);
++		num_feature_args += test_bit(DM_CRYPT_NO_OFFLOAD, &cc->flags);
++		if (num_feature_args) {
++			DMEMIT(" %d", num_feature_args);
++			if (ti->num_discard_bios)
++				DMEMIT(" allow_discards");
++			if (test_bit(DM_CRYPT_SAME_CPU, &cc->flags))
++				DMEMIT(" same_cpu_crypt");
++			if (test_bit(DM_CRYPT_NO_OFFLOAD, &cc->flags))
++				DMEMIT(" submit_from_crypt_cpus");
++		}
+ 
+ 		break;
+ 	}
+@@ -1976,7 +2042,7 @@ static int crypt_iterate_devices(struct dm_target *ti,
+ 
+ static struct target_type crypt_target = {
+ 	.name   = "crypt",
+-	.version = {1, 13, 0},
++	.version = {1, 14, 0},
+ 	.module = THIS_MODULE,
+ 	.ctr    = crypt_ctr,
+ 	.dtr    = crypt_dtr,
+@@ -1994,15 +2060,9 @@ static int __init dm_crypt_init(void)
+ {
+ 	int r;
+ 
+-	_crypt_io_pool = KMEM_CACHE(dm_crypt_io, 0);
+-	if (!_crypt_io_pool)
+-		return -ENOMEM;
+-
+ 	r = dm_register_target(&crypt_target);
+-	if (r < 0) {
++	if (r < 0)
+ 		DMERR("register failed %d", r);
+-		kmem_cache_destroy(_crypt_io_pool);
+-	}
+ 
+ 	return r;
+ }
+@@ -2010,7 +2070,6 @@ static int __init dm_crypt_init(void)
+ static void __exit dm_crypt_exit(void)
+ {
+ 	dm_unregister_target(&crypt_target);
+-	kmem_cache_destroy(_crypt_io_pool);
+ }
+ 
+ module_init(dm_crypt_init);
+diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c
+index cc9537e..c59f939 100644
+--- a/drivers/media/v4l2-core/videobuf2-core.c
++++ b/drivers/media/v4l2-core/videobuf2-core.c
+@@ -3221,7 +3221,6 @@ EXPORT_SYMBOL_GPL(vb2_thread_start);
+ int vb2_thread_stop(struct vb2_queue *q)
+ {
+ 	struct vb2_threadio_data *threadio = q->threadio;
+-	struct vb2_fileio_data *fileio = q->fileio;
+ 	int err;
+ 
+ 	if (threadio == NULL)
+diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
+index 1456ea7..da983a7 100644
+--- a/drivers/mfd/Kconfig
++++ b/drivers/mfd/Kconfig
+@@ -223,6 +223,18 @@ config MFD_HI6421_PMIC
+ 	  menus in order to enable them.
+ 	  We communicate with the Hi6421 via memory-mapped I/O.
+ 
++config MFD_HISI_FMC
++	tristate "Hisilicon Flash Memory Controller"
++	depends on OF
++	select MFD_CORE
++	select REGMAP_MMIO
++	default y if (HIFMC_SPI_NAND && SPI_HISI_SFC && HIFMC_NAND)
++	help
++	  If you need to use SPI nor flash or SPI nand flash at same time,
++	  enable this option for swap controller. if your enable
++	  HIFMC_SPI_NAND and SPI_HISI_SFC at same time, this function should
++	  be select.
++
+ config HTC_EGPIO
+ 	bool "HTC EGPIO support"
+ 	depends on GPIOLIB && ARM
+diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
+index 8bd54b1..70a68ac 100644
+--- a/drivers/mfd/Makefile
++++ b/drivers/mfd/Makefile
+@@ -174,6 +174,7 @@ obj-$(CONFIG_MFD_STW481X)	+= stw481x.o
+ obj-$(CONFIG_MFD_IPAQ_MICRO)	+= ipaq-micro.o
+ obj-$(CONFIG_MFD_MENF21BMC)	+= menf21bmc.o
+ obj-$(CONFIG_MFD_HI6421_PMIC)	+= hi6421-pmic-core.o
++obj-$(CONFIG_MFD_HISI_FMC)	+= hisi_fmc.o
+ 
+ intel-soc-pmic-objs		:= intel_soc_pmic_core.o intel_soc_pmic_crc.o
+ obj-$(CONFIG_INTEL_SOC_PMIC)	+= intel-soc-pmic.o
+diff --git a/drivers/mfd/hisi_fmc.c b/drivers/mfd/hisi_fmc.c
+new file mode 100644
+index 0000000..43b771c
+--- /dev/null
++++ b/drivers/mfd/hisi_fmc.c
+@@ -0,0 +1,114 @@
++/* HiSilicon Flash Memory Controller Driver
++ *
++ * Copyright (c) 2016 Hisilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <linux/device.h>
++#include <linux/err.h>
++#include <linux/mfd/core.h>
++#include <linux/module.h>
++#include <linux/clk.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++#include <linux/regmap.h>
++#include <linux/mfd/hisi_fmc.h>
++
++unsigned char hifmc_cs_user[HIFMC_MAX_CHIP_NUM];
++
++DEFINE_MUTEX(fmc_switch_mutex);
++EXPORT_SYMBOL_GPL(fmc_switch_mutex);
++
++/* ------------------------------------------------------------------------ */
++static const struct mfd_cell hisi_fmc_devs[] = {
++	{
++		.name = "hisi_spi_nor",
++		.of_compatible = "hisilicon,hisi-sfc",
++	},
++	{
++		.name = "hisi_spi_nand",
++		.of_compatible = "hisilicon,hisi-spi-nand",
++	},
++	{
++		.name = "hisi_nand",
++		.of_compatible = "hisilicon,hisi-nand",
++	},
++};
++
++static int hisi_fmc_probe(struct platform_device *pdev)
++{
++	int ret;
++	struct hisi_fmc *fmc;
++	struct resource *res;
++
++	fmc = devm_kzalloc(&pdev->dev, sizeof(*fmc), GFP_KERNEL);
++	if (!fmc)
++		return -ENOMEM;
++
++	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "control");
++	fmc->regbase = devm_ioremap_resource(&pdev->dev, res);
++	if (IS_ERR(fmc->regbase))
++		return PTR_ERR(fmc->regbase);
++
++	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "memory");
++	fmc->iobase = devm_ioremap_resource(&pdev->dev, res);
++	if (IS_ERR(fmc->iobase))
++		return PTR_ERR(fmc->iobase);
++
++	fmc->clk = devm_clk_get(&pdev->dev, NULL);
++	if (IS_ERR(fmc->clk))
++		return PTR_ERR(fmc->clk);
++
++	mutex_init(&fmc->lock);
++
++	platform_set_drvdata(pdev, fmc);
++
++	ret = mfd_add_devices(&pdev->dev, 0, hisi_fmc_devs,
++			ARRAY_SIZE(hisi_fmc_devs), NULL, 0, NULL);
++	if (ret) {
++		dev_err(&pdev->dev, "add mfd devices failed: %d\n", ret);
++		return ret;
++	}
++
++	return 0;
++}
++
++static int hisi_fmc_remove(struct platform_device *pdev)
++{
++	struct hisi_fmc *fmc = platform_get_drvdata(pdev);
++
++	mfd_remove_devices(&pdev->dev);
++	mutex_destroy(&fmc->lock);
++
++	return 0;
++}
++
++static const struct of_device_id hisi_fmc_of_match[] = {
++	{ .compatible = "hisilicon,hisi-fmc"},
++	{ }
++};
++
++static struct platform_driver hisi_fmc_driver = {
++	.driver = {
++		.name = "hifmc",
++		.of_match_table = hisi_fmc_of_match,
++	},
++	.probe = hisi_fmc_probe,
++	.remove = hisi_fmc_remove,
++};
++module_platform_driver(hisi_fmc_driver);
++
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("HiSilicon Flash Memory Controller Driver");
+diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
+index bbeb451..14ba5bc 100644
+--- a/drivers/misc/Kconfig
++++ b/drivers/misc/Kconfig
+@@ -402,6 +402,10 @@ config TI_DAC7512
+ 	  This driver can also be built as a module. If so, the module
+ 	  will be called ti_dac7512.
+ 
++config UID_STAT
++	bool "UID based statistics tracking exported to /proc/uid_stat"
++	default n
++
+ config VMWARE_BALLOON
+ 	tristate "VMware Balloon Driver"
+ 	depends on X86 && HYPERVISOR_GUEST
+@@ -515,6 +519,12 @@ config VEXPRESS_SYSCFG
+ 	  bus. System Configuration interface is one of the possible means
+ 	  of generating transactions on this bus.
+ 
++config UID_CPUTIME
++	tristate "Per-UID cpu time statistics"
++	depends on PROFILING
++	help
++	  Per UID based cpu time statistics exported to /proc/uid_cputime
++
+ source "drivers/misc/c2port/Kconfig"
+ source "drivers/misc/eeprom/Kconfig"
+ source "drivers/misc/cb710/Kconfig"
+@@ -528,4 +538,5 @@ source "drivers/misc/mic/Kconfig"
+ source "drivers/misc/genwqe/Kconfig"
+ source "drivers/misc/echo/Kconfig"
+ source "drivers/misc/cxl/Kconfig"
++source "drivers/misc/hi_reg/Kconfig"
+ endmenu
+diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
+index 7d5c4cd..ecf313b 100644
+--- a/drivers/misc/Makefile
++++ b/drivers/misc/Makefile
+@@ -34,6 +34,7 @@ obj-$(CONFIG_ISL29020)		+= isl29020.o
+ obj-$(CONFIG_SENSORS_TSL2550)	+= tsl2550.o
+ obj-$(CONFIG_DS1682)		+= ds1682.o
+ obj-$(CONFIG_TI_DAC7512)	+= ti_dac7512.o
++obj-$(CONFIG_UID_STAT)		+= uid_stat.o
+ obj-$(CONFIG_C2PORT)		+= c2port/
+ obj-$(CONFIG_HMC6352)		+= hmc6352.o
+ obj-y				+= eeprom/
+@@ -56,3 +57,5 @@ obj-$(CONFIG_GENWQE)		+= genwqe/
+ obj-$(CONFIG_ECHO)		+= echo/
+ obj-$(CONFIG_VEXPRESS_SYSCFG)	+= vexpress-syscfg.o
+ obj-$(CONFIG_CXL_BASE)		+= cxl/
++obj-$(CONFIG_UID_CPUTIME) += uid_cputime.o
++obj-y				+= hi_reg/
+diff --git a/drivers/misc/hi_reg/Kconfig b/drivers/misc/hi_reg/Kconfig
+new file mode 100644
+index 0000000..76c8741
+--- /dev/null
++++ b/drivers/misc/hi_reg/Kconfig
+@@ -0,0 +1,13 @@
++menu "hisi 'himm/himd.l/himc'support"
++
++config HISI_REG
++	tristate "hisi \"himd\" \"himm\" \"himc\" support"
++	default y if (ARCH_HI3519)
++	default y if (ARCH_HI3519V101)
++	help
++	  This selects the Hisilicon io register access support
++	  If you want use "himd" "himm" "himc" command,
++	  Say Y or M here.
++
++	  Default is Y.
++endmenu
+diff --git a/drivers/misc/hi_reg/Makefile b/drivers/misc/hi_reg/Makefile
+new file mode 100644
+index 0000000..5c66458
+--- /dev/null
++++ b/drivers/misc/hi_reg/Makefile
+@@ -0,0 +1 @@
++obj-$(CONFIG_HISI_REG)	+= hi_reg.o
+diff --git a/drivers/misc/hi_reg/hi_reg.c b/drivers/misc/hi_reg/hi_reg.c
+new file mode 100644
+index 0000000..3dbdfd1
+--- /dev/null
++++ b/drivers/misc/hi_reg/hi_reg.c
+@@ -0,0 +1,164 @@
++#include <mach/io.h>
++#include <linux/io.h>
++
++#include <asm/uaccess.h>
++#include <linux/slab.h>
++#include <linux/module.h>
++#include <linux/fs.h>
++#include <linux/miscdevice.h>
++
++#include "hi_reg_user.h"
++
++static int hi_reg_open(struct inode *inode, struct file *file)
++{
++	return 0;
++}
++
++static int hi_reg_release(struct inode *inode, struct file *file)
++{
++	return 0;
++}
++
++static int hi_reg_read(struct file *file, char __user *buf,
++		size_t count, loff_t *f_pos)
++{
++	return 0;
++}
++
++static int hi_reg_write(struct file *file, const char __user *buf,
++		size_t count, loff_t *f_pos)
++{
++	return 0;
++}
++
++
++static long hi_reg_ioctl(struct file *file, unsigned int cmd,
++		unsigned long arg)
++{
++	void __iomem *virt_addr;
++	struct hi_reg_handle handle;
++	int valid_addr = 0;
++	unsigned int new_value = 0;
++
++	if (copy_from_user((void *)&handle, (void *)arg,
++				sizeof(struct hi_reg_handle))) {
++		printk(KERN_ERR"hi reg copy from user error!\n");
++		return -EFAULT;
++	}
++
++	/* phys addr must be aligned by 4 bytes */
++    if (!handle.phys_addr || (handle.phys_addr & (sizeof(u32) - 1))) {
++        printk(KERN_ERR"phys addr not aligned by 4 bytes,which is [0x%08x]!\n",
++                handle.phys_addr);
++		return -EFAULT;
++	}
++
++#ifdef CONFIG_ARCH_HI3516AV200
++	/* phys addr must be in IO_ADDRESS */
++    if ((handle.phys_addr >= HI3516AV200_IOCH3_PHYS)
++			&& (handle.phys_addr < HI3516AV200_IOCH3_PHYS + HI3516AV200_IOCH3_SIZE)) {
++		valid_addr = 1;
++    } else if ((handle.phys_addr >= HI3516AV200_IOCH2_PHYS)
++			&& (handle.phys_addr < HI3516AV200_IOCH2_PHYS + HI3516AV200_IOCH2_SIZE)) {
++		valid_addr = 1;
++    } else if ((handle.phys_addr >= HI3516AV200_IOCH1_PHYS)
++			&& (handle.phys_addr < HI3516AV200_IOCH1_PHYS + HI3516AV200_IOCH1_SIZE)) {
++		valid_addr = 1;
++    }
++#endif
++
++#if defined(CONFIG_ARCH_HI3519) || defined(CONFIG_ARCH_HI3519V101)
++	/* phys addr must be in IO_ADDRESS */
++    if ((handle.phys_addr >= HI3519_IOCH3_PHYS)
++			&& (handle.phys_addr < HI3519_IOCH3_PHYS + HI3519_IOCH3_SIZE)) {
++		valid_addr = 1;
++    } else if ((handle.phys_addr >= HI3519_IOCH2_PHYS)
++			&& (handle.phys_addr < HI3519_IOCH2_PHYS + HI3519_IOCH2_SIZE)) {
++		valid_addr = 1;
++    } else if ((handle.phys_addr >= HI3519_IOCH1_PHYS)
++			&& (handle.phys_addr < HI3519_IOCH1_PHYS + HI3519_IOCH1_SIZE)) {
++		valid_addr = 1;
++    }
++#endif
++
++	if (!valid_addr) {
++        printk(KERN_ERR"invalid addr, which is [0x%08x]!\n",
++                handle.phys_addr);
++		return -EFAULT;
++	}
++	if ('R' == _IOC_TYPE(cmd)) {
++		switch (_IOC_NR(cmd)) {
++			case _IOC_NR(HI_REG_READ):
++				virt_addr = (void *)IO_ADDRESS(handle.phys_addr);
++				new_value = hi_readl(virt_addr);
++				handle.data = (void *)new_value;
++				if (copy_to_user((void *)arg, (void *)&handle,
++							sizeof(struct hi_reg_handle))) {
++					printk(KERN_ERR"hi reg copy to user error!\n");
++					return -EFAULT;
++				}
++				break;
++
++			case _IOC_NR(HI_REG_WRITE):
++				virt_addr = (void *)IO_ADDRESS(handle.phys_addr);
++
++				if (sizeof(u32) == handle.size) {
++					hi_writel((u32)handle.data, virt_addr);
++				} else if (sizeof(u16) == handle.size) {
++					hi_writew(((u32)handle.data & 0xFFFF), virt_addr);
++				} else if (sizeof(u8) == handle.size) {
++					hi_writeb(((u32)handle.data & 0xFF), virt_addr);
++				} else {
++					printk(KERN_ERR"%d, write size should be 1, 2 or 4!\n", __LINE__);
++				}
++				break;
++
++			default:
++				printk(KERN_ERR"%d, hi reg unknow cmd!\n", __LINE__);
++				break;
++		}
++	} else {
++		printk(KERN_ERR"%d, hi reg unknow cmd!\n", __LINE__);
++	}
++	return 0;
++}
++
++static const struct file_operations hi_reg_fops = {
++	.owner          = THIS_MODULE,
++	.open           = hi_reg_open,
++	.release        = hi_reg_release,
++	.unlocked_ioctl = hi_reg_ioctl,
++	.write          = hi_reg_write,
++	.read           = hi_reg_read
++};
++
++static struct miscdevice hi_reg_dev = {
++	.minor    = MISC_DYNAMIC_MINOR,
++	.fops     = &hi_reg_fops,
++	.name     = "hi_reg"
++};
++
++static int __init hi_reg_init(void)
++{
++	int ret;
++	ret = misc_register(&hi_reg_dev);
++	if (ret) {
++		printk("register hi_reg device failed!");
++	}
++	return ret;
++}
++
++void __exit hi_reg_exit(void)
++{
++	misc_deregister(&hi_reg_dev);
++}
++#ifndef MODULE
++subsys_initcall(hi_reg_init);
++#else
++module_init(hi_reg_init);
++#endif
++module_exit(hi_reg_exit);
++
++MODULE_DESCRIPTION("Driver for himd/himm/himc");
++MODULE_AUTHOR("ou jinsong");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/misc/hi_reg/hi_reg_user.h b/drivers/misc/hi_reg/hi_reg_user.h
+new file mode 100644
+index 0000000..21e2e76
+--- /dev/null
++++ b/drivers/misc/hi_reg/hi_reg_user.h
+@@ -0,0 +1,21 @@
++#include <linux/ioctl.h>
++
++#ifndef __HI_REG_USER_H__
++#define __HI_REG_USER_H__
++
++struct hi_reg_handle {
++	unsigned int phys_addr;
++	unsigned int size;
++	void *data;
++	int flags;
++};
++
++
++#define HI_REG_BASE  'R'
++
++#define HI_REG_READ  \
++	_IOW(HI_REG_BASE, 1, struct hi_reg_handle)
++#define HI_REG_WRITE  \
++	_IOW(HI_REG_BASE, 2, struct hi_reg_handle)
++
++#endif   /* __HI_REG_USER_H__ */
+diff --git a/drivers/misc/uid_cputime.c b/drivers/misc/uid_cputime.c
+new file mode 100644
+index 0000000..43298a4
+--- /dev/null
++++ b/drivers/misc/uid_cputime.c
+@@ -0,0 +1,253 @@
++/* drivers/misc/uid_cputime.c
++ *
++ * Copyright (C) 2014 - 2015 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#include <linux/atomic.h>
++#include <linux/err.h>
++#include <linux/hashtable.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/list.h>
++#include <linux/proc_fs.h>
++#include <linux/profile.h>
++#include <linux/sched.h>
++#include <linux/seq_file.h>
++#include <linux/slab.h>
++#include <linux/uaccess.h>
++
++#define UID_HASH_BITS	10
++DECLARE_HASHTABLE(hash_table, UID_HASH_BITS);
++
++static DEFINE_MUTEX(uid_lock);
++static struct proc_dir_entry *parent;
++
++struct uid_entry {
++	uid_t uid;
++	cputime_t utime;
++	cputime_t stime;
++	cputime_t active_utime;
++	cputime_t active_stime;
++	unsigned long long active_power;
++	unsigned long long power;
++	struct hlist_node hash;
++};
++
++static struct uid_entry *find_uid_entry(uid_t uid)
++{
++	struct uid_entry *uid_entry;
++	hash_for_each_possible(hash_table, uid_entry, hash, uid) {
++		if (uid_entry->uid == uid)
++			return uid_entry;
++	}
++	return NULL;
++}
++
++static struct uid_entry *find_or_register_uid(uid_t uid)
++{
++	struct uid_entry *uid_entry;
++
++	uid_entry = find_uid_entry(uid);
++	if (uid_entry)
++		return uid_entry;
++
++	uid_entry = kzalloc(sizeof(struct uid_entry), GFP_ATOMIC);
++	if (!uid_entry)
++		return NULL;
++
++	uid_entry->uid = uid;
++
++	hash_add(hash_table, &uid_entry->hash, uid);
++
++	return uid_entry;
++}
++
++static int uid_stat_show(struct seq_file *m, void *v)
++{
++	struct uid_entry *uid_entry;
++	struct task_struct *task, *temp;
++	cputime_t utime;
++	cputime_t stime;
++	unsigned long bkt;
++
++	mutex_lock(&uid_lock);
++
++	hash_for_each(hash_table, bkt, uid_entry, hash) {
++		uid_entry->active_stime = 0;
++		uid_entry->active_utime = 0;
++		uid_entry->active_power = 0;
++	}
++
++	read_lock(&tasklist_lock);
++	do_each_thread(temp, task) {
++		uid_entry = find_or_register_uid(from_kuid_munged(
++			current_user_ns(), task_uid(task)));
++		if (!uid_entry) {
++			read_unlock(&tasklist_lock);
++			mutex_unlock(&uid_lock);
++			pr_err("%s: failed to find the uid_entry for uid %d\n",
++				__func__, from_kuid_munged(current_user_ns(),
++				task_uid(task)));
++			return -ENOMEM;
++		}
++		/* if this task is exiting, we have already accounted for the
++		 * time and power.
++		 */
++		if (task->cpu_power == ULLONG_MAX)
++			continue;
++		task_cputime_adjusted(task, &utime, &stime);
++		uid_entry->active_utime += utime;
++		uid_entry->active_stime += stime;
++		uid_entry->active_power += task->cpu_power;
++	} while_each_thread(temp, task);
++	read_unlock(&tasklist_lock);
++
++	hash_for_each(hash_table, bkt, uid_entry, hash) {
++		cputime_t total_utime = uid_entry->utime +
++							uid_entry->active_utime;
++		cputime_t total_stime = uid_entry->stime +
++							uid_entry->active_stime;
++		unsigned long long total_power = uid_entry->power +
++							uid_entry->active_power;
++		seq_printf(m, "%d: %llu %llu %llu\n", uid_entry->uid,
++			(unsigned long long)jiffies_to_msecs(
++				cputime_to_jiffies(total_utime)) * USEC_PER_MSEC,
++			(unsigned long long)jiffies_to_msecs(
++				cputime_to_jiffies(total_stime)) * USEC_PER_MSEC,
++			total_power);
++	}
++
++	mutex_unlock(&uid_lock);
++	return 0;
++}
++
++static int uid_stat_open(struct inode *inode, struct file *file)
++{
++	return single_open(file, uid_stat_show, PDE_DATA(inode));
++}
++
++static const struct file_operations uid_stat_fops = {
++	.open		= uid_stat_open,
++	.read		= seq_read,
++	.llseek		= seq_lseek,
++	.release	= single_release,
++};
++
++static int uid_remove_open(struct inode *inode, struct file *file)
++{
++	return single_open(file, NULL, NULL);
++}
++
++static ssize_t uid_remove_write(struct file *file,
++			const char __user *buffer, size_t count, loff_t *ppos)
++{
++	struct uid_entry *uid_entry;
++	struct hlist_node *tmp;
++	char uids[128];
++	char *start_uid, *end_uid = NULL;
++	long int uid_start = 0, uid_end = 0;
++
++	if (count >= sizeof(uids))
++		count = sizeof(uids) - 1;
++
++	if (copy_from_user(uids, buffer, count))
++		return -EFAULT;
++
++	uids[count] = '\0';
++	end_uid = uids;
++	start_uid = strsep(&end_uid, "-");
++
++	if (!start_uid || !end_uid)
++		return -EINVAL;
++
++	if (kstrtol(start_uid, 10, &uid_start) != 0 ||
++		kstrtol(end_uid, 10, &uid_end) != 0) {
++		return -EINVAL;
++	}
++
++	mutex_lock(&uid_lock);
++
++	for (; uid_start <= uid_end; uid_start++) {
++		hash_for_each_possible_safe(hash_table, uid_entry, tmp,
++							hash, uid_start) {
++			hash_del(&uid_entry->hash);
++			kfree(uid_entry);
++		}
++	}
++
++	mutex_unlock(&uid_lock);
++	return count;
++}
++
++static const struct file_operations uid_remove_fops = {
++	.open		= uid_remove_open,
++	.release	= single_release,
++	.write		= uid_remove_write,
++};
++
++static int process_notifier(struct notifier_block *self,
++			unsigned long cmd, void *v)
++{
++	struct task_struct *task = v;
++	struct uid_entry *uid_entry;
++	cputime_t utime, stime;
++	uid_t uid;
++
++	if (!task)
++		return NOTIFY_OK;
++
++	mutex_lock(&uid_lock);
++	uid = from_kuid_munged(current_user_ns(), task_uid(task));
++	uid_entry = find_or_register_uid(uid);
++	if (!uid_entry) {
++		pr_err("%s: failed to find uid %d\n", __func__, uid);
++		goto exit;
++	}
++
++	task_cputime_adjusted(task, &utime, &stime);
++	uid_entry->utime += utime;
++	uid_entry->stime += stime;
++	uid_entry->power += task->cpu_power;
++	task->cpu_power = ULLONG_MAX;
++
++exit:
++	mutex_unlock(&uid_lock);
++	return NOTIFY_OK;
++}
++
++static struct notifier_block process_notifier_block = {
++	.notifier_call	= process_notifier,
++};
++
++static int __init proc_uid_cputime_init(void)
++{
++	hash_init(hash_table);
++
++	parent = proc_mkdir("uid_cputime", NULL);
++	if (!parent) {
++		pr_err("%s: failed to create proc entry\n", __func__);
++		return -ENOMEM;
++	}
++
++	proc_create_data("remove_uid_range", S_IWUGO, parent, &uid_remove_fops,
++					NULL);
++
++	proc_create_data("show_uid_stat", S_IRUGO, parent, &uid_stat_fops,
++					NULL);
++
++	profile_event_register(PROFILE_TASK_EXIT, &process_notifier_block);
++
++	return 0;
++}
++
++early_initcall(proc_uid_cputime_init);
+diff --git a/drivers/misc/uid_stat.c b/drivers/misc/uid_stat.c
+new file mode 100644
+index 0000000..4766c1f
+--- /dev/null
++++ b/drivers/misc/uid_stat.c
+@@ -0,0 +1,152 @@
++/* drivers/misc/uid_stat.c
++ *
++ * Copyright (C) 2008 - 2009 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#include <asm/atomic.h>
++
++#include <linux/err.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/list.h>
++#include <linux/proc_fs.h>
++#include <linux/seq_file.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/stat.h>
++#include <linux/uid_stat.h>
++#include <net/activity_stats.h>
++
++static DEFINE_SPINLOCK(uid_lock);
++static LIST_HEAD(uid_list);
++static struct proc_dir_entry *parent;
++
++struct uid_stat {
++	struct list_head link;
++	uid_t uid;
++	atomic_t tcp_rcv;
++	atomic_t tcp_snd;
++};
++
++static struct uid_stat *find_uid_stat(uid_t uid) {
++	struct uid_stat *entry;
++
++	list_for_each_entry(entry, &uid_list, link) {
++		if (entry->uid == uid) {
++			return entry;
++		}
++	}
++	return NULL;
++}
++
++static int uid_stat_atomic_int_show(struct seq_file *m, void *v)
++{
++	unsigned int bytes;
++	atomic_t *counter = m->private;
++
++	bytes = (unsigned int) (atomic_read(counter) + INT_MIN);
++	return seq_printf(m, "%u\n", bytes);
++}
++
++static int uid_stat_read_atomic_int_open(struct inode *inode, struct file *file)
++{
++	return single_open(file, uid_stat_atomic_int_show, PDE_DATA(inode));
++}
++
++static const struct file_operations uid_stat_read_atomic_int_fops = {
++	.open		= uid_stat_read_atomic_int_open,
++	.read		= seq_read,
++	.llseek		= seq_lseek,
++	.release	= seq_release,
++};
++
++/* Create a new entry for tracking the specified uid. */
++static struct uid_stat *create_stat(uid_t uid) {
++	struct uid_stat *new_uid;
++	/* Create the uid stat struct and append it to the list. */
++	new_uid = kmalloc(sizeof(struct uid_stat), GFP_ATOMIC);
++	if (!new_uid)
++		return NULL;
++
++	new_uid->uid = uid;
++	/* Counters start at INT_MIN, so we can track 4GB of network traffic. */
++	atomic_set(&new_uid->tcp_rcv, INT_MIN);
++	atomic_set(&new_uid->tcp_snd, INT_MIN);
++
++	list_add_tail(&new_uid->link, &uid_list);
++	return new_uid;
++}
++
++static void create_stat_proc(struct uid_stat *new_uid)
++{
++	char uid_s[32];
++	struct proc_dir_entry *entry;
++	sprintf(uid_s, "%d", new_uid->uid);
++	entry = proc_mkdir(uid_s, parent);
++
++	/* Keep reference to uid_stat so we know what uid to read stats from. */
++	proc_create_data("tcp_snd", S_IRUGO, entry,
++			 &uid_stat_read_atomic_int_fops, &new_uid->tcp_snd);
++
++	proc_create_data("tcp_rcv", S_IRUGO, entry,
++			 &uid_stat_read_atomic_int_fops, &new_uid->tcp_rcv);
++}
++
++static struct uid_stat *find_or_create_uid_stat(uid_t uid)
++{
++	struct uid_stat *entry;
++	unsigned long flags;
++	spin_lock_irqsave(&uid_lock, flags);
++	entry = find_uid_stat(uid);
++	if (entry) {
++		spin_unlock_irqrestore(&uid_lock, flags);
++		return entry;
++	}
++	entry = create_stat(uid);
++	spin_unlock_irqrestore(&uid_lock, flags);
++	if (entry)
++		create_stat_proc(entry);
++	return entry;
++}
++
++int uid_stat_tcp_snd(uid_t uid, int size) {
++	struct uid_stat *entry;
++	activity_stats_update();
++	entry = find_or_create_uid_stat(uid);
++	if (!entry)
++		return -1;
++	atomic_add(size, &entry->tcp_snd);
++	return 0;
++}
++
++int uid_stat_tcp_rcv(uid_t uid, int size) {
++	struct uid_stat *entry;
++	activity_stats_update();
++	entry = find_or_create_uid_stat(uid);
++	if (!entry)
++		return -1;
++	atomic_add(size, &entry->tcp_rcv);
++	return 0;
++}
++
++static int __init uid_stat_init(void)
++{
++	parent = proc_mkdir("uid_stat", NULL);
++	if (!parent) {
++		pr_err("uid_stat: failed to create proc entry\n");
++		return -1;
++	}
++	return 0;
++}
++
++__initcall(uid_stat_init);
+diff --git a/drivers/mmc/card/Kconfig b/drivers/mmc/card/Kconfig
+index 5562308..79d8212 100644
+--- a/drivers/mmc/card/Kconfig
++++ b/drivers/mmc/card/Kconfig
+@@ -50,6 +50,15 @@ config MMC_BLOCK_BOUNCE
+ 
+ 	  If unsure, say Y here.
+ 
++config MMC_BLOCK_DEFERRED_RESUME
++	bool "Deferr MMC layer resume until I/O is requested"
++	depends on MMC_BLOCK
++	default n
++	help
++	  Say Y here to enable deferred MMC resume until I/O
++	  is requested. This will reduce overall resume latency and
++	  save power when theres an SD card inserted but not being used.
++
+ config SDIO_UART
+ 	tristate "SDIO UART/GPS class support"
+ 	depends on TTY
+diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
+index 10ecc0a..fd8f4b3 100644
+--- a/drivers/mmc/card/block.c
++++ b/drivers/mmc/card/block.c
+@@ -36,6 +36,9 @@
+ #include <linux/compat.h>
+ #include <linux/pm_runtime.h>
+ 
++#define CREATE_TRACE_POINTS
++#include <trace/events/mmc.h>
++
+ #include <linux/mmc/ioctl.h>
+ #include <linux/mmc/card.h>
+ #include <linux/mmc/host.h>
+@@ -136,6 +139,7 @@ static inline int mmc_blk_part_switch(struct mmc_card *card,
+ 				      struct mmc_blk_data *md);
+ static int get_card_status(struct mmc_card *card, u32 *status, int retries);
+ 
++#if 0
+ static inline void mmc_blk_clear_packed(struct mmc_queue_req *mqrq)
+ {
+ 	struct mmc_packed *packed = mqrq->packed;
+@@ -148,6 +152,7 @@ static inline void mmc_blk_clear_packed(struct mmc_queue_req *mqrq)
+ 	packed->retries = 0;
+ 	packed->blocks = 0;
+ }
++#endif
+ 
+ static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
+ {
+@@ -166,11 +171,7 @@ static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
+ 
+ static inline int mmc_get_devidx(struct gendisk *disk)
+ {
+-	int devmaj = MAJOR(disk_devt(disk));
+-	int devidx = MINOR(disk_devt(disk)) / perdev_minors;
+-
+-	if (!devmaj)
+-		devidx = disk->first_minor / perdev_minors;
++	int devidx = disk->first_minor / perdev_minors;
+ 	return devidx;
+ }
+ 
+@@ -427,9 +428,11 @@ static int ioctl_do_sanitize(struct mmc_card *card)
+ 	pr_debug("%s: %s - SANITIZE IN PROGRESS...\n",
+ 		mmc_hostname(card->host), __func__);
+ 
++	trace_mmc_blk_erase_start(EXT_CSD_SANITIZE_START, 0, 0);
+ 	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ 					EXT_CSD_SANITIZE_START, 1,
+ 					MMC_SANITIZE_REQ_TIMEOUT);
++	trace_mmc_blk_erase_end(EXT_CSD_SANITIZE_START, 0, 0);
+ 
+ 	if (err)
+ 		pr_err("%s: %s - EXT_CSD_SANITIZE_START failed. err=%d\n",
+@@ -668,6 +671,7 @@ static inline int mmc_blk_part_switch(struct mmc_card *card,
+ 	return 0;
+ }
+ 
++#if 0
+ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
+ {
+ 	int err;
+@@ -722,6 +726,7 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
+ 
+ 	return result;
+ }
++#endif
+ 
+ static int get_card_status(struct mmc_card *card, u32 *status, int retries)
+ {
+@@ -852,18 +857,22 @@ static int mmc_blk_cmd_error(struct request *req, const char *name, int error,
+ 			req->rq_disk->disk_name, "timed out", name, status);
+ 
+ 		/* If the status cmd initially failed, retry the r/w cmd */
+-		if (!status_valid)
++		if (!status_valid) {
++			pr_err("%s: status not valid, retrying timeout\n", req->rq_disk->disk_name);
+ 			return ERR_RETRY;
+-
++		}
+ 		/*
+ 		 * If it was a r/w cmd crc error, or illegal command
+ 		 * (eg, issued in wrong state) then retry - we should
+ 		 * have corrected the state problem above.
+ 		 */
+-		if (status & (R1_COM_CRC_ERROR | R1_ILLEGAL_COMMAND))
++		if (status & (R1_COM_CRC_ERROR | R1_ILLEGAL_COMMAND)) {
++			pr_err("%s: command error, retrying timeout\n", req->rq_disk->disk_name);
+ 			return ERR_RETRY;
++		}
+ 
+ 		/* Otherwise abort the command */
++		pr_err("%s: not retrying timeout\n", req->rq_disk->disk_name);
+ 		return ERR_ABORT;
+ 
+ 	default:
+@@ -1003,6 +1012,14 @@ static int mmc_blk_reset(struct mmc_blk_data *md, struct mmc_host *host,
+ 		return -EEXIST;
+ 
+ 	md->reset_done |= type;
++
++#if !defined(CONFIG_ARCH_HI3559) && !defined(CONFIG_ARCH_HI3556)
++	/*Step1: try to software reset*/
++	if (mmc_sw_reset(host) == 0)
++		return 0;
++#endif
++
++	/*Step2: try to hardware reset*/
+ 	err = mmc_hw_reset(host);
+ 	/* Ensure we switch back to the correct partition */
+ 	if (err != -EOPNOTSUPP) {
+@@ -1195,13 +1212,11 @@ static inline void mmc_apply_rel_rw(struct mmc_blk_request *brq,
+ 	 R1_CC_ERROR |		/* Card controller error */		\
+ 	 R1_ERROR)		/* General/unknown error */
+ 
+-static int mmc_blk_err_check(struct mmc_card *card,
+-			     struct mmc_async_req *areq)
++int mmc_blk_err_check(struct mmc_card *card,
++			     struct mmc_req_mrq *req_mrq)
+ {
+-	struct mmc_queue_req *mq_mrq = container_of(areq, struct mmc_queue_req,
+-						    mmc_active);
+-	struct mmc_blk_request *brq = &mq_mrq->brq;
+-	struct request *req = mq_mrq->req;
++	struct mmc_blk_request *brq = &req_mrq->brq;
++	struct request *req = req_mrq->req;
+ 	int ecc_err = 0, gen_err = 0;
+ 
+ 	/*
+@@ -1287,19 +1302,13 @@ static int mmc_blk_err_check(struct mmc_card *card,
+ 	if (!brq->data.bytes_xfered)
+ 		return MMC_BLK_RETRY;
+ 
+-	if (mmc_packed_cmd(mq_mrq->cmd_type)) {
+-		if (unlikely(brq->data.blocks << 9 != brq->data.bytes_xfered))
+-			return MMC_BLK_PARTIAL;
+-		else
+-			return MMC_BLK_SUCCESS;
+-	}
+-
+ 	if (blk_rq_bytes(req) != brq->data.bytes_xfered)
+ 		return MMC_BLK_PARTIAL;
+ 
+ 	return MMC_BLK_SUCCESS;
+ }
+ 
++#if 0
+ static int mmc_blk_packed_err_check(struct mmc_card *card,
+ 				    struct mmc_async_req *areq)
+ {
+@@ -2021,61 +2030,470 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
+ 
+ 	return 0;
+ }
++#endif
++
++static int mmc_send_reqs(struct mmc_req_mrq *req_mrq,
++			       struct mmc_card *card,
++			       struct mmc_queue *mq)
++{
++	u32 readcmd, writecmd;
++	struct mmc_queue_req *mqrq = mq->mqrq_cur;
++	struct mmc_blk_request *brq;
++	struct request *req = req_mrq->req;
++	struct mmc_blk_data *md = mq->data;
++	bool do_data_tag;
++	int err = 0;
++
++	/*
++	 * Reliable writes are used to implement Forced Unit Access and
++	 * REQ_META accesses, and are supported only on MMCs.
++	 *
++	 * XXX: this really needs a good explanation of why REQ_META
++	 * is treated special.
++	 */
++	bool do_rel_wr = ((req->cmd_flags & REQ_FUA) ||
++			  (req->cmd_flags & REQ_META)) &&
++		(rq_data_dir(req) == WRITE) &&
++		(md->flags & MMC_BLK_REL_WR);
++
++	/*
++	 * prepare for each request
++	 */
++	mqrq->req = req;
++	brq = &req_mrq->brq;
++
++	brq->mrq.cmd = &brq->cmd;
++	brq->mrq.data = &brq->data;
++	brq->cmd.data = &brq->data;
++	brq->cmd.mrq = &brq->mrq;
++
++	brq->cmd.arg = blk_rq_pos(req);
++	if (!mmc_card_blockaddr(card))
++		brq->cmd.arg <<= 9;
++	brq->cmd.flags |= MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
++	brq->cmd.flags |= MMC_CMD_TYPE_RW;
++	brq->data.blksz = 512;
++	brq->stop.opcode = MMC_STOP_TRANSMISSION;
++	brq->stop.arg = 0;
++	brq->data.blocks = blk_rq_sectors(req);
++
++	/*
++	 * The block layer doesn't support all sector count
++	 * restrictions, so we need to be prepared for too big
++	 * requests.
++	 */
++	if (brq->data.blocks > card->host->max_blk_count)
++		brq->data.blocks = card->host->max_blk_count;
++
++	if (brq->data.blocks > 1) {
++		/*
++		 * Some controllers have HW issues while operating
++		 * in multiple I/O mode
++		 */
++		if (card->host->ops->multi_io_quirk)
++			brq->data.blocks = card->host->ops->multi_io_quirk(card,
++						(rq_data_dir(req) == READ) ?
++						MMC_DATA_READ : MMC_DATA_WRITE,
++						brq->data.blocks);
++	}
++
++	if (brq->data.blocks > 1 || do_rel_wr) {
++		/* SPI multiblock writes terminate using a special
++		 * token, not a STOP_TRANSMISSION request.
++		 */
++		if (!mmc_host_is_spi(card->host) ||
++		    rq_data_dir(req) == READ)
++			brq->mrq.stop = &brq->stop;
++		readcmd = MMC_READ_MULTIPLE_BLOCK;
++		writecmd = MMC_WRITE_MULTIPLE_BLOCK;
++	} else {
++		brq->mrq.stop = NULL;
++		readcmd = MMC_READ_SINGLE_BLOCK;
++		writecmd = MMC_WRITE_BLOCK;
++	}
++	if (rq_data_dir(req) == READ) {
++		brq->cmd.opcode = readcmd;
++		brq->data.flags |= MMC_DATA_READ;
++		if (brq->mrq.stop)
++			brq->stop.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 |
++					MMC_CMD_AC;
++	} else {
++		brq->cmd.opcode = writecmd;
++		brq->data.flags |= MMC_DATA_WRITE;
++		if (brq->mrq.stop)
++			brq->stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B |
++					MMC_CMD_AC;
++	}
++
++	if (do_rel_wr)
++		mmc_apply_rel_rw(brq, card, req);
++	/*
++	 * When 4KB native sector is enabled, only 8 blocks
++	 * multiple read or write is allowed
++	 */
++	if ((brq->data.blocks & 0x07) &&
++			(card->ext_csd.data_sector_size == 4096)) {
++		pr_err("%s: Transfer size is not 4KB sector size aligned\n",
++				req->rq_disk->disk_name);
++		err = -EMEDIUMTYPE;
++		goto prep_err;
++	}
++
++	/*
++	 * Data tag is used only during writing meta data to speed
++	 * up write and any subsequent read of this meta data
++	 */
++	do_data_tag = (card->ext_csd.data_tag_unit_size) &&
++		(req->cmd_flags & REQ_META) &&
++		(rq_data_dir(req) == WRITE) &&
++		((brq->data.blocks * brq->data.blksz) >=
++		 card->ext_csd.data_tag_unit_size);
++
++	/*
++	 * Pre-defined multi-block transfers are preferable to
++	 * open ended-ones (and necessary for reliable writes).
++	 * However, it is not sufficient to just send CMD23,
++	 * and avoid the final CMD12, as on an error condition
++	 * CMD12 (stop) needs to be sent anyway. This, coupled
++	 * with Auto-CMD23 enhancements provided by some
++	 * hosts, means that the complexity of dealing
++	 * with this is best left to the host. If CMD23 is
++	 * supported by card and host, we'll fill sbc in and let
++	 * the host deal with handling it correctly. This means
++	 * that for hosts that don't expose MMC_CAP_CMD23, no
++	 * change of behavior will be observed.
++	 *
++	 * N.B: Some MMC cards experience perf degradation.
++	 * We'll avoid using CMD23-bounded multiblock writes for
++	 * these, while retaining features like reliable writes.
++	 */
++	if ((md->flags & MMC_BLK_CMD23) && mmc_op_multi(brq->cmd.opcode) &&
++	    (do_rel_wr || !(card->quirks & MMC_QUIRK_BLK_NO_CMD23) ||
++	     do_data_tag)) {
++		brq->sbc.opcode = MMC_SET_BLOCK_COUNT;
++		brq->sbc.arg = brq->data.blocks |
++			(do_rel_wr ? (1 << 31) : 0) |
++			(do_data_tag ? (1 << 29) : 0);
++		brq->sbc.flags = MMC_RSP_R1 | MMC_CMD_AC;
++		brq->mrq.sbc = &brq->sbc;
++	}
++
++	mmc_set_data_timeout(&brq->data, card);
++
++	mqrq->sg = req_mrq->sg;
++	brq->data.sg = req_mrq->sg;
++	brq->data.sg_len = mmc_queue_map_sg(mq, mqrq);
++
++	/*
++	 * Adjust the sg list so it is the same size as the
++	 * request.
++	 */
++	if (brq->data.blocks != blk_rq_sectors(req)) {
++		int i, data_size = brq->data.blocks << 9;
++		struct scatterlist *sg;
++
++		for_each_sg(brq->data.sg, sg, brq->data.sg_len, i) {
++			data_size -= sg->length;
++			if (data_size <= 0) {
++				sg->length += data_size;
++				i++;
++				break;
++			}
++		}
++		brq->data.sg_len = i;
++	}
++
++	err = __mmc_start_data_req(card->host, &brq->mrq);
++
++	if (err) {
++		mmc_trace(3, "send mrq fail!\n");
++		goto prep_err;
++	} else {
++		req_mrq->wr_pos = brq->mrq.wr_pos;
++		mmc_trace(3, "write pos is %d", req_mrq->wr_pos);
++		return 0;
++	}
++prep_err:
++	return err;
++}
++
++/*
++ * mmc_wait_reqs_done() - wait multi packet intr to wake up
++ * @host: MMC host to prepare the command.
++ * Blocks MMC context till host controller will ack intr of multi-pactet
++ */
++void mmc_wait_reqs_done(struct mmc_host *host)
++{
++	struct mmc_context_info *context_info = &host->context_info;
++	unsigned long flags;
++
++	spin_lock_irqsave(&context_info->lock, flags);
++	context_info->is_waiting_last_req = true;
++	spin_unlock_irqrestore(&context_info->lock, flags);
++
++	mmc_trace(3, "wait intr...");
++	wait_event_interruptible(context_info->wait,
++			(context_info->is_done_rcv ||
++			 context_info->is_new_req));
++	mmc_trace(3, "intr wake up");
++
++	spin_lock_irqsave(&context_info->lock, flags);
++	context_info->is_waiting_last_req = false;
++	context_info->is_done_rcv = false;
++	context_info->is_new_req = false;
++	spin_unlock_irqrestore(&context_info->lock, flags);
++}
++
++#define MMC_CMD_SUCCESS		(0)
++#define MMC_CMD_ABORT		(1)
++/*
++ * mmc_req_retrieve() - retrieve all of request that has completed
++ * @mq: request queue that has attached to card.
++ * @host: MMC host to prepare the command.
++ * @drain: retrieve all request if true.
++ * Blocks MMC context till host controller will ack end of data request
++ * execution or new request notification arrives from the block layer.
++ * Handles command retries.
++ *
++ * Returns enum mmc_blk_status of checking errors.
++ */
++int mmc_blk_retrieve_reqs(struct mmc_queue *mq,
++		struct mmc_host *host, bool drain)
++{
++	struct mmc_blk_data *md = mq->data;
++	struct mmc_card *card = md->queue.card;
++	struct request *req;
++	struct mmc_blk_request *brq;
++	struct mmc_req_mrq *req_mrq;
++	struct mmc_xmited *xmited = &mq->xmited;
++	enum mmc_blk_status status = MMC_BLK_SUCCESS;
++	bool res = false;
++	int rd_pos, type;
++	unsigned int cmd_flags;
++
++	while (!mmc_xmited_empty(xmited)) {
++		rd_pos = host->ops->get_rd(host);
++		req_mrq = xmited->rq_buf[xmited->start];
++		mmc_trace(3, "remain %d, cmd ptr %d, read ptr %d",
++				xmited->used, req_mrq->wr_pos, rd_pos);
++		mmc_trace(3, "status = %d", host->status);
++		if (!host->status && (req_mrq->wr_pos == rd_pos)) {
++			mmc_trace(3, "no new request complete");
++			if (drain) {
++				if (!(req_mrq->brq.cmd.flags & MMC_CMD_NON_BLOCKING))
++					mmc_wait_reqs_done(host);
++				continue;
++			} else {
++				break;
++			}
++		}
++		req = req_mrq->req;
++		brq = &req_mrq->brq;
++
++		if (brq->cmd.resp[0] & CMD_ERRORS || brq->cmd.error || brq->data.error) {
++			pr_info("%s: req failed (CMD%u) cmd %d data %d cmd resp:%x\n",
++					mmc_hostname(host), brq->cmd.opcode,
++					brq->cmd.error, brq->data.error, brq->cmd.resp[0]);
++			status = xmited->err_check(card, req_mrq);
++		} else {
++			host->ops->post_req(host, &brq->mrq, 0);
++			res = blk_end_request(req, 0, brq->data.bytes_xfered);
++			mmc_put_rbuf(xmited, req_mrq);
++			if (res) {
++				pr_info("%s BUG d_totel %d d_xfer %d\n",
++						__func__, blk_rq_bytes(req),
++						brq->data.bytes_xfered);
++				blk_requeue_request(mq->queue, req);
++			}
++		}
++
++		type = rq_data_dir(req) == READ ?
++			MMC_BLK_READ : MMC_BLK_WRITE;
++		switch (status) {
++		case MMC_BLK_SUCCESS:
++		case MMC_BLK_PARTIAL:
++			/*
++			 * A block was successfully transferred.
++			*/
++			mmc_blk_reset_success(md, type);
++			continue;
++		case MMC_BLK_CMD_ERR:
++			if (!mmc_blk_reset(md, card->host, type))
++				goto cmd_restart;
++			goto cmd_abort;
++		case MMC_BLK_RETRY:
++
++			/* Fall through */
++		case MMC_BLK_ABORT:
++			if (!mmc_blk_reset(md, card->host, type) && req->retries++ < 5)
++				goto cmd_restart;
++			goto cmd_abort;
++		case MMC_BLK_ECC_ERR:
++		case MMC_BLK_DATA_ERR: {
++			int error;
++
++			error = mmc_blk_reset(md, card->host, type);
++			if (!error)
++				goto  cmd_restart;
++			if (error == -ENODEV)
++				goto cmd_abort;
++		}
++		/* Fall through */
++		case MMC_BLK_NOMEDIUM:
++			goto cmd_abort;
++		default:
++			pr_err("%s: Unhandled return value (%d)",
++			req->rq_disk->disk_name, status);
++			goto cmd_abort;
++		}
++	}
++	return MMC_CMD_SUCCESS;
++
++cmd_abort:
++	pr_err("%s: error, req abort\n", mmc_hostname(card->host));
++
++	cmd_flags = mmc_card_removed(card) ? REQ_QUIET : 0;
++	mmc_xmited_abort(xmited, cmd_flags);
++	mmc_xmited_reset(xmited);
++	card->host->status = MMC_HOST_OK;
++	return MMC_CMD_ABORT;
++
++cmd_restart:
++	/*
++	 * putback all incomplete request.
++	 * when error fixed, restart
++	 */
++	pr_info("%s: error fixed, restart...\n", mmc_hostname(card->host));
++	mmc_xmited_requeue(mq->queue, xmited);
++	mmc_xmited_reset(xmited);
++	card->host->status = MMC_HOST_OK;
++	return MMC_CMD_SUCCESS;
++}
++
++/**
++ * mmc_blk_xmit_reqs - fetch request from queue then transmit it.
++ * @mq: mmc queue
++ * @card: mmc card to attach this queue
++ * @req: new req that should xmited
++ * return: the count of request send this time.
++ *
++ * transmit the request till can't fetch
++ */
++static int mmc_blk_xmit_reqs(struct mmc_queue *mq,
++		struct mmc_card *card, struct request *req)
++{
++	struct request *cur;
++	struct mmc_host *host = card->host;
++	struct mmc_req_mrq *req_mrq = NULL;
++	struct request_queue *q = mq->queue;
++	struct mmc_xmited *xmited = &mq->xmited;
++#if !defined(CONFIG_ARCH_HI3559) && !defined(CONFIG_ARCH_HI3556)
++	u32 intr_step = 4;
++#endif
++	/*u32 max_send_reqs = 16;*/
++	u32 reqs = 0;
++	int ret = 0;
++	unsigned int cmd_flags;
++
++	do {
++		cur = req;
++		if (cur && mmc_xmited_full(xmited)) {
++			blk_requeue_request(q, cur);
++			return reqs;
++		}
++		/* In case sepecial request(discard, flush), we must be sure
++		 * all of request has finished.
++		 */
++		cmd_flags = cur ? cur->cmd_flags : 0;
++		if (cmd_flags & REQ_DISCARD) {
++			/* complete ongoing async transfer
++			 * before issuing discard
++			 */
++			if (!mmc_xmited_empty(xmited))
++				mmc_blk_retrieve_reqs(mq, host, true);
++			if (cur->cmd_flags & REQ_SECURE)
++				ret = mmc_blk_issue_secdiscard_rq(mq, cur);
++			else
++				ret = mmc_blk_issue_discard_rq(mq, cur);
++		} else if (cmd_flags & REQ_FLUSH) {
++			/* complete ongoing async transfer
++			 * before issuing flush
++			 */
++			if (!mmc_xmited_empty(xmited))
++				mmc_blk_retrieve_reqs(mq, host, true);
++			ret = mmc_blk_issue_flush(mq, cur);
++		} else if (cur) {
++			req_mrq = mmc_get_rbuf(xmited);
++			memset(&req_mrq->brq, 0,
++					sizeof(struct mmc_blk_request));
++			req_mrq->req = cur;
++			reqs++;
++		}
++
++		/* fetch next request */
++		spin_lock_irq(q->queue_lock);
++		req = blk_fetch_request(q);
++		spin_unlock_irq(q->queue_lock);
++
++		if (req_mrq) {
++#if !defined(CONFIG_ARCH_HI3559) && !defined(CONFIG_ARCH_HI3556)
++			if (((reqs % intr_step) != 1) && req)
++				req_mrq->brq.cmd.flags |= MMC_CMD_NON_BLOCKING;
++#endif
++
++			ret = mmc_send_reqs(req_mrq, card, mq);
++			req_mrq = NULL;
++			if (ret)
++				goto cmd_abort;
++		}
++	} while (req);
++
++	return reqs;
++
++cmd_abort:
++	pr_err("%s: send cmd fail. abort...\n",
++			mmc_hostname(card->host));
++	cmd_flags = mmc_card_removed(card) ? REQ_QUIET : 0;
++	mmc_xmited_abort(xmited, cmd_flags);
++	mmc_xmited_reset(xmited);
++	if (req) {
++		req->cmd_flags |= cmd_flags;
++		blk_end_request_all(req, -EIO);
++	}
++	return 0;
++}
+ 
+ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
+ {
+-	int ret;
++	int ret, reqs;
+ 	struct mmc_blk_data *md = mq->data;
+ 	struct mmc_card *card = md->queue.card;
+ 	struct mmc_host *host = card->host;
+-	unsigned long flags;
+-	unsigned int cmd_flags = req ? req->cmd_flags : 0;
++	struct mmc_xmited *xmited = &mq->xmited;
+ 
+-	if (req && !mq->mqrq_prev->req)
++	set_current_state(TASK_RUNNING);
++#ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME
++	if (mmc_bus_needs_resume(card->host))
++		mmc_resume_bus(card->host);
++#endif
++
++	if (mmc_xmited_empty(xmited))
+ 		/* claim host only for the first request */
+ 		mmc_get_card(card);
+ 
+ 	ret = mmc_blk_part_switch(card, md);
+ 	if (ret) {
+-		if (req) {
+-			blk_end_request_all(req, -EIO);
+-		}
+-		ret = 0;
+ 		goto out;
+ 	}
+ 
+-	mq->flags &= ~MMC_QUEUE_NEW_REQUEST;
+-	if (cmd_flags & REQ_DISCARD) {
+-		/* complete ongoing async transfer before issuing discard */
+-		if (card->host->areq)
+-			mmc_blk_issue_rw_rq(mq, NULL);
+-		if (req->cmd_flags & REQ_SECURE)
+-			ret = mmc_blk_issue_secdiscard_rq(mq, req);
+-		else
+-			ret = mmc_blk_issue_discard_rq(mq, req);
+-	} else if (cmd_flags & REQ_FLUSH) {
+-		/* complete ongoing async transfer before issuing flush */
+-		if (card->host->areq)
+-			mmc_blk_issue_rw_rq(mq, NULL);
+-		ret = mmc_blk_issue_flush(mq, req);
+-	} else {
+-		if (!req && host->areq) {
+-			spin_lock_irqsave(&host->context_info.lock, flags);
+-			host->context_info.is_waiting_last_req = true;
+-			spin_unlock_irqrestore(&host->context_info.lock, flags);
+-		}
+-		ret = mmc_blk_issue_rw_rq(mq, req);
+-	}
++	mmc_blk_retrieve_reqs(mq, card->host, false);
+ 
++	reqs = mmc_blk_xmit_reqs(mq, card, req);
++	if (!reqs && !mmc_xmited_empty(xmited))
++		mmc_wait_reqs_done(host);
+ out:
+-	if ((!req && !(mq->flags & MMC_QUEUE_NEW_REQUEST)) ||
+-	     (cmd_flags & MMC_REQ_SPECIAL_MASK))
+-		/*
+-		 * Release host when there are no more requests
+-		 * and after special request(discard, flush) is done.
+-		 * In case sepecial request, there is no reentry to
+-		 * the 'mmc_blk_issue_rq' with 'mqrq_prev->req'.
+-		 */
++	if (mmc_xmited_empty(xmited))
++		/* Release host when there are no more requests */
+ 		mmc_put_card(card);
+ 	return ret;
+ }
+@@ -2152,6 +2570,7 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
+ 	md->disk->queue = md->queue.queue;
+ 	md->disk->driverfs_dev = parent;
+ 	set_disk_ro(md->disk, md->read_only || default_ro);
++	md->disk->flags = GENHD_FL_EXT_DEVT;
+ 	if (area_type & (MMC_BLK_DATA_AREA_RPMB | MMC_BLK_DATA_AREA_BOOT))
+ 		md->disk->flags |= GENHD_FL_NO_PART_SCAN;
+ 
+@@ -2193,14 +2612,6 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
+ 		blk_queue_flush(md->queue.queue, REQ_FLUSH | REQ_FUA);
+ 	}
+ 
+-	if (mmc_card_mmc(card) &&
+-	    (area_type == MMC_BLK_DATA_AREA_MAIN) &&
+-	    (md->flags & MMC_BLK_CMD23) &&
+-	    card->ext_csd.packed_event_en) {
+-		if (!mmc_packed_init(&md->queue, card))
+-			md->flags |= MMC_BLK_PACKED_CMD;
+-	}
+-
+ 	return md;
+ 
+  err_putdisk:
+@@ -2302,8 +2713,6 @@ static void mmc_blk_remove_req(struct mmc_blk_data *md)
+ 		 */
+ 		card = md->queue.card;
+ 		mmc_cleanup_queue(&md->queue);
+-		if (md->flags & MMC_BLK_PACKED_CMD)
+-			mmc_packed_clean(&md->queue);
+ 		if (md->disk->flags & GENHD_FL_UP) {
+ 			device_remove_file(disk_to_dev(md->disk), &md->force_ro);
+ 			if ((md->area_type & MMC_BLK_DATA_AREA_BOOT) &&
+@@ -2469,6 +2878,9 @@ static int mmc_blk_probe(struct mmc_card *card)
+ 
+ 	mmc_set_drvdata(card, md);
+ 
++#ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME
++	mmc_set_bus_resume_policy(card->host, 1);
++#endif
+ 	if (mmc_add_disk(md))
+ 		goto out;
+ 
+@@ -2511,6 +2923,9 @@ static void mmc_blk_remove(struct mmc_card *card)
+ 	pm_runtime_put_noidle(&card->dev);
+ 	mmc_blk_remove_req(md);
+ 	mmc_set_drvdata(card, NULL);
++#ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME
++	mmc_set_bus_resume_policy(card->host, 0);
++#endif
+ }
+ 
+ static int _mmc_blk_suspend(struct mmc_card *card)
+diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
+index 7a41a22..1003139 100644
+--- a/drivers/mmc/card/queue.c
++++ b/drivers/mmc/card/queue.c
+@@ -23,6 +23,9 @@
+ 
+ #define MMC_QUEUE_BOUNCESZ	65536
+ 
++extern int mmc_blk_err_check(struct mmc_card *card,
++		struct mmc_req_mrq *req_mrq);
++
+ /*
+  * Prepare a MMC request. This just filters out odd stuff.
+  */
+@@ -50,14 +53,13 @@ static int mmc_queue_thread(void *d)
+ {
+ 	struct mmc_queue *mq = d;
+ 	struct request_queue *q = mq->queue;
++	struct mmc_xmited *xmited = &mq->xmited;
+ 
+ 	current->flags |= PF_MEMALLOC;
+ 
+ 	down(&mq->thread_sem);
+ 	do {
+ 		struct request *req = NULL;
+-		struct mmc_queue_req *tmp;
+-		unsigned int cmd_flags = 0;
+ 
+ 		spin_lock_irq(q->queue_lock);
+ 		set_current_state(TASK_INTERRUPTIBLE);
+@@ -65,30 +67,8 @@ static int mmc_queue_thread(void *d)
+ 		mq->mqrq_cur->req = req;
+ 		spin_unlock_irq(q->queue_lock);
+ 
+-		if (req || mq->mqrq_prev->req) {
+-			set_current_state(TASK_RUNNING);
+-			cmd_flags = req ? req->cmd_flags : 0;
++		if (req || (!mmc_xmited_empty(xmited))) {
+ 			mq->issue_fn(mq, req);
+-			if (mq->flags & MMC_QUEUE_NEW_REQUEST) {
+-				mq->flags &= ~MMC_QUEUE_NEW_REQUEST;
+-				continue; /* fetch again */
+-			}
+-
+-			/*
+-			 * Current request becomes previous request
+-			 * and vice versa.
+-			 * In case of special requests, current request
+-			 * has been finished. Do not assign it to previous
+-			 * request.
+-			 */
+-			if (cmd_flags & MMC_REQ_SPECIAL_MASK)
+-				mq->mqrq_cur->req = NULL;
+-
+-			mq->mqrq_prev->brq.mrq.data = NULL;
+-			mq->mqrq_prev->req = NULL;
+-			tmp = mq->mqrq_prev;
+-			mq->mqrq_prev = mq->mqrq_cur;
+-			mq->mqrq_cur = tmp;
+ 		} else {
+ 			if (kthread_should_stop()) {
+ 				set_current_state(TASK_RUNNING);
+@@ -126,7 +106,7 @@ static void mmc_request_fn(struct request_queue *q)
+ 	}
+ 
+ 	cntx = &mq->card->host->context_info;
+-	if (!mq->mqrq_cur->req && mq->mqrq_prev->req) {
++	if (!mmc_xmited_empty(&mq->xmited)) {
+ 		/*
+ 		 * New MMC request arrived when MMC thread may be
+ 		 * blocked on the previous request to be complete
+@@ -138,7 +118,7 @@ static void mmc_request_fn(struct request_queue *q)
+ 			wake_up_interruptible(&cntx->wait);
+ 		}
+ 		spin_unlock_irqrestore(&cntx->lock, flags);
+-	} else if (!mq->mqrq_cur->req && !mq->mqrq_prev->req)
++	} else
+ 		wake_up_process(mq->thread);
+ }
+ 
+@@ -178,6 +158,14 @@ static void mmc_queue_setup_discard(struct request_queue *q,
+ 		queue_flag_set_unlocked(QUEUE_FLAG_SECDISCARD, q);
+ }
+ 
++void mmc_xmited_reset(struct mmc_xmited *xmited)
++{
++	xmited->start = 0;
++	xmited->end = 0;
++	xmited->used = 0;
++	xmited->capacity = MMC_MAX_REQS_SEND_ONCE;
++}
++
+ /**
+  * mmc_init_queue - initialise a queue structure.
+  * @mq: mmc queue
+@@ -191,10 +179,10 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card,
+ 		   spinlock_t *lock, const char *subname)
+ {
+ 	struct mmc_host *host = card->host;
++	struct mmc_xmited *xmited = &mq->xmited;
+ 	u64 limit = BLK_BOUNCE_HIGH;
+-	int ret;
+-	struct mmc_queue_req *mqrq_cur = &mq->mqrq[0];
+-	struct mmc_queue_req *mqrq_prev = &mq->mqrq[1];
++	int ret, i;
++	struct mmc_queue_req *mqrq_cur = &mq->mqrq;
+ 
+ 	if (mmc_dev(host)->dma_mask && *mmc_dev(host)->dma_mask)
+ 		limit = (u64)dma_max_pfn(mmc_dev(host)) << PAGE_SHIFT;
+@@ -205,9 +193,11 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card,
+ 		return -ENOMEM;
+ 
+ 	mq->mqrq_cur = mqrq_cur;
+-	mq->mqrq_prev = mqrq_prev;
+ 	mq->queue->queuedata = mq;
+ 
++	mmc_xmited_reset(xmited);
++	xmited->err_check = mmc_blk_err_check;
++
+ 	blk_queue_prep_rq(mq->queue, mmc_prep_request);
+ 	queue_flag_set_unlocked(QUEUE_FLAG_NONROT, mq->queue);
+ 	queue_flag_clear_unlocked(QUEUE_FLAG_ADD_RANDOM, mq->queue);
+@@ -233,57 +223,46 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card,
+ 				pr_warn("%s: unable to allocate bounce cur buffer\n",
+ 					mmc_card_name(card));
+ 			}
+-			mqrq_prev->bounce_buf = kmalloc(bouncesz, GFP_KERNEL);
+-			if (!mqrq_prev->bounce_buf) {
+-				pr_warn("%s: unable to allocate bounce prev buffer\n",
+-					mmc_card_name(card));
+-				kfree(mqrq_cur->bounce_buf);
+-				mqrq_cur->bounce_buf = NULL;
+-			}
+ 		}
+ 
+-		if (mqrq_cur->bounce_buf && mqrq_prev->bounce_buf) {
++		if (mqrq_cur->bounce_buf) {
+ 			blk_queue_bounce_limit(mq->queue, BLK_BOUNCE_ANY);
+ 			blk_queue_max_hw_sectors(mq->queue, bouncesz / 512);
+ 			blk_queue_max_segments(mq->queue, bouncesz / 512);
+ 			blk_queue_max_segment_size(mq->queue, bouncesz);
+ 
+-			mqrq_cur->sg = mmc_alloc_sg(1, &ret);
+-			if (ret)
+-				goto cleanup_queue;
+-
+ 			mqrq_cur->bounce_sg =
+ 				mmc_alloc_sg(bouncesz / 512, &ret);
+ 			if (ret)
+ 				goto cleanup_queue;
+-
+-			mqrq_prev->sg = mmc_alloc_sg(1, &ret);
+-			if (ret)
+-				goto cleanup_queue;
+-
+-			mqrq_prev->bounce_sg =
+-				mmc_alloc_sg(bouncesz / 512, &ret);
+-			if (ret)
+-				goto cleanup_queue;
+ 		}
+ 	}
+ #endif
+ 
+-	if (!mqrq_cur->bounce_buf && !mqrq_prev->bounce_buf) {
++	if (!mqrq_cur->bounce_buf) {
+ 		blk_queue_bounce_limit(mq->queue, limit);
+ 		blk_queue_max_hw_sectors(mq->queue,
+ 			min(host->max_blk_count, host->max_req_size / 512));
+ 		blk_queue_max_segments(mq->queue, host->max_segs);
+ 		blk_queue_max_segment_size(mq->queue, host->max_seg_size);
+ 
+-		mqrq_cur->sg = mmc_alloc_sg(host->max_segs, &ret);
+-		if (ret)
+-			goto cleanup_queue;
+-
++		memset(xmited->sg_buf, 0, sizeof(struct scatterlist *)
++				* MMC_MAX_REQS_SEND_ONCE);
++		memset(xmited->rq_buf, 0, sizeof(struct mmc_req_mrq *)
++				* MMC_MAX_REQS_SEND_ONCE);
+ 
+-		mqrq_prev->sg = mmc_alloc_sg(host->max_segs, &ret);
+-		if (ret)
+-			goto cleanup_queue;
++		for (i = 0; i < MMC_MAX_REQS_SEND_ONCE; i++) {
++			xmited->sg_buf[i] = mmc_alloc_sg(host->max_segs, &ret);
++			if (ret)
++				goto cleanup_buf;
++			xmited->rq_buf[i] = (struct mmc_req_mrq *)
++				kmalloc(sizeof(struct mmc_req_mrq), GFP_KERNEL);
++			if (!xmited->rq_buf[i]) {
++				kfree(xmited->sg_buf[i]);
++				goto cleanup_buf;
++			}
++			xmited->rq_buf[i]->sg = xmited->sg_buf[i];
++		}
+ 	}
+ 
+ 	sema_init(&mq->thread_sem, 1);
+@@ -297,23 +276,25 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card,
+ 	}
+ 
+ 	return 0;
+- free_bounce_sg:
++free_bounce_sg:
+ 	kfree(mqrq_cur->bounce_sg);
+ 	mqrq_cur->bounce_sg = NULL;
+-	kfree(mqrq_prev->bounce_sg);
+-	mqrq_prev->bounce_sg = NULL;
+ 
+- cleanup_queue:
+-	kfree(mqrq_cur->sg);
++cleanup_buf:
++	if (!mqrq_cur->bounce_buf) {
++		for (i--; i >= 0; i--) {
++			kfree(xmited->sg_buf[i]);
++			xmited->sg_buf[i] = NULL;
++			kfree(xmited->rq_buf[i]);
++			xmited->rq_buf[i] = NULL;
++		}
++	}
++
++cleanup_queue:
+ 	mqrq_cur->sg = NULL;
+ 	kfree(mqrq_cur->bounce_buf);
+ 	mqrq_cur->bounce_buf = NULL;
+ 
+-	kfree(mqrq_prev->sg);
+-	mqrq_prev->sg = NULL;
+-	kfree(mqrq_prev->bounce_buf);
+-	mqrq_prev->bounce_buf = NULL;
+-
+ 	blk_cleanup_queue(mq->queue);
+ 	return ret;
+ }
+@@ -321,9 +302,10 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card,
+ void mmc_cleanup_queue(struct mmc_queue *mq)
+ {
+ 	struct request_queue *q = mq->queue;
++	struct mmc_xmited *xmited = &mq->xmited;
+ 	unsigned long flags;
++	int i;
+ 	struct mmc_queue_req *mqrq_cur = mq->mqrq_cur;
+-	struct mmc_queue_req *mqrq_prev = mq->mqrq_prev;
+ 
+ 	/* Make sure the queue isn't suspended, as that will deadlock */
+ 	mmc_queue_resume(mq);
+@@ -340,25 +322,22 @@ void mmc_cleanup_queue(struct mmc_queue *mq)
+ 	kfree(mqrq_cur->bounce_sg);
+ 	mqrq_cur->bounce_sg = NULL;
+ 
+-	kfree(mqrq_cur->sg);
+ 	mqrq_cur->sg = NULL;
+ 
+ 	kfree(mqrq_cur->bounce_buf);
+ 	mqrq_cur->bounce_buf = NULL;
+ 
+-	kfree(mqrq_prev->bounce_sg);
+-	mqrq_prev->bounce_sg = NULL;
+-
+-	kfree(mqrq_prev->sg);
+-	mqrq_prev->sg = NULL;
+-
+-	kfree(mqrq_prev->bounce_buf);
+-	mqrq_prev->bounce_buf = NULL;
+-
++	for (i = 0; i < MMC_MAX_REQS_SEND_ONCE; i++) {
++		kfree(xmited->sg_buf[i]);
++		xmited->sg_buf[i] = NULL;
++		kfree(xmited->rq_buf[i]);
++		xmited->rq_buf[i] = NULL;
++	}
+ 	mq->card = NULL;
+ }
+ EXPORT_SYMBOL(mmc_cleanup_queue);
+ 
++#if 0
+ int mmc_packed_init(struct mmc_queue *mq, struct mmc_card *card)
+ {
+ 	struct mmc_queue_req *mqrq_cur = &mq->mqrq[0];
+@@ -401,6 +380,7 @@ void mmc_packed_clean(struct mmc_queue *mq)
+ 	kfree(mqrq_prev->packed);
+ 	mqrq_prev->packed = NULL;
+ }
++#endif
+ 
+ /**
+  * mmc_queue_suspend - suspend a MMC request queue
+@@ -446,6 +426,7 @@ void mmc_queue_resume(struct mmc_queue *mq)
+ 	}
+ }
+ 
++#if 0
+ static unsigned int mmc_queue_packed_map_sg(struct mmc_queue *mq,
+ 					    struct mmc_packed *packed,
+ 					    struct scatterlist *sg,
+@@ -480,6 +461,7 @@ static unsigned int mmc_queue_packed_map_sg(struct mmc_queue *mq,
+ 	sg_mark_end(sg + (sg_len - 1));
+ 	return sg_len;
+ }
++#endif
+ 
+ /*
+  * Prepare the sg list(s) to be handed of to the host driver
+@@ -495,20 +477,12 @@ unsigned int mmc_queue_map_sg(struct mmc_queue *mq, struct mmc_queue_req *mqrq)
+ 	cmd_type = mqrq->cmd_type;
+ 
+ 	if (!mqrq->bounce_buf) {
+-		if (mmc_packed_cmd(cmd_type))
+-			return mmc_queue_packed_map_sg(mq, mqrq->packed,
+-						       mqrq->sg, cmd_type);
+-		else
+ 			return blk_rq_map_sg(mq->queue, mqrq->req, mqrq->sg);
+ 	}
+ 
+ 	BUG_ON(!mqrq->bounce_sg);
+ 
+-	if (mmc_packed_cmd(cmd_type))
+-		sg_len = mmc_queue_packed_map_sg(mq, mqrq->packed,
+-						 mqrq->bounce_sg, cmd_type);
+-	else
+-		sg_len = blk_rq_map_sg(mq->queue, mqrq->req, mqrq->bounce_sg);
++	sg_len = blk_rq_map_sg(mq->queue, mqrq->req, mqrq->bounce_sg);
+ 
+ 	mqrq->bounce_sg_len = sg_len;
+ 
+@@ -552,3 +526,69 @@ void mmc_queue_bounce_post(struct mmc_queue_req *mqrq)
+ 	sg_copy_from_buffer(mqrq->bounce_sg, mqrq->bounce_sg_len,
+ 		mqrq->bounce_buf, mqrq->sg[0].length);
+ }
++
++/**
++ * mmc_get_rbuf - get next idle mmc_req_mrq from buf pool.
++ * @xmited: mmc queue pool
++ */
++struct mmc_req_mrq *mmc_get_rbuf(struct mmc_xmited *xmited)
++{
++	struct mmc_req_mrq *req_mrq = NULL;
++
++	if (xmited->used == (xmited->capacity - 2)) {
++		req_mrq = NULL;
++	} else {
++		req_mrq = xmited->rq_buf[xmited->end];
++		xmited->end++;
++		xmited->end %= xmited->capacity;
++		xmited->used++;
++	}
++	return req_mrq;
++}
++
++/**
++ * mmc_put_rbuf - release an mmc_req_mrq to buf pool.
++ * @mq: mmc queue
++ * return 0 ok -1 failed 1 confuse
++ */
++int mmc_put_rbuf(struct mmc_xmited *xmited, struct mmc_req_mrq *req_mrq)
++{
++	int ret = 0;
++
++	if (xmited->used <= 0) {
++		ret = -1;
++	} else if (xmited->rq_buf[xmited->start] == req_mrq) {
++		xmited->start++;
++		xmited->start %= xmited->capacity;
++		xmited->used--;
++		ret = 0;
++	} else {
++		ret = 1;
++	}
++	return ret;
++}
++
++void mmc_xmited_abort(struct mmc_xmited *xmited, unsigned int flags)
++{
++	struct request *req;
++	struct mmc_req_mrq *req_mrq;
++
++	while (!mmc_xmited_empty(xmited)) {
++		req_mrq = xmited->rq_buf[xmited->start];
++		req = req_mrq->req;
++		req->cmd_flags |= flags;
++		blk_end_request_all(req_mrq->req, -EIO);
++		mmc_put_rbuf(xmited, req_mrq);
++	}
++}
++
++void mmc_xmited_requeue(struct request_queue *q, struct mmc_xmited *xmited)
++{
++	struct mmc_req_mrq *req_mrq;
++
++	while (!mmc_xmited_empty(xmited)) {
++		req_mrq = xmited->rq_buf[xmited->start];
++		blk_requeue_request(q, req_mrq->req);
++		mmc_put_rbuf(xmited, req_mrq);
++	}
++}
+diff --git a/drivers/mmc/card/queue.h b/drivers/mmc/card/queue.h
+index 99e6521..e40a65d 100644
+--- a/drivers/mmc/card/queue.h
++++ b/drivers/mmc/card/queue.h
+@@ -33,7 +33,7 @@ struct mmc_packed {
+ 
+ struct mmc_queue_req {
+ 	struct request		*req;
+-	struct mmc_blk_request	brq;
++	struct mmc_blk_request	*brq;
+ 	struct scatterlist	*sg;
+ 	char			*bounce_buf;
+ 	struct scatterlist	*bounce_sg;
+@@ -43,6 +43,29 @@ struct mmc_queue_req {
+ 	struct mmc_packed	*packed;
+ };
+ 
++#define MMC_REQ_FRESH	(0x1<<0)
++#define MMC_REQ_PREP    (0x1<<1)
++#define MMC_REQ_SEND	(0x1<<2)
++#define MMC_REQ_DONE	(0x1<<3)
++#define MMC_REQ_FAIL	(0x1<<4)
++struct mmc_req_mrq {
++	struct request *req;
++	struct mmc_blk_request brq;
++	struct scatterlist *sg;
++	u32 wr_pos;
++};
++
++#define MMC_MAX_REQS_SEND_ONCE	(32)
++struct mmc_xmited {
++	struct scatterlist	*sg_buf[MMC_MAX_REQS_SEND_ONCE];
++	struct mmc_req_mrq	*rq_buf[MMC_MAX_REQS_SEND_ONCE];
++	u32			capacity;
++	u32			used;
++	u32			start;
++	u32			end;
++	int		(*err_check)(struct mmc_card *, struct mmc_req_mrq *);
++};
++
+ struct mmc_queue {
+ 	struct mmc_card		*card;
+ 	struct task_struct	*thread;
+@@ -54,9 +77,9 @@ struct mmc_queue {
+ 	int			(*issue_fn)(struct mmc_queue *, struct request *);
+ 	void			*data;
+ 	struct request_queue	*queue;
+-	struct mmc_queue_req	mqrq[2];
++	struct mmc_queue_req	mqrq;
+ 	struct mmc_queue_req	*mqrq_cur;
+-	struct mmc_queue_req	*mqrq_prev;
++	struct mmc_xmited	xmited;
+ };
+ 
+ extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *, spinlock_t *,
+@@ -75,4 +98,14 @@ extern void mmc_packed_clean(struct mmc_queue *);
+ 
+ extern int mmc_access_rpmb(struct mmc_queue *);
+ 
++#define mmc_xmited_empty(x) (!((x)->used))
++#define mmc_xmited_full(x) ((x)->used >= ((x)->capacity-2))
++
++void mmc_xmited_reset(struct mmc_xmited *);
++
++struct mmc_req_mrq *mmc_get_rbuf(struct mmc_xmited *);
++int mmc_put_rbuf(struct mmc_xmited *, struct mmc_req_mrq *);
++
++void mmc_xmited_requeue(struct request_queue *, struct mmc_xmited *);
++void mmc_xmited_abort(struct mmc_xmited *, unsigned int);
+ #endif
+diff --git a/drivers/mmc/core/Kconfig b/drivers/mmc/core/Kconfig
+index 9ebee72..f771bc3 100644
+--- a/drivers/mmc/core/Kconfig
++++ b/drivers/mmc/core/Kconfig
+@@ -11,3 +11,18 @@ config MMC_CLKGATE
+ 	  support handling this in order for it to be of any use.
+ 
+ 	  If unsure, say N.
++
++config MMC_EMBEDDED_SDIO
++	boolean "MMC embedded SDIO device support (EXPERIMENTAL)"
++	help
++	  If you say Y here, support will be added for embedded SDIO
++	  devices which do not contain the necessary enumeration
++	  support in hardware to be properly detected.
++
++config MMC_PARANOID_SD_INIT
++	bool "Enable paranoid SD card initialization (EXPERIMENTAL)"
++	help
++	  If you say Y here, the MMC layer will be extra paranoid
++	  about re-trying SD init requests. This can be a useful
++	  work-around for buggy controllers and hardware. Enable
++	  if you are experiencing issues with SD detection.
+diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
+index 297b4f9..b850534 100644
+--- a/drivers/mmc/core/core.c
++++ b/drivers/mmc/core/core.c
+@@ -29,6 +29,9 @@
+ #include <linux/random.h>
+ #include <linux/slab.h>
+ #include <linux/of.h>
++#include <linux/wakelock.h>
++
++#include <trace/events/mmc.h>
+ 
+ #include <linux/mmc/card.h>
+ #include <linux/mmc/host.h>
+@@ -55,6 +58,7 @@
+ #define MMC_BKOPS_MAX_TIMEOUT	(4 * 60 * 1000) /* max time to wait in ms */
+ 
+ static struct workqueue_struct *workqueue;
++static struct wake_lock mmc_delayed_work_wake_lock;
+ static const unsigned freqs[] = { 400000, 300000, 200000, 100000 };
+ 
+ /*
+@@ -71,6 +75,7 @@ module_param(use_spi_crc, bool, 0);
+ static int mmc_schedule_delayed_work(struct delayed_work *work,
+ 				     unsigned long delay)
+ {
++	wake_lock(&mmc_delayed_work_wake_lock);
+ 	return queue_delayed_work(workqueue, work, delay);
+ }
+ 
+@@ -158,6 +163,7 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
+ 			pr_debug("%s:     %d bytes transferred: %d\n",
+ 				mmc_hostname(host),
+ 				mrq->data->bytes_xfered, mrq->data->error);
++			trace_mmc_blk_rw_end(cmd->opcode, cmd->arg, mrq->data);
+ 		}
+ 
+ 		if (mrq->stop) {
+@@ -331,7 +337,7 @@ static void mmc_wait_done(struct mmc_request *mrq)
+  * Sets the done callback to be called when request is completed by the card.
+  * Starts data mmc request execution
+  */
+-static int __mmc_start_data_req(struct mmc_host *host, struct mmc_request *mrq)
++int __mmc_start_data_req(struct mmc_host *host, struct mmc_request *mrq)
+ {
+ 	mrq->done = mmc_wait_data_done;
+ 	mrq->host = host;
+@@ -344,6 +350,7 @@ static int __mmc_start_data_req(struct mmc_host *host, struct mmc_request *mrq)
+ 
+ 	return 0;
+ }
++EXPORT_SYMBOL(__mmc_start_data_req);
+ 
+ static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)
+ {
+@@ -358,6 +365,7 @@ static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)
+ 	return 0;
+ }
+ 
++#if 0
+ /*
+  * mmc_wait_for_data_req_done() - wait for request completed
+  * @host: MMC host to prepare the command.
+@@ -414,6 +422,7 @@ static int mmc_wait_for_data_req_done(struct mmc_host *host,
+ 	}
+ 	return err;
+ }
++#endif
+ 
+ static void mmc_wait_for_req_done(struct mmc_host *host,
+ 				  struct mmc_request *mrq)
+@@ -454,6 +463,7 @@ static void mmc_wait_for_req_done(struct mmc_host *host,
+ 	}
+ }
+ 
++#if 0
+ /**
+  *	mmc_pre_req - Prepare for a new request
+  *	@host: MMC host to prepare command
+@@ -474,6 +484,7 @@ static void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq,
+ 		mmc_host_clk_release(host);
+ 	}
+ }
++#endif
+ 
+ /**
+  *	mmc_post_req - Post process a completed request
+@@ -484,7 +495,7 @@ static void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq,
+  *	Let the host post process a completed request. Post processing of
+  *	a request may be performed while another reuqest is running.
+  */
+-static void mmc_post_req(struct mmc_host *host, struct mmc_request *mrq,
++void mmc_post_req(struct mmc_host *host, struct mmc_request *mrq,
+ 			 int err)
+ {
+ 	if (host->ops->post_req) {
+@@ -494,6 +505,7 @@ static void mmc_post_req(struct mmc_host *host, struct mmc_request *mrq,
+ 	}
+ }
+ 
++#if 0
+ /**
+  *	mmc_start_req - start a non-blocking request
+  *	@host: MMC host to start command
+@@ -542,8 +554,12 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host,
+ 			mmc_start_bkops(host->card, true);
+ 	}
+ 
+-	if (!err && areq)
++	if (!err && areq) {
++		trace_mmc_blk_rw_start(areq->mrq->cmd->opcode,
++				       areq->mrq->cmd->arg,
++				       areq->mrq->data);
+ 		start_err = __mmc_start_data_req(host, areq->mrq);
++	}
+ 
+ 	if (host->areq)
+ 		mmc_post_req(host, host->areq->mrq, 0);
+@@ -562,6 +578,7 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host,
+ 	return data;
+ }
+ EXPORT_SYMBOL(mmc_start_req);
++#endif
+ 
+ /**
+  *	mmc_wait_for_req - start a request and wait for completion
+@@ -745,6 +762,9 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card)
+ {
+ 	unsigned int mult;
+ 
++	if (!card)
++		return;
++
+ 	/*
+ 	 * SDIO cards only define an upper 1 s limit on access.
+ 	 */
+@@ -1879,8 +1899,13 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
+ 	struct mmc_command cmd = {0};
+ 	unsigned int qty = 0;
+ 	unsigned long timeout;
++	unsigned int fr, nr;
+ 	int err;
+ 
++	fr = from;
++	nr = to - from + 1;
++	trace_mmc_blk_erase_start(arg, fr, nr);
++
+ 	/*
+ 	 * qty is used to calculate the erase timeout which depends on how many
+ 	 * erase groups (or allocation units in SD terminology) are affected.
+@@ -1984,6 +2009,8 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
+ 	} while (!(cmd.resp[0] & R1_READY_FOR_DATA) ||
+ 		 (R1_CURRENT_STATE(cmd.resp[0]) == R1_STATE_PRG));
+ out:
++
++	trace_mmc_blk_erase_end(arg, fr, nr);
+ 	return err;
+ }
+ 
+@@ -2295,6 +2322,22 @@ int mmc_hw_reset(struct mmc_host *host)
+ }
+ EXPORT_SYMBOL(mmc_hw_reset);
+ 
++int mmc_sw_reset(struct mmc_host *host)
++{
++
++	if (!mmc_card_sd(host->card) || !host->ops->sw_reset)
++		return -EOPNOTSUPP;
++
++	host->ios.bus_width = MMC_BUS_WIDTH_1;
++	host->ios.timing = MMC_TIMING_LEGACY;
++	host->ios.clock = host->f_init;
++	mmc_set_ios(host);
++	host->ops->sw_reset(host);
++
++	return host->bus_ops->power_restore(host);
++}
++EXPORT_SYMBOL(mmc_sw_reset);
++
+ int mmc_hw_reset_check(struct mmc_host *host)
+ {
+ 	return mmc_do_hw_reset(host, 1);
+@@ -2411,6 +2454,7 @@ void mmc_rescan(struct work_struct *work)
+ 	struct mmc_host *host =
+ 		container_of(work, struct mmc_host, detect.work);
+ 	int i;
++	bool extend_wakelock = false;
+ 
+ 	if (host->trigger_card_event && host->ops->card_event) {
+ 		host->ops->card_event(host);
+@@ -2437,6 +2481,12 @@ void mmc_rescan(struct work_struct *work)
+ 
+ 	host->detect_change = 0;
+ 
++	/* If the card was removed the bus will be marked
++	 * as dead - extend the wakelock so userspace
++	 * can respond */
++	if (host->bus_dead)
++		extend_wakelock = 1;
++
+ 	/*
+ 	 * Let mmc_bus_put() free the bus/bus_ops if we've found that
+ 	 * the card is no longer present.
+@@ -2460,20 +2510,30 @@ void mmc_rescan(struct work_struct *work)
+ 			host->ops->get_cd(host) == 0) {
+ 		mmc_claim_host(host);
+ 		mmc_power_off(host);
++		if (host->ops->card_info_save)
++			host->ops->card_info_save(host);
+ 		mmc_release_host(host);
+ 		goto out;
+ 	}
+ 
+ 	mmc_claim_host(host);
+ 	for (i = 0; i < ARRAY_SIZE(freqs); i++) {
+-		if (!mmc_rescan_try_freq(host, max(freqs[i], host->f_min)))
++		if (!mmc_rescan_try_freq(host, max(freqs[i], host->f_min))) {
++			extend_wakelock = true;
++			if (host->ops->card_info_save)
++				host->ops->card_info_save(host);
+ 			break;
++		}
+ 		if (freqs[i] <= host->f_min)
+ 			break;
+ 	}
+ 	mmc_release_host(host);
+ 
+  out:
++	if (extend_wakelock)
++		wake_lock_timeout(&mmc_delayed_work_wake_lock, HZ / 2);
++	else
++		wake_unlock(&mmc_delayed_work_wake_lock);
+ 	if (host->caps & MMC_CAP_NEEDS_POLL)
+ 		mmc_schedule_delayed_work(&host->detect, HZ);
+ }
+@@ -2671,6 +2731,22 @@ void mmc_init_context_info(struct mmc_host *host)
+ 	init_waitqueue_head(&host->context_info.wait);
+ }
+ 
++#ifdef CONFIG_MMC_EMBEDDED_SDIO
++void mmc_set_embedded_sdio_data(struct mmc_host *host,
++				struct sdio_cis *cis,
++				struct sdio_cccr *cccr,
++				struct sdio_embedded_func *funcs,
++				int num_funcs)
++{
++	host->embedded_sdio_data.cis = cis;
++	host->embedded_sdio_data.cccr = cccr;
++	host->embedded_sdio_data.funcs = funcs;
++	host->embedded_sdio_data.num_funcs = num_funcs;
++}
++
++EXPORT_SYMBOL(mmc_set_embedded_sdio_data);
++#endif
++
+ static int __init mmc_init(void)
+ {
+ 	int ret;
+@@ -2679,6 +2755,9 @@ static int __init mmc_init(void)
+ 	if (!workqueue)
+ 		return -ENOMEM;
+ 
++	wake_lock_init(&mmc_delayed_work_wake_lock, WAKE_LOCK_SUSPEND,
++		       "mmc_delayed_work");
++
+ 	ret = mmc_register_bus();
+ 	if (ret)
+ 		goto destroy_workqueue;
+@@ -2699,6 +2778,7 @@ unregister_bus:
+ 	mmc_unregister_bus();
+ destroy_workqueue:
+ 	destroy_workqueue(workqueue);
++	wake_lock_destroy(&mmc_delayed_work_wake_lock);
+ 
+ 	return ret;
+ }
+@@ -2709,6 +2789,7 @@ static void __exit mmc_exit(void)
+ 	mmc_unregister_host_class();
+ 	mmc_unregister_bus();
+ 	destroy_workqueue(workqueue);
++	wake_lock_destroy(&mmc_delayed_work_wake_lock);
+ }
+ 
+ subsys_initcall(mmc_init);
+diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
+index 270d58a..08e11cb 100644
+--- a/drivers/mmc/core/host.c
++++ b/drivers/mmc/core/host.c
+@@ -371,7 +371,7 @@ int mmc_of_parse(struct mmc_host *host)
+ 			if (ret == -EPROBE_DEFER)
+ 				return ret;
+ 			if (ret != -ENOENT) {
+-				dev_err(host->parent,
++				dev_dbg(host->parent,
+ 					"Failed to request CD GPIO: %d\n",
+ 					ret);
+ 			}
+@@ -401,7 +401,7 @@ int mmc_of_parse(struct mmc_host *host)
+ 		if (ret == -EPROBE_DEFER)
+ 			goto out;
+ 		if (ret != -ENOENT) {
+-			dev_err(host->parent,
++			dev_dbg(host->parent,
+ 				"Failed to request WP GPIO: %d\n",
+ 				ret);
+ 		}
+@@ -560,7 +560,8 @@ int mmc_add_host(struct mmc_host *host)
+ 	mmc_host_clk_sysfs_init(host);
+ 
+ 	mmc_start_host(host);
+-	register_pm_notifier(&host->pm_notify);
++	if (!(host->pm_flags & MMC_PM_IGNORE_PM_NOTIFY))
++		register_pm_notifier(&host->pm_notify);
+ 
+ 	return 0;
+ }
+@@ -577,7 +578,9 @@ EXPORT_SYMBOL(mmc_add_host);
+  */
+ void mmc_remove_host(struct mmc_host *host)
+ {
+-	unregister_pm_notifier(&host->pm_notify);
++	if (!(host->pm_flags & MMC_PM_IGNORE_PM_NOTIFY))
++		unregister_pm_notifier(&host->pm_notify);
++
+ 	mmc_stop_host(host);
+ 
+ #ifdef CONFIG_DEBUG_FS
+diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
+index a301a78..f4b9bf0 100644
+--- a/drivers/mmc/core/mmc.c
++++ b/drivers/mmc/core/mmc.c
+@@ -1175,38 +1175,6 @@ bus_speed:
+ 	return err;
+ }
+ 
+-const u8 tuning_blk_pattern_4bit[MMC_TUNING_BLK_PATTERN_4BIT_SIZE] = {
+-	0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc,
+-	0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef,
+-	0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb,
+-	0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef,
+-	0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c,
+-	0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee,
+-	0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff,
+-	0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde,
+-};
+-EXPORT_SYMBOL(tuning_blk_pattern_4bit);
+-
+-const u8 tuning_blk_pattern_8bit[MMC_TUNING_BLK_PATTERN_8BIT_SIZE] = {
+-	0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
+-	0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc,
+-	0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff,
+-	0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff,
+-	0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd,
+-	0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb,
+-	0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff,
+-	0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff,
+-	0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
+-	0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc,
+-	0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff,
+-	0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee,
+-	0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd,
+-	0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff,
+-	0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff,
+-	0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee,
+-};
+-EXPORT_SYMBOL(tuning_blk_pattern_8bit);
+-
+ /*
+  * Execute tuning sequence to seek the proper bus operating
+  * conditions for HS200 and HS400, which sends CMD21 to the device.
+@@ -1239,6 +1207,34 @@ static int mmc_hs200_tuning(struct mmc_card *card)
+ 	return err;
+ }
+ 
++static int mmc_hs400_tuning(struct mmc_card *card)
++{
++	struct mmc_host *host = card->host;
++	int err = 0;
++
++	/*
++	 * Timing should be adjusted to the HS400 target
++	 * operation frequency for tuning process
++	 */
++	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400 &&
++	    host->ios.bus_width == MMC_BUS_WIDTH_8)
++		if (host->ops->prepare_hs400_tuning)
++			host->ops->prepare_hs400_tuning(host, &host->ios);
++
++	if (host->ops->execute_tuning) {
++		mmc_host_clk_hold(host);
++		err = host->ops->execute_tuning(host,
++				MMC_SEND_EXT_CSD);
++		mmc_host_clk_release(host);
++
++		if (err)
++			pr_warn("%s: tuning execution failed\n",
++				mmc_hostname(host));
++	}
++
++	return err;
++}
++
+ /*
+  * Handle the detection and initialisation of a card.
+  *
+@@ -1463,6 +1459,12 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
+ 		err = mmc_select_hs400(card);
+ 		if (err)
+ 			goto err;
++
++		if (mmc_card_hs400(card)) {
++			err = mmc_hs400_tuning(card);
++			if (err)
++				goto err;
++		}
+ 	} else if (mmc_card_hs(card)) {
+ 		/* Select the desired bus width optionally */
+ 		err = mmc_select_bus_width(card);
+diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
+index 7911e05..2692021 100644
+--- a/drivers/mmc/core/mmc_ops.c
++++ b/drivers/mmc/core/mmc_ops.c
+@@ -23,6 +23,36 @@
+ 
+ #define MMC_OPS_TIMEOUT_MS	(10 * 60 * 1000) /* 10 minute timeout */
+ 
++static const u8 tuning_blk_pattern_4bit[] = {
++	0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc,
++	0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef,
++	0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb,
++	0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef,
++	0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c,
++	0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee,
++	0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff,
++	0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde,
++};
++
++static const u8 tuning_blk_pattern_8bit[] = {
++	0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
++	0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc,
++	0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff,
++	0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff,
++	0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd,
++	0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb,
++	0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff,
++	0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff,
++	0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
++	0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc,
++	0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff,
++	0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee,
++	0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd,
++	0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff,
++	0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff,
++	0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee,
++};
++
+ static inline int __mmc_send_status(struct mmc_card *card, u32 *status,
+ 				    bool ignore_crc)
+ {
+@@ -543,6 +573,93 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
+ }
+ EXPORT_SYMBOL_GPL(mmc_switch);
+ 
++int mmc_send_tuning(struct mmc_host *host, u32 opcode, int *cmd_error)
++{
++	struct mmc_request mrq = {NULL};
++	struct mmc_command cmd = {0};
++	struct mmc_data data = {0};
++	struct scatterlist sg;
++	struct mmc_ios *ios = &host->ios;
++	const u8 *tuning_block_pattern;
++	int size, err = 0;
++	u8 *data_buf;
++
++	if (ios->bus_width == MMC_BUS_WIDTH_8) {
++		tuning_block_pattern = tuning_blk_pattern_8bit;
++		size = sizeof(tuning_blk_pattern_8bit);
++	} else if (ios->bus_width == MMC_BUS_WIDTH_4) {
++		tuning_block_pattern = tuning_blk_pattern_4bit;
++		size = sizeof(tuning_blk_pattern_4bit);
++	} else
++		return -EINVAL;
++
++	data_buf = kzalloc(size, GFP_KERNEL);
++	if (!data_buf)
++		return -ENOMEM;
++
++	mrq.cmd = &cmd;
++	mrq.data = &data;
++
++	cmd.opcode = opcode;
++	cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
++
++	data.blksz = size;
++	data.blocks = 1;
++	data.flags = MMC_DATA_READ;
++
++	/*
++	 * According to the tuning specs, Tuning process
++	 * is normally shorter 40 executions of CMD19,
++	 * and timeout value should be shorter than 150 ms
++	 */
++	data.timeout_ns = 150 * NSEC_PER_MSEC;
++
++	data.sg = &sg;
++	data.sg_len = 1;
++	sg_init_one(&sg, data_buf, size);
++
++	mmc_wait_for_req(host, &mrq);
++
++	if (cmd_error)
++		*cmd_error = cmd.error;
++
++	if (cmd.error) {
++		err = cmd.error;
++		goto out;
++	}
++
++	if (data.error) {
++		err = data.error;
++		goto out;
++	}
++
++	if (memcmp(data_buf, tuning_block_pattern, size))
++		err = -EIO;
++
++out:
++	kfree(data_buf);
++	return err;
++}
++EXPORT_SYMBOL_GPL(mmc_send_tuning);
++
++int mmc_send_dll_tuning(struct mmc_host *host)
++{
++	u8 *ext_csd;
++	int err = 0;
++
++	ext_csd = kzalloc(512, GFP_KERNEL);
++	if (!ext_csd)
++		return -ENOMEM;
++
++	err = mmc_send_cxd_data(NULL, host, MMC_SEND_EXT_CSD,
++			ext_csd, 512);
++
++	kfree(ext_csd);
++
++	return err;
++}
++EXPORT_SYMBOL_GPL(mmc_send_dll_tuning);
++
+ static int
+ mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode,
+ 		  u8 len)
+diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
+index d90a6de..a9e09ce 100644
+--- a/drivers/mmc/core/sd.c
++++ b/drivers/mmc/core/sd.c
+@@ -246,8 +246,10 @@ static int mmc_read_ssr(struct mmc_card *card)
+ 		goto out;
+ 	}
+ 
+-	for (i = 0; i < 16; i++)
++	for (i = 0; i < 16; i++) {
+ 		ssr[i] = be32_to_cpu(ssr[i]);
++		card->c_ssr[i] = ssr[i];
++	}
+ 
+ 	/*
+ 	 * UNSTUFF_BITS only works with four u32s so we have to offset the
+@@ -813,6 +815,9 @@ int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card,
+ 	bool reinit)
+ {
+ 	int err;
++#ifdef CONFIG_MMC_PARANOID_SD_INIT
++	int retries;
++#endif
+ 
+ 	if (!reinit) {
+ 		/*
+@@ -839,7 +844,26 @@ int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card,
+ 		/*
+ 		 * Fetch switch information from card.
+ 		 */
++#ifdef CONFIG_MMC_PARANOID_SD_INIT
++		for (retries = 1; retries <= 3; retries++) {
++			err = mmc_read_switch(card);
++			if (!err) {
++				if (retries > 1) {
++					printk(KERN_WARNING
++					       "%s: recovered\n", 
++					       mmc_hostname(host));
++				}
++				break;
++			} else {
++				printk(KERN_WARNING
++				       "%s: read switch failed (attempt %d)\n",
++				       mmc_hostname(host), retries);
++			}
++		}
++#else
+ 		err = mmc_read_switch(card);
++#endif
++
+ 		if (err)
+ 			return err;
+ 	}
+@@ -969,6 +993,15 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
+ 	if (err)
+ 		goto free_card;
+ 
++	/* check have been set bus speed*/
++	if (card->sd_bus_speed != 0) {
++		err = mmc_sd_init_uhs_card(card);
++		if (err)
++			goto free_card;
++
++		goto done;
++	}
++
+ 	/* Initialization sequence for UHS-I cards */
+ 	if (rocr & SD_ROCR_S18A) {
+ 		err = mmc_sd_init_uhs_card(card);
+@@ -1002,6 +1035,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
+ 		}
+ 	}
+ 
++done:
+ 	host->card = card;
+ 	return 0;
+ 
+@@ -1037,7 +1071,10 @@ static int mmc_sd_alive(struct mmc_host *host)
+  */
+ static void mmc_sd_detect(struct mmc_host *host)
+ {
+-	int err;
++	int err = 0;
++#ifdef CONFIG_MMC_PARANOID_SD_INIT
++	int retries = 5;
++#endif
+ 
+ 	BUG_ON(!host);
+ 	BUG_ON(!host->card);
+@@ -1047,7 +1084,23 @@ static void mmc_sd_detect(struct mmc_host *host)
+ 	/*
+ 	 * Just check if our card has been removed.
+ 	 */
++#ifdef CONFIG_MMC_PARANOID_SD_INIT
++	while(retries) {
++		err = mmc_send_status(host->card, NULL);
++		if (err) {
++			retries--;
++			udelay(5);
++			continue;
++		}
++		break;
++	}
++	if (!retries) {
++		printk(KERN_ERR "%s(%s): Unable to re-detect card (%d)\n",
++		       __func__, mmc_hostname(host), err);
++	}
++#else
+ 	err = _mmc_detect_card_removed(host);
++#endif
+ 
+ 	mmc_put_card(host->card);
+ 
+@@ -1109,6 +1162,9 @@ static int mmc_sd_suspend(struct mmc_host *host)
+ static int _mmc_sd_resume(struct mmc_host *host)
+ {
+ 	int err = 0;
++#ifdef CONFIG_MMC_PARANOID_SD_INIT
++	int retries;
++#endif
+ 
+ 	BUG_ON(!host);
+ 	BUG_ON(!host->card);
+@@ -1119,7 +1175,23 @@ static int _mmc_sd_resume(struct mmc_host *host)
+ 		goto out;
+ 
+ 	mmc_power_up(host, host->card->ocr);
++#ifdef CONFIG_MMC_PARANOID_SD_INIT
++	retries = 5;
++	while (retries) {
++		err = mmc_sd_init_card(host, host->card->ocr, host->card);
++
++		if (err) {
++			printk(KERN_ERR "%s: Re-init card rc = %d (retries = %d)\n",
++			       mmc_hostname(host), err, retries);
++			mdelay(5);
++			retries--;
++			continue;
++		}
++		break;
++	}
++#else
+ 	err = mmc_sd_init_card(host, host->card->ocr, host->card);
++#endif
+ 	mmc_card_clr_suspended(host->card);
+ 
+ out:
+@@ -1210,6 +1282,9 @@ int mmc_attach_sd(struct mmc_host *host)
+ {
+ 	int err;
+ 	u32 ocr, rocr;
++#ifdef CONFIG_MMC_PARANOID_SD_INIT
++	int retries;
++#endif
+ 
+ 	BUG_ON(!host);
+ 	WARN_ON(!host->claimed);
+@@ -1246,9 +1321,27 @@ int mmc_attach_sd(struct mmc_host *host)
+ 	/*
+ 	 * Detect and init the card.
+ 	 */
++#ifdef CONFIG_MMC_PARANOID_SD_INIT
++	retries = 5;
++	while (retries) {
++		err = mmc_sd_init_card(host, rocr, NULL);
++		if (err) {
++			retries--;
++			continue;
++		}
++		break;
++	}
++
++	if (!retries) {
++		printk(KERN_ERR "%s: mmc_sd_init_card() failure (err = %d)\n",
++		       mmc_hostname(host), err);
++		goto err;
++	}
++#else
+ 	err = mmc_sd_init_card(host, rocr, NULL);
+ 	if (err)
+ 		goto err;
++#endif
+ 
+ 	mmc_release_host(host);
+ 	err = mmc_add_card(host->card);
+diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c
+index 48d0c93..e608af5 100644
+--- a/drivers/mmc/core/sd_ops.c
++++ b/drivers/mmc/core/sd_ops.c
+@@ -393,3 +393,4 @@ int mmc_app_sd_status(struct mmc_card *card, void *ssr)
+ 
+ 	return 0;
+ }
++EXPORT_SYMBOL(mmc_app_sd_status);
+diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
+index 2439e71..7c7e544 100644
+--- a/drivers/mmc/core/sdio.c
++++ b/drivers/mmc/core/sdio.c
+@@ -10,6 +10,7 @@
+  */
+ 
+ #include <linux/err.h>
++#include <linux/module.h>
+ #include <linux/pm_runtime.h>
+ 
+ #include <linux/mmc/host.h>
+@@ -28,6 +29,10 @@
+ #include "sdio_ops.h"
+ #include "sdio_cis.h"
+ 
++#ifdef CONFIG_MMC_EMBEDDED_SDIO
++#include <linux/mmc/sdio_ids.h>
++#endif
++
+ static int sdio_read_fbr(struct sdio_func *func)
+ {
+ 	int ret;
+@@ -738,19 +743,35 @@ try_again:
+ 		goto finish;
+ 	}
+ 
+-	/*
+-	 * Read the common registers.
+-	 */
+-	err = sdio_read_cccr(card, ocr);
+-	if (err)
+-		goto remove;
++#ifdef CONFIG_MMC_EMBEDDED_SDIO
++	if (host->embedded_sdio_data.cccr)
++		memcpy(&card->cccr, host->embedded_sdio_data.cccr, sizeof(struct sdio_cccr));
++	else {
++#endif
++		/*
++		 * Read the common registers.
++		 */
++		err = sdio_read_cccr(card,  ocr);
++		if (err)
++			goto remove;
++#ifdef CONFIG_MMC_EMBEDDED_SDIO
++	}
++#endif
+ 
+-	/*
+-	 * Read the common CIS tuples.
+-	 */
+-	err = sdio_read_common_cis(card);
+-	if (err)
+-		goto remove;
++#ifdef CONFIG_MMC_EMBEDDED_SDIO
++	if (host->embedded_sdio_data.cis)
++		memcpy(&card->cis, host->embedded_sdio_data.cis, sizeof(struct sdio_cis));
++	else {
++#endif
++		/*
++		 * Read the common CIS tuples.
++		 */
++		err = sdio_read_common_cis(card);
++		if (err)
++			goto remove;
++#ifdef CONFIG_MMC_EMBEDDED_SDIO
++	}
++#endif
+ 
+ 	if (oldcard) {
+ 		int same = (card->cis.vendor == oldcard->cis.vendor &&
+@@ -1143,14 +1164,36 @@ int mmc_attach_sdio(struct mmc_host *host)
+ 	funcs = (ocr & 0x70000000) >> 28;
+ 	card->sdio_funcs = 0;
+ 
++#ifdef CONFIG_MMC_EMBEDDED_SDIO
++	if (host->embedded_sdio_data.funcs)
++		card->sdio_funcs = funcs = host->embedded_sdio_data.num_funcs;
++#endif
++
+ 	/*
+ 	 * Initialize (but don't add) all present functions.
+ 	 */
+ 	for (i = 0; i < funcs; i++, card->sdio_funcs++) {
+-		err = sdio_init_func(host->card, i + 1);
+-		if (err)
+-			goto remove;
+-
++#ifdef CONFIG_MMC_EMBEDDED_SDIO
++		if (host->embedded_sdio_data.funcs) {
++			struct sdio_func *tmp;
++
++			tmp = sdio_alloc_func(host->card);
++			if (IS_ERR(tmp))
++				goto remove;
++			tmp->num = (i + 1);
++			card->sdio_func[i] = tmp;
++			tmp->class = host->embedded_sdio_data.funcs[i].f_class;
++			tmp->max_blksize = host->embedded_sdio_data.funcs[i].f_maxblksize;
++			tmp->vendor = card->cis.vendor;
++			tmp->device = card->cis.device;
++		} else {
++#endif
++			err = sdio_init_func(host->card, i + 1);
++			if (err)
++				goto remove;
++#ifdef CONFIG_MMC_EMBEDDED_SDIO
++		}
++#endif
+ 		/*
+ 		 * Enable Runtime PM for this func (if supported)
+ 		 */
+@@ -1198,3 +1241,40 @@ err:
+ 	return err;
+ }
+ 
++int sdio_reset_comm(struct mmc_card *card)
++{
++	struct mmc_host *host = card->host;
++	u32 ocr;
++	u32 rocr;
++	int err;
++
++	printk("%s():\n", __func__);
++	mmc_claim_host(host);
++
++	mmc_go_idle(host);
++
++	mmc_set_clock(host, host->f_min);
++
++	err = mmc_send_io_op_cond(host, 0, &ocr);
++	if (err)
++		goto err;
++
++	rocr = mmc_select_voltage(host, ocr);
++	if (!rocr) {
++		err = -EINVAL;
++		goto err;
++	}
++
++	err = mmc_sdio_init_card(host, rocr, card, 0);
++	if (err)
++		goto err;
++
++	mmc_release_host(host);
++	return 0;
++err:
++	printk("%s: Error resetting SDIO communications (%d)\n",
++	       mmc_hostname(host), err);
++	mmc_release_host(host);
++	return err;
++}
++EXPORT_SYMBOL(sdio_reset_comm);
+diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c
+index 6da97b1..a735f89 100644
+--- a/drivers/mmc/core/sdio_bus.c
++++ b/drivers/mmc/core/sdio_bus.c
+@@ -26,6 +26,10 @@
+ #include "sdio_cis.h"
+ #include "sdio_bus.h"
+ 
++#ifdef CONFIG_MMC_EMBEDDED_SDIO
++#include <linux/mmc/host.h>
++#endif
++
+ /* show configuration fields */
+ #define sdio_config_attr(field, format_string)				\
+ static ssize_t								\
+@@ -262,7 +266,14 @@ static void sdio_release_func(struct device *dev)
+ {
+ 	struct sdio_func *func = dev_to_sdio_func(dev);
+ 
+-	sdio_free_func_cis(func);
++#ifdef CONFIG_MMC_EMBEDDED_SDIO
++	/*
++	 * If this device is embedded then we never allocated
++	 * cis tables for this func
++	 */
++	if (!func->card->host->embedded_sdio_data.funcs)
++#endif
++		sdio_free_func_cis(func);
+ 
+ 	kfree(func->info);
+ 
+diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c
+old mode 100644
+new mode 100755
+index 78cb4d5..8fdeb07
+--- a/drivers/mmc/core/sdio_io.c
++++ b/drivers/mmc/core/sdio_io.c
+@@ -384,6 +384,39 @@ u8 sdio_readb(struct sdio_func *func, unsigned int addr, int *err_ret)
+ EXPORT_SYMBOL_GPL(sdio_readb);
+ 
+ /**
++ *	sdio_readb_ext - read a single byte from a SDIO function
++ *	@func: SDIO function to access
++ *	@addr: address to read
++ *	@err_ret: optional status value from transfer
++ *	@in: value to add to argument
++ *
++ *	Reads a single byte from the address space of a given SDIO
++ *	function. If there is a problem reading the address, 0xff
++ *	is returned and @err_ret will contain the error code.
++ */
++unsigned char sdio_readb_ext(struct sdio_func *func, unsigned int addr,
++	int *err_ret, unsigned in)
++{
++	int ret;
++	unsigned char val;
++
++	BUG_ON(!func);
++
++	if (err_ret)
++		*err_ret = 0;
++
++	ret = mmc_io_rw_direct(func->card, 0, func->num, addr, (u8)in, &val);
++	if (ret) {
++		if (err_ret)
++			*err_ret = ret;
++		return 0xFF;
++	}
++
++	return val;
++}
++EXPORT_SYMBOL_GPL(sdio_readb_ext);
++
++/**
+  *	sdio_writeb - write a single byte to a SDIO function
+  *	@func: SDIO function to access
+  *	@b: byte to write
+diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
+index 1386065..9629e12 100644
+--- a/drivers/mmc/host/Kconfig
++++ b/drivers/mmc/host/Kconfig
+@@ -748,3 +748,5 @@ config MMC_SUNXI
+ 	help
+ 	  This selects support for the SD/MMC Host Controller on
+ 	  Allwinner sunxi SoCs.
++
++source "drivers/mmc/host/himciv200/Kconfig"
+diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
+index b09ecfb..8999d29 100644
+--- a/drivers/mmc/host/Makefile
++++ b/drivers/mmc/host/Makefile
+@@ -75,3 +75,4 @@ obj-$(CONFIG_MMC_SDHCI_ST)		+= sdhci-st.o
+ ifeq ($(CONFIG_CB710_DEBUG),y)
+ 	CFLAGS-cb710-mmc	+= -DDEBUG
+ endif
++obj-$(CONFIG_HIMCIV200)  += himciv200/
+diff --git a/drivers/mmc/host/himciv200/Kconfig b/drivers/mmc/host/himciv200/Kconfig
+new file mode 100644
+index 0000000..323a5dd
+--- /dev/null
++++ b/drivers/mmc/host/himciv200/Kconfig
+@@ -0,0 +1,38 @@
++#
++# himci v200 device configuration
++#
++menuconfig HIMCIV200
++	tristate "himci v200 eMMC/SDXC/SDIO device support"
++	depends on (ARCH_HI3516CV300 || ARCH_HI3519 || ARCH_HI3519V101 || ARCH_HI3559 || ARCH_HI3556 || ARCH_HI3516AV200)
++	default y if (ARCH_HI3516CV300)
++	default y if (ARCH_HI3519)
++	default y if (ARCH_HI3519V101)
++	default y if (ARCH_HI3516AV200)
++	default y if (ARCH_HI3559)
++	default y if (ARCH_HI3556)
++	select MMC_UNSAFE_RESUME
++	select MMC_EMBEDDED_SDIO
++	select MMC_BLOCK
++	select MMC_BLOCK_BOUNCE
++	help
++	  This selects the Hisilicon Synopsys MultiMedia Card Driver
++	  support. If you want use SD/MMC/SDIO driver,
++	  Say Y or M here.
++
++	  default is Y.
++
++config SEND_AUTO_STOP
++	bool "Send Auto Stop to terminate data transfer between host and SD card"
++	depends on (ARCH_HI3516CV300 || ARCH_HI3519 || ARCH_HI3519V101 || ARCH_HI3559 || ARCH_HI3556 || ARCH_HI3516AV200) && HIMCIV200
++	default y
++
++config DETECT_CARD_TIME
++	int "The Period to detect whether Card is pluged or unpluged."
++	depends on (ARCH_HI3516CV300 || ARCH_HI3519 || ARCH_HI3519V101 || ARCH_HI3559 || ARCH_HI3556 || ARCH_HI3516AV200) && HIMCIV200
++	range 10 500
++	default 200
++	help
++	  Set the Period Time to detect the card, which the unit is ms.
++	  Should set it between 10 and 500.
++
++	  Default is 200 here.
+diff --git a/drivers/mmc/host/himciv200/Makefile b/drivers/mmc/host/himciv200/Makefile
+new file mode 100644
+index 0000000..6ba3ce4
+--- /dev/null
++++ b/drivers/mmc/host/himciv200/Makefile
+@@ -0,0 +1,2 @@
++obj-$(CONFIG_HIMCIV200) += himciv200.o
++himciv200-objs := himci.o himci_proc.o
+diff --git a/drivers/mmc/host/himciv200/himci.c b/drivers/mmc/host/himciv200/himci.c
+new file mode 100644
+index 0000000..51b5343
+--- /dev/null
++++ b/drivers/mmc/host/himciv200/himci.c
+@@ -0,0 +1,2237 @@
++/*
++ * himci.c - hisilicon MMC Host driver
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++#define pr_fmt(fmt) "himci: " fmt
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/platform_device.h>
++#include <linux/mm.h>
++#include <linux/interrupt.h>
++#include <linux/dma-mapping.h>
++#include <linux/scatterlist.h>
++
++#include <linux/mmc/host.h>
++#include <linux/mmc/mmc.h>
++#include <linux/mmc/card.h>
++#include <linux/mmc/core.h>
++#include <linux/mmc/sd.h>
++#include <linux/slab.h>
++
++#include <linux/ioport.h>
++#include <linux/device.h>
++#include <linux/spinlock.h>
++
++#include <linux/delay.h>
++#include <linux/dma-mapping.h>
++#include <linux/kthread.h>
++#include <linux/workqueue.h>
++#include <linux/freezer.h>
++#include <asm/dma.h>
++#include <asm/irq.h>
++#include <linux/sizes.h>
++#include <mach/io.h>
++
++#include <linux/io.h>
++#include <linux/of.h>
++#include <linux/clk.h>
++#include <linux/clk-provider.h>
++
++#include "himci_reg.h"
++#include "himci.h"
++#include "himci_dbg.h"
++#include "himci_acl.h"
++#include "himci_proc.h"
++
++/*************************************************************************/
++#ifdef CONFIG_ARCH_HI3516CV300
++#include "himci_hi3516cv300.c"
++#endif
++
++#ifdef CONFIG_ARCH_HI3519
++#include "himci_hi3519.c"
++#endif
++
++#ifdef CONFIG_ARCH_HI3519V101
++#include "himci_hi3519v101.c"
++#endif
++
++#ifdef CONFIG_ARCH_HI3516AV200
++#include "himci_hi3516av200.c"
++#endif
++
++#if defined(CONFIG_ARCH_HI3559) || defined(CONFIG_ARCH_HI3556)
++#include "himci_hi3559.c"
++#endif
++
++#if defined(CONFIG_ARCH_HI3559) || defined(CONFIG_ARCH_HI3556)
++	#define PERF_OPT_RATIO 8
++	#define MAX_SEGS 4096
++#else
++	#define PERF_OPT_RATIO 1
++	#define MAX_SEGS 1024
++#endif
++
++/*************************************************************************/
++#define DRIVER_NAME "himci"
++
++#ifdef CONFIG_DETECT_CARD_TIME
++static unsigned int detect_time = HZ*CONFIG_DETECT_CARD_TIME/1000;
++#else
++static unsigned int detect_time = HI_MCI_DETECT_TIMEOUT;
++#endif
++
++static unsigned int retry_count = MAX_RETRY_COUNT;
++static unsigned int request_timeout = HI_MCI_REQUEST_TIMEOUT;
++int trace_level = HIMCI_TRACE_LEVEL;
++unsigned int slot_index = 0;
++struct himci_host *mci_host[HIMCI_SLOT_NUM] = {NULL};
++
++#ifdef MODULE
++
++module_param(detect_time, uint, 0600);
++MODULE_PARM_DESC(detect_timer, "card detect time (default:500ms))");
++
++module_param(retry_count, uint, 0600);
++MODULE_PARM_DESC(retry_count, "retry count times (default:100))");
++
++module_param(request_timeout, uint, 0600);
++MODULE_PARM_DESC(request_timeout, "Request timeout time (default:3s))");
++
++module_param(trace_level, int, 0600);
++MODULE_PARM_DESC(trace_level, "HIMCI_TRACE_LEVEL");
++
++#endif
++
++/* reset MMC host controller */
++static void himciv200_sys_reset(struct himci_host *host)
++{
++	unsigned int reg_value;
++	unsigned long flags;
++
++	local_irq_save(flags);
++
++	reg_value = himci_readl(host->base + MCI_BMOD);
++	reg_value |= BMOD_SWR;
++	himci_writel(reg_value, host->base + MCI_BMOD);
++	mdelay(10);
++
++	reg_value = himci_readl(host->base + MCI_BMOD);
++	reg_value |= BURST_16 | BURST_INCR;
++	himci_writel(reg_value, host->base + MCI_BMOD);
++
++	reg_value = himci_readl(host->base + MCI_CTRL);
++	reg_value |= CTRL_RESET | FIFO_RESET | DMA_RESET;
++	himci_writel(reg_value, host->base + MCI_CTRL);
++
++	local_irq_restore(flags);
++}
++
++static void himci_ctrl_power(struct himci_host *host,
++		unsigned int flag, unsigned int force)
++{
++	unsigned int port;
++
++	himci_trace(2, "begin");
++
++	port = host->cur_port;
++
++	if (host->power_status != flag || force == FORCE_ENABLE) {
++		unsigned int reg_value;
++
++		if (flag == POWER_OFF) {
++			reg_value = himci_readl(host->base + MCI_RESET_N);
++			reg_value &= ~(MMC_RST_N << port);
++			himci_writel(reg_value, host->base + MCI_RESET_N);
++		}
++
++		reg_value = himci_readl(host->base + MCI_PWREN);
++		if (flag == POWER_OFF)
++			reg_value &= ~(0x1 << port);
++		else
++			reg_value |= (0x1 << port);
++
++		himci_writel(reg_value, host->base + MCI_PWREN);
++
++		if (flag == POWER_ON) {
++			reg_value = himci_readl(host->base + MCI_RESET_N);
++			reg_value |= (MMC_RST_N << port);
++			himci_writel(reg_value, host->base + MCI_RESET_N);
++		}
++
++		if (in_interrupt())
++			mdelay(100);
++		else
++			msleep(100);
++
++		host->power_status = flag;
++	}
++}
++
++static void himciv200_host_power(struct himci_host *host, unsigned int power_on,
++		unsigned int force)
++{
++	if (host->power_status != power_on || force) {
++		if (!power_on) {
++			himci_writel(0, host->base + MCI_RESET_N);
++			himci_writel(0, host->base + MCI_PWREN);
++		} else {
++			himci_writel(1, host->base + MCI_PWREN);
++			himci_writel(1, host->base + MCI_RESET_N);
++		}
++
++		mdelay(100);
++
++		host->power_status = power_on;
++	}
++}
++
++static void himci_idma_start(struct himci_host *host)
++{
++	unsigned int tmp;
++
++	himci_trace(2, "begin");
++
++	tmp = himci_readl(host->base + MCI_BMOD);
++	tmp |= BMOD_DMA_EN;
++	himci_writel(tmp, host->base + MCI_BMOD);
++}
++
++/**********************************************
++ *1: card off
++ *0: card on
++ ***********************************************/
++static unsigned int himci_sys_card_detect(struct himci_host *host)
++{
++	unsigned int card_status;
++
++	card_status = himci_readl(host->base + MCI_CDETECT);
++
++	/* eMMC need't detect, but we check if eMMC controller available */
++	if (!(host->mmc->caps & MMC_CAP_SD_HIGHSPEED))
++		return himci_check_emmc(host);
++
++	card_status &= HIMCI_CARD0;
++	return card_status;
++}
++
++/**********************************************
++ *1: card readonly
++ *0: card read/write
++ ***********************************************/
++static unsigned int himci_ctrl_card_readonly(struct himci_host *host)
++{
++	unsigned int card_value = himci_readl(host->base + MCI_WRTPRT);
++	unsigned int port = host->cur_port;
++
++	return card_value & (HIMCI_CARD0 << port);
++}
++
++static int himci_wait_cmd(struct himci_host *host)
++{
++	int wait_retry_count = 0;
++	unsigned int reg_data = 0;
++	unsigned long flags;
++
++	while (1) {
++		/*
++		   Check if CMD::start_cmd bit is clear.
++		   start_cmd = 0 means MMC Host controller has loaded registers
++		   and next command can be loaded in.
++		 */
++		reg_data = himci_readl(host->base + MCI_CMD);
++		if ((reg_data & START_CMD) == 0)
++			return 0;
++
++		/* Check if Raw_Intr_Status::HLE bit is set. */
++		spin_lock_irqsave(&host->lock, flags);
++		reg_data = himci_readl(host->base + MCI_RINTSTS);
++		if (reg_data & HLE_INT_STATUS) {
++			reg_data |= HLE_INT_STATUS;
++			himci_writel(reg_data, host->base + MCI_RINTSTS);
++			spin_unlock_irqrestore(&host->lock, flags);
++
++			himci_trace(5, "Other CMD is running,"
++				"please operate cmd again!");
++			return 1;
++		}
++
++		spin_unlock_irqrestore(&host->lock, flags);
++		udelay(100);
++
++		/* Check if number of retries for this are over. */
++		wait_retry_count++;
++		if (wait_retry_count >= retry_count) {
++			himci_trace(3, "send cmd is timeout!");
++			return -1;
++		}
++	}
++}
++
++static void himci_control_cclk(struct himci_host *host, unsigned int flag)
++{
++	unsigned int reg;
++	union cmd_arg_u cmd_reg;
++	unsigned int port = host->cur_port;
++
++	himci_trace(2, "begin");
++	himci_assert(host);
++
++	reg = himci_readl(host->base + MCI_CLKENA);
++	if (flag == ENABLE) {
++		reg |= (CCLK_ENABLE << port);
++		reg |= (0x10000 << port);
++	} else {
++		reg &= ~(CCLK_ENABLE << port);
++		reg &= ~(0x10000 << port);
++	}
++
++	himci_writel(reg, host->base + MCI_CLKENA);
++	cmd_reg.cmd_arg = himci_readl(host->base + MCI_CMD);
++	cmd_reg.bits.start_cmd = 1;
++	cmd_reg.bits.card_number = port;
++	cmd_reg.bits.cmd_index = 0;
++	cmd_reg.bits.data_transfer_expected = 0;
++	cmd_reg.bits.update_clk_reg_only = 1;
++	cmd_reg.bits.response_expect = 0;
++	cmd_reg.bits.send_auto_stop = 0;
++	cmd_reg.bits.wait_prvdata_complete = 0;
++	cmd_reg.bits.check_response_crc = 0;
++	himci_writel(cmd_reg.cmd_arg, host->base + MCI_CMD);
++	if (himci_wait_cmd(host) != 0)
++		himci_trace(3, "disable or enable clk is timeout!");
++}
++
++static void himci_set_cclk(struct himci_host *host, unsigned int cclk)
++{
++	unsigned int reg_value = 0;
++	union cmd_arg_u clk_cmd;
++	unsigned int port = host->cur_port;
++	unsigned int hclk;
++	unsigned int clk_rate;
++	int ret;
++
++	himci_trace(2, "begin");
++	himci_assert(host);
++	himci_assert(cclk);
++
++	clk_rate = cclk > MMC_CRG_MIN ? cclk : MMC_CRG_MIN;
++	ret = clk_set_rate(host->clk, clk_rate);
++	if (ret)
++		dev_warn(mmc_dev(host->mmc),
++				"failed to set rate %uHz\n", clk_rate);
++
++	hclk = clk_get_rate(host->clk);
++
++	/*
++	 * set card clk divider value,
++	 * clk_divider = Fmmcclk/(Fmmc_cclk * 2)
++	 */
++	reg_value = hclk / (cclk * 2);
++	if ((hclk % (cclk * 2)) && (hclk > cclk))
++		reg_value++;
++	if (reg_value > 0xFF)
++		reg_value = 0xFF;
++
++	host->hclk = hclk;
++	host->cclk = reg_value ? (hclk / (reg_value * 2)) : hclk;
++	himci_writel(reg_value, host->base + MCI_CLKDIV);
++	clk_cmd.cmd_arg = himci_readl(host->base + MCI_CMD);
++	clk_cmd.bits.start_cmd = 1;
++	clk_cmd.bits.card_number = port;
++	clk_cmd.bits.update_clk_reg_only = 1;
++	clk_cmd.bits.cmd_index = 0;
++	clk_cmd.bits.data_transfer_expected = 0;
++	clk_cmd.bits.response_expect = 0;
++	himci_writel(clk_cmd.cmd_arg, host->base + MCI_CMD);
++	if (himci_wait_cmd(host) != 0)
++		himci_trace(3, "set card clk divider is failed!");
++}
++
++static void himci_pre_init_host(struct himci_host *host)
++{
++#if !defined(CONFIG_ARCH_HI3516CV300)
++	unsigned int shift[] = {13, 5, 21};
++	unsigned int reg;
++
++	reg = himci_readl(PERI_CRG49);
++	reg |= 0x1 << shift[host->devid];
++	himci_writel(reg, PERI_CRG49);
++
++	if (!(host->mmc->caps & MMC_CAP_SD_HIGHSPEED)) {
++		himci_writel(0x10, EMMC_DLL_CTRL);
++		reg = himci_readl(PERI_CRG49);
++		reg |= 0x1 << 22;
++		himci_writel(reg, PERI_CRG49);
++	}
++#endif
++}
++
++static void himci_init_host(struct himci_host *host)
++{
++	unsigned int tmp_reg = 0;
++	struct mmc_host *mmc;
++
++	himci_trace(3, "begin init card");
++	himci_assert(host);
++
++	mmc = host->mmc;
++	host->error_count = 0;
++	/* controller config gpio */
++	himci_writel(CMD_OUT_EN_FIX_BYPASS | DTO_FIX_BYPASS,
++			host->base + MCI_GPIO);
++
++	himciv200_sys_reset(host);
++
++	himci_pre_init_host(host);
++
++	/* set drv/smpl phase shift */
++	if (mmc->caps & MMC_CAP_HW_RESET)
++		tmp_reg |= EMMC_SMPL_PHASE_DFLT | EMMC_DRV_PHASE_DFLT;
++	else
++		tmp_reg |= SMPL_PHASE_DFLT | DRV_PHASE_DFLT;
++
++	himci_writel(tmp_reg, host->base + MCI_UHS_REG_EXT);
++
++	/* set card read threshold */
++	himci_writel(RW_THRESHOLD_SIZE, host->base + MCI_CARDTHRCTL);
++
++	/* clear MMC host intr */
++	himci_writel(ALL_INT_CLR, host->base + MCI_RINTSTS);
++	tmp_reg = himci_readl(host->base + MCI_IDSTS);
++	tmp_reg |= ALL_ADMA_INT_CLR;
++	himci_writel(tmp_reg, host->base + MCI_IDSTS);
++
++	/* MASK MMC all host intr */
++	tmp_reg = himci_readl(host->base + MCI_INTMASK);
++	tmp_reg &= ~ALL_INT_MASK;
++	himci_writel(tmp_reg, host->base + MCI_INTMASK);
++
++	/* enable inner DMA mode and close intr of MMC host controller */
++	tmp_reg = himci_readl(host->base + MCI_CTRL);
++	tmp_reg &= ~INTR_EN;
++	tmp_reg |= USE_INTERNAL_DMA | INTR_EN;
++	himci_writel(tmp_reg, host->base + MCI_CTRL);
++
++	/* set timeout param */
++	himci_writel(DATA_TIMEOUT | RESPONSE_TIMEOUT, host->base + MCI_TIMEOUT);
++
++	/* set FIFO param */
++	tmp_reg = 0;
++	tmp_reg |= BURST_SIZE | RX_WMARK | TX_WMARK;
++	himci_writel(tmp_reg, host->base + MCI_FIFOTH);
++
++	/* ADMA3: disable ADMA Func */
++	himci_writel(0x0, host->base + ADMA_CTRL);
++
++	/* ADMA3: set entire des addr and quene deepth  */
++	himci_writel(host->entire_paddr, host->base + ADMA_Q_ADDR); /* */
++	himci_writel(ADMA_QUEUE_DEEPTH, host->base + ADMA_Q_DEEPTH);
++
++	/* ADMA3: reset queue read/write ptr */
++	tmp_reg = himci_readl(host->base + ADMA_CTRL);
++	tmp_reg |= RDPTR_MOD_EN;
++	himci_writel(tmp_reg, host->base + ADMA_CTRL);
++	himci_writel(0x0, host->base + ADMA_Q_RDPTR);
++	himci_writel(0x0, host->base + ADMA_Q_WRPTR);
++	tmp_reg = himci_readl(host->base + ADMA_CTRL);
++	tmp_reg &= ~RDPTR_MOD_EN;
++	himci_writel(tmp_reg, host->base + ADMA_CTRL);
++
++	/* ADMA3: set queue timeout value */
++	himci_writel(0xffffffff, host->base + ADMA_Q_TO);
++
++	/* ADMA3: enable ADMA intr */
++	tmp_reg = (CMD_LOCK_ERR | OWNBIT_ERR | QUEUE_OVERFLOW
++			| RESP_CHECK_ERR | PACKET_INT | PACKET_TO_INT
++			| AUTO_STOP_ERR | QUEUE_FULL | CES | DU | FBE);
++
++	himci_writel(tmp_reg, host->base + MCI_IDINTEN);
++	/* ADMA3: clear ADMA3 intr */
++	tmp_reg = (CMD_LOCK_ERR | OWNBIT_ERR | QUEUE_OVERFLOW
++			| RESP_CHECK_ERR | PACKET_INT | PACKET_TO_INT
++			| AUTO_STOP_ERR | QUEUE_FULL | QUEUE_EMPTY | CES
++			| DU | FBE);
++	himci_writel(tmp_reg, host->base + MCI_IDSTS);
++
++	/* ADMA3: enable ADMA Func */
++	tmp_reg = PACKET_INT_EN | ADMA3_EN;
++	himci_writel(tmp_reg, host->base + ADMA_CTRL);
++
++	himci_idma_start(host);
++	host->mmc->status = MMC_HOST_OK;
++}
++
++void himci_sw_reset(struct mmc_host *mmc)
++{
++	struct himci_host *host = mmc_priv(mmc);
++	int i;
++
++	clk_prepare_enable(host->clk);
++	himci_init_host(host);
++
++	for (i = 0; i < ADMA_QUEUE_DEEPTH ; i++)
++		host->pmrq[i] = NULL;
++}
++
++static void himci_detect_card(unsigned long arg)
++{
++	struct himci_host *host = (struct himci_host *)arg;
++	unsigned int i, curr_status, status[3], detect_retry_count = 0;
++
++	himci_assert(host);
++
++	while (1) {
++		for (i = 0; i < 3; i++) {
++			status[i] = himci_sys_card_detect(host);
++			udelay(10);
++		}
++		if ((status[0] == status[1]) && (status[0] == status[2]))
++			break;
++		detect_retry_count++;
++		if (detect_retry_count >= retry_count) {
++			himci_error("this is a dithering, card detect error!");
++			goto err;
++		}
++	}
++	curr_status = status[0];
++	if (curr_status != host->card_status) {
++		himci_trace(2, "begin card_status = %d\n", host->card_status);
++		host->card_status = curr_status;
++		if (curr_status != CARD_UNPLUGED) {
++			himci_init_host(host);
++			pr_info("card connected!\n");
++		} else {
++			pr_info("card disconnected!\n");
++			host->mmc->status = MMC_HOST_ERR;
++		}
++
++		mmc_detect_change(host->mmc, 0);
++	}
++err:
++	mod_timer(&host->timer, jiffies + detect_time);
++}
++
++static int himci_prep_data(struct himci_host *host, struct mmc_data *data)
++{
++	unsigned int sg_phyaddr, sg_length;
++	unsigned int i, ret = 0;
++	unsigned int data_size;
++	unsigned int max_des, des_cnt;
++	struct himci_dma_des *dma_des;
++	struct himci_dma_des *des;
++	unsigned int *dma_paddr;
++	unsigned int dma_dir;
++
++	himci_trace(2, "begin");
++	himci_assert(host);
++	himci_assert(data);
++
++	host->data = data;
++
++	if (data->flags & MMC_DATA_READ)
++		dma_dir = DMA_FROM_DEVICE;
++	else
++		dma_dir = DMA_TO_DEVICE;
++
++	host->dma_sg = data->sg;
++	host->dma_sg_num = dma_map_sg(mmc_dev(host->mmc), data->sg,
++				      data->sg_len, dma_dir);
++	himci_assert(host->dma_sg_num);
++	himci_trace(2, "sg_num is %d\n", host->dma_sg_num);
++
++	data_size = data->blksz * data->blocks;
++	if (data_size > (DMA_BUFFER * MAX_DMA_DES)) {
++		himci_error("mci request data_size is too big!\n");
++		ret = -1;
++		goto out;
++	}
++
++	himci_trace(2, "host->dma_paddr is 0x%08X,host->dma_addr is 0x%08X\n",
++		    (unsigned int)host->dma_paddr,
++		    (unsigned int)host->dma_addr);
++
++	max_des = PERF_OPT_RATIO * PAGE_SIZE / sizeof(struct himci_dma_des) - 1;
++
++	/* dma descriptor is followed by cmd descriptor */
++	dma_des = (struct himci_dma_des *)(host->wr_cmd_des + 1);
++	dma_paddr = (unsigned int *)(host->cmd_paddr + PERF_OPT_RATIO * PAGE_SIZE * host->wr_pos
++			+ sizeof(struct himci_cmd_des));
++
++	des = dma_des;
++	des_cnt = 0;
++
++	for (i = 0; i < host->dma_sg_num; i++) {
++		sg_length = sg_dma_len(&data->sg[i]);
++		sg_phyaddr = sg_dma_address(&data->sg[i]);
++		himci_trace(2, "sg[%d] sg_length is 0x%08X,"
++			" sg_phyaddr is 0x%08X\n",
++			i,
++			(unsigned int)sg_length, (unsigned int)sg_phyaddr);
++		while (sg_length) {
++			des[des_cnt].idmac_des_ctrl =
++				DMA_DES_OWN | DMA_DES_NEXT_DES;
++			des[des_cnt].idmac_des_buf_addr = sg_phyaddr;
++			/* idmac_des_next_addr is paddr for dma */
++			des[des_cnt].idmac_des_next_addr = (unsigned long)
++				(dma_paddr + (des_cnt + 1) * 4);
++
++			/* buffer size <= 4k */
++			if (sg_length >= 0x1000) {
++				des[des_cnt].idmac_des_buf_size = 0x1000;
++				sg_length -= 0x1000;
++				sg_phyaddr += 0x1000;
++			} else {
++				/* data alignment */
++				des[des_cnt].idmac_des_buf_size = sg_length;
++				sg_length = 0;
++			}
++			himci_trace(2, "des[%d] vaddr  is 0x%08X",
++				des_cnt, (unsigned int)&des[des_cnt]);
++			himci_trace(2, "des[%d].idmac_des_ctrl is 0x%08X",
++				des_cnt, (unsigned int)
++				des[des_cnt].idmac_des_ctrl);
++			himci_trace(2, "des[%d].idmac_des_buf_size is 0x%08X",
++				des_cnt, (unsigned int)
++				des[des_cnt].idmac_des_buf_size);
++			himci_trace(2, "des[%d].idmac_des_buf_addr 0x%08X",
++				des_cnt,
++				(unsigned int)des[des_cnt].idmac_des_buf_addr);
++			himci_trace(2, "des[%d].idmac_des_next_addr is 0x%08X",
++				des_cnt, (unsigned int)
++				des[des_cnt].idmac_des_next_addr);
++			des_cnt++;
++		}
++
++		himci_assert(des_cnt < max_des);
++	}
++	des[0].idmac_des_ctrl |= DMA_DES_FIRST_DES;
++	des[des_cnt - 1].idmac_des_ctrl |= DMA_DES_LAST_DES;
++	des[des_cnt - 1].idmac_des_next_addr = 0;
++	himci_trace(2, "des[%d].idmac_des_ctrl is 0x%08X",
++			des_cnt-1, (unsigned int)des[des_cnt-1].idmac_des_ctrl);
++out:
++	return ret;
++}
++
++static int himci_prep_cmd(struct himci_host *host, struct mmc_command *cmd,
++		struct mmc_data *data)
++{
++	volatile union cmd_arg_u cmd_regs;
++	unsigned int port = host->cur_port;
++	struct himci_cmd_des *cmd_des;
++
++	himci_trace(2, "begin");
++	himci_assert(host);
++	himci_assert(cmd);
++
++	host->cmd = cmd;
++
++	cmd_des = host->wr_cmd_des;
++	cmd_des->arg = cmd->arg;
++
++	himci_trace(3, "arg_reg 0x%x, val 0x%x\n", MCI_CMDARG, cmd->arg);
++	cmd_regs.cmd_arg = DEFAULT_CMD_VALUE;
++	if (data) {
++		cmd_regs.bits.data_transfer_expected = 1;
++		if (data->flags & (MMC_DATA_WRITE | MMC_DATA_READ))
++			cmd_regs.bits.transfer_mode = 0;
++		if (data->flags & MMC_DATA_STREAM)
++			cmd_regs.bits.transfer_mode = 1;
++		if (data->flags & MMC_DATA_WRITE)
++			cmd_regs.bits.read_write = 1;
++		else if (data->flags & MMC_DATA_READ)
++			cmd_regs.bits.read_write = 0;
++	} else {
++		cmd_regs.bits.data_transfer_expected = 0;
++		cmd_regs.bits.transfer_mode = 0;
++		cmd_regs.bits.read_write = 0;
++	}
++
++#ifdef CONFIG_SEND_AUTO_STOP
++	if (host->mrq->stop)
++		cmd_regs.bits.send_auto_stop = 1;
++#endif
++
++	if (cmd->opcode == MMC_STOP_TRANSMISSION) {
++		cmd_regs.bits.stop_abort_cmd = 1;
++		cmd_regs.bits.wait_prvdata_complete = 0;
++	} else {
++		cmd_regs.bits.stop_abort_cmd = 0;
++		cmd_regs.bits.wait_prvdata_complete = 1;
++	}
++
++	switch (mmc_resp_type(cmd)) {
++	case MMC_RSP_NONE:
++		cmd_regs.bits.response_expect = 0;
++		cmd_regs.bits.response_length = 0;
++		cmd_regs.bits.check_response_crc = 0;
++		break;
++	case MMC_RSP_R1:
++	case MMC_RSP_R1B:
++		cmd_regs.bits.response_expect = 1;
++		cmd_regs.bits.response_length = 0;
++		cmd_regs.bits.check_response_crc = 1;
++		break;
++	case MMC_RSP_R2:
++		cmd_regs.bits.response_expect = 1;
++		cmd_regs.bits.response_length = 1;
++		cmd_regs.bits.check_response_crc = 1;
++		break;
++	case MMC_RSP_R3:
++	case MMC_RSP_R1 & (~MMC_RSP_CRC):
++		cmd_regs.bits.response_expect = 1;
++		cmd_regs.bits.response_length = 0;
++		cmd_regs.bits.check_response_crc = 0;
++		break;
++	default:
++		host->cmd->error = -EINVAL;
++		himci_error("himci: unhandled response type %02x\n",
++				mmc_resp_type(cmd));
++		return -EINVAL;
++	}
++
++	himci_trace(4, "cmd->opcode = %d cmd->arg = 0x%X\n",
++			cmd->opcode, cmd->arg);
++
++	if (cmd->opcode == SD_SWITCH_VOLTAGE)
++		cmd_regs.bits.volt_switch = 1;
++	else
++		cmd_regs.bits.volt_switch = 0;
++
++	cmd_regs.bits.send_initialization = 1;
++	cmd_regs.bits.card_number = port;
++	cmd_regs.bits.cmd_index = cmd->opcode;
++	cmd_regs.bits.start_cmd = 1;
++	cmd_regs.bits.update_clk_reg_only = 0;
++
++	cmd_des->cmd = cmd_regs.cmd_arg;
++
++	himci_trace(4, "cmd_reg 0x%x, val 0x%x\n", MCI_CMD, cmd_regs.cmd_arg);
++
++	return 0;
++}
++
++static void himci_data_done(struct mmc_host *host,
++		struct mmc_request *mrq, int err)
++{
++	struct mmc_data *data = mrq->data;
++	unsigned int dma_dir;
++
++	if (!data)
++		return;
++	if (data->flags & MMC_DATA_READ)
++		dma_dir = DMA_FROM_DEVICE;
++	else
++		dma_dir = DMA_TO_DEVICE;
++	dma_unmap_sg(mmc_dev(host), data->sg, data->sg_len, dma_dir);
++
++	if (!data->error)
++		data->bytes_xfered = data->blocks * data->blksz;
++	else
++		data->bytes_xfered = 0;
++
++}
++
++static void himci_finish_request(struct himci_host *host,
++				  struct mmc_request *mrq)
++{
++	himci_trace(2, "begin");
++	himci_assert(host);
++	himci_assert(mrq);
++
++	himci_data_done(host->mmc, mrq, 0);
++	mmc_request_done(host->mmc, mrq);
++}
++
++static void himci_cmd_done(struct mmc_request *mrq, unsigned int stat)
++{
++	struct mmc_command *cmd = mrq->cmd;
++
++	himci_trace(2, "begin");
++	himci_assert(cmd);
++
++	if (stat & RTO_INT_STATUS) {
++		cmd->error = -ETIMEDOUT;
++		himci_trace(3, "irq cmd status stat = 0x%x is timeout error!",
++			stat);
++	} else if (stat & (RCRC_INT_STATUS | RE_INT_STATUS)) {
++		cmd->error = -EILSEQ;
++		himci_error("irq cmd status stat = 0x%x is response error!",
++			stat);
++	}
++}
++
++#define CMD_ERRORS                          \
++	(R1_OUT_OF_RANGE |  /* Command argument out of range */ \
++	 R1_ADDRESS_ERROR | /* Misaligned address */        \
++	 R1_BLOCK_LEN_ERROR |   /* Transferred block length incorrect */\
++	 R1_WP_VIOLATION |  /* Tried to write to protected block */ \
++	 R1_CC_ERROR |      /* Card controller error */     \
++	 R1_ERROR)      /* General/unknown error */
++
++static void himci_read_response(struct himci_host *host,
++		struct mmc_command *cmd)
++{
++	/* Read response of the card */
++	if (cmd->flags & MMC_RSP_PRESENT) {
++		if (cmd->flags & MMC_RSP_136) {
++			cmd->resp[3] = himci_readl(host->base + MCI_RESP0);
++			cmd->resp[2] = himci_readl(host->base + MCI_RESP1);
++			cmd->resp[1] = himci_readl(host->base + MCI_RESP2);
++			cmd->resp[0] = himci_readl(host->base + MCI_RESP3);
++		} else {
++			cmd->resp[0] = himci_readl(host->base + MCI_RESP0);
++			cmd->resp[1] = 0;
++			cmd->resp[2] = 0;
++			cmd->resp[3] = 0;
++		}
++	}
++	if ((cmd->flags & MMC_CMD_TYPE_RW) && (cmd->resp[0] & CMD_ERRORS))
++		host->error_count++;
++}
++
++static void himci_reset_host(struct himci_host *host)
++{
++	unsigned int i = 0, reg_value;
++
++	/* DMA Controller resets */
++	reg_value = himci_readl(host->base + ADMA_CTRL);
++	reg_value &= ~(ADMA3_EN);
++	himci_writel(reg_value, host->base + ADMA_CTRL);
++	reg_value = himci_readl(host->base + MCI_BMOD);
++	reg_value |= BMOD_SWR;
++	himci_writel(reg_value, host->base + MCI_BMOD);
++	himci_writel(0xFFFFFFFF, host->base + MCI_IDSTS);
++
++	/* ADMA3: reset queue R/W ptr */
++	reg_value = himci_readl(host->base + ADMA_CTRL);
++	reg_value |= (RDPTR_MOD_EN);
++	reg_value &= ~(ADMA3_EN);
++	himci_writel(reg_value, host->base + ADMA_CTRL);
++	himci_writel(0, host->base + ADMA_Q_WRPTR);
++	himci_writel(0, host->base + ADMA_Q_RDPTR);
++	for (i = 0; i < ADMA_QUEUE_DEEPTH ; i++)
++		host->pmrq[i] = NULL;
++
++	himci_writel(0xFFFFFFFF, host->base + MCI_RINTSTS);
++	udelay(800);
++
++	reg_value = himci_readl(host->base + ADMA_CTRL);
++	reg_value &= ~RDPTR_MOD_EN;
++	reg_value |= (ADMA3_EN);
++	himci_writel(reg_value, host->base + ADMA_CTRL);
++
++	/* ADMA3: restart */
++	reg_value = himci_readl(host->base + ADMA_CTRL);
++	reg_value |= ADMA3_RESTART;
++	himci_writel(reg_value, host->base + ADMA_CTRL);
++
++	/* dma enable */
++	himci_idma_start(host);
++}
++
++static void himci_err_check(struct himci_host *host,
++		unsigned int qstat, unsigned int rstat,
++		unsigned int *cmd_err, unsigned int *data_err)
++{
++	*cmd_err = 0;
++	*data_err = 0;
++
++	if (!(qstat & (ADMA_INT_ERR | CES)))
++		return;
++
++	if (qstat & ADMA_INT_ERR) {
++		himci_trace(4, "ADMA err! qstat:%x rstat:%x\n", qstat, rstat);
++		*cmd_err = -ETIMEDOUT;
++	}
++
++	if (qstat & CES) {
++		himci_trace(4, "CES err! qstat:%x rstat:%x\n", qstat, rstat);
++		if (rstat & RTO_INT_STATUS) {
++			himci_trace(3, "response timeout error!");
++			*cmd_err = -ETIMEDOUT;
++		} else if (rstat & (RCRC_INT_STATUS | RE_INT_STATUS)) {
++			himci_trace(3, "response crc error!");
++			*cmd_err = -EILSEQ;
++		}
++
++		if (rstat & (HTO_INT_STATUS | DRTO_INT_STATUS)) {
++			himci_trace(3, "data transfer timeout error!");
++			*data_err = -ETIMEDOUT;
++		} else if (rstat & (EBE_INT_STATUS | SBE_INT_STATUS |
++					FRUN_INT_STATUS | DCRC_INT_STATUS)) {
++			himci_trace(3, "data transfer error!");
++			*data_err = -EILSEQ;
++		}
++	}
++
++	if (*cmd_err || *data_err)
++		himci_reset_host(host);
++}
++
++static int himci_wait_voltage_switch(struct himci_host *host)
++{
++	unsigned int cmd_retry_count = 0;
++	unsigned long cmd_jiffies_timeout;
++	unsigned int cmd_irq_reg = 0;
++	struct mmc_command *cmd = host->cmd;
++	unsigned long flags;
++
++	himci_trace(2, "begin");
++	himci_assert(host);
++	himci_assert(cmd);
++
++	himci_trace(3, "wait voltage switch...");
++	cmd_jiffies_timeout = jiffies + request_timeout;
++	while (1) {
++		do {
++			spin_lock_irqsave(&host->lock, flags);
++			cmd_irq_reg = himci_readl(host->base + MCI_RINTSTS);
++			if (cmd_irq_reg & VOLT_SWITCH_INT_STATUS) {
++				himci_writel(VOLT_SWITCH_INT_STATUS,
++						host->base + MCI_RINTSTS);
++				spin_unlock_irqrestore(&host->lock, flags);
++				himci_cmd_done(host->mrq, cmd_irq_reg);
++				goto switch_succeed;
++			}
++			spin_unlock_irqrestore(&host->lock, flags);
++			cmd_retry_count++;
++		} while (cmd_retry_count < retry_count);
++		cmd_retry_count = 0;
++
++		if (host->card_status == CARD_UNPLUGED) {
++			cmd->error = -ETIMEDOUT;
++			return -1;
++		}
++
++		if (!time_before(jiffies, cmd_jiffies_timeout)) {
++			unsigned int i = 0;
++
++			for (i = 0; i < 4; i++) {
++				cmd->resp[i] = himci_readl(host->base
++						+ MCI_RESP0 + i * 0x4);
++			}
++			cmd->error = -ETIMEDOUT;
++			himci_trace(3, "wait cmd request complete is timeout!");
++			return -1;
++		}
++
++		schedule();
++	}
++switch_succeed:
++	/* bugfix: synopsys will trigger sdio intr when send cmd11,
++	 * it's a bug and must be cleared
++	 */
++	himci_writel(SDIO_INT_STATUS, host->base + MCI_RINTSTS);
++	return 0;
++}
++
++/* Prepare the entire descriptor */
++static void himci_prep_entire(struct himci_host *host,
++		struct mmc_request *mrq)
++{
++	struct himci_entire_des	*ent_des;
++	struct himci_cmd_des	*cmd_des;
++	unsigned int wr_pos;
++
++	wr_pos = himci_readl(host->base + ADMA_Q_WRPTR);
++	mrq->wr_pos = wr_pos;		/* only for ADMA3 R/W */
++	host->pmrq[wr_pos] = mrq;	/* save send mrq */
++	host->wr_pos = wr_pos;
++
++	himci_trace(3, "write des to position %d", wr_pos);
++	/* select entire descriptor */
++	ent_des = (struct himci_entire_des *)(host->entire_addr);
++	ent_des = ent_des + wr_pos;
++	host->wr_ent_des = ent_des;
++
++	/* config entire descriptor */
++	ent_des->cmd_des_addr = host->cmd_paddr + PERF_OPT_RATIO * PAGE_SIZE * wr_pos;
++
++	if ((host->cmd->flags & MMC_CMD_NON_BLOCKING)
++			|| (mrq->cmd->opcode == SD_SWITCH_VOLTAGE)) {
++		/* non-blocking command needn't issue intr */
++		himci_trace(2, "command is non-blocking");
++		ent_des->ctrl = 0x80000000;
++	} else {
++		himci_trace(2, "command is block");
++		ent_des->ctrl = 0xa0000000;
++	}
++	himci_trace(2, "ent des addr: 0x%x", host->entire_paddr
++			+ sizeof(struct himci_entire_des) * wr_pos);
++
++	/* select command descriptor */
++	cmd_des = (struct himci_cmd_des *)(host->cmd_addr);
++	cmd_des = cmd_des + (PERF_OPT_RATIO * 256 * wr_pos);
++	host->wr_cmd_des = cmd_des;
++}
++
++static void himci_request(struct mmc_host *mmc, struct mmc_request *mrq)
++{
++	struct himci_host *host = mmc_priv(mmc);
++	unsigned int byte_cnt = 0;
++	unsigned int status;
++	int ret = 0, i = 0;
++	struct himci_cmd_des	*cmd_des;
++	unsigned int rd_pos;
++
++	himci_trace(2, "begin");
++	himci_assert(mmc);
++	himci_assert(mrq);
++	himci_assert(host);
++
++	host->mrq = mrq;
++	host->cmd = mrq->cmd;
++	host->data = mrq->data;
++
++	/* prepare entire des */
++	himci_prep_entire(host, mrq);
++	cmd_des = host->wr_cmd_des;
++
++	/* prepare data des */
++	if (mrq->data) {
++		ret = himci_prep_data(host, mrq->data);
++		if (ret) {
++			mrq->data->error = ret;
++			himci_trace(3, "data setup is error!");
++			goto request_done;
++		}
++
++		byte_cnt = mrq->data->blksz * mrq->data->blocks;
++		cmd_des->blk_sz	= mrq->data->blksz;
++		cmd_des->byte_cnt = byte_cnt;
++		himci_trace(3, "blk_sz:%d blk_cnt:%d",
++				mrq->data->blksz, mrq->data->blocks);
++	} else {
++		cmd_des->blk_sz	= 0;
++		cmd_des->byte_cnt = 0;
++	}
++
++	/* prepare command des */
++	ret = himci_prep_cmd(host, mrq->cmd, mrq->data);
++	if (ret)
++		goto request_done;
++
++	if (mmc->caps & MMC_CAP_SD_HIGHSPEED) {
++		status = himci_sys_card_detect(host);
++		if (status == CARD_UNPLUGED) {
++			for (i = 0; i < ADMA_QUEUE_DEEPTH ; i++)
++				host->pmrq[i] = NULL;
++			host->cmd->error = -ETIMEDOUT;
++			if (host->cmd->flags & MMC_CMD_TYPE_RW)
++				host->mmc->status = MMC_HOST_ERR;
++			goto request_done;
++		}
++	}
++
++	/* update des write pointer */
++	host->wr_pos++;
++	host->wr_pos %= ADMA_QUEUE_DEEPTH;
++	himci_writel(host->wr_pos, host->base + ADMA_Q_WRPTR);
++
++	if (host->cmd->opcode == SD_SWITCH_VOLTAGE) {
++		ret = himci_wait_voltage_switch(host);
++		if (ret)
++			himci_trace(5, "voltage switch failed!");
++		rd_pos = host->wr_pos ? host->wr_pos - 1
++			: ADMA_QUEUE_DEEPTH - 1;
++		host->pmrq[rd_pos] = NULL;
++		goto request_done;
++	}
++
++	if (!(host->cmd->flags & MMC_CMD_TYPE_RW)) {
++		long time;
++
++		time = wait_event_timeout(host->intr_wait, host->cmd_done, HZ);
++		if (time <= 0) {
++			unsigned int rstat;
++			unsigned int qstat;
++			unsigned int cmd_err;
++			unsigned int data_err;
++
++			rstat = himci_readl(host->base + MCI_RINTSTS);
++			qstat = himci_readl(host->base + MCI_IDSTS);
++			himci_err_check(host, qstat, rstat,
++					&cmd_err, &data_err);
++			mrq->cmd->error = -ETIMEDOUT;
++			himci_trace(5, "CMD%u wait event timeout", mrq->cmd->opcode);
++		}
++
++		host->cmd_done = 0;
++		rd_pos = host->wr_pos ? host->wr_pos - 1
++			: ADMA_QUEUE_DEEPTH - 1;
++		host->pmrq[rd_pos] = NULL;
++		himci_read_response(host, mrq->cmd);
++		goto request_done;
++	}
++	return;
++
++request_done:
++	himci_finish_request(host, mrq);
++}
++
++static int himci_do_voltage_switch(struct himci_host *host,
++						 struct mmc_ios *ios)
++{
++	struct mmc_host *mmc = host->mmc;
++	u32 ctrl;
++	unsigned int port = host->cur_port;
++	/*
++	 * We first check whether the request is to set signalling voltage
++	 * to 3.3V. If so, we change the voltage to 3.3V and return quickly.
++	 */
++	ctrl = himci_readl(host->base + MCI_UHS_REG);
++	if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
++		/* Set 1.8V Signal Enable in the MCI_UHS_REG to 1 */
++		himci_trace(3, "switch voltage 330");
++		ctrl &= ~(HI_SDXC_CTRL_VDD_180 << port);
++		himci_writel(ctrl, host->base + MCI_UHS_REG);
++
++		/* Wait for 5ms */
++		usleep_range(5000, 5500);
++
++		/* 3.3V regulator output should be stable within 5ms */
++		ctrl = himci_readl(host->base + MCI_UHS_REG);
++		if (!(ctrl & (HI_SDXC_CTRL_VDD_180 << port))) {
++			return 0;
++		} else {
++			himci_error(": Switching to 3.3V ");
++			himci_error("signalling voltage failed\n");
++			return -EIO;
++		}
++	} else if (!(ctrl & (HI_SDXC_CTRL_VDD_180 << port)) &&
++		(ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180)) {
++		/* Stop SDCLK */
++		himci_trace(3, "switch voltage 180");
++		himci_control_cclk(host, DISABLE);
++
++		/*
++		 * Enable 1.8V Signal Enable in the MCI_UHS_REG
++		 */
++		ctrl |= (HI_SDXC_CTRL_VDD_180 << port);
++		himci_writel(ctrl, host->base + MCI_UHS_REG);
++
++		/* Wait for 8ms */
++		usleep_range(8000, 8500);
++
++		ctrl = himci_readl(host->base + MCI_UHS_REG);
++		if (ctrl & (HI_SDXC_CTRL_VDD_180 << port)) {
++			/* Provide SDCLK again and wait for 1ms */
++			himci_control_cclk(host, ENABLE);
++			usleep_range(1000, 1500);
++
++			if (mmc->caps2 & MMC_CAP2_HS200) {
++				/* eMMC needn't to check the int status*/
++				return 0;
++			}
++			/*
++			 * If CMD11 return CMD down, then the card
++			 * was successfully switched to 1.8V signaling.
++			 */
++			ctrl = himci_readl(host->base + MCI_RINTSTS);
++			if ((ctrl & VOLT_SWITCH_INT_STATUS)
++					&& (ctrl & CD_INT_STATUS)) {
++				himci_writel(VOLT_SWITCH_INT_STATUS | CD_INT_STATUS,
++						host->base + MCI_RINTSTS);
++				return 0;
++			}
++		}
++
++		/*
++		 * If we are here, that means the switch to 1.8V signaling
++		 * failed. We power cycle the card, and retry initialization
++		 * sequence by setting S18R to 0.
++		 */
++
++		ctrl &= ~(HI_SDXC_CTRL_VDD_180 << port);
++		himci_writel(ctrl, host->base + MCI_UHS_REG);
++
++		/* Wait for 5ms */
++		usleep_range(5000, 5500);
++
++		himci_ctrl_power(host, POWER_OFF, FORCE_DISABLE);
++		/* Wait for 1ms as per the spec */
++		usleep_range(1000, 1500);
++		himci_ctrl_power(host, POWER_ON, FORCE_DISABLE);
++
++		himci_control_cclk(host, DISABLE);
++		/* Wait for 1ms as per the spec */
++		usleep_range(1000, 1500);
++		himci_control_cclk(host, ENABLE);
++
++		himci_error(": Switching to 1.8V signalling ");
++		himci_error("voltage failed, retrying with S18R set to 0\n");
++		return -EAGAIN;
++	} else
++		/* No signal voltage switch required */
++		return 0;
++}
++
++static int himci_start_signal_voltage_switch(struct mmc_host *mmc,
++					      struct mmc_ios *ios)
++{
++	struct himci_host *host = mmc_priv(mmc);
++	int err;
++
++	err = himci_do_voltage_switch(host, ios);
++	return err;
++}
++
++static int himci_send_stop(struct mmc_host *host)
++{
++	struct mmc_command cmd = {0};
++	int err;
++
++	cmd.opcode = MMC_STOP_TRANSMISSION;
++	cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
++	err = mmc_wait_for_cmd(host, &cmd, 0);
++	return err;
++}
++
++#if defined(CONFIG_ARCH_HI3516CV300)
++static void himci_edge_tuning_enable(struct himci_host *host)
++{
++	unsigned int val;
++
++	val = himci_readl(host->base + MCI_TUNING_CTRL);
++	val |= HW_TUNING_EN;
++	himci_writel(val, host->base + MCI_TUNING_CTRL);
++}
++
++static void himci_edge_tuning_disable(struct himci_host *host)
++{
++	unsigned int val;
++
++	val = himci_readl(host->base + MCI_TUNING_CTRL);
++	val &= ~HW_TUNING_EN;
++	himci_writel(val, host->base + MCI_TUNING_CTRL);
++}
++
++static void himci_set_sap_phase(struct himci_host *host, u32 phase)
++{
++	unsigned int val;
++	unsigned int phase_a;
++
++	phase_a = phase >= 2 ? phase - 2 : phase + 6;
++	val = himci_readl(host->base + MCI_UHS_REG_EXT);
++	val &= ~(CLK_SMPL_PHS_MASK | CLK_SMPLA_PHS_MASK);
++	val |= (phase << CLK_SMPL_PHS_SHIFT) | (phase_a << CLK_SMPLA_PHS_SHIFT);
++	himci_writel(val, host->base + MCI_UHS_REG_EXT);
++	val = himci_readl(host->base + MCI_UHS_REG_EXT);
++}
++
++static int himci_execute_edge_tuning(struct mmc_host *mmc, u32 opcode)
++{
++	struct himci_host *host = mmc_priv(mmc);
++	unsigned int index, val;
++	unsigned int found = 0, prev_found = 0, prev_point = 0;
++	unsigned int start_point = NOT_FOUND, end_point = NOT_FOUND;
++	unsigned int phase = 0;
++
++	himci_trace(3, "begin");
++
++	himci_edge_tuning_enable(host);
++
++	for (index = 0; index < HIMCI_PHASE_SCALE; index++) {
++		himci_set_sap_phase(host, index);
++
++		mmc_send_tuning(mmc, opcode, NULL);
++
++		himci_send_stop(mmc);
++
++		val = himci_readl(host->base + MCI_TUNING_CTRL);
++		found = val & FOUND_EDGE;
++
++		himci_trace(3, "try phase:%02d, found:0x%x\n", index, found);
++
++		if (prev_found && !found) {
++			end_point = prev_point;
++		} else if (!prev_found && found) {
++			if (index != 0)
++				start_point = index;
++		}
++		if ((start_point != NOT_FOUND) && (end_point != NOT_FOUND))
++			goto scan_out;
++
++		prev_point = index;
++		prev_found = found;
++		found = 0;
++	}
++
++scan_out:
++	if ((start_point == NOT_FOUND) && (end_point == NOT_FOUND)) {
++		himci_trace(5, "%s: no valid phase shift! use default",
++				mmc_hostname(mmc));
++		return 0;
++	}
++
++	if (start_point == NOT_FOUND)
++		start_point = end_point;
++
++	if (end_point == NOT_FOUND)
++		end_point = start_point;
++
++	pr_info("tuning %s: found edge on (s:%d, e:%d)",
++			mmc_hostname(mmc), start_point, end_point);
++
++	if (start_point > end_point)
++		end_point += HIMCI_PHASE_SCALE;
++
++	phase = ((start_point + end_point) / 2) % HIMCI_PHASE_SCALE;
++
++	phase += HIMCI_PHASE_SCALE / 2;
++	phase %= HIMCI_PHASE_SCALE;
++
++	himci_set_sap_phase(host, phase);
++
++	himci_edge_tuning_disable(host);
++
++	himci_writel(ALL_INT_CLR, host->base + MCI_RINTSTS);
++
++	pr_info("determing final phase %d\n", phase);
++
++	return 0;
++}
++#else
++#if defined(CONFIG_ARCH_HI3519V101) || defined(CONFIG_ARCH_HI3559) || defined(CONFIG_ARCH_HI3556) || \
++	defined(CONFIG_ARCH_HI3516AV200)
++static int himci_set_sd_drv_strength(struct mmc_host *mmc,
++		unsigned int drv_type)
++{
++	struct mmc_request mrq = {NULL};
++	struct mmc_command cmd = {0};
++	struct mmc_data data = {0};
++	struct scatterlist sg;
++	u8 *status;
++
++	status = kmalloc(64, GFP_KERNEL);
++	if (!status)
++			return -ENOMEM;
++
++	drv_type &= 0xF;
++
++	mrq.cmd = &cmd;
++	mrq.data = &data;
++
++	cmd.opcode = SD_SWITCH;
++	cmd.arg = 0x1 << 31 | 0x00FFFFFF;
++	cmd.arg &= ~(0xF << 8);
++	cmd.arg |= drv_type << 8;
++	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
++
++	data.blksz = 64;
++	data.blocks = 1;
++	data.flags = MMC_DATA_READ;
++	data.sg = &sg;
++	data.sg_len = 1;
++
++	sg_init_one(&sg, status, 64);
++
++	mmc_wait_for_req(mmc, &mrq);
++
++	kfree(status);
++	if (cmd.error)
++		    return cmd.error;
++	if (data.error)
++		    return data.error;
++
++	return 0;
++}
++
++static int himci_set_mmc_drv_strength(struct mmc_host *mmc,
++		unsigned int drv_type)
++{
++	int err;
++	struct mmc_command cmd = {0};
++	unsigned int value;
++
++	drv_type &= 0xF;
++	value = EXT_CSD_TIMING_HS200 | (drv_type << 4);
++
++	cmd.opcode = MMC_SWITCH;
++	cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
++		(EXT_CSD_HS_TIMING << 16) |
++		(value << 8) |
++		EXT_CSD_CMD_SET_NORMAL;
++	cmd.flags = MMC_CMD_AC | MMC_RSP_SPI_R1B | MMC_RSP_R1B;
++
++	err = mmc_wait_for_cmd(mmc, &cmd, 0);
++
++	return err;
++}
++#endif
++static void himci_set_sap_phase(struct himci_host *host,
++		u32 phase, u32 hs400_tuning)
++{
++	unsigned int reg_value;
++	unsigned long flags;
++
++	spin_lock_irqsave(&host->lock, flags);
++	if (hs400_tuning) {
++		phase = (phase < 8) ? (8 - phase) : phase;
++		reg_value = himci_readl(EMMC_DLL_CTRL);
++		reg_value &= ~0xF;
++		reg_value |= phase;
++		himci_writel(reg_value, EMMC_DLL_CTRL);
++		host->dll_phase = phase;
++	} else {
++		reg_value = himci_readl(host->base + MCI_UHS_REG_EXT);
++		reg_value &= ~CLK_SMPL_PHS_MASK;
++		reg_value |= (phase << CLK_SMPL_PHS_SHIFT);
++		himci_writel(reg_value, host->base + MCI_UHS_REG_EXT);
++		host->phase = phase;
++	}
++	spin_unlock_irqrestore(&host->lock, flags);
++}
++
++/*
++ * The procedure of tuning the phase shift of sampling clock
++ *
++ * 1.Set a phase shift of 0�� on cclk_in_sample
++ * 2.Send the Tuning command to the card
++ * 3.increase the phase shift value of cclk_in_sample until the
++ *   correct sampling point is received such that the host does not
++ *   see any of the errors.
++ * 4.Mark this phase shift value as the starting point of the sampling
++ *   window.
++ * 5.increase the phase shift value of cclk_in_sample until the host
++ *   sees the errors starting to come again or the phase shift value
++ *   reaches 360��.
++ * 6.Mark the last successful phase shift value as the ending
++ *   point of the sampling window.
++ *
++ *     A window is established where the tuning block is matched.
++ * For example, for a scenario where the tuning block is received
++ * correctly for a phase shift window of 90��and 180��, then an appropriate
++ * sampling point is established as 135��. Once a sampling point is
++ * established, no errors should be visible in the tuning block.
++ *
++ */
++static int himci_execute_tuning(struct mmc_host *mmc, u32 opcode)
++{
++	struct himci_host *host;
++	unsigned int index, count;
++	unsigned int err = 0;
++	unsigned int found = 0; /* identify if we have found a valid phase */
++	unsigned int start_point;
++	unsigned int end_point;
++	unsigned int prev_err = NOT_FOUND;
++	unsigned int raise_point = NOT_FOUND;
++	unsigned int fall_point = NOT_FOUND;
++	unsigned int hs400_tuning;
++	int phase, ret, send_cmd_num = 1;
++#if defined(CONFIG_ARCH_HI3519V101) || defined(CONFIG_ARCH_HI3559) || defined(CONFIG_ARCH_HI3556) || \
++	defined(CONFIG_ARCH_HI3516AV200)
++	int retry = 0;
++#endif
++
++	if (opcode == MMC_SEND_EXT_CSD) {
++		start_point = HS400_TUNING_START_PHASE;
++		end_point = HS400_TUNING_END_PHASE;
++		hs400_tuning = 1;
++	} else {
++		start_point = TUNING_START_PHASE;
++		end_point = TUNING_END_PHASE;
++		hs400_tuning = 0;
++	}
++
++	host = mmc_priv(mmc);
++
++	himci_trace(3, "start sd3.0 phase tuning...");
++
++#if defined(CONFIG_ARCH_HI3519V101) || defined(CONFIG_ARCH_HI3559) || defined(CONFIG_ARCH_HI3556) || \
++	defined(CONFIG_ARCH_HI3516AV200)
++	if (!hs400_tuning && (mmc->caps & MMC_CAP_UHS_SDR104))
++		himci_set_sd_drv_strength(mmc, SD_STRENGTH_TYPE_C);
++try_again:
++#endif
++
++	for (index = start_point; index <= end_point; index++) {
++		/* set sample clk phase shift */
++		himci_set_sap_phase(host, index, hs400_tuning);
++
++		count = 0;
++		do {
++			if (hs400_tuning) {
++				ret = mmc_send_dll_tuning(mmc);
++			} else {
++				ret = mmc_send_tuning(mmc, opcode, NULL);
++				himci_send_stop(mmc); /* send soft_stop tail */
++			}
++
++			if (ret) {
++				himci_trace(3, "send tuning CMD%u fail! phase:%d err:%d\n",
++						opcode, index, ret);
++				err = 1;
++				break;
++			}
++			count++;
++		} while (count < send_cmd_num);
++
++		if (!err)
++			found = 1;	/* found a valid phase */
++
++		if (index > start_point) {
++			if (err && !prev_err)
++				fall_point = index - 1;
++
++			if (!err && prev_err)
++				raise_point = index;
++		}
++
++		if ((raise_point != NOT_FOUND) && (fall_point != NOT_FOUND))
++			goto tuning_out;
++
++		prev_err = err;
++		err = 0;
++	}
++
++#if defined(CONFIG_ARCH_HI3519V101) || defined(CONFIG_ARCH_HI3559) || defined(CONFIG_ARCH_HI3556) || \
++	defined(CONFIG_ARCH_HI3516AV200)
++	if ((NOT_FOUND == raise_point) && (NOT_FOUND == fall_point)
++			&& !hs400_tuning && !retry) {
++		if (mmc->caps & MMC_CAP_UHS_SDR104)
++			himci_set_sd_drv_strength(mmc, SD_STRENGTH_TYPE_D);
++		else if (mmc->caps2 & MMC_CAP2_HS200)
++			himci_set_mmc_drv_strength(mmc, MMC_STRENGTH_TYPE_3);
++
++		prev_err = NOT_FOUND;
++		send_cmd_num = 40;
++		retry = 1;
++		goto try_again;
++	}
++#endif
++
++tuning_out:
++	if (!found) {
++		himci_trace(5, "%s: no valid phase shift! use default",
++				mmc_hostname(mmc));
++		if (!hs400_tuning)
++			himci_set_sap_phase(host, DEFAULT_SMPL_PHASE, hs400_tuning);
++	} else {
++		himci_trace(3, "Tuning finished!!");
++
++		if (NOT_FOUND == raise_point)
++			raise_point = start_point;
++		if (NOT_FOUND == fall_point)
++			fall_point = end_point;
++
++		if (fall_point < raise_point) {
++#ifdef CONFIG_ARCH_HI3519
++			if (fall_point - start_point > end_point - raise_point)
++				phase = (fall_point + start_point) / 2;
++			else
++				phase = (end_point + raise_point) / 2;
++#else
++			phase = (raise_point + fall_point) / 2;
++			phase = phase - (HIMCI_PHASE_SCALE / 2);
++			phase = (phase < 0) ? (HIMCI_PHASE_SCALE + phase) : phase;
++#endif
++		} else
++			phase = (raise_point + fall_point) / 2;
++
++		himci_set_sap_phase(host, phase, hs400_tuning);
++
++		pr_info("%stuning %s: valid phase shift [%d, %d] Final Phase %d\n",
++			hs400_tuning ? "HS400 " : "", mmc_hostname(mmc),
++			raise_point, fall_point, phase);
++	}
++
++#if defined(CONFIG_ARCH_HI3519V101) || defined(CONFIG_ARCH_HI3559) || defined(CONFIG_ARCH_HI3556) || \
++	defined(CONFIG_ARCH_HI3516AV200)
++	if (retry) {
++		if (mmc->caps & MMC_CAP_UHS_SDR104)
++			himci_set_sd_drv_strength(mmc, SD_STRENGTH_TYPE_C);
++		else if (mmc->caps2 & MMC_CAP2_HS200)
++			himci_set_mmc_drv_strength(mmc, MMC_STRENGTH_TYPE_0);
++	}
++#endif
++	return 0;
++}
++#endif
++
++static void himci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
++{
++	struct himci_host *host = mmc_priv(mmc);
++	unsigned int tmp_reg;
++	unsigned int port = host->cur_port;
++	u32 ctrl = 0;
++
++	himci_trace(2, "begin");
++	himci_assert(mmc);
++	himci_assert(ios);
++	himci_assert(host);
++
++	himci_trace(3, "ios->power_mode = %d ", ios->power_mode);
++	if (!ios->clock)
++		himci_control_cclk(host, DISABLE);
++
++	switch (ios->power_mode) {
++	case MMC_POWER_OFF:
++		himci_ctrl_power(host, POWER_OFF, FORCE_DISABLE);
++		break;
++	case MMC_POWER_UP:
++	case MMC_POWER_ON:
++		himci_ctrl_power(host, POWER_ON, FORCE_DISABLE);
++		break;
++	}
++	himci_trace(3, "ios->clock = %d ", ios->clock);
++	if (ios->clock) {
++		himci_control_cclk(host, DISABLE);
++		himci_set_cclk(host, ios->clock);
++		himci_control_cclk(host, ENABLE);
++
++		/* speed mode check ,if it is DDR50 set DDR mode */
++		if (ios->timing == MMC_TIMING_UHS_DDR50) {
++			ctrl = himci_readl(host->base + MCI_UHS_REG);
++			if (!((HI_SDXC_CTRL_DDR_REG << port) & ctrl)) {
++				ctrl |= (HI_SDXC_CTRL_DDR_REG << port);
++				himci_writel(ctrl, host->base + MCI_UHS_REG);
++			}
++		}
++
++		if (ios->timing == MMC_TIMING_MMC_HS400) {
++			ctrl = himci_readl(host->base + MCI_EMMC_DDR_REG);
++			if (!(HI_EMMC_HS400_MODE & ctrl)) {
++				ctrl |= HI_EMMC_HS400_MODE;
++				himci_writel(ctrl,
++					host->base + MCI_EMMC_DDR_REG);
++			}
++		}
++	} else {
++		himci_control_cclk(host, DISABLE);
++		if (ios->timing != MMC_TIMING_UHS_DDR50) {
++			ctrl = himci_readl(host->base + MCI_UHS_REG);
++			if ((HI_SDXC_CTRL_DDR_REG << port) & ctrl) {
++				ctrl &= ~(HI_SDXC_CTRL_DDR_REG << port);
++				himci_writel(ctrl, host->base + MCI_UHS_REG);
++			}
++		}
++
++		if (ios->timing != MMC_TIMING_MMC_HS400) {
++			ctrl = himci_readl(host->base + MCI_EMMC_DDR_REG);
++			if (HI_EMMC_HS400_MODE & ctrl) {
++				ctrl &= ~HI_EMMC_HS400_MODE;
++				himci_writel(ctrl,
++					host->base + MCI_EMMC_DDR_REG);
++			}
++		}
++	}
++
++	himci_set_drv_cap(host, ios);
++
++	/* set bus_width */
++	himci_trace(3, "ios->bus_width = %d ", ios->bus_width);
++
++	/* clear bus width to 1bit first */
++	tmp_reg = himci_readl(host->base + MCI_CTYPE);
++	tmp_reg &= ~((CARD_WIDTH_0 | CARD_WIDTH_1) << port);
++
++	if (ios->bus_width == MMC_BUS_WIDTH_8) {
++		tmp_reg |= (CARD_WIDTH_0 << port);
++		himci_writel(tmp_reg, host->base + MCI_CTYPE);
++	} else if (ios->bus_width == MMC_BUS_WIDTH_4) {
++		tmp_reg |= (CARD_WIDTH_1 << port);
++		himci_writel(tmp_reg, host->base + MCI_CTYPE);
++	} else {
++		himci_writel(tmp_reg, host->base + MCI_CTYPE);
++	}
++}
++
++static void himci_enable_sdio_irq(struct mmc_host *mmc, int enable)
++{
++	struct himci_host *host = mmc_priv(mmc);
++	unsigned int reg_value;
++
++	reg_value = himci_readl(host->base + MCI_INTMASK);
++	if (enable)
++		reg_value |= SDIO_INT_MASK;
++	else
++		reg_value &= ~SDIO_INT_MASK;
++	himci_writel(reg_value, host->base + MCI_INTMASK);
++}
++
++static int himci_get_card_detect(struct mmc_host *mmc)
++{
++	unsigned ret;
++	struct himci_host *host = mmc_priv(mmc);
++
++	himci_trace(2, "begin");
++	ret = himci_sys_card_detect(host);
++
++	if (ret)
++		return 0;
++	else
++		return 1;
++}
++
++static int himci_get_ro(struct mmc_host *mmc)
++{
++	unsigned ret;
++	struct himci_host *host = mmc_priv(mmc);
++
++	himci_trace(2, "begin");
++	himci_assert(mmc);
++
++	ret = himci_ctrl_card_readonly(host);
++
++	return ret;
++}
++
++static unsigned int himci_get_rdptr(struct mmc_host *mmc)
++{
++	unsigned int cur;
++	struct himci_host *host = mmc_priv(mmc);
++
++	himci_trace(2, "begin");
++	himci_assert(mmc);
++
++	cur = himci_readl(host->base + ADMA_Q_RDPTR);
++
++	return cur;
++}
++
++static void himci_hw_reset(struct mmc_host *mmc)
++{
++	unsigned int reg_value;
++	struct himci_host *host = mmc_priv(mmc);
++	unsigned int port = host->cur_port;
++
++	reg_value = himci_readl(host->base + MCI_RESET_N);
++	reg_value &= ~(MMC_RST_N << port);
++	himci_writel(reg_value, host->base + MCI_RESET_N);
++	/* For eMMC, minimum is 1us but give it 10us for good measure */
++	udelay(10);
++	reg_value = himci_readl(host->base + MCI_RESET_N);
++	reg_value |= (MMC_RST_N << port);
++	himci_writel(reg_value, host->base + MCI_RESET_N);
++	/* For eMMC, minimum is 200us but give it 300us for good measure */
++	usleep_range(300, 1000);
++}
++
++static int himci_select_drv_strength(unsigned int max_dtr,
++		int host_drv, int card_drv)
++{
++	if ((host_drv & SD_DRIVER_TYPE_C) &&
++			(card_drv & SD_DRIVER_TYPE_C))
++		return SD_STRENGTH_TYPE_C;
++	else
++		return SD_STRENGTH_TYPE_B;
++}
++
++static int himci_card_info_save(struct mmc_host *mmc)
++{
++	struct mmc_card *card = mmc->card;
++	struct himci_host * host= mmc_priv(mmc);
++	struct card_info * c_info = &host->c_info;
++
++	if (!card) {
++		memset(c_info,0,sizeof(struct card_info));
++		c_info->card_connect = CARD_DISCONNECT;
++		goto out;
++	}
++
++	c_info->card_type = card->type;
++	c_info->card_state = card->state;
++
++	c_info->timing = mmc->ios.timing;
++	c_info->card_support_clock = mmc->ios.clock;
++
++	c_info->sd_bus_speed = card->sd_bus_speed;
++
++	memcpy(c_info->ssr, card->c_ssr, ARRAY_SIZE(c_info->ssr));
++
++	c_info->card_connect = CARD_CONNECT;
++out:
++	return 0;
++}
++
++static const struct mmc_host_ops himci_ops = {
++	.request = himci_request,
++	.post_req = himci_data_done,
++	.set_ios = himci_set_ios,
++	.get_rd = himci_get_rdptr,
++	.get_ro = himci_get_ro,
++	.start_signal_voltage_switch = himci_start_signal_voltage_switch,
++#if defined(CONFIG_ARCH_HI3516CV300)
++	.execute_tuning	= himci_execute_edge_tuning,
++#else
++	.execute_tuning	= himci_execute_tuning,
++#endif
++	.enable_sdio_irq = himci_enable_sdio_irq,
++	.select_drive_strength = himci_select_drv_strength,
++	.hw_reset = himci_hw_reset,
++	.sw_reset = himci_sw_reset,
++	.get_cd = himci_get_card_detect,
++	.card_info_save = himci_card_info_save,
++};
++
++static void himci_check_sdio_irq(struct himci_host *host, unsigned int rstat)
++{
++	u32 mstate;
++
++	if ((host->mmc->card != NULL)
++			&& (host->mmc->card->type == MMC_TYPE_SDIO)) {
++		mstate = himci_readl(host->base + MCI_INTMASK);
++		if ((rstat & SDIO_INT_STATUS) && (mstate & SDIO_INT_MASK)) {
++			spin_lock(&host->lock);
++			himci_writel(SDIO_INT_STATUS,
++					host->base + MCI_RINTSTS);
++			spin_unlock(&host->lock);
++			mmc_signal_sdio_irq(host->mmc);
++		}
++	}
++}
++
++static unsigned int himci_get_stable_rd_pos(struct himci_host *host,
++		unsigned int qstat, unsigned int rstat)
++{
++	unsigned int rd_pos;
++	unsigned int fsm_stat;
++	volatile unsigned int new_pos;
++	volatile unsigned int new_fsm;
++	unsigned int count = 0;
++	int try = 1000;
++
++	rd_pos = himci_readl(host->base + ADMA_Q_RDPTR);
++	fsm_stat = himci_readl(host->base + MCI_IDSTS);
++	while (try > 0) {
++		new_pos = himci_readl(host->base + ADMA_Q_RDPTR);
++		new_fsm = himci_readl(host->base + MCI_IDSTS);
++		if ((rd_pos == new_pos) && (fsm_stat == new_fsm)) {
++			count++;
++		} else {
++			rd_pos = new_pos;
++			fsm_stat = new_fsm;
++			count = 0;
++		}
++
++		if (count == 3)
++			break;
++		try--;
++	}
++
++	/* when error occur, whether the read ptr jump next is depend on
++	 * host's state machine when CES && ADMA3_FSM=4 && FSM!=0,
++	 *rdptr don't jump next
++	 */
++	if (!(qstat & PACKET_TO_INT)) {
++		if (!((qstat & CES) &&
++			(((fsm_stat >> ADMA3_FSM_SHIFT) & 0xF) == 4) &&
++			((fsm_stat >> FSM_SHIFT) & 0xF)))
++			rd_pos = rd_pos ? (rd_pos - 1)
++				: (ADMA_QUEUE_DEEPTH - 1);
++	}
++
++	return rd_pos;
++}
++
++static irqreturn_t hisd_irq(int irq, void *dev_id)
++{
++	struct himci_host *host = dev_id;
++	struct mmc_request  *mrq;
++	u32 rd_pos = 0;
++	u32 rstat = 0;
++	u32 qstat = 0;
++	int cmd_err = 0;
++	int data_err = 0;
++
++	rstat = himci_readl(host->base + MCI_RINTSTS); /* read RAW intr */
++	qstat = himci_readl(host->base + MCI_IDSTS); /* clear ADMA3 intr */
++	himci_writel(qstat, host->base + MCI_IDSTS);
++	himci_trace(3, "queue state:0x%x raw state:0x%x", qstat, rstat);
++
++	if (!(qstat & ADMA_INT_ALL) && !(rstat & SDIO_INT_STATUS)) {
++		himci_trace(5, "##### no irq, should never be here! ######");
++		return IRQ_NONE;
++	}
++
++	/* bugfix: when send soft stop to SD Card, Host will report
++	   sdio interrupt, This situation needs to be avoided */
++	if (host->mmc->caps & MMC_CAP_SDIO_IRQ)
++		himci_check_sdio_irq(host, rstat);
++
++	rd_pos = himci_get_stable_rd_pos(host, qstat, rstat);
++
++	mrq = host->pmrq[rd_pos];
++	himci_err_check(host, qstat, rstat, &cmd_err, &data_err);
++
++	host->pmrq[rd_pos] = NULL;
++	if (!mrq || !mrq->cmd) {
++		himci_trace(4, "##################");
++		himci_trace(4, "queue state:0x%x raw state:0x%x", qstat, rstat);
++		himci_trace(4, "current rd:%d", rd_pos);
++		return IRQ_HANDLED;
++	}
++
++	if (cmd_err || data_err) {
++		if (mrq->cmd->flags & MMC_CMD_TYPE_RW) {
++			himci_trace(5, "R/W CMD%u error, qstat:0x%x rstat:0x%x",
++					mrq->cmd->opcode, qstat, rstat);
++			host->error_count++;
++			host->mmc->status = MMC_HOST_ERR;
++		}
++		mrq->cmd->error = cmd_err;
++		if (mrq->data)
++			mrq->data->error = data_err;
++	}
++
++	/* finish each mrq */
++	if (mrq->cmd->flags & MMC_CMD_TYPE_RW) {
++		himci_read_response(host, mrq->cmd);
++		mmc_request_done(host->mmc, mrq);
++	} else {
++		host->cmd_done = 1;
++		wake_up(&host->intr_wait);
++	}
++
++	return IRQ_HANDLED;
++}
++
++static int himci_of_parse(struct device_node *np, struct mmc_host *mmc)
++{
++	struct himci_host *host = mmc_priv(mmc);
++	int ret = mmc_of_parse(mmc);
++	int len;
++
++	if (ret)
++		return ret;
++
++	if (of_property_read_u32(np, "min-frequency", &mmc->f_min))
++		mmc->f_min = MMC_CCLK_MIN;
++
++	if (of_property_read_u32(np, "devid", &host->devid))
++		return -EINVAL;
++
++	if (of_find_property(np, "cap-mmc-hw-reset", &len))
++		mmc->caps |= MMC_CAP_HW_RESET;
++
++	return 0;
++}
++
++static int __init himci_probe(struct platform_device *pdev)
++{
++	struct mmc_host *mmc;
++	struct himci_host *host = NULL;
++	struct resource *host_ioaddr_res = NULL;
++	int ret = 0, irq;
++	struct device_node *np = pdev->dev.of_node;
++
++	himci_trace(2, "begin");
++	pr_info("mmc host probe\n");
++	himci_assert(pdev);
++
++	mmc = mmc_alloc_host(sizeof(struct himci_host), &pdev->dev);
++	if (!mmc) {
++		himci_error("no mem for hi mci host controller!\n");
++		ret = -ENOMEM;
++		goto out;
++	}
++
++	platform_set_drvdata(pdev, mmc);
++
++	mmc->ops = &himci_ops;
++
++	host_ioaddr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	if (NULL == host_ioaddr_res) {
++		himci_error("no ioaddr rescources config!\n");
++		ret = -ENODEV;
++		goto out;
++	}
++
++	if (himci_of_parse(np, mmc)) {
++		himci_error("failed to parse mmc dts!\n");
++		ret = -EINVAL;
++		goto out;
++	}
++
++	/* reload by this controller */
++	mmc->max_blk_count = 2048;
++	mmc->max_segs = MAX_SEGS;
++	mmc->max_seg_size = mmc->max_blk_size * mmc->max_blk_count;
++	mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
++	mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
++	mmc->status = MMC_HOST_OK;
++
++	host = mmc_priv(mmc);
++	mci_host[slot_index++] = host;
++	pdev->id = host->devid;
++	host->pdev = pdev;
++	host->mmc = mmc;
++
++	/* ADMA3 buffer alloc */
++	host->entire_addr = dma_alloc_coherent(&pdev->dev, PAGE_SIZE,
++			&host->entire_paddr, GFP_KERNEL);
++	if (!host->entire_addr) {
++		himci_error("no mem for himci dma!\n");
++		ret = -ENOMEM;
++		goto out;
++	}
++
++	host->cmd_addr = dma_alloc_coherent(&pdev->dev,
++			PERF_OPT_RATIO * PAGE_SIZE * ADMA_QUEUE_DEEPTH,
++			&host->cmd_paddr, GFP_KERNEL);
++	if (!host->cmd_addr) {
++		himci_error("no mem for himci dma!\n");
++		ret = -ENOMEM;
++		goto out;
++	}
++
++	host->base = devm_ioremap_resource(&pdev->dev, host_ioaddr_res);
++	if (IS_ERR_OR_NULL(host->base)) {
++		himci_error("no mem for himci base!\n");
++		ret = -ENOMEM;
++		goto out;
++	}
++
++	spin_lock_init(&host->lock);
++
++	host->clk = devm_clk_get(&pdev->dev, "mmc_clk");
++	if (IS_ERR_OR_NULL(host->clk)) {
++		himci_error("get clock fail.\n");
++		ret = PTR_ERR(host->clk);
++		goto out;
++	}
++
++	clk_prepare_enable(host->clk);
++
++	host->power_status = POWER_OFF;
++	host->cur_port = 0;
++
++	/* enable card */
++	himci_init_host(host);
++	host->card_status = himci_sys_card_detect(host);
++
++	if (mmc->caps & MMC_CAP_SD_HIGHSPEED) {
++		init_timer(&host->timer);
++		host->timer.function = himci_detect_card;
++		host->timer.data = (unsigned long)host;
++		host->timer.expires = jiffies + detect_time;
++		add_timer(&host->timer);
++	}
++
++	host->cmd_done = 0;
++	init_waitqueue_head(&host->intr_wait);
++	irq = platform_get_irq(pdev, 0);
++	if (irq < 0)
++		goto out;
++
++	host->irq = irq;
++	ret = request_irq(irq, hisd_irq, 0, DRIVER_NAME, host);
++	if (ret)
++		goto out;
++
++	mmc_add_host(mmc);
++	return 0;
++out:
++	if (host) {
++		if (mmc->caps & MMC_CAP_SD_HIGHSPEED)
++			del_timer(&host->timer);
++
++		if (host->base)
++			devm_iounmap(&pdev->dev, host->base);
++
++		if (host->entire_addr)
++			dma_free_coherent(&pdev->dev, PAGE_SIZE,
++					host->entire_addr, host->entire_paddr);
++		if (host->cmd_addr)
++			dma_free_coherent(&pdev->dev,
++					PERF_OPT_RATIO * PAGE_SIZE * ADMA_QUEUE_DEEPTH,
++					host->cmd_addr, host->cmd_paddr);
++	}
++	if (mmc)
++		mmc_free_host(mmc);
++	return ret;
++}
++
++static int __exit himci_remove(struct platform_device *pdev)
++{
++	struct mmc_host *mmc = platform_get_drvdata(pdev);
++
++	himci_trace(2, "begin");
++	himci_assert(pdev);
++
++	platform_set_drvdata(pdev, NULL);
++
++	if (mmc) {
++		struct himci_host *host = mmc_priv(mmc);
++
++		mmc_remove_host(mmc);
++		free_irq(host->irq, host);
++		if (mmc->caps & MMC_CAP_SD_HIGHSPEED)
++			del_timer_sync(&host->timer);
++		himci_ctrl_power(host, POWER_OFF, FORCE_DISABLE);
++		himci_control_cclk(host, DISABLE);
++		devm_iounmap(&pdev->dev, host->base);
++		dma_free_coherent(&pdev->dev, PAGE_SIZE,
++				host->entire_addr, host->entire_paddr);
++		dma_free_coherent(&pdev->dev,
++				PERF_OPT_RATIO * PAGE_SIZE * ADMA_QUEUE_DEEPTH,
++				host->cmd_addr, host->cmd_paddr);
++		mmc_free_host(mmc);
++	}
++	return 0;
++}
++
++static void himci_shutdown(struct platform_device *pdev)
++{
++	struct mmc_host *mmc = platform_get_drvdata(pdev);
++
++	himci_trace(3, "shutdown");
++	if (mmc) {
++		unsigned int val;
++		struct himci_host *host = mmc_priv(mmc);
++
++		/* bugfix: host reset can trigger error intr */
++		himci_writel(0, host->base + MCI_IDINTEN);
++		himci_writel(0, host->base + MCI_INTMASK);
++
++		val = himci_readl(host->base + MCI_CTRL);
++		val |= CTRL_RESET | FIFO_RESET | DMA_RESET;
++		himci_writel(val, host->base + MCI_CTRL);
++
++		himciv200_host_power(host, POWER_OFF, FORCE_DISABLE);
++	}
++}
++
++#ifdef CONFIG_PM
++static int himciv200_pltm_suspend(struct platform_device *pdev,
++		pm_message_t state)
++{
++	struct mmc_host *mmc = platform_get_drvdata(pdev);
++	struct himci_host *host;
++	int ret = 0;
++
++	if (mmc) {
++		host = mmc_priv(mmc);
++		if (mmc->caps & MMC_CAP_SD_HIGHSPEED)
++			del_timer_sync(&host->timer);
++
++		if (__clk_is_enabled(host->clk))
++			clk_disable_unprepare(host->clk);
++	}
++
++	return ret;
++}
++/******************************************************************************/
++
++static int himciv200_pltm_resume(struct platform_device *pdev)
++{
++	struct mmc_host *mmc = platform_get_drvdata(pdev);
++	struct himci_host *host;
++	int ret = 0;
++
++	if (mmc) {
++		host = mmc_priv(mmc);
++
++		if (!__clk_is_enabled(host->clk))
++			clk_prepare_enable(host->clk);
++
++		himci_init_host(host);
++
++		if (mmc->caps & MMC_CAP_SD_HIGHSPEED)
++			add_timer(&host->timer);
++	}
++
++	return ret;
++}
++#else
++#define himciv200_pltm_suspend    NULL
++#define himciv200_pltm_resume     NULL
++#endif
++
++void himci_mmc_rescan(int slot)
++{
++	struct mmc_host *mmc;
++	struct himci_host *host;
++
++	host = mci_host[slot];
++	if (!host || !host->mmc) {
++		himci_trace(5, "mmc%d: invalid slot!\n", slot);
++		return;
++	}
++
++	mmc = host->mmc;
++	if (mmc->caps & MMC_CAP_SD_HIGHSPEED)
++		del_timer_sync(&host->timer);
++
++	mmc_remove_host(mmc);
++
++	mmc_add_host(mmc);
++
++	if (mmc->caps & MMC_CAP_SD_HIGHSPEED)
++		add_timer(&host->timer);
++}
++EXPORT_SYMBOL(himci_mmc_rescan);
++
++static const struct of_device_id
++himciv200_match[] __maybe_unused = {
++	{.compatible = "hisilicon,hi3516cv300-himciv200"},
++	{.compatible = "hisilicon,hi3519-himciv200"},
++	{.compatible = "hisilicon,hi3516av200-himciv200"},
++	{.compatible = "hisilicon,hi3559-himciv200"},
++	{.compatible = "hisilicon,hi3556-himciv200"},
++	{},
++};
++
++static struct platform_driver himci_driver = {
++	.probe = himci_probe,
++	.remove = himci_remove,
++	.shutdown = himci_shutdown,
++	.suspend = himciv200_pltm_suspend,
++	.resume = himciv200_pltm_resume,
++	.driver = {
++		   .name = DRIVER_NAME,
++		   .owner = THIS_MODULE,
++		   .of_match_table = of_match_ptr(himciv200_match),
++		   },
++};
++
++static int __init himci_init(void)
++{
++	int ret;
++
++	himci_trace(2, "begin");
++
++	/*
++	 * We should register SDIO1 first to make sure that
++	 * the eMMC device,which connected to SDIO1 is mmcblk0.
++	 */
++
++	ret = platform_driver_register(&himci_driver);
++	if (ret) {
++		platform_driver_unregister(&himci_driver);
++		himci_error("Himci driver register failed!");
++		return ret;
++	}
++
++	/* device proc entry */
++	ret = mci_proc_init(HIMCI_SLOT_NUM);
++	if (ret)
++		himci_error("device proc init is failed!");
++
++	return ret;
++}
++
++static void __exit himci_exit(void)
++{
++	himci_trace(2, "begin");
++
++	mci_proc_shutdown();
++
++	platform_driver_unregister(&himci_driver);
++}
++
++module_init(himci_init);
++module_exit(himci_exit);
++
++#ifdef MODULE
++MODULE_AUTHOR("Hisilicon Drive Group");
++MODULE_DESCRIPTION("MMC/SD driver for the Hisilicon MMC/SD Host Controller");
++MODULE_LICENSE("GPL");
++#endif
+diff --git a/drivers/mmc/host/himciv200/himci.h b/drivers/mmc/host/himciv200/himci.h
+new file mode 100644
+index 0000000..7b78611
+--- /dev/null
++++ b/drivers/mmc/host/himciv200/himci.h
+@@ -0,0 +1,192 @@
++#ifndef _HI_MCI_H_
++#define _HI_MCI_H_
++
++#include <linux/mmc/mmc.h>
++
++extern int trace_level;
++#define HIMCI_TRACE_LEVEL  5
++/*
++   0 - all message
++   1 - dump all register read/write
++   2 - flow trace
++   3 - timeouut err and protocol err
++   */
++
++#define HIMCI_TRACE_FMT KERN_INFO
++/* #define HIMCI_TRACE_FMT KERN_DEBUG */
++
++#define HS400_TUNING_START_PHASE        1
++#define HS400_TUNING_END_PHASE          15
++#define NOT_FOUND       -1
++
++#define POWER_ON         1
++#define POWER_OFF        0
++#define FORCE_ENABLE     1
++#define FORCE_DISABLE    0
++
++#define CARD_UNPLUGED     1
++#define CARD_PLUGED       0
++
++#define ENABLE            1
++#define DISABLE           0
++
++#define SD_STRENGTH_TYPE_B	0
++#define SD_STRENGTH_TYPE_C	2
++#define SD_STRENGTH_TYPE_D	3
++#define MMC_STRENGTH_TYPE_0	0
++#define MMC_STRENGTH_TYPE_3	3
++
++#define HI_MCI_DETECT_TIMEOUT (HZ / 5)
++#define HI_MCI_REQUEST_TIMEOUT  (5 * HZ)
++#define MAX_RETRY_COUNT   100
++
++#define MMC_CCLK_MIN      100000
++
++#define	ADMA_QUEUE_DEEPTH	(32)
++
++/* Base address of SD card register */
++#define HI_MCI_INTR               (48+32)
++
++#define himci_trace(level, msg...) do { \
++	if ((level) >= trace_level) { \
++		printk(HIMCI_TRACE_FMT "%s:%d: ", __func__, __LINE__); \
++		printk(msg); \
++		printk("\n"); \
++	} \
++} while (0)
++
++#define himci_assert(cond) do { \
++	if (!(cond)) {\
++		printk(KERN_ERR "Assert:himci:%s:%d\n", \
++				__func__, \
++				__LINE__); \
++		BUG(); \
++	} \
++} while (0)
++
++#define himci_error(s...) do { \
++	printk(KERN_ERR "himci:%s:%d: ", __func__, __LINE__); \
++	printk(s); \
++	printk("\n"); \
++} while (0)
++
++#define himci_readl(addr) ({unsigned int reg = hi_readl(IOMEM(addr)); \
++	himci_trace(1, "readl(0x%04X) = 0x%08X", (unsigned int)addr, reg); \
++	reg; })
++
++#define himci_writel(v, addr) do { hi_writel(v, IOMEM(addr)); \
++	himci_trace(1, "writel(0x%04X) = 0x%08X", (unsigned int)addr, \
++			(unsigned int)(v)); \
++} while (0)
++
++struct himci_queue_info {
++	unsigned long	     end;
++	unsigned long	     cur;
++	unsigned int	     status;
++};
++
++struct himci_entire_des {
++	unsigned long ctrl;
++	unsigned long cmd_des_addr;
++	unsigned long response;
++	unsigned long reserved;
++};
++
++struct himci_cmd_des {
++	unsigned long blk_sz;
++	unsigned long byte_cnt;
++	unsigned long arg;
++	unsigned long cmd;
++};
++
++struct himci_dma_des {
++	unsigned long idmac_des_ctrl;
++	unsigned long idmac_des_buf_size;
++	unsigned long idmac_des_buf_addr;
++	unsigned long idmac_des_next_addr;
++};
++
++struct card_info {
++	unsigned int     card_type;
++	unsigned char    timing;
++	unsigned char    card_connect;
++#define CARD_CONNECT    1
++#define CARD_DISCONNECT 0
++	unsigned int     card_support_clock; /* clock rate */
++	unsigned int     card_state;      /* (our) card state */
++	unsigned int     sd_bus_speed;
++	unsigned int     ssr[16];
++};
++
++struct himci_host {
++	struct mmc_host    *mmc;
++	struct platform_device *pdev;
++	spinlock_t          lock;
++	struct mmc_request  *mrq;
++	struct mmc_command  *cmd;
++	struct mmc_data     *data;
++	void __iomem        *base;
++	void                *sys_regmap;
++	struct scatterlist  *dma_sg;
++
++	dma_addr_t	entire_paddr;
++	dma_addr_t	cmd_paddr;
++	dma_addr_t	dma_paddr;
++	unsigned int	*entire_addr;
++	unsigned int	*cmd_addr;
++	unsigned int	*dma_addr;
++	unsigned int	dma_sg_num;
++	struct himci_entire_des	*wr_ent_des;
++	struct himci_cmd_des	*wr_cmd_des;
++	/* save the pointer of send mrq */
++	struct mmc_request	*pmrq[ADMA_QUEUE_DEEPTH];
++	struct timer_list	timer;
++	wait_queue_head_t	intr_wait;
++	unsigned int	cmd_done;
++	unsigned int	irq;
++	unsigned int	irq_status;
++	unsigned int	power_status;
++	unsigned int	card_status;
++	unsigned int	devid;
++	unsigned int	cur_port;
++	unsigned int	wr_pos;
++	unsigned int	hclk;
++	unsigned int	cclk;
++	unsigned int	phase;
++	unsigned int	dll_phase;
++	struct clk	*clk;
++	unsigned int    error_count;
++	struct card_info c_info;
++};
++
++union cmd_arg_u {
++	unsigned int cmd_arg;
++	struct cmd_bits_arg {
++		unsigned int cmd_index:6;
++		unsigned int response_expect:1;
++		unsigned int response_length:1;
++		unsigned int check_response_crc:1;
++		unsigned int data_transfer_expected:1;
++		unsigned int read_write:1;
++		unsigned int transfer_mode:1;
++		unsigned int send_auto_stop:1;
++		unsigned int wait_prvdata_complete:1;
++		unsigned int stop_abort_cmd:1;
++		unsigned int send_initialization:1;
++		unsigned int card_number:5;
++		unsigned int update_clk_reg_only:1; /* bit 21 */
++		unsigned int read_ceata_device:1;
++		unsigned int ccs_expected:1;
++		unsigned int enable_boot:1;
++		unsigned int expect_boot_ack:1;
++		unsigned int disable_boot:1;
++		unsigned int boot_mode:1;
++		unsigned int volt_switch:1;
++		unsigned int use_hold_reg:1;
++		unsigned int reserved:1;
++		unsigned int start_cmd:1; /* HSB */
++	} bits;
++};
++
++struct mmc_host *get_mmchost(int hostid);
++#endif
+diff --git a/drivers/mmc/host/himciv200/himci_acl.c b/drivers/mmc/host/himciv200/himci_acl.c
+new file mode 100644
+index 0000000..43e8b43
+--- /dev/null
++++ b/drivers/mmc/host/himciv200/himci_acl.c
+@@ -0,0 +1,139 @@
++/******************************************************************************
++ *    Copyright (C) 2014 Hisilicon STB Development Dept
++ *    All rights reserved.
++ * ***
++ *    Create by Czyong
++ *
++******************************************************************************/
++#define pr_fmt(fmt) "mmcacl: " fmt
++
++#include <linux/kobject.h>
++#include <linux/slab.h>
++#include <linux/kmod.h>
++#include <linux/vmalloc.h>
++#include <linux/debugfs.h>
++#include <linux/mutex.h>
++#include <linux/uaccess.h>
++#include <linux/ctype.h>
++#include <linux/sched.h>
++#include <linux/cmdline-parser.h>
++#include <linux/delay.h>
++
++struct part_t {
++	u32 start;
++	u32 end;
++	int part;
++};
++
++static int mmcacl_devid = -1;
++extern char *get_blkdevparts(void);
++
++static struct part_t ro_parts[64];
++static int nr_ro_parts;
++
++static int mmcadd_part(int slot, struct cmdline_subpart *subpart, void *param)
++{
++	u32 start = (u32)(subpart->from >> 9);
++	u32 end = start + (u32)(subpart->size >> 9);
++	struct part_t *part = (struct part_t *)param;
++
++	if (subpart->flags & PF_RDONLY) {
++		if (nr_ro_parts < 64) {
++			part[nr_ro_parts].start = start;
++			part[nr_ro_parts].end   =  end;
++			part[nr_ro_parts].part  = slot;
++			nr_ro_parts++;
++		} else {
++			pr_err("too many ro partition. please increase ro_parts\n");
++		}
++	}
++
++	return 0;
++}
++/*****************************************************************************/
++
++static int mmcpart_part(char *cmdline)
++{
++	struct cmdline_parts *bdev_parts = NULL;
++
++	if (cmdline_parts_parse(&bdev_parts, cmdline))
++		return -1;
++
++	cmdline_parts_set(bdev_parts, (sector_t)0x1000000000ULL, 0, mmcadd_part,
++			  (void *)ro_parts);
++
++	cmdline_parts_free(&bdev_parts);
++
++	return 0;
++}
++/*****************************************************************************/
++
++int himci_acl_init(int devid)
++{
++	char *cmdline = NULL;
++
++	if (mmcacl_devid != -1)
++		return 0;
++
++	mmcacl_devid = devid;
++
++	cmdline = get_blkdevparts();
++	if (!cmdline)
++		return 0;
++
++	mmcpart_part(cmdline);
++
++	return 0;
++}
++/*****************************************************************************/
++
++struct part_t *part_find(struct part_t *part,
++		u32 nr_part, u32 ofblk, u32 endblk)
++{
++	u32 min = 0;
++	u32 max = nr_part;
++	u32 pos = (min + max) >> 1;
++
++	do {
++		if (endblk <= part[pos].start) {
++			max = pos;
++			goto next;
++		}
++
++		if (part[pos].end <= ofblk) {
++			min = pos;
++			goto next;
++		}
++
++		break;
++next:
++		pos = (min + max) >> 1;
++	} while (pos != min && pos != max);
++
++	return (endblk <= part[pos].start || part[pos].end <= ofblk) ?
++		NULL : &part[pos];
++}
++/*****************************************************************************/
++
++int himci_acl_rw(int devid, int is_write, u32 ofblk, u32 nrblk)
++{
++	struct part_t *part;
++
++	if (mmcacl_devid != devid)
++		return 0;
++
++	if (!is_write)
++		return 0;
++
++	if (!nr_ro_parts)
++		return 0;
++
++	part = part_find(ro_parts, nr_ro_parts, ofblk, ofblk + nrblk);
++	if (part) {
++		pr_warn("attempt to write ro area, offset:0x%08x, count:0x%08x.\n",
++			ofblk, nrblk);
++		return 1;
++	}
++
++	return 0;
++}
+diff --git a/drivers/mmc/host/himciv200/himci_acl.h b/drivers/mmc/host/himciv200/himci_acl.h
+new file mode 100644
+index 0000000..fee8229
+--- /dev/null
++++ b/drivers/mmc/host/himciv200/himci_acl.h
+@@ -0,0 +1,15 @@
++/******************************************************************************
++ *    Copyright (C) 2014 Hisilicon STB Development Dept
++ *    All rights reserved.
++ * ***
++ *    Create by Czyong
++ *
++******************************************************************************/
++#ifndef HIMCI_ACL_H
++#define HIMCI_ACL_H
++
++int himci_acl_init(int devid);
++
++int himci_acl_rw(int devid, int is_write, u32 ofblk, u32 nrblk);
++
++#endif
+diff --git a/drivers/mmc/host/himciv200/himci_dbg.c b/drivers/mmc/host/himciv200/himci_dbg.c
+new file mode 100644
+index 0000000..8fb3f27
+--- /dev/null
++++ b/drivers/mmc/host/himciv200/himci_dbg.c
+@@ -0,0 +1,662 @@
++/******************************************************************************
++ *    Copyright (C) 2014 Hisilicon STB Development Dept
++ *    All rights reserved.
++ * ***
++ *    Create by Czyong
++ *
++******************************************************************************/
++#define pr_fmt(fmt) "mmcdbg: " fmt
++
++#include <linux/kobject.h>
++#include <linux/slab.h>
++#include <linux/kmod.h>
++#include <linux/vmalloc.h>
++#include <linux/debugfs.h>
++#include <linux/mutex.h>
++#include <linux/uaccess.h>
++#include <linux/ctype.h>
++#include <linux/sched.h>
++#include <linux/export.h>
++
++#define MMC_MAX_BLK                0x2000000   /* 32M block, 16G size */
++#define MMC_CHUNK_SIZE_SHIFT       11 /* 2K blocks, 1M size */
++
++#define MMC_CHUNK_SIZE             (1 << MMC_CHUNK_SIZE_SHIFT)
++#define MMC_CHUNK_SIZE_MASK        (MMC_CHUNK_SIZE - 1)
++#define MMC_NUM_CHUNK              (MMC_MAX_BLK / MMC_CHUNK_SIZE)
++
++#define NUM_PER_LINE               8
++#define MAX_BUF                    ((NUM_PER_LINE + 1) * 9 + 24)
++#define MAX_PATH_LEN               260
++
++static DEFINE_MUTEX(mutex_rwcount);
++static DEFINE_MUTEX(mutex_notice);
++
++static volatile unsigned int *rw_chunk[2][MMC_NUM_CHUNK] = { {0}, {0} };
++
++#define GET_CHUNK(_rw, _ofblk) rw_chunk[_rw][(_ofblk) >> MMC_CHUNK_SIZE_SHIFT]
++
++static char *mmcdbg_options_string;
++static char mmcdbg_helper[MAX_PATH_LEN] = {0};
++static int mmcdbg_rcount_enable;
++static int mmcdbg_wcount_enable;
++static int mmcdbg_devid = -1;
++
++struct fo_data_t {
++	int is_write;
++	unsigned int ofblk;
++	int state;
++};
++/******************************************************************************/
++
++static int mmcdbg_rw_count(int is_write, unsigned int ofblk, unsigned int nrblk)
++{
++	int ret = -1;
++	int rw = is_write ? 1 : 0;
++
++	if (!nrblk)
++		return 0;
++
++	if (ofblk + nrblk > MMC_MAX_BLK) {
++		pr_err("out of block count.\n");
++		return -1;
++	}
++
++	mutex_lock(&mutex_rwcount);
++
++	while (nrblk-- > 0) {
++		volatile unsigned int *entry = GET_CHUNK(rw, ofblk);
++
++		if (!entry) {
++			entry = vmalloc(MMC_CHUNK_SIZE << 2);
++			if (!entry) {
++				pr_err("out of memory.\n");
++				goto fail;
++			}
++			memset((void *)entry, 0, MMC_CHUNK_SIZE << 2);
++
++			GET_CHUNK(rw, ofblk) = entry;
++		}
++		entry[ofblk & MMC_CHUNK_SIZE_MASK]++;
++		ofblk++;
++	}
++	ret = 0;
++fail:
++	mutex_unlock(&mutex_rwcount);
++
++	return ret;
++}
++/******************************************************************************/
++
++static int mmcdbg_rw_free(int is_write)
++{
++	unsigned int blk;
++	int rw = is_write ? 1 : 0;
++
++	mutex_lock(&mutex_rwcount);
++
++	for (blk = 0; blk < MMC_MAX_BLK; blk += MMC_CHUNK_SIZE) {
++		volatile unsigned int *entry = GET_CHUNK(rw, blk);
++
++		if (entry) {
++			GET_CHUNK(rw, blk) = NULL;
++			vfree((void *)entry);
++		}
++	}
++
++	mutex_unlock(&mutex_rwcount);
++
++	return 0;
++}
++/******************************************************************************/
++
++static void dump_line(unsigned int ofblk, unsigned int *value, char **buf,
++		      unsigned int *sz_buf, int state)
++{
++	int ret;
++
++	if (state == 0 || state == 1) {
++		int ix;
++		unsigned int tmp[NUM_PER_LINE] = {0};
++		unsigned int *v = (value == NULL ? tmp : value);
++
++		ret = snprintf(*buf, *sz_buf, "%08x:", ofblk);
++		*buf += ret;
++		*sz_buf -= ret;
++
++		for (ix = 0; ix < NUM_PER_LINE; ix++) {
++			ret = snprintf(*buf, *sz_buf, " %04x", v[ix]);
++			*buf += ret;
++			*sz_buf -= ret;
++		}
++
++	} else if (state == 2) {
++		ret = snprintf(*buf, *sz_buf, "...");
++		*buf += ret;
++		*sz_buf -= ret;
++
++	} else if (state == 3) {
++		ret = snprintf(*buf, *sz_buf, "%08x:", ofblk);
++		*buf += ret;
++		*sz_buf -= ret;
++
++	}
++
++	ret = snprintf(*buf, *sz_buf, "\n");
++	*buf += ret;
++	*sz_buf -= ret;
++}
++/******************************************************************************/
++
++static int mmcdbg_rw_dump_buf(int is_write, unsigned int *ofblk, char *buf,
++			      unsigned int sz_buf, int *state)
++{
++	char *pbuf = buf;
++	unsigned int index;
++	unsigned int blk = *ofblk;
++	int rw = is_write ? 1 : 0;
++
++	if (*state == 3)
++		return 0;
++
++	sz_buf--; /* for trailing end '\0' */
++
++	while (blk < MMC_MAX_BLK) {
++		unsigned int *entry = (unsigned int *)GET_CHUNK(rw, blk);
++
++		if (!entry) {
++			if (sz_buf < MAX_BUF)
++				goto no_buf;
++
++			if (*state == 0) {
++			/* XXXXXXX: 0000 0000 0000 0000 0000 0000 0000 0000 */
++				*state = 1;
++				dump_line(blk, NULL, &pbuf, &sz_buf, *state);
++			}
++
++			if (*state == 1) {
++				/* ... */
++				*state = 2;
++				dump_line(blk, NULL, &pbuf, &sz_buf, *state);
++			}
++
++			blk += MMC_CHUNK_SIZE;
++			continue;
++		}
++
++		index = blk & MMC_CHUNK_SIZE_MASK;
++		blk = blk & ~MMC_CHUNK_SIZE_MASK;
++
++		while (index < MMC_CHUNK_SIZE) {
++			int ix, ret;
++
++			if (sz_buf < MAX_BUF) {
++				blk += index;
++				goto no_buf;
++			}
++
++			ret = 0;
++			for (ix = 0; ix < NUM_PER_LINE; ix++)
++				ret |= entry[ix + index];
++
++			if (!ret) {
++				if (*state == 0) {
++					*state = 1;
++					dump_line(blk + index, NULL, &pbuf,
++						  &sz_buf, *state);
++				} else if (*state == 1) {
++					*state = 2;
++					dump_line(blk + index, NULL, &pbuf,
++						  &sz_buf, *state);
++				}
++			} else {
++				if (*state)
++					*state = 0;
++
++				dump_line(blk + index, &entry[index],
++					  &pbuf, &sz_buf, *state);
++			}
++
++			index += NUM_PER_LINE;
++		}
++
++		blk += MMC_CHUNK_SIZE;
++	}
++
++	if (*state == 2) {
++		*state = 3;
++		dump_line(blk, NULL, &pbuf, &sz_buf, *state);
++	}
++
++no_buf:
++	*ofblk = blk;
++
++	pbuf[0] = '\0';
++
++	return pbuf - buf;
++}
++/******************************************************************************/
++
++static int mmcdbg_rw_notice(int is_write, u32 ofblk, u32 nrblk)
++{
++	int retval = 0;
++	char *argv[2];
++	struct kobj_uevent_env *env;
++	char *rwstr = is_write ? "write" : "read";
++
++	env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL);
++	if (!env)
++		return -ENOMEM;
++
++	retval = add_uevent_var(env, "RW=%s", rwstr);
++	if (retval)
++		goto exit;
++
++	retval = add_uevent_var(env, "OFFSET=0x%08x", ofblk);
++	if (retval)
++		goto exit;
++
++	retval = add_uevent_var(env, "COUNT=0x%08x", nrblk);
++	if (retval)
++		goto exit;
++
++	retval = add_uevent_var(env, "PID=%d", current->pid);
++	if (retval)
++		goto exit;
++
++	retval = add_uevent_var(env, "COMM=%s", current->comm);
++	if (retval)
++		goto exit;
++
++	argv[0] = mmcdbg_helper;
++	argv[1] = NULL;
++
++	retval = add_uevent_var(env, "PATH=/sbin:/bin:/usr/sbin:/usr/bin");
++	if (retval)
++		goto exit;
++
++	retval = call_usermodehelper(argv[0], argv,
++				     env->envp, UMH_WAIT_EXEC);
++exit:
++	kfree(env);
++	return retval;
++}
++/******************************************************************************/
++
++static ssize_t fo_dump_rwcount_read(struct file *filp, char __user *buffer,
++				    size_t count, loff_t *ppos)
++{
++	int ret;
++	char buf[256] = {0};
++	char __user *pusrbuf = buffer;
++	struct fo_data_t *data = (struct fo_data_t *)filp->private_data;
++
++	if (*ppos == 2)
++		return 0;
++
++	if (data->is_write && !mmcdbg_wcount_enable) {
++		*ppos = 2;
++
++		ret = snprintf(buf, sizeof(buf), "mmc write count is disable.\n"
++			       "input \"echo 1 > write\" to enable.\n");
++
++		if (copy_to_user(pusrbuf, buf, ret))
++			return -EFAULT;
++
++		pusrbuf += ret;
++
++		return pusrbuf - buffer;
++	}
++
++	if (!data->is_write && !mmcdbg_rcount_enable) {
++		*ppos = 2;
++
++		ret = snprintf(buf, sizeof(buf), "mmc read count is disable.\n"
++			       "input \"echo 1 > read\" to enable\n");
++
++		if (copy_to_user(pusrbuf, buf, ret))
++			return -EFAULT;
++
++		pusrbuf += ret;
++
++		return pusrbuf - buffer;
++	}
++
++	do {
++		if (count < sizeof(buf)) {
++			*ppos = 1;
++			break;
++		}
++
++		mutex_lock(&mutex_rwcount);
++
++		ret = mmcdbg_rw_dump_buf(data->is_write, &data->ofblk, buf,
++					 sizeof(buf), &data->state);
++
++		mutex_unlock(&mutex_rwcount);
++
++		if (!ret) {
++			*ppos = 2;
++			break;
++		}
++
++		if (copy_to_user(pusrbuf, buf, ret))
++			return -EFAULT;
++
++		pusrbuf += ret;
++		count -= ret;
++
++	} while (ret);
++
++	return pusrbuf - buffer;
++}
++/******************************************************************************/
++
++static ssize_t fo_dump_rwcount_write(struct file *filp,
++					const char __user *buffer,
++					size_t count, loff_t *ppos)
++{
++	char *enstr;
++	long enable = 0;
++	char buf[32] = {0};
++	unsigned int sz_buf = sizeof(buf) - 1;
++	struct fo_data_t *data = (struct fo_data_t *)filp->private_data;
++	int rw = data->is_write ? 1 : 0;
++
++	if (count < sz_buf)
++		sz_buf = count;
++
++	if (copy_from_user(buf, buffer, sz_buf))
++		return -EFAULT;
++
++	buf[sz_buf] = '\0';
++	if (kstrtol(buf, 0, &enable)) {
++		pr_err("input error :%s\n", buf);
++		enable = rw ? mmcdbg_wcount_enable : mmcdbg_rcount_enable;
++	}
++
++	enstr = enable ? "enable" : "disable";
++
++	if (rw) {
++		if (enable != mmcdbg_wcount_enable) {
++			mmcdbg_wcount_enable = enable;
++			if (!mmcdbg_wcount_enable)
++				mmcdbg_rw_free(rw);
++			pr_info("%s write count.\n", enstr);
++		}
++	} else {
++		if (enable != mmcdbg_rcount_enable) {
++			mmcdbg_rcount_enable = enable;
++			if (!mmcdbg_rcount_enable)
++				mmcdbg_rw_free(rw);
++			pr_info("%s read count.\n", enstr);
++		}
++	}
++
++	return count;
++}
++/******************************************************************************/
++
++static int fo_dump_rcount_open(struct inode *inode, struct file *file)
++{
++	struct fo_data_t *data;
++
++	data = vmalloc(sizeof(struct fo_data_t));
++	if (!data) {
++		pr_err("out of memory.\n");
++		return -ENOMEM;
++	}
++
++	data->is_write = 0;
++	data->ofblk = 0;
++	data->state = 0;
++
++	file->private_data = (void *)data;
++
++	return 0;
++}
++/******************************************************************************/
++
++static int fo_dump_wcount_open(struct inode *inode, struct file *file)
++{
++	struct fo_data_t *data;
++
++	data = vmalloc(sizeof(struct fo_data_t));
++	if (!data) {
++		pr_err("out of memory.\n");
++		return -ENOMEM;
++	}
++
++	data->is_write = 1;
++	data->ofblk = 0;
++	data->state = 0;
++
++	file->private_data = (void *)data;
++
++	return 0;
++}
++/******************************************************************************/
++
++static int fp_dump_rwcount_release(struct inode *inode, struct file *file)
++{
++	struct fo_data_t *data = (struct fo_data_t *)file->private_data;
++
++	if (data)
++		vfree(data);
++
++	file->private_data = NULL;
++
++	return 0;
++}
++/******************************************************************************/
++
++static ssize_t fo_rw_notice_read(struct file *filp, char __user *buffer,
++				 size_t count, loff_t *ppos)
++{
++	int ret = 0;
++	char *kbuf;
++
++	if (*ppos == 1)
++		return 0;
++
++	*ppos = 1;
++
++	kbuf = vmalloc(sizeof(mmcdbg_helper) + 4);
++	if (!kbuf) {
++		pr_err("out of memory.\n");
++		return -ENOMEM;
++	}
++
++	ret = snprintf(kbuf, sizeof(mmcdbg_helper) + 4,
++			"<%s>\n", mmcdbg_helper);
++	if (copy_to_user(buffer, kbuf, ret)) {
++		vfree(kbuf);
++		return -EFAULT;
++	}
++
++	vfree(kbuf);
++
++	return ret;
++}
++/******************************************************************************/
++
++static ssize_t fo_rw_notice_write(struct file *filp, const char __user *buffer,
++				  size_t count, loff_t *ppos)
++{
++	char *kbuf;
++	char *pkbuf;
++	int size = count;
++
++	if (size >= sizeof(mmcdbg_helper))
++		size = sizeof(mmcdbg_helper) - 1;
++
++	kbuf = vmalloc(size + 1);
++	if (!kbuf) {
++		pr_err("out of memory.\n");
++		return -ENOMEM;
++	}
++
++	if (copy_from_user(kbuf, buffer, size)) {
++		vfree(kbuf);
++		return -EFAULT;
++	}
++
++	kbuf[size] = '\0';
++
++	pkbuf = strim(kbuf);
++
++	mutex_lock(&mutex_notice);
++
++	strncpy(mmcdbg_helper, pkbuf, size);
++
++	mutex_unlock(&mutex_notice);
++
++	vfree(kbuf);
++
++	return count;
++}
++/******************************************************************************/
++
++static const struct file_operations fo_dump_rcount = {
++	.owner = THIS_MODULE,
++	.open = fo_dump_rcount_open,
++	.read  = fo_dump_rwcount_read,
++	.write = fo_dump_rwcount_write,
++	.release = fp_dump_rwcount_release,
++};
++
++static const struct file_operations fo_dump_wcount = {
++	.owner = THIS_MODULE,
++	.open = fo_dump_wcount_open,
++	.read  = fo_dump_rwcount_read,
++	.write = fo_dump_rwcount_write,
++	.release = fp_dump_rwcount_release,
++};
++
++static const struct file_operations fo_rw_notice = {
++	.owner = THIS_MODULE,
++	.read  = fo_rw_notice_read,
++	.write = fo_rw_notice_write,
++};
++/******************************************************************************/
++
++static void mmcdbg_options(const char *string)
++{
++	int enable;
++	const char *pos, *cmd;
++
++	pos = string;
++
++	while (*pos) {
++		while (*pos && *pos != '+' && *pos != '-')
++			pos++;
++
++		switch (*pos++) {
++		case '+':
++			enable = 1;
++			break;
++		case '-':
++			enable = 0;
++			break;
++		default:
++			return;
++		}
++
++		cmd = pos;
++
++		while (*pos == '_' || isalpha(*pos))
++			pos++;
++
++		if (*cmd && pos > cmd) {
++			int size = pos - cmd;
++			char *enstr = enable ? "enable" : "disable";
++
++			if (!strncmp(cmd, "read", size)) {
++				mmcdbg_rcount_enable = enable;
++				pr_info("%s read count.\n", enstr);
++			} else if (!strncmp(cmd, "write", size)) {
++				mmcdbg_wcount_enable = enable;
++				pr_info("%s write count.\n", enstr);
++			}
++		}
++
++		while (isspace(*pos) || *pos == ',' || *pos == ';')
++			pos++;
++	}
++}
++/******************************************************************************/
++
++int himci_dbg_rw(int devid, int is_write, u32 ofblk, u32 nrblk)
++{
++	if (mmcdbg_devid != devid)
++		return 0;
++
++	if (is_write && mmcdbg_wcount_enable)
++		mmcdbg_rw_count(is_write, ofblk, nrblk);
++
++	if (!is_write && mmcdbg_rcount_enable)
++		mmcdbg_rw_count(is_write, ofblk, nrblk);
++
++	if (mmcdbg_helper[0]) {
++		mutex_lock(&mutex_notice);
++
++		mmcdbg_rw_notice(is_write, ofblk, nrblk);
++
++		mutex_unlock(&mutex_notice);
++	}
++
++	return 0;
++}
++/*****************************************************************************/
++
++int himci_dbg_init(int devid)
++{
++	char buf[16];
++	struct dentry *root = NULL;
++	struct dentry *ret = NULL;
++	unsigned int mode = S_IFREG | S_IRUSR | S_IWUSR;
++
++	snprintf(buf, sizeof(buf), "himci%d", devid);
++	root = debugfs_create_dir(buf, NULL);
++	if (!root) {
++		pr_err("Can't create '%s' dir.\n", buf);
++		return -ENOENT;
++	}
++
++	ret = debugfs_create_file("read", mode, root, NULL, &fo_dump_rcount);
++	if (!ret) {
++		pr_err("Can't create 'read' file.\n");
++		goto fail;
++	}
++
++	ret = debugfs_create_file("write", mode, root, NULL, &fo_dump_wcount);
++	if (!ret) {
++		pr_err("Can't create 'write' file.\n");
++		goto fail;
++	}
++
++	ret = debugfs_create_file("notice", mode, root, NULL, &fo_rw_notice);
++	if (!ret) {
++		pr_err("Can't create 'notice' file.\n");
++		goto fail;
++	}
++
++	if (mmcdbg_options_string)
++		mmcdbg_options(mmcdbg_options_string);
++
++	mmcdbg_devid = devid;
++
++	return 0;
++fail:
++	debugfs_remove_recursive(root);
++
++	return -ENOENT;
++}
++/*****************************************************************************/
++
++static int __init mmcdbg_options_setup(char *s)
++{
++	mmcdbg_options_string = s;
++	return 1;
++}
++__setup("mmcdbg=", mmcdbg_options_setup);
+diff --git a/drivers/mmc/host/himciv200/himci_dbg.h b/drivers/mmc/host/himciv200/himci_dbg.h
+new file mode 100644
+index 0000000..45adb29
+--- /dev/null
++++ b/drivers/mmc/host/himciv200/himci_dbg.h
+@@ -0,0 +1,15 @@
++/******************************************************************************
++ *    Copyright (C) 2014 Hisilicon STB Development Dept
++ *    All rights reserved.
++ * ***
++ *    Create by Czyong
++ *
++******************************************************************************/
++#ifndef HIMCI_DBG_H
++#define HIMCI_DBG_H
++
++int himci_dbg_init(int devid);
++
++int himci_dbg_rw(int devid, int is_write, u32 ofblk, u32 nrblk);
++
++#endif
+diff --git a/drivers/mmc/host/himciv200/himci_hi3516av200.c b/drivers/mmc/host/himciv200/himci_hi3516av200.c
+new file mode 100644
+index 0000000..f505bf5
+--- /dev/null
++++ b/drivers/mmc/host/himciv200/himci_hi3516av200.c
+@@ -0,0 +1,210 @@
++/*
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++#include <mach/platform.h>
++
++#define MMC_CRG_MIN       12500000
++
++#define PERI_CRG49			IO_ADDRESS(0x120100c4)
++#define EMMC_DLL_CTRL		IO_ADDRESS(0x12030140)
++
++#define TUNING_START_PHASE      0
++#define TUNING_END_PHASE        15
++#define HIMCI_PHASE_SCALE       16
++#define DRV_PHASE_DFLT         (0x6<<23)
++#define SMPL_PHASE_DFLT        (0x0<<16)
++
++#define EMMC_DRV_PHASE_DFLT         (0x4<<23)
++#define EMMC_SMPL_PHASE_DFLT        SMPL_PHASE_DFLT
++
++#define REG_PAD_CTRL			0x12040800
++#define REG_CTRL_SDIO0_CCLK		0xc4
++#define REG_CTRL_SDIO0_CCMD		0xc8
++#define REG_CTRL_SDIO0_CDATA0	0xcc
++#define REG_CTRL_SDIO0_CDATA1	0xd0
++#define REG_CTRL_SDIO0_CDATA2	0xd4
++#define REG_CTRL_SDIO0_CDATA3	0xd8
++
++#define REG_CTRL_SDIO1_CCLK		0xe8
++#define REG_CTRL_SDIO1_CCMD		0xec
++#define REG_CTRL_SDIO1_CDATA0	0xf0
++#define REG_CTRL_SDIO1_CDATA1	0xf4
++#define REG_CTRL_SDIO1_CDATA2	0xf8
++#define REG_CTRL_SDIO1_CDATA3	0xfc
++
++#define REG_CTRL_EMMC_CLK		0x1ac
++#define REG_CTRL_EMMC_CMD		0x1c8
++#define REG_CTRL_EMMC_DATA0		0x1b0
++#define REG_CTRL_EMMC_DATA1		0x1cc
++#define REG_CTRL_EMMC_DATA2		0x1b4
++#define REG_CTRL_EMMC_DATA3		0x1bc
++#define REG_CTRL_EMMC_DATA4		0x1c0
++#define REG_CTRL_EMMC_DATA5		0x1a8
++#define REG_CTRL_EMMC_DATA6		0x1dc
++#define REG_CTRL_EMMC_DATA7		0x1b8
++
++#define EMMC_CLK_DS_3V3			0xd0
++#define EMMC_CMD_DS_3V3			0xd0
++#define EMMC_DATA0_DS_3V3		0xd0
++#define EMMC_DATA1_DS_3V3		0xd0
++#define EMMC_DATA2_DS_3V3		0xd0
++#define EMMC_DATA3_DS_3V3		0xd0
++#define EMMC_DATA4_DS_3V3		0xd0
++#define EMMC_DATA5_DS_3V3		0xd0
++#define EMMC_DATA6_DS_3V3		0xd0
++#define EMMC_DATA7_DS_3V3		0xd0
++
++#define EMMC_CLK_DS_1V8			0xc0
++#define EMMC_CMD_DS_1V8			0xc0
++#define EMMC_DATA0_DS_1V8		0xc0
++#define EMMC_DATA1_DS_1V8		0xc0
++#define EMMC_DATA2_DS_1V8		0xc0
++#define EMMC_DATA3_DS_1V8		0xc0
++#define EMMC_DATA4_DS_1V8		0xc0
++#define EMMC_DATA5_DS_1V8		0xc0
++#define EMMC_DATA6_DS_1V8		0xc0
++#define EMMC_DATA7_DS_1V8		0xc0
++
++struct sdio_drv_cap {
++	unsigned int reg_addr[2];
++	unsigned int ds;
++};
++
++#define SDIO_DRV_CAP(ofst1, ofst2, v) { \
++	.reg_addr[0] = (REG_PAD_CTRL + ofst1), \
++	.reg_addr[1] = (REG_PAD_CTRL + ofst2), \
++	.ds = v}
++static struct sdio_drv_cap sdio_ds_hs[] = {
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CCLK, REG_CTRL_SDIO1_CCLK, 0x1c0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CCMD, REG_CTRL_SDIO1_CCMD, 0x1e0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CDATA0, REG_CTRL_SDIO1_CDATA0, 0x1e0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CDATA1, REG_CTRL_SDIO1_CDATA1, 0x1e0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CDATA2, REG_CTRL_SDIO1_CDATA2, 0x1e0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CDATA3, REG_CTRL_SDIO1_CDATA3, 0x1e0)
++};
++
++static struct sdio_drv_cap sdio_ds_ddr50[] = {
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CCLK, REG_CTRL_SDIO1_CCLK, 0x1b0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CCMD, REG_CTRL_SDIO1_CCMD, 0x1c0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CDATA0, REG_CTRL_SDIO1_CDATA0, 0x1c0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CDATA1, REG_CTRL_SDIO1_CDATA1, 0x1c0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CDATA2, REG_CTRL_SDIO1_CDATA2, 0x1c0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CDATA3, REG_CTRL_SDIO1_CDATA3, 0x1c0)
++};
++
++static struct sdio_drv_cap sdio_ds_sdr50[] = {
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CCLK, REG_CTRL_SDIO1_CCLK, 0x80),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CCMD, REG_CTRL_SDIO1_CCMD, 0x1c0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CDATA0, REG_CTRL_SDIO1_CDATA0, 0x1c0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CDATA1, REG_CTRL_SDIO1_CDATA1, 0x1c0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CDATA2, REG_CTRL_SDIO1_CDATA2, 0x1c0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CDATA3, REG_CTRL_SDIO1_CDATA3, 0x1c0)
++};
++
++static struct sdio_drv_cap sdio_ds_sdr104[] = {
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CCLK, REG_CTRL_SDIO1_CCLK, 0x0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CCMD, REG_CTRL_SDIO1_CCMD, 0xc0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CDATA0, REG_CTRL_SDIO1_CDATA0, 0xc0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CDATA1, REG_CTRL_SDIO1_CDATA1, 0xc0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CDATA2, REG_CTRL_SDIO1_CDATA2, 0xc0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CDATA3, REG_CTRL_SDIO1_CDATA3, 0xc0)
++};
++
++struct emmc_drv_cap {
++	unsigned int reg_addr;
++	unsigned int ds[2];
++};
++
++#define EMMC_DRV_CAP(ofst, v1, v2) { \
++	.reg_addr = (REG_PAD_CTRL + ofst), \
++	.ds[0] = v1, \
++	.ds[1] = v2}
++static  struct emmc_drv_cap emmc_ds[] = {
++	EMMC_DRV_CAP(REG_CTRL_EMMC_CLK, EMMC_CLK_DS_3V3, EMMC_CLK_DS_1V8),
++	EMMC_DRV_CAP(REG_CTRL_EMMC_CMD, EMMC_CMD_DS_3V3, EMMC_CMD_DS_1V8),
++	EMMC_DRV_CAP(REG_CTRL_EMMC_DATA0, EMMC_DATA0_DS_3V3, EMMC_DATA0_DS_1V8),
++	EMMC_DRV_CAP(REG_CTRL_EMMC_DATA1, EMMC_DATA1_DS_3V3, EMMC_DATA1_DS_1V8),
++	EMMC_DRV_CAP(REG_CTRL_EMMC_DATA2, EMMC_DATA2_DS_3V3, EMMC_DATA2_DS_1V8),
++	EMMC_DRV_CAP(REG_CTRL_EMMC_DATA3, EMMC_DATA3_DS_3V3, EMMC_DATA3_DS_1V8),
++	EMMC_DRV_CAP(REG_CTRL_EMMC_DATA4, EMMC_DATA4_DS_3V3, EMMC_DATA4_DS_1V8),
++	EMMC_DRV_CAP(REG_CTRL_EMMC_DATA5, EMMC_DATA5_DS_3V3, EMMC_DATA5_DS_1V8),
++	EMMC_DRV_CAP(REG_CTRL_EMMC_DATA6, EMMC_DATA6_DS_3V3, EMMC_DATA6_DS_1V8),
++	EMMC_DRV_CAP(REG_CTRL_EMMC_DATA7, EMMC_DATA7_DS_3V3, EMMC_DATA7_DS_1V8),
++};
++
++static void himci_set_pin_drv_cap(struct himci_host *host, unsigned int flag,
++		unsigned char timing)
++{
++	struct sdio_drv_cap *sdio_ds;
++	unsigned int i;
++
++	if (host->devid == 2) {
++		for (i = 0; i < ARRAY_SIZE(emmc_ds); i++)
++			himci_writel(emmc_ds[i].ds[flag], IO_ADDRESS(emmc_ds[i].reg_addr));
++	} else {
++		if (timing == MMC_TIMING_UHS_SDR104)
++			sdio_ds = sdio_ds_sdr104;
++		else if (timing ==  MMC_TIMING_UHS_SDR50)
++			sdio_ds = sdio_ds_sdr50;
++		else if (timing ==  MMC_TIMING_UHS_DDR50)
++			sdio_ds = sdio_ds_ddr50;
++		else
++			sdio_ds = sdio_ds_hs;
++
++		for (i = 0; i < ARRAY_SIZE(sdio_ds_hs); i++)
++			himci_writel(sdio_ds[i].ds,
++					IO_ADDRESS(sdio_ds[i].reg_addr[host->devid]));
++	}
++}
++
++static void himci_set_drv_cap(struct himci_host *host, struct mmc_ios *ios)
++{
++	unsigned int tmp_reg;
++
++	if (ios->timing == MMC_TIMING_UHS_DDR50) {
++		tmp_reg = himci_readl(host->base + MCI_UHS_REG_EXT);
++		tmp_reg &= ~CLK_SMPL_PHS_MASK;
++		tmp_reg |= (0x4 << CLK_SMPL_PHS_SHIFT);
++		himci_writel(tmp_reg, host->base + MCI_UHS_REG_EXT);
++	} else if (ios->timing == MMC_TIMING_MMC_HS) {
++		tmp_reg = himci_readl(host->base + MCI_UHS_REG_EXT);
++		tmp_reg &= ~CLK_SMPL_PHS_MASK;
++		tmp_reg |= SMPL_PHASE_DFLT;
++		himci_writel(tmp_reg, host->base + MCI_UHS_REG_EXT);
++	} else if (ios->timing == MMC_TIMING_MMC_HS400) {
++		tmp_reg = himci_readl(host->base + MCI_UHS_REG_EXT);
++		tmp_reg &= ~CLK_SMPL_PHS_MASK;
++		tmp_reg |= (host->phase << CLK_SMPL_PHS_SHIFT);
++		himci_writel(tmp_reg, host->base + MCI_UHS_REG_EXT);
++	}
++
++	/* set pin drive capability */
++	if (ios->timing == MMC_TIMING_MMC_HS200 ||
++			ios->timing == MMC_TIMING_MMC_HS400)
++		himci_set_pin_drv_cap(host, 1, ios->timing);
++	else
++		himci_set_pin_drv_cap(host, 0, ios->timing);
++}
++
++static int himci_check_emmc(struct himci_host *host)
++{
++	unsigned int val;
++
++	val = himci_readl(IO_ADDRESS(SYS_CTRL_BASE + REG_SC_STAT));
++
++	return !(GET_SYS_BOOT_MODE(val) == BOOT_FROM_EMMC);
++}
+diff --git a/drivers/mmc/host/himciv200/himci_hi3516cv300.c b/drivers/mmc/host/himciv200/himci_hi3516cv300.c
+new file mode 100644
+index 0000000..ea35c2b
+--- /dev/null
++++ b/drivers/mmc/host/himciv200/himci_hi3516cv300.c
+@@ -0,0 +1,119 @@
++/*
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++#include <linux/mfd/syscon.h>
++#include <linux/regmap.h>
++
++#define MMC_CRG_MIN       49500000
++
++#define TUNING_START_PHASE	0
++#define TUNING_END_PHASE	7
++#define HIMCI_PHASE_SCALE	8
++#define DRV_PHASE_DFLT		(0x4<<23)
++#define SMPL_PHASE_DFLT		(0x1<<16)
++
++#define EMMC_DRV_PHASE_DFLT         DRV_PHASE_DFLT
++#define EMMC_SMPL_PHASE_DFLT        SMPL_PHASE_DFLT
++
++#define GET_SYS_BOOT_MODE(_reg) (((_reg) >> 0x4) & 0x1)
++#define BOOT_FROM_EMMC			0x1
++
++#define REG_PAD_CTRL			0x12040800
++
++#define REG_CTRL_EMMC_CLK		0xa0
++#define REG_CTRL_EMMC_CMD		0x9c
++#define REG_CTRL_EMMC_DATA0		0x90
++#define REG_CTRL_EMMC_DATA1		0x98
++#define REG_CTRL_EMMC_DATA2		0xa4
++#define REG_CTRL_EMMC_DATA3		0x8c
++
++#define EMMC_CLK_DS_1V8			0xc0
++#define EMMC_CMD_DS_1V8			0x150
++#define EMMC_DATA0_DS_1V8		0x1d0
++#define EMMC_DATA1_DS_1V8		0x1d0
++#define EMMC_DATA2_DS_1V8		0x1d0
++#define EMMC_DATA3_DS_1V8		0x1d0
++
++struct emmc_drv_cap {
++	unsigned int reg_addr;
++	unsigned int ds;
++};
++
++#define EMMC_DRV_CAP(ofst, v) { \
++	.reg_addr = ofst, \
++	.ds = v}
++static  struct emmc_drv_cap emmc_ds[] = {
++	EMMC_DRV_CAP(REG_CTRL_EMMC_CLK, EMMC_CLK_DS_1V8),
++	EMMC_DRV_CAP(REG_CTRL_EMMC_CMD, EMMC_CMD_DS_1V8),
++	EMMC_DRV_CAP(REG_CTRL_EMMC_DATA0, EMMC_DATA0_DS_1V8),
++	EMMC_DRV_CAP(REG_CTRL_EMMC_DATA1, EMMC_DATA1_DS_1V8),
++	EMMC_DRV_CAP(REG_CTRL_EMMC_DATA2, EMMC_DATA2_DS_1V8),
++	EMMC_DRV_CAP(REG_CTRL_EMMC_DATA3, EMMC_DATA3_DS_1V8),
++};
++
++static void himci_set_drv_cap(struct himci_host *host, struct mmc_ios *ios)
++{
++	static void *pad_ctrl = NULL;
++	unsigned int i, tmp_reg;
++
++	if (ios->timing == MMC_TIMING_MMC_DDR52) {
++		tmp_reg = himci_readl(host->base + MCI_UHS_REG_EXT);
++		tmp_reg &= ~CLK_DRV_PHS_MASK;
++		tmp_reg |= (0x2 << CLK_DRV_PHS_SHIFT);
++		himci_writel(tmp_reg, host->base + MCI_UHS_REG_EXT);
++	}
++
++	if (ios->timing == MMC_TIMING_MMC_HS200) {
++		tmp_reg = himci_readl(host->base + MCI_UHS_REG_EXT);
++		tmp_reg &= ~(CLK_DRV_PHS_MASK);
++		tmp_reg |= (0x3 << CLK_DRV_PHS_SHIFT);
++		himci_writel(tmp_reg, host->base + MCI_UHS_REG_EXT);
++	}
++
++	if (host->mmc->caps & MMC_CAP_SD_HIGHSPEED
++			|| ios->timing == MMC_TIMING_LEGACY)
++		return;
++
++	if (!pad_ctrl)
++		pad_ctrl = ioremap(REG_PAD_CTRL, 0x1000);
++
++	if (!pad_ctrl)
++		return;
++
++	for (i = 0; i < ARRAY_SIZE(emmc_ds); i++)
++		himci_writel(emmc_ds[i].ds, pad_ctrl + emmc_ds[i].reg_addr);
++}
++
++static int himci_check_emmc(struct himci_host *host)
++{
++	struct device *dev = &(host->pdev->dev);
++	unsigned int val;
++
++	if (!host->sys_regmap) {
++		host->sys_regmap = syscon_regmap_lookup_by_phandle(dev->of_node,
++				"regmap");
++		if (IS_ERR(host->sys_regmap)) {
++			host->sys_regmap = NULL;
++		    return 1;
++		}
++	}
++
++	if (regmap_read(host->sys_regmap, 0x8c, &val))
++		return 1;
++
++	return !(GET_SYS_BOOT_MODE(val) == BOOT_FROM_EMMC);
++}
+diff --git a/drivers/mmc/host/himciv200/himci_hi3519.c b/drivers/mmc/host/himciv200/himci_hi3519.c
+new file mode 100644
+index 0000000..03bfafe
+--- /dev/null
++++ b/drivers/mmc/host/himciv200/himci_hi3519.c
+@@ -0,0 +1,192 @@
++/*
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++#include <mach/platform.h>
++
++#define MMC_CRG_MIN       12500000
++
++#define PERI_CRG49			IO_ADDRESS(0x120100c4)
++#define TUNING_START_PHASE      2
++#define TUNING_END_PHASE        14
++
++#define EMMC_DLL_CTRL		IO_ADDRESS(0x12030140)
++#define REG_PAD_CTRL		0x12040800
++#define DRV_PHASE_DFLT         (0x6<<23)
++#define SMPL_PHASE_DFLT        (0x0<<16)
++
++#define EMMC_DRV_PHASE_DFLT         DRV_PHASE_DFLT
++#define EMMC_SMPL_PHASE_DFLT        SMPL_PHASE_DFLT
++
++#define REG_CTRL_SDIO0_CCLK	IO_ADDRESS(REG_PAD_CTRL + 0x114)
++#define REG_CTRL_SDIO0_CCMD	IO_ADDRESS(REG_PAD_CTRL + 0x118)
++#define REG_CTRL_SDIO0_CDATA0	IO_ADDRESS(REG_PAD_CTRL + 0x11c)
++#define REG_CTRL_SDIO0_CDATA1	IO_ADDRESS(REG_PAD_CTRL + 0x120)
++#define REG_CTRL_SDIO0_CDATA2	IO_ADDRESS(REG_PAD_CTRL + 0x124)
++#define REG_CTRL_SDIO0_CDATA3	IO_ADDRESS(REG_PAD_CTRL + 0x128)
++
++#define REG_CTRL_SDIO1_CCLK	IO_ADDRESS(REG_PAD_CTRL + 0x138)
++#define REG_CTRL_SDIO1_CCMD	IO_ADDRESS(REG_PAD_CTRL + 0x13c)
++#define REG_CTRL_SDIO1_CDATA0	IO_ADDRESS(REG_PAD_CTRL + 0x140)
++#define REG_CTRL_SDIO1_CDATA1	IO_ADDRESS(REG_PAD_CTRL + 0x144)
++#define REG_CTRL_SDIO1_CDATA2	IO_ADDRESS(REG_PAD_CTRL + 0x148)
++#define REG_CTRL_SDIO1_CDATA3	IO_ADDRESS(REG_PAD_CTRL + 0x14c)
++
++#define REG_CTRL_EMMC_DS	IO_ADDRESS(REG_PAD_CTRL + 0x17c)
++#define REG_CTRL_EMMC_CLK	IO_ADDRESS(REG_PAD_CTRL + 0x154)
++#define REG_CTRL_EMMC_CMD	IO_ADDRESS(REG_PAD_CTRL + 0x170)
++#define REG_CTRL_EMMC_DATA0	IO_ADDRESS(REG_PAD_CTRL + 0x158)
++#define REG_CTRL_EMMC_DATA1	IO_ADDRESS(REG_PAD_CTRL + 0x174)
++#define REG_CTRL_EMMC_DATA2	IO_ADDRESS(REG_PAD_CTRL + 0x15c)
++#define REG_CTRL_EMMC_DATA3	IO_ADDRESS(REG_PAD_CTRL + 0x164)
++#define REG_CTRL_EMMC_DATA4	IO_ADDRESS(REG_PAD_CTRL + 0x168)
++#define REG_CTRL_EMMC_DATA5	IO_ADDRESS(REG_PAD_CTRL + 0x150)
++#define REG_CTRL_EMMC_DATA6	IO_ADDRESS(REG_PAD_CTRL + 0x184)
++#define REG_CTRL_EMMC_DATA7	IO_ADDRESS(REG_PAD_CTRL + 0x160)
++
++#define SDIO_CCLK_DS_3V3		0x1c0
++#define SDIO_CCMD_DS_3V3		0x140
++#define SDIO_CDATA0_DS_3V3		0x140
++#define SDIO_CDATA1_DS_3V3		0x140
++#define SDIO_CDATA2_DS_3V3		0x140
++#define SDIO_CDATA3_DS_3V3		0x140
++
++#define SDIO_CCLK_DS_1V8		0x0
++#define SDIO_CCMD_DS_1V8		0x120
++#define SDIO_CDATA0_DS_1V8		0x120
++#define SDIO_CDATA1_DS_1V8		0x120
++#define SDIO_CDATA2_DS_1V8		0x120
++#define SDIO_CDATA3_DS_1V8		0x120
++
++#define EMMC_DS_DS_3V3			0x120
++#define EMMC_CLK_DS_3V3			0x1c0
++#define EMMC_CMD_DS_3V3			0x1d0
++#define EMMC_DATA0_DS_3V3		0x1e0
++#define EMMC_DATA1_DS_3V3		0x1d0
++#define EMMC_DATA2_DS_3V3		0x1d0
++#define EMMC_DATA3_DS_3V3		0x1e0
++#define EMMC_DATA4_DS_3V3		0x1e0
++#define EMMC_DATA5_DS_3V3		0x1d0
++#define EMMC_DATA6_DS_3V3		0x1e0
++#define EMMC_DATA7_DS_3V3		0x1e0
++
++#define EMMC_DS_DS_1V8			0x100
++#define EMMC_CLK_DS_1V8			0x160
++#define EMMC_CMD_DS_1V8			0x180
++#define EMMC_DATA0_DS_1V8		0x180
++#define EMMC_DATA1_DS_1V8		0x180
++#define EMMC_DATA2_DS_1V8		0x180
++#define EMMC_DATA3_DS_1V8		0x180
++#define EMMC_DATA4_DS_1V8		0x180
++#define EMMC_DATA5_DS_1V8		0x180
++#define EMMC_DATA6_DS_1V8		0x180
++#define EMMC_DATA7_DS_1V8		0x180
++
++static void himci_set_pin_drv_cap(struct himci_host *host, unsigned int flag)
++{
++	if (flag) {
++		if (0 == host->devid) {
++			himci_writel(SDIO_CCLK_DS_1V8, REG_CTRL_SDIO0_CCLK);
++			himci_writel(SDIO_CCMD_DS_1V8, REG_CTRL_SDIO0_CCMD);
++			himci_writel(SDIO_CDATA0_DS_1V8, REG_CTRL_SDIO0_CDATA0);
++			himci_writel(SDIO_CDATA1_DS_1V8, REG_CTRL_SDIO0_CDATA1);
++			himci_writel(SDIO_CDATA2_DS_1V8, REG_CTRL_SDIO0_CDATA2);
++			himci_writel(SDIO_CDATA3_DS_1V8, REG_CTRL_SDIO0_CDATA3);
++		} else if (1 == host->devid) {
++			himci_writel(SDIO_CCLK_DS_1V8, REG_CTRL_SDIO1_CCLK);
++			himci_writel(SDIO_CCMD_DS_1V8, REG_CTRL_SDIO1_CCMD);
++			himci_writel(SDIO_CDATA0_DS_1V8, REG_CTRL_SDIO1_CDATA0);
++			himci_writel(SDIO_CDATA1_DS_1V8, REG_CTRL_SDIO1_CDATA1);
++			himci_writel(SDIO_CDATA2_DS_1V8, REG_CTRL_SDIO1_CDATA2);
++			himci_writel(SDIO_CDATA3_DS_1V8, REG_CTRL_SDIO1_CDATA3);
++		} else if (2 == host->devid) {
++			himci_writel(EMMC_DS_DS_1V8, REG_CTRL_EMMC_DS);
++			himci_writel(EMMC_CLK_DS_1V8, REG_CTRL_EMMC_CLK);
++			himci_writel(EMMC_CMD_DS_1V8, REG_CTRL_EMMC_CMD);
++			himci_writel(EMMC_DATA0_DS_1V8, REG_CTRL_EMMC_DATA0);
++			himci_writel(EMMC_DATA1_DS_1V8, REG_CTRL_EMMC_DATA1);
++			himci_writel(EMMC_DATA2_DS_1V8, REG_CTRL_EMMC_DATA2);
++			himci_writel(EMMC_DATA3_DS_1V8, REG_CTRL_EMMC_DATA3);
++			himci_writel(EMMC_DATA4_DS_1V8, REG_CTRL_EMMC_DATA4);
++			himci_writel(EMMC_DATA5_DS_1V8, REG_CTRL_EMMC_DATA5);
++			himci_writel(EMMC_DATA6_DS_1V8, REG_CTRL_EMMC_DATA6);
++			himci_writel(EMMC_DATA7_DS_1V8, REG_CTRL_EMMC_DATA7);
++		}
++	} else {
++		/* config Pin drive capability */
++		if (0 == host->devid) {
++			himci_writel(SDIO_CCLK_DS_3V3, REG_CTRL_SDIO0_CCLK);
++			himci_writel(SDIO_CCMD_DS_3V3, REG_CTRL_SDIO0_CCMD);
++			himci_writel(SDIO_CDATA0_DS_3V3, REG_CTRL_SDIO0_CDATA0);
++			himci_writel(SDIO_CDATA1_DS_3V3, REG_CTRL_SDIO0_CDATA1);
++			himci_writel(SDIO_CDATA2_DS_3V3, REG_CTRL_SDIO0_CDATA2);
++			himci_writel(SDIO_CDATA3_DS_3V3, REG_CTRL_SDIO0_CDATA3);
++		} else if (1 == host->devid) {
++			himci_writel(SDIO_CCLK_DS_3V3, REG_CTRL_SDIO1_CCLK);
++			himci_writel(SDIO_CCMD_DS_3V3, REG_CTRL_SDIO1_CCMD);
++			himci_writel(SDIO_CDATA0_DS_3V3, REG_CTRL_SDIO1_CDATA0);
++			himci_writel(SDIO_CDATA1_DS_3V3, REG_CTRL_SDIO1_CDATA1);
++			himci_writel(SDIO_CDATA2_DS_3V3, REG_CTRL_SDIO1_CDATA2);
++			himci_writel(SDIO_CDATA3_DS_3V3, REG_CTRL_SDIO1_CDATA3);
++		} else if (2 == host->devid) {
++			himci_writel(EMMC_DS_DS_3V3, REG_CTRL_EMMC_DS);
++			himci_writel(EMMC_CLK_DS_3V3, REG_CTRL_EMMC_CLK);
++			himci_writel(EMMC_CMD_DS_3V3, REG_CTRL_EMMC_CMD);
++			himci_writel(EMMC_DATA0_DS_3V3, REG_CTRL_EMMC_DATA0);
++			himci_writel(EMMC_DATA1_DS_3V3, REG_CTRL_EMMC_DATA1);
++			himci_writel(EMMC_DATA2_DS_3V3, REG_CTRL_EMMC_DATA2);
++			himci_writel(EMMC_DATA3_DS_3V3, REG_CTRL_EMMC_DATA3);
++			himci_writel(EMMC_DATA4_DS_3V3, REG_CTRL_EMMC_DATA4);
++			himci_writel(EMMC_DATA5_DS_3V3, REG_CTRL_EMMC_DATA5);
++			himci_writel(EMMC_DATA6_DS_3V3, REG_CTRL_EMMC_DATA6);
++			himci_writel(EMMC_DATA7_DS_3V3, REG_CTRL_EMMC_DATA7);
++		}
++	}
++}
++
++static void himci_set_drv_cap(struct himci_host *host, struct mmc_ios *ios)
++{
++	unsigned int tmp_reg;
++
++	if (ios->timing == MMC_TIMING_UHS_DDR50) {
++		tmp_reg = himci_readl(host->base + MCI_UHS_REG_EXT);
++		tmp_reg &= ~CLK_SMPL_PHS_MASK;
++		tmp_reg |= (0x4 << 16);
++		himci_writel(tmp_reg, host->base + MCI_UHS_REG_EXT);
++	} else if (ios->timing == MMC_TIMING_UHS_SDR104) {
++		tmp_reg = himci_readl(host->base + MCI_UHS_REG_EXT);
++		tmp_reg &= ~CLK_DRV_PHS_MASK;
++		tmp_reg |= (0x4 << 23);
++		himci_writel(tmp_reg, host->base + MCI_UHS_REG_EXT);
++	}
++
++	/* set pin drive capability */
++	if (ios->timing == MMC_TIMING_MMC_HS200 ||
++			ios->timing == MMC_TIMING_MMC_HS400 ||
++			ios->timing == MMC_TIMING_UHS_SDR104)
++		himci_set_pin_drv_cap(host, 1);
++	else
++		himci_set_pin_drv_cap(host, 0);
++}
++
++static int himci_check_emmc(struct himci_host *host)
++{
++	unsigned int val;
++
++	val = himci_readl(IO_ADDRESS(SYS_CTRL_BASE + REG_SC_STAT));
++
++	return !(GET_SYS_BOOT_MODE(val) == BOOT_FROM_EMMC);
++}
+diff --git a/drivers/mmc/host/himciv200/himci_hi3519v101.c b/drivers/mmc/host/himciv200/himci_hi3519v101.c
+new file mode 100644
+index 0000000..f505bf5
+--- /dev/null
++++ b/drivers/mmc/host/himciv200/himci_hi3519v101.c
+@@ -0,0 +1,210 @@
++/*
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++#include <mach/platform.h>
++
++#define MMC_CRG_MIN       12500000
++
++#define PERI_CRG49			IO_ADDRESS(0x120100c4)
++#define EMMC_DLL_CTRL		IO_ADDRESS(0x12030140)
++
++#define TUNING_START_PHASE      0
++#define TUNING_END_PHASE        15
++#define HIMCI_PHASE_SCALE       16
++#define DRV_PHASE_DFLT         (0x6<<23)
++#define SMPL_PHASE_DFLT        (0x0<<16)
++
++#define EMMC_DRV_PHASE_DFLT         (0x4<<23)
++#define EMMC_SMPL_PHASE_DFLT        SMPL_PHASE_DFLT
++
++#define REG_PAD_CTRL			0x12040800
++#define REG_CTRL_SDIO0_CCLK		0xc4
++#define REG_CTRL_SDIO0_CCMD		0xc8
++#define REG_CTRL_SDIO0_CDATA0	0xcc
++#define REG_CTRL_SDIO0_CDATA1	0xd0
++#define REG_CTRL_SDIO0_CDATA2	0xd4
++#define REG_CTRL_SDIO0_CDATA3	0xd8
++
++#define REG_CTRL_SDIO1_CCLK		0xe8
++#define REG_CTRL_SDIO1_CCMD		0xec
++#define REG_CTRL_SDIO1_CDATA0	0xf0
++#define REG_CTRL_SDIO1_CDATA1	0xf4
++#define REG_CTRL_SDIO1_CDATA2	0xf8
++#define REG_CTRL_SDIO1_CDATA3	0xfc
++
++#define REG_CTRL_EMMC_CLK		0x1ac
++#define REG_CTRL_EMMC_CMD		0x1c8
++#define REG_CTRL_EMMC_DATA0		0x1b0
++#define REG_CTRL_EMMC_DATA1		0x1cc
++#define REG_CTRL_EMMC_DATA2		0x1b4
++#define REG_CTRL_EMMC_DATA3		0x1bc
++#define REG_CTRL_EMMC_DATA4		0x1c0
++#define REG_CTRL_EMMC_DATA5		0x1a8
++#define REG_CTRL_EMMC_DATA6		0x1dc
++#define REG_CTRL_EMMC_DATA7		0x1b8
++
++#define EMMC_CLK_DS_3V3			0xd0
++#define EMMC_CMD_DS_3V3			0xd0
++#define EMMC_DATA0_DS_3V3		0xd0
++#define EMMC_DATA1_DS_3V3		0xd0
++#define EMMC_DATA2_DS_3V3		0xd0
++#define EMMC_DATA3_DS_3V3		0xd0
++#define EMMC_DATA4_DS_3V3		0xd0
++#define EMMC_DATA5_DS_3V3		0xd0
++#define EMMC_DATA6_DS_3V3		0xd0
++#define EMMC_DATA7_DS_3V3		0xd0
++
++#define EMMC_CLK_DS_1V8			0xc0
++#define EMMC_CMD_DS_1V8			0xc0
++#define EMMC_DATA0_DS_1V8		0xc0
++#define EMMC_DATA1_DS_1V8		0xc0
++#define EMMC_DATA2_DS_1V8		0xc0
++#define EMMC_DATA3_DS_1V8		0xc0
++#define EMMC_DATA4_DS_1V8		0xc0
++#define EMMC_DATA5_DS_1V8		0xc0
++#define EMMC_DATA6_DS_1V8		0xc0
++#define EMMC_DATA7_DS_1V8		0xc0
++
++struct sdio_drv_cap {
++	unsigned int reg_addr[2];
++	unsigned int ds;
++};
++
++#define SDIO_DRV_CAP(ofst1, ofst2, v) { \
++	.reg_addr[0] = (REG_PAD_CTRL + ofst1), \
++	.reg_addr[1] = (REG_PAD_CTRL + ofst2), \
++	.ds = v}
++static struct sdio_drv_cap sdio_ds_hs[] = {
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CCLK, REG_CTRL_SDIO1_CCLK, 0x1c0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CCMD, REG_CTRL_SDIO1_CCMD, 0x1e0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CDATA0, REG_CTRL_SDIO1_CDATA0, 0x1e0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CDATA1, REG_CTRL_SDIO1_CDATA1, 0x1e0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CDATA2, REG_CTRL_SDIO1_CDATA2, 0x1e0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CDATA3, REG_CTRL_SDIO1_CDATA3, 0x1e0)
++};
++
++static struct sdio_drv_cap sdio_ds_ddr50[] = {
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CCLK, REG_CTRL_SDIO1_CCLK, 0x1b0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CCMD, REG_CTRL_SDIO1_CCMD, 0x1c0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CDATA0, REG_CTRL_SDIO1_CDATA0, 0x1c0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CDATA1, REG_CTRL_SDIO1_CDATA1, 0x1c0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CDATA2, REG_CTRL_SDIO1_CDATA2, 0x1c0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CDATA3, REG_CTRL_SDIO1_CDATA3, 0x1c0)
++};
++
++static struct sdio_drv_cap sdio_ds_sdr50[] = {
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CCLK, REG_CTRL_SDIO1_CCLK, 0x80),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CCMD, REG_CTRL_SDIO1_CCMD, 0x1c0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CDATA0, REG_CTRL_SDIO1_CDATA0, 0x1c0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CDATA1, REG_CTRL_SDIO1_CDATA1, 0x1c0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CDATA2, REG_CTRL_SDIO1_CDATA2, 0x1c0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CDATA3, REG_CTRL_SDIO1_CDATA3, 0x1c0)
++};
++
++static struct sdio_drv_cap sdio_ds_sdr104[] = {
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CCLK, REG_CTRL_SDIO1_CCLK, 0x0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CCMD, REG_CTRL_SDIO1_CCMD, 0xc0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CDATA0, REG_CTRL_SDIO1_CDATA0, 0xc0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CDATA1, REG_CTRL_SDIO1_CDATA1, 0xc0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CDATA2, REG_CTRL_SDIO1_CDATA2, 0xc0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CDATA3, REG_CTRL_SDIO1_CDATA3, 0xc0)
++};
++
++struct emmc_drv_cap {
++	unsigned int reg_addr;
++	unsigned int ds[2];
++};
++
++#define EMMC_DRV_CAP(ofst, v1, v2) { \
++	.reg_addr = (REG_PAD_CTRL + ofst), \
++	.ds[0] = v1, \
++	.ds[1] = v2}
++static  struct emmc_drv_cap emmc_ds[] = {
++	EMMC_DRV_CAP(REG_CTRL_EMMC_CLK, EMMC_CLK_DS_3V3, EMMC_CLK_DS_1V8),
++	EMMC_DRV_CAP(REG_CTRL_EMMC_CMD, EMMC_CMD_DS_3V3, EMMC_CMD_DS_1V8),
++	EMMC_DRV_CAP(REG_CTRL_EMMC_DATA0, EMMC_DATA0_DS_3V3, EMMC_DATA0_DS_1V8),
++	EMMC_DRV_CAP(REG_CTRL_EMMC_DATA1, EMMC_DATA1_DS_3V3, EMMC_DATA1_DS_1V8),
++	EMMC_DRV_CAP(REG_CTRL_EMMC_DATA2, EMMC_DATA2_DS_3V3, EMMC_DATA2_DS_1V8),
++	EMMC_DRV_CAP(REG_CTRL_EMMC_DATA3, EMMC_DATA3_DS_3V3, EMMC_DATA3_DS_1V8),
++	EMMC_DRV_CAP(REG_CTRL_EMMC_DATA4, EMMC_DATA4_DS_3V3, EMMC_DATA4_DS_1V8),
++	EMMC_DRV_CAP(REG_CTRL_EMMC_DATA5, EMMC_DATA5_DS_3V3, EMMC_DATA5_DS_1V8),
++	EMMC_DRV_CAP(REG_CTRL_EMMC_DATA6, EMMC_DATA6_DS_3V3, EMMC_DATA6_DS_1V8),
++	EMMC_DRV_CAP(REG_CTRL_EMMC_DATA7, EMMC_DATA7_DS_3V3, EMMC_DATA7_DS_1V8),
++};
++
++static void himci_set_pin_drv_cap(struct himci_host *host, unsigned int flag,
++		unsigned char timing)
++{
++	struct sdio_drv_cap *sdio_ds;
++	unsigned int i;
++
++	if (host->devid == 2) {
++		for (i = 0; i < ARRAY_SIZE(emmc_ds); i++)
++			himci_writel(emmc_ds[i].ds[flag], IO_ADDRESS(emmc_ds[i].reg_addr));
++	} else {
++		if (timing == MMC_TIMING_UHS_SDR104)
++			sdio_ds = sdio_ds_sdr104;
++		else if (timing ==  MMC_TIMING_UHS_SDR50)
++			sdio_ds = sdio_ds_sdr50;
++		else if (timing ==  MMC_TIMING_UHS_DDR50)
++			sdio_ds = sdio_ds_ddr50;
++		else
++			sdio_ds = sdio_ds_hs;
++
++		for (i = 0; i < ARRAY_SIZE(sdio_ds_hs); i++)
++			himci_writel(sdio_ds[i].ds,
++					IO_ADDRESS(sdio_ds[i].reg_addr[host->devid]));
++	}
++}
++
++static void himci_set_drv_cap(struct himci_host *host, struct mmc_ios *ios)
++{
++	unsigned int tmp_reg;
++
++	if (ios->timing == MMC_TIMING_UHS_DDR50) {
++		tmp_reg = himci_readl(host->base + MCI_UHS_REG_EXT);
++		tmp_reg &= ~CLK_SMPL_PHS_MASK;
++		tmp_reg |= (0x4 << CLK_SMPL_PHS_SHIFT);
++		himci_writel(tmp_reg, host->base + MCI_UHS_REG_EXT);
++	} else if (ios->timing == MMC_TIMING_MMC_HS) {
++		tmp_reg = himci_readl(host->base + MCI_UHS_REG_EXT);
++		tmp_reg &= ~CLK_SMPL_PHS_MASK;
++		tmp_reg |= SMPL_PHASE_DFLT;
++		himci_writel(tmp_reg, host->base + MCI_UHS_REG_EXT);
++	} else if (ios->timing == MMC_TIMING_MMC_HS400) {
++		tmp_reg = himci_readl(host->base + MCI_UHS_REG_EXT);
++		tmp_reg &= ~CLK_SMPL_PHS_MASK;
++		tmp_reg |= (host->phase << CLK_SMPL_PHS_SHIFT);
++		himci_writel(tmp_reg, host->base + MCI_UHS_REG_EXT);
++	}
++
++	/* set pin drive capability */
++	if (ios->timing == MMC_TIMING_MMC_HS200 ||
++			ios->timing == MMC_TIMING_MMC_HS400)
++		himci_set_pin_drv_cap(host, 1, ios->timing);
++	else
++		himci_set_pin_drv_cap(host, 0, ios->timing);
++}
++
++static int himci_check_emmc(struct himci_host *host)
++{
++	unsigned int val;
++
++	val = himci_readl(IO_ADDRESS(SYS_CTRL_BASE + REG_SC_STAT));
++
++	return !(GET_SYS_BOOT_MODE(val) == BOOT_FROM_EMMC);
++}
+diff --git a/drivers/mmc/host/himciv200/himci_hi3559.c b/drivers/mmc/host/himciv200/himci_hi3559.c
+new file mode 100644
+index 0000000..f505bf5
+--- /dev/null
++++ b/drivers/mmc/host/himciv200/himci_hi3559.c
+@@ -0,0 +1,210 @@
++/*
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++#include <mach/platform.h>
++
++#define MMC_CRG_MIN       12500000
++
++#define PERI_CRG49			IO_ADDRESS(0x120100c4)
++#define EMMC_DLL_CTRL		IO_ADDRESS(0x12030140)
++
++#define TUNING_START_PHASE      0
++#define TUNING_END_PHASE        15
++#define HIMCI_PHASE_SCALE       16
++#define DRV_PHASE_DFLT         (0x6<<23)
++#define SMPL_PHASE_DFLT        (0x0<<16)
++
++#define EMMC_DRV_PHASE_DFLT         (0x4<<23)
++#define EMMC_SMPL_PHASE_DFLT        SMPL_PHASE_DFLT
++
++#define REG_PAD_CTRL			0x12040800
++#define REG_CTRL_SDIO0_CCLK		0xc4
++#define REG_CTRL_SDIO0_CCMD		0xc8
++#define REG_CTRL_SDIO0_CDATA0	0xcc
++#define REG_CTRL_SDIO0_CDATA1	0xd0
++#define REG_CTRL_SDIO0_CDATA2	0xd4
++#define REG_CTRL_SDIO0_CDATA3	0xd8
++
++#define REG_CTRL_SDIO1_CCLK		0xe8
++#define REG_CTRL_SDIO1_CCMD		0xec
++#define REG_CTRL_SDIO1_CDATA0	0xf0
++#define REG_CTRL_SDIO1_CDATA1	0xf4
++#define REG_CTRL_SDIO1_CDATA2	0xf8
++#define REG_CTRL_SDIO1_CDATA3	0xfc
++
++#define REG_CTRL_EMMC_CLK		0x1ac
++#define REG_CTRL_EMMC_CMD		0x1c8
++#define REG_CTRL_EMMC_DATA0		0x1b0
++#define REG_CTRL_EMMC_DATA1		0x1cc
++#define REG_CTRL_EMMC_DATA2		0x1b4
++#define REG_CTRL_EMMC_DATA3		0x1bc
++#define REG_CTRL_EMMC_DATA4		0x1c0
++#define REG_CTRL_EMMC_DATA5		0x1a8
++#define REG_CTRL_EMMC_DATA6		0x1dc
++#define REG_CTRL_EMMC_DATA7		0x1b8
++
++#define EMMC_CLK_DS_3V3			0xd0
++#define EMMC_CMD_DS_3V3			0xd0
++#define EMMC_DATA0_DS_3V3		0xd0
++#define EMMC_DATA1_DS_3V3		0xd0
++#define EMMC_DATA2_DS_3V3		0xd0
++#define EMMC_DATA3_DS_3V3		0xd0
++#define EMMC_DATA4_DS_3V3		0xd0
++#define EMMC_DATA5_DS_3V3		0xd0
++#define EMMC_DATA6_DS_3V3		0xd0
++#define EMMC_DATA7_DS_3V3		0xd0
++
++#define EMMC_CLK_DS_1V8			0xc0
++#define EMMC_CMD_DS_1V8			0xc0
++#define EMMC_DATA0_DS_1V8		0xc0
++#define EMMC_DATA1_DS_1V8		0xc0
++#define EMMC_DATA2_DS_1V8		0xc0
++#define EMMC_DATA3_DS_1V8		0xc0
++#define EMMC_DATA4_DS_1V8		0xc0
++#define EMMC_DATA5_DS_1V8		0xc0
++#define EMMC_DATA6_DS_1V8		0xc0
++#define EMMC_DATA7_DS_1V8		0xc0
++
++struct sdio_drv_cap {
++	unsigned int reg_addr[2];
++	unsigned int ds;
++};
++
++#define SDIO_DRV_CAP(ofst1, ofst2, v) { \
++	.reg_addr[0] = (REG_PAD_CTRL + ofst1), \
++	.reg_addr[1] = (REG_PAD_CTRL + ofst2), \
++	.ds = v}
++static struct sdio_drv_cap sdio_ds_hs[] = {
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CCLK, REG_CTRL_SDIO1_CCLK, 0x1c0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CCMD, REG_CTRL_SDIO1_CCMD, 0x1e0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CDATA0, REG_CTRL_SDIO1_CDATA0, 0x1e0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CDATA1, REG_CTRL_SDIO1_CDATA1, 0x1e0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CDATA2, REG_CTRL_SDIO1_CDATA2, 0x1e0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CDATA3, REG_CTRL_SDIO1_CDATA3, 0x1e0)
++};
++
++static struct sdio_drv_cap sdio_ds_ddr50[] = {
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CCLK, REG_CTRL_SDIO1_CCLK, 0x1b0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CCMD, REG_CTRL_SDIO1_CCMD, 0x1c0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CDATA0, REG_CTRL_SDIO1_CDATA0, 0x1c0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CDATA1, REG_CTRL_SDIO1_CDATA1, 0x1c0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CDATA2, REG_CTRL_SDIO1_CDATA2, 0x1c0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CDATA3, REG_CTRL_SDIO1_CDATA3, 0x1c0)
++};
++
++static struct sdio_drv_cap sdio_ds_sdr50[] = {
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CCLK, REG_CTRL_SDIO1_CCLK, 0x80),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CCMD, REG_CTRL_SDIO1_CCMD, 0x1c0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CDATA0, REG_CTRL_SDIO1_CDATA0, 0x1c0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CDATA1, REG_CTRL_SDIO1_CDATA1, 0x1c0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CDATA2, REG_CTRL_SDIO1_CDATA2, 0x1c0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CDATA3, REG_CTRL_SDIO1_CDATA3, 0x1c0)
++};
++
++static struct sdio_drv_cap sdio_ds_sdr104[] = {
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CCLK, REG_CTRL_SDIO1_CCLK, 0x0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CCMD, REG_CTRL_SDIO1_CCMD, 0xc0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CDATA0, REG_CTRL_SDIO1_CDATA0, 0xc0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CDATA1, REG_CTRL_SDIO1_CDATA1, 0xc0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CDATA2, REG_CTRL_SDIO1_CDATA2, 0xc0),
++	SDIO_DRV_CAP(REG_CTRL_SDIO0_CDATA3, REG_CTRL_SDIO1_CDATA3, 0xc0)
++};
++
++struct emmc_drv_cap {
++	unsigned int reg_addr;
++	unsigned int ds[2];
++};
++
++#define EMMC_DRV_CAP(ofst, v1, v2) { \
++	.reg_addr = (REG_PAD_CTRL + ofst), \
++	.ds[0] = v1, \
++	.ds[1] = v2}
++static  struct emmc_drv_cap emmc_ds[] = {
++	EMMC_DRV_CAP(REG_CTRL_EMMC_CLK, EMMC_CLK_DS_3V3, EMMC_CLK_DS_1V8),
++	EMMC_DRV_CAP(REG_CTRL_EMMC_CMD, EMMC_CMD_DS_3V3, EMMC_CMD_DS_1V8),
++	EMMC_DRV_CAP(REG_CTRL_EMMC_DATA0, EMMC_DATA0_DS_3V3, EMMC_DATA0_DS_1V8),
++	EMMC_DRV_CAP(REG_CTRL_EMMC_DATA1, EMMC_DATA1_DS_3V3, EMMC_DATA1_DS_1V8),
++	EMMC_DRV_CAP(REG_CTRL_EMMC_DATA2, EMMC_DATA2_DS_3V3, EMMC_DATA2_DS_1V8),
++	EMMC_DRV_CAP(REG_CTRL_EMMC_DATA3, EMMC_DATA3_DS_3V3, EMMC_DATA3_DS_1V8),
++	EMMC_DRV_CAP(REG_CTRL_EMMC_DATA4, EMMC_DATA4_DS_3V3, EMMC_DATA4_DS_1V8),
++	EMMC_DRV_CAP(REG_CTRL_EMMC_DATA5, EMMC_DATA5_DS_3V3, EMMC_DATA5_DS_1V8),
++	EMMC_DRV_CAP(REG_CTRL_EMMC_DATA6, EMMC_DATA6_DS_3V3, EMMC_DATA6_DS_1V8),
++	EMMC_DRV_CAP(REG_CTRL_EMMC_DATA7, EMMC_DATA7_DS_3V3, EMMC_DATA7_DS_1V8),
++};
++
++static void himci_set_pin_drv_cap(struct himci_host *host, unsigned int flag,
++		unsigned char timing)
++{
++	struct sdio_drv_cap *sdio_ds;
++	unsigned int i;
++
++	if (host->devid == 2) {
++		for (i = 0; i < ARRAY_SIZE(emmc_ds); i++)
++			himci_writel(emmc_ds[i].ds[flag], IO_ADDRESS(emmc_ds[i].reg_addr));
++	} else {
++		if (timing == MMC_TIMING_UHS_SDR104)
++			sdio_ds = sdio_ds_sdr104;
++		else if (timing ==  MMC_TIMING_UHS_SDR50)
++			sdio_ds = sdio_ds_sdr50;
++		else if (timing ==  MMC_TIMING_UHS_DDR50)
++			sdio_ds = sdio_ds_ddr50;
++		else
++			sdio_ds = sdio_ds_hs;
++
++		for (i = 0; i < ARRAY_SIZE(sdio_ds_hs); i++)
++			himci_writel(sdio_ds[i].ds,
++					IO_ADDRESS(sdio_ds[i].reg_addr[host->devid]));
++	}
++}
++
++static void himci_set_drv_cap(struct himci_host *host, struct mmc_ios *ios)
++{
++	unsigned int tmp_reg;
++
++	if (ios->timing == MMC_TIMING_UHS_DDR50) {
++		tmp_reg = himci_readl(host->base + MCI_UHS_REG_EXT);
++		tmp_reg &= ~CLK_SMPL_PHS_MASK;
++		tmp_reg |= (0x4 << CLK_SMPL_PHS_SHIFT);
++		himci_writel(tmp_reg, host->base + MCI_UHS_REG_EXT);
++	} else if (ios->timing == MMC_TIMING_MMC_HS) {
++		tmp_reg = himci_readl(host->base + MCI_UHS_REG_EXT);
++		tmp_reg &= ~CLK_SMPL_PHS_MASK;
++		tmp_reg |= SMPL_PHASE_DFLT;
++		himci_writel(tmp_reg, host->base + MCI_UHS_REG_EXT);
++	} else if (ios->timing == MMC_TIMING_MMC_HS400) {
++		tmp_reg = himci_readl(host->base + MCI_UHS_REG_EXT);
++		tmp_reg &= ~CLK_SMPL_PHS_MASK;
++		tmp_reg |= (host->phase << CLK_SMPL_PHS_SHIFT);
++		himci_writel(tmp_reg, host->base + MCI_UHS_REG_EXT);
++	}
++
++	/* set pin drive capability */
++	if (ios->timing == MMC_TIMING_MMC_HS200 ||
++			ios->timing == MMC_TIMING_MMC_HS400)
++		himci_set_pin_drv_cap(host, 1, ios->timing);
++	else
++		himci_set_pin_drv_cap(host, 0, ios->timing);
++}
++
++static int himci_check_emmc(struct himci_host *host)
++{
++	unsigned int val;
++
++	val = himci_readl(IO_ADDRESS(SYS_CTRL_BASE + REG_SC_STAT));
++
++	return !(GET_SYS_BOOT_MODE(val) == BOOT_FROM_EMMC);
++}
+diff --git a/drivers/mmc/host/himciv200/himci_proc.c b/drivers/mmc/host/himciv200/himci_proc.c
+new file mode 100644
+index 0000000..280f24f
+--- /dev/null
++++ b/drivers/mmc/host/himciv200/himci_proc.c
+@@ -0,0 +1,290 @@
++/*****************************************************************************
++ *  This is the driver for the host mci SOC.
++ *
++ *  Copyright (C) Hisilicon. All rights reserved.
++ *
++ ******************************************************************************/
++
++#include <linux/proc_fs.h>
++#include <linux/seq_file.h>
++#include <linux/device.h>
++#include <linux/io.h>
++#include <linux/platform_device.h>
++
++#include <linux/mmc/card.h>
++
++#include <linux/export.h>
++#include <linux/mmc/host.h>
++#include "himci.h"
++#include "himci_reg.h"
++#include "himci_proc.h"
++
++#define MCI_PARENT       "mci"
++#define MCI_STATS_PROC   "mci_info"
++#define MAX_CLOCK_SCALE	(4)
++#define UNSTUFF_BITS(resp,start,size)                   \
++	({                              \
++	 const int __size = size;                \
++	 const u32 __mask = (__size < 32 ? 1 << __size : 0) - 1; \
++	 const int __off = 3 - ((start) / 32);           \
++	 const int __shft = (start) & 31;            \
++	 u32 __res;                      \
++	 \
++	 __res = resp[__off] >> __shft;              \
++	 if (__size + __shft > 32)               \
++	 __res |= resp[__off-1] << ((32 - __shft) % 32); \
++	 __res & __mask;                     \
++	 })
++
++static struct proc_dir_entry *proc_mci_dir;
++static unsigned int mci_max_connections;
++static char *card_type[MAX_CARD_TYPE + 1] = {
++	"MMC card",
++	"SD card",
++	"SDIO card",
++	"SD combo (IO+mem) card",
++	"unknown"
++};
++static char *clock_unit[4] = {
++	"Hz",
++	"KHz",
++	"MHz",
++	"GHz"
++};
++
++static char *mci_get_card_type(unsigned int sd_type)
++{
++	if (MAX_CARD_TYPE <= sd_type)
++		return card_type[MAX_CARD_TYPE];
++	else
++		return card_type[sd_type];
++}
++
++static unsigned int analyze_clock_scale(unsigned int clock,
++		unsigned int *clock_val)
++{
++	unsigned int scale = 0;
++	unsigned int tmp = clock;
++
++	while (1) {
++		tmp = tmp / 1000;
++		if (0 < tmp) {
++			*clock_val = tmp;
++			scale++;
++		} else {
++			break;
++		}
++	}
++	return scale;
++}
++
++static inline int is_card_uhs(unsigned char timing)
++{
++	return timing >= MMC_TIMING_UHS_SDR12 &&
++		timing <= MMC_TIMING_UHS_DDR50;
++}
++
++static inline int is_card_hs(unsigned char timing)
++{
++	return timing == MMC_TIMING_SD_HS || timing == MMC_TIMING_MMC_HS;
++}
++
++static void mci_stats_seq_printout(struct seq_file *s)
++{
++	unsigned int index_mci;
++	unsigned int clock;
++	unsigned int clock_scale;
++	unsigned int clock_value = 0;
++	const char *type;
++	struct himci_host *host;
++	struct card_info * c_info;
++	const char *uhs_bus_speed_mode = "";
++	u32 speed_class, grade_speed_uhs;
++	static const char *const uhs_speeds[] = {
++		[UHS_SDR12_BUS_SPEED] = "SDR12 ",
++		[UHS_SDR25_BUS_SPEED] = "SDR25 ",
++		[UHS_SDR50_BUS_SPEED] = "SDR50 ",
++		[UHS_SDR104_BUS_SPEED] = "SDR104 ",
++		[UHS_DDR50_BUS_SPEED] = "DDR50 ",
++	};
++
++
++	for (index_mci = 0; index_mci < HIMCI_SLOT_NUM; index_mci++) {
++		host = mci_host[index_mci];
++		c_info = &host->c_info;
++		if (!host || !host->mmc) {
++			seq_printf(s, "MCI%d: invalid\n", index_mci);
++			continue;
++		} else {
++			seq_printf(s, "MCI%d", index_mci);
++		}
++
++		if (CARD_PLUGED == host->card_status) {
++			seq_puts(s, ": pluged");
++		} else {
++			seq_puts(s, ": unplugged");
++		}
++
++		if (CARD_CONNECT != c_info->card_connect) {
++			seq_puts(s, "_disconnected\n");
++		} else {
++			seq_puts(s, "_connected\n");
++
++			seq_printf(s,
++					"\tType: %s",
++					mci_get_card_type(c_info->card_type)
++				  );
++
++			if (c_info->card_state & MMC_STATE_BLOCKADDR) {
++				if (c_info->card_state & MMC_CARD_SDXC)
++					type = "SDXC";
++				else
++					type = "SDHC";
++				seq_printf(s, "(%s)\n", type);
++			}
++
++			if (is_card_uhs(c_info->timing) &&
++					c_info->sd_bus_speed < ARRAY_SIZE(uhs_speeds))
++				uhs_bus_speed_mode = uhs_speeds[c_info->sd_bus_speed];
++
++			seq_printf(s, "\tMode: %s%s%s%s\n",
++					is_card_uhs(c_info->timing) ? "UHS " :
++					(is_card_hs(c_info->timing) ? "HS " : ""),
++					c_info->timing == MMC_TIMING_MMC_HS400 ? "HS400 " :
++					(c_info->timing == MMC_TIMING_MMC_HS200 ? "HS200 " : ""),
++					c_info->timing == MMC_TIMING_MMC_DDR52 ? "DDR " : "",
++					uhs_bus_speed_mode);
++
++			speed_class = UNSTUFF_BITS(c_info->ssr, 440 - 384, 8);
++			grade_speed_uhs = UNSTUFF_BITS(c_info->ssr, 396 - 384, 4);
++			seq_printf(s, "\tSpeed Class: Class %s\n",
++					(0x00 == speed_class) ? "0":
++					(0x01 == speed_class) ? "2":
++					(0x02 == speed_class) ? "4":
++					(0x03 == speed_class) ? "6":
++					(0x04 == speed_class) ? "10":
++					"Reserved");
++			seq_printf(s, "\tUhs Speed Grade: %s\n",
++					(0x00 == grade_speed_uhs)?
++					"Less than 10MB/sec(0h)" :
++					(0x01 == grade_speed_uhs)?
++					"10MB/sec and above(1h)":
++					"Reserved");
++
++			clock = host->hclk;
++			clock_scale = analyze_clock_scale(clock, &clock_value);
++			seq_printf(s, "\tHost work clock: %d%s\n",
++					clock_value, clock_unit[clock_scale]);
++
++			clock = c_info->card_support_clock;
++			clock_scale = analyze_clock_scale(clock, &clock_value);
++			seq_printf(s, "\tCard support clock: %d%s\n",
++					clock_value, clock_unit[clock_scale]);
++
++			clock = host->cclk;
++			clock_scale = analyze_clock_scale(clock, &clock_value);
++			seq_printf(s, "\tCard work clock: %d%s\n",
++					clock_value, clock_unit[clock_scale]);
++			/* add card read/write error count */
++			seq_printf(s, "\tCard error count: %d\n",
++					host->error_count);
++		}
++	}
++}
++
++/* proc interface setup */
++static void *mci_seq_start(struct seq_file *s, loff_t *pos)
++{
++	/*   counter is used to tracking multi proc interfaces
++	 *  We have only one interface so return zero
++	 *  pointer to start the sequence.
++	 */
++	static unsigned long counter;
++
++	if (*pos == 0)
++		return &counter;
++
++	*pos = 0;
++	return NULL;
++}
++
++/* proc interface next */
++static void *mci_seq_next(struct seq_file *s, void *v, loff_t *pos)
++{
++	(*pos)++;
++	if (*pos >= HIMCI_SLOT_NUM)
++		return NULL;
++
++	return NULL;
++}
++
++/* define parameters where showed in proc file */
++static int mci_stats_seq_show(struct seq_file *s, void *v)
++{
++	mci_stats_seq_printout(s);
++	return 0;
++}
++
++/* proc interface stop */
++static void mci_seq_stop(struct seq_file *s, void *v)
++{
++}
++
++/* proc interface operation */
++static const struct seq_operations mci_stats_seq_ops = {
++	.start = mci_seq_start,
++	.next = mci_seq_next,
++	.stop = mci_seq_stop,
++	.show = mci_stats_seq_show
++};
++
++/* proc file open*/
++static int mci_stats_proc_open(struct inode *inode, struct file *file)
++{
++	return seq_open(file, &mci_stats_seq_ops);
++};
++
++/* proc file operation */
++static const struct file_operations mci_stats_proc_ops = {
++	.owner = THIS_MODULE,
++	.open = mci_stats_proc_open,
++	.read = seq_read,
++	.release = seq_release
++};
++
++int mci_proc_init(unsigned int max_connections)
++{
++	struct proc_dir_entry *proc_stats_entry;
++
++	mci_max_connections = max_connections;
++
++	proc_mci_dir = proc_mkdir(MCI_PARENT, NULL);
++	if (!proc_mci_dir) {
++		pr_err("%s: failed to create proc file %s\n",
++				__func__, MCI_PARENT);
++		return 1;
++	}
++
++	proc_stats_entry = proc_create(MCI_STATS_PROC,
++			0, proc_mci_dir, &mci_stats_proc_ops);
++	if (!proc_stats_entry) {
++		pr_err("%s: failed to create proc file %s\n",
++				__func__, MCI_STATS_PROC);
++		return 1;
++	}
++
++	return 0;
++}
++
++int mci_proc_shutdown(void)
++{
++	if (proc_mci_dir) {
++		if (mci_max_connections > 0)
++			remove_proc_entry(MCI_STATS_PROC, proc_mci_dir);
++
++		remove_proc_entry(MCI_PARENT, NULL);
++		proc_mci_dir = NULL;
++	}
++
++	return 0;
++}
+diff --git a/drivers/mmc/host/himciv200/himci_proc.h b/drivers/mmc/host/himciv200/himci_proc.h
+new file mode 100644
+index 0000000..989d6e4
+--- /dev/null
++++ b/drivers/mmc/host/himciv200/himci_proc.h
+@@ -0,0 +1,25 @@
++/*
++ *  MCI connection table manager
++ */
++#ifndef __MCI_PROC_H__
++#define __MCI_PROC_H__
++
++#include <linux/proc_fs.h>
++
++#define MAX_CARD_TYPE	4
++#define MAX_SPEED_MODE	5
++
++#ifdef CONFIG_ARCH_HI3516CV300
++	#define HIMCI_SLOT_NUM 4
++#endif
++
++#if (defined CONFIG_ARCH_HI3519 || defined CONFIG_ARCH_HI3519V101 || defined CONFIG_ARCH_HI3559 || defined CONFIG_ARCH_HI3556 || \
++		defined CONFIG_ARCH_HI3516AV200)
++	#define HIMCI_SLOT_NUM 3
++#endif
++
++extern struct himci_host *mci_host[HIMCI_SLOT_NUM];
++int mci_proc_init(unsigned int max_connections);
++int mci_proc_shutdown(void);
++
++#endif /*  __MCI_PROC_H__ */
+diff --git a/drivers/mmc/host/himciv200/himci_reg.h b/drivers/mmc/host/himciv200/himci_reg.h
+new file mode 100644
+index 0000000..8ecb3ed
+--- /dev/null
++++ b/drivers/mmc/host/himciv200/himci_reg.h
+@@ -0,0 +1,252 @@
++#ifndef _HI_MCI_REG_H_
++#define _HI_MCI_REG_H_
++
++#define HI_MCI_IO_SIZE		0x1000
++
++#define MCI_CTRL		0x00
++#define MCI_PWREN		0x04
++#define MCI_CLKDIV		0x08
++#define MCI_CLKSRC		0x0C
++#define MCI_CLKENA		0x10
++#define MCI_TIMEOUT		0x14
++#define MCI_CTYPE		0x18
++#define MCI_BLKSIZ		0x1c
++#define MCI_BYTCNT		0x20
++#define MCI_INTMASK		0x24
++#define MCI_CMDARG		0x28
++#define MCI_CMD			0x2C
++#define MCI_RESP0		0x30
++#define MCI_RESP1		0x34
++#define MCI_RESP2		0x38
++#define MCI_RESP3		0x3C
++#define MCI_MINTSTS		0x40
++#define MCI_RINTSTS		0x44
++#define MCI_STATUS		0x48
++#define MCI_FIFOTH		0x4C
++#define MCI_CDETECT		0x50
++#define MCI_WRTPRT		0x54
++#define MCI_GPIO		0x58
++#define MCI_TCBCNT		0x5C
++#define MCI_TBBCNT		0x60
++#define MCI_DEBNCE		0x64
++#define MCI_USRID		0x68
++#define MCI_VERID		0x6C
++#define MCI_HCON		0x70
++#define MCI_UHS_REG		0x74
++#define MCI_RESET_N		0x78
++#define MCI_BMOD		0x80
++#define MCI_DBADDR		0x88
++#define MCI_IDSTS		0x8C
++#define MCI_IDINTEN		0x90
++#define MCI_DSCADDR		0x94
++#define MCI_BUFADDR		0x98
++#define ADMA_CTRL		0xb0
++#define ADMA_Q_ADDR		0xb4
++#define ADMA_Q_DEEPTH	0xb8
++#define ADMA_Q_RDPTR	0xbc
++#define ADMA_Q_WRPTR	0xc0
++#define ADMA_Q_TO		0xc4
++#define MCI_CARDTHRCTL		0x100
++#define MCI_UHS_REG_EXT     0x108
++#define MCI_EMMC_DDR_REG    0x10c
++#define MCI_TUNING_CTRL		0x118
++
++/* MCI_IDSTS(0x8c) detals */
++#define CMD_LOCK_ERR	(0x1<<29)
++#define OWNBIT_ERR		(0x1<<28)
++#define QUEUE_OVERFLOW	(0x1<<27)
++#define RESP_CHECK_ERR	(0x1<<26)
++#define PACKET_INT		(0x1<<25)
++#define PACKET_TO_INT	(0x1<<24)
++#define AUTO_STOP_ERR	(0x1<<23)
++#define QUEUE_FULL		(0x1<<22)
++#define QUEUE_EMPTY		(0x1<<21)
++#define ADMA3_FSM_SHIFT	(17)
++#define FSM_SHIFT		(13)
++#define CES			(0x1<<5)
++#define DU			(0x1<<4)
++#define FBE			(0x1<<2)
++
++#define ADMA_INT_ERR		(CMD_LOCK_ERR | OWNBIT_ERR | QUEUE_OVERFLOW \
++				| AUTO_STOP_ERR | PACKET_TO_INT | DU | FBE)
++
++#define ADMA_INT_ALL		(CMD_LOCK_ERR | OWNBIT_ERR | QUEUE_OVERFLOW \
++					| RESP_CHECK_ERR | PACKET_INT \
++					| PACKET_TO_INT | AUTO_STOP_ERR \
++					| QUEUE_FULL | CES | DU | FBE)
++#define RESP_CHK_EN		(0x1<<4)
++#define RDPTR_MOD_EN	(0x1<<3)
++#define PACKET_INT_EN	(0x1<<2)
++#define ADMA3_RESTART	(0x1<<1)
++#define ADMA3_EN		(0x1<<0)
++
++/* GPIO config */
++#define DTO_FIX_BYPASS		(0x1<<23)
++#define CMD_OUT_EN_FIX_BYPASS	(0x1<<8)
++
++/* MCI_UHS_REG(0x74) details */
++#define HI_EMMC_CTRL_VDD_180	(0x2<<0)
++#define HI_EMMC_CTRL_DDR_REG	(0x2<<16)
++#define HI_SDXC_CTRL_VDD_180	(0x1<<0)
++#define HI_SDXC_CTRL_DDR_REG	(0x1<<16)
++
++/* MCI_BMOD(0x80) details */
++#define BMOD_SWR		(0x1<<0)
++#define BURST_INCR		(0x1<<1)
++#define BMOD_DMA_EN		(0x1<<7)
++#define BURST_8			(0x2<<8)
++#define BURST_16		(0x3<<8)
++
++/* MCI_CTRL(0x00) details */
++#define CTRL_RESET		(1<<0)
++#define FIFO_RESET		(1<<1)
++#define DMA_RESET		(1<<2)
++#define INTR_EN			(1<<4)
++#define USE_INTERNAL_DMA	(1<<25)
++
++/* IDMAC DEST1 details */
++#define DMA_BUFFER		(0x2000)
++#define MAX_DMA_DES		(20480)
++
++/* IDMAC DEST0 details */
++#define DMA_DES_OWN		(1<<31)
++#define DMA_DES_NEXT_DES	(1<<4)
++#define DMA_DES_FIRST_DES	(1<<3)
++#define DMA_DES_LAST_DES	(1<<2)
++
++/* MCI_CDETECT(0x50) details */
++#define HIMCI_CARD0		(0x1<<0)
++#define HIMCI_CARD_MASK		(0x3<<0)
++#define HIMCI_CARD_EMMC		(0x1<<1)
++#define HIMCI_CARD_SD		(0x1<<0)
++
++/* MCI_TIMEOUT(0x14) details: */
++/*bit 31-8: data read timeout param */
++#define DATA_TIMEOUT		(0xffffff<<8)
++/* bit 7-0: response timeout param */
++#define RESPONSE_TIMEOUT	0xff
++
++/* MCI_CLKENA(0x10) details */
++#define CCLK_ENABLE		(0x1<<0)	/* bit 0: enable of card clk*/
++
++/* MCI_CTYPE(0x18) details */
++#define EMMC_CARD_WIDTH_1	(0x2<<0)
++#define EMMC_CARD_WIDTH_0	(0x2<<16)
++#define CARD_WIDTH_1		(0x1<<0)
++#define CARD_WIDTH_0		(0x1<<16)
++
++/* MCI_CARDTHRCTL(0x100) details */
++#define RW_THRESHOLD_SIZE	(0x2000005)
++
++/* MCI_SRC(0x0C) details */
++#define EMMC_CLK_SOURCE		(0x1<<2)
++
++/* MCI_EMMC_DDR_REG(0x10c) details */
++#define HI_EMMC_HS400_MODE	(0x1<<31)
++
++/* MCI_RESET_N(0x78) details */
++#define MMC_RST_N		(0x1<<0)	/* control reset*/
++
++/* MCI_INTMASK(0x24) details:
++   bit 16-1: mask MMC host controller each interrupt
++*/
++#define ALL_INT_MASK		0x1ffff
++#define DTO_INT_MASK		(0x1<<3)
++#define SDIO_INT_MASK		(0x1<<16)
++
++/* MCI_UHS_REG_EXT(0x108) details */
++/* bit[19:16] sampling phase */
++#define CLK_SMPL_PHS_SHIFT	(16)
++#define CLK_SMPL_PHS_MASK	(0xF<<16)
++#define CLK_SMPLA_PHS_SHIFT	(9)
++#define CLK_SMPLA_PHS_MASK	(0x7<<9)
++/* bit[26:23] drv phase */
++#define CLK_DRV_PHS_SHIFT	(23)
++#define CLK_DRV_PHS_MASK	(0xF<<23)
++#define DEFAULT_SMPL_PHASE	(0x5)
++
++/* MCI_CMD(0x2c) details:
++   bit 31: cmd execute or load start param of interface clk bit
++*/
++#define START_CMD         (0x1<<31)
++
++/* MCI_INTSTS(0x44) details */
++/***************************************************************/
++/* bit 16: sdio interrupt status */
++#define SDIO_INT_STATUS    (0x1<<16)
++
++/* bit 15: end-bit error (read)/write no CRC interrupt status */
++#define EBE_INT_STATUS    (0x1<<15)
++
++/* bit 14: auto command done interrupt status */
++#define ACD_INT_STATUS    (0x1<<14)
++
++/* bit 13: start bit error interrupt status */
++#define SBE_INT_STATUS    (0x1<<13)
++
++/* bit 12: hardware locked write error interrupt status */
++#define HLE_INT_STATUS    (0x1<<12)
++
++/* bit 11: FIFO underrun/overrun error interrupt status */
++#define FRUN_INT_STATUS    (0x1<<11)
++
++/* bit 10: data starvation-by-host timeout interrupt status */
++#define HTO_INT_STATUS    (0x1<<10)
++
++/* bit 10: volt_switch to 1.8v for sdxc */
++#define VOLT_SWITCH_INT_STATUS    (0x1<<10)
++
++/* bit 9: data read timeout interrupt status */
++#define DRTO_INT_STATUS    (0x1<<9)
++
++/* bit 8: response timeout interrupt status */
++#define RTO_INT_STATUS    (0x1<<8)
++
++/* bit 7: data CRC error interrupt status */
++#define DCRC_INT_STATUS    (0x1<<7)
++
++/* bit 6: response CRC error interrupt status */
++#define RCRC_INT_STATUS    (0x1<<6)
++
++/* bit 5: receive FIFO data request interrupt status */
++#define RXDR_INT_STATUS    (0x1<<5)
++
++/* bit 4: transmit FIFO data request interrupt status */
++#define TXDR_INT_STATUS    (0x1<<4)
++
++/* bit 3: data transfer Over interrupt status */
++#define DTO_INT_STATUS    (0x1<<3)
++
++/* bit 2: command done interrupt status */
++#define CD_INT_STATUS    (0x1<<2)
++
++/* bit 1: response error interrupt status */
++#define RE_INT_STATUS    (0x1<<1)
++
++#define CMD_INT_MASK	(RTO_INT_STATUS | RCRC_INT_STATUS | RE_INT_STATUS)
++#define DATA_INT_MASK	(DCRC_INT_STATUS | SBE_INT_STATUS | EBE_INT_STATUS)
++/***************************************************************/
++
++/* MCI_RINTSTS(0x44) details:bit 16-1: clear
++   MMC host controller each interrupt but
++   hardware locked write error interrupt
++*/
++#define ALL_INT_CLR       0x1efff
++#define ALL_ADMA_INT_CLR  (0xffe<<21)
++
++/* MCI_STATUS(0x48) details */
++#define DATA_BUSY         (0x1<<9)
++
++/* MCI_FIFOTH(0x4c) details */
++#define BURST_SIZE        (0x6<<28)
++#define RX_WMARK          (0x7f<<16)
++#define TX_WMARK          (0x80)
++
++/* MCI_TUNING_CTRL(0x118) details */
++#define HW_TUNING_EN	(0x1 << 0)
++#define EDGE_CTRL		(0x1 << 1)
++#define FOUND_EDGE		(0x1 << 5)
++
++#define DEFAULT_CMD_VALUE	0x20000000
++
++#endif
+diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
+index 94b8210..ff3808f 100644
+--- a/drivers/mtd/Kconfig
++++ b/drivers/mtd/Kconfig
+@@ -258,7 +258,7 @@ config INFTL
+ 	  not use it.
+ 
+ config RFD_FTL
+-        tristate "Resident Flash Disk (Flash Translation Layer) support"
++	tristate "Resident Flash Disk (Flash Translation Layer) support"
+ 	depends on BLOCK
+ 	select MTD_BLKDEVS
+ 	---help---
+@@ -305,10 +305,59 @@ config MTD_SWAP
+ 	select MTD_BLKDEVS
+ 	help
+ 	  Provides volatile block device driver on top of mtd partition
+-          suitable for swapping.  The mapping of written blocks is not saved.
++	  suitable for swapping. The mapping of written blocks is not saved.
+ 	  The driver provides wear leveling by storing erase counter into the
+ 	  OOB.
+ 
++config HIFMC
++	bool "Enable HIFMC - Hisilicon Flash Memory Controller"
++	depends on MTD
++	default y if ARCH_HI3516CV300
++	default y if ARCH_HI3519
++	default y if ARCH_HI3519V101
++	default y if ARCH_HI3516AV200
++	default y if ARCH_HI3559
++	default y if ARCH_HI3556
++	default y if ARCH_HI3536C
++	default y if ARCH_HI3531D
++	default y if ARCH_HI3521D
++	help
++	  Hisilicon Flash Memory Controller support SPI Nor SPI Nand and parallel
++	  Nand Flash. often used on embedded chip. This option will provide the
++	  generic support for FMC drivers to register
++
++if HIFMC
++
++config HIFMC_SPI_NAND
++	bool "Enable SPI nand flash Support on HIFMC"
++	depends on ARCH_HI3516CV300 || ARCH_HI3519 || ARCH_HI3519V101 || ARCH_HI3559 || ARCH_HI3556 || ARCH_HI3516AV200 || ARCH_HI3531D || ARCH_HI3521D || ARCH_HI3536C
++	select MTD_NAND
++	select HIFMC100_SPI_NAND
++	default y if ARCH_HI3516CV300
++	default y if ARCH_HI3519
++	default y if ARCH_HI3519V101
++	default y if ARCH_HI3516AV200
++	default y if ARCH_HI3559
++	default y if ARCH_HI3556
++	default y if ARCH_HI3536C
++	default y if ARCH_HI3531D
++	default y if ARCH_HI3521D
++	help
++	  Hisilicon Flash Memory Controller is called hifmc for short.
++	  This option enable hifmc support SPI nand flash.
++	  If your enadle this option, HIFMC100_SPI_NAND should be select
++
++config HIFMC_NAND
++	bool "Enable Nand flash Support on HIFMC"
++	select MTD_NAND
++	select HIFMC100_NAND
++	help
++	  Hisilicon Flash Memory Controller is called hifmc for short.
++	  This option enable hifmc support Nand flash.
++	  If your choice this option, HIFMC100_NAND should be select
++
++endif # End of HIFMC
++
+ source "drivers/mtd/chips/Kconfig"
+ 
+ source "drivers/mtd/maps/Kconfig"
+diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
+index 99bb9a1..da61523 100644
+--- a/drivers/mtd/Makefile
++++ b/drivers/mtd/Makefile
+@@ -7,8 +7,8 @@ obj-$(CONFIG_MTD)		+= mtd.o
+ mtd-y				:= mtdcore.o mtdsuper.o mtdconcat.o mtdpart.o mtdchar.o
+ 
+ obj-$(CONFIG_MTD_OF_PARTS)	+= ofpart.o
+-obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o
+-obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o
++obj-$(CONFIG_MTD_REDBOOT_PARTS)	+= redboot.o
++obj-$(CONFIG_MTD_CMDLINE_PARTS)	+= cmdlinepart.o
+ obj-$(CONFIG_MTD_AFS_PARTS)	+= afs.o
+ obj-$(CONFIG_MTD_AR7_PARTS)	+= ar7part.o
+ obj-$(CONFIG_MTD_BCM63XX_PARTS)	+= bcm63xxpart.o
+@@ -30,7 +30,7 @@ obj-$(CONFIG_MTD_SWAP)		+= mtdswap.o
+ nftl-objs		:= nftlcore.o nftlmount.o
+ inftl-objs		:= inftlcore.o inftlmount.o
+ 
++obj-$(CONFIG_MTD_SPI_NOR)	+= spi-nor/
+ obj-y		+= chips/ lpddr/ maps/ devices/ nand/ onenand/ tests/
+ 
+-obj-$(CONFIG_MTD_SPI_NOR)	+= spi-nor/
+ obj-$(CONFIG_MTD_UBI)		+= ubi/
+diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile
+index f0b0e61..da80a3d 100644
+--- a/drivers/mtd/devices/Makefile
++++ b/drivers/mtd/devices/Makefile
+@@ -17,5 +17,4 @@ obj-$(CONFIG_MTD_SST25L)	+= sst25l.o
+ obj-$(CONFIG_MTD_BCM47XXSFLASH)	+= bcm47xxsflash.o
+ obj-$(CONFIG_MTD_ST_SPI_FSM)    += st_spi_fsm.o
+ 
+-
+ CFLAGS_docg3.o			+= -I$(src)
+diff --git a/drivers/mtd/devices/spi_ids.h b/drivers/mtd/devices/spi_ids.h
+new file mode 100644
+index 0000000..f082969
+--- /dev/null
++++ b/drivers/mtd/devices/spi_ids.h
+@@ -0,0 +1,185 @@
++/*
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++ 
++#ifndef SPI_IDSH
++#define SPI_IDSH
++
++/*****************************************************************************/
++
++#define _1K             (0x400)
++#define _2K             (0x800)
++
++#define _4K             (0x1000)
++#define _8K             (0x2000)
++#define _16K            (0x4000)
++#define _32K            (0x8000)
++
++#define _64K            (0x10000)
++#define _128K           (0x20000)
++#define _256K           (0x40000)
++#define _512K           (0x80000)
++
++#define _1M             (0x100000)
++#define _2M             (0x200000)
++#define _4M             (0x400000)
++#define _8M             (0x800000)
++
++#define _16M            (0x1000000)
++#define _32M            (0x2000000)
++#define _64M            (0x4000000)
++
++#define INFINITE        (0xFFFFFFFF)
++/*****************************************************************************/
++
++#define SPI_IF_READ_STD           (0x01)
++#define SPI_IF_READ_FAST          (0x02)
++#define SPI_IF_READ_DUAL          (0x04)
++#define SPI_IF_READ_DUAL_ADDR     (0x08)
++#define SPI_IF_READ_QUAD          (0x10)
++#define SPI_IF_READ_QUAD_ADDR     (0x20)
++
++#define SPI_IF_WRITE_STD          (0x01)
++#define SPI_IF_WRITE_DUAL         (0x02)
++#define SPI_IF_WRITE_DUAL_ADDR    (0x04)
++#define SPI_IF_WRITE_QUAD         (0x08)
++#define SPI_IF_WRITE_QUAD_ADDR    (0x10)
++
++#define SPI_IF_ERASE_SECTOR       (0x01)  /* sector erase, 64K */
++#define SPI_IF_ERASE_CHIP         (0x02)  /* chip erase */
++#define SPI_IF_ERASE_4K           (0x04)  /* 4K */
++#define SPI_IF_ERASE_8K           (0x08)  /* 8K */
++
++#define SPI_IF_ERASE_SECTOR_4K		(0x01)  /* 4K */
++#define SPI_IF_ERASE_SECTOR_32K		(0x02)  /* 32K */
++#define SPI_IF_ERASE_SECTOR_64K		(0x04)  /* 64K */
++#define SPI_IF_ERASE_SECTOR_128K	(0x08)  /* 128K */
++#define SPI_IF_ERASE_SECTOR_256K	(0x10)  /* 256K */
++/*****************************************************************************/
++#define SPI_CMD_BRWR          (0x17)  /*write value to BAR*/
++#define SPI_EN4B_VALUE        (0x80)  /*the enable 4Byte addr len value*/
++#define SPI_EX4B_VALUE        (0x00)  /*the disable 4Byte addr len value*/
++#define SPI_4BYTE_ADDR_LEN    (4)     /*address len 4Byte*/
++/*****************************************************************************/
++
++#define SPI_CMD_WREN			0x06   /* Write Enable */
++#define SPI_CMD_WRDI			0x04   /* Write Disable */
++/*****************************************************************************/
++#define SPI_CMD_SE_4K			0x20   /* 4KB sector Erase */
++#define SPI_CMD_SE_32K			0x52   /* 32KB sector Erase */
++
++#define SPI_CMD_SE_64K			0xD8   /* 64KB sector Erase */
++#define SPI_CMD_SE_128K			0xD8   /* 128KB sector Erase */
++#define SPI_CMD_SE_256K			0xD8   /* 256KB sector Erase */
++
++#define SPI_CMD_SE			0xD8   /* 64KB Sector Erase */
++#define SPI_CMD_BE			0xC7   /* chip erase */
++/*****************************************************************************/
++#define SPI_CMD_WRSR			0x01	/* Write Status Register */
++#define SPI_CMD_WRSR2			0x31	/* Write Status Register-2 */
++#define SPI_CMD_WRSR3			0x11	/* Write Status Register-3 */
++
++#define SPI_CMD_RDSR			0x05	/* Read Status Register */
++#define SPI_CMD_GET_FEATURES		0x0F   /* Get Features */
++#define SPI_CMD_SET_FEATURES		0x1F   /* Set Features */
++#define SPI_CMD_RDSR2			0x35	/* Read Status Register-2 */
++#define SPI_CMD_RDSR3			0x15	/* Read Status Register-3 */
++
++#define SPI_CMD_RDCR			0x35	/* Read Config Register */
++
++#define SPI_CMD_RDID			0x9F	/* Read Identification */
++#define SPI_CMD_RESET			0xff   /* Reset the device */
++/*****************************************************************************/
++#define SPI_CMD_PP			0x02   /* Page Programming */
++#define SPI_CMD_WRITE_DUAL		0xA2   /* fast program dual input */
++#define SPI_CMD_WRITE_QUAD		0x32   /* fast program quad input */
++#define SPI_CMD_WRITE_DUAL_ADDR	0xD2   /* Dual I/O High Performance Write */
++#define SPI_CMD_WRITE_QUAD_ADDR	0x12   /* Quad I/O High Performance Write */
++/*****************************************************************************/
++#define SPI_CMD_PAGE_READ		0x13   /* Page Read to Cache */
++#define SPI_CMD_READ			0x03   /* Read Data bytes */
++#define SPI_CMD_FAST_READ	0x0B   /* Read Data Bytes at Higher Speed */
++#define SPI_CMD_READ_DUAL		0x3B   /* fast read dual output */
++#define SPI_CMD_READ_QUAD		0x6B   /* fast read quad output */
++#define SPI_CMD_READ_DUAL_ADDR	0xBB   /* Dual I/O High Performance Read */
++#define SPI_CMD_READ_QUAD_ADDR	0xEB   /* Quad I/O High Performance Read */
++/*****************************************************************************/
++#define SPI_CMD_SR_WIP			1      /* Write in Progress */
++#define SPI_CMD_SR_WEL			2      /* Write Enable Latch */
++#define SPI_CMD_SR_QE			(1 << 9)	/* quad enable */
++#define SPI_CMD_SR_XQE			(0 << 9)	/* quad disable */
++/*****************************************************************************/
++#define SPI_CMD_EN4B	0xB7  /* enter 4 bytes mode and set 4 byte bit as '1' */
++#define SPI_CMD_EX4B	0xE9  /* exit 4 bytes mode and clear 4 byte bit */
++/*****************************************************************************/
++
++/*****************************************************************************/
++#ifndef DBG_BUG
++#define DBG_BUG(fmt, args...) \
++	do { \
++		pr_err("%s(%d): BUG !!! " fmt, __FILE__, \
++				__LINE__, ##args); \
++		while (1) \
++			; \
++	} while (0)
++#endif
++
++/*****************************************************************************/
++struct spi_operation {
++	unsigned char  iftype;
++	unsigned char  cmd;
++	unsigned char  dummy;
++	unsigned int   size;
++	unsigned int   clock;
++};
++
++struct spi_info {
++	char *name;
++
++	unsigned char  id[8];
++	unsigned int   id_len;
++
++	unsigned long  chipsize;
++	unsigned int   erasesize;
++	unsigned int   addrcycle;
++
++#define MAX_SPI_OP                       (8)
++	struct spi_operation *read[8];
++	struct spi_operation *write[8];
++	struct spi_operation *erase[8];
++#ifndef CONFIG_MTD_HISFC300
++	struct spi_driver *driver;
++#endif
++};
++/*****************************************************************************/
++
++struct spi_info *spi_serach_ids(unsigned char ids[8]);
++
++void spi_search_rw(struct spi_info *spiinfo, struct spi_operation *spiop_rw,
++	unsigned int iftype, unsigned int max_dummy, int is_read);
++
++#ifndef CONFIG_MTD_HISFC300
++void spi_get_erase(struct spi_info *spiinfo, struct spi_operation *spiop_erase);
++#else
++void spi_get_erase(struct spi_info *spiinfo, struct spi_operation *spiop_erase,
++	unsigned int *erasesize);
++#endif
++/******************************************************************************/
++
++extern struct spi_info spi_info_table[];
++/******************************************************************************/
++#endif /* SPI_IDSH */
+diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
+index dd10646..be09cf3 100644
+--- a/drivers/mtd/nand/Kconfig
++++ b/drivers/mtd/nand/Kconfig
+@@ -1,3 +1,10 @@
++config MTD_NAND_IDS
++	tristate "Include chip ids for known NAND devices."
++	depends on MTD
++	help
++	  Useful for NAND drivers that do not use the NAND subsystem but
++	  still like to take advantage of the known chip information.
++
+ config MTD_NAND_ECC
+ 	tristate
+ 
+@@ -109,9 +116,6 @@ config MTD_NAND_OMAP_BCH
+ config MTD_NAND_OMAP_BCH_BUILD
+ 	def_tristate MTD_NAND_OMAP2 && MTD_NAND_OMAP_BCH
+ 
+-config MTD_NAND_IDS
+-	tristate
+-
+ config MTD_NAND_RICOH
+ 	tristate "Ricoh xD card reader"
+ 	default n
+@@ -516,4 +520,21 @@ config MTD_NAND_XWAY
+ 	  Enables support for NAND Flash chips on Lantiq XWAY SoCs. NAND is attached
+ 	  to the External Bus Unit (EBU).
+ 
++config HISI_NAND_FS_MAY_NO_YAFFS2
++	bool "Remove the restraintion of 16bit ecc type on yaffs2 to HiSilicon"
++	default n
++	help
++	  The ecc type: 16bit is limited by the HiSilicon flash memory controller,
++	  as the yaffs2 tag of hisi rootfs limits the min size of CTRL len is 28.
++
++config HISI_NAND_ECC_STATUS_REPORT
++	bool "Report the ecc status to MTD for HiSilicon Nand Driver"
++	default n
++	help
++	  Flash Memory Controller V100 reports the ecc status include ECC error
++	  and ECC corrected to MTD to monitor the aging of devices.
++
++source "drivers/mtd/nand/hinfc610/Kconfig"
++source "drivers/mtd/nand/hifmc100_nand/Kconfig"
++source "drivers/mtd/nand/hifmc100/Kconfig"
+ endif # MTD_NAND
+diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
+index 9c847e4..63877fd 100644
+--- a/drivers/mtd/nand/Makefile
++++ b/drivers/mtd/nand/Makefile
+@@ -8,6 +8,9 @@ obj-$(CONFIG_MTD_NAND_BCH)		+= nand_bch.o
+ obj-$(CONFIG_MTD_NAND_IDS)		+= nand_ids.o
+ obj-$(CONFIG_MTD_SM_COMMON) 		+= sm_common.o
+ 
++obj-$(CONFIG_MTD_NAND_HINFC610)		+= hinfc610/
++obj-$(CONFIG_HIFMC_NAND)		+= hifmc100_nand/
++obj-$(CONFIG_HIFMC_SPI_NAND)		+= hifmc100/
+ obj-$(CONFIG_MTD_NAND_CAFE)		+= cafe_nand.o
+ obj-$(CONFIG_MTD_NAND_AMS_DELTA)	+= ams-delta.o
+ obj-$(CONFIG_MTD_NAND_DENALI)		+= denali.o
+@@ -51,4 +54,4 @@ obj-$(CONFIG_MTD_NAND_GPMI_NAND)	+= gpmi-nand/
+ obj-$(CONFIG_MTD_NAND_XWAY)		+= xway_nand.o
+ obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH)	+= bcm47xxnflash/
+ 
+-nand-objs := nand_base.o nand_bbt.o nand_timings.o
++nand-objs := nand_base.o nand_bbt.o nand_timings.o hinfc_gen.o hinfc_spl_ids.o match_table.o
+diff --git a/drivers/mtd/nand/hifmc100/Kconfig b/drivers/mtd/nand/hifmc100/Kconfig
+new file mode 100644
+index 0000000..92a7c77
+--- /dev/null
++++ b/drivers/mtd/nand/hifmc100/Kconfig
+@@ -0,0 +1,79 @@
++#
++# hisilicon flash memory controller SPI nand device driver version 100
++# drivers/mtd/nand/hifmc100/Kconfig
++# add by hisilicon 2015.5.7
++#
++
++menuconfig HIFMC100_SPI_NAND
++	tristate "Hisilicon Flash Memory Controller v100 SPI Nand device Support"
++	depends on HIFMC
++	depends on MTD_NAND
++	depends on HIFMC_SPI_NAND
++	default n if ARCH_HI3516CV300
++	default n if ARCH_HI3519
++	default n if ARCH_HI3519V101
++	default n if ARCH_HI3559
++	default n if ARCH_HI3556
++	default n if ARCH_HI3536C
++	default n if ARCH_HI3531D
++	default n if ARCH_HI3521D
++	select MISC_FILESYSTEMS
++	select MTD_BLOCK
++	help
++	  Hisilicon Flash Memory Controller device version 100 driver Support
++	  Hisilicon Flash Memory Controller version 100 is called hifmc100 for
++	  short. The controller driver support registers and DMA transfers
++	  while reading or writing the SPI nand flash.
++
++if HIFMC100_SPI_NAND
++
++config SPI_NAND_MAX_CHIP_NUM
++	int "Support max number of SPI Nand flash chip (1, 2)"
++	default 1 if ARCH_HI3516CV300
++	default 1 if ARCH_HI3519
++	default 1 if ARCH_HI3519V101
++	default 1 if ARCH_HI3559
++	default 1 if ARCH_HI3556
++	default 1 if ARCH_HI3536C
++	default 1 if ARCH_HI3531D
++	default 1 if ARCH_HI3521D
++	help
++	  flash memory controller v100 device only support 1 or 2 SPI nand flash
++	  chip, your should not config other value.
++
++choice
++	prompt "Page Size and Ecc Type Select"
++	default HIFMC100_AUTO_PAGESIZE_ECC if ARCH_HI3516CV300
++	default HIFMC100_AUTO_PAGESIZE_ECC if ARCH_HI3519
++	default HIFMC100_AUTO_PAGESIZE_ECC if ARCH_HI3519V101
++	default HIFMC100_AUTO_PAGESIZE_ECC if ARCH_HI3559
++	default HIFMC100_AUTO_PAGESIZE_ECC if ARCH_HI3556
++	default HIFMC100_AUTO_PAGESIZE_ECC if ARCH_HI3536C
++	default HIFMC100_AUTO_PAGESIZE_ECC if ARCH_HI3531D
++	default HIFMC100_AUTO_PAGESIZE_ECC if ARCH_HI3521D
++
++config HIFMC100_HARDWARE_PAGESIZE_ECC
++	bool "Hardware"
++	help
++	  the configure of page size and ecc type lie on switch on the board.
++	  so the page size and ecc type is controlled by Hardware see demo
++	  board of SOC.
++
++config HIFMC100_AUTO_PAGESIZE_ECC
++	bool "Auto"
++	help
++	  auto-sensed the page size and ecc type value. driver will try each of
++	  page size and ecc type one by one till flash can be read and wrote
++	  accurately. so the page size and ecc type is match adaptively without
++	  switch on the board
++
++config HIFMC100_PAGESIZE_AUTO_ECC_NONE
++	bool "Pagesize Auto, Ecc None"
++	help
++	  auto-sensed the page size and select ecc none. driver will try each
++	  of page size one by one till flash can be read and wrote accurately.
++	  so the page size is match adaptively without switch on the board
++
++endchoice
++
++endif # End of HIFMC100_SPI_NAND
+diff --git a/drivers/mtd/nand/hifmc100/Makefile b/drivers/mtd/nand/hifmc100/Makefile
+new file mode 100644
+index 0000000..72f7661
+--- /dev/null
++++ b/drivers/mtd/nand/hifmc100/Makefile
+@@ -0,0 +1,26 @@
++#
++# The Flash Memory Controller v100 Device Driver for hisilicon
++#
++# Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++#
++# 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, see <http://www.gnu.org/licenses/>.
++#
++#
++
++#
++# drivers/mtd/nand/hifmc100/Makefile
++#
++
++obj-$(CONFIG_HIFMC_SPI_NAND)	+= hifmc_spi_nand_ids.o
++obj-$(CONFIG_HIFMC100_SPI_NAND) += hifmc100.o hifmc100_os.o
+diff --git a/drivers/mtd/nand/hifmc100/hifmc100.c b/drivers/mtd/nand/hifmc100/hifmc100.c
+new file mode 100644
+index 0000000..60bb364
+--- /dev/null
++++ b/drivers/mtd/nand/hifmc100/hifmc100.c
+@@ -0,0 +1,1161 @@
++/*
++ * The Flash Memory Controller v100 Device Driver for hisilicon
++ *
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/clk.h>
++#include <linux/io.h>
++#include <linux/errno.h>
++#include <linux/slab.h>
++#include <linux/mtd/nand.h>
++#include <linux/delay.h>
++#include <linux/sched.h>
++#include <asm/setup.h>
++
++#include "../hinfc_gen.h"
++#include "hifmc100_os.h"
++#include "hifmc100.h"
++#include <linux/mfd/hisi_fmc.h>
++
++/*****************************************************************************/
++static void hifmc100_switch_to_spi_nand(struct hifmc_host *host)
++{
++	int reg;
++
++	reg = hifmc_readl(host, FMC_CFG);
++	reg &= ~FLASH_TYPE_SEL_MASK;
++	reg |= FMC_CFG_FLASH_SEL(FLASH_TYPE_SPI_NAND);
++	hifmc_writel(host, FMC_CFG, reg);
++}
++
++/*****************************************************************************/
++static void hifmc100_operation_config(struct hifmc_host *host, int op)
++{
++	int ret, clkrate = 0;
++	struct hifmc_spi *spi = host->spi;
++
++	hifmc100_switch_to_spi_nand(host);
++	clk_prepare_enable(host->clk);
++	switch (op) {
++	case OP_STYPE_WRITE:
++		clkrate = min((u_long)host->clkrate,
++				 (u_long)CLK_FMC_TO_CRG_MHZ(spi->write->clock));
++		break;
++	case OP_STYPE_READ:
++		clkrate = min((u_long)host->clkrate,
++				 (u_long)CLK_FMC_TO_CRG_MHZ(spi->read->clock));
++		break;
++	case OP_STYPE_ERASE:
++		clkrate = min((u_long)host->clkrate,
++				 (u_long)CLK_FMC_TO_CRG_MHZ(spi->erase->clock));
++		break;
++	default:
++		break;
++	}
++
++	ret = clk_set_rate(host->clk, clkrate);
++	BUG_ON(ret);
++}
++
++/*****************************************************************************/
++static void hifmc100_send_cmd_write(struct hifmc_host *host)
++{
++	unsigned char pages_per_block_shift;
++	unsigned int reg, block_num, block_num_h, page_num;
++	struct hifmc_spi *spi = host->spi;
++	struct nand_chip *chip = host->chip;
++#ifdef HIFMC100_SPI_NAND_SUPPORT_REG_WRITE
++	const char *op = "Reg";
++#else
++	const char *op = "Dma";
++#endif
++
++	if (WR_DBG)
++		pr_info("\n");
++	FMC_PR(WR_DBG, "*-Start send %s page write command\n", op);
++
++	mutex_lock(host->lock);
++	hifmc100_operation_config(host, OP_STYPE_WRITE);
++
++	reg = spi->driver->wait_ready(spi);
++	if (reg) {
++		DB_MSG("Error: %s program wait ready failed! status: %#x\n",
++				op, reg);
++		goto end;
++	}
++
++	reg = spi->driver->write_enable(spi);
++	if (reg) {
++		DB_MSG("Error: %s program write enable failed! reg: %#x\n",
++				op, reg);
++		goto end;
++	}
++
++	reg = FMC_INT_CLR_ALL;
++	hifmc_writel(host, FMC_INT_CLR, reg);
++	FMC_PR(WR_DBG, "|-Set INT_CLR[%#x]%#x\n", FMC_INT_CLR, reg);
++
++	reg = OP_CFG_FM_CS(host->cmd_op.cs)
++		| OP_CFG_MEM_IF_TYPE(spi->write->iftype);
++	hifmc_writel(host, FMC_OP_CFG, reg);
++	FMC_PR(WR_DBG, "|-Set OP_CFG[%#x]%#x\n", FMC_OP_CFG, reg);
++
++	pages_per_block_shift = chip->phys_erase_shift - chip->page_shift;
++	block_num = host->addr_value[1] >> pages_per_block_shift;
++	block_num_h = block_num >> REG_CNT_HIGH_BLOCK_NUM_SHIFT;
++	reg = FMC_ADDRH_SET(block_num_h);
++	hifmc_writel(host, FMC_ADDRH, reg);
++	FMC_PR(WR_DBG, "|-Set ADDRH[%#x]%#x\n", FMC_ADDRH, reg);
++
++	page_num = host->addr_value[1] - (block_num << pages_per_block_shift);
++	reg = ((block_num & REG_CNT_BLOCK_NUM_MASK) << REG_CNT_BLOCK_NUM_SHIFT)
++	     | ((page_num & REG_CNT_PAGE_NUM_MASK) << REG_CNT_PAGE_NUM_SHIFT);
++	hifmc_writel(host, FMC_ADDRL, reg);
++	FMC_PR(WR_DBG, "|-Set ADDRL[%#x]%#x\n", FMC_ADDRL, reg);
++
++	*host->epm = 0x0000;
++
++#ifndef HIFMC100_SPI_NAND_SUPPORT_REG_WRITE
++	reg = host->dma_buffer;
++	hifmc_writel(host, FMC_DMA_SADDR_D0, reg);
++	FMC_PR(WR_DBG, "|-Set DMA_SADDR_D[0x40]%#x\n", reg);
++
++	reg = host->dma_oob;
++	hifmc_writel(host, FMC_DMA_SADDR_OOB, reg);
++	FMC_PR(WR_DBG, "|-Set DMA_SADDR_OOB[%#x]%#x\n", FMC_DMA_SADDR_OOB, reg);
++#endif
++
++	reg = OP_CTRL_WR_OPCODE(spi->write->cmd)
++#ifdef HIFMC100_SPI_NAND_SUPPORT_REG_WRITE
++		| OP_CTRL_DMA_OP(OP_TYPE_REG)
++#else
++		| OP_CTRL_DMA_OP(OP_TYPE_DMA)
++#endif
++		| OP_CTRL_RW_OP(RW_OP_WRITE)
++		| OP_CTRL_DMA_OP_READY;
++	hifmc_writel(host, FMC_OP_CTRL, reg);
++	FMC_PR(WR_DBG, "|-Set OP_CTRL[%#x]%#x\n", FMC_OP_CTRL, reg);
++
++	FMC_DMA_WAIT_INT_FINISH(host);
++
++end:
++	mutex_unlock(host->lock);
++	FMC_PR(WR_DBG, "*-End %s page program!\n", op);
++}
++
++/*****************************************************************************/
++static void hifmc100_send_cmd_status(struct hifmc_host *host)
++{
++	unsigned char status, addr = STATUS_ADDR;
++	struct hifmc_spi *spi = host->spi;
++
++	if (host->cmd_op.l_cmd == NAND_CMD_GET_FEATURES)
++		addr = PROTECT_ADDR;
++
++	status = spi_nand_feature_op(spi, GET_OP, addr, 0);
++	FMC_PR((ER_DBG || WR_DBG), "\t*-Get status[%#x]: %#x\n", addr, status);
++}
++
++/*****************************************************************************/
++static void hifmc100_send_cmd_read(struct hifmc_host *host)
++{
++	unsigned char pages_per_block_shift, only_oob = 0;
++	unsigned short wrap = 0;
++	unsigned int reg, block_num, block_num_h, page_num, addr_of = 0;
++	struct hifmc_spi *spi = host->spi;
++	struct nand_chip *chip = host->chip;
++#ifdef HIFMC100_SPI_NAND_SUPPORT_REG_READ
++	char *op = "Reg";
++#else
++	char *op = "Dma";
++#endif
++
++	if (RD_DBG)
++		pr_info("\n");
++	FMC_PR(RD_DBG, "\t*-Start %s page read\n", op);
++
++	if ((host->addr_value[0] == host->cache_addr_value[0])
++		&& (host->addr_value[1] == host->cache_addr_value[1])) {
++		FMC_PR(RD_DBG, "\t*-%s read cache hit, addr[%#x %#x]\n",
++			op, host->addr_value[1], host->addr_value[0]);
++		return;
++	}
++
++	mutex_lock(host->lock);
++	hifmc100_operation_config(host, OP_STYPE_READ);
++
++	FMC_PR(RD_DBG, "\t|-Wait ready before %s page read\n", op);
++	reg = spi->driver->wait_ready(spi);
++	if (reg) {
++		DB_MSG("Error: %s read wait ready fail! reg: %#x\n", op, reg);
++		goto end;
++	}
++
++	reg = FMC_INT_CLR_ALL;
++	hifmc_writel(host, FMC_INT_CLR, reg);
++	FMC_PR(RD_DBG, "\t|-Set INT_CLR[%#x]%#x\n", FMC_INT_CLR, reg);
++
++	if (host->cmd_op.l_cmd == NAND_CMD_READOOB) {
++		only_oob = 1;
++		host->cmd_op.op_cfg = OP_CTRL_RD_OP_SEL(RD_OP_READ_OOB);
++	} else
++		host->cmd_op.op_cfg = OP_CTRL_RD_OP_SEL(RD_OP_READ_ALL_PAGE);
++
++	reg = OP_CFG_FM_CS(host->cmd_op.cs)
++		| OP_CFG_MEM_IF_TYPE(spi->read->iftype)
++		| OP_CFG_DUMMY_NUM(spi->read->dummy);
++	hifmc_writel(host, FMC_OP_CFG, reg);
++	FMC_PR(RD_DBG, "\t|-Set OP_CFG[%#x]%#x\n", FMC_OP_CFG, reg);
++
++	pages_per_block_shift = chip->phys_erase_shift - chip->page_shift;
++	block_num = host->addr_value[1] >> pages_per_block_shift;
++	block_num_h = block_num >> REG_CNT_HIGH_BLOCK_NUM_SHIFT;
++
++	reg = FMC_ADDRH_SET(block_num_h);
++	hifmc_writel(host, FMC_ADDRH, reg);
++	FMC_PR(RD_DBG, "\t|-Set ADDRH[%#x]%#x\n", FMC_ADDRH, reg);
++
++	page_num = host->addr_value[1] - (block_num << pages_per_block_shift);
++	if (only_oob)
++		switch (host->ecctype) {
++		case NAND_ECC_8BIT:
++			addr_of = REG_CNT_ECC_8BIT_OFFSET;
++			break;
++		case NAND_ECC_16BIT:
++			addr_of = REG_CNT_ECC_16BIT_OFFSET;
++			break;
++		case NAND_ECC_24BIT:
++			addr_of = REG_CNT_ECC_24BIT_OFFSET;
++			break;
++		case NAND_ECC_0BIT:
++		default:
++			break;
++		}
++
++	reg = ((block_num & REG_CNT_BLOCK_NUM_MASK) << REG_CNT_BLOCK_NUM_SHIFT)
++		| ((page_num & REG_CNT_PAGE_NUM_MASK) << REG_CNT_PAGE_NUM_SHIFT)
++		| ((wrap & REG_CNT_WRAP_MASK) << REG_CNT_WRAP_SHIFT)
++		| (addr_of & REG_CNT_ECC_OFFSET_MASK);
++	hifmc_writel(host, FMC_ADDRL, reg);
++	FMC_PR(RD_DBG, "\t|-Set ADDRL[%#x]%#x\n", FMC_ADDRL, reg);
++
++#ifndef HIFMC100_SPI_NAND_SUPPORT_REG_READ
++	reg = host->dma_buffer;
++	hifmc_writel(host, FMC_DMA_SADDR_D0, reg);
++	FMC_PR(RD_DBG, "\t|-Set DMA_SADDR_D0[%#x]%#x\n", FMC_DMA_SADDR_D0, reg);
++
++	reg = host->dma_oob;
++	hifmc_writel(host, FMC_DMA_SADDR_OOB, reg);
++	FMC_PR(RD_DBG, "\t|-Set DMA_SADDR_OOB[%#x]%#x\n", FMC_DMA_SADDR_OOB,
++			reg);
++#endif
++
++	reg = OP_CTRL_RD_OPCODE(spi->read->cmd) | host->cmd_op.op_cfg
++#ifdef HIFMC100_SPI_NAND_SUPPORT_REG_READ
++		| OP_CTRL_DMA_OP(OP_TYPE_REG)
++#else
++		| OP_CTRL_DMA_OP(OP_TYPE_DMA)
++#endif
++		| OP_CTRL_RW_OP(RW_OP_READ) | OP_CTRL_DMA_OP_READY;
++	hifmc_writel(host, FMC_OP_CTRL, reg);
++	FMC_PR(RD_DBG, "\t|-Set OP_CTRL[%#x]%#x\n", FMC_OP_CTRL, reg);
++
++	FMC_DMA_WAIT_INT_FINISH(host);
++
++	host->cache_addr_value[0] = host->addr_value[0];
++	host->cache_addr_value[1] = host->addr_value[1];
++
++end:
++	mutex_unlock(host->lock);
++	FMC_PR(RD_DBG, "\t*-End %s page read\n", op);
++}
++
++/*****************************************************************************/
++static void hifmc100_send_cmd_erase(struct hifmc_host *host)
++{
++	unsigned int reg;
++	struct hifmc_spi *spi = host->spi;
++
++	if (ER_DBG)
++		pr_info("\n");
++	FMC_PR(ER_DBG, "\t*-Start send cmd erase!\n");
++
++	mutex_lock(host->lock);
++	hifmc100_operation_config(host, OP_STYPE_ERASE);
++
++	reg = spi->driver->wait_ready(spi);
++	FMC_PR(ER_DBG, "\t|-Erase wait ready, reg: %#x\n", reg);
++	if (reg) {
++		DB_MSG("Error: Erase wait ready fail! status: %#x\n", reg);
++		goto end;
++	}
++
++	reg = spi->driver->write_enable(spi);
++	if (reg) {
++		DB_MSG("Error: Erase write enable failed! reg: %#x\n", reg);
++		goto end;
++	}
++
++	reg = FMC_INT_CLR_ALL;
++	hifmc_writel(host, FMC_INT_CLR, reg);
++	FMC_PR(ER_DBG, "\t|-Set INT_CLR[%#x]%#x\n", FMC_INT_CLR, reg);
++
++	reg = spi->erase->cmd;
++	hifmc_writel(host, FMC_CMD, FMC_CMD_CMD1(reg));
++	FMC_PR(ER_DBG, "\t|-Set CMD[%#x]%#x\n", FMC_CMD, reg);
++
++	reg = FMC_ADDRL_BLOCK_H_MASK(host->addr_value[1])
++		| FMC_ADDRL_BLOCK_L_MASK(host->addr_value[0]);
++	hifmc_writel(host, FMC_ADDRL, reg);
++	FMC_PR(ER_DBG, "\t|-Set ADDRL[%#x]%#x\n", FMC_ADDRL, reg);
++
++	reg = OP_CFG_FM_CS(host->cmd_op.cs)
++		| OP_CFG_MEM_IF_TYPE(spi->erase->iftype)
++		| OP_CFG_ADDR_NUM(STD_OP_ADDR_NUM)
++		| OP_CFG_DUMMY_NUM(spi->erase->dummy);
++	hifmc_writel(host, FMC_OP_CFG, reg);
++	FMC_PR(ER_DBG, "\t|-Set OP_CFG[%#x]%#x\n", FMC_OP_CFG, reg);
++
++	reg = FMC_OP_CMD1_EN
++		| FMC_OP_ADDR_EN
++		| FMC_OP_REG_OP_START;
++	hifmc_writel(host, FMC_OP, reg);
++	FMC_PR(ER_DBG, "\t|-Set OP[%#x]%#x\n", FMC_OP, reg);
++
++	FMC_CMD_WAIT_CPU_FINISH(host);
++
++end:
++	mutex_unlock(host->lock);
++	FMC_PR(ER_DBG, "\t*-End send cmd erase!\n");
++}
++
++/*****************************************************************************/
++void hifmc100_ecc0_switch(struct hifmc_host *host, unsigned char op)
++{
++	unsigned int config;
++#if EC_DBG
++	unsigned int cmp_cfg;
++
++	config = hifmc_readl(host, FMC_CFG);
++	FMC_PR(EC_DBG, "\t *-Get CFG[%#x]%#x\n", FMC_CFG, config);
++
++	if (op)
++		cmp_cfg = host->fmc_cfg;
++	else
++		cmp_cfg = host->fmc_cfg_ecc0;
++
++	if (cmp_cfg != config)
++		DB_MSG("Warning: FMC config[%#x] is different.\n",
++				cmp_cfg);
++#endif
++
++	if (op == ENABLE)
++		config = host->fmc_cfg_ecc0;
++	else if (op == DISABLE)
++		config = host->fmc_cfg;
++	else {
++		DB_MSG("Error: Invalid opcode: %d\n", op);
++		return;
++	}
++
++	hifmc_writel(host, FMC_CFG, config);
++	FMC_PR(EC_DBG, "\t *-Set CFG[%#x]%#x\n", FMC_CFG, config);
++}
++
++/*****************************************************************************/
++static void hifmc100_send_cmd_readid(struct hifmc_host *host)
++{
++	unsigned int reg;
++
++	FMC_PR(BT_DBG, "\t|*-Start send cmd read ID\n");
++
++	hifmc100_ecc0_switch(host, ENABLE);
++
++	reg = FMC_CMD_CMD1(SPI_CMD_RDID);
++	hifmc_writel(host, FMC_CMD, reg);
++	FMC_PR(BT_DBG, "\t||-Set CMD[%#x]%#x\n", FMC_CMD, reg);
++
++	reg = READ_ID_ADDR;
++	hifmc_writel(host, FMC_ADDRL, reg);
++	FMC_PR(BT_DBG, "\t||-Set ADDRL[%#x]%#x\n", FMC_ADDRL, reg);
++
++	reg = OP_CFG_FM_CS(host->cmd_op.cs)
++		| OP_CFG_ADDR_NUM(READ_ID_ADDR_NUM);
++	hifmc_writel(host, FMC_OP_CFG, reg);
++	FMC_PR(BT_DBG, "\t||-Set OP_CFG[%#x]%#x\n", FMC_OP_CFG, reg);
++
++	reg = FMC_DATA_NUM_CNT(MAX_SPI_NAND_ID_LEN);
++	hifmc_writel(host, FMC_DATA_NUM, reg);
++	FMC_PR(BT_DBG, "\t||-Set DATA_NUM[%#x]%#x\n", FMC_DATA_NUM, reg);
++
++	reg = FMC_OP_CMD1_EN
++		| FMC_OP_ADDR_EN
++		| FMC_OP_READ_DATA_EN
++		| FMC_OP_REG_OP_START;
++	hifmc_writel(host, FMC_OP, reg);
++	FMC_PR(BT_DBG, "\t||-Set OP[%#x]%#x\n", FMC_OP, reg);
++
++	host->addr_cycle = 0x0;
++
++	FMC_CMD_WAIT_CPU_FINISH(host);
++
++	hifmc100_ecc0_switch(host, DISABLE);
++
++	FMC_PR(BT_DBG, "\t|*-End read flash ID\n");
++}
++
++/*****************************************************************************/
++static void hifmc100_send_cmd_reset(struct hifmc_host *host)
++{
++	unsigned int reg;
++
++	FMC_PR(BT_DBG, "\t|*-Start send cmd reset\n");
++
++	reg = FMC_CMD_CMD1(SPI_CMD_RESET);
++	hifmc_writel(host, FMC_CMD, reg);
++	FMC_PR(BT_DBG, "\t||-Set CMD[%#x]%#x\n", FMC_CMD, reg);
++
++	reg = OP_CFG_FM_CS(host->cmd_op.cs);
++	hifmc_writel(host, FMC_OP_CFG, reg);
++	FMC_PR(BT_DBG, "\t||-Set OP_CFG[%#x]%#x\n", FMC_OP_CFG, reg);
++
++	reg = FMC_OP_CMD1_EN | FMC_OP_REG_OP_START;
++	hifmc_writel(host, FMC_OP, reg);
++	FMC_PR(BT_DBG, "\t||-Set OP[%#x]%#x\n", FMC_OP, reg);
++
++	FMC_CMD_WAIT_CPU_FINISH(host);
++
++	FMC_PR(BT_DBG, "\t|*-End send cmd reset\n");
++}
++
++/*****************************************************************************/
++static void hifmc100_host_init(struct hifmc_host *host)
++{
++	unsigned int reg;
++
++	FMC_PR(BT_DBG, "\t||*-Start SPI Nand host init\n");
++
++	reg = hifmc_readl(host, FMC_CFG);
++	if ((reg & FMC_CFG_OP_MODE_MASK) == FMC_CFG_OP_MODE_BOOT) {
++		reg |= FMC_CFG_OP_MODE(FMC_CFG_OP_MODE_NORMAL);
++		hifmc_writel(host, FMC_CFG, reg);
++		FMC_PR(BT_DBG, "\t|||-Set CFG[%#x]%#x\n", FMC_CFG, reg);
++	}
++
++	host->fmc_cfg = reg;
++	host->fmc_cfg_ecc0 = (reg & ~ECC_TYPE_MASK) | ECC_TYPE_0BIT;
++
++	reg = hifmc_readl(host, FMC_GLOBAL_CFG);
++	if (reg & FMC_GLOBAL_CFG_WP_ENABLE) {
++		reg &= ~FMC_GLOBAL_CFG_WP_ENABLE;
++		hifmc_writel(host, FMC_GLOBAL_CFG, reg);
++	}
++
++	host->addr_cycle = 0;
++	host->addr_value[0] = 0;
++	host->addr_value[1] = 0;
++	host->cache_addr_value[0] = ~0;
++	host->cache_addr_value[1] = ~0;
++
++	host->send_cmd_write = hifmc100_send_cmd_write;
++	host->send_cmd_status = hifmc100_send_cmd_status;
++	host->send_cmd_read = hifmc100_send_cmd_read;
++	host->send_cmd_erase = hifmc100_send_cmd_erase;
++	host->send_cmd_readid = hifmc100_send_cmd_readid;
++	host->send_cmd_reset = hifmc100_send_cmd_reset;
++#ifdef CONFIG_PM
++	host->suspend = hifmc100_suspend;
++	host->resume  = hifmc100_resume;
++#endif
++
++	reg = TIMING_CFG_TCSH(CS_HOLD_TIME)
++		| TIMING_CFG_TCSS(CS_SETUP_TIME)
++		| TIMING_CFG_TSHSL(CS_DESELECT_TIME);
++	hifmc_writel(host, FMC_SPI_TIMING_CFG, reg);
++
++	reg = ALL_BURST_ENABLE;
++	hifmc_writel(host, FMC_DMA_AHB_CTRL, reg);
++
++	FMC_PR(BT_DBG, "\t||*-End SPI Nand host init\n");
++}
++
++/*****************************************************************************/
++static unsigned char hifmc100_read_byte(struct mtd_info *mtd)
++{
++	struct nand_chip *chip = mtd->priv;
++	struct hifmc_host *host = chip->priv;
++	unsigned char value, ret_val = 0;
++
++	if (host->cmd_op.l_cmd == NAND_CMD_READID) {
++		value = hifmc_readb(host->iobase + host->offset);
++		host->offset++;
++		if (host->cmd_op.data_no == host->offset)
++			host->cmd_op.l_cmd = 0;
++		return value;
++	}
++
++	if (host->cmd_op.cmd == NAND_CMD_STATUS) {
++		value = hifmc_readl(host, FMC_STATUS);
++		if (host->cmd_op.l_cmd == NAND_CMD_GET_FEATURES) {
++			FMC_PR((ER_DBG || WR_DBG), "\t\tRead BP status:%#x\n",
++					value);
++			if (ANY_BP_ENABLE(value))
++				ret_val |= NAND_STATUS_WP;
++
++			host->cmd_op.l_cmd = NAND_CMD_STATUS;
++		}
++
++		if (!(value & STATUS_OIP_MASK))
++			ret_val |= NAND_STATUS_READY;
++
++		if (value & STATUS_E_FAIL_MASK) {
++			FMC_PR(ER_DBG, "\t\tGet erase status: %#x\n", value);
++			ret_val |= NAND_STATUS_FAIL;
++		}
++
++		if (value & STATUS_P_FAIL_MASK) {
++			FMC_PR(WR_DBG, "\t\tGet write status: %#x\n", value);
++			ret_val |= NAND_STATUS_FAIL;
++		}
++
++		return ret_val;
++	}
++
++	if (host->cmd_op.l_cmd == NAND_CMD_READOOB) {
++		value  = hifmc_readb(host->buffer + host->pagesize + host->offset);
++		host->offset++;
++		return value;
++	}
++
++	host->offset++;
++
++	return hifmc_readb(host->buffer + host->column + host->offset - 1);
++}
++
++/*****************************************************************************/
++static unsigned short hifmc100_read_word(struct mtd_info *mtd)
++{
++	struct nand_chip *chip = mtd->priv;
++	struct hifmc_host *host = chip->priv;
++
++	host->offset += 2;
++	return hifmc_readw(host->buffer + host->column + host->offset - 2);
++}
++
++/*****************************************************************************/
++static void hifmc100_write_buf(struct mtd_info *mtd,
++	const u_char *buf, int len)
++{
++	struct nand_chip *chip = mtd->priv;
++	struct hifmc_host *host = chip->priv;
++
++#ifdef HIFMC100_SPI_NAND_SUPPORT_REG_WRITE
++	if (buf == chip->oob_poi)
++		memcpy((char *)host->iobase + host->pagesize, buf, len);
++	else
++		memcpy((char *)host->iobase, buf, len);
++#else
++	if (buf == chip->oob_poi)
++		memcpy((char *)(host->buffer + host->pagesize), buf, len);
++	else
++		memcpy((char *)host->buffer, buf, len);
++#endif
++	return;
++}
++
++/*****************************************************************************/
++static void hifmc100_read_buf(struct mtd_info *mtd, u_char *buf, int len)
++{
++	struct nand_chip *chip = mtd->priv;
++	struct hifmc_host *host = chip->priv;
++
++#ifdef HIFMC100_SPI_NAND_SUPPORT_REG_READ
++	if (buf == chip->oob_poi)
++		memcpy(buf, (char *)host->iobase + host->pagesize, len);
++	else
++		memcpy(buf, (char *)host->iobase, len);
++#else
++	if (buf == chip->oob_poi)
++		memcpy(buf, (char *)host->buffer + host->pagesize, len);
++	else
++		memcpy(buf, (char *)host->buffer, len);
++#endif
++
++#ifdef CONFIG_HISI_NAND_ECC_STATUS_REPORT
++	if (buf != chip->oob_poi) {
++		u_int reg, ecc_step = host->pagesize >> 10;
++
++		reg = hifmc_readl(host, HIFMC100_ECC_ERR_NUM0_BUF0);
++		while (ecc_step) {
++			u_char err_num;
++
++			err_num = GET_ECC_ERR_NUM(--ecc_step, reg);
++			if (err_num == 0xff)
++				mtd->ecc_stats.failed++;
++			else
++				mtd->ecc_stats.corrected += err_num;
++		}
++	}
++#endif
++
++	return;
++}
++
++/*****************************************************************************/
++static void hifmc100_select_chip(struct mtd_info *mtd, int chipselect)
++{
++	struct nand_chip *chip = mtd->priv;
++	struct hifmc_host *host = chip->priv;
++
++	if (chipselect < 0) {
++		mutex_unlock(&fmc_switch_mutex);
++		return;
++	}
++
++	mutex_lock(&fmc_switch_mutex);
++
++	if (chipselect > CONFIG_SPI_NAND_MAX_CHIP_NUM)
++		DB_BUG("Error: Invalid chipselect: %d\n", chipselect);
++
++	if (host->mtd != mtd) {
++		host->mtd = mtd;
++		host->cmd_op.cs = chipselect;
++	}
++
++	if (!(chip->options & NAND_BROKEN_XD)) {
++		if ((chip->state == FL_ERASING) || (chip->state == FL_WRITING))
++			host->cmd_op.l_cmd = NAND_CMD_GET_FEATURES;
++	}
++}
++
++/*****************************************************************************/
++static void hifmc100_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned ctrl)
++{
++	unsigned char cmd;
++	int is_cache_invalid = 1;
++	struct nand_chip *chip = mtd->priv;
++	struct hifmc_host *host = chip->priv;
++
++	if (ctrl & NAND_ALE) {
++		unsigned int addr_value = 0;
++		unsigned int addr_offset = 0;
++
++		if (ctrl & NAND_CTRL_CHANGE) {
++			host->addr_cycle = 0x0;
++			host->addr_value[0] = 0x0;
++			host->addr_value[1] = 0x0;
++		}
++		addr_offset = host->addr_cycle << 3;
++
++		if (host->addr_cycle >= HIFMC100_ADDR_CYCLE_MASK) {
++			addr_offset = (host->addr_cycle -
++					HIFMC100_ADDR_CYCLE_MASK) << 3;
++			addr_value = 1;
++		}
++
++		host->addr_value[addr_value] |=
++			((dat & 0xff) << addr_offset);
++
++		host->addr_cycle++;
++	}
++
++	if ((ctrl & NAND_CLE) && (ctrl & NAND_CTRL_CHANGE)) {
++		cmd = dat & 0xff;
++		host->cmd_op.cmd = cmd;
++		switch (cmd) {
++		case NAND_CMD_PAGEPROG:
++			host->offset = 0;
++			host->send_cmd_write(host);
++			break;
++
++		case NAND_CMD_READSTART:
++			is_cache_invalid = 0;
++			if (host->addr_value[0] == host->pagesize)
++				host->cmd_op.l_cmd = NAND_CMD_READOOB;
++			host->send_cmd_read(host);
++			break;
++
++		case NAND_CMD_ERASE2:
++			host->send_cmd_erase(host);
++			break;
++
++		case NAND_CMD_READID:
++			memset((u_char *)(host->iobase), 0,
++					MAX_SPI_NAND_ID_LEN);
++			host->cmd_op.l_cmd = cmd;
++			host->cmd_op.data_no = MAX_SPI_NAND_ID_LEN;
++			host->send_cmd_readid(host);
++			break;
++
++		case NAND_CMD_STATUS:
++			host->send_cmd_status(host);
++			break;
++
++		case NAND_CMD_READ0:
++			host->cmd_op.l_cmd = cmd;
++			break;
++
++		case NAND_CMD_RESET:
++			host->send_cmd_reset(host);
++			break;
++
++		case NAND_CMD_SEQIN:
++		case NAND_CMD_ERASE1:
++		default:
++			break;
++		}
++	}
++
++	if ((dat == NAND_CMD_NONE) && host->addr_cycle) {
++		if (host->cmd_op.cmd == NAND_CMD_SEQIN
++			|| host->cmd_op.cmd == NAND_CMD_READ0
++			|| host->cmd_op.cmd == NAND_CMD_READID) {
++			host->offset = 0x0;
++			host->column = (host->addr_value[0] & 0xffff);
++		}
++	}
++
++	if (is_cache_invalid) {
++		host->cache_addr_value[0] = ~0;
++		host->cache_addr_value[1] = ~0;
++	}
++}
++
++/*****************************************************************************/
++static int hifmc100_dev_ready(struct mtd_info *mtd)
++{
++	unsigned int reg;
++	unsigned long deadline = jiffies + FMC_MAX_READY_WAIT_JIFFIES;
++	struct nand_chip *chip = mtd->priv;
++	struct hifmc_host *host = chip->priv;
++
++	do {
++		reg = OP_CFG_FM_CS(host->cmd_op.cs);
++		hifmc_writel(host, FMC_OP_CFG, reg);
++
++		reg = FMC_OP_READ_STATUS_EN | FMC_OP_REG_OP_START;
++		hifmc_writel(host, FMC_OP, reg);
++
++		FMC_CMD_WAIT_CPU_FINISH(host);
++
++		reg = hifmc_readl(host, FMC_STATUS);
++
++		if (!(reg & STATUS_OIP_MASK))
++			return NAND_STATUS_READY;
++
++		cond_resched();
++
++	} while (!time_after_eq(jiffies, deadline));
++
++	if (!(chip->options & NAND_SCAN_SILENT_NODEV))
++		pr_warn("Wait SPI nand ready timeout, status: %#x\n", reg);
++
++	return 0;
++}
++
++/*****************************************************************************/
++/*
++ * 'host->epm' only use the first oobfree[0] field, it looks very simple, But...
++ */
++static struct nand_ecclayout nand_ecc_default = {
++	.oobfree = {{2, 30} }
++};
++#ifdef CONFIG_HISI_NAND_FS_MAY_NO_YAFFS2
++static struct nand_ecclayout nand_ecc_2k16bit = {
++	    .oobfree = {{2, 6} }
++};
++
++static struct nand_ecclayout nand_ecc_4k16bit = {
++	    .oobfree = {{2, 14} }
++};
++#endif
++
++/*****************************************************************************/
++static struct nand_config_info hifmc_spi_nand_config_table[] = {
++	{NAND_PAGE_4K,	NAND_ECC_24BIT,	200,	&nand_ecc_default},
++#ifdef CONFIG_HISI_NAND_FS_MAY_NO_YAFFS2
++	{NAND_PAGE_4K,	NAND_ECC_16BIT,	128,	&nand_ecc_4k16bit},
++#endif
++	{NAND_PAGE_4K,	NAND_ECC_8BIT,	88,		&nand_ecc_default},
++	{NAND_PAGE_4K,	NAND_ECC_0BIT,	32,		&nand_ecc_default},
++
++	{NAND_PAGE_2K,	NAND_ECC_24BIT,	128,	&nand_ecc_default},
++#ifdef CONFIG_HISI_NAND_FS_MAY_NO_YAFFS2
++	{NAND_PAGE_2K,	NAND_ECC_16BIT,	64,		&nand_ecc_2k16bit},
++#endif
++	{NAND_PAGE_2K,	NAND_ECC_8BIT,	64,		&nand_ecc_default},
++	{NAND_PAGE_2K,	NAND_ECC_0BIT,	32,		&nand_ecc_default},
++
++	{0,		0,		0,	NULL},
++};
++
++/*****************************************************************************/
++/* used the best correct arithmetic. */
++static struct nand_config_info *hifmc100_get_best_ecc(struct mtd_info *mtd)
++{
++	struct nand_config_info *best = NULL;
++	struct nand_config_info *info = hifmc_spi_nand_config_table;
++
++	for (; info->layout; info++) {
++		if (match_page_type_to_size(info->pagetype) != mtd->writesize)
++			continue;
++
++		if (mtd->oobsize < info->oobsize)
++			continue;
++
++		if (!best || (best->ecctype < info->ecctype))
++			best = info;
++	}
++
++	if (!best)
++		DB_BUG(ERR_STR_DRIVER "pagesize: %d and oobsize: %d.\n",
++				mtd->writesize, mtd->oobsize);
++	return best;
++}
++
++#if defined(CONFIG_HIFMC100_PAGESIZE_AUTO_ECC_NONE) \
++	|| defined(CONFIG_HIFMC100_HARDWARE_PAGESIZE_ECC)
++/*****************************************************************************/
++/* force the pagesize and ecctype */
++static struct nand_config_info *hifmc100_force_ecc(struct mtd_info *mtd,
++		int pagetype, int ecctype, char *cfgmsg, int allow_pagediv)
++{
++	int pagesize;
++	struct nand_config_info *fit = NULL;
++	struct nand_config_info *info = hifmc_spi_nand_config_table;
++
++	for (; info->layout; info++) {
++		if (info->pagetype == pagetype && info->ecctype == ecctype) {
++			fit = info;
++			break;
++		}
++	}
++
++	if (!fit) {
++		DB_MSG("Driver(%s) can't find this configure\n", cfgmsg);
++		DB_BUG(ERR_STR_DRIVER "pagesize: %s, ecctype: %s\n",
++			nand_page_name(pagetype), nand_ecc_name(ecctype));
++		return NULL;
++	}
++
++	pagesize = match_page_type_to_size(pagetype);
++	if ((pagesize != mtd->writesize)
++		&& (pagesize > mtd->writesize || !allow_pagediv)) {
++		DB_MSG("This SPI Nand Flash pageszie: %d\n", mtd->writesize);
++		DB_BUG("But (%s) configure pagesize: %d" ERR_STR_CHECK "\n",
++				cfgmsg, pagesize);
++		return NULL;
++	}
++
++	if (fit->oobsize > mtd->oobsize) {
++		DB_MSG("This SPI Nand Flash offer space area is %dB\n",
++				mtd->oobsize);
++		DB_BUG("But (%s) the controller request %dB in ecc %s.",
++				cfgmsg, fit->oobsize, nand_ecc_name(ecctype));
++		return NULL;
++	}
++
++	return fit;
++}
++#endif
++
++/*****************************************************************************/
++static void hifmc100_chip_init(struct nand_chip *chip)
++{
++	chip->read_byte = hifmc100_read_byte;
++	chip->read_word = hifmc100_read_word;
++	chip->write_buf = hifmc100_write_buf;
++	chip->read_buf = hifmc100_read_buf;
++
++	chip->select_chip = hifmc100_select_chip;
++
++	chip->cmd_ctrl = hifmc100_cmd_ctrl;
++	chip->dev_ready = hifmc100_dev_ready;
++
++	chip->chip_delay = FMC_CHIP_DELAY;
++
++	chip->options = NAND_NO_AUTOINCR | NAND_SKIP_BBTSCAN | NAND_BROKEN_XD
++		| NAND_SCAN_SILENT_NODEV;
++
++	chip->ecc.layout = NULL;
++	chip->ecc.mode = NAND_ECC_NONE;
++}
++
++/*****************************************************************************/
++static int hifmc100_ecc_probe(struct mtd_info *mtd, struct nand_chip *chip,
++		struct nand_dev_t *nand_dev)
++{
++	unsigned char page_reg, pagetype, ecc_reg, ecctype, block_reg = 0;
++	unsigned int reg, page_per_block;
++	char *start_type = "unknown";
++	struct nand_config_info *best = NULL;
++	struct hifmc_host *host = chip->priv;
++
++	FMC_PR(BT_DBG, "\t*-Start match PageSize and EccType\n");
++
++	reg = hifmc_readl(host, FMC_CFG);
++	FMC_PR(BT_DBG, "\t|-Get FMC_CFG[%#x] config: %#x\n", FMC_CFG, reg);
++
++#ifdef CONFIG_HIFMC100_AUTO_PAGESIZE_ECC
++	best = hifmc100_get_best_ecc(mtd);
++	if (!best)
++		DB_BUG("Can't found any configure for SPI Nand Flash\n");
++
++	start_type = "Auto";
++
++	pagetype = best->pagetype;
++	ecctype = best->ecctype;
++
++	page_reg = match_page_type_to_reg(pagetype);
++	reg &= ~PAGE_SIZE_MASK;
++	reg |= FMC_CFG_PAGE_SIZE(page_reg);
++	FMC_PR(BT_DBG, "\t|-%s Config, PageSize %s EccType %s OobSize %d\n",
++			start_type, nand_page_name(pagetype),
++			nand_ecc_name(ecctype), best->oobsize);
++
++	ecc_reg = match_ecc_type_to_reg(ecctype);
++	reg &= ~ECC_TYPE_MASK;
++	reg |= FMC_CFG_ECC_TYPE(ecc_reg);
++	FMC_PR(BT_DBG, "\t|-%s Config best EccType: %s\n", start_type,
++			nand_ecc_name(best->ecctype));
++
++	page_per_block = mtd->erasesize / match_page_type_to_size(pagetype);
++	switch (page_per_block) {
++	case 64:
++		block_reg = BLOCK_SIZE_64_PAGE;
++		break;
++	case 128:
++		block_reg = BLOCK_SIZE_128_PAGE;
++		break;
++	case 256:
++		block_reg = BLOCK_SIZE_256_PAGE;
++		break;
++	case 512:
++		block_reg = BLOCK_SIZE_512_PAGE;
++		break;
++	default:
++		DB_MSG("Can't support block %#x and page %#x size\n",
++				mtd->erasesize, mtd->writesize);
++	}
++	reg &= ~BLOCK_SIZE_MASK;
++	reg |= FMC_CFG_BLOCK_SIZE(block_reg);
++
++	hifmc_writel(host, FMC_CFG, reg);
++	FMC_PR(BT_DBG, "\t|-Set FMC_CFG[%#x] config: %#x\n", FMC_CFG, reg);
++#endif
++
++	host->fmc_cfg = reg;
++	FMC_PR(BT_DBG, "\t|-Save FMC_CFG config: %#x\n", reg);
++
++#ifdef CONFIG_HIFMC100_HARDWARE_PAGESIZE_ECC
++	#ifdef CONFIG_HIFMC100_AUTO_PAGESIZE_ECC
++	#error you SHOULD NOT define CONFIG_HIFMC100_AUTO_PAGESIZE_ECC \
++		and CONFIG_HIFMC100_HARDWARE_PAGESIZE_ECC at the same time
++	#endif
++
++	page_reg = (host->fmc_cfg & PAGE_SIZE_MASK) >> PAGE_SIZE_SHIFT;
++	pagetype = match_page_reg_to_type(page_reg);
++	FMC_PR(BT_DBG, "\t|-Get Hardware Config PageSize: %s\n",
++			nand_page_name(pagetype));
++
++	ecc_reg = (host->fmc_cfg & ECC_TYPE_MASK) >> ECC_TYPE_SHIFT;
++	ecctype = match_ecc_reg_to_type(ecc_reg);
++	FMC_PR(BT_DBG, "\t|-Get Hardware Config EccType: %s\n",
++			match_ecc_type_to_str(ecctype));
++
++	FMC_PR(BT_DBG, "\t|-Check FMC_CFG Config with Hardware Config\n");
++	best = hifmc100_force_ecc(mtd, pagetype, ecctype,
++			"hardware config mode", 0);
++	if (!best)
++		DB_BUG("Can't found any configure for SPI Nand Flash\n");
++
++	start_type = "Hardware";
++#endif
++
++#ifdef CONFIG_HIFMC100_PAGESIZE_AUTO_ECC_NONE
++
++	#ifdef CONFIG_HIFMC100_AUTO_PAGESIZE_ECC
++	#error you SHOULD NOT define CONFIG_HIFMC100_PAGESIZE_AUTO_ECC_NONE \
++		and CONFIG_HIFMC100_AUTO_PAGESIZE_ECC at the same time
++	#endif
++
++	#ifdef CONFIG_HIFMC100_HARDWARE_PAGESIZE_ECC
++	#error you SHOULD NOT define CONFIG_HIFMC100_PAGESIZE_AUTO_ECC_NONE \
++		and CONFIG_HIFMC100_HARDWARE_PAGESIZE_ECC at the same time
++	#endif
++
++	pagetype = match_page_size_to_type(mtd->writesize);
++
++	best = hifmc100_force_ecc(mtd, pagetype, NAND_ECC_0BIT,
++			"force config mode", 0);
++	if (!best)
++		DB_BUG("Can't found any configure for SPI Nand Flash\n");
++
++	start_type = "AutoForce";
++	FMC_PR(BT_DBG, "\t|-Check PageSize %s Config\n", start_type);
++
++	page_reg = match_page_type_to_reg(best->pagetype);
++
++	reg &= ~(PAGE_SIZE_MASK | ECC_TYPE_MASK);
++	reg |= FMC_CFG_PAGE_SIZE(page_reg);
++	reg |= FMC_CFG_ECC_TYPE(ECC_TYPE_0BIT);
++	host->fmc_cfg = reg;
++	FMC_PR(BT_DBG, "\t|-Save FMC_CFG config: %#x\n", reg);
++#endif /* End of CONFIG_HIFMC100_PAGESIZE_AUTO_ECC_NONE */
++
++	if (!best)
++		DB_BUG("Can't found any configure for SPI Nand Flash\n");
++
++	if (best->ecctype != NAND_ECC_0BIT)
++		mtd->oobsize = best->oobsize;
++
++	chip->ecc.layout = best->layout;
++
++	host->ecctype = best->ecctype;
++	host->pagesize = match_page_type_to_size(best->pagetype);
++	host->oobsize = mtd->oobsize;
++
++	FMC_PR(BT_DBG, "\t|-%s Config end, best OOB Size: %d\n", start_type,
++			best->oobsize);
++
++	host->block_page_mask = ((mtd->erasesize / mtd->writesize) - 1);
++	host->dma_oob = host->dma_buffer + host->pagesize;
++	host->bbm = (u_char *)(host->buffer + host->pagesize
++			+ HIFMC_BAD_BLOCK_POS);
++
++	/* EB bits locate in the bottom two of CTRL(30) */
++	host->epm = (u_short *)(host->buffer + host->pagesize
++			+ chip->ecc.layout->oobfree[0].offset + 28);
++
++#ifdef CONFIG_HISI_NAND_FS_MAY_NO_YAFFS2
++	if (best->ecctype == NAND_ECC_16BIT) {
++		if (host->pagesize == _2K) {
++			/* EB bits locate in the bottom two of CTRL(4) */
++			host->epm = (u_short *)(host->buffer + host->pagesize
++					+ chip->ecc.layout->oobfree[0].offset + 4);
++		} else if (host->pagesize == _4K) {
++			/* EB bit locate in the bottom two of CTRL(14) */
++			host->epm = (u_short *)(host->buffer + host->pagesize
++					+ chip->ecc.layout->oobfree[0].offset + 12);
++		}
++	}
++#endif
++
++	host->fmc_cfg_ecc0 = (host->fmc_cfg & ~ECC_TYPE_MASK) | ECC_TYPE_0BIT;
++
++	if (mtd->writesize > SPI_NAND_MAX_PAGESIZE
++		|| mtd->oobsize > SPI_NAND_MAX_OOBSIZE) {
++		DB_MSG(ERR_STR_DRIVER "pageszie: %d and oobsize: %d\n",
++				mtd->writesize, mtd->oobsize);
++		DB_BUG("Please increase MAX PAGESIZE and OOBSIZE.\n");
++	}
++
++	if (mtd->writesize != host->pagesize) {
++		unsigned int shift = 0;
++		unsigned int writesize = mtd->writesize;
++		while (writesize > host->pagesize) {
++			writesize >>= 1;
++			shift++;
++		}
++		chip->chipsize = chip->chipsize >> shift;
++		mtd->erasesize = mtd->erasesize >> shift;
++		mtd->writesize = host->pagesize;
++		DB_MSG("SPI Nand divide into 1/%u\n", (1 << shift));
++	}
++
++	nand_dev->start_type = start_type;
++	nand_dev->oobsize = host->oobsize;
++	nand_dev->ecctype = host->ecctype;
++
++	FMC_PR(BT_DBG, "\t*-End match PageSize and EccType\n");
++
++	return 0;
++}
++
++/*****************************************************************************/
++int hifmc100_spi_nand_init(struct nand_chip *chip)
++{
++	struct hifmc_host *host = chip->priv;
++
++	FMC_PR(BT_DBG, "\t|*-Start hifmc100 SPI Nand init\n");
++
++	/* Set system clock and enable controller */
++	clk_prepare_enable(host->clk);
++
++	/* Switch SPI type to SPI nand */
++	hifmc100_switch_to_spi_nand(host);
++
++	/* Hifmc host init */
++	hifmc100_host_init(host);
++	host->chip = chip;
++
++	/* Hifmc nand_chip struct init */
++	hifmc100_chip_init(chip);
++
++	hifmc_spi_nand_ids_register();
++	hinfc_param_adjust = hifmc100_ecc_probe;
++
++	FMC_PR(BT_DBG, "\t|*-End hifmc100 SPI Nand init\n");
++
++	return 0;
++}
++#ifdef CONFIG_PM
++/*****************************************************************************/
++int hifmc100_suspend(struct platform_device *pltdev, pm_message_t state)
++{
++	unsigned int ret;
++	struct hifmc_host *host = platform_get_drvdata(pltdev);
++	struct hifmc_spi *spi = host->spi;
++
++	mutex_lock(host->lock);
++	hifmc100_switch_to_spi_nand(host);
++
++	ret = spi->driver->wait_ready(spi);
++	if (ret) {
++		DB_MSG("Error: wait ready failed!");
++		return 0;
++	}
++
++	clk_disable_unprepare(host->clk);
++	mutex_unlock(host->lock);
++
++	return 0;
++}
++/*****************************************************************************/
++int hifmc100_resume(struct platform_device *pltdev)
++{
++	int cs;
++	struct hifmc_host *host = platform_get_drvdata(pltdev);
++	struct nand_chip *chip = host->chip;
++
++	mutex_lock(host->lock);
++	hifmc100_switch_to_spi_nand(host);
++	clk_prepare_enable(host->clk);
++
++	for (cs = 0; cs < chip->numchips; cs++)
++		host->send_cmd_reset(host);
++
++	hifmc100_spi_nand_config(host);
++
++	mutex_unlock(host->lock);
++	return 0;
++}
++#endif
++
+diff --git a/drivers/mtd/nand/hifmc100/hifmc100.h b/drivers/mtd/nand/hifmc100/hifmc100.h
+new file mode 100644
+index 0000000..7d04635
+--- /dev/null
++++ b/drivers/mtd/nand/hifmc100/hifmc100.h
+@@ -0,0 +1,386 @@
++/*
++ * The Flash Memory Controller v100 Device Driver for hisilicon
++ *
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++ 
++#ifndef __HIFMC100_H__
++#define __HIFMC100_H__
++
++/*****************************************************************************/
++#include <linux/platform_device.h>
++#include <linux/mfd/hisi_fmc.h>
++
++/*****************************************************************************/
++#define INFINITE			(0xFFFFFFFF)
++
++/*****************************************************************************/
++#define SPI_IF_READ_STD			(0x01)
++#define SPI_IF_READ_FAST		(0x02)
++#define SPI_IF_READ_DUAL		(0x04)
++#define SPI_IF_READ_DUAL_ADDR		(0x08)
++#define SPI_IF_READ_QUAD		(0x10)
++#define SPI_IF_READ_QUAD_ADDR		(0x20)
++
++#define SPI_IF_WRITE_STD		(0x01)
++#define SPI_IF_WRITE_DUAL		(0x02)
++#define SPI_IF_WRITE_DUAL_ADDR		(0x04)
++#define SPI_IF_WRITE_QUAD		(0x08)
++#define SPI_IF_WRITE_QUAD_ADDR		(0x10)
++
++#define SPI_IF_ERASE_SECTOR_4K		(0x01)
++#define SPI_IF_ERASE_SECTOR_32K		(0x02)
++#define SPI_IF_ERASE_SECTOR_64K		(0x04)
++#define SPI_IF_ERASE_SECTOR_128K	(0x08)
++#define SPI_IF_ERASE_SECTOR_256K	(0x10)
++
++/******************************************************************************/
++#define HIFMC_SPI_NAND_SUPPORT_READ	(SPI_IF_READ_STD \
++					| SPI_IF_READ_FAST \
++					| SPI_IF_READ_DUAL \
++					| SPI_IF_READ_DUAL_ADDR \
++					| SPI_IF_READ_QUAD \
++					| SPI_IF_READ_QUAD_ADDR)
++
++#define HIFMC_SPI_NAND_SUPPORT_WRITE	(SPI_IF_WRITE_STD | SPI_IF_WRITE_QUAD)
++
++#define HIFMC_SPI_NAND_SUPPORT_MAX_DUMMY	8
++
++/*****************************************************************************/
++#define SPI_CMD_READ_STD		0x03	/* Standard read cache */
++#define SPI_CMD_READ_FAST		0x0B	/* Higher speed read cache */
++#define SPI_CMD_READ_DUAL		0x3B	/* 2 IO read cache only date */
++#define SPI_CMD_READ_DUAL_ADDR		0xBB	/* 2 IO read cache date&addr */
++#define SPI_CMD_READ_QUAD		0x6B	/* 4 IO read cache only date */
++#define SPI_CMD_READ_QUAD_ADDR		0xEB	/* 4 IO read cache date&addr */
++
++#define SPI_CMD_WRITE_STD		0x02	/* Standard page program */
++#define SPI_CMD_WRITE_DUAL		0xA2	/* 2 IO program only date */
++#define SPI_CMD_WRITE_DUAL_ADDR		0xD2	/* 2 IO program date&addr */
++#define SPI_CMD_WRITE_QUAD		0x32	/* 4 IO program only date */
++#define SPI_CMD_WRITE_QUAD_ADDR		0x12	/* 4 IO program date&addr */
++
++#define SPI_CMD_SE_4K			0x20	/* 4KB sector Erase */
++#define SPI_CMD_SE_32K			0x52	/* 32KB sector Erase */
++#define SPI_CMD_SE_64K			0xD8	/* 64KB sector Erase */
++#define SPI_CMD_SE_128K			0xD8	/* 128KB sector Erase */
++#define SPI_CMD_SE_256K			0xD8	/* 256KB sector Erase */
++
++/*****************************************************************************/
++#define SET_READ_STD(_dummy_, _size_, _clk_) \
++	static struct spi_op read_std_##_dummy_##_size_##_clk_ = { \
++	SPI_IF_READ_STD, SPI_CMD_READ_STD, _dummy_, _size_, _clk_ }
++
++#define SET_READ_FAST(_dummy_, _size_, _clk_) \
++	static struct spi_op read_fast_##_dummy_##_size_##_clk_ = { \
++	SPI_IF_READ_FAST, SPI_CMD_READ_FAST, _dummy_, _size_, _clk_ }
++
++#define SET_READ_DUAL(_dummy_, _size_, _clk_) \
++	static struct spi_op read_dual_##_dummy_##_size_##_clk_ = { \
++	SPI_IF_READ_DUAL, SPI_CMD_READ_DUAL, _dummy_, _size_, _clk_ }
++
++#define SET_READ_DUAL_ADDR(_dummy_, _size_, _clk_) \
++	static struct spi_op read_dual_addr_##_dummy_##_size_##_clk_ = { \
++	SPI_IF_READ_DUAL_ADDR, SPI_CMD_READ_DUAL_ADDR, _dummy_, _size_, _clk_ }
++
++#define SET_READ_QUAD(_dummy_, _size_, _clk_) \
++	static struct spi_op read_quad_##_dummy_##_size_##_clk_ = { \
++	SPI_IF_READ_QUAD, SPI_CMD_READ_QUAD, _dummy_, _size_, _clk_ }
++
++#define SET_READ_QUAD_ADDR(_dummy_, _size_, _clk_) \
++	static struct spi_op read_quad_addr_##_dummy_##_size_##_clk_ = { \
++	SPI_IF_READ_QUAD_ADDR, SPI_CMD_READ_QUAD_ADDR, _dummy_, _size_, _clk_ }
++
++/*****************************************************************************/
++#define SET_WRITE_STD(_dummy_, _size_, _clk_) \
++	static struct spi_op write_std_##_dummy_##_size_##_clk_ = { \
++	SPI_IF_WRITE_STD, SPI_CMD_WRITE_STD, _dummy_, _size_, _clk_ }
++
++#define SET_WRITE_DUAL(_dummy_, _size_, _clk_) \
++	static struct spi_op write_dual_##_dummy_##_size_##_clk_ = { \
++	SPI_IF_WRITE_DUAL, SPI_CMD_WRITE_DUAL, _dummy_, _size_, _clk_ }
++
++#define SET_WRITE_DUAL_ADDR(_dummy_, _size_, _clk_) \
++	static struct spi_op write_dual_addr_##_dummy_##_size_##_clk_ = { \
++SPI_IF_WRITE_DUAL_ADDR, SPI_CMD_WRITE_DUAL_ADDR, _dummy_, _size_, _clk_ }
++
++#define SET_WRITE_QUAD(_dummy_, _size_, _clk_) \
++	static struct spi_op write_quad_##_dummy_##_size_##_clk_ = { \
++	SPI_IF_WRITE_QUAD, SPI_CMD_WRITE_QUAD, _dummy_, _size_, _clk_ }
++
++#define SET_WRITE_QUAD_ADDR(_dummy_, _size_, _clk_) \
++	static struct spi_op write_quad_addr_##_dummy_##_size_##_clk_ = { \
++SPI_IF_WRITE_QUAD_ADDR, SPI_CMD_WRITE_QUAD_ADDR, _dummy_, _size_, _clk_ }
++
++/*****************************************************************************/
++#define SET_ERASE_SECTOR_4K(_dummy_, _size_, _clk_) \
++	static struct spi_op erase_sector_4k_##_dummy_##_size_##_clk_ = { \
++	SPI_IF_ERASE_SECTOR_4K, SPI_CMD_SE_4K, _dummy_, _size_, _clk_ }
++
++#define SET_ERASE_SECTOR_32K(_dummy_, _size_, _clk_) \
++	static struct spi_op erase_sector_32k_##_dummy_##_size_##_clk_ = { \
++	SPI_IF_ERASE_SECTOR_32K, SPI_CMD_SE_32K, _dummy_, _size_, _clk_ }
++
++#define SET_ERASE_SECTOR_64K(_dummy_, _size_, _clk_) \
++	static struct spi_op erase_sector_64k_##_dummy_##_size_##_clk_ = { \
++	SPI_IF_ERASE_SECTOR_64K, SPI_CMD_SE_64K, _dummy_, _size_, _clk_ }
++
++#define SET_ERASE_SECTOR_128K(_dummy_, _size_, _clk_) \
++	static struct spi_op erase_sector_128k_##_dummy_##_size_##_clk_ = { \
++	SPI_IF_ERASE_SECTOR_128K, SPI_CMD_SE_128K, _dummy_, _size_, _clk_ }
++
++#define SET_ERASE_SECTOR_256K(_dummy_, _size_, _clk_) \
++	static struct spi_op erase_sector_256k_##_dummy_##_size_##_clk_ = { \
++	SPI_IF_ERASE_SECTOR_256K, SPI_CMD_SE_256K, _dummy_, _size_, _clk_ }
++
++/*****************************************************************************/
++#define READ_STD(_dummy_, _size_, _clk_) read_std_##_dummy_##_size_##_clk_
++#define READ_FAST(_dummy_, _size_, _clk_) read_fast_##_dummy_##_size_##_clk_
++#define READ_DUAL(_dummy_, _size_, _clk_) read_dual_##_dummy_##_size_##_clk_
++#define READ_DUAL_ADDR(_dummy_, _size_, _clk_) \
++		read_dual_addr_##_dummy_##_size_##_clk_
++#define READ_QUAD(_dummy_, _size_, _clk_) read_quad_##_dummy_##_size_##_clk_
++#define READ_QUAD_ADDR(_dummy_, _size_, _clk_) \
++		read_quad_addr_##_dummy_##_size_##_clk_
++
++/*****************************************************************************/
++#define WRITE_STD(_dummy_, _size_, _clk_) write_std_##_dummy_##_size_##_clk_
++#define WRITE_DUAL(_dummy_, _size_, _clk_) write_dual_##_dummy_##_size_##_clk_
++#define WRITE_DUAL_ADDR(_dummy_, _size_, _clk_) \
++		write_dual_addr_##_dummy_##_size_##_clk_
++#define WRITE_QUAD(_dummy_, _size_, _clk_) write_quad_##_dummy_##_size_##_clk_
++#define WRITE_QUAD_ADDR(_dummy_, _size_, _clk_) \
++		write_quad_addr_##_dummy_##_size_##_clk_
++
++/*****************************************************************************/
++#define ERASE_SECTOR_4K(_dummy_, _size_, _clk_) \
++		erase_sector_4k_##_dummy_##_size_##_clk_
++#define ERASE_SECTOR_32K(_dummy_, _size_, _clk_) \
++		erase_sector_32k_##_dummy_##_size_##_clk_
++#define ERASE_SECTOR_64K(_dummy_, _size_, _clk_) \
++		erase_sector_64k_##_dummy_##_size_##_clk_
++#define ERASE_SECTOR_128K(_dummy_, _size_, _clk_) \
++		erase_sector_128k_##_dummy_##_size_##_clk_
++#define ERASE_SECTOR_256K(_dummy_, _size_, _clk_) \
++		erase_sector_256k_##_dummy_##_size_##_clk_
++
++/*****************************************************************************/
++#define SPI_CMD_WREN			0x06	/* Write Enable */
++#define SPI_CMD_WRDI			0x04	/* Write Disable */
++
++#define SPI_CMD_RDID			0x9F	/* Read Identification */
++
++/*****************************************************************************/
++#define SPI_CMD_GET_FEATURES		0x0F	/* Get Features */
++#define SPI_CMD_SET_FEATURE		0x1F	/* Set Feature */
++
++#define SPI_CMD_PAGE_READ		0x13	/* Page Read to Cache */
++
++#define SPI_CMD_RESET			0xff	/* Reset the device */
++
++/*****************************************************************************/
++/* These macroes are for debug only, reg option is slower then dma option */
++#undef HIFMC100_SPI_NAND_SUPPORT_REG_READ
++/* #define HIFMC100_SPI_NAND_SUPPORT_REG_READ */
++
++#undef HIFMC100_SPI_NAND_SUPPORT_REG_WRITE
++/* #define HIFMC100_SPI_NAND_SUPPORT_REG_WRITE */
++
++#ifdef CONFIG_HISI_NAND_ECC_STATUS_REPORT
++/*****************************************************************************/
++#define HIFMC100_ECC_ERR_NUM0_BUF0		0xc0
++
++#define GET_ECC_ERR_NUM(_i, _reg)		(((_reg) >> ((_i) * 8)) & 0xff)
++#endif
++/*****************************************************************************/
++#define REG_CNT_HIGH_BLOCK_NUM_SHIFT		10
++
++#define REG_CNT_BLOCK_NUM_MASK			0x3ff
++#define REG_CNT_BLOCK_NUM_SHIFT			22
++
++#define REG_CNT_PAGE_NUM_MASK			0x3f
++#define REG_CNT_PAGE_NUM_SHIFT			16
++
++#define REG_CNT_WRAP_MASK			0xf
++#define REG_CNT_WRAP_SHIFT			12
++
++#define REG_CNT_ECC_OFFSET_MASK			0xfff
++#define REG_CNT_ECC_8BIT_OFFSET			1054
++#define REG_CNT_ECC_16BIT_OFFSET		1056
++#define REG_CNT_ECC_24BIT_OFFSET		1082
++
++#define ERR_STR_DRIVER "Driver does not support this configure "
++#define ERR_STR_CHECK "Please make sure the hardware configuration is correct"
++
++/*****************************************************************************/
++#define HIFMC100_ADDR_CYCLE_MASK		0x2
++
++/*****************************************************************************/
++#define OP_STYPE_NONE			0x0
++#define OP_STYPE_READ			0x01
++#define OP_STYPE_WRITE			0x02
++#define OP_STYPE_ERASE			0x04
++#define CLK_FMC_TO_CRG_MHZ(_clk)	((_clk) * 2000000)
++
++/*****************************************************************************/
++#define MAX_SPI_OP			8
++
++/*****************************************************************************/
++/* SPI general operation parameter */
++struct spi_op {
++	unsigned char iftype;
++	unsigned char cmd;
++	unsigned char dummy;
++	unsigned int size;
++	unsigned int clock;
++};
++
++struct spi_drv;
++
++/* SPI interface all operation */
++struct hifmc_spi {
++	char *name;
++	int chipselect;
++	unsigned long long chipsize;
++	unsigned int erasesize;
++#define SPI_NOR_3BYTE_ADDR_LEN	3	/* address len 3Bytes */
++#define SPI_NOR_4BYTE_ADDR_LEN	4	/* address len 4Bytes for 32MB */
++	unsigned int addrcycle;
++
++	struct spi_op read[1];
++	struct spi_op write[1];
++	struct spi_op erase[MAX_SPI_OP];
++
++	void *host;
++
++	struct spi_drv *driver;
++};
++
++/* SPI interface special operation function hook */
++struct spi_drv {
++	int (*wait_ready)(struct hifmc_spi *spi);
++	int (*write_enable)(struct hifmc_spi *spi);
++	int (*qe_enable)(struct hifmc_spi *spi);
++	int (*bus_prepare)(struct hifmc_spi *spi, int op);
++	int (*entry_4addr)(struct hifmc_spi *spi, int en);
++};
++
++struct spi_nand_info {
++	char *name;
++	unsigned char id[MAX_SPI_NAND_ID_LEN];
++	unsigned char id_len;
++	unsigned long long chipsize;
++	unsigned int erasesize;
++	unsigned int pagesize;
++	unsigned int oobsize;
++#define BBP_LAST_PAGE		0x01
++#define BBP_FIRST_PAGE		0x02
++	unsigned int badblock_pos;
++	struct spi_op *read[MAX_SPI_OP];
++	struct spi_op *write[MAX_SPI_OP];
++	struct spi_op *erase[MAX_SPI_OP];
++	struct spi_drv *driver;
++};
++
++/*****************************************************************************/
++extern u_char spi_nand_feature_op(struct hifmc_spi *spi, u_char op, u_char addr,
++		u_char val);
++
++/*****************************************************************************/
++struct hifmc_host {
++	struct mtd_info *mtd;
++	struct nand_chip *chip;
++	struct hifmc_spi spi[CONFIG_SPI_NAND_MAX_CHIP_NUM];
++	struct hifmc_cmd_op cmd_op;
++
++	void __iomem *iobase;
++	void __iomem *regbase;
++	struct clk *clk;
++	u32 clkrate;
++
++	unsigned int fmc_cfg;
++	unsigned int fmc_cfg_ecc0;
++
++	unsigned int offset;
++
++	struct device *dev;
++	struct mutex *lock;
++
++	/* This is maybe an un-aligment address, only for malloc or free */
++	char *buforg;
++	char *buffer;
++
++	unsigned int dma_buffer;
++	unsigned int dma_oob;
++
++	unsigned int addr_cycle;
++	unsigned int addr_value[2];
++	unsigned int cache_addr_value[2];
++
++	unsigned int column;
++	unsigned int block_page_mask;
++
++	unsigned int ecctype;
++	unsigned int pagesize;
++	unsigned int oobsize;
++
++	int add_partition;
++
++	int  need_rr_data;
++#define HIFMC100_READ_RETRY_DATA_LEN         128
++	char rr_data[HIFMC100_READ_RETRY_DATA_LEN];
++	struct read_retry_t *read_retry;
++
++	int version;
++
++	/* BOOTROM read two bytes to detect the bad block flag */
++#define HIFMC_BAD_BLOCK_POS		0
++	unsigned char *bbm;	/* nand bad block mark */
++	unsigned short *epm;	/* nand empty page mark */
++
++	unsigned int uc_er;
++
++	void (*send_cmd_write)(struct hifmc_host *host);
++	void (*send_cmd_status)(struct hifmc_host *host);
++	void (*send_cmd_read)(struct hifmc_host *host);
++	void (*send_cmd_erase)(struct hifmc_host *host);
++	void (*send_cmd_readid)(struct hifmc_host *host);
++	void (*send_cmd_reset)(struct hifmc_host *host);
++#ifdef CONFIG_PM
++	int (*suspend)(struct platform_device *pltdev, pm_message_t state);
++	int (*resume)(struct platform_device *pltdev);
++#endif
++};
++
++/*****************************************************************************/
++void hifmc100_ecc0_switch(struct hifmc_host *host, unsigned char op);
++
++int hifmc100_spi_nand_init(struct nand_chip *chip);
++
++/*****************************************************************************/
++extern void hifmc_spi_nand_ids_register(void);
++
++extern void hifmc_set_nand_system_clock(struct spi_op *op, int clk_en);
++
++/*****************************************************************************/
++#ifdef CONFIG_PM
++int hifmc100_suspend(struct platform_device *pltdev, pm_message_t state);
++int hifmc100_resume(struct platform_device *pltdev);
++void hifmc100_spi_nand_config(struct hifmc_host *host);
++#endif
++
++#endif /* End of __HIFMC100_H__ */
+diff --git a/drivers/mtd/nand/hifmc100/hifmc100_os.c b/drivers/mtd/nand/hifmc100/hifmc100_os.c
+new file mode 100644
+index 0000000..f699e8f
+--- /dev/null
++++ b/drivers/mtd/nand/hifmc100/hifmc100_os.c
+@@ -0,0 +1,330 @@
++/*
++ * The Flash Memory Controller v100 Device Driver for hisilicon
++ *
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/delay.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/dma-mapping.h>
++#include <linux/mtd/nand.h>
++#include <linux/mtd/partitions.h>
++#include <linux/of_platform.h>
++#include <linux/mfd/hisi_fmc.h>
++
++#include <asm/setup.h>
++
++#include "../../mtdcore.h"
++#include "hifmc100.h"
++#include "hifmc100_os.h"
++
++/*****************************************************************************/
++#define MAX_MTD_PARTITIONS	(32)
++
++struct partition_entry {
++	char name[16];
++	unsigned long long start;
++	unsigned long long length;
++	unsigned int flags;
++};
++
++struct partition_info {
++	int parts_num;
++	struct partition_entry entry[MAX_MTD_PARTITIONS];
++	struct mtd_partition parts[MAX_MTD_PARTITIONS];
++};
++
++static struct partition_info ptn_info = {0};
++
++/*****************************************************************************/
++static int __init parse_nand_partitions(const struct tag *tag)
++{
++	int i, len;
++
++	if (tag->hdr.size <= 2) {
++		pr_info("tag->hdr.size <= 2\n");
++		return 0;
++	}
++
++	len = sizeof(struct partition_entry) / sizeof(int);
++	ptn_info.parts_num = (tag->hdr.size - 2) / len;
++
++	len = ptn_info.parts_num * sizeof(struct partition_entry);
++	memcpy(ptn_info.entry, &tag->u, len);
++
++	for (i = 0; i < ptn_info.parts_num; i++) {
++		ptn_info.parts[i].name = ptn_info.entry[i].name;
++		ptn_info.parts[i].size = (ptn_info.entry[i].length);
++		ptn_info.parts[i].offset = (ptn_info.entry[i].start);
++		ptn_info.parts[i].mask_flags = 0;
++		ptn_info.parts[i].ecclayout = 0;
++	}
++
++	return 0;
++}
++
++/* turn to ascii is "HiNp" */
++__tagtable(0x48694E70, parse_nand_partitions);
++
++/*****************************************************************************/
++static int hifmc100_spi_nand_pre_probe(struct nand_chip *chip)
++{
++	uint8_t nand_maf_id;
++	struct hifmc_host *host = chip->priv;
++
++	/* Reset the chip first */
++	host->send_cmd_reset(host);
++	udelay(1000);
++
++	/* Check the ID */
++	host->offset = 0;
++	memset((unsigned char *)(chip->IO_ADDR_R), 0, 0x10);
++	host->send_cmd_readid(host);
++	nand_maf_id = hifmc_readb(chip->IO_ADDR_R);
++
++	if (nand_maf_id == 0x00 || nand_maf_id == 0xff) {
++		printk("Cannot found a valid SPI Nand Device\n");
++		return 1;
++	}
++
++	return 0;
++}
++/*****************************************************************************/
++static int hifmc_nand_scan(struct mtd_info *mtd)
++{
++	int result = 0;
++	unsigned char cs, chip_num = CONFIG_SPI_NAND_MAX_CHIP_NUM;
++	struct nand_chip *chip = mtd->priv;
++	struct hifmc_host *host = chip->priv;
++
++	for (cs = 0; chip_num && (cs < HIFMC_MAX_CHIP_NUM); cs++) {
++		if (hifmc_cs_user[cs]) {
++			FMC_PR(BT_DBG, "\t\t*-Current CS(%d) is occupied.\n",
++					cs);
++			continue;
++		}
++
++		host->cmd_op.cs = cs;
++
++		if (hifmc100_spi_nand_pre_probe(chip))
++			return -ENODEV;
++
++		FMC_PR(BT_DBG, "\t\t*-Scan SPI nand flash on CS: %d\n", cs);
++		if (nand_scan(mtd, chip_num))
++			continue;
++		chip_num--;
++	}
++
++	if (chip_num == CONFIG_SPI_NAND_MAX_CHIP_NUM)
++		result = -ENXIO;
++	else
++		result = 0;
++
++	return result;
++}
++
++/*****************************************************************************/
++static int hifmc_os_add_paratitions(struct hifmc_host *host)
++{
++	int ix;
++	int nr_parts = 0;
++	struct mtd_partition *parts = NULL;
++	int ret;
++
++#ifdef CONFIG_MTD_CMDLINE_PARTS
++	static const char *part_probes[] = {"cmdlinepart", NULL, };
++	nr_parts = parse_mtd_partitions(host->mtd, part_probes, &parts, 0);
++#endif
++
++	/* (1) if nr_parts > 0, Using commandline partition definition
++	 * (2) if nr_parts = 0, Using board partition definition, or parse
++	 * the parameter from __tag.
++	 */
++	if (!nr_parts) {
++		nr_parts = ptn_info.parts_num;
++		parts    = ptn_info.parts;
++	}
++
++	if (nr_parts <= 0)
++		return 0;
++
++	if (BT_DBG)
++		for (ix = 0; ix < nr_parts; ix++) {
++			DB_MSG("partitions[%d] = {.name = %s, ",
++					ix, parts[ix].name);
++			DB_MSG(".offset = 0x%.8x, .size = 0x%08x (%uMB) }\n",
++				(unsigned int)parts[ix].offset,
++				(unsigned int)parts[ix].size,
++				(unsigned int)parts[ix].size / (1024 * 1024));
++		}
++
++	host->add_partition = 1;
++
++	ret = mtd_device_register(host->mtd, parts, nr_parts);
++
++	return (1 == ret) ? -ENODEV : 0;
++}
++
++/*****************************************************************************/
++static int hisi_spi_nand_probe(struct platform_device *pltdev)
++{
++	int len, result = 0;
++	struct hifmc_host *host;
++	struct nand_chip *chip;
++	struct mtd_info *mtd;
++	struct device *dev = &pltdev->dev;
++	struct device_node *np = NULL;
++	struct hisi_fmc *fmc = dev_get_drvdata(dev->parent);
++
++	FMC_PR(BT_DBG, "\t*-Start SPI Nand flash driver probe\n");
++
++	len = sizeof(struct hifmc_host) + sizeof(struct nand_chip)
++		+ sizeof(struct mtd_info);
++	host = devm_kzalloc(dev, len, GFP_KERNEL);
++	if (!host)
++		return -ENOMEM;
++	memset((char *)host, 0, len);
++
++	platform_set_drvdata(pltdev, host);
++	host->dev = &pltdev->dev;
++
++	host->chip = chip = (struct nand_chip *)&host[1];
++	host->mtd = mtd = (struct mtd_info *)&chip[1];
++
++	host->regbase = fmc->regbase;
++	host->iobase = fmc->iobase;
++	host->clk = fmc->clk;
++	host->lock = &fmc->lock;
++
++	memset((char *)host->iobase, 0xff, SPI_NAND_BUFFER_LEN);
++	chip->IO_ADDR_R = chip->IO_ADDR_W = host->iobase;
++
++	host->buffer = dmam_alloc_coherent(host->dev, SPI_NAND_BUFFER_LEN,
++			&host->dma_buffer, GFP_KERNEL);
++	if (!host->buffer) {
++		DB_MSG("Error: Can't allocate memory for dma buffer.");
++		result = -EIO;
++		goto fail;
++	}
++	memset(host->buffer, 0xff, SPI_NAND_BUFFER_LEN);
++
++	chip->priv = host;
++	result = hifmc100_spi_nand_init(chip);
++	if (result) {
++		FMC_PR(BT_DBG, "\t|-SPI Nand init failed, ret: %d\n", result);
++		result = -ENODEV;
++		goto fail;
++	}
++
++	np = of_get_next_available_child(dev->of_node, NULL);
++	mtd->name = np->name;
++	mtd->type = MTD_NANDFLASH;
++	mtd->priv = chip;
++	mtd->owner = THIS_MODULE;
++
++	result = of_property_read_u32(np, "spi-max-frequency", &host->clkrate);
++	if (result)
++		goto fail;
++
++	result = hifmc_nand_scan(mtd);
++	if (result) {
++		FMC_PR(BT_DBG, "\t|-Scan SPI Nand failed.\n");
++		goto fail;
++	}
++
++	result = hifmc_os_add_paratitions(host);
++	if (host->add_partition)
++		goto end;
++
++	if (!add_mtd_device(host->mtd)) {
++		result = 0;
++		goto end;
++	}
++
++	result = -ENODEV;
++	DB_MSG("Error: MTD partition register failed! result: %d\n",
++			result);
++fail:
++	nand_release(mtd);
++	clk_disable_unprepare(host->clk);
++end:
++	FMC_PR(BT_DBG, "\t*-End driver probe, result: %d\n", result);
++	return result;
++}
++
++/*****************************************************************************/
++static int hisi_spi_nand_remove(struct platform_device *pltdev)
++{
++	struct hifmc_host *host = platform_get_drvdata(pltdev);
++
++	clk_disable_unprepare(host->clk);
++	nand_release(host->mtd);
++
++	return 0;
++}
++
++#ifdef CONFIG_PM
++/*****************************************************************************/
++static int hifmc100_os_suspend(struct platform_device *pltdev,
++		pm_message_t state)
++{
++	struct hifmc_host *host = platform_get_drvdata(pltdev);
++
++	if (host && host->suspend)
++		return (host->suspend)(pltdev, state);
++
++	return 0;
++}
++
++/*****************************************************************************/
++static int hifmc100_os_resume(struct platform_device *pltdev)
++{
++	struct hifmc_host *host = platform_get_drvdata(pltdev);
++
++	if (host && host->resume)
++		return (host->resume)(pltdev);
++
++	return 0;
++}
++#endif /* End of CONFIG_PM */
++/*****************************************************************************/
++static const struct of_device_id hisi_spi_nand_dt_ids[] = {
++	{ .compatible = "hisilicon,hisi-spi-nand"},
++	{ /* sentinel */ }
++};
++MODULE_DEVICE_TABLE(of, hisi_spi_nand_dt_ids);
++
++static struct platform_driver hisi_spi_nand_driver = {
++	.driver = {
++		.name	= "hisi_spi_nand",
++		.of_match_table = hisi_spi_nand_dt_ids,
++	},
++	.probe	= hisi_spi_nand_probe,
++	.remove = hisi_spi_nand_remove,
++#ifdef CONFIG_PM
++	.suspend	= hifmc100_os_suspend,
++	.resume		= hifmc100_os_resume,
++#endif
++};
++module_platform_driver(hisi_spi_nand_driver);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("BVT_BSP");
++MODULE_DESCRIPTION("Hisilicon Flash Memory Controller V100 SPI Nand Driver");
+diff --git a/drivers/mtd/nand/hifmc100/hifmc100_os.h b/drivers/mtd/nand/hifmc100/hifmc100_os.h
+new file mode 100644
+index 0000000..9c720b4
+--- /dev/null
++++ b/drivers/mtd/nand/hifmc100/hifmc100_os.h
+@@ -0,0 +1,37 @@
++/*
++ * The Flash Memory Controller v100 Device Driver for hisilicon
++ *
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#ifndef __HIFMC100_OS_H__
++#define __HIFMC100_OS_H__
++
++/*****************************************************************************/
++#ifndef CONFIG_SPI_NAND_MAX_CHIP_NUM
++	#define CONFIG_SPI_NAND_MAX_CHIP_NUM		(1)
++	#warning NOT config CONFIG_SPI_NAND_MAX_CHIP_NUM, \
++		used default value, maybe invalid.
++#endif
++
++/*****************************************************************************/
++#define SPI_NAND_MAX_PAGESIZE			4096
++#define SPI_NAND_MAX_OOBSIZE			256
++
++#define SPI_NAND_BUFFER_LEN	(SPI_NAND_MAX_PAGESIZE + SPI_NAND_MAX_OOBSIZE)
++
++#endif /* End of __HIFMC100_OS_H__ */
+diff --git a/drivers/mtd/nand/hifmc100/hifmc100_spi_general.c b/drivers/mtd/nand/hifmc100/hifmc100_spi_general.c
+new file mode 100644
+index 0000000..6fef356
+--- /dev/null
++++ b/drivers/mtd/nand/hifmc100/hifmc100_spi_general.c
+@@ -0,0 +1,260 @@
++/*
++ * The Flash Memory Controller v100 Device Driver for hisilicon
++ *
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++/*
++	Send set/get features command to SPI Nand flash
++*/
++u_char spi_nand_feature_op(struct hifmc_spi *spi, u_char op, u_char addr,
++		u_char val)
++{
++	unsigned int reg;
++	const char *str[] = {"Get", "Set"};
++	struct hifmc_host *host = (struct hifmc_host *)spi->host;
++
++	if ((GET_OP == op) && (STATUS_ADDR == addr)) {
++		if (SR_DBG)
++			pr_info("\n");
++		FMC_PR(SR_DBG, "\t\t|*-Start Get Status\n");
++
++		reg = OP_CFG_FM_CS(host->cmd_op.cs);
++		hifmc_writel(host, FMC_OP_CFG, reg);
++		FMC_PR(SR_DBG, "\t\t||-Set OP_CFG[%#x]%#x\n", FMC_OP_CFG, reg);
++
++		reg = FMC_OP_READ_STATUS_EN | FMC_OP_REG_OP_START;
++		hifmc_writel(host, FMC_OP, reg);
++		FMC_PR(SR_DBG, "\t\t||-Set OP[%#x]%#x\n", FMC_OP, reg);
++
++		FMC_CMD_WAIT_CPU_FINISH(host);
++
++		val = hifmc_readl(host, FMC_STATUS);
++		FMC_PR(SR_DBG, "\t\t|*-End Get Status, result: %#x\n", val);
++
++		return val;
++	}
++
++	FMC_PR(FT_DBG, "\t|||*-Start %s feature, addr[%#x]\n", str[op], addr);
++
++	hifmc100_ecc0_switch(host, ENABLE);
++
++	reg = FMC_CMD_CMD1(op ? SPI_CMD_SET_FEATURE : SPI_CMD_GET_FEATURES);
++	hifmc_writel(host, FMC_CMD, reg);
++	FMC_PR(FT_DBG, "\t||||-Set CMD[%#x]%#x\n", FMC_CMD, reg);
++
++	hifmc_writel(host, FMC_ADDRL, addr);
++	FMC_PR(FT_DBG, "\t||||-Set ADDRL[%#x]%#x\n", FMC_ADDRL, addr);
++
++	reg = OP_CFG_FM_CS(host->cmd_op.cs)
++		| OP_CFG_ADDR_NUM(FEATURES_OP_ADDR_NUM);
++	hifmc_writel(host, FMC_OP_CFG, reg);
++	FMC_PR(FT_DBG, "\t||||-Set OP_CFG[%#x]%#x\n", FMC_OP_CFG, reg);
++
++	reg = FMC_DATA_NUM_CNT(FEATURES_DATA_LEN);
++	hifmc_writel(host, FMC_DATA_NUM, reg);
++	FMC_PR(FT_DBG, "\t||||-Set DATA_NUM[%#x]%#x\n", FMC_DATA_NUM, reg);
++
++	reg = FMC_OP_CMD1_EN
++		| FMC_OP_ADDR_EN
++		| FMC_OP_REG_OP_START;
++
++	if (SET_OP == op) {
++		reg |= FMC_OP_WRITE_DATA_EN;
++		hifmc_writeb(val, host->iobase);
++		FMC_PR(FT_DBG, "\t||||-Write IO[%#x]%#x\n", (u_int)host->iobase,
++				*(u_char *)host->iobase);
++	} else
++		reg |= FMC_OP_READ_DATA_EN;
++
++	hifmc_writel(host, FMC_OP, reg);
++	FMC_PR(FT_DBG, "\t||||-Set OP[%#x]%#x\n", FMC_OP, reg);
++
++	FMC_CMD_WAIT_CPU_FINISH(host);
++
++	if (GET_OP == op) {
++		val = hifmc_readb(host->iobase);
++		FMC_PR(FT_DBG, "\t||||-Read IO[%#x]%#x\n", (u_int)host->iobase,
++				*(u_char *)host->iobase);
++	}
++
++	hifmc100_ecc0_switch(host, DISABLE);
++
++	FMC_PR(FT_DBG, "\t|||*-End %s Feature[%#x]:%#x\n", str[op], addr, val);
++
++	return val;
++}
++
++/*****************************************************************************/
++/*
++	Read status[C0H]:[0]bit OIP, judge whether the device is busy or not
++*/
++static int spi_general_wait_ready(struct hifmc_spi *spi)
++{
++	unsigned char status;
++	unsigned long deadline = jiffies + FMC_MAX_READY_WAIT_JIFFIES;
++	struct hifmc_host *host = (struct hifmc_host *)spi->host;
++
++	do {
++		status = spi_nand_feature_op(spi, GET_OP, STATUS_ADDR, 0);
++		if (!(status & STATUS_OIP_MASK)) {
++			if ((host->cmd_op.l_cmd == NAND_CMD_ERASE2)
++			    && (status & STATUS_E_FAIL_MASK))
++				return status;
++			if ((host->cmd_op.l_cmd == NAND_CMD_PAGEPROG)
++			    && (status & STATUS_P_FAIL_MASK))
++				return status;
++			return 0;
++		}
++
++		cond_resched();
++
++	} while (!time_after_eq(jiffies, deadline));
++
++	DB_MSG("Error: SPI Nand wait ready timeout, status: %#x\n", status);
++
++	return 1;
++}
++
++/*****************************************************************************/
++/*
++	Send write enable cmd to SPI Nand, status[C0H]:[2]bit WEL must be set 1
++*/
++static int spi_general_write_enable(struct hifmc_spi *spi)
++{
++	unsigned int reg;
++	struct hifmc_host *host = (struct hifmc_host *)spi->host;
++
++	if (WE_DBG)
++		pr_info("\n");
++	FMC_PR(WE_DBG, "\t|*-Start Write Enable\n");
++
++	reg = spi_nand_feature_op(spi, GET_OP, STATUS_ADDR, 0);
++	if (reg & STATUS_WEL_MASK) {
++		FMC_PR(WE_DBG, "\t||-Write Enable was opened! reg: %#x\n",
++				reg);
++		return 0;
++	}
++
++	reg = hifmc_readl(host, FMC_GLOBAL_CFG);
++	FMC_PR(WE_DBG, "\t||-Get GLOBAL_CFG[%#x]%#x\n", FMC_GLOBAL_CFG, reg);
++	if (reg & FMC_GLOBAL_CFG_WP_ENABLE) {
++		reg &= ~FMC_GLOBAL_CFG_WP_ENABLE;
++		hifmc_writel(host, FMC_GLOBAL_CFG, reg);
++		FMC_PR(WE_DBG, "\t||-Set GLOBAL_CFG[%#x]%#x\n",
++				FMC_GLOBAL_CFG, reg);
++	}
++
++	reg = FMC_CMD_CMD1(SPI_CMD_WREN);
++	hifmc_writel(host, FMC_CMD, reg);
++	FMC_PR(WE_DBG, "\t||-Set CMD[%#x]%#x\n", FMC_CMD, reg);
++
++	reg = OP_CFG_FM_CS(host->cmd_op.cs);
++	hifmc_writel(host, FMC_OP_CFG, reg);
++	FMC_PR(WE_DBG, "\t||-Set OP_CFG[%#x]%#x\n", FMC_OP_CFG, reg);
++
++	reg = FMC_OP_CMD1_EN | FMC_OP_REG_OP_START;
++	hifmc_writel(host, FMC_OP, reg);
++	FMC_PR(WE_DBG, "\t||-Set OP[%#x]%#x\n", FMC_OP, reg);
++
++	FMC_CMD_WAIT_CPU_FINISH(host);
++
++#if WE_DBG
++	spi->driver->wait_ready(spi);
++
++	reg = spi_nand_feature_op(spi, GET_OP, STATUS_ADDR, 0);
++	if (reg & STATUS_WEL_MASK)
++		FMC_PR(WE_DBG, "\t||-Write Enable success. reg: %#x\n", reg);
++	else {
++		DB_MSG("Error: Write Enable failed! reg: %#x\n", reg);
++		return reg;
++	}
++#endif
++
++	FMC_PR(WE_DBG, "\t|*-End Write Enable\n");
++	return 0;
++}
++
++/*****************************************************************************/
++/*
++	judge whether SPI Nand support QUAD read/write or not
++*/
++static int spi_is_quad(struct hifmc_spi *spi)
++{
++	const char *if_str[] = {"STD", "DUAL", "DIO", "QUAD", "QIO"};
++
++	FMC_PR(QE_DBG, "\t\t|||*-SPI read iftype: %s write iftype: %s\n",
++		if_str[spi->read->iftype], if_str[spi->write->iftype]);
++
++	if ((IF_TYPE_QUAD == spi->read->iftype)
++	    || (IF_TYPE_QIO == spi->read->iftype)
++	    || (IF_TYPE_QUAD == spi->write->iftype)
++	    || (IF_TYPE_QIO == spi->write->iftype))
++		return 1;
++
++	return 0;
++}
++
++/*****************************************************************************/
++/*
++	Send set features cmd to SPI Nand, feature[B0H]:[0]bit QE would be set
++*/
++static int spi_general_qe_enable(struct hifmc_spi *spi)
++{
++	unsigned int reg, op;
++	const char *str[] = {"Disable", "Enable"};
++
++	FMC_PR(QE_DBG, "\t||*-Start SPI Nand flash QE\n");
++
++	op = spi_is_quad(spi);
++
++	FMC_PR(QE_DBG, "\t|||*-End Quad check, SPI Nand %s Quad.\n", str[op]);
++
++	reg = spi_nand_feature_op(spi, GET_OP, FEATURE_ADDR, 0);
++	FMC_PR(QE_DBG, "\t|||-Get [%#x]feature: %#x\n", FEATURE_ADDR, reg);
++	if ((reg & FEATURE_QE_ENABLE) == op) {
++		FMC_PR(QE_DBG, "\t||*-SPI Nand quad was %sd!\n", str[op]);
++		return op;
++	}
++
++	if (op == ENABLE)
++		reg |= FEATURE_QE_ENABLE;
++	else
++		reg &= ~FEATURE_QE_ENABLE;
++
++	spi_nand_feature_op(spi, SET_OP, FEATURE_ADDR, reg);
++	FMC_PR(QE_DBG, "\t|||-SPI Nand %s Quad\n", str[op]);
++
++	spi->driver->wait_ready(spi);
++
++	reg = spi_nand_feature_op(spi, GET_OP, FEATURE_ADDR, 0);
++	if ((reg & FEATURE_QE_ENABLE) == op)
++		FMC_PR(QE_DBG, "\t|||-SPI Nand %s Quad succeed!\n", str[op]);
++	else
++		DB_MSG("Error: %s Quad failed! reg: %#x\n", str[op], reg);
++
++	FMC_PR(QE_DBG, "\t||*-End SPI Nand %s Quad.\n", str[op]);
++
++	return op;
++}
++
++/****************************************************************************/
++/* some spi nand flash don't QUAD enable */
++static int spi_do_not_qe_enable(struct hifmc_spi *spi)
++{
++	return 0;
++}
+diff --git a/drivers/mtd/nand/hifmc100/hifmc_spi_nand_ids.c b/drivers/mtd/nand/hifmc100/hifmc_spi_nand_ids.c
+new file mode 100644
+index 0000000..de4751f
+--- /dev/null
++++ b/drivers/mtd/nand/hifmc100/hifmc_spi_nand_ids.c
+@@ -0,0 +1,1335 @@
++/*
++ * The Flash Memory Controller v100 Device Driver for hisilicon
++ *
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++ 
++#include <asm/setup.h>
++#include <linux/types.h>
++#include <linux/io.h>
++#include <linux/sched.h>
++#include <linux/printk.h>
++#include <linux/platform_device.h>
++#include <linux/mtd/nand.h>
++#include <linux/mtd/partitions.h>
++#include <mach/platform.h>
++#include <linux/mfd/hisi_fmc.h>
++
++#include "../hinfc_gen.h"
++#include "hifmc100.h"
++
++/*****************************************************************************/
++SET_READ_STD(1, INFINITE, 24);
++
++SET_READ_FAST(1, INFINITE, 75);
++SET_READ_FAST(1, INFINITE, 80);
++SET_READ_FAST(1, INFINITE, 104);
++SET_READ_FAST(1, INFINITE, 108);
++SET_READ_FAST(1, INFINITE, 120);
++
++SET_READ_DUAL(1, INFINITE, 75);
++SET_READ_DUAL(1, INFINITE, 80);
++SET_READ_DUAL(1, INFINITE, 104);
++SET_READ_DUAL(1, INFINITE, 108);
++SET_READ_DUAL(1, INFINITE, 120);
++
++SET_READ_DUAL_ADDR(1, INFINITE, 75);
++SET_READ_DUAL_ADDR(1, INFINITE, 80);
++SET_READ_DUAL_ADDR(1, INFINITE, 104);
++SET_READ_DUAL_ADDR(1, INFINITE, 108);
++SET_READ_DUAL_ADDR(1, INFINITE, 120);
++
++SET_READ_QUAD(1, INFINITE, 75);
++SET_READ_QUAD(1, INFINITE, 80);
++SET_READ_QUAD(1, INFINITE, 104);
++SET_READ_QUAD(1, INFINITE, 108);
++SET_READ_QUAD(1, INFINITE, 120);
++
++SET_READ_QUAD_ADDR(1, INFINITE, 75);
++SET_READ_QUAD_ADDR(2, INFINITE, 75);
++SET_READ_QUAD_ADDR(1, INFINITE, 80);
++SET_READ_QUAD_ADDR(2, INFINITE, 80);
++SET_READ_QUAD_ADDR(2, INFINITE, 104);
++SET_READ_QUAD_ADDR(1, INFINITE, 108);
++SET_READ_QUAD_ADDR(1, INFINITE, 120);
++
++/*****************************************************************************/
++SET_WRITE_STD(0, 256, 24);
++SET_WRITE_STD(0, 256, 75);
++SET_WRITE_STD(0, 256, 80);
++SET_WRITE_STD(0, 256, 104);
++
++SET_WRITE_QUAD(0, 256, 75);
++SET_WRITE_QUAD(0, 256, 80);
++SET_WRITE_QUAD(0, 256, 104);
++SET_WRITE_QUAD(0, 256, 108);
++SET_WRITE_QUAD(0, 256, 120);
++
++/*****************************************************************************/
++SET_ERASE_SECTOR_128K(0, _128K, 24);
++SET_ERASE_SECTOR_128K(0, _128K, 75);
++SET_ERASE_SECTOR_128K(0, _128K, 80);
++SET_ERASE_SECTOR_128K(0, _128K, 104);
++
++SET_ERASE_SECTOR_256K(0, _256K, 24);
++SET_ERASE_SECTOR_256K(0, _256K, 75);
++SET_ERASE_SECTOR_256K(0, _256K, 80);
++SET_ERASE_SECTOR_256K(0, _256K, 104);
++
++/*****************************************************************************/
++#include "hifmc100_spi_general.c"
++static struct spi_drv spi_driver_general = {
++	.wait_ready = spi_general_wait_ready,
++	.write_enable = spi_general_write_enable,
++	.qe_enable = spi_general_qe_enable,
++};
++
++static struct spi_drv spi_driver_no_qe = {
++	.wait_ready = spi_general_wait_ready,
++	.write_enable = spi_general_write_enable,
++	.qe_enable = spi_do_not_qe_enable,
++};
++
++/*****************************************************************************/
++#define SPI_NAND_ID_TAB_VER		"2.4"
++
++/******* SPI Nand ID Table ***************************************************
++* Version	Manufacturer	Chip Name	Size		Operation
++* 1.0		ESMT		F50L512M41A	64MB		Add 5 chip
++*		GD		5F1GQ4UAYIG	128MB
++*		GD		5F2GQ4UAYIG	256MB
++*		GD		5F4GQ4UAYIG	512MB
++*		GD		5F4GQ4UBYIG	512MB
++* 1.1		ESMT		F50L1G41A	128MB		Add 2 chip
++*		Winbond		W25N01GV	128MB
++* 1.2		GD		5F1GQ4UBYIG	128MB		Add 2 chip
++*		GD		5F2GQ4UBYIG	256MB
++* 1.3		ATO		ATO25D1GA	128MB		Add 1 chip
++* 1.4		MXIC		MX35LF1GE4AB	128MB		Add 2 chip
++*		MXIC		MX35LF2GE4AB	256MB		(SOP-16Pin)
++* 1.5		Paragon		PN26G01A	128MB		Add 1 chip
++* 1.6		All-flash	AFS1GQ4UAC	128MB		Add 1 chip
++* 1.7		TOSHIBA		TC58CVG0S3H	128MB		Add 2 chip
++*		TOSHIBA		TC58CVG2S0H	512MB
++* 1.8		ALL-flash	AFS2GQ4UAD	256MB		Add 2 chip
++*		Paragon		PN26G02A	256MB
++* 1.9		TOSHIBA		TC58CVG1S3H	256MB		Add 1 chip
++* 2.0		HeYangTek	HYF1GQ4UAACAE	128MB		Add 3 chip
++*		HeYangTek	HYF2GQ4UAACAE	256MB
++*		HeYangTek	HYF4GQ4UAACBE	512MB
++* 2.1		Micron		MT29F1G01ABA	128MB		Add 5 chip
++		Paragon	1.8V	PN26Q01AWSIUG	128MB
++		TOSHIBA 1.8V	TC58CYG0S3H	128MB
++		TOSHIBA 1.8V	TC58CYG1S3H	256MB
++		TOSHIBA 1.8V	TC58CYG2S0H	512MB
++* 2.2		Micron		MT29F2G01ABA	256MB		Add 1 chip
++* 2.3		MXIC		MX35LF2G14AC	256MB		Add 1 chip
++* 2.4	    GD 1.8V		5F4GQ4RAYIG		512MB		Add 1 chip
++******************************************************************************/
++struct spi_nand_info hifmc_spi_nand_flash_table[] = {
++	/* Micron MT29F1G01ABA 1GBit */
++	{
++		.name      = "MT29F1G01ABA",
++		.id        = {0x2C, 0x14},
++		.id_len    = 2,
++		.chipsize  = _128M,
++		.erasesize = _128K,
++		.pagesize  = _2K,
++		.oobsize   = 128,
++		.badblock_pos = BBP_FIRST_PAGE,
++		.read      = {
++			&READ_STD(1, INFINITE, 24),
++			&READ_FAST(1, INFINITE, 80),
++			&READ_DUAL(1, INFINITE, 80),
++			&READ_DUAL_ADDR(1, INFINITE, 80),
++			&READ_QUAD(1, INFINITE, 80),
++			&READ_QUAD_ADDR(2, INFINITE, 80),
++			0
++		},
++		.write     = {
++			&WRITE_STD(0, 256, 80),
++			&WRITE_QUAD(0, 256, 80),
++			0
++		},
++		.erase     = {
++			&ERASE_SECTOR_128K(0, _128K, 80),
++			0
++		},
++		.driver    = &spi_driver_no_qe,
++	},
++
++	/* Micron MT29F2G01ABA 2GBit */
++	{
++		.name      = "MT29F2G01ABA",
++		.id        = {0x2C, 0x24},
++		.id_len    = 2,
++		.chipsize  = _256M,
++		.erasesize = _128K,
++		.pagesize  = _2K,
++		.oobsize   = 128,
++		.badblock_pos = BBP_FIRST_PAGE,
++		.read      = {
++			&READ_STD(1, INFINITE, 24),
++			&READ_FAST(1, INFINITE, 108),
++			&READ_DUAL(1, INFINITE, 108),
++			&READ_DUAL_ADDR(1, INFINITE, 108),
++			&READ_QUAD(1, INFINITE, 108),
++			&READ_QUAD_ADDR(2, INFINITE, 104),
++			0
++		},
++		.write     = {
++			&WRITE_STD(0, 256, 80),
++			&WRITE_QUAD(0, 256, 108),
++			0
++		},
++		.erase     = {
++			&ERASE_SECTOR_128K(0, _128K, 80),
++			0
++		},
++		.driver    = &spi_driver_no_qe,
++	},
++
++	/* ESMT F50L512M41A 512Mbit */
++	{
++		.name      = "F50L512M41A",
++		.id        = {0xC8, 0x20},
++		.id_len    = 2,
++		.chipsize  = _64M,
++		.erasesize = _128K,
++		.pagesize  = _2K,
++		.oobsize   = 64,
++		.badblock_pos = BBP_FIRST_PAGE,
++		.read      = {
++			&READ_STD(1, INFINITE, 24),
++			&READ_FAST(1, INFINITE, 104),
++			&READ_DUAL(1, INFINITE, 104),
++			&READ_QUAD(1, INFINITE, 104),
++			0
++		},
++		.write     = {
++			&WRITE_STD(0, 256, 24),
++			&WRITE_QUAD(0, 256, 104),
++			0
++		},
++		.erase     = {
++			&ERASE_SECTOR_128K(0, _128K, 24),
++			0
++		},
++		.driver    = &spi_driver_no_qe,
++	},
++
++	/* ESMT F50L1G41A 1Gbit */
++	{
++		.name      = "F50L1G41A",
++		.id        = {0xC8, 0x21},
++		.id_len    = 2,
++		.chipsize  = _128M,
++		.erasesize = _128K,
++		.pagesize  = _2K,
++		.oobsize   = 64,
++		.badblock_pos = BBP_FIRST_PAGE,
++		.read      = {
++			&READ_STD(1, INFINITE, 24),
++			&READ_FAST(1, INFINITE, 104),
++			&READ_DUAL(1, INFINITE, 104),
++			&READ_QUAD(1, INFINITE, 104),
++			0
++		},
++		.write     = {
++			&WRITE_STD(0, 256, 24),
++			&WRITE_QUAD(0, 256, 104),
++			0
++		},
++		.erase     = {
++			&ERASE_SECTOR_128K(0, _128K, 24),
++			0
++		},
++		.driver    = &spi_driver_no_qe,
++	},
++
++	/* GD 5F1GQ4UAYIG 1Gbit */
++	{
++		.name      = "5F1GQ4UAYIG",
++		.id        = {0xc8, 0xf1},
++		.id_len    = 2,
++		.chipsize  = _128M,
++		.erasesize = _128K,
++		.pagesize  = _2K,
++		.oobsize   = 64,
++		.badblock_pos = BBP_FIRST_PAGE,
++		.read      = {
++			&READ_STD(1, INFINITE, 24),
++			&READ_FAST(1, INFINITE, 120),
++			&READ_DUAL(1, INFINITE, 120),
++			&READ_DUAL_ADDR(1, INFINITE, 120),
++			&READ_QUAD(1, INFINITE, 120),
++			&READ_QUAD_ADDR(1, INFINITE, 120),
++			0
++		},
++		.write     = {
++			&WRITE_STD(0, 256, 24),
++			&WRITE_QUAD(0, 256, 120),
++			0
++		},
++		.erase     = {
++			&ERASE_SECTOR_128K(0, _128K, 24),
++			0
++		},
++		.driver    = &spi_driver_general,
++	},
++
++	/* GD 5F1GQ4UBYIG 1Gbit */
++	{
++		.name      = "5F1GQ4UBYIG",
++		.id        = {0xc8, 0xd1},
++		.id_len    = 2,
++		.chipsize  = _128M,
++		.erasesize = _128K,
++		.pagesize  = _2K,
++		.oobsize   = 128,
++		.badblock_pos = BBP_FIRST_PAGE,
++		.read      = {
++			&READ_STD(1, INFINITE, 24),
++			&READ_FAST(1, INFINITE, 120),
++			&READ_DUAL(1, INFINITE, 120),
++			&READ_DUAL_ADDR(1, INFINITE, 120),
++			&READ_QUAD(1, INFINITE, 120),
++			&READ_QUAD_ADDR(1, INFINITE, 120),
++			0
++		},
++		.write     = {
++			&WRITE_STD(0, 256, 24),
++			&WRITE_QUAD(0, 256, 120),
++			0
++		},
++		.erase     = {
++			&ERASE_SECTOR_128K(0, _128K, 24),
++			0
++		},
++		.driver    = &spi_driver_general,
++	},
++
++	/* GD 5F2GQ4UAYIG 2Gbit */
++	{
++		.name      = "5F2GQ4UAYIG",
++		.id        = {0xc8, 0xf2},
++		.id_len    = 2,
++		.chipsize  = _256M,
++		.erasesize = _128K,
++		.pagesize  = _2K,
++		.oobsize   = 64,
++		.badblock_pos = BBP_FIRST_PAGE,
++		.read      = {
++			&READ_STD(1, INFINITE, 24),
++			&READ_FAST(1, INFINITE, 120),
++			&READ_DUAL(1, INFINITE, 120),
++			&READ_DUAL_ADDR(1, INFINITE, 120),
++			&READ_QUAD(1, INFINITE, 120),
++			&READ_QUAD_ADDR(1, INFINITE, 120),
++			0
++		},
++		.write     = {
++			&WRITE_STD(0, 256, 24),
++			&WRITE_QUAD(0, 256, 120),
++			0
++		},
++		.erase     = {
++			&ERASE_SECTOR_128K(0, _128K, 24),
++			0
++		},
++		.driver    = &spi_driver_general,
++	},
++
++	/* GD 5F2GQ4UBYIG 2Gbit */
++	{
++		.name      = "5F2GQ4UBYIG",
++		.id        = {0xc8, 0xd2},
++		.id_len    = 2,
++		.chipsize  = _256M,
++		.erasesize = _128K,
++		.pagesize  = _2K,
++		.oobsize   = 128,
++		.badblock_pos = BBP_FIRST_PAGE,
++		.read      = {
++			&READ_STD(1, INFINITE, 24),
++			&READ_FAST(1, INFINITE, 120),
++			&READ_DUAL(1, INFINITE, 120),
++			&READ_DUAL_ADDR(1, INFINITE, 120),
++			&READ_QUAD(1, INFINITE, 120),
++			&READ_QUAD_ADDR(1, INFINITE, 120),
++			0
++		},
++		.write     = {
++			&WRITE_STD(0, 256, 24),
++			&WRITE_QUAD(0, 256, 120),
++			0
++		},
++		.erase     = {
++			&ERASE_SECTOR_128K(0, _128K, 24),
++			0
++		},
++		.driver    = &spi_driver_general,
++	},
++
++	/* GD 5F4GQ4UAYIG 4Gbit */
++	{
++		.name      = "5F4GQ4UAYIG",
++		.id        = {0xc8, 0xf4},
++		.id_len    = 2,
++		.chipsize  = _512M,
++		.erasesize = _128K,
++		.pagesize  = _2K,
++		.oobsize   = 64,
++		.badblock_pos = BBP_FIRST_PAGE,
++		.read      = {
++			&READ_STD(1, INFINITE, 24),
++			&READ_FAST(1, INFINITE, 120),
++			&READ_DUAL(1, INFINITE, 120),
++			&READ_DUAL_ADDR(1, INFINITE, 120),
++			&READ_QUAD(1, INFINITE, 120),
++			&READ_QUAD_ADDR(1, INFINITE, 120),
++			0
++		},
++		.write     = {
++			&WRITE_STD(0, 256, 24),
++			&WRITE_QUAD(0, 256, 120),
++			0
++		},
++		.erase     = {
++			&ERASE_SECTOR_128K(0, _128K, 24),
++			0
++		},
++		.driver    = &spi_driver_general,
++	},
++
++	/* GD 5F4GQ4UBYIG 4Gbit */
++	{
++		.name      = "5F4GQ4UBYIG",
++		.id        = {0xc8, 0xd4},
++		.id_len    = 2,
++		.chipsize  = _512M,
++		.erasesize = _256K,
++		.pagesize  = _4K,
++		.oobsize   = 256,
++		.badblock_pos = BBP_FIRST_PAGE,
++		.read      = {
++			&READ_STD(1, INFINITE, 24),
++			&READ_FAST(1, INFINITE, 120),
++			&READ_DUAL(1, INFINITE, 120),
++			&READ_DUAL_ADDR(1, INFINITE, 120),
++			&READ_QUAD(1, INFINITE, 120),
++			&READ_QUAD_ADDR(1, INFINITE, 120),
++			0
++		},
++		.write     = {
++			&WRITE_STD(0, 256, 24),
++			&WRITE_QUAD(0, 256, 120),
++			0
++		},
++		.erase     = {
++			&ERASE_SECTOR_256K(0, _256K, 24),
++			0
++		},
++		.driver    = &spi_driver_general,
++	},
++
++	/* GD 1.8V 5F4GQ4RAYIG 4Gbit */
++	{
++		.name      = "5F4GQ4RAYIG",
++		.id        = {0xc8, 0xe4},
++		.id_len    = 2,
++		.chipsize  = _512M,
++		.erasesize = _256K,
++		.pagesize  = _4K,
++		.oobsize   = 256,
++		.badblock_pos = BBP_FIRST_PAGE,
++		.read      = {
++			&READ_STD(1, INFINITE, 24),
++			&READ_FAST(1, INFINITE, 75),
++			&READ_DUAL(1, INFINITE, 75),
++			&READ_DUAL_ADDR(1, INFINITE, 75),
++			&READ_QUAD(1, INFINITE, 75),
++			&READ_QUAD_ADDR(1, INFINITE, 75),
++			0
++		},
++		.write     = {
++			&WRITE_STD(0, 256, 24),
++			&WRITE_QUAD(0, 256, 75),
++			0
++		},
++		.erase     = {
++			&ERASE_SECTOR_256K(0, _256K, 24),
++			0
++		},
++		.driver    = &spi_driver_general,
++	},
++
++	/* Winbond W25N01GV 1Gbit */
++	{
++		.name      = "W25N01GV",
++		.id        = {0xef, 0xaa, 0x21},
++		.id_len    = 3,
++		.chipsize  = _128M,
++		.erasesize = _128K,
++		.pagesize  = _2K,
++		.oobsize   = 64,
++		.badblock_pos = BBP_FIRST_PAGE,
++		.read      = {
++			&READ_STD(1, INFINITE, 24),
++			&READ_FAST(1, INFINITE, 104),
++			&READ_DUAL(1, INFINITE, 104),
++			&READ_DUAL_ADDR(1, INFINITE, 104),
++			&READ_QUAD(1, INFINITE, 104),
++			&READ_QUAD_ADDR(2, INFINITE, 104),
++			0
++		},
++		.write     = {
++			&WRITE_STD(0, 256, 24),
++			&WRITE_QUAD(0, 256, 104),
++			0
++		},
++		.erase     = {
++			&ERASE_SECTOR_128K(0, _128K, 24),
++			0
++		},
++		.driver    = &spi_driver_no_qe,
++	},
++
++	/* Winbond W25N01GW 1Gbit 1.8V */
++	{
++		.name      = "W25N01GW",
++		.id        = {0xef, 0xba, 0x21},
++		.id_len    = 3,
++		.chipsize  = _128M,
++		.erasesize = _128K,
++		.pagesize  = _2K,
++		.oobsize   = 64,
++		.badblock_pos = BBP_FIRST_PAGE,
++		.read      = {
++			&READ_STD(1, INFINITE, 24),
++			&READ_FAST(1, INFINITE, 75),
++			&READ_DUAL(1, INFINITE, 75),
++			&READ_DUAL_ADDR(1, INFINITE, 75),
++			&READ_QUAD(1, INFINITE, 75),
++			&READ_QUAD_ADDR(2, INFINITE, 75),
++			0
++		},
++		.write     = {
++			&WRITE_STD(0, 256, 24),
++			&WRITE_QUAD(0, 256, 75),
++			0
++		},
++		.erase     = {
++			&ERASE_SECTOR_128K(0, _128K, 24),
++			0
++		},
++		.driver    = &spi_driver_no_qe,
++	},
++
++	/* ATO ATO25D1GA 1Gbit */
++	{
++		.name      = "ATO25D1GA",
++		.id        = {0x9b, 0x12},
++		.id_len    = 2,
++		.chipsize  = _128M,
++		.erasesize = _128K,
++		.pagesize  = _2K,
++		.oobsize   = 64,
++		.badblock_pos = BBP_FIRST_PAGE,
++		.read      = {
++			&READ_STD(1, INFINITE, 24),
++			&READ_FAST(1, INFINITE, 104),
++			&READ_QUAD(1, INFINITE, 104),
++			0
++		},
++		.write     = {
++			&WRITE_STD(0, 256, 24),
++			&WRITE_QUAD(0, 256, 104),
++			0
++		},
++		.erase     = {
++			&ERASE_SECTOR_128K(0, _128K, 24),
++			0
++		},
++		.driver    = &spi_driver_general,
++	},
++
++	/* MXIC MX35LF1GE4AB 1Gbit */
++	{
++		.name      = "MX35LF1GE4AB",
++		.id        = {0xc2, 0x12},
++		.id_len    = 2,
++		.chipsize  = _128M,
++		.erasesize = _128K,
++		.pagesize  = _2K,
++		.oobsize   = 64,
++		.badblock_pos = BBP_FIRST_PAGE,
++		.read      = {
++			&READ_STD(1, INFINITE, 24),
++			&READ_FAST(1, INFINITE, 104),
++			&READ_QUAD(1, INFINITE, 104),
++			0
++		},
++		.write     = {
++			&WRITE_STD(0, 256, 24),
++			&WRITE_QUAD(0, 256, 104),
++			0
++		},
++		.erase     = {
++			&ERASE_SECTOR_128K(0, _128K, 24),
++			0
++		},
++		.driver    = &spi_driver_general,
++	},
++
++	/* MXIC MX35LF2GE4AB 2Gbit SOP-16Pin */
++	{
++		.name      = "MX35LF2GE4AB",
++		.id        = {0xc2, 0x22},
++		.id_len    = 2,
++		.chipsize  = _256M,
++		.erasesize = _128K,
++		.pagesize  = _2K,
++		.oobsize   = 64,
++		.badblock_pos = BBP_FIRST_PAGE,
++		.read      = {
++			&READ_STD(1, INFINITE, 24),
++			&READ_FAST(1, INFINITE, 104),
++			&READ_QUAD(1, INFINITE, 104),
++			0
++		},
++		.write     = {
++			&WRITE_STD(0, 256, 24),
++			&WRITE_QUAD(0, 256, 104),
++			0
++		},
++		.erase     = {
++			&ERASE_SECTOR_128K(0, _128K, 24),
++			0
++		},
++		.driver    = &spi_driver_general,
++	},
++
++	/* MXIC MX35LF2G14AC 2GBit */
++	{
++		.name      = "MX35LF2G14AC",
++		.id        = {0xc2, 0x20},
++		.id_len    = 2,
++		.chipsize  = _256M,
++		.erasesize = _128K,
++		.pagesize  = _2K,
++		.oobsize   = 64,
++		.badblock_pos = BBP_FIRST_PAGE,
++		.read      = {
++			&READ_STD(1, INFINITE, 24),
++			&READ_FAST(1, INFINITE, 104),
++			&READ_QUAD(1, INFINITE, 104),
++			0
++		},
++		.write     = {
++			&WRITE_STD(0, 256, 24),
++			&WRITE_QUAD(0, 256, 104),
++			0
++		},
++		.erase     = {
++			&ERASE_SECTOR_128K(0, _128K, 24),
++			0
++		},
++		.driver    = &spi_driver_general,
++	},
++
++	/* Paragon PN26G01AWSIUG 1Gbit 1.8V */
++	{
++		.name      = "PN26G01AW",
++		.id        = {0xa1, 0xc1},
++		.id_len    = 2,
++		.chipsize  = _128M,
++		.erasesize = _128K,
++		.pagesize  = _2K,
++		.oobsize   = 128,
++		.badblock_pos = BBP_FIRST_PAGE,
++		.read      = {
++			&READ_STD(1, INFINITE, 24),
++			&READ_FAST(1, INFINITE, 75),
++			&READ_DUAL(1, INFINITE, 75),
++			&READ_DUAL_ADDR(1, INFINITE, 75),
++			&READ_QUAD(1, INFINITE, 75),
++			&READ_QUAD_ADDR(1, INFINITE, 75),
++			0
++		},
++		.write     = {
++			&WRITE_STD(0, 256, 24),
++			&WRITE_QUAD(0, 256, 75),
++			0
++		},
++		.erase     = {
++			&ERASE_SECTOR_128K(0, _128K, 75),
++			0
++		},
++		.driver    = &spi_driver_general,
++	},
++
++	/* Paragon PN26G01A 1Gbit */
++	{
++		.name      = "PN26G01A",
++		.id        = {0xa1, 0xe1},
++		.id_len    = 2,
++		.chipsize  = _128M,
++		.erasesize = _128K,
++		.pagesize  = _2K,
++		.oobsize   = 128,
++		.badblock_pos = BBP_FIRST_PAGE,
++		.read      = {
++			&READ_STD(1, INFINITE, 24),
++			&READ_FAST(1, INFINITE, 108),
++			&READ_DUAL(1, INFINITE, 108),
++			&READ_DUAL_ADDR(1, INFINITE, 108),
++			&READ_QUAD(1, INFINITE, 108),
++			&READ_QUAD_ADDR(1, INFINITE, 108),
++			0
++		},
++		.write     = {
++			&WRITE_STD(0, 256, 24),
++			&WRITE_QUAD(0, 256, 108),
++			0
++		},
++		.erase     = {
++			&ERASE_SECTOR_128K(0, _128K, 24),
++			0
++		},
++		.driver    = &spi_driver_general,
++	},
++
++	/* Paragon PN26G02A 2Gbit */
++	{
++		.name      = "PN26G02A",
++		.id        = {0xa1, 0xe2},
++		.id_len    = 2,
++		.chipsize  = _256M,
++		.erasesize = _128K,
++		.pagesize  = _2K,
++		.oobsize   = 128,
++		.badblock_pos = BBP_FIRST_PAGE,
++		.read      = {
++			&READ_STD(1, INFINITE, 24),
++			&READ_FAST(1, INFINITE, 108),
++			&READ_DUAL(1, INFINITE, 108),
++			&READ_DUAL_ADDR(1, INFINITE, 108),
++			&READ_QUAD(1, INFINITE, 108),
++			&READ_QUAD_ADDR(1, INFINITE, 108),
++			0
++		},
++		.write     = {
++			&WRITE_STD(0, 256, 24),
++			&WRITE_QUAD(0, 256, 108),
++			0
++		},
++		.erase     = {
++			&ERASE_SECTOR_128K(0, _128K, 24),
++			0
++		},
++		.driver    = &spi_driver_general,
++	},
++
++	/* All-flash AFS1GQ4UAC 1Gbit */
++	{
++		.name      = "AFS1GQ4UAC",
++		.id        = {0xc1, 0x51},
++		.id_len    = 2,
++		.chipsize  = _128M,
++		.erasesize = _128K,
++		.pagesize  = _2K,
++		.oobsize   = 128,
++		.badblock_pos = BBP_FIRST_PAGE,
++		.read      = {
++			&READ_STD(1, INFINITE, 24),
++			&READ_FAST(1, INFINITE, 80),
++			&READ_DUAL(1, INFINITE, 80),
++			&READ_DUAL_ADDR(1, INFINITE, 80),
++			&READ_QUAD(1, INFINITE, 80),
++			&READ_QUAD_ADDR(1, INFINITE, 80),
++			0
++		},
++		.write     = {
++			&WRITE_STD(0, 256, 24),
++			&WRITE_QUAD(0, 256, 80),
++			0
++		},
++		.erase     = {
++			&ERASE_SECTOR_128K(0, _128K, 24),
++			0
++		},
++		.driver    = &spi_driver_general,
++	},
++
++	/* All-flash AFS2GQ4UAD 2Gbit */
++	{
++		.name      = "AFS2GQ4UAD",
++		.id        = {0xc1, 0x52},
++		.id_len    = 2,
++		.chipsize  = _256M,
++		.erasesize = _128K,
++		.pagesize  = _2K,
++		.oobsize   = 128,
++		.badblock_pos = BBP_FIRST_PAGE,
++		.read      = {
++			&READ_STD(1, INFINITE, 24),
++			&READ_FAST(1, INFINITE, 80),
++			&READ_DUAL(1, INFINITE, 80),
++			&READ_DUAL_ADDR(1, INFINITE, 80),
++			&READ_QUAD(1, INFINITE, 80),
++			&READ_QUAD_ADDR(1, INFINITE, 80),
++			0
++		},
++		.write     = {
++			&WRITE_STD(0, 256, 24),
++			&WRITE_QUAD(0, 256, 80),
++			0
++		},
++		.erase     = {
++			&ERASE_SECTOR_128K(0, _128K, 24),
++			0
++		},
++		.driver    = &spi_driver_general,
++	},
++
++	/* TOSHIBA TC58CVG0S3H 1Gbit */
++	{
++		.name      = "TC58CVG0S3H",
++		.id        = {0x98, 0xc2},
++		.id_len    = 2,
++		.chipsize  = _128M,
++		.erasesize = _128K,
++		.pagesize  = _2K,
++		.oobsize   = 128,
++		.badblock_pos = BBP_FIRST_PAGE,
++		.read      = {
++			&READ_STD(1, INFINITE, 24),
++			&READ_FAST(1, INFINITE, 104),
++			&READ_DUAL(1, INFINITE, 104),
++			&READ_QUAD(1, INFINITE, 104),
++			0
++		},
++		.write     = {
++			&WRITE_STD(0, 256, 104),
++			0
++		},
++		.erase     = {
++			&ERASE_SECTOR_128K(0, _128K, 104),
++			0
++		},
++		.driver    = &spi_driver_no_qe,
++	},
++
++	/* TOSHIBA TC58CYG0S3H 1.8V 1Gbit */
++	{
++		.name      = "TC58CYG0S3H",
++		.id        = {0x98, 0xb2},
++		.id_len    = 2,
++		.chipsize  = _128M,
++		.erasesize = _128K,
++		.pagesize  = _2K,
++		.oobsize   = 128,
++		.badblock_pos = BBP_FIRST_PAGE,
++		.read      = {
++			&READ_STD(1, INFINITE, 24),
++			&READ_FAST(1, INFINITE, 75),
++			&READ_DUAL(1, INFINITE, 75),
++			&READ_QUAD(1, INFINITE, 75),
++			0
++		},
++		.write     = {
++			&WRITE_STD(0, 256, 75),
++			0
++		},
++		.erase     = {
++			&ERASE_SECTOR_128K(0, _128K, 75),
++			0
++		},
++		.driver    = &spi_driver_no_qe,
++	},
++
++	/* TOSHIBA TC58CVG1S3H 2Gbit */
++	{
++		.name      = "TC58CVG1S3H",
++		.id        = {0x98, 0xcb},
++		.id_len    = 2,
++		.chipsize  = _256M,
++		.erasesize = _128K,
++		.pagesize  = _2K,
++		.oobsize   = 128,
++		.badblock_pos = BBP_FIRST_PAGE,
++		.read      = {
++			&READ_STD(1, INFINITE, 24),
++			&READ_FAST(1, INFINITE, 104),
++			&READ_DUAL(1, INFINITE, 104),
++			&READ_QUAD(1, INFINITE, 104),
++			0
++		},
++		.write     = {
++			&WRITE_STD(0, 256, 104),
++			0
++		},
++		.erase     = {
++			&ERASE_SECTOR_128K(0, _128K, 104),
++			0
++		},
++		.driver    = &spi_driver_no_qe,
++	},
++
++	/* TOSHIBA TC58CYG1S3H 1.8V 2Gbit */
++	{
++		.name      = "TC58CYG1S3H",
++		.id        = {0x98, 0xbb},
++		.id_len    = 2,
++		.chipsize  = _256M,
++		.erasesize = _128K,
++		.pagesize  = _2K,
++		.oobsize   = 128,
++		.badblock_pos = BBP_FIRST_PAGE,
++		.read      = {
++			&READ_STD(1, INFINITE, 24),
++			&READ_FAST(1, INFINITE, 75),
++			&READ_DUAL(1, INFINITE, 75),
++			&READ_QUAD(1, INFINITE, 75),
++			0
++		},
++		.write     = {
++			&WRITE_STD(0, 256, 75),
++			0
++		},
++		.erase     = {
++			&ERASE_SECTOR_128K(0, _128K, 75),
++			0
++		},
++		.driver    = &spi_driver_no_qe,
++	},
++
++	/* TOSHIBA TC58CVG2S0H 4Gbit */
++	{
++		.name      = "TC58CVG2S0H",
++		.id        = {0x98, 0xcd},
++		.id_len    = 2,
++		.chipsize  = _512M,
++		.erasesize = _256K,
++		.pagesize  = _4K,
++		.oobsize   = 256,
++		.badblock_pos = BBP_FIRST_PAGE,
++		.read      = {
++			&READ_STD(1, INFINITE, 24),
++			&READ_FAST(1, INFINITE, 104),
++			&READ_DUAL(1, INFINITE, 104),
++			&READ_QUAD(1, INFINITE, 104),
++			0
++		},
++		.write     = {
++			&WRITE_STD(0, 256, 104),
++			0
++		},
++		.erase     = {
++			&ERASE_SECTOR_256K(0, _256K, 104),
++			0
++		},
++		.driver    = &spi_driver_no_qe,
++	},
++
++	/* TOSHIBA TC58CYG2S0H 1.8V 4Gbit */
++	{
++		.name      = "TC58CYG2S0H",
++		.id        = {0x98, 0xbd},
++		.id_len    = 2,
++		.chipsize  = _512M,
++		.erasesize = _256K,
++		.pagesize  = _4K,
++		.oobsize   = 256,
++		.badblock_pos = BBP_FIRST_PAGE,
++		.read      = {
++			&READ_STD(1, INFINITE, 24),
++			&READ_FAST(1, INFINITE, 75),
++			&READ_DUAL(1, INFINITE, 75),
++			&READ_QUAD(1, INFINITE, 75),
++			0
++		},
++		.write     = {
++			&WRITE_STD(0, 256, 75),
++			0
++		},
++		.erase     = {
++			&ERASE_SECTOR_256K(0, _256K, 75),
++			0
++		},
++		.driver    = &spi_driver_no_qe,
++	},
++
++	/* HeYangTek HYF1GQ4UAACAE 1Gbit */
++	{
++		.name      = "HYF1GQ4UAACAE",
++		.id        = {0xc9, 0x51},
++		.id_len    = 2,
++		.chipsize  = _128M,
++		.erasesize = _128K,
++		.pagesize  = _2K,
++		.oobsize   = 128,
++		.badblock_pos = BBP_FIRST_PAGE,
++		.read      = {
++			&READ_STD(1, INFINITE, 24),
++			&READ_FAST(1, INFINITE, 80),
++			&READ_DUAL(1, INFINITE, 80),
++			&READ_DUAL_ADDR(1, INFINITE, 80),
++			&READ_QUAD(1, INFINITE, 80),
++			&READ_QUAD_ADDR(1, INFINITE, 80),
++			0
++		},
++		.write     = {
++			&WRITE_STD(0, 256, 80),
++			&WRITE_QUAD(0, 256, 80),
++			0
++		},
++		.erase     = {
++			&ERASE_SECTOR_128K(0, _128K, 80),
++			0
++		},
++		.driver    = &spi_driver_general,
++	},
++
++	/* HeYangTek HYF2GQ4UAACAE 2Gbit */
++	{
++		.name      = "HYF2GQ4UAACAE",
++		.id        = {0xc9, 0x52},
++		.id_len    = 2,
++		.chipsize  = _256M,
++		.erasesize = _128K,
++		.pagesize  = _2K,
++		.oobsize   = 128,
++		.badblock_pos = BBP_FIRST_PAGE,
++		.read      = {
++			&READ_STD(1, INFINITE, 24),
++			&READ_FAST(1, INFINITE, 80),
++			&READ_DUAL(1, INFINITE, 80),
++			&READ_DUAL_ADDR(1, INFINITE, 80),
++			&READ_QUAD(1, INFINITE, 80),
++			&READ_QUAD_ADDR(1, INFINITE, 80),
++			0
++		},
++		.write     = {
++			&WRITE_STD(0, 256, 80),
++			&WRITE_QUAD(0, 256, 80),
++			0
++		},
++		.erase     = {
++			&ERASE_SECTOR_128K(0, _128K, 80),
++			0
++		},
++		.driver    = &spi_driver_general,
++	},
++
++	/* HeYangTek HYF4GQ4UAACBE 4Gbit */
++	{
++		.name      = "HYF4GQ4UAACBE",
++		.id        = {0xc9, 0xd4},
++		.id_len    = 2,
++		.chipsize  = _512M,
++		.erasesize = _256K,
++		.pagesize  = _4K,
++		.oobsize   = 256,
++		.badblock_pos = BBP_FIRST_PAGE,
++		.read      = {
++			&READ_STD(1, INFINITE, 24),
++			&READ_FAST(1, INFINITE, 80),
++			&READ_DUAL(1, INFINITE, 80),
++			&READ_DUAL_ADDR(1, INFINITE, 80),
++			&READ_QUAD(1, INFINITE, 80),
++			&READ_QUAD_ADDR(1, INFINITE, 80),
++			0
++		},
++		.write     = {
++			&WRITE_STD(0, 256, 80),
++			&WRITE_QUAD(0, 256, 80),
++			0
++		},
++		.erase     = {
++			&ERASE_SECTOR_256K(0, _256K, 80),
++			0
++		},
++		.driver    = &spi_driver_general,
++	},
++
++	{	.id_len    = 0,	},
++};
++
++/*****************************************************************************/
++static void hifmc100_spi_nand_search_rw(struct spi_nand_info *spiinfo,
++	struct spi_op *spiop_rw, u_int iftype, u_int max_dummy, int rw_type)
++{
++	int ix = 0;
++	struct spi_op **spiop, **fitspiop;
++
++	for (fitspiop = spiop = (rw_type ? spiinfo->write : spiinfo->read);
++		(*spiop) && ix < MAX_SPI_OP; spiop++, ix++) {
++		if (((*spiop)->iftype & iftype)
++			&& ((*spiop)->dummy <= max_dummy)
++			&& (*fitspiop)->iftype < (*spiop)->iftype)
++			fitspiop = spiop;
++	}
++	memcpy(spiop_rw, (*fitspiop), sizeof(struct spi_op));
++}
++
++/*****************************************************************************/
++static void hifmc100_spi_nand_get_erase(struct spi_nand_info *spiinfo,
++		struct spi_op *spiop_erase)
++{
++	int ix;
++
++	spiop_erase->size = 0;
++	for (ix = 0; ix < MAX_SPI_OP; ix++) {
++		if (spiinfo->erase[ix] == NULL)
++			break;
++		if (spiinfo->erasesize == spiinfo->erase[ix]->size) {
++			memcpy(&spiop_erase[ix], spiinfo->erase[ix],
++					sizeof(struct spi_op));
++			break;
++		}
++	}
++}
++
++/*****************************************************************************/
++static void hifmc100_map_spi_op(struct hifmc_spi *spi)
++{
++	unsigned char ix;
++	const int iftype_read[] = {
++		SPI_IF_READ_STD,	IF_TYPE_STD,
++		SPI_IF_READ_FAST,	IF_TYPE_STD,
++		SPI_IF_READ_DUAL,	IF_TYPE_DUAL,
++		SPI_IF_READ_DUAL_ADDR,	IF_TYPE_DIO,
++		SPI_IF_READ_QUAD,	IF_TYPE_QUAD,
++		SPI_IF_READ_QUAD_ADDR,	IF_TYPE_QIO,
++		0,			0,
++	};
++	const int iftype_write[] = {
++		SPI_IF_WRITE_STD,	IF_TYPE_STD,
++		SPI_IF_WRITE_QUAD,	IF_TYPE_QUAD,
++		0,			0,
++	};
++	const char *if_str[] = {"STD", "DUAL", "DIO", "QUAD", "QIO"};
++
++	FMC_PR(BT_DBG, "\t||*-Start Get SPI operation iftype\n");
++
++	for (ix = 0; iftype_write[ix]; ix += 2) {
++		if (spi->write->iftype == iftype_write[ix]) {
++			spi->write->iftype = iftype_write[ix + 1];
++			break;
++		}
++	}
++	FMC_PR(BT_DBG, "\t|||-Get best write iftype: %s \n",
++		if_str[spi->write->iftype]);
++
++	for (ix = 0; iftype_read[ix]; ix += 2) {
++		if (spi->read->iftype == iftype_read[ix]) {
++			spi->read->iftype = iftype_read[ix + 1];
++			break;
++		}
++	}
++	FMC_PR(BT_DBG, "\t|||-Get best read iftype: %s \n",
++		if_str[spi->read->iftype]);
++
++	spi->erase->iftype = IF_TYPE_STD;
++	FMC_PR(BT_DBG, "\t|||-Get best erase iftype: %s \n",
++		if_str[spi->erase->iftype]);
++
++	FMC_PR(BT_DBG, "\t||*-End Get SPI operation iftype \n");
++}
++
++/*****************************************************************************/
++static void hifmc100_spi_ids_probe(struct mtd_info *mtd,
++				struct spi_nand_info *spi_dev)
++{
++	unsigned int reg;
++	struct nand_chip *chip = mtd->priv;
++	struct hifmc_host *host = chip->priv;
++	struct hifmc_spi *spi = host->spi;
++
++	FMC_PR(BT_DBG, "\t|*-Start match SPI operation & chip init\n");
++
++	spi->host = host;
++	spi->name = spi_dev->name;
++	spi->driver = spi_dev->driver;
++
++	hifmc100_spi_nand_search_rw(spi_dev, spi->read,
++			HIFMC_SPI_NAND_SUPPORT_READ,
++			HIFMC_SPI_NAND_SUPPORT_MAX_DUMMY, RW_OP_READ);
++	FMC_PR(BT_DBG, "\t||-Save spi->read op cmd:%#x\n", spi->read->cmd);
++
++	hifmc100_spi_nand_search_rw(spi_dev, spi->write,
++			HIFMC_SPI_NAND_SUPPORT_WRITE,
++			HIFMC_SPI_NAND_SUPPORT_MAX_DUMMY, RW_OP_WRITE);
++	FMC_PR(BT_DBG, "\t||-Save spi->write op cmd:%#x\n", spi->write->cmd);
++
++	hifmc100_spi_nand_get_erase(spi_dev, spi->erase);
++	FMC_PR(BT_DBG, "\t||-Save spi->erase op cmd:%#x\n", spi->erase->cmd);
++
++	hifmc100_map_spi_op(spi);
++
++	spi->driver->qe_enable(spi);
++
++	/* Disable write protection */
++	reg = spi_nand_feature_op(spi, GET_OP, PROTECT_ADDR, 0);
++	FMC_PR(BT_DBG, "\t||-Get protect status[%#x]: %#x\n", PROTECT_ADDR,
++			reg);
++	if (ANY_BP_ENABLE(reg)) {
++		reg &= ~ALL_BP_MASK;
++		spi_nand_feature_op(spi, SET_OP, PROTECT_ADDR, reg);
++		FMC_PR(BT_DBG, "\t||-Set [%#x]FT %#x\n", PROTECT_ADDR, reg);
++
++		spi->driver->wait_ready(spi);
++
++		reg = spi_nand_feature_op(spi, GET_OP, PROTECT_ADDR, 0);
++		FMC_PR(BT_DBG, "\t||-Check BP disable result: %#x\n", reg);
++		if (ANY_BP_ENABLE(reg))
++			DB_MSG("Error: Write protection disable failed!\n");
++	}
++
++	/* Disable chip internal ECC */
++	reg = spi_nand_feature_op(spi, GET_OP, FEATURE_ADDR, 0);
++	FMC_PR(BT_DBG, "\t||-Get feature status[%#x]: %#x\n", FEATURE_ADDR,
++			reg);
++	if (reg & FEATURE_ECC_ENABLE) {
++		reg &= ~FEATURE_ECC_ENABLE;
++		spi_nand_feature_op(spi, SET_OP, FEATURE_ADDR, reg);
++		FMC_PR(BT_DBG, "\t||-Set [%#x]FT: %#x\n", FEATURE_ADDR, reg);
++
++		spi->driver->wait_ready(spi);
++
++		reg = spi_nand_feature_op(spi, GET_OP, FEATURE_ADDR, 0);
++		FMC_PR(BT_DBG, "\t||-Check internal ECC disable result: %#x\n",
++				reg);
++		if (reg & FEATURE_ECC_ENABLE)
++			DB_MSG("Error: Chip internal ECC disable failed!\n");
++	}
++
++	hifmc_cs_user[host->cmd_op.cs]++;
++
++	FMC_PR(BT_DBG, "\t|*-End match SPI operation & chip init\n");
++}
++
++static struct nand_flash_dev spi_nand_dev;
++/*****************************************************************************/
++static struct nand_flash_dev *spi_nand_get_flash_info(struct mtd_info *mtd,
++		unsigned char *id)
++{
++	unsigned char ix, len = 0;
++	char buffer[100];
++	struct nand_chip *chip = mtd->priv;
++	struct hifmc_host *host = chip->priv;
++	struct spi_nand_info *spi_dev = hifmc_spi_nand_flash_table;
++	struct nand_flash_dev *type = &spi_nand_dev;
++
++	FMC_PR(BT_DBG, "\t*-Start find SPI Nand flash\n");
++
++	len = sprintf(buffer, "SPI Nand(cs %d) ID: %#x %#x",
++			host->cmd_op.cs, id[0], id[1]);
++
++	for (; spi_dev->id_len; spi_dev++) {
++		if (memcmp(id, spi_dev->id, spi_dev->id_len))
++			continue;
++
++		for (ix = 2; ix < spi_dev->id_len; ix++)
++			len += sprintf(buffer + len, " %#x", id[ix]);
++		pr_info("%s\n", buffer);
++
++		FMC_PR(BT_DBG, "\t||-CS(%d) found SPI Nand: %s\n",
++				host->cmd_op.cs, spi_dev->name);
++
++		type->name = spi_dev->name;
++		memcpy(type->id, spi_dev->id, spi_dev->id_len);
++		type->pagesize = spi_dev->pagesize;
++		type->chipsize = spi_dev->chipsize >> 20;
++		type->erasesize = spi_dev->erasesize;
++		type->id_len = spi_dev->id_len;
++		type->oobsize = spi_dev->oobsize;
++		FMC_PR(BT_DBG, "\t|-Save struct nand_flash_dev info\n");
++
++		mtd->size = spi_dev->chipsize;
++
++		hifmc100_spi_ids_probe(mtd, spi_dev);
++
++		FMC_PR(BT_DBG, "\t*-Found SPI nand: %s\n", spi_dev->name);
++
++		return type;
++	}
++
++	FMC_PR(BT_DBG, "\t*-Not found SPI nand flash, %s\n", buffer);
++
++	return NULL;
++}
++
++/*****************************************************************************/
++void hifmc_spi_nand_ids_register(void)
++{
++	pr_info("SPI Nand ID Table Version %s\n", SPI_NAND_ID_TAB_VER);
++	get_spi_nand_flash_type_hook = spi_nand_get_flash_info;
++}
++
++#ifdef CONFIG_PM
++/*****************************************************************************/
++void hifmc100_spi_nand_config(struct hifmc_host *host)
++{
++	unsigned int reg;
++	struct hifmc_spi *spi = host->spi;
++	static const char const *str[] = {"STD", "DUAL", "DIO", "QUAD", "QIO"};
++
++	/* judge whether support QUAD read/write or not, set it if yes */
++	FMC_PR(PM_DBG, "\t|-SPI read iftype: %s write iftype: %s\n",
++		str[spi->read->iftype], str[spi->write->iftype]);
++	spi->driver->qe_enable(spi);
++
++	/* Disable write protection */
++	reg = spi_nand_feature_op(spi, GET_OP, PROTECT_ADDR, 0);
++	FMC_PR(PM_DBG, "\t|-Get protect status[%#x]: %#x\n", PROTECT_ADDR,
++			reg);
++	if (ANY_BP_ENABLE(reg)) {
++		reg &= ~ALL_BP_MASK;
++		spi_nand_feature_op(spi, SET_OP, PROTECT_ADDR, reg);
++		FMC_PR(PM_DBG, "\t|-Set [%#x]FT %#x\n", PROTECT_ADDR, reg);
++
++		spi->driver->wait_ready(spi);
++
++		reg = spi_nand_feature_op(spi, GET_OP, PROTECT_ADDR, 0);
++		FMC_PR(PM_DBG, "\t|-Check BP disable result: %#x\n", reg);
++		if (ANY_BP_ENABLE(reg))
++			DB_MSG("Error: Write protection disable failed!\n");
++	}
++
++	/* Disable chip internal ECC */
++	reg = spi_nand_feature_op(spi, GET_OP, FEATURE_ADDR, 0);
++	FMC_PR(PM_DBG, "\t|-Get feature status[%#x]: %#x\n", FEATURE_ADDR,
++			reg);
++	if (reg & FEATURE_ECC_ENABLE) {
++		reg &= ~FEATURE_ECC_ENABLE;
++		spi_nand_feature_op(spi, SET_OP, FEATURE_ADDR, reg);
++		FMC_PR(PM_DBG, "\t|-Set [%#x]FT: %#x\n", FEATURE_ADDR, reg);
++
++		spi->driver->wait_ready(spi);
++
++		reg = spi_nand_feature_op(spi, GET_OP, FEATURE_ADDR, 0);
++		FMC_PR(PM_DBG, "\t|-Check internal ECC disable result: %#x\n",
++				reg);
++		if (reg & FEATURE_ECC_ENABLE)
++			DB_MSG("Error: Chip internal ECC disable failed!\n");
++	}
++}
++/*****************************************************************************/
++#endif /* CONFIG_PM */
+diff --git a/drivers/mtd/nand/hifmc100_nand/Kconfig b/drivers/mtd/nand/hifmc100_nand/Kconfig
+new file mode 100644
+index 0000000..976db6a
+--- /dev/null
++++ b/drivers/mtd/nand/hifmc100_nand/Kconfig
+@@ -0,0 +1,104 @@
++#
++# drivers/mtd/nand/hifmc100_nand/Kconfig
++# add by hisilicon 2015.5.7
++#
++
++menuconfig HIFMC100_NAND
++	tristate "Hisilicon Flash Memory Controller v100 Nand device Support"
++	depends on HIFMC
++	depends on MTD_NAND
++	default n if ARCH_HI3519
++	default n if ARCH_HI3519V101
++	default n if ARCH_HI3559
++	default n if ARCH_HI3556
++	select MISC_FILESYSTEMS
++	select MTD_BLOCK
++	help
++	  Hisilicon Flash Memory Controller device version 100 driver Support
++	  Hisilicon Flash Memory Controller version 100 is called hifmc100 for
++	  short. The controller support DMA transfers while reading or writing
++	  the Nand flash.
++
++if HIFMC100_NAND
++
++config HIFMC100_MAX_NAND_CHIP
++	int "number of Nand flash chip (1, 2)"
++	default 1 if ARCH_HI3519
++	default 1 if ARCH_HI3519V101
++	default 1 if ARCH_HI3559
++	default 1 if ARCH_HI3556
++	help
++	  flash memory controller v100 device only support 1 or 2 Nand flash
++	  chip, your should not config other value.
++
++config HIFMC100_NAND_EDO_MODE
++	bool "the Extended Data Out(EDO) mode"
++	help
++	  In Extended data out (EDO), a new data cycle is started while the data
++	  output of the previous cycle is still active. This process of cycle
++	  overlapping, called pipelining, increases processing speed by about
++	  10 nanoseconds per cycle,increasing computer performance by about 5
++	  percent compared to performance using FMP.
++
++config RW_H_WIDTH
++	int "the width of Read/Write HIGH Hold Time (0 to 15)"
++	range 0 15
++	default 10 if ARCH_HI3519
++	default 10 if ARCH_HI3519V101
++	default 10 if ARCH_HI3559
++	default 10 if ARCH_HI3556
++	help
++	  the Read/Write HIGH Hold Time of nand flash
++
++config R_L_WIDTH
++	int "the Read pulse width (0 to 15)"
++	range 0 15
++	default 10 if ARCH_HI3519
++	default 10 if ARCH_HI3519V101
++	default 10 if ARCH_HI3559
++	default 10 if ARCH_HI3556
++	help
++	  the Read/Write LOW Hold Time of nand flash
++
++config W_L_WIDTH
++	int "the Write pulse width (0 to 15)"
++	range 0 15
++	default 10 if ARCH_HI3519
++	default 10 if ARCH_HI3519V101
++	default 10 if ARCH_HI3559
++	default 10 if ARCH_HI3556
++	help
++	  the Read/Write LOW Hold Time of nand flash
++
++choice
++	prompt "Page Size and Ecc Type Select"
++	default HIFMC100_NAND_AUTO_PAGESIZE_ECC if ARCH_HI3519
++	default HIFMC100_NAND_AUTO_PAGESIZE_ECC if ARCH_HI3519V101
++	default HIFMC100_NAND_AUTO_PAGESIZE_ECC if ARCH_HI3559
++	default HIFMC100_NAND_AUTO_PAGESIZE_ECC if ARCH_HI3556
++
++config HIFMC100_NAND_HARDWARE_PAGESIZE_ECC
++	bool "Hardware"
++	help
++	  the configure of page size and ecc type lie on switch on the board.
++	  so the page size and ecc type is controlled by Hardware see demo
++	  board of SOC.
++
++config HIFMC100_NAND_AUTO_PAGESIZE_ECC
++	bool "Auto"
++	help
++	  auto-sensed the page size and ecc type value. driver will try each of
++	  page size and ecc type one by one till flash can be read and wrote
++	  accurately. so the page size and ecc type is match adaptively without
++	  switch on the board
++
++config HIFMC100_NAND_PAGESIZE_AUTO_ECC_NONE
++	bool "Pagesize Auto, Ecc None"
++	help
++	  auto-sensed the page size and select ecc none. driver will try each
++	  of page size one by one till flash can be read and wrote accurately.
++	  so the page size is match adaptively without switch on the board
++
++endchoice
++
++endif # End of HIFMC100_NAND
+diff --git a/drivers/mtd/nand/hifmc100_nand/Makefile b/drivers/mtd/nand/hifmc100_nand/Makefile
+new file mode 100644
+index 0000000..b046e8d
+--- /dev/null
++++ b/drivers/mtd/nand/hifmc100_nand/Makefile
+@@ -0,0 +1,26 @@
++#
++# The Flash Memory Controller v100 Device Driver for hisilicon
++#
++# Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++#
++# 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, see <http://www.gnu.org/licenses/>.
++#
++#
++
++#
++# drivers/mtd/nand/hifmc100_nand/Makefile
++#
++
++obj-$(CONFIG_HIFMC_NAND)	+= hifmc_nand_spl_ids.o
++obj-$(CONFIG_HIFMC_NAND)	+= hifmc100_nand.o hifmc100_nand_os.o
+diff --git a/drivers/mtd/nand/hifmc100_nand/hifmc100_nand.c b/drivers/mtd/nand/hifmc100_nand/hifmc100_nand.c
+new file mode 100644
+index 0000000..d4fa8fe
+--- /dev/null
++++ b/drivers/mtd/nand/hifmc100_nand/hifmc100_nand.c
+@@ -0,0 +1,1102 @@
++/*
++ * The Flash Memory Controller v100 Device Driver for hisilicon
++ *
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++ 
++#include <linux/io.h>
++#include <linux/compiler.h>
++#include <linux/delay.h>
++#include <linux/printk.h>
++#include <linux/clk.h>
++#include <linux/mfd/hisi_fmc.h>
++
++#include "../hinfc_gen.h"
++#include "hifmc100_nand_os.h"
++#include "hifmc100_nand.h"
++
++#include <mach/platform.h>
++/*****************************************************************************/
++static void hifmc100_dma_transfer(struct hifmc_host *host, int todev)
++{
++	unsigned int reg = (unsigned int)host->dma_buffer;
++	char *op = todev ? "write" : "read";
++
++	FMC_PR(DMA_DB, "\t\t *-Start %s page dma transfer\n", op);
++
++	hifmc_writel(host, FMC_DMA_SADDR_D0, reg);
++	FMC_PR(DMA_DB, "\t\t |-Set ADDR0[%#x]%#x\n", FMC_DMA_SADDR_D0, reg);
++
++	reg += FMC_DMA_ADDR_OFFSET;
++	hifmc_writel(host, FMC_DMA_SADDR_D1, reg);
++	FMC_PR(DMA_DB, "\t\t |-Set ADDR1[%#x]%#x\n", FMC_DMA_SADDR_D1, reg);
++
++	reg += FMC_DMA_ADDR_OFFSET;
++	hifmc_writel(host, FMC_DMA_SADDR_D2, reg);
++	FMC_PR(DMA_DB, "\t\t |-Set ADDR2[%#x]%#x\n", FMC_DMA_SADDR_D2, reg);
++
++	reg += FMC_DMA_ADDR_OFFSET;
++	hifmc_writel(host, FMC_DMA_SADDR_D3, reg);
++	FMC_PR(DMA_DB, "\t\t |-Set ADDR3[%#x]%#x\n", FMC_DMA_SADDR_D3, reg);
++
++	reg = host->dma_oob;
++	hifmc_writel(host, FMC_DMA_SADDR_OOB, reg);
++	FMC_PR(DMA_DB, "\t\t |-Set OOB[%#x]%#x\n", FMC_DMA_SADDR_OOB, reg);
++
++	if (host->ecctype == NAND_ECC_0BIT) {
++		hifmc_writel(host, FMC_DMA_LEN, FMC_DMA_LEN_SET(host->oobsize));
++		FMC_PR(DMA_DB, "\t\t |-Set LEN[%#x]%#x\n", FMC_DMA_LEN, reg);
++	}
++	reg = FMC_OP_READ_DATA_EN | FMC_OP_WRITE_DATA_EN;
++	hifmc_writel(host, FMC_OP, reg);
++	FMC_PR(DMA_DB, "\t\t |-Set OP[%#x]%#x\n", FMC_OP, reg);
++
++	reg = FMC_DMA_AHB_CTRL_DMA_PP_EN
++		| FMC_DMA_AHB_CTRL_BURST16_EN
++		| FMC_DMA_AHB_CTRL_BURST8_EN
++		| FMC_DMA_AHB_CTRL_BURST4_EN;
++	hifmc_writel(host, FMC_DMA_AHB_CTRL, reg);
++	FMC_PR(DMA_DB, "\t\t |-Set AHBCTRL[%#x]%#x\n", FMC_DMA_AHB_CTRL, reg);
++
++	reg = OP_CFG_FM_CS(host->cmd_op.cs)
++		| OP_CFG_ADDR_NUM(host->addr_cycle);
++	hifmc_writel(host, FMC_OP_CFG, reg);
++	FMC_PR(DMA_DB, "\t\t |-Set OP_CFG[%#x]%#x\n", FMC_OP_CFG, reg);
++
++	reg = OP_CTRL_DMA_OP_READY;
++	if (todev)
++		reg |= OP_CTRL_RW_OP(todev);
++	hifmc_writel(host, FMC_OP_CTRL, reg);
++	FMC_PR(DMA_DB, "\t\t |-Set OP_CTRL[%#x]%#x\n", FMC_OP_CTRL, reg);
++
++	FMC_DMA_WAIT_CPU_FINISH(host);
++
++	FMC_PR(DMA_DB, "\t\t *-End %s page dma transfer\n", op);
++
++	return;
++}
++
++/*****************************************************************************/
++static void hifmc100_send_cmd_write(struct hifmc_host *host)
++{
++	unsigned int reg;
++
++	FMC_PR(WR_DBG, "\t|*-Start send page programme cmd\n");
++
++	if (*host->bbm != 0xFF && *host->bbm != 0x00)
++		pr_info("WARNING: attempt to write an invalid bbm. " \
++				"page: 0x%08x, mark: 0x%02x,\n",
++				GET_PAGE_INDEX(host), *host->bbm);
++
++	host->enable_ecc_randomizer(host, ENABLE, ENABLE);
++
++	reg = host->addr_value[1];
++	hifmc_writel(host, FMC_ADDRH, reg);
++	FMC_PR(WR_DBG, "\t||-Set ADDRH[%#x]%#x\n", FMC_ADDRH, reg);
++
++	reg = host->addr_value[0] & 0xffff0000;
++	hifmc_writel(host, FMC_ADDRL, reg);
++	FMC_PR(WR_DBG, "\t||-Set ADDRL[%#x]%#x\n", FMC_ADDRL, reg);
++
++	reg = FMC_CMD_CMD2(NAND_CMD_PAGEPROG) | FMC_CMD_CMD1(NAND_CMD_SEQIN);
++	hifmc_writel(host, FMC_CMD, reg);
++	FMC_PR(WR_DBG, "\t||-Set CMD[%#x]%#x\n", FMC_CMD, reg);
++
++	*host->epm = 0x0000;
++
++	hifmc100_dma_transfer(host, RW_OP_WRITE);
++
++	FMC_PR(WR_DBG, "\t|*-End send page read cmd\n");
++}
++
++/*****************************************************************************/
++static void hifmc100_send_cmd_read(struct hifmc_host *host)
++{
++	unsigned int reg;
++
++	FMC_PR(RD_DBG, "\t*-Start send page read cmd\n");
++
++	if ((host->addr_value[0] == host->cache_addr_value[0])
++		&& (host->addr_value[1] == host->cache_addr_value[1])) {
++		FMC_PR(RD_DBG, "\t*-Cache hit! addr1[%#x], addr0[%#x]\n",
++			host->addr_value[1], host->addr_value[0]);
++		return;
++	}
++
++	host->page_status = 0;
++
++	host->enable_ecc_randomizer(host, ENABLE, ENABLE);
++
++	reg = FMC_INT_CLR_ALL;
++	hifmc_writel(host, FMC_INT_CLR, reg);
++	FMC_PR(RD_DBG, "\t|-Set INT_CLR[%#x]%#x\n", FMC_INT_CLR, reg);
++
++	reg = host->nand_cfg;
++	hifmc_writel(host, FMC_CFG, reg);
++	FMC_PR(RD_DBG, "\t|-Set CFG[%#x]%#x\n", FMC_CFG, reg);
++
++	reg = host->addr_value[1];
++	hifmc_writel(host, FMC_ADDRH, reg);
++	FMC_PR(RD_DBG, "\t|-Set ADDRH[%#x]%#x\n", FMC_ADDRH, reg);
++
++	reg = host->addr_value[0] & 0xffff0000;
++	hifmc_writel(host, FMC_ADDRL, reg);
++	FMC_PR(RD_DBG, "\t|-Set ADDRL[%#x]%#x\n", FMC_ADDRL, reg);
++
++	reg = FMC_CMD_CMD2(NAND_CMD_READSTART) | FMC_CMD_CMD1(NAND_CMD_READ0);
++	hifmc_writel(host, FMC_CMD, reg);
++	FMC_PR(RD_DBG, "\t|-Set CMD[%#x]%#x\n", FMC_CMD, reg);
++
++	hifmc100_dma_transfer(host, RW_OP_READ);
++
++	if (hifmc_readl(host, FMC_INT) & FMC_INT_ERR_INVALID)
++		host->page_status |= HIFMC100_PS_UC_ECC;
++
++	host->cache_addr_value[0] = host->addr_value[0];
++	host->cache_addr_value[1] = host->addr_value[1];
++
++	FMC_PR(RD_DBG, "\t*-End send page read cmd\n");
++}
++
++/*****************************************************************************/
++static void hifmc100_send_cmd_erase(struct hifmc_host *host)
++{
++	unsigned int reg;
++
++	FMC_PR(ER_DBG, "\t *-Start send cmd erase\n");
++
++	/* Don't case the read retry config */
++	host->enable_ecc_randomizer(host, DISABLE, DISABLE);
++
++	reg = host->addr_value[0];
++	hifmc_writel(host, FMC_ADDRL, reg);
++	FMC_PR(ER_DBG, "\t |-Set ADDRL[%#x]%#x\n", FMC_ADDRL, reg);
++
++	reg = FMC_CMD_CMD2(NAND_CMD_ERASE2) | FMC_CMD_CMD1(NAND_CMD_ERASE1);
++	hifmc_writel(host, FMC_CMD, reg);
++	FMC_PR(ER_DBG, "\t |-Set CMD[%#x]%#x\n", FMC_CMD, reg);
++
++	reg = OP_CFG_FM_CS(host->cmd_op.cs)
++		| OP_CFG_ADDR_NUM(host->addr_cycle);
++	hifmc_writel(host, FMC_OP_CFG, reg);
++	FMC_PR(ER_DBG, "\t |-Set OP_CFG[%#x]%#x\n", FMC_OP_CFG, reg);
++
++	/* need to config WAIT_READY_EN */
++	reg = FMC_OP_WAIT_READY_EN
++		| FMC_OP_CMD1_EN
++		| FMC_OP_CMD2_EN
++		| FMC_OP_ADDR_EN
++		| FMC_OP_REG_OP_START;
++	hifmc_writel(host, FMC_OP, reg);
++	FMC_PR(ER_DBG, "\t |-Set OP[%#x]%#x\n", FMC_OP, reg);
++
++	FMC_CMD_WAIT_CPU_FINISH(host);
++
++	FMC_PR(ER_DBG, "\t |*-End send cmd erase\n");
++}
++
++/*****************************************************************************/
++static void hifmc100_ecc_randomizer(struct hifmc_host *host, int ecc_en,
++		int randomizer_en)
++{
++	unsigned int old_reg, reg, change = 0;
++	char *ecc_op = ecc_en ? "Quit" : "Enter";
++	char *rand_op = randomizer_en ? "Enable" : "Disable";
++
++	if (IS_NAND_RANDOM(host)) {
++		reg = old_reg = hifmc_readl(host, FMC_GLOBAL_CFG);
++		if (randomizer_en)
++			reg |= FMC_GLOBAL_CFG_RANDOMIZER_EN;
++		else
++			reg &= ~FMC_GLOBAL_CFG_RANDOMIZER_EN;
++
++		if (old_reg != reg) {
++			FMC_PR(EC_DBG, "\t |*-Start %s randomizer\n", rand_op);
++			FMC_PR(EC_DBG, "\t ||-Get global CFG[%#x]%#x\n",
++					FMC_GLOBAL_CFG, old_reg);
++			hifmc_writel(host, FMC_GLOBAL_CFG, reg);
++			FMC_PR(EC_DBG, "\t ||-Set global CFG[%#x]%#x\n",
++					FMC_GLOBAL_CFG, reg);
++			change++;
++		}
++	}
++
++	old_reg = hifmc_readl(host, FMC_CFG);
++	reg = (ecc_en ? host->nand_cfg : host->nand_cfg_ecc0);
++
++	if (old_reg != reg) {
++		FMC_PR(EC_DBG, "\t |%s-Start %s ECC0 mode\n", change ? "|":"*",
++				ecc_op);
++		FMC_PR(EC_DBG, "\t ||-Get CFG[%#x]%#x\n", FMC_CFG, old_reg);
++		hifmc_writel(host, FMC_CFG, reg);
++		FMC_PR(EC_DBG, "\t ||-Set CFG[%#x]%#x\n", FMC_CFG, reg);
++		change++;
++	}
++
++	if (EC_DBG && change)
++		FMC_PR(EC_DBG, "\t |*-End randomizer and ECC0 mode config\n");
++}
++
++/*****************************************************************************/
++static void hifmc100_send_cmd_status(struct hifmc_host *host)
++{
++	unsigned int regval;
++
++	host->enable_ecc_randomizer(host, DISABLE, DISABLE);
++
++	regval = OP_CFG_FM_CS(host->cmd_op.cs);
++	hifmc_writel(host, FMC_OP_CFG, regval);
++
++	regval = FMC_OP_READ_STATUS_EN | FMC_OP_REG_OP_START;
++	hifmc_writel(host, FMC_OP, regval);
++
++	FMC_CMD_WAIT_CPU_FINISH(host);
++}
++
++/*****************************************************************************/
++static void hifmc100_send_cmd_readid(struct hifmc_host *host)
++{
++	unsigned int reg;
++
++	FMC_PR(BT_DBG, "\t *-Start read nand flash ID\n");
++
++	host->enable_ecc_randomizer(host, DISABLE, DISABLE);
++
++	reg = FMC_DATA_NUM_CNT(host->cmd_op.data_no);
++	hifmc_writel(host, FMC_DATA_NUM, reg);
++	FMC_PR(BT_DBG, "\t |-Set DATA_NUM[%#x]%#x\n", FMC_DATA_NUM, reg);
++
++	reg = FMC_CMD_CMD1(NAND_CMD_READID);
++	hifmc_writel(host, FMC_CMD, reg);
++	FMC_PR(BT_DBG, "\t |-Set CMD[%#x]%#x\n", FMC_CMD, reg);
++
++	reg = 0;
++	hifmc_writel(host, FMC_ADDRL, reg);
++	FMC_PR(BT_DBG, "\t |-Set ADDRL[%#x]%#x\n", FMC_ADDRL, reg);
++
++	reg = OP_CFG_FM_CS(host->cmd_op.cs)
++		| OP_CFG_ADDR_NUM(READ_ID_ADDR_NUM);
++	hifmc_writel(host, FMC_OP_CFG, reg);
++	FMC_PR(BT_DBG, "\t |-Set OP_CFG[%#x]%#x\n", FMC_OP_CFG, reg);
++
++	reg = FMC_OP_CMD1_EN
++		| FMC_OP_ADDR_EN
++		| FMC_OP_READ_DATA_EN
++		| FMC_OP_REG_OP_START;
++	hifmc_writel(host, FMC_OP, reg);
++	FMC_PR(BT_DBG, "\t |-Set OP[%#x]%#x\n", FMC_OP, reg);
++
++	host->addr_cycle = 0x0;
++
++	FMC_CMD_WAIT_CPU_FINISH(host);
++
++	FMC_PR(BT_DBG, "\t *-End read nand flash ID\n");
++}
++
++/*****************************************************************************/
++static void hifmc100_send_cmd_reset(struct hifmc_host *host)
++{
++	unsigned int reg;
++
++	FMC_PR(BT_DBG, "\t *-Start reset nand flash\n");
++
++	reg = FMC_CMD_CMD1(NAND_CMD_RESET);
++	hifmc_writel(host, FMC_CMD, reg);
++	FMC_PR(BT_DBG, "\t |-Set CMD[%#x]%#x\n", FMC_CMD, reg);
++
++	reg = OP_CFG_FM_CS(host->cmd_op.cs);
++	hifmc_writel(host, FMC_OP_CFG, reg);
++	FMC_PR(BT_DBG, "\t |-Set OP_CFG[%#x]%#x\n", FMC_OP_CFG, reg);
++
++	reg = FMC_OP_CMD1_EN
++		| FMC_OP_WAIT_READY_EN
++		| FMC_OP_REG_OP_START;
++	hifmc_writel(host, FMC_OP, reg);
++	FMC_PR(BT_DBG, "\t |-Set OP[%#x]%#x\n", FMC_OP, reg);
++
++	FMC_CMD_WAIT_CPU_FINISH(host);
++
++	FMC_PR(BT_DBG, "\t *-End reset nand flash\n");
++}
++
++/*****************************************************************************/
++static unsigned char hifmc100_read_byte(struct mtd_info *mtd)
++{
++	unsigned char value = 0;
++	struct nand_chip *chip = mtd->priv;
++	struct hifmc_host *host = chip->priv;
++
++	if (host->cmd_op.l_cmd == NAND_CMD_READID) {
++		value = hifmc_readb((void __iomem *)(chip->IO_ADDR_R + host->offset));
++		host->offset++;
++		if (host->cmd_op.data_no == host->offset)
++			host->cmd_op.l_cmd = 0;
++		return value;
++	}
++
++	if (host->cmd_op.cmd == NAND_CMD_STATUS) {
++		value = hifmc_readl(host, FMC_STATUS);
++		if (host->cmd_op.l_cmd == NAND_CMD_ERASE1)
++			FMC_PR(ER_DBG, "\t*-Erase WP status: %#x\n", value);
++		if (host->cmd_op.l_cmd == NAND_CMD_PAGEPROG)
++			FMC_PR(WR_DBG, "\t*-Write WP status: %#x\n", value);
++		return value;
++	}
++
++	if (host->cmd_op.l_cmd == NAND_CMD_READOOB) {
++		value = hifmc_readb((void __iomem *)(host->buffer + host->pagesize
++					+ host->offset));
++		host->offset++;
++		return value;
++	}
++
++	host->offset++;
++
++	return hifmc_readb((void __iomem *)(host->buffer + host->column \
++				+ host->offset - 1));
++}
++
++/*****************************************************************************/
++static unsigned short hifmc100_read_word(struct mtd_info *mtd)
++{
++	struct nand_chip *chip = mtd->priv;
++	struct hifmc_host *host = chip->priv;
++
++	host->offset += 2;
++	return hifmc_readw(host->buffer + host->column + host->offset - 2);
++}
++
++/*****************************************************************************/
++static void hifmc100_write_buf(struct mtd_info *mtd,
++	const u_char *buf, int len)
++{
++	struct nand_chip *chip = mtd->priv;
++	struct hifmc_host *host = chip->priv;
++
++#ifdef HIFMC100_NAND_SUPPORT_REG_WRITE
++	if (buf == chip->oob_poi)
++		memcpy((char *)host->iobase + host->pagesize, buf, len);
++	else
++		memcpy((char *)host->iobase, buf, len);
++#else
++	if (buf == chip->oob_poi)
++		memcpy((char *)host->buffer + host->pagesize, buf, len);
++	else
++		memcpy((char *)host->buffer, buf, len);
++#endif
++	return;
++}
++
++#ifdef CONFIG_HISI_NAND_ECC_STATUS_REPORT
++/*****************************************************************************/
++static void hifmc100_ecc_err_num_count(struct mtd_info *mtd,
++			u_int ecc_st, u_int reg)
++{
++	u_char err_num;
++
++	if (ecc_st > 4)
++		ecc_st = 4;
++
++	while (ecc_st) {
++		err_num = GET_ECC_ERR_NUM(--ecc_st, reg);
++		if (err_num == 0xff)
++			mtd->ecc_stats.failed++;
++		else
++			mtd->ecc_stats.corrected += err_num;
++	}
++}
++#endif
++
++/*****************************************************************************/
++static void hifmc100_read_buf(struct mtd_info *mtd, u_char *buf, int len)
++{
++	struct nand_chip *chip = mtd->priv;
++	struct hifmc_host *host = chip->priv;
++
++#ifdef HIFMC100_NAND_SUPPORT_REG_READ
++	if (buf == chip->oob_poi)
++		memcpy(buf, (char *)host->iobase + host->pagesize, len);
++	else
++		memcpy(buf, (char *)host->iobase, len);
++#else
++	if (buf == chip->oob_poi)
++		memcpy(buf, (char *)host->buffer + host->pagesize, len);
++	else
++		memcpy(buf, (char *)host->buffer, len);
++#endif
++
++#ifdef CONFIG_HISI_NAND_ECC_STATUS_REPORT
++	if (buf != chip->oob_poi) {
++		u_int reg, ecc_step = host->pagesize >> 10;
++
++		/* 2K or 4K or 8K(1) or 16K(1-1) pagesize */
++		reg = hifmc_readl(host, HIFMC100_ECC_ERR_NUM0_BUF0);
++		hifmc100_ecc_err_num_count(mtd, ecc_step, reg);
++
++		if (ecc_step > 4) {
++			/* 8K(2) or 16K(1-2) pagesize */
++			reg = hifmc_readl(host, HIFMC100_ECC_ERR_NUM1_BUF0);
++			hifmc100_ecc_err_num_count(mtd, ecc_step, reg);
++			if (ecc_step > 8) {
++				/* 16K(2-1) pagesize */
++				reg = hifmc_readl(host,
++						HIFMC100_ECC_ERR_NUM0_BUF1);
++				hifmc100_ecc_err_num_count(mtd, ecc_step, reg);
++				/* 16K(2-2) pagesize */
++				reg = hifmc_readl(host,
++						HIFMC100_ECC_ERR_NUM1_BUF1);
++				hifmc100_ecc_err_num_count(mtd, ecc_step, reg);
++			}
++		}
++	}
++#endif
++
++	return;
++}
++
++/*****************************************************************************/
++static void hifmc100_select_chip(struct mtd_info *mtd, int chipselect)
++{
++	struct nand_chip *chip = mtd->priv;
++	struct hifmc_host *host = chip->priv;
++
++	if (chipselect < 0) {
++		mutex_unlock(&fmc_switch_mutex);
++		return;
++	}
++
++	mutex_lock(&fmc_switch_mutex);
++
++	if (chipselect > CONFIG_HIFMC100_MAX_NAND_CHIP)
++		DB_BUG("Error: Invalid chip select: %d\n", chipselect);
++
++	host->cmd_op.cs = chipselect;
++	if (host->mtd != mtd)
++		host->mtd = mtd;
++
++	switch (chip->state) {
++	case FL_ERASING:
++		host->cmd_op.l_cmd = NAND_CMD_ERASE1;
++		if (ER_DBG)
++			pr_info("\n");
++		FMC_PR(ER_DBG, "\t*-Erase chip: %d\n", chipselect);
++		break;
++	case FL_WRITING:
++		host->cmd_op.l_cmd = NAND_CMD_PAGEPROG;
++		if (WR_DBG)
++			pr_info("\n");
++		FMC_PR(WR_DBG, "\t*-Write chip: %d\n", chipselect);
++		break;
++	case FL_READING:
++		host->cmd_op.l_cmd = NAND_CMD_READ0;
++		if (RD_DBG)
++			pr_info("\n");
++		FMC_PR(RD_DBG, "\t*-Read chip: %d\n", chipselect);
++		break;
++	default:
++		break;
++	}
++}
++
++/*****************************************************************************/
++static void hifmc100_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned ctrl)
++{
++	unsigned char cmd;
++	int is_cache_invalid = 1;
++	struct nand_chip *chip = mtd->priv;
++	struct hifmc_host *host = chip->priv;
++
++	if (ctrl & NAND_ALE) {
++		unsigned int addr_value = 0;
++		unsigned int addr_offset = 0;
++
++		if (ctrl & NAND_CTRL_CHANGE) {
++			host->addr_cycle = 0x0;
++			host->addr_value[0] = 0x0;
++			host->addr_value[1] = 0x0;
++		}
++		addr_offset = host->addr_cycle << 3;
++
++		if (host->addr_cycle >= HIFMC100_ADDR_CYCLE_MASK) {
++			addr_offset = (host->addr_cycle -
++					HIFMC100_ADDR_CYCLE_MASK) << 3;
++			addr_value = 1;
++		}
++
++		host->addr_value[addr_value] |=
++			((dat & 0xff) << addr_offset);
++
++		host->addr_cycle++;
++	}
++
++	if ((ctrl & NAND_CLE) && (ctrl & NAND_CTRL_CHANGE)) {
++		cmd = dat & 0xff;
++		host->cmd_op.cmd = cmd;
++		switch (cmd) {
++		case NAND_CMD_PAGEPROG:
++			host->offset = 0;
++			host->send_cmd_pageprog(host);
++			break;
++
++		case NAND_CMD_READSTART:
++			is_cache_invalid = 0;
++			if (host->addr_value[0] == host->pagesize)
++				host->cmd_op.l_cmd = NAND_CMD_READOOB;
++			host->send_cmd_readstart(host);
++			break;
++
++		case NAND_CMD_ERASE2:
++			host->cmd_op.l_cmd = cmd;
++			host->send_cmd_erase(host);
++			break;
++
++		case NAND_CMD_READID:
++			memset((u_char *)(chip->IO_ADDR_R), 0, MAX_NAND_ID_LEN);
++			host->cmd_op.l_cmd = cmd;
++			host->cmd_op.data_no = MAX_NAND_ID_LEN;
++			host->send_cmd_readid(host);
++			break;
++
++		case NAND_CMD_STATUS:
++			host->send_cmd_status(host);
++			break;
++
++		case NAND_CMD_READ0:
++			host->cmd_op.l_cmd = cmd;
++			break;
++
++		case NAND_CMD_RESET:
++			host->send_cmd_reset(host);
++			break;
++
++		case NAND_CMD_SEQIN:
++		case NAND_CMD_ERASE1:
++		default:
++			break;
++		}
++	}
++
++	/* pass pagesize and ecctype to kernel when startup. */
++	host->enable_ecc_randomizer(host, ENABLE, ENABLE);
++
++	if ((dat == NAND_CMD_NONE) && host->addr_cycle) {
++		if (host->cmd_op.cmd == NAND_CMD_SEQIN
++			|| host->cmd_op.cmd == NAND_CMD_READ0
++			|| host->cmd_op.cmd == NAND_CMD_READID) {
++			host->offset = 0x0;
++			host->column = (host->addr_value[0] & 0xffff);
++		}
++	}
++
++	if (is_cache_invalid) {
++		host->cache_addr_value[0] = ~0;
++		host->cache_addr_value[1] = ~0;
++	}
++}
++
++/*****************************************************************************/
++static int hifmc100_dev_ready(struct mtd_info *mtd)
++{
++	return 0x1;
++}
++
++/*****************************************************************************/
++/*
++ * 'host->epm' only use the first oobfree[0] field, it looks very simple, But...
++ */
++static struct nand_ecclayout nand_ecc_default = {
++	.oobfree = {{2, 30} }
++};
++
++#ifdef CONFIG_HISI_NAND_FS_MAY_NO_YAFFS2
++static struct nand_ecclayout nand_ecc_2k16bit = {
++	        .oobfree = {{2, 6} }
++};
++
++static struct nand_ecclayout nand_ecc_4k16bit = {
++	        .oobfree = {{2, 14} }
++};
++#endif
++/*****************************************************************************/
++/* ecc/pagesize get from CPU PIN. */
++static struct nand_config_info hifmc100_nand_hw_pin_config_table[] = {
++	{NAND_PAGE_16K, NAND_ECC_64BIT, 1824/*1824*/, &nand_ecc_default},
++	{NAND_PAGE_16K, NAND_ECC_40BIT, 1152/*1152*/, &nand_ecc_default},
++	{NAND_PAGE_16K, NAND_ECC_0BIT,  32 ,          &nand_ecc_default},
++
++	{NAND_PAGE_8K, NAND_ECC_64BIT, 928 /*928*/,  &nand_ecc_default},
++	{NAND_PAGE_8K, NAND_ECC_40BIT, 592 /*592 */,  &nand_ecc_default},
++	{NAND_PAGE_8K, NAND_ECC_24BIT, 368 /*368*/,  &nand_ecc_default},
++	{NAND_PAGE_8K, NAND_ECC_0BIT,  32,           &nand_ecc_default},
++
++	{NAND_PAGE_4K, NAND_ECC_24BIT, 200 /*200*/,  &nand_ecc_default},
++#ifdef CONFIG_HISI_NAND_FS_MAY_NO_YAFFS2
++	{NAND_PAGE_4K, NAND_ECC_16BIT, 128 /*128*/,  &nand_ecc_4k16bit},
++#endif
++	{NAND_PAGE_4K, NAND_ECC_8BIT,  88  /*88*/,   &nand_ecc_default},
++	{NAND_PAGE_4K, NAND_ECC_0BIT,  32,           &nand_ecc_default},
++
++	{NAND_PAGE_2K, NAND_ECC_24BIT, 116 /*116*/, &nand_ecc_default},
++#ifdef CONFIG_HISI_NAND_FS_MAY_NO_YAFFS2
++	{NAND_PAGE_2K, NAND_ECC_16BIT, 64  /*64*/,  &nand_ecc_2k16bit},
++#endif
++	{NAND_PAGE_2K, NAND_ECC_8BIT,  60  /*60*/,  &nand_ecc_default},
++	{NAND_PAGE_2K, NAND_ECC_0BIT,  32,          &nand_ecc_default},
++
++	{0, 0, 0, NULL},
++};
++
++/*****************************************************************************/
++/* ecc/pagesize get from NAND controller */
++static struct nand_config_info hifmc100_nand_hw_auto_config_table[] = {
++	{NAND_PAGE_16K, NAND_ECC_64BIT, 1824/*1824*/, &nand_ecc_default},
++	{NAND_PAGE_16K, NAND_ECC_40BIT, 1200/*1152*/, &nand_ecc_default},
++	{NAND_PAGE_16K, NAND_ECC_0BIT,  32 ,          &nand_ecc_default},
++
++	{NAND_PAGE_8K, NAND_ECC_64BIT, 928 /*928*/,  &nand_ecc_default},
++	{NAND_PAGE_8K, NAND_ECC_40BIT, 600 /*592*/,  &nand_ecc_default},
++	{NAND_PAGE_8K, NAND_ECC_24BIT, 368 /*368*/,  &nand_ecc_default},
++	{NAND_PAGE_8K, NAND_ECC_0BIT,  32,           &nand_ecc_default},
++
++	{NAND_PAGE_4K, NAND_ECC_24BIT, 200 /*200*/,  &nand_ecc_default},
++#ifdef CONFIG_HISI_NAND_FS_MAY_NO_YAFFS2
++	{NAND_PAGE_4K, NAND_ECC_16BIT,  128 /*128*/,  &nand_ecc_default},
++#endif
++	{NAND_PAGE_4K, NAND_ECC_8BIT,  128 /*88*/,   &nand_ecc_default},
++	{NAND_PAGE_4K, NAND_ECC_0BIT,  32,           &nand_ecc_default},
++
++	{NAND_PAGE_2K, NAND_ECC_24BIT, 128 /*116*/, &nand_ecc_default},
++#ifdef CONFIG_HISI_NAND_FS_MAY_NO_YAFFS2
++	{NAND_PAGE_2K, NAND_ECC_16BIT,  64 /*64*/, &nand_ecc_default},
++#endif
++	{NAND_PAGE_2K, NAND_ECC_8BIT,  64  /*60*/,  &nand_ecc_default},
++	{NAND_PAGE_2K, NAND_ECC_0BIT,  32,          &nand_ecc_default},
++
++	{0,		0,		0,	NULL},
++};
++
++/*****************************************************************************/
++/*
++ *  0 - This NAND NOT support randomizer
++ *  1 - This NAND support randomizer.
++ */
++static int hifmc100_nand_support_randomizer(u_int pageisze, u_int ecctype)
++{
++	switch (pageisze) {
++	case _8K:
++		return (ecctype >= NAND_ECC_24BIT && ecctype <= NAND_ECC_80BIT);
++	case _16K:
++		return (ecctype >= NAND_ECC_40BIT && ecctype <= NAND_ECC_80BIT);
++	case _32K:
++		return (ecctype >= NAND_ECC_40BIT && ecctype <= NAND_ECC_80BIT);
++	default:
++		return 0;
++	}
++}
++
++/*****************************************************************************/
++/* used the best correct arithmetic. */
++static struct nand_config_info *hifmc100_get_best_ecc(
++		struct nand_config_info *config, struct mtd_info *mtd)
++{
++	struct nand_config_info *best = NULL;
++
++	for (; config->layout; config++) {
++		if (match_page_type_to_size(config->pagetype) != mtd->writesize)
++			continue;
++
++		if (mtd->oobsize < config->oobsize)
++			continue;
++
++		if (!best || (best->ecctype < config->ecctype))
++			best = config;
++	}
++
++	if (!best)
++		DB_BUG(ERSTR_DRIVER " the pagesize(%d) and oobsize(%d).\n",
++				mtd->writesize, mtd->oobsize);
++	return best;
++}
++
++/*****************************************************************************/
++static void debug_register_dump(struct hifmc_host *host)
++{
++	int ix;
++
++	pr_info("Register dump:");
++	for (ix = 0; ix <= 0x98; ix += 0x04) {
++		if (!(ix & 0x0F))
++			pr_info("\n0x%08X: ",
++					(unsigned int)(host->regbase + ix));
++		pr_info("%08X ", hifmc_readl(host, ix));
++	}
++	pr_info("\n");
++}
++
++/*****************************************************************************/
++static void hifmc100_check_config(struct hifmc_host *host,
++				 struct nand_dev_t *flash_dev_ex,
++				 struct nand_config_info *best, int is_hw_auto)
++{
++	unsigned char page_reg, pagetype, ecc_reg, ecctype;
++	int isdump = 0;
++
++	FMC_PR(BT_DBG, "\t  *-Start check best and controller auto config\n");
++
++	page_reg = (host->nand_cfg & PAGE_SIZE_MASK) >> PAGE_SIZE_SHIFT;
++	pagetype = match_page_reg_to_type(page_reg);
++
++	ecc_reg = (host->nand_cfg & ECC_TYPE_MASK) >> ECC_TYPE_SHIFT;
++	ecctype = match_ecc_reg_to_type(ecc_reg);
++
++	if (pagetype != best->pagetype) {
++		if (!isdump++)
++			debug_register_dump(host);
++		if (is_hw_auto) {
++			DB_BUG("!!! warning: Hardware configure pagesize %s" \
++				", but the Nand Flash pageszie is %s. Update" \
++				" fastboot will resolve this problem.\n",
++				match_page_type_to_str(pagetype),
++				match_page_type_to_str(best->pagetype));
++		} else {
++			DB_BUG("!!! warning: Hardware configure pagesize %s" \
++				", but the Nand Flash pageszie is %s. Modify" \
++				"hardware pin will resolve this problem.\n",
++				match_page_type_to_str(pagetype),
++				match_page_type_to_str(best->pagetype));
++		}
++	}
++
++	if (ecctype < best->ecctype) {
++		if (!is_hw_auto)
++			best->ecctype = ecctype;
++	} else if (ecctype > best->ecctype) {
++		DB_BUG("!!! warning: Hardware configure ecctype %s, " \
++			"but %s is more suitable for this Nand Flash." \
++			"Modify hardware pin will resolve this problem.\n",
++			match_ecc_type_to_str(ecctype),
++			match_ecc_type_to_str(best->ecctype));
++	}
++
++	if (IS_NAND_RANDOM(flash_dev_ex) && !IS_NAND_RANDOM(host)) {
++		if (is_hw_auto) {
++			DB_BUG("Hardware is't configure randomizer, but it "\
++				"is more suitable for this Nand Flash. Update"\
++				" fastboot will resolve this problem\n");
++		} else {
++			DB_BUG("Hardware is't configure randomizer, but it" \
++				"is more suitable for this Nand Flash. Modify"\
++				"hardware pin will resolve this problem.\n");
++		}
++	}
++
++	FMC_PR(BT_DBG, "\t  *-End check, PageSize: %s, EccType: %s\n",
++	match_page_type_to_str(pagetype), match_ecc_type_to_str(ecctype));
++}
++
++/*****************************************************************************/
++static int hifmc100_ecc_probe(struct mtd_info *mtd, struct nand_chip *chip,
++		struct nand_dev_t *dev)
++{
++	int regval, buffer_len;
++	char *start_type = "unknown";
++	struct nand_config_info *best = NULL;
++	struct nand_config_info *config = NULL;
++	struct hifmc_host *host = chip->priv;
++	struct nand_dev_t *nand_dev = &g_nand_dev;
++
++	FMC_PR(BT_DBG, "\t *-Start match PageSize and EccType\n");
++
++	if (IS_NANDC_HW_AUTO(host)) {
++		FMC_PR(BT_DBG, "\t |-Get hardware auto config\n");
++		config = hifmc100_nand_hw_auto_config_table;
++
++		start_type = "HW-Auto";
++		best = hifmc100_get_best_ecc(config, mtd);
++	} else {
++		FMC_PR(BT_DBG, "\t |-Get config from CPU PIN\n");
++		config = hifmc100_nand_hw_pin_config_table;
++		start_type = "HW-Pin";
++		best = hifmc100_get_best_ecc(config, mtd);
++		hifmc100_check_config(host, nand_dev, best, 0);
++	}
++
++	nand_dev->flags |= (IS_NANDC_HW_AUTO(host)
++				| IS_NANDC_CONFIG_DONE(host));
++
++	if (!best)
++		DB_BUG(ERSTR_HARDWARE
++			"Please configure Nand Flash pagesize and ecctype!\n");
++
++	if (best->ecctype != NAND_ECC_0BIT)
++		mtd->oobsize = best->oobsize;
++	mtd->oobavail = HIFMC100_NAND_OOBSIZE_FOR_YAFFS;
++	chip->ecc.layout = best->layout;
++
++	host->ecctype = best->ecctype;
++	FMC_PR(BT_DBG, "\t |-Save best EccType %d(%s)\n", host->ecctype,
++			match_ecc_type_to_str(best->ecctype));
++	host->pagesize = match_page_type_to_size(best->pagetype);
++	FMC_PR(BT_DBG, "\t |-Save best PageSize %d(%s)\n", host->pagesize,
++			match_page_type_to_str(best->pagetype));
++
++	if (hifmc100_nand_support_randomizer(host->pagesize, host->ecctype))
++		host->flags |= IS_NAND_RANDOM(nand_dev);
++
++	host->oobsize = mtd->oobsize;
++	host->block_page_mask = ((mtd->erasesize / mtd->writesize) - 1);
++
++	buffer_len = host->pagesize + host->oobsize;
++	host->buffer = dmam_alloc_coherent(host->dev, buffer_len,
++			&host->dma_buffer, GFP_KERNEL);
++	if (!host->buffer) {
++		DB_MSG("Error: Can't malloc memory for hifmc100 driver.\n");
++		return -ENOMEM;
++	}
++	memset(host->buffer, 0xff, buffer_len);
++	host->dma_oob = host->dma_buffer + host->pagesize;
++
++	host->bbm = (unsigned char *)(host->buffer + host->pagesize
++			+ HIFMC100_BAD_BLOCK_POS);
++
++	host->epm = (unsigned short *)(host->buffer + host->pagesize
++			+ chip->ecc.layout->oobfree[0].offset + 28);
++
++#ifdef CONFIG_HISI_NAND_FS_MAY_NO_YAFFS2
++	if (best->ecctype == NAND_ECC_16BIT) {
++		if (host->pagesize == _2K) {
++			/* EB bits locate in the bottom two of CTRL(4) */
++			host->epm = (u_short *)(host->buffer + host->pagesize
++					+ chip->ecc.layout->oobfree[0].offset + 4);
++		} else if (host->pagesize == _4K) {
++			/* EB bit locate in the bottom two of CTRL(14) */
++			host->epm = (u_short *)(host->buffer + host->pagesize
++					+ chip->ecc.layout->oobfree[0].offset + 12);
++		}
++	}
++#endif
++
++	host->nand_cfg &= ~PAGE_SIZE_MASK;
++	host->nand_cfg_ecc0 &= ~PAGE_SIZE_MASK;
++	regval = match_page_type_to_reg(best->pagetype);
++	host->nand_cfg |= FMC_CFG_PAGE_SIZE(regval);
++	host->nand_cfg_ecc0 |= FMC_CFG_PAGE_SIZE(regval);
++
++	host->nand_cfg &= ~ECC_TYPE_MASK;
++	host->nand_cfg_ecc0 &= ~ECC_TYPE_MASK;
++	regval = match_ecc_type_to_reg(best->ecctype);
++	host->nand_cfg |= FMC_CFG_ECC_TYPE(regval);
++
++	/* pass pagesize and ecctype to kernel when spiflash startup. */
++	host->enable_ecc_randomizer(host, ENABLE, ENABLE);
++
++	if (mtd->writesize > NAND_MAX_PAGESIZE
++			|| mtd->oobsize > NAND_MAX_OOBSIZE) {
++		DB_BUG(ERSTR_DRIVER
++			"Driver does not support this Nand Flash. Please " \
++			"increase NAND_MAX_PAGESIZE and NAND_MAX_OOBSIZE.\n");
++	}
++
++	if (mtd->writesize != host->pagesize) {
++		unsigned int shift = 0;
++		unsigned int writesize = mtd->writesize;
++
++		while (writesize > host->pagesize) {
++			writesize >>= 1;
++			shift++;
++		}
++		chip->chipsize = chip->chipsize >> shift;
++		mtd->erasesize = mtd->erasesize >> shift;
++		mtd->writesize = host->pagesize;
++		pr_info("Nand divide into 1/%u\n", (1 << shift));
++	}
++
++	nand_dev->start_type = start_type;
++	dev->start_type = nand_dev->start_type;
++	nand_dev->ecctype = host->ecctype;
++	dev->ecctype = nand_dev->ecctype;
++
++	host->read_retry = NULL;
++
++	/*
++	 * If it want to support the 'read retry' feature, the 'randomizer'
++	 * feature must be support first.
++	 */
++	if (host->read_retry && !IS_NAND_RANDOM(host)) {
++		DB_BUG(ERSTR_HARDWARE
++			"This Nand flash need to enable 'randomizer' feature. "
++			"Please configure hardware randomizer PIN.");
++	}
++
++	/*
++	 * Check if hardware enable randomizer PIN, But NAND does not need
++	 * randomizer. We will notice user.
++	 */
++	if (IS_NAND_RANDOM(host) &&
++	    !hifmc100_nand_support_randomizer(host->pagesize, host->ecctype))
++		DB_BUG(ERSTR_HARDWARE
++			"This NAND flash does not support `randomizer`, "
++			"Please don't configure hardware randomizer PIN.");
++
++	FMC_PR(BT_DBG, "\t *-End match ecctype\n");
++
++	return 0;
++}
++
++/*****************************************************************************/
++static void hifmc100_chip_init(struct nand_chip *chip)
++{
++	memset((char *)chip->IO_ADDR_R, 0xff, NAND_BUFFER_LEN);
++
++	chip->read_byte = hifmc100_read_byte;
++	chip->read_word = hifmc100_read_word;
++	chip->write_buf = hifmc100_write_buf;
++	chip->read_buf = hifmc100_read_buf;
++
++	chip->select_chip = hifmc100_select_chip;
++
++	chip->cmd_ctrl = hifmc100_cmd_ctrl;
++	chip->dev_ready = hifmc100_dev_ready;
++
++	chip->chip_delay = FMC_CHIP_DELAY;
++
++	chip->options = NAND_NO_AUTOINCR | NAND_NEED_READRDY | NAND_BROKEN_XD
++		| NAND_SKIP_BBTSCAN;
++
++	chip->ecc.layout = NULL;
++	chip->ecc.mode = NAND_ECC_NONE;
++}
++
++/*****************************************************************************/
++static int hifmc100_host_init(struct hifmc_host *host)
++{
++	unsigned int addr, reg, flash_type;
++
++	FMC_PR(BT_DBG, "\t *-Start nand host init\n");
++
++	addr = (unsigned int)host->regbase + FMC_CFG;
++	reg = hifmc_readl(host, FMC_CFG);
++	FMC_PR(BT_DBG, "\t |-Read FMC CFG[%#x]%#x\n", addr, reg);
++	flash_type = GET_SPI_FLASH_TYPE(reg);
++	if (flash_type != FLASH_TYPE_NAND) {
++		DB_MSG("Error: Flash type isn't Nand flash. reg[%#x]\n", reg);
++		reg |= FMC_CFG_FLASH_SEL(FLASH_TYPE_NAND);
++		FMC_PR(BT_DBG, "\t |-Change flash type to Nand flash\n");
++	}
++
++	if ((reg & FMC_CFG_OP_MODE_MASK) == FMC_CFG_OP_MODE_BOOT) {
++		reg |= FMC_CFG_OP_MODE(FMC_CFG_OP_MODE_NORMAL);
++		FMC_PR(BT_DBG, "\t |-Controller enter normal mode\n");
++	}
++	hifmc_writel(host, FMC_CFG, reg);
++	FMC_PR(BT_DBG, "\t |-Set CFG[%#x]%#x\n", addr, reg);
++
++	host->nand_cfg = reg;
++	host->nand_cfg_ecc0 = (reg & ~ECC_TYPE_MASK) | ECC_TYPE_0BIT;
++
++	addr = (unsigned int)host->regbase + FMC_GLOBAL_CFG;
++	reg = hifmc_readl(host, FMC_GLOBAL_CFG);
++	FMC_PR(BT_DBG, "\t |-Read global CFG[%#x]%#x\n", addr, reg);
++	if (reg & FMC_GLOBAL_CFG_RANDOMIZER_EN) {
++		host->flags &= ~NAND_RANDOMIZER;
++		FMC_PR(BT_DBG, "\t |-Default disable randomizer\n");
++		reg &= ~FMC_GLOBAL_CFG_RANDOMIZER_EN;
++		hifmc_writel(host, FMC_GLOBAL_CFG, reg);
++		FMC_PR(BT_DBG, "\t |-Set global CFG[%#x]%#x\n", addr, reg);
++	}
++
++#ifdef CONFIG_HIFMC100_NAND_EDO_MODE
++	/* enable EDO node */
++	reg = hifmc_readl(host, FMC_GLOBAL_CFG);
++	hifmc_writel(host, FMC_GLOBAL_CFG, SET_NAND_EDO_MODE_EN(reg));
++#endif
++
++	host->addr_cycle = 0;
++	host->addr_value[0] = 0;
++	host->addr_value[1] = 0;
++	host->cache_addr_value[0] = ~0;
++	host->cache_addr_value[1] = ~0;
++
++	host->send_cmd_pageprog = hifmc100_send_cmd_write;
++	host->send_cmd_status = hifmc100_send_cmd_status;
++	host->send_cmd_readstart = hifmc100_send_cmd_read;
++	host->send_cmd_erase = hifmc100_send_cmd_erase;
++	host->send_cmd_readid = hifmc100_send_cmd_readid;
++	host->send_cmd_reset = hifmc100_send_cmd_reset;
++
++	/*
++	 * check if start from nand.
++	 * This register REG_SYSSTAT is set in start.S
++	 * When start in NAND (Auto), the ECC/PAGESIZE driver don't detect.
++	 */
++	host->flags |= NANDC_HW_AUTO;
++
++	if (GET_SYS_BOOT_MODE(reg) == BOOT_FROM_NAND) {
++		host->flags |= NANDC_CONFIG_DONE;
++		FMC_PR(BT_DBG, "\t |-Auto config pagesize and ecctype\n");
++	}
++
++	host->enable_ecc_randomizer = hifmc100_ecc_randomizer;
++
++	FMC_PR(BT_DBG, "\t *-End nand host init\n");
++
++	return 0;
++}
++
++/*****************************************************************************/
++int hifmc100_nand_init(struct nand_chip *chip)
++{
++	struct hifmc_host *host = chip->priv;
++
++	/* enable and set system clock */
++	clk_prepare_enable(host->clk);
++
++	/* fmc ip version check */
++	host->version = hifmc_readl(host, FMC_VERSION);
++	if (host->version != HIFMC_VER_100)
++		return -EFAULT;
++	pr_info("Found Flash Memory Controller v100 Nand Driver\n");
++
++	/* hifmc host init */
++	if (hifmc100_host_init(host)) {
++		DB_MSG("Error: Nand host init failed!\n");
++		return -EFAULT;
++	}
++	host->chip = chip;
++
++	hifmc_writel(host, FMC_PND_PWIDTH_CFG, PWIDTH_CFG_RW_HCNT(CONFIG_RW_H_WIDTH)
++			| PWIDTH_CFG_R_LCNT(CONFIG_R_L_WIDTH)
++			| PWIDTH_CFG_W_LCNT(CONFIG_W_L_WIDTH));
++
++	/* hifmc nand_chip struct init */
++	hifmc100_chip_init(chip);
++
++	hifmc_spl_ids_register();
++	hinfc_param_adjust = hifmc100_ecc_probe;
++
++	return 0;
++}
++
++#ifdef CONFIG_PM
++/*****************************************************************************/
++void hifmc100_nand_config(struct hifmc_host *host)
++{
++	/* enable system clock */
++	clk_prepare_enable(host->clk);
++	FMC_PR(PM_DBG, "\t |-enable system clock\n");
++}
++#endif  /* CONFIG_PM */
+diff --git a/drivers/mtd/nand/hifmc100_nand/hifmc100_nand.h b/drivers/mtd/nand/hifmc100_nand/hifmc100_nand.h
+new file mode 100644
+index 0000000..469e562
+--- /dev/null
++++ b/drivers/mtd/nand/hifmc100_nand/hifmc100_nand.h
+@@ -0,0 +1,159 @@
++/*
++ * The Flash Memory Controller v100 Device Driver for hisilicon
++ *
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#ifndef __HIFMC100_NAND_H__
++#define __HIFMC100_NAND_H__
++
++#include <linux/mfd/hisi_fmc.h>
++
++/******************************************************************************/
++/* These macroes are for debug only, reg option is slower then dma option */
++#undef HIFMC100_NAND_SUPPORT_REG_READ
++/* #define HIFMC100_NAND_SUPPORT_REG_READ */
++
++#undef HIFMC100_NAND_SUPPORT_REG_WRITE
++/* #define HIFMC100_NAND_SUPPORT_REG_WRITE */
++
++#ifdef CONFIG_HISI_NAND_ECC_STATUS_REPORT
++/*****************************************************************************/
++#define HIFMC100_ECC_ERR_NUM0_BUF0		0xc0
++#define HIFMC100_ECC_ERR_NUM1_BUF0		0xc4
++#define HIFMC100_ECC_ERR_NUM0_BUF1		0xc8
++#define HIFMC100_ECC_ERR_NUM1_BUF1		0xcc
++
++#define GET_ECC_ERR_NUM(_i, _reg)		(((_reg) >> ((_i) * 8)) & 0xff)
++#endif
++/*****************************************************************************/
++#define NAND_MAX_PAGESIZE			32768
++#define NAND_MAX_OOBSIZE			4800
++
++#define HIFMC100_NAND_OOBSIZE_FOR_YAFFS		32
++
++/*****************************************************************************/
++#define REG_CNT_HIGH_BLOCK_NUM_SHIFT		10
++
++#define REG_CNT_BLOCK_NUM_MASK			0x3ff
++#define REG_CNT_BLOCK_NUM_SHIFT			22
++
++#define REG_CNT_PAGE_NUM_MASK			0x3f
++#define REG_CNT_PAGE_NUM_SHIFT			16
++
++#define REG_CNT_WRAP_MASK			0xf
++#define REG_CNT_WRAP_SHIFT			12
++
++#define REG_CNT_ECC_OFFSET_MASK			0xfff
++#define REG_CNT_ECC_8BIT_OFFSET			1054
++#define REG_CNT_ECC_16BIT_OFFSET		1056
++#define REG_CNT_ECC_24BIT_OFFSET		1082
++
++/*****************************************************************************/
++#define HIFMC100_ADDR_CYCLE_MASK		0x4
++
++#define NAND_EDO_MODE_SHIFT            9
++#define NAND_EDO_MODE_MASK             (1<<NAND_EDO_MODE_SHIFT)
++#define SET_NAND_EDO_MODE_EN(reg)      ((reg) | NAND_EDO_MODE_MASK)
++/*****************************************************************************/
++struct hifmc_host {
++	struct nand_chip *chip;
++	struct mtd_info  *mtd;
++
++	struct hifmc_cmd_op cmd_op;
++	void __iomem *regbase;
++	void __iomem *iobase;
++
++	/* Controller config option nand flash */
++	unsigned int nand_cfg;
++	unsigned int nand_cfg_ecc0;
++
++	unsigned int offset;
++
++	struct device *dev;
++
++	/* This is maybe an un-aligment address, only for malloc or free */
++	char *buforg;
++	char *buffer;
++
++	unsigned int dma_buffer;
++	unsigned int dma_oob;
++
++	unsigned int addr_cycle;
++	unsigned int addr_value[2];
++	unsigned int cache_addr_value[2];
++
++	unsigned int column;
++	unsigned int block_page_mask;
++
++	unsigned int ecctype;
++	unsigned int pagesize;
++	unsigned int oobsize;
++
++	int  need_rr_data;
++#define HIFMC100_READ_RETRY_DATA_LEN         128
++	char rr_data[HIFMC100_READ_RETRY_DATA_LEN];
++	int  version;
++	int   add_partition;
++
++	/* BOOTROM read two bytes to detect the bad block flag */
++#define HIFMC100_BAD_BLOCK_POS              0
++	unsigned char *bbm;  /* nand bad block mark */
++	unsigned short *epm;  /* nand empty page mark */
++	unsigned int flags;
++
++#define HIFMC100_PS_UC_ECC        0x01 /* page has ecc error */
++#define HIFMC100_PS_BAD_BLOCK     0x02 /* bad block */
++#define HIFMC100_PS_EMPTY_PAGE    0x04 /* page is empty */
++#define HIFMC100_PS_EPM_ERROR     0x0100 /* empty page mark word has error. */
++#define HIFMC100_PS_BBM_ERROR     0x0200 /* bad block mark word has error. */
++	unsigned int page_status;
++
++	struct clk *clk;
++
++	void (*send_cmd_pageprog)(struct hifmc_host *host);
++	void (*send_cmd_status)(struct hifmc_host *host);
++	void (*send_cmd_readstart)(struct hifmc_host *host);
++	void (*send_cmd_erase)(struct hifmc_host *host);
++	void (*send_cmd_readid)(struct hifmc_host *host);
++	void (*send_cmd_reset)(struct hifmc_host *host);
++	void (*enable)(int enable);
++
++	void (*enable_ecc_randomizer)(struct hifmc_host *host,
++				     int ecc_en, int randomizer_en);
++
++	void (*detect_ecc)(struct hifmc_host *host);
++
++	struct read_retry_t *read_retry;
++};
++
++/*****************************************************************************/
++extern struct nand_dev_t g_nand_dev;
++
++/*****************************************************************************/
++int hifmc100_nand_init(struct nand_chip *chip);
++
++/*****************************************************************************/
++extern void hifmc_spl_ids_register(void);
++
++/*****************************************************************************/
++#ifdef CONFIG_PM
++void hifmc100_nand_config(struct hifmc_host *host);
++#endif
++/*****************************************************************************/
++
++#endif /* End of __HIFMC100_NAND_H__ */
+diff --git a/drivers/mtd/nand/hifmc100_nand/hifmc100_nand_os.c b/drivers/mtd/nand/hifmc100_nand/hifmc100_nand_os.c
+new file mode 100644
+index 0000000..b475615
+--- /dev/null
++++ b/drivers/mtd/nand/hifmc100_nand/hifmc100_nand_os.c
+@@ -0,0 +1,180 @@
++/*
++ * The Flash Memory Controller v100 Device Driver for hisilicon
++ *
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include <linux/of_platform.h>
++
++#include "hifmc100_nand_os.h"
++#include "hifmc100_nand.h"
++#include <linux/mfd/hisi_fmc.h>
++
++/*****************************************************************************/
++static inline int mtd_has_partitions(void) { return 1; }
++
++/*****************************************************************************/
++static int hisi_nand_os_probe(struct platform_device *pltdev)
++{
++	int len, result = 0;
++	struct hifmc_host *host;
++	struct nand_chip *chip;
++	struct mtd_info *mtd;
++	int nr_parts = 0;
++	struct mtd_partition *parts = NULL;
++	struct device *dev = &pltdev->dev;
++	struct device_node *np = NULL;
++	struct hisi_fmc *fmc = dev_get_drvdata(dev->parent);
++
++	len = sizeof(struct hifmc_host) + sizeof(struct nand_chip)
++		+ sizeof(struct mtd_info);
++	host = devm_kzalloc(dev, len, GFP_KERNEL);
++	if (!host)
++		return -ENOMEM;
++	memset((char *)host, 0, len);
++	platform_set_drvdata(pltdev, host);
++
++	host->dev = &pltdev->dev;
++	host->chip = chip = (struct nand_chip *)&host[1];
++	host->mtd = mtd = (struct mtd_info *)&chip[1];
++	host->regbase = fmc->regbase;
++	host->iobase = fmc->iobase;
++	host->clk = fmc->clk;
++	chip->IO_ADDR_R = chip->IO_ADDR_W = host->iobase;
++
++	/* hifmc Nand host init */
++	chip->priv = host;
++	result = hifmc100_nand_init(chip);
++	if (result) {
++		DB_MSG("Error: host init failed! result: %d\n", result);
++		goto fail;
++	}
++
++	np = of_get_next_available_child(dev->of_node, NULL);
++	mtd->name = np->name;
++	mtd->type = MTD_NANDFLASH;
++	mtd->priv = chip;
++	mtd->flags = MTD_CAP_NANDFLASH;
++	mtd->owner = THIS_MODULE;
++
++	if (nand_scan(mtd, CONFIG_HIFMC100_MAX_NAND_CHIP)) {
++		result = -ENXIO;
++		goto fail;
++	}
++
++	if (mtd_has_partitions()) {
++		static char const *part_probes[] = {
++			"cmdlinepart",
++			NULL,
++		};
++
++		nr_parts = parse_mtd_partitions(host->mtd,
++				part_probes, &parts, 0);
++		FMC_PR(BT_DBG, "parse mtd partitions: %d\n", nr_parts);
++		if (nr_parts > 0)
++			host->add_partition = 1;
++	}
++
++	result = mtd_device_register(host->mtd, parts, nr_parts);
++	if (result) {
++		kfree(parts);
++		parts = NULL;
++	}
++
++	return (1 == result) ? -ENODEV : 0;
++
++fail:
++	nand_release(mtd);
++	clk_disable_unprepare(host->clk);
++	return result;
++}
++
++/*****************************************************************************/
++static int hisi_nand_os_remove(struct platform_device *pltdev)
++{
++	struct hifmc_host *host = platform_get_drvdata(pltdev);
++
++	clk_disable_unprepare(host->clk);
++	nand_release(host->mtd);
++
++	return 0;
++}
++
++#ifdef CONFIG_PM
++/*****************************************************************************/
++static int hifmc100_nand_os_suspend(struct platform_device *pltdev,
++		pm_message_t state)
++{
++	struct hifmc_host *host = platform_get_drvdata(pltdev);
++	if (!host)
++		return 0;
++
++	while ((hifmc_readl(host, FMC_OP) & FMC_OP_REG_OP_START))
++		_cond_resched();
++
++	while ((hifmc_readl(host, FMC_OP_CTRL) & OP_CTRL_DMA_OP_READY))
++		_cond_resched();
++
++	clk_disable_unprepare(host->clk);
++	FMC_PR(PM_DBG, "\t|-disable system clock\n");
++	return 0;
++}
++
++/*****************************************************************************/
++static int hifmc100_nand_os_resume(struct platform_device *pltdev)
++{
++	int cs;
++	struct hifmc_host *host = platform_get_drvdata(pltdev);
++	struct nand_chip *chip;
++
++	if (!host)
++		return 0;
++
++	chip = host->chip;
++
++	for (cs = 0; cs < chip->numchips; cs++)
++		host->send_cmd_reset(host);
++
++	hifmc100_nand_config(host);
++	return 0;
++}
++#endif /* CONFIG_PM */
++
++/*****************************************************************************/
++static const struct of_device_id hisi_nand_dt_ids[] = {
++	{ .compatible = "hisilicon,hisi-nand" },
++	{ /* sentinel */ }
++};
++MODULE_DEVICE_TABLE(of, hisi_nand_dt_ids);
++
++static struct platform_driver hisi_nand_driver = {
++	.driver = {
++		.name	= "hisi-nand",
++		.of_match_table = hisi_nand_dt_ids,
++	},
++	.probe	= hisi_nand_os_probe,
++	.remove = hisi_nand_os_remove,
++#ifdef CONFIG_PM
++	.suspend	= hifmc100_nand_os_suspend,
++	.resume		= hifmc100_nand_os_resume,
++#endif
++};
++module_platform_driver(hisi_nand_driver);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("BVT_BSP");
++MODULE_DESCRIPTION("Hisilicon Flash Memory Controller V100 Nand Driver");
+diff --git a/drivers/mtd/nand/hifmc100_nand/hifmc100_nand_os.h b/drivers/mtd/nand/hifmc100_nand/hifmc100_nand_os.h
+new file mode 100644
+index 0000000..063fef8
+--- /dev/null
++++ b/drivers/mtd/nand/hifmc100_nand/hifmc100_nand_os.h
+@@ -0,0 +1,80 @@
++/*
++ * The Flash Memory Controller v100 Device Driver for hisilicon
++ *
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#ifndef __HIFMC100_NAND_OS_H__
++#define __HIFMC100_NAND_OS_H__
++
++/*****************************************************************************/
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/nand.h>
++#include <linux/mtd/partitions.h>
++#include <linux/delay.h>
++#include <linux/dma-mapping.h>
++#include <linux/sched.h>
++#include <asm/errno.h>
++#include <asm/setup.h>
++#include <linux/io.h>
++#include <linux/version.h>
++#include <linux/kernel.h>
++#include <linux/platform_device.h>
++
++#include <asm/clkdev.h>
++#include <linux/resource.h>
++#include <linux/clk.h>
++#include <linux/clkdev.h>
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 5))
++	#include "../../mtdcore.h"
++#endif
++
++/*****************************************************************************/
++#define DEFAULT_NAND_PAGESIZE	2048
++#define DEFAULT_NAND_OOBSIZE	64
++
++#define NAND_BUFFER_LEN		(DEFAULT_NAND_PAGESIZE + DEFAULT_NAND_OOBSIZE)
++
++/*****************************************************************************/
++#ifndef CONFIG_HIFMC100_MAX_NAND_CHIP
++	#define CONFIG_HIFMC100_MAX_NAND_CHIP	(1)
++	#warning NOT config CONFIG_HIFMC100_MAX_NAND_CHIP, \
++		used default value, maybe invalid.
++#endif
++
++#ifndef CONFIG_RW_H_WIDTH
++	#define CONFIG_RW_H_WIDTH	(10)
++	#warning NOT config CONFIG_RW_H_WIDTH, used default value, maybe invalid.
++#endif
++
++#ifndef CONFIG_R_L_WIDTH
++	#define CONFIG_R_L_WIDTH	(10)
++	#warning NOT config CONFIG_R_L_WIDTH, used default value, maybe invalid.
++#endif
++
++#ifndef CONFIG_W_L_WIDTH
++	#define CONFIG_W_L_WIDTH	(10)
++	#warning NOT config CONFIG_W_L_WIDTH, used default value, maybe invalid.
++#endif
++
++extern void hifmc100_nand_controller_enable(int enable);
++
++#endif /* End of __HIFMC100_NAND_OS_H__ */
+diff --git a/drivers/mtd/nand/hifmc100_nand/hifmc_nand_spl_ids.c b/drivers/mtd/nand/hifmc100_nand/hifmc_nand_spl_ids.c
+new file mode 100644
+index 0000000..5b34c02
+--- /dev/null
++++ b/drivers/mtd/nand/hifmc100_nand/hifmc_nand_spl_ids.c
+@@ -0,0 +1,925 @@
++/*
++ * The Flash Memory Controller v100 Device Driver for hisilicon
++ *
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include <asm/setup.h>
++#include <linux/mtd/nand.h>
++#include <linux/mfd/hisi_fmc.h>
++
++#include "../hinfc_gen.h"
++#include "hifmc100_nand.h"
++
++/*****************************************************************************/
++#define _768K           (_256K + _512K)
++
++/*****************************************************************************/
++struct nand_flash_special_dev {
++	unsigned char id[8];
++	int length;             /* length of id. */
++	unsigned long long chipsize;
++	struct nand_flash_dev *(*probe)(unsigned char *id);
++	char *name;
++
++	unsigned long pagesize;
++	unsigned long erasesize;
++	unsigned long oobsize;
++	unsigned long options;
++	unsigned int read_retry_type;
++
++#define BBP_LAST_PAGE                    0x01
++#define BBP_FIRST_PAGE                   0x02
++	unsigned int badblock_pos;
++	int flags;
++};
++
++/*****************************************************************************/
++/*                    this is nand probe function.                           */
++/*****************************************************************************/
++
++static struct nand_flash_dev *hynix_probe_v02(unsigned char *id)
++{
++	struct nand_flash_dev *type = &g_nand_dev.flash_dev;
++
++	int pagesizes[]   = {_2K, _4K, _8K, 0};
++	int oobsizes[]    = {128, 224, 448, 0, 0, 0, 0, 0};
++	int blocksizes[]  = {_128K, _256K, _512K, _768K, _1M, _2M, 0, 0};
++
++	int blocktype = (((id[3] >> 5) & 0x04) | ((id[3] >> 4) & 0x03));
++	int oobtype   = (((id[3] >> 2) & 0x03) | ((id[3] >> 4) & 0x04));
++
++	type->options   = 0;
++	type->pagesize  = pagesizes[(id[3] & 0x03)];
++	type->erasesize = blocksizes[blocktype];
++	type->oobsize = oobsizes[oobtype];
++
++	return type;
++}
++
++/*****************************************************************************/
++static struct nand_flash_dev *samsung_probe_v02(unsigned char *id)
++{
++	struct nand_flash_dev *type = &g_nand_dev.flash_dev;
++
++	int pagesizes[]   = {_2K, _4K, _8K, 0};
++	int oobsizes[]    = {0, 128, 218, 400, 436, 0, 0, 0};
++	int blocksizes[]  = {_128K, _256K, _512K, _1M, 0, 0, 0, 0};
++
++	int blocktype = (((id[3] >> 5) & 0x04) | ((id[3] >> 4) & 0x03));
++	int oobtype   = (((id[3] >> 4) & 0x04) | ((id[3] >> 2) & 0x03));
++
++	type->options   = 0;
++	type->pagesize  = pagesizes[(id[3] & 0x03)];
++	type->erasesize = blocksizes[blocktype];
++	type->oobsize = oobsizes[oobtype];
++
++	return type;
++}
++
++/*****************************************************************************/
++
++#define DRV_VERSION     "1.38"
++
++/*****************************************************************************/
++/*
++ * samsung:  27nm need randomizer, 21nm need read retry;
++ * micron:   25nm need read retry, datasheet will explain read retry.
++ * toshaba   32nm need randomizer, 24nm need read retry.
++ * hynix:    2xnm need read retry.
++ *
++ *		The special nand flash ID table version 1.38
++ *
++ * manufactory  |  type  |       name 	     |   ecc_type  | version_tag
++ * Micron		|  MLC	 |  MT29F64G08CBABA  |   40bit/1k  |  1.36
++ * Micron		|  MLC	 |  MT29F32G08CBADA  |   40bit/1k  |
++ * Micron		|  SLC	 |  MT29F8G08ABxBA   |   4bit/512  |
++ * Micron		|  MLC	 |  MT29F16G08CBABx  |   12bit/512 |
++ * Micron		|  MLC	 |  MT29F16G08CBACA  |   24bit/1k  |
++ * Micron		|  MLC	 |  MT29F32G08CBACA  |   24bit/1k  |
++ * Micron		|  MLC	 |  MT29F64G08CxxAA  |   24bit/1k  |
++ * Micron		|  MLC	 |  MT29F256G08CJAAA |   24bit/1k  |   2CE
++ * Micron		|  MLC	 |  MT29F256G08CMCBB |   24bit/1k  |
++ * Micron		|  SLC	 |  MT29F8G08ABACA   |   8bit/512  |
++ * Micron		|  SLC	 |  MT29F4G08ABAEA   |   8bit/512  |
++ * Micron		|  SLC	 |  MT29F2G08ABAFA   |   8bit/512  |
++ * Micron		|  SLC	 |  MT29F16G08ABACA  |   8bit/512  |
++ * Toshiba		|  MLC   |  TC58NVG4D2FTA00  |   24bit/1k  |
++ * Toshiba		|  MLC   |  TH58NVG6D2FTA20  |   24bit/1k  |   2CE
++ * Toshiba		|  MLC   |  TC58NVG5D2HTA00  |   40bit/1k  |
++ * Toshiba		|  MLC   |  TC58NVG6D2GTA00  |   40bit/1k  |
++ * Toshiba		|  MLC   |  TC58NVG6DCJTA00  |			   |
++ * Toshiba		|  MLC   |  TC58TEG5DCJTA00  |			   |
++ * Toshiba		|  SLC   |  TC58NVG0S3HTA00  |   8bit/512  |
++ * Toshiba		|  SLC   |  TC58NVG1S3HTA00  |   8bit/512  |
++ * Toshiba		|  SLC   |  TC58NVG1S3ETA00  |   4bit/512  |
++ * Toshiba		|  SLC   |  TC58NVG3S0FTA00  |   4bit/512  |
++ * Toshiba		|  SLC   |  TC58NVG2S0FTA00  |   4bit/512  |
++ * Toshiba		|  SLC   |  TH58NVG2S3HTA00  |   4bit/512  |
++ * Toshiba		|  TLC   |  TC58NVG5T2JTA00  |   60bit/1k  |
++ * Toshiba		|  TLC   |  TC58TEG5DCKTAx0  |   60bit/1k  |
++ * Toshiba		|  MLC   |  Tx58TEGxDDKTAx0  |			   |
++ * Samsung		|  MLC   |  K9LB(HC/PD/MD)G08U0(1)D  |   8bit/512B  |
++ * Samsung		|  MLC   |  K9GAG08U0E	     |   24bit/1KB |
++ * Samsung		|  MLC   |  K9LBG08U0E	     |   24bit/1KB |
++ * Samsung		|  MLC   |  K9G8G08U0C	     |   24bit/1KB |
++ * Samsung		|  MLC   |  K9GAG08U0F	     |   24bit/1KB |
++ * Samsung		|  MLC   |  K9LBG08U0M	     |             |
++ * Samsung		|  MLC   |  K9GBG08U0A	     |   24bit/1KB |
++ * Samsung		|  MLC   |  K9GBG08U0B	     |   40bit/1KB |
++ * Hynix		|  MLC   |  H27UAG8T2A	     |			   |
++ * Hynix		|  MLC   |  H27UAG8T2B	     |			   |
++ * Hynix		|  MLC   |  H27UBG8T2A	     |			   |
++ * Hynix		|  MLC   |  H27UBG8T2BTR	 |	 24bit/1KB |
++ * Hynix		|  MLC   |  H27UCG8T2A		 |	 40bit/1KB |
++ * Hynix		|  MLC   |  H27UBG8T2C		 |	 40bit/1KB |
++ * MISC			|  MLC   |  P1UAGA30AT-GCA	 |	 8bit/512  |
++ * MISC			|  MLC   |  PSU8GA30AT-GIA/ASU8GA30IT-G30CA	 |	 4bit/512  |
++ * MISC			|  SLC   |  PSU2GA30AT   	 |	 1bit/512  |   1.36
++ * Toshiba		|  SLC   |  TC58NVG2S0HTA00  |	 24bit/1K  |   1.37
++ * Toshiba		|  SLC   |  TC58NVG3S0HTA00  |   24bit/1K  |   1.37
++ * Micron		|  SLC	 |  MT29F2G08ABAEA   |   4bit/512 |
++ * Spansion		|  SLC	 | S34ML02G200TFI000	 | 24bit/1K |
++ * Spansion		|  SLC	 | S34ML04G200TFI000	 | 24bit/1K |  1.38
++ *
++ */
++static struct nand_flash_special_dev nand_flash_special_table[] = {
++
++	/****************************** Spansion *******************************/
++
++	{		/* SLC S34ML02G200TFI000 */
++		.name      = "S34ML02G200TFI000",
++		.id        = {0x01, 0xDA, 0x90, 0x95, 0x46, 0x00, 0x00, 0x00},
++		.length    = 5,
++		.chipsize  = _256M,
++		.probe     = NULL,
++		.pagesize  = _2K,
++		.erasesize = _128K,
++		.oobsize   = 128,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE,
++		.flags = 0,
++	},
++
++	{		/* SLC S34ML04G200TFI000 */
++		.name      = "S34ML04G200TFI000",
++		.id        = {0x01, 0xDC, 0x90, 0x95, 0x56, 0x00, 0x00, 0x00},
++		.length    = 5,
++		.chipsize  = _512M,
++		.probe     = NULL,
++		.pagesize  = _2K,
++		.erasesize = _128K,
++		.oobsize   = 128,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE,
++		.flags = 0,
++	},
++
++	/****************************** Micron *******************************/
++
++	{        /* MLC 40bit/1k */
++		.name      = "MT29F64G08CBABA",
++		.id        = {0x2C, 0x64, 0x44, 0x4B, 0xA9, 0x00, 0x00, 0x00},
++		.length    = 8,
++		.chipsize  = _8G,
++		.probe     = NULL,
++		.pagesize  = _8K,
++		.erasesize = _2M,
++		.oobsize   = 744,
++		.options   = 0,
++		.read_retry_type = NAND_RR_MICRON,
++		.badblock_pos    = BBP_FIRST_PAGE,
++		.flags = NAND_RANDOMIZER | NAND_CHIP_MICRON,
++	},
++	{        /* MLC 40bit/1k */
++		.name      = "MT29F32G08CBADA",
++		.id        = {0x2C, 0x44, 0x44, 0x4B, 0xA9, 0x00, 0x00, 0x00},
++		.length    = 8,
++		.chipsize  = _4G,
++		.probe     = NULL,
++		.pagesize  = _8K,
++		.erasesize = _2M,
++		.oobsize   = 744,
++		.options   = 0,
++		.read_retry_type = NAND_RR_MICRON,
++		.badblock_pos    = BBP_FIRST_PAGE,
++		.flags = NAND_RANDOMIZER,
++	},
++	{        /* SLC 4bit/512 */
++		.name      = "MT29F8G08ABxBA",
++		.id        = {0x2C, 0x38, 0x00, 0x26, 0x85, 0x00, 0x00, 0x00},
++		.length    = 8,
++		.chipsize  = _1G,
++		.probe     = NULL,
++		.pagesize  = _4K,
++		.erasesize = _512K,
++		.oobsize   = 224,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE,
++		.flags = 0,
++	},
++	{        /* MLC 12bit/512 */
++		.name      = "MT29F16G08CBABx",
++		.id        = {0x2C, 0x48, 0x04, 0x46, 0x85, 0x00, 0x00, 0x00},
++		.length    = 8,
++		.chipsize  = _2G,
++		.probe     = NULL,
++		.pagesize  = _4K,
++		.erasesize = _1M,
++		.oobsize   = 224,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE,
++		.flags = 0,
++	},
++	{        /* MLC 24bit/1k */
++		.name      = "MT29F16G08CBACA",
++		.id        = {0x2C, 0x48, 0x04, 0x4A, 0xA5, 0x00, 0x00, 0x00},
++		.length    = 8,
++		.chipsize  = _2G,
++		.probe     = NULL,
++		.pagesize  = _4K,
++		.erasesize = _1M,
++		.oobsize   = 224,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE,
++		.flags = 0,
++	},
++	{        /* MLC 24bit/1k */
++		.name      = "MT29F32G08CBACA",
++		.id        = {0x2C, 0x68, 0x04, 0x4A, 0xA9, 0x00, 0x00, 0x00},
++		.length    = 8,
++		.chipsize  = _4G,
++		.probe     = NULL,
++		.pagesize  = _4K,
++		.erasesize = _1M,
++		.oobsize   = 224,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE,
++		.flags = 0,
++	},
++	{        /* MLC 24bit/1k */
++		.name      = "MT29F64G08CxxAA",
++		.id        = {0x2C, 0x88, 0x04, 0x4B, 0xA9, 0x00, 0x00, 0x00},
++		.length    = 8,
++		.chipsize  = _8G,
++		.probe     = NULL,
++		.pagesize  = _8K,
++		.erasesize = _2M,
++		.oobsize   = 448,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE,
++		.flags = NAND_RANDOMIZER,
++	},
++	{        /* MLC 24bit/1k 2CE */
++		.name      = "MT29F256G08CJAAA",
++		.id        = {0x2C, 0xA8, 0x05, 0xCB, 0xA9, 0x00, 0x00, 0x00},
++		.length    = 8,
++		.chipsize  = _16G,
++		.probe     = NULL,
++		.pagesize  = _8K,
++		.erasesize = _2M,
++		.oobsize   = 448,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE,
++		.flags = NAND_RANDOMIZER,
++	},
++	{        /* MLC 40bit/1k */
++		.name      = "MT29F256G08CMCBB",
++		.id        = {0x2C, 0x64, 0x44, 0x4B, 0xA9, 0x00, 0x00, 0x00},
++		.length    = 8,
++		.chipsize  = _8G,
++		.probe     = NULL,
++		.pagesize  = _8K,
++		.erasesize = _2M,
++		.oobsize   = 744,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE,
++		.flags = 0,
++	},
++	{        /* SLC 8bit/512 */
++		.name      = "MT29F8G08ABACA",
++		.id        = {0x2C, 0xD3, 0x90, 0xA6, 0x64, 0x00, 0x00, 0x00},
++		.length    = 5,
++		.chipsize  = _1G,
++		.probe     = NULL,
++		.pagesize  = _4K,
++		.erasesize = _256K,
++		.oobsize   = 224,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE,
++		.flags = 0,
++	},
++	{        /* SLC 8bit/512 */
++		.name      = "MT29F4G08ABAEA",
++		.id        = {0x2C, 0xDC, 0x90, 0xA6, 0x54, 0x00, 0x00, 0x00},
++		.length    = 5,
++		.chipsize  = _512M,
++		.probe     = NULL,
++		.pagesize  = _4K,
++		.erasesize = _256K,
++		.oobsize   = 224,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE,
++		.flags = 0,
++	},
++	{        /* SLC 8bit/512 */
++		.name      = "MT29F2G08ABAFA",
++		.id        = {0x2C, 0xDA, 0x90, 0x95, 0x04, 0x00, 0x00, 0x00},
++		.length    = 5,
++		.chipsize  = _256M,
++		.probe     = NULL,
++		.pagesize  = _2K,
++		.erasesize = _128K,
++		.oobsize   = 224,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE,
++		.flags = 0,
++	},
++	{		/* SLC MT29F2G08ABAEA */
++		.name      = "MT29F2G08ABAEA",
++		.id        = {0x2C, 0xDA, 0x90, 0x95, 0x06, 0x00, 0x00, 0x00},
++		.length    = 5,
++		.chipsize  = _256M,
++		.probe     = NULL,
++		.pagesize  = _2K,
++		.erasesize = _128K,
++		.oobsize   = 64,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE,
++		.flags = 0,
++	},
++	{        /* SLC 8bit/512 */
++		.name      = "MT29F16G08ABACA",
++		.id        = {0x2C, 0x48, 0x00, 0x26, 0xA9, 0x00, 0x00, 0x00},
++		.length    = 5,
++		.chipsize  = _2G,
++		.probe     = NULL,
++		.pagesize  = _4K,
++		.erasesize = _512K,
++		.oobsize   = 224,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE,
++		.flags = 0,
++	},
++
++	/****************************** Toshaba *******************************/
++
++	{       /* MLC 24bit/1k 32nm */
++		.name      = "TC58NVG4D2FTA00",
++		.id        = {0x98, 0xD5, 0x94, 0x32, 0x76, 0x55, 0x00, 0x00},
++		.length    = 6,
++		.chipsize  = _2G,
++		.probe     = NULL,
++		.pagesize  = _8K,
++		.erasesize = _1M,
++		.oobsize   = 448,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE | BBP_LAST_PAGE,
++		.flags = 0,
++	},
++	{       /* MLC 24bit/1k 32nm 2CE*/
++		.name      = "TH58NVG6D2FTA20",
++		.id        = {0x98, 0xD7, 0x94, 0x32, 0x76, 0x55, 0x00, 0x00},
++		.length    = 6,
++		.chipsize  = _4G,
++		.probe     = NULL,
++		.pagesize  = _8K,
++		.erasesize = _1M,
++		.oobsize   = 448,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE | BBP_LAST_PAGE,
++		.flags = 0,
++	},
++	{       /* MLC 40bit/1k 24nm */
++		.name      = "TC58NVG5D2HTA00 24nm",
++		.id        = {0x98, 0xD7, 0x94, 0x32, 0x76, 0x56, 0x08, 0x00},
++		.length    = 6,
++		.chipsize  = _4G,
++		.probe     = NULL,
++		.pagesize  = _8K,
++		.erasesize = _1M,
++		.oobsize   = 640,
++		.options   = 0,
++		.read_retry_type = NAND_RR_TOSHIBA_24nm,
++		.badblock_pos    = BBP_FIRST_PAGE | BBP_LAST_PAGE,
++		.flags = NAND_RANDOMIZER,
++	},
++	{       /* MLC 40bit/1k */
++		.name      = "TC58NVG6D2GTA00",
++		.id        = {0x98, 0xDE, 0x94, 0x82, 0x76, 0x00, 0x00, 0x00},
++		.length    = 5,
++		.chipsize  = _8G,
++		.probe     = NULL,
++		.pagesize  = _8K,
++		.erasesize = _2M,
++		.oobsize   = 640,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE | BBP_LAST_PAGE,
++		.flags = 0,
++	},
++	{       /* MLC 19nm */
++		.name      = "TC58NVG6DCJTA00 19nm",
++		.id        = {0x98, 0xDE, 0x84, 0x93, 0x72, 0x57, 0x08, 0x04},
++		.length    = 8,
++		.chipsize  = _8G,
++		.probe     = NULL,
++		.pagesize  = _16K,
++		.erasesize = _4M,
++		.oobsize   = 1280,
++		.options   = 0,
++		.read_retry_type = NAND_RR_TOSHIBA_24nm,
++		.badblock_pos    = BBP_FIRST_PAGE | BBP_LAST_PAGE,
++		.flags = NAND_RANDOMIZER,
++	},
++	{       /* MLC 19nm */
++		.name      = "TC58TEG5DCJTA00 19nm",
++		.id        = {0x98, 0xD7, 0x84, 0x93, 0x72, 0x57, 0x08, 0x04},
++		.length    = 6,
++		.chipsize  = _4G,
++		.probe     = NULL,
++		.pagesize  = _16K,
++		.erasesize = _4M,
++		.oobsize   = 1280,
++		.options   = 0,
++		.read_retry_type = NAND_RR_TOSHIBA_24nm,
++		.badblock_pos    = BBP_FIRST_PAGE | BBP_LAST_PAGE,
++		.flags = NAND_RANDOMIZER | NAND_CHIP_TOSHIBA_TOGGLE_10,
++	},
++	{       /* SLC 8bit/512 */
++		.name      = "TC58NVG0S3HTA00",
++		.id        = {0x98, 0xF1, 0x80, 0x15, 0x72, 0x00, 0x00, 0x00},
++		.length    = 5,
++		.chipsize  = _128M,
++		.probe     = NULL,
++		.pagesize  = _2K,
++		.erasesize = _128K,
++		.oobsize   = 128,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		/*
++		 * Datasheet: read one column of any page in each block. If the
++		 * data of the column is 00 (Hex), define the block as a bad
++		 * block.
++		 */
++		.badblock_pos    = BBP_FIRST_PAGE,
++		.flags = 0,
++	},
++	{       /* SLC 8bit/512 */
++		.name      = "TC58NVG1S3HTA00",
++		.id        = {0x98, 0xDA, 0x90, 0x15, 0x76, 0x16, 0x08, 0x00},
++		.length    = 7,
++		.chipsize  = _256M,
++		.probe     = NULL,
++		.pagesize  = _2K,
++		.erasesize = _128K,
++		.oobsize   = 128,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE,
++		.flags = 0,
++	},
++	{       /* SLC 4bit/512 */
++		.name      = "TC58NVG1S3ETA00",
++		.id        = {0x98, 0xDA, 0x90, 0x15, 0x76, 0x14, 0x03, 0x00},
++		.length    = 7,
++		.chipsize  = _256M,
++		.probe     = NULL,
++		.pagesize  = _2K,
++		.erasesize = _128K,
++		.oobsize   = 64,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE,
++		.flags = 0,
++	},
++	{       /* SLC 4bit/512 */
++		.name      = "TC58NVG3S0FTA00",
++		.id        = {0x98, 0xD3, 0x90, 0x26, 0x76, 0x15, 0x02, 0x08},
++		.length    = 8,
++		.chipsize  = _1G,
++		.probe     = NULL,
++		.pagesize  = _4K,
++		.erasesize = _256K,
++		.oobsize   = 232,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE,
++		.flags = 0,
++	},
++	{       /* SLC 24bit/1k */
++		.name      = "TC58NVG3S0HTA00",
++		.id        = {0x98, 0xD3, 0x91, 0x26, 0x76, 0x16, 0x08, 0x00},
++		.length    = 8,
++		.chipsize  = _1G,
++		.probe     = NULL,
++		.pagesize  = _4K,
++		.erasesize = _256K,
++		.oobsize   = 256,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE,
++		.flags = 0,
++	},
++	{       /* SLC 24bit/1k */
++		.name      = "TC58NVG2S0HTA00",
++		.id        = {0x98, 0xDC, 0x90, 0x26, 0x76, 0x16, 0x08, 0x00},
++		.length    = 8,
++		.chipsize  = _512M,
++		.probe     = NULL,
++		.pagesize  = _4K,
++		.erasesize = _256K,
++		.oobsize   = 256,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE,
++		.flags = 0,
++	},
++	{       /* SLC 4bit/512 */
++		.name      = "TC58NVG2S0FTA00",
++		.id        = {0x98, 0xDC, 0x90, 0x26, 0x76, 0x15, 0x01, 0x08},
++		.length    = 8,
++		.chipsize  = _512M,
++		.probe     = NULL,
++		.pagesize  = _4K,
++		.erasesize = _256K,
++		.oobsize   = 224,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE,
++		.flags = 0,
++	},
++	{       /* SLC 4bit/512 */
++		.name      = "TH58NVG2S3HTA00",
++		.id        = {0x98, 0xDC, 0x91, 0x15, 0x76},
++		.length    = 5,
++		.chipsize  = _512M,
++		.probe     = NULL,
++		.pagesize  = _2K,
++		.erasesize = _128K,
++		.oobsize   = 128,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE,
++		.flags = 0,
++	},
++	{       /* TLC 60bit/1k 19nm */
++		.name      = "TC58NVG5T2JTA00 19nm TLC",
++		/* datasheet says 6 ids id data, but really has 8 ids. */
++		.id        = {0x98, 0xD7, 0x98, 0x92, 0x72, 0x57, 0x08, 0x10},
++		.length    = 6,
++		.chipsize  = _4G,
++		.probe     = NULL,
++		.pagesize  = _8K,
++		.erasesize = _4M,
++		.oobsize   = 1024,
++		.options   = 0,
++		.read_retry_type = NAND_RR_TOSHIBA_24nm,
++		.badblock_pos    = BBP_FIRST_PAGE | BBP_LAST_PAGE,
++		.flags = NAND_RANDOMIZER,
++	},
++	{	/* TLC 60bit/1k 19nm */
++		.name	   = "TC58TEG5DCKTAx0 19nm MLC",
++		/* datasheet says 6 ids id data, but really has 8 ids. */
++		.id	   = {0x98, 0xD7, 0x84, 0x93, 0x72, 0x50, 0x08, 0x04},
++		.length    = 6,
++		.chipsize  = _4G,
++		.probe	   = NULL,
++		.pagesize  = _16K,
++		.erasesize = _4M,
++		.oobsize   = 1280,
++		.options   = 0,
++		.read_retry_type = NAND_RR_TOSHIBA_19nm,
++		.badblock_pos	 = BBP_FIRST_PAGE | BBP_LAST_PAGE,
++		.flags = NAND_RANDOMIZER,
++	},
++	{
++		.name	   = "Tx58TEGxDDKTAx0 19nm MLC",
++		.id	   = {0x98, 0xDE, 0x94, 0x93, 0x76, 0x50},
++		.length    = 6,
++		.chipsize  = _4G,
++		.probe	   = NULL,
++		.pagesize  = _16K,
++		.erasesize = _4M,
++		.oobsize   = 1280,
++		.options   = 0,
++		.read_retry_type = NAND_RR_TOSHIBA_19nm,
++		.badblock_pos	 = BBP_FIRST_PAGE | BBP_LAST_PAGE,
++		.flags = NAND_RANDOMIZER,
++	},
++	/******************************* Samsung ******************************/
++	{       /* MLC 8bit/512B */
++		.name     = "K9LB(HC/PD/MD)G08U0(1)D",
++		.id       = {0xEC, 0xD7, 0xD5, 0x29, 0x38, 0x41, 0x00, 0x00},
++		.length   = 6,
++		.chipsize = _4G,
++		.probe    = samsung_probe_v02,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_LAST_PAGE,
++		.flags = 0,
++	},
++	{       /* MLC 24bit/1KB */
++		.name      = "K9GAG08U0E",
++		.id        = {0xEC, 0xD5, 0x84, 0x72, 0x50, 0x42, 0x00, 0x00},
++		.length    = 6,
++		.chipsize  = _2G,
++		.probe     = samsung_probe_v02,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE | BBP_LAST_PAGE,
++		.flags = 0,
++	},
++	{       /* MLC 24bit/1KB */
++		.name     = "K9LBG08U0E",
++		.id       = {0xEC, 0xD7, 0xC5, 0x72, 0x54, 0x42, 0x00, 0x00},
++		.length   = 6,
++		.chipsize = _4G,
++		.probe    = samsung_probe_v02,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE | BBP_LAST_PAGE,
++		.flags = 0,
++	},
++	{       /* MLC 24bit/1KB */
++		.name     = "K9G8G08U0C",
++		.id       = {0xEC, 0xD3, 0x84, 0x72, 0x50, 0x42, 0x00, 0x00},
++		.length   = 6,
++		.chipsize = _1G,
++		.probe    = samsung_probe_v02,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE | BBP_LAST_PAGE,
++		.flags = 0,
++	},
++	{        /* MLC 24bit/1k */
++		.name      = "K9GAG08U0F",
++		.id        = {0xEC, 0xD5, 0x94, 0x76, 0x54, 0x43, 0x00, 0x00},
++		.length    = 6,
++		.chipsize  = _2G,
++		.probe     = NULL,
++		.pagesize  = _8K,
++		.erasesize = _1M,
++		.oobsize   = 512,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE | BBP_LAST_PAGE,
++		.flags = 0,
++	},
++	{        /* MLC */
++		.name      = "K9LBG08U0M",
++		.id        = {0xEC, 0xD7, 0x55, 0xB6, 0x78, 0x00, 0x00, 0x00},
++		.length    = 5,
++		.chipsize  = _4G,
++		.probe     = NULL,
++		.pagesize  = _4K,
++		.erasesize = _512K,
++		.oobsize   = 128,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_LAST_PAGE,
++		.flags = 0,
++	},
++	{        /* MLC 24bit/1k */
++		.name      = "K9GBG08U0A 20nm",
++		.id        = {0xEC, 0xD7, 0x94, 0x7A, 0x54, 0x43, 0x00, 0x00},
++		.length    = 6,
++		.chipsize  = _4G,
++		.probe     = NULL,
++		.pagesize  = _8K,
++		.erasesize = _1M,
++		.oobsize   = 640,
++		.options   = 0,
++		.read_retry_type = NAND_RR_SAMSUNG,
++		.badblock_pos    = BBP_FIRST_PAGE | BBP_LAST_PAGE,
++		.flags = NAND_RANDOMIZER,
++	},
++	{        /* MLC 40bit/1k */
++		.name      = "K9GBG08U0B",
++		.id        = {0xEC, 0xD7, 0x94, 0x7E, 0x64, 0x44, 0x00, 0x00},
++		.length    = 6,
++		.chipsize  = _4G,
++		.probe     = NULL,
++		.pagesize  = _8K,
++		.erasesize = _1M,
++		.oobsize   = 1024,
++		.options   = 0,
++		.read_retry_type = NAND_RR_SAMSUNG,
++		.badblock_pos    = BBP_FIRST_PAGE | BBP_LAST_PAGE,
++		.flags = NAND_RANDOMIZER,
++	},
++
++	/*********************************** Hynix ****************************/
++	{       /* MLC */
++		.name     = "H27UAG8T2A",
++		.id       = {0xAD, 0xD5, 0x94, 0x25, 0x44, 0x41, },
++		.length   = 6,
++		.chipsize = _2G,
++		.probe    = hynix_probe_v02,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE | BBP_LAST_PAGE,
++		.flags = 0,
++	},
++	{       /* MLC */
++		.name     = "H27UAG8T2B",
++		.id       = {0xAD, 0xD5, 0x94, 0x9A, 0x74, 0x42, },
++		.length   = 6,
++		.chipsize = _2G,
++		.probe    = hynix_probe_v02,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE | BBP_LAST_PAGE,
++		.flags = 0,
++	},
++	{       /* MLC */
++		.name     = "H27UBG8T2A",
++		.id       = {0xAD, 0xD7, 0x94, 0x9A, 0x74, 0x42, },
++		.length   = 6,
++		.chipsize = _4G,
++		.probe    = hynix_probe_v02,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE | BBP_LAST_PAGE,
++		.flags = 0,
++	},
++	{       /* MLC 24bit/1K, 26nm TODO: Need read retry, chip is EOS */
++		.name      = "H27UBG8T2BTR 26nm",
++		.id        = {0xAD, 0xD7, 0x94, 0xDA, 0x74, 0xC3, },
++		.length    = 6,
++		.chipsize  = _4G,
++		.probe     = NULL,
++		.pagesize  = _8K,
++		.erasesize = _2M,
++		.oobsize   = 640,
++		.options   = 0,
++		.read_retry_type = NAND_RR_HYNIX_BG_BDIE,
++		.badblock_pos    = BBP_FIRST_PAGE | BBP_LAST_PAGE,
++		.flags = NAND_RANDOMIZER,
++	},
++	{        /* MLC 40bit/1k */
++		.name      = "H27UCG8T2A",
++		.id        = {0xAD, 0xDE, 0x94, 0xDA, 0x74, 0xC4, },
++		.length    = 6,
++		.chipsize  = _8G,
++		.probe     = NULL,
++		.pagesize  = _8K,
++		.erasesize = _2M,
++		.oobsize   = 640,
++		.options   = 0,
++		.read_retry_type = NAND_RR_HYNIX_CG_ADIE,
++		.badblock_pos    = BBP_FIRST_PAGE | BBP_LAST_PAGE,
++		.flags = NAND_RANDOMIZER,
++	},
++	{        /* MLC 40bit/1k */
++		.name      = "H27UBG8T2C",
++		.id        = {0xAD, 0xD7, 0x94, 0x91, 0x60, 0x44, },
++		.length    = 6,
++		.chipsize  = _4G,
++		.probe     = NULL,
++		.pagesize  = _8K,
++		.erasesize = _2M,
++		.oobsize   = 640,
++		.options   = 0,
++		.read_retry_type = NAND_RR_HYNIX_BG_CDIE,
++		.badblock_pos    = BBP_FIRST_PAGE | BBP_LAST_PAGE,
++		.flags = NAND_RANDOMIZER,
++	},
++
++	/********************** MISC ******************************************/
++	{        /* MLC 8bit/512 */
++		.name      = "P1UAGA30AT-GCA",
++		.id        = {0xC8, 0xD5, 0x14, 0x29, 0x34, 0x01, },
++		.length    = 6,
++		.chipsize  = _2G,
++		.probe     = NULL,
++		.pagesize  = _4K,
++		.erasesize = _512K,
++		.oobsize   = 218,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE | BBP_LAST_PAGE,
++		.flags = 0,
++	},
++	{       /* MLC 4bit/512 */
++		/*
++		 * PowerFlash ASU8GA30IT-G30CA ID and MIRA PSU8GA30AT-GIA ID are
++		 * the same ID
++		 */
++		.name      = "PSU8GA30AT-GIA/ASU8GA30IT-G30CA",
++		.id        = {0xC8, 0xD3, 0x90, 0x19, 0x34, 0x01, },
++		.length    = 6,
++		.chipsize  = _1G,
++		.probe     = NULL,
++		.pagesize  = _4K,
++		.erasesize = _256K,
++		.oobsize   = 218,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE | BBP_LAST_PAGE,
++		.flags = 0,
++	},
++	{        /* SLC 1bit/512 */
++		.name      = "PSU2GA30AT",
++		.id        = {0x7F, 0x7F, 0x7F, 0x7F, 0xC8, 0xDA, 0x00, 0x15, },
++		.length    = 8,
++		.chipsize  = _256M,
++		.probe     = NULL,
++		.pagesize  = _2K,
++		.erasesize = _128K,
++		.oobsize   = 64,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE | BBP_LAST_PAGE,
++		.flags = 0,
++	},
++	{{0}, 0, 0, 0, 0, 0, 0, 0, 0},
++};
++
++struct nand_dev_t g_nand_dev;
++/*****************************************************************************/
++struct nand_flash_dev *hifmc_get_spl_flash_type(struct mtd_info *mtd,
++		unsigned char *id)
++{
++	struct nand_chip *chip = mtd->priv;
++	struct nand_flash_special_dev *spl_dev = nand_flash_special_table;
++	struct nand_flash_dev *type = &g_nand_dev.flash_dev;
++	struct nand_dev_t *nand_dev = &g_nand_dev;
++
++	FMC_PR(BT_DBG, "\t *-Start find special nand flash\n");
++
++	pr_info("Nand ID: %#X %#X %#X %#X %#X %#X %#X %#X\n", id[0], id[1],
++			id[2], id[3], id[4], id[5], id[6], id[7]);
++
++	for (; spl_dev->length; spl_dev++) {
++		if (memcmp(id, spl_dev->id, spl_dev->length))
++			continue;
++
++		FMC_PR(BT_DBG, "\t |-Found special Nand flash: %s\n",
++				spl_dev->name);
++
++		if (spl_dev->probe) {
++			type = spl_dev->probe(id);
++		} else {
++			type->options   = spl_dev->options;
++			type->pagesize  = spl_dev->pagesize;
++			type->erasesize = spl_dev->erasesize;
++			type->oobsize = spl_dev->oobsize;
++		}
++
++		type->name = spl_dev->name;
++		type->id_len = spl_dev->length;
++		memcpy(type->id, id, type->id_len);
++		type->chipsize = (unsigned int)(spl_dev->chipsize >> 20);
++		FMC_PR(BT_DBG, "\t |-Save struct nand_flash_dev info\n");
++
++		memcpy(nand_dev->ids, id, MAX_NAND_ID_LEN);
++		nand_dev->oobsize = type->oobsize;
++		nand_dev->flags = spl_dev->flags;
++		nand_dev->read_retry_type = spl_dev->read_retry_type;
++		FMC_PR(BT_DBG, "\t |-Save struct nand_dev_t information\n");
++
++		mtd->size = spl_dev->chipsize;
++
++		return type;
++	}
++	nand_dev->read_retry_type = NAND_RR_NONE;
++
++	chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
++	chip->read_byte(mtd);
++	chip->read_byte(mtd);
++
++	FMC_PR(BT_DBG, "\t *-Not found special nand flash\n");
++
++	return NULL;
++}
++
++/*****************************************************************************/
++void hifmc_spl_ids_register(void)
++{
++	pr_info("Special NAND id table Version %s\n", DRV_VERSION);
++	get_spi_nand_flash_type_hook = hifmc_get_spl_flash_type;
++}
+diff --git a/drivers/mtd/nand/hinfc610/Kconfig b/drivers/mtd/nand/hinfc610/Kconfig
+new file mode 100644
+index 0000000..7d9dbbe
+--- /dev/null
++++ b/drivers/mtd/nand/hinfc610/Kconfig
+@@ -0,0 +1,100 @@
++menuconfig MTD_NAND_HINFC610
++	tristate "Hisilicon NAND Controller v610 device Support"
++	depends on MTD_NAND
++	default y if ARCH_HI3531D
++	select YAFFS_FS
++	select MISC_FILESYSTEMS
++	select MTD_BLOCK
++	select YAFFS_YAFFS2
++	help
++	  When the config is set, the kernel will support Hisilicon
++	  NAND Controller v610 device. It means that the kernel would
++	  control the nand flash with the nand controller v610 device
++	  in operation.
++
++if MTD_NAND_HINFC610
++
++config MTD_PARTITION_FROM_DTS
++	bool "get the mtd partition from devicetree"
++	default n
++	help
++	  Get the mtd partition info from devicetree list.
++
++config HINFC610_MAX_CHIP
++	int "number of nand flash chip (1,4)"
++	default 1
++	help
++	  nand controller v610 device only support 1 or 2 nand flash chip,
++	  your should not config other value.
++
++config HINFC610_DBG_NAND_DEBUG
++	bool "Debug: create debug file to control debug type"
++	default y
++	help
++	  When the config is set, the kernel will add the "debug" file
++	  to control debug type. When the config is set, we could choose
++	  the debugging type to display the informations of the nand controller
++	  v610 device in operation.
++
++config HINFC610_DBG_NAND_DUMP
++	bool "Debug: display read/write/erase process nand data"
++	depends on HINFC610_DBG_NAND_DEBUG
++	default y
++	default n if (ARCH_HI3531D)
++	help
++	  When the config is set, the kernel will add "dump" file to
++	  display all nand operation and data.When the "HINFC610_DBG_NAND_DEBUG"
++	  has been set, the nand controller v610 device will display
++	  all the operations and data.
++
++config HINFC610_DBG_NAND_ERASE_COUNT
++	bool "Debug: display last erase count"
++	depends on HINFC610_DBG_NAND_DEBUG
++	default y
++	default n if (ARCH_HI3531D)
++	help
++	  When the config is set, the kernel will add "erase_count" file
++	  to display last erase count. When the "HINFC610_DBG_NAND_DEBUG"
++	  has been set, the nand controller v610 device will display
++	  the last erase count.
++
++config HINFC610_DBG_NAND_ECC_COUNT
++	bool "Debug: display last ecc count."
++	depends on HINFC610_DBG_NAND_DEBUG
++	default y
++	default n if (ARCH_HI3531D)
++	help
++	  When the config is set, the kernel will add "ecc_count"
++	  to display last ecc count. When the "HINFC610_DBG_NAND_DEBUG"
++	  has been set, the nand controller v610 device will display
++	  the last ecc count.
++
++config HINFC610_DBG_NAND_READ_RETRY
++	bool "Debug: display read_retry process"
++	depends on HINFC610_DBG_NAND_DEBUG
++	default y
++	default n if (ARCH_HI3531D)
++	help
++	  When the config is set, the kernel will add read_retry file
++	  to display read_retry process.
++
++choice
++	prompt "Pagesize and Ecc Type Select"
++	default HINFC610_AUTO_PAGESIZE_ECC if ARCH_HI3531D
++
++config HINFC610_AUTO_PAGESIZE_ECC
++	bool "Auto"
++	help
++	  When the config is set, pagesize and ecc type will use
++	  hardware config. When we replace the flash, the
++	  controller will identify the pagesize and ecc type of
++	  the flash.
++
++config HINFC610_PAGESIZE_AUTO_ECC_NONE
++	bool "Pagesize Auto, Ecc None"
++	help
++	  select pagesize 2K, ecc none.
++
++endchoice
++
++endif # MTD_NAND_HINFC610
+diff --git a/drivers/mtd/nand/hinfc610/Makefile b/drivers/mtd/nand/hinfc610/Makefile
+new file mode 100644
+index 0000000..9ef9acd
+--- /dev/null
++++ b/drivers/mtd/nand/hinfc610/Makefile
+@@ -0,0 +1,19 @@
++
++obj-$(CONFIG_MTD_NAND_HINFC610) += hinfc610.o hinfc610_os.o hinfc610_gen.o \
++	hinfc620_gen.o hinfc610_dbg_inf.o \
++	hinfc610_read_retry_hynix_bg_cdie.o \
++	hinfc610_read_retry_hynix_bg_bdie.o \
++	hinfc610_read_retry_hynix_cg_adie.o \
++	hinfc610_read_retry_micron.o  \
++	hinfc610_read_retry_samsung.o \
++	hinfc610_read_retry_toshiba.o \
++	hinfc610_read_retry.o \
++	hinfc610_sync.o \
++	hinfc610_sync_onfi_23.o \
++	hinfc610_sync_toggle.o
++
++obj-$(CONFIG_HINFC610_DBG_NAND_DEBUG) += hinfc610_dbg.o hinfc610_dbg_ecc_dump.o
++obj-$(CONFIG_HINFC610_DBG_NAND_DUMP) += hinfc610_dbg_dump.o
++obj-$(CONFIG_HINFC610_DBG_NAND_ERASE_COUNT) += hinfc610_dbg_erase_count.o
++obj-$(CONFIG_HINFC610_DBG_NAND_ECC_COUNT) += hinfc610_dbg_ecc_count.o
++obj-$(CONFIG_HINFC610_DBG_NAND_READ_RETRY) += hinfc610_dbg_read_retry.o
+diff --git a/drivers/mtd/nand/hinfc610/hinfc610.c b/drivers/mtd/nand/hinfc610/hinfc610.c
+new file mode 100644
+index 0000000..4be2451
+--- /dev/null
++++ b/drivers/mtd/nand/hinfc610/hinfc610.c
+@@ -0,0 +1,1154 @@
++/*
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#define pr_fmt(fmt) "hinfc610: " fmt
++
++#include "hinfc610_os.h"
++#include "hinfc610.h"
++#include "hinfc610_dbg_inf.h"
++#include "hinfc610_gen.h"
++#include "hinfc620_gen.h"
++#include "hinfc610_sync.h"
++#include "hinfc610_read_retry.h"
++
++/*****************************************************************************/
++static unsigned int get_8bits(unsigned char byte)
++{
++	int ix = 0;
++	int num = 0;
++
++	if (byte == 0xFF)
++		return 8;
++	if (!byte)
++		return 0;
++
++	while (ix++ < 8) {
++		if ((byte & 1))
++			num++;
++		byte = (byte >> 1);
++	}
++	return num;
++}
++/*****************************************************************************/
++
++static unsigned int get_16bits(unsigned short byte)
++{
++	int ix = 0;
++	int num = 0;
++
++	if (byte == 0xFFFF)
++		return 16;
++	if (!byte)
++		return 0;
++
++	while (ix++ < 16) {
++		if ((byte & 1))
++			num++;
++		byte = (byte >> 1);
++	}
++	return num;
++}
++/*****************************************************************************/
++
++static void hinfc610_dma_transfer(struct hinfc_host *host, int todev)
++{
++	unsigned long reg_val;
++	unsigned int dma_addr = (unsigned int)host->dma_buffer;
++
++	hinfc_write(host, dma_addr, HINFC610_DMA_ADDR_DATA);
++
++	dma_addr += HINFC610_DMA_ADDR_OFFSET;
++	hinfc_write(host, dma_addr, HINFC610_DMA_ADDR_DATA1);
++
++	dma_addr += HINFC610_DMA_ADDR_OFFSET;
++	hinfc_write(host, dma_addr, HINFC610_DMA_ADDR_DATA2);
++
++	dma_addr += HINFC610_DMA_ADDR_OFFSET;
++	hinfc_write(host, dma_addr, HINFC610_DMA_ADDR_DATA3);
++
++	/* 32K PAGESIZE need below. */
++	dma_addr += HINFC610_DMA_ADDR_OFFSET;
++	hinfc_write(host, dma_addr, HINFC610_DMA_ADDR_DATA4);
++
++	dma_addr += HINFC610_DMA_ADDR_OFFSET;
++	hinfc_write(host, dma_addr, HINFC610_DMA_ADDR_DATA5);
++
++	dma_addr += HINFC610_DMA_ADDR_OFFSET;
++	hinfc_write(host, dma_addr, HINFC610_DMA_ADDR_DATA6);
++
++	dma_addr += HINFC610_DMA_ADDR_OFFSET;
++	hinfc_write(host, dma_addr, HINFC610_DMA_ADDR_DATA7);
++
++	hinfc_write(host, host->dma_oob, HINFC610_DMA_ADDR_OOB);
++
++	if (host->ecctype == NAND_ECC_NONE) {
++		hinfc_write(host,
++			((host->oobsize & HINFC610_DMA_LEN_OOB_MASK)
++			 << HINFC610_DMA_LEN_OOB_SHIFT),
++			HINFC610_DMA_LEN);
++
++		hinfc_write(host,
++			HINFC610_DMA_PARA_DATA_RW_EN
++			| HINFC610_DMA_PARA_OOB_RW_EN,
++			HINFC610_DMA_PARA);
++	} else
++		hinfc_write(host,
++			HINFC610_DMA_PARA_DATA_RW_EN
++			| HINFC610_DMA_PARA_OOB_RW_EN
++			| HINFC610_DMA_PARA_DATA_EDC_EN
++			| HINFC610_DMA_PARA_OOB_EDC_EN,
++			HINFC610_DMA_PARA);
++
++	reg_val = (HINFC610_DMA_CTRL_DMA_START
++		| HINFC610_DMA_CTRL_BURST4_EN
++		| HINFC610_DMA_CTRL_BURST8_EN
++		| HINFC610_DMA_CTRL_BURST16_EN
++		| ((host->addr_cycle == 4 ? 1 : 0)
++		   << HINFC610_DMA_CTRL_ADDR_NUM_SHIFT)
++		| (((unsigned int)host->chipselect & HINFC610_DMA_CTRL_CS_MASK)
++		   << HINFC610_DMA_CTRL_CS_SHIFT));
++
++	if (todev)
++		reg_val |= HINFC610_DMA_CTRL_WE;
++
++	hinfc_write(host, reg_val, HINFC610_DMA_CTRL);
++
++	do {
++		unsigned int timeout = 0xF0000000;
++
++		while ((hinfc_read(host, HINFC610_DMA_CTRL))
++			& HINFC610_DMA_CTRL_DMA_START && timeout) {
++			_cond_resched();
++			timeout--;
++		}
++		if (!timeout)
++			PR_BUG("Wait DMA finish timeout.\n");
++	} while (0);
++}
++/*****************************************************************************/
++
++static void hinfc610_sync_entry(struct hinfc_host *host)
++{
++	struct nand_sync *sync = host->sync;
++	struct nand_chip *chip = host->chip;
++
++	if (!sync) {
++		PR_BUG("this NAND not support sync feature.\n");
++		return;
++	}
++
++	if (HINFC610_IS_SYNC(host)) {
++		PR_BUG("this NAND not support sync feature.\n");
++		return;
++	}
++
++	if (sync->enable)
++		sync->enable(chip);
++
++	clk_prepare_enable(host->clk);
++
++	switch (sync->type) {
++	case NAND_TYPE_TOGGLE_10:
++		host->NFC_CON |= HINFC610_CON_NF_MODE_TOGGLE;
++		host->NFC_CON_ECC_NONE |= HINFC610_CON_NF_MODE_TOGGLE;
++		break;
++
++	case NAND_TYPE_ONFI_23:
++		host->NFC_CON |= HINFC610_CON_NF_MODE_ONFI_23;
++		host->NFC_CON_ECC_NONE |= HINFC610_CON_NF_MODE_ONFI_23;
++		break;
++
++	case NAND_TYPE_ONFI_30:
++		host->NFC_CON |= HINFC610_CON_NF_MODE_ONFI_30;
++		host->NFC_CON_ECC_NONE |= HINFC610_CON_NF_MODE_ONFI_30;
++		break;
++
++	default:
++		PR_BUG("Unsupport sync type 0x%08X.\n", sync->type);
++		break;
++	}
++}
++/*****************************************************************************/
++
++static void hinfc610_sync_exit(struct hinfc_host *host)
++{
++	struct nand_sync *sync = host->sync;
++	struct nand_chip *chip = host->chip;
++
++	if (!HINFC610_IS_SYNC(host)) {
++		PR_BUG("Current already exit from sync feature.\n");
++		return;
++	}
++
++	if (sync->disable)
++		sync->disable(chip);
++
++	host->NFC_CON &= ~HINFC610_CON_NF_MODE_MASK;
++	host->NFC_CON_ECC_NONE &= ~HINFC610_CON_NF_MODE_MASK;
++
++	clk_disable_unprepare(host->clk);
++}
++/*****************************************************************************/
++
++void hinfc610_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
++{
++	int is_cache_invalid = 1;
++	struct nand_chip *chip = mtd->priv;
++	struct hinfc_host *host = chip->priv;
++
++	if (ctrl & NAND_ALE) {
++		unsigned int addr_value = 0;
++		unsigned int addr_offset = 0;
++
++		if (ctrl & NAND_CTRL_CHANGE) {
++			host->addr_cycle = 0x0;
++			host->addr_value[0] = 0x0;
++			host->addr_value[1] = 0x0;
++		}
++		addr_offset = host->addr_cycle << 3;
++
++		if (host->addr_cycle >= HINFC610_ADDR_CYCLE_MASK) {
++			addr_offset =
++			    (host->addr_cycle - HINFC610_ADDR_CYCLE_MASK) << 3;
++			addr_value = 1;
++		}
++
++		host->addr_value[addr_value] |=
++			((dat & 0xff) << addr_offset);
++
++		host->addr_cycle++;
++	}
++
++	if ((ctrl & NAND_CLE) && (ctrl & NAND_CTRL_CHANGE)) {
++		host->command = dat & 0xff;
++		switch (host->command) {
++		case NAND_CMD_PAGEPROG:
++			host->send_cmd_pageprog(host);
++			hinfc610_dbg_write(host);
++			break;
++
++		case NAND_CMD_READSTART:
++			is_cache_invalid = 0;
++			host->send_cmd_readstart(host);
++			hinfc610_dbg_read(host);
++
++			break;
++
++		case NAND_CMD_ERASE2:
++			host->send_cmd_erase(host);
++			hinfc610_dbg_erase(host);
++
++			break;
++
++		case NAND_CMD_READID:
++			memset((unsigned char *)(chip->IO_ADDR_R), 0, 0x10);
++			host->send_cmd_readid(host);
++			break;
++
++		case NAND_CMD_STATUS:
++			host->send_cmd_status(host);
++			break;
++
++		case NAND_CMD_SEQIN:
++		case NAND_CMD_ERASE1:
++		case NAND_CMD_READ0:
++			break;
++		case NAND_CMD_RESET:
++			host->send_cmd_reset(host, host->chipselect);
++			break;
++
++		default:
++			break;
++		}
++	}
++
++	if ((dat == NAND_CMD_NONE) && host->addr_cycle) {
++		if (host->command == NAND_CMD_SEQIN ||
++		    host->command == NAND_CMD_READ0 ||
++		    host->command == NAND_CMD_READID) {
++			host->offset = 0x0;
++			host->column = (host->addr_value[0] & 0xffff);
++		}
++	}
++
++	if (is_cache_invalid) {
++		host->cache_addr_value[0] = ~0;
++		host->cache_addr_value[1] = ~0;
++	}
++}
++/*****************************************************************************/
++
++static int hinfc610_send_cmd_pageprog(struct hinfc_host *host)
++{
++	if (*host->bbm != 0xFF && *host->bbm != 0x00)
++		pr_warn("Attempt to write an invalid bbm. page: 0x%08x, mark: 0x%02x, current process(pid): %s(%d).\n",
++			GET_PAGE_INDEX(host), *host->bbm,
++			current->comm, current->pid);
++
++	if (IS_NAND_SYNC_ASYNC(host))
++		hinfc610_sync_entry(host);
++
++	host->enable_ecc_randomizer(host, ENABLE, ENABLE);
++
++	hinfc_write(host, host->addr_value[0] & 0xffff0000, HINFC610_ADDRL);
++	hinfc_write(host, host->addr_value[1], HINFC610_ADDRH);
++	hinfc_write(host,
++		((NAND_CMD_STATUS << 16) | (NAND_CMD_PAGEPROG << 8) |
++		 NAND_CMD_SEQIN),
++		HINFC610_CMD);
++
++	*host->epm = 0x0000;
++
++	hinfc610_dma_transfer(host, 1);
++
++	if (IS_NAND_SYNC_ASYNC(host))
++		hinfc610_sync_exit(host);
++
++	return 0;
++}
++/*****************************************************************************/
++
++static int hinfc610_get_data_status(struct hinfc_host *host)
++{
++	unsigned int page_status = 0;
++
++	if (IS_PS_UN_ECC(host))
++		page_status = HINFC610_PS_UC_ECC;
++
++	/* this is block start address */
++	if (!((host->addr_value[0] >> 16) & host->block_page_mask)) {
++
++		/* it is a bad block */
++		if (*host->bbm == 0x00) {
++			page_status |= HINFC610_PS_BAD_BLOCK;
++			goto out;
++		}
++
++		if (*host->bbm != 0xFF) {
++			page_status |= HINFC610_PS_BBM_ERROR;
++
++			/*
++			 * if there are more than 2 bits flipping, it is
++			 * maybe a bad block
++			 */
++			if (!IS_PS_UN_ECC(host) || get_8bits(*host->bbm) < 6) {
++				page_status |= HINFC610_PS_BAD_BLOCK;
++				goto out;
++			}
++		}
++	}
++
++	if (*host->epm == 0x0000)
++		goto out;
++
++	if (*host->epm == 0xFFFF) {
++		page_status |= HINFC610_PS_EMPTY_PAGE;
++		goto out;
++	}
++
++	page_status |= HINFC610_PS_EPM_ERROR;
++
++	if (IS_PS_UN_ECC(host) && get_16bits(*host->epm) > 12) {
++		page_status |= HINFC610_PS_EMPTY_PAGE;
++		goto out;
++	}
++
++out:
++	return page_status;
++}
++/*****************************************************************************/
++
++static int hinfc610_do_read_retry(struct hinfc_host *host)
++{
++	int ix;
++
++	for (ix = 1; IS_PS_UN_ECC(host) && ix < host->read_retry->count; ix++) {
++
++		hinfc_write(host, HINFC610_INTCLR_UE | HINFC610_INTCLR_CE,
++			    HINFC610_INTCLR);
++
++		host->enable_ecc_randomizer(host, DISABLE, DISABLE);
++		host->read_retry->set_rr_param(host, ix);
++
++		/* enable ecc and randomizer */
++		host->enable_ecc_randomizer(host, ENABLE, ENABLE);
++
++		hinfc_write(host, HINFC610_INTCLR_UE | HINFC610_INTCLR_CE,
++			    HINFC610_INTCLR);
++		hinfc_write(host, host->NFC_CON, HINFC610_CON);
++		hinfc_write(host, host->addr_value[0] & 0xffff0000,
++			    HINFC610_ADDRL);
++		hinfc_write(host, host->addr_value[1], HINFC610_ADDRH);
++		hinfc_write(host,
++			    HINFC_CMD_SEQ(NAND_CMD_READ0, NAND_CMD_READSTART),
++			    HINFC610_CMD);
++
++		hinfc610_dma_transfer(host, 0);
++
++		if (hinfc_read(host, HINFC610_INTS) & HINFC610_INTS_UE)
++			host->page_status |= HINFC610_PS_UC_ECC;
++		else
++			host->page_status &= ~HINFC610_PS_UC_ECC;
++	}
++
++	host->page_status = hinfc610_get_data_status(host);
++
++	hinfc610_dbg_read_retry(host, ix);
++
++	host->enable_ecc_randomizer(host, DISABLE, DISABLE);
++	host->read_retry->reset_rr_param(host);
++
++	return 0;
++}
++/*****************************************************************************/
++
++static int hinfc610_send_cmd_readstart(struct hinfc_host *host)
++{
++	if ((host->addr_value[0] == host->cache_addr_value[0]) &&
++	    (host->addr_value[1] == host->cache_addr_value[1]))
++		return 0;
++
++	if (IS_NAND_SYNC_ASYNC(host))
++		hinfc610_sync_entry(host);
++
++	host->page_status = 0;
++
++	host->enable_ecc_randomizer(host, ENABLE, ENABLE);
++
++	hinfc_write(host, HINFC610_INTCLR_UE | HINFC610_INTCLR_CE,
++		    HINFC610_INTCLR);
++	hinfc_write(host, host->NFC_CON, HINFC610_CON);
++	hinfc_write(host, host->addr_value[0] & 0xffff0000, HINFC610_ADDRL);
++	hinfc_write(host, host->addr_value[1], HINFC610_ADDRH);
++	hinfc_write(host, NAND_CMD_READSTART << 8 | NAND_CMD_READ0,
++		    HINFC610_CMD);
++
++	hinfc610_dma_transfer(host, 0);
++
++	if (hinfc_read(host, HINFC610_INTS) & HINFC610_INTS_UE)
++		host->page_status |= HINFC610_PS_UC_ECC;
++
++	if (host->read_retry || IS_NAND_RANDOM(host)) {
++		host->page_status |= hinfc610_get_data_status(host);
++
++		if (IS_PS_EMPTY_PAGE(host)) {
++			/*
++			 * oob area used by yaffs2 only 32 bytes,
++			 * so we only fill 32 bytes.
++			 */
++			if (IS_NAND_RANDOM(host))
++				memset(host->buffer, 0xFF,
++				       host->pagesize + host->oobsize);
++
++		} else if (!IS_PS_BAD_BLOCK(host)) {
++			/* if NAND chip support read retry */
++			if (IS_PS_UN_ECC(host) && host->read_retry)
++				hinfc610_do_read_retry(host);
++
++		} /* 'else' NAND have a bad block, do nothing. */
++	}
++
++	if (IS_NAND_SYNC_ASYNC(host))
++		hinfc610_sync_exit(host);
++
++	host->cache_addr_value[0] = host->addr_value[0];
++	host->cache_addr_value[1] = host->addr_value[1];
++
++	return 0;
++}
++/*****************************************************************************/
++
++static int hinfc610_send_cmd_erase(struct hinfc_host *host)
++{
++	unsigned int regval;
++
++	/* Don't case the read retry config */
++	host->enable_ecc_randomizer(host, DISABLE, DISABLE);
++
++	hinfc_write(host, host->addr_value[0], HINFC610_ADDRL);
++	hinfc_write(host, (NAND_CMD_ERASE2 << 8) | NAND_CMD_ERASE1,
++		HINFC610_CMD);
++
++	regval = HINFC610_OP_WAIT_READY_EN
++		 | HINFC610_OP_CMD2_EN
++		 | HINFC610_OP_CMD1_EN
++		 | HINFC610_OP_ADDR_EN
++		 | (((unsigned int)host->chipselect & HINFC610_OP_NF_CS_MASK)
++		    << HINFC610_OP_NF_CS_SHIFT)
++		 | ((host->addr_cycle & HINFC610_OP_ADDR_CYCLE_MASK)
++		    << HINFC610_OP_ADDR_CYCLE_SHIFT);
++
++	hinfc_write(host, regval, HINFC610_OP);
++
++	WAIT_CONTROLLER_FINISH();
++
++	return 0;
++}
++/*****************************************************************************/
++
++static int hinfc610_send_cmd_sync_readid(struct hinfc_host *host)
++{
++	unsigned int regval;
++
++	host->enable_ecc_randomizer(host, DISABLE, DISABLE);
++
++	hinfc_write(host, HINFC610_NANDINFO_LEN, HINFC610_DATA_NUM);
++	hinfc_write(host, NAND_CMD_READID, HINFC610_CMD);
++	hinfc_write(host, 0, HINFC610_ADDRL);
++
++	/* no need to config HINFC610_OP_WAIT_READY_EN, here not config. */
++	regval = HINFC610_OP_CMD1_EN
++		 | HINFC610_OP_ADDR_EN
++		 | HINFC610_OP_READ_DATA_EN
++		 | (((unsigned int)host->chipselect & HINFC610_OP_NF_CS_MASK)
++		    << HINFC610_OP_NF_CS_SHIFT)
++		 | (1 << HINFC610_OP_ADDR_CYCLE_SHIFT)
++		 | HINFC610_OP_READID_EN
++		 | HINFC610_OP_RW_REG_EN;
++
++	hinfc_write(host, regval, HINFC610_OP);
++
++	host->addr_cycle = 0x0;
++
++	WAIT_CONTROLLER_FINISH();
++
++	return 0;
++}
++/*****************************************************************************/
++
++static int hinfc610_send_cmd_async_readid(struct hinfc_host *host)
++{
++	unsigned int regval;
++
++	host->enable_ecc_randomizer(host, DISABLE, DISABLE);
++
++	hinfc_write(host, HINFC610_NANDINFO_LEN, HINFC610_DATA_NUM);
++	hinfc_write(host, NAND_CMD_READID, HINFC610_CMD);
++	hinfc_write(host, 0, HINFC610_ADDRL);
++
++	/* no need to config HINFC610_OP_WAIT_READY_EN, here not config. */
++	regval = HINFC610_OP_CMD1_EN
++		 | HINFC610_OP_ADDR_EN
++		 | HINFC610_OP_READ_DATA_EN
++		 | (((unsigned int)host->chipselect & HINFC610_OP_NF_CS_MASK)
++		    << HINFC610_OP_NF_CS_SHIFT)
++		 | (1 << HINFC610_OP_ADDR_CYCLE_SHIFT);
++
++	hinfc_write(host, regval, HINFC610_OP);
++
++	host->addr_cycle = 0x0;
++
++	WAIT_CONTROLLER_FINISH();
++
++	return 0;
++}
++/*****************************************************************************/
++
++static int hinfc610_send_cmd_readid(struct hinfc_host *host)
++{
++	if (HINFC610_IS_SYNC(host))
++		return hinfc610_send_cmd_sync_readid(host);
++	else
++		return hinfc610_send_cmd_async_readid(host);
++}
++/*****************************************************************************/
++
++static int hinfc610_enable_ecc_randomizer(struct hinfc_host *host, int ecc_en,
++					  int randomizer_en)
++{
++	unsigned int nfc_con;
++
++	if (IS_NAND_RANDOM(host)) {
++		if (randomizer_en) {
++			host->NFC_CON |= HINFC610_CON_RANDOMIZER_EN;
++			host->NFC_CON_ECC_NONE |= HINFC610_CON_RANDOMIZER_EN;
++		} else {
++			host->NFC_CON &= ~HINFC610_CON_RANDOMIZER_EN;
++			host->NFC_CON_ECC_NONE &= ~HINFC610_CON_RANDOMIZER_EN;
++		}
++	}
++
++	nfc_con = (ecc_en ? host->NFC_CON : host->NFC_CON_ECC_NONE);
++
++	hinfc_write(host, nfc_con, HINFC610_CON);
++
++	return 0;
++}
++/*****************************************************************************/
++
++static int hinfc610_send_cmd_status(struct hinfc_host *host)
++{
++	unsigned int regval;
++
++	host->enable_ecc_randomizer(host, DISABLE, DISABLE);
++
++	hinfc_write(host, HINFC610_NANDINFO_LEN, HINFC610_DATA_NUM);
++	hinfc_write(host, NAND_CMD_STATUS, HINFC610_CMD);
++
++	/* no need config HINFC610_OP_WAIT_READY_EN, here not config */
++	regval = HINFC610_OP_CMD1_EN
++		 | HINFC610_OP_READ_DATA_EN
++		 | (((unsigned int)host->chipselect & HINFC610_OP_NF_CS_MASK)
++		    << HINFC610_OP_NF_CS_SHIFT);
++
++	hinfc_write(host, regval, HINFC610_OP);
++
++	WAIT_CONTROLLER_FINISH();
++
++	return 0;
++}
++
++/*****************************************************************************/
++static int hinfc610_send_cmd_async_reset(struct hinfc_host *host,
++					 int chipselect)
++{
++	unsigned int regval;
++
++	hinfc_write(host, NAND_CMD_RESET, HINFC610_CMD);
++
++	/* need to config HINFC610_OP_WAIT_READY_EN */
++	regval = HINFC610_OP_CMD1_EN
++		 | ((((unsigned int)chipselect & HINFC610_OP_NF_CS_MASK)
++		    << HINFC610_OP_NF_CS_SHIFT)
++		 | HINFC610_OP_WAIT_READY_EN);
++
++	hinfc_write(host, regval, HINFC610_OP);
++
++	WAIT_CONTROLLER_FINISH();
++
++	return 0;
++}
++/*****************************************************************************/
++
++static int hinfc610_send_cmd_sync_reset(struct hinfc_host *host,
++					int chipselect)
++{
++	unsigned int regval;
++
++	/*
++	 * Regarding the ONFI chip sync mode,
++	 * NAND_CMD_SYNC_RESET make chip remain sync mode.
++	 * But NAND_CMD_RESET will change chip mode to async mode.
++	 */
++	hinfc_write(host, NAND_CMD_SYNC_RESET, HINFC610_CMD);
++
++	/* need to config HINFC610_OP_WAIT_READY_EN */
++	regval = HINFC610_OP_CMD1_EN
++		 | (((unsigned int)chipselect & HINFC610_OP_NF_CS_MASK)
++		     << HINFC610_OP_NF_CS_SHIFT)
++		 | HINFC610_OP_WAIT_READY_EN;
++
++	hinfc_write(host, regval, HINFC610_OP);
++
++	WAIT_CONTROLLER_FINISH();
++
++	return 0;
++}
++/*****************************************************************************/
++
++static int hinfc610_send_cmd_reset(struct hinfc_host *host, int chipselect)
++{
++	if (HINFC610_IS_SYNC(host))
++		return hinfc610_send_cmd_sync_reset(host, chipselect);
++	else
++		return hinfc610_send_cmd_async_reset(host, chipselect);
++}
++/*****************************************************************************/
++
++int hinfc610_dev_ready(struct mtd_info *mtd)
++{
++	return 0x1;
++}
++/*****************************************************************************/
++
++void hinfc610_select_chip(struct mtd_info *mtd, int chipselect)
++{
++	struct nand_chip *chip = mtd->priv;
++	struct hinfc_host *host = chip->priv;
++
++	if (chipselect < 0)
++		return;
++
++	if (chipselect > CONFIG_HINFC610_MAX_CHIP)
++		PR_BUG("invalid chipselect: %d\n", chipselect);
++
++	host->chipselect = chipselect;
++}
++/*****************************************************************************/
++
++uint8_t hinfc610_read_byte(struct mtd_info *mtd)
++{
++	struct nand_chip *chip = mtd->priv;
++	struct hinfc_host *host = chip->priv;
++
++	if (host->command == NAND_CMD_STATUS)
++		return readb(chip->IO_ADDR_R);
++
++	host->offset++;
++
++	if (host->command == NAND_CMD_READID)
++		return readb(chip->IO_ADDR_R + host->offset - 1);
++
++	return readb(host->buffer + host->column + host->offset - 1);
++}
++/*****************************************************************************/
++
++u16 hinfc610_read_word(struct mtd_info *mtd)
++{
++	struct nand_chip *chip = mtd->priv;
++	struct hinfc_host *host = chip->priv;
++
++	host->offset += 2;
++	return readw(host->buffer + host->column + host->offset - 2);
++}
++/*****************************************************************************/
++
++void hinfc610_write_buf(struct mtd_info *mtd, const uint8_t *buf,
++			       int len)
++{
++	struct nand_chip *chip = mtd->priv;
++	struct hinfc_host *host = chip->priv;
++
++	memcpy(host->buffer + host->column + host->offset, buf, len);
++	host->offset += len;
++}
++/*****************************************************************************/
++static void hinfc610_ecc_err_num_count(struct mtd_info *mtd,
++		uint8_t ecc_st, int reg)
++{
++	u_char err_num;
++
++	if (ecc_st > 4)
++		ecc_st = 4;
++
++	while (ecc_st) {
++		err_num = GET_ECC_ERR_NUM(--ecc_st, reg);
++		if (err_num == 0xff)
++			mtd->ecc_stats.failed++;
++		else
++			mtd->ecc_stats.corrected += err_num;
++	}
++}
++
++/*****************************************************************************/
++
++void hinfc610_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
++{
++	struct nand_chip *chip = mtd->priv;
++	struct hinfc_host *host = chip->priv;
++	int reg;
++	uint8_t ecc_step = host->pagesize >> 10;
++
++	memcpy(buf, host->buffer + host->column + host->offset, len);
++	host->offset += len;
++
++	/* 2K or 4K or 8K(1) or 16K(1-1) pagesize */
++	reg = hinfc_read(host, HINFC_ECC_ERR_NUM0_BUF0);
++	hinfc610_ecc_err_num_count(mtd, ecc_step, reg);
++
++	if (ecc_step > 4) {
++		/* 8K(2) or 16K(1-2) pagesize */
++		reg = hinfc_read(host, HINFC_ECC_ERR_NUM1_BUF0);
++		hinfc610_ecc_err_num_count(mtd, ecc_step, reg);
++		if (ecc_step > 8) {
++			/* 16K(2-1) pagesize */
++			reg = hinfc_read(host, HINFC_ECC_ERR_NUM0_BUF1);
++			hinfc610_ecc_err_num_count(mtd, ecc_step, reg);
++			/* 16K(2-2) pagesize */
++			reg = hinfc_read(host, HINFC_ECC_ERR_NUM1_BUF1);
++			hinfc610_ecc_err_num_count(mtd, ecc_step, reg);
++		}
++	}
++}
++/*****************************************************************************/
++/*
++ * 'host->epm' only use the first oobfree[0] field, it looks very simple, But...
++ */
++static struct nand_ecclayout nand_ecc_default = {
++	.oobfree = {{2, 30} }
++};
++
++/*****************************************************************************/
++
++static struct nand_config_info hinfc610_soft_auto_config_table[] = {
++	{NAND_PAGE_16K, NAND_ECC_64BIT, 1824/*1824*/, &nand_ecc_default},
++	{NAND_PAGE_16K, NAND_ECC_40BIT, 1200/*1152*/, &nand_ecc_default},
++	{NAND_PAGE_16K, NAND_ECC_NONE,  32 ,          &nand_ecc_default},
++
++	{NAND_PAGE_8K, NAND_ECC_64BIT, 928 /*928*/,  &nand_ecc_default},
++	{NAND_PAGE_8K, NAND_ECC_40BIT, 600 /*592*/,  &nand_ecc_default},
++	{NAND_PAGE_8K, NAND_ECC_24BIT, 368 /*368*/,  &nand_ecc_default},
++	{NAND_PAGE_8K, NAND_ECC_NONE,  32,           &nand_ecc_default},
++
++	{NAND_PAGE_4K, NAND_ECC_24BIT, 200 /*200*/,  &nand_ecc_default},
++	{NAND_PAGE_4K, NAND_ECC_4BIT_512,  128  /*88*/,   &nand_ecc_default},
++	{NAND_PAGE_4K, NAND_ECC_NONE,  32,           &nand_ecc_default},
++
++	{NAND_PAGE_2K, NAND_ECC_24BIT, 128 /*116*/, &nand_ecc_default},
++	{NAND_PAGE_2K, NAND_ECC_4BIT_512,  64  /*60*/,  &nand_ecc_default},
++	{NAND_PAGE_2K, NAND_ECC_NONE,  32,          &nand_ecc_default},
++
++	{0, 0, 0, NULL},
++};
++/*****************************************************************************/
++/* used the best correct arithmetic. */
++struct nand_config_info *hinfc610_get_best_ecc(struct mtd_info *mtd)
++{
++	struct nand_config_info *best = NULL;
++	struct nand_config_info *config = hinfc610_soft_auto_config_table;
++
++	for (; config->layout; config++) {
++		if (nandpage_type2size(config->pagetype) != mtd->writesize)
++			continue;
++
++		if (mtd->oobsize < config->oobsize)
++			continue;
++
++		if (!best || (best->ecctype < config->ecctype))
++			best = config;
++	}
++
++	if (!best)
++		PR_BUG(ERSTR_DRIVER
++		       "Driver does not support the pagesize(%d) "
++		       "and oobsize(%d).\n",
++		       mtd->writesize, mtd->oobsize);
++
++	return best;
++}
++/*****************************************************************************/
++/* force the pagesize and ecctype */
++struct nand_config_info *hinfc610_force_ecc(struct mtd_info *mtd, int pagetype,
++					     int oobsize, char *cfgmsg,
++					     int allow_pagediv)
++{
++	struct nand_config_info *fit = NULL;
++	struct nand_config_info *config = hinfc610_soft_auto_config_table;
++
++	for (; config->layout; config++) {
++		if (config->pagetype == pagetype
++			&& config->oobsize <= oobsize) {
++			fit = config;
++			break;
++		}
++	}
++
++	if (!fit) {
++		PR_BUG(ERSTR_DRIVER
++		       "Driver(%s mode) does not support this Nand Flash "
++		       "pagesize:%s, oobsize:%d\n",
++		       cfgmsg,
++		       nand_page_name(pagetype),
++		       oobsize);
++		return NULL;
++	}
++	return fit;
++}
++/*****************************************************************************/
++static unsigned int  nand_otp_len;
++static unsigned char nand_otp[128] = {0};
++
++/* Get NAND parameter table. */
++static int __init parse_nand_param(const struct tag *tag)
++{
++	if (tag->hdr.size <= 2)
++		return 0;
++
++	nand_otp_len = ((tag->hdr.size << 2) - sizeof(struct tag_header));
++
++	if (nand_otp_len > sizeof(nand_otp)) {
++		pr_warn("%s(%d): Get Nand OTP from tag fail.\n",
++			__func__, __LINE__);
++		return 0;
++	}
++	memcpy(nand_otp, &tag->u, nand_otp_len);
++	return 0;
++}
++/* 0x48694E77 equal to fastoot ATAG_NAND_PARAM */
++__tagtable(0x48694E77, parse_nand_param);
++
++/*****************************************************************************/
++int hinfc610_ecc_type2reg_intf(int type, struct hinfc_host *host)
++{
++	if (HINFC_VER_620 == host->version)
++		return hinfc620_ecc_type2reg(type);
++	else
++		return hinfc610_ecc_type2reg(type);
++}
++/*****************************************************************************/
++int hinfc610_ecc_reg2type_intf(int reg, struct hinfc_host *host)
++{
++	if (HINFC_VER_620 == host->version)
++		return hinfc620_ecc_reg2type(reg);
++	else
++		return hinfc610_ecc_reg2type(reg);
++}
++
++/*****************************************************************************/
++static int hinfc610_param_adjust(struct mtd_info *mtd, struct nand_chip *chip,
++				 struct nand_dev_t *nand_dev)
++{
++	int pagetype;
++	int oobsize;
++	int regval;
++	char *start_type = "unknown";
++	struct nand_config_info *best = NULL;
++	struct hinfc_host *host = chip->priv;
++
++	if (IS_NANDC_HW_AUTO(host))
++		start_type = "HW-Auto";
++	else
++		start_type = "HW-Reg";
++
++	if ((mtd->writesize == SZ_8K)
++	|| (mtd->writesize == SZ_16K)
++	|| (mtd->writesize == SZ_32K))
++		host->flags |= NAND_RANDOMIZER;
++
++	pagetype = nandpage_size2type(mtd->writesize);
++	oobsize = mtd->oobsize;
++
++	best = hinfc610_force_ecc(mtd, pagetype, oobsize,
++		start_type, 0);
++
++#ifdef CONFIG_HINFC610_PAGESIZE_AUTO_ECC_NONE
++#  ifdef CONFIG_HINFC610_AUTO_PAGESIZE_ECC
++#  error you SHOULD NOT define CONFIG_HINFC610_PAGESIZE_AUTO_ECC_NONE \
++	and CONFIG_HINFC610_AUTO_PAGESIZE_ECC at the same time
++#  endif
++#  ifdef CONFIG_HINFC610_HARDWARE_PAGESIZE_ECC
++#  error you SHOULD NOT define CONFIG_HINFC610_PAGESIZE_AUTO_ECC_NONE \
++	and CONFIG_HINFC610_HARDWARE_PAGESIZE_ECC at the same time
++#  endif
++
++	pagetype = nandpage_size2type(mtd->writesize);
++	oobsize = 32;
++	best = hinfc610_force_ecc(mtd, pagetype, oobsize,
++				  "force config", 0);
++	start_type = "AutoForce";
++
++#endif /* CONFIG_HINFC610_PAGESIZE_AUTO_ECC_NONE */
++
++	if (!best) {
++		PR_BUG(ERSTR_HARDWARE
++		       "Please configure Nand Flash pagesize and ecctype!\n");
++		return -1;
++	}
++
++	/* only in case fastboot check randomizer failed.
++	 * Update fastboot or configure hardware randomizer pin
++	 * fix this problem.
++	 */
++	if (IS_NAND_RANDOM(nand_dev) && !(IS_NAND_RANDOM(host)))
++		PR_BUG(ERSTR_HARDWARE
++		       "Hardware is not configure randomizer, "
++		       "but it is more suitable for this Nand Flash. "
++		       "1. Please configure hardware randomizer PIN."
++		       "2. Please updata fastboot.\n");
++
++	host->flags |= (IS_NAND_RANDOM(nand_dev) |
++		IS_NAND_SYNC_ASYNC(nand_dev) |
++		IS_NAND_ONLY_SYNC(nand_dev) |
++		IS_NAND_ONFI(nand_dev));
++
++	/* only for print nand info. */
++	nand_dev->flags |= (IS_NANDC_HW_AUTO(host) |
++		IS_NANDC_SYNC_BOOT(host));
++
++	/* only in case fastboot check sync boot pin failed.
++	 * Update fastboot or configure hardware sync boot pin fix this problem.
++	 */
++	if (IS_NANDC_SYNC_BOOT(host)) {
++		/* But NAND do not support sync mode, warning ! */
++		if (!IS_NAND_ONLY_SYNC(nand_dev))
++			PR_BUG(ERSTR_HARDWARE
++				"Hardware SYNC BOOT PIN has configured sync mode, "
++				"but the Nand Flash is async mode.\n"
++				"1. DO NOT configure SYNC BOOT PIN. "
++				"2. Update fastboot.\n");
++	} else {
++		if (IS_NAND_ONLY_SYNC(nand_dev))
++			PR_BUG(ERSTR_HARDWARE
++				"Hardware SYNC BOOT PIN has configured async mode, "
++				"but the Nand Flash only support sync mode.\n"
++				"1. Please configure SYNC BOOT PIN."
++				"2. Update fastboot.\n");
++	}
++
++	if (IS_NAND_SYNC_ASYNC(nand_dev))
++		hinfc610_get_sync_info(host);
++
++	if (best->ecctype != NAND_ECC_NONE)
++		mtd->oobsize = best->oobsize;
++	chip->ecc.layout = best->layout;
++
++	host->ecctype  = best->ecctype;
++	host->pagesize = nandpage_type2size(best->pagetype);
++	host->oobsize  = mtd->oobsize;
++	host->block_page_mask = ((mtd->erasesize / mtd->writesize) - 1);
++
++	host->buffer = dma_alloc_coherent(host->dev,
++		(host->pagesize + host->oobsize),
++		&host->dma_buffer, GFP_KERNEL);
++	if (!host->buffer) {
++		PR_BUG("Can't malloc memory for NAND driver.");
++		return -EIO;
++	}
++	memset(host->buffer, 0xff, (host->pagesize + host->oobsize));
++
++	host->dma_oob = host->dma_buffer + host->pagesize;
++	host->bbm = (unsigned char *)(host->buffer
++		+ host->pagesize + HINFC_BAD_BLOCK_POS);
++
++	host->epm = (unsigned short *)(host->buffer
++		+ host->pagesize + chip->ecc.layout->oobfree[0].offset + 28);
++
++	regval = ~(HINFC610_CON_PAGESIZE_MASK << HINFC610_CON_PAGEISZE_SHIFT);
++	host->NFC_CON &= regval;
++	host->NFC_CON_ECC_NONE &= regval;
++	regval = (hinfc610_page_type2reg(best->pagetype)
++		& HINFC610_CON_PAGESIZE_MASK) << HINFC610_CON_PAGEISZE_SHIFT;
++	host->NFC_CON |= regval;
++	host->NFC_CON_ECC_NONE |= regval;
++
++	regval = ~(HINFC610_CON_ECCTYPE_MASK << HINFC610_CON_ECCTYPE_SHIFT);
++	host->NFC_CON &= regval;
++	host->NFC_CON_ECC_NONE &= regval;
++	regval = (hinfc610_ecc_type2reg_intf(best->ecctype, host)
++		& HINFC610_CON_ECCTYPE_MASK) << HINFC610_CON_ECCTYPE_SHIFT;
++	host->NFC_CON |= regval;
++
++	if (mtd->writesize > NAND_MAX_PAGESIZE ||
++	    mtd->oobsize > NAND_MAX_OOBSIZE) {
++		PR_BUG(ERSTR_DRIVER
++		       "Driver does not support this Nand Flash. "
++		       "Please increase NAND_MAX_PAGESIZE and NAND_MAX_OOBSIZE.\n");
++	}
++
++	if (mtd->writesize != host->pagesize) {
++		unsigned int shift = 0;
++		unsigned int writesize = mtd->writesize;
++
++		while (writesize > host->pagesize) {
++			writesize >>= 1;
++			shift++;
++		}
++		chip->chipsize = chip->chipsize >> shift;
++		mtd->erasesize = mtd->erasesize >> shift;
++		mtd->writesize = host->pagesize;
++		PR_MSG("Nand divide into 1/%u\n", (1 << shift));
++	}
++
++	nand_dev->start_type = start_type;
++	nand_dev->ecctype = host->ecctype;
++	nand_dev->oobsize = mtd->oobsize;
++
++	host->read_retry = NULL;
++	if (nand_dev->read_retry_type != NAND_RR_NONE) {
++		host->read_retry
++		    = hinfc610_find_read_retry(nand_dev->read_retry_type);
++		if (!host->read_retry) {
++			PR_BUG(ERSTR_DRIVER
++			       "This Nand Flash need to enable the "
++			       "'read retry' feature. "
++			       "but the driver dose not offer the feature");
++		}
++
++		if (nand_otp_len)
++			memcpy(host->rr_data, nand_otp, nand_otp_len);
++	}
++
++	/*
++	 * If it want to support the 'read retry' feature, the 'randomizer'
++	 * feature must be support first.
++	 */
++	if (host->read_retry && !IS_NAND_RANDOM(host)) {
++		PR_BUG(ERSTR_HARDWARE
++			"This Nand flash need to enable 'randomizer' feature. "
++			"Please configure hardware randomizer PIN.");
++	}
++
++	hinfc610_dbg_init(host);
++
++	return 0;
++}
++/*****************************************************************************/
++
++int hinfc610_nand_init(struct hinfc_host *host, struct nand_chip *chip)
++{
++	unsigned int regval;
++
++	host->version = hinfc_read(host, HINFC610_VERSION);
++
++	host->addr_cycle    = 0;
++	host->addr_value[0] = 0;
++	host->addr_value[1] = 0;
++	host->cache_addr_value[0] = ~0;
++	host->cache_addr_value[1] = ~0;
++	host->chipselect    = 0;
++
++	host->send_cmd_pageprog = hinfc610_send_cmd_pageprog;
++	host->send_cmd_readstart = hinfc610_send_cmd_readstart;
++	host->send_cmd_erase = hinfc610_send_cmd_erase;
++	host->send_cmd_readid = hinfc610_send_cmd_readid;
++	host->send_cmd_status = hinfc610_send_cmd_status;
++	host->send_cmd_reset = hinfc610_send_cmd_reset;
++
++	host->flags = 0;
++
++	regval = hinfc_read(host, HINFC610_CON);
++
++	host->NFC_CON = (regval
++		| HINFC610_CON_OP_MODE_NORMAL
++		| HINFC610_CON_READY_BUSY_SEL);
++
++	host->NFC_CON_ECC_NONE = host->NFC_CON
++		& (~(HINFC610_CON_ECCTYPE_MASK
++		     << HINFC610_CON_ECCTYPE_SHIFT))
++		& (~HINFC610_CON_RANDOMIZER_EN);
++
++	hinfc_write(host,
++		(SET_HINFC610_PWIDTH(CONFIG_HINFC610_W_LATCH,
++				     CONFIG_HINFC610_R_LATCH,
++				     CONFIG_HINFC610_RW_LATCH)),
++		HINFC610_PWIDTH);
++
++	host->flags |= NANDC_HW_AUTO;
++
++	/* check if chip is sync mode. */
++	if (regval & HINFC610_BOOT_CFG_SYC_NAND_PAD) {
++		host->flags |= NANDC_IS_SYNC_BOOT;
++
++		/*
++		 * NAND default is sync mode, and read id, reset in sync mode.
++		 */
++		host->NFC_CON |= HINFC610_CON_NF_MODE_TOGGLE;
++		host->NFC_CON_ECC_NONE |= HINFC610_CON_NF_MODE_TOGGLE;
++
++		/* set synchronous clock and timing. */
++		clk_prepare_enable(host->clk);
++	}
++
++	memset((char *)chip->IO_ADDR_R,
++		0xff, HINFC610_BUFFER_BASE_ADDRESS_LEN);
++
++	host->enable_ecc_randomizer = hinfc610_enable_ecc_randomizer;
++	hinfc_param_adjust = hinfc610_param_adjust;
++
++	return 0;
++}
+diff --git a/drivers/mtd/nand/hinfc610/hinfc610.h b/drivers/mtd/nand/hinfc610/hinfc610.h
+new file mode 100644
+index 0000000..18d90fd
+--- /dev/null
++++ b/drivers/mtd/nand/hinfc610/hinfc610.h
+@@ -0,0 +1,512 @@
++/*
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#ifndef HINFCV610H
++#define HINFCV610H
++/******************************************************************************/
++
++#ifndef CONFIG_HINFC610_W_LATCH
++	#define CONFIG_HINFC610_W_LATCH			(5)
++#endif /* CONFIG_HINFC610_W_LATCH */
++
++#ifndef CONFIG_HINFC610_R_LATCH
++	#define CONFIG_HINFC610_R_LATCH			(7)
++#endif /* CONFIG_HINFC610_R_LATCH */
++
++#ifndef CONFIG_HINFC610_RW_LATCH
++	#define CONFIG_HINFC610_RW_LATCH		(3)
++#endif /* CONFIG_HINFC610_RW_LATCH */
++
++#ifndef CONFIG_HINFC610_MAX_CHIP
++	#define CONFIG_HINFC610_MAX_CHIP		(1)
++	#warning NOT config CONFIG_HINFC610_MAX_CHIP, \
++	used default value, maybe invalid.
++#endif /* CONFIG_HINFC610_MAX_CHIP */
++/*****************************************************************************/
++#define HINFC_ECC_ERR_NUM0_BUF0			0xa0
++#define HINFC_ECC_ERR_NUM1_BUF0			0xa4
++#define HINFC_ECC_ERR_NUM0_BUF1			0xa8
++#define HINFC_ECC_ERR_NUM1_BUF1			0xcc
++
++#define GET_ECC_ERR_NUM(_i, _reg)		(((_reg) >> ((_i) * 8)) & 0xff)
++
++/*****************************************************************************/
++#define HINFC610_REG_BASE_ADDRESS_LEN                 (0x100)
++#define HINFC610_BUFFER_BASE_ADDRESS_LEN              (2048 + 128)
++
++#define HINFC610_CHIP_DELAY                           (25)
++
++#define HINFC610_ADDR_CYCLE_MASK                      0x4
++#define HINFC610_DMA_ADDR_OFFSET                      4096
++/*****************************************************************************/
++#define HINFC610_CON                                 0x00
++#define HINFC610_CON_OP_MODE_NORMAL      (1U << 0)
++#define HINFC610_CON_PAGEISZE_SHIFT      (1)
++#define HINFC610_CON_PAGESIZE_MASK       (0x07)
++#define HINFC610_CON_BUS_WIDTH           (1U << 4)
++#define HINFC610_CON_READY_BUSY_SEL      (1U << 8)
++#define HINFC610_CON_ECCTYPE_SHIFT       (9)
++#define HINFC610_CON_ECCTYPE_MASK        (0x0f)
++#define HINFC610_CON_RANDOMIZER_EN       (1 << 14)
++#define HINFC610_CON_NF_MODE_SHIFT       15
++#define HINFC610_CON_NF_MODE_MASK        (3 << HINFC610_CON_NF_MODE_SHIFT)
++#define HINFC610_CON_NF_MODE_TOGGLE      (1 << HINFC610_CON_NF_MODE_SHIFT)
++#define HINFC610_CON_NF_MODE_ONFI_23     (2 << HINFC610_CON_NF_MODE_SHIFT)
++#define HINFC610_CON_NF_MODE_ONFI_30     (3 << HINFC610_CON_NF_MODE_SHIFT)
++
++#define HINFC610_PWIDTH                              0x04
++#define SET_HINFC610_PWIDTH(_w_lcnt, _r_lcnt, _rw_hcnt) \
++	((_w_lcnt) | (((_r_lcnt) & 0x0F) << 4) | (((_rw_hcnt) & 0x0F) << 8))
++
++#define HINFC610_CMD                                 0x0C
++#define HINFC610_ADDRL                               0x10
++#define HINFC610_ADDRH                               0x14
++#define HINFC610_DATA_NUM                            0x18
++
++#define HINFC610_OP                                  0x1C
++#define HINFC610_OP_READ_STATUS_EN       (1U << 0)
++#define HINFC610_OP_READ_DATA_EN         (1U << 1)
++#define HINFC610_OP_WAIT_READY_EN        (1U << 2)
++#define HINFC610_OP_CMD2_EN              (1U << 3)
++#define HINFC610_OP_WRITE_DATA_EN        (1U << 4)
++#define HINFC610_OP_ADDR_EN              (1U << 5)
++#define HINFC610_OP_CMD1_EN              (1U << 6)
++#define HINFC610_OP_NF_CS_SHIFT          (7)
++#define HINFC610_OP_NF_CS_MASK           (3)
++#define HINFC610_OP_ADDR_CYCLE_SHIFT     (9)
++#define HINFC610_OP_ADDR_CYCLE_MASK      (7)
++#define HINFC610_OP_READID_EN            (1U << 12)
++#define HINFC610_OP_RW_REG_EN            (1U << 13)
++
++#define HINFC610_STATUS                               0x20
++
++#define HINFC610_INTS                                 0x28
++#define HINFC610_INTS_UE                 (1U << 6)
++#define HINFC610_INTCLR                               0x2C
++#define HINFC610_INTCLR_UE               (1U << 6)
++#define HINFC610_INTCLR_CE               (1U << 5)
++
++#define HINFC610_DMA_CTRL                             0x60
++#define HINFC610_DMA_CTRL_DMA_START      (1U << 0)
++#define HINFC610_DMA_CTRL_WE             (1U << 1)
++#define HINFC610_DMA_CTRL_BURST4_EN      (1U << 4)
++#define HINFC610_DMA_CTRL_BURST8_EN      (1U << 5)
++#define HINFC610_DMA_CTRL_BURST16_EN     (1U << 6)
++#define HINFC610_DMA_CTRL_ADDR_NUM_SHIFT (7)
++#define HINFC610_DMA_CTRL_ADDR_NUM_MASK  (1)
++#define HINFC610_DMA_CTRL_CS_SHIFT       (8)
++#define HINFC610_DMA_CTRL_CS_MASK        (0x03)
++
++#define HINFC610_DMA_ADDR_DATA                        0x64
++#define HINFC610_DMA_ADDR_OOB                         0x68
++#define HINFC610_DMA_ADDR_DATA1                       0xB4
++#define HINFC610_DMA_ADDR_DATA2                       0xB8
++#define HINFC610_DMA_ADDR_DATA3                       0xBC
++#define HINFC610_DMA_ADDR_DATA4                       0xEC
++#define HINFC610_DMA_ADDR_DATA5                       0xF0
++#define HINFC610_DMA_ADDR_DATA6                       0xF4
++#define HINFC610_DMA_ADDR_DATA7                       0xF8
++
++#define HINFC610_DMA_LEN                              0x6C
++#define HINFC610_DMA_LEN_OOB_SHIFT       (16)
++#define HINFC610_DMA_LEN_OOB_MASK        (0x1FFF)
++
++#define HINFC610_DMA_PARA                             0x70
++#define HINFC610_DMA_PARA_DATA_RW_EN     (1U << 0)
++#define HINFC610_DMA_PARA_OOB_RW_EN      (1U << 1)
++#define HINFC610_DMA_PARA_DATA_EDC_EN    (1U << 2)
++#define HINFC610_DMA_PARA_OOB_EDC_EN     (1U << 3)
++#define HINFC610_DMA_PARA_EXT_LEN_SHIFT  (6)
++#define HINFC610_DMA_PARA_EXT_LEN_MASK   (0x03)
++
++#define HINFC610_VERSION                              0x74
++#define HINFC610_LOG_READ_ADDR                        0x7C
++#define HINFC610_LOG_READ_LEN                         0x80
++
++#define HINFC610_ECC_REG0                             0xA0
++#define HINFC610_ECC_REG1                             0xA4
++#define HINFC610_ECC_REG2                             0xA8
++#define HINFC610_ECC_REG3                             0xAC
++
++#define HINFC610_RANDOMIZER                           0xC0
++#define HINFC610_RANDOMIZER_PAD           0x02
++#define HINFC610_RANDOMIZER_ENABLE        0x01
++/* read nand id or nand status, return from nand data length */
++#define HINFC610_NANDINFO_LEN             0x10
++
++#define HINFC610_BOOT_CFG                             0xC4
++#define HINFC610_BOOT_CFG_RANDOMIZER_PAD  0x01
++#define HINFC610_BOOT_CFG_SAVE_PIN_MODE_SHIFT    13
++#define HINFC610_BOOT_CFG_SAVE_PIN_MODE   \
++	(1U << HINFC610_BOOT_CFG_SAVE_PIN_MODE_SHIFT)
++#define HINFC610_BOOT_CFG_SYC_NAND_PAD_SHIFT     12
++#define HINFC610_BOOT_CFG_SYC_NAND_PAD    \
++	(1U << HINFC610_BOOT_CFG_SYC_NAND_PAD_SHIFT)
++
++#define HINFC610_SYNC_TIMING                          0xD0
++
++/* ONFI: sync nand timing config */
++#define HINFC610_SYNC_ONFI_T_CAD          (0xF << 24)
++#define HINFC610_SYNC_ONFI_T_DQZ          (0xF << 20)
++
++/* TOGGLE: sync nand timing config */
++#define HINFC610_SYNC_TOGGLE_PRE_RDQS     (0xF << 16)
++#define HINFC610_SYNC_TOGGLE_POST_RDQS    (0xF << 12)
++#define HINFC610_SYNC_TOGGLE_PRE_WDQS     (0xF << 8)
++#define HINFC610_SYNC_TOGGLE_POST_WDQS    (0xF << 4)
++#define HINFC610_SYNC_TOGGLE_RW_PSTH      (0xF << 0)
++
++/*****************************************************************************/
++/*
++ * This constant declares the max. oobsize / page, which
++ * is supported now. If you add a chip with bigger oobsize/page
++ * adjust this accordingly.
++ */
++#define NAND_MAX_OOBSIZE	4800
++#define NAND_MAX_PAGESIZE	32768
++
++/* DMA address align with 32 bytes. */
++#define HINFC610_DMA_ALIGN                            64
++/*****************************************************************************/
++#include "../hinfc_gen.h"
++
++#undef  READ
++#define READ           1
++
++#undef  WRITE
++#define WRITE          0
++
++#undef  FALSE
++#define FALSE          0
++
++#undef  TRUE
++#define TRUE           1
++
++#undef ENABLE
++#define ENABLE         1
++
++#undef DISABLE
++#define DISABLE        0
++/*****************************************************************************/
++
++struct hinfc_host {
++	struct nand_chip *chip;
++	struct mtd_info  *mtd;
++	void __iomem *iobase;
++	struct device *dev;
++
++	unsigned int offset;
++	unsigned int command;
++
++	int chipselect;
++
++	unsigned int n24bit_ext_len;
++	int ecctype;
++
++/* Current system has already gone to sync mode */
++#define HINFC610_IS_SYNC(_host) ((_host)->NFC_CON & HINFC610_CON_NF_MODE_MASK)
++	unsigned long NFC_CON;
++	unsigned long NFC_CON_ECC_NONE;
++
++	unsigned int addr_cycle;
++	unsigned int addr_value[2];
++	unsigned int cache_addr_value[2];
++	unsigned int column;
++	unsigned int block_page_mask;
++
++	unsigned int dma_oob;
++	unsigned int dma_buffer;
++	unsigned int pagesize;
++	unsigned int oobsize;
++	/* This is maybe an un-aligment address, only for malloc or free */
++	char *buforg;
++	char *buffer;
++
++	int  need_rr_data;
++#define HINFC_READ_RETRY_DATA_LEN         128
++	char rr_data[HINFC_READ_RETRY_DATA_LEN];
++	int  version;
++	int   add_partition;
++
++	/* BOOTROM read two bytes to detect the bad block flag */
++#define HINFC_BAD_BLOCK_POS              0
++	unsigned char *bbm;       /* nand bad block mark */
++	unsigned short *epm;      /* nand empty page mark */
++	unsigned int flags;
++
++#define HINFC610_PS_UC_ECC        0x01 /* page has ecc error */
++#define HINFC610_PS_BAD_BLOCK     0x02 /* bad block */
++#define HINFC610_PS_EMPTY_PAGE    0x04 /* page is empty */
++#define HINFC610_PS_EPM_ERROR     0x0100 /* empty page mark word has ecc error*/
++#define HINFC610_PS_BBM_ERROR     0x0200 /* bad block mark word has ecc error*/
++	unsigned int page_status;
++
++	struct clk *clk;
++
++	int (*send_cmd_pageprog)(struct hinfc_host *host);
++	int (*send_cmd_status)(struct hinfc_host *host);
++	int (*send_cmd_readstart)(struct hinfc_host *host);
++	int (*send_cmd_erase)(struct hinfc_host *host);
++	int (*send_cmd_readid)(struct hinfc_host *host);
++	int (*send_cmd_reset)(struct hinfc_host *host, int chipselect);
++	int (*enable)(struct hinfc_host *host, int enable);
++
++	int (*enable_ecc_randomizer)(struct hinfc_host *host,
++				     int ecc_en, int randomizer_en);
++
++	struct read_retry_t *read_retry;
++	struct nand_sync *sync;
++};
++
++#define HINFC610_UC_ECC               0x01
++#define HINFC610_BAD_BLOCK            0x02
++#define HINFC610_EMPTY_PAGE           0x04
++
++#define IS_PS_EMPTY_PAGE(_host)  ((_host)->page_status & HINFC610_PS_EMPTY_PAGE)
++#define IS_PS_BAD_BLOCK(_host)   ((_host)->page_status & HINFC610_PS_BAD_BLOCK)
++#define IS_PS_UN_ECC(_host)      ((_host)->page_status & HINFC610_PS_UC_ECC)
++#define IS_PS_EPM_ERR(_host)      ((_host)->page_status & HINFC610_PS_EPM_ERROR)
++#define IS_PS_BBM_ERR(_host)      ((_host)->page_status & HINFC610_PS_BBM_ERROR)
++
++/*****************************************************************************/
++
++#define HINFC610_READ_1CMD_0ADD_NODATA \
++	(HINFC610_OP_CMD1_EN \
++	| ((host->chipselect & HINFC610_OP_NF_CS_MASK) \
++		<< HINFC610_OP_NF_CS_SHIFT))
++
++#define HINFC610_READ_1CMD_1ADD_DATA    \
++	(HINFC610_OP_CMD1_EN \
++	| HINFC610_OP_ADDR_EN \
++	| HINFC610_OP_READ_DATA_EN \
++	| (((unsigned int)host->chipselect & HINFC610_OP_NF_CS_MASK) \
++		<< HINFC610_OP_NF_CS_SHIFT) \
++	| (1 << HINFC610_OP_ADDR_CYCLE_SHIFT))
++
++#define HINFC610_READ_1CMD_1ADD_DATA_WAIT_READY    \
++	(HINFC610_OP_CMD1_EN \
++	| HINFC610_OP_ADDR_EN \
++	| HINFC610_OP_READ_DATA_EN \
++	| HINFC610_OP_WAIT_READY_EN \
++	| (((unsigned int)host->chipselect & HINFC610_OP_NF_CS_MASK) \
++		<< HINFC610_OP_NF_CS_SHIFT) \
++	| (1 << HINFC610_OP_ADDR_CYCLE_SHIFT))
++
++#define HINFC610_READ_1CMD_1ADD_DATA_SYNC \
++	(HINFC610_OP_CMD1_EN \
++	| HINFC610_OP_ADDR_EN \
++	| HINFC610_OP_READ_DATA_EN \
++	| HINFC610_OP_WAIT_READY_EN \
++	| HINFC610_OP_RW_REG_EN \
++	| (((unsigned int)host->chipselect & HINFC610_OP_NF_CS_MASK) \
++		<< HINFC610_OP_NF_CS_SHIFT) \
++	| (1 << HINFC610_OP_ADDR_CYCLE_SHIFT))
++
++#define HINFC610_READ_2CMD_5ADD    \
++	(HINFC610_OP_CMD1_EN \
++	| HINFC610_OP_CMD2_EN \
++	| HINFC610_OP_ADDR_EN \
++	| HINFC610_OP_READ_DATA_EN \
++	| HINFC610_OP_WAIT_READY_EN \
++	| (((unsigned int)host->chipselect & HINFC610_OP_NF_CS_MASK) \
++		<< HINFC610_OP_NF_CS_SHIFT) \
++	| (5 << HINFC610_OP_ADDR_CYCLE_SHIFT))
++
++#define HINFC610_WRITE_0CMD_1ADD_DATA \
++	(HINFC610_OP_ADDR_EN \
++	| HINFC610_OP_WRITE_DATA_EN \
++	| (((unsigned int)host->chipselect & HINFC610_OP_NF_CS_MASK) \
++		<< HINFC610_OP_NF_CS_SHIFT) \
++	| (1 << HINFC610_OP_ADDR_CYCLE_SHIFT))
++
++#define HINFC610_WRITE_0CMD_1ADD_DATA_WAIT_READY \
++	(HINFC610_OP_ADDR_EN \
++	| HINFC610_OP_WRITE_DATA_EN \
++	| HINFC610_OP_WAIT_READY_EN \
++	| (((unsigned int)host->chipselect & HINFC610_OP_NF_CS_MASK) \
++		<< HINFC610_OP_NF_CS_SHIFT) \
++	| (1 << HINFC610_OP_ADDR_CYCLE_SHIFT))
++
++#define HINFC610_WRITE_0CMD_1ADD_DATA_SYNC \
++	(HINFC610_OP_ADDR_EN \
++	 | HINFC610_OP_WRITE_DATA_EN \
++	 | HINFC610_OP_RW_REG_EN \
++	 | (((unsigned int)host->chipselect & HINFC610_OP_NF_CS_MASK) \
++		 << HINFC610_OP_NF_CS_SHIFT) \
++	 | (1 << HINFC610_OP_ADDR_CYCLE_SHIFT))
++
++#define HINFC610_WRITE_0CMD_1ADD_DATA_SYNC_WAIT_READY \
++	(HINFC610_OP_ADDR_EN \
++	 | HINFC610_OP_WRITE_DATA_EN \
++	 | HINFC610_OP_RW_REG_EN \
++	 | HINFC610_OP_WAIT_READY_EN \
++	 | (((unsigned int)host->chipselect & HINFC610_OP_NF_CS_MASK) \
++		 << HINFC610_OP_NF_CS_SHIFT) \
++	 | (1 << HINFC610_OP_ADDR_CYCLE_SHIFT))
++
++#define HINFC610_WRITE_1CMD_1ADD_DATA  \
++	(HINFC610_OP_CMD1_EN \
++	| HINFC610_OP_ADDR_EN \
++	| HINFC610_OP_WRITE_DATA_EN \
++	| (((unsigned int)host->chipselect & HINFC610_OP_NF_CS_MASK) \
++		<< HINFC610_OP_NF_CS_SHIFT) \
++	| (1 << HINFC610_OP_ADDR_CYCLE_SHIFT))
++
++#define HINFC610_WRITE_1CMD_1ADD_DATA_WAIT_READY  \
++	(HINFC610_OP_CMD1_EN \
++	| HINFC610_OP_ADDR_EN \
++	| HINFC610_OP_WRITE_DATA_EN \
++	| HINFC610_OP_WAIT_READY_EN \
++	| (((unsigned int)host->chipselect & HINFC610_OP_NF_CS_MASK) \
++		<< HINFC610_OP_NF_CS_SHIFT) \
++	| (1 << HINFC610_OP_ADDR_CYCLE_SHIFT))
++
++#define HINFC610_WRITE_1CMD_1ADD_DATA_SYNC  \
++	(HINFC610_OP_CMD1_EN \
++	 | HINFC610_OP_ADDR_EN \
++	 | HINFC610_OP_WRITE_DATA_EN \
++	 | HINFC610_OP_RW_REG_EN \
++	 | (((unsigned int)host->chipselect & HINFC610_OP_NF_CS_MASK) \
++		 << HINFC610_OP_NF_CS_SHIFT) \
++	 | (1 << HINFC610_OP_ADDR_CYCLE_SHIFT))
++
++#define HINFC610_WRITE_1CMD_1ADD_DATA_SYNC_WAIT_READY  \
++	(HINFC610_OP_CMD1_EN \
++	 | HINFC610_OP_ADDR_EN \
++	 | HINFC610_OP_WRITE_DATA_EN \
++	 | HINFC610_OP_WAIT_READY_EN \
++	 | HINFC610_OP_RW_REG_EN \
++	 | (((unsigned int)host->chipselect & HINFC610_OP_NF_CS_MASK) \
++		 << HINFC610_OP_NF_CS_SHIFT) \
++	 | (1 << HINFC610_OP_ADDR_CYCLE_SHIFT))
++
++#define HINFC610_WRITE_1CMD_2ADD_DATA  \
++	(HINFC610_OP_CMD1_EN \
++	| HINFC610_OP_ADDR_EN \
++	| HINFC610_OP_WRITE_DATA_EN \
++	| (((unsigned int)host->chipselect & HINFC610_OP_NF_CS_MASK) \
++		<< HINFC610_OP_NF_CS_SHIFT) \
++	| (2 << HINFC610_OP_ADDR_CYCLE_SHIFT))
++
++#define HINFC610_WRITE_1CMD_2ADD_DATA_SYNC  \
++	(HINFC610_OP_CMD1_EN \
++	 | HINFC610_OP_ADDR_EN \
++	 | HINFC610_OP_WRITE_DATA_EN \
++	 | HINFC610_OP_RW_REG_EN \
++	 | (((unsigned int)host->chipselect & HINFC610_OP_NF_CS_MASK) \
++		 << HINFC610_OP_NF_CS_SHIFT) \
++	 | (2 << HINFC610_OP_ADDR_CYCLE_SHIFT))
++
++#define HINFC610_WRITE_2CMD_0ADD_NODATA \
++	(HINFC610_OP_CMD1_EN \
++	| HINFC610_OP_CMD2_EN \
++	| (((unsigned int)host->chipselect & HINFC610_OP_NF_CS_MASK) \
++		<< HINFC610_OP_NF_CS_SHIFT))
++
++#define HINFC610_WRITE_2CMD_0ADD_NODATA_SYNC \
++	(HINFC610_OP_CMD1_EN \
++	| HINFC610_OP_CMD2_EN \
++	| HINFC610_OP_RW_REG_EN \
++	| (((unsigned int)host->chipselect & HINFC610_OP_NF_CS_MASK) \
++		<< HINFC610_OP_NF_CS_SHIFT))
++
++#define HINFC610_WRITE_1CMD_0ADD_NODATA \
++	(HINFC610_OP_CMD1_EN \
++	| (((unsigned int)host->chipselect & HINFC610_OP_NF_CS_MASK) \
++		<< HINFC610_OP_NF_CS_SHIFT))
++
++#define HINFC610_WRITE_1CMD_0ADD_NODATA_WAIT_READY \
++	(HINFC610_OP_CMD1_EN \
++	| HINFC610_OP_WAIT_READY_EN \
++	| (((unsigned int)host->chipselect & HINFC610_OP_NF_CS_MASK) \
++		<< HINFC610_OP_NF_CS_SHIFT))
++
++/*****************************************************************************/
++
++#define WAIT_CONTROLLER_FINISH() \
++do { \
++	unsigned int timeout = 0x800000; \
++	while ((hinfc_read(host, HINFC610_STATUS) & 0x1) == 0x0 && timeout) \
++		timeout--; \
++	if (!timeout) \
++		PR_ERR("Wait NAND controller finish timeout.\n"); \
++} while (0)
++
++/*****************************************************************************/
++
++#define hinfc_read(_host, _reg) \
++	readl((char *)_host->iobase + (_reg))
++
++#define hinfc_write(_host, _value, _reg) \
++	writel((_value), (char *)_host->iobase + (_reg))
++
++#define HINFC_CMD_SEQ(_cmd0, _cmd1)        \
++	(((_cmd0) & 0xFF) | ((_cmd1) & 0xFF) << 8)
++/*****************************************************************************/
++
++#define GET_PAGE_INDEX(host) \
++	((host->addr_value[0] >> 16) | (host->addr_value[1] << 16))
++
++/*****************************************************************************/
++
++void hinfc610_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl);
++int hinfc610_dev_ready(struct mtd_info *mtd);
++void hinfc610_select_chip(struct mtd_info *mtd, int chipselect);
++uint8_t hinfc610_read_byte(struct mtd_info *mtd);
++u16 hinfc610_read_word(struct mtd_info *mtd);
++void hinfc610_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len);
++void hinfc610_read_buf(struct mtd_info *mtd, uint8_t *buf, int len);
++int hinfc610_nand_init(struct hinfc_host *host, struct nand_chip *chip);
++/******************************************************************************/
++
++extern struct nand_sync hinfc610_sync_onfi_23;
++extern struct nand_sync hinfc610_sync_onfi_30;
++extern struct nand_sync hinfc610_sync_toggle_10;
++extern struct read_retry_t hinfc610_hynix_bg_cdie_read_retry;
++extern struct read_retry_t hinfc610_hynix_bg_bdie_read_retry;
++extern struct read_retry_t hinfc610_hynix_cg_adie_read_retry;
++extern struct read_retry_t hinfc610_micron_read_retry;
++extern struct read_retry_t hinfc610_toshiba_24nm_read_retry;
++extern struct read_retry_t hinfc610_samsung_read_retry;
++
++#if 0
++#ifdef CONFIG_MTD_PART_CHANGE
++extern int register_mtd_partdev(struct mtd_info *mtd);
++extern int unregister_mtd_partdev(struct mtd_info *mtd);
++#else
++int register_mtd_partdev(struct mtd_info *mtd)
++{
++	return 0;
++};
++
++int unregister_mtd_partdev(struct mtd_info *mtd)
++{
++	return 0;
++};
++#endif
++
++void hinfc610_controller_enable(struct hinfc_host *host, int enable);
++#endif
++
++extern int hinfc610_dbgfs_debug_init(struct hinfc_host *host);
++
++#ifdef CONFIG_HINFC610_DBG_NAND_DEBUG
++extern struct hinfc610_dbg_inf_t *hinfc610_dbg_inf[];
++#endif
++
++#endif /* HINFCV610H */
+diff --git a/drivers/mtd/nand/hinfc610/hinfc610_dbg.c b/drivers/mtd/nand/hinfc610/hinfc610_dbg.c
+new file mode 100644
+index 0000000..ee25956
+--- /dev/null
++++ b/drivers/mtd/nand/hinfc610/hinfc610_dbg.c
+@@ -0,0 +1,294 @@
++/*
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include <linux/moduleparam.h>
++#include <linux/vmalloc.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/debugfs.h>
++#include <linux/uaccess.h>
++#include <linux/ctype.h>
++
++#include "hinfc610_os.h"
++#include "hinfc610.h"
++#include "hinfc610_dbg.h"
++
++struct hinfc610_dbg_inf_t *hinfc610_dbg_inf[] = {
++	&hinfc610_dbg_inf_ecc_notice,
++	&hinfc610_dbg_inf_read_retry_notice,
++#ifdef CONFIG_HINFC610_DBG_NAND_DUMP
++	&hinfc610_dbg_inf_dump,
++#endif
++#ifdef CONFIG_HINFC610_DBG_NAND_ERASE_COUNT
++	&hinfc610_dbg_inf_erase_count,
++#endif
++#ifdef CONFIG_HINFC610_DBG_NAND_ECC_COUNT
++	&hinfc610_dbg_inf_ecc_count,
++#endif
++#ifdef CONFIG_HINFC610_DBG_NAND_READ_RETRY
++	&hinfc610_dbg_inf_read_retry,
++#endif
++	NULL,
++};
++
++static struct dentry *dbgfs_root;
++static struct hinfc_host *dbgfs_host;
++
++/*****************************************************************************/
++static ssize_t dbgfs_debug_read(struct file *filp, char __user *buffer,
++				size_t count, loff_t *ppos)
++{
++	char *msg, *p;
++	struct hinfc610_dbg_inf_t **inf;
++
++	if (*ppos != 0)
++		return 0;
++
++	msg = (char *)__get_free_page(GFP_TEMPORARY);
++	if (!msg)
++		return -ENOMEM;
++
++	p = msg;
++	if (count > PAGE_SIZE)
++		count = PAGE_SIZE;
++
++	for (inf = hinfc610_dbg_inf; *inf; inf++) {
++		if ((p - msg) + MAX_OPTION_SIZE + 2 > count) {
++			PR_ERR("Not enough memory.\n");
++			break;
++		}
++		p += snprintf(p, (MAX_OPTION_SIZE + 2), "%c%s,",
++			      ((*inf)->enable ? '+' : '-'),
++			      (*inf)->name);
++	}
++
++	p += sprintf(p, "\n");
++	count = (p - msg);
++	if (copy_to_user(buffer, msg, count)) {
++		free_page((unsigned long) msg);
++		return -EFAULT;
++	}
++
++	free_page((unsigned long) msg);
++
++	*ppos += count;
++	return count;
++}
++/*****************************************************************************/
++
++static void dbgfs_debug_do_cmd(struct hinfc610_dbg_inf_t **dbg_inf,
++			       const char *cmd, unsigned int length, int enable)
++{
++	int ret = 0;
++	struct hinfc610_dbg_inf_t **inf;
++
++	if (length >= sizeof((*inf)->name))
++		return;
++
++	for (inf = dbg_inf; *inf; inf++) {
++		if (!(*inf)->name[length] &&
++		    !memcmp((*inf)->name, cmd, length))
++			break;
++	}
++
++	if (!(*inf) || (*inf)->enable == enable)
++		return;
++
++	if (enable) {
++		if ((*inf)->init)
++			ret = (*inf)->init(dbgfs_root, dbgfs_host);
++	} else {
++		if ((*inf)->uninit)
++			ret = (*inf)->uninit();
++	}
++
++	if (!ret)
++		(*inf)->enable = enable;
++}
++/*****************************************************************************/
++
++static void dbgfs_debug_ops(const char *options,
++			    struct hinfc610_dbg_inf_t **dbg_inf)
++{
++	int enable;
++	const char *pos, *cmd;
++
++	pos = options;
++
++	while (*pos) {
++
++		while (*pos && *pos != '+' && *pos != '-')
++			pos++;
++
++		switch (*pos++) {
++		case '+':
++			enable = 1;
++			break;
++		case '-':
++			enable = 0;
++			break;
++		default:
++			return;
++		}
++
++		cmd = pos;
++		while (*pos == '_' || isalpha(*pos))
++			pos++;
++
++		if (*cmd && pos > cmd)
++			dbgfs_debug_do_cmd(dbg_inf, cmd, (pos - cmd), enable);
++
++		while (isspace(*pos) || *pos == ',' || *pos == ';')
++			pos++;
++	}
++}
++/*****************************************************************************/
++/*
++ * echo "+dump, +read_retry, +ecc_count, +erase_count"  > debug
++ */
++static ssize_t dbgfs_debug_write(struct file *filp, const char __user *buffer,
++				 size_t count, loff_t *ppos)
++{
++	char *options;
++	size_t num = count;
++
++	if (count > PAGE_SIZE)
++		num = (PAGE_SIZE - 1);
++
++	options = (char *)__get_free_page(GFP_TEMPORARY);
++	if (!options)
++		return -ENOMEM;
++
++	if (copy_from_user(options, buffer, num)) {
++		free_page((unsigned long) options);
++		return -EFAULT;
++	}
++
++	options[num] = 0;
++
++	dbgfs_debug_ops(options, hinfc610_dbg_inf);
++
++	free_page((unsigned long) options);
++
++	*ppos += count;
++	return count;
++}
++/*****************************************************************************/
++
++static const struct file_operations dbgfs_debug_fops = {
++	.owner = THIS_MODULE,
++	.read  = dbgfs_debug_read,
++	.write = dbgfs_debug_write,
++};
++/*****************************************************************************/
++
++int hinfc610_dbgfs_debug_init(struct hinfc_host *host)
++{
++	struct dentry *dentry;
++
++	if (dbgfs_root)
++		return 0;
++
++	dbgfs_root = debugfs_create_dir("nand", NULL);
++	if (!dbgfs_root) {
++		PR_ERR("Can't create 'nand' dir.\n");
++		return -ENOENT;
++	}
++
++	dentry = debugfs_create_file("debug", S_IFREG | S_IRUSR | S_IWUSR,
++				     dbgfs_root, NULL, &dbgfs_debug_fops);
++	if (!dentry) {
++		PR_ERR("Can't create 'debug' file.\n");
++		goto fail;
++	}
++
++	dbgfs_host = host;
++
++	if (nand_dbgfs_options)
++		dbgfs_debug_ops(nand_dbgfs_options, hinfc610_dbg_inf);
++
++	return 0;
++
++fail:
++	debugfs_remove_recursive(dbgfs_root);
++	dbgfs_root = NULL;
++
++	return -ENOENT;
++}
++/*****************************************************************************/
++
++static int dbgfs_read_retry_notice_init(struct dentry *root,
++					struct hinfc_host *host)
++{
++	if (!host->read_retry) {
++		pr_warn("read_retry_notice: The NAND not support this interface.\n");
++		return -1;
++	}
++
++	return 0;
++}
++
++static void hinfc610_dbg_read_retry_notice(struct hinfc_host *host, int index)
++{
++	pr_warn("Page 0x%08x do read retry (%d/%d) %s.\n",
++		GET_PAGE_INDEX(host), index, host->read_retry->count,
++		(IS_PS_UN_ECC(host) ? "Fail" : "Success"));
++}
++
++struct hinfc610_dbg_inf_t hinfc610_dbg_inf_read_retry_notice = {
++	"read_retry_notice", 0,
++	dbgfs_read_retry_notice_init,
++	NULL,
++	NULL,
++	NULL,
++	NULL,
++	hinfc610_dbg_read_retry_notice,
++};
++/*****************************************************************************/
++
++static void hinfc610_dbg_ecc_notice_read(struct hinfc_host *host)
++{
++	unsigned int pageindex =  GET_PAGE_INDEX(host);
++
++	if (IS_PS_BAD_BLOCK(host) || IS_PS_EMPTY_PAGE(host)) {
++		if (IS_PS_BBM_ERR(host))
++			pr_warn("page 0x%08x bbm is corruption, bbm: 0x%x.\n",
++				pageindex, *host->bbm);
++
++		if (IS_PS_EPM_ERR(host))
++			pr_warn("page 0x%08x epm is corruption, epm: 0x%x.\n",
++				pageindex, *host->epm);
++
++		return;
++	}
++
++	if (IS_PS_UN_ECC(host))
++		pr_warn("page 0x%08x has uncorrect ecc.\n", pageindex);
++}
++
++struct hinfc610_dbg_inf_t hinfc610_dbg_inf_ecc_notice = {
++	"ecc_notice", 0,
++	NULL,
++	NULL,
++	hinfc610_dbg_ecc_notice_read,
++	NULL,
++	NULL,
++	NULL,
++};
++/*****************************************************************************/
+diff --git a/drivers/mtd/nand/hinfc610/hinfc610_dbg.h b/drivers/mtd/nand/hinfc610/hinfc610_dbg.h
+new file mode 100644
+index 0000000..8fd4deb
+--- /dev/null
++++ b/drivers/mtd/nand/hinfc610/hinfc610_dbg.h
+@@ -0,0 +1,63 @@
++/*
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++
++#ifndef HINFC610_DBGH
++#define HINFC610_DBGH
++/******************************************************************************/
++
++#define MAX_OPTION_SIZE                20
++
++struct hinfc610_dbg_inf_t {
++	const char name[MAX_OPTION_SIZE];
++	int enable;
++	int (*init)(struct dentry *root, struct hinfc_host *host);
++	int (*uninit)(void);
++
++	void (*read)(struct hinfc_host *host);
++	void (*write)(struct hinfc_host *host);
++	void (*erase)(struct hinfc_host *host);
++
++	void (*read_retry)(struct hinfc_host *host, int index);
++};
++
++#define CMD_WORD_OFFSET             "offset="
++#define CMD_WORD_LENGTH             "length="
++#define CMD_WORD_CLEAN              "clear"
++#define CMD_WORD_ON                 "on"
++#define CMD_WORD_OFF                "off"
++
++struct hinfc610_ecc_inf_t {
++	int pagesize;
++	int ecctype;
++	int section;
++	void (*ecc_inf)(struct hinfc_host *host, unsigned char ecc[]);
++};
++
++struct hinfc610_ecc_inf_t *hinfc610_get_ecc_inf(struct hinfc_host *host,
++						int pagesize, int ecctype);
++
++extern struct hinfc610_dbg_inf_t hinfc610_dbg_inf_dump;
++extern struct hinfc610_dbg_inf_t hinfc610_dbg_inf_erase_count;
++extern struct hinfc610_dbg_inf_t hinfc610_dbg_inf_ecc_count;
++extern struct hinfc610_dbg_inf_t hinfc610_dbg_inf_read_retry;
++extern struct hinfc610_dbg_inf_t hinfc610_dbg_inf_read_retry_notice;
++extern struct hinfc610_dbg_inf_t hinfc610_dbg_inf_ecc_notice;
++
++/******************************************************************************/
++#endif /* HINFC610_DBGH */
+diff --git a/drivers/mtd/nand/hinfc610/hinfc610_dbg_dump.c b/drivers/mtd/nand/hinfc610/hinfc610_dbg_dump.c
+new file mode 100644
+index 0000000..e330bb5
+--- /dev/null
++++ b/drivers/mtd/nand/hinfc610/hinfc610_dbg_dump.c
+@@ -0,0 +1,448 @@
++/*
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include <linux/moduleparam.h>
++#include <linux/vmalloc.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/debugfs.h>
++#include <linux/uaccess.h>
++#include <linux/mutex.h>
++
++#include "hinfc610_os.h"
++#include "hinfc610.h"
++#include "hinfc610_dbg.h"
++
++#ifndef CONFIG_HINFC610_DBG_NAND_NUM_OF_LOGS
++#  define CONFIG_HINFC610_DBG_NAND_NUM_OF_LOGS      (80)
++#endif /* CONFIG_HINFC610_DBG_NAND_NUM_OF_LOGS */
++
++#ifndef CONFIG_HINFC610_DBG_NAND_LOG_LENGTH
++#  define CONFIG_HINFC610_DBG_NAND_LOG_LENGTH       (40)
++#endif /* CONFIG_HINFC610_DBG_NAND_LOG_LENGTH */
++
++struct hinfc610_dbg_dump_item_t {
++	unsigned short hour;
++	unsigned short min;
++	unsigned short sec;
++	unsigned short msec;
++
++	unsigned int cycle;
++
++	unsigned long  page;
++	unsigned long  offset;
++	unsigned long  length;
++
++	char page_status[4];
++	char op;
++
++	unsigned char data[CONFIG_HINFC610_DBG_NAND_LOG_LENGTH];
++};
++
++struct hinfc610_dbg_dump_t {
++
++	struct dentry *dentry;
++	unsigned int index; /* current logs index */
++	int count;          /* number of logs */
++
++	unsigned long offset;
++	unsigned long length;
++
++	struct hinfc610_dbg_dump_item_t
++		logs[CONFIG_HINFC610_DBG_NAND_NUM_OF_LOGS];
++
++	unsigned int read_index;
++};
++
++static DEFINE_MUTEX(dbg_dump_mutex);
++static struct hinfc610_dbg_dump_t *dbg_dump;
++
++/*****************************************************************************/
++
++static void do_gettime(unsigned short *hour, unsigned short *min,
++		       unsigned short *sec, unsigned short *msec)
++{
++	long val;
++	struct timeval tv;
++
++	do_gettimeofday(&tv);
++	val = tv.tv_sec % 86400; /* the second form 0 hour */
++
++	if (hour)
++		*hour = val / 3600;
++	val %= 3600;
++	if (min)
++		*min  = val / 60;
++	if (sec)
++		*sec  = val % 60;
++	if (msec)
++		*msec = tv.tv_usec / 1000;
++}
++/*****************************************************************************/
++/*
++ *
++# cat ./debugfs/nand/dump
++Print parameter: "offset=0 length=8"
++UTC Clock   op cylce  page-offset     data
++00:00:33.0321  W  5   0x0000258F-0000   31 18 10 06 18 EF FE 11
++00:00:33.0325  W  5   0x00002740-0000   31 18 10 06 7C D4 B3 0C
++*
++*/
++static ssize_t dbgfs_dump_read(struct file *filp, char __user *buffer,
++			       size_t count, loff_t *ppos)
++{
++	int len = 0;
++	char buf[128] = {0};
++	unsigned int read_index;
++	char __user *pusrbuf = buffer;
++	struct hinfc610_dbg_dump_item_t *logs;
++
++	if (*ppos == 0) {
++
++		if (dbg_dump->count
++		    < CONFIG_HINFC610_DBG_NAND_NUM_OF_LOGS)
++			dbg_dump->read_index = 0;
++		else
++			dbg_dump->read_index
++				= (dbg_dump->index + 1);
++
++		len = snprintf(buf, sizeof(buf),
++			       "Print parameter: \"offset=%ld length=%ld\"\n",
++			       dbg_dump->offset, dbg_dump->length);
++
++		if (copy_to_user(pusrbuf, buf, len))
++			return -EFAULT;
++
++		pusrbuf += len;
++
++		len += snprintf(buf, sizeof(buf),
++				"  UTC Clock   op cylce  page-offset     data\n");
++
++		if (copy_to_user(pusrbuf, buf, len))
++			return -EFAULT;
++
++		pusrbuf += len;
++
++	} else if (dbg_dump->read_index == dbg_dump->index)
++		return 0;
++
++	for (read_index = dbg_dump->read_index;
++	     (read_index != dbg_dump->index);
++	     ++read_index) {
++
++		if (read_index >= CONFIG_HINFC610_DBG_NAND_NUM_OF_LOGS)
++			read_index = 0;
++
++		logs = &dbg_dump->logs[read_index];
++
++		if ((count - (pusrbuf - buffer)) < (50 + logs->length * 3))
++			break;
++
++		len = snprintf(buf, sizeof(buf),
++			       "%02d:%02d:%02d.%04d  %c  %-2u  0x%08lX-%04lX",
++			       logs->hour, logs->min, logs->sec, logs->msec,
++			       logs->op, logs->cycle,
++			       logs->page, logs->offset);
++
++		if (copy_to_user(pusrbuf, buf, len))
++			return -EFAULT;
++
++		pusrbuf += len;
++
++		if (logs->op == 'E') {
++
++			len = snprintf(buf, sizeof(buf), "   ---");
++			if (copy_to_user(pusrbuf, buf, len))
++				return -EFAULT;
++			pusrbuf += len;
++
++		} else {
++
++			int ix;
++
++			len = snprintf(buf, sizeof(buf), "%s",
++				       logs->page_status);
++			if (copy_to_user(pusrbuf, buf, len))
++				return -EFAULT;
++			pusrbuf += len;
++
++			for (ix = 0; ix < logs->length; ix++) {
++				if ((ix % 16) == 15) {
++					len = snprintf(buf, sizeof(buf),
++						       "%02X-",
++						       logs->data[ix]);
++					if (copy_to_user(pusrbuf, buf, len))
++						return -EFAULT;
++					pusrbuf += len;
++				} else {
++					len = snprintf(buf, sizeof(buf),
++						       "%02X ",
++						       logs->data[ix]);
++					if (copy_to_user(pusrbuf, buf, len))
++						return -EFAULT;
++					pusrbuf += len;
++				}
++			}
++		}
++		len = snprintf(buf, sizeof(buf), "\n");
++		if (copy_to_user(pusrbuf, buf, len))
++			return -EFAULT;
++		pusrbuf += len;
++	}
++
++	dbg_dump->read_index = read_index;
++
++	*ppos += (pusrbuf - buffer);
++	return pusrbuf - buffer;
++}
++/*****************************************************************************/
++
++static ssize_t dbgfs_dump_write(struct file *filp, const char __user *buffer,
++				size_t count, loff_t *ppos)
++{
++	char *p;
++	int ret;
++	unsigned long value = 0;
++	char buf[128] = {0};
++	unsigned long pos = 0;
++
++	if (count > sizeof(buf))
++		count = sizeof(buf);
++
++	if (copy_from_user(buf, buffer, count))
++		return -EFAULT;
++
++	while (pos < count) {
++
++		while (pos < count
++		       && (buf[pos] == ' ' ||
++			   buf[pos] == ',' || buf[pos] == ';'))
++			pos++;
++
++		if (pos >= count)
++			break;
++
++		switch (buf[pos]) {
++		case 'o':
++			if (!memcmp(&buf[pos], CMD_WORD_OFFSET,
++				    sizeof(CMD_WORD_OFFSET) - 1)) {
++
++				pos += sizeof(CMD_WORD_OFFSET) - 1;
++				p = (char *)(buf + pos);
++				ret = kstrtoul(p, 10, &value);
++				if (ret < 0)
++					value = 0;
++				dbg_dump->offset = value;
++			}
++			break;
++
++		case 'l':
++			if (!memcmp(&buf[pos], CMD_WORD_LENGTH,
++				    sizeof(CMD_WORD_LENGTH) - 1)) {
++
++				pos += sizeof(CMD_WORD_LENGTH) - 1;
++				p = (char *)(buf + pos);
++				ret = kstrtoul(p, 10, &value);
++				if (ret < 0)
++					value = 0;
++				dbg_dump->length = value;
++			}
++			break;
++		}
++
++		while (pos < count &&
++		       (buf[pos] != ' ' && buf[pos] != ',' && buf[pos] != ';'))
++			pos++;
++	}
++
++	*ppos += count;
++	return count;
++}
++/*****************************************************************************/
++
++static const struct file_operations dbgfs_dump_fops = {
++	.owner = THIS_MODULE,
++	.read  = dbgfs_dump_read,
++	.write = dbgfs_dump_write,
++};
++/*****************************************************************************/
++
++static int dbgfs_dump_init(struct dentry *root, struct hinfc_host *host)
++{
++	struct hinfc610_dbg_dump_t *dump;
++
++	if (dbg_dump)
++		return 0;
++
++	dump = vmalloc(sizeof(struct hinfc610_dbg_dump_t));
++	if (!dump) {
++		PR_ERR("Can't allocate memory.\n");
++		return -ENOMEM;
++	}
++	memset(dump, 0, sizeof(struct hinfc610_dbg_dump_t));
++
++	dump->dentry = debugfs_create_file("dump",
++		S_IFREG | S_IRUSR | S_IWUSR,
++		root, NULL, &dbgfs_dump_fops);
++	if (!dump->dentry) {
++		PR_ERR("Can't create 'dump' file.\n");
++		vfree(dump);
++		return -ENOENT;
++	}
++
++	dump->length = 8;
++
++	dbg_dump = dump;
++
++	return 0;
++}
++/*****************************************************************************/
++
++static int dbgfs_dump_uninit(void)
++{
++	if (!dbg_dump)
++		return 0;
++
++	mutex_lock(&dbg_dump_mutex);
++
++	debugfs_remove(dbg_dump->dentry);
++
++	vfree(dbg_dump);
++	dbg_dump = NULL;
++
++	mutex_unlock(&dbg_dump_mutex);
++
++	return 0;
++}
++/*****************************************************************************/
++
++static void dbg_dump_rw(struct hinfc_host *host, char op)
++{
++	unsigned long buflen;
++	struct hinfc610_dbg_dump_item_t *logs;
++
++	mutex_lock(&dbg_dump_mutex);
++
++	if (!dbg_dump)
++		goto exit;
++
++	buflen = (host->pagesize + host->oobsize);
++	logs = &dbg_dump->logs[dbg_dump->index];
++
++	dbg_dump->count++;
++
++	do_gettime(&logs->hour, &logs->min, &logs->sec, &logs->msec);
++
++	memcpy(logs->page_status, "\x20\x20\x20\x00", 4);
++
++	if (host->page_status) {
++		if (IS_PS_BAD_BLOCK(host))
++			logs->page_status[0] = 'B';
++		else if (IS_PS_EMPTY_PAGE(host))
++			logs->page_status[0] = 'E';
++
++		if (IS_PS_UN_ECC(host))
++			logs->page_status[1] = '*';
++
++		if (IS_PS_EPM_ERR(host) || IS_PS_BBM_ERR(host))
++			logs->page_status[2] = '?';
++	}
++
++	logs->op = op;
++	logs->cycle = host->addr_cycle;
++	logs->length = dbg_dump->length;
++	logs->offset = (host->addr_value[0] & 0xFFFF);
++	logs->page   = GET_PAGE_INDEX(host);
++
++	if (!logs->offset)
++		logs->offset = dbg_dump->offset;
++
++	if (logs->offset >= buflen)
++		logs->offset = 0;
++
++	if (logs->length > (buflen - logs->offset))
++		logs->length = (buflen - logs->offset);
++
++	if (logs->length > CONFIG_HINFC610_DBG_NAND_LOG_LENGTH)
++		logs->length = CONFIG_HINFC610_DBG_NAND_LOG_LENGTH;
++
++	memcpy(logs->data, (host->buffer + logs->offset), logs->length);
++
++	if (++dbg_dump->index >= CONFIG_HINFC610_DBG_NAND_NUM_OF_LOGS)
++		dbg_dump->index = 0;
++
++exit:
++	mutex_unlock(&dbg_dump_mutex);
++}
++/*****************************************************************************/
++
++static void dbg_dump_read(struct hinfc_host *host)
++{
++	dbg_dump_rw(host, 'R');
++}
++/*****************************************************************************/
++
++static void dbg_dump_write(struct hinfc_host *host)
++{
++	dbg_dump_rw(host, 'W');
++}
++/*****************************************************************************/
++
++static void dbg_dump_erase(struct hinfc_host *host)
++{
++	struct hinfc610_dbg_dump_item_t *logs;
++
++	mutex_lock(&dbg_dump_mutex);
++
++	if (!dbg_dump)
++		goto exit;
++
++	dbg_dump->count++;
++	logs = &dbg_dump->logs[dbg_dump->index];
++
++	do_gettime(&logs->hour, &logs->min, &logs->sec, &logs->msec);
++
++	memcpy(logs->page_status, "\x20\x20\x20\x00", 4);
++
++	logs->op = 'E';
++	logs->cycle  = host->addr_cycle;
++	logs->length = dbg_dump->length;
++
++	logs->offset = 0;
++	logs->page   = host->addr_value[0];
++	logs->length = 0;
++
++	if (++dbg_dump->index >= CONFIG_HINFC610_DBG_NAND_NUM_OF_LOGS)
++		dbg_dump->index = 0;
++
++exit:
++	mutex_unlock(&dbg_dump_mutex);
++}
++/*****************************************************************************/
++
++struct hinfc610_dbg_inf_t hinfc610_dbg_inf_dump = {
++	"dump", 0,
++	dbgfs_dump_init,
++	dbgfs_dump_uninit,
++	dbg_dump_read,
++	dbg_dump_write,
++	dbg_dump_erase,
++	NULL,
++};
++/*****************************************************************************/
+diff --git a/drivers/mtd/nand/hinfc610/hinfc610_dbg_ecc_count.c b/drivers/mtd/nand/hinfc610/hinfc610_dbg_ecc_count.c
+new file mode 100644
+index 0000000..b7174ab
+--- /dev/null
++++ b/drivers/mtd/nand/hinfc610/hinfc610_dbg_ecc_count.c
+@@ -0,0 +1,401 @@
++/*
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include <linux/moduleparam.h>
++#include <linux/vmalloc.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/debugfs.h>
++#include <linux/uaccess.h>
++#include <linux/mutex.h>
++
++#include "hinfc610_os.h"
++#include "hinfc610.h"
++#include "hinfc610_dbg.h"
++
++#ifndef CONFIG_HINFC610_DBG_ECC_COUNT_NUM
++#  define CONFIG_HINFC610_DBG_ECC_COUNT_NUM          (100)
++#endif /* CONFIG_HINFC610_DBG_ECC_COUNT_NUM */
++
++struct hinfc610_dbg_ecc_count_item_t {
++	unsigned int page;
++	unsigned int page_status;    /* the same as host->page_status */
++	unsigned short hour;
++	unsigned short min;
++	unsigned short sec;
++	unsigned short msec;
++
++	unsigned char ecc[4];
++};
++
++struct hinfc610_dbg_ecc_count_t {
++
++	struct dentry *dentry;
++	unsigned int index; /* current logs index */
++	int count;          /* number of logs */
++
++	struct hinfc610_ecc_inf_t *ecc_inf;
++	unsigned int offset;
++	unsigned int length;
++	unsigned int pagecount;
++
++	unsigned char *item;
++
++	unsigned int read_index;
++};
++
++#define GET_ITEM(_ecc_count, _index)     \
++	((struct hinfc610_dbg_ecc_count_item_t *)((_ecc_count)->item + \
++		((sizeof(struct hinfc610_dbg_ecc_count_item_t) + \
++			(_ecc_count)->ecc_inf->section) * (_index))))
++
++static DEFINE_MUTEX(dbg_ecc_count_mutex);
++static struct hinfc610_dbg_ecc_count_t *dbg_ecc_count;
++/*****************************************************************************/
++
++static void do_gettime(unsigned short *hour, unsigned short *min,
++		       unsigned short *sec, unsigned short *msec)
++{
++	long val;
++	struct timeval tv;
++
++	do_gettimeofday(&tv);
++	val = tv.tv_sec % 86400; /* the second form 0 hour */
++
++	if (hour)
++		*hour = val / 3600;
++	val %= 3600;
++	if (min)
++		*min  = val / 60;
++	if (sec)
++		*sec  = val % 60;
++	if (msec)
++		*msec = tv.tv_usec / 1000;
++}
++/*****************************************************************************/
++
++static ssize_t dbgfs_ecc_count_read(struct file *filp, char __user *buffer,
++				    size_t count, loff_t *ppos)
++{
++	int len = 0;
++	char buf[128] = {0};
++	unsigned int read_index;
++	char __user *pusrbuf = buffer;
++	struct hinfc610_dbg_ecc_count_item_t *item;
++
++	if (*ppos == 0) {
++
++		if (dbg_ecc_count->count
++		    < CONFIG_HINFC610_DBG_ECC_COUNT_NUM)
++			dbg_ecc_count->read_index = 0;
++		else
++			dbg_ecc_count->read_index
++				= (dbg_ecc_count->index + 1);
++
++		len = snprintf(buf, sizeof(buf),
++			"Print parameter: \"offset=%d length=%d\"\n",
++			dbg_ecc_count->offset,
++			dbg_ecc_count->length);
++
++		if (copy_to_user(pusrbuf, buf, len))
++			return -EFAULT;
++
++		pusrbuf += len;
++
++		len = snprintf(buf, sizeof(buf),
++			"  UTC Clock    page          ecc data\n");
++
++		if (copy_to_user(pusrbuf, buf, len))
++			return -EFAULT;
++
++		pusrbuf += len;
++
++	} else if (dbg_ecc_count->read_index == dbg_ecc_count->index)
++		return 0;
++
++	for (read_index = dbg_ecc_count->read_index;
++	     (read_index != dbg_ecc_count->index); ++read_index) {
++
++		if (read_index >= CONFIG_HINFC610_DBG_ECC_COUNT_NUM)
++			read_index = 0;
++
++		item = GET_ITEM(dbg_ecc_count, read_index);
++
++		if ((count - (pusrbuf - buffer)) < 80)
++			break;
++
++		len = snprintf(buf, sizeof(buf),
++			"%02d:%02d:%02d.%04d  0x%08X    ",
++			item->hour, item->min, item->sec, item->msec,
++			item->page);
++
++		if (copy_to_user(pusrbuf, buf, len))
++			return -EFAULT;
++
++		pusrbuf += len;
++
++		if (IS_PS_BAD_BLOCK(item) || IS_PS_EMPTY_PAGE(item) ||
++		    IS_PS_UN_ECC(item)) {
++			char *ptr = buf;
++
++			if (IS_PS_BAD_BLOCK(item))
++				ptr += snprintf(ptr, 16, "bb ");
++			else if (IS_PS_EMPTY_PAGE(item))
++				ptr += snprintf(ptr, 16, "ep ");
++
++			if (IS_PS_UN_ECC(item))
++				ptr += snprintf(ptr, 16, "ecc ");
++
++			if (IS_PS_EPM_ERR(item) || IS_PS_BBM_ERR(item))
++				ptr += snprintf(ptr, 16, "? ");
++
++			ptr += snprintf(ptr, 16, "\n");
++			len = (ptr - buf);
++
++		} else {
++			int ix;
++			char *ptr = buf;
++
++			for (ix = 0; ix < dbg_ecc_count->ecc_inf->section; ix++)
++				ptr += snprintf(ptr, 16, "%d/", item->ecc[ix]);
++
++			if (IS_PS_EPM_ERR(item))
++				ptr += snprintf(ptr, 16, " ?");
++
++			ptr += snprintf(ptr, 16, "\n");
++			len = (ptr - buf);
++		}
++
++		if (copy_to_user(pusrbuf, buf, len))
++			return -EFAULT;
++		pusrbuf += len;
++	}
++
++	dbg_ecc_count->read_index = read_index;
++
++	*ppos += (pusrbuf - buffer);
++	return pusrbuf - buffer;
++}
++/******************************************************************************/
++/*
++ * echo "offset=8192,length=102400" > ecc_count
++ *
++ */
++static ssize_t dbgfs_ecc_count_write(struct file *filp,
++				     const char __user *buffer, size_t count,
++				     loff_t *ppos)
++{
++	char *str;
++	char buf[128] = {0};
++	int ret;
++	unsigned long value = 0;
++	unsigned long pos = 0;
++
++	if (count > sizeof(buf))
++		count = sizeof(buf);
++
++	if (copy_from_user(buf, buffer, count))
++		return -EFAULT;
++
++	while (pos < count) {
++		while (pos < count &&
++			(buf[pos] == ' ' || buf[pos] == ',' || buf[pos] == ';'))
++			pos++;
++
++		if (pos >= count)
++			break;
++
++		switch (buf[pos]) {
++
++		case 'o':
++
++			if (memcmp(&buf[pos], CMD_WORD_OFFSET,
++				sizeof(CMD_WORD_OFFSET) - 1))
++				break;
++
++			pos += sizeof(CMD_WORD_OFFSET) - 1;
++			str = (char *)(buf + pos);
++			ret = kstrtoul(str, 10, &value);
++
++			if (ret < 0)
++				value = 0;
++			if (value >= dbg_ecc_count->pagecount)
++				value = 0;
++
++			dbg_ecc_count->offset = (value & ~7);
++
++			break;
++
++		case 'l':
++			if (memcmp(&buf[pos], CMD_WORD_LENGTH,
++				sizeof(CMD_WORD_LENGTH) - 1))
++				break;
++
++			pos += sizeof(CMD_WORD_LENGTH) - 1;
++			str = (char *)(buf + pos);
++			ret = kstrtoul(str, 10, &value);
++
++			if (ret < 0)
++				value = dbg_ecc_count->pagecount;
++
++			value = ((value + 7) & ~7);
++
++			if (dbg_ecc_count->offset + value >
++			    dbg_ecc_count->pagecount)
++				value = dbg_ecc_count->pagecount
++					- dbg_ecc_count->offset;
++
++			dbg_ecc_count->length = value;
++
++			break;
++		}
++
++		while (pos < count &&
++			(buf[pos] != ' ' && buf[pos] != ',' && buf[pos] != ';'))
++			pos++;
++	}
++
++	return count;
++}
++/******************************************************************************/
++
++static const struct file_operations dbgfs_ecc_count_fops = {
++	.owner = THIS_MODULE,
++	.read  = dbgfs_ecc_count_read,
++	.write = dbgfs_ecc_count_write,
++};
++/*****************************************************************************/
++
++static int dbgfs_ecc_count_init(struct dentry *root, struct hinfc_host *host)
++{
++	unsigned int size;
++	unsigned int pagesize;
++	unsigned int chipsize;
++	struct hinfc610_ecc_inf_t *ecc_inf;
++	struct hinfc610_dbg_ecc_count_t *ecc_count;
++
++	if (dbg_ecc_count)
++		return 0;
++
++	ecc_inf = hinfc610_get_ecc_inf(host, host->pagesize, host->ecctype);
++	if (!ecc_inf) {
++		pr_warn("ecc_count: The NAND not support this interface.\n");
++		return -1;
++	}
++
++	size = sizeof(struct hinfc610_dbg_ecc_count_t);
++	size += CONFIG_HINFC610_DBG_ECC_COUNT_NUM *
++		(sizeof(struct hinfc610_dbg_ecc_count_item_t)
++		 + ecc_inf->section);
++
++	ecc_count = vmalloc(size);
++	if (!ecc_count) {
++		PR_ERR("Can't allocate memory.\n");
++		return -ENOMEM;
++	}
++	memset(ecc_count, 0, size);
++
++	ecc_count->item = (char *)ecc_count +
++		sizeof(struct hinfc610_dbg_ecc_count_t);
++	ecc_count->ecc_inf = ecc_inf;
++
++	pagesize  = (host->pagesize >> 10);
++	chipsize = (unsigned int)(host->chip->chipsize >> 10);
++	ecc_count->pagecount = (chipsize / pagesize);
++	ecc_count->length = ecc_count->pagecount;
++
++	ecc_count->dentry = debugfs_create_file("ecc_count",
++		S_IFREG | S_IRUSR | S_IWUSR,
++		root, NULL, &dbgfs_ecc_count_fops);
++	if (!ecc_count->dentry) {
++		PR_ERR("Can't create 'ecc_count' file.\n");
++		vfree(ecc_count);
++		return -ENOENT;
++	}
++
++	dbg_ecc_count = ecc_count;
++
++	return 0;
++}
++/*****************************************************************************/
++
++static int dbgfs_ecc_count_uninit(void)
++{
++	if (!dbg_ecc_count)
++		return 0;
++
++	mutex_lock(&dbg_ecc_count_mutex);
++
++	debugfs_remove(dbg_ecc_count->dentry);
++
++	vfree(dbg_ecc_count);
++	dbg_ecc_count = NULL;
++
++	mutex_unlock(&dbg_ecc_count_mutex);
++
++	return 0;
++}
++/*****************************************************************************/
++
++static void dbg_ecc_count_read(struct hinfc_host *host)
++{
++	unsigned int page;
++	struct hinfc610_dbg_ecc_count_item_t *item;
++
++	mutex_lock(&dbg_ecc_count_mutex);
++
++	if (!dbg_ecc_count)
++		goto exit;
++
++	page = GET_PAGE_INDEX(host);
++
++	if (page < dbg_ecc_count->offset ||
++	    page > (dbg_ecc_count->offset + dbg_ecc_count->length))
++		goto exit;
++
++	item = GET_ITEM(dbg_ecc_count, dbg_ecc_count->index);
++
++	dbg_ecc_count->count++;
++
++	do_gettime(&item->hour, &item->min, &item->sec, &item->msec);
++
++	item->page = page;
++	item->page_status = host->page_status;
++
++	if (!IS_PS_UN_ECC(host))
++		dbg_ecc_count->ecc_inf->ecc_inf(host, item->ecc);
++
++	if (++dbg_ecc_count->index >= CONFIG_HINFC610_DBG_ECC_COUNT_NUM)
++		dbg_ecc_count->index = 0;
++
++exit:
++	mutex_unlock(&dbg_ecc_count_mutex);
++}
++/*****************************************************************************/
++
++struct hinfc610_dbg_inf_t hinfc610_dbg_inf_ecc_count = {
++	"ecc_count", 0,
++	dbgfs_ecc_count_init,
++	dbgfs_ecc_count_uninit,
++	dbg_ecc_count_read,
++	NULL,
++	NULL,
++	NULL,
++};
++/*****************************************************************************/
+diff --git a/drivers/mtd/nand/hinfc610/hinfc610_dbg_ecc_dump.c b/drivers/mtd/nand/hinfc610/hinfc610_dbg_ecc_dump.c
+new file mode 100644
+index 0000000..a1b7eda
+--- /dev/null
++++ b/drivers/mtd/nand/hinfc610/hinfc610_dbg_ecc_dump.c
+@@ -0,0 +1,141 @@
++/*
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include <linux/moduleparam.h>
++#include <linux/vmalloc.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/debugfs.h>
++#include <linux/uaccess.h>
++
++#include "hinfc610_os.h"
++#include "hinfc610.h"
++#include "hinfc610_dbg.h"
++
++/*****************************************************************************/
++static inline void hinfc610_detect_ecc(unsigned char ecc[], int begin,
++				       int end, unsigned int reg)
++{
++	while (begin < end) {
++		ecc[begin] = (reg & 0xff);
++		reg = (reg >> 8);
++		begin++;
++	}
++}
++/*****************************************************************************/
++
++static void hinfc610_ecc_32k(struct hinfc_host *host, unsigned char ecc[])
++{
++	int ix, jx, kx;
++
++	for (ix = 0, jx = 0; ix < 4; ix ++, jx += 4)
++		hinfc610_detect_ecc(ecc, jx, jx + 4,
++				    hinfc_read(host, 0xA0 + jx));
++	kx = jx;
++	for (ix = 0, jx = 0; ix < 4; ix ++, jx += 4)
++		hinfc610_detect_ecc(ecc, kx, kx + 4,
++				    hinfc_read(host, 0xDC + jx));
++}
++/*****************************************************************************/
++
++static void hinfc610_ecc_16k(struct hinfc_host *host, unsigned char ecc[])
++{
++	int ix, jx;
++
++	for (ix = 0, jx = 0; ix < 4; ix ++, jx += 4)
++		hinfc610_detect_ecc(ecc, jx, jx + 4,
++				    hinfc_read(host, 0xA0 + jx));
++}
++/*****************************************************************************/
++
++static void hinfc610_ecc_8k(struct hinfc_host *host, unsigned char ecc[])
++{
++	int ix, jx;
++
++	for (ix = 0, jx = 0; ix < 2; ix ++, jx += 4)
++		hinfc610_detect_ecc(ecc, jx, jx + 4,
++				    hinfc_read(host, 0xA0 + jx));
++}
++/*****************************************************************************/
++
++static void hinfc610_ecc_4k(struct hinfc_host *host, unsigned char ecc[])
++{
++	hinfc610_detect_ecc(ecc, 0, 4, hinfc_read(host, 0xA0));
++}
++/*****************************************************************************/
++
++static void hinfc610_ecc_2k(struct hinfc_host *host, unsigned char ecc[])
++{
++	hinfc610_detect_ecc(ecc, 0, 2, hinfc_read(host, 0xA0));
++}
++/*****************************************************************************/
++
++static struct hinfc610_ecc_inf_t hinfc610_ecc_inf[] = {
++
++	{32768, NAND_ECC_80BIT, 32, hinfc610_ecc_32k},
++	{32768, NAND_ECC_72BIT, 32, hinfc610_ecc_32k},
++	{32768, NAND_ECC_60BIT, 32, hinfc610_ecc_32k},
++	{32768, NAND_ECC_48BIT, 32, hinfc610_ecc_32k},
++	{32768, NAND_ECC_41BIT, 32, hinfc610_ecc_32k},
++
++	{16384, NAND_ECC_80BIT, 16, hinfc610_ecc_16k},
++	{16384, NAND_ECC_72BIT, 16, hinfc610_ecc_16k},
++	{16384, NAND_ECC_60BIT, 16, hinfc610_ecc_16k},
++	{16384, NAND_ECC_48BIT, 16, hinfc610_ecc_16k},
++	{16384, NAND_ECC_41BIT, 16, hinfc610_ecc_16k},
++
++	{8192, NAND_ECC_80BIT, 8, hinfc610_ecc_8k},
++	{8192, NAND_ECC_72BIT, 8, hinfc610_ecc_8k},
++	{8192, NAND_ECC_60BIT, 8, hinfc610_ecc_8k},
++	{8192, NAND_ECC_48BIT, 8, hinfc610_ecc_8k},
++	{8192, NAND_ECC_41BIT, 8, hinfc610_ecc_8k},
++	{8192, NAND_ECC_32BIT, 8, hinfc610_ecc_8k},
++	{8192, NAND_ECC_27BIT, 8, hinfc610_ecc_8k},
++	{8192, NAND_ECC_24BIT, 8, hinfc610_ecc_8k},
++
++
++
++	{4096, NAND_ECC_32BIT, 4, hinfc610_ecc_4k},
++	{4096, NAND_ECC_27BIT, 4, hinfc610_ecc_4k},
++	{4096, NAND_ECC_24BIT, 4, hinfc610_ecc_4k},
++	{4096, NAND_ECC_18BIT, 4, hinfc610_ecc_4k},
++	{4096, NAND_ECC_13BIT, 4, hinfc610_ecc_4k},
++	{4096, NAND_ECC_8BIT,  4, hinfc610_ecc_4k},
++
++	{2048, NAND_ECC_32BIT, 2, hinfc610_ecc_2k},
++	{2048, NAND_ECC_27BIT, 2, hinfc610_ecc_2k},
++	{2048, NAND_ECC_24BIT, 2, hinfc610_ecc_2k},
++	{2048, NAND_ECC_18BIT, 2, hinfc610_ecc_2k},
++	{2048, NAND_ECC_13BIT, 2, hinfc610_ecc_2k},
++	{2048, NAND_ECC_8BIT,  2, hinfc610_ecc_2k},
++	{0, 0, 0},
++};
++/*****************************************************************************/
++
++struct hinfc610_ecc_inf_t *hinfc610_get_ecc_inf(struct hinfc_host *host,
++						int pagesize, int ecctype)
++{
++	struct hinfc610_ecc_inf_t *inf;
++
++	for (inf = hinfc610_ecc_inf; inf->pagesize; inf++)
++		if (inf->pagesize == pagesize && inf->ecctype == ecctype)
++			return inf;
++
++	return NULL;
++}
+diff --git a/drivers/mtd/nand/hinfc610/hinfc610_dbg_erase_count.c b/drivers/mtd/nand/hinfc610/hinfc610_dbg_erase_count.c
+new file mode 100644
+index 0000000..eedbd2b
+--- /dev/null
++++ b/drivers/mtd/nand/hinfc610/hinfc610_dbg_erase_count.c
+@@ -0,0 +1,317 @@
++/*
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include <linux/moduleparam.h>
++#include <linux/vmalloc.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/debugfs.h>
++#include <linux/uaccess.h>
++#include <linux/mutex.h>
++
++#include "hinfc610_os.h"
++#include "hinfc610.h"
++#include "hinfc610_dbg.h"
++
++struct hinfc610_dbg_erase_count_t {
++
++	unsigned int index;  /* display pos */
++	unsigned int offset; /* display offset */
++	unsigned int length; /* display length */
++
++	struct dentry *dentry;
++
++	unsigned int blocknum;
++	unsigned int page_per_block;
++
++	unsigned int pe[1];
++};
++
++static DEFINE_MUTEX(dbg_erase_count_mutex);
++static struct hinfc610_dbg_erase_count_t *dbg_erase_count;
++
++/*****************************************************************************/
++
++static int dbgfs_erase_count_read(struct file *filp, char __user *buffer,
++				  size_t count, loff_t *ppos)
++{
++	int len = 0;
++	int value = 0;
++	unsigned int *pe;
++	unsigned int index;
++	char buf[128] = {0};
++	char __user *pusrbuf = buffer;
++
++	if (*ppos == 0) {
++		dbg_erase_count->index = dbg_erase_count->offset;
++
++		len = snprintf(buf, sizeof(buf),
++			"Print parameter: \"offset=%d length=%d\"\n",
++			dbg_erase_count->offset,
++			dbg_erase_count->length);
++
++		if (copy_to_user(pusrbuf, buf, len))
++			return -EFAULT;
++		pusrbuf += len;
++
++		len = snprintf(buf, sizeof(buf),
++			"Block Index  ---------------- "
++			"Erase count from system startup ----------------\n");
++
++		if (copy_to_user(pusrbuf, buf, len))
++			return -EFAULT;
++		pusrbuf += len;
++	}
++
++	for (index = dbg_erase_count->index;
++	     index < (dbg_erase_count->offset + dbg_erase_count->length) &&
++		     ((pusrbuf - buffer) < (count - 100));
++	     index += 8) {
++
++		pe = &dbg_erase_count->pe[index];
++
++		len = snprintf(buf, sizeof(buf),
++			"%4d: %8u %8u %8u %8u  %8u %8u %8u %8u\n",
++			index,
++			pe[0], pe[1], pe[2], pe[3],
++			pe[4], pe[5], pe[6], pe[7]);
++
++		if (copy_to_user(pusrbuf, buf, len))
++			return -EFAULT;
++		pusrbuf += len;
++	}
++
++	dbg_erase_count->index = index;
++
++	*ppos += (pusrbuf - buffer);
++	value = pusrbuf - buffer;
++	return value;
++}
++/*****************************************************************************/
++/*
++ * echo "offset=48,length=78" > /sys/kernel/debug/nand/erase_count
++ * echo "clear" > /sys/kernel/debug/nand/erase_count
++ *
++
++ # cat ./debugfs/nand/erase_count
++ Print parameter: "offset=0 length=1024"
++ Block Index  ---------------- Erase count from system startup ----------------
++  0:        0        0        0        0         0        0        0        0
++  8:        0        0        0        0         0        0        0        0
++ 16:        0        0        0        0         0        0        0        0
++ 24:        0        0        0        0         0        0        0        0
++ 32:        0        0        0        0         0        0        0        0
++ 40:        0        0        0        0         0        0        0        0
++ 48:        0        0        0        0         0        0        0        0
++ 56:        0        0        0        0         0        0        0        0
++ 64:        0        0        0        0         0        0        0        0
++ 72:        0        0        0        0         0        0        0        0
++ 80:        0        0        0        0         0        0        0        0
++
++ */
++static int dbgfs_erase_count_write(struct file *filp,
++				   const char __user *buffer,
++				   size_t count, loff_t *ppos)
++{
++	char *str;
++	char buf[128] = {0};
++	int ret;
++	unsigned long value = 0;
++	unsigned long pos = 0;
++
++	if (count > sizeof(buf))
++		count = sizeof(buf);
++
++	if (copy_from_user(buf, buffer, count))
++		return -EFAULT;
++
++	while (pos < count) {
++		while (pos < count &&
++		       (buf[pos] == ' ' || buf[pos] == ',' || buf[pos] == ';'))
++			pos++;
++
++		if (pos >= count)
++			break;
++
++		switch (buf[pos]) {
++
++		case 'o':
++
++			if (memcmp(&buf[pos], CMD_WORD_OFFSET,
++				    sizeof(CMD_WORD_OFFSET) - 1))
++				break;
++
++			pos += sizeof(CMD_WORD_OFFSET) - 1;
++			str = (char *)(buf + pos);
++			ret = kstrtoul(str, 10, &value);
++			if (ret < 0)
++				value = 0;
++			if (value >= dbg_erase_count->blocknum)
++				value = 0;
++
++			dbg_erase_count->offset = (value & ~7);
++
++			break;
++
++		case 'l':
++			if (memcmp(&buf[pos], CMD_WORD_LENGTH,
++				sizeof(CMD_WORD_LENGTH) - 1))
++				break;
++
++			pos += sizeof(CMD_WORD_LENGTH) - 1;
++			str = (char *)(buf + pos);
++			ret = kstrtoul(str, 10, &value);
++			if (ret < 0)
++				value = dbg_erase_count->blocknum;
++
++			value = ((value + 7) & ~7);
++
++			if (dbg_erase_count->offset + value
++			    > dbg_erase_count->blocknum)
++				value = dbg_erase_count->blocknum
++					- dbg_erase_count->offset;
++
++			dbg_erase_count->length = value;
++
++			break;
++
++		case 'c':
++			if (memcmp(&buf[pos], CMD_WORD_CLEAN,
++				sizeof(CMD_WORD_CLEAN) - 1))
++				break;
++
++			memset(dbg_erase_count->pe, 0,
++			       dbg_erase_count->blocknum *
++			       sizeof(struct hinfc610_dbg_erase_count_t));
++
++			return count;
++		}
++
++		while (pos < count &&
++		       (buf[pos] != ' ' && buf[pos] != ',' && buf[pos] != ';'))
++			pos++;
++	}
++
++	return count;
++}
++/*****************************************************************************/
++
++static const struct file_operations dbgfs_erase_count_fops = {
++	.owner = THIS_MODULE,
++	.read  = dbgfs_erase_count_read,
++	.write = dbgfs_erase_count_write,
++};
++/*****************************************************************************/
++
++static int dbgfs_erase_count_init(struct dentry *root, struct hinfc_host *host)
++{
++	unsigned int size;
++	unsigned int blocknum;
++	unsigned int pagesize;
++	unsigned int blocksize;
++	unsigned int chipsize;
++	struct hinfc610_dbg_erase_count_t *erase_count;
++
++	if (dbg_erase_count)
++		return 0;
++
++	pagesize  = (host->pagesize >> 10);
++	blocksize = (host->mtd->erasesize >> 10);
++	chipsize = (unsigned int)(host->chip->chipsize >> 10);
++
++	blocknum = chipsize / blocksize;
++	size = sizeof(int) * blocknum
++		+ sizeof(struct hinfc610_dbg_erase_count_t);
++
++	erase_count = vmalloc(size);
++	if (!erase_count) {
++		PR_ERR("Can't allocate memory.\n");
++		return -ENOMEM;
++	}
++	memset(erase_count, 0, size);
++
++	erase_count->blocknum = blocknum;
++	erase_count->page_per_block = blocksize / pagesize;
++	erase_count->length = blocknum;
++
++	erase_count->dentry = debugfs_create_file("erase_count",
++		S_IFREG | S_IRUSR | S_IWUSR,
++		root, NULL, &dbgfs_erase_count_fops);
++	if (!erase_count->dentry) {
++		PR_ERR("Can't create 'erase_count' file.\n");
++		vfree(erase_count);
++		return -ENOENT;
++	}
++
++	dbg_erase_count = erase_count;
++
++	return 0;
++}
++/*****************************************************************************/
++
++static int dbgfs_erase_count_uninit(void)
++{
++	if (!dbg_erase_count)
++		return 0;
++
++	mutex_lock(&dbg_erase_count_mutex);
++
++	debugfs_remove(dbg_erase_count->dentry);
++
++	vfree(dbg_erase_count);
++	dbg_erase_count = NULL;
++
++	mutex_unlock(&dbg_erase_count_mutex);
++
++	return 0;
++}
++/*****************************************************************************/
++
++static void dbg_erase_count_erase(struct hinfc_host *host)
++{
++	unsigned int block_index;
++
++	mutex_lock(&dbg_erase_count_mutex);
++
++	if (!dbg_erase_count)
++		goto exit;
++
++	block_index = (host->addr_value[0] / dbg_erase_count->page_per_block);
++
++	if (block_index > dbg_erase_count->blocknum) {
++		PR_ERR("Block out of range.\n");
++		return;
++	}
++
++	dbg_erase_count->pe[block_index]++;
++
++exit:
++	mutex_unlock(&dbg_erase_count_mutex);
++}
++/*****************************************************************************/
++
++struct hinfc610_dbg_inf_t hinfc610_dbg_inf_erase_count = {
++	"erase_count", 0,
++	dbgfs_erase_count_init,
++	dbgfs_erase_count_uninit,
++	NULL,
++	NULL,
++	dbg_erase_count_erase,
++	NULL,
++};
+diff --git a/drivers/mtd/nand/hinfc610/hinfc610_dbg_inf.c b/drivers/mtd/nand/hinfc610/hinfc610_dbg_inf.c
+new file mode 100644
+index 0000000..f3e7140
+--- /dev/null
++++ b/drivers/mtd/nand/hinfc610/hinfc610_dbg_inf.c
+@@ -0,0 +1,81 @@
++/*
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include <linux/moduleparam.h>
++#include <linux/vmalloc.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/debugfs.h>
++#include <linux/uaccess.h>
++
++#include "hinfc610_os.h"
++#include "hinfc610.h"
++#include "hinfc610_dbg.h"
++
++void hinfc610_dbg_write(struct hinfc_host *host)
++{
++#ifdef CONFIG_HINFC610_DBG_NAND_DEBUG
++	struct hinfc610_dbg_inf_t **inf;
++
++	for (inf = hinfc610_dbg_inf; *inf; inf++)
++		if ((*inf)->enable && (*inf)->write)
++			(*inf)->write(host);
++#endif
++}
++
++void hinfc610_dbg_erase(struct hinfc_host *host)
++{
++#ifdef CONFIG_HINFC610_DBG_NAND_DEBUG
++	struct hinfc610_dbg_inf_t **inf;
++
++	for (inf = hinfc610_dbg_inf; *inf; inf++)
++		if ((*inf)->enable && (*inf)->erase)
++			(*inf)->erase(host);
++#endif
++}
++
++void hinfc610_dbg_read(struct hinfc_host *host)
++{
++#ifdef CONFIG_HINFC610_DBG_NAND_DEBUG
++	struct hinfc610_dbg_inf_t **inf;
++
++	for (inf = hinfc610_dbg_inf; *inf; inf++)
++		if ((*inf)->enable && (*inf)->read)
++			(*inf)->read(host);
++#endif
++}
++
++void hinfc610_dbg_read_retry(struct hinfc_host *host, int index)
++{
++#ifdef CONFIG_HINFC610_DBG_NAND_DEBUG
++	struct hinfc610_dbg_inf_t **inf;
++
++	for (inf = hinfc610_dbg_inf; *inf; inf++)
++		if ((*inf)->enable && (*inf)->read_retry)
++			(*inf)->read_retry(host, index);
++#endif
++}
++
++int hinfc610_dbg_init(struct hinfc_host *host)
++{
++#ifdef CONFIG_HINFC610_DBG_NAND_DEBUG
++	return hinfc610_dbgfs_debug_init(host);
++#endif
++	return 0;
++}
+diff --git a/drivers/mtd/nand/hinfc610/hinfc610_dbg_inf.h b/drivers/mtd/nand/hinfc610/hinfc610_dbg_inf.h
+new file mode 100644
+index 0000000..10ac797
+--- /dev/null
++++ b/drivers/mtd/nand/hinfc610/hinfc610_dbg_inf.h
+@@ -0,0 +1,34 @@
++/*
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#ifndef HINFC610_DBG_INFH
++#define HINFC610_DBG_INFH
++/******************************************************************************/
++
++int hinfc610_dbg_init(struct hinfc_host *host);
++
++void hinfc610_dbg_write(struct hinfc_host *host);
++
++void hinfc610_dbg_erase(struct hinfc_host *host);
++
++void hinfc610_dbg_read(struct hinfc_host *host);
++
++void hinfc610_dbg_read_retry(struct hinfc_host *host, int index);
++
++/******************************************************************************/
++#endif /* HINFC610_DBG_INFH */
+diff --git a/drivers/mtd/nand/hinfc610/hinfc610_dbg_read_retry.c b/drivers/mtd/nand/hinfc610/hinfc610_dbg_read_retry.c
+new file mode 100644
+index 0000000..176d9c1
+--- /dev/null
++++ b/drivers/mtd/nand/hinfc610/hinfc610_dbg_read_retry.c
+@@ -0,0 +1,385 @@
++/*
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include <linux/moduleparam.h>
++#include <linux/vmalloc.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/debugfs.h>
++#include <linux/uaccess.h>
++#include <linux/mutex.h>
++
++#include "hinfc610_os.h"
++#include "hinfc610.h"
++#include "hinfc610_dbg.h"
++
++#ifndef CONFIG_HINFC610_DBG_READ_RETRY_NUM
++#  define CONFIG_HINFC610_DBG_READ_RETRY_NUM          (100)
++#endif /* CONFIG_HINFC610_DBG_READ_RETRY_NUM */
++
++struct hinfc610_dbg_read_retry_item_t {
++	unsigned int page;
++
++	unsigned short hour;
++	unsigned short min;
++	unsigned short sec;
++	unsigned short msec;
++
++	unsigned short retry;  /* success retry */
++	unsigned short ecc_err;
++};
++
++struct hinfc610_dbg_read_retry_t {
++
++	struct dentry *dentry;
++	unsigned int index; /* current logs index */
++	int count;          /* number of logs */
++
++	unsigned int offset;
++	unsigned int length;
++	unsigned int pagecount;
++
++	unsigned int read_index;
++
++	unsigned int max_retry; /* the max read retry times */
++	unsigned int retry[16];
++
++	struct hinfc610_dbg_read_retry_item_t
++		item[CONFIG_HINFC610_DBG_READ_RETRY_NUM];
++};
++
++static DEFINE_MUTEX(dbg_read_retry_mutex);
++static struct hinfc610_dbg_read_retry_t *dbg_read_retry;
++/*****************************************************************************/
++
++static void do_gettime(unsigned short *hour, unsigned short *min,
++		       unsigned short *sec, unsigned short *msec)
++{
++	long val;
++	struct timeval tv;
++
++	do_gettimeofday(&tv);
++	val = tv.tv_sec % 86400; /* the second form 0 hour */
++
++	if (hour)
++		*hour = val / 3600;
++	val %= 3600;
++	if (min)
++		*min  = val / 60;
++	if (sec)
++		*sec  = val % 60;
++	if (msec)
++		*msec = tv.tv_usec / 1000;
++}
++/*****************************************************************************/
++
++static ssize_t dbgfs_read_retry_read(struct file *filp, char __user *buffer,
++				    size_t count, loff_t *ppos)
++{
++	int ix;
++	char *ptr;
++	int len = 0;
++	char buf[128] = {0};
++	unsigned int read_index;
++	char __user *pusrbuf = buffer;
++	struct hinfc610_dbg_read_retry_item_t *item;
++
++	if (*ppos == 0) {
++
++		if (dbg_read_retry->count
++		    < CONFIG_HINFC610_DBG_READ_RETRY_NUM)
++			dbg_read_retry->read_index = 0;
++		else
++			dbg_read_retry->read_index
++				= (dbg_read_retry->index + 1);
++
++		len = snprintf(buf, sizeof(buf),
++			"Print parameter: \"offset=%d length=%d\"\n",
++			dbg_read_retry->offset,
++			dbg_read_retry->length);
++
++		if (copy_to_user(pusrbuf, buf, len))
++			return -EFAULT;
++		pusrbuf += len;
++
++		len = snprintf(buf, sizeof(buf),
++			"  UTC Clock    page          read retry (max: %d)\n",
++			dbg_read_retry->max_retry);
++
++		ptr = buf;
++		ptr += sprintf(ptr, "Read retry: ");
++		for (ix = 1; ix <= dbg_read_retry->max_retry; ix++)
++			ptr += sprintf(ptr, "%d, ", dbg_read_retry->retry[ix]);
++		ptr += sprintf(ptr, "\n");
++
++		len = (ptr - buf);
++		if (copy_to_user(pusrbuf, buf, len))
++			return -EFAULT;
++		pusrbuf += len;
++
++
++		len = snprintf(buf, sizeof(buf),
++			"  UTC Clock    page          read retry (max: %d)\n",
++			dbg_read_retry->max_retry);
++
++		if (copy_to_user(pusrbuf, buf, len))
++			return -EFAULT;
++		pusrbuf += len;
++
++	} else if (dbg_read_retry->read_index == dbg_read_retry->index)
++		return 0;
++
++	for (read_index = dbg_read_retry->read_index;
++	     (read_index != dbg_read_retry->index); ++read_index) {
++
++		if (read_index >= CONFIG_HINFC610_DBG_READ_RETRY_NUM)
++			read_index = 0;
++
++		item = &dbg_read_retry->item[read_index];
++
++		if ((count - (pusrbuf - buffer)) < 80)
++			break;
++
++		len = snprintf(buf, sizeof(buf),
++			"%02d:%02d:%02d.%04d  0x%08X    ",
++			item->hour, item->min, item->sec, item->msec,
++			item->page);
++
++		if (copy_to_user(pusrbuf, buf, len))
++			return -EFAULT;
++		pusrbuf += len;
++
++		if (!item->ecc_err)
++			len = sprintf(buf, "%d\n", item->retry);
++		else
++			len = sprintf(buf, "fail\n");
++
++		if (copy_to_user(pusrbuf, buf, len))
++			return -EFAULT;
++		pusrbuf += len;
++	}
++
++	dbg_read_retry->read_index = read_index;
++
++	*ppos += (pusrbuf - buffer);
++	return pusrbuf - buffer;
++}
++/******************************************************************************/
++/*
++ * echo "offset=8192,length=102400" > read_retry
++ *
++ */
++static ssize_t dbgfs_read_retry_write(struct file *filp,
++				     const char __user *buffer, size_t count,
++				     loff_t *ppos)
++{
++	char *str;
++	char buf[128] = {0};
++	int ret;
++	unsigned long value = 0;
++	unsigned long pos = 0;
++
++	if (count > sizeof(buf))
++		count = sizeof(buf);
++
++	if (copy_from_user(buf, buffer, count))
++		return -EFAULT;
++
++	while (pos < count) {
++		while (pos < count &&
++			(buf[pos] == ' ' || buf[pos] == ',' || buf[pos] == ';'))
++			pos++;
++
++		if (pos >= count)
++			break;
++
++		switch (buf[pos]) {
++
++		case 'o':
++
++			if (memcmp(&buf[pos], CMD_WORD_OFFSET,
++				sizeof(CMD_WORD_OFFSET) - 1))
++				break;
++
++			pos += sizeof(CMD_WORD_OFFSET) - 1;
++			str = (char *)(buf + pos);
++			ret = kstrtoul(str, 10, &value);
++
++			if (ret < 0)
++				value = 0;
++			if (value >= dbg_read_retry->pagecount)
++				value = 0;
++
++			dbg_read_retry->offset = (value & ~7);
++
++			break;
++
++		case 'l':
++			if (memcmp(&buf[pos], CMD_WORD_LENGTH,
++				sizeof(CMD_WORD_LENGTH) - 1))
++				break;
++
++			pos += sizeof(CMD_WORD_LENGTH) - 1;
++			str = (char *)(buf + pos);
++			ret = kstrtoul(str, 10, &value);
++
++			if (ret < 0)
++				value = dbg_read_retry->pagecount;
++
++			value = ((value + 7) & ~7);
++
++			if (dbg_read_retry->offset + value >
++			    dbg_read_retry->pagecount)
++				value = dbg_read_retry->pagecount
++					- dbg_read_retry->offset;
++
++			dbg_read_retry->length = value;
++
++			break;
++		}
++
++		while (pos < count &&
++			(buf[pos] != ' ' && buf[pos] != ',' && buf[pos] != ';'))
++			pos++;
++	}
++
++	return count;
++}
++/******************************************************************************/
++
++static const struct file_operations dbgfs_read_retry_fops = {
++	.owner = THIS_MODULE,
++	.read  = dbgfs_read_retry_read,
++	.write = dbgfs_read_retry_write,
++};
++/*****************************************************************************/
++
++static int dbgfs_read_retry_init(struct dentry *root, struct hinfc_host *host)
++{
++	unsigned int pagesize;
++	unsigned int chipsize;
++	struct hinfc610_dbg_read_retry_t *read_retry;
++
++	if (dbg_read_retry)
++		return 0;
++
++	if (!host->read_retry) {
++		pr_warn("read_retry: The NAND not support this interface.\n");
++		return -1;
++	}
++
++	read_retry = vmalloc(sizeof(struct hinfc610_dbg_read_retry_t));
++	if (!read_retry) {
++		PR_ERR("Can't allocate memory.\n");
++		return -ENOMEM;
++	}
++	memset(read_retry, 0, sizeof(struct hinfc610_dbg_read_retry_t));
++
++	pagesize  = (host->pagesize >> 10);
++	chipsize = (unsigned int)(host->chip->chipsize >> 10);
++	read_retry->pagecount = (chipsize / pagesize);
++	read_retry->length = read_retry->pagecount;
++	read_retry->max_retry = host->read_retry->count;
++
++	if (read_retry->max_retry > 16) {
++		vfree(read_retry);
++		PR_ERR("Bug, max_retry too small.\n");
++		return -EFAULT;
++	}
++
++	read_retry->dentry = debugfs_create_file("read_retry",
++		S_IFREG | S_IRUSR | S_IWUSR,
++		root, NULL, &dbgfs_read_retry_fops);
++	if (!read_retry->dentry) {
++		PR_ERR("Can't create 'read_retry' file.\n");
++		vfree(read_retry);
++		return -ENOENT;
++	}
++
++	dbg_read_retry = read_retry;
++
++	return 0;
++}
++/*****************************************************************************/
++
++static int dbgfs_read_retry_uninit(void)
++{
++	if (!dbg_read_retry)
++		return 0;
++
++	mutex_lock(&dbg_read_retry_mutex);
++
++	debugfs_remove(dbg_read_retry->dentry);
++
++	vfree(dbg_read_retry);
++	dbg_read_retry = NULL;
++
++	mutex_unlock(&dbg_read_retry_mutex);
++
++	return 0;
++}
++/*****************************************************************************/
++
++static void hinfc610_dbg_read_retry_rr(struct hinfc_host *host, int index)
++{
++	unsigned int page;
++	struct hinfc610_dbg_read_retry_item_t *item;
++
++	mutex_lock(&dbg_read_retry_mutex);
++
++	if (!dbg_read_retry)
++		goto exit;
++
++	page = GET_PAGE_INDEX(host);
++
++	if (page < dbg_read_retry->offset ||
++	    page > (dbg_read_retry->offset + dbg_read_retry->length))
++		goto exit;
++
++	item = &dbg_read_retry->item[dbg_read_retry->index];
++
++	dbg_read_retry->count++;
++
++	do_gettime(&item->hour, &item->min, &item->sec, &item->msec);
++
++	item->page = page;
++	item->retry = index;
++
++	item->ecc_err = IS_PS_UN_ECC(host) ? 1 : 0;
++	if (!item->ecc_err)
++		dbg_read_retry->retry[index]++;
++
++	if (++dbg_read_retry->index >= CONFIG_HINFC610_DBG_READ_RETRY_NUM)
++		dbg_read_retry->index = 0;
++
++exit:
++	mutex_unlock(&dbg_read_retry_mutex);
++}
++/*****************************************************************************/
++
++struct hinfc610_dbg_inf_t hinfc610_dbg_inf_read_retry = {
++	"read_retry", 0,
++	dbgfs_read_retry_init,
++	dbgfs_read_retry_uninit,
++	NULL,
++	NULL,
++	NULL,
++	hinfc610_dbg_read_retry_rr,
++};
++/*****************************************************************************/
+diff --git a/drivers/mtd/nand/hinfc610/hinfc610_gen.c b/drivers/mtd/nand/hinfc610/hinfc610_gen.c
+new file mode 100644
+index 0000000..2b43cf9
+--- /dev/null
++++ b/drivers/mtd/nand/hinfc610/hinfc610_gen.c
+@@ -0,0 +1,85 @@
++/*
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include "../match_table.h"
++#include "hinfc610_gen.h"
++
++/*****************************************************************************/
++
++static struct match_reg_type page_type2reg[] = {
++	{
++		hinfc610_pagesize_2K, NAND_PAGE_2K,
++	}, {
++		hinfc610_pagesize_4K, NAND_PAGE_4K,
++	}, {
++		hinfc610_pagesize_8K, NAND_PAGE_8K,
++	}, {
++		hinfc610_pagesize_16K, NAND_PAGE_16K,
++	}, {
++		hinfc610_pagesize_32K, NAND_PAGE_32K,
++	}
++};
++
++enum hinfc610_page_reg hinfc610_page_type2reg(int type)
++{
++	return type2reg(page_type2reg, ARRAY_SIZE(page_type2reg), type, 0);
++}
++
++int hinfc610_page_reg2type(enum hinfc610_page_reg reg)
++{
++	return reg2type(page_type2reg, ARRAY_SIZE(page_type2reg), reg, 0);
++}
++/*****************************************************************************/
++
++static struct match_reg_type ecc_type2reg[] = {
++	{
++		hinfc610_ecc_none, NAND_ECC_NONE,
++	}, {
++		hinfc610_ecc_8bit, NAND_ECC_8BIT,
++	}, {
++		hinfc610_ecc_13bit, NAND_ECC_13BIT,
++	}, {
++		hinfc610_ecc_18bit, NAND_ECC_18BIT,
++	}, {
++		hinfc610_ecc_24bit, NAND_ECC_24BIT,
++	}, {
++		hinfc610_ecc_27bit, NAND_ECC_27BIT,
++	}, {
++		hinfc610_ecc_32bit, NAND_ECC_32BIT,
++	}, {
++		hinfc610_ecc_41bit, NAND_ECC_41BIT,
++	}, {
++		hinfc610_ecc_48bit, NAND_ECC_48BIT,
++	}, {
++		hinfc610_ecc_60bit, NAND_ECC_60BIT,
++	}, {
++		hinfc610_ecc_72bit, NAND_ECC_72BIT,
++	}, {
++		hinfc610_ecc_80bit, NAND_ECC_80BIT,
++	}
++};
++
++enum hinfc610_ecc_reg hinfc610_ecc_type2reg(int type)
++{
++	return type2reg(ecc_type2reg, ARRAY_SIZE(ecc_type2reg), type, 0);
++}
++
++int hinfc610_ecc_reg2type(enum hinfc610_ecc_reg reg)
++{
++	return reg2type(ecc_type2reg, ARRAY_SIZE(ecc_type2reg), reg, 0);
++}
+diff --git a/drivers/mtd/nand/hinfc610/hinfc610_gen.h b/drivers/mtd/nand/hinfc610/hinfc610_gen.h
+new file mode 100644
+index 0000000..c41ff6f
+--- /dev/null
++++ b/drivers/mtd/nand/hinfc610/hinfc610_gen.h
+@@ -0,0 +1,57 @@
++/*
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#ifndef HINFC610_GENH
++#define HINFC610_GENH
++/******************************************************************************/
++
++#include "../hinfc_gen.h"
++
++enum hinfc610_ecc_reg {
++	hinfc610_ecc_none   = 0x00,
++	hinfc610_ecc_8bit   = 0x01,
++	hinfc610_ecc_13bit  = 0x02,
++	hinfc610_ecc_18bit  = 0x03,
++	hinfc610_ecc_24bit  = 0x04,
++	hinfc610_ecc_27bit  = 0x05,
++	hinfc610_ecc_32bit  = 0x06,
++	hinfc610_ecc_41bit  = 0x07,
++	hinfc610_ecc_48bit  = 0x08,
++	hinfc610_ecc_60bit  = 0x09,
++	hinfc610_ecc_72bit  = 0x0a,
++	hinfc610_ecc_80bit  = 0x0b,
++};
++
++enum hinfc610_page_reg {
++	hinfc610_pagesize_2K    = 0x01,
++	hinfc610_pagesize_4K    = 0x02,
++	hinfc610_pagesize_8K    = 0x03,
++	hinfc610_pagesize_16K   = 0x04,
++	hinfc610_pagesize_32K   = 0x05,
++};
++
++enum hinfc610_page_reg hinfc610_page_type2reg(int type);
++
++int hinfc610_page_reg2type(enum hinfc610_page_reg reg);
++
++enum hinfc610_ecc_reg hinfc610_ecc_type2reg(int type);
++
++int hinfc610_ecc_reg2type(enum hinfc610_ecc_reg reg);
++
++/******************************************************************************/
++#endif /* HINFC610_GENH */
+diff --git a/drivers/mtd/nand/hinfc610/hinfc610_os.c b/drivers/mtd/nand/hinfc610/hinfc610_os.c
+new file mode 100644
+index 0000000..449ec93
+--- /dev/null
++++ b/drivers/mtd/nand/hinfc610/hinfc610_os.c
+@@ -0,0 +1,394 @@
++/*
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include <linux/of_platform.h>
++#include "hinfc610_os.h"
++#include "hinfc610.h"
++
++#ifdef CONFIG_MTD_PARTITION_FROM_DTS
++/*****************************************************************************/
++static inline int mtd_has_partitions(void) { return 1; }
++#else
++
++/*****************************************************************************/
++#define MAX_MTD_PARTITIONS         (32)
++
++struct partition_entry {
++	char name[16];
++	unsigned long long start;
++	unsigned long long length;
++	unsigned int flags;
++};
++
++struct partition_info {
++	int parts_num;
++	struct partition_entry entry[MAX_MTD_PARTITIONS];
++	struct mtd_partition parts[MAX_MTD_PARTITIONS];
++};
++
++static struct partition_info ptn_info = {0};
++
++static int __init parse_nand_partitions(const struct tag *tag)
++{
++	int i;
++
++	if (tag->hdr.size <= 2) {
++		PR_BUG("tag->hdr.size <= 2\n");
++		return 0;
++	}
++	ptn_info.parts_num = (tag->hdr.size - 2)
++		/ (sizeof(struct partition_entry)/sizeof(int));
++	memcpy(ptn_info.entry,
++		&tag->u,
++		ptn_info.parts_num * sizeof(struct partition_entry));
++
++	for (i = 0; i < ptn_info.parts_num; i++) {
++		ptn_info.parts[i].name   = ptn_info.entry[i].name;
++		ptn_info.parts[i].size   = (ptn_info.entry[i].length);
++		ptn_info.parts[i].offset = (ptn_info.entry[i].start);
++		ptn_info.parts[i].mask_flags = 0;
++		ptn_info.parts[i].ecclayout  = 0;
++	}
++
++	return 0;
++}
++
++/* turn to ascii is "HiNp" */
++__tagtable(0x48694E70, parse_nand_partitions);
++/*****************************************************************************/
++static int hinfc_os_add_paratitions(struct hinfc_host *host)
++{
++	int ix;
++	int nr_parts = 0;
++	struct mtd_partition *parts = NULL;
++	int ret;
++
++#ifdef CONFIG_MTD_CMDLINE_PARTS
++	static const char * const part_probes[] = {"cmdlinepart", NULL, };
++
++	nr_parts = parse_mtd_partitions(host->mtd, part_probes, &parts, 0);
++#endif
++
++	if (!nr_parts) {
++		nr_parts = ptn_info.parts_num;
++		parts    = ptn_info.parts;
++	}
++
++	if (nr_parts <= 0)
++		return 0;
++
++	for (ix = 0; ix < nr_parts; ix++) {
++		DBG_MSG("partitions[%d] = {.name = %s, .offset = 0x%.8x,",
++			ix, parts[ix].name,
++			(unsigned int)parts[ix].offset);
++		DBG_MSG(".size = 0x%08x (%uKiB) }\n",
++			(unsigned int)parts[ix].size,
++			(unsigned int)parts[ix].size/1024);
++	}
++
++	host->add_partition = 1;
++
++	ret = mtd_device_register(host->mtd, parts, nr_parts);
++
++	kfree(parts);
++	parts = NULL;
++
++	return (1 == ret) ? -ENODEV : 0;
++}
++/*****************************************************************************/
++#endif /* CONFIG_MTD_PARTITION_FROM_DTS */
++
++static unsigned int  nand_otp_len;
++static unsigned char nand_otp[128] = {0};
++
++/* Get NAND parameter table. */
++static int __init parse_nand_param(const struct tag *tag)
++{
++	if (tag->hdr.size <= 2)
++		return 0;
++
++	nand_otp_len = ((tag->hdr.size << 2) - sizeof(struct tag_header));
++
++	if (nand_otp_len > sizeof(nand_otp)) {
++		PR_BUG("tag->hdr.size <= 2\n");
++		return 0;
++	}
++	memcpy(nand_otp, &tag->u, nand_otp_len);
++	return 0;
++}
++/* 0x48694E77 equal to fastoot ATAG_NAND_PARAM */
++__tagtable(0x48694E77, parse_nand_param);
++/*****************************************************************************/
++
++static int hinfc610_nand_pre_probe(struct nand_chip *chip)
++{
++	uint8_t nand_maf_id;
++	struct hinfc_host *host = chip->priv;
++
++	/* Reset the chip first */
++	host->send_cmd_reset(host, 0);
++
++	/* Check the ID */
++	host->offset = 0;
++	memset((unsigned char *)(chip->IO_ADDR_R), 0, 0x10);
++	host->send_cmd_readid(host);
++	nand_maf_id = readb(chip->IO_ADDR_R);
++
++	if (nand_maf_id == 0x00 || nand_maf_id == 0xff) {
++		PR_BUG("\nCannot found a valid Nand Device\n");
++		return 1;
++	}
++
++	return 0;
++}
++/*****************************************************************************/
++
++static int hinfc610_os_probe(struct platform_device *pltdev)
++{
++	int size;
++	int result = 0;
++	struct hinfc_host *host;
++	struct nand_chip *chip;
++	struct mtd_info *mtd;
++	struct resource *rs_reg, *rs_io = NULL;
++	struct device *dev = &pltdev->dev;
++	struct device_node *np = NULL;
++#ifdef CONFIG_MTD_PARTITION_FROM_DTS
++	struct mtd_partition *parts = NULL;
++	int nr_parts = 0;
++#endif
++
++	size = sizeof(struct hinfc_host) + sizeof(struct nand_chip)
++		+ sizeof(struct mtd_info);
++	host = kmalloc(size, GFP_KERNEL);
++	if (!host) {
++		PR_BUG("failed to allocate device structure.\n");
++		return -ENOMEM;
++	}
++	memset((char *)host, 0, size);
++	platform_set_drvdata(pltdev, host);
++
++	host->dev  = dev;
++	host->chip = chip = (struct nand_chip *)&host[1];
++	host->mtd  = mtd  = (struct mtd_info *)&chip[1];
++
++	host->clk = devm_clk_get(dev, NULL);
++	if (IS_ERR(host->clk))
++		return PTR_ERR(host->clk);
++
++	/* enable and set system clock */
++	clk_prepare_enable(host->clk);
++
++	rs_reg = platform_get_resource_byname(pltdev, IORESOURCE_MEM,
++				"control");
++	host->iobase = devm_ioremap_resource(dev, rs_reg);
++	if (IS_ERR(host->iobase)) {
++		PR_BUG("Error: Can't get resource for reg address.\n");
++		result = -EIO;
++		goto fail;
++	}
++
++	np = of_get_next_available_child(dev->of_node, NULL);
++
++	mtd->type = MTD_NANDFLASH;
++	mtd->priv  = chip;
++	mtd->flags = MTD_CAP_NANDFLASH;
++	mtd->owner = THIS_MODULE;
++	mtd->name = np->name;
++
++	rs_io = platform_get_resource_byname(pltdev, IORESOURCE_MEM,
++					"memory");
++	chip->IO_ADDR_R = chip->IO_ADDR_W = devm_ioremap_resource(dev, rs_io);
++	if (IS_ERR(chip->IO_ADDR_R)) {
++		PR_BUG("Error: Can't get resource for buffer address.\n");
++		result = -EIO;
++		goto fail;
++	}
++
++	host->buffer = dma_alloc_coherent(host->dev,
++		(NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE),
++		&host->dma_buffer, GFP_KERNEL);
++	if (!host->buffer) {
++		PR_BUG("Can't malloc memory for NAND driver.");
++		result = -EIO;
++		goto fail;
++	}
++
++	chip->priv        = host;
++	host->chip        = chip;
++	chip->cmd_ctrl    = hinfc610_cmd_ctrl;
++	chip->dev_ready   = hinfc610_dev_ready;
++	chip->select_chip = hinfc610_select_chip;
++	chip->read_byte   = hinfc610_read_byte;
++	chip->read_word   = hinfc610_read_word;
++	chip->write_buf   = hinfc610_write_buf;
++	chip->read_buf    = hinfc610_read_buf;
++
++	chip->chip_delay = HINFC610_CHIP_DELAY;
++	chip->options    = NAND_NO_AUTOINCR
++			| NAND_NEED_READRDY
++			| NAND_BROKEN_XD
++			| NAND_SKIP_BBTSCAN;
++	chip->ecc.layout = NULL;
++	chip->ecc.mode   = NAND_ECC_NONE;
++
++	if (hinfc610_nand_init(host, chip)) {
++		PR_BUG("failed to allocate device buffer.\n");
++		result = -EIO;
++		goto fail;
++	}
++
++	if (hinfc610_nand_pre_probe(chip)) {
++		result = -EXDEV;
++		goto fail;
++	}
++
++	if (nand_otp_len) {
++		PR_MSG("Copy Nand read retry parameter from boot,");
++		PR_MSG(" parameter length %d.\n", nand_otp_len);
++		memcpy(host->rr_data, nand_otp, nand_otp_len);
++	}
++
++	if (nand_scan(mtd, CONFIG_HINFC610_MAX_CHIP)) {
++		result = -ENXIO;
++		goto fail;
++	}
++
++#ifdef CONFIG_MTD_PARTITION_FROM_DTS
++	if (mtd_has_partitions()) {
++		static char const *part_probes[] = {
++			"cmdlinepart",
++			NULL,
++		};
++
++		nr_parts = parse_mtd_partitions(host->mtd,
++				part_probes, &parts, 0);
++		PR_MSG("parse mtd partitions: %d\n", nr_parts);
++		if (nr_parts > 0)
++			host->add_partition = 1;
++	}
++
++	result = mtd_device_register(host->mtd, parts, nr_parts);
++	if (result) {
++		kfree(parts);
++		parts = NULL;
++	}
++	return (1 == result) ? -ENODEV : 0;
++#else
++	result = hinfc_os_add_paratitions(host);
++	if (host->add_partition)
++		return result;
++
++	if (!add_mtd_device(host->mtd))
++		return 0;
++#endif
++	result = -ENODEV;
++fail:
++	if (host->buffer) {
++		dma_free_coherent(host->dev,
++			(NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE),
++			host->buffer,
++			host->dma_buffer);
++		host->buffer = NULL;
++	}
++	nand_release(host->mtd);
++	kfree(host);
++	platform_set_drvdata(pltdev, NULL);
++
++	return result;
++}
++/*****************************************************************************/
++
++static int hinfc610_os_remove(struct platform_device *pltdev)
++{
++	struct hinfc_host *host = platform_get_drvdata(pltdev);
++
++	clk_disable_unprepare(host->clk);
++
++	nand_release(host->mtd);
++
++	dma_free_coherent(host->dev,
++		(NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE),
++		host->buffer,
++		host->dma_buffer);
++	kfree(host);
++	platform_set_drvdata(pltdev, NULL);
++
++	return 0;
++}
++/*****************************************************************************/
++#ifdef CONFIG_PM
++static int hinfc610_os_suspend(struct platform_device *pltdev,
++			       pm_message_t state)
++{
++	struct hinfc_host *host = platform_get_drvdata(pltdev);
++
++	while ((hinfc_read(host, HINFC610_STATUS) & 0x1) == 0x0)
++		;
++
++	while ((hinfc_read(host, HINFC610_DMA_CTRL))
++		& HINFC610_DMA_CTRL_DMA_START)
++		_cond_resched();
++
++	clk_disable_unprepare(host->clk);
++
++	return 0;
++}
++/*****************************************************************************/
++
++static int hinfc610_os_resume(struct platform_device *pltdev)
++{
++	int cs;
++	struct hinfc_host *host = platform_get_drvdata(pltdev);
++	struct nand_chip *chip = host->chip;
++
++	clk_prepare_enable(host->clk);
++	for (cs = 0; cs < chip->numchips; cs++)
++		host->send_cmd_reset(host, cs);
++	hinfc_write(host,
++		SET_HINFC610_PWIDTH(CONFIG_HINFC610_W_LATCH,
++			CONFIG_HINFC610_R_LATCH, CONFIG_HINFC610_RW_LATCH),
++		HINFC610_PWIDTH);
++
++	return 0;
++}
++#endif /* CONFIG_PM */
++/*****************************************************************************/
++static const struct of_device_id hisi_nand_dt_ids[] = {
++	{ .compatible = "hisilicon,hinfc610-nand" },
++	{ /* sentinel */ }
++};
++MODULE_DEVICE_TABLE(of, hisi_nand_dt_ids);
++
++static struct platform_driver hisi_nand_driver = {
++	.driver = {
++		.name	= "hisi-nand",
++		.of_match_table = hisi_nand_dt_ids,
++	},
++	.probe	= hinfc610_os_probe,
++	.remove = hinfc610_os_remove,
++#ifdef CONFIG_PM
++	.suspend	= hinfc610_os_suspend,
++	.resume		= hinfc610_os_resume,
++#endif
++};
++module_platform_driver(hisi_nand_driver);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("BVT_BSP");
++MODULE_DESCRIPTION("Hisilicon Flash Memory Controller NFC610 Nand Driver");
+diff --git a/drivers/mtd/nand/hinfc610/hinfc610_os.h b/drivers/mtd/nand/hinfc610/hinfc610_os.h
+new file mode 100644
+index 0000000..1dafd9e
+--- /dev/null
++++ b/drivers/mtd/nand/hinfc610/hinfc610_os.h
+@@ -0,0 +1,78 @@
++/*
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++
++#ifndef HINFC610_OSH
++#define HINFC610_OSH
++/******************************************************************************/
++
++#include <linux/version.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/module.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/nand.h>
++#include <linux/delay.h>
++#include <linux/dma-mapping.h>
++#include <linux/io.h>
++#include <asm/setup.h>
++#include <linux/errno.h>
++#include <linux/platform_device.h>
++#include <linux/mtd/partitions.h>
++#include <linux/clk.h>
++#include <linux/clkdev.h>
++
++#include "../../mtdcore.h"
++
++/*****************************************************************************/
++
++#define DUMP_DATA(_p, _n) do { \
++	int ix; \
++	unsigned char *rr = (unsigned char *)(_p); \
++	for (ix = 0; ix < _n; ix++) { \
++		pr_info("%02X ", rr[ix]); \
++		if (!((ix + 1) % 16)) \
++			pr_info("\n"); \
++	} \
++} while (0)
++
++#define DBG_OUT(fmt, args...)\
++	pr_warn("%s(%d): " fmt, __FILE__, __LINE__, ##args) \
++
++#if 1
++#  define DBG_MSG(_fmt, arg...)
++#else
++#  define DBG_MSG(_fmt, arg...) \
++	pr_info("%s(%d): " _fmt, __FILE__, __LINE__, ##arg)
++#endif
++
++#define PR_BUG(fmt, args...) do {\
++	pr_debug("%s(%d): bug " fmt, __FILE__, __LINE__, ##args); \
++	asm("b ."); \
++} while (0)
++
++#define PR_ERR(fmt, args...)\
++	pr_err("%s(%d): " fmt, __FILE__, __LINE__, ##args) \
++
++#define PR_MSG(_fmt, arg...) \
++	printk(_fmt, ##arg)
++
++/******************************************************************************/
++#endif /* HINFC610_OSH */
+diff --git a/drivers/mtd/nand/hinfc610/hinfc610_read_retry.c b/drivers/mtd/nand/hinfc610/hinfc610_read_retry.c
+new file mode 100644
+index 0000000..3f1a9f2
+--- /dev/null
++++ b/drivers/mtd/nand/hinfc610/hinfc610_read_retry.c
+@@ -0,0 +1,43 @@
++/*
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include "hinfc610_gen.h"
++#include "hinfc610.h"
++#include "hinfc610_read_retry.h"
++
++static struct read_retry_t *read_retry_table[] = {
++	&hinfc610_hynix_bg_bdie_read_retry,
++	&hinfc610_hynix_bg_cdie_read_retry,
++	&hinfc610_hynix_cg_adie_read_retry,
++	&hinfc610_micron_read_retry,
++	&hinfc610_toshiba_24nm_read_retry,
++	&hinfc610_samsung_read_retry,
++	NULL,
++};
++
++struct read_retry_t *hinfc610_find_read_retry(int type)
++{
++	struct read_retry_t **rr;
++
++	for (rr = read_retry_table; rr; rr++) {
++		if ((*rr)->type == type)
++			return *rr;
++	}
++
++	return NULL;
++}
+diff --git a/drivers/mtd/nand/hinfc610/hinfc610_read_retry.h b/drivers/mtd/nand/hinfc610/hinfc610_read_retry.h
+new file mode 100644
+index 0000000..cfd8880
+--- /dev/null
++++ b/drivers/mtd/nand/hinfc610/hinfc610_read_retry.h
+@@ -0,0 +1,25 @@
++/*
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#ifndef HINFC610_READ_RETRY_H
++#define HINFC610_READ_RETRY_H
++
++struct read_retry_t *hinfc610_find_read_retry(int type);
++
++#endif /* HINFC610_READ_RETRY_H */
++
+diff --git a/drivers/mtd/nand/hinfc610/hinfc610_read_retry_hynix_bg_bdie.c b/drivers/mtd/nand/hinfc610/hinfc610_read_retry_hynix_bg_bdie.c
+new file mode 100644
+index 0000000..b6fb1a8
+--- /dev/null
++++ b/drivers/mtd/nand/hinfc610/hinfc610_read_retry_hynix_bg_bdie.c
+@@ -0,0 +1,136 @@
++/*
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include "hinfc610_os.h"
++#include "hinfc610.h"
++
++/*****************************************************************************/
++
++static int hynix_bg_bdie_rr_org_exist;
++static char hynix_bg_bdie_rr_org[4] = {0};
++
++/*****************************************************************************/
++
++static int hinfc610_hynix_bg_bdie_set_rr_reg(struct hinfc_host *host, int index)
++{
++	int ix;
++	char HYNIX_BG_BDIE_RR_REG[4] = {0xA7,  0xAD,  0xAE,  0xAF};
++	char value_offset[7][4] = {
++		{0x00,  0x00,  0x00,  0x00},
++		{0x00,  0x06,  0x0A,  0x06},
++		{0x7F, -0x03, -0x07, -0x08},
++		{0x7F, -0x06, -0x0D, -0x0F},
++		{0x7F, -0x09, -0x14, -0x17},
++		{0x7F,  0x7F, -0x1A, -0x1E},
++		{0x7F,  0x7F, -0x20, -0x25}
++	};
++	char *value = &value_offset[index][0];
++
++	host->enable_ecc_randomizer(host, DISABLE, DISABLE);
++	hinfc_write(host, 1, HINFC610_DATA_NUM);
++
++	if (!hynix_bg_bdie_rr_org_exist) {
++
++		for (ix = 0; ix < 4; ix++) {
++
++			memset(host->chip->IO_ADDR_R, 0xff, 32);
++
++			hinfc_write(host, 0x37, HINFC610_CMD);
++			hinfc_write(host, HYNIX_BG_BDIE_RR_REG[ix],
++				HINFC610_ADDRL);
++			/*
++			 * according to hynix doc, no need to config
++			 * HINFC610_OP_WAIT_READY_EN,
++			 * here not config this bit.
++			 */
++			hinfc_write(host, HINFC610_READ_1CMD_1ADD_DATA,
++				HINFC610_OP);
++			WAIT_CONTROLLER_FINISH();
++
++			hynix_bg_bdie_rr_org[ix]
++				= (char)(readl(host->chip->IO_ADDR_R) & 0xff);
++		}
++		hynix_bg_bdie_rr_org_exist = 1;
++	}
++
++	for (ix = 0; ix < 4; ix++) {
++		if (value[ix] == 0x7F)
++			value[ix] = 0x00;
++		else
++			value[ix] += hynix_bg_bdie_rr_org[ix];
++	}
++
++	writel(value[0], host->chip->IO_ADDR_W);
++	hinfc_write(host, HYNIX_BG_BDIE_RR_REG[0], HINFC610_ADDRL);
++	hinfc_write(host, 0x36, HINFC610_CMD);
++	/*
++	 * according to hynix doc, no need to config HINFC610_OP_WAIT_READY_EN,
++	 * here not config this bit.
++	 */
++	hinfc_write(host, HINFC610_WRITE_1CMD_1ADD_DATA, HINFC610_OP);
++	WAIT_CONTROLLER_FINISH();
++
++	for (ix = 1; ix < 4; ix++) {
++		writel(value[ix], host->chip->IO_ADDR_W);
++		hinfc_write(host, HYNIX_BG_BDIE_RR_REG[ix], HINFC610_ADDRL);
++		/*
++		 * according to hynix doc, no need to config
++		 * HINFC610_OP_WAIT_READY_EN,
++		 * here not config this bit.
++		 */
++		hinfc_write(host, HINFC610_WRITE_0CMD_1ADD_DATA, HINFC610_OP);
++		WAIT_CONTROLLER_FINISH();
++	}
++
++	hinfc_write(host, 0x16, HINFC610_CMD);
++	/*
++	 * according to hynix doc, only 1 cmd: 0x16.
++	 * And no need to config HINFC610_OP_WAIT_READY_EN,
++	 * here not config this bit.
++	 */
++	hinfc_write(host, HINFC610_WRITE_1CMD_0ADD_NODATA, HINFC610_OP);
++	WAIT_CONTROLLER_FINISH();
++
++	host->enable_ecc_randomizer(host, ENABLE, ENABLE);
++
++	return 0;
++}
++/*****************************************************************************/
++
++static int hinfc610_hynix_bg_bdie_set_rr_param(struct hinfc_host *host,
++		int param)
++{
++	if (!param)
++		return 0;
++	return hinfc610_hynix_bg_bdie_set_rr_reg(host, param);
++}
++/*****************************************************************************/
++
++static int hinfc610_hynix_bg_bdie_reset_rr_param(struct hinfc_host *host)
++{
++	return hinfc610_hynix_bg_bdie_set_rr_param(host, 0);
++}
++/*****************************************************************************/
++
++struct read_retry_t hinfc610_hynix_bg_bdie_read_retry = {
++	.type = NAND_RR_HYNIX_BG_BDIE,
++	.count = 7,
++	.set_rr_param = hinfc610_hynix_bg_bdie_set_rr_param,
++	.get_rr_param = NULL,
++	.reset_rr_param = hinfc610_hynix_bg_bdie_reset_rr_param,
++};
+diff --git a/drivers/mtd/nand/hinfc610/hinfc610_read_retry_hynix_bg_cdie.c b/drivers/mtd/nand/hinfc610/hinfc610_read_retry_hynix_bg_cdie.c
+new file mode 100644
+index 0000000..fc39d70
+--- /dev/null
++++ b/drivers/mtd/nand/hinfc610/hinfc610_read_retry_hynix_bg_cdie.c
+@@ -0,0 +1,225 @@
++/*
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include "hinfc610_os.h"
++#include "hinfc610.h"
++
++/*****************************************************************************/
++
++static char *hinfc610_hynix_bg_cdie_otp_check(char *otp)
++{
++	int index = 0;
++	int ix, jx;
++	char *ptr = NULL;
++	int min, cur;
++	char *otp_origin, *otp_inverse;
++
++	min = 64;
++	for (ix = 0; ix < 8; ix++, otp += 128) {
++
++		otp_origin  = otp;
++		otp_inverse = otp + 64;
++		cur = 0;
++
++		for (jx = 0; jx < 64; jx++, otp_origin++, otp_inverse++) {
++			if (((*otp_origin) ^ (*otp_inverse)) == 0xFF)
++				continue;
++			cur++;
++		}
++
++		if (cur < min) {
++			min = cur;
++			index = ix;
++			ptr = otp;
++			if (!cur)
++				break;
++		}
++	}
++
++	pr_info("RR select parameter %d from %d, error %d\n",
++		index, ix, min);
++	return ptr;
++}
++/*****************************************************************************/
++
++static int hinfc610_hynix_bg_cdie_get_rr_param(struct hinfc_host *host)
++{
++	char *otp;
++
++	host->enable_ecc_randomizer(host, DISABLE, DISABLE);
++	/* step1: reset the chip */
++	host->send_cmd_reset(host, host->chipselect);
++
++	/* step2: cmd: 0x36, address: 0xAE, data: 0x00 */
++	hinfc_write(host, 1, HINFC610_DATA_NUM);/* data length 1 */
++	writel(0x00, host->chip->IO_ADDR_R); /* data: 0x00 */
++	hinfc_write(host, 0xAE, HINFC610_ADDRL);/* address: 0xAE */
++	hinfc_write(host, 0x36, HINFC610_CMD);  /* cmd: 0x36 */
++	/* according to hynix doc, no need to config
++	 * HINFC610_OP_WAIT_READY_EN */
++	hinfc_write(host, HINFC610_WRITE_1CMD_1ADD_DATA, HINFC610_OP);
++	WAIT_CONTROLLER_FINISH();
++
++	/* step3: address: 0xB0, data: 0x4D */
++	hinfc_write(host, 1, HINFC610_DATA_NUM);/* data length 1 */
++	writel(0x4D, host->chip->IO_ADDR_R); /* data: 0x4d */
++	hinfc_write(host, 0xB0, HINFC610_ADDRL);/* address: 0xB0 */
++	/* only address and data, without cmd */
++	/* according to hynix doc, no need to config
++	 * HINFC610_OP_WAIT_READY_EN */
++	hinfc_write(host, HINFC610_WRITE_0CMD_1ADD_DATA, HINFC610_OP);
++	WAIT_CONTROLLER_FINISH();
++
++	/* step4: cmd: 0x16, 0x17, 0x04, 0x19 */
++	hinfc_write(host, 0x17 << 8 | 0x16, HINFC610_CMD);
++	/* according to hynix doc, no need to config
++	 * HINFC610_OP_WAIT_READY_EN */
++	hinfc_write(host, HINFC610_WRITE_2CMD_0ADD_NODATA, HINFC610_OP);
++	WAIT_CONTROLLER_FINISH();
++
++	hinfc_write(host, 0x19 << 8 | 0x04, HINFC610_CMD);
++	/* according to hynix doc, no need to config
++	 * HINFC610_OP_WAIT_READY_EN */
++	hinfc_write(host, HINFC610_WRITE_2CMD_0ADD_NODATA, HINFC610_OP);
++	WAIT_CONTROLLER_FINISH();
++
++	/* step5: cmd: 0x00 0x30, address: 0x02 00 00 00 */
++	hinfc_write(host, 0x2000000, HINFC610_ADDRL);
++	hinfc_write(host, 0x00, HINFC610_ADDRH);
++	hinfc_write(host, 0x30 << 8 | 0x00, HINFC610_CMD);
++	hinfc_write(host, 0x800, HINFC610_DATA_NUM);
++	/* according to hynix doc, need to config
++	 * HINFC610_OP_WAIT_READY_EN */
++	hinfc_write(host, HINFC610_READ_2CMD_5ADD, HINFC610_OP);
++	WAIT_CONTROLLER_FINISH();
++
++	/*step6 save otp read retry table to mem*/
++	otp = hinfc610_hynix_bg_cdie_otp_check(host->chip->IO_ADDR_R + 2);
++	if (!otp) {
++		pr_err("Read Retry select parameter failed, this Nand Chip maybe invalidation.\n");
++		return -1;
++	}
++	memcpy(host->rr_data, otp, 64);
++	host->need_rr_data = 1;
++
++	/* step7: reset the chip */
++	host->send_cmd_reset(host, host->chipselect);
++
++	/* step8: cmd: 0x38 */
++	hinfc_write(host, 0x38, HINFC610_CMD);
++	/* according to hynix doc, need to config HINFC610_OP_WAIT_READY_EN */
++	hinfc_write(host, HINFC610_WRITE_1CMD_0ADD_NODATA_WAIT_READY,
++			HINFC610_OP);
++	WAIT_CONTROLLER_FINISH();
++
++	host->enable_ecc_randomizer(host, ENABLE, ENABLE);
++	/* get hynix otp table finish */
++	return 0;
++}
++/*****************************************************************************/
++static char hinfc610_hynix_bg_cdie_rr_reg[8] = {
++	0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7};
++
++static int hinfc610_hynix_bg_cdie_set_rr_reg(struct hinfc_host *host,
++					     char *val)
++{
++	int i;
++
++	host->enable_ecc_randomizer(host, DISABLE, DISABLE);
++	hinfc_write(host, 1, HINFC610_DATA_NUM);/* data length 1 */
++
++	for (i = 0; i <= 8; i++) {
++		switch (i) {
++		case 0:
++			writel(val[i], host->chip->IO_ADDR_R);
++			hinfc_write(host,
++				hinfc610_hynix_bg_cdie_rr_reg[i],
++				HINFC610_ADDRL);
++			hinfc_write(host,
++				0x36, HINFC610_CMD);
++			/*
++			 * no need to config HINFC610_OP_WAIT_READY_EN,
++			 * here not config this bit.
++			 */
++			hinfc_write(host,
++				HINFC610_WRITE_1CMD_1ADD_DATA,
++				HINFC610_OP);
++			break;
++		case 8:
++			hinfc_write(host,
++				0x16, HINFC610_CMD);
++			/*
++			 * according to hynix doc, only 1 cmd: 0x16.
++			 * And no need to config HINFC610_OP_WAIT_READY_EN,
++			 * here not config this bit.
++			 */
++			hinfc_write(host,
++				HINFC610_WRITE_1CMD_0ADD_NODATA,
++				HINFC610_OP);
++			break;
++		default:
++			writel(val[i], host->chip->IO_ADDR_R);
++			hinfc_write(host,
++				hinfc610_hynix_bg_cdie_rr_reg[i],
++				HINFC610_ADDRL);
++			/*
++			 * no need to config HINFC610_OP_WAIT_READY_EN,
++			 * here not config this bit.
++			 */
++			hinfc_write(host,
++				HINFC610_WRITE_0CMD_1ADD_DATA,
++				HINFC610_OP);
++			break;
++		}
++		WAIT_CONTROLLER_FINISH();
++	}
++	host->enable_ecc_randomizer(host, ENABLE, ENABLE);
++	return 0;
++}
++
++/*****************************************************************************/
++
++static int hinfc610_hynix_bg_cdie_set_rr_param(struct hinfc_host *host,
++					       int param)
++{
++	unsigned char *rr;
++
++	if (!(host->rr_data[0] | host->rr_data[1]
++	    | host->rr_data[2] | host->rr_data[3]) || !param)
++		return -1;
++
++	rr = (unsigned char *)&host->rr_data[((param & 0x07) << 3)];
++
++	/* set the read retry regs to adjust reading level */
++	return hinfc610_hynix_bg_cdie_set_rr_reg(host, (char *)rr);
++}
++/*****************************************************************************/
++
++static int hinfc610_hynix_bg_cdie_reset_rr_param(struct hinfc_host *host)
++{
++	return hinfc610_hynix_bg_cdie_set_rr_param(host, 0);
++}
++/*****************************************************************************/
++
++struct read_retry_t hinfc610_hynix_bg_cdie_read_retry = {
++	.type = NAND_RR_HYNIX_BG_CDIE,
++	.count = 8,
++	.set_rr_param = hinfc610_hynix_bg_cdie_set_rr_param,
++	.get_rr_param = hinfc610_hynix_bg_cdie_get_rr_param,
++	.reset_rr_param = hinfc610_hynix_bg_cdie_reset_rr_param,
++};
+diff --git a/drivers/mtd/nand/hinfc610/hinfc610_read_retry_hynix_cg_adie.c b/drivers/mtd/nand/hinfc610/hinfc610_read_retry_hynix_cg_adie.c
+new file mode 100644
+index 0000000..b7444b8
+--- /dev/null
++++ b/drivers/mtd/nand/hinfc610/hinfc610_read_retry_hynix_cg_adie.c
+@@ -0,0 +1,234 @@
++/*
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include "hinfc610_os.h"
++#include "hinfc610.h"
++
++/*****************************************************************************/
++static char *hinfc610_hynix_cg_adie_otp_check(char *otp)
++{
++	int index = 0;
++	int ix, jx;
++	char *ptr = NULL;
++	int min, cur;
++	char *otp_origin, *otp_inverse;
++
++	min = 64;
++	for (ix = 0; ix < 8; ix++, otp += 128) {
++
++		otp_origin  = otp;
++		otp_inverse = otp + 64;
++		cur = 0;
++
++		for (jx = 0; jx < 64; jx++, otp_origin++, otp_inverse++) {
++			if (((*otp_origin) ^ (*otp_inverse)) == 0xFF)
++				continue;
++			cur++;
++		}
++
++		if (cur < min) {
++			min = cur;
++			index = ix;
++			ptr = otp;
++			if (!cur)
++				break;
++		}
++	}
++
++	pr_info("RR select parameter %d from %d, error %d\n",
++		index, ix, min);
++	return ptr;
++}
++/*****************************************************************************/
++
++static int hinfc610_hynix_cg_adie_get_rr_param(struct hinfc_host *host)
++{
++	char *otp;
++
++	host->enable_ecc_randomizer(host, DISABLE, DISABLE);
++	/* step1: reset the chip */
++	host->send_cmd_reset(host, host->chipselect);
++
++	/* step2: cmd: 0x36, address: 0xFF, data: 0x40 */
++	hinfc_write(host, 1, HINFC610_DATA_NUM);/* data length 1 */
++	writel(0x40, host->chip->IO_ADDR_R); /* data: 0x00 */
++	hinfc_write(host, 0xFF, HINFC610_ADDRL);/* address: 0xAE */
++	hinfc_write(host, 0x36, HINFC610_CMD);  /* cmd: 0x36 */
++	/*
++	 * no need to config HINFC610_OP_WAIT_READY_EN,
++	 * here not config this bit.
++	 */
++	hinfc_write(host, HINFC610_WRITE_1CMD_1ADD_DATA, HINFC610_OP);
++	WAIT_CONTROLLER_FINISH();
++
++	/* step3: address: 0xCC, data: 0x4D */
++	hinfc_write(host, 1, HINFC610_DATA_NUM);/* data length 1 */
++	writel(0x4D, host->chip->IO_ADDR_R); /* data: 0x4d */
++	hinfc_write(host, 0xCC, HINFC610_ADDRL);/* address: 0xB0 */
++	/*
++	 * no need to config HINFC610_OP_WAIT_READY_EN,
++	 * here not config this bit.
++	 * only address and data, without cmd
++	 */
++	hinfc_write(host, HINFC610_WRITE_0CMD_1ADD_DATA, HINFC610_OP);
++	WAIT_CONTROLLER_FINISH();
++
++	/* step4: cmd: 0x16, 0x17, 0x04, 0x19 */
++	hinfc_write(host, 0x17 << 8 | 0x16, HINFC610_CMD);
++	/*
++	 * no need to config HINFC610_OP_WAIT_READY_EN,
++	 * here not config this bit.
++	 */
++	hinfc_write(host, HINFC610_WRITE_2CMD_0ADD_NODATA, HINFC610_OP);
++	WAIT_CONTROLLER_FINISH();
++
++	hinfc_write(host, 0x19 << 8 | 0x04, HINFC610_CMD);
++	/*
++	 * no need to config HINFC610_OP_WAIT_READY_EN,
++	 * here not config this bit.
++	 */
++	hinfc_write(host, HINFC610_WRITE_2CMD_0ADD_NODATA, HINFC610_OP);
++	WAIT_CONTROLLER_FINISH();
++
++	/* step5: cmd: 0x00 0x30, address: 0x02 00 00 00 */
++	hinfc_write(host, 0x2000000, HINFC610_ADDRL);
++	hinfc_write(host, 0x00, HINFC610_ADDRH);
++	hinfc_write(host, 0x30 << 8 | 0x00, HINFC610_CMD);
++	hinfc_write(host, 0x800, HINFC610_DATA_NUM);
++	/*
++	 * need to config HINFC610_OP_WAIT_READY_EN, here config this bit.
++	 */
++	hinfc_write(host, HINFC610_READ_2CMD_5ADD, HINFC610_OP);
++	WAIT_CONTROLLER_FINISH();
++
++	/*step6 save otp read retry table to mem*/
++	otp = hinfc610_hynix_cg_adie_otp_check(host->chip->IO_ADDR_R + 2);
++	if (!otp) {
++		pr_err("Read Retry select parameter failed, this Nand Chip maybe invalidation.\n");
++		return -1;
++	}
++	memcpy(host->rr_data, otp, 64);
++	host->need_rr_data = 1;
++
++	/* step7: reset the chip */
++	host->send_cmd_reset(host, host->chipselect);
++
++	/* step8: cmd: 0x38 */
++	hinfc_write(host, 0x38, HINFC610_CMD);
++	/*
++	 * need to config HINFC610_OP_WAIT_READY_EN, here config this bit.
++	 */
++	hinfc_write(host, HINFC610_WRITE_1CMD_0ADD_NODATA_WAIT_READY,
++			HINFC610_OP);
++	WAIT_CONTROLLER_FINISH();
++
++	host->enable_ecc_randomizer(host, ENABLE, ENABLE);
++	/* get hynix otp table finish */
++	return 0;
++}
++/*****************************************************************************/
++static char hinfc610_hynix_cg_adie__rr_reg[8] = {
++	0xCC, 0xBF, 0xAA, 0xAB, 0xCD, 0xAD, 0xAE, 0xAF};
++
++static int hinfc610_hynix_cg_adie_set_rr_reg(struct hinfc_host *host, char *val)
++{
++	int i;
++
++	host->enable_ecc_randomizer(host, DISABLE, DISABLE);
++	hinfc_write(host, 1, HINFC610_DATA_NUM);/* data length 1 */
++
++	for (i = 0; i <= 8; i++) {
++		switch (i) {
++		case 0:
++			writel(val[i], host->chip->IO_ADDR_R);
++			hinfc_write(host,
++				hinfc610_hynix_cg_adie__rr_reg[i],
++				HINFC610_ADDRL);
++			hinfc_write(host,
++				0x36, HINFC610_CMD);
++			/*
++			 * no need to config HINFC610_OP_WAIT_READY_EN,
++			 * here not config this bit.
++			 */
++			hinfc_write(host,
++				HINFC610_WRITE_1CMD_1ADD_DATA,
++				HINFC610_OP);
++			break;
++		case 8:
++			hinfc_write(host,
++				0x16, HINFC610_CMD);
++			/*
++			 * only have 1 cmd: 0x16
++			 * no need to config HINFC610_OP_WAIT_READY_EN,
++			 * here not config this bit.
++			 */
++			hinfc_write(host,
++				HINFC610_WRITE_1CMD_0ADD_NODATA,
++				HINFC610_OP);
++			break;
++		default:
++			writel(val[i], host->chip->IO_ADDR_R);
++			hinfc_write(host,
++				hinfc610_hynix_cg_adie__rr_reg[i],
++				HINFC610_ADDRL);
++			/*
++			 * no need to config HINFC610_OP_WAIT_READY_EN,
++			 * here not config this bit.
++			 */
++			hinfc_write(host,
++				HINFC610_WRITE_0CMD_1ADD_DATA,
++				HINFC610_OP);
++			break;
++		}
++		WAIT_CONTROLLER_FINISH();
++	}
++	host->enable_ecc_randomizer(host, ENABLE, ENABLE);
++	return 0;
++}
++
++/*****************************************************************************/
++
++static int hinfc610_hynix_cg_adie_set_rr_param(struct hinfc_host *host,
++		int param)
++{
++	unsigned char *rr;
++
++	if (!(host->rr_data[0] | host->rr_data[1]
++	    | host->rr_data[2] | host->rr_data[3]) || !param)
++		return -1;
++
++	rr = (unsigned char *)&host->rr_data[((param & 0x07) << 3)];
++
++	/* set the read retry regs to adjust reading level */
++	return hinfc610_hynix_cg_adie_set_rr_reg(host, (char *)rr);
++}
++/*****************************************************************************/
++
++static int hinfc610_hynix_cg_adie_reset_rr_param(struct hinfc_host *host)
++{
++	return hinfc610_hynix_cg_adie_set_rr_param(host, 0);
++}
++/*****************************************************************************/
++
++struct read_retry_t hinfc610_hynix_cg_adie_read_retry = {
++	.type = NAND_RR_HYNIX_CG_ADIE,
++	.count = 8,
++	.set_rr_param = hinfc610_hynix_cg_adie_set_rr_param,
++	.get_rr_param = hinfc610_hynix_cg_adie_get_rr_param,
++	.reset_rr_param = hinfc610_hynix_cg_adie_reset_rr_param,
++};
+diff --git a/drivers/mtd/nand/hinfc610/hinfc610_read_retry_micron.c b/drivers/mtd/nand/hinfc610/hinfc610_read_retry_micron.c
+new file mode 100644
+index 0000000..c4c0716
+--- /dev/null
++++ b/drivers/mtd/nand/hinfc610/hinfc610_read_retry_micron.c
+@@ -0,0 +1,74 @@
++/*
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include "hinfc610_os.h"
++#include "hinfc610.h"
++
++/*****************************************************************************/
++
++#define MICRON_RR_ADDR         0x89
++
++static int hinfc610_micron_set_rr_reg(struct hinfc_host *host, int rr)
++{
++	int regval;
++
++	host->enable_ecc_randomizer(host, DISABLE, DISABLE);
++
++	hinfc_write(host, 1, HINFC610_DATA_NUM);
++
++	writel(rr, host->chip->IO_ADDR_W);
++	hinfc_write(host, MICRON_RR_ADDR, HINFC610_ADDRL);
++	/* set read retry */
++	hinfc_write(host, 0xEF, HINFC610_CMD);
++
++	/* need to config WAIT_READY_EN, here config WAIT_READY_EN bit. */
++	regval = (HINFC610_IS_SYNC(host) ?
++		HINFC610_WRITE_1CMD_1ADD_DATA_SYNC_WAIT_READY :
++		HINFC610_WRITE_1CMD_1ADD_DATA_WAIT_READY);
++
++	hinfc_write(host, regval, HINFC610_OP);
++
++	WAIT_CONTROLLER_FINISH();
++
++	host->enable_ecc_randomizer(host, ENABLE, ENABLE);
++
++	return 0;
++}
++/*****************************************************************************/
++#undef MICRON_RR_ADDR
++/*****************************************************************************/
++
++static int hinfc610_micron_set_rr_param(struct hinfc_host *host, int rr_option)
++{
++	return hinfc610_micron_set_rr_reg(host, rr_option);
++}
++/*****************************************************************************/
++
++static int hinfc610_micron_reset_rr_param(struct hinfc_host *host)
++{
++	return hinfc610_micron_set_rr_reg(host, 0);
++}
++/*****************************************************************************/
++
++struct read_retry_t hinfc610_micron_read_retry = {
++	.type = NAND_RR_MICRON,
++	.count = 8,
++	.set_rr_param = hinfc610_micron_set_rr_param,
++	.get_rr_param = NULL,
++	.reset_rr_param = hinfc610_micron_reset_rr_param,
++};
+diff --git a/drivers/mtd/nand/hinfc610/hinfc610_read_retry_samsung.c b/drivers/mtd/nand/hinfc610/hinfc610_read_retry_samsung.c
+new file mode 100644
+index 0000000..6d9adcb
+--- /dev/null
++++ b/drivers/mtd/nand/hinfc610/hinfc610_read_retry_samsung.c
+@@ -0,0 +1,109 @@
++/*
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include "hinfc610_os.h"
++#include "hinfc610.h"
++
++/*****************************************************************************/
++
++static int hinfc610_samsung_set_rr_reg(struct hinfc_host *host, int param)
++{
++#define SAMSUNG_RR_CMD     0xA1
++	int opval;
++
++	unsigned char samsung_rr_params[15][4] = {
++		{0x00, 0x00, 0x00, 0x00},
++		{0x05, 0x0A, 0x00, 0x00},
++		{0x28, 0x00, 0xEC, 0xD8},
++		{0xED, 0xF5, 0xED, 0xE6},
++		{0x0A, 0x0F, 0x05, 0x00},
++		{0x0F, 0x0A, 0xFB, 0xEC},
++		{0xE8, 0xEF, 0xE8, 0xDC},
++		{0xF1, 0xFB, 0xFE, 0xF0},
++		{0x0A, 0x00, 0xFB, 0xEC},
++		{0xD0, 0xE2, 0xD0, 0xC2},
++		{0x14, 0x0F, 0xFB, 0xEC},
++		{0xE8, 0xFB, 0xE8, 0xDC},
++		{0x1E, 0x14, 0xFB, 0xEC},
++		{0xFB, 0xFF, 0xFB, 0xF8},
++		{0x07, 0x0C, 0x02, 0x00}
++	};
++
++	if (param >= 15)
++		param = (param % 15);
++
++	host->enable_ecc_randomizer(host, DISABLE, DISABLE);
++
++	/* no need to config WAIT_READY_EN, here not config WAIT_READY_EN bit */
++	opval = (HINFC610_IS_SYNC(host) ? HINFC610_WRITE_1CMD_2ADD_DATA_SYNC
++		: HINFC610_WRITE_1CMD_2ADD_DATA);
++
++	hinfc_write(host, 1, HINFC610_DATA_NUM);
++
++	writel(samsung_rr_params[param][0], host->chip->IO_ADDR_R);
++	hinfc_write(host, 0xA700, HINFC610_ADDRL);
++	hinfc_write(host, SAMSUNG_RR_CMD, HINFC610_CMD);
++	hinfc_write(host, opval, HINFC610_OP);
++	WAIT_CONTROLLER_FINISH();
++
++	writel(samsung_rr_params[param][1], host->chip->IO_ADDR_R);
++	hinfc_write(host, 0xA400, HINFC610_ADDRL);
++	hinfc_write(host, SAMSUNG_RR_CMD, HINFC610_CMD);
++	hinfc_write(host, opval, HINFC610_OP);
++	WAIT_CONTROLLER_FINISH();
++
++	writel(samsung_rr_params[param][2], host->chip->IO_ADDR_R);
++	hinfc_write(host, 0xA500, HINFC610_ADDRL);
++	hinfc_write(host, SAMSUNG_RR_CMD, HINFC610_CMD);
++	hinfc_write(host, opval, HINFC610_OP);
++	WAIT_CONTROLLER_FINISH();
++
++	writel(samsung_rr_params[param][3], host->chip->IO_ADDR_R);
++	hinfc_write(host, 0xA600, HINFC610_ADDRL);
++	hinfc_write(host, SAMSUNG_RR_CMD, HINFC610_CMD);
++	hinfc_write(host, opval, HINFC610_OP);
++	WAIT_CONTROLLER_FINISH();
++
++	host->enable_ecc_randomizer(host, ENABLE, ENABLE);
++
++	return 0;
++
++#undef SAMSUNG_RR_CMD
++}
++/*****************************************************************************/
++
++static int hinfc610_samsung_set_rr_param(struct hinfc_host *host, int param)
++{
++	return hinfc610_samsung_set_rr_reg(host, param);
++}
++/*****************************************************************************/
++
++static int hinfc610_samsung_reset_rr_param(struct hinfc_host *host)
++{
++	return hinfc610_samsung_set_rr_reg(host, 0);
++}
++/*****************************************************************************/
++
++struct read_retry_t hinfc610_samsung_read_retry = {
++	.type = NAND_RR_SAMSUNG,
++	.count = 15,
++	.set_rr_param = hinfc610_samsung_set_rr_param,
++	.get_rr_param = NULL,
++	.reset_rr_param = hinfc610_samsung_reset_rr_param,
++};
++
+diff --git a/drivers/mtd/nand/hinfc610/hinfc610_read_retry_toshiba.c b/drivers/mtd/nand/hinfc610/hinfc610_read_retry_toshiba.c
+new file mode 100644
+index 0000000..0a1a87e
+--- /dev/null
++++ b/drivers/mtd/nand/hinfc610/hinfc610_read_retry_toshiba.c
+@@ -0,0 +1,113 @@
++/*
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include "hinfc610_os.h"
++#include "hinfc610.h"
++
++/*****************************************************************************/
++
++static int hinfc610_toshiba_24nm_set_rr_reg(struct hinfc_host *host, int param)
++{
++#define TOSHIBA_RR_CMD     0x55
++	int opval;
++	static char toshiba_rr_param[] = {0x00, 0x04, 0x7c, 0x78, 0x74, 0x08};
++
++	if (!param) {
++		host->send_cmd_reset(host, host->chipselect);
++		return 0;
++	}
++
++	if (param >= 6)
++		param = (param % 6);
++
++	/*
++	 * no need to config WAIT_READY_EN, here not config WAIT_READY_EN
++	 */
++	opval = (HINFC610_IS_SYNC(host) ? HINFC610_WRITE_1CMD_1ADD_DATA_SYNC
++		: HINFC610_WRITE_1CMD_1ADD_DATA);
++
++	hinfc_write(host, 1, HINFC610_DATA_NUM);
++
++	writel(toshiba_rr_param[param], host->chip->IO_ADDR_R);
++	hinfc_write(host, 0x4, HINFC610_ADDRL);
++	hinfc_write(host, TOSHIBA_RR_CMD, HINFC610_CMD);
++	hinfc_write(host, opval, HINFC610_OP);
++	WAIT_CONTROLLER_FINISH();
++
++	writel(toshiba_rr_param[param], host->chip->IO_ADDR_R);
++	hinfc_write(host, 0x5, HINFC610_ADDRL);
++	hinfc_write(host, TOSHIBA_RR_CMD, HINFC610_CMD);
++	hinfc_write(host, opval, HINFC610_OP);
++	WAIT_CONTROLLER_FINISH();
++
++	writel(toshiba_rr_param[param], host->chip->IO_ADDR_R);
++	hinfc_write(host, 0x6, HINFC610_ADDRL);
++	hinfc_write(host, TOSHIBA_RR_CMD, HINFC610_CMD);
++	hinfc_write(host, opval, HINFC610_OP);
++	WAIT_CONTROLLER_FINISH();
++
++	writel(toshiba_rr_param[param], host->chip->IO_ADDR_R);
++	hinfc_write(host, 0x7, HINFC610_ADDRL);
++	hinfc_write(host, TOSHIBA_RR_CMD, HINFC610_CMD);
++	hinfc_write(host, opval, HINFC610_OP);
++	WAIT_CONTROLLER_FINISH();
++
++	return 0;
++
++#undef TOSHIBA_RR_CMD
++}
++/*****************************************************************************/
++
++static int hinfc610_toshiba_24nm_set_rr_param(struct hinfc_host *host,
++		int param)
++{
++	int opval;
++
++	host->enable_ecc_randomizer(host, DISABLE, DISABLE);
++
++	opval = (HINFC610_IS_SYNC(host) ? HINFC610_WRITE_2CMD_0ADD_NODATA_SYNC
++		: HINFC610_WRITE_2CMD_0ADD_NODATA);
++
++	hinfc_write(host, HINFC_CMD_SEQ(0x5C, 0xC5), HINFC610_CMD);
++	hinfc_write(host, opval, HINFC610_OP);
++	WAIT_CONTROLLER_FINISH();
++
++	hinfc610_toshiba_24nm_set_rr_reg(host, param);
++
++	hinfc_write(host, HINFC_CMD_SEQ(0x26, 0x5D), HINFC610_CMD);
++	hinfc_write(host, opval, HINFC610_OP);
++	WAIT_CONTROLLER_FINISH();
++
++	host->enable_ecc_randomizer(host, ENABLE, ENABLE);
++
++	return 0;
++}
++/*****************************************************************************/
++
++static int hinfc610_toshiba_24nm_reset_rr_param(struct hinfc_host *host)
++{
++	return hinfc610_toshiba_24nm_set_rr_reg(host, 0);
++}
++/*****************************************************************************/
++struct read_retry_t hinfc610_toshiba_24nm_read_retry = {
++	.type = NAND_RR_TOSHIBA_24nm,
++	.count = 6,
++	.set_rr_param = hinfc610_toshiba_24nm_set_rr_param,
++	.get_rr_param = NULL,
++	.reset_rr_param = hinfc610_toshiba_24nm_reset_rr_param,
++};
+diff --git a/drivers/mtd/nand/hinfc610/hinfc610_sync.c b/drivers/mtd/nand/hinfc610/hinfc610_sync.c
+new file mode 100644
+index 0000000..c389d98
+--- /dev/null
++++ b/drivers/mtd/nand/hinfc610/hinfc610_sync.c
+@@ -0,0 +1,187 @@
++/*
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include "hinfc610_os.h"
++#include "hinfc610_gen.h"
++#include "hinfc610.h"
++#include "hinfc610_sync.h"
++
++static struct nand_sync *nand_sync_table[] = {
++	&hinfc610_sync_onfi_23,
++	&hinfc610_sync_onfi_30,
++	&hinfc610_sync_toggle_10,
++	NULL,
++};
++
++static struct nand_sync *hinfc610_find_sync_type(int type)
++{
++	struct nand_sync **sync;
++
++	for (sync = nand_sync_table; sync; sync++) {
++		if ((*sync)->type == type)
++			return *sync;
++	}
++
++	return NULL;
++}
++/*****************************************************************************/
++
++static int hinfc610_onfi_support_sync(struct hinfc_host *host)
++{
++	char buf[6] = {0};
++
++	host->enable_ecc_randomizer(host, DISABLE, DISABLE);
++
++	hinfc_write(host, sizeof(buf), HINFC610_DATA_NUM);
++	hinfc_write(host, NAND_CMD_READID, HINFC610_CMD);
++	hinfc_write(host, 0x20, HINFC610_ADDRL);
++	hinfc_write(host, HINFC610_READ_1CMD_1ADD_DATA, HINFC610_OP);
++
++	WAIT_CONTROLLER_FINISH();
++	memcpy(buf, host->chip->IO_ADDR_R, sizeof(buf));
++
++	if (memcmp(buf, "ONFI", 4))
++		return 0;
++
++	hinfc_write(host, sizeof(buf), HINFC610_DATA_NUM);
++	hinfc_write(host, NAND_CMD_READID, HINFC610_CMD);
++	hinfc_write(host, 0x40, HINFC610_ADDRL);
++	hinfc_write(host, HINFC610_READ_1CMD_1ADD_DATA, HINFC610_OP);
++
++	WAIT_CONTROLLER_FINISH();
++	memcpy(buf, host->chip->IO_ADDR_R, sizeof(buf));
++
++	if (memcmp(buf, "JEDEC", 5))
++		return 0;
++
++	return (buf[5] == 0x05);
++}
++/*****************************************************************************/
++
++static int hinfc610_get_onfi_info(struct hinfc_host *host, int *type)
++{
++	char buf[6] = {0};
++
++	*type = 0;
++
++	if (!hinfc610_onfi_support_sync(host))
++		return 0;
++
++	host->enable_ecc_randomizer(host, DISABLE, DISABLE);
++
++	hinfc_write(host, sizeof(buf), HINFC610_DATA_NUM);
++	hinfc_write(host, NAND_CMD_PARAM, HINFC610_CMD);
++	hinfc_write(host, 0x00, HINFC610_ADDRL);
++	hinfc_write(host, HINFC610_READ_1CMD_1ADD_DATA, HINFC610_OP);
++
++	WAIT_CONTROLLER_FINISH();
++	memcpy(buf, host->chip->IO_ADDR_R, sizeof(buf));
++
++	if (memcmp(buf, "ONFI", 4))
++		return 0;
++
++	if (buf[4] & (1 << 6))
++		*type = NAND_TYPE_ONFI_30;
++	else if (buf[4] & (1 << 5) ||
++		 buf[4] & (1 << 4) ||
++		 buf[4] & (1 << 3) ||
++		 buf[4] & (1 << 2))
++		*type = NAND_TYPE_ONFI_23;
++
++	return 1;
++}
++/*****************************************************************************/
++
++static int hinfc610_toggle_support_sync(struct hinfc_host *host)
++{
++	char buf[6] = {0};
++
++	host->enable_ecc_randomizer(host, DISABLE, DISABLE);
++
++	hinfc_write(host, sizeof(buf), HINFC610_DATA_NUM);
++	hinfc_write(host, NAND_CMD_READID, HINFC610_CMD);
++	hinfc_write(host, 0x40, HINFC610_ADDRL);
++	hinfc_write(host, HINFC610_READ_1CMD_1ADD_DATA, HINFC610_OP);
++
++	WAIT_CONTROLLER_FINISH();
++
++	memcpy(buf, host->chip->IO_ADDR_R, sizeof(buf));
++
++	if (memcmp(buf, "JEDEC", 5))
++		return 0;
++
++	return 1;
++}
++/*****************************************************************************/
++
++static int hinfc610_get_toggle_info(struct hinfc_host *host, int *type)
++{
++	char buf[8] = {0};
++
++	*type = 0;
++
++	if (!hinfc610_toggle_support_sync(host))
++		return 0;
++
++	host->enable_ecc_randomizer(host, DISABLE, DISABLE);
++
++	hinfc_write(host, sizeof(buf), HINFC610_DATA_NUM);
++	hinfc_write(host, NAND_CMD_PARAM, HINFC610_CMD);
++	hinfc_write(host, 0x40, HINFC610_ADDRL);
++	hinfc_write(host, HINFC610_READ_1CMD_1ADD_DATA, HINFC610_OP);
++
++	WAIT_CONTROLLER_FINISH();
++
++	memcpy(buf, host->chip->IO_ADDR_R, sizeof(buf));
++
++	if (memcmp(buf, "JESD", 4))
++		return 0;
++
++	if (buf[4] & (1 << 1))
++		/* supports revision 1.0 */
++		*type = NAND_TYPE_TOGGLE_10;
++	else
++		pr_warn("sync NAND has unknown toggle revision.\n");
++
++	return 1;
++}
++/*****************************************************************************/
++
++int hinfc610_get_sync_info(struct hinfc_host *host)
++{
++	int type = 0;
++
++	if (IS_NAND_ONFI(host))
++		hinfc610_get_onfi_info(host, &type);
++	else
++		hinfc610_get_toggle_info(host, &type);
++
++	if (!type) {
++		host->flags &= ~NAND_MODE_SYNC_ASYNC;
++		return 0;
++	}
++
++	host->sync = hinfc610_find_sync_type(type);
++	if (!host->sync)
++		PR_BUG(ERSTR_DRIVER
++			"This Nand Flash need to enable the 'synchronous' feature. "
++			"but the driver dose not offer the feature");
++
++	return 0;
++}
++/*****************************************************************************/
+diff --git a/drivers/mtd/nand/hinfc610/hinfc610_sync.h b/drivers/mtd/nand/hinfc610/hinfc610_sync.h
+new file mode 100644
+index 0000000..906fd10
+--- /dev/null
++++ b/drivers/mtd/nand/hinfc610/hinfc610_sync.h
+@@ -0,0 +1,25 @@
++/*
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#ifndef HINFC610_SYNC_H
++#define HINFC610_SYNC_H
++
++int hinfc610_get_sync_info(struct hinfc_host *host);
++
++#endif /* HINFC610_SYNC_H */
++
+diff --git a/drivers/mtd/nand/hinfc610/hinfc610_sync_onfi_23.c b/drivers/mtd/nand/hinfc610/hinfc610_sync_onfi_23.c
+new file mode 100644
+index 0000000..8fba306
+--- /dev/null
++++ b/drivers/mtd/nand/hinfc610/hinfc610_sync_onfi_23.c
+@@ -0,0 +1,107 @@
++/*
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include <linux/io.h>
++#include "hinfc610_os.h"
++#include "hinfc610.h"
++
++/*****************************************************************************/
++
++static int hinfc610_onfi_enable_sync(struct nand_chip *chip)
++{
++	struct hinfc_host *host = chip->priv;
++	unsigned char micron_sync_param[4] = {
++		0x14, /* set sync mode timing */ 0x00, 0x00, 0x00,
++	};
++
++	host->enable_ecc_randomizer(host, DISABLE, DISABLE);
++
++	hinfc_write(host, 1, HINFC610_DATA_NUM);
++	hinfc_write(host, 0xEF, HINFC610_CMD);
++	hinfc_write(host, 0x01, HINFC610_ADDRL);
++	writel(micron_sync_param[0], host->chip->IO_ADDR_R);
++	hinfc_write(host, HINFC610_WRITE_1CMD_1ADD_DATA, HINFC610_OP);
++	WAIT_CONTROLLER_FINISH();
++
++	writel(micron_sync_param[1], host->chip->IO_ADDR_R);
++	hinfc_write(host, HINFC610_WRITE_0CMD_1ADD_DATA, HINFC610_OP);
++	WAIT_CONTROLLER_FINISH();
++
++	writel(micron_sync_param[2], host->chip->IO_ADDR_R);
++	hinfc_write(host, HINFC610_WRITE_0CMD_1ADD_DATA, HINFC610_OP);
++	WAIT_CONTROLLER_FINISH();
++
++	/* need to config WAIT_READY_EN, here config this bit. */
++	writel(micron_sync_param[3], host->chip->IO_ADDR_R);
++	hinfc_write(host, HINFC610_WRITE_0CMD_1ADD_DATA_WAIT_READY,
++			HINFC610_OP);
++	WAIT_CONTROLLER_FINISH();
++
++	host->enable_ecc_randomizer(host, ENABLE, ENABLE);
++
++	return 0;
++}
++
++/*****************************************************************************/
++
++static int hinfc610_onfi_disable_sync(struct nand_chip *chip)
++{
++	struct hinfc_host *host = chip->priv;
++	unsigned char micron_sync_param[4] = {
++		0x00, 0x00, 0x00, 0x00,
++	};
++
++	host->enable_ecc_randomizer(host, DISABLE, DISABLE);
++
++	hinfc_write(host, 1, HINFC610_DATA_NUM);
++	hinfc_write(host, 0xEF, HINFC610_CMD);
++	hinfc_write(host, 0x01, HINFC610_ADDRL);
++	writel(micron_sync_param[0], host->chip->IO_ADDR_R);
++	hinfc_write(host, HINFC610_WRITE_1CMD_1ADD_DATA_SYNC, HINFC610_OP);
++	WAIT_CONTROLLER_FINISH();
++
++	writel(micron_sync_param[1], host->chip->IO_ADDR_R);
++	hinfc_write(host, HINFC610_WRITE_0CMD_1ADD_DATA_SYNC, HINFC610_OP);
++	WAIT_CONTROLLER_FINISH();
++
++	writel(micron_sync_param[2], host->chip->IO_ADDR_R);
++	hinfc_write(host, HINFC610_WRITE_0CMD_1ADD_DATA_SYNC, HINFC610_OP);
++	WAIT_CONTROLLER_FINISH();
++
++	writel(micron_sync_param[3], host->chip->IO_ADDR_R);
++	hinfc_write(host, HINFC610_WRITE_0CMD_1ADD_DATA_SYNC_WAIT_READY,
++			HINFC610_OP);
++	WAIT_CONTROLLER_FINISH();
++
++	host->enable_ecc_randomizer(host, ENABLE, ENABLE);
++
++	return 0;
++}
++/*****************************************************************************/
++
++struct nand_sync hinfc610_sync_onfi_23 = {
++	.type    = NAND_TYPE_ONFI_23,
++	.enable  = hinfc610_onfi_enable_sync,
++	.disable = hinfc610_onfi_disable_sync,
++};
++
++struct nand_sync hinfc610_sync_onfi_30 = {
++	.type    = NAND_TYPE_ONFI_30,
++	.enable  = hinfc610_onfi_enable_sync,
++	.disable = hinfc610_onfi_disable_sync,
++};
+diff --git a/drivers/mtd/nand/hinfc610/hinfc610_sync_toggle.c b/drivers/mtd/nand/hinfc610/hinfc610_sync_toggle.c
+new file mode 100644
+index 0000000..918b210
+--- /dev/null
++++ b/drivers/mtd/nand/hinfc610/hinfc610_sync_toggle.c
+@@ -0,0 +1,101 @@
++/*
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include <linux/io.h>
++#include "hinfc610_os.h"
++#include "hinfc610.h"
++
++/*****************************************************************************/
++
++static int hinfc610_toggle_enable_sync(struct nand_chip *chip)
++{
++	struct hinfc_host *host = chip->priv;
++	unsigned char toshiba_sync_param[4] = {
++		0x00, 0x00, 0x00, 0x00,
++	};
++
++	host->enable_ecc_randomizer(host, DISABLE, DISABLE);
++
++	hinfc_write(host, 1, HINFC610_DATA_NUM);
++	hinfc_write(host, 0xEF, HINFC610_CMD);
++	hinfc_write(host, 0x80, HINFC610_ADDRL);
++	writel(toshiba_sync_param[0], host->chip->IO_ADDR_R);
++	hinfc_write(host, HINFC610_WRITE_1CMD_1ADD_DATA, HINFC610_OP);
++	WAIT_CONTROLLER_FINISH();
++
++	writel(toshiba_sync_param[1], host->chip->IO_ADDR_R);
++	hinfc_write(host, HINFC610_WRITE_0CMD_1ADD_DATA, HINFC610_OP);
++	WAIT_CONTROLLER_FINISH();
++
++	writel(toshiba_sync_param[2], host->chip->IO_ADDR_R);
++	hinfc_write(host, HINFC610_WRITE_0CMD_1ADD_DATA, HINFC610_OP);
++	WAIT_CONTROLLER_FINISH();
++
++	/* need to config WAIT_READY_EN. */
++	writel(toshiba_sync_param[3], host->chip->IO_ADDR_R);
++	hinfc_write(host, HINFC610_WRITE_0CMD_1ADD_DATA_WAIT_READY,
++			HINFC610_OP);
++	WAIT_CONTROLLER_FINISH();
++
++	host->enable_ecc_randomizer(host, ENABLE, ENABLE);
++
++	return 0;
++}
++/*****************************************************************************/
++
++static int hinfc610_toggle_disable_sync(struct nand_chip *chip)
++{
++	struct hinfc_host *host = chip->priv;
++	unsigned char toshiba_sync_param[4] = {
++		0x01, 0x00, 0x00, 0x00,
++	};
++
++	host->enable_ecc_randomizer(host, DISABLE, DISABLE);
++
++	hinfc_write(host, 1, HINFC610_DATA_NUM);
++	hinfc_write(host, 0xEF, HINFC610_CMD);
++	hinfc_write(host, 0x80, HINFC610_ADDRL);
++	writel(toshiba_sync_param[0], host->chip->IO_ADDR_R);
++	hinfc_write(host, HINFC610_WRITE_1CMD_1ADD_DATA_SYNC, HINFC610_OP);
++	WAIT_CONTROLLER_FINISH();
++
++	writel(toshiba_sync_param[1], host->chip->IO_ADDR_R);
++	hinfc_write(host, HINFC610_WRITE_0CMD_1ADD_DATA_SYNC, HINFC610_OP);
++	WAIT_CONTROLLER_FINISH();
++
++	writel(toshiba_sync_param[2], host->chip->IO_ADDR_R);
++	hinfc_write(host, HINFC610_WRITE_0CMD_1ADD_DATA_SYNC, HINFC610_OP);
++	WAIT_CONTROLLER_FINISH();
++
++	/* need to config WAIT_READY_EN */
++	writel(toshiba_sync_param[3], host->chip->IO_ADDR_R);
++	hinfc_write(host, HINFC610_WRITE_0CMD_1ADD_DATA_SYNC_WAIT_READY,
++			HINFC610_OP);
++	WAIT_CONTROLLER_FINISH();
++
++	host->enable_ecc_randomizer(host, ENABLE, ENABLE);
++
++	return 0;
++}
++/*****************************************************************************/
++
++struct nand_sync hinfc610_sync_toggle_10 = {
++	.type    = NAND_TYPE_TOGGLE_10,
++	.enable  = hinfc610_toggle_enable_sync,
++	.disable = hinfc610_toggle_disable_sync,
++};
+diff --git a/drivers/mtd/nand/hinfc610/hinfc620_gen.c b/drivers/mtd/nand/hinfc610/hinfc620_gen.c
+new file mode 100644
+index 0000000..a1e68f8
+--- /dev/null
++++ b/drivers/mtd/nand/hinfc610/hinfc620_gen.c
+@@ -0,0 +1,78 @@
++/*
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include "../match_table.h"
++#include "hinfc620_gen.h"
++
++/*****************************************************************************/
++
++static struct match_reg_type page_type2reg[] = {
++	{
++		hinfc620_pagesize_2K, NAND_PAGE_2K,
++	}, {
++		hinfc620_pagesize_4K, NAND_PAGE_4K,
++	}, {
++		hinfc620_pagesize_8K, NAND_PAGE_8K,
++	}, {
++		hinfc620_pagesize_16K, NAND_PAGE_16K,
++	}, {
++		hinfc620_pagesize_32K, NAND_PAGE_32K,
++	}
++};
++
++enum hinfc620_page_reg hinfc620_page_type2reg(int type)
++{
++	return type2reg(page_type2reg, ARRAY_SIZE(page_type2reg), type, 0);
++}
++
++int hinfc620_page_reg2type(enum hinfc620_page_reg reg)
++{
++	return reg2type(page_type2reg, ARRAY_SIZE(page_type2reg), reg, 0);
++}
++/*****************************************************************************/
++
++static struct match_reg_type ecc_type2reg[] = {
++	{
++		hinfc620_ecc_none, NAND_ECC_NONE,
++	}, {
++		hinfc620_ecc_8bit, NAND_ECC_4BIT_512,
++	}, {
++		hinfc620_ecc_16bit, NAND_ECC_8BIT_512,
++	}, {
++		hinfc620_ecc_24bit, NAND_ECC_24BIT,
++	}, {
++		hinfc620_ecc_40bit, NAND_ECC_40BIT,
++	}, {
++		hinfc620_ecc_64bit, NAND_ECC_64BIT,
++	}, {
++		hinfc620_ecc_28bit, NAND_ECC_28BIT,
++	}, {
++		hinfc620_ecc_42bit, NAND_ECC_42BIT,
++	}
++};
++
++enum hinfc620_ecc_reg hinfc620_ecc_type2reg(int type)
++{
++	return type2reg(ecc_type2reg, ARRAY_SIZE(ecc_type2reg), type, 0);
++}
++
++int hinfc620_ecc_reg2type(enum hinfc620_ecc_reg reg)
++{
++	return reg2type(ecc_type2reg, ARRAY_SIZE(ecc_type2reg), reg, 0);
++}
++
+diff --git a/drivers/mtd/nand/hinfc610/hinfc620_gen.h b/drivers/mtd/nand/hinfc610/hinfc620_gen.h
+new file mode 100644
+index 0000000..88fb1e4
+--- /dev/null
++++ b/drivers/mtd/nand/hinfc610/hinfc620_gen.h
+@@ -0,0 +1,53 @@
++/*
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#ifndef HINFC620_GENH
++#define HINFC620_GENH
++/******************************************************************************/
++
++#include "../hinfc_gen.h"
++
++enum hinfc620_ecc_reg {
++	hinfc620_ecc_none   = 0x00,
++	hinfc620_ecc_8bit   = 0x02,
++	hinfc620_ecc_16bit  = 0x03,
++	hinfc620_ecc_24bit  = 0x04,
++	hinfc620_ecc_40bit  = 0x05,
++	hinfc620_ecc_64bit  = 0x06,
++	hinfc620_ecc_28bit  = 0x07,
++	hinfc620_ecc_42bit  = 0x08,
++};
++
++enum hinfc620_page_reg {
++	hinfc620_pagesize_2K    = 0x01,
++	hinfc620_pagesize_4K    = 0x02,
++	hinfc620_pagesize_8K    = 0x03,
++	hinfc620_pagesize_16K   = 0x04,
++	hinfc620_pagesize_32K   = 0x05,
++};
++
++enum hinfc620_page_reg hinfc620_page_type2reg(int type);
++
++int hinfc620_page_reg2type(enum hinfc620_page_reg reg);
++
++enum hinfc620_ecc_reg hinfc620_ecc_type2reg(int type);
++
++int hinfc620_ecc_reg2type(enum hinfc620_ecc_reg reg);
++
++/******************************************************************************/
++#endif /* HINFC620_GENH */
+diff --git a/drivers/mtd/nand/hinfc_gen.c b/drivers/mtd/nand/hinfc_gen.c
+new file mode 100644
+index 0000000..7ecfb5a
+--- /dev/null
++++ b/drivers/mtd/nand/hinfc_gen.c
+@@ -0,0 +1,247 @@
++/*
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++ 
++#include <linux/mfd/hisi_fmc.h>
++#include "match_table.h"
++#include "hinfc_gen.h"
++
++/*****************************************************************************/
++struct nand_flash_dev *(*nand_get_flash_type_func)(struct mtd_info *mtd,
++	struct nand_chip *chip, struct nand_dev_t *spinand_dev_t) = NULL;
++
++struct nand_flash_dev *(*get_spi_nand_flash_type_hook)(struct mtd_info *mtd,
++		unsigned char *id) = NULL;
++
++/*****************************************************************************/
++static struct match_t match_ecc[] = {
++	MATCH_SET_TYPE_DATA(NAND_ECC_NONE, "none"),
++	MATCH_SET_TYPE_DATA(NAND_ECC_0BIT, "none"),
++	MATCH_SET_TYPE_DATA(NAND_ECC_1BIT_512, "1bit/512"),
++	MATCH_SET_TYPE_DATA(NAND_ECC_4BIT, "4bit/512"),
++	MATCH_SET_TYPE_DATA(NAND_ECC_4BIT_512, "4bit/512"),
++	MATCH_SET_TYPE_DATA(NAND_ECC_4BYTE, "4byte/1k"),
++	MATCH_SET_TYPE_DATA(NAND_ECC_8BIT, "4bit/512"),
++	MATCH_SET_TYPE_DATA(NAND_ECC_8BIT_512, "8bit/512"),
++	MATCH_SET_TYPE_DATA(NAND_ECC_8BYTE, "8byte/1k"),
++	MATCH_SET_TYPE_DATA(NAND_ECC_13BIT, "13bit/1k"),
++	MATCH_SET_TYPE_DATA(NAND_ECC_16BIT, "8bit/512"),
++	MATCH_SET_TYPE_DATA(NAND_ECC_18BIT, "18bit/1k"),
++	MATCH_SET_TYPE_DATA(NAND_ECC_24BIT, "24bit/1k"),
++	MATCH_SET_TYPE_DATA(NAND_ECC_27BIT, "27bit/1k"),
++	MATCH_SET_TYPE_DATA(NAND_ECC_32BIT, "32bit/1k"),
++	MATCH_SET_TYPE_DATA(NAND_ECC_40BIT, "40bit/1k"),
++	MATCH_SET_TYPE_DATA(NAND_ECC_41BIT, "41bit/1k"),
++	MATCH_SET_TYPE_DATA(NAND_ECC_48BIT, "48bit/1k"),
++	MATCH_SET_TYPE_DATA(NAND_ECC_60BIT, "60bit/1k"),
++	MATCH_SET_TYPE_DATA(NAND_ECC_72BIT, "72bit/1k"),
++	MATCH_SET_TYPE_DATA(NAND_ECC_80BIT, "80bit/1k"),
++};
++
++const char *nand_ecc_name(int type)
++{
++	return (char *)match_type_to_data(match_ecc, ARRAY_SIZE(match_ecc),
++		type, "unknown");
++}
++
++char *get_ecctype_str(enum ecc_type ecctype)
++{
++	static char *ecctype_string[] = {
++		"None", "1bit/512Byte", "4bits/512Byte", "8bits/512Byte",
++		"24bits/1K", "40bits/1K", "unknown", "unknown"};
++	return ecctype_string[(ecctype & 0x07)];
++}
++
++/*****************************************************************************/
++static struct match_type_str page2name[] = {
++	{ NAND_PAGE_512B, "512" },
++	{ NAND_PAGE_2K,   "2K" },
++	{ NAND_PAGE_4K,   "4K" },
++	{ NAND_PAGE_8K,   "8K" },
++	{ NAND_PAGE_16K,  "16K" },
++	{ NAND_PAGE_32K,  "32K" },
++};
++
++const char *nand_page_name(int type)
++{
++	return type2str(page2name, ARRAY_SIZE(page2name), type, "unknown");
++}
++
++char *get_pagesize_str(enum page_type pagetype)
++{
++	static char *pagesize_str[] = {
++		"512", "2K", "4K", "8K", "16K", "unknown",
++		"unknown", "unknown"};
++	return pagesize_str[(pagetype & 0x07)];
++}
++
++/*****************************************************************************/
++static struct match_reg_type page2size[] = {
++	{ _512B, NAND_PAGE_512B },
++	{ _2K, NAND_PAGE_2K },
++	{ _4K, NAND_PAGE_4K },
++	{ _8K, NAND_PAGE_8K },
++	{ _16K, NAND_PAGE_16K },
++	{ _32K, NAND_PAGE_32K },
++};
++
++unsigned int get_pagesize(enum page_type pagetype)
++{
++	unsigned int pagesize[] = {
++		_512B, _2K, _4K, _8K, _16K, 0, 0, 0};
++	return pagesize[(pagetype & 0x07)];
++}
++
++int nandpage_size2type(int size)
++{
++	return reg2type(page2size, ARRAY_SIZE(page2size), size, NAND_PAGE_2K);
++}
++
++int nandpage_type2size(int size)
++{
++	return type2reg(page2size, ARRAY_SIZE(page2size), size, NAND_PAGE_2K);
++}
++
++char *nand_dbgfs_options;
++
++static int __init dbgfs_options_setup(char *s)
++{
++	nand_dbgfs_options = s;
++	return 1;
++}
++__setup("nanddbgfs=", dbgfs_options_setup);
++
++/*****************************************************************************/
++
++int get_bits(unsigned int n)
++{
++	int loop;
++	int ret = 0;
++
++	if (!n)
++		return 0;
++
++	if (n > 0xFFFF)
++		loop = n > 0xFFFFFF ? 32 : 24;
++	else
++		loop = n > 0xFF ? 16 : 8;
++
++	while (loop-- > 0 && n) {
++		if (n & 1)
++			ret++;
++		n >>= 1;
++	}
++	return ret;
++}
++
++/*****************************************************************************/
++#define et_ecc_none	0x00
++#define et_ecc_4bit	0x02
++#define et_ecc_8bit	0x03
++#define et_ecc_24bit1k	0x04
++#define et_ecc_40bit1k	0x05
++#define et_ecc_64bit1k	0x06
++
++static struct match_reg_type ecc_yaffs_type_t[] = {
++	{et_ecc_none,		NAND_ECC_0BIT},
++	{et_ecc_4bit,		NAND_ECC_8BIT},
++	{et_ecc_8bit,		NAND_ECC_16BIT},
++	{et_ecc_24bit1k,	NAND_ECC_24BIT},
++	{et_ecc_40bit1k,	NAND_ECC_40BIT},
++	{et_ecc_64bit1k,	NAND_ECC_64BIT}
++};
++
++unsigned char match_ecc_type_to_yaffs(unsigned char type)
++{
++	return type2reg(ecc_yaffs_type_t, ARRAY_SIZE(ecc_yaffs_type_t), type,
++			et_ecc_4bit);
++}
++
++/*****************************************************************************/
++static struct match_t page_table[] = {
++	{NAND_PAGE_2K,	PAGE_SIZE_2KB,	"2K"},
++	{NAND_PAGE_4K,	PAGE_SIZE_4KB,	"4K"},
++	{NAND_PAGE_8K,	PAGE_SIZE_8KB,	"8K"},
++	{NAND_PAGE_16K,	PAGE_SIZE_16KB,	"16K"},
++};
++
++unsigned char match_page_reg_to_type(unsigned char reg)
++{
++	return match_reg_to_type(page_table, ARRAY_SIZE(page_table), reg,
++			NAND_PAGE_2K);
++}
++
++unsigned char match_page_type_to_reg(unsigned char type)
++{
++	return match_type_to_reg(page_table, ARRAY_SIZE(page_table), type,
++			PAGE_SIZE_2KB);
++}
++
++const char *match_page_type_to_str(unsigned char type)
++{
++	return match_type_to_data(page_table, ARRAY_SIZE(page_table), type,
++			"unknown");
++}
++
++/*****************************************************************************/
++static struct match_t ecc_table[] = {
++	{NAND_ECC_0BIT,		ECC_TYPE_0BIT,	"none"},
++	{NAND_ECC_8BIT,		ECC_TYPE_8BIT,	"4bit/512"},
++	{NAND_ECC_16BIT,	ECC_TYPE_16BIT,	"8bit/512"},
++	{NAND_ECC_24BIT,	ECC_TYPE_24BIT,	"24bit/1K"},
++	{NAND_ECC_28BIT,	ECC_TYPE_28BIT,	"28bit/1K"},
++	{NAND_ECC_40BIT,	ECC_TYPE_40BIT,	"40bit/1K"},
++	{NAND_ECC_64BIT,	ECC_TYPE_64BIT,	"64bit/1K"},
++};
++
++unsigned char match_ecc_reg_to_type(unsigned char reg)
++{
++	return match_reg_to_type(ecc_table, ARRAY_SIZE(ecc_table), reg,
++			NAND_ECC_8BIT);
++}
++
++unsigned char match_ecc_type_to_reg(unsigned char type)
++{
++	return match_type_to_reg(ecc_table, ARRAY_SIZE(ecc_table), type,
++			ECC_TYPE_8BIT);
++}
++
++const char *match_ecc_type_to_str(unsigned char type)
++{
++	return match_type_to_data(ecc_table, ARRAY_SIZE(ecc_table), type,
++			"unknown");
++}
++
++/*****************************************************************************/
++static struct match_t page_type_size_table[] = {
++	{NAND_PAGE_2K,	_2K,	NULL},
++	{NAND_PAGE_4K,	_4K,	NULL},
++	{NAND_PAGE_8K,	_8K,	NULL},
++	{NAND_PAGE_16K,	_16K,	NULL},
++};
++
++unsigned char match_page_size_to_type(unsigned int size)
++{
++	return match_reg_to_type(page_type_size_table,
++			ARRAY_SIZE(page_type_size_table), size, NAND_PAGE_2K);
++}
++
++unsigned int match_page_type_to_size(unsigned char type)
++{
++	return match_type_to_reg(page_type_size_table,
++			ARRAY_SIZE(page_type_size_table), type, _2K);
++}
+diff --git a/drivers/mtd/nand/hinfc_gen.h b/drivers/mtd/nand/hinfc_gen.h
+new file mode 100644
+index 0000000..bc3658c
+--- /dev/null
++++ b/drivers/mtd/nand/hinfc_gen.h
+@@ -0,0 +1,288 @@
++/*
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#ifndef __HINFC_GEN_H__
++#define __HINFC_GEN_H__
++
++/*****************************************************************************/
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/nand.h>
++#include <linux/string_helpers.h>
++#include <asm/setup.h>
++#include <linux/module.h>
++
++/*****************************************************************************/
++#define HINFC_VER_300                   (0x300)
++#define HINFC_VER_301                   (0x301)
++#define HINFC_VER_310                   (0x310)
++#define HINFC_VER_504                   (0x504)
++#define HINFC_VER_505                   (0x505)
++#define HINFC_VER_600                   (0x600)
++#define HINFC_VER_610                   (0x610)
++#define HINFC_VER_620                   (0x620)
++
++/*****************************************************************************/
++#define NAND_PAGE_512B                   0
++#define NAND_PAGE_1K                     1
++#define NAND_PAGE_2K                     2
++#define NAND_PAGE_4K                     3
++#define NAND_PAGE_8K                     4
++#define NAND_PAGE_16K                    5
++#define NAND_PAGE_32K                    6
++
++/*****************************************************************************/
++#define NAND_ECC_NONE                    0
++#define NAND_ECC_0BIT                    0
++#define NAND_ECC_1BIT                    1
++#define NAND_ECC_1BIT_512                1
++#define NAND_ECC_4BIT                    2
++#define NAND_ECC_4BIT_512                2
++#define NAND_ECC_4BYTE                   2
++#define NAND_ECC_8BIT                    2
++#define NAND_ECC_8BIT_512                3
++#define NAND_ECC_8BYTE                   3
++#define NAND_ECC_13BIT                   4
++#define NAND_ECC_16BIT                   5
++#define NAND_ECC_18BIT                   6
++#define NAND_ECC_24BIT                   7
++#define NAND_ECC_27BIT                   8
++#define NAND_ECC_28BIT                   9
++#define NAND_ECC_32BIT                   10
++#define NAND_ECC_40BIT                   11
++#define NAND_ECC_41BIT                   12
++#define NAND_ECC_42BIT                   13
++#define NAND_ECC_48BIT                   14
++#define NAND_ECC_60BIT                   15
++#define NAND_ECC_64BIT                   16
++#define NAND_ECC_72BIT                   17
++#define NAND_ECC_80BIT                   18
++
++enum ecc_type {
++	et_ecc_none    = 0x00,
++	et_ecc_1bit    = 0x01,
++	et_ecc_4bit    = 0x02,
++	et_ecc_8bit    = 0x03,
++	et_ecc_24bit1k = 0x04,
++	et_ecc_40bit1k = 0x05,
++	et_ecc_64bit1k = 0x06,
++};
++
++enum page_type {
++	pt_pagesize_512   = 0x00,
++	pt_pagesize_2K    = 0x01,
++	pt_pagesize_4K    = 0x02,
++	pt_pagesize_8K    = 0x03,
++	pt_pagesize_16K   = 0x04,
++};
++
++/*****************************************************************************/
++struct nand_config_info {
++	unsigned int pagetype;
++	unsigned int ecctype;
++	unsigned int oobsize;
++	struct nand_ecclayout *layout;
++};
++
++struct hinfc_host;
++
++struct nand_sync {
++
++#define SET_NAND_SYNC_TYPE(_mfr, _onfi, _version) \
++	((((_mfr) & 0xFF) << 16) | (((_version) & 0xFF) << 8) \
++	 | ((_onfi) & 0xFF))
++
++#define GET_NAND_SYNC_TYPE_MFR(_type) (((_type) >> 16) & 0xFF)
++#define GET_NAND_SYNC_TYPE_VER(_type) (((_type) >> 8) & 0xFF)
++#define GET_NAND_SYNC_TYPE_INF(_type) ((_type) & 0xFF)
++
++#define NAND_TYPE_ONFI_23_MICRON    \
++	SET_NAND_SYNC_TYPE(NAND_MFR_MICRON, NAND_IS_ONFI, 0x23)
++#define NAND_TYPE_ONFI_30_MICRON    \
++	SET_NAND_SYNC_TYPE(NAND_MFR_MICRON, NAND_IS_ONFI, 0x30)
++#define NAND_TYPE_TOGGLE_TOSHIBA    \
++	SET_NAND_SYNC_TYPE(NAND_MFR_TOSHIBA, 0, 0)
++#define NAND_TYPE_TOGGLE_SAMSUNG    \
++	SET_NAND_SYNC_TYPE(NAND_MFR_SAMSUNG, 0, 0)
++
++#define NAND_TYPE_TOGGLE_10         SET_NAND_SYNC_TYPE(0, 0, 0x10)
++#define NAND_TYPE_ONFI_30           SET_NAND_SYNC_TYPE(0, NAND_IS_ONFI, 0x30)
++#define NAND_TYPE_ONFI_23           SET_NAND_SYNC_TYPE(0, NAND_IS_ONFI, 0x23)
++
++	int type;
++	int (*enable)(struct nand_chip *chip);
++	int (*disable)(struct nand_chip *chip);
++};
++
++struct read_retry_t {
++	int type;
++	int count;
++	int (*set_rr_param)(struct hinfc_host *host, int param);
++	int (*get_rr_param)(struct hinfc_host *host);
++	int (*reset_rr_param)(struct hinfc_host *host);
++};
++
++struct ecc_info_t {
++	int pagesize;
++	int ecctype;
++	int threshold;
++	int section;
++	void (*dump)(struct hinfc_host *host, unsigned char ecc[],
++		     int *max_bitsflag);
++};
++
++struct nand_dev_t {
++	struct nand_flash_dev flash_dev;
++
++	char *start_type;
++	unsigned char ids[8];
++	int oobsize;
++	int ecctype;
++
++	/* (Controller) support ecc/page detect, driver don't need detect */
++#define NANDC_HW_AUTO                         0x01
++	/* (Controller) support ecc/page detect,
++	 * and current ecc/page config finish */
++#define NANDC_CONFIG_DONE                     0x02
++	/* (Controller) is sync, default is async */
++#define NANDC_IS_SYNC_BOOT                    0x04
++
++/* (NAND) need randomizer */
++#define NAND_RANDOMIZER                       0x10
++/* (NAND) is ONFI interface, combine with sync/async symble */
++#define NAND_IS_ONFI                          0x20
++/* (NAND) support async and sync, such micron onfi, toshiba toggle 1.0 */
++#define NAND_MODE_SYNC_ASYNC                  0x40
++/* (NAND) support only sync, such samsung sync. */
++#define NAND_MODE_ONLY_SYNC                   0x80
++
++#define NAND_CHIP_MICRON   (NAND_MODE_SYNC_ASYNC | NAND_IS_ONFI)
++/* This NAND is async, or sync/async, default is async mode,
++ * toggle1.0 interface */
++#define NAND_CHIP_TOSHIBA_TOGGLE_10  (NAND_MODE_SYNC_ASYNC)
++/* This NAND is only sync mode, toggle2.0 interface */
++#define NAND_CHIP_TOSHIBA_TOGGLE_20   (NAND_MODE_ONLY_SYNC)
++/* This NAND is only sync mode */
++#define NAND_CHIP_SAMSUNG  (NAND_MODE_ONLY_SYNC)
++
++	unsigned int flags;
++
++#define NAND_RR_NONE                   0x00
++#define NAND_RR_HYNIX_BG_BDIE          0x10
++#define NAND_RR_HYNIX_BG_CDIE          0x11
++#define NAND_RR_HYNIX_CG_ADIE          0x12
++#define NAND_RR_MICRON                 0x20
++#define NAND_RR_SAMSUNG                0x30
++#define NAND_RR_TOSHIBA_24nm           0x40
++#define NAND_RR_TOSHIBA_19nm           0x41
++	int read_retry_type;
++};
++
++/*****************************************************************************/
++
++#define IS_NANDC_HW_AUTO(_host)         ((_host)->flags & NANDC_HW_AUTO)
++#define IS_NANDC_CONFIG_DONE(_host)     ((_host)->flags & NANDC_CONFIG_DONE)
++#define IS_NANDC_SYNC_BOOT(_host)       ((_host)->flags & NANDC_IS_SYNC_BOOT)
++
++#define IS_NAND_RANDOM(_dev)         ((_dev)->flags & NAND_RANDOMIZER)
++#define IS_NAND_ONLY_SYNC(_dev)      ((_dev)->flags & NAND_MODE_ONLY_SYNC)
++#define IS_NAND_SYNC_ASYNC(_dev)     ((_dev)->flags & NAND_MODE_SYNC_ASYNC)
++#define IS_NAND_ONFI(_dev)           ((_dev)->flags & NAND_IS_ONFI)
++
++#define ERSTR_HARDWARE  "Hardware configuration error. "
++#define ERSTR_DRIVER    "Driver does not support. "
++
++#define ENABLE                    1
++#define DISABLE                   0
++
++/*****************************************************************************/
++
++char *get_ecctype_str(enum ecc_type ecctype);
++
++char *get_pagesize_str(enum page_type pagetype);
++
++unsigned int get_pagesize(enum page_type pagetype);
++
++const char *nand_ecc_name(int type);
++
++const char *nand_page_name(int type);
++
++int nandpage_size2type(int size);
++
++int nandpage_type2size(int size);
++
++/*****************************************************************************/
++extern int (*hinfc_param_adjust)(struct mtd_info *mtd, struct nand_chip *chip,
++	struct nand_dev_t *nand_dev);
++
++extern struct nand_flash_dev *(*nand_get_flash_type_func)(struct mtd_info *mtd,
++	struct nand_chip *chip, struct nand_dev_t *spinand_dev_t);
++
++extern struct nand_flash_dev *(*get_spi_nand_flash_type_hook)
++		(struct mtd_info *mtd, unsigned char *id);
++
++extern int (*hinfc_param_adjust)(struct mtd_info *,
++		struct nand_chip *, struct nand_dev_t *);
++
++/*****************************************************************************/
++struct nand_flash_dev *hinfc_get_flash_type(struct mtd_info *mtd,
++	struct nand_chip *chip, u8 *id_data, int *busw);
++
++extern struct nand_flash_dev *(*get_spi_nand_flash_type_hook)
++	(struct mtd_info *mtd, unsigned char *id);
++
++void hinfc_nand_param_adjust(struct mtd_info *mtd, struct nand_chip *chip);
++
++void hinfc_show_info(struct mtd_info *mtd, char *vendor, char *chipname);
++
++void hinfc_show_chipsize(struct nand_chip *chip);
++
++int get_bits(unsigned int n);
++
++/*****************************************************************************/
++#define hinfc_pr_msg(_fmt, arg...) printk(_fmt, ##arg)
++
++#define hinfc_pr_bug(fmt, args...) do { \
++	printk("%s(%d): bug " fmt, __FILE__, __LINE__, ##args); \
++	while (1) \
++		; \
++} while (0)
++
++extern char *nand_dbgfs_options;
++/*****************************************************************************/
++extern unsigned char match_page_reg_to_type(unsigned char reg);
++
++extern unsigned char match_page_type_to_reg(unsigned char type);
++
++extern const char *match_page_type_to_str(unsigned char type);
++
++/*****************************************************************************/
++extern unsigned char match_ecc_reg_to_type(unsigned char reg);
++
++extern unsigned char match_ecc_type_to_reg(unsigned char type);
++
++extern const char *match_ecc_type_to_str(unsigned char type);
++
++/*****************************************************************************/
++extern unsigned char match_page_size_to_type(unsigned int size);
++
++extern unsigned int match_page_type_to_size(unsigned char type);
++
++const char *nand_ecc_name(int type);
++/*****************************************************************************/
++
++#endif /* End of __HINFC_GEN_H__ */
+diff --git a/drivers/mtd/nand/hinfc_spl_ids.c b/drivers/mtd/nand/hinfc_spl_ids.c
+new file mode 100644
+index 0000000..ccc15de
+--- /dev/null
++++ b/drivers/mtd/nand/hinfc_spl_ids.c
+@@ -0,0 +1,979 @@
++/*
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include <linux/mtd/mtd.h>
++#include <linux/mfd/hisi_fmc.h>
++#include "hinfc_gen.h"
++
++/*****************************************************************************/
++
++struct nand_flash_special_dev {
++	unsigned char id[8];
++	int length;             /* length of id. */
++	unsigned long long chipsize;
++	struct nand_flash_dev *(*probe)(struct nand_dev_t *nand_dev);
++	char *name;
++
++	unsigned long pagesize;
++	unsigned long erasesize;
++	unsigned long oobsize;
++	unsigned long options;
++	unsigned int read_retry_type;
++
++#define BBP_LAST_PAGE                    0x01
++#define BBP_FIRST_PAGE                   0x02
++	unsigned int badblock_pos;
++	unsigned int flags;
++};
++
++/*****************************************************************************/
++/*                    this is nand probe function.                           */
++/*****************************************************************************/
++
++static struct nand_flash_dev *hynix_probe_v02(
++	struct nand_dev_t *nand_dev)
++{
++	unsigned char *id = nand_dev->ids;
++	struct nand_flash_dev *type = &nand_dev->flash_dev;
++
++	int pagesizes[]   = {SZ_2K, SZ_4K, SZ_8K, 0};
++	int oobsizes[]    = {128, 224, 448, 0, 0, 0, 0, 0};
++	int blocksizes[]  = {SZ_128K, SZ_256K, SZ_512K,
++				(SZ_256K + SZ_512K), SZ_1M, SZ_2M, 0, 0};
++
++	int blocktype = (((id[3] >> 5) & 0x04) | ((id[3] >> 4) & 0x03));
++	int oobtype   = (((id[3] >> 2) & 0x03) | ((id[3] >> 4) & 0x04));
++
++	type->options   = 0;
++	type->pagesize  = pagesizes[(id[3] & 0x03)];
++	type->erasesize = blocksizes[blocktype];
++	nand_dev->oobsize = oobsizes[oobtype];
++
++	return type;
++}
++/*****************************************************************************/
++
++static struct nand_flash_dev *samsung_probe_v02(
++	struct nand_dev_t *nand_dev)
++{
++	unsigned char *id = nand_dev->ids;
++	struct nand_flash_dev *type = &nand_dev->flash_dev;
++
++	int pagesizes[]   = {SZ_2K, SZ_4K, SZ_8K, 0};
++	int oobsizes[]    = {0, 128, 218, 400, 436, 0, 0, 0};
++	int blocksizes[]  = {SZ_128K, SZ_256K, SZ_512K, SZ_1M, 0, 0, 0, 0};
++
++	int blocktype = (((id[3] >> 5) & 0x04) | ((id[3] >> 4) & 0x03));
++	int oobtype   = (((id[3] >> 4) & 0x04) | ((id[3] >> 2) & 0x03));
++
++	type->options   = 0;
++	type->pagesize  = pagesizes[(id[3] & 0x03)];
++	type->erasesize = blocksizes[blocktype];
++	nand_dev->oobsize = oobsizes[oobtype];
++
++	return type;
++}
++/*****************************************************************************/
++
++#define DRV_VERSION     "1.38"
++
++/*****************************************************************************/
++/*
++ * samsung:  27nm need randomizer, 21nm need read retry;
++ * micron:   25nm need read retry, datasheet will explain read retry.
++ * toshaba   32nm need randomizer, 24nm need read retry.
++ * hynix:    2xnm need read retry.
++ *
++ *		The special nand flash ID table version 1.37
++ *
++ * manufactory  |  type  |       name 	     |   ecc_type  | version_tag
++ * Micron		|  MLC	 |  MT29F64G08CBABA  |   40bit/1k  |  1.36
++ * Micron		|  MLC	 |  MT29F32G08CBADA  |   40bit/1k  |
++ * Micron		|  SLC	 |  MT29F8G08ABxBA   |   4bit/512  |
++ * Micron		|  MLC	 |  MT29F16G08CBABx  |   12bit/512 |
++ * Micron		|  MLC	 |  MT29F16G08CBACA  |   24bit/1k  |
++ * Micron		|  MLC	 |  MT29F32G08CBACA  |   24bit/1k  |
++ * Micron		|  MLC	 |  MT29F64G08CxxAA  |   24bit/1k  |
++ * Micron		|  MLC	 |  MT29F256G08CJAAA |   24bit/1k  |   2CE
++ * Micron		|  MLC	 |  MT29F256G08CMCBB |   24bit/1k  |
++ * Micron		|  SLC	 |  MT29F8G08ABACA   |   8bit/512  |
++ * Micron		|  SLC	 |  MT29F4G08ABAEA   |   8bit/512  |
++ * Micron		|  SLC	 |  MT29F2G08ABAFA   |   8bit/512  |
++ * Micron		|  SLC	 |  MT29F16G08ABACA  |   8bit/512  |
++ * Toshiba		|  MLC   |  TC58NVG4D2FTA00  |   24bit/1k  |
++ * Toshiba		|  MLC   |  TH58NVG6D2FTA20  |   24bit/1k  |   2CE
++ * Toshiba		|  MLC   |  TC58NVG5D2HTA00  |   40bit/1k  |
++ * Toshiba		|  MLC   |  TC58NVG6D2GTA00  |   40bit/1k  |
++ * Toshiba		|  MLC   |  TC58NVG6DCJTA00  |			   |
++ * Toshiba		|  MLC   |  TC58TEG5DCJTA00  |			   |
++ * Toshiba		|  SLC   |  TC58NVG0S3HTA00  |   8bit/512  |
++ * Toshiba		|  SLC   |  TC58NVG1S3HTA00  |   8bit/512  |
++ * Toshiba		|  SLC   |  TC58NVG1S3ETA00  |   4bit/512  |
++ * Toshiba		|  SLC   |  TC58NVG3S0FTA00  |   4bit/512  |
++ * Toshiba		|  SLC   |  TC58NVG2S0FTA00  |   4bit/512  |
++ * Toshiba		|  SLC   |  TH58NVG2S3HTA00  |   4bit/512  |
++ * Toshiba		|  TLC   |  TC58NVG5T2JTA00  |   60bit/1k  |
++ * Toshiba		|  TLC   |  TC58TEG5DCKTAx0  |   60bit/1k  |
++ * Toshiba		|  MLC   |  Tx58TEGxDDKTAx0  |			   |
++ * Samsung		|  MLC   |  K9LB(HC/PD/MD)G08U0(1)D  |   8bit/512B  |
++ * Samsung		|  MLC   |  K9GAG08U0E	     |   24bit/1KB |
++ * Samsung		|  MLC   |  K9LBG08U0E	     |   24bit/1KB |
++ * Samsung		|  MLC   |  K9G8G08U0C	     |   24bit/1KB |
++ * Samsung		|  MLC   |  K9GAG08U0F	     |   24bit/1KB |
++ * Samsung		|  MLC   |  K9LBG08U0M	     |             |
++ * Samsung		|  MLC   |  K9GBG08U0A	     |   24bit/1KB |
++ * Samsung		|  MLC   |  K9GBG08U0B	     |   40bit/1KB |
++ * Hynix		|  MLC   |  H27UAG8T2A	     |			   |
++ * Hynix		|  MLC   |  H27UAG8T2B	     |			   |
++ * Hynix		|  MLC   |  H27UBG8T2A	     |			   |
++ * Hynix		|  MLC   |  H27UBG8T2BTR	 |	 24bit/1KB |
++ * Hynix		|  MLC   |  H27UCG8T2A		 |	 40bit/1KB |
++ * Hynix		|  MLC   |  H27UBG8T2C		 |	 40bit/1KB |
++ * MISC			|  MLC   |  P1UAGA30AT-GCA	 |	 8bit/512  |
++ * MISC			|  MLC   |  PSU8GA30AT-GIA/ASU8GA30IT-G30CA	 |	 4bit/512  |
++ * MISC			|  SLC   |  PSU2GA30AT   	 |	 1bit/512  |   1.36
++ * Toshiba		|  SLC   |  TC58NVG2S0HTA00  |	 24bit/1K  |   1.37
++ * Toshiba		|  SLC   |  TC58NVG3S0HTA00  |   24bit/1K  |   1.37
++ * Micron		|  SLC	 |  MT29F2G08ABAEA   |   4bit/512 |
++ * Spansion		|  SLC	 | S34ML02G200TFI000	 | 24bit/1K |
++ * Spansion		|  SLC	 | S34ML04G200TFI000	 | 24bit/1K |  1.38
++ *
++ */
++
++static struct nand_flash_special_dev nand_flash_special_dev[] = {
++
++/****************************** Spansion *******************************/
++
++	{		/* SLC S34ML02G200TFI000 */
++		.name      = "S34ML02G200TFI000",
++		.id        = {0x01, 0xDA, 0x90, 0x95, 0x46, 0x00, 0x00, 0x00},
++		.length    = 5,
++		.chipsize  = _256M,
++		.probe     = NULL,
++		.pagesize  = SZ_2K,
++		.erasesize = SZ_128K,
++		.oobsize   = 128,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE,
++		.flags = 0,
++	},
++
++	{		/* SLC S34ML04G200TFI000 */
++		.name      = "S34ML04G200TFI000",
++		.id        = {0x01, 0xDC, 0x90, 0x95, 0x56, 0x00, 0x00, 0x00},
++		.length    = 5,
++		.chipsize  = _512M,
++		.probe     = NULL,
++		.pagesize  = SZ_2K,
++		.erasesize = SZ_128K,
++		.oobsize   = 128,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE,
++		.flags = 0,
++	},
++
++/****************************** Micron *******************************/
++	{        /* MLC 40bit/1k */
++		.name      = "MT29F64G08CBABA",
++		.id        = {0x2C, 0x64, 0x44, 0x4B, 0xA9, 0x00, 0x00, 0x00},
++		.length    = 8,
++		.chipsize  = _8G,
++		.probe     = NULL,
++		.pagesize  = SZ_8K,
++		.erasesize = SZ_2M,
++		.oobsize   = 744,
++		.options   = 0,
++		.read_retry_type = NAND_RR_MICRON,
++		.badblock_pos    = BBP_FIRST_PAGE,
++		.flags = NAND_RANDOMIZER | NAND_CHIP_MICRON,
++	},
++	{        /* MLC 40bit/1k */
++		.name      = "MT29F32G08CBADA",
++		.id        = {0x2C, 0x44, 0x44, 0x4B, 0xA9, 0x00, 0x00, 0x00},
++		.length    = 8,
++		.chipsize  = _4G,
++		.probe     = NULL,
++		.pagesize  = SZ_8K,
++		.erasesize = SZ_2M,
++		.oobsize   = 744,
++		.options   = 0,
++		.read_retry_type = NAND_RR_MICRON,
++		.badblock_pos    = BBP_FIRST_PAGE,
++		.flags = NAND_RANDOMIZER,
++	},
++	{        /* SLC 4bit/512 */
++		.name      = "MT29F8G08ABxBA",
++		.id        = {0x2C, 0x38, 0x00, 0x26, 0x85, 0x00, 0x00, 0x00},
++		.length    = 8,
++		.chipsize  = SZ_1G,
++		.probe     = NULL,
++		.pagesize  = SZ_4K,
++		.erasesize = SZ_512K,
++		.oobsize   = 224,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE,
++		.flags = 0,
++	},
++	{        /* MLC 12bit/512 */
++		.name      = "MT29F16G08CBABx",
++		.id        = {0x2C, 0x48, 0x04, 0x46, 0x85, 0x00, 0x00, 0x00},
++		.length    = 8,
++		.chipsize  = SZ_2G,
++		.probe     = NULL,
++		.pagesize  = SZ_4K,
++		.erasesize = SZ_1M,
++		.oobsize   = 224,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE,
++		.flags = 0,
++	},
++	{        /* MLC 24bit/1k */
++		.name      = "MT29F16G08CBACA",
++		.id        = {0x2C, 0x48, 0x04, 0x4A, 0xA5, 0x00, 0x00, 0x00},
++		.length    = 8,
++		.chipsize  = SZ_2G,
++		.probe     = NULL,
++		.pagesize  = SZ_4K,
++		.erasesize = SZ_1M,
++		.oobsize   = 224,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE,
++		.flags = 0,
++	},
++	{        /* MLC 24bit/1k */
++		.name      = "MT29F32G08CBACA",
++		.id        = {0x2C, 0x68, 0x04, 0x4A, 0xA9, 0x00, 0x00, 0x00},
++		.length    = 8,
++		.chipsize  = _4G,
++		.probe     = NULL,
++		.pagesize  = SZ_4K,
++		.erasesize = SZ_1M,
++		.oobsize   = 224,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE,
++		.flags = 0,
++	},
++	{        /* MLC 24bit/1k */
++		.name      = "MT29F64G08CxxAA",
++		.id        = {0x2C, 0x88, 0x04, 0x4B, 0xA9, 0x00, 0x00, 0x00},
++		.length    = 8,
++		.chipsize  = _8G,
++		.probe     = NULL,
++		.pagesize  = SZ_8K,
++		.erasesize = SZ_2M,
++		.oobsize   = 448,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE,
++		.flags = 0,
++	},
++	{        /* MLC 24bit/1k 2CE */
++		.name      = "MT29F256G08CJAAA",
++		.id        = {0x2C, 0xA8, 0x05, 0xCB, 0xA9, 0x00, 0x00, 0x00},
++		.length    = 8,
++		.chipsize  = _16G,
++		.probe     = NULL,
++		.pagesize  = SZ_8K,
++		.erasesize = SZ_2M,
++		.oobsize   = 448,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE,
++		.flags = 0,
++	},
++	{        /* MLC 40bit/1k */
++		.name      = "MT29F256G08CMCBB",
++		.id        = {0x2C, 0x64, 0x44, 0x4B, 0xA9, 0x00, 0x00, 0x00},
++		.length    = 8,
++		.chipsize  = _8G,
++		.probe     = NULL,
++		.pagesize  = SZ_8K,
++		.erasesize = SZ_2M,
++		.oobsize   = 744,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE,
++		.flags = 0,
++	},
++	{        /* SLC 8bit/512 */
++		.name      = "MT29F8G08ABACA",
++		.id        = {0x2C, 0xD3, 0x90, 0xA6, 0x64, 0x00, 0x00, 0x00},
++		.length    = 5,
++		.chipsize  = SZ_1G,
++		.probe     = NULL,
++		.pagesize  = SZ_4K,
++		.erasesize = SZ_256K,
++		.oobsize   = 224,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE,
++		.flags = 0,
++	},
++	{        /* SLC 8bit/512 */
++		.name      = "MT29F4G08ABAEA",
++		.id        = {0x2C, 0xDC, 0x90, 0xA6, 0x54, 0x00, 0x00, 0x00},
++		.length    = 5,
++		.chipsize  = SZ_512M,
++		.probe     = NULL,
++		.pagesize  = SZ_4K,
++		.erasesize = SZ_256K,
++		.oobsize   = 224,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE,
++		.flags = 0,
++	},
++	{        /* SLC 8bit/512 */
++		.name      = "MT29F2G08ABAFA",
++		.id        = {0x2C, 0xDA, 0x90, 0x95, 0x04, 0x00, 0x00, 0x00},
++		.length    = 5,
++		.chipsize  = SZ_256M,
++		.probe     = NULL,
++		.pagesize  = SZ_2K,
++		.erasesize = SZ_128K,
++		.oobsize   = 224,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE,
++		.flags = 0,
++	},
++	{		/* SLC MT29F2G08ABAEA */
++		.name      = "MT29F2G08ABAEA",
++		.id        = {0x2C, 0xDA, 0x90, 0x95, 0x06, 0x00, 0x00, 0x00},
++		.length    = 5,
++		.chipsize  = _256M,
++		.probe     = NULL,
++		.pagesize  = SZ_2K,
++		.erasesize = SZ_128K,
++		.oobsize   = 64,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE,
++		.flags = 0,
++	},
++	{        /* SLC 8bit/512 */
++		.name      = "MT29F16G08ABACA",
++		.id        = {0x2C, 0x48, 0x00, 0x26, 0xA9, 0x00, 0x00, 0x00},
++		.length    = 5,
++		.chipsize  = SZ_2G,
++		.probe     = NULL,
++		.pagesize  = SZ_4K,
++		.erasesize = SZ_512K,
++		.oobsize   = 224,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE,
++		.flags = 0,
++	},
++
++/****************************** Toshaba *******************************/
++
++	{       /* MLC 24bit/1k 32nm */
++		.name      = "TC58NVG4D2FTA00",
++		.id        = {0x98, 0xD5, 0x94, 0x32, 0x76, 0x55, 0x00, 0x00},
++		.length    = 6,
++		.chipsize  = SZ_2G,
++		.probe     = NULL,
++		.pagesize  = SZ_8K,
++		.erasesize = SZ_1M,
++		.oobsize   = 448,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE | BBP_LAST_PAGE,
++		.flags = 0,
++	},
++	{       /* MLC 24bit/1k 32nm 2CE*/
++		.name      = "TH58NVG6D2FTA20",
++		.id        = {0x98, 0xD7, 0x94, 0x32, 0x76, 0x55, 0x00, 0x00},
++		.length    = 6,
++		.chipsize  = _4G,
++		.probe     = NULL,
++		.pagesize  = SZ_8K,
++		.erasesize = SZ_1M,
++		.oobsize   = 448,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE | BBP_LAST_PAGE,
++		.flags = 0,
++	},
++	{       /* MLC 40bit/1k 24nm */
++		.name      = "TC58NVG5D2HTA00 24nm",
++		.id        = {0x98, 0xD7, 0x94, 0x32, 0x76, 0x56, 0x08, 0x00},
++		.length    = 6,
++		.chipsize  = _4G,
++		.probe     = NULL,
++		.pagesize  = SZ_8K,
++		.erasesize = SZ_1M,
++		.oobsize   = 640,
++		.options   = 0,
++		.read_retry_type = NAND_RR_TOSHIBA_24nm,
++		.badblock_pos    = BBP_FIRST_PAGE | BBP_LAST_PAGE,
++		.flags = NAND_RANDOMIZER,
++	},
++	{       /* MLC 40bit/1k */
++		.name      = "TC58NVG6D2GTA00",
++		.id        = {0x98, 0xDE, 0x94, 0x82, 0x76, 0x00, 0x00, 0x00},
++		.length    = 5,
++		.chipsize  = _8G,
++		.probe     = NULL,
++		.pagesize  = SZ_8K,
++		.erasesize = SZ_2M,
++		.oobsize   = 640,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE | BBP_LAST_PAGE,
++		.flags = 0,
++	},
++	{       /* MLC 19nm */
++		.name      = "TC58NVG6DCJTA00 19nm",
++		.id        = {0x98, 0xDE, 0x84, 0x93, 0x72, 0x57, 0x08, 0x04},
++		.length    = 8,
++		.chipsize  = _8G,
++		.probe     = NULL,
++		.pagesize  = SZ_16K,
++		.erasesize = SZ_4M,
++		.oobsize   = 1280,
++		.options   = 0,
++		.read_retry_type = NAND_RR_TOSHIBA_24nm,
++		.badblock_pos    = BBP_FIRST_PAGE | BBP_LAST_PAGE,
++		.flags = NAND_RANDOMIZER,
++	},
++	{       /* MLC 19nm */
++		.name      = "TC58TEG5DCJTA00 19nm",
++		.id        = {0x98, 0xD7, 0x84, 0x93, 0x72, 0x57, 0x08, 0x04},
++		.length    = 6,
++		.chipsize  = _4G,
++		.probe     = NULL,
++		.pagesize  = SZ_16K,
++		.erasesize = SZ_4M,
++		.oobsize   = 1280,
++		.options   = 0,
++		.read_retry_type = NAND_RR_TOSHIBA_24nm,
++		.badblock_pos    = BBP_FIRST_PAGE | BBP_LAST_PAGE,
++		.flags = NAND_RANDOMIZER | NAND_CHIP_TOSHIBA_TOGGLE_10,
++	},
++	{       /* SLC 8bit/512 */
++		.name      = "TC58NVG0S3HTA00",
++		.id        = {0x98, 0xF1, 0x80, 0x15, 0x72, 0x00, 0x00, 0x00},
++		.length    = 5,
++		.chipsize  = SZ_128M,
++		.probe     = NULL,
++		.pagesize  = SZ_2K,
++		.erasesize = SZ_128K,
++		.oobsize   = 128,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		/*
++		 * Datasheet: read one column of any page in each block. If the
++		 * data of the column is 00 (Hex), define the block as a bad
++		 * block.
++		 */
++		.badblock_pos    = BBP_FIRST_PAGE,
++		.flags = 0,
++	},
++	{       /* SLC 8bit/512 */
++		.name      = "TC58NVG1S3HTA00",
++		.id        = {0x98, 0xDA, 0x90, 0x15, 0x76, 0x16, 0x08, 0x00},
++		.length    = 7,
++		.chipsize  = SZ_256M,
++		.probe     = NULL,
++		.pagesize  = SZ_2K,
++		.erasesize = SZ_128K,
++		.oobsize   = 128,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE,
++		.flags = 0,
++	},
++	{       /* SLC 4bit/512 */
++		.name      = "TC58NVG1S3ETA00",
++		.id        = {0x98, 0xDA, 0x90, 0x15, 0x76, 0x14, 0x03, 0x00},
++		.length    = 7,
++		.chipsize  = SZ_256M,
++		.probe     = NULL,
++		.pagesize  = SZ_2K,
++		.erasesize = SZ_128K,
++		.oobsize   = 64,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE,
++		.flags = 0,
++	},
++	{       /* SLC 4bit/512 */
++		.name      = "TC58NVG3S0FTA00",
++		.id        = {0x98, 0xD3, 0x90, 0x26, 0x76, 0x15, 0x02, 0x08},
++		.length    = 8,
++		.chipsize  = SZ_1G,
++		.probe     = NULL,
++		.pagesize  = SZ_4K,
++		.erasesize = SZ_256K,
++		.oobsize   = 232,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE,
++		.flags = 0,
++	},
++	{       /* SLC 4bit/512 */
++		.name      = "TC58NVG3S0HTA00",
++		.id        = {0x98, 0xD3, 0x91, 0x26, 0x76, 0x16, 0x08, 0x00},
++		.length    = 8,
++		.chipsize  = SZ_1G,
++		.probe     = NULL,
++		.pagesize  = SZ_4K,
++		.erasesize = SZ_256K,
++		.oobsize   = 256,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE,
++		.flags = 0,
++	},
++	{       /* SLC 24bit/1k */
++		.name      = "TC58NVG2S0HTA00",
++		.id        = {0x98, 0xDC, 0x90, 0x26, 0x76, 0x16, 0x08, 0x00},
++		.length    = 8,
++		.chipsize  = SZ_512M,
++		.probe     = NULL,
++		.pagesize  = SZ_4K,
++		.erasesize = SZ_256K,
++		.oobsize   = 256,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE,
++		.flags = 0,
++	},
++	{       /* SLC 4bit/512 */
++		.name      = "TC58NVG2S0FTA00",
++		.id        = {0x98, 0xDC, 0x90, 0x26, 0x76, 0x15, 0x01, 0x08},
++		.length    = 8,
++		.chipsize  = SZ_512M,
++		.probe     = NULL,
++		.pagesize  = SZ_4K,
++		.erasesize = SZ_256K,
++		.oobsize   = 224,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE,
++		.flags = 0,
++	},
++	{       /* SLC 4bit/512 */
++		.name      = "TH58NVG2S3HTA00",
++		.id        = {0x98, 0xDC, 0x91, 0x15, 0x76},
++		.length    = 5,
++		.chipsize  = SZ_512M,
++		.probe     = NULL,
++		.pagesize  = SZ_2K,
++		.erasesize = SZ_128K,
++		.oobsize   = 128,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE,
++		.flags = 0,
++	},
++	{       /* TLC 60bit/1k 19nm */
++		.name      = "TC58NVG5T2JTA00 19nm TLC",
++		.id        = {0x98, 0xD7, 0x98, 0x92, 0x72, 0x57, 0x08, 0x10},
++		.length    = 6,
++		.chipsize  = _4G,
++		.probe     = NULL,
++		.pagesize  = SZ_8K,
++		.erasesize = SZ_4M,
++		.oobsize   = 1024,
++		.options   = 0,
++		.read_retry_type = NAND_RR_TOSHIBA_24nm,
++		.badblock_pos    = BBP_FIRST_PAGE | BBP_LAST_PAGE,
++		.flags = NAND_RANDOMIZER,
++	},
++	{	/* TLC 60bit/1k 19nm */
++		.name	   = "TC58TEG5DCKTAx0 19nm MLC",
++		/* datasheet says 6 ids id data, but really has 8 ids. */
++		.id	   = {0x98, 0xD7, 0x84, 0x93, 0x72, 0x50, 0x08, 0x04},
++		.length    = 6,
++		.chipsize  = _4G,
++		.probe	   = NULL,
++		.pagesize  = SZ_16K,
++		.erasesize = SZ_4M,
++		.oobsize   = 1280,
++		.options   = 0,
++		.read_retry_type = NAND_RR_TOSHIBA_19nm,
++		.badblock_pos	 = BBP_FIRST_PAGE | BBP_LAST_PAGE,
++		.flags = NAND_RANDOMIZER,
++	},
++	{
++		.name	   = "Tx58TEGxDDKTAx0 19nm MLC",
++		.id	   = {0x98, 0xDE, 0x94, 0x93, 0x76, 0x50},
++		.length    = 6,
++		.chipsize  = _4G,
++		.probe	   = NULL,
++		.pagesize  = SZ_16K,
++		.erasesize = SZ_4M,
++		.oobsize   = 1280,
++		.options   = 0,
++		.read_retry_type = NAND_RR_TOSHIBA_19nm,
++		.badblock_pos	 = BBP_FIRST_PAGE | BBP_LAST_PAGE,
++		.flags = NAND_RANDOMIZER,
++	},
++/******************************* Samsung ******************************/
++	{       /* MLC 8bit/512B */
++		.name     = "K9LB(HC/PD/MD)G08U0(1)D",
++		.id       = {0xEC, 0xD7, 0xD5, 0x29, 0x38, 0x41, 0x00, 0x00},
++		.length   = 6,
++		.chipsize = _4G,
++		.probe    = samsung_probe_v02,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_LAST_PAGE,
++		.flags = 0,
++	},
++	{       /* MLC 24bit/1KB */
++		.name      = "K9GAG08U0E",
++		.id        = {0xEC, 0xD5, 0x84, 0x72, 0x50, 0x42, 0x00, 0x00},
++		.length    = 6,
++		.chipsize  = SZ_2G,
++		.probe     = samsung_probe_v02,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE | BBP_LAST_PAGE,
++		.flags = 0,
++	},
++	{       /* MLC 24bit/1KB */
++		.name     = "K9LBG08U0E",
++		.id       = {0xEC, 0xD7, 0xC5, 0x72, 0x54, 0x42, 0x00, 0x00},
++		.length   = 6,
++		.chipsize = _4G,
++		.probe    = samsung_probe_v02,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE | BBP_LAST_PAGE,
++		.flags = 0,
++	},
++	{       /* MLC 24bit/1KB */
++		.name     = "K9G8G08U0C",
++		.id       = {0xEC, 0xD3, 0x84, 0x72, 0x50, 0x42, 0x00, 0x00},
++		.length   = 6,
++		.chipsize = SZ_1G,
++		.probe    = samsung_probe_v02,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE | BBP_LAST_PAGE,
++		.flags = 0,
++	},
++	{        /* MLC 24bit/1k */
++		.name      = "K9GAG08U0F",
++		.id        = {0xEC, 0xD5, 0x94, 0x76, 0x54, 0x43, 0x00, 0x00},
++		.length    = 6,
++		.chipsize  = SZ_2G,
++		.probe     = NULL,
++		.pagesize  = SZ_8K,
++		.erasesize = SZ_1M,
++		.oobsize   = 512,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE | BBP_LAST_PAGE,
++		.flags = 0,
++	},
++	{        /* MLC */
++		.name      = "K9LBG08U0M",
++		.id        = {0xEC, 0xD7, 0x55, 0xB6, 0x78, 0x00, 0x00, 0x00},
++		.length    = 5,
++		.chipsize  = _4G,
++		.probe     = NULL,
++		.pagesize  = SZ_4K,
++		.erasesize = SZ_512K,
++		.oobsize   = 128,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_LAST_PAGE,
++		.flags = 0,
++	},
++	{        /* MLC 24bit/1k */
++		.name      = "K9GBG08U0A 20nm",
++		.id        = {0xEC, 0xD7, 0x94, 0x7A, 0x54, 0x43, 0x00, 0x00},
++		.length    = 6,
++		.chipsize  = _4G,
++		.probe     = NULL,
++		.pagesize  = SZ_8K,
++		.erasesize = SZ_1M,
++		.oobsize   = 640,
++		.options   = 0,
++		.read_retry_type = NAND_RR_SAMSUNG,
++		.badblock_pos    = BBP_FIRST_PAGE | BBP_LAST_PAGE,
++		.flags = NAND_RANDOMIZER,
++	},
++	{        /* MLC 40bit/1k */
++		.name      = "K9GBG08U0B",
++		.id        = {0xEC, 0xD7, 0x94, 0x7E, 0x64, 0x44, 0x00, 0x00},
++		.length    = 6,
++		.chipsize  = _4G,
++		.probe     = NULL,
++		.pagesize  = SZ_8K,
++		.erasesize = SZ_1M,
++		.oobsize   = 1024,
++		.options   = 0,
++		.read_retry_type = NAND_RR_SAMSUNG,
++		.badblock_pos    = BBP_FIRST_PAGE | BBP_LAST_PAGE,
++		.flags = NAND_RANDOMIZER,
++	},
++
++/*********************************** Hynix ****************************/
++	{       /* MLC */
++		.name     = "H27UAG8T2A",
++		.id       = {0xAD, 0xD5, 0x94, 0x25, 0x44, 0x41, },
++		.length   = 6,
++		.chipsize = SZ_2G,
++		.probe    = hynix_probe_v02,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE | BBP_LAST_PAGE,
++		.flags = 0,
++	},
++	{       /* MLC */
++		.name     = "H27UAG8T2B",
++		.id       = {0xAD, 0xD5, 0x94, 0x9A, 0x74, 0x42, },
++		.length   = 6,
++		.chipsize = SZ_2G,
++		.probe    = hynix_probe_v02,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE | BBP_LAST_PAGE,
++		.flags = 0,
++	},
++	{       /* MLC */
++		.name     = "H27UBG8T2A",
++		.id       = {0xAD, 0xD7, 0x94, 0x9A, 0x74, 0x42, },
++		.length   = 6,
++		.chipsize = _4G,
++		.probe    = hynix_probe_v02,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE | BBP_LAST_PAGE,
++		.flags = 0,
++	},
++	{       /* MLC 24bit/1K, 26nm TODO: Need read retry, chip is EOS */
++		.name      = "H27UBG8T2BTR 26nm",
++		.id        = {0xAD, 0xD7, 0x94, 0xDA, 0x74, 0xC3, },
++		.length    = 6,
++		.chipsize  = _4G,
++		.probe     = NULL,
++		.pagesize  = SZ_8K,
++		.erasesize = SZ_2M,
++		.oobsize   = 640,
++		.options   = 0,
++		.read_retry_type = NAND_RR_HYNIX_BG_BDIE,
++		.badblock_pos    = BBP_FIRST_PAGE | BBP_LAST_PAGE,
++		.flags = NAND_RANDOMIZER,
++	},
++	{        /* MLC 40bit/1k */
++		.name      = "H27UCG8T2A",
++		.id        = {0xAD, 0xDE, 0x94, 0xDA, 0x74, 0xC4, },
++		.length    = 6,
++		.chipsize  = _8G,
++		.probe     = NULL,
++		.pagesize  = SZ_8K,
++		.erasesize = SZ_2M,
++		.oobsize   = 640,
++		.options   = 0,
++		.read_retry_type = NAND_RR_HYNIX_CG_ADIE,
++		.badblock_pos    = BBP_FIRST_PAGE | BBP_LAST_PAGE,
++		.flags = NAND_RANDOMIZER,
++	},
++	{        /* MLC 40bit/1k */
++		.name      = "H27UBG8T2C",
++		.id        = {0xAD, 0xD7, 0x94, 0x91, 0x60, 0x44, },
++		.length    = 6,
++		.chipsize  = _4G,
++		.probe     = NULL,
++		.pagesize  = SZ_8K,
++		.erasesize = SZ_2M,
++		.oobsize   = 640,
++		.options   = 0,
++		.read_retry_type = NAND_RR_HYNIX_BG_CDIE,
++		.badblock_pos    = BBP_FIRST_PAGE | BBP_LAST_PAGE,
++		.flags = NAND_RANDOMIZER,
++	},
++
++/********************** MISC ******************************************/
++	{        /* MLC 8bit/512 */
++		.name      = "P1UAGA30AT-GCA",
++		.id        = {0xC8, 0xD5, 0x14, 0x29, 0x34, 0x01, },
++		.length    = 6,
++		.chipsize  = SZ_2G,
++		.probe     = NULL,
++		.pagesize  = SZ_4K,
++		.erasesize = SZ_512K,
++		.oobsize   = 218,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE | BBP_LAST_PAGE,
++		.flags = 0,
++	},
++	{       /* MLC 4bit/512 */
++		/*
++		 * PowerFlash ASU8GA30IT-G30CA ID and MIRA PSU8GA30AT-GIA ID are
++		 * the same ID
++		 */
++		.name      = "PSU8GA30AT-GIA/ASU8GA30IT-G30CA",
++		.id        = {0xC8, 0xD3, 0x90, 0x19, 0x34, 0x01, },
++		.length    = 6,
++		.chipsize  = SZ_1G,
++		.probe     = NULL,
++		.pagesize  = SZ_4K,
++		.erasesize = SZ_256K,
++		.oobsize   = 218,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE | BBP_LAST_PAGE,
++		.flags = 0,
++	},
++	{        /* SLC 1bit/512 */
++		.name      = "PSU2GA30AT",
++		.id        = {0x7F, 0x7F, 0x7F, 0x7F, 0xC8, 0xDA, 0x00, 0x15, },
++		.length    = 8,
++		.chipsize  = SZ_256M,
++		.probe     = NULL,
++		.pagesize  = SZ_2K,
++		.erasesize = SZ_128K,
++		.oobsize   = 64,
++		.options   = 0,
++		.read_retry_type = NAND_RR_NONE,
++		.badblock_pos    = BBP_FIRST_PAGE | BBP_LAST_PAGE,
++		.flags = 0,
++	},
++	{{0}, 0, 0, 0, 0, 0, 0, 0, 0},
++};
++
++#define NUM_OF_SPECIAL_DEVICE  \
++	(sizeof(nand_flash_special_dev)/sizeof(struct nand_flash_special_dev))
++
++int (*hinfc_param_adjust)(struct mtd_info *, struct nand_chip *,
++			struct nand_dev_t *) = NULL;
++
++static struct nand_dev_t __nand_dev;
++/*****************************************************************************/
++
++static struct nand_flash_dev *hinfc_nand_probe(struct mtd_info *mtd,
++					       struct nand_chip *chip,
++					       struct nand_dev_t *nand_dev)
++{
++	struct nand_flash_special_dev *spl_dev;
++	unsigned char *byte = nand_dev->ids;
++	struct nand_flash_dev *type = &nand_dev->flash_dev;
++
++	hinfc_pr_msg("Nand ID: 0x%02X 0x%02X 0x%02X 0x%02X",
++			byte[0], byte[1], byte[2], byte[3]);
++	hinfc_pr_msg(" 0x%02X 0x%02X 0x%02X 0x%02X\n",
++			byte[4], byte[5], byte[6], byte[7]);
++
++	for (spl_dev = nand_flash_special_dev; spl_dev->length; spl_dev++) {
++		if (memcmp(byte, spl_dev->id, spl_dev->length))
++			continue;
++
++		hinfc_pr_msg("The Special NAND id table Version: %s\n", DRV_VERSION);
++
++		if (spl_dev->probe) {
++			type = spl_dev->probe(nand_dev);
++		} else {
++			type->options   = spl_dev->options;
++			type->pagesize  = spl_dev->pagesize;
++			type->erasesize = spl_dev->erasesize;
++			nand_dev->oobsize = spl_dev->oobsize;
++		}
++
++		nand_dev->read_retry_type = spl_dev->read_retry_type;
++		nand_dev->flags = spl_dev->flags;
++
++		type->id[1] = byte[1];
++		type->chipsize = (unsigned long)(spl_dev->chipsize >> 20);
++		type->name = spl_dev->name;
++		return type;
++	}
++	nand_dev->read_retry_type = NAND_RR_NONE;
++
++	return NULL;
++}
++/*****************************************************************************/
++
++struct nand_flash_dev *hinfc_get_flash_type(struct mtd_info *mtd,
++					    struct nand_chip *chip,
++					    u8 *id_data, int *busw)
++{
++	struct nand_flash_dev *type;
++	struct nand_dev_t *nand_dev = &__nand_dev;
++
++	memset(nand_dev, 0, sizeof(struct nand_dev_t));
++	memcpy(nand_dev->ids, id_data, 8);
++
++	if (!hinfc_nand_probe(mtd, chip, nand_dev))
++		return NULL;
++
++	type = &nand_dev->flash_dev;
++
++	if (!mtd->name)
++		mtd->name = type->name;
++
++	chip->chipsize = (uint64_t)type->chipsize << 20;
++	mtd->erasesize = type->erasesize;
++	mtd->writesize = type->pagesize;
++	mtd->oobsize   = nand_dev->oobsize;
++	*busw = (type->options & NAND_BUSWIDTH_16);
++
++	return type;
++}
++/*****************************************************************************/
++
++void hinfc_nand_param_adjust(struct mtd_info *mtd, struct nand_chip *chip)
++{
++	struct nand_dev_t *nand_dev = &__nand_dev;
++
++	if (!nand_dev->oobsize)
++		nand_dev->oobsize = mtd->oobsize;
++
++	if (hinfc_param_adjust)
++		hinfc_param_adjust(mtd, chip, nand_dev);
++}
++/*****************************************************************************/
++
++void hinfc_show_info(struct mtd_info *mtd, char *vendor, char *chipname)
++{
++	/* char buf[20]; */
++	struct nand_dev_t *nand_dev = &__nand_dev;
++
++	/* hinfc_pr_msg("Nand: %s %s ", vendor, chipname); */
++
++	if (IS_NAND_RANDOM(nand_dev))
++		hinfc_pr_msg("Randomizer \n");
++
++	if (nand_dev->read_retry_type != NAND_RR_NONE)
++		hinfc_pr_msg("Read-Retry \n");
++
++	if (nand_dev->start_type)
++		hinfc_pr_msg("Nand(%s): ", nand_dev->start_type);
++	else
++		hinfc_pr_msg("Nand: ");
++
++	hinfc_pr_msg("OOB:%dB ", nand_dev->oobsize);
++	hinfc_pr_msg("ECC:%s ", nand_ecc_name(nand_dev->ecctype));
++}
++/*****************************************************************************/
++
++void hinfc_show_chipsize(struct nand_chip *chip)
++{
++	/*char buf[20];*/
++
++	/*hinfc_pr_msg("Chip:%sB*%d\n",
++		     ultohstr(chip->chipsize, buf, sizeof(buf)),
++		     chip->numchips);*/
++}
+diff --git a/drivers/mtd/nand/match_table.c b/drivers/mtd/nand/match_table.c
+new file mode 100644
+index 0000000..271da05
+--- /dev/null
++++ b/drivers/mtd/nand/match_table.c
+@@ -0,0 +1,96 @@
++/******************************************************************************
++ *    COPYRIGHT (C) Hisilicon.2013
++ *    All rights reserved.
++ * ***
++ *    Create by Hisilicon 2013-08-15
++ *
++ *****************************************************************************/
++
++/*****************************************************************************/
++#include <linux/string.h>
++#include "match_table.h"
++
++/*****************************************************************************/
++int reg2type(struct match_reg_type *table, int length, int reg, int def)
++{
++	while (length-- > 0) {
++		if (table->reg == reg)
++			return table->type;
++		table++;
++	}
++	return def;
++}
++
++int type2reg(struct match_reg_type *table, int length, int type, int def)
++{
++	while (length-- > 0) {
++		if (table->type == type)
++			return table->reg;
++		table++;
++	}
++	return def;
++}
++
++int str2type(struct match_type_str *table, int length, const char *str,
++	     int size, int def)
++{
++	while (length-- > 0) {
++		if (!strncmp(table->str, str, size))
++			return table->type;
++		table++;
++	}
++	return def;
++}
++
++const char *type2str(struct match_type_str *table, int length, int type,
++		     const char *def)
++{
++	while (length-- > 0) {
++		if (table->type == type)
++			return table->str;
++		table++;
++	}
++	return def;
++}
++
++int match_reg_to_type(struct match_t *table, int nr_table, int reg, int def)
++{
++	while (nr_table-- > 0) {
++		if (table->reg == reg)
++			return table->type;
++		table++;
++	}
++	return def;
++}
++
++int match_type_to_reg(struct match_t *table, int nr_table, int type, int def)
++{
++	while (nr_table-- > 0) {
++		if (table->type == type)
++			return table->reg;
++		table++;
++	}
++	return def;
++}
++
++int match_data_to_type(struct match_t *table, int nr_table, char *data,
++		int size, int def)
++{
++	while (nr_table-- > 0) {
++		if (!memcmp(table->data, data, size))
++			return table->type;
++		table++;
++	}
++	return def;
++}
++
++void *match_type_to_data(struct match_t *table, int nr_table, int type,
++			 void *def)
++{
++	while (nr_table-- > 0) {
++		if (table->type == type)
++			return table->data;
++		table++;
++	}
++	return def;
++}
+diff --git a/drivers/mtd/nand/match_table.h b/drivers/mtd/nand/match_table.h
+new file mode 100644
+index 0000000..6fb55cf
+--- /dev/null
++++ b/drivers/mtd/nand/match_table.h
+@@ -0,0 +1,56 @@
++/******************************************************************************
++ *    COPYRIGHT (C) Hisilicon 2013
++ *    All rights reserved.
++ * ***
++ *    Create by Hisilicon 2013-08-15
++ *
++ *****************************************************************************/
++#ifndef __MATCH_TABLE_H__
++#define __MATCH_TABLE_H__
++
++/*****************************************************************************/
++struct match_reg_type {
++	int reg;
++	int type;
++};
++
++struct match_type_str {
++	int type;
++	const char *str;
++};
++
++struct match_t {
++	int type;
++	int reg;
++	void *data;
++};
++
++/*****************************************************************************/
++#define MATCH_SET_TYPE_REG(_type, _reg)   {(_type), (_reg), (void *)0}
++#define MATCH_SET_TYPE_DATA(_type, _data) {(_type), 0, (void *)(_data)}
++#define MATCH_SET(_type, _reg, _data)     {(_type), (_reg), (void *)(_data)}
++
++/*****************************************************************************/
++int reg2type(struct match_reg_type *table, int length, int reg, int def);
++
++int type2reg(struct match_reg_type *table, int length, int type, int def);
++
++int str2type(struct match_type_str *table, int length, const char *str,
++	     int size, int def);
++
++const char *type2str(struct match_type_str *table, int length, int type,
++		     const char *def);
++
++int match_reg_to_type(struct match_t *table, int nr_table, int reg, int def);
++
++int match_type_to_reg(struct match_t *table, int nr_table, int type, int def);
++
++int match_data_to_type(struct match_t *table, int nr_table, char *data,
++		int size, int def);
++
++void *match_type_to_data(struct match_t *table, int nr_table, int type,
++			 void *def);
++
++/*****************************************************************************/
++
++#endif /* End of __MATCH_TABLE_H__ */
+diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
+index 5b5c627..7a754d2 100644
+--- a/drivers/mtd/nand/nand_base.c
++++ b/drivers/mtd/nand/nand_base.c
+@@ -49,6 +49,8 @@
+ #include <linux/io.h>
+ #include <linux/mtd/partitions.h>
+ 
++#include "hinfc_gen.h"
++
+ /* Define default oob placement schemes for large and small page devices */
+ static struct nand_ecclayout nand_oob_8 = {
+ 	.eccbytes = 3,
+@@ -3570,7 +3572,7 @@ static void nand_decode_bbm_options(struct mtd_info *mtd,
+ 				 maf_id == NAND_MFR_HYNIX ||
+ 				 maf_id == NAND_MFR_TOSHIBA ||
+ 				 maf_id == NAND_MFR_AMD ||
+-				 maf_id == NAND_MFR_MACRONIX)) ||
++				 maf_id == NAND_MFR_MXIC)) ||
+ 			(mtd->writesize == 2048 &&
+ 			 maf_id == NAND_MFR_MICRON))
+ 		chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
+@@ -3589,7 +3591,13 @@ static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip,
+ 		mtd->erasesize = type->erasesize;
+ 		mtd->oobsize = type->oobsize;
+ 
++#ifdef CONFIG_HIFMC100_SPI_NAND
++		/* Hisilicon only support SLC spi nand devices */
++		chip->bits_per_cell = 1;
++#else
+ 		chip->bits_per_cell = nand_get_bits_per_cell(id_data[2]);
++#endif
++
+ 		chip->chipsize = (uint64_t)type->chipsize << 20;
+ 		chip->options |= type->options;
+ 		chip->ecc_strength_ds = NAND_ECC_STRENGTH(type);
+@@ -3615,7 +3623,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
+ 						  int *maf_id, int *dev_id,
+ 						  struct nand_flash_dev *type)
+ {
+-	int busw;
++	int busw = 0;
+ 	int i, maf_idx;
+ 	u8 id_data[8];
+ 
+@@ -3654,6 +3662,15 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
+ 		return ERR_PTR(-ENODEV);
+ 	}
+ 
++#ifdef CONFIG_HIFMC
++	if (get_spi_nand_flash_type_hook)
++		type = get_spi_nand_flash_type_hook(mtd, id_data);
++#else
++	type = hinfc_get_flash_type(mtd, chip, id_data, &busw);
++	if (type)
++		goto ident_done;
++#endif
++
+ 	if (!type)
+ 		type = nand_flash_ids;
+ 
+@@ -3704,6 +3721,9 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
+ 	if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize)
+ 		chip->options &= ~NAND_SAMSUNG_LP_OPTIONS;
+ ident_done:
++#if defined(CONFIG_HIFMC) || defined(CONFIG_MTD_NAND_HINFC610)
++	hinfc_nand_param_adjust(mtd, chip);
++#endif
+ 
+ 	/* Try to identify manufacturer */
+ 	for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_idx++) {
+@@ -3765,9 +3785,13 @@ ident_done:
+ 		pr_info("%s %s\n", nand_manuf_ids[maf_idx].name,
+ 				type->name);
+ 
+-	pr_info("%dMiB, %s, page size: %d, OOB size: %d\n",
++	pr_info("%dMiB, %s, page size: %d\n",
+ 		(int)(chip->chipsize >> 20), nand_is_slc(chip) ? "SLC" : "MLC",
+-		mtd->writesize, mtd->oobsize);
++		mtd->writesize);
++
++	/* Print ecc type and ecc mode about hisilicon flash controller */
++	hinfc_show_info(mtd, nand_manuf_ids[maf_idx].name, type->name);
++
+ 	return type;
+ }
+ 
+@@ -4047,7 +4071,7 @@ int nand_scan_tail(struct mtd_info *mtd)
+ 		break;
+ 
+ 	case NAND_ECC_NONE:
+-		pr_warn("NAND_ECC_NONE selected by board driver. This is not recommended!\n");
++		pr_warn(" ECC provided by Flash Memory Controller\n");
+ 		ecc->read_page = nand_read_page_raw;
+ 		ecc->write_page = nand_write_page_raw;
+ 		ecc->read_oob = nand_read_oob_std;
+diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c
+index fbde891..59b1fba 100644
+--- a/drivers/mtd/nand/nand_ids.c
++++ b/drivers/mtd/nand/nand_ids.c
+@@ -165,19 +165,25 @@ struct nand_flash_dev nand_flash_ids[] = {
+ 
+ /* Manufacturer IDs */
+ struct nand_manufacturers nand_manuf_ids[] = {
+-	{NAND_MFR_TOSHIBA, "Toshiba"},
+-	{NAND_MFR_SAMSUNG, "Samsung"},
+-	{NAND_MFR_FUJITSU, "Fujitsu"},
+-	{NAND_MFR_NATIONAL, "National"},
+-	{NAND_MFR_RENESAS, "Renesas"},
+-	{NAND_MFR_STMICRO, "ST Micro"},
+-	{NAND_MFR_HYNIX, "Hynix"},
+-	{NAND_MFR_MICRON, "Micron"},
+-	{NAND_MFR_AMD, "AMD/Spansion"},
+-	{NAND_MFR_MACRONIX, "Macronix"},
+-	{NAND_MFR_EON, "Eon"},
++	{NAND_MFR_TOSHIBA,	"Toshiba"},
++	{NAND_MFR_SAMSUNG,	"Samsung"},
++	{NAND_MFR_FUJITSU,	"Fujitsu"},
++	{NAND_MFR_NATIONAL,	"National"},
++	{NAND_MFR_RENESAS,	"Renesas"},
++	{NAND_MFR_ST_MICRO,	"ST/Micro"},
++	{NAND_MFR_HYNIX,	"Hynix"},
++	{NAND_MFR_MICRON,	"Micron"},
++	{NAND_MFR_AMD,		"AMD/Spansion"},
++	{NAND_MFR_GD_ESMT,	"GD/ESMT"},
++	{NAND_MFR_EON,		"Eon"},
++	{NAND_MFR_WINBOND,	"Winbond"},
++	{NAND_MFR_ATO,		"ATO"},
++	{NAND_MFR_MXIC,		"MXIC"},
++	{NAND_MFR_ALL_FLASH,	"All-flash"},
++	{NAND_MFR_PARAGON,	"Paragon"},
+ 	{NAND_MFR_SANDISK, "SanDisk"},
+ 	{NAND_MFR_INTEL, "Intel"},
++	{NAND_MFR_HEYANGTEK, "HeYangTek"},
+ 	{0x0, "Unknown"}
+ };
+ 
+diff --git a/drivers/mtd/spi-nor/Kconfig b/drivers/mtd/spi-nor/Kconfig
+index 64a4f0e..3d8abfc 100644
+--- a/drivers/mtd/spi-nor/Kconfig
++++ b/drivers/mtd/spi-nor/Kconfig
+@@ -23,9 +23,35 @@ config MTD_SPI_NOR_USE_4K_SECTORS
+ 
+ config SPI_FSL_QUADSPI
+ 	tristate "Freescale Quad SPI controller"
+-	depends on ARCH_MXC
++	depends on ARCH_MXC || COMPILE_TEST
++	depends on HAS_IOMEM
+ 	help
+ 	  This enables support for the Quad SPI controller in master mode.
+-	  We only connect the NOR to this controller now.
++	  This controller does not support generic SPI. It only supports
++	  SPI NOR.
++
++config SPI_HISI_SFC
++	tristate "Hisilicon SPI-NOR Flash Controller(SFC)"
++	depends on ARCH_HISI
++	help
++	  This enables support for hisilicon SPI-NOR flash controller.
++
++config CLOSE_SPI_8PIN_4IO
++	bool "Hisilicon close SPI device Quad SPI mode for some 8PIN chip"
++	default y if ARCH_HISI
++	help
++	  SFC support Quad SPI mode and Quad&addr SPI mode.
++	  But some 8PIN chip does not support this mode when HOLD/IO3 PIN was
++	  used by reset operation. Usually, your should not config this option.
++
++config HISI_SPI_BLOCK_PROTECT
++	bool "Hisilicon Spi Nor Device BP(Block Protect) Support"
++	default y if ARCH_HISI
++	help
++	  HISI SFC supports BP(Block Protect) feature to preestablish a series
++	  area to avoid writing and erasing, except to reading. With this macro
++	  definition we can get the BP info which was setted before. The
++	  BOTTOM/TOP bit is setted to BOTTOM, it means the lock area starts
++	  from 0 address.
+ 
+ endif # MTD_SPI_NOR
+diff --git a/drivers/mtd/spi-nor/Makefile b/drivers/mtd/spi-nor/Makefile
+index 6a7ce14..4544966 100644
+--- a/drivers/mtd/spi-nor/Makefile
++++ b/drivers/mtd/spi-nor/Makefile
+@@ -1,2 +1,3 @@
+ obj-$(CONFIG_MTD_SPI_NOR)	+= spi-nor.o
+ obj-$(CONFIG_SPI_FSL_QUADSPI)	+= fsl-quadspi.o
++obj-$(CONFIG_SPI_HISI_SFC)	+= hisi-sfc.o
+diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c
+index d5269a2..df8d001 100644
+--- a/drivers/mtd/spi-nor/fsl-quadspi.c
++++ b/drivers/mtd/spi-nor/fsl-quadspi.c
+@@ -26,6 +26,21 @@
+ #include <linux/mtd/mtd.h>
+ #include <linux/mtd/partitions.h>
+ #include <linux/mtd/spi-nor.h>
++#include <linux/mutex.h>
++#include <linux/pm_qos.h>
++#include <linux/sizes.h>
++
++/* Controller needs driver to swap endian */
++#define QUADSPI_QUIRK_SWAP_ENDIAN	(1 << 0)
++/* Controller needs 4x internal clock */
++#define QUADSPI_QUIRK_4X_INT_CLK	(1 << 1)
++/*
++ * TKT253890, Controller needs driver to fill txfifo till 16 byte to
++ * trigger data transfer even though extern data will not transferred.
++ */
++#define QUADSPI_QUIRK_TKT253890		(1 << 2)
++/* Controller cannot wake up from wait mode, TKT245618 */
++#define QUADSPI_QUIRK_TKT245618         (1 << 3)
+ 
+ /* The registers */
+ #define QUADSPI_MCR			0x00
+@@ -57,7 +72,9 @@
+ 
+ #define QUADSPI_BUF3CR			0x1c
+ #define QUADSPI_BUF3CR_ALLMST_SHIFT	31
+-#define QUADSPI_BUF3CR_ALLMST		(1 << QUADSPI_BUF3CR_ALLMST_SHIFT)
++#define QUADSPI_BUF3CR_ALLMST_MASK	(1 << QUADSPI_BUF3CR_ALLMST_SHIFT)
++#define QUADSPI_BUF3CR_ADATSZ_SHIFT		8
++#define QUADSPI_BUF3CR_ADATSZ_MASK	(0xFF << QUADSPI_BUF3CR_ADATSZ_SHIFT)
+ 
+ #define QUADSPI_BFGENCR			0x20
+ #define QUADSPI_BFGENCR_PAR_EN_SHIFT	16
+@@ -138,15 +155,15 @@
+ #define LUT_MODE		4
+ #define LUT_MODE2		5
+ #define LUT_MODE4		6
+-#define LUT_READ		7
+-#define LUT_WRITE		8
++#define LUT_FSL_READ		7
++#define LUT_FSL_WRITE		8
+ #define LUT_JMP_ON_CS		9
+ #define LUT_ADDR_DDR		10
+ #define LUT_MODE_DDR		11
+ #define LUT_MODE2_DDR		12
+ #define LUT_MODE4_DDR		13
+-#define LUT_READ_DDR		14
+-#define LUT_WRITE_DDR		15
++#define LUT_FSL_READ_DDR		14
++#define LUT_FSL_WRITE_DDR		15
+ #define LUT_DATA_LEARN		16
+ 
+ /*
+@@ -189,36 +206,66 @@
+ #define SEQID_EN4B		10
+ #define SEQID_BRWR		11
+ 
++#define QUADSPI_MIN_IOMAP SZ_4M
++
+ enum fsl_qspi_devtype {
+ 	FSL_QUADSPI_VYBRID,
+ 	FSL_QUADSPI_IMX6SX,
++	FSL_QUADSPI_IMX7D,
++	FSL_QUADSPI_IMX6UL,
+ };
+ 
+ struct fsl_qspi_devtype_data {
+ 	enum fsl_qspi_devtype devtype;
+ 	int rxfifo;
+ 	int txfifo;
++	int ahb_buf_size;
++	int driver_data;
+ };
+ 
+ static struct fsl_qspi_devtype_data vybrid_data = {
+ 	.devtype = FSL_QUADSPI_VYBRID,
+ 	.rxfifo = 128,
+-	.txfifo = 64
++	.txfifo = 64,
++	.ahb_buf_size = 1024,
++	.driver_data = QUADSPI_QUIRK_SWAP_ENDIAN,
+ };
+ 
+ static struct fsl_qspi_devtype_data imx6sx_data = {
+ 	.devtype = FSL_QUADSPI_IMX6SX,
+ 	.rxfifo = 128,
+-	.txfifo = 512
++	.txfifo = 512,
++	.ahb_buf_size = 1024,
++	.driver_data = QUADSPI_QUIRK_4X_INT_CLK
++		       | QUADSPI_QUIRK_TKT245618,
++};
++
++static struct fsl_qspi_devtype_data imx7d_data = {
++	.devtype = FSL_QUADSPI_IMX7D,
++	.rxfifo = 512,
++	.txfifo = 512,
++	.ahb_buf_size = 1024,
++	.driver_data = QUADSPI_QUIRK_TKT253890
++		       | QUADSPI_QUIRK_4X_INT_CLK,
++};
++
++static struct fsl_qspi_devtype_data imx6ul_data = {
++	.devtype = FSL_QUADSPI_IMX6UL,
++	.rxfifo = 128,
++	.txfifo = 512,
++	.ahb_buf_size = 1024,
++	.driver_data = QUADSPI_QUIRK_TKT253890
++		       | QUADSPI_QUIRK_4X_INT_CLK,
+ };
+ 
+ #define FSL_QSPI_MAX_CHIP	4
+ struct fsl_qspi {
+-	struct mtd_info mtd[FSL_QSPI_MAX_CHIP];
+ 	struct spi_nor nor[FSL_QSPI_MAX_CHIP];
+ 	void __iomem *iobase;
+-	void __iomem *ahb_base; /* Used when read from AHB bus */
++	void __iomem *ahb_addr;
+ 	u32 memmap_phy;
++	u32 memmap_offs;
++	u32 memmap_len;
+ 	struct clk *clk, *clk_en;
+ 	struct device *dev;
+ 	struct completion c;
+@@ -227,16 +274,29 @@ struct fsl_qspi {
+ 	u32 nor_num;
+ 	u32 clk_rate;
+ 	unsigned int chip_base_addr; /* We may support two chips. */
++	bool has_second_chip;
++	struct mutex lock;
++	struct pm_qos_request pm_qos_req;
+ };
+ 
+-static inline int is_vybrid_qspi(struct fsl_qspi *q)
++static inline int needs_swap_endian(struct fsl_qspi *q)
+ {
+-	return q->devtype_data->devtype == FSL_QUADSPI_VYBRID;
++	return q->devtype_data->driver_data & QUADSPI_QUIRK_SWAP_ENDIAN;
+ }
+ 
+-static inline int is_imx6sx_qspi(struct fsl_qspi *q)
++static inline int needs_4x_clock(struct fsl_qspi *q)
+ {
+-	return q->devtype_data->devtype == FSL_QUADSPI_IMX6SX;
++	return q->devtype_data->driver_data & QUADSPI_QUIRK_4X_INT_CLK;
++}
++
++static inline int needs_fill_txfifo(struct fsl_qspi *q)
++{
++	return q->devtype_data->driver_data & QUADSPI_QUIRK_TKT253890;
++}
++
++static inline int needs_wakeup_wait_mode(struct fsl_qspi *q)
++{
++	return q->devtype_data->driver_data & QUADSPI_QUIRK_TKT245618;
+ }
+ 
+ /*
+@@ -245,7 +305,7 @@ static inline int is_imx6sx_qspi(struct fsl_qspi *q)
+  */
+ static inline u32 fsl_qspi_endian_xchg(struct fsl_qspi *q, u32 a)
+ {
+-	return is_vybrid_qspi(q) ? __swab32(a) : a;
++	return needs_swap_endian(q) ? __swab32(a) : a;
+ }
+ 
+ static inline void fsl_qspi_unlock_lut(struct fsl_qspi *q)
+@@ -306,7 +366,7 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q)
+ 
+ 	writel(LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen),
+ 			base + QUADSPI_LUT(lut_base));
+-	writel(LUT0(DUMMY, PAD1, dummy) | LUT1(READ, PAD4, rxfifo),
++	writel(LUT0(DUMMY, PAD1, dummy) | LUT1(FSL_READ, PAD4, rxfifo),
+ 			base + QUADSPI_LUT(lut_base + 1));
+ 
+ 	/* Write enable */
+@@ -327,24 +387,18 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q)
+ 
+ 	writel(LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen),
+ 			base + QUADSPI_LUT(lut_base));
+-	writel(LUT0(WRITE, PAD1, 0), base + QUADSPI_LUT(lut_base + 1));
++	writel(LUT0(FSL_WRITE, PAD1, 0), base + QUADSPI_LUT(lut_base + 1));
+ 
+ 	/* Read Status */
+ 	lut_base = SEQID_RDSR * 4;
+-	writel(LUT0(CMD, PAD1, SPINOR_OP_RDSR) | LUT1(READ, PAD1, 0x1),
++	writel(LUT0(CMD, PAD1, SPINOR_OP_RDSR) | LUT1(FSL_READ, PAD1, 0x1),
+ 			base + QUADSPI_LUT(lut_base));
+ 
+ 	/* Erase a sector */
+ 	lut_base = SEQID_SE * 4;
+ 
+-	if (q->nor_size <= SZ_16M) {
+-		cmd = SPINOR_OP_SE;
+-		addrlen = ADDR24BIT;
+-	} else {
+-		/* use the 4-byte address */
+-		cmd = SPINOR_OP_SE;
+-		addrlen = ADDR32BIT;
+-	}
++	cmd = q->nor[0].erase_opcode;
++	addrlen = q->nor_size <= SZ_16M ? ADDR24BIT : ADDR32BIT;
+ 
+ 	writel(LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen),
+ 			base + QUADSPI_LUT(lut_base));
+@@ -356,17 +410,17 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q)
+ 
+ 	/* READ ID */
+ 	lut_base = SEQID_RDID * 4;
+-	writel(LUT0(CMD, PAD1, SPINOR_OP_RDID) | LUT1(READ, PAD1, 0x8),
++	writel(LUT0(CMD, PAD1, SPINOR_OP_RDID) | LUT1(FSL_READ, PAD1, 0x8),
+ 			base + QUADSPI_LUT(lut_base));
+ 
+ 	/* Write Register */
+ 	lut_base = SEQID_WRSR * 4;
+-	writel(LUT0(CMD, PAD1, SPINOR_OP_WRSR) | LUT1(WRITE, PAD1, 0x2),
++	writel(LUT0(CMD, PAD1, SPINOR_OP_WRSR) | LUT1(FSL_WRITE, PAD1, 0x2),
+ 			base + QUADSPI_LUT(lut_base));
+ 
+ 	/* Read Configuration Register */
+ 	lut_base = SEQID_RDCR * 4;
+-	writel(LUT0(CMD, PAD1, SPINOR_OP_RDCR) | LUT1(READ, PAD1, 0x1),
++	writel(LUT0(CMD, PAD1, SPINOR_OP_RDCR) | LUT1(FSL_READ, PAD1, 0x1),
+ 			base + QUADSPI_LUT(lut_base));
+ 
+ 	/* Write disable */
+@@ -413,6 +467,8 @@ static int fsl_qspi_get_seqid(struct fsl_qspi *q, u8 cmd)
+ 	case SPINOR_OP_BRWR:
+ 		return SEQID_BRWR;
+ 	default:
++		if (cmd == q->nor[0].erase_opcode)
++			return SEQID_SE;
+ 		dev_err(q->dev, "Unsupported cmd 0x%.2x\n", cmd);
+ 		break;
+ 	}
+@@ -454,8 +510,7 @@ fsl_qspi_runcmd(struct fsl_qspi *q, u8 cmd, unsigned int addr, int len)
+ 	writel((seqid << QUADSPI_IPCR_SEQID_SHIFT) | len, base + QUADSPI_IPCR);
+ 
+ 	/* Wait for the interrupt. */
+-	err = wait_for_completion_timeout(&q->c, msecs_to_jiffies(1000));
+-	if (!err) {
++	if (!wait_for_completion_timeout(&q->c, msecs_to_jiffies(1000))) {
+ 		dev_err(q->dev,
+ 			"cmd 0x%.2x timeout, addr@%.8x, FR:0x%.8x, SR:0x%.8x\n",
+ 			cmd, addr, readl(base + QUADSPI_FR),
+@@ -532,7 +587,7 @@ static int fsl_qspi_nor_write(struct fsl_qspi *q, struct spi_nor *nor,
+ 
+ 	/* clear the TX FIFO. */
+ 	tmp = readl(q->iobase + QUADSPI_MCR);
+-	writel(tmp | QUADSPI_MCR_CLR_RXF_MASK, q->iobase + QUADSPI_MCR);
++	writel(tmp | QUADSPI_MCR_CLR_TXF_MASK, q->iobase + QUADSPI_MCR);
+ 
+ 	/* fill the TX data to the FIFO */
+ 	for (j = 0, i = ((count + 3) / 4); j < i; j++) {
+@@ -541,6 +596,11 @@ static int fsl_qspi_nor_write(struct fsl_qspi *q, struct spi_nor *nor,
+ 		txbuf++;
+ 	}
+ 
++	/* fill the TXFIFO upto 16 bytes for i.MX7d */
++	if (needs_fill_txfifo(q))
++		for (; i < 4; i++)
++			writel(tmp, q->iobase + QUADSPI_TBDR);
++
+ 	/* Trigger it */
+ 	ret = fsl_qspi_runcmd(q, opcode, to, count);
+ 
+@@ -583,7 +643,12 @@ static void fsl_qspi_init_abh_read(struct fsl_qspi *q)
+ 	writel(QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF0CR);
+ 	writel(QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF1CR);
+ 	writel(QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF2CR);
+-	writel(QUADSPI_BUF3CR_ALLMST, base + QUADSPI_BUF3CR);
++	/*
++	 * Set ADATSZ with the maximum AHB buffer size to improve the
++	 * read performance.
++	 */
++	writel(QUADSPI_BUF3CR_ALLMST_MASK | ((q->devtype_data->ahb_buf_size / 8)
++			<< QUADSPI_BUF3CR_ADATSZ_SHIFT), base + QUADSPI_BUF3CR);
+ 
+ 	/* We only use the buffer3 */
+ 	writel(0, base + QUADSPI_BUF0IND);
+@@ -596,6 +661,38 @@ static void fsl_qspi_init_abh_read(struct fsl_qspi *q)
+ 		q->iobase + QUADSPI_BFGENCR);
+ }
+ 
++/* This function was used to prepare and enable QSPI clock */
++static int fsl_qspi_clk_prep_enable(struct fsl_qspi *q)
++{
++	int ret;
++
++	ret = clk_prepare_enable(q->clk_en);
++	if (ret)
++		return ret;
++
++	ret = clk_prepare_enable(q->clk);
++	if (ret) {
++		clk_disable_unprepare(q->clk_en);
++		return ret;
++	}
++
++	if (needs_wakeup_wait_mode(q))
++		pm_qos_add_request(&q->pm_qos_req, PM_QOS_CPU_DMA_LATENCY, 0);
++
++	return 0;
++}
++
++/* This function was used to disable and unprepare QSPI clock */
++static void fsl_qspi_clk_disable_unprep(struct fsl_qspi *q)
++{
++	if (needs_wakeup_wait_mode(q))
++		pm_qos_remove_request(&q->pm_qos_req);
++
++	clk_disable_unprepare(q->clk);
++	clk_disable_unprepare(q->clk_en);
++
++}
++
+ /* We use this function to do some basic init for spi_nor_scan(). */
+ static int fsl_qspi_nor_setup(struct fsl_qspi *q)
+ {
+@@ -603,11 +700,23 @@ static int fsl_qspi_nor_setup(struct fsl_qspi *q)
+ 	u32 reg;
+ 	int ret;
+ 
+-	/* the default frequency, we will change it in the future.*/
++	/* disable and unprepare clock to avoid glitch pass to controller */
++	fsl_qspi_clk_disable_unprep(q);
++
++	/* the default frequency, we will change it in the future. */
+ 	ret = clk_set_rate(q->clk, 66000000);
+ 	if (ret)
+ 		return ret;
+ 
++	ret = fsl_qspi_clk_prep_enable(q);
++	if (ret)
++		return ret;
++
++	/* Reset the module */
++	writel(QUADSPI_MCR_SWRSTSD_MASK | QUADSPI_MCR_SWRSTHD_MASK,
++		base + QUADSPI_MCR);
++	udelay(1);
++
+ 	/* Init the LUT table. */
+ 	fsl_qspi_init_lut(q);
+ 
+@@ -625,6 +734,9 @@ static int fsl_qspi_nor_setup(struct fsl_qspi *q)
+ 	writel(QUADSPI_MCR_RESERVED_MASK | QUADSPI_MCR_END_CFG_MASK,
+ 			base + QUADSPI_MCR);
+ 
++	/* clear all interrupt status */
++	writel(0xffffffff, q->iobase + QUADSPI_FR);
++
+ 	/* enable the interrupt */
+ 	writel(QUADSPI_RSER_TFIE, q->iobase + QUADSPI_RSER);
+ 
+@@ -636,13 +748,20 @@ static int fsl_qspi_nor_setup_last(struct fsl_qspi *q)
+ 	unsigned long rate = q->clk_rate;
+ 	int ret;
+ 
+-	if (is_imx6sx_qspi(q))
++	if (needs_4x_clock(q))
+ 		rate *= 4;
+ 
++	/* disable and unprepare clock to avoid glitch pass to controller */
++	fsl_qspi_clk_disable_unprep(q);
++
+ 	ret = clk_set_rate(q->clk, rate);
+ 	if (ret)
+ 		return ret;
+ 
++	ret = fsl_qspi_clk_prep_enable(q);
++	if (ret)
++		return ret;
++
+ 	/* Init the LUT table again. */
+ 	fsl_qspi_init_lut(q);
+ 
+@@ -652,9 +771,11 @@ static int fsl_qspi_nor_setup_last(struct fsl_qspi *q)
+ 	return 0;
+ }
+ 
+-static struct of_device_id fsl_qspi_dt_ids[] = {
++static const struct of_device_id fsl_qspi_dt_ids[] = {
+ 	{ .compatible = "fsl,vf610-qspi", .data = (void *)&vybrid_data, },
+ 	{ .compatible = "fsl,imx6sx-qspi", .data = (void *)&imx6sx_data, },
++	{ .compatible = "fsl,imx7d-qspi", .data = (void *)&imx7d_data, },
++	{ .compatible = "fsl,imx6ul-qspi", .data = (void *)&imx6ul_data, },
+ 	{ /* sentinel */ }
+ };
+ MODULE_DEVICE_TABLE(of, fsl_qspi_dt_ids);
+@@ -677,8 +798,7 @@ static int fsl_qspi_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
+ 	return 0;
+ }
+ 
+-static int fsl_qspi_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len,
+-			int write_enable)
++static int fsl_qspi_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
+ {
+ 	struct fsl_qspi *q = nor->priv;
+ 	int ret;
+@@ -719,18 +839,45 @@ static int fsl_qspi_read(struct spi_nor *nor, loff_t from,
+ {
+ 	struct fsl_qspi *q = nor->priv;
+ 	u8 cmd = nor->read_opcode;
+-	int ret;
+ 
+-	dev_dbg(q->dev, "cmd [%x],read from (0x%p, 0x%.8x, 0x%.8x),len:%d\n",
+-		cmd, q->ahb_base, q->chip_base_addr, (unsigned int)from, len);
++	/* if necessary,ioremap buffer before AHB read, */
++	if (!q->ahb_addr) {
++		q->memmap_offs = q->chip_base_addr + from;
++		q->memmap_len =
++			len > QUADSPI_MIN_IOMAP ? len : QUADSPI_MIN_IOMAP;
++
++		q->ahb_addr = ioremap_nocache(
++				q->memmap_phy + q->memmap_offs,
++				q->memmap_len);
++		if (!q->ahb_addr) {
++			dev_err(q->dev, "ioremap failed\n");
++			return -ENOMEM;
++		}
++	/* ioremap if the data requested is out of range */
++	} else if (q->chip_base_addr + from < q->memmap_offs
++			|| q->chip_base_addr + from + len >
++			q->memmap_offs + q->memmap_len) {
++		iounmap(q->ahb_addr);
++
++		q->memmap_offs = q->chip_base_addr + from;
++		q->memmap_len =
++			len > QUADSPI_MIN_IOMAP ? len : QUADSPI_MIN_IOMAP;
++		q->ahb_addr = ioremap_nocache(
++				q->memmap_phy + q->memmap_offs,
++				q->memmap_len);
++		if (!q->ahb_addr) {
++			dev_err(q->dev, "ioremap failed\n");
++			return -ENOMEM;
++		}
++	}
+ 
+-	/* Wait until the previous command is finished. */
+-	ret = nor->wait_till_ready(nor);
+-	if (ret)
+-		return ret;
++	dev_dbg(q->dev, "cmd [%x],read from %p, len:%zd\n",
++		cmd, q->ahb_addr + q->chip_base_addr + from - q->memmap_offs,
++		len);
+ 
+ 	/* Read out the data directly from the AHB buffer.*/
+-	memcpy(buf, q->ahb_base + q->chip_base_addr + from, len);
++	memcpy(buf, q->ahb_addr + q->chip_base_addr + from - q->memmap_offs,
++		len);
+ 
+ 	*retlen += len;
+ 	return 0;
+@@ -742,17 +889,7 @@ static int fsl_qspi_erase(struct spi_nor *nor, loff_t offs)
+ 	int ret;
+ 
+ 	dev_dbg(nor->dev, "%dKiB at 0x%08x:0x%08x\n",
+-		nor->mtd->erasesize / 1024, q->chip_base_addr, (u32)offs);
+-
+-	/* Wait until finished previous write command. */
+-	ret = nor->wait_till_ready(nor);
+-	if (ret)
+-		return ret;
+-
+-	/* Send write enable, then erase commands. */
+-	ret = nor->write_reg(nor, SPINOR_OP_WREN, NULL, 0, 0);
+-	if (ret)
+-		return ret;
++		nor->mtd.erasesize / 1024, q->chip_base_addr, (u32)offs);
+ 
+ 	ret = fsl_qspi_runcmd(q, nor->erase_opcode, offs, 0);
+ 	if (ret)
+@@ -767,26 +904,26 @@ static int fsl_qspi_prep(struct spi_nor *nor, enum spi_nor_ops ops)
+ 	struct fsl_qspi *q = nor->priv;
+ 	int ret;
+ 
+-	ret = clk_enable(q->clk_en);
+-	if (ret)
+-		return ret;
++	mutex_lock(&q->lock);
+ 
+-	ret = clk_enable(q->clk);
+-	if (ret) {
+-		clk_disable(q->clk_en);
+-		return ret;
+-	}
++	ret = fsl_qspi_clk_prep_enable(q);
++	if (ret)
++		goto err_mutex;
+ 
+ 	fsl_qspi_set_base_addr(q, nor);
+ 	return 0;
++
++err_mutex:
++	mutex_unlock(&q->lock);
++	return ret;
+ }
+ 
+ static void fsl_qspi_unprep(struct spi_nor *nor, enum spi_nor_ops ops)
+ {
+ 	struct fsl_qspi *q = nor->priv;
+ 
+-	clk_disable(q->clk);
+-	clk_disable(q->clk_en);
++	fsl_qspi_clk_disable_unprep(q);
++	mutex_unlock(&q->lock);
+ }
+ 
+ static int fsl_qspi_probe(struct platform_device *pdev)
+@@ -799,7 +936,6 @@ static int fsl_qspi_probe(struct platform_device *pdev)
+ 	struct spi_nor *nor;
+ 	struct mtd_info *mtd;
+ 	int ret, i = 0;
+-	bool has_second_chip = false;
+ 	const struct of_device_id *of_id =
+ 			of_match_device(fsl_qspi_dt_ids, &pdev->dev);
+ 
+@@ -811,89 +947,76 @@ static int fsl_qspi_probe(struct platform_device *pdev)
+ 	if (!q->nor_num || q->nor_num > FSL_QSPI_MAX_CHIP)
+ 		return -ENODEV;
+ 
++	q->dev = dev;
++	q->devtype_data = (struct fsl_qspi_devtype_data *)of_id->data;
++	platform_set_drvdata(pdev, q);
++
+ 	/* find the resources */
+ 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "QuadSPI");
+ 	q->iobase = devm_ioremap_resource(dev, res);
+-	if (IS_ERR(q->iobase)) {
+-		ret = PTR_ERR(q->iobase);
+-		goto map_failed;
+-	}
++	if (IS_ERR(q->iobase))
++		return PTR_ERR(q->iobase);
+ 
+ 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ 					"QuadSPI-memory");
+-	q->ahb_base = devm_ioremap_resource(dev, res);
+-	if (IS_ERR(q->ahb_base)) {
+-		ret = PTR_ERR(q->ahb_base);
+-		goto map_failed;
++	if (!devm_request_mem_region(dev, res->start, resource_size(res),
++				     res->name)) {
++		dev_err(dev, "can't request region for resource %pR\n", res);
++		return -EBUSY;
+ 	}
++
+ 	q->memmap_phy = res->start;
+ 
+ 	/* find the clocks */
+ 	q->clk_en = devm_clk_get(dev, "qspi_en");
+-	if (IS_ERR(q->clk_en)) {
+-		ret = PTR_ERR(q->clk_en);
+-		goto map_failed;
+-	}
++	if (IS_ERR(q->clk_en))
++		return PTR_ERR(q->clk_en);
+ 
+ 	q->clk = devm_clk_get(dev, "qspi");
+-	if (IS_ERR(q->clk)) {
+-		ret = PTR_ERR(q->clk);
+-		goto map_failed;
+-	}
+-
+-	ret = clk_prepare_enable(q->clk_en);
+-	if (ret) {
+-		dev_err(dev, "can not enable the qspi_en clock\n");
+-		goto map_failed;
+-	}
++	if (IS_ERR(q->clk))
++		return PTR_ERR(q->clk);
+ 
+-	ret = clk_prepare_enable(q->clk);
++	ret = fsl_qspi_clk_prep_enable(q);
+ 	if (ret) {
+-		clk_disable_unprepare(q->clk_en);
+-		dev_err(dev, "can not enable the qspi clock\n");
+-		goto map_failed;
++		dev_err(dev, "can not enable the clock\n");
++		goto clk_failed;
+ 	}
+ 
+ 	/* find the irq */
+ 	ret = platform_get_irq(pdev, 0);
+ 	if (ret < 0) {
+-		dev_err(dev, "failed to get the irq\n");
++		dev_err(dev, "failed to get the irq: %d\n", ret);
+ 		goto irq_failed;
+ 	}
+ 
+ 	ret = devm_request_irq(dev, ret,
+ 			fsl_qspi_irq_handler, 0, pdev->name, q);
+ 	if (ret) {
+-		dev_err(dev, "failed to request irq.\n");
++		dev_err(dev, "failed to request irq: %d\n", ret);
+ 		goto irq_failed;
+ 	}
+ 
+-	q->dev = dev;
+-	q->devtype_data = (struct fsl_qspi_devtype_data *)of_id->data;
+-	platform_set_drvdata(pdev, q);
+-
+ 	ret = fsl_qspi_nor_setup(q);
+ 	if (ret)
+ 		goto irq_failed;
+ 
+ 	if (of_get_property(np, "fsl,qspi-has-second-chip", NULL))
+-		has_second_chip = true;
++		q->has_second_chip = true;
++
++	mutex_init(&q->lock);
+ 
+ 	/* iterate the subnodes. */
+ 	for_each_available_child_of_node(dev->of_node, np) {
+-		char modalias[40];
+-
+ 		/* skip the holes */
+-		if (!has_second_chip)
++		if (!q->has_second_chip)
+ 			i *= 2;
+ 
+ 		nor = &q->nor[i];
+-		mtd = &q->mtd[i];
++		mtd = &nor->mtd;
+ 
+-		nor->mtd = mtd;
+ 		nor->dev = dev;
++		nor->flash_node = np;
+ 		nor->priv = q;
+-		mtd->priv = nor;
+ 
+ 		/* fill the hooks */
+ 		nor->read_reg = fsl_qspi_read_reg;
+@@ -905,25 +1028,22 @@ static int fsl_qspi_probe(struct platform_device *pdev)
+ 		nor->prepare = fsl_qspi_prep;
+ 		nor->unprepare = fsl_qspi_unprep;
+ 
+-		if (of_modalias_node(np, modalias, sizeof(modalias)) < 0)
+-			goto map_failed;
+-
+ 		ret = of_property_read_u32(np, "spi-max-frequency",
+ 				&q->clk_rate);
+ 		if (ret < 0)
+-			goto map_failed;
++			goto mutex_failed;
+ 
+ 		/* set the chip address for READID */
+ 		fsl_qspi_set_base_addr(q, nor);
+ 
+-		ret = spi_nor_scan(nor, modalias, SPI_NOR_QUAD);
++		ret = spi_nor_scan(nor, NULL, SPI_NOR_QUAD);
+ 		if (ret)
+-			goto map_failed;
++			goto mutex_failed;
+ 
+ 		ppdata.of_node = np;
+ 		ret = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
+ 		if (ret)
+-			goto map_failed;
++			goto mutex_failed;
+ 
+ 		/* Set the correct NOR size now. */
+ 		if (q->nor_size == 0) {
+@@ -953,19 +1073,21 @@ static int fsl_qspi_probe(struct platform_device *pdev)
+ 	if (ret)
+ 		goto last_init_failed;
+ 
+-	clk_disable(q->clk);
+-	clk_disable(q->clk_en);
+-	dev_info(dev, "QuadSPI SPI NOR flash driver\n");
++	fsl_qspi_clk_disable_unprep(q);
+ 	return 0;
+ 
+ last_init_failed:
+-	for (i = 0; i < q->nor_num; i++)
+-		mtd_device_unregister(&q->mtd[i]);
+-
++	for (i = 0; i < q->nor_num; i++) {
++		/* skip the holes */
++		if (!q->has_second_chip)
++			i *= 2;
++		mtd_device_unregister(&q->nor[i].mtd);
++	}
++mutex_failed:
++	mutex_destroy(&q->lock);
+ irq_failed:
+-	clk_disable_unprepare(q->clk);
+-	clk_disable_unprepare(q->clk_en);
+-map_failed:
++	fsl_qspi_clk_disable_unprep(q);
++clk_failed:
+ 	dev_err(dev, "Freescale QuadSPI probe failed\n");
+ 	return ret;
+ }
+@@ -975,15 +1097,45 @@ static int fsl_qspi_remove(struct platform_device *pdev)
+ 	struct fsl_qspi *q = platform_get_drvdata(pdev);
+ 	int i;
+ 
+-	for (i = 0; i < q->nor_num; i++)
+-		mtd_device_unregister(&q->mtd[i]);
++	for (i = 0; i < q->nor_num; i++) {
++		/* skip the holes */
++		if (!q->has_second_chip)
++			i *= 2;
++		mtd_device_unregister(&q->nor[i].mtd);
++	}
+ 
+ 	/* disable the hardware */
+ 	writel(QUADSPI_MCR_MDIS_MASK, q->iobase + QUADSPI_MCR);
+ 	writel(0x0, q->iobase + QUADSPI_RSER);
+ 
+-	clk_unprepare(q->clk);
+-	clk_unprepare(q->clk_en);
++	mutex_destroy(&q->lock);
++
++	if (q->ahb_addr)
++		iounmap(q->ahb_addr);
++
++	return 0;
++}
++
++static int fsl_qspi_suspend(struct platform_device *pdev, pm_message_t state)
++{
++	return 0;
++}
++
++static int fsl_qspi_resume(struct platform_device *pdev)
++{
++	int ret;
++	struct fsl_qspi *q = platform_get_drvdata(pdev);
++
++	ret = fsl_qspi_clk_prep_enable(q);
++	if (ret)
++		return ret;
++
++	fsl_qspi_nor_setup(q);
++	fsl_qspi_set_map_addr(q);
++	fsl_qspi_nor_setup_last(q);
++
++	fsl_qspi_clk_disable_unprep(q);
++
+ 	return 0;
+ }
+ 
+@@ -991,11 +1143,12 @@ static struct platform_driver fsl_qspi_driver = {
+ 	.driver = {
+ 		.name	= "fsl-quadspi",
+ 		.bus	= &platform_bus_type,
+-		.owner	= THIS_MODULE,
+ 		.of_match_table = fsl_qspi_dt_ids,
+ 	},
+ 	.probe          = fsl_qspi_probe,
+ 	.remove		= fsl_qspi_remove,
++	.suspend	= fsl_qspi_suspend,
++	.resume		= fsl_qspi_resume,
+ };
+ module_platform_driver(fsl_qspi_driver);
+ 
+diff --git a/drivers/mtd/spi-nor/hisi-sfc.c b/drivers/mtd/spi-nor/hisi-sfc.c
+new file mode 100644
+index 0000000..d09e27a
+--- /dev/null
++++ b/drivers/mtd/spi-nor/hisi-sfc.c
+@@ -0,0 +1,588 @@
++/*
++ * HiSilicon SPI Nor Flash Controller Driver
++ *
++ * Copyright (c) 2015-2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ */
++#include <linux/slab.h>
++#include <linux/module.h>
++#include <linux/clk.h>
++#include <linux/dma-mapping.h>
++#include <linux/mtd/mtd.h>
++#include <linux/of_address.h>
++#include <linux/of_platform.h>
++#include <linux/mtd/spi-nor.h>
++#include <mach/platform.h>
++#include <linux/mfd/hisi_fmc.h>
++
++#include "../mtdcore.h"
++
++#define FMC_OP_DMA			0x68
++
++struct hifmc_priv {
++	u32 chipselect;
++	u32 clkrate;
++	struct hifmc_host *host;
++};
++
++struct hifmc_host {
++	struct device *dev;
++	struct mutex *lock;
++
++	void __iomem *regbase;
++	void __iomem *iobase;
++	struct clk *clk;
++	void *buffer;
++	dma_addr_t dma_buffer;
++
++	struct spi_nor	*nor[HIFMC_MAX_CHIP_NUM];
++	struct hifmc_priv priv[HIFMC_MAX_CHIP_NUM];
++	int num_chip;
++};
++
++/******************************************************************************/
++static inline int wait_op_finish(struct hifmc_host *host)
++{
++	unsigned int reg, timeout = FMC_WAIT_TIMEOUT;
++
++	do {
++		reg = hifmc_readl(host, FMC_INT);
++	} while (!(reg & FMC_INT_OP_DONE) && --timeout);
++
++	if (!timeout) {
++		dev_dbg(host->dev, "wait for operation finish timeout\n");
++		return -EAGAIN;
++	}
++
++	return 0;
++}
++
++static int get_if_type(enum spi_nor_protocol mode)
++{
++	enum hifmc_iftype if_type;
++
++	switch (mode) {
++	case SNOR_PROTO_1_1_2:
++		if_type = IF_TYPE_DUAL;
++		break;
++	case SNOR_PROTO_1_2_2:
++		if_type = IF_TYPE_DIO;
++		break;
++	case SNOR_PROTO_1_1_4:
++		if_type = IF_TYPE_QUAD;
++		break;
++	case SNOR_PROTO_1_4_4:
++		if_type = IF_TYPE_QIO;
++		break;
++	case SNOR_PROTO_1_1_1:
++	default:
++		if_type = IF_TYPE_STD;
++		break;
++	}
++
++	return if_type;
++}
++
++/******************************************************************************/
++static void spi_nor_switch_spi_type(struct hifmc_host *host)
++{
++	unsigned int reg;
++
++	reg = hifmc_readl(host, FMC_CFG);
++	reg &= ~FLASH_TYPE_SEL_MASK;
++	reg |= FMC_CFG_FLASH_SEL(0);
++	hifmc_writel(host, FMC_CFG, reg);
++}
++
++/******************************************************************************/
++static void hisi_spi_nor_init(struct hifmc_host *host)
++{
++	unsigned int reg;
++
++	/* switch the flash type to spi nor */
++	spi_nor_switch_spi_type(host);
++
++	/* set the boot mode to normal */
++	reg = hifmc_readl(host, FMC_CFG);
++	if ((reg & FMC_CFG_OP_MODE_MASK) == FMC_CFG_OP_MODE_BOOT) {
++		reg |= FMC_CFG_OP_MODE(FMC_CFG_OP_MODE_NORMAL);
++		hifmc_writel(host, FMC_CFG, reg);
++	}
++
++	/* set timming */
++	reg = TIMING_CFG_TCSH(CS_HOLD_TIME)
++		| TIMING_CFG_TCSS(CS_SETUP_TIME)
++		| TIMING_CFG_TSHSL(CS_DESELECT_TIME);
++	hifmc_writel(host, FMC_SPI_TIMING_CFG, reg);
++}
++
++/******************************************************************************/
++static int hisi_spi_nor_prep(struct spi_nor *nor, enum spi_nor_ops ops)
++{
++	int ret;
++	u32 clkrate;
++	struct hifmc_priv *priv = nor->priv;
++	struct hifmc_host *host = priv->host;
++
++	mutex_lock(&fmc_switch_mutex);
++	mutex_lock(host->lock);
++
++	ret = clk_prepare_enable(host->clk);
++	if (ret)
++		goto out;
++
++	clkrate = min_t(u32, priv->clkrate, nor->clkrate);
++	ret = clk_set_rate(host->clk, clkrate);
++	if (ret)
++		goto out;
++
++	spi_nor_switch_spi_type(host);
++
++	return 0;
++
++out:
++	mutex_unlock(host->lock);
++	return ret;
++}
++
++/******************************************************************************/
++static void hisi_spi_nor_unprep(struct spi_nor *nor, enum spi_nor_ops ops)
++{
++	struct hifmc_priv *priv = nor->priv;
++	struct hifmc_host *host = priv->host;
++
++	clk_disable_unprepare(host->clk);
++	mutex_unlock(host->lock);
++	mutex_unlock(&fmc_switch_mutex);
++}
++
++/******************************************************************************/
++static int hisi_spi_nor_op_reg(struct spi_nor *nor, u8 opcode, int len, u8 optype)
++{
++	struct hifmc_priv *priv = nor->priv;
++	struct hifmc_host *host = priv->host;
++	u32 reg;
++
++	reg = FMC_CMD_CMD1(opcode);
++	hifmc_writel(host, FMC_CMD, reg);
++
++	reg = FMC_DATA_NUM_CNT(len);
++	hifmc_writel(host, FMC_DATA_NUM, reg);
++
++	reg = OP_CFG_FM_CS(priv->chipselect);
++	hifmc_writel(host, FMC_OP_CFG, reg);
++
++	hifmc_writel(host, FMC_INT_CLR, 0xff);
++	reg = FMC_OP_CMD1_EN;
++	if (optype == FMC_OP_READ)
++		reg |= FMC_OP_READ_DATA_EN;
++	else
++		reg |= FMC_OP_WRITE_DATA_EN;
++	reg |= FMC_OP_REG_OP_START;
++	hifmc_writel(host, FMC_OP, reg);
++
++	return wait_op_finish(host);
++}
++
++/******************************************************************************/
++static int hisi_spi_nor_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf,
++		int len)
++{
++	struct hifmc_priv *priv = nor->priv;
++	struct hifmc_host *host = priv->host;
++	int ret;
++
++	ret = hisi_spi_nor_op_reg(nor, opcode, len, FMC_OP_READ);
++	if (ret)
++		return ret;
++
++	memcpy_fromio(buf, host->iobase, len);
++	return 0;
++}
++
++/******************************************************************************/
++static int hisi_spi_nor_write_reg(struct spi_nor *nor, u8 opcode,
++				u8 *buf, int len)
++{
++	struct hifmc_priv *priv = nor->priv;
++	struct hifmc_host *host = priv->host;
++
++	if (len)
++		memcpy_toio(host->iobase, buf, len);
++
++	return hisi_spi_nor_op_reg(nor, opcode, len, FMC_OP_WRITE);
++}
++
++/******************************************************************************/
++static int hisi_spi_nor_dma_transfer(struct spi_nor *nor, loff_t start_off,
++		dma_addr_t dma_buf, size_t len, u8 op_type)
++{
++	struct hifmc_priv *priv = nor->priv;
++	struct hifmc_host *host = priv->host;
++	u8 if_type = 0, dummy = 0;
++	u32 reg;
++
++	reg = hifmc_readl(host, FMC_CFG);
++	reg &= ~SPI_NOR_ADDR_MODE_MASK;
++	if (nor->addr_width == 4)
++		reg |= SPI_NOR_ADDR_MODE_4BYTES;
++	else
++		reg |= SPI_NOR_ADDR_MODE_3BYTES;
++	hifmc_writel(host, FMC_CFG, reg);
++	hifmc_writel(host, FMC_ADDRL, start_off);
++	hifmc_writel(host, FMC_DMA_SADDR_D0, dma_buf);
++	hifmc_writel(host, FMC_DMA_LEN, FMC_DMA_LEN_SET(len));
++
++	reg = OP_CFG_FM_CS(priv->chipselect);
++	if (op_type == FMC_OP_READ) {
++		if_type = get_if_type(nor->read_proto);
++		dummy = nor->read_dummy >> 3;
++	} else {
++		if_type = get_if_type(nor->write_proto);
++	}
++	reg |= OP_CFG_MEM_IF_TYPE(if_type)
++		| OP_CFG_DUMMY_NUM(dummy);
++	hifmc_writel(host, FMC_OP_CFG, reg);
++
++	hifmc_writel(host, FMC_INT_CLR, 0xff);
++	reg = OP_CTRL_RW_OP(op_type) | OP_CTRL_DMA_OP_READY;
++	if (op_type == FMC_OP_READ)
++		reg |= OP_CTRL_RD_OPCODE(nor->read_opcode);
++	else
++		reg |= OP_CTRL_WR_OPCODE(nor->program_opcode);
++	hifmc_writel(host, FMC_OP_DMA, reg);
++
++	return wait_op_finish(host);
++}
++
++/******************************************************************************/
++static int hisi_spi_nor_read(struct spi_nor *nor, loff_t from, size_t len,
++		size_t *retlen, u_char *read_buf)
++{
++	struct hifmc_priv *priv = nor->priv;
++	struct hifmc_host *host = priv->host;
++	size_t offset;
++	int ret;
++
++	for (offset = 0; offset < len; offset += HIFMC_DMA_MAX_LEN) {
++		size_t trans = min_t(size_t, HIFMC_DMA_MAX_LEN, len - offset);
++
++		ret = hisi_spi_nor_dma_transfer(nor, from + offset,
++				host->dma_buffer, trans, FMC_OP_READ);
++		if (ret) {
++			dev_warn(nor->dev, "DMA read timeout\n");
++			return ret;
++		}
++		memcpy(read_buf + offset, host->buffer, trans);
++		*retlen += trans;
++	}
++
++	return 0;
++}
++/******************************************************************************/
++static void hisi_spi_nor_write(struct spi_nor *nor, loff_t to,
++			size_t len, size_t *retlen, const u_char *write_buf)
++{
++	struct hifmc_priv *priv = nor->priv;
++	struct hifmc_host *host = priv->host;
++	int ret;
++
++	memcpy(host->buffer, write_buf, len);
++	ret = hisi_spi_nor_dma_transfer(nor, to, host->dma_buffer,
++			len, FMC_OP_WRITE);
++	if (ret) {
++		dev_warn(nor->dev, "DMA write timeout\n");
++		return;
++	}
++	*retlen += len;
++}
++
++/**
++ * parse partitions info and register spi flash device as mtd device.
++ */
++static int hisi_snor_device_register(struct mtd_info *mtd)
++{
++	int nr_parts = 0;
++	struct mtd_partition *parts = NULL;
++	static const char *part_probes[] = {"cmdlinepart", NULL, };
++
++	/* We do not add the whole spi flash as a mtdblock device,
++	 * To avoid the number of nand partition +1.
++	 */
++	nr_parts = parse_mtd_partitions(mtd, part_probes, &parts, 0);
++
++	return nr_parts ? mtd_device_register(mtd, parts, nr_parts) : nr_parts;
++}
++
++/**
++ * Get spi flash device information and register it as a mtd device.
++ */
++static int hisi_spi_nor_register(struct device_node *np,
++				struct hifmc_host *host)
++{
++	struct device *dev = host->dev;
++	struct spi_nor *nor;
++	struct hifmc_priv *priv = &host->priv[host->num_chip];
++	struct mtd_info *mtd;
++	int ret;
++	struct spi_nor_modes modes = {
++		.rd_modes = SNOR_MODE_SLOW,
++		.wr_modes = SNOR_MODE_1_1_1,
++	};
++
++	nor = devm_kzalloc(dev, sizeof(*nor), GFP_KERNEL);
++	if (!nor)
++		return -ENOMEM;
++
++	nor->dev = dev;
++	nor->flash_node = np;
++
++	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
++	if (!priv)
++		return -ENOMEM;
++
++	ret = of_property_read_u32(np, "reg", &priv->chipselect);
++	if (ret) {
++		dev_err(dev, "There's no reg property for %s\n",
++			np->full_name);
++		return ret;
++	}
++
++	if (priv->chipselect != host->num_chip) {
++		dev_warn(dev, " The CS: %d states in device trees isn't real " \
++				"chipselect on board\n, using CS: %d instead. ",
++				priv->chipselect, host->num_chip);
++		priv->chipselect = host->num_chip;
++	}
++
++	ret = of_property_read_u32(np, "spi-max-frequency",
++			&priv->clkrate);
++	if (ret) {
++		dev_err(dev, "There's no spi-max-frequency property for %s\n",
++			np->full_name);
++		return ret;
++	}
++	priv->host = host;
++	nor->priv = priv;
++
++	nor->prepare = hisi_spi_nor_prep;
++	nor->unprepare = hisi_spi_nor_unprep;
++	nor->read_reg = hisi_spi_nor_read_reg;
++	nor->write_reg = hisi_spi_nor_write_reg;
++	nor->read = hisi_spi_nor_read;
++	nor->write = hisi_spi_nor_write;
++
++	modes.rd_modes |= SNOR_MODE_1_1_1
++			| SNOR_MODE_1_1_2
++			| SNOR_MODE_1_2_2;
++#ifndef CONFIG_CLOSE_SPI_8PIN_4IO
++	modes.rd_modes |= SNOR_MODE_1_1_4 | SNOR_MODE_1_4_4;
++	modes.wr_modes |= SNOR_MODE_1_1_4 | SNOR_MODE_1_4_4;
++#endif
++	ret = spi_nor_scan(nor, NULL, &modes);
++	if (ret)
++		return ret;
++
++	mtd = &nor->mtd;
++	mtd->name = np->name;
++	ret = hisi_snor_device_register(mtd);
++	if (ret)
++		return ret;
++
++	/* current chipselect has scanned, to detect next chipselect */
++	hifmc_cs_user[host->num_chip]++;
++	host->nor[host->num_chip] = nor;
++	host->num_chip++;
++	return 0;
++}
++
++static void hisi_spi_nor_unregister_all(struct hifmc_host *host)
++{
++	int i;
++
++	for (i = 0; i < host->num_chip; i++)
++		mtd_device_unregister(&host->nor[i]->mtd);
++}
++
++static int hisi_spi_nor_register_all(struct hifmc_host *host)
++{
++	struct device *dev = host->dev;
++	struct device_node *np = NULL;
++	int ret;
++
++	for_each_available_child_of_node(dev->of_node, np) {
++		if (hifmc_cs_user[host->num_chip]) {
++			dev_warn(dev, "Current CS(%d) is occupied.\n",
++					host->num_chip);
++			continue;
++		}
++		ret = hisi_spi_nor_register(np, host);
++		if (ret)
++			goto fail;
++
++		if (host->num_chip == HIFMC_MAX_CHIP_NUM) {
++			dev_warn(dev, "Flash device number exceeds the "
++					"maximum chipselect number\n");
++			break;
++		}
++	}
++
++	return 0;
++
++fail:
++	hisi_spi_nor_unregister_all(host);
++	return ret;
++}
++
++/******************************************************************************/
++static int hisi_spi_nor_probe(struct platform_device *pdev)
++{
++	struct device *dev = &pdev->dev;
++	struct hisi_fmc *fmc = dev_get_drvdata(dev->parent);
++	struct hifmc_host *host;
++	int ret;
++
++	host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
++	if (!host)
++		return -ENOMEM;
++
++	platform_set_drvdata(pdev, host);
++	host->dev = dev;
++
++	host->regbase = fmc->regbase;
++	host->iobase = fmc->iobase;
++	host->clk = fmc->clk;
++	host->lock = &fmc->lock;
++
++	host->buffer = dmam_alloc_coherent(dev, HIFMC_DMA_MAX_LEN,
++			&host->dma_buffer, GFP_KERNEL);
++	if (!host->buffer)
++		return -ENOMEM;
++
++	clk_prepare_enable(host->clk);
++	hisi_spi_nor_init(host);
++	ret = hisi_spi_nor_register_all(host);
++	if (ret)
++		dev_warn(dev, "spi nor register fail!\n");
++
++	clk_disable_unprepare(host->clk);
++
++	return ret;
++}
++
++/******************************************************************************/
++static int hisi_spi_nor_remove(struct platform_device *pdev)
++{
++	struct hifmc_host *host = platform_get_drvdata(pdev);
++
++	hisi_spi_nor_unregister_all(host);
++	clk_disable_unprepare(host->clk);
++	return 0;
++}
++
++/******************************************************************************/
++static void hisi_spi_nor_driver_shutdown(struct platform_device *pdev)
++{
++	int i;
++	struct hifmc_host *host = platform_get_drvdata(pdev);
++
++	if (!host)
++		return;
++
++	mutex_lock(host->lock);
++	clk_prepare_enable(host->clk);
++
++	spi_nor_switch_spi_type(host);
++	for (i = 0; i < host->num_chip; i++)
++		spi_nor_driver_shutdown(host->nor[i]);
++
++	clk_disable_unprepare(host->clk);
++	mutex_unlock(host->lock);
++	dev_dbg(host->dev, "End of driver shutdown\n");
++}
++
++#ifdef CONFIG_PM
++/******************************************************************************/
++static int hisi_spi_nor_driver_suspend(struct platform_device *pdev,
++		pm_message_t state)
++{
++	int i;
++	struct hifmc_host *host = platform_get_drvdata(pdev);
++
++	if (!host)
++		return 0;
++
++	mutex_lock(host->lock);
++	clk_prepare_enable(host->clk);
++
++	spi_nor_switch_spi_type(host);
++	for (i = 0; i < host->num_chip; i++)
++		spi_nor_suspend(host->nor[i], state);
++
++	clk_disable_unprepare(host->clk);
++	mutex_unlock(host->lock);
++	dev_dbg(host->dev, "End of suspend\n");
++
++	return 0;
++}
++
++/******************************************************************************/
++static int hisi_spi_nor_driver_resume(struct platform_device *pdev)
++{
++	int i;
++	struct hifmc_host *host = platform_get_drvdata(pdev);
++
++	if (!host)
++		return 0;
++
++	mutex_lock(host->lock);
++	clk_prepare_enable(host->clk);
++
++	spi_nor_switch_spi_type(host);
++	for (i = 0; i < host->num_chip; i++)
++		spi_nor_resume(host->nor[i]);
++
++	mutex_unlock(host->lock);
++	dev_dbg(host->dev, "End of resume\n");
++
++	return 0;
++}
++#endif /* End of CONFIG_PM */
++
++/******************************************************************************/
++static const struct of_device_id hisi_spi_nor_dt_ids[] = {
++	{ .compatible = "hisilicon,hisi-sfc"},
++	{ /* sentinel */ }
++};
++MODULE_DEVICE_TABLE(of, hisi_spi_nor_dt_ids);
++
++/******************************************************************************/
++static struct platform_driver hisi_spi_nor_driver = {
++	.driver = {
++		.name	= "hisi-sfc",
++		.of_match_table = hisi_spi_nor_dt_ids,
++	},
++	.probe		= hisi_spi_nor_probe,
++	.remove		= hisi_spi_nor_remove,
++	.shutdown	= hisi_spi_nor_driver_shutdown,
++#ifdef CONFIG_PM
++	.suspend	= hisi_spi_nor_driver_suspend,
++	.resume		= hisi_spi_nor_driver_resume,
++#endif
++};
++module_platform_driver(hisi_spi_nor_driver);
++
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("HiSilicon SPI Nor Flash Controller Driver");
+diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
+index c51ee52..208e2a3 100644
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -16,19 +16,77 @@
+ #include <linux/device.h>
+ #include <linux/mutex.h>
+ #include <linux/math64.h>
++#include <linux/sizes.h>
+ 
+-#include <linux/mtd/cfi.h>
+ #include <linux/mtd/mtd.h>
+ #include <linux/of_platform.h>
+ #include <linux/spi/flash.h>
+ #include <linux/mtd/spi-nor.h>
+ 
+ /* Define max times to check status register before we give up. */
+-#define	MAX_READY_WAIT_JIFFIES	(40 * HZ) /* M25P16 specs 40s max chip erase */
+ 
+-#define JEDEC_MFR(_jedec_id)	((_jedec_id) >> 16)
++/*
++ * For everything but full-chip erase; probably could be much smaller, but kept
++ * around for safety for now
++ */
++#define DEFAULT_READY_WAIT_JIFFIES		(40UL * HZ)
++
++/*
++ * For full-chip erase, calibrated to a 2MB flash (M25P16); should be scaled up
++ * for larger flash
++ */
++#define CHIP_ERASE_2MB_READY_WAIT_JIFFIES	(40UL * HZ)
++
++#define SPI_NOR_MAX_ID_LEN	6
++#define SPI_NOR_MAX_ADDR_WIDTH	4
++
++struct flash_info {
++	char		*name;
++
++	/*
++	 * This array stores the ID bytes.
++	 * The first three bytes are the JEDIC ID.
++	 * JEDEC ID zero means "no ID" (mostly older chips).
++	 */
++	u8		id[SPI_NOR_MAX_ID_LEN];
++	u8		id_len;
++
++	/* The size listed here is what works with SPINOR_OP_SE, which isn't
++	 * necessarily called a "sector" by the vendor.
++	 */
++	unsigned	sector_size;
++	u16		n_sectors;
++
++	u16		page_size;
++	u16		addr_width;
++
++	u16		flags;
++#define SECT_4K			BIT(0)	/* SPINOR_OP_BE_4K works uniformly */
++#define SPI_NOR_NO_ERASE	BIT(1)	/* No erase command needed */
++#define SST_WRITE		BIT(2)	/* use SST byte programming */
++#define SPI_NOR_NO_FR		BIT(3)	/* Can't do fastread */
++#define SECT_4K_PMC		BIT(4)	/* SPINOR_OP_BE_4K_PMC works uniformly*/
++#define SPI_NOR_DUAL_READ	BIT(5)	/* Flash supports Dual Read */
++#define SPI_NOR_QUAD_READ	BIT(6)	/* Flash supports Quad Read */
++#define USE_FSR			BIT(7)	/* use flag status register */
++#define SPI_NOR_HAS_LOCK	BIT(8)	/* Flash supports lock/unlock via SR */
++#define SPI_NOR_HAS_TB		BIT(9)	/*
++					 * Flash SR has Top/Bottom (TB) protect
++					 * bit. Must be used with
++					 * SPI_NOR_HAS_LOCK.
++					 */
++#define SPI_NOR_4B_OPCODES	BIT(10)	/*
++					 * Use dedicated 4byte address op codes
++					 * to support memory size above 128Mib.
++					 */
++
++	const struct spi_nor_basic_flash_parameter *params;
++	u32 clkrate;
++};
++
++#define JEDEC_MFR(info)	((info)->id[0])
+ 
+-static const struct spi_device_id *spi_nor_match_id(const char *name);
++static const struct flash_info *spi_nor_match_id(const char *name);
+ 
+ /*
+  * Read the status register, returning its value in the location
+@@ -88,31 +146,13 @@ static int read_cr(struct spi_nor *nor)
+ }
+ 
+ /*
+- * Dummy Cycle calculation for different type of read.
+- * It can be used to support more commands with
+- * different dummy cycle requirements.
+- */
+-static inline int spi_nor_read_dummy_cycles(struct spi_nor *nor)
+-{
+-	switch (nor->flash_read) {
+-	case SPI_NOR_FAST:
+-	case SPI_NOR_DUAL:
+-	case SPI_NOR_QUAD:
+-		return 1;
+-	case SPI_NOR_NORMAL:
+-		return 0;
+-	}
+-	return 0;
+-}
+-
+-/*
+  * Write status register 1 byte
+  * Returns negative if error occurred.
+  */
+ static inline int write_sr(struct spi_nor *nor, u8 val)
+ {
+ 	nor->cmd_buf[0] = val;
+-	return nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 1, 0);
++	return nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 1);
+ }
+ 
+ /*
+@@ -121,7 +161,7 @@ static inline int write_sr(struct spi_nor *nor, u8 val)
+  */
+ static inline int write_enable(struct spi_nor *nor)
+ {
+-	return nor->write_reg(nor, SPINOR_OP_WREN, NULL, 0, 0);
++	return nor->write_reg(nor, SPINOR_OP_WREN, NULL, 0);
+ }
+ 
+ /*
+@@ -129,7 +169,7 @@ static inline int write_enable(struct spi_nor *nor)
+  */
+ static inline int write_disable(struct spi_nor *nor)
+ {
+-	return nor->write_reg(nor, SPINOR_OP_WRDI, NULL, 0, 0);
++	return nor->write_reg(nor, SPINOR_OP_WRDI, NULL, 0);
+ }
+ 
+ static inline struct spi_nor *mtd_to_spi_nor(struct mtd_info *mtd)
+@@ -137,88 +177,186 @@ static inline struct spi_nor *mtd_to_spi_nor(struct mtd_info *mtd)
+ 	return mtd->priv;
+ }
+ 
++struct spi_nor_address_entry {
++	u8	src_opcode;
++	u8	dst_opcode;
++};
++
++static u8 spi_nor_convert_opcode(u8 opcode,
++				 const struct spi_nor_address_entry *entries,
++				 size_t num_entries)
++{
++	int min, max;
++
++	min = 0;
++	max = num_entries - 1;
++	while (min <= max) {
++		int mid = (min + max) >> 1;
++		const struct spi_nor_address_entry *entry = &entries[mid];
++
++		if (opcode == entry->src_opcode)
++			return entry->dst_opcode;
++
++		if (opcode < entry->src_opcode)
++			max = mid - 1;
++		else
++			min = mid + 1;
++	}
++
++	/* No conversion found */
++	return opcode;
++}
++
++static u8 spi_nor_3to4_opcode(u8 opcode)
++{
++	/* MUST be sorted by 3byte opcode */
++#define ENTRY_3TO4(_opcode)	{ _opcode, _opcode##_4B }
++	static const struct spi_nor_address_entry spi_nor_3to4_table[] = {
++		ENTRY_3TO4(SPINOR_OP_PP),		/* 0x02 */
++		ENTRY_3TO4(SPINOR_OP_READ),		/* 0x03 */
++		ENTRY_3TO4(SPINOR_OP_READ_FAST),	/* 0x0b */
++		ENTRY_3TO4(SPINOR_OP_BE_4K),		/* 0x20 */
++		ENTRY_3TO4(SPINOR_OP_PP_1_1_4),		/* 0x32 */
++		ENTRY_3TO4(SPINOR_OP_PP_1_4_4),		/* 0x38 */
++		ENTRY_3TO4(SPINOR_OP_READ_1_1_2),	/* 0x3b */
++		ENTRY_3TO4(SPINOR_OP_BE_32K),		/* 0x52 */
++		ENTRY_3TO4(SPINOR_OP_READ_1_1_4),	/* 0x6b */
++		ENTRY_3TO4(SPINOR_OP_READ_1_2_2),	/* 0xbb */
++		ENTRY_3TO4(SPINOR_OP_SE),		/* 0xd8 */
++		ENTRY_3TO4(SPINOR_OP_READ_1_4_4),	/* 0xeb */
++	};
++#undef ENTRY_3TO4
++
++	return spi_nor_convert_opcode(opcode, spi_nor_3to4_table,
++				      ARRAY_SIZE(spi_nor_3to4_table));
++}
++
++static void spi_nor_set_4byte_opcodes(struct spi_nor *nor,
++				      const struct flash_info *info)
++{
++	/* Do some manufacturer fixups first */
++	switch (JEDEC_MFR(info)) {
++	case SNOR_MFR_SPANSION:
++		/* No small sector erase for 4-byte command set */
++		nor->erase_opcode = SPINOR_OP_SE;
++		nor->mtd.erasesize = info->sector_size;
++		break;
++
++	default:
++		break;
++	}
++
++	nor->read_opcode	= spi_nor_3to4_opcode(nor->read_opcode);
++	nor->program_opcode	= spi_nor_3to4_opcode(nor->program_opcode);
++	nor->erase_opcode	= spi_nor_3to4_opcode(nor->erase_opcode);
++}
++
+ /* Enable/disable 4-byte addressing mode. */
+-static inline int set_4byte(struct spi_nor *nor, u32 jedec_id, int enable)
++static inline int set_4byte(struct spi_nor *nor, const struct flash_info *info,
++			    int enable)
+ {
+ 	int status;
+ 	bool need_wren = false;
+ 	u8 cmd;
+ 
+-	switch (JEDEC_MFR(jedec_id)) {
+-	case CFI_MFR_ST: /* Micron, actually */
++	switch (JEDEC_MFR(info)) {
++	case SNOR_MFR_MICRON:
+ 		/* Some Micron need WREN command; all will accept it */
+ 		need_wren = true;
+-	case CFI_MFR_MACRONIX:
+-	case 0xEF /* winbond */:
++	case SNOR_MFR_MACRONIX:
+ 		if (need_wren)
+ 			write_enable(nor);
+ 
+ 		cmd = enable ? SPINOR_OP_EN4B : SPINOR_OP_EX4B;
+-		status = nor->write_reg(nor, cmd, NULL, 0, 0);
++		status = nor->write_reg(nor, cmd, NULL, 0);
++
+ 		if (need_wren)
+ 			write_disable(nor);
+ 
+ 		return status;
++	case SNOR_MFR_WINBOND:
++		if (enable)
++			return nor->write_reg(nor, SPINOR_OP_EN4B, NULL, 0);
++		else {
++			/* w25q256fvfg must send reset to disable 4 byte mode */
++			nor->write_reg(nor, SPINOR_ENABLE_RESET, NULL, 0);
++			nor->write_reg(nor, SPINOR_OP_RESET, NULL, 0);
++			udelay(30);
++		}
++		return 0;
+ 	default:
+ 		/* Spansion style */
+ 		nor->cmd_buf[0] = enable << 7;
+-		return nor->write_reg(nor, SPINOR_OP_BRWR, nor->cmd_buf, 1, 0);
++		return nor->write_reg(nor, SPINOR_OP_BRWR, nor->cmd_buf, 1);
+ 	}
+ }
+-
+-static int spi_nor_wait_till_ready(struct spi_nor *nor)
++static inline int spi_nor_sr_ready(struct spi_nor *nor)
+ {
+-	unsigned long deadline;
+-	int sr;
++	int sr = read_sr(nor);
+ 
+-	deadline = jiffies + MAX_READY_WAIT_JIFFIES;
++	if (sr < 0)
++		return sr;
++	else
++		return !(sr & SR_WIP);
++}
+ 
+-	do {
+-		cond_resched();
++static inline int spi_nor_fsr_ready(struct spi_nor *nor)
++{
++	int fsr = read_fsr(nor);
+ 
+-		sr = read_sr(nor);
+-		if (sr < 0)
+-			break;
+-		else if (!(sr & SR_WIP))
+-			return 0;
+-	} while (!time_after_eq(jiffies, deadline));
++	if (fsr < 0)
++		return fsr;
++	else
++		return fsr & FSR_READY;
++}
+ 
+-	return -ETIMEDOUT;
++static int spi_nor_ready(struct spi_nor *nor)
++{
++	int sr, fsr;
++
++	sr = spi_nor_sr_ready(nor);
++	if (sr < 0)
++		return sr;
++	fsr = nor->flags & SNOR_F_USE_FSR ? spi_nor_fsr_ready(nor) : 1;
++	if (fsr < 0)
++		return fsr;
++	return sr && fsr;
+ }
+ 
+-static int spi_nor_wait_till_fsr_ready(struct spi_nor *nor)
++/*
++ * Service routine to read status register until ready, or timeout occurs.
++ * Returns non-zero if error.
++ */
++static int spi_nor_wait_till_ready_with_timeout(struct spi_nor *nor,
++						unsigned long timeout_jiffies)
+ {
+ 	unsigned long deadline;
+-	int sr;
+-	int fsr;
++	int timeout = 0, ret;
++
++	deadline = jiffies + timeout_jiffies;
+ 
+-	deadline = jiffies + MAX_READY_WAIT_JIFFIES;
++	while (!timeout) {
++		if (time_after_eq(jiffies, deadline))
++			timeout = 1;
++
++		ret = spi_nor_ready(nor);
++		if (ret < 0)
++			return ret;
++		if (ret)
++			return 0;
+ 
+-	do {
+ 		cond_resched();
++	}
+ 
+-		sr = read_sr(nor);
+-		if (sr < 0) {
+-			break;
+-		} else if (!(sr & SR_WIP)) {
+-			fsr = read_fsr(nor);
+-			if (fsr < 0)
+-				break;
+-			if (fsr & FSR_READY)
+-				return 0;
+-		}
+-	} while (!time_after_eq(jiffies, deadline));
++	dev_err(nor->dev, "flash operation timed out\n");
+ 
+ 	return -ETIMEDOUT;
+ }
+ 
+-/*
+- * Service routine to read status register until ready, or timeout occurs.
+- * Returns non-zero if error.
+- */
+-static int wait_till_ready(struct spi_nor *nor)
++static int spi_nor_wait_till_ready(struct spi_nor *nor)
+ {
+-	return nor->wait_till_ready(nor);
++	return spi_nor_wait_till_ready_with_timeout(nor,
++						    DEFAULT_READY_WAIT_JIFFIES);
+ }
+ 
+ /*
+@@ -228,19 +366,9 @@ static int wait_till_ready(struct spi_nor *nor)
+  */
+ static int erase_chip(struct spi_nor *nor)
+ {
+-	int ret;
+-
+-	dev_dbg(nor->dev, " %lldKiB\n", (long long)(nor->mtd->size >> 10));
+-
+-	/* Wait until finished previous write command. */
+-	ret = wait_till_ready(nor);
+-	if (ret)
+-		return ret;
+-
+-	/* Send write enable, then erase commands. */
+-	write_enable(nor);
++	dev_dbg(nor->dev, " %lldKiB\n", (long long)(nor->mtd.size >> 10));
+ 
+-	return nor->write_reg(nor, SPINOR_OP_CHIP_ERASE, NULL, 0, 0);
++	return nor->write_reg(nor, SPINOR_OP_CHIP_ERASE, NULL, 0);
+ }
+ 
+ static int spi_nor_lock_and_prep(struct spi_nor *nor, enum spi_nor_ops ops)
+@@ -268,6 +396,29 @@ static void spi_nor_unlock_and_unprep(struct spi_nor *nor, enum spi_nor_ops ops)
+ }
+ 
+ /*
++ * Initiate the erasure of a single sector
++ */
++static int spi_nor_erase_sector(struct spi_nor *nor, u32 addr)
++{
++	u8 buf[SPI_NOR_MAX_ADDR_WIDTH];
++	int i;
++
++	if (nor->erase)
++		return nor->erase(nor, addr);
++
++	/*
++	 * Default implementation, if driver doesn't have a specialized HW
++	 * control
++	 */
++	for (i = nor->addr_width - 1; i >= 0; i--) {
++		buf[i] = addr & 0xff;
++		addr >>= 8;
++	}
++
++	return nor->write_reg(nor, nor->erase_opcode, buf, nor->addr_width);
++}
++
++/*
+  * Erase an address range on the nor chip.  The address range may extend
+  * one or more erase sectors.  Return an error is there is a problem erasing.
+  */
+@@ -292,13 +443,36 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
+ 	if (ret)
+ 		return ret;
+ 
++#ifdef CONFIG_HISI_SPI_BLOCK_PROTECT
++	if ((nor->level) && (addr < nor->end_addr)) {
++		dev_err(nor->dev, "Error: The erase area was locked\n");
++		return -EINVAL;
++	}
++#endif
+ 	/* whole-chip erase? */
+ 	if (len == mtd->size) {
++		unsigned long timeout;
++
++		write_enable(nor);
++
+ 		if (erase_chip(nor)) {
+ 			ret = -EIO;
+ 			goto erase_err;
+ 		}
+ 
++		/*
++		 * Scale the timeout linearly with the size of the flash, with
++		 * a minimum calibrated to an old 2MB flash. We could try to
++		 * pull these from CFI/SFDP, but these values should be good
++		 * enough for now.
++		 */
++		timeout = max(CHIP_ERASE_2MB_READY_WAIT_JIFFIES,
++			      CHIP_ERASE_2MB_READY_WAIT_JIFFIES *
++			      (unsigned long)(mtd->size / SZ_2M));
++		ret = spi_nor_wait_till_ready_with_timeout(nor, timeout);
++		if (ret)
++			goto erase_err;
++
+ 	/* REVISIT in some cases we could speed up erasing large regions
+ 	 * by using SPINOR_OP_SE instead of SPINOR_OP_BE_4K.  We may have set up
+ 	 * to use "small sector erase", but that's not always optimal.
+@@ -307,276 +481,827 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
+ 	/* "sector"-at-a-time erase */
+ 	} else {
+ 		while (len) {
+-			if (nor->erase(nor, addr)) {
+-				ret = -EIO;
++			write_enable(nor);
++
++			ret = spi_nor_erase_sector(nor, addr);
++			if (ret)
+ 				goto erase_err;
+-			}
+ 
+ 			addr += mtd->erasesize;
+ 			len -= mtd->erasesize;
++
++			ret = spi_nor_wait_till_ready(nor);
++			if (ret)
++				goto erase_err;
+ 		}
+ 	}
+ 
++	write_disable(nor);
++
++erase_err:
+ 	spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_ERASE);
+ 
+-	instr->state = MTD_ERASE_DONE;
++	instr->state = ret ? MTD_ERASE_FAILED : MTD_ERASE_DONE;
+ 	mtd_erase_callback(instr);
+ 
+ 	return ret;
+-
+-erase_err:
+-	spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_ERASE);
+-	instr->state = MTD_ERASE_FAILED;
+-	return ret;
+ }
+ 
+-static int spi_nor_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
++static void stm_get_locked_range(struct spi_nor *nor, u8 sr, loff_t *ofs,
++				 uint64_t *len)
+ {
+-	struct spi_nor *nor = mtd_to_spi_nor(mtd);
+-	uint32_t offset = ofs;
+-	uint8_t status_old, status_new;
+-	int ret = 0;
++	struct mtd_info *mtd = &nor->mtd;
++	u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
++	int shift = ffs(mask) - 1;
++	int pow;
++
++	if (!(sr & mask)) {
++		/* No protection */
++		*ofs = 0;
++		*len = 0;
++	} else {
++		pow = ((sr & mask) ^ mask) >> shift;
++		*len = mtd->size >> pow;
++		if (nor->flags & SNOR_F_HAS_SR_TB && sr & SR_TB)
++			*ofs = 0;
++		else
++			*ofs = mtd->size - *len;
++	}
++}
+ 
+-	ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_LOCK);
+-	if (ret)
+-		return ret;
++/*
++ * Return 1 if the entire region is locked (if @locked is true) or unlocked (if
++ * @locked is false); 0 otherwise
++ */
++static int stm_check_lock_status_sr(struct spi_nor *nor, loff_t ofs,
++		uint64_t len, u8 sr, bool locked)
++{
++	loff_t lock_offs;
++	uint64_t lock_len;
+ 
+-	/* Wait until finished previous command */
+-	ret = wait_till_ready(nor);
+-	if (ret)
+-		goto err;
++	if (!len)
++		return 1;
+ 
+-	status_old = read_sr(nor);
++	stm_get_locked_range(nor, sr, &lock_offs, &lock_len);
+ 
+-	if (offset < mtd->size - (mtd->size / 2))
+-		status_new = status_old | SR_BP2 | SR_BP1 | SR_BP0;
+-	else if (offset < mtd->size - (mtd->size / 4))
+-		status_new = (status_old & ~SR_BP0) | SR_BP2 | SR_BP1;
+-	else if (offset < mtd->size - (mtd->size / 8))
+-		status_new = (status_old & ~SR_BP1) | SR_BP2 | SR_BP0;
+-	else if (offset < mtd->size - (mtd->size / 16))
+-		status_new = (status_old & ~(SR_BP0 | SR_BP1)) | SR_BP2;
+-	else if (offset < mtd->size - (mtd->size / 32))
+-		status_new = (status_old & ~SR_BP2) | SR_BP1 | SR_BP0;
+-	else if (offset < mtd->size - (mtd->size / 64))
+-		status_new = (status_old & ~(SR_BP2 | SR_BP0)) | SR_BP1;
++	if (locked)
++		/* Requested range is a sub-range of locked range */
++		return (ofs + len <= lock_offs + lock_len)
++			&& (ofs >= lock_offs);
+ 	else
+-		status_new = (status_old & ~(SR_BP2 | SR_BP1)) | SR_BP0;
++		/* Requested range does not overlap with locked range */
++		return (ofs >= lock_offs + lock_len)
++			|| (ofs + len <= lock_offs);
++}
+ 
+-	/* Only modify protection if it will not unlock other areas */
+-	if ((status_new & (SR_BP2 | SR_BP1 | SR_BP0)) >
+-				(status_old & (SR_BP2 | SR_BP1 | SR_BP0))) {
+-		write_enable(nor);
+-		ret = write_sr(nor, status_new);
+-		if (ret)
+-			goto err;
+-	}
++static int stm_is_locked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
++			    u8 sr)
++{
++	return stm_check_lock_status_sr(nor, ofs, len, sr, true);
++}
+ 
+-err:
+-	spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_LOCK);
+-	return ret;
++static int stm_is_unlocked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
++			      u8 sr)
++{
++	return stm_check_lock_status_sr(nor, ofs, len, sr, false);
+ }
+ 
+-static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
++/*
++ * Lock a region of the flash. Compatible with ST Micro and similar flash.
++ * Supports the block protection bits BP{0,1,2} in the status register
++ * (SR). Does not support these features found in newer SR bitfields:
++ *   - SEC: sector/block protect - only handle SEC=0 (block protect)
++ *   - CMP: complement protect - only support CMP=0 (range is not complemented)
++ *
++ * Support for the following is provided conditionally for some flash:
++ *   - TB: top/bottom protect
++ *
++ * Sample table portion for 8MB flash (Winbond w25q64fw):
++ *
++ *   SEC  |  TB   |  BP2  |  BP1  |  BP0  |  Prot Length  | Protected Portion
++ *  --------------------------------------------------------------------------
++ *    X   |   X   |   0   |   0   |   0   |  NONE         | NONE
++ *    0   |   0   |   0   |   0   |   1   |  128 KB       | Upper 1/64
++ *    0   |   0   |   0   |   1   |   0   |  256 KB       | Upper 1/32
++ *    0   |   0   |   0   |   1   |   1   |  512 KB       | Upper 1/16
++ *    0   |   0   |   1   |   0   |   0   |  1 MB         | Upper 1/8
++ *    0   |   0   |   1   |   0   |   1   |  2 MB         | Upper 1/4
++ *    0   |   0   |   1   |   1   |   0   |  4 MB         | Upper 1/2
++ *    X   |   X   |   1   |   1   |   1   |  8 MB         | ALL
++ *  ------|-------|-------|-------|-------|---------------|-------------------
++ *    0   |   1   |   0   |   0   |   1   |  128 KB       | Lower 1/64
++ *    0   |   1   |   0   |   1   |   0   |  256 KB       | Lower 1/32
++ *    0   |   1   |   0   |   1   |   1   |  512 KB       | Lower 1/16
++ *    0   |   1   |   1   |   0   |   0   |  1 MB         | Lower 1/8
++ *    0   |   1   |   1   |   0   |   1   |  2 MB         | Lower 1/4
++ *    0   |   1   |   1   |   1   |   0   |  4 MB         | Lower 1/2
++ *
++ * Returns negative on errors, 0 on success.
++ */
++static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
+ {
+-	struct spi_nor *nor = mtd_to_spi_nor(mtd);
+-	uint32_t offset = ofs;
+-	uint8_t status_old, status_new;
+-	int ret = 0;
++	struct mtd_info *mtd = &nor->mtd;
++	int status_old, status_new;
++	u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
++	u8 shift = ffs(mask) - 1, pow, val;
++	loff_t lock_len;
++	bool can_be_top = true, can_be_bottom = nor->flags & SNOR_F_HAS_SR_TB;
++	bool use_top;
++	int ret;
+ 
+-	ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_UNLOCK);
+-	if (ret)
+-		return ret;
++	status_old = read_sr(nor);
++	if (status_old < 0)
++		return status_old;
+ 
+-	/* Wait until finished previous command */
+-	ret = wait_till_ready(nor);
+-	if (ret)
+-		goto err;
++	/* If nothing in our range is unlocked, we don't need to do anything */
++	if (stm_is_locked_sr(nor, ofs, len, status_old))
++		return 0;
+ 
+-	status_old = read_sr(nor);
++	/* If anything below us is unlocked, we can't use 'bottom' protection */
++	if (!stm_is_locked_sr(nor, 0, ofs, status_old))
++		can_be_bottom = false;
+ 
+-	if (offset+len > mtd->size - (mtd->size / 64))
+-		status_new = status_old & ~(SR_BP2 | SR_BP1 | SR_BP0);
+-	else if (offset+len > mtd->size - (mtd->size / 32))
+-		status_new = (status_old & ~(SR_BP2 | SR_BP1)) | SR_BP0;
+-	else if (offset+len > mtd->size - (mtd->size / 16))
+-		status_new = (status_old & ~(SR_BP2 | SR_BP0)) | SR_BP1;
+-	else if (offset+len > mtd->size - (mtd->size / 8))
+-		status_new = (status_old & ~SR_BP2) | SR_BP1 | SR_BP0;
+-	else if (offset+len > mtd->size - (mtd->size / 4))
+-		status_new = (status_old & ~(SR_BP0 | SR_BP1)) | SR_BP2;
+-	else if (offset+len > mtd->size - (mtd->size / 2))
+-		status_new = (status_old & ~SR_BP1) | SR_BP2 | SR_BP0;
+-	else
+-		status_new = (status_old & ~SR_BP0) | SR_BP2 | SR_BP1;
++	/* If anything above us is unlocked, we can't use 'top' protection */
++	if (!stm_is_locked_sr(nor, ofs + len, mtd->size - (ofs + len),
++				status_old))
++		can_be_top = false;
+ 
+-	/* Only modify protection if it will not lock other areas */
+-	if ((status_new & (SR_BP2 | SR_BP1 | SR_BP0)) <
+-				(status_old & (SR_BP2 | SR_BP1 | SR_BP0))) {
+-		write_enable(nor);
+-		ret = write_sr(nor, status_new);
+-		if (ret)
+-			goto err;
+-	}
++	if (!can_be_bottom && !can_be_top)
++		return -EINVAL;
+ 
+-err:
+-	spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_UNLOCK);
+-	return ret;
+-}
++	/* Prefer top, if both are valid */
++	use_top = can_be_top;
+ 
+-struct flash_info {
+-	/* JEDEC id zero means "no ID" (most older chips); otherwise it has
+-	 * a high byte of zero plus three data bytes: the manufacturer id,
+-	 * then a two byte device id.
+-	 */
+-	u32		jedec_id;
+-	u16             ext_id;
++	/* lock_len: length of region that should end up locked */
++	if (use_top)
++		lock_len = mtd->size - ofs;
++	else
++		lock_len = ofs + len;
+ 
+-	/* The size listed here is what works with SPINOR_OP_SE, which isn't
+-	 * necessarily called a "sector" by the vendor.
++	/*
++	 * Need smallest pow such that:
++	 *
++	 *   1 / (2^pow) <= (len / size)
++	 *
++	 * so (assuming power-of-2 size) we do:
++	 *
++	 *   pow = ceil(log2(size / len)) = log2(size) - floor(log2(len))
+ 	 */
+-	unsigned	sector_size;
+-	u16		n_sectors;
++	pow = ilog2(mtd->size) - ilog2(lock_len);
++	val = mask - (pow << shift);
++	if (val & ~mask)
++		return -EINVAL;
++	/* Don't "lock" with no region! */
++	if (!(val & mask))
++		return -EINVAL;
+ 
+-	u16		page_size;
+-	u16		addr_width;
++	status_new = (status_old & ~mask & ~SR_TB) | val;
+ 
+-	u16		flags;
+-#define	SECT_4K			0x01	/* SPINOR_OP_BE_4K works uniformly */
+-#define	SPI_NOR_NO_ERASE	0x02	/* No erase command needed */
+-#define	SST_WRITE		0x04	/* use SST byte programming */
+-#define	SPI_NOR_NO_FR		0x08	/* Can't do fastread */
+-#define	SECT_4K_PMC		0x10	/* SPINOR_OP_BE_4K_PMC works uniformly */
+-#define	SPI_NOR_DUAL_READ	0x20    /* Flash supports Dual Read */
+-#define	SPI_NOR_QUAD_READ	0x40    /* Flash supports Quad Read */
+-#define	USE_FSR			0x80	/* use flag status register */
+-};
++	/* Disallow further writes if WP pin is asserted */
++	status_new |= SR_SRWD;
+ 
+-#define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags)	\
+-	((kernel_ulong_t)&(struct flash_info) {				\
+-		.jedec_id = (_jedec_id),				\
+-		.ext_id = (_ext_id),					\
+-		.sector_size = (_sector_size),				\
+-		.n_sectors = (_n_sectors),				\
+-		.page_size = 256,					\
+-		.flags = (_flags),					\
+-	})
++	if (!use_top)
++		status_new |= SR_TB;
+ 
+-#define CAT25_INFO(_sector_size, _n_sectors, _page_size, _addr_width, _flags)	\
+-	((kernel_ulong_t)&(struct flash_info) {				\
+-		.sector_size = (_sector_size),				\
+-		.n_sectors = (_n_sectors),				\
+-		.page_size = (_page_size),				\
+-		.addr_width = (_addr_width),				\
+-		.flags = (_flags),					\
+-	})
++	/* Don't bother if they're the same */
++	if (status_new == status_old)
++		return 0;
+ 
+-/* NOTE: double check command sets and memory organization when you add
+- * more nor chips.  This current list focusses on newer chips, which
+- * have been converging on command sets which including JEDEC ID.
+- */
+-static const struct spi_device_id spi_nor_ids[] = {
+-	/* Atmel -- some are (confusingly) marketed as "DataFlash" */
+-	{ "at25fs010",  INFO(0x1f6601, 0, 32 * 1024,   4, SECT_4K) },
+-	{ "at25fs040",  INFO(0x1f6604, 0, 64 * 1024,   8, SECT_4K) },
++	/* Only modify protection if it will not unlock other areas */
++	if ((status_new & mask) < (status_old & mask))
++		return -EINVAL;
+ 
+-	{ "at25df041a", INFO(0x1f4401, 0, 64 * 1024,   8, SECT_4K) },
+-	{ "at25df321a", INFO(0x1f4701, 0, 64 * 1024,  64, SECT_4K) },
+-	{ "at25df641",  INFO(0x1f4800, 0, 64 * 1024, 128, SECT_4K) },
++	write_enable(nor);
++	ret = write_sr(nor, status_new);
++	if (ret)
++		return ret;
++	return spi_nor_wait_till_ready(nor);
++}
+ 
+-	{ "at26f004",   INFO(0x1f0400, 0, 64 * 1024,  8, SECT_4K) },
+-	{ "at26df081a", INFO(0x1f4501, 0, 64 * 1024, 16, SECT_4K) },
+-	{ "at26df161a", INFO(0x1f4601, 0, 64 * 1024, 32, SECT_4K) },
+-	{ "at26df321",  INFO(0x1f4700, 0, 64 * 1024, 64, SECT_4K) },
++/*
++ * Unlock a region of the flash. See stm_lock() for more info
++ *
++ * Returns negative on errors, 0 on success.
++ */
++static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
++{
++	struct mtd_info *mtd = &nor->mtd;
++	int status_old, status_new;
++	u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
++	u8 shift = ffs(mask) - 1, pow, val;
++	loff_t lock_len;
++	bool can_be_top = true, can_be_bottom = nor->flags & SNOR_F_HAS_SR_TB;
++	bool use_top;
++	int ret;
+ 
+-	{ "at45db081d", INFO(0x1f2500, 0, 64 * 1024, 16, SECT_4K) },
++	status_old = read_sr(nor);
++	if (status_old < 0)
++		return status_old;
+ 
+-	/* EON -- en25xxx */
+-	{ "en25f32",    INFO(0x1c3116, 0, 64 * 1024,   64, SECT_4K) },
+-	{ "en25p32",    INFO(0x1c2016, 0, 64 * 1024,   64, 0) },
+-	{ "en25q32b",   INFO(0x1c3016, 0, 64 * 1024,   64, 0) },
+-	{ "en25p64",    INFO(0x1c2017, 0, 64 * 1024,  128, 0) },
+-	{ "en25q64",    INFO(0x1c3017, 0, 64 * 1024,  128, SECT_4K) },
+-	{ "en25qh128",  INFO(0x1c7018, 0, 64 * 1024,  256, 0) },
+-	{ "en25qh256",  INFO(0x1c7019, 0, 64 * 1024,  512, 0) },
++	/* If nothing in our range is locked, we don't need to do anything */
++	if (stm_is_unlocked_sr(nor, ofs, len, status_old))
++		return 0;
+ 
+-	/* ESMT */
+-	{ "f25l32pa", INFO(0x8c2016, 0, 64 * 1024, 64, SECT_4K) },
++	/* If anything below us is locked, we can't use 'top' protection */
++	if (!stm_is_unlocked_sr(nor, 0, ofs, status_old))
++		can_be_top = false;
+ 
+-	/* Everspin */
+-	{ "mr25h256", CAT25_INFO( 32 * 1024, 1, 256, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
+-	{ "mr25h10",  CAT25_INFO(128 * 1024, 1, 256, 3, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
++	/* If anything above us is locked, we can't use 'bottom' protection */
++	if (!stm_is_unlocked_sr(nor, ofs + len, mtd->size - (ofs + len),
++				status_old))
++		can_be_bottom = false;
+ 
+-	/* GigaDevice */
+-	{ "gd25q32", INFO(0xc84016, 0, 64 * 1024,  64, SECT_4K) },
+-	{ "gd25q64", INFO(0xc84017, 0, 64 * 1024, 128, SECT_4K) },
++	if (!can_be_bottom && !can_be_top)
++		return -EINVAL;
+ 
+-	/* Intel/Numonyx -- xxxs33b */
+-	{ "160s33b",  INFO(0x898911, 0, 64 * 1024,  32, 0) },
+-	{ "320s33b",  INFO(0x898912, 0, 64 * 1024,  64, 0) },
+-	{ "640s33b",  INFO(0x898913, 0, 64 * 1024, 128, 0) },
++	/* Prefer top, if both are valid */
++	use_top = can_be_top;
+ 
+-	/* Macronix */
+-	{ "mx25l2005a",  INFO(0xc22012, 0, 64 * 1024,   4, SECT_4K) },
+-	{ "mx25l4005a",  INFO(0xc22013, 0, 64 * 1024,   8, SECT_4K) },
+-	{ "mx25l8005",   INFO(0xc22014, 0, 64 * 1024,  16, 0) },
+-	{ "mx25l1606e",  INFO(0xc22015, 0, 64 * 1024,  32, SECT_4K) },
+-	{ "mx25l3205d",  INFO(0xc22016, 0, 64 * 1024,  64, 0) },
+-	{ "mx25l3255e",  INFO(0xc29e16, 0, 64 * 1024,  64, SECT_4K) },
+-	{ "mx25l6405d",  INFO(0xc22017, 0, 64 * 1024, 128, 0) },
+-	{ "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) },
+-	{ "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) },
+-	{ "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) },
+-	{ "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) },
+-	{ "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_QUAD_READ) },
+-	{ "mx66l1g55g",  INFO(0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ) },
+-
+-	/* Micron */
+-	{ "n25q064",     INFO(0x20ba17, 0, 64 * 1024,  128, 0) },
+-	{ "n25q128a11",  INFO(0x20bb18, 0, 64 * 1024,  256, 0) },
+-	{ "n25q128a13",  INFO(0x20ba18, 0, 64 * 1024,  256, 0) },
+-	{ "n25q256a",    INFO(0x20ba19, 0, 64 * 1024,  512, SECT_4K) },
+-	{ "n25q512a",    INFO(0x20bb20, 0, 64 * 1024, 1024, SECT_4K) },
+-	{ "n25q512ax3",  INFO(0x20ba20, 0, 64 * 1024, 1024, USE_FSR) },
+-	{ "n25q00",      INFO(0x20ba21, 0, 64 * 1024, 2048, USE_FSR) },
++	/* lock_len: length of region that should remain locked */
++	if (use_top)
++		lock_len = mtd->size - (ofs + len);
++	else
++		lock_len = ofs;
+ 
+-	/* PMC */
+-	{ "pm25lv512",   INFO(0,        0, 32 * 1024,    2, SECT_4K_PMC) },
+-	{ "pm25lv010",   INFO(0,        0, 32 * 1024,    4, SECT_4K_PMC) },
+-	{ "pm25lq032",   INFO(0x7f9d46, 0, 64 * 1024,   64, SECT_4K) },
++	/*
++	 * Need largest pow such that:
++	 *
++	 *   1 / (2^pow) >= (len / size)
++	 *
++	 * so (assuming power-of-2 size) we do:
++	 *
++	 *   pow = floor(log2(size / len)) = log2(size) - ceil(log2(len))
++	 */
++	pow = ilog2(mtd->size) - order_base_2(lock_len);
++	if (lock_len == 0) {
++		val = 0; /* fully unlocked */
++	} else {
++		val = mask - (pow << shift);
++		/* Some power-of-two sizes are not supported */
++		if (val & ~mask)
++			return -EINVAL;
++	}
++
++	status_new = (status_old & ~mask & ~SR_TB) | val;
++
++	/* Don't protect status register if we're fully unlocked */
++	if (lock_len == mtd->size)
++		status_new &= ~SR_SRWD;
++
++	if (!use_top)
++		status_new |= SR_TB;
++
++	/* Don't bother if they're the same */
++	if (status_new == status_old)
++		return 0;
++
++	/* Only modify protection if it will not lock other areas */
++	if ((status_new & mask) > (status_old & mask))
++		return -EINVAL;
++
++	write_enable(nor);
++	ret = write_sr(nor, status_new);
++	if (ret)
++		return ret;
++	return spi_nor_wait_till_ready(nor);
++}
++
++/*
++ * Check if a region of the flash is (completely) locked. See stm_lock() for
++ * more info.
++ *
++ * Returns 1 if entire region is locked, 0 if any portion is unlocked, and
++ * negative on errors.
++ */
++static int stm_is_locked(struct spi_nor *nor, loff_t ofs, uint64_t len)
++{
++	int status;
++
++	status = read_sr(nor);
++	if (status < 0)
++		return status;
++
++	return stm_is_locked_sr(nor, ofs, len, status);
++}
++
++static int spi_nor_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
++{
++	struct spi_nor *nor = mtd_to_spi_nor(mtd);
++	int ret;
++
++	ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_LOCK);
++	if (ret)
++		return ret;
++
++	ret = nor->flash_lock(nor, ofs, len);
++
++	spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_UNLOCK);
++	return ret;
++}
++
++static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
++{
++	struct spi_nor *nor = mtd_to_spi_nor(mtd);
++	int ret;
++
++	ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_UNLOCK);
++	if (ret)
++		return ret;
++
++	ret = nor->flash_unlock(nor, ofs, len);
++
++	spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_LOCK);
++	return ret;
++}
++
++static int spi_nor_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len)
++{
++	struct spi_nor *nor = mtd_to_spi_nor(mtd);
++	int ret;
++
++	ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_UNLOCK);
++	if (ret)
++		return ret;
++
++	ret = nor->flash_is_locked(nor, ofs, len);
++
++	spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_LOCK);
++	return ret;
++}
++
++#define SNOR_RD_MODES			\
++	(SNOR_MODE_SLOW |			\
++	 SNOR_MODE_1_1_1 |			\
++	 SNOR_MODE_1_1_2 |			\
++	 SNOR_MODE_1_2_2 |			\
++	 SNOR_MODE_1_1_4 |			\
++	 SNOR_MODE_1_4_4)
++
++#define SNOR_WR_MODES			\
++	(SNOR_MODE_1_1_1 |			\
++	 SNOR_MODE_1_1_4)
++
++static int spansion_quad_enable(struct spi_nor *nor);
++static int macronix_quad_enable(struct spi_nor *nor);
++static int gd_quad_enable(struct spi_nor *nor);
++
++#define SNOR_EON_RD_MODES			\
++	(SNOR_MODE_SLOW |			\
++	 SNOR_MODE_1_1_1 |			\
++	 SNOR_MODE_1_1_2 |			\
++	 SNOR_MODE_1_2_2)
++
++#define SNOR_EON_WR_MODES			\
++	(SNOR_MODE_1_1_1)
++
++static const struct spi_nor_basic_flash_parameter eon_params = {
++	.rd_modes		= SNOR_EON_RD_MODES,
++	.reads[SNOR_MIDX_SLOW]	= SNOR_OP_READ(0, 0, SPINOR_OP_READ),
++	.reads[SNOR_MIDX_1_1_1]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_FAST),
++	.reads[SNOR_MIDX_1_1_2]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_2),
++	.reads[SNOR_MIDX_1_2_2]	= SNOR_OP_READ(8, 0, SPINOR_OP_READ_1_2_2),
++	.reads[SNOR_MIDX_1_1_4]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_4),
++	.reads[SNOR_MIDX_1_4_4]	= SNOR_OP_READ(8, 16, SPINOR_OP_READ_1_4_4),
++
++	.wr_modes		= SNOR_EON_WR_MODES,
++	.page_programs[SNOR_MIDX_1_1_1]	= SPINOR_OP_PP,
++
++	.erase_types[0]		= SNOR_OP_ERASE_64K(SPINOR_OP_SE),
++
++};
++
++static const struct spi_nor_basic_flash_parameter esmt_params = {
++	.rd_modes		= SNOR_RD_MODES,
++	.reads[SNOR_MIDX_SLOW]	= SNOR_OP_READ(0, 0, SPINOR_OP_READ),
++	.reads[SNOR_MIDX_1_1_1]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_FAST),
++	.reads[SNOR_MIDX_1_1_2]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_2),
++	.reads[SNOR_MIDX_1_2_2]	= SNOR_OP_READ(8, 0, SPINOR_OP_READ_1_2_2),
++	.reads[SNOR_MIDX_1_1_4]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_4),
++	.reads[SNOR_MIDX_1_4_4]	= SNOR_OP_READ(8, 16, SPINOR_OP_READ_1_4_4),
++
++	.wr_modes		= SNOR_WR_MODES,
++	.page_programs[SNOR_MIDX_1_1_1]	= SPINOR_OP_PP,
++	.page_programs[SNOR_MIDX_1_1_4]	= SPINOR_OP_PP_1_1_4,
++
++	.erase_types[0]		= SNOR_OP_ERASE_64K(SPINOR_OP_SE),
++
++	.enable_quad_io         = macronix_quad_enable,
++
++};
++
++#define SNOR_PARAGON_WR_MODES			\
++	(SNOR_MODE_1_1_1)
++
++static const struct spi_nor_basic_flash_parameter paragon_params = {
++	.rd_modes		= SNOR_RD_MODES,
++	.reads[SNOR_MIDX_SLOW]	= SNOR_OP_READ(0, 0, SPINOR_OP_READ),
++	.reads[SNOR_MIDX_1_1_1]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_FAST),
++	.reads[SNOR_MIDX_1_1_2]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_2),
++	.reads[SNOR_MIDX_1_2_2]	= SNOR_OP_READ(8, 0, SPINOR_OP_READ_1_2_2),
++	.reads[SNOR_MIDX_1_1_4]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_4),
++	.reads[SNOR_MIDX_1_4_4]	= SNOR_OP_READ(8, 16, SPINOR_OP_READ_1_4_4),
++
++	.wr_modes		= SNOR_PARAGON_WR_MODES,
++	.page_programs[SNOR_MIDX_1_1_1]	= SPINOR_OP_PP,
++
++	.erase_types[0]		= SNOR_OP_ERASE_64K(SPINOR_OP_SE),
++
++	.enable_quad_io         = spansion_quad_enable,
++
++};
++
++static const struct spi_nor_basic_flash_parameter gd_params = {
++	.rd_modes		= SNOR_RD_MODES,
++	.reads[SNOR_MIDX_SLOW]	= SNOR_OP_READ(0, 0, SPINOR_OP_READ),
++	.reads[SNOR_MIDX_1_1_1]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_FAST),
++	.reads[SNOR_MIDX_1_1_2]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_2),
++	.reads[SNOR_MIDX_1_2_2]	= SNOR_OP_READ(8, 0, SPINOR_OP_READ_1_2_2),
++	.reads[SNOR_MIDX_1_1_4]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_4),
++	.reads[SNOR_MIDX_1_4_4]	= SNOR_OP_READ(8, 16, SPINOR_OP_READ_1_4_4),
++
++	.wr_modes		= SNOR_WR_MODES,
++	.page_programs[SNOR_MIDX_1_1_1]	= SPINOR_OP_PP,
++	.page_programs[SNOR_MIDX_1_1_4]	= SPINOR_OP_PP_1_1_4,
++
++	.erase_types[0]		= SNOR_OP_ERASE_64K(SPINOR_OP_SE),
++
++	.enable_quad_io         = gd_quad_enable,
++
++};
++
++static const struct spi_nor_basic_flash_parameter winbond_params = {
++	.rd_modes		= SNOR_RD_MODES,
++	.reads[SNOR_MIDX_SLOW]	= SNOR_OP_READ(0, 0, SPINOR_OP_READ),
++	.reads[SNOR_MIDX_1_1_1]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_FAST),
++	.reads[SNOR_MIDX_1_1_2]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_2),
++	.reads[SNOR_MIDX_1_2_2]	= SNOR_OP_READ(8, 0, SPINOR_OP_READ_1_2_2),
++	.reads[SNOR_MIDX_1_1_4]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_4),
++	.reads[SNOR_MIDX_1_4_4]	= SNOR_OP_READ(8, 16, SPINOR_OP_READ_1_4_4),
++
++	.wr_modes		= SNOR_WR_MODES,
++	.page_programs[SNOR_MIDX_1_1_1]	= SPINOR_OP_PP,
++	.page_programs[SNOR_MIDX_1_1_4]	= SPINOR_OP_PP_1_1_4,
++
++	.erase_types[0]		= SNOR_OP_ERASE_64K(SPINOR_OP_SE),
++
++	.enable_quad_io         = spansion_quad_enable,
++
++};
++
++static const struct spi_nor_basic_flash_parameter spansion_params = {
++	.rd_modes		= SNOR_RD_MODES,
++	.reads[SNOR_MIDX_SLOW]	= SNOR_OP_READ(0, 0, SPINOR_OP_READ),
++	.reads[SNOR_MIDX_1_1_1]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_FAST),
++	.reads[SNOR_MIDX_1_1_2]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_2),
++	.reads[SNOR_MIDX_1_2_2]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_2_2),
++	.reads[SNOR_MIDX_1_1_4]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_4),
++	.reads[SNOR_MIDX_1_4_4]	= SNOR_OP_READ(8, 16, SPINOR_OP_READ_1_4_4),
++
++	.wr_modes		= SNOR_WR_MODES,
++	.page_programs[SNOR_MIDX_1_1_1]	= SPINOR_OP_PP,
++	.page_programs[SNOR_MIDX_1_1_4]	= SPINOR_OP_PP_1_1_4,
++
++	.erase_types[0]		= SNOR_OP_ERASE_64K(SPINOR_OP_SE),
++
++	.enable_quad_io         = spansion_quad_enable,
++
++};
++
++#define SNOR_MXIC_WR_MODES			\
++	(SNOR_MODE_1_1_1 |			\
++	 SNOR_MODE_1_4_4)
++
++static const struct spi_nor_basic_flash_parameter mxic_params = {
++	.rd_modes		= SNOR_RD_MODES,
++	.reads[SNOR_MIDX_SLOW]	= SNOR_OP_READ(0, 0, SPINOR_OP_READ),
++	.reads[SNOR_MIDX_1_1_1]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_FAST),
++	.reads[SNOR_MIDX_1_1_2]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_2),
++	.reads[SNOR_MIDX_1_2_2]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_2_2),
++	.reads[SNOR_MIDX_1_1_4]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_4),
++	.reads[SNOR_MIDX_1_4_4]	= SNOR_OP_READ(8, 16, SPINOR_OP_READ_1_4_4),
++
++	.wr_modes		= SNOR_MXIC_WR_MODES,
++	.page_programs[SNOR_MIDX_1_1_1]	= SPINOR_OP_PP,
++	.page_programs[SNOR_MIDX_1_4_4]	= SPINOR_OP_PP_1_4_4,
++
++	.erase_types[0]		= SNOR_OP_ERASE_64K(SPINOR_OP_SE),
++
++	.enable_quad_io         = macronix_quad_enable,
++
++};
++
++static const struct spi_nor_basic_flash_parameter micron_params = {
++	.rd_modes		= SNOR_RD_MODES,
++	.reads[SNOR_MIDX_SLOW]	= SNOR_OP_READ(0, 0, SPINOR_OP_READ),
++	.reads[SNOR_MIDX_1_1_1]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_FAST),
++	.reads[SNOR_MIDX_1_1_2]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_2),
++	.reads[SNOR_MIDX_1_2_2]	= SNOR_OP_READ(8, 8, SPINOR_OP_READ_1_2_2),
++	.reads[SNOR_MIDX_1_1_4]	= SNOR_OP_READ(1, 7, SPINOR_OP_READ_1_1_4),
++	.reads[SNOR_MIDX_1_4_4]	= SNOR_OP_READ(0, 40, SPINOR_OP_READ_1_4_4),
++
++	.wr_modes		= SNOR_WR_MODES,
++	.page_programs[SNOR_MIDX_1_1_1]	= SPINOR_OP_PP,
++	.page_programs[SNOR_MIDX_1_1_4]	= SPINOR_OP_PP_1_1_4,
++
++	.erase_types[0]		= SNOR_OP_ERASE_64K(SPINOR_OP_SE),
++
++};
++
++static const struct spi_nor_basic_flash_parameter micron_4k_params = {
++	.rd_modes		= SNOR_RD_MODES,
++	.reads[SNOR_MIDX_SLOW]	= SNOR_OP_READ(0, 0, SPINOR_OP_READ),
++	.reads[SNOR_MIDX_1_1_1]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_FAST),
++	.reads[SNOR_MIDX_1_1_2]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_2),
++	.reads[SNOR_MIDX_1_2_2]	= SNOR_OP_READ(1, 7, SPINOR_OP_READ_1_2_2),
++	.reads[SNOR_MIDX_1_1_4]	= SNOR_OP_READ(1, 7, SPINOR_OP_READ_1_1_4),
++	.reads[SNOR_MIDX_1_4_4]	= SNOR_OP_READ(1, 9, SPINOR_OP_READ_1_4_4),
++
++	.wr_modes		= SNOR_WR_MODES,
++	.page_programs[SNOR_MIDX_1_1_1]	= SPINOR_OP_PP,
++	.page_programs[SNOR_MIDX_1_1_4]	= SPINOR_OP_PP_1_1_4,
++
++	.erase_types[0]		= SNOR_OP_ERASE_64K(SPINOR_OP_SE),
++	.erase_types[1]		= SNOR_OP_ERASE_4K(SPINOR_OP_BE_4K),
++};
++
++#define PARAMS(_name) .params = &_name##_params
++
++/* Used when the "_ext_id" is two bytes at most */
++#define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags)	\
++		.id = {							\
++			((_jedec_id) >> 16) & 0xff,			\
++			((_jedec_id) >> 8) & 0xff,			\
++			(_jedec_id) & 0xff,				\
++			((_ext_id) >> 8) & 0xff,			\
++			(_ext_id) & 0xff,				\
++			},						\
++		.id_len = (!(_jedec_id) ? 0 : (3 + ((_ext_id) ? 2 : 0))), \
++		.sector_size = (_sector_size),				\
++		.n_sectors = (_n_sectors),				\
++		.page_size = 256,					\
++		.flags = (_flags)
++
++#define INFO6(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags)	\
++		.id = {							\
++			((_jedec_id) >> 16) & 0xff,			\
++			((_jedec_id) >> 8) & 0xff,			\
++			(_jedec_id) & 0xff,				\
++			((_ext_id) >> 16) & 0xff,			\
++			((_ext_id) >> 8) & 0xff,			\
++			(_ext_id) & 0xff,				\
++			},						\
++		.id_len = 6,						\
++		.sector_size = (_sector_size),				\
++		.n_sectors = (_n_sectors),				\
++		.page_size = 256,					\
++		.flags = (_flags),
++
++#define CAT25_INFO(_sector_size, _n_sectors, _page_size, _addr_width, _flags) \
++		.sector_size = (_sector_size),				\
++		.n_sectors = (_n_sectors),				\
++		.page_size = (_page_size),				\
++		.addr_width = (_addr_width),				\
++		.flags = (_flags),
++
++/* Different from spi-max-frequency in DTS, the clk here stands for the clock 
++ * rate on SPI interface, it is half of the FMC CRG configuration */
++#define CLK_MHZ_2X(clk)  .clkrate = (clk * 2000000),
++
++/* NOTE: double check command sets and memory organization when you add
++ * more nor chips.  This current list focusses on newer chips, which
++ * have been converging on command sets which including JEDEC ID.
++ *
++ * All newly added entries should describe *hardware* and should use SECT_4K
++ * (or SECT_4K_PMC) if hardware supports erasing 4 KiB sectors. For usage
++ * scenarios excluding small sectors there is config option that can be
++ * disabled: CONFIG_MTD_SPI_NOR_USE_4K_SECTORS.
++ * For historical (and compatibility) reasons (before we got above config) some
++ * old entries may be missing 4K flag.
++ */
++
++/******* SPI Nor ID Table **************************************************
++ * Version   Manufacturer    Chip Name    Chipsize	Block	Vol  Operation
++ * 1.0		Macronix/MXIC	MX25L1606E		2M		64K		3V3
++ *			Macronix/MXIC	MX25L6436F		8M		64K		3V3
++ *			Macronix/MXIC	MX25R6435F		8M		64K		1V8/3V3 Add 14chips
++ *			Macronix/MXIC	MX25U6435F		8M		64K		1V8
++ *			Macronix/MXIC	MX25U12835F		16M		64K     1V8
++ *			Macronix/MXIC	MX25F128XXX		16M		64K     3V3
++ *			Macronix/MXIC	MX25U25635F/45G	32M		64K		1V8 25645G-DTR
++ *			Macronix/MXIC	MX25L(256/257)	32M     64K     3V3	25645G-DTR
++ *			Spansion		S25FL129P1		16M     64K		3V3
++ *			Spansion		S25FL256S		32M     64K		3V3
++ *			Micron			N25Q064A		8M      64K     3V3
++ *			Micron			N25QL064A		8M      64K     3V3
++ *			Micron	N25Q128A11/MT25QU128AB  16M     64K     1V8
++ *			Micron			N25QL128A		16M     64K     3V3
++ *			Micron			MT25QU256A		32M     64K     1V8
++ *			Micron			MT25Q256A		32M     64K     3V3
++ *			Winbond	W25Q16(B/C)V/S25FL016K	2M		64K     3V3
++ *			Winbond			W25Q32(B/F)V	4M		64K     3V3
++ *			Winbond			W25Q32FW		4M		64K     1V8
++ *			Winbond			W25Q64FW		8M		64K     1V8
++ *			Winbond			W25Q64FV		8M		64K     3V3
++ *			Winbond			W25Q128FW		16M     64K     1V8
++ *			Winbond			W25Q128(B/F)V	16M     64K     3V3
++ *			Winbond			W25Q128JV		16M     64K     3V3  DTR
++ *			ESMT/CFEON		EN25Q32B		4M      64K     3V3
++ *			ESMT/CFEON		EN25Q64			8M      64K     3V3
++ *			ESMT/CFEON		EN25Q128		16M     64K     3V3
++ *			ESMT/CFEON		F25L64QA		8M      64K     3V3
++ *			GD				GD25Q64			8M      64K     3V3
++ *			GD				GD25LQ128		16M     64K     1V8
++ *			GD				GD25Q128		16M     64K     3V3
++ *			GD				GD25LQ64C		8M      64K     1V8
++ *			GD				GD25Q32			4M      64K     3V3
++ *			Paragon			PN25F16S		2M		64K     3V3
++ *			Paragon			PN25F32S		4M      64K     3V3
++ *****************************************************************************/
++static const struct flash_info spi_nor_ids[] = {
++	/* Atmel -- some are (confusingly) marketed as "DataFlash" */
++	{ "at25fs010",  INFO(0x1f6601, 0, 32 * 1024,   4, SECT_4K) },
++	{ "at25fs040",  INFO(0x1f6604, 0, 64 * 1024,   8, SECT_4K) },
++
++	{ "at25df041a", INFO(0x1f4401, 0, 64 * 1024,   8, SECT_4K) },
++	{ "at25df321a", INFO(0x1f4701, 0, 64 * 1024,  64, SECT_4K) },
++	{ "at25df641",  INFO(0x1f4800, 0, 64 * 1024, 128, SECT_4K) },
++
++	{ "at26f004",   INFO(0x1f0400, 0, 64 * 1024,  8, SECT_4K) },
++	{ "at26df081a", INFO(0x1f4501, 0, 64 * 1024, 16, SECT_4K) },
++	{ "at26df161a", INFO(0x1f4601, 0, 64 * 1024, 32, SECT_4K) },
++	{ "at26df321",  INFO(0x1f4700, 0, 64 * 1024, 64, SECT_4K) },
++
++	{ "at45db081d", INFO(0x1f2500, 0, 64 * 1024, 16, SECT_4K) },
++
++	/* EON -- en25xxx */
++	{ "en25f32",    INFO(0x1c3116, 0, 64 * 1024,   64, SECT_4K) },
++	{ "en25p32",    INFO(0x1c2016, 0, 64 * 1024,   64, 0) },
++	{ "en25q32b",   INFO(0x1c3016, 0, 64 * 1024,   64,
++			SPI_NOR_QUAD_READ), PARAMS(eon), CLK_MHZ_2X(104) },
++	{ "en25p64",    INFO(0x1c2017, 0, 64 * 1024,  128, 0) },
++	{ "en25q64",    INFO(0x1c3017, 0, 64 * 1024,  128,
++			SECT_4K | SPI_NOR_QUAD_READ), PARAMS(eon), CLK_MHZ_2X(104) },
++	{ "en25q128",   INFO(0x1c3018, 0, 64 * 1024,  256,
++			SPI_NOR_QUAD_READ), PARAMS(eon), CLK_MHZ_2X(104) },
++	{ "en25qh128",  INFO(0x1c7018, 0, 64 * 1024,  256, 0) },
++	{ "en25qh256",  INFO(0x1c7019, 0, 64 * 1024,  512, 0) },
++	{ "en25s64",	INFO(0x1c3817, 0, 64 * 1024,  128, SECT_4K) },
++
++	/* ESMT */
++	{ "f25l32pa", INFO(0x8c2016, 0, 64 * 1024, 64, SECT_4K) },
++	{ "f25l64qa", INFO(0x8c4117, 0, 64 * 1024, 128,
++					SPI_NOR_QUAD_READ), PARAMS(esmt), CLK_MHZ_2X(84) },
++
++	/* Everspin */
++	{ "mr25h256", CAT25_INFO(32 * 1024, 1, 256, 2, SPI_NOR_NO_ERASE
++			| SPI_NOR_NO_FR) },
++	{ "mr25h10",  CAT25_INFO(128 * 1024, 1, 256, 3, SPI_NOR_NO_ERASE
++			| SPI_NOR_NO_FR) },
++
++	/* Fujitsu */
++	{ "mb85rs1mt", INFO(0x047f27, 0, 128 * 1024, 1, SPI_NOR_NO_ERASE) },
++
++	/* GigaDevice 3.3V */
++	{ "gd25q16c", INFO(0xc84015, 0, 64 * 1024, 32,
++			SECT_4K | SPI_NOR_QUAD_READ), PARAMS(gd), CLK_MHZ_2X(120) },
++	{ "gd25q32", INFO(0xc84016, 0, 64 * 1024,  64,
++			SECT_4K | SPI_NOR_QUAD_READ), PARAMS(gd), CLK_MHZ_2X(120) },
++	{ "gd25q64", INFO(0xc84017, 0, 64 * 1024, 128,
++			SECT_4K | SPI_NOR_QUAD_READ), PARAMS(gd), CLK_MHZ_2X(120) },
++	{ "gd25q128", INFO(0xc84018, 0, 64 * 1024, 256,
++			SECT_4K | SPI_NOR_QUAD_READ), PARAMS(gd), CLK_MHZ_2X(80) },
++	/* GigaDevice 1.8V */
++	{ "gd25lq64", INFO(0xc86017, 0, 64 * 1024, 128,
++			SECT_4K | SPI_NOR_QUAD_READ), PARAMS(gd), CLK_MHZ_2X(133) },
++	{ "gd25lq128", INFO(0xc86018, 0, 64 * 1024, 256,
++			SECT_4K | SPI_NOR_QUAD_READ), PARAMS(gd), CLK_MHZ_2X(133) },
++
++	/* Intel/Numonyx -- xxxs33b */
++	{ "160s33b",  INFO(0x898911, 0, 64 * 1024,  32, 0) },
++	{ "320s33b",  INFO(0x898912, 0, 64 * 1024,  64, 0) },
++	{ "640s33b",  INFO(0x898913, 0, 64 * 1024, 128, 0) },
++
++	/* ISSI */
++	{ "is25cd512", INFO(0x7f9d20, 0, 32 * 1024,   2, SECT_4K) },
++
++	/* Macronix/MXIC 3.3V */
++	{ "mx25l512e",   INFO(0xc22010, 0, 64 * 1024,   1, SECT_4K) },
++	{ "mx25l2005a",  INFO(0xc22012, 0, 64 * 1024,   4, SECT_4K) },
++	{ "mx25l4005a",  INFO(0xc22013, 0, 64 * 1024,   8, SECT_4K) },
++	{ "mx25l8005",   INFO(0xc22014, 0, 64 * 1024,  16, 0) },
++	{ "mx25l1606e",  INFO(0xc22015, 0, 64 * 1024,  32, SECT_4K
++			| SPI_NOR_DUAL_READ), CLK_MHZ_2X(80) },
++	{ "mx25l3205d",  INFO(0xc22016, 0, 64 * 1024,  64, 0) },
++	{ "mx25l3255e",  INFO(0xc29e16, 0, 64 * 1024,  64, SECT_4K) },
++	{ "mx25l6436f",  INFO(0xc22017, 0, 64 * 1024, 128,
++			SPI_NOR_QUAD_READ), PARAMS(mxic), CLK_MHZ_2X(133) },
++	{ "mx25l12835f", INFO(0xc22018, 0, 64 * 1024, 256,
++			SPI_NOR_QUAD_READ), PARAMS(mxic), CLK_MHZ_2X(84) },
++	{ "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) },
++	{ "mx25l25635f", INFO(0xc22019, 0, 64 * 1024, 512,
++			SPI_NOR_QUAD_READ), PARAMS(mxic), CLK_MHZ_2X(84) },
++	{ "mx25l25673g", INFO(0xc22019, 0, 64 * 1024, 512, SPI_NOR_QUAD_READ
++			| SPI_NOR_4B_OPCODES) },
++	{ "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) },
++	{ "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_QUAD_READ)},
++	{ "mx66l1g55g",  INFO(0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ)},
++	{ "mx25v1635f",  INFO(0xc22315, 0, 64 * 1024, 32 ,
++			SPI_NOR_QUAD_READ), PARAMS(mxic), CLK_MHZ_2X(80) },
++	/* Macronix/MXIC Wide Voltage Range 1.65~3.6V */
++	{ "mx25r6435f",  INFO(0xc22817, 0, 64 * 1024, 128,
++			SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ), CLK_MHZ_2X(80) },
++	/* Macronix/MXIC 1.8V */
++	{ "mx25u6435f",  INFO(0xc22537, 0, 64 * 1024, 128,
++			SECT_4K | SPI_NOR_QUAD_READ), PARAMS(mxic), CLK_MHZ_2X(84) },
++	{ "mx25u12835f", INFO(0xc22538, 0, 64 * 1024, 256,
++			SPI_NOR_QUAD_READ), PARAMS(mxic), CLK_MHZ_2X(84) },
++	{ "mx25u25635f", INFO(0xc22539, 0, 64 * 1024, 512,
++			SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES), PARAMS(mxic), CLK_MHZ_2X(84) },
++
++	/* Micron 3.3V */
++	{ "n25q032",     INFO(0x20ba16, 0, 64 * 1024,   64, SPI_NOR_QUAD_READ),
++			PARAMS(micron), CLK_MHZ_2X(84) },
++	{ "n25q064",     INFO(0x20ba17, 0, 64 * 1024,  128, SPI_NOR_QUAD_READ),
++			PARAMS(micron_4k), CLK_MHZ_2X(108) },
++	{ "n25q128a13",  INFO(0x20ba18, 0, 64 * 1024,  256, SPI_NOR_QUAD_READ),
++			PARAMS(micron), CLK_MHZ_2X(108) },
++	{ "mt25ql256a/n25q256a",  INFO(0x20ba19, 0, 64 * 1024,  512, SPI_NOR_QUAD_READ),
++			PARAMS(micron), CLK_MHZ_2X(108) },
++	{ "n25q512ax3",  INFO(0x20ba20, 0, 64 * 1024, 1024, USE_FSR),
++			PARAMS(micron_4k) },
++	{ "n25q00",      INFO(0x20ba21, 0, 64 * 1024, 2048, USE_FSR | SPI_NOR_QUAD_READ),
++			PARAMS(micron_4k), CLK_MHZ_2X(80) },
++	/* Micron 1.8V */
++	{ "n25q032a",    INFO(0x20bb16, 0, 64 * 1024,   64, SPI_NOR_QUAD_READ),
++			PARAMS(micron), CLK_MHZ_2X(108) },
++	{ "n25q064a",    INFO(0x20bb17, 0, 64 * 1024,  128, SPI_NOR_QUAD_READ),
++			PARAMS(micron), CLK_MHZ_2X(108) },
++	{ "mt25qu128a/n25q128a11",  INFO(0x20bb18, 0, 64 * 1024,  256, SPI_NOR_QUAD_READ),
++			PARAMS(micron), CLK_MHZ_2X(108) },
++	{ "mt25qu256a",  INFO(0x20bb19, 0, 64 * 1024,  512,
++			SPI_NOR_QUAD_READ), PARAMS(micron), CLK_MHZ_2X(108) },
++	{ "n25q512a",    INFO(0x20bb20, 0, 64 * 1024, 1024, USE_FSR | SPI_NOR_QUAD_READ),
++			PARAMS(micron_4k), CLK_MHZ_2X(80) },
++
++	/* PMC */
++	{ "pm25lv512",	INFO(0,        0, 32 * 1024,    2, SECT_4K_PMC) },
++	{ "pm25lv010",	INFO(0,        0, 32 * 1024,    4, SECT_4K_PMC) },
++	{ "pm25lq032",	INFO(0x7f9d46, 0, 64 * 1024,   64, SECT_4K) },
+ 
+ 	/* Spansion -- single (large) sector size only, at least
+ 	 * for the chips listed here (without boot sectors).
+ 	 */
+-	{ "s25sl032p",  INFO(0x010215, 0x4d00,  64 * 1024,  64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+-	{ "s25sl064p",  INFO(0x010216, 0x4d00,  64 * 1024, 128, 0) },
++	{ "s25sl032p",  INFO(0x010215, 0x4d00,  64 * 1024,  64,
++			SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
++	{ "s25sl064p",  INFO(0x010216, 0x4d00,  64 * 1024, 128,
++			SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+ 	{ "s25fl256s0", INFO(0x010219, 0x4d00, 256 * 1024, 128, 0) },
+-	{ "s25fl256s1", INFO(0x010219, 0x4d01,  64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+-	{ "s25fl512s",  INFO(0x010220, 0x4d00, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+-	{ "s70fl01gs",  INFO(0x010221, 0x4d00, 256 * 1024, 256, 0) },
++	{ "s25fl256s1", INFO(0x010219, 0x4d01,  64 * 1024, 512,
++			 SPI_NOR_4B_OPCODES | SPI_NOR_QUAD_READ), PARAMS(spansion), CLK_MHZ_2X(104) },
++	{ "s25fl512s",	INFO(0x010220, 0x4d00, 256 * 1024, 256,
++			SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
++	{ "s70fl01gs",	INFO(0x010221, 0x4d00, 256 * 1024, 256, 0) },
++	{ "s25fl127s/129p1", INFO(0x012018, 0x4d01, 64 * 1024, 256,
++			SECT_4K | SPI_NOR_QUAD_READ), PARAMS(spansion), CLK_MHZ_2X(108) },
+ 	{ "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024,  64, 0) },
+ 	{ "s25sl12801", INFO(0x012018, 0x0301,  64 * 1024, 256, 0) },
+-	{ "s25fl129p0", INFO(0x012018, 0x4d00, 256 * 1024,  64, 0) },
+-	{ "s25fl129p1", INFO(0x012018, 0x4d01,  64 * 1024, 256, 0) },
+-	{ "s25sl004a",  INFO(0x010212,      0,  64 * 1024,   8, 0) },
+-	{ "s25sl008a",  INFO(0x010213,      0,  64 * 1024,  16, 0) },
+-	{ "s25sl016a",  INFO(0x010214,      0,  64 * 1024,  32, 0) },
+-	{ "s25sl032a",  INFO(0x010215,      0,  64 * 1024,  64, 0) },
+-	{ "s25sl064a",  INFO(0x010216,      0,  64 * 1024, 128, 0) },
+-	{ "s25fl008k",  INFO(0xef4014,      0,  64 * 1024,  16, SECT_4K) },
+-	{ "s25fl016k",  INFO(0xef4015,      0,  64 * 1024,  32, SECT_4K) },
+-	{ "s25fl064k",  INFO(0xef4017,      0,  64 * 1024, 128, SECT_4K) },
++	{ "s25fl128s",	INFO6(0x012018, 0x4d0180, 64 * 1024, 256, SECT_4K
++			| SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
++	{ "s25fl129p0", INFO(0x012018, 0x4d00, 256 * 1024,  64,
++			SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
++	{ "s25fl129p1", INFO(0x012018, 0x4d01,  64 * 1024, 256,
++			SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
++	{ "s25sl004a",	INFO(0x010212,      0,  64 * 1024,   8, 0) },
++	{ "s25sl008a",	INFO(0x010213,      0,  64 * 1024,  16, 0) },
++	{ "s25sl016a",	INFO(0x010214,      0,  64 * 1024,  32, 0) },
++	{ "s25sl032a",	INFO(0x010215,      0,  64 * 1024,  64, 0) },
++	{ "s25sl064a",	INFO(0x010216,      0,  64 * 1024, 128, 0) },
++	{ "s25fl004k",	INFO(0xef4013,      0,  64 * 1024,   8, SECT_4K
++			| SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
++	{ "s25fl008k",	INFO(0xef4014,      0,  64 * 1024,  16, SECT_4K
++			| SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
++	{ "w25x16/s25fl016k",	INFO(0xef4015,      0,  64 * 1024,  32,
++			SECT_4K | SPI_NOR_QUAD_READ), PARAMS(winbond), CLK_MHZ_2X(84) },
++	/* { "s25fl064k",	INFO(0xef4017,      0,  64 * 1024, 128, SECT_4K
++			| SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, */
++	{ "s25fl132k",	INFO(0x014016,      0,  64 * 1024,  64, SECT_4K) },
++	{ "s25fl164k",	INFO(0x014017,      0,  64 * 1024, 128, SECT_4K) },
++	{ "s25fl204k",	INFO(0x014013,      0,  64 * 1024,   8, SECT_4K
++			| SPI_NOR_DUAL_READ) },
+ 
+ 	/* SST -- large erase sizes are "overlays", "sectors" are 4K */
+-	{ "sst25vf040b", INFO(0xbf258d, 0, 64 * 1024,  8, SECT_4K | SST_WRITE) },
+-	{ "sst25vf080b", INFO(0xbf258e, 0, 64 * 1024, 16, SECT_4K | SST_WRITE) },
+-	{ "sst25vf016b", INFO(0xbf2541, 0, 64 * 1024, 32, SECT_4K | SST_WRITE) },
+-	{ "sst25vf032b", INFO(0xbf254a, 0, 64 * 1024, 64, SECT_4K | SST_WRITE) },
++	{ "sst25vf040b", INFO(0xbf258d, 0, 64 * 1024,  8, SECT_4K | SST_WRITE)},
++	{ "sst25vf080b", INFO(0xbf258e, 0, 64 * 1024, 16, SECT_4K | SST_WRITE)},
++	{ "sst25vf016b", INFO(0xbf2541, 0, 64 * 1024, 32, SECT_4K | SST_WRITE)},
++	{ "sst25vf032b", INFO(0xbf254a, 0, 64 * 1024, 64, SECT_4K | SST_WRITE)},
+ 	{ "sst25vf064c", INFO(0xbf254b, 0, 64 * 1024, 128, SECT_4K) },
+-	{ "sst25wf512",  INFO(0xbf2501, 0, 64 * 1024,  1, SECT_4K | SST_WRITE) },
+-	{ "sst25wf010",  INFO(0xbf2502, 0, 64 * 1024,  2, SECT_4K | SST_WRITE) },
+-	{ "sst25wf020",  INFO(0xbf2503, 0, 64 * 1024,  4, SECT_4K | SST_WRITE) },
+-	{ "sst25wf040",  INFO(0xbf2504, 0, 64 * 1024,  8, SECT_4K | SST_WRITE) },
++	{ "sst25wf512",  INFO(0xbf2501, 0, 64 * 1024,  1, SECT_4K | SST_WRITE)},
++	{ "sst25wf010",  INFO(0xbf2502, 0, 64 * 1024,  2, SECT_4K | SST_WRITE)},
++	{ "sst25wf020",  INFO(0xbf2503, 0, 64 * 1024,  4, SECT_4K | SST_WRITE)},
++	{ "sst25wf020a", INFO(0x621612, 0, 64 * 1024,  4, SECT_4K) },
++	{ "sst25wf040b", INFO(0x621613, 0, 64 * 1024,  8, SECT_4K) },
++	{ "sst25wf040",  INFO(0xbf2504, 0, 64 * 1024,  8, SECT_4K | SST_WRITE)},
++	{ "sst25wf080",  INFO(0xbf2505, 0, 64 * 1024, 16, SECT_4K | SST_WRITE)},
+ 
+ 	/* ST Microelectronics -- newer production may have feature updates */
+ 	{ "m25p05",  INFO(0x202010,  0,  32 * 1024,   2, 0) },
+@@ -588,7 +1313,6 @@ static const struct spi_device_id spi_nor_ids[] = {
+ 	{ "m25p32",  INFO(0x202016,  0,  64 * 1024,  64, 0) },
+ 	{ "m25p64",  INFO(0x202017,  0,  64 * 1024, 128, 0) },
+ 	{ "m25p128", INFO(0x202018,  0, 256 * 1024,  64, 0) },
+-	{ "n25q032", INFO(0x20ba16,  0,  64 * 1024,  64, 0) },
+ 
+ 	{ "m25p05-nonjedec",  INFO(0, 0,  32 * 1024,   2, 0) },
+ 	{ "m25p10-nonjedec",  INFO(0, 0,  32 * 1024,   4, 0) },
+@@ -615,60 +1339,78 @@ static const struct spi_device_id spi_nor_ids[] = {
+ 	{ "m25px64",    INFO(0x207117,  0, 64 * 1024, 128, 0) },
+ 	{ "m25px80",    INFO(0x207114,  0, 64 * 1024, 16, 0) },
+ 
+-	/* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */
++	/* Winbond 3.3V-- w25x "blocks" are 64K, "sectors" are 4KiB */
++	{ "w25x05", INFO(0xef3010, 0, 64 * 1024,  1,  SECT_4K) },
+ 	{ "w25x10", INFO(0xef3011, 0, 64 * 1024,  2,  SECT_4K) },
+ 	{ "w25x20", INFO(0xef3012, 0, 64 * 1024,  4,  SECT_4K) },
+ 	{ "w25x40", INFO(0xef3013, 0, 64 * 1024,  8,  SECT_4K) },
+ 	{ "w25x80", INFO(0xef3014, 0, 64 * 1024,  16, SECT_4K) },
+-	{ "w25x16", INFO(0xef3015, 0, 64 * 1024,  32, SECT_4K) },
++	{ "w25x16", INFO(0xef3015, 0, 64 * 1024,  32, SECT_4K
++			| SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+ 	{ "w25x32", INFO(0xef3016, 0, 64 * 1024,  64, SECT_4K) },
+-	{ "w25q32", INFO(0xef4016, 0, 64 * 1024,  64, SECT_4K) },
+-	{ "w25q32dw", INFO(0xef6016, 0, 64 * 1024,  64, SECT_4K) },
++	{ "w25q32", INFO(0xef4016, 0, 64 * 1024,  64,
++			SECT_4K | SPI_NOR_QUAD_READ), PARAMS(winbond), CLK_MHZ_2X(80) },
+ 	{ "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) },
+-	{ "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) },
++	{ "w25q64/s25fl064k", INFO(0xef4017, 0, 64 * 1024, 128,
++			SECT_4K | SPI_NOR_QUAD_READ), PARAMS(winbond), CLK_MHZ_2X(80) },
+ 	{ "w25q80", INFO(0xef5014, 0, 64 * 1024,  16, SECT_4K) },
+ 	{ "w25q80bl", INFO(0xef4014, 0, 64 * 1024,  16, SECT_4K) },
+-	{ "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) },
+-	{ "w25q256", INFO(0xef4019, 0, 64 * 1024, 512, SECT_4K) },
++	{ "w25q128", INFO(0xef4018, 0, 64 * 1024, 256,
++			SECT_4K | SPI_NOR_QUAD_READ), PARAMS(winbond), CLK_MHZ_2X(104) },
++	{ "w25q256", INFO(0xef4019, 0, 64 * 1024, 512,
++			SECT_4K | SPI_NOR_QUAD_READ), PARAMS(winbond), CLK_MHZ_2X(80) },
++	/* Winbond 1.8V */
++	{ "w25q32fw", INFO(0xef6016, 0, 64 * 1024,  64,
++			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
++			SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB), PARAMS(winbond), CLK_MHZ_2X(80) },
++	{ "w25q64dw", INFO(0xef6017, 0, 64 * 1024, 128,
++			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
++			SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB), PARAMS(winbond), CLK_MHZ_2X(80) },
++	{ "w25q128fw", INFO(0xef6018, 0, 64 * 1024, 256,
++			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
++			SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB), PARAMS(winbond), CLK_MHZ_2X(80) },
+ 
+ 	/* Catalyst / On Semiconductor -- non-JEDEC */
+-	{ "cat25c11", CAT25_INFO(  16, 8, 16, 1, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
+-	{ "cat25c03", CAT25_INFO(  32, 8, 16, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
+-	{ "cat25c09", CAT25_INFO( 128, 8, 32, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
+-	{ "cat25c17", CAT25_INFO( 256, 8, 32, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
+-	{ "cat25128", CAT25_INFO(2048, 8, 64, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
++	{ "cat25c11", CAT25_INFO(16, 8, 16, 1, SPI_NOR_NO_ERASE
++			| SPI_NOR_NO_FR) },
++	{ "cat25c03", CAT25_INFO(32, 8, 16, 2, SPI_NOR_NO_ERASE
++			| SPI_NOR_NO_FR) },
++	{ "cat25c09", CAT25_INFO(28, 8, 32, 2, SPI_NOR_NO_ERASE
++			| SPI_NOR_NO_FR) },
++	{ "cat25c17", CAT25_INFO(256, 8, 32, 2, SPI_NOR_NO_ERASE
++			| SPI_NOR_NO_FR) },
++	{ "cat25128", CAT25_INFO(2048, 8, 64, 2, SPI_NOR_NO_ERASE
++			| SPI_NOR_NO_FR) },
++	/* Paragon 3.3V */
++	{ "pn25f16s", INFO(0xe04015, 0, 64 * 1024,  32,
++			SPI_NOR_QUAD_READ), PARAMS(paragon), CLK_MHZ_2X(80) },
++	{ "pn25f32s", INFO(0xe04016, 0, 64 * 1024,  64,
++			SPI_NOR_QUAD_READ), PARAMS(paragon), CLK_MHZ_2X(80) },
++
+ 	{ },
+ };
+ 
+-static const struct spi_device_id *spi_nor_read_id(struct spi_nor *nor)
++static const struct flash_info *spi_nor_read_id(struct spi_nor *nor)
+ {
+ 	int			tmp;
+-	u8			id[5];
+-	u32			jedec;
+-	u16                     ext_jedec;
+-	struct flash_info	*info;
++	u8			id[SPI_NOR_MAX_ID_LEN];
++	const struct flash_info	*info;
+ 
+-	tmp = nor->read_reg(nor, SPINOR_OP_RDID, id, 5);
++	tmp = nor->read_reg(nor, SPINOR_OP_RDID, id, SPI_NOR_MAX_ID_LEN);
+ 	if (tmp < 0) {
+ 		dev_dbg(nor->dev, " error %d reading JEDEC ID\n", tmp);
+ 		return ERR_PTR(tmp);
+ 	}
+-	jedec = id[0];
+-	jedec = jedec << 8;
+-	jedec |= id[1];
+-	jedec = jedec << 8;
+-	jedec |= id[2];
+-
+-	ext_jedec = id[3] << 8 | id[4];
+ 
+ 	for (tmp = 0; tmp < ARRAY_SIZE(spi_nor_ids) - 1; tmp++) {
+-		info = (void *)spi_nor_ids[tmp].driver_data;
+-		if (info->jedec_id == jedec) {
+-			if (info->ext_id == 0 || info->ext_id == ext_jedec)
++		info = &spi_nor_ids[tmp];
++		if (info->id_len) {
++			if (!memcmp(info->id, id, info->id_len))
+ 				return &spi_nor_ids[tmp];
+ 		}
+ 	}
+-	dev_err(nor->dev, "unrecognized JEDEC id %06x\n", jedec);
++	dev_err(nor->dev, "unrecognized JEDEC id bytes: %02x, %02x, %02x\n",
++		id[0], id[1], id[2]);
+ 	return ERR_PTR(-ENODEV);
+ }
+ 
+@@ -703,11 +1445,6 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,
+ 	if (ret)
+ 		return ret;
+ 
+-	/* Wait until finished previous write command. */
+-	ret = wait_till_ready(nor);
+-	if (ret)
+-		goto time_out;
+-
+ 	write_enable(nor);
+ 
+ 	nor->sst_write_second = false;
+@@ -719,7 +1456,7 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,
+ 
+ 		/* write one byte. */
+ 		nor->write(nor, to, 1, retlen, buf);
+-		ret = wait_till_ready(nor);
++		ret = spi_nor_wait_till_ready(nor);
+ 		if (ret)
+ 			goto time_out;
+ 	}
+@@ -731,7 +1468,7 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,
+ 
+ 		/* write two bytes. */
+ 		nor->write(nor, to, 2, retlen, buf + actual);
+-		ret = wait_till_ready(nor);
++		ret = spi_nor_wait_till_ready(nor);
+ 		if (ret)
+ 			goto time_out;
+ 		to += 2;
+@@ -740,7 +1477,7 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,
+ 	nor->sst_write_second = false;
+ 
+ 	write_disable(nor);
+-	ret = wait_till_ready(nor);
++	ret = spi_nor_wait_till_ready(nor);
+ 	if (ret)
+ 		goto time_out;
+ 
+@@ -751,7 +1488,7 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,
+ 		nor->program_opcode = SPINOR_OP_BP;
+ 		nor->write(nor, to, 1, retlen, buf + actual);
+ 
+-		ret = wait_till_ready(nor);
++		ret = spi_nor_wait_till_ready(nor);
+ 		if (ret)
+ 			goto time_out;
+ 		write_disable(nor);
+@@ -779,11 +1516,12 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
+ 	if (ret)
+ 		return ret;
+ 
+-	/* Wait until finished previous write command. */
+-	ret = wait_till_ready(nor);
+-	if (ret)
+-		goto write_err;
+-
++#ifdef CONFIG_HISI_SPI_BLOCK_PROTECT
++	if (nor->level && (to < nor->end_addr)) {
++		dev_err(nor->dev, "Error: The DMA write area was locked\n");
++		return -EINVAL;
++	}
++#endif
+ 	write_enable(nor);
+ 
+ 	page_offset = to & (nor->page_size - 1);
+@@ -802,16 +1540,20 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
+ 			if (page_size > nor->page_size)
+ 				page_size = nor->page_size;
+ 
+-			wait_till_ready(nor);
++			ret = spi_nor_wait_till_ready(nor);
++			if (ret)
++				goto write_err;
++
+ 			write_enable(nor);
+ 
+ 			nor->write(nor, to + i, page_size, retlen, buf + i);
+ 		}
+ 	}
+ 
++	ret = spi_nor_wait_till_ready(nor);
+ write_err:
+ 	spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_WRITE);
+-	return 0;
++	return ret;
+ }
+ 
+ static int macronix_quad_enable(struct spi_nor *nor)
+@@ -819,16 +1561,24 @@ static int macronix_quad_enable(struct spi_nor *nor)
+ 	int ret, val;
+ 
+ 	val = read_sr(nor);
++	if (val < 0)
++		return val;
++
++	if ((unsigned int)val & SR_QUAD_EN_MX)
++		return 0;
++
++	/* Update the Quad Enable bit. */
++	dev_info(nor->dev, "setting Macronix Quad Enable (non-volatile) bit\n");
++
+ 	write_enable(nor);
+ 
+-	nor->cmd_buf[0] = val | SR_QUAD_EN_MX;
+-	nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 1, 0);
++	write_sr(nor, (u8)val | SR_QUAD_EN_MX);
+ 
+-	if (wait_till_ready(nor))
++	if (spi_nor_wait_till_ready(nor))
+ 		return 1;
+ 
+ 	ret = read_sr(nor);
+-	if (!(ret > 0 && (ret & SR_QUAD_EN_MX))) {
++	if (!(ret > 0 && ((unsigned int)ret & SR_QUAD_EN_MX))) {
+ 		dev_err(nor->dev, "Macronix Quad bit not set\n");
+ 		return -EINVAL;
+ 	}
+@@ -847,23 +1597,38 @@ static int write_sr_cr(struct spi_nor *nor, u16 val)
+ 	nor->cmd_buf[0] = val & 0xff;
+ 	nor->cmd_buf[1] = (val >> 8);
+ 
+-	return nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 2, 0);
++	return nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 2);
+ }
+ 
+ static int spansion_quad_enable(struct spi_nor *nor)
+ {
+ 	int ret;
+-	int quad_en = CR_QUAD_EN_SPAN << 8;
++	u16 val;
++
++	ret = read_cr(nor);
++	if (ret & CR_QUAD_EN_SPAN)
++		return 0;
++
++	/* Update the Quad Enable bit. */
++	dev_info(nor->dev, "setting Quad Enable (non-volatile) bit\n");
++
++	val = ((ret & 0xff) | CR_QUAD_EN_SPAN) << 8;
++
++	ret = read_sr(nor);
++	val |= (ret & 0xff);
+ 
+ 	write_enable(nor);
+ 
+-	ret = write_sr_cr(nor, quad_en);
++	ret = write_sr_cr(nor, val);
+ 	if (ret < 0) {
+ 		dev_err(nor->dev,
+ 			"error while writing configuration register\n");
+ 		return -EINVAL;
+ 	}
+ 
++	if (spi_nor_wait_till_ready(nor))
++		return 1;
++
+ 	/* read back and check it */
+ 	ret = read_cr(nor);
+ 	if (!(ret > 0 && (ret & CR_QUAD_EN_SPAN))) {
+@@ -874,18 +1639,128 @@ static int spansion_quad_enable(struct spi_nor *nor)
+ 	return 0;
+ }
+ 
+-static int set_quad_mode(struct spi_nor *nor, u32 jedec_id)
++static int micron_quad_enable(struct spi_nor *nor)
++{
++	int ret;
++	u8 val;
++
++	ret = nor->read_reg(nor, SPINOR_OP_RD_EVCR, &val, 1);
++	if (ret < 0) {
++		dev_err(nor->dev, "error %d reading EVCR\n", ret);
++		return ret;
++	}
++
++	write_enable(nor);
++
++	/* set EVCR, enable quad I/O */
++	nor->cmd_buf[0] = val & ~EVCR_QUAD_EN_MICRON;
++	ret = nor->write_reg(nor, SPINOR_OP_WD_EVCR, nor->cmd_buf, 1);
++	if (ret < 0) {
++		dev_err(nor->dev, "error while writing EVCR register\n");
++		return ret;
++	}
++
++	ret = spi_nor_wait_till_ready(nor);
++	if (ret)
++		return ret;
++
++	/* read EVCR and check it */
++	ret = nor->read_reg(nor, SPINOR_OP_RD_EVCR, &val, 1);
++	if (ret < 0) {
++		dev_err(nor->dev, "error %d reading EVCR\n", ret);
++		return ret;
++	}
++	if (val & EVCR_QUAD_EN_MICRON) {
++		dev_err(nor->dev, "Micron EVCR Quad bit not clear\n");
++		return -EINVAL;
++	}
++
++	return 0;
++}
++
++static int gd_quad_enable(struct spi_nor *nor)
++{
++	int ret;
++	u16 val;
++
++	/* First, Quad Enable for 16-Pin GD flash, use WRSR[01h] cmd */
++	ret = read_cr(nor);
++	val = ((ret & 0xff) | CR_QUAD_EN_SPAN) << 8;
++
++	ret = read_sr(nor);
++	val |= (ret & 0xff);
++
++	write_enable(nor);
++
++	ret = write_sr_cr(nor, val);
++	if (ret < 0) {
++		dev_err(nor->dev,
++			"error while writing config and status register\n");
++		return -EINVAL;
++	}
++
++	if (spi_nor_wait_till_ready(nor))
++		return 1;
++
++	/* read back and check it */
++	ret = read_cr(nor);
++	if (ret & CR_QUAD_EN_SPAN)
++		return 0;
++
++	/* Second, Quad Enable for 8-Pin GD flash, use WRCR[31h] cmd */
++	ret = read_sr(nor);
++	if (!(ret & SR_WEL))
++		write_enable(nor);
++
++	ret = read_cr(nor);
++	nor->cmd_buf[0] = (ret & 0xff) | CR_QUAD_EN_SPAN;
++
++	ret = nor->write_reg(nor, SPINOR_OP_WRCR, nor->cmd_buf, 1);
++	if (ret < 0) {
++		dev_err(nor->dev, "error while writing config register\n");
++		return ret;
++	}
++
++	if (spi_nor_wait_till_ready(nor))
++		return 1;
++
++	/* read back and check it */
++	ret = read_cr(nor);
++	if (!(ret > 0 && (ret & CR_QUAD_EN_SPAN))) {
++		dev_err(nor->dev, "GigaDevice Quad bit not set\n");
++		return -EINVAL;
++	}
++
++	return 0;
++}
++
++static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
+ {
+ 	int status;
+ 
+-	switch (JEDEC_MFR(jedec_id)) {
+-	case CFI_MFR_MACRONIX:
++	switch (JEDEC_MFR(info)) {
++	case SNOR_MFR_ESMT:
++	case SNOR_MFR_MACRONIX:
+ 		status = macronix_quad_enable(nor);
+ 		if (status) {
+ 			dev_err(nor->dev, "Macronix quad-read not enabled\n");
+ 			return -EINVAL;
+ 		}
+ 		return status;
++	case SNOR_MFR_MICRON:
++		status = micron_quad_enable(nor);
++		if (status) {
++			dev_err(nor->dev, "Micron quad-read not enabled\n");
++			return -EINVAL;
++		}
++		return status;
++	case SNOR_MFR_GD:
++		status = gd_quad_enable(nor);
++		if (status) {
++			dev_err(nor->dev, "GD quad-read not enabled\n");
++			return -EINVAL;
++		}
++		return status;
+ 	default:
+ 		status = spansion_quad_enable(nor);
+ 		if (status) {
+@@ -899,26 +1774,362 @@ static int set_quad_mode(struct spi_nor *nor, u32 jedec_id)
+ static int spi_nor_check(struct spi_nor *nor)
+ {
+ 	if (!nor->dev || !nor->read || !nor->write ||
+-		!nor->read_reg || !nor->write_reg || !nor->erase) {
++		!nor->read_reg || !nor->write_reg) {
+ 		pr_err("spi-nor: please fill all the necessary fields!\n");
+ 		return -EINVAL;
+ 	}
+ 
+-	if (!nor->read_id)
+-		nor->read_id = spi_nor_read_id;
+-	if (!nor->wait_till_ready)
+-		nor->wait_till_ready = spi_nor_wait_till_ready;
++	return 0;
++}
++
++#ifdef CONFIG_HISI_SPI_BLOCK_PROTECT
++static void spi_lock_update_address(struct spi_nor *nor, const struct flash_info *info)
++{
++	unsigned int lock_level_max, sectorsize, chipsize;
++
++	if (!nor->level) {
++		nor->end_addr = 0;
++		dev_warn(nor->dev, "all blocks is unlocked.\n");
++		return;
++	}
++
++	sectorsize = info->sector_size;
++	chipsize = sectorsize * info->n_sectors;
++	lock_level_max = nor->lock_level_max;
++
++	switch (JEDEC_MFR(info)) {
++	case SNOR_MFR_MACRONIX:
++		if (chipsize == _2M) {
++			if ((nor->level != lock_level_max)
++					&& (nor->level != 1))
++				nor->end_addr = chipsize - (sectorsize <<
++					(lock_level_max - nor->level - 1));
++			else
++				nor->end_addr = chipsize;
++			return;
++		}
++
++		if (chipsize != _8M)
++			break;
++	case SNOR_MFR_ESMT:
++		/* this case is for ESMT and MXIC 8M devices */
++		if (nor->level != lock_level_max)
++			nor->end_addr = chipsize - (sectorsize
++					<< (lock_level_max - nor->level));
++		else
++			nor->end_addr = chipsize;
++		return;
++	case SNOR_MFR_EON:
++		if (nor->level != lock_level_max)
++			nor->end_addr = chipsize - (sectorsize
++					<< (nor->level - 1));
++		else
++			nor->end_addr = chipsize;
++		return;
++	default:
++		break;
++	}
++
++	/* general case */
++	nor->end_addr = chipsize >> (lock_level_max - nor->level);
++}
++
++static unsigned char hisi_bp_to_level(struct spi_nor *nor,
++		const struct flash_info *info, unsigned int bp_num)
++{
++	int ret;
++	unsigned char val;
++	unsigned char level;
++	unsigned int chipsize;
++
++	ret = spi_nor_wait_till_ready(nor);
++	BUG_ON(ret);
++
++	ret = nor->read_reg(nor, SPINOR_OP_RDSR, &val, 1);
++	if (ret < 0) {
++		dev_err(nor->dev, "error %d reading SR\n", ret);
++		return ret;
++	}
++
++	if (bp_num == BP_NUM_3)
++		level = (val & SPI_NOR_SR_BP_MASK_3) >> SPI_NOR_SR_BP0_SHIFT;
++	else
++		level = (val & SPI_NOR_SR_BP_MASK_4) >> SPI_NOR_SR_BP0_SHIFT;
++
++	/* dev_info(nor->dev, "the current level[%d]\n", level); */
++
++	if (bp_num == BP_NUM_4) {
++		nor->lock_level_max = LOCK_LEVEL_MAX(bp_num) - 5;
++		chipsize = info->sector_size * info->n_sectors;
++		if ((JEDEC_MFR(info) == SNOR_MFR_MACRONIX)
++				&& (chipsize == _16M))
++			nor->lock_level_max--;
++	} else
++		nor->lock_level_max = LOCK_LEVEL_MAX(bp_num);
++	/* dev_info(nor->dev, "Get the max bp level: [%d]\n",
++	*   nor->lock_level_max); */
++
++	return level;
++}
++
++static void hisi_get_spi_lock_info(struct spi_nor *nor, const struct flash_info *info)
++{
++	unsigned int chipsize;
++	struct device *dev = nor->dev;
++
++	chipsize = info->sector_size * info->n_sectors;
++
++	/* read the BP bit in RDSR to check whether nor is lock or not */
++	switch (JEDEC_MFR(info)) {
++	case SNOR_MFR_GD:
++	case SNOR_MFR_ESMT:
++	case SNOR_MFR_EON:
++	case SNOR_MFR_SPANSION:
++		/* BP bit convert to lock level */
++		nor->level = hisi_bp_to_level(nor, info, BP_NUM_3);
++		break;
++	case SNOR_MFR_WINBOND:
++		/* BP bit convert to lock level */
++		if (chipsize <= _16M)
++			nor->level = hisi_bp_to_level(nor, info, BP_NUM_3);
++		else
++			nor->level = hisi_bp_to_level(nor, info, BP_NUM_4);
++		break;
++	case SNOR_MFR_MACRONIX:
++		/* BP bit convert to lock level */
++		if (chipsize <= _8M)
++			nor->level = hisi_bp_to_level(nor, info, BP_NUM_3);
++		else
++			nor->level = hisi_bp_to_level(nor, info, BP_NUM_4);
++		break;
++	default:
++		goto usage;
++	}
++
++	spi_lock_update_address(nor, info);
++	if (nor->end_addr)
++		dev_info(dev, "Address range [0 => %#x] is locked.\n",
++		nor->end_addr);
++	return;
++usage:
++	dev_err(dev, "The ID: %#x isn't in the BP table,"
++			" Current device can't not protect\n",
++			JEDEC_MFR(info));
++}
++#endif/* CONFIG_HISI_SPI_BLOCK_PROTECT */
++
++static int spi_nor_midx2proto(int midx, enum spi_nor_protocol *proto)
++{
++	switch (midx) {
++	case SNOR_MIDX_SLOW:
++	case SNOR_MIDX_1_1_1:
++		*proto = SNOR_PROTO_1_1_1;
++		break;
++
++	case SNOR_MIDX_1_1_2:
++		*proto = SNOR_PROTO_1_1_2;
++		break;
++
++	case SNOR_MIDX_1_2_2:
++		*proto = SNOR_PROTO_1_2_2;
++		break;
++	case SNOR_MIDX_1_1_4:
++		*proto = SNOR_PROTO_1_1_4;
++		break;
++
++	case SNOR_MIDX_1_4_4:
++		*proto = SNOR_PROTO_1_4_4;
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	return 0;
++}
++
++static int spi_nor_sr3_to_reset(struct spi_nor *nor)
++{
++	int ret;
++	unsigned char val;
++
++	ret = nor->read_reg(nor, SPINOR_OP_RDSR3, &val, 1);
++	if (ret < 0) {
++		dev_err(nor->dev, "error %d reading Status Reg 3.\n", ret);
++		return ret;
++	}
++
++	if (SPI_NOR_GET_RST(val)) {
++		dev_dbg(nor->dev, "Device has worked on RESET#.\n");
++		return 0;
++	}
++
++	dev_dbg(nor->dev, "Start to enable RESET# function.\n");
++	val = SPI_NOR_SET_RST(val);
++
++	nor->write_reg(nor, SPINOR_OP_WRSR3, &val, 1);
++	if (ret < 0) {
++		dev_err(nor->dev, "error while writing Status Reg 3.\n");
++		return ret;
++	}
++
++	dev_dbg(nor->dev, "Enable RESET# function success.\n");
++
++	return 0;
++}
++
++static int spi_nor_reset_pin_enable(struct spi_nor *nor,
++		const struct flash_info *info)
++{
++	switch (JEDEC_MFR(info)) {
++	case SNOR_MFR_WINBOND:
++	case SNOR_MFR_GD:
++		return spi_nor_sr3_to_reset(nor);
++	default:
++		return 0;
++	}
++}
++
++static int spi_nor_setup(struct spi_nor *nor, const struct flash_info *info,
++			 const struct spi_nor_basic_flash_parameter *params,
++			 const struct spi_nor_modes *modes)
++{
++	bool enable_quad_io;
++	u32 rd_modes, wr_modes;
++	const struct spi_nor_erase_type *erase_type;
++	const struct spi_nor_read_op *read;
++	int rd_midx, wr_midx, err = 0;
++
++	rd_modes = modes->rd_modes;
++	wr_modes = modes->wr_modes;
++
++	/* Setup read operation. */
++	rd_midx = fls(params->rd_modes & rd_modes) - 1;
++	if (spi_nor_midx2proto(rd_midx, &nor->read_proto)) {
++		dev_err(nor->dev, "invalid (fast) read\n");
++		return -EINVAL;
++	}
++	read = &params->reads[rd_midx];
++	nor->read_opcode = read->opcode;
++	nor->read_dummy = read->num_mode_clocks + read->num_wait_states;
++
++	/* Set page program op code and protocol. */
++	wr_midx = fls(params->wr_modes & wr_modes) - 1;
++	if (spi_nor_midx2proto(wr_midx, &nor->write_proto)) {
++		dev_err(nor->dev, "invalid page program\n");
++		return -EINVAL;
++	}
++	nor->program_opcode = params->page_programs[wr_midx];
++
++	/* Set sector erase op code and size. */
++	erase_type = &params->erase_types[0];
++#ifdef CONFIG_MTD_SPI_NOR_USE_4K_SECTORS
++	for (i = 1; i < SNOR_MAX_ERASE_TYPES; ++i)
++		if (params->erase_types[i].size == 0x0c)
++			erase_type = &params->erase_types[i];
++#endif
++	nor->erase_opcode = erase_type->opcode;
++	nor->mtd.erasesize = (1 << erase_type->size);
++
++	enable_quad_io = (SNOR_PROTO_DATA_FROM_PROTO(nor->read_proto) == 4 ||
++			  SNOR_PROTO_DATA_FROM_PROTO(nor->write_proto) == 4);
++
++	/* Enable Quad I/O if needed. */
++	if (enable_quad_io && params->enable_quad_io) {
++		err = params->enable_quad_io(nor);
++		if (err) {
++			dev_err(nor->dev,
++				"failed to enable the Quad I/O mode\n");
++			return err;
++		}
++	}
++
++	/*
++	 * Fix erase protocol if needed, read and write protocols should
++	 * already be valid.
++	 */
++	nor->erase_proto = SNOR_PROTO_1_1_1;
++
++	dev_dbg(nor->dev,
++		"(Fast) Read:  opcode=%02Xh, protocol=%03x, mode=%u, wait=%u\n",
++		nor->read_opcode, nor->read_proto,
++		read->num_mode_clocks, read->num_wait_states);
++	dev_dbg(nor->dev,
++		"Page Program: opcode=%02Xh, protocol=%03x\n",
++		nor->program_opcode, nor->write_proto);
++	dev_dbg(nor->dev,
++		"Sector Erase: opcode=%02Xh, protocol=%03x, sector size=%zu\n",
++		nor->erase_opcode, nor->erase_proto, nor->mtd.erasesize);
++
++	return 0;
++}
++
++static int spi_nor_config(struct spi_nor *nor, const struct flash_info *info,
++			 const struct spi_nor_basic_flash_parameter *params,
++			 struct spi_nor_modes *modes)
++{
++	int ret;
++
++	if (params) {
++		ret = spi_nor_setup(nor, info, params, modes);
++		if (ret)
++			return ret;
++	} else if (modes->rd_modes & SNOR_MODE_1_1_4 &&
++				info->flags & SPI_NOR_QUAD_READ) {
++		/*
++		 * This branch is spcially for some devices which can
++		 * not be stated by params, but only SPI_NOR_QUAD_READ,
++		 * it just supports the protocol 1_1_4.
++		 */
++			if (spi_nor_wait_till_ready(nor))
++				return 1;
++
++			ret = set_quad_mode(nor, info);
++			if (ret) {
++				dev_err(nor->dev, "quad mode not supported\n");
++				return ret;
++			}
++			nor->read_proto = SNOR_PROTO_1_1_4;
++			nor->read_opcode = SPINOR_OP_READ_1_1_4;
++			nor->read_dummy = 8;
++	} else if (modes->rd_modes & SNOR_MODE_1_1_2 &&
++			info->flags & SPI_NOR_DUAL_READ) {
++		/*
++		 * This branch is spcially for some devices which can
++		 * not be stated by params, but only SPI_NOR_DUAL_READ,
++		 * it just supports the protocol 1_1_2.
++		 */
++			nor->read_proto = SNOR_PROTO_1_1_2;
++			nor->read_opcode = SPINOR_OP_READ_1_1_2;
++			nor->read_dummy = 8;
++	} else {
++		if (modes->rd_modes & SNOR_MODE_1_1_1) {
++			nor->read_opcode = SPINOR_OP_READ_FAST;
++			nor->read_dummy = 8;
++		} else {
++			nor->read_opcode = SPINOR_OP_READ;
++			nor->read_dummy = 0;
++		}
++	}
++
++	if (!(modes->rd_modes & (SNOR_MODE_1_1_4 | SNOR_MODE_1_4_4))) {
++		ret = spi_nor_reset_pin_enable(nor, info);
++		if (ret < 0) {
++			dev_err(nor->dev, "Enable RESET# fail.\n");
++			return ret;
++		}
++	}
+ 
+ 	return 0;
+ }
+ 
+-int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
++int spi_nor_scan(struct spi_nor *nor, const char *name,
++		 struct spi_nor_modes *modes)
+ {
+-	const struct spi_device_id	*id = NULL;
+-	struct flash_info		*info;
++	const struct spi_nor_basic_flash_parameter *params = NULL;
++	const struct flash_info *info = NULL;
+ 	struct device *dev = nor->dev;
+-	struct mtd_info *mtd = nor->mtd;
+-	struct device_node *np = dev->of_node;
++	struct mtd_info *mtd = &nor->mtd;
++	struct device_node *np = nor->flash_node;
+ 	int ret;
+ 	int i;
+ 
+@@ -926,19 +2137,30 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
+ 	if (ret)
+ 		return ret;
+ 
+-	id = spi_nor_match_id(name);
+-	if (!id)
++	/* Reset SPI protocol for all commands */
++	nor->erase_proto = SNOR_PROTO_1_1_1;
++	nor->read_proto = SNOR_PROTO_1_1_1;
++	nor->write_proto = SNOR_PROTO_1_1_1;
++
++	if (name)
++		info = spi_nor_match_id(name);
++	/* Try to auto-detect if chip name wasn't specified or not found */
++	if (!info)
++		info = spi_nor_read_id(nor);
++	if (IS_ERR_OR_NULL(info))
+ 		return -ENOENT;
+ 
+-	info = (void *)id->driver_data;
+-
+-	if (info->jedec_id) {
+-		const struct spi_device_id *jid;
++	/*
++	 * If caller has specified name of flash model that can normally be
++	 * detected using JEDEC, let's verify it.
++	 */
++	if (name && info->id_len) {
++		const struct flash_info *jinfo;
+ 
+-		jid = nor->read_id(nor);
+-		if (IS_ERR(jid)) {
+-			return PTR_ERR(jid);
+-		} else if (jid != id) {
++		jinfo = spi_nor_read_id(nor);
++		if (IS_ERR(jinfo)) {
++			return PTR_ERR(jinfo);
++		} else if (jinfo != info) {
+ 			/*
+ 			 * JEDEC knows better, so overwrite platform ID. We
+ 			 * can't trust partitions any longer, but we'll let
+@@ -947,28 +2169,37 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
+ 			 * information, even if it's not 100% accurate.
+ 			 */
+ 			dev_warn(dev, "found %s, expected %s\n",
+-				 jid->name, id->name);
+-			id = jid;
+-			info = (void *)jid->driver_data;
++				 jinfo->name, info->name);
++			info = jinfo;
+ 		}
+ 	}
++	if (info->params)
++		params = info->params;
+ 
+ 	mutex_init(&nor->lock);
+ 
++#ifdef CONFIG_HISI_SPI_BLOCK_PROTECT
++	/* NOR block protection support */
++	hisi_get_spi_lock_info(nor, info);
++#else
+ 	/*
+-	 * Atmel, SST and Intel/Numonyx serial nor tend to power
+-	 * up with the software protection bits set
++	 * Atmel, SST, Intel/Numonyx, and others serial NOR tend to power up
++	 * with the software protection bits set
+ 	 */
+ 
+-	if (JEDEC_MFR(info->jedec_id) == CFI_MFR_ATMEL ||
+-	    JEDEC_MFR(info->jedec_id) == CFI_MFR_INTEL ||
+-	    JEDEC_MFR(info->jedec_id) == CFI_MFR_SST) {
++	if (JEDEC_MFR(info) == SNOR_MFR_ATMEL ||
++	    JEDEC_MFR(info) == SNOR_MFR_INTEL ||
++	    JEDEC_MFR(info) == SNOR_MFR_SST ||
++	    info->flags & SPI_NOR_HAS_LOCK) {
+ 		write_enable(nor);
+ 		write_sr(nor, 0);
++		spi_nor_wait_till_ready(nor);
+ 	}
++#endif
+ 
+ 	if (!mtd->name)
+ 		mtd->name = dev_name(dev);
++	mtd->priv = nor;
+ 	mtd->type = MTD_NORFLASH;
+ 	mtd->writesize = 1;
+ 	mtd->flags = MTD_CAP_NORFLASH;
+@@ -976,10 +2207,19 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
+ 	mtd->_erase = spi_nor_erase;
+ 	mtd->_read = spi_nor_read;
+ 
+-	/* nor protection support for STmicro chips */
+-	if (JEDEC_MFR(info->jedec_id) == CFI_MFR_ST) {
++	/* NOR protection support for STmicro/Micron chips and similar */
++	if (JEDEC_MFR(info) == SNOR_MFR_MICRON ||
++	    JEDEC_MFR(info) == SNOR_MFR_WINBOND ||
++		info->flags & SPI_NOR_HAS_LOCK) {
++		nor->flash_lock = stm_lock;
++		nor->flash_unlock = stm_unlock;
++		nor->flash_is_locked = stm_is_locked;
++	}
++
++	if (nor->flash_lock && nor->flash_unlock && nor->flash_is_locked) {
+ 		mtd->_lock = spi_nor_lock;
+ 		mtd->_unlock = spi_nor_unlock;
++		mtd->_is_locked = spi_nor_is_locked;
+ 	}
+ 
+ 	/* sst nor chips use AAI word program */
+@@ -988,9 +2228,10 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
+ 	else
+ 		mtd->_write = spi_nor_write;
+ 
+-	if ((info->flags & USE_FSR) &&
+-	    nor->wait_till_ready == spi_nor_wait_till_ready)
+-		nor->wait_till_ready = spi_nor_wait_till_fsr_ready;
++	if (info->flags & USE_FSR)
++		nor->flags |= SNOR_F_USE_FSR;
++	if (info->flags & SPI_NOR_HAS_TB)
++		nor->flags |= SNOR_F_HAS_SR_TB;
+ 
+ #ifdef CONFIG_MTD_SPI_NOR_USE_4K_SECTORS
+ 	/* prefer "small sector" erase if possible */
+@@ -1017,85 +2258,58 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
+ 	if (np) {
+ 		/* If we were instantiated by DT, use it */
+ 		if (of_property_read_bool(np, "m25p,fast-read"))
+-			nor->flash_read = SPI_NOR_FAST;
++			modes->rd_modes |= SNOR_MODE_1_1_1;
+ 		else
+-			nor->flash_read = SPI_NOR_NORMAL;
++			modes->rd_modes &= ~SNOR_MODE_1_1_1;
+ 	} else {
+ 		/* If we weren't instantiated by DT, default to fast-read */
+-		nor->flash_read = SPI_NOR_FAST;
++		modes->rd_modes |= SNOR_MODE_1_1_1;
+ 	}
+ 
+ 	/* Some devices cannot do fast-read, no matter what DT tells us */
+ 	if (info->flags & SPI_NOR_NO_FR)
+-		nor->flash_read = SPI_NOR_NORMAL;
+-
+-	/* Quad/Dual-read mode takes precedence over fast/normal */
+-	if (mode == SPI_NOR_QUAD && info->flags & SPI_NOR_QUAD_READ) {
+-		ret = set_quad_mode(nor, info->jedec_id);
+-		if (ret) {
+-			dev_err(dev, "quad mode not supported\n");
+-			return ret;
+-		}
+-		nor->flash_read = SPI_NOR_QUAD;
+-	} else if (mode == SPI_NOR_DUAL && info->flags & SPI_NOR_DUAL_READ) {
+-		nor->flash_read = SPI_NOR_DUAL;
+-	}
+-
+-	/* Default commands */
+-	switch (nor->flash_read) {
+-	case SPI_NOR_QUAD:
+-		nor->read_opcode = SPINOR_OP_READ_1_1_4;
+-		break;
+-	case SPI_NOR_DUAL:
+-		nor->read_opcode = SPINOR_OP_READ_1_1_2;
+-		break;
+-	case SPI_NOR_FAST:
+-		nor->read_opcode = SPINOR_OP_READ_FAST;
+-		break;
+-	case SPI_NOR_NORMAL:
+-		nor->read_opcode = SPINOR_OP_READ;
+-		break;
+-	default:
+-		dev_err(dev, "No Read opcode defined\n");
+-		return -EINVAL;
+-	}
++		modes->rd_modes &= ~SNOR_MODE_1_1_1;
+ 
+ 	nor->program_opcode = SPINOR_OP_PP;
+ 
++	/*
++	 * Configure the SPI memory:
++	 * - select op codes for (Fast) Read, Page Program and Sector Erase.
++	 * - set the number of dummy cycles (mode cycles + wait states).
++	 * - set the SPI protocols for register and memory accesses.
++	 * - set the Quad Enable bit if needed (required by SPI x-y-4 protos).
++	 */
++	ret = spi_nor_config(nor, info, params, modes);
++	if (ret)
++		return ret;
++
+ 	if (info->addr_width)
+ 		nor->addr_width = info->addr_width;
+ 	else if (mtd->size > 0x1000000) {
+ 		/* enable 4-byte addressing if the device exceeds 16MiB */
+ 		nor->addr_width = 4;
+-		if (JEDEC_MFR(info->jedec_id) == CFI_MFR_AMD) {
+-			/* Dedicated 4-byte command set */
+-			switch (nor->flash_read) {
+-			case SPI_NOR_QUAD:
+-				nor->read_opcode = SPINOR_OP_READ4_1_1_4;
+-				break;
+-			case SPI_NOR_DUAL:
+-				nor->read_opcode = SPINOR_OP_READ4_1_1_2;
+-				break;
+-			case SPI_NOR_FAST:
+-				nor->read_opcode = SPINOR_OP_READ4_FAST;
+-				break;
+-			case SPI_NOR_NORMAL:
+-				nor->read_opcode = SPINOR_OP_READ4;
+-				break;
+-			}
+-			nor->program_opcode = SPINOR_OP_PP_4B;
+-			/* No small sector erase for 4-byte command set */
+-			nor->erase_opcode = SPINOR_OP_SE_4B;
+-			mtd->erasesize = info->sector_size;
+-		} else
+-			set_4byte(nor, info->jedec_id, 1);
++		if (JEDEC_MFR(info) == SNOR_MFR_SPANSION ||
++		    info->flags & SPI_NOR_4B_OPCODES)
++			spi_nor_set_4byte_opcodes(nor, info);
++		else
++			set_4byte(nor, info, 1);
+ 	} else {
+ 		nor->addr_width = 3;
+ 	}
+ 
+-	nor->read_dummy = spi_nor_read_dummy_cycles(nor);
++	/* choose the suitable clockrate */
++	if (info->clkrate && (modes->rd_modes != SNOR_MODE_1_1_1))
++		nor->clkrate = info->clkrate;
++	else
++		nor->clkrate = 24000000;
++
++	if (nor->addr_width > SPI_NOR_MAX_ADDR_WIDTH) {
++		dev_err(dev, "address width is too large: %u\n",
++			nor->addr_width);
++		return -EINVAL;
++	}
+ 
+-	dev_info(dev, "%s (%lld Kbytes)\n", id->name,
++	dev_info(dev, "%s (%lld Kbytes)\n", info->name,
+ 			(long long)mtd->size >> 10);
+ 
+ 	dev_dbg(dev,
+@@ -1118,11 +2332,11 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
+ }
+ EXPORT_SYMBOL_GPL(spi_nor_scan);
+ 
+-static const struct spi_device_id *spi_nor_match_id(const char *name)
++static const struct flash_info *spi_nor_match_id(const char *name)
+ {
+-	const struct spi_device_id *id = spi_nor_ids;
++	const struct flash_info *id = spi_nor_ids;
+ 
+-	while (id->name[0]) {
++	while (id->name) {
+ 		if (!strcmp(name, id->name))
+ 			return id;
+ 		id++;
+@@ -1130,6 +2344,64 @@ static const struct spi_device_id *spi_nor_match_id(const char *name)
+ 	return NULL;
+ }
+ 
++/******************************************************************************/
++void spi_nor_driver_shutdown(struct spi_nor *nor)
++{
++	/* disable 4-byte addressing if the device exceeds 16MiB */
++	if (nor->addr_width == 4) {
++		const struct flash_info *info = NULL;
++
++		info = spi_nor_read_id(nor);
++		set_4byte(nor, info, 0);
++	}
++	return;
++}
++
++#ifdef CONFIG_PM
++/******************************************************************************/
++int spi_nor_suspend(struct spi_nor *nor, pm_message_t state)
++{
++	return spi_nor_wait_till_ready(nor);
++}
++
++/******************************************************************************/
++int spi_nor_resume(struct spi_nor *nor)
++{
++	int ret;
++	const struct flash_info *info = NULL;
++	const struct spi_nor_basic_flash_parameter *params = NULL;
++	struct spi_nor_modes modes = {
++		.rd_modes = SNOR_MODE_SLOW,
++		.wr_modes = SNOR_MODE_1_1_1,
++	};
++
++	modes.rd_modes |= SNOR_MODE_1_1_1
++			| SNOR_MODE_1_1_2
++			| SNOR_MODE_1_2_2;
++#ifndef CONFIG_CLOSE_SPI_8PIN_4IO
++	modes.rd_modes |= SNOR_MODE_1_1_4 | SNOR_MODE_1_4_4;
++	modes.wr_modes |= SNOR_MODE_1_1_4 | SNOR_MODE_1_4_4;
++#endif
++
++	if (!info)
++		info = spi_nor_read_id(nor);
++
++	/* Quad mode takes precedence over fast/normal */
++	if (info->params)
++		params = info->params;
++
++	ret = spi_nor_config(nor, info, params, &modes);
++	if (ret)
++		return ret;
++
++	/* enable 4-byte addressing if the device exceeds 16MiB */
++	if (nor->addr_width == 4 && JEDEC_MFR(info) != SNOR_MFR_SPANSION)
++		set_4byte(nor, info, 1);
++
++	return 0;
++}
++#endif /* End of CONFIG_PM */
++
+ MODULE_LICENSE("GPL");
+ MODULE_AUTHOR("Huang Shijie <shijie8@gmail.com>");
+ MODULE_AUTHOR("Mike Lavender");
+diff --git a/drivers/net/ethernet/hisilicon/Kconfig b/drivers/net/ethernet/hisilicon/Kconfig
+index e942173..1389b6c 100644
+--- a/drivers/net/ethernet/hisilicon/Kconfig
++++ b/drivers/net/ethernet/hisilicon/Kconfig
+@@ -24,4 +24,19 @@ config HIX5HD2_GMAC
+ 	help
+ 	  This selects the hix5hd2 mac family network device.
+ 
++config HISI_FEMAC
++	tristate "Hisilicon Fast Ethernet MAC device support"
++	depends on HAS_IOMEM
++	select PHYLIB
++	select RESET_CONTROLLER
++	help
++	  This selects the Hisilicon Fast Ethernet MAC device(FEMAC).
++	  The FEMAC receives and transmits data over Ethernet
++	  ports at 10/100 Mbps in full-duplex or half-duplex mode.
++	  The FEMAC exchanges data with the CPU, and supports
++	  the energy efficient Ethernet (EEE).
++
++source "drivers/net/ethernet/hisilicon/higmac/Kconfig"
++source "drivers/net/ethernet/hisilicon/hieth/Kconfig"
++
+ endif # NET_VENDOR_HISILICON
+diff --git a/drivers/net/ethernet/hisilicon/Makefile b/drivers/net/ethernet/hisilicon/Makefile
+index 9175e84..75126b4 100644
+--- a/drivers/net/ethernet/hisilicon/Makefile
++++ b/drivers/net/ethernet/hisilicon/Makefile
+@@ -3,3 +3,6 @@
+ #
+ 
+ obj-$(CONFIG_HIX5HD2_GMAC) += hix5hd2_gmac.o
++obj-$(CONFIG_HISI_FEMAC) += hisi_femac.o
++obj-$(CONFIG_HIETH_GMAC) += higmac/
++obj-$(CONFIG_HIETH_SWITCH_FABRIC) += hieth/
+diff --git a/drivers/net/ethernet/hisilicon/hieth/Kconfig b/drivers/net/ethernet/hisilicon/hieth/Kconfig
+new file mode 100644
+index 0000000..2c359ce
+--- /dev/null
++++ b/drivers/net/ethernet/hisilicon/hieth/Kconfig
+@@ -0,0 +1,57 @@
++#
++# hieth family network device configuration
++#
++
++menuconfig HIETH_SWITCH_FABRIC
++	tristate "hieth(switch fabric) family network device support"
++	select PHYLIB
++	select RESET_CONTROLLER
++	help
++	  This selects the hieth family network device.
++	  The hieth switch fabric (SF) receives and transmits data over two Ethernet
++	  ports at 10/100 Mbit/s in full-duplex or half-duplex mode.
++	  The Ethernet port exchanges data with the CPU port, and supports
++	  the energy efficient Ethernet (EEE).
++
++if HIETH_SWITCH_FABRIC
++
++config HIETH_MAX_RX_POOLS
++	int "hieth max rx pool size"
++	default "1024"
++	help
++	  hieth max static rx pool size.
++
++config TX_FLOW_CTRL_SUPPORT
++	bool "tx flow ctrl supported"
++	default y
++	help
++	  Tx flow ctrl supported, default is enabled.
++	  When we has no buffer to receive packet,
++	  we will send pause frame.
++	  Rx flow ctrl default is enabled, cannot be disabled.
++
++config TX_FLOW_CTRL_ACTIVE_THRESHOLD
++	int "tx flow ctrl active threshold"
++	default "3"
++	range 1 31
++	help
++	  The threshold for activing tx flow ctrl.
++	  When the left amount of receive queue descriptors is below this threshold,
++	  hardware will send pause frame immediately.
++	  We advise this value is set between 1 and 10. Too bigger is not a good choice.
++	  This value must be smaller than tx flow ctrl deactive threshold.
++
++config TX_FLOW_CTRL_DEACTIVE_THRESHOLD
++	int "tx flow ctrl deactive threshold"
++	default "5"
++	range 1 31
++	help
++	  The threshold for deactiving tx flow ctrl.
++	  When the left amount of receive queue descriptors is above or equal with this threshold,
++	  hardware will exit flow control state.
++	  We advise this value is set between 1 and 10. Too bigger is not a good choice.
++	  This value must be larger than tx flow ctrl active threshold.
++
++endif # HIETH_SWITCH_FABRIC
++
++#vim: set ts=8 sw=8 tw=78:
+diff --git a/drivers/net/ethernet/hisilicon/hieth/Makefile b/drivers/net/ethernet/hisilicon/hieth/Makefile
+new file mode 100644
+index 0000000..28ddee5
+--- /dev/null
++++ b/drivers/net/ethernet/hisilicon/hieth/Makefile
+@@ -0,0 +1,5 @@
++#
++# Makefile for the hisilicon hieth device drivers.
++#
++
++obj-$(CONFIG_HIETH_SWITCH_FABRIC) += mdio.o hieth.o phy.o autoeee.o proc.o
+diff --git a/drivers/net/ethernet/hisilicon/hieth/autoeee.c b/drivers/net/ethernet/hisilicon/hieth/autoeee.c
+new file mode 100644
+index 0000000..970ea04
+--- /dev/null
++++ b/drivers/net/ethernet/hisilicon/hieth/autoeee.c
+@@ -0,0 +1,260 @@
++#include <linux/phy.h>
++#include "phy.h"
++#include "hieth.h"
++
++/*----------------------------Macro definition-------------------------------*/
++#define NO_EEE          0
++#define MAC_EEE         1
++#define PHY_EEE         2
++#define PARTNER_EEE     2
++
++#define debug(fmt...)
++struct phy_info {
++	char *name;
++	int phy_id;
++	char eee_available;/* eee support by this phy */
++	int (*eee_init)(struct phy_device *phy_dev);
++};
++
++/* GMAC register definition */
++#define EEE_ENABLE		0x488
++#define BIT_EEE_ENABLE		(1 << 0)
++#define EEE_TIMER		0x48C
++#define EEE_LINK_STATUS		0x490
++#define BIT_PHY_LINK_STATUS	(1 << 0)
++#define EEE_TIME_CLK_CNT	0x494
++
++/* ----------------------------phy register-------------------------------*/
++/* MMD: MDIO Manageable Device */
++#define MACR		0x0D
++#define MAADR		0x0E
++#define EEE_DEV		0x3
++#define EEE_CAPABILITY	0x14
++#define	EEELPAR_DEV	0x7
++#define EEELPAR		0x3D	/* EEE link partner ability register */
++#define EEE_ADVERTISE	0x3c
++#define LP_1000BASE_EEE	(1 << 2)
++#define LP_100BASE_EEE	(1 << 1)
++
++static struct phy_info phy_info_table[];
++
++static struct phy_info *phy_search_ids(int phy_id)
++{
++	int i;
++	struct phy_info *fit_info = NULL;
++
++	for (i = 0; phy_info_table[i].name != NULL; i++) {
++		if (phy_id == phy_info_table[i].phy_id)
++			fit_info = &phy_info_table[i];
++	}
++
++	return fit_info;
++}
++
++static inline int phy_mmd_read(struct phy_device *phy_dev,
++			       u32 mmd_device, u32 regnum)
++{
++	phy_write(phy_dev, MACR, mmd_device);/* function = 00 address */
++	phy_write(phy_dev, MAADR, regnum);
++	phy_write(phy_dev, MACR, 0x4000 | mmd_device);/* function = 01 data */
++
++	return phy_read(phy_dev, MAADR);
++}
++
++static inline int phy_mmd_write(struct phy_device *phy_dev,
++				u32 mmd_device, u32 regnum, u16 val)
++{
++	phy_write(phy_dev, MACR, mmd_device);/* function = 00 address */
++	phy_write(phy_dev, MAADR, regnum);
++	phy_write(phy_dev, MACR, 0x4000 | mmd_device);/* function = 01 data */
++
++	return phy_write(phy_dev, MAADR, val);
++}
++
++static int smsc_lan8740_init(struct phy_device *phy_dev)
++{
++	static int first_time;
++	int v, eee_type = 0;
++
++	if (!first_time) {
++		/* Realtek LAN 8740 start to enable eee */
++		int eee_lan;
++
++		eee_lan	= phy_read(phy_dev, 0x10);
++		eee_lan |= 0x4;
++		phy_write(phy_dev, 0x10, eee_lan);
++		eee_lan = phy_read(phy_dev, 0x10);
++		debug("eee enable bit[45?] :%x\n", eee_lan);
++		/* auto negotiate after enable eee*/
++		eee_lan = phy_read(phy_dev, 0x0);
++		eee_lan |= 0x200;
++		phy_write(phy_dev, 0x0, eee_lan);
++		first_time = 1;
++	}
++
++	v = phy_mmd_read(phy_dev, EEELPAR_DEV, EEELPAR);
++	debug("EEELPAR = 0x%x\n", v);
++
++	if (v & LP_100BASE_EEE)
++		eee_type |= HIETH_P_MAC_PORTSET_SPD_100M;
++
++	return eee_type;
++}
++
++#define RTL8211EG_MAC   0
++#if RTL8211EG_MAC
++static int rtl8211EG_mac_init(struct phy_device *phy_dev)
++{
++	static int first_time_rtl;
++	/* Realtek 8211EG start reset to change eee to mac */
++	int v, eee_type = 0;
++
++	if (!first_time_rtl) {
++		int tmp = 0;
++
++		phy_write(phy_dev, 0x1f, 0x0);
++		phy_write(phy_dev, MII_BMCR, BMCR_RESET);       /* reset phy */
++		do {            /* wait phy restart over */
++			udelay(1);
++			tmp = phy_read(phy_dev, MII_BMSR);
++			/* no need to wait AN finished */
++			tmp &= (BMSR_ANEGCOMPLETE | BMSR_ANEGCAPABLE);
++		} while (!tmp);
++
++		phy_write(phy_dev, 0x1f, 0x7);
++		phy_write(phy_dev, 0x1e, 0x20);
++		phy_write(phy_dev, 0x1b, 0xa03a);
++		phy_write(phy_dev, 0x1f, 0x0);
++
++		first_time_rtl = 1;
++	}
++
++	v = phy_mmd_read(phy_dev, EEELPAR_DEV, EEELPAR);
++
++	if (v & LP_100BASE_EEE)
++		eee_type |= HIETH_P_MAC_PORTSET_SPD_100M;
++
++	return eee_type;
++}
++#else
++static int rtl8211EG_init(struct phy_device *phy_dev)
++{
++	int eee_type = 0, v;
++
++	v = phy_mmd_read(phy_dev, EEELPAR_DEV, EEELPAR);
++	debug("EEELPAR = 0x%x\n", v);
++
++	if (v & LP_100BASE_EEE)
++		eee_type |= HIETH_P_MAC_PORTSET_SPD_100M;
++
++	return eee_type;
++}
++#endif
++
++static int festa_v200_init(struct phy_device *phy_dev)
++{
++	static int first_time_init;
++	int v, eee_type = 0;
++
++	if (!first_time_init) {
++		/* EEE_CAPABILITY register: support 100M-BaseT */
++		v = phy_mmd_read(phy_dev, EEE_DEV, EEE_CAPABILITY);
++		phy_mmd_write(phy_dev, EEE_DEV, EEE_CAPABILITY, v|(1<<1));
++
++		/* EEE_ADVERTISEMENT register: advertising 100M-BaseT */
++		v = phy_mmd_read(phy_dev, EEELPAR_DEV, EEE_ADVERTISE);
++		phy_mmd_write(phy_dev, EEELPAR_DEV, EEE_ADVERTISE, v|(1<<1));
++
++		v = phy_read(phy_dev, MII_BMCR);
++		v |= (BMCR_ANENABLE | BMCR_ANRESTART);
++		phy_write(phy_dev, MII_BMCR, v);/* auto-neg restart */
++
++		first_time_init = 1;
++	}
++
++	v = phy_mmd_read(phy_dev, EEELPAR_DEV, EEELPAR);
++	debug("EEELPAR = 0x%x\n", v);
++
++	if (v & LP_100BASE_EEE)
++		eee_type |= HIETH_P_MAC_PORTSET_SPD_100M;
++
++	return eee_type;
++}
++
++static struct phy_info phy_info_table[] = {
++	/* phy_name		phy_id	eee_available	phy_driver */
++	/* SMSC */
++	{"SMSC LAN8740", 0x0007c110,  MAC_EEE, &smsc_lan8740_init},
++	/* Realtek */
++#if RTL8211EG_MAC
++	{"Realtek 8211EG", 0x001cc915, MAC_EEE, &rtl8211EG_mac_init},
++#else
++	{"Realtek 8211EG", 0x001cc915, PHY_EEE, &rtl8211EG_init},
++#endif
++	{"Festa V200", HISILICON_PHY_ID_FESTAV200, MAC_EEE, &festa_v200_init},
++	{"Festa V300", HISILICON_PHY_ID_FESTAV300, MAC_EEE, &festa_v200_init},
++	{0, 0, 0, 0},
++};
++
++void hieth_autoeee_init(struct hieth_netdev_priv *priv, int link_stat)
++{
++	int phy_id = priv->phy->phy_id;
++	struct phy_info *phy_info;
++
++	if (priv->eee_init)
++		goto eee_init;
++
++	phy_info = phy_search_ids(phy_id);
++	if (phy_info) {
++		int eee_available, lp_eee_capable, v;
++
++		eee_available = phy_info->eee_available;
++			debug("fit phy_id:0x%x, phy_name:%s, eee:%d\n",
++			      phy_info->phy_id, phy_info->name, eee_available);
++
++		if (!eee_available)
++			goto not_support;
++
++		if (eee_available == PHY_EEE) {
++			debug("enter phy-EEE mode\n");
++			v = readl(priv->glb_base + EEE_ENABLE);
++			v &= ~BIT_EEE_ENABLE;/* disable auto-EEE */
++			writel(v, priv->glb_base + EEE_ENABLE);
++			return;
++		}
++
++		priv->eee_init = phy_info->eee_init;
++eee_init:
++		lp_eee_capable = priv->eee_init(priv->phy);
++		if (link_stat & HIETH_P_MAC_PORTSET_LINKED) {
++			if (lp_eee_capable & link_stat) {
++				/* EEE_1us: 0x7c for 125M */
++				writel(0x7c, priv->glb_base + EEE_TIME_CLK_CNT);
++				writel(0x4002710, priv->glb_base + EEE_TIMER);
++
++				v = readl(priv->glb_base + EEE_LINK_STATUS);
++				v |= 0x3 << 1;/* auto EEE and ... */
++				v |= BIT_PHY_LINK_STATUS;/* phy linkup */
++				writel(v, priv->glb_base + EEE_LINK_STATUS);
++
++				v = readl(priv->glb_base + EEE_ENABLE);
++				v |= BIT_EEE_ENABLE;/* enable EEE */
++				writel(v, priv->glb_base + EEE_ENABLE);
++
++				debug("enter auto-EEE mode\n");
++			} else {
++				debug("link partner not support EEE\n");
++			}
++		} else {
++			v = readl(priv->glb_base + EEE_LINK_STATUS);
++			v &= ~(BIT_PHY_LINK_STATUS);/* phy linkdown */
++			writel(v, priv->glb_base + EEE_LINK_STATUS);
++		}
++
++		return;
++	}
++
++not_support:
++	priv->eee_init = NULL;
++	debug("non-EEE mode\n");
++}
+diff --git a/drivers/net/ethernet/hisilicon/hieth/hieth.c b/drivers/net/ethernet/hisilicon/hieth/hieth.c
+new file mode 100644
+index 0000000..8b8ad4d
+--- /dev/null
++++ b/drivers/net/ethernet/hisilicon/hieth/hieth.c
+@@ -0,0 +1,2016 @@
++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
++
++#include <linux/module.h>
++#include <linux/interrupt.h>
++#include <linux/etherdevice.h>
++#include <linux/platform_device.h>
++#include <linux/of_net.h>
++#include <linux/of_mdio.h>
++#include <linux/clk.h>
++#include <linux/reset.h>
++#include <linux/circ_buf.h>
++#include <linux/if_ether.h>
++#include <linux/if_vlan.h>
++#include <linux/ip.h>
++#include <net/ipv6.h>
++#include <linux/tcp.h>
++#include <net/protocol.h>
++#include "hieth.h"
++#include "mdio.h"
++#include "proc.h"
++#include "tso.h"
++
++#ifdef HIETH_TSO_SUPPORTED
++#define E_MAC_TX_FAIL   2
++#define E_MAC_SW_GSO    3
++#endif
++
++#define FCS_BYTES       4
++
++/*----------------------------Global variable-------------------------------*/
++struct hieth_phy_param_s hieth_phy_param[HIETH_MAX_PORT];
++
++#define FC_ACTIVE_MIN           1
++#define FC_ACTIVE_DEFAULT       3
++#define FC_ACTIVE_MAX           31
++#define FC_DEACTIVE_MIN         1
++#define FC_DEACTIVE_DEFAULT     5
++#define FC_DEACTIVE_MAX         31
++
++/*----------------------------Local variable-------------------------------*/
++static struct net_device *hieth_devs_save[HIETH_MAX_PORT] = { NULL, NULL };
++static struct hieth_netdev_priv hieth_priv;
++
++/* real port count */
++static int hieth_real_port_cnt;
++/* default, eth enable */
++static bool hieth_disable;
++/* autoeee, enabled by dts */
++static bool hieth_enable_autoeee;
++
++static int __init hieth_noeth(char *str)
++{
++	hieth_disable = true;
++
++	return 0;
++}
++
++early_param("noeth", hieth_noeth);
++
++#include "pm.c"
++
++static int hieth_hw_set_macaddress(struct hieth_netdev_priv *priv,
++				   unsigned char *mac)
++{
++	u32 reg;
++
++	if (priv->port == HIETH_PORT_1) {
++		reg = hieth_readl(priv->glb_base, HIETH_GLB_DN_HOSTMAC_ENA);
++		reg |= HIETH_GLB_DN_HOSTMAC_ENA_BIT;
++		hieth_writel(priv->glb_base, reg, HIETH_GLB_DN_HOSTMAC_ENA);
++	}
++
++	reg = mac[1] | (mac[0] << 8);
++	if (priv->port == HIETH_PORT_0)
++		hieth_writel(priv->glb_base, reg, HIETH_GLB_HOSTMAC_H16);
++	else
++		hieth_writel(priv->glb_base, reg, HIETH_GLB_DN_HOSTMAC_H16);
++
++	reg = mac[5] | (mac[4] << 8) | (mac[3] << 16) | (mac[2] << 24);
++	if (priv->port == HIETH_PORT_0)
++		hieth_writel(priv->glb_base, reg, HIETH_GLB_HOSTMAC_L32);
++	else
++		hieth_writel(priv->glb_base, reg, HIETH_GLB_DN_HOSTMAC_L32);
++
++	return 0;
++}
++
++static void hieth_irq_enable(struct hieth_netdev_priv *priv, int irqs)
++{
++	u32 val;
++
++	local_lock(priv);
++	val = hieth_readl(priv->glb_base, HIETH_GLB_IRQ_ENA);
++	hieth_writel(priv->glb_base, val | irqs, HIETH_GLB_IRQ_ENA);
++	local_unlock(priv);
++}
++
++static void hieth_irq_disable(struct hieth_netdev_priv *priv, int irqs)
++{
++	u32 val;
++
++	local_lock(priv);
++	val = hieth_readl(priv->glb_base, HIETH_GLB_IRQ_ENA);
++	hieth_writel(priv->glb_base, val & (~irqs), HIETH_GLB_IRQ_ENA);
++	local_unlock(priv);
++}
++
++static void hieth_clear_irqstatus(struct hieth_netdev_priv *priv, int irqs)
++{
++	local_lock(priv);
++	hieth_writel(priv->glb_base, irqs, HIETH_GLB_IRQ_RAW);
++	local_unlock(priv);
++}
++
++static void hieth_set_flow_ctrl(struct hieth_netdev_priv *priv)
++{
++	unsigned int pause_en;
++	unsigned int tx_flow_ctrl;
++
++	tx_flow_ctrl = hieth_readl(priv->port_base, HIETH_P_GLB_FC_LEVEL);
++	tx_flow_ctrl &= ~BITS_THR_MASK;
++	tx_flow_ctrl |= priv->tx_pause_deactive_thresh;
++	tx_flow_ctrl &= ~(BITS_THR_MASK << BITS_FC_ACTIVE_THR_OFFSET);
++	tx_flow_ctrl |= priv->tx_pause_active_thresh <<
++				BITS_FC_ACTIVE_THR_OFFSET;
++
++	pause_en = hieth_readl(priv->port_base, HIETH_P_MAC_SET);
++
++	if (priv->tx_pause_en) {
++		tx_flow_ctrl |= BIT_FC_EN;
++		pause_en |= BIT_PAUSE_EN;
++	} else {
++		tx_flow_ctrl &= ~BIT_FC_EN;
++		pause_en &= ~BIT_PAUSE_EN;
++	}
++
++	hieth_writel(priv->port_base, tx_flow_ctrl, HIETH_P_GLB_FC_LEVEL);
++
++	hieth_writel(priv->port_base, pause_en, HIETH_P_MAC_SET);
++}
++
++static int hieth_port_reset(struct hieth_netdev_priv *priv)
++{
++	u32 rst_bit = 0;
++	u32 val;
++
++	if (hieth_real_port_cnt == 1) {
++		rst_bit = HIETH_GLB_SOFT_RESET_ALL;
++	} else {
++		if (priv->port == HIETH_PORT_0)
++			rst_bit |= HIETH_GLB_SOFT_RESET_P0;
++		else if (priv->port == HIETH_PORT_1)
++			rst_bit |= HIETH_GLB_SOFT_RESET_P1;
++		else
++			BUG();
++	}
++
++	val = hieth_readl(priv->glb_base, HIETH_GLB_SOFT_RESET);
++
++	val |= rst_bit;
++	hieth_writel(priv->glb_base, val, HIETH_GLB_SOFT_RESET);
++	usleep_range(1000, 10000);
++	val &= ~rst_bit;
++	hieth_writel(priv->glb_base, val, HIETH_GLB_SOFT_RESET);
++	usleep_range(1000, 10000);
++	val |= rst_bit;
++	hieth_writel(priv->glb_base, val, HIETH_GLB_SOFT_RESET);
++	usleep_range(1000, 10000);
++	val &= ~rst_bit;
++	hieth_writel(priv->glb_base, val, HIETH_GLB_SOFT_RESET);
++
++	return 0;
++}
++
++static void hieth_port_init(struct hieth_netdev_priv *priv)
++{
++	u32 val;
++	int phy_intf = (priv->phy_mode == PHY_INTERFACE_MODE_MII ?
++			HIETH_P_MAC_PORTSEL_MII : HIETH_P_MAC_PORTSEL_RMII);
++
++	/* set little endian */
++	val = hieth_readl(priv->glb_base, HIETH_GLB_ENDIAN_MOD);
++	val |= HIETH_GLB_ENDIAN_MOD_IN;
++	val |= HIETH_GLB_ENDIAN_MOD_OUT;
++	hieth_writel(priv->glb_base, val, HIETH_GLB_ENDIAN_MOD);
++
++	/* set stat ctrl to cpuset, and MII or RMII mode */
++	hieth_writel(priv->port_base, phy_intf | HIETH_P_MAC_PORTSEL_STAT_CPU,
++		     HIETH_P_MAC_PORTSEL);
++
++	/*clear all interrupt status */
++	hieth_clear_irqstatus(priv, UD_BIT_NAME(HIETH_GLB_IRQ_ENA_BIT));
++
++	/*disable interrupts */
++	hieth_irq_disable(priv, UD_BIT_NAME(HIETH_GLB_IRQ_ENA_BIT) |
++			  UD_BIT_NAME(HIETH_GLB_IRQ_ENA_IEN));
++
++#ifdef HIETH_TSO_SUPPORTED
++	/* enable TSO debug for error handle */
++	val = hieth_readl(priv->port_base, HIETH_P_GLB_TSO_DBG_EN);
++	val |= BITS_TSO_DBG_EN;
++	hieth_writel(priv->port_base, val, HIETH_P_GLB_TSO_DBG_EN);
++#endif
++
++	/* disable vlan, enable UpEther<->CPU */
++	val = hieth_readl(priv->glb_base, HIETH_GLB_FWCTRL);
++	val &= ~HIETH_GLB_FWCTRL_VLAN_ENABLE;
++	val |= UD_BIT_NAME(HIETH_GLB_FWCTRL_FW2CPU_ENA);
++	val &= ~(UD_BIT_NAME(HIETH_GLB_FWCTRL_FWALL2CPU));
++	hieth_writel(priv->glb_base, val, HIETH_GLB_FWCTRL);
++	val = hieth_readl(priv->glb_base, HIETH_GLB_MACTCTRL);
++	val |= UD_BIT_NAME(HIETH_GLB_MACTCTRL_BROAD2CPU);
++	val |= UD_BIT_NAME(HIETH_GLB_MACTCTRL_MACT_ENA);
++	hieth_writel(priv->glb_base, val, HIETH_GLB_MACTCTRL);
++
++	/* set pre count limit */
++	val = hieth_readl(priv->port_base, HIETH_P_MAC_TX_IPGCTRL);
++	val &= ~HIETH_P_MAC_TX_IPGCTRL_PRE_CNT_LMT_MSK;
++	val |= 0;
++	hieth_writel(priv->port_base, val, HIETH_P_MAC_TX_IPGCTRL);
++
++	/* set max receive length */
++	val = hieth_readl(priv->port_base, HIETH_P_MAC_SET);
++	val &= ~HIETH_P_MAC_SET_LEN_MAX_MSK;
++	val |= HIETH_P_MAC_SET_LEN_MAX(HIETH_MAX_RCV_LEN);
++	hieth_writel(priv->port_base, val, HIETH_P_MAC_SET);
++
++	hieth_set_flow_ctrl(priv);
++}
++
++static void hieth_set_hwq_depth(struct hieth_netdev_priv *priv)
++{
++	u32 val;
++
++	val = hieth_readl(priv->port_base, HIETH_P_GLB_QLEN_SET);
++	val &= ~HIETH_P_GLB_QLEN_SET_TXQ_DEP_MSK;
++	val |= HIETH_P_GLB_QLEN_SET_TXQ_DEP(priv->depth.hw_xmitq);
++	val &= ~HIETH_P_GLB_QLEN_SET_RXQ_DEP_MSK;
++	val |= HIETH_P_GLB_QLEN_SET_RXQ_DEP(HIETH_MAX_QUEUE_DEPTH -
++					    priv->depth.hw_xmitq);
++	hieth_writel(priv->port_base, val, HIETH_P_GLB_QLEN_SET);
++}
++
++static int hieth_hw_xmitq_ready(struct hieth_netdev_priv *priv)
++{
++	int ret;
++
++	local_lock(priv);
++	ret = hieth_readl(priv->port_base, HIETH_P_GLB_RO_QUEUE_STAT);
++	ret &= HIETH_P_GLB_RO_QUEUE_STAT_XMITQ_RDY_MSK;
++	local_unlock(priv);
++
++	return ret;
++}
++
++#ifdef HIETH_TSO_SUPPORTED
++#ifdef HIETH_TSO_DEBUG
++unsigned int id_send;
++unsigned int id_free;
++struct send_pkt_info    pkt_rec[MAX_RECORD];
++#endif
++#endif
++
++#ifdef HIETH_TSO_SUPPORTED
++static struct sk_buff *hieth_xmit_release_gso(struct hieth_netdev_priv *priv)
++{
++	struct sk_buff *skb;
++	struct tx_pkt_info *txq_cur;
++	int pkt_type;
++
++	txq_cur = priv->txq + priv->txq_tail;
++
++	skb = txq_cur->skb;
++
++	if (txq_cur->tx.info.sg_flag)
++		pkt_type = PKT_SG;
++	else
++		pkt_type = PKT_NORMAL;
++
++	if (pkt_type == PKT_NORMAL) {
++		dma_addr_t dma_addr;
++
++		dma_addr = txq_cur->tx_addr;
++		dma_unmap_single(priv->dev, dma_addr, skb->len, DMA_TO_DEVICE);
++	} else { /* TSO pkt */
++		struct dma_tx_desc *desc_cur;
++		unsigned int desc_offset;
++		int nfrags = skb_shinfo(skb)->nr_frags;
++		int i;
++
++		desc_offset = txq_cur->sg_desc_offset;
++		BUG_ON(desc_offset != priv->sg_tail);
++		desc_cur = priv->dma_tx + desc_offset;
++
++		dma_unmap_single(priv->dev, desc_cur->linear_addr,
++				 desc_cur->linear_len, DMA_TO_DEVICE);
++		for (i = 0; i < nfrags; i++) {
++			dma_unmap_page(priv->dev, desc_cur->frags[i].addr,
++				       desc_cur->frags[i].size, DMA_TO_DEVICE);
++		}
++
++		priv->sg_tail = (priv->sg_tail + 1) % priv->q_size;
++	}
++
++	txq_cur->skb = NULL;
++	priv->txq_tail = (priv->txq_tail + 1) % priv->q_size;
++
++#ifdef HIETH_TSO_DEBUG
++	pkt_rec[id_free].status = 0;
++	id_free++;
++	if (id_free == MAX_RECORD)
++		id_free = 0;
++#endif
++
++	return skb;
++}
++#endif
++
++static int hieth_xmit_release_skb(struct hieth_netdev_priv *priv)
++{
++	u32 val;
++	int ret = 0;
++	struct sk_buff *skb;
++
++	local_lock(priv);
++
++	val = hieth_readl(priv->port_base, HIETH_P_GLB_RO_QUEUE_STAT) &
++			  HIETH_P_GLB_RO_QUEUE_STAT_XMITQ_CNT_INUSE_MSK;
++	while (val < priv->tx_hw_cnt) {
++#ifdef HIETH_TSO_SUPPORTED
++		skb = hieth_xmit_release_gso(priv);
++#else
++		skb = skb_dequeue(&priv->tx_hw);
++#endif
++
++		if (!skb) {
++			pr_err("hw_xmitq_cnt_inuse=%d, tx_hw_cnt=%d\n",
++			       val, priv->tx_hw_cnt);
++
++			BUG();
++			ret = -1;
++			goto error_exit;
++		}
++		dev_kfree_skb_any(skb);
++
++		priv->tx_hw_cnt--;
++
++		val = hieth_readl(priv->port_base, HIETH_P_GLB_RO_QUEUE_STAT) &
++				HIETH_P_GLB_RO_QUEUE_STAT_XMITQ_CNT_INUSE_MSK;
++	}
++
++error_exit:
++	local_unlock(priv);
++	return ret;
++}
++
++#ifdef HIETH_TSO_SUPPORTED
++void hieth_get_tso_err_info(struct hieth_netdev_priv *priv)
++{
++	unsigned int reg_addr, reg_tx_info, reg_tx_err;
++	unsigned int sg_index;
++	struct dma_tx_desc *sg_desc;
++	int *sg_word;
++	int i;
++
++	reg_addr = hieth_readl(priv->port_base, HIETH_P_GLB_TSO_DBG_ADDR);
++	reg_tx_info = hieth_readl(priv->port_base, HIETH_P_GLB_TSO_DBG_TX_INFO);
++	reg_tx_err = hieth_readl(priv->port_base, HIETH_P_GLB_TSO_DBG_TX_ERR);
++
++	WARN(1, "tx err=0x%x, tx_info=0x%x, addr=0x%x\n",
++	     reg_tx_err, reg_tx_info, reg_addr);
++
++	sg_index = (reg_addr - priv->dma_tx_phy) / sizeof(struct dma_tx_desc);
++	sg_desc = priv->dma_tx + sg_index;
++	sg_word = (int *)sg_desc;
++	for (i = 0; i < sizeof(struct dma_tx_desc) / sizeof(int); i++)
++		pr_err("%s,%d: sg_desc word[%d]=0x%x\n",
++		       __func__, __LINE__, i, sg_word[i]);
++
++	/* restart MAC to transmit next packet */
++	hieth_irq_disable(priv, UD_BIT_NAME(HIETH_INT_TX_ERR));
++#if 0
++	hieth_readl(priv, HIETH_P_GLB_TSO_DBG_STATE));
++	hieth_irq_enable(priv, UD_BIT_NAME(HIETH_INT_TX_ERR));
++#endif
++}
++
++static int hieth_xmit_real_send(struct hieth_netdev_priv *priv,
++				struct sk_buff *skb);
++
++static int hieth_sw_gso(struct hieth_netdev_priv *priv, struct sk_buff *skb)
++{
++	struct sk_buff *segs, *curr_skb;
++	struct net_device *ndev = hieth_devs_save[priv->port];
++	int ret;
++
++	segs = skb_gso_segment(skb, ndev->features &
++			~(NETIF_F_ALL_CSUM | NETIF_F_GSO_SOFTWARE));
++	if (IS_ERR(segs))
++		goto sw_tso_end;
++
++	do {
++		curr_skb = segs;
++		segs = segs->next;
++		curr_skb->next = NULL;
++		ret = hieth_xmit_real_send(priv, curr_skb);
++		if (ret < 0) {
++			dev_kfree_skb(curr_skb);
++			while (segs != NULL) {
++				curr_skb = segs;
++				segs = segs->next;
++				curr_skb->next = NULL;
++				dev_kfree_skb(curr_skb);
++			}
++			goto sw_tso_end;
++		}
++	} while (segs);
++
++sw_tso_end:
++	dev_kfree_skb(skb);
++
++	return 0;
++}
++
++int hieth_get_pkt_info(struct sk_buff *skb, struct tx_pkt_info *txq_cur)
++{
++	int nfrags = skb_shinfo(skb)->nr_frags;
++
++	__be16 l3_proto; /* level 3 protocol */
++	unsigned int l4_proto = IPPROTO_MAX;
++	unsigned char coe_enable = 0;
++
++	if (skb->ip_summed == CHECKSUM_PARTIAL)
++		coe_enable = 1;
++
++	txq_cur->tx.val = 0;
++
++	if (skb_is_gso(skb)) {
++		txq_cur->tx.info.tso_flag = 1;
++		txq_cur->tx.info.sg_flag = 1;
++	} else if (nfrags) {
++		txq_cur->tx.info.sg_flag = 1;
++	}
++
++	/* deal with VLAN flag */
++	l3_proto = skb->protocol;
++	if (skb->protocol == htons(ETH_P_8021Q)) {
++		struct vlan_hdr *vhdr;
++
++		vhdr = (struct vlan_hdr *)(skb->data + ETH_HLEN);
++		l3_proto = vhdr->h_vlan_encapsulated_proto;
++		txq_cur->tx.info.vlan_flag = 1;
++	}
++
++	if (l3_proto == htons(ETH_P_IP)) {
++		const struct iphdr *iph;
++
++		iph = ip_hdr(skb);
++		txq_cur->tx.info.ip_ver = PKT_IPV4;
++		txq_cur->tx.info.ip_hdr_len = iph->ihl;
++
++		l4_proto = iph->protocol;
++		l4_proto = l4_proto & (MAX_INET_PROTOS - 1);
++	} else if (l3_proto == htons(ETH_P_IPV6)) {
++		const struct ipv6hdr *hdr;
++
++		txq_cur->tx.info.ip_ver = PKT_IPV6;
++		txq_cur->tx.info.ip_hdr_len = PKT_IPV6_HDR_LEN;
++		hdr = ipv6_hdr(skb);
++		l4_proto = hdr->nexthdr;
++	} else {
++		coe_enable = 0;
++		/* pr_err("unknown level 3 prot=0x%x\n", ntohs(l3_proto)); */
++	}
++
++	if (l4_proto == IPPROTO_TCP) {
++		const struct tcphdr *th;
++
++		th = tcp_hdr(skb);
++		txq_cur->tx.info.prot_type = PKT_TCP;
++		txq_cur->tx.info.prot_hdr_len = th->doff;
++	} else if (l4_proto == IPPROTO_UDP) {
++		txq_cur->tx.info.prot_type = PKT_UDP;
++		txq_cur->tx.info.prot_hdr_len = PKT_UDP_HDR_LEN;
++	} else {
++		coe_enable = 0;
++		/* pr_err("unknown level 4 prot=0x%x\n", l4_proto); */
++		/* TODO: when l3_proto == ETH_P_IPV6,
++		 * we need to deal with IPV6 next header.
++		 */
++		if (l3_proto == htons(ETH_P_IPV6) &&
++		    skb->ip_summed == CHECKSUM_PARTIAL)
++			return -E_MAC_SW_GSO;
++	}
++
++	if (skb_is_gso(skb))
++		txq_cur->tx.info.data_len
++			= skb_shinfo(skb)->gso_size;
++	else
++		txq_cur->tx.info.data_len = skb->len + FCS_BYTES;
++
++	if (coe_enable) {
++		if (skb_is_gso(skb) && (l4_proto == IPPROTO_UDP)) {
++			/* TODO: self checksum caculate */
++			int offset;
++			__wsum csum;
++			__sum16 udp_csum;
++
++			offset = skb_checksum_start_offset(skb);
++			WARN_ON(offset >= skb_headlen(skb));
++			csum = skb_checksum(skb, offset, skb->len - offset, 0);
++
++			offset += skb->csum_offset;
++			BUG_ON(offset + sizeof(__sum16) > skb_headlen(skb));
++			udp_csum = csum_fold(csum);
++			if (udp_csum == 0)
++				udp_csum = CSUM_MANGLED_0;
++
++			*(__sum16 *)(skb->data + offset) = udp_csum;
++
++			skb->ip_summed = CHECKSUM_NONE;
++			coe_enable = 0;
++		}
++	}
++
++	txq_cur->tx.info.coe_flag = coe_enable;
++	txq_cur->tx.info.nfrags_num = nfrags;
++
++	return 0;
++}
++
++int hieth_xmit_gso(struct hieth_netdev_priv *priv, struct sk_buff *skb)
++{
++	int pkt_type = PKT_NORMAL;
++	int nfrags = skb_shinfo(skb)->nr_frags;
++	struct tx_pkt_info *txq_cur;
++	int ret;
++
++	if (((priv->txq_head + 1) % priv->q_size) == priv->txq_tail) {
++		/* txq full, stop */
++		pr_err("WARNING: txq full.");
++		return -E_MAC_TX_FAIL;
++	}
++
++	if (skb_is_gso(skb) || nfrags) {
++		/* TSO pkt or SG pkt */
++		pkt_type = PKT_SG;
++	} else { /* Normal pkt */
++		pkt_type = PKT_NORMAL;
++	}
++
++	txq_cur = priv->txq + priv->txq_head;
++
++	ret = hieth_get_pkt_info(skb, txq_cur);
++	if (unlikely(ret < 0))
++		return ret;
++
++	if (pkt_type == PKT_NORMAL) {
++		txq_cur->tx_addr = dma_map_single(priv->dev, skb->data,
++				skb->len, DMA_TO_DEVICE);
++	} else { /* TSO pkt */
++		struct dma_tx_desc *desc_cur;
++		int i;
++
++		if (unlikely(((priv->sg_head + 1) % priv->q_size) ==
++		    priv->sg_tail)) {
++			/* SG pkt, but sg desc all used */
++			pr_err("WARNING: sg desc all used.");
++			return -E_MAC_TX_FAIL;
++		}
++
++		desc_cur = priv->dma_tx + priv->sg_head;
++
++		/* TODO: deal with ipv6_id */
++		if (txq_cur->tx.info.tso_flag &&
++		    txq_cur->tx.info.ip_ver == PKT_IPV6 &&
++		    txq_cur->tx.info.prot_type == PKT_UDP) {
++			desc_cur->ipv6_id = ntohl(skb_shinfo(skb)->ip6_frag_id);
++		}
++
++		desc_cur->total_len = skb->len;
++		desc_cur->linear_len = skb_headlen(skb);
++		desc_cur->linear_addr = dma_map_single(priv->dev, skb->data,
++				desc_cur->linear_len, DMA_TO_DEVICE);
++		if (unlikely(dma_mapping_error(priv->dev,
++					       desc_cur->linear_addr))) {
++			pr_err("DMA Mapping fail.");
++			return -E_MAC_TX_FAIL;
++		}
++
++		for (i = 0; i < nfrags; i++) {
++			skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
++			int len = frag->size;
++
++			WARN(len <= 0, "%s,%d: frag %d size %d. desc=%x\n",
++			     __func__, __LINE__, i, len, txq_cur->tx.val);
++
++			desc_cur->frags[i].addr =
++				skb_frag_dma_map(priv->dev, frag, 0,
++						 len, DMA_TO_DEVICE);
++			ret = dma_mapping_error(priv->dev,
++						desc_cur->frags[i].addr);
++			if (unlikely(ret)) {
++				pr_err("skb frag DMA Mapping fail.");
++				return -E_MAC_TX_FAIL;
++			}
++			desc_cur->frags[i].size = len;
++		}
++
++		txq_cur->tx_addr = priv->dma_tx_phy +
++			priv->sg_head * sizeof(struct dma_tx_desc);
++		txq_cur->sg_desc_offset = priv->sg_head;
++
++		priv->sg_head = (priv->sg_head + 1) % priv->q_size;
++
++		/* Ensure desc info writen to memory before config hardware */
++		wmb();
++	}
++
++	txq_cur->skb = skb;
++	priv->txq_head = (priv->txq_head + 1) % priv->q_size;
++
++#ifdef HIETH_TSO_DEBUG
++	pkt_rec[id_send].reg_addr = txq_cur->tx_addr;
++	pkt_rec[id_send].reg_pkt_info = txq_cur->tx.val;
++	pkt_rec[id_send].status = 1;
++	id_send++;
++	if (id_send == MAX_RECORD)
++		id_send = 0;
++#endif
++	hieth_writel(priv->port_base, txq_cur->tx_addr, HIETH_P_GLB_EQ_ADDR);
++	hieth_writel(priv->port_base, txq_cur->tx.val, HIETH_P_GLB_EQFRM_LEN);
++
++	return 0;
++}
++#endif
++
++static int hieth_xmit_real_send(struct hieth_netdev_priv *priv,
++				struct sk_buff *skb)
++{
++	int ret = 0;
++	u32 val;
++
++	local_lock(priv);
++
++	val = hieth_readl(priv->port_base, HIETH_P_GLB_RO_QUEUE_STAT);
++	val &= HIETH_P_GLB_RO_QUEUE_STAT_XMITQ_RDY_MSK;
++	if (!val) {
++		pr_err("hw xmit queue is not ready\n");
++		ret = -1;
++		goto _trans_exit;
++	}
++
++#ifdef HIETH_TSO_SUPPORTED
++	/* TSO supported */
++	ret = hieth_xmit_gso(priv, skb);
++	if (unlikely(ret < 0)) {
++		if (ret == -E_MAC_SW_GSO) {
++			local_unlock(priv);
++			return hieth_sw_gso(priv, skb);
++		}
++		ret = -1;
++		goto _trans_exit;
++	}
++#else
++	dma_map_single(priv->dev, skb->data, skb->len, DMA_TO_DEVICE);
++	/* for recalc CRC, 4 bytes more is needed */
++	hieth_writel(priv->port_base, virt_to_phys(skb->data),
++		     HIETH_P_GLB_EQ_ADDR);
++	hieth_writel(priv->port_base, skb->len + FCS_BYTES,
++		     HIETH_P_GLB_EQFRM_LEN);
++
++	skb_queue_tail(&priv->tx_hw, skb);
++#endif
++
++	priv->tx_hw_cnt++;
++
++_trans_exit:
++	local_unlock(priv);
++
++	return ret;
++}
++
++static struct sk_buff *hieth_platdev_alloc_skb(struct hieth_netdev_priv *priv)
++{
++	struct sk_buff *skb;
++
++	skb = priv->rx_pool.sk_pool[priv->rx_pool.next_free_skb++];
++
++	if (priv->rx_pool.next_free_skb == CONFIG_HIETH_MAX_RX_POOLS)
++		priv->rx_pool.next_free_skb = 0;
++
++	/*current skb is used by kernel or other process,find another skb*/
++	if (skb_shared(skb) || (atomic_read(&(skb_shinfo(skb)->dataref)) > 1)) {
++		int i;
++
++		for (i = 0; i < CONFIG_HIETH_MAX_RX_POOLS; i++) {
++			skb = priv->rx_pool.sk_pool[priv->
++						    rx_pool.next_free_skb++];
++			if (priv->rx_pool.next_free_skb ==
++			    CONFIG_HIETH_MAX_RX_POOLS)
++				priv->rx_pool.next_free_skb = 0;
++
++			if ((skb_shared(skb) == 0) &&
++			    (atomic_read(&(skb_shinfo(skb)->dataref)) <= 1))
++				break;
++		}
++
++		if (i == CONFIG_HIETH_MAX_RX_POOLS) {
++			priv->stat.rx_pool_dry_times++;
++			pr_debug("%ld: no free skb\n",
++				 priv->stat.rx_pool_dry_times);
++			skb = dev_alloc_skb(SKB_SIZE);
++			return skb;
++		}
++	}
++	memset(skb, 0, offsetof(struct sk_buff, tail));
++
++	skb->data = skb->head;
++	skb->tail = skb->head;
++
++	skb_reserve(skb, NET_SKB_PAD);
++	skb->len = 0;
++	skb->data_len = 0;
++	skb->cloned = 0;
++	atomic_inc(&skb->users);
++	return skb;
++}
++
++static int hieth_feed_hw(struct hieth_netdev_priv *priv)
++{
++	struct sk_buff *skb;
++	int cnt = 0;
++	int rx_head_len;
++
++	/* if skb occupied too much, then do not alloc any more. */
++	rx_head_len = skb_queue_len(&priv->rx_head);
++	if (rx_head_len > HIETH_MAX_RX_HEAD_LEN)
++		return 0;
++
++	local_lock(priv);
++
++	while (hieth_readl(priv->port_base, HIETH_P_GLB_RO_QUEUE_STAT) &
++		HIETH_P_GLB_RO_QUEUE_STAT_RECVQ_RDY_MSK) {
++		skb = hieth_platdev_alloc_skb(priv);
++		if (!skb)
++			break;
++
++		dma_map_single(priv->dev, skb->data, HIETH_MAX_FRAME_SIZE,
++			       DMA_FROM_DEVICE);
++		hieth_writel(priv->port_base, virt_to_phys(skb->data + 2),
++			     HIETH_P_GLB_IQ_ADDR);
++		skb_queue_tail(&priv->rx_hw, skb);
++		cnt++;
++	}
++
++	local_unlock(priv);
++	return cnt;
++}
++
++static int hieth_hw_recv_tryup(struct hieth_netdev_priv *priv)
++{
++	struct sk_buff *skb;
++	u32 rlen;
++	int cnt = 0;
++	uint32_t rx_pkt_info;
++#ifdef HIETH_RXCSUM_SUPPORTED
++	struct net_device *ndev = hieth_devs_save[priv->port];
++	int hdr_csum_done, hdr_csum_err;
++	int payload_csum_done, payload_csum_err;
++#endif
++
++	local_lock(priv);
++
++	while ((hieth_readl(priv->glb_base, HIETH_GLB_IRQ_RAW) &
++		(UD_BIT_NAME(HIETH_GLB_IRQ_INT_RX_RDY)))) {
++		rx_pkt_info = hieth_readl(priv->port_base,
++					  HIETH_P_GLB_RO_IQFRM_DES);
++		rlen = rx_pkt_info & HIETH_P_GLB_RO_IQFRM_DES_FDIN_LEN_MSK;
++		rlen -= 4; /* remove FCS 4Bytes */
++
++		/* hw set rx pkg finish */
++		hieth_writel(priv->glb_base,
++			     UD_BIT_NAME(HIETH_GLB_IRQ_INT_RX_RDY),
++			     HIETH_GLB_IRQ_RAW);
++
++		skb = skb_dequeue(&priv->rx_hw);
++		if (!skb) {
++			pr_err("chip told receive pkg, but no packet find!\n");
++			BUG();
++			break;
++		}
++
++		dma_map_single(priv->dev, skb->data, HIETH_MAX_FRAME_SIZE,
++			       DMA_FROM_DEVICE);
++		skb_reserve(skb, 2);
++		skb_put(skb, rlen);
++#ifdef HIETH_RXCSUM_SUPPORTED
++		skb->ip_summed = CHECKSUM_NONE;
++		if (ndev->features & NETIF_F_RXCSUM) {
++			hdr_csum_done =
++				(rx_pkt_info >> BITS_HEADER_DONE_OFFSET) &
++				BITS_HEADER_DONE_MASK;
++			payload_csum_done =
++				(rx_pkt_info >> BITS_PAYLOAD_DONE_OFFSET) &
++				BITS_PAYLOAD_DONE_MASK;
++			hdr_csum_err =
++				(rx_pkt_info >> BITS_HEADER_ERR_OFFSET) &
++				BITS_HEADER_ERR_MASK;
++			payload_csum_err =
++				(rx_pkt_info >> BITS_PAYLOAD_ERR_OFFSET) &
++				BITS_PAYLOAD_ERR_MASK;
++
++			if (hdr_csum_done && payload_csum_done) {
++				if (unlikely(hdr_csum_err ||
++					     payload_csum_err)) {
++					priv->stats.rx_errors++;
++					priv->stats.rx_crc_errors++;
++					dev_kfree_skb_any(skb);
++					continue;
++				} else {
++					skb->ip_summed = CHECKSUM_UNNECESSARY;
++				}
++			}
++		}
++#endif
++		skb_queue_tail(&priv->rx_head, skb);
++		cnt++;
++	}
++
++	local_unlock(priv);
++
++	/* fill hardware receive queue again */
++	hieth_feed_hw(priv);
++	return cnt;
++}
++
++static void hieth_adjust_link(struct net_device *dev)
++{
++	int stat = 0;
++	struct hieth_netdev_priv *priv = netdev_priv(dev);
++
++	stat |= (priv->phy->link) ? HIETH_P_MAC_PORTSET_LINKED : 0;
++	stat |= (priv->phy->duplex == DUPLEX_FULL) ?
++		HIETH_P_MAC_PORTSET_DUP_FULL : 0;
++	stat |= (priv->phy->speed == SPEED_100) ?
++		HIETH_P_MAC_PORTSET_SPD_100M : 0;
++
++	if ((stat != priv->link_stat) &&
++	    ((stat | priv->link_stat) & HIETH_P_MAC_PORTSET_LINKED)) {
++		hieth_writel(priv->port_base, stat, HIETH_P_MAC_PORTSET);
++		phy_print_status(priv->phy);
++		priv->link_stat = stat;
++
++		priv->tx_pause_en = priv->phy->pause;
++		hieth_set_flow_ctrl(priv);
++
++		if (hieth_enable_autoeee)
++			hieth_autoeee_init(priv, stat);
++	}
++}
++
++static int hieth_init_skb_buffers(struct hieth_netdev_priv *priv)
++{
++	int i;
++	struct sk_buff *skb;
++
++	for (i = 0; i < CONFIG_HIETH_MAX_RX_POOLS; i++) {
++		skb = dev_alloc_skb(SKB_SIZE);
++		if (!skb)
++			break;
++		priv->rx_pool.sk_pool[i] = skb;
++	}
++
++	if (i < CONFIG_HIETH_MAX_RX_POOLS) {
++		pr_err("no mem\n");
++		for (i--; i > 0; i--)
++			dev_kfree_skb_any(priv->rx_pool.sk_pool[i]);
++		return -ENOMEM;
++	}
++
++	priv->rx_pool.next_free_skb = 0;
++	priv->stat.rx_pool_dry_times = 0;
++	return 0;
++}
++
++static void hieth_destroy_skb_buffers(struct hieth_netdev_priv *priv)
++{
++	int i;
++
++	for (i = 0; i < CONFIG_HIETH_MAX_RX_POOLS; i++)
++		dev_kfree_skb_any(priv->rx_pool.sk_pool[i]);
++
++	priv->rx_pool.next_free_skb = 0;
++	priv->stat.rx_pool_dry_times = 0;
++}
++
++static void hieth_bfproc_recv(unsigned long data)
++{
++	int ret = 0;
++	struct net_device *dev = (void *)data;
++	struct hieth_netdev_priv *priv = netdev_priv(dev);
++	struct sk_buff *skb;
++
++	hieth_hw_recv_tryup(priv);
++
++	while ((skb = skb_dequeue(&priv->rx_head)) != NULL) {
++		skb->protocol = eth_type_trans(skb, dev);
++		if (HIETH_INVALID_RXPKG_LEN(skb->len)) {
++			pr_err("pkg len error\n");
++			priv->stats.rx_errors++;
++			priv->stats.rx_length_errors++;
++			dev_kfree_skb_any(skb);
++			continue;
++		}
++
++		priv->stats.rx_packets++;
++		priv->stats.rx_bytes += skb->len;
++		dev->last_rx = jiffies;
++		skb->dev = dev;
++
++		ret = netif_rx(skb);
++		if (ret)
++			priv->stats.rx_dropped++;
++	}
++}
++
++static void hieth_net_isr_proc(struct net_device *ndev, int ints)
++{
++	struct hieth_netdev_priv *priv = netdev_priv(ndev);
++
++	if ((ints & UD_BIT_NAME(HIETH_GLB_IRQ_INT_MULTI_RXRDY)) &&
++	    (hieth_hw_recv_tryup(priv) > 0)) {
++		tasklet_schedule(&priv->bf_recv);
++	}
++
++	if (ints & UD_BIT_NAME(HIETH_GLB_IRQ_INT_TXQUE_RDY)) {
++		hieth_irq_disable(priv,
++				  UD_BIT_NAME(HIETH_GLB_IRQ_INT_TXQUE_RDY));
++		netif_wake_queue(ndev);
++	}
++}
++
++static irqreturn_t hieth_net_isr(int irq, void *dev_id)
++{
++	int ints;
++	struct net_device *dev = (struct net_device *)dev_id;
++	struct hieth_netdev_priv *priv = netdev_priv(dev);
++
++	/*mask the all interrupt */
++	hieth_irq_disable(priv, HIETH_GLB_IRQ_ENA_IEN_A);
++
++	ints = hieth_readl(priv->glb_base, HIETH_GLB_IRQ_STAT);
++
++	if ((HIETH_PORT_0 == priv->port) &&
++	    likely(ints & HIETH_GLB_IRQ_ENA_BIT_U)) {
++		hieth_net_isr_proc(dev, (ints & HIETH_GLB_IRQ_ENA_BIT_U));
++		hieth_clear_irqstatus(priv, (ints & HIETH_GLB_IRQ_ENA_BIT_U));
++		ints &= ~HIETH_GLB_IRQ_ENA_BIT_U;
++	}
++
++	if ((HIETH_PORT_1 == priv->port) &&
++	    likely(ints & HIETH_GLB_IRQ_ENA_BIT_D)) {
++		hieth_net_isr_proc(dev, (ints & HIETH_GLB_IRQ_ENA_BIT_D));
++		hieth_clear_irqstatus(priv, (ints & HIETH_GLB_IRQ_ENA_BIT_D));
++		ints &= ~HIETH_GLB_IRQ_ENA_BIT_D;
++	}
++#ifdef HIETH_TSO_SUPPORTED
++	if (unlikely(ints & HIETH_INT_TX_ERR_U)) {
++		priv = netdev_priv(hieth_devs_save[HIETH_PORT_0]);
++
++		hieth_get_tso_err_info(priv);
++		ints &= ~HIETH_INT_TX_ERR_U;
++	}
++
++	if (unlikely(ints & HIETH_INT_TX_ERR_D)) {
++		priv = netdev_priv(hieth_devs_save[HIETH_PORT_1]);
++
++		hieth_get_tso_err_info(priv);
++		ints &= ~HIETH_INT_TX_ERR_D;
++	}
++#endif
++
++	/*unmask the all interrupt */
++	hieth_irq_enable(priv, HIETH_GLB_IRQ_ENA_IEN_A);
++
++	return IRQ_HANDLED;
++}
++
++static void hieth_monitor_func(unsigned long arg)
++{
++	struct net_device *dev = (struct net_device *)arg;
++	struct hieth_netdev_priv *priv = netdev_priv(dev);
++
++	if (!priv || !netif_running(dev)) {
++		pr_debug("network driver is stopped.\n");
++		return;
++	}
++
++	hieth_feed_hw(priv);
++	hieth_xmit_release_skb(priv);
++
++	priv->monitor.expires =
++	    jiffies + msecs_to_jiffies(HIETH_MONITOR_TIMER);
++	add_timer(&priv->monitor);
++}
++
++static int hieth_net_open(struct net_device *dev)
++{
++	int ret = 0;
++	struct cpumask cpumask;
++	struct hieth_netdev_priv *priv = netdev_priv(dev);
++
++	ret = request_irq(dev->irq, hieth_net_isr, IRQF_SHARED,
++			  dev->name, dev);
++	if (ret) {
++		pr_err("request_irq %d failed!\n", dev->irq);
++		return ret;
++	}
++
++	/* set irq affinity */
++	if ((num_online_cpus() > 1) && cpu_online(HIETH_IRQ_AFFINITY_CPU)) {
++		cpumask_clear(&cpumask);
++		cpumask_set_cpu(HIETH_IRQ_AFFINITY_CPU, &cpumask);
++		irq_set_affinity(dev->irq, &cpumask);
++	}
++
++	if (!is_valid_ether_addr(dev->dev_addr))
++		random_ether_addr(dev->dev_addr);
++
++	hieth_hw_set_macaddress(priv, dev->dev_addr);
++
++	/* init tasklet */
++	priv->bf_recv.next = NULL;
++	priv->bf_recv.state = 0;
++	priv->bf_recv.func = hieth_bfproc_recv;
++	priv->bf_recv.data = (unsigned long)dev;
++	atomic_set(&priv->bf_recv.count, 0);
++
++	/* setup hardware */
++	hieth_set_hwq_depth(priv);
++	hieth_clear_irqstatus(priv, UD_BIT_NAME(HIETH_GLB_IRQ_ENA_BIT));
++
++	netif_carrier_off(dev);
++	hieth_feed_hw(priv);
++	netif_start_queue(dev);
++
++	priv->link_stat = 0;
++	if (priv->phy)
++		phy_start(priv->phy);
++
++	hieth_irq_enable(priv, UD_BIT_NAME(HIETH_GLB_IRQ_INT_MULTI_RXRDY) |
++			UD_BIT_NAME(HIETH_GLB_IRQ_ENA_IEN) |
++			HIETH_GLB_IRQ_ENA_IEN_A);
++#ifdef HIETH_TSO_SUPPORTED
++	hieth_irq_enable(priv, UD_BIT_NAME(HIETH_INT_TX_ERR));
++#endif
++
++	priv->monitor.expires =
++	    jiffies + msecs_to_jiffies(HIETH_MONITOR_TIMER);
++	add_timer(&priv->monitor);
++
++	return 0;
++}
++
++static int hieth_net_close(struct net_device *dev)
++{
++	struct hieth_netdev_priv *priv = netdev_priv(dev);
++#ifdef HIETH_TSO_SUPPORTED
++	struct sk_buff *skb = NULL;
++#endif
++
++	hieth_irq_disable(priv, UD_BIT_NAME(HIETH_GLB_IRQ_INT_MULTI_RXRDY));
++#ifdef HIETH_TSO_SUPPORTED
++	hieth_irq_disable(priv, UD_BIT_NAME(HIETH_INT_TX_ERR));
++#endif
++
++	if (priv->phy)
++		phy_stop(priv->phy);
++
++	del_timer_sync(&priv->monitor);
++
++	/* delete tasklet  */
++	tasklet_kill(&priv->bf_recv);
++
++	/* reset and init port */
++	hieth_port_reset(priv);
++
++	skb_queue_purge(&priv->rx_head);
++	skb_queue_purge(&priv->rx_hw);
++#ifdef HIETH_TSO_SUPPORTED
++	while (priv->txq_tail != priv->txq_head) {
++		skb = hieth_xmit_release_gso(priv);
++		BUG_ON(skb == NULL);
++		kfree_skb(skb);
++	}
++#else
++	skb_queue_purge(&priv->tx_hw);
++#endif
++	priv->tx_hw_cnt = 0;
++
++	free_irq(dev->irq, dev);
++	return 0;
++}
++
++static void hieth_net_timeout(struct net_device *dev)
++{
++	pr_err("tx timeout\n");
++}
++
++static int hieth_net_hard_start_xmit(struct sk_buff *skb,
++				     struct net_device *dev)
++{
++	int ret;
++	struct hieth_netdev_priv *priv = netdev_priv(dev);
++
++	hieth_xmit_release_skb(priv);
++
++	ret = hieth_xmit_real_send(priv, skb);
++	if (ret < 0) {
++		priv->stats.tx_dropped++;
++		return NETDEV_TX_BUSY;
++	}
++
++	dev->trans_start = jiffies;
++	priv->stats.tx_packets++;
++	priv->stats.tx_bytes += skb->len;
++	hieth_clear_irqstatus(priv, UD_BIT_NAME(HIETH_GLB_IRQ_INT_TXQUE_RDY));
++
++	if (!hieth_hw_xmitq_ready(priv)) {
++		netif_stop_queue(dev);
++		hieth_irq_enable(priv,
++				 UD_BIT_NAME(HIETH_GLB_IRQ_INT_TXQUE_RDY));
++	}
++
++	return NETDEV_TX_OK;
++}
++
++static struct net_device_stats *hieth_net_get_stats(struct net_device *dev)
++{
++	struct hieth_netdev_priv *priv = netdev_priv(dev);
++
++	return &priv->stats;
++}
++
++static int hieth_net_set_mac_address(struct net_device *dev, void *p)
++{
++	struct hieth_netdev_priv *priv = netdev_priv(dev);
++	struct sockaddr *skaddr = p;
++
++	if (!is_valid_ether_addr(skaddr->sa_data))
++		return -EADDRNOTAVAIL;
++
++	memcpy(dev->dev_addr, skaddr->sa_data, dev->addr_len);
++	dev->addr_assign_type &= ~NET_ADDR_RANDOM;
++
++	hieth_hw_set_macaddress(priv, dev->dev_addr);
++
++	return 0;
++}
++
++static inline void hieth_enable_mac_addr_filter(struct hieth_netdev_priv *priv,
++						unsigned int reg_n, int enable)
++{
++	u32 val;
++
++	val = hieth_readl(priv->glb_base, GLB_MAC_H16(priv->port, reg_n));
++	if (enable)
++		val |= UD_BIT_NAME(HIETH_GLB_MACFLT_ENA);
++	else
++		val &= ~(UD_BIT_NAME(HIETH_GLB_MACFLT_ENA));
++	hieth_writel(priv->glb_base, val, GLB_MAC_H16(priv->port, reg_n));
++}
++
++static void hieth_set_mac_addr(struct hieth_netdev_priv *priv, u8 addr[6],
++			       unsigned int high, unsigned int low)
++{
++	u32 val;
++	u32 data;
++
++	val = hieth_readl(priv->glb_base, high);
++	val |= UD_BIT_NAME(HIETH_GLB_MACFLT_ENA);
++	hieth_writel(priv->glb_base, val, high);
++
++	val &= ~HIETH_GLB_MACFLT_HI16;
++	val |= ((addr[0] << 8) | addr[1]);
++	hieth_writel(priv->glb_base, val, high);
++
++	data = (addr[2] << 24) | (addr[3] << 16) | (addr[4] << 8) | addr[5];
++	hieth_writel(priv->glb_base, data, low);
++
++	val |= UD_BIT_NAME(HIETH_GLB_MACFLT_FW2CPU);
++	hieth_writel(priv->glb_base, val, high);
++}
++
++static inline void hieth_set_mac_addr_filter(struct hieth_netdev_priv *priv,
++					     unsigned char *addr,
++					     unsigned int reg_n)
++{
++	hieth_set_mac_addr(priv, addr, GLB_MAC_H16(priv->port, reg_n),
++			   GLB_MAC_L32(priv->port, reg_n));
++}
++
++static void hieth_net_set_rx_mode(struct net_device *dev)
++{
++	u32 val;
++	struct hieth_netdev_priv *priv = netdev_priv(dev);
++
++	local_lock(priv);
++
++	val = hieth_readl(priv->glb_base, HIETH_GLB_FWCTRL);
++	if (dev->flags & IFF_PROMISC) {
++		val |= ((priv->port == HIETH_PORT_0) ?
++			HIETH_GLB_FWCTRL_FWALL2CPU_U :
++			HIETH_GLB_FWCTRL_FWALL2CPU_D);
++		hieth_writel(priv->glb_base, val, HIETH_GLB_FWCTRL);
++	} else {
++		val &= ~((priv->port == HIETH_PORT_0) ?
++			HIETH_GLB_FWCTRL_FWALL2CPU_U :
++			HIETH_GLB_FWCTRL_FWALL2CPU_D);
++		hieth_writel(priv->glb_base, val, HIETH_GLB_FWCTRL);
++
++		val = hieth_readl(priv->glb_base, HIETH_GLB_MACTCTRL);
++		if ((netdev_mc_count(dev) > HIETH_MAX_MULTICAST_ADDRESSES) ||
++		    (dev->flags & IFF_ALLMULTI)) {
++			val |= UD_BIT_NAME(HIETH_GLB_MACTCTRL_MULTI2CPU);
++		} else {
++			int reg = HIETH_MAX_UNICAST_ADDRESSES;
++			int i;
++			struct netdev_hw_addr *ha;
++
++			for (i = reg; i < HIETH_MAX_MAC_FILTER_NUM; i++)
++				hieth_enable_mac_addr_filter(priv, i, 0);
++
++			netdev_for_each_mc_addr(ha, dev) {
++				hieth_set_mac_addr_filter(priv, ha->addr, reg);
++				reg++;
++			}
++
++			val &= ~(UD_BIT_NAME(HIETH_GLB_MACTCTRL_MULTI2CPU));
++		}
++
++		/* Handle multiple unicast addresses (perfect filtering)*/
++		if (netdev_uc_count(dev) > HIETH_MAX_UNICAST_ADDRESSES) {
++			val |= UD_BIT_NAME(HIETH_GLB_MACTCTRL_UNI2CPU);
++		} else {
++			int reg = 0;
++			int i;
++			struct netdev_hw_addr *ha;
++
++			for (i = reg; i < HIETH_MAX_UNICAST_ADDRESSES; i++)
++				hieth_enable_mac_addr_filter(priv, i, 0);
++
++			netdev_for_each_uc_addr(ha, dev) {
++				hieth_set_mac_addr_filter(priv, ha->addr, reg);
++				reg++;
++			}
++
++			val &= ~(UD_BIT_NAME(HIETH_GLB_MACTCTRL_UNI2CPU));
++		}
++		hieth_writel(priv->glb_base, val, HIETH_GLB_MACTCTRL);
++	}
++
++	local_unlock(priv);
++}
++
++static int hieth_net_ioctl(struct net_device *net_dev,
++			   struct ifreq *ifreq, int cmd)
++{
++	struct hieth_netdev_priv *priv = netdev_priv(net_dev);
++	struct hieth_pm_config pm_config;
++
++	switch (cmd) {
++	case SIOCSETPM:
++		if (copy_from_user(&pm_config, ifreq->ifr_data,
++				   sizeof(pm_config)))
++			return -EFAULT;
++		return hieth_pmt_config(&pm_config);
++
++	default:
++		if (!netif_running(net_dev))
++			return -EINVAL;
++
++		if (!priv->phy)
++			return -EINVAL;
++
++		return phy_mii_ioctl(priv->phy, ifreq, cmd);
++	}
++
++	return 0;
++}
++
++static void hieth_ethtools_get_drvinfo(struct net_device *net_dev,
++				       struct ethtool_drvinfo *info)
++{
++	strcpy(info->driver, "hieth driver");
++	strcpy(info->version, "v300");
++	strcpy(info->bus_info, "platform");
++}
++
++static u32 hieth_ethtools_get_link(struct net_device *net_dev)
++{
++	struct hieth_netdev_priv *priv = netdev_priv(net_dev);
++
++	return ((priv->phy->link) ? HIETH_P_MAC_PORTSET_LINKED : 0);
++}
++
++static int hieth_ethtools_get_settings(struct net_device *net_dev,
++				       struct ethtool_cmd *cmd)
++{
++	struct hieth_netdev_priv *priv = netdev_priv(net_dev);
++
++	if (priv->phy)
++		return phy_ethtool_gset(priv->phy, cmd);
++
++	return -EINVAL;
++}
++
++static int hieth_ethtools_set_settings(struct net_device *net_dev,
++				       struct ethtool_cmd *cmd)
++{
++	struct hieth_netdev_priv *priv = netdev_priv(net_dev);
++
++	if (!capable(CAP_NET_ADMIN))
++		return -EPERM;
++
++	if (priv->phy)
++		return phy_ethtool_sset(priv->phy, cmd);
++
++	return -EINVAL;
++}
++
++static void hieth_get_pauseparam(struct net_device *net_dev,
++				 struct ethtool_pauseparam *pause)
++{
++	struct hieth_netdev_priv *priv = netdev_priv(net_dev);
++
++	pause->autoneg = priv->phy->autoneg;
++	pause->rx_pause = 1;
++	if (priv->tx_pause_en)
++		pause->tx_pause = 1;
++}
++
++static int hieth_set_pauseparam(struct net_device *net_dev,
++				struct ethtool_pauseparam *pause)
++{
++	struct hieth_netdev_priv *priv = netdev_priv(net_dev);
++	struct phy_device *phy = priv->phy;
++	int ret = 0;
++
++	if (pause->rx_pause == 0)
++		return -EINVAL;
++
++	if (pause->tx_pause != priv->tx_pause_en) {
++		priv->tx_pause_en = pause->tx_pause;
++		hieth_set_flow_ctrl(priv);
++	}
++
++	if (phy->autoneg) {
++		if (netif_running(net_dev)) {
++			struct ethtool_cmd cmd;
++			/* auto-negotiation automatically restarted */
++			cmd.cmd = ETHTOOL_NWAY_RST;
++			cmd.supported = phy->supported;
++			cmd.advertising = phy->advertising;
++			cmd.autoneg = phy->autoneg;
++			cmd.speed = phy->speed;
++			cmd.duplex = phy->duplex;
++			cmd.phy_address = phy->addr;
++			ret = phy_ethtool_sset(phy, &cmd);
++		}
++	}
++
++	return ret;
++}
++
++static inline void hieth_enable_rxcsum_drop(struct hieth_netdev_priv *priv,
++					    bool drop)
++{
++	unsigned int val;
++
++	val = hieth_readl(priv->port_base, HIETH_P_GLB_RX_COE_CTRL);
++	if (drop)
++		val |= COE_ERR_DROP;
++	else
++		val &= ~COE_ERR_DROP;
++	hieth_writel(priv->port_base, val, HIETH_P_GLB_RX_COE_CTRL);
++}
++
++static int hieth_set_features(struct net_device *dev,
++			      netdev_features_t features)
++{
++	struct hieth_netdev_priv *priv = netdev_priv(dev);
++	netdev_features_t changed = dev->features ^ features;
++
++	if (changed & NETIF_F_RXCSUM) {
++		if (features & NETIF_F_RXCSUM)
++			hieth_enable_rxcsum_drop(priv, true);
++		else
++			hieth_enable_rxcsum_drop(priv, false);
++	}
++
++	return 0;
++}
++
++static struct ethtool_ops hieth_ethtools_ops = {
++	.get_drvinfo = hieth_ethtools_get_drvinfo,
++	.get_link = hieth_ethtools_get_link,
++	.get_settings = hieth_ethtools_get_settings,
++	.set_settings = hieth_ethtools_set_settings,
++	.get_pauseparam = hieth_get_pauseparam,
++	.set_pauseparam = hieth_set_pauseparam,
++};
++
++static const struct net_device_ops hieth_netdev_ops = {
++	.ndo_open = hieth_net_open,
++	.ndo_stop = hieth_net_close,
++	.ndo_start_xmit = hieth_net_hard_start_xmit,
++	.ndo_tx_timeout = hieth_net_timeout,
++	.ndo_do_ioctl = hieth_net_ioctl,
++	.ndo_set_mac_address = hieth_net_set_mac_address,
++	.ndo_set_rx_mode	= hieth_net_set_rx_mode,
++	.ndo_change_mtu		= eth_change_mtu,
++	.ndo_get_stats = hieth_net_get_stats,
++	.ndo_set_features       = hieth_set_features,
++};
++
++static void hieth_verify_flow_ctrl_args(struct hieth_netdev_priv *priv)
++{
++	if (priv->tx_pause_active_thresh < FC_ACTIVE_MIN ||
++	    priv->tx_pause_active_thresh > FC_ACTIVE_MAX)
++		priv->tx_pause_active_thresh = FC_ACTIVE_DEFAULT;
++
++	if (priv->tx_pause_deactive_thresh < FC_DEACTIVE_MIN ||
++	    priv->tx_pause_deactive_thresh > FC_DEACTIVE_MAX)
++		priv->tx_pause_deactive_thresh = FC_DEACTIVE_DEFAULT;
++
++	if (priv->tx_pause_active_thresh >= priv->tx_pause_deactive_thresh) {
++		priv->tx_pause_active_thresh = FC_ACTIVE_DEFAULT;
++		priv->tx_pause_deactive_thresh = FC_DEACTIVE_DEFAULT;
++	}
++}
++
++static int hieth_platdev_probe_port(struct platform_device *pdev,
++				    struct hieth_netdev_priv *com_priv,
++				    int port)
++{
++	int ret = -1;
++	struct net_device *netdev = NULL;
++	struct device *dev = &pdev->dev;
++	struct hieth_netdev_priv *priv;
++
++	if ((HIETH_PORT_0 != port) && (HIETH_PORT_1 != port)) {
++		pr_err("port error!\n");
++		ret = -ENODEV;
++		goto _error_exit;
++	}
++
++	netdev = alloc_etherdev(sizeof(*priv));
++	if (netdev == NULL) {
++		pr_err("alloc_etherdev fail!\n");
++		ret = -ENOMEM;
++		goto _error_exit;
++	}
++
++	platform_set_drvdata(pdev, netdev);
++	SET_NETDEV_DEV(netdev, &pdev->dev);
++
++	netdev->irq = com_priv->irq;
++
++	netdev->watchdog_timeo = 3 * HZ;
++	netdev->netdev_ops = &hieth_netdev_ops;
++	netdev->ethtool_ops = &hieth_ethtools_ops;
++
++#ifdef HIETH_TSO_SUPPORTED
++	netdev->hw_features |= NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 |
++		NETIF_F_UFO | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
++#endif
++#ifdef HIETH_RXCSUM_SUPPORTED
++	netdev->hw_features |= NETIF_F_RXCSUM;
++#endif
++	netdev->features |= netdev->hw_features;
++	netdev->vlan_features |= netdev->features;
++
++	netdev->priv_flags |= IFF_UNICAST_FLT;
++
++	if (hieth_phy_param[port].macaddr)
++		ether_addr_copy(netdev->dev_addr,
++				hieth_phy_param[port].macaddr);
++
++	if (!is_valid_ether_addr(netdev->dev_addr))
++		eth_hw_addr_random(netdev);
++
++	/* init hieth_global somethings... */
++	hieth_devs_save[port] = netdev;
++
++	/* init hieth_local_driver */
++	priv = netdev_priv(netdev);
++	memset(priv, 0, sizeof(*priv));
++	memcpy(priv, com_priv, sizeof(*priv));
++
++	local_lock_init(priv);
++
++	priv->port = port;
++
++	if (port == HIETH_PORT_0)
++		priv->port_base = priv->glb_base;
++	else
++		priv->port_base = priv->glb_base + 0x2000;
++
++	priv->dev = dev;
++
++	init_timer(&priv->monitor);
++	priv->monitor.function = hieth_monitor_func;
++	priv->monitor.data = (unsigned long)netdev;
++	priv->monitor.expires =
++	    jiffies + msecs_to_jiffies(HIETH_MONITOR_TIMER);
++
++	/* wol need */
++	device_set_wakeup_capable(priv->dev, 1);
++	/* TODO: when we can let phy powerdown?
++	 * In forcing fwd mode, we don't want phy powerdown,
++	 * so I set wakeup enable all the time
++	 */
++	device_set_wakeup_enable(priv->dev, 1);
++
++#ifdef CONFIG_TX_FLOW_CTRL_SUPPORT
++	priv->tx_pause_en = 1;
++#endif
++	priv->tx_pause_active_thresh = CONFIG_TX_FLOW_CTRL_ACTIVE_THRESHOLD;
++	priv->tx_pause_deactive_thresh = CONFIG_TX_FLOW_CTRL_DEACTIVE_THRESHOLD;
++
++	hieth_verify_flow_ctrl_args(priv);
++
++	/* reset and init port */
++	hieth_port_init(priv);
++
++#ifdef HIETH_RXCSUM_SUPPORTED
++	hieth_enable_rxcsum_drop(priv, true);
++#endif
++	priv->depth.hw_xmitq = HIETH_HWQ_XMIT_DEPTH;
++
++	priv->phy = of_phy_connect(netdev, priv->phy_node,
++				   hieth_adjust_link, 0, priv->phy_mode);
++	if (!(priv->phy) || IS_ERR(priv->phy)) {
++		pr_info("connect to port[%d] PHY failed!\n", port);
++		priv->phy = NULL;
++		goto _error_phy_connect;
++	}
++
++	priv->phy->advertising |= ADVERTISED_Pause;
++	priv->phy->supported |= ADVERTISED_Pause;
++
++	pr_info("attached port %d PHY %d to driver %s, phy_mode=%s\n",
++		port, priv->phy->addr, priv->phy->drv->name,
++		phy_modes(priv->phy_mode));
++
++	if (hieth_enable_autoeee)
++		hieth_autoeee_init(priv, 0);
++
++	skb_queue_head_init(&priv->rx_head);
++	skb_queue_head_init(&priv->rx_hw);
++#ifdef HIETH_TSO_SUPPORTED
++	priv->q_size = 2 * (priv->depth.hw_xmitq);
++
++	priv->dma_tx = (struct dma_tx_desc *)dma_alloc_coherent(priv->dev,
++			priv->q_size * sizeof(struct dma_tx_desc),
++			&priv->dma_tx_phy,
++			GFP_KERNEL);
++	if (priv->dma_tx == NULL) {
++		pr_err("dma_alloc_coherent fail!\n");
++		goto _error_alloc_dma_tx;
++	}
++	priv->sg_head = 0;
++	priv->sg_tail = 0;
++
++	priv->txq = kmalloc_array(priv->q_size, sizeof(struct tx_pkt_info),
++			GFP_KERNEL);
++	if (priv->txq == NULL)
++		goto _error_alloc_txq;
++	priv->txq_head = 0;
++	priv->txq_tail = 0;
++#else
++	skb_queue_head_init(&priv->tx_hw);
++#endif
++	priv->tx_hw_cnt = 0;
++
++	ret = hieth_init_skb_buffers(priv);
++	if (ret) {
++		pr_err("hieth_init_skb_buffers failed!\n");
++		goto _error_init_skb_buffers;
++	}
++
++	ret = register_netdev(netdev);
++	if (ret) {
++		pr_err("register_netdev %s failed!\n", netdev->name);
++		goto _error_register_netdev;
++	}
++
++	return ret;
++
++_error_register_netdev:
++	hieth_destroy_skb_buffers(priv);
++
++_error_init_skb_buffers:
++#ifdef HIETH_TSO_SUPPORTED
++	kfree(priv->txq);
++_error_alloc_txq:
++	dma_free_coherent(priv->dev,
++			  priv->q_size * sizeof(struct dma_tx_desc),
++			  priv->dma_tx, priv->dma_tx_phy);
++_error_alloc_dma_tx:
++#endif
++	phy_disconnect(priv->phy);
++	priv->phy = NULL;
++
++_error_phy_connect:
++	local_lock_exit();
++	hieth_devs_save[port] = NULL;
++	free_netdev(netdev);
++
++_error_exit:
++	return ret;
++}
++
++static int hieth_platdev_remove_port(struct platform_device *pdev, int port)
++{
++	struct net_device *ndev;
++	struct hieth_netdev_priv *priv;
++
++	ndev = hieth_devs_save[port];
++
++	if (!ndev)
++		goto _ndev_exit;
++
++	priv = netdev_priv(ndev);
++
++	unregister_netdev(ndev);
++#ifdef HIETH_TSO_SUPPORTED
++	kfree(priv->txq);
++	dma_free_coherent(priv->dev,
++			  priv->q_size * sizeof(struct dma_tx_desc),
++			  priv->dma_tx, priv->dma_tx_phy);
++#endif
++	hieth_destroy_skb_buffers(priv);
++
++	phy_disconnect(priv->phy);
++	priv->phy = NULL;
++
++	iounmap((void *)priv->glb_base);
++
++	local_lock_exit();
++
++	hieth_devs_save[port] = NULL;
++	free_netdev(ndev);
++
++_ndev_exit:
++	return 0;
++}
++
++static int hieth_of_get_param(struct device_node *node)
++{
++	struct device_node *child = NULL;
++	int idx = 0;
++	int data;
++
++	/* get auto eee */
++	hieth_enable_autoeee = of_property_read_bool(node, "autoeee");
++
++	for_each_available_child_of_node(node, child) {
++		/* get phy-addr */
++		if (of_property_read_u32(child, "reg", &data))
++			return -EINVAL;
++		if ((data < 0) || (data >= PHY_MAX_ADDR)) {
++			pr_info("%s has invalid PHY address\n",
++				child->full_name);
++			data = HIETH_INVALID_PHY_ADDR;
++		}
++
++		hieth_phy_param[idx].phy_addr = data;
++		if (data != HIETH_INVALID_PHY_ADDR)
++			hieth_phy_param[idx].isvalid = true;
++
++		/* get phy_mode */
++		hieth_phy_param[idx].phy_mode = of_get_phy_mode(child);
++
++		/* get mac */
++		hieth_phy_param[idx].macaddr = of_get_mac_address(child);
++
++		/* get gpio_base and bit */
++		of_property_read_u32(child, "phy-gpio-base",
++				     (u32 *)(&hieth_phy_param[idx].gpio_base));
++		of_property_read_u32(child, "phy-gpio-bit",
++				     &hieth_phy_param[idx].gpio_bit);
++
++		/* get internal flag */
++		hieth_phy_param[idx].isinternal =
++			of_property_read_bool(child, "internal-phy");
++
++		if (++idx >= HIETH_MAX_PORT)
++			break;
++	}
++
++	return 0;
++}
++
++static void hieth_mac_core_reset(struct hieth_netdev_priv *priv)
++{
++	/* undo reset */
++	reset_control_deassert(priv->mac_rst);
++	usleep_range(50, 60);
++
++	/* soft reset mac port */
++	reset_control_assert(priv->mac_rst);
++	usleep_range(50, 60);
++	/* undo reset */
++	reset_control_deassert(priv->mac_rst);
++}
++
++void hieth_phy_get_reset_controller(struct device *dev)
++{
++	int i;
++	struct hieth_phy_param_s *phy_param;
++	char *rst_name;
++
++	for (i = 0; i < HIETH_MAX_PORT; i++) {
++		phy_param = &hieth_phy_param[i];
++
++		if (!phy_param->isvalid)
++			continue;
++
++		if (i == 0)
++			rst_name = HIETH_PHY0_RST_NAME;
++		else
++			rst_name = HIETH_PHY1_RST_NAME;
++
++		phy_param->phy_rst = devm_reset_control_get(dev, rst_name);
++		if (IS_ERR(phy_param->phy_rst))
++			phy_param->phy_rst = NULL;
++	}
++}
++
++static int hieth_plat_driver_probe(struct platform_device *pdev)
++{
++	int ret = 0;
++	int irq;
++	struct net_device *ndev = NULL;
++	struct device *dev = &pdev->dev;
++	struct device_node *node = dev->of_node;
++	struct resource *res;
++	struct hieth_netdev_priv *priv = &hieth_priv;
++	struct device_node *child = NULL;
++	int port = -1;
++
++	memset(hieth_devs_save, 0, sizeof(hieth_devs_save));
++	memset(hieth_phy_param, 0, sizeof(hieth_phy_param));
++	memset(priv, 0, sizeof(*priv));
++
++	if (hieth_of_get_param(node)) {
++		pr_err("of get parameter fail\n");
++		ret = -ENODEV;
++		goto exit;
++	}
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	priv->glb_base = devm_ioremap_resource(dev, res);
++	if (IS_ERR(priv->glb_base)) {
++		ret = PTR_ERR(priv->glb_base);
++		goto exit;
++	}
++
++	priv->clk = devm_clk_get(&pdev->dev, NULL);
++	if (IS_ERR(priv->clk)) {
++		pr_err("failed to get clk\n");
++		ret = -ENODEV;
++		goto exit;
++	}
++
++	ret = clk_prepare_enable(priv->clk);
++	if (ret < 0) {
++		pr_err("failed to enable clk %d\n", ret);
++		goto exit;
++	}
++
++	priv->mac_rst = devm_reset_control_get(dev, HIETH_MAC_RST_NAME);
++	if (IS_ERR(priv->mac_rst)) {
++		ret = PTR_ERR(priv->mac_rst);
++		goto exit_clk_disable;
++	}
++
++	hieth_mac_core_reset(priv);
++
++	irq = platform_get_irq(pdev, 0);
++	if (irq < 0) {
++		pr_err("no IRQ defined!\n");
++		ret = -ENODEV;
++		goto exit_clk_disable;
++	}
++	priv->irq = irq;
++
++	hieth_phy_get_reset_controller(dev);
++	hieth_phy_reset();
++
++	if (hieth_mdiobus_driver_init(pdev, priv)) {
++		pr_err("mdio bus init error!\n");
++		ret = -ENODEV;
++		goto exit_clk_disable;
++	}
++
++	/* phy param */
++	hieth_phy_register_fixups();
++
++	for_each_available_child_of_node(node, child) {
++		if (++port >= HIETH_MAX_PORT)
++			break;
++
++		if (!hieth_phy_param[port].isvalid)
++			continue;
++
++		priv->phy_node = of_parse_phandle(node, "phy-handle", port);
++		if (!priv->phy_node) {
++			pr_err("not find phy-handle [%d]\n", port);
++			continue;
++		}
++
++		priv->phy_mode = hieth_phy_param[port].phy_mode;
++
++		if (!hieth_platdev_probe_port(pdev, priv, port))
++			hieth_real_port_cnt++;
++	}
++
++	if (hieth_devs_save[HIETH_PORT_0])
++		ndev = hieth_devs_save[HIETH_PORT_0];
++	else if (hieth_devs_save[HIETH_PORT_1])
++		ndev = hieth_devs_save[HIETH_PORT_1];
++
++	if (!ndev) {
++		pr_err("no dev probed!\n");
++		ret = -ENODEV;
++		goto exit_mdiobus;
++	}
++
++	return ret;
++
++exit_mdiobus:
++	hieth_mdiobus_driver_exit(priv);
++
++exit_clk_disable:
++	clk_disable_unprepare(priv->clk);
++
++exit:
++
++	return ret;
++}
++
++static int hieth_plat_driver_remove(struct platform_device *pdev)
++{
++	int i;
++	struct net_device *ndev = NULL;
++	struct hieth_netdev_priv *priv = netdev_priv(ndev);
++
++	if (hieth_devs_save[HIETH_PORT_0])
++		ndev = hieth_devs_save[HIETH_PORT_0];
++	else if (hieth_devs_save[HIETH_PORT_1])
++		ndev = hieth_devs_save[HIETH_PORT_1];
++
++	free_irq(ndev->irq, hieth_devs_save);
++
++	for (i = 0; i < HIETH_MAX_PORT; i++)
++		hieth_platdev_remove_port(pdev, i);
++
++	hieth_mdiobus_driver_exit(priv);
++
++	clk_disable_unprepare(priv->clk);
++
++	memset(hieth_devs_save, 0, sizeof(hieth_devs_save));
++
++	return 0;
++}
++
++#ifdef CONFIG_PM
++static int hieth_plat_driver_suspend_port(struct platform_device *pdev,
++					  pm_message_t state, int port)
++{
++	struct net_device *ndev = hieth_devs_save[port];
++
++	if (ndev) {
++		if (netif_running(ndev)) {
++			hieth_net_close(ndev);
++			netif_device_detach(ndev);
++		}
++	}
++
++	return 0;
++}
++
++int hieth_plat_driver_suspend(struct platform_device *pdev,
++			      pm_message_t state)
++{
++	int i;
++	bool power_off = true;
++	struct hieth_netdev_priv *priv = NULL;
++
++	for (i = 0; i < HIETH_MAX_PORT; i++)
++		hieth_plat_driver_suspend_port(pdev, state, i);
++
++	if (hieth_pmt_enter())
++		power_off = false;
++
++	if (power_off) {
++		for (i = 0; i < HIETH_MAX_PORT; i++) {
++			if (hieth_devs_save[i]) {
++				priv = netdev_priv(hieth_devs_save[i]);
++				genphy_suspend(priv->phy);/* power down phy */
++			}
++		}
++
++		/* need some time before phy suspend finished. */
++		usleep_range(1000, 10000);
++
++		if (priv)
++			clk_disable_unprepare(priv->clk);
++	}
++
++	return 0;
++}
++
++static int hieth_plat_driver_resume_port(struct platform_device *pdev, int port)
++{
++	struct net_device *ndev = hieth_devs_save[port];
++	struct hieth_netdev_priv *priv = netdev_priv(ndev);
++
++	if (ndev) {
++		if (netif_running(ndev)) {
++			hieth_port_init(priv);
++			hieth_net_open(ndev);
++			netif_device_attach(ndev);
++		}
++	}
++
++	return 0;
++}
++
++int hieth_plat_driver_resume(struct platform_device *pdev)
++{
++	int i;
++	struct hieth_netdev_priv *priv = &hieth_priv;
++
++	/* enable clk */
++	clk_prepare_enable(priv->clk);
++	hieth_phy_reset();
++
++	for (i = 0; i < HIETH_MAX_PORT; i++)
++		hieth_plat_driver_resume_port(pdev, i);
++
++	hieth_pmt_exit();
++	return 0;
++}
++#else
++#  define hieth_plat_driver_suspend	NULL
++#  define hieth_plat_driver_resume	NULL
++#endif
++
++static const struct of_device_id hieth_of_match[] = {
++	{.compatible = "hisilicon,hieth", },
++	{},
++};
++
++MODULE_DEVICE_TABLE(of, hieth_of_match);
++
++static struct platform_driver hieth_platform_driver = {
++	.probe = hieth_plat_driver_probe,
++	.remove = hieth_plat_driver_remove,
++	.suspend = hieth_plat_driver_suspend,
++	.resume = hieth_plat_driver_resume,
++	.driver = {
++		   .owner = THIS_MODULE,
++		   .name = HIETH_DRIVER_NAME,
++		   .bus = &platform_bus_type,
++		   .of_match_table = of_match_ptr(hieth_of_match),
++		   },
++};
++
++static int hieth_mod_init(void)
++{
++	int ret = 0;
++
++	if (hieth_disable)
++		return 0;
++
++	ret = platform_driver_register(&hieth_platform_driver);
++	if (ret)
++		pr_err("register platform driver failed!\n");
++
++	hieth_proc_create();
++
++	return ret;
++}
++
++static void hieth_mod_exit(void)
++{
++	if (hieth_disable)
++		return;
++
++	hieth_proc_destroy();
++
++	platform_driver_unregister(&hieth_platform_driver);
++}
++
++module_init(hieth_mod_init);
++module_exit(hieth_mod_exit);
++
++MODULE_DESCRIPTION("Hisilicon ETH driver whith MDIO support");
++MODULE_LICENSE("GPL");
++
++/* vim: set ts=8 sw=8 tw=78: */
+diff --git a/drivers/net/ethernet/hisilicon/hieth/hieth.h b/drivers/net/ethernet/hisilicon/hieth/hieth.h
+new file mode 100644
+index 0000000..88334b9
+--- /dev/null
++++ b/drivers/net/ethernet/hisilicon/hieth/hieth.h
+@@ -0,0 +1,418 @@
++#ifndef __HIETH_H
++#define __HIETH_H
++
++#include <linux/kernel.h>
++#include <linux/interrupt.h>
++#include <linux/delay.h>
++#include <linux/netdevice.h>
++#include <linux/list.h>
++#include <linux/phy.h>
++#include <linux/io.h>
++
++#define HIETH_MIIBUS_NAME	"himii"
++#define HIETH_DRIVER_NAME	"hieth"
++
++#define HIETH_MAC_RST_NAME    "mac_reset"
++#define HIETH_PHY0_RST_NAME    "phy0_reset"
++#define HIETH_PHY1_RST_NAME    "phy1_reset"
++
++#define HIETH_TSO_SUPPORTED
++#define HIETH_TSO_DEBUG
++#define HIETH_RXCSUM_SUPPORTED
++
++#ifdef HIETH_TSO_SUPPORTED
++#include "tso.h"
++#endif
++
++/* hieth max port */
++#define HIETH_MAX_PORT	2
++
++/* invalid phy addr */
++#define HIETH_INVALID_PHY_ADDR  31
++
++/* hieth monitor timer, 10ms */
++#define HIETH_MONITOR_TIMER	10
++
++/* hieth hardware queue send fifo depth, increase to optimize TX performance. */
++#define HIETH_HWQ_XMIT_DEPTH	12
++
++/* set irq affinity to cpu1 when multi-processor */
++#define HIETH_IRQ_AFFINITY_CPU	1
++
++#define HIETH_MAX_QUEUE_DEPTH	64
++#define HIETH_MAX_RX_HEAD_LEN	(10000)  /* max skbs for rx */
++#define HIETH_MAX_RCV_LEN	1535     /* max receive length */
++
++/*  mmu should be less than 1600 Bytes
++ */
++
++#define HIETH_MAX_FRAME_SIZE	(1600)
++#define HIETH_INVALID_RXPKG_LEN(len) (!((len) >= 42 && \
++				      (len) <= HIETH_MAX_FRAME_SIZE))
++
++#define HIETH_MAX_MAC_FILTER_NUM	8
++#define HIETH_MAX_UNICAST_ADDRESSES	2
++#define HIETH_MAX_MULTICAST_ADDRESSES	(HIETH_MAX_MAC_FILTER_NUM - \
++		HIETH_MAX_UNICAST_ADDRESSES)
++
++/* Register Definition
++ */
++/*------------------------- port register -----------------------------------*/
++/* Mac port sel */
++#define HIETH_P_MAC_PORTSEL             0x0200
++#define  HIETH_P_MAC_PORTSEL_STAT       0
++#define   HIETH_P_MAC_PORTSEL_STAT_MDIO 0
++#define   HIETH_P_MAC_PORTSEL_STAT_CPU  1
++#define  HIETH_P_MAC_PORTSEL_MII_MODE   1
++#define   HIETH_P_MAC_PORTSEL_MII       ~BIT(1)
++#define   HIETH_P_MAC_PORTSEL_RMII      BIT(1)
++/* Mac ro status */
++#define HIETH_P_MAC_RO_STAT             0x0204
++/* Mac port status set */
++#define HIETH_P_MAC_PORTSET             0x0208
++#define  HIETH_P_MAC_PORTSET_SPD_100M   BIT(2)
++#define  HIETH_P_MAC_PORTSET_LINKED     BIT(1)
++#define  HIETH_P_MAC_PORTSET_DUP_FULL   BIT(0)
++/* Mac status change */
++#define HIETH_P_MAC_STAT_CHANGE         0x020C
++/* Mac set */
++#define HIETH_P_MAC_SET                 0x0210
++#define BIT_PAUSE_EN	BIT(18)
++#define  HIETH_P_MAC_SET_LEN_MAX(n)     ((n) & 0x7FF)
++#define  HIETH_P_MAC_SET_LEN_MAX_MSK    GENMASK(10, 0)
++
++#define HIETH_P_MAC_RX_IPGCTRL          0x0214
++#define HIETH_P_MAC_TX_IPGCTRL          0x0218
++#define  HIETH_P_MAC_TX_IPGCTRL_PRE_CNT_LMT_SHIFT 23
++#define  HIETH_P_MAC_TX_IPGCTRL_PRE_CNT_LMT_MSK   GENMASK(25, 23)
++/* queue length set */
++#define HIETH_P_GLB_QLEN_SET            0x0344
++#define  HIETH_P_GLB_QLEN_SET_TXQ_DEP_MSK GENMASK(5, 0)
++#define  HIETH_P_GLB_QLEN_SET_TXQ_DEP(n)  ((n) << 0)
++#define  HIETH_P_GLB_QLEN_SET_RXQ_DEP_MSK GENMASK(13, 8)
++#define  HIETH_P_GLB_QLEN_SET_RXQ_DEP(n)  ((n) << 8)
++/* 802.3x flow control register */
++#define HIETH_P_GLB_FC_LEVEL		0x0348
++#define BITS_FC_ACTIVE_THR_OFFSET	8
++#define BIT_FC_EN			BIT(14)
++#define BITS_THR_MASK			0x3F
++
++/* Rx frame start addr */
++#define HIETH_P_GLB_RXFRM_SADDR         0x0350
++/* Rx (read only) Queue-ID and LEN */
++#define HIETH_P_GLB_RO_IQFRM_DES        0x0354
++#define  HIETH_P_GLB_RO_IQFRM_DES_FDIN_LEN_MSK GENMASK(11, 0)
++#define BITS_PAYLOAD_ERR_OFFSET         20
++#define BITS_PAYLOAD_ERR_MASK           0x1
++#define BITS_HEADER_ERR_OFFSET          21
++#define BITS_HEADER_ERR_MASK            0x1
++#define BITS_PAYLOAD_DONE_OFFSET        22
++#define BITS_PAYLOAD_DONE_MASK          0x1
++#define BITS_HEADER_DONE_OFFSET         23
++#define BITS_HEADER_DONE_MASK           0x1
++
++/* Rx ADDR */
++#define HIETH_P_GLB_IQ_ADDR             0x0358
++/* Tx ADDR and LEN */
++#define HIETH_P_GLB_EQ_ADDR             0x0360
++#define HIETH_P_GLB_EQFRM_LEN           0x0364
++/* Rx/Tx Queue ID */
++#define HIETH_P_GLB_RO_QUEUE_ID         0x0368
++/* Rx/Tx Queue staus  */
++#define HIETH_P_GLB_RO_QUEUE_STAT       0x036C
++/* check this bit to see if we can add a Tx package */
++#define  HIETH_P_GLB_RO_QUEUE_STAT_XMITQ_RDY_MSK BIT(24)
++/* check this bit to see if we can add a Rx addr */
++#define  HIETH_P_GLB_RO_QUEUE_STAT_RECVQ_RDY_MSK BIT(25)
++/* counts in queue, include currently sending */
++#define  HIETH_P_GLB_RO_QUEUE_STAT_XMITQ_CNT_INUSE_MSK GENMASK(5, 0)
++
++/* Rx COE control */
++#define HIETH_P_GLB_RX_COE_CTRL               0x0380
++#define BIT_COE_IPV6_UDP_ZERO_DROP     BIT(13)
++#define BIT_COE_PAYLOAD_DROP           BIT(14)
++#define BIT_COE_IPHDR_DROP             BIT(15)
++#define COE_ERR_DROP	(BIT_COE_IPHDR_DROP | BIT_COE_PAYLOAD_DROP | \
++				BIT_COE_IPV6_UDP_ZERO_DROP)
++
++#ifdef HIETH_TSO_SUPPORTED
++/* TSO debug enable */
++#define HIETH_P_GLB_TSO_DBG_EN                0x03A4
++#define BITS_TSO_DBG_EN                 BIT(31)
++/* TSO debug state */
++#define HIETH_P_GLB_TSO_DBG_STATE             0x03A8
++#define BITS_TSO_DBG_STATE              BIT(31)
++/* TSO debug addr */
++#define HIETH_P_GLB_TSO_DBG_ADDR	0x03AC
++/* TSO debug tx info */
++#define HIETH_P_GLB_TSO_DBG_TX_INFO           0x03B0
++/* TSO debug tx err */
++#define HIETH_P_GLB_TSO_DBG_TX_ERR            0x03B4
++#endif
++
++/*------------------------- global register --------------------------------*/
++/* host mac address  */
++#define HIETH_GLB_HOSTMAC_L32           0x1300
++#define HIETH_GLB_HOSTMAC_H16           0x1304
++/* soft reset */
++#define HIETH_GLB_SOFT_RESET            0x1308
++#define  HIETH_GLB_SOFT_RESET_ALL       BIT(0)
++#define  HIETH_GLB_SOFT_RESET_P0        BIT(2)
++#define  HIETH_GLB_SOFT_RESET_P1        BIT(3)
++/* forward contrl */
++#define HIETH_GLB_FWCTRL                0x1310
++#define  HIETH_GLB_FWCTRL_VLAN_ENABLE   BIT(0)
++#define  HIETH_GLB_FWCTRL_FW2CPU_ENA_U  BIT(5)
++#define  HIETH_GLB_FWCTRL_FW2CPU_ENA_D  BIT(9)
++#define  HIETH_GLB_FWCTRL_FWALL2CPU_U   BIT(7)
++#define  HIETH_GLB_FWCTRL_FWALL2CPU_D   BIT(11)
++#define  HIETH_GLB_FWCTRL_FW2OTHPORT_ENA_U   BIT(4)
++#define  HIETH_GLB_FWCTRL_FW2OTHPORT_ENA_D   BIT(8)
++#define  HIETH_GLB_FWCTRL_FW2OTHPORT_FORCE_U BIT(6)
++#define  HIETH_GLB_FWCTRL_FW2OTHPORT_FORCE_D BIT(10)
++/* Mac filter table control */
++#define HIETH_GLB_MACTCTRL              0x1314
++#define  HIETH_GLB_MACTCTRL_MACT_ENA_U  BIT(7)
++#define  HIETH_GLB_MACTCTRL_MACT_ENA_D  BIT(15)
++#define  HIETH_GLB_MACTCTRL_BROAD2CPU_U BIT(5)
++#define  HIETH_GLB_MACTCTRL_BROAD2CPU_D BIT(13)
++#define  HIETH_GLB_MACTCTRL_BROAD2OTHPORT_U  BIT(4)
++#define  HIETH_GLB_MACTCTRL_BROAD2OTHPORT_D  BIT(12)
++#define  HIETH_GLB_MACTCTRL_MULTI2CPU_U      BIT(3)
++#define  HIETH_GLB_MACTCTRL_MULTI2CPU_D      BIT(11)
++#define  HIETH_GLB_MACTCTRL_MULTI2OTHPORT_U  BIT(2)
++#define  HIETH_GLB_MACTCTRL_MULTI2OTHPORT_D  BIT(10)
++#define  HIETH_GLB_MACTCTRL_UNI2CPU_U        BIT(1)
++#define  HIETH_GLB_MACTCTRL_UNI2CPU_D        BIT(9)
++#define  HIETH_GLB_MACTCTRL_UNI2OTHPORT_U    BIT(0)
++#define  HIETH_GLB_MACTCTRL_UNI2OTHPORT_D    BIT(8)
++/* Host mac address */
++#define HIETH_GLB_DN_HOSTMAC_L32        0x1340
++#define HIETH_GLB_DN_HOSTMAC_H16        0x1344
++#define HIETH_GLB_DN_HOSTMAC_ENA        0x1348
++#define  HIETH_GLB_DN_HOSTMAC_ENA_BIT   BIT(0)
++/* Mac filter */
++#define HIETH_GLB_MAC_L32_BASE          0x1400
++#define HIETH_GLB_MAC_H16_BASE          0x1404
++#define HIETH_GLB_MAC_L32_BASE_D        (0x1400 + 16 * 0x8)
++#define HIETH_GLB_MAC_H16_BASE_D        (0x1404 + 16 * 0x8)
++#define  HIETH_GLB_MACFLT_HI16          GENMASK(15, 0)
++#define  HIETH_GLB_MACFLT_FW2CPU_U      BIT(21)
++#define  HIETH_GLB_MACFLT_FW2CPU_D      BIT(19)
++#define  HIETH_GLB_MACFLT_FW2PORT_U     BIT(20)
++#define  HIETH_GLB_MACFLT_FW2PORT_D     BIT(18)
++#define  HIETH_GLB_MACFLT_ENA_U         BIT(17)
++#define  HIETH_GLB_MACFLT_ENA_D         BIT(16)
++/* ENDIAN */
++#define HIETH_GLB_ENDIAN_MOD            0x1318
++#define  HIETH_GLB_ENDIAN_MOD_IN        BIT(1)
++#define  HIETH_GLB_ENDIAN_MOD_OUT       BIT(0)
++/* IRQs */
++#define HIETH_GLB_IRQ_STAT              0x1330
++#define HIETH_GLB_IRQ_ENA               0x1334
++#define  HIETH_GLB_IRQ_ENA_IEN_A        BIT(19)
++#define  HIETH_GLB_IRQ_ENA_IEN_U        BIT(18)
++#define  HIETH_GLB_IRQ_ENA_IEN_D        BIT(17)
++#define  HIETH_GLB_IRQ_ENA_BIT_U        GENMASK(7, 0)
++#define  HIETH_GLB_IRQ_ENA_BIT_D        GENMASK(27, 20)
++#define HIETH_GLB_IRQ_RAW               0x1338
++#define  HIETH_GLB_IRQ_INT_MULTI_RXRDY_U BIT(7)
++#define  HIETH_GLB_IRQ_INT_MULTI_RXRDY_D BIT(27)
++#define  HIETH_GLB_IRQ_INT_TXQUE_RDY_U  BIT(6)
++#define  HIETH_GLB_IRQ_INT_TXQUE_RDY_D  BIT(26)
++#define  HIETH_GLB_IRQ_INT_RX_RDY_U     BIT(0)
++#define  HIETH_GLB_IRQ_INT_RX_RDY_D     BIT(20)
++#define HIETH_INT_TX_ERR_U      BIT(8)
++#define HIETH_INT_TX_ERR_D      BIT(28)
++
++/* ***********************************************************
++*
++* Only for internal used!
++*
++* ***********************************************************
++*/
++
++/* read/write IO */
++#define hieth_readl(base, ofs) \
++	readl(base + (ofs))
++#define hieth_writel(base, v, ofs) \
++	writel(v, base + (ofs))
++
++#define hieth_trace_level 8
++#define hireg_trace(level, msg...) do { \
++if ((level) >= hieth_trace_level) { \
++	pr_info("hireg_trace:%s:%d: ", __func__, __LINE__); \
++	pr_info(msg); \
++	pr_info("\n"); \
++} \
++} while (0)
++
++#define hireg_readl(base, ofs) ({ unsigned long reg = readl((base) + (ofs)); \
++	hireg_trace(2, "_readl(0x%04X) = 0x%08lX", (ofs), reg); \
++	reg; })
++
++#define hireg_writel(base, v, ofs) do { writel((v), (base) + (ofs)); \
++	hireg_trace(2, "_writel(0x%04X) = 0x%08lX", \
++		    (ofs), (unsigned long)(v)); \
++} while (0)
++
++#define hieth_dump_buf(buf, len) do {\
++	int i;\
++	char *p = (void *)(buf);\
++	pr_info("%s->%d, buf=0x%.8x, len=%d\n", \
++			__func__, __LINE__, \
++			(int)(buf), (int)(len)); \
++	for (i = 0; i < (len); i++) {\
++		pr_info("0x%.2x ", *(p+i));\
++		if (!((i+1) & 0x07)) \
++			pr_info("\n");\
++	} \
++	pr_info("\n");\
++} while (0)
++
++/* port */
++enum hieth_port_e {
++	HIETH_PORT_0 = 0,
++	HIETH_PORT_1,
++	HIETH_PORT_NUM,
++};
++
++struct hieth_netdev_priv {
++	void __iomem *glb_base;     /* virtual io global addr */
++	void __iomem *port_base;    /* virtual to port addr:
++				     * port0-0; port1-0x2000
++				     */
++	int port;                   /* 0 => up port, 1 => down port */
++	int irq;
++
++	struct device *dev;
++	struct net_device_stats stats;
++	struct phy_device *phy;
++	struct device_node *phy_node;
++	phy_interface_t	phy_mode;
++
++	struct mii_bus *mii_bus;
++
++	struct sk_buff_head rx_head;   /*received pkgs */
++	struct sk_buff_head rx_hw;     /*rx pkgs in hw */
++#ifdef HIETH_TSO_SUPPORTED
++	struct dma_tx_desc *dma_tx ____cacheline_aligned;
++	dma_addr_t dma_tx_phy;
++	unsigned int sg_head;
++	unsigned int sg_tail;
++#endif
++#ifdef HIETH_TSO_SUPPORTED
++	struct tx_pkt_info *txq;
++	unsigned int txq_head;
++	unsigned int txq_tail;
++	int q_size;
++#else
++	struct sk_buff_head tx_hw;     /*tx pkgs in hw */
++#endif
++	u32 tx_hw_cnt;
++
++	struct timer_list monitor;
++
++	struct {
++		int hw_xmitq;
++	} depth;
++
++	struct {
++		unsigned long rx_pool_dry_times;
++	} stat;
++
++#define SKB_SIZE		(HIETH_MAX_FRAME_SIZE)
++	struct rx_skb_pool {
++		struct sk_buff *sk_pool[CONFIG_HIETH_MAX_RX_POOLS];/*skb pool*/
++		int next_free_skb;	/*next free skb*/
++	} rx_pool;
++
++	struct tasklet_struct bf_recv;
++
++	int link_stat;
++	int (*eee_init)(struct phy_device *phy_dev);
++
++	spinlock_t lock; /* lock for reg rw */
++	unsigned long lockflags;
++
++	spinlock_t mdio_lock; /* lock for mdio reg */
++	unsigned long mdio_lockflags;
++
++	struct clk *clk;
++	struct reset_control *mac_rst;
++	struct reset_control *phy_rst;
++	/* 802.3x flow control */
++	int tx_pause_en;
++	int tx_pause_active_thresh;
++	int tx_pause_deactive_thresh;
++};
++
++/* phy parameter */
++struct hieth_phy_param_s {
++	bool isvalid;     /* valid or not */
++	bool isinternal;  /* internal phy or external phy */
++	int phy_addr;
++	phy_interface_t phy_mode;
++	const char *macaddr;
++
++	struct reset_control *phy_rst;
++
++	/* gpio reset pin if has */
++	void __iomem *gpio_base;
++	u32 gpio_bit;
++};
++
++#ifdef HIETH_TSO_DEBUG
++#define MAX_RECORD      (100)
++struct send_pkt_info {
++	u32 reg_addr;
++	u32 reg_pkt_info;
++	u32 status;
++};
++
++extern unsigned int id_send;
++extern unsigned int id_free;
++extern struct send_pkt_info    pkt_rec[MAX_RECORD];
++#endif
++
++#define local_lock_init(priv)	spin_lock_init(&(priv)->lock)
++#define local_lock_exit(priv)
++#define local_lock(priv)	spin_lock_irqsave(&(priv)->lock, \
++							(priv)->lockflags)
++#define local_unlock(priv)	spin_unlock_irqrestore(&(priv)->lock, \
++							(priv)->lockflags)
++
++#define hieth_mdio_lock_init(priv) spin_lock_init(&(priv)->mdio_lock)
++#define hieth_mdio_lock_exit(priv)
++#define hieth_mdio_lock(priv)      spin_lock_irqsave(&(priv)->mdio_lock, \
++						     (priv)->mdio_lockflags)
++#define hieth_mdio_unlock(priv)    spin_unlock_irqrestore(&(priv)->mdio_lock, \
++							 (priv)->mdio_lockflags)
++
++#define UD_BIT_NAME(name)       ((priv->port == HIETH_PORT_0) ? \
++				 name##_U : name##_D)
++
++#define GLB_MAC_H16(port, reg)	((((port) == HIETH_PORT_0) ? \
++				 HIETH_GLB_MAC_H16_BASE : \
++				 HIETH_GLB_MAC_H16_BASE_D) + (reg * 0x8))
++#define GLB_MAC_L32(port, reg)	((((port) == HIETH_PORT_0) ? \
++				 HIETH_GLB_MAC_L32_BASE : \
++				 HIETH_GLB_MAC_L32_BASE_D) + (reg * 0x8))
++
++#define SIOCGETMODE	(SIOCDEVPRIVATE)	/* get work mode */
++#define SIOCSETMODE	(SIOCDEVPRIVATE + 1)	/* set work mode */
++#define SIOCGETFWD	(SIOCDEVPRIVATE + 2)	/* get forcing forward config */
++#define SIOCSETFWD	(SIOCDEVPRIVATE + 3)	/* set forcing forward config */
++#define SIOCSETPM	(SIOCDEVPRIVATE + 4)	/* set pmt wake up config */
++#define SIOCSETSUSPEND	(SIOCDEVPRIVATE + 5)	/* call dev->suspend */
++#define SIOCSETRESUME	(SIOCDEVPRIVATE + 6)	/* call dev->resume */
++
++extern struct hieth_phy_param_s hieth_phy_param[];
++
++void hieth_autoeee_init(struct hieth_netdev_priv *priv, int link_stat);
++void hieth_phy_register_fixups(void);
++void hieth_phy_reset(void);
++
++#endif
++
++/* vim: set ts=8 sw=8 tw=78: */
+diff --git a/drivers/net/ethernet/hisilicon/hieth/mdio.c b/drivers/net/ethernet/hisilicon/hieth/mdio.c
+new file mode 100644
+index 0000000..bb63593
+--- /dev/null
++++ b/drivers/net/ethernet/hisilicon/hieth/mdio.c
+@@ -0,0 +1,180 @@
++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
++
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/string.h>
++#include <linux/errno.h>
++#include <linux/unistd.h>
++#include <linux/slab.h>
++#include <linux/interrupt.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/skbuff.h>
++#include <linux/spinlock.h>
++#include <linux/mm.h>
++#include <linux/module.h>
++#include <linux/version.h>
++#include <linux/mii.h>
++#include <linux/ethtool.h>
++#include <linux/phy.h>
++#include <linux/dma-mapping.h>
++#include <linux/platform_device.h>
++#include <linux/of_mdio.h>
++#include <linux/io.h>
++#include <asm/irq.h>
++#include <linux/uaccess.h>
++
++#include "hieth.h"
++#include "mdio.h"
++
++/* MDIO Bus Interface */
++
++static void hieth_mdio_init(struct hieth_netdev_priv *priv)
++{
++	hieth_mdio_lock_init(priv);
++	mdio_reg_reset(priv);
++}
++
++static void hieth_mdio_exit(struct hieth_netdev_priv *priv)
++{
++	hieth_mdio_lock_exit(priv);
++}
++
++static int hieth_wait_mdio_ready(struct hieth_netdev_priv *priv)
++{
++	int timeout_us = 1000;
++
++	while (--timeout_us && !mdio_test_ready(priv))
++		udelay(1);
++
++	return timeout_us;
++}
++
++static int hieth_mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum)
++{
++	int val = 0;
++	struct hieth_netdev_priv *priv = bus->priv;
++
++	hieth_mdio_lock(priv);
++
++	if (!hieth_wait_mdio_ready(priv)) {
++		pr_err("mdio busy\n");
++		goto error_exit;
++	}
++
++	mdio_start_phyread(priv, phy_addr, regnum);
++
++	if (hieth_wait_mdio_ready(priv))
++		val = mdio_get_phyread_val(priv);
++	else
++		pr_err("read timeout\n");
++
++error_exit:
++
++	hieth_mdio_unlock(priv);
++
++	pr_debug("phy_addr = %d, regnum = %d, val = 0x%04x\n",
++		 phy_addr, regnum, val);
++
++	return val;
++}
++
++static int hieth_mdiobus_write(struct mii_bus *bus, int phy_addr, int regnum,
++			       u16 val)
++{
++	int ret = 0;
++	struct hieth_netdev_priv *priv = bus->priv;
++
++	pr_debug("phy_addr = %d, regnum = %d\n", phy_addr, regnum);
++
++	hieth_mdio_lock(priv);
++
++	if (!hieth_wait_mdio_ready(priv)) {
++		pr_err("mdio busy\n");
++		ret = -1;
++		goto error_exit;
++	}
++
++	mdio_phywrite(priv, phy_addr, regnum, val);
++
++error_exit:
++
++	hieth_mdio_unlock(priv);
++
++	return ret;
++}
++
++static int hieth_mdiobus_reset(struct mii_bus *bus)
++{
++	struct hieth_netdev_priv *priv = bus->priv;
++
++	mdio_reg_reset(priv);
++	return 0;
++}
++
++int hieth_mdiobus_driver_init(struct platform_device *pdev,
++			      struct hieth_netdev_priv *priv)
++{
++	int phy, ret = 0;
++	struct mii_bus *bus;
++	struct device *dev = &pdev->dev;
++	struct device_node *node = dev->of_node;
++
++	hieth_mdio_init(priv);
++
++	/* register MII bus */
++	bus = mdiobus_alloc();
++	if (!bus) {
++		pr_err("get ioresource failed!\n");
++		ret = -ENOMEM;
++		goto _error_exit;
++	}
++
++	bus->name = HIETH_MIIBUS_NAME;
++
++	snprintf(bus->id, MII_BUS_ID_SIZE, "%s", bus->name);
++	bus->read = hieth_mdiobus_read;
++	bus->write = hieth_mdiobus_write;
++	bus->reset = hieth_mdiobus_reset;
++	bus->priv = priv;
++	priv->mii_bus = bus;
++	bus->parent = &pdev->dev;	/*for Power Management */
++
++	bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
++	if (!bus->irq) {
++		ret = -ENOMEM;
++		goto _error_free_mdiobus;
++	}
++
++	for (phy = 0; phy < PHY_MAX_ADDR; phy++)
++		bus->irq[phy] = PHY_POLL;
++
++	ret = of_mdiobus_register(bus, node);
++	if (ret) {
++		pr_err("failed to register MDIO bus\n");
++		goto _error_free_mdiobus;
++	}
++
++	return 0;
++
++_error_free_mdiobus:
++	kfree(bus->irq);
++	mdiobus_free(bus);
++
++_error_exit:
++	return ret;
++}
++
++void hieth_mdiobus_driver_exit(struct hieth_netdev_priv *priv)
++{
++	struct mii_bus *bus = priv->mii_bus;
++
++	mdiobus_unregister(bus);
++	kfree(bus->irq);
++	mdiobus_free(bus);
++	hieth_mdio_exit(priv);
++}
++
++/* vim: set ts=8 sw=8 tw=78: */
+diff --git a/drivers/net/ethernet/hisilicon/hieth/mdio.h b/drivers/net/ethernet/hisilicon/hieth/mdio.h
+new file mode 100644
+index 0000000..9bb13fb
+--- /dev/null
++++ b/drivers/net/ethernet/hisilicon/hieth/mdio.h
+@@ -0,0 +1,61 @@
++#ifndef __HIETH_MDIO_H
++#define __HIETH_MDIO_H
++
++#define HIETH_MDIO_FRQDIV               2
++
++#define HIETH_MDIO_RWCTRL               0x1100
++#define HIETH_MDIO_RO_DATA              0x1104
++#define HIETH_U_MDIO_PHYADDR            0x0108
++#define HIETH_D_MDIO_PHYADDR            0x2108
++#define HIETH_U_MDIO_RO_STAT            0x010C
++#define HIETH_D_MDIO_RO_STAT            0x210C
++#define HIETH_U_MDIO_ANEG_CTRL          0x0110
++#define HIETH_D_MDIO_ANEG_CTRL          0x2110
++#define HIETH_U_MDIO_IRQENA             0x0114
++#define HIETH_D_MDIO_IRQENA             0x2114
++
++#define MDIO_MK_RWCTL(cpu_data_in, finish, rw, phy_exaddr, frq_div, phy_regnum)\
++		(((cpu_data_in) << 16) | \
++		  (((finish) & 0x01) << 15) | \
++		  (((rw) & 0x01) << 13) | \
++		  (((phy_exaddr) & 0x1F) << 8) | \
++		  (((frq_div) & 0x7) << 5) | \
++		  ((phy_regnum) & 0x1F))
++
++/* hardware set bit'15 of MDIO_REG(0) if mdio ready */
++#define mdio_test_ready(priv) (hieth_readl(priv->glb_base, \
++			       HIETH_MDIO_RWCTRL) & (1 << 15))
++
++#define mdio_start_phyread(priv, phy_addr, regnum) \
++	hieth_writel(priv->glb_base, \
++		     MDIO_MK_RWCTL(0, 0, 0, phy_addr, HIETH_MDIO_FRQDIV, \
++				   regnum), \
++		     HIETH_MDIO_RWCTRL)
++
++#define mdio_get_phyread_val(priv) (hieth_readl(priv->glb_base, \
++				    HIETH_MDIO_RO_DATA) & 0xFFFF)
++
++#define mdio_phywrite(priv, phy_addr, regnum, val) \
++	hieth_writel(priv->glb_base, \
++		     MDIO_MK_RWCTL(val, 0, 1, phy_addr, HIETH_MDIO_FRQDIV, \
++				   regnum), \
++		     HIETH_MDIO_RWCTRL)
++
++/* write mdio registers reset value */
++#define mdio_reg_reset(priv) do { \
++	hieth_writel(priv->glb_base, 0x00008000, HIETH_MDIO_RWCTRL); \
++	hieth_writel(priv->glb_base, 0x00000001, HIETH_U_MDIO_PHYADDR); \
++	hieth_writel(priv->glb_base, 0x00000001, HIETH_D_MDIO_PHYADDR); \
++	hieth_writel(priv->glb_base, 0x04631EA9, HIETH_U_MDIO_ANEG_CTRL); \
++	hieth_writel(priv->glb_base, 0x04631EA9, HIETH_D_MDIO_ANEG_CTRL); \
++	hieth_writel(priv->glb_base, 0x00000000, HIETH_U_MDIO_IRQENA); \
++	hieth_writel(priv->glb_base, 0x00000000, HIETH_D_MDIO_IRQENA); \
++} while (0)
++
++int hieth_mdiobus_driver_init(struct platform_device *pdev,
++			      struct hieth_netdev_priv *priv);
++void hieth_mdiobus_driver_exit(struct hieth_netdev_priv *priv);
++
++#endif
++
++/* vim: set ts=8 sw=8 tw=78: */
+diff --git a/drivers/net/ethernet/hisilicon/hieth/phy.c b/drivers/net/ethernet/hisilicon/hieth/phy.c
+new file mode 100644
+index 0000000..075a2c3
+--- /dev/null
++++ b/drivers/net/ethernet/hisilicon/hieth/phy.c
+@@ -0,0 +1,89 @@
++#include <linux/platform_device.h>
++#include <linux/reset.h>
++#include "hieth.h"
++#include "mdio.h"
++#include "phy.h"
++
++static int KSZ8051MNL_phy_fix(struct phy_device *phy_dev)
++{
++	u32 v;
++
++	if (phy_dev->interface != PHY_INTERFACE_MODE_RMII)
++		return 0;
++
++	v = phy_read(phy_dev, 0x1F);
++	v |= (1 << 7);       /* set phy RMII 50MHz clk; */
++	phy_write(phy_dev, 0x1F, v);
++
++	v = phy_read(phy_dev, 0x16);
++	v |= (1 << 1);       /* set phy RMII override; */
++	phy_write(phy_dev, 0x16, v);
++
++	return 0;
++}
++
++static int KSZ8081RNB_phy_fix(struct phy_device *phy_dev)
++{
++	u32 v;
++
++	if (phy_dev->interface != PHY_INTERFACE_MODE_RMII)
++		return 0;
++
++	v = phy_read(phy_dev, 0x1F);
++	v |= (1 << 7);       /* set phy RMII 50MHz clk; */
++	phy_write(phy_dev, 0x1F, v);
++
++	return 0;
++}
++
++void hieth_phy_register_fixups(void)
++{
++	phy_register_fixup_for_uid(PHY_ID_KSZ8051MNL,
++				   DEFAULT_PHY_MASK, KSZ8051MNL_phy_fix);
++	phy_register_fixup_for_uid(PHY_ID_KSZ8081RNB,
++				   DEFAULT_PHY_MASK, KSZ8081RNB_phy_fix);
++}
++
++static void hieth_internal_phy_reset(struct hieth_phy_param_s *phy_param)
++{
++}
++
++static void hieth_external_phy_reset(struct hieth_phy_param_s *phy_param)
++{
++	if (phy_param->phy_rst) {
++		/* write 0 to cancel reset */
++		reset_control_deassert(phy_param->phy_rst);
++		msleep(50);
++
++		/* RST_BIT, write 1 to reset phy, write 0 to cancel reset */
++		reset_control_assert(phy_param->phy_rst);
++
++		/* delay some time to ensure reset ok,
++		 * this depends on PHY hardware feature
++		 */
++		msleep(50);
++
++		/* write 0 to cancel reset */
++		reset_control_deassert(phy_param->phy_rst);
++		/* delay some time to ensure later MDIO access */
++		msleep(50);
++	}
++}
++
++void hieth_phy_reset(void)
++{
++	int i;
++	struct hieth_phy_param_s *phy_param;
++
++	for (i = 0; i < HIETH_MAX_PORT; i++) {
++		phy_param = &hieth_phy_param[i];
++
++		if (!phy_param->isvalid)
++			continue;
++
++		if (phy_param->isinternal)
++			hieth_internal_phy_reset(phy_param);
++		else
++			hieth_external_phy_reset(phy_param);
++	}
++}
+diff --git a/drivers/net/ethernet/hisilicon/hieth/phy.h b/drivers/net/ethernet/hisilicon/hieth/phy.h
+new file mode 100644
+index 0000000..60de1bc
+--- /dev/null
++++ b/drivers/net/ethernet/hisilicon/hieth/phy.h
+@@ -0,0 +1,18 @@
++#ifndef __HIETH_FEPHY_FIX_H
++#define __HIETH_FEPHY_FIX_H
++
++#define MII_EXPMD			0x1D
++#define MII_EXPMA			0x1E
++
++#define HISILICON_PHY_ID_FESTAV200	(0x20669823)
++#define HISILICON_PHY_ID_FESTAV300	(0x20669833)
++#define HISILICON_PHY_MASK		(0xfffffff0)
++
++/* the following two copied from phy_quirk()
++ * in "./drivers/net/ethernet/hieth-sf/net.c"
++ */
++#define PHY_ID_KSZ8051MNL		(0x00221550)
++#define PHY_ID_KSZ8081RNB		(0x00221560)
++#define DEFAULT_PHY_MASK		(0xfffffff0)
++
++#endif
+diff --git a/drivers/net/ethernet/hisilicon/hieth/pm.c b/drivers/net/ethernet/hisilicon/hieth/pm.c
+new file mode 100644
+index 0000000..2ace419
+--- /dev/null
++++ b/drivers/net/ethernet/hisilicon/hieth/pm.c
+@@ -0,0 +1,323 @@
++#include <linux/crc16.h>
++
++#define HIETH_PM_N              (31)
++#define HIETH_PM_FILTERS        (4)
++
++struct hieth_pm_config {
++	unsigned char index;		/* bit0--eth0 bit1--eth1 */
++	unsigned char uc_pkts_enable;
++	unsigned char magic_pkts_enable;
++	unsigned char wakeup_pkts_enable;
++	struct {
++		unsigned int	mask_bytes : HIETH_PM_N;
++		unsigned int	reserved   : 1;/* userspace ignore this bit */
++		unsigned char	offset;	/* >= 12 */
++		unsigned char	value[HIETH_PM_N];/* byte string */
++		unsigned char	valid;	/* valid filter */
++	} filter[HIETH_PM_FILTERS];
++};
++
++#define HIETH_PMT_CTRL		0x0500
++#define HIETH_PMT_MASK0		0x0504
++#define HIETH_PMT_MASK1		0x0508
++#define HIETH_PMT_MASK2		0x050c
++#define HIETH_PMT_MASK3		0x0510
++#define HIETH_PMT_CMD		0x0514
++#define HIETH_PMT_OFFSET	0x0518
++#define HIETH_PMT_CRC1_0	0x051c
++#define HIETH_PMT_CRC3_2	0x0520
++
++static void hieth_init_crc_table(void);
++static unsigned short hieth_compute_crc(char *message, int n_bytes);
++static unsigned short calculate_crc16(char *buf, unsigned int mask)
++{
++	char data[HIETH_PM_N];
++	int i, len = 0;
++
++	memset(data, 0, sizeof(data));
++
++	for (i = 0; i < HIETH_PM_N; i++) {
++		if (mask & 0x1)
++			data[len++] = buf[i];
++
++		mask >>= 1;
++	}
++
++	return hieth_compute_crc(data, len);
++}
++
++#define	HIETH_PM_SET			(1)
++#define HIETH_PM_CLEAR		(0)
++static char pm_state[HIETH_MAX_PORT] = {HIETH_PM_CLEAR, HIETH_PM_CLEAR};
++
++int hieth_pmt_config_eth(struct hieth_pm_config *config,
++			 struct hieth_netdev_priv *priv)
++{
++	unsigned int v = 0, cmd = 0, offset = 0;
++	unsigned short crc[HIETH_PM_FILTERS] = {0};
++	int reg_mask = 0;
++	int i;
++
++	if (!priv)
++		return -EINVAL;
++
++	local_lock(priv);
++	if (config->wakeup_pkts_enable) {
++		/* disable wakeup_pkts_enable before reconfig? */
++		v = hieth_readl(priv->port_base, HIETH_PMT_CTRL);
++		v &= ~(1 << 2);
++		/* any side effect? */
++		hieth_writel(priv->port_base, v, HIETH_PMT_CTRL);
++	} else {
++		goto config_ctrl;
++	}
++
++/* filter.valid		mask.valid	mask_bytes	effect
++ *	0		*		*		no use the filter
++ *	1		0		*	all pkts can wake-up(non-exist)
++ *	1		1		0		all pkts can wake-up
++ *	1		1		!0		normal filter
++ */
++	/* setup filter */
++	for (i = 0; i < HIETH_PM_FILTERS; i++) {
++		if (config->filter[i].valid) {
++			if (config->filter[i].offset < 12)
++				continue;
++			/* offset and valid bit */
++			offset |= config->filter[i].offset << (i * 8);
++			cmd    |= 1 << (i * 8); /* valid bit */
++			/* mask */
++			reg_mask = HIETH_PMT_MASK0 + (i * 4);
++
++			/* for logic, mask valid bit(bit31) must set to 0,
++			 * 0 is enable
++			 */
++			v = config->filter[i].mask_bytes;
++			v &= ~(1 << 31);
++			hieth_writel(priv->port_base, v, reg_mask);
++
++			/* crc */
++			crc[i] = calculate_crc16(config->filter[i].value, v);
++			if (i <= 1) {/* for filter0 and filter 1 */
++				v = hieth_readl(priv->port_base,
++						HIETH_PMT_CRC1_0);
++				v &= ~(0xFFFF << (16 * i));
++				v |= crc[i] << (16 * i);
++				hieth_writel(priv->port_base, v,
++					     HIETH_PMT_CRC1_0);
++			} else {/* filter2 and filter3 */
++				v = hieth_readl(priv->port_base,
++						HIETH_PMT_CRC3_2);
++				v &= ~(0xFFFF << (16 * (i - 2)));
++				v |= crc[i] << (16 * (i - 2));
++				hieth_writel(priv->port_base, v,
++					     HIETH_PMT_CRC3_2);
++			}
++		}
++	}
++
++	if (cmd) {
++		hieth_writel(priv->port_base, offset, HIETH_PMT_OFFSET);
++		hieth_writel(priv->port_base, cmd, HIETH_PMT_CMD);
++	}
++
++config_ctrl:
++	v = 0;
++	if (config->uc_pkts_enable)
++		v |= 1 << 9;	/* uc pkts wakeup */
++	if (config->wakeup_pkts_enable)
++		v |= 1 << 2;	/* use filter framework */
++	if (config->magic_pkts_enable)
++		v |= 1 << 1;	/* magic pkts wakeup */
++
++	v |= 3 << 5;		/* clear irq status */
++	hieth_writel(priv->port_base, v, HIETH_PMT_CTRL);
++
++	local_unlock(priv);
++
++	return 0;
++}
++
++/* pmt_config will overwrite pre-config */
++int hieth_pmt_config(struct hieth_pm_config *config)
++{
++	static int init;
++	int map = config->index, i, ret = -EINVAL;
++	struct hieth_netdev_priv *priv;
++
++	if (!init)
++		hieth_init_crc_table();
++
++	for (i = 0; i < HIETH_MAX_PORT; i++) {
++		if (!hieth_devs_save[i])
++			continue;
++
++		priv = netdev_priv(hieth_devs_save[i]);
++
++		if (map & 0x1) {
++			ret = hieth_pmt_config_eth(config, priv);
++			if (ret)
++				return ret;
++
++			pm_state[i] = HIETH_PM_SET;
++			device_set_wakeup_enable(priv->dev, 1);
++		}
++		map >>= 1;
++	}
++
++	return ret;
++}
++
++inline bool hieth_pmt_enter(void)
++{
++	int i, v, pm = false;
++	struct hieth_netdev_priv *priv;
++
++	for (i = 0; i < HIETH_MAX_PORT; i++) {
++		if (!hieth_devs_save[i])
++			continue;
++
++		priv = netdev_priv(hieth_devs_save[i]);
++
++		local_lock(priv);
++		if (pm_state[i] == HIETH_PM_SET) {
++			v = hieth_readl(priv->port_base, HIETH_PMT_CTRL);
++			v |= 1 << 0;	/* enter power down */
++			v |= 1 << 3;	/* enable wakeup irq */
++			v |= 3 << 5;	/* clear irq status */
++			hieth_writel(priv->port_base, v, HIETH_PMT_CTRL);
++
++			pm_state[i] = HIETH_PM_CLEAR;
++			pm = true;
++		}
++		local_unlock(priv);
++	}
++	return pm;
++}
++
++inline void hieth_pmt_exit(void)
++{
++	int i, v;
++	struct hieth_netdev_priv *priv;
++
++	for (i = 0; i < HIETH_MAX_PORT; i++) {
++		if (!hieth_devs_save[i])
++			continue;
++
++		priv = netdev_priv(hieth_devs_save[i]);
++
++		/* logic auto exit power down mode */
++		local_lock(priv);
++
++		v = hieth_readl(priv->port_base, HIETH_PMT_CTRL);
++		v &= ~(1 << 0);	/* enter power down */
++		v &= ~(1 << 3);	/* enable wakeup irq */
++
++		v |= 3 << 5;	/* clear irq status */
++		hieth_writel(priv->port_base, v, HIETH_PMT_CTRL);
++
++		local_unlock(priv);
++	}
++
++	/* device_set_wakeup_enable(priv->dev, 0); */
++}
++
++/* ========the following code copy from Synopsys DWC_gmac_crc_example.c====== */
++#define CRC16			/* Change it to CRC16 for CRC16 Computation*/
++
++#define FALSE	0
++#define TRUE	!FALSE
++
++#if defined(CRC16)
++#define CRC_NAME		"CRC-16"
++#define POLYNOMIAL		0x8005
++#define INITIAL_REMAINDER	0xFFFF
++#define FINAL_XOR_VALUE		0x0000
++#define REVERSE_DATA		TRUE
++#define REVERSE_REMAINDER	FALSE
++#endif
++
++#define WIDTH    (8 * sizeof(unsigned short))
++#define TOPBIT   (1 << (WIDTH - 1))
++
++#if (REVERSE_DATA)
++#undef  REVERSE_DATA
++#define REVERSE_DATA(X)		((unsigned char)reverse((X), 8))
++#else
++#undef  REVERSE_DATA
++#define REVERSE_DATA(X)		(X)
++#endif
++
++#if (REVERSE_REMAINDER)
++#undef  REVERSE_REMAINDER
++#define REVERSE_REMAINDER(X)	((unsigned short)reverse((X), WIDTH))
++#else
++#undef  REVERSE_REMAINDER
++#define REVERSE_REMAINDER(X)	(X)
++#endif
++
++static unsigned short crctable[256];
++
++/* Reverse the data
++ *
++ * Input1: Data to be reversed
++ * Input2: number of bits in the data
++ * Output: The reversed data
++ */
++unsigned long reverse(unsigned long data, unsigned char nbits)
++{
++	unsigned long  reversed = 0x00000000;
++	unsigned char  bit;
++
++	/* Reverse the data about the center bit. */
++	for (bit = 0; bit < nbits; ++bit) {
++		/* If the LSB bit is set, set the reflection of it. */
++		if (data & 0x01)
++			reversed |= (1 << ((nbits - 1) - bit));
++
++		data = (data >> 1);
++	}
++	return reversed;
++}
++
++/* This Initializes the partial CRC look up table */
++static void hieth_init_crc_table(void)
++{
++	unsigned short remainder;
++	int dividend;
++	unsigned char  bit;
++
++	/* Compute the remainder of each possible dividend. */
++	for (dividend = 0; dividend < 256; ++dividend) {
++		/* Start with the dividend followed by zeros. */
++		remainder = (unsigned short)(dividend << (WIDTH - 8));
++
++		/* Perform modulo-2 division, a bit at a time. */
++		for (bit = 8; bit > 0; --bit) {
++			/* Try to divide the current data bit. */
++			if (remainder & TOPBIT)
++				remainder = (remainder << 1) ^ POLYNOMIAL;
++			else
++				remainder = (remainder << 1);
++		}
++
++		/* Store the result into the table. */
++		crctable[dividend] = remainder;
++	}
++}
++
++static unsigned short hieth_compute_crc(char *message, int n_bytes)
++{
++	unsigned short remainder = INITIAL_REMAINDER;
++	int	byte;
++	unsigned char  data;
++
++	/* Divide the message by the polynomial, a byte at a time. */
++	for (byte = 0; byte < n_bytes; ++byte) {
++		data = REVERSE_DATA(message[byte]) ^ (remainder >> (WIDTH - 8));
++		remainder = crctable[data] ^ (remainder << 8);
++	}
++
++	/* The final remainder is the CRC. */
++	return (REVERSE_REMAINDER(remainder) ^ FINAL_XOR_VALUE);
++}
+diff --git a/drivers/net/ethernet/hisilicon/hieth/proc.c b/drivers/net/ethernet/hisilicon/hieth/proc.c
+new file mode 100644
+index 0000000..54eea7b
+--- /dev/null
++++ b/drivers/net/ethernet/hisilicon/hieth/proc.c
+@@ -0,0 +1,89 @@
++#include <linux/proc_fs.h>
++
++#include "hieth.h"
++#include "proc.h"
++
++static int hieth_tx_info_read(struct seq_file *m, void *v)
++{
++#ifdef HIETH_TSO_DEBUG
++	{
++		int i;
++		int id_now;
++
++		if (id_send == 0)
++			id_now = MAX_RECORD-1;
++		else
++			id_now = id_send-1;
++
++		for (i = id_now; i >= 0; i--) {
++			seq_printf(m, "%x,%x,%x\n",
++				   pkt_rec[i].reg_addr,
++				   pkt_rec[i].reg_pkt_info,
++				   pkt_rec[i].status);
++		}
++		for (i = MAX_RECORD-1; i > id_now; i--) {
++			seq_printf(m, "%x,%x,%x\n",
++				   pkt_rec[i].reg_addr,
++				   pkt_rec[i].reg_pkt_info,
++				   pkt_rec[i].status);
++		}
++	}
++#endif
++	return 0;
++}
++
++static struct proc_dir_entry *hieth_proc_root;
++
++#define proc_open(name) \
++static int proc_open_##name(struct inode *inode, struct file *file) \
++{ \
++	return single_open(file, name, PDE_DATA(inode)); \
++} \
++
++proc_open(hieth_tx_info_read);
++
++static struct proc_file {
++	char *name;
++	const struct file_operations ops;
++} proc_file[] = {
++	{
++		.name = "tx_info",
++		.ops = {
++			.open           = proc_open_hieth_tx_info_read,
++			.read           = seq_read,
++			.llseek         = seq_lseek,
++			.release        = single_release,
++		},
++	},
++};
++
++/* /proc/hieth/
++ *      |---tx_info
++ */
++void hieth_proc_create(void)
++{
++	int i;
++
++	hieth_proc_root = proc_mkdir("hieth", NULL);
++	if (!hieth_proc_root)
++		return;
++
++	for (i = 0; i < ARRAY_SIZE(proc_file); i++) {
++		struct proc_dir_entry *entry;
++
++		entry = proc_create(proc_file[i].name, 0, hieth_proc_root,
++				    &proc_file[i].ops);
++		if (!entry)
++			pr_err("failed to create %s\n", proc_file[i].name);
++	}
++}
++
++void hieth_proc_destroy(void)
++{
++	int i;
++
++	for (i = 0; i < ARRAY_SIZE(proc_file); i++)
++		remove_proc_entry(proc_file[i].name, hieth_proc_root);
++
++	remove_proc_entry("hieth", NULL);
++}
+diff --git a/drivers/net/ethernet/hisilicon/hieth/proc.h b/drivers/net/ethernet/hisilicon/hieth/proc.h
+new file mode 100644
+index 0000000..20cc8d4
+--- /dev/null
++++ b/drivers/net/ethernet/hisilicon/hieth/proc.h
+@@ -0,0 +1,7 @@
++#ifndef __HIETH_PROC_H
++#define __HIETH_PROC_H
++
++void hieth_proc_create(void);
++void hieth_proc_destroy(void);
++
++#endif
+diff --git a/drivers/net/ethernet/hisilicon/hieth/tso.h b/drivers/net/ethernet/hisilicon/hieth/tso.h
+new file mode 100644
+index 0000000..9929869
+--- /dev/null
++++ b/drivers/net/ethernet/hisilicon/hieth/tso.h
+@@ -0,0 +1,76 @@
++#ifndef __HIETH_TSO_H
++#define __HIETH_TSO_H
++
++#define TSO_FLAG	(1 << 31)
++#define VLAN_FLAG	(1 << 30)
++#define IPV6_FLAG	(1 << 29)
++#define UDP_FLAG	(1 << 28)
++#define TX_CSUM_FLAG	(1 << 27)
++#define SG_FLAG		(1 << 26)
++
++#define PKT_IPV6_HDR_LEN        (10)
++#define PKT_UDP_HDR_LEN         (2)
++#define WORD_TO_BYTE            (4)
++
++enum {
++	PKT_NORMAL,
++	PKT_SG
++};
++
++enum {
++	PKT_IPV4,
++	PKT_IPV6
++};
++
++enum {
++	PKT_TCP,
++	PKT_UDP
++};
++
++struct frags_info {
++	/* Word(2*i+2) */
++	u32 addr;
++	/* Word(2*i+3) */
++	u32 size:16;
++	u32 reserved:16;
++};
++
++struct dma_tx_desc {
++	/* Word0 */
++	u32 total_len:17;
++	u32 reserv:15;
++	/* Word1 */
++	u32 ipv6_id;
++	/* Word2 */
++	u32 linear_addr;
++	/* Word3 */
++	u32 linear_len:16;
++	u32 reserv3:16;
++	/* MAX_SKB_FRAGS = 17 */
++	struct frags_info frags[30];
++	/* struct frags_info frags[MAX_SKB_FRAGS]; */
++};
++
++struct tx_pkt_info {
++	union {
++		struct {
++			u32 data_len:11;
++			u32 nfrags_num:5;
++			u32 prot_hdr_len:4;
++			u32 ip_hdr_len:4;
++			u32 reserved:2;
++			u32 sg_flag:1;
++			u32 coe_flag:1;
++			u32 prot_type:1;
++			u32 ip_ver:1;
++			u32 vlan_flag:1;
++			u32 tso_flag:1;
++		} info;
++		u32 val;
++	} tx;
++	u32 tx_addr; /* normal pkt, skb->data */
++	u32 sg_desc_offset; /* TSO pkt, desc addr */
++	struct sk_buff *skb;
++};
++
++#endif
+diff --git a/drivers/net/ethernet/hisilicon/higmac/Kconfig b/drivers/net/ethernet/hisilicon/higmac/Kconfig
+new file mode 100644
+index 0000000..bda6f74
+--- /dev/null
++++ b/drivers/net/ethernet/hisilicon/higmac/Kconfig
+@@ -0,0 +1,96 @@
++#
++# higmac family network device configuration
++#
++
++menuconfig HIETH_GMAC
++	tristate "hieth gmac family network device support"
++	select PHYLIB
++	select RESET_CONTROLLER
++	help
++	  This selects the hieth gmac family network device.
++	  The gigabit switch fabric (GSF) receives and transmits data over Ethernet
++	  ports at 10/100/1000 Mbit/s in full-duplex or half-duplex mode.
++	  The Ethernet port exchanges data with the CPU port, and supports
++	  the energy efficient Ethernet (EEE) and wake on LAN (WoL) functions.
++
++if HIETH_GMAC
++
++config HIGMAC_DESC_4WORD
++        bool "higmac descriptor size is 4 words"
++        default y
++        help
++	  This define the size of higmac descriptor structure.
++	  In the newest version, descriptor size is 4 words.
++	  But in some old version, the size is 8 words.
++	  The default value is true.
++
++config HIGMAC_RXCSUM
++        bool "higmac Receive checksumming offload supported"
++        default y
++        help
++	  This indicate MAC support Receive checksumming offload.
++	  Support IPv4 and IPv6, tcp and udp.
++	  The default value is enabled.
++	  If old version MAC does not support, disable this option please.
++
++config RX_FLOW_CTRL_SUPPORT
++	bool "rx flow ctrl supported"
++	default y
++	help
++	  Rx flow ctrl supported, default is enabled.
++	  When we received pause frame,
++	  we will stop transmiting data frame for some time.
++	  The stopping time is the time filled in pause frame.
++
++config TX_FLOW_CTRL_SUPPORT
++	bool "tx flow ctrl supported"
++	default y
++	help
++	  Tx flow ctrl supported, default is enabled.
++	  When we has no buffer to receive packet,
++	  we will send pause frame.
++	  When buffer is available, we will send zero-quanta pause frame.
++
++config TX_FLOW_CTRL_PAUSE_TIME
++	hex "tx flow ctrl pause time"
++	default "0xFFFF"
++	help
++	  The pause time filled in the sending pause frame.
++	  The unit is the time for transmiting 512 bit data.
++	  This value is 16 bit, so its value is 0x0000~0xFFFF.
++	  The default value is 0xFFFF.
++
++config TX_FLOW_CTRL_PAUSE_INTERVAL
++	hex "tx flow ctrl pause interval"
++	default "0xFFFF"
++	help
++	  The interval time for sending pause frame.
++	  When the remainint amount of receive queue is below tx flow ctrl active threshold,
++	  we will wait this time to transmiting pause frame.
++	  The unit is the time for transmiting 512 bit data.
++	  This value is 16 bit, so its value is 0x0000~0xFFFF.
++	  The default value is 0xFFFF.
++
++config TX_FLOW_CTRL_ACTIVE_THRESHOLD
++	int "tx flow ctrl active threshold"
++	default "16"
++	range 1 127
++	help
++	  The threshold for activing tx flow ctrl.
++	  When the left amount of receive queue descriptors is below this threshold,
++	  hardware will send pause frame immediately.
++	  We advise this value is set smaller than 64. Too bigger is not a good choice.
++	  This value must be smaller than tx flow ctrl deactive threshold.
++
++config TX_FLOW_CTRL_DEACTIVE_THRESHOLD
++	int "tx flow ctrl deactive threshold"
++	default "32"
++	range 1 127
++	help
++	  The threshold for deactiving tx flow ctrl.
++	  When the left amount of receive queue descriptors is above or equal with this threshold,
++	  hardware will exit flow control state.
++	  We advise this value is set smaller than 64. Too bigger is not a good choice.
++	  This value must be larger than tx flow ctrl active threshold.
++
++endif # HIETH_GMAC
+diff --git a/drivers/net/ethernet/hisilicon/higmac/Makefile b/drivers/net/ethernet/hisilicon/higmac/Makefile
+new file mode 100644
+index 0000000..e3d9c53
+--- /dev/null
++++ b/drivers/net/ethernet/hisilicon/higmac/Makefile
+@@ -0,0 +1,2 @@
++obj-$(CONFIG_HIETH_GMAC) += hieth-gmac.o
++hieth-gmac-objs := board.o higmac.o autoeee/autoeee.o autoeee/phy_id_table.o
+diff --git a/drivers/net/ethernet/hisilicon/higmac/autoeee/autoeee.c b/drivers/net/ethernet/hisilicon/higmac/autoeee/autoeee.c
+new file mode 100644
+index 0000000..be12244
+--- /dev/null
++++ b/drivers/net/ethernet/hisilicon/higmac/autoeee/autoeee.c
+@@ -0,0 +1,125 @@
++#include <linux/phy.h>
++#include <linux/micrel_phy.h>
++#include "../higmac.h"
++#include "autoeee.h"
++
++void init_autoeee(struct higmac_netdev_local *ld)
++{
++	int phy_id = ld->phy->phy_id;
++	struct phy_info *phy_info;
++
++	if (ld->eee_init)
++		goto eee_init;
++
++	phy_info = phy_search_ids(phy_id);
++	if (phy_info) {
++		int eee_available, lp_eee_capable, v;
++		u32 link_stat = 0;
++
++		eee_available = phy_info->eee_available;
++		if (netif_msg_wol(ld))
++			pr_info("fit phy_id:0x%x, phy_name:%s, eee:%d\n",
++				phy_info->phy_id, phy_info->name,
++				eee_available);
++
++		if (!eee_available)
++			goto not_support;
++
++		if (eee_available == PHY_EEE) {
++			if (netif_msg_wol(ld))
++				pr_info("enter phy-EEE mode\n");
++
++			v = readl(ld->gmac_iobase + EEE_ENABLE);
++			v &= ~BIT_EEE_ENABLE;	/* disable auto-EEE */
++			writel(v, ld->gmac_iobase + EEE_ENABLE);
++			return;
++		}
++
++		ld->eee_init = phy_info->eee_init;
++eee_init:
++		switch (ld->phy->speed) {
++		case SPEED_10:
++			link_stat |= HIGMAC_SPD_10M;
++			break;
++		case SPEED_100:
++			link_stat |= HIGMAC_SPD_100M;
++			break;
++		case SPEED_1000:
++			link_stat |= HIGMAC_SPD_1000M;
++			break;
++		default:
++			break;
++		}
++
++		lp_eee_capable = ld->eee_init(ld->phy);
++		if (lp_eee_capable < 0)
++			return;
++
++		if (ld->phy->link) {
++			if (((u32)lp_eee_capable) & link_stat) {
++				if ((phy_id & REALTEK_PHY_MASK) ==
++				    REALTEK_PHY_ID_8211E) {
++					v = readl(ld->gmac_iobase + EEE_CLK);
++					v &= ~MASK_EEE_CLK;
++					v |= BIT_DISABLE_TX_CLK;
++					writel(v, ld->gmac_iobase + EEE_CLK);
++				} else if ((phy_id & MICREL_PHY_ID_MASK) ==
++					   PHY_ID_KSZ9031) {
++					v = readl(ld->gmac_iobase + EEE_CLK);
++					v &= ~MASK_EEE_CLK;
++					v |= (BIT_DISABLE_TX_CLK |
++						BIT_PHY_KSZ9031);
++					writel(v, ld->gmac_iobase + EEE_CLK);
++				}
++
++				/* EEE_1us: 0x7c for 125M */
++				writel(0x7c, ld->gmac_iobase +
++				       EEE_TIME_CLK_CNT);
++				writel(0x1e0400, ld->gmac_iobase +
++				       EEE_TIMER);/* FIXME */
++
++				v = readl(ld->gmac_iobase + EEE_LINK_STATUS);
++				v |= 0x3 << 1;	/* auto EEE and ... */
++				v |= BIT_PHY_LINK_STATUS;	/* phy linkup */
++				writel(v, ld->gmac_iobase + EEE_LINK_STATUS);
++
++				v = readl(ld->gmac_iobase + EEE_ENABLE);
++				v |= BIT_EEE_ENABLE;	/* enable EEE */
++				writel(v, ld->gmac_iobase + EEE_ENABLE);
++
++				if (netif_msg_wol(ld))
++					pr_info("enter auto-EEE mode\n");
++			} else {
++				if (netif_msg_wol(ld))
++					pr_info("link partner not support EEE\n");
++			}
++		} else {
++			v = readl(ld->gmac_iobase + EEE_LINK_STATUS);
++			v &= ~(BIT_PHY_LINK_STATUS);	/* phy linkdown */
++			writel(v, ld->gmac_iobase + EEE_LINK_STATUS);
++		}
++
++		return;
++	}
++
++not_support:
++	ld->eee_init = NULL;
++	if (netif_msg_wol(ld))
++		pr_info("non-EEE mode\n");
++}
++
++void eee_phy_linkdown(struct higmac_netdev_local *ld)
++{
++	int v = readl(ld->gmac_iobase + EEE_LINK_STATUS);
++	/* update phy link state */
++	v &= ~BIT_PHY_LINK_STATUS;
++	writel(v, ld->gmac_iobase + EEE_LINK_STATUS);
++}
++
++void eee_phy_linkup(struct higmac_netdev_local *ld)
++{
++	int v = readl(ld->gmac_iobase + EEE_LINK_STATUS);
++	/* update phy link state */
++	v |= BIT_PHY_LINK_STATUS;
++	writel(v, ld->gmac_iobase + EEE_LINK_STATUS);
++}
+diff --git a/drivers/net/ethernet/hisilicon/higmac/autoeee/autoeee.h b/drivers/net/ethernet/hisilicon/higmac/autoeee/autoeee.h
+new file mode 100644
+index 0000000..8f75a7a
+--- /dev/null
++++ b/drivers/net/ethernet/hisilicon/higmac/autoeee/autoeee.h
+@@ -0,0 +1,42 @@
++#ifndef	_AUTO_EEE_H
++
++#define NO_EEE          0
++#define MAC_EEE         1
++#define PHY_EEE         2
++#define PARTNER_EEE     2
++
++struct phy_info {
++	char *name;
++	int phy_id;
++	char eee_available;	/* eee support by this phy */
++	int (*eee_init)(struct phy_device *phy_dev);
++};
++
++/* GMAC register definition */
++#define EEE_CLK			0x800
++#define MASK_EEE_CLK		(0x3 << 20)
++#define BIT_DISABLE_TX_CLK	BIT(21)
++#define BIT_PHY_KSZ9031		BIT(20)
++#define EEE_ENABLE		0x808
++#define BIT_EEE_ENABLE		BIT(0)
++#define EEE_TIMER		0x80C
++#define EEE_LINK_STATUS		0x810
++#define BIT_PHY_LINK_STATUS	BIT(0)
++#define EEE_TIME_CLK_CNT	0x814
++
++/* ----------------------------phy register-------------------------------*/
++/* MMD: MDIO Manageable Device */
++#define MACR		0x0D
++#define MAADR		0x0E
++#define EEE_DEV		0x3
++#define EEE_CAPABILITY	0x14
++#define	EEELPAR_DEV	0x7
++#define EEELPAR		0x3D	/* EEE link partner ability register */
++#define EEE_ADVERTISE	0x3c
++#define LP_1000BASE_EEE	BIT(2)
++#define LP_100BASE_EEE	BIT(1)
++
++struct phy_info *phy_search_ids(int phy_id);
++void init_autoeee(struct higmac_netdev_local *ld);
++
++#endif
+diff --git a/drivers/net/ethernet/hisilicon/higmac/autoeee/phy_id_table.c b/drivers/net/ethernet/hisilicon/higmac/autoeee/phy_id_table.c
+new file mode 100644
+index 0000000..8ffaf2a
+--- /dev/null
++++ b/drivers/net/ethernet/hisilicon/higmac/autoeee/phy_id_table.c
+@@ -0,0 +1,177 @@
++#include <linux/delay.h>
++#include <linux/kernel.h>
++#include <linux/phy.h>
++#include "../higmac.h"
++#include "autoeee.h"
++
++struct phy_info phy_info_table[];
++
++struct phy_info *phy_search_ids(int phy_id)
++{
++	int i;
++	struct phy_info *fit_info = NULL;
++
++	for (i = 0; phy_info_table[i].name; i++) {
++		if (phy_id == phy_info_table[i].phy_id)
++			fit_info = &phy_info_table[i];
++	}
++
++	return fit_info;
++}
++
++static inline int phy_mmd_read(struct phy_device *phy_dev,
++			       u32 mmd_device, u32 regnum)
++{
++	phy_write(phy_dev, MACR, mmd_device);	/* function = 00 address */
++	phy_write(phy_dev, MAADR, regnum);
++	phy_write(phy_dev, MACR, 0x4000 | mmd_device);	/* function = 01 data */
++
++	return phy_read(phy_dev, MAADR);
++}
++
++static inline int phy_mmd_write(struct phy_device *phy_dev, u32 mmd_device,
++				u32 regnum, u16 val)
++{
++	phy_write(phy_dev, MACR, mmd_device);	/* function = 00 address */
++	phy_write(phy_dev, MAADR, regnum);
++	phy_write(phy_dev, MACR, 0x4000 | mmd_device);	/* function = 01 data */
++
++	return phy_write(phy_dev, MAADR, val);
++}
++
++static int smsc_lan8740_init(struct phy_device *phy_dev)
++{
++	static int first_time;
++	int v, eee_type = 0;
++
++	if (!first_time) {
++		/* Realtek LAN 8740 start to enable eee */
++		int eee_lan;
++
++		eee_lan = phy_read(phy_dev, 0x10);
++		if (eee_lan < 0)
++			return eee_lan;
++		eee_lan |= 0x4;
++		phy_write(phy_dev, 0x10, eee_lan);
++		eee_lan = phy_read(phy_dev, 0x10);
++		if (eee_lan < 0)
++			return eee_lan;
++		/* auto negotiate after enable eee */
++		eee_lan = phy_read(phy_dev, 0x0);
++		if (eee_lan < 0)
++			return eee_lan;
++		eee_lan |= 0x200;
++		phy_write(phy_dev, 0x0, eee_lan);
++		first_time = 1;
++	}
++
++	v = phy_mmd_read(phy_dev, EEELPAR_DEV, EEELPAR);
++
++	if (v & LP_1000BASE_EEE)
++		eee_type |= HIGMAC_SPD_1000M;
++	if (v & LP_100BASE_EEE)
++		eee_type |= HIGMAC_SPD_100M;
++
++	return eee_type;
++}
++
++#define RTL8211EG_MAC	0
++#if RTL8211EG_MAC
++static int rtl8211EG_mac_init(struct phy_device *phy_dev)
++{
++	static int first_time;
++	/* Realtek 8211EG start reset to change eee to mac */
++	int v, eee_type = 0;
++
++	if (!first_time) {
++		int tmp = 0;
++
++		phy_write(phy_dev, 0x1f, 0x0);
++		phy_write(phy_dev, MII_BMCR, BMCR_RESET);	/* reset phy */
++		do {		/* wait phy restart over */
++			udelay(1);
++			tmp = phy_read(phy_dev, MII_BMSR);
++			/* no need to wait AN finished */
++			tmp &= (BMSR_ANEGCOMPLETE | BMSR_ANEGCAPABLE);
++		} while (!tmp);
++
++		phy_write(phy_dev, 0x1f, 0x7);
++		phy_write(phy_dev, 0x1e, 0x20);
++		phy_write(phy_dev, 0x1b, 0xa03a);
++		phy_write(phy_dev, 0x1f, 0x0);
++
++		first_time = 1;
++	}
++
++	v = phy_mmd_read(phy_dev, EEELPAR_DEV, EEELPAR);
++
++	if (v & LP_1000BASE_EEE)
++		eee_type |= HIGMAC_SPD_1000M;
++	if (v & LP_100BASE_EEE)
++		eee_type |= HIGMAC_SPD_100M;
++
++	return eee_type;
++}
++#else
++static int rtl8211EG_init(struct phy_device *phy_dev)
++{
++	int eee_type = 0, v;
++
++	v = phy_mmd_read(phy_dev, EEELPAR_DEV, EEELPAR);
++
++	if (v & LP_1000BASE_EEE)
++		eee_type |= HIGMAC_SPD_1000M;
++	if (v & LP_100BASE_EEE)
++		eee_type |= HIGMAC_SPD_100M;
++
++	return eee_type;
++}
++#endif
++
++static int festa_v200_init(struct phy_device *phy_dev)
++{
++	static int first_time_init;
++	int v, eee_type = 0;
++
++	if (!first_time_init) {
++		/* EEE_CAPABILITY register: support 100M-BaseT */
++		v = phy_mmd_read(phy_dev, EEE_DEV, EEE_CAPABILITY);
++		phy_mmd_write(phy_dev, EEE_DEV, EEE_CAPABILITY,
++			      ((u32)v) | BIT(1));
++
++		/* EEE_ADVERTISEMENT register: advertising 100M-BaseT */
++		v = phy_mmd_read(phy_dev, EEELPAR_DEV, EEE_ADVERTISE);
++		phy_mmd_write(phy_dev, EEELPAR_DEV, EEE_ADVERTISE,
++			      ((u32)v) | BIT(1));
++
++		v = phy_read(phy_dev, MII_BMCR);
++		if (v < 0)
++			return v;
++		v |= (BMCR_ANENABLE | BMCR_ANRESTART);
++		phy_write(phy_dev, MII_BMCR, v);	/* auto-neg restart */
++
++		first_time_init = 1;
++	}
++
++	v = phy_mmd_read(phy_dev, EEELPAR_DEV, EEELPAR);
++
++	if (v & LP_1000BASE_EEE)
++		eee_type |= HIGMAC_SPD_1000M;
++	if (v & LP_100BASE_EEE)
++		eee_type |= HIGMAC_SPD_100M;
++
++	return eee_type;
++}
++
++struct phy_info phy_info_table[] = {
++	/* phy_name             phy_id  eee_available   phy_driver */
++/* SMSC */
++	{"SMSC LAN8740", 0x0007c110, MAC_EEE, &smsc_lan8740_init},
++/* Realtek */
++#if RTL8211EG_MAC
++	{"Realtek 8211EG", 0x001cc915, MAC_EEE, &rtl8211EG_mac_init},
++#else
++	{"Realtek 8211EG", 0x001cc915, PHY_EEE, &rtl8211EG_init},
++#endif
++	{"Festa V200", HISILICON_PHY_ID_FESTAV200, MAC_EEE, &festa_v200_init},
++};
+diff --git a/drivers/net/ethernet/hisilicon/higmac/board.c b/drivers/net/ethernet/hisilicon/higmac/board.c
+new file mode 100644
+index 0000000..89b9d16
+--- /dev/null
++++ b/drivers/net/ethernet/hisilicon/higmac/board.c
+@@ -0,0 +1,96 @@
++#include <linux/clk.h>
++#include <linux/kernel.h>
++#include <linux/reset.h>
++#include "higmac.h"
++
++void higmac_mac_core_reset(struct higmac_netdev_local *priv)
++{
++	/* undo reset */
++	reset_control_deassert(priv->port_rst);
++	usleep_range(50, 60);
++
++	/* soft reset mac port */
++	reset_control_assert(priv->port_rst);
++	usleep_range(50, 60);
++	/* undo reset */
++	reset_control_deassert(priv->port_rst);
++}
++
++void higmac_hw_internal_phy_reset(struct higmac_netdev_local *priv)
++{
++}
++
++void higmac_hw_phy_reset(struct higmac_netdev_local *priv)
++{
++	if (priv->internal_phy)
++		higmac_hw_internal_phy_reset(priv);
++	else
++		higmac_hw_external_phy_reset(priv);
++}
++
++void higmac_hw_external_phy_reset(struct higmac_netdev_local *priv)
++{
++	if (priv->phy_rst) {
++		/* write 0 to cancel reset */
++		reset_control_deassert(priv->phy_rst);
++		msleep(50);
++
++		/* HIFONE or 98cv200 use CRG register to reset phy */
++		/* RST_BIT, write 0 to reset phy, write 1 to cancel reset */
++		reset_control_assert(priv->phy_rst);
++
++		/* delay some time to ensure reset ok,
++		 * this depends on PHY hardware feature
++		 */
++		msleep(50);
++
++		/* write 0 to cancel reset */
++		reset_control_deassert(priv->phy_rst);
++		/* delay some time to ensure later MDIO access */
++		msleep(50);
++	}
++}
++
++void higmac_internal_phy_clk_disable(struct higmac_netdev_local *priv)
++{
++}
++
++void higmac_internal_phy_clk_enable(struct higmac_netdev_local *priv)
++{
++}
++
++void higmac_hw_all_clk_disable(struct higmac_netdev_local *priv)
++{
++	/* If macif clock is enabled when suspend, we should
++	 * disable it here.
++	 * Because when resume, PHY will link up again and
++	 * macif clock will be enabled too. If we don't disable
++	 * macif clock in suspend, macif clock will be enabled twice.
++	 */
++	if (priv->netdev->flags & IFF_UP)
++		clk_disable_unprepare(priv->macif_clk);
++
++	/* This is called in suspend, when net device is down,
++	 * MAC clk is disabled.
++	 * So we need to judge whether MAC clk is enabled,
++	 * otherwise kernel will WARNING if clk disable twice.
++	 */
++	if (priv->netdev->flags & IFF_UP)
++		clk_disable_unprepare(priv->clk);
++
++	if (priv->internal_phy)
++		higmac_internal_phy_clk_disable(priv);
++}
++
++void higmac_hw_all_clk_enable(struct higmac_netdev_local *priv)
++{
++	if (priv->internal_phy)
++		higmac_internal_phy_clk_enable(priv);
++
++	if (priv->netdev->flags & IFF_UP)
++		clk_prepare_enable(priv->macif_clk);
++
++	/* If net device is down when suspend, we should not enable MAC clk. */
++	if (priv->netdev->flags & IFF_UP)
++		clk_prepare_enable(priv->clk);
++}
+diff --git a/drivers/net/ethernet/hisilicon/higmac/higmac.c b/drivers/net/ethernet/hisilicon/higmac/higmac.c
+new file mode 100644
+index 0000000..135788f
+--- /dev/null
++++ b/drivers/net/ethernet/hisilicon/higmac/higmac.c
+@@ -0,0 +1,3120 @@
++#include <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/unistd.h>
++#include <linux/interrupt.h>
++#include <linux/delay.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/skbuff.h>
++#include <linux/spinlock.h>
++#include <linux/mm.h>
++#include <linux/mii.h>
++#include <linux/ethtool.h>
++#include <linux/phy.h>
++#include <linux/dma-mapping.h>
++#include <linux/workqueue.h>
++#include <linux/device.h>
++#include <linux/atomic.h>
++#include <linux/platform_device.h>
++#include <linux/capability.h>
++#include <linux/time.h>
++#include <asm/setup.h>
++#include <linux/proc_fs.h>
++#include <linux/module.h>
++
++#include <linux/circ_buf.h>
++#include <linux/if_vlan.h>
++#include <linux/ip.h>
++#include <linux/ipv6.h>
++#include <net/ipv6.h>
++
++#include <linux/of_net.h>
++#include <linux/of_mdio.h>
++#include <linux/clk.h>
++#include <linux/reset.h>
++
++#include "util.h"
++#include "higmac.h"
++#include "autoeee/autoeee.h"
++#include "sockioctl.h"
++
++#define HAS_TSO_CAP(hw_cap)		((((hw_cap) >> 28) & 0x3) == VER_TSO)
++#define HAS_RXHASH_CAP(hw_cap)		((hw_cap) & BIT(30))
++#define HAS_RSS_CAP(hw_cap)		((hw_cap) & BIT(31))
++
++#define RGMII_SPEED_1000		0x2c
++#define RGMII_SPEED_100			0x2f
++#define RGMII_SPEED_10			0x2d
++#define MII_SPEED_100			0x0f
++#define MII_SPEED_10			0x0d
++#define RMII_SPEED_100			0x8f
++#define RMII_SPEED_10			0x8d
++#define GMAC_FULL_DUPLEX		BIT(4)
++
++static unsigned int flow_ctrl_en = FLOW_OFF;
++static int tx_flow_ctrl_pause_time = CONFIG_TX_FLOW_CTRL_PAUSE_TIME;
++static int tx_flow_ctrl_pause_interval = CONFIG_TX_FLOW_CTRL_PAUSE_INTERVAL;
++static int tx_flow_ctrl_active_threshold = CONFIG_TX_FLOW_CTRL_ACTIVE_THRESHOLD;
++static int tx_flow_ctrl_deactive_threshold =
++				CONFIG_TX_FLOW_CTRL_DEACTIVE_THRESHOLD;
++
++#define DEFAULT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK)
++static int debug = -1;
++module_param(debug, int, 0000);
++MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
++
++static void higmac_config_port(struct net_device *dev, u32 speed, u32 duplex)
++{
++	struct higmac_netdev_local *priv = netdev_priv(dev);
++	u32 val;
++
++	switch (priv->phy_mode) {
++	case PHY_INTERFACE_MODE_RGMII:
++		if (speed == SPEED_1000)
++			val = RGMII_SPEED_1000;
++		else if (speed == SPEED_100)
++			val = RGMII_SPEED_100;
++		else
++			val = RGMII_SPEED_10;
++		break;
++	case PHY_INTERFACE_MODE_MII:
++		if (speed == SPEED_100)
++			val = MII_SPEED_100;
++		else
++			val = MII_SPEED_10;
++		break;
++	case PHY_INTERFACE_MODE_RMII:
++		if (speed == SPEED_100)
++			val = RMII_SPEED_100;
++		else
++			val = RMII_SPEED_10;
++		break;
++	default:
++		netdev_warn(dev, "not supported mode\n");
++		val = MII_SPEED_10;
++		break;
++	}
++
++	if (duplex)
++		val |= GMAC_FULL_DUPLEX;
++
++	reset_control_assert(priv->macif_rst);
++	writel_relaxed(val, priv->macif_base);
++	reset_control_deassert(priv->macif_rst);
++
++	writel_relaxed(BIT_MODE_CHANGE_EN, priv->gmac_iobase + MODE_CHANGE_EN);
++	if (speed == SPEED_1000)
++		val = GMAC_SPEED_1000;
++	else if (speed == SPEED_100)
++		val = GMAC_SPEED_100;
++	else
++		val = GMAC_SPEED_10;
++	writel_relaxed(val, priv->gmac_iobase + PORT_MODE);
++	writel_relaxed(0, priv->gmac_iobase + MODE_CHANGE_EN);
++	writel_relaxed(duplex, priv->gmac_iobase + MAC_DUPLEX_HALF_CTRL);
++}
++
++static void higmac_set_desc_depth(struct higmac_netdev_local *priv,
++				  u32 rx, u32 tx)
++{
++	u32 reg;
++	int i;
++
++	writel(BITS_RX_FQ_DEPTH_EN, priv->gmac_iobase + RX_FQ_REG_EN);
++	writel(rx << DESC_WORD_SHIFT, priv->gmac_iobase + RX_FQ_DEPTH);
++	writel(0, priv->gmac_iobase + RX_FQ_REG_EN);
++
++	writel(BITS_RX_BQ_DEPTH_EN, priv->gmac_iobase + RX_BQ_REG_EN);
++	writel(rx << DESC_WORD_SHIFT, priv->gmac_iobase + RX_BQ_DEPTH);
++	for (i = 1; i < priv->num_rxqs; i++) {
++		reg = RX_BQ_DEPTH_QUEUE(i);
++		writel(rx << DESC_WORD_SHIFT, priv->gmac_iobase + reg);
++	}
++	writel(0, priv->gmac_iobase + RX_BQ_REG_EN);
++
++	writel(BITS_TX_BQ_DEPTH_EN, priv->gmac_iobase + TX_BQ_REG_EN);
++	writel(tx << DESC_WORD_SHIFT, priv->gmac_iobase + TX_BQ_DEPTH);
++	writel(0, priv->gmac_iobase + TX_BQ_REG_EN);
++
++	writel(BITS_TX_RQ_DEPTH_EN, priv->gmac_iobase + TX_RQ_REG_EN);
++	writel(tx << DESC_WORD_SHIFT, priv->gmac_iobase + TX_RQ_DEPTH);
++	writel(0, priv->gmac_iobase + TX_RQ_REG_EN);
++}
++
++static void higmac_set_rx_fq(struct higmac_netdev_local *priv,
++			     dma_addr_t phy_addr)
++{
++	writel(BITS_RX_FQ_START_ADDR_EN, priv->gmac_iobase + RX_FQ_REG_EN);
++	writel(phy_addr, priv->gmac_iobase + RX_FQ_START_ADDR);
++	writel(0, priv->gmac_iobase + RX_FQ_REG_EN);
++}
++
++static void higmac_set_rx_bq(struct higmac_netdev_local *priv,
++			     dma_addr_t phy_addr)
++{
++	writel(BITS_RX_BQ_START_ADDR_EN, priv->gmac_iobase + RX_BQ_REG_EN);
++	writel(phy_addr, priv->gmac_iobase + RX_BQ_START_ADDR);
++	writel(0, priv->gmac_iobase + RX_BQ_REG_EN);
++}
++
++static void higmac_set_tx_bq(struct higmac_netdev_local *priv,
++			     dma_addr_t phy_addr)
++{
++	writel(BITS_TX_BQ_START_ADDR_EN, priv->gmac_iobase + TX_BQ_REG_EN);
++	writel(phy_addr, priv->gmac_iobase + TX_BQ_START_ADDR);
++	writel(0, priv->gmac_iobase + TX_BQ_REG_EN);
++}
++
++static void higmac_set_tx_rq(struct higmac_netdev_local *priv,
++			     dma_addr_t phy_addr)
++{
++	writel(BITS_TX_RQ_START_ADDR_EN, priv->gmac_iobase + TX_RQ_REG_EN);
++	writel(phy_addr, priv->gmac_iobase + TX_RQ_START_ADDR);
++	writel(0, priv->gmac_iobase + TX_RQ_REG_EN);
++}
++
++static void higmac_hw_set_desc_addr(struct higmac_netdev_local *priv)
++{
++	u32 reg;
++	int i;
++
++	higmac_set_rx_fq(priv, priv->rx_fq.phys_addr);
++	higmac_set_rx_bq(priv, priv->rx_bq.phys_addr);
++	higmac_set_tx_rq(priv, priv->tx_rq.phys_addr);
++	higmac_set_tx_bq(priv, priv->tx_bq.phys_addr);
++
++	for (i = 1; i < priv->num_rxqs; i++) {
++		reg = RX_BQ_START_ADDR_QUEUE(i);
++		writel(BITS_RX_BQ_START_ADDR_EN,
++		       priv->gmac_iobase + RX_BQ_REG_EN);
++		writel(priv->pool[3 + i].phys_addr, priv->gmac_iobase + reg);
++		writel(0, priv->gmac_iobase + RX_BQ_REG_EN);
++	}
++}
++
++static void higmac_set_rss_cap(struct higmac_netdev_local *priv)
++{
++	u32 val = 0;
++
++	if (priv->has_rxhash_cap)
++		val |= BIT_RXHASH_CAP;
++	if (priv->has_rss_cap)
++		val |= BIT_RSS_CAP;
++	writel(val, priv->gmac_iobase + HW_CAP_EN);
++}
++
++static void higmac_hw_init(struct higmac_netdev_local *priv)
++{
++	u32 val;
++	u32 reg;
++	int i;
++
++#if defined(CONFIG_ARCH_HI3519) || defined(CONFIG_ARCH_HI3519V101) || \
++	defined(CONFIG_ARCH_HI3559) || defined(CONFIG_ARCH_HI3556) || \
++	defined(CONFIG_ARCH_HI3516AV200)
++	/* config AXI parameter for better performance. */
++	val = readl(priv->gmac_iobase + BURST_OUTSTANDING_REG);
++	val >>= BURST_OUTSTANDING_OFFSET;
++	if (!val)
++		writel(BURST4_OUTSTANDING1, priv->gmac_iobase +
++			BURST_OUTSTANDING_REG);
++#elif (defined(CONFIG_ARCH_HI3531D))
++	/* config AXI parameter for better performance. */
++	writel(BURST4_OUTSTANDING1, priv->gmac_iobase +
++		BURST_OUTSTANDING_REG);
++#endif
++
++	/* disable and clear all interrupts */
++	writel(0, priv->gmac_iobase + ENA_PMU_INT);
++	writel(~0, priv->gmac_iobase + RAW_PMU_INT);
++
++	for (i = 1; i < priv->num_rxqs; i++) {
++		reg = RSS_ENA_INT_QUEUE(i);
++		writel(0, priv->gmac_iobase + reg);
++	}
++	writel(~0, priv->gmac_iobase + RSS_RAW_PMU_INT);
++
++	/* enable CRC erro packets filter */
++	val = readl(priv->gmac_iobase + REC_FILT_CONTROL);
++	val |= BIT_CRC_ERR_PASS;
++	writel(val, priv->gmac_iobase + REC_FILT_CONTROL);
++
++	/* set tx min packet length */
++	val = readl(priv->gmac_iobase + CRF_MIN_PACKET);
++	val &= ~BIT_MASK_TX_MIN_LEN;
++	val |= ETH_HLEN << BIT_OFFSET_TX_MIN_LEN;
++	writel(val, priv->gmac_iobase + CRF_MIN_PACKET);
++
++	/* fix bug for udp and ip error check */
++	writel(CONTROL_WORD_CONFIG, priv->gmac_iobase + CONTROL_WORD);
++
++	writel(0, priv->gmac_iobase + COL_SLOT_TIME);
++
++	writel(DUPLEX_HALF, priv->gmac_iobase + MAC_DUPLEX_HALF_CTRL);
++
++	/* FIXME: interrupt when rcv packets >= RX_BQ_INT_THRESHOLD */
++	val = RX_BQ_INT_THRESHOLD |
++		(TX_RQ_INT_THRESHOLD << BITS_OFFSET_TX_RQ_IN_TH);
++	writel(val, priv->gmac_iobase + IN_QUEUE_TH);
++
++	/* FIXME: rx_bq/tx_rq in timeout threshold */
++	writel(0x10000, priv->gmac_iobase + RX_BQ_IN_TIMEOUT_TH);
++
++	writel(0x18000, priv->gmac_iobase + TX_RQ_IN_TIMEOUT_TH);
++
++	higmac_set_desc_depth(priv, RX_DESC_NUM, TX_DESC_NUM);
++}
++
++static inline void higmac_irq_enable(struct higmac_netdev_local *ld)
++{
++	writel(RX_BQ_IN_INT | RX_BQ_IN_TIMEOUT_INT
++		| TX_RQ_IN_INT | TX_RQ_IN_TIMEOUT_INT,
++		ld->gmac_iobase + ENA_PMU_INT);
++}
++
++static inline void higmac_irq_enable_queue(struct higmac_netdev_local *ld,
++					   int rxq_id)
++{
++	if (rxq_id) {
++		u32 reg;
++
++		reg = RSS_ENA_INT_QUEUE(rxq_id);
++		writel(~0, ld->gmac_iobase + reg);
++	} else {
++		higmac_irq_enable(ld);
++	}
++}
++
++static inline void higmac_irq_enable_all_queue(struct higmac_netdev_local *ld)
++{
++	int i;
++
++	for (i = 0; i < ld->num_rxqs; i++)
++		higmac_irq_enable_queue(ld, i);
++}
++
++static inline void higmac_irq_disable(struct higmac_netdev_local *ld)
++{
++	writel(0, ld->gmac_iobase + ENA_PMU_INT);
++}
++
++static inline void higmac_irq_disable_queue(struct higmac_netdev_local *ld,
++					    int rxq_id)
++{
++	if (rxq_id) {
++		u32 reg;
++
++		reg = RSS_ENA_INT_QUEUE(rxq_id);
++		writel(0, ld->gmac_iobase + reg);
++	} else {
++		higmac_irq_disable(ld);
++	}
++}
++
++static inline void higmac_irq_disable_all_queue(struct higmac_netdev_local *ld)
++{
++	int i;
++
++	for (i = 0; i < ld->num_rxqs; i++)
++		higmac_irq_disable_queue(ld, i);
++}
++
++static inline bool higmac_queue_irq_disabled(struct higmac_netdev_local *ld,
++					     int rxq_id)
++{
++	u32 reg, val;
++
++	if (rxq_id)
++		reg = RSS_ENA_INT_QUEUE(rxq_id);
++	else
++		reg = ENA_PMU_INT;
++	val = readl(ld->gmac_iobase + reg);
++
++	return !val;
++}
++
++static inline void higmac_hw_desc_enable(struct higmac_netdev_local *ld)
++{
++	writel(0xF, ld->gmac_iobase + DESC_WR_RD_ENA);
++}
++
++static inline void higmac_hw_desc_disable(struct higmac_netdev_local *ld)
++{
++	writel(0, ld->gmac_iobase + DESC_WR_RD_ENA);
++}
++
++static inline void higmac_port_enable(struct higmac_netdev_local *ld)
++{
++	writel(BITS_TX_EN | BITS_RX_EN, ld->gmac_iobase + PORT_EN);
++}
++
++static inline void higmac_port_disable(struct higmac_netdev_local *ld)
++{
++	writel(0, ld->gmac_iobase + PORT_EN);
++}
++
++void higmac_set_flow_ctrl_params(struct higmac_netdev_local *ld)
++{
++	unsigned int rx_fq_empty_th;
++	unsigned int rx_fq_full_th;
++	unsigned int rx_bq_empty_th;
++	unsigned int rx_bq_full_th;
++	unsigned int rec_filter;
++
++	writel(ld->pause, ld->gmac_iobase + FC_TX_TIMER);
++	writel(ld->pause_interval, ld->gmac_iobase + PAUSE_THR);
++
++	rx_fq_empty_th = readl(ld->gmac_iobase + RX_FQ_ALEMPTY_TH);
++	rx_fq_empty_th &= ~(BITS_Q_PAUSE_TH_MASK << BITS_Q_PAUSE_TH_OFFSET);
++	rx_fq_empty_th |= (ld->flow_ctrl_active_threshold <<
++			BITS_Q_PAUSE_TH_OFFSET);
++	writel(rx_fq_empty_th, ld->gmac_iobase + RX_FQ_ALEMPTY_TH);
++
++	rx_fq_full_th = readl(ld->gmac_iobase + RX_FQ_ALFULL_TH);
++	rx_fq_full_th &= ~(BITS_Q_PAUSE_TH_MASK << BITS_Q_PAUSE_TH_OFFSET);
++	rx_fq_full_th |= (ld->flow_ctrl_deactive_threshold <<
++			BITS_Q_PAUSE_TH_OFFSET);
++	writel(rx_fq_full_th, ld->gmac_iobase + RX_FQ_ALFULL_TH);
++
++	rx_bq_empty_th = readl(ld->gmac_iobase + RX_BQ_ALEMPTY_TH);
++	rx_bq_empty_th &= ~(BITS_Q_PAUSE_TH_MASK << BITS_Q_PAUSE_TH_OFFSET);
++	rx_bq_empty_th |= (ld->flow_ctrl_active_threshold <<
++			BITS_Q_PAUSE_TH_OFFSET);
++	writel(rx_bq_empty_th, ld->gmac_iobase + RX_BQ_ALEMPTY_TH);
++
++	rx_bq_full_th = readl(ld->gmac_iobase + RX_BQ_ALFULL_TH);
++	rx_bq_full_th &= ~(BITS_Q_PAUSE_TH_MASK << BITS_Q_PAUSE_TH_OFFSET);
++	rx_bq_full_th |= (ld->flow_ctrl_deactive_threshold <<
++			BITS_Q_PAUSE_TH_OFFSET);
++	writel(rx_bq_full_th, ld->gmac_iobase + RX_BQ_ALFULL_TH);
++
++	writel(0, ld->gmac_iobase + CRF_TX_PAUSE);
++
++	rec_filter = readl(ld->gmac_iobase + REC_FILT_CONTROL);
++	rec_filter |= BIT_PAUSE_FRM_PASS;
++	writel(rec_filter, ld->gmac_iobase + REC_FILT_CONTROL);
++}
++
++void higmac_set_flow_ctrl_state(struct higmac_netdev_local *ld, int pause)
++{
++	unsigned int flow_rx_q_en;
++	unsigned int flow;
++
++	flow_rx_q_en = readl(ld->gmac_iobase + RX_PAUSE_EN);
++	flow_rx_q_en &= ~(BIT_RX_FQ_PAUSE_EN | BIT_RX_BQ_PAUSE_EN);
++	if (pause && (ld->flow_ctrl & FLOW_TX))
++		flow_rx_q_en |= (BIT_RX_FQ_PAUSE_EN | BIT_RX_BQ_PAUSE_EN);
++	writel(flow_rx_q_en, ld->gmac_iobase + RX_PAUSE_EN);
++
++	flow = readl(ld->gmac_iobase + PAUSE_EN);
++	flow &= ~(BIT_RX_FDFC | BIT_TX_FDFC);
++	if (pause) {
++		if (ld->flow_ctrl & FLOW_RX)
++			flow |= BIT_RX_FDFC;
++		if (ld->flow_ctrl & FLOW_TX)
++			flow |= BIT_TX_FDFC;
++	}
++	writel(flow, ld->gmac_iobase + PAUSE_EN);
++}
++
++static void higmac_set_flow_ctrl_args(struct higmac_netdev_local *ld)
++{
++	ld->flow_ctrl = flow_ctrl_en;
++	ld->pause = tx_flow_ctrl_pause_time;
++	ld->pause_interval = tx_flow_ctrl_pause_interval;
++	ld->flow_ctrl_active_threshold = tx_flow_ctrl_active_threshold;
++	ld->flow_ctrl_deactive_threshold = tx_flow_ctrl_deactive_threshold;
++}
++
++/* set gmac's multicast list, here we setup gmac's mc filter */
++static void higmac_gmac_multicast_list(struct net_device *dev)
++{
++	struct higmac_netdev_local *ld = netdev_priv(dev);
++	unsigned int rec_filter;
++
++	rec_filter = readl(ld->gmac_iobase + REC_FILT_CONTROL);
++	/* when set gmac in promisc mode
++	 * a. dev in IFF_PROMISC mode
++	 */
++	if ((dev->flags & IFF_PROMISC)) {
++		/* promisc mode.received all pkgs. */
++		rec_filter &= ~(BIT_BC_DROP_EN | BIT_MC_MATCH_EN |
++				BIT_UC_MATCH_EN);
++	} else {
++		/* drop uc pkgs with field 'DA' not match our's */
++		rec_filter |= BIT_UC_MATCH_EN;
++
++		if (dev->flags & IFF_BROADCAST)	/* no broadcast */
++			rec_filter &= ~BIT_BC_DROP_EN;
++		else
++			rec_filter |= BIT_BC_DROP_EN;
++
++		if (netdev_mc_empty(dev) || !(dev->flags & IFF_MULTICAST)) {
++			/* haven't join any mc group */
++			writel(0, ld->gmac_iobase + PORT_MC_ADDR_LOW);
++			writel(0, ld->gmac_iobase + PORT_MC_ADDR_HIGH);
++			rec_filter |= BIT_MC_MATCH_EN;
++		} else if (netdev_mc_count(dev) == 1 &&
++			(dev->flags & IFF_MULTICAST)) {
++			struct netdev_hw_addr *ha;
++			unsigned int d = 0;
++
++			netdev_for_each_mc_addr(ha, dev) {
++				d = (ha->addr[0] << 8) | (ha->addr[1]);
++				writel(d, ld->gmac_iobase + PORT_MC_ADDR_HIGH);
++
++				d = (ha->addr[2] << 24) | (ha->addr[3] << 16)
++					| (ha->addr[4] << 8) | (ha->addr[5]);
++				writel(d, ld->gmac_iobase + PORT_MC_ADDR_LOW);
++			}
++			rec_filter |= BIT_MC_MATCH_EN;
++		} else {
++			rec_filter &= ~BIT_MC_MATCH_EN;
++		}
++	}
++	writel(rec_filter, ld->gmac_iobase + REC_FILT_CONTROL);
++}
++
++/* the func stop the hw desc and relaim the software skb resource
++ * before reusing the gmac, you'd better reset the gmac
++ */
++void higmac_reclaim_rx_tx_resource(struct higmac_netdev_local *ld)
++{
++	unsigned long rxflags, txflags;
++	int rd_offset, wr_offset;
++	int i;
++
++	higmac_irq_disable_all_queue(ld);
++	higmac_hw_desc_disable(ld);
++	writel(STOP_RX_TX, ld->gmac_iobase + STOP_CMD);
++
++	spin_lock_irqsave(&ld->rxlock, rxflags);
++	/* rx_bq: logic write pointer */
++	wr_offset = readl(ld->gmac_iobase + RX_BQ_WR_ADDR);
++	/* rx_bq: software read pointer */
++	rd_offset = readl(ld->gmac_iobase + RX_BQ_RD_ADDR);
++	/* FIXME: prevent to reclaim skb in rx bottom half */
++	writel(wr_offset, ld->gmac_iobase + RX_BQ_RD_ADDR);
++
++	for (i = 1; i < ld->num_rxqs; i++) {
++		u32 rx_bq_wr_reg, rx_bq_rd_reg;
++
++		rx_bq_wr_reg = RX_BQ_WR_ADDR_QUEUE(i);
++		rx_bq_rd_reg = RX_BQ_RD_ADDR_QUEUE(i);
++
++		wr_offset = readl(ld->gmac_iobase + rx_bq_wr_reg);
++		writel(wr_offset, ld->gmac_iobase + rx_bq_rd_reg);
++	}
++
++	/* rx_fq: software write pointer */
++	wr_offset = readl(ld->gmac_iobase + RX_FQ_WR_ADDR);
++	/* rx_fq: logic read pointer */
++	rd_offset = readl(ld->gmac_iobase + RX_FQ_RD_ADDR);
++	if (!rd_offset)
++		rd_offset = (RX_DESC_NUM - 1) << DESC_BYTE_SHIFT;
++	else
++		rd_offset -= DESC_SIZE;
++	/* FIXME: stop to feed hw desc */
++	writel(rd_offset, ld->gmac_iobase + RX_FQ_WR_ADDR);
++
++	for (i = 0; i < ld->rx_fq.count; i++) {
++		if (!ld->rx_fq.skb[i])
++			ld->rx_fq.skb[i] = SKB_MAGIC;
++	}
++	spin_unlock_irqrestore(&ld->rxlock, rxflags);
++
++	/* no need to wait pkts in tx_rq finish to free all skb,
++	 * because higmac_xmit_reclaim is in the tx_lock,
++	 */
++	spin_lock_irqsave(&ld->txlock, txflags);
++	/* tx_rq: logic write */
++	wr_offset = readl(ld->gmac_iobase + TX_RQ_WR_ADDR);
++	/* tx_rq: software read */
++	rd_offset = readl(ld->gmac_iobase + TX_RQ_RD_ADDR);
++	/* FIXME: stop to reclaim tx skb */
++	writel(wr_offset, ld->gmac_iobase + TX_RQ_RD_ADDR);
++
++	/* tx_bq: logic read */
++	rd_offset = readl(ld->gmac_iobase + TX_BQ_RD_ADDR);
++	if (!rd_offset)
++		rd_offset = (TX_DESC_NUM - 1) << DESC_BYTE_SHIFT;
++	else
++		rd_offset -= DESC_SIZE;
++	/* FIXME: stop software tx skb */
++	writel(rd_offset, ld->gmac_iobase + TX_BQ_WR_ADDR);
++
++	for (i = 0; i < ld->tx_bq.count; i++) {
++		if (!ld->tx_bq.skb[i])
++			ld->tx_bq.skb[i] = SKB_MAGIC;
++	}
++	spin_unlock_irqrestore(&ld->txlock, txflags);
++}
++
++static void higmac_monitor_func(unsigned long arg);
++static void higmac_set_multicast_list(struct net_device *dev);
++
++static void higmac_hw_set_mac_addr(struct net_device *dev)
++{
++	struct higmac_netdev_local *priv = netdev_priv(dev);
++	unsigned char *mac = dev->dev_addr;
++	u32 val;
++
++	val = mac[1] | (mac[0] << 8);
++	writel(val, priv->gmac_iobase + STATION_ADDR_HIGH);
++
++	val = mac[5] | (mac[4] << 8) | (mac[3] << 16) | (mac[2] << 24);
++	writel(val, priv->gmac_iobase + STATION_ADDR_LOW);
++}
++
++static u32 higmac_rx_refill(struct higmac_netdev_local *priv);
++
++static void higmac_free_rx_skb(struct higmac_netdev_local *ld)
++{
++	struct sk_buff *skb = NULL;
++	int i;
++
++	for (i = 0; i < ld->rx_fq.count; i++) {
++		skb = ld->rx_fq.skb[i];
++		if (skb) {
++			ld->rx_skb[i] = NULL;
++			ld->rx_fq.skb[i] = NULL;
++			if (skb == SKB_MAGIC)
++				continue;
++			dev_kfree_skb_any(skb);
++			/* TODO: need to unmap the skb here
++			 * but there is no way to get the dma_addr here,
++			 * and unmap(TO_DEVICE) ops do nothing in fact,
++			 * so we ignore to call
++			 * dma_unmap_single(dev, dma_addr, skb->len,
++			 *      DMA_TO_DEVICE)
++			 */
++		}
++	}
++}
++
++static void higmac_free_tx_skb(struct higmac_netdev_local *ld)
++{
++	struct sk_buff *skb = NULL;
++	int i;
++
++	for (i = 0; i < ld->tx_bq.count; i++) {
++		skb = ld->tx_bq.skb[i];
++		if (skb) {
++			ld->tx_skb[i] = NULL;
++			ld->tx_bq.skb[i] = NULL;
++			if (skb == SKB_MAGIC)
++				continue;
++			dev_kfree_skb_any(skb);
++			/* TODO: unmap the skb */
++		}
++	}
++}
++
++/* reset and re-config gmac */
++void higmac_restart(struct higmac_netdev_local *ld)
++{
++	unsigned long rxflags, txflags;
++
++	/* restart hw engine now */
++	higmac_mac_core_reset(ld);
++
++	spin_lock_irqsave(&ld->rxlock, rxflags);
++	spin_lock_irqsave(&ld->txlock, txflags);
++
++	higmac_free_rx_skb(ld);
++	higmac_free_tx_skb(ld);
++
++	pmt_reg_restore(ld);
++	higmac_hw_init(ld);
++	higmac_hw_set_mac_addr(ld->netdev);
++	higmac_hw_set_desc_addr(ld);
++
++	/* we don't set macif here, it will be set in adjust_link */
++	if (ld->netdev->flags & IFF_UP) {
++		/* when resume, only do the following operations
++		 * when dev is up before suspend.
++		 */
++		higmac_rx_refill(ld);
++		higmac_set_multicast_list(ld->netdev);
++
++		higmac_hw_desc_enable(ld);
++		higmac_port_enable(ld);
++		higmac_irq_enable_all_queue(ld);
++	}
++	spin_unlock_irqrestore(&ld->txlock, txflags);
++	spin_unlock_irqrestore(&ld->rxlock, rxflags);
++}
++
++static int higmac_net_set_mac_address(struct net_device *dev, void *p)
++{
++	int ret;
++
++	ret = eth_mac_addr(dev, p);
++	if (!ret)
++		higmac_hw_set_mac_addr(dev);
++
++	return ret;
++}
++
++#define HIGMAC_LINK_CHANGE_PROTECT
++#define HIGMAC_MAC_TX_RESET_IN_LINKUP
++
++#ifdef HIGMAC_LINK_CHANGE_PROTECT
++#define HIGMAC_MS_TO_NS (1000000ULL)
++#define HIGMAC_FLUSH_WAIT_TIME (100*HIGMAC_MS_TO_NS)
++/* protect code */
++static void higmac_linkup_flush(struct higmac_netdev_local *ld)
++{
++	int tx_bq_wr_offset, tx_bq_rd_offset;
++	unsigned long long time_limit, time_now;
++
++	time_now = sched_clock();
++	time_limit = time_now + HIGMAC_FLUSH_WAIT_TIME;
++
++	do {
++		tx_bq_wr_offset = readl(ld->gmac_iobase + TX_BQ_WR_ADDR);
++		tx_bq_rd_offset = readl(ld->gmac_iobase + TX_BQ_RD_ADDR);
++
++		time_now = sched_clock();
++		if (unlikely((long long)time_now -
++					(long long)time_limit >= 0))
++			break;
++	} while (tx_bq_rd_offset != tx_bq_wr_offset);
++
++	mdelay(1);
++}
++#endif
++
++#ifdef HIGMAC_MAC_TX_RESET_IN_LINKUP
++static void higmac_mac_tx_state_engine_reset(struct higmac_netdev_local *priv)
++{
++	u32 val;
++
++	val = readl(priv->gmac_iobase + MAC_CLEAR);
++	val |= BIT_TX_SOFT_RESET;
++	writel(val, priv->gmac_iobase + MAC_CLEAR);
++
++	mdelay(5);
++
++	val = readl(priv->gmac_iobase + MAC_CLEAR);
++	val &= ~BIT_TX_SOFT_RESET;
++	writel(val, priv->gmac_iobase + MAC_CLEAR);
++}
++#endif
++
++static void higmac_adjust_link(struct net_device *dev)
++{
++	struct higmac_netdev_local *priv = netdev_priv(dev);
++	struct phy_device *phy = priv->phy;
++	bool link_status_changed = false;
++
++	if (phy->link) {
++		if ((priv->old_speed != phy->speed) ||
++		    (priv->old_duplex != phy->duplex)) {
++#ifdef HIGMAC_LINK_CHANGE_PROTECT
++			unsigned long txflags;
++
++			spin_lock_irqsave(&priv->txlock, txflags);
++
++			higmac_linkup_flush(priv);
++#endif
++			higmac_config_port(dev, phy->speed, phy->duplex);
++#ifdef HIGMAC_MAC_TX_RESET_IN_LINKUP
++			higmac_mac_tx_state_engine_reset(priv);
++#endif
++#ifdef HIGMAC_LINK_CHANGE_PROTECT
++			spin_unlock_irqrestore(&priv->txlock, txflags);
++#endif
++			higmac_set_flow_ctrl_state(priv, phy->pause);
++
++			if (priv->autoeee)
++				init_autoeee(priv);
++
++			link_status_changed = true;
++			priv->old_link = 1;
++			priv->old_speed = phy->speed;
++			priv->old_duplex = phy->duplex;
++		}
++	} else if (priv->old_link) {
++		link_status_changed = true;
++		priv->old_link = 0;
++		priv->old_speed = SPEED_UNKNOWN;
++		priv->old_duplex = DUPLEX_UNKNOWN;
++	}
++
++	if (link_status_changed && netif_msg_link(priv))
++		phy_print_status(phy);
++}
++
++int higmac_tx_avail(struct higmac_netdev_local *ld)
++{
++	int tx_bq_wr_offset, tx_bq_rd_offset;
++
++	tx_bq_wr_offset = readl(ld->gmac_iobase + TX_BQ_WR_ADDR);
++	tx_bq_rd_offset = readl(ld->gmac_iobase + TX_BQ_RD_ADDR);
++
++	return (tx_bq_rd_offset >> DESC_BYTE_SHIFT) + TX_DESC_NUM
++		- (tx_bq_wr_offset >> DESC_BYTE_SHIFT) - 1;
++}
++
++static int higmac_init_sg_desc_queue(struct higmac_netdev_local *ld)
++{
++	ld->sg_count = ld->tx_bq.count + HIGMAC_SG_DESC_ADD;
++	if (HAS_CAP_CCI(ld->hw_cap)) {
++		ld->dma_sg_desc = kmalloc_array(ld->sg_count,
++				sizeof(struct sg_desc),
++				GFP_KERNEL);
++		if (ld->dma_sg_desc)
++			ld->dma_sg_phy = virt_to_phys(ld->dma_sg_desc);
++	} else {
++		ld->dma_sg_desc = (struct sg_desc *)dma_alloc_coherent(ld->dev,
++				ld->sg_count * sizeof(struct sg_desc),
++				&ld->dma_sg_phy, GFP_KERNEL);
++	}
++
++	if (!ld->dma_sg_desc) {
++		pr_err("alloc sg desc dma error!\n");
++		return -ENOMEM;
++	}
++#ifdef HIGMAC_TSO_DEBUG
++	pr_info("Higmac dma_sg_phy: 0x%p\n", (void *)ld->dma_sg_phy);
++#endif
++
++	ld->sg_head = 0;
++	ld->sg_tail = 0;
++
++	return 0;
++}
++
++static void higmac_destroy_sg_desc_queue(struct higmac_netdev_local *ld)
++{
++	if (ld->dma_sg_desc) {
++		if (HAS_CAP_CCI(ld->hw_cap))
++			kfree(ld->dma_sg_desc);
++		else
++			dma_free_coherent(ld->dev,
++					  ld->sg_count * sizeof(struct sg_desc),
++					  ld->dma_sg_desc, ld->dma_sg_phy);
++		ld->dma_sg_desc = NULL;
++	}
++}
++
++static bool higmac_rx_fq_empty(struct higmac_netdev_local *priv)
++{
++	u32 start, end;
++
++	start = readl(priv->gmac_iobase + RX_FQ_WR_ADDR);
++	end = readl(priv->gmac_iobase + RX_FQ_RD_ADDR);
++
++	if (start == end)
++		return true;
++	else
++		return false;
++}
++
++static bool higmac_rxq_has_packets(struct higmac_netdev_local *priv, int rxq_id)
++{
++	u32 rx_bq_rd_reg, rx_bq_wr_reg;
++	u32 start, end;
++
++	rx_bq_rd_reg = RX_BQ_RD_ADDR_QUEUE(rxq_id);
++	rx_bq_wr_reg = RX_BQ_WR_ADDR_QUEUE(rxq_id);
++
++	start = readl(priv->gmac_iobase + rx_bq_rd_reg);
++	end = readl(priv->gmac_iobase + rx_bq_wr_reg);
++
++	if (start == end)
++		return false;
++	else
++		return true;
++}
++
++static void higmac_monitor_func(unsigned long arg)
++{
++	struct net_device *dev = (struct net_device *)arg;
++	struct higmac_netdev_local *ld = netdev_priv(dev);
++	u32 refill_cnt;
++
++	if (!ld || !netif_running(dev)) {
++		higmac_trace(7, "network driver is stopped.");
++		return;
++	}
++
++	spin_lock(&ld->rxlock);
++	refill_cnt = higmac_rx_refill(ld);
++	if (!refill_cnt && higmac_rx_fq_empty(ld)) {
++		int rxq_id;
++
++		for (rxq_id = 0; rxq_id < ld->num_rxqs; rxq_id++) {
++			if (higmac_rxq_has_packets(ld, rxq_id))
++				napi_schedule(&ld->q_napi[rxq_id].napi);
++		}
++	}
++	spin_unlock(&ld->rxlock);
++
++	ld->monitor.expires = jiffies + HIGMAC_MONITOR_TIMER;
++	mod_timer(&ld->monitor, ld->monitor.expires);
++}
++
++static u32 higmac_rx_refill(struct higmac_netdev_local *priv)
++{
++	struct higmac_desc *desc;
++	struct sk_buff *skb;
++	u32 start, end, num, pos, i;
++	u32 len = HIETH_MAX_FRAME_SIZE;
++	dma_addr_t addr;
++	u32 refill_cnt = 0;
++
++	/* software write pointer */
++	start = dma_cnt(readl(priv->gmac_iobase + RX_FQ_WR_ADDR));
++	/* logic read pointer */
++	end = dma_cnt(readl(priv->gmac_iobase + RX_FQ_RD_ADDR));
++	num = CIRC_SPACE(start, end, RX_DESC_NUM);
++
++	for (i = 0, pos = start; i < num; i++) {
++		if (priv->rx_fq.skb[pos] || priv->rx_skb[pos])
++			break;
++
++		skb = netdev_alloc_skb_ip_align(priv->netdev, len);
++		if (unlikely(!skb))
++			break;
++
++		if (!HAS_CAP_CCI(priv->hw_cap)) {
++			addr = dma_map_single(priv->dev, skb->data, len,
++					      DMA_FROM_DEVICE);
++			if (dma_mapping_error(priv->dev, addr)) {
++				dev_kfree_skb_any(skb);
++				break;
++			}
++		} else {
++			addr = virt_to_phys(skb->data);
++		}
++
++		desc = priv->rx_fq.desc + pos;
++		desc->data_buff_addr = addr;
++		priv->rx_fq.skb[pos] = skb;
++		priv->rx_skb[pos] = skb;
++
++		desc->buffer_len = len - 1;
++		desc->data_len = 0;
++		desc->fl = 0;
++		desc->descvid = DESC_VLD_FREE;
++		desc->skb_id = pos;
++
++		refill_cnt++;
++		pos = dma_ring_incr(pos, RX_DESC_NUM);
++	}
++
++	/* This barrier is important here.  It is required to ensure
++	 * the ARM CPU flushes it's DMA write buffers before proceeding
++	 * to the next instruction, to ensure that GMAC will see
++	 * our descriptor changes in memory
++	 */
++	HIGMAC_SYNC_BARRIER();
++
++	if (pos != start)
++		writel(dma_byte(pos), priv->gmac_iobase + RX_FQ_WR_ADDR);
++
++	return refill_cnt;
++}
++
++static int higmac_rx(struct net_device *dev, int limit, int rxq_id)
++{
++	struct higmac_netdev_local *ld = netdev_priv(dev);
++	struct sk_buff *skb;
++	struct higmac_desc *desc;
++	dma_addr_t addr;
++	u32 start, end, num, pos, i, len;
++	u32 rx_bq_rd_reg, rx_bq_wr_reg;
++	u16 skb_id;
++
++	rx_bq_rd_reg = RX_BQ_RD_ADDR_QUEUE(rxq_id);
++	rx_bq_wr_reg = RX_BQ_WR_ADDR_QUEUE(rxq_id);
++
++	/* software read pointer */
++	start = dma_cnt(readl(ld->gmac_iobase + rx_bq_rd_reg));
++	/* logic write pointer */
++	end = dma_cnt(readl(ld->gmac_iobase + rx_bq_wr_reg));
++	num = CIRC_CNT(end, start, RX_DESC_NUM);
++	if (num > limit)
++		num = limit;
++
++	/* ensure get updated desc */
++	rmb();
++	for (i = 0, pos = start; i < num; i++) {
++		if (rxq_id)
++			desc = ld->pool[3 + rxq_id].desc + pos;
++		else
++			desc = ld->rx_bq.desc + pos;
++		skb_id = desc->skb_id;
++
++		spin_lock(&ld->rxlock);
++		skb = ld->rx_skb[skb_id];
++		if (unlikely(!skb)) {
++			spin_unlock(&ld->rxlock);
++			netdev_err(dev, "inconsistent rx_skb\n");
++			break;
++		}
++
++		/* data consistent check */
++		if (unlikely(skb != ld->rx_fq.skb[skb_id])) {
++			netdev_err(dev, "desc->skb(0x%p),rx_fq.skb[%d](0x%p)\n",
++				   skb, skb_id, ld->rx_fq.skb[skb_id]);
++			if (ld->rx_fq.skb[skb_id] == SKB_MAGIC) {
++				spin_unlock(&ld->rxlock);
++				goto next;
++			}
++			WARN_ON(1);
++		} else {
++			ld->rx_fq.skb[skb_id] = NULL;
++		}
++		spin_unlock(&ld->rxlock);
++
++		len = desc->data_len;
++
++		if (!HAS_CAP_CCI(ld->hw_cap)) {
++			addr = desc->data_buff_addr;
++			dma_unmap_single(ld->dev, addr, HIETH_MAX_FRAME_SIZE,
++					 DMA_FROM_DEVICE);
++		}
++
++		skb_put(skb, len);
++		if (skb->len > HIETH_MAX_FRAME_SIZE) {
++			netdev_err(dev, "rcv len err, len = %d\n", skb->len);
++			dev->stats.rx_errors++;
++			dev->stats.rx_length_errors++;
++			dev_kfree_skb_any(skb);
++			goto next;
++		}
++
++		skb->protocol = eth_type_trans(skb, dev);
++		skb->ip_summed = CHECKSUM_NONE;
++#if defined(CONFIG_HIGMAC_RXCSUM)
++		if (dev->features & NETIF_F_RXCSUM) {
++			int hdr_csum_done =
++				desc->header_csum_done;
++			int payload_csum_done =
++				desc->payload_csum_done;
++			int hdr_csum_err =
++				desc->header_csum_err;
++			int payload_csum_err =
++				desc->payload_csum_err;
++
++			if (hdr_csum_done && payload_csum_done) {
++				if (unlikely(hdr_csum_err ||
++					     payload_csum_err)) {
++					dev->stats.rx_errors++;
++					dev->stats.rx_crc_errors++;
++					dev_kfree_skb_any(skb);
++					goto next;
++				} else {
++					skb->ip_summed = CHECKSUM_UNNECESSARY;
++				}
++			}
++		}
++#endif
++		if ((dev->features & NETIF_F_RXHASH) && desc->has_hash)
++			skb_set_hash(skb, desc->rxhash, desc->l3_hash ?
++				     PKT_HASH_TYPE_L3 : PKT_HASH_TYPE_L4);
++
++		skb_record_rx_queue(skb, rxq_id);
++
++		napi_gro_receive(&ld->q_napi[rxq_id].napi, skb);
++		dev->stats.rx_packets++;
++		dev->stats.rx_bytes += len;
++		dev->last_rx = jiffies;
++next:
++		spin_lock(&ld->rxlock);
++		ld->rx_skb[skb_id] = NULL;
++		spin_unlock(&ld->rxlock);
++		pos = dma_ring_incr(pos, RX_DESC_NUM);
++	}
++
++	if (pos != start)
++		writel(dma_byte(pos), ld->gmac_iobase + rx_bq_rd_reg);
++
++	spin_lock(&ld->rxlock);
++	higmac_rx_refill(ld);
++	spin_unlock(&ld->rxlock);
++
++	return num;
++}
++
++#ifdef HIGMAC_TSO_DEBUG
++unsigned int id_send;
++unsigned int id_free;
++struct send_pkt_info pkt_rec[MAX_RECORD];
++#endif
++
++static int higmac_check_tx_err(struct higmac_netdev_local *ld,
++			       struct higmac_tso_desc *tx_bq_desc,
++			       unsigned int desc_pos)
++{
++	unsigned int tx_err = tx_bq_desc->tx_err;
++
++	if (unlikely(tx_err & ERR_ALL)) {
++		struct sg_desc *desc_cur;
++		int *sg_word;
++		int i;
++
++		WARN((tx_err & ERR_ALL),
++		     "TX ERR: desc1=0x%x, desc2=0x%x, desc5=0x%x\n",
++		     tx_bq_desc->data_buff_addr,
++		     tx_bq_desc->desc1.val, tx_bq_desc->tx_err);
++
++		desc_cur = ld->dma_sg_desc + ld->tx_bq.sg_desc_offset[desc_pos];
++		sg_word = (int *)desc_cur;
++		for (i = 0; i < sizeof(struct sg_desc) / sizeof(int); i++)
++			pr_err("%s,%d: sg_desc word[%d]=0x%x\n",
++			       __func__, __LINE__, i, sg_word[i]);
++
++		return -1;
++	}
++
++	return 0;
++}
++
++static int higmac_xmit_release_gso(struct higmac_netdev_local *ld,
++				   struct higmac_tso_desc *tx_bq_desc,
++				   unsigned int desc_pos)
++{
++	int pkt_type;
++	int nfrags = tx_bq_desc->desc1.tx.nfrags_num;
++	dma_addr_t addr;
++	size_t len;
++
++	if (unlikely(higmac_check_tx_err(ld, tx_bq_desc, desc_pos) < 0)) {
++		/* dev_close */
++		higmac_irq_disable_all_queue(ld);
++		higmac_hw_desc_disable(ld);
++
++		netif_carrier_off(ld->netdev);
++		netif_stop_queue(ld->netdev);
++
++		phy_stop(ld->phy);
++		del_timer_sync(&ld->monitor);
++		return -1;
++	}
++
++	if (tx_bq_desc->desc1.tx.tso_flag || nfrags)
++		pkt_type = PKT_SG;
++	else
++		pkt_type = PKT_NORMAL;
++
++	if (pkt_type == PKT_NORMAL) {
++		if (!HAS_CAP_CCI(ld->hw_cap)) {
++			addr = tx_bq_desc->data_buff_addr;
++			len = tx_bq_desc->desc1.tx.data_len;
++			dma_unmap_single(ld->dev, addr, len, DMA_TO_DEVICE);
++		}
++	} else {
++		if (!HAS_CAP_CCI(ld->hw_cap)) {
++			struct sg_desc *desc_cur;
++			unsigned int desc_offset;
++			int i;
++
++			desc_offset = ld->tx_bq.sg_desc_offset[desc_pos];
++			WARN_ON(desc_offset != ld->sg_tail);
++			desc_cur = ld->dma_sg_desc + desc_offset;
++
++			addr = desc_cur->linear_addr;
++			len = desc_cur->linear_len;
++			dma_unmap_single(ld->dev, addr, len, DMA_TO_DEVICE);
++			for (i = 0; i < nfrags; i++) {
++				addr = desc_cur->frags[i].addr;
++				len = desc_cur->frags[i].size;
++				dma_unmap_page(ld->dev, addr, len,
++					       DMA_TO_DEVICE);
++			}
++		}
++
++		ld->sg_tail = (ld->sg_tail + 1) % ld->sg_count;
++	}
++
++#ifdef HIGMAC_TSO_DEBUG
++	pkt_rec[id_free].status = 0;
++	id_free++;
++	if (id_free == MAX_RECORD)
++		id_free = 0;
++#endif
++
++	return 0;
++}
++
++static void higmac_xmit_reclaim(struct net_device *dev)
++{
++	struct sk_buff *skb;
++	struct higmac_desc *desc;
++	struct higmac_tso_desc *tso_desc;
++	struct higmac_netdev_local *priv = netdev_priv(dev);
++	unsigned int bytes_compl = 0, pkts_compl = 0;
++	u32 start, end, num, pos, i;
++	dma_addr_t addr;
++	int ret;
++
++	spin_lock(&priv->txlock);
++
++	/* software read */
++	start = dma_cnt(readl(priv->gmac_iobase + TX_RQ_RD_ADDR));
++	/* logic write */
++	end = dma_cnt(readl(priv->gmac_iobase + TX_RQ_WR_ADDR));
++	num = CIRC_CNT(end, start, TX_DESC_NUM);
++
++	for (i = 0, pos = start; i < num; i++) {
++		skb = priv->tx_skb[pos];
++		if (unlikely(!skb)) {
++			netdev_err(dev, "inconsistent tx_skb\n");
++			break;
++		}
++
++		if (skb != priv->tx_bq.skb[pos]) {
++			netdev_err(dev, "wired, tx skb[%d](%p) != skb(%p)\n",
++				   pos, priv->tx_bq.skb[pos], skb);
++			if (priv->tx_bq.skb[pos] == SKB_MAGIC)
++				goto next;
++		}
++
++		pkts_compl++;
++		bytes_compl += skb->len;
++		desc = priv->tx_rq.desc + pos;
++		if (priv->tso_supported) {
++			tso_desc = (struct higmac_tso_desc *)desc;
++			ret = higmac_xmit_release_gso(priv, tso_desc, pos);
++			if (ret < 0)
++				break;
++		} else if (!HAS_CAP_CCI(priv->hw_cap)) {
++			addr = desc->data_buff_addr;
++			dma_unmap_single(priv->dev, addr, skb->len,
++					 DMA_TO_DEVICE);
++		}
++		priv->tx_bq.skb[pos] = NULL;
++next:
++		priv->tx_skb[pos] = NULL;
++		dev_consume_skb_any(skb);
++		pos = dma_ring_incr(pos, TX_DESC_NUM);
++	}
++
++	if (pos != start)
++		writel(dma_byte(pos), priv->gmac_iobase + TX_RQ_RD_ADDR);
++
++	if (pkts_compl || bytes_compl)
++		netdev_completed_queue(dev, pkts_compl, bytes_compl);
++
++	if (unlikely(netif_queue_stopped(priv->netdev)) && pkts_compl)
++		netif_wake_queue(priv->netdev);
++
++	spin_unlock(&priv->txlock);
++}
++
++static int higmac_poll(struct napi_struct *napi, int budget)
++{
++	struct higmac_napi *q_napi = container_of(napi,
++					struct higmac_napi, napi);
++	struct higmac_netdev_local *priv = q_napi->ndev_priv;
++	struct net_device *dev = priv->netdev;
++	int work_done = 0, task = budget;
++	u32 ints, num;
++	u32 raw_int_reg, raw_int_mask;
++
++	if (q_napi->rxq_id) {
++		raw_int_reg = RSS_RAW_PMU_INT;
++		raw_int_mask = DEF_INT_MASK_QUEUE(q_napi->rxq_id);
++	} else {
++		raw_int_reg = RAW_PMU_INT;
++		raw_int_mask = DEF_INT_MASK;
++	}
++
++	do {
++		if (!q_napi->rxq_id)
++			higmac_xmit_reclaim(dev);
++		num = higmac_rx(dev, task, q_napi->rxq_id);
++		work_done += num;
++		task -= num;
++		if (work_done >= budget)
++			break;
++
++		ints = readl(priv->gmac_iobase + raw_int_reg);
++		ints &= raw_int_mask;
++		writel(ints, priv->gmac_iobase + raw_int_reg);
++	} while (ints || higmac_rxq_has_packets(priv, q_napi->rxq_id));
++
++	if (work_done < budget) {
++		napi_complete(napi);
++		higmac_irq_enable_queue(priv, q_napi->rxq_id);
++	}
++
++	return work_done;
++}
++
++static irqreturn_t higmac_interrupt(int irq, void *dev_id)
++{
++	struct higmac_napi *q_napi = (struct higmac_napi *)dev_id;
++	struct higmac_netdev_local *ld = q_napi->ndev_priv;
++	u32 ints;
++	u32 raw_int_reg, raw_int_mask;
++
++	if (higmac_queue_irq_disabled(ld, q_napi->rxq_id))
++		return IRQ_NONE;
++
++	if (q_napi->rxq_id) {
++		raw_int_reg = RSS_RAW_PMU_INT;
++		raw_int_mask = DEF_INT_MASK_QUEUE(q_napi->rxq_id);
++	} else {
++		raw_int_reg = RAW_PMU_INT;
++		raw_int_mask = DEF_INT_MASK;
++	}
++
++	ints = readl(ld->gmac_iobase + raw_int_reg);
++	ints &= raw_int_mask;
++	writel(ints, ld->gmac_iobase + raw_int_reg);
++
++	if (likely(ints || higmac_rxq_has_packets(ld, q_napi->rxq_id))) {
++		higmac_irq_disable_queue(ld, q_napi->rxq_id);
++		napi_schedule(&q_napi->napi);
++	}
++
++	return IRQ_HANDLED;
++}
++
++static inline __be16 higmac_get_l3_proto(struct sk_buff *skb)
++{
++	__be16 l3_proto;
++
++	l3_proto = skb->protocol;
++	if (skb->protocol == htons(ETH_P_8021Q))
++		l3_proto = vlan_get_protocol(skb);
++
++	return l3_proto;
++}
++
++static inline unsigned int higmac_get_l4_proto(struct sk_buff *skb)
++{
++	__be16 l3_proto;
++	unsigned int l4_proto = IPPROTO_MAX;
++
++	l3_proto = higmac_get_l3_proto(skb);
++	if (l3_proto == htons(ETH_P_IP))
++		l4_proto = ip_hdr(skb)->protocol;
++	else if (l3_proto == htons(ETH_P_IPV6))
++		l4_proto = ipv6_hdr(skb)->nexthdr;
++
++	return l4_proto;
++}
++
++static inline bool higmac_skb_is_ipv6(struct sk_buff *skb)
++{
++	return (higmac_get_l3_proto(skb) == htons(ETH_P_IPV6));
++}
++
++static inline bool higmac_skb_is_udp(struct sk_buff *skb)
++{
++	return (higmac_get_l4_proto(skb) == IPPROTO_UDP);
++}
++
++static int higmac_check_hw_capability_for_udp(struct sk_buff *skb)
++{
++	struct ethhdr *eth;
++
++	/* hardware can't dea with UFO broadcast packet */
++	eth = (struct ethhdr *)(skb->data);
++	if (skb_is_gso(skb) && is_broadcast_ether_addr(eth->h_dest))
++		return -ENOTSUPP;
++
++	return 0;
++}
++
++static int higmac_check_hw_capability_for_ipv6(struct sk_buff *skb)
++{
++	unsigned int l4_proto = IPPROTO_MAX;
++
++	l4_proto = ipv6_hdr(skb)->nexthdr;
++
++	if ((l4_proto != IPPROTO_TCP) && (l4_proto != IPPROTO_UDP)) {
++		/* when IPv6 next header is not tcp or udp,
++		 * it means that IPv6 next header is extension header.
++		 * Hardware can't deal with this case,
++		 * so do checksumming by software or do GSO by software.
++		 */
++		if (skb_is_gso(skb))
++			return -ENOTSUPP;
++
++		if (skb->ip_summed == CHECKSUM_PARTIAL &&
++		    skb_checksum_help(skb))
++			return -EFAULT;
++	}
++
++	return 0;
++}
++
++static inline bool higmac_skb_is_ipv4_with_options(struct sk_buff *skb)
++{
++	return ((higmac_get_l3_proto(skb) == htons(ETH_P_IP)) &&
++		(ip_hdr(skb)->ihl > 5));
++}
++
++static int higmac_check_hw_capability(struct sk_buff *skb)
++{
++	int ret = 0;
++
++	/* if tcp_mtu_probe() use (2 * tp->mss_cache) as probe_size,
++	 * the linear data length will be larger than 2048,
++	 * the MAC can't handle it, so let the software do it.
++	 */
++	if (skb_is_gso(skb) && (skb_headlen(skb) > 2048))
++		return -ENOTSUPP;
++
++	if (higmac_skb_is_ipv6(skb)) {
++		ret = higmac_check_hw_capability_for_ipv6(skb);
++		if (ret)
++			return ret;
++	}
++
++	if (higmac_skb_is_udp(skb)) {
++		ret = higmac_check_hw_capability_for_udp(skb);
++		if (ret)
++			return ret;
++	}
++
++	if (((skb->ip_summed == CHECKSUM_PARTIAL) || skb_is_gso(skb)) &&
++	    higmac_skb_is_ipv4_with_options(skb))
++		return -ENOTSUPP;
++
++	return 0;
++}
++
++static void higmac_do_udp_checksum(struct sk_buff *skb)
++{
++	int offset;
++	__wsum csum;
++	__sum16 udp_csum;
++
++	offset = skb_checksum_start_offset(skb);
++	WARN_ON(offset >= skb_headlen(skb));
++	csum = skb_checksum(skb, offset, skb->len - offset, 0);
++
++	offset += skb->csum_offset;
++	WARN_ON(offset + sizeof(__sum16) > skb_headlen(skb));
++	udp_csum = csum_fold(csum);
++	if (udp_csum == 0)
++		udp_csum = CSUM_MANGLED_0;
++
++	*(__sum16 *)(skb->data + offset) = udp_csum;
++
++	skb->ip_summed = CHECKSUM_NONE;
++}
++
++static void higmac_get_pkt_info(struct higmac_netdev_local *ld,
++				struct sk_buff *skb,
++				struct higmac_tso_desc *tx_bq_desc)
++{
++	int nfrags = skb_shinfo(skb)->nr_frags;
++
++	__be16 l3_proto;	/* level 3 protocol */
++	unsigned int l4_proto = IPPROTO_MAX;
++	unsigned int max_mss = ETH_DATA_LEN;
++	unsigned char coe_enable = 0;
++	int max_data_len = skb->len - ETH_HLEN;
++
++	if (likely(skb->ip_summed == CHECKSUM_PARTIAL))
++		coe_enable = 1;
++
++	tx_bq_desc->desc1.val = 0;
++
++	if (skb_is_gso(skb)) {
++		tx_bq_desc->desc1.tx.tso_flag = 1;
++		tx_bq_desc->desc1.tx.sg_flag = 1;
++	} else if (nfrags) {
++		tx_bq_desc->desc1.tx.sg_flag = 1;
++	}
++
++	l3_proto = skb->protocol;
++	if (skb->protocol == htons(ETH_P_8021Q)) {
++		l3_proto = vlan_get_protocol(skb);
++		tx_bq_desc->desc1.tx.vlan_flag = 1;
++		max_data_len -= VLAN_HLEN;
++	}
++
++	if (l3_proto == htons(ETH_P_IP)) {
++		struct iphdr *iph;
++
++		iph = ip_hdr(skb);
++		tx_bq_desc->desc1.tx.ip_ver = PKT_IPV4;
++		tx_bq_desc->desc1.tx.ip_hdr_len = iph->ihl;
++
++		if ((max_data_len >= GSO_MAX_SIZE) &&
++		    (ntohs(iph->tot_len) <= (iph->ihl << 2)))
++			iph->tot_len = htons(GSO_MAX_SIZE - 1);
++
++		max_mss -= iph->ihl * WORD_TO_BYTE;
++		l4_proto = iph->protocol;
++	} else if (l3_proto == htons(ETH_P_IPV6)) {
++		tx_bq_desc->desc1.tx.ip_ver = PKT_IPV6;
++		tx_bq_desc->desc1.tx.ip_hdr_len = PKT_IPV6_HDR_LEN;
++		max_mss -= PKT_IPV6_HDR_LEN * WORD_TO_BYTE;
++		l4_proto = ipv6_hdr(skb)->nexthdr;
++	} else {
++		coe_enable = 0;
++	}
++
++	if (l4_proto == IPPROTO_TCP) {
++		tx_bq_desc->desc1.tx.prot_type = PKT_TCP;
++		tx_bq_desc->desc1.tx.prot_hdr_len = tcp_hdr(skb)->doff;
++		max_mss -= tcp_hdr(skb)->doff * WORD_TO_BYTE;
++	} else if (l4_proto == IPPROTO_UDP) {
++		tx_bq_desc->desc1.tx.prot_type = PKT_UDP;
++		tx_bq_desc->desc1.tx.prot_hdr_len = PKT_UDP_HDR_LEN;
++		if (l3_proto == htons(ETH_P_IPV6))
++			max_mss -= sizeof(struct frag_hdr);
++	} else {
++		coe_enable = 0;
++	}
++
++	if (skb_is_gso(skb))
++		tx_bq_desc->desc1.tx.data_len =
++			(skb_shinfo(skb)->gso_size > max_mss) ? max_mss :
++					skb_shinfo(skb)->gso_size;
++	else
++		tx_bq_desc->desc1.tx.data_len = skb->len;
++
++	if (coe_enable && skb_is_gso(skb) && (l4_proto == IPPROTO_UDP))
++		higmac_do_udp_checksum(skb);
++
++	if (coe_enable)
++		tx_bq_desc->desc1.tx.coe_flag = 1;
++
++	tx_bq_desc->desc1.tx.nfrags_num = nfrags;
++
++	tx_bq_desc->desc1.tx.hw_own = DESC_VLD_BUSY;
++}
++
++static int higmac_xmit_gso(struct higmac_netdev_local *ld, struct sk_buff *skb,
++			   struct higmac_tso_desc *tx_bq_desc,
++			   unsigned int desc_pos)
++{
++	int pkt_type = PKT_NORMAL;
++	int nfrags = skb_shinfo(skb)->nr_frags;
++	dma_addr_t addr;
++	int ret;
++
++	if (skb_is_gso(skb) || nfrags) {
++		/* TSO pkt or SG pkt */
++		pkt_type = PKT_SG;
++	} else {		/* Normal pkt */
++		pkt_type = PKT_NORMAL;
++	}
++
++	ret = higmac_check_hw_capability(skb);
++	if (unlikely(ret))
++		return ret;
++
++	higmac_get_pkt_info(ld, skb, tx_bq_desc);
++
++	if (pkt_type == PKT_NORMAL) {
++		if (!HAS_CAP_CCI(ld->hw_cap)) {
++			addr = dma_map_single(ld->dev, skb->data, skb->len,
++					      DMA_TO_DEVICE);
++			ret = dma_mapping_error(ld->dev, addr);
++			if (unlikely(ret)) {
++				pr_err("Normal Packet DMA Mapping fail.\n");
++				return -EFAULT;
++			}
++			tx_bq_desc->data_buff_addr = addr;
++		} else {
++			tx_bq_desc->data_buff_addr = virt_to_phys(skb->data);
++		}
++	} else {
++		struct sg_desc *desc_cur;
++		int i;
++
++		if (unlikely(((ld->sg_head + 1) % ld->sg_count) ==
++			ld->sg_tail)) {
++			/* SG pkt, but sg desc all used */
++			pr_err("WARNING: sg desc all used.\n");
++			return -EBUSY;
++		}
++
++		desc_cur = ld->dma_sg_desc + ld->sg_head;
++
++		/* TODO: deal with ipv6_id */
++		if (tx_bq_desc->desc1.tx.tso_flag &&
++		    tx_bq_desc->desc1.tx.ip_ver == PKT_IPV6 &&
++		    tx_bq_desc->desc1.tx.prot_type == PKT_UDP) {
++			desc_cur->ipv6_id = ntohl(skb_shinfo(skb)->ip6_frag_id);
++		}
++
++		desc_cur->total_len = skb->len;
++		desc_cur->linear_len = skb_headlen(skb);
++		if (!HAS_CAP_CCI(ld->hw_cap)) {
++			addr = dma_map_single(ld->dev, skb->data,
++					      desc_cur->linear_len,
++					      DMA_TO_DEVICE);
++			ret = dma_mapping_error(ld->dev, addr);
++			if (unlikely(ret)) {
++				pr_err("DMA Mapping fail.");
++				return -EFAULT;
++			}
++			desc_cur->linear_addr = addr;
++		} else {
++			desc_cur->linear_addr = virt_to_phys(skb->data);
++		}
++
++		for (i = 0; i < nfrags; i++) {
++			skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
++			int len = frag->size;
++
++			if (!HAS_CAP_CCI(ld->hw_cap)) {
++				addr = skb_frag_dma_map(ld->dev, frag, 0, len,
++							DMA_TO_DEVICE);
++				ret = dma_mapping_error(ld->dev, addr);
++				if (unlikely(ret)) {
++					pr_err("skb frag DMA Mapping fail.");
++					return -EFAULT;
++				}
++				desc_cur->frags[i].addr = addr;
++			} else {
++				desc_cur->frags[i].addr =
++					page_to_phys(skb_frag_page(frag)) +
++					frag->page_offset;
++			}
++			desc_cur->frags[i].size = len;
++		}
++		tx_bq_desc->data_buff_addr = ld->dma_sg_phy +
++			ld->sg_head * sizeof(struct sg_desc);
++		ld->tx_bq.sg_desc_offset[desc_pos] = ld->sg_head;
++
++		ld->sg_head = (ld->sg_head + 1) % ld->sg_count;
++	}
++
++#ifdef HIGMAC_TSO_DEBUG
++	memcpy(&pkt_rec[id_send].desc, tx_bq_desc,
++	       sizeof(struct higmac_tso_desc));
++	pkt_rec[id_send].status = 1;
++	id_send++;
++	if (id_send == MAX_RECORD)
++		id_send = 0;
++#endif
++	return 0;
++}
++
++static netdev_tx_t higmac_net_xmit(struct sk_buff *skb, struct net_device *dev);
++
++static netdev_tx_t higmac_sw_gso(struct higmac_netdev_local *ld,
++				 struct sk_buff *skb)
++{
++	struct sk_buff *segs, *curr_skb;
++	int gso_segs = skb_shinfo(skb)->gso_segs;
++
++	if (gso_segs == 0 && skb_shinfo(skb)->gso_size != 0)
++		gso_segs = DIV_ROUND_UP(skb->len, skb_shinfo(skb)->gso_size);
++
++	/* Estimate the number of fragments in the worst case */
++	if (unlikely(higmac_tx_avail(ld) < gso_segs)) {
++		netif_stop_queue(ld->netdev);
++		if (higmac_tx_avail(ld) < gso_segs) {
++			ld->netdev->stats.tx_dropped++;
++			ld->netdev->stats.tx_fifo_errors++;
++			return NETDEV_TX_BUSY;
++		}
++
++		netif_wake_queue(ld->netdev);
++	}
++
++	segs = skb_gso_segment(skb, ld->netdev->features & ~(NETIF_F_ALL_CSUM |
++					NETIF_F_SG | NETIF_F_GSO_SOFTWARE));
++
++	if (IS_ERR_OR_NULL(segs))
++		goto drop;
++
++	do {
++		curr_skb = segs;
++		segs = segs->next;
++		curr_skb->next = NULL;
++		higmac_net_xmit(curr_skb, ld->netdev);
++	} while (segs);
++
++	dev_kfree_skb_any(skb);
++	return NETDEV_TX_OK;
++
++drop:
++	dev_kfree_skb_any(skb);
++	ld->netdev->stats.tx_dropped++;
++	return NETDEV_TX_OK;
++}
++
++static netdev_tx_t higmac_net_xmit(struct sk_buff *skb, struct net_device *dev)
++{
++	struct higmac_netdev_local *ld = netdev_priv(dev);
++	struct higmac_desc *desc;
++	dma_addr_t addr;
++	unsigned long txflags;
++	int ret;
++	u32 pos;
++
++	if (skb->len < ETH_HLEN) {
++		dev_kfree_skb_any(skb);
++		dev->stats.tx_errors++;
++		dev->stats.tx_dropped++;
++		return NETDEV_TX_OK;
++	}
++
++	/* if adding higmac_xmit_reclaim here, iperf tcp client
++	 * performance will be affected, from 550M(avg) to 513M~300M
++	 */
++
++	/* software write pointer */
++	pos = dma_cnt(readl(ld->gmac_iobase + TX_BQ_WR_ADDR));
++
++	spin_lock_irqsave(&ld->txlock, txflags);
++
++	if (unlikely(ld->tx_skb[pos] || ld->tx_bq.skb[pos])) {
++		dev->stats.tx_dropped++;
++		dev->stats.tx_fifo_errors++;
++		netif_stop_queue(dev);
++		spin_unlock_irqrestore(&ld->txlock, txflags);
++
++		return NETDEV_TX_BUSY;
++	}
++
++	ld->tx_bq.skb[pos] = skb;
++	ld->tx_skb[pos] = skb;
++
++	desc = ld->tx_bq.desc + pos;
++
++	if (ld->tso_supported) {
++		ret = higmac_xmit_gso(ld, skb,
++				      (struct higmac_tso_desc *)desc,
++				      pos);
++		if (unlikely(ret < 0)) {
++			ld->tx_skb[pos] = NULL;
++			ld->tx_bq.skb[pos] = NULL;
++			spin_unlock_irqrestore(&ld->txlock, txflags);
++
++			if (ret == -ENOTSUPP)
++				return higmac_sw_gso(ld, skb);
++
++			dev_kfree_skb_any(skb);
++			dev->stats.tx_dropped++;
++			return NETDEV_TX_OK;
++		}
++	} else {
++		if (!HAS_CAP_CCI(ld->hw_cap)) {
++			addr = dma_map_single(ld->dev, skb->data, skb->len,
++					      DMA_TO_DEVICE);
++			if (unlikely(dma_mapping_error(ld->dev, addr))) {
++				dev_kfree_skb_any(skb);
++				dev->stats.tx_dropped++;
++				ld->tx_skb[pos] = NULL;
++				ld->tx_bq.skb[pos] = NULL;
++				spin_unlock_irqrestore(&ld->txlock, txflags);
++				return NETDEV_TX_OK;
++			}
++			desc->data_buff_addr = addr;
++		} else {
++			desc->data_buff_addr = virt_to_phys(skb->data);
++		}
++		desc->buffer_len = HIETH_MAX_FRAME_SIZE - 1;
++		desc->data_len = skb->len;
++		desc->fl = DESC_FL_FULL;
++		desc->descvid = DESC_VLD_BUSY;
++	}
++
++	/* This barrier is important here.  It is required to ensure
++	 * the ARM CPU flushes it's DMA write buffers before proceeding
++	 * to the next instruction, to ensure that GMAC will see
++	 * our descriptor changes in memory
++	 */
++	HIGMAC_SYNC_BARRIER();
++
++	pos = dma_ring_incr(pos, TX_DESC_NUM);
++	writel(dma_byte(pos), ld->gmac_iobase + TX_BQ_WR_ADDR);
++
++	dev->trans_start = jiffies;
++	dev->stats.tx_packets++;
++	dev->stats.tx_bytes += skb->len;
++	netdev_sent_queue(dev, skb->len);
++
++	spin_unlock_irqrestore(&ld->txlock, txflags);
++
++	return NETDEV_TX_OK;
++}
++
++void higmac_enable_napi(struct higmac_netdev_local *priv)
++{
++	struct higmac_napi *q_napi;
++	int i;
++
++	for (i = 0; i < priv->num_rxqs; i++) {
++		q_napi = &priv->q_napi[i];
++		napi_enable(&q_napi->napi);
++	}
++}
++
++void higmac_disable_napi(struct higmac_netdev_local *priv)
++{
++	struct higmac_napi *q_napi;
++	int i;
++
++	for (i = 0; i < priv->num_rxqs; i++) {
++		q_napi = &priv->q_napi[i];
++		napi_disable(&q_napi->napi);
++	}
++}
++
++static int higmac_net_open(struct net_device *dev)
++{
++	struct higmac_netdev_local *ld = netdev_priv(dev);
++	unsigned long flags;
++
++	clk_prepare_enable(ld->macif_clk);
++	clk_prepare_enable(ld->clk);
++
++	/* If we configure mac address by
++	 * "ifconfig ethX hw ether XX:XX:XX:XX:XX:XX",
++	 * the ethX must be down state and mac core clock is disabled
++	 * which results the mac address has not been configured
++	 * in mac core register.
++	 * So we must set mac address again here,
++	 * because mac core clock is enabled at this time
++	 * and we can configure mac address to mac core register.
++	 */
++	higmac_hw_set_mac_addr(dev);
++
++	/* We should use netif_carrier_off() here,
++	 * because the default state should be off.
++	 * And this call should before phy_start().
++	 */
++	netif_carrier_off(dev);
++	higmac_enable_napi(ld);
++	phy_start(ld->phy);
++
++	higmac_hw_desc_enable(ld);
++	higmac_port_enable(ld);
++	higmac_irq_enable_all_queue(ld);
++
++	spin_lock_irqsave(&ld->rxlock, flags);
++	higmac_rx_refill(ld);
++	spin_unlock_irqrestore(&ld->rxlock, flags);
++
++	ld->monitor.expires = jiffies + HIGMAC_MONITOR_TIMER;
++	mod_timer(&ld->monitor, ld->monitor.expires);
++
++	netif_start_queue(dev);
++
++	return 0;
++}
++
++static int higmac_net_close(struct net_device *dev)
++{
++	struct higmac_netdev_local *ld = netdev_priv(dev);
++
++	higmac_irq_disable_all_queue(ld);
++	higmac_hw_desc_disable(ld);
++
++	higmac_disable_napi(ld);
++
++	netif_carrier_off(dev);
++	netif_stop_queue(dev);
++
++	phy_stop(ld->phy);
++	del_timer_sync(&ld->monitor);
++
++	clk_disable_unprepare(ld->clk);
++	clk_disable_unprepare(ld->macif_clk);
++
++	return 0;
++}
++
++static void higmac_net_timeout(struct net_device *dev)
++{
++	dev->stats.tx_errors++;
++
++	pr_err("tx timeout!\n");
++}
++
++static void higmac_set_multicast_list(struct net_device *dev)
++{
++	higmac_gmac_multicast_list(dev);
++}
++
++static inline void higmac_enable_rxcsum_drop(struct higmac_netdev_local *ld,
++					     bool drop)
++{
++	unsigned int v;
++
++	v = readl(ld->gmac_iobase + TSO_COE_CTRL);
++	if (drop)
++		v |= COE_ERR_DROP;
++	else
++		v &= ~COE_ERR_DROP;
++	writel(v, ld->gmac_iobase + TSO_COE_CTRL);
++}
++
++static int higmac_set_features(struct net_device *dev,
++			       netdev_features_t features)
++{
++	struct higmac_netdev_local *ld = netdev_priv(dev);
++	netdev_features_t changed = dev->features ^ features;
++
++	if (changed & NETIF_F_RXCSUM) {
++		if (features & NETIF_F_RXCSUM)
++			higmac_enable_rxcsum_drop(ld, true);
++		else
++			higmac_enable_rxcsum_drop(ld, false);
++	}
++
++	return 0;
++}
++
++static struct net_device_stats *higmac_net_get_stats(struct net_device *dev)
++{
++	return &dev->stats;
++}
++
++static void higmac_get_drvinfo(struct net_device *net_dev,
++			       struct ethtool_drvinfo *info)
++{
++	strncpy(info->driver, "higmac driver", 15);
++	strncpy(info->version, "higmac v200", 15);
++	strncpy(info->bus_info, "platform", 15);
++}
++
++static unsigned int higmac_get_link(struct net_device *net_dev)
++{
++	struct higmac_netdev_local *ld = netdev_priv(net_dev);
++
++	return ld->phy->link ? HIGMAC_LINKED : 0;
++}
++
++static int higmac_get_settings(struct net_device *net_dev,
++			       struct ethtool_cmd *cmd)
++{
++	struct higmac_netdev_local *ld = netdev_priv(net_dev);
++
++	if (ld->phy)
++		return phy_ethtool_gset(ld->phy, cmd);
++
++	return -EINVAL;
++}
++
++static int higmac_set_settings(struct net_device *net_dev,
++			       struct ethtool_cmd *cmd)
++{
++	struct higmac_netdev_local *ld = netdev_priv(net_dev);
++
++	if (!capable(CAP_NET_ADMIN))
++		return -EPERM;
++
++	if (ld->phy)
++		return phy_ethtool_sset(ld->phy, cmd);
++
++	return -EINVAL;
++}
++
++static void higmac_get_pauseparam(struct net_device *net_dev,
++				  struct ethtool_pauseparam *pause)
++{
++	struct higmac_netdev_local *ld = netdev_priv(net_dev);
++
++	pause->rx_pause = 0;
++	pause->tx_pause = 0;
++	pause->autoneg = ld->phy->autoneg;
++
++	if (ld->flow_ctrl & FLOW_RX)
++		pause->rx_pause = 1;
++	if (ld->flow_ctrl & FLOW_TX)
++		pause->tx_pause = 1;
++}
++
++static int higmac_set_pauseparam(struct net_device *net_dev,
++				 struct ethtool_pauseparam *pause)
++{
++	struct higmac_netdev_local *ld = netdev_priv(net_dev);
++	struct phy_device *phy = ld->phy;
++	int new_pause = FLOW_OFF;
++	int ret = 0;
++
++	if (pause->rx_pause)
++		new_pause |= FLOW_RX;
++	if (pause->tx_pause)
++		new_pause |= FLOW_TX;
++
++	if (new_pause != ld->flow_ctrl)
++		ld->flow_ctrl = new_pause;
++
++	higmac_set_flow_ctrl_state(ld, phy->pause);
++	phy->advertising &= ~SUPPORTED_Pause;
++	if (ld->flow_ctrl)
++		phy->advertising |= SUPPORTED_Pause;
++
++	if (phy->autoneg) {
++		if (netif_running(net_dev))
++			return phy_start_aneg(phy);
++	}
++
++	return ret;
++}
++
++static u32 higmac_ethtool_getmsglevel(struct net_device *ndev)
++{
++	struct higmac_netdev_local *priv = netdev_priv(ndev);
++
++	return priv->msg_enable;
++}
++
++static void higmac_ethtool_setmsglevel(struct net_device *ndev, u32 level)
++{
++	struct higmac_netdev_local *priv = netdev_priv(ndev);
++
++	priv->msg_enable = level;
++}
++
++static u32 higmac_get_rxfh_key_size(struct net_device *ndev)
++{
++	return RSS_HASH_KEY_SIZE;
++}
++
++static u32 higmac_get_rxfh_indir_size(struct net_device *ndev)
++{
++	struct higmac_netdev_local *priv = netdev_priv(ndev);
++
++	return priv->rss_info.ind_tbl_size;
++}
++
++static int higmac_get_rxfh(struct net_device *ndev, u32 *indir, u8 *hkey)
++{
++	struct higmac_netdev_local *priv = netdev_priv(ndev);
++	struct higmac_rss_info *rss = &priv->rss_info;
++
++	if (hkey)
++		memcpy(hkey, rss->key, RSS_HASH_KEY_SIZE);
++
++	if (indir) {
++		int i;
++
++		for (i = 0; i < rss->ind_tbl_size; i++)
++			indir[i] = rss->ind_tbl[i];
++	}
++
++	return 0;
++}
++
++static void higmac_get_rss_key(struct higmac_netdev_local *priv)
++{
++	struct higmac_rss_info *rss = &priv->rss_info;
++	u32 hkey;
++
++	hkey = readl(priv->gmac_iobase + RSS_HASH_KEY);
++	*((u32 *)rss->key) = hkey;
++}
++
++static void higmac_set_rss_key(struct higmac_netdev_local *priv)
++{
++	struct higmac_rss_info *rss = &priv->rss_info;
++
++	writel(*((u32 *)rss->key), priv->gmac_iobase + RSS_HASH_KEY);
++}
++
++static int higmac_wait_rss_ready(struct higmac_netdev_local *priv)
++{
++	void __iomem *base = priv->gmac_iobase;
++	int i, timeout = 10000;
++
++	for (i = 0; !(readl(base + RSS_IND_TBL) & BIT_IND_TBL_READY); i++) {
++		if (i == timeout) {
++			netdev_err(priv->netdev, "wait rss ready timeout!\n");
++			return -ETIMEDOUT;
++		}
++		usleep_range(10, 20);
++	}
++
++	return 0;
++}
++
++static void higmac_config_rss(struct higmac_netdev_local *priv)
++{
++	struct higmac_rss_info *rss = &priv->rss_info;
++	u32 rss_val;
++	int i;
++
++	for (i = 0; i < rss->ind_tbl_size; i++) {
++		if (higmac_wait_rss_ready(priv))
++			break;
++		rss_val = BIT_IND_TLB_WR | (rss->ind_tbl[i] << 8) | i;
++		writel(rss_val, priv->gmac_iobase + RSS_IND_TBL);
++	}
++}
++
++static void higmac_get_rss(struct higmac_netdev_local *priv)
++{
++	struct higmac_rss_info *rss = &priv->rss_info;
++	u32 rss_val;
++	int i;
++
++	for (i = 0; i < rss->ind_tbl_size; i++) {
++		if (higmac_wait_rss_ready(priv))
++			break;
++		writel(i, priv->gmac_iobase + RSS_IND_TBL);
++		if (higmac_wait_rss_ready(priv))
++			break;
++		rss_val = readl(priv->gmac_iobase + RSS_IND_TBL);
++		rss->ind_tbl[i] = (rss_val >> 10) & 0x3;
++	}
++}
++
++static int higmac_set_rxfh(struct net_device *ndev, const u32 *indir,
++			   const u8 *hkey)
++{
++	struct higmac_netdev_local *priv = netdev_priv(ndev);
++	struct higmac_rss_info *rss = &priv->rss_info;
++
++	if (indir) {
++		int i;
++
++		for (i = 0; i < rss->ind_tbl_size; i++)
++			rss->ind_tbl[i] = indir[i];
++	}
++
++	if (hkey) {
++		memcpy(rss->key, hkey, RSS_HASH_KEY_SIZE);
++		higmac_set_rss_key(priv);
++	}
++
++	higmac_config_rss(priv);
++
++	return 0;
++}
++
++static int higmac_get_rss_hash_opts(struct higmac_netdev_local *priv,
++				    struct ethtool_rxnfc *info)
++{
++	u32 hash_cfg = priv->rss_info.hash_cfg;
++
++	info->data = 0;
++
++	switch (info->flow_type) {
++	case TCP_V4_FLOW:
++		if (hash_cfg & TCPV4_L3_HASH_EN)
++			info->data |= RXH_IP_SRC | RXH_IP_DST;
++		if (hash_cfg & TCPV4_L4_HASH_EN)
++			info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
++		if (hash_cfg & TCPV4_VLAN_HASH_EN)
++			info->data |= RXH_VLAN;
++		break;
++	case TCP_V6_FLOW:
++		if (hash_cfg & TCPV6_L3_HASH_EN)
++			info->data |= RXH_IP_SRC | RXH_IP_DST;
++		if (hash_cfg & TCPV6_L4_HASH_EN)
++			info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
++		if (hash_cfg & TCPV6_VLAN_HASH_EN)
++			info->data |= RXH_VLAN;
++		break;
++	case UDP_V4_FLOW:
++		if (hash_cfg & UDPV4_L3_HASH_EN)
++			info->data |= RXH_IP_SRC | RXH_IP_DST;
++		if (hash_cfg & UDPV4_L4_HASH_EN)
++			info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
++		if (hash_cfg & UDPV4_VLAN_HASH_EN)
++			info->data |= RXH_VLAN;
++		break;
++	case UDP_V6_FLOW:
++		if (hash_cfg & UDPV6_L3_HASH_EN)
++			info->data |= RXH_IP_SRC | RXH_IP_DST;
++		if (hash_cfg & UDPV6_L4_HASH_EN)
++			info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
++		if (hash_cfg & UDPV6_VLAN_HASH_EN)
++			info->data |= RXH_VLAN;
++		break;
++	case IPV4_FLOW:
++		if (hash_cfg & IPV4_L3_HASH_EN)
++			info->data |= RXH_IP_SRC | RXH_IP_DST;
++		if (hash_cfg & IPV4_VLAN_HASH_EN)
++			info->data |= RXH_VLAN;
++		break;
++	case IPV6_FLOW:
++		if (hash_cfg & IPV6_L3_HASH_EN)
++			info->data |= RXH_IP_SRC | RXH_IP_DST;
++		if (hash_cfg & IPV6_VLAN_HASH_EN)
++			info->data |= RXH_VLAN;
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	return 0;
++}
++
++static int higmac_get_rxnfc(struct net_device *ndev,
++			    struct ethtool_rxnfc *info, u32 *rules)
++{
++	struct higmac_netdev_local *priv = netdev_priv(ndev);
++	int ret = -EOPNOTSUPP;
++
++	switch (info->cmd) {
++	case ETHTOOL_GRXRINGS:
++		info->data = priv->num_rxqs;
++		ret = 0;
++		break;
++	case ETHTOOL_GRXFH:
++		return higmac_get_rss_hash_opts(priv, info);
++	default:
++		break;
++	}
++	return ret;
++}
++
++static void higmac_config_hash_policy(struct higmac_netdev_local *priv)
++{
++	writel(priv->rss_info.hash_cfg, priv->gmac_iobase + RSS_HASH_CONFIG);
++}
++
++static int higmac_set_rss_hash_opts(struct higmac_netdev_local *priv,
++				    struct ethtool_rxnfc *info)
++{
++	u32 hash_cfg = priv->rss_info.hash_cfg;
++
++	netdev_info(priv->netdev, "Set RSS flow type = %d, data = %lld\n",
++		    info->flow_type, info->data);
++
++	if (!(info->data & RXH_IP_SRC) || !(info->data & RXH_IP_DST))
++		return -EINVAL;
++
++	switch (info->flow_type) {
++	case TCP_V4_FLOW:
++		switch (info->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
++		case 0:
++			hash_cfg &= ~TCPV4_L4_HASH_EN;
++			break;
++		case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
++			hash_cfg |= TCPV4_L4_HASH_EN;
++			break;
++		default:
++			return -EINVAL;
++		}
++		if (info->data & RXH_VLAN)
++			hash_cfg |= TCPV4_VLAN_HASH_EN;
++		else
++			hash_cfg &= ~TCPV4_VLAN_HASH_EN;
++		break;
++	case TCP_V6_FLOW:
++		switch (info->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
++		case 0:
++			hash_cfg &= ~TCPV6_L4_HASH_EN;
++			break;
++		case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
++			hash_cfg |= TCPV6_L4_HASH_EN;
++			break;
++		default:
++			return -EINVAL;
++		}
++		if (info->data & RXH_VLAN)
++			hash_cfg |= TCPV6_VLAN_HASH_EN;
++		else
++			hash_cfg &= ~TCPV6_VLAN_HASH_EN;
++		break;
++	case UDP_V4_FLOW:
++		switch (info->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
++		case 0:
++			hash_cfg &= ~UDPV4_L4_HASH_EN;
++			break;
++		case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
++			hash_cfg |= UDPV4_L4_HASH_EN;
++			break;
++		default:
++			return -EINVAL;
++		}
++		if (info->data & RXH_VLAN)
++			hash_cfg |= UDPV4_VLAN_HASH_EN;
++		else
++			hash_cfg &= ~UDPV4_VLAN_HASH_EN;
++		break;
++	case UDP_V6_FLOW:
++		switch (info->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
++		case 0:
++			hash_cfg &= ~UDPV6_L4_HASH_EN;
++			break;
++		case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
++			hash_cfg |= UDPV6_L4_HASH_EN;
++			break;
++		default:
++			return -EINVAL;
++		}
++		if (info->data & RXH_VLAN)
++			hash_cfg |= UDPV6_VLAN_HASH_EN;
++		else
++			hash_cfg &= ~UDPV6_VLAN_HASH_EN;
++		break;
++	case IPV4_FLOW:
++		if (info->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3))
++			return -EINVAL;
++		if (info->data & RXH_VLAN)
++			hash_cfg |= IPV4_VLAN_HASH_EN;
++		else
++			hash_cfg &= ~IPV4_VLAN_HASH_EN;
++		break;
++	case IPV6_FLOW:
++		if (info->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3))
++			return -EINVAL;
++		if (info->data & RXH_VLAN)
++			hash_cfg |= IPV6_VLAN_HASH_EN;
++		else
++			hash_cfg &= ~IPV6_VLAN_HASH_EN;
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	priv->rss_info.hash_cfg = hash_cfg;
++	higmac_config_hash_policy(priv);
++
++	return 0;
++}
++
++static int higmac_set_rxnfc(struct net_device *ndev, struct ethtool_rxnfc *info)
++{
++	struct higmac_netdev_local *priv = netdev_priv(ndev);
++
++	switch (info->cmd) {
++	case ETHTOOL_SRXFH:
++		return higmac_set_rss_hash_opts(priv, info);
++	default:
++		break;
++	}
++	return -EOPNOTSUPP;
++}
++
++static const struct ethtool_ops hieth_ethtools_ops = {
++	.get_drvinfo = higmac_get_drvinfo,
++	.get_link = higmac_get_link,
++	.get_settings = higmac_get_settings,
++	.set_settings = higmac_set_settings,
++	.get_pauseparam = higmac_get_pauseparam,
++	.set_pauseparam = higmac_set_pauseparam,
++	.get_msglevel = higmac_ethtool_getmsglevel,
++	.set_msglevel = higmac_ethtool_setmsglevel,
++	.get_rxfh_key_size = higmac_get_rxfh_key_size,
++	.get_rxfh_indir_size = higmac_get_rxfh_indir_size,
++	.get_rxfh = higmac_get_rxfh,
++	.set_rxfh = higmac_set_rxfh,
++	.get_rxnfc = higmac_get_rxnfc,
++	.set_rxnfc = higmac_set_rxnfc,
++};
++
++static const struct net_device_ops hieth_netdev_ops = {
++	.ndo_open = higmac_net_open,
++	.ndo_stop = higmac_net_close,
++	.ndo_start_xmit = higmac_net_xmit,
++	.ndo_tx_timeout = higmac_net_timeout,
++	.ndo_set_rx_mode = higmac_set_multicast_list,
++	.ndo_set_features = higmac_set_features,
++	.ndo_do_ioctl = higmac_ioctl,
++	.ndo_set_mac_address = higmac_net_set_mac_address,
++	.ndo_change_mtu = eth_change_mtu,
++	.ndo_get_stats = higmac_net_get_stats,
++};
++
++static int higmac_of_get_param(struct higmac_netdev_local *ld,
++			       struct device_node *node)
++{
++	/* get auto eee */
++	ld->autoeee = of_property_read_bool(node, "autoeee");
++	/* get internal flag */
++	ld->internal_phy =
++		of_property_read_bool(node, "internal-phy");
++
++	return 0;
++}
++
++static int KSZ8051MNL_phy_fix(struct phy_device *phy_dev)
++{
++	u32 v;
++	int ret;
++
++	if (phy_dev->interface != PHY_INTERFACE_MODE_RMII)
++		return 0;
++
++	ret = phy_read(phy_dev, 0x1F);
++	if (ret < 0)
++		return ret;
++	v = ret;
++	v |= (1 << 7);		/* set phy RMII 50MHz clk; */
++	phy_write(phy_dev, 0x1F, v);
++
++	ret = phy_read(phy_dev, 0x16);
++	if (ret < 0)
++		return ret;
++	v = ret;
++	v |= (1 << 1);		/* set phy RMII override; */
++	phy_write(phy_dev, 0x16, v);
++
++	return 0;
++}
++
++static int KSZ8081RNB_phy_fix(struct phy_device *phy_dev)
++{
++	u32 v;
++	int ret;
++
++	if (phy_dev->interface != PHY_INTERFACE_MODE_RMII)
++		return 0;
++
++	ret = phy_read(phy_dev, 0x1F);
++	if (ret < 0)
++		return ret;
++	v = ret;
++	v |= (1 << 7);		/* set phy RMII 50MHz clk; */
++	phy_write(phy_dev, 0x1F, v);
++
++	return 0;
++}
++
++static int rtl8211e_phy_fix(struct phy_device *phy_dev)
++{
++	u32 v;
++	int ret;
++
++	/* select Extension page */
++	phy_write(phy_dev, 0x1f, 0x7);
++	/* switch ExtPage 164 */
++	phy_write(phy_dev, 0x1e, 0xa4);
++
++	/* config RGMII rx pin io driver max */
++	ret = phy_read(phy_dev, 0x1c);
++	if (ret < 0)
++		return ret;
++	v = ret;
++	v = (v & 0xff03) | 0xfc;
++	phy_write(phy_dev, 0x1c, v);
++
++	/* select to page 0 */
++	phy_write(phy_dev, 0x1f, 0);
++
++	return 0;
++}
++
++static void phy_register_fixups(void)
++{
++	phy_register_fixup_for_uid(PHY_ID_KSZ8051MNL, DEFAULT_PHY_MASK,
++				   KSZ8051MNL_phy_fix);
++	phy_register_fixup_for_uid(PHY_ID_KSZ8081RNB, DEFAULT_PHY_MASK,
++				   KSZ8081RNB_phy_fix);
++	phy_register_fixup_for_uid(REALTEK_PHY_ID_8211E, REALTEK_PHY_MASK,
++				   rtl8211e_phy_fix);
++}
++
++static void phy_unregister_fixups(void)
++{
++	phy_unregister_fixup_for_uid(PHY_ID_KSZ8051MNL, DEFAULT_PHY_MASK);
++	phy_unregister_fixup_for_uid(PHY_ID_KSZ8081RNB, DEFAULT_PHY_MASK);
++	phy_unregister_fixup_for_uid(REALTEK_PHY_ID_8211E, REALTEK_PHY_MASK);
++}
++
++static void higmac_verify_flow_ctrl_args(void)
++{
++#if defined(CONFIG_TX_FLOW_CTRL_SUPPORT)
++	flow_ctrl_en |= FLOW_TX;
++#endif
++#if defined(CONFIG_RX_FLOW_CTRL_SUPPORT)
++	flow_ctrl_en |= FLOW_RX;
++#endif
++	if (tx_flow_ctrl_active_threshold < FC_ACTIVE_MIN ||
++	    tx_flow_ctrl_active_threshold > FC_ACTIVE_MAX)
++		tx_flow_ctrl_active_threshold = FC_ACTIVE_DEFAULT;
++
++	if (tx_flow_ctrl_deactive_threshold < FC_DEACTIVE_MIN ||
++	    tx_flow_ctrl_deactive_threshold > FC_DEACTIVE_MAX)
++		tx_flow_ctrl_deactive_threshold = FC_DEACTIVE_DEFAULT;
++
++	if (tx_flow_ctrl_active_threshold >= tx_flow_ctrl_deactive_threshold) {
++		tx_flow_ctrl_active_threshold = FC_ACTIVE_DEFAULT;
++		tx_flow_ctrl_deactive_threshold = FC_DEACTIVE_DEFAULT;
++	}
++
++	if (tx_flow_ctrl_pause_time < 0 ||
++	    tx_flow_ctrl_pause_time > FC_PAUSE_TIME_MAX)
++		tx_flow_ctrl_pause_time = FC_PAUSE_TIME_DEFAULT;
++
++	if (tx_flow_ctrl_pause_interval < 0 ||
++	    tx_flow_ctrl_pause_interval > FC_PAUSE_TIME_MAX)
++		tx_flow_ctrl_pause_interval = FC_PAUSE_INTERVAL_DEFAULT;
++
++	/* pause interval should not bigger than pause time,
++	 * but should not too smaller to avoid sending too many pause frame.
++	 */
++	if ((tx_flow_ctrl_pause_interval > tx_flow_ctrl_pause_time) ||
++	    (tx_flow_ctrl_pause_interval < (tx_flow_ctrl_pause_time >> 1)))
++		tx_flow_ctrl_pause_interval = tx_flow_ctrl_pause_time;
++}
++
++static void higmac_destroy_hw_desc_queue(struct higmac_netdev_local *priv)
++{
++	int i;
++
++	for (i = 0; i < QUEUE_NUMS + RSS_NUM_RXQS - 1; i++) {
++		if (priv->pool[i].desc) {
++			if (HAS_CAP_CCI(priv->hw_cap))
++				kfree(priv->pool[i].desc);
++			else
++				dma_free_coherent(priv->dev, priv->pool[i].size,
++						  priv->pool[i].desc,
++						  priv->pool[i].phys_addr);
++			priv->pool[i].desc = NULL;
++		}
++	}
++
++	kfree(priv->rx_fq.skb);
++	kfree(priv->tx_bq.skb);
++	priv->rx_fq.skb = NULL;
++	priv->tx_bq.skb = NULL;
++
++	if (priv->tso_supported) {
++		kfree(priv->tx_bq.sg_desc_offset);
++		priv->tx_bq.sg_desc_offset = NULL;
++	}
++
++	kfree(priv->tx_skb);
++	priv->tx_skb = NULL;
++
++	kfree(priv->rx_skb);
++	priv->rx_skb = NULL;
++}
++
++static int higmac_init_hw_desc_queue(struct higmac_netdev_local *priv)
++{
++	struct device *dev = priv->dev;
++	struct higmac_desc *virt_addr;
++	dma_addr_t phys_addr = 0;
++	int size, i;
++
++	priv->rx_fq.count = RX_DESC_NUM;
++	priv->rx_bq.count = RX_DESC_NUM;
++	priv->tx_bq.count = TX_DESC_NUM;
++	priv->tx_rq.count = TX_DESC_NUM;
++
++	for (i = 1; i < RSS_NUM_RXQS; i++)
++		priv->pool[3 + i].count = RX_DESC_NUM;
++
++	for (i = 0; i < (QUEUE_NUMS + RSS_NUM_RXQS - 1); i++) {
++		size = priv->pool[i].count * sizeof(struct higmac_desc);
++		if (HAS_CAP_CCI(priv->hw_cap)) {
++			virt_addr = kmalloc(size, GFP_KERNEL);
++			if (virt_addr)
++				phys_addr = virt_to_phys(virt_addr);
++		} else {
++			virt_addr = dma_alloc_coherent(dev, size, &phys_addr,
++						       GFP_KERNEL);
++		}
++		if (!virt_addr)
++			goto error_free_pool;
++
++		memset(virt_addr, 0, size);
++		priv->pool[i].size = size;
++		priv->pool[i].desc = virt_addr;
++		priv->pool[i].phys_addr = phys_addr;
++	}
++	priv->rx_fq.skb = kzalloc(priv->rx_fq.count
++				* sizeof(struct sk_buff *), GFP_KERNEL);
++	if (!priv->rx_fq.skb)
++		goto error_free_pool;
++
++	priv->rx_skb = kzalloc(priv->rx_fq.count
++			     * sizeof(struct sk_buff *), GFP_KERNEL);
++	if (!priv->rx_skb)
++		goto error_free_pool;
++
++	priv->tx_bq.skb = kzalloc(priv->tx_bq.count
++				* sizeof(struct sk_buff *), GFP_KERNEL);
++	if (!priv->tx_bq.skb)
++		goto error_free_pool;
++
++	priv->tx_skb = kzalloc(priv->tx_bq.count
++			     * sizeof(struct sk_buff *), GFP_KERNEL);
++	if (!priv->tx_skb)
++		goto error_free_pool;
++
++	if (priv->tso_supported) {
++		priv->tx_bq.sg_desc_offset = kzalloc(priv->tx_bq.count
++						   * sizeof(int), GFP_KERNEL);
++		if (!priv->tx_bq.sg_desc_offset)
++			goto error_free_pool;
++	}
++
++	higmac_hw_set_desc_addr(priv);
++	if (HAS_CAP_CCI(priv->hw_cap))
++		pr_info("higmac: ETH MAC supporte CCI.\n");
++
++	return 0;
++
++error_free_pool:
++	higmac_destroy_hw_desc_queue(priv);
++
++	return -ENOMEM;
++}
++
++void higmac_init_napi(struct higmac_netdev_local *priv)
++{
++	struct higmac_napi *q_napi;
++	int i;
++
++	for (i = 0; i < priv->num_rxqs; i++) {
++		q_napi = &priv->q_napi[i];
++		q_napi->rxq_id = i;
++		q_napi->ndev_priv = priv;
++		netif_napi_add(priv->netdev, &q_napi->napi, higmac_poll,
++			       NAPI_POLL_WEIGHT);
++	}
++}
++
++void higmac_destroy_napi(struct higmac_netdev_local *priv)
++{
++	struct higmac_napi *q_napi;
++	int i;
++
++	for (i = 0; i < priv->num_rxqs; i++) {
++		q_napi = &priv->q_napi[i];
++		netif_napi_del(&q_napi->napi);
++	}
++}
++
++int higmac_request_irqs(struct platform_device *pdev,
++			struct higmac_netdev_local *priv)
++{
++	struct device *dev = priv->dev;
++	int ret;
++	int i;
++
++	for (i = 0; i < priv->num_rxqs; i++) {
++		ret = platform_get_irq(pdev, i);
++		if (ret < 0) {
++			dev_err(dev, "No irq[%d] resource, ret=%d\n", i, ret);
++			return ret;
++		}
++		priv->irq[i] = ret;
++
++		ret = devm_request_irq(dev, priv->irq[i], higmac_interrupt,
++				       IRQF_SHARED, pdev->name,
++				       &priv->q_napi[i]);
++		if (ret) {
++			dev_err(dev, "devm_request_irq failed, ret=%d\n", ret);
++			return ret;
++		}
++	}
++
++	return 0;
++}
++
++static int higmac_dev_probe(struct platform_device *pdev)
++{
++	struct device *dev = &pdev->dev;
++	struct device_node *node = dev->of_node;
++	struct net_device *ndev;
++	struct higmac_netdev_local *priv;
++	struct resource *res;
++	const char *mac_addr;
++	unsigned int hw_cap;
++	int ret;
++	int num_rxqs;
++
++	higmac_verify_flow_ctrl_args();
++
++	if (of_device_is_compatible(node, "hisilicon,higmac-v5"))
++		num_rxqs = RSS_NUM_RXQS;
++	else
++		num_rxqs = 1;
++
++	ndev = alloc_etherdev_mqs(sizeof(struct higmac_netdev_local), 1,
++				  num_rxqs);
++	if (!ndev)
++		return -ENOMEM;
++
++	platform_set_drvdata(pdev, ndev);
++	SET_NETDEV_DEV(ndev, dev);
++
++	priv = netdev_priv(ndev);
++	priv->dev = dev;
++	priv->netdev = ndev;
++	priv->num_rxqs = num_rxqs;
++
++	if (of_device_is_compatible(node, "hisilicon,higmac-v3"))
++		priv->hw_cap |= HW_CAP_CCI;
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, MEM_GMAC_IOBASE);
++	priv->gmac_iobase = devm_ioremap_resource(dev, res);
++	if (IS_ERR(priv->gmac_iobase)) {
++		ret = PTR_ERR(priv->gmac_iobase);
++		goto out_free_netdev;
++	}
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM,
++				    MEM_MACIF_IOBASE);
++	priv->macif_base = devm_ioremap_resource(dev, res);
++	if (IS_ERR(priv->macif_base)) {
++		ret = PTR_ERR(priv->macif_base);
++		goto out_free_netdev;
++	}
++
++	priv->port_rst = devm_reset_control_get(dev, HIGMAC_PORT_RST_NAME);
++	if (IS_ERR(priv->port_rst)) {
++		ret = PTR_ERR(priv->port_rst);
++		goto out_free_netdev;
++	}
++
++	priv->macif_rst = devm_reset_control_get(dev, HIGMAC_MACIF_RST_NAME);
++	if (IS_ERR(priv->macif_rst)) {
++		ret = PTR_ERR(priv->macif_rst);
++		goto out_free_netdev;
++	}
++
++	priv->phy_rst = devm_reset_control_get(dev, HIGMAC_PHY_RST_NAME);
++	if (IS_ERR(priv->phy_rst))
++		priv->phy_rst = NULL;
++
++	priv->clk = devm_clk_get(&pdev->dev, HIGMAC_MAC_CLK_NAME);
++	if (IS_ERR(priv->clk)) {
++		netdev_err(ndev, "failed to get clk\n");
++		ret = -ENODEV;
++		goto out_free_netdev;
++	}
++
++	ret = clk_prepare_enable(priv->clk);
++	if (ret < 0) {
++		netdev_err(ndev, "failed to enable clk %d\n", ret);
++		goto out_free_netdev;
++	}
++
++	priv->macif_clk = devm_clk_get(&pdev->dev, HIGMAC_MACIF_CLK_NAME);
++	if (IS_ERR(priv->macif_clk))
++		priv->macif_clk = NULL;
++
++	if (priv->macif_clk) {
++		ret = clk_prepare_enable(priv->macif_clk);
++		if (ret < 0) {
++			netdev_err(ndev, "failed enable macif_clk %d\n", ret);
++			goto out_clk_disable;
++		}
++	}
++
++	higmac_mac_core_reset(priv);
++
++	/* phy reset, should be early than "of_mdiobus_register".
++	 * becausue "of_mdiobus_register" will read PHY register by MDIO.
++	 */
++	higmac_hw_phy_reset(priv);
++
++	higmac_of_get_param(priv, node);
++
++	ret = of_get_phy_mode(node);
++	if (ret < 0) {
++		netdev_err(ndev, "not find phy-mode\n");
++		goto out_macif_clk_disable;
++	}
++	priv->phy_mode = ret;
++
++	priv->phy_node = of_parse_phandle(node, "phy-handle", 0);
++	if (!priv->phy_node) {
++		netdev_err(ndev, "not find phy-handle\n");
++		ret = -EINVAL;
++		goto out_macif_clk_disable;
++	}
++
++	mac_addr = of_get_mac_address(node);
++	if (mac_addr)
++		ether_addr_copy(ndev->dev_addr, mac_addr);
++	if (!is_valid_ether_addr(ndev->dev_addr)) {
++		eth_hw_addr_random(ndev);
++		netdev_warn(ndev, "using random MAC address %pM\n",
++			    ndev->dev_addr);
++	}
++
++	higmac_hw_set_mac_addr(ndev);
++
++	hw_cap = readl(priv->gmac_iobase + CRF_MIN_PACKET);
++	priv->tso_supported = HAS_TSO_CAP(hw_cap);
++	priv->has_rxhash_cap = HAS_RXHASH_CAP(hw_cap);
++	priv->has_rss_cap = HAS_RSS_CAP(hw_cap);
++
++	higmac_set_rss_cap(priv);
++	higmac_get_rss_key(priv);
++	if (priv->has_rss_cap) {
++		priv->rss_info.ind_tbl_size = RSS_INDIRECTION_TABLE_SIZE;
++		higmac_get_rss(priv);
++	}
++
++	if (priv->has_rxhash_cap) {
++		priv->rss_info.hash_cfg = DEF_HASH_CFG;
++		higmac_config_hash_policy(priv);
++	}
++
++	/* init hw controller */
++	higmac_hw_init(priv);
++
++	/* TODO: phy fix here?? other way ??? */
++	phy_register_fixups();
++
++	priv->phy = of_phy_connect(ndev, priv->phy_node,
++				   &higmac_adjust_link, 0, priv->phy_mode);
++	if (!priv->phy) {
++		ret = -ENODEV;
++		goto out_phy_node;
++	}
++
++	/* If the phy_id is mostly Fs, there is no device there */
++	if ((priv->phy->phy_id & 0x1fffffff) == 0x1fffffff ||
++	    priv->phy->phy_id == 0) {
++		pr_info("phy %d not found\n", priv->phy->addr);
++		ret = -ENODEV;
++		goto out_phy_disconnect;
++	}
++
++	pr_info("attached PHY %d to driver %s, PHY_ID=0x%x\n",
++		priv->phy->addr, priv->phy->drv->name, priv->phy->phy_id);
++
++	/* Stop Advertising 1000BASE Capability if interface is not RGMII */
++	if ((priv->phy_mode == PHY_INTERFACE_MODE_MII) ||
++	    (priv->phy_mode == PHY_INTERFACE_MODE_RMII)) {
++		priv->phy->advertising &= ~(SUPPORTED_1000baseT_Half |
++					    SUPPORTED_1000baseT_Full);
++
++		/* Internal FE phy's reg BMSR bit8 is wrong, make the kernel
++		 * believe it has the 1000base Capability, so fix it here
++		 */
++		if (priv->phy->phy_id == HISILICON_PHY_ID_FESTAV200)
++			priv->phy->supported &= ~(ADVERTISED_1000baseT_Full |
++						  ADVERTISED_1000baseT_Half);
++	}
++
++	higmac_set_flow_ctrl_args(priv);
++	higmac_set_flow_ctrl_params(priv);
++	priv->phy->supported |= SUPPORTED_Pause;
++	if (priv->flow_ctrl)
++		priv->phy->advertising |= SUPPORTED_Pause;
++
++	if (priv->autoeee)
++		init_autoeee(priv);
++
++	ret = higmac_request_irqs(pdev, priv);
++	if (ret)
++		goto out_phy_disconnect;
++
++	higmac_init_napi(priv);
++	spin_lock_init(&priv->rxlock);
++	spin_lock_init(&priv->txlock);
++	spin_lock_init(&priv->pmtlock);
++
++	/* init netdevice */
++	ndev->irq = priv->irq[0];
++	ndev->watchdog_timeo = 3 * HZ;
++	ndev->netdev_ops = &hieth_netdev_ops;
++	ndev->ethtool_ops = &hieth_ethtools_ops;
++
++	if (priv->has_rxhash_cap)
++		ndev->hw_features |= NETIF_F_RXHASH;
++	if (priv->has_rss_cap)
++		ndev->hw_features |= NETIF_F_NTUPLE;
++	if (priv->tso_supported) {
++		ndev->hw_features |= NETIF_F_SG |
++			NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
++			NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_UFO;
++	}
++#if defined(CONFIG_HIGMAC_RXCSUM)
++	ndev->hw_features |= NETIF_F_RXCSUM;
++	higmac_enable_rxcsum_drop(priv, true);
++#endif
++
++	ndev->features |= ndev->hw_features;
++	ndev->features |= NETIF_F_HIGHDMA | NETIF_F_GSO;
++	ndev->vlan_features |= ndev->features;
++
++	init_timer(&priv->monitor);
++	priv->monitor.function = higmac_monitor_func;
++	priv->monitor.data = (unsigned long)ndev;
++	priv->monitor.expires = jiffies + HIGMAC_MONITOR_TIMER;
++
++	device_set_wakeup_capable(priv->dev, 1);
++	/* TODO: when we can let phy powerdown?
++	 * In some mode, we don't want phy powerdown,
++	 * so I set wakeup enable all the time
++	 */
++	device_set_wakeup_enable(priv->dev, 1);
++
++	priv->wol_enable = false;
++
++	priv->msg_enable = netif_msg_init(debug, DEFAULT_MSG_ENABLE);
++
++	/* init hw desc queue */
++	ret = higmac_init_hw_desc_queue(priv);
++	if (ret)
++		goto _error_hw_desc_queue;
++
++	if (priv->tso_supported) {
++		ret = higmac_init_sg_desc_queue(priv);
++		if (ret)
++			goto _error_sg_desc_queue;
++	}
++
++	/* register netdevice */
++	ret = register_netdev(priv->netdev);
++	if (ret) {
++		pr_err("register_ndev failed!");
++		goto _error_sg_desc_queue;
++	}
++
++	/* reset queue here to make BQL only reset once.
++	 * if we put netdev_reset_queue() in higmac_net_open(),
++	 * the BQL will be reset when ifconfig eth0 down and up,
++	 * but the tx ring is not cleared before.
++	 * As a result, the NAPI poll will call netdev_completed_queue()
++	 * and BQL throw a bug.
++	 */
++	netdev_reset_queue(ndev);
++
++	clk_disable_unprepare(priv->clk);
++	if (priv->macif_clk)
++		clk_disable_unprepare(priv->macif_clk);
++
++	pr_info("ETH: %s, phy_addr=%d\n",
++		phy_modes(priv->phy_mode), priv->phy->addr);
++
++	return ret;
++
++_error_sg_desc_queue:
++	if (priv->tso_supported)
++		higmac_destroy_sg_desc_queue(priv);
++
++_error_hw_desc_queue:
++	higmac_destroy_hw_desc_queue(priv);
++	higmac_destroy_napi(priv);
++out_phy_disconnect:
++	phy_disconnect(priv->phy);
++out_phy_node:
++	of_node_put(priv->phy_node);
++out_macif_clk_disable:
++	if (priv->macif_clk)
++		clk_disable_unprepare(priv->macif_clk);
++out_clk_disable:
++	clk_disable_unprepare(priv->clk);
++out_free_netdev:
++	free_netdev(ndev);
++
++	return ret;
++}
++
++static int higmac_dev_remove(struct platform_device *pdev)
++{
++	struct net_device *ndev = platform_get_drvdata(pdev);
++	struct higmac_netdev_local *priv = netdev_priv(ndev);
++
++	/* TODO: stop the gmac and free all resource */
++	del_timer_sync(&priv->monitor);
++	higmac_destroy_napi(priv);
++
++	unregister_netdev(ndev);
++
++	higmac_reclaim_rx_tx_resource(priv);
++	higmac_free_rx_skb(priv);
++	higmac_free_tx_skb(priv);
++
++	if (priv->tso_supported)
++		higmac_destroy_sg_desc_queue(priv);
++	higmac_destroy_hw_desc_queue(priv);
++
++	phy_disconnect(priv->phy);
++	of_node_put(priv->phy_node);
++
++	free_netdev(ndev);
++
++	phy_unregister_fixups();
++
++	return 0;
++}
++
++#include "pm.c"
++#ifdef CONFIG_PM
++
++static void higmac_disable_irq(struct higmac_netdev_local *priv)
++{
++	int i;
++
++	for (i = 0; i < priv->num_rxqs; i++)
++		disable_irq(priv->irq[i]);
++}
++
++static void higmac_enable_irq(struct higmac_netdev_local *priv)
++{
++	int i;
++
++	for (i = 0; i < priv->num_rxqs; i++)
++		enable_irq(priv->irq[i]);
++}
++
++int higmac_dev_suspend(struct platform_device *pdev, pm_message_t state)
++{
++	struct net_device *ndev = platform_get_drvdata(pdev);
++	struct higmac_netdev_local *priv = netdev_priv(ndev);
++
++	higmac_disable_irq(priv);
++	/* If support Wake on LAN, we should not disconnect phy
++	 * because it will call phy_suspend to power down phy.
++	 */
++	if (!priv->wol_enable)
++		phy_disconnect(priv->phy);
++	del_timer_sync(&priv->monitor);
++	/* If suspend when netif is not up, the napi_disable will run into
++	 * dead loop and dpm_drv_timeout will give warning.
++	 */
++	if (netif_running(ndev))
++		higmac_disable_napi(priv);
++	netif_device_detach(ndev);
++
++	netif_carrier_off(ndev);
++
++	/* If netdev is down, MAC clock is disabled.
++	 * So if we want to reclaim MAC rx and tx resource,
++	 * we must first enable MAC clock and then disable it.
++	 */
++	if (!(ndev->flags & IFF_UP))
++		clk_prepare_enable(priv->clk);
++
++	higmac_reclaim_rx_tx_resource(priv);
++
++	if (!(ndev->flags & IFF_UP))
++		clk_disable_unprepare(priv->clk);
++
++	pmt_enter(priv);
++
++	if (!priv->wol_enable) {	/* if no WOL, then poweroff */
++		/* pr_info("power off gmac.\n"); */
++		/* no need to call genphy_resume() in resume,
++		 * because we reset everything
++		 */
++		genphy_suspend(priv->phy);	/* power down phy */
++		msleep(20);
++		higmac_hw_all_clk_disable(priv);
++	}
++
++	return 0;
++}
++EXPORT_SYMBOL(higmac_dev_suspend);
++
++int higmac_dev_resume(struct platform_device *pdev)
++{
++	struct net_device *ndev = platform_get_drvdata(pdev);
++	struct higmac_netdev_local *priv = netdev_priv(ndev);
++	int ret = 0;
++
++	/* If we support Wake on LAN, we doesn't call clk_disable.
++	 * But when we resume, the uboot may off mac clock and reset phy
++	 * by re-write the mac CRG register.
++	 * So we first call clk_disable, and then clk_enable.
++	 */
++	if (priv->wol_enable)
++		higmac_hw_all_clk_disable(priv);
++
++	higmac_hw_all_clk_enable(priv);
++	/* internal FE_PHY: enable clk and reset  */
++	higmac_hw_phy_reset(priv);
++
++	/* If netdev is down, MAC clock is disabled.
++	 * So if we want to restart MAC and re-initialize it,
++	 * we must first enable MAC clock and then disable it.
++	 */
++	if (!(ndev->flags & IFF_UP))
++		clk_prepare_enable(priv->clk);
++
++	/* power on gmac */
++	higmac_restart(priv);
++
++	/* If support WoL, we didn't disconnect phy.
++	 * But when we resume, we reset PHY, so we want to
++	 * call phy_connect to make phy_fixup excuted.
++	 * This is important for internal PHY fix.
++	 */
++	if (priv->wol_enable)
++		phy_disconnect(priv->phy);
++
++	ret = phy_connect_direct(ndev, priv->phy, higmac_adjust_link,
++				 priv->phy_mode);
++	if (ret)
++		return ret;
++
++	/* If we suspend and resume when net device is down,
++	 * some operations are unnecessary.
++	 */
++	if (ndev->flags & IFF_UP) {
++		priv->monitor.expires = jiffies + HIGMAC_MONITOR_TIMER;
++		mod_timer(&priv->monitor, priv->monitor.expires);
++		priv->old_link = 0;
++		priv->old_speed = SPEED_UNKNOWN;
++		priv->old_duplex = DUPLEX_UNKNOWN;
++	}
++	if (netif_running(ndev))
++		higmac_enable_napi(priv);
++	netif_device_attach(ndev);
++	if (ndev->flags & IFF_UP)
++		phy_start(priv->phy);
++	higmac_enable_irq(priv);
++
++	pmt_exit(priv);
++
++	if (!(ndev->flags & IFF_UP))
++		clk_disable_unprepare(priv->clk);
++
++	return 0;
++}
++EXPORT_SYMBOL(higmac_dev_resume);
++#else
++#define higmac_dev_suspend	NULL
++#define higmac_dev_resume	NULL
++#endif
++
++static const struct of_device_id higmac_of_match[] = {
++	{.compatible = "hisilicon,higmac",},
++	{.compatible = "hisilicon,higmac-v1",},
++	{.compatible = "hisilicon,higmac-v2",},
++	{.compatible = "hisilicon,higmac-v3",},
++	{.compatible = "hisilicon,higmac-v4",},
++	{.compatible = "hisilicon,higmac-v5",},
++	{ },
++};
++
++MODULE_DEVICE_TABLE(of, higmac_of_match);
++
++static struct platform_driver higmac_dev_driver = {
++	.probe = higmac_dev_probe,
++	.remove = higmac_dev_remove,
++	.suspend = higmac_dev_suspend,
++	.resume = higmac_dev_resume,
++	.driver = {
++		   .owner = THIS_MODULE,
++		   .name = HIGMAC_DRIVER_NAME,
++		   .of_match_table = higmac_of_match,
++		   },
++};
++
++#include "proc-dev.c"
++
++static int __init higmac_init(void)
++{
++	int ret = 0;
++
++	ret = platform_driver_register(&higmac_dev_driver);
++	if (ret)
++		return ret;
++
++	higmac_proc_create();
++
++	return ret;
++}
++
++static void __exit higmac_exit(void)
++{
++	platform_driver_unregister(&higmac_dev_driver);
++
++	higmac_proc_destroy();
++}
++
++module_init(higmac_init);
++module_exit(higmac_exit);
++
++MODULE_AUTHOR("ZMJUN");
++MODULE_DESCRIPTION("Hisilicon double GMAC driver, base on driver higmacv200 by CHH");
++MODULE_LICENSE("GPL v2");
+diff --git a/drivers/net/ethernet/hisilicon/higmac/higmac.h b/drivers/net/ethernet/hisilicon/higmac/higmac.h
+new file mode 100644
+index 0000000..df0295f
+--- /dev/null
++++ b/drivers/net/ethernet/hisilicon/higmac/higmac.h
+@@ -0,0 +1,615 @@
++#ifndef __HIGMAC_H__
++#define __HIGMAC_H__
++
++#include <linux/kernel.h>
++#include <linux/delay.h>
++#include <linux/netdevice.h>
++#include <linux/list.h>
++#include <linux/phy.h>
++#include <linux/io.h>
++#include <linux/interrupt.h>
++
++#define STATION_ADDR_LOW		0x0000
++#define STATION_ADDR_HIGH		0x0004
++#define MAC_DUPLEX_HALF_CTRL		0x0008
++
++#define PORT_MODE			0x0040
++
++#define PORT_EN				0x0044
++#define BITS_TX_EN			BIT(2)
++#define BITS_RX_EN			BIT(1)
++
++#define FC_TX_TIMER			0x001C
++
++#define PAUSE_THR			0x0038
++
++#define PAUSE_EN			0x0048
++#define BIT_RX_FDFC			BIT(0)
++#define BIT_TX_FDFC			BIT(1)
++
++#define RX_PAUSE_EN			0x02A4
++#define BIT_RX_FQ_PAUSE_EN		BIT(0)
++#define BIT_RX_BQ_PAUSE_EN		BIT(1)
++
++#define CRF_TX_PAUSE			0x0340
++
++#define BITS_Q_PAUSE_TH_OFFSET		16
++#define BITS_Q_PAUSE_TH_MASK		0xFFFF
++
++#define REC_FILT_CONTROL		0x0064
++#define BIT_CRC_ERR_PASS		BIT(5)
++#define BIT_PAUSE_FRM_PASS		BIT(4)
++#define BIT_VLAN_DROP_EN		BIT(3)
++#define BIT_BC_DROP_EN			BIT(2)
++#define BIT_MC_MATCH_EN			BIT(1)
++#define BIT_UC_MATCH_EN			BIT(0)
++
++#define	PORT_MC_ADDR_LOW		0x0068
++#define	PORT_MC_ADDR_HIGH		0x006C
++#define MAC_CLEAR			0x0070
++#define BIT_TX_SOFT_RESET		BIT(0)
++
++#define MODE_CHANGE_EN			0x01b4
++#define BIT_MODE_CHANGE_EN		BIT(0)
++
++#define COL_SLOT_TIME			0x01c0
++
++#define CRF_MIN_PACKET			0x0210
++#define BIT_OFFSET_TX_MIN_LEN		8
++#define BIT_MASK_TX_MIN_LEN		GENMASK(13, 8)
++
++#define CONTROL_WORD			0x0214
++#define CONTROL_WORD_CONFIG		0x640
++
++#define TSO_COE_CTRL			0x02e8
++#define BIT_COE_IPHDR_DROP		BIT(4)
++#define BIT_COE_PAYLOAD_DROP		BIT(5)
++#define BIT_COE_IPV6_UDP_ZERO_DROP	BIT(6)
++#define COE_ERR_DROP			(BIT_COE_IPHDR_DROP | \
++					BIT_COE_PAYLOAD_DROP | \
++					BIT_COE_IPV6_UDP_ZERO_DROP)
++
++#define RX_FQ_START_ADDR		0x0500
++#define RX_FQ_DEPTH			0x0504
++#define RX_FQ_WR_ADDR			0x0508
++#define BITS_RX_FQ_WR_ADDR		MK_BITS(0, 21)
++#define RX_FQ_RD_ADDR			0x050c
++#define BITS_RX_FQ_RD_ADDR		MK_BITS(0, 21)
++#define RX_FQ_VLDDESC_CNT		0x0510
++#define BITS_RX_FQ_VLDDESC_CNT		MK_BITS(0, 16)
++#define RX_FQ_ALEMPTY_TH		0x0514
++#define BITS_RX_FQ_ALEMPTY_TH		MK_BITS(0, 16)
++#define RX_FQ_REG_EN			0x0518
++#define BITS_RX_FQ_START_ADDR_EN	BIT(2)
++#define BITS_RX_FQ_DEPTH_EN		BIT(1)
++#define BITS_RX_FQ_RD_ADDR_EN		MK_BITS(0, 1)
++#define RX_FQ_ALFULL_TH			0x051c
++#define BITS_RX_FQ_ALFULL_TH		MK_BITS(0, 16)
++
++#define RX_BQ_START_ADDR		0x0520
++#define RX_BQ_DEPTH			0x0524
++#define RX_BQ_WR_ADDR			0x0528
++#define RX_BQ_RD_ADDR			0x052c
++#define RX_BQ_FREE_DESC_CNT		0x0530
++#define BITS_RX_BQ_FREE_DESC_CNT	MK_BITS(0, 16)
++#define RX_BQ_ALEMPTY_TH		0x0534
++#define BITS_RX_BQ_ALEMPTY_TH		MK_BITS(0, 16)
++#define RX_BQ_REG_EN			0x0538
++#define BITS_RX_BQ_START_ADDR_EN	BIT(2)
++#define BITS_RX_BQ_DEPTH_EN		BIT(1)
++#define BITS_RX_BQ_WR_ADDR_EN		MK_BITS(0, 1)
++#define RX_BQ_ALFULL_TH			0x053c
++#define BITS_RX_BQ_ALFULL_TH		MK_BITS(0, 16)
++
++#define TX_BQ_START_ADDR		0x0580
++#define TX_BQ_DEPTH			0x0584
++#define TX_BQ_WR_ADDR			0x0588
++#define BITS_TX_BQ_WR_ADDR		MK_BITS(0, 21)
++#define TX_BQ_RD_ADDR			0x058c
++#define BITS_TX_BQ_RD_ADDR		MK_BITS(0, 21)
++#define TX_BQ_VLDDESC_CNT		0x0590
++#define BITS_TX_BQ_VLDDESC_CNT		MK_BITS(0, 16)
++#define TX_BQ_ALEMPTY_TH		0x0594
++#define BITS_TX_BQ_ALEMPTY_TH		MK_BITS(0, 16)
++#define TX_BQ_REG_EN			0x0598
++#define BITS_TX_BQ_START_ADDR_EN	BIT(2)
++#define BITS_TX_BQ_DEPTH_EN		BIT(1)
++#define BITS_TX_BQ_RD_ADDR_EN		MK_BITS(0, 1)
++#define TX_BQ_ALFULL_TH			0x059c
++#define BITS_TX_BQ_ALFULL_TH		MK_BITS(0, 16)
++
++#define TX_RQ_START_ADDR		0x05a0
++#define TX_RQ_DEPTH			0x05a4
++#define TX_RQ_WR_ADDR			0x05a8
++#define BITS_TX_RQ_WR_ADDR		MK_BITS(0, 21)
++#define TX_RQ_RD_ADDR			0x05ac
++#define BITS_TX_RQ_RD_ADDR		MK_BITS(0, 21)
++#define TX_RQ_FREE_DESC_CNT		0x05b0
++#define BITS_TX_RQ_FREE_DESC_CNT	MK_BITS(0, 16)
++#define TX_RQ_ALEMPTY_TH		0x05b4
++#define BITS_TX_RQ_ALEMPTY_TH		MK_BITS(0, 16)
++#define TX_RQ_REG_EN			0x05b8
++#define BITS_TX_RQ_START_ADDR_EN	BIT(2)
++#define BITS_TX_RQ_DEPTH_EN		BIT(1)
++#define BITS_TX_RQ_WR_ADDR_EN		MK_BITS(0, 1)
++#define TX_RQ_ALFULL_TH			0x05bc
++#define BITS_TX_RQ_ALFULL_TH		MK_BITS(0, 16)
++
++#define RAW_PMU_INT			0x05c0
++#define ENA_PMU_INT			0x05c4
++
++#define DESC_WR_RD_ENA					0x05CC
++
++#define IN_QUEUE_TH					0x05d8
++#define BITS_OFFSET_TX_RQ_IN_TH				16
++
++#define RX_BQ_IN_TIMEOUT_TH				0x05E0
++
++#define TX_RQ_IN_TIMEOUT_TH				0x05e4
++
++#define STOP_CMD			0x05e8
++#define BITS_TX_STOP_EN			BIT(1)
++#define BITS_RX_STOP_EN			BIT(0)
++#define	STOP_RX_TX			(BITS_TX_STOP_EN | BITS_RX_STOP_EN)
++
++#define HW_CAP_EN			0x0c00
++#define BIT_RSS_CAP			BIT(0)
++#define BIT_RXHASH_CAP			BIT(1)
++#define RSS_HASH_KEY			0x0c04
++#define RSS_HASH_CONFIG			0x0c08
++#define TCPV4_L3_HASH_EN		BIT(0)
++#define TCPV4_L4_HASH_EN		BIT(1)
++#define TCPV4_VLAN_HASH_EN		BIT(2)
++#define UDPV4_L3_HASH_EN		BIT(4)
++#define UDPV4_L4_HASH_EN		BIT(5)
++#define UDPV4_VLAN_HASH_EN		BIT(6)
++#define IPV4_L3_HASH_EN			BIT(8)
++#define IPV4_VLAN_HASH_EN		BIT(9)
++#define TCPV6_L3_HASH_EN		BIT(12)
++#define TCPV6_L4_HASH_EN		BIT(13)
++#define TCPV6_VLAN_HASH_EN		BIT(14)
++#define UDPV6_L3_HASH_EN		BIT(16)
++#define UDPV6_L4_HASH_EN		BIT(17)
++#define UDPV6_VLAN_HASH_EN		BIT(18)
++#define IPV6_L3_HASH_EN			BIT(20)
++#define IPV6_VLAN_HASH_EN		BIT(21)
++#define DEF_HASH_CFG			0x377377
++
++#define RSS_IND_TBL			0x0c0c
++#define BIT_IND_TBL_READY		BIT(13)
++#define BIT_IND_TLB_WR			BIT(12)
++#define RSS_RAW_PMU_INT			0x0c10
++#define RSS_QUEUE1_START_ADDR		0x0c20
++#define RX_BQ_START_ADDR_QUEUE(i)	(RSS_QUEUE1_START_ADDR + \
++					((i) - 1) * 0x10)
++#define RSS_QUEUE1_DEPTH		0x0c24
++#define RX_BQ_WR_ADDR_QUEUE1		0x0c28
++#define RX_BQ_RD_ADDR_QUEUE1		0x0c2c
++#define RSS_QUEUE1_ENA_INT		0x0c90
++#define RSS_ENA_INT_QUEUE(i)		(RSS_QUEUE1_ENA_INT + ((i) - 1) * 0x4)
++#define RX_BQ_DEPTH_QUEUE(i)		(RSS_QUEUE1_DEPTH + ((i) - 1) * 0x10)
++#define RX_BQ_WR_ADDR_QUEUE(i)		((i) ? (RX_BQ_WR_ADDR_QUEUE1 + \
++					((i) - 1) * 0x10) : RX_BQ_WR_ADDR)
++#define RX_BQ_RD_ADDR_QUEUE(i)		((i) ? (RX_BQ_RD_ADDR_QUEUE1 + \
++					((i) - 1) * 0x10) : RX_BQ_RD_ADDR)
++
++#define DEF_INT_MASK_QUEUE(i)		(0x3 << (2 * ((i) - 1)))
++
++/* AXI burst and outstanding config */
++#define BURST_OUTSTANDING_REG		0x3014
++#define BURST4_OUTSTANDING1		0x81ff
++#define BURST_OUTSTANDING_OFFSET	16
++
++#define GMAC_SPEED_1000			0x05
++#define GMAC_SPEED_100			0x01
++#define GMAC_SPEED_10			0x00
++
++enum higmac_tx_err {
++	ERR_NONE = 0,
++	ERR_DESC_CFG = (1 << 0),
++	ERR_DATA_LEN = (1 << 1),
++	ERR_DESC_NFRAG_NUM = (1 << 2),
++	ERR_DESC_IP_HDR_LEN = (1 << 3),
++	ERR_DESC_PROT_HDR_LEN = (1 << 4),
++	ERR_DESC_MTU = (1 << 5),
++	ERR_LINK_SGPKT_LEN = (1 << 8),
++	ERR_LINK_TSOPKT_LINEAR = (1 << 9),
++	ERR_LINK_NFRAG_LEN = (1 << 10),
++	ERR_LINK_TOTAL_LEN = (1 << 11),
++	ERR_HDR_TCP_BCMC = (1 << 12),
++	ERR_HDR_UDP_BC = (1 << 13),
++	ERR_HDR_VLAN_IP_TYPE = (1 << 14),
++	ERR_HDR_IP_TYPE = (1 << 15),
++	ERR_HDR_IP_VERSION = (1 << 16),
++	ERR_HDR_IP_HDR_LEN = (1 << 17),
++	ERR_HDR_IP_TOTAL_LEN = (1 << 18),
++	ERR_HDR_IPV6_TTL_PROT = (1 << 19),
++	ERR_HDR_IPV4_OFFSET = (1 << 20),
++	ERR_HDR_IPV4_TTL_PROT = (1 << 21),
++	ERR_HDR_UDP_LEN = (1 << 22),
++	ERR_HDR_TCP_LEN = (1 << 23),
++	ERR_DESC = (ERR_DESC_CFG | ERR_DATA_LEN |
++			ERR_DESC_NFRAG_NUM | ERR_DESC_IP_HDR_LEN |
++			ERR_DESC_PROT_HDR_LEN | ERR_DESC_MTU),
++	ERR_LINK = (ERR_LINK_SGPKT_LEN | ERR_LINK_TSOPKT_LINEAR |
++			ERR_LINK_NFRAG_LEN | ERR_LINK_TOTAL_LEN),
++	ERR_HDR = (ERR_HDR_TCP_BCMC | ERR_HDR_UDP_BC |
++			ERR_HDR_VLAN_IP_TYPE | ERR_HDR_IP_TYPE |
++			ERR_HDR_IP_VERSION | ERR_HDR_IP_HDR_LEN |
++			ERR_HDR_IP_TOTAL_LEN | ERR_HDR_IPV6_TTL_PROT |
++			ERR_HDR_IPV4_OFFSET | ERR_HDR_IPV4_TTL_PROT |
++			ERR_HDR_UDP_LEN | ERR_HDR_TCP_LEN),
++	ERR_ALL = (ERR_DESC | ERR_LINK | ERR_HDR),
++};
++
++#define HIGMAC_DRIVER_NAME	"hi_gmac_v200"
++
++#define HIGMAC_MAC_CLK_NAME	"higmac_clk"
++#define HIGMAC_MACIF_CLK_NAME	"macif_clk"
++
++#define HIGMAC_PORT_RST_NAME	"port_reset"
++#define HIGMAC_MACIF_RST_NAME	"macif_reset"
++#define HIGMAC_PHY_RST_NAME	"phy_reset"
++
++#define HIGMAC_TSO_DEBUG
++
++#include "tso.h"
++
++#if defined(CONFIG_ARCH_HI3519) || defined(CONFIG_ARCH_HI3519V101) || \
++	defined(CONFIG_ARCH_HI3516AV200)
++#ifdef readl
++#undef readl
++#undef readl_relaxed
++#undef writel
++#undef writel_relaxed
++#define readl		hi_readl
++#define readl_relaxed	hi_readl_relaxed
++#define writel		hi_writel
++#define writel_relaxed	hi_writel_relaxed
++#endif /* readl */
++#endif /* defined(CONFIG_ARCH_HI3519) || defined(CONFIG_HI3519V101) */
++
++#define HIGMAC_IOSIZE			(0x1000)
++#define HIGMAC_OFFSET			(HIGMAC_IOSIZE)
++
++#define RX_BQ_IN_INT			BIT(17)
++#define TX_RQ_IN_INT			BIT(19)
++#define RX_BQ_IN_TIMEOUT_INT		BIT(28)
++#define TX_RQ_IN_TIMEOUT_INT		BIT(29)
++
++#define DEF_INT_MASK			(RX_BQ_IN_INT | RX_BQ_IN_TIMEOUT_INT | \
++					TX_RQ_IN_INT | TX_RQ_IN_TIMEOUT_INT)
++
++/* write or read descriptor need memory barrier */
++#define HIGMAC_SYNC_BARRIER() do { isb(); smp_mb(); } while (0)
++
++#define HISILICON_PHY_ID_FESTAV200	(0x20669823)
++#define PHY_ID_KSZ8051MNL               (0x00221550)
++#define PHY_ID_KSZ8081RNB               (0x00221560)
++#define DEFAULT_PHY_MASK                (0xfffffff0)
++#define REALTEK_PHY_ID_8211E		(0x001cc915)
++#define REALTEK_PHY_MASK		(0x001fffff)
++
++enum {
++	GMAC_PORT0,
++	GMAC_PORT1,
++	GMAC_MAX_PORT,
++};
++
++enum {
++	MEM_GMAC_IOBASE,
++	MEM_MACIF_IOBASE,
++	MEM_FWD_IOBASE,
++	MEM_CTRL_IOBASE,
++};
++
++#define HIGMAC_LINKED		BIT(0)
++#define HIGMAC_DUP_FULL		BIT(1)
++#define HIGMAC_SPD_10M		BIT(2)
++#define HIGMAC_SPD_100M		BIT(3)
++#define HIGMAC_SPD_1000M	BIT(4)
++/* Flow Control defines */
++#define FLOW_OFF        0
++#define FLOW_RX         1
++#define FLOW_TX         2
++#define FLOW_AUTO       (FLOW_TX | FLOW_RX)
++
++#define FC_ACTIVE_MIN		1
++#define FC_ACTIVE_DEFAULT	16
++#define FC_ACTIVE_MAX		127
++#define FC_DEACTIVE_MIN		1
++#define FC_DEACTIVE_DEFAULT	32
++#define FC_DEACTIVE_MAX		127
++
++#define FC_PAUSE_TIME_DEFAULT		0xFFFF
++#define FC_PAUSE_INTERVAL_DEFAULT	0xFFFF
++#define FC_PAUSE_TIME_MAX		0xFFFF
++
++#define RX_BQ_INT_THRESHOLD	0x40	/* TODO: */
++#define TX_RQ_INT_THRESHOLD	0x20	/* TODO: */
++
++#define HIGMAC_MONITOR_TIMER	(msecs_to_jiffies(200))
++
++#define HIETH_MAX_FRAME_SIZE	(1600 + 128)
++#define SKB_SIZE		(HIETH_MAX_FRAME_SIZE)
++
++#define DESC_VLD_FREE		0
++#define DESC_VLD_BUSY		1
++
++#define DESC_FL_FIRST		2
++#define DESC_FL_MID		0
++#define DESC_FL_LAST		1
++#define DESC_FL_FULL		3
++
++#if defined(CONFIG_HIGMAC_DESC_4WORD)
++#define DESC_WORD_SHIFT		2
++#else
++#define DESC_WORD_SHIFT		3
++#endif
++#define DESC_BYTE_SHIFT		(DESC_WORD_SHIFT + 2)
++#define DESC_WORD_CNT		(1 << DESC_WORD_SHIFT)
++#define DESC_SIZE		(1 << DESC_BYTE_SHIFT)
++
++#define RX_DESC_NUM			1024
++#define TX_DESC_NUM			1024
++
++/* DMA descriptor ring helpers */
++#define dma_ring_incr(n, s)		(((n) + 1) & ((s) - 1))
++#define dma_cnt(n)			((n) >> DESC_BYTE_SHIFT)
++#define dma_byte(n)			((n) << DESC_BYTE_SHIFT)
++
++#define RSS_HASH_KEY_SIZE		4
++#define RSS_INDIRECTION_TABLE_SIZE	128
++#define RSS_NUM_RXQS		4
++
++#define HW_CAP_TSO			BIT(0)
++#define HW_CAP_RXCSUM			BIT(1)
++#define HW_CAP_CCI			BIT(2)
++#define HAS_CAP_TSO(hw_cap)		((hw_cap) & HW_CAP_TSO)
++#define HAS_CAP_RXCSUM(hw_cap)		((hw_cap) & HW_CAP_RXCSUM)
++#define HAS_CAP_CCI(hw_cap)		((hw_cap) & HW_CAP_CCI)
++
++#if defined(CONFIG_HIGMAC_DESC_4WORD)
++struct higmac_desc {
++	unsigned int data_buff_addr;
++
++	unsigned int buffer_len:11;
++#if defined(CONFIG_HIGMAC_RXCSUM)
++	unsigned int reserve2:1;
++	unsigned int payload_csum_err:1;
++	unsigned int header_csum_err:1;
++	unsigned int payload_csum_done:1;
++	unsigned int header_csum_done:1;
++#else
++	unsigned int reserve2:5;
++#endif
++	unsigned int data_len:11;
++	unsigned int reserve1:2;
++	unsigned int fl:2;
++	unsigned int descvid:1;
++
++	unsigned int rxhash;
++	unsigned int reserve3:8;
++	unsigned int l3_hash:1;
++	unsigned int has_hash:1;
++	unsigned int skb_id:14;
++	unsigned int reserve31:8;
++};
++
++struct higmac_tso_desc {
++	unsigned int data_buff_addr;
++	union {
++		struct {
++			unsigned int prot_hdr_len:4;
++			unsigned int ip_hdr_len:4;
++			unsigned int prot_type:1;
++			unsigned int ip_ver:1;
++			unsigned int vlan_flag:1;
++			unsigned int nfrags_num:5;
++			unsigned int data_len:11;
++			unsigned int reservel:1;
++			unsigned int tso_flag:1;
++			unsigned int coe_flag:1;
++			unsigned int sg_flag:1;
++			unsigned int hw_own:1;
++		} tx;
++		unsigned int val;
++	} desc1;
++	unsigned int reserve_desc2;
++	unsigned int tx_err;
++};
++#else
++struct higmac_desc {
++	unsigned int data_buff_addr;
++
++	unsigned int buffer_len:11;
++#if defined(CONFIG_HIGMAC_RXCSUM)
++	unsigned int reserve2:1;
++	unsigned int payload_csum_err:1;
++	unsigned int header_csum_err:1;
++	unsigned int payload_csum_done:1;
++#else
++	unsigned int reserve2:5;
++#endif
++	unsigned int data_len:11;
++	unsigned int reserve1:2;
++	unsigned int fl:2;
++	unsigned int descvid:1;
++
++	unsigned int rxhash;
++	unsigned int reserve3:8;
++	unsigned int l3_hash:1;
++	unsigned int has_hash:1;
++	unsigned int skb_id:14;
++	unsigned int reserve31:8;
++
++	unsigned int reserve4;
++	unsigned int reserve5;
++	unsigned int reserve6;
++	unsigned int reserve7;
++};
++
++struct higmac_tso_desc {
++	unsigned int data_buff_addr;
++	union {
++		struct {
++			unsigned int prot_hdr_len:4;
++			unsigned int ip_hdr_len:4;
++			unsigned int prot_type:1;
++			unsigned int ip_ver:1;
++			unsigned int vlan_flag:1;
++			unsigned int nfrags_num:5;
++			unsigned int data_len:11;
++			unsigned int reservel:1;
++			unsigned int tso_flag:1;
++			unsigned int coe_flag:1;
++			unsigned int sg_flag:1;
++			unsigned int hw_own:1;
++		} tx;
++		unsigned int val;
++	} desc1;
++	unsigned int reserve_desc2;
++	unsigned int reserve3;
++
++	unsigned int tx_err;
++	unsigned int reserve5;
++	unsigned int reserve6;
++	unsigned int reserve7;
++};
++#endif
++
++#define SKB_MAGIC	((struct sk_buff *)0x5a)
++
++struct higmac_napi {
++	struct napi_struct napi;
++	struct higmac_netdev_local *ndev_priv;
++	int rxq_id;
++};
++
++struct higmac_rss_info {
++	u32 hash_cfg;
++	u32 ind_tbl_size;
++	u8 ind_tbl[RSS_INDIRECTION_TABLE_SIZE];
++	u8 key[RSS_HASH_KEY_SIZE];
++};
++
++#define QUEUE_NUMS	(4)
++struct higmac_netdev_local {
++#define HIGMAC_SG_DESC_ADD	(64U)
++	struct sg_desc *dma_sg_desc ____cacheline_aligned;
++	dma_addr_t dma_sg_phy;
++	unsigned int sg_head;
++	unsigned int sg_tail;
++	unsigned int sg_count;
++
++	void __iomem *gmac_iobase;
++	void __iomem *macif_base;
++	int index;		/* 0 -- mac0, 1 -- mac1 */
++
++	u32 hw_cap;
++	bool tso_supported;
++	bool has_rxhash_cap;
++	bool has_rss_cap;
++	int num_rxqs;
++	struct higmac_napi q_napi[RSS_NUM_RXQS];
++	int irq[RSS_NUM_RXQS];
++	struct higmac_rss_info rss_info;
++
++	struct reset_control *port_rst;
++	struct reset_control *macif_rst;
++	struct reset_control *phy_rst;
++
++	struct {
++		struct higmac_desc *desc;
++		dma_addr_t phys_addr;
++		int *sg_desc_offset;
++
++		/* how many desc in the desc pool */
++		unsigned int count;
++		struct sk_buff **skb;
++
++		/* sizeof(desc) * count */
++		unsigned int size;
++	} pool[QUEUE_NUMS + RSS_NUM_RXQS - 1];
++#define rx_fq		pool[0]
++#define rx_bq		pool[1]
++#define tx_bq		pool[2]
++#define tx_rq		pool[3]
++
++	struct sk_buff **tx_skb;
++	struct sk_buff **rx_skb;
++
++	struct device *dev;
++	struct net_device *netdev;
++	struct clk *clk;
++	struct clk *macif_clk;
++
++	struct higmac_adapter *adapter;
++
++	struct timer_list monitor;
++
++	char phy_name[MII_BUS_ID_SIZE];
++	struct phy_device *phy;
++	struct device_node *phy_node;
++	phy_interface_t phy_mode;
++	bool autoeee;
++	bool internal_phy;
++	int (*eee_init)(struct phy_device *phy_dev);
++
++	unsigned int flow_ctrl;
++	unsigned int pause;
++	unsigned int pause_interval;
++	unsigned int flow_ctrl_active_threshold;
++	unsigned int flow_ctrl_deactive_threshold;
++
++	int old_link;
++	int old_speed;
++	int old_duplex;
++
++	/* receive packet lock */
++	spinlock_t rxlock;
++	/* transmit packet lock */
++	spinlock_t txlock;
++	/* power management lock */
++	spinlock_t pmtlock;
++
++	int dev_state;		/* INIT/OPEN/CLOSE */
++	char pm_state;
++	bool wol_enable;
++	u32 msg_enable;
++#define INIT			(0)	/* power off gmac */
++#define OPEN			(1)	/* power on gmac */
++#define CLOSE			(2)	/* power off gmac */
++};
++
++enum tso_version {
++	VER_NO_TSO = 0x0,
++	VER_BYTE_SPLICE = 0x1,
++	VER_SG_COE = 0x2,
++	VER_TSO = 0x3,
++};
++
++#ifdef HIGMAC_TSO_DEBUG
++#define MAX_RECORD	(100)
++struct send_pkt_info {
++	struct higmac_tso_desc desc;
++	int status;
++};
++#endif
++
++int higmac_tx_avail(struct higmac_netdev_local *ld);
++
++/* board related func */
++void higmac_mac_core_reset(struct higmac_netdev_local *priv);
++void higmac_hw_internal_phy_reset(struct higmac_netdev_local *priv);
++void higmac_hw_external_phy_reset(struct higmac_netdev_local *priv);
++void higmac_internal_phy_clk_disable(struct higmac_netdev_local *priv);
++void higmac_internal_phy_clk_enable(struct higmac_netdev_local *priv);
++void higmac_hw_all_clk_disable(struct higmac_netdev_local *priv);
++void higmac_hw_all_clk_enable(struct higmac_netdev_local *priv);
++
++/* board independent func */
++void higmac_hw_phy_reset(struct higmac_netdev_local *priv);
++
++void pmt_reg_restore(struct higmac_netdev_local *ld);
++#endif
+diff --git a/drivers/net/ethernet/hisilicon/higmac/pm.c b/drivers/net/ethernet/hisilicon/higmac/pm.c
+new file mode 100644
+index 0000000..7620abe
+--- /dev/null
++++ b/drivers/net/ethernet/hisilicon/higmac/pm.c
+@@ -0,0 +1,359 @@
++#include <linux/crc16.h>
++#include "higmac.h"
++
++#define N			(31)
++#define FILTERS			(4)
++struct pm_config {
++	unsigned char index;	/* bit0--eth0 bit1--eth1 */
++	unsigned char uc_pkts_enable;
++	unsigned char magic_pkts_enable;
++	unsigned char wakeup_pkts_enable;
++	struct {
++		unsigned int mask_bytes:N;
++		unsigned int reserved:1;	/* userspace ignore this bit */
++		unsigned char offset;	/* >= 12 */
++		unsigned char value[N];	/* byte string */
++		unsigned char valid;	/* valid filter */
++	} filter[FILTERS];
++};
++
++struct pm_reg_config {
++	unsigned int pmt_ctrl;
++	unsigned int pmt_mask0;
++	unsigned int pmt_mask1;
++	unsigned int pmt_mask2;
++	unsigned int pmt_mask3;
++	unsigned int pmt_cmd;
++	unsigned int pmt_offset;
++	unsigned int pmt_crc1_0;
++	unsigned int pmt_crc3_2;
++};
++
++struct pm_reg_config pm_reg_config_backup;
++
++#define PMT_CTRL		0xa00
++#define PMT_MASK0		0xa04
++#define PMT_MASK1		0xa08
++#define PMT_MASK2		0xa0c
++#define PMT_MASK3		0xa10
++#define PMT_CMD			0xa14
++#define PMT_OFFSET		0xa18
++#define PMT_CRC1_0		0xa1c
++#define PMT_CRC3_2		0xa20
++#define MASK_INVALID_BIT	BIT(31)
++
++static void init_crc_table(void);
++static unsigned short compute_crc(char *message, int nbytes);
++static unsigned short calculate_crc16(char *buf, unsigned int mask)
++{
++	char data[N];
++	int i, len = 0;
++
++	memset(data, 0, sizeof(data));
++
++	for (i = 0; i < N; i++) {
++		if (mask & 0x1)
++			data[len++] = buf[i];
++
++		mask >>= 1;
++	}
++
++	return compute_crc(data, len);
++}
++
++/* use this func in config pm func */
++void _pmt_reg_backup(struct higmac_netdev_local *ld)
++{
++	pm_reg_config_backup.pmt_ctrl = readl(ld->gmac_iobase + PMT_CTRL);
++	pm_reg_config_backup.pmt_mask0 = readl(ld->gmac_iobase + PMT_MASK0);
++	pm_reg_config_backup.pmt_mask1 = readl(ld->gmac_iobase + PMT_MASK1);
++	pm_reg_config_backup.pmt_mask2 = readl(ld->gmac_iobase + PMT_MASK2);
++	pm_reg_config_backup.pmt_mask3 = readl(ld->gmac_iobase + PMT_MASK3);
++	pm_reg_config_backup.pmt_cmd = readl(ld->gmac_iobase + PMT_CMD);
++	pm_reg_config_backup.pmt_offset = readl(ld->gmac_iobase + PMT_OFFSET);
++	pm_reg_config_backup.pmt_crc1_0 = readl(ld->gmac_iobase + PMT_CRC1_0);
++	pm_reg_config_backup.pmt_crc3_2 = readl(ld->gmac_iobase + PMT_CRC3_2);
++}
++
++#define	PM_SET			(1)
++#define PM_CLEAR		(0)
++
++int pmt_config_gmac(struct pm_config *config, struct higmac_netdev_local *ld)
++{
++	unsigned int v = 0, cmd = 0, offset = 0;
++	unsigned short crc[FILTERS] = { 0 };
++	unsigned long flags;
++	int reg_mask = 0;
++	int i;
++
++	if (!ld)
++		return -EINVAL;
++
++	spin_lock_irqsave(&ld->pmtlock, flags);
++	if (config->wakeup_pkts_enable) {
++		/* disable wakeup_pkts_enable before reconfig? */
++		v = readl(ld->gmac_iobase + PMT_CTRL);
++		v &= ~BIT(2);
++		writel(v, ld->gmac_iobase + PMT_CTRL);	/* any side effect? */
++	} else {
++		goto config_ctrl;
++	}
++
++/* filter.valid		mask.valid	mask_bytes	effect
++ *	0		*		*		no use the filter
++ *	1		0		*	all pkts can wake-up(non-exist)
++ *	1		1		0		all pkts can wake-up
++ *	1		1		!0		normal filter
++ */
++	/* setup filter */
++	for (i = 0; i < FILTERS; i++) {
++		if (config->filter[i].valid) {
++			if (config->filter[i].offset < 12)
++				continue;
++			/* offset and valid bit */
++			offset |= config->filter[i].offset << (i * 8);
++			cmd |= BIT(i * 8);	/* valid bit */
++			/* mask */
++			reg_mask = PMT_MASK0 + (i * 4);
++
++			/* for logic, mask valid bit(bit31) must set to 0,
++			 * 0 is enable
++			 */
++			v = config->filter[i].mask_bytes;
++			v &= ~BIT(31);
++			writel(v, ld->gmac_iobase + reg_mask);
++
++			/* crc */
++			crc[i] = calculate_crc16(config->filter[i].value, v);
++			if (i <= 1) {	/* for filter0 and filter 1 */
++				v = readl(ld->gmac_iobase + PMT_CRC1_0);
++				v &= ~(0xFFFF << (16 * i));
++				v |= crc[i] << (16 * i);
++				writel(v, ld->gmac_iobase + PMT_CRC1_0);
++			} else {	/* filter2 and filter3 */
++				v = readl(ld->gmac_iobase + PMT_CRC3_2);
++				v &= ~(0xFFFF << (16 * (i - 2)));
++				v |= crc[i] << (16 * (i - 2));
++				writel(v, ld->gmac_iobase + PMT_CRC3_2);
++			}
++		}
++	}
++
++	if (cmd) {
++		writel(offset, ld->gmac_iobase + PMT_OFFSET);
++		writel(cmd, ld->gmac_iobase + PMT_CMD);
++	}
++
++config_ctrl:
++	v = 0;
++	if (config->uc_pkts_enable)
++		v |= BIT(9);	/* uc pkts wakeup */
++	if (config->wakeup_pkts_enable)
++		v |= BIT(2);	/* use filter framework */
++	if (config->magic_pkts_enable)
++		v |= BIT(1);	/* magic pkts wakeup */
++
++	v |= 3 << 5;		/* clear irq status */
++	writel(v, ld->gmac_iobase + PMT_CTRL);
++
++	_pmt_reg_backup(ld);
++
++	spin_unlock_irqrestore(&ld->pmtlock, flags);
++
++	return 0;
++}
++
++/* pmt_config will overwrite pre-config */
++int pmt_config(struct net_device *ndev, struct pm_config *config)
++{
++	static int init;
++	int ret = -EINVAL;
++	struct higmac_netdev_local *priv = netdev_priv(ndev);
++
++	if (!init)
++		init_crc_table();
++
++	ret = pmt_config_gmac(config, priv);
++	if (ret)
++		return ret;
++
++	priv->pm_state = PM_SET;
++	priv->wol_enable = true;
++	device_set_wakeup_enable(priv->dev, 1);
++
++	return ret;
++}
++
++inline bool pmt_enter(struct higmac_netdev_local *ld)
++{
++	int pm = false;
++	unsigned long flags;
++
++	spin_lock_irqsave(&ld->pmtlock, flags);
++	if (ld->pm_state == PM_SET) {
++		int v;
++
++		v = readl(ld->gmac_iobase + PMT_CTRL);
++		v |= BIT(0);	/* enter power down */
++		v |= BIT(3);	/* enable wakeup irq */
++		v |= 3 << 5;	/* clear irq status */
++		writel(v, ld->gmac_iobase + PMT_CTRL);
++
++		ld->pm_state = PM_CLEAR;
++		pm = true;
++	}
++	spin_unlock_irqrestore(&ld->pmtlock, flags);
++	return pm;
++}
++
++inline void pmt_exit(struct higmac_netdev_local *ld)
++{
++	int v;
++	unsigned long flags;
++
++	/* logic auto exit power down mode */
++	spin_lock_irqsave(&ld->pmtlock, flags);
++
++	v = readl(ld->gmac_iobase + PMT_CTRL);
++	v &= ~BIT(0);		/* enter power down */
++	v &= ~BIT(3);		/* enable wakeup irq */
++
++	v |= 3 << 5;		/* clear irq status */
++	writel(v, ld->gmac_iobase + PMT_CTRL);
++
++	spin_unlock_irqrestore(&ld->pmtlock, flags);
++
++	ld->wol_enable = false;
++	/* device_set_wakeup_enable(ld->dev, 0); */
++}
++
++void pmt_reg_restore(struct higmac_netdev_local *ld)
++{
++	unsigned int v;
++	unsigned long flags;
++
++	spin_lock_irqsave(&ld->pmtlock, flags);
++	v = pm_reg_config_backup.pmt_mask0;
++	writel(v, ld->gmac_iobase + PMT_MASK0);
++
++	v = pm_reg_config_backup.pmt_mask1;
++	writel(v, ld->gmac_iobase + PMT_MASK1);
++
++	v = pm_reg_config_backup.pmt_mask2;
++	writel(v, ld->gmac_iobase + PMT_MASK2);
++
++	v = pm_reg_config_backup.pmt_mask3;
++	writel(v, ld->gmac_iobase + PMT_MASK3);
++
++	v = pm_reg_config_backup.pmt_cmd;
++	writel(v, ld->gmac_iobase + PMT_CMD);
++
++	v = pm_reg_config_backup.pmt_offset;
++	writel(v, ld->gmac_iobase + PMT_OFFSET);
++
++	v = pm_reg_config_backup.pmt_crc1_0;
++	writel(v, ld->gmac_iobase + PMT_CRC1_0);
++
++	v = pm_reg_config_backup.pmt_crc3_2;
++	writel(v, ld->gmac_iobase + PMT_CRC3_2);
++
++	v = pm_reg_config_backup.pmt_ctrl;
++	writel(v, ld->gmac_iobase + PMT_CTRL);
++	spin_unlock_irqrestore(&ld->pmtlock, flags);
++}
++
++/* ========the following code copy from Synopsys DWC_gmac_crc_example.c====== */
++#define CRC16			/* Change it to CRC16 for CRC16 Computation */
++
++#if defined(CRC16)
++#define CRC_NAME		"CRC-16"
++#define POLYNOMIAL		0x8005
++#define INITIAL_REMAINDER	0xFFFF
++#define FINAL_XOR_VALUE		0x0000
++#define REVERSE_DATA
++#undef REVERSE_REMAINDER
++#endif
++
++#define WIDTH    (8 * sizeof(unsigned short))
++#define TOPBIT   BIT(WIDTH - 1)
++
++#ifdef REVERSE_DATA
++#undef  REVERSE_DATA
++#define REVERSE_DATA(X)		((unsigned char)reverse((X), 8))
++#else
++#undef  REVERSE_DATA
++#define REVERSE_DATA(X)		(X)
++#endif
++
++#ifdef REVERSE_REMAINDER
++#undef  REVERSE_REMAINDER
++#define REVERSE_REMAINDER(X)	((unsigned short)reverse((X), WIDTH))
++#else
++#undef  REVERSE_REMAINDER
++#define REVERSE_REMAINDER(X)	(X)
++#endif
++
++static unsigned short crc_table[256];
++
++/* Reverse the data
++ * Input1: Data to be reversed
++ * Input2: number of bits in the data
++ * Output: The reversed data
++ */
++static unsigned int reverse(unsigned int data, unsigned char nbits)
++{
++	unsigned int reversed = 0x00000000;
++	unsigned char bit;
++
++	/* Reverse the data about the center bit. */
++	for (bit = 0; bit < nbits; ++bit) {
++		/* If the LSB bit is set, set the reflection of it. */
++		if (data & 0x01)
++			reversed |= BIT((nbits - 1) - bit);
++
++		data = (data >> 1);
++	}
++	return reversed;
++}
++
++/* This Initializes the partial CRC look up table */
++static void init_crc_table(void)
++{
++	unsigned short remainder;
++	int dividend;
++	unsigned char bit;
++
++	/* Compute the remainder of each possible dividend. */
++	for (dividend = 0; dividend < 256; ++dividend) {
++		/* Start with the dividend followed by zeros. */
++		remainder = (unsigned short)(dividend << (WIDTH - 8));
++
++		/* Perform modulo-2 division, a bit at a time. */
++		for (bit = 8; bit > 0; --bit) {
++			/* Try to divide the current data bit. */
++			if (remainder & TOPBIT)
++				remainder = (remainder << 1) ^ POLYNOMIAL;
++			else
++				remainder = (remainder << 1);
++		}
++
++		/* Store the result into the table. */
++		crc_table[dividend] = remainder;
++	}
++}
++
++static unsigned short compute_crc(char *message, int nbytes)
++{
++	unsigned short remainder = INITIAL_REMAINDER;
++	int byte;
++	unsigned char data;
++
++	/* Divide the message by the polynomial, a byte at a time. */
++	for (byte = 0; byte < nbytes; ++byte) {
++		data = REVERSE_DATA(message[byte]) ^ (remainder >> (WIDTH - 8));
++		remainder = crc_table[data] ^ (remainder << 8);
++	}
++
++	/* The final remainder is the CRC. */
++	return (REVERSE_REMAINDER(remainder) ^ FINAL_XOR_VALUE);
++}
+diff --git a/drivers/net/ethernet/hisilicon/higmac/proc-dev.c b/drivers/net/ethernet/hisilicon/higmac/proc-dev.c
+new file mode 100644
+index 0000000..d522565
+--- /dev/null
++++ b/drivers/net/ethernet/hisilicon/higmac/proc-dev.c
+@@ -0,0 +1,111 @@
++#include "sockioctl.h"
++
++/* debug code */
++static int set_suspend(int eth_n)
++{
++	return 0;
++}
++
++/* debug code */
++static int set_resume(int eth_n)
++{
++	/* higmac_dev_driver.resume(&higmac_platform_device); */
++	return 0;
++}
++
++static int hw_states_read(struct seq_file *m, void *v)
++{
++	return 0;
++}
++
++static struct proc_dir_entry *higmac_proc_root;
++
++#define proc_open(name)	\
++static int proc_open_##name(struct inode *inode, struct file *file) \
++{ \
++	return single_open(file, name, PDE_DATA(inode)); \
++} \
++
++proc_open(hw_states_read);
++
++static struct proc_file {
++	char *name;
++	const struct file_operations ops;
++
++} proc_file[] = {
++	{
++		.name = "hw_stats",
++		.ops = {
++			.open           = proc_open_hw_states_read,
++			.read           = seq_read,
++			.llseek         = seq_lseek,
++			.release        = single_release,
++		},
++	}
++};
++
++/* /proc/higmac/
++ *	|---hw_stats
++ *	|---skb_pools
++ */
++void higmac_proc_create(void)
++{
++	int i;
++
++	higmac_proc_root = proc_mkdir("higmac", NULL);
++	if (!higmac_proc_root)
++		return;
++
++	for (i = 0; i < ARRAY_SIZE(proc_file); i++) {
++		struct proc_dir_entry *entry;
++
++		entry = proc_create(proc_file[i].name, 0000, higmac_proc_root,
++				    &proc_file[i].ops);
++		if (!entry)
++			pr_err("failed to create %s\n", proc_file[i].name);
++	}
++}
++
++void higmac_proc_destroy(void)
++{
++	int i;
++
++	for (i = 0; i < ARRAY_SIZE(proc_file); i++)
++		remove_proc_entry(proc_file[i].name, higmac_proc_root);
++
++	remove_proc_entry("higmac", NULL);
++}
++
++int higmac_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
++{
++	struct higmac_netdev_local *priv = netdev_priv(ndev);
++	struct pm_config pm_config;
++	int val = 0;
++
++	switch (cmd) {
++	case SIOCSETPM:
++		if (copy_from_user(&pm_config, rq->ifr_data, sizeof(pm_config)))
++			return -EFAULT;
++		return pmt_config(ndev, &pm_config);
++
++	case SIOCSETSUSPEND:
++		if (copy_from_user(&val, rq->ifr_data, sizeof(val)))
++			return -EFAULT;
++		return set_suspend(val);
++
++	case SIOCSETRESUME:
++		if (copy_from_user(&val, rq->ifr_data, sizeof(val)))
++			return -EFAULT;
++		return set_resume(val);
++
++	default:
++		if (!netif_running(ndev))
++			return -EINVAL;
++
++		if (!priv->phy)
++			return -EINVAL;
++
++		return phy_mii_ioctl(priv->phy, rq, cmd);
++	}
++	return 0;
++}
+diff --git a/drivers/net/ethernet/hisilicon/higmac/sockioctl.h b/drivers/net/ethernet/hisilicon/higmac/sockioctl.h
+new file mode 100644
+index 0000000..571c71a
+--- /dev/null
++++ b/drivers/net/ethernet/hisilicon/higmac/sockioctl.h
+@@ -0,0 +1,12 @@
++#ifndef _SOCKIOCTL_H_
++#define _SOCKIOCTL_H_
++
++#include <linux/sockios.h>
++
++#define SIOCSETPM	(SIOCDEVPRIVATE + 4)	/* set pmt wake up config */
++#define SIOCSETSUSPEND	(SIOCDEVPRIVATE + 5)	/* call dev->suspend, debug */
++#define SIOCSETRESUME	(SIOCDEVPRIVATE + 6)	/* call dev->resume, debug */
++
++int higmac_ioctl(struct net_device *net_dev, struct ifreq *rq, int cmd);
++
++#endif
+diff --git a/drivers/net/ethernet/hisilicon/higmac/tso.h b/drivers/net/ethernet/hisilicon/higmac/tso.h
+new file mode 100644
+index 0000000..6416eef
+--- /dev/null
++++ b/drivers/net/ethernet/hisilicon/higmac/tso.h
+@@ -0,0 +1,53 @@
++#ifndef __HIETH_TSO_H
++#define __HIETH_TSO_H
++
++#define SG_FLAG		BIT(30)
++#define COE_FLAG	BIT(29)
++#define TSO_FLAG	BIT(28)
++#define VLAN_FLAG	BIT(10)
++#define IPV6_FLAG	BIT(9)
++#define UDP_FLAG	BIT(8)
++
++#define PKT_IPV6_HDR_LEN	10
++#define PKT_UDP_HDR_LEN		2
++#define WORD_TO_BYTE		4
++enum {
++	PKT_NORMAL,
++	PKT_SG
++};
++
++enum {
++	PKT_IPV4,
++	PKT_IPV6
++};
++
++enum {
++	PKT_TCP,
++	PKT_UDP
++};
++
++struct frags_info {
++	/* Word(2*i+2) */
++	u32 addr;
++	/* Word(2*i+3) */
++	u32 size:16;
++	u32 reserved:16;
++};
++
++struct sg_desc {
++	/* Word0 */
++	u32 total_len:17;
++	u32 reserv:15;
++	/* Word1 */
++	u32 ipv6_id;
++	/* Word2 */
++	u32 linear_addr;
++	/* Word3 */
++	u32 linear_len:16;
++	u32 reserv3:16;
++	/* MAX_SKB_FRAGS = 17 */
++	struct frags_info frags[18];
++	/* struct frags_info frags[MAX_SKB_FRAGS]; */
++};
++
++#endif
+diff --git a/drivers/net/ethernet/hisilicon/higmac/util.h b/drivers/net/ethernet/hisilicon/higmac/util.h
+new file mode 100644
+index 0000000..f08cbf6
+--- /dev/null
++++ b/drivers/net/ethernet/hisilicon/higmac/util.h
+@@ -0,0 +1,29 @@
++#ifndef __HIGMAC_UTIL_H__
++#define __HIGMAC_UTIL_H__
++
++#define HIGMAC_TRACE_LEVEL 10
++
++#define higmac_trace(level, msg...) do { \
++	if ((level) >= HIGMAC_TRACE_LEVEL) { \
++		pr_info("higmac_trace:%s:%d: ", __FILE__, __LINE__); \
++		printk(msg); \
++		printk("\n"); \
++	} \
++} while (0)
++
++#define higmac_error(args...) do { \
++	pr_err("higmac:%s:%d: ", __FILE__, __LINE__); \
++	printk(args); \
++	printk("\n"); \
++} while (0)
++
++#define higmac_assert(cond) do { \
++	if (!(cond)) \
++		pr_alert("Assert:higmac:%s:%d\n", \
++			__FILE__, \
++			__LINE__);\
++} while (0)
++
++#define MK_BITS(shift, nbits) ((((shift) & 0x1F) << 16) | ((nbits) & 0x3F))
++
++#endif
+diff --git a/drivers/net/ethernet/hisilicon/hisi_femac.c b/drivers/net/ethernet/hisilicon/hisi_femac.c
+new file mode 100644
+index 0000000..2257832
+--- /dev/null
++++ b/drivers/net/ethernet/hisilicon/hisi_femac.c
+@@ -0,0 +1,1705 @@
++/*
++ * Hisilicon Fast Ethernet MAC Driver
++ *
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <linux/circ_buf.h>
++#include <linux/clk.h>
++#include <linux/etherdevice.h>
++#include <linux/if_ether.h>
++#include <linux/if_vlan.h>
++#include <linux/ip.h>
++#include <linux/interrupt.h>
++#include <linux/module.h>
++#include <linux/of_mdio.h>
++#include <linux/of_net.h>
++#include <linux/platform_device.h>
++#include <linux/reset.h>
++#include <linux/tcp.h>
++#include <net/ipv6.h>
++#include <net/protocol.h>
++
++/* MAC control register list */
++#define MAC_PORTSEL			0x0200
++#define MAC_PORTSEL_STAT_CPU		BIT(0)
++#define MAC_PORTSEL_RMII		BIT(1)
++#define MAC_PORTSET			0x0208
++#define MAC_PORTSET_DUPLEX_FULL		BIT(0)
++#define MAC_PORTSET_LINKED		BIT(1)
++#define MAC_PORTSET_SPEED_100M		BIT(2)
++#define MAC_SET				0x0210
++#define MAX_FRAME_SIZE			1600
++#define MAX_FRAME_SIZE_MASK		GENMASK(10, 0)
++#define BIT_PAUSE_EN			BIT(18)
++#define RX_COALESCE_SET			0x0340
++#define RX_COALESCED_FRAME_OFFSET	24
++#define RX_COALESCED_FRAMES		8
++#define RX_COALESCED_TIMER		0x74
++#define QLEN_SET			0x0344
++#define RX_DEPTH_OFFSET			8
++#define MAX_HW_FIFO_DEPTH		64
++#define HW_TX_FIFO_DEPTH		12
++#define HW_RX_FIFO_DEPTH		(MAX_HW_FIFO_DEPTH - HW_TX_FIFO_DEPTH)
++#define FC_LEVEL			0x0348
++#define BITS_FC_ACTIVE_THR_OFFSET	8
++#define FC_DEACTIVE_THR_MASK		GENMASK(5, 0)
++#define FC_ACTIVE_THR_MASK		GENMASK(13, 8)
++#define BIT_FC_EN			BIT(14)
++#define IQFRM_DES			0x0354
++#define RX_FRAME_LEN_MASK		GENMASK(11, 0)
++#define BITS_PAYLOAD_ERR_OFFSET		28
++#define BITS_PAYLOAD_ERR_MASK		0x1
++#define BITS_HEADER_ERR_OFFSET		29
++#define BITS_HEADER_ERR_MASK		0x1
++#define BITS_PAYLOAD_DONE_OFFSET	30
++#define BITS_PAYLOAD_DONE_MASK		0x1
++#define BITS_HEADER_DONE_OFFSET		31
++#define BITS_HEADER_DONE_MASK		0x1
++#define IQ_ADDR				0x0358
++#define EQ_ADDR				0x0360
++#define EQFRM_LEN			0x0364
++#define ADDRQ_STAT			0x036C
++#define TX_CNT_INUSE_MASK		GENMASK(5, 0)
++#define BIT_TX_READY			BIT(24)
++#define BIT_RX_READY			BIT(25)
++#define RX_COE_CTRL			0x0380
++#define BIT_COE_IPV6_UDP_ZERO_DROP	BIT(13)
++#define BIT_COE_PAYLOAD_DROP		BIT(14)
++#define BIT_COE_IPHDR_DROP		BIT(15)
++#define COE_ERR_DROP			(BIT_COE_IPHDR_DROP | \
++					BIT_COE_PAYLOAD_DROP | \
++					BIT_COE_IPV6_UDP_ZERO_DROP)
++#define TSO_DBG_EN			0x03A4
++#define BITS_TSO_DBG_EN			BIT(31)
++#define TSO_DBG_STATE			0x03A8
++#define TSO_DBG_ADDR			0x03AC
++#define TSO_DBG_TX_INFO			0x03B0
++#define TSO_DBG_TX_ERR			0x03B4
++/* global control register list */
++#define GLB_HOSTMAC_L32			0x0000
++#define GLB_HOSTMAC_H16			0x0004
++#define GLB_SOFT_RESET			0x0008
++#define SOFT_RESET_ALL			BIT(0)
++#define GLB_FWCTRL			0x0010
++#define FWCTRL_VLAN_ENABLE		BIT(0)
++#define FWCTRL_FW2CPU_ENA		BIT(5)
++#define FWCTRL_FWALL2CPU		BIT(7)
++#define GLB_MACTCTRL			0x0014
++#define MACTCTRL_UNI2CPU		BIT(1)
++#define MACTCTRL_MULTI2CPU		BIT(3)
++#define MACTCTRL_BROAD2CPU		BIT(5)
++#define MACTCTRL_MACT_ENA		BIT(7)
++#define GLB_IRQ_STAT			0x0030
++#define GLB_IRQ_ENA			0x0034
++#define IRQ_ENA_PORT0_MASK		GENMASK(7, 0)
++#define IRQ_ENA_PORT0			BIT(18)
++#define IRQ_ENA_ALL			BIT(19)
++#define GLB_IRQ_RAW			0x0038
++#define IRQ_INT_RX_RDY			BIT(0)
++#define IRQ_INT_TX_PER_PACKET		BIT(1)
++#define IRQ_INT_TX_FIFO_EMPTY		BIT(6)
++#define IRQ_INT_MULTI_RXRDY		BIT(7)
++#define INT_TX_ERR			BIT(8)
++#define DEF_INT_MASK			(IRQ_INT_MULTI_RXRDY | \
++					IRQ_INT_TX_PER_PACKET | \
++					IRQ_INT_TX_FIFO_EMPTY)
++#define GLB_MAC_L32_BASE		0x0100
++#define GLB_MAC_H16_BASE		0x0104
++#define MACFLT_HI16_MASK		GENMASK(15, 0)
++#define BIT_MACFLT_ENA			BIT(17)
++#define BIT_MACFLT_FW2CPU		BIT(21)
++#define GLB_MAC_H16(reg)		(GLB_MAC_H16_BASE + ((reg) * 0x8))
++#define GLB_MAC_L32(reg)		(GLB_MAC_L32_BASE + ((reg) * 0x8))
++#define MAX_MAC_FILTER_NUM		8
++#define MAX_UNICAST_ADDRESSES		2
++#define MAX_MULTICAST_ADDRESSES		(MAX_MAC_FILTER_NUM - \
++					MAX_UNICAST_ADDRESSES)
++/* software tx and rx queue number, should be power of 2 */
++#define TXQ_NUM				64
++#define RXQ_NUM				128
++#define FEMAC_POLL_WEIGHT		16
++#define HW_CAP_TSO			BIT(0)
++#define HW_CAP_RXCSUM			BIT(1)
++#define HAS_TSO_CAP(hw_cap)		((hw_cap) & HW_CAP_TSO)
++#define HAS_RXCSUM_CAP(hw_cap)		((hw_cap) & HW_CAP_RXCSUM)
++#define RXBUF_ADDR_ALIGN_SIZE		64UL
++/* UDP header len is 2 word */
++#define UDP_HDR_LEN			2
++/* IPv6 header len is 10 word */
++#define IPV6_HDR_LEN			10
++#define WORD_TO_BYTE			4
++
++#define BIT_OFFSET_NFRAGS_NUM		11
++#define BIT_OFFSET_PROT_HEADER_LEN	16
++#define BIT_OFFSET_IP_HEADER_LEN	20
++#define BIT_FLAG_SG			BIT(26)
++#define BIT_FLAG_TXCSUM			BIT(27)
++#define BIT_FLAG_UDP			BIT(28)
++#define BIT_FLAG_IPV6			BIT(29)
++#define BIT_FLAG_VLAN			BIT(30)
++#define BIT_FLAG_TSO			BIT(31)
++
++#define PHY_RESET_DELAYS_PROPERTY	"hisilicon,phy-reset-delays-us"
++
++/* The threshold for activing tx flow ctrl.
++ * When the left amount of receive queue descriptors is below this threshold,
++ * hardware will send pause frame immediately.
++ * We advise this value is set between 1 and 10.
++ * Too bigger is not a good choice.
++ * This value must be smaller than tx flow ctrl deactive threshold.
++ */
++#define TX_FLOW_CTRL_ACTIVE_THRESHOLD	3
++/* The threshold for deactiving tx flow ctrl.
++ * When the left amount of receive queue descriptors is
++ * above or equal with this threshold,
++ * hardware will exit flow control state.
++ * We advise this value is set between 1 and 10.
++ * Too bigger is not a good choice.
++ * This value must be larger than tx flow ctrl active threshold.
++ */
++#define TX_FLOW_CTRL_DEACTIVE_THRESHOLD	5
++#define FC_ACTIVE_MIN			1
++#define FC_ACTIVE_DEFAULT		3
++#define FC_ACTIVE_MAX			31
++#define FC_DEACTIVE_MIN			1
++#define FC_DEACTIVE_DEFAULT		5
++#define FC_DEACTIVE_MAX			31
++
++enum phy_reset_delays {
++	PRE_DELAY,
++	PULSE,
++	POST_DELAY,
++	DELAYS_NUM,
++};
++
++struct hisi_femac_queue {
++	struct sk_buff **skb;
++	dma_addr_t *dma_phys;
++	int num;
++	unsigned int head;
++	unsigned int tail;
++};
++
++struct hisi_femac_tx_desc_ring {
++	struct tx_desc *desc;
++	dma_addr_t dma_phys;
++};
++
++struct hisi_femac_priv {
++	void __iomem *port_base;
++	void __iomem *glb_base;
++	struct clk *clk;
++	struct reset_control *mac_rst;
++	struct reset_control *phy_rst;
++	u32 phy_reset_delays[DELAYS_NUM];
++	u32 link_status;
++
++	struct device *dev;
++	struct net_device *ndev;
++
++	u32 hw_cap;
++	struct hisi_femac_queue txq;
++	struct hisi_femac_queue rxq;
++	struct hisi_femac_tx_desc_ring tx_ring;
++	u32 tx_fifo_used_cnt;
++	struct napi_struct napi;
++
++	/* 802.3x flow control */
++	bool tx_pause_en;
++	u32 tx_pause_active_thresh;
++	u32 tx_pause_deactive_thresh;
++};
++
++struct frags_info {
++	/* Word(2*i+2) */
++	u32 addr;
++	/* Word(2*i+3) */
++	u32 size:16;
++	u32 reserved:16;
++};
++
++struct tx_desc {
++	/* Word0 */
++	u32 total_len:17;
++	u32 reserv:15;
++	/* Word1 */
++	u32 ipv6_id;
++	/* Word2 */
++	u32 linear_addr;
++	/* Word3 */
++	u32 linear_len:16;
++	u32 reserv3:16;
++	/* MAX_SKB_FRAGS = 17 */
++	struct frags_info frags[30];
++	/* struct frags_info frags[MAX_SKB_FRAGS]; */
++};
++
++static void hisi_femac_irq_enable(struct hisi_femac_priv *priv, u32 irqs)
++{
++	u32 val;
++
++	val = readl(priv->glb_base + GLB_IRQ_ENA);
++	writel(val | irqs, priv->glb_base + GLB_IRQ_ENA);
++}
++
++static void hisi_femac_irq_disable(struct hisi_femac_priv *priv, u32 irqs)
++{
++	u32 val;
++
++	val = readl(priv->glb_base + GLB_IRQ_ENA);
++	writel(val & (~irqs), priv->glb_base + GLB_IRQ_ENA);
++}
++
++static void hisi_femac_set_flow_ctrl(struct hisi_femac_priv *priv)
++{
++	unsigned int pause_en;
++	unsigned int tx_flow_ctrl;
++
++	tx_flow_ctrl = readl(priv->port_base + FC_LEVEL);
++	tx_flow_ctrl &= ~FC_DEACTIVE_THR_MASK;
++	tx_flow_ctrl |= priv->tx_pause_deactive_thresh;
++	tx_flow_ctrl &= ~FC_ACTIVE_THR_MASK;
++	tx_flow_ctrl |= priv->tx_pause_active_thresh <<
++				BITS_FC_ACTIVE_THR_OFFSET;
++
++	pause_en = readl(priv->port_base + MAC_SET);
++
++	if (priv->tx_pause_en) {
++		tx_flow_ctrl |= BIT_FC_EN;
++		pause_en |= BIT_PAUSE_EN;
++	} else {
++		tx_flow_ctrl &= ~BIT_FC_EN;
++		pause_en &= ~BIT_PAUSE_EN;
++	}
++
++	writel(tx_flow_ctrl, priv->port_base + FC_LEVEL);
++
++	writel(pause_en, priv->port_base + MAC_SET);
++}
++
++static void hisi_femac_tx_sg_dma_unmap(struct hisi_femac_priv *priv,
++				       struct sk_buff *skb, unsigned int pos)
++{
++	struct tx_desc *desc_cur;
++	dma_addr_t addr;
++	u32 len;
++	int i;
++
++	desc_cur = priv->tx_ring.desc + pos;
++
++	addr = desc_cur->linear_addr;
++	len = desc_cur->linear_len;
++	dma_unmap_single(priv->dev, addr, len, DMA_TO_DEVICE);
++
++	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
++		addr = desc_cur->frags[i].addr;
++		len = desc_cur->frags[i].size;
++		dma_unmap_page(priv->dev, addr, len, DMA_TO_DEVICE);
++	}
++}
++
++static void hisi_femac_tx_dma_unmap(struct hisi_femac_priv *priv,
++				    struct sk_buff *skb, unsigned int pos)
++{
++	if (!(skb_is_gso(skb) || skb_shinfo(skb)->nr_frags)) {
++		dma_addr_t dma_addr;
++
++		dma_addr = priv->txq.dma_phys[pos];
++		dma_unmap_single(priv->dev, dma_addr, skb->len, DMA_TO_DEVICE);
++	} else {
++		hisi_femac_tx_sg_dma_unmap(priv, skb, pos);
++	}
++}
++
++static void hisi_femac_xmit_reclaim(struct net_device *dev)
++{
++	struct sk_buff *skb;
++	struct hisi_femac_priv *priv = netdev_priv(dev);
++	struct hisi_femac_queue *txq = &priv->txq;
++	unsigned int bytes_compl = 0, pkts_compl = 0;
++	u32 val;
++
++	netif_tx_lock(dev);
++
++	val = readl(priv->port_base + ADDRQ_STAT) & TX_CNT_INUSE_MASK;
++	while (val < priv->tx_fifo_used_cnt) {
++		skb = txq->skb[txq->tail];
++		if (unlikely(!skb)) {
++			netdev_err(dev, "xmitq_cnt_inuse=%d, tx_fifo_used=%d\n",
++				   val, priv->tx_fifo_used_cnt);
++			break;
++		}
++		hisi_femac_tx_dma_unmap(priv, skb, txq->tail);
++		pkts_compl++;
++		bytes_compl += skb->len;
++		dev_kfree_skb_any(skb);
++
++		priv->tx_fifo_used_cnt--;
++
++		val = readl(priv->port_base + ADDRQ_STAT) & TX_CNT_INUSE_MASK;
++		txq->skb[txq->tail] = NULL;
++		txq->tail = (txq->tail + 1) % txq->num;
++	}
++
++	netdev_completed_queue(dev, pkts_compl, bytes_compl);
++
++	if (unlikely(netif_queue_stopped(dev)) && pkts_compl)
++		netif_wake_queue(dev);
++
++	netif_tx_unlock(dev);
++}
++
++static void hisi_femac_get_tso_err_info(struct hisi_femac_priv *priv)
++{
++	unsigned int reg_addr, reg_tx_info, reg_tx_err;
++	unsigned int sg_index;
++	struct tx_desc *sg_desc;
++	int *sg_word;
++	int i;
++
++	reg_addr = readl(priv->port_base + TSO_DBG_ADDR);
++	reg_tx_info = readl(priv->port_base + TSO_DBG_TX_INFO);
++	reg_tx_err = readl(priv->port_base + TSO_DBG_TX_ERR);
++
++	WARN(1, "tx err=0x%x, tx_info=0x%x, addr=0x%x\n",
++	     reg_tx_err, reg_tx_info, reg_addr);
++
++	sg_index = (reg_addr - priv->tx_ring.dma_phys) / sizeof(struct tx_desc);
++	sg_desc = priv->tx_ring.desc + sg_index;
++	sg_word = (int *)sg_desc;
++	for (i = 0; i < sizeof(struct tx_desc) / sizeof(int); i++)
++		pr_err("%s,%d: sg_desc word[%d]=0x%x\n",
++		       __func__, __LINE__, i, sg_word[i]);
++
++	/* restart MAC to transmit next packet */
++	hisi_femac_irq_disable(priv, INT_TX_ERR);
++	/* The following is recovery code,
++	 * allow netcard transmit packet again.
++	 * But now we disable it for error debug.
++	 */
++#if 0
++	readl(priv->port_base + TSO_DBG_STATE));
++	hisi_femac_irq_enable(priv, INT_TX_ERR);
++#endif
++}
++
++static netdev_tx_t hisi_femac_net_xmit(struct sk_buff *skb,
++				       struct net_device *dev);
++
++static netdev_tx_t hisi_femac_sw_gso(struct sk_buff *skb,
++				     struct net_device *dev)
++{
++	struct sk_buff *segs, *curr_skb;
++	netdev_features_t features = dev->features;
++
++	features &= ~(NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
++			NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_UFO);
++	segs = skb_gso_segment(skb, features);
++	if (IS_ERR_OR_NULL(segs))
++		goto drop;
++
++	do {
++		curr_skb = segs;
++		segs = segs->next;
++		curr_skb->next = NULL;
++		if (hisi_femac_net_xmit(curr_skb, dev)) {
++			dev_kfree_skb(curr_skb);
++			while (segs) {
++				curr_skb = segs;
++				segs = segs->next;
++				curr_skb->next = NULL;
++				dev_kfree_skb_any(curr_skb);
++			}
++			goto drop;
++		}
++	} while (segs);
++
++	dev_kfree_skb_any(skb);
++	return NETDEV_TX_OK;
++
++drop:
++	dev_kfree_skb_any(skb);
++	dev->stats.tx_dropped++;
++	return NETDEV_TX_OK;
++}
++
++static void hisi_femac_do_udp_checksum(struct sk_buff *skb)
++{
++	int offset;
++	__wsum csum;
++	__sum16 udp_csum;
++
++	offset = skb_checksum_start_offset(skb);
++	WARN_ON(offset >= skb_headlen(skb));
++	csum = skb_checksum(skb, offset, skb->len - offset, 0);
++
++	offset += skb->csum_offset;
++	WARN_ON(offset + sizeof(__sum16) > skb_headlen(skb));
++
++	udp_csum = csum_fold(csum);
++	if (udp_csum == 0)
++		udp_csum = CSUM_MANGLED_0;
++
++	*(__sum16 *)(skb->data + offset) = udp_csum;
++
++	skb->ip_summed = CHECKSUM_NONE;
++}
++
++static inline __be16 hisi_femac_get_l3_proto(struct sk_buff *skb)
++{
++	__be16 l3_proto;
++
++	l3_proto = skb->protocol;
++	if (skb->protocol == htons(ETH_P_8021Q))
++		l3_proto = vlan_get_protocol(skb);
++
++	return l3_proto;
++}
++
++static inline bool hisi_femac_skb_is_ipv6(struct sk_buff *skb)
++{
++	return (hisi_femac_get_l3_proto(skb) == htons(ETH_P_IPV6));
++}
++
++static int hisi_femac_check_hw_capability_for_ipv6(struct sk_buff *skb)
++{
++	unsigned int l4_proto = IPPROTO_MAX;
++
++	l4_proto = ipv6_hdr(skb)->nexthdr;
++
++	if ((l4_proto != IPPROTO_TCP) && (l4_proto != IPPROTO_UDP)) {
++		/* when IPv6 next header is not tcp or udp,
++		 * it means that IPv6 next header is extension header.
++		 * Hardware can't deal with this case,
++		 * so do checksumming by software or do GSO by software.
++		 */
++		if (skb_is_gso(skb))
++			return -ENOTSUPP;
++
++		if (skb->ip_summed == CHECKSUM_PARTIAL &&
++		    skb_checksum_help(skb))
++			return -EINVAL;
++	}
++
++	return 0;
++}
++
++static int hisi_femac_check_hw_capability(struct sk_buff *skb)
++{
++	/* if tcp_mtu_probe() use (2 * tp->mss_cache) as probe_size,
++	 * the linear data length will be larger than 2048,
++	 * the MAC can't handle it, so let the software do it.
++	 */
++	if (skb_is_gso(skb) && (skb_headlen(skb) > 2048))
++		return -ENOTSUPP;
++
++	if (hisi_femac_skb_is_ipv6(skb))
++		return hisi_femac_check_hw_capability_for_ipv6(skb);
++
++	return 0;
++}
++
++static u32 hisi_femac_get_pkt_info(struct sk_buff *skb)
++{
++	__be16 l3_proto;
++	unsigned int l4_proto = IPPROTO_MAX;
++	bool do_txcsum = false;
++	int max_data_len = skb->len - ETH_HLEN;
++	unsigned int max_mss = ETH_DATA_LEN;
++	u32 pkt_info = 0;
++
++	if (skb->ip_summed == CHECKSUM_PARTIAL)
++		do_txcsum = true;
++
++	l3_proto = skb->protocol;
++	if (skb->protocol == htons(ETH_P_8021Q)) {
++		l3_proto = vlan_get_protocol(skb);
++		max_data_len -= VLAN_HLEN;
++		pkt_info |= BIT_FLAG_VLAN;
++	}
++
++	if (l3_proto == htons(ETH_P_IP)) {
++		struct iphdr *iph = ip_hdr(skb);
++
++		if ((max_data_len >= GSO_MAX_SIZE) &&
++		    (ntohs(iph->tot_len) <= (iph->ihl << 2)))
++			iph->tot_len = htons(GSO_MAX_SIZE - 1);
++
++		max_mss -= iph->ihl * WORD_TO_BYTE;
++		pkt_info |= (iph->ihl << BIT_OFFSET_IP_HEADER_LEN);
++		l4_proto = iph->protocol;
++	} else if (l3_proto == htons(ETH_P_IPV6)) {
++		max_mss -= IPV6_HDR_LEN * WORD_TO_BYTE;
++		pkt_info |= BIT_FLAG_IPV6;
++		pkt_info |= (IPV6_HDR_LEN << BIT_OFFSET_IP_HEADER_LEN);
++		l4_proto = ipv6_hdr(skb)->nexthdr;
++	} else {
++		do_txcsum = false;
++	}
++
++	if (l4_proto == IPPROTO_TCP) {
++		max_mss -= tcp_hdr(skb)->doff * WORD_TO_BYTE;
++		pkt_info |= (tcp_hdr(skb)->doff << BIT_OFFSET_PROT_HEADER_LEN);
++	} else if (l4_proto == IPPROTO_UDP) {
++		if (l3_proto == htons(ETH_P_IPV6))
++			max_mss -= sizeof(struct frag_hdr);
++		pkt_info |= (BIT_FLAG_UDP |
++				(UDP_HDR_LEN << BIT_OFFSET_PROT_HEADER_LEN));
++	} else {
++		do_txcsum = false;
++	}
++
++	/* Although netcard support UFO feature, it can't deal with
++	 * UDP header checksum.
++	 * So the driver will do UDP header checksum and netcard will just
++	 * fragment the packet.
++	 */
++	if (do_txcsum && skb_is_gso(skb) && (l4_proto == IPPROTO_UDP)) {
++		hisi_femac_do_udp_checksum(skb);
++		do_txcsum = false;
++	}
++
++	if (do_txcsum)
++		pkt_info |= BIT_FLAG_TXCSUM;
++
++	if (skb_is_gso(skb))
++		pkt_info |= (BIT_FLAG_SG | BIT_FLAG_TSO);
++	else if (skb_shinfo(skb)->nr_frags)
++		pkt_info |= BIT_FLAG_SG;
++
++	pkt_info |= (skb_shinfo(skb)->nr_frags << BIT_OFFSET_NFRAGS_NUM);
++	pkt_info |= (skb_is_gso(skb) ?
++		((skb_shinfo(skb)->gso_size > max_mss) ? max_mss :
++		skb_shinfo(skb)->gso_size) : (skb->len + ETH_FCS_LEN));
++
++	return pkt_info;
++}
++
++static int hisi_femac_fill_sg_desc(struct hisi_femac_priv *priv,
++				   struct sk_buff *skb, unsigned int pos)
++{
++	struct tx_desc *desc_cur;
++	dma_addr_t addr;
++	int ret;
++	int i;
++
++	desc_cur = priv->tx_ring.desc + pos;
++
++	desc_cur->ipv6_id = ntohl(skb_shinfo(skb)->ip6_frag_id);
++
++	desc_cur->total_len = skb->len;
++	addr = dma_map_single(priv->dev, skb->data, skb_headlen(skb),
++			      DMA_TO_DEVICE);
++	if (unlikely(dma_mapping_error(priv->dev, addr)))
++		return -EINVAL;
++	desc_cur->linear_addr = addr;
++	desc_cur->linear_len = skb_headlen(skb);
++
++	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
++		skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
++		int len = frag->size;
++
++		addr = skb_frag_dma_map(priv->dev, frag, 0, len, DMA_TO_DEVICE);
++		ret = dma_mapping_error(priv->dev, addr);
++		if (unlikely(ret))
++			return -EINVAL;
++		desc_cur->frags[i].addr = addr;
++		desc_cur->frags[i].size = len;
++	}
++
++	return 0;
++}
++
++static void hisi_femac_adjust_link(struct net_device *dev)
++{
++	struct hisi_femac_priv *priv = netdev_priv(dev);
++	struct phy_device *phy = dev->phydev;
++	u32 status = 0;
++
++	if (phy->link)
++		status |= MAC_PORTSET_LINKED;
++	if (phy->duplex == DUPLEX_FULL)
++		status |= MAC_PORTSET_DUPLEX_FULL;
++	if (phy->speed == SPEED_100)
++		status |= MAC_PORTSET_SPEED_100M;
++
++	if ((status != priv->link_status) &&
++	    ((status | priv->link_status) & MAC_PORTSET_LINKED)) {
++		writel(status, priv->port_base + MAC_PORTSET);
++		priv->link_status = status;
++		phy_print_status(phy);
++
++		priv->tx_pause_en = phy->pause;
++		hisi_femac_set_flow_ctrl(priv);
++	}
++}
++
++static void hisi_femac_rx_refill(struct hisi_femac_priv *priv)
++{
++	struct hisi_femac_queue *rxq = &priv->rxq;
++	struct sk_buff *skb;
++	u32 pos;
++	u32 len = MAX_FRAME_SIZE;
++	dma_addr_t addr;
++	u32 alloc_rxbuf_align = 0;
++	int reserve_room = 0;
++
++	pos = rxq->head;
++	while (readl(priv->port_base + ADDRQ_STAT) & BIT_RX_READY) {
++		if (!CIRC_SPACE(pos, rxq->tail, rxq->num))
++			break;
++		if (unlikely(rxq->skb[pos])) {
++			netdev_err(priv->ndev, "err skb[%d]=%p\n",
++				   pos, rxq->skb[pos]);
++			break;
++		}
++		len = MAX_FRAME_SIZE + RXBUF_ADDR_ALIGN_SIZE;
++		skb = netdev_alloc_skb_ip_align(priv->ndev, len);
++		if (unlikely(!skb))
++			break;
++
++		alloc_rxbuf_align = ((unsigned long)skb->data - NET_IP_ALIGN) &
++						(RXBUF_ADDR_ALIGN_SIZE - 1);
++		if (alloc_rxbuf_align) {
++			reserve_room = RXBUF_ADDR_ALIGN_SIZE - alloc_rxbuf_align;
++			len -= reserve_room;
++			skb_reserve(skb, reserve_room);
++		}
++
++		addr = dma_map_single(priv->dev, skb->data, len,
++				      DMA_FROM_DEVICE);
++		if (dma_mapping_error(priv->dev, addr)) {
++			dev_kfree_skb_any(skb);
++			break;
++		}
++		rxq->dma_phys[pos] = addr;
++		rxq->skb[pos] = skb;
++		writel(addr, priv->port_base + IQ_ADDR);
++		pos = (pos + 1) % rxq->num;
++	}
++	rxq->head = pos;
++}
++
++static u32 hisi_femac_rx(struct net_device *dev, int limit)
++{
++	struct hisi_femac_priv *priv = netdev_priv(dev);
++	struct hisi_femac_queue *rxq = &priv->rxq;
++	struct sk_buff *skb;
++	dma_addr_t addr;
++	u32 rx_pkt_info, pos, len, rx_pkts_num = 0;
++	int hdr_csum_done, hdr_csum_err;
++	int payload_csum_done, payload_csum_err;
++
++	pos = rxq->tail;
++	while (readl(priv->glb_base + GLB_IRQ_RAW) & IRQ_INT_RX_RDY) {
++		rx_pkt_info = readl(priv->port_base + IQFRM_DES);
++		len = rx_pkt_info & RX_FRAME_LEN_MASK;
++		len -= ETH_FCS_LEN;
++
++		/* tell hardware we will deal with this packet */
++		writel(IRQ_INT_RX_RDY, priv->glb_base + GLB_IRQ_RAW);
++
++		rx_pkts_num++;
++
++		skb = rxq->skb[pos];
++		if (unlikely(!skb)) {
++			netdev_err(dev, "rx skb NULL. pos=%d\n", pos);
++			break;
++		}
++		rxq->skb[pos] = NULL;
++
++		addr = rxq->dma_phys[pos];
++		dma_unmap_single(priv->dev, addr, MAX_FRAME_SIZE,
++				 DMA_FROM_DEVICE);
++		skb_put(skb, len);
++		if (unlikely(skb->len > MAX_FRAME_SIZE)) {
++			netdev_err(dev, "rcv len err, len = %d\n", skb->len);
++			dev->stats.rx_errors++;
++			dev->stats.rx_length_errors++;
++			dev_kfree_skb_any(skb);
++			goto next;
++		}
++
++		skb->ip_summed = CHECKSUM_NONE;
++		if (dev->features & NETIF_F_RXCSUM) {
++			hdr_csum_done =
++				(rx_pkt_info >> BITS_HEADER_DONE_OFFSET) &
++				BITS_HEADER_DONE_MASK;
++			payload_csum_done =
++				(rx_pkt_info >> BITS_PAYLOAD_DONE_OFFSET) &
++				BITS_PAYLOAD_DONE_MASK;
++			hdr_csum_err =
++				(rx_pkt_info >> BITS_HEADER_ERR_OFFSET) &
++				BITS_HEADER_ERR_MASK;
++			payload_csum_err =
++				(rx_pkt_info >> BITS_PAYLOAD_ERR_OFFSET) &
++				BITS_PAYLOAD_ERR_MASK;
++
++			if (hdr_csum_done && payload_csum_done) {
++				if (unlikely(hdr_csum_err)) {
++					dev->stats.rx_errors++;
++					dev->stats.rx_crc_errors++;
++					dev_kfree_skb_any(skb);
++					goto next;
++				} else if (!payload_csum_err) {
++					skb->ip_summed = CHECKSUM_UNNECESSARY;
++				}
++			}
++		}
++
++		skb->protocol = eth_type_trans(skb, dev);
++		napi_gro_receive(&priv->napi, skb);
++		dev->stats.rx_packets++;
++		dev->stats.rx_bytes += len;
++next:
++		pos = (pos + 1) % rxq->num;
++		if (rx_pkts_num >= limit)
++			break;
++	}
++	rxq->tail = pos;
++
++	hisi_femac_rx_refill(priv);
++
++	return rx_pkts_num;
++}
++
++static int hisi_femac_poll(struct napi_struct *napi, int budget)
++{
++	struct hisi_femac_priv *priv = container_of(napi,
++					struct hisi_femac_priv, napi);
++	struct net_device *dev = priv->ndev;
++	int work_done = 0, task = budget;
++	u32 ints, num;
++
++	do {
++		hisi_femac_xmit_reclaim(dev);
++		num = hisi_femac_rx(dev, task);
++		work_done += num;
++		task -= num;
++		if (work_done >= budget)
++			break;
++
++		ints = readl(priv->glb_base + GLB_IRQ_RAW);
++		writel(ints & DEF_INT_MASK,
++		       priv->glb_base + GLB_IRQ_RAW);
++	} while (ints & DEF_INT_MASK);
++
++	if (work_done < budget) {
++		napi_complete(napi);
++		hisi_femac_irq_enable(priv, DEF_INT_MASK &
++					(~IRQ_INT_TX_PER_PACKET));
++	}
++
++	return work_done;
++}
++
++static irqreturn_t hisi_femac_interrupt(int irq, void *dev_id)
++{
++	u32 ints;
++	struct net_device *dev = (struct net_device *)dev_id;
++	struct hisi_femac_priv *priv = netdev_priv(dev);
++
++	ints = readl(priv->glb_base + GLB_IRQ_RAW);
++
++	if (likely(ints & DEF_INT_MASK)) {
++		writel(ints & DEF_INT_MASK,
++		       priv->glb_base + GLB_IRQ_RAW);
++		hisi_femac_irq_disable(priv, DEF_INT_MASK);
++		napi_schedule(&priv->napi);
++	}
++
++	if (HAS_TSO_CAP(priv->hw_cap) &&
++	    unlikely(ints & INT_TX_ERR))
++		hisi_femac_get_tso_err_info(priv);
++
++	return IRQ_HANDLED;
++}
++
++static int hisi_femac_init_tx_descriptor_ring(struct hisi_femac_priv *priv)
++{
++	priv->tx_ring.desc = (struct tx_desc *)dma_zalloc_coherent(priv->dev,
++			TXQ_NUM * sizeof(struct tx_desc),
++			&priv->tx_ring.dma_phys,
++			GFP_KERNEL);
++	if (!priv->tx_ring.desc)
++		return -ENOMEM;
++
++	return 0;
++}
++
++static void hisi_femac_destroy_tx_descriptor_ring(struct hisi_femac_priv *priv)
++{
++	if (priv->tx_ring.desc)
++		dma_free_coherent(priv->dev,
++				  TXQ_NUM * sizeof(struct tx_desc),
++				  priv->tx_ring.desc, priv->tx_ring.dma_phys);
++	priv->tx_ring.desc = NULL;
++}
++
++static int hisi_femac_init_queue(struct device *dev,
++				 struct hisi_femac_queue *queue,
++				 unsigned int num)
++{
++	queue->skb = devm_kcalloc(dev, num, sizeof(struct sk_buff *),
++				  GFP_KERNEL);
++	if (!queue->skb)
++		return -ENOMEM;
++
++	queue->dma_phys = devm_kcalloc(dev, num, sizeof(dma_addr_t),
++				       GFP_KERNEL);
++	if (!queue->dma_phys)
++		return -ENOMEM;
++
++	queue->num = num;
++	queue->head = 0;
++	queue->tail = 0;
++
++	return 0;
++}
++
++static int hisi_femac_init_tx_and_rx_queues(struct hisi_femac_priv *priv)
++{
++	int ret;
++
++	ret = hisi_femac_init_queue(priv->dev, &priv->txq, TXQ_NUM);
++	if (ret)
++		return ret;
++
++	ret = hisi_femac_init_queue(priv->dev, &priv->rxq, RXQ_NUM);
++	if (ret)
++		return ret;
++
++	priv->tx_fifo_used_cnt = 0;
++
++	return 0;
++}
++
++static void hisi_femac_free_skb_rings(struct hisi_femac_priv *priv)
++{
++	struct hisi_femac_queue *txq = &priv->txq;
++	struct hisi_femac_queue *rxq = &priv->rxq;
++	struct sk_buff *skb;
++	dma_addr_t dma_addr;
++	u32 pos;
++
++	pos = rxq->tail;
++	while (pos != rxq->head) {
++		skb = rxq->skb[pos];
++		if (unlikely(!skb)) {
++			netdev_err(priv->ndev, "NULL rx skb. pos=%d, head=%d\n",
++				   pos, rxq->head);
++			continue;
++		}
++
++		dma_addr = rxq->dma_phys[pos];
++		dma_unmap_single(priv->dev, dma_addr, MAX_FRAME_SIZE,
++				 DMA_FROM_DEVICE);
++
++		dev_kfree_skb_any(skb);
++		rxq->skb[pos] = NULL;
++		pos = (pos + 1) % rxq->num;
++	}
++	rxq->tail = pos;
++
++	pos = txq->tail;
++	while (pos != txq->head) {
++		skb = txq->skb[pos];
++		if (unlikely(!skb)) {
++			netdev_err(priv->ndev, "NULL tx skb. pos=%d, head=%d\n",
++				   pos, txq->head);
++			continue;
++		}
++		hisi_femac_tx_dma_unmap(priv, skb, pos);
++		dev_kfree_skb_any(skb);
++		txq->skb[pos] = NULL;
++		pos = (pos + 1) % txq->num;
++	}
++	txq->tail = pos;
++	priv->tx_fifo_used_cnt = 0;
++}
++
++static int hisi_femac_set_hw_mac_addr(struct hisi_femac_priv *priv,
++				      unsigned char *mac)
++{
++	u32 reg;
++
++	reg = mac[1] | (mac[0] << 8);
++	writel(reg, priv->glb_base + GLB_HOSTMAC_H16);
++
++	reg = mac[5] | (mac[4] << 8) | (mac[3] << 16) | (mac[2] << 24);
++	writel(reg, priv->glb_base + GLB_HOSTMAC_L32);
++
++	return 0;
++}
++
++static int hisi_femac_port_reset(struct hisi_femac_priv *priv)
++{
++	u32 val;
++
++	val = readl(priv->glb_base + GLB_SOFT_RESET);
++	val |= SOFT_RESET_ALL;
++	writel(val, priv->glb_base + GLB_SOFT_RESET);
++
++	usleep_range(500, 800);
++
++	val &= ~SOFT_RESET_ALL;
++	writel(val, priv->glb_base + GLB_SOFT_RESET);
++
++	return 0;
++}
++
++static int hisi_femac_net_open(struct net_device *dev)
++{
++	struct hisi_femac_priv *priv = netdev_priv(dev);
++
++	hisi_femac_set_hw_mac_addr(priv, dev->dev_addr);
++	/* clear interrupts will drop the first packet MAC have received,
++	 * so do it before refill the rx free skbs.
++	 */
++	writel(IRQ_ENA_PORT0_MASK, priv->glb_base + GLB_IRQ_RAW);
++	hisi_femac_rx_refill(priv);
++
++	netif_carrier_off(dev);
++	netdev_reset_queue(dev);
++	netif_start_queue(dev);
++	napi_enable(&priv->napi);
++
++	priv->link_status = 0;
++	if (dev->phydev)
++		phy_start(dev->phydev);
++
++	hisi_femac_irq_enable(priv, IRQ_ENA_ALL | IRQ_ENA_PORT0 | DEF_INT_MASK);
++	if (HAS_TSO_CAP(priv->hw_cap))
++		hisi_femac_irq_enable(priv, INT_TX_ERR);
++
++	return 0;
++}
++
++static void hisi_femac_port_init(struct hisi_femac_priv *priv);
++
++static int hisi_femac_net_close(struct net_device *dev)
++{
++	struct hisi_femac_priv *priv = netdev_priv(dev);
++
++	hisi_femac_irq_disable(priv, IRQ_ENA_PORT0);
++
++	if (dev->phydev)
++		phy_stop(dev->phydev);
++
++	netif_stop_queue(dev);
++	napi_disable(&priv->napi);
++
++	/* reset MAC port first before free skb rings
++	 * to prevent potential risk of use-after-free.
++	 */
++	hisi_femac_port_reset(priv);
++	hisi_femac_port_init(priv);
++
++	priv->tx_pause_en = false;
++	hisi_femac_set_flow_ctrl(priv);
++	hisi_femac_free_skb_rings(priv);
++
++	return 0;
++}
++
++static netdev_tx_t hisi_femac_net_xmit(struct sk_buff *skb,
++				       struct net_device *dev)
++{
++	struct hisi_femac_priv *priv = netdev_priv(dev);
++	struct hisi_femac_queue *txq = &priv->txq;
++	dma_addr_t addr;
++	int ret;
++	u32 pkt_info;
++	u32 val;
++
++	val = readl(priv->port_base + ADDRQ_STAT);
++	val &= BIT_TX_READY;
++	if (!val) {
++		hisi_femac_irq_enable(priv, IRQ_INT_TX_PER_PACKET);
++		dev->stats.tx_dropped++;
++		dev->stats.tx_fifo_errors++;
++		netif_stop_queue(dev);
++		return NETDEV_TX_BUSY;
++	}
++
++	if (unlikely(!CIRC_SPACE(txq->head, txq->tail,
++				 txq->num))) {
++		hisi_femac_irq_enable(priv, IRQ_INT_TX_PER_PACKET);
++		dev->stats.tx_dropped++;
++		dev->stats.tx_fifo_errors++;
++		netif_stop_queue(dev);
++		return NETDEV_TX_BUSY;
++	}
++
++	ret = hisi_femac_check_hw_capability(skb);
++	if (unlikely(ret)) {
++		if (ret == -ENOTSUPP)
++			return hisi_femac_sw_gso(skb, dev);
++
++		dev_kfree_skb_any(skb);
++		dev->stats.tx_dropped++;
++		return NETDEV_TX_OK;
++	}
++
++	pkt_info = hisi_femac_get_pkt_info(skb);
++
++	if (!(skb_is_gso(skb) || skb_shinfo(skb)->nr_frags)) {
++		addr = dma_map_single(priv->dev, skb->data,
++				      skb->len, DMA_TO_DEVICE);
++		if (unlikely(dma_mapping_error(priv->dev, addr))) {
++			dev_kfree_skb_any(skb);
++			dev->stats.tx_dropped++;
++			return NETDEV_TX_OK;
++		}
++	} else {
++		ret = hisi_femac_fill_sg_desc(priv, skb, txq->head);
++		if (unlikely(ret)) {
++			dev_kfree_skb_any(skb);
++			dev->stats.tx_dropped++;
++			return NETDEV_TX_OK;
++		}
++
++		addr = priv->tx_ring.dma_phys +
++			txq->head * sizeof(struct tx_desc);
++
++		/* Ensure desc info writen to memory before config hardware */
++		wmb();
++	}
++	txq->dma_phys[txq->head] = addr;
++
++	txq->skb[txq->head] = skb;
++	txq->head = (txq->head + 1) % txq->num;
++
++	writel(addr, priv->port_base + EQ_ADDR);
++	writel(pkt_info, priv->port_base + EQFRM_LEN);
++
++	priv->tx_fifo_used_cnt++;
++
++	dev->stats.tx_packets++;
++	dev->stats.tx_bytes += skb->len;
++	netdev_sent_queue(dev, skb->len);
++
++	return NETDEV_TX_OK;
++}
++
++static int hisi_femac_set_mac_address(struct net_device *dev, void *p)
++{
++	struct hisi_femac_priv *priv = netdev_priv(dev);
++	struct sockaddr *skaddr = p;
++
++	if (!is_valid_ether_addr(skaddr->sa_data))
++		return -EADDRNOTAVAIL;
++
++	memcpy(dev->dev_addr, skaddr->sa_data, dev->addr_len);
++	dev->addr_assign_type &= ~NET_ADDR_RANDOM;
++
++	hisi_femac_set_hw_mac_addr(priv, dev->dev_addr);
++
++	return 0;
++}
++
++static void hisi_femac_enable_hw_addr_filter(struct hisi_femac_priv *priv,
++					     unsigned int reg_n, bool enable)
++{
++	u32 val;
++
++	val = readl(priv->glb_base + GLB_MAC_H16(reg_n));
++	if (enable)
++		val |= BIT_MACFLT_ENA;
++	else
++		val &= ~BIT_MACFLT_ENA;
++	writel(val, priv->glb_base + GLB_MAC_H16(reg_n));
++}
++
++static void hisi_femac_set_hw_addr_filter(struct hisi_femac_priv *priv,
++					  unsigned char *addr,
++					  unsigned int reg_n)
++{
++	unsigned int high, low;
++	u32 val;
++
++	high = GLB_MAC_H16(reg_n);
++	low = GLB_MAC_L32(reg_n);
++
++	val = (addr[2] << 24) | (addr[3] << 16) | (addr[4] << 8) | addr[5];
++	writel(val, priv->glb_base + low);
++
++	val = readl(priv->glb_base + high);
++	val &= ~MACFLT_HI16_MASK;
++	val |= ((addr[0] << 8) | addr[1]);
++	val |= (BIT_MACFLT_ENA | BIT_MACFLT_FW2CPU);
++	writel(val, priv->glb_base + high);
++}
++
++static void hisi_femac_set_promisc_mode(struct hisi_femac_priv *priv,
++					bool promisc_mode)
++{
++	u32 val;
++
++	val = readl(priv->glb_base + GLB_FWCTRL);
++	if (promisc_mode)
++		val |= FWCTRL_FWALL2CPU;
++	else
++		val &= ~FWCTRL_FWALL2CPU;
++	writel(val, priv->glb_base + GLB_FWCTRL);
++}
++
++/* Handle multiple multicast addresses (perfect filtering)*/
++static void hisi_femac_set_mc_addr_filter(struct hisi_femac_priv *priv)
++{
++	struct net_device *dev = priv->ndev;
++	u32 val;
++
++	val = readl(priv->glb_base + GLB_MACTCTRL);
++	if ((netdev_mc_count(dev) > MAX_MULTICAST_ADDRESSES) ||
++	    (dev->flags & IFF_ALLMULTI)) {
++		val |= MACTCTRL_MULTI2CPU;
++	} else {
++		int reg = MAX_UNICAST_ADDRESSES;
++		int i;
++		struct netdev_hw_addr *ha;
++
++		for (i = reg; i < MAX_MAC_FILTER_NUM; i++)
++			hisi_femac_enable_hw_addr_filter(priv, i, false);
++
++		netdev_for_each_mc_addr(ha, dev) {
++			hisi_femac_set_hw_addr_filter(priv, ha->addr, reg);
++			reg++;
++		}
++		val &= ~MACTCTRL_MULTI2CPU;
++	}
++	writel(val, priv->glb_base + GLB_MACTCTRL);
++}
++
++/* Handle multiple unicast addresses (perfect filtering)*/
++static void hisi_femac_set_uc_addr_filter(struct hisi_femac_priv *priv)
++{
++	struct net_device *dev = priv->ndev;
++	u32 val;
++
++	val = readl(priv->glb_base + GLB_MACTCTRL);
++	if (netdev_uc_count(dev) > MAX_UNICAST_ADDRESSES) {
++		val |= MACTCTRL_UNI2CPU;
++	} else {
++		int reg = 0;
++		int i;
++		struct netdev_hw_addr *ha;
++
++		for (i = reg; i < MAX_UNICAST_ADDRESSES; i++)
++			hisi_femac_enable_hw_addr_filter(priv, i, false);
++
++		netdev_for_each_uc_addr(ha, dev) {
++			hisi_femac_set_hw_addr_filter(priv, ha->addr, reg);
++			reg++;
++		}
++		val &= ~MACTCTRL_UNI2CPU;
++	}
++	writel(val, priv->glb_base + GLB_MACTCTRL);
++}
++
++static void hisi_femac_net_set_rx_mode(struct net_device *dev)
++{
++	struct hisi_femac_priv *priv = netdev_priv(dev);
++
++	if (dev->flags & IFF_PROMISC) {
++		hisi_femac_set_promisc_mode(priv, true);
++	} else {
++		hisi_femac_set_promisc_mode(priv, false);
++		hisi_femac_set_mc_addr_filter(priv);
++		hisi_femac_set_uc_addr_filter(priv);
++	}
++}
++
++static int hisi_femac_net_ioctl(struct net_device *dev,
++				struct ifreq *ifreq, int cmd)
++{
++	if (!netif_running(dev))
++		return -EINVAL;
++
++	if (!dev->phydev)
++		return -EINVAL;
++
++	return phy_mii_ioctl(dev->phydev, ifreq, cmd);
++}
++
++static void hisi_femac_get_pauseparam(struct net_device *dev,
++				      struct ethtool_pauseparam *pause)
++{
++	struct hisi_femac_priv *priv = netdev_priv(dev);
++
++	pause->autoneg = dev->phydev->autoneg;
++	pause->rx_pause = 1;
++	if (priv->tx_pause_en)
++		pause->tx_pause = 1;
++}
++
++static int hisi_femac_set_pauseparam(struct net_device *dev,
++				     struct ethtool_pauseparam *pause)
++{
++	struct hisi_femac_priv *priv = netdev_priv(dev);
++	struct phy_device *phy = dev->phydev;
++	int ret = 0;
++
++	if (pause->rx_pause == 0)
++		return -EINVAL;
++
++	if (pause->tx_pause != priv->tx_pause_en) {
++		priv->tx_pause_en = pause->tx_pause;
++		hisi_femac_set_flow_ctrl(priv);
++	}
++
++	if (phy->autoneg) {
++		if (netif_running(dev)) {
++			struct ethtool_cmd cmd;
++			/* auto-negotiation automatically restarted */
++			cmd.cmd = ETHTOOL_NWAY_RST;
++			cmd.supported = phy->supported;
++			cmd.advertising = phy->advertising;
++			cmd.autoneg = phy->autoneg;
++			cmd.speed = phy->speed;
++			cmd.duplex = phy->duplex;
++			cmd.phy_address = phy->addr;
++			ret = phy_ethtool_sset(phy, &cmd);
++		}
++	}
++
++	return ret;
++}
++
++static void hisi_femac_enable_rxcsum_drop(struct hisi_femac_priv *priv,
++					  bool drop)
++{
++	unsigned int val;
++
++	val = readl(priv->port_base + RX_COE_CTRL);
++	val &= ~COE_ERR_DROP;
++	if (drop)
++		val |= (BIT_COE_IPHDR_DROP | BIT_COE_IPV6_UDP_ZERO_DROP);
++	writel(val, priv->port_base + RX_COE_CTRL);
++}
++
++static int hisi_femac_set_features(struct net_device *dev,
++				   netdev_features_t features)
++{
++	struct hisi_femac_priv *priv = netdev_priv(dev);
++	netdev_features_t changed = dev->features ^ features;
++
++	if (changed & NETIF_F_RXCSUM) {
++		if (features & NETIF_F_RXCSUM)
++			hisi_femac_enable_rxcsum_drop(priv, true);
++		else
++			hisi_femac_enable_rxcsum_drop(priv, false);
++	}
++
++	return 0;
++}
++
++static int hisi_femac_get_settings(struct net_device *ndev,
++				   struct ethtool_cmd *cmd)
++{
++	if (!ndev->phydev)
++		return -EINVAL;
++
++	return phy_ethtool_gset(ndev->phydev, cmd);
++}
++
++static int hisi_femac_set_settings(struct net_device *ndev,
++				   struct ethtool_cmd *cmd)
++{
++	if (!capable(CAP_NET_ADMIN))
++		return -EPERM;
++
++	if (!ndev->phydev)
++		return -EINVAL;
++
++	return phy_ethtool_sset(ndev->phydev, cmd);
++}
++
++static struct ethtool_ops hisi_femac_ethtools_ops = {
++	.get_link		= ethtool_op_get_link,
++	.get_settings		= hisi_femac_get_settings,
++	.set_settings		= hisi_femac_set_settings,
++	.get_pauseparam		= hisi_femac_get_pauseparam,
++	.set_pauseparam		= hisi_femac_set_pauseparam,
++};
++
++static const struct net_device_ops hisi_femac_netdev_ops = {
++	.ndo_open		= hisi_femac_net_open,
++	.ndo_stop		= hisi_femac_net_close,
++	.ndo_start_xmit		= hisi_femac_net_xmit,
++	.ndo_do_ioctl		= hisi_femac_net_ioctl,
++	.ndo_set_mac_address	= hisi_femac_set_mac_address,
++	.ndo_set_rx_mode	= hisi_femac_net_set_rx_mode,
++	.ndo_change_mtu		= eth_change_mtu,
++	.ndo_set_features	= hisi_femac_set_features,
++};
++
++static void hisi_femac_verify_flow_ctrl_args(struct hisi_femac_priv *priv)
++{
++	if (priv->tx_pause_active_thresh < FC_ACTIVE_MIN ||
++	    priv->tx_pause_active_thresh > FC_ACTIVE_MAX)
++		priv->tx_pause_active_thresh = FC_ACTIVE_DEFAULT;
++
++	if (priv->tx_pause_deactive_thresh < FC_DEACTIVE_MIN ||
++	    priv->tx_pause_deactive_thresh > FC_DEACTIVE_MAX)
++		priv->tx_pause_deactive_thresh = FC_DEACTIVE_DEFAULT;
++
++	if (priv->tx_pause_active_thresh >= priv->tx_pause_deactive_thresh) {
++		priv->tx_pause_active_thresh = FC_ACTIVE_DEFAULT;
++		priv->tx_pause_deactive_thresh = FC_DEACTIVE_DEFAULT;
++	}
++}
++
++static void hisi_femac_core_reset(struct hisi_femac_priv *priv)
++{
++	reset_control_assert(priv->mac_rst);
++	reset_control_deassert(priv->mac_rst);
++}
++
++static void hisi_femac_sleep_us(u32 time_us)
++{
++	u32 time_ms;
++
++	if (!time_us)
++		return;
++
++	time_ms = DIV_ROUND_UP(time_us, 1000);
++	if (time_ms < 20)
++		usleep_range(time_us, time_us + 500);
++	else
++		msleep(time_ms);
++}
++
++static void hisi_femac_phy_reset(struct hisi_femac_priv *priv)
++{
++	/* To make sure PHY hardware reset success,
++	 * we must keep PHY in deassert state first and
++	 * then complete the hardware reset operation
++	 */
++	reset_control_deassert(priv->phy_rst);
++	hisi_femac_sleep_us(priv->phy_reset_delays[PRE_DELAY]);
++
++	reset_control_assert(priv->phy_rst);
++	/* delay some time to ensure reset ok,
++	 * this depends on PHY hardware feature
++	 */
++	hisi_femac_sleep_us(priv->phy_reset_delays[PULSE]);
++	reset_control_deassert(priv->phy_rst);
++	/* delay some time to ensure later MDIO access */
++	hisi_femac_sleep_us(priv->phy_reset_delays[POST_DELAY]);
++}
++
++static void hisi_femac_port_init(struct hisi_femac_priv *priv)
++{
++	u32 val;
++
++	/* MAC gets link status info and phy mode by software config */
++	val = MAC_PORTSEL_STAT_CPU;
++	if (priv->ndev->phydev->interface == PHY_INTERFACE_MODE_RMII)
++		val |= MAC_PORTSEL_RMII;
++	writel(val, priv->port_base + MAC_PORTSEL);
++
++	/*clear all interrupt status */
++	writel(IRQ_ENA_PORT0_MASK, priv->glb_base + GLB_IRQ_RAW);
++	hisi_femac_irq_disable(priv, IRQ_ENA_PORT0_MASK | IRQ_ENA_PORT0);
++
++	if (HAS_TSO_CAP(priv->hw_cap)) {
++		/* enable TSO debug for error handle */
++		val = readl(priv->port_base + TSO_DBG_EN);
++		val |= BITS_TSO_DBG_EN;
++		writel(val, priv->port_base + TSO_DBG_EN);
++	}
++
++	val = readl(priv->glb_base + GLB_FWCTRL);
++	val &= ~(FWCTRL_VLAN_ENABLE | FWCTRL_FWALL2CPU);
++	val |= FWCTRL_FW2CPU_ENA;
++	writel(val, priv->glb_base + GLB_FWCTRL);
++
++	val = readl(priv->glb_base + GLB_MACTCTRL);
++	val |= (MACTCTRL_BROAD2CPU | MACTCTRL_MACT_ENA);
++	writel(val, priv->glb_base + GLB_MACTCTRL);
++
++	val = readl(priv->port_base + MAC_SET);
++	val &= ~MAX_FRAME_SIZE_MASK;
++	val |= MAX_FRAME_SIZE;
++	writel(val, priv->port_base + MAC_SET);
++
++	val = RX_COALESCED_TIMER |
++		(RX_COALESCED_FRAMES << RX_COALESCED_FRAME_OFFSET);
++	writel(val, priv->port_base + RX_COALESCE_SET);
++
++	val = (HW_RX_FIFO_DEPTH << RX_DEPTH_OFFSET) | HW_TX_FIFO_DEPTH;
++	writel(val, priv->port_base + QLEN_SET);
++
++	hisi_femac_set_flow_ctrl(priv);
++}
++
++static int hisi_femac_drv_probe(struct platform_device *pdev)
++{
++	struct device *dev = &pdev->dev;
++	struct device_node *node = dev->of_node;
++	struct resource *res;
++	struct net_device *ndev;
++	struct hisi_femac_priv *priv;
++	struct phy_device *phy;
++	const char *mac_addr;
++	int ret;
++
++	ndev = alloc_etherdev(sizeof(*priv));
++	if (!ndev)
++		return -ENOMEM;
++
++	platform_set_drvdata(pdev, ndev);
++
++	priv = netdev_priv(ndev);
++	priv->dev = dev;
++	priv->ndev = ndev;
++
++	if (of_device_is_compatible(node, "hisilicon,hisi-femac-v2"))
++		priv->hw_cap |= HW_CAP_TSO | HW_CAP_RXCSUM;
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	priv->port_base = devm_ioremap_resource(dev, res);
++	if (IS_ERR(priv->port_base)) {
++		ret = PTR_ERR(priv->port_base);
++		goto out_free_netdev;
++	}
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
++	priv->glb_base = devm_ioremap_resource(dev, res);
++	if (IS_ERR(priv->glb_base)) {
++		ret = PTR_ERR(priv->glb_base);
++		goto out_free_netdev;
++	}
++
++	priv->clk = devm_clk_get(&pdev->dev, NULL);
++	if (IS_ERR(priv->clk)) {
++		dev_err(dev, "failed to get clk\n");
++		ret = -ENODEV;
++		goto out_free_netdev;
++	}
++
++	ret = clk_prepare_enable(priv->clk);
++	if (ret) {
++		dev_err(dev, "failed to enable clk %d\n", ret);
++		goto out_free_netdev;
++	}
++
++	priv->mac_rst = devm_reset_control_get(dev, "mac");
++	if (IS_ERR(priv->mac_rst)) {
++		ret = PTR_ERR(priv->mac_rst);
++		goto out_disable_clk;
++	}
++	hisi_femac_core_reset(priv);
++
++	priv->phy_rst = devm_reset_control_get(dev, "phy");
++	if (IS_ERR(priv->phy_rst)) {
++		priv->phy_rst = NULL;
++	} else {
++		ret = of_property_read_u32_array(node,
++						 PHY_RESET_DELAYS_PROPERTY,
++						 priv->phy_reset_delays,
++						 DELAYS_NUM);
++		if (ret)
++			goto out_disable_clk;
++		hisi_femac_phy_reset(priv);
++	}
++
++	phy = of_phy_get_and_connect(ndev, node, hisi_femac_adjust_link);
++	if (!phy) {
++		dev_err(dev, "connect to PHY failed!\n");
++		ret = -ENODEV;
++		goto out_disable_clk;
++	}
++
++	phy->advertising |= ADVERTISED_Pause;
++	phy->supported |= ADVERTISED_Pause;
++
++	dev_info(dev, "phy_id=0x%.8lx, phy_addr=%d, phy_mode=%s\n",
++			(unsigned long)phy->phy_id,
++			phy->addr,
++			phy_modes(phy->interface));
++
++	mac_addr = of_get_mac_address(node);
++	if (mac_addr)
++		ether_addr_copy(ndev->dev_addr, mac_addr);
++	if (!is_valid_ether_addr(ndev->dev_addr)) {
++		eth_hw_addr_random(ndev);
++		dev_warn(dev, "using random MAC address %pM\n",
++			 ndev->dev_addr);
++	}
++
++	ndev->watchdog_timeo = 6 * HZ;
++	ndev->priv_flags |= IFF_UNICAST_FLT;
++	ndev->netdev_ops = &hisi_femac_netdev_ops;
++	ndev->ethtool_ops = &hisi_femac_ethtools_ops;
++	netif_napi_add(ndev, &priv->napi, hisi_femac_poll, FEMAC_POLL_WEIGHT);
++	SET_NETDEV_DEV(ndev, &pdev->dev);
++
++	if (HAS_TSO_CAP(priv->hw_cap))
++		ndev->hw_features |= NETIF_F_SG |
++			NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
++			NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_UFO;
++
++	if (HAS_RXCSUM_CAP(priv->hw_cap))
++		ndev->hw_features |= NETIF_F_RXCSUM;
++	ndev->features |= ndev->hw_features;
++	ndev->vlan_features |= ndev->features;
++
++	device_set_wakeup_capable(priv->dev, true);
++	device_set_wakeup_enable(priv->dev, true);
++
++	priv->tx_pause_en = true;
++	priv->tx_pause_active_thresh = TX_FLOW_CTRL_ACTIVE_THRESHOLD;
++	priv->tx_pause_deactive_thresh = TX_FLOW_CTRL_DEACTIVE_THRESHOLD;
++
++	hisi_femac_verify_flow_ctrl_args(priv);
++
++	hisi_femac_port_init(priv);
++
++	if (HAS_RXCSUM_CAP(priv->hw_cap))
++		hisi_femac_enable_rxcsum_drop(priv, true);
++
++	ret = hisi_femac_init_tx_and_rx_queues(priv);
++	if (ret)
++		goto out_disconnect_phy;
++
++	if (HAS_TSO_CAP(priv->hw_cap)) {
++		ret = hisi_femac_init_tx_descriptor_ring(priv);
++		if (ret)
++			goto out_disconnect_phy;
++	}
++
++	ndev->irq = platform_get_irq(pdev, 0);
++	if (ndev->irq <= 0) {
++		dev_err(dev, "No irq resource\n");
++		ret = -ENODEV;
++		goto out_destroy_descriptor;
++	}
++
++	ret = devm_request_irq(dev, ndev->irq, hisi_femac_interrupt,
++			       IRQF_SHARED, pdev->name, ndev);
++	if (ret) {
++		dev_err(dev, "devm_request_irq %d failed!\n", ndev->irq);
++		goto out_destroy_descriptor;
++	}
++
++	ret = register_netdev(ndev);
++	if (ret) {
++		dev_err(dev, "register_netdev failed!\n");
++		goto out_destroy_descriptor;
++	}
++
++	return ret;
++
++out_destroy_descriptor:
++	if (HAS_TSO_CAP(priv->hw_cap))
++		hisi_femac_destroy_tx_descriptor_ring(priv);
++out_disconnect_phy:
++	netif_napi_del(&priv->napi);
++	phy_disconnect(phy);
++out_disable_clk:
++	clk_disable_unprepare(priv->clk);
++out_free_netdev:
++	free_netdev(ndev);
++
++	return ret;
++}
++
++static int hisi_femac_drv_remove(struct platform_device *pdev)
++{
++	struct net_device *ndev = platform_get_drvdata(pdev);
++	struct hisi_femac_priv *priv = netdev_priv(ndev);
++
++	netif_napi_del(&priv->napi);
++	unregister_netdev(ndev);
++	if (HAS_TSO_CAP(priv->hw_cap))
++		hisi_femac_destroy_tx_descriptor_ring(priv);
++
++	phy_disconnect(ndev->phydev);
++	clk_disable_unprepare(priv->clk);
++	free_netdev(ndev);
++
++	return 0;
++}
++
++#ifdef CONFIG_PM
++int hisi_femac_drv_suspend(struct platform_device *pdev,
++			   pm_message_t state)
++{
++	struct net_device *ndev = platform_get_drvdata(pdev);
++	struct hisi_femac_priv *priv = netdev_priv(ndev);
++
++	disable_irq(ndev->irq);
++	if (netif_running(ndev)) {
++		hisi_femac_net_close(ndev);
++		netif_device_detach(ndev);
++	}
++
++	clk_disable_unprepare(priv->clk);
++
++	return 0;
++}
++
++int hisi_femac_drv_resume(struct platform_device *pdev)
++{
++	struct net_device *ndev = platform_get_drvdata(pdev);
++	struct hisi_femac_priv *priv = netdev_priv(ndev);
++
++	clk_prepare_enable(priv->clk);
++	if (priv->phy_rst)
++		hisi_femac_phy_reset(priv);
++
++	if (netif_running(ndev)) {
++		hisi_femac_port_init(priv);
++		hisi_femac_net_open(ndev);
++		netif_device_attach(ndev);
++	}
++	enable_irq(ndev->irq);
++
++	return 0;
++}
++#endif
++
++static const struct of_device_id hisi_femac_match[] = {
++	{.compatible = "hisilicon,hisi-femac-v1",},
++	{.compatible = "hisilicon,hisi-femac-v2",},
++	{.compatible = "hisilicon,hi3516cv300-femac",},
++	{},
++};
++
++MODULE_DEVICE_TABLE(of, hisi_femac_match);
++
++static struct platform_driver hisi_femac_driver = {
++	.driver = {
++		.name = "hisi-femac",
++		.of_match_table = hisi_femac_match,
++	},
++	.probe = hisi_femac_drv_probe,
++	.remove = hisi_femac_drv_remove,
++#ifdef CONFIG_PM
++	.suspend = hisi_femac_drv_suspend,
++	.resume = hisi_femac_drv_resume,
++#endif
++};
++
++module_platform_driver(hisi_femac_driver);
++
++MODULE_DESCRIPTION("Hisilicon Fast Ethernet MAC driver");
++MODULE_AUTHOR("Dongpo Li <lidongpo@hisilicon.com>");
++MODULE_LICENSE("GPL v2");
++MODULE_ALIAS("platform:hisi-femac");
+diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
+index 75472cf..faa78eb 100644
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -212,6 +212,20 @@ config MDIO_BCM_UNIMAC
+ 	  controllers as well as some Broadcom Ethernet switches such as the
+ 	  Starfighter 2 switches.
+ 
++config MDIO_HISI_FEMAC
++	tristate "Hisilicon FEMAC MDIO bus controller"
++	depends on HAS_IOMEM && OF_MDIO
++	help
++	  This module provides a driver for the MDIO busses found in the
++	  Hisilicon SoC that have an Fast Ethernet MAC.
++
++config MDIO_HISI_GEMAC
++	tristate "Hisilicon GEMAC MDIO bus controller"
++	depends on HAS_IOMEM && OF_MDIO
++	help
++	  This module provides a driver for the MDIO busses found in the
++	  Hisilicon SoC that have an Gigabit Ethernet MAC.
++
+ endif # PHYLIB
+ 
+ config MICREL_KS8995MA
+diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
+index eb3b18b..d1cc7c5 100644
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -35,3 +35,5 @@ obj-$(CONFIG_MDIO_SUN4I)	+= mdio-sun4i.o
+ obj-$(CONFIG_MDIO_MOXART)	+= mdio-moxart.o
+ obj-$(CONFIG_AMD_XGBE_PHY)	+= amd-xgbe-phy.o
+ obj-$(CONFIG_MDIO_BCM_UNIMAC)	+= mdio-bcm-unimac.o
++obj-$(CONFIG_MDIO_HISI_FEMAC)	+= mdio-hisi-femac.o
++obj-$(CONFIG_MDIO_HISI_GEMAC)	+= mdio-hisi-gemac.o
+diff --git a/drivers/net/phy/mdio-hisi-femac.c b/drivers/net/phy/mdio-hisi-femac.c
+new file mode 100644
+index 0000000..186badd
+--- /dev/null
++++ b/drivers/net/phy/mdio-hisi-femac.c
+@@ -0,0 +1,166 @@
++/*
++ * Hisilicon Fast Ethernet MDIO Bus Driver
++ *
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <linux/clk.h>
++#include <linux/iopoll.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/of_address.h>
++#include <linux/of_mdio.h>
++#include <linux/platform_device.h>
++
++#define MDIO_RWCTRL		0x00
++#define MDIO_RO_DATA		0x04
++#define MDIO_WRITE		BIT(13)
++#define MDIO_RW_FINISH		BIT(15)
++#define BIT_PHY_ADDR_OFFSET	8
++#define BIT_WR_DATA_OFFSET	16
++
++struct hisi_femac_mdio_data {
++	struct clk *clk;
++	void __iomem *membase;
++};
++
++static int hisi_femac_mdio_wait_ready(struct hisi_femac_mdio_data *data)
++{
++	u32 val;
++
++	return readl_poll_timeout(data->membase + MDIO_RWCTRL,
++				  val, val & MDIO_RW_FINISH, 20, 10000);
++}
++
++static int hisi_femac_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
++{
++	struct hisi_femac_mdio_data *data = bus->priv;
++	int ret;
++
++	ret = hisi_femac_mdio_wait_ready(data);
++	if (ret)
++		return ret;
++
++	writel((mii_id << BIT_PHY_ADDR_OFFSET) | ((u32)regnum),
++		  data->membase + MDIO_RWCTRL);
++
++	ret = hisi_femac_mdio_wait_ready(data);
++	if (ret)
++		return ret;
++
++	return readl(data->membase + MDIO_RO_DATA) & 0xFFFF;
++}
++
++static int hisi_femac_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
++				 u16 value)
++{
++	struct hisi_femac_mdio_data *data = bus->priv;
++	int ret;
++
++	ret = hisi_femac_mdio_wait_ready(data);
++	if (ret)
++		return ret;
++
++	writel(MDIO_WRITE | (value << BIT_WR_DATA_OFFSET) |
++	       (mii_id << BIT_PHY_ADDR_OFFSET) | ((u32)regnum),
++	       data->membase + MDIO_RWCTRL);
++
++	return hisi_femac_mdio_wait_ready(data);
++}
++
++static int hisi_femac_mdio_probe(struct platform_device *pdev)
++{
++	struct device_node *np = pdev->dev.of_node;
++	struct mii_bus *bus;
++	struct hisi_femac_mdio_data *data;
++	struct resource *res;
++	int ret;
++
++	bus = mdiobus_alloc_size(sizeof(*data));
++	if (!bus)
++		return -ENOMEM;
++
++	bus->name = "hisi_femac_mii_bus";
++	bus->read = &hisi_femac_mdio_read;
++	bus->write = &hisi_femac_mdio_write;
++	snprintf(bus->id, MII_BUS_ID_SIZE, "%s", pdev->name);
++	bus->parent = &pdev->dev;
++
++	data = bus->priv;
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	data->membase = devm_ioremap_resource(&pdev->dev, res);
++	if (IS_ERR(data->membase)) {
++		ret = PTR_ERR(data->membase);
++		goto err_out_free_mdiobus;
++	}
++
++	data->clk = devm_clk_get(&pdev->dev, NULL);
++	if (IS_ERR(data->clk)) {
++		ret = PTR_ERR(data->clk);
++		goto err_out_free_mdiobus;
++	}
++
++	ret = clk_prepare_enable(data->clk);
++	if (ret)
++		goto err_out_free_mdiobus;
++
++	ret = of_mdiobus_register(bus, np);
++	if (ret)
++		goto err_out_disable_clk;
++
++	platform_set_drvdata(pdev, bus);
++
++	return 0;
++
++err_out_disable_clk:
++	clk_disable_unprepare(data->clk);
++err_out_free_mdiobus:
++	mdiobus_free(bus);
++	return ret;
++}
++
++static int hisi_femac_mdio_remove(struct platform_device *pdev)
++{
++	struct mii_bus *bus = platform_get_drvdata(pdev);
++	struct hisi_femac_mdio_data *data = bus->priv;
++
++	mdiobus_unregister(bus);
++	clk_disable_unprepare(data->clk);
++	mdiobus_free(bus);
++
++	return 0;
++}
++
++static const struct of_device_id hisi_femac_mdio_dt_ids[] = {
++	{ .compatible = "hisilicon,hisi-femac-mdio" },
++	{ }
++};
++MODULE_DEVICE_TABLE(of, hisi_femac_mdio_dt_ids);
++
++static struct platform_driver hisi_femac_mdio_driver = {
++	.probe = hisi_femac_mdio_probe,
++	.remove = hisi_femac_mdio_remove,
++	.driver = {
++		.name = "hisi-femac-mdio",
++		.of_match_table = hisi_femac_mdio_dt_ids,
++	},
++};
++
++module_platform_driver(hisi_femac_mdio_driver);
++
++MODULE_DESCRIPTION("Hisilicon Fast Ethernet MAC MDIO interface driver");
++MODULE_AUTHOR("Dongpo Li <lidongpo@hisilicon.com>");
++MODULE_LICENSE("GPL v2");
+diff --git a/drivers/net/phy/mdio-hisi-gemac.c b/drivers/net/phy/mdio-hisi-gemac.c
+new file mode 100644
+index 0000000..efe0897
+--- /dev/null
++++ b/drivers/net/phy/mdio-hisi-gemac.c
+@@ -0,0 +1,221 @@
++/*
++ * Hisilicon Gigabit Ethernet MDIO Bus Driver
++ *
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <linux/clk.h>
++#include <linux/iopoll.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/of_address.h>
++#include <linux/of_mdio.h>
++#include <linux/platform_device.h>
++#include <linux/reset.h>
++
++#if defined(CONFIG_ARCH_HI3519) || defined(CONFIG_ARCH_HI3519V101) || defined(CONFIG_ARCH_HI3516AV200)
++#ifdef readl
++#undef readl
++#undef writel
++#define readl		hi_readl
++#define writel		hi_writel
++#endif
++#endif
++
++#define MDIO_SINGLE_CMD		0x00
++#define MDIO_SINGLE_DATA	0x04
++#define MDIO_RDATA_STATUS	0x10
++#define BIT_PHY_ADDR_OFFSET	8
++#define MDIO_WRITE		BIT(16)
++#define MDIO_READ		BIT(17)
++#define MDIO_START		BIT(20)
++#define MDIO_START_READ		(MDIO_START | MDIO_READ)
++#define MDIO_START_WRITE	(MDIO_START | MDIO_WRITE)
++
++struct hisi_gemac_mdio_data {
++	struct clk *clk;
++	struct reset_control *phy_rst;
++	void __iomem *membase;
++};
++
++static int hisi_gemac_mdio_wait_ready(struct hisi_gemac_mdio_data *data)
++{
++	u32 val;
++
++	return readl_poll_timeout(data->membase + MDIO_SINGLE_CMD,
++				  val, !(val & MDIO_START), 20, 10000);
++}
++
++static int hisi_gemac_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
++{
++	struct hisi_gemac_mdio_data *data = bus->priv;
++	int ret;
++
++	ret = hisi_gemac_mdio_wait_ready(data);
++	if (ret)
++		return ret;
++
++	writel(MDIO_START_READ | ((u32)mii_id << BIT_PHY_ADDR_OFFSET) |
++		((u32)regnum),
++	       data->membase + MDIO_SINGLE_CMD);
++
++	ret = hisi_gemac_mdio_wait_ready(data);
++	if (ret)
++		return ret;
++
++	/* if read data is invalid, we just return 0 instead of -EAGAIN.
++	 * This can make MDIO more robust when reading PHY status.
++	 */
++	if (readl(data->membase + MDIO_RDATA_STATUS))
++		return 0;
++
++	return readl(data->membase + MDIO_SINGLE_DATA) >> 16;
++}
++
++static int hisi_gemac_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
++				 u16 value)
++{
++	struct hisi_gemac_mdio_data *data = bus->priv;
++	int ret;
++
++	ret = hisi_gemac_mdio_wait_ready(data);
++	if (ret)
++		return ret;
++
++	writel(value, data->membase + MDIO_SINGLE_DATA);
++	writel(MDIO_START_WRITE | ((u32)mii_id << BIT_PHY_ADDR_OFFSET) |
++		((u32)regnum),
++	       data->membase + MDIO_SINGLE_CMD);
++
++	return hisi_gemac_mdio_wait_ready(data);
++}
++
++static void hisi_gemac_external_phy_reset(struct hisi_gemac_mdio_data *data)
++{
++	if (data->phy_rst) {
++		/* write 0 to cancel reset */
++		reset_control_deassert(data->phy_rst);
++		msleep(50);
++
++		/* HIFONE or 98cv200 use CRG register to reset phy */
++		/* RST_BIT, write 0 to reset phy, write 1 to cancel reset */
++		reset_control_assert(data->phy_rst);
++
++		/* delay some time to ensure reset ok,
++		 * this depends on PHY hardware feature
++		 */
++		msleep(50);
++
++		/* write 0 to cancel reset */
++		reset_control_deassert(data->phy_rst);
++		/* delay some time to ensure later MDIO access */
++		msleep(50);
++	}
++}
++
++static int hisi_gemac_mdio_probe(struct platform_device *pdev)
++{
++	struct device_node *np = pdev->dev.of_node;
++	struct mii_bus *bus;
++	struct hisi_gemac_mdio_data *data;
++	struct resource *res;
++	int ret;
++
++	bus = mdiobus_alloc_size(sizeof(*data));
++	if (!bus)
++		return -ENOMEM;
++
++	bus->name = "hisi_gemac_mii_bus";
++	bus->read = &hisi_gemac_mdio_read;
++	bus->write = &hisi_gemac_mdio_write;
++	snprintf(bus->id, MII_BUS_ID_SIZE, "%s", pdev->name);
++	bus->parent = &pdev->dev;
++
++	data = bus->priv;
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	if (!res) {
++		ret = -ENXIO;
++		goto err_out_free_mdiobus;
++	}
++	data->membase = devm_ioremap(&pdev->dev, res->start,
++				     resource_size(res));
++	if (!data->membase) {
++		ret = -ENOMEM;
++		goto err_out_free_mdiobus;
++	}
++
++	data->clk = devm_clk_get(&pdev->dev, NULL);
++	if (IS_ERR(data->clk)) {
++		ret = PTR_ERR(data->clk);
++		goto err_out_free_mdiobus;
++	}
++
++	ret = clk_prepare_enable(data->clk);
++	if (ret)
++		goto err_out_free_mdiobus;
++
++	data->phy_rst = devm_reset_control_get(&pdev->dev, "phy_reset");
++	if (IS_ERR(data->phy_rst))
++		data->phy_rst = NULL;
++	hisi_gemac_external_phy_reset(data);
++
++	ret = of_mdiobus_register(bus, np);
++	if (ret)
++		goto err_out_disable_clk;
++
++	platform_set_drvdata(pdev, bus);
++
++	return 0;
++
++err_out_disable_clk:
++	clk_disable_unprepare(data->clk);
++err_out_free_mdiobus:
++	mdiobus_free(bus);
++	return ret;
++}
++
++static int hisi_gemac_mdio_remove(struct platform_device *pdev)
++{
++	struct mii_bus *bus = platform_get_drvdata(pdev);
++	struct hisi_gemac_mdio_data *data = bus->priv;
++
++	mdiobus_unregister(bus);
++	clk_disable_unprepare(data->clk);
++	mdiobus_free(bus);
++
++	return 0;
++}
++
++static const struct of_device_id hisi_gemac_mdio_dt_ids[] = {
++	{ .compatible = "hisilicon,hisi-gemac-mdio" },
++	{ }
++};
++MODULE_DEVICE_TABLE(of, hisi_gemac_mdio_dt_ids);
++
++static struct platform_driver hisi_gemac_mdio_driver = {
++	.probe = hisi_gemac_mdio_probe,
++	.remove = hisi_gemac_mdio_remove,
++	.driver = {
++		.name = "hisi-gemac-mdio",
++		.of_match_table = hisi_gemac_mdio_dt_ids,
++	},
++};
++
++module_platform_driver(hisi_gemac_mdio_driver);
++
++MODULE_DESCRIPTION("Hisilicon Gigabit Ethernet MAC MDIO interface driver");
++MODULE_AUTHOR("Dongpo Li <lidongpo@hisilicon.com>");
++MODULE_LICENSE("GPL v2");
+diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
+index 70a0d88..b599982 100644
+--- a/drivers/net/phy/phy_device.c
++++ b/drivers/net/phy/phy_device.c
+@@ -109,6 +109,53 @@ int phy_register_fixup_for_id(const char *bus_id,
+ }
+ EXPORT_SYMBOL(phy_register_fixup_for_id);
+ 
++/**
++ * phy_unregister_fixup - remove a phy_fixup from the list
++ * @bus_id: A string matches fixup->bus_id (or PHY_ANY_ID) in phy_fixup_list
++ * @phy_uid: A phy id matches fixup->phy_id (or PHY_ANY_UID) in phy_fixup_list
++ * @phy_uid_mask: Applied to phy_uid and fixup->phy_uid before comparison
++ */
++int phy_unregister_fixup(const char *bus_id, u32 phy_uid, u32 phy_uid_mask)
++{
++	struct list_head *pos, *n;
++	struct phy_fixup *fixup;
++	int ret;
++
++	ret = -ENODEV;
++
++	mutex_lock(&phy_fixup_lock);
++	list_for_each_safe(pos, n, &phy_fixup_list) {
++		fixup = list_entry(pos, struct phy_fixup, list);
++
++		if ((!strcmp(fixup->bus_id, bus_id)) &&
++		    ((fixup->phy_uid & phy_uid_mask) ==
++		     (phy_uid & phy_uid_mask))) {
++			list_del(&fixup->list);
++			kfree(fixup);
++			ret = 0;
++			break;
++		}
++	}
++	mutex_unlock(&phy_fixup_lock);
++
++	return ret;
++}
++EXPORT_SYMBOL(phy_unregister_fixup);
++
++/* Unregisters a fixup of any PHY with the UID in phy_uid */
++int phy_unregister_fixup_for_uid(u32 phy_uid, u32 phy_uid_mask)
++{
++	return phy_unregister_fixup(PHY_ANY_ID, phy_uid, phy_uid_mask);
++}
++EXPORT_SYMBOL(phy_unregister_fixup_for_uid);
++
++/* Unregisters a fixup of the PHY with id string bus_id */
++int phy_unregister_fixup_for_id(const char *bus_id)
++{
++	return phy_unregister_fixup(bus_id, PHY_ANY_UID, 0xffffffff);
++}
++EXPORT_SYMBOL(phy_unregister_fixup_for_id);
++
+ /* Returns 1 if fixup matches phydev in bus_id and phy_uid.
+  * Fixups can be set to match any in one or more fields.
+  */
+diff --git a/drivers/net/ppp/Kconfig b/drivers/net/ppp/Kconfig
+index 1373c6d..282aec4 100644
+--- a/drivers/net/ppp/Kconfig
++++ b/drivers/net/ppp/Kconfig
+@@ -149,6 +149,23 @@ config PPPOL2TP
+ 	  tunnels. L2TP is replacing PPTP for VPN uses.
+ if TTY
+ 
++config PPPOLAC
++	tristate "PPP on L2TP Access Concentrator"
++	depends on PPP && INET
++	help
++	  L2TP (RFC 2661) is a tunneling protocol widely used in virtual private
++	  networks. This driver handles L2TP data packets between a UDP socket
++	  and a PPP channel, but only permits one session per socket. Thus it is
++	  fairly simple and suited for clients.
++
++config PPPOPNS
++	tristate "PPP on PPTP Network Server"
++	depends on PPP && INET
++	help
++	  PPTP (RFC 2637) is a tunneling protocol widely used in virtual private
++	  networks. This driver handles PPTP data packets between a RAW socket
++	  and a PPP channel. It is fairly simple and easy to use.
++
+ config PPP_ASYNC
+ 	tristate "PPP support for async serial ports"
+ 	depends on PPP
+diff --git a/drivers/net/ppp/Makefile b/drivers/net/ppp/Makefile
+index a6b6297..d283d03 100644
+--- a/drivers/net/ppp/Makefile
++++ b/drivers/net/ppp/Makefile
+@@ -11,3 +11,5 @@ obj-$(CONFIG_PPP_SYNC_TTY) += ppp_synctty.o
+ obj-$(CONFIG_PPPOE) += pppox.o pppoe.o
+ obj-$(CONFIG_PPPOL2TP) += pppox.o
+ obj-$(CONFIG_PPTP) += pppox.o pptp.o
++obj-$(CONFIG_PPPOLAC) += pppox.o pppolac.o
++obj-$(CONFIG_PPPOPNS) += pppox.o pppopns.o
+diff --git a/drivers/net/ppp/pppolac.c b/drivers/net/ppp/pppolac.c
+new file mode 100644
+index 0000000..a5d3d63
+--- /dev/null
++++ b/drivers/net/ppp/pppolac.c
+@@ -0,0 +1,449 @@
++/* drivers/net/pppolac.c
++ *
++ * Driver for PPP on L2TP Access Concentrator / PPPoLAC Socket (RFC 2661)
++ *
++ * Copyright (C) 2009 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * 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.
++ */
++
++/* This driver handles L2TP data packets between a UDP socket and a PPP channel.
++ * The socket must keep connected, and only one session per socket is permitted.
++ * Sequencing of outgoing packets is controlled by LNS. Incoming packets with
++ * sequences are reordered within a sliding window of one second. Currently
++ * reordering only happens when a packet is received. It is done for simplicity
++ * since no additional locks or threads are required. This driver only works on
++ * IPv4 due to the lack of UDP encapsulation support in IPv6. */
++
++#include <linux/module.h>
++#include <linux/jiffies.h>
++#include <linux/workqueue.h>
++#include <linux/skbuff.h>
++#include <linux/file.h>
++#include <linux/netdevice.h>
++#include <linux/net.h>
++#include <linux/udp.h>
++#include <linux/ppp_defs.h>
++#include <linux/if_ppp.h>
++#include <linux/if_pppox.h>
++#include <linux/ppp_channel.h>
++#include <net/tcp_states.h>
++#include <asm/uaccess.h>
++
++#define L2TP_CONTROL_BIT	0x80
++#define L2TP_LENGTH_BIT		0x40
++#define L2TP_SEQUENCE_BIT	0x08
++#define L2TP_OFFSET_BIT		0x02
++#define L2TP_VERSION		0x02
++#define L2TP_VERSION_MASK	0x0F
++
++#define PPP_ADDR	0xFF
++#define PPP_CTRL	0x03
++
++union unaligned {
++	__u32 u32;
++} __attribute__((packed));
++
++static inline union unaligned *unaligned(void *ptr)
++{
++	return (union unaligned *)ptr;
++}
++
++struct meta {
++	__u32 sequence;
++	__u32 timestamp;
++};
++
++static inline struct meta *skb_meta(struct sk_buff *skb)
++{
++	return (struct meta *)skb->cb;
++}
++
++/******************************************************************************/
++
++static int pppolac_recv_core(struct sock *sk_udp, struct sk_buff *skb)
++{
++	struct sock *sk = (struct sock *)sk_udp->sk_user_data;
++	struct pppolac_opt *opt = &pppox_sk(sk)->proto.lac;
++	struct meta *meta = skb_meta(skb);
++	__u32 now = jiffies;
++	__u8 bits;
++	__u8 *ptr;
++
++	/* Drop the packet if L2TP header is missing. */
++	if (skb->len < sizeof(struct udphdr) + 6)
++		goto drop;
++
++	/* Put it back if it is a control packet. */
++	if (skb->data[sizeof(struct udphdr)] & L2TP_CONTROL_BIT)
++		return opt->backlog_rcv(sk_udp, skb);
++
++	/* Skip UDP header. */
++	skb_pull(skb, sizeof(struct udphdr));
++
++	/* Check the version. */
++	if ((skb->data[1] & L2TP_VERSION_MASK) != L2TP_VERSION)
++		goto drop;
++	bits = skb->data[0];
++	ptr = &skb->data[2];
++
++	/* Check the length if it is present. */
++	if (bits & L2TP_LENGTH_BIT) {
++		if ((ptr[0] << 8 | ptr[1]) != skb->len)
++			goto drop;
++		ptr += 2;
++	}
++
++	/* Skip all fields including optional ones. */
++	if (!skb_pull(skb, 6 + (bits & L2TP_SEQUENCE_BIT ? 4 : 0) +
++			(bits & L2TP_LENGTH_BIT ? 2 : 0) +
++			(bits & L2TP_OFFSET_BIT ? 2 : 0)))
++		goto drop;
++
++	/* Skip the offset padding if it is present. */
++	if (bits & L2TP_OFFSET_BIT &&
++			!skb_pull(skb, skb->data[-2] << 8 | skb->data[-1]))
++		goto drop;
++
++	/* Check the tunnel and the session. */
++	if (unaligned(ptr)->u32 != opt->local)
++		goto drop;
++
++	/* Check the sequence if it is present. */
++	if (bits & L2TP_SEQUENCE_BIT) {
++		meta->sequence = ptr[4] << 8 | ptr[5];
++		if ((__s16)(meta->sequence - opt->recv_sequence) < 0)
++			goto drop;
++	}
++
++	/* Skip PPP address and control if they are present. */
++	if (skb->len >= 2 && skb->data[0] == PPP_ADDR &&
++			skb->data[1] == PPP_CTRL)
++		skb_pull(skb, 2);
++
++	/* Fix PPP protocol if it is compressed. */
++	if (skb->len >= 1 && skb->data[0] & 1)
++		skb_push(skb, 1)[0] = 0;
++
++	/* Drop the packet if PPP protocol is missing. */
++	if (skb->len < 2)
++		goto drop;
++
++	/* Perform reordering if sequencing is enabled. */
++	atomic_set(&opt->sequencing, bits & L2TP_SEQUENCE_BIT);
++	if (bits & L2TP_SEQUENCE_BIT) {
++		struct sk_buff *skb1;
++
++		/* Insert the packet into receive queue in order. */
++		skb_set_owner_r(skb, sk);
++		skb_queue_walk(&sk->sk_receive_queue, skb1) {
++			struct meta *meta1 = skb_meta(skb1);
++			__s16 order = meta->sequence - meta1->sequence;
++			if (order == 0)
++				goto drop;
++			if (order < 0) {
++				meta->timestamp = meta1->timestamp;
++				skb_insert(skb1, skb, &sk->sk_receive_queue);
++				skb = NULL;
++				break;
++			}
++		}
++		if (skb) {
++			meta->timestamp = now;
++			skb_queue_tail(&sk->sk_receive_queue, skb);
++		}
++
++		/* Remove packets from receive queue as long as
++		 * 1. the receive buffer is full,
++		 * 2. they are queued longer than one second, or
++		 * 3. there are no missing packets before them. */
++		skb_queue_walk_safe(&sk->sk_receive_queue, skb, skb1) {
++			meta = skb_meta(skb);
++			if (atomic_read(&sk->sk_rmem_alloc) < sk->sk_rcvbuf &&
++					now - meta->timestamp < HZ &&
++					meta->sequence != opt->recv_sequence)
++				break;
++			skb_unlink(skb, &sk->sk_receive_queue);
++			opt->recv_sequence = (__u16)(meta->sequence + 1);
++			skb_orphan(skb);
++			ppp_input(&pppox_sk(sk)->chan, skb);
++		}
++		return NET_RX_SUCCESS;
++	}
++
++	/* Flush receive queue if sequencing is disabled. */
++	skb_queue_purge(&sk->sk_receive_queue);
++	skb_orphan(skb);
++	ppp_input(&pppox_sk(sk)->chan, skb);
++	return NET_RX_SUCCESS;
++drop:
++	kfree_skb(skb);
++	return NET_RX_DROP;
++}
++
++static int pppolac_recv(struct sock *sk_udp, struct sk_buff *skb)
++{
++	sock_hold(sk_udp);
++	sk_receive_skb(sk_udp, skb, 0);
++	return 0;
++}
++
++static struct sk_buff_head delivery_queue;
++
++static void pppolac_xmit_core(struct work_struct *delivery_work)
++{
++	mm_segment_t old_fs = get_fs();
++	struct sk_buff *skb;
++
++	set_fs(KERNEL_DS);
++	while ((skb = skb_dequeue(&delivery_queue))) {
++		struct sock *sk_udp = skb->sk;
++		struct kvec iov = {.iov_base = skb->data, .iov_len = skb->len};
++		struct msghdr msg = {
++			.msg_iov = (struct iovec *)&iov,
++			.msg_iovlen = 1,
++			.msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT,
++		};
++		sk_udp->sk_prot->sendmsg(NULL, sk_udp, &msg, skb->len);
++		kfree_skb(skb);
++	}
++	set_fs(old_fs);
++}
++
++static DECLARE_WORK(delivery_work, pppolac_xmit_core);
++
++static int pppolac_xmit(struct ppp_channel *chan, struct sk_buff *skb)
++{
++	struct sock *sk_udp = (struct sock *)chan->private;
++	struct pppolac_opt *opt = &pppox_sk(sk_udp->sk_user_data)->proto.lac;
++
++	/* Install PPP address and control. */
++	skb_push(skb, 2);
++	skb->data[0] = PPP_ADDR;
++	skb->data[1] = PPP_CTRL;
++
++	/* Install L2TP header. */
++	if (atomic_read(&opt->sequencing)) {
++		skb_push(skb, 10);
++		skb->data[0] = L2TP_SEQUENCE_BIT;
++		skb->data[6] = opt->xmit_sequence >> 8;
++		skb->data[7] = opt->xmit_sequence;
++		skb->data[8] = 0;
++		skb->data[9] = 0;
++		opt->xmit_sequence++;
++	} else {
++		skb_push(skb, 6);
++		skb->data[0] = 0;
++	}
++	skb->data[1] = L2TP_VERSION;
++	unaligned(&skb->data[2])->u32 = opt->remote;
++
++	/* Now send the packet via the delivery queue. */
++	skb_set_owner_w(skb, sk_udp);
++	skb_queue_tail(&delivery_queue, skb);
++	schedule_work(&delivery_work);
++	return 1;
++}
++
++/******************************************************************************/
++
++static struct ppp_channel_ops pppolac_channel_ops = {
++	.start_xmit = pppolac_xmit,
++};
++
++static int pppolac_connect(struct socket *sock, struct sockaddr *useraddr,
++	int addrlen, int flags)
++{
++	struct sock *sk = sock->sk;
++	struct pppox_sock *po = pppox_sk(sk);
++	struct sockaddr_pppolac *addr = (struct sockaddr_pppolac *)useraddr;
++	struct socket *sock_udp = NULL;
++	struct sock *sk_udp;
++	int error;
++
++	if (addrlen != sizeof(struct sockaddr_pppolac) ||
++			!addr->local.tunnel || !addr->local.session ||
++			!addr->remote.tunnel || !addr->remote.session) {
++		return -EINVAL;
++	}
++
++	lock_sock(sk);
++	error = -EALREADY;
++	if (sk->sk_state != PPPOX_NONE)
++		goto out;
++
++	sock_udp = sockfd_lookup(addr->udp_socket, &error);
++	if (!sock_udp)
++		goto out;
++	sk_udp = sock_udp->sk;
++	lock_sock(sk_udp);
++
++	/* Remove this check when IPv6 supports UDP encapsulation. */
++	error = -EAFNOSUPPORT;
++	if (sk_udp->sk_family != AF_INET)
++		goto out;
++	error = -EPROTONOSUPPORT;
++	if (sk_udp->sk_protocol != IPPROTO_UDP)
++		goto out;
++	error = -EDESTADDRREQ;
++	if (sk_udp->sk_state != TCP_ESTABLISHED)
++		goto out;
++	error = -EBUSY;
++	if (udp_sk(sk_udp)->encap_type || sk_udp->sk_user_data)
++		goto out;
++	if (!sk_udp->sk_bound_dev_if) {
++		struct dst_entry *dst = sk_dst_get(sk_udp);
++		error = -ENODEV;
++		if (!dst)
++			goto out;
++		sk_udp->sk_bound_dev_if = dst->dev->ifindex;
++		dst_release(dst);
++	}
++
++	po->chan.hdrlen = 12;
++	po->chan.private = sk_udp;
++	po->chan.ops = &pppolac_channel_ops;
++	po->chan.mtu = PPP_MRU - 80;
++	po->proto.lac.local = unaligned(&addr->local)->u32;
++	po->proto.lac.remote = unaligned(&addr->remote)->u32;
++	atomic_set(&po->proto.lac.sequencing, 1);
++	po->proto.lac.backlog_rcv = sk_udp->sk_backlog_rcv;
++
++	error = ppp_register_channel(&po->chan);
++	if (error)
++		goto out;
++
++	sk->sk_state = PPPOX_CONNECTED;
++	udp_sk(sk_udp)->encap_type = UDP_ENCAP_L2TPINUDP;
++	udp_sk(sk_udp)->encap_rcv = pppolac_recv;
++	sk_udp->sk_backlog_rcv = pppolac_recv_core;
++	sk_udp->sk_user_data = sk;
++out:
++	if (sock_udp) {
++		release_sock(sk_udp);
++		if (error)
++			sockfd_put(sock_udp);
++	}
++	release_sock(sk);
++	return error;
++}
++
++static int pppolac_release(struct socket *sock)
++{
++	struct sock *sk = sock->sk;
++
++	if (!sk)
++		return 0;
++
++	lock_sock(sk);
++	if (sock_flag(sk, SOCK_DEAD)) {
++		release_sock(sk);
++		return -EBADF;
++	}
++
++	if (sk->sk_state != PPPOX_NONE) {
++		struct sock *sk_udp = (struct sock *)pppox_sk(sk)->chan.private;
++		lock_sock(sk_udp);
++		skb_queue_purge(&sk->sk_receive_queue);
++		pppox_unbind_sock(sk);
++		udp_sk(sk_udp)->encap_type = 0;
++		udp_sk(sk_udp)->encap_rcv = NULL;
++		sk_udp->sk_backlog_rcv = pppox_sk(sk)->proto.lac.backlog_rcv;
++		sk_udp->sk_user_data = NULL;
++		release_sock(sk_udp);
++		sockfd_put(sk_udp->sk_socket);
++	}
++
++	sock_orphan(sk);
++	sock->sk = NULL;
++	release_sock(sk);
++	sock_put(sk);
++	return 0;
++}
++
++/******************************************************************************/
++
++static struct proto pppolac_proto = {
++	.name = "PPPOLAC",
++	.owner = THIS_MODULE,
++	.obj_size = sizeof(struct pppox_sock),
++};
++
++static struct proto_ops pppolac_proto_ops = {
++	.family = PF_PPPOX,
++	.owner = THIS_MODULE,
++	.release = pppolac_release,
++	.bind = sock_no_bind,
++	.connect = pppolac_connect,
++	.socketpair = sock_no_socketpair,
++	.accept = sock_no_accept,
++	.getname = sock_no_getname,
++	.poll = sock_no_poll,
++	.ioctl = pppox_ioctl,
++	.listen = sock_no_listen,
++	.shutdown = sock_no_shutdown,
++	.setsockopt = sock_no_setsockopt,
++	.getsockopt = sock_no_getsockopt,
++	.sendmsg = sock_no_sendmsg,
++	.recvmsg = sock_no_recvmsg,
++	.mmap = sock_no_mmap,
++};
++
++static int pppolac_create(struct net *net, struct socket *sock)
++{
++	struct sock *sk;
++
++	sk = sk_alloc(net, PF_PPPOX, GFP_KERNEL, &pppolac_proto);
++	if (!sk)
++		return -ENOMEM;
++
++	sock_init_data(sock, sk);
++	sock->state = SS_UNCONNECTED;
++	sock->ops = &pppolac_proto_ops;
++	sk->sk_protocol = PX_PROTO_OLAC;
++	sk->sk_state = PPPOX_NONE;
++	return 0;
++}
++
++/******************************************************************************/
++
++static struct pppox_proto pppolac_pppox_proto = {
++	.create = pppolac_create,
++	.owner = THIS_MODULE,
++};
++
++static int __init pppolac_init(void)
++{
++	int error;
++
++	error = proto_register(&pppolac_proto, 0);
++	if (error)
++		return error;
++
++	error = register_pppox_proto(PX_PROTO_OLAC, &pppolac_pppox_proto);
++	if (error)
++		proto_unregister(&pppolac_proto);
++	else
++		skb_queue_head_init(&delivery_queue);
++	return error;
++}
++
++static void __exit pppolac_exit(void)
++{
++	unregister_pppox_proto(PX_PROTO_OLAC);
++	proto_unregister(&pppolac_proto);
++}
++
++module_init(pppolac_init);
++module_exit(pppolac_exit);
++
++MODULE_DESCRIPTION("PPP on L2TP Access Concentrator (PPPoLAC)");
++MODULE_AUTHOR("Chia-chi Yeh <chiachi@android.com>");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/net/ppp/pppopns.c b/drivers/net/ppp/pppopns.c
+new file mode 100644
+index 0000000..dc15f97
+--- /dev/null
++++ b/drivers/net/ppp/pppopns.c
+@@ -0,0 +1,428 @@
++/* drivers/net/pppopns.c
++ *
++ * Driver for PPP on PPTP Network Server / PPPoPNS Socket (RFC 2637)
++ *
++ * Copyright (C) 2009 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * 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.
++ */
++
++/* This driver handles PPTP data packets between a RAW socket and a PPP channel.
++ * The socket is created in the kernel space and connected to the same address
++ * of the control socket. Outgoing packets are always sent with sequences but
++ * without acknowledgements. Incoming packets with sequences are reordered
++ * within a sliding window of one second. Currently reordering only happens when
++ * a packet is received. It is done for simplicity since no additional locks or
++ * threads are required. This driver should work on both IPv4 and IPv6. */
++
++#include <linux/module.h>
++#include <linux/jiffies.h>
++#include <linux/workqueue.h>
++#include <linux/skbuff.h>
++#include <linux/file.h>
++#include <linux/netdevice.h>
++#include <linux/net.h>
++#include <linux/ppp_defs.h>
++#include <linux/if.h>
++#include <linux/if_ppp.h>
++#include <linux/if_pppox.h>
++#include <linux/ppp_channel.h>
++#include <asm/uaccess.h>
++
++#define GRE_HEADER_SIZE		8
++
++#define PPTP_GRE_BITS		htons(0x2001)
++#define PPTP_GRE_BITS_MASK	htons(0xEF7F)
++#define PPTP_GRE_SEQ_BIT	htons(0x1000)
++#define PPTP_GRE_ACK_BIT	htons(0x0080)
++#define PPTP_GRE_TYPE		htons(0x880B)
++
++#define PPP_ADDR	0xFF
++#define PPP_CTRL	0x03
++
++struct header {
++	__u16	bits;
++	__u16	type;
++	__u16	length;
++	__u16	call;
++	__u32	sequence;
++} __attribute__((packed));
++
++struct meta {
++	__u32 sequence;
++	__u32 timestamp;
++};
++
++static inline struct meta *skb_meta(struct sk_buff *skb)
++{
++	return (struct meta *)skb->cb;
++}
++
++/******************************************************************************/
++
++static int pppopns_recv_core(struct sock *sk_raw, struct sk_buff *skb)
++{
++	struct sock *sk = (struct sock *)sk_raw->sk_user_data;
++	struct pppopns_opt *opt = &pppox_sk(sk)->proto.pns;
++	struct meta *meta = skb_meta(skb);
++	__u32 now = jiffies;
++	struct header *hdr;
++
++	/* Skip transport header */
++	skb_pull(skb, skb_transport_header(skb) - skb->data);
++
++	/* Drop the packet if GRE header is missing. */
++	if (skb->len < GRE_HEADER_SIZE)
++		goto drop;
++	hdr = (struct header *)skb->data;
++
++	/* Check the header. */
++	if (hdr->type != PPTP_GRE_TYPE || hdr->call != opt->local ||
++			(hdr->bits & PPTP_GRE_BITS_MASK) != PPTP_GRE_BITS)
++		goto drop;
++
++	/* Skip all fields including optional ones. */
++	if (!skb_pull(skb, GRE_HEADER_SIZE +
++			(hdr->bits & PPTP_GRE_SEQ_BIT ? 4 : 0) +
++			(hdr->bits & PPTP_GRE_ACK_BIT ? 4 : 0)))
++		goto drop;
++
++	/* Check the length. */
++	if (skb->len != ntohs(hdr->length))
++		goto drop;
++
++	/* Check the sequence if it is present. */
++	if (hdr->bits & PPTP_GRE_SEQ_BIT) {
++		meta->sequence = ntohl(hdr->sequence);
++		if ((__s32)(meta->sequence - opt->recv_sequence) < 0)
++			goto drop;
++	}
++
++	/* Skip PPP address and control if they are present. */
++	if (skb->len >= 2 && skb->data[0] == PPP_ADDR &&
++			skb->data[1] == PPP_CTRL)
++		skb_pull(skb, 2);
++
++	/* Fix PPP protocol if it is compressed. */
++	if (skb->len >= 1 && skb->data[0] & 1)
++		skb_push(skb, 1)[0] = 0;
++
++	/* Drop the packet if PPP protocol is missing. */
++	if (skb->len < 2)
++		goto drop;
++
++	/* Perform reordering if sequencing is enabled. */
++	if (hdr->bits & PPTP_GRE_SEQ_BIT) {
++		struct sk_buff *skb1;
++
++		/* Insert the packet into receive queue in order. */
++		skb_set_owner_r(skb, sk);
++		skb_queue_walk(&sk->sk_receive_queue, skb1) {
++			struct meta *meta1 = skb_meta(skb1);
++			__s32 order = meta->sequence - meta1->sequence;
++			if (order == 0)
++				goto drop;
++			if (order < 0) {
++				meta->timestamp = meta1->timestamp;
++				skb_insert(skb1, skb, &sk->sk_receive_queue);
++				skb = NULL;
++				break;
++			}
++		}
++		if (skb) {
++			meta->timestamp = now;
++			skb_queue_tail(&sk->sk_receive_queue, skb);
++		}
++
++		/* Remove packets from receive queue as long as
++		 * 1. the receive buffer is full,
++		 * 2. they are queued longer than one second, or
++		 * 3. there are no missing packets before them. */
++		skb_queue_walk_safe(&sk->sk_receive_queue, skb, skb1) {
++			meta = skb_meta(skb);
++			if (atomic_read(&sk->sk_rmem_alloc) < sk->sk_rcvbuf &&
++					now - meta->timestamp < HZ &&
++					meta->sequence != opt->recv_sequence)
++				break;
++			skb_unlink(skb, &sk->sk_receive_queue);
++			opt->recv_sequence = meta->sequence + 1;
++			skb_orphan(skb);
++			ppp_input(&pppox_sk(sk)->chan, skb);
++		}
++		return NET_RX_SUCCESS;
++	}
++
++	/* Flush receive queue if sequencing is disabled. */
++	skb_queue_purge(&sk->sk_receive_queue);
++	skb_orphan(skb);
++	ppp_input(&pppox_sk(sk)->chan, skb);
++	return NET_RX_SUCCESS;
++drop:
++	kfree_skb(skb);
++	return NET_RX_DROP;
++}
++
++static void pppopns_recv(struct sock *sk_raw)
++{
++	struct sk_buff *skb;
++	while ((skb = skb_dequeue(&sk_raw->sk_receive_queue))) {
++		sock_hold(sk_raw);
++		sk_receive_skb(sk_raw, skb, 0);
++	}
++}
++
++static struct sk_buff_head delivery_queue;
++
++static void pppopns_xmit_core(struct work_struct *delivery_work)
++{
++	mm_segment_t old_fs = get_fs();
++	struct sk_buff *skb;
++
++	set_fs(KERNEL_DS);
++	while ((skb = skb_dequeue(&delivery_queue))) {
++		struct sock *sk_raw = skb->sk;
++		struct kvec iov = {.iov_base = skb->data, .iov_len = skb->len};
++		struct msghdr msg = {
++			.msg_iov = (struct iovec *)&iov,
++			.msg_iovlen = 1,
++			.msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT,
++		};
++		sk_raw->sk_prot->sendmsg(NULL, sk_raw, &msg, skb->len);
++		kfree_skb(skb);
++	}
++	set_fs(old_fs);
++}
++
++static DECLARE_WORK(delivery_work, pppopns_xmit_core);
++
++static int pppopns_xmit(struct ppp_channel *chan, struct sk_buff *skb)
++{
++	struct sock *sk_raw = (struct sock *)chan->private;
++	struct pppopns_opt *opt = &pppox_sk(sk_raw->sk_user_data)->proto.pns;
++	struct header *hdr;
++	__u16 length;
++
++	/* Install PPP address and control. */
++	skb_push(skb, 2);
++	skb->data[0] = PPP_ADDR;
++	skb->data[1] = PPP_CTRL;
++	length = skb->len;
++
++	/* Install PPTP GRE header. */
++	hdr = (struct header *)skb_push(skb, 12);
++	hdr->bits = PPTP_GRE_BITS | PPTP_GRE_SEQ_BIT;
++	hdr->type = PPTP_GRE_TYPE;
++	hdr->length = htons(length);
++	hdr->call = opt->remote;
++	hdr->sequence = htonl(opt->xmit_sequence);
++	opt->xmit_sequence++;
++
++	/* Now send the packet via the delivery queue. */
++	skb_set_owner_w(skb, sk_raw);
++	skb_queue_tail(&delivery_queue, skb);
++	schedule_work(&delivery_work);
++	return 1;
++}
++
++/******************************************************************************/
++
++static struct ppp_channel_ops pppopns_channel_ops = {
++	.start_xmit = pppopns_xmit,
++};
++
++static int pppopns_connect(struct socket *sock, struct sockaddr *useraddr,
++	int addrlen, int flags)
++{
++	struct sock *sk = sock->sk;
++	struct pppox_sock *po = pppox_sk(sk);
++	struct sockaddr_pppopns *addr = (struct sockaddr_pppopns *)useraddr;
++	struct sockaddr_storage ss;
++	struct socket *sock_tcp = NULL;
++	struct socket *sock_raw = NULL;
++	struct sock *sk_tcp;
++	struct sock *sk_raw;
++	int error;
++
++	if (addrlen != sizeof(struct sockaddr_pppopns))
++		return -EINVAL;
++
++	lock_sock(sk);
++	error = -EALREADY;
++	if (sk->sk_state != PPPOX_NONE)
++		goto out;
++
++	sock_tcp = sockfd_lookup(addr->tcp_socket, &error);
++	if (!sock_tcp)
++		goto out;
++	sk_tcp = sock_tcp->sk;
++	error = -EPROTONOSUPPORT;
++	if (sk_tcp->sk_protocol != IPPROTO_TCP)
++		goto out;
++	addrlen = sizeof(struct sockaddr_storage);
++	error = kernel_getpeername(sock_tcp, (struct sockaddr *)&ss, &addrlen);
++	if (error)
++		goto out;
++	if (!sk_tcp->sk_bound_dev_if) {
++		struct dst_entry *dst = sk_dst_get(sk_tcp);
++		error = -ENODEV;
++		if (!dst)
++			goto out;
++		sk_tcp->sk_bound_dev_if = dst->dev->ifindex;
++		dst_release(dst);
++	}
++
++	error = sock_create(ss.ss_family, SOCK_RAW, IPPROTO_GRE, &sock_raw);
++	if (error)
++		goto out;
++	sk_raw = sock_raw->sk;
++	sk_raw->sk_bound_dev_if = sk_tcp->sk_bound_dev_if;
++	error = kernel_connect(sock_raw, (struct sockaddr *)&ss, addrlen, 0);
++	if (error)
++		goto out;
++
++	po->chan.hdrlen = 14;
++	po->chan.private = sk_raw;
++	po->chan.ops = &pppopns_channel_ops;
++	po->chan.mtu = PPP_MRU - 80;
++	po->proto.pns.local = addr->local;
++	po->proto.pns.remote = addr->remote;
++	po->proto.pns.data_ready = sk_raw->sk_data_ready;
++	po->proto.pns.backlog_rcv = sk_raw->sk_backlog_rcv;
++
++	error = ppp_register_channel(&po->chan);
++	if (error)
++		goto out;
++
++	sk->sk_state = PPPOX_CONNECTED;
++	lock_sock(sk_raw);
++	sk_raw->sk_data_ready = pppopns_recv;
++	sk_raw->sk_backlog_rcv = pppopns_recv_core;
++	sk_raw->sk_user_data = sk;
++	release_sock(sk_raw);
++out:
++	if (sock_tcp)
++		sockfd_put(sock_tcp);
++	if (error && sock_raw)
++		sock_release(sock_raw);
++	release_sock(sk);
++	return error;
++}
++
++static int pppopns_release(struct socket *sock)
++{
++	struct sock *sk = sock->sk;
++
++	if (!sk)
++		return 0;
++
++	lock_sock(sk);
++	if (sock_flag(sk, SOCK_DEAD)) {
++		release_sock(sk);
++		return -EBADF;
++	}
++
++	if (sk->sk_state != PPPOX_NONE) {
++		struct sock *sk_raw = (struct sock *)pppox_sk(sk)->chan.private;
++		lock_sock(sk_raw);
++		skb_queue_purge(&sk->sk_receive_queue);
++		pppox_unbind_sock(sk);
++		sk_raw->sk_data_ready = pppox_sk(sk)->proto.pns.data_ready;
++		sk_raw->sk_backlog_rcv = pppox_sk(sk)->proto.pns.backlog_rcv;
++		sk_raw->sk_user_data = NULL;
++		release_sock(sk_raw);
++		sock_release(sk_raw->sk_socket);
++	}
++
++	sock_orphan(sk);
++	sock->sk = NULL;
++	release_sock(sk);
++	sock_put(sk);
++	return 0;
++}
++
++/******************************************************************************/
++
++static struct proto pppopns_proto = {
++	.name = "PPPOPNS",
++	.owner = THIS_MODULE,
++	.obj_size = sizeof(struct pppox_sock),
++};
++
++static struct proto_ops pppopns_proto_ops = {
++	.family = PF_PPPOX,
++	.owner = THIS_MODULE,
++	.release = pppopns_release,
++	.bind = sock_no_bind,
++	.connect = pppopns_connect,
++	.socketpair = sock_no_socketpair,
++	.accept = sock_no_accept,
++	.getname = sock_no_getname,
++	.poll = sock_no_poll,
++	.ioctl = pppox_ioctl,
++	.listen = sock_no_listen,
++	.shutdown = sock_no_shutdown,
++	.setsockopt = sock_no_setsockopt,
++	.getsockopt = sock_no_getsockopt,
++	.sendmsg = sock_no_sendmsg,
++	.recvmsg = sock_no_recvmsg,
++	.mmap = sock_no_mmap,
++};
++
++static int pppopns_create(struct net *net, struct socket *sock)
++{
++	struct sock *sk;
++
++	sk = sk_alloc(net, PF_PPPOX, GFP_KERNEL, &pppopns_proto);
++	if (!sk)
++		return -ENOMEM;
++
++	sock_init_data(sock, sk);
++	sock->state = SS_UNCONNECTED;
++	sock->ops = &pppopns_proto_ops;
++	sk->sk_protocol = PX_PROTO_OPNS;
++	sk->sk_state = PPPOX_NONE;
++	return 0;
++}
++
++/******************************************************************************/
++
++static struct pppox_proto pppopns_pppox_proto = {
++	.create = pppopns_create,
++	.owner = THIS_MODULE,
++};
++
++static int __init pppopns_init(void)
++{
++	int error;
++
++	error = proto_register(&pppopns_proto, 0);
++	if (error)
++		return error;
++
++	error = register_pppox_proto(PX_PROTO_OPNS, &pppopns_pppox_proto);
++	if (error)
++		proto_unregister(&pppopns_proto);
++	else
++		skb_queue_head_init(&delivery_queue);
++	return error;
++}
++
++static void __exit pppopns_exit(void)
++{
++	unregister_pppox_proto(PX_PROTO_OPNS);
++	proto_unregister(&pppopns_proto);
++}
++
++module_init(pppopns_init);
++module_exit(pppopns_exit);
++
++MODULE_DESCRIPTION("PPP on PPTP Network Server (PPPoPNS)");
++MODULE_AUTHOR("Chia-chi Yeh <chiachi@android.com>");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/net/tun.c b/drivers/net/tun.c
+index 9dd3746..cae87f0 100644
+--- a/drivers/net/tun.c
++++ b/drivers/net/tun.c
+@@ -1881,6 +1881,12 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
+ 	unsigned int ifindex;
+ 	int ret;
+ 
++#ifdef CONFIG_ANDROID_PARANOID_NETWORK
++	if (cmd != TUNGETIFF && !capable(CAP_NET_ADMIN)) {
++		return -EPERM;
++	}
++#endif
++
+ 	if (cmd == TUNSETIFF || cmd == TUNSETQUEUE || _IOC_TYPE(cmd) == 0x89) {
+ 		if (copy_from_user(&ifr, argp, ifreq_len))
+ 			return -EFAULT;
+diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
+index 16604bd..710733f 100644
+--- a/drivers/net/wireless/Kconfig
++++ b/drivers/net/wireless/Kconfig
+@@ -265,6 +265,11 @@ config MWL8K
+ 	  To compile this driver as a module, choose M here: the module
+ 	  will be called mwl8k.  If unsure, say N.
+ 
++config WIFI_CONTROL_FUNC
++	bool "Enable WiFi control function abstraction"
++	help
++	  Enables Power/Reset/Carddetect function abstraction
++
+ source "drivers/net/wireless/ath/Kconfig"
+ source "drivers/net/wireless/b43/Kconfig"
+ source "drivers/net/wireless/b43legacy/Kconfig"
+diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
+index d134710..821f6b5 100644
+--- a/drivers/of/fdt.c
++++ b/drivers/of/fdt.c
+@@ -885,36 +885,66 @@ int __init early_init_dt_scan_memory(unsigned long node, const char *uname,
+ 	return 0;
+ }
+ 
++/*
++ * Convert configs to something easy to use in C code
++ */
++#if defined(CONFIG_CMDLINE_FORCE)
++static const int overwrite_incoming_cmdline = 1;
++static const int read_dt_cmdline;
++static const int concat_cmdline;
++#elif defined(CONFIG_CMDLINE_EXTEND)
++static const int overwrite_incoming_cmdline;
++static const int read_dt_cmdline = 1;
++static const int concat_cmdline = 1;
++#else /* CMDLINE_FROM_BOOTLOADER */
++static const int overwrite_incoming_cmdline;
++static const int read_dt_cmdline = 1;
++static const int concat_cmdline;
++#endif
++
++#ifdef CONFIG_CMDLINE
++static const char *config_cmdline = CONFIG_CMDLINE;
++#else
++static const char *config_cmdline = "";
++#endif
++
+ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname,
+ 				     int depth, void *data)
+ {
+-	int l;
+-	const char *p;
++	int l = 0;
++	const char *p = NULL;
++	char *cmdline = data;
+ 
+ 	pr_debug("search \"chosen\", depth: %d, uname: %s\n", depth, uname);
+ 
+-	if (depth != 1 || !data ||
++	if (depth != 1 || !cmdline ||
+ 	    (strcmp(uname, "chosen") != 0 && strcmp(uname, "chosen@0") != 0))
+ 		return 0;
+ 
+ 	early_init_dt_check_for_initrd(node);
+ 
+-	/* Retrieve command line */
+-	p = of_get_flat_dt_prop(node, "bootargs", &l);
+-	if (p != NULL && l > 0)
+-		strlcpy(data, p, min((int)l, COMMAND_LINE_SIZE));
+-
+-	/*
+-	 * CONFIG_CMDLINE is meant to be a default in case nothing else
+-	 * managed to set the command line, unless CONFIG_CMDLINE_FORCE
+-	 * is set in which case we override whatever was found earlier.
+-	 */
+-#ifdef CONFIG_CMDLINE
+-#ifndef CONFIG_CMDLINE_FORCE
+-	if (!((char *)data)[0])
+-#endif
+-		strlcpy(data, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
+-#endif /* CONFIG_CMDLINE */
++	/* Put CONFIG_CMDLINE in if forced or if data had nothing in it to start */
++	if (overwrite_incoming_cmdline || !cmdline[0])
++		strlcpy(cmdline, config_cmdline, COMMAND_LINE_SIZE);
++
++	/* Retrieve command line unless forcing */
++	if (read_dt_cmdline)
++		p = of_get_flat_dt_prop(node, "bootargs", &l);
++
++	if (p != NULL && l > 0) {
++		if (concat_cmdline) {
++			int cmdline_len;
++			int copy_len;
++			strlcat(cmdline, " ", COMMAND_LINE_SIZE);
++			cmdline_len = strlen(cmdline);
++			copy_len = COMMAND_LINE_SIZE - cmdline_len - 1;
++			copy_len = min((int)l, copy_len);
++			strncpy(cmdline + cmdline_len, p, copy_len);
++			cmdline[cmdline_len + copy_len] = '\0';
++		} else {
++			strlcpy(cmdline, p, min((int)l, COMMAND_LINE_SIZE));
++		}
++	}
+ 
+ 	pr_debug("Command line is: %s\n", (char*)data);
+ 
+diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c
+index 1bd4305..a925f29 100644
+--- a/drivers/of/of_mdio.c
++++ b/drivers/of/of_mdio.c
+@@ -18,6 +18,7 @@
+ #include <linux/of.h>
+ #include <linux/of_irq.h>
+ #include <linux/of_mdio.h>
++#include <linux/of_net.h>
+ #include <linux/module.h>
+ 
+ MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
+@@ -231,6 +232,41 @@ struct phy_device *of_phy_connect(struct net_device *dev,
+ EXPORT_SYMBOL(of_phy_connect);
+ 
+ /**
++ * of_phy_get_and_connect
++ * - Get phy node and connect to the phy described in the device tree
++ * @dev: pointer to net_device claiming the phy
++ * @np: Pointer to device tree node for the net_device claiming the phy
++ * @hndlr: Link state callback for the network device
++ *
++ * If successful, returns a pointer to the phy_device with the embedded
++ * struct device refcount incremented by one, or NULL on failure. The
++ * refcount must be dropped by calling phy_disconnect() or phy_detach().
++ */
++struct phy_device *of_phy_get_and_connect(struct net_device *dev,
++					  struct device_node *np,
++					  void (*hndlr)(struct net_device *))
++{
++	phy_interface_t iface;
++	struct device_node *phy_np;
++	struct phy_device *phy;
++
++	iface = of_get_phy_mode(np);
++	if (iface < 0)
++		return NULL;
++
++	phy_np = of_parse_phandle(np, "phy-handle", 0);
++	if (!phy_np)
++		return NULL;
++
++	phy = of_phy_connect(dev, phy_np, hndlr, 0, iface);
++
++	of_node_put(phy_np);
++
++	return phy;
++}
++EXPORT_SYMBOL(of_phy_get_and_connect);
++
++/**
+  * of_phy_attach - Attach to a PHY without starting the state machine
+  * @dev: pointer to net_device claiming the phy
+  * @phy_np: Node pointer for the PHY
+diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
+index e04fe2d..0db2477 100644
+--- a/drivers/pci/Makefile
++++ b/drivers/pci/Makefile
+@@ -9,6 +9,7 @@ obj-$(CONFIG_PROC_FS) += proc.o
+ obj-$(CONFIG_SYSFS) += slot.o
+ 
+ obj-$(CONFIG_PCI_QUIRKS) += quirks.o
++obj-$(CONFIG_HIPCIE) += hipcie/
+ 
+ # Build PCI Express stuff if needed
+ obj-$(CONFIG_PCIEPORTBUS) += pcie/
+diff --git a/drivers/pci/hipcie/Kconfig b/drivers/pci/hipcie/Kconfig
+new file mode 100644
+index 0000000..4e5cfc6
+--- /dev/null
++++ b/drivers/pci/hipcie/Kconfig
+@@ -0,0 +1,119 @@
++menuconfig HIPCIE
++	bool "Hisilicon PCI Express support"
++	depends on PCI && (ARCH_HI3519 || ARCH_HI3519V101 || ARCH_HI3559 || ARCH_HI3556 || ARCH_HI3516AV200 || ARCH_HI3531D)
++	default y if PCI
++	default n if !PCI
++	help
++	Hisilicon PCI Express support
++	Choose this selection to support PCI Express uses.
++
++if HIPCIE
++
++menu "PCI Express configs"
++
++config PCIE0_SEL
++        int "PCI Express controller 0 sel"
++        range 0 1
++        default "0" if !PCI
++        default "1" if PCI
++        depends on PCI
++        help
++        PCI Express controller 0 sel.
++        Set 0 to disable controller 0 as RC.
++        set 1 to enable controller 0 to work at RC mode.
++
++config PCIE0_DEVICES_MEM_SIZE
++        hex "Total memory size of PCI Express EP devices"
++        range 0x0 0x10000000 if ARCH_HI3519
++        range 0x0 0x10000000 if ARCH_HI3519V101
++        range 0x0 0x10000000 if ARCH_HI3516AV200
++	range 0x0 0x10000000 if ARCH_HI3559
++	range 0x0 0x10000000 if ARCH_HI3556
++	range 0x0 0x10000000 if ARCH_HI3531D
++        default "0x8000000" if ARCH_HI3519
++        default "0x8000000" if ARCH_HI3519V101
++        default "0x8000000" if ARCH_HI3516AV200
++	default "0x8000000" if ARCH_HI3559
++	default "0x8000000" if ARCH_HI3556
++	default "0x8000000" if ARCH_HI3531D
++        depends on PCI
++        help
++        Memory available for all pcie EP devices in pci subsystem.
++        Hisilicon PCI Express controller provides up to 256MBytes address
++	space for its subordinated devices.
++	No IO address space is reserved, since to support PCI legacy devices
++	which required IO address space.
++        You can change this value as you please.
++
++config PCIE0_DEVICES_CONFIG_SIZE
++        hex "Sum of configuration header size mapped for all PCIe EP devices"
++        range 0x0 0x10000000   if ARCH_HI3519
++        range 0x0 0x10000000   if ARCH_HI3519V101
++        range 0x0 0x10000000   if ARCH_HI3516AV200
++	range 0x0 0x10000000   if ARCH_HI3559
++	range 0x0 0x10000000   if ARCH_HI3556
++	range 0x0 0x10000000    if ARCH_HI3531D
++	default 0x800000       if ARCH_HI3519
++	default 0x800000       if ARCH_HI3519V101
++        default 0x800000       if ARCH_HI3516AV200
++	default 0x800000       if ARCH_HI3559
++	default 0x800000       if ARCH_HI3556
++	default 0x8000000      if ARCH_HI3531D
++        depends on PCI
++        help
++	As to the PCIe address space configuration, address space for all EPs
++	is up to 256Mbytes. But, normally people do not used that much. Each
++	EP device will use 4Kbytes virtual address space for PCIe configuration header.
++	Normally people will not use that much(256MB).
++	Enlarge this value will require more system virtual address space.
++	The DEFAULT value(8MB) is enough for most applications.
++
++config LIMIT_MAX_RD_REQ_SIZE
++	bool "limit pcie max read request size"
++	default y
++	depends on PCI && HIPCIE
++	help
++	The default max read request size of pcie device is 512 Byte. When pcie use
++	the card of pcie-to-sata to connect to the sata disk, with the default max read
++	request size value of 512 byte, would cause the low bandwidth of VDP. If you enable
++	the LIMIT_MAX_RD_REQ_SIZE config, the max read request size of pcie device would be
++	set to 128 byte, and the problem of VDP low band width also be avoided.
++
++config PCIE1_SEL
++	int "PCI Express controller 1 sel"
++	range 0 1
++	default "0"
++	depends on (PCI && (ARCH_GODNET || ARCH_HI3531D))
++	help
++	PCI Express controller 1 sel.
++	Set 0 to disable controller 1,
++	set 1 to enable controller 1 to work at RC mode.
++
++config PCIE1_DEVICES_MEM_SIZE
++	hex "Total memory size of PCI Express EP devices"
++	range 0x0 0x8000000
++	default "0x7800000"
++	depends on (PCI && ARCH_HI3531D)
++	help
++	All memory size required by all devices in pci subsystem.
++	Hisilicon PCI Express controller provide up to 128M memory
++	and io size for device.
++	Here we set memory size up to 120M, means that io size has at least 8M
++	You can change this depend on you device connected
++	to Hisilicon PCI Express controller.
++
++config PCIE1_DEVICES_CONFIG_SIZE
++	hex "Total configuration header size of PCI Express system devices"
++	range 0x0 0x10000000
++	default 0x800000
++	depends on (PCI && ARCH_HI3531D)
++	help
++	All configuration size required by devices connnect to
++	Hisilicon PCI Express controller.
++	NOTE: This will alloc memory from kernel,
++	enlarge this will require the same memory.
++	The default value is enough for most applications.
++
++endmenu
++
++endif
+diff --git a/drivers/pci/hipcie/Makefile b/drivers/pci/hipcie/Makefile
+new file mode 100644
+index 0000000..0455420
+--- /dev/null
++++ b/drivers/pci/hipcie/Makefile
+@@ -0,0 +1,8 @@
++
++obj-$(CONFIG_HIPCIE) += hipcie.o
++
++hipcie-objs	:= pcie.o
++
++ifeq ($(CONFIG_PCI_DEBUG),y)
++	        EXTRA_CFLAGS += -DPCIE_DEBUG
++endif
+diff --git a/drivers/pci/hipcie/pcie.c b/drivers/pci/hipcie/pcie.c
+new file mode 100644
+index 0000000..2f1e9d1
+--- /dev/null
++++ b/drivers/pci/hipcie/pcie.c
+@@ -0,0 +1,732 @@
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/pci.h>
++#include <linux/mbus.h>
++#include <asm/irq.h>
++#include <asm/mach/pci.h>
++#include <linux/delay.h>
++#include <linux/spinlock.h>
++#include <linux/version.h>
++#include <asm/siginfo.h>
++
++#define PCIE_DBG_REG		1
++#define PCIE_DBG_FUNC		2
++#define PCIE_DBG_MODULE		3
++
++#define PCIE_DEBUG_LEVEL PCIE_DBG_MODULE
++
++/*#define PCIE_DEBUG*/
++#ifdef PCIE_DEBUG
++#define pcie_debug(level, str, arg...)\
++	do {\
++		if ((level) <= PCIE_DEBUG_LEVEL) {\
++			pr_debug("%s->%d," str "\n", \
++				__func__, __LINE__, ##arg);\
++		} \
++	} while (0)
++#else
++#define pcie_debug(level, str, arg...)
++#endif
++
++#define pcie_assert(con)\
++	do {\
++		if (!(con)) {\
++			pr_err("%s->%d,assert fail!\n", \
++				__func__, __LINE__);\
++		} \
++	} while (0)
++
++#define pcie_error(str, arg...)\
++	pr_err("%s->%d" str "\n", __func__, __LINE__, ##arg)
++
++
++#define __256MB__	0x10000000
++#define __128MB__	0x8000000
++#define __4KB__		0x1000
++#define __8KB__		0x2000
++
++enum pcie_sel {
++	/*
++	 * No controller selected.
++	 */
++	pcie_sel_none,
++	/*
++	 * PCIE0 selected.
++	 */
++	pcie0_x1_sel,
++	/*
++	 * PCIE1 selected.
++	 */
++	pcie1_x1_sel
++};
++
++enum pcie_rc_sel {
++	pcie_controller_unselected,
++	pcie_controller_selected
++};
++
++enum pcie_controller {
++	pcie_controller_none = -1,
++	pcie_controller_0 = 0,
++	pcie_controller_1 = 1
++};
++
++struct pcie_iatu {
++	unsigned int viewport;          /* iATU Viewport Register        */
++	unsigned int region_ctrl_1;     /* Region Control 1 Register     */
++	unsigned int region_ctrl_2;     /* Region Control 2 Register     */
++	unsigned int lbar;              /* Lower Base Address Register   */
++	unsigned int ubar;              /* Upper Base Address Register   */
++	unsigned int lar;               /* Limit Address Register        */
++	unsigned int ltar;		/* Lower Target Address Register */
++	unsigned int utar;              /* Upper Target Address Register */
++};
++
++#define MAX_IATU_PER_CTRLLER	(6)
++
++struct pcie_info {
++	/*
++	 * Root bus number
++	 */
++	u8		root_bus_nr;
++	enum		pcie_controller controller;
++
++	/*
++	 * Devices configuration space base
++	 */
++	unsigned int	base_addr;
++
++	/*
++	 * RC configuration space base
++	 */
++	unsigned int	conf_base_addr;
++};
++
++static struct pcie_info pcie_info[2];
++static int pcie_controllers_nr;
++
++static unsigned int pcie0_sel = pcie_controller_unselected;
++static unsigned int pcie0_mem_space_size = 0x0;
++
++static unsigned int pcie_errorvalue;
++
++/*
++ * For number 22 bus err.
++ */
++static int pcie_fault(unsigned long addr, unsigned int fsr,
++		struct pt_regs *regs)
++{
++	pcie_errorvalue = 1;
++	return 0;
++}
++
++static DEFINE_SPINLOCK(cw_lock);
++
++#define PCIE0_MODE_SEL  (1 << 0)
++#define PCIE1_MODE_SEL  (1 << 1)
++
++#if (defined CONFIG_ARCH_HI3519 || defined CONFIG_ARCH_HI3519V101)
++#include "pcie_hi3519.c"
++#elif defined(CONFIG_ARCH_HI3559) || defined(CONFIG_ARCH_HI3556)
++#include "pcie_hi3559.c"
++#elif defined(CONFIG_ARCH_HI3516AV200)
++#include "pcie_hi3516av200.c"
++#elif defined(CONFIG_ARCH_HI3531D)
++#include "pcie_hi3531d.c"
++#else
++#error You must have defined either CONFIG_ARCH_HI3519 or CONFIG_ARCH_HI3559 or CONFIG_ARCH_HI3556 or CONFIG_ARCH_HI3516AV200...
++#endif
++
++/*
++ * PCIE memory size bootargs: pcie0_mem_size=0xa00000;pcie1_mem_size=0xa00000
++ */
++static int __init pcie0_mem_size_parser(char *str)
++{
++	unsigned int size;
++
++	if (kstrtoul(str, 16, (long *)&size) < 0)
++		return 0;
++
++	/* if size >= 256MB, set default 256MB */
++	if (size >= 0x10000000)
++		size = 0x10000000;
++	pcie0_mem_space_size = size;
++
++	return 1;
++}
++__setup("pcie0_mem_size=", pcie0_mem_size_parser);
++
++/*
++ * PCIE sel bootargs: pcie0_sel=x1 pcie1=x1 or pcie1=x2
++ * Any other value after "pcieX_sel=" prefix
++ * will be treated as none controller selected.
++ * e.g. "pcie0_sel=none" will be treated as no PCIE0 selected.
++ */
++static int __init pcie0_sel_parser(char *str)
++{
++	if (strncasecmp(str, "x1", 2) == 0)
++		pcie0_sel = pcie0_x1_sel;
++	else
++		pcie0_sel = pcie_sel_none;
++
++	return 1;
++}
++__setup("pcie0_sel=", pcie0_sel_parser);
++
++static void __init pcie_preinit(void)
++{
++	pcie_debug(PCIE_DBG_FUNC, "!");
++	__arch_pcie_preinit();
++}
++
++static int request_pcie_res(int controller, struct pci_sys_data *sys)
++{
++	int ret;
++	struct resource *mem = NULL;
++	struct resource *io = NULL;
++
++	__arch_get_pcie_res(controller, &mem, &io);
++
++	ret = request_resource(&ioport_resource, io);
++	if (ret) {
++		pcie_error(
++		"request io resource failed,io->start=0x%x,io->end=0x%x",
++		io->start, io->end);
++		return ret;
++	}
++
++	ret = request_resource(&iomem_resource, mem);
++	if (ret) {
++		pcie_error(
++		"request mem resource failed,mem->start=0x%x,mem->end=0x%x",
++		mem->start, mem->end);
++
++		release_resource(io);
++		return ret;
++	}
++
++	pci_add_resource_offset(&sys->resources, io, sys->io_offset);
++	pci_add_resource_offset(&sys->resources, mem, sys->mem_offset);
++
++	return 0;
++}
++
++static int __init pcie_setup(int nr, struct pci_sys_data *sys)
++{
++	struct pcie_info *info;
++	int ret;
++
++	pcie_debug(PCIE_DBG_FUNC, "nr %d, sys->busnr %d",
++			nr, sys->busnr);
++	if (nr >= pcie_controllers_nr)
++		return 0;
++
++	info = &pcie_info[nr];
++	info->root_bus_nr = sys->busnr;
++	sys->mem_offset = 0;
++
++	/*
++	 * Requeset resources for the right controller.
++	 */
++	ret = request_pcie_res(info->controller, sys);
++	if (ret)
++		return ret;
++
++	__arch_config_iatu_tbl(info, sys);
++
++	return 1;
++}
++
++static struct pcie_info *bus_to_info(int busnr)
++{
++	int i = pcie_controllers_nr - 1;
++
++	for (; i >= 0; i--) {
++		if (pcie_info[i].controller != pcie_controller_none
++				&& pcie_info[i].root_bus_nr <= busnr
++				&& pcie_info[i].root_bus_nr != -1)
++			return &pcie_info[i];
++	}
++
++	return NULL;
++}
++
++
++static int __init pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
++{
++	struct pcie_info *info = bus_to_info(dev->bus->number);
++	
++	if (unlikely(!info)) {
++		pcie_error(
++		"%s:Cannot find corresponding controller for appointed device!", __func__);
++		BUG();
++	}
++
++	pcie_debug(PCIE_DBG_FUNC,
++		"dev->bus->number %d, slot %d, pin %d",
++		dev->bus->number, slot, pin);
++	return __arch_get_int_irq(info, pin);
++
++}
++
++#define PCIE_CFG_BUS(busnr)	((busnr & 0xff) << 20)
++#define PCIE_CFG_DEV(devfn)	((devfn & 0xff) << 12)
++#define PCIE_CFG_REG(reg)	(reg & 0xffc)	/*set dword align*/
++
++static inline unsigned int to_pcie_address(struct pci_bus *bus,
++		unsigned int devfn, int where)
++{
++	struct pcie_info *info = bus_to_info(bus->number);
++	unsigned int address = 0;
++
++	if (unlikely(!info)) {
++		pcie_error(
++		"%s:Cannot find corresponding controller for appointed device!", __func__);
++		BUG();
++	}
++
++	address = info->base_addr + (PCIE_CFG_BUS(bus->number)
++		| PCIE_CFG_DEV(devfn) | PCIE_CFG_REG(where));
++
++
++	return address;
++}
++
++static inline int is_pcie_link_up(struct pcie_info *info)
++{
++	int i;
++
++	 for (i = 0; i < 10000; i++) {
++		if (__arch_check_pcie_link(info))
++			break;
++		udelay(100);
++	}
++
++	return (i < 10000);
++}
++
++static int pcie_read_from_device(struct pci_bus *bus, unsigned int devfn,
++		int where, int size, u32 *value)
++{
++	struct pcie_info *info = bus_to_info(bus->number);
++	unsigned int val;
++	void __iomem *addr;
++	int i = 0;
++
++	if (unlikely(!info)) {
++		pcie_error(
++		"%s:Cannot find corresponding controller for appointed device!", __func__);
++		BUG();
++	}
++	
++	if (!is_pcie_link_up(info)) {
++		pcie_debug(PCIE_DBG_MODULE, "pcie %d not link up!",
++				info->controller);
++		return -1;
++	}
++
++	addr = (void __iomem *)to_pcie_address(bus, devfn, where);
++
++	val = readl(addr);
++
++	i = 0;
++	while (i < 2000) {
++		__asm__ __volatile__("nop\n");
++		i++;
++	}
++
++	if (pcie_errorvalue == 1) {
++		pcie_errorvalue = 0;
++		val = 0xffffffff;
++	}
++
++	if (size == 1)
++		*value = ((val >> ((where & 0x3) << 3)) & 0xff);
++	else if (size == 2)
++		*value = ((val >> ((where & 0x3) << 3)) & 0xffff);
++	else if (size == 4)
++		*value = val;
++	else{
++		pcie_error("Unknown size(%d) for read ops", size);
++		BUG();
++	}
++
++	return PCIBIOS_SUCCESSFUL;
++}
++
++static int pcie_read_from_dbi(struct pcie_info *info, unsigned int devfn,
++		int where, int size, u32 *value)
++{
++	unsigned int val;
++
++	/*
++	 * For host-side config space read, ignore device func nr.
++	 */
++	if (devfn > 0)
++		return -EIO;
++
++	val = (u32)readl((void *)(info->conf_base_addr + (where & (~0x3))));
++
++	if (1 == size)
++		*value = (val >> ((where & 0x3) << 3)) & 0xff;
++	else if (2 == size)
++		*value = (val >> ((where & 0x3) << 3)) & 0xffff;
++	else if (4 == size)
++		*value = val;
++	else {
++		pcie_error("Unknown size for config read operation!");
++		BUG();
++	}
++
++	return PCIBIOS_SUCCESSFUL;
++}
++
++static int pcie_read_conf(struct pci_bus *bus, unsigned int devfn,
++		int where, int size, u32 *value)
++{
++	struct pcie_info *info = bus_to_info(bus->number);
++	int ret;
++
++	if (unlikely(!info)) {
++		pcie_error(
++		"%s:Cannot find corresponding controller for appointed device!", __func__);
++		BUG();
++	}
++
++	if (bus->number == info->root_bus_nr)
++		ret =  pcie_read_from_dbi(info, devfn, where, size, value);
++	else
++		ret =  pcie_read_from_device(bus, devfn, where, size, value);
++
++	pcie_debug(PCIE_DBG_REG,
++		"bus %d, devfn %d, where 0x%x, size 0x%x, value 0x%x",
++		bus->number & 0xff, devfn, where, size, *value);
++
++	return ret;
++}
++
++static int pcie_write_to_device(struct pci_bus *bus, unsigned int devfn,
++		int where, int size, u32 value)
++{
++	struct pcie_info *info = bus_to_info(bus->number);
++	void __iomem *addr;
++	unsigned int org;
++	unsigned long flag;
++
++	if (unlikely(!info)) {
++		pcie_error(
++		"%s:Cannot find corresponding controller for appointed device!", __func__);
++		BUG();
++	}
++
++	if (!is_pcie_link_up(info)) {
++		pcie_debug(PCIE_DBG_MODULE, "pcie %d not link up!",
++				info->controller);
++		return -1;
++	}
++
++	spin_lock_irqsave(&cw_lock, flag);
++
++	pcie_read_from_device(bus, devfn, where, 4, &org);
++
++	addr = (void __iomem *)to_pcie_address(bus, devfn, where);
++
++	if (size == 1) {
++		org &= (~(0xff << ((where & 0x3) << 3)));
++		org |= (value << ((where & 0x3) << 3));
++	} else if (size == 2) {
++		org &= (~(0xffff << ((where & 0x3) << 3)));
++		org |= (value << ((where & 0x3) << 3));
++	} else if (size == 4) {
++		org = value;
++	} else {
++		pcie_error("Unknown size(%d) for read ops", size);
++		BUG();
++	}
++	writel(org, addr);
++
++	spin_unlock_irqrestore(&cw_lock, flag);
++
++	return PCIBIOS_SUCCESSFUL;
++
++}
++
++static int pcie_write_to_dbi(struct pcie_info *info, unsigned int devfn,
++		int where, int size, u32 value)
++{
++	unsigned long flag;
++	unsigned int org;
++
++	spin_lock_irqsave(&cw_lock, flag);
++
++	if (pcie_read_from_dbi(info, devfn, where, 4, &org)) {
++		pcie_error("Cannot read from dbi! 0x%x:0x%x:0x%x!",
++				0, devfn, where);
++		spin_unlock_irqrestore(&cw_lock, flag);
++		return -EIO;
++	}
++	if (size == 1) {
++		org &= (~(0xff << ((where & 0x3) << 3)));
++		org |= (value << ((where & 0x3) << 3));
++	} else if (size == 2) {
++		org &= (~(0xffff << ((where & 0x3) << 3)));
++		org |= (value << ((where & 0x3) << 3));
++	} else if (size == 4) {
++		org = value;
++	} else {
++		pcie_error("Unknown size(%d) for read ops", size);
++		BUG();
++	}
++	writel(org, ((void __iomem *)info->conf_base_addr + (where & (~0x3))));
++
++	spin_unlock_irqrestore(&cw_lock, flag);
++
++	return PCIBIOS_SUCCESSFUL;
++}
++
++static int pcie_write_conf(struct pci_bus *bus, unsigned int devfn,
++		int where, int size, u32 value)
++{
++	struct pcie_info *info = bus_to_info(bus->number);
++
++	pcie_debug(PCIE_DBG_REG,
++		"bus %d, devfn %d, where 0x%x, size 0x%x, value 0x%x",
++		bus->number & 0xff, devfn, where, size, value);
++
++	if (unlikely(!info)) {
++		pcie_error(
++		"%s:Cannot find corresponding controller for appointed device!", __func__);
++		BUG();
++	}
++
++	if (bus->number == info->root_bus_nr)
++		return pcie_write_to_dbi(info, devfn, where, size, value);
++	else
++		return pcie_write_to_device(bus, devfn, where, size, value);
++}
++
++static struct pci_ops pcie_ops = {
++	.read = pcie_read_conf,
++	.write = pcie_write_conf,
++};
++
++void pci_set_max_rd_req_size(const struct pci_bus *bus)
++{
++	struct pci_dev *dev;
++	struct pci_bus *child;
++	int pos;
++	unsigned short dev_contrl_reg_val = 0;
++	unsigned int max_rd_req_size = 0;
++
++	list_for_each_entry(dev, &bus->devices, bus_list) {
++
++		/* set device max read requset size*/
++		pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
++		if (pos) {
++			pci_read_config_word(dev, pos + PCI_EXP_DEVCTL,
++					&dev_contrl_reg_val);
++			max_rd_req_size = (dev_contrl_reg_val >> 12) & 0x7;
++			if (max_rd_req_size > 0x0) {
++				dev_contrl_reg_val &= ~(max_rd_req_size << 12);
++				pci_write_config_word(dev, pos + PCI_EXP_DEVCTL,
++						dev_contrl_reg_val);
++			}
++
++		}
++	}
++
++	list_for_each_entry(dev, &bus->devices, bus_list) {
++		BUG_ON(!dev->is_added);
++		child = dev->subordinate;
++		if (child)
++			pci_set_max_rd_req_size(child);
++	}
++}
++
++static struct pci_bus *__init pcie_scan_bus(int nr, struct pci_sys_data *sys)
++{
++	struct pci_bus *bus;
++
++	pcie_debug(PCIE_DBG_FUNC,
++		"nr %d, sys->busnr %d, sys->mem_offset 0x%llx, sys->io_offset 0x%lx",
++		nr, sys->busnr, sys->mem_offset, sys->io_offset);
++	if (nr < pcie_controllers_nr) {
++		bus = pci_scan_root_bus(NULL, sys->busnr, &pcie_ops, sys,
++				&sys->resources);
++	} else {
++		bus = NULL;
++		pcie_error("Unknown controller nr :0x%x!", nr);
++		BUG();
++	}
++
++#ifdef CONFIG_LIMIT_MAX_RD_REQ_SIZE
++	if (bus)
++		pci_set_max_rd_req_size(bus);
++#endif
++
++	return bus;
++}
++
++
++static struct hw_pci hipcie __initdata = {
++	.nr_controllers = 1,
++	.preinit    = pcie_preinit,
++	.swizzle    = pci_common_swizzle,
++	.setup      = pcie_setup,
++	.scan       = pcie_scan_bus,
++	.map_irq    = pcie_map_irq,
++};
++
++
++static int __init pcie_init(void)
++{
++	pcie_info[0].root_bus_nr = -1;
++	pcie_info[1].root_bus_nr = -1;
++
++	/*
++	 * Scene: PCIe host(RC)<--->SWITCH<--->PCIe device(*)
++	 *                            |
++	 *                            |------->NULL SLOT
++	 * PCIe will generate a DataAbort to ARM, when scanning NULL SLOT.
++	 * Register hook to capture this exception and handle it.
++	 */
++	hook_fault_code(22, pcie_fault, 7, BUS_OBJERR,
++		"external abort on non-linefetch");
++
++	if (__arch_pcie_info_setup(pcie_info, &pcie_controllers_nr))
++		return -EIO;
++
++	if (__arch_pcie_sys_init(pcie_info))
++		goto pcie_init_err;
++	hipcie.nr_controllers = pcie_controllers_nr;
++	pr_err("Number of PCIe controllers: %d\n",
++		hipcie.nr_controllers);
++
++	pci_common_init(&hipcie);
++
++	return 0;
++pcie_init_err:
++	__arch_pcie_info_release(pcie_info);
++
++	return -EIO;
++}
++
++static void __exit pcie_uinit(void)
++{
++	__arch_pcie_info_release(pcie_info);
++}
++
++#include <linux/platform_device.h>
++#include <linux/pm.h>
++
++int  hisi_pcie_plat_driver_probe(struct platform_device *pdev)
++{
++	return 0;
++}
++int  hisi_pcie_plat_driver_remove(struct platform_device *pdev)
++{
++	return 0;
++}
++
++#ifdef CONFIG_PM
++int hisi_pcie_plat_driver_suspend(struct device *dev)
++{
++	__arch_pcie_sys_exit();
++	return 0;
++}
++
++int hisi_pcie_plat_driver_resume(struct device *dev)
++{
++	return __arch_pcie_sys_init(pcie_info);
++}
++
++const struct dev_pm_ops hisi_pcie_pm_ops = {
++	.suspend = NULL,
++	.suspend_noirq = hisi_pcie_plat_driver_suspend,
++	.resume = NULL,
++	.resume_noirq = hisi_pcie_plat_driver_resume
++};
++
++#define HISI_PCIE_PM_OPS (&hisi_pcie_pm_ops)
++#else
++#define HISI_PCIE_PM_OPS NULL
++#endif
++
++#define PCIE_RC_DRV_NAME "hisi pcie root complex"
++
++static struct platform_driver hisi_pcie_platform_driver = {
++	.probe          = hisi_pcie_plat_driver_probe,
++	.remove         = hisi_pcie_plat_driver_remove,
++	.driver         = {
++		.owner  = THIS_MODULE,
++		.name   = PCIE_RC_DRV_NAME,
++		.bus    = &platform_bus_type,
++		.pm     = HISI_PCIE_PM_OPS
++	},
++};
++
++static void hisi_pcie_platform_device_release(struct device *dev)
++{
++}
++
++static struct resource hisi_pcie_resources[] = {
++	[0] = {
++		.start  = PCIE_DBI_BASE,
++		.end    = PCIE_DBI_BASE + __8KB__ - 1,
++		.flags  = IORESOURCE_REG,
++	}
++};
++
++static u64 hipcie_dmamask = DMA_BIT_MASK(32);
++
++static struct platform_device hisi_pcie_platform_device = {
++	.name = PCIE_RC_DRV_NAME,
++	.id   = 0,
++	.dev = {
++		.platform_data  = NULL,
++		.dma_mask = &hipcie_dmamask,
++		.coherent_dma_mask = DMA_BIT_MASK(32),
++		.release = hisi_pcie_platform_device_release,
++	},
++	.num_resources = ARRAY_SIZE(hisi_pcie_resources),
++	.resource = hisi_pcie_resources,
++};
++
++static int __init hisi_pcie_init(void)
++{
++	int ret;
++
++	ret = platform_device_register(&hisi_pcie_platform_device);
++	if (ret)
++		goto err_device;
++
++	ret = platform_driver_register(&hisi_pcie_platform_driver);
++	if (ret)
++		goto err_driver;
++
++	if (pcie_init()) {
++		pcie_error("pcie sys init failed!");
++		goto err_init;
++	}
++
++	return 0;
++err_init:
++	platform_driver_unregister(&hisi_pcie_platform_driver);
++err_driver:
++	platform_device_unregister(&hisi_pcie_platform_device);
++err_device:
++	return -1;
++}
++
++static void __exit hisi_pcie_exit(void)
++{
++	pcie_uinit();
++	platform_device_unregister(&hisi_pcie_platform_device);
++	platform_driver_unregister(&hisi_pcie_platform_driver);
++}
++
++subsys_initcall(hisi_pcie_init);
++module_exit(hisi_pcie_exit);
++
++MODULE_DESCRIPTION("Hisilicon PCI-Express Root Complex driver");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/pci/hipcie/pcie_hi3516av200.c b/drivers/pci/hipcie/pcie_hi3516av200.c
+new file mode 100644
+index 0000000..b8b85a7
+--- /dev/null
++++ b/drivers/pci/hipcie/pcie_hi3516av200.c
+@@ -0,0 +1,319 @@
++#include <mach/io.h>
++#include "pcie_hi3516av200.h"
++
++static void *dbi_base;
++static int __arch_pcie_info_setup(struct pcie_info *info, int *controllers_nr);
++static int __arch_pcie_sys_init(struct pcie_info *info);
++static void __arch_pcie_info_release(struct pcie_info *info);
++
++struct pcie_iatu iatu_table[] = {
++		{
++			.viewport	= 0,
++			.region_ctrl_1  = 0x00000004,
++			.region_ctrl_2  = 0x90000000,
++			.lbar           = PCIE_EP_CONF_BASE + (1<<20),
++			.ubar           = 0x0,
++			.lar            = PCIE_EP_CONF_BASE + (2<<20) - 1,
++			.ltar           = 0x01000000,
++			.utar           = 0x00000000,
++		},
++		{
++			.viewport       = 1,
++			.region_ctrl_1  = 0x00000005,
++			.region_ctrl_2  = 0x90000000,
++			.lbar           = PCIE_EP_CONF_BASE + (2<<20),
++			.ubar           = 0x0,
++			.lar            = PCIE_EP_CONF_BASE + (__128MB__ - 1),
++			.ltar           = 0x02000000,
++			.utar           = 0x00000000,
++		},
++};
++
++static void __arch_pcie_preinit(void)
++{
++
++}
++
++static struct resource pcie_mem;
++static struct resource pcie_io;
++static void __arch_get_pcie_res(int controller,
++		struct resource **pmem,
++		struct resource **pio)
++{
++	*pmem = &pcie_mem;
++	(*pmem)->start = PCIE_MEM_BASE;
++	(*pmem)->end = PCIE_MEM_BASE + __128MB__ - 0x100000 - 1;
++	(*pmem)->flags = IORESOURCE_MEM;
++	(*pmem)->name = "memory";
++
++	*pio = &pcie_io;
++	(*pio)->start = PCIE_MEM_BASE + __128MB__ - 0x100000;
++	(*pio)->end = PCIE_MEM_BASE + __128MB__ - 1;
++	(*pio)->flags = IORESOURCE_IO;
++	(*pio)->name = "io";
++}
++
++static int __arch_get_int_irq(struct pcie_info *info, u8 pin)
++{
++	switch (pin) {
++	case PCIE_INTA_PIN:
++		return PCIE_IRQ_INTA;
++	case PCIE_INTB_PIN:
++		return PCIE_IRQ_INTB;
++	case PCIE_INTC_PIN:
++		return PCIE_IRQ_INTC;
++	case PCIE_INTD_PIN:
++		return PCIE_IRQ_INTD;
++	default:
++		pcie_error("Unknown pin for mapping irq!");
++		return -1;
++	}
++}
++
++static void __arch_config_iatu_tbl(struct pcie_info *info,
++		struct pci_sys_data *sys)
++{
++	int i;
++	void __iomem *config_base = (void __iomem *)info->conf_base_addr;
++	struct pcie_iatu *ptable = iatu_table;
++	int table_size = ARRAY_SIZE(iatu_table);
++
++	for (i = 0; i < table_size; i++) {
++		writel((ptable + i)->viewport, config_base + 0x900);
++		writel((ptable + i)->lbar, config_base + 0x90c);
++		writel((ptable + i)->ubar, config_base + 0x910);
++		writel((ptable + i)->lar,  config_base + 0x914);
++		writel((ptable + i)->ltar, config_base + 0x918);
++		writel((ptable + i)->utar, config_base + 0x91c);
++		writel((ptable + i)->region_ctrl_1, config_base + 0x904);
++		writel((ptable + i)->region_ctrl_2, config_base + 0x908);
++	}
++
++}
++
++static inline int __arch_check_pcie_link(struct pcie_info *info)
++{
++	int val;
++
++	val = readl(dbi_base + PCIE_SYS_STATE0);
++	return ((val & (1 << PCIE_XMLH_LINK_UP))
++			&& (val & (1 << PCIE_RDLH_LINK_UP))) ? 1 : 0;
++}
++
++/*
++ * ret:
++ */
++static int __arch_pcie_info_setup(struct pcie_info *info, int *controllers_nr)
++{
++	unsigned int mem_size = CONFIG_PCIE0_DEVICES_MEM_SIZE;
++	unsigned int cfg_size = CONFIG_PCIE0_DEVICES_CONFIG_SIZE;
++
++	if ((mem_size > __128MB__) || (cfg_size > __128MB__)) {
++		pcie_error(
++		"Invalid parameter: pcie mem size[0x%x], pcie cfg size[0x%x]!",
++		mem_size, cfg_size);
++		return -EINVAL;
++	}
++
++	info->controller = 0;
++
++	/* RC configuration space */
++	info->conf_base_addr = (unsigned int)ioremap_nocache(PCIE_DBI_BASE,
++							 __8KB__);
++	if (!info->conf_base_addr) {
++		pcie_error("Address mapping for RC dbi failed!");
++		return -EIO;
++	}
++
++	/* Configuration space for all EPs */
++	info->base_addr = (unsigned int)ioremap_nocache(PCIE_EP_CONF_BASE,
++							 cfg_size);
++	if (!info->base_addr) {
++		iounmap((void *)info->conf_base_addr);
++		pcie_error("Address mapping for EPs cfg failed!");
++		return -EIO;
++	}
++
++	*controllers_nr = 1;
++
++	return 0;
++
++}
++
++static void __arch_pcie_info_release(struct pcie_info *info)
++{
++	if (info->base_addr)
++		iounmap((void *)info->base_addr);
++
++	if (info->conf_base_addr)
++		iounmap((void *)info->conf_base_addr);
++}
++
++void set_pcie_para(void *crg_base)
++{
++	unsigned int val;
++
++	void * misc_base = (void *)IO_ADDRESS(MISC_CTRL_BASE);
++
++	val = readl(crg_base + PERI_CRG43);	
++	val = val & (~(1 << 0));
++	val = val | (1 << 1);
++	writel(val,crg_base + PERI_CRG43);
++
++	writel(0x1506, misc_base + MISC_CTRL33);
++	writel(0x11506, misc_base + MISC_CTRL33);
++	writel(0x1506, misc_base + MISC_CTRL33);
++	writel(0x0, misc_base + MISC_CTRL33);
++
++	writel(0x108, misc_base + MISC_CTRL33);
++	writel(0x10108, misc_base + MISC_CTRL33);
++	writel(0x108, misc_base + MISC_CTRL33);
++	writel(0x0, misc_base + MISC_CTRL33);
++}
++
++static int __arch_pcie_sys_init(struct pcie_info *info)
++{
++	unsigned int val;
++	void *crg_base = (void *)IO_ADDRESS(PERI_CRG_BASE);
++
++	dbi_base = (void *)info->conf_base_addr;
++
++#ifdef CONFIG_ARCH_HI3516AV200
++	/*open pcie pad oe*/
++	val = readl(crg_base + PERI_CRG44);
++	val &= ~(PCIE_PAD_OE_MASK);
++	writel(val, crg_base + PERI_CRG44);
++	
++	/* refclk output from phy */
++	writel(PCIE_CLKREQ_FILTER_BYPASS,
++		(void *)IO_ADDRESS(MISC_CTRL_BASE + MISC_CTRL34));
++	mdelay(1);
++#endif
++
++	/*
++	 * Disable PCIE
++	 */
++	val = readl(dbi_base + PCIE_SYS_CTRL7);
++	val &= (~(1 << PCIE_APP_LTSSM_ENBALE));
++	val |= (1 << PCIE_ACCESS_ENABLE);
++	writel(val, dbi_base + PCIE_SYS_CTRL7);
++
++	/*
++	 * Reset
++	 */
++	val = readl(crg_base + PERI_CRG44);
++	val |= (1 << PCIE_X2_SRST_REQ);
++	writel(val, crg_base + PERI_CRG44);
++
++	/*
++	 * Retreat from the reset state
++	 */
++	udelay(500);
++	val = readl(crg_base + PERI_CRG44);
++	val &= ~(1 << PCIE_X2_SRST_REQ);
++	writel(val, crg_base + PERI_CRG44);
++	mdelay(10);
++
++
++	/*
++	 * PCIE RC work mode
++	 */
++	val = readl(dbi_base + PCIE_SYS_CTRL0);
++	val &= (~(0xf << PCIE_DEVICE_TYPE));
++	val |= (PCIE_WM_RC << PCIE_DEVICE_TYPE);
++	writel(val, dbi_base + PCIE_SYS_CTRL0);
++
++	/*
++	 * Enable clk
++	 */
++	val = readl(crg_base + PERI_CRG44);
++	val |= ((1 << PCIE_X2_BUS_CKEN)
++			| (1 << PCIE_X2_SYS_CKEN)
++			| (1 << PCIE_X2_PIPE_CKEN)
++			| (1 << PCIE_X2_AUX_CKEN));
++	writel(val, crg_base + PERI_CRG44);
++
++	mdelay(10);
++
++	
++	set_pcie_para(crg_base);
++	mdelay(10);
++
++	/*
++	 * Set PCIE controller class code to be PCI-PCI bridge device
++	 */
++	val = readl(dbi_base + PCI_CLASS_REVISION);
++	val &= ~(0xffffff00);
++	val |= (0x60400 << 8);
++	writel(val, dbi_base + PCI_CLASS_REVISION);
++	udelay(1000);
++
++#ifdef CONFIG_ARCH_HI3516AV200
++	/* phy always work at 5Gbps */
++	writel(COM_PHY_TEST_VAL1,
++		(void *)IO_ADDRESS(MISC_CTRL_BASE + MISC_CTRL33));
++	writel(COM_PHY_TEST_VAL2,
++		(void *)IO_ADDRESS(MISC_CTRL_BASE + MISC_CTRL33));
++	writel(COM_PHY_TEST_VAL1,
++		(void *)IO_ADDRESS(MISC_CTRL_BASE + MISC_CTRL33));
++	writel(0x0, (void *)IO_ADDRESS(MISC_CTRL_BASE + MISC_CTRL33));
++	
++	/* default deemphasis to -3.5 dB */
++	writel(DEEMPHASIS_VAL, (void *)IO_ADDRESS(PCIE_DBI_BASE + DEEMPHASIS_REG));
++#endif
++
++	/*
++	 * Enable controller
++	 */
++	val = readl(dbi_base + PCIE_SYS_CTRL7);
++	val |= (1 << PCIE_APP_LTSSM_ENBALE);
++	writel(val, dbi_base + PCIE_SYS_CTRL7);
++	udelay(1000);
++
++	val = readl(dbi_base + PCI_COMMAND);
++	val |= 7;
++	writel(val, dbi_base + PCI_COMMAND);
++
++	/* set pcie to gen 1*/
++#if 0
++	writel(0x1, dbi_base + 0x8BC);
++	val = readl(dbi_base + 0x7C);
++	val = ((val >> 4) << 4) | 0x1;
++	writel(val, dbi_base + 0x7C);
++#endif
++	return 0;
++}
++
++static void __arch_pcie_sys_exit(void)
++{
++	unsigned int val;
++	void *crg_base = (void *)IO_ADDRESS(PERI_CRG_BASE);
++
++	/*
++	 * Disable PCIE
++	 */
++	val = readl(dbi_base + PCIE_SYS_CTRL7);
++	val &= (~(1 << PCIE_APP_LTSSM_ENBALE));
++	writel(val, dbi_base + PCIE_SYS_CTRL7);
++
++	/*
++	 * Reset
++	 */
++	val = readl(crg_base + PERI_CRG44);
++	val |= (1 << PCIE_X2_SRST_REQ);
++	writel(val, crg_base + PERI_CRG44);
++
++	udelay(1000);
++
++	/*
++	 * Disable clk
++	 */
++	val = readl(crg_base + PERI_CRG44);
++	val &= (~(1 << PCIE_X2_AUX_CKEN));
++	val &= (~(1 << PCIE_X2_PIPE_CKEN));
++	val &= (~(1 << PCIE_X2_SYS_CKEN));
++	val &= (~(1 << PCIE_X2_BUS_CKEN));
++	writel(val, crg_base + PERI_CRG44);
++
++	udelay(1000);
++}
+diff --git a/drivers/pci/hipcie/pcie_hi3516av200.h b/drivers/pci/hipcie/pcie_hi3516av200.h
+new file mode 100644
+index 0000000..e185999
+--- /dev/null
++++ b/drivers/pci/hipcie/pcie_hi3516av200.h
+@@ -0,0 +1,55 @@
++#ifndef __HISI_PCIE_H__
++#define __HISI_PCIE_H__
++
++#define MISC_CTRL_BASE		0x12030000
++#define PCIE_MEM_BASE		0x28000000
++#define PCIE_EP_CONF_BASE	0x20000000
++#define PCIE_DBI_BASE		0x12160000
++#define PERI_CRG_BASE		0x12010000
++
++#define PERI_CRG43      0xAC
++#define PERI_CRG44		0xB0
++#define PCIE_X2_SRST_REQ	2
++
++#define PCIE_X2_AUX_CKEN	7
++#define PCIE_X2_PIPE_CKEN	6
++#define PCIE_X2_SYS_CKEN	5
++#define PCIE_X2_BUS_CKEN	4
++#define PCIE_PAD_OE_MASK	(0x7 << 8)
++
++#define PCIE_SYS_CTRL0		0x1000
++#define PCIE_DEVICE_TYPE	28
++#define PCIE_WM_EP		0x0
++#define PCIE_WM_LEGACY		0x1
++#define PCIE_WM_RC		0x4
++
++#define PCIE_SYS_CTRL7		0x101C
++#define PCIE_APP_LTSSM_ENBALE	11
++#define PCIE_ACCESS_ENABLE	13
++
++#define PCIE_SYS_STATE0		0x1100
++#define PCIE_XMLH_LINK_UP	15
++#define PCIE_RDLH_LINK_UP	5
++
++#define PCIE_IRQ_INTA		89
++#define PCIE_IRQ_INTB		90
++#define PCIE_IRQ_INTC		91
++#define PCIE_IRQ_INTD		92
++#define PCIE_IRQ_EDMA		93
++#define PCIE_IRQ_MSI		94
++#define PCIE_IRQ_LINK_DOWN	95
++
++#define PCIE_INTA_PIN		1
++#define PCIE_INTB_PIN		2
++#define PCIE_INTC_PIN		3
++#define PCIE_INTD_PIN		4
++
++#define MISC_CTRL33		0x84
++#define MISC_CTRL34		0x88
++#define DEEMPHASIS_REG		0xa0
++#define PCIE_CLKREQ_FILTER_BYPASS	0x600
++#define DEEMPHASIS_VAL			0x42
++#define COM_PHY_TEST_VAL1		((0x1 << 3) | (0x1 << 8))
++#define COM_PHY_TEST_VAL2		((0x1 << 16) | (0x1 << 3) | (0x1 << 8))
++
++#endif
+diff --git a/drivers/pci/hipcie/pcie_hi3519.c b/drivers/pci/hipcie/pcie_hi3519.c
+new file mode 100644
+index 0000000..fdfdf0a
+--- /dev/null
++++ b/drivers/pci/hipcie/pcie_hi3519.c
+@@ -0,0 +1,335 @@
++#include <mach/io.h>
++#include "pcie_hi3519.h"
++
++static void *dbi_base;
++static int __arch_pcie_info_setup(struct pcie_info *info, int *controllers_nr);
++static int __arch_pcie_sys_init(struct pcie_info *info);
++static void __arch_pcie_info_release(struct pcie_info *info);
++
++struct pcie_iatu iatu_table[] = {
++		{
++			.viewport	= 0,
++			.region_ctrl_1  = 0x00000004,
++			.region_ctrl_2  = 0x90000000,
++			.lbar           = PCIE_EP_CONF_BASE + (1<<20),
++			.ubar           = 0x0,
++			.lar            = PCIE_EP_CONF_BASE + (2<<20) - 1,
++			.ltar           = 0x01000000,
++			.utar           = 0x00000000,
++		},
++		{
++			.viewport       = 1,
++			.region_ctrl_1  = 0x00000005,
++			.region_ctrl_2  = 0x90000000,
++			.lbar           = PCIE_EP_CONF_BASE + (2<<20),
++			.ubar           = 0x0,
++			.lar            = PCIE_EP_CONF_BASE + (__128MB__ - 1),
++			.ltar           = 0x02000000,
++			.utar           = 0x00000000,
++		},
++};
++
++static void __arch_pcie_preinit(void)
++{
++
++}
++
++static struct resource pcie_mem;
++static struct resource pcie_io;
++static void __arch_get_pcie_res(int controller,
++		struct resource **pmem,
++		struct resource **pio)
++{
++	*pmem = &pcie_mem;
++	(*pmem)->start = PCIE_MEM_BASE;
++	(*pmem)->end = PCIE_MEM_BASE + __128MB__ - 0x100000 - 1;
++	(*pmem)->flags = IORESOURCE_MEM;
++	(*pmem)->name = "memory";
++
++	*pio = &pcie_io;
++	(*pio)->start = PCIE_MEM_BASE + __128MB__ - 0x100000;
++	(*pio)->end = PCIE_MEM_BASE + __128MB__ - 1;
++	(*pio)->flags = IORESOURCE_IO;
++	(*pio)->name = "io";
++}
++
++static int __arch_get_int_irq(struct pcie_info *info, u8 pin)
++{
++	switch (pin) {
++	case PCIE_INTA_PIN:
++		return PCIE_IRQ_INTA;
++	case PCIE_INTB_PIN:
++		return PCIE_IRQ_INTB;
++	case PCIE_INTC_PIN:
++		return PCIE_IRQ_INTC;
++	case PCIE_INTD_PIN:
++		return PCIE_IRQ_INTD;
++	default:
++		pcie_error("Unknown pin for mapping irq!");
++		return -1;
++	}
++}
++
++static void __arch_config_iatu_tbl(struct pcie_info *info,
++		struct pci_sys_data *sys)
++{
++	int i;
++	void __iomem *config_base = (void __iomem *)info->conf_base_addr;
++	struct pcie_iatu *ptable = iatu_table;
++	int table_size = ARRAY_SIZE(iatu_table);
++
++	for (i = 0; i < table_size; i++) {
++		writel((ptable + i)->viewport, config_base + 0x900);
++		writel((ptable + i)->lbar, config_base + 0x90c);
++		writel((ptable + i)->ubar, config_base + 0x910);
++		writel((ptable + i)->lar,  config_base + 0x914);
++		writel((ptable + i)->ltar, config_base + 0x918);
++		writel((ptable + i)->utar, config_base + 0x91c);
++		writel((ptable + i)->region_ctrl_1, config_base + 0x904);
++		writel((ptable + i)->region_ctrl_2, config_base + 0x908);
++	}
++
++}
++
++static inline int __arch_check_pcie_link(struct pcie_info *info)
++{
++	int val;
++
++	val = readl(dbi_base + PCIE_SYS_STATE0);
++	return ((val & (1 << PCIE_XMLH_LINK_UP))
++			&& (val & (1 << PCIE_RDLH_LINK_UP))) ? 1 : 0;
++}
++
++/*
++ * ret:
++ */
++static int __arch_pcie_info_setup(struct pcie_info *info, int *controllers_nr)
++{
++	unsigned int mem_size = CONFIG_PCIE0_DEVICES_MEM_SIZE;
++	unsigned int cfg_size = CONFIG_PCIE0_DEVICES_CONFIG_SIZE;
++
++	if ((mem_size > __128MB__) || (cfg_size > __128MB__)) {
++		pcie_error(
++		"Invalid parameter: pcie mem size[0x%x], pcie cfg size[0x%x]!",
++		mem_size, cfg_size);
++		return -EINVAL;
++	}
++
++	info->controller = 0;
++
++	/* RC configuration space */
++	info->conf_base_addr = (unsigned int)ioremap_nocache(PCIE_DBI_BASE,
++							 __8KB__);
++	if (!info->conf_base_addr) {
++		pcie_error("Address mapping for RC dbi failed!");
++		return -EIO;
++	}
++
++	/* Configuration space for all EPs */
++	info->base_addr = (unsigned int)ioremap_nocache(PCIE_EP_CONF_BASE,
++							 cfg_size);
++	if (!info->base_addr) {
++		iounmap((void *)info->conf_base_addr);
++		pcie_error("Address mapping for EPs cfg failed!");
++		return -EIO;
++	}
++
++	*controllers_nr = 1;
++
++	return 0;
++
++}
++
++static void __arch_pcie_info_release(struct pcie_info *info)
++{
++	if (info->base_addr)
++		iounmap((void *)info->base_addr);
++
++	if (info->conf_base_addr)
++		iounmap((void *)info->conf_base_addr);
++}
++
++void set_pcie_para(void *crg_base)
++{
++	unsigned int val;
++	
++	void * misc_base = (void *)IO_ADDRESS(MISC_CTRL_BASE);
++	
++	val = readl(crg_base + PERI_CRG43);	
++	val = val & (~(1 << 0));
++	val = val | (1 << 1);
++	writel(val,crg_base + PERI_CRG43);
++
++#ifdef CONFIG_ARCH_HI3519V101
++	writel(0x1506, misc_base + MISC_CTRL33);
++	writel(0x11506, misc_base + MISC_CTRL33);
++	writel(0x1506, misc_base + MISC_CTRL33);
++	writel(0x0, misc_base + MISC_CTRL33);
++
++	writel(0x108, misc_base + MISC_CTRL33);
++	writel(0x10108, misc_base + MISC_CTRL33);
++	writel(0x108, misc_base + MISC_CTRL33);
++	writel(0x0, misc_base + MISC_CTRL33);
++#else
++	writel(0x1a04, misc_base + MISC_CTRL33);
++	writel(0x11a04, misc_base + MISC_CTRL33);
++	writel(0x1a04, misc_base + MISC_CTRL33);
++	writel(0x0, misc_base + MISC_CTRL33);
++
++	writel(0xc09, misc_base + MISC_CTRL33);
++	writel(0x10c09, misc_base + MISC_CTRL33);
++	writel(0xc09, misc_base + MISC_CTRL33);
++	writel(0x0, misc_base + MISC_CTRL33);
++
++	writel(0x303, misc_base + MISC_CTRL33);
++	writel(0x10303, misc_base + MISC_CTRL33);
++	writel(0x303, misc_base + MISC_CTRL33);
++	writel(0x0, misc_base + MISC_CTRL33);
++#endif
++}
++
++static int __arch_pcie_sys_init(struct pcie_info *info)
++{
++	unsigned int val;
++	void *crg_base = (void *)IO_ADDRESS(PERI_CRG_BASE);
++
++	dbi_base = (void *)info->conf_base_addr;
++
++#ifdef CONFIG_ARCH_HI3519V101
++	/*open pcie pad oe*/
++	val = readl(crg_base + PERI_CRG44);
++	val &= ~(PCIE_PAD_OE_MASK);
++	writel(val, crg_base + PERI_CRG44);
++	
++	/* refclk output from phy */
++	writel(PCIE_CLKREQ_FILTER_BYPASS,
++		(void *)IO_ADDRESS(MISC_CTRL_BASE + MISC_CTRL34));
++	mdelay(1);
++#endif
++
++	/*
++	 * Disable PCIE
++	 */
++	val = readl(dbi_base + PCIE_SYS_CTRL7);
++	val &= (~(1 << PCIE_APP_LTSSM_ENBALE));
++	val |= (1 << PCIE_ACCESS_ENABLE);
++	writel(val, dbi_base + PCIE_SYS_CTRL7);
++
++	/*
++	 * Reset
++	 */
++	val = readl(crg_base + PERI_CRG44);
++	val |= (1 << PCIE_X2_SRST_REQ);
++	writel(val, crg_base + PERI_CRG44);
++
++	/*
++	 * Retreat from the reset state
++	 */
++	udelay(500);
++	val = readl(crg_base + PERI_CRG44);
++	val &= ~(1 << PCIE_X2_SRST_REQ);
++	writel(val, crg_base + PERI_CRG44);
++	mdelay(10);
++
++
++	/*
++	 * PCIE RC work mode
++	 */
++	val = readl(dbi_base + PCIE_SYS_CTRL0);
++	val &= (~(0xf << PCIE_DEVICE_TYPE));
++	val |= (PCIE_WM_RC << PCIE_DEVICE_TYPE);
++	writel(val, dbi_base + PCIE_SYS_CTRL0);
++
++	/*
++	 * Enable clk
++	 */
++	val = readl(crg_base + PERI_CRG44);
++	val |= ((1 << PCIE_X2_BUS_CKEN)
++			| (1 << PCIE_X2_SYS_CKEN)
++			| (1 << PCIE_X2_PIPE_CKEN)
++			| (1 << PCIE_X2_AUX_CKEN));
++	writel(val, crg_base + PERI_CRG44);
++
++	mdelay(10);
++	
++	set_pcie_para(crg_base);
++	mdelay(10);
++	
++	/*
++	 * Set PCIE controller class code to be PCI-PCI bridge device
++	 */
++	val = readl(dbi_base + PCI_CLASS_REVISION);
++	val &= ~(0xffffff00);
++	val |= (0x60400 << 8);
++	writel(val, dbi_base + PCI_CLASS_REVISION);
++	udelay(1000);
++
++#ifdef CONFIG_ARCH_HI3519V101
++	/* phy always work at 5Gbps */
++	writel(COM_PHY_TEST_VAL1,
++		(void *)IO_ADDRESS(MISC_CTRL_BASE + MISC_CTRL33));
++	writel(COM_PHY_TEST_VAL2,
++		(void *)IO_ADDRESS(MISC_CTRL_BASE + MISC_CTRL33));
++	writel(COM_PHY_TEST_VAL1,
++		(void *)IO_ADDRESS(MISC_CTRL_BASE + MISC_CTRL33));
++	writel(0x0, (void *)IO_ADDRESS(MISC_CTRL_BASE + MISC_CTRL33));
++	
++	/* default deemphasis to -3.5 dB */
++	writel(DEEMPHASIS_VAL, (void *)IO_ADDRESS(PCIE_DBI_BASE + DEEMPHASIS_REG));
++#endif
++
++	/*
++	 * Enable controller
++	 */
++	val = readl(dbi_base + PCIE_SYS_CTRL7);
++	val |= (1 << PCIE_APP_LTSSM_ENBALE);
++	writel(val, dbi_base + PCIE_SYS_CTRL7);
++	udelay(1000);
++
++	val = readl(dbi_base + PCI_COMMAND);
++	val |= 7;
++	writel(val, dbi_base + PCI_COMMAND);
++
++	/* set pcie to gen 1*/
++#if 0
++	writel(0x1, dbi_base + 0x8BC);
++	val = readl(dbi_base + 0x7C);
++	val = ((val >> 4) << 4) | 0x1;
++	writel(val, dbi_base + 0x7C);
++#endif
++	return 0;
++}
++
++static void __arch_pcie_sys_exit(void)
++{
++	unsigned int val;
++	void *crg_base = (void *)IO_ADDRESS(PERI_CRG_BASE);
++
++	/*
++	 * Disable PCIE
++	 */
++	val = readl(dbi_base + PCIE_SYS_CTRL7);
++	val &= (~(1 << PCIE_APP_LTSSM_ENBALE));
++	writel(val, dbi_base + PCIE_SYS_CTRL7);
++
++	/*
++	 * Reset
++	 */
++	val = readl(crg_base + PERI_CRG44);
++	val |= (1 << PCIE_X2_SRST_REQ);
++	writel(val, crg_base + PERI_CRG44);
++
++	udelay(1000);
++
++	/*
++	 * Disable clk
++	 */
++	val = readl(crg_base + PERI_CRG44);
++	val &= (~(1 << PCIE_X2_AUX_CKEN));
++	val &= (~(1 << PCIE_X2_PIPE_CKEN));
++	val &= (~(1 << PCIE_X2_SYS_CKEN));
++	val &= (~(1 << PCIE_X2_BUS_CKEN));
++	writel(val, crg_base + PERI_CRG44);
++
++	udelay(1000);
++}
+diff --git a/drivers/pci/hipcie/pcie_hi3519.h b/drivers/pci/hipcie/pcie_hi3519.h
+new file mode 100644
+index 0000000..e185999
+--- /dev/null
++++ b/drivers/pci/hipcie/pcie_hi3519.h
+@@ -0,0 +1,55 @@
++#ifndef __HISI_PCIE_H__
++#define __HISI_PCIE_H__
++
++#define MISC_CTRL_BASE		0x12030000
++#define PCIE_MEM_BASE		0x28000000
++#define PCIE_EP_CONF_BASE	0x20000000
++#define PCIE_DBI_BASE		0x12160000
++#define PERI_CRG_BASE		0x12010000
++
++#define PERI_CRG43      0xAC
++#define PERI_CRG44		0xB0
++#define PCIE_X2_SRST_REQ	2
++
++#define PCIE_X2_AUX_CKEN	7
++#define PCIE_X2_PIPE_CKEN	6
++#define PCIE_X2_SYS_CKEN	5
++#define PCIE_X2_BUS_CKEN	4
++#define PCIE_PAD_OE_MASK	(0x7 << 8)
++
++#define PCIE_SYS_CTRL0		0x1000
++#define PCIE_DEVICE_TYPE	28
++#define PCIE_WM_EP		0x0
++#define PCIE_WM_LEGACY		0x1
++#define PCIE_WM_RC		0x4
++
++#define PCIE_SYS_CTRL7		0x101C
++#define PCIE_APP_LTSSM_ENBALE	11
++#define PCIE_ACCESS_ENABLE	13
++
++#define PCIE_SYS_STATE0		0x1100
++#define PCIE_XMLH_LINK_UP	15
++#define PCIE_RDLH_LINK_UP	5
++
++#define PCIE_IRQ_INTA		89
++#define PCIE_IRQ_INTB		90
++#define PCIE_IRQ_INTC		91
++#define PCIE_IRQ_INTD		92
++#define PCIE_IRQ_EDMA		93
++#define PCIE_IRQ_MSI		94
++#define PCIE_IRQ_LINK_DOWN	95
++
++#define PCIE_INTA_PIN		1
++#define PCIE_INTB_PIN		2
++#define PCIE_INTC_PIN		3
++#define PCIE_INTD_PIN		4
++
++#define MISC_CTRL33		0x84
++#define MISC_CTRL34		0x88
++#define DEEMPHASIS_REG		0xa0
++#define PCIE_CLKREQ_FILTER_BYPASS	0x600
++#define DEEMPHASIS_VAL			0x42
++#define COM_PHY_TEST_VAL1		((0x1 << 3) | (0x1 << 8))
++#define COM_PHY_TEST_VAL2		((0x1 << 16) | (0x1 << 3) | (0x1 << 8))
++
++#endif
+diff --git a/drivers/pci/hipcie/pcie_hi3531d.c b/drivers/pci/hipcie/pcie_hi3531d.c
+new file mode 100644
+index 0000000..24c3a6d
+--- /dev/null
++++ b/drivers/pci/hipcie/pcie_hi3531d.c
+@@ -0,0 +1,641 @@
++
++#include "pcie_hi3531d.h"
++
++static void *dbi_base_pcie0;
++static void *dbi_base_pcie1;
++static void *__iomem misc_ctrl_virt;
++static int __arch_pcie_info_setup(struct pcie_info *info, int *controllers_nr);
++static int __arch_pcie_sys_init(struct pcie_info *info);
++static void __arch_pcie_info_release(struct pcie_info *info);
++
++struct pcie_iatu pcie0_iatu_table[] = {
++		{
++			.viewport	= 0,
++			.region_ctrl_1  = 0x00000004,
++			.region_ctrl_2  = 0x90000000,
++			.lbar           = PCIE0_EP_CONF_BASE + (1<<20),
++			.ubar           = 0x0,
++			.lar            = PCIE0_EP_CONF_BASE + (2<<20) - 1,
++			.ltar           = 0x01000000,
++			.utar           = 0x00000000,
++		},
++		{
++			.viewport       = 1,
++			.region_ctrl_1  = 0x00000005,
++			.region_ctrl_2  = 0x90000000,
++			.lbar           = PCIE0_EP_CONF_BASE + (2<<20),
++			.ubar           = 0x0,
++			.lar            = PCIE0_EP_CONF_BASE + (__128MB__ - 1),
++			.ltar           = 0x02000000,
++			.utar           = 0x00000000,
++		},
++};
++
++struct pcie_iatu pcie1_iatu_table[] = {
++		{
++			.viewport	= 0,
++			.region_ctrl_1  = 0x00000004,
++			.region_ctrl_2  = 0x90000000,
++			.lbar           = PCIE1_EP_CONF_BASE,
++			.ubar           = 0x0,
++			.lar            = PCIE1_EP_CONF_BASE + (1<<20) - 1,
++			.ltar           = 0x01000000,
++			.utar           = 0x00000000,
++		},
++		{
++			.viewport       = 1,
++			.region_ctrl_1  = 0x00000005,
++			.region_ctrl_2  = 0x90000000,
++			.lbar           = PCIE1_EP_CONF_BASE,
++			.ubar           = 0x0,
++			.lar            = PCIE1_EP_CONF_BASE + (__128MB__ - 1),
++			.ltar           = 0x02000000,
++			.utar           = 0x00000000,
++		},
++};
++
++static void __arch_pcie_preinit(void)
++{
++
++}
++
++static struct resource pcie_mem[2];
++static struct resource pcie_io[2];
++static void __arch_get_pcie_res(int controller,
++		struct resource **pmem,
++		struct resource **pio)
++{
++	if (controller >= 2) {
++		pcie_error("Pcie controller index(%d) error!", controller);
++		return;
++	}
++
++
++	*pmem = &pcie_mem[controller];
++	*pio = &pcie_io[controller];
++
++	if (pcie_controller_0 == controller) {
++		(*pmem)->start = PCIE0_MEM_BASE;
++		(*pmem)->end = PCIE0_MEM_BASE + 0x8000000 - 1;
++		(*pmem)->flags = IORESOURCE_MEM;
++		(*pmem)->name = "memory";
++
++		(*pio)->start = 0x0;
++		(*pio)->end = 0x0;
++		(*pio)->flags = IORESOURCE_IO;
++		(*pio)->name = "io";
++	}
++
++	if (pcie_controller_1 == controller) {
++
++		(*pmem)->start = PCIE1_MEM_BASE;
++		(*pmem)->end = PCIE1_MEM_BASE + 0x8000000 - 1;
++		(*pmem)->flags = IORESOURCE_MEM;
++		(*pmem)->name = "memory";
++
++		(*pio)->start = 0x1;
++		(*pio)->end = 0x1;
++		(*pio)->flags = IORESOURCE_IO;
++		(*pio)->name = "io";
++	}
++}
++
++static int __arch_get_int_irq(struct pcie_info *info, u8 pin)
++{
++	if (pcie_controller_0 == info->controller) {
++		switch (pin) {
++		case PCIE_INTA_PIN:
++			return PCIE0_IRQ_INTA;
++		case PCIE_INTB_PIN:
++			return PCIE0_IRQ_INTB;
++		case PCIE_INTC_PIN:
++			return PCIE0_IRQ_INTC;
++		case PCIE_INTD_PIN:
++			return PCIE0_IRQ_INTD;
++		default:
++			pcie_error("Unknown pin for mapping irq!");
++			return -1;
++		}
++	}
++
++	if (pcie_controller_1 == info->controller) {
++		switch (pin) {
++		case PCIE_INTA_PIN:
++			return PCIE1_IRQ_INTA;
++		case PCIE_INTB_PIN:
++			return PCIE1_IRQ_INTB;
++		case PCIE_INTC_PIN:
++			return PCIE1_IRQ_INTC;
++		case PCIE_INTD_PIN:
++			return PCIE1_IRQ_INTD;
++		default:
++			pcie_error("Unknown pin for mapping irq!");
++			return -1;
++		}
++	}
++
++	return -1;
++}
++
++static void __arch_config_iatu_tbl(struct pcie_info *info,
++		struct pci_sys_data *sys)
++{
++	int i;
++	void __iomem *config_base;
++	struct pcie_iatu *ptable;
++	int table_size;
++	unsigned int ctl1_lbar_offset;
++
++	config_base = (void __iomem *)info->conf_base_addr;
++
++	if (pcie_controller_0 == info->controller) {
++		ptable = pcie0_iatu_table;
++		table_size = ARRAY_SIZE(pcie0_iatu_table);
++	}
++
++	if (pcie_controller_1 == info->controller) {
++		ptable = pcie1_iatu_table;
++		table_size = ARRAY_SIZE(pcie1_iatu_table);
++
++		ctl1_lbar_offset = (sys->busnr + 1) << 20;
++		ptable->lbar |= ctl1_lbar_offset;
++		ptable->lar |= ctl1_lbar_offset;
++
++		ctl1_lbar_offset = (sys->busnr + 2) << 20;
++		(ptable + 1)->lbar |= ctl1_lbar_offset;
++	}
++
++	for (i = 0; i < table_size; i++) {
++		writel((ptable + i)->viewport, config_base + 0x900);
++		writel((ptable + i)->lbar, config_base + 0x90c);
++		writel((ptable + i)->ubar, config_base + 0x910);
++		writel((ptable + i)->lar,  config_base + 0x914);
++		writel((ptable + i)->ltar, config_base + 0x918);
++		writel((ptable + i)->utar, config_base + 0x91c);
++		writel((ptable + i)->region_ctrl_1, config_base + 0x904);
++		writel((ptable + i)->region_ctrl_2, config_base + 0x908);
++	}
++
++}
++
++static inline int __arch_check_pcie_link(struct pcie_info *info)
++{
++	int val;
++
++	if (pcie_controller_0 == info->controller) {
++		val = readl(dbi_base_pcie0 + PCIE_SYS_STATE0);
++		return ((val & (1 << PCIE_XMLH_LINK_UP))
++				&& (val & (1 << PCIE_RDLH_LINK_UP))) ? 1 : 0;
++	}
++
++	if (pcie_controller_1 == info->controller) {
++		val = readl(dbi_base_pcie1 + PCIE_SYS_STATE0);
++		return ((val & (1 << PCIE_XMLH_LINK_UP))
++				&& (val & (1 << PCIE_RDLH_LINK_UP))) ? 1 : 0;
++	}
++
++	return 0;
++}
++
++/*
++ * ret:
++ */
++static int __arch_pcie_info_set(struct pcie_info *info, int controller)
++{
++	unsigned int pcie_mem_size;
++	unsigned int pcie_cfg_size;
++	unsigned int pcie_dbi_base;
++	unsigned int pcie_ep_conf_base;
++
++#if CONFIG_PCIE0_SEL
++	if (pcie_controller_0 == controller) {
++		pcie_mem_size = CONFIG_PCIE0_DEVICES_MEM_SIZE;
++		pcie_cfg_size = CONFIG_PCIE0_DEVICES_CONFIG_SIZE;
++		pcie_dbi_base = PCIE0_DBI_BASE;
++		pcie_ep_conf_base = PCIE0_EP_CONF_BASE;
++	}
++#endif
++#if CONFIG_PCIE1_SEL
++	if (pcie_controller_1 == controller) {
++		pcie_mem_size = CONFIG_PCIE1_DEVICES_MEM_SIZE;
++		pcie_cfg_size = CONFIG_PCIE1_DEVICES_CONFIG_SIZE;
++		pcie_dbi_base = PCIE1_DBI_BASE;
++		pcie_ep_conf_base = PCIE1_EP_CONF_BASE;
++	}
++#endif
++
++	if ((pcie_mem_size > __128MB__) || (pcie_cfg_size > __128MB__)) {
++		pcie_error(
++		"Invalid parameter: pcie mem size[0x%x], pcie cfg size[0x%x]!",
++		pcie_mem_size, pcie_cfg_size);
++		return -EINVAL;
++	}
++
++	info->controller = controller;
++
++	/* RC configuration space */
++	info->conf_base_addr = (unsigned int)ioremap_nocache(pcie_dbi_base,
++			__8KB__);
++	if (!info->conf_base_addr) {
++		pcie_error("Address mapping for RC dbi failed!");
++		return -EIO;
++	}
++
++	/* Configuration space for all EPs */
++	info->base_addr = (unsigned int)ioremap_nocache(pcie_ep_conf_base,
++			pcie_cfg_size);
++	if (!info->base_addr) {
++		iounmap((void *)info->conf_base_addr);
++		pcie_error("Address mapping for EPs cfg failed!");
++		return -EIO;
++	}
++
++	return 0;
++}
++
++static void __arch_pcie_info_clr(struct pcie_info *info)
++{
++	if (info->base_addr)
++		iounmap((void *)info->base_addr);
++
++	if (info->conf_base_addr)
++		iounmap((void *)info->conf_base_addr);
++}
++
++static int  __arch_get_port_nr(void)
++{
++	unsigned int val, mode;
++	int nr;
++
++	val = readl((void *)PCIE_SYS_STAT);
++	mode = (val >> 12) & 0xf;
++	switch (mode) {
++	case 0x1:
++	case 0x9:
++		nr = 1;
++		break;
++
++	case 0x3:
++	case 0xb:
++		nr = 2;
++		break;
++
++	default:
++		nr = 0;
++		break;
++	}
++
++	return nr;
++}
++
++static int __arch_pcie_info_setup(struct pcie_info *info, int *controllers_nr)
++{
++	int nr;
++
++	misc_ctrl_virt = (void *)IO_ADDRESS(MISC_CTRL_BASE);
++
++	nr = __arch_get_port_nr();
++	if (!nr) {
++		pr_err("Pcie port number: 0\n");
++		return -EINVAL;
++	}
++	*controllers_nr = 0;
++
++#if CONFIG_PCIE0_SEL
++	if (__arch_pcie_info_set(&info[*controllers_nr], pcie_controller_0))
++		return -EIO;
++	(*controllers_nr)++;
++#endif
++#if CONFIG_PCIE1_SEL
++	if (nr < 2) {
++		pr_err("1-PCIE port mode, skip PCIE1 even config pcie1-sel!\n");
++		return 0;
++	}
++	if (__arch_pcie_info_set(&info[*controllers_nr], pcie_controller_1)) {
++#if CONFIG_PCIE0_SEL
++		__arch_pcie_info_clr(&info[pcie_controller_0]);
++#endif
++		return -EIO;
++	}
++	(*controllers_nr)++;
++#endif
++
++	return 0;
++}
++
++static void __arch_pcie_info_release(struct pcie_info *info)
++{
++	int nr;
++
++	for (nr = 0; nr < pcie_controllers_nr; nr++)
++		__arch_pcie_info_clr(&info[nr]);
++}
++
++void set_pcie0_para(void)
++{
++	unsigned int val;
++	unsigned int flag;
++
++	val = readl((void *)PCIE_SYS_STAT);
++	flag = (val >> 12) & 0xf;
++
++	switch(flag) {
++		case 0x1:
++		case 0x3:
++		case 0x9:
++		case 0xb:
++			writel(0x615, misc_ctrl_virt + MISC_CTRL81);
++			writel(0x655, misc_ctrl_virt + MISC_CTRL81);
++			writel(0x615, misc_ctrl_virt + MISC_CTRL81);
++			writel(0x0, misc_ctrl_virt + MISC_CTRL81);
++			break;
++		default:
++			break;
++
++	}
++}
++
++void set_pcie1_para(void)
++{
++	unsigned int val;
++	unsigned int flag;
++
++	val = readl((void *)PCIE_SYS_STAT);
++	flag = (val >> 12) & 0xf;
++
++	switch(flag) {
++		case 0x3:
++		case 0xb:
++			writel(0x615, misc_ctrl_virt + MISC_CTRL80);
++			writel(0x655, misc_ctrl_virt + MISC_CTRL80);
++			writel(0x615, misc_ctrl_virt + MISC_CTRL80);
++			writel(0x0, misc_ctrl_virt + MISC_CTRL80);
++			break;
++		default:
++			break;
++
++	}
++}
++
++static void __arch_pcie_sys_config(struct pcie_info *info)
++{
++	static unsigned int loop_count = 0, comp_mode_nr = 0;
++	unsigned int val;
++	void *dbi_base = (void *)info->conf_base_addr;
++	void *crg_base = (void *)IO_ADDRESS(PERI_CRG_BASE);
++
++	/* set pcie crg */
++	writel(COMPHY_CLK_REST_VAL, crg_base + PERI_CRG_72);
++
++	if (comp_mode_nr > 1) {
++		/* PCIE 1*/
++		/* phy always work at 5Gbps */
++		/* step1 addr/data enable: 0x901 */
++		writel((PCIE_COMBPHY_TEST_ADDR_EN | PCIE_COMBPHY_TEST_DATA_EN),
++				(void *)IO_ADDRESS(MISC_CTRL_BASE + MISC_CTRL80));
++		/* step2 write enable: 0x941*/
++		writel((PCIE_COMBPHY_TEST_ADDR_EN
++					| PCIE_COMBPHY_TEST_DATA_EN
++					| PCIE_COMBPHY_TEST_WR_EN),
++				(void *)IO_ADDRESS(MISC_CTRL_BASE + MISC_CTRL80));
++		/* step3 write release: 0x901 */
++		writel((PCIE_COMBPHY_TEST_ADDR_EN | PCIE_COMBPHY_TEST_DATA_EN),
++				(void *)IO_ADDRESS(MISC_CTRL_BASE + MISC_CTRL80));
++		/* step4 status recovery */
++		writel(PCIE_COMBPHY_RECOVER,
++				(void *)IO_ADDRESS(MISC_CTRL_BASE + MISC_CTRL80));
++	}
++
++	if (loop_count == 0) {
++		comp_mode_nr = __arch_get_port_nr();
++		if (comp_mode_nr) {
++			/*PCIE 0*/
++			/* phy always work at 5Gbps */
++			/* step1 addr/data enable: 0x901 */
++			writel((PCIE_COMBPHY_TEST_ADDR_EN | PCIE_COMBPHY_TEST_DATA_EN),
++					(void *)IO_ADDRESS(MISC_CTRL_BASE + MISC_CTRL81));
++			/* step2 write enable: 0x941*/
++			writel((PCIE_COMBPHY_TEST_ADDR_EN
++						| PCIE_COMBPHY_TEST_DATA_EN
++						| PCIE_COMBPHY_TEST_WR_EN),
++					(void *)IO_ADDRESS(MISC_CTRL_BASE + MISC_CTRL81));
++			/* step3 write release: 0x901 */
++			writel((PCIE_COMBPHY_TEST_ADDR_EN | PCIE_COMBPHY_TEST_DATA_EN),
++					(void *)IO_ADDRESS(MISC_CTRL_BASE + MISC_CTRL81));
++			/* step4 status recovery */
++			writel(PCIE_COMBPHY_RECOVER,
++					(void *)IO_ADDRESS(MISC_CTRL_BASE + MISC_CTRL81));
++		}
++		loop_count++;
++	}
++
++#if CONFIG_PCIE0_SEL
++	/* refclk output from phy for PCIE0 */
++	val = readl((void *)IO_ADDRESS(MISC_CTRL_BASE + MISC_CTRL3));
++	/* bit0 = 1: pad output enable;
++	 * bit1 = 0: pad input disable;
++	 * bit6 = 1: refclk from phy */
++	val |= PCIE0_REGCLK_OUTPUT_EN | PCIE0_REGCLK_SRC_SEL_PHY;
++	val &= ~PCIE0_REGCLK_INPUT_EN;
++	writel(val, (void *)IO_ADDRESS(MISC_CTRL_BASE + MISC_CTRL3));
++	mdelay(1);
++#endif
++
++#if CONFIG_PCIE1_SEL
++	/* refclk output from phy for PCIE1 */
++	val = readl((void *)IO_ADDRESS(MISC_CTRL_BASE + MISC_CTRL3));
++	/* bit2 = 1: pad output enable;
++	 * bit3 = 0: pad input disable;
++	 * bit7 = 1: refclk from phy */
++	val |= PCIE1_REGCLK_OUTPUT_EN | PCIE1_REGCLK_SRC_SEL_PHY;
++	val &= ~PCIE1_REGCLK_INPUT_EN;
++	writel(val, (void *)IO_ADDRESS(MISC_CTRL_BASE + MISC_CTRL3));
++	mdelay(1);
++#endif
++
++	/*
++	 * Disable PCIE
++	 */
++	val = readl(dbi_base + PCIE_SYS_CTRL7);
++	val &= (~(1 << PCIE_APP_LTSSM_ENBALE));
++	writel(val, dbi_base + PCIE_SYS_CTRL7);
++
++	if (pcie_controller_0 == info->controller) {
++
++		dbi_base_pcie0 = dbi_base;
++		/*
++		 * Reset
++		 */
++		val = readl(crg_base + PERI_CRG73);
++		val |= (1 << PCIE0_X2_SRST_REQ);
++		writel(val, crg_base + PERI_CRG73);
++
++		/*
++		 * Retreat from the reset state
++		 */
++		udelay(500);
++		val = readl(crg_base + PERI_CRG73);
++		val &= ~(1 << PCIE0_X2_SRST_REQ);
++		writel(val, crg_base + PERI_CRG73);
++		mdelay(10);
++
++		set_pcie0_para();
++		mdelay(10);
++	}
++
++	if (pcie_controller_1 == info->controller) {
++
++		dbi_base_pcie1 = dbi_base;
++		/*
++		 * Reset
++		 */
++		val = readl(crg_base + PERI_CRG73);
++		val |= (1 << PCIE1_X2_SRST_REQ);
++		writel(val, crg_base + PERI_CRG73);
++
++		/*
++		 * Retreat from the reset state
++		 */
++		udelay(500);
++		val = readl(crg_base + PERI_CRG73);
++		val &= ~(1 << PCIE1_X2_SRST_REQ);
++		writel(val, crg_base + PERI_CRG73);
++		mdelay(10);
++
++		set_pcie1_para();
++		mdelay(10);
++	}
++
++	/*
++	 * PCIE RC work mode
++	 */
++	val = readl(dbi_base + PCIE_SYS_CTRL0);
++	val &= (~(0xf << PCIE_DEVICE_TYPE));
++	val |= (PCIE_WM_RC << PCIE_DEVICE_TYPE);
++	writel(val, dbi_base + PCIE_SYS_CTRL0);
++
++	if (pcie_controller_0 == info->controller) {
++		/*
++		 * Enable clk
++		 */
++		val = readl(crg_base + PERI_CRG73);
++		val |= ((1 << PCIE0_X2_BUS_CKEN)
++				| (1 << PCIE0_X2_SYS_CKEN)
++				| (1 << PCIE0_X2_PIPE_CKEN)
++				| (1 << PCIE0_X2_AUX_CKEN));
++		writel(val, crg_base + PERI_CRG73);
++	}
++
++	if (pcie_controller_1 == info->controller) {
++
++		/*
++		 * Enable clk
++		 */
++		val = readl(crg_base + PERI_CRG73);
++		val |= ((1 << PCIE1_X2_BUS_CKEN)
++				| (1 << PCIE1_X2_SYS_CKEN)
++				| (1 << PCIE1_X2_PIPE_CKEN)
++				| (1 << PCIE1_X2_AUX_CKEN));
++		writel(val, crg_base + PERI_CRG73);
++	}
++
++	mdelay(10);
++
++	/*
++	 * Enable controller
++	 */
++	val = readl(dbi_base + PCIE_SYS_CTRL7);
++	val |= (1 << PCIE_APP_LTSSM_ENBALE);
++	writel(val, dbi_base + PCIE_SYS_CTRL7);
++	udelay(1000);
++
++	/*
++	 * Set PCIE controller class code to be PCI-PCI bridge device
++	 */
++	val = readl(dbi_base + PCI_CLASS_REVISION);
++	val &= ~(0xffffff00);
++	val |= (0x60400 << 8);
++	writel(val, dbi_base + PCI_CLASS_REVISION);
++	udelay(1000);
++
++	val = readl(dbi_base + PCI_COMMAND);
++	val |= 7;
++	writel(val, dbi_base + PCI_COMMAND);
++}
++
++static int __arch_pcie_sys_init(struct pcie_info *info)
++{
++	int nr;
++
++	for (nr = 0; nr < pcie_controllers_nr; nr++)
++		__arch_pcie_sys_config(&info[nr]);
++
++	return 0;
++}
++
++static void __arch_pcie_sys_exit(void)
++{
++	void *crg_base = (void *)IO_ADDRESS(PERI_CRG_BASE);
++	unsigned int val;
++
++#ifdef CONFIG_PCIE0_SEL
++	/*
++	 * Disable PCIE
++	 */
++	val = readl(dbi_base_pcie0 + PCIE_SYS_CTRL7);
++	val &= (~(1 << PCIE_APP_LTSSM_ENBALE));
++	writel(val, dbi_base_pcie0 + PCIE_SYS_CTRL7);
++
++	/*
++	 * Reset
++	 */
++	val = readl(crg_base + PERI_CRG73);
++	val |= (1 << PCIE0_X2_SRST_REQ);
++	writel(val, crg_base + PERI_CRG73);
++
++	udelay(1000);
++
++	/*
++	 * Disable clk
++	 */
++	val = readl(crg_base + PERI_CRG73);
++	val &= (~(1 << PCIE0_X2_AUX_CKEN));
++	val &= (~(1 << PCIE0_X2_PIPE_CKEN));
++	val &= (~(1 << PCIE0_X2_SYS_CKEN));
++	val &= (~(1 << PCIE0_X2_BUS_CKEN));
++	writel(val, crg_base + PERI_CRG73);
++
++	udelay(1000);
++#endif
++
++#if CONFIG_PCIE1_SEL
++	/*
++	 * Disable PCIE
++	 */
++	val = readl(dbi_base_pcie1 + PCIE_SYS_CTRL7);
++	val &= (~(1 << PCIE_APP_LTSSM_ENBALE));
++	writel(val, dbi_base_pcie1 + PCIE_SYS_CTRL7);
++
++	/*
++	 * Reset
++	 */
++	val = readl(crg_base + PERI_CRG73);
++	val |= (1 << PCIE1_X2_SRST_REQ);
++	writel(val, crg_base + PERI_CRG73);
++
++	udelay(1000);
++
++	/*
++	 * Disable clk
++	 */
++	val = readl(crg_base + PERI_CRG73);
++	val &= (~(1 << PCIE1_X2_AUX_CKEN));
++	val &= (~(1 << PCIE1_X2_PIPE_CKEN));
++	val &= (~(1 << PCIE1_X2_SYS_CKEN));
++	val &= (~(1 << PCIE1_X2_BUS_CKEN));
++	writel(val, crg_base + PERI_CRG73);
++
++	udelay(1000);
++#endif
++}
++
+diff --git a/drivers/pci/hipcie/pcie_hi3531d.h b/drivers/pci/hipcie/pcie_hi3531d.h
+new file mode 100644
+index 0000000..4c95f07
+--- /dev/null
++++ b/drivers/pci/hipcie/pcie_hi3531d.h
+@@ -0,0 +1,98 @@
++#ifndef __HISI_PCIE_H__
++#define __HISI_PCIE_H__
++
++#include <mach/io.h>
++
++#define MISC_CTRL_BASE		0x12120000
++#define PERI_CRG_BASE		0x12040000
++#define PCIE_SYS_STAT		IO_ADDRESS(0x1205008C)
++
++#define PCIE0_MEM_BASE		0x28000000
++#define PCIE0_EP_CONF_BASE	0x20000000
++#define PCIE0_DBI_BASE		0x122F0000
++#define PCIE_DBI_BASE		PCIE0_MEM_BASE
++
++#define PCIE1_MEM_BASE		0x38000000
++#define PCIE1_EP_CONF_BASE	0x30000000
++#define PCIE1_DBI_BASE		0x122F8000
++
++#define PERI_CRG_72		0x120
++#define COMPHY_CLK_REST_VAL	((0x2 << 14) | (0x2 << 12) \
++				| (0x1 << 9) | (0x1 << 8) \
++				| (0x2 << 6) | (0x2 << 4) | 0x3)
++
++#define PERI_CRG73		0x124
++
++#define PCIE0_X2_SRST_REQ	6
++#define PCIE0_X2_AUX_CKEN	3
++#define PCIE0_X2_PIPE_CKEN	2
++#define PCIE0_X2_SYS_CKEN	1
++#define PCIE0_X2_BUS_CKEN	0
++
++#define PCIE_PAD_OE_MASK	(0x7 << 8)
++
++#define PCIE1_X2_SRST_REQ	14
++#define PCIE1_X2_AUX_CKEN	11
++#define PCIE1_X2_PIPE_CKEN	10
++#define PCIE1_X2_SYS_CKEN	9
++#define PCIE1_X2_BUS_CKEN	8
++
++#define PCIE_SYS_CTRL0		0x1000
++#define PCIE_DEVICE_TYPE	28
++#define PCIE_WM_EP		0x0
++#define PCIE_WM_LEGACY		0x1
++#define PCIE_WM_RC		0x4
++
++#define PCIE_SYS_CTRL7		0x101C
++#define PCIE_APP_LTSSM_ENBALE	11
++#define PCIE_ACCESS_ENABLE	13
++
++#define PCIE_SYS_STATE0		0x1100
++#define PCIE_XMLH_LINK_UP	15
++#define PCIE_RDLH_LINK_UP	5
++
++#define PCIE0_IRQ_INTA		94
++#define PCIE0_IRQ_INTB		95
++#define PCIE0_IRQ_INTC		96
++#define PCIE0_IRQ_INTD		97
++#define PCIE0_IRQ_EDMA		98
++#define PCIE0_IRQ_MSI		99
++#define PCIE0_IRQ_LINK_DOWN	100
++
++#define PCIE1_IRQ_INTA		101
++#define PCIE1_IRQ_INTB		102
++#define PCIE1_IRQ_INTC		103
++#define PCIE1_IRQ_INTD		104
++#define PCIE1_IRQ_EDMA		105
++#define PCIE1_IRQ_MSI		106
++#define PCIE1_IRQ_LINK_DOWN	107
++
++#define PCIE_INTA_PIN		1
++#define PCIE_INTB_PIN		2
++#define PCIE_INTC_PIN		3
++#define PCIE_INTD_PIN		4
++
++#define MISC_CTRL3			0xC
++#define MISC_CTRL81			0x144
++#define MISC_CTRL80			0x140
++
++#define PCIE_COMBPHY_TEST_ADDR_EN	0x1
++#define PCIE_COMBPHY_TEST_DATA_EN	(0x9 << 8)
++
++#define PCIE_COMBPHY_TEST_WR_EN		(0x1 << 6)
++#define PCIE_COMBPHY_RECOVER		0x0
++
++#define PCIE0_REGCLK_OUTPUT_EN		(1 << 0)
++#define PCIE0_REGCLK_INPUT_EN		(1 << 1)
++#define PCIE0_REGCLK_SRC_SEL_PHY	(1 << 6)
++
++#define PCIE1_REGCLK_OUTPUT_EN		(1 << 2)
++#define PCIE1_REGCLK_INPUT_EN		(1 << 3)
++#define PCIE1_REGCLK_SRC_SEL_PHY	(1 << 7)
++
++#define REG_GPIO_15_BASE			0x12240000
++#define GPIO_15_DATA				0x4
++#define GPIO_15_DIR					0x400
++#define GPIO_15_DIR_SET_OUTPUT		1
++
++#endif
+diff --git a/drivers/pci/hipcie/pcie_hi3559.c b/drivers/pci/hipcie/pcie_hi3559.c
+new file mode 100644
+index 0000000..89d4fbe
+--- /dev/null
++++ b/drivers/pci/hipcie/pcie_hi3559.c
+@@ -0,0 +1,314 @@
++#include <mach/io.h>
++#include "pcie_hi3559.h"
++
++static void *dbi_base;
++static int __arch_pcie_info_setup(struct pcie_info *info, int *controllers_nr);
++static int __arch_pcie_sys_init(struct pcie_info *info);
++static void __arch_pcie_info_release(struct pcie_info *info);
++
++struct pcie_iatu iatu_table[] = {
++		{
++			.viewport	= 0,
++			.region_ctrl_1  = 0x00000004,
++			.region_ctrl_2  = 0x90000000,
++			.lbar           = PCIE_EP_CONF_BASE + (1<<20),
++			.ubar           = 0x0,
++			.lar            = PCIE_EP_CONF_BASE + (2<<20) - 1,
++			.ltar           = 0x01000000,
++			.utar           = 0x00000000,
++		},
++		{
++			.viewport       = 1,
++			.region_ctrl_1  = 0x00000005,
++			.region_ctrl_2  = 0x90000000,
++			.lbar           = PCIE_EP_CONF_BASE + (2<<20),
++			.ubar           = 0x0,
++			.lar            = PCIE_EP_CONF_BASE + (__128MB__ - 1),
++			.ltar           = 0x02000000,
++			.utar           = 0x00000000,
++		},
++};
++
++static void __arch_pcie_preinit(void)
++{
++
++}
++
++static struct resource pcie_mem;
++static struct resource pcie_io;
++static void __arch_get_pcie_res(int controller,
++		struct resource **pmem,
++		struct resource **pio)
++{
++	*pmem = &pcie_mem;
++	(*pmem)->start = PCIE_MEM_BASE;
++	(*pmem)->end = PCIE_MEM_BASE + __128MB__ - 0x100000 - 1;
++	(*pmem)->flags = IORESOURCE_MEM;
++	(*pmem)->name = "memory";
++
++	*pio = &pcie_io;
++	(*pio)->start = PCIE_MEM_BASE + __128MB__ - 0x100000;
++	(*pio)->end = PCIE_MEM_BASE + __128MB__ - 1;
++	(*pio)->flags = IORESOURCE_IO;
++	(*pio)->name = "io";
++}
++
++static int __arch_get_int_irq(struct pcie_info *info, u8 pin)
++{
++	switch (pin) {
++	case PCIE_INTA_PIN:
++		return PCIE_IRQ_INTA;
++	case PCIE_INTB_PIN:
++		return PCIE_IRQ_INTB;
++	case PCIE_INTC_PIN:
++		return PCIE_IRQ_INTC;
++	case PCIE_INTD_PIN:
++		return PCIE_IRQ_INTD;
++	default:
++		pcie_error("Unknown pin for mapping irq!");
++		return -1;
++	}
++}
++
++static void __arch_config_iatu_tbl(struct pcie_info *info,
++		struct pci_sys_data *sys)
++{
++	int i;
++	void __iomem *config_base = (void __iomem *)info->conf_base_addr;
++	struct pcie_iatu *ptable = iatu_table;
++	int table_size = ARRAY_SIZE(iatu_table);
++
++	for (i = 0; i < table_size; i++) {
++		writel((ptable + i)->viewport, config_base + 0x900);
++		writel((ptable + i)->lbar, config_base + 0x90c);
++		writel((ptable + i)->ubar, config_base + 0x910);
++		writel((ptable + i)->lar,  config_base + 0x914);
++		writel((ptable + i)->ltar, config_base + 0x918);
++		writel((ptable + i)->utar, config_base + 0x91c);
++		writel((ptable + i)->region_ctrl_1, config_base + 0x904);
++		writel((ptable + i)->region_ctrl_2, config_base + 0x908);
++	}
++
++}
++
++static inline int __arch_check_pcie_link(struct pcie_info *info)
++{
++	int val;
++
++	val = readl(dbi_base + PCIE_SYS_STATE0);
++	return ((val & (1 << PCIE_XMLH_LINK_UP))
++			&& (val & (1 << PCIE_RDLH_LINK_UP))) ? 1 : 0;
++}
++
++/*
++ * ret:
++ */
++static int __arch_pcie_info_setup(struct pcie_info *info, int *controllers_nr)
++{
++	unsigned int mem_size = CONFIG_PCIE0_DEVICES_MEM_SIZE;
++	unsigned int cfg_size = CONFIG_PCIE0_DEVICES_CONFIG_SIZE;
++
++	if ((mem_size > __128MB__) || (cfg_size > __128MB__)) {
++		pcie_error(
++		"Invalid parameter: pcie mem size[0x%x], pcie cfg size[0x%x]!",
++		mem_size, cfg_size);
++		return -EINVAL;
++	}
++
++	info->controller = 0;
++
++	/* RC configuration space */
++	info->conf_base_addr = (unsigned int)ioremap_nocache(PCIE_DBI_BASE,
++							 __8KB__);
++	if (!info->conf_base_addr) {
++		pcie_error("Address mapping for RC dbi failed!");
++		return -EIO;
++	}
++
++	/* Configuration space for all EPs */
++	info->base_addr = (unsigned int)ioremap_nocache(PCIE_EP_CONF_BASE,
++							 cfg_size);
++	if (!info->base_addr) {
++		iounmap((void *)info->conf_base_addr);
++		pcie_error("Address mapping for EPs cfg failed!");
++		return -EIO;
++	}
++
++	*controllers_nr = 1;
++
++	return 0;
++
++}
++
++static void __arch_pcie_info_release(struct pcie_info *info)
++{
++	if (info->base_addr)
++		iounmap((void *)info->base_addr);
++
++	if (info->conf_base_addr)
++		iounmap((void *)info->conf_base_addr);
++}
++
++void set_pcie_para(void *crg_base)
++{
++	unsigned int val;
++
++	void * misc_base = (void *)IO_ADDRESS(MISC_CTRL_BASE);
++
++	val = readl(crg_base + PERI_CRG43);
++	val = val & (~(1 << 0));
++	val = val | (1 << 1);
++	writel(val,crg_base + PERI_CRG43);
++
++	writel(0x1506, misc_base + MISC_CTRL33);
++	writel(0x11506, misc_base + MISC_CTRL33);
++	writel(0x1506, misc_base + MISC_CTRL33);
++	writel(0x0, misc_base + MISC_CTRL33);
++
++	writel(0x108, misc_base + MISC_CTRL33);
++	writel(0x10108, misc_base + MISC_CTRL33);
++	writel(0x108, misc_base + MISC_CTRL33);
++	writel(0x0, misc_base + MISC_CTRL33);
++}
++
++static int __arch_pcie_sys_init(struct pcie_info *info)
++{
++	unsigned int val;
++	void *crg_base = (void *)IO_ADDRESS(PERI_CRG_BASE);
++
++	dbi_base = (void *)info->conf_base_addr;
++
++	/*open pcie pad oe*/
++	val = readl(crg_base + PERI_CRG44);
++	val &= ~(PCIE_PAD_OE_MASK);
++	writel(val, crg_base + PERI_CRG44);
++	
++	/* refclk output from phy */
++	writel(PCIE_CLKREQ_FILTER_BYPASS,
++		(void *)IO_ADDRESS(MISC_CTRL_BASE + MISC_CTRL34));
++	mdelay(1);
++
++	/*
++	 * Disable PCIE
++	 */
++	val = readl(dbi_base + PCIE_SYS_CTRL7);
++	val &= (~(1 << PCIE_APP_LTSSM_ENBALE));
++	val |= (1 << PCIE_ACCESS_ENABLE);
++	writel(val, dbi_base + PCIE_SYS_CTRL7);
++
++	/*
++	 * Reset
++	 */
++	val = readl(crg_base + PERI_CRG44);
++	val |= (1 << PCIE_X2_SRST_REQ);
++	writel(val, crg_base + PERI_CRG44);
++
++	/*
++	 * Retreat from the reset state
++	 */
++	udelay(500);
++	val = readl(crg_base + PERI_CRG44);
++	val &= ~(1 << PCIE_X2_SRST_REQ);
++	writel(val, crg_base + PERI_CRG44);
++	mdelay(10);
++
++
++	/*
++	 * PCIE RC work mode
++	 */
++	val = readl(dbi_base + PCIE_SYS_CTRL0);
++	val &= (~(0xf << PCIE_DEVICE_TYPE));
++	val |= (PCIE_WM_RC << PCIE_DEVICE_TYPE);
++	writel(val, dbi_base + PCIE_SYS_CTRL0);
++
++	/*
++	 * Enable clk
++	 */
++	val = readl(crg_base + PERI_CRG44);
++	val |= ((1 << PCIE_X2_BUS_CKEN)
++			| (1 << PCIE_X2_SYS_CKEN)
++			| (1 << PCIE_X2_PIPE_CKEN)
++			| (1 << PCIE_X2_AUX_CKEN));
++	writel(val, crg_base + PERI_CRG44);
++
++	mdelay(10);
++	
++	set_pcie_para(crg_base);
++	mdelay(10);
++	
++	/*
++	 * Set PCIE controller class code to be PCI-PCI bridge device
++	 */
++	val = readl(dbi_base + PCI_CLASS_REVISION);
++	val &= ~(0xffffff00);
++	val |= (0x60400 << 8);
++	writel(val, dbi_base + PCI_CLASS_REVISION);
++	udelay(1000);
++
++	/* phy always work at 5Gbps */
++	writel(COM_PHY_TEST_VAL1,
++		(void *)IO_ADDRESS(MISC_CTRL_BASE + MISC_CTRL33));
++	writel(COM_PHY_TEST_VAL2,
++		(void *)IO_ADDRESS(MISC_CTRL_BASE + MISC_CTRL33));
++	writel(COM_PHY_TEST_VAL1,
++		(void *)IO_ADDRESS(MISC_CTRL_BASE + MISC_CTRL33));
++	writel(0x0, (void *)IO_ADDRESS(MISC_CTRL_BASE + MISC_CTRL33));
++	
++	/* default deemphasis to -3.5 dB */
++	writel(DEEMPHASIS_VAL, (void *)IO_ADDRESS(PCIE_DBI_BASE + DEEMPHASIS_REG));
++
++	/*
++	 * Enable controller
++	 */
++	val = readl(dbi_base + PCIE_SYS_CTRL7);
++	val |= (1 << PCIE_APP_LTSSM_ENBALE);
++	writel(val, dbi_base + PCIE_SYS_CTRL7);
++	udelay(1000);
++
++	val = readl(dbi_base + PCI_COMMAND);
++	val |= 7;
++	writel(val, dbi_base + PCI_COMMAND);
++
++	/* set pcie to gen 1*/
++#if 0
++	writel(0x1, dbi_base + 0x8BC);
++	val = readl(dbi_base + 0x7C);
++	val = ((val >> 4) << 4) | 0x1;
++	writel(val, dbi_base + 0x7C);
++#endif
++	return 0;
++}
++
++static void __arch_pcie_sys_exit(void)
++{
++	unsigned int val;
++	void *crg_base = (void *)IO_ADDRESS(PERI_CRG_BASE);
++
++	/*
++	 * Disable PCIE
++	 */
++	val = readl(dbi_base + PCIE_SYS_CTRL7);
++	val &= (~(1 << PCIE_APP_LTSSM_ENBALE));
++	writel(val, dbi_base + PCIE_SYS_CTRL7);
++
++	/*
++	 * Reset
++	 */
++	val = readl(crg_base + PERI_CRG44);
++	val |= (1 << PCIE_X2_SRST_REQ);
++	writel(val, crg_base + PERI_CRG44);
++
++	udelay(1000);
++
++	/*
++	 * Disable clk
++	 */
++	val = readl(crg_base + PERI_CRG44);
++	val &= (~(1 << PCIE_X2_AUX_CKEN));
++	val &= (~(1 << PCIE_X2_PIPE_CKEN));
++	val &= (~(1 << PCIE_X2_SYS_CKEN));
++	val &= (~(1 << PCIE_X2_BUS_CKEN));
++	writel(val, crg_base + PERI_CRG44);
++
++	udelay(1000);
++}
+diff --git a/drivers/pci/hipcie/pcie_hi3559.h b/drivers/pci/hipcie/pcie_hi3559.h
+new file mode 100644
+index 0000000..e185999
+--- /dev/null
++++ b/drivers/pci/hipcie/pcie_hi3559.h
+@@ -0,0 +1,55 @@
++#ifndef __HISI_PCIE_H__
++#define __HISI_PCIE_H__
++
++#define MISC_CTRL_BASE		0x12030000
++#define PCIE_MEM_BASE		0x28000000
++#define PCIE_EP_CONF_BASE	0x20000000
++#define PCIE_DBI_BASE		0x12160000
++#define PERI_CRG_BASE		0x12010000
++
++#define PERI_CRG43      0xAC
++#define PERI_CRG44		0xB0
++#define PCIE_X2_SRST_REQ	2
++
++#define PCIE_X2_AUX_CKEN	7
++#define PCIE_X2_PIPE_CKEN	6
++#define PCIE_X2_SYS_CKEN	5
++#define PCIE_X2_BUS_CKEN	4
++#define PCIE_PAD_OE_MASK	(0x7 << 8)
++
++#define PCIE_SYS_CTRL0		0x1000
++#define PCIE_DEVICE_TYPE	28
++#define PCIE_WM_EP		0x0
++#define PCIE_WM_LEGACY		0x1
++#define PCIE_WM_RC		0x4
++
++#define PCIE_SYS_CTRL7		0x101C
++#define PCIE_APP_LTSSM_ENBALE	11
++#define PCIE_ACCESS_ENABLE	13
++
++#define PCIE_SYS_STATE0		0x1100
++#define PCIE_XMLH_LINK_UP	15
++#define PCIE_RDLH_LINK_UP	5
++
++#define PCIE_IRQ_INTA		89
++#define PCIE_IRQ_INTB		90
++#define PCIE_IRQ_INTC		91
++#define PCIE_IRQ_INTD		92
++#define PCIE_IRQ_EDMA		93
++#define PCIE_IRQ_MSI		94
++#define PCIE_IRQ_LINK_DOWN	95
++
++#define PCIE_INTA_PIN		1
++#define PCIE_INTB_PIN		2
++#define PCIE_INTC_PIN		3
++#define PCIE_INTD_PIN		4
++
++#define MISC_CTRL33		0x84
++#define MISC_CTRL34		0x88
++#define DEEMPHASIS_REG		0xa0
++#define PCIE_CLKREQ_FILTER_BYPASS	0x600
++#define DEEMPHASIS_VAL			0x42
++#define COM_PHY_TEST_VAL1		((0x1 << 3) | (0x1 << 8))
++#define COM_PHY_TEST_VAL2		((0x1 << 16) | (0x1 << 3) | (0x1 << 8))
++
++#endif
+diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
+index 2a436e6..e433939 100644
+--- a/drivers/phy/Kconfig
++++ b/drivers/phy/Kconfig
+@@ -133,6 +133,30 @@ config PHY_EXYNOS5250_SATA
+ 	  SATA 3.0 Gb/s, SATA 6.0 Gb/s speeds. It supports one SATA host
+ 	  port to accept one SATA device.
+ 
++config PHY_HISI_INNO_USB2
++	tristate "Hisilicon Inno USB2 PHY support"
++	depends on OF && HAS_IOMEM && (USB_EHCI_HCD || HIUSB_DEVICE2_0)
++	select GENERIC_PHY
++	select MFD_SYSCON
++	default n
++	help
++	  Support for INNO PHY on Hisilicon Socs. This Phy supports
++	  USB 1.5Mb/s, USB 12Mb/s, USB 480Mb/s speeds. It suppots one
++	  USB host port to accept one USB device. Support init the phy
++	  and adjust phy Eye Diagram.
++
++config PHY_HI35x1D_INNO_USB2
++	tristate "Hisilicon 3531D&3521D Inno USB2 PHY support"
++	depends on (ARCH_HI3531D|| ARCH_HI3521D) && OF && HAS_IOMEM && (!PHY_HISI_INNO_USB2)
++	select GENERIC_PHY
++	select MFD_SYSCON
++	default y
++	help
++	  Support for INNO PHY on Hisilicon Socs. This Phy supports
++	  USB 1.5Mb/s, USB 12Mb/s, USB 480Mb/s speeds. It suppots one
++	  USB host port to accept one USB device. Support init the phy
++	  and adjust phy Eye Diagram.
++
+ config PHY_HIX5HD2_SATA
+ 	tristate "HIX5HD2 SATA PHY Driver"
+ 	depends on ARCH_HIX5HD2 && OF && HAS_IOMEM
+@@ -141,6 +165,28 @@ config PHY_HIX5HD2_SATA
+ 	help
+ 	  Support for SATA PHY on Hisilicon hix5hd2 Soc.
+ 
++config PHY_HISI_USB3
++	tristate "HISI USB3 PHY Driver"
++	depends on (ARCH_HI3519 || ARCH_HI3519V101 || ARCH_HI3559 || ARCH_HI3556 || ARCH_HI3516AV200) && OF && HAS_IOMEM && USB_XHCI_HCD
++	select GENERIC_PHY
++	select MFD_SYSCON
++	help
++	  Support for USB PHY on Hisilicon Soc.
++	  Enable this to support the hisi USB 3.0 PHY driver for hisilicon
++	  SoCs. This driver provides the interface for USB 3.0 PHY. Support
++	  init the phy and adjust phy Eye Diagram.
++
++config PHY_HI3531D_USB3
++	tristate "HI3531D USB3 PHY Driver"
++	depends on ARCH_HI3531D && OF && HAS_IOMEM && USB_XHCI_HCD
++	select GENERIC_PHY
++	select MFD_SYSCON
++	help
++	  Support for USB PHY on Hisilicon Soc.
++	  Enable this to support the hisi USB 3.0 PHY driver for hisilicon
++	  SoCs. This driver provides the interface for USB 3.0 PHY. Support
++	  init the phy and adjust phy Eye Diagram.
++
+ config PHY_SUN4I_USB
+ 	tristate "Allwinner sunxi SoC USB PHY driver"
+ 	depends on ARCH_SUNXI && HAS_IOMEM && OF
+@@ -256,4 +302,31 @@ config PHY_STIH41X_USB
+ 	  Enable this to support the USB transceiver that is part of
+ 	  STMicroelectronics STiH41x SoC series.
+ 
++config HI_NANO_PHY_SATA
++	tristate "hisilicon sata nano phy support"
++	depends on ((ARCH_HI3531D || ARCH_HI3536C || ARCH_HI3521D) && OF && HAS_IOMEM)
++	default y if (ARCH_HI3531D || ARCH_HI3536C || ARCH_HI3521D)
++	select GENERIC_PHY
++	help
++	  Enable this to support the sata nano phy that is part of
++	  sata driver for hisilicon.
++
++config HI_SATA_PORTS
++	int "hi sata port number"
++	depends on HI_NANO_PHY_SATA
++	range 1 4 if ARCH_HI3531D
++	range 1 2 if (ARCH_HI3536C || ARCH_HI3521D)
++	default "4" if ARCH_HI3531D
++	default "2" if (ARCH_HI3536C || ARCH_HI3521D)
++	help
++	  hisilicon sata port number.
++
++config HI_SATA_MODE
++	int "hi sata interworking speed mode(1.5G:0/3G:1/6G:2)"
++	depends on HI_NANO_PHY_SATA
++	range 0 2 if (ARCH_HI3536C || ARCH_HI3521D || ARCH_HI3531D)
++	default "1" if (ARCH_HI3536C || ARCH_HI3521D || ARCH_HI3531D)
++	help
++	  hisilicon interworking speed mode.
++
+ endmenu
+diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
+index c4590fc..857f284 100644
+--- a/drivers/phy/Makefile
++++ b/drivers/phy/Makefile
+@@ -16,6 +16,15 @@ obj-$(CONFIG_TI_PIPE3)			+= phy-ti-pipe3.o
+ obj-$(CONFIG_TWL4030_USB)		+= phy-twl4030-usb.o
+ obj-$(CONFIG_PHY_EXYNOS5250_SATA)	+= phy-exynos5250-sata.o
+ obj-$(CONFIG_PHY_HIX5HD2_SATA)		+= phy-hix5hd2-sata.o
++obj-$(CONFIG_HI_NANO_PHY_SATA)		+= phy-hisi-nano-phy-sata.o
++ifdef CONFIG_ARCH_HI3516CV300
++obj-$(CONFIG_PHY_HISI_INNO_USB2)	+= phy-hisi-inno-usb2.o
++else
++obj-$(CONFIG_PHY_HISI_INNO_USB2)	+= phy-hisi-usb.o
++endif
++obj-$(CONFIG_PHY_HI35x1D_INNO_USB2)	+= phy-hi35x1d-usb.o
++obj-$(CONFIG_PHY_HI3531D_USB3)		+= phy-hi3531d-usb3.o
++obj-$(CONFIG_PHY_HISI_USB3)		+= phy-hisi-usb3.o
+ obj-$(CONFIG_PHY_SUN4I_USB)		+= phy-sun4i-usb.o
+ obj-$(CONFIG_PHY_SAMSUNG_USB2)		+= phy-exynos-usb2.o
+ phy-exynos-usb2-y			+= phy-samsung-usb2.o
+diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c
+index 2733112..bfbbf43 100644
+--- a/drivers/phy/phy-core.c
++++ b/drivers/phy/phy-core.c
+@@ -586,6 +586,38 @@ struct phy *devm_of_phy_get(struct device *dev, struct device_node *np,
+ EXPORT_SYMBOL_GPL(devm_of_phy_get);
+ 
+ /**
++ * devm_of_phy_get_by_index() - lookup and obtain a reference to a phy by index.
++ * @dev: device that requests this phy
++ * @np: node containing the phy
++ * @index: index of the phy
++ *
++ * Gets the phy using _of_phy_get(), and associates a device with it using
++ * devres. On driver detach, release function is invoked on the devres data,
++ * then, devres data is freed.
++ *
++ */
++struct phy *devm_of_phy_get_by_index(struct device *dev, struct device_node *np,
++				     int index)
++{
++	struct phy **ptr, *phy;
++
++	ptr = devres_alloc(devm_phy_release, sizeof(*ptr), GFP_KERNEL);
++	if (!ptr)
++		return ERR_PTR(-ENOMEM);
++
++	phy = _of_phy_get(np, index);
++	if (!IS_ERR(phy)) {
++		*ptr = phy;
++		devres_add(dev, ptr);
++	} else {
++		devres_free(ptr);
++	}
++
++	return phy;
++}
++EXPORT_SYMBOL_GPL(devm_of_phy_get_by_index);
++
++/**
+  * phy_create() - create a new phy
+  * @dev: device that is creating the new phy
+  * @node: device node of the phy
+diff --git a/drivers/phy/phy-hi3521d-sata.c b/drivers/phy/phy-hi3521d-sata.c
+new file mode 100644
+index 0000000..8666605
+--- /dev/null
++++ b/drivers/phy/phy-hi3521d-sata.c
+@@ -0,0 +1,415 @@
++/*
++ * Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include <linux/delay.h>
++#include <linux/io.h>
++#include <linux/mfd/syscon.h>
++#include <linux/module.h>
++#include <linux/phy/phy.h>
++#include <linux/platform_device.h>
++#include <linux/regmap.h>
++#include <mach/io.h>
++#include <mach/platform.h>
++
++unsigned int sata_port_map;
++
++enum {
++	HI_SATA_PERI_CTRL		= IO_ADDRESS(0x12040000),
++	HI_SATA_PERI_CRG72		= (HI_SATA_PERI_CTRL + 0x120),
++	HI_SATA_PERI_CRG74		= (HI_SATA_PERI_CTRL + 0x128),
++
++	HI_SATA_PHY0_REFCLK_SEL_MASK = (0x3 << 4),
++	HI_SATA_PHY0_REFCLK_SEL = (0x1 << 4),
++	HI_SATA_PHY1_REFCLK_SEL_MASK = (0x3 << 6),
++	HI_SATA_PHY1_REFCLK_SEL = (0x1 << 6),
++
++	HI_SATA_PHY0_CLK_EN		= (1 << 0),
++	HI_SATA_PHY1_CLK_EN		= (1 << 1),
++
++	HI_SATA_PHY0_RST		= (1 << 2),
++	HI_SATA_PHY1_RST		= (1 << 3),
++
++	HI_SATA_PHY_BACK_MASK_ALL	= 0xf0,
++	HI_SATA_PHY1_RST_BACK_MASK	= (1 << 5),
++	HI_SATA_PHY0_RST_BACK_MASK	= (1 << 4),
++
++	HI_SATA_BUS_CKEN		= (1 << 0),
++	HI_SATA_BUS_SRST_REQ	= (1 << 8),
++	HI_SATA_CKO_ALIVE_CKEN	= (1 << 2),
++	HI_SATA_CKO_ALIVE_SRST_REQ	= (1 << 9),
++	HI_SATA_RX0_CKEN		= (1 << 1),
++	HI_SATA_TX0_CKEN		= (1 << 3),
++	HI_SATA_RX0_SRST_REQ	= (1 << 10),
++	HI_SATA0_SRST_REQ		= (1 << 11),
++	HI_SATA_RX1_CKEN		= (1 << 12),
++	HI_SATA_TX1_CKEN		= (1 << 13),
++	HI_SATA_RX1_SRST_REQ	= (1 << 14),
++	HI_SATA1_SRST_REQ		= (1 << 15),
++
++	HI_SATA_SYS_CTRL		= IO_ADDRESS(0x1205008C),
++};
++
++static void hi_sata_poweron(void)
++{
++	/* msleep(20); */
++}
++
++static void hi_sata_poweroff(void)
++{
++}
++
++void hisi_sata_reset_rxtx_assert(unsigned int port_no)
++{
++	unsigned int tmp_val;
++
++	tmp_val = readl((void *)HI_SATA_PERI_CRG74);
++
++	if (port_no == 1) {
++		tmp_val |= HI_SATA_RX1_SRST_REQ
++			| HI_SATA1_SRST_REQ;
++	} else if (port_no == 0) {
++		tmp_val |= HI_SATA_RX0_SRST_REQ
++			| HI_SATA0_SRST_REQ;
++	}
++
++	writel(tmp_val, (void *)HI_SATA_PERI_CRG74);
++}
++EXPORT_SYMBOL(hisi_sata_reset_rxtx_assert);
++
++void hisi_sata_reset_rxtx_deassert(unsigned int port_no)
++{
++	unsigned int tmp_val;
++
++	tmp_val = readl((void *)HI_SATA_PERI_CRG74);
++
++	if (port_no == 1) {
++		tmp_val &= ~(HI_SATA_RX1_SRST_REQ
++				| HI_SATA1_SRST_REQ);
++	} else if (port_no == 0) {
++		tmp_val &= ~(HI_SATA_RX0_SRST_REQ
++					| HI_SATA0_SRST_REQ);
++	}
++
++	writel(tmp_val, (void *)HI_SATA_PERI_CRG74);
++}
++EXPORT_SYMBOL(hisi_sata_reset_rxtx_deassert);
++
++static void hi_sata_reset(void)
++{
++	unsigned int tmp_val;
++
++	tmp_val = readl((void *)HI_SATA_PERI_CRG74);
++
++	tmp_val |= HI_SATA_BUS_SRST_REQ | HI_SATA_CKO_ALIVE_SRST_REQ;
++	if (n_ports == 2) {
++			tmp_val |= HI_SATA_RX0_SRST_REQ
++					| HI_SATA0_SRST_REQ
++					| HI_SATA_RX1_SRST_REQ
++					| HI_SATA1_SRST_REQ;
++	} else if (n_ports == 1) {
++			tmp_val |= HI_SATA_RX0_SRST_REQ
++					| HI_SATA0_SRST_REQ;
++	}
++
++	writel(tmp_val, (void *)HI_SATA_PERI_CRG74);
++}
++
++static void hi_sata_unreset(void)
++{
++	unsigned int tmp_val;
++
++	tmp_val = readl((void *)HI_SATA_PERI_CRG74);
++
++	tmp_val &= ~(HI_SATA_BUS_SRST_REQ | HI_SATA_CKO_ALIVE_SRST_REQ);
++	if (n_ports == 2) {
++			tmp_val &= ~(HI_SATA_RX0_SRST_REQ
++					| HI_SATA0_SRST_REQ
++					| HI_SATA_RX1_SRST_REQ
++					| HI_SATA1_SRST_REQ);
++
++	} else if (n_ports == 1) {
++		tmp_val &= ~(HI_SATA_RX0_SRST_REQ
++					| HI_SATA0_SRST_REQ);
++	}
++
++	writel(tmp_val, (void *)HI_SATA_PERI_CRG74);
++}
++
++static void hi_sata_phy_reset(void)
++{
++	unsigned int tmp_val;
++
++	tmp_val = readl((void *)HI_SATA_PERI_CRG72);
++
++	if (n_ports == 2) {
++			tmp_val |= HI_SATA_PHY0_RST
++					| HI_SATA_PHY1_RST;
++
++	} else if (n_ports == 1)
++		tmp_val |= HI_SATA_PHY0_RST;
++
++	writel(tmp_val, (void *)HI_SATA_PERI_CRG72);
++}
++
++static void hi_sata_phy_unreset(void)
++{
++	unsigned int tmp_val;
++
++	tmp_val = readl((void *)HI_SATA_PERI_CRG72);
++
++	if (n_ports == 2) {
++			tmp_val &= ~(HI_SATA_PHY0_RST
++					| HI_SATA_PHY1_RST);
++	} else if (n_ports == 1)
++			tmp_val &= ~HI_SATA_PHY0_RST;
++
++	writel(tmp_val, (void *)HI_SATA_PERI_CRG72);
++}
++
++static void hi_sata_clk_enable(void)
++{
++	unsigned int tmp_val, tmp_reg;
++
++	tmp_val = readl((void *)HI_SATA_PERI_CRG72);
++	tmp_reg = readl((void *)HI_SATA_PERI_CRG74);
++
++	if (n_ports == 2) {
++			tmp_val |= HI_SATA_PHY0_CLK_EN;
++			tmp_val |= HI_SATA_PHY1_CLK_EN;
++
++			tmp_reg |= HI_SATA_RX0_CKEN
++					| HI_SATA_TX0_CKEN
++					| HI_SATA_RX1_CKEN
++					| HI_SATA_TX1_CKEN;
++
++	} else if (n_ports == 1) {
++		tmp_val |= HI_SATA_PHY0_CLK_EN;
++
++		tmp_reg |= HI_SATA_RX0_CKEN
++				| HI_SATA_TX0_CKEN;
++
++	}
++
++	writel(tmp_val, (void *)HI_SATA_PERI_CRG72);
++	writel(tmp_reg, (void *)HI_SATA_PERI_CRG74);
++
++}
++
++static void hi_sata_clk_disable(void)
++{
++}
++
++static void hi_sata_clk_reset(void)
++{
++}
++
++static void hi_sata_phy_clk_sel(void)
++{
++	unsigned int tmp_val;
++
++	tmp_val = readl((void *)HI_SATA_PERI_CRG72);
++
++	if (n_ports == 2) {
++			tmp_val &= ~HI_SATA_PHY0_REFCLK_SEL_MASK;
++			tmp_val &= ~HI_SATA_PHY1_REFCLK_SEL_MASK;
++
++			tmp_val |= HI_SATA_PHY0_REFCLK_SEL;
++			tmp_val |= HI_SATA_PHY1_REFCLK_SEL;
++
++	} else if (n_ports == 1) {
++		tmp_val &= ~HI_SATA_PHY1_REFCLK_SEL_MASK;
++		tmp_val |= HI_SATA_PHY1_REFCLK_SEL;
++	}
++	writel(tmp_val, (void *)HI_SATA_PERI_CRG72);
++}
++
++void hisata_v200_set_fifo(void *mmio, int n_ports)
++{
++	int i;
++
++	for (i = 0; i < n_ports; i++)
++		writel(HI_SATA_FIFOTH_VALUE, (mmio + 0x100 + i*0x80
++					+ HI_SATA_PORT_FIFOTH));
++}
++
++void hisata_phy_init(void *mmio, int phy_mode, int n_ports)
++{
++	unsigned int tmp, phy_config = HI_SATA_PHY_3G;
++	unsigned int phy_sg = HI_SATA_PHY_SG_3G;
++	int i, port_no;
++
++	if ((n_ports < 1) || (n_ports > 2))
++		pr_err("ERROR: PORT num you set is WRONG!!!\n");
++
++	sata_port_map = (1 << n_ports) - 1;
++	hisata_v200_set_fifo(mmio, n_ports);
++
++	tmp = readl(mmio + HI_SATA_PHY_CTL1);
++	tmp |= HI_SATA_BIGENDINE;
++	writel(tmp, (mmio + HI_SATA_PHY_CTL1));
++	tmp = readl(mmio + HI_SATA_PHY_CTL2);
++	tmp |= HI_SATA_BIGENDINE;
++	writel(tmp, (mmio + HI_SATA_PHY_CTL2));
++
++	tmp = readl(mmio + HI_SATA_PHY_RST_BACK_MASK);
++	tmp |= HI_SATA_PHY_BACK_MASK_ALL;
++	if (n_ports == 1)
++		tmp &= ~HI_SATA_PHY1_RST_BACK_MASK;
++	else if (n_ports == 2)
++		/* Not need mask any port */
++
++	writel(tmp, (mmio + HI_SATA_PHY_RST_BACK_MASK));
++
++	if (phy_mode == HI_SATA_PHY_MODE_1_5G) {
++		phy_config = HI_SATA_PHY_1_5G;
++		phy_sg = HI_SATA_PHY_SG_1_5G;
++	}
++
++	if (phy_mode == HI_SATA_PHY_MODE_3G) {
++		phy_config = HI_SATA_PHY_3G;
++		phy_sg = HI_SATA_PHY_SG_3G;
++	}
++
++	if (phy_mode == HI_SATA_PHY_MODE_6G) {
++		phy_config = HI_SATA_PHY_6G;
++		phy_sg = HI_SATA_PHY_SG_6G;
++	}
++
++	for (i = 0; i < n_ports; i++) {
++		port_no = i;
++		writel(phy_config, (mmio + 0x100 + port_no*0x80
++					+ HI_SATA_PORT_PHYCTL));
++
++		writel(phy_sg, (mmio + 0x100 + port_no*0x80
++					+ HI_SATA_PORT_PHYCTL1));
++	}
++}
++
++static void hi_sata_phy_reg_config(void)
++{
++	unsigned int i, port_no;
++
++	for (i = 0; i < n_ports; i++) {
++		port_no = i;
++
++		if (port_no == 0) {
++			/* PLL always 6G & CDR <= RATE */
++			writel(0xd01, (void *)HI_SATA_MISC_SATA_PHY0);
++			writel(0xd41, (void *)HI_SATA_MISC_SATA_PHY0);
++			writel(0xd01, (void *)HI_SATA_MISC_SATA_PHY0);
++			writel(0x0, (void *)HI_SATA_MISC_SATA_PHY0);
++
++			/* disable SSC */
++			writel(0x803, (void *)HI_SATA_MISC_SATA_PHY0);
++			writel(0x843, (void *)HI_SATA_MISC_SATA_PHY0);
++			writel(0x803, (void *)HI_SATA_MISC_SATA_PHY0);
++			writel(0x0, (void *)HI_SATA_MISC_SATA_PHY0);
++
++			/* EQ set b010000 */
++			writel(0x009, (void *)HI_SATA_MISC_SATA_PHY0);
++			writel(0x049, (void *)HI_SATA_MISC_SATA_PHY0);
++			writel(0x009, (void *)HI_SATA_MISC_SATA_PHY0);
++			writel(0x0, (void *)HI_SATA_MISC_SATA_PHY0);
++
++			writel(0x508, (void *)HI_SATA_MISC_SATA_PHY0);
++			writel(0x548, (void *)HI_SATA_MISC_SATA_PHY0);
++			writel(0x508, (void *)HI_SATA_MISC_SATA_PHY0);
++			writel(0x0, (void *)HI_SATA_MISC_SATA_PHY0);
++		} else if (port_no == 1) {
++			/* PLL always 6G & CDR <= RATE */
++			writel(0xd01, (void *)HI_SATA_MISC_SATA_PHY1);
++			writel(0xd41, (void *)HI_SATA_MISC_SATA_PHY1);
++			writel(0xd01, (void *)HI_SATA_MISC_SATA_PHY1);
++			writel(0x0, (void *)HI_SATA_MISC_SATA_PHY1);
++
++			/* disable SSC */
++			writel(0x803, (void *)HI_SATA_MISC_SATA_PHY1);
++			writel(0x843, (void *)HI_SATA_MISC_SATA_PHY1);
++			writel(0x803, (void *)HI_SATA_MISC_SATA_PHY1);
++			writel(0x0, (void *)HI_SATA_MISC_SATA_PHY1);
++
++			/* EQ set b010000 */
++			writel(0x009, (void *)HI_SATA_MISC_SATA_PHY1);
++			writel(0x049, (void *)HI_SATA_MISC_SATA_PHY1);
++			writel(0x009, (void *)HI_SATA_MISC_SATA_PHY1);
++			writel(0x0, (void *)HI_SATA_MISC_SATA_PHY1);
++
++			writel(0x508, (void *)HI_SATA_MISC_SATA_PHY1);
++			writel(0x548, (void *)HI_SATA_MISC_SATA_PHY1);
++			writel(0x508, (void *)HI_SATA_MISC_SATA_PHY1);
++			writel(0x0, (void *)HI_SATA_MISC_SATA_PHY1);
++		}
++	}
++}
++
++void hi_sata_eq_recovery(unsigned int port_no)
++{
++	if (port_no == 0) {
++		/* EQ recovery */
++		writel(0xf09, (void *)HI_SATA_MISC_SATA_PHY0);
++		writel(0xf49, (void *)HI_SATA_MISC_SATA_PHY0);
++		writel(0xf09, (void *)HI_SATA_MISC_SATA_PHY0);
++		writel(0x0, (void *)HI_SATA_MISC_SATA_PHY0);
++
++		writel(0x308, (void *)HI_SATA_MISC_SATA_PHY0);
++		writel(0x348, (void *)HI_SATA_MISC_SATA_PHY0);
++		writel(0x308, (void *)HI_SATA_MISC_SATA_PHY0);
++		writel(0x0, (void *)HI_SATA_MISC_SATA_PHY0);
++	} else if (port_no == 1) {
++		/* EQ recovery */
++		writel(0xf09, (void *)HI_SATA_MISC_SATA_PHY1);
++		writel(0xf49, (void *)HI_SATA_MISC_SATA_PHY1);
++		writel(0xf09, (void *)HI_SATA_MISC_SATA_PHY1);
++		writel(0x0, (void *)HI_SATA_MISC_SATA_PHY1);
++
++		writel(0x308, (void *)HI_SATA_MISC_SATA_PHY1);
++		writel(0x348, (void *)HI_SATA_MISC_SATA_PHY1);
++		writel(0x308, (void *)HI_SATA_MISC_SATA_PHY1);
++		writel(0x0, (void *)HI_SATA_MISC_SATA_PHY1);
++	}
++}
++EXPORT_SYMBOL(hi_sata_eq_recovery);
++
++void hi_sata_set_eq(unsigned int port_no)
++{
++	if (port_no == 0) {
++		/* EQ set b010000 */
++		writel(0x009, (void *)HI_SATA_MISC_SATA_PHY0);
++		writel(0x049, (void *)HI_SATA_MISC_SATA_PHY0);
++		writel(0x009, (void *)HI_SATA_MISC_SATA_PHY0);
++		writel(0x0, (void *)HI_SATA_MISC_SATA_PHY0);
++
++		writel(0x508, (void *)HI_SATA_MISC_SATA_PHY0);
++		writel(0x548, (void *)HI_SATA_MISC_SATA_PHY0);
++		writel(0x508, (void *)HI_SATA_MISC_SATA_PHY0);
++		writel(0x0, (void *)HI_SATA_MISC_SATA_PHY0);
++	} else if (port_no == 1) {
++		/* EQ set b010000 */
++		writel(0x009, (void *)HI_SATA_MISC_SATA_PHY1);
++		writel(0x049, (void *)HI_SATA_MISC_SATA_PHY1);
++		writel(0x009, (void *)HI_SATA_MISC_SATA_PHY1);
++		writel(0x0, (void *)HI_SATA_MISC_SATA_PHY1);
++
++		writel(0x508, (void *)HI_SATA_MISC_SATA_PHY1);
++		writel(0x548, (void *)HI_SATA_MISC_SATA_PHY1);
++		writel(0x508, (void *)HI_SATA_MISC_SATA_PHY1);
++		writel(0x0, (void *)HI_SATA_MISC_SATA_PHY1);
++	}
++}
++EXPORT_SYMBOL(hi_sata_set_eq);
++
+diff --git a/drivers/phy/phy-hi3531d-sata.c b/drivers/phy/phy-hi3531d-sata.c
+new file mode 100644
+index 0000000..8dc6dd4
+--- /dev/null
++++ b/drivers/phy/phy-hi3531d-sata.c
+@@ -0,0 +1,814 @@
++/*
++ * Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include <linux/delay.h>
++#include <linux/io.h>
++#include <linux/mfd/syscon.h>
++#include <linux/module.h>
++#include <linux/phy/phy.h>
++#include <linux/platform_device.h>
++#include <linux/regmap.h>
++#include <mach/io.h>
++#include <mach/platform.h>
++
++static unsigned int mplx_port0;
++static unsigned int sata_port_nr;
++
++enum {
++	HI_SATA_PERI_CTRL		= IO_ADDRESS(0x12040000),
++	HI_SATA_PERI_CRG72		= (HI_SATA_PERI_CTRL + 0x120),
++	HI_SATA_PERI_CRG74		= (HI_SATA_PERI_CTRL + 0x128),
++
++	HI_SATA_PHY0_REFCLK_SEL_MASK = (0x3 << 4),
++	HI_SATA_PHY0_REFCLK_SEL = (0x1 << 4),
++	HI_SATA_PHY1_REFCLK_SEL_MASK = (0x3 << 6),
++	HI_SATA_PHY1_REFCLK_SEL = (0x1 << 6),
++	HI_SATA_PHY2_REFCLK_SEL_MASK = (0x3 << 12),
++	HI_SATA_PHY2_REFCLK_SEL = (0x1 << 12),
++	HI_SATA_PHY3_REFCLK_SEL_MASK = (0x3 << 14),
++	HI_SATA_PHY3_REFCLK_SEL = (0x1 << 14),
++
++	HI_SATA_PHY0_CLK_EN		= (1 << 0),
++	HI_SATA_PHY1_CLK_EN		= (1 << 1),
++	HI_SATA_PHY2_CLK_EN		= (1 << 8),
++	HI_SATA_PHY3_CLK_EN		= (1 << 9),
++
++	HI_SATA_PHY0_RST		= (1 << 2),
++	HI_SATA_PHY1_RST		= (1 << 3),
++	HI_SATA_PHY2_RST		= (1 << 10),
++	HI_SATA_PHY3_RST		= (1 << 11),
++
++	HI_SATA_PHY3_RST_BACK_MASK	= (1 << 7),
++	HI_SATA_PHY2_RST_BACK_MASK	= (1 << 6),
++	HI_SATA_PHY1_RST_BACK_MASK	= (1 << 5),
++	HI_SATA_PHY0_RST_BACK_MASK	= (1 << 4),
++
++	HI_SATA_BUS_CKEN		= (1 << 0),
++	HI_SATA_BUS_SRST_REQ	= (1 << 8),
++	HI_SATA_CKO_ALIVE_CKEN	= (1 << 2),
++	HI_SATA_CKO_ALIVE_SRST_REQ	= (1 << 9),
++	HI_SATA_RX0_CKEN		= (1 << 1),
++	HI_SATA_TX0_CKEN		= (1 << 3),
++	HI_SATA_RX0_SRST_REQ	= (1 << 10),
++	HI_SATA0_SRST_REQ		= (1 << 11),
++	HI_SATA_RX1_CKEN		= (1 << 12),
++	HI_SATA_TX1_CKEN		= (1 << 13),
++	HI_SATA_RX1_SRST_REQ	= (1 << 14),
++	HI_SATA1_SRST_REQ		= (1 << 15),
++	HI_SATA_RX2_CKEN        = (1 << 16),
++	HI_SATA_TX2_CKEN        = (1 << 17),
++	HI_SATA_RX2_SRST_REQ    = (1 << 18),
++	HI_SATA2_SRST_REQ       = (1 << 19),
++	HI_SATA_RX3_CKEN        = (1 << 20),
++	HI_SATA_TX3_CKEN        = (1 << 21),
++	HI_SATA_RX3_SRST_REQ    = (1 << 22),
++	HI_SATA3_SRST_REQ       = (1 << 23),
++
++	HI_SATA_SYS_CTRL		= IO_ADDRESS(0x1205008C),
++	HI_SATA_PCIE_MODE		= 12,
++};
++
++
++static unsigned int hi_sata_port_nr(void)
++{
++	unsigned int val, mode, port_nr;
++
++	val = readl((void *)HI_SATA_SYS_CTRL);
++
++	mode = (val >> HI_SATA_PCIE_MODE) & 0xf;
++	switch (mode) {
++	case 0x0:
++		port_nr = 4;
++		sata_port_map = 0xf;
++		break;
++
++	case 0x1:
++		port_nr = 3;
++		sata_port_map = 0x7;
++		break;
++
++	case 0x3:
++		port_nr = 2;
++		sata_port_map = 0x3;
++		break;
++
++	case 0x8:
++		port_nr = 3;
++		sata_port_map = 0xe;
++		break;
++
++	case 0x9:
++		port_nr = 2;
++		sata_port_map = 0x6;
++		break;
++
++	case 0xb:
++		port_nr = 1;
++		sata_port_map = 0x2;
++		break;
++
++	default:
++		port_nr = 0;
++		break;
++	}
++
++	mplx_port0 = (mode & 0x8) ? 1 : 0;
++	sata_port_nr = port_nr;
++
++	return port_nr;
++}
++
++static void hi_sata_poweron(void)
++{
++	/* msleep(20); */
++}
++
++static void hi_sata_poweroff(void)
++{
++}
++
++void hisi_sata_reset_rxtx_assert(unsigned int port_no)
++{
++	unsigned int tmp_val;
++
++	tmp_val = readl((void *)HI_SATA_PERI_CRG74);
++
++	if (port_no == 0)
++		tmp_val |= HI_SATA_RX0_SRST_REQ
++			| HI_SATA0_SRST_REQ;
++	else if (port_no == 1)
++		tmp_val |= HI_SATA_RX1_SRST_REQ
++			| HI_SATA1_SRST_REQ;
++	else if (port_no == 2)
++		tmp_val |= HI_SATA_RX2_SRST_REQ
++			| HI_SATA2_SRST_REQ;
++	else if (port_no == 3)
++		tmp_val |= HI_SATA_RX3_SRST_REQ
++			| HI_SATA3_SRST_REQ;
++
++	writel(tmp_val, (void *)HI_SATA_PERI_CRG74);
++}
++EXPORT_SYMBOL(hisi_sata_reset_rxtx_assert);
++
++void hisi_sata_reset_rxtx_deassert(unsigned int port_no)
++{
++	unsigned int tmp_val;
++
++	tmp_val = readl((void *)HI_SATA_PERI_CRG74);
++
++	if (port_no == 0)
++		tmp_val &= ~(HI_SATA_RX0_SRST_REQ
++			| HI_SATA0_SRST_REQ);
++	else if (port_no == 1)
++		tmp_val &= ~(HI_SATA_RX1_SRST_REQ
++			| HI_SATA1_SRST_REQ);
++	else if (port_no == 2)
++		tmp_val &= ~(HI_SATA_RX2_SRST_REQ
++			| HI_SATA2_SRST_REQ);
++	else if (port_no == 3)
++		tmp_val &= ~(HI_SATA_RX3_SRST_REQ
++			| HI_SATA3_SRST_REQ);
++
++	writel(tmp_val, (void *)HI_SATA_PERI_CRG74);
++}
++EXPORT_SYMBOL(hisi_sata_reset_rxtx_deassert);
++
++static void hi_sata_reset(void)
++{
++	unsigned int tmp_val, nport;
++
++	nport = sata_port_nr;
++
++	tmp_val = readl((void *)HI_SATA_PERI_CRG74);
++
++	tmp_val |= HI_SATA_BUS_SRST_REQ | HI_SATA_CKO_ALIVE_SRST_REQ;
++
++	if (nport == 4) {
++		tmp_val |= HI_SATA_RX0_SRST_REQ
++				| HI_SATA0_SRST_REQ
++				| HI_SATA_RX1_SRST_REQ
++				| HI_SATA1_SRST_REQ
++				| HI_SATA_RX2_SRST_REQ
++				| HI_SATA2_SRST_REQ
++				| HI_SATA_RX3_SRST_REQ
++				| HI_SATA3_SRST_REQ;
++	} else if (nport == 3) {
++		if (mplx_port0) {
++			tmp_val |= HI_SATA_RX1_SRST_REQ
++					| HI_SATA1_SRST_REQ
++					| HI_SATA_RX2_SRST_REQ
++					| HI_SATA2_SRST_REQ
++					| HI_SATA_RX3_SRST_REQ
++					| HI_SATA3_SRST_REQ;
++		} else {
++			tmp_val |= HI_SATA_RX0_SRST_REQ
++					| HI_SATA0_SRST_REQ
++					| HI_SATA_RX1_SRST_REQ
++					| HI_SATA1_SRST_REQ
++					| HI_SATA_RX2_SRST_REQ
++					| HI_SATA2_SRST_REQ;
++		}
++	} else if (nport == 2) {
++		if (mplx_port0) {
++			tmp_val |= HI_SATA_RX1_SRST_REQ
++					| HI_SATA1_SRST_REQ
++					| HI_SATA_RX2_SRST_REQ
++					| HI_SATA2_SRST_REQ;
++		} else {
++			tmp_val |= HI_SATA_RX0_SRST_REQ
++					| HI_SATA0_SRST_REQ
++					| HI_SATA_RX1_SRST_REQ
++					| HI_SATA1_SRST_REQ;
++		}
++	} else if (nport == 1) {
++			tmp_val |= HI_SATA_RX1_SRST_REQ
++					| HI_SATA1_SRST_REQ;
++	}
++
++	writel(tmp_val, (void *)HI_SATA_PERI_CRG74);
++}
++
++static void hi_sata_unreset(void)
++{
++	unsigned int tmp_val, nport;
++
++	nport = sata_port_nr;
++
++	tmp_val = readl((void *)HI_SATA_PERI_CRG74);
++
++	tmp_val &= ~(HI_SATA_BUS_SRST_REQ | HI_SATA_CKO_ALIVE_SRST_REQ);
++
++	if (nport == 4) {
++		tmp_val &= ~(HI_SATA_RX0_SRST_REQ
++				| HI_SATA0_SRST_REQ
++				| HI_SATA_RX1_SRST_REQ
++				| HI_SATA1_SRST_REQ
++				| HI_SATA_RX2_SRST_REQ
++				| HI_SATA2_SRST_REQ
++				| HI_SATA_RX3_SRST_REQ
++				| HI_SATA3_SRST_REQ);
++	} else if (nport == 3) {
++		if (mplx_port0) {
++			tmp_val &= ~(HI_SATA_RX1_SRST_REQ
++					| HI_SATA1_SRST_REQ
++					| HI_SATA_RX2_SRST_REQ
++					| HI_SATA2_SRST_REQ
++					| HI_SATA_RX3_SRST_REQ
++					| HI_SATA3_SRST_REQ);
++		} else {
++			tmp_val &= ~(HI_SATA_RX0_SRST_REQ
++					| HI_SATA0_SRST_REQ
++					| HI_SATA_RX1_SRST_REQ
++					| HI_SATA1_SRST_REQ
++					| HI_SATA_RX2_SRST_REQ
++					| HI_SATA2_SRST_REQ);
++		}
++	} else if (nport == 2) {
++		if (mplx_port0) {
++			tmp_val &= ~(HI_SATA_RX1_SRST_REQ
++					| HI_SATA1_SRST_REQ
++					| HI_SATA_RX2_SRST_REQ
++					| HI_SATA2_SRST_REQ);
++		} else {
++			tmp_val &= ~(HI_SATA_RX0_SRST_REQ
++					| HI_SATA0_SRST_REQ
++					| HI_SATA_RX1_SRST_REQ
++					| HI_SATA1_SRST_REQ);
++		}
++	} else if (nport == 1) {
++			tmp_val &= ~(HI_SATA_RX1_SRST_REQ
++					| HI_SATA1_SRST_REQ);
++	}
++
++	writel(tmp_val, (void *)HI_SATA_PERI_CRG74);
++}
++
++static void hi_sata_phy_reset(void)
++{
++	unsigned int tmp_val, nport;
++
++	tmp_val = readl((void *)HI_SATA_PERI_CRG72);
++
++	nport = sata_port_nr;
++
++	if (nport == 4) {
++		tmp_val |= HI_SATA_PHY0_RST
++				| HI_SATA_PHY1_RST
++				| HI_SATA_PHY2_RST
++				| HI_SATA_PHY3_RST;
++	} else if (nport == 3) {
++		if (mplx_port0) {
++			tmp_val |= HI_SATA_PHY1_RST
++					| HI_SATA_PHY2_RST
++					| HI_SATA_PHY3_RST;
++		} else {
++			tmp_val |= HI_SATA_PHY0_RST
++					| HI_SATA_PHY1_RST
++					| HI_SATA_PHY2_RST;
++		}
++	} else if (nport == 2) {
++		if (mplx_port0) {
++			tmp_val |= HI_SATA_PHY1_RST
++					| HI_SATA_PHY2_RST;
++		} else {
++			tmp_val |= HI_SATA_PHY0_RST
++					| HI_SATA_PHY1_RST;
++		}
++	} else if (nport == 1) {
++			tmp_val |= HI_SATA_PHY1_RST;
++	}
++
++	writel(tmp_val, (void *)HI_SATA_PERI_CRG72);
++}
++
++static void hi_sata_phy_unreset(void)
++{
++	unsigned int tmp_val, nport;
++
++	tmp_val = readl((void *)HI_SATA_PERI_CRG72);
++
++	nport = sata_port_nr;
++
++	if (nport == 4) {
++		tmp_val &= ~(HI_SATA_PHY0_RST
++				| HI_SATA_PHY1_RST
++				| HI_SATA_PHY2_RST
++				| HI_SATA_PHY3_RST);
++	} else if (nport == 3) {
++		if (mplx_port0) {
++			tmp_val &= ~(HI_SATA_PHY1_RST
++					| HI_SATA_PHY2_RST
++					| HI_SATA_PHY3_RST);
++		} else {
++			tmp_val &= ~(HI_SATA_PHY0_RST
++					| HI_SATA_PHY1_RST
++					| HI_SATA_PHY2_RST);
++		}
++	} else if (nport == 2) {
++		if (mplx_port0) {
++			tmp_val &= ~(HI_SATA_PHY1_RST
++					| HI_SATA_PHY2_RST);
++		} else {
++			tmp_val &= ~(HI_SATA_PHY0_RST
++					| HI_SATA_PHY1_RST);
++		}
++	} else if (nport == 1) {
++			tmp_val &= ~HI_SATA_PHY1_RST;
++	}
++
++	writel(tmp_val, (void *)HI_SATA_PERI_CRG72);
++}
++
++static void hi_sata_clk_enable(void)
++{
++	unsigned int tmp_val, tmp_reg, nport;
++
++	nport = sata_port_nr;
++
++	tmp_val = readl((void *)HI_SATA_PERI_CRG72);
++	tmp_reg = readl((void *)HI_SATA_PERI_CRG74);
++
++	tmp_reg |= HI_SATA_BUS_CKEN
++			| HI_SATA_CKO_ALIVE_CKEN;
++
++	if (nport == 4) {
++		tmp_val |= HI_SATA_PHY0_CLK_EN;
++		tmp_val |= HI_SATA_PHY1_CLK_EN;
++		tmp_val |= HI_SATA_PHY2_CLK_EN;
++		tmp_val |= HI_SATA_PHY3_CLK_EN;
++
++		tmp_reg |= HI_SATA_RX0_CKEN
++				| HI_SATA_TX0_CKEN
++				| HI_SATA_RX1_CKEN
++				| HI_SATA_TX1_CKEN
++				| HI_SATA_RX2_CKEN
++				| HI_SATA_TX2_CKEN
++				| HI_SATA_RX3_CKEN
++				| HI_SATA_TX3_CKEN;
++
++	} else if (nport == 3) {
++		if (mplx_port0) {
++			tmp_val |= HI_SATA_PHY1_CLK_EN;
++			tmp_val |= HI_SATA_PHY2_CLK_EN;
++			tmp_val |= HI_SATA_PHY3_CLK_EN;
++
++			tmp_reg |= HI_SATA_RX1_CKEN
++					| HI_SATA_TX1_CKEN
++					| HI_SATA_RX2_CKEN
++					| HI_SATA_TX2_CKEN
++					| HI_SATA_RX3_CKEN
++					| HI_SATA_TX3_CKEN;
++		} else {
++			tmp_val |= HI_SATA_PHY0_CLK_EN;
++			tmp_val |= HI_SATA_PHY1_CLK_EN;
++			tmp_val |= HI_SATA_PHY2_CLK_EN;
++
++			tmp_reg |= HI_SATA_RX0_CKEN
++					| HI_SATA_TX0_CKEN
++					| HI_SATA_RX1_CKEN
++					| HI_SATA_TX1_CKEN
++					| HI_SATA_RX2_CKEN
++					| HI_SATA_TX2_CKEN;
++		}
++	} else if (nport == 2) {
++		if (mplx_port0) {
++			tmp_val |= HI_SATA_PHY1_CLK_EN;
++			tmp_val |= HI_SATA_PHY2_CLK_EN;
++
++			tmp_reg |= HI_SATA_RX1_CKEN
++					| HI_SATA_TX1_CKEN
++					| HI_SATA_RX2_CKEN
++					| HI_SATA_TX2_CKEN;
++		} else {
++			tmp_val |= HI_SATA_PHY0_CLK_EN;
++			tmp_val |= HI_SATA_PHY1_CLK_EN;
++
++			tmp_reg |= HI_SATA_RX0_CKEN
++					| HI_SATA_TX0_CKEN
++					| HI_SATA_RX1_CKEN
++					| HI_SATA_TX1_CKEN;
++		}
++	} else if (nport == 1) {
++		tmp_val |= HI_SATA_PHY1_CLK_EN;
++
++		tmp_reg |= HI_SATA_RX1_CKEN
++				| HI_SATA_TX1_CKEN;
++	} else
++		return;
++
++	writel(tmp_val, (void *)HI_SATA_PERI_CRG72);
++	writel(tmp_reg, (void *)HI_SATA_PERI_CRG74);
++
++}
++static void hi_sata_clk_disable(void)
++{
++}
++
++static void hi_sata_clk_reset(void)
++{
++}
++
++static void hi_sata_phy_clk_sel(void)
++{
++	unsigned int tmp_val, nport;
++
++	nport = sata_port_nr;
++
++	tmp_val = readl((void *)HI_SATA_PERI_CRG72);
++
++	if (nport == 4) {
++		tmp_val &= ~HI_SATA_PHY0_REFCLK_SEL_MASK;
++		tmp_val &= ~HI_SATA_PHY1_REFCLK_SEL_MASK;
++		tmp_val &= ~HI_SATA_PHY2_REFCLK_SEL_MASK;
++		tmp_val &= ~HI_SATA_PHY3_REFCLK_SEL_MASK;
++
++		tmp_val |= HI_SATA_PHY0_REFCLK_SEL;
++		tmp_val |= HI_SATA_PHY1_REFCLK_SEL;
++		tmp_val |= HI_SATA_PHY2_REFCLK_SEL;
++		tmp_val |= HI_SATA_PHY3_REFCLK_SEL;
++	} else if (nport == 3) {
++		if (mplx_port0) {
++			tmp_val &= ~HI_SATA_PHY1_REFCLK_SEL_MASK;
++			tmp_val &= ~HI_SATA_PHY2_REFCLK_SEL_MASK;
++			tmp_val &= ~HI_SATA_PHY3_REFCLK_SEL_MASK;
++
++			tmp_val |= HI_SATA_PHY1_REFCLK_SEL;
++			tmp_val |= HI_SATA_PHY2_REFCLK_SEL;
++			tmp_val |= HI_SATA_PHY3_REFCLK_SEL;
++		} else {
++			tmp_val &= ~HI_SATA_PHY0_REFCLK_SEL_MASK;
++			tmp_val &= ~HI_SATA_PHY1_REFCLK_SEL_MASK;
++			tmp_val &= ~HI_SATA_PHY2_REFCLK_SEL_MASK;
++
++			tmp_val |= HI_SATA_PHY0_REFCLK_SEL;
++			tmp_val |= HI_SATA_PHY1_REFCLK_SEL;
++			tmp_val |= HI_SATA_PHY2_REFCLK_SEL;
++		}
++	} else if (nport == 2) {
++		if (mplx_port0) {
++			tmp_val &= ~HI_SATA_PHY1_REFCLK_SEL_MASK;
++			tmp_val &= ~HI_SATA_PHY2_REFCLK_SEL_MASK;
++
++			tmp_val |= HI_SATA_PHY1_REFCLK_SEL;
++			tmp_val |= HI_SATA_PHY2_REFCLK_SEL;
++		} else {
++			tmp_val &= ~HI_SATA_PHY0_REFCLK_SEL_MASK;
++			tmp_val &= ~HI_SATA_PHY1_REFCLK_SEL_MASK;
++
++			tmp_val |= HI_SATA_PHY0_REFCLK_SEL;
++			tmp_val |= HI_SATA_PHY1_REFCLK_SEL;
++
++		}
++	} else if (nport == 1) {
++		tmp_val &= ~HI_SATA_PHY1_REFCLK_SEL_MASK;
++		tmp_val |= HI_SATA_PHY1_REFCLK_SEL;
++	} else
++		return;
++
++	writel(tmp_val, (void *)HI_SATA_PERI_CRG72);
++}
++
++void hisata_v200_set_fifo(void *mmio, int n_ports)
++{
++	int i, port_no;
++
++	for (i = 0; i < n_ports; i++) {
++		port_no = i;
++		if (mplx_port0)
++			port_no++;
++
++		writel(HI_SATA_FIFOTH_VALUE, (mmio + 0x100 + port_no*0x80
++					+ HI_SATA_PORT_FIFOTH));
++	}
++}
++
++void hisata_phy_init(void *mmio, int phy_mode, int n_ports)
++{
++	unsigned int tmp, phy_config = HI_SATA_PHY_3G;
++	unsigned int phy_sg = HI_SATA_PHY_SG_3G;
++	int i, port_no;
++
++	hisata_v200_set_fifo(mmio, n_ports);
++
++	tmp = readl(mmio + HI_SATA_PHY_CTL1);
++	tmp |= HI_SATA_BIGENDINE;
++	writel(tmp, (mmio + HI_SATA_PHY_CTL1));
++	tmp = readl(mmio + HI_SATA_PHY_CTL2);
++	tmp |= HI_SATA_BIGENDINE;
++	writel(tmp, (mmio + HI_SATA_PHY_CTL2));
++
++	tmp = readl(mmio + HI_SATA_PHY_RST_BACK_MASK);
++	tmp &= 0xffffff0f;
++	if (n_ports == 1) {
++		tmp |= HI_SATA_PHY0_RST_BACK_MASK
++			| HI_SATA_PHY2_RST_BACK_MASK
++			| HI_SATA_PHY3_RST_BACK_MASK;
++	} else if (n_ports == 2) {
++		if (mplx_port0) {
++			tmp |= HI_SATA_PHY0_RST_BACK_MASK
++				| HI_SATA_PHY3_RST_BACK_MASK;
++		} else {
++			tmp |= HI_SATA_PHY2_RST_BACK_MASK
++				| HI_SATA_PHY3_RST_BACK_MASK;
++		}
++	} else if (n_ports == 3) {
++		if (mplx_port0)
++			tmp |= HI_SATA_PHY0_RST_BACK_MASK;
++		else
++			tmp |= HI_SATA_PHY3_RST_BACK_MASK;
++	} else if (n_ports == 4) {
++		/* Not need mask any port */
++	}
++	writel(tmp, (mmio + HI_SATA_PHY_RST_BACK_MASK));
++
++	if (phy_mode == HI_SATA_PHY_MODE_1_5G) {
++		phy_config = HI_SATA_PHY_1_5G;
++		phy_sg = HI_SATA_PHY_SG_1_5G;
++	}
++
++	if (phy_mode == HI_SATA_PHY_MODE_3G) {
++		phy_config = HI_SATA_PHY_3G;
++		phy_sg = HI_SATA_PHY_SG_3G;
++	}
++
++	if (phy_mode == HI_SATA_PHY_MODE_6G) {
++		phy_config = HI_SATA_PHY_6G;
++		phy_sg = HI_SATA_PHY_SG_6G;
++	}
++
++	for (i = 0; i < n_ports; i++) {
++		port_no = i;
++		if (mplx_port0)
++			port_no++;
++
++		writel(phy_config, (mmio + 0x100 + port_no*0x80
++					+ HI_SATA_PORT_PHYCTL));
++
++		writel(phy_sg, (mmio + 0x100 + port_no*0x80
++					+ HI_SATA_PORT_PHYCTL1));
++	}
++}
++
++static void hi_sata_phy_reg_config(void)
++{
++	unsigned int i, port_no;
++
++	for (i = 0; i < sata_port_nr; i++) {
++		port_no = i;
++		if (mplx_port0)
++			port_no++;
++
++		if (port_no == 0) {
++			/* PLL always 6G & CDR <= RATE */
++			writel(0xd01, (void *)HI_SATA_MISC_COMB_PHY0);
++			writel(0xd41, (void *)HI_SATA_MISC_COMB_PHY0);
++			writel(0xd01, (void *)HI_SATA_MISC_COMB_PHY0);
++			writel(0x0, (void *)HI_SATA_MISC_COMB_PHY0);
++
++			/* disable SSC */
++			writel(0x803, (void *)HI_SATA_MISC_COMB_PHY0);
++			writel(0x843, (void *)HI_SATA_MISC_COMB_PHY0);
++			writel(0x803, (void *)HI_SATA_MISC_COMB_PHY0);
++			writel(0x0, (void *)HI_SATA_MISC_COMB_PHY0);
++
++			/* EQ set 6'b010000 */
++			writel(0x009, (void *)HI_SATA_MISC_COMB_PHY0);
++			writel(0x049, (void *)HI_SATA_MISC_COMB_PHY0);
++			writel(0x009, (void *)HI_SATA_MISC_COMB_PHY0);
++			writel(0x0, (void *)HI_SATA_MISC_COMB_PHY0);
++
++			writel(0x508, (void *)HI_SATA_MISC_COMB_PHY0);
++			writel(0x548, (void *)HI_SATA_MISC_COMB_PHY0);
++			writel(0x508, (void *)HI_SATA_MISC_COMB_PHY0);
++			writel(0x0, (void *)HI_SATA_MISC_COMB_PHY0);
++		} else if (port_no == 1) {
++			/* PLL always 6G & CDR <= RATE */
++			writel(0xd01, (void *)HI_SATA_MISC_COMB_PHY1);
++			writel(0xd41, (void *)HI_SATA_MISC_COMB_PHY1);
++			writel(0xd01, (void *)HI_SATA_MISC_COMB_PHY1);
++			writel(0x0, (void *)HI_SATA_MISC_COMB_PHY1);
++
++			/* disable SSC */
++			writel(0x803, (void *)HI_SATA_MISC_COMB_PHY1);
++			writel(0x843, (void *)HI_SATA_MISC_COMB_PHY1);
++			writel(0x803, (void *)HI_SATA_MISC_COMB_PHY1);
++			writel(0x0, (void *)HI_SATA_MISC_COMB_PHY1);
++
++			/* EQ set 6'b010000 */
++			writel(0x009, (void *)HI_SATA_MISC_COMB_PHY1);
++			writel(0x049, (void *)HI_SATA_MISC_COMB_PHY1);
++			writel(0x009, (void *)HI_SATA_MISC_COMB_PHY1);
++			writel(0x0, (void *)HI_SATA_MISC_COMB_PHY1);
++
++			writel(0x508, (void *)HI_SATA_MISC_COMB_PHY1);
++			writel(0x548, (void *)HI_SATA_MISC_COMB_PHY1);
++			writel(0x508, (void *)HI_SATA_MISC_COMB_PHY1);
++			writel(0x0, (void *)HI_SATA_MISC_COMB_PHY1);
++		} else if (port_no == 2) {
++			/* PLL always 6G & CDR <= RATE */
++			writel(0xd01, (void *)HI_SATA_MISC_COMB_PHY2);
++			writel(0xd41, (void *)HI_SATA_MISC_COMB_PHY2);
++			writel(0xd01, (void *)HI_SATA_MISC_COMB_PHY2);
++			writel(0x0, (void *)HI_SATA_MISC_COMB_PHY2);
++
++			/* disable SSC */
++			writel(0x803, (void *)HI_SATA_MISC_COMB_PHY2);
++			writel(0x843, (void *)HI_SATA_MISC_COMB_PHY2);
++			writel(0x803, (void *)HI_SATA_MISC_COMB_PHY2);
++			writel(0x0, (void *)HI_SATA_MISC_COMB_PHY2);
++
++			/* EQ set 6'b010000 */
++			writel(0x009, (void *)HI_SATA_MISC_COMB_PHY2);
++			writel(0x049, (void *)HI_SATA_MISC_COMB_PHY2);
++			writel(0x009, (void *)HI_SATA_MISC_COMB_PHY2);
++			writel(0x0, (void *)HI_SATA_MISC_COMB_PHY2);
++
++			writel(0x508, (void *)HI_SATA_MISC_COMB_PHY2);
++			writel(0x548, (void *)HI_SATA_MISC_COMB_PHY2);
++			writel(0x508, (void *)HI_SATA_MISC_COMB_PHY2);
++			writel(0x0, (void *)HI_SATA_MISC_COMB_PHY2);
++		} else if (port_no == 3) {
++			/* PLL always 6G & CDR <= RATE */
++			writel(0xd01, (void *)HI_SATA_MISC_COMB_PHY3);
++			writel(0xd41, (void *)HI_SATA_MISC_COMB_PHY3);
++			writel(0xd01, (void *)HI_SATA_MISC_COMB_PHY3);
++			writel(0x0, (void *)HI_SATA_MISC_COMB_PHY3);
++
++			/* disable SSC */
++			writel(0x803, (void *)HI_SATA_MISC_COMB_PHY3);
++			writel(0x843, (void *)HI_SATA_MISC_COMB_PHY3);
++			writel(0x803, (void *)HI_SATA_MISC_COMB_PHY3);
++			writel(0x0, (void *)HI_SATA_MISC_COMB_PHY3);
++
++			/* EQ set 6'b010000 */
++			writel(0x009, (void *)HI_SATA_MISC_COMB_PHY3);
++			writel(0x049, (void *)HI_SATA_MISC_COMB_PHY3);
++			writel(0x009, (void *)HI_SATA_MISC_COMB_PHY3);
++			writel(0x0, (void *)HI_SATA_MISC_COMB_PHY3);
++
++			writel(0x508, (void *)HI_SATA_MISC_COMB_PHY3);
++			writel(0x548, (void *)HI_SATA_MISC_COMB_PHY3);
++			writel(0x508, (void *)HI_SATA_MISC_COMB_PHY3);
++			writel(0x0, (void *)HI_SATA_MISC_COMB_PHY3);
++		}
++	}
++}
++
++void hi_sata_eq_recovery(unsigned int port_no)
++{
++	if (port_no == 0) {
++		/* auto_eq */
++		writel(0xf09, (void *)HI_SATA_MISC_COMB_PHY0);
++		writel(0xf49, (void *)HI_SATA_MISC_COMB_PHY0);
++		writel(0xf09, (void *)HI_SATA_MISC_COMB_PHY0);
++		writel(0x0, (void *)HI_SATA_MISC_COMB_PHY0);
++
++		writel(0x308, (void *)HI_SATA_MISC_COMB_PHY0);
++		writel(0x348, (void *)HI_SATA_MISC_COMB_PHY0);
++		writel(0x308, (void *)HI_SATA_MISC_COMB_PHY0);
++		writel(0x0, (void *)HI_SATA_MISC_COMB_PHY0);
++	} else if (port_no == 1) {
++		/* auto_eq */
++		writel(0xf09, (void *)HI_SATA_MISC_COMB_PHY1);
++		writel(0xf49, (void *)HI_SATA_MISC_COMB_PHY1);
++		writel(0xf09, (void *)HI_SATA_MISC_COMB_PHY1);
++		writel(0x0, (void *)HI_SATA_MISC_COMB_PHY1);
++
++		writel(0x308, (void *)HI_SATA_MISC_COMB_PHY1);
++		writel(0x348, (void *)HI_SATA_MISC_COMB_PHY1);
++		writel(0x308, (void *)HI_SATA_MISC_COMB_PHY1);
++		writel(0x0, (void *)HI_SATA_MISC_COMB_PHY1);
++	} else if (port_no == 2) {
++		/* auto_eq */
++		writel(0xf09, (void *)HI_SATA_MISC_COMB_PHY2);
++		writel(0xf49, (void *)HI_SATA_MISC_COMB_PHY2);
++		writel(0xf09, (void *)HI_SATA_MISC_COMB_PHY2);
++		writel(0x0, (void *)HI_SATA_MISC_COMB_PHY2);
++
++		writel(0x308, (void *)HI_SATA_MISC_COMB_PHY2);
++		writel(0x348, (void *)HI_SATA_MISC_COMB_PHY2);
++		writel(0x308, (void *)HI_SATA_MISC_COMB_PHY2);
++		writel(0x0, (void *)HI_SATA_MISC_COMB_PHY2);
++	} else if (port_no == 3) {
++		/* auto_eq */
++		writel(0xf09, (void *)HI_SATA_MISC_COMB_PHY3);
++		writel(0xf49, (void *)HI_SATA_MISC_COMB_PHY3);
++		writel(0xf09, (void *)HI_SATA_MISC_COMB_PHY3);
++		writel(0x0, (void *)HI_SATA_MISC_COMB_PHY3);
++
++		writel(0x308, (void *)HI_SATA_MISC_COMB_PHY3);
++		writel(0x348, (void *)HI_SATA_MISC_COMB_PHY3);
++		writel(0x308, (void *)HI_SATA_MISC_COMB_PHY3);
++		writel(0x0, (void *)HI_SATA_MISC_COMB_PHY3);
++	}
++
++	return;
++}
++EXPORT_SYMBOL(hi_sata_eq_recovery);
++
++void hi_sata_set_eq(unsigned int port_no)
++{
++	if (port_no == 0) {
++		/* EQ set 6'b010000 */
++		writel(0x009, (void *)HI_SATA_MISC_COMB_PHY0);
++		writel(0x049, (void *)HI_SATA_MISC_COMB_PHY0);
++		writel(0x009, (void *)HI_SATA_MISC_COMB_PHY0);
++		writel(0x0, (void *)HI_SATA_MISC_COMB_PHY0);
++
++		writel(0x508, (void *)HI_SATA_MISC_COMB_PHY0);
++		writel(0x548, (void *)HI_SATA_MISC_COMB_PHY0);
++		writel(0x508, (void *)HI_SATA_MISC_COMB_PHY0);
++		writel(0x0, (void *)HI_SATA_MISC_COMB_PHY0);
++	} else if (port_no == 1) {
++		/* EQ set 6'b010000 */
++		writel(0x009, (void *)HI_SATA_MISC_COMB_PHY1);
++		writel(0x049, (void *)HI_SATA_MISC_COMB_PHY1);
++		writel(0x009, (void *)HI_SATA_MISC_COMB_PHY1);
++		writel(0x0, (void *)HI_SATA_MISC_COMB_PHY1);
++
++		writel(0x508, (void *)HI_SATA_MISC_COMB_PHY1);
++		writel(0x548, (void *)HI_SATA_MISC_COMB_PHY1);
++		writel(0x508, (void *)HI_SATA_MISC_COMB_PHY1);
++		writel(0x0, (void *)HI_SATA_MISC_COMB_PHY1);
++	} else if (port_no == 2) {
++		/* EQ set 6'b010000 */
++		writel(0x009, (void *)HI_SATA_MISC_COMB_PHY2);
++		writel(0x049, (void *)HI_SATA_MISC_COMB_PHY2);
++		writel(0x009, (void *)HI_SATA_MISC_COMB_PHY2);
++		writel(0x0, (void *)HI_SATA_MISC_COMB_PHY2);
++
++		writel(0x508, (void *)HI_SATA_MISC_COMB_PHY2);
++		writel(0x548, (void *)HI_SATA_MISC_COMB_PHY2);
++		writel(0x508, (void *)HI_SATA_MISC_COMB_PHY2);
++		writel(0x0, (void *)HI_SATA_MISC_COMB_PHY2);
++	} else if (port_no == 3) {
++		/* EQ set 6'b010000 */
++		writel(0x009, (void *)HI_SATA_MISC_COMB_PHY3);
++		writel(0x049, (void *)HI_SATA_MISC_COMB_PHY3);
++		writel(0x009, (void *)HI_SATA_MISC_COMB_PHY3);
++		writel(0x0, (void *)HI_SATA_MISC_COMB_PHY3);
++
++		writel(0x508, (void *)HI_SATA_MISC_COMB_PHY3);
++		writel(0x548, (void *)HI_SATA_MISC_COMB_PHY3);
++		writel(0x508, (void *)HI_SATA_MISC_COMB_PHY3);
++		writel(0x0, (void *)HI_SATA_MISC_COMB_PHY3);
++	}
++
++	return;
++}
++EXPORT_SYMBOL(hi_sata_set_eq);
+diff --git a/drivers/phy/phy-hi3531d-usb3.c b/drivers/phy/phy-hi3531d-usb3.c
+new file mode 100644
+index 0000000..1cc46c1
+--- /dev/null
++++ b/drivers/phy/phy-hi3531d-usb3.c
+@@ -0,0 +1,309 @@
++/*
++ * Copyright (c) 2015 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <linux/delay.h>
++#include <linux/io.h>
++#include <linux/module.h>
++#include <linux/phy/phy.h>
++#include <linux/platform_device.h>
++#include <linux/of_address.h>
++#include <mach/io.h>
++
++#define SYS_CTRL		0x12050000
++#define USB2_PHY1		0x16c
++#define USB2_PHY1_TEST_SRST_REQ	BIT(10)
++#define USB2_PHY1_SRST_TREQ	BIT(9)
++#define USB2_PHY1_SRST_REQ	BIT(8)
++#define USB2_PHY1_REF_CLKEN	BIT(0)
++
++#define HOST_U3_DISABLE        (1 << 3)
++#define USB3_U2_PHY		0x12c
++
++#define USB3_CTRL		0x12c
++#define USB3_VCC_SRST_REQ		BIT(13)
++#define USB3_UTMI_CLKEN			BIT(12)
++#define USB3_PIPE_CLKEN			BIT(11)
++#define USB3_SUSPEND_CLKEN		BIT(10)
++#define USB3_REF_CLKEN			BIT(9)
++#define USB3_BUS_CLKEN			BIT(8)
++
++#define USB3_COMBPHY		0x120
++#define COMBPHY1_LANE0_REQ		BIT(2)
++
++#define GTXTHRCFG		0xc108
++#define GRXTHRCFG		0xc10c
++#define REG_GCTL		0xc110
++#define U2RSTECN		(0x1 << 16)
++
++#define REG_GUSB2PHYCFG0	0xC200
++#define BIT_UTMI_ULPI		(0x1 << 4)
++#define BIT_UTMI_8_16		(0x1 << 3)
++
++#define REG_GUSB3PIPECTL0	0xc2c0
++#define PCS_SSP_SOFT_RESET	(0x1 << 31)
++#define TX_MARGIN_MASK		(0x7 << 3)
++#define TX_MARGIN_VAL		(0x2 << 3)
++
++#define USB2_PHY0_CTLL		0x80
++
++#define USB3_PHY		0x88
++#define COMBO_PHY_TX_DEEMP_MASK		(0x7 << 12)
++#define COMBO_PHY_TX_DEEMP_VAL		(0x1 << 12)
++
++#define USB2_PHY_TEST_REG_ACCESS        (1 << 20)
++
++struct hisi_priv {
++	void __iomem	*base;
++	void __iomem	*dwc3_ctrl; /* 0x11000000 */
++	void __iomem	*peri_ctrl; /* 0x12040000 */
++	void __iomem	*misc_ctrl; /* 0x12120000 */
++};
++
++static void hisi_usb3_phy_eye(struct phy *phy)
++{
++	int reg;
++	struct hisi_priv *priv = phy_get_drvdata(phy);
++
++	/* configuration method */
++	reg = readl(priv->misc_ctrl + 0x10);
++	reg |= USB2_PHY_TEST_REG_ACCESS;
++	writel(reg, priv->misc_ctrl + 0x10);
++	udelay(100);
++	/* slew rate */
++	writel(0xc4, priv->misc_ctrl + 0x8020);
++	udelay(20);
++	/* Calibration mode */
++	writel(0xc1, priv->misc_ctrl + 0x8044);
++	udelay(20);
++	/* disconnect threshold value */
++	writel(0x1b, priv->misc_ctrl + 0x8028);
++	udelay(20);
++	/* turn on pre-emphasis */
++	writel(0x1c, priv->misc_ctrl + 0x8000);
++	udelay(20);
++	writel(0x92, priv->misc_ctrl + 0x8014);
++	udelay(20);
++	writel(0xd, priv->misc_ctrl + 0x8018);
++	udelay(20);
++	/* down 100mv 2017/2/13 by h292880*/
++	writel(0x103, priv->misc_ctrl + 0x134);
++	udelay(20);
++	writel(0x143, priv->misc_ctrl + 0x134);
++	udelay(20);
++}
++
++static int hisi_usb3_ctrl_phy_config(struct phy *phy)
++{
++	int reg;
++	struct hisi_priv *priv = phy_get_drvdata(phy);
++
++	reg = readl(priv->dwc3_ctrl + REG_GUSB3PIPECTL0);
++	reg |= PCS_SSP_SOFT_RESET;
++	writel(reg, priv->dwc3_ctrl + REG_GUSB3PIPECTL0);
++
++	/*step 3: USB2 PHY chose ulpi 8bit interface */
++	reg = readl(priv->dwc3_ctrl + REG_GUSB2PHYCFG0);
++	reg &= ~BIT_UTMI_ULPI;
++	reg &= ~(BIT_UTMI_8_16);
++	writel(reg, priv->dwc3_ctrl + REG_GUSB2PHYCFG0);
++	mdelay(20);
++	reg = readl(priv->dwc3_ctrl + REG_GCTL);
++	reg &= ~(0x3<<12);
++	reg |= (0x1<<12); /*[13:12] 01: Host; 10: Device; 11: OTG*/
++	reg &= ~U2RSTECN;
++	writel(reg, priv->dwc3_ctrl + REG_GCTL);
++	mdelay(20);
++
++	reg = readl(priv->dwc3_ctrl + REG_GUSB3PIPECTL0);
++	reg &= ~PCS_SSP_SOFT_RESET;
++	reg &= ~(1<<17);       /* disable suspend */
++	writel(reg, priv->dwc3_ctrl + REG_GUSB3PIPECTL0);
++	mdelay(100);
++
++	writel(0x23100000, priv->dwc3_ctrl + GTXTHRCFG);
++	writel(0x23180000, priv->dwc3_ctrl + GRXTHRCFG);
++	mdelay(20);
++
++	hisi_usb3_phy_eye(phy);
++
++	return 0;
++}
++
++static int hisi_usb3_phy_on(struct phy *phy)
++{
++	int reg;
++	void __iomem *sys_base;
++	struct hisi_priv *priv = phy_get_drvdata(phy);
++
++	sys_base = ioremap(SYS_CTRL, 0x1000);
++	reg = readl(sys_base + 0x8c);
++	if ((reg & (0x1 << 15)) != 0) {
++		reg = readl(priv->peri_ctrl + 0x120);
++		reg |= COMBPHY1_LANE0_REQ;
++		writel(reg, priv->peri_ctrl + 0x120);
++		mdelay(10);
++
++		reg = readl_relaxed(priv->peri_ctrl + USB3_COMBPHY);
++		reg &= ~COMBPHY1_LANE0_REQ;
++		writel_relaxed(reg, priv->peri_ctrl + USB3_COMBPHY);
++		mdelay(10);
++	} else {
++		reg = readl(priv->misc_ctrl + 0x128);
++		reg |= HOST_U3_DISABLE;
++		writel(reg, priv->misc_ctrl + 0x128);
++		mdelay(1);
++
++		pr_info("COMBPHY IS NOT USB\n");
++	}
++	iounmap(sys_base);
++
++	reg = readl_relaxed(priv->peri_ctrl + USB2_PHY1);
++	reg &= ~USB2_PHY1_TEST_SRST_REQ;
++	reg &= ~USB2_PHY1_SRST_TREQ;
++	reg &= ~USB2_PHY1_SRST_REQ;
++	reg |= USB2_PHY1_REF_CLKEN;
++	writel_relaxed(reg, priv->peri_ctrl + USB2_PHY1);
++	mdelay(10);
++
++	reg = readl_relaxed(priv->peri_ctrl + USB3_CTRL);
++	reg |= USB3_UTMI_CLKEN;
++	reg |= USB3_PIPE_CLKEN;
++	reg |= USB3_SUSPEND_CLKEN;
++	reg |= USB3_REF_CLKEN;
++	reg |= USB3_BUS_CLKEN;
++	reg &= ~USB3_VCC_SRST_REQ;
++	writel_relaxed(reg, priv->peri_ctrl + USB3_CTRL);
++	mdelay(10);
++
++	hisi_usb3_ctrl_phy_config(phy);
++
++	return 0;
++}
++
++static int hisi_usb3_phy_power_off(struct device *dev)
++{
++	int reg;
++	struct phy *phy = dev_get_drvdata(dev);
++	struct hisi_priv *priv = phy_get_drvdata(phy);
++
++	reg = readl_relaxed(priv->peri_ctrl + USB3_COMBPHY);
++	reg |= COMBPHY1_LANE0_REQ;
++	writel_relaxed(reg, priv->peri_ctrl + USB3_COMBPHY);
++	mdelay(100);
++
++	reg = readl_relaxed(priv->peri_ctrl + USB3_CTRL);
++	reg |= USB3_VCC_SRST_REQ;
++	writel_relaxed(reg, priv->peri_ctrl + USB3_CTRL);
++	mdelay(10);
++
++	return 0;
++}
++
++static int hisi_usb3_phy_power_on(struct device *dev)
++{
++	struct phy *phy = dev_get_drvdata(dev);
++
++	hisi_usb3_phy_on(phy);
++
++	return 0;
++}
++
++static int hisi_usb3_phy_probe(struct platform_device *pdev)
++{
++	struct device *dev = &pdev->dev;
++	struct phy *phy;
++	struct hisi_priv *priv;
++	struct device_node *np = pdev->dev.of_node;
++
++	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
++	if (!priv)
++		return -ENOMEM;
++
++	priv->dwc3_ctrl = of_iomap(np, 0); /* 0x11000000 */
++	if (IS_ERR(priv->dwc3_ctrl))
++		priv->dwc3_ctrl = NULL;
++
++	priv->peri_ctrl = of_iomap(np, 1); /* 0x12040000 */
++	if (IS_ERR(priv->peri_ctrl))
++		priv->peri_ctrl = NULL;
++
++	priv->misc_ctrl = of_iomap(np, 2); /* 0x12120000 */
++	if (IS_ERR(priv->misc_ctrl))
++		priv->misc_ctrl = NULL;
++
++	phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
++	if (!phy)
++		return -ENOMEM;
++
++	platform_set_drvdata(pdev, phy);
++	phy_set_drvdata(phy, priv);
++	hisi_usb3_phy_on(phy);
++
++	return 0;
++}
++
++static int hisi_usb3_phy_remove(struct platform_device *pdev)
++{
++	int reg;
++	struct phy *phy = platform_get_drvdata(pdev);
++	struct hisi_priv *priv = phy_get_drvdata(phy);
++
++	reg = readl_relaxed(priv->peri_ctrl + USB3_CTRL);
++	reg &= ~USB3_UTMI_CLKEN;
++	reg &= ~USB3_PIPE_CLKEN;
++	reg &= ~USB3_SUSPEND_CLKEN;
++	reg &= ~USB3_REF_CLKEN;
++	reg &= ~USB3_BUS_CLKEN;
++	reg |= USB3_VCC_SRST_REQ;
++	writel_relaxed(reg, priv->peri_ctrl + USB3_CTRL);
++	mdelay(10);
++
++	return 0;
++}
++
++static const struct dev_pm_ops hisi_usb3_pmops = {
++	.suspend = hisi_usb3_phy_power_off,
++	.resume  = hisi_usb3_phy_power_on,
++#if defined(CONFIG_PM_HIBERNATE) || defined(CONFIG_HISI_SNAPSHOT_BOOT)
++	.freeze = hisi_usb3_phy_power_off,
++	.thaw = hisi_usb3_phy_power_on,
++	.poweroff = hisi_usb3_phy_power_off,
++	.restore = hisi_usb3_phy_power_on,
++#endif
++};
++
++static const struct of_device_id hisi_usb3_phy_of_match[] = {
++	{.compatible = "hisilicon,hi3531d-usb3-phy",},
++	{ },
++};
++MODULE_DEVICE_TABLE(of, hisi_usb3_phy_of_match);
++
++static struct platform_driver hisi_usb3_phy_driver = {
++	.probe	= hisi_usb3_phy_probe,
++	.remove = hisi_usb3_phy_remove,
++	.driver = {
++		.name	= "hisi-usb3-phy",
++		.of_match_table	= hisi_usb3_phy_of_match,
++		.pm    = &hisi_usb3_pmops,
++	}
++};
++module_platform_driver(hisi_usb3_phy_driver);
++
++MODULE_AUTHOR("Pengcheng Li <lpc.li@hisilicon.com>");
++MODULE_DESCRIPTION("HISILICON USB PHY driver");
++MODULE_ALIAS("platform:hisi-usb3-phy");
++MODULE_LICENSE("GPL v2");
+diff --git a/drivers/phy/phy-hi3536c-sata.c b/drivers/phy/phy-hi3536c-sata.c
+new file mode 100644
+index 0000000..dbfba40
+--- /dev/null
++++ b/drivers/phy/phy-hi3536c-sata.c
+@@ -0,0 +1,416 @@
++/*
++ * Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++
++#include <linux/delay.h>
++#include <linux/io.h>
++#include <linux/mfd/syscon.h>
++#include <linux/module.h>
++#include <linux/phy/phy.h>
++#include <linux/platform_device.h>
++#include <linux/regmap.h>
++#include <mach/io.h>
++#include <mach/platform.h>
++
++unsigned int sata_port_map;
++
++enum {
++	HI_SATA_PERI_CTRL		= IO_ADDRESS(0x12040000),
++	HI_SATA_PERI_CRG72		= (HI_SATA_PERI_CTRL + 0x120),
++	HI_SATA_PERI_CRG74		= (HI_SATA_PERI_CTRL + 0x128),
++
++	HI_SATA_PHY0_REFCLK_SEL_MASK = (0x3 << 4),
++	HI_SATA_PHY0_REFCLK_SEL = (0x1 << 4),
++	HI_SATA_PHY1_REFCLK_SEL_MASK = (0x3 << 6),
++	HI_SATA_PHY1_REFCLK_SEL = (0x1 << 6),
++
++	HI_SATA_PHY0_CLK_EN		= (1 << 0),
++	HI_SATA_PHY1_CLK_EN		= (1 << 1),
++
++	HI_SATA_PHY0_RST		= (1 << 2),
++	HI_SATA_PHY1_RST		= (1 << 3),
++
++	HI_SATA_PHY_BACK_MASK_ALL	= 0xf0,
++	HI_SATA_PHY1_RST_BACK_MASK	= (1 << 5),
++	HI_SATA_PHY0_RST_BACK_MASK	= (1 << 4),
++
++	HI_SATA_BUS_CKEN		= (1 << 0),
++	HI_SATA_BUS_SRST_REQ	= (1 << 8),
++	HI_SATA_CKO_ALIVE_CKEN	= (1 << 2),
++	HI_SATA_CKO_ALIVE_SRST_REQ	= (1 << 9),
++	HI_SATA_RX0_CKEN		= (1 << 1),
++	HI_SATA_TX0_CKEN		= (1 << 3),
++	HI_SATA_RX0_SRST_REQ	= (1 << 10),
++	HI_SATA0_SRST_REQ		= (1 << 11),
++	HI_SATA_RX1_CKEN		= (1 << 12),
++	HI_SATA_TX1_CKEN		= (1 << 13),
++	HI_SATA_RX1_SRST_REQ	= (1 << 14),
++	HI_SATA1_SRST_REQ		= (1 << 15),
++
++	HI_SATA_SYS_CTRL		= IO_ADDRESS(0x1205008C),
++};
++
++static void hi_sata_poweron(void)
++{
++	/* msleep(20); */
++}
++
++static void hi_sata_poweroff(void)
++{
++}
++
++void hisi_sata_reset_rxtx_assert(unsigned int port_no)
++{
++	unsigned int tmp_val;
++
++	tmp_val = readl((void *)HI_SATA_PERI_CRG74);
++
++	if (port_no == 1) {
++		tmp_val |= HI_SATA_RX1_SRST_REQ
++			| HI_SATA1_SRST_REQ;
++	} else if (port_no == 0) {
++		tmp_val |= HI_SATA_RX0_SRST_REQ
++			| HI_SATA0_SRST_REQ;
++	}
++
++	writel(tmp_val, (void *)HI_SATA_PERI_CRG74);
++}
++EXPORT_SYMBOL(hisi_sata_reset_rxtx_assert);
++
++void hisi_sata_reset_rxtx_deassert(unsigned int port_no)
++{
++	unsigned int tmp_val;
++
++	tmp_val = readl((void *)HI_SATA_PERI_CRG74);
++
++	if (port_no == 1) {
++		tmp_val &= ~(HI_SATA_RX1_SRST_REQ
++				| HI_SATA1_SRST_REQ);
++	} else if (port_no == 0) {
++		tmp_val &= ~(HI_SATA_RX0_SRST_REQ
++					| HI_SATA0_SRST_REQ);
++	}
++
++	writel(tmp_val, (void *)HI_SATA_PERI_CRG74);
++}
++EXPORT_SYMBOL(hisi_sata_reset_rxtx_deassert);
++
++static void hi_sata_reset(void)
++{
++	unsigned int tmp_val;
++
++	tmp_val = readl((void *)HI_SATA_PERI_CRG74);
++
++	tmp_val |= HI_SATA_BUS_SRST_REQ | HI_SATA_CKO_ALIVE_SRST_REQ;
++	if (n_ports == 2) {
++			tmp_val |= HI_SATA_RX0_SRST_REQ
++					| HI_SATA0_SRST_REQ
++					| HI_SATA_RX1_SRST_REQ
++					| HI_SATA1_SRST_REQ;
++	} else if (n_ports == 1) {
++			tmp_val |= HI_SATA_RX0_SRST_REQ
++					| HI_SATA0_SRST_REQ;
++	}
++
++	writel(tmp_val, (void *)HI_SATA_PERI_CRG74);
++}
++
++static void hi_sata_unreset(void)
++{
++	unsigned int tmp_val;
++
++	tmp_val = readl((void *)HI_SATA_PERI_CRG74);
++
++	tmp_val &= ~(HI_SATA_BUS_SRST_REQ | HI_SATA_CKO_ALIVE_SRST_REQ);
++	if (n_ports == 2) {
++			tmp_val &= ~(HI_SATA_RX0_SRST_REQ
++					| HI_SATA0_SRST_REQ
++					| HI_SATA_RX1_SRST_REQ
++					| HI_SATA1_SRST_REQ);
++
++	} else if (n_ports == 1) {
++		tmp_val &= ~(HI_SATA_RX0_SRST_REQ
++					| HI_SATA0_SRST_REQ);
++	}
++
++	writel(tmp_val, (void *)HI_SATA_PERI_CRG74);
++}
++
++static void hi_sata_phy_reset(void)
++{
++	unsigned int tmp_val;
++
++	tmp_val = readl((void *)HI_SATA_PERI_CRG72);
++
++	if (n_ports == 2) {
++			tmp_val |= HI_SATA_PHY0_RST
++					| HI_SATA_PHY1_RST;
++
++	} else if (n_ports == 1)
++		tmp_val |= HI_SATA_PHY0_RST;
++
++	writel(tmp_val, (void *)HI_SATA_PERI_CRG72);
++}
++
++static void hi_sata_phy_unreset(void)
++{
++	unsigned int tmp_val;
++
++	tmp_val = readl((void *)HI_SATA_PERI_CRG72);
++
++	if (n_ports == 2) {
++			tmp_val &= ~(HI_SATA_PHY0_RST
++					| HI_SATA_PHY1_RST);
++	} else if (n_ports == 1)
++			tmp_val &= ~HI_SATA_PHY0_RST;
++
++	writel(tmp_val, (void *)HI_SATA_PERI_CRG72);
++}
++
++static void hi_sata_clk_enable(void)
++{
++	unsigned int tmp_val, tmp_reg;
++
++	tmp_val = readl((void *)HI_SATA_PERI_CRG72);
++	tmp_reg = readl((void *)HI_SATA_PERI_CRG74);
++
++	if (n_ports == 2) {
++			tmp_val |= HI_SATA_PHY0_CLK_EN;
++			tmp_val |= HI_SATA_PHY1_CLK_EN;
++
++			tmp_reg |= HI_SATA_RX0_CKEN
++					| HI_SATA_TX0_CKEN
++					| HI_SATA_RX1_CKEN
++					| HI_SATA_TX1_CKEN;
++
++	} else if (n_ports == 1) {
++		tmp_val |= HI_SATA_PHY0_CLK_EN;
++
++		tmp_reg |= HI_SATA_RX0_CKEN
++				| HI_SATA_TX0_CKEN;
++
++	}
++
++	writel(tmp_val, (void *)HI_SATA_PERI_CRG72);
++	writel(tmp_reg, (void *)HI_SATA_PERI_CRG74);
++
++}
++
++static void hi_sata_clk_disable(void)
++{
++}
++
++static void hi_sata_clk_reset(void)
++{
++}
++
++static void hi_sata_phy_clk_sel(void)
++{
++	unsigned int tmp_val;
++
++	tmp_val = readl((void *)HI_SATA_PERI_CRG72);
++
++	if (n_ports == 2) {
++			tmp_val &= ~HI_SATA_PHY0_REFCLK_SEL_MASK;
++			tmp_val &= ~HI_SATA_PHY1_REFCLK_SEL_MASK;
++
++			tmp_val |= HI_SATA_PHY0_REFCLK_SEL;
++			tmp_val |= HI_SATA_PHY1_REFCLK_SEL;
++
++	} else if (n_ports == 1) {
++		tmp_val &= ~HI_SATA_PHY1_REFCLK_SEL_MASK;
++		tmp_val |= HI_SATA_PHY1_REFCLK_SEL;
++	}
++	writel(tmp_val, (void *)HI_SATA_PERI_CRG72);
++}
++
++void hisata_v200_set_fifo(void *mmio, int n_ports)
++{
++	int i;
++
++	for (i = 0; i < n_ports; i++)
++		writel(HI_SATA_FIFOTH_VALUE, (mmio + 0x100 + i*0x80
++					+ HI_SATA_PORT_FIFOTH));
++}
++
++void hisata_phy_init(void *mmio, int phy_mode, int n_ports)
++{
++	unsigned int tmp, phy_config = HI_SATA_PHY_3G;
++	unsigned int phy_sg = HI_SATA_PHY_SG_3G;
++	int i, port_no;
++
++	if ((n_ports < 1) || (n_ports > 2))
++		pr_err("ERROR: PORT num you set is WRONG!!!\n");
++
++	sata_port_map = (1 << n_ports) - 1;
++	hisata_v200_set_fifo(mmio, n_ports);
++
++	tmp = readl(mmio + HI_SATA_PHY_CTL1);
++	tmp |= HI_SATA_BIGENDINE;
++	writel(tmp, (mmio + HI_SATA_PHY_CTL1));
++	tmp = readl(mmio + HI_SATA_PHY_CTL2);
++	tmp |= HI_SATA_BIGENDINE;
++	writel(tmp, (mmio + HI_SATA_PHY_CTL2));
++
++	tmp = readl(mmio + HI_SATA_PHY_RST_BACK_MASK);
++	tmp |= HI_SATA_PHY_BACK_MASK_ALL;
++	if (n_ports == 1)
++		tmp &= ~HI_SATA_PHY1_RST_BACK_MASK;
++	else if (n_ports == 2)
++		/* Not need mask any port */
++
++	writel(tmp, (mmio + HI_SATA_PHY_RST_BACK_MASK));
++
++	if (phy_mode == HI_SATA_PHY_MODE_1_5G) {
++		phy_config = HI_SATA_PHY_1_5G;
++		phy_sg = HI_SATA_PHY_SG_1_5G;
++	}
++
++	if (phy_mode == HI_SATA_PHY_MODE_3G) {
++		phy_config = HI_SATA_PHY_3G;
++		phy_sg = HI_SATA_PHY_SG_3G;
++	}
++
++	if (phy_mode == HI_SATA_PHY_MODE_6G) {
++		phy_config = HI_SATA_PHY_6G;
++		phy_sg = HI_SATA_PHY_SG_6G;
++	}
++
++	for (i = 0; i < n_ports; i++) {
++		port_no = i;
++		writel(phy_config, (mmio + 0x100 + port_no*0x80
++					+ HI_SATA_PORT_PHYCTL));
++
++		writel(phy_sg, (mmio + 0x100 + port_no*0x80
++					+ HI_SATA_PORT_PHYCTL1));
++	}
++}
++
++static void hi_sata_phy_reg_config(void)
++{
++	unsigned int i, port_no;
++
++	for (i = 0; i < n_ports; i++) {
++		port_no = i;
++
++		if (port_no == 0) {
++			/* PLL always 6G & CDR <= RATE */
++			writel(0xd01, (void *)HI_SATA_MISC_SATA_PHY0);
++			writel(0xd41, (void *)HI_SATA_MISC_SATA_PHY0);
++			writel(0xd01, (void *)HI_SATA_MISC_SATA_PHY0);
++			writel(0x0, (void *)HI_SATA_MISC_SATA_PHY0);
++
++			/* disable SSC */
++			writel(0x803, (void *)HI_SATA_MISC_SATA_PHY0);
++			writel(0x843, (void *)HI_SATA_MISC_SATA_PHY0);
++			writel(0x803, (void *)HI_SATA_MISC_SATA_PHY0);
++			writel(0x0, (void *)HI_SATA_MISC_SATA_PHY0);
++
++			/* EQ set b010000 */
++			writel(0x009, (void *)HI_SATA_MISC_SATA_PHY0);
++			writel(0x049, (void *)HI_SATA_MISC_SATA_PHY0);
++			writel(0x009, (void *)HI_SATA_MISC_SATA_PHY0);
++			writel(0x0, (void *)HI_SATA_MISC_SATA_PHY0);
++
++			writel(0x508, (void *)HI_SATA_MISC_SATA_PHY0);
++			writel(0x548, (void *)HI_SATA_MISC_SATA_PHY0);
++			writel(0x508, (void *)HI_SATA_MISC_SATA_PHY0);
++			writel(0x0, (void *)HI_SATA_MISC_SATA_PHY0);
++		} else if (port_no == 1) {
++			/* PLL always 6G & CDR <= RATE */
++			writel(0xd01, (void *)HI_SATA_MISC_SATA_PHY1);
++			writel(0xd41, (void *)HI_SATA_MISC_SATA_PHY1);
++			writel(0xd01, (void *)HI_SATA_MISC_SATA_PHY1);
++			writel(0x0, (void *)HI_SATA_MISC_SATA_PHY1);
++
++			/* disable SSC */
++			writel(0x803, (void *)HI_SATA_MISC_SATA_PHY1);
++			writel(0x843, (void *)HI_SATA_MISC_SATA_PHY1);
++			writel(0x803, (void *)HI_SATA_MISC_SATA_PHY1);
++			writel(0x0, (void *)HI_SATA_MISC_SATA_PHY1);
++
++			/* EQ set b010000 */
++			writel(0x009, (void *)HI_SATA_MISC_SATA_PHY1);
++			writel(0x049, (void *)HI_SATA_MISC_SATA_PHY1);
++			writel(0x009, (void *)HI_SATA_MISC_SATA_PHY1);
++			writel(0x0, (void *)HI_SATA_MISC_SATA_PHY1);
++
++			writel(0x508, (void *)HI_SATA_MISC_SATA_PHY1);
++			writel(0x548, (void *)HI_SATA_MISC_SATA_PHY1);
++			writel(0x508, (void *)HI_SATA_MISC_SATA_PHY1);
++			writel(0x0, (void *)HI_SATA_MISC_SATA_PHY1);
++		}
++	}
++}
++
++void hi_sata_eq_recovery(unsigned int port_no)
++{
++	if (port_no == 0) {
++		/* EQ recovery */
++		writel(0xf09, (void *)HI_SATA_MISC_SATA_PHY0);
++		writel(0xf49, (void *)HI_SATA_MISC_SATA_PHY0);
++		writel(0xf09, (void *)HI_SATA_MISC_SATA_PHY0);
++		writel(0x0, (void *)HI_SATA_MISC_SATA_PHY0);
++
++		writel(0x308, (void *)HI_SATA_MISC_SATA_PHY0);
++		writel(0x348, (void *)HI_SATA_MISC_SATA_PHY0);
++		writel(0x308, (void *)HI_SATA_MISC_SATA_PHY0);
++		writel(0x0, (void *)HI_SATA_MISC_SATA_PHY0);
++	} else if (port_no == 1) {
++		/* EQ recovery */
++		writel(0xf09, (void *)HI_SATA_MISC_SATA_PHY1);
++		writel(0xf49, (void *)HI_SATA_MISC_SATA_PHY1);
++		writel(0xf09, (void *)HI_SATA_MISC_SATA_PHY1);
++		writel(0x0, (void *)HI_SATA_MISC_SATA_PHY1);
++
++		writel(0x308, (void *)HI_SATA_MISC_SATA_PHY1);
++		writel(0x348, (void *)HI_SATA_MISC_SATA_PHY1);
++		writel(0x308, (void *)HI_SATA_MISC_SATA_PHY1);
++		writel(0x0, (void *)HI_SATA_MISC_SATA_PHY1);
++	}
++}
++EXPORT_SYMBOL(hi_sata_eq_recovery);
++
++void hi_sata_set_eq(unsigned int port_no)
++{
++	if (port_no == 0) {
++		/* EQ set b010000 */
++		writel(0x009, (void *)HI_SATA_MISC_SATA_PHY0);
++		writel(0x049, (void *)HI_SATA_MISC_SATA_PHY0);
++		writel(0x009, (void *)HI_SATA_MISC_SATA_PHY0);
++		writel(0x0, (void *)HI_SATA_MISC_SATA_PHY0);
++
++		writel(0x508, (void *)HI_SATA_MISC_SATA_PHY0);
++		writel(0x548, (void *)HI_SATA_MISC_SATA_PHY0);
++		writel(0x508, (void *)HI_SATA_MISC_SATA_PHY0);
++		writel(0x0, (void *)HI_SATA_MISC_SATA_PHY0);
++	} else if (port_no == 1) {
++		/* EQ set b010000 */
++		writel(0x009, (void *)HI_SATA_MISC_SATA_PHY1);
++		writel(0x049, (void *)HI_SATA_MISC_SATA_PHY1);
++		writel(0x009, (void *)HI_SATA_MISC_SATA_PHY1);
++		writel(0x0, (void *)HI_SATA_MISC_SATA_PHY1);
++
++		writel(0x508, (void *)HI_SATA_MISC_SATA_PHY1);
++		writel(0x548, (void *)HI_SATA_MISC_SATA_PHY1);
++		writel(0x508, (void *)HI_SATA_MISC_SATA_PHY1);
++		writel(0x0, (void *)HI_SATA_MISC_SATA_PHY1);
++	}
++}
++EXPORT_SYMBOL(hi_sata_set_eq);
++
+diff --git a/drivers/phy/phy-hi35x1d-usb.c b/drivers/phy/phy-hi35x1d-usb.c
+new file mode 100644
+index 0000000..2fdf0ba
+--- /dev/null
++++ b/drivers/phy/phy-hi35x1d-usb.c
+@@ -0,0 +1,350 @@
++/*
++ * Copyright (c) 2015 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <linux/delay.h>
++#include <linux/io.h>
++#include <linux/module.h>
++#include <linux/phy/phy.h>
++#include <linux/platform_device.h>
++#include <linux/of_address.h>
++#include <mach/io.h>
++#include <linux/kthread.h>
++#include <linux/export.h>
++
++#define USB2_CTRL		0x130
++#define USB2_BUS_CKEN		(1 << 0)
++#define USB2_OHCI48M_CKEN	(1 << 1)
++#define USB2_OHCI12M_CKEN	(1 << 2)
++#define USB2_HST_PHY_CKEN	(1 << 4)
++#define USB2_UTMI0_CKEN		(1 << 5)
++#define USB2_UTMI1_CKEN		(1 << 6)
++#define USB2_BUS_SRST_REQ	(1 << 12)
++#define USB2_UTMI0_SRST_REQ	(1 << 13)
++#define USB2_UTMI1_SRST_REQ	(1 << 14)
++#define USB2_HST_PHY_SYST_REQ	(1 << 16)
++
++#define REG_USB2_PHY0		0x134
++#define USB_PHY0_REF_CKEN	(1 << 0)
++#define USB_PHY0_SRST_REQ	(1 << 8)
++#define USB_PHY0_SRST_TREQ	(1 << 9)
++#define USB_PHY1_SRST_TREQ	(1 << 10)
++#define USB_PHY0_TEST_SRST_REQ	(1 << 11)
++#define USB_PHY0_REFCLK_SEL	(1 << 16)
++#ifdef CONFIG_ARCH_HI3531D
++#define USB1_CTRL0		0x90
++#endif
++#if defined(CONFIG_ARCH_HI3521D) || defined(CONFIG_ARCH_HI3536C)
++#define USB1_CTRL0		0x50
++#endif
++#define WORDINTERFACE		(1 << 0)
++#define SS_BURST4_EN		(1 << 7)
++#define SS_BURST8_EN		(1 << 8)
++#define SS_BURST16_EN		(1 << 9)
++
++#define USB2_PHY_TEST_REG_ACCESS	(1 << 20)
++
++#define USB2_CTRL1		0x94
++/* write(0x1 << 5) 0x6 to addr 0x4 */
++#define CONFIG_CLK	((0x1 << 21) | (0x6 << 8) | (0x4 << 0))
++
++extern int otg_usbdev_stat;
++int otg_usbhost_stat;
++EXPORT_SYMBOL(otg_usbhost_stat);
++
++struct hisi_priv {
++	void __iomem	*base;
++	void __iomem	*peri_ctrl; /* 0x12040000 */
++	void __iomem	*misc_ctrl; /* 0x12120000 */
++};
++
++static int hisi_usb_phy_on(struct phy *phy)
++{
++	int reg;
++	struct hisi_priv *priv = phy_get_drvdata(phy);
++
++	/* reset enable */
++	reg = readl(priv->peri_ctrl + USB2_CTRL);
++	reg |= (USB2_BUS_SRST_REQ
++		| USB2_UTMI0_SRST_REQ
++		| USB2_HST_PHY_SYST_REQ);
++#if defined(CONFIG_ARCH_HI3521D) || defined(CONFIG_ARCH_HI3536C)
++	reg |= USB2_UTMI1_SRST_REQ;
++#endif
++
++	writel(reg, priv->peri_ctrl + USB2_CTRL);
++	udelay(200);
++
++	reg = readl(priv->peri_ctrl + REG_USB2_PHY0);
++	reg |= (USB_PHY0_SRST_REQ
++		| USB_PHY0_SRST_TREQ);
++#if defined(CONFIG_ARCH_HI3521D) || defined(CONFIG_ARCH_HI3536C)
++	reg |= USB_PHY1_SRST_TREQ;
++#endif
++	writel(reg, priv->peri_ctrl + REG_USB2_PHY0);
++	udelay(200);
++	reg = readl(priv->misc_ctrl + USB1_CTRL0);
++	reg &= ~(WORDINTERFACE); /* 8bit */
++	reg &= ~(SS_BURST16_EN); /* 16 bit burst disable */
++	writel(reg, priv->misc_ctrl + USB1_CTRL0);
++	udelay(100);
++	/* for ssk usb storage ok */
++	msleep(20);
++
++	/* open ref clock */
++	reg = readl(priv->peri_ctrl + REG_USB2_PHY0);
++	reg |= (USB_PHY0_REF_CKEN);
++	writel(reg, priv->peri_ctrl + REG_USB2_PHY0);
++	udelay(100);
++
++	/* cancel power on reset */
++	reg = readl(priv->peri_ctrl + REG_USB2_PHY0);
++	reg &= ~(USB_PHY0_SRST_REQ);
++	reg &= ~(USB_PHY0_TEST_SRST_REQ);
++	writel(reg , priv->peri_ctrl + REG_USB2_PHY0);
++	udelay(300);
++
++	/* config type */
++	reg = readl(priv->misc_ctrl + 0x10);
++	reg |= USB2_PHY_TEST_REG_ACCESS;
++	writel(reg, priv->misc_ctrl + 0x10);
++	udelay(2);
++#if defined(CONFIG_ARCH_HI3521D) || defined(CONFIG_ARCH_HI3536C)
++	/* config clock */
++	writel(0xc, priv->misc_ctrl + 0x8018);
++	mdelay(2);
++	/* port0 IComp default 400 and disconnect 625mv */
++	writel(0x1, priv->misc_ctrl + 0x8028);
++	udelay(20);
++	/* port1 IComp default400 and disconnect 625mv */
++	writel(0x1, priv->misc_ctrl + 0x8428);
++	udelay(20);
++	/* comp 262mv */
++	writel(0xc, priv->misc_ctrl + 0x8018);
++	udelay(20);
++	writel(0x92, priv->misc_ctrl + 0x8014);
++	udelay(20);
++	/* port0 pre-emphasis to adjust for 000 0x9[5:3] */
++	writel(0x4, priv->misc_ctrl + 0x8024);
++	udelay(20);
++	/* port1 pre-emphasis to adjust for 000 0x9[5:3] */
++	writel(0x4, priv->misc_ctrl + 0x8424);
++	udelay(20);
++	/* port 1 pre driver  011 */
++	writel(0xc4, priv->misc_ctrl + 0x8420);
++	udelay(20);
++	/* port0 pre-emphasis to adjust for 000 0x9[5:3] */
++	writel(0xc4, priv->misc_ctrl + 0x8020);
++	udelay(20);
++#endif
++#ifdef CONFIG_ARCH_HI3531D
++	/* config clock */
++	writel(0xc, priv->misc_ctrl + 0x4018);
++	mdelay(2);
++	/* slew rate */
++	writel(0xc4, priv->misc_ctrl + 0x4020);
++	udelay(20);
++	writel(0xc1, priv->misc_ctrl + 0x4044);
++	udelay(20);
++	/* disconnect */
++	writel(0x1b, priv->misc_ctrl + 0x4028);
++	udelay(20);
++	writel(0x1c, priv->misc_ctrl + 0x4000);
++	udelay(20);
++	writel(0x92, priv->misc_ctrl + 0x4014);
++	udelay(20);
++	writel(0xe, priv->misc_ctrl + 0x4018);
++	udelay(20);
++	writel(0x4, priv->misc_ctrl + 0x4024);
++	udelay(20);
++#endif
++	/* cancel port reset */
++	reg = readl(priv->peri_ctrl + REG_USB2_PHY0);
++	reg &= ~(USB_PHY0_SRST_TREQ);
++#if defined(CONFIG_ARCH_HI3521D) || defined(CONFIG_ARCH_HI3536C)
++	reg &= ~(USB_PHY1_SRST_TREQ);
++#endif
++	writel(reg, priv->peri_ctrl + REG_USB2_PHY0);
++	udelay(300);
++
++	/* cancel control reset */
++	reg = readl(priv->peri_ctrl + USB2_CTRL);
++	reg &= ~(USB2_BUS_SRST_REQ
++		| USB2_UTMI0_SRST_REQ
++		| USB2_HST_PHY_SYST_REQ);
++#if defined(CONFIG_ARCH_HI3521D) || defined(CONFIG_ARCH_HI3536C)
++	reg &= ~USB2_UTMI1_SRST_REQ;
++#endif
++
++	reg |= (USB2_BUS_CKEN
++			| USB2_OHCI48M_CKEN
++			| USB2_OHCI12M_CKEN
++			| USB2_HST_PHY_CKEN
++			| USB2_UTMI0_CKEN);
++#if defined(CONFIG_ARCH_HI3521D) || defined(CONFIG_ARCH_HI3536C)
++	reg |= USB2_UTMI1_CKEN;
++#endif
++	writel(reg, priv->peri_ctrl + USB2_CTRL);
++	udelay(200);
++
++	return 0;
++}
++
++static int hisi_usb_phy_probe(struct platform_device *pdev)
++{
++	struct device *dev = &pdev->dev;
++	struct phy *phy;
++	struct hisi_priv *priv;
++	struct device_node *np = pdev->dev.of_node;
++
++	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
++	if (!priv)
++		return -ENOMEM;
++
++	priv->peri_ctrl = of_iomap(np, 0); /* 0x12040000 */
++	if (IS_ERR(priv->peri_ctrl))
++		priv->peri_ctrl = NULL;
++
++	priv->misc_ctrl = of_iomap(np, 1); /* 0x12120000 */
++	if (IS_ERR(priv->misc_ctrl))
++		priv->misc_ctrl = NULL;
++
++
++	phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
++	if (!phy)
++		return -ENOMEM;
++	platform_set_drvdata(pdev, phy);
++	phy_set_drvdata(phy, priv);
++	hisi_usb_phy_on(phy);
++
++	return 0;
++}
++
++static int hisi_usb_phy_remove(struct platform_device *pdev)
++{
++#if 1
++	int reg;
++	struct phy *phy = platform_get_drvdata(pdev);
++	struct hisi_priv *priv = phy_get_drvdata(phy);
++
++	reg = readl(priv->peri_ctrl + REG_USB2_PHY0);
++	reg |= (USB_PHY0_SRST_REQ
++		| USB_PHY0_SRST_TREQ);
++#if defined(CONFIG_ARCH_HI3521D) || defined(CONFIG_ARCH_HI3536C)
++	reg |= USB_PHY1_SRST_TREQ;
++#endif
++	writel(reg, priv->peri_ctrl + REG_USB2_PHY0);
++	udelay(100);
++
++	/* close clock */
++	reg = readl(priv->peri_ctrl + REG_USB2_PHY0);
++	reg &= ~(USB_PHY0_REFCLK_SEL
++		| USB_PHY0_REF_CKEN);
++	writel(reg, priv->peri_ctrl + REG_USB2_PHY0);
++	udelay(300);
++
++	/* close clock */
++	reg = readl(priv->peri_ctrl + USB2_CTRL);
++	reg &= ~(USB2_BUS_CKEN
++		| USB2_OHCI48M_CKEN
++		| USB2_OHCI12M_CKEN
++		| USB2_HST_PHY_CKEN
++		| USB2_UTMI0_CKEN);
++#if defined(CONFIG_ARCH_HI3521D) || defined(CONFIG_ARCH_HI3536C)
++	reg &= ~USB2_UTMI1_CKEN;
++#endif
++	writel(reg, priv->peri_ctrl + USB2_CTRL);
++	udelay(200);
++#endif
++	return 0;
++}
++
++static const struct of_device_id hisi_usb_phy_of_match[] = {
++	{.compatible = "hisilicon,hi3531d-usb2-phy",},
++	{.compatible = "hisilicon,hi3521d-usb2-phy",},
++	{.compatible = "hisilicon,hi3536c-usb2-phy",},
++	{ },
++};
++MODULE_DEVICE_TABLE(of, hisi_usb_phy_of_match);
++
++#ifdef CONFIG_PM_SLEEP
++
++static int hisi_usb_phy_suspend(struct device *dev)
++{
++	int reg;
++	struct phy *phy = dev_get_drvdata(dev);
++	struct hisi_priv *priv = phy_get_drvdata(phy);
++
++	reg = readl(priv->peri_ctrl + REG_USB2_PHY0);
++	reg |= (USB_PHY0_SRST_REQ
++		| USB_PHY0_SRST_TREQ);
++#if defined(CONFIG_ARCH_HI3521D) || defined(CONFIG_ARCH_HI3536C)
++	reg |= USB_PHY1_SRST_TREQ;
++#endif
++	writel(reg, priv->peri_ctrl + REG_USB2_PHY0);
++	udelay(100);
++
++	/* close clock */
++	reg = readl(priv->peri_ctrl + REG_USB2_PHY0);
++	reg &= ~(USB_PHY0_REFCLK_SEL
++		| USB_PHY0_REF_CKEN);
++	writel(reg, priv->peri_ctrl + REG_USB2_PHY0);
++	udelay(300);
++
++	/* close clock */
++	reg = readl(priv->peri_ctrl + USB2_CTRL);
++	reg &= ~(USB2_BUS_CKEN
++		| USB2_OHCI48M_CKEN
++		| USB2_OHCI12M_CKEN
++		| USB2_HST_PHY_CKEN
++		| USB2_UTMI0_CKEN);
++#if defined(CONFIG_ARCH_HI3521D) || defined(CONFIG_ARCH_HI3536C)
++	reg &= ~USB2_UTMI1_CKEN;
++#endif
++	writel(reg, priv->peri_ctrl + USB2_CTRL);
++	udelay(200);
++
++	return 0;
++}
++
++static int hisi_usb_phy_resume(struct device *dev)
++{
++	struct phy *phy = dev_get_drvdata(dev);
++
++	hisi_usb_phy_on(phy);
++	return 0;
++}
++
++#endif /* CONFIG_PM_SLEEP */
++
++static SIMPLE_DEV_PM_OPS(hisi_usb2_pm_ops, hisi_usb_phy_suspend,
++		hisi_usb_phy_resume);
++
++static struct platform_driver hisi_usb_phy_driver = {
++	.probe	= hisi_usb_phy_probe,
++	.remove = hisi_usb_phy_remove,
++	.driver = {
++		.name	= "hisi-usb-phy",
++		.pm     = &hisi_usb2_pm_ops,
++		.of_match_table	= hisi_usb_phy_of_match,
++	}
++};
++module_platform_driver(hisi_usb_phy_driver);
++
++MODULE_AUTHOR("Pengcheng Li <lpc.li@hisilicon.com>");
++MODULE_DESCRIPTION("HISILICON USB PHY driver");
++MODULE_ALIAS("platform:hisi-usb-phy");
++MODULE_LICENSE("GPL v2");
+diff --git a/drivers/phy/phy-hisi-inno-usb2.c b/drivers/phy/phy-hisi-inno-usb2.c
+new file mode 100644
+index 0000000..1a50295
+--- /dev/null
++++ b/drivers/phy/phy-hisi-inno-usb2.c
+@@ -0,0 +1,489 @@
++ /*
++ * HiSilicon INNO USB2 PHY Driver.
++ *
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <linux/clk.h>
++#include <linux/delay.h>
++#include <linux/mfd/syscon.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/phy/phy.h>
++#include <linux/io.h>
++#include <linux/regmap.h>
++#include <linux/reset.h>
++#include <linux/kthread.h>
++#include <linux/export.h>
++#include <linux/pm.h>
++#include <linux/of_address.h>
++
++#define USB2_SWITCH_BASE		ioremap_nocache(0x12020150, 0x4)
++#define USB2_OTG_BASE		0x5c
++#define USB2_PHY_SET		0x60
++#define USB_PHY_REG_ACCESS	(0x1 << 16)
++#define DWC_OTG_EN                      (1 << 31)
++#define USB2_PHY_DPPULL_DOWN            (0x3 << 26)
++#define	MAX_PORTS	4
++#define	PHY_CLK		0x18
++
++#define US2_CRG_BASE		0xb8
++#define	USB2_OHCI48M_CKEN	(0x1 << 1)
++#define	USB2_OHCI12M_CKEN	(0x1 << 2)
++#define	USB2_HST_PHY_CKEN	(0x1 << 4)
++#define	USB2_UTMI0_CKEN		(0x1 << 5)
++#define	USB2_PHY_CKEN		(0x1 << 7)
++#define	USB2_BUS_SRST_REQ	(0x1 << 8)
++#define	USB2_UTMI0_SRST_REQ	(0x1 << 9)
++#define	USB2_HST_PHY_SRST_REQ	(0x1 << 11)
++#define	USB2_PHY_REQ		(0x1 << 13)
++#define	USB2_PHY_PORT0_TREQ	(0x1 << 14)
++#define	USB2_PHY_CLKSEL		(0x1 << 15)
++
++struct  hisi_inno_phy_port {
++	struct clk *utmi_clk;
++	struct reset_control *port_rst;
++	struct reset_control *utmi_rst;
++};
++
++struct hisi_inno_phy_priv {
++	void __iomem	*peri_ctrl; /* 0x12030000 */
++	void __iomem	*phy_reg; /* 0x120d0000 */
++	struct clk *ref_clk;
++	struct reset_control *test_rst;
++	struct reset_control *por_rst;
++	struct reg_sequence *reg_seq;
++	u32	reg_num;
++	struct  hisi_inno_phy_port *ports;
++	u8	port_num;
++};
++static struct task_struct *kusbotg_task;
++static int *usb2_switch_base;
++
++extern void usb2_low_power(int);
++extern int otg_usbdev_stat;
++int otg_usbhost_stat;
++EXPORT_SYMBOL(otg_usbhost_stat);
++static void __iomem	*peri_crg; /* 0x12010000 */
++static void __iomem	*sys_ctrl;
++#define SC_SYS_ID	0xEE0
++
++void hisi_switch_func(int otg)
++{
++	int reg;
++
++	reg = readl(usb2_switch_base);
++	if (otg) {
++		reg |= 0x1;
++		writel(reg, usb2_switch_base);
++	} else {
++		reg &= ~(0x1);
++		writel(reg, usb2_switch_base);
++	}
++}
++EXPORT_SYMBOL(hisi_switch_func);
++
++void usb2_low_power(int portsc)
++{
++#ifdef CONFIG_HIUSB_DEVICE2_0
++	return;
++#else
++	int reg;
++
++	if (portsc & 0x1) {
++		reg = readl(peri_crg + US2_CRG_BASE);
++		reg |= USB2_PHY_CKEN;
++		writel(reg, peri_crg + US2_CRG_BASE);
++		udelay(100);
++		reg = readl(peri_crg + US2_CRG_BASE);
++		reg &= ~USB2_PHY_REQ;
++		writel(reg, peri_crg + US2_CRG_BASE);
++		mdelay(1);
++		reg = readl(peri_crg + US2_CRG_BASE);
++		reg &= ~USB2_PHY_PORT0_TREQ;
++		writel(reg, peri_crg + US2_CRG_BASE);
++		udelay(10);
++		reg = readl(peri_crg + US2_CRG_BASE);
++		reg &= ~USB2_OHCI48M_CKEN;
++		reg &= ~USB2_OHCI12M_CKEN;
++		reg &= ~USB2_UTMI0_CKEN;
++		writel(reg, peri_crg + US2_CRG_BASE);
++		udelay(10);
++		reg = readl(peri_crg + US2_CRG_BASE);
++		reg &= ~USB2_PHY_CLKSEL;
++		writel(reg, peri_crg + US2_CRG_BASE);
++		udelay(10);
++		reg = readl(peri_crg + US2_CRG_BASE);
++		reg |= USB2_OHCI48M_CKEN;
++		reg |= USB2_OHCI12M_CKEN;
++		reg |= USB2_HST_PHY_CKEN;
++		reg |= USB2_UTMI0_CKEN;
++		writel(reg, peri_crg + US2_CRG_BASE);
++	} else {
++		reg = readl(peri_crg + US2_CRG_BASE);
++		reg &= ~USB2_OHCI48M_CKEN;
++		reg &= ~USB2_OHCI12M_CKEN;
++		reg &= ~USB2_HST_PHY_CKEN;
++		reg &= ~USB2_UTMI0_CKEN;
++		writel(reg, peri_crg + US2_CRG_BASE);
++		reg = readl(peri_crg + US2_CRG_BASE);
++		reg |= USB2_PHY_CLKSEL;
++		writel(reg, peri_crg + US2_CRG_BASE);
++		reg = readl(peri_crg + US2_CRG_BASE);
++		reg |= USB2_OHCI48M_CKEN;
++		reg |= USB2_OHCI12M_CKEN;
++		reg |= USB2_UTMI0_CKEN;
++		writel(reg, peri_crg + US2_CRG_BASE);
++		reg = readl(peri_crg + US2_CRG_BASE);
++		reg |= USB2_PHY_PORT0_TREQ;
++		reg |= USB2_PHY_REQ;
++		reg &= ~USB2_PHY_CKEN;
++		writel(reg, peri_crg + US2_CRG_BASE);
++	}
++#endif
++}
++
++static int hisi_inno_phy_setup(struct hisi_inno_phy_priv *priv)
++{
++	int reg;
++	/* config eye */
++	reg = readl(priv->peri_ctrl + USB2_PHY_SET);
++	reg |= USB_PHY_REG_ACCESS;
++	writel(reg, priv->peri_ctrl + USB2_PHY_SET);
++	writel(0x4, priv->phy_reg + PHY_CLK);
++	mdelay(2);
++
++	reg = readl(sys_ctrl + SC_SYS_ID);
++	if ((reg >> 24) == 0x4)	/* hi3516ev100 */
++		writel(0x1c, priv->phy_reg);
++	else
++		writel(0x18, priv->phy_reg);
++	udelay(20);
++	writel(0xc4, priv->phy_reg + 0x20);
++	udelay(20);
++	writel(0xc1, priv->phy_reg + 0x44);
++	udelay(20);
++	writel(0x1b, priv->phy_reg + 0x28);
++	udelay(20);
++
++	return 0;
++}
++
++static int hisi_inno_port_init(struct hisi_inno_phy_port *port)
++{
++	int ret = 0;
++
++	reset_control_deassert(port->port_rst);
++	mdelay(2);
++
++	ret = clk_prepare_enable(port->utmi_clk);
++	if (ret)
++		return ret;
++	udelay(200);
++
++	reset_control_deassert(port->utmi_rst);
++	udelay(200);
++
++	return 0;
++}
++
++static int hisi_inno_phy_init(struct phy *phy)
++{
++	struct hisi_inno_phy_priv *priv = phy_get_drvdata(phy);
++	int ret, port;
++
++	ret = clk_prepare_enable(priv->ref_clk);
++	if (ret)
++		return ret;
++	udelay(100);
++
++	if (priv->test_rst) {
++		reset_control_deassert(priv->test_rst);
++		udelay(100);
++	}
++
++	reset_control_deassert(priv->por_rst);
++	udelay(300);
++
++	/* config phy clk and phy eye diagram */
++	ret = hisi_inno_phy_setup(priv);
++	if (ret)
++		goto err_disable_ref_clk;
++
++	for (port = 0; port < priv->port_num; port++) {
++		ret = hisi_inno_port_init(&priv->ports[port]);
++		if (ret)
++			goto err_disable_clks;
++	}
++
++	return 0;
++
++err_disable_clks:
++	while (--port >= 0)
++		clk_disable_unprepare(priv->ports[port].utmi_clk);
++err_disable_ref_clk:
++	clk_disable_unprepare(priv->ref_clk);
++
++	return ret;
++}
++
++static void hisi_inno_phy_disable(struct phy *phy)
++{
++	struct hisi_inno_phy_priv *priv = phy_get_drvdata(phy);
++	int i;
++
++	for (i = 0; i < priv->port_num; i++)
++		clk_disable_unprepare(priv->ports[i].utmi_clk);
++
++	clk_disable_unprepare(priv->ref_clk);
++}
++
++static int hisi_inno_phy_of_get_ports(struct device *dev,
++					struct  hisi_inno_phy_priv *priv)
++{
++	struct device_node *node = dev->of_node, *child;
++	int port = 0, ret = 0;
++
++	priv->port_num = of_get_child_count(node);
++	if (priv->port_num > MAX_PORTS) {
++		dev_err(dev, "too many ports : %d (max = %d)\n",
++				priv->port_num, MAX_PORTS);
++		return -EINVAL;
++	}
++
++	priv->ports = devm_kcalloc(dev, priv->port_num,
++				sizeof(struct hisi_inno_phy_port), GFP_KERNEL);
++	if (!priv->ports)
++		return -ENOMEM;
++
++	for_each_child_of_node(node, child) {
++		struct hisi_inno_phy_port *phy_port = &priv->ports[port];
++
++		phy_port->utmi_clk = of_clk_get(child, 0);
++		if (IS_ERR(phy_port->utmi_clk)) {
++			ret = PTR_ERR(phy_port->utmi_clk);
++			goto fail;
++		}
++
++		phy_port->port_rst = of_reset_control_get(child, "port_rst");
++		if (IS_ERR(phy_port->port_rst)) {
++			ret = PTR_ERR(phy_port->port_rst);
++			clk_put(phy_port->utmi_clk);
++			goto fail;
++		}
++
++		phy_port->utmi_rst = of_reset_control_get(child, "utmi_rst");
++		if (IS_ERR(phy_port->utmi_rst)) {
++			ret = PTR_ERR(phy_port->utmi_rst);
++			reset_control_put(phy_port->port_rst);
++			clk_put(phy_port->utmi_clk);
++			goto fail;
++		}
++		port++;
++	}
++
++	return ret;
++
++fail:
++	while (--port >= 0) {
++		struct hisi_inno_phy_port *phy_port = &priv->ports[port];
++
++		reset_control_put(phy_port->utmi_rst);
++		reset_control_put(phy_port->port_rst);
++		clk_put(phy_port->utmi_clk);
++	}
++	of_node_put(child);
++
++	return ret;
++}
++
++/* hiotg run */
++static void device_to_host(struct hisi_inno_phy_priv *priv)
++{
++	int reg;
++
++	reg = readl_relaxed(priv->peri_ctrl + USB2_OTG_BASE);
++	reg |= USB2_PHY_DPPULL_DOWN;
++	reg &= ~DWC_OTG_EN;
++	writel_relaxed(reg, priv->peri_ctrl + USB2_OTG_BASE);
++
++}
++
++static void host_to_device(struct hisi_inno_phy_priv *priv)
++{
++
++	int reg;
++
++	reg = readl_relaxed(priv->peri_ctrl + USB2_OTG_BASE);
++	reg &= ~(USB2_PHY_DPPULL_DOWN);
++	reg |= DWC_OTG_EN;
++	writel_relaxed(reg, priv->peri_ctrl + USB2_OTG_BASE);
++
++}
++
++int  otg_run(struct hisi_inno_phy_priv *priv)
++{
++	int reg;
++
++	reg = readl(priv->peri_ctrl + USB2_OTG_BASE);
++
++	/* device -->host */
++	if ((reg & DWC_OTG_EN) == DWC_OTG_EN) {
++
++		if (otg_usbhost_stat == 1)
++			return 0;
++		device_to_host(priv);
++
++	} else { /* host -->device */
++		if (otg_usbdev_stat == 1)
++			return 0;
++
++		host_to_device(priv);
++	}
++
++
++	return 0;
++
++}
++
++static int usbotg_thread(void *arg)
++{
++#ifdef CONFIG_USB_AUTO_SWITCH
++	struct hisi_inno_phy_priv *priv = arg;
++	int reg;
++#endif
++
++	writel(0x0, usb2_switch_base);
++#ifdef CONFIG_USB_AUTO_SWITCH
++	do {
++		reg = readl(usb2_switch_base);
++		if (!(reg & (0x1 << 1)))
++			otg_run(priv);
++
++		msleep(1000);
++
++	} while (1);
++#endif
++
++	return 0;
++}
++
++
++static int hisi_inno_phy_probe(struct platform_device *pdev)
++{
++	struct device *dev = &pdev->dev;
++	struct phy *phy;
++	struct hisi_inno_phy_priv *priv;
++	struct device_node *node = dev->of_node;
++	int ret = 0;
++
++	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
++	if (!priv)
++		return -ENOMEM;
++
++	priv->peri_ctrl = of_iomap(node, 0); /* 0x12030000 */
++	priv->phy_reg = of_iomap(node, 1); /* 0x120d0000 */
++
++#ifdef CONFIG_HIUSB_DEVICE2_0
++	peri_crg = NULL;
++#else
++	peri_crg = of_iomap(node, 2); /* 0x12010000 */
++#endif
++	sys_ctrl = of_iomap(node, 3);
++
++	priv->ref_clk = devm_clk_get(dev, NULL);
++	if (IS_ERR(priv->ref_clk))
++		return PTR_ERR(priv->ref_clk);
++
++	priv->por_rst = devm_reset_control_get(dev, "por_rst");
++	if (IS_ERR(priv->por_rst))
++		return PTR_ERR(priv->por_rst);
++
++	priv->test_rst = devm_reset_control_get(dev, "test_rst");
++	if (IS_ERR(priv->test_rst))
++		priv->test_rst = NULL;
++
++	ret = hisi_inno_phy_of_get_ports(dev, priv);
++	if (ret)
++		return ret;
++
++	phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
++	if (!phy)
++		return -ENOMEM;
++
++	platform_set_drvdata(pdev, phy);
++	phy_set_drvdata(phy, priv);
++	ret = hisi_inno_phy_init(phy);
++
++	usb2_switch_base = (int *)USB2_SWITCH_BASE;
++	/* run hiotg */
++	kusbotg_task = kthread_run(usbotg_thread, priv, "kusbotg");
++	if (IS_ERR(kusbotg_task)) {
++		dev_err(dev, "can't start kusbotg\n");
++
++		return ret;
++	}
++
++	return ret;
++}
++
++#ifdef CONFIG_PM_SLEEP
++static int hisi_inno_phy_suspend(struct device *dev)
++{
++	struct phy *phy = dev_get_drvdata(dev);
++
++	hisi_inno_phy_disable(phy);
++
++	return 0;
++}
++
++static int hisi_inno_phy_resume(struct device *dev)
++{
++	struct phy *phy = dev_get_drvdata(dev);
++	int ret = 0;
++
++	ret = hisi_inno_phy_init(phy);
++	if (ret)
++		return ret;
++
++	return 0;
++}
++#endif /* CONFIG_PM_SLEEP */
++
++static const struct dev_pm_ops hisi_inno_phy_pm_ops = {
++	SET_SYSTEM_SLEEP_PM_OPS(hisi_inno_phy_suspend, hisi_inno_phy_resume)
++};
++
++static const struct of_device_id hisi_inno_phy_of_match[] = {
++	{.compatible = "hisilicon,inno_usb2_phy",},
++	{ },
++};
++MODULE_DEVICE_TABLE(of, hisi_inno_phy_of_match);
++
++static struct platform_driver hisi_inno_phy_driver = {
++	.probe	= hisi_inno_phy_probe,
++	.driver = {
++		.name	= "hisi-inno-phy",
++		.of_match_table	= hisi_inno_phy_of_match,
++		.pm    = &hisi_inno_phy_pm_ops,
++	}
++};
++module_platform_driver(hisi_inno_phy_driver);
++
++MODULE_AUTHOR("Pengcheng Li <lpc.li@hisilicon.com>");
++MODULE_DESCRIPTION("HISILICON USB PHY driver");
++MODULE_ALIAS("platform:hisi-usb-phy");
++MODULE_LICENSE("GPL v2");
+diff --git a/drivers/phy/phy-hisi-nano-phy-sata.c b/drivers/phy/phy-hisi-nano-phy-sata.c
+new file mode 100644
+index 0000000..811cdbc
+--- /dev/null
++++ b/drivers/phy/phy-hisi-nano-phy-sata.c
+@@ -0,0 +1,182 @@
++/*
++ * Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include <linux/delay.h>
++#include <linux/io.h>
++#include <linux/mfd/syscon.h>
++#include <linux/module.h>
++#include <linux/phy/phy.h>
++#include <linux/platform_device.h>
++#include <linux/regmap.h>
++#include <mach/io.h>
++#include <mach/platform.h>
++
++static int n_ports = CONFIG_HI_SATA_PORTS;
++static int phy_mode = CONFIG_HI_SATA_MODE;
++unsigned int sata_port_map;
++
++#ifdef MODULE
++module_param(phy_config, uint, 0600);
++MODULE_PARM_DESC(phy_config, "sata phy config (default:0x0e180000)");
++
++module_param(n_ports, uint, 0600);
++MODULE_PARM_DESC(n_ports, "sata port number (default:2)");
++module_param(mode_3g, uint, 0600);
++MODULE_PARM_DESC(phy_mode, "sata phy mode (0:1.5G;1:3G(default);2:6G)");
++#endif
++
++#ifdef CONFIG_ARCH_HI3536C
++#include "phy-hi3536c-sata.c"
++#endif
++
++#ifdef CONFIG_ARCH_HI3521D
++#include "phy-hi3521d-sata.c"
++#endif
++
++#ifdef CONFIG_ARCH_HI3531D
++#include "phy-hi3531d-sata.c"
++#endif
++
++static int hisi_sata_phy_init(struct phy *phy)
++{
++	void __iomem *mmio = phy_get_drvdata(phy);
++#ifdef CONFIG_ARCH_HI3531D
++	int port_num;
++
++	port_num = hi_sata_port_nr();
++	if ((port_num < 1) || (port_num > 4)) {
++		pr_err("sata ports number:%d WRONG!!!\n", n_ports);
++		return -EINVAL;
++	}
++
++	n_ports = port_num;
++#endif
++
++	hi_sata_poweron();
++	hi_sata_reset();
++	hi_sata_phy_reset();
++	hi_sata_phy_clk_sel();
++	hi_sata_clk_enable();
++	msleep(20);
++	hi_sata_phy_unreset();
++	msleep(20);
++	hi_sata_phy_reg_config();
++	msleep(20);
++	hi_sata_unreset();
++	msleep(20);
++	hisata_phy_init(mmio, phy_mode, n_ports);
++
++	return 0;
++}
++
++static int hisi_sata_phy_exit(struct phy *phy)
++{
++	hi_sata_phy_reset();
++	msleep(20);
++	hi_sata_reset();
++	msleep(20);
++	hi_sata_clk_reset();
++	msleep(20);
++	hi_sata_clk_disable();
++	hi_sata_poweroff();
++	msleep(20);
++
++	return 0;
++}
++
++static struct phy_ops hisi_sata_phy_ops = {
++	.init		= hisi_sata_phy_init,
++	.exit		= hisi_sata_phy_exit,
++	.owner		= THIS_MODULE,
++};
++
++static int hisi_sata_phy_probe(struct platform_device *pdev)
++{
++	struct phy_provider *phy_provider;
++	struct device *dev = &pdev->dev;
++	struct resource *res;
++	struct phy *phy;
++	void __iomem *mmio;
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	if (!res) {
++		dev_err(dev, "failed to get reg base\n");
++		return -ENOENT;
++	}
++
++	mmio = devm_ioremap(dev, res->start, resource_size(res));
++	if (!mmio)
++		return -ENOMEM;
++
++	phy = devm_phy_create(dev, NULL, &hisi_sata_phy_ops, NULL);
++	if (IS_ERR(phy)) {
++		dev_err(dev, "failed to create PHY\n");
++		return PTR_ERR(phy);
++	}
++
++	phy_set_drvdata(phy, mmio);
++
++	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
++	if (IS_ERR(phy_provider))
++		return PTR_ERR(phy_provider);
++
++	return 0;
++}
++
++static int hisi_sata_phy_suspend(struct platform_device *pdev,
++		pm_message_t state)
++{
++	struct device *dev = &pdev->dev;
++	struct phy *phy = to_phy(dev);
++
++	hisi_sata_phy_exit(phy);
++
++	return 0;
++}
++
++static int hisi_sata_phy_resume(struct platform_device *pdev)
++{
++	struct device *dev = &pdev->dev;
++	struct phy *phy = to_phy(dev);
++
++	hisi_sata_phy_init(phy);
++
++	return 0;
++}
++
++static const struct of_device_id hisi_sata_phy_of_match[] = {
++	{.compatible = "hisilicon,hisi-sata-nano-phy",},
++	{ },
++};
++MODULE_DEVICE_TABLE(of, hisi_sata_phy_of_match);
++
++static struct platform_driver hisi_sata_phy_driver = {
++	.probe	= hisi_sata_phy_probe,
++	.suspend = hisi_sata_phy_suspend,
++	.resume  = hisi_sata_phy_resume,
++	.driver = {
++		.name	= "hisi-sata-nano-phy",
++		.of_match_table	= hisi_sata_phy_of_match,
++	}
++};
++module_platform_driver(hisi_sata_phy_driver);
++
++MODULE_AUTHOR("HiSilicon BVT");
++MODULE_DESCRIPTION("HISILICON SATA NANO PHY driver");
++MODULE_ALIAS("platform:hisi-sata-nano-phy");
++MODULE_LICENSE("GPL v2");
+diff --git a/drivers/phy/phy-hisi-usb.c b/drivers/phy/phy-hisi-usb.c
+new file mode 100644
+index 0000000..7890c80
+--- /dev/null
++++ b/drivers/phy/phy-hisi-usb.c
+@@ -0,0 +1,550 @@
++/*
++ * Copyright (c) 2015 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <linux/delay.h>
++#include <linux/io.h>
++#include <linux/module.h>
++#include <linux/phy/phy.h>
++#include <linux/platform_device.h>
++#include <linux/of_address.h>
++#include <mach/io.h>
++#include <linux/kthread.h>
++#include <linux/export.h>
++
++#if defined(CONFIG_ARCH_HI3519) || defined(CONFIG_ARCH_HI3519V101) || defined(CONFIG_ARCH_HI3516AV200)
++#ifdef readl
++#undef readl
++#undef readl_relaxed
++#undef writel
++#undef writel_relaxed
++#define readl		hi_readl
++#define readl_relaxed	hi_readl_relaxed
++#define writel		hi_writel
++#define writel_relaxed	hi_writel_relaxed
++#endif /* readl */
++#endif /* defined(CONFIG_ARCH_HI3519) || defined(CONFIG_HI3519V101) || defined(CONFIG_ARCH_HI3516AV200)*/
++
++#define USB2_SWITCH_BASE		ioremap_nocache(0x12020150, 0x4)
++#define USB2_OTG_BASE		0x78
++#define DWC_OTG_EN			(1 << 31)
++#define USB2_PHY_DPPULL_DOWN		(0x3 << 26)
++
++#define USB2_PHY0_RST		0xb4
++
++#if (defined CONFIG_ARCH_HI3519 || defined CONFIG_ARCH_HI3519V101)
++#define HI3519_USB2_PHY_REQ		BIT(1)
++#define HI3519_USB2_PHY_PORT0_TREQ	BIT(2)
++#define HI3519_USB2_CTRL_HUB_REQ	BIT(4)
++#define HI3519_USB_CKEN			BIT(7)
++#endif
++
++#if defined(CONFIG_ARCH_HI3559) || defined(CONFIG_ARCH_HI3556)
++#define HI3559_USB2_PHY_REQ		BIT(1)
++#define HI3559_USB2_PHY_PORT0_TREQ	BIT(2)
++#define HI3559_USB2_CTRL_HUB_REQ	BIT(4)
++#define HI3559_USB_CKEN			BIT(7)
++#endif
++
++#ifdef CONFIG_ARCH_HI3516AV200
++#define HI3516AV200_USB2_PHY_REQ	BIT(1)
++#define HI3516AV200_USB2_PHY_PORT0_TREQ	BIT(2)
++#define HI3516AV200_USB2_CTRL_HUB_REQ 	BIT(4)
++#define HI3516AV200_USB_CKEN		BIT(7)
++#endif
++
++#define USB2_PHY0_CTLL		0x80
++
++/* HI3536C */
++#define USB2_CTRL		0x130
++#define USB2_BUS_CKEN		(1 << 0)
++#define USB2_OHCI48M_CKEN	(1 << 1)
++#define USB2_OHCI12M_CKEN	(1 << 2)
++#define USB2_HST_PHY_CKEN	(1 << 4)
++#define USB2_UTMI0_CKEN		(1 << 5)
++#define USB2_UTMI1_CKEN		(1 << 6)
++#define USB2_BUS_SRST_REQ	(1 << 12)
++#define USB2_UTMI0_SRST_REQ	(1 << 13)
++#define USB2_UTMI1_SRST_REQ	(1 << 14)
++#define USB2_HST_PHY_SYST_REQ	(1 << 16)
++
++#define REG_USB2_PHY0		0x134
++#define USB_PHY0_REF_CKEN	(1 << 0)
++#define USB_PHY0_SRST_REQ	(1 << 8)
++#define USB_PHY0_SRST_TREQ	(1 << 9)
++#define USB_PHY1_SRST_TREQ	(1 << 10)
++#define USB_PHY0_TEST_SRST_REQ	(1 << 11)
++#define USB_PHY0_REFCLK_SEL	(1 << 16)
++#if (defined(CONFIG_ARCH_HI3536C))
++#define USB1_CTRL0		0x50
++#endif
++#define WORDINTERFACE		(1 << 0)
++#define SS_BURST4_EN		(1 << 7)
++#define SS_BURST8_EN		(1 << 8)
++#define SS_BURST16_EN		(1 << 9)
++
++#define USB2_PHY_TEST_REG_ACCESS	(1 << 20)
++
++#define USB2_CTRL1		0x94
++/* write(0x1 << 5) 0x6 to addr 0x4 */
++#define CONFIG_CLK	((0x1 << 21) | (0x6 << 8) | (0x4 << 0))
++/* END HI3536C */
++
++#if (!defined(CONFIG_ARCH_HI3536C))
++static struct task_struct *kusbotg_task;
++static int *usb2_switch_base;
++
++extern int otg_usbdev_stat;
++int otg_usbhost_stat;
++EXPORT_SYMBOL(otg_usbhost_stat);
++
++void hisi_switch_func(int otg)
++{
++	int reg;
++
++	reg = readl(usb2_switch_base);
++	if (otg) {
++		reg |= 0x1;
++		writel(reg, usb2_switch_base);
++	} else {
++		reg &= ~(0x1);
++		writel(reg, usb2_switch_base);
++	}
++}
++EXPORT_SYMBOL(hisi_switch_func);
++#endif
++struct hisi_priv {
++	void __iomem	*base;
++	void __iomem	*misc_ctrl; /* 0x12030000 */
++	void __iomem	*peri_ctrl; /* 0x12010000 */
++};
++
++#if (!defined(CONFIG_ARCH_HI3536C))
++static int hisi_usb_phy_config(struct phy *phy)
++{
++	struct hisi_priv *priv = phy_get_drvdata(phy);
++
++	writel_relaxed(0x80001c, priv->misc_ctrl + USB2_PHY0_CTLL);
++	writel_relaxed(0xa0001c, priv->misc_ctrl + USB2_PHY0_CTLL);
++	usleep_range(200, 250);
++
++#if defined(CONFIG_ARCH_HI3519V101) \
++        || defined(CONFIG_ARCH_HI3559) || defined(CONFIG_ARCH_HI3556) || defined(CONFIG_ARCH_HI3516AV200)
++	writel_relaxed(0x800acb, priv->misc_ctrl + USB2_PHY0_CTLL);
++	writel_relaxed(0xa00acb, priv->misc_ctrl + USB2_PHY0_CTLL);
++	usleep_range(200, 250);
++
++	writel_relaxed(0x801181, priv->misc_ctrl + USB2_PHY0_CTLL);
++	writel_relaxed(0xa01181, priv->misc_ctrl + USB2_PHY0_CTLL);
++	usleep_range(200, 250);
++
++	writel_relaxed(0x800592, priv->misc_ctrl + USB2_PHY0_CTLL);
++	writel_relaxed(0xa00592, priv->misc_ctrl + USB2_PHY0_CTLL);
++	usleep_range(200, 250);
++#endif
++
++	writel_relaxed(0x800904, priv->misc_ctrl + USB2_PHY0_CTLL);
++	writel_relaxed(0xa00904, priv->misc_ctrl + USB2_PHY0_CTLL);
++	usleep_range(200, 250);
++
++	writel_relaxed(0x80060f, priv->misc_ctrl + USB2_PHY0_CTLL);
++	writel_relaxed(0xa0060f, priv->misc_ctrl + USB2_PHY0_CTLL);
++	usleep_range(200, 250);
++
++#ifdef CONFIG_ARCH_HI3519
++	writel_relaxed(0x800a4b, priv->misc_ctrl + USB2_PHY0_CTLL);
++	writel_relaxed(0xa00a4b, priv->misc_ctrl + USB2_PHY0_CTLL);
++	usleep_range(200, 250);
++#endif
++
++	writel_relaxed(0x801141, priv->misc_ctrl + USB2_PHY0_CTLL);
++	writel_relaxed(0xa01141, priv->misc_ctrl + USB2_PHY0_CTLL);
++	msleep(20);
++
++	return 0;
++}
++#endif
++
++static int hisi_usb_phy_on(struct phy *phy)
++{
++	int reg;
++	struct hisi_priv *priv = phy_get_drvdata(phy);
++
++#if (defined(CONFIG_ARCH_HI3536C))
++	reg = readl(priv->peri_ctrl + USB2_CTRL);
++	reg |= (USB2_BUS_SRST_REQ
++		| USB2_UTMI0_SRST_REQ
++		| USB2_HST_PHY_SYST_REQ);
++	reg |= USB2_UTMI1_SRST_REQ;
++	writel(reg, priv->peri_ctrl + USB2_CTRL);
++	udelay(200);
++
++	reg = readl(priv->peri_ctrl + REG_USB2_PHY0);
++	reg |= (USB_PHY0_SRST_REQ
++		| USB_PHY0_SRST_TREQ);
++	reg |= USB_PHY1_SRST_TREQ;
++	writel(reg, priv->peri_ctrl + REG_USB2_PHY0);
++	udelay(200);
++	reg = readl(priv->misc_ctrl + USB1_CTRL0);
++	reg &= ~(WORDINTERFACE); /* 8bit */
++	reg &= ~(SS_BURST16_EN); /* 16 bit burst disable */
++	writel(reg, priv->misc_ctrl + USB1_CTRL0);
++	udelay(100);
++	/* for ssk usb storage ok */
++	msleep(20);
++
++	/* open ref clock */
++	reg = readl(priv->peri_ctrl + REG_USB2_PHY0);
++	reg |= (USB_PHY0_REF_CKEN);
++	writel(reg, priv->peri_ctrl + REG_USB2_PHY0);
++	udelay(100);
++
++	/* cancel power on reset */
++	reg = readl(priv->peri_ctrl + REG_USB2_PHY0);
++	reg &= ~(USB_PHY0_SRST_REQ);
++	reg &= ~(USB_PHY0_TEST_SRST_REQ);
++	writel(reg , priv->peri_ctrl + REG_USB2_PHY0);
++	udelay(300);
++
++	/* config type */
++	reg = readl(priv->misc_ctrl + 0x10);
++	reg |= USB2_PHY_TEST_REG_ACCESS;
++	writel(reg, priv->misc_ctrl + 0x10);
++	udelay(2);
++	/* config clock */
++	writel(0xc, priv->misc_ctrl + 0x8018);
++	mdelay(2);
++	/* cancel port reset */
++	reg = readl(priv->peri_ctrl + REG_USB2_PHY0);
++	reg &= ~(USB_PHY0_SRST_TREQ);
++	reg &= ~(USB_PHY1_SRST_TREQ);
++	writel(reg, priv->peri_ctrl + REG_USB2_PHY0);
++	udelay(300);
++
++	/* cancel control reset */
++	reg = readl(priv->peri_ctrl + USB2_CTRL);
++	reg &= ~(USB2_BUS_SRST_REQ
++		| USB2_UTMI0_SRST_REQ
++		| USB2_HST_PHY_SYST_REQ);
++	reg &= ~USB2_UTMI1_SRST_REQ;
++
++	reg |= (USB2_BUS_CKEN
++			| USB2_OHCI48M_CKEN
++			| USB2_OHCI12M_CKEN
++			| USB2_HST_PHY_CKEN
++			| USB2_UTMI0_CKEN);
++	reg |= USB2_UTMI1_CKEN;
++	writel(reg, priv->peri_ctrl + USB2_CTRL);
++	udelay(200);
++
++#else
++	reg = readl_relaxed(priv->peri_ctrl + USB2_PHY0_RST);
++#if (defined CONFIG_ARCH_HI3519 || defined CONFIG_ARCH_HI3519V101)
++	reg &= ~HI3519_USB2_PHY_REQ;
++	reg &= ~HI3519_USB2_PHY_PORT0_TREQ;
++	reg &= ~HI3519_USB2_CTRL_HUB_REQ;
++	reg |= HI3519_USB_CKEN;
++#endif
++
++#if defined(CONFIG_ARCH_HI3516AV200)
++	reg &= ~HI3516AV200_USB2_PHY_REQ;
++	reg &= ~HI3516AV200_USB2_PHY_PORT0_TREQ;
++	reg &= ~HI3516AV200_USB2_CTRL_HUB_REQ;
++	reg |= HI3516AV200_USB_CKEN;
++#endif
++
++#if defined(CONFIG_ARCH_HI3559) || defined(CONFIG_ARCH_HI3556)
++	reg &=  ~HI3559_USB2_PHY_REQ;
++	reg &=  ~HI3559_USB2_PHY_PORT0_TREQ;
++	reg &=  ~HI3559_USB2_CTRL_HUB_REQ;
++	reg |= HI3559_USB_CKEN;
++#endif
++	writel_relaxed(reg, priv->peri_ctrl + USB2_PHY0_RST);
++	mdelay(100);
++
++	writel_relaxed(0x800000, priv->misc_ctrl + USB2_PHY0_CTLL);
++	mdelay(100);
++	writel_relaxed(0xa0060c, priv->misc_ctrl + USB2_PHY0_CTLL);
++	mdelay(100);
++
++	hisi_usb_phy_config(phy);
++#endif
++	return 0;
++}
++
++#if (!defined(CONFIG_ARCH_HI3536C))
++/* hiotg run */
++static void device_to_host(struct hisi_priv *priv)
++{
++	int reg;
++
++	reg = readl_relaxed(priv->misc_ctrl + USB2_OTG_BASE);
++	reg |= USB2_PHY_DPPULL_DOWN;
++	reg &= ~DWC_OTG_EN;
++	writel_relaxed(reg, priv->misc_ctrl + USB2_OTG_BASE);
++}
++
++static void host_to_device(struct hisi_priv *priv)
++{
++	int reg;
++
++	reg = readl_relaxed(priv->misc_ctrl + USB2_OTG_BASE);
++	reg &= ~(USB2_PHY_DPPULL_DOWN);
++	reg |= DWC_OTG_EN;
++	writel_relaxed(reg, priv->misc_ctrl + USB2_OTG_BASE);
++}
++
++int  otg_run(struct hisi_priv *priv)
++{
++	int reg;
++
++	reg = readl(priv->misc_ctrl + USB2_OTG_BASE);
++
++	/* device -->host */
++	if ((reg & DWC_OTG_EN) == DWC_OTG_EN) {
++
++		if (otg_usbhost_stat == 1)
++			return 0;
++		device_to_host(priv);
++
++	} else { /* host -->device */
++		if (otg_usbdev_stat == 1)
++			return 0;
++
++		host_to_device(priv);
++	}
++
++
++	return 0;
++
++}
++
++static int usbotg_thread(void *arg)
++{
++#ifdef CONFIG_USB_AUTO_SWITCH
++	struct hisi_priv *priv = arg;
++	int reg;
++#endif
++
++
++	writel_relaxed(0x0, usb2_switch_base);
++#ifdef CONFIG_USB_AUTO_SWITCH
++	do {
++		reg = readl_relaxed(usb2_switch_base);
++		if (!(reg & (0x1 << 1)))
++			otg_run(priv);
++
++		msleep(1000);
++
++	} while (1);
++#endif
++
++	return 0;
++}
++#endif
++
++static int hisi_usb_phy_probe(struct platform_device *pdev)
++{
++	struct device *dev = &pdev->dev;
++	struct phy *phy;
++	struct hisi_priv *priv;
++	struct device_node *np = pdev->dev.of_node;
++
++	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
++	if (!priv)
++		return -ENOMEM;
++
++	priv->misc_ctrl = of_iomap(np, 0); /* 0x12030000 */
++	if (IS_ERR(priv->misc_ctrl))
++		priv->misc_ctrl = NULL;
++
++	priv->peri_ctrl = of_iomap(np, 1); /* 0x12010000 */
++	if (IS_ERR(priv->peri_ctrl))
++		priv->peri_ctrl = NULL;
++
++	phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
++	if (!phy)
++		return -ENOMEM;
++	platform_set_drvdata(pdev, phy);
++	phy_set_drvdata(phy, priv);
++	hisi_usb_phy_on(phy);
++
++#if (!defined(CONFIG_ARCH_HI3536C))
++	usb2_switch_base = (int *)USB2_SWITCH_BASE;
++	/* run hiotg */
++	kusbotg_task = kthread_run(usbotg_thread, priv, "kusbotg");
++	if (IS_ERR(kusbotg_task)) {
++		dev_err(dev, "can't start kusbotg\n");
++		return -1;
++	}
++#endif
++	return 0;
++}
++
++static int hisi_usb_phy_remove(struct platform_device *pdev)
++{
++	int reg;
++	struct phy *phy = platform_get_drvdata(pdev);
++	struct hisi_priv *priv = phy_get_drvdata(phy);
++
++#if (defined(CONFIG_ARCH_HI3536C))
++	reg = readl(priv->peri_ctrl + REG_USB2_PHY0);
++	reg |= (USB_PHY0_SRST_REQ
++		| USB_PHY0_SRST_TREQ);
++	reg |= USB_PHY1_SRST_TREQ;
++	writel(reg, priv->peri_ctrl + REG_USB2_PHY0);
++	udelay(100);
++
++	/* close clock */
++	reg = readl(priv->peri_ctrl + REG_USB2_PHY0);
++	reg &= ~(USB_PHY0_REFCLK_SEL
++		| USB_PHY0_REF_CKEN);
++	writel(reg, priv->peri_ctrl + REG_USB2_PHY0);
++	udelay(300);
++
++	/* close clock */
++	reg = readl(priv->peri_ctrl + USB2_CTRL);
++	reg &= ~(USB2_BUS_CKEN
++		| USB2_OHCI48M_CKEN
++		| USB2_OHCI12M_CKEN
++		| USB2_HST_PHY_CKEN
++		| USB2_UTMI0_CKEN);
++	reg &= ~USB2_UTMI1_CKEN;
++	writel(reg, priv->peri_ctrl + USB2_CTRL);
++	udelay(200);
++#else
++	reg = readl_relaxed(priv->peri_ctrl + USB2_PHY0_RST);
++#if (defined CONFIG_ARCH_HI3519 || defined CONFIG_ARCH_HI3519V101)
++	reg |= HI3519_USB2_PHY_REQ;
++	reg |= HI3519_USB2_PHY_PORT0_TREQ;
++	reg |= HI3519_USB2_CTRL_HUB_REQ;
++	reg &= ~HI3519_USB_CKEN;
++#endif
++
++#if defined(CONFIG_ARCH_HI3516AV200)
++	reg |= HI3516AV200_USB2_PHY_REQ;
++	reg |= HI3516AV200_USB2_PHY_PORT0_TREQ;
++	reg |= HI3516AV200_USB2_CTRL_HUB_REQ;
++	reg &= ~HI3516AV200_USB_CKEN;
++#endif
++
++#if defined(CONFIG_ARCH_HI3559) || defined(CONFIG_ARCH_HI3556)
++	reg |= HI3559_USB2_PHY_REQ;
++	reg |= HI3559_USB2_PHY_PORT0_TREQ;
++	reg |= HI3559_USB2_CTRL_HUB_REQ;
++	reg &= ~HI3559_USB_CKEN;
++#endif
++	writel_relaxed(reg, priv->peri_ctrl + USB2_PHY0_RST);
++	mdelay(100);
++#endif
++	return 0;
++}
++
++static const struct of_device_id hisi_usb_phy_of_match[] = {
++	{.compatible = "hisilicon,hisi-usb-phy",},
++	{ },
++};
++MODULE_DEVICE_TABLE(of, hisi_usb_phy_of_match);
++
++#ifdef CONFIG_PM_SLEEP
++
++static int hisi_usb_phy_suspend(struct device *dev)
++{
++	int reg;
++	struct phy *phy = dev_get_drvdata(dev);
++	struct hisi_priv *priv = phy_get_drvdata(phy);
++
++#if (defined(CONFIG_ARCH_HI3536C))
++	reg = readl(priv->peri_ctrl + REG_USB2_PHY0);
++	reg |= (USB_PHY0_SRST_REQ
++		| USB_PHY0_SRST_TREQ);
++	reg |= USB_PHY1_SRST_TREQ;
++	writel(reg, priv->peri_ctrl + REG_USB2_PHY0);
++	udelay(100);
++
++	/* close clock */
++	reg = readl(priv->peri_ctrl + REG_USB2_PHY0);
++	reg &= ~(USB_PHY0_REFCLK_SEL
++		| USB_PHY0_REF_CKEN);
++	writel(reg, priv->peri_ctrl + REG_USB2_PHY0);
++	udelay(300);
++
++	/* close clock */
++	reg = readl(priv->peri_ctrl + USB2_CTRL);
++	reg &= ~(USB2_BUS_CKEN
++		| USB2_OHCI48M_CKEN
++		| USB2_OHCI12M_CKEN
++		| USB2_HST_PHY_CKEN
++		| USB2_UTMI0_CKEN);
++	reg &= ~USB2_UTMI1_CKEN;
++	writel(reg, priv->peri_ctrl + USB2_CTRL);
++	udelay(200);
++#else
++	reg = readl_relaxed(priv->peri_ctrl + USB2_PHY0_RST);
++#if (defined CONFIG_ARCH_HI3519 || defined CONFIG_ARCH_HI3519V101)
++	reg |= HI3519_USB2_PHY_REQ;
++	reg |= HI3519_USB2_PHY_PORT0_TREQ;
++	reg |= HI3519_USB2_CTRL_HUB_REQ;
++	reg &= ~HI3519_USB_CKEN;
++#endif
++
++#if defined(CONFIG_ARCH_HI3516AV200)
++	reg |= HI3516AV200_USB2_PHY_REQ;
++	reg |= HI3516AV200_USB2_PHY_PORT0_TREQ;
++	reg |= HI3516AV200_USB2_CTRL_HUB_REQ;
++	reg &= ~HI3516AV200_USB_CKEN;
++#endif
++
++#if defined(CONFIG_ARCH_HI3559) || defined(CONFIG_ARCH_HI3556)
++	reg |= HI3559_USB2_PHY_REQ;
++	reg |= HI3559_USB2_PHY_PORT0_TREQ;
++	reg |= HI3559_USB2_CTRL_HUB_REQ;
++	reg &= ~HI3559_USB_CKEN;
++#endif
++	writel_relaxed(reg, priv->peri_ctrl + USB2_PHY0_RST);
++	mdelay(100);
++#endif
++	return 0;
++}
++
++static int hisi_usb_phy_resume(struct device *dev)
++{
++	struct phy *phy = dev_get_drvdata(dev);
++
++	hisi_usb_phy_on(phy);
++	return 0;
++}
++
++#endif /* CONFIG_PM_SLEEP */
++
++static SIMPLE_DEV_PM_OPS(hisi_usb2_pm_ops, hisi_usb_phy_suspend,
++		       hisi_usb_phy_resume);
++
++static struct platform_driver hisi_usb_phy_driver = {
++	.probe	= hisi_usb_phy_probe,
++	.remove = hisi_usb_phy_remove,
++	.driver = {
++		.name	= "hisi-usb-phy",
++		.pm	= &hisi_usb2_pm_ops,
++		.of_match_table	= hisi_usb_phy_of_match,
++	}
++};
++module_platform_driver(hisi_usb_phy_driver);
++
++MODULE_AUTHOR("Pengcheng Li <lpc.li@hisilicon.com>");
++MODULE_DESCRIPTION("HISILICON USB PHY driver");
++MODULE_ALIAS("platform:hisi-usb-phy");
++MODULE_LICENSE("GPL v2");
+diff --git a/drivers/phy/phy-hisi-usb3.c b/drivers/phy/phy-hisi-usb3.c
+new file mode 100644
+index 0000000..f8a6ff2
+--- /dev/null
++++ b/drivers/phy/phy-hisi-usb3.c
+@@ -0,0 +1,313 @@
++/*
++ * Copyright (c) 2015 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <linux/delay.h>
++#include <linux/io.h>
++#include <linux/module.h>
++#include <linux/phy/phy.h>
++#include <linux/platform_device.h>
++#include <linux/of_address.h>
++#include <mach/io.h>
++
++#if defined(CONFIG_ARCH_HI3519) || defined(CONFIG_ARCH_HI3519V101) || defined(CONFIG_ARCH_HI3516AV200)
++#ifdef readl
++#undef readl
++#undef readl_relaxed
++#undef writel
++#undef writel_relaxed
++#define readl		hi_readl
++#define readl_relaxed	hi_readl_relaxed
++#define writel		hi_writel
++#define writel_relaxed	hi_writel_relaxed
++#endif /* readl */
++#endif /* defined(CONFIG_ARCH_HI3519) || defined(CONFIG_ARCH_HI3519V101) || defined(CONFIG_ARCH_HI3516AV200)*/
++
++#define USB3_CTRL		0xb8
++#define USB3_UTMI_CLKSEL		BIT(13)
++#define USB3_UTMI_CLKEN			BIT(12)
++#define USB3_PIPE_CLKEN			BIT(11)
++#define USB3_SUSPEND_CLKEN		BIT(10)
++#define USB3_REF_CLKEN			BIT(9)
++#define USB3_BUS_CLKEN			BIT(8)
++#define USB3_VCC_SRST_REQ		BIT(0)
++
++#define USB3_COMBPHY		0xac
++#define HI3519_COMBPHY_SRST_REQ		BIT(0)
++
++#define GTXTHRCFG		0xc108
++#define GRXTHRCFG		0xc10c
++#define REG_GCTL		0xc110
++#define U2RSTECN		(0x1 << 16)
++
++#define REG_GUSB2PHYCFG0	0xC200
++#define BIT_UTMI_ULPI		(0x1 << 4)
++#define BIT_UTMI_8_16		(0x1 << 3)
++
++#define REG_GUSB3PIPECTL0	0xc2c0
++#define PCS_SSP_SOFT_RESET	(0x1 << 31)
++#define TX_MARGIN_MASK		(0x7 << 3)
++#define TX_MARGIN_VAL		(0x2 << 3)
++
++#define USB2_PHY0_CTLL		0x80
++
++#define USB3_PHY		0x88
++#define COMBO_PHY_TX_DEEMP_MASK		(0x7 << 12)
++#define COMBO_PHY_TX_DEEMP_VAL		(0x1 << 12)
++#ifdef CONFIG_USB3_DEVICE_GPIO_CTRL
++#define GPIO_MODE		__io_address(0x12040000)
++#define GPIO1_DIR		__io_address(0x12141400)
++#define GPIO1_IBE		__io_address(0x12141408)
++#define GPIO1_IC		__io_address(0x1214141c)
++#define GPIO1_IE		__io_address(0x12141410)
++#define GPIO1_0_DIR		(1<<0)
++#define GPIO1_0_IBE		(1<<0)
++#define GPIO1_0_IC		(1<<0)
++#define GPIO1_0_IE		(1<<0)
++#endif
++struct hisi_priv {
++	void __iomem	*base;
++	void __iomem	*dwc3_ctrl; /* 0x10180000 */
++	void __iomem	*peri_ctrl; /* 0x12010000 */
++#if (defined CONFIG_ARCH_HI3519V101 || defined CONFIG_ARCH_HI3559 || defined CONFIG_ARCH_HI3556 || defined CONFIG_ARCH_HI3516AV200)
++	void __iomem	*misc_ctrl; /* 0x12030000 */
++#endif
++};
++
++static void hisi_usb3_phy_eye(struct phy *phy)
++{
++	int reg;
++	struct hisi_priv *priv = phy_get_drvdata(phy);
++
++#if (defined CONFIG_ARCH_HI3519V101 || defined CONFIG_ARCH_HI3559 || defined CONFIG_ARCH_HI3556 || defined CONFIG_ARCH_HI3516AV200)
++	/* djustment LFPS AM */
++	reg = readl(priv->dwc3_ctrl + REG_GUSB3PIPECTL0);
++	reg &= ~TX_MARGIN_MASK;
++	reg |= TX_MARGIN_VAL;
++	writel(reg, priv->dwc3_ctrl + REG_GUSB3PIPECTL0);
++
++	/* de-emphasis -3.5dB */
++	reg = readl(priv->misc_ctrl + USB3_PHY);
++	reg &= ~COMBO_PHY_TX_DEEMP_MASK;
++	reg |= COMBO_PHY_TX_DEEMP_VAL;
++	writel(reg, priv->misc_ctrl + USB3_PHY);
++#endif
++}
++
++static int hisi_usb3_ctrl_phy_config(struct phy *phy)
++{
++	int reg;
++	struct hisi_priv *priv = phy_get_drvdata(phy);
++
++#ifdef CONFIG_USB3_DEVICE_GPIO_CTRL
++	/* GPIO mode */
++	hi_writel(0x0, GPIO_MODE);
++
++	reg = hi_readl(GPIO1_DIR);
++	reg &= ~GPIO1_0_DIR;
++	hi_writel(reg, GPIO1_DIR);
++	mdelay(20);
++	/* falling edge */
++	reg = hi_readl(GPIO1_IBE);
++	reg &= ~GPIO1_0_IBE;
++	hi_writel(reg, GPIO1_IBE);
++	mdelay(20);
++	/* clear */
++	reg = hi_readl(GPIO1_IC);
++	reg |= GPIO1_0_IC;
++	hi_writel(reg, GPIO1_IC);
++	mdelay(20);
++	/* unmask */
++	reg = hi_readl(GPIO1_IE);
++	reg |= GPIO1_0_IE;
++	hi_writel(reg, GPIO1_IE);
++	mdelay(20);
++#endif
++	reg = readl(priv->dwc3_ctrl + REG_GUSB3PIPECTL0);
++	reg |= PCS_SSP_SOFT_RESET;
++	writel(reg, priv->dwc3_ctrl + REG_GUSB3PIPECTL0);
++
++	/*step 3: USB2 PHY chose ulpi 8bit interface */
++	reg = readl(priv->dwc3_ctrl + REG_GUSB2PHYCFG0);
++	reg &= ~BIT_UTMI_ULPI;
++	reg &= ~(BIT_UTMI_8_16);
++	writel(reg, priv->dwc3_ctrl + REG_GUSB2PHYCFG0);
++	mdelay(20);
++
++	reg = readl(priv->dwc3_ctrl + REG_GCTL);
++	reg &= ~(0x3<<12);
++	reg |= (0x1<<12); /*[13:12] 01: Host; 10: Device; 11: OTG*/
++	reg &= ~U2RSTECN;
++	writel(reg, priv->dwc3_ctrl + REG_GCTL);
++	mdelay(20);
++
++	reg = readl(priv->dwc3_ctrl + REG_GUSB3PIPECTL0);
++	reg &= ~PCS_SSP_SOFT_RESET;
++	reg &= ~(1<<17);       /* disable suspend */
++	writel(reg, priv->dwc3_ctrl + REG_GUSB3PIPECTL0);
++	mdelay(100);
++
++	writel(0x23100000, priv->dwc3_ctrl + GTXTHRCFG);
++	writel(0x23180000, priv->dwc3_ctrl + GRXTHRCFG);
++	mdelay(20);
++
++	hisi_usb3_phy_eye(phy);
++
++	return 0;
++}
++
++static int hisi_usb3_phy_on(struct phy *phy)
++{
++	int reg;
++	struct hisi_priv *priv = phy_get_drvdata(phy);
++
++	reg = readl_relaxed(priv->peri_ctrl + USB3_CTRL);
++	reg |= USB3_UTMI_CLKSEL;
++	reg |= USB3_UTMI_CLKEN;
++	reg |= USB3_PIPE_CLKEN;
++	reg |= USB3_SUSPEND_CLKEN;
++	reg |= USB3_REF_CLKEN;
++	reg |= USB3_BUS_CLKEN;
++	reg &= ~USB3_VCC_SRST_REQ;
++	writel_relaxed(reg, priv->peri_ctrl + USB3_CTRL);
++	mdelay(10);
++
++	reg = readl_relaxed(priv->peri_ctrl + USB3_COMBPHY);
++	reg &=  ~HI3519_COMBPHY_SRST_REQ;
++	writel_relaxed(reg, priv->peri_ctrl + USB3_COMBPHY);
++	mdelay(10);
++
++	hisi_usb3_ctrl_phy_config(phy);
++
++	return 0;
++}
++
++static int hisi_usb3_phy_power_off(struct device *dev)
++{
++	int reg;
++	struct phy *phy = dev_get_drvdata(dev);
++	struct hisi_priv *priv = phy_get_drvdata(phy);
++
++	reg = readl_relaxed(priv->peri_ctrl + USB3_COMBPHY);
++	reg |=  HI3519_COMBPHY_SRST_REQ;
++	writel_relaxed(reg, priv->peri_ctrl + USB3_COMBPHY);
++	mdelay(100);
++
++	reg = readl_relaxed(priv->peri_ctrl + USB3_CTRL);
++	reg |= USB3_VCC_SRST_REQ;
++	writel_relaxed(reg, priv->peri_ctrl + USB3_CTRL);
++	mdelay(10);
++
++	return 0;
++}
++
++static int hisi_usb3_phy_power_on(struct device *dev)
++{
++	struct phy *phy = dev_get_drvdata(dev);
++
++	hisi_usb3_phy_on(phy);
++
++	return 0;
++}
++
++static int hisi_usb3_phy_probe(struct platform_device *pdev)
++{
++	struct device *dev = &pdev->dev;
++	struct phy *phy;
++	struct hisi_priv *priv;
++	struct device_node *np = pdev->dev.of_node;
++
++	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
++	if (!priv)
++		return -ENOMEM;
++
++	priv->dwc3_ctrl = of_iomap(np, 0);
++	if (IS_ERR(priv->dwc3_ctrl))
++		priv->dwc3_ctrl = NULL;
++
++	priv->peri_ctrl = of_iomap(np, 1);
++	if (IS_ERR(priv->peri_ctrl))
++		priv->peri_ctrl = NULL;
++
++#if (defined CONFIG_ARCH_HI3519V101 || defined CONFIG_ARCH_HI3559 || defined CONFIG_ARCH_HI3556 || defined CONFIG_ARCH_HI3516AV200)
++	priv->misc_ctrl = of_iomap(np, 2);
++	if (IS_ERR(priv->misc_ctrl))
++		priv->misc_ctrl = NULL;
++#endif
++
++	phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
++	if (!phy)
++		return -ENOMEM;
++
++	platform_set_drvdata(pdev, phy);
++	phy_set_drvdata(phy, priv);
++	hisi_usb3_phy_on(phy);
++
++	return 0;
++}
++
++static int hisi_usb3_phy_remove(struct platform_device *pdev)
++{
++	int reg;
++	struct phy *phy = platform_get_drvdata(pdev);
++	struct hisi_priv *priv = phy_get_drvdata(phy);
++
++	reg = readl_relaxed(priv->peri_ctrl + USB3_CTRL);
++	reg |= USB3_UTMI_CLKSEL;
++	reg &= ~USB3_UTMI_CLKEN;
++	reg &= ~USB3_PIPE_CLKEN;
++	reg &= ~USB3_SUSPEND_CLKEN;
++	reg &= ~USB3_REF_CLKEN;
++	reg &= ~USB3_BUS_CLKEN;
++	reg |= USB3_VCC_SRST_REQ;
++	writel_relaxed(reg, priv->peri_ctrl + USB3_CTRL);
++	mdelay(10);
++
++	return 0;
++}
++
++static const struct dev_pm_ops hisi_usb3_pmops = {
++	.suspend = hisi_usb3_phy_power_off,
++	.resume  = hisi_usb3_phy_power_on,
++#if defined(CONFIG_PM_HIBERNATE) || defined(CONFIG_HISI_SNAPSHOT_BOOT)
++	.freeze = hisi_usb3_phy_power_off,
++	.thaw = hisi_usb3_phy_power_on,
++	.poweroff = hisi_usb3_phy_power_off,
++	.restore = hisi_usb3_phy_power_on,
++#endif
++};
++
++static const struct of_device_id hisi_usb3_phy_of_match[] = {
++	{.compatible = "hisilicon,hisi-usb3-phy",},
++	{ },
++};
++MODULE_DEVICE_TABLE(of, hisi_usb3_phy_of_match);
++
++static struct platform_driver hisi_usb3_phy_driver = {
++	.probe	= hisi_usb3_phy_probe,
++	.remove = hisi_usb3_phy_remove,
++	.driver = {
++		.name	= "hisi-usb3-phy",
++		.of_match_table	= hisi_usb3_phy_of_match,
++		.pm    = &hisi_usb3_pmops,
++	}
++};
++module_platform_driver(hisi_usb3_phy_driver);
++
++MODULE_AUTHOR("Pengcheng Li <lpc.li@hisilicon.com>");
++MODULE_DESCRIPTION("HISILICON USB PHY driver");
++MODULE_ALIAS("platform:hisi-usb3-phy");
++MODULE_LICENSE("GPL v2");
+diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c
+index f94467c..7f21f75 100644
+--- a/drivers/platform/x86/acerhdf.c
++++ b/drivers/platform/x86/acerhdf.c
+@@ -330,7 +330,8 @@ static int acerhdf_bind(struct thermal_zone_device *thermal,
+ 		return 0;
+ 
+ 	if (thermal_zone_bind_cooling_device(thermal, 0, cdev,
+-			THERMAL_NO_LIMIT, THERMAL_NO_LIMIT)) {
++			THERMAL_NO_LIMIT, THERMAL_NO_LIMIT,
++			THERMAL_WEIGHT_DEFAULT)) {
+ 		pr_err("error binding cooling dev\n");
+ 		return -EINVAL;
+ 	}
+diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c
+index 62653f5..87a348c 100644
+--- a/drivers/power/power_supply_sysfs.c
++++ b/drivers/power/power_supply_sysfs.c
+@@ -106,7 +106,10 @@ static ssize_t power_supply_show_property(struct device *dev,
+ 	else if (off >= POWER_SUPPLY_PROP_MODEL_NAME)
+ 		return sprintf(buf, "%s\n", value.strval);
+ 
+-	return sprintf(buf, "%d\n", value.intval);
++	if (off == POWER_SUPPLY_PROP_CHARGE_COUNTER_EXT)
++		return sprintf(buf, "%lld\n", value.int64val);
++	else
++		return sprintf(buf, "%d\n", value.intval);
+ }
+ 
+ static ssize_t power_supply_store_property(struct device *dev,
+@@ -197,6 +200,12 @@ static struct device_attribute power_supply_attrs[] = {
+ 	POWER_SUPPLY_ATTR(scope),
+ 	POWER_SUPPLY_ATTR(charge_term_current),
+ 	POWER_SUPPLY_ATTR(calibrate),
++	/* Local extensions */
++	POWER_SUPPLY_ATTR(usb_hc),
++	POWER_SUPPLY_ATTR(usb_otg),
++	POWER_SUPPLY_ATTR(charge_enabled),
++	/* Local extensions of type int64_t */
++	POWER_SUPPLY_ATTR(charge_counter_ext),
+ 	/* Properties of type `const char *' */
+ 	POWER_SUPPLY_ATTR(model_name),
+ 	POWER_SUPPLY_ATTR(manufacturer),
+diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
+index ef2dd2e..c6e48b5 100644
+--- a/drivers/pwm/Kconfig
++++ b/drivers/pwm/Kconfig
+@@ -110,6 +110,15 @@ config PWM_FSL_FTM
+ 	  To compile this driver as a module, choose M here: the module
+ 	  will be called pwm-fsl-ftm.
+ 
++config PWM_HIBVT
++	tristate "HiSilicon BVT PWM support"
++	depends on ARCH_HISI || COMPILE_TEST
++	help
++	  Generic PWM framework driver for HiSilicon BVT SoCs.
++
++	  To compile this driver as a module, choose M here: the module
++	  will be called pwm-hibvt.
++
+ config PWM_IMX
+ 	tristate "i.MX PWM support"
+ 	depends on ARCH_MXC
+diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
+index c458606..e90fbbe 100644
+--- a/drivers/pwm/Makefile
++++ b/drivers/pwm/Makefile
+@@ -8,6 +8,7 @@ obj-$(CONFIG_PWM_BFIN)		+= pwm-bfin.o
+ obj-$(CONFIG_PWM_CLPS711X)	+= pwm-clps711x.o
+ obj-$(CONFIG_PWM_EP93XX)	+= pwm-ep93xx.o
+ obj-$(CONFIG_PWM_FSL_FTM)	+= pwm-fsl-ftm.o
++obj-$(CONFIG_PWM_HIBVT)		+= pwm-hibvt.o
+ obj-$(CONFIG_PWM_IMX)		+= pwm-imx.o
+ obj-$(CONFIG_PWM_JZ4740)	+= pwm-jz4740.o
+ obj-$(CONFIG_PWM_LP3943)	+= pwm-lp3943.o
+diff --git a/drivers/pwm/pwm-hibvt.c b/drivers/pwm/pwm-hibvt.c
+new file mode 100644
+index 0000000..89e9fe5
+--- /dev/null
++++ b/drivers/pwm/pwm-hibvt.c
+@@ -0,0 +1,246 @@
++/*
++ * PWM Controller Driver for HiSilicon BVT SoCs
++ *
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <linux/bitops.h>
++#include <linux/clk.h>
++#include <linux/delay.h>
++#include <linux/io.h>
++#include <linux/module.h>
++#include <linux/of_device.h>
++#include <linux/platform_device.h>
++#include <linux/pwm.h>
++#include <linux/reset.h>
++
++#define PWM_CFG0_ADDR(x)    (((x) * 0x20) + 0x0)
++#define PWM_CFG1_ADDR(x)    (((x) * 0x20) + 0x4)
++#define PWM_CFG2_ADDR(x)    (((x) * 0x20) + 0x8)
++#define PWM_CTRL_ADDR(x)    (((x) * 0x20) + 0xC)
++
++#define PWM_ENABLE_SHIFT    0
++#define PWM_ENABLE_MASK     BIT(0)
++
++#define PWM_POLARITY_SHIFT  1
++#define PWM_POLARITY_MASK   BIT(1)
++
++#define PWM_KEEP_SHIFT      2
++#define PWM_KEEP_MASK       BIT(2)
++
++#define PWM_PERIOD_MASK     GENMASK(31, 0)
++#define PWM_DUTY_MASK       GENMASK(31, 0)
++
++struct hibvt_pwm_chip {
++	struct pwm_chip	chip;
++	struct clk *clk;
++	void __iomem *base;
++	struct reset_control *rstc;
++};
++
++struct hibvt_pwm_soc {
++	u32 num_pwms;
++};
++
++static const struct hibvt_pwm_soc pwm_soc[2] = {
++	{ .num_pwms = 4 },
++	{ .num_pwms = 8 },
++};
++
++static inline struct hibvt_pwm_chip *to_hibvt_pwm_chip(struct pwm_chip *chip)
++{
++	return container_of(chip, struct hibvt_pwm_chip, chip);
++}
++
++static void hibvt_pwm_set_bits(void __iomem *base, u32 offset,
++					u32 mask, u32 data)
++{
++	void __iomem *address = base + offset;
++	u32 value;
++
++	value = readl(address);
++	value &= ~mask;
++	value |= (data & mask);
++	writel(value, address);
++}
++
++static int hibvt_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
++{
++	struct hibvt_pwm_chip *hi_pwm_chip = to_hibvt_pwm_chip(chip);
++
++	hibvt_pwm_set_bits(hi_pwm_chip->base, PWM_CTRL_ADDR(pwm->hwpwm),
++			PWM_ENABLE_MASK, 0x1);
++
++	return 0;
++}
++
++static void hibvt_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
++{
++	struct hibvt_pwm_chip *hi_pwm_chip = to_hibvt_pwm_chip(chip);
++
++	hibvt_pwm_set_bits(hi_pwm_chip->base, PWM_CTRL_ADDR(pwm->hwpwm),
++			PWM_ENABLE_MASK, 0x0);
++}
++
++static int hibvt_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
++					int duty_cycle_ns, int period_ns)
++{
++	struct hibvt_pwm_chip *hi_pwm_chip = to_hibvt_pwm_chip(chip);
++	u32 freq, period, duty;
++
++	freq = div_u64(clk_get_rate(hi_pwm_chip->clk), 1000000);
++
++	period = div_u64(freq * period_ns, 1000);
++	duty = div_u64(period * duty_cycle_ns, period_ns);
++
++	hibvt_pwm_set_bits(hi_pwm_chip->base, PWM_CFG0_ADDR(pwm->hwpwm),
++			PWM_PERIOD_MASK, period);
++
++	hibvt_pwm_set_bits(hi_pwm_chip->base, PWM_CFG1_ADDR(pwm->hwpwm),
++			PWM_DUTY_MASK, duty);
++
++	return 0;
++}
++
++static int hibvt_pwm_set_polarity(struct pwm_chip *chip,
++					struct pwm_device *pwm,
++					enum pwm_polarity polarity)
++{
++	struct hibvt_pwm_chip *hi_pwm_chip = to_hibvt_pwm_chip(chip);
++
++	if (polarity == PWM_POLARITY_INVERSED)
++		hibvt_pwm_set_bits(hi_pwm_chip->base, PWM_CTRL_ADDR(pwm->hwpwm),
++				PWM_POLARITY_MASK, (0x1 << PWM_POLARITY_SHIFT));
++	else
++		hibvt_pwm_set_bits(hi_pwm_chip->base, PWM_CTRL_ADDR(pwm->hwpwm),
++				PWM_POLARITY_MASK, (0x0 << PWM_POLARITY_SHIFT));
++
++	return 0;
++}
++
++static struct pwm_ops hibvt_pwm_ops = {
++	.enable = hibvt_pwm_enable,
++	.disable = hibvt_pwm_disable,
++	.config = hibvt_pwm_config,
++	.set_polarity = hibvt_pwm_set_polarity,
++
++	.owner = THIS_MODULE,
++};
++
++static const struct of_device_id hibvt_pwm_of_match[] = {
++	{ .compatible = "hisilicon,hi3516cv300-pwm", .data = &pwm_soc[0] },
++	{ .compatible = "hisilicon,hi3519v100-pwm", .data = &pwm_soc[1] },
++	{  }
++};
++MODULE_DEVICE_TABLE(of, hibvt_pwm_of_match);
++
++static int hibvt_pwm_probe(struct platform_device *pdev)
++{
++	const struct hibvt_pwm_soc *soc;
++	const struct of_device_id *of_id =
++			of_match_device(hibvt_pwm_of_match, &pdev->dev);
++	struct hibvt_pwm_chip *pwm_chip;
++	struct resource *res;
++	int ret;
++	int i;
++
++	if (!of_id)
++		return -ENODEV;
++
++	pwm_chip = devm_kzalloc(&pdev->dev, sizeof(*pwm_chip), GFP_KERNEL);
++	if (pwm_chip == NULL)
++		return -ENOMEM;
++
++	pwm_chip->clk = devm_clk_get(&pdev->dev, NULL);
++	if (IS_ERR(pwm_chip->clk)) {
++		dev_err(&pdev->dev, "getting clock failed with %ld\n",
++				PTR_ERR(pwm_chip->clk));
++		return PTR_ERR(pwm_chip->clk);
++	}
++
++	soc = of_id->data;
++
++	pwm_chip->chip.ops = &hibvt_pwm_ops;
++	pwm_chip->chip.dev = &pdev->dev;
++	pwm_chip->chip.base = -1;
++	pwm_chip->chip.npwm = soc->num_pwms;
++	pwm_chip->chip.of_xlate = of_pwm_xlate_with_flags;
++	pwm_chip->chip.of_pwm_n_cells = 3;
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	pwm_chip->base = devm_ioremap_resource(&pdev->dev, res);
++	if (IS_ERR(pwm_chip->base))
++		return PTR_ERR(pwm_chip->base);
++
++	ret = clk_prepare_enable(pwm_chip->clk);
++	if (ret < 0)
++		return ret;
++
++	pwm_chip->rstc = devm_reset_control_get(&pdev->dev, NULL);
++	if (IS_ERR(pwm_chip->rstc)) {
++		clk_disable_unprepare(pwm_chip->clk);
++		return PTR_ERR(pwm_chip->rstc);
++	}
++
++	reset_control_assert(pwm_chip->rstc);
++	msleep(30);
++	reset_control_deassert(pwm_chip->rstc);
++
++	ret = pwmchip_add(&pwm_chip->chip);
++	if (ret < 0) {
++		clk_disable_unprepare(pwm_chip->clk);
++		return ret;
++	}
++
++	for (i = 0; i < pwm_chip->chip.npwm; i++) {
++		hibvt_pwm_set_bits(pwm_chip->base, PWM_CTRL_ADDR(i),
++				PWM_KEEP_MASK, (0x1 << PWM_KEEP_SHIFT));
++	}
++
++	platform_set_drvdata(pdev, pwm_chip);
++
++	return 0;
++}
++
++static int hibvt_pwm_remove(struct platform_device *pdev)
++{
++	struct hibvt_pwm_chip *pwm_chip;
++
++	pwm_chip = platform_get_drvdata(pdev);
++
++	reset_control_assert(pwm_chip->rstc);
++	msleep(30);
++	reset_control_deassert(pwm_chip->rstc);
++
++	clk_disable_unprepare(pwm_chip->clk);
++
++	return pwmchip_remove(&pwm_chip->chip);
++}
++
++static struct platform_driver hibvt_pwm_driver = {
++	.driver = {
++		.name = "hibvt-pwm",
++		.owner = THIS_MODULE,
++		.of_match_table = hibvt_pwm_of_match,
++	},
++	.probe = hibvt_pwm_probe,
++	.remove	= hibvt_pwm_remove,
++};
++module_platform_driver(hibvt_pwm_driver);
++
++MODULE_AUTHOR("Jian Yuan");
++MODULE_DESCRIPTION("HiSilicon BVT SoCs PWM driver");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
+index bc3d80f..9749ec1 100644
+--- a/drivers/regulator/core.c
++++ b/drivers/regulator/core.c
+@@ -1715,6 +1715,8 @@ static void regulator_ena_gpio_free(struct regulator_dev *rdev)
+ 				gpiod_put(pin->gpiod);
+ 				list_del(&pin->list);
+ 				kfree(pin);
++				rdev->ena_pin = NULL;
++				return;
+ 			} else {
+ 				pin->request_count--;
+ 			}
+diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
+index 6dd12dd..7c88521 100644
+--- a/drivers/rtc/Kconfig
++++ b/drivers/rtc/Kconfig
+@@ -701,6 +701,14 @@ endif # SPI_MASTER
+ 
+ comment "Platform RTC drivers"
+ 
++config RTC_DRV_HIBVT
++	tristate "HiSilicon BVT RTC support"
++	help
++	  Generic RTC framework driver for HiSilicon BVT SoCs.
++
++	  To compile this driver as a module, choose M here: the module
++	  will be called rtc-hibvt.
++	  
+ # this 'CMOS' RTC driver is arch dependent because <asm-generic/rtc.h>
+ # requires <asm/mc146818rtc.h> defining CMOS_READ/CMOS_WRITE, and a
+ # global rtc_lock ... it's not yet just another platform_device.
+diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
+index b188323..632f526 100644
+--- a/drivers/rtc/Makefile
++++ b/drivers/rtc/Makefile
+@@ -149,3 +149,4 @@ obj-$(CONFIG_RTC_DRV_X1205)	+= rtc-x1205.o
+ obj-$(CONFIG_RTC_DRV_XGENE)	+= rtc-xgene.o
+ obj-$(CONFIG_RTC_DRV_SIRFSOC)	+= rtc-sirfsoc.o
+ obj-$(CONFIG_RTC_DRV_MOXART)	+= rtc-moxart.o
++obj-$(CONFIG_RTC_DRV_HIBVT)	+= rtc-hibvt.o
+diff --git a/drivers/rtc/rtc-hibvt.c b/drivers/rtc/rtc-hibvt.c
+new file mode 100644
+index 0000000..28d0bae
+--- /dev/null
++++ b/drivers/rtc/rtc-hibvt.c
+@@ -0,0 +1,581 @@
++/*
++ * RTC driver for Hisilicon BVT
++ * Copyright (C) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/bcd.h>
++#include <linux/bitops.h>
++#include <linux/log2.h>
++#include <linux/interrupt.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/rtc.h>
++#include <linux/version.h>
++#include <linux/io.h>
++#include <linux/delay.h>
++
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include <linux/platform_device.h>
++
++union u_spi_rw {
++	struct {
++		unsigned int spi_wdata		: 8; /* [7:0] */
++		unsigned int spi_rdata		: 8; /* [15:8] */
++		unsigned int spi_addr		: 7; /* [22:16] */
++		unsigned int spi_rw		    : 1; /* [23] */
++		unsigned int spi_start		: 1; /* [24] */
++		unsigned int reserved		: 6; /* [30:25] */
++		unsigned int spi_busy		: 1; /* [31] */
++	} bits;
++	unsigned int u32;
++};
++
++#define SPI_CLK_DIV			(0x000)
++#define SPI_RW				(0x004)
++
++#define SPI_WRITE		(0)
++#define SPI_READ		(1)
++
++/* RTC REG */
++#define RTC_10MS_COUN	0x00
++#define RTC_S_COUNT		0x01
++#define RTC_M_COUNT		0x02
++#define RTC_H_COUNT		0x03
++#define RTC_D_COUNT_L	0x04
++#define RTC_D_COUNT_H	0x05
++
++#define RTC_MR_10MS		0x06
++#define RTC_MR_S		0x07
++#define RTC_MR_M		0x08
++#define RTC_MR_H		0x09
++#define RTC_MR_D_L		0x0A
++#define RTC_MR_D_H		0x0B
++
++#define RTC_LR_10MS		0x0C
++#define RTC_LR_S		0x0D
++#define RTC_LR_M		0x0E
++#define RTC_LR_H		0x0F
++#define RTC_LR_D_L		0x10
++#define RTC_LR_D_H		0x11
++
++#define RTC_LORD		0x12
++
++#define RTC_IMSC		0x13
++#define RTC_INT_CLR		0x14
++#define RTC_INT			0x15
++#define RTC_INT_RAW		0x16
++
++#define RTC_CLK			0x17
++#define RTC_POR_N		0x18
++#define RTC_SAR_CTRL	0x1A
++#define RTC_CLK_CFG	    0x1B
++
++#define RTC_FREQ_H		0x51
++#define RTC_FREQ_L		0x52
++
++#define FREQ_H_DEFAULT  0x8
++#define FREQ_L_DEFAULT  0x1B
++
++#define LV_CTL_DEFAULT  0x01
++#define CLK_DIV_DEFAULT 0x4
++#define INT_RST_DEFAULT 0x0
++#define INT_MSK_DEFAULT 0x4
++
++#define AIE_INT_MASK       BIT(0)
++#define LV_INT_MASK        BIT(1)
++#define REG_LOAD_STAT      BIT(0)
++#define REG_LOCK_STAT      BIT(1)
++#define REG_LOCK_BYPASS    BIT(2)
++
++#define RETRY_CNT 500
++
++#define DATE_TO_SEC(d, h, m, s)     (s + m*60 + h*60*60 + d*24*60*60)
++#define SEC_TO_DAY(s)            (s/(60*60*24))
++
++struct hibvt_rtc {
++	struct rtc_device	*rtc_dev;
++	void __iomem		*regs;
++	int                  rtc_irq;
++};
++
++static int hibvt_spi_write(void *spi_reg, unsigned char reg,
++	unsigned char val)
++{
++	union u_spi_rw w_data, r_data;
++	int cnt = RETRY_CNT;
++
++	r_data.u32 = 0;
++	w_data.u32 = 0;
++
++	w_data.bits.spi_wdata = val;
++	w_data.bits.spi_addr = reg;
++	w_data.bits.spi_rw = SPI_WRITE;
++	w_data.bits.spi_start = 0x1;
++
++	writel(w_data.u32, (spi_reg+SPI_RW));
++
++	do
++		r_data.u32 = readl(spi_reg+SPI_RW);
++	while (r_data.bits.spi_busy && (--cnt));
++
++	if (r_data.bits.spi_busy)
++		return -EIO;
++
++	return 0;
++}
++
++
++static int hibvt_spi_rtc_write(void *spi_reg, unsigned char reg,
++	unsigned char val)
++{
++	return hibvt_spi_write(spi_reg, reg, val);
++}
++
++static int hibvt_spi_read(void *spi_reg, unsigned char reg,
++	unsigned char *val)
++{
++	union u_spi_rw w_data, r_data;
++	int cnt = RETRY_CNT;
++
++	r_data.u32 = 0;
++	w_data.u32 = 0;
++	w_data.bits.spi_addr = reg;
++	w_data.bits.spi_rw = SPI_READ;
++	w_data.bits.spi_start = 0x1;
++
++	writel(w_data.u32, (spi_reg+SPI_RW));
++
++	do
++		r_data.u32 = readl(spi_reg+SPI_RW);
++	while (r_data.bits.spi_busy && (--cnt));
++
++	if (r_data.bits.spi_busy)
++		return -EIO;
++
++	*val = r_data.bits.spi_rdata;
++
++	return 0;
++}
++
++static int hibvt_spi_rtc_read(void *spi_reg, unsigned char reg,
++	unsigned char *val)
++{
++	return hibvt_spi_read(spi_reg, reg, val);
++}
++
++static int hibvt_rtc_read_time(struct device *dev, struct rtc_time *time)
++{
++	struct hibvt_rtc *rtc = dev_get_drvdata(dev);
++	unsigned char dayl, dayh;
++	unsigned char second, minute, hour;
++	unsigned long seconds = 0;
++	unsigned int day;
++	unsigned char raw_value;
++	int cnt = RETRY_CNT;
++	int ret = 0;
++
++	ret = hibvt_spi_rtc_read(rtc->regs, RTC_INT_RAW, &raw_value);
++	if (ret) {
++		dev_err(dev, "IO err.\n");
++		return ret;
++	}
++
++	if (raw_value & LV_INT_MASK) {
++		dev_err(dev,
++			"low voltage detected, date/time is not reliable.\n");
++		hibvt_spi_write(rtc->regs, RTC_INT_CLR, 1);
++		return -EINVAL;
++	}
++
++	ret |= hibvt_spi_rtc_read(rtc->regs, RTC_LORD, &raw_value);
++	if (raw_value & REG_LOCK_BYPASS)
++		ret |= hibvt_spi_rtc_write(rtc->regs, RTC_LORD,
++		(~(REG_LOCK_BYPASS)) & raw_value);
++
++	ret |= hibvt_spi_rtc_read(rtc->regs, RTC_LORD, &raw_value);
++	/* lock the time */
++	ret |= hibvt_spi_rtc_write(rtc->regs, RTC_LORD,
++	(REG_LOCK_STAT) | raw_value);
++	/* wait rtc load flag */
++	do {
++		ret |= hibvt_spi_rtc_read(rtc->regs, RTC_LORD, &raw_value);
++		msleep(20);
++	} while ((ret || (raw_value & REG_LOCK_STAT)) && (--cnt));
++
++	if (!ret && (raw_value & REG_LOCK_STAT))
++		return -EBUSY;
++
++	ret |= hibvt_spi_rtc_read(rtc->regs, RTC_S_COUNT, &second);
++	ret |= hibvt_spi_rtc_read(rtc->regs, RTC_M_COUNT, &minute);
++	ret |= hibvt_spi_rtc_read(rtc->regs, RTC_H_COUNT, &hour);
++	ret |= hibvt_spi_rtc_read(rtc->regs, RTC_D_COUNT_L, &dayl);
++	ret |= hibvt_spi_rtc_read(rtc->regs, RTC_D_COUNT_H, &dayh);
++
++	if (ret) {
++		dev_err(dev, "IO err.\n");
++		return ret;
++	}
++
++	day = (dayl | (dayh << 8));
++	seconds = DATE_TO_SEC(day, hour, minute, second);
++
++	rtc_time_to_tm(seconds, time);
++
++	return rtc_valid_tm(time);
++}
++
++static int hibvt_rtc_set_time(struct device *dev, struct rtc_time *time)
++{
++	struct hibvt_rtc	*rtc = dev_get_drvdata(dev);
++	unsigned char ret = 0;
++	unsigned int days;
++	unsigned long seconds = 0;
++	unsigned int cnt = RETRY_CNT;
++	unsigned char raw_value = 0;
++
++	ret = rtc_tm_to_time(time, &seconds);
++	if (ret)
++		return ret;
++	days = SEC_TO_DAY(seconds);
++
++	ret |= hibvt_spi_rtc_write(rtc->regs, RTC_LR_10MS, 0);
++	ret |= hibvt_spi_rtc_write(rtc->regs, RTC_LR_S, time->tm_sec);
++	ret |= hibvt_spi_rtc_write(rtc->regs, RTC_LR_M, time->tm_min);
++	ret |= hibvt_spi_rtc_write(rtc->regs, RTC_LR_H, time->tm_hour);
++	ret |= hibvt_spi_rtc_write(rtc->regs, RTC_LR_D_L, (days & 0xFF));
++	ret |= hibvt_spi_rtc_write(rtc->regs, RTC_LR_D_H, (days >> 8));
++
++	ret |= hibvt_spi_rtc_write(rtc->regs, RTC_LORD,
++		(raw_value | REG_LOAD_STAT));
++	/* wait rtc load flag */
++	do {
++		ret |= hibvt_spi_rtc_read(rtc->regs, RTC_LORD, &raw_value);
++		msleep(20);
++	} while ((ret || (raw_value & REG_LOAD_STAT)) && (--cnt));
++
++	if (!ret && (raw_value & REG_LOAD_STAT))
++		return -EBUSY;
++
++	if (ret)
++		dev_err(dev, "IO err.\n");
++
++	return ret;
++}
++
++static int hibvt_rtc_read_alarm(struct device *dev,
++	struct rtc_wkalrm *alrm)
++{
++	struct hibvt_rtc *rtc = dev_get_drvdata(dev);
++	unsigned char dayl, dayh;
++	unsigned char second, minute, hour;
++	unsigned long seconds = 0;
++	unsigned int day;
++	unsigned char int_state = 0;
++	int ret = 0;
++
++	memset(alrm, 0, sizeof(struct rtc_wkalrm));
++
++	ret |= hibvt_spi_rtc_read(rtc->regs, RTC_MR_S, &second);
++	ret |= hibvt_spi_rtc_read(rtc->regs, RTC_MR_M, &minute);
++	ret |= hibvt_spi_rtc_read(rtc->regs, RTC_MR_H, &hour);
++	ret |= hibvt_spi_rtc_read(rtc->regs, RTC_MR_D_L, &dayl);
++	ret |= hibvt_spi_rtc_read(rtc->regs, RTC_MR_D_H, &dayh);
++
++	day = (unsigned int)(dayl | (dayh << 8));
++	seconds = DATE_TO_SEC(day, hour, minute, second);
++
++	rtc_time_to_tm(seconds, &alrm->time);
++
++	ret |= hibvt_spi_rtc_read(rtc->regs, RTC_IMSC, &int_state);
++	if (ret) {
++		dev_err(dev, "IO err.\n");
++		return ret;
++	}
++
++	alrm->enabled = !!(int_state & AIE_INT_MASK);
++	alrm->pending = alrm->enabled;
++
++	return 0;
++}
++
++static int hibvt_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
++{
++	struct hibvt_rtc	*rtc = dev_get_drvdata(dev);
++	unsigned int days;
++	unsigned long seconds = 0;
++	unsigned char val = 0;
++	int ret = 0;
++
++	rtc_tm_to_time(&alrm->time, &seconds);
++
++	days = SEC_TO_DAY(seconds);
++
++	ret |= hibvt_spi_rtc_write(rtc->regs, RTC_MR_10MS, 0);
++	ret |= hibvt_spi_rtc_write(rtc->regs, RTC_MR_S, alrm->time.tm_sec);
++	ret |= hibvt_spi_rtc_write(rtc->regs, RTC_MR_M, alrm->time.tm_min);
++	ret |= hibvt_spi_rtc_write(rtc->regs, RTC_MR_H, alrm->time.tm_hour);
++	ret |= hibvt_spi_rtc_write(rtc->regs, RTC_MR_D_L, (days & 0xFF));
++	ret |= hibvt_spi_rtc_write(rtc->regs, RTC_MR_D_H, (days >> 8));
++
++	ret |= hibvt_spi_rtc_read(rtc->regs, RTC_IMSC, &val);
++	if (alrm->enabled)
++		ret |= hibvt_spi_rtc_write(rtc->regs, RTC_IMSC,
++		val | AIE_INT_MASK);
++	else
++		ret |= hibvt_spi_rtc_write(rtc->regs, RTC_IMSC,
++		val & ~AIE_INT_MASK);
++
++	if (ret) {
++		dev_err(dev, "IO err.\n");
++		return ret;
++	}
++
++	return 0;
++}
++
++static int hibvt_rtc_alarm_irq_enable(struct device *dev,
++	unsigned int enabled)
++{
++	struct hibvt_rtc	*rtc = dev_get_drvdata(dev);
++	unsigned char val = 0;
++	int ret = 0;
++
++	ret |= hibvt_spi_rtc_read(rtc->regs, RTC_IMSC, &val);
++	if (enabled)
++		ret |= hibvt_spi_rtc_write(rtc->regs, RTC_IMSC,
++		val | AIE_INT_MASK);
++	else
++		ret |= hibvt_spi_rtc_write(rtc->regs, RTC_IMSC,
++		val & ~AIE_INT_MASK);
++
++	if (ret) {
++		dev_err(dev, "IO err.\n");
++		return ret;
++	}
++
++	return 0;
++}
++
++
++/*
++ * interrupt function
++ * do nothing. left for future
++ */
++static irqreturn_t hibvt_rtc_alm_interrupt(int irq, void *data)
++{
++	struct hibvt_rtc *rtc = (struct hibvt_rtc *)data;
++	unsigned char val = 0;
++	int ret = 0;
++
++	ret |= hibvt_spi_read(rtc->regs, RTC_INT, &val);
++	ret |= hibvt_spi_write(rtc->regs, RTC_INT_CLR, AIE_INT_MASK);
++
++	if (ret) {
++		dev_err(&rtc->rtc_dev->dev, "IO err.\n");
++		return ret;
++	}
++
++	if (val & AIE_INT_MASK)
++		rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF);
++
++	return IRQ_HANDLED;
++}
++
++#define FREQ_MAX_VAL	    3277000
++#define FREQ_MIN_VAL	    3276000
++
++static int hibvt_rtc_ioctl(struct device *dev,
++	unsigned int cmd, unsigned long arg)
++{
++	struct hibvt_rtc	*rtc = dev_get_drvdata(dev);
++	int ret = 0;
++
++	switch (cmd) {
++	case RTC_PLL_SET:
++	{
++		char freq_l, freq_h;
++		struct rtc_pll_info pll_info;
++
++		if (copy_from_user(&pll_info, (struct rtc_pll_info *)arg,
++			sizeof(struct rtc_pll_info)))
++			return -EFAULT;
++
++		/* freq = 32700 + (freq /3052)*100 */
++		if (pll_info.pll_value > FREQ_MAX_VAL
++			|| pll_info.pll_value < FREQ_MIN_VAL)
++			return -EINVAL;
++
++		pll_info.pll_value = (pll_info.pll_value - 3270000)
++			* 3052 / 10000;
++
++		freq_l = (char)(pll_info.pll_value & 0xff);
++		freq_h = (char)((pll_info.pll_value >> 8) & 0xf);
++
++		ret |= hibvt_spi_rtc_write(rtc->regs, RTC_FREQ_H, freq_h);
++		ret |= hibvt_spi_rtc_write(rtc->regs, RTC_FREQ_L, freq_l);
++
++		if (ret) {
++			dev_err(dev, "IO err.\n");
++			return ret;
++		}
++
++		return 0;
++	}
++	case RTC_PLL_GET:
++	{
++		char freq_l, freq_h;
++		struct rtc_pll_info pll_info;
++
++		ret |= hibvt_spi_rtc_read(rtc->regs, RTC_FREQ_H, &freq_h);
++		ret |= hibvt_spi_rtc_read(rtc->regs, RTC_FREQ_L, &freq_l);
++
++		if (ret) {
++			dev_err(dev, "IO err.\n");
++			return ret;
++		}
++
++		pll_info.pll_value = ((freq_h & 0xf) << 8) + freq_l;
++		pll_info.pll_value = 3270000
++			+ (pll_info.pll_value * 10000) / 3052;
++
++		pll_info.pll_max = FREQ_MAX_VAL;
++		pll_info.pll_min = FREQ_MIN_VAL;
++
++		if (copy_to_user((void __user *)arg,
++			&pll_info, sizeof(struct rtc_pll_info)))
++			return -EFAULT;
++
++		return 0;
++	}
++	default:
++		return -ENOIOCTLCMD;
++	}
++}
++
++static const struct rtc_class_ops hibvt_rtc_ops = {
++	.read_time		= hibvt_rtc_read_time,
++	.set_time		= hibvt_rtc_set_time,
++	.read_alarm		= hibvt_rtc_read_alarm,
++	.set_alarm		= hibvt_rtc_set_alarm,
++	.alarm_irq_enable	= hibvt_rtc_alarm_irq_enable,
++	.ioctl          = hibvt_rtc_ioctl,
++};
++
++static int hibvt_rtc_init(struct hibvt_rtc *rtc)
++{
++	void *spi_reg = rtc->regs;
++	int ret = 0;
++	unsigned char val = 0;
++	/*
++	 * clk div value = (apb_clk/spi_clk)/2-1,
++	 *	apb clk = 100MHz, spi_clk = 10MHz,so value= 0x4
++	 */
++	writel(CLK_DIV_DEFAULT, (spi_reg+SPI_CLK_DIV));
++
++	ret |= hibvt_spi_rtc_write(spi_reg, RTC_IMSC, INT_MSK_DEFAULT);
++	ret |= hibvt_spi_rtc_write(spi_reg, RTC_SAR_CTRL, LV_CTL_DEFAULT);
++
++   
++	ret |= hibvt_spi_rtc_write(spi_reg, RTC_CLK_CFG, 0x01);
++
++    /* default FREQ COEF */
++	ret |= hibvt_spi_rtc_write(spi_reg, RTC_FREQ_H, FREQ_H_DEFAULT);
++	ret |= hibvt_spi_rtc_write(spi_reg, RTC_FREQ_L, FREQ_L_DEFAULT);
++
++	ret |= hibvt_spi_rtc_read(spi_reg, RTC_INT_RAW, &val);
++    //ret |= hibvt_spi_rtc_read(spi_reg, RTC_CLK_CFG, &val2);
++	if (ret) {
++		dev_err(&rtc->rtc_dev->dev, "IO err.\n");
++		return ret;
++	}
++ 
++	if (val & LV_INT_MASK) {
++		dev_err(&rtc->rtc_dev->dev,
++			"low voltage detected, date/time is not reliable.\n");
++		hibvt_spi_write(rtc->regs, RTC_INT_CLR, 1);
++	}
++
++	return ret;
++}
++
++static int hibvt_rtc_probe(struct platform_device *pdev)
++{
++	struct resource  *mem;
++	struct hibvt_rtc *rtc;
++	int    ret;
++
++	rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
++	if (!rtc)
++		return -ENOMEM;
++
++	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	rtc->regs = devm_ioremap_resource(&pdev->dev, mem);
++	if (IS_ERR((const void *)rtc->regs)) {
++		dev_err(&pdev->dev, "could not map I/O memory\n");
++		return PTR_ERR((const void *)rtc->regs);
++	}
++
++	rtc->rtc_irq = platform_get_irq(pdev, 0);
++	ret = devm_request_irq(&pdev->dev, rtc->rtc_irq,
++		hibvt_rtc_alm_interrupt, 0, pdev->name, rtc);
++	if (ret) {
++		dev_err(&pdev->dev, "could not request irq %d\n", rtc->rtc_irq);
++		return ret;
++	}
++
++	platform_set_drvdata(pdev, rtc);
++	rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, pdev->name,
++						&hibvt_rtc_ops, THIS_MODULE);
++	if (IS_ERR(rtc->rtc_dev)) {
++		dev_err(&pdev->dev, "could not register rtc device\n");
++		return PTR_ERR(rtc->rtc_dev);
++	}
++
++	if (hibvt_rtc_init(rtc)) {
++		dev_err(&pdev->dev, "hibvt_rtc_init failed.\n");
++		return -EIO;
++	}
++
++	dev_info(&pdev->dev, "RTC driver for hibvt enabled\n");
++
++	return 0;
++}
++
++static int hibvt_rtc_remove(struct platform_device *pdev)
++{
++	return 0;
++}
++
++static const struct of_device_id hibvt_rtc_match[] = {
++	{ .compatible = "hisilicon,hi35xx-rtc" },
++	{},
++};
++
++static struct platform_driver hibvt_rtc_driver = {
++	.probe  = hibvt_rtc_probe,
++	.remove = hibvt_rtc_remove,
++	.driver =  { .name = "hibvt_rtc",
++				.of_match_table = hibvt_rtc_match,
++				},
++};
++
++module_platform_driver(hibvt_rtc_driver);
++
++#define OSDRV_MODULE_VERSION_STRING "HISI_rtc @HiMPP"
++
++MODULE_AUTHOR("Hisilicon");
++MODULE_DESCRIPTION("Hisilicon RTC driver");
++MODULE_LICENSE("GPL v2");
++MODULE_VERSION("HI_VERSION=" OSDRV_MODULE_VERSION_STRING);
++
+diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
+index b1ab509..d0bc88d 100644
+--- a/drivers/scsi/scsi_lib.c
++++ b/drivers/scsi/scsi_lib.c
+@@ -1491,7 +1491,7 @@ static inline int scsi_host_queue_ready(struct request_queue *q,
+ 	if (scsi_host_in_recovery(shost))
+ 		return 0;
+ 
+-	busy = atomic_inc_return(&shost->host_busy) - 1;
++	busy = atomic_read(&shost->host_busy);
+ 	if (atomic_read(&shost->host_blocked) > 0) {
+ 		if (busy)
+ 			goto starved;
+@@ -1500,7 +1500,7 @@ static inline int scsi_host_queue_ready(struct request_queue *q,
+ 		 * unblock after host_blocked iterates to zero
+ 		 */
+ 		if (atomic_dec_return(&shost->host_blocked) > 0)
+-			goto out_dec;
++			goto out;
+ 
+ 		SCSI_LOG_MLQUEUE(3,
+ 			shost_printk(KERN_INFO, shost,
+@@ -1520,6 +1520,7 @@ static inline int scsi_host_queue_ready(struct request_queue *q,
+ 		spin_unlock_irq(shost->host_lock);
+ 	}
+ 
++	atomic_inc(&shost->host_busy);
+ 	return 1;
+ 
+ starved:
+@@ -1527,8 +1528,7 @@ starved:
+ 	if (list_empty(&sdev->starved_entry))
+ 		list_add_tail(&sdev->starved_entry, &shost->starved_list);
+ 	spin_unlock_irq(shost->host_lock);
+-out_dec:
+-	atomic_dec(&shost->host_busy);
++out:
+ 	return 0;
+ }
+ 
+diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
+index 07b2ea1..b34be2a 100644
+--- a/drivers/scsi/sg.c
++++ b/drivers/scsi/sg.c
+@@ -592,6 +592,9 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
+ 	sg_io_hdr_t *hp;
+ 	unsigned char cmnd[SG_MAX_CDB_SIZE];
+ 
++	if (unlikely(segment_eq(get_fs(), KERNEL_DS)))
++		return -EINVAL;
++
+ 	if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
+ 		return -ENXIO;
+ 	SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sdp,
+@@ -787,8 +790,14 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp,
+ 		return k;	/* probably out of space --> ENOMEM */
+ 	}
+ 	if (atomic_read(&sdp->detaching)) {
+-		if (srp->bio)
++		if (srp->bio) {
++			if (srp->rq->cmd != srp->rq->__cmd)
++				kfree(srp->rq->cmd);
++
+ 			blk_end_request_all(srp->rq, -EIO);
++			srp->rq = NULL;
++		}
++
+ 		sg_finish_rem_req(srp);
+ 		return -ENODEV;
+ 	}
+@@ -1013,6 +1022,8 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
+ 		result = get_user(val, ip);
+ 		if (result)
+ 			return result;
++		if (val > SG_MAX_CDB_SIZE)
++			return -ENOMEM;
+ 		sfp->next_cmd_len = (val > 0) ? val : 0;
+ 		return 0;
+ 	case SG_GET_VERSION_NUM:
+@@ -1785,6 +1796,9 @@ sg_start_req(Sg_request *srp, unsigned char *cmd)
+ 			md->from_user = 0;
+ 	}
+ 
++	if (unlikely(iov_count > UIO_MAXIOV))
++			return -EINVAL;
++
+ 	if (iov_count) {
+ 		int len, size = sizeof(struct sg_iovec) * iov_count;
+ 		struct iovec *iov;
+diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c
+index 11e1834..f295a8a 100644
+--- a/drivers/spi/spi-pl022.c
++++ b/drivers/spi/spi-pl022.c
+@@ -43,6 +43,7 @@
+ #include <linux/gpio.h>
+ #include <linux/of_gpio.h>
+ #include <linux/pinctrl/consumer.h>
++#include <linux/of_address.h>
+ 
+ /*
+  * This macro is used to define some register default values.
+@@ -137,6 +138,13 @@
+ #define SSP_CR1_MASK_FBCLKDEL_ST (0x7UL << 13)
+ 
+ /*
++ * The Hisilicon version of this block adds some bits
++ * in SSP_CR1
++ */
++#define SSP_CR1_MASK_BIGEND_HISI	(0x1UL << 4)
++#define SSP_CR1_MASK_ALTASENS_HISI	(0x1UL << 6)
++
++/*
+  * SSP Status Register - SSP_SR
+  */
+ #define SSP_SR_MASK_TFE		(0x1UL << 0) /* Transmit FIFO empty */
+@@ -291,6 +299,8 @@
+ 
+ #define SPI_POLLING_TIMEOUT 1000
+ 
++#define PL022_IDS_INDEX_HISI		4
++
+ /*
+  * The type of reading going on on this chip
+  */
+@@ -332,6 +342,13 @@ struct vendor_data {
+ 	bool internal_cs_ctrl;
+ };
+ 
++struct cs_data {
++	struct resource		res;
++	void __iomem		*virt_addr;
++	unsigned int		cs_sb;
++	unsigned int		cs_mask_bit;
++};
++
+ /**
+  * struct pl022 - This is the private SSP driver data structure
+  * @adev: AMBA device model hookup
+@@ -405,6 +422,7 @@ struct pl022 {
+ #endif
+ 	int cur_cs;
+ 	int *chipselects;
++	struct cs_data		*cs_data;
+ };
+ 
+ /**
+@@ -461,13 +479,37 @@ static void null_cs_control(u32 command)
+ static void internal_cs_control(struct pl022 *pl022, u32 command)
+ {
+ 	u32 tmp;
++	struct amba_device *adev = pl022->adev;
++	struct amba_driver *adrv = container_of(adev->dev.driver,
++			struct amba_driver, drv);
++
++	if (pl022->vendor->extended_cr && (adev->periphid ==
++				adrv->id_table[PL022_IDS_INDEX_HISI].id)) {
++		if (pl022->cs_data) {
++			tmp = readl(pl022->cs_data->virt_addr);
++			tmp &= ~(pl022->cs_data->cs_mask_bit);
++			tmp |= ((u32)pl022->cur_cs) << pl022->cs_data->cs_sb;
++			writel(tmp, pl022->cs_data->virt_addr);
++		}
+ 
+-	tmp = readw(SSP_CSR(pl022->virtbase));
+-	if (command == SSP_CHIP_SELECT)
+-		tmp &= ~BIT(pl022->cur_cs);
+-	else
+-		tmp |= BIT(pl022->cur_cs);
+-	writew(tmp, SSP_CSR(pl022->virtbase));
++		if (command == SSP_CHIP_SELECT)
++			/* Enable SSP */
++			writew((readw(SSP_CR1(pl022->virtbase)) |
++						SSP_CR1_MASK_SSE),
++					SSP_CR1(pl022->virtbase));
++		else
++			/* disable SSP */
++			writew((readw(SSP_CR1(pl022->virtbase)) &
++						(~SSP_CR1_MASK_SSE)),
++					SSP_CR1(pl022->virtbase));
++	} else {
++		tmp = readw(SSP_CSR(pl022->virtbase));
++		if (command == SSP_CHIP_SELECT)
++			tmp &= ~BIT((u32)pl022->cur_cs);
++		else
++			tmp |= BIT((u32)pl022->cur_cs);
++		writew(tmp, SSP_CSR(pl022->virtbase));
++	}
+ }
+ 
+ static void pl022_cs_control(struct pl022 *pl022, u32 command)
+@@ -568,8 +610,12 @@ static int flush(struct pl022 *pl022)
+ static void restore_state(struct pl022 *pl022)
+ {
+ 	struct chip_data *chip = pl022->cur_chip;
++	struct amba_device *adev = pl022->adev;
++	struct amba_driver *adrv = container_of(adev->dev.driver,
++			struct amba_driver, drv);
+ 
+-	if (pl022->vendor->extended_cr)
++	if (pl022->vendor->extended_cr && (adev->periphid !=
++				adrv->id_table[PL022_IDS_INDEX_HISI].id))
+ 		writel(chip->cr0, SSP_CR0(pl022->virtbase));
+ 	else
+ 		writew(chip->cr0, SSP_CR0(pl022->virtbase));
+@@ -642,6 +688,13 @@ static void restore_state(struct pl022 *pl022)
+ 	GEN_MASK_BITS(SSP_FEEDBACK_CLK_DELAY_NONE, SSP_CR1_MASK_FBCLKDEL_ST, 13) \
+ )
+ 
++/* Hisilicon versions extend this register to use all 16 bits */
++#define DEFAULT_SSP_REG_CR1_HISI ( \
++	DEFAULT_SSP_REG_CR1 | \
++	GEN_MASK_BITS(SSP_RX_MSB, SSP_CR1_MASK_BIGEND_HISI, 4) | \
++	GEN_MASK_BITS(0x1, SSP_CR1_MASK_ALTASENS_HISI, 6) \
++)
++
+ #define DEFAULT_SSP_REG_CPSR ( \
+ 	GEN_MASK_BITS(SSP_DEFAULT_PRESCALE, SSP_CPSR_MASK_CPSDVSR, 0) \
+ )
+@@ -657,12 +710,24 @@ static void restore_state(struct pl022 *pl022)
+  */
+ static void load_ssp_default_config(struct pl022 *pl022)
+ {
++	struct amba_device *adev = pl022->adev;
++	struct amba_driver *adrv = container_of(adev->dev.driver,
++			struct amba_driver, drv);
++
+ 	if (pl022->vendor->pl023) {
+ 		writel(DEFAULT_SSP_REG_CR0_ST_PL023, SSP_CR0(pl022->virtbase));
+ 		writew(DEFAULT_SSP_REG_CR1_ST_PL023, SSP_CR1(pl022->virtbase));
+ 	} else if (pl022->vendor->extended_cr) {
+-		writel(DEFAULT_SSP_REG_CR0_ST, SSP_CR0(pl022->virtbase));
+-		writew(DEFAULT_SSP_REG_CR1_ST, SSP_CR1(pl022->virtbase));
++		if (adev->periphid == adrv->id_table[PL022_IDS_INDEX_HISI].id) {
++			writew(DEFAULT_SSP_REG_CR0, SSP_CR0(pl022->virtbase));
++			writew(DEFAULT_SSP_REG_CR1_HISI,
++					SSP_CR1(pl022->virtbase));
++		} else {
++			writel(DEFAULT_SSP_REG_CR0_ST,
++					SSP_CR0(pl022->virtbase));
++			writew(DEFAULT_SSP_REG_CR1_ST,
++					SSP_CR1(pl022->virtbase));
++		}
+ 	} else {
+ 		writew(DEFAULT_SSP_REG_CR0, SSP_CR0(pl022->virtbase));
+ 		writew(DEFAULT_SSP_REG_CR1, SSP_CR1(pl022->virtbase));
+@@ -1830,6 +1895,10 @@ static int pl022_setup(struct spi_device *spi)
+ 	unsigned int bits = spi->bits_per_word;
+ 	u32 tmp;
+ 	struct device_node *np = spi->dev.of_node;
++	struct amba_device *adev = pl022->adev;
++	struct amba_driver *adrv = container_of(adev->dev.driver,
++			struct amba_driver, drv);
++
+ 
+ 	if (!spi->max_speed_hz)
+ 		return -EINVAL;
+@@ -1972,7 +2041,8 @@ static int pl022_setup(struct spi_device *spi)
+ 	chip->cpsr = clk_freq.cpsdvsr;
+ 
+ 	/* Special setup for the ST micro extended control registers */
+-	if (pl022->vendor->extended_cr) {
++	if (pl022->vendor->extended_cr && (adev->periphid !=
++				adrv->id_table[PL022_IDS_INDEX_HISI].id)) {
+ 		u32 etx;
+ 
+ 		if (pl022->vendor->pl023) {
+@@ -2006,6 +2076,20 @@ static int pl022_setup(struct spi_device *spi)
+ 			       SSP_CR1_MASK_RXIFLSEL_ST, 7);
+ 		SSP_WRITE_BITS(chip->cr1, chip_info->tx_lev_trig,
+ 			       SSP_CR1_MASK_TXIFLSEL_ST, 10);
++	} else if (pl022->vendor->extended_cr && (adev->periphid ==
++				adrv->id_table[PL022_IDS_INDEX_HISI].id)) {
++		SSP_WRITE_BITS(chip->cr0, bits - 1,
++			       SSP_CR0_MASK_DSS, 0);
++		SSP_WRITE_BITS(chip->cr0, chip_info->iface,
++			       SSP_CR0_MASK_FRF, 4);
++
++		if (spi->mode & SPI_LSB_FIRST)
++			tmp = !!SPI_LSB_FIRST;
++		else
++			tmp = !SPI_LSB_FIRST;
++
++		SSP_WRITE_BITS(chip->cr1, tmp, SSP_CR1_MASK_BIGEND_HISI, 4);
++		SSP_WRITE_BITS(chip->cr1, 0x1, SSP_CR1_MASK_ALTASENS_HISI, 6);
+ 	} else {
+ 		SSP_WRITE_BITS(chip->cr0, bits - 1,
+ 			       SSP_CR0_MASK_DSS, 0);
+@@ -2037,7 +2121,7 @@ static int pl022_setup(struct spi_device *spi)
+ 	}
+ 	SSP_WRITE_BITS(chip->cr1, SSP_DISABLED, SSP_CR1_MASK_SSE, 1);
+ 	SSP_WRITE_BITS(chip->cr1, chip_info->hierarchy, SSP_CR1_MASK_MS, 2);
+-	SSP_WRITE_BITS(chip->cr1, chip_info->slave_tx_disable, SSP_CR1_MASK_SOD,
++	SSP_WRITE_BITS(chip->cr1, (unsigned int)chip_info->slave_tx_disable, SSP_CR1_MASK_SOD,
+ 		3);
+ 
+ 	/* Save controller_state */
+@@ -2069,7 +2153,7 @@ pl022_platform_data_dt_get(struct device *dev)
+ {
+ 	struct device_node *np = dev->of_node;
+ 	struct pl022_ssp_controller *pd;
+-	u32 tmp;
++	u32 tmp = 0;
+ 
+ 	if (!np) {
+ 		dev_err(dev, "no dt node defined\n");
+@@ -2094,6 +2178,8 @@ pl022_platform_data_dt_get(struct device *dev)
+ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
+ {
+ 	struct device *dev = &adev->dev;
++	struct amba_driver *adrv = container_of(adev->dev.driver,
++			struct amba_driver, drv);
+ 	struct pl022_ssp_controller *platform_info =
+ 			dev_get_platdata(&adev->dev);
+ 	struct spi_master *master;
+@@ -2157,6 +2243,41 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
+ 	} else if (pl022->vendor->internal_cs_ctrl) {
+ 		for (i = 0; i < num_cs; i++)
+ 			pl022->chipselects[i] = i;
++
++		if ((adev->periphid == adrv->id_table[PL022_IDS_INDEX_HISI].id)
++				&& pl022->vendor->extended_cr
++				&& (num_cs > 1)) {
++			pl022->cs_data = devm_kzalloc(dev,
++					sizeof(struct cs_data),
++					GFP_KERNEL);
++			if (!pl022->cs_data) {
++				status = -ENOMEM;
++				goto err_no_mem;
++			}
++
++			if (of_address_to_resource(np, 1,
++						&pl022->cs_data->res)) {
++				status = -EPROBE_DEFER;
++				goto err_no_gpio;
++			}
++
++			if (of_property_read_u32(np, "hisi,spi_cs_sb",
++						&pl022->cs_data->cs_sb)) {
++				status = -EPROBE_DEFER;
++				goto err_no_gpio;
++			}
++
++			if (of_property_read_u32(np, "hisi,spi_cs_mask_bit",
++						&pl022->cs_data->cs_mask_bit)) {
++				status = -EPROBE_DEFER;
++				goto err_no_gpio;
++			}
++
++			pl022->cs_data->virt_addr = devm_ioremap(dev,
++					pl022->cs_data->res.start,
++					resource_size(&adev->res));
++		} else
++				pl022->cs_data = NULL;
+ 	} else if (IS_ENABLED(CONFIG_OF)) {
+ 		for (i = 0; i < num_cs; i++) {
+ 			int cs_gpio = of_get_named_gpio(np, "cs-gpios", i);
+@@ -2279,6 +2400,10 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
+  err_no_ioremap:
+ 	amba_release_regions(adev);
+  err_no_ioregion:
++	if (pl022->cs_data)
++		release_mem_region(pl022->cs_data->res.start,
++				resource_size(&pl022->cs_data->res));
++
+  err_no_gpio:
+  err_no_mem:
+ 	spi_master_put(master);
+@@ -2305,6 +2430,10 @@ pl022_remove(struct amba_device *adev)
+ 
+ 	clk_disable_unprepare(pl022->clk);
+ 	amba_release_regions(adev);
++	if (pl022->cs_data)
++		release_mem_region(pl022->cs_data->res.start,
++				resource_size(&pl022->cs_data->res));
++
+ 	tasklet_disable(&pl022->pump_transfers);
+ 	return 0;
+ }
+@@ -2420,6 +2549,16 @@ static struct vendor_data vendor_lsi = {
+ 	.internal_cs_ctrl = true,
+ };
+ 
++static struct vendor_data vendor_hisi = {
++	.fifodepth = 256,
++	.max_bpw = 16,
++	.unidir = false,
++	.extended_cr = true,
++	.pl023 = false,
++	.loopback = true,
++	.internal_cs_ctrl = true,
++};
++
+ static struct amba_id pl022_ids[] = {
+ 	{
+ 		/*
+@@ -2460,6 +2599,15 @@ static struct amba_id pl022_ids[] = {
+ 		.mask	= 0x000fffff,
+ 		.data	= &vendor_lsi,
+ 	},
++	{
++		/*
++		 * Hisilicon derivative, this has a 16bit wide
++		 * and 256 locations deep TX/RX FIFO
++		 */
++		.id	= 0x00800022,
++		.mask	= 0xffffffff,
++		.data	= &vendor_hisi,
++	},
+ 	{ 0, 0 },
+ };
+ 
+diff --git a/drivers/staging/android/Kconfig b/drivers/staging/android/Kconfig
+index 7a0e288..21bc8ec 100644
+--- a/drivers/staging/android/Kconfig
++++ b/drivers/staging/android/Kconfig
+@@ -44,23 +44,6 @@ config ASHMEM
+ 	  It is, in theory, a good memory allocator for low-memory devices,
+ 	  because it can discard shared memory units when under memory pressure.
+ 
+-config ANDROID_LOGGER
+-	tristate "Android log driver"
+-	default n
+-	---help---
+-	  This adds support for system-wide logging using four log buffers.
+-
+-	  These are:
+-
+-	      1: main
+-	      2: events
+-	      3: radio
+-	      4: system
+-
+-	  Log reading and writing is performed via normal Linux reads and
+-	  optimized writes. This optimization avoids logging having too
+-	  much overhead in the system.
+-
+ config ANDROID_TIMED_OUTPUT
+ 	bool "Timed output class driver"
+ 	default y
+@@ -75,14 +58,14 @@ config ANDROID_LOW_MEMORY_KILLER
+ 	---help---
+ 	  Registers processes to be killed when memory is low
+ 
+-config ANDROID_INTF_ALARM_DEV
+-	tristate "Android alarm driver"
+-	depends on RTC_CLASS
+-	default n
++config ANDROID_LOW_MEMORY_KILLER_AUTODETECT_OOM_ADJ_VALUES
++	bool "Android Low Memory Killer: detect oom_adj values"
++	depends on ANDROID_LOW_MEMORY_KILLER
++	default y
+ 	---help---
+-	  Provides non-wakeup and rtc backed wakeup alarms based on rtc or
+-	  elapsed realtime, and a non-wakeup alarm on the monotonic clock.
+-	  Also exports the alarm interface to user-space.
++	  Detect oom_adj values written to
++	  /sys/module/lowmemorykiller/parameters/adj and convert them
++	  to oom_score_adj values.
+ 
+ config SYNC
+ 	bool "Synchronization framework"
+@@ -114,6 +97,8 @@ config SW_SYNC_USER
+ 
+ source "drivers/staging/android/ion/Kconfig"
+ 
++source "drivers/staging/android/fiq_debugger/Kconfig"
++
+ endif # if ANDROID
+ 
+ endmenu
+diff --git a/drivers/staging/android/Makefile b/drivers/staging/android/Makefile
+index 517ad5f..b7b9980 100644
+--- a/drivers/staging/android/Makefile
++++ b/drivers/staging/android/Makefile
+@@ -1,13 +1,12 @@
+ ccflags-y += -I$(src)			# needed for trace events
+ 
+ obj-y					+= ion/
++obj-$(CONFIG_FIQ_DEBUGGER)		+= fiq_debugger/
+ 
+ obj-$(CONFIG_ANDROID_BINDER_IPC)	+= binder.o
+ obj-$(CONFIG_ASHMEM)			+= ashmem.o
+-obj-$(CONFIG_ANDROID_LOGGER)		+= logger.o
+ obj-$(CONFIG_ANDROID_TIMED_OUTPUT)	+= timed_output.o
+ obj-$(CONFIG_ANDROID_TIMED_GPIO)	+= timed_gpio.o
+ obj-$(CONFIG_ANDROID_LOW_MEMORY_KILLER)	+= lowmemorykiller.o
+-obj-$(CONFIG_ANDROID_INTF_ALARM_DEV)	+= alarm-dev.o
+ obj-$(CONFIG_SYNC)			+= sync.o sync_debug.o
+ obj-$(CONFIG_SW_SYNC)			+= sw_sync.o
+diff --git a/drivers/staging/android/TODO b/drivers/staging/android/TODO
+deleted file mode 100644
+index b15fb0d..0000000
+--- a/drivers/staging/android/TODO
++++ /dev/null
+@@ -1,10 +0,0 @@
+-TODO:
+-	- checkpatch.pl cleanups
+-	- sparse fixes
+-	- rename files to be not so "generic"
+-	- make sure things build as modules properly
+-	- add proper arch dependencies as needed
+-	- audit userspace interfaces to make sure they are sane
+-
+-Please send patches to Greg Kroah-Hartman <greg@kroah.com> and Cc:
+-Brian Swetland <swetland@google.com>
+diff --git a/drivers/staging/android/alarm-dev.c b/drivers/staging/android/alarm-dev.c
+deleted file mode 100644
+index ff4b3e8..0000000
+--- a/drivers/staging/android/alarm-dev.c
++++ /dev/null
+@@ -1,446 +0,0 @@
+-/* drivers/rtc/alarm-dev.c
+- *
+- * Copyright (C) 2007-2009 Google, Inc.
+- *
+- * This software is licensed under the terms of the GNU General Public
+- * License version 2, as published by the Free Software Foundation, and
+- * may be copied, distributed, and modified under those terms.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- * GNU General Public License for more details.
+- *
+- */
+-
+-#include <linux/time.h>
+-#include <linux/module.h>
+-#include <linux/device.h>
+-#include <linux/miscdevice.h>
+-#include <linux/fs.h>
+-#include <linux/platform_device.h>
+-#include <linux/sched.h>
+-#include <linux/spinlock.h>
+-#include <linux/uaccess.h>
+-#include <linux/alarmtimer.h>
+-#include "android_alarm.h"
+-
+-#define ANDROID_ALARM_PRINT_INFO (1U << 0)
+-#define ANDROID_ALARM_PRINT_IO (1U << 1)
+-#define ANDROID_ALARM_PRINT_INT (1U << 2)
+-
+-static int debug_mask = ANDROID_ALARM_PRINT_INFO;
+-module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
+-
+-#define alarm_dbg(debug_level_mask, fmt, ...)				\
+-do {									\
+-	if (debug_mask & ANDROID_ALARM_PRINT_##debug_level_mask)	\
+-		pr_info(fmt, ##__VA_ARGS__);				\
+-} while (0)
+-
+-#define ANDROID_ALARM_WAKEUP_MASK ( \
+-	ANDROID_ALARM_RTC_WAKEUP_MASK | \
+-	ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP_MASK)
+-
+-static int alarm_opened;
+-static DEFINE_SPINLOCK(alarm_slock);
+-static struct wakeup_source alarm_wake_lock;
+-static DECLARE_WAIT_QUEUE_HEAD(alarm_wait_queue);
+-static uint32_t alarm_pending;
+-static uint32_t alarm_enabled;
+-static uint32_t wait_pending;
+-
+-struct devalarm {
+-	union {
+-		struct hrtimer hrt;
+-		struct alarm alrm;
+-	} u;
+-	enum android_alarm_type type;
+-};
+-
+-static struct devalarm alarms[ANDROID_ALARM_TYPE_COUNT];
+-
+-/**
+- * is_wakeup() - Checks to see if this alarm can wake the device
+- * @type:	 The type of alarm being checked
+- *
+- * Return: 1 if this is a wakeup alarm, otherwise 0
+- */
+-static int is_wakeup(enum android_alarm_type type)
+-{
+-	return type == ANDROID_ALARM_RTC_WAKEUP ||
+-		type == ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP;
+-}
+-
+-static void devalarm_start(struct devalarm *alrm, ktime_t exp)
+-{
+-	if (is_wakeup(alrm->type))
+-		alarm_start(&alrm->u.alrm, exp);
+-	else
+-		hrtimer_start(&alrm->u.hrt, exp, HRTIMER_MODE_ABS);
+-}
+-
+-static int devalarm_try_to_cancel(struct devalarm *alrm)
+-{
+-	if (is_wakeup(alrm->type))
+-		return alarm_try_to_cancel(&alrm->u.alrm);
+-	return hrtimer_try_to_cancel(&alrm->u.hrt);
+-}
+-
+-static void devalarm_cancel(struct devalarm *alrm)
+-{
+-	if (is_wakeup(alrm->type))
+-		alarm_cancel(&alrm->u.alrm);
+-	else
+-		hrtimer_cancel(&alrm->u.hrt);
+-}
+-
+-static void alarm_clear(enum android_alarm_type alarm_type)
+-{
+-	uint32_t alarm_type_mask = 1U << alarm_type;
+-	unsigned long flags;
+-
+-	spin_lock_irqsave(&alarm_slock, flags);
+-	alarm_dbg(IO, "alarm %d clear\n", alarm_type);
+-	devalarm_try_to_cancel(&alarms[alarm_type]);
+-	if (alarm_pending) {
+-		alarm_pending &= ~alarm_type_mask;
+-		if (!alarm_pending && !wait_pending)
+-			__pm_relax(&alarm_wake_lock);
+-	}
+-	alarm_enabled &= ~alarm_type_mask;
+-	spin_unlock_irqrestore(&alarm_slock, flags);
+-}
+-
+-static void alarm_set(enum android_alarm_type alarm_type,
+-							struct timespec *ts)
+-{
+-	uint32_t alarm_type_mask = 1U << alarm_type;
+-	unsigned long flags;
+-
+-	spin_lock_irqsave(&alarm_slock, flags);
+-	alarm_dbg(IO, "alarm %d set %ld.%09ld\n",
+-			alarm_type, ts->tv_sec, ts->tv_nsec);
+-	alarm_enabled |= alarm_type_mask;
+-	devalarm_start(&alarms[alarm_type], timespec_to_ktime(*ts));
+-	spin_unlock_irqrestore(&alarm_slock, flags);
+-}
+-
+-static int alarm_wait(void)
+-{
+-	unsigned long flags;
+-	int rv = 0;
+-
+-	spin_lock_irqsave(&alarm_slock, flags);
+-	alarm_dbg(IO, "alarm wait\n");
+-	if (!alarm_pending && wait_pending) {
+-		__pm_relax(&alarm_wake_lock);
+-		wait_pending = 0;
+-	}
+-	spin_unlock_irqrestore(&alarm_slock, flags);
+-
+-	rv = wait_event_interruptible(alarm_wait_queue, alarm_pending);
+-	if (rv)
+-		return rv;
+-
+-	spin_lock_irqsave(&alarm_slock, flags);
+-	rv = alarm_pending;
+-	wait_pending = 1;
+-	alarm_pending = 0;
+-	spin_unlock_irqrestore(&alarm_slock, flags);
+-
+-	return rv;
+-}
+-
+-static int alarm_set_rtc(struct timespec *ts)
+-{
+-	struct rtc_time new_rtc_tm;
+-	struct rtc_device *rtc_dev;
+-	unsigned long flags;
+-	int rv = 0;
+-
+-	rtc_time_to_tm(ts->tv_sec, &new_rtc_tm);
+-	rtc_dev = alarmtimer_get_rtcdev();
+-	rv = do_settimeofday(ts);
+-	if (rv < 0)
+-		return rv;
+-	if (rtc_dev)
+-		rv = rtc_set_time(rtc_dev, &new_rtc_tm);
+-
+-	spin_lock_irqsave(&alarm_slock, flags);
+-	alarm_pending |= ANDROID_ALARM_TIME_CHANGE_MASK;
+-	wake_up(&alarm_wait_queue);
+-	spin_unlock_irqrestore(&alarm_slock, flags);
+-
+-	return rv;
+-}
+-
+-static int alarm_get_time(enum android_alarm_type alarm_type,
+-							struct timespec *ts)
+-{
+-	int rv = 0;
+-
+-	switch (alarm_type) {
+-	case ANDROID_ALARM_RTC_WAKEUP:
+-	case ANDROID_ALARM_RTC:
+-		getnstimeofday(ts);
+-		break;
+-	case ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP:
+-	case ANDROID_ALARM_ELAPSED_REALTIME:
+-		get_monotonic_boottime(ts);
+-		break;
+-	case ANDROID_ALARM_SYSTEMTIME:
+-		ktime_get_ts(ts);
+-		break;
+-	default:
+-		rv = -EINVAL;
+-	}
+-	return rv;
+-}
+-
+-static long alarm_do_ioctl(struct file *file, unsigned int cmd,
+-							struct timespec *ts)
+-{
+-	int rv = 0;
+-	unsigned long flags;
+-	enum android_alarm_type alarm_type = ANDROID_ALARM_IOCTL_TO_TYPE(cmd);
+-
+-	if (alarm_type >= ANDROID_ALARM_TYPE_COUNT)
+-		return -EINVAL;
+-
+-	if (ANDROID_ALARM_BASE_CMD(cmd) != ANDROID_ALARM_GET_TIME(0)) {
+-		if ((file->f_flags & O_ACCMODE) == O_RDONLY)
+-			return -EPERM;
+-		if (file->private_data == NULL &&
+-		    cmd != ANDROID_ALARM_SET_RTC) {
+-			spin_lock_irqsave(&alarm_slock, flags);
+-			if (alarm_opened) {
+-				spin_unlock_irqrestore(&alarm_slock, flags);
+-				return -EBUSY;
+-			}
+-			alarm_opened = 1;
+-			file->private_data = (void *)1;
+-			spin_unlock_irqrestore(&alarm_slock, flags);
+-		}
+-	}
+-
+-	switch (ANDROID_ALARM_BASE_CMD(cmd)) {
+-	case ANDROID_ALARM_CLEAR(0):
+-		alarm_clear(alarm_type);
+-		break;
+-	case ANDROID_ALARM_SET(0):
+-		alarm_set(alarm_type, ts);
+-		break;
+-	case ANDROID_ALARM_SET_AND_WAIT(0):
+-		alarm_set(alarm_type, ts);
+-		/* fall though */
+-	case ANDROID_ALARM_WAIT:
+-		rv = alarm_wait();
+-		break;
+-	case ANDROID_ALARM_SET_RTC:
+-		rv = alarm_set_rtc(ts);
+-		break;
+-	case ANDROID_ALARM_GET_TIME(0):
+-		rv = alarm_get_time(alarm_type, ts);
+-		break;
+-
+-	default:
+-		rv = -EINVAL;
+-	}
+-	return rv;
+-}
+-
+-static long alarm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+-{
+-
+-	struct timespec ts;
+-	int rv;
+-
+-	switch (ANDROID_ALARM_BASE_CMD(cmd)) {
+-	case ANDROID_ALARM_SET_AND_WAIT(0):
+-	case ANDROID_ALARM_SET(0):
+-	case ANDROID_ALARM_SET_RTC:
+-		if (copy_from_user(&ts, (void __user *)arg, sizeof(ts)))
+-			return -EFAULT;
+-		break;
+-	}
+-
+-	rv = alarm_do_ioctl(file, cmd, &ts);
+-	if (rv)
+-		return rv;
+-
+-	switch (ANDROID_ALARM_BASE_CMD(cmd)) {
+-	case ANDROID_ALARM_GET_TIME(0):
+-		if (copy_to_user((void __user *)arg, &ts, sizeof(ts)))
+-			return -EFAULT;
+-		break;
+-	}
+-
+-	return 0;
+-}
+-
+-#ifdef CONFIG_COMPAT
+-static long alarm_compat_ioctl(struct file *file, unsigned int cmd,
+-							unsigned long arg)
+-{
+-
+-	struct timespec ts;
+-	int rv;
+-
+-	switch (ANDROID_ALARM_BASE_CMD(cmd)) {
+-	case ANDROID_ALARM_SET_AND_WAIT_COMPAT(0):
+-	case ANDROID_ALARM_SET_COMPAT(0):
+-	case ANDROID_ALARM_SET_RTC_COMPAT:
+-		if (compat_get_timespec(&ts, (void __user *)arg))
+-			return -EFAULT;
+-		/* fall through */
+-	case ANDROID_ALARM_GET_TIME_COMPAT(0):
+-		cmd = ANDROID_ALARM_COMPAT_TO_NORM(cmd);
+-		break;
+-	}
+-
+-	rv = alarm_do_ioctl(file, cmd, &ts);
+-	if (rv)
+-		return rv;
+-
+-	switch (ANDROID_ALARM_BASE_CMD(cmd)) {
+-	case ANDROID_ALARM_GET_TIME(0): /* NOTE: we modified cmd above */
+-		if (compat_put_timespec(&ts, (void __user *)arg))
+-			return -EFAULT;
+-		break;
+-	}
+-
+-	return 0;
+-}
+-#endif
+-
+-static int alarm_open(struct inode *inode, struct file *file)
+-{
+-	file->private_data = NULL;
+-	return 0;
+-}
+-
+-static int alarm_release(struct inode *inode, struct file *file)
+-{
+-	int i;
+-	unsigned long flags;
+-
+-	spin_lock_irqsave(&alarm_slock, flags);
+-	if (file->private_data) {
+-		for (i = 0; i < ANDROID_ALARM_TYPE_COUNT; i++) {
+-			uint32_t alarm_type_mask = 1U << i;
+-
+-			if (alarm_enabled & alarm_type_mask) {
+-				alarm_dbg(INFO,
+-					  "%s: clear alarm, pending %d\n",
+-					  __func__,
+-					  !!(alarm_pending & alarm_type_mask));
+-				alarm_enabled &= ~alarm_type_mask;
+-			}
+-			spin_unlock_irqrestore(&alarm_slock, flags);
+-			devalarm_cancel(&alarms[i]);
+-			spin_lock_irqsave(&alarm_slock, flags);
+-		}
+-		if (alarm_pending | wait_pending) {
+-			if (alarm_pending)
+-				alarm_dbg(INFO, "%s: clear pending alarms %x\n",
+-					  __func__, alarm_pending);
+-			__pm_relax(&alarm_wake_lock);
+-			wait_pending = 0;
+-			alarm_pending = 0;
+-		}
+-		alarm_opened = 0;
+-	}
+-	spin_unlock_irqrestore(&alarm_slock, flags);
+-	return 0;
+-}
+-
+-static void devalarm_triggered(struct devalarm *alarm)
+-{
+-	unsigned long flags;
+-	uint32_t alarm_type_mask = 1U << alarm->type;
+-
+-	alarm_dbg(INT, "%s: type %d\n", __func__, alarm->type);
+-	spin_lock_irqsave(&alarm_slock, flags);
+-	if (alarm_enabled & alarm_type_mask) {
+-		__pm_wakeup_event(&alarm_wake_lock, 5000); /* 5secs */
+-		alarm_enabled &= ~alarm_type_mask;
+-		alarm_pending |= alarm_type_mask;
+-		wake_up(&alarm_wait_queue);
+-	}
+-	spin_unlock_irqrestore(&alarm_slock, flags);
+-}
+-
+-static enum hrtimer_restart devalarm_hrthandler(struct hrtimer *hrt)
+-{
+-	struct devalarm *devalrm = container_of(hrt, struct devalarm, u.hrt);
+-
+-	devalarm_triggered(devalrm);
+-	return HRTIMER_NORESTART;
+-}
+-
+-static enum alarmtimer_restart devalarm_alarmhandler(struct alarm *alrm,
+-							ktime_t now)
+-{
+-	struct devalarm *devalrm = container_of(alrm, struct devalarm, u.alrm);
+-
+-	devalarm_triggered(devalrm);
+-	return ALARMTIMER_NORESTART;
+-}
+-
+-
+-static const struct file_operations alarm_fops = {
+-	.owner = THIS_MODULE,
+-	.unlocked_ioctl = alarm_ioctl,
+-	.open = alarm_open,
+-	.release = alarm_release,
+-#ifdef CONFIG_COMPAT
+-	.compat_ioctl = alarm_compat_ioctl,
+-#endif
+-};
+-
+-static struct miscdevice alarm_device = {
+-	.minor = MISC_DYNAMIC_MINOR,
+-	.name = "alarm",
+-	.fops = &alarm_fops,
+-};
+-
+-static int __init alarm_dev_init(void)
+-{
+-	int err;
+-	int i;
+-
+-	err = misc_register(&alarm_device);
+-	if (err)
+-		return err;
+-
+-	alarm_init(&alarms[ANDROID_ALARM_RTC_WAKEUP].u.alrm,
+-			ALARM_REALTIME, devalarm_alarmhandler);
+-	hrtimer_init(&alarms[ANDROID_ALARM_RTC].u.hrt,
+-			CLOCK_REALTIME, HRTIMER_MODE_ABS);
+-	alarm_init(&alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP].u.alrm,
+-			ALARM_BOOTTIME, devalarm_alarmhandler);
+-	hrtimer_init(&alarms[ANDROID_ALARM_ELAPSED_REALTIME].u.hrt,
+-			CLOCK_BOOTTIME, HRTIMER_MODE_ABS);
+-	hrtimer_init(&alarms[ANDROID_ALARM_SYSTEMTIME].u.hrt,
+-			CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
+-
+-	for (i = 0; i < ANDROID_ALARM_TYPE_COUNT; i++) {
+-		alarms[i].type = i;
+-		if (!is_wakeup(i))
+-			alarms[i].u.hrt.function = devalarm_hrthandler;
+-	}
+-
+-	wakeup_source_init(&alarm_wake_lock, "alarm");
+-	return 0;
+-}
+-
+-static void  __exit alarm_dev_exit(void)
+-{
+-	misc_deregister(&alarm_device);
+-	wakeup_source_trash(&alarm_wake_lock);
+-}
+-
+-module_init(alarm_dev_init);
+-module_exit(alarm_dev_exit);
+-MODULE_LICENSE("GPL");
+diff --git a/drivers/staging/android/android_alarm.h b/drivers/staging/android/android_alarm.h
+deleted file mode 100644
+index 495b20c..0000000
+--- a/drivers/staging/android/android_alarm.h
++++ /dev/null
+@@ -1,41 +0,0 @@
+-/* include/linux/android_alarm.h
+- *
+- * Copyright (C) 2006-2007 Google, Inc.
+- *
+- * This software is licensed under the terms of the GNU General Public
+- * License version 2, as published by the Free Software Foundation, and
+- * may be copied, distributed, and modified under those terms.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- * GNU General Public License for more details.
+- *
+- */
+-
+-#ifndef _LINUX_ANDROID_ALARM_H
+-#define _LINUX_ANDROID_ALARM_H
+-
+-#include <linux/compat.h>
+-#include <linux/ioctl.h>
+-
+-#include "uapi/android_alarm.h"
+-
+-#ifdef CONFIG_COMPAT
+-#define ANDROID_ALARM_SET_COMPAT(type)		ALARM_IOW(2, type, \
+-							struct compat_timespec)
+-#define ANDROID_ALARM_SET_AND_WAIT_COMPAT(type)	ALARM_IOW(3, type, \
+-							struct compat_timespec)
+-#define ANDROID_ALARM_GET_TIME_COMPAT(type)	ALARM_IOW(4, type, \
+-							struct compat_timespec)
+-#define ANDROID_ALARM_SET_RTC_COMPAT		_IOW('a', 5, \
+-							struct compat_timespec)
+-#define ANDROID_ALARM_IOCTL_NR(cmd)		(_IOC_NR(cmd) & ((1<<4)-1))
+-#define ANDROID_ALARM_COMPAT_TO_NORM(cmd)  \
+-				ALARM_IOW(ANDROID_ALARM_IOCTL_NR(cmd), \
+-					ANDROID_ALARM_IOCTL_TO_TYPE(cmd), \
+-					struct timespec)
+-
+-#endif
+-
+-#endif
+diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c
+index ad4f579..afee619 100644
+--- a/drivers/staging/android/ashmem.c
++++ b/drivers/staging/android/ashmem.c
+@@ -396,22 +396,14 @@ static int ashmem_mmap(struct file *file, struct vm_area_struct *vma)
+ 	}
+ 	get_file(asma->file);
+ 
+-	/*
+-	 * XXX - Reworked to use shmem_zero_setup() instead of
+-	 * shmem_set_file while we're in staging. -jstultz
+-	 */
+-	if (vma->vm_flags & VM_SHARED) {
+-		ret = shmem_zero_setup(vma);
+-		if (ret) {
+-			fput(asma->file);
+-			goto out;
+-		}
++	if (vma->vm_flags & VM_SHARED)
++		shmem_set_file(vma, asma->file);
++	else {
++		if (vma->vm_file)
++			fput(vma->vm_file);
++		vma->vm_file = asma->file;
+ 	}
+ 
+-	if (vma->vm_file)
+-		fput(vma->vm_file);
+-	vma->vm_file = asma->file;
+-
+ out:
+ 	mutex_unlock(&ashmem_mutex);
+ 	return ret;
+@@ -441,12 +433,14 @@ ashmem_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)
+ 	if (!(sc->gfp_mask & __GFP_FS))
+ 		return SHRINK_STOP;
+ 
+-	mutex_lock(&ashmem_mutex);
++	if (!mutex_trylock(&ashmem_mutex))
++		return -1;
++
+ 	list_for_each_entry_safe(range, next, &ashmem_lru_list, lru) {
+ 		loff_t start = range->pgstart * PAGE_SIZE;
+ 		loff_t end = (range->pgend + 1) * PAGE_SIZE;
+ 
+-		do_fallocate(range->asma->file,
++		range->asma->file->f_op->fallocate(range->asma->file,
+ 				FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
+ 				start, end - start);
+ 		range->purged = ASHMEM_WAS_PURGED;
+diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c
+index c69c40d..710393a 100644
+--- a/drivers/staging/android/binder.c
++++ b/drivers/staging/android/binder.c
+@@ -26,6 +26,7 @@
+ #include <linux/miscdevice.h>
+ #include <linux/mm.h>
+ #include <linux/module.h>
++#include <linux/rtmutex.h>
+ #include <linux/mutex.h>
+ #include <linux/nsproxy.h>
+ #include <linux/poll.h>
+@@ -37,11 +38,12 @@
+ #include <linux/vmalloc.h>
+ #include <linux/slab.h>
+ #include <linux/pid_namespace.h>
++#include <linux/security.h>
+ 
+ #include "binder.h"
+ #include "binder_trace.h"
+ 
+-static DEFINE_MUTEX(binder_main_lock);
++static DEFINE_RT_MUTEX(binder_main_lock);
+ static DEFINE_MUTEX(binder_deferred_lock);
+ static DEFINE_MUTEX(binder_mmap_lock);
+ 
+@@ -421,14 +423,14 @@ static long task_close_fd(struct binder_proc *proc, unsigned int fd)
+ static inline void binder_lock(const char *tag)
+ {
+ 	trace_binder_lock(tag);
+-	mutex_lock(&binder_main_lock);
++	rt_mutex_lock(&binder_main_lock);
+ 	trace_binder_locked(tag);
+ }
+ 
+ static inline void binder_unlock(const char *tag)
+ {
+ 	trace_binder_unlock(tag);
+-	mutex_unlock(&binder_main_lock);
++	rt_mutex_unlock(&binder_main_lock);
+ }
+ 
+ static void binder_set_nice(long nice)
+@@ -1316,6 +1318,7 @@ static void binder_transaction(struct binder_proc *proc,
+ 	struct binder_transaction *t;
+ 	struct binder_work *tcomplete;
+ 	binder_size_t *offp, *off_end;
++	binder_size_t off_min;
+ 	struct binder_proc *target_proc;
+ 	struct binder_thread *target_thread = NULL;
+ 	struct binder_node *target_node = NULL;
+@@ -1396,6 +1399,10 @@ static void binder_transaction(struct binder_proc *proc,
+ 			return_error = BR_DEAD_REPLY;
+ 			goto err_dead_binder;
+ 		}
++		if (security_binder_transaction(proc->tsk, target_proc->tsk) < 0) {
++			return_error = BR_FAILED_REPLY;
++			goto err_invalid_target_handle;
++		}
+ 		if (!(tr->flags & TF_ONE_WAY) && thread->transaction_stack) {
+ 			struct binder_transaction *tmp;
+ 
+@@ -1512,18 +1519,24 @@ static void binder_transaction(struct binder_proc *proc,
+ 		goto err_bad_offset;
+ 	}
+ 	off_end = (void *)offp + tr->offsets_size;
++	off_min = 0;
+ 	for (; offp < off_end; offp++) {
+ 		struct flat_binder_object *fp;
+ 
+ 		if (*offp > t->buffer->data_size - sizeof(*fp) ||
++		    *offp < off_min ||
+ 		    t->buffer->data_size < sizeof(*fp) ||
+ 		    !IS_ALIGNED(*offp, sizeof(u32))) {
+-			binder_user_error("%d:%d got transaction with invalid offset, %lld\n",
+-					  proc->pid, thread->pid, (u64)*offp);
++			binder_user_error("%d:%d got transaction with invalid offset, %lld (min %lld, max %lld)\n",
++					  proc->pid, thread->pid, (u64)*offp,
++					  (u64)off_min,
++					  (u64)(t->buffer->data_size -
++					  sizeof(*fp)));
+ 			return_error = BR_FAILED_REPLY;
+ 			goto err_bad_offset;
+ 		}
+ 		fp = (struct flat_binder_object *)(t->buffer->data + *offp);
++		off_min = *offp + sizeof(struct flat_binder_object);
+ 		switch (fp->type) {
+ 		case BINDER_TYPE_BINDER:
+ 		case BINDER_TYPE_WEAK_BINDER: {
+@@ -1547,6 +1560,10 @@ static void binder_transaction(struct binder_proc *proc,
+ 				return_error = BR_FAILED_REPLY;
+ 				goto err_binder_get_ref_for_node_failed;
+ 			}
++	if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) {
++				return_error = BR_FAILED_REPLY;
++				goto err_binder_get_ref_for_node_failed;
++			}
+ 			ref = binder_get_ref_for_node(target_proc, node);
+ 			if (ref == NULL) {
+ 				return_error = BR_FAILED_REPLY;
+@@ -1577,6 +1594,10 @@ static void binder_transaction(struct binder_proc *proc,
+ 				return_error = BR_FAILED_REPLY;
+ 				goto err_binder_get_ref_failed;
+ 			}
++			if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) {
++				return_error = BR_FAILED_REPLY;
++				goto err_binder_get_ref_failed;
++			}
+ 			if (ref->node->proc == target_proc) {
+ 				if (fp->type == BINDER_TYPE_HANDLE)
+ 					fp->type = BINDER_TYPE_BINDER;
+@@ -1634,6 +1655,11 @@ static void binder_transaction(struct binder_proc *proc,
+ 				return_error = BR_FAILED_REPLY;
+ 				goto err_fget_failed;
+ 			}
++			if (security_binder_transfer_file(proc->tsk, target_proc->tsk, file) < 0) {
++				fput(file);
++				return_error = BR_FAILED_REPLY;
++				goto err_get_unused_fd_failed;
++			}
+ 			target_fd = task_get_unused_fd_flags(target_proc, O_CLOEXEC);
+ 			if (target_fd < 0) {
+ 				fput(file);
+@@ -2736,6 +2762,9 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+ 		ret = binder_ioctl_set_ctx_mgr(filp);
+ 		if (ret)
+ 			goto err;
++		ret = security_binder_set_context_mgr(proc->tsk);
++		if (ret < 0)
++			goto err;
+ 		break;
+ 	case BINDER_THREAD_EXIT:
+ 		binder_debug(BINDER_DEBUG_THREADS, "%d:%d exit\n",
+diff --git a/drivers/staging/android/fiq_debugger/Kconfig b/drivers/staging/android/fiq_debugger/Kconfig
+new file mode 100644
+index 0000000..56f7f99
+--- /dev/null
++++ b/drivers/staging/android/fiq_debugger/Kconfig
+@@ -0,0 +1,49 @@
++config FIQ_DEBUGGER
++	bool "FIQ Mode Serial Debugger"
++	default n
++	depends on ARM || ARM64
++	help
++	  The FIQ serial debugger can accept commands even when the
++	  kernel is unresponsive due to being stuck with interrupts
++	  disabled.
++
++config FIQ_DEBUGGER_NO_SLEEP
++	bool "Keep serial debugger active"
++	depends on FIQ_DEBUGGER
++	default n
++	help
++	  Enables the serial debugger at boot. Passing
++	  fiq_debugger.no_sleep on the kernel commandline will
++	  override this config option.
++
++config FIQ_DEBUGGER_WAKEUP_IRQ_ALWAYS_ON
++	bool "Don't disable wakeup IRQ when debugger is active"
++	depends on FIQ_DEBUGGER
++	default n
++	help
++	  Don't disable the wakeup irq when enabling the uart clock.  This will
++	  cause extra interrupts, but it makes the serial debugger usable with
++	  on some MSM radio builds that ignore the uart clock request in power
++	  collapse.
++
++config FIQ_DEBUGGER_CONSOLE
++	bool "Console on FIQ Serial Debugger port"
++	depends on FIQ_DEBUGGER
++	default n
++	help
++	  Enables a console so that printk messages are displayed on
++	  the debugger serial port as the occur.
++
++config FIQ_DEBUGGER_CONSOLE_DEFAULT_ENABLE
++	bool "Put the FIQ debugger into console mode by default"
++	depends on FIQ_DEBUGGER_CONSOLE
++	default n
++	help
++	  If enabled, this puts the fiq debugger into console mode by default.
++	  Otherwise, the fiq debugger will start out in debug mode.
++
++config FIQ_WATCHDOG
++	bool
++	select FIQ_DEBUGGER
++	select PSTORE_RAM
++	default n
+diff --git a/drivers/staging/android/fiq_debugger/Makefile b/drivers/staging/android/fiq_debugger/Makefile
+new file mode 100644
+index 0000000..a7ca487
+--- /dev/null
++++ b/drivers/staging/android/fiq_debugger/Makefile
+@@ -0,0 +1,4 @@
++obj-y			+= fiq_debugger.o
++obj-$(CONFIG_ARM)	+= fiq_debugger_arm.o
++obj-$(CONFIG_ARM64)	+= fiq_debugger_arm64.o
++obj-$(CONFIG_FIQ_WATCHDOG)	+= fiq_watchdog.o
+diff --git a/drivers/staging/android/fiq_debugger/fiq_debugger.c b/drivers/staging/android/fiq_debugger/fiq_debugger.c
+new file mode 100644
+index 0000000..52f6816
+--- /dev/null
++++ b/drivers/staging/android/fiq_debugger/fiq_debugger.c
+@@ -0,0 +1,1212 @@
++/*
++ * drivers/staging/android/fiq_debugger.c
++ *
++ * Serial Debugger Interface accessed through an FIQ interrupt.
++ *
++ * Copyright (C) 2008 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#include <stdarg.h>
++#include <linux/module.h>
++#include <linux/io.h>
++#include <linux/console.h>
++#include <linux/interrupt.h>
++#include <linux/clk.h>
++#include <linux/platform_device.h>
++#include <linux/kernel_stat.h>
++#include <linux/kmsg_dump.h>
++#include <linux/irq.h>
++#include <linux/delay.h>
++#include <linux/reboot.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/smp.h>
++#include <linux/timer.h>
++#include <linux/tty.h>
++#include <linux/tty_flip.h>
++#include <linux/wakelock.h>
++
++#ifdef CONFIG_FIQ_GLUE
++#include <asm/fiq_glue.h>
++#endif
++
++#include <linux/uaccess.h>
++
++#include "fiq_debugger.h"
++#include "fiq_debugger_priv.h"
++#include "fiq_debugger_ringbuf.h"
++
++#define DEBUG_MAX 64
++#define MAX_UNHANDLED_FIQ_COUNT 1000000
++
++#define MAX_FIQ_DEBUGGER_PORTS 4
++
++struct fiq_debugger_state {
++#ifdef CONFIG_FIQ_GLUE
++	struct fiq_glue_handler handler;
++#endif
++	struct fiq_debugger_output output;
++
++	int fiq;
++	int uart_irq;
++	int signal_irq;
++	int wakeup_irq;
++	bool wakeup_irq_no_set_wake;
++	struct clk *clk;
++	struct fiq_debugger_pdata *pdata;
++	struct platform_device *pdev;
++
++	char debug_cmd[DEBUG_MAX];
++	int debug_busy;
++	int debug_abort;
++
++	char debug_buf[DEBUG_MAX];
++	int debug_count;
++
++	bool no_sleep;
++	bool debug_enable;
++	bool ignore_next_wakeup_irq;
++	struct timer_list sleep_timer;
++	spinlock_t sleep_timer_lock;
++	bool uart_enabled;
++	struct wake_lock debugger_wake_lock;
++	bool console_enable;
++	int current_cpu;
++	atomic_t unhandled_fiq_count;
++	bool in_fiq;
++
++	struct work_struct work;
++	spinlock_t work_lock;
++	char work_cmd[DEBUG_MAX];
++
++#ifdef CONFIG_FIQ_DEBUGGER_CONSOLE
++	spinlock_t console_lock;
++	struct console console;
++	struct tty_port tty_port;
++	struct fiq_debugger_ringbuf *tty_rbuf;
++	bool syslog_dumping;
++#endif
++
++	unsigned int last_irqs[NR_IRQS];
++	unsigned int last_local_timer_irqs[NR_CPUS];
++};
++
++#ifdef CONFIG_FIQ_DEBUGGER_CONSOLE
++struct tty_driver *fiq_tty_driver;
++#endif
++
++#ifdef CONFIG_FIQ_DEBUGGER_NO_SLEEP
++static bool initial_no_sleep = true;
++#else
++static bool initial_no_sleep;
++#endif
++
++#ifdef CONFIG_FIQ_DEBUGGER_CONSOLE_DEFAULT_ENABLE
++static bool initial_debug_enable = true;
++static bool initial_console_enable = true;
++#else
++static bool initial_debug_enable;
++static bool initial_console_enable;
++#endif
++
++static bool fiq_kgdb_enable;
++
++module_param_named(no_sleep, initial_no_sleep, bool, 0644);
++module_param_named(debug_enable, initial_debug_enable, bool, 0644);
++module_param_named(console_enable, initial_console_enable, bool, 0644);
++module_param_named(kgdb_enable, fiq_kgdb_enable, bool, 0644);
++
++#ifdef CONFIG_FIQ_DEBUGGER_WAKEUP_IRQ_ALWAYS_ON
++static inline
++void fiq_debugger_enable_wakeup_irq(struct fiq_debugger_state *state) {}
++static inline
++void fiq_debugger_disable_wakeup_irq(struct fiq_debugger_state *state) {}
++#else
++static inline
++void fiq_debugger_enable_wakeup_irq(struct fiq_debugger_state *state)
++{
++	if (state->wakeup_irq < 0)
++		return;
++	enable_irq(state->wakeup_irq);
++	if (!state->wakeup_irq_no_set_wake)
++		enable_irq_wake(state->wakeup_irq);
++}
++static inline
++void fiq_debugger_disable_wakeup_irq(struct fiq_debugger_state *state)
++{
++	if (state->wakeup_irq < 0)
++		return;
++	disable_irq_nosync(state->wakeup_irq);
++	if (!state->wakeup_irq_no_set_wake)
++		disable_irq_wake(state->wakeup_irq);
++}
++#endif
++
++static inline bool fiq_debugger_have_fiq(struct fiq_debugger_state *state)
++{
++	return (state->fiq >= 0);
++}
++
++#ifdef CONFIG_FIQ_GLUE
++static void fiq_debugger_force_irq(struct fiq_debugger_state *state)
++{
++	unsigned int irq = state->signal_irq;
++
++	if (WARN_ON(!fiq_debugger_have_fiq(state)))
++		return;
++	if (state->pdata->force_irq) {
++		state->pdata->force_irq(state->pdev, irq);
++	} else {
++		struct irq_chip *chip = irq_get_chip(irq);
++		if (chip && chip->irq_retrigger)
++			chip->irq_retrigger(irq_get_irq_data(irq));
++	}
++}
++#endif
++
++static void fiq_debugger_uart_enable(struct fiq_debugger_state *state)
++{
++	if (state->clk)
++		clk_enable(state->clk);
++	if (state->pdata->uart_enable)
++		state->pdata->uart_enable(state->pdev);
++}
++
++static void fiq_debugger_uart_disable(struct fiq_debugger_state *state)
++{
++	if (state->pdata->uart_disable)
++		state->pdata->uart_disable(state->pdev);
++	if (state->clk)
++		clk_disable(state->clk);
++}
++
++static void fiq_debugger_uart_flush(struct fiq_debugger_state *state)
++{
++	if (state->pdata->uart_flush)
++		state->pdata->uart_flush(state->pdev);
++}
++
++static void fiq_debugger_putc(struct fiq_debugger_state *state, char c)
++{
++	state->pdata->uart_putc(state->pdev, c);
++}
++
++static void fiq_debugger_puts(struct fiq_debugger_state *state, char *s)
++{
++	unsigned c;
++	while ((c = *s++)) {
++		if (c == '\n')
++			fiq_debugger_putc(state, '\r');
++		fiq_debugger_putc(state, c);
++	}
++}
++
++static void fiq_debugger_prompt(struct fiq_debugger_state *state)
++{
++	fiq_debugger_puts(state, "debug> ");
++}
++
++static void fiq_debugger_dump_kernel_log(struct fiq_debugger_state *state)
++{
++	char buf[512];
++	size_t len;
++	struct kmsg_dumper dumper = { .active = true };
++
++
++	kmsg_dump_rewind_nolock(&dumper);
++	while (kmsg_dump_get_line_nolock(&dumper, true, buf,
++					 sizeof(buf) - 1, &len)) {
++		buf[len] = 0;
++		fiq_debugger_puts(state, buf);
++	}
++}
++
++static void fiq_debugger_printf(struct fiq_debugger_output *output,
++			       const char *fmt, ...)
++{
++	struct fiq_debugger_state *state;
++	char buf[256];
++	va_list ap;
++
++	state = container_of(output, struct fiq_debugger_state, output);
++	va_start(ap, fmt);
++	vsnprintf(buf, sizeof(buf), fmt, ap);
++	va_end(ap);
++
++	fiq_debugger_puts(state, buf);
++}
++
++/* Safe outside fiq context */
++static int fiq_debugger_printf_nfiq(void *cookie, const char *fmt, ...)
++{
++	struct fiq_debugger_state *state = cookie;
++	char buf[256];
++	va_list ap;
++	unsigned long irq_flags;
++
++	va_start(ap, fmt);
++	vsnprintf(buf, 128, fmt, ap);
++	va_end(ap);
++
++	local_irq_save(irq_flags);
++	fiq_debugger_puts(state, buf);
++	fiq_debugger_uart_flush(state);
++	local_irq_restore(irq_flags);
++	return state->debug_abort;
++}
++
++static void fiq_debugger_dump_irqs(struct fiq_debugger_state *state)
++{
++	int n;
++	struct irq_desc *desc;
++
++	fiq_debugger_printf(&state->output,
++			"irqnr       total  since-last   status  name\n");
++	for_each_irq_desc(n, desc) {
++		struct irqaction *act = desc->action;
++		if (!act && !kstat_irqs(n))
++			continue;
++		fiq_debugger_printf(&state->output, "%5d: %10u %11u %8x  %s\n", n,
++			kstat_irqs(n),
++			kstat_irqs(n) - state->last_irqs[n],
++			desc->status_use_accessors,
++			(act && act->name) ? act->name : "???");
++		state->last_irqs[n] = kstat_irqs(n);
++	}
++}
++
++static void fiq_debugger_do_ps(struct fiq_debugger_state *state)
++{
++	struct task_struct *g;
++	struct task_struct *p;
++	unsigned task_state;
++	static const char stat_nam[] = "RSDTtZX";
++
++	fiq_debugger_printf(&state->output, "pid   ppid  prio task            pc\n");
++	read_lock(&tasklist_lock);
++	do_each_thread(g, p) {
++		task_state = p->state ? __ffs(p->state) + 1 : 0;
++		fiq_debugger_printf(&state->output,
++			     "%5d %5d %4d ", p->pid, p->parent->pid, p->prio);
++		fiq_debugger_printf(&state->output, "%-13.13s %c", p->comm,
++			     task_state >= sizeof(stat_nam) ? '?' : stat_nam[task_state]);
++		if (task_state == TASK_RUNNING)
++			fiq_debugger_printf(&state->output, " running\n");
++		else
++			fiq_debugger_printf(&state->output, " %08lx\n",
++					thread_saved_pc(p));
++	} while_each_thread(g, p);
++	read_unlock(&tasklist_lock);
++}
++
++#ifdef CONFIG_FIQ_DEBUGGER_CONSOLE
++static void fiq_debugger_begin_syslog_dump(struct fiq_debugger_state *state)
++{
++	state->syslog_dumping = true;
++}
++
++static void fiq_debugger_end_syslog_dump(struct fiq_debugger_state *state)
++{
++	state->syslog_dumping = false;
++}
++#else
++extern int do_syslog(int type, char __user *bug, int count);
++static void fiq_debugger_begin_syslog_dump(struct fiq_debugger_state *state)
++{
++	do_syslog(5 /* clear */, NULL, 0);
++}
++
++static void fiq_debugger_end_syslog_dump(struct fiq_debugger_state *state)
++{
++	fiq_debugger_dump_kernel_log(state);
++}
++#endif
++
++static void fiq_debugger_do_sysrq(struct fiq_debugger_state *state, char rq)
++{
++	if ((rq == 'g' || rq == 'G') && !fiq_kgdb_enable) {
++		fiq_debugger_printf(&state->output, "sysrq-g blocked\n");
++		return;
++	}
++	fiq_debugger_begin_syslog_dump(state);
++	handle_sysrq(rq);
++	fiq_debugger_end_syslog_dump(state);
++}
++
++#ifdef CONFIG_KGDB
++static void fiq_debugger_do_kgdb(struct fiq_debugger_state *state)
++{
++	if (!fiq_kgdb_enable) {
++		fiq_debugger_printf(&state->output, "kgdb through fiq debugger not enabled\n");
++		return;
++	}
++
++	fiq_debugger_printf(&state->output, "enabling console and triggering kgdb\n");
++	state->console_enable = true;
++	handle_sysrq('g');
++}
++#endif
++
++static void fiq_debugger_schedule_work(struct fiq_debugger_state *state,
++		char *cmd)
++{
++	unsigned long flags;
++
++	spin_lock_irqsave(&state->work_lock, flags);
++	if (state->work_cmd[0] != '\0') {
++		fiq_debugger_printf(&state->output, "work command processor busy\n");
++		spin_unlock_irqrestore(&state->work_lock, flags);
++		return;
++	}
++
++	strlcpy(state->work_cmd, cmd, sizeof(state->work_cmd));
++	spin_unlock_irqrestore(&state->work_lock, flags);
++
++	schedule_work(&state->work);
++}
++
++static void fiq_debugger_work(struct work_struct *work)
++{
++	struct fiq_debugger_state *state;
++	char work_cmd[DEBUG_MAX];
++	char *cmd;
++	unsigned long flags;
++
++	state = container_of(work, struct fiq_debugger_state, work);
++
++	spin_lock_irqsave(&state->work_lock, flags);
++
++	strlcpy(work_cmd, state->work_cmd, sizeof(work_cmd));
++	state->work_cmd[0] = '\0';
++
++	spin_unlock_irqrestore(&state->work_lock, flags);
++
++	cmd = work_cmd;
++	if (!strncmp(cmd, "reboot", 6)) {
++		cmd += 6;
++		while (*cmd == ' ')
++			cmd++;
++		if (cmd != '\0')
++			kernel_restart(cmd);
++		else
++			kernel_restart(NULL);
++	} else {
++		fiq_debugger_printf(&state->output, "unknown work command '%s'\n",
++				work_cmd);
++	}
++}
++
++/* This function CANNOT be called in FIQ context */
++static void fiq_debugger_irq_exec(struct fiq_debugger_state *state, char *cmd)
++{
++	if (!strcmp(cmd, "ps"))
++		fiq_debugger_do_ps(state);
++	if (!strcmp(cmd, "sysrq"))
++		fiq_debugger_do_sysrq(state, 'h');
++	if (!strncmp(cmd, "sysrq ", 6))
++		fiq_debugger_do_sysrq(state, cmd[6]);
++#ifdef CONFIG_KGDB
++	if (!strcmp(cmd, "kgdb"))
++		fiq_debugger_do_kgdb(state);
++#endif
++	if (!strncmp(cmd, "reboot", 6))
++		fiq_debugger_schedule_work(state, cmd);
++}
++
++static void fiq_debugger_help(struct fiq_debugger_state *state)
++{
++	fiq_debugger_printf(&state->output,
++				"FIQ Debugger commands:\n"
++				" pc            PC status\n"
++				" regs          Register dump\n"
++				" allregs       Extended Register dump\n"
++				" bt            Stack trace\n"
++				" reboot [<c>]  Reboot with command <c>\n"
++				" reset [<c>]   Hard reset with command <c>\n"
++				" irqs          Interupt status\n"
++				" kmsg          Kernel log\n"
++				" version       Kernel version\n");
++	fiq_debugger_printf(&state->output,
++				" sleep         Allow sleep while in FIQ\n"
++				" nosleep       Disable sleep while in FIQ\n"
++				" console       Switch terminal to console\n"
++				" cpu           Current CPU\n"
++				" cpu <number>  Switch to CPU<number>\n");
++	fiq_debugger_printf(&state->output,
++				" ps            Process list\n"
++				" sysrq         sysrq options\n"
++				" sysrq <param> Execute sysrq with <param>\n");
++#ifdef CONFIG_KGDB
++	fiq_debugger_printf(&state->output,
++				" kgdb          Enter kernel debugger\n");
++#endif
++}
++
++static void fiq_debugger_take_affinity(void *info)
++{
++	struct fiq_debugger_state *state = info;
++	struct cpumask cpumask;
++
++	cpumask_clear(&cpumask);
++	cpumask_set_cpu(get_cpu(), &cpumask);
++
++	irq_set_affinity(state->uart_irq, &cpumask);
++}
++
++static void fiq_debugger_switch_cpu(struct fiq_debugger_state *state, int cpu)
++{
++	if (!fiq_debugger_have_fiq(state))
++		smp_call_function_single(cpu, fiq_debugger_take_affinity, state,
++				false);
++	state->current_cpu = cpu;
++}
++
++static bool fiq_debugger_fiq_exec(struct fiq_debugger_state *state,
++			const char *cmd, const struct pt_regs *regs,
++			void *svc_sp)
++{
++	bool signal_helper = false;
++
++	if (!strcmp(cmd, "help") || !strcmp(cmd, "?")) {
++		fiq_debugger_help(state);
++	} else if (!strcmp(cmd, "pc")) {
++		fiq_debugger_dump_pc(&state->output, regs);
++	} else if (!strcmp(cmd, "regs")) {
++		fiq_debugger_dump_regs(&state->output, regs);
++	} else if (!strcmp(cmd, "allregs")) {
++		fiq_debugger_dump_allregs(&state->output, regs);
++	} else if (!strcmp(cmd, "bt")) {
++		fiq_debugger_dump_stacktrace(&state->output, regs, 100, svc_sp);
++	} else if (!strncmp(cmd, "reset", 5)) {
++		cmd += 5;
++		while (*cmd == ' ')
++			cmd++;
++		if (*cmd) {
++			char tmp_cmd[32];
++			strlcpy(tmp_cmd, cmd, sizeof(tmp_cmd));
++			machine_restart(tmp_cmd);
++		} else {
++			machine_restart(NULL);
++		}
++	} else if (!strcmp(cmd, "irqs")) {
++		fiq_debugger_dump_irqs(state);
++	} else if (!strcmp(cmd, "kmsg")) {
++		fiq_debugger_dump_kernel_log(state);
++	} else if (!strcmp(cmd, "version")) {
++		fiq_debugger_printf(&state->output, "%s\n", linux_banner);
++	} else if (!strcmp(cmd, "sleep")) {
++		state->no_sleep = false;
++		fiq_debugger_printf(&state->output, "enabling sleep\n");
++	} else if (!strcmp(cmd, "nosleep")) {
++		state->no_sleep = true;
++		fiq_debugger_printf(&state->output, "disabling sleep\n");
++	} else if (!strcmp(cmd, "console")) {
++		fiq_debugger_printf(&state->output, "console mode\n");
++		fiq_debugger_uart_flush(state);
++		state->console_enable = true;
++	} else if (!strcmp(cmd, "cpu")) {
++		fiq_debugger_printf(&state->output, "cpu %d\n", state->current_cpu);
++	} else if (!strncmp(cmd, "cpu ", 4)) {
++		unsigned long cpu = 0;
++		if (kstrtoul(cmd + 4, 10, &cpu) == 0)
++			fiq_debugger_switch_cpu(state, cpu);
++		else
++			fiq_debugger_printf(&state->output, "invalid cpu\n");
++		fiq_debugger_printf(&state->output, "cpu %d\n", state->current_cpu);
++	} else {
++		if (state->debug_busy) {
++			fiq_debugger_printf(&state->output,
++				"command processor busy. trying to abort.\n");
++			state->debug_abort = -1;
++		} else {
++			strcpy(state->debug_cmd, cmd);
++			state->debug_busy = 1;
++		}
++
++		return true;
++	}
++	if (!state->console_enable)
++		fiq_debugger_prompt(state);
++
++	return signal_helper;
++}
++
++static void fiq_debugger_sleep_timer_expired(unsigned long data)
++{
++	struct fiq_debugger_state *state = (struct fiq_debugger_state *)data;
++	unsigned long flags;
++
++	spin_lock_irqsave(&state->sleep_timer_lock, flags);
++	if (state->uart_enabled && !state->no_sleep) {
++		if (state->debug_enable && !state->console_enable) {
++			state->debug_enable = false;
++			fiq_debugger_printf_nfiq(state,
++					"suspending fiq debugger\n");
++		}
++		state->ignore_next_wakeup_irq = true;
++		fiq_debugger_uart_disable(state);
++		state->uart_enabled = false;
++		fiq_debugger_enable_wakeup_irq(state);
++	}
++	wake_unlock(&state->debugger_wake_lock);
++	spin_unlock_irqrestore(&state->sleep_timer_lock, flags);
++}
++
++static void fiq_debugger_handle_wakeup(struct fiq_debugger_state *state)
++{
++	unsigned long flags;
++
++	spin_lock_irqsave(&state->sleep_timer_lock, flags);
++	if (state->wakeup_irq >= 0 && state->ignore_next_wakeup_irq) {
++		state->ignore_next_wakeup_irq = false;
++	} else if (!state->uart_enabled) {
++		wake_lock(&state->debugger_wake_lock);
++		fiq_debugger_uart_enable(state);
++		state->uart_enabled = true;
++		fiq_debugger_disable_wakeup_irq(state);
++		mod_timer(&state->sleep_timer, jiffies + HZ / 2);
++	}
++	spin_unlock_irqrestore(&state->sleep_timer_lock, flags);
++}
++
++static irqreturn_t fiq_debugger_wakeup_irq_handler(int irq, void *dev)
++{
++	struct fiq_debugger_state *state = dev;
++
++	if (!state->no_sleep)
++		fiq_debugger_puts(state, "WAKEUP\n");
++	fiq_debugger_handle_wakeup(state);
++
++	return IRQ_HANDLED;
++}
++
++static
++void fiq_debugger_handle_console_irq_context(struct fiq_debugger_state *state)
++{
++#if defined(CONFIG_FIQ_DEBUGGER_CONSOLE)
++	if (state->tty_port.ops) {
++		int i;
++		int count = fiq_debugger_ringbuf_level(state->tty_rbuf);
++		for (i = 0; i < count; i++) {
++			int c = fiq_debugger_ringbuf_peek(state->tty_rbuf, 0);
++			tty_insert_flip_char(&state->tty_port, c, TTY_NORMAL);
++			if (!fiq_debugger_ringbuf_consume(state->tty_rbuf, 1))
++				pr_warn("fiq tty failed to consume byte\n");
++		}
++		tty_flip_buffer_push(&state->tty_port);
++	}
++#endif
++}
++
++static void fiq_debugger_handle_irq_context(struct fiq_debugger_state *state)
++{
++	if (!state->no_sleep) {
++		unsigned long flags;
++
++		spin_lock_irqsave(&state->sleep_timer_lock, flags);
++		wake_lock(&state->debugger_wake_lock);
++		mod_timer(&state->sleep_timer, jiffies + HZ * 5);
++		spin_unlock_irqrestore(&state->sleep_timer_lock, flags);
++	}
++	fiq_debugger_handle_console_irq_context(state);
++	if (state->debug_busy) {
++		fiq_debugger_irq_exec(state, state->debug_cmd);
++		if (!state->console_enable)
++			fiq_debugger_prompt(state);
++		state->debug_busy = 0;
++	}
++}
++
++static int fiq_debugger_getc(struct fiq_debugger_state *state)
++{
++	return state->pdata->uart_getc(state->pdev);
++}
++
++static bool fiq_debugger_handle_uart_interrupt(struct fiq_debugger_state *state,
++			int this_cpu, const struct pt_regs *regs, void *svc_sp)
++{
++	int c;
++	static int last_c;
++	int count = 0;
++	bool signal_helper = false;
++
++	if (this_cpu != state->current_cpu) {
++		if (state->in_fiq)
++			return false;
++
++		if (atomic_inc_return(&state->unhandled_fiq_count) !=
++					MAX_UNHANDLED_FIQ_COUNT)
++			return false;
++
++		fiq_debugger_printf(&state->output,
++			"fiq_debugger: cpu %d not responding, "
++			"reverting to cpu %d\n", state->current_cpu,
++			this_cpu);
++
++		atomic_set(&state->unhandled_fiq_count, 0);
++		fiq_debugger_switch_cpu(state, this_cpu);
++		return false;
++	}
++
++	state->in_fiq = true;
++
++	while ((c = fiq_debugger_getc(state)) != FIQ_DEBUGGER_NO_CHAR) {
++		count++;
++		if (!state->debug_enable) {
++			if ((c == 13) || (c == 10)) {
++				state->debug_enable = true;
++				state->debug_count = 0;
++				fiq_debugger_prompt(state);
++			}
++		} else if (c == FIQ_DEBUGGER_BREAK) {
++			state->console_enable = false;
++			fiq_debugger_puts(state, "fiq debugger mode\n");
++			state->debug_count = 0;
++			fiq_debugger_prompt(state);
++#ifdef CONFIG_FIQ_DEBUGGER_CONSOLE
++		} else if (state->console_enable && state->tty_rbuf) {
++			fiq_debugger_ringbuf_push(state->tty_rbuf, c);
++			signal_helper = true;
++#endif
++		} else if ((c >= ' ') && (c < 127)) {
++			if (state->debug_count < (DEBUG_MAX - 1)) {
++				state->debug_buf[state->debug_count++] = c;
++				fiq_debugger_putc(state, c);
++			}
++		} else if ((c == 8) || (c == 127)) {
++			if (state->debug_count > 0) {
++				state->debug_count--;
++				fiq_debugger_putc(state, 8);
++				fiq_debugger_putc(state, ' ');
++				fiq_debugger_putc(state, 8);
++			}
++		} else if ((c == 13) || (c == 10)) {
++			if (c == '\r' || (c == '\n' && last_c != '\r')) {
++				fiq_debugger_putc(state, '\r');
++				fiq_debugger_putc(state, '\n');
++			}
++			if (state->debug_count) {
++				state->debug_buf[state->debug_count] = 0;
++				state->debug_count = 0;
++				signal_helper |=
++					fiq_debugger_fiq_exec(state,
++							state->debug_buf,
++							regs, svc_sp);
++			} else {
++				fiq_debugger_prompt(state);
++			}
++		}
++		last_c = c;
++	}
++	if (!state->console_enable)
++		fiq_debugger_uart_flush(state);
++	if (state->pdata->fiq_ack)
++		state->pdata->fiq_ack(state->pdev, state->fiq);
++
++	/* poke sleep timer if necessary */
++	if (state->debug_enable && !state->no_sleep)
++		signal_helper = true;
++
++	atomic_set(&state->unhandled_fiq_count, 0);
++	state->in_fiq = false;
++
++	return signal_helper;
++}
++
++#ifdef CONFIG_FIQ_GLUE
++static void fiq_debugger_fiq(struct fiq_glue_handler *h,
++		const struct pt_regs *regs, void *svc_sp)
++{
++	struct fiq_debugger_state *state =
++		container_of(h, struct fiq_debugger_state, handler);
++	unsigned int this_cpu = THREAD_INFO(svc_sp)->cpu;
++	bool need_irq;
++
++	need_irq = fiq_debugger_handle_uart_interrupt(state, this_cpu, regs,
++			svc_sp);
++	if (need_irq)
++		fiq_debugger_force_irq(state);
++}
++#endif
++
++/*
++ * When not using FIQs, we only use this single interrupt as an entry point.
++ * This just effectively takes over the UART interrupt and does all the work
++ * in this context.
++ */
++static irqreturn_t fiq_debugger_uart_irq(int irq, void *dev)
++{
++	struct fiq_debugger_state *state = dev;
++	bool not_done;
++
++	fiq_debugger_handle_wakeup(state);
++
++	/* handle the debugger irq in regular context */
++	not_done = fiq_debugger_handle_uart_interrupt(state, smp_processor_id(),
++					      get_irq_regs(),
++					      current_thread_info());
++	if (not_done)
++		fiq_debugger_handle_irq_context(state);
++
++	return IRQ_HANDLED;
++}
++
++/*
++ * If FIQs are used, not everything can happen in fiq context.
++ * FIQ handler does what it can and then signals this interrupt to finish the
++ * job in irq context.
++ */
++static irqreturn_t fiq_debugger_signal_irq(int irq, void *dev)
++{
++	struct fiq_debugger_state *state = dev;
++
++	if (state->pdata->force_irq_ack)
++		state->pdata->force_irq_ack(state->pdev, state->signal_irq);
++
++	fiq_debugger_handle_irq_context(state);
++
++	return IRQ_HANDLED;
++}
++
++#ifdef CONFIG_FIQ_GLUE
++static void fiq_debugger_resume(struct fiq_glue_handler *h)
++{
++	struct fiq_debugger_state *state =
++		container_of(h, struct fiq_debugger_state, handler);
++	if (state->pdata->uart_resume)
++		state->pdata->uart_resume(state->pdev);
++}
++#endif
++
++#if defined(CONFIG_FIQ_DEBUGGER_CONSOLE)
++struct tty_driver *fiq_debugger_console_device(struct console *co, int *index)
++{
++	*index = co->index;
++	return fiq_tty_driver;
++}
++
++static void fiq_debugger_console_write(struct console *co,
++				const char *s, unsigned int count)
++{
++	struct fiq_debugger_state *state;
++	unsigned long flags;
++
++	state = container_of(co, struct fiq_debugger_state, console);
++
++	if (!state->console_enable && !state->syslog_dumping)
++		return;
++
++	fiq_debugger_uart_enable(state);
++	spin_lock_irqsave(&state->console_lock, flags);
++	while (count--) {
++		if (*s == '\n')
++			fiq_debugger_putc(state, '\r');
++		fiq_debugger_putc(state, *s++);
++	}
++	fiq_debugger_uart_flush(state);
++	spin_unlock_irqrestore(&state->console_lock, flags);
++	fiq_debugger_uart_disable(state);
++}
++
++static struct console fiq_debugger_console = {
++	.name = "ttyFIQ",
++	.device = fiq_debugger_console_device,
++	.write = fiq_debugger_console_write,
++	.flags = CON_PRINTBUFFER | CON_ANYTIME | CON_ENABLED,
++};
++
++int fiq_tty_open(struct tty_struct *tty, struct file *filp)
++{
++	int line = tty->index;
++	struct fiq_debugger_state **states = tty->driver->driver_state;
++	struct fiq_debugger_state *state = states[line];
++
++	return tty_port_open(&state->tty_port, tty, filp);
++}
++
++void fiq_tty_close(struct tty_struct *tty, struct file *filp)
++{
++	tty_port_close(tty->port, tty, filp);
++}
++
++int  fiq_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
++{
++	int i;
++	int line = tty->index;
++	struct fiq_debugger_state **states = tty->driver->driver_state;
++	struct fiq_debugger_state *state = states[line];
++
++	if (!state->console_enable)
++		return count;
++
++	fiq_debugger_uart_enable(state);
++	spin_lock_irq(&state->console_lock);
++	for (i = 0; i < count; i++)
++		fiq_debugger_putc(state, *buf++);
++	spin_unlock_irq(&state->console_lock);
++	fiq_debugger_uart_disable(state);
++
++	return count;
++}
++
++int  fiq_tty_write_room(struct tty_struct *tty)
++{
++	return 16;
++}
++
++#ifdef CONFIG_CONSOLE_POLL
++static int fiq_tty_poll_init(struct tty_driver *driver, int line, char *options)
++{
++	return 0;
++}
++
++static int fiq_tty_poll_get_char(struct tty_driver *driver, int line)
++{
++	struct fiq_debugger_state **states = driver->driver_state;
++	struct fiq_debugger_state *state = states[line];
++	int c = NO_POLL_CHAR;
++
++	fiq_debugger_uart_enable(state);
++	if (fiq_debugger_have_fiq(state)) {
++		int count = fiq_debugger_ringbuf_level(state->tty_rbuf);
++		if (count > 0) {
++			c = fiq_debugger_ringbuf_peek(state->tty_rbuf, 0);
++			fiq_debugger_ringbuf_consume(state->tty_rbuf, 1);
++		}
++	} else {
++		c = fiq_debugger_getc(state);
++		if (c == FIQ_DEBUGGER_NO_CHAR)
++			c = NO_POLL_CHAR;
++	}
++	fiq_debugger_uart_disable(state);
++
++	return c;
++}
++
++static void fiq_tty_poll_put_char(struct tty_driver *driver, int line, char ch)
++{
++	struct fiq_debugger_state **states = driver->driver_state;
++	struct fiq_debugger_state *state = states[line];
++	fiq_debugger_uart_enable(state);
++	fiq_debugger_putc(state, ch);
++	fiq_debugger_uart_disable(state);
++}
++#endif
++
++static const struct tty_port_operations fiq_tty_port_ops;
++
++static const struct tty_operations fiq_tty_driver_ops = {
++	.write = fiq_tty_write,
++	.write_room = fiq_tty_write_room,
++	.open = fiq_tty_open,
++	.close = fiq_tty_close,
++#ifdef CONFIG_CONSOLE_POLL
++	.poll_init = fiq_tty_poll_init,
++	.poll_get_char = fiq_tty_poll_get_char,
++	.poll_put_char = fiq_tty_poll_put_char,
++#endif
++};
++
++static int fiq_debugger_tty_init(void)
++{
++	int ret;
++	struct fiq_debugger_state **states = NULL;
++
++	states = kzalloc(sizeof(*states) * MAX_FIQ_DEBUGGER_PORTS, GFP_KERNEL);
++	if (!states) {
++		pr_err("Failed to allocate fiq debugger state structres\n");
++		return -ENOMEM;
++	}
++
++	fiq_tty_driver = alloc_tty_driver(MAX_FIQ_DEBUGGER_PORTS);
++	if (!fiq_tty_driver) {
++		pr_err("Failed to allocate fiq debugger tty\n");
++		ret = -ENOMEM;
++		goto err_free_state;
++	}
++
++	fiq_tty_driver->owner		= THIS_MODULE;
++	fiq_tty_driver->driver_name	= "fiq-debugger";
++	fiq_tty_driver->name		= "ttyFIQ";
++	fiq_tty_driver->type		= TTY_DRIVER_TYPE_SERIAL;
++	fiq_tty_driver->subtype		= SERIAL_TYPE_NORMAL;
++	fiq_tty_driver->init_termios	= tty_std_termios;
++	fiq_tty_driver->flags		= TTY_DRIVER_REAL_RAW |
++					  TTY_DRIVER_DYNAMIC_DEV;
++	fiq_tty_driver->driver_state	= states;
++
++	fiq_tty_driver->init_termios.c_cflag =
++					B115200 | CS8 | CREAD | HUPCL | CLOCAL;
++	fiq_tty_driver->init_termios.c_ispeed = 115200;
++	fiq_tty_driver->init_termios.c_ospeed = 115200;
++
++	tty_set_operations(fiq_tty_driver, &fiq_tty_driver_ops);
++
++	ret = tty_register_driver(fiq_tty_driver);
++	if (ret) {
++		pr_err("Failed to register fiq tty: %d\n", ret);
++		goto err_free_tty;
++	}
++
++	pr_info("Registered FIQ tty driver\n");
++	return 0;
++
++err_free_tty:
++	put_tty_driver(fiq_tty_driver);
++	fiq_tty_driver = NULL;
++err_free_state:
++	kfree(states);
++	return ret;
++}
++
++static int fiq_debugger_tty_init_one(struct fiq_debugger_state *state)
++{
++	int ret;
++	struct device *tty_dev;
++	struct fiq_debugger_state **states = fiq_tty_driver->driver_state;
++
++	states[state->pdev->id] = state;
++
++	state->tty_rbuf = fiq_debugger_ringbuf_alloc(1024);
++	if (!state->tty_rbuf) {
++		pr_err("Failed to allocate fiq debugger ringbuf\n");
++		ret = -ENOMEM;
++		goto err;
++	}
++
++	tty_port_init(&state->tty_port);
++	state->tty_port.ops = &fiq_tty_port_ops;
++
++	tty_dev = tty_port_register_device(&state->tty_port, fiq_tty_driver,
++					   state->pdev->id, &state->pdev->dev);
++	if (IS_ERR(tty_dev)) {
++		pr_err("Failed to register fiq debugger tty device\n");
++		ret = PTR_ERR(tty_dev);
++		goto err;
++	}
++
++	device_set_wakeup_capable(tty_dev, 1);
++
++	pr_info("Registered fiq debugger ttyFIQ%d\n", state->pdev->id);
++
++	return 0;
++
++err:
++	fiq_debugger_ringbuf_free(state->tty_rbuf);
++	state->tty_rbuf = NULL;
++	return ret;
++}
++#endif
++
++static int fiq_debugger_dev_suspend(struct device *dev)
++{
++	struct platform_device *pdev = to_platform_device(dev);
++	struct fiq_debugger_state *state = platform_get_drvdata(pdev);
++
++	if (state->pdata->uart_dev_suspend)
++		return state->pdata->uart_dev_suspend(pdev);
++	return 0;
++}
++
++static int fiq_debugger_dev_resume(struct device *dev)
++{
++	struct platform_device *pdev = to_platform_device(dev);
++	struct fiq_debugger_state *state = platform_get_drvdata(pdev);
++
++	if (state->pdata->uart_dev_resume)
++		return state->pdata->uart_dev_resume(pdev);
++	return 0;
++}
++
++static int fiq_debugger_probe(struct platform_device *pdev)
++{
++	int ret;
++	struct fiq_debugger_pdata *pdata = dev_get_platdata(&pdev->dev);
++	struct fiq_debugger_state *state;
++	int fiq;
++	int uart_irq;
++
++	if (pdev->id >= MAX_FIQ_DEBUGGER_PORTS)
++		return -EINVAL;
++
++	if (!pdata->uart_getc || !pdata->uart_putc)
++		return -EINVAL;
++	if ((pdata->uart_enable && !pdata->uart_disable) ||
++	    (!pdata->uart_enable && pdata->uart_disable))
++		return -EINVAL;
++
++	fiq = platform_get_irq_byname(pdev, "fiq");
++	uart_irq = platform_get_irq_byname(pdev, "uart_irq");
++
++	/* uart_irq mode and fiq mode are mutually exclusive, but one of them
++	 * is required */
++	if ((uart_irq < 0 && fiq < 0) || (uart_irq >= 0 && fiq >= 0))
++		return -EINVAL;
++	if (fiq >= 0 && !pdata->fiq_enable)
++		return -EINVAL;
++
++	state = kzalloc(sizeof(*state), GFP_KERNEL);
++	state->output.printf = fiq_debugger_printf;
++	setup_timer(&state->sleep_timer, fiq_debugger_sleep_timer_expired,
++		    (unsigned long)state);
++	state->pdata = pdata;
++	state->pdev = pdev;
++	state->no_sleep = initial_no_sleep;
++	state->debug_enable = initial_debug_enable;
++	state->console_enable = initial_console_enable;
++
++	state->fiq = fiq;
++	state->uart_irq = uart_irq;
++	state->signal_irq = platform_get_irq_byname(pdev, "signal");
++	state->wakeup_irq = platform_get_irq_byname(pdev, "wakeup");
++
++	INIT_WORK(&state->work, fiq_debugger_work);
++	spin_lock_init(&state->work_lock);
++
++	platform_set_drvdata(pdev, state);
++
++	spin_lock_init(&state->sleep_timer_lock);
++
++	if (state->wakeup_irq < 0 && fiq_debugger_have_fiq(state))
++		state->no_sleep = true;
++	state->ignore_next_wakeup_irq = !state->no_sleep;
++
++	wake_lock_init(&state->debugger_wake_lock,
++			WAKE_LOCK_SUSPEND, "serial-debug");
++
++	state->clk = clk_get(&pdev->dev, NULL);
++	if (IS_ERR(state->clk))
++		state->clk = NULL;
++
++	/* do not call pdata->uart_enable here since uart_init may still
++	 * need to do some initialization before uart_enable can work.
++	 * So, only try to manage the clock during init.
++	 */
++	if (state->clk)
++		clk_enable(state->clk);
++
++	if (pdata->uart_init) {
++		ret = pdata->uart_init(pdev);
++		if (ret)
++			goto err_uart_init;
++	}
++
++	fiq_debugger_printf_nfiq(state,
++				"<hit enter %sto activate fiq debugger>\n",
++				state->no_sleep ? "" : "twice ");
++
++#ifdef CONFIG_FIQ_GLUE
++	if (fiq_debugger_have_fiq(state)) {
++		state->handler.fiq = fiq_debugger_fiq;
++		state->handler.resume = fiq_debugger_resume;
++		ret = fiq_glue_register_handler(&state->handler);
++		if (ret) {
++			pr_err("%s: could not install fiq handler\n", __func__);
++			goto err_register_irq;
++		}
++
++		pdata->fiq_enable(pdev, state->fiq, 1);
++	} else
++#endif
++	{
++		ret = request_irq(state->uart_irq, fiq_debugger_uart_irq,
++				  IRQF_NO_SUSPEND, "debug", state);
++		if (ret) {
++			pr_err("%s: could not install irq handler\n", __func__);
++			goto err_register_irq;
++		}
++
++		/* for irq-only mode, we want this irq to wake us up, if it
++		 * can.
++		 */
++		enable_irq_wake(state->uart_irq);
++	}
++
++	if (state->clk)
++		clk_disable(state->clk);
++
++	if (state->signal_irq >= 0) {
++		ret = request_irq(state->signal_irq, fiq_debugger_signal_irq,
++			  IRQF_TRIGGER_RISING, "debug-signal", state);
++		if (ret)
++			pr_err("serial_debugger: could not install signal_irq");
++	}
++
++	if (state->wakeup_irq >= 0) {
++		ret = request_irq(state->wakeup_irq,
++				  fiq_debugger_wakeup_irq_handler,
++				  IRQF_TRIGGER_FALLING | IRQF_DISABLED,
++				  "debug-wakeup", state);
++		if (ret) {
++			pr_err("serial_debugger: "
++				"could not install wakeup irq\n");
++			state->wakeup_irq = -1;
++		} else {
++			ret = enable_irq_wake(state->wakeup_irq);
++			if (ret) {
++				pr_err("serial_debugger: "
++					"could not enable wakeup\n");
++				state->wakeup_irq_no_set_wake = true;
++			}
++		}
++	}
++	if (state->no_sleep)
++		fiq_debugger_handle_wakeup(state);
++
++#if defined(CONFIG_FIQ_DEBUGGER_CONSOLE)
++	spin_lock_init(&state->console_lock);
++	state->console = fiq_debugger_console;
++	state->console.index = pdev->id;
++	if (!console_set_on_cmdline)
++		add_preferred_console(state->console.name,
++			state->console.index, NULL);
++	register_console(&state->console);
++	fiq_debugger_tty_init_one(state);
++#endif
++	return 0;
++
++err_register_irq:
++	if (pdata->uart_free)
++		pdata->uart_free(pdev);
++err_uart_init:
++	if (state->clk)
++		clk_disable(state->clk);
++	if (state->clk)
++		clk_put(state->clk);
++	wake_lock_destroy(&state->debugger_wake_lock);
++	platform_set_drvdata(pdev, NULL);
++	kfree(state);
++	return ret;
++}
++
++static const struct dev_pm_ops fiq_debugger_dev_pm_ops = {
++	.suspend	= fiq_debugger_dev_suspend,
++	.resume		= fiq_debugger_dev_resume,
++};
++
++static struct platform_driver fiq_debugger_driver = {
++	.probe	= fiq_debugger_probe,
++	.driver	= {
++		.name	= "fiq_debugger",
++		.pm	= &fiq_debugger_dev_pm_ops,
++	},
++};
++
++static int __init fiq_debugger_init(void)
++{
++#if defined(CONFIG_FIQ_DEBUGGER_CONSOLE)
++	fiq_debugger_tty_init();
++#endif
++	return platform_driver_register(&fiq_debugger_driver);
++}
++
++postcore_initcall(fiq_debugger_init);
+diff --git a/drivers/staging/android/fiq_debugger/fiq_debugger.h b/drivers/staging/android/fiq_debugger/fiq_debugger.h
+new file mode 100644
+index 0000000..c9ec4f8
+--- /dev/null
++++ b/drivers/staging/android/fiq_debugger/fiq_debugger.h
+@@ -0,0 +1,64 @@
++/*
++ * drivers/staging/android/fiq_debugger/fiq_debugger.h
++ *
++ * Copyright (C) 2010 Google, Inc.
++ * Author: Colin Cross <ccross@android.com>
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#ifndef _ARCH_ARM_MACH_TEGRA_FIQ_DEBUGGER_H_
++#define _ARCH_ARM_MACH_TEGRA_FIQ_DEBUGGER_H_
++
++#include <linux/serial_core.h>
++
++#define FIQ_DEBUGGER_NO_CHAR NO_POLL_CHAR
++#define FIQ_DEBUGGER_BREAK 0x00ff0100
++
++#define FIQ_DEBUGGER_FIQ_IRQ_NAME	"fiq"
++#define FIQ_DEBUGGER_SIGNAL_IRQ_NAME	"signal"
++#define FIQ_DEBUGGER_WAKEUP_IRQ_NAME	"wakeup"
++
++/**
++ * struct fiq_debugger_pdata - fiq debugger platform data
++ * @uart_resume:	used to restore uart state right before enabling
++ *			the fiq.
++ * @uart_enable:	Do the work necessary to communicate with the uart
++ *			hw (enable clocks, etc.). This must be ref-counted.
++ * @uart_disable:	Do the work necessary to disable the uart hw
++ *			(disable clocks, etc.). This must be ref-counted.
++ * @uart_dev_suspend:	called during PM suspend, generally not needed
++ *			for real fiq mode debugger.
++ * @uart_dev_resume:	called during PM resume, generally not needed
++ *			for real fiq mode debugger.
++ */
++struct fiq_debugger_pdata {
++	int (*uart_init)(struct platform_device *pdev);
++	void (*uart_free)(struct platform_device *pdev);
++	int (*uart_resume)(struct platform_device *pdev);
++	int (*uart_getc)(struct platform_device *pdev);
++	void (*uart_putc)(struct platform_device *pdev, unsigned int c);
++	void (*uart_flush)(struct platform_device *pdev);
++	void (*uart_enable)(struct platform_device *pdev);
++	void (*uart_disable)(struct platform_device *pdev);
++
++	int (*uart_dev_suspend)(struct platform_device *pdev);
++	int (*uart_dev_resume)(struct platform_device *pdev);
++
++	void (*fiq_enable)(struct platform_device *pdev, unsigned int fiq,
++								bool enable);
++	void (*fiq_ack)(struct platform_device *pdev, unsigned int fiq);
++
++	void (*force_irq)(struct platform_device *pdev, unsigned int irq);
++	void (*force_irq_ack)(struct platform_device *pdev, unsigned int irq);
++};
++
++#endif
+diff --git a/drivers/staging/android/fiq_debugger/fiq_debugger_arm.c b/drivers/staging/android/fiq_debugger/fiq_debugger_arm.c
+new file mode 100644
+index 0000000..8b3e013
+--- /dev/null
++++ b/drivers/staging/android/fiq_debugger/fiq_debugger_arm.c
+@@ -0,0 +1,240 @@
++/*
++ * Copyright (C) 2014 Google, Inc.
++ * Author: Colin Cross <ccross@android.com>
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#include <linux/ptrace.h>
++#include <linux/uaccess.h>
++
++#include <asm/stacktrace.h>
++
++#include "fiq_debugger_priv.h"
++
++static char *mode_name(unsigned cpsr)
++{
++	switch (cpsr & MODE_MASK) {
++	case USR_MODE: return "USR";
++	case FIQ_MODE: return "FIQ";
++	case IRQ_MODE: return "IRQ";
++	case SVC_MODE: return "SVC";
++	case ABT_MODE: return "ABT";
++	case UND_MODE: return "UND";
++	case SYSTEM_MODE: return "SYS";
++	default: return "???";
++	}
++}
++
++void fiq_debugger_dump_pc(struct fiq_debugger_output *output,
++		const struct pt_regs *regs)
++{
++	output->printf(output, " pc %08x cpsr %08x mode %s\n",
++		regs->ARM_pc, regs->ARM_cpsr, mode_name(regs->ARM_cpsr));
++}
++
++void fiq_debugger_dump_regs(struct fiq_debugger_output *output,
++		const struct pt_regs *regs)
++{
++	output->printf(output,
++			" r0 %08x  r1 %08x  r2 %08x  r3 %08x\n",
++			regs->ARM_r0, regs->ARM_r1, regs->ARM_r2, regs->ARM_r3);
++	output->printf(output,
++			" r4 %08x  r5 %08x  r6 %08x  r7 %08x\n",
++			regs->ARM_r4, regs->ARM_r5, regs->ARM_r6, regs->ARM_r7);
++	output->printf(output,
++			" r8 %08x  r9 %08x r10 %08x r11 %08x  mode %s\n",
++			regs->ARM_r8, regs->ARM_r9, regs->ARM_r10, regs->ARM_fp,
++			mode_name(regs->ARM_cpsr));
++	output->printf(output,
++			" ip %08x  sp %08x  lr %08x  pc %08x cpsr %08x\n",
++			regs->ARM_ip, regs->ARM_sp, regs->ARM_lr, regs->ARM_pc,
++			regs->ARM_cpsr);
++}
++
++struct mode_regs {
++	unsigned long sp_svc;
++	unsigned long lr_svc;
++	unsigned long spsr_svc;
++
++	unsigned long sp_abt;
++	unsigned long lr_abt;
++	unsigned long spsr_abt;
++
++	unsigned long sp_und;
++	unsigned long lr_und;
++	unsigned long spsr_und;
++
++	unsigned long sp_irq;
++	unsigned long lr_irq;
++	unsigned long spsr_irq;
++
++	unsigned long r8_fiq;
++	unsigned long r9_fiq;
++	unsigned long r10_fiq;
++	unsigned long r11_fiq;
++	unsigned long r12_fiq;
++	unsigned long sp_fiq;
++	unsigned long lr_fiq;
++	unsigned long spsr_fiq;
++};
++
++static void __naked get_mode_regs(struct mode_regs *regs)
++{
++	asm volatile (
++	"mrs	r1, cpsr\n"
++	"msr	cpsr_c, #0xd3 @(SVC_MODE | PSR_I_BIT | PSR_F_BIT)\n"
++	"stmia	r0!, {r13 - r14}\n"
++	"mrs	r2, spsr\n"
++	"msr	cpsr_c, #0xd7 @(ABT_MODE | PSR_I_BIT | PSR_F_BIT)\n"
++	"stmia	r0!, {r2, r13 - r14}\n"
++	"mrs	r2, spsr\n"
++	"msr	cpsr_c, #0xdb @(UND_MODE | PSR_I_BIT | PSR_F_BIT)\n"
++	"stmia	r0!, {r2, r13 - r14}\n"
++	"mrs	r2, spsr\n"
++	"msr	cpsr_c, #0xd2 @(IRQ_MODE | PSR_I_BIT | PSR_F_BIT)\n"
++	"stmia	r0!, {r2, r13 - r14}\n"
++	"mrs	r2, spsr\n"
++	"msr	cpsr_c, #0xd1 @(FIQ_MODE | PSR_I_BIT | PSR_F_BIT)\n"
++	"stmia	r0!, {r2, r8 - r14}\n"
++	"mrs	r2, spsr\n"
++	"stmia	r0!, {r2}\n"
++	"msr	cpsr_c, r1\n"
++	"bx	lr\n");
++}
++
++
++void fiq_debugger_dump_allregs(struct fiq_debugger_output *output,
++		const struct pt_regs *regs)
++{
++	struct mode_regs mode_regs;
++	unsigned long mode = regs->ARM_cpsr & MODE_MASK;
++
++	fiq_debugger_dump_regs(output, regs);
++	get_mode_regs(&mode_regs);
++
++	output->printf(output,
++			"%csvc: sp %08x  lr %08x  spsr %08x\n",
++			mode == SVC_MODE ? '*' : ' ',
++			mode_regs.sp_svc, mode_regs.lr_svc, mode_regs.spsr_svc);
++	output->printf(output,
++			"%cabt: sp %08x  lr %08x  spsr %08x\n",
++			mode == ABT_MODE ? '*' : ' ',
++			mode_regs.sp_abt, mode_regs.lr_abt, mode_regs.spsr_abt);
++	output->printf(output,
++			"%cund: sp %08x  lr %08x  spsr %08x\n",
++			mode == UND_MODE ? '*' : ' ',
++			mode_regs.sp_und, mode_regs.lr_und, mode_regs.spsr_und);
++	output->printf(output,
++			"%cirq: sp %08x  lr %08x  spsr %08x\n",
++			mode == IRQ_MODE ? '*' : ' ',
++			mode_regs.sp_irq, mode_regs.lr_irq, mode_regs.spsr_irq);
++	output->printf(output,
++			"%cfiq: r8 %08x  r9 %08x  r10 %08x  r11 %08x  r12 %08x\n",
++			mode == FIQ_MODE ? '*' : ' ',
++			mode_regs.r8_fiq, mode_regs.r9_fiq, mode_regs.r10_fiq,
++			mode_regs.r11_fiq, mode_regs.r12_fiq);
++	output->printf(output,
++			" fiq: sp %08x  lr %08x  spsr %08x\n",
++			mode_regs.sp_fiq, mode_regs.lr_fiq, mode_regs.spsr_fiq);
++}
++
++struct stacktrace_state {
++	struct fiq_debugger_output *output;
++	unsigned int depth;
++};
++
++static int report_trace(struct stackframe *frame, void *d)
++{
++	struct stacktrace_state *sts = d;
++
++	if (sts->depth) {
++		sts->output->printf(sts->output,
++			"  pc: %p (%pF), lr %p (%pF), sp %p, fp %p\n",
++			frame->pc, frame->pc, frame->lr, frame->lr,
++			frame->sp, frame->fp);
++		sts->depth--;
++		return 0;
++	}
++	sts->output->printf(sts->output, "  ...\n");
++
++	return sts->depth == 0;
++}
++
++struct frame_tail {
++	struct frame_tail *fp;
++	unsigned long sp;
++	unsigned long lr;
++} __attribute__((packed));
++
++static struct frame_tail *user_backtrace(struct fiq_debugger_output *output,
++					struct frame_tail *tail)
++{
++	struct frame_tail buftail[2];
++
++	/* Also check accessibility of one struct frame_tail beyond */
++	if (!access_ok(VERIFY_READ, tail, sizeof(buftail))) {
++		output->printf(output, "  invalid frame pointer %p\n",
++				tail);
++		return NULL;
++	}
++	if (__copy_from_user_inatomic(buftail, tail, sizeof(buftail))) {
++		output->printf(output,
++			"  failed to copy frame pointer %p\n", tail);
++		return NULL;
++	}
++
++	output->printf(output, "  %p\n", buftail[0].lr);
++
++	/* frame pointers should strictly progress back up the stack
++	 * (towards higher addresses) */
++	if (tail >= buftail[0].fp)
++		return NULL;
++
++	return buftail[0].fp-1;
++}
++
++void fiq_debugger_dump_stacktrace(struct fiq_debugger_output *output,
++		const struct pt_regs *regs, unsigned int depth, void *ssp)
++{
++	struct frame_tail *tail;
++	struct thread_info *real_thread_info = THREAD_INFO(ssp);
++	struct stacktrace_state sts;
++
++	sts.depth = depth;
++	sts.output = output;
++	*current_thread_info() = *real_thread_info;
++
++	if (!current)
++		output->printf(output, "current NULL\n");
++	else
++		output->printf(output, "pid: %d  comm: %s\n",
++			current->pid, current->comm);
++	fiq_debugger_dump_regs(output, regs);
++
++	if (!user_mode(regs)) {
++		struct stackframe frame;
++		frame.fp = regs->ARM_fp;
++		frame.sp = regs->ARM_sp;
++		frame.lr = regs->ARM_lr;
++		frame.pc = regs->ARM_pc;
++		output->printf(output,
++			"  pc: %p (%pF), lr %p (%pF), sp %p, fp %p\n",
++			regs->ARM_pc, regs->ARM_pc, regs->ARM_lr, regs->ARM_lr,
++			regs->ARM_sp, regs->ARM_fp);
++		walk_stackframe(&frame, report_trace, &sts);
++		return;
++	}
++
++	tail = ((struct frame_tail *) regs->ARM_fp) - 1;
++	while (depth-- && tail && !((unsigned long) tail & 3))
++		tail = user_backtrace(output, tail);
++}
+diff --git a/drivers/staging/android/fiq_debugger/fiq_debugger_arm64.c b/drivers/staging/android/fiq_debugger/fiq_debugger_arm64.c
+new file mode 100644
+index 0000000..99c6584
+--- /dev/null
++++ b/drivers/staging/android/fiq_debugger/fiq_debugger_arm64.c
+@@ -0,0 +1,202 @@
++/*
++ * Copyright (C) 2014 Google, Inc.
++ * Author: Colin Cross <ccross@android.com>
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#include <linux/ptrace.h>
++#include <asm/stacktrace.h>
++
++#include "fiq_debugger_priv.h"
++
++static char *mode_name(const struct pt_regs *regs)
++{
++	if (compat_user_mode(regs)) {
++		return "USR";
++	} else {
++		switch (processor_mode(regs)) {
++		case PSR_MODE_EL0t: return "EL0t";
++		case PSR_MODE_EL1t: return "EL1t";
++		case PSR_MODE_EL1h: return "EL1h";
++		case PSR_MODE_EL2t: return "EL2t";
++		case PSR_MODE_EL2h: return "EL2h";
++		default: return "???";
++		}
++	}
++}
++
++void fiq_debugger_dump_pc(struct fiq_debugger_output *output,
++		const struct pt_regs *regs)
++{
++	output->printf(output, " pc %016lx cpsr %08lx mode %s\n",
++		regs->pc, regs->pstate, mode_name(regs));
++}
++
++void fiq_debugger_dump_regs_aarch32(struct fiq_debugger_output *output,
++		const struct pt_regs *regs)
++{
++	output->printf(output, " r0 %08x  r1 %08x  r2 %08x  r3 %08x\n",
++			regs->compat_usr(0), regs->compat_usr(1),
++			regs->compat_usr(2), regs->compat_usr(3));
++	output->printf(output, " r4 %08x  r5 %08x  r6 %08x  r7 %08x\n",
++			regs->compat_usr(4), regs->compat_usr(5),
++			regs->compat_usr(6), regs->compat_usr(7));
++	output->printf(output, " r8 %08x  r9 %08x r10 %08x r11 %08x\n",
++			regs->compat_usr(8), regs->compat_usr(9),
++			regs->compat_usr(10), regs->compat_usr(11));
++	output->printf(output, " ip %08x  sp %08x  lr %08x  pc %08x\n",
++			regs->compat_usr(12), regs->compat_sp,
++			regs->compat_lr, regs->pc);
++	output->printf(output, " cpsr %08x (%s)\n",
++			regs->pstate, mode_name(regs));
++}
++
++void fiq_debugger_dump_regs_aarch64(struct fiq_debugger_output *output,
++		const struct pt_regs *regs)
++{
++
++	output->printf(output, "  x0 %016lx   x1 %016lx\n",
++			regs->regs[0], regs->regs[1]);
++	output->printf(output, "  x2 %016lx   x3 %016lx\n",
++			regs->regs[2], regs->regs[3]);
++	output->printf(output, "  x4 %016lx   x5 %016lx\n",
++			regs->regs[4], regs->regs[5]);
++	output->printf(output, "  x6 %016lx   x7 %016lx\n",
++			regs->regs[6], regs->regs[7]);
++	output->printf(output, "  x8 %016lx   x9 %016lx\n",
++			regs->regs[8], regs->regs[9]);
++	output->printf(output, " x10 %016lx  x11 %016lx\n",
++			regs->regs[10], regs->regs[11]);
++	output->printf(output, " x12 %016lx  x13 %016lx\n",
++			regs->regs[12], regs->regs[13]);
++	output->printf(output, " x14 %016lx  x15 %016lx\n",
++			regs->regs[14], regs->regs[15]);
++	output->printf(output, " x16 %016lx  x17 %016lx\n",
++			regs->regs[16], regs->regs[17]);
++	output->printf(output, " x18 %016lx  x19 %016lx\n",
++			regs->regs[18], regs->regs[19]);
++	output->printf(output, " x20 %016lx  x21 %016lx\n",
++			regs->regs[20], regs->regs[21]);
++	output->printf(output, " x22 %016lx  x23 %016lx\n",
++			regs->regs[22], regs->regs[23]);
++	output->printf(output, " x24 %016lx  x25 %016lx\n",
++			regs->regs[24], regs->regs[25]);
++	output->printf(output, " x26 %016lx  x27 %016lx\n",
++			regs->regs[26], regs->regs[27]);
++	output->printf(output, " x28 %016lx  x29 %016lx\n",
++			regs->regs[28], regs->regs[29]);
++	output->printf(output, " x30 %016lx   sp %016lx\n",
++			regs->regs[30], regs->sp);
++	output->printf(output, "  pc %016lx cpsr %08x (%s)\n",
++			regs->pc, regs->pstate, mode_name(regs));
++}
++
++void fiq_debugger_dump_regs(struct fiq_debugger_output *output,
++		const struct pt_regs *regs)
++{
++	if (compat_user_mode(regs))
++		fiq_debugger_dump_regs_aarch32(output, regs);
++	else
++		fiq_debugger_dump_regs_aarch64(output, regs);
++}
++
++#define READ_SPECIAL_REG(x) ({ \
++	u64 val; \
++	asm volatile ("mrs %0, " # x : "=r"(val)); \
++	val; \
++})
++
++void fiq_debugger_dump_allregs(struct fiq_debugger_output *output,
++		const struct pt_regs *regs)
++{
++	u32 pstate = READ_SPECIAL_REG(CurrentEl);
++	bool in_el2 = (pstate & PSR_MODE_MASK) >= PSR_MODE_EL2t;
++
++	fiq_debugger_dump_regs(output, regs);
++
++	output->printf(output, " sp_el0   %016lx\n",
++			READ_SPECIAL_REG(sp_el0));
++
++	if (in_el2)
++		output->printf(output, " sp_el1   %016lx\n",
++				READ_SPECIAL_REG(sp_el1));
++
++	output->printf(output, " elr_el1  %016lx\n",
++			READ_SPECIAL_REG(elr_el1));
++
++	output->printf(output, " spsr_el1 %08lx\n",
++			READ_SPECIAL_REG(spsr_el1));
++
++	if (in_el2) {
++		output->printf(output, " spsr_irq %08lx\n",
++				READ_SPECIAL_REG(spsr_irq));
++		output->printf(output, " spsr_abt %08lx\n",
++				READ_SPECIAL_REG(spsr_abt));
++		output->printf(output, " spsr_und %08lx\n",
++				READ_SPECIAL_REG(spsr_und));
++		output->printf(output, " spsr_fiq %08lx\n",
++				READ_SPECIAL_REG(spsr_fiq));
++		output->printf(output, " spsr_el2 %08lx\n",
++				READ_SPECIAL_REG(elr_el2));
++		output->printf(output, " spsr_el2 %08lx\n",
++				READ_SPECIAL_REG(spsr_el2));
++	}
++}
++
++struct stacktrace_state {
++	struct fiq_debugger_output *output;
++	unsigned int depth;
++};
++
++static int report_trace(struct stackframe *frame, void *d)
++{
++	struct stacktrace_state *sts = d;
++
++	if (sts->depth) {
++		sts->output->printf(sts->output, "%pF:\n", frame->pc);
++		sts->output->printf(sts->output,
++				"  pc %016lx   sp %016lx   fp %016lx\n",
++				frame->pc, frame->sp, frame->fp);
++		sts->depth--;
++		return 0;
++	}
++	sts->output->printf(sts->output, "  ...\n");
++
++	return sts->depth == 0;
++}
++
++void fiq_debugger_dump_stacktrace(struct fiq_debugger_output *output,
++		const struct pt_regs *regs, unsigned int depth, void *ssp)
++{
++	struct thread_info *real_thread_info = THREAD_INFO(ssp);
++	struct stacktrace_state sts;
++
++	sts.depth = depth;
++	sts.output = output;
++	*current_thread_info() = *real_thread_info;
++
++	if (!current)
++		output->printf(output, "current NULL\n");
++	else
++		output->printf(output, "pid: %d  comm: %s\n",
++			current->pid, current->comm);
++	fiq_debugger_dump_regs(output, regs);
++
++	if (!user_mode(regs)) {
++		struct stackframe frame;
++		frame.fp = regs->regs[29];
++		frame.sp = regs->sp;
++		frame.pc = regs->pc;
++		output->printf(output, "\n");
++		walk_stackframe(&frame, report_trace, &sts);
++	}
++}
+diff --git a/drivers/staging/android/fiq_debugger/fiq_debugger_priv.h b/drivers/staging/android/fiq_debugger/fiq_debugger_priv.h
+new file mode 100644
+index 0000000..d5d051f
+--- /dev/null
++++ b/drivers/staging/android/fiq_debugger/fiq_debugger_priv.h
+@@ -0,0 +1,37 @@
++/*
++ * Copyright (C) 2014 Google, Inc.
++ * Author: Colin Cross <ccross@android.com>
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#ifndef _FIQ_DEBUGGER_PRIV_H_
++#define _FIQ_DEBUGGER_PRIV_H_
++
++#define THREAD_INFO(sp) ((struct thread_info *) \
++		((unsigned long)(sp) & ~(THREAD_SIZE - 1)))
++
++struct fiq_debugger_output {
++	void (*printf)(struct fiq_debugger_output *output, const char *fmt, ...);
++};
++
++struct pt_regs;
++
++void fiq_debugger_dump_pc(struct fiq_debugger_output *output,
++		const struct pt_regs *regs);
++void fiq_debugger_dump_regs(struct fiq_debugger_output *output,
++		const struct pt_regs *regs);
++void fiq_debugger_dump_allregs(struct fiq_debugger_output *output,
++		const struct pt_regs *regs);
++void fiq_debugger_dump_stacktrace(struct fiq_debugger_output *output,
++		const struct pt_regs *regs, unsigned int depth, void *ssp);
++
++#endif
+diff --git a/drivers/staging/android/fiq_debugger/fiq_debugger_ringbuf.h b/drivers/staging/android/fiq_debugger/fiq_debugger_ringbuf.h
+new file mode 100644
+index 0000000..10c3c5d
+--- /dev/null
++++ b/drivers/staging/android/fiq_debugger/fiq_debugger_ringbuf.h
+@@ -0,0 +1,94 @@
++/*
++ * drivers/staging/android/fiq_debugger/fiq_debugger_ringbuf.h
++ *
++ * simple lockless ringbuffer
++ *
++ * Copyright (C) 2010 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/kernel.h>
++#include <linux/slab.h>
++
++struct fiq_debugger_ringbuf {
++	int len;
++	int head;
++	int tail;
++	u8 buf[];
++};
++
++
++static inline struct fiq_debugger_ringbuf *fiq_debugger_ringbuf_alloc(int len)
++{
++	struct fiq_debugger_ringbuf *rbuf;
++
++	rbuf = kzalloc(sizeof(*rbuf) + len, GFP_KERNEL);
++	if (rbuf == NULL)
++		return NULL;
++
++	rbuf->len = len;
++	rbuf->head = 0;
++	rbuf->tail = 0;
++	smp_mb();
++
++	return rbuf;
++}
++
++static inline void fiq_debugger_ringbuf_free(struct fiq_debugger_ringbuf *rbuf)
++{
++	kfree(rbuf);
++}
++
++static inline int fiq_debugger_ringbuf_level(struct fiq_debugger_ringbuf *rbuf)
++{
++	int level = rbuf->head - rbuf->tail;
++
++	if (level < 0)
++		level = rbuf->len + level;
++
++	return level;
++}
++
++static inline int fiq_debugger_ringbuf_room(struct fiq_debugger_ringbuf *rbuf)
++{
++	return rbuf->len - fiq_debugger_ringbuf_level(rbuf) - 1;
++}
++
++static inline u8
++fiq_debugger_ringbuf_peek(struct fiq_debugger_ringbuf *rbuf, int i)
++{
++	return rbuf->buf[(rbuf->tail + i) % rbuf->len];
++}
++
++static inline int
++fiq_debugger_ringbuf_consume(struct fiq_debugger_ringbuf *rbuf, int count)
++{
++	count = min(count, fiq_debugger_ringbuf_level(rbuf));
++
++	rbuf->tail = (rbuf->tail + count) % rbuf->len;
++	smp_mb();
++
++	return count;
++}
++
++static inline int
++fiq_debugger_ringbuf_push(struct fiq_debugger_ringbuf *rbuf, u8 datum)
++{
++	if (fiq_debugger_ringbuf_room(rbuf) == 0)
++		return 0;
++
++	rbuf->buf[rbuf->head] = datum;
++	smp_mb();
++	rbuf->head = (rbuf->head + 1) % rbuf->len;
++	smp_mb();
++
++	return 1;
++}
+diff --git a/drivers/staging/android/fiq_debugger/fiq_watchdog.c b/drivers/staging/android/fiq_debugger/fiq_watchdog.c
+new file mode 100644
+index 0000000..194b541
+--- /dev/null
++++ b/drivers/staging/android/fiq_debugger/fiq_watchdog.c
+@@ -0,0 +1,56 @@
++/*
++ * Copyright (C) 2014 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/spinlock.h>
++#include <linux/pstore_ram.h>
++
++#include "fiq_watchdog.h"
++#include "fiq_debugger_priv.h"
++
++static DEFINE_RAW_SPINLOCK(fiq_watchdog_lock);
++
++static void fiq_watchdog_printf(struct fiq_debugger_output *output,
++				const char *fmt, ...)
++{
++	char buf[256];
++	va_list ap;
++	int len;
++
++	va_start(ap, fmt);
++	len = vscnprintf(buf, sizeof(buf), fmt, ap);
++	va_end(ap);
++
++	ramoops_console_write_buf(buf, len);
++}
++
++struct fiq_debugger_output fiq_watchdog_output = {
++	.printf = fiq_watchdog_printf,
++};
++
++void fiq_watchdog_triggered(const struct pt_regs *regs, void *svc_sp)
++{
++	char msg[24];
++	int len;
++
++	raw_spin_lock(&fiq_watchdog_lock);
++
++	len = scnprintf(msg, sizeof(msg), "watchdog fiq cpu %d\n",
++			THREAD_INFO(svc_sp)->cpu);
++	ramoops_console_write_buf(msg, len);
++
++	fiq_debugger_dump_stacktrace(&fiq_watchdog_output, regs, 100, svc_sp);
++
++	raw_spin_unlock(&fiq_watchdog_lock);
++}
+diff --git a/drivers/staging/android/fiq_debugger/fiq_watchdog.h b/drivers/staging/android/fiq_debugger/fiq_watchdog.h
+new file mode 100644
+index 0000000..c6b507f
+--- /dev/null
++++ b/drivers/staging/android/fiq_debugger/fiq_watchdog.h
+@@ -0,0 +1,20 @@
++/*
++ * Copyright (C) 2014 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#ifndef _FIQ_WATCHDOG_H_
++#define _FIQ_WATCHDOG_H_
++
++void fiq_watchdog_triggered(const struct pt_regs *regs, void *svc_sp);
++
++#endif
+diff --git a/drivers/staging/android/ion/Kconfig b/drivers/staging/android/ion/Kconfig
+index 3452346..301948c 100644
+--- a/drivers/staging/android/ion/Kconfig
++++ b/drivers/staging/android/ion/Kconfig
+@@ -33,3 +33,10 @@ config ION_TEGRA
+ 	help
+ 	  Choose this option if you wish to use ion on an nVidia Tegra.
+ 
++config ION_POOL_CACHE_POLICY
++	bool "Ion set page pool cache policy"
++	depends on ION
++	default y if X86
++	help
++	  Choose this option if need to explicity set cache policy of the
++	  pages in the page pool.
+diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c
+index 56604f4..8724ef8 100644
+--- a/drivers/staging/android/ion/ion.c
++++ b/drivers/staging/android/ion/ion.c
+@@ -250,7 +250,7 @@ static struct ion_buffer *ion_buffer_create(struct ion_heap *heap,
+ 	   our systems the only dma_address space is physical addresses.
+ 	   Additionally, we can't afford the overhead of invalidating every
+ 	   allocation via dma_map_sg. The implicit contract here is that
+-	   memory comming from the heaps is ready for dma, ie if it has a
++	   memory coming from the heaps is ready for dma, ie if it has a
+ 	   cached mapping that mapping has been invalidated */
+ 	for_each_sg(buffer->sg_table->sgl, sg, buffer->sg_table->nents, i)
+ 		sg_dma_address(sg) = sg_phys(sg);
+@@ -902,7 +902,7 @@ void ion_pages_sync_for_device(struct device *dev, struct page *page,
+ 	sg_set_page(&sg, page, size, 0);
+ 	/*
+ 	 * This is not correct - sg_dma_address needs a dma_addr_t that is valid
+-	 * for the the targeted device, but this works on the currently targeted
++	 * for the targeted device, but this works on the currently targeted
+ 	 * hardware.
+ 	 */
+ 	sg_dma_address(&sg) = page_to_phys(page);
+diff --git a/drivers/staging/android/ion/ion.h b/drivers/staging/android/ion/ion.h
+index d305bb7..443db84 100644
+--- a/drivers/staging/android/ion/ion.h
++++ b/drivers/staging/android/ion/ion.h
+@@ -76,7 +76,7 @@ struct ion_platform_data {
+  *		size
+  *
+  * Calls memblock reserve to set aside memory for heaps that are
+- * located at specific memory addresses or of specfic sizes not
++ * located at specific memory addresses or of specific sizes not
+  * managed by the kernel
+  */
+ void ion_reserve(struct ion_platform_data *data);
+diff --git a/drivers/staging/android/ion/ion_carveout_heap.c b/drivers/staging/android/ion/ion_carveout_heap.c
+old mode 100644
+new mode 100755
+index 9156d82..e702ce6
+--- a/drivers/staging/android/ion/ion_carveout_heap.c
++++ b/drivers/staging/android/ion/ion_carveout_heap.c
+@@ -167,7 +167,7 @@ struct ion_heap *ion_carveout_heap_create(struct ion_platform_heap *heap_data)
+ 	if (!carveout_heap)
+ 		return ERR_PTR(-ENOMEM);
+ 
+-	carveout_heap->pool = gen_pool_create(12, -1);
++	carveout_heap->pool = gen_pool_create(PAGE_SHIFT, -1);
+ 	if (!carveout_heap->pool) {
+ 		kfree(carveout_heap);
+ 		return ERR_PTR(-ENOMEM);
+diff --git a/drivers/staging/android/ion/ion_page_pool.c b/drivers/staging/android/ion/ion_page_pool.c
+index 5864f3d..b021748 100644
+--- a/drivers/staging/android/ion/ion_page_pool.c
++++ b/drivers/staging/android/ion/ion_page_pool.c
+@@ -30,6 +30,8 @@ static void *ion_page_pool_alloc_pages(struct ion_page_pool *pool)
+ 
+ 	if (!page)
+ 		return NULL;
++	ion_page_pool_alloc_set_cache_policy(pool, page);
++
+ 	ion_pages_sync_for_device(NULL, page, PAGE_SIZE << pool->order,
+ 						DMA_BIDIRECTIONAL);
+ 	return page;
+@@ -38,6 +40,7 @@ static void *ion_page_pool_alloc_pages(struct ion_page_pool *pool)
+ static void ion_page_pool_free_pages(struct ion_page_pool *pool,
+ 				     struct page *page)
+ {
++	ion_page_pool_free_set_cache_policy(pool, page);
+ 	__free_pages(page, pool->order);
+ }
+ 
+@@ -103,6 +106,11 @@ void ion_page_pool_free(struct ion_page_pool *pool, struct page *page)
+ 		ion_page_pool_free_pages(pool, page);
+ }
+ 
++void ion_page_pool_free_immediate(struct ion_page_pool *pool, struct page *page)
++{
++	ion_page_pool_free_pages(pool, page);
++}
++
+ static int ion_page_pool_total(struct ion_page_pool *pool, bool high)
+ {
+ 	int count = pool->low_count;
+@@ -120,7 +128,7 @@ int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask,
+ 	bool high;
+ 
+ 	if (current_is_kswapd())
+-		high = 1;
++		high = true;
+ 	else
+ 		high = !!(gfp_mask & __GFP_HIGHMEM);
+ 
+diff --git a/drivers/staging/android/ion/ion_priv.h b/drivers/staging/android/ion/ion_priv.h
+index c8f0175..0e3b8a6 100644
+--- a/drivers/staging/android/ion/ion_priv.h
++++ b/drivers/staging/android/ion/ion_priv.h
+@@ -26,6 +26,9 @@
+ #include <linux/sched.h>
+ #include <linux/shrinker.h>
+ #include <linux/types.h>
++#ifdef CONFIG_ION_POOL_CACHE_POLICY
++#include <asm/cacheflush.h>
++#endif
+ 
+ #include "ion.h"
+ 
+@@ -345,7 +348,7 @@ void ion_carveout_free(struct ion_heap *heap, ion_phys_addr_t addr,
+  * functions for creating and destroying a heap pool -- allows you
+  * to keep a pool of pre allocated memory to use from your heap.  Keeping
+  * a pool of memory that is ready for dma, ie any cached mapping have been
+- * invalidated from the cache, provides a significant peformance benefit on
++ * invalidated from the cache, provides a significant performance benefit on
+  * many systems */
+ 
+ /**
+@@ -362,7 +365,7 @@ void ion_carveout_free(struct ion_heap *heap, ion_phys_addr_t addr,
+  *
+  * Allows you to keep a pool of pre allocated pages to use from your heap.
+  * Keeping a pool of pages that is ready for dma, ie any cached mapping have
+- * been invalidated from the cache, provides a significant peformance benefit
++ * been invalidated from the cache, provides a significant performance benefit
+  * on many systems
+  */
+ struct ion_page_pool {
+@@ -380,6 +383,37 @@ struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order);
+ void ion_page_pool_destroy(struct ion_page_pool *);
+ struct page *ion_page_pool_alloc(struct ion_page_pool *);
+ void ion_page_pool_free(struct ion_page_pool *, struct page *);
++void ion_page_pool_free_immediate(struct ion_page_pool *, struct page *);
++
++#ifdef CONFIG_ION_POOL_CACHE_POLICY
++static inline void ion_page_pool_alloc_set_cache_policy
++				(struct ion_page_pool *pool,
++				struct page *page){
++	void *va = page_address(page);
++
++	if (va)
++		set_memory_wc((unsigned long)va, 1 << pool->order);
++}
++
++static inline void ion_page_pool_free_set_cache_policy
++				(struct ion_page_pool *pool,
++				struct page *page){
++	void *va = page_address(page);
++
++	if (va)
++		set_memory_wb((unsigned long)va, 1 << pool->order);
++
++}
++#else
++static inline void ion_page_pool_alloc_set_cache_policy
++				(struct ion_page_pool *pool,
++				struct page *page){ }
++
++static inline void ion_page_pool_free_set_cache_policy
++				(struct ion_page_pool *pool,
++				struct page *page){ }
++#endif
++
+ 
+ /** ion_page_pool_shrink - shrinks the size of the memory cached in the pool
+  * @pool:		the pool
+diff --git a/drivers/staging/android/ion/ion_system_heap.c b/drivers/staging/android/ion/ion_system_heap.c
+index da2a63c..1f9feb7 100644
+--- a/drivers/staging/android/ion/ion_system_heap.c
++++ b/drivers/staging/android/ion/ion_system_heap.c
+@@ -85,8 +85,10 @@ static void free_buffer_page(struct ion_system_heap *heap,
+ 
+ 	if (!cached && !(buffer->private_flags & ION_PRIV_FLAG_SHRINKER_FREE)) {
+ 		struct ion_page_pool *pool = heap->pools[order_to_index(order)];
+-
+-		ion_page_pool_free(pool, page);
++		if (buffer->private_flags & ION_PRIV_FLAG_SHRINKER_FREE)
++			ion_page_pool_free_immediate(pool, page);
++		else
++			ion_page_pool_free(pool, page);
+ 	} else {
+ 		__free_pages(page, order);
+ 	}
+diff --git a/drivers/staging/android/logger.c b/drivers/staging/android/logger.c
+deleted file mode 100644
+index a673ffa..0000000
+--- a/drivers/staging/android/logger.c
++++ /dev/null
+@@ -1,808 +0,0 @@
+-/*
+- * drivers/misc/logger.c
+- *
+- * A Logging Subsystem
+- *
+- * Copyright (C) 2007-2008 Google, Inc.
+- *
+- * Robert Love <rlove@google.com>
+- *
+- * This software is licensed under the terms of the GNU General Public
+- * License version 2, as published by the Free Software Foundation, and
+- * may be copied, distributed, and modified under those terms.
+- *
+- * 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.
+- */
+-
+-#define pr_fmt(fmt) "logger: " fmt
+-
+-#include <linux/sched.h>
+-#include <linux/module.h>
+-#include <linux/fs.h>
+-#include <linux/miscdevice.h>
+-#include <linux/uaccess.h>
+-#include <linux/poll.h>
+-#include <linux/slab.h>
+-#include <linux/time.h>
+-#include <linux/vmalloc.h>
+-#include <linux/aio.h>
+-#include "logger.h"
+-
+-#include <asm/ioctls.h>
+-
+-/**
+- * struct logger_log - represents a specific log, such as 'main' or 'radio'
+- * @buffer:	The actual ring buffer
+- * @misc:	The "misc" device representing the log
+- * @wq:		The wait queue for @readers
+- * @readers:	This log's readers
+- * @mutex:	The mutex that protects the @buffer
+- * @w_off:	The current write head offset
+- * @head:	The head, or location that readers start reading at.
+- * @size:	The size of the log
+- * @logs:	The list of log channels
+- *
+- * This structure lives from module insertion until module removal, so it does
+- * not need additional reference counting. The structure is protected by the
+- * mutex 'mutex'.
+- */
+-struct logger_log {
+-	unsigned char		*buffer;
+-	struct miscdevice	misc;
+-	wait_queue_head_t	wq;
+-	struct list_head	readers;
+-	struct mutex		mutex;
+-	size_t			w_off;
+-	size_t			head;
+-	size_t			size;
+-	struct list_head	logs;
+-};
+-
+-static LIST_HEAD(log_list);
+-
+-
+-/**
+- * struct logger_reader - a logging device open for reading
+- * @log:	The associated log
+- * @list:	The associated entry in @logger_log's list
+- * @r_off:	The current read head offset.
+- * @r_all:	Reader can read all entries
+- * @r_ver:	Reader ABI version
+- *
+- * This object lives from open to release, so we don't need additional
+- * reference counting. The structure is protected by log->mutex.
+- */
+-struct logger_reader {
+-	struct logger_log	*log;
+-	struct list_head	list;
+-	size_t			r_off;
+-	bool			r_all;
+-	int			r_ver;
+-};
+-
+-/* logger_offset - returns index 'n' into the log via (optimized) modulus */
+-static size_t logger_offset(struct logger_log *log, size_t n)
+-{
+-	return n & (log->size - 1);
+-}
+-
+-
+-/*
+- * file_get_log - Given a file structure, return the associated log
+- *
+- * This isn't aesthetic. We have several goals:
+- *
+- *	1) Need to quickly obtain the associated log during an I/O operation
+- *	2) Readers need to maintain state (logger_reader)
+- *	3) Writers need to be very fast (open() should be a near no-op)
+- *
+- * In the reader case, we can trivially go file->logger_reader->logger_log.
+- * For a writer, we don't want to maintain a logger_reader, so we just go
+- * file->logger_log. Thus what file->private_data points at depends on whether
+- * or not the file was opened for reading. This function hides that dirtiness.
+- */
+-static inline struct logger_log *file_get_log(struct file *file)
+-{
+-	if (file->f_mode & FMODE_READ) {
+-		struct logger_reader *reader = file->private_data;
+-
+-		return reader->log;
+-	}
+-	return file->private_data;
+-}
+-
+-/*
+- * get_entry_header - returns a pointer to the logger_entry header within
+- * 'log' starting at offset 'off'. A temporary logger_entry 'scratch' must
+- * be provided. Typically the return value will be a pointer within
+- * 'logger->buf'.  However, a pointer to 'scratch' may be returned if
+- * the log entry spans the end and beginning of the circular buffer.
+- */
+-static struct logger_entry *get_entry_header(struct logger_log *log,
+-		size_t off, struct logger_entry *scratch)
+-{
+-	size_t len = min(sizeof(struct logger_entry), log->size - off);
+-
+-	if (len != sizeof(struct logger_entry)) {
+-		memcpy(((void *) scratch), log->buffer + off, len);
+-		memcpy(((void *) scratch) + len, log->buffer,
+-			sizeof(struct logger_entry) - len);
+-		return scratch;
+-	}
+-
+-	return (struct logger_entry *) (log->buffer + off);
+-}
+-
+-/*
+- * get_entry_msg_len - Grabs the length of the message of the entry
+- * starting from from 'off'.
+- *
+- * An entry length is 2 bytes (16 bits) in host endian order.
+- * In the log, the length does not include the size of the log entry structure.
+- * This function returns the size including the log entry structure.
+- *
+- * Caller needs to hold log->mutex.
+- */
+-static __u32 get_entry_msg_len(struct logger_log *log, size_t off)
+-{
+-	struct logger_entry scratch;
+-	struct logger_entry *entry;
+-
+-	entry = get_entry_header(log, off, &scratch);
+-	return entry->len;
+-}
+-
+-static size_t get_user_hdr_len(int ver)
+-{
+-	if (ver < 2)
+-		return sizeof(struct user_logger_entry_compat);
+-	return sizeof(struct logger_entry);
+-}
+-
+-static ssize_t copy_header_to_user(int ver, struct logger_entry *entry,
+-					 char __user *buf)
+-{
+-	void *hdr;
+-	size_t hdr_len;
+-	struct user_logger_entry_compat v1;
+-
+-	if (ver < 2) {
+-		v1.len      = entry->len;
+-		v1.__pad    = 0;
+-		v1.pid      = entry->pid;
+-		v1.tid      = entry->tid;
+-		v1.sec      = entry->sec;
+-		v1.nsec     = entry->nsec;
+-		hdr         = &v1;
+-		hdr_len     = sizeof(struct user_logger_entry_compat);
+-	} else {
+-		hdr         = entry;
+-		hdr_len     = sizeof(struct logger_entry);
+-	}
+-
+-	return copy_to_user(buf, hdr, hdr_len);
+-}
+-
+-/*
+- * do_read_log_to_user - reads exactly 'count' bytes from 'log' into the
+- * user-space buffer 'buf'. Returns 'count' on success.
+- *
+- * Caller must hold log->mutex.
+- */
+-static ssize_t do_read_log_to_user(struct logger_log *log,
+-				   struct logger_reader *reader,
+-				   char __user *buf,
+-				   size_t count)
+-{
+-	struct logger_entry scratch;
+-	struct logger_entry *entry;
+-	size_t len;
+-	size_t msg_start;
+-
+-	/*
+-	 * First, copy the header to userspace, using the version of
+-	 * the header requested
+-	 */
+-	entry = get_entry_header(log, reader->r_off, &scratch);
+-	if (copy_header_to_user(reader->r_ver, entry, buf))
+-		return -EFAULT;
+-
+-	count -= get_user_hdr_len(reader->r_ver);
+-	buf += get_user_hdr_len(reader->r_ver);
+-	msg_start = logger_offset(log,
+-		reader->r_off + sizeof(struct logger_entry));
+-
+-	/*
+-	 * We read from the msg in two disjoint operations. First, we read from
+-	 * the current msg head offset up to 'count' bytes or to the end of
+-	 * the log, whichever comes first.
+-	 */
+-	len = min(count, log->size - msg_start);
+-	if (copy_to_user(buf, log->buffer + msg_start, len))
+-		return -EFAULT;
+-
+-	/*
+-	 * Second, we read any remaining bytes, starting back at the head of
+-	 * the log.
+-	 */
+-	if (count != len)
+-		if (copy_to_user(buf + len, log->buffer, count - len))
+-			return -EFAULT;
+-
+-	reader->r_off = logger_offset(log, reader->r_off +
+-		sizeof(struct logger_entry) + count);
+-
+-	return count + get_user_hdr_len(reader->r_ver);
+-}
+-
+-/*
+- * get_next_entry_by_uid - Starting at 'off', returns an offset into
+- * 'log->buffer' which contains the first entry readable by 'euid'
+- */
+-static size_t get_next_entry_by_uid(struct logger_log *log,
+-		size_t off, kuid_t euid)
+-{
+-	while (off != log->w_off) {
+-		struct logger_entry *entry;
+-		struct logger_entry scratch;
+-		size_t next_len;
+-
+-		entry = get_entry_header(log, off, &scratch);
+-
+-		if (uid_eq(entry->euid, euid))
+-			return off;
+-
+-		next_len = sizeof(struct logger_entry) + entry->len;
+-		off = logger_offset(log, off + next_len);
+-	}
+-
+-	return off;
+-}
+-
+-/*
+- * logger_read - our log's read() method
+- *
+- * Behavior:
+- *
+- *	- O_NONBLOCK works
+- *	- If there are no log entries to read, blocks until log is written to
+- *	- Atomically reads exactly one log entry
+- *
+- * Will set errno to EINVAL if read
+- * buffer is insufficient to hold next entry.
+- */
+-static ssize_t logger_read(struct file *file, char __user *buf,
+-			   size_t count, loff_t *pos)
+-{
+-	struct logger_reader *reader = file->private_data;
+-	struct logger_log *log = reader->log;
+-	ssize_t ret;
+-	DEFINE_WAIT(wait);
+-
+-start:
+-	while (1) {
+-		mutex_lock(&log->mutex);
+-
+-		prepare_to_wait(&log->wq, &wait, TASK_INTERRUPTIBLE);
+-
+-		ret = (log->w_off == reader->r_off);
+-		mutex_unlock(&log->mutex);
+-		if (!ret)
+-			break;
+-
+-		if (file->f_flags & O_NONBLOCK) {
+-			ret = -EAGAIN;
+-			break;
+-		}
+-
+-		if (signal_pending(current)) {
+-			ret = -EINTR;
+-			break;
+-		}
+-
+-		schedule();
+-	}
+-
+-	finish_wait(&log->wq, &wait);
+-	if (ret)
+-		return ret;
+-
+-	mutex_lock(&log->mutex);
+-
+-	if (!reader->r_all)
+-		reader->r_off = get_next_entry_by_uid(log,
+-			reader->r_off, current_euid());
+-
+-	/* is there still something to read or did we race? */
+-	if (unlikely(log->w_off == reader->r_off)) {
+-		mutex_unlock(&log->mutex);
+-		goto start;
+-	}
+-
+-	/* get the size of the next entry */
+-	ret = get_user_hdr_len(reader->r_ver) +
+-		get_entry_msg_len(log, reader->r_off);
+-	if (count < ret) {
+-		ret = -EINVAL;
+-		goto out;
+-	}
+-
+-	/* get exactly one entry from the log */
+-	ret = do_read_log_to_user(log, reader, buf, ret);
+-
+-out:
+-	mutex_unlock(&log->mutex);
+-
+-	return ret;
+-}
+-
+-/*
+- * get_next_entry - return the offset of the first valid entry at least 'len'
+- * bytes after 'off'.
+- *
+- * Caller must hold log->mutex.
+- */
+-static size_t get_next_entry(struct logger_log *log, size_t off, size_t len)
+-{
+-	size_t count = 0;
+-
+-	do {
+-		size_t nr = sizeof(struct logger_entry) +
+-			get_entry_msg_len(log, off);
+-		off = logger_offset(log, off + nr);
+-		count += nr;
+-	} while (count < len);
+-
+-	return off;
+-}
+-
+-/*
+- * is_between - is a < c < b, accounting for wrapping of a, b, and c
+- *    positions in the buffer
+- *
+- * That is, if a<b, check for c between a and b
+- * and if a>b, check for c outside (not between) a and b
+- *
+- * |------- a xxxxxxxx b --------|
+- *               c^
+- *
+- * |xxxxx b --------- a xxxxxxxxx|
+- *    c^
+- *  or                    c^
+- */
+-static inline int is_between(size_t a, size_t b, size_t c)
+-{
+-	if (a < b) {
+-		/* is c between a and b? */
+-		if (a < c && c <= b)
+-			return 1;
+-	} else {
+-		/* is c outside of b through a? */
+-		if (c <= b || a < c)
+-			return 1;
+-	}
+-
+-	return 0;
+-}
+-
+-/*
+- * fix_up_readers - walk the list of all readers and "fix up" any who were
+- * lapped by the writer; also do the same for the default "start head".
+- * We do this by "pulling forward" the readers and start head to the first
+- * entry after the new write head.
+- *
+- * The caller needs to hold log->mutex.
+- */
+-static void fix_up_readers(struct logger_log *log, size_t len)
+-{
+-	size_t old = log->w_off;
+-	size_t new = logger_offset(log, old + len);
+-	struct logger_reader *reader;
+-
+-	if (is_between(old, new, log->head))
+-		log->head = get_next_entry(log, log->head, len);
+-
+-	list_for_each_entry(reader, &log->readers, list)
+-		if (is_between(old, new, reader->r_off))
+-			reader->r_off = get_next_entry(log, reader->r_off, len);
+-}
+-
+-/*
+- * logger_write_iter - our write method, implementing support for write(),
+- * writev(), and aio_write(). Writes are our fast path, and we try to optimize
+- * them above all else.
+- */
+-static ssize_t logger_write_iter(struct kiocb *iocb, struct iov_iter *from)
+-{
+-	struct logger_log *log = file_get_log(iocb->ki_filp);
+-	struct logger_entry header;
+-	struct timespec now;
+-	size_t len, count, w_off;
+-
+-	count = min_t(size_t, iocb->ki_nbytes, LOGGER_ENTRY_MAX_PAYLOAD);
+-
+-	now = current_kernel_time();
+-
+-	header.pid = current->tgid;
+-	header.tid = current->pid;
+-	header.sec = now.tv_sec;
+-	header.nsec = now.tv_nsec;
+-	header.euid = current_euid();
+-	header.len = count;
+-	header.hdr_size = sizeof(struct logger_entry);
+-
+-	/* null writes succeed, return zero */
+-	if (unlikely(!header.len))
+-		return 0;
+-
+-	mutex_lock(&log->mutex);
+-
+-	/*
+-	 * Fix up any readers, pulling them forward to the first readable
+-	 * entry after (what will be) the new write offset. We do this now
+-	 * because if we partially fail, we can end up with clobbered log
+-	 * entries that encroach on readable buffer.
+-	 */
+-	fix_up_readers(log, sizeof(struct logger_entry) + header.len);
+-
+-	len = min(sizeof(header), log->size - log->w_off);
+-	memcpy(log->buffer + log->w_off, &header, len);
+-	memcpy(log->buffer, (char *)&header + len, sizeof(header) - len);
+-
+-	/* Work with a copy until we are ready to commit the whole entry */
+-	w_off =  logger_offset(log, log->w_off + sizeof(struct logger_entry));
+-
+-	len = min(count, log->size - w_off);
+-
+-	if (copy_from_iter(log->buffer + w_off, len, from) != len) {
+-		/*
+-		 * Note that by not updating log->w_off, this abandons the
+-		 * portion of the new entry that *was* successfully
+-		 * copied, just above.  This is intentional to avoid
+-		 * message corruption from missing fragments.
+-		 */
+-		mutex_unlock(&log->mutex);
+-		return -EFAULT;
+-	}
+-
+-	if (copy_from_iter(log->buffer, count - len, from) != count - len) {
+-		mutex_unlock(&log->mutex);
+-		return -EFAULT;
+-	}
+-
+-	log->w_off = logger_offset(log, w_off + count);
+-	mutex_unlock(&log->mutex);
+-
+-	/* wake up any blocked readers */
+-	wake_up_interruptible(&log->wq);
+-
+-	return len;
+-}
+-
+-static struct logger_log *get_log_from_minor(int minor)
+-{
+-	struct logger_log *log;
+-
+-	list_for_each_entry(log, &log_list, logs)
+-		if (log->misc.minor == minor)
+-			return log;
+-	return NULL;
+-}
+-
+-/*
+- * logger_open - the log's open() file operation
+- *
+- * Note how near a no-op this is in the write-only case. Keep it that way!
+- */
+-static int logger_open(struct inode *inode, struct file *file)
+-{
+-	struct logger_log *log;
+-	int ret;
+-
+-	ret = nonseekable_open(inode, file);
+-	if (ret)
+-		return ret;
+-
+-	log = get_log_from_minor(MINOR(inode->i_rdev));
+-	if (!log)
+-		return -ENODEV;
+-
+-	if (file->f_mode & FMODE_READ) {
+-		struct logger_reader *reader;
+-
+-		reader = kmalloc(sizeof(struct logger_reader), GFP_KERNEL);
+-		if (!reader)
+-			return -ENOMEM;
+-
+-		reader->log = log;
+-		reader->r_ver = 1;
+-		reader->r_all = in_egroup_p(inode->i_gid) ||
+-			capable(CAP_SYSLOG);
+-
+-		INIT_LIST_HEAD(&reader->list);
+-
+-		mutex_lock(&log->mutex);
+-		reader->r_off = log->head;
+-		list_add_tail(&reader->list, &log->readers);
+-		mutex_unlock(&log->mutex);
+-
+-		file->private_data = reader;
+-	} else
+-		file->private_data = log;
+-
+-	return 0;
+-}
+-
+-/*
+- * logger_release - the log's release file operation
+- *
+- * Note this is a total no-op in the write-only case. Keep it that way!
+- */
+-static int logger_release(struct inode *ignored, struct file *file)
+-{
+-	if (file->f_mode & FMODE_READ) {
+-		struct logger_reader *reader = file->private_data;
+-		struct logger_log *log = reader->log;
+-
+-		mutex_lock(&log->mutex);
+-		list_del(&reader->list);
+-		mutex_unlock(&log->mutex);
+-
+-		kfree(reader);
+-	}
+-
+-	return 0;
+-}
+-
+-/*
+- * logger_poll - the log's poll file operation, for poll/select/epoll
+- *
+- * Note we always return POLLOUT, because you can always write() to the log.
+- * Note also that, strictly speaking, a return value of POLLIN does not
+- * guarantee that the log is readable without blocking, as there is a small
+- * chance that the writer can lap the reader in the interim between poll()
+- * returning and the read() request.
+- */
+-static unsigned int logger_poll(struct file *file, poll_table *wait)
+-{
+-	struct logger_reader *reader;
+-	struct logger_log *log;
+-	unsigned int ret = POLLOUT | POLLWRNORM;
+-
+-	if (!(file->f_mode & FMODE_READ))
+-		return ret;
+-
+-	reader = file->private_data;
+-	log = reader->log;
+-
+-	poll_wait(file, &log->wq, wait);
+-
+-	mutex_lock(&log->mutex);
+-	if (!reader->r_all)
+-		reader->r_off = get_next_entry_by_uid(log,
+-			reader->r_off, current_euid());
+-
+-	if (log->w_off != reader->r_off)
+-		ret |= POLLIN | POLLRDNORM;
+-	mutex_unlock(&log->mutex);
+-
+-	return ret;
+-}
+-
+-static long logger_set_version(struct logger_reader *reader, void __user *arg)
+-{
+-	int version;
+-
+-	if (copy_from_user(&version, arg, sizeof(int)))
+-		return -EFAULT;
+-
+-	if ((version < 1) || (version > 2))
+-		return -EINVAL;
+-
+-	reader->r_ver = version;
+-	return 0;
+-}
+-
+-static long logger_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+-{
+-	struct logger_log *log = file_get_log(file);
+-	struct logger_reader *reader;
+-	long ret = -EINVAL;
+-	void __user *argp = (void __user *) arg;
+-
+-	mutex_lock(&log->mutex);
+-
+-	switch (cmd) {
+-	case LOGGER_GET_LOG_BUF_SIZE:
+-		ret = log->size;
+-		break;
+-	case LOGGER_GET_LOG_LEN:
+-		if (!(file->f_mode & FMODE_READ)) {
+-			ret = -EBADF;
+-			break;
+-		}
+-		reader = file->private_data;
+-		if (log->w_off >= reader->r_off)
+-			ret = log->w_off - reader->r_off;
+-		else
+-			ret = (log->size - reader->r_off) + log->w_off;
+-		break;
+-	case LOGGER_GET_NEXT_ENTRY_LEN:
+-		if (!(file->f_mode & FMODE_READ)) {
+-			ret = -EBADF;
+-			break;
+-		}
+-		reader = file->private_data;
+-
+-		if (!reader->r_all)
+-			reader->r_off = get_next_entry_by_uid(log,
+-				reader->r_off, current_euid());
+-
+-		if (log->w_off != reader->r_off)
+-			ret = get_user_hdr_len(reader->r_ver) +
+-				get_entry_msg_len(log, reader->r_off);
+-		else
+-			ret = 0;
+-		break;
+-	case LOGGER_FLUSH_LOG:
+-		if (!(file->f_mode & FMODE_WRITE)) {
+-			ret = -EBADF;
+-			break;
+-		}
+-		if (!(in_egroup_p(file_inode(file)->i_gid) ||
+-				capable(CAP_SYSLOG))) {
+-			ret = -EPERM;
+-			break;
+-		}
+-		list_for_each_entry(reader, &log->readers, list)
+-			reader->r_off = log->w_off;
+-		log->head = log->w_off;
+-		ret = 0;
+-		break;
+-	case LOGGER_GET_VERSION:
+-		if (!(file->f_mode & FMODE_READ)) {
+-			ret = -EBADF;
+-			break;
+-		}
+-		reader = file->private_data;
+-		ret = reader->r_ver;
+-		break;
+-	case LOGGER_SET_VERSION:
+-		if (!(file->f_mode & FMODE_READ)) {
+-			ret = -EBADF;
+-			break;
+-		}
+-		reader = file->private_data;
+-		ret = logger_set_version(reader, argp);
+-		break;
+-	}
+-
+-	mutex_unlock(&log->mutex);
+-
+-	return ret;
+-}
+-
+-static const struct file_operations logger_fops = {
+-	.owner = THIS_MODULE,
+-	.read = logger_read,
+-	.write_iter = logger_write_iter,
+-	.poll = logger_poll,
+-	.unlocked_ioctl = logger_ioctl,
+-	.compat_ioctl = logger_ioctl,
+-	.open = logger_open,
+-	.release = logger_release,
+-};
+-
+-/*
+- * Log size must must be a power of two, and greater than
+- * (LOGGER_ENTRY_MAX_PAYLOAD + sizeof(struct logger_entry)).
+- */
+-static int __init create_log(char *log_name, int size)
+-{
+-	int ret = 0;
+-	struct logger_log *log;
+-	unsigned char *buffer;
+-
+-	buffer = vmalloc(size);
+-	if (buffer == NULL)
+-		return -ENOMEM;
+-
+-	log = kzalloc(sizeof(struct logger_log), GFP_KERNEL);
+-	if (log == NULL) {
+-		ret = -ENOMEM;
+-		goto out_free_buffer;
+-	}
+-	log->buffer = buffer;
+-
+-	log->misc.minor = MISC_DYNAMIC_MINOR;
+-	log->misc.name = kstrdup(log_name, GFP_KERNEL);
+-	if (log->misc.name == NULL) {
+-		ret = -ENOMEM;
+-		goto out_free_log;
+-	}
+-
+-	log->misc.fops = &logger_fops;
+-	log->misc.parent = NULL;
+-
+-	init_waitqueue_head(&log->wq);
+-	INIT_LIST_HEAD(&log->readers);
+-	mutex_init(&log->mutex);
+-	log->w_off = 0;
+-	log->head = 0;
+-	log->size = size;
+-
+-	INIT_LIST_HEAD(&log->logs);
+-	list_add_tail(&log->logs, &log_list);
+-
+-	/* finally, initialize the misc device for this log */
+-	ret = misc_register(&log->misc);
+-	if (unlikely(ret)) {
+-		pr_err("failed to register misc device for log '%s'!\n",
+-				log->misc.name);
+-		goto out_free_misc_name;
+-	}
+-
+-	pr_info("created %luK log '%s'\n",
+-		(unsigned long) log->size >> 10, log->misc.name);
+-
+-	return 0;
+-
+-out_free_misc_name:
+-	kfree(log->misc.name);
+-
+-out_free_log:
+-	kfree(log);
+-
+-out_free_buffer:
+-	vfree(buffer);
+-	return ret;
+-}
+-
+-static int __init logger_init(void)
+-{
+-	int ret;
+-
+-	ret = create_log(LOGGER_LOG_MAIN, 256*1024);
+-	if (unlikely(ret))
+-		goto out;
+-
+-	ret = create_log(LOGGER_LOG_EVENTS, 256*1024);
+-	if (unlikely(ret))
+-		goto out;
+-
+-	ret = create_log(LOGGER_LOG_RADIO, 256*1024);
+-	if (unlikely(ret))
+-		goto out;
+-
+-	ret = create_log(LOGGER_LOG_SYSTEM, 256*1024);
+-	if (unlikely(ret))
+-		goto out;
+-
+-out:
+-	return ret;
+-}
+-
+-static void __exit logger_exit(void)
+-{
+-	struct logger_log *current_log, *next_log;
+-
+-	list_for_each_entry_safe(current_log, next_log, &log_list, logs) {
+-		/* we have to delete all the entry inside log_list */
+-		misc_deregister(&current_log->misc);
+-		vfree(current_log->buffer);
+-		kfree(current_log->misc.name);
+-		list_del(&current_log->logs);
+-		kfree(current_log);
+-	}
+-}
+-
+-
+-device_initcall(logger_init);
+-module_exit(logger_exit);
+-
+-MODULE_LICENSE("GPL");
+-MODULE_AUTHOR("Robert Love, <rlove@google.com>");
+-MODULE_DESCRIPTION("Android Logger");
+diff --git a/drivers/staging/android/logger.h b/drivers/staging/android/logger.h
+deleted file mode 100644
+index 70af7d8..0000000
+--- a/drivers/staging/android/logger.h
++++ /dev/null
+@@ -1,89 +0,0 @@
+-/* include/linux/logger.h
+- *
+- * Copyright (C) 2007-2008 Google, Inc.
+- * Author: Robert Love <rlove@android.com>
+- *
+- * This software is licensed under the terms of the GNU General Public
+- * License version 2, as published by the Free Software Foundation, and
+- * may be copied, distributed, and modified under those terms.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- * GNU General Public License for more details.
+- *
+- */
+-
+-#ifndef _LINUX_LOGGER_H
+-#define _LINUX_LOGGER_H
+-
+-#include <linux/types.h>
+-#include <linux/ioctl.h>
+-
+-/**
+- * struct user_logger_entry_compat - defines a single entry that is given to a logger
+- * @len:	The length of the payload
+- * @__pad:	Two bytes of padding that appear to be required
+- * @pid:	The generating process' process ID
+- * @tid:	The generating process' thread ID
+- * @sec:	The number of seconds that have elapsed since the Epoch
+- * @nsec:	The number of nanoseconds that have elapsed since @sec
+- * @msg:	The message that is to be logged
+- *
+- * The userspace structure for version 1 of the logger_entry ABI.
+- * This structure is returned to userspace unless the caller requests
+- * an upgrade to a newer ABI version.
+- */
+-struct user_logger_entry_compat {
+-	__u16		len;
+-	__u16		__pad;
+-	__s32		pid;
+-	__s32		tid;
+-	__s32		sec;
+-	__s32		nsec;
+-	char		msg[0];
+-};
+-
+-/**
+- * struct logger_entry - defines a single entry that is given to a logger
+- * @len:	The length of the payload
+- * @hdr_size:	sizeof(struct logger_entry_v2)
+- * @pid:	The generating process' process ID
+- * @tid:	The generating process' thread ID
+- * @sec:	The number of seconds that have elapsed since the Epoch
+- * @nsec:	The number of nanoseconds that have elapsed since @sec
+- * @euid:	Effective UID of logger
+- * @msg:	The message that is to be logged
+- *
+- * The structure for version 2 of the logger_entry ABI.
+- * This structure is returned to userspace if ioctl(LOGGER_SET_VERSION)
+- * is called with version >= 2
+- */
+-struct logger_entry {
+-	__u16		len;
+-	__u16		hdr_size;
+-	__s32		pid;
+-	__s32		tid;
+-	__s32		sec;
+-	__s32		nsec;
+-	kuid_t		euid;
+-	char		msg[0];
+-};
+-
+-#define LOGGER_LOG_RADIO	"log_radio"	/* radio-related messages */
+-#define LOGGER_LOG_EVENTS	"log_events"	/* system/hardware events */
+-#define LOGGER_LOG_SYSTEM	"log_system"	/* system/framework messages */
+-#define LOGGER_LOG_MAIN		"log_main"	/* everything else */
+-
+-#define LOGGER_ENTRY_MAX_PAYLOAD	4076
+-
+-#define __LOGGERIO	0xAE
+-
+-#define LOGGER_GET_LOG_BUF_SIZE		_IO(__LOGGERIO, 1) /* size of log */
+-#define LOGGER_GET_LOG_LEN		_IO(__LOGGERIO, 2) /* used log len */
+-#define LOGGER_GET_NEXT_ENTRY_LEN	_IO(__LOGGERIO, 3) /* next entry len */
+-#define LOGGER_FLUSH_LOG		_IO(__LOGGERIO, 4) /* flush log */
+-#define LOGGER_GET_VERSION		_IO(__LOGGERIO, 5) /* abi version */
+-#define LOGGER_SET_VERSION		_IO(__LOGGERIO, 6) /* abi version */
+-
+-#endif /* _LINUX_LOGGER_H */
+diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c
+index b545d3d..ca92b60 100644
+--- a/drivers/staging/android/lowmemorykiller.c
++++ b/drivers/staging/android/lowmemorykiller.c
+@@ -39,7 +39,6 @@
+ #include <linux/sched.h>
+ #include <linux/swap.h>
+ #include <linux/rcupdate.h>
+-#include <linux/profile.h>
+ #include <linux/notifier.h>
+ 
+ static uint32_t lowmem_debug_level = 1;
+@@ -83,6 +82,7 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc)
+ 	int tasksize;
+ 	int i;
+ 	short min_score_adj = OOM_SCORE_ADJ_MAX + 1;
++	int minfree = 0;
+ 	int selected_tasksize = 0;
+ 	short selected_oom_score_adj;
+ 	int array_size = ARRAY_SIZE(lowmem_adj);
+@@ -96,8 +96,8 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc)
+ 	if (lowmem_minfree_size < array_size)
+ 		array_size = lowmem_minfree_size;
+ 	for (i = 0; i < array_size; i++) {
+-		if (other_free < lowmem_minfree[i] &&
+-		    other_file < lowmem_minfree[i]) {
++		minfree = lowmem_minfree[i];
++		if (other_free < minfree && other_file < minfree) {
+ 			min_score_adj = lowmem_adj[i];
+ 			break;
+ 		}
+@@ -152,13 +152,22 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc)
+ 		selected = p;
+ 		selected_tasksize = tasksize;
+ 		selected_oom_score_adj = oom_score_adj;
+-		lowmem_print(2, "select %d (%s), adj %hd, size %d, to kill\n",
+-			     p->pid, p->comm, oom_score_adj, tasksize);
++		lowmem_print(2, "select '%s' (%d), adj %hd, size %d, to kill\n",
++			     p->comm, p->pid, oom_score_adj, tasksize);
+ 	}
+ 	if (selected) {
+-		lowmem_print(1, "send sigkill to %d (%s), adj %hd, size %d\n",
+-			     selected->pid, selected->comm,
+-			     selected_oom_score_adj, selected_tasksize);
++		lowmem_print(1, "Killing '%s' (%d), adj %hd,\n" \
++				"   to free %ldkB on behalf of '%s' (%d) because\n" \
++				"   cache %ldkB is below limit %ldkB for oom_score_adj %hd\n" \
++				"   Free memory is %ldkB above reserved\n",
++			     selected->comm, selected->pid,
++			     selected_oom_score_adj,
++			     selected_tasksize * (long)(PAGE_SIZE / 1024),
++			     current->comm, current->pid,
++			     other_file * (long)(PAGE_SIZE / 1024),
++			     minfree * (long)(PAGE_SIZE / 1024),
++			     min_score_adj,
++			     other_free * (long)(PAGE_SIZE / 1024));
+ 		lowmem_deathpending_timeout = jiffies + HZ;
+ 		set_tsk_thread_flag(selected, TIF_MEMDIE);
+ 		send_sig(SIGKILL, selected, 0);
+@@ -188,9 +197,92 @@ static void __exit lowmem_exit(void)
+ 	unregister_shrinker(&lowmem_shrinker);
+ }
+ 
++#ifdef CONFIG_ANDROID_LOW_MEMORY_KILLER_AUTODETECT_OOM_ADJ_VALUES
++static short lowmem_oom_adj_to_oom_score_adj(short oom_adj)
++{
++	if (oom_adj == OOM_ADJUST_MAX)
++		return OOM_SCORE_ADJ_MAX;
++	else
++		return (oom_adj * OOM_SCORE_ADJ_MAX) / -OOM_DISABLE;
++}
++
++static void lowmem_autodetect_oom_adj_values(void)
++{
++	int i;
++	short oom_adj;
++	short oom_score_adj;
++	int array_size = ARRAY_SIZE(lowmem_adj);
++
++	if (lowmem_adj_size < array_size)
++		array_size = lowmem_adj_size;
++
++	if (array_size <= 0)
++		return;
++
++	oom_adj = lowmem_adj[array_size - 1];
++	if (oom_adj > OOM_ADJUST_MAX)
++		return;
++
++	oom_score_adj = lowmem_oom_adj_to_oom_score_adj(oom_adj);
++	if (oom_score_adj <= OOM_ADJUST_MAX)
++		return;
++
++	lowmem_print(1, "lowmem_shrink: convert oom_adj to oom_score_adj:\n");
++	for (i = 0; i < array_size; i++) {
++		oom_adj = lowmem_adj[i];
++		oom_score_adj = lowmem_oom_adj_to_oom_score_adj(oom_adj);
++		lowmem_adj[i] = oom_score_adj;
++		lowmem_print(1, "oom_adj %d => oom_score_adj %d\n",
++			     oom_adj, oom_score_adj);
++	}
++}
++
++static int lowmem_adj_array_set(const char *val, const struct kernel_param *kp)
++{
++	int ret;
++
++	ret = param_array_ops.set(val, kp);
++
++	/* HACK: Autodetect oom_adj values in lowmem_adj array */
++	lowmem_autodetect_oom_adj_values();
++
++	return ret;
++}
++
++static int lowmem_adj_array_get(char *buffer, const struct kernel_param *kp)
++{
++	return param_array_ops.get(buffer, kp);
++}
++
++static void lowmem_adj_array_free(void *arg)
++{
++	param_array_ops.free(arg);
++}
++
++static struct kernel_param_ops lowmem_adj_array_ops = {
++	.set = lowmem_adj_array_set,
++	.get = lowmem_adj_array_get,
++	.free = lowmem_adj_array_free,
++};
++
++static const struct kparam_array __param_arr_adj = {
++	.max = ARRAY_SIZE(lowmem_adj),
++	.num = &lowmem_adj_size,
++	.ops = &param_ops_short,
++	.elemsize = sizeof(lowmem_adj[0]),
++	.elem = lowmem_adj,
++};
++#endif
++
+ module_param_named(cost, lowmem_shrinker.seeks, int, S_IRUGO | S_IWUSR);
++#ifdef CONFIG_ANDROID_LOW_MEMORY_KILLER_AUTODETECT_OOM_ADJ_VALUES
++module_param_cb(adj, &lowmem_adj_array_ops,
++		.arr = &__param_arr_adj, S_IRUGO | S_IWUSR);
++__MODULE_PARM_TYPE(adj, "array of short");
++#else
+ module_param_array_named(adj, lowmem_adj, short, &lowmem_adj_size,
+ 			 S_IRUGO | S_IWUSR);
++#endif
+ module_param_array_named(minfree, lowmem_minfree, uint, &lowmem_minfree_size,
+ 			 S_IRUGO | S_IWUSR);
+ module_param_named(debug_level, lowmem_debug_level, uint, S_IRUGO | S_IWUSR);
+diff --git a/drivers/staging/android/uapi/android_alarm.h b/drivers/staging/android/uapi/android_alarm.h
+deleted file mode 100644
+index aa013f6..0000000
+--- a/drivers/staging/android/uapi/android_alarm.h
++++ /dev/null
+@@ -1,62 +0,0 @@
+-/* drivers/staging/android/uapi/android_alarm.h
+- *
+- * Copyright (C) 2006-2007 Google, Inc.
+- *
+- * This software is licensed under the terms of the GNU General Public
+- * License version 2, as published by the Free Software Foundation, and
+- * may be copied, distributed, and modified under those terms.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- * GNU General Public License for more details.
+- *
+- */
+-
+-#ifndef _UAPI_LINUX_ANDROID_ALARM_H
+-#define _UAPI_LINUX_ANDROID_ALARM_H
+-
+-#include <linux/ioctl.h>
+-#include <linux/time.h>
+-
+-enum android_alarm_type {
+-	/* return code bit numbers or set alarm arg */
+-	ANDROID_ALARM_RTC_WAKEUP,
+-	ANDROID_ALARM_RTC,
+-	ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP,
+-	ANDROID_ALARM_ELAPSED_REALTIME,
+-	ANDROID_ALARM_SYSTEMTIME,
+-
+-	ANDROID_ALARM_TYPE_COUNT,
+-
+-	/* return code bit numbers */
+-	/* ANDROID_ALARM_TIME_CHANGE = 16 */
+-};
+-
+-enum android_alarm_return_flags {
+-	ANDROID_ALARM_RTC_WAKEUP_MASK = 1U << ANDROID_ALARM_RTC_WAKEUP,
+-	ANDROID_ALARM_RTC_MASK = 1U << ANDROID_ALARM_RTC,
+-	ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP_MASK =
+-				1U << ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP,
+-	ANDROID_ALARM_ELAPSED_REALTIME_MASK =
+-				1U << ANDROID_ALARM_ELAPSED_REALTIME,
+-	ANDROID_ALARM_SYSTEMTIME_MASK = 1U << ANDROID_ALARM_SYSTEMTIME,
+-	ANDROID_ALARM_TIME_CHANGE_MASK = 1U << 16
+-};
+-
+-/* Disable alarm */
+-#define ANDROID_ALARM_CLEAR(type)           _IO('a', 0 | ((type) << 4))
+-
+-/* Ack last alarm and wait for next */
+-#define ANDROID_ALARM_WAIT                  _IO('a', 1)
+-
+-#define ALARM_IOW(c, type, size)            _IOW('a', (c) | ((type) << 4), size)
+-/* Set alarm */
+-#define ANDROID_ALARM_SET(type)             ALARM_IOW(2, type, struct timespec)
+-#define ANDROID_ALARM_SET_AND_WAIT(type)    ALARM_IOW(3, type, struct timespec)
+-#define ANDROID_ALARM_GET_TIME(type)        ALARM_IOW(4, type, struct timespec)
+-#define ANDROID_ALARM_SET_RTC               _IOW('a', 5, struct timespec)
+-#define ANDROID_ALARM_BASE_CMD(cmd)         (cmd & ~(_IOC(0, 0, 0xf0, 0)))
+-#define ANDROID_ALARM_IOCTL_TO_TYPE(cmd)    (_IOC_NR(cmd) >> 4)
+-
+-#endif
+diff --git a/drivers/staging/android/uapi/ashmem.h b/drivers/staging/android/uapi/ashmem.h
+index ba4743c..13df42d 100644
+--- a/drivers/staging/android/uapi/ashmem.h
++++ b/drivers/staging/android/uapi/ashmem.h
+@@ -13,6 +13,7 @@
+ #define _UAPI_LINUX_ASHMEM_H
+ 
+ #include <linux/ioctl.h>
++#include <linux/types.h>
+ 
+ #define ASHMEM_NAME_LEN		256
+ 
+diff --git a/drivers/staging/lustre/lustre/llite/llite_lib.c b/drivers/staging/lustre/lustre/llite/llite_lib.c
+index f4ca7b7..d9797ba 100644
+--- a/drivers/staging/lustre/lustre/llite/llite_lib.c
++++ b/drivers/staging/lustre/lustre/llite/llite_lib.c
+@@ -1434,6 +1434,10 @@ int ll_setattr_raw(struct dentry *dentry, struct iattr *attr, bool hsm_import)
+ 		spin_unlock(&lli->lli_lock);
+ 	}
+ 
++	rc = setattr_killpriv(dentry, attr);
++	if (rc)
++		return rc;
++
+ 	/* We always do an MDS RPC, even if we're only changing the size;
+ 	 * only the MDS knows whether truncate() should fail with -ETXTBUSY */
+ 
+diff --git a/drivers/switch/Kconfig b/drivers/switch/Kconfig
+new file mode 100644
+index 0000000..19404b6
+--- /dev/null
++++ b/drivers/switch/Kconfig
+@@ -0,0 +1,15 @@
++menuconfig SWITCH
++	tristate "Switch class support"
++	help
++	  Say Y here to enable switch class support. This allows
++	  monitoring switches by userspace via sysfs and uevent.
++
++if SWITCH
++
++config SWITCH_GPIO
++	tristate "GPIO Swith support"
++	depends on GPIOLIB
++	help
++	  Say Y here to enable GPIO based switch support.
++
++endif # SWITCH
+diff --git a/drivers/switch/Makefile b/drivers/switch/Makefile
+new file mode 100644
+index 0000000..f7606ed
+--- /dev/null
++++ b/drivers/switch/Makefile
+@@ -0,0 +1,4 @@
++# Switch Class Driver
++obj-$(CONFIG_SWITCH)		+= switch_class.o
++obj-$(CONFIG_SWITCH_GPIO)	+= switch_gpio.o
++
+diff --git a/drivers/switch/switch_class.c b/drivers/switch/switch_class.c
+new file mode 100644
+index 0000000..e373b62
+--- /dev/null
++++ b/drivers/switch/switch_class.c
+@@ -0,0 +1,174 @@
++/*
++ *  drivers/switch/switch_class.c
++ *
++ * Copyright (C) 2008 Google, Inc.
++ * Author: Mike Lockwood <lockwood@android.com>
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++*/
++
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/init.h>
++#include <linux/device.h>
++#include <linux/fs.h>
++#include <linux/err.h>
++#include <linux/switch.h>
++
++struct class *switch_class;
++static atomic_t device_count;
++
++static ssize_t state_show(struct device *dev, struct device_attribute *attr,
++		char *buf)
++{
++	struct switch_dev *sdev = (struct switch_dev *)
++		dev_get_drvdata(dev);
++
++	if (sdev->print_state) {
++		int ret = sdev->print_state(sdev, buf);
++		if (ret >= 0)
++			return ret;
++	}
++	return sprintf(buf, "%d\n", sdev->state);
++}
++
++static ssize_t name_show(struct device *dev, struct device_attribute *attr,
++		char *buf)
++{
++	struct switch_dev *sdev = (struct switch_dev *)
++		dev_get_drvdata(dev);
++
++	if (sdev->print_name) {
++		int ret = sdev->print_name(sdev, buf);
++		if (ret >= 0)
++			return ret;
++	}
++	return sprintf(buf, "%s\n", sdev->name);
++}
++
++static DEVICE_ATTR(state, S_IRUGO, state_show, NULL);
++static DEVICE_ATTR(name, S_IRUGO, name_show, NULL);
++
++void switch_set_state(struct switch_dev *sdev, int state)
++{
++	char name_buf[120];
++	char state_buf[120];
++	char *prop_buf;
++	char *envp[3];
++	int env_offset = 0;
++	int length;
++
++	if (sdev->state != state) {
++		sdev->state = state;
++
++		prop_buf = (char *)get_zeroed_page(GFP_KERNEL);
++		if (prop_buf) {
++			length = name_show(sdev->dev, NULL, prop_buf);
++			if (length > 0) {
++				if (prop_buf[length - 1] == '\n')
++					prop_buf[length - 1] = 0;
++				snprintf(name_buf, sizeof(name_buf),
++					"SWITCH_NAME=%s", prop_buf);
++				envp[env_offset++] = name_buf;
++			}
++			length = state_show(sdev->dev, NULL, prop_buf);
++			if (length > 0) {
++				if (prop_buf[length - 1] == '\n')
++					prop_buf[length - 1] = 0;
++				snprintf(state_buf, sizeof(state_buf),
++					"SWITCH_STATE=%s", prop_buf);
++				envp[env_offset++] = state_buf;
++			}
++			envp[env_offset] = NULL;
++			kobject_uevent_env(&sdev->dev->kobj, KOBJ_CHANGE, envp);
++			free_page((unsigned long)prop_buf);
++		} else {
++			printk(KERN_ERR "out of memory in switch_set_state\n");
++			kobject_uevent(&sdev->dev->kobj, KOBJ_CHANGE);
++		}
++	}
++}
++EXPORT_SYMBOL_GPL(switch_set_state);
++
++static int create_switch_class(void)
++{
++	if (!switch_class) {
++		switch_class = class_create(THIS_MODULE, "switch");
++		if (IS_ERR(switch_class))
++			return PTR_ERR(switch_class);
++		atomic_set(&device_count, 0);
++	}
++
++	return 0;
++}
++
++int switch_dev_register(struct switch_dev *sdev)
++{
++	int ret;
++
++	if (!switch_class) {
++		ret = create_switch_class();
++		if (ret < 0)
++			return ret;
++	}
++
++	sdev->index = atomic_inc_return(&device_count);
++	sdev->dev = device_create(switch_class, NULL,
++		MKDEV(0, sdev->index), NULL, sdev->name);
++	if (IS_ERR(sdev->dev))
++		return PTR_ERR(sdev->dev);
++
++	ret = device_create_file(sdev->dev, &dev_attr_state);
++	if (ret < 0)
++		goto err_create_file_1;
++	ret = device_create_file(sdev->dev, &dev_attr_name);
++	if (ret < 0)
++		goto err_create_file_2;
++
++	dev_set_drvdata(sdev->dev, sdev);
++	sdev->state = 0;
++	return 0;
++
++err_create_file_2:
++	device_remove_file(sdev->dev, &dev_attr_state);
++err_create_file_1:
++	device_destroy(switch_class, MKDEV(0, sdev->index));
++	printk(KERN_ERR "switch: Failed to register driver %s\n", sdev->name);
++
++	return ret;
++}
++EXPORT_SYMBOL_GPL(switch_dev_register);
++
++void switch_dev_unregister(struct switch_dev *sdev)
++{
++	device_remove_file(sdev->dev, &dev_attr_name);
++	device_remove_file(sdev->dev, &dev_attr_state);
++	device_destroy(switch_class, MKDEV(0, sdev->index));
++	dev_set_drvdata(sdev->dev, NULL);
++}
++EXPORT_SYMBOL_GPL(switch_dev_unregister);
++
++static int __init switch_class_init(void)
++{
++	return create_switch_class();
++}
++
++static void __exit switch_class_exit(void)
++{
++	class_destroy(switch_class);
++}
++
++module_init(switch_class_init);
++module_exit(switch_class_exit);
++
++MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>");
++MODULE_DESCRIPTION("Switch class driver");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/switch/switch_gpio.c b/drivers/switch/switch_gpio.c
+new file mode 100644
+index 0000000..621d62d
+--- /dev/null
++++ b/drivers/switch/switch_gpio.c
+@@ -0,0 +1,172 @@
++/*
++ *  drivers/switch/switch_gpio.c
++ *
++ * Copyright (C) 2008 Google, Inc.
++ * Author: Mike Lockwood <lockwood@android.com>
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++*/
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++#include <linux/switch.h>
++#include <linux/workqueue.h>
++#include <linux/gpio.h>
++
++struct gpio_switch_data {
++	struct switch_dev sdev;
++	unsigned gpio;
++	const char *name_on;
++	const char *name_off;
++	const char *state_on;
++	const char *state_off;
++	int irq;
++	struct work_struct work;
++};
++
++static void gpio_switch_work(struct work_struct *work)
++{
++	int state;
++	struct gpio_switch_data	*data =
++		container_of(work, struct gpio_switch_data, work);
++
++	state = gpio_get_value(data->gpio);
++	switch_set_state(&data->sdev, state);
++}
++
++static irqreturn_t gpio_irq_handler(int irq, void *dev_id)
++{
++	struct gpio_switch_data *switch_data =
++	    (struct gpio_switch_data *)dev_id;
++
++	schedule_work(&switch_data->work);
++	return IRQ_HANDLED;
++}
++
++static ssize_t switch_gpio_print_state(struct switch_dev *sdev, char *buf)
++{
++	struct gpio_switch_data	*switch_data =
++		container_of(sdev, struct gpio_switch_data, sdev);
++	const char *state;
++	if (switch_get_state(sdev))
++		state = switch_data->state_on;
++	else
++		state = switch_data->state_off;
++
++	if (state)
++		return sprintf(buf, "%s\n", state);
++	return -1;
++}
++
++static int gpio_switch_probe(struct platform_device *pdev)
++{
++	struct gpio_switch_platform_data *pdata = pdev->dev.platform_data;
++	struct gpio_switch_data *switch_data;
++	int ret = 0;
++
++	if (!pdata)
++		return -EBUSY;
++
++	switch_data = kzalloc(sizeof(struct gpio_switch_data), GFP_KERNEL);
++	if (!switch_data)
++		return -ENOMEM;
++
++	switch_data->sdev.name = pdata->name;
++	switch_data->gpio = pdata->gpio;
++	switch_data->name_on = pdata->name_on;
++	switch_data->name_off = pdata->name_off;
++	switch_data->state_on = pdata->state_on;
++	switch_data->state_off = pdata->state_off;
++	switch_data->sdev.print_state = switch_gpio_print_state;
++
++	ret = switch_dev_register(&switch_data->sdev);
++	if (ret < 0)
++		goto err_switch_dev_register;
++
++	ret = gpio_request(switch_data->gpio, pdev->name);
++	if (ret < 0)
++		goto err_request_gpio;
++
++	ret = gpio_direction_input(switch_data->gpio);
++	if (ret < 0)
++		goto err_set_gpio_input;
++
++	INIT_WORK(&switch_data->work, gpio_switch_work);
++
++	switch_data->irq = gpio_to_irq(switch_data->gpio);
++	if (switch_data->irq < 0) {
++		ret = switch_data->irq;
++		goto err_detect_irq_num_failed;
++	}
++
++	ret = request_irq(switch_data->irq, gpio_irq_handler,
++			  IRQF_TRIGGER_LOW, pdev->name, switch_data);
++	if (ret < 0)
++		goto err_request_irq;
++
++	/* Perform initial detection */
++	gpio_switch_work(&switch_data->work);
++
++	return 0;
++
++err_request_irq:
++err_detect_irq_num_failed:
++err_set_gpio_input:
++	gpio_free(switch_data->gpio);
++err_request_gpio:
++	switch_dev_unregister(&switch_data->sdev);
++err_switch_dev_register:
++	kfree(switch_data);
++
++	return ret;
++}
++
++static int gpio_switch_remove(struct platform_device *pdev)
++{
++	struct gpio_switch_data *switch_data = platform_get_drvdata(pdev);
++
++	cancel_work_sync(&switch_data->work);
++	gpio_free(switch_data->gpio);
++	switch_dev_unregister(&switch_data->sdev);
++	kfree(switch_data);
++
++	return 0;
++}
++
++static struct platform_driver gpio_switch_driver = {
++	.probe		= gpio_switch_probe,
++	.remove		= gpio_switch_remove,
++	.driver		= {
++		.name	= "switch-gpio",
++		.owner	= THIS_MODULE,
++	},
++};
++
++static int __init gpio_switch_init(void)
++{
++	return platform_driver_register(&gpio_switch_driver);
++}
++
++static void __exit gpio_switch_exit(void)
++{
++	platform_driver_unregister(&gpio_switch_driver);
++}
++
++module_init(gpio_switch_init);
++module_exit(gpio_switch_exit);
++
++MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>");
++MODULE_DESCRIPTION("GPIO Switch driver");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
+index f554d25..8b7d47f 100644
+--- a/drivers/thermal/Kconfig
++++ b/drivers/thermal/Kconfig
+@@ -42,6 +42,17 @@ config THERMAL_OF
+ 	  Say 'Y' here if you need to build thermal infrastructure
+ 	  based on device tree.
+ 
++config THERMAL_WRITABLE_TRIPS
++	bool "Enable writable trip points"
++	help
++	  This option allows the system integrator to choose whether
++	  trip temperatures can be changed from userspace. The
++	  writable trips need to be specified when setting up the
++	  thermal zone but the choice here takes precedence.
++
++	  Say 'Y' here if you would like to allow userspace tools to
++	  change trip temperatures.
++
+ choice
+ 	prompt "Default Thermal governor"
+ 	default THERMAL_DEFAULT_GOV_STEP_WISE
+@@ -71,6 +82,14 @@ config THERMAL_DEFAULT_GOV_USER_SPACE
+ 	  Select this if you want to let the user space manage the
+ 	  platform thermals.
+ 
++config THERMAL_DEFAULT_GOV_POWER_ALLOCATOR
++	bool "power_allocator"
++	select THERMAL_GOV_POWER_ALLOCATOR
++	help
++	  Select this if you want to control temperature based on
++	  system and device power allocation. This governor can only
++	  operate on cooling devices that implement the power API.
++
+ endchoice
+ 
+ config THERMAL_GOV_FAIR_SHARE
+@@ -99,6 +118,13 @@ config THERMAL_GOV_USER_SPACE
+ 	help
+ 	  Enable this to let the user space manage the platform thermals.
+ 
++config THERMAL_GOV_POWER_ALLOCATOR
++	bool "Power allocator thermal governor"
++	select THERMAL_POWER_ACTOR
++	help
++	  Enable this to manage platform thermals by dynamically
++	  allocating and limiting power to devices.
++
+ config CPU_THERMAL
+ 	bool "generic cpu cooling support"
+ 	depends on CPU_FREQ
+@@ -112,6 +138,18 @@ config CPU_THERMAL
+ 
+ 	  If you want this support, you should say Y here.
+ 
++config CLOCK_THERMAL
++	bool "Generic clock cooling support"
++	depends on COMMON_CLK
++	depends on PM_OPP
++	help
++	  This entry implements the generic clock cooling mechanism through
++	  frequency clipping. Typically used to cool off co-processors. The
++	  device that is configured to use this cooling mechanism will be
++	  controlled to reduce clock frequency whenever temperature is high.
++
++	  If you want this support, you should say Y here.
++
+ config THERMAL_EMULATION
+ 	bool "Thermal emulation mode support"
+ 	help
+@@ -185,6 +223,16 @@ config ARMADA_THERMAL
+ 	  Enable this option if you want to have support for thermal management
+ 	  controller present in Armada 370 and Armada XP SoC.
+ 
++config TEGRA_SOCTHERM
++	tristate "Tegra SOCTHERM thermal management"
++	depends on ARCH_TEGRA
++	help
++	  Enable this option for integrated thermal management support on NVIDIA
++	  Tegra124 systems-on-chip. The driver supports four thermal zones
++	  (CPU, GPU, MEM, PLLX). Cooling devices can be bound to the thermal
++	  zones to manage temperatures. This option is also required for the
++	  emergency thermal reset (thermtrip) feature to function.
++
+ config DB8500_CPUFREQ_COOLING
+ 	tristate "DB8500 cpufreq cooling"
+ 	depends on ARCH_U8500
+diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
+index 39c4fe8..dae37c0 100644
+--- a/drivers/thermal/Makefile
++++ b/drivers/thermal/Makefile
+@@ -14,10 +14,14 @@ thermal_sys-$(CONFIG_THERMAL_GOV_FAIR_SHARE)	+= fair_share.o
+ thermal_sys-$(CONFIG_THERMAL_GOV_BANG_BANG)	+= gov_bang_bang.o
+ thermal_sys-$(CONFIG_THERMAL_GOV_STEP_WISE)	+= step_wise.o
+ thermal_sys-$(CONFIG_THERMAL_GOV_USER_SPACE)	+= user_space.o
++thermal_sys-$(CONFIG_THERMAL_GOV_POWER_ALLOCATOR)	+= power_allocator.o
+ 
+ # cpufreq cooling
+ thermal_sys-$(CONFIG_CPU_THERMAL)	+= cpu_cooling.o
+ 
++# clock cooling
++thermal_sys-$(CONFIG_CLOCK_THERMAL)	+= clock_cooling.o
++
+ # platform thermal drivers
+ obj-$(CONFIG_SPEAR_THERMAL)	+= spear_thermal.o
+ obj-$(CONFIG_RCAR_THERMAL)	+= rcar_thermal.o
+@@ -34,3 +38,4 @@ obj-$(CONFIG_INTEL_SOC_DTS_THERMAL)	+= intel_soc_dts_thermal.o
+ obj-$(CONFIG_TI_SOC_THERMAL)	+= ti-soc-thermal/
+ obj-$(CONFIG_INT340X_THERMAL)  += int340x_thermal/
+ obj-$(CONFIG_ST_THERMAL)	+= st/
++obj-$(CONFIG_TEGRA_SOCTHERM)	+= tegra_soctherm.o
+diff --git a/drivers/thermal/clock_cooling.c b/drivers/thermal/clock_cooling.c
+new file mode 100644
+index 0000000..1b4ff0f
+--- /dev/null
++++ b/drivers/thermal/clock_cooling.c
+@@ -0,0 +1,485 @@
++/*
++ *  drivers/thermal/clock_cooling.c
++ *
++ *  Copyright (C) 2014 Eduardo Valentin <edubezval@gmail.com>
++ *
++ *  Copyright (C) 2013	Texas Instruments Inc.
++ *  Contact:  Eduardo Valentin <eduardo.valentin@ti.com>
++ *
++ *  Highly based on cpu_cooling.c.
++ *  Copyright (C) 2012	Samsung Electronics Co., Ltd(http://www.samsung.com)
++ *  Copyright (C) 2012  Amit Daniel <amit.kachhap@linaro.org>
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation; version 2 of the License.
++ *
++ *  This program is distributed in the hope that it will be useful, but
++ *  WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++ *  General Public License for more details.
++ */
++#include <linux/clk.h>
++#include <linux/cpufreq.h>
++#include <linux/device.h>
++#include <linux/err.h>
++#include <linux/idr.h>
++#include <linux/mutex.h>
++#include <linux/pm_opp.h>
++#include <linux/slab.h>
++#include <linux/thermal.h>
++#include <linux/clock_cooling.h>
++
++/**
++ * struct clock_cooling_device - data for cooling device with clock
++ * @id: unique integer value corresponding to each clock_cooling_device
++ *	registered.
++ * @dev: struct device pointer to the device being used to cool off using
++ *       clock frequencies.
++ * @cdev: thermal_cooling_device pointer to keep track of the
++ *	registered cooling device.
++ * @clk_rate_change_nb: reference to notifier block used to receive clock
++ *                      rate changes.
++ * @freq_table: frequency table used to keep track of available frequencies.
++ * @clock_state: integer value representing the current state of clock
++ *	cooling	devices.
++ * @clock_val: integer value representing the absolute value of the clipped
++ *	frequency.
++ * @clk: struct clk reference used to enforce clock limits.
++ * @lock: mutex lock to protect this struct.
++ *
++ * This structure is required for keeping information of each
++ * clock_cooling_device registered. In order to prevent corruption of this a
++ * mutex @lock is used.
++ */
++struct clock_cooling_device {
++	int id;
++	struct device *dev;
++	struct thermal_cooling_device *cdev;
++	struct notifier_block clk_rate_change_nb;
++	struct cpufreq_frequency_table *freq_table;
++	unsigned long clock_state;
++	unsigned long clock_val;
++	struct clk *clk;
++	struct mutex lock; /* lock to protect the content of this struct */
++};
++#define to_clock_cooling_device(x) \
++		container_of(x, struct clock_cooling_device, clk_rate_change_nb)
++static DEFINE_IDR(clock_idr);
++static DEFINE_MUTEX(cooling_clock_lock);
++
++/**
++ * clock_cooling_get_idr - function to get an unique id.
++ * @id: int * value generated by this function.
++ *
++ * This function will populate @id with an unique
++ * id, using the idr API.
++ *
++ * Return: 0 on success, an error code on failure.
++ */
++static int clock_cooling_get_idr(int *id)
++{
++	int ret;
++
++	mutex_lock(&cooling_clock_lock);
++	ret = idr_alloc(&clock_idr, NULL, 0, 0, GFP_KERNEL);
++	mutex_unlock(&cooling_clock_lock);
++	if (unlikely(ret < 0))
++		return ret;
++	*id = ret;
++
++	return 0;
++}
++
++/**
++ * release_idr - function to free the unique id.
++ * @id: int value representing the unique id.
++ */
++static void release_idr(int id)
++{
++	mutex_lock(&cooling_clock_lock);
++	idr_remove(&clock_idr, id);
++	mutex_unlock(&cooling_clock_lock);
++}
++
++/* Below code defines functions to be used for clock as cooling device */
++
++enum clock_cooling_property {
++	GET_LEVEL,
++	GET_FREQ,
++	GET_MAXL,
++};
++
++/**
++ * clock_cooling_get_property - fetch a property of interest for a give cpu.
++ * @ccdev: clock cooling device reference
++ * @input: query parameter
++ * @output: query return
++ * @property: type of query (frequency, level, max level)
++ *
++ * This is the common function to
++ * 1. get maximum clock cooling states
++ * 2. translate frequency to cooling state
++ * 3. translate cooling state to frequency
++ * Note that the code may be not in good shape
++ * but it is written in this way in order to:
++ * a) reduce duplicate code as most of the code can be shared.
++ * b) make sure the logic is consistent when translating between
++ *    cooling states and frequencies.
++ *
++ * Return: 0 on success, -EINVAL when invalid parameters are passed.
++ */
++static int clock_cooling_get_property(struct clock_cooling_device *ccdev,
++				      unsigned long input,
++				      unsigned long *output,
++				      enum clock_cooling_property property)
++{
++	int i;
++	unsigned long max_level = 0, level = 0;
++	unsigned int freq = CPUFREQ_ENTRY_INVALID;
++	int descend = -1;
++	struct cpufreq_frequency_table *pos, *table = ccdev->freq_table;
++
++	if (!output)
++		return -EINVAL;
++
++	if (!table)
++		return -EINVAL;
++
++	cpufreq_for_each_valid_entry(pos, table) {
++		/* ignore duplicate entry */
++		if (freq == pos->frequency)
++			continue;
++
++		/* get the frequency order */
++		if (freq != CPUFREQ_ENTRY_INVALID && descend == -1)
++			descend = freq > pos->frequency;
++
++		freq = pos->frequency;
++		max_level++;
++	}
++
++	/* No valid cpu frequency entry */
++	if (max_level == 0)
++		return -EINVAL;
++
++	/* max_level is an index, not a counter */
++	max_level--;
++
++	/* get max level */
++	if (property == GET_MAXL) {
++		*output = max_level;
++		return 0;
++	}
++
++	if (property == GET_FREQ)
++		level = descend ? input : (max_level - input);
++
++	i = 0;
++	cpufreq_for_each_valid_entry(pos, table) {
++		/* ignore duplicate entry */
++		if (freq == pos->frequency)
++			continue;
++
++		/* now we have a valid frequency entry */
++		freq = pos->frequency;
++
++		if (property == GET_LEVEL && (unsigned int)input == freq) {
++			/* get level by frequency */
++			*output = descend ? i : (max_level - i);
++			return 0;
++		}
++		if (property == GET_FREQ && level == i) {
++			/* get frequency by level */
++			*output = freq;
++			return 0;
++		}
++		i++;
++	}
++
++	return -EINVAL;
++}
++
++/**
++ * clock_cooling_get_level - return the cooling level of given clock cooling.
++ * @cdev: reference of a thermal cooling device of used as clock cooling device
++ * @freq: the frequency of interest
++ *
++ * This function will match the cooling level corresponding to the
++ * requested @freq and return it.
++ *
++ * Return: The matched cooling level on success or THERMAL_CSTATE_INVALID
++ * otherwise.
++ */
++unsigned long clock_cooling_get_level(struct thermal_cooling_device *cdev,
++				      unsigned long freq)
++{
++	struct clock_cooling_device *ccdev = cdev->devdata;
++	unsigned long val;
++
++	if (clock_cooling_get_property(ccdev, (unsigned long)freq, &val,
++				       GET_LEVEL))
++		return THERMAL_CSTATE_INVALID;
++
++	return val;
++}
++EXPORT_SYMBOL_GPL(clock_cooling_get_level);
++
++/**
++ * clock_cooling_get_frequency - get the absolute value of frequency from level.
++ * @ccdev: clock cooling device reference
++ * @level: cooling level
++ *
++ * This function matches cooling level with frequency. Based on a cooling level
++ * of frequency, equals cooling state of cpu cooling device, it will return
++ * the corresponding frequency.
++ *	e.g level=0 --> 1st MAX FREQ, level=1 ---> 2nd MAX FREQ, .... etc
++ *
++ * Return: 0 on error, the corresponding frequency otherwise.
++ */
++static unsigned long
++clock_cooling_get_frequency(struct clock_cooling_device *ccdev,
++			    unsigned long level)
++{
++	int ret = 0;
++	unsigned long freq;
++
++	ret = clock_cooling_get_property(ccdev, level, &freq, GET_FREQ);
++	if (ret)
++		return 0;
++
++	return freq;
++}
++
++/**
++ * clock_cooling_apply - function to apply frequency clipping.
++ * @ccdev: clock_cooling_device pointer containing frequency clipping data.
++ * @cooling_state: value of the cooling state.
++ *
++ * Function used to make sure the clock layer is aware of current thermal
++ * limits. The limits are applied by updating the clock rate in case it is
++ * higher than the corresponding frequency based on the requested cooling_state.
++ *
++ * Return: 0 on success, an error code otherwise (-EINVAL in case wrong
++ * cooling state).
++ */
++static int clock_cooling_apply(struct clock_cooling_device *ccdev,
++			       unsigned long cooling_state)
++{
++	unsigned long clip_freq, cur_freq;
++	int ret = 0;
++
++	/* Here we write the clipping */
++	/* Check if the old cooling action is same as new cooling action */
++	if (ccdev->clock_state == cooling_state)
++		return 0;
++
++	clip_freq = clock_cooling_get_frequency(ccdev, cooling_state);
++	if (!clip_freq)
++		return -EINVAL;
++
++	cur_freq = clk_get_rate(ccdev->clk);
++
++	mutex_lock(&ccdev->lock);
++	ccdev->clock_state = cooling_state;
++	ccdev->clock_val = clip_freq;
++	/* enforce clock level */
++	if (cur_freq > clip_freq)
++		ret = clk_set_rate(ccdev->clk, clip_freq);
++	mutex_unlock(&ccdev->lock);
++
++	return ret;
++}
++
++/**
++ * clock_cooling_clock_notifier - notifier callback on clock rate changes.
++ * @nb:	struct notifier_block * with callback info.
++ * @event: value showing clock event for which this function invoked.
++ * @data: callback-specific data
++ *
++ * Callback to hijack the notification on clock transition.
++ * Every time there is a clock change, we intercept all pre change events
++ * and block the transition in case the new rate infringes thermal limits.
++ *
++ * Return: NOTIFY_DONE (success) or NOTIFY_BAD (new_rate > thermal limit).
++ */
++static int clock_cooling_clock_notifier(struct notifier_block *nb,
++					unsigned long event, void *data)
++{
++	struct clk_notifier_data *ndata = data;
++	struct clock_cooling_device *ccdev = to_clock_cooling_device(nb);
++
++	switch (event) {
++	case PRE_RATE_CHANGE:
++		/*
++		 * checks on current state
++		 * TODO: current method is not best we can find as it
++		 * allows possibly voltage transitions, in case DVFS
++		 * layer is also hijacking clock pre notifications.
++		 */
++		if (ndata->new_rate > ccdev->clock_val)
++			return NOTIFY_BAD;
++		/* fall through */
++	case POST_RATE_CHANGE:
++	case ABORT_RATE_CHANGE:
++	default:
++		return NOTIFY_DONE;
++	}
++}
++
++/* clock cooling device thermal callback functions are defined below */
++
++/**
++ * clock_cooling_get_max_state - callback function to get the max cooling state.
++ * @cdev: thermal cooling device pointer.
++ * @state: fill this variable with the max cooling state.
++ *
++ * Callback for the thermal cooling device to return the clock
++ * max cooling state.
++ *
++ * Return: 0 on success, an error code otherwise.
++ */
++static int clock_cooling_get_max_state(struct thermal_cooling_device *cdev,
++				       unsigned long *state)
++{
++	struct clock_cooling_device *ccdev = cdev->devdata;
++	unsigned long count = 0;
++	int ret;
++
++	ret = clock_cooling_get_property(ccdev, 0, &count, GET_MAXL);
++	if (!ret)
++		*state = count;
++
++	return ret;
++}
++
++/**
++ * clock_cooling_get_cur_state - function to get the current cooling state.
++ * @cdev: thermal cooling device pointer.
++ * @state: fill this variable with the current cooling state.
++ *
++ * Callback for the thermal cooling device to return the clock
++ * current cooling state.
++ *
++ * Return: 0 (success)
++ */
++static int clock_cooling_get_cur_state(struct thermal_cooling_device *cdev,
++				       unsigned long *state)
++{
++	struct clock_cooling_device *ccdev = cdev->devdata;
++
++	*state = ccdev->clock_state;
++
++	return 0;
++}
++
++/**
++ * clock_cooling_set_cur_state - function to set the current cooling state.
++ * @cdev: thermal cooling device pointer.
++ * @state: set this variable to the current cooling state.
++ *
++ * Callback for the thermal cooling device to change the clock cooling
++ * current cooling state.
++ *
++ * Return: 0 on success, an error code otherwise.
++ */
++static int clock_cooling_set_cur_state(struct thermal_cooling_device *cdev,
++				       unsigned long state)
++{
++	struct clock_cooling_device *clock_device = cdev->devdata;
++
++	return clock_cooling_apply(clock_device, state);
++}
++
++/* Bind clock callbacks to thermal cooling device ops */
++static struct thermal_cooling_device_ops const clock_cooling_ops = {
++	.get_max_state = clock_cooling_get_max_state,
++	.get_cur_state = clock_cooling_get_cur_state,
++	.set_cur_state = clock_cooling_set_cur_state,
++};
++
++/**
++ * clock_cooling_register - function to create clock cooling device.
++ * @dev: struct device pointer to the device used as clock cooling device.
++ * @clock_name: string containing the clock used as cooling mechanism.
++ *
++ * This interface function registers the clock cooling device with the name
++ * "thermal-clock-%x". The cooling device is based on clock frequencies.
++ * The struct device is assumed to be capable of DVFS transitions.
++ * The OPP layer is used to fetch and fill the available frequencies for
++ * the referred device. The ordered frequency table is used to control
++ * the clock cooling device cooling states and to limit clock transitions
++ * based on the cooling state requested by the thermal framework.
++ *
++ * Return: a valid struct thermal_cooling_device pointer on success,
++ * on failure, it returns a corresponding ERR_PTR().
++ */
++struct thermal_cooling_device *
++clock_cooling_register(struct device *dev, const char *clock_name)
++{
++	struct thermal_cooling_device *cdev;
++	struct clock_cooling_device *ccdev = NULL;
++	char dev_name[THERMAL_NAME_LENGTH];
++	int ret = 0;
++
++	ccdev = devm_kzalloc(dev, sizeof(*ccdev), GFP_KERNEL);
++	if (!ccdev)
++		return ERR_PTR(-ENOMEM);
++
++	ccdev->dev = dev;
++	ccdev->clk = devm_clk_get(dev, clock_name);
++	if (IS_ERR(ccdev->clk))
++		return ERR_CAST(ccdev->clk);
++
++	ret = clock_cooling_get_idr(&ccdev->id);
++	if (ret)
++		return ERR_PTR(-EINVAL);
++
++	snprintf(dev_name, sizeof(dev_name), "thermal-clock-%d", ccdev->id);
++
++	cdev = thermal_cooling_device_register(dev_name, ccdev,
++					       &clock_cooling_ops);
++	if (IS_ERR(cdev)) {
++		release_idr(ccdev->id);
++		return ERR_PTR(-EINVAL);
++	}
++	ccdev->cdev = cdev;
++	ccdev->clk_rate_change_nb.notifier_call = clock_cooling_clock_notifier;
++
++	/* Assuming someone has already filled the opp table for this device */
++	ret = dev_pm_opp_init_cpufreq_table(dev, &ccdev->freq_table);
++	if (ret) {
++		release_idr(ccdev->id);
++		return ERR_PTR(ret);
++	}
++	ccdev->clock_state = 0;
++	ccdev->clock_val = clock_cooling_get_frequency(ccdev, 0);
++
++	clk_notifier_register(ccdev->clk, &ccdev->clk_rate_change_nb);
++
++	return cdev;
++}
++EXPORT_SYMBOL_GPL(clock_cooling_register);
++
++/**
++ * clock_cooling_unregister - function to remove clock cooling device.
++ * @cdev: thermal cooling device pointer.
++ *
++ * This interface function unregisters the "thermal-clock-%x" cooling device.
++ */
++void clock_cooling_unregister(struct thermal_cooling_device *cdev)
++{
++	struct clock_cooling_device *ccdev;
++
++	if (!cdev)
++		return;
++
++	ccdev = cdev->devdata;
++
++	clk_notifier_unregister(ccdev->clk, &ccdev->clk_rate_change_nb);
++	dev_pm_opp_free_cpufreq_table(ccdev->dev, &ccdev->freq_table);
++
++	thermal_cooling_device_unregister(ccdev->cdev);
++	release_idr(ccdev->id);
++}
++EXPORT_SYMBOL_GPL(clock_cooling_unregister);
+diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c
+index ad09e51..6509c61 100644
+--- a/drivers/thermal/cpu_cooling.c
++++ b/drivers/thermal/cpu_cooling.c
+@@ -4,6 +4,8 @@
+  *  Copyright (C) 2012	Samsung Electronics Co., Ltd(http://www.samsung.com)
+  *  Copyright (C) 2012  Amit Daniel <amit.kachhap@linaro.org>
+  *
++ *  Copyright (C) 2014  Viresh Kumar <viresh.kumar@linaro.org>
++ *
+  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  *  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
+@@ -24,10 +26,40 @@
+ #include <linux/thermal.h>
+ #include <linux/cpufreq.h>
+ #include <linux/err.h>
++#include <linux/pm_opp.h>
+ #include <linux/slab.h>
+ #include <linux/cpu.h>
+ #include <linux/cpu_cooling.h>
+ 
++#include <trace/events/thermal.h>
++
++/*
++ * Cooling state <-> CPUFreq frequency
++ *
++ * Cooling states are translated to frequencies throughout this driver and this
++ * is the relation between them.
++ *
++ * Highest cooling state corresponds to lowest possible frequency.
++ *
++ * i.e.
++ *	level 0 --> 1st Max Freq
++ *	level 1 --> 2nd Max Freq
++ *	...
++ */
++
++/**
++ * struct power_table - frequency to power conversion
++ * @frequency:	frequency in KHz
++ * @power:	power in mW
++ *
++ * This structure is built when the cooling device registers and helps
++ * in translating frequency to power and viceversa.
++ */
++struct power_table {
++	u32 frequency;
++	u32 power;
++};
++
+ /**
+  * struct cpufreq_cooling_device - data for cooling device with cpufreq
+  * @id: unique integer value corresponding to each cpufreq_cooling_device
+@@ -38,25 +70,43 @@
+  *	cooling	devices.
+  * @cpufreq_val: integer value representing the absolute value of the clipped
+  *	frequency.
++ * @max_level: maximum cooling level. One less than total number of valid
++ *	cpufreq frequencies.
+  * @allowed_cpus: all the cpus involved for this cpufreq_cooling_device.
++ * @node: list_head to link all cpufreq_cooling_device together.
++ * @last_load: load measured by the latest call to cpufreq_get_actual_power()
++ * @time_in_idle: previous reading of the absolute time that this cpu was idle
++ * @time_in_idle_timestamp: wall time of the last invocation of
++ *	get_cpu_idle_time_us()
++ * @dyn_power_table: array of struct power_table for frequency to power
++ *	conversion, sorted in ascending order.
++ * @dyn_power_table_entries: number of entries in the @dyn_power_table array
++ * @cpu_dev: the first cpu_device from @allowed_cpus that has OPPs registered
++ * @plat_get_static_power: callback to calculate the static power
+  *
+- * This structure is required for keeping information of each
+- * cpufreq_cooling_device registered. In order to prevent corruption of this a
+- * mutex lock cooling_cpufreq_lock is used.
++ * This structure is required for keeping information of each registered
++ * cpufreq_cooling_device.
+  */
+ struct cpufreq_cooling_device {
+ 	int id;
+ 	struct thermal_cooling_device *cool_dev;
+ 	unsigned int cpufreq_state;
+ 	unsigned int cpufreq_val;
++	unsigned int max_level;
++	unsigned int *freq_table;	/* In descending order */
+ 	struct cpumask allowed_cpus;
+ 	struct list_head node;
++	u32 last_load;
++	u64 *time_in_idle;
++	u64 *time_in_idle_timestamp;
++	struct power_table *dyn_power_table;
++	int dyn_power_table_entries;
++	struct device *cpu_dev;
++	get_static_t plat_get_static_power;
+ };
+ static DEFINE_IDR(cpufreq_idr);
+ static DEFINE_MUTEX(cooling_cpufreq_lock);
+ 
+-static unsigned int cpufreq_dev_count;
+-
+ static LIST_HEAD(cpufreq_dev_list);
+ 
+ /**
+@@ -98,120 +148,30 @@ static void release_idr(struct idr *idr, int id)
+ /* Below code defines functions to be used for cpufreq as cooling device */
+ 
+ /**
+- * is_cpufreq_valid - function to check frequency transitioning capability.
+- * @cpu: cpu for which check is needed.
++ * get_level: Find the level for a particular frequency
++ * @cpufreq_dev: cpufreq_dev for which the property is required
++ * @freq: Frequency
+  *
+- * This function will check the current state of the system if
+- * it is capable of changing the frequency for a given @cpu.
+- *
+- * Return: 0 if the system is not currently capable of changing
+- * the frequency of given cpu. !0 in case the frequency is changeable.
+- */
+-static int is_cpufreq_valid(int cpu)
+-{
+-	struct cpufreq_policy policy;
+-
+-	return !cpufreq_get_policy(&policy, cpu);
+-}
+-
+-enum cpufreq_cooling_property {
+-	GET_LEVEL,
+-	GET_FREQ,
+-	GET_MAXL,
+-};
+-
+-/**
+- * get_property - fetch a property of interest for a give cpu.
+- * @cpu: cpu for which the property is required
+- * @input: query parameter
+- * @output: query return
+- * @property: type of query (frequency, level, max level)
+- *
+- * This is the common function to
+- * 1. get maximum cpu cooling states
+- * 2. translate frequency to cooling state
+- * 3. translate cooling state to frequency
+- * Note that the code may be not in good shape
+- * but it is written in this way in order to:
+- * a) reduce duplicate code as most of the code can be shared.
+- * b) make sure the logic is consistent when translating between
+- *    cooling states and frequencies.
+- *
+- * Return: 0 on success, -EINVAL when invalid parameters are passed.
++ * Return: level on success, THERMAL_CSTATE_INVALID on error.
+  */
+-static int get_property(unsigned int cpu, unsigned long input,
+-			unsigned int *output,
+-			enum cpufreq_cooling_property property)
++static unsigned long get_level(struct cpufreq_cooling_device *cpufreq_dev,
++			       unsigned int freq)
+ {
+-	int i;
+-	unsigned long max_level = 0, level = 0;
+-	unsigned int freq = CPUFREQ_ENTRY_INVALID;
+-	int descend = -1;
+-	struct cpufreq_frequency_table *pos, *table =
+-					cpufreq_frequency_get_table(cpu);
+-
+-	if (!output)
+-		return -EINVAL;
+-
+-	if (!table)
+-		return -EINVAL;
+-
+-	cpufreq_for_each_valid_entry(pos, table) {
+-		/* ignore duplicate entry */
+-		if (freq == pos->frequency)
+-			continue;
+-
+-		/* get the frequency order */
+-		if (freq != CPUFREQ_ENTRY_INVALID && descend == -1)
+-			descend = freq > pos->frequency;
+-
+-		freq = pos->frequency;
+-		max_level++;
+-	}
+-
+-	/* No valid cpu frequency entry */
+-	if (max_level == 0)
+-		return -EINVAL;
++	unsigned long level;
+ 
+-	/* max_level is an index, not a counter */
+-	max_level--;
+-
+-	/* get max level */
+-	if (property == GET_MAXL) {
+-		*output = (unsigned int)max_level;
+-		return 0;
+-	}
+-
+-	if (property == GET_FREQ)
+-		level = descend ? input : (max_level - input);
+-
+-	i = 0;
+-	cpufreq_for_each_valid_entry(pos, table) {
+-		/* ignore duplicate entry */
+-		if (freq == pos->frequency)
+-			continue;
+-
+-		/* now we have a valid frequency entry */
+-		freq = pos->frequency;
++	for (level = 0; level <= cpufreq_dev->max_level; level++) {
++		if (freq == cpufreq_dev->freq_table[level])
++			return level;
+ 
+-		if (property == GET_LEVEL && (unsigned int)input == freq) {
+-			/* get level by frequency */
+-			*output = descend ? i : (max_level - i);
+-			return 0;
+-		}
+-		if (property == GET_FREQ && level == i) {
+-			/* get frequency by level */
+-			*output = freq;
+-			return 0;
+-		}
+-		i++;
++		if (freq > cpufreq_dev->freq_table[level])
++			break;
+ 	}
+ 
+-	return -EINVAL;
++	return THERMAL_CSTATE_INVALID;
+ }
+ 
+ /**
+- * cpufreq_cooling_get_level - for a give cpu, return the cooling level.
++ * cpufreq_cooling_get_level - for a given cpu, return the cooling level.
+  * @cpu: cpu for which the level is required
+  * @freq: the frequency of interest
+  *
+@@ -223,119 +183,272 @@ static int get_property(unsigned int cpu, unsigned long input,
+  */
+ unsigned long cpufreq_cooling_get_level(unsigned int cpu, unsigned int freq)
+ {
+-	unsigned int val;
++	struct cpufreq_cooling_device *cpufreq_dev;
+ 
+-	if (get_property(cpu, (unsigned long)freq, &val, GET_LEVEL))
+-		return THERMAL_CSTATE_INVALID;
++	mutex_lock(&cooling_cpufreq_lock);
++	list_for_each_entry(cpufreq_dev, &cpufreq_dev_list, node) {
++		if (cpumask_test_cpu(cpu, &cpufreq_dev->allowed_cpus)) {
++			mutex_unlock(&cooling_cpufreq_lock);
++			return get_level(cpufreq_dev, freq);
++		}
++	}
++	mutex_unlock(&cooling_cpufreq_lock);
+ 
+-	return (unsigned long)val;
++	pr_err("%s: cpu:%d not part of any cooling device\n", __func__, cpu);
++	return THERMAL_CSTATE_INVALID;
+ }
+ EXPORT_SYMBOL_GPL(cpufreq_cooling_get_level);
+ 
+ /**
+- * get_cpu_frequency - get the absolute value of frequency from level.
+- * @cpu: cpu for which frequency is fetched.
+- * @level: cooling level
++ * cpufreq_thermal_notifier - notifier callback for cpufreq policy change.
++ * @nb:	struct notifier_block * with callback info.
++ * @event: value showing cpufreq event for which this function invoked.
++ * @data: callback-specific data
+  *
+- * This function matches cooling level with frequency. Based on a cooling level
+- * of frequency, equals cooling state of cpu cooling device, it will return
+- * the corresponding frequency.
+- *	e.g level=0 --> 1st MAX FREQ, level=1 ---> 2nd MAX FREQ, .... etc
++ * Callback to hijack the notification on cpufreq policy transition.
++ * Every time there is a change in policy, we will intercept and
++ * update the cpufreq policy with thermal constraints.
+  *
+- * Return: 0 on error, the corresponding frequency otherwise.
++ * Return: 0 (success)
+  */
+-static unsigned int get_cpu_frequency(unsigned int cpu, unsigned long level)
++static int cpufreq_thermal_notifier(struct notifier_block *nb,
++				    unsigned long event, void *data)
+ {
+-	int ret = 0;
+-	unsigned int freq;
++	struct cpufreq_policy *policy = data;
++	unsigned long max_freq = 0;
++	struct cpufreq_cooling_device *cpufreq_dev;
+ 
+-	ret = get_property(cpu, level, &freq, GET_FREQ);
+-	if (ret)
+-		return 0;
++	switch (event) {
++
++	case CPUFREQ_ADJUST:
++		mutex_lock(&cooling_cpufreq_lock);
++		list_for_each_entry(cpufreq_dev, &cpufreq_dev_list, node) {
++			if (!cpumask_test_cpu(policy->cpu,
++					      &cpufreq_dev->allowed_cpus))
++				continue;
+ 
+-	return freq;
++			max_freq = cpufreq_dev->cpufreq_val;
++
++			if (policy->max != max_freq)
++				cpufreq_verify_within_limits(policy, 0,
++							     max_freq);
++		}
++		mutex_unlock(&cooling_cpufreq_lock);
++		break;
++	default:
++		return NOTIFY_DONE;
++	}
++
++	return NOTIFY_OK;
+ }
+ 
+ /**
+- * cpufreq_apply_cooling - function to apply frequency clipping.
+- * @cpufreq_device: cpufreq_cooling_device pointer containing frequency
+- *	clipping data.
+- * @cooling_state: value of the cooling state.
++ * build_dyn_power_table() - create a dynamic power to frequency table
++ * @cpufreq_device:	the cpufreq cooling device in which to store the table
++ * @capacitance: dynamic power coefficient for these cpus
+  *
+- * Function used to make sure the cpufreq layer is aware of current thermal
+- * limits. The limits are applied by updating the cpufreq policy.
++ * Build a dynamic power to frequency table for this cpu and store it
++ * in @cpufreq_device.  This table will be used in cpu_power_to_freq() and
++ * cpu_freq_to_power() to convert between power and frequency
++ * efficiently.  Power is stored in mW, frequency in KHz.  The
++ * resulting table is in ascending order.
+  *
+- * Return: 0 on success, an error code otherwise (-EINVAL in case wrong
+- * cooling state).
++ * Return: 0 on success, -E* on error.
+  */
+-static int cpufreq_apply_cooling(struct cpufreq_cooling_device *cpufreq_device,
+-				 unsigned long cooling_state)
++static int build_dyn_power_table(struct cpufreq_cooling_device *cpufreq_device,
++				 u32 capacitance)
+ {
+-	unsigned int cpuid, clip_freq;
+-	struct cpumask *mask = &cpufreq_device->allowed_cpus;
+-	unsigned int cpu = cpumask_any(mask);
++	struct power_table *power_table;
++	struct dev_pm_opp *opp;
++	struct device *dev = NULL;
++	int num_opps = 0, cpu, i, ret = 0;
++	unsigned long freq;
++
++	rcu_read_lock();
++
++	for_each_cpu(cpu, &cpufreq_device->allowed_cpus) {
++		dev = get_cpu_device(cpu);
++		if (!dev) {
++			dev_warn(&cpufreq_device->cool_dev->device,
++				 "No cpu device for cpu %d\n", cpu);
++			continue;
++		}
+ 
++		num_opps = dev_pm_opp_get_opp_count(dev);
++		if (num_opps > 0) {
++			break;
++		} else if (num_opps < 0) {
++			ret = num_opps;
++			goto unlock;
++		}
++	}
+ 
+-	/* Check if the old cooling action is same as new cooling action */
+-	if (cpufreq_device->cpufreq_state == cooling_state)
+-		return 0;
++	if (num_opps == 0) {
++		ret = -EINVAL;
++		goto unlock;
++	}
+ 
+-	clip_freq = get_cpu_frequency(cpu, cooling_state);
+-	if (!clip_freq)
+-		return -EINVAL;
++	power_table = kcalloc(num_opps, sizeof(*power_table), GFP_KERNEL);
++	if (!power_table) {
++		ret = -ENOMEM;
++		goto unlock;
++	}
+ 
+-	cpufreq_device->cpufreq_state = cooling_state;
+-	cpufreq_device->cpufreq_val = clip_freq;
++	for (freq = 0, i = 0;
++	     opp = dev_pm_opp_find_freq_ceil(dev, &freq), !IS_ERR(opp);
++	     freq++, i++) {
++		u32 freq_mhz, voltage_mv;
++		u64 power;
++
++		freq_mhz = freq / 1000000;
++		voltage_mv = dev_pm_opp_get_voltage(opp) / 1000;
++
++		/*
++		 * Do the multiplication with MHz and millivolt so as
++		 * to not overflow.
++		 */
++		power = (u64)capacitance * freq_mhz * voltage_mv * voltage_mv;
++		do_div(power, 1000000000);
+ 
+-	for_each_cpu(cpuid, mask) {
+-		if (is_cpufreq_valid(cpuid))
+-			cpufreq_update_policy(cpuid);
++		/* frequency is stored in power_table in KHz */
++		power_table[i].frequency = freq / 1000;
++
++		/* power is stored in mW */
++		power_table[i].power = power;
+ 	}
+ 
+-	return 0;
++	if (i == 0) {
++		ret = PTR_ERR(opp);
++		goto unlock;
++	}
++
++	cpufreq_device->cpu_dev = dev;
++	cpufreq_device->dyn_power_table = power_table;
++	cpufreq_device->dyn_power_table_entries = i;
++
++unlock:
++	rcu_read_unlock();
++	return ret;
++}
++
++static u32 cpu_freq_to_power(struct cpufreq_cooling_device *cpufreq_device,
++			     u32 freq)
++{
++	int i;
++	struct power_table *pt = cpufreq_device->dyn_power_table;
++
++	for (i = 1; i < cpufreq_device->dyn_power_table_entries; i++)
++		if (freq < pt[i].frequency)
++			break;
++
++	return pt[i - 1].power;
++}
++
++static u32 cpu_power_to_freq(struct cpufreq_cooling_device *cpufreq_device,
++			     u32 power)
++{
++	int i;
++	struct power_table *pt = cpufreq_device->dyn_power_table;
++
++	for (i = 1; i < cpufreq_device->dyn_power_table_entries; i++)
++		if (power < pt[i].power)
++			break;
++
++	return pt[i - 1].frequency;
+ }
+ 
+ /**
+- * cpufreq_thermal_notifier - notifier callback for cpufreq policy change.
+- * @nb:	struct notifier_block * with callback info.
+- * @event: value showing cpufreq event for which this function invoked.
+- * @data: callback-specific data
++ * get_load() - get load for a cpu since last updated
++ * @cpufreq_device:	&struct cpufreq_cooling_device for this cpu
++ * @cpu:	cpu number
+  *
+- * Callback to hijack the notification on cpufreq policy transition.
+- * Every time there is a change in policy, we will intercept and
+- * update the cpufreq policy with thermal constraints.
+- *
+- * Return: 0 (success)
++ * Return: The average load of cpu @cpu in percentage since this
++ * function was last called.
+  */
+-static int cpufreq_thermal_notifier(struct notifier_block *nb,
+-				    unsigned long event, void *data)
++static u32 get_load(struct cpufreq_cooling_device *cpufreq_device, int cpu)
+ {
+-	struct cpufreq_policy *policy = data;
+-	unsigned long max_freq = 0;
+-	struct cpufreq_cooling_device *cpufreq_dev;
++	u32 load;
++	u64 now, now_idle, delta_time, delta_idle;
++
++	now_idle = get_cpu_idle_time(cpu, &now, 0);
++	delta_idle = now_idle - cpufreq_device->time_in_idle[cpu];
++	delta_time = now - cpufreq_device->time_in_idle_timestamp[cpu];
++
++	if (delta_time <= delta_idle)
++		load = 0;
++	else
++		load = div64_u64(100 * (delta_time - delta_idle), delta_time);
+ 
+-	if (event != CPUFREQ_ADJUST)
++	cpufreq_device->time_in_idle[cpu] = now_idle;
++	cpufreq_device->time_in_idle_timestamp[cpu] = now;
++
++	return load;
++}
++
++/**
++ * get_static_power() - calculate the static power consumed by the cpus
++ * @cpufreq_device:	struct &cpufreq_cooling_device for this cpu cdev
++ * @tz:		thermal zone device in which we're operating
++ * @freq:	frequency in KHz
++ * @power:	pointer in which to store the calculated static power
++ *
++ * Calculate the static power consumed by the cpus described by
++ * @cpu_actor running at frequency @freq.  This function relies on a
++ * platform specific function that should have been provided when the
++ * actor was registered.  If it wasn't, the static power is assumed to
++ * be negligible.  The calculated static power is stored in @power.
++ *
++ * Return: 0 on success, -E* on failure.
++ */
++static int get_static_power(struct cpufreq_cooling_device *cpufreq_device,
++			    struct thermal_zone_device *tz, unsigned long freq,
++			    u32 *power)
++{
++	struct dev_pm_opp *opp;
++	unsigned long voltage;
++	struct cpumask *cpumask = &cpufreq_device->allowed_cpus;
++	unsigned long freq_hz = freq * 1000;
++
++	if (!cpufreq_device->plat_get_static_power ||
++	    !cpufreq_device->cpu_dev) {
++		*power = 0;
+ 		return 0;
++	}
+ 
+-	mutex_lock(&cooling_cpufreq_lock);
+-	list_for_each_entry(cpufreq_dev, &cpufreq_dev_list, node) {
+-		if (!cpumask_test_cpu(policy->cpu,
+-					&cpufreq_dev->allowed_cpus))
+-			continue;
++	rcu_read_lock();
+ 
+-		if (!cpufreq_dev->cpufreq_val)
+-			cpufreq_dev->cpufreq_val = get_cpu_frequency(
+-					cpumask_any(&cpufreq_dev->allowed_cpus),
+-					cpufreq_dev->cpufreq_state);
++	opp = dev_pm_opp_find_freq_exact(cpufreq_device->cpu_dev, freq_hz,
++					 true);
++	voltage = dev_pm_opp_get_voltage(opp);
+ 
+-		max_freq = cpufreq_dev->cpufreq_val;
++	rcu_read_unlock();
+ 
+-		if (policy->max != max_freq)
+-			cpufreq_verify_within_limits(policy, 0, max_freq);
++	if (voltage == 0) {
++		dev_warn_ratelimited(cpufreq_device->cpu_dev,
++				     "Failed to get voltage for frequency %lu: %ld\n",
++				     freq_hz, IS_ERR(opp) ? PTR_ERR(opp) : 0);
++		return -EINVAL;
+ 	}
+-	mutex_unlock(&cooling_cpufreq_lock);
+ 
+-	return 0;
++	return cpufreq_device->plat_get_static_power(cpumask, tz->passive_delay,
++						     voltage, power);
++}
++
++/**
++ * get_dynamic_power() - calculate the dynamic power
++ * @cpufreq_device:	&cpufreq_cooling_device for this cdev
++ * @freq:	current frequency
++ *
++ * Return: the dynamic power consumed by the cpus described by
++ * @cpufreq_device.
++ */
++static u32 get_dynamic_power(struct cpufreq_cooling_device *cpufreq_device,
++			     unsigned long freq)
++{
++	u32 raw_cpu_power;
++
++	raw_cpu_power = cpu_freq_to_power(cpufreq_device, freq);
++	return (raw_cpu_power * cpufreq_device->last_load) / 100;
+ }
+ 
+ /* cpufreq cooling device callback functions are defined below */
+@@ -354,19 +467,9 @@ static int cpufreq_get_max_state(struct thermal_cooling_device *cdev,
+ 				 unsigned long *state)
+ {
+ 	struct cpufreq_cooling_device *cpufreq_device = cdev->devdata;
+-	struct cpumask *mask = &cpufreq_device->allowed_cpus;
+-	unsigned int cpu;
+-	unsigned int count = 0;
+-	int ret;
+ 
+-	cpu = cpumask_any(mask);
+-
+-	ret = get_property(cpu, 0, &count, GET_MAXL);
+-
+-	if (count > 0)
+-		*state = count;
+-
+-	return ret;
++	*state = cpufreq_device->max_level;
++	return 0;
+ }
+ 
+ /**
+@@ -403,12 +506,225 @@ static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev,
+ 				 unsigned long state)
+ {
+ 	struct cpufreq_cooling_device *cpufreq_device = cdev->devdata;
++	unsigned int cpu = cpumask_any(&cpufreq_device->allowed_cpus);
++	unsigned int clip_freq;
++
++	/* Request state should be less than max_level */
++	if (WARN_ON(state > cpufreq_device->max_level))
++		return -EINVAL;
++
++	/* Check if the old cooling action is same as new cooling action */
++	if (cpufreq_device->cpufreq_state == state)
++		return 0;
++
++	clip_freq = cpufreq_device->freq_table[state];
++	cpufreq_device->cpufreq_state = state;
++	cpufreq_device->cpufreq_val = clip_freq;
++
++	cpufreq_update_policy(cpu);
++
++	return 0;
++}
++
++/**
++ * cpufreq_get_requested_power() - get the current power
++ * @cdev:	&thermal_cooling_device pointer
++ * @tz:		a valid thermal zone device pointer
++ * @power:	pointer in which to store the resulting power
++ *
++ * Calculate the current power consumption of the cpus in milliwatts
++ * and store it in @power.  This function should actually calculate
++ * the requested power, but it's hard to get the frequency that
++ * cpufreq would have assigned if there were no thermal limits.
++ * Instead, we calculate the current power on the assumption that the
++ * immediate future will look like the immediate past.
++ *
++ * We use the current frequency and the average load since this
++ * function was last called.  In reality, there could have been
++ * multiple opps since this function was last called and that affects
++ * the load calculation.  While it's not perfectly accurate, this
++ * simplification is good enough and works.  REVISIT this, as more
++ * complex code may be needed if experiments show that it's not
++ * accurate enough.
++ *
++ * Return: 0 on success, -E* if getting the static power failed.
++ */
++static int cpufreq_get_requested_power(struct thermal_cooling_device *cdev,
++				       struct thermal_zone_device *tz,
++				       u32 *power)
++{
++	unsigned long freq;
++	int i = 0, cpu, ret;
++	u32 static_power, dynamic_power, total_load = 0;
++	struct cpufreq_cooling_device *cpufreq_device = cdev->devdata;
++	u32 *load_cpu = NULL;
++
++	cpu = cpumask_any_and(&cpufreq_device->allowed_cpus, cpu_online_mask);
++
++	/*
++	 * All the CPUs are offline, thus the requested power by
++	 * the cdev is 0
++	 */
++	if (cpu >= nr_cpu_ids) {
++		*power = 0;
++		return 0;
++	}
++
++	freq = cpufreq_quick_get(cpu);
++
++	if (trace_thermal_power_cpu_get_power_enabled()) {
++		u32 ncpus = cpumask_weight(&cpufreq_device->allowed_cpus);
++
++		load_cpu = devm_kcalloc(&cdev->device, ncpus, sizeof(*load_cpu),
++					GFP_KERNEL);
++	}
++
++	for_each_cpu(cpu, &cpufreq_device->allowed_cpus) {
++		u32 load;
++
++		if (cpu_online(cpu))
++			load = get_load(cpufreq_device, cpu);
++		else
++			load = 0;
++
++		total_load += load;
++		if (trace_thermal_power_cpu_limit_enabled() && load_cpu)
++			load_cpu[i] = load;
++
++		i++;
++	}
++
++	cpufreq_device->last_load = total_load;
++
++	dynamic_power = get_dynamic_power(cpufreq_device, freq);
++	ret = get_static_power(cpufreq_device, tz, freq, &static_power);
++	if (ret) {
++		if (load_cpu)
++			devm_kfree(&cdev->device, load_cpu);
++		return ret;
++	}
++
++	if (load_cpu) {
++		trace_thermal_power_cpu_get_power(
++			&cpufreq_device->allowed_cpus,
++			freq, load_cpu, i, dynamic_power, static_power);
++
++		devm_kfree(&cdev->device, load_cpu);
++	}
++
++	*power = static_power + dynamic_power;
++	return 0;
++}
++
++/**
++ * cpufreq_state2power() - convert a cpu cdev state to power consumed
++ * @cdev:	&thermal_cooling_device pointer
++ * @tz:		a valid thermal zone device pointer
++ * @state:	cooling device state to be converted
++ * @power:	pointer in which to store the resulting power
++ *
++ * Convert cooling device state @state into power consumption in
++ * milliwatts assuming 100% load.  Store the calculated power in
++ * @power.
++ *
++ * Return: 0 on success, -EINVAL if the cooling device state could not
++ * be converted into a frequency or other -E* if there was an error
++ * when calculating the static power.
++ */
++static int cpufreq_state2power(struct thermal_cooling_device *cdev,
++			       struct thermal_zone_device *tz,
++			       unsigned long state, u32 *power)
++{
++	unsigned int freq, num_cpus;
++	cpumask_t cpumask;
++	u32 static_power, dynamic_power;
++	int ret;
++	struct cpufreq_cooling_device *cpufreq_device = cdev->devdata;
++
++	cpumask_and(&cpumask, &cpufreq_device->allowed_cpus, cpu_online_mask);
++	num_cpus = cpumask_weight(&cpumask);
++
++	/* None of our cpus are online, so no power */
++	if (num_cpus == 0) {
++		*power = 0;
++		return 0;
++	}
++
++	freq = cpufreq_device->freq_table[state];
++	if (!freq)
++		return -EINVAL;
+ 
+-	return cpufreq_apply_cooling(cpufreq_device, state);
++	dynamic_power = cpu_freq_to_power(cpufreq_device, freq) * num_cpus;
++	ret = get_static_power(cpufreq_device, tz, freq, &static_power);
++	if (ret)
++		return ret;
++
++	*power = static_power + dynamic_power;
++	return 0;
++}
++
++/**
++ * cpufreq_power2state() - convert power to a cooling device state
++ * @cdev:	&thermal_cooling_device pointer
++ * @tz:		a valid thermal zone device pointer
++ * @power:	power in milliwatts to be converted
++ * @state:	pointer in which to store the resulting state
++ *
++ * Calculate a cooling device state for the cpus described by @cdev
++ * that would allow them to consume at most @power mW and store it in
++ * @state.  Note that this calculation depends on external factors
++ * such as the cpu load or the current static power.  Calling this
++ * function with the same power as input can yield different cooling
++ * device states depending on those external factors.
++ *
++ * Return: 0 on success, -ENODEV if no cpus are online or -EINVAL if
++ * the calculated frequency could not be converted to a valid state.
++ * The latter should not happen unless the frequencies available to
++ * cpufreq have changed since the initialization of the cpu cooling
++ * device.
++ */
++static int cpufreq_power2state(struct thermal_cooling_device *cdev,
++			       struct thermal_zone_device *tz, u32 power,
++			       unsigned long *state)
++{
++	unsigned int cpu, cur_freq, target_freq;
++	int ret;
++	s32 dyn_power;
++	u32 last_load, normalised_power, static_power;
++	struct cpufreq_cooling_device *cpufreq_device = cdev->devdata;
++
++	cpu = cpumask_any_and(&cpufreq_device->allowed_cpus, cpu_online_mask);
++
++	/* None of our cpus are online */
++	if (cpu >= nr_cpu_ids)
++		return -ENODEV;
++
++	cur_freq = cpufreq_quick_get(cpu);
++	ret = get_static_power(cpufreq_device, tz, cur_freq, &static_power);
++	if (ret)
++		return ret;
++
++	dyn_power = power - static_power;
++	dyn_power = dyn_power > 0 ? dyn_power : 0;
++	last_load = cpufreq_device->last_load ?: 1;
++	normalised_power = (dyn_power * 100) / last_load;
++	target_freq = cpu_power_to_freq(cpufreq_device, normalised_power);
++
++	*state = cpufreq_cooling_get_level(cpu, target_freq);
++	if (*state == THERMAL_CSTATE_INVALID) {
++		dev_warn_ratelimited(&cdev->device,
++				     "Failed to convert %dKHz for cpu %d into a cdev state\n",
++				     target_freq, cpu);
++		return -EINVAL;
++	}
++
++	trace_thermal_power_cpu_limit(&cpufreq_device->allowed_cpus,
++				      target_freq, *state, power);
++	return 0;
+ }
+ 
+ /* Bind cpufreq callbacks to thermal cooling device ops */
+-static struct thermal_cooling_device_ops const cpufreq_cooling_ops = {
++static struct thermal_cooling_device_ops cpufreq_cooling_ops = {
+ 	.get_max_state = cpufreq_get_max_state,
+ 	.get_cur_state = cpufreq_get_cur_state,
+ 	.set_cur_state = cpufreq_set_cur_state,
+@@ -419,10 +735,28 @@ static struct notifier_block thermal_cpufreq_notifier_block = {
+ 	.notifier_call = cpufreq_thermal_notifier,
+ };
+ 
++static unsigned int find_next_max(struct cpufreq_frequency_table *table,
++				  unsigned int prev_max)
++{
++	struct cpufreq_frequency_table *pos;
++	unsigned int max = 0;
++
++	cpufreq_for_each_valid_entry(pos, table) {
++		if (pos->frequency > max && pos->frequency < prev_max)
++			max = pos->frequency;
++	}
++
++	return max;
++}
++
+ /**
+  * __cpufreq_cooling_register - helper function to create cpufreq cooling device
+  * @np: a valid struct device_node to the cooling device device tree node
+  * @clip_cpus: cpumask of cpus where the frequency constraints will happen.
++ * Normally this should be same as cpufreq policy->related_cpus.
++ * @capacitance: dynamic power coefficient for these cpus
++ * @plat_static_func: function to calculate the static power consumed by these
++ *                    cpus (optional)
+  *
+  * This interface function registers the cpufreq cooling device with the name
+  * "thermal-cpufreq-%x". This api can support multiple instances of cpufreq
+@@ -434,40 +768,77 @@ static struct notifier_block thermal_cpufreq_notifier_block = {
+  */
+ static struct thermal_cooling_device *
+ __cpufreq_cooling_register(struct device_node *np,
+-			   const struct cpumask *clip_cpus)
++			const struct cpumask *clip_cpus, u32 capacitance,
++			get_static_t plat_static_func)
+ {
+ 	struct thermal_cooling_device *cool_dev;
+-	struct cpufreq_cooling_device *cpufreq_dev = NULL;
+-	unsigned int min = 0, max = 0;
++	struct cpufreq_cooling_device *cpufreq_dev;
+ 	char dev_name[THERMAL_NAME_LENGTH];
+-	int ret = 0, i;
+-	struct cpufreq_policy policy;
++	struct cpufreq_frequency_table *pos, *table;
++	unsigned int freq, i, num_cpus;
++	int ret;
+ 
+-	/* Verify that all the clip cpus have same freq_min, freq_max limit */
+-	for_each_cpu(i, clip_cpus) {
+-		/* continue if cpufreq policy not found and not return error */
+-		if (!cpufreq_get_policy(&policy, i))
+-			continue;
+-		if (min == 0 && max == 0) {
+-			min = policy.cpuinfo.min_freq;
+-			max = policy.cpuinfo.max_freq;
+-		} else {
+-			if (min != policy.cpuinfo.min_freq ||
+-			    max != policy.cpuinfo.max_freq)
+-				return ERR_PTR(-EINVAL);
+-		}
++	table = cpufreq_frequency_get_table(cpumask_first(clip_cpus));
++	if (!table) {
++		pr_debug("%s: CPUFreq table not found\n", __func__);
++		return ERR_PTR(-EPROBE_DEFER);
+ 	}
+-	cpufreq_dev = kzalloc(sizeof(struct cpufreq_cooling_device),
+-			      GFP_KERNEL);
++
++	cpufreq_dev = kzalloc(sizeof(*cpufreq_dev), GFP_KERNEL);
+ 	if (!cpufreq_dev)
+ 		return ERR_PTR(-ENOMEM);
+ 
++	num_cpus = cpumask_weight(clip_cpus);
++	cpufreq_dev->time_in_idle = kcalloc(num_cpus,
++					    sizeof(*cpufreq_dev->time_in_idle),
++					    GFP_KERNEL);
++	if (!cpufreq_dev->time_in_idle) {
++		cool_dev = ERR_PTR(-ENOMEM);
++		goto free_cdev;
++	}
++
++	cpufreq_dev->time_in_idle_timestamp =
++		kcalloc(num_cpus, sizeof(*cpufreq_dev->time_in_idle_timestamp),
++			GFP_KERNEL);
++	if (!cpufreq_dev->time_in_idle_timestamp) {
++		cool_dev = ERR_PTR(-ENOMEM);
++		goto free_time_in_idle;
++	}
++
++	/* Find max levels */
++	cpufreq_for_each_valid_entry(pos, table)
++		cpufreq_dev->max_level++;
++
++	cpufreq_dev->freq_table = kmalloc(sizeof(*cpufreq_dev->freq_table) *
++					  cpufreq_dev->max_level, GFP_KERNEL);
++	if (!cpufreq_dev->freq_table) {
++		cool_dev = ERR_PTR(-ENOMEM);
++		goto free_time_in_idle_timestamp;
++	}
++
++	/* max_level is an index, not a counter */
++	cpufreq_dev->max_level--;
++
+ 	cpumask_copy(&cpufreq_dev->allowed_cpus, clip_cpus);
+ 
++	if (capacitance) {
++		cpufreq_cooling_ops.get_requested_power =
++			cpufreq_get_requested_power;
++		cpufreq_cooling_ops.state2power = cpufreq_state2power;
++		cpufreq_cooling_ops.power2state = cpufreq_power2state;
++		cpufreq_dev->plat_get_static_power = plat_static_func;
++
++		ret = build_dyn_power_table(cpufreq_dev, capacitance);
++		if (ret) {
++			cool_dev = ERR_PTR(ret);
++			goto free_table;
++		}
++	}
++
+ 	ret = get_idr(&cpufreq_idr, &cpufreq_dev->id);
+ 	if (ret) {
+-		kfree(cpufreq_dev);
+-		return ERR_PTR(-EINVAL);
++		cool_dev = ERR_PTR(ret);
++		goto free_table;
+ 	}
+ 
+ 	snprintf(dev_name, sizeof(dev_name), "thermal-cpufreq-%d",
+@@ -475,25 +846,48 @@ __cpufreq_cooling_register(struct device_node *np,
+ 
+ 	cool_dev = thermal_of_cooling_device_register(np, dev_name, cpufreq_dev,
+ 						      &cpufreq_cooling_ops);
+-	if (IS_ERR(cool_dev)) {
+-		release_idr(&cpufreq_idr, cpufreq_dev->id);
+-		kfree(cpufreq_dev);
+-		return cool_dev;
++	if (IS_ERR(cool_dev))
++		goto remove_idr;
++
++	/* Fill freq-table in descending order of frequencies */
++	for (i = 0, freq = -1; i <= cpufreq_dev->max_level; i++) {
++		freq = find_next_max(table, freq);
++		cpufreq_dev->freq_table[i] = freq;
++
++		/* Warn for duplicate entries */
++		if (!freq)
++			pr_warn("%s: table has duplicate entries\n", __func__);
++		else
++			pr_debug("%s: freq:%u KHz\n", __func__, freq);
+ 	}
++
++	cpufreq_dev->cpufreq_val = cpufreq_dev->freq_table[0];
+ 	cpufreq_dev->cool_dev = cool_dev;
+-	cpufreq_dev->cpufreq_state = 0;
++
+ 	mutex_lock(&cooling_cpufreq_lock);
+ 
+ 	/* Register the notifier for first cpufreq cooling device */
+-	if (cpufreq_dev_count == 0)
++	if (list_empty(&cpufreq_dev_list))
+ 		cpufreq_register_notifier(&thermal_cpufreq_notifier_block,
+ 					  CPUFREQ_POLICY_NOTIFIER);
+-	cpufreq_dev_count++;
+ 	list_add(&cpufreq_dev->node, &cpufreq_dev_list);
+ 
+ 	mutex_unlock(&cooling_cpufreq_lock);
+ 
+ 	return cool_dev;
++
++remove_idr:
++	release_idr(&cpufreq_idr, cpufreq_dev->id);
++free_table:
++	kfree(cpufreq_dev->freq_table);
++free_time_in_idle_timestamp:
++	kfree(cpufreq_dev->time_in_idle_timestamp);
++free_time_in_idle:
++	kfree(cpufreq_dev->time_in_idle);
++free_cdev:
++	kfree(cpufreq_dev);
++
++	return cool_dev;
+ }
+ 
+ /**
+@@ -510,7 +904,7 @@ __cpufreq_cooling_register(struct device_node *np,
+ struct thermal_cooling_device *
+ cpufreq_cooling_register(const struct cpumask *clip_cpus)
+ {
+-	return __cpufreq_cooling_register(NULL, clip_cpus);
++	return __cpufreq_cooling_register(NULL, clip_cpus, 0, NULL);
+ }
+ EXPORT_SYMBOL_GPL(cpufreq_cooling_register);
+ 
+@@ -534,11 +928,78 @@ of_cpufreq_cooling_register(struct device_node *np,
+ 	if (!np)
+ 		return ERR_PTR(-EINVAL);
+ 
+-	return __cpufreq_cooling_register(np, clip_cpus);
++	return __cpufreq_cooling_register(np, clip_cpus, 0, NULL);
+ }
+ EXPORT_SYMBOL_GPL(of_cpufreq_cooling_register);
+ 
+ /**
++ * cpufreq_power_cooling_register() - create cpufreq cooling device with power extensions
++ * @clip_cpus:	cpumask of cpus where the frequency constraints will happen
++ * @capacitance:	dynamic power coefficient for these cpus
++ * @plat_static_func:	function to calculate the static power consumed by these
++ *			cpus (optional)
++ *
++ * This interface function registers the cpufreq cooling device with
++ * the name "thermal-cpufreq-%x".  This api can support multiple
++ * instances of cpufreq cooling devices.  Using this function, the
++ * cooling device will implement the power extensions by using a
++ * simple cpu power model.  The cpus must have registered their OPPs
++ * using the OPP library.
++ *
++ * An optional @plat_static_func may be provided to calculate the
++ * static power consumed by these cpus.  If the platform's static
++ * power consumption is unknown or negligible, make it NULL.
++ *
++ * Return: a valid struct thermal_cooling_device pointer on success,
++ * on failure, it returns a corresponding ERR_PTR().
++ */
++struct thermal_cooling_device *
++cpufreq_power_cooling_register(const struct cpumask *clip_cpus, u32 capacitance,
++			       get_static_t plat_static_func)
++{
++	return __cpufreq_cooling_register(NULL, clip_cpus, capacitance,
++				plat_static_func);
++}
++EXPORT_SYMBOL(cpufreq_power_cooling_register);
++
++/**
++ * of_cpufreq_power_cooling_register() - create cpufreq cooling device with power extensions
++ * @np:	a valid struct device_node to the cooling device device tree node
++ * @clip_cpus:	cpumask of cpus where the frequency constraints will happen
++ * @capacitance:	dynamic power coefficient for these cpus
++ * @plat_static_func:	function to calculate the static power consumed by these
++ *			cpus (optional)
++ *
++ * This interface function registers the cpufreq cooling device with
++ * the name "thermal-cpufreq-%x".  This api can support multiple
++ * instances of cpufreq cooling devices.  Using this API, the cpufreq
++ * cooling device will be linked to the device tree node provided.
++ * Using this function, the cooling device will implement the power
++ * extensions by using a simple cpu power model.  The cpus must have
++ * registered their OPPs using the OPP library.
++ *
++ * An optional @plat_static_func may be provided to calculate the
++ * static power consumed by these cpus.  If the platform's static
++ * power consumption is unknown or negligible, make it NULL.
++ *
++ * Return: a valid struct thermal_cooling_device pointer on success,
++ * on failure, it returns a corresponding ERR_PTR().
++ */
++struct thermal_cooling_device *
++of_cpufreq_power_cooling_register(struct device_node *np,
++				  const struct cpumask *clip_cpus,
++				  u32 capacitance,
++				  get_static_t plat_static_func)
++{
++	if (!np)
++		return ERR_PTR(-EINVAL);
++
++	return __cpufreq_cooling_register(np, clip_cpus, capacitance,
++				plat_static_func);
++}
++EXPORT_SYMBOL(of_cpufreq_power_cooling_register);
++
++/**
+  * cpufreq_cooling_unregister - function to remove cpufreq cooling device.
+  * @cdev: thermal cooling device pointer.
+  *
+@@ -554,16 +1015,18 @@ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
+ 	cpufreq_dev = cdev->devdata;
+ 	mutex_lock(&cooling_cpufreq_lock);
+ 	list_del(&cpufreq_dev->node);
+-	cpufreq_dev_count--;
+ 
+ 	/* Unregister the notifier for the last cpufreq cooling device */
+-	if (cpufreq_dev_count == 0)
++	if (list_empty(&cpufreq_dev_list))
+ 		cpufreq_unregister_notifier(&thermal_cpufreq_notifier_block,
+ 					    CPUFREQ_POLICY_NOTIFIER);
+ 	mutex_unlock(&cooling_cpufreq_lock);
+ 
+ 	thermal_cooling_device_unregister(cpufreq_dev->cool_dev);
+ 	release_idr(&cpufreq_idr, cpufreq_dev->id);
++	kfree(cpufreq_dev->time_in_idle_timestamp);
++	kfree(cpufreq_dev->time_in_idle);
++	kfree(cpufreq_dev->freq_table);
+ 	kfree(cpufreq_dev);
+ }
+ EXPORT_SYMBOL_GPL(cpufreq_cooling_unregister);
+diff --git a/drivers/thermal/db8500_cpufreq_cooling.c b/drivers/thermal/db8500_cpufreq_cooling.c
+index 786d192..1ac7ec6 100644
+--- a/drivers/thermal/db8500_cpufreq_cooling.c
++++ b/drivers/thermal/db8500_cpufreq_cooling.c
+@@ -18,7 +18,6 @@
+  */
+ 
+ #include <linux/cpu_cooling.h>
+-#include <linux/cpufreq.h>
+ #include <linux/err.h>
+ #include <linux/module.h>
+ #include <linux/of.h>
+@@ -30,10 +29,6 @@ static int db8500_cpufreq_cooling_probe(struct platform_device *pdev)
+ 	struct thermal_cooling_device *cdev;
+ 	struct cpumask mask_val;
+ 
+-	/* make sure cpufreq driver has been initialized */
+-	if (!cpufreq_frequency_get_table(0))
+-		return -EPROBE_DEFER;
+-
+ 	cpumask_set_cpu(0, &mask_val);
+ 	cdev = cpufreq_cooling_register(&mask_val);
+ 
+diff --git a/drivers/thermal/db8500_thermal.c b/drivers/thermal/db8500_thermal.c
+index 1e3b3bf..e3ccc22 100644
+--- a/drivers/thermal/db8500_thermal.c
++++ b/drivers/thermal/db8500_thermal.c
+@@ -76,7 +76,7 @@ static int db8500_cdev_bind(struct thermal_zone_device *thermal,
+ 		upper = lower = i > max_state ? max_state : i;
+ 
+ 		ret = thermal_zone_bind_cooling_device(thermal, i, cdev,
+-			upper, lower);
++			upper, lower, THERMAL_WEIGHT_DEFAULT);
+ 
+ 		dev_info(&cdev->device, "%s bind to %d: %d-%s\n", cdev->type,
+ 			i, ret, ret ? "fail" : "succeed");
+diff --git a/drivers/thermal/fair_share.c b/drivers/thermal/fair_share.c
+index 6e0a3fb..8c50b8d 100644
+--- a/drivers/thermal/fair_share.c
++++ b/drivers/thermal/fair_share.c
+@@ -59,13 +59,13 @@ static int get_trip_level(struct thermal_zone_device *tz)
+ }
+ 
+ static long get_target_state(struct thermal_zone_device *tz,
+-		struct thermal_cooling_device *cdev, int weight, int level)
++		struct thermal_cooling_device *cdev, int percentage, int level)
+ {
+ 	unsigned long max_state;
+ 
+ 	cdev->ops->get_max_state(cdev, &max_state);
+ 
+-	return (long)(weight * level * max_state) / (100 * tz->trips);
++	return (long)(percentage * level * max_state) / (100 * tz->trips);
+ }
+ 
+ /**
+@@ -77,7 +77,7 @@ static long get_target_state(struct thermal_zone_device *tz,
+  *
+  * Parameters used for Throttling:
+  * P1. max_state: Maximum throttle state exposed by the cooling device.
+- * P2. weight[i]/100:
++ * P2. percentage[i]/100:
+  *	How 'effective' the 'i'th device is, in cooling the given zone.
+  * P3. cur_trip_level/max_no_of_trips:
+  *	This describes the extent to which the devices should be throttled.
+@@ -88,28 +88,33 @@ static long get_target_state(struct thermal_zone_device *tz,
+  */
+ static int fair_share_throttle(struct thermal_zone_device *tz, int trip)
+ {
+-	const struct thermal_zone_params *tzp;
+-	struct thermal_cooling_device *cdev;
+ 	struct thermal_instance *instance;
+-	int i;
++	int total_weight = 0;
++	int total_instance = 0;
+ 	int cur_trip_level = get_trip_level(tz);
+ 
+-	if (!tz->tzp || !tz->tzp->tbp)
+-		return -EINVAL;
++	list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
++		if (instance->trip != trip)
++			continue;
++
++		total_weight += instance->weight;
++		total_instance++;
++	}
+ 
+-	tzp = tz->tzp;
++	list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
++		int percentage;
++		struct thermal_cooling_device *cdev = instance->cdev;
+ 
+-	for (i = 0; i < tzp->num_tbps; i++) {
+-		if (!tzp->tbp[i].cdev)
++		if (instance->trip != trip)
+ 			continue;
+ 
+-		cdev = tzp->tbp[i].cdev;
+-		instance = get_thermal_instance(tz, cdev, trip);
+-		if (!instance)
+-			continue;
++		if (!total_weight)
++			percentage = 100 / total_instance;
++		else
++			percentage = (instance->weight * 100) / total_weight;
+ 
+-		instance->target = get_target_state(tz, cdev,
+-					tzp->tbp[i].weight, cur_trip_level);
++		instance->target = get_target_state(tz, cdev, percentage,
++						    cur_trip_level);
+ 
+ 		instance->cdev->updated = false;
+ 		thermal_cdev_update(cdev);
+diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c
+index 5a1f107..31ada06 100644
+--- a/drivers/thermal/imx_thermal.c
++++ b/drivers/thermal/imx_thermal.c
+@@ -9,7 +9,6 @@
+ 
+ #include <linux/clk.h>
+ #include <linux/cpu_cooling.h>
+-#include <linux/cpufreq.h>
+ #include <linux/delay.h>
+ #include <linux/device.h>
+ #include <linux/init.h>
+@@ -307,7 +306,8 @@ static int imx_bind(struct thermal_zone_device *tz,
+ 
+ 	ret = thermal_zone_bind_cooling_device(tz, IMX_TRIP_PASSIVE, cdev,
+ 					       THERMAL_NO_LIMIT,
+-					       THERMAL_NO_LIMIT);
++					       THERMAL_NO_LIMIT,
++					       THERMAL_WEIGHT_DEFAULT);
+ 	if (ret) {
+ 		dev_err(&tz->device,
+ 			"binding zone %s with cdev %s failed:%d\n",
+@@ -459,10 +459,6 @@ static int imx_thermal_probe(struct platform_device *pdev)
+ 	int measure_freq;
+ 	int ret;
+ 
+-	if (!cpufreq_get_current_driver()) {
+-		dev_dbg(&pdev->dev, "no cpufreq driver!");
+-		return -EPROBE_DEFER;
+-	}
+ 	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ 	if (!data)
+ 		return -ENOMEM;
+diff --git a/drivers/thermal/int340x_thermal/int3403_thermal.c b/drivers/thermal/int340x_thermal/int3403_thermal.c
+index 6e9fb62..76910d3 100644
+--- a/drivers/thermal/int340x_thermal/int3403_thermal.c
++++ b/drivers/thermal/int340x_thermal/int3403_thermal.c
+@@ -471,7 +471,6 @@ static struct platform_driver int3403_driver = {
+ 	.remove = int3403_remove,
+ 	.driver = {
+ 		.name = "int3403 thermal",
+-		.owner  = THIS_MODULE,
+ 		.acpi_match_table = int3403_device_ids,
+ 	},
+ };
+diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
+index 62143ba..b295b2b 100644
+--- a/drivers/thermal/of-thermal.c
++++ b/drivers/thermal/of-thermal.c
+@@ -30,27 +30,13 @@
+ #include <linux/err.h>
+ #include <linux/export.h>
+ #include <linux/string.h>
++#include <linux/thermal.h>
+ 
+ #include "thermal_core.h"
+ 
+ /***   Private data structures to represent thermal device tree data ***/
+ 
+ /**
+- * struct __thermal_trip - representation of a point in temperature domain
+- * @np: pointer to struct device_node that this trip point was created from
+- * @temperature: temperature value in miliCelsius
+- * @hysteresis: relative hysteresis in miliCelsius
+- * @type: trip point type
+- */
+-
+-struct __thermal_trip {
+-	struct device_node *np;
+-	unsigned long int temperature;
+-	unsigned long int hysteresis;
+-	enum thermal_trip_type type;
+-};
+-
+-/**
+  * struct __thermal_bind_param - a match between trip and cooling device
+  * @cooling_device: a pointer to identify the referred cooling device
+  * @trip_id: the trip point index
+@@ -72,23 +58,26 @@ struct __thermal_bind_params {
+  * @mode: current thermal zone device mode (enabled/disabled)
+  * @passive_delay: polling interval while passive cooling is activated
+  * @polling_delay: zone polling interval
++ * @slope: slope of the temperature adjustment curve
++ * @offset: offset of the temperature adjustment curve
+  * @ntrips: number of trip points
+  * @trips: an array of trip points (0..ntrips - 1)
+  * @num_tbps: number of thermal bind params
+  * @tbps: an array of thermal bind params (0..num_tbps - 1)
+  * @sensor_data: sensor private data used while reading temperature and trend
+- * @get_temp: sensor callback to read temperature
+- * @get_trend: sensor callback to read temperature trend
++ * @ops: set of callbacks to handle the thermal zone based on DT
+  */
+ 
+ struct __thermal_zone {
+ 	enum thermal_device_mode mode;
+ 	int passive_delay;
+ 	int polling_delay;
++	int slope;
++	int offset;
+ 
+ 	/* trip data */
+ 	int ntrips;
+-	struct __thermal_trip *trips;
++	struct thermal_trip *trips;
+ 
+ 	/* cooling binding data */
+ 	int num_tbps;
+@@ -96,8 +85,7 @@ struct __thermal_zone {
+ 
+ 	/* sensor interface */
+ 	void *sensor_data;
+-	int (*get_temp)(void *, long *);
+-	int (*get_trend)(void *, long *);
++	const struct thermal_zone_of_device_ops *ops;
+ };
+ 
+ /***   DT thermal zone device callbacks   ***/
+@@ -107,10 +95,96 @@ static int of_thermal_get_temp(struct thermal_zone_device *tz,
+ {
+ 	struct __thermal_zone *data = tz->devdata;
+ 
+-	if (!data->get_temp)
++	if (!data->ops->get_temp)
+ 		return -EINVAL;
+ 
+-	return data->get_temp(data->sensor_data, temp);
++	return data->ops->get_temp(data->sensor_data, temp);
++}
++
++/**
++ * of_thermal_get_ntrips - function to export number of available trip
++ *			   points.
++ * @tz: pointer to a thermal zone
++ *
++ * This function is a globally visible wrapper to get number of trip points
++ * stored in the local struct __thermal_zone
++ *
++ * Return: number of available trip points, -ENODEV when data not available
++ */
++int of_thermal_get_ntrips(struct thermal_zone_device *tz)
++{
++	struct __thermal_zone *data = tz->devdata;
++
++	if (!data || IS_ERR(data))
++		return -ENODEV;
++
++	return data->ntrips;
++}
++EXPORT_SYMBOL_GPL(of_thermal_get_ntrips);
++
++/**
++ * of_thermal_is_trip_valid - function to check if trip point is valid
++ *
++ * @tz:	pointer to a thermal zone
++ * @trip:	trip point to evaluate
++ *
++ * This function is responsible for checking if passed trip point is valid
++ *
++ * Return: true if trip point is valid, false otherwise
++ */
++bool of_thermal_is_trip_valid(struct thermal_zone_device *tz, int trip)
++{
++	struct __thermal_zone *data = tz->devdata;
++
++	if (!data || trip >= data->ntrips || trip < 0)
++		return false;
++
++	return true;
++}
++EXPORT_SYMBOL_GPL(of_thermal_is_trip_valid);
++
++/**
++ * of_thermal_get_trip_points - function to get access to a globally exported
++ *				trip points
++ *
++ * @tz:	pointer to a thermal zone
++ *
++ * This function provides a pointer to trip points table
++ *
++ * Return: pointer to trip points table, NULL otherwise
++ */
++const struct thermal_trip *
++of_thermal_get_trip_points(struct thermal_zone_device *tz)
++{
++	struct __thermal_zone *data = tz->devdata;
++
++	if (!data)
++		return NULL;
++
++	return data->trips;
++}
++EXPORT_SYMBOL_GPL(of_thermal_get_trip_points);
++
++/**
++ * of_thermal_set_emul_temp - function to set emulated temperature
++ *
++ * @tz:	pointer to a thermal zone
++ * @temp:	temperature to set
++ *
++ * This function gives the ability to set emulated value of temperature,
++ * which is handy for debugging
++ *
++ * Return: zero on success, error code otherwise
++ */
++static int of_thermal_set_emul_temp(struct thermal_zone_device *tz,
++				    unsigned long temp)
++{
++	struct __thermal_zone *data = tz->devdata;
++
++	if (!data->ops || !data->ops->set_emul_temp)
++		return -EINVAL;
++
++	return data->ops->set_emul_temp(data->sensor_data, temp);
+ }
+ 
+ static int of_thermal_get_trend(struct thermal_zone_device *tz, int trip,
+@@ -120,10 +194,10 @@ static int of_thermal_get_trend(struct thermal_zone_device *tz, int trip,
+ 	long dev_trend;
+ 	int r;
+ 
+-	if (!data->get_trend)
++	if (!data->ops->get_trend)
+ 		return -EINVAL;
+ 
+-	r = data->get_trend(data->sensor_data, &dev_trend);
++	r = data->ops->get_trend(data->sensor_data, &dev_trend);
+ 	if (r)
+ 		return r;
+ 
+@@ -157,7 +231,8 @@ static int of_thermal_bind(struct thermal_zone_device *thermal,
+ 			ret = thermal_zone_bind_cooling_device(thermal,
+ 						tbp->trip_id, cdev,
+ 						tbp->max,
+-						tbp->min);
++						tbp->min,
++						tbp->usage);
+ 			if (ret)
+ 				return ret;
+ 		}
+@@ -324,8 +399,7 @@ static struct thermal_zone_device_ops of_thermal_ops = {
+ static struct thermal_zone_device *
+ thermal_zone_of_add_sensor(struct device_node *zone,
+ 			   struct device_node *sensor, void *data,
+-			   int (*get_temp)(void *, long *),
+-			   int (*get_trend)(void *, long *))
++			   const struct thermal_zone_of_device_ops *ops)
+ {
+ 	struct thermal_zone_device *tzd;
+ 	struct __thermal_zone *tz;
+@@ -336,13 +410,16 @@ thermal_zone_of_add_sensor(struct device_node *zone,
+ 
+ 	tz = tzd->devdata;
+ 
++	if (!ops)
++		return ERR_PTR(-EINVAL);
++
+ 	mutex_lock(&tzd->lock);
+-	tz->get_temp = get_temp;
+-	tz->get_trend = get_trend;
++	tz->ops = ops;
+ 	tz->sensor_data = data;
+ 
+ 	tzd->ops->get_temp = of_thermal_get_temp;
+ 	tzd->ops->get_trend = of_thermal_get_trend;
++	tzd->ops->set_emul_temp = of_thermal_set_emul_temp;
+ 	mutex_unlock(&tzd->lock);
+ 
+ 	return tzd;
+@@ -356,8 +433,7 @@ thermal_zone_of_add_sensor(struct device_node *zone,
+  *             than one sensors
+  * @data: a private pointer (owned by the caller) that will be passed
+  *        back, when a temperature reading is needed.
+- * @get_temp: a pointer to a function that reads the sensor temperature.
+- * @get_trend: a pointer to a function that reads the sensor temperature trend.
++ * @ops: struct thermal_zone_of_device_ops *. Must contain at least .get_temp.
+  *
+  * This function will search the list of thermal zones described in device
+  * tree and look for the zone that refer to the sensor device pointed by
+@@ -382,9 +458,8 @@ thermal_zone_of_add_sensor(struct device_node *zone,
+  * check the return value with help of IS_ERR() helper.
+  */
+ struct thermal_zone_device *
+-thermal_zone_of_sensor_register(struct device *dev, int sensor_id,
+-				void *data, int (*get_temp)(void *, long *),
+-				int (*get_trend)(void *, long *))
++thermal_zone_of_sensor_register(struct device *dev, int sensor_id, void *data,
++				const struct thermal_zone_of_device_ops *ops)
+ {
+ 	struct device_node *np, *child, *sensor_np;
+ 	struct thermal_zone_device *tzd = ERR_PTR(-ENODEV);
+@@ -426,9 +501,10 @@ thermal_zone_of_sensor_register(struct device *dev, int sensor_id,
+ 
+ 		if (sensor_specs.np == sensor_np && id == sensor_id) {
+ 			tzd = thermal_zone_of_add_sensor(child, sensor_np,
+-							 data,
+-							 get_temp,
+-							 get_trend);
++							 data, ops);
++			if (!IS_ERR(tzd))
++				tzd->ops->set_mode(tzd, THERMAL_DEVICE_ENABLED);
++
+ 			of_node_put(sensor_specs.np);
+ 			of_node_put(child);
+ 			goto exit;
+@@ -475,9 +551,9 @@ void thermal_zone_of_sensor_unregister(struct device *dev,
+ 	mutex_lock(&tzd->lock);
+ 	tzd->ops->get_temp = NULL;
+ 	tzd->ops->get_trend = NULL;
++	tzd->ops->set_emul_temp = NULL;
+ 
+-	tz->get_temp = NULL;
+-	tz->get_trend = NULL;
++	tz->ops = NULL;
+ 	tz->sensor_data = NULL;
+ 	mutex_unlock(&tzd->lock);
+ }
+@@ -501,7 +577,7 @@ EXPORT_SYMBOL_GPL(thermal_zone_of_sensor_unregister);
+  */
+ static int thermal_of_populate_bind_params(struct device_node *np,
+ 					   struct __thermal_bind_params *__tbp,
+-					   struct __thermal_trip *trips,
++					   struct thermal_trip *trips,
+ 					   int ntrips)
+ {
+ 	struct of_phandle_args cooling_spec;
+@@ -510,7 +586,7 @@ static int thermal_of_populate_bind_params(struct device_node *np,
+ 	u32 prop;
+ 
+ 	/* Default weight. Usage is optional */
+-	__tbp->usage = 0;
++	__tbp->usage = THERMAL_WEIGHT_DEFAULT;
+ 	ret = of_property_read_u32(np, "contribution", &prop);
+ 	if (ret == 0)
+ 		__tbp->usage = prop;
+@@ -604,7 +680,7 @@ static int thermal_of_get_trip_type(struct device_node *np,
+  * Return: 0 on success, proper error code otherwise
+  */
+ static int thermal_of_populate_trip(struct device_node *np,
+-				    struct __thermal_trip *trip)
++				    struct thermal_trip *trip)
+ {
+ 	int prop;
+ 	int ret;
+@@ -644,7 +720,7 @@ static int thermal_of_populate_trip(struct device_node *np,
+  * @np parameter and fills the read data into a __thermal_zone data structure
+  * and return this pointer.
+  *
+- * TODO: Missing properties to parse: thermal-sensor-names and coefficients
++ * TODO: Missing properties to parse: thermal-sensor-names
+  *
+  * Return: On success returns a valid struct __thermal_zone,
+  * otherwise, it returns a corresponding ERR_PTR(). Caller must
+@@ -656,7 +732,7 @@ thermal_of_build_thermal_zone(struct device_node *np)
+ 	struct device_node *child = NULL, *gchild;
+ 	struct __thermal_zone *tz;
+ 	int ret, i;
+-	u32 prop;
++	u32 prop, coef[2];
+ 
+ 	if (!np) {
+ 		pr_err("no thermal zone np\n");
+@@ -681,6 +757,20 @@ thermal_of_build_thermal_zone(struct device_node *np)
+ 	}
+ 	tz->polling_delay = prop;
+ 
++	/*
++	 * REVIST: for now, the thermal framework supports only
++	 * one sensor per thermal zone. Thus, we are considering
++	 * only the first two values as slope and offset.
++	 */
++	ret = of_property_read_u32_array(np, "coefficients", coef, 2);
++	if (ret == 0) {
++		tz->slope = coef[0];
++		tz->offset = coef[1];
++	} else {
++		tz->slope = 1;
++		tz->offset = 0;
++	}
++
+ 	/* trips */
+ 	child = of_get_child_by_name(np, "trips");
+ 
+@@ -794,6 +884,8 @@ int __init of_parse_thermal_zones(void)
+ 	for_each_child_of_node(np, child) {
+ 		struct thermal_zone_device *zone;
+ 		struct thermal_zone_params *tzp;
++		int i, mask = 0;
++		u32 prop;
+ 
+ 		/* Check whether child is enabled or not */
+ 		if (!of_device_is_available(child))
+@@ -820,8 +912,18 @@ int __init of_parse_thermal_zones(void)
+ 		/* No hwmon because there might be hwmon drivers registering */
+ 		tzp->no_hwmon = true;
+ 
++		if (!of_property_read_u32(child, "sustainable-power", &prop))
++			tzp->sustainable_power = prop;
++
++		for (i = 0; i < tz->ntrips; i++)
++			mask |= 1 << i;
++
++		/* these two are left for temperature drivers to use */
++		tzp->slope = tz->slope;
++		tzp->offset = tz->offset;
++
+ 		zone = thermal_zone_device_register(child->name, tz->ntrips,
+-						    0, tz,
++						    mask, tz,
+ 						    ops, tzp,
+ 						    tz->passive_delay,
+ 						    tz->polling_delay);
+diff --git a/drivers/thermal/power_allocator.c b/drivers/thermal/power_allocator.c
+new file mode 100644
+index 0000000..2516769
+--- /dev/null
++++ b/drivers/thermal/power_allocator.c
+@@ -0,0 +1,544 @@
++/*
++ * A power allocator to manage temperature
++ *
++ * Copyright (C) 2014 ARM Ltd.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed "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.
++ */
++
++#define pr_fmt(fmt) "Power allocator: " fmt
++
++#include <linux/rculist.h>
++#include <linux/slab.h>
++#include <linux/thermal.h>
++
++#define CREATE_TRACE_POINTS
++#include <trace/events/thermal_power_allocator.h>
++
++#include "thermal_core.h"
++
++#define FRAC_BITS 10
++#define int_to_frac(x) ((x) << FRAC_BITS)
++#define frac_to_int(x) ((x) >> FRAC_BITS)
++
++/**
++ * mul_frac() - multiply two fixed-point numbers
++ * @x:	first multiplicand
++ * @y:	second multiplicand
++ *
++ * Return: the result of multiplying two fixed-point numbers.  The
++ * result is also a fixed-point number.
++ */
++static inline s64 mul_frac(s64 x, s64 y)
++{
++	return (x * y) >> FRAC_BITS;
++}
++
++/**
++ * div_frac() - divide two fixed-point numbers
++ * @x:	the dividend
++ * @y:	the divisor
++ *
++ * Return: the result of dividing two fixed-point numbers.  The
++ * result is also a fixed-point number.
++ */
++static inline s64 div_frac(s64 x, s64 y)
++{
++	return div_s64(x << FRAC_BITS, y);
++}
++
++/**
++ * struct power_allocator_params - parameters for the power allocator governor
++ * @err_integral:	accumulated error in the PID controller.
++ * @prev_err:	error in the previous iteration of the PID controller.
++ *		Used to calculate the derivative term.
++ * @trip_switch_on:	first passive trip point of the thermal zone.  The
++ *			governor switches on when this trip point is crossed.
++ * @trip_max_desired_temperature:	last passive trip point of the thermal
++ *					zone.  The temperature we are
++ *					controlling for.
++ */
++struct power_allocator_params {
++	s64 err_integral;
++	s32 prev_err;
++	int trip_switch_on;
++	int trip_max_desired_temperature;
++};
++
++/**
++ * pid_controller() - PID controller
++ * @tz:	thermal zone we are operating in
++ * @current_temp:	the current temperature in millicelsius
++ * @control_temp:	the target temperature in millicelsius
++ * @max_allocatable_power:	maximum allocatable power for this thermal zone
++ *
++ * This PID controller increases the available power budget so that the
++ * temperature of the thermal zone gets as close as possible to
++ * @control_temp and limits the power if it exceeds it.  k_po is the
++ * proportional term when we are overshooting, k_pu is the
++ * proportional term when we are undershooting.  integral_cutoff is a
++ * threshold below which we stop accumulating the error.  The
++ * accumulated error is only valid if the requested power will make
++ * the system warmer.  If the system is mostly idle, there's no point
++ * in accumulating positive error.
++ *
++ * Return: The power budget for the next period.
++ */
++static u32 pid_controller(struct thermal_zone_device *tz,
++			  unsigned long current_temp,
++			  unsigned long control_temp,
++			  u32 max_allocatable_power)
++{
++	s64 p, i, d, power_range;
++	s32 err, max_power_frac;
++	struct power_allocator_params *params = tz->governor_data;
++
++	max_power_frac = int_to_frac(max_allocatable_power);
++
++	err = ((s32)control_temp - (s32)current_temp);
++	err = int_to_frac(err);
++
++	/* Calculate the proportional term */
++	p = mul_frac(err < 0 ? tz->tzp->k_po : tz->tzp->k_pu, err);
++
++	/*
++	 * Calculate the integral term
++	 *
++	 * if the error is less than cut off allow integration (but
++	 * the integral is limited to max power)
++	 */
++	i = mul_frac(tz->tzp->k_i, params->err_integral);
++
++	if (err < int_to_frac(tz->tzp->integral_cutoff)) {
++		s64 i_next = i + mul_frac(tz->tzp->k_i, err);
++
++		if (abs64(i_next) < max_power_frac) {
++			i = i_next;
++			params->err_integral += err;
++		}
++	}
++
++	/*
++	 * Calculate the derivative term
++	 *
++	 * We do err - prev_err, so with a positive k_d, a decreasing
++	 * error (i.e. driving closer to the line) results in less
++	 * power being applied, slowing down the controller)
++	 */
++	d = mul_frac(tz->tzp->k_d, err - params->prev_err);
++	d = div_frac(d, tz->passive_delay);
++	params->prev_err = err;
++
++	power_range = p + i + d;
++
++	/* feed-forward the known sustainable dissipatable power */
++	power_range = tz->tzp->sustainable_power + frac_to_int(power_range);
++
++	power_range = clamp(power_range, (s64)0, (s64)max_allocatable_power);
++
++	trace_thermal_power_allocator_pid(tz, frac_to_int(err),
++					  frac_to_int(params->err_integral),
++					  frac_to_int(p), frac_to_int(i),
++					  frac_to_int(d), power_range);
++
++	return power_range;
++}
++
++/**
++ * divvy_up_power() - divvy the allocated power between the actors
++ * @req_power:	each actor's requested power
++ * @max_power:	each actor's maximum available power
++ * @num_actors:	size of the @req_power, @max_power and @granted_power's array
++ * @total_req_power: sum of @req_power
++ * @power_range:	total allocated power
++ * @granted_power:	output array: each actor's granted power
++ * @extra_actor_power:	an appropriately sized array to be used in the
++ *			function as temporary storage of the extra power given
++ *			to the actors
++ *
++ * This function divides the total allocated power (@power_range)
++ * fairly between the actors.  It first tries to give each actor a
++ * share of the @power_range according to how much power it requested
++ * compared to the rest of the actors.  For example, if only one actor
++ * requests power, then it receives all the @power_range.  If
++ * three actors each requests 1mW, each receives a third of the
++ * @power_range.
++ *
++ * If any actor received more than their maximum power, then that
++ * surplus is re-divvied among the actors based on how far they are
++ * from their respective maximums.
++ *
++ * Granted power for each actor is written to @granted_power, which
++ * should've been allocated by the calling function.
++ */
++static void divvy_up_power(u32 *req_power, u32 *max_power, int num_actors,
++			   u32 total_req_power, u32 power_range,
++			   u32 *granted_power, u32 *extra_actor_power)
++{
++	u32 extra_power, capped_extra_power;
++	int i;
++
++	/*
++	 * Prevent division by 0 if none of the actors request power.
++	 */
++	if (!total_req_power)
++		total_req_power = 1;
++
++	capped_extra_power = 0;
++	extra_power = 0;
++	for (i = 0; i < num_actors; i++) {
++		u64 req_range = req_power[i] * power_range;
++
++		granted_power[i] = DIV_ROUND_CLOSEST_ULL(req_range,
++							 total_req_power);
++
++		if (granted_power[i] > max_power[i]) {
++			extra_power += granted_power[i] - max_power[i];
++			granted_power[i] = max_power[i];
++		}
++
++		extra_actor_power[i] = max_power[i] - granted_power[i];
++		capped_extra_power += extra_actor_power[i];
++	}
++
++	if (!extra_power)
++		return;
++
++	/*
++	 * Re-divvy the reclaimed extra among actors based on
++	 * how far they are from the max
++	 */
++	extra_power = min(extra_power, capped_extra_power);
++	if (capped_extra_power > 0)
++		for (i = 0; i < num_actors; i++)
++			granted_power[i] += (extra_actor_power[i] *
++					extra_power) / capped_extra_power;
++}
++
++static int allocate_power(struct thermal_zone_device *tz,
++			  unsigned long current_temp,
++			  unsigned long control_temp)
++{
++	struct thermal_instance *instance;
++	struct power_allocator_params *params = tz->governor_data;
++	u32 *req_power, *max_power, *granted_power, *extra_actor_power;
++	u32 *weighted_req_power;
++	u32 total_req_power, max_allocatable_power, total_weighted_req_power;
++	u32 total_granted_power, power_range;
++	int i, num_actors, total_weight, ret = 0;
++	int trip_max_desired_temperature = params->trip_max_desired_temperature;
++
++	mutex_lock(&tz->lock);
++
++	num_actors = 0;
++	total_weight = 0;
++	list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
++		if ((instance->trip == trip_max_desired_temperature) &&
++		    cdev_is_power_actor(instance->cdev)) {
++			num_actors++;
++			total_weight += instance->weight;
++		}
++	}
++
++	/*
++	 * We need to allocate five arrays of the same size:
++	 * req_power, max_power, granted_power, extra_actor_power and
++	 * weighted_req_power.  They are going to be needed until this
++	 * function returns.  Allocate them all in one go to simplify
++	 * the allocation and deallocation logic.
++	 */
++	BUILD_BUG_ON(sizeof(*req_power) != sizeof(*max_power));
++	BUILD_BUG_ON(sizeof(*req_power) != sizeof(*granted_power));
++	BUILD_BUG_ON(sizeof(*req_power) != sizeof(*extra_actor_power));
++	BUILD_BUG_ON(sizeof(*req_power) != sizeof(*weighted_req_power));
++	req_power = kcalloc(num_actors * 5, sizeof(*req_power), GFP_KERNEL);
++	if (!req_power) {
++		ret = -ENOMEM;
++		goto unlock;
++	}
++
++	max_power = &req_power[num_actors];
++	granted_power = &req_power[2 * num_actors];
++	extra_actor_power = &req_power[3 * num_actors];
++	weighted_req_power = &req_power[4 * num_actors];
++
++	i = 0;
++	total_weighted_req_power = 0;
++	total_req_power = 0;
++	max_allocatable_power = 0;
++
++	list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
++		int weight;
++		struct thermal_cooling_device *cdev = instance->cdev;
++
++		if (instance->trip != trip_max_desired_temperature)
++			continue;
++
++		if (!cdev_is_power_actor(cdev))
++			continue;
++
++		if (cdev->ops->get_requested_power(cdev, tz, &req_power[i]))
++			continue;
++
++		if (!total_weight)
++			weight = 1 << FRAC_BITS;
++		else
++			weight = instance->weight;
++
++		weighted_req_power[i] = frac_to_int(weight * req_power[i]);
++
++		if (power_actor_get_max_power(cdev, tz, &max_power[i]))
++			continue;
++
++		total_req_power += req_power[i];
++		max_allocatable_power += max_power[i];
++		total_weighted_req_power += weighted_req_power[i];
++
++		i++;
++	}
++
++	power_range = pid_controller(tz, current_temp, control_temp,
++				     max_allocatable_power);
++
++	divvy_up_power(weighted_req_power, max_power, num_actors,
++		       total_weighted_req_power, power_range, granted_power,
++		       extra_actor_power);
++
++	total_granted_power = 0;
++	i = 0;
++	list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
++		if (instance->trip != trip_max_desired_temperature)
++			continue;
++
++		if (!cdev_is_power_actor(instance->cdev))
++			continue;
++
++		power_actor_set_power(instance->cdev, instance,
++				      granted_power[i]);
++		total_granted_power += granted_power[i];
++
++		i++;
++	}
++
++	trace_thermal_power_allocator(tz, req_power, total_req_power,
++				      granted_power, total_granted_power,
++				      num_actors, power_range,
++				      max_allocatable_power, current_temp,
++				      (s32)control_temp - (s32)current_temp);
++
++	kfree(req_power);
++unlock:
++	mutex_unlock(&tz->lock);
++
++	return ret;
++}
++
++static int get_governor_trips(struct thermal_zone_device *tz,
++			      struct power_allocator_params *params)
++{
++	int i, ret, last_passive;
++	bool found_first_passive;
++
++	found_first_passive = false;
++	last_passive = -1;
++	ret = -EINVAL;
++
++	for (i = 0; i < tz->trips; i++) {
++		enum thermal_trip_type type;
++
++		ret = tz->ops->get_trip_type(tz, i, &type);
++		if (ret)
++			return ret;
++
++		if (!found_first_passive) {
++			if (type == THERMAL_TRIP_PASSIVE) {
++				params->trip_switch_on = i;
++				found_first_passive = true;
++			}
++		} else if (type == THERMAL_TRIP_PASSIVE) {
++			last_passive = i;
++		} else {
++			break;
++		}
++	}
++
++	if (last_passive != -1) {
++		params->trip_max_desired_temperature = last_passive;
++		ret = 0;
++	} else {
++		ret = -EINVAL;
++	}
++
++	return ret;
++}
++
++static void reset_pid_controller(struct power_allocator_params *params)
++{
++	params->err_integral = 0;
++	params->prev_err = 0;
++}
++
++static void allow_maximum_power(struct thermal_zone_device *tz)
++{
++	struct thermal_instance *instance;
++	struct power_allocator_params *params = tz->governor_data;
++
++	list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
++		if ((instance->trip != params->trip_max_desired_temperature) ||
++		    (!cdev_is_power_actor(instance->cdev)))
++			continue;
++
++		instance->target = 0;
++		instance->cdev->updated = false;
++		thermal_cdev_update(instance->cdev);
++	}
++}
++
++/**
++ * power_allocator_bind() - bind the power_allocator governor to a thermal zone
++ * @tz:	thermal zone to bind it to
++ *
++ * Check that the thermal zone is valid for this governor, that is, it
++ * has two thermal trips.  If so, initialize the PID controller
++ * parameters and bind it to the thermal zone.
++ *
++ * Return: 0 on success, -EINVAL if the trips were invalid or -ENOMEM
++ * if we ran out of memory.
++ */
++static int power_allocator_bind(struct thermal_zone_device *tz)
++{
++	int ret;
++	struct power_allocator_params *params;
++	unsigned long switch_on_temp, control_temp;
++	u32 temperature_threshold;
++
++	if (!tz->tzp || !tz->tzp->sustainable_power) {
++		dev_err(&tz->device,
++			"power_allocator: missing sustainable_power\n");
++		return -EINVAL;
++	}
++
++	params = kzalloc(sizeof(*params), GFP_KERNEL);
++	if (!params)
++		return -ENOMEM;
++
++	ret = get_governor_trips(tz, params);
++	if (ret) {
++		dev_err(&tz->device,
++			"thermal zone %s has wrong trip setup for power allocator\n",
++			tz->type);
++		goto free;
++	}
++
++	ret = tz->ops->get_trip_temp(tz, params->trip_switch_on,
++				     &switch_on_temp);
++	if (ret)
++		goto free;
++
++	ret = tz->ops->get_trip_temp(tz, params->trip_max_desired_temperature,
++				     &control_temp);
++	if (ret)
++		goto free;
++
++	temperature_threshold = control_temp - switch_on_temp;
++
++	tz->tzp->k_po = tz->tzp->k_po ?:
++		int_to_frac(tz->tzp->sustainable_power) / temperature_threshold;
++	tz->tzp->k_pu = tz->tzp->k_pu ?:
++		int_to_frac(2 * tz->tzp->sustainable_power) /
++		temperature_threshold;
++	tz->tzp->k_i = tz->tzp->k_i ?: int_to_frac(10) / 1000;
++	/*
++	 * The default for k_d and integral_cutoff is 0, so we can
++	 * leave them as they are.
++	 */
++
++	reset_pid_controller(params);
++
++	tz->governor_data = params;
++
++	return 0;
++
++free:
++	kfree(params);
++	return ret;
++}
++
++static void power_allocator_unbind(struct thermal_zone_device *tz)
++{
++	dev_dbg(&tz->device, "Unbinding from thermal zone %d\n", tz->id);
++	kfree(tz->governor_data);
++	tz->governor_data = NULL;
++}
++
++static int power_allocator_throttle(struct thermal_zone_device *tz, int trip)
++{
++	int ret;
++	unsigned long switch_on_temp, control_temp, current_temp;
++	struct power_allocator_params *params = tz->governor_data;
++
++	/*
++	 * We get called for every trip point but we only need to do
++	 * our calculations once
++	 */
++	if (trip != params->trip_max_desired_temperature)
++		return 0;
++
++	ret = thermal_zone_get_temp(tz, &current_temp);
++	if (ret) {
++		dev_warn(&tz->device, "Failed to get temperature: %d\n", ret);
++		return ret;
++	}
++
++	ret = tz->ops->get_trip_temp(tz, params->trip_switch_on,
++				     &switch_on_temp);
++	if (ret) {
++		dev_warn(&tz->device,
++			 "Failed to get switch on temperature: %d\n", ret);
++		return ret;
++	}
++
++	if (current_temp < switch_on_temp) {
++		tz->passive = 0;
++		reset_pid_controller(params);
++		allow_maximum_power(tz);
++		return 0;
++	}
++
++	tz->passive = 1;
++
++	ret = tz->ops->get_trip_temp(tz, params->trip_max_desired_temperature,
++				&control_temp);
++	if (ret) {
++		dev_warn(&tz->device,
++			 "Failed to get the maximum desired temperature: %d\n",
++			 ret);
++		return ret;
++	}
++
++	return allocate_power(tz, current_temp, control_temp);
++}
++
++static struct thermal_governor thermal_gov_power_allocator = {
++	.name		= "power_allocator",
++	.bind_to_tz	= power_allocator_bind,
++	.unbind_from_tz	= power_allocator_unbind,
++	.throttle	= power_allocator_throttle,
++};
++
++int thermal_gov_power_allocator_register(void)
++{
++	return thermal_register_governor(&thermal_gov_power_allocator);
++}
++
++void thermal_gov_power_allocator_unregister(void)
++{
++	thermal_unregister_governor(&thermal_gov_power_allocator);
++}
+diff --git a/drivers/thermal/samsung/Kconfig b/drivers/thermal/samsung/Kconfig
+index f760389..c43306e 100644
+--- a/drivers/thermal/samsung/Kconfig
++++ b/drivers/thermal/samsung/Kconfig
+@@ -1,6 +1,6 @@
+ config EXYNOS_THERMAL
+ 	tristate "Exynos thermal management unit driver"
+-	depends on ARCH_HAS_BANDGAP && OF
++	depends on OF
+ 	help
+ 	  If you say yes here you get support for the TMU (Thermal Management
+ 	  Unit) driver for SAMSUNG EXYNOS series of SoCs. This driver initialises
+diff --git a/drivers/thermal/samsung/exynos_thermal_common.c b/drivers/thermal/samsung/exynos_thermal_common.c
+index b6be572..7c97db1 100644
+--- a/drivers/thermal/samsung/exynos_thermal_common.c
++++ b/drivers/thermal/samsung/exynos_thermal_common.c
+@@ -163,7 +163,7 @@ static int exynos_bind(struct thermal_zone_device *thermal,
+ 		case MONITOR_ZONE:
+ 		case WARN_ZONE:
+ 			if (thermal_zone_bind_cooling_device(thermal, i, cdev,
+-								level, 0)) {
++							     level, 0, THERMAL_WEIGHT_DEFAULT)) {
+ 				dev_err(data->dev,
+ 					"error unbinding cdev inst=%d\n", i);
+ 				ret = -EINVAL;
+@@ -371,9 +371,11 @@ int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf)
+ 		th_zone->cool_dev[th_zone->cool_dev_size] =
+ 					cpufreq_cooling_register(&mask_val);
+ 		if (IS_ERR(th_zone->cool_dev[th_zone->cool_dev_size])) {
+-			dev_err(sensor_conf->dev,
+-				"Failed to register cpufreq cooling device\n");
+-			ret = -EINVAL;
++			ret = PTR_ERR(th_zone->cool_dev[th_zone->cool_dev_size]);
++			if (ret != -EPROBE_DEFER)
++				dev_err(sensor_conf->dev,
++					"Failed to register cpufreq cooling device: %d\n",
++					ret);
+ 			goto err_unregister;
+ 		}
+ 		th_zone->cool_dev_size++;
+diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
+index 49c0924..2afca9b 100644
+--- a/drivers/thermal/samsung/exynos_tmu.c
++++ b/drivers/thermal/samsung/exynos_tmu.c
+@@ -683,7 +683,10 @@ static int exynos_tmu_probe(struct platform_device *pdev)
+ 	/* Register the sensor with thermal management interface */
+ 	ret = exynos_register_thermal(sensor_conf);
+ 	if (ret) {
+-		dev_err(&pdev->dev, "Failed to register thermal interface\n");
++		if (ret != -EPROBE_DEFER)
++			dev_err(&pdev->dev,
++				"Failed to register thermal interface: %d\n",
++				ret);
+ 		goto err_clk;
+ 	}
+ 	data->reg_conf = sensor_conf;
+diff --git a/drivers/thermal/tegra_soctherm.c b/drivers/thermal/tegra_soctherm.c
+new file mode 100644
+index 0000000..9197fc0
+--- /dev/null
++++ b/drivers/thermal/tegra_soctherm.c
+@@ -0,0 +1,476 @@
++/*
++ * Copyright (c) 2014, NVIDIA CORPORATION.  All rights reserved.
++ *
++ * Author:
++ *	Mikko Perttunen <mperttunen@nvidia.com>
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#include <linux/bitops.h>
++#include <linux/clk.h>
++#include <linux/delay.h>
++#include <linux/err.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++#include <linux/reset.h>
++#include <linux/thermal.h>
++
++#include <soc/tegra/fuse.h>
++
++#define SENSOR_CONFIG0				0
++#define SENSOR_CONFIG0_STOP			BIT(0)
++#define SENSOR_CONFIG0_TALL_SHIFT		8
++#define SENSOR_CONFIG0_TCALC_OVER		BIT(4)
++#define SENSOR_CONFIG0_OVER			BIT(3)
++#define SENSOR_CONFIG0_CPTR_OVER		BIT(2)
++
++#define SENSOR_CONFIG1				4
++#define SENSOR_CONFIG1_TSAMPLE_SHIFT		0
++#define SENSOR_CONFIG1_TIDDQ_EN_SHIFT		15
++#define SENSOR_CONFIG1_TEN_COUNT_SHIFT		24
++#define SENSOR_CONFIG1_TEMP_ENABLE		BIT(31)
++
++#define SENSOR_CONFIG2				8
++#define SENSOR_CONFIG2_THERMA_SHIFT		16
++#define SENSOR_CONFIG2_THERMB_SHIFT		0
++
++#define SENSOR_PDIV				0x1c0
++#define SENSOR_PDIV_T124			0x8888
++#define SENSOR_HOTSPOT_OFF			0x1c4
++#define SENSOR_HOTSPOT_OFF_T124			0x00060600
++#define SENSOR_TEMP1				0x1c8
++#define SENSOR_TEMP2				0x1cc
++
++#define SENSOR_TEMP_MASK			0xffff
++#define READBACK_VALUE_MASK			0xff00
++#define READBACK_VALUE_SHIFT			8
++#define READBACK_ADD_HALF			BIT(7)
++#define READBACK_NEGATE				BIT(1)
++
++#define FUSE_TSENSOR8_CALIB			0x180
++#define FUSE_SPARE_REALIGNMENT_REG_0		0x1fc
++
++#define FUSE_TSENSOR_CALIB_CP_TS_BASE_MASK	0x1fff
++#define FUSE_TSENSOR_CALIB_FT_TS_BASE_MASK	(0x1fff << 13)
++#define FUSE_TSENSOR_CALIB_FT_TS_BASE_SHIFT	13
++
++#define FUSE_TSENSOR8_CALIB_CP_TS_BASE_MASK	0x3ff
++#define FUSE_TSENSOR8_CALIB_FT_TS_BASE_MASK	(0x7ff << 10)
++#define FUSE_TSENSOR8_CALIB_FT_TS_BASE_SHIFT	10
++
++#define FUSE_SPARE_REALIGNMENT_REG_SHIFT_CP_MASK 0x3f
++#define FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT_MASK (0x1f << 21)
++#define FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT_SHIFT 21
++
++#define NOMINAL_CALIB_FT_T124			105
++#define NOMINAL_CALIB_CP_T124			25
++
++struct tegra_tsensor_configuration {
++	u32 tall, tsample, tiddq_en, ten_count, pdiv, tsample_ate, pdiv_ate;
++};
++
++struct tegra_tsensor {
++	const struct tegra_tsensor_configuration *config;
++	u32 base, calib_fuse_offset;
++	/* Correction values used to modify values read from calibration fuses */
++	s32 fuse_corr_alpha, fuse_corr_beta;
++};
++
++struct tegra_thermctl_zone {
++	void __iomem *reg;
++	unsigned int shift;
++};
++
++static const struct tegra_tsensor_configuration t124_tsensor_config = {
++	.tall = 16300,
++	.tsample = 120,
++	.tiddq_en = 1,
++	.ten_count = 1,
++	.pdiv = 8,
++	.tsample_ate = 480,
++	.pdiv_ate = 8
++};
++
++static const struct tegra_tsensor t124_tsensors[] = {
++	{
++		.config = &t124_tsensor_config,
++		.base = 0xc0,
++		.calib_fuse_offset = 0x098,
++		.fuse_corr_alpha = 1135400,
++		.fuse_corr_beta = -6266900,
++	},
++	{
++		.config = &t124_tsensor_config,
++		.base = 0xe0,
++		.calib_fuse_offset = 0x084,
++		.fuse_corr_alpha = 1122220,
++		.fuse_corr_beta = -5700700,
++	},
++	{
++		.config = &t124_tsensor_config,
++		.base = 0x100,
++		.calib_fuse_offset = 0x088,
++		.fuse_corr_alpha = 1127000,
++		.fuse_corr_beta = -6768200,
++	},
++	{
++		.config = &t124_tsensor_config,
++		.base = 0x120,
++		.calib_fuse_offset = 0x12c,
++		.fuse_corr_alpha = 1110900,
++		.fuse_corr_beta = -6232000,
++	},
++	{
++		.config = &t124_tsensor_config,
++		.base = 0x140,
++		.calib_fuse_offset = 0x158,
++		.fuse_corr_alpha = 1122300,
++		.fuse_corr_beta = -5936400,
++	},
++	{
++		.config = &t124_tsensor_config,
++		.base = 0x160,
++		.calib_fuse_offset = 0x15c,
++		.fuse_corr_alpha = 1145700,
++		.fuse_corr_beta = -7124600,
++	},
++	{
++		.config = &t124_tsensor_config,
++		.base = 0x180,
++		.calib_fuse_offset = 0x154,
++		.fuse_corr_alpha = 1120100,
++		.fuse_corr_beta = -6000500,
++	},
++	{
++		.config = &t124_tsensor_config,
++		.base = 0x1a0,
++		.calib_fuse_offset = 0x160,
++		.fuse_corr_alpha = 1106500,
++		.fuse_corr_beta = -6729300,
++	},
++};
++
++struct tegra_soctherm {
++	struct reset_control *reset;
++	struct clk *clock_tsensor;
++	struct clk *clock_soctherm;
++	void __iomem *regs;
++
++	struct thermal_zone_device *thermctl_tzs[4];
++};
++
++struct tsensor_shared_calibration {
++	u32 base_cp, base_ft;
++	u32 actual_temp_cp, actual_temp_ft;
++};
++
++static int calculate_shared_calibration(struct tsensor_shared_calibration *r)
++{
++	u32 val, shifted_cp, shifted_ft;
++	int err;
++
++	err = tegra_fuse_readl(FUSE_TSENSOR8_CALIB, &val);
++	if (err)
++		return err;
++	r->base_cp = val & FUSE_TSENSOR8_CALIB_CP_TS_BASE_MASK;
++	r->base_ft = (val & FUSE_TSENSOR8_CALIB_FT_TS_BASE_MASK)
++		>> FUSE_TSENSOR8_CALIB_FT_TS_BASE_SHIFT;
++	val = ((val & FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT_MASK)
++		>> FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT_SHIFT);
++	shifted_ft = sign_extend32(val, 4);
++
++	err = tegra_fuse_readl(FUSE_SPARE_REALIGNMENT_REG_0, &val);
++	if (err)
++		return err;
++	shifted_cp = sign_extend32(val, 5);
++
++	r->actual_temp_cp = 2 * NOMINAL_CALIB_CP_T124 + shifted_cp;
++	r->actual_temp_ft = 2 * NOMINAL_CALIB_FT_T124 + shifted_ft;
++
++	return 0;
++}
++
++static s64 div64_s64_precise(s64 a, s64 b)
++{
++	s64 r, al;
++
++	/* Scale up for increased precision division */
++	al = a << 16;
++
++	r = div64_s64(al * 2 + 1, 2 * b);
++	return r >> 16;
++}
++
++static int
++calculate_tsensor_calibration(const struct tegra_tsensor *sensor,
++			      const struct tsensor_shared_calibration *shared,
++			      u32 *calib)
++{
++	u32 val;
++	s32 actual_tsensor_ft, actual_tsensor_cp, delta_sens, delta_temp,
++	    mult, div;
++	s16 therma, thermb;
++	s64 tmp;
++	int err;
++
++	err = tegra_fuse_readl(sensor->calib_fuse_offset, &val);
++	if (err)
++		return err;
++
++	actual_tsensor_cp = (shared->base_cp * 64) + sign_extend32(val, 12);
++	val = (val & FUSE_TSENSOR_CALIB_FT_TS_BASE_MASK)
++		>> FUSE_TSENSOR_CALIB_FT_TS_BASE_SHIFT;
++	actual_tsensor_ft = (shared->base_ft * 32) + sign_extend32(val, 12);
++
++	delta_sens = actual_tsensor_ft - actual_tsensor_cp;
++	delta_temp = shared->actual_temp_ft - shared->actual_temp_cp;
++
++	mult = sensor->config->pdiv * sensor->config->tsample_ate;
++	div = sensor->config->tsample * sensor->config->pdiv_ate;
++
++	therma = div64_s64_precise((s64) delta_temp * (1LL << 13) * mult,
++				   (s64) delta_sens * div);
++
++	tmp = (s64)actual_tsensor_ft * shared->actual_temp_cp -
++	      (s64)actual_tsensor_cp * shared->actual_temp_ft;
++	thermb = div64_s64_precise(tmp, (s64)delta_sens);
++
++	therma = div64_s64_precise((s64)therma * sensor->fuse_corr_alpha,
++				   (s64)1000000LL);
++	thermb = div64_s64_precise((s64)thermb * sensor->fuse_corr_alpha +
++				   sensor->fuse_corr_beta, (s64)1000000LL);
++
++	*calib = ((u16)therma << SENSOR_CONFIG2_THERMA_SHIFT) |
++		 ((u16)thermb << SENSOR_CONFIG2_THERMB_SHIFT);
++
++	return 0;
++}
++
++static int enable_tsensor(struct tegra_soctherm *tegra,
++			  const struct tegra_tsensor *sensor,
++			  const struct tsensor_shared_calibration *shared)
++{
++	void __iomem *base = tegra->regs + sensor->base;
++	unsigned int val;
++	u32 calib;
++	int err;
++
++	err = calculate_tsensor_calibration(sensor, shared, &calib);
++	if (err)
++		return err;
++
++	val = sensor->config->tall << SENSOR_CONFIG0_TALL_SHIFT;
++	writel(val, base + SENSOR_CONFIG0);
++
++	val  = (sensor->config->tsample - 1) << SENSOR_CONFIG1_TSAMPLE_SHIFT;
++	val |= sensor->config->tiddq_en << SENSOR_CONFIG1_TIDDQ_EN_SHIFT;
++	val |= sensor->config->ten_count << SENSOR_CONFIG1_TEN_COUNT_SHIFT;
++	val |= SENSOR_CONFIG1_TEMP_ENABLE;
++	writel(val, base + SENSOR_CONFIG1);
++
++	writel(calib, base + SENSOR_CONFIG2);
++
++	return 0;
++}
++
++/*
++ * Translate from soctherm readback format to millicelsius.
++ * The soctherm readback format in bits is as follows:
++ *   TTTTTTTT H______N
++ * where T's contain the temperature in Celsius,
++ * H denotes an addition of 0.5 Celsius and N denotes negation
++ * of the final value.
++ */
++static long translate_temp(u16 val)
++{
++	long t;
++
++	t = ((val & READBACK_VALUE_MASK) >> READBACK_VALUE_SHIFT) * 1000;
++	if (val & READBACK_ADD_HALF)
++		t += 500;
++	if (val & READBACK_NEGATE)
++		t *= -1;
++
++	return t;
++}
++
++static int tegra_thermctl_get_temp(void *data, long *out_temp)
++{
++	struct tegra_thermctl_zone *zone = data;
++	u32 val;
++
++	val = (readl(zone->reg) >> zone->shift) & SENSOR_TEMP_MASK;
++	*out_temp = translate_temp(val);
++
++	return 0;
++}
++
++static const struct thermal_zone_of_device_ops tegra_of_thermal_ops = {
++	.get_temp = tegra_thermctl_get_temp,
++};
++
++static const struct of_device_id tegra_soctherm_of_match[] = {
++	{ .compatible = "nvidia,tegra124-soctherm" },
++	{ },
++};
++MODULE_DEVICE_TABLE(of, tegra_soctherm_of_match);
++
++struct thermctl_zone_desc {
++	unsigned int offset;
++	unsigned int shift;
++};
++
++static const struct thermctl_zone_desc t124_thermctl_temp_zones[] = {
++	{ SENSOR_TEMP1, 16 },
++	{ SENSOR_TEMP2, 16 },
++	{ SENSOR_TEMP1, 0 },
++	{ SENSOR_TEMP2, 0 }
++};
++
++static int tegra_soctherm_probe(struct platform_device *pdev)
++{
++	struct tegra_soctherm *tegra;
++	struct thermal_zone_device *tz;
++	struct tsensor_shared_calibration shared_calib;
++	struct resource *res;
++	unsigned int i;
++	int err;
++
++	const struct tegra_tsensor *tsensors = t124_tsensors;
++
++	tegra = devm_kzalloc(&pdev->dev, sizeof(*tegra), GFP_KERNEL);
++	if (!tegra)
++		return -ENOMEM;
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	tegra->regs = devm_ioremap_resource(&pdev->dev, res);
++	if (IS_ERR(tegra->regs))
++		return PTR_ERR(tegra->regs);
++
++	tegra->reset = devm_reset_control_get(&pdev->dev, "soctherm");
++	if (IS_ERR(tegra->reset)) {
++		dev_err(&pdev->dev, "can't get soctherm reset\n");
++		return PTR_ERR(tegra->reset);
++	}
++
++	tegra->clock_tsensor = devm_clk_get(&pdev->dev, "tsensor");
++	if (IS_ERR(tegra->clock_tsensor)) {
++		dev_err(&pdev->dev, "can't get tsensor clock\n");
++		return PTR_ERR(tegra->clock_tsensor);
++	}
++
++	tegra->clock_soctherm = devm_clk_get(&pdev->dev, "soctherm");
++	if (IS_ERR(tegra->clock_soctherm)) {
++		dev_err(&pdev->dev, "can't get soctherm clock\n");
++		return PTR_ERR(tegra->clock_soctherm);
++	}
++
++	reset_control_assert(tegra->reset);
++
++	err = clk_prepare_enable(tegra->clock_soctherm);
++	if (err)
++		return err;
++
++	err = clk_prepare_enable(tegra->clock_tsensor);
++	if (err) {
++		clk_disable_unprepare(tegra->clock_soctherm);
++		return err;
++	}
++
++	reset_control_deassert(tegra->reset);
++
++	/* Initialize raw sensors */
++
++	err = calculate_shared_calibration(&shared_calib);
++	if (err)
++		goto disable_clocks;
++
++	for (i = 0; i < ARRAY_SIZE(t124_tsensors); ++i) {
++		err = enable_tsensor(tegra, tsensors + i, &shared_calib);
++		if (err)
++			goto disable_clocks;
++	}
++
++	writel(SENSOR_PDIV_T124, tegra->regs + SENSOR_PDIV);
++	writel(SENSOR_HOTSPOT_OFF_T124, tegra->regs + SENSOR_HOTSPOT_OFF);
++
++	/* Initialize thermctl sensors */
++
++	for (i = 0; i < ARRAY_SIZE(tegra->thermctl_tzs); ++i) {
++		struct tegra_thermctl_zone *zone =
++			devm_kzalloc(&pdev->dev, sizeof(*zone), GFP_KERNEL);
++		if (!zone) {
++			err = -ENOMEM;
++			goto unregister_tzs;
++		}
++
++		zone->reg = tegra->regs + t124_thermctl_temp_zones[i].offset;
++		zone->shift = t124_thermctl_temp_zones[i].shift;
++
++		tz = thermal_zone_of_sensor_register(&pdev->dev, i, zone,
++						     &tegra_of_thermal_ops);
++		if (IS_ERR(tz)) {
++			err = PTR_ERR(tz);
++			dev_err(&pdev->dev, "failed to register sensor: %d\n",
++				err);
++			goto unregister_tzs;
++		}
++
++		tegra->thermctl_tzs[i] = tz;
++	}
++
++	return 0;
++
++unregister_tzs:
++	while (i--)
++		thermal_zone_of_sensor_unregister(&pdev->dev,
++						  tegra->thermctl_tzs[i]);
++
++disable_clocks:
++	clk_disable_unprepare(tegra->clock_tsensor);
++	clk_disable_unprepare(tegra->clock_soctherm);
++
++	return err;
++}
++
++static int tegra_soctherm_remove(struct platform_device *pdev)
++{
++	struct tegra_soctherm *tegra = platform_get_drvdata(pdev);
++	unsigned int i;
++
++	for (i = 0; i < ARRAY_SIZE(tegra->thermctl_tzs); ++i) {
++		thermal_zone_of_sensor_unregister(&pdev->dev,
++						  tegra->thermctl_tzs[i]);
++	}
++
++	clk_disable_unprepare(tegra->clock_tsensor);
++	clk_disable_unprepare(tegra->clock_soctherm);
++
++	return 0;
++}
++
++static struct platform_driver tegra_soctherm_driver = {
++	.probe = tegra_soctherm_probe,
++	.remove = tegra_soctherm_remove,
++	.driver = {
++		.name = "tegra-soctherm",
++		.of_match_table = tegra_soctherm_of_match,
++	},
++};
++module_platform_driver(tegra_soctherm_driver);
++
++MODULE_AUTHOR("Mikko Perttunen <mperttunen@nvidia.com>");
++MODULE_DESCRIPTION("NVIDIA Tegra SOCTHERM thermal management driver");
++MODULE_LICENSE("GPL v2");
+diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
+index 488e9bf..249b612 100644
+--- a/drivers/thermal/thermal_core.c
++++ b/drivers/thermal/thermal_core.c
+@@ -75,6 +75,58 @@ static struct thermal_governor *__find_governor(const char *name)
+ 	return NULL;
+ }
+ 
++/**
++ * bind_previous_governor() - bind the previous governor of the thermal zone
++ * @tz:		a valid pointer to a struct thermal_zone_device
++ * @failed_gov_name:	the name of the governor that failed to register
++ *
++ * Register the previous governor of the thermal zone after a new
++ * governor has failed to be bound.
++ */
++static void bind_previous_governor(struct thermal_zone_device *tz,
++				   const char *failed_gov_name)
++{
++	if (tz->governor && tz->governor->bind_to_tz) {
++		if (tz->governor->bind_to_tz(tz)) {
++			dev_err(&tz->device,
++				"governor %s failed to bind and the previous one (%s) failed to bind again, thermal zone %s has no governor\n",
++				failed_gov_name, tz->governor->name, tz->type);
++			tz->governor = NULL;
++		}
++	}
++}
++
++/**
++ * thermal_set_governor() - Switch to another governor
++ * @tz:		a valid pointer to a struct thermal_zone_device
++ * @new_gov:	pointer to the new governor
++ *
++ * Change the governor of thermal zone @tz.
++ *
++ * Return: 0 on success, an error if the new governor's bind_to_tz() failed.
++ */
++static int thermal_set_governor(struct thermal_zone_device *tz,
++				struct thermal_governor *new_gov)
++{
++	int ret = 0;
++
++	if (tz->governor && tz->governor->unbind_from_tz)
++		tz->governor->unbind_from_tz(tz);
++
++	if (new_gov && new_gov->bind_to_tz) {
++		ret = new_gov->bind_to_tz(tz);
++		if (ret) {
++			bind_previous_governor(tz, new_gov->name);
++
++			return ret;
++		}
++	}
++
++	tz->governor = new_gov;
++
++	return ret;
++}
++
+ int thermal_register_governor(struct thermal_governor *governor)
+ {
+ 	int err;
+@@ -107,8 +159,15 @@ int thermal_register_governor(struct thermal_governor *governor)
+ 
+ 		name = pos->tzp->governor_name;
+ 
+-		if (!strncasecmp(name, governor->name, THERMAL_NAME_LENGTH))
+-			pos->governor = governor;
++		if (!strncasecmp(name, governor->name, THERMAL_NAME_LENGTH)) {
++			int ret;
++
++			ret = thermal_set_governor(pos, governor);
++			if (ret)
++				dev_err(&pos->device,
++					"Failed to set governor %s for thermal zone %s: %d\n",
++					governor->name, pos->type, ret);
++		}
+ 	}
+ 
+ 	mutex_unlock(&thermal_list_lock);
+@@ -134,7 +193,7 @@ void thermal_unregister_governor(struct thermal_governor *governor)
+ 	list_for_each_entry(pos, &thermal_tz_list, node) {
+ 		if (!strncasecmp(pos->governor->name, governor->name,
+ 						THERMAL_NAME_LENGTH))
+-			pos->governor = NULL;
++			thermal_set_governor(pos, NULL);
+ 	}
+ 
+ 	mutex_unlock(&thermal_list_lock);
+@@ -218,7 +277,8 @@ static void print_bind_err_msg(struct thermal_zone_device *tz,
+ 
+ static void __bind(struct thermal_zone_device *tz, int mask,
+ 			struct thermal_cooling_device *cdev,
+-			unsigned long *limits)
++			unsigned long *limits,
++			unsigned int weight)
+ {
+ 	int i, ret;
+ 
+@@ -233,7 +293,8 @@ static void __bind(struct thermal_zone_device *tz, int mask,
+ 				upper = limits[i * 2 + 1];
+ 			}
+ 			ret = thermal_zone_bind_cooling_device(tz, i, cdev,
+-							       upper, lower);
++							       upper, lower,
++							       weight);
+ 			if (ret)
+ 				print_bind_err_msg(tz, cdev, ret);
+ 		}
+@@ -280,7 +341,8 @@ static void bind_cdev(struct thermal_cooling_device *cdev)
+ 				continue;
+ 			tzp->tbp[i].cdev = cdev;
+ 			__bind(pos, tzp->tbp[i].trip_mask, cdev,
+-			       tzp->tbp[i].binding_limits);
++			       tzp->tbp[i].binding_limits,
++			       tzp->tbp[i].weight);
+ 		}
+ 	}
+ 
+@@ -319,7 +381,8 @@ static void bind_tz(struct thermal_zone_device *tz)
+ 				continue;
+ 			tzp->tbp[i].cdev = pos;
+ 			__bind(tz, tzp->tbp[i].trip_mask, pos,
+-			       tzp->tbp[i].binding_limits);
++			       tzp->tbp[i].binding_limits,
++			       tzp->tbp[i].weight);
+ 		}
+ 	}
+ exit:
+@@ -368,7 +431,7 @@ static void handle_critical_trips(struct thermal_zone_device *tz,
+ 	tz->ops->get_trip_temp(tz, trip, &trip_temp);
+ 
+ 	/* If we have not crossed the trip_temp, we do not care. */
+-	if (tz->temperature < trip_temp)
++	if (trip_temp <= 0 || tz->temperature < trip_temp)
+ 		return;
+ 
+ 	trace_thermal_zone_trip(tz, trip, trip_type);
+@@ -711,7 +774,8 @@ passive_store(struct device *dev, struct device_attribute *attr,
+ 				thermal_zone_bind_cooling_device(tz,
+ 						THERMAL_TRIPS_NONE, cdev,
+ 						THERMAL_NO_LIMIT,
+-						THERMAL_NO_LIMIT);
++						THERMAL_NO_LIMIT,
++						THERMAL_WEIGHT_DEFAULT);
+ 		}
+ 		mutex_unlock(&thermal_list_lock);
+ 		if (!tz->passive_delay)
+@@ -757,15 +821,18 @@ policy_store(struct device *dev, struct device_attribute *attr,
+ 	snprintf(name, sizeof(name), "%s", buf);
+ 
+ 	mutex_lock(&thermal_governor_lock);
++	mutex_lock(&tz->lock);
+ 
+ 	gov = __find_governor(strim(name));
+ 	if (!gov)
+ 		goto exit;
+ 
+-	tz->governor = gov;
+-	ret = count;
++	ret = thermal_set_governor(tz, gov);
++	if (!ret)
++		ret = count;
+ 
+ exit:
++	mutex_unlock(&tz->lock);
+ 	mutex_unlock(&thermal_governor_lock);
+ 	return ret;
+ }
+@@ -806,6 +873,158 @@ emul_temp_store(struct device *dev, struct device_attribute *attr,
+ static DEVICE_ATTR(emul_temp, S_IWUSR, NULL, emul_temp_store);
+ #endif/*CONFIG_THERMAL_EMULATION*/
+ 
++static ssize_t
++sustainable_power_show(struct device *dev, struct device_attribute *devattr,
++		       char *buf)
++{
++	struct thermal_zone_device *tz = to_thermal_zone(dev);
++
++	if (tz->tzp)
++		return sprintf(buf, "%u\n", tz->tzp->sustainable_power);
++	else
++		return -EIO;
++}
++
++static ssize_t
++sustainable_power_store(struct device *dev, struct device_attribute *devattr,
++			const char *buf, size_t count)
++{
++	struct thermal_zone_device *tz = to_thermal_zone(dev);
++	u32 sustainable_power;
++
++	if (!tz->tzp)
++		return -EIO;
++
++	if (kstrtou32(buf, 10, &sustainable_power))
++		return -EINVAL;
++
++	tz->tzp->sustainable_power = sustainable_power;
++
++	return count;
++}
++static DEVICE_ATTR(sustainable_power, S_IWUSR | S_IRUGO, sustainable_power_show,
++		sustainable_power_store);
++
++#define create_s32_tzp_attr(name)					\
++	static ssize_t							\
++	name##_show(struct device *dev, struct device_attribute *devattr, \
++		char *buf)						\
++	{								\
++	struct thermal_zone_device *tz = to_thermal_zone(dev);		\
++									\
++	if (tz->tzp)							\
++		return sprintf(buf, "%u\n", tz->tzp->name);		\
++	else								\
++		return -EIO;						\
++	}								\
++									\
++	static ssize_t							\
++	name##_store(struct device *dev, struct device_attribute *devattr, \
++		const char *buf, size_t count)				\
++	{								\
++		struct thermal_zone_device *tz = to_thermal_zone(dev);	\
++		s32 value;						\
++									\
++		if (!tz->tzp)						\
++			return -EIO;					\
++									\
++		if (kstrtos32(buf, 10, &value))				\
++			return -EINVAL;					\
++									\
++		tz->tzp->name = value;					\
++									\
++		return count;						\
++	}								\
++	static DEVICE_ATTR(name, S_IWUSR | S_IRUGO, name##_show, name##_store)
++
++create_s32_tzp_attr(k_po);
++create_s32_tzp_attr(k_pu);
++create_s32_tzp_attr(k_i);
++create_s32_tzp_attr(k_d);
++create_s32_tzp_attr(integral_cutoff);
++create_s32_tzp_attr(slope);
++create_s32_tzp_attr(offset);
++#undef create_s32_tzp_attr
++
++static struct device_attribute *dev_tzp_attrs[] = {
++	&dev_attr_sustainable_power,
++	&dev_attr_k_po,
++	&dev_attr_k_pu,
++	&dev_attr_k_i,
++	&dev_attr_k_d,
++	&dev_attr_integral_cutoff,
++	&dev_attr_slope,
++	&dev_attr_offset,
++};
++
++static int create_tzp_attrs(struct device *dev)
++{
++	int i;
++
++	for (i = 0; i < ARRAY_SIZE(dev_tzp_attrs); i++) {
++		int ret;
++		struct device_attribute *dev_attr = dev_tzp_attrs[i];
++
++		ret = device_create_file(dev, dev_attr);
++		if (ret)
++			return ret;
++	}
++
++	return 0;
++}
++
++/**
++ * power_actor_get_max_power() - get the maximum power that a cdev can consume
++ * @cdev:	pointer to &thermal_cooling_device
++ * @tz:		a valid thermal zone device pointer
++ * @max_power:	pointer in which to store the maximum power
++ *
++ * Calculate the maximum power consumption in milliwats that the
++ * cooling device can currently consume and store it in @max_power.
++ *
++ * Return: 0 on success, -EINVAL if @cdev doesn't support the
++ * power_actor API or -E* on other error.
++ */
++int power_actor_get_max_power(struct thermal_cooling_device *cdev,
++			      struct thermal_zone_device *tz, u32 *max_power)
++{
++	if (!cdev_is_power_actor(cdev))
++		return -EINVAL;
++
++	return cdev->ops->state2power(cdev, tz, 0, max_power);
++}
++
++/**
++ * power_actor_set_power() - limit the maximum power that a cooling device can consume
++ * @cdev:	pointer to &thermal_cooling_device
++ * @instance:	thermal instance to update
++ * @power:	the power in milliwatts
++ *
++ * Set the cooling device to consume at most @power milliwatts.
++ *
++ * Return: 0 on success, -EINVAL if the cooling device does not
++ * implement the power actor API or -E* for other failures.
++ */
++int power_actor_set_power(struct thermal_cooling_device *cdev,
++			  struct thermal_instance *instance, u32 power)
++{
++	unsigned long state;
++	int ret;
++
++	if (!cdev_is_power_actor(cdev))
++		return -EINVAL;
++
++	ret = cdev->ops->power2state(cdev, instance->tz, power, &state);
++	if (ret)
++		return ret;
++
++	instance->target = state;
++	cdev->updated = false;
++	thermal_cdev_update(cdev);
++
++	return 0;
++}
++
+ static DEVICE_ATTR(type, 0444, type_show, NULL);
+ static DEVICE_ATTR(temp, 0444, temp_show, NULL);
+ static DEVICE_ATTR(mode, 0644, mode_show, mode_store);
+@@ -897,6 +1116,50 @@ thermal_cooling_device_trip_point_show(struct device *dev,
+ 		return sprintf(buf, "%d\n", instance->trip);
+ }
+ 
++static struct attribute *cooling_device_attrs[] = {
++	&dev_attr_cdev_type.attr,
++	&dev_attr_max_state.attr,
++	&dev_attr_cur_state.attr,
++	NULL,
++};
++
++static const struct attribute_group cooling_device_attr_group = {
++	.attrs = cooling_device_attrs,
++};
++
++static const struct attribute_group *cooling_device_attr_groups[] = {
++	&cooling_device_attr_group,
++	NULL,
++};
++
++static ssize_t
++thermal_cooling_device_weight_show(struct device *dev,
++				   struct device_attribute *attr, char *buf)
++{
++	struct thermal_instance *instance;
++
++	instance = container_of(attr, struct thermal_instance, weight_attr);
++
++	return sprintf(buf, "%d\n", instance->weight);
++}
++
++static ssize_t
++thermal_cooling_device_weight_store(struct device *dev,
++				    struct device_attribute *attr,
++				    const char *buf, size_t count)
++{
++	struct thermal_instance *instance;
++	int ret, weight;
++
++	ret = kstrtoint(buf, 0, &weight);
++	if (ret)
++		return ret;
++
++	instance = container_of(attr, struct thermal_instance, weight_attr);
++	instance->weight = weight;
++
++	return count;
++}
+ /* Device management */
+ 
+ /**
+@@ -911,6 +1174,9 @@ thermal_cooling_device_trip_point_show(struct device *dev,
+  * @lower:	the Minimum cooling state can be used for this trip point.
+  *		THERMAL_NO_LIMIT means no lower limit,
+  *		and the cooling device can be in cooling state 0.
++ * @weight:	The weight of the cooling device to be bound to the
++ *		thermal zone. Use THERMAL_WEIGHT_DEFAULT for the
++ *		default value
+  *
+  * This interface function bind a thermal cooling device to the certain trip
+  * point of a thermal zone device.
+@@ -921,7 +1187,8 @@ thermal_cooling_device_trip_point_show(struct device *dev,
+ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
+ 				     int trip,
+ 				     struct thermal_cooling_device *cdev,
+-				     unsigned long upper, unsigned long lower)
++				     unsigned long upper, unsigned long lower,
++				     unsigned int weight)
+ {
+ 	struct thermal_instance *dev;
+ 	struct thermal_instance *pos;
+@@ -964,6 +1231,7 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
+ 	dev->upper = upper;
+ 	dev->lower = lower;
+ 	dev->target = THERMAL_NO_TARGET;
++	dev->weight = weight;
+ 
+ 	result = get_idr(&tz->idr, &tz->lock, &dev->id);
+ 	if (result)
+@@ -984,6 +1252,16 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
+ 	if (result)
+ 		goto remove_symbol_link;
+ 
++	sprintf(dev->weight_attr_name, "cdev%d_weight", dev->id);
++	sysfs_attr_init(&dev->weight_attr.attr);
++	dev->weight_attr.attr.name = dev->weight_attr_name;
++	dev->weight_attr.attr.mode = S_IWUSR | S_IRUGO;
++	dev->weight_attr.show = thermal_cooling_device_weight_show;
++	dev->weight_attr.store = thermal_cooling_device_weight_store;
++	result = device_create_file(&tz->device, &dev->weight_attr);
++	if (result)
++		goto remove_trip_file;
++
+ 	mutex_lock(&tz->lock);
+ 	mutex_lock(&cdev->lock);
+ 	list_for_each_entry(pos, &tz->thermal_instances, tz_node)
+@@ -1001,6 +1279,8 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
+ 	if (!result)
+ 		return 0;
+ 
++	device_remove_file(&tz->device, &dev->weight_attr);
++remove_trip_file:
+ 	device_remove_file(&tz->device, &dev->attr);
+ remove_symbol_link:
+ 	sysfs_remove_link(&tz->device.kobj, dev->name);
+@@ -1126,6 +1406,7 @@ __thermal_cooling_device_register(struct device_node *np,
+ 	cdev->ops = ops;
+ 	cdev->updated = false;
+ 	cdev->device.class = &thermal_class;
++	cdev->device.groups = cooling_device_attr_groups;
+ 	cdev->devdata = devdata;
+ 	dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
+ 	result = device_register(&cdev->device);
+@@ -1135,21 +1416,6 @@ __thermal_cooling_device_register(struct device_node *np,
+ 		return ERR_PTR(result);
+ 	}
+ 
+-	/* sys I/F */
+-	if (type) {
+-		result = device_create_file(&cdev->device, &dev_attr_cdev_type);
+-		if (result)
+-			goto unregister;
+-	}
+-
+-	result = device_create_file(&cdev->device, &dev_attr_max_state);
+-	if (result)
+-		goto unregister;
+-
+-	result = device_create_file(&cdev->device, &dev_attr_cur_state);
+-	if (result)
+-		goto unregister;
+-
+ 	/* Add 'this' new cdev to the global cdev list */
+ 	mutex_lock(&thermal_list_lock);
+ 	list_add(&cdev->node, &thermal_cdev_list);
+@@ -1159,11 +1425,6 @@ __thermal_cooling_device_register(struct device_node *np,
+ 	bind_cdev(cdev);
+ 
+ 	return cdev;
+-
+-unregister:
+-	release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
+-	device_unregister(&cdev->device);
+-	return ERR_PTR(result);
+ }
+ 
+ /**
+@@ -1374,7 +1635,8 @@ static int create_trip_attrs(struct thermal_zone_device *tz, int mask)
+ 						tz->trip_temp_attrs[indx].name;
+ 		tz->trip_temp_attrs[indx].attr.attr.mode = S_IRUGO;
+ 		tz->trip_temp_attrs[indx].attr.show = trip_point_temp_show;
+-		if (mask & (1 << indx)) {
++		if (IS_ENABLED(CONFIG_THERMAL_WRITABLE_TRIPS) &&
++		    mask & (1 << indx)) {
+ 			tz->trip_temp_attrs[indx].attr.attr.mode |= S_IWUSR;
+ 			tz->trip_temp_attrs[indx].attr.store =
+ 							trip_point_temp_store;
+@@ -1451,7 +1713,7 @@ static void remove_trip_attrs(struct thermal_zone_device *tz)
+ struct thermal_zone_device *thermal_zone_device_register(const char *type,
+ 	int trips, int mask, void *devdata,
+ 	struct thermal_zone_device_ops *ops,
+-	const struct thermal_zone_params *tzp,
++	struct thermal_zone_params *tzp,
+ 	int passive_delay, int polling_delay)
+ {
+ 	struct thermal_zone_device *tz;
+@@ -1459,6 +1721,7 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type,
+ 	int result;
+ 	int count;
+ 	int passive = 0;
++	struct thermal_governor *governor;
+ 
+ 	if (type && strlen(type) >= THERMAL_NAME_LENGTH)
+ 		return ERR_PTR(-EINVAL);
+@@ -1545,13 +1808,24 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type,
+ 	if (result)
+ 		goto unregister;
+ 
++	/* Add thermal zone params */
++	result = create_tzp_attrs(&tz->device);
++	if (result)
++		goto unregister;
++
+ 	/* Update 'this' zone's governor information */
+ 	mutex_lock(&thermal_governor_lock);
+ 
+ 	if (tz->tzp)
+-		tz->governor = __find_governor(tz->tzp->governor_name);
++		governor = __find_governor(tz->tzp->governor_name);
+ 	else
+-		tz->governor = def_governor;
++		governor = def_governor;
++
++	result = thermal_set_governor(tz, governor);
++	if (result) {
++		mutex_unlock(&thermal_governor_lock);
++		goto unregister;
++	}
+ 
+ 	mutex_unlock(&thermal_governor_lock);
+ 
+@@ -1640,7 +1914,7 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)
+ 		device_remove_file(&tz->device, &dev_attr_mode);
+ 	device_remove_file(&tz->device, &dev_attr_policy);
+ 	remove_trip_attrs(tz);
+-	tz->governor = NULL;
++	thermal_set_governor(tz, NULL);
+ 
+ 	thermal_remove_hwmon_sysfs(tz);
+ 	release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
+@@ -1800,7 +2074,11 @@ static int __init thermal_register_governors(void)
+ 	if (result)
+ 		return result;
+ 
+-	return thermal_gov_user_space_register();
++	result = thermal_gov_user_space_register();
++	if (result)
++		return result;
++
++	return thermal_gov_power_allocator_register();
+ }
+ 
+ static void thermal_unregister_governors(void)
+@@ -1809,6 +2087,7 @@ static void thermal_unregister_governors(void)
+ 	thermal_gov_fair_share_unregister();
+ 	thermal_gov_bang_bang_unregister();
+ 	thermal_gov_user_space_unregister();
++	thermal_gov_power_allocator_unregister();
+ }
+ 
+ static int __init thermal_init(void)
+diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h
+index d15d243..8a66244 100644
+--- a/drivers/thermal/thermal_core.h
++++ b/drivers/thermal/thermal_core.h
+@@ -46,8 +46,11 @@ struct thermal_instance {
+ 	unsigned long target;	/* expected cooling state */
+ 	char attr_name[THERMAL_NAME_LENGTH];
+ 	struct device_attribute attr;
++	char weight_attr_name[THERMAL_NAME_LENGTH];
++	struct device_attribute weight_attr;
+ 	struct list_head tz_node; /* node in tz->thermal_instances */
+ 	struct list_head cdev_node; /* node in cdev->thermal_instances */
++	unsigned int weight; /* The weight of the cooling device */
+ };
+ 
+ int thermal_register_governor(struct thermal_governor *);
+@@ -85,13 +88,39 @@ static inline int thermal_gov_user_space_register(void) { return 0; }
+ static inline void thermal_gov_user_space_unregister(void) {}
+ #endif /* CONFIG_THERMAL_GOV_USER_SPACE */
+ 
++#ifdef CONFIG_THERMAL_GOV_POWER_ALLOCATOR
++int thermal_gov_power_allocator_register(void);
++void thermal_gov_power_allocator_unregister(void);
++#else
++static inline int thermal_gov_power_allocator_register(void) { return 0; }
++static inline void thermal_gov_power_allocator_unregister(void) {}
++#endif /* CONFIG_THERMAL_GOV_POWER_ALLOCATOR */
++
+ /* device tree support */
+ #ifdef CONFIG_THERMAL_OF
+ int of_parse_thermal_zones(void);
+ void of_thermal_destroy_zones(void);
++int of_thermal_get_ntrips(struct thermal_zone_device *);
++bool of_thermal_is_trip_valid(struct thermal_zone_device *, int);
++const struct thermal_trip *
++of_thermal_get_trip_points(struct thermal_zone_device *);
+ #else
+ static inline int of_parse_thermal_zones(void) { return 0; }
+ static inline void of_thermal_destroy_zones(void) { }
++static inline int of_thermal_get_ntrips(struct thermal_zone_device *tz)
++{
++	return 0;
++}
++static inline bool of_thermal_is_trip_valid(struct thermal_zone_device *tz,
++					    int trip)
++{
++	return 0;
++}
++static inline const struct thermal_trip *
++of_thermal_get_trip_points(struct thermal_zone_device *tz)
++{
++	return NULL;
++}
+ #endif
+ 
+ #endif /* __THERMAL_CORE_H__ */
+diff --git a/drivers/thermal/ti-soc-thermal/ti-thermal-common.c b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c
+index 9eec26d..68f53fc 100644
+--- a/drivers/thermal/ti-soc-thermal/ti-thermal-common.c
++++ b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c
+@@ -28,7 +28,6 @@
+ #include <linux/kernel.h>
+ #include <linux/workqueue.h>
+ #include <linux/thermal.h>
+-#include <linux/cpufreq.h>
+ #include <linux/cpumask.h>
+ #include <linux/cpu_cooling.h>
+ #include <linux/of.h>
+@@ -147,7 +146,8 @@ static int ti_thermal_bind(struct thermal_zone_device *thermal,
+ 	return thermal_zone_bind_cooling_device(thermal, 0, cdev,
+ 	/* bind with min and max states defined by cpu_cooling */
+ 						THERMAL_NO_LIMIT,
+-						THERMAL_NO_LIMIT);
++						THERMAL_NO_LIMIT,
++						THERMAL_WEIGHT_DEFAULT);
+ }
+ 
+ /* Unbind callback functions for thermal zone */
+@@ -286,6 +286,11 @@ static int ti_thermal_get_crit_temp(struct thermal_zone_device *thermal,
+ 	return ti_thermal_get_trip_temp(thermal, OMAP_TRIP_NUMBER - 1, temp);
+ }
+ 
++static const struct thermal_zone_of_device_ops ti_of_thermal_ops = {
++	.get_temp = __ti_thermal_get_temp,
++	.get_trend = __ti_thermal_get_trend,
++};
++
+ static struct thermal_zone_device_ops ti_thermal_ops = {
+ 	.get_temp = ti_thermal_get_temp,
+ 	.get_trend = ti_thermal_get_trend,
+@@ -333,8 +338,7 @@ int ti_thermal_expose_sensor(struct ti_bandgap *bgp, int id,
+ 
+ 	/* in case this is specified by DT */
+ 	data->ti_thermal = thermal_zone_of_sensor_register(bgp->dev, id,
+-					data, __ti_thermal_get_temp,
+-					__ti_thermal_get_trend);
++					data, &ti_of_thermal_ops);
+ 	if (IS_ERR(data->ti_thermal)) {
+ 		/* Create thermal zone */
+ 		data->ti_thermal = thermal_zone_device_register(domain,
+@@ -403,11 +407,6 @@ int ti_thermal_register_cpu_cooling(struct ti_bandgap *bgp, int id)
+ 	if (!data)
+ 		return -EINVAL;
+ 
+-	if (!cpufreq_get_current_driver()) {
+-		dev_dbg(bgp->dev, "no cpufreq driver yet\n");
+-		return -EPROBE_DEFER;
+-	}
+-
+ 	/* Register cooling device */
+ 	data->cool_dev = cpufreq_cooling_register(cpu_present_mask);
+ 	if (IS_ERR(data->cool_dev)) {
+diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
+index a28dee9..ec40c59 100644
+--- a/drivers/tty/serial/serial_core.c
++++ b/drivers/tty/serial/serial_core.c
+@@ -95,6 +95,9 @@ static void __uart_start(struct tty_struct *tty)
+ 	struct uart_state *state = tty->driver_data;
+ 	struct uart_port *port = state->uart_port;
+ 
++	if (port->ops->wake_peer)
++		port->ops->wake_peer(port);
++
+ 	if (!uart_tx_stopped(port))
+ 		port->ops->start_tx(port);
+ }
+diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
+index 0a0a630..dacf8d5 100644
+--- a/drivers/tty/tty_io.c
++++ b/drivers/tty/tty_io.c
+@@ -2594,6 +2594,28 @@ static int tiocsetd(struct tty_struct *tty, int __user *p)
+ }
+ 
+ /**
++ *	tiocgetd	-	get line discipline
++ *	@tty: tty device
++ *	@p: pointer to user data
++ *
++ *	Retrieves the line discipline id directly from the ldisc.
++ *
++ *	Locking: waits for ldisc reference (in case the line discipline
++ *		is changing or the tty is being hungup)
++ */
++
++static int tiocgetd(struct tty_struct *tty, int __user *p)
++{
++	struct tty_ldisc *ld;
++	int ret;
++
++	ld = tty_ldisc_ref_wait(tty);
++	ret = put_user(ld->ops->num, p);
++	tty_ldisc_deref(ld);
++	return ret;
++}
++
++/**
+  *	send_break	-	performed time break
+  *	@tty: device to break on
+  *	@duration: timeout in mS
+@@ -2807,7 +2829,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+ 	case TIOCGSID:
+ 		return tiocgsid(tty, real_tty, p);
+ 	case TIOCGETD:
+-		return put_user(tty->ldisc->ops->num, (int __user *)p);
++		return tiocgetd(tty, p);
+ 	case TIOCSETD:
+ 		return tiocsetd(tty, p);
+ 	case TIOCVHANGUP:
+diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c
+index 2d822aa..a72e359 100644
+--- a/drivers/tty/tty_ldisc.c
++++ b/drivers/tty/tty_ldisc.c
+@@ -414,6 +414,10 @@ EXPORT_SYMBOL_GPL(tty_ldisc_flush);
+  *	they are not on hot paths so a little discipline won't do
+  *	any harm.
+  *
++ *  The line discipline-related tty_struct fields are reset to
++ *  prevent the ldisc driver from re-using stale information for
++ *  the new ldisc instance.
++ *
+  *	Locking: takes termios_rwsem
+  */
+ 
+@@ -422,6 +426,9 @@ static void tty_set_termios_ldisc(struct tty_struct *tty, int num)
+ 	down_write(&tty->termios_rwsem);
+ 	tty->termios.c_line = num;
+ 	up_write(&tty->termios_rwsem);
++
++	tty->disc_data = NULL;
++	tty->receive_room = 0;
+ }
+ 
+ /**
+diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
+index b2a540b..062a7c5 100644
+--- a/drivers/usb/core/config.c
++++ b/drivers/usb/core/config.c
+@@ -520,15 +520,23 @@ static int usb_parse_configuration(struct usb_device *dev, int cfgidx,
+ 
+ 		} else if (header->bDescriptorType ==
+ 				USB_DT_INTERFACE_ASSOCIATION) {
++			struct usb_interface_assoc_descriptor *d;
++
++			d = (struct usb_interface_assoc_descriptor *)header;
++			if (d->bLength < USB_DT_INTERFACE_ASSOCIATION_SIZE) {
++				dev_warn(ddev,
++						"config %d has an invalid interface association descriptor of length %d, skipping\n",
++						cfgno, d->bLength);
++				continue;
++			}
++
+ 			if (iad_num == USB_MAXIADS) {
+ 				dev_warn(ddev, "found more Interface "
+ 					       "Association Descriptors "
+ 					       "than allocated for in "
+ 					       "configuration %d\n", cfgno);
+ 			} else {
+-				config->intf_assoc[iad_num] =
+-					(struct usb_interface_assoc_descriptor
+-					*)header;
++				config->intf_assoc[iad_num] = d;
+ 				iad_num++;
+ 			}
+ 
+@@ -633,18 +641,21 @@ void usb_destroy_configuration(struct usb_device *dev)
+ 		return;
+ 
+ 	if (dev->rawdescriptors) {
+-		for (i = 0; i < dev->descriptor.bNumConfigurations; i++)
++		for (i = 0; i < dev->descriptor.bNumConfigurations &&
++				i < USB_MAXCONFIG; i++)
+ 			kfree(dev->rawdescriptors[i]);
+ 
+ 		kfree(dev->rawdescriptors);
+ 		dev->rawdescriptors = NULL;
+ 	}
+ 
+-	for (c = 0; c < dev->descriptor.bNumConfigurations; c++) {
++	for (c = 0; c < dev->descriptor.bNumConfigurations &&
++			c < USB_MAXCONFIG; c++) {
+ 		struct usb_host_config *cf = &dev->config[c];
+ 
+ 		kfree(cf->string);
+-		for (i = 0; i < cf->desc.bNumInterfaces; i++) {
++		for (i = 0; i < cf->desc.bNumInterfaces &&
++				i < USB_MAXINTERFACES; i++) {
+ 			if (cf->intf_cache[i])
+ 				kref_put(&cf->intf_cache[i]->ref,
+ 					  usb_release_interface_cache);
+@@ -829,10 +840,12 @@ int usb_get_bos_descriptor(struct usb_device *dev)
+ 	for (i = 0; i < num; i++) {
+ 		buffer += length;
+ 		cap = (struct usb_dev_cap_header *)buffer;
+-		length = cap->bLength;
+ 
+-		if (total_len < length)
++		if (total_len < sizeof(*cap) || total_len < cap->bLength) {
++			dev->bos->desc->bNumDeviceCaps = i;
+ 			break;
++		}
++		length = cap->bLength;
+ 		total_len -= length;
+ 
+ 		if (cap->bDescriptorType != USB_DT_DEVICE_CAPABILITY) {
+diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
+index a85eadf..dfcb5f8 100644
+--- a/drivers/usb/core/devio.c
++++ b/drivers/usb/core/devio.c
+@@ -1202,10 +1202,11 @@ static int proc_getdriver(struct usb_dev_state *ps, void __user *arg)
+ 
+ static int proc_connectinfo(struct usb_dev_state *ps, void __user *arg)
+ {
+-	struct usbdevfs_connectinfo ci = {
+-		.devnum = ps->dev->devnum,
+-		.slow = ps->dev->speed == USB_SPEED_LOW
+-	};
++	struct usbdevfs_connectinfo ci;
++
++	memset(&ci, 0, sizeof(ci));
++	ci.devnum = ps->dev->devnum;
++	ci.slow = ps->dev->speed == USB_SPEED_LOW;
+ 
+ 	if (copy_to_user(arg, &ci, sizeof(ci)))
+ 		return -EFAULT;
+diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
+index 2222899..68c1112 100644
+--- a/drivers/usb/core/hub.c
++++ b/drivers/usb/core/hub.c
+@@ -36,6 +36,9 @@
+ #define USB_VENDOR_GENESYS_LOGIC		0x05e3
+ #define HUB_QUIRK_CHECK_PORT_AUTOSUSPEND	0x01
+ 
++int otg_usbdev_stat;
++EXPORT_SYMBOL(otg_usbdev_stat);
++
+ /* Protect struct usb_device->state and ->children members
+  * Note: Both are also protected by ->dev.sem, except that ->state can
+  * change to USB_STATE_NOTATTACHED even when the semaphore isn't held. */
+@@ -1030,10 +1033,20 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
+ 	unsigned delay;
+ 
+ 	/* Continue a partial initialization */
+-	if (type == HUB_INIT2)
+-		goto init2;
+-	if (type == HUB_INIT3)
++	if (type == HUB_INIT2 || type == HUB_INIT3) {
++		device_lock(hub->intfdev);
++
++		/* Was the hub disconnected while we were waiting? */
++		if (hub->disconnected) {
++			device_unlock(hub->intfdev);
++			kref_put(&hub->kref, hub_release);
++			return;
++		}
++		if (type == HUB_INIT2)
++			goto init2;
+ 		goto init3;
++	}
++	kref_get(&hub->kref);
+ 
+ 	/* The superspeed hub except for root hub has to use Hub Depth
+ 	 * value as an offset into the route string to locate the bits
+@@ -1231,6 +1244,7 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
+ 			queue_delayed_work(system_power_efficient_wq,
+ 					&hub->init_work,
+ 					msecs_to_jiffies(delay));
++			device_unlock(hub->intfdev);
+ 			return;		/* Continues at init3: below */
+ 		} else {
+ 			msleep(delay);
+@@ -1252,6 +1266,10 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
+ 	/* Allow autosuspend if it was suppressed */
+ 	if (type <= HUB_INIT3)
+ 		usb_autopm_put_interface_async(to_usb_interface(hub->intfdev));
++
++	if (type == HUB_INIT2 || type == HUB_INIT3)
++		device_unlock(hub->intfdev);
++	kref_put(&hub->kref, hub_release);
+ }
+ 
+ /* Implement the continuations for the delays above */
+@@ -4953,9 +4971,19 @@ static void port_event(struct usb_hub *hub, int port1)
+ 		dev_dbg(&port_dev->dev, "do warm reset\n");
+ 		if (!udev || !(portstatus & USB_PORT_STAT_CONNECTION)
+ 				|| udev->state == USB_STATE_NOTATTACHED) {
+-			if (hub_port_reset(hub, port1, NULL,
+-					HUB_BH_RESET_TIME, true) < 0)
++			int ret;
++
++			ret = hub_port_reset(hub, port1, NULL,
++					HUB_BH_RESET_TIME, true);
++			if (ret < 0)
+ 				hub_port_disable(hub, port1, 1);
++			ret = hub_port_status(hub, port1,
++					&portstatus, &portchange);
++			if (ret < 0)
++				return;
++		if ((portstatus & USB_PORT_STAT_CONNECTION) && !udev &&
++				portstatus & USB_PORT_STAT_ENABLE)
++			connect_change = 1;
+ 		} else
+ 			reset_device = 1;
+ 	}
+@@ -4984,6 +5012,10 @@ static void port_event(struct usb_hub *hub, int port1)
+ 
+ 	if (connect_change)
+ 		hub_port_connect_change(hub, port1, portstatus, portchange);
++
++	if (!(portstatus & USB_PORT_STAT_CONNECTION)
++			&& (hdev->parent == NULL))
++		otg_usbdev_stat = 0;
+ }
+ 
+ static void hub_event(struct work_struct *work)
+@@ -5060,6 +5092,7 @@ static void hub_event(struct work_struct *work)
+ 			 * (powered-off), we leave it in that state, run
+ 			 * an abbreviated port_event(), and move on.
+ 			 */
++			otg_usbdev_stat = 1;
+ 			pm_runtime_get_noresume(&port_dev->dev);
+ 			pm_runtime_barrier(&port_dev->dev);
+ 			usb_lock_port(port_dev);
+diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
+index c4880fc..23814ec 100644
+--- a/drivers/usb/gadget/Kconfig
++++ b/drivers/usb/gadget/Kconfig
+@@ -183,13 +183,28 @@ config USB_F_FS
+ 
+ config USB_F_UAC1
+ 	tristate
+-
++ 
+ config USB_F_UAC2
+ 	tristate
+ 
+ config USB_F_UVC
+ 	tristate
+ 
++config USB_F_MTP
++	tristate
++
++config USB_F_PTP
++        tristate
++
++config USB_F_AUDIO_SRC
++	tristate
++
++config USB_F_ACC
++	tristate
++
++config USB_F_MIDI
++	tristate
++
+ choice
+ 	tristate "USB Gadget Drivers"
+ 	default USB_ETH
+@@ -362,6 +377,57 @@ config USB_CONFIGFS_F_FS
+ 	  implemented in kernel space (for instance Ethernet, serial or
+ 	  mass storage) and other are implemented in user space.
+ 
++config USB_CONFIGFS_F_MTP
++        boolean "MTP gadget"
++        depends on USB_CONFIGFS
++        select USB_F_MTP
++        help
++          USB gadget MTP support
++
++config USB_CONFIGFS_F_PTP
++        boolean "PTP gadget"
++        depends on USB_CONFIGFS && USB_CONFIGFS_F_MTP
++        select USB_F_PTP
++        help
++          USB gadget PTP support
++
++config USB_CONFIGFS_F_ACC
++	boolean "Accessory gadget"
++	depends on USB_CONFIGFS
++	select USB_F_ACC
++	help
++	  USB gadget Accessory support
++
++config USB_CONFIGFS_F_AUDIO_SRC
++	boolean "Audio Source gadget"
++	depends on USB_CONFIGFS && USB_CONFIGFS_F_ACC
++	depends on SND_PCM
++	select USB_F_AUDIO_SRC
++	help
++	  USB gadget Audio Source support
++
++config USB_CONFIGFS_UEVENT
++	boolean "Uevent notification of Gadget state"
++	depends on USB_CONFIGFS
++	help
++	  Enable uevent notifications to userspace when the gadget
++	  state changes. The gadget can be in any of the following
++	  three states: "CONNECTED/DISCONNECTED/CONFIGURED"
++
++config USB_CONFIGFS_F_MIDI
++	boolean "MIDI function"
++	depends on USB_CONFIGFS
++	depends on SND
++	select USB_LIBCOMPOSITE
++	select SND_RAWMIDI
++	select USB_F_MIDI
++	help
++	  The MIDI Function acts as a USB Audio device, with one MIDI
++	  input and one MIDI output. These MIDI jacks appear as
++	  a sound "card" in the ALSA sound system. Other MIDI
++	  connections can then be made on the gadget system, using
++	  ALSA's aconnect utility etc.
++
+ source "drivers/usb/gadget/legacy/Kconfig"
+ 
+ endchoice
+diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
+index f6a51fd..e50ec80 100644
+--- a/drivers/usb/gadget/composite.c
++++ b/drivers/usb/gadget/composite.c
+@@ -17,11 +17,42 @@
+ #include <linux/module.h>
+ #include <linux/device.h>
+ #include <linux/utsname.h>
++#include <linux/delay.h>
++#ifdef CONFIG_USB3_DEVICE_GPIO_CTRL
++#include <linux/interrupt.h>
++#endif
+ 
+ #include <linux/usb/composite.h>
+ #include <asm/unaligned.h>
++#include <mach/io.h>
+ 
+ #include "u_os_desc.h"
++#ifdef CONFIG_USB3_DEVICE_GPIO_CTRL
++#define GPIO_IRQ_NUM		75
++#define GPIO1_0_IE		(1<<0)
++#define GPIO1_0_IC		(1<<0)
++#define GPIO1_IE		__io_address(0x12141410)
++#define GPIO1_0_DATA		__io_address(0x12141004)
++#define GPIO1_IC		__io_address(0x1214141c)
++static int uvc_flag;
++static const char gpio_driver_name[] = "usb_gpio_irq";
++#endif
++#if defined(CONFIG_ARCH_HI3519) || defined(CONFIG_ARCH_HI3519V101) \
++	|| defined(CONFIG_ARCH_HI3559) || defined(CONFIG_ARCH_HI3556) \
++	|| defined(CONFIG_ARCH_HI3516CV300) || defined(CONFIG_ARCH_HI3516AV200)
++#define USB2_BASE_REG		0x12030000
++#define DWC_OTG_EN		(1 << 31)
++#define USB2_PHY_DPPULL_DOWN	(0x3 << 26)
++#endif
++
++#ifdef CONFIG_ARCH_HI3516CV300
++#define USB2_OTG_BASE		0x5c
++#endif
++
++#if defined(CONFIG_ARCH_HI3519) || defined(CONFIG_ARCH_HI3519V101) \
++	|| defined(CONFIG_ARCH_HI3559) || defined(CONFIG_ARCH_HI3556) || defined(CONFIG_ARCH_HI3516AV200)
++#define USB2_OTG_BASE		0x78
++#endif
+ 
+ /**
+  * struct usb_os_string - represents OS String to be reported by a gadget
+@@ -165,6 +196,8 @@ ep_found:
+ 		case USB_ENDPOINT_XFER_ISOC:
+ 			/* mult: bits 1:0 of bmAttributes */
+ 			_ep->mult = comp_desc->bmAttributes & 0x3;
++			_ep->maxburst = comp_desc->bMaxBurst;
++			break;
+ 		case USB_ENDPOINT_XFER_BULK:
+ 		case USB_ENDPOINT_XFER_INT:
+ 			_ep->maxburst = comp_desc->bMaxBurst + 1;
+@@ -278,10 +311,10 @@ int usb_function_deactivate(struct usb_function *function)
+ 
+ 	spin_lock_irqsave(&cdev->lock, flags);
+ 
+-	if (cdev->deactivations == 0)
++	if (cdev->deactivations == 0) {
+ 		status = usb_gadget_disconnect(cdev->gadget);
+-	if (status == 0)
+ 		cdev->deactivations++;
++	}
+ 
+ 	spin_unlock_irqrestore(&cdev->lock, flags);
+ 	return status;
+@@ -845,7 +878,7 @@ done:
+ }
+ EXPORT_SYMBOL_GPL(usb_add_config);
+ 
+-static void remove_config(struct usb_composite_dev *cdev,
++static void unbind_config(struct usb_composite_dev *cdev,
+ 			      struct usb_configuration *config)
+ {
+ 	while (!list_empty(&config->functions)) {
+@@ -860,7 +893,6 @@ static void remove_config(struct usb_composite_dev *cdev,
+ 			/* may free memory for "f" */
+ 		}
+ 	}
+-	list_del(&config->list);
+ 	if (config->unbind) {
+ 		DBG(cdev, "unbind config '%s'/%p\n", config->label, config);
+ 		config->unbind(config);
+@@ -887,9 +919,11 @@ void usb_remove_config(struct usb_composite_dev *cdev,
+ 	if (cdev->config == config)
+ 		reset_config(cdev);
+ 
++	list_del(&config->list);
++
+ 	spin_unlock_irqrestore(&cdev->lock, flags);
+ 
+-	remove_config(cdev, config);
++	unbind_config(cdev, config);
+ }
+ 
+ /*-------------------------------------------------------------------------*/
+@@ -1780,6 +1814,12 @@ void composite_disconnect(struct usb_gadget *gadget)
+ 	struct usb_composite_dev	*cdev = get_gadget_data(gadget);
+ 	unsigned long			flags;
+ 
++	if (cdev == NULL) {
++		WARN(1, "%s: Calling disconnect on a Gadget that is \
++			 not connected\n", __func__);
++		return;
++	}
++
+ 	/* REVISIT:  should we have config and device level
+ 	 * disconnect callbacks?
+ 	 */
+@@ -1818,7 +1858,8 @@ static void __composite_unbind(struct usb_gadget *gadget, bool unbind_driver)
+ 		struct usb_configuration	*c;
+ 		c = list_first_entry(&cdev->configs,
+ 				struct usb_configuration, list);
+-		remove_config(cdev, c);
++		list_del(&c->list);
++		unbind_config(cdev, c);
+ 	}
+ 	if (cdev->driver->unbind && unbind_driver)
+ 		cdev->driver->unbind(cdev);
+@@ -1835,6 +1876,35 @@ static void composite_unbind(struct usb_gadget *gadget)
+ 	__composite_unbind(gadget, true);
+ }
+ 
++#ifdef CONFIG_USB3_DEVICE_GPIO_CTRL
++static irqreturn_t dwc_usb3_gpio_irq(int irq, void *dev)
++{
++	int reg;
++	/* mask */
++	reg = hi_readl(GPIO1_IE);
++	reg &= ~GPIO1_0_IE;
++	hi_writel(reg, GPIO1_IE);
++	/* GPIO1_0 */
++	if (0 == (hi_readl(GPIO1_0_DATA) & 0x1)) {
++		/* host */
++		hi_writel(0x30c11004, __io_address(0x1018c110));
++		udelay(200);
++		/* device */
++		hi_writel(0x30c12004, __io_address(0x1018c110));
++		udelay(200);
++	}
++	/* clear */
++	reg = hi_readl(GPIO1_IC);
++	reg |= GPIO1_0_IC;
++	hi_writel(reg, GPIO1_IC);
++	/* unmask */
++	reg = hi_readl(GPIO1_IE);
++	reg |= GPIO1_0_IE;
++	hi_writel(reg, GPIO1_IE);
++	return 0;
++}
++#endif
++
+ static void update_unchanged_dev_desc(struct usb_device_descriptor *new,
+ 		const struct usb_device_descriptor *old)
+ {
+@@ -1968,6 +2038,10 @@ static int composite_bind(struct usb_gadget *gadget,
+ 	struct usb_composite_dev	*cdev;
+ 	struct usb_composite_driver	*composite = to_cdriver(gdriver);
+ 	int				status = -ENOMEM;
++#ifdef CONFIG_HIUSB_DEVICE2_0
++	void __iomem *usb2_base_reg;
++	int usb2_reg;
++#endif
+ 
+ 	cdev = kzalloc(sizeof *cdev, GFP_KERNEL);
+ 	if (!cdev)
+@@ -1999,10 +2073,39 @@ static int composite_bind(struct usb_gadget *gadget,
+ 
+ 	update_unchanged_dev_desc(&cdev->desc, composite->dev);
+ 
++#ifdef CONFIG_USB3_DEVICE_GPIO_CTRL
++	/* uvc Vendor and Product */
++	if (((cdev->desc).idVendor == 0x1d6b)
++		&& ((cdev->desc).idProduct == 0x102)) {
++		int ret = 0;
++
++		ret = request_irq(GPIO_IRQ_NUM, dwc_usb3_gpio_irq,
++				IRQF_SHARED | IRQF_DISABLED,
++				gpio_driver_name, cdev->driver);
++		uvc_flag = 1;
++		if (ret)
++			return ret;
++	}
++#endif
+ 	/* has userspace failed to provide a serial number? */
+ 	if (composite->needs_serial && !cdev->desc.iSerialNumber)
+ 		WARNING(cdev, "userspace failed to provide iSerialNumber\n");
+-
++#ifdef CONFIG_HIUSB_SS_DEVICE
++	writel(0x8000, __io_address(0x12030004));
++	mdelay(200);
++	writel(0x30c01004, __io_address(0x1018c110));
++	mdelay(200);
++	writel(0x30c02004, __io_address(0x1018c110));
++	mdelay(200);
++#endif
++#ifdef CONFIG_HIUSB_DEVICE2_0
++	usb2_base_reg = ioremap_nocache(USB2_BASE_REG, 0x1000);
++	usb2_reg = readl(usb2_base_reg + USB2_OTG_BASE);
++	usb2_reg &= ~(USB2_PHY_DPPULL_DOWN);
++	usb2_reg |= DWC_OTG_EN;
++	writel(usb2_reg, usb2_base_reg + USB2_OTG_BASE);
++	iounmap(usb2_base_reg);
++#endif
+ 	INFO(cdev, "%s ready\n", composite->name);
+ 	return 0;
+ 
+@@ -2129,7 +2232,26 @@ EXPORT_SYMBOL_GPL(usb_composite_probe);
+  */
+ void usb_composite_unregister(struct usb_composite_driver *driver)
+ {
++#ifdef CONFIG_HIUSB_DEVICE2_0
++	void __iomem *usb2_base_reg;
++	int usb2_reg;
++#endif
++
+ 	usb_gadget_unregister_driver(&driver->gadget_driver);
++#ifdef CONFIG_USB3_DEVICE_GPIO_CTRL
++	if (uvc_flag) {
++		free_irq(GPIO_IRQ_NUM, driver);
++		uvc_flag = 0;
++	}
++#endif
++#ifdef CONFIG_HIUSB_DEVICE2_0
++	usb2_base_reg = ioremap_nocache(USB2_BASE_REG, 0x1000);
++	usb2_reg = readl(usb2_base_reg + USB2_OTG_BASE);
++	usb2_reg |= USB2_PHY_DPPULL_DOWN;
++	usb2_reg &= ~DWC_OTG_EN;
++	writel(usb2_reg, usb2_base_reg + USB2_OTG_BASE);
++	iounmap(usb2_base_reg);
++#endif
+ }
+ EXPORT_SYMBOL_GPL(usb_composite_unregister);
+ 
+diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c
+index a7e1a96..fbf07ff 100644
+--- a/drivers/usb/gadget/configfs.c
++++ b/drivers/usb/gadget/configfs.c
+@@ -9,6 +9,31 @@
+ #include "u_f.h"
+ #include "u_os_desc.h"
+ 
++#ifdef CONFIG_USB_CONFIGFS_UEVENT
++#include <linux/platform_device.h>
++#include <linux/kdev_t.h>
++#include <linux/usb/ch9.h>
++
++#ifdef CONFIG_USB_CONFIGFS_F_ACC
++extern int acc_ctrlrequest(struct usb_composite_dev *cdev,
++				const struct usb_ctrlrequest *ctrl);
++void acc_disconnect(void);
++#endif
++static struct class *android_class;
++static struct device *android_device;
++static int index;
++
++struct device *create_function_device(char *name)
++{
++	if (android_device && !IS_ERR(android_device))
++		return device_create(android_class, android_device,
++			MKDEV(0, index++), NULL, name);
++	else
++		return ERR_PTR(-EINVAL);
++}
++EXPORT_SYMBOL_GPL(create_function_device);
++#endif
++
+ int check_user_usb_string(const char *name,
+ 		struct usb_gadget_strings *stringtab_dev)
+ {
+@@ -63,6 +88,12 @@ struct gadget_info {
+ 	bool use_os_desc;
+ 	char b_vendor_code;
+ 	char qw_sign[OS_STRING_QW_SIGN_LEN];
++#ifdef CONFIG_USB_CONFIGFS_UEVENT
++	bool connected;
++	bool sw_connected;
++	struct work_struct work;
++	struct device *dev;
++#endif
+ };
+ 
+ struct config_usb_cfg {
+@@ -262,7 +293,7 @@ static ssize_t gadget_dev_desc_UDC_store(struct gadget_info *gi,
+ 
+ 	mutex_lock(&gi->lock);
+ 
+-	if (!strlen(name)) {
++	if (!strlen(name) || strcmp(name, "none") == 0) {
+ 		ret = unregister_gadget(gi);
+ 		if (ret)
+ 			goto err;
+@@ -405,6 +436,11 @@ static int config_usb_cfg_link(
+ 	}
+ 
+ 	f = usb_get_function(fi);
++	if (f == NULL) {
++		/* Are we trying to symlink PTP without MTP function? */
++		ret = -EINVAL; /* Invalid Configuration */
++		goto out;
++	}
+ 	if (IS_ERR(f)) {
+ 		ret = PTR_ERR(f);
+ 		goto out;
+@@ -1427,6 +1463,60 @@ err_comp_cleanup:
+ 	return ret;
+ }
+ 
++#ifdef CONFIG_USB_CONFIGFS_UEVENT
++static void android_work(struct work_struct *data)
++{
++	struct gadget_info *gi = container_of(data, struct gadget_info, work);
++	struct usb_composite_dev *cdev = &gi->cdev;
++	char *disconnected[2] = { "USB_STATE=DISCONNECTED", NULL };
++	char *connected[2]    = { "USB_STATE=CONNECTED", NULL };
++	char *configured[2]   = { "USB_STATE=CONFIGURED", NULL };
++	/* 0-connected 1-configured 2-disconnected*/
++	bool status[3] = { false, false, false };
++	unsigned long flags;
++	bool uevent_sent = false;
++
++	spin_lock_irqsave(&cdev->lock, flags);
++	if (cdev->config)
++		status[1] = true;
++
++	if (gi->connected != gi->sw_connected) {
++		if (gi->connected)
++			status[0] = true;
++		else
++			status[2] = true;
++		gi->sw_connected = gi->connected;
++	}
++	spin_unlock_irqrestore(&cdev->lock, flags);
++
++	if (status[0]) {
++		kobject_uevent_env(&android_device->kobj,
++					KOBJ_CHANGE, connected);
++		pr_info("%s: sent uevent %s\n", __func__, connected[0]);
++		uevent_sent = true;
++	}
++
++	if (status[1]) {
++		kobject_uevent_env(&android_device->kobj,
++					KOBJ_CHANGE, configured);
++		pr_info("%s: sent uevent %s\n", __func__, configured[0]);
++		uevent_sent = true;
++	}
++
++	if (status[2]) {
++		kobject_uevent_env(&android_device->kobj,
++					KOBJ_CHANGE, disconnected);
++		pr_info("%s: sent uevent %s\n", __func__, disconnected[0]);
++		uevent_sent = true;
++	}
++
++	if (!uevent_sent) {
++		pr_info("%s: did not send uevent (%d %d %p)\n", __func__,
++			gi->connected, gi->sw_connected, cdev->config);
++	}
++}
++#endif
++
+ static void configfs_composite_unbind(struct usb_gadget *gadget)
+ {
+ 	struct usb_composite_dev	*cdev;
+@@ -1444,14 +1534,78 @@ static void configfs_composite_unbind(struct usb_gadget *gadget)
+ 	set_gadget_data(gadget, NULL);
+ }
+ 
++#ifdef CONFIG_USB_CONFIGFS_UEVENT
++static int android_setup(struct usb_gadget *gadget,
++			const struct usb_ctrlrequest *c)
++{
++	struct usb_composite_dev *cdev = get_gadget_data(gadget);
++	unsigned long flags;
++	struct gadget_info *gi = container_of(cdev, struct gadget_info, cdev);
++	int value = -EOPNOTSUPP;
++	struct usb_function_instance *fi;
++
++	spin_lock_irqsave(&cdev->lock, flags);
++	if (!gi->connected) {
++		gi->connected = 1;
++		schedule_work(&gi->work);
++	}
++	spin_unlock_irqrestore(&cdev->lock, flags);
++	list_for_each_entry(fi, &gi->available_func, cfs_list) {
++		if (fi != NULL && fi->f != NULL && fi->f->setup != NULL) {
++			value = fi->f->setup(fi->f, c);
++			if (value >= 0)
++				break;
++		}
++	}
++
++#ifdef CONFIG_USB_CONFIGFS_F_ACC
++	if (value < 0)
++		value = acc_ctrlrequest(cdev, c);
++#endif
++
++	if (value < 0)
++		value = composite_setup(gadget, c);
++
++	spin_lock_irqsave(&cdev->lock, flags);
++	if (c->bRequest == USB_REQ_SET_CONFIGURATION &&
++						cdev->config) {
++		schedule_work(&gi->work);
++	}
++	spin_unlock_irqrestore(&cdev->lock, flags);
++
++	return value;
++}
++
++static void android_disconnect(struct usb_gadget *gadget)
++{
++	struct usb_composite_dev        *cdev = get_gadget_data(gadget);
++	struct gadget_info *gi = container_of(cdev, struct gadget_info, cdev);
++
++	/* accessory HID support can be active while the
++		accessory function is not actually enabled,
++		so we need to inform it when we are disconnected.
++	*/
++
++#ifdef CONFIG_USB_CONFIGFS_F_ACC
++	acc_disconnect();
++#endif
++	gi->connected = 0;
++	schedule_work(&gi->work);
++	composite_disconnect(gadget);
++}
++#endif
++
+ static const struct usb_gadget_driver configfs_driver_template = {
+ 	.bind           = configfs_composite_bind,
+ 	.unbind         = configfs_composite_unbind,
+-
++#ifdef CONFIG_USB_CONFIGFS_UEVENT
++	.setup          = android_setup,
++	.disconnect     = android_disconnect,
++#else
+ 	.setup          = composite_setup,
+ 	.reset          = composite_disconnect,
+ 	.disconnect     = composite_disconnect,
+-
++#endif
+ 	.max_speed	= USB_SPEED_SUPER,
+ 	.driver = {
+ 		.owner          = THIS_MODULE,
+@@ -1459,6 +1613,89 @@ static const struct usb_gadget_driver configfs_driver_template = {
+ 	},
+ };
+ 
++#ifdef CONFIG_USB_CONFIGFS_UEVENT
++static ssize_t state_show(struct device *pdev, struct device_attribute *attr,
++			char *buf)
++{
++	struct gadget_info *dev = dev_get_drvdata(pdev);
++	struct usb_composite_dev *cdev;
++	char *state = "DISCONNECTED";
++	unsigned long flags;
++
++	if (!dev)
++		goto out;
++
++	cdev = &dev->cdev;
++
++	if (!cdev)
++		goto out;
++
++	spin_lock_irqsave(&cdev->lock, flags);
++	if (cdev->config)
++		state = "CONFIGURED";
++	else if (dev->connected)
++		state = "CONNECTED";
++	spin_unlock_irqrestore(&cdev->lock, flags);
++out:
++	return sprintf(buf, "%s\n", state);
++}
++
++static DEVICE_ATTR(state, S_IRUGO, state_show, NULL);
++
++static struct device_attribute *android_usb_attributes[] = {
++	&dev_attr_state,
++	NULL
++};
++
++static int android_device_create(struct gadget_info *gi)
++{
++	struct device_attribute **attrs;
++	struct device_attribute *attr;
++
++	INIT_WORK(&gi->work, android_work);
++	android_device = device_create(android_class, NULL,
++				MKDEV(0, 0), NULL, "android0");
++	if (IS_ERR(android_device))
++		return PTR_ERR(android_device);
++
++	dev_set_drvdata(android_device, gi);
++
++	attrs = android_usb_attributes;
++	while ((attr = *attrs++)) {
++		int err;
++
++		err = device_create_file(android_device, attr);
++		if (err) {
++			device_destroy(android_device->class,
++				       android_device->devt);
++			return err;
++		}
++	}
++
++	return 0;
++}
++
++static void android_device_destroy(void)
++{
++	struct device_attribute **attrs;
++	struct device_attribute *attr;
++
++	attrs = android_usb_attributes;
++	while ((attr = *attrs++))
++		device_remove_file(android_device, attr);
++	device_destroy(android_device->class, android_device->devt);
++}
++#else
++static inline int android_device_create(struct gadget_info *gi)
++{
++	return 0;
++}
++
++static inline void android_device_destroy(void)
++{
++}
++#endif
++
+ static struct config_group *gadgets_make(
+ 		struct config_group *group,
+ 		const char *name)
+@@ -1468,7 +1705,6 @@ static struct config_group *gadgets_make(
+ 	gi = kzalloc(sizeof(*gi), GFP_KERNEL);
+ 	if (!gi)
+ 		return ERR_PTR(-ENOMEM);
+-
+ 	gi->group.default_groups = gi->default_groups;
+ 	gi->group.default_groups[0] = &gi->functions_group;
+ 	gi->group.default_groups[1] = &gi->configs_group;
+@@ -1507,6 +1743,9 @@ static struct config_group *gadgets_make(
+ 	if (!gi->composite.gadget_driver.function)
+ 		goto err;
+ 
++	if (android_device_create(gi) < 0)
++		goto err;
++
+ #ifdef CONFIG_USB_OTG
+ 	gi->otg.bLength = sizeof(struct usb_otg_descriptor);
+ 	gi->otg.bDescriptorType = USB_DT_OTG;
+@@ -1516,6 +1755,7 @@ static struct config_group *gadgets_make(
+ 	config_group_init_type_name(&gi->group, name,
+ 				&gadget_root_type);
+ 	return &gi->group;
++
+ err:
+ 	kfree(gi);
+ 	return ERR_PTR(-ENOMEM);
+@@ -1524,6 +1764,7 @@ err:
+ static void gadgets_drop(struct config_group *group, struct config_item *item)
+ {
+ 	config_item_put(item);
++	android_device_destroy();
+ }
+ 
+ static struct configfs_group_operations gadgets_ops = {
+@@ -1561,6 +1802,13 @@ static int __init gadget_cfs_init(void)
+ 	config_group_init(&gadget_subsys.su_group);
+ 
+ 	ret = configfs_register_subsystem(&gadget_subsys);
++
++#ifdef CONFIG_USB_CONFIGFS_UEVENT
++	android_class = class_create(THIS_MODULE, "android_usb");
++	if (IS_ERR(android_class))
++		return PTR_ERR(android_class);
++#endif
++
+ 	return ret;
+ }
+ module_init(gadget_cfs_init);
+@@ -1568,5 +1816,10 @@ module_init(gadget_cfs_init);
+ static void __exit gadget_cfs_exit(void)
+ {
+ 	configfs_unregister_subsystem(&gadget_subsys);
++#ifdef CONFIG_USB_CONFIGFS_UEVENT
++	if (!IS_ERR(android_class))
++		class_destroy(android_class);
++#endif
++
+ }
+ module_exit(gadget_cfs_exit);
+diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c
+index 0567cca..741d75b 100644
+--- a/drivers/usb/gadget/epautoconf.c
++++ b/drivers/usb/gadget/epautoconf.c
+@@ -180,8 +180,8 @@ ep_matches (
+ 		int size = ep->maxpacket_limit;
+ 
+ 		/* min() doesn't work on bitfields with gcc-3.5 */
+-		if (size > 64)
+-			size = 64;
++		if (size > 512)
++			size = 512;
+ 		desc->wMaxPacketSize = cpu_to_le16(size);
+ 	}
+ 	ep->address = desc->bEndpointAddress;
+diff --git a/drivers/usb/gadget/function/Makefile b/drivers/usb/gadget/function/Makefile
+index 90701aa..4167a04 100644
+--- a/drivers/usb/gadget/function/Makefile
++++ b/drivers/usb/gadget/function/Makefile
+@@ -32,9 +32,21 @@ usb_f_mass_storage-y		:= f_mass_storage.o storage_common.o
+ obj-$(CONFIG_USB_F_MASS_STORAGE)+= usb_f_mass_storage.o
+ usb_f_fs-y			:= f_fs.o
+ obj-$(CONFIG_USB_F_FS)		+= usb_f_fs.o
+-usb_f_uac1-y			:= f_uac1.o u_uac1.o
++usb_f_uac1-y			:= f_uac1.o uac_audio_ex.o uac_queue_ex.o uac_v4l2_ex.o
+ obj-$(CONFIG_USB_F_UAC1)	+= usb_f_uac1.o
+ usb_f_uac2-y			:= f_uac2.o
+ obj-$(CONFIG_USB_F_UAC2)	+= usb_f_uac2.o
+ usb_f_uvc-y			:= f_uvc.o uvc_queue.o uvc_v4l2.o uvc_video.o
+ obj-$(CONFIG_USB_F_UVC)		+= usb_f_uvc.o
++usb_f_mtp-y                     := f_mtp.o
++obj-$(CONFIG_USB_F_MTP)         += usb_f_mtp.o
++usb_f_ptp-y                     := f_ptp.o
++obj-$(CONFIG_USB_F_PTP)         += usb_f_ptp.o
++usb_f_audio_source-y            := f_audio_source.o
++obj-$(CONFIG_USB_F_AUDIO_SRC)   += usb_f_audio_source.o
++usb_f_accessory-y               := f_accessory.o
++obj-$(CONFIG_USB_F_ACC)         += usb_f_accessory.o
++
++
++usb_f_midi-y			:= f_midi.o
++obj-$(CONFIG_USB_F_MIDI)	+= usb_f_midi.o
+diff --git a/drivers/usb/gadget/function/f_accessory.c b/drivers/usb/gadget/function/f_accessory.c
+new file mode 100644
+index 0000000..95a7bbb
+--- /dev/null
++++ b/drivers/usb/gadget/function/f_accessory.c
+@@ -0,0 +1,1362 @@
++/*
++ * Gadget Function Driver for Android USB accessories
++ *
++ * Copyright (C) 2011 Google, Inc.
++ * Author: Mike Lockwood <lockwood@android.com>
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * 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.
++ *
++ */
++
++/* #define DEBUG */
++/* #define VERBOSE_DEBUG */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/poll.h>
++#include <linux/delay.h>
++#include <linux/wait.h>
++#include <linux/err.h>
++#include <linux/interrupt.h>
++#include <linux/kthread.h>
++#include <linux/freezer.h>
++
++#include <linux/types.h>
++#include <linux/file.h>
++#include <linux/device.h>
++#include <linux/miscdevice.h>
++
++#include <linux/hid.h>
++#include <linux/hiddev.h>
++#include <linux/usb.h>
++#include <linux/usb/ch9.h>
++#include <linux/usb/f_accessory.h>
++
++#include <linux/configfs.h>
++#include <linux/usb/composite.h>
++
++#define MAX_INST_NAME_LEN        40
++#define BULK_BUFFER_SIZE    16384
++#define ACC_STRING_SIZE     256
++
++#define PROTOCOL_VERSION    2
++
++/* String IDs */
++#define INTERFACE_STRING_INDEX	0
++
++/* number of tx and rx requests to allocate */
++#define TX_REQ_MAX 4
++#define RX_REQ_MAX 2
++
++struct acc_hid_dev {
++	struct list_head	list;
++	struct hid_device *hid;
++	struct acc_dev *dev;
++	/* accessory defined ID */
++	int id;
++	/* HID report descriptor */
++	u8 *report_desc;
++	/* length of HID report descriptor */
++	int report_desc_len;
++	/* number of bytes of report_desc we have received so far */
++	int report_desc_offset;
++};
++
++struct acc_dev {
++	struct usb_function function;
++	struct usb_composite_dev *cdev;
++	spinlock_t lock;
++
++	struct usb_ep *ep_in;
++	struct usb_ep *ep_out;
++
++	/* set to 1 when we connect */
++	int online:1;
++	/* Set to 1 when we disconnect.
++	 * Not cleared until our file is closed.
++	 */
++	int disconnected:1;
++
++	/* strings sent by the host */
++	char manufacturer[ACC_STRING_SIZE];
++	char model[ACC_STRING_SIZE];
++	char description[ACC_STRING_SIZE];
++	char version[ACC_STRING_SIZE];
++	char uri[ACC_STRING_SIZE];
++	char serial[ACC_STRING_SIZE];
++
++	/* for acc_complete_set_string */
++	int string_index;
++
++	/* set to 1 if we have a pending start request */
++	int start_requested;
++
++	int audio_mode;
++
++	/* synchronize access to our device file */
++	atomic_t open_excl;
++
++	struct list_head tx_idle;
++
++	wait_queue_head_t read_wq;
++	wait_queue_head_t write_wq;
++	struct usb_request *rx_req[RX_REQ_MAX];
++	int rx_done;
++
++	/* delayed work for handling ACCESSORY_START */
++	struct delayed_work start_work;
++
++	/* worker for registering and unregistering hid devices */
++	struct work_struct hid_work;
++
++	/* list of active HID devices */
++	struct list_head	hid_list;
++
++	/* list of new HID devices to register */
++	struct list_head	new_hid_list;
++
++	/* list of dead HID devices to unregister */
++	struct list_head	dead_hid_list;
++};
++
++static struct usb_interface_descriptor acc_interface_desc = {
++	.bLength                = USB_DT_INTERFACE_SIZE,
++	.bDescriptorType        = USB_DT_INTERFACE,
++	.bInterfaceNumber       = 0,
++	.bNumEndpoints          = 2,
++	.bInterfaceClass        = USB_CLASS_VENDOR_SPEC,
++	.bInterfaceSubClass     = USB_SUBCLASS_VENDOR_SPEC,
++	.bInterfaceProtocol     = 0,
++};
++
++static struct usb_endpoint_descriptor acc_highspeed_in_desc = {
++	.bLength                = USB_DT_ENDPOINT_SIZE,
++	.bDescriptorType        = USB_DT_ENDPOINT,
++	.bEndpointAddress       = USB_DIR_IN,
++	.bmAttributes           = USB_ENDPOINT_XFER_BULK,
++	.wMaxPacketSize         = __constant_cpu_to_le16(512),
++};
++
++static struct usb_endpoint_descriptor acc_highspeed_out_desc = {
++	.bLength                = USB_DT_ENDPOINT_SIZE,
++	.bDescriptorType        = USB_DT_ENDPOINT,
++	.bEndpointAddress       = USB_DIR_OUT,
++	.bmAttributes           = USB_ENDPOINT_XFER_BULK,
++	.wMaxPacketSize         = __constant_cpu_to_le16(512),
++};
++
++static struct usb_endpoint_descriptor acc_fullspeed_in_desc = {
++	.bLength                = USB_DT_ENDPOINT_SIZE,
++	.bDescriptorType        = USB_DT_ENDPOINT,
++	.bEndpointAddress       = USB_DIR_IN,
++	.bmAttributes           = USB_ENDPOINT_XFER_BULK,
++};
++
++static struct usb_endpoint_descriptor acc_fullspeed_out_desc = {
++	.bLength                = USB_DT_ENDPOINT_SIZE,
++	.bDescriptorType        = USB_DT_ENDPOINT,
++	.bEndpointAddress       = USB_DIR_OUT,
++	.bmAttributes           = USB_ENDPOINT_XFER_BULK,
++};
++
++static struct usb_descriptor_header *fs_acc_descs[] = {
++	(struct usb_descriptor_header *) &acc_interface_desc,
++	(struct usb_descriptor_header *) &acc_fullspeed_in_desc,
++	(struct usb_descriptor_header *) &acc_fullspeed_out_desc,
++	NULL,
++};
++
++static struct usb_descriptor_header *hs_acc_descs[] = {
++	(struct usb_descriptor_header *) &acc_interface_desc,
++	(struct usb_descriptor_header *) &acc_highspeed_in_desc,
++	(struct usb_descriptor_header *) &acc_highspeed_out_desc,
++	NULL,
++};
++
++static struct usb_string acc_string_defs[] = {
++	[INTERFACE_STRING_INDEX].s	= "Android Accessory Interface",
++	{  },	/* end of list */
++};
++
++static struct usb_gadget_strings acc_string_table = {
++	.language		= 0x0409,	/* en-US */
++	.strings		= acc_string_defs,
++};
++
++static struct usb_gadget_strings *acc_strings[] = {
++	&acc_string_table,
++	NULL,
++};
++
++/* temporary variable used between acc_open() and acc_gadget_bind() */
++static struct acc_dev *_acc_dev;
++
++struct acc_instance {
++	struct usb_function_instance func_inst;
++	const char *name;
++};
++
++static inline struct acc_dev *func_to_dev(struct usb_function *f)
++{
++	return container_of(f, struct acc_dev, function);
++}
++
++static struct usb_request *acc_request_new(struct usb_ep *ep, int buffer_size)
++{
++	struct usb_request *req = usb_ep_alloc_request(ep, GFP_KERNEL);
++	if (!req)
++		return NULL;
++
++	/* now allocate buffers for the requests */
++	req->buf = kmalloc(buffer_size, GFP_KERNEL);
++	if (!req->buf) {
++		usb_ep_free_request(ep, req);
++		return NULL;
++	}
++
++	return req;
++}
++
++static void acc_request_free(struct usb_request *req, struct usb_ep *ep)
++{
++	if (req) {
++		kfree(req->buf);
++		usb_ep_free_request(ep, req);
++	}
++}
++
++/* add a request to the tail of a list */
++static void req_put(struct acc_dev *dev, struct list_head *head,
++		struct usb_request *req)
++{
++	unsigned long flags;
++
++	spin_lock_irqsave(&dev->lock, flags);
++	list_add_tail(&req->list, head);
++	spin_unlock_irqrestore(&dev->lock, flags);
++}
++
++/* remove a request from the head of a list */
++static struct usb_request *req_get(struct acc_dev *dev, struct list_head *head)
++{
++	unsigned long flags;
++	struct usb_request *req;
++
++	spin_lock_irqsave(&dev->lock, flags);
++	if (list_empty(head)) {
++		req = 0;
++	} else {
++		req = list_first_entry(head, struct usb_request, list);
++		list_del(&req->list);
++	}
++	spin_unlock_irqrestore(&dev->lock, flags);
++	return req;
++}
++
++static void acc_set_disconnected(struct acc_dev *dev)
++{
++	dev->online = 0;
++	dev->disconnected = 1;
++}
++
++static void acc_complete_in(struct usb_ep *ep, struct usb_request *req)
++{
++	struct acc_dev *dev = _acc_dev;
++
++	if (req->status == -ESHUTDOWN) {
++		pr_debug("acc_complete_in set disconnected");
++		acc_set_disconnected(dev);
++	}
++
++	req_put(dev, &dev->tx_idle, req);
++
++	wake_up(&dev->write_wq);
++}
++
++static void acc_complete_out(struct usb_ep *ep, struct usb_request *req)
++{
++	struct acc_dev *dev = _acc_dev;
++
++	dev->rx_done = 1;
++	if (req->status == -ESHUTDOWN) {
++		pr_debug("acc_complete_out set disconnected");
++		acc_set_disconnected(dev);
++	}
++
++	wake_up(&dev->read_wq);
++}
++
++static void acc_complete_set_string(struct usb_ep *ep, struct usb_request *req)
++{
++	struct acc_dev	*dev = ep->driver_data;
++	char *string_dest = NULL;
++	int length = req->actual;
++
++	if (req->status != 0) {
++		pr_err("acc_complete_set_string, err %d\n", req->status);
++		return;
++	}
++
++	switch (dev->string_index) {
++	case ACCESSORY_STRING_MANUFACTURER:
++		string_dest = dev->manufacturer;
++		break;
++	case ACCESSORY_STRING_MODEL:
++		string_dest = dev->model;
++		break;
++	case ACCESSORY_STRING_DESCRIPTION:
++		string_dest = dev->description;
++		break;
++	case ACCESSORY_STRING_VERSION:
++		string_dest = dev->version;
++		break;
++	case ACCESSORY_STRING_URI:
++		string_dest = dev->uri;
++		break;
++	case ACCESSORY_STRING_SERIAL:
++		string_dest = dev->serial;
++		break;
++	}
++	if (string_dest) {
++		unsigned long flags;
++
++		if (length >= ACC_STRING_SIZE)
++			length = ACC_STRING_SIZE - 1;
++
++		spin_lock_irqsave(&dev->lock, flags);
++		memcpy(string_dest, req->buf, length);
++		/* ensure zero termination */
++		string_dest[length] = 0;
++		spin_unlock_irqrestore(&dev->lock, flags);
++	} else {
++		pr_err("unknown accessory string index %d\n",
++			dev->string_index);
++	}
++}
++
++static void acc_complete_set_hid_report_desc(struct usb_ep *ep,
++		struct usb_request *req)
++{
++	struct acc_hid_dev *hid = req->context;
++	struct acc_dev *dev = hid->dev;
++	int length = req->actual;
++
++	if (req->status != 0) {
++		pr_err("acc_complete_set_hid_report_desc, err %d\n",
++			req->status);
++		return;
++	}
++
++	memcpy(hid->report_desc + hid->report_desc_offset, req->buf, length);
++	hid->report_desc_offset += length;
++	if (hid->report_desc_offset == hid->report_desc_len) {
++		/* After we have received the entire report descriptor
++		 * we schedule work to initialize the HID device
++		 */
++		schedule_work(&dev->hid_work);
++	}
++}
++
++static void acc_complete_send_hid_event(struct usb_ep *ep,
++		struct usb_request *req)
++{
++	struct acc_hid_dev *hid = req->context;
++	int length = req->actual;
++
++	if (req->status != 0) {
++		pr_err("acc_complete_send_hid_event, err %d\n", req->status);
++		return;
++	}
++
++	hid_report_raw_event(hid->hid, HID_INPUT_REPORT, req->buf, length, 1);
++}
++
++static int acc_hid_parse(struct hid_device *hid)
++{
++	struct acc_hid_dev *hdev = hid->driver_data;
++
++	hid_parse_report(hid, hdev->report_desc, hdev->report_desc_len);
++	return 0;
++}
++
++static int acc_hid_start(struct hid_device *hid)
++{
++	return 0;
++}
++
++static void acc_hid_stop(struct hid_device *hid)
++{
++}
++
++static int acc_hid_open(struct hid_device *hid)
++{
++	return 0;
++}
++
++static void acc_hid_close(struct hid_device *hid)
++{
++}
++
++static struct hid_ll_driver acc_hid_ll_driver = {
++	.parse = acc_hid_parse,
++	.start = acc_hid_start,
++	.stop = acc_hid_stop,
++	.open = acc_hid_open,
++	.close = acc_hid_close,
++};
++
++static struct acc_hid_dev *acc_hid_new(struct acc_dev *dev,
++		int id, int desc_len)
++{
++	struct acc_hid_dev *hdev;
++
++	hdev = kzalloc(sizeof(*hdev), GFP_ATOMIC);
++	if (!hdev)
++		return NULL;
++	hdev->report_desc = kzalloc(desc_len, GFP_ATOMIC);
++	if (!hdev->report_desc) {
++		kfree(hdev);
++		return NULL;
++	}
++	hdev->dev = dev;
++	hdev->id = id;
++	hdev->report_desc_len = desc_len;
++
++	return hdev;
++}
++
++static struct acc_hid_dev *acc_hid_get(struct list_head *list, int id)
++{
++	struct acc_hid_dev *hid;
++
++	list_for_each_entry(hid, list, list) {
++		if (hid->id == id)
++			return hid;
++	}
++	return NULL;
++}
++
++static int acc_register_hid(struct acc_dev *dev, int id, int desc_length)
++{
++	struct acc_hid_dev *hid;
++	unsigned long flags;
++
++	/* report descriptor length must be > 0 */
++	if (desc_length <= 0)
++		return -EINVAL;
++
++	spin_lock_irqsave(&dev->lock, flags);
++	/* replace HID if one already exists with this ID */
++	hid = acc_hid_get(&dev->hid_list, id);
++	if (!hid)
++		hid = acc_hid_get(&dev->new_hid_list, id);
++	if (hid)
++		list_move(&hid->list, &dev->dead_hid_list);
++
++	hid = acc_hid_new(dev, id, desc_length);
++	if (!hid) {
++		spin_unlock_irqrestore(&dev->lock, flags);
++		return -ENOMEM;
++	}
++
++	list_add(&hid->list, &dev->new_hid_list);
++	spin_unlock_irqrestore(&dev->lock, flags);
++
++	/* schedule work to register the HID device */
++	schedule_work(&dev->hid_work);
++	return 0;
++}
++
++static int acc_unregister_hid(struct acc_dev *dev, int id)
++{
++	struct acc_hid_dev *hid;
++	unsigned long flags;
++
++	spin_lock_irqsave(&dev->lock, flags);
++	hid = acc_hid_get(&dev->hid_list, id);
++	if (!hid)
++		hid = acc_hid_get(&dev->new_hid_list, id);
++	if (!hid) {
++		spin_unlock_irqrestore(&dev->lock, flags);
++		return -EINVAL;
++	}
++
++	list_move(&hid->list, &dev->dead_hid_list);
++	spin_unlock_irqrestore(&dev->lock, flags);
++
++	schedule_work(&dev->hid_work);
++	return 0;
++}
++
++static int create_bulk_endpoints(struct acc_dev *dev,
++				struct usb_endpoint_descriptor *in_desc,
++				struct usb_endpoint_descriptor *out_desc)
++{
++	struct usb_composite_dev *cdev = dev->cdev;
++	struct usb_request *req;
++	struct usb_ep *ep;
++	int i;
++
++	DBG(cdev, "create_bulk_endpoints dev: %p\n", dev);
++
++	ep = usb_ep_autoconfig(cdev->gadget, in_desc);
++	if (!ep) {
++		DBG(cdev, "usb_ep_autoconfig for ep_in failed\n");
++		return -ENODEV;
++	}
++	DBG(cdev, "usb_ep_autoconfig for ep_in got %s\n", ep->name);
++	ep->driver_data = dev;		/* claim the endpoint */
++	dev->ep_in = ep;
++
++	ep = usb_ep_autoconfig(cdev->gadget, out_desc);
++	if (!ep) {
++		DBG(cdev, "usb_ep_autoconfig for ep_out failed\n");
++		return -ENODEV;
++	}
++	DBG(cdev, "usb_ep_autoconfig for ep_out got %s\n", ep->name);
++	ep->driver_data = dev;		/* claim the endpoint */
++	dev->ep_out = ep;
++
++	ep = usb_ep_autoconfig(cdev->gadget, out_desc);
++	if (!ep) {
++		DBG(cdev, "usb_ep_autoconfig for ep_out failed\n");
++		return -ENODEV;
++	}
++	DBG(cdev, "usb_ep_autoconfig for ep_out got %s\n", ep->name);
++	ep->driver_data = dev;		/* claim the endpoint */
++	dev->ep_out = ep;
++
++	/* now allocate requests for our endpoints */
++	for (i = 0; i < TX_REQ_MAX; i++) {
++		req = acc_request_new(dev->ep_in, BULK_BUFFER_SIZE);
++		if (!req)
++			goto fail;
++		req->complete = acc_complete_in;
++		req_put(dev, &dev->tx_idle, req);
++	}
++	for (i = 0; i < RX_REQ_MAX; i++) {
++		req = acc_request_new(dev->ep_out, BULK_BUFFER_SIZE);
++		if (!req)
++			goto fail;
++		req->complete = acc_complete_out;
++		dev->rx_req[i] = req;
++	}
++
++	return 0;
++
++fail:
++	pr_err("acc_bind() could not allocate requests\n");
++	while ((req = req_get(dev, &dev->tx_idle)))
++		acc_request_free(req, dev->ep_in);
++	for (i = 0; i < RX_REQ_MAX; i++)
++		acc_request_free(dev->rx_req[i], dev->ep_out);
++	return -1;
++}
++
++static ssize_t acc_read(struct file *fp, char __user *buf,
++	size_t count, loff_t *pos)
++{
++	struct acc_dev *dev = fp->private_data;
++	struct usb_request *req;
++	ssize_t r = count;
++	unsigned xfer;
++	int ret = 0;
++
++	pr_debug("acc_read(%zu)\n", count);
++
++	if (dev->disconnected) {
++		pr_debug("acc_read disconnected");
++		return -ENODEV;
++	}
++
++	if (count > BULK_BUFFER_SIZE)
++		count = BULK_BUFFER_SIZE;
++
++	/* we will block until we're online */
++	pr_debug("acc_read: waiting for online\n");
++	ret = wait_event_interruptible(dev->read_wq, dev->online);
++	if (ret < 0) {
++		r = ret;
++		goto done;
++	}
++
++	if (dev->rx_done) {
++		// last req cancelled. try to get it.
++		req = dev->rx_req[0];
++		goto copy_data;
++	}
++
++requeue_req:
++	/* queue a request */
++	req = dev->rx_req[0];
++	req->length = count;
++	dev->rx_done = 0;
++	ret = usb_ep_queue(dev->ep_out, req, GFP_KERNEL);
++	if (ret < 0) {
++		r = -EIO;
++		goto done;
++	} else {
++		pr_debug("rx %p queue\n", req);
++	}
++
++	/* wait for a request to complete */
++	ret = wait_event_interruptible(dev->read_wq, dev->rx_done);
++	if (ret < 0) {
++		r = ret;
++		ret = usb_ep_dequeue(dev->ep_out, req);
++		if (ret != 0) {
++			// cancel failed. There can be a data already received.
++			// it will be retrieved in the next read.
++			pr_debug("acc_read: cancelling failed %d", ret);
++		}
++		goto done;
++	}
++
++copy_data:
++	dev->rx_done = 0;
++	if (dev->online) {
++		/* If we got a 0-len packet, throw it back and try again. */
++		if (req->actual == 0)
++			goto requeue_req;
++
++		pr_debug("rx %p %u\n", req, req->actual);
++		xfer = (req->actual < count) ? req->actual : count;
++		r = xfer;
++		if (copy_to_user(buf, req->buf, xfer))
++			r = -EFAULT;
++	} else
++		r = -EIO;
++
++done:
++	pr_debug("acc_read returning %zd\n", r);
++	return r;
++}
++
++static ssize_t acc_write(struct file *fp, const char __user *buf,
++	size_t count, loff_t *pos)
++{
++	struct acc_dev *dev = fp->private_data;
++	struct usb_request *req = 0;
++	ssize_t r = count;
++	unsigned xfer;
++	int ret;
++
++	pr_debug("acc_write(%zu)\n", count);
++
++	if (!dev->online || dev->disconnected) {
++		pr_debug("acc_write disconnected or not online");
++		return -ENODEV;
++	}
++
++	while (count > 0) {
++		if (!dev->online) {
++			pr_debug("acc_write dev->error\n");
++			r = -EIO;
++			break;
++		}
++
++		/* get an idle tx request to use */
++		req = 0;
++		ret = wait_event_interruptible(dev->write_wq,
++			((req = req_get(dev, &dev->tx_idle)) || !dev->online));
++		if (!req) {
++			r = ret;
++			break;
++		}
++
++		if (count > BULK_BUFFER_SIZE) {
++			xfer = BULK_BUFFER_SIZE;
++			/* ZLP, They will be more TX requests so not yet. */
++			req->zero = 0;
++		} else {
++			xfer = count;
++			/* If the data length is a multple of the
++			 * maxpacket size then send a zero length packet(ZLP).
++			*/
++			req->zero = ((xfer % dev->ep_in->maxpacket) == 0);
++		}
++		if (copy_from_user(req->buf, buf, xfer)) {
++			r = -EFAULT;
++			break;
++		}
++
++		req->length = xfer;
++		ret = usb_ep_queue(dev->ep_in, req, GFP_KERNEL);
++		if (ret < 0) {
++			pr_debug("acc_write: xfer error %d\n", ret);
++			r = -EIO;
++			break;
++		}
++
++		buf += xfer;
++		count -= xfer;
++
++		/* zero this so we don't try to free it on error exit */
++		req = 0;
++	}
++
++	if (req)
++		req_put(dev, &dev->tx_idle, req);
++
++	pr_debug("acc_write returning %zd\n", r);
++	return r;
++}
++
++static long acc_ioctl(struct file *fp, unsigned code, unsigned long value)
++{
++	struct acc_dev *dev = fp->private_data;
++	char *src = NULL;
++	int ret;
++
++	switch (code) {
++	case ACCESSORY_GET_STRING_MANUFACTURER:
++		src = dev->manufacturer;
++		break;
++	case ACCESSORY_GET_STRING_MODEL:
++		src = dev->model;
++		break;
++	case ACCESSORY_GET_STRING_DESCRIPTION:
++		src = dev->description;
++		break;
++	case ACCESSORY_GET_STRING_VERSION:
++		src = dev->version;
++		break;
++	case ACCESSORY_GET_STRING_URI:
++		src = dev->uri;
++		break;
++	case ACCESSORY_GET_STRING_SERIAL:
++		src = dev->serial;
++		break;
++	case ACCESSORY_IS_START_REQUESTED:
++		return dev->start_requested;
++	case ACCESSORY_GET_AUDIO_MODE:
++		return dev->audio_mode;
++	}
++	if (!src)
++		return -EINVAL;
++
++	ret = strlen(src) + 1;
++	if (copy_to_user((void __user *)value, src, ret))
++		ret = -EFAULT;
++	return ret;
++}
++
++static int acc_open(struct inode *ip, struct file *fp)
++{
++	printk(KERN_INFO "acc_open\n");
++	if (atomic_xchg(&_acc_dev->open_excl, 1))
++		return -EBUSY;
++
++	_acc_dev->disconnected = 0;
++	fp->private_data = _acc_dev;
++	return 0;
++}
++
++static int acc_release(struct inode *ip, struct file *fp)
++{
++	printk(KERN_INFO "acc_release\n");
++
++	WARN_ON(!atomic_xchg(&_acc_dev->open_excl, 0));
++	_acc_dev->disconnected = 0;
++	return 0;
++}
++
++/* file operations for /dev/usb_accessory */
++static const struct file_operations acc_fops = {
++	.owner = THIS_MODULE,
++	.read = acc_read,
++	.write = acc_write,
++	.unlocked_ioctl = acc_ioctl,
++	.open = acc_open,
++	.release = acc_release,
++};
++
++static int acc_hid_probe(struct hid_device *hdev,
++		const struct hid_device_id *id)
++{
++	int ret;
++
++	ret = hid_parse(hdev);
++	if (ret)
++		return ret;
++	return hid_hw_start(hdev, HID_CONNECT_DEFAULT);
++}
++
++static struct miscdevice acc_device = {
++	.minor = MISC_DYNAMIC_MINOR,
++	.name = "usb_accessory",
++	.fops = &acc_fops,
++};
++
++static const struct hid_device_id acc_hid_table[] = {
++	{ HID_USB_DEVICE(HID_ANY_ID, HID_ANY_ID) },
++	{ }
++};
++
++static struct hid_driver acc_hid_driver = {
++	.name = "USB accessory",
++	.id_table = acc_hid_table,
++	.probe = acc_hid_probe,
++};
++
++int acc_ctrlrequest(struct usb_composite_dev *cdev,
++				const struct usb_ctrlrequest *ctrl)
++{
++	struct acc_dev	*dev = _acc_dev;
++	int	value = -EOPNOTSUPP;
++	struct acc_hid_dev *hid;
++	int offset;
++	u8 b_requestType = ctrl->bRequestType;
++	u8 b_request = ctrl->bRequest;
++	u16	w_index = le16_to_cpu(ctrl->wIndex);
++	u16	w_value = le16_to_cpu(ctrl->wValue);
++	u16	w_length = le16_to_cpu(ctrl->wLength);
++	unsigned long flags;
++
++/*
++	printk(KERN_INFO "acc_ctrlrequest "
++			"%02x.%02x v%04x i%04x l%u\n",
++			b_requestType, b_request,
++			w_value, w_index, w_length);
++*/
++
++	if (b_requestType == (USB_DIR_OUT | USB_TYPE_VENDOR)) {
++		if (b_request == ACCESSORY_START) {
++			dev->start_requested = 1;
++			schedule_delayed_work(
++				&dev->start_work, msecs_to_jiffies(10));
++			value = 0;
++		} else if (b_request == ACCESSORY_SEND_STRING) {
++			dev->string_index = w_index;
++			cdev->gadget->ep0->driver_data = dev;
++			cdev->req->complete = acc_complete_set_string;
++			value = w_length;
++		} else if (b_request == ACCESSORY_SET_AUDIO_MODE &&
++				w_index == 0 && w_length == 0) {
++			dev->audio_mode = w_value;
++			value = 0;
++		} else if (b_request == ACCESSORY_REGISTER_HID) {
++			value = acc_register_hid(dev, w_value, w_index);
++		} else if (b_request == ACCESSORY_UNREGISTER_HID) {
++			value = acc_unregister_hid(dev, w_value);
++		} else if (b_request == ACCESSORY_SET_HID_REPORT_DESC) {
++			spin_lock_irqsave(&dev->lock, flags);
++			hid = acc_hid_get(&dev->new_hid_list, w_value);
++			spin_unlock_irqrestore(&dev->lock, flags);
++			if (!hid) {
++				value = -EINVAL;
++				goto err;
++			}
++			offset = w_index;
++			if (offset != hid->report_desc_offset
++				|| offset + w_length > hid->report_desc_len) {
++				value = -EINVAL;
++				goto err;
++			}
++			cdev->req->context = hid;
++			cdev->req->complete = acc_complete_set_hid_report_desc;
++			value = w_length;
++		} else if (b_request == ACCESSORY_SEND_HID_EVENT) {
++			spin_lock_irqsave(&dev->lock, flags);
++			hid = acc_hid_get(&dev->hid_list, w_value);
++			spin_unlock_irqrestore(&dev->lock, flags);
++			if (!hid) {
++				value = -EINVAL;
++				goto err;
++			}
++			cdev->req->context = hid;
++			cdev->req->complete = acc_complete_send_hid_event;
++			value = w_length;
++		}
++	} else if (b_requestType == (USB_DIR_IN | USB_TYPE_VENDOR)) {
++		if (b_request == ACCESSORY_GET_PROTOCOL) {
++			*((u16 *)cdev->req->buf) = PROTOCOL_VERSION;
++			value = sizeof(u16);
++
++			/* clear any string left over from a previous session */
++			memset(dev->manufacturer, 0, sizeof(dev->manufacturer));
++			memset(dev->model, 0, sizeof(dev->model));
++			memset(dev->description, 0, sizeof(dev->description));
++			memset(dev->version, 0, sizeof(dev->version));
++			memset(dev->uri, 0, sizeof(dev->uri));
++			memset(dev->serial, 0, sizeof(dev->serial));
++			dev->start_requested = 0;
++			dev->audio_mode = 0;
++		}
++	}
++
++	if (value >= 0) {
++		cdev->req->zero = 0;
++		cdev->req->length = value;
++		value = usb_ep_queue(cdev->gadget->ep0, cdev->req, GFP_ATOMIC);
++		if (value < 0)
++			ERROR(cdev, "%s setup response queue error\n",
++				__func__);
++	}
++
++err:
++	if (value == -EOPNOTSUPP)
++		VDBG(cdev,
++			"unknown class-specific control req "
++			"%02x.%02x v%04x i%04x l%u\n",
++			ctrl->bRequestType, ctrl->bRequest,
++			w_value, w_index, w_length);
++	return value;
++}
++EXPORT_SYMBOL_GPL(acc_ctrlrequest);
++
++static int
++__acc_function_bind(struct usb_configuration *c,
++			struct usb_function *f, bool configfs)
++{
++	struct usb_composite_dev *cdev = c->cdev;
++	struct acc_dev	*dev = func_to_dev(f);
++	int			id;
++	int			ret;
++
++	DBG(cdev, "acc_function_bind dev: %p\n", dev);
++
++	if (configfs) {
++		if (acc_string_defs[INTERFACE_STRING_INDEX].id == 0) {
++			ret = usb_string_id(c->cdev);
++			if (ret < 0)
++				return ret;
++			acc_string_defs[INTERFACE_STRING_INDEX].id = ret;
++			acc_interface_desc.iInterface = ret;
++		}
++		dev->cdev = c->cdev;
++	}
++	ret = hid_register_driver(&acc_hid_driver);
++	if (ret)
++		return ret;
++
++	dev->start_requested = 0;
++
++	/* allocate interface ID(s) */
++	id = usb_interface_id(c, f);
++	if (id < 0)
++		return id;
++	acc_interface_desc.bInterfaceNumber = id;
++
++	/* allocate endpoints */
++	ret = create_bulk_endpoints(dev, &acc_fullspeed_in_desc,
++			&acc_fullspeed_out_desc);
++	if (ret)
++		return ret;
++
++	/* support high speed hardware */
++	if (gadget_is_dualspeed(c->cdev->gadget)) {
++		acc_highspeed_in_desc.bEndpointAddress =
++			acc_fullspeed_in_desc.bEndpointAddress;
++		acc_highspeed_out_desc.bEndpointAddress =
++			acc_fullspeed_out_desc.bEndpointAddress;
++	}
++
++	DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n",
++			gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
++			f->name, dev->ep_in->name, dev->ep_out->name);
++	return 0;
++}
++
++static int
++acc_function_bind(struct usb_configuration *c, struct usb_function *f) {
++	return __acc_function_bind(c, f, false);
++}
++
++static int
++acc_function_bind_configfs(struct usb_configuration *c,
++			struct usb_function *f) {
++	return __acc_function_bind(c, f, true);
++}
++
++static void
++kill_all_hid_devices(struct acc_dev *dev)
++{
++	struct acc_hid_dev *hid;
++	struct list_head *entry, *temp;
++	unsigned long flags;
++
++	/* do nothing if usb accessory device doesn't exist */
++	if (!dev)
++		return;
++
++	spin_lock_irqsave(&dev->lock, flags);
++	list_for_each_safe(entry, temp, &dev->hid_list) {
++		hid = list_entry(entry, struct acc_hid_dev, list);
++		list_del(&hid->list);
++		list_add(&hid->list, &dev->dead_hid_list);
++	}
++	list_for_each_safe(entry, temp, &dev->new_hid_list) {
++		hid = list_entry(entry, struct acc_hid_dev, list);
++		list_del(&hid->list);
++		list_add(&hid->list, &dev->dead_hid_list);
++	}
++	spin_unlock_irqrestore(&dev->lock, flags);
++
++	schedule_work(&dev->hid_work);
++}
++
++static void
++acc_hid_unbind(struct acc_dev *dev)
++{
++	hid_unregister_driver(&acc_hid_driver);
++	kill_all_hid_devices(dev);
++}
++
++static void
++acc_function_unbind(struct usb_configuration *c, struct usb_function *f)
++{
++	struct acc_dev	*dev = func_to_dev(f);
++	struct usb_request *req;
++	int i;
++
++	while ((req = req_get(dev, &dev->tx_idle)))
++		acc_request_free(req, dev->ep_in);
++	for (i = 0; i < RX_REQ_MAX; i++)
++		acc_request_free(dev->rx_req[i], dev->ep_out);
++
++	acc_hid_unbind(dev);
++}
++
++static void acc_start_work(struct work_struct *data)
++{
++	char *envp[2] = { "ACCESSORY=START", NULL };
++	kobject_uevent_env(&acc_device.this_device->kobj, KOBJ_CHANGE, envp);
++}
++
++static int acc_hid_init(struct acc_hid_dev *hdev)
++{
++	struct hid_device *hid;
++	int ret;
++
++	hid = hid_allocate_device();
++	if (IS_ERR(hid))
++		return PTR_ERR(hid);
++
++	hid->ll_driver = &acc_hid_ll_driver;
++	hid->dev.parent = acc_device.this_device;
++
++	hid->bus = BUS_USB;
++	hid->vendor = HID_ANY_ID;
++	hid->product = HID_ANY_ID;
++	hid->driver_data = hdev;
++	ret = hid_add_device(hid);
++	if (ret) {
++		pr_err("can't add hid device: %d\n", ret);
++		hid_destroy_device(hid);
++		return ret;
++	}
++
++	hdev->hid = hid;
++	return 0;
++}
++
++static void acc_hid_delete(struct acc_hid_dev *hid)
++{
++	kfree(hid->report_desc);
++	kfree(hid);
++}
++
++static void acc_hid_work(struct work_struct *data)
++{
++	struct acc_dev *dev = _acc_dev;
++	struct list_head	*entry, *temp;
++	struct acc_hid_dev *hid;
++	struct list_head	new_list, dead_list;
++	unsigned long flags;
++
++	INIT_LIST_HEAD(&new_list);
++
++	spin_lock_irqsave(&dev->lock, flags);
++
++	/* copy hids that are ready for initialization to new_list */
++	list_for_each_safe(entry, temp, &dev->new_hid_list) {
++		hid = list_entry(entry, struct acc_hid_dev, list);
++		if (hid->report_desc_offset == hid->report_desc_len)
++			list_move(&hid->list, &new_list);
++	}
++
++	if (list_empty(&dev->dead_hid_list)) {
++		INIT_LIST_HEAD(&dead_list);
++	} else {
++		/* move all of dev->dead_hid_list to dead_list */
++		dead_list.prev = dev->dead_hid_list.prev;
++		dead_list.next = dev->dead_hid_list.next;
++		dead_list.next->prev = &dead_list;
++		dead_list.prev->next = &dead_list;
++		INIT_LIST_HEAD(&dev->dead_hid_list);
++	}
++
++	spin_unlock_irqrestore(&dev->lock, flags);
++
++	/* register new HID devices */
++	list_for_each_safe(entry, temp, &new_list) {
++		hid = list_entry(entry, struct acc_hid_dev, list);
++		if (acc_hid_init(hid)) {
++			pr_err("can't add HID device %p\n", hid);
++			acc_hid_delete(hid);
++		} else {
++			spin_lock_irqsave(&dev->lock, flags);
++			list_move(&hid->list, &dev->hid_list);
++			spin_unlock_irqrestore(&dev->lock, flags);
++		}
++	}
++
++	/* remove dead HID devices */
++	list_for_each_safe(entry, temp, &dead_list) {
++		hid = list_entry(entry, struct acc_hid_dev, list);
++		list_del(&hid->list);
++		if (hid->hid)
++			hid_destroy_device(hid->hid);
++		acc_hid_delete(hid);
++	}
++}
++
++static int acc_function_set_alt(struct usb_function *f,
++		unsigned intf, unsigned alt)
++{
++	struct acc_dev	*dev = func_to_dev(f);
++	struct usb_composite_dev *cdev = f->config->cdev;
++	int ret;
++
++	DBG(cdev, "acc_function_set_alt intf: %d alt: %d\n", intf, alt);
++
++	ret = config_ep_by_speed(cdev->gadget, f, dev->ep_in);
++	if (ret)
++		return ret;
++
++	ret = usb_ep_enable(dev->ep_in);
++	if (ret)
++		return ret;
++
++	ret = config_ep_by_speed(cdev->gadget, f, dev->ep_out);
++	if (ret)
++		return ret;
++
++	ret = usb_ep_enable(dev->ep_out);
++	if (ret) {
++		usb_ep_disable(dev->ep_in);
++		return ret;
++	}
++
++	dev->online = 1;
++
++	/* readers may be blocked waiting for us to go online */
++	wake_up(&dev->read_wq);
++	return 0;
++}
++
++static void acc_function_disable(struct usb_function *f)
++{
++	struct acc_dev	*dev = func_to_dev(f);
++	struct usb_composite_dev	*cdev = dev->cdev;
++
++	DBG(cdev, "acc_function_disable\n");
++	acc_set_disconnected(dev);
++	usb_ep_disable(dev->ep_in);
++	usb_ep_disable(dev->ep_out);
++
++	/* readers may be blocked waiting for us to go online */
++	wake_up(&dev->read_wq);
++
++	VDBG(cdev, "%s disabled\n", dev->function.name);
++}
++
++static int __maybe_unused acc_bind_config(struct usb_configuration *c)
++{
++	struct acc_dev *dev = _acc_dev;
++	int ret;
++
++	printk(KERN_INFO "acc_bind_config\n");
++
++	/* allocate a string ID for our interface */
++	if (acc_string_defs[INTERFACE_STRING_INDEX].id == 0) {
++		ret = usb_string_id(c->cdev);
++		if (ret < 0)
++			return ret;
++		acc_string_defs[INTERFACE_STRING_INDEX].id = ret;
++		acc_interface_desc.iInterface = ret;
++	}
++
++	dev->cdev = c->cdev;
++	dev->function.name = "accessory";
++	dev->function.strings = acc_strings,
++	dev->function.fs_descriptors = fs_acc_descs;
++	dev->function.hs_descriptors = hs_acc_descs;
++	dev->function.bind = acc_function_bind;
++	dev->function.unbind = acc_function_unbind;
++	dev->function.set_alt = acc_function_set_alt;
++	dev->function.disable = acc_function_disable;
++
++	return usb_add_function(c, &dev->function);
++}
++
++static int acc_setup(void)
++{
++	struct acc_dev *dev;
++	int ret;
++
++	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
++	if (!dev)
++		return -ENOMEM;
++
++	spin_lock_init(&dev->lock);
++	init_waitqueue_head(&dev->read_wq);
++	init_waitqueue_head(&dev->write_wq);
++	atomic_set(&dev->open_excl, 0);
++	INIT_LIST_HEAD(&dev->tx_idle);
++	INIT_LIST_HEAD(&dev->hid_list);
++	INIT_LIST_HEAD(&dev->new_hid_list);
++	INIT_LIST_HEAD(&dev->dead_hid_list);
++	INIT_DELAYED_WORK(&dev->start_work, acc_start_work);
++	INIT_WORK(&dev->hid_work, acc_hid_work);
++
++	/* _acc_dev must be set before calling usb_gadget_register_driver */
++	_acc_dev = dev;
++
++	ret = misc_register(&acc_device);
++	if (ret)
++		goto err;
++
++	return 0;
++
++err:
++	kfree(dev);
++	pr_err("USB accessory gadget driver failed to initialize\n");
++	return ret;
++}
++
++void acc_disconnect(void)
++{
++	/* unregister all HID devices if USB is disconnected */
++	kill_all_hid_devices(_acc_dev);
++}
++EXPORT_SYMBOL_GPL(acc_disconnect);
++
++static void acc_cleanup(void)
++{
++	misc_deregister(&acc_device);
++	kfree(_acc_dev);
++	_acc_dev = NULL;
++}
++static struct acc_instance *to_acc_instance(struct config_item *item)
++{
++	return container_of(to_config_group(item), struct acc_instance,
++		func_inst.group);
++}
++
++static void acc_attr_release(struct config_item *item)
++{
++	struct acc_instance *fi_acc = to_acc_instance(item);
++
++	usb_put_function_instance(&fi_acc->func_inst);
++}
++
++static struct configfs_item_operations acc_item_ops = {
++	.release        = acc_attr_release,
++};
++
++static struct config_item_type acc_func_type = {
++	.ct_item_ops    = &acc_item_ops,
++	.ct_owner       = THIS_MODULE,
++};
++
++static struct acc_instance *to_fi_acc(struct usb_function_instance *fi)
++{
++	return container_of(fi, struct acc_instance, func_inst);
++}
++
++static int acc_set_inst_name(struct usb_function_instance *fi, const char *name)
++{
++	struct acc_instance *fi_acc;
++	char *ptr;
++	int name_len;
++
++	name_len = strlen(name) + 1;
++	if (name_len > MAX_INST_NAME_LEN)
++		return -ENAMETOOLONG;
++
++	ptr = kstrndup(name, name_len, GFP_KERNEL);
++	if (!ptr)
++		return -ENOMEM;
++
++	fi_acc = to_fi_acc(fi);
++	fi_acc->name = ptr;
++	return 0;
++}
++
++static void acc_free_inst(struct usb_function_instance *fi)
++{
++	struct acc_instance *fi_acc;
++
++	fi_acc = to_fi_acc(fi);
++	kfree(fi_acc->name);
++	acc_cleanup();
++}
++
++static struct usb_function_instance *acc_alloc_inst(void)
++{
++	struct acc_instance *fi_acc;
++	struct acc_dev *dev;
++	int err;
++
++	fi_acc = kzalloc(sizeof(*fi_acc), GFP_KERNEL);
++	if (!fi_acc)
++		return ERR_PTR(-ENOMEM);
++	fi_acc->func_inst.set_inst_name = acc_set_inst_name;
++	fi_acc->func_inst.free_func_inst = acc_free_inst;
++
++	err = acc_setup();
++	if (err) {
++		kfree(fi_acc);
++		pr_err("Error setting ACCESSORY\n");
++		return ERR_PTR(err);
++	}
++
++	config_group_init_type_name(&fi_acc->func_inst.group,
++					"", &acc_func_type);
++	dev = _acc_dev;
++	return  &fi_acc->func_inst;
++}
++
++static void acc_free(struct usb_function *f)
++{
++/*NO-OP: no function specific resource allocation in mtp_alloc*/
++}
++
++int acc_ctrlrequest_configfs(struct usb_function *f,
++			const struct usb_ctrlrequest *ctrl) {
++	if (f->config != NULL && f->config->cdev != NULL)
++		return acc_ctrlrequest(f->config->cdev, ctrl);
++	else
++		return -1;
++}
++
++static struct usb_function *acc_alloc(struct usb_function_instance *fi)
++{
++	struct acc_dev *dev = _acc_dev;
++
++	pr_info("acc_alloc\n");
++
++	dev->function.name = "accessory";
++	dev->function.strings = acc_strings,
++	dev->function.fs_descriptors = fs_acc_descs;
++	dev->function.hs_descriptors = hs_acc_descs;
++	dev->function.bind = acc_function_bind_configfs;
++	dev->function.unbind = acc_function_unbind;
++	dev->function.set_alt = acc_function_set_alt;
++	dev->function.disable = acc_function_disable;
++	dev->function.free_func = acc_free;
++	dev->function.setup = acc_ctrlrequest_configfs;
++
++	return &dev->function;
++}
++DECLARE_USB_FUNCTION_INIT(accessory, acc_alloc_inst, acc_alloc);
++MODULE_LICENSE("GPL");
+diff --git a/drivers/usb/gadget/function/f_audio_source.c b/drivers/usb/gadget/function/f_audio_source.c
+new file mode 100644
+index 0000000..39645be
+--- /dev/null
++++ b/drivers/usb/gadget/function/f_audio_source.c
+@@ -0,0 +1,1054 @@
++/*
++ * Gadget Function Driver for USB audio source device
++ *
++ * Copyright (C) 2012 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#include <linux/device.h>
++#include <linux/usb/audio.h>
++#include <linux/wait.h>
++#include <sound/core.h>
++#include <sound/initval.h>
++#include <sound/pcm.h>
++
++#include <linux/usb.h>
++#include <linux/usb_usual.h>
++#include <linux/usb/ch9.h>
++#include <linux/configfs.h>
++#include <linux/usb/composite.h>
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#define SAMPLE_RATE 44100
++#define FRAMES_PER_MSEC (SAMPLE_RATE / 1000)
++
++#define IN_EP_MAX_PACKET_SIZE 256
++
++/* Number of requests to allocate */
++#define IN_EP_REQ_COUNT 4
++
++#define AUDIO_AC_INTERFACE	0
++#define AUDIO_AS_INTERFACE	1
++#define AUDIO_NUM_INTERFACES	2
++#define MAX_INST_NAME_LEN     40
++
++/* B.3.1  Standard AC Interface Descriptor */
++static struct usb_interface_descriptor ac_interface_desc = {
++	.bLength =		USB_DT_INTERFACE_SIZE,
++	.bDescriptorType =	USB_DT_INTERFACE,
++	.bNumEndpoints =	0,
++	.bInterfaceClass =	USB_CLASS_AUDIO,
++	.bInterfaceSubClass =	USB_SUBCLASS_AUDIOCONTROL,
++};
++
++DECLARE_UAC_AC_HEADER_DESCRIPTOR(2);
++
++#define UAC_DT_AC_HEADER_LENGTH	UAC_DT_AC_HEADER_SIZE(AUDIO_NUM_INTERFACES)
++/* 1 input terminal, 1 output terminal and 1 feature unit */
++#define UAC_DT_TOTAL_LENGTH (UAC_DT_AC_HEADER_LENGTH \
++	+ UAC_DT_INPUT_TERMINAL_SIZE + UAC_DT_OUTPUT_TERMINAL_SIZE \
++	+ UAC_DT_FEATURE_UNIT_SIZE(0))
++/* B.3.2  Class-Specific AC Interface Descriptor */
++static struct uac1_ac_header_descriptor_2 ac_header_desc = {
++	.bLength =		UAC_DT_AC_HEADER_LENGTH,
++	.bDescriptorType =	USB_DT_CS_INTERFACE,
++	.bDescriptorSubtype =	UAC_HEADER,
++	.bcdADC =		__constant_cpu_to_le16(0x0100),
++	.wTotalLength =		__constant_cpu_to_le16(UAC_DT_TOTAL_LENGTH),
++	.bInCollection =	AUDIO_NUM_INTERFACES,
++	.baInterfaceNr = {
++		[0] =		AUDIO_AC_INTERFACE,
++		[1] =		AUDIO_AS_INTERFACE,
++	}
++};
++
++#define INPUT_TERMINAL_ID	1
++static struct uac_input_terminal_descriptor input_terminal_desc = {
++	.bLength =		UAC_DT_INPUT_TERMINAL_SIZE,
++	.bDescriptorType =	USB_DT_CS_INTERFACE,
++	.bDescriptorSubtype =	UAC_INPUT_TERMINAL,
++	.bTerminalID =		INPUT_TERMINAL_ID,
++	.wTerminalType =	UAC_INPUT_TERMINAL_MICROPHONE,
++	.bAssocTerminal =	0,
++	.wChannelConfig =	0x3,
++};
++
++DECLARE_UAC_FEATURE_UNIT_DESCRIPTOR(0);
++
++#define FEATURE_UNIT_ID		2
++static struct uac_feature_unit_descriptor_0 feature_unit_desc = {
++	.bLength		= UAC_DT_FEATURE_UNIT_SIZE(0),
++	.bDescriptorType	= USB_DT_CS_INTERFACE,
++	.bDescriptorSubtype	= UAC_FEATURE_UNIT,
++	.bUnitID		= FEATURE_UNIT_ID,
++	.bSourceID		= INPUT_TERMINAL_ID,
++	.bControlSize		= 2,
++};
++
++#define OUTPUT_TERMINAL_ID	3
++static struct uac1_output_terminal_descriptor output_terminal_desc = {
++	.bLength		= UAC_DT_OUTPUT_TERMINAL_SIZE,
++	.bDescriptorType	= USB_DT_CS_INTERFACE,
++	.bDescriptorSubtype	= UAC_OUTPUT_TERMINAL,
++	.bTerminalID		= OUTPUT_TERMINAL_ID,
++	.wTerminalType		= UAC_TERMINAL_STREAMING,
++	.bAssocTerminal		= FEATURE_UNIT_ID,
++	.bSourceID		= FEATURE_UNIT_ID,
++};
++
++/* B.4.1  Standard AS Interface Descriptor */
++static struct usb_interface_descriptor as_interface_alt_0_desc = {
++	.bLength =		USB_DT_INTERFACE_SIZE,
++	.bDescriptorType =	USB_DT_INTERFACE,
++	.bAlternateSetting =	0,
++	.bNumEndpoints =	0,
++	.bInterfaceClass =	USB_CLASS_AUDIO,
++	.bInterfaceSubClass =	USB_SUBCLASS_AUDIOSTREAMING,
++};
++
++static struct usb_interface_descriptor as_interface_alt_1_desc = {
++	.bLength =		USB_DT_INTERFACE_SIZE,
++	.bDescriptorType =	USB_DT_INTERFACE,
++	.bAlternateSetting =	1,
++	.bNumEndpoints =	1,
++	.bInterfaceClass =	USB_CLASS_AUDIO,
++	.bInterfaceSubClass =	USB_SUBCLASS_AUDIOSTREAMING,
++};
++
++/* B.4.2  Class-Specific AS Interface Descriptor */
++static struct uac1_as_header_descriptor as_header_desc = {
++	.bLength =		UAC_DT_AS_HEADER_SIZE,
++	.bDescriptorType =	USB_DT_CS_INTERFACE,
++	.bDescriptorSubtype =	UAC_AS_GENERAL,
++	.bTerminalLink =	INPUT_TERMINAL_ID,
++	.bDelay =		1,
++	.wFormatTag =		UAC_FORMAT_TYPE_I_PCM,
++};
++
++DECLARE_UAC_FORMAT_TYPE_I_DISCRETE_DESC(1);
++
++static struct uac_format_type_i_discrete_descriptor_1 as_type_i_desc = {
++	.bLength =		UAC_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(1),
++	.bDescriptorType =	USB_DT_CS_INTERFACE,
++	.bDescriptorSubtype =	UAC_FORMAT_TYPE,
++	.bFormatType =		UAC_FORMAT_TYPE_I,
++	.bSubframeSize =	2,
++	.bBitResolution =	16,
++	.bSamFreqType =		1,
++};
++
++/* Standard ISO IN Endpoint Descriptor for highspeed */
++static struct usb_endpoint_descriptor hs_as_in_ep_desc  = {
++	.bLength =		USB_DT_ENDPOINT_AUDIO_SIZE,
++	.bDescriptorType =	USB_DT_ENDPOINT,
++	.bEndpointAddress =	USB_DIR_IN,
++	.bmAttributes =		USB_ENDPOINT_SYNC_SYNC
++				| USB_ENDPOINT_XFER_ISOC,
++	.wMaxPacketSize =	__constant_cpu_to_le16(IN_EP_MAX_PACKET_SIZE),
++	.bInterval =		4, /* poll 1 per millisecond */
++};
++
++/* Standard ISO IN Endpoint Descriptor for highspeed */
++static struct usb_endpoint_descriptor fs_as_in_ep_desc  = {
++	.bLength =		USB_DT_ENDPOINT_AUDIO_SIZE,
++	.bDescriptorType =	USB_DT_ENDPOINT,
++	.bEndpointAddress =	USB_DIR_IN,
++	.bmAttributes =		USB_ENDPOINT_SYNC_SYNC
++				| USB_ENDPOINT_XFER_ISOC,
++	.wMaxPacketSize =	__constant_cpu_to_le16(IN_EP_MAX_PACKET_SIZE),
++	.bInterval =		1, /* poll 1 per millisecond */
++};
++
++/* Class-specific AS ISO OUT Endpoint Descriptor */
++static struct uac_iso_endpoint_descriptor as_iso_in_desc = {
++	.bLength =		UAC_ISO_ENDPOINT_DESC_SIZE,
++	.bDescriptorType =	USB_DT_CS_ENDPOINT,
++	.bDescriptorSubtype =	UAC_EP_GENERAL,
++	.bmAttributes =		1,
++	.bLockDelayUnits =	1,
++	.wLockDelay =		__constant_cpu_to_le16(1),
++};
++
++static struct usb_descriptor_header *hs_audio_desc[] = {
++	(struct usb_descriptor_header *)&ac_interface_desc,
++	(struct usb_descriptor_header *)&ac_header_desc,
++
++	(struct usb_descriptor_header *)&input_terminal_desc,
++	(struct usb_descriptor_header *)&output_terminal_desc,
++	(struct usb_descriptor_header *)&feature_unit_desc,
++
++	(struct usb_descriptor_header *)&as_interface_alt_0_desc,
++	(struct usb_descriptor_header *)&as_interface_alt_1_desc,
++	(struct usb_descriptor_header *)&as_header_desc,
++
++	(struct usb_descriptor_header *)&as_type_i_desc,
++
++	(struct usb_descriptor_header *)&hs_as_in_ep_desc,
++	(struct usb_descriptor_header *)&as_iso_in_desc,
++	NULL,
++};
++
++static struct usb_descriptor_header *fs_audio_desc[] = {
++	(struct usb_descriptor_header *)&ac_interface_desc,
++	(struct usb_descriptor_header *)&ac_header_desc,
++
++	(struct usb_descriptor_header *)&input_terminal_desc,
++	(struct usb_descriptor_header *)&output_terminal_desc,
++	(struct usb_descriptor_header *)&feature_unit_desc,
++
++	(struct usb_descriptor_header *)&as_interface_alt_0_desc,
++	(struct usb_descriptor_header *)&as_interface_alt_1_desc,
++	(struct usb_descriptor_header *)&as_header_desc,
++
++	(struct usb_descriptor_header *)&as_type_i_desc,
++
++	(struct usb_descriptor_header *)&fs_as_in_ep_desc,
++	(struct usb_descriptor_header *)&as_iso_in_desc,
++	NULL,
++};
++
++static struct snd_pcm_hardware audio_hw_info = {
++	.info =			SNDRV_PCM_INFO_MMAP |
++				SNDRV_PCM_INFO_MMAP_VALID |
++				SNDRV_PCM_INFO_BATCH |
++				SNDRV_PCM_INFO_INTERLEAVED |
++				SNDRV_PCM_INFO_BLOCK_TRANSFER,
++
++	.formats		= SNDRV_PCM_FMTBIT_S16_LE,
++	.channels_min		= 2,
++	.channels_max		= 2,
++	.rate_min		= SAMPLE_RATE,
++	.rate_max		= SAMPLE_RATE,
++
++	.buffer_bytes_max =	1024 * 1024,
++	.period_bytes_min =	64,
++	.period_bytes_max =	512 * 1024,
++	.periods_min =		2,
++	.periods_max =		1024,
++};
++
++/*-------------------------------------------------------------------------*/
++
++struct audio_source_config {
++	int	card;
++	int	device;
++};
++
++struct audio_dev {
++	struct usb_function		func;
++	struct snd_card			*card;
++	struct snd_pcm			*pcm;
++	struct snd_pcm_substream *substream;
++
++	struct list_head		idle_reqs;
++	struct usb_ep			*in_ep;
++
++	spinlock_t			lock;
++
++	/* beginning, end and current position in our buffer */
++	void				*buffer_start;
++	void				*buffer_end;
++	void				*buffer_pos;
++
++	/* byte size of a "period" */
++	unsigned int			period;
++	/* bytes sent since last call to snd_pcm_period_elapsed */
++	unsigned int			period_offset;
++	/* time we started playing */
++	ktime_t				start_time;
++	/* number of frames sent since start_time */
++	s64				frames_sent;
++	struct audio_source_config	*config;
++};
++
++static inline struct audio_dev *func_to_audio(struct usb_function *f)
++{
++	return container_of(f, struct audio_dev, func);
++}
++
++/*-------------------------------------------------------------------------*/
++
++struct audio_source_instance {
++	struct usb_function_instance func_inst;
++	const char *name;
++	struct audio_source_config *config;
++	struct device *audio_device;
++};
++
++static void audio_source_attr_release(struct config_item *item);
++
++static struct configfs_item_operations audio_source_item_ops = {
++	.release        = audio_source_attr_release,
++};
++
++static struct config_item_type audio_source_func_type = {
++	.ct_item_ops    = &audio_source_item_ops,
++	.ct_owner       = THIS_MODULE,
++};
++
++static ssize_t audio_source_pcm_show(struct device *dev,
++		struct device_attribute *attr, char *buf);
++
++static DEVICE_ATTR(pcm, S_IRUGO, audio_source_pcm_show, NULL);
++
++static struct device_attribute *audio_source_function_attributes[] = {
++	&dev_attr_pcm,
++	NULL
++};
++
++/*--------------------------------------------------------------------------*/
++
++static struct usb_request *audio_request_new(struct usb_ep *ep, int buffer_size)
++{
++	struct usb_request *req = usb_ep_alloc_request(ep, GFP_KERNEL);
++	if (!req)
++		return NULL;
++
++	req->buf = kmalloc(buffer_size, GFP_KERNEL);
++	if (!req->buf) {
++		usb_ep_free_request(ep, req);
++		return NULL;
++	}
++	req->length = buffer_size;
++	return req;
++}
++
++static void audio_request_free(struct usb_request *req, struct usb_ep *ep)
++{
++	if (req) {
++		kfree(req->buf);
++		usb_ep_free_request(ep, req);
++	}
++}
++
++static void audio_req_put(struct audio_dev *audio, struct usb_request *req)
++{
++	unsigned long flags;
++
++	spin_lock_irqsave(&audio->lock, flags);
++	list_add_tail(&req->list, &audio->idle_reqs);
++	spin_unlock_irqrestore(&audio->lock, flags);
++}
++
++static struct usb_request *audio_req_get(struct audio_dev *audio)
++{
++	unsigned long flags;
++	struct usb_request *req;
++
++	spin_lock_irqsave(&audio->lock, flags);
++	if (list_empty(&audio->idle_reqs)) {
++		req = 0;
++	} else {
++		req = list_first_entry(&audio->idle_reqs, struct usb_request,
++				list);
++		list_del(&req->list);
++	}
++	spin_unlock_irqrestore(&audio->lock, flags);
++	return req;
++}
++
++/* send the appropriate number of packets to match our bitrate */
++static void audio_send(struct audio_dev *audio)
++{
++	struct snd_pcm_runtime *runtime;
++	struct usb_request *req;
++	int length, length1, length2, ret;
++	s64 msecs;
++	s64 frames;
++	ktime_t now;
++
++	/* audio->substream will be null if we have been closed */
++	if (!audio->substream)
++		return;
++	/* audio->buffer_pos will be null if we have been stopped */
++	if (!audio->buffer_pos)
++		return;
++
++	runtime = audio->substream->runtime;
++
++	/* compute number of frames to send */
++	now = ktime_get();
++	msecs = ktime_to_ns(now) - ktime_to_ns(audio->start_time);
++	do_div(msecs, 1000000);
++	frames = msecs * SAMPLE_RATE;
++	do_div(frames, 1000);
++
++	/* Readjust our frames_sent if we fall too far behind.
++	 * If we get too far behind it is better to drop some frames than
++	 * to keep sending data too fast in an attempt to catch up.
++	 */
++	if (frames - audio->frames_sent > 10 * FRAMES_PER_MSEC)
++		audio->frames_sent = frames - FRAMES_PER_MSEC;
++
++	frames -= audio->frames_sent;
++
++	/* We need to send something to keep the pipeline going */
++	if (frames <= 0)
++		frames = FRAMES_PER_MSEC;
++
++	while (frames > 0) {
++		req = audio_req_get(audio);
++		if (!req)
++			break;
++
++		length = frames_to_bytes(runtime, frames);
++		if (length > IN_EP_MAX_PACKET_SIZE)
++			length = IN_EP_MAX_PACKET_SIZE;
++
++		if (audio->buffer_pos + length > audio->buffer_end)
++			length1 = audio->buffer_end - audio->buffer_pos;
++		else
++			length1 = length;
++		memcpy(req->buf, audio->buffer_pos, length1);
++		if (length1 < length) {
++			/* Wrap around and copy remaining length
++			 * at beginning of buffer.
++			 */
++			length2 = length - length1;
++			memcpy(req->buf + length1, audio->buffer_start,
++					length2);
++			audio->buffer_pos = audio->buffer_start + length2;
++		} else {
++			audio->buffer_pos += length1;
++			if (audio->buffer_pos >= audio->buffer_end)
++				audio->buffer_pos = audio->buffer_start;
++		}
++
++		req->length = length;
++		ret = usb_ep_queue(audio->in_ep, req, GFP_ATOMIC);
++		if (ret < 0) {
++			pr_err("usb_ep_queue failed ret: %d\n", ret);
++			audio_req_put(audio, req);
++			break;
++		}
++
++		frames -= bytes_to_frames(runtime, length);
++		audio->frames_sent += bytes_to_frames(runtime, length);
++	}
++}
++
++static void audio_control_complete(struct usb_ep *ep, struct usb_request *req)
++{
++	/* nothing to do here */
++}
++
++static void audio_data_complete(struct usb_ep *ep, struct usb_request *req)
++{
++	struct audio_dev *audio = req->context;
++
++	pr_debug("audio_data_complete req->status %d req->actual %d\n",
++		req->status, req->actual);
++
++	audio_req_put(audio, req);
++
++	if (!audio->buffer_start || req->status)
++		return;
++
++	audio->period_offset += req->actual;
++	if (audio->period_offset >= audio->period) {
++		snd_pcm_period_elapsed(audio->substream);
++		audio->period_offset = 0;
++	}
++	audio_send(audio);
++}
++
++static int audio_set_endpoint_req(struct usb_function *f,
++		const struct usb_ctrlrequest *ctrl)
++{
++	int value = -EOPNOTSUPP;
++	u16 ep = le16_to_cpu(ctrl->wIndex);
++	u16 len = le16_to_cpu(ctrl->wLength);
++	u16 w_value = le16_to_cpu(ctrl->wValue);
++
++	pr_debug("bRequest 0x%x, w_value 0x%04x, len %d, endpoint %d\n",
++			ctrl->bRequest, w_value, len, ep);
++
++	switch (ctrl->bRequest) {
++	case UAC_SET_CUR:
++	case UAC_SET_MIN:
++	case UAC_SET_MAX:
++	case UAC_SET_RES:
++		value = len;
++		break;
++	default:
++		break;
++	}
++
++	return value;
++}
++
++static int audio_get_endpoint_req(struct usb_function *f,
++		const struct usb_ctrlrequest *ctrl)
++{
++	struct usb_composite_dev *cdev = f->config->cdev;
++	int value = -EOPNOTSUPP;
++	u8 ep = ((le16_to_cpu(ctrl->wIndex) >> 8) & 0xFF);
++	u16 len = le16_to_cpu(ctrl->wLength);
++	u16 w_value = le16_to_cpu(ctrl->wValue);
++	u8 *buf = cdev->req->buf;
++
++	pr_debug("bRequest 0x%x, w_value 0x%04x, len %d, endpoint %d\n",
++			ctrl->bRequest, w_value, len, ep);
++
++	if (w_value == UAC_EP_CS_ATTR_SAMPLE_RATE << 8) {
++		switch (ctrl->bRequest) {
++		case UAC_GET_CUR:
++		case UAC_GET_MIN:
++		case UAC_GET_MAX:
++		case UAC_GET_RES:
++			/* return our sample rate */
++			buf[0] = (u8)SAMPLE_RATE;
++			buf[1] = (u8)(SAMPLE_RATE >> 8);
++			buf[2] = (u8)(SAMPLE_RATE >> 16);
++			value = 3;
++			break;
++		default:
++			break;
++		}
++	}
++
++	return value;
++}
++
++static int
++audio_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
++{
++	struct usb_composite_dev *cdev = f->config->cdev;
++	struct usb_request *req = cdev->req;
++	int value = -EOPNOTSUPP;
++	u16 w_index = le16_to_cpu(ctrl->wIndex);
++	u16 w_value = le16_to_cpu(ctrl->wValue);
++	u16 w_length = le16_to_cpu(ctrl->wLength);
++
++	/* composite driver infrastructure handles everything; interface
++	 * activation uses set_alt().
++	 */
++	switch (ctrl->bRequestType) {
++	case USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_ENDPOINT:
++		value = audio_set_endpoint_req(f, ctrl);
++		break;
++
++	case USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT:
++		value = audio_get_endpoint_req(f, ctrl);
++		break;
++	}
++
++	/* respond with data transfer or status phase? */
++	if (value >= 0) {
++		pr_debug("audio req%02x.%02x v%04x i%04x l%d\n",
++			ctrl->bRequestType, ctrl->bRequest,
++			w_value, w_index, w_length);
++		req->zero = 0;
++		req->length = value;
++		req->complete = audio_control_complete;
++		value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
++		if (value < 0)
++			pr_err("audio response on err %d\n", value);
++	}
++
++	/* device either stalls (value < 0) or reports success */
++	return value;
++}
++
++static int audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
++{
++	struct audio_dev *audio = func_to_audio(f);
++	struct usb_composite_dev *cdev = f->config->cdev;
++	int ret;
++
++	pr_debug("audio_set_alt intf %d, alt %d\n", intf, alt);
++
++	ret = config_ep_by_speed(cdev->gadget, f, audio->in_ep);
++	if (ret)
++		return ret;
++
++	usb_ep_enable(audio->in_ep);
++	return 0;
++}
++
++static void audio_disable(struct usb_function *f)
++{
++	struct audio_dev	*audio = func_to_audio(f);
++
++	pr_debug("audio_disable\n");
++	usb_ep_disable(audio->in_ep);
++}
++
++/*-------------------------------------------------------------------------*/
++
++static void audio_build_desc(struct audio_dev *audio)
++{
++	u8 *sam_freq;
++	int rate;
++
++	/* Set channel numbers */
++	input_terminal_desc.bNrChannels = 2;
++	as_type_i_desc.bNrChannels = 2;
++
++	/* Set sample rates */
++	rate = SAMPLE_RATE;
++	sam_freq = as_type_i_desc.tSamFreq[0];
++	memcpy(sam_freq, &rate, 3);
++}
++
++
++static int snd_card_setup(struct usb_configuration *c,
++	struct audio_source_config *config);
++static struct audio_source_instance *to_fi_audio_source(
++	const struct usb_function_instance *fi);
++
++
++/* audio function driver setup/binding */
++static int
++audio_bind(struct usb_configuration *c, struct usb_function *f)
++{
++	struct usb_composite_dev *cdev = c->cdev;
++	struct audio_dev *audio = func_to_audio(f);
++	int status;
++	struct usb_ep *ep;
++	struct usb_request *req;
++	int i;
++	int err;
++
++	if (IS_ENABLED(CONFIG_USB_CONFIGFS)) {
++		struct audio_source_instance *fi_audio =
++				to_fi_audio_source(f->fi);
++		struct audio_source_config *config =
++				fi_audio->config;
++
++		err = snd_card_setup(c, config);
++		if (err)
++			return err;
++	}
++
++	audio_build_desc(audio);
++
++	/* allocate instance-specific interface IDs, and patch descriptors */
++	status = usb_interface_id(c, f);
++	if (status < 0)
++		goto fail;
++	ac_interface_desc.bInterfaceNumber = status;
++
++	/* AUDIO_AC_INTERFACE */
++	ac_header_desc.baInterfaceNr[0] = status;
++
++	status = usb_interface_id(c, f);
++	if (status < 0)
++		goto fail;
++	as_interface_alt_0_desc.bInterfaceNumber = status;
++	as_interface_alt_1_desc.bInterfaceNumber = status;
++
++	/* AUDIO_AS_INTERFACE */
++	ac_header_desc.baInterfaceNr[1] = status;
++
++	status = -ENODEV;
++
++	/* allocate our endpoint */
++	ep = usb_ep_autoconfig(cdev->gadget, &fs_as_in_ep_desc);
++	if (!ep)
++		goto fail;
++	audio->in_ep = ep;
++	ep->driver_data = audio; /* claim */
++
++	if (gadget_is_dualspeed(c->cdev->gadget))
++		hs_as_in_ep_desc.bEndpointAddress =
++			fs_as_in_ep_desc.bEndpointAddress;
++
++	f->fs_descriptors = fs_audio_desc;
++	f->hs_descriptors = hs_audio_desc;
++
++	for (i = 0, status = 0; i < IN_EP_REQ_COUNT && status == 0; i++) {
++		req = audio_request_new(ep, IN_EP_MAX_PACKET_SIZE);
++		if (req) {
++			req->context = audio;
++			req->complete = audio_data_complete;
++			audio_req_put(audio, req);
++		} else
++			status = -ENOMEM;
++	}
++
++fail:
++	return status;
++}
++
++static void
++audio_unbind(struct usb_configuration *c, struct usb_function *f)
++{
++	struct audio_dev *audio = func_to_audio(f);
++	struct usb_request *req;
++
++	while ((req = audio_req_get(audio)))
++		audio_request_free(req, audio->in_ep);
++
++	snd_card_free_when_closed(audio->card);
++	audio->card = NULL;
++	audio->pcm = NULL;
++	audio->substream = NULL;
++	audio->in_ep = NULL;
++
++	if (IS_ENABLED(CONFIG_USB_CONFIGFS)) {
++		struct audio_source_instance *fi_audio =
++				to_fi_audio_source(f->fi);
++		struct audio_source_config *config =
++				fi_audio->config;
++
++		config->card = -1;
++		config->device = -1;
++	}
++}
++
++static void audio_pcm_playback_start(struct audio_dev *audio)
++{
++	audio->start_time = ktime_get();
++	audio->frames_sent = 0;
++	audio_send(audio);
++}
++
++static void audio_pcm_playback_stop(struct audio_dev *audio)
++{
++	unsigned long flags;
++
++	spin_lock_irqsave(&audio->lock, flags);
++	audio->buffer_start = 0;
++	audio->buffer_end = 0;
++	audio->buffer_pos = 0;
++	spin_unlock_irqrestore(&audio->lock, flags);
++}
++
++static int audio_pcm_open(struct snd_pcm_substream *substream)
++{
++	struct snd_pcm_runtime *runtime = substream->runtime;
++	struct audio_dev *audio = substream->private_data;
++
++	runtime->private_data = audio;
++	runtime->hw = audio_hw_info;
++	snd_pcm_limit_hw_rates(runtime);
++	runtime->hw.channels_max = 2;
++
++	audio->substream = substream;
++	return 0;
++}
++
++static int audio_pcm_close(struct snd_pcm_substream *substream)
++{
++	struct audio_dev *audio = substream->private_data;
++	unsigned long flags;
++
++	spin_lock_irqsave(&audio->lock, flags);
++	audio->substream = NULL;
++	spin_unlock_irqrestore(&audio->lock, flags);
++
++	return 0;
++}
++
++static int audio_pcm_hw_params(struct snd_pcm_substream *substream,
++				struct snd_pcm_hw_params *params)
++{
++	unsigned int channels = params_channels(params);
++	unsigned int rate = params_rate(params);
++
++	if (rate != SAMPLE_RATE)
++		return -EINVAL;
++	if (channels != 2)
++		return -EINVAL;
++
++	return snd_pcm_lib_alloc_vmalloc_buffer(substream,
++		params_buffer_bytes(params));
++}
++
++static int audio_pcm_hw_free(struct snd_pcm_substream *substream)
++{
++	return snd_pcm_lib_free_vmalloc_buffer(substream);
++}
++
++static int audio_pcm_prepare(struct snd_pcm_substream *substream)
++{
++	struct snd_pcm_runtime *runtime = substream->runtime;
++	struct audio_dev *audio = runtime->private_data;
++
++	audio->period = snd_pcm_lib_period_bytes(substream);
++	audio->period_offset = 0;
++	audio->buffer_start = runtime->dma_area;
++	audio->buffer_end = audio->buffer_start
++		+ snd_pcm_lib_buffer_bytes(substream);
++	audio->buffer_pos = audio->buffer_start;
++
++	return 0;
++}
++
++static snd_pcm_uframes_t audio_pcm_pointer(struct snd_pcm_substream *substream)
++{
++	struct snd_pcm_runtime *runtime = substream->runtime;
++	struct audio_dev *audio = runtime->private_data;
++	ssize_t bytes = audio->buffer_pos - audio->buffer_start;
++
++	/* return offset of next frame to fill in our buffer */
++	return bytes_to_frames(runtime, bytes);
++}
++
++static int audio_pcm_playback_trigger(struct snd_pcm_substream *substream,
++					int cmd)
++{
++	struct audio_dev *audio = substream->runtime->private_data;
++	int ret = 0;
++
++	switch (cmd) {
++	case SNDRV_PCM_TRIGGER_START:
++	case SNDRV_PCM_TRIGGER_RESUME:
++		audio_pcm_playback_start(audio);
++		break;
++
++	case SNDRV_PCM_TRIGGER_STOP:
++	case SNDRV_PCM_TRIGGER_SUSPEND:
++		audio_pcm_playback_stop(audio);
++		break;
++
++	default:
++		ret = -EINVAL;
++	}
++
++	return ret;
++}
++
++static struct audio_dev _audio_dev = {
++	.func = {
++		.name = "audio_source",
++		.bind = audio_bind,
++		.unbind = audio_unbind,
++		.set_alt = audio_set_alt,
++		.setup = audio_setup,
++		.disable = audio_disable,
++	},
++	.lock = __SPIN_LOCK_UNLOCKED(_audio_dev.lock),
++	.idle_reqs = LIST_HEAD_INIT(_audio_dev.idle_reqs),
++};
++
++static struct snd_pcm_ops audio_playback_ops = {
++	.open		= audio_pcm_open,
++	.close		= audio_pcm_close,
++	.ioctl		= snd_pcm_lib_ioctl,
++	.hw_params	= audio_pcm_hw_params,
++	.hw_free	= audio_pcm_hw_free,
++	.prepare	= audio_pcm_prepare,
++	.trigger	= audio_pcm_playback_trigger,
++	.pointer	= audio_pcm_pointer,
++};
++
++int audio_source_bind_config(struct usb_configuration *c,
++		struct audio_source_config *config)
++{
++	struct audio_dev *audio;
++	int err;
++
++	config->card = -1;
++	config->device = -1;
++
++	audio = &_audio_dev;
++
++	err = snd_card_setup(c, config);
++	if (err)
++		return err;
++
++	err = usb_add_function(c, &audio->func);
++	if (err)
++		goto add_fail;
++
++	return 0;
++
++add_fail:
++	snd_card_free(audio->card);
++	return err;
++}
++
++static int snd_card_setup(struct usb_configuration *c,
++		struct audio_source_config *config)
++{
++	struct audio_dev *audio;
++	struct snd_card *card;
++	struct snd_pcm *pcm;
++	int err;
++
++	audio = &_audio_dev;
++
++	err = snd_card_new(&c->cdev->gadget->dev,
++			SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
++			THIS_MODULE, 0, &card);
++	if (err)
++		return err;
++
++	err = snd_pcm_new(card, "USB audio source", 0, 1, 0, &pcm);
++	if (err)
++		goto pcm_fail;
++
++	pcm->private_data = audio;
++	pcm->info_flags = 0;
++	audio->pcm = pcm;
++
++	strlcpy(pcm->name, "USB gadget audio", sizeof(pcm->name));
++
++	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &audio_playback_ops);
++	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
++				NULL, 0, 64 * 1024);
++
++	strlcpy(card->driver, "audio_source", sizeof(card->driver));
++	strlcpy(card->shortname, card->driver, sizeof(card->shortname));
++	strlcpy(card->longname, "USB accessory audio source",
++		sizeof(card->longname));
++
++	err = snd_card_register(card);
++	if (err)
++		goto register_fail;
++
++	config->card = pcm->card->number;
++	config->device = pcm->device;
++	audio->card = card;
++	return 0;
++
++register_fail:
++pcm_fail:
++	snd_card_free(audio->card);
++	return err;
++}
++
++static struct audio_source_instance *to_audio_source_instance(
++					struct config_item *item)
++{
++	return container_of(to_config_group(item), struct audio_source_instance,
++		func_inst.group);
++}
++
++static struct audio_source_instance *to_fi_audio_source(
++					const struct usb_function_instance *fi)
++{
++	return container_of(fi, struct audio_source_instance, func_inst);
++}
++
++static void audio_source_attr_release(struct config_item *item)
++{
++	struct audio_source_instance *fi_audio = to_audio_source_instance(item);
++
++	usb_put_function_instance(&fi_audio->func_inst);
++}
++
++static int audio_source_set_inst_name(struct usb_function_instance *fi,
++					const char *name)
++{
++	struct audio_source_instance *fi_audio;
++	char *ptr;
++	int name_len;
++
++	name_len = strlen(name) + 1;
++	if (name_len > MAX_INST_NAME_LEN)
++		return -ENAMETOOLONG;
++
++	ptr = kstrndup(name, name_len, GFP_KERNEL);
++	if (!ptr)
++		return -ENOMEM;
++
++	fi_audio = to_fi_audio_source(fi);
++	fi_audio->name = ptr;
++
++	return 0;
++}
++
++static void audio_source_free_inst(struct usb_function_instance *fi)
++{
++	struct audio_source_instance *fi_audio;
++
++	fi_audio = to_fi_audio_source(fi);
++	device_destroy(fi_audio->audio_device->class,
++			fi_audio->audio_device->devt);
++	kfree(fi_audio->name);
++	kfree(fi_audio->config);
++}
++
++static ssize_t audio_source_pcm_show(struct device *dev,
++		struct device_attribute *attr, char *buf)
++{
++	struct audio_source_instance *fi_audio = dev_get_drvdata(dev);
++	struct audio_source_config *config = fi_audio->config;
++
++	/* print PCM card and device numbers */
++	return sprintf(buf, "%d %d\n", config->card, config->device);
++}
++
++struct device *create_function_device(char *name);
++
++static struct usb_function_instance *audio_source_alloc_inst(void)
++{
++	struct audio_source_instance *fi_audio;
++	struct device_attribute **attrs;
++	struct device_attribute *attr;
++	struct device *dev;
++	void *err_ptr;
++	int err = 0;
++
++	fi_audio = kzalloc(sizeof(*fi_audio), GFP_KERNEL);
++	if (!fi_audio)
++		return ERR_PTR(-ENOMEM);
++
++	fi_audio->func_inst.set_inst_name = audio_source_set_inst_name;
++	fi_audio->func_inst.free_func_inst = audio_source_free_inst;
++
++	fi_audio->config = kzalloc(sizeof(struct audio_source_config),
++							GFP_KERNEL);
++	if (!fi_audio->config) {
++		err_ptr = ERR_PTR(-ENOMEM);
++		goto fail_audio;
++	}
++
++	config_group_init_type_name(&fi_audio->func_inst.group, "",
++						&audio_source_func_type);
++	dev = create_function_device("f_audio_source");
++
++	if (IS_ERR(dev)) {
++		err_ptr = dev;
++		goto fail_audio_config;
++	}
++
++	fi_audio->config->card = -1;
++	fi_audio->config->device = -1;
++	fi_audio->audio_device = dev;
++
++	attrs = audio_source_function_attributes;
++	if (attrs) {
++		while ((attr = *attrs++) && !err)
++			err = device_create_file(dev, attr);
++		if (err) {
++			err_ptr = ERR_PTR(-EINVAL);
++			goto fail_device;
++		}
++	}
++
++	dev_set_drvdata(dev, fi_audio);
++	_audio_dev.config = fi_audio->config;
++
++	return  &fi_audio->func_inst;
++
++fail_device:
++	device_destroy(dev->class, dev->devt);
++fail_audio_config:
++	kfree(fi_audio->config);
++fail_audio:
++	kfree(fi_audio);
++	return err_ptr;
++
++}
++
++static struct usb_function *audio_source_alloc(struct usb_function_instance *fi)
++{
++	return &_audio_dev.func;
++}
++
++DECLARE_USB_FUNCTION_INIT(audio_source, audio_source_alloc_inst,
++			audio_source_alloc);
++MODULE_LICENSE("GPL");
+diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
+index ab9b7ac..45207e2 100644
+--- a/drivers/usb/gadget/function/f_fs.c
++++ b/drivers/usb/gadget/function/f_fs.c
+@@ -86,12 +86,15 @@ ffs_setup_state_clear_cancelled(struct ffs_data *ffs)
+ 		cmpxchg(&ffs->setup_state, FFS_SETUP_CANCELLED, FFS_NO_SETUP);
+ }
+ 
++static void ffs_func_free(struct ffs_function *func);
+ 
+ static void ffs_func_eps_disable(struct ffs_function *func);
+ static int __must_check ffs_func_eps_enable(struct ffs_function *func);
+ 
+ static int ffs_func_bind(struct usb_configuration *,
+ 			 struct usb_function *);
++static void old_ffs_func_unbind(struct usb_configuration *,
++				struct usb_function *);
+ static int ffs_func_set_alt(struct usb_function *, unsigned, unsigned);
+ static void ffs_func_disable(struct usb_function *);
+ static int ffs_func_setup(struct usb_function *,
+@@ -1616,6 +1619,71 @@ static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count)
+ 	kfree(epfiles);
+ }
+ 
++static int functionfs_bind_config(struct usb_composite_dev *cdev,
++				   struct usb_configuration *c,
++				   struct ffs_data *ffs)
++{
++	struct ffs_function *func;
++	int ret;
++
++	ENTER();
++
++	func = kzalloc(sizeof *func, GFP_KERNEL);
++	if (unlikely(!func))
++		return -ENOMEM;
++
++	func->function.name    = "Function FS Gadget";
++	func->function.strings = ffs->stringtabs;
++
++	func->function.bind    = ffs_func_bind;
++	func->function.unbind  = old_ffs_func_unbind;
++	func->function.set_alt = ffs_func_set_alt;
++	func->function.disable = ffs_func_disable;
++	func->function.setup   = ffs_func_setup;
++	func->function.suspend = ffs_func_suspend;
++	func->function.resume  = ffs_func_resume;
++
++	func->conf   = c;
++	func->gadget = cdev->gadget;
++	func->ffs = ffs;
++	ffs_data_get(ffs);
++
++	ret = usb_add_function(c, &func->function);
++	if (unlikely(ret))
++		ffs_func_free(func);
++
++	return ret;
++}
++
++static void ffs_func_free(struct ffs_function *func)
++{
++	struct ffs_ep *ep         = func->eps;
++	unsigned count            = func->ffs->eps_count;
++	unsigned long flags;
++
++	ENTER();
++
++	/* cleanup after autoconfig */
++	spin_lock_irqsave(&func->ffs->eps_lock, flags);
++	do {
++		if (ep->ep && ep->req)
++			usb_ep_free_request(ep->ep, ep->req);
++		ep->req = NULL;
++		++ep;
++	} while (--count);
++	spin_unlock_irqrestore(&func->ffs->eps_lock, flags);
++
++	ffs_data_put(func->ffs);
++
++	kfree(func->eps);
++	/*
++	 * eps and interfaces_nums are allocated in the same chunk so
++	 * only one free is required.  Descriptors are also allocated
++	 * in the same chunk.
++	 */
++
++	kfree(func);
++}
+ 
+ static void ffs_func_eps_disable(struct ffs_function *func)
+ {
+@@ -2888,6 +2956,24 @@ static int ffs_func_bind(struct usb_configuration *c,
+ 
+ /* Other USB function hooks *************************************************/
+ 
++static void old_ffs_func_unbind(struct usb_configuration *c,
++				struct usb_function *f)
++{
++	struct ffs_function *func = ffs_func_from_usb(f);
++	struct ffs_data *ffs = func->ffs;
++
++	ENTER();
++
++	if (ffs->func == func) {
++		ffs_func_eps_disable(func);
++		ffs->func = NULL;
++	}
++
++	ffs_event_add(ffs, FUNCTIONFS_UNBIND);
++
++	ffs_func_free(func);
++}
++
+ static int ffs_func_set_alt(struct usb_function *f,
+ 			    unsigned interface, unsigned alt)
+ {
+diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c
+index 59ab62c..6f71a69 100644
+--- a/drivers/usb/gadget/function/f_hid.c
++++ b/drivers/usb/gadget/function/f_hid.c
+@@ -373,8 +373,9 @@ static int hidg_setup(struct usb_function *f,
+ 	value	= __le16_to_cpu(ctrl->wValue);
+ 	length	= __le16_to_cpu(ctrl->wLength);
+ 
+-	VDBG(cdev, "hid_setup crtl_request : bRequestType:0x%x bRequest:0x%x "
+-		"Value:0x%x\n", ctrl->bRequestType, ctrl->bRequest, value);
++	VDBG(cdev,
++	     "%s crtl_request : bRequestType:0x%x bRequest:0x%x Value:0x%x\n",
++	     __func__, ctrl->bRequestType, ctrl->bRequest, value);
+ 
+ 	switch ((ctrl->bRequestType << 8) | ctrl->bRequest) {
+ 	case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8
+diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c
+index 811929c..e4d3f6a 100644
+--- a/drivers/usb/gadget/function/f_mass_storage.c
++++ b/drivers/usb/gadget/function/f_mass_storage.c
+@@ -253,6 +253,7 @@ static struct usb_gadget_strings *fsg_strings_array[] = {
+ 
+ struct fsg_dev;
+ struct fsg_common;
++extern void hisi_switch_func(int otg);
+ 
+ /* Data shared by all the FSG instances. */
+ struct fsg_common {
+@@ -1935,6 +1936,9 @@ static int do_scsi_command(struct fsg_common *common)
+ 				      "READ CAPACITY");
+ 		if (reply == 0)
+ 			reply = do_read_capacity(common, bh);
++
++		hisi_switch_func(1);
++
+ 		break;
+ 
+ 	case READ_HEADER:
+@@ -1978,6 +1982,9 @@ static int do_scsi_command(struct fsg_common *common)
+ 				      "REQUEST SENSE");
+ 		if (reply == 0)
+ 			reply = do_request_sense(common, bh);
++
++		hisi_switch_func(1);
++
+ 		break;
+ 
+ 	case START_STOP:
+diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c
+index 807b31c..ee1bfc9 100644
+--- a/drivers/usb/gadget/function/f_midi.c
++++ b/drivers/usb/gadget/function/f_midi.c
+@@ -20,6 +20,7 @@
+  */
+ 
+ #include <linux/kernel.h>
++#include <linux/module.h>
+ #include <linux/slab.h>
+ #include <linux/device.h>
+ 
+@@ -33,6 +34,7 @@
+ #include <linux/usb/midi.h>
+ 
+ #include "u_f.h"
++#include "u_midi.h"
+ 
+ MODULE_AUTHOR("Ben Williamson");
+ MODULE_LICENSE("GPL v2");
+@@ -99,7 +101,7 @@ DECLARE_USB_MIDI_OUT_JACK_DESCRIPTOR(1);
+ DECLARE_USB_MS_ENDPOINT_DESCRIPTOR(16);
+ 
+ /* B.3.1  Standard AC Interface Descriptor */
+-static struct usb_interface_descriptor ac_interface_desc __initdata = {
++static struct usb_interface_descriptor ac_interface_desc = {
+ 	.bLength =		USB_DT_INTERFACE_SIZE,
+ 	.bDescriptorType =	USB_DT_INTERFACE,
+ 	/* .bInterfaceNumber =	DYNAMIC */
+@@ -110,7 +112,7 @@ static struct usb_interface_descriptor ac_interface_desc __initdata = {
+ };
+ 
+ /* B.3.2  Class-Specific AC Interface Descriptor */
+-static struct uac1_ac_header_descriptor_1 ac_header_desc __initdata = {
++static struct uac1_ac_header_descriptor_1 ac_header_desc = {
+ 	.bLength =		UAC_DT_AC_HEADER_SIZE(1),
+ 	.bDescriptorType =	USB_DT_CS_INTERFACE,
+ 	.bDescriptorSubtype =	USB_MS_HEADER,
+@@ -121,7 +123,7 @@ static struct uac1_ac_header_descriptor_1 ac_header_desc __initdata = {
+ };
+ 
+ /* B.4.1  Standard MS Interface Descriptor */
+-static struct usb_interface_descriptor ms_interface_desc __initdata = {
++static struct usb_interface_descriptor ms_interface_desc = {
+ 	.bLength =		USB_DT_INTERFACE_SIZE,
+ 	.bDescriptorType =	USB_DT_INTERFACE,
+ 	/* .bInterfaceNumber =	DYNAMIC */
+@@ -132,7 +134,7 @@ static struct usb_interface_descriptor ms_interface_desc __initdata = {
+ };
+ 
+ /* B.4.2  Class-Specific MS Interface Descriptor */
+-static struct usb_ms_header_descriptor ms_header_desc __initdata = {
++static struct usb_ms_header_descriptor ms_header_desc = {
+ 	.bLength =		USB_DT_MS_HEADER_SIZE,
+ 	.bDescriptorType =	USB_DT_CS_INTERFACE,
+ 	.bDescriptorSubtype =	USB_MS_HEADER,
+@@ -327,6 +329,10 @@ static int f_midi_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
+ 	unsigned i;
+ 	int err;
+ 
++	/* For Control Device interface we do nothing */
++	if (intf == 0)
++		return 0;
++
+ 	err = f_midi_start_ep(midi, f, midi->in_ep);
+ 	if (err)
+ 		return err;
+@@ -387,29 +393,6 @@ static void f_midi_disable(struct usb_function *f)
+ 	usb_ep_disable(midi->out_ep);
+ }
+ 
+-static void f_midi_unbind(struct usb_configuration *c, struct usb_function *f)
+-{
+-	struct usb_composite_dev *cdev = f->config->cdev;
+-	struct f_midi *midi = func_to_midi(f);
+-	struct snd_card *card;
+-
+-	DBG(cdev, "unbind\n");
+-
+-	/* just to be sure */
+-	f_midi_disable(f);
+-
+-	card = midi->card;
+-	midi->card = NULL;
+-	if (card)
+-		snd_card_free(card);
+-
+-	kfree(midi->id);
+-	midi->id = NULL;
+-
+-	usb_free_all_descriptors(f);
+-	kfree(midi);
+-}
+-
+ static int f_midi_snd_free(struct snd_device *device)
+ {
+ 	return 0;
+@@ -541,7 +524,7 @@ static void f_midi_transmit(struct f_midi *midi, struct usb_request *req)
+ 		req = midi_alloc_ep_req(ep, midi->buflen);
+ 
+ 	if (!req) {
+-		ERROR(midi, "gmidi_transmit: alloc_ep_request failed\n");
++		ERROR(midi, "%s: alloc_ep_request failed\n", __func__);
+ 		return;
+ 	}
+ 	req->length = 0;
+@@ -654,6 +637,14 @@ static struct snd_rawmidi_ops gmidi_out_ops = {
+ 	.trigger = f_midi_out_trigger
+ };
+ 
++static inline void f_midi_unregister_card(struct f_midi *midi)
++{
++	if (midi->card) {
++		snd_card_free(midi->card);
++		midi->card = NULL;
++	}
++}
++
+ /* register as a sound "card" */
+ static int f_midi_register_card(struct f_midi *midi)
+ {
+@@ -715,17 +706,13 @@ static int f_midi_register_card(struct f_midi *midi)
+ 	return 0;
+ 
+ fail:
+-	if (midi->card) {
+-		snd_card_free(midi->card);
+-		midi->card = NULL;
+-	}
++	f_midi_unregister_card(midi);
+ 	return err;
+ }
+ 
+ /* MIDI function driver setup/binding */
+ 
+-static int __init
+-f_midi_bind(struct usb_configuration *c, struct usb_function *f)
++static int f_midi_bind(struct usb_configuration *c, struct usb_function *f)
+ {
+ 	struct usb_descriptor_header **midi_function;
+ 	struct usb_midi_in_jack_descriptor jack_in_ext_desc[MAX_PORTS];
+@@ -734,15 +721,23 @@ f_midi_bind(struct usb_configuration *c, struct usb_function *f)
+ 	struct usb_midi_out_jack_descriptor_1 jack_out_emb_desc[MAX_PORTS];
+ 	struct usb_composite_dev *cdev = c->cdev;
+ 	struct f_midi *midi = func_to_midi(f);
++	struct usb_string *us;
+ 	int status, n, jack = 1, i = 0;
+ 
++	midi->gadget = cdev->gadget;
++	tasklet_init(&midi->tasklet, f_midi_in_tasklet, (unsigned long) midi);
++	status = f_midi_register_card(midi);
++	if (status < 0)
++		goto fail_register;
++
+ 	/* maybe allocate device-global string ID */
+-	if (midi_string_defs[0].id == 0) {
+-		status = usb_string_id(c->cdev);
+-		if (status < 0)
+-			goto fail;
+-		midi_string_defs[0].id = status;
++	us = usb_gstrings_attach(c->cdev, midi_strings,
++				 ARRAY_SIZE(midi_string_defs));
++	if (IS_ERR(us)) {
++		status = PTR_ERR(us);
++		goto fail;
+ 	}
++	ac_interface_desc.iInterface = us[STRING_FUNC_IDX].id;
+ 
+ 	/* We have two interfaces, AudioControl and MIDIStreaming */
+ 	status = usb_interface_id(c, f);
+@@ -892,6 +887,8 @@ fail_f_midi:
+ 	kfree(midi_function);
+ 	usb_free_descriptors(f->hs_descriptors);
+ fail:
++	f_midi_unregister_card(midi);
++fail_register:
+ 	/* we might as well release our claims on endpoints */
+ 	if (midi->out_ep)
+ 		midi->out_ep->driver_data = NULL;
+@@ -903,42 +900,305 @@ fail:
+ 	return status;
+ }
+ 
+-/**
+- * f_midi_bind_config - add USB MIDI function to a configuration
+- * @c: the configuration to supcard the USB audio function
+- * @index: the soundcard index to use for the ALSA device creation
+- * @id: the soundcard id to use for the ALSA device creation
+- * @buflen: the buffer length to use
+- * @qlen the number of read requests to pre-allocate
+- * Context: single threaded during gadget setup
+- *
+- * Returns zero on success, else negative errno.
+- */
+-int __init f_midi_bind_config(struct usb_configuration *c,
+-			      int index, char *id,
+-			      unsigned int in_ports,
+-			      unsigned int out_ports,
+-			      unsigned int buflen,
+-			      unsigned int qlen)
++static inline struct f_midi_opts *to_f_midi_opts(struct config_item *item)
++{
++	return container_of(to_config_group(item), struct f_midi_opts,
++			    func_inst.group);
++}
++
++CONFIGFS_ATTR_STRUCT(f_midi_opts);
++CONFIGFS_ATTR_OPS(f_midi_opts);
++
++static void midi_attr_release(struct config_item *item)
++{
++	struct f_midi_opts *opts = to_f_midi_opts(item);
++
++	usb_put_function_instance(&opts->func_inst);
++}
++
++static struct configfs_item_operations midi_item_ops = {
++	.release	= midi_attr_release,
++	.show_attribute	= f_midi_opts_attr_show,
++	.store_attribute = f_midi_opts_attr_store,
++};
++
++#define F_MIDI_OPT(name, test_limit, limit)				\
++static ssize_t f_midi_opts_##name##_show(struct f_midi_opts *opts, char *page) \
++{									\
++	int result;							\
++									\
++	mutex_lock(&opts->lock);					\
++	result = sprintf(page, "%d\n", opts->name);			\
++	mutex_unlock(&opts->lock);					\
++									\
++	return result;							\
++}									\
++									\
++static ssize_t f_midi_opts_##name##_store(struct f_midi_opts *opts,	\
++					 const char *page, size_t len)	\
++{									\
++	int ret;							\
++	u32 num;							\
++									\
++	mutex_lock(&opts->lock);					\
++	if (opts->refcnt) {						\
++		ret = -EBUSY;						\
++		goto end;						\
++	}								\
++									\
++	ret = kstrtou32(page, 0, &num);					\
++	if (ret)							\
++		goto end;						\
++									\
++	if (test_limit && num > limit) {				\
++		ret = -EINVAL;						\
++		goto end;						\
++	}								\
++	opts->name = num;						\
++	ret = len;							\
++									\
++end:									\
++	mutex_unlock(&opts->lock);					\
++	return ret;							\
++}									\
++									\
++static struct f_midi_opts_attribute f_midi_opts_##name =		\
++	__CONFIGFS_ATTR(name, S_IRUGO | S_IWUSR, f_midi_opts_##name##_show, \
++			f_midi_opts_##name##_store)
++
++F_MIDI_OPT(index, true, SNDRV_CARDS);
++F_MIDI_OPT(buflen, false, 0);
++F_MIDI_OPT(qlen, false, 0);
++F_MIDI_OPT(in_ports, true, MAX_PORTS);
++F_MIDI_OPT(out_ports, true, MAX_PORTS);
++
++static ssize_t f_midi_opts_id_show(struct f_midi_opts *opts, char *page)
++{
++	int result;
++
++	mutex_lock(&opts->lock);
++	if (opts->id) {
++		result = strlcpy(page, opts->id, PAGE_SIZE);
++	} else {
++		page[0] = 0;
++		result = 0;
++	}
++
++	mutex_unlock(&opts->lock);
++
++	return result;
++}
++
++static ssize_t f_midi_opts_id_store(struct f_midi_opts *opts,
++				    const char *page, size_t len)
++{
++	int ret;
++	char *c;
++
++	mutex_lock(&opts->lock);
++	if (opts->refcnt) {
++		ret = -EBUSY;
++		goto end;
++	}
++
++	c = kstrndup(page, len, GFP_KERNEL);
++	if (!c) {
++		ret = -ENOMEM;
++		goto end;
++	}
++	if (opts->id_allocated)
++		kfree(opts->id);
++	opts->id = c;
++	opts->id_allocated = true;
++	ret = len;
++end:
++	mutex_unlock(&opts->lock);
++	return ret;
++}
++
++static struct f_midi_opts_attribute f_midi_opts_id =
++	__CONFIGFS_ATTR(id, S_IRUGO | S_IWUSR, f_midi_opts_id_show,
++			f_midi_opts_id_store);
++
++static struct configfs_attribute *midi_attrs[] = {
++	&f_midi_opts_index.attr,
++	&f_midi_opts_buflen.attr,
++	&f_midi_opts_qlen.attr,
++	&f_midi_opts_in_ports.attr,
++	&f_midi_opts_out_ports.attr,
++	&f_midi_opts_id.attr,
++	NULL,
++};
++
++static struct config_item_type midi_func_type = {
++	.ct_item_ops	= &midi_item_ops,
++	.ct_attrs	= midi_attrs,
++	.ct_owner	= THIS_MODULE,
++};
++
++static void f_midi_free_inst(struct usb_function_instance *f)
++{
++	struct f_midi_opts *opts;
++
++	opts = container_of(f, struct f_midi_opts, func_inst);
++
++	if (opts->id_allocated)
++		kfree(opts->id);
++
++	kfree(opts);
++}
++
++#ifdef CONFIG_USB_CONFIGFS_UEVENT
++extern struct device *create_function_device(char *name);
++static ssize_t alsa_show(struct device *dev,
++		struct device_attribute *attr, char *buf)
+ {
++	struct usb_function_instance *fi_midi = dev_get_drvdata(dev);
+ 	struct f_midi *midi;
++
++	if (!fi_midi->f)
++		dev_warn(dev, "f_midi: function not set\n");
++
++	if (fi_midi && fi_midi->f) {
++		midi = func_to_midi(fi_midi->f);
++		if (midi->rmidi && midi->rmidi->card)
++			return sprintf(buf, "%d %d\n",
++			midi->rmidi->card->number, midi->rmidi->device);
++	}
++
++	/* print PCM card and device numbers */
++	return sprintf(buf, "%d %d\n", -1, -1);
++}
++
++static DEVICE_ATTR(alsa, S_IRUGO, alsa_show, NULL);
++
++static struct device_attribute *alsa_function_attributes[] = {
++	&dev_attr_alsa,
++	NULL
++};
++
++static int create_alsa_device(struct usb_function_instance *fi)
++{
++	struct device *dev;
++	struct device_attribute **attrs;
++	struct device_attribute *attr;
++	int err = 0;
++
++	dev = create_function_device("f_midi");
++	if (IS_ERR(dev))
++		return PTR_ERR(dev);
++
++	attrs = alsa_function_attributes;
++	if (attrs) {
++		while ((attr = *attrs++) && !err)
++			err = device_create_file(dev, attr);
++		if (err) {
++			device_destroy(dev->class, dev->devt);
++			return -EINVAL;
++		}
++	}
++	dev_set_drvdata(dev, fi);
++	return 0;
++}
++#else
++static int create_alsa_device(struct usb_function_instance *fi)
++{
++	return 0;
++}
++#endif
++
++static struct usb_function_instance *f_midi_alloc_inst(void)
++{
++	struct f_midi_opts *opts;
++
++	opts = kzalloc(sizeof(*opts), GFP_KERNEL);
++	if (!opts)
++		return ERR_PTR(-ENOMEM);
++
++	mutex_init(&opts->lock);
++	opts->func_inst.free_func_inst = f_midi_free_inst;
++	opts->index = SNDRV_DEFAULT_IDX1;
++	opts->id = SNDRV_DEFAULT_STR1;
++	opts->buflen = 256;
++	opts->qlen = 32;
++	opts->in_ports = 1;
++	opts->out_ports = 1;
++
++	if (create_alsa_device(&opts->func_inst)) {
++		kfree(opts);
++		return ERR_PTR(-ENODEV);
++	}
++
++	config_group_init_type_name(&opts->func_inst.group, "",
++				    &midi_func_type);
++
++	return &opts->func_inst;
++}
++
++static void f_midi_free(struct usb_function *f)
++{
++	struct f_midi *midi;
++	struct f_midi_opts *opts;
++	int i;
++
++	midi = func_to_midi(f);
++	opts = container_of(f->fi, struct f_midi_opts, func_inst);
++	kfree(midi->id);
++	mutex_lock(&opts->lock);
++	for (i = opts->in_ports - 1; i >= 0; --i)
++		kfree(midi->in_port[i]);
++	kfree(midi);
++	--opts->refcnt;
++	mutex_unlock(&opts->lock);
++}
++
++static void f_midi_unbind(struct usb_configuration *c, struct usb_function *f)
++{
++	struct usb_composite_dev *cdev = f->config->cdev;
++	struct f_midi *midi = func_to_midi(f);
++	struct snd_card *card;
++
++	DBG(cdev, "unbind\n");
++
++	/* just to be sure */
++	f_midi_disable(f);
++
++	card = midi->card;
++	midi->card = NULL;
++	if (card)
++		snd_card_free(card);
++
++	usb_free_all_descriptors(f);
++}
++
++static struct usb_function *f_midi_alloc(struct usb_function_instance *fi)
++{
++	struct f_midi *midi;
++	struct f_midi_opts *opts;
+ 	int status, i;
+ 
++	opts = container_of(fi, struct f_midi_opts, func_inst);
++
++	mutex_lock(&opts->lock);
+ 	/* sanity check */
+-	if (in_ports > MAX_PORTS || out_ports > MAX_PORTS)
+-		return -EINVAL;
++	if (opts->in_ports > MAX_PORTS || opts->out_ports > MAX_PORTS) {
++		mutex_unlock(&opts->lock);
++		return ERR_PTR(-EINVAL);
++	}
+ 
+ 	/* allocate and initialize one new instance */
+-	midi = kzalloc(sizeof *midi, GFP_KERNEL);
++	midi = kzalloc(sizeof(*midi), GFP_KERNEL);
+ 	if (!midi) {
+-		status = -ENOMEM;
+-		goto fail;
++		mutex_unlock(&opts->lock);
++		return ERR_PTR(-ENOMEM);
+ 	}
+ 
+-	for (i = 0; i < in_ports; i++) {
++	for (i = 0; i < opts->in_ports; i++) {
+ 		struct gmidi_in_port *port = kzalloc(sizeof(*port), GFP_KERNEL);
++
+ 		if (!port) {
+ 			status = -ENOMEM;
++			mutex_unlock(&opts->lock);
+ 			goto setup_fail;
+ 		}
+ 
+@@ -948,39 +1208,36 @@ int __init f_midi_bind_config(struct usb_configuration *c,
+ 		midi->in_port[i] = port;
+ 	}
+ 
+-	midi->gadget = c->cdev->gadget;
+-	tasklet_init(&midi->tasklet, f_midi_in_tasklet, (unsigned long) midi);
+-
+ 	/* set up ALSA midi devices */
+-	midi->in_ports = in_ports;
+-	midi->out_ports = out_ports;
+-	status = f_midi_register_card(midi);
+-	if (status < 0)
+-		goto setup_fail;
+-
+-	midi->func.name        = "gmidi function";
+-	midi->func.strings     = midi_strings;
+-	midi->func.bind        = f_midi_bind;
+-	midi->func.unbind      = f_midi_unbind;
+-	midi->func.set_alt     = f_midi_set_alt;
+-	midi->func.disable     = f_midi_disable;
+-
+-	midi->id = kstrdup(id, GFP_KERNEL);
+-	midi->index = index;
+-	midi->buflen = buflen;
+-	midi->qlen = qlen;
+-
+-	status = usb_add_function(c, &midi->func);
+-	if (status)
++	midi->id = kstrdup(opts->id, GFP_KERNEL);
++	if (opts->id && !midi->id) {
++		status = -ENOMEM;
++		mutex_unlock(&opts->lock);
+ 		goto setup_fail;
+-
+-	return 0;
++	}
++	midi->in_ports = opts->in_ports;
++	midi->out_ports = opts->out_ports;
++	midi->index = opts->index;
++	midi->buflen = opts->buflen;
++	midi->qlen = opts->qlen;
++	++opts->refcnt;
++	mutex_unlock(&opts->lock);
++
++	midi->func.name		= "gmidi function";
++	midi->func.bind		= f_midi_bind;
++	midi->func.unbind	= f_midi_unbind;
++	midi->func.set_alt	= f_midi_set_alt;
++	midi->func.disable	= f_midi_disable;
++	midi->func.free_func	= f_midi_free;
++
++	fi->f = &midi->func;
++	return &midi->func;
+ 
+ setup_fail:
+ 	for (--i; i >= 0; i--)
+ 		kfree(midi->in_port[i]);
+ 	kfree(midi);
+-fail:
+-	return status;
++	return ERR_PTR(status);
+ }
+ 
++DECLARE_USB_FUNCTION_INIT(midi, f_midi_alloc_inst, f_midi_alloc);
+diff --git a/drivers/usb/gadget/function/f_mtp.c b/drivers/usb/gadget/function/f_mtp.c
+new file mode 100644
+index 0000000..79053fd
+--- /dev/null
++++ b/drivers/usb/gadget/function/f_mtp.c
+@@ -0,0 +1,1473 @@
++/*
++ * Gadget Function Driver for MTP
++ *
++ * Copyright (C) 2010 Google, Inc.
++ * Author: Mike Lockwood <lockwood@android.com>
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * 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.
++ *
++ */
++
++/* #define DEBUG */
++/* #define VERBOSE_DEBUG */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/poll.h>
++#include <linux/delay.h>
++#include <linux/wait.h>
++#include <linux/err.h>
++#include <linux/interrupt.h>
++
++#include <linux/types.h>
++#include <linux/file.h>
++#include <linux/device.h>
++#include <linux/miscdevice.h>
++
++#include <linux/usb.h>
++#include <linux/usb_usual.h>
++#include <linux/usb/ch9.h>
++#include <linux/usb/f_mtp.h>
++#include <linux/configfs.h>
++#include <linux/usb/composite.h>
++
++#include "configfs.h"
++
++#define MTP_BULK_BUFFER_SIZE       16384
++#define INTR_BUFFER_SIZE           28
++#define MAX_INST_NAME_LEN          40
++
++/* String IDs */
++#define INTERFACE_STRING_INDEX	0
++
++/* values for mtp_dev.state */
++#define STATE_OFFLINE               0   /* initial state, disconnected */
++#define STATE_READY                 1   /* ready for userspace calls */
++#define STATE_BUSY                  2   /* processing userspace calls */
++#define STATE_CANCELED              3   /* transaction canceled by host */
++#define STATE_ERROR                 4   /* error from completion routine */
++
++/* number of tx and rx requests to allocate */
++#define TX_REQ_MAX 4
++#define RX_REQ_MAX 2
++#define INTR_REQ_MAX 5
++
++/* ID for Microsoft MTP OS String */
++#define MTP_OS_STRING_ID   0xEE
++
++/* MTP class reqeusts */
++#define MTP_REQ_CANCEL              0x64
++#define MTP_REQ_GET_EXT_EVENT_DATA  0x65
++#define MTP_REQ_RESET               0x66
++#define MTP_REQ_GET_DEVICE_STATUS   0x67
++
++/* constants for device status */
++#define MTP_RESPONSE_OK             0x2001
++#define MTP_RESPONSE_DEVICE_BUSY    0x2019
++#define DRIVER_NAME "mtp"
++
++static const char mtp_shortname[] = DRIVER_NAME "_usb";
++
++struct mtp_dev {
++	struct usb_function function;
++	struct usb_composite_dev *cdev;
++	spinlock_t lock;
++
++	struct usb_ep *ep_in;
++	struct usb_ep *ep_out;
++	struct usb_ep *ep_intr;
++
++	int state;
++
++	/* synchronize access to our device file */
++	atomic_t open_excl;
++	/* to enforce only one ioctl at a time */
++	atomic_t ioctl_excl;
++
++	struct list_head tx_idle;
++	struct list_head intr_idle;
++
++	wait_queue_head_t read_wq;
++	wait_queue_head_t write_wq;
++	wait_queue_head_t intr_wq;
++	struct usb_request *rx_req[RX_REQ_MAX];
++	int rx_done;
++
++	/* for processing MTP_SEND_FILE, MTP_RECEIVE_FILE and
++	 * MTP_SEND_FILE_WITH_HEADER ioctls on a work queue
++	 */
++	struct workqueue_struct *wq;
++	struct work_struct send_file_work;
++	struct work_struct receive_file_work;
++	struct file *xfer_file;
++	loff_t xfer_file_offset;
++	int64_t xfer_file_length;
++	unsigned xfer_send_header;
++	uint16_t xfer_command;
++	uint32_t xfer_transaction_id;
++	int xfer_result;
++};
++
++static struct usb_interface_descriptor mtp_interface_desc = {
++	.bLength                = USB_DT_INTERFACE_SIZE,
++	.bDescriptorType        = USB_DT_INTERFACE,
++	.bInterfaceNumber       = 0,
++	.bNumEndpoints          = 3,
++	.bInterfaceClass        = USB_CLASS_VENDOR_SPEC,
++	.bInterfaceSubClass     = USB_SUBCLASS_VENDOR_SPEC,
++	.bInterfaceProtocol     = 0,
++};
++
++static struct usb_interface_descriptor ptp_interface_desc = {
++	.bLength                = USB_DT_INTERFACE_SIZE,
++	.bDescriptorType        = USB_DT_INTERFACE,
++	.bInterfaceNumber       = 0,
++	.bNumEndpoints          = 3,
++	.bInterfaceClass        = USB_CLASS_STILL_IMAGE,
++	.bInterfaceSubClass     = 1,
++	.bInterfaceProtocol     = 1,
++};
++
++static struct usb_endpoint_descriptor mtp_highspeed_in_desc = {
++	.bLength                = USB_DT_ENDPOINT_SIZE,
++	.bDescriptorType        = USB_DT_ENDPOINT,
++	.bEndpointAddress       = USB_DIR_IN,
++	.bmAttributes           = USB_ENDPOINT_XFER_BULK,
++	.wMaxPacketSize         = __constant_cpu_to_le16(512),
++};
++
++static struct usb_endpoint_descriptor mtp_highspeed_out_desc = {
++	.bLength                = USB_DT_ENDPOINT_SIZE,
++	.bDescriptorType        = USB_DT_ENDPOINT,
++	.bEndpointAddress       = USB_DIR_OUT,
++	.bmAttributes           = USB_ENDPOINT_XFER_BULK,
++	.wMaxPacketSize         = __constant_cpu_to_le16(512),
++};
++
++static struct usb_endpoint_descriptor mtp_fullspeed_in_desc = {
++	.bLength                = USB_DT_ENDPOINT_SIZE,
++	.bDescriptorType        = USB_DT_ENDPOINT,
++	.bEndpointAddress       = USB_DIR_IN,
++	.bmAttributes           = USB_ENDPOINT_XFER_BULK,
++};
++
++static struct usb_endpoint_descriptor mtp_fullspeed_out_desc = {
++	.bLength                = USB_DT_ENDPOINT_SIZE,
++	.bDescriptorType        = USB_DT_ENDPOINT,
++	.bEndpointAddress       = USB_DIR_OUT,
++	.bmAttributes           = USB_ENDPOINT_XFER_BULK,
++};
++
++static struct usb_endpoint_descriptor mtp_intr_desc = {
++	.bLength                = USB_DT_ENDPOINT_SIZE,
++	.bDescriptorType        = USB_DT_ENDPOINT,
++	.bEndpointAddress       = USB_DIR_IN,
++	.bmAttributes           = USB_ENDPOINT_XFER_INT,
++	.wMaxPacketSize         = __constant_cpu_to_le16(INTR_BUFFER_SIZE),
++	.bInterval              = 6,
++};
++
++static struct usb_descriptor_header *fs_mtp_descs[] = {
++	(struct usb_descriptor_header *) &mtp_interface_desc,
++	(struct usb_descriptor_header *) &mtp_fullspeed_in_desc,
++	(struct usb_descriptor_header *) &mtp_fullspeed_out_desc,
++	(struct usb_descriptor_header *) &mtp_intr_desc,
++	NULL,
++};
++
++static struct usb_descriptor_header *hs_mtp_descs[] = {
++	(struct usb_descriptor_header *) &mtp_interface_desc,
++	(struct usb_descriptor_header *) &mtp_highspeed_in_desc,
++	(struct usb_descriptor_header *) &mtp_highspeed_out_desc,
++	(struct usb_descriptor_header *) &mtp_intr_desc,
++	NULL,
++};
++
++static struct usb_descriptor_header *fs_ptp_descs[] = {
++	(struct usb_descriptor_header *) &ptp_interface_desc,
++	(struct usb_descriptor_header *) &mtp_fullspeed_in_desc,
++	(struct usb_descriptor_header *) &mtp_fullspeed_out_desc,
++	(struct usb_descriptor_header *) &mtp_intr_desc,
++	NULL,
++};
++
++static struct usb_descriptor_header *hs_ptp_descs[] = {
++	(struct usb_descriptor_header *) &ptp_interface_desc,
++	(struct usb_descriptor_header *) &mtp_highspeed_in_desc,
++	(struct usb_descriptor_header *) &mtp_highspeed_out_desc,
++	(struct usb_descriptor_header *) &mtp_intr_desc,
++	NULL,
++};
++
++static struct usb_string mtp_string_defs[] = {
++	/* Naming interface "MTP" so libmtp will recognize us */
++	[INTERFACE_STRING_INDEX].s	= "MTP",
++	{  },	/* end of list */
++};
++
++static struct usb_gadget_strings mtp_string_table = {
++	.language		= 0x0409,	/* en-US */
++	.strings		= mtp_string_defs,
++};
++
++static struct usb_gadget_strings *mtp_strings[] = {
++	&mtp_string_table,
++	NULL,
++};
++
++/* Microsoft MTP OS String */
++static u8 mtp_os_string[] = {
++	18, /* sizeof(mtp_os_string) */
++	USB_DT_STRING,
++	/* Signature field: "MSFT100" */
++	'M', 0, 'S', 0, 'F', 0, 'T', 0, '1', 0, '0', 0, '0', 0,
++	/* vendor code */
++	1,
++	/* padding */
++	0
++};
++
++/* Microsoft Extended Configuration Descriptor Header Section */
++struct mtp_ext_config_desc_header {
++	__le32	dwLength;
++	__u16	bcdVersion;
++	__le16	wIndex;
++	__u8	bCount;
++	__u8	reserved[7];
++};
++
++/* Microsoft Extended Configuration Descriptor Function Section */
++struct mtp_ext_config_desc_function {
++	__u8	bFirstInterfaceNumber;
++	__u8	bInterfaceCount;
++	__u8	compatibleID[8];
++	__u8	subCompatibleID[8];
++	__u8	reserved[6];
++};
++
++/* MTP Extended Configuration Descriptor */
++struct {
++	struct mtp_ext_config_desc_header	header;
++	struct mtp_ext_config_desc_function    function;
++} mtp_ext_config_desc = {
++	.header = {
++		.dwLength = __constant_cpu_to_le32(sizeof(mtp_ext_config_desc)),
++		.bcdVersion = __constant_cpu_to_le16(0x0100),
++		.wIndex = __constant_cpu_to_le16(4),
++		.bCount = __constant_cpu_to_le16(1),
++	},
++	.function = {
++		.bFirstInterfaceNumber = 0,
++		.bInterfaceCount = 1,
++		.compatibleID = { 'M', 'T', 'P' },
++	},
++};
++
++struct mtp_device_status {
++	__le16	wLength;
++	__le16	wCode;
++};
++
++struct mtp_data_header {
++	/* length of packet, including this header */
++	__le32	length;
++	/* container type (2 for data packet) */
++	__le16	type;
++	/* MTP command code */
++	__le16	command;
++	/* MTP transaction ID */
++	__le32	transaction_id;
++};
++
++struct mtp_instance {
++	struct usb_function_instance func_inst;
++	const char *name;
++	struct mtp_dev *dev;
++};
++
++/* temporary variable used between mtp_open() and mtp_gadget_bind() */
++static struct mtp_dev *_mtp_dev;
++
++static inline struct mtp_dev *func_to_mtp(struct usb_function *f)
++{
++	return container_of(f, struct mtp_dev, function);
++}
++
++static struct usb_request *mtp_request_new(struct usb_ep *ep, int buffer_size)
++{
++	struct usb_request *req = usb_ep_alloc_request(ep, GFP_KERNEL);
++	if (!req)
++		return NULL;
++
++	/* now allocate buffers for the requests */
++	req->buf = kmalloc(buffer_size, GFP_KERNEL);
++	if (!req->buf) {
++		usb_ep_free_request(ep, req);
++		return NULL;
++	}
++
++	return req;
++}
++
++static void mtp_request_free(struct usb_request *req, struct usb_ep *ep)
++{
++	if (req) {
++		kfree(req->buf);
++		usb_ep_free_request(ep, req);
++	}
++}
++
++static inline int mtp_lock(atomic_t *excl)
++{
++	if (atomic_inc_return(excl) == 1) {
++		return 0;
++	} else {
++		atomic_dec(excl);
++		return -1;
++	}
++}
++
++static inline void mtp_unlock(atomic_t *excl)
++{
++	atomic_dec(excl);
++}
++
++/* add a request to the tail of a list */
++static void mtp_req_put(struct mtp_dev *dev, struct list_head *head,
++		struct usb_request *req)
++{
++	unsigned long flags;
++
++	spin_lock_irqsave(&dev->lock, flags);
++	list_add_tail(&req->list, head);
++	spin_unlock_irqrestore(&dev->lock, flags);
++}
++
++/* remove a request from the head of a list */
++static struct usb_request
++*mtp_req_get(struct mtp_dev *dev, struct list_head *head)
++{
++	unsigned long flags;
++	struct usb_request *req;
++
++	spin_lock_irqsave(&dev->lock, flags);
++	if (list_empty(head)) {
++		req = 0;
++	} else {
++		req = list_first_entry(head, struct usb_request, list);
++		list_del(&req->list);
++	}
++	spin_unlock_irqrestore(&dev->lock, flags);
++	return req;
++}
++
++static void mtp_complete_in(struct usb_ep *ep, struct usb_request *req)
++{
++	struct mtp_dev *dev = _mtp_dev;
++
++	if (req->status != 0)
++		dev->state = STATE_ERROR;
++
++	mtp_req_put(dev, &dev->tx_idle, req);
++
++	wake_up(&dev->write_wq);
++}
++
++static void mtp_complete_out(struct usb_ep *ep, struct usb_request *req)
++{
++	struct mtp_dev *dev = _mtp_dev;
++
++	dev->rx_done = 1;
++	if (req->status != 0)
++		dev->state = STATE_ERROR;
++
++	wake_up(&dev->read_wq);
++}
++
++static void mtp_complete_intr(struct usb_ep *ep, struct usb_request *req)
++{
++	struct mtp_dev *dev = _mtp_dev;
++
++	if (req->status != 0)
++		dev->state = STATE_ERROR;
++
++	mtp_req_put(dev, &dev->intr_idle, req);
++
++	wake_up(&dev->intr_wq);
++}
++
++static int mtp_create_bulk_endpoints(struct mtp_dev *dev,
++				struct usb_endpoint_descriptor *in_desc,
++				struct usb_endpoint_descriptor *out_desc,
++				struct usb_endpoint_descriptor *intr_desc)
++{
++	struct usb_composite_dev *cdev = dev->cdev;
++	struct usb_request *req;
++	struct usb_ep *ep;
++	int i;
++
++	DBG(cdev, "create_bulk_endpoints dev: %p\n", dev);
++
++	ep = usb_ep_autoconfig(cdev->gadget, in_desc);
++	if (!ep) {
++		DBG(cdev, "usb_ep_autoconfig for ep_in failed\n");
++		return -ENODEV;
++	}
++	DBG(cdev, "usb_ep_autoconfig for ep_in got %s\n", ep->name);
++	ep->driver_data = dev;		/* claim the endpoint */
++	dev->ep_in = ep;
++
++	ep = usb_ep_autoconfig(cdev->gadget, out_desc);
++	if (!ep) {
++		DBG(cdev, "usb_ep_autoconfig for ep_out failed\n");
++		return -ENODEV;
++	}
++	DBG(cdev, "usb_ep_autoconfig for mtp ep_out got %s\n", ep->name);
++	ep->driver_data = dev;		/* claim the endpoint */
++	dev->ep_out = ep;
++
++	ep = usb_ep_autoconfig(cdev->gadget, intr_desc);
++	if (!ep) {
++		DBG(cdev, "usb_ep_autoconfig for ep_intr failed\n");
++		return -ENODEV;
++	}
++	DBG(cdev, "usb_ep_autoconfig for mtp ep_intr got %s\n", ep->name);
++	ep->driver_data = dev;		/* claim the endpoint */
++	dev->ep_intr = ep;
++
++	/* now allocate requests for our endpoints */
++	for (i = 0; i < TX_REQ_MAX; i++) {
++		req = mtp_request_new(dev->ep_in, MTP_BULK_BUFFER_SIZE);
++		if (!req)
++			goto fail;
++		req->complete = mtp_complete_in;
++		mtp_req_put(dev, &dev->tx_idle, req);
++	}
++	for (i = 0; i < RX_REQ_MAX; i++) {
++		req = mtp_request_new(dev->ep_out, MTP_BULK_BUFFER_SIZE);
++		if (!req)
++			goto fail;
++		req->complete = mtp_complete_out;
++		dev->rx_req[i] = req;
++	}
++	for (i = 0; i < INTR_REQ_MAX; i++) {
++		req = mtp_request_new(dev->ep_intr, INTR_BUFFER_SIZE);
++		if (!req)
++			goto fail;
++		req->complete = mtp_complete_intr;
++		mtp_req_put(dev, &dev->intr_idle, req);
++	}
++
++	return 0;
++
++fail:
++	pr_err("mtp_bind() could not allocate requests\n");
++	return -1;
++}
++
++static ssize_t mtp_read(struct file *fp, char __user *buf,
++	size_t count, loff_t *pos)
++{
++	struct mtp_dev *dev = fp->private_data;
++	struct usb_composite_dev *cdev = dev->cdev;
++	struct usb_request *req;
++	ssize_t r = count;
++	unsigned xfer;
++	int ret = 0;
++
++	DBG(cdev, "mtp_read(%zu)\n", count);
++
++	if (count > MTP_BULK_BUFFER_SIZE)
++		return -EINVAL;
++
++	/* we will block until we're online */
++	DBG(cdev, "mtp_read: waiting for online state\n");
++	ret = wait_event_interruptible(dev->read_wq,
++		dev->state != STATE_OFFLINE);
++	if (ret < 0) {
++		r = ret;
++		goto done;
++	}
++	spin_lock_irq(&dev->lock);
++	if (dev->state == STATE_CANCELED) {
++		/* report cancelation to userspace */
++		dev->state = STATE_READY;
++		spin_unlock_irq(&dev->lock);
++		return -ECANCELED;
++	}
++	dev->state = STATE_BUSY;
++	spin_unlock_irq(&dev->lock);
++
++requeue_req:
++	/* queue a request */
++	req = dev->rx_req[0];
++	req->length = count;
++	dev->rx_done = 0;
++	ret = usb_ep_queue(dev->ep_out, req, GFP_KERNEL);
++	if (ret < 0) {
++		r = -EIO;
++		goto done;
++	} else {
++		DBG(cdev, "rx %p queue\n", req);
++	}
++
++	/* wait for a request to complete */
++	ret = wait_event_interruptible(dev->read_wq, dev->rx_done);
++	if (ret < 0) {
++		r = ret;
++		usb_ep_dequeue(dev->ep_out, req);
++		goto done;
++	}
++	if (dev->state == STATE_BUSY) {
++		/* If we got a 0-len packet, throw it back and try again. */
++		if (req->actual == 0)
++			goto requeue_req;
++
++		DBG(cdev, "rx %p %d\n", req, req->actual);
++		xfer = (req->actual < count) ? req->actual : count;
++		r = xfer;
++		if (copy_to_user(buf, req->buf, xfer))
++			r = -EFAULT;
++	} else
++		r = -EIO;
++
++done:
++	spin_lock_irq(&dev->lock);
++	if (dev->state == STATE_CANCELED)
++		r = -ECANCELED;
++	else if (dev->state != STATE_OFFLINE)
++		dev->state = STATE_READY;
++	spin_unlock_irq(&dev->lock);
++
++	DBG(cdev, "mtp_read returning %zd\n", r);
++	return r;
++}
++
++static ssize_t mtp_write(struct file *fp, const char __user *buf,
++	size_t count, loff_t *pos)
++{
++	struct mtp_dev *dev = fp->private_data;
++	struct usb_composite_dev *cdev = dev->cdev;
++	struct usb_request *req = 0;
++	ssize_t r = count;
++	unsigned xfer;
++	int sendZLP = 0;
++	int ret;
++
++	DBG(cdev, "mtp_write(%zu)\n", count);
++
++	spin_lock_irq(&dev->lock);
++	if (dev->state == STATE_CANCELED) {
++		/* report cancelation to userspace */
++		dev->state = STATE_READY;
++		spin_unlock_irq(&dev->lock);
++		return -ECANCELED;
++	}
++	if (dev->state == STATE_OFFLINE) {
++		spin_unlock_irq(&dev->lock);
++		return -ENODEV;
++	}
++	dev->state = STATE_BUSY;
++	spin_unlock_irq(&dev->lock);
++
++	/* we need to send a zero length packet to signal the end of transfer
++	 * if the transfer size is aligned to a packet boundary.
++	 */
++	if ((count & (dev->ep_in->maxpacket - 1)) == 0)
++		sendZLP = 1;
++
++	while (count > 0 || sendZLP) {
++		/* so we exit after sending ZLP */
++		if (count == 0)
++			sendZLP = 0;
++
++		if (dev->state != STATE_BUSY) {
++			DBG(cdev, "mtp_write dev->error\n");
++			r = -EIO;
++			break;
++		}
++
++		/* get an idle tx request to use */
++		req = 0;
++		ret = wait_event_interruptible(dev->write_wq,
++			((req = mtp_req_get(dev, &dev->tx_idle))
++				|| dev->state != STATE_BUSY));
++		if (!req) {
++			r = ret;
++			break;
++		}
++
++		if (count > MTP_BULK_BUFFER_SIZE)
++			xfer = MTP_BULK_BUFFER_SIZE;
++		else
++			xfer = count;
++		if (xfer && copy_from_user(req->buf, buf, xfer)) {
++			r = -EFAULT;
++			break;
++		}
++
++		req->length = xfer;
++		ret = usb_ep_queue(dev->ep_in, req, GFP_KERNEL);
++		if (ret < 0) {
++			DBG(cdev, "mtp_write: xfer error %d\n", ret);
++			r = -EIO;
++			break;
++		}
++
++		buf += xfer;
++		count -= xfer;
++
++		/* zero this so we don't try to free it on error exit */
++		req = 0;
++	}
++
++	if (req)
++		mtp_req_put(dev, &dev->tx_idle, req);
++
++	spin_lock_irq(&dev->lock);
++	if (dev->state == STATE_CANCELED)
++		r = -ECANCELED;
++	else if (dev->state != STATE_OFFLINE)
++		dev->state = STATE_READY;
++	spin_unlock_irq(&dev->lock);
++
++	DBG(cdev, "mtp_write returning %zd\n", r);
++	return r;
++}
++
++/* read from a local file and write to USB */
++static void send_file_work(struct work_struct *data)
++{
++	struct mtp_dev *dev = container_of(data, struct mtp_dev,
++						send_file_work);
++	struct usb_composite_dev *cdev = dev->cdev;
++	struct usb_request *req = 0;
++	struct mtp_data_header *header;
++	struct file *filp;
++	loff_t offset;
++	int64_t count;
++	int xfer, ret, hdr_size;
++	int r = 0;
++	int sendZLP = 0;
++
++	/* read our parameters */
++	smp_rmb();
++	filp = dev->xfer_file;
++	offset = dev->xfer_file_offset;
++	count = dev->xfer_file_length;
++
++	DBG(cdev, "send_file_work(%lld %lld)\n", offset, count);
++
++	if (dev->xfer_send_header) {
++		hdr_size = sizeof(struct mtp_data_header);
++		count += hdr_size;
++	} else {
++		hdr_size = 0;
++	}
++
++	/* we need to send a zero length packet to signal the end of transfer
++	 * if the transfer size is aligned to a packet boundary.
++	 */
++	if ((count & (dev->ep_in->maxpacket - 1)) == 0)
++		sendZLP = 1;
++
++	while (count > 0 || sendZLP) {
++		/* so we exit after sending ZLP */
++		if (count == 0)
++			sendZLP = 0;
++
++		/* get an idle tx request to use */
++		req = 0;
++		ret = wait_event_interruptible(dev->write_wq,
++			(req = mtp_req_get(dev, &dev->tx_idle))
++			|| dev->state != STATE_BUSY);
++		if (dev->state == STATE_CANCELED) {
++			r = -ECANCELED;
++			break;
++		}
++		if (!req) {
++			r = ret;
++			break;
++		}
++
++		if (count > MTP_BULK_BUFFER_SIZE)
++			xfer = MTP_BULK_BUFFER_SIZE;
++		else
++			xfer = count;
++
++		if (hdr_size) {
++			/* prepend MTP data header */
++			header = (struct mtp_data_header *)req->buf;
++			header->length = __cpu_to_le32(count);
++			header->type = __cpu_to_le16(2); /* data packet */
++			header->command = __cpu_to_le16(dev->xfer_command);
++			header->transaction_id =
++					__cpu_to_le32(dev->xfer_transaction_id);
++		}
++
++		ret = vfs_read(filp, req->buf + hdr_size, xfer - hdr_size,
++								&offset);
++		if (ret < 0) {
++			r = ret;
++			break;
++		}
++		xfer = ret + hdr_size;
++		hdr_size = 0;
++
++		req->length = xfer;
++		ret = usb_ep_queue(dev->ep_in, req, GFP_KERNEL);
++		if (ret < 0) {
++			DBG(cdev, "send_file_work: xfer error %d\n", ret);
++			dev->state = STATE_ERROR;
++			r = -EIO;
++			break;
++		}
++
++		count -= xfer;
++
++		/* zero this so we don't try to free it on error exit */
++		req = 0;
++	}
++
++	if (req)
++		mtp_req_put(dev, &dev->tx_idle, req);
++
++	DBG(cdev, "send_file_work returning %d\n", r);
++	/* write the result */
++	dev->xfer_result = r;
++	smp_wmb();
++}
++
++/* read from USB and write to a local file */
++static void receive_file_work(struct work_struct *data)
++{
++	struct mtp_dev *dev = container_of(data, struct mtp_dev,
++						receive_file_work);
++	struct usb_composite_dev *cdev = dev->cdev;
++	struct usb_request *read_req = NULL, *write_req = NULL;
++	struct file *filp;
++	loff_t offset;
++	int64_t count;
++	int ret, cur_buf = 0;
++	int r = 0;
++
++	/* read our parameters */
++	smp_rmb();
++	filp = dev->xfer_file;
++	offset = dev->xfer_file_offset;
++	count = dev->xfer_file_length;
++
++	DBG(cdev, "receive_file_work(%lld)\n", count);
++
++	while (count > 0 || write_req) {
++		if (count > 0) {
++			/* queue a request */
++			read_req = dev->rx_req[cur_buf];
++			cur_buf = (cur_buf + 1) % RX_REQ_MAX;
++
++			read_req->length = (count > MTP_BULK_BUFFER_SIZE
++					? MTP_BULK_BUFFER_SIZE : count);
++			dev->rx_done = 0;
++			ret = usb_ep_queue(dev->ep_out, read_req, GFP_KERNEL);
++			if (ret < 0) {
++				r = -EIO;
++				dev->state = STATE_ERROR;
++				break;
++			}
++		}
++
++		if (write_req) {
++			DBG(cdev, "rx %p %d\n", write_req, write_req->actual);
++			ret = vfs_write(filp, write_req->buf, write_req->actual,
++				&offset);
++			DBG(cdev, "vfs_write %d\n", ret);
++			if (ret != write_req->actual) {
++				r = -EIO;
++				dev->state = STATE_ERROR;
++				break;
++			}
++			write_req = NULL;
++		}
++
++		if (read_req) {
++			/* wait for our last read to complete */
++			ret = wait_event_interruptible(dev->read_wq,
++				dev->rx_done || dev->state != STATE_BUSY);
++			if (dev->state == STATE_CANCELED) {
++				r = -ECANCELED;
++				if (!dev->rx_done)
++					usb_ep_dequeue(dev->ep_out, read_req);
++				break;
++			}
++			/* if xfer_file_length is 0xFFFFFFFF, then we read until
++			 * we get a zero length packet
++			 */
++			if (count != 0xFFFFFFFF)
++				count -= read_req->actual;
++			if (read_req->actual < read_req->length) {
++				/*
++				 * short packet is used to signal EOF for
++				 * sizes > 4 gig
++				 */
++				DBG(cdev, "got short packet\n");
++				count = 0;
++			}
++
++			write_req = read_req;
++			read_req = NULL;
++		}
++	}
++
++	DBG(cdev, "receive_file_work returning %d\n", r);
++	/* write the result */
++	dev->xfer_result = r;
++	smp_wmb();
++}
++
++static int mtp_send_event(struct mtp_dev *dev, struct mtp_event *event)
++{
++	struct usb_request *req = NULL;
++	int ret;
++	int length = event->length;
++
++	DBG(dev->cdev, "mtp_send_event(%zu)\n", event->length);
++
++	if (length < 0 || length > INTR_BUFFER_SIZE)
++		return -EINVAL;
++	if (dev->state == STATE_OFFLINE)
++		return -ENODEV;
++
++	ret = wait_event_interruptible_timeout(dev->intr_wq,
++			(req = mtp_req_get(dev, &dev->intr_idle)),
++			msecs_to_jiffies(1000));
++	if (!req)
++		return -ETIME;
++
++	if (copy_from_user(req->buf, (void __user *)event->data, length)) {
++		mtp_req_put(dev, &dev->intr_idle, req);
++		return -EFAULT;
++	}
++	req->length = length;
++	ret = usb_ep_queue(dev->ep_intr, req, GFP_KERNEL);
++	if (ret)
++		mtp_req_put(dev, &dev->intr_idle, req);
++
++	return ret;
++}
++
++static long mtp_ioctl(struct file *fp, unsigned code, unsigned long value)
++{
++	struct mtp_dev *dev = fp->private_data;
++	struct file *filp = NULL;
++	int ret = -EINVAL;
++
++	if (mtp_lock(&dev->ioctl_excl))
++		return -EBUSY;
++
++	switch (code) {
++	case MTP_SEND_FILE:
++	case MTP_RECEIVE_FILE:
++	case MTP_SEND_FILE_WITH_HEADER:
++	{
++		struct mtp_file_range	mfr;
++		struct work_struct *work;
++
++		spin_lock_irq(&dev->lock);
++		if (dev->state == STATE_CANCELED) {
++			/* report cancelation to userspace */
++			dev->state = STATE_READY;
++			spin_unlock_irq(&dev->lock);
++			ret = -ECANCELED;
++			goto out;
++		}
++		if (dev->state == STATE_OFFLINE) {
++			spin_unlock_irq(&dev->lock);
++			ret = -ENODEV;
++			goto out;
++		}
++		dev->state = STATE_BUSY;
++		spin_unlock_irq(&dev->lock);
++
++		if (copy_from_user(&mfr, (void __user *)value, sizeof(mfr))) {
++			ret = -EFAULT;
++			goto fail;
++		}
++		/* hold a reference to the file while we are working with it */
++		filp = fget(mfr.fd);
++		if (!filp) {
++			ret = -EBADF;
++			goto fail;
++		}
++
++		/* write the parameters */
++		dev->xfer_file = filp;
++		dev->xfer_file_offset = mfr.offset;
++		dev->xfer_file_length = mfr.length;
++		smp_wmb();
++
++		if (code == MTP_SEND_FILE_WITH_HEADER) {
++			work = &dev->send_file_work;
++			dev->xfer_send_header = 1;
++			dev->xfer_command = mfr.command;
++			dev->xfer_transaction_id = mfr.transaction_id;
++		} else if (code == MTP_SEND_FILE) {
++			work = &dev->send_file_work;
++			dev->xfer_send_header = 0;
++		} else {
++			work = &dev->receive_file_work;
++		}
++
++		/* We do the file transfer on a work queue so it will run
++		 * in kernel context, which is necessary for vfs_read and
++		 * vfs_write to use our buffers in the kernel address space.
++		 */
++		queue_work(dev->wq, work);
++		/* wait for operation to complete */
++		flush_workqueue(dev->wq);
++		fput(filp);
++
++		/* read the result */
++		smp_rmb();
++		ret = dev->xfer_result;
++		break;
++	}
++	case MTP_SEND_EVENT:
++	{
++		struct mtp_event	event;
++		/* return here so we don't change dev->state below,
++		 * which would interfere with bulk transfer state.
++		 */
++		if (copy_from_user(&event, (void __user *)value, sizeof(event)))
++			ret = -EFAULT;
++		else
++			ret = mtp_send_event(dev, &event);
++		goto out;
++	}
++	}
++
++fail:
++	spin_lock_irq(&dev->lock);
++	if (dev->state == STATE_CANCELED)
++		ret = -ECANCELED;
++	else if (dev->state != STATE_OFFLINE)
++		dev->state = STATE_READY;
++	spin_unlock_irq(&dev->lock);
++out:
++	mtp_unlock(&dev->ioctl_excl);
++	DBG(dev->cdev, "ioctl returning %d\n", ret);
++	return ret;
++}
++
++static int mtp_open(struct inode *ip, struct file *fp)
++{
++	printk(KERN_INFO "mtp_open\n");
++	if (mtp_lock(&_mtp_dev->open_excl))
++		return -EBUSY;
++
++	/* clear any error condition */
++	if (_mtp_dev->state != STATE_OFFLINE)
++		_mtp_dev->state = STATE_READY;
++
++	fp->private_data = _mtp_dev;
++	return 0;
++}
++
++static int mtp_release(struct inode *ip, struct file *fp)
++{
++	printk(KERN_INFO "mtp_release\n");
++
++	mtp_unlock(&_mtp_dev->open_excl);
++	return 0;
++}
++
++/* file operations for /dev/mtp_usb */
++static const struct file_operations mtp_fops = {
++	.owner = THIS_MODULE,
++	.read = mtp_read,
++	.write = mtp_write,
++	.unlocked_ioctl = mtp_ioctl,
++	.open = mtp_open,
++	.release = mtp_release,
++};
++
++static struct miscdevice mtp_device = {
++	.minor = MISC_DYNAMIC_MINOR,
++	.name = mtp_shortname,
++	.fops = &mtp_fops,
++};
++
++static int mtp_ctrlrequest(struct usb_composite_dev *cdev,
++				const struct usb_ctrlrequest *ctrl)
++{
++	struct mtp_dev *dev = _mtp_dev;
++	int	value = -EOPNOTSUPP;
++	u16	w_index = le16_to_cpu(ctrl->wIndex);
++	u16	w_value = le16_to_cpu(ctrl->wValue);
++	u16	w_length = le16_to_cpu(ctrl->wLength);
++	unsigned long	flags;
++
++	VDBG(cdev, "mtp_ctrlrequest "
++			"%02x.%02x v%04x i%04x l%u\n",
++			ctrl->bRequestType, ctrl->bRequest,
++			w_value, w_index, w_length);
++
++	/* Handle MTP OS string */
++	if (ctrl->bRequestType ==
++			(USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE)
++			&& ctrl->bRequest == USB_REQ_GET_DESCRIPTOR
++			&& (w_value >> 8) == USB_DT_STRING
++			&& (w_value & 0xFF) == MTP_OS_STRING_ID) {
++		value = (w_length < sizeof(mtp_os_string)
++				? w_length : sizeof(mtp_os_string));
++		memcpy(cdev->req->buf, mtp_os_string, value);
++	} else if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_VENDOR) {
++		/* Handle MTP OS descriptor */
++		DBG(cdev, "vendor request: %d index: %d value: %d length: %d\n",
++			ctrl->bRequest, w_index, w_value, w_length);
++
++		if (ctrl->bRequest == 1
++				&& (ctrl->bRequestType & USB_DIR_IN)
++				&& (w_index == 4 || w_index == 5)) {
++			value = (w_length < sizeof(mtp_ext_config_desc) ?
++					w_length : sizeof(mtp_ext_config_desc));
++			memcpy(cdev->req->buf, &mtp_ext_config_desc, value);
++		}
++	} else if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_CLASS) {
++		DBG(cdev, "class request: %d index: %d value: %d length: %d\n",
++			ctrl->bRequest, w_index, w_value, w_length);
++
++		if (ctrl->bRequest == MTP_REQ_CANCEL && w_index == 0
++				&& w_value == 0) {
++			DBG(cdev, "MTP_REQ_CANCEL\n");
++
++			spin_lock_irqsave(&dev->lock, flags);
++			if (dev->state == STATE_BUSY) {
++				dev->state = STATE_CANCELED;
++				wake_up(&dev->read_wq);
++				wake_up(&dev->write_wq);
++			}
++			spin_unlock_irqrestore(&dev->lock, flags);
++
++			/* We need to queue a request to read the remaining
++			 *  bytes, but we don't actually need to look at
++			 * the contents.
++			 */
++			value = w_length;
++		} else if (ctrl->bRequest == MTP_REQ_GET_DEVICE_STATUS
++				&& w_index == 0 && w_value == 0) {
++			struct mtp_device_status *status = cdev->req->buf;
++			status->wLength =
++				__constant_cpu_to_le16(sizeof(*status));
++
++			DBG(cdev, "MTP_REQ_GET_DEVICE_STATUS\n");
++			spin_lock_irqsave(&dev->lock, flags);
++			/* device status is "busy" until we report
++			 * the cancelation to userspace
++			 */
++			if (dev->state == STATE_CANCELED)
++				status->wCode =
++					__cpu_to_le16(MTP_RESPONSE_DEVICE_BUSY);
++			else
++				status->wCode =
++					__cpu_to_le16(MTP_RESPONSE_OK);
++			spin_unlock_irqrestore(&dev->lock, flags);
++			value = sizeof(*status);
++		}
++	}
++
++	/* respond with data transfer or status phase? */
++	if (value >= 0) {
++		int rc;
++		cdev->req->zero = value < w_length;
++		cdev->req->length = value;
++		rc = usb_ep_queue(cdev->gadget->ep0, cdev->req, GFP_ATOMIC);
++		if (rc < 0)
++			ERROR(cdev, "%s: response queue error\n", __func__);
++	}
++	return value;
++}
++
++static int
++mtp_function_bind(struct usb_configuration *c, struct usb_function *f)
++{
++	struct usb_composite_dev *cdev = c->cdev;
++	struct mtp_dev	*dev = func_to_mtp(f);
++	int			id;
++	int			ret;
++
++	dev->cdev = cdev;
++	DBG(cdev, "mtp_function_bind dev: %p\n", dev);
++
++	/* allocate interface ID(s) */
++	id = usb_interface_id(c, f);
++	if (id < 0)
++		return id;
++	mtp_interface_desc.bInterfaceNumber = id;
++
++	if (mtp_string_defs[INTERFACE_STRING_INDEX].id == 0) {
++		ret = usb_string_id(c->cdev);
++		if (ret < 0)
++			return ret;
++		mtp_string_defs[INTERFACE_STRING_INDEX].id = ret;
++		mtp_interface_desc.iInterface = ret;
++	}
++	/* allocate endpoints */
++	ret = mtp_create_bulk_endpoints(dev, &mtp_fullspeed_in_desc,
++			&mtp_fullspeed_out_desc, &mtp_intr_desc);
++	if (ret)
++		return ret;
++
++	/* support high speed hardware */
++	if (gadget_is_dualspeed(c->cdev->gadget)) {
++		mtp_highspeed_in_desc.bEndpointAddress =
++			mtp_fullspeed_in_desc.bEndpointAddress;
++		mtp_highspeed_out_desc.bEndpointAddress =
++			mtp_fullspeed_out_desc.bEndpointAddress;
++	}
++
++	DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n",
++			gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
++			f->name, dev->ep_in->name, dev->ep_out->name);
++	return 0;
++}
++
++static void
++mtp_function_unbind(struct usb_configuration *c, struct usb_function *f)
++{
++	struct mtp_dev	*dev = func_to_mtp(f);
++	struct usb_request *req;
++	int i;
++
++	mtp_string_defs[INTERFACE_STRING_INDEX].id = 0;
++	while ((req = mtp_req_get(dev, &dev->tx_idle)))
++		mtp_request_free(req, dev->ep_in);
++	for (i = 0; i < RX_REQ_MAX; i++)
++		mtp_request_free(dev->rx_req[i], dev->ep_out);
++	while ((req = mtp_req_get(dev, &dev->intr_idle)))
++		mtp_request_free(req, dev->ep_intr);
++	dev->state = STATE_OFFLINE;
++}
++
++static int mtp_function_set_alt(struct usb_function *f,
++		unsigned intf, unsigned alt)
++{
++	struct mtp_dev	*dev = func_to_mtp(f);
++	struct usb_composite_dev *cdev = f->config->cdev;
++	int ret;
++
++	DBG(cdev, "mtp_function_set_alt intf: %d alt: %d\n", intf, alt);
++
++	ret = config_ep_by_speed(cdev->gadget, f, dev->ep_in);
++	if (ret)
++		return ret;
++
++	ret = usb_ep_enable(dev->ep_in);
++	if (ret)
++		return ret;
++
++	ret = config_ep_by_speed(cdev->gadget, f, dev->ep_out);
++	if (ret)
++		return ret;
++
++	ret = usb_ep_enable(dev->ep_out);
++	if (ret) {
++		usb_ep_disable(dev->ep_in);
++		return ret;
++	}
++
++	ret = config_ep_by_speed(cdev->gadget, f, dev->ep_intr);
++	if (ret)
++		return ret;
++
++	ret = usb_ep_enable(dev->ep_intr);
++	if (ret) {
++		usb_ep_disable(dev->ep_out);
++		usb_ep_disable(dev->ep_in);
++		return ret;
++	}
++	dev->state = STATE_READY;
++
++	/* readers may be blocked waiting for us to go online */
++	wake_up(&dev->read_wq);
++	return 0;
++}
++
++static void mtp_function_disable(struct usb_function *f)
++{
++	struct mtp_dev	*dev = func_to_mtp(f);
++	struct usb_composite_dev	*cdev = dev->cdev;
++
++	DBG(cdev, "mtp_function_disable\n");
++	dev->state = STATE_OFFLINE;
++	usb_ep_disable(dev->ep_in);
++	usb_ep_disable(dev->ep_out);
++	usb_ep_disable(dev->ep_intr);
++
++	/* readers may be blocked waiting for us to go online */
++	wake_up(&dev->read_wq);
++
++	VDBG(cdev, "%s disabled\n", dev->function.name);
++}
++
++static int __maybe_unused mtp_bind_config(struct usb_configuration *c, bool ptp_config)
++{
++	struct mtp_dev *dev = _mtp_dev;
++	int ret = 0;
++
++	printk(KERN_INFO "mtp_bind_config\n");
++
++	/* allocate a string ID for our interface */
++	if (mtp_string_defs[INTERFACE_STRING_INDEX].id == 0) {
++		ret = usb_string_id(c->cdev);
++		if (ret < 0)
++			return ret;
++		mtp_string_defs[INTERFACE_STRING_INDEX].id = ret;
++		mtp_interface_desc.iInterface = ret;
++	}
++
++	dev->cdev = c->cdev;
++	dev->function.name = DRIVER_NAME;
++	dev->function.strings = mtp_strings;
++	if (ptp_config) {
++		dev->function.fs_descriptors = fs_ptp_descs;
++		dev->function.hs_descriptors = hs_ptp_descs;
++	} else {
++		dev->function.fs_descriptors = fs_mtp_descs;
++		dev->function.hs_descriptors = hs_mtp_descs;
++	}
++	dev->function.bind = mtp_function_bind;
++	dev->function.unbind = mtp_function_unbind;
++	dev->function.set_alt = mtp_function_set_alt;
++	dev->function.disable = mtp_function_disable;
++
++	return usb_add_function(c, &dev->function);
++}
++
++static int __mtp_setup(struct mtp_instance *fi_mtp)
++{
++	struct mtp_dev *dev;
++	int ret;
++
++	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
++
++	if (fi_mtp != NULL)
++		fi_mtp->dev = dev;
++
++	if (!dev)
++		return -ENOMEM;
++
++	spin_lock_init(&dev->lock);
++	init_waitqueue_head(&dev->read_wq);
++	init_waitqueue_head(&dev->write_wq);
++	init_waitqueue_head(&dev->intr_wq);
++	atomic_set(&dev->open_excl, 0);
++	atomic_set(&dev->ioctl_excl, 0);
++	INIT_LIST_HEAD(&dev->tx_idle);
++	INIT_LIST_HEAD(&dev->intr_idle);
++
++	dev->wq = create_singlethread_workqueue("f_mtp");
++	if (!dev->wq) {
++		ret = -ENOMEM;
++		goto err1;
++	}
++	INIT_WORK(&dev->send_file_work, send_file_work);
++	INIT_WORK(&dev->receive_file_work, receive_file_work);
++
++	_mtp_dev = dev;
++
++	ret = misc_register(&mtp_device);
++	if (ret)
++		goto err2;
++
++	return 0;
++
++err2:
++	destroy_workqueue(dev->wq);
++err1:
++	_mtp_dev = NULL;
++	kfree(dev);
++	printk(KERN_ERR "mtp gadget driver failed to initialize\n");
++	return ret;
++}
++
++static int __maybe_unused mtp_setup(void)
++{
++	return __mtp_setup(NULL);
++}
++
++static int mtp_setup_configfs(struct mtp_instance *fi_mtp)
++{
++	return __mtp_setup(fi_mtp);
++}
++
++
++static void mtp_cleanup(void)
++{
++	struct mtp_dev *dev = _mtp_dev;
++
++	if (!dev)
++		return;
++
++	misc_deregister(&mtp_device);
++	destroy_workqueue(dev->wq);
++	_mtp_dev = NULL;
++	kfree(dev);
++}
++
++static struct mtp_instance *to_mtp_instance(struct config_item *item)
++{
++	return container_of(to_config_group(item), struct mtp_instance,
++		func_inst.group);
++}
++
++static void mtp_attr_release(struct config_item *item)
++{
++	struct mtp_instance *fi_mtp = to_mtp_instance(item);
++	usb_put_function_instance(&fi_mtp->func_inst);
++}
++
++static struct configfs_item_operations mtp_item_ops = {
++	.release        = mtp_attr_release,
++};
++
++static struct config_item_type mtp_func_type = {
++	.ct_item_ops    = &mtp_item_ops,
++	.ct_owner       = THIS_MODULE,
++};
++
++
++static struct mtp_instance *to_fi_mtp(struct usb_function_instance *fi)
++{
++	return container_of(fi, struct mtp_instance, func_inst);
++}
++
++static int mtp_set_inst_name(struct usb_function_instance *fi, const char *name)
++{
++	struct mtp_instance *fi_mtp;
++	char *ptr;
++	int name_len;
++
++	name_len = strlen(name) + 1;
++	if (name_len > MAX_INST_NAME_LEN)
++		return -ENAMETOOLONG;
++
++	ptr = kstrndup(name, name_len, GFP_KERNEL);
++	if (!ptr)
++		return -ENOMEM;
++
++	fi_mtp = to_fi_mtp(fi);
++	fi_mtp->name = ptr;
++
++	return 0;
++}
++
++static void mtp_free_inst(struct usb_function_instance *fi)
++{
++	struct mtp_instance *fi_mtp;
++
++	fi_mtp = to_fi_mtp(fi);
++	kfree(fi_mtp->name);
++	mtp_cleanup();
++	kfree(fi_mtp);
++}
++
++struct usb_function_instance *alloc_inst_mtp_ptp(bool mtp_config)
++{
++	struct mtp_instance *fi_mtp;
++	int ret = 0;
++
++	fi_mtp = kzalloc(sizeof(*fi_mtp), GFP_KERNEL);
++	if (!fi_mtp)
++		return ERR_PTR(-ENOMEM);
++	fi_mtp->func_inst.set_inst_name = mtp_set_inst_name;
++	fi_mtp->func_inst.free_func_inst = mtp_free_inst;
++
++	if (mtp_config) {
++		ret = mtp_setup_configfs(fi_mtp);
++		if (ret) {
++			kfree(fi_mtp);
++			pr_err("Error setting MTP\n");
++			return ERR_PTR(ret);
++		}
++	} else
++		fi_mtp->dev = _mtp_dev;
++
++	config_group_init_type_name(&fi_mtp->func_inst.group,
++					"", &mtp_func_type);
++
++	return  &fi_mtp->func_inst;
++}
++EXPORT_SYMBOL_GPL(alloc_inst_mtp_ptp);
++
++static struct usb_function_instance *mtp_alloc_inst(void)
++{
++		return alloc_inst_mtp_ptp(true);
++}
++
++static int mtp_ctrlreq_configfs(struct usb_function *f,
++				const struct usb_ctrlrequest *ctrl)
++{
++	return mtp_ctrlrequest(f->config->cdev, ctrl);
++}
++
++static void mtp_free(struct usb_function *f)
++{
++	/*NO-OP: no function specific resource allocation in mtp_alloc*/
++}
++
++struct usb_function *function_alloc_mtp_ptp(struct usb_function_instance *fi,
++					bool mtp_config)
++{
++	struct mtp_instance *fi_mtp = to_fi_mtp(fi);
++	struct mtp_dev *dev;
++
++	/*
++	 * PTP piggybacks on MTP function so make sure we have
++	 * created MTP function before we associate this PTP
++	 * function with a gadget configuration.
++	 */
++	if (fi_mtp->dev == NULL) {
++		pr_err("Error: Create MTP function before linking"
++				" PTP function with a gadget configuration\n");
++		pr_err("\t1: Delete existing PTP function if any\n");
++		pr_err("\t2: Create MTP function\n");
++		pr_err("\t3: Create and symlink PTP function"
++				" with a gadget configuration\n");
++		return NULL;
++	}
++
++	dev = fi_mtp->dev;
++	dev->function.name = DRIVER_NAME;
++	dev->function.strings = mtp_strings;
++	if (mtp_config) {
++		dev->function.fs_descriptors = fs_mtp_descs;
++		dev->function.hs_descriptors = hs_mtp_descs;
++	} else {
++		dev->function.fs_descriptors = fs_ptp_descs;
++		dev->function.hs_descriptors = hs_ptp_descs;
++	}
++	dev->function.bind = mtp_function_bind;
++	dev->function.unbind = mtp_function_unbind;
++	dev->function.set_alt = mtp_function_set_alt;
++	dev->function.disable = mtp_function_disable;
++	dev->function.setup = mtp_ctrlreq_configfs;
++	dev->function.free_func = mtp_free;
++
++	return &dev->function;
++}
++EXPORT_SYMBOL_GPL(function_alloc_mtp_ptp);
++
++static struct usb_function *mtp_alloc(struct usb_function_instance *fi)
++{
++	return function_alloc_mtp_ptp(fi, true);
++}
++
++DECLARE_USB_FUNCTION_INIT(mtp, mtp_alloc_inst, mtp_alloc);
++MODULE_LICENSE("GPL");
+diff --git a/drivers/usb/gadget/function/f_mtp.h b/drivers/usb/gadget/function/f_mtp.h
+new file mode 100644
+index 0000000..7adb1ff
+--- /dev/null
++++ b/drivers/usb/gadget/function/f_mtp.h
+@@ -0,0 +1,18 @@
++/*
++ * Copyright (C) 2014 Google, Inc.
++ * Author: Badhri Jagan Sridharan <badhri@android.com>
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * 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.
++ *
++ */
++
++extern struct usb_function_instance *alloc_inst_mtp_ptp(bool mtp_config);
++extern struct usb_function *function_alloc_mtp_ptp(
++			struct usb_function_instance *fi, bool mtp_config);
+diff --git a/drivers/usb/gadget/function/f_ptp.c b/drivers/usb/gadget/function/f_ptp.c
+new file mode 100644
+index 0000000..da3e4d5
+--- /dev/null
++++ b/drivers/usb/gadget/function/f_ptp.c
+@@ -0,0 +1,38 @@
++/*
++ * Gadget Function Driver for PTP
++ *
++ * Copyright (C) 2014 Google, Inc.
++ * Author: Badhri Jagan Sridharan <badhri@android.com>
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/types.h>
++
++#include <linux/configfs.h>
++#include <linux/usb/composite.h>
++
++#include "f_mtp.h"
++
++static struct usb_function_instance *ptp_alloc_inst(void)
++{
++	return alloc_inst_mtp_ptp(false);
++}
++
++static struct usb_function *ptp_alloc(struct usb_function_instance *fi)
++{
++	return function_alloc_mtp_ptp(fi, false);
++}
++
++DECLARE_USB_FUNCTION_INIT(ptp, ptp_alloc_inst, ptp_alloc);
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Badhri Jagan Sridharan");
+diff --git a/drivers/usb/gadget/function/f_rndis.c b/drivers/usb/gadget/function/f_rndis.c
+index f13fc6a..f4286a4 100644
+--- a/drivers/usb/gadget/function/f_rndis.c
++++ b/drivers/usb/gadget/function/f_rndis.c
+@@ -70,6 +70,16 @@
+  *   - MS-Windows drivers sometimes emit undocumented requests.
+  */
+ 
++static unsigned int rndis_dl_max_pkt_per_xfer = 3;
++module_param(rndis_dl_max_pkt_per_xfer, uint, S_IRUGO | S_IWUSR);
++MODULE_PARM_DESC(rndis_dl_max_pkt_per_xfer,
++	"Maximum packets per transfer for DL aggregation");
++
++static unsigned int rndis_ul_max_pkt_per_xfer = 3;
++module_param(rndis_ul_max_pkt_per_xfer, uint, S_IRUGO | S_IWUSR);
++MODULE_PARM_DESC(rndis_ul_max_pkt_per_xfer,
++       "Maximum packets per transfer for UL aggregation");
++
+ struct f_rndis {
+ 	struct gether			port;
+ 	u8				ctrl_id, data_id;
+@@ -378,7 +388,7 @@ static struct sk_buff *rndis_add_header(struct gether *port,
+ 	if (skb2)
+ 		rndis_add_hdr(skb2);
+ 
+-	dev_kfree_skb(skb);
++	dev_kfree_skb_irq(skb);
+ 	return skb2;
+ }
+ 
+@@ -451,6 +461,7 @@ static void rndis_command_complete(struct usb_ep *ep, struct usb_request *req)
+ {
+ 	struct f_rndis			*rndis = req->context;
+ 	int				status;
++	rndis_init_msg_type		*buf;
+ 
+ 	/* received RNDIS command from USB_CDC_SEND_ENCAPSULATED_COMMAND */
+ //	spin_lock(&dev->lock);
+@@ -458,6 +469,21 @@ static void rndis_command_complete(struct usb_ep *ep, struct usb_request *req)
+ 	if (status < 0)
+ 		pr_err("RNDIS command error %d, %d/%d\n",
+ 			status, req->actual, req->length);
++
++	buf = (rndis_init_msg_type *)req->buf;
++
++	if (buf->MessageType == RNDIS_MSG_INIT) {
++		if (buf->MaxTransferSize > 2048)
++			rndis->port.multi_pkt_xfer = 1;
++		else
++			rndis->port.multi_pkt_xfer = 0;
++		pr_info_once("%s: MaxTransferSize: %d : Multi_pkt_txr: %s\n",
++				__func__, buf->MaxTransferSize,
++				rndis->port.multi_pkt_xfer ? "enabled" :
++							    "disabled");
++		if (rndis_dl_max_pkt_per_xfer <= 1)
++			rndis->port.multi_pkt_xfer = 0;
++	}
+ //	spin_unlock(&dev->lock);
+ }
+ 
+@@ -799,6 +825,7 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
+ 
+ 	rndis_set_param_medium(rndis->config, RNDIS_MEDIUM_802_3, 0);
+ 	rndis_set_host_mac(rndis->config, rndis->ethaddr);
++	rndis_set_max_pkt_xfer(rndis->config, rndis_ul_max_pkt_per_xfer);
+ 
+ 	if (rndis->manufacturer && rndis->vendorID &&
+ 			rndis_set_param_vendor(rndis->config, rndis->vendorID,
+@@ -843,6 +870,62 @@ fail:
+ 	return status;
+ }
+ 
++static void
++rndis_old_unbind(struct usb_configuration *c, struct usb_function *f)
++{
++	struct f_rndis          *rndis = func_to_rndis(f);
++
++	rndis_deregister(rndis->config);
++
++	usb_free_all_descriptors(f);
++
++	kfree(rndis->notify_req->buf);
++	usb_ep_free_request(rndis->notify, rndis->notify_req);
++
++	kfree(rndis);
++}
++
++int
++rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
++		u32 vendorID, const char *manufacturer, struct eth_dev *dev)
++{
++	struct f_rndis  *rndis;
++	int             status;
++
++	/* allocate and initialize one new instance */
++	status = -ENOMEM;
++	rndis = kzalloc(sizeof *rndis, GFP_KERNEL);
++	if (!rndis)
++		goto fail;
++
++	memcpy(rndis->ethaddr, ethaddr, ETH_ALEN);
++	rndis->vendorID = vendorID;
++	rndis->manufacturer = manufacturer;
++
++	rndis->port.ioport = dev;
++	/* RNDIS activates when the host changes this filter */
++	rndis->port.cdc_filter = 0;
++
++	/* RNDIS has special (and complex) framing */
++	rndis->port.header_len = sizeof(struct rndis_packet_msg_type);
++	rndis->port.wrap = rndis_add_header;
++	rndis->port.unwrap = rndis_rm_hdr;
++
++	rndis->port.func.name = "rndis";
++	/* descriptors are per-instance copies */
++	rndis->port.func.bind = rndis_bind;
++	rndis->port.func.unbind = rndis_old_unbind;
++	rndis->port.func.set_alt = rndis_set_alt;
++	rndis->port.func.setup = rndis_setup;
++	rndis->port.func.disable = rndis_disable;
++
++	status = usb_add_function(c, &rndis->port.func);
++	if (status)
++		kfree(rndis);
++fail:
++	return status;
++}
++
+ void rndis_borrow_net(struct usb_function_instance *f, struct net_device *net)
+ {
+ 	struct f_rndis_opts *opts;
+@@ -993,6 +1076,8 @@ static struct usb_function *rndis_alloc(struct usb_function_instance *fi)
+ 	rndis->port.header_len = sizeof(struct rndis_packet_msg_type);
+ 	rndis->port.wrap = rndis_add_header;
+ 	rndis->port.unwrap = rndis_rm_hdr;
++	rndis->port.ul_max_pkts_per_xfer = rndis_ul_max_pkt_per_xfer;
++	rndis->port.dl_max_pkts_per_xfer = rndis_dl_max_pkt_per_xfer;
+ 
+ 	rndis->port.func.name = "rndis";
+ 	/* descriptors are per-instance copies */
+diff --git a/drivers/usb/gadget/function/f_uac1.c b/drivers/usb/gadget/function/f_uac1.c
+index f7b2032..4a4823b 100644
+--- a/drivers/usb/gadget/function/f_uac1.c
++++ b/drivers/usb/gadget/function/f_uac1.c
+@@ -1,24 +1,61 @@
+ /*
+- * f_audio.c -- USB Audio class function driver
+-  *
+- * Copyright (C) 2008 Bryan Wu <cooloney@kernel.org>
+- * Copyright (C) 2008 Analog Devices, Inc
++ * f_uac1.c -- USB Audio Class 1.0 Function (using u_audio API)
+  *
+- * Enter bugs at http://blackfin.uclinux.org/
++ * Copyright (C) 2016 Ruslan Bilovol <ruslan.bilovol@gmail.com>
+  *
+- * Licensed under the GPL-2 or later.
++ * This driver doesn't expect any real Audio codec to be present
++ * on the device - the audio streams are simply sinked to and
++ * sourced from a virtual ALSA sound card created.
++ *
++ * This file is based on f_uac1.c which is
++ *   Copyright (C) 2008 Bryan Wu <cooloney@kernel.org>
++ *   Copyright (C) 2008 Analog Devices, 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.
+  */
+ 
+-#include <linux/slab.h>
+-#include <linux/kernel.h>
++#include <linux/usb/audio.h>
+ #include <linux/module.h>
+-#include <linux/device.h>
+-#include <linux/atomic.h>
+ 
++#include <media/v4l2-dev.h>
++#include <media/v4l2-event.h>
++#include "uac_ex.h"
++#include "uac_v4l2_ex.h"
+ #include "u_uac1.h"
+ 
+-static int generic_set_cmd(struct usb_audio_control *con, u8 cmd, int value);
+-static int generic_get_cmd(struct usb_audio_control *con, u8 cmd);
++struct f_uac1 {
++	struct uac_device uac_dev;
++	u8 ac_intf, as_in_intf, as_out_intf;
++	u8 ac_alt, as_in_alt, as_out_alt;	/* needed for get_alt() */
++};
++
++struct uac1_format_type_ii_discrete_descriptor {
++    __u8 bLength;
++    __u8 bDescriptorType;
++    __u8 bDescriptorSubtype;
++    __u8 bFormatType;
++    __le16 wMaxBitRate;
++    __le16 wSamplesPerFrame;
++    __u8 bSamFreqType;
++    __u8 tSamFreq[4][3];
++} __attribute__((packed));
++
++struct uac1_format_type_ii_ac3_descriptor {
++    __u8 bLength;
++    __u8 bDescriptorType;
++    __u8 bDescriptorSubtype;
++    __le16 wFormatTag;
++    __u8 bmBSID[4];
++    __u8 bmAC3Features;
++} __attribute__((packed));
++
++static inline struct f_uac1 *func_to_uac1(struct usb_function *f)
++{
++	return container_of(f, struct f_uac1, uac_dev.func);
++}
+ 
+ /*
+  * DESCRIPTORS ... most are static, but strings and full
+@@ -26,12 +63,28 @@ static int generic_get_cmd(struct usb_audio_control *con, u8 cmd);
+  */
+ 
+ /*
+- * We have two interfaces- AudioControl and AudioStreaming
+- * TODO: only supcard playback currently
++ * We have three interfaces - one AudioControl and two AudioStreaming
++ *
++ * The driver implements a simple UAC_1 topology.
++ * USB-OUT -> IT_1 -> OT_2 -> ALSA_Capture
++ * ALSA_Playback -> IT_3 -> OT_4 -> USB-IN
+  */
+-#define F_AUDIO_AC_INTERFACE	0
+-#define F_AUDIO_AS_INTERFACE	1
+-#define F_AUDIO_NUM_INTERFACES	2
++#define F_AUDIO_AC_INTERFACE		0
++#define F_AUDIO_AS_OUT_INTERFACE	1
++#define F_AUDIO_AS_IN_INTERFACE		2
++/* Number of streaming interfaces */
++#define F_AUDIO_NUM_INTERFACES		1
++
++static struct usb_interface_assoc_descriptor uac_iad = {
++	.bLength		= sizeof(uac_iad),
++	.bDescriptorType	= USB_DT_INTERFACE_ASSOCIATION,
++	.bFirstInterface	= 0,
++	.bInterfaceCount	= 2,
++	.bFunctionClass		= USB_CLASS_AUDIO,
++	.bFunctionSubClass	= 0x00,
++	.bFunctionProtocol	= 0x00,
++	.iFunction		= 0,
++};
+ 
+ /* B.3.1  Standard AC Interface Descriptor */
+ static struct usb_interface_descriptor ac_interface_desc = {
+@@ -42,89 +95,96 @@ static struct usb_interface_descriptor ac_interface_desc = {
+ 	.bInterfaceSubClass =	USB_SUBCLASS_AUDIOCONTROL,
+ };
+ 
+-DECLARE_UAC_AC_HEADER_DESCRIPTOR(2);
++/*
++ * The number of AudioStreaming and MIDIStreaming interfaces
++ * in the Audio Interface Collection
++ */
++DECLARE_UAC_AC_HEADER_DESCRIPTOR(1);
+ 
+ #define UAC_DT_AC_HEADER_LENGTH	UAC_DT_AC_HEADER_SIZE(F_AUDIO_NUM_INTERFACES)
+-/* 1 input terminal, 1 output terminal and 1 feature unit */
+-#define UAC_DT_TOTAL_LENGTH (UAC_DT_AC_HEADER_LENGTH + UAC_DT_INPUT_TERMINAL_SIZE \
+-	+ UAC_DT_OUTPUT_TERMINAL_SIZE + UAC_DT_FEATURE_UNIT_SIZE(0))
++
++/* 2 input terminals and 2 output terminals */
++#define UAC_DT_TOTAL_LENGTH (UAC_DT_AC_HEADER_LENGTH \
++	+ 1*UAC_DT_INPUT_TERMINAL_SIZE + 1*UAC_DT_OUTPUT_TERMINAL_SIZE)
++
+ /* B.3.2  Class-Specific AC Interface Descriptor */
+-static struct uac1_ac_header_descriptor_2 ac_header_desc = {
++static struct uac1_ac_header_descriptor_1 ac_header_desc = {
+ 	.bLength =		UAC_DT_AC_HEADER_LENGTH,
+ 	.bDescriptorType =	USB_DT_CS_INTERFACE,
+ 	.bDescriptorSubtype =	UAC_HEADER,
+-	.bcdADC =		__constant_cpu_to_le16(0x0100),
+-	.wTotalLength =		__constant_cpu_to_le16(UAC_DT_TOTAL_LENGTH),
++	.bcdADC =		cpu_to_le16(0x0100),
++	.wTotalLength =		cpu_to_le16(UAC_DT_TOTAL_LENGTH),
+ 	.bInCollection =	F_AUDIO_NUM_INTERFACES,
+ 	.baInterfaceNr = {
+-		[0] =		F_AUDIO_AC_INTERFACE,
+-		[1] =		F_AUDIO_AS_INTERFACE,
++	/* Interface number of the AudioStream interfaces */
++		[0] =		1,
+ 	}
+ };
+ 
+-#define INPUT_TERMINAL_ID	1
+-static struct uac_input_terminal_descriptor input_terminal_desc = {
++#define USB_OUT_IT_ID	1
++static struct uac_input_terminal_descriptor usb_out_it_desc = {
+ 	.bLength =		UAC_DT_INPUT_TERMINAL_SIZE,
+ 	.bDescriptorType =	USB_DT_CS_INTERFACE,
+ 	.bDescriptorSubtype =	UAC_INPUT_TERMINAL,
+-	.bTerminalID =		INPUT_TERMINAL_ID,
+-	.wTerminalType =	UAC_TERMINAL_STREAMING,
++	.bTerminalID =		USB_OUT_IT_ID,
++	.wTerminalType =	cpu_to_le16(UAC_TERMINAL_STREAMING),
+ 	.bAssocTerminal =	0,
+-	.wChannelConfig =	0x3,
++	.wChannelConfig =	cpu_to_le16(0x3),
+ };
+ 
+-DECLARE_UAC_FEATURE_UNIT_DESCRIPTOR(0);
+-
+-#define FEATURE_UNIT_ID		2
+-static struct uac_feature_unit_descriptor_0 feature_unit_desc = {
+-	.bLength		= UAC_DT_FEATURE_UNIT_SIZE(0),
++#define IO_OUT_OT_ID	2
++static struct uac1_output_terminal_descriptor io_out_ot_desc = {
++	.bLength		= UAC_DT_OUTPUT_TERMINAL_SIZE,
+ 	.bDescriptorType	= USB_DT_CS_INTERFACE,
+-	.bDescriptorSubtype	= UAC_FEATURE_UNIT,
+-	.bUnitID		= FEATURE_UNIT_ID,
+-	.bSourceID		= INPUT_TERMINAL_ID,
+-	.bControlSize		= 2,
+-	.bmaControls[0]		= (UAC_FU_MUTE | UAC_FU_VOLUME),
++	.bDescriptorSubtype	= UAC_OUTPUT_TERMINAL,
++	.bTerminalID		= IO_OUT_OT_ID,
++	.wTerminalType		= cpu_to_le16(UAC_OUTPUT_TERMINAL_SPEAKER),
++	.bAssocTerminal		= 0,
++	.bSourceID		= USB_OUT_IT_ID,
+ };
+ 
+-static struct usb_audio_control mute_control = {
+-	.list = LIST_HEAD_INIT(mute_control.list),
+-	.name = "Mute Control",
+-	.type = UAC_FU_MUTE,
+-	/* Todo: add real Mute control code */
+-	.set = generic_set_cmd,
+-	.get = generic_get_cmd,
++#define IO_IN_IT_ID	3
++static struct uac_input_terminal_descriptor io_in_it_desc = {
++	.bLength		= UAC_DT_INPUT_TERMINAL_SIZE,
++	.bDescriptorType	= USB_DT_CS_INTERFACE,
++	.bDescriptorSubtype	= UAC_INPUT_TERMINAL,
++	.bTerminalID		= IO_IN_IT_ID,
++	.wTerminalType		= cpu_to_le16(UAC_INPUT_TERMINAL_MICROPHONE),
++	.bAssocTerminal		= 0,
++	.wChannelConfig		= cpu_to_le16(0x3),
+ };
+ 
+-static struct usb_audio_control volume_control = {
+-	.list = LIST_HEAD_INIT(volume_control.list),
+-	.name = "Volume Control",
+-	.type = UAC_FU_VOLUME,
+-	/* Todo: add real Volume control code */
+-	.set = generic_set_cmd,
+-	.get = generic_get_cmd,
++#define USB_IN_OT_ID	4
++static struct uac1_output_terminal_descriptor usb_in_ot_desc = {
++	.bLength =		UAC_DT_OUTPUT_TERMINAL_SIZE,
++	.bDescriptorType =	USB_DT_CS_INTERFACE,
++	.bDescriptorSubtype =	UAC_OUTPUT_TERMINAL,
++	.bTerminalID =		USB_IN_OT_ID,
++	.wTerminalType =	cpu_to_le16(UAC_TERMINAL_STREAMING),
++	.bAssocTerminal =	0,
++	.bSourceID =		IO_IN_IT_ID,
+ };
+ 
+-static struct usb_audio_control_selector feature_unit = {
+-	.list = LIST_HEAD_INIT(feature_unit.list),
+-	.id = FEATURE_UNIT_ID,
+-	.name = "Mute & Volume Control",
+-	.type = UAC_FEATURE_UNIT,
+-	.desc = (struct usb_descriptor_header *)&feature_unit_desc,
++/* B.4.1  Standard AS Interface Descriptor */
++static struct usb_interface_descriptor as_out_interface_alt_0_desc = {
++	.bLength =		USB_DT_INTERFACE_SIZE,
++	.bDescriptorType =	USB_DT_INTERFACE,
++	.bAlternateSetting =	0,
++	.bNumEndpoints =	0,
++	.bInterfaceClass =	USB_CLASS_AUDIO,
++	.bInterfaceSubClass =	USB_SUBCLASS_AUDIOSTREAMING,
+ };
+ 
+-#define OUTPUT_TERMINAL_ID	3
+-static struct uac1_output_terminal_descriptor output_terminal_desc = {
+-	.bLength		= UAC_DT_OUTPUT_TERMINAL_SIZE,
+-	.bDescriptorType	= USB_DT_CS_INTERFACE,
+-	.bDescriptorSubtype	= UAC_OUTPUT_TERMINAL,
+-	.bTerminalID		= OUTPUT_TERMINAL_ID,
+-	.wTerminalType		= UAC_OUTPUT_TERMINAL_SPEAKER,
+-	.bAssocTerminal		= FEATURE_UNIT_ID,
+-	.bSourceID		= FEATURE_UNIT_ID,
++static struct usb_interface_descriptor as_out_interface_alt_1_desc = {
++	.bLength =		USB_DT_INTERFACE_SIZE,
++	.bDescriptorType =	USB_DT_INTERFACE,
++	.bAlternateSetting =	1,
++	.bNumEndpoints =	1,
++	.bInterfaceClass =	USB_CLASS_AUDIO,
++	.bInterfaceSubClass =	USB_SUBCLASS_AUDIOSTREAMING,
+ };
+ 
+-/* B.4.1  Standard AS Interface Descriptor */
+-static struct usb_interface_descriptor as_interface_alt_0_desc = {
++static struct usb_interface_descriptor as_in_interface_alt_0_desc = {
+ 	.bLength =		USB_DT_INTERFACE_SIZE,
+ 	.bDescriptorType =	USB_DT_INTERFACE,
+ 	.bAlternateSetting =	0,
+@@ -133,7 +193,7 @@ static struct usb_interface_descriptor as_interface_alt_0_desc = {
+ 	.bInterfaceSubClass =	USB_SUBCLASS_AUDIOSTREAMING,
+ };
+ 
+-static struct usb_interface_descriptor as_interface_alt_1_desc = {
++static struct usb_interface_descriptor as_in_interface_alt_1_desc = {
+ 	.bLength =		USB_DT_INTERFACE_SIZE,
+ 	.bDescriptorType =	USB_DT_INTERFACE,
+ 	.bAlternateSetting =	1,
+@@ -142,26 +202,62 @@ static struct usb_interface_descriptor as_interface_alt_1_desc = {
+ 	.bInterfaceSubClass =	USB_SUBCLASS_AUDIOSTREAMING,
+ };
+ 
++static struct usb_interface_descriptor as_in_interface_alt_2_desc = {
++    .bLength =        USB_DT_INTERFACE_SIZE,
++    .bDescriptorType =    USB_DT_INTERFACE,
++    .bAlternateSetting =    2,
++    .bNumEndpoints =    1,
++    .bInterfaceClass =    USB_CLASS_AUDIO,
++    .bInterfaceSubClass =    USB_SUBCLASS_AUDIOSTREAMING,
++};
++
+ /* B.4.2  Class-Specific AS Interface Descriptor */
+-static struct uac1_as_header_descriptor as_header_desc = {
++static struct uac1_as_header_descriptor as_in_header_desc = {
+ 	.bLength =		UAC_DT_AS_HEADER_SIZE,
+ 	.bDescriptorType =	USB_DT_CS_INTERFACE,
+ 	.bDescriptorSubtype =	UAC_AS_GENERAL,
+-	.bTerminalLink =	INPUT_TERMINAL_ID,
++	.bTerminalLink =	USB_IN_OT_ID,
+ 	.bDelay =		1,
+-	.wFormatTag =		UAC_FORMAT_TYPE_I_PCM,
++	.wFormatTag =		cpu_to_le16(UAC_FORMAT_TYPE_I_PCM),
++};
++
++/* B.4.2  Class-Specific AS Interface Descriptor */
++static struct uac1_as_header_descriptor as_in_header_2_desc = {
++    .bLength =        UAC_DT_AS_HEADER_SIZE,
++    .bDescriptorType =    USB_DT_CS_INTERFACE,
++    .bDescriptorSubtype =    UAC_AS_GENERAL,
++    .bTerminalLink =    USB_IN_OT_ID,
++    .bDelay =        1,
++    .wFormatTag =        cpu_to_le16(UAC_FORMAT_TYPE_II_AC3),
++};
++
++static struct uac1_format_type_ii_discrete_descriptor as_in_type_ii_ac3_desc = {
++    .bLength =        sizeof(as_in_type_ii_ac3_desc),
++    .bDescriptorType =    USB_DT_CS_INTERFACE,
++    .bDescriptorSubtype =    UAC_FORMAT_TYPE,
++    .bFormatType =        UAC_FORMAT_TYPE_II,
++    .wMaxBitRate =    2,        /*FIXME: how to set MaxBitRate value ?? */
++    .wSamplesPerFrame =    16,   /*FIXME: how to set SamplesPerFrame??*/
++    .bSamFreqType =        4,
++};
++
++static struct uac1_format_type_ii_ac3_descriptor as_in_type_ii_ac3_spec_desc = {
++    .bLength =        sizeof(as_in_type_ii_ac3_spec_desc),
++    .bDescriptorType =    USB_DT_CS_INTERFACE,
++    .bDescriptorSubtype =    UAC_FORMAT_SPECIFIC,
++    .wFormatTag =        cpu_to_le16(UAC_FORMAT_TYPE_II_AC3),
+ };
+ 
+-DECLARE_UAC_FORMAT_TYPE_I_DISCRETE_DESC(1);
++DECLARE_UAC_FORMAT_TYPE_I_DISCRETE_DESC(4);
+ 
+-static struct uac_format_type_i_discrete_descriptor_1 as_type_i_desc = {
+-	.bLength =		UAC_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(1),
++static struct uac_format_type_i_discrete_descriptor_4 as_out_type_i_desc = {
++    .bLength =        UAC_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(4),
+ 	.bDescriptorType =	USB_DT_CS_INTERFACE,
+ 	.bDescriptorSubtype =	UAC_FORMAT_TYPE,
+ 	.bFormatType =		UAC_FORMAT_TYPE_I,
+ 	.bSubframeSize =	2,
+ 	.bBitResolution =	16,
+-	.bSamFreqType =		1,
++	.bSamFreqType =        4,
+ };
+ 
+ /* Standard ISO OUT Endpoint Descriptor */
+@@ -175,53 +271,86 @@ static struct usb_endpoint_descriptor as_out_ep_desc  = {
+ 	.bInterval =		4,
+ };
+ 
++static struct uac_format_type_i_discrete_descriptor_4 as_in_type_i_desc = {
++    .bLength =        UAC_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(4),
++	.bDescriptorType =	USB_DT_CS_INTERFACE,
++	.bDescriptorSubtype =	UAC_FORMAT_TYPE,
++	.bFormatType =		UAC_FORMAT_TYPE_I,
++	.bSubframeSize =	2,
++	.bBitResolution =	16,
++    .bSamFreqType =        4,
++};
++
++/* Standard ISO OUT Endpoint Descriptor */
++static struct usb_endpoint_descriptor as_in_ep_desc  = {
++	.bLength =		USB_DT_ENDPOINT_AUDIO_SIZE,
++	.bDescriptorType =	USB_DT_ENDPOINT,
++	.bEndpointAddress =	USB_DIR_IN,
++	.bmAttributes =		USB_ENDPOINT_SYNC_ASYNC
++				| USB_ENDPOINT_XFER_ISOC,
++	.wMaxPacketSize	=	cpu_to_le16(UAC1_OUT_EP_MAX_PACKET_SIZE),
++	.bInterval =		4,
++};
++
+ /* Class-specific AS ISO OUT Endpoint Descriptor */
+-static struct uac_iso_endpoint_descriptor as_iso_out_desc = {
++static struct uac_iso_endpoint_descriptor as_iso_in_desc = {
+ 	.bLength =		UAC_ISO_ENDPOINT_DESC_SIZE,
+ 	.bDescriptorType =	USB_DT_CS_ENDPOINT,
+ 	.bDescriptorSubtype =	UAC_EP_GENERAL,
+-	.bmAttributes = 	1,
+-	.bLockDelayUnits =	1,
+-	.wLockDelay =		__constant_cpu_to_le16(1),
++	.bmAttributes =		1,
++	.bLockDelayUnits =	0,
++	.wLockDelay =		0,
+ };
+ 
+ static struct usb_descriptor_header *f_audio_desc[] = {
++	(struct usb_descriptor_header *)&uac_iad,
+ 	(struct usb_descriptor_header *)&ac_interface_desc,
+ 	(struct usb_descriptor_header *)&ac_header_desc,
+-
+-	(struct usb_descriptor_header *)&input_terminal_desc,
+-	(struct usb_descriptor_header *)&output_terminal_desc,
+-	(struct usb_descriptor_header *)&feature_unit_desc,
+-
+-	(struct usb_descriptor_header *)&as_interface_alt_0_desc,
+-	(struct usb_descriptor_header *)&as_interface_alt_1_desc,
+-	(struct usb_descriptor_header *)&as_header_desc,
+-
+-	(struct usb_descriptor_header *)&as_type_i_desc,
+-
+-	(struct usb_descriptor_header *)&as_out_ep_desc,
+-	(struct usb_descriptor_header *)&as_iso_out_desc,
++	(struct usb_descriptor_header *)&io_in_it_desc,
++	(struct usb_descriptor_header *)&usb_in_ot_desc,
++	(struct usb_descriptor_header *)&as_in_interface_alt_0_desc,
++	(struct usb_descriptor_header *)&as_in_interface_alt_1_desc,
++	(struct usb_descriptor_header *)&as_in_header_desc,
++	(struct usb_descriptor_header *)&as_in_type_i_desc,
++	(struct usb_descriptor_header *)&as_in_ep_desc,
++	(struct usb_descriptor_header *)&as_iso_in_desc,
++    (struct usb_descriptor_header *)&as_in_interface_alt_2_desc,
++    (struct usb_descriptor_header *)&as_in_header_2_desc,
++    (struct usb_descriptor_header *)&as_in_type_ii_ac3_desc,
++    (struct usb_descriptor_header *)&as_in_type_ii_ac3_spec_desc,
++    (struct usb_descriptor_header *)&as_in_ep_desc,
++    (struct usb_descriptor_header *)&as_iso_in_desc,
+ 	NULL,
+ };
+ 
+ enum {
+ 	STR_AC_IF,
+-	STR_INPUT_TERMINAL,
+-	STR_INPUT_TERMINAL_CH_NAMES,
+-	STR_FEAT_DESC_0,
+-	STR_OUTPUT_TERMINAL,
+-	STR_AS_IF_ALT0,
+-	STR_AS_IF_ALT1,
++	STR_USB_OUT_IT,
++	STR_USB_OUT_IT_CH_NAMES,
++	STR_IO_OUT_OT,
++	STR_IO_IN_IT,
++	STR_IO_IN_IT_CH_NAMES,
++	STR_USB_IN_OT,
++	STR_AS_OUT_IF_ALT0,
++	STR_AS_OUT_IF_ALT1,
++	STR_AS_IN_IF_ALT0,
++	STR_AS_IN_IF_ALT1,
++    STR_AS_IN_IF_ALT2,
+ };
+ 
+ static struct usb_string strings_uac1[] = {
+-	[STR_AC_IF].s = "AC Interface",
+-	[STR_INPUT_TERMINAL].s = "Input terminal",
+-	[STR_INPUT_TERMINAL_CH_NAMES].s = "Channels",
+-	[STR_FEAT_DESC_0].s = "Volume control & mute",
+-	[STR_OUTPUT_TERMINAL].s = "Output terminal",
+-	[STR_AS_IF_ALT0].s = "AS Interface",
+-	[STR_AS_IF_ALT1].s = "AS Interface",
++	[STR_AC_IF].s = "Hisilicon HD Audio",
++	[STR_USB_OUT_IT].s = "Playback Input terminal",
++	[STR_USB_OUT_IT_CH_NAMES].s = "Playback Channels",
++	[STR_IO_OUT_OT].s = "Playback Output terminal",
++	[STR_IO_IN_IT].s = "Capture Input terminal",
++	[STR_IO_IN_IT_CH_NAMES].s = "Capture Channels",
++	[STR_USB_IN_OT].s = "Capture Output terminal",
++	[STR_AS_OUT_IF_ALT0].s = "Playback Inactive",
++	[STR_AS_OUT_IF_ALT1].s = "Playback Active",
++	[STR_AS_IN_IF_ALT0].s = "Capture Inactive",
++	[STR_AS_IN_IF_ALT1].s = "Capture Active",
++    [STR_AS_IN_IF_ALT2].s = "Capture Active",
+ 	{ },
+ };
+ 
+@@ -239,227 +368,23 @@ static struct usb_gadget_strings *uac1_strings[] = {
+  * This function is an ALSA sound card following USB Audio Class Spec 1.0.
+  */
+ 
+-/*-------------------------------------------------------------------------*/
+-struct f_audio_buf {
+-	u8 *buf;
+-	int actual;
+-	struct list_head list;
+-};
+-
+-static struct f_audio_buf *f_audio_buffer_alloc(int buf_size)
+-{
+-	struct f_audio_buf *copy_buf;
+-
+-	copy_buf = kzalloc(sizeof *copy_buf, GFP_ATOMIC);
+-	if (!copy_buf)
+-		return ERR_PTR(-ENOMEM);
+-
+-	copy_buf->buf = kzalloc(buf_size, GFP_ATOMIC);
+-	if (!copy_buf->buf) {
+-		kfree(copy_buf);
+-		return ERR_PTR(-ENOMEM);
+-	}
+-
+-	return copy_buf;
+-}
+-
+-static void f_audio_buffer_free(struct f_audio_buf *audio_buf)
+-{
+-	kfree(audio_buf->buf);
+-	kfree(audio_buf);
+-}
+-/*-------------------------------------------------------------------------*/
+-
+-struct f_audio {
+-	struct gaudio			card;
+-
+-	/* endpoints handle full and/or high speeds */
+-	struct usb_ep			*out_ep;
+-
+-	spinlock_t			lock;
+-	struct f_audio_buf *copy_buf;
+-	struct work_struct playback_work;
+-	struct list_head play_queue;
+-
+-	/* Control Set command */
+-	struct list_head cs;
+-	u8 set_cmd;
+-	struct usb_audio_control *set_con;
+-};
+-
+-static inline struct f_audio *func_to_audio(struct usb_function *f)
+-{
+-	return container_of(f, struct f_audio, card.func);
+-}
+-
+-/*-------------------------------------------------------------------------*/
+-
+-static void f_audio_playback_work(struct work_struct *data)
+-{
+-	struct f_audio *audio = container_of(data, struct f_audio,
+-					playback_work);
+-	struct f_audio_buf *play_buf;
+-
+-	spin_lock_irq(&audio->lock);
+-	if (list_empty(&audio->play_queue)) {
+-		spin_unlock_irq(&audio->lock);
+-		return;
+-	}
+-	play_buf = list_first_entry(&audio->play_queue,
+-			struct f_audio_buf, list);
+-	list_del(&play_buf->list);
+-	spin_unlock_irq(&audio->lock);
+-
+-	u_audio_playback(&audio->card, play_buf->buf, play_buf->actual);
+-	f_audio_buffer_free(play_buf);
+-}
+-
+-static int f_audio_out_ep_complete(struct usb_ep *ep, struct usb_request *req)
+-{
+-	struct f_audio *audio = req->context;
+-	struct usb_composite_dev *cdev = audio->card.func.config->cdev;
+-	struct f_audio_buf *copy_buf = audio->copy_buf;
+-	struct f_uac1_opts *opts;
+-	int audio_buf_size;
+-	int err;
+-
+-	opts = container_of(audio->card.func.fi, struct f_uac1_opts,
+-			    func_inst);
+-	audio_buf_size = opts->audio_buf_size;
+-
+-	if (!copy_buf)
+-		return -EINVAL;
+-
+-	/* Copy buffer is full, add it to the play_queue */
+-	if (audio_buf_size - copy_buf->actual < req->actual) {
+-		list_add_tail(&copy_buf->list, &audio->play_queue);
+-		schedule_work(&audio->playback_work);
+-		copy_buf = f_audio_buffer_alloc(audio_buf_size);
+-		if (IS_ERR(copy_buf))
+-			return -ENOMEM;
+-	}
+-
+-	memcpy(copy_buf->buf + copy_buf->actual, req->buf, req->actual);
+-	copy_buf->actual += req->actual;
+-	audio->copy_buf = copy_buf;
+-
+-	err = usb_ep_queue(ep, req, GFP_ATOMIC);
+-	if (err)
+-		ERROR(cdev, "%s queue req: %d\n", ep->name, err);
+-
+-	return 0;
+-
+-}
+-
+-static void f_audio_complete(struct usb_ep *ep, struct usb_request *req)
+-{
+-	struct f_audio *audio = req->context;
+-	int status = req->status;
+-	u32 data = 0;
+-	struct usb_ep *out_ep = audio->out_ep;
+-
+-	switch (status) {
+-
+-	case 0:				/* normal completion? */
+-		if (ep == out_ep)
+-			f_audio_out_ep_complete(ep, req);
+-		else if (audio->set_con) {
+-			memcpy(&data, req->buf, req->length);
+-			audio->set_con->set(audio->set_con, audio->set_cmd,
+-					le16_to_cpu(data));
+-			audio->set_con = NULL;
+-		}
+-		break;
+-	default:
+-		break;
+-	}
+-}
+-
+-static int audio_set_intf_req(struct usb_function *f,
+-		const struct usb_ctrlrequest *ctrl)
+-{
+-	struct f_audio		*audio = func_to_audio(f);
+-	struct usb_composite_dev *cdev = f->config->cdev;
+-	struct usb_request	*req = cdev->req;
+-	u8			id = ((le16_to_cpu(ctrl->wIndex) >> 8) & 0xFF);
+-	u16			len = le16_to_cpu(ctrl->wLength);
+-	u16			w_value = le16_to_cpu(ctrl->wValue);
+-	u8			con_sel = (w_value >> 8) & 0xFF;
+-	u8			cmd = (ctrl->bRequest & 0x0F);
+-	struct usb_audio_control_selector *cs;
+-	struct usb_audio_control *con;
+-
+-	DBG(cdev, "bRequest 0x%x, w_value 0x%04x, len %d, entity %d\n",
+-			ctrl->bRequest, w_value, len, id);
+-
+-	list_for_each_entry(cs, &audio->cs, list) {
+-		if (cs->id == id) {
+-			list_for_each_entry(con, &cs->control, list) {
+-				if (con->type == con_sel) {
+-					audio->set_con = con;
+-					break;
+-				}
+-			}
+-			break;
+-		}
+-	}
+-
+-	audio->set_cmd = cmd;
+-	req->context = audio;
+-	req->complete = f_audio_complete;
+-
+-	return len;
+-}
+-
+-static int audio_get_intf_req(struct usb_function *f,
+-		const struct usb_ctrlrequest *ctrl)
+-{
+-	struct f_audio		*audio = func_to_audio(f);
+-	struct usb_composite_dev *cdev = f->config->cdev;
+-	struct usb_request	*req = cdev->req;
+-	int			value = -EOPNOTSUPP;
+-	u8			id = ((le16_to_cpu(ctrl->wIndex) >> 8) & 0xFF);
+-	u16			len = le16_to_cpu(ctrl->wLength);
+-	u16			w_value = le16_to_cpu(ctrl->wValue);
+-	u8			con_sel = (w_value >> 8) & 0xFF;
+-	u8			cmd = (ctrl->bRequest & 0x0F);
+-	struct usb_audio_control_selector *cs;
+-	struct usb_audio_control *con;
+-
+-	DBG(cdev, "bRequest 0x%x, w_value 0x%04x, len %d, entity %d\n",
+-			ctrl->bRequest, w_value, len, id);
+-
+-	list_for_each_entry(cs, &audio->cs, list) {
+-		if (cs->id == id) {
+-			list_for_each_entry(con, &cs->control, list) {
+-				if (con->type == con_sel && con->get) {
+-					value = con->get(con, cmd);
+-					break;
+-				}
+-			}
+-			break;
+-		}
+-	}
+-
+-	req->context = audio;
+-	req->complete = f_audio_complete;
+-	len = min_t(size_t, sizeof(value), len);
+-	memcpy(req->buf, &value, len);
+-
+-	return len;
+-}
+-
+ static int audio_set_endpoint_req(struct usb_function *f,
+ 		const struct usb_ctrlrequest *ctrl)
+ {
+-	struct usb_composite_dev *cdev = f->config->cdev;
++	//struct usb_composite_dev *cdev = f->config->cdev;
+ 	int			value = -EOPNOTSUPP;
+ 	u16			ep = le16_to_cpu(ctrl->wIndex);
+ 	u16			len = le16_to_cpu(ctrl->wLength);
+ 	u16			w_value = le16_to_cpu(ctrl->wValue);
+ 
+-	DBG(cdev, "bRequest 0x%x, w_value 0x%04x, len %d, endpoint %d\n",
+-			ctrl->bRequest, w_value, len, ep);
++	printk(KERN_EMERG  "%s:bRequest 0x%x, w_value 0x%04x, len %d, endpoint %d\n",
++			__func__, ctrl->bRequest, w_value, len, ep);
++
++
++    if ((w_value >>8) != UAC_EP_CS_ATTR_SAMPLE_RATE) {
++        printk("!!!!! value = 0x%x\n", (w_value >>8));
++        return value;
++	}
+ 
+ 	switch (ctrl->bRequest) {
+ 	case UAC_SET_CUR:
+@@ -489,16 +414,24 @@ static int audio_get_endpoint_req(struct usb_function *f,
+ 		const struct usb_ctrlrequest *ctrl)
+ {
+ 	struct usb_composite_dev *cdev = f->config->cdev;
++	struct f_uac1 *uac1 = func_to_uac1(f);
++	struct usb_request    *req = uac1->uac_dev.control_req;
++	struct uac_device *uac = req->context;
+ 	int value = -EOPNOTSUPP;
+ 	u8 ep = ((le16_to_cpu(ctrl->wIndex) >> 8) & 0xFF);
+ 	u16 len = le16_to_cpu(ctrl->wLength);
+ 	u16 w_value = le16_to_cpu(ctrl->wValue);
+ 
+-	DBG(cdev, "bRequest 0x%x, w_value 0x%04x, len %d, endpoint %d\n",
+-			ctrl->bRequest, w_value, len, ep);
++	printk(KERN_EMERG  "%s:bRequest 0x%x, w_value 0x%04x, len %d, endpoint %d\n",
++			__func__, ctrl->bRequest, w_value, len, ep);
+ 
+ 	switch (ctrl->bRequest) {
+ 	case UAC_GET_CUR:
++		if ((w_value >>8) == UAC_EP_CS_ATTR_SAMPLE_RATE) {
++			memcpy(req->buf, &uac->params.p_srate, 3);
++		}
++		value = len;
++		break;
+ 	case UAC_GET_MIN:
+ 	case UAC_GET_MAX:
+ 	case UAC_GET_RES:
+@@ -517,41 +450,25 @@ static int
+ f_audio_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
+ {
+ 	struct usb_composite_dev *cdev = f->config->cdev;
+-	struct usb_request	*req = cdev->req;
++    struct f_uac1 *uac1 = func_to_uac1(f);
++    struct usb_request    *req = uac1->uac_dev.control_req;
+ 	int			value = -EOPNOTSUPP;
+ 	u16			w_index = le16_to_cpu(ctrl->wIndex);
+ 	u16			w_value = le16_to_cpu(ctrl->wValue);
+ 	u16			w_length = le16_to_cpu(ctrl->wLength);
+ 
++	printk(KERN_EMERG "%s:\n", __func__);
++
+ 	/* composite driver infrastructure handles everything; interface
+ 	 * activation uses set_alt().
+ 	 */
+ 	switch (ctrl->bRequestType) {
+-	case USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE:
+-		value = audio_set_intf_req(f, ctrl);
+-		break;
+-
+-	case USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE:
+-		value = audio_get_intf_req(f, ctrl);
+-		break;
+-
+ 	case USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_ENDPOINT:
+-		value = audio_set_endpoint_req(f, ctrl);
+-		break;
+-
+-	case USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT:
+-		value = audio_get_endpoint_req(f, ctrl);
+-		break;
+-
+-	default:
+-		ERROR(cdev, "invalid control req%02x.%02x v%04x i%04x l%d\n",
+-			ctrl->bRequestType, ctrl->bRequest,
+-			w_value, w_index, w_length);
+-	}
+-
++        {
++            value = audio_set_endpoint_req(f, ctrl);
+ 	/* respond with data transfer or status phase? */
+ 	if (value >= 0) {
+-		DBG(cdev, "audio req%02x.%02x v%04x i%04x l%d\n",
++		printk(KERN_EMERG  "audio req%02x.%02x v%04x i%04x l%d\n",
+ 			ctrl->bRequestType, ctrl->bRequest,
+ 			w_value, w_index, w_length);
+ 		req->zero = 0;
+@@ -559,7 +476,29 @@ f_audio_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
+ 		value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
+ 		if (value < 0)
+ 			ERROR(cdev, "audio response on err %d\n", value);
+-	}
++            }
++        }
++        break;
++
++    case USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT:
++        value = audio_get_endpoint_req(f, ctrl);
++		if (value >= 0) {
++			printk(KERN_EMERG  "audio req%02x.%02x v%04x i%04x l%d\n",
++				ctrl->bRequestType, ctrl->bRequest,
++				w_value, w_index, w_length);
++				req->zero = 0;
++				req->length = value;
++				value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
++				if (value < 0)
++					ERROR(cdev, "audio response on err %d\n", value);
++          }
++        break;
++
++    default:
++        printk(KERN_EMERG   "invalid control req%02x.%02x v%04x i%04x l%d\n",
++            ctrl->bRequestType, ctrl->bRequest,
++            w_value, w_index, w_length);
++    }
+ 
+ 	/* device either stalls (value < 0) or reports success */
+ 	return value;
+@@ -567,343 +506,426 @@ f_audio_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
+ 
+ static int f_audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
+ {
+-	struct f_audio		*audio = func_to_audio(f);
+-	struct usb_composite_dev *cdev = f->config->cdev;
+-	struct usb_ep *out_ep = audio->out_ep;
+-	struct usb_request *req;
+-	struct f_uac1_opts *opts;
+-	int req_buf_size, req_count, audio_buf_size;
+-	int i = 0, err = 0;
++	struct f_uac1 *uac1 = func_to_uac1(f);
++	int ret = 0;
+ 
+-	DBG(cdev, "intf %d, alt %d\n", intf, alt);
++	printk(KERN_EMERG "%s:intf:%d alt=%d\n", __func__, intf, alt);
+ 
+-	opts = container_of(f->fi, struct f_uac1_opts, func_inst);
+-	req_buf_size = opts->req_buf_size;
+-	req_count = opts->req_count;
+-	audio_buf_size = opts->audio_buf_size;
+-
+-	if (intf == 1) {
+-		if (alt == 1) {
+-			usb_ep_enable(out_ep);
+-			out_ep->driver_data = audio;
+-			audio->copy_buf = f_audio_buffer_alloc(audio_buf_size);
+-			if (IS_ERR(audio->copy_buf))
+-				return -ENOMEM;
+-
+-			/*
+-			 * allocate a bunch of read buffers
+-			 * and queue them all at once.
+-			 */
+-			for (i = 0; i < req_count && err == 0; i++) {
+-				req = usb_ep_alloc_request(out_ep, GFP_ATOMIC);
+-				if (req) {
+-					req->buf = kzalloc(req_buf_size,
+-							GFP_ATOMIC);
+-					if (req->buf) {
+-						req->length = req_buf_size;
+-						req->context = audio;
+-						req->complete =
+-							f_audio_complete;
+-						err = usb_ep_queue(out_ep,
+-							req, GFP_ATOMIC);
+-						if (err)
+-							ERROR(cdev,
+-							"%s queue req: %d\n",
+-							out_ep->name, err);
+-					} else
+-						err = -ENOMEM;
+-				} else
+-					err = -ENOMEM;
+-			}
++	/* No i/f has more than 2 alt settings */
++	if (alt > 1) {
++		printk(KERN_EMERG  "%s:%d Error!\n", __func__, __LINE__);
++		return -EINVAL;
++	}
+ 
++	if (intf == uac1->ac_intf) {
++		/* Control I/f has only 1 AltSetting - 0 */
++		if (alt) {
++			printk(KERN_EMERG  "%s:%d Error!\n", __func__, __LINE__);
++			return -EINVAL;
++		}
++
++		/*FIXME: notify userpace uac has been connected*/
++		{
++			struct uac_device *uac_dev = &uac1->uac_dev;
++			struct v4l2_event v4l2_event;
++
++			memset(&v4l2_event, 0, sizeof(v4l2_event));
++			v4l2_event.type = UAC_EVENT_CONNECT;
++			v4l2_event_queue(uac_dev->vdev, &v4l2_event);
++
++			printk(KERN_EMERG "%s: trigger connect\n", __func__);
++		}
++
++		return 0;
++	}
++
++	if (intf == uac1->as_out_intf) {
++		uac1->as_out_alt = alt;
++
++		if (alt) {
+ 		} else {
+-			struct f_audio_buf *copy_buf = audio->copy_buf;
+-			if (copy_buf) {
+-				list_add_tail(&copy_buf->list,
+-						&audio->play_queue);
+-				schedule_work(&audio->playback_work);
+-			}
+ 		}
++	} else if (intf == uac1->as_in_intf) {
++		uac1->as_in_alt = alt;
++
++			if (alt) {
++				/*FIXME: notify userpace to start audio streaming*/
++				{
++					struct uac_device *uac_dev = &uac1->uac_dev;
++					struct v4l2_event v4l2_event;
++
++					memset(&v4l2_event, 0, sizeof(v4l2_event));
++					v4l2_event.type = UAC_EVENT_STREAMON;
++					v4l2_event_queue(uac_dev->vdev, &v4l2_event);
++
++					printk(KERN_EMERG "%s: trigger UAC_EVENT_STREAMON\n", __func__);
++				}
++
++				ret = uac_device_start_playback(&uac1->uac_dev);
++			} else {
++				/*FIXME: notify userpace to start audio streaming*/
++				{
++					struct uac_device *uac_dev = &uac1->uac_dev;
++					struct v4l2_event v4l2_event;
++
++					memset(&v4l2_event, 0, sizeof(v4l2_event));
++					v4l2_event.type = UAC_EVENT_STREAMOFF;
++					v4l2_event_queue(uac_dev->vdev, &v4l2_event);
++
++					printk(KERN_EMERG "%s: trigger UAC_EVENT_STREAMOFF\n", __func__);
++				}
++
++				uac_device_stop_playback(&uac1->uac_dev);
++			}
++	} else {
++		printk(KERN_EMERG  "%s:%d Error!\n", __func__, __LINE__);
++		return -EINVAL;
+ 	}
+ 
+-	return err;
++	return ret;
+ }
+ 
++static int f_audio_get_alt(struct usb_function *f, unsigned intf)
++{
++	struct f_uac1 *uac1 = func_to_uac1(f);
++
++	printk(KERN_EMERG "%s:\n", __func__);
++
++	if (intf == uac1->ac_intf) {
++		printk(KERN_EMERG "%s:ac_intf = %d\n", __func__, uac1->ac_intf);
++		return uac1->ac_alt;
++	}
++	else if (intf == uac1->as_out_intf) {
++		printk(KERN_EMERG "%s:as_out_intf = %d\n", __func__, uac1->as_out_intf);
++		return uac1->as_out_alt;
++	}
++	else if (intf == uac1->as_in_intf) {
++		printk(KERN_EMERG "%s:as_in_intf = %d\n", __func__, uac1->as_in_intf);
++		return uac1->as_in_alt;
++	}
++	else
++		printk(KERN_EMERG  "%s:%d Invalid Interface %d!\n",
++			__func__, __LINE__, intf);
++
++	return -EINVAL;
++}
++
++
+ static void f_audio_disable(struct usb_function *f)
+ {
+-	return;
++	struct f_uac1 *uac1 = func_to_uac1(f);
++
++	uac1->as_out_alt = 0;
++	uac1->as_in_alt = 0;
++
++
++	/*FIXME: notify userpace to disconnect*/
++	{
++		struct uac_device *uac_dev = &uac1->uac_dev;
++		struct v4l2_event v4l2_event;
++
++		memset(&v4l2_event, 0, sizeof(v4l2_event));
++		v4l2_event.type = UAC_EVENT_DISCONNECT;
++		v4l2_event_queue(uac_dev->vdev, &v4l2_event);
++	}
+ }
+ 
+ /*-------------------------------------------------------------------------*/
+ 
+-static void f_audio_build_desc(struct f_audio *audio)
++static int
++__uac_register_video(struct usb_composite_dev *dev, struct uac_device *uac_dev)
+ {
+-	struct gaudio *card = &audio->card;
+-	u8 *sam_freq;
+-	int rate;
++	struct usb_composite_dev *cdev = dev;
++	struct video_device *video;
+ 
+-	/* Set channel numbers */
+-	input_terminal_desc.bNrChannels = u_audio_get_playback_channels(card);
+-	as_type_i_desc.bNrChannels = u_audio_get_playback_channels(card);
++	/* TODO reference counting. */
++	video = video_device_alloc();
++	if (video == NULL)
++		return -ENOMEM;
+ 
+-	/* Set sample rates */
+-	rate = u_audio_get_playback_rate(card);
+-	sam_freq = as_type_i_desc.tSamFreq[0];
+-	memcpy(sam_freq, &rate, 3);
++	video->v4l2_dev = &uac_dev->v4l2_dev;
++	video->fops = &uac_v4l2_fops;
++	video->ioctl_ops = &uac_v4l2_ioctl_ops;
++	video->release = video_device_release;
++	video->vfl_dir = VFL_DIR_TX;
++	strlcpy(video->name, cdev->gadget->name, sizeof(video->name));
++
++	uac_dev->vdev = video;
++	video_set_drvdata(video, uac_dev);
++
++	return video_register_device(video, VFL_TYPE_GRABBER, -1);
++}
+ 
+-	/* Todo: Set Sample bits and other parameters */
++static void
++__uac_function_ep0_complete(struct usb_ep *ep, struct usb_request *req)
++{
++    struct uac_device *uac = req->context;
++    struct v4l2_event v4l2_event;
++	struct uac_event *uac_event = (void *)&v4l2_event.u.data;
++
++	/*FIXME: notify userpace to set audio resolution */
++	if (req->actual == 3)
++	{
++		int rate = ((unsigned char*)req->buf)[0] | (((unsigned char*)req->buf)[1] << 8) | (((unsigned char*)req->buf)[2] << 16);
++
++		uac->params.p_srate = rate;
++		uac->p_pktsize = (rate / 1000) * uac->params.p_ssize * num_channels(uac->params.p_chmask);
+ 
+-	return;
++		memset(&v4l2_event, 0, sizeof(v4l2_event));
++		v4l2_event.type = UAC_EVENT_DATA;
++		uac_event->data.length = req->actual;
++		memcpy(&uac_event->data.data, req->buf, req->actual);
++		v4l2_event_queue(uac->vdev, &v4l2_event);
++
++		printk("%s:rate=%d srate = %d pkt_size=%d\n",__func__, rate, uac->params.p_srate, uac->p_pktsize);
++	}
++}
++
++static void __print_params(struct uac_params *params)
++{
++	printk(KERN_EMERG "pamrams: p_chmask=%d p_srate=%d(hz) p_ssize=%d \
++			req_number=%d\n",
++			params->p_chmask,
++			params->p_srate,
++			params->p_ssize,
++			params->req_number
++		);
+ }
+ 
+ /* audio function driver setup/binding */
+-static int
+-f_audio_bind(struct usb_configuration *c, struct usb_function *f)
++static int f_audio_bind(struct usb_configuration *c, struct usb_function *f)
+ {
+-	struct usb_composite_dev *cdev = c->cdev;
+-	struct f_audio		*audio = func_to_audio(f);
+-	struct usb_string	*us;
+-	int			status;
+-	struct usb_ep		*ep = NULL;
+-	struct f_uac1_opts	*audio_opts;
++	struct usb_composite_dev	*cdev = c->cdev;
++	struct usb_gadget		*gadget = cdev->gadget;
++	struct f_uac1			*uac1 = func_to_uac1(f);
++	struct uac_device *uac_dev = &uac1->uac_dev;
++	struct f_uac1_opts		*audio_opts;
++	struct usb_ep			*ep = NULL;
++	struct usb_string		*us;
++	u8				*sam_freq;
++	int				rate;
++	int				status;
+ 
+ 	audio_opts = container_of(f->fi, struct f_uac1_opts, func_inst);
+-	audio->card.gadget = c->cdev->gadget;
+-	audio_opts->card = &audio->card;
+-	/* set up ASLA audio devices */
+-	if (!audio_opts->bound) {
+-		status = gaudio_setup(&audio->card);
+-		if (status < 0)
+-			return status;
+-		audio_opts->bound = true;
+-	}
++
+ 	us = usb_gstrings_attach(cdev, uac1_strings, ARRAY_SIZE(strings_uac1));
+ 	if (IS_ERR(us))
+ 		return PTR_ERR(us);
++
++	uac_iad.iFunction = us[STR_AC_IF].id;
+ 	ac_interface_desc.iInterface = us[STR_AC_IF].id;
+-	input_terminal_desc.iTerminal = us[STR_INPUT_TERMINAL].id;
+-	input_terminal_desc.iChannelNames = us[STR_INPUT_TERMINAL_CH_NAMES].id;
+-	feature_unit_desc.iFeature = us[STR_FEAT_DESC_0].id;
+-	output_terminal_desc.iTerminal = us[STR_OUTPUT_TERMINAL].id;
+-	as_interface_alt_0_desc.iInterface = us[STR_AS_IF_ALT0].id;
+-	as_interface_alt_1_desc.iInterface = us[STR_AS_IF_ALT1].id;
++	usb_out_it_desc.iTerminal = us[STR_USB_OUT_IT].id;
++	usb_out_it_desc.iChannelNames = us[STR_USB_OUT_IT_CH_NAMES].id;
++	io_out_ot_desc.iTerminal = us[STR_IO_OUT_OT].id;
++	as_out_interface_alt_0_desc.iInterface = us[STR_AS_OUT_IF_ALT0].id;
++	as_out_interface_alt_1_desc.iInterface = us[STR_AS_OUT_IF_ALT1].id;
++	io_in_it_desc.iTerminal = us[STR_IO_IN_IT].id;
++	io_in_it_desc.iChannelNames = us[STR_IO_IN_IT_CH_NAMES].id;
++	usb_in_ot_desc.iTerminal = us[STR_USB_IN_OT].id;
++	as_in_interface_alt_0_desc.iInterface = us[STR_AS_IN_IF_ALT0].id;
++	as_in_interface_alt_1_desc.iInterface = us[STR_AS_IN_IF_ALT1].id;
++    as_in_interface_alt_2_desc.iInterface = us[STR_AS_IN_IF_ALT2].id;
++
++	/* Set channel numbers */
++	usb_out_it_desc.bNrChannels = num_channels(audio_opts->c_chmask);
++	usb_out_it_desc.wChannelConfig = cpu_to_le16(audio_opts->c_chmask);
++	as_out_type_i_desc.bNrChannels = num_channels(audio_opts->c_chmask);
++	as_out_type_i_desc.bSubframeSize = audio_opts->c_ssize;
++	as_out_type_i_desc.bBitResolution = audio_opts->c_ssize * 8;
++	io_in_it_desc.bNrChannels = num_channels(audio_opts->p_chmask);
++	io_in_it_desc.wChannelConfig = cpu_to_le16(audio_opts->p_chmask);
++	as_in_type_i_desc.bNrChannels = num_channels(audio_opts->p_chmask);
++	as_in_type_i_desc.bSubframeSize = audio_opts->p_ssize;
++	as_in_type_i_desc.bBitResolution = audio_opts->p_ssize * 8;
++    as_out_ep_desc.wMaxPacketSize = 48*audio_opts->c_ssize * num_channels(audio_opts->c_chmask);
++	/*FIXME: max_resolution * sample * channnel*/
++    as_in_ep_desc.wMaxPacketSize = 48*audio_opts->p_ssize * num_channels(audio_opts->p_chmask);
+ 
+ 
+-	f_audio_build_desc(audio);
++	/* Set sample rates */
++	/*rate = audio_opts->c_srate;
++	  sam_freq = as_out_type_i_desc.tSamFreq[0];
++	  memcpy(sam_freq, &rate, 3);
++	  rate = audio_opts->p_srate;
++	  sam_freq = as_in_type_i_desc.tSamFreq[0];
++	  memcpy(sam_freq, &rate, 3);
++	  */
++	rate = 8000;
++	sam_freq = as_out_type_i_desc.tSamFreq[0];
++	memcpy(sam_freq, &rate, 3);
++	sam_freq = as_in_type_i_desc.tSamFreq[0];
++	memcpy(sam_freq, &rate, 3);
++	sam_freq = as_in_type_ii_ac3_desc.tSamFreq[0];
++	memcpy(sam_freq, &rate, 3);
++
++	rate = 16000;
++	sam_freq = as_out_type_i_desc.tSamFreq[1];
++	memcpy(sam_freq, &rate, 3);
++	sam_freq = as_in_type_i_desc.tSamFreq[1];
++	memcpy(sam_freq, &rate, 3);
++	sam_freq = as_in_type_ii_ac3_desc.tSamFreq[1];
++	memcpy(sam_freq, &rate, 3);
++
++	rate = 32000;
++	sam_freq = as_out_type_i_desc.tSamFreq[2];
++	memcpy(sam_freq, &rate, 3);
++	sam_freq = as_in_type_i_desc.tSamFreq[2];
++	memcpy(sam_freq, &rate, 3);
++	sam_freq = as_in_type_ii_ac3_desc.tSamFreq[2];
++	memcpy(sam_freq, &rate, 3);
++
++	rate = 48000;
++	sam_freq = as_out_type_i_desc.tSamFreq[3];
++	memcpy(sam_freq, &rate, 3);
++	sam_freq = as_in_type_i_desc.tSamFreq[3];
++	memcpy(sam_freq, &rate, 3);
++	sam_freq = as_in_type_ii_ac3_desc.tSamFreq[3];
++	memcpy(sam_freq, &rate, 3);
+ 
+ 	/* allocate instance-specific interface IDs, and patch descriptors */
+ 	status = usb_interface_id(c, f);
+-	if (status < 0)
++	if (status < 0) {
++		printk(KERN_EMERG "%s:%d\n", __func__, __LINE__);
+ 		goto fail;
++	}
++
++	uac_iad.bFirstInterface = status;
+ 	ac_interface_desc.bInterfaceNumber = status;
++	uac1->ac_intf = status;
++	uac1->ac_alt = 0;
++	printk(KERN_EMERG "ac_intf:%d\n", status);
+ 
+ 	status = usb_interface_id(c, f);
+-	if (status < 0)
++	if (status < 0) {
++		printk(KERN_EMERG "%s:%d\n", __func__, __LINE__);
+ 		goto fail;
+-	as_interface_alt_0_desc.bInterfaceNumber = status;
+-	as_interface_alt_1_desc.bInterfaceNumber = status;
++	}
++
++	as_in_interface_alt_0_desc.bInterfaceNumber = status;
++	as_in_interface_alt_1_desc.bInterfaceNumber = status;
++	as_in_interface_alt_2_desc.bInterfaceNumber = status;
++
++	ac_header_desc.baInterfaceNr[0] = status;
++
++	uac1->as_in_intf = status;
++	uac1->as_in_alt = 0;
++
++	printk(KERN_EMERG "as_in_intf:%d\n", status);
++
++	uac_dev->gadget = gadget;
+ 
+ 	status = -ENODEV;
+ 
+ 	/* allocate instance-specific endpoints */
+ 	ep = usb_ep_autoconfig(cdev->gadget, &as_out_ep_desc);
+-	if (!ep)
++	if (!ep) {
++		printk(KERN_EMERG "%s:%d\n", __func__,__LINE__);
+ 		goto fail;
+-	audio->out_ep = ep;
+-	audio->out_ep->desc = &as_out_ep_desc;
+-	ep->driver_data = cdev;	/* claim */
++	}
+ 
+-	status = -ENOMEM;
++	uac_dev->out_ep = ep;
++	uac_dev->out_ep->desc = &as_out_ep_desc;
++
++	ep = usb_ep_autoconfig(cdev->gadget, &as_in_ep_desc);
++	if (!ep) {
++		printk(KERN_EMERG "%s:%d\n", __func__,__LINE__);
++		goto fail;
++	}
++	uac_dev->in_ep = ep;
++	uac_dev->in_ep->desc = &as_in_ep_desc;
+ 
+ 	/* copy descriptors, and track endpoint copies */
+ 	status = usb_assign_descriptors(f, f_audio_desc, f_audio_desc, NULL);
+-	if (status)
++	if (status) {
++		printk(KERN_EMERG "%s:%d\n", __func__,__LINE__);
+ 		goto fail;
+-	return 0;
++	}
+ 
+-fail:
+-	gaudio_cleanup(&audio->card);
+-	if (ep)
+-		ep->driver_data = NULL;
+-	return status;
+-}
++	uac_dev->out_ep_maxpsize = le16_to_cpu(as_out_ep_desc.wMaxPacketSize);
++	uac_dev->in_ep_maxpsize = le16_to_cpu(as_in_ep_desc.wMaxPacketSize);
++	uac_dev->params.c_chmask = audio_opts->c_chmask;
++	uac_dev->params.c_srate = audio_opts->c_srate;
++	uac_dev->params.c_ssize = audio_opts->c_ssize;
++	uac_dev->params.p_chmask = audio_opts->p_chmask;
++	uac_dev->params.p_srate = audio_opts->p_srate;
++	uac_dev->params.p_ssize = audio_opts->p_ssize;
++	uac_dev->params.req_number = audio_opts->req_number;
+ 
+-/*-------------------------------------------------------------------------*/
++	__print_params(&uac_dev->params);
+ 
+-static int generic_set_cmd(struct usb_audio_control *con, u8 cmd, int value)
+-{
+-	con->data[cmd] = value;
++	status = uac_device_setup(uac_dev);
++	if (status)
++		goto err_card_register;
++
++    /* Preallocate control endpoint request. */
++    uac_dev->control_req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL);
++    uac_dev->control_buf = kmalloc(64, GFP_KERNEL);
++    if (uac_dev->control_req == NULL || uac_dev->control_buf == NULL) {
++        status = -ENOMEM;
++        goto error;
++    }
++
++    uac_dev->control_req->buf = uac_dev->control_buf;
++    uac_dev->control_req->complete = __uac_function_ep0_complete;
++    uac_dev->control_req->context = uac_dev;
++
++	/*FIXME: add v4l2 interface*/
++	{
++		struct uac_device *uac_dev = &uac1->uac_dev;
++
++		if (uac_dev) {
++			if (v4l2_device_register(&cdev->gadget->dev, &(uac_dev->v4l2_dev))) {
++				printk(KERN_INFO "v4l2_device_register failed\n");
++				goto error;
++			}
+ 
+-	return 0;
+-}
++			/* Initialise queue buffer. */
++			status = uac_queue_init(&(uac_dev->queue));
++			if (status < 0)
++				goto error;
+ 
+-static int generic_get_cmd(struct usb_audio_control *con, u8 cmd)
+-{
+-	return con->data[cmd];
+-}
++			/* Register a V4L2 device. */
++			status = __uac_register_video(cdev, uac_dev);
++			if (status < 0) {
++				printk(KERN_INFO "Unable to register video device\n");
++				goto error;
++			}
++		}
++	}
+ 
+-/* Todo: add more control selecotor dynamically */
+-static int control_selector_init(struct f_audio *audio)
+-{
+-	INIT_LIST_HEAD(&audio->cs);
+-	list_add(&feature_unit.list, &audio->cs);
++	return 0;
+ 
+-	INIT_LIST_HEAD(&feature_unit.control);
+-	list_add(&mute_control.list, &feature_unit.control);
+-	list_add(&volume_control.list, &feature_unit.control);
++error:
++	if (&uac1->uac_dev) {
++		v4l2_device_unregister(&(uac1->uac_dev.v4l2_dev));
++		if ((uac1->uac_dev.vdev))
++			video_device_release((uac1->uac_dev.vdev));
++    }
+ 
+-	volume_control.data[UAC__CUR] = 0xffc0;
+-	volume_control.data[UAC__MIN] = 0xe3a0;
+-	volume_control.data[UAC__MAX] = 0xfff0;
+-	volume_control.data[UAC__RES] = 0x0030;
++	if (&uac1->uac_dev) {
++		usb_ep_free_request(cdev->gadget->ep0, uac_dev->control_req);
++		kfree(uac_dev->control_buf);
++	}
+ 
+-	return 0;
++err_card_register:
++	usb_free_all_descriptors(f);
++fail:
++	return status;
+ }
+ 
++/*-------------------------------------------------------------------------*/
++
+ static inline struct f_uac1_opts *to_f_uac1_opts(struct config_item *item)
+ {
+ 	return container_of(to_config_group(item), struct f_uac1_opts,
+-			    func_inst.group);
+-}
+-
+-CONFIGFS_ATTR_STRUCT(f_uac1_opts);
+-CONFIGFS_ATTR_OPS(f_uac1_opts);
+-
+-static void f_uac1_attr_release(struct config_item *item)
+-{
+-	struct f_uac1_opts *opts = to_f_uac1_opts(item);
+-
+-	usb_put_function_instance(&opts->func_inst);
++			func_inst.group);
+ }
+ 
+-static struct configfs_item_operations f_uac1_item_ops = {
+-	.release	= f_uac1_attr_release,
+-	.show_attribute	= f_uac1_opts_attr_show,
+-	.store_attribute = f_uac1_opts_attr_store,
+-};
+-
+-#define UAC1_INT_ATTRIBUTE(name)					\
+-static ssize_t f_uac1_opts_##name##_show(struct f_uac1_opts *opts,	\
+-					 char *page)			\
+-{									\
+-	int result;							\
+-									\
+-	mutex_lock(&opts->lock);					\
+-	result = sprintf(page, "%u\n", opts->name);			\
+-	mutex_unlock(&opts->lock);					\
+-									\
+-	return result;							\
+-}									\
+-									\
+-static ssize_t f_uac1_opts_##name##_store(struct f_uac1_opts *opts,	\
+-					  const char *page, size_t len)	\
+-{									\
+-	int ret;							\
+-	u32 num;							\
+-									\
+-	mutex_lock(&opts->lock);					\
+-	if (opts->refcnt) {						\
+-		ret = -EBUSY;						\
+-		goto end;						\
+-	}								\
+-									\
+-	ret = kstrtou32(page, 0, &num);					\
+-	if (ret)							\
+-		goto end;						\
+-									\
+-	opts->name = num;						\
+-	ret = len;							\
+-									\
+-end:									\
+-	mutex_unlock(&opts->lock);					\
+-	return ret;							\
+-}									\
+-									\
+-static struct f_uac1_opts_attribute f_uac1_opts_##name =		\
+-	__CONFIGFS_ATTR(name, S_IRUGO | S_IWUSR,			\
+-			f_uac1_opts_##name##_show,			\
+-			f_uac1_opts_##name##_store)
+-
+-UAC1_INT_ATTRIBUTE(req_buf_size);
+-UAC1_INT_ATTRIBUTE(req_count);
+-UAC1_INT_ATTRIBUTE(audio_buf_size);
+-
+-#define UAC1_STR_ATTRIBUTE(name)					\
+-static ssize_t f_uac1_opts_##name##_show(struct f_uac1_opts *opts,	\
+-					 char *page)			\
+-{									\
+-	int result;							\
+-									\
+-	mutex_lock(&opts->lock);					\
+-	result = sprintf(page, "%s\n", opts->name);			\
+-	mutex_unlock(&opts->lock);					\
+-									\
+-	return result;							\
+-}									\
+-									\
+-static ssize_t f_uac1_opts_##name##_store(struct f_uac1_opts *opts,	\
+-					  const char *page, size_t len)	\
+-{									\
+-	int ret = -EBUSY;						\
+-	char *tmp;							\
+-									\
+-	mutex_lock(&opts->lock);					\
+-	if (opts->refcnt)						\
+-		goto end;						\
+-									\
+-	tmp = kstrndup(page, len, GFP_KERNEL);				\
+-	if (tmp) {							\
+-		ret = -ENOMEM;						\
+-		goto end;						\
+-	}								\
+-	if (opts->name##_alloc)						\
+-		kfree(opts->name);					\
+-	opts->name##_alloc = true;					\
+-	opts->name = tmp;						\
+-	ret = len;							\
+-									\
+-end:									\
+-	mutex_unlock(&opts->lock);					\
+-	return ret;							\
+-}									\
+-									\
+-static struct f_uac1_opts_attribute f_uac1_opts_##name =		\
+-	__CONFIGFS_ATTR(name, S_IRUGO | S_IWUSR,			\
+-			f_uac1_opts_##name##_show,			\
+-			f_uac1_opts_##name##_store)
+-
+-UAC1_STR_ATTRIBUTE(fn_play);
+-UAC1_STR_ATTRIBUTE(fn_cap);
+-UAC1_STR_ATTRIBUTE(fn_cntl);
+-
+-static struct configfs_attribute *f_uac1_attrs[] = {
+-	&f_uac1_opts_req_buf_size.attr,
+-	&f_uac1_opts_req_count.attr,
+-	&f_uac1_opts_audio_buf_size.attr,
+-	&f_uac1_opts_fn_play.attr,
+-	&f_uac1_opts_fn_cap.attr,
+-	&f_uac1_opts_fn_cntl.attr,
+-	NULL,
+-};
+-
+-static struct config_item_type f_uac1_func_type = {
+-	.ct_item_ops	= &f_uac1_item_ops,
+-	.ct_attrs	= f_uac1_attrs,
+-	.ct_owner	= THIS_MODULE,
+-};
+-
+ static void f_audio_free_inst(struct usb_function_instance *f)
+ {
+ 	struct f_uac1_opts *opts;
+ 
+ 	opts = container_of(f, struct f_uac1_opts, func_inst);
+-	gaudio_cleanup(opts->card);
+-	if (opts->fn_play_alloc)
+-		kfree(opts->fn_play);
+-	if (opts->fn_cap_alloc)
+-		kfree(opts->fn_cap);
+-	if (opts->fn_cntl_alloc)
+-		kfree(opts->fn_cntl);
+ 	kfree(opts);
+ }
+ 
+@@ -918,68 +940,76 @@ static struct usb_function_instance *f_audio_alloc_inst(void)
+ 	mutex_init(&opts->lock);
+ 	opts->func_inst.free_func_inst = f_audio_free_inst;
+ 
+-	config_group_init_type_name(&opts->func_inst.group, "",
+-				    &f_uac1_func_type);
+-
+-	opts->req_buf_size = UAC1_OUT_EP_MAX_PACKET_SIZE;
+-	opts->req_count = UAC1_REQ_COUNT;
+-	opts->audio_buf_size = UAC1_AUDIO_BUF_SIZE;
+-	opts->fn_play = FILE_PCM_PLAYBACK;
+-	opts->fn_cap = FILE_PCM_CAPTURE;
+-	opts->fn_cntl = FILE_CONTROL;
++	opts->c_chmask = UAC1_DEF_CCHMASK;
++	opts->c_srate = UAC1_DEF_CSRATE;
++	opts->c_ssize = UAC1_DEF_CSSIZE;
++	opts->p_chmask = UAC1_DEF_PCHMASK;
++	opts->p_srate = UAC1_DEF_PSRATE;
++	opts->p_ssize = UAC1_DEF_PSSIZE;
++	opts->req_number = UAC1_DEF_REQ_NUM;
+ 	return &opts->func_inst;
+ }
+ 
+ static void f_audio_free(struct usb_function *f)
+ {
+-	struct f_audio *audio = func_to_audio(f);
+ 	struct f_uac1_opts *opts;
++	struct f_uac1  *uac1 = func_to_uac1(f);
+ 
+ 	opts = container_of(f->fi, struct f_uac1_opts, func_inst);
+-	kfree(audio);
+ 	mutex_lock(&opts->lock);
+ 	--opts->refcnt;
+ 	mutex_unlock(&opts->lock);
++
++	kfree(uac1);
+ }
+ 
+ static void f_audio_unbind(struct usb_configuration *c, struct usb_function *f)
+ {
++	struct f_uac1  *uac1 = func_to_uac1(f);
++	struct uac_device *uac_dev = &uac1->uac_dev;
++    struct usb_composite_dev *cdev = c->cdev;
++
++	uac_device_cleanup(uac_dev);
+ 	usb_free_all_descriptors(f);
++
++	uac_dev->gadget = NULL;
++
++	if (uac_dev) { /* release v4l2 device*/
++		video_unregister_device(uac_dev->vdev);
++		v4l2_device_unregister(&(uac_dev->v4l2_dev));
++
++        usb_ep_free_request(cdev->gadget->ep0, uac_dev->control_req);
++        kfree(uac_dev->control_buf);
++	}
+ }
+ 
+ static struct usb_function *f_audio_alloc(struct usb_function_instance *fi)
+ {
+-	struct f_audio *audio;
++	struct f_uac1 *uac1;
+ 	struct f_uac1_opts *opts;
+ 
+ 	/* allocate and initialize one new instance */
+-	audio = kzalloc(sizeof(*audio), GFP_KERNEL);
+-	if (!audio)
++	uac1 = kzalloc(sizeof(*uac1), GFP_KERNEL);
++	if (!uac1)
+ 		return ERR_PTR(-ENOMEM);
+ 
+-	audio->card.func.name = "g_audio";
+-
+ 	opts = container_of(fi, struct f_uac1_opts, func_inst);
+ 	mutex_lock(&opts->lock);
+ 	++opts->refcnt;
+ 	mutex_unlock(&opts->lock);
+-	INIT_LIST_HEAD(&audio->play_queue);
+-	spin_lock_init(&audio->lock);
+-
+-	audio->card.func.bind = f_audio_bind;
+-	audio->card.func.unbind = f_audio_unbind;
+-	audio->card.func.set_alt = f_audio_set_alt;
+-	audio->card.func.setup = f_audio_setup;
+-	audio->card.func.disable = f_audio_disable;
+-	audio->card.func.free_func = f_audio_free;
+-
+-	control_selector_init(audio);
+ 
+-	INIT_WORK(&audio->playback_work, f_audio_playback_work);
++	uac1->uac_dev.func.name = "uac1_func";
++	uac1->uac_dev.func.bind = f_audio_bind;
++	uac1->uac_dev.func.unbind = f_audio_unbind;
++	uac1->uac_dev.func.set_alt = f_audio_set_alt;
++	uac1->uac_dev.func.get_alt = f_audio_get_alt;
++	uac1->uac_dev.func.setup = f_audio_setup;
++	uac1->uac_dev.func.disable = f_audio_disable;
++	uac1->uac_dev.func.free_func = f_audio_free;
+ 
+-	return &audio->card.func;
++	return &uac1->uac_dev.func;
+ }
+ 
+ DECLARE_USB_FUNCTION_INIT(uac1, f_audio_alloc_inst, f_audio_alloc);
+ MODULE_LICENSE("GPL");
+-MODULE_AUTHOR("Bryan Wu");
++MODULE_AUTHOR("Ruslan Bilovol");
+diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c
+index 945b3bd..04fb4a9 100644
+--- a/drivers/usb/gadget/function/f_uvc.c
++++ b/drivers/usb/gadget/function/f_uvc.c
+@@ -32,6 +32,17 @@
+ #include "uvc_video.h"
+ #include "u_uvc.h"
+ 
++
++static unsigned int bulk_max_size = 1024;
++module_param(bulk_max_size, uint, S_IRUGO|S_IWUSR);
++MODULE_PARM_DESC(bulk_max_size, "bulk max size");
++
++static bool bulk_streaming_ep;
++module_param(bulk_streaming_ep, bool, S_IRUGO|S_IWUSR);
++MODULE_PARM_DESC(bulk_streaming_ep, "0 (Use ISOC video streaming ep) / "
++					"1 (Use BULK video streaming ep)");
++
++
+ unsigned int uvc_gadget_trace_param;
+ 
+ /* --------------------------------------------------------------------------
+@@ -197,6 +208,85 @@ static const struct usb_descriptor_header * const uvc_ss_streaming[] = {
+ 	NULL,
+ };
+ 
++static struct usb_interface_descriptor uvc_bulk_streaming_intf_alt0 = {
++	.bLength		= USB_DT_INTERFACE_SIZE,
++	.bDescriptorType	= USB_DT_INTERFACE,
++	.bInterfaceNumber	= UVC_INTF_VIDEO_STREAMING,
++	.bAlternateSetting	= 0,
++	.bNumEndpoints		= 1,
++	.bInterfaceClass	= USB_CLASS_VIDEO,
++	.bInterfaceSubClass	= UVC_SC_VIDEOSTREAMING,
++	.bInterfaceProtocol	= 0x00,
++	.iInterface		= 0,
++};
++
++
++static struct usb_endpoint_descriptor uvc_fs_bulk_streaming_ep = {
++	.bLength		= USB_DT_ENDPOINT_SIZE,
++	.bDescriptorType	= USB_DT_ENDPOINT,
++	.bEndpointAddress	= USB_DIR_IN,
++	.bmAttributes		= USB_ENDPOINT_XFER_BULK,
++	/* The wMaxPacketSize and bInterval values will be initialized from
++	 * module parameters.
++	 */
++	.wMaxPacketSize		= 0,
++	.bInterval		= 0,
++};
++
++
++static struct usb_endpoint_descriptor uvc_hs_bulk_streaming_ep = {
++	.bLength		= USB_DT_ENDPOINT_SIZE,
++	.bDescriptorType	= USB_DT_ENDPOINT,
++	.bEndpointAddress	= USB_DIR_IN,
++	.bmAttributes		= USB_ENDPOINT_XFER_BULK,
++	/* The wMaxPacketSize and bInterval values will be initialized from
++	 * module parameters.
++	 */
++	.wMaxPacketSize		= 0,
++	.bInterval		= 0,
++};
++
++
++static struct usb_endpoint_descriptor uvc_ss_bulk_streaming_ep = {
++	.bLength		= USB_DT_ENDPOINT_SIZE,
++	.bDescriptorType	= USB_DT_ENDPOINT,
++
++	.bEndpointAddress	= USB_DIR_IN,
++	.bmAttributes		= USB_ENDPOINT_XFER_BULK,
++	/* The wMaxPacketSize and bInterval values will be initialized from
++	 * module parameters.
++	 */
++	.wMaxPacketSize		= 0,
++	.bInterval		= 0,
++};
++
++
++static struct usb_ss_ep_comp_descriptor uvc_ss_bulk_streaming_comp
++ = {
++	.bLength		= sizeof(uvc_ss_bulk_streaming_comp),
++	.bDescriptorType	= USB_DT_SS_ENDPOINT_COMP,
++	/* The following 3 values can be tweaked if necessary. */
++	.bMaxBurst		= 0,
++	.bmAttributes		= 0,
++	.wBytesPerInterval	= cpu_to_le16(1024),
++};
++
++static const struct usb_descriptor_header * const uvc_fs_bulk_streaming[] = {
++	(struct usb_descriptor_header *) &uvc_fs_bulk_streaming_ep,
++	NULL,
++};
++
++static const struct usb_descriptor_header * const uvc_hs_bulk_streaming[] = {
++	(struct usb_descriptor_header *) &uvc_hs_bulk_streaming_ep,
++	NULL,
++};
++
++static const struct usb_descriptor_header * const uvc_ss_bulk_streaming[] = {
++	(struct usb_descriptor_header *) &uvc_ss_bulk_streaming_ep,
++	(struct usb_descriptor_header *) &uvc_ss_bulk_streaming_comp,
++	NULL,
++};
++
+ void uvc_set_trace_param(unsigned int trace)
+ {
+ 	uvc_gadget_trace_param = trace;
+@@ -278,8 +368,20 @@ uvc_function_get_alt(struct usb_function *f, unsigned interface)
+ 		return 0;
+ 	else if (interface != uvc->streaming_intf)
+ 		return -EINVAL;
+-	else
+-		return uvc->video.ep->driver_data ? 1 : 0;
++	else {
++		/*
++		 * Alt settings in an interface are supported only for
++		 * ISOC endpoints as there are different alt-settings for
++		 * zero-bandwidth and full-bandwidth cases, but the same
++		 * is not true for BULK endpoints, as they have a single
++		 * alt-setting.
++		 */
++		if (!bulk_streaming_ep)
++			return uvc->state == UVC_STATE_STREAMING ? 1 : 0;
++		else
++			return 0;
++	}
++
+ }
+ 
+ static int
+@@ -325,55 +427,101 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
+ 	if (interface != uvc->streaming_intf)
+ 		return -EINVAL;
+ 
+-	/* TODO
+-	if (usb_endpoint_xfer_bulk(&uvc->desc.vs_ep))
+-		return alt ? -EINVAL : 0;
+-	*/
++	if (!bulk_streaming_ep) {
++		switch (alt) {
++		case 0:
++			if (uvc->state != UVC_STATE_STREAMING)
++				return 0;
++
++			if (uvc->video.ep) {
++				usb_ep_disable(uvc->video.ep);
++				uvc->video.ep->driver_data = NULL;
++			}
+ 
+-	switch (alt) {
+-	case 0:
+-		if (uvc->state != UVC_STATE_STREAMING)
++			memset(&v4l2_event, 0, sizeof(v4l2_event));
++			v4l2_event.type = UVC_EVENT_STREAMOFF;
++			v4l2_event_queue(uvc->vdev, &v4l2_event);
++
++			uvc->state = UVC_STATE_CONNECTED;
+ 			return 0;
+ 
+-		if (uvc->video.ep) {
+-			usb_ep_disable(uvc->video.ep);
+-			uvc->video.ep->driver_data = NULL;
+-		}
++		case 1:
++			if (uvc->state != UVC_STATE_CONNECTED)
++				return 0;
+ 
+-		memset(&v4l2_event, 0, sizeof(v4l2_event));
+-		v4l2_event.type = UVC_EVENT_STREAMOFF;
+-		v4l2_event_queue(uvc->vdev, &v4l2_event);
++			if (!uvc->video.ep)
++				return -EINVAL;
+ 
+-		uvc->state = UVC_STATE_CONNECTED;
+-		return 0;
++			if (uvc->video.ep->driver_data) {
++				INFO(cdev, "reset UVC\n");
++				usb_ep_disable(uvc->video.ep);
++				uvc->video.ep->driver_data = NULL;
++			}
+ 
+-	case 1:
+-		if (uvc->state != UVC_STATE_CONNECTED)
+-			return 0;
++			ret = config_ep_by_speed(f->config->cdev->gadget,
++					&(uvc->func), uvc->video.ep);
++			if (ret)
++				return ret;
++			usb_ep_enable(uvc->video.ep);
++			uvc->video.ep->driver_data = uvc;
+ 
+-		if (!uvc->video.ep)
+-			return -EINVAL;
++			memset(&v4l2_event, 0, sizeof(v4l2_event));
++			v4l2_event.type = UVC_EVENT_STREAMON;
++			v4l2_event_queue(uvc->vdev, &v4l2_event);
++			return USB_GADGET_DELAYED_STATUS;
+ 
+-		if (uvc->video.ep->driver_data) {
+-			INFO(cdev, "reset UVC\n");
+-			usb_ep_disable(uvc->video.ep);
+-			uvc->video.ep->driver_data = NULL;
++		default:
++			return -EINVAL;
+ 		}
++	} else {
++		switch (uvc->state) {
++		case UVC_STATE_CONNECTED:
++			if (!uvc->video.ep->driver_data) {
++				/*
++				 * Enable the video streaming endpoint,
++				 * but don't change the 'uvc->state'.
++				 */
++				if (uvc->video.ep) {
++					ret = config_ep_by_speed
++						(f->config->cdev->gadget,
++						&(uvc->func), uvc->video.ep);
++					if (ret)
++						return ret;
++					ret = usb_ep_enable(uvc->video.ep);
++					if (ret)
++						return ret;
++
++					uvc->video.ep->driver_data = uvc;
++				}
++			} else {
++				memset(&v4l2_event, 0, sizeof(v4l2_event));
++				v4l2_event.type = UVC_EVENT_STREAMON;
++				v4l2_event_queue(uvc->vdev, &v4l2_event);
++
++				uvc->state = UVC_STATE_STREAMING;
++			}
++			return 0;
+ 
+-		ret = config_ep_by_speed(f->config->cdev->gadget,
+-				&(uvc->func), uvc->video.ep);
+-		if (ret)
+-			return ret;
+-		usb_ep_enable(uvc->video.ep);
+-		uvc->video.ep->driver_data = uvc;
++		case UVC_STATE_STREAMING:
++			if (uvc->video.ep->driver_data) {
++				if (uvc->video.ep) {
++					ret = usb_ep_disable(uvc->video.ep);
++					if (ret)
++						return ret;
++				}
++			}
+ 
+-		memset(&v4l2_event, 0, sizeof(v4l2_event));
+-		v4l2_event.type = UVC_EVENT_STREAMON;
+-		v4l2_event_queue(uvc->vdev, &v4l2_event);
+-		return USB_GADGET_DELAYED_STATUS;
++			memset(&v4l2_event, 0, sizeof(v4l2_event));
++			v4l2_event.type = UVC_EVENT_STREAMOFF;
++			v4l2_event_queue(uvc->vdev, &v4l2_event);
++			uvc->state = UVC_STATE_CONNECTED;
++			INFO(cdev, "uvc_function_set_alt: state to streamoff\n");
+ 
+-	default:
+-		return -EINVAL;
++			return 0;
++
++		default:
++			return -EINVAL;
++		}
+ 	}
+ }
+ 
+@@ -480,6 +628,7 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
+ 	const struct uvc_descriptor_header * const *uvc_streaming_cls;
+ 	const struct usb_descriptor_header * const *uvc_streaming_std;
+ 	const struct usb_descriptor_header * const *src;
++	struct usb_interface_descriptor *streaming_intf_alt0;
+ 	struct usb_descriptor_header **dst;
+ 	struct usb_descriptor_header **hdr;
+ 	unsigned int control_size;
+@@ -488,6 +637,11 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
+ 	unsigned int bytes;
+ 	void *mem;
+ 
++	if (!bulk_streaming_ep)
++		streaming_intf_alt0 = &uvc_streaming_intf_alt0;
++	else
++		streaming_intf_alt0 = &uvc_bulk_streaming_intf_alt0;
++
+ 	switch (speed) {
+ 	case USB_SPEED_SUPER:
+ 		uvc_control_desc = uvc->desc.ss_control;
+@@ -509,6 +663,22 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
+ 		break;
+ 	}
+ 
++	if (bulk_streaming_ep) {
++		switch (speed) {
++		case USB_SPEED_SUPER:
++			uvc_streaming_std = uvc_ss_bulk_streaming;
++			break;
++
++		case USB_SPEED_HIGH:
++			uvc_streaming_std = uvc_hs_bulk_streaming;
++			break;
++
++		case USB_SPEED_FULL:
++		default:
++			uvc_streaming_std = uvc_fs_bulk_streaming;
++			break;
++		}
++	}
+ 	/* Descriptors layout
+ 	 *
+ 	 * uvc_iad
+@@ -526,8 +696,8 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
+ 	control_size = 0;
+ 	streaming_size = 0;
+ 	bytes = uvc_iad.bLength + uvc_control_intf.bLength
+-	      + uvc_control_ep.bLength + uvc_control_cs_ep.bLength
+-	      + uvc_streaming_intf_alt0.bLength;
++		+ uvc_control_ep.bLength + uvc_control_cs_ep.bLength
++		+ streaming_intf_alt0->bLength;
+ 
+ 	if (speed == USB_SPEED_SUPER) {
+ 		bytes += uvc_ss_control_comp.bLength;
+@@ -537,13 +707,13 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
+ 	}
+ 
+ 	for (src = (const struct usb_descriptor_header **)uvc_control_desc;
+-	     *src; ++src) {
++			*src; ++src) {
+ 		control_size += (*src)->bLength;
+ 		bytes += (*src)->bLength;
+ 		n_desc++;
+ 	}
+ 	for (src = (const struct usb_descriptor_header **)uvc_streaming_cls;
+-	     *src; ++src) {
++			*src; ++src) {
+ 		streaming_size += (*src)->bLength;
+ 		bytes += (*src)->bLength;
+ 		n_desc++;
+@@ -577,7 +747,7 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
+ 		UVC_COPY_DESCRIPTOR(mem, dst, &uvc_ss_control_comp);
+ 
+ 	UVC_COPY_DESCRIPTOR(mem, dst, &uvc_control_cs_ep);
+-	UVC_COPY_DESCRIPTOR(mem, dst, &uvc_streaming_intf_alt0);
++	UVC_COPY_DESCRIPTOR(mem, dst, streaming_intf_alt0);
+ 
+ 	uvc_streaming_header = mem;
+ 	UVC_COPY_DESCRIPTORS(mem, dst,
+@@ -605,13 +775,21 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
+ 
+ 	INFO(cdev, "uvc_function_bind\n");
+ 
++	/* Use Bulk endpoint for video streaming?. */
++	uvc->video.bulk_streaming_ep = bulk_streaming_ep;
++	uvc->video.bulk_max_size = bulk_max_size;
++
+ 	opts = to_f_uvc_opts(f->fi);
+ 	/* Sanity check the streaming endpoint module parameters.
+ 	 */
+-	opts->streaming_interval = clamp(opts->streaming_interval, 1U, 16U);
+-	opts->streaming_maxpacket = clamp(opts->streaming_maxpacket, 1U, 3072U);
+-	opts->streaming_maxburst = min(opts->streaming_maxburst, 15U);
+-
++	if (!bulk_streaming_ep) {
++		opts->streaming_interval = clamp(opts->streaming_interval, 1U, 16U);
++		opts->streaming_maxpacket = clamp(opts->streaming_maxpacket, 1U, 3072U);
++		opts->streaming_maxburst = min(opts->streaming_maxburst, 15U);
++	} else {
++		opts->streaming_maxpacket = clamp(opts->streaming_maxpacket, 1U, 1024U);
++		opts->streaming_maxburst = min(opts->streaming_maxburst, 15U);
++	}
+ 	/* Fill in the FS/HS/SS Video Streaming specific descriptors from the
+ 	 * module parameters.
+ 	 *
+@@ -629,21 +807,33 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
+ 		max_packet_size = opts->streaming_maxpacket / 3;
+ 	}
+ 
+-	uvc_fs_streaming_ep.wMaxPacketSize =
+-		cpu_to_le16(min(opts->streaming_maxpacket, 1023U));
+-	uvc_fs_streaming_ep.bInterval = opts->streaming_interval;
++	if (!bulk_streaming_ep) {
++		uvc_fs_streaming_ep.wMaxPacketSize =
++			cpu_to_le16(min(opts->streaming_maxpacket, 1023U));
++		uvc_fs_streaming_ep.bInterval = opts->streaming_interval;
+ 
+-	uvc_hs_streaming_ep.wMaxPacketSize =
+-		cpu_to_le16(max_packet_size | ((max_packet_mult - 1) << 11));
+-	uvc_hs_streaming_ep.bInterval = opts->streaming_interval;
++		uvc_hs_streaming_ep.wMaxPacketSize =
++			cpu_to_le16(max_packet_size | ((max_packet_mult - 1) << 11));
++		uvc_hs_streaming_ep.bInterval = opts->streaming_interval;
+ 
+-	uvc_ss_streaming_ep.wMaxPacketSize = cpu_to_le16(max_packet_size);
+-	uvc_ss_streaming_ep.bInterval = opts->streaming_interval;
+-	uvc_ss_streaming_comp.bmAttributes = max_packet_mult - 1;
+-	uvc_ss_streaming_comp.bMaxBurst = opts->streaming_maxburst;
+-	uvc_ss_streaming_comp.wBytesPerInterval =
+-		cpu_to_le16(max_packet_size * max_packet_mult *
+-			    opts->streaming_maxburst);
++		uvc_ss_streaming_ep.wMaxPacketSize = cpu_to_le16(max_packet_size);
++		uvc_ss_streaming_ep.bInterval = opts->streaming_interval;
++		uvc_ss_streaming_comp.bmAttributes = max_packet_mult - 1;
++		uvc_ss_streaming_comp.bMaxBurst = opts->streaming_maxburst;
++		uvc_ss_streaming_comp.wBytesPerInterval =
++			cpu_to_le16(max_packet_size * max_packet_mult *
++					opts->streaming_maxburst);
++
++	} else {
++		uvc_fs_bulk_streaming_ep.wMaxPacketSize =
++					min(opts->streaming_maxpacket, 64U);
++
++		uvc_hs_bulk_streaming_ep.wMaxPacketSize = 512;
++		uvc_ss_bulk_streaming_ep.wMaxPacketSize = max_packet_size;
++		uvc_ss_streaming_comp.bMaxBurst = opts->streaming_maxburst;
++		uvc_ss_streaming_comp.wBytesPerInterval =
++			max_packet_size * opts->streaming_maxburst;
++	}
+ 
+ 	/* Allocate endpoints. */
+ 	ep = usb_ep_autoconfig(cdev->gadget, &uvc_control_ep);
+@@ -654,14 +844,31 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
+ 	uvc->control_ep = ep;
+ 	ep->driver_data = uvc;
+ 
+-	if (gadget_is_superspeed(c->cdev->gadget))
+-		ep = usb_ep_autoconfig_ss(cdev->gadget, &uvc_ss_streaming_ep,
+-					  &uvc_ss_streaming_comp);
+-	else if (gadget_is_dualspeed(cdev->gadget))
+-		ep = usb_ep_autoconfig(cdev->gadget, &uvc_hs_streaming_ep);
+-	else
+-		ep = usb_ep_autoconfig(cdev->gadget, &uvc_fs_streaming_ep);
+-
++	if (gadget_is_superspeed(c->cdev->gadget)) {
++		if (!bulk_streaming_ep)
++			ep = usb_ep_autoconfig_ss(cdev->gadget,
++						&uvc_ss_streaming_ep,
++						&uvc_ss_streaming_comp);
++		else
++			ep = usb_ep_autoconfig_ss(cdev->gadget,
++						&uvc_ss_bulk_streaming_ep,
++						&uvc_ss_bulk_streaming_comp);
++
++	} else if (gadget_is_dualspeed(cdev->gadget)) {
++		if (!bulk_streaming_ep)
++			ep = usb_ep_autoconfig(cdev->gadget,
++					&uvc_hs_streaming_ep);
++		else
++			ep = usb_ep_autoconfig(cdev->gadget,
++					&uvc_hs_bulk_streaming_ep);
++	} else {
++		if (!bulk_streaming_ep)
++			ep = usb_ep_autoconfig(cdev->gadget,
++					&uvc_fs_streaming_ep);
++		else
++			ep = usb_ep_autoconfig(cdev->gadget,
++					&uvc_fs_bulk_streaming_ep);
++	}
+ 	if (!ep) {
+ 		INFO(cdev, "Unable to allocate streaming EP\n");
+ 		goto error;
+@@ -669,9 +876,18 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
+ 	uvc->video.ep = ep;
+ 	ep->driver_data = uvc;
+ 
+-	uvc_fs_streaming_ep.bEndpointAddress = uvc->video.ep->address;
+-	uvc_hs_streaming_ep.bEndpointAddress = uvc->video.ep->address;
+-	uvc_ss_streaming_ep.bEndpointAddress = uvc->video.ep->address;
++	if (!bulk_streaming_ep) {
++		uvc_fs_streaming_ep.bEndpointAddress = uvc->video.ep->address;
++		uvc_hs_streaming_ep.bEndpointAddress = uvc->video.ep->address;
++		uvc_ss_streaming_ep.bEndpointAddress = uvc->video.ep->address;
++	} else {
++		uvc_fs_bulk_streaming_ep.bEndpointAddress =
++					uvc->video.ep->address;
++		uvc_hs_bulk_streaming_ep.bEndpointAddress =
++					uvc->video.ep->address;
++		uvc_ss_bulk_streaming_ep.bEndpointAddress =
++					uvc->video.ep->address;
++	}
+ 
+ 	us = usb_gstrings_attach(cdev, uvc_function_strings,
+ 				 ARRAY_SIZE(uvc_en_us_strings));
+@@ -682,8 +898,13 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
+ 	uvc_iad.iFunction = us[UVC_STRING_CONTROL_IDX].id;
+ 	uvc_control_intf.iInterface = us[UVC_STRING_CONTROL_IDX].id;
+ 	ret = us[UVC_STRING_STREAMING_IDX].id;
+-	uvc_streaming_intf_alt0.iInterface = ret;
+-	uvc_streaming_intf_alt1.iInterface = ret;
++
++	if (!bulk_streaming_ep) {
++		uvc_streaming_intf_alt0.iInterface = ret;
++		uvc_streaming_intf_alt1.iInterface = ret;
++	} else {
++		uvc_bulk_streaming_intf_alt0.iInterface = ret;
++	}
+ 
+ 	/* Allocate interface IDs. */
+ 	if ((ret = usb_interface_id(c, f)) < 0)
+@@ -694,8 +915,15 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
+ 
+ 	if ((ret = usb_interface_id(c, f)) < 0)
+ 		goto error;
+-	uvc_streaming_intf_alt0.bInterfaceNumber = ret;
+-	uvc_streaming_intf_alt1.bInterfaceNumber = ret;
++
++	if (!bulk_streaming_ep) {
++
++		uvc_streaming_intf_alt0.bInterfaceNumber = ret;
++		uvc_streaming_intf_alt1.bInterfaceNumber = ret;
++	} else {
++		uvc_bulk_streaming_intf_alt0.bInterfaceNumber = ret;
++	}
++
+ 	uvc->streaming_intf = ret;
+ 
+ 	/* Copy descriptors */
+@@ -720,6 +948,7 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
+ 	/* Avoid letting this gadget enumerate until the userspace server is
+ 	 * active.
+ 	 */
++
+ 	if ((ret = usb_function_deactivate(f)) < 0)
+ 		goto error;
+ 
+diff --git a/drivers/usb/gadget/function/rndis.c b/drivers/usb/gadget/function/rndis.c
+index 95d2324..6411667 100644
+--- a/drivers/usb/gadget/function/rndis.c
++++ b/drivers/usb/gadget/function/rndis.c
+@@ -41,6 +41,24 @@
+ 
+ #include "rndis.h"
+ 
++typedef enum
++{
++	RNDIS_SKB_IDLE=0,
++	RNDIS_SKB_COMBINING,
++	RNDIS_SKB_COMBINED,
++}rndis_skb_status;
++
++typedef struct{
++	rndis_skb_status status;
++	int msgtype;
++	int msglen;
++	int halflen;
++	int datalen;
++	int dataoffset;
++	struct sk_buff *skb;
++}rndis_skb_recombine;
++rndis_skb_recombine g_skb[2];
++
+ 
+ /* The driver for your USB chip needs to support ep0 OUT to work with
+  * RNDIS, plus all three CDC Ethernet endpoints (interrupt not optional).
+@@ -59,6 +77,16 @@ MODULE_PARM_DESC (rndis_debug, "enable debugging");
+ 
+ #define RNDIS_MAX_CONFIGS	1
+ 
++int rndis_ul_max_pkt_per_xfer_rcvd;
++module_param(rndis_ul_max_pkt_per_xfer_rcvd, int, S_IRUGO);
++MODULE_PARM_DESC(rndis_ul_max_pkt_per_xfer_rcvd,
++		"Max num of REMOTE_NDIS_PACKET_MSGs received in a single transfer");
++
++int rndis_ul_max_xfer_size_rcvd;
++module_param(rndis_ul_max_xfer_size_rcvd, int, S_IRUGO);
++MODULE_PARM_DESC(rndis_ul_max_xfer_size_rcvd,
++		"Max size of bus transfer received");
++
+ 
+ static rndis_params rndis_per_dev_params[RNDIS_MAX_CONFIGS];
+ 
+@@ -585,12 +613,12 @@ static int rndis_init_response(int configNr, rndis_init_msg_type *buf)
+ 	resp->MinorVersion = cpu_to_le32(RNDIS_MINOR_VERSION);
+ 	resp->DeviceFlags = cpu_to_le32(RNDIS_DF_CONNECTIONLESS);
+ 	resp->Medium = cpu_to_le32(RNDIS_MEDIUM_802_3);
+-	resp->MaxPacketsPerTransfer = cpu_to_le32(1);
+-	resp->MaxTransferSize = cpu_to_le32(
+-		  params->dev->mtu
++	resp->MaxPacketsPerTransfer = cpu_to_le32(params->max_pkt_per_xfer);
++	resp->MaxTransferSize = cpu_to_le32(params->max_pkt_per_xfer *
++		(params->dev->mtu
+ 		+ sizeof(struct ethhdr)
+ 		+ sizeof(struct rndis_packet_msg_type)
+-		+ 22);
++		+ 22));
+ 	resp->PacketAlignmentFactor = cpu_to_le32(0);
+ 	resp->AFListOffset = cpu_to_le32(0);
+ 	resp->AFListSize = cpu_to_le32(0);
+@@ -686,6 +714,12 @@ static int rndis_reset_response(int configNr, rndis_reset_msg_type *buf)
+ 	rndis_reset_cmplt_type *resp;
+ 	rndis_resp_t *r;
+ 	struct rndis_params *params = rndis_per_dev_params + configNr;
++	u32 length;
++	u8 *xbuf;
++
++	/* drain the response queue */
++	while ((xbuf = rndis_get_next_response(configNr, &length)))
++		rndis_free_response(configNr, xbuf);
+ 
+ 	r = rndis_add_response(configNr, sizeof(rndis_reset_cmplt_type));
+ 	if (!r)
+@@ -917,6 +951,8 @@ int rndis_set_param_dev(u8 configNr, struct net_device *dev, u16 *cdc_filter)
+ 	rndis_per_dev_params[configNr].dev = dev;
+ 	rndis_per_dev_params[configNr].filter = cdc_filter;
+ 
++	rndis_ul_max_xfer_size_rcvd = 0;
++	rndis_ul_max_pkt_per_xfer_rcvd = 0;
+ 	return 0;
+ }
+ EXPORT_SYMBOL_GPL(rndis_set_param_dev);
+@@ -946,6 +982,13 @@ int rndis_set_param_medium(u8 configNr, u32 medium, u32 speed)
+ }
+ EXPORT_SYMBOL_GPL(rndis_set_param_medium);
+ 
++void rndis_set_max_pkt_xfer(u8 configNr, u8 max_pkt_per_xfer)
++{
++	pr_debug("%s:\n", __func__);
++
++	rndis_per_dev_params[configNr].max_pkt_per_xfer = max_pkt_per_xfer;
++}
++
+ void rndis_add_hdr(struct sk_buff *skb)
+ {
+ 	struct rndis_packet_msg_type *header;
+@@ -1021,23 +1064,135 @@ int rndis_rm_hdr(struct gether *port,
+ 			struct sk_buff *skb,
+ 			struct sk_buff_head *list)
+ {
+-	/* tmp points to a struct rndis_packet_msg_type */
+-	__le32 *tmp = (void *)skb->data;
++	int num_pkts = 1,i = 0;
++
++	if (skb->len > rndis_ul_max_xfer_size_rcvd)
++		rndis_ul_max_xfer_size_rcvd = skb->len;
++
++	while (skb->len) {
++		struct rndis_packet_msg_type *hdr;
++		struct sk_buff          *skb2;
++		u32             msg_len, data_offset, data_len;
++		/*recombine broken packet and add to skb process queue*/
++		int index = 0;
++		for(i=0;i< (sizeof(g_skb)/sizeof(rndis_skb_recombine));i++){
++			if(RNDIS_SKB_COMBINING == g_skb[i].status){
++				g_skb[i].status = RNDIS_SKB_COMBINED;
++				memcpy(g_skb[i].skb->data+g_skb[i].halflen,skb->data,g_skb[i].msglen-g_skb[i].halflen);
++				skb_pull(skb, g_skb[i].msglen-g_skb[i].halflen);//update skb
++				g_skb[i].skb->data += g_skb[i].dataoffset+8;
++				g_skb[i].skb->len = g_skb[i].datalen;
++				g_skb[i].skb->tail = g_skb[i].skb->data + g_skb[i].skb->len;
++				index = i + 1;
++				break;
++			}
++		}
++		if(index){
++			if((g_skb[i].dataoffset + g_skb[i].datalen + 8) > g_skb[i].msglen){
++				pr_err("invalid rndis message: %d/%d/%d/%d, len:%d\n",
++						g_skb[i].msgtype,g_skb[i].msglen, g_skb[i].dataoffset, g_skb[i].datalen, skb->len);
++				dev_kfree_skb_any(g_skb[i].skb);
++				continue;
++			}
++			if (g_skb[i].msgtype != RNDIS_MSG_PACKET) {
++				pr_err("invalid rndis message: %d/%d/%d/%d, len:%d\n",
++						g_skb[i].msgtype,g_skb[i].msglen, g_skb[i].dataoffset, g_skb[i].datalen, skb->len);
++				dev_kfree_skb_any(g_skb[i].skb);
++				continue;
++			}
++			skb_queue_tail(list, g_skb[i].skb);
++			num_pkts++;
++			continue;
++		}
++		/* some rndis hosts send extra byte to avoid zlp, ignore it */
++		if (skb->len == 1) {
++			dev_kfree_skb_any(skb);
++			return 0;
++		}
+ 
+-	/* MessageType, MessageLength */
+-	if (cpu_to_le32(RNDIS_MSG_PACKET)
+-			!= get_unaligned(tmp++)) {
+-		dev_kfree_skb_any(skb);
+-		return -EINVAL;
+-	}
+-	tmp++;
++		if (skb->len < sizeof *hdr) {
++			pr_err("invalid rndis pkt: skblen:%u hdr_len:%u",
++					skb->len, sizeof *hdr);
++			dev_kfree_skb_any(skb);
++			return -EINVAL;
++		}
++
++		hdr = (void *)skb->data;
++		msg_len = le32_to_cpu(hdr->MessageLength);
++		data_offset = le32_to_cpu(hdr->DataOffset);
++		data_len = le32_to_cpu(hdr->DataLength);
++		/*backup the broken packet for recombining*/
++		if(skb->len < msg_len){
++			int size = 1558+20;
++			for(i=0;i< (sizeof(g_skb)/sizeof(rndis_skb_recombine));i++){
++				if(RNDIS_SKB_IDLE == g_skb[i].status){
++					g_skb[i].status = RNDIS_SKB_COMBINING;
++					g_skb[i].skb = alloc_skb(size + NET_IP_ALIGN, GFP_ATOMIC);
++					if (g_skb[i].skb == NULL) {
++						g_skb[i].status = RNDIS_SKB_IDLE;
++						return -EINVAL;
++					}
++					skb_reserve(g_skb[i].skb, NET_IP_ALIGN);
++					g_skb[i].msgtype = le32_to_cpu(hdr->MessageType);
++					g_skb[i].msglen = msg_len;
++					g_skb[i].dataoffset = data_offset;
++					g_skb[i].datalen = data_len;
++					g_skb[i].halflen = skb->len;
++					memcpy(g_skb[i].skb->data,skb->data,g_skb[i].halflen);
++					skb_pull(skb,g_skb[i].halflen);
++					break;
++				}
++			}
++			if(!skb->len)
++				break;
++			pr_err("invalid rndis message: %d/%d/%d/%d, len:%d\n",
++					le32_to_cpu(hdr->MessageType),
++					msg_len, data_offset, data_len, skb->len);
++			dev_kfree_skb_any(skb);
++			return -EOVERFLOW;
++		}
++        if((data_offset + data_len + 8) > msg_len){
++			pr_err("invalid rndis message: %d/%d/%d/%d, len:%d\n",
++					le32_to_cpu(hdr->MessageType),
++					msg_len, data_offset, data_len, skb->len);
++			dev_kfree_skb_any(skb);
++			return -EOVERFLOW;
++		}
++		if (le32_to_cpu(hdr->MessageType) != RNDIS_MSG_PACKET) {
++			int len = skb->len;
++			skb_pull(skb,len);
++			break;
++		}
+ 
+-	/* DataOffset, DataLength */
+-	if (!skb_pull(skb, get_unaligned_le32(tmp++) + 8)) {
+-		dev_kfree_skb_any(skb);
+-		return -EOVERFLOW;
++		skb_pull(skb, data_offset + 8);
++
++		if (msg_len == skb->len) {
++			skb_trim(skb, data_len);
++			break;
++		}
++
++		skb2 = skb_clone(skb, GFP_ATOMIC);
++		if (!skb2) {
++			pr_err("%s:skb clone failed\n", __func__);
++			dev_kfree_skb_any(skb);
++			return -ENOMEM;
++		}
++
++		skb_pull(skb, msg_len - sizeof *hdr);
++		skb_trim(skb2, data_len);
++		skb_queue_tail(list, skb2);
++
++		num_pkts++;
+ 	}
+-	skb_trim(skb, get_unaligned_le32(tmp++));
++
++	if (num_pkts > rndis_ul_max_pkt_per_xfer_rcvd)
++		rndis_ul_max_pkt_per_xfer_rcvd = num_pkts;
++	/*recombinant is finished, update combining status*/
++
++	if(RNDIS_SKB_COMBINED == g_skb[0].status)
++		g_skb[0].status = RNDIS_SKB_IDLE;
++	if(RNDIS_SKB_COMBINED == g_skb[1].status)
++		g_skb[1].status = RNDIS_SKB_IDLE;
+ 
+ 	skb_queue_tail(list, skb);
+ 	return 0;
+diff --git a/drivers/usb/gadget/function/rndis.h b/drivers/usb/gadget/function/rndis.h
+index 0f4abb4..145f01b 100644
+--- a/drivers/usb/gadget/function/rndis.h
++++ b/drivers/usb/gadget/function/rndis.h
+@@ -190,6 +190,7 @@ typedef struct rndis_params
+ 	struct net_device	*dev;
+ 
+ 	u32			vendorID;
++	u8			max_pkt_per_xfer;
+ 	const char		*vendorDescr;
+ 	void			(*resp_avail)(void *v);
+ 	void			*v;
+@@ -205,6 +206,7 @@ int  rndis_set_param_dev (u8 configNr, struct net_device *dev,
+ int  rndis_set_param_vendor (u8 configNr, u32 vendorID,
+ 			    const char *vendorDescr);
+ int  rndis_set_param_medium (u8 configNr, u32 medium, u32 speed);
++void rndis_set_max_pkt_xfer(u8 configNr, u8 max_pkt_per_xfer);
+ void rndis_add_hdr (struct sk_buff *skb);
+ int rndis_rm_hdr(struct gether *port, struct sk_buff *skb,
+ 			struct sk_buff_head *list);
+diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c
+index 6e6f876..f1fd777 100644
+--- a/drivers/usb/gadget/function/u_ether.c
++++ b/drivers/usb/gadget/function/u_ether.c
+@@ -729,9 +729,7 @@ static int get_ether_addr_str(u8 dev_addr[ETH_ALEN], char *str, int len)
+ 	if (len < 18)
+ 		return -EINVAL;
+ 
+-	snprintf(str, len, "%02x:%02x:%02x:%02x:%02x:%02x",
+-		 dev_addr[0], dev_addr[1], dev_addr[2],
+-		 dev_addr[3], dev_addr[4], dev_addr[5]);
++	snprintf(str, len, "%pM", dev_addr);
+ 	return 18;
+ }
+ 
+diff --git a/drivers/usb/gadget/function/u_ether.h b/drivers/usb/gadget/function/u_ether.h
+index 334b389..f591f74 100644
+--- a/drivers/usb/gadget/function/u_ether.h
++++ b/drivers/usb/gadget/function/u_ether.h
+@@ -75,6 +75,9 @@ struct gether {
+ 	bool				is_fixed;
+ 	u32				fixed_out_len;
+ 	u32				fixed_in_len;
++	unsigned		ul_max_pkts_per_xfer;
++	unsigned		dl_max_pkts_per_xfer;
++	bool				multi_pkt_xfer;
+ 	bool				supports_multi_frame;
+ 	struct sk_buff			*(*wrap)(struct gether *port,
+ 						struct sk_buff *skb);
+diff --git a/drivers/usb/gadget/function/u_midi.h b/drivers/usb/gadget/function/u_midi.h
+new file mode 100644
+index 0000000..2251018
+--- /dev/null
++++ b/drivers/usb/gadget/function/u_midi.h
+@@ -0,0 +1,40 @@
++/*
++ * u_midi.h
++ *
++ * Utility definitions for the midi function
++ *
++ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
++ *		http://www.samsung.com
++ *
++ * Author: Andrzej Pietrasiewicz <andrzej.p@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 U_MIDI_H
++#define U_MIDI_H
++
++#include <linux/usb/composite.h>
++
++struct f_midi_opts {
++	struct usb_function_instance	func_inst;
++	int				index;
++	char				*id;
++	bool				id_allocated;
++	unsigned int			in_ports;
++	unsigned int			out_ports;
++	unsigned int			buflen;
++	unsigned int			qlen;
++
++	/*
++	 * Protect the data form concurrent access by read/write
++	 * and create symlink/remove symlink.
++	 */
++	 struct mutex			lock;
++	 int				refcnt;
++};
++
++#endif /* U_MIDI_H */
++
+diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c
+index 491082a..d9b867a 100644
+--- a/drivers/usb/gadget/function/u_serial.c
++++ b/drivers/usb/gadget/function/u_serial.c
+@@ -1122,6 +1122,7 @@ int gserial_alloc_line(unsigned char *line_num)
+ 
+ 	tty_dev = tty_port_register_device(&ports[port_num].port->port,
+ 			gs_tty_driver, port_num, NULL);
++
+ 	if (IS_ERR(tty_dev)) {
+ 		struct gs_port	*port;
+ 		pr_err("%s: failed to register tty for port %d, err %ld\n",
+diff --git a/drivers/usb/gadget/function/u_uac1.h b/drivers/usb/gadget/function/u_uac1.h
+index f8b17fe..88bddfe 100644
+--- a/drivers/usb/gadget/function/u_uac1.h
++++ b/drivers/usb/gadget/function/u_uac1.h
+@@ -1,85 +1,42 @@
+ /*
+- * u_uac1.h -- interface to USB gadget "ALSA AUDIO" utilities
++ * u_uac1.h - Utility definitions for UAC1 function
+  *
+- * Copyright (C) 2008 Bryan Wu <cooloney@kernel.org>
+- * Copyright (C) 2008 Analog Devices, Inc
++ * Copyright (C) 2016 Ruslan Bilovol <ruslan.bilovol@gmail.com>
+  *
+- * Enter bugs at http://blackfin.uclinux.org/
+- *
+- * Licensed under the GPL-2 or later.
++ * 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 __U_AUDIO_H
+-#define __U_AUDIO_H
++#ifndef __U_UAC1_H
++#define __U_UAC1_H
+ 
+-#include <linux/device.h>
+-#include <linux/err.h>
+-#include <linux/usb/audio.h>
+ #include <linux/usb/composite.h>
+ 
+-#include <sound/core.h>
+-#include <sound/pcm.h>
+-#include <sound/pcm_params.h>
+-
+-#include "gadget_chips.h"
+-
+-#define FILE_PCM_PLAYBACK	"/dev/snd/pcmC0D0p"
+-#define FILE_PCM_CAPTURE	"/dev/snd/pcmC0D0c"
+-#define FILE_CONTROL		"/dev/snd/controlC0"
+ 
++#define UAC1_DEF_CCHMASK	0x3
++#define UAC1_DEF_CSRATE		48000
++#define UAC1_DEF_CSSIZE		2
++#define UAC1_DEF_PCHMASK	0x1//0x3
++#define UAC1_DEF_PSRATE		8000//48000
++#define UAC1_DEF_PSSIZE		2
+ #define UAC1_OUT_EP_MAX_PACKET_SIZE	200
+-#define UAC1_REQ_COUNT			256
+-#define UAC1_AUDIO_BUF_SIZE		48000
+-
+-/*
+- * This represents the USB side of an audio card device, managed by a USB
+- * function which provides control and stream interfaces.
+- */
+-
+-struct gaudio_snd_dev {
+-	struct gaudio			*card;
+-	struct file			*filp;
+-	struct snd_pcm_substream	*substream;
+-	int				access;
+-	int				format;
+-	int				channels;
+-	int				rate;
+-};
+-
+-struct gaudio {
+-	struct usb_function		func;
+-	struct usb_gadget		*gadget;
+-
+-	/* ALSA sound device interfaces */
+-	struct gaudio_snd_dev		control;
+-	struct gaudio_snd_dev		playback;
+-	struct gaudio_snd_dev		capture;
+-
+-	/* TODO */
+-};
++#define UAC1_DEF_REQ_NUM	1
+ 
+ struct f_uac1_opts {
+ 	struct usb_function_instance	func_inst;
+-	int				req_buf_size;
+-	int				req_count;
+-	int				audio_buf_size;
+-	char				*fn_play;
+-	char				*fn_cap;
+-	char				*fn_cntl;
++	int				c_chmask;
++	int				c_srate;
++	int				c_ssize;
++	int				p_chmask;
++	int				p_srate;
++	int				p_ssize;
++	int				req_number;
++	int             req_buf_size;
+ 	unsigned			bound:1;
+-	unsigned			fn_play_alloc:1;
+-	unsigned			fn_cap_alloc:1;
+-	unsigned			fn_cntl_alloc:1;
+-	struct gaudio			*card;
++
+ 	struct mutex			lock;
+ 	int				refcnt;
+ };
+ 
+-int gaudio_setup(struct gaudio *card);
+-void gaudio_cleanup(struct gaudio *the_card);
+-
+-size_t u_audio_playback(struct gaudio *card, void *buf, size_t count);
+-int u_audio_get_playback_channels(struct gaudio *card);
+-int u_audio_get_playback_rate(struct gaudio *card);
+-
+-#endif /* __U_AUDIO_H */
++#endif /* __U_UAC1_H */
+diff --git a/drivers/usb/gadget/function/uac_audio_ex.c b/drivers/usb/gadget/function/uac_audio_ex.c
+new file mode 100644
+index 0000000..c7ef83b
+--- /dev/null
++++ b/drivers/usb/gadget/function/uac_audio_ex.c
+@@ -0,0 +1,275 @@
++/*
++ * uac_device.c -- interface to USB gadget "ALSA sound card" utilities
++ *
++ * Copyright (C) 2016
++ * Author: Ruslan Bilovol <ruslan.bilovol@gmail.com>
++ *
++ * Sound card implementation was cut-and-pasted with changes
++ * from f_uac2.c and has:
++ *    Copyright (C) 2011
++ *    Yadwinder Singh (yadi.brar01@gmail.com)
++ *    Jaswinder Singh (jaswinder.singh@linaro.org)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/module.h>
++#include <sound/core.h>
++#include <sound/pcm.h>
++#include <sound/pcm_params.h>
++
++#include "uac_queue_ex.h"
++#include "uac_ex.h"
++
++static void
++__uac_audio_complete(struct usb_ep *ep, struct usb_request *req)
++{
++	struct uac_device *uac_dev = req->context;
++	struct uac_queue *queue = &uac_dev->queue;
++	struct uac_buffer *buf;
++
++	unsigned long flags;
++	int ret;
++
++	switch (req->status) {
++	case 0:
++		break;
++
++	case -ESHUTDOWN:	/* disconnect from host. */
++		printk(KERN_DEBUG "AS request cancelled.\n");
++		uac_queue_cancel(queue, 1);
++		goto err;
++
++	default:
++		printk(KERN_INFO "AS request completed with status %d.\n",
++			req->status);
++		uac_queue_cancel(queue, 0);
++		goto err;
++	}
++
++	spin_lock_irqsave(&uac_dev->queue.irqlock, flags);
++	buf = uac_queue_head(&uac_dev->queue);
++	if (buf == NULL) {
++		req->length = 0;
++		goto tran_zero;
++	}
++
++	{
++		/*
++		 * For each IN packet, take the quotient of the current data
++		 * rate and the endpoint's interval as the base packet size.
++		 * If there is a residue from this division, add it to the
++		 * residue accumulator.
++		 */
++		req->length = uac_dev->p_pktsize;
++		uac_dev->p_residue += uac_dev->p_pktsize_residue;
++
++		/*
++		 * Whenever there are more bytes in the accumulator than we
++		 * need to add one more sample frame, increase this packet's
++		 * size and decrease the accumulator.
++		 */
++
++		if (uac_dev->p_residue / uac_dev->p_interval >= uac_dev->p_framesize)
++		{
++			req->length += uac_dev->p_framesize;
++			uac_dev->p_residue -= uac_dev->p_framesize *
++				uac_dev->p_interval;
++		}
++
++		req->actual = req->length;
++	}
++
++	{
++		unsigned int nbytes;
++		void *mem;
++
++		/* Copy video data to the USB buffer. */
++		mem = buf->mem + queue->buf_used;
++		nbytes = min((unsigned int)req->length, buf->bytesused - queue->buf_used);
++
++		memcpy(req->buf, mem, nbytes);
++		queue->buf_used += nbytes;
++
++		req->length = nbytes;
++		req->actual = req->length;
++
++		if (buf->bytesused == uac_dev->queue.buf_used) {
++			uac_dev->queue.buf_used = 0;
++			buf->state = UVC_BUF_STATE_DONE;
++			uac_queue_next_buffer(&uac_dev->queue, buf);
++		}
++	}
++
++tran_zero:
++
++	req->actual = req->length;
++
++	if ((ret = usb_ep_queue(ep, req, GFP_ATOMIC)) < 0) {
++		printk(KERN_INFO "Failed to queue request (%d).\n", ret);
++		usb_ep_set_halt(ep);
++		spin_unlock_irqrestore(&uac_dev->queue.irqlock, flags);
++		uac_queue_cancel(queue, 0);
++	}
++	spin_unlock_irqrestore(&uac_dev->queue.irqlock, flags);
++
++err:
++	return;
++}
++
++static inline void free_ep(struct uac_device *dev, struct usb_ep *ep)
++{
++	struct uac_params *params;
++	int i;
++
++	if (!dev->ep_enabled)
++		return;
++
++	dev->ep_enabled = false;
++	params = &dev->params;
++
++	for (i = 0; i < params->req_number; i++) {
++		if (dev->ureq[i].req) {
++			usb_ep_dequeue(ep, dev->ureq[i].req);
++			usb_ep_free_request(ep, dev->ureq[i].req);
++			dev->ureq[i].req = NULL;
++		}
++	}
++
++	if (usb_ep_disable(ep))
++		printk(KERN_EMERG "%s:%d Error!\n", __func__, __LINE__);
++}
++
++int uac_device_start_playback(struct uac_device *uac_dev)
++{
++	struct usb_gadget *gadget = uac_dev->gadget;
++	struct usb_request *req;
++	struct usb_ep *ep;
++	struct uac_params *params = &uac_dev->params;
++	unsigned int factor, rate;
++	const struct usb_endpoint_descriptor *ep_desc;
++	int req_len, i;
++
++	if (uac_dev->ep_enabled)
++		return 0;
++
++	ep = uac_dev->in_ep;
++	config_ep_by_speed(gadget, &uac_dev->func, ep);
++	ep_desc = ep->desc;
++
++	/* pre-calculate the playback endpoint's interval */
++	if (gadget->speed == USB_SPEED_FULL)
++		factor = 1000;
++	else
++		factor = 8000;
++
++	/* pre-compute some values for iso_complete() */
++	uac_dev->p_framesize = params->p_ssize *
++		num_channels(params->p_chmask);
++	rate = params->p_srate * uac_dev->p_framesize;
++	uac_dev->p_interval = factor / (1 << (ep_desc->bInterval - 1));
++	uac_dev->p_pktsize = min_t(unsigned int, rate / uac_dev->p_interval,
++				uac_dev->max_psize);
++
++	if (uac_dev->p_pktsize < uac_dev->max_psize)
++		uac_dev->p_pktsize_residue = rate % uac_dev->p_interval;
++	else
++		uac_dev->p_pktsize_residue = 0;
++
++	req_len = uac_dev->p_pktsize;
++	uac_dev->p_residue = 0;
++
++	uac_dev->ep_enabled = true;
++	usb_ep_enable(ep);
++
++	printk(KERN_EMERG "p_framesize=%d p_interval=%d p_pktsize=%d \
++					p_pktsize_residue=%d m=%d\n",
++					uac_dev->p_framesize,
++					uac_dev->p_interval,
++					uac_dev->p_pktsize,
++					uac_dev->p_pktsize_residue,
++					uac_dev->max_psize);
++
++	for (i = 0; i < params->req_number; i++) {
++		if (!uac_dev->ureq[i].req) {
++			req = usb_ep_alloc_request(ep, GFP_ATOMIC);
++			if (req == NULL)
++				return -ENOMEM;
++
++			uac_dev->ureq[i].req = req;
++			uac_dev->ureq[i].dev = uac_dev;
++
++			req->zero = 0;
++			req->context = uac_dev;
++			req->length = req_len;
++			req->complete = __uac_audio_complete;
++			req->buf = uac_dev->rbuf + i * uac_dev->max_psize;
++		}
++
++		if (usb_ep_queue(ep, uac_dev->ureq[i].req, GFP_ATOMIC))
++			printk(KERN_EMERG "%s:%d Error!\n", __func__, __LINE__);
++	}
++
++	return 0;
++}
++
++void uac_device_stop_playback(struct uac_device *uac_dev)
++{
++	free_ep(uac_dev, uac_dev->in_ep);
++}
++
++int uac_device_setup(struct uac_device *uac_dev)
++{
++	struct uac_params *params;
++	int p_chmask;
++	int err = 0;
++
++	if (!uac_dev)
++		return -EINVAL;
++
++	params = &uac_dev->params;
++	p_chmask = params->p_chmask;
++
++	if (p_chmask) {
++		uac_dev->max_psize = uac_dev->in_ep_maxpsize;
++		uac_dev->ureq = kcalloc(params->req_number, sizeof(struct uac_req),
++				GFP_KERNEL);
++		if (!uac_dev->ureq) {
++			err = -ENOMEM;
++			goto fail;
++		}
++
++		uac_dev->rbuf = kcalloc(params->req_number, uac_dev->max_psize,
++				GFP_KERNEL);
++		if (!uac_dev->rbuf) {
++			uac_dev->max_psize = 0;
++			err = -ENOMEM;
++			goto fail;
++		}
++	}
++
++	if (!err)
++		return 0;
++fail:
++	kfree(uac_dev->ureq);
++	kfree(uac_dev->rbuf);
++
++	return err;
++}
++
++void uac_device_cleanup(struct uac_device *uac_dev)
++{
++	if (!uac_dev)
++		return;
++
++	kfree(uac_dev->ureq);
++	kfree(uac_dev->rbuf);
++}
+diff --git a/drivers/usb/gadget/function/uac_ex.h b/drivers/usb/gadget/function/uac_ex.h
+new file mode 100644
+index 0000000..a62708c
+--- /dev/null
++++ b/drivers/usb/gadget/function/uac_ex.h
+@@ -0,0 +1,133 @@
++/*
++ * The file defines UAC API for user space
++ */
++
++#ifndef _UAC_EX_H_
++#define _UAC_EX_H_
++
++#include <linux/ioctl.h>
++#include <linux/types.h>
++#include <linux/usb/ch9.h>
++
++#define UAC_EVENT_FIRST			(V4L2_EVENT_PRIVATE_START + 0)
++#define UAC_EVENT_CONNECT		(V4L2_EVENT_PRIVATE_START + 0)
++#define UAC_EVENT_DISCONNECT		(V4L2_EVENT_PRIVATE_START + 1)
++#define UAC_EVENT_STREAMON		(V4L2_EVENT_PRIVATE_START + 2)
++#define UAC_EVENT_STREAMOFF		(V4L2_EVENT_PRIVATE_START + 3)
++#define UAC_EVENT_SETUP			(V4L2_EVENT_PRIVATE_START + 4)
++#define UAC_EVENT_DATA			(V4L2_EVENT_PRIVATE_START + 5)
++#define UAC_EVENT_LAST			(V4L2_EVENT_PRIVATE_START + 5)
++
++#ifdef __KERNEL__
++
++#include <linux/usb.h>	/* For usb_endpoint_* */
++#include <linux/usb/composite.h>
++#include <linux/usb/gadget.h>
++#include <linux/videodev2.h>
++#include <linux/version.h>
++#include <media/v4l2-fh.h>
++#include <media/v4l2-device.h>
++
++#include "uac_queue_ex.h"
++
++struct uac_request_data
++{
++	__s32 length;
++	__u8 data[60];
++};
++
++struct uac_event
++{
++	union {
++		struct uac_request_data data;
++	};
++};
++
++/* ------------------------------------------------------------------------
++ * Structures
++ */
++
++struct uac_params {
++	/* playback */
++	int p_chmask;	/* channel mask */
++	int p_srate;	/* rate in Hz */
++	int p_ssize;	/* sample size */
++
++	/* capture */
++	int c_chmask;	/* channel mask */
++	int c_srate;	/* rate in Hz */
++	int c_ssize;	/* sample size */
++
++	int req_number; /* number of preallocated requests */
++};
++
++struct uac_req {
++	struct uac_device *dev; /* parent param */
++	struct usb_request *req;
++};
++
++struct uac_device
++{
++	struct usb_function func;
++	struct usb_gadget *gadget;
++	struct usb_ep *in_ep;
++	struct usb_ep *out_ep;
++	struct uac_params params;
++	struct video_device *vdev;
++	struct v4l2_device v4l2_dev;
++	struct uac_queue queue;
++	struct uac_req *ureq;
++	void *rbuf;
++	struct usb_request *control_req;
++	void *control_buf;
++
++	unsigned int in_ep_maxpsize;
++	unsigned int out_ep_maxpsize;
++	bool ep_enabled; /* if the ep is enabled */
++	unsigned max_psize;	/* MaxPacketSize of endpoint */
++
++	/* timekeeping for the playback endpoint */
++	unsigned int p_interval;
++	unsigned int p_residue;
++
++	/* pre-calculated values for playback iso completion */
++	unsigned int p_pktsize;
++	unsigned int p_pktsize_residue;
++	unsigned int p_framesize;
++};
++
++struct uac_file_handle
++{
++	struct v4l2_fh vfh;
++	struct uac_device *dev;
++};
++
++#define to_uac_file_handle(handle) \
++	container_of(handle, struct uac_file_handle, vfh)
++
++static inline struct uac_device *func_to_uac_device(struct usb_function *f)
++{
++	return container_of(f, struct uac_device, func);
++}
++
++static inline uint num_channels(uint chanmask)
++{
++	uint num = 0;
++
++	while (chanmask) {
++		num += (chanmask & 1);
++		chanmask >>= 1;
++	}
++
++	return num;
++}
++
++int uac_device_setup(struct uac_device *uac_dev);
++void uac_device_cleanup(struct uac_device *g_audio);
++int uac_device_start_playback(struct uac_device *uac_dev);
++void uac_device_stop_playback(struct uac_device *uac_dev);
++
++#endif /* __KERNEL__ */
++
++#endif /* _UAC_EX_H_ */
++
+diff --git a/drivers/usb/gadget/function/uac_queue_ex.c b/drivers/usb/gadget/function/uac_queue_ex.c
+new file mode 100644
+index 0000000..89dcf6b
+--- /dev/null
++++ b/drivers/usb/gadget/function/uac_queue_ex.c
+@@ -0,0 +1,379 @@
++/*
++ *	uac_queue.c  --  USB Video Class driver - Buffers management
++ *
++ *	Copyright (C) 2005-2010
++ *	    Laurent Pinchart (laurent.pinchart@ideasonboard.com)
++ *
++ *	This program is free software; you can redistribute it and/or modify
++ *	it under the terms of the GNU General Public License as published by
++ *	the Free Software Foundation; either version 2 of the License, or
++ *	(at your option) any later version.
++ */
++
++#include <linux/atomic.h>
++#include <linux/kernel.h>
++#include <linux/mm.h>
++#include <linux/list.h>
++#include <linux/module.h>
++#include <linux/usb.h>
++#include <linux/videodev2.h>
++#include <linux/vmalloc.h>
++#include <linux/wait.h>
++
++#include <media/v4l2-common.h>
++#include <media/videobuf2-vmalloc.h>
++
++#include "uac_ex.h"
++
++/* ------------------------------------------------------------------------
++ * Video buffers queue management.
++ *
++ * Video queues is initialized by uac_queue_init(). The function performs
++ * basic initialization of the uac_queue struct and never fails.
++ *
++ * Video buffers are managed by videobuf2. The driver uses a mutex to protect
++ * the videobuf2 queue operations by serializing calls to videobuf2 and a
++ * spinlock to protect the IRQ queue that holds the buffers to be processed by
++ * the driver.
++ */
++
++/* -----------------------------------------------------------------------------
++ * videobuf2 queue operations
++ */
++
++static int uac_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
++			   unsigned int *nbuffers, unsigned int *nplanes,
++			   unsigned int sizes[], void *alloc_ctxs[])
++{
++	if (*nbuffers > UVC_MAX_VIDEO_BUFFERS)
++		*nbuffers = UVC_MAX_VIDEO_BUFFERS;
++
++	*nplanes = 1;
++
++	sizes[0] = 1024;
++
++	return 0;
++}
++
++static int uac_buffer_prepare(struct vb2_buffer *vb)
++{
++	struct uac_queue *queue = vb2_get_drv_priv(vb->vb2_queue);
++	struct uac_buffer *buf = container_of(vb, struct uac_buffer, buf);
++
++	if (vb->v4l2_buf.type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
++	    vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) {
++		printk(KERN_EMERG "[E] Bytes used out of bounds.\n");
++		return -EINVAL;
++	}
++
++	if (unlikely(queue->flags & UVC_QUEUE_DISCONNECTED))
++		return -ENODEV;
++
++	buf->state = UVC_BUF_STATE_QUEUED;
++	buf->mem = vb2_plane_vaddr(vb, 0);
++	buf->length = vb2_plane_size(vb, 0);
++	if (vb->v4l2_buf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
++		buf->bytesused = 0;
++	else
++		buf->bytesused = vb2_get_plane_payload(vb, 0);
++
++	return 0;
++}
++
++static void uac_buffer_queue(struct vb2_buffer *vb)
++{
++	struct uac_queue *queue = vb2_get_drv_priv(vb->vb2_queue);
++	struct uac_buffer *buf = container_of(vb, struct uac_buffer, buf);
++	unsigned long flags;
++
++	spin_lock_irqsave(&queue->irqlock, flags);
++
++	if (likely(!(queue->flags & UVC_QUEUE_DISCONNECTED))) {
++		list_add_tail(&buf->queue, &queue->irqqueue);
++	} else {
++		/* If the device is disconnected return the buffer to userspace
++		 * directly. The next QBUF call will fail with -ENODEV.
++		 */
++		buf->state = UVC_BUF_STATE_ERROR;
++		vb2_buffer_done(&buf->buf, VB2_BUF_STATE_ERROR);
++	}
++
++	spin_unlock_irqrestore(&queue->irqlock, flags);
++}
++
++static void uac_wait_prepare(struct vb2_queue *vq)
++{
++	struct uac_queue *queue = vb2_get_drv_priv(vq);
++
++	mutex_unlock(&queue->mutex);
++}
++
++static void uac_wait_finish(struct vb2_queue *vq)
++{
++	struct uac_queue *queue = vb2_get_drv_priv(vq);
++
++	mutex_lock(&queue->mutex);
++}
++
++static void uac_stop_streaming(struct vb2_queue *vq)
++{
++    struct uac_queue *queue = vb2_get_drv_priv(vq);
++
++	uac_queue_cancel(queue, 0);
++}
++
++static struct vb2_ops uac_queue_qops = {
++	.queue_setup = uac_queue_setup,
++	.buf_prepare = uac_buffer_prepare,
++	.buf_queue = uac_buffer_queue,
++	.wait_prepare = uac_wait_prepare,
++	.wait_finish = uac_wait_finish,
++	.stop_streaming = uac_stop_streaming,
++};
++
++int uac_queue_init(struct uac_queue *queue)
++{
++	int ret;
++
++	queue->queue.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
++	queue->queue.io_modes = VB2_USERPTR;
++	queue->queue.drv_priv = queue;
++	queue->queue.buf_struct_size = sizeof(struct uac_buffer);
++	queue->queue.ops = &uac_queue_qops;
++	queue->queue.mem_ops = &vb2_vmalloc_memops;
++	queue->queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC
++				     | V4L2_BUF_FLAG_TSTAMP_SRC_EOF;
++	ret = vb2_queue_init(&queue->queue);
++	if (ret)
++		return ret;
++
++	mutex_init(&queue->mutex);
++	spin_lock_init(&queue->irqlock);
++	INIT_LIST_HEAD(&queue->irqqueue);
++	queue->flags = 0;
++
++	return 0;
++}
++
++/*
++ * Free the video buffers.
++ */
++void uac_free_buffers(struct uac_queue *queue)
++{
++	mutex_lock(&queue->mutex);
++	vb2_queue_release(&queue->queue);
++	mutex_unlock(&queue->mutex);
++}
++
++/*
++ * Allocate the video buffers.
++ */
++int uac_alloc_buffers(struct uac_queue *queue,
++			      struct v4l2_requestbuffers *rb)
++{
++	int ret;
++
++	mutex_lock(&queue->mutex);
++	ret = vb2_reqbufs(&queue->queue, rb);
++	mutex_unlock(&queue->mutex);
++
++	return ret ? ret : rb->count;
++}
++
++int uac_query_buffer(struct uac_queue *queue, struct v4l2_buffer *buf)
++{
++	int ret;
++
++	mutex_lock(&queue->mutex);
++	ret = vb2_querybuf(&queue->queue, buf);
++	mutex_unlock(&queue->mutex);
++
++	return ret;
++}
++
++int uac_queue_buffer(struct uac_queue *queue, struct v4l2_buffer *buf)
++{
++	unsigned long flags;
++	int ret;
++
++	mutex_lock(&queue->mutex);
++	ret = vb2_qbuf(&queue->queue, buf);
++	if (ret < 0)
++		goto done;
++
++	spin_lock_irqsave(&queue->irqlock, flags);
++	ret = (queue->flags & UVC_QUEUE_PAUSED) != 0;
++	queue->flags &= ~UVC_QUEUE_PAUSED;
++	spin_unlock_irqrestore(&queue->irqlock, flags);
++
++done:
++	mutex_unlock(&queue->mutex);
++	return ret;
++}
++
++/*
++ * Dequeue a video buffer. If nonblocking is false, block until a buffer is
++ * available.
++ */
++int uac_dequeue_buffer(struct uac_queue *queue, struct v4l2_buffer *buf,
++			int nonblocking)
++{
++	int ret;
++
++	mutex_lock(&queue->mutex);
++	ret = vb2_dqbuf(&queue->queue, buf, nonblocking);
++	mutex_unlock(&queue->mutex);
++
++	return ret;
++}
++
++/*
++ * Poll the video queue.
++ *
++ * This function implements video queue polling and is intended to be used by
++ * the device poll handler.
++ */
++unsigned int uac_queue_poll(struct uac_queue *queue, struct file *file,
++			     poll_table *wait)
++{
++	unsigned int ret;
++
++	mutex_lock(&queue->mutex);
++	ret = vb2_poll(&queue->queue, file, wait);
++	mutex_unlock(&queue->mutex);
++
++	return ret;
++}
++
++/*
++ * Cancel the video buffers queue.
++ *
++ * Cancelling the queue marks all buffers on the irq queue as erroneous,
++ * wakes them up and removes them from the queue.
++ *
++ * If the disconnect parameter is set, further calls to uac_queue_buffer will
++ * fail with -ENODEV.
++ *
++ * This function acquires the irq spinlock and can be called from interrupt
++ * context.
++ */
++void uac_queue_cancel(struct uac_queue *queue, int disconnect)
++{
++	struct uac_buffer *buf;
++	unsigned long flags;
++
++	spin_lock_irqsave(&queue->irqlock, flags);
++	while (!list_empty(&queue->irqqueue)) {
++		buf = list_first_entry(&queue->irqqueue, struct uac_buffer,
++				       queue);
++		list_del(&buf->queue);
++		buf->state = UVC_BUF_STATE_ERROR;
++		vb2_buffer_done(&buf->buf, VB2_BUF_STATE_ERROR);
++	}
++	/* This must be protected by the irqlock spinlock to avoid race
++	 * conditions between uac_queue_buffer and the disconnection event that
++	 * could result in an interruptible wait in uac_dequeue_buffer. Do not
++	 * blindly replace this logic by checking for the UVC_DEV_DISCONNECTED
++	 * state outside the queue code.
++	 */
++	if (disconnect)
++		queue->flags |= UVC_QUEUE_DISCONNECTED;
++	spin_unlock_irqrestore(&queue->irqlock, flags);
++}
++
++/*
++ * Enable or disable the video buffers queue.
++ *
++ * The queue must be enabled before starting video acquisition and must be
++ * disabled after stopping it. This ensures that the video buffers queue
++ * state can be properly initialized before buffers are accessed from the
++ * interrupt handler.
++ *
++ * Enabling the video queue initializes parameters (such as sequence number,
++ * sync pattern, ...). If the queue is already enabled, return -EBUSY.
++ *
++ * Disabling the video queue cancels the queue and removes all buffers from
++ * the main queue.
++ *
++ * This function can't be called from interrupt context. Use
++ * uac_queue_cancel() instead.
++ */
++int uac_queue_enable(struct uac_queue *queue, int enable)
++{
++	unsigned long flags;
++	int ret = 0;
++
++	mutex_lock(&queue->mutex);
++	if (enable) {
++		ret = vb2_streamon(&queue->queue, queue->queue.type);
++		if (ret < 0)
++			goto done;
++
++		queue->sequence = 0;
++		queue->buf_used = 0;
++	} else {
++		ret = vb2_streamoff(&queue->queue, queue->queue.type);
++		if (ret < 0)
++			goto done;
++
++		spin_lock_irqsave(&queue->irqlock, flags);
++		INIT_LIST_HEAD(&queue->irqqueue);
++
++		/*
++		 * FIXME: We need to clear the DISCONNECTED flag to ensure that
++		 * applications will be able to queue buffers for the next
++		 * streaming run. However, clearing it here doesn't guarantee
++		 * that the device will be reconnected in the meantime.
++		 */
++		queue->flags &= ~UVC_QUEUE_DISCONNECTED;
++		spin_unlock_irqrestore(&queue->irqlock, flags);
++	}
++
++done:
++	mutex_unlock(&queue->mutex);
++	return ret;
++}
++
++/* called with &queue_irqlock held.. */
++struct uac_buffer *uac_queue_next_buffer(struct uac_queue *queue,
++					  struct uac_buffer *buf)
++{
++	struct uac_buffer *nextbuf;
++
++	if ((queue->flags & UVC_QUEUE_DROP_INCOMPLETE) &&
++	     buf->length != buf->bytesused) {
++		buf->state = UVC_BUF_STATE_QUEUED;
++		vb2_set_plane_payload(&buf->buf, 0, 0);
++		return buf;
++	}
++
++	list_del(&buf->queue);
++	if (!list_empty(&queue->irqqueue))
++		nextbuf = list_first_entry(&queue->irqqueue, struct uac_buffer,
++					   queue);
++	else
++		nextbuf = NULL;
++
++	buf->buf.v4l2_buf.field = V4L2_FIELD_NONE;
++	buf->buf.v4l2_buf.sequence = queue->sequence++;
++	v4l2_get_timestamp(&buf->buf.v4l2_buf.timestamp);
++
++	vb2_set_plane_payload(&buf->buf, 0, buf->bytesused);
++	vb2_buffer_done(&buf->buf, VB2_BUF_STATE_DONE);
++
++	return nextbuf;
++}
++
++struct uac_buffer *uac_queue_head(struct uac_queue *queue)
++{
++	struct uac_buffer *buf = NULL;
++
++	if (!list_empty(&queue->irqqueue))
++		buf = list_first_entry(&queue->irqqueue, struct uac_buffer,
++				       queue);
++	else
++		queue->flags |= UVC_QUEUE_PAUSED;
++
++	return buf;
++}
++
+diff --git a/drivers/usb/gadget/function/uac_queue_ex.h b/drivers/usb/gadget/function/uac_queue_ex.h
+new file mode 100644
+index 0000000..4b5db20
+--- /dev/null
++++ b/drivers/usb/gadget/function/uac_queue_ex.h
+@@ -0,0 +1,90 @@
++#ifndef _UAC_QUEUE_H_
++#define _UAC_QUEUE_H_
++
++#ifdef __KERNEL__
++
++#include <linux/kernel.h>
++#include <linux/poll.h>
++#include <linux/videodev2.h>
++#include <media/videobuf2-core.h>
++
++/* Maximum frame size in bytes, for sanity checking. */
++#define UVC_MAX_FRAME_SIZE	(16*1024*1024)
++/* Maximum number of video buffers. */
++#define UVC_MAX_VIDEO_BUFFERS	32
++
++/* ------------------------------------------------------------------------
++ * Structures.
++ */
++
++enum uac_buffer_state {
++	UVC_BUF_STATE_IDLE	= 0,
++	UVC_BUF_STATE_QUEUED	= 1,
++	UVC_BUF_STATE_ACTIVE	= 2,
++	UVC_BUF_STATE_DONE	= 3,
++	UVC_BUF_STATE_ERROR	= 4,
++};
++
++struct uac_buffer {
++	struct vb2_buffer buf;
++	struct list_head queue;
++
++	enum uac_buffer_state state;
++	void *mem;
++	unsigned int length;
++	unsigned int bytesused;
++};
++
++#define UVC_QUEUE_DISCONNECTED		(1 << 0)
++#define UVC_QUEUE_DROP_INCOMPLETE	(1 << 1)
++#define UVC_QUEUE_PAUSED		(1 << 2)
++
++struct uac_queue {
++	struct vb2_queue queue;
++	struct mutex mutex;	/* Protects queue */
++
++	unsigned int flags;
++	__u32 sequence;
++
++	unsigned int buf_used;
++
++	spinlock_t irqlock;	/* Protects flags and irqqueue */
++	struct list_head irqqueue;
++};
++
++static inline int uac_queue_streaming(struct uac_queue *queue)
++{
++	return vb2_is_streaming(&queue->queue);
++}
++
++int uac_queue_init(struct uac_queue *queue);
++
++void uac_free_buffers(struct uac_queue *queue);
++
++int uac_alloc_buffers(struct uac_queue *queue,
++		       struct v4l2_requestbuffers *rb);
++
++int uac_query_buffer(struct uac_queue *queue, struct v4l2_buffer *buf);
++
++int uac_queue_buffer(struct uac_queue *queue, struct v4l2_buffer *buf);
++
++int uac_dequeue_buffer(struct uac_queue *queue,
++			struct v4l2_buffer *buf, int nonblocking);
++
++unsigned int uac_queue_poll(struct uac_queue *queue,
++			     struct file *file, poll_table *wait);
++
++
++void uac_queue_cancel(struct uac_queue *queue, int disconnect);
++
++int uac_queue_enable(struct uac_queue *queue, int enable);
++
++struct uac_buffer *uac_queue_next_buffer(struct uac_queue *queue,
++					  struct uac_buffer *buf);
++
++struct uac_buffer *uac_queue_head(struct uac_queue *queue);
++
++#endif /* __KERNEL__ */
++
++#endif /* _UAC_QUEUE_H_ */
++
+diff --git a/drivers/usb/gadget/function/uac_v4l2_ex.c b/drivers/usb/gadget/function/uac_v4l2_ex.c
+new file mode 100644
+index 0000000..4570b7a
+--- /dev/null
++++ b/drivers/usb/gadget/function/uac_v4l2_ex.c
+@@ -0,0 +1,218 @@
++/*
++ *	uac_v4l2.c  --  USB Video Class Gadget driver
++ *
++ *	Copyright (C) 2009-2010
++ *	    Laurent Pinchart (laurent.pinchart@ideasonboard.com)
++ *
++ *	This program is free software; you can redistribute it and/or modify
++ *	it under the terms of the GNU General Public License as published by
++ *	the Free Software Foundation; either version 2 of the License, or
++ *	(at your option) any later version.
++ */
++
++#include <linux/kernel.h>
++#include <linux/device.h>
++#include <linux/errno.h>
++#include <linux/list.h>
++#include <linux/mutex.h>
++#include <linux/videodev2.h>
++#include <linux/vmalloc.h>
++#include <linux/wait.h>
++
++#include <media/v4l2-dev.h>
++#include <media/v4l2-event.h>
++#include <media/v4l2-ioctl.h>
++
++#include "uac_ex.h"
++#include "uac_queue_ex.h"
++
++static int
++uac_v4l2_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
++{
++	strlcpy(cap->driver, "g_uac", sizeof(cap->driver));
++	strlcpy(cap->card, "g_uac", sizeof(cap->card));
++
++	cap->capabilities = V4L2_CAP_AUDIO;
++
++	return 0;
++}
++static int
++uac_v4l2_get_format(struct file *file, void *fh, struct v4l2_format *fmt)
++{
++	return 0;
++}
++
++static int
++uac_v4l2_set_format(struct file *file, void *fh, struct v4l2_format *fmt)
++{
++	return 0;
++}
++
++static int
++uac_v4l2_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *b)
++{
++	struct video_device *vdev = video_devdata(file);
++	struct uac_device *uac = video_get_drvdata(vdev);
++
++	if (b->type != uac->queue.queue.type)
++		return -EINVAL;
++
++	return uac_alloc_buffers(&uac->queue, b);
++}
++
++static int
++uac_v4l2_querybuf(struct file *file, void *fh, struct v4l2_buffer *b)
++{
++	struct video_device *vdev = video_devdata(file);
++	struct uac_device *uac = video_get_drvdata(vdev);
++
++	return uac_query_buffer(&uac->queue, b);
++}
++
++static int
++uac_v4l2_qbuf(struct file *file, void *fh, struct v4l2_buffer *b)
++{
++	struct video_device *vdev = video_devdata(file);
++	struct uac_device *uac = video_get_drvdata(vdev);
++
++	return uac_queue_buffer(&uac->queue, b);
++}
++
++static int
++uac_v4l2_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
++{
++	struct video_device *vdev = video_devdata(file);
++	struct uac_device *uac = video_get_drvdata(vdev);
++
++	return uac_dequeue_buffer(&uac->queue, b, file->f_flags & O_NONBLOCK);
++}
++
++static int
++uac_v4l2_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
++{
++	struct video_device *vdev = video_devdata(file);
++	struct uac_device *uac = video_get_drvdata(vdev);
++
++	int ret;
++
++	if (type != uac->queue.queue.type)
++		return -EINVAL;
++
++	ret = uac_queue_enable(&uac->queue, 1);
++	if (ret < 0)
++		return ret;
++
++	return 0;
++}
++
++static int
++uac_v4l2_streamoff(struct file *file, void *fh, enum v4l2_buf_type type)
++{
++	struct video_device *vdev = video_devdata(file);
++	struct uac_device *uac = video_get_drvdata(vdev);
++
++	if (type != uac->queue.queue.type)
++		return -EINVAL;
++
++	return uac_queue_enable(&uac->queue, 0);
++}
++
++static int
++uac_v4l2_subscribe_event(struct v4l2_fh *fh,
++			 const struct v4l2_event_subscription *sub)
++{
++	if (sub->type < UAC_EVENT_FIRST || sub->type > UAC_EVENT_LAST)
++		return -EINVAL;
++
++	return v4l2_event_subscribe(fh, sub, 2, NULL);
++}
++
++static int
++uac_v4l2_unsubscribe_event(struct v4l2_fh *fh,
++			   const struct v4l2_event_subscription *sub)
++{
++	return v4l2_event_unsubscribe(fh, sub);
++}
++
++static long
++uac_v4l2_ioctl_default(struct file *file, void *fh, bool valid_prio,
++		unsigned int cmd, void *arg)
++{
++	switch (cmd) {
++	default:
++		return -ENOIOCTLCMD;
++	}
++}
++
++const struct v4l2_ioctl_ops uac_v4l2_ioctl_ops = {
++	.vidioc_querycap = uac_v4l2_querycap,
++	.vidioc_reqbufs = uac_v4l2_reqbufs,
++	.vidioc_querybuf = uac_v4l2_querybuf,
++	.vidioc_g_fmt_vid_out = uac_v4l2_get_format,
++	.vidioc_s_fmt_vid_out = uac_v4l2_set_format,
++	.vidioc_qbuf = uac_v4l2_qbuf,
++	.vidioc_dqbuf = uac_v4l2_dqbuf,
++	.vidioc_streamon = uac_v4l2_streamon,
++	.vidioc_streamoff = uac_v4l2_streamoff,
++	.vidioc_subscribe_event = uac_v4l2_subscribe_event,
++	.vidioc_unsubscribe_event = uac_v4l2_unsubscribe_event,
++	.vidioc_default = uac_v4l2_ioctl_default,
++};
++
++/* --------------------------------------------------------------------------
++ * V4L2
++ */
++
++static int
++uac_v4l2_open(struct file *file)
++{
++	struct video_device *vdev = video_devdata(file);
++	struct uac_device *uac_dev = video_get_drvdata(vdev);
++	struct uac_file_handle *handle;
++
++	handle = kzalloc(sizeof(*handle), GFP_KERNEL);
++	if (handle == NULL)
++		return -ENOMEM;
++
++	v4l2_fh_init(&handle->vfh, vdev);
++	v4l2_fh_add(&handle->vfh);
++
++	handle->dev = uac_dev;
++	file->private_data = &handle->vfh;
++
++	return 0;
++}
++
++static int
++uac_v4l2_release(struct file *file)
++{
++	struct uac_file_handle *handle = to_uac_file_handle(file->private_data);
++	struct uac_device *uac_dev = handle->dev;
++
++	uac_queue_enable(&uac_dev->queue, 0);
++	uac_free_buffers(&uac_dev->queue);
++
++	file->private_data = NULL;
++	v4l2_fh_del(&handle->vfh);
++	v4l2_fh_exit(&handle->vfh);
++	kfree(handle);
++
++	return 0;
++}
++
++static unsigned int
++uac_v4l2_poll(struct file *file, poll_table *wait)
++{
++	struct video_device *vdev = video_devdata(file);
++	struct uac_device *uac = video_get_drvdata(vdev);
++
++	return uac_queue_poll(&uac->queue, file, wait);
++}
++
++struct v4l2_file_operations uac_v4l2_fops = {
++	.owner		= THIS_MODULE,
++	.open		= uac_v4l2_open,
++	.release	= uac_v4l2_release,
++	.ioctl		= video_ioctl2,
++	.poll		= uac_v4l2_poll,
++};
+diff --git a/drivers/usb/gadget/function/uac_v4l2_ex.h b/drivers/usb/gadget/function/uac_v4l2_ex.h
+new file mode 100644
+index 0000000..9df310f
+--- /dev/null
++++ b/drivers/usb/gadget/function/uac_v4l2_ex.h
+@@ -0,0 +1,22 @@
++/*
++ *	uvc_v4l2.h  --  USB Video Class Gadget driver
++ *
++ * Copyright (C) 2009-2010
++ *		Laurent Pinchart (laurent.pinchart@ideasonboard.com)
++ *
++ * Copyright (c) 2013 Samsung Electronics Co., Ltd.
++ *		http://www.samsung.com
++ *		Author: Andrzej Pietrasiewicz <andrzej.p@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 __UAC_V4L2_H__
++#define __UAC_V4L2_H__
++
++extern const struct v4l2_ioctl_ops uac_v4l2_ioctl_ops;
++extern struct v4l2_file_operations uac_v4l2_fops;
++
++#endif /* __UAC_V4L2_H__ */
+diff --git a/drivers/usb/gadget/function/uvc.h b/drivers/usb/gadget/function/uvc.h
+index f67695c..f057ce3 100644
+--- a/drivers/usb/gadget/function/uvc.h
++++ b/drivers/usb/gadget/function/uvc.h
+@@ -96,8 +96,11 @@ extern unsigned int uvc_gadget_trace_param;
+ /* ------------------------------------------------------------------------
+  * Driver specific constants
+  */
+-
+-#define UVC_NUM_REQUESTS			4
++#ifdef CONFIG_HIUSB_DEVICE2_0
++#define UVC_NUM_REQUESTS		1
++#else
++#define UVC_NUM_REQUESTS		32
++#endif
+ #define UVC_MAX_REQUEST_SIZE			64
+ #define UVC_MAX_EVENTS				4
+ 
+@@ -132,6 +135,8 @@ struct uvc_video
+ 
+ 	struct uvc_video_queue queue;
+ 	unsigned int fid;
++	bool bulk_streaming_ep;
++	unsigned int bulk_max_size;
+ };
+ 
+ enum uvc_state
+diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/function/uvc_v4l2.c
+index 5aad7fe..07f9442 100644
+--- a/drivers/usb/gadget/function/uvc_v4l2.c
++++ b/drivers/usb/gadget/function/uvc_v4l2.c
+@@ -62,6 +62,7 @@ struct uvc_format
+ static struct uvc_format uvc_formats[] = {
+ 	{ 16, V4L2_PIX_FMT_YUYV  },
+ 	{ 0,  V4L2_PIX_FMT_MJPEG },
++	{ 0,  V4L2_PIX_FMT_H264 },
+ };
+ 
+ static int
+@@ -200,6 +201,9 @@ uvc_v4l2_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
+ 	if (type != video->queue.queue.type)
+ 		return -EINVAL;
+ 
++	if (video->bulk_streaming_ep)
++		uvc_function_connect(uvc);
++
+ 	/* Enable UVC video. */
+ 	ret = uvcg_video_enable(video, 1);
+ 	if (ret < 0)
+@@ -209,8 +213,15 @@ uvc_v4l2_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
+ 	 * Complete the alternate setting selection setup phase now that
+ 	 * userspace is ready to provide video frames.
+ 	 */
+-	uvc_function_setup_continue(uvc);
+-	uvc->state = UVC_STATE_STREAMING;
++	if (!video->bulk_streaming_ep) {
++		/*
++		 * Complete the alternate setting selection setup
++		 * phase now that userspace is ready to provide video
++		 * frames.
++		 */
++		uvc_function_setup_continue(uvc);
++		uvc->state = UVC_STATE_STREAMING;
++	}
+ 
+ 	return 0;
+ }
+@@ -218,6 +229,7 @@ uvc_v4l2_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
+ static int
+ uvc_v4l2_streamoff(struct file *file, void *fh, enum v4l2_buf_type type)
+ {
++	int code = 0;
+ 	struct video_device *vdev = video_devdata(file);
+ 	struct uvc_device *uvc = video_get_drvdata(vdev);
+ 	struct uvc_video *video = &uvc->video;
+@@ -225,7 +237,12 @@ uvc_v4l2_streamoff(struct file *file, void *fh, enum v4l2_buf_type type)
+ 	if (type != video->queue.queue.type)
+ 		return -EINVAL;
+ 
+-	return uvcg_video_enable(video, 0);
++	code = uvcg_video_enable(video, 0);
++
++	if (video->bulk_streaming_ep)
++		uvc_function_disconnect(uvc);
++
++	return code;
+ }
+ 
+ static int
+@@ -363,4 +380,3 @@ struct v4l2_file_operations uvc_v4l2_fops = {
+ 	.get_unmapped_area = uvcg_v4l2_get_unmapped_area,
+ #endif
+ };
+-
+diff --git a/drivers/usb/gadget/function/uvc_video.c b/drivers/usb/gadget/function/uvc_video.c
+index 9cb86bc..754a321 100644
+--- a/drivers/usb/gadget/function/uvc_video.c
++++ b/drivers/usb/gadget/function/uvc_video.c
+@@ -185,13 +185,26 @@ uvc_video_complete(struct usb_ep *ep, struct usb_request *req)
+ 
+ 	spin_lock_irqsave(&video->queue.irqlock, flags);
+ 	buf = uvcg_queue_head(&video->queue);
++#ifdef CONFIG_ARCH_HISI
++	if (buf == NULL) {
++		if (video->bulk_streaming_ep) {
++			spin_unlock_irqrestore(&video->queue.irqlock, flags);
++			goto requeue;
++		} else {
++			req->length = 0;
++			goto tran_zero;
++		}
++	}
++#else
+ 	if (buf == NULL) {
+ 		spin_unlock_irqrestore(&video->queue.irqlock, flags);
+ 		goto requeue;
+ 	}
++#endif
+ 
+ 	video->encode(req, video, buf);
+ 
++tran_zero:
+ 	if ((ret = usb_ep_queue(ep, req, GFP_ATOMIC)) < 0) {
+ 		printk(KERN_INFO "Failed to queue request (%d).\n", ret);
+ 		usb_ep_set_halt(ep);
+@@ -240,9 +253,13 @@ uvc_video_alloc_requests(struct uvc_video *video)
+ 
+ 	BUG_ON(video->req_size);
+ 
+-	req_size = video->ep->maxpacket
+-		 * max_t(unsigned int, video->ep->maxburst, 1)
+-		 * (video->ep->mult + 1);
++	if (!video->bulk_streaming_ep)
++		req_size = video->ep->maxpacket
++			* max_t(unsigned int, video->ep->maxburst, 1)
++			* (video->ep->mult + 1);
++	else
++		req_size = video->ep->maxpacket
++			* max_t(unsigned int, video->ep->maxburst, 1);
+ 
+ 	for (i = 0; i < UVC_NUM_REQUESTS; ++i) {
+ 		video->req_buffer[i] = kmalloc(req_size, GFP_KERNEL);
+@@ -389,6 +406,10 @@ int uvcg_video_init(struct uvc_video *video)
+ 	video->height = 240;
+ 	video->imagesize = 320 * 240 * 2;
+ 
++	if (video->bulk_streaming_ep)
++		video->max_payload_size = video->bulk_max_size;
++
++
+ 	/* Initialize the video buffers queue. */
+ 	uvcg_queue_init(&video->queue, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+ 	return 0;
+diff --git a/drivers/usb/gadget/functions.c b/drivers/usb/gadget/functions.c
+index b13f839..389c1f3 100644
+--- a/drivers/usb/gadget/functions.c
++++ b/drivers/usb/gadget/functions.c
+@@ -58,7 +58,7 @@ struct usb_function *usb_get_function(struct usb_function_instance *fi)
+ 	struct usb_function *f;
+ 
+ 	f = fi->fd->alloc_func(fi);
+-	if (IS_ERR(f))
++	if ((f == NULL) || IS_ERR(f))
+ 		return f;
+ 	f->fi = fi;
+ 	return f;
+diff --git a/drivers/usb/gadget/legacy/Kconfig b/drivers/usb/gadget/legacy/Kconfig
+index 24392d2..6b3a349 100644
+--- a/drivers/usb/gadget/legacy/Kconfig
++++ b/drivers/usb/gadget/legacy/Kconfig
+@@ -51,11 +51,8 @@ config USB_ZERO_HNPTEST
+ 
+ config USB_AUDIO
+ 	tristate "Audio Gadget"
+-	depends on SND
+ 	select USB_LIBCOMPOSITE
+-	select SND_PCM
+ 	select USB_F_UAC1 if GADGET_UAC1
+-	select USB_F_UAC2 if !GADGET_UAC1
+ 	help
+ 	  This Gadget Audio driver is compatible with USB Audio Class
+ 	  specification 2.0. It implements 1 AudioControl interface,
+@@ -75,6 +72,7 @@ config USB_AUDIO
+ config GADGET_UAC1
+ 	bool "UAC 1.0 (Legacy)"
+ 	depends on USB_AUDIO
++	select USB_F_UAC1
+ 	help
+ 	  If you instead want older UAC Spec-1.0 driver that also has audio
+ 	  paths hardwired to the Audio codec chip on-board and doesn't work
+@@ -313,6 +311,26 @@ config USB_G_PRINTER
+ 	  For more information, see Documentation/usb/gadget_printer.txt
+ 	  which includes sample code for accessing the device file.
+ 
++config USB_G_ANDROID
++	boolean "Android Composite Gadget"
++	select USB_F_ACM
++	select USB_LIBCOMPOSITE
++	select USB_U_SERIAL
++	select USB_F_MASS_STORAGE
++	select SND_PCM
++	help
++	  The Android Composite Gadget supports multiple USB
++	  functions: adb, acm, mass storage, mtp, accessory
++	  and rndis.
++	  Each function can be configured and enabled/disabled
++	  dynamically from userspace through a sysfs interface.
++
++config USB_ANDROID_RNDIS_DWORD_ALIGNED
++	boolean "Use double word aligned"
++	depends on USB_G_ANDROID
++	help
++		Provides dword aligned for DMA controller.
++
+ if TTY
+ 
+ config USB_CDC_COMPOSITE
+@@ -476,3 +494,20 @@ config USB_G_WEBCAM
+ 
+ 	  Say "y" to link the driver statically, or "m" to build a
+ 	  dynamically linked module called "g_webcam".
++
++# put drivers that need isochronous transfer support (for audio
++# or video class gadget drivers), or specific hardware, here.
++config USB_G_WEBCAM_AUDIO
++	tristate "USB Webcam+ Gadget(include audio)"
++	depends on VIDEO_DEV
++	select USB_LIBCOMPOSITE
++	select VIDEOBUF2_VMALLOC
++	select USB_F_UVC
++	help
++	  The Webcam+ Gadget acts as a composite USB Audio and Video Class
++	  device. It provides a userspace API to process UVC control requests
++	  and stream video data to the host.
++
++	  Say "y" to link the driver statically, or "m" to build a
++	  dynamically linked module called "g_webcam".
++
+diff --git a/drivers/usb/gadget/legacy/Makefile b/drivers/usb/gadget/legacy/Makefile
+index 7f485f2..3e309aa 100644
+--- a/drivers/usb/gadget/legacy/Makefile
++++ b/drivers/usb/gadget/legacy/Makefile
+@@ -20,8 +20,10 @@ g_hid-y				:= hid.o
+ g_dbgp-y			:= dbgp.o
+ g_nokia-y			:= nokia.o
+ g_webcam-y			:= webcam.o
++g_webcam_audio-y			:= webcam_audio.o
+ g_ncm-y				:= ncm.o
+ g_acm_ms-y			:= acm_ms.o
++g_android-y			:= android.o
+ g_tcm_usb_gadget-y		:= tcm_usb_gadget.o
+ 
+ obj-$(CONFIG_USB_ZERO)		+= g_zero.o
+@@ -39,6 +41,8 @@ obj-$(CONFIG_USB_G_DBGP)	+= g_dbgp.o
+ obj-$(CONFIG_USB_G_MULTI)	+= g_multi.o
+ obj-$(CONFIG_USB_G_NOKIA)	+= g_nokia.o
+ obj-$(CONFIG_USB_G_WEBCAM)	+= g_webcam.o
++obj-$(CONFIG_USB_G_WEBCAM_AUDIO)	+= g_webcam_audio.o
+ obj-$(CONFIG_USB_G_NCM)		+= g_ncm.o
+ obj-$(CONFIG_USB_G_ACM_MS)	+= g_acm_ms.o
++obj-$(CONFIG_USB_G_ANDROID)	+= g_android.o
+ obj-$(CONFIG_USB_GADGET_TARGET)	+= tcm_usb_gadget.o
+diff --git a/drivers/usb/gadget/legacy/android.c b/drivers/usb/gadget/legacy/android.c
+new file mode 100644
+index 0000000..1d38c8d
+--- /dev/null
++++ b/drivers/usb/gadget/legacy/android.c
+@@ -0,0 +1,1568 @@
++/*
++ * Gadget Driver for Android
++ *
++ * Copyright (C) 2008 Google, Inc.
++ * Author: Mike Lockwood <lockwood@android.com>
++ *         Benoit Goby <benoit@android.com>
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/fs.h>
++#include <linux/delay.h>
++#include <linux/kernel.h>
++#include <linux/utsname.h>
++#include <linux/platform_device.h>
++
++#include <linux/usb/ch9.h>
++#include <linux/usb/composite.h>
++#include <linux/usb/gadget.h>
++
++#include "gadget_chips.h"
++
++#include "f_fs.c"
++#include "f_audio_source.c"
++#include "f_mtp.c"
++#include "f_accessory.c"
++#define USB_ETH_RNDIS y
++#include "f_rndis.c"
++#include "rndis.c"
++#include "u_ether.c"
++
++USB_ETHERNET_MODULE_PARAMETERS();
++
++MODULE_AUTHOR("Mike Lockwood");
++MODULE_DESCRIPTION("Android Composite USB Driver");
++MODULE_LICENSE("GPL");
++MODULE_VERSION("1.0");
++
++static const char longname[] = "Gadget Android";
++
++/* Default vendor and product IDs, overridden by userspace */
++#define VENDOR_ID		0x18D1
++#define PRODUCT_ID		0x0001
++
++struct android_usb_function {
++	char *name;
++	void *config;
++
++	struct device *dev;
++	char *dev_name;
++	struct device_attribute **attributes;
++
++	/* for android_dev.enabled_functions */
++	struct list_head enabled_list;
++
++	/* Optional: initialization during gadget bind */
++	int (*init)(struct android_usb_function *, struct usb_composite_dev *);
++	/* Optional: cleanup during gadget unbind */
++	void (*cleanup)(struct android_usb_function *);
++	/* Optional: called when the function is added the list of
++	 *		enabled functions */
++	void (*enable)(struct android_usb_function *);
++	/* Optional: called when it is removed */
++	void (*disable)(struct android_usb_function *);
++
++	int (*bind_config)(struct android_usb_function *,
++			   struct usb_configuration *);
++
++	/* Optional: called when the configuration is removed */
++	void (*unbind_config)(struct android_usb_function *,
++			      struct usb_configuration *);
++	/* Optional: handle ctrl requests before the device is configured */
++	int (*ctrlrequest)(struct android_usb_function *,
++					struct usb_composite_dev *,
++					const struct usb_ctrlrequest *);
++};
++
++struct android_dev {
++	struct android_usb_function **functions;
++	struct list_head enabled_functions;
++	struct usb_composite_dev *cdev;
++	struct device *dev;
++
++	void (*setup_complete)(struct usb_ep *ep,
++				struct usb_request *req);
++
++	bool enabled;
++	int disable_depth;
++	struct mutex mutex;
++	bool connected;
++	bool sw_connected;
++	struct work_struct work;
++	char ffs_aliases[256];
++};
++
++static struct class *android_class;
++static struct android_dev *_android_dev;
++static int android_bind_config(struct usb_configuration *c);
++static void android_unbind_config(struct usb_configuration *c);
++
++/* string IDs are assigned dynamically */
++#define STRING_MANUFACTURER_IDX		0
++#define STRING_PRODUCT_IDX		1
++#define STRING_SERIAL_IDX		2
++
++static char manufacturer_string[256];
++static char product_string[256];
++static char serial_string[256];
++
++/*---Copied from configfs.c to let this composite driver build---*/
++static struct class *android_class;
++static struct device *android_device;
++static int index;
++
++struct device *create_function_device(char *name)
++{
++        if (android_device && !IS_ERR(android_device))
++                return device_create(android_class, android_device,
++                        MKDEV(0, index++), NULL, name);
++        else
++                return ERR_PTR(-EINVAL);
++}
++EXPORT_SYMBOL_GPL(create_function_device);
++/*---------------------------------------------------------------*/
++
++/* String Table */
++static struct usb_string strings_dev[] = {
++	[STRING_MANUFACTURER_IDX].s = manufacturer_string,
++	[STRING_PRODUCT_IDX].s = product_string,
++	[STRING_SERIAL_IDX].s = serial_string,
++	{  }			/* end of list */
++};
++
++static struct usb_gadget_strings stringtab_dev = {
++	.language	= 0x0409,	/* en-us */
++	.strings	= strings_dev,
++};
++
++static struct usb_gadget_strings *dev_strings[] = {
++	&stringtab_dev,
++	NULL,
++};
++
++static struct usb_device_descriptor device_desc = {
++	.bLength              = sizeof(device_desc),
++	.bDescriptorType      = USB_DT_DEVICE,
++	.bcdUSB               = __constant_cpu_to_le16(0x0200),
++	.bDeviceClass         = USB_CLASS_PER_INTERFACE,
++	.idVendor             = __constant_cpu_to_le16(VENDOR_ID),
++	.idProduct            = __constant_cpu_to_le16(PRODUCT_ID),
++	.bcdDevice            = __constant_cpu_to_le16(0xffff),
++	.bNumConfigurations   = 1,
++};
++
++static struct usb_configuration android_config_driver = {
++	.label		= "android",
++	.unbind		= android_unbind_config,
++	.bConfigurationValue = 1,
++	.bmAttributes	= USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
++	.MaxPower	= 500, /* 500ma */
++};
++
++static void android_work(struct work_struct *data)
++{
++	struct android_dev *dev = container_of(data, struct android_dev, work);
++	struct usb_composite_dev *cdev = dev->cdev;
++	char *disconnected[2] = { "USB_STATE=DISCONNECTED", NULL };
++	char *connected[2]    = { "USB_STATE=CONNECTED", NULL };
++	char *configured[2]   = { "USB_STATE=CONFIGURED", NULL };
++	char **uevent_envp = NULL;
++	unsigned long flags;
++
++	spin_lock_irqsave(&cdev->lock, flags);
++	if (cdev->config)
++		uevent_envp = configured;
++	else if (dev->connected != dev->sw_connected)
++		uevent_envp = dev->connected ? connected : disconnected;
++	dev->sw_connected = dev->connected;
++	spin_unlock_irqrestore(&cdev->lock, flags);
++
++	if (uevent_envp) {
++		kobject_uevent_env(&dev->dev->kobj, KOBJ_CHANGE, uevent_envp);
++		pr_info("%s: sent uevent %s\n", __func__, uevent_envp[0]);
++	} else {
++		pr_info("%s: did not send uevent (%d %d %p)\n", __func__,
++			 dev->connected, dev->sw_connected, cdev->config);
++	}
++}
++
++static void android_enable(struct android_dev *dev)
++{
++	struct usb_composite_dev *cdev = dev->cdev;
++
++	if (WARN_ON(!dev->disable_depth))
++		return;
++
++	if (--dev->disable_depth == 0) {
++		usb_add_config(cdev, &android_config_driver,
++					android_bind_config);
++		usb_gadget_connect(cdev->gadget);
++	}
++}
++
++static void android_disable(struct android_dev *dev)
++{
++	struct usb_composite_dev *cdev = dev->cdev;
++
++	if (dev->disable_depth++ == 0) {
++		usb_gadget_disconnect(cdev->gadget);
++		/* Cancel pending control requests */
++		usb_ep_dequeue(cdev->gadget->ep0, cdev->req);
++		usb_remove_config(cdev, &android_config_driver);
++	}
++}
++
++/*-------------------------------------------------------------------------*/
++/* Supported functions initialization */
++
++struct functionfs_config {
++	bool opened;
++	bool enabled;
++	struct ffs_data *data;
++};
++
++static int ffs_function_init(struct android_usb_function *f,
++			     struct usb_composite_dev *cdev)
++{
++	f->config = kzalloc(sizeof(struct functionfs_config), GFP_KERNEL);
++	if (!f->config)
++		return -ENOMEM;
++
++	return functionfs_init();
++}
++
++static void ffs_function_cleanup(struct android_usb_function *f)
++{
++	functionfs_cleanup();
++	kfree(f->config);
++}
++
++static void ffs_function_enable(struct android_usb_function *f)
++{
++	struct android_dev *dev = _android_dev;
++	struct functionfs_config *config = f->config;
++
++	config->enabled = true;
++
++	/* Disable the gadget until the function is ready */
++	if (!config->opened)
++		android_disable(dev);
++}
++
++static void ffs_function_disable(struct android_usb_function *f)
++{
++	struct android_dev *dev = _android_dev;
++	struct functionfs_config *config = f->config;
++
++	config->enabled = false;
++
++	/* Balance the disable that was called in closed_callback */
++	if (!config->opened)
++		android_enable(dev);
++}
++
++static int ffs_function_bind_config(struct android_usb_function *f,
++				    struct usb_configuration *c)
++{
++	struct functionfs_config *config = f->config;
++	return functionfs_bind_config(c->cdev, c, config->data);
++}
++
++static ssize_t
++ffs_aliases_show(struct device *pdev, struct device_attribute *attr, char *buf)
++{
++	struct android_dev *dev = _android_dev;
++	int ret;
++
++	mutex_lock(&dev->mutex);
++	ret = sprintf(buf, "%s\n", dev->ffs_aliases);
++	mutex_unlock(&dev->mutex);
++
++	return ret;
++}
++
++static ssize_t
++ffs_aliases_store(struct device *pdev, struct device_attribute *attr,
++					const char *buf, size_t size)
++{
++	struct android_dev *dev = _android_dev;
++	char buff[256];
++
++	mutex_lock(&dev->mutex);
++
++	if (dev->enabled) {
++		mutex_unlock(&dev->mutex);
++		return -EBUSY;
++	}
++
++	strlcpy(buff, buf, sizeof(buff));
++	strlcpy(dev->ffs_aliases, strim(buff), sizeof(dev->ffs_aliases));
++
++	mutex_unlock(&dev->mutex);
++
++	return size;
++}
++
++static DEVICE_ATTR(aliases, S_IRUGO | S_IWUSR, ffs_aliases_show,
++					       ffs_aliases_store);
++static struct device_attribute *ffs_function_attributes[] = {
++	&dev_attr_aliases,
++	NULL
++};
++
++static struct android_usb_function ffs_function = {
++	.name		= "ffs",
++	.init		= ffs_function_init,
++	.enable		= ffs_function_enable,
++	.disable	= ffs_function_disable,
++	.cleanup	= ffs_function_cleanup,
++	.bind_config	= ffs_function_bind_config,
++	.attributes	= ffs_function_attributes,
++};
++
++static int functionfs_ready_callback(struct ffs_data *ffs)
++{
++	struct android_dev *dev = _android_dev;
++	struct functionfs_config *config = ffs_function.config;
++	int ret = 0;
++
++	mutex_lock(&dev->mutex);
++
++	ret = functionfs_bind(ffs, dev->cdev);
++	if (ret)
++		goto err;
++
++	config->data = ffs;
++	config->opened = true;
++
++	if (config->enabled)
++		android_enable(dev);
++
++err:
++	mutex_unlock(&dev->mutex);
++	return ret;
++}
++
++static void functionfs_closed_callback(struct ffs_data *ffs)
++{
++	struct android_dev *dev = _android_dev;
++	struct functionfs_config *config = ffs_function.config;
++
++	mutex_lock(&dev->mutex);
++
++	if (config->enabled)
++		android_disable(dev);
++
++	config->opened = false;
++	config->data = NULL;
++
++	functionfs_unbind(ffs);
++
++	mutex_unlock(&dev->mutex);
++}
++
++static void *functionfs_acquire_dev_callback(const char *dev_name)
++{
++	return 0;
++}
++
++static void functionfs_release_dev_callback(struct ffs_data *ffs_data)
++{
++}
++
++#define MAX_ACM_INSTANCES 4
++struct acm_function_config {
++	int instances;
++	int instances_on;
++	struct usb_function *f_acm[MAX_ACM_INSTANCES];
++	struct usb_function_instance *f_acm_inst[MAX_ACM_INSTANCES];
++};
++
++static int
++acm_function_init(struct android_usb_function *f,
++		struct usb_composite_dev *cdev)
++{
++	int i;
++	int ret;
++	struct acm_function_config *config;
++
++	config = kzalloc(sizeof(struct acm_function_config), GFP_KERNEL);
++	if (!config)
++		return -ENOMEM;
++	f->config = config;
++
++	for (i = 0; i < MAX_ACM_INSTANCES; i++) {
++		config->f_acm_inst[i] = usb_get_function_instance("acm");
++		if (IS_ERR(config->f_acm_inst[i])) {
++			ret = PTR_ERR(config->f_acm_inst[i]);
++			goto err_usb_get_function_instance;
++		}
++		config->f_acm[i] = usb_get_function(config->f_acm_inst[i]);
++		if (IS_ERR(config->f_acm[i])) {
++			ret = PTR_ERR(config->f_acm[i]);
++			goto err_usb_get_function;
++		}
++	}
++	return 0;
++err_usb_get_function_instance:
++	while (i-- > 0) {
++		usb_put_function(config->f_acm[i]);
++err_usb_get_function:
++		usb_put_function_instance(config->f_acm_inst[i]);
++	}
++	return ret;
++}
++
++static void acm_function_cleanup(struct android_usb_function *f)
++{
++	int i;
++	struct acm_function_config *config = f->config;
++
++	for (i = 0; i < MAX_ACM_INSTANCES; i++) {
++		usb_put_function(config->f_acm[i]);
++		usb_put_function_instance(config->f_acm_inst[i]);
++	}
++	kfree(f->config);
++	f->config = NULL;
++}
++
++static int
++acm_function_bind_config(struct android_usb_function *f,
++		struct usb_configuration *c)
++{
++	int i;
++	int ret = 0;
++	struct acm_function_config *config = f->config;
++
++	config->instances_on = config->instances;
++	for (i = 0; i < config->instances_on; i++) {
++		ret = usb_add_function(c, config->f_acm[i]);
++		if (ret) {
++			pr_err("Could not bind acm%u config\n", i);
++			goto err_usb_add_function;
++		}
++	}
++
++	return 0;
++
++err_usb_add_function:
++	while (i-- > 0)
++		usb_remove_function(c, config->f_acm[i]);
++	return ret;
++}
++
++static void acm_function_unbind_config(struct android_usb_function *f,
++				       struct usb_configuration *c)
++{
++	int i;
++	struct acm_function_config *config = f->config;
++
++	for (i = 0; i < config->instances_on; i++)
++		usb_remove_function(c, config->f_acm[i]);
++}
++
++static ssize_t acm_instances_show(struct device *dev,
++		struct device_attribute *attr, char *buf)
++{
++	struct android_usb_function *f = dev_get_drvdata(dev);
++	struct acm_function_config *config = f->config;
++	return sprintf(buf, "%d\n", config->instances);
++}
++
++static ssize_t acm_instances_store(struct device *dev,
++		struct device_attribute *attr, const char *buf, size_t size)
++{
++	struct android_usb_function *f = dev_get_drvdata(dev);
++	struct acm_function_config *config = f->config;
++	int value;
++
++	sscanf(buf, "%d", &value);
++	if (value > MAX_ACM_INSTANCES)
++		value = MAX_ACM_INSTANCES;
++	config->instances = value;
++	return size;
++}
++
++static DEVICE_ATTR(instances, S_IRUGO | S_IWUSR, acm_instances_show,
++						 acm_instances_store);
++static struct device_attribute *acm_function_attributes[] = {
++	&dev_attr_instances,
++	NULL
++};
++
++static struct android_usb_function acm_function = {
++	.name		= "acm",
++	.init		= acm_function_init,
++	.cleanup	= acm_function_cleanup,
++	.bind_config	= acm_function_bind_config,
++	.unbind_config	= acm_function_unbind_config,
++	.attributes	= acm_function_attributes,
++};
++
++
++static int
++mtp_function_init(struct android_usb_function *f,
++		struct usb_composite_dev *cdev)
++{
++	return mtp_setup();
++}
++
++static void mtp_function_cleanup(struct android_usb_function *f)
++{
++	mtp_cleanup();
++}
++
++static int
++mtp_function_bind_config(struct android_usb_function *f,
++		struct usb_configuration *c)
++{
++	return mtp_bind_config(c, false);
++}
++
++static int
++ptp_function_init(struct android_usb_function *f,
++		struct usb_composite_dev *cdev)
++{
++	/* nothing to do - initialization is handled by mtp_function_init */
++	return 0;
++}
++
++static void ptp_function_cleanup(struct android_usb_function *f)
++{
++	/* nothing to do - cleanup is handled by mtp_function_cleanup */
++}
++
++static int
++ptp_function_bind_config(struct android_usb_function *f,
++		struct usb_configuration *c)
++{
++	return mtp_bind_config(c, true);
++}
++
++static int mtp_function_ctrlrequest(struct android_usb_function *f,
++					struct usb_composite_dev *cdev,
++					const struct usb_ctrlrequest *c)
++{
++	return mtp_ctrlrequest(cdev, c);
++}
++
++static struct android_usb_function mtp_function = {
++	.name		= "mtp",
++	.init		= mtp_function_init,
++	.cleanup	= mtp_function_cleanup,
++	.bind_config	= mtp_function_bind_config,
++	.ctrlrequest	= mtp_function_ctrlrequest,
++};
++
++/* PTP function is same as MTP with slightly different interface descriptor */
++static struct android_usb_function ptp_function = {
++	.name		= "ptp",
++	.init		= ptp_function_init,
++	.cleanup	= ptp_function_cleanup,
++	.bind_config	= ptp_function_bind_config,
++};
++
++
++struct rndis_function_config {
++	u8      ethaddr[ETH_ALEN];
++	u32     vendorID;
++	char	manufacturer[256];
++	/* "Wireless" RNDIS; auto-detected by Windows */
++	bool	wceis;
++	struct eth_dev *dev;
++};
++
++static int
++rndis_function_init(struct android_usb_function *f,
++		struct usb_composite_dev *cdev)
++{
++	f->config = kzalloc(sizeof(struct rndis_function_config), GFP_KERNEL);
++	if (!f->config)
++		return -ENOMEM;
++	return 0;
++}
++
++static void rndis_function_cleanup(struct android_usb_function *f)
++{
++	kfree(f->config);
++	f->config = NULL;
++}
++
++static int
++rndis_function_bind_config(struct android_usb_function *f,
++		struct usb_configuration *c)
++{
++	int ret;
++	struct eth_dev *dev;
++	struct rndis_function_config *rndis = f->config;
++
++	if (!rndis) {
++		pr_err("%s: rndis_pdata\n", __func__);
++		return -1;
++	}
++
++	pr_info("%s MAC: %02X:%02X:%02X:%02X:%02X:%02X\n", __func__,
++		rndis->ethaddr[0], rndis->ethaddr[1], rndis->ethaddr[2],
++		rndis->ethaddr[3], rndis->ethaddr[4], rndis->ethaddr[5]);
++
++	dev = gether_setup_name(c->cdev->gadget,dev_addr, host_addr, rndis->ethaddr, qmult, "rndis");
++	if (IS_ERR(dev)) {
++		ret = PTR_ERR(dev);
++		pr_err("%s: gether_setup failed\n", __func__);
++		return ret;
++	}
++	rndis->dev = dev;
++
++	if (rndis->wceis) {
++		/* "Wireless" RNDIS; auto-detected by Windows */
++		rndis_iad_descriptor.bFunctionClass =
++						USB_CLASS_WIRELESS_CONTROLLER;
++		rndis_iad_descriptor.bFunctionSubClass = 0x01;
++		rndis_iad_descriptor.bFunctionProtocol = 0x03;
++		rndis_control_intf.bInterfaceClass =
++						USB_CLASS_WIRELESS_CONTROLLER;
++		rndis_control_intf.bInterfaceSubClass =	 0x01;
++		rndis_control_intf.bInterfaceProtocol =	 0x03;
++	}
++
++	return rndis_bind_config_vendor(c, rndis->ethaddr, rndis->vendorID,
++					   rndis->manufacturer, rndis->dev);
++}
++
++static void rndis_function_unbind_config(struct android_usb_function *f,
++						struct usb_configuration *c)
++{
++	struct rndis_function_config *rndis = f->config;
++	gether_cleanup(rndis->dev);
++}
++
++static ssize_t rndis_manufacturer_show(struct device *dev,
++		struct device_attribute *attr, char *buf)
++{
++	struct android_usb_function *f = dev_get_drvdata(dev);
++	struct rndis_function_config *config = f->config;
++	return sprintf(buf, "%s\n", config->manufacturer);
++}
++
++static ssize_t rndis_manufacturer_store(struct device *dev,
++		struct device_attribute *attr, const char *buf, size_t size)
++{
++	struct android_usb_function *f = dev_get_drvdata(dev);
++	struct rndis_function_config *config = f->config;
++
++	if (size >= sizeof(config->manufacturer))
++		return -EINVAL;
++	if (sscanf(buf, "%s", config->manufacturer) == 1)
++		return size;
++	return -1;
++}
++
++static DEVICE_ATTR(manufacturer, S_IRUGO | S_IWUSR, rndis_manufacturer_show,
++						    rndis_manufacturer_store);
++
++static ssize_t rndis_wceis_show(struct device *dev,
++		struct device_attribute *attr, char *buf)
++{
++	struct android_usb_function *f = dev_get_drvdata(dev);
++	struct rndis_function_config *config = f->config;
++	return sprintf(buf, "%d\n", config->wceis);
++}
++
++static ssize_t rndis_wceis_store(struct device *dev,
++		struct device_attribute *attr, const char *buf, size_t size)
++{
++	struct android_usb_function *f = dev_get_drvdata(dev);
++	struct rndis_function_config *config = f->config;
++	int value;
++
++	if (sscanf(buf, "%d", &value) == 1) {
++		config->wceis = value;
++		return size;
++	}
++	return -EINVAL;
++}
++
++static DEVICE_ATTR(wceis, S_IRUGO | S_IWUSR, rndis_wceis_show,
++					     rndis_wceis_store);
++
++static ssize_t rndis_ethaddr_show(struct device *dev,
++		struct device_attribute *attr, char *buf)
++{
++	struct android_usb_function *f = dev_get_drvdata(dev);
++	struct rndis_function_config *rndis = f->config;
++	return sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x\n",
++		rndis->ethaddr[0], rndis->ethaddr[1], rndis->ethaddr[2],
++		rndis->ethaddr[3], rndis->ethaddr[4], rndis->ethaddr[5]);
++}
++
++static ssize_t rndis_ethaddr_store(struct device *dev,
++		struct device_attribute *attr, const char *buf, size_t size)
++{
++	struct android_usb_function *f = dev_get_drvdata(dev);
++	struct rndis_function_config *rndis = f->config;
++
++	if (sscanf(buf, "%02x:%02x:%02x:%02x:%02x:%02x\n",
++		    (int *)&rndis->ethaddr[0], (int *)&rndis->ethaddr[1],
++		    (int *)&rndis->ethaddr[2], (int *)&rndis->ethaddr[3],
++		    (int *)&rndis->ethaddr[4], (int *)&rndis->ethaddr[5]) == 6)
++		return size;
++	return -EINVAL;
++}
++
++static DEVICE_ATTR(ethaddr, S_IRUGO | S_IWUSR, rndis_ethaddr_show,
++					       rndis_ethaddr_store);
++
++static ssize_t rndis_vendorID_show(struct device *dev,
++		struct device_attribute *attr, char *buf)
++{
++	struct android_usb_function *f = dev_get_drvdata(dev);
++	struct rndis_function_config *config = f->config;
++	return sprintf(buf, "%04x\n", config->vendorID);
++}
++
++static ssize_t rndis_vendorID_store(struct device *dev,
++		struct device_attribute *attr, const char *buf, size_t size)
++{
++	struct android_usb_function *f = dev_get_drvdata(dev);
++	struct rndis_function_config *config = f->config;
++	int value;
++
++	if (sscanf(buf, "%04x", &value) == 1) {
++		config->vendorID = value;
++		return size;
++	}
++	return -EINVAL;
++}
++
++static DEVICE_ATTR(vendorID, S_IRUGO | S_IWUSR, rndis_vendorID_show,
++						rndis_vendorID_store);
++
++static struct device_attribute *rndis_function_attributes[] = {
++	&dev_attr_manufacturer,
++	&dev_attr_wceis,
++	&dev_attr_ethaddr,
++	&dev_attr_vendorID,
++	NULL
++};
++
++static struct android_usb_function rndis_function = {
++	.name		= "rndis",
++	.init		= rndis_function_init,
++	.cleanup	= rndis_function_cleanup,
++	.bind_config	= rndis_function_bind_config,
++	.unbind_config	= rndis_function_unbind_config,
++	.attributes	= rndis_function_attributes,
++};
++
++
++#define MAX_MS_INSTANCES 1
++struct mass_storage_function_config {
++	int instances;
++	int instances_on;
++	struct usb_function *f_ms[MAX_MS_INSTANCES];
++	struct usb_function_instance *f_ms_inst[MAX_MS_INSTANCES];
++};
++
++static int mass_storage_function_init(struct android_usb_function *f,
++					struct usb_composite_dev *cdev)
++{
++	struct mass_storage_function_config *config;
++	int i;
++	int ret;
++
++	config = kzalloc(sizeof(struct mass_storage_function_config),
++								GFP_KERNEL);
++	if (!config)
++		return -ENOMEM;
++	f->config = config;
++
++	for (i = 0; i < MAX_MS_INSTANCES; i++) {
++		config->f_ms_inst[i] = usb_get_function_instance("mass_storage");
++		if (IS_ERR(config->f_ms_inst[i])) {
++			ret = PTR_ERR(config->f_ms_inst[i]);
++			goto err_usb_get_function_instance;
++		}
++		config->f_ms[i] = usb_get_function(config->f_ms_inst[i]);
++		if (IS_ERR(config->f_ms[i])) {
++			ret = PTR_ERR(config->f_ms[i]);
++			goto err_usb_get_function;
++		}
++	}
++
++	return 0;
++err_usb_get_function_instance:
++	while (i-- > 0) {
++		usb_put_function(config->f_ms[i]);
++err_usb_get_function:
++		usb_put_function_instance(config->f_ms_inst[i]);
++	}
++	return ret;
++}
++
++static void mass_storage_function_cleanup(struct android_usb_function *f)
++{
++	struct mass_storage_function_config *config = f->config;
++	int i;
++
++	for (i = 0; i < MAX_MS_INSTANCES; i++) {
++		usb_put_function(config->f_ms[i]);
++		usb_put_function_instance(config->f_ms_inst[i]);
++	}
++	kfree(f->config);
++	f->config = NULL;
++}
++
++static int mass_storage_function_bind_config(struct android_usb_function *f,
++					   struct usb_configuration *c)
++{
++	struct mass_storage_function_config *config = f->config;
++	int ret = 0;
++	int i;
++
++	config->instances_on = config->instances;
++	for (i = 0; i < config->instances_on; i++) {
++		ret = usb_add_function(c, config->f_ms[i]);
++		if (ret) {
++			pr_err("Could not bind ms%u config\n", i);
++			goto err_usb_add_function;
++		}
++	}
++
++	return 0;
++
++err_usb_add_function:
++	while (i-- > 0)
++		usb_remove_function(c, config->f_ms[i]);
++	return ret;
++}
++
++static void mass_storage_function_unbind_config(struct android_usb_function *f,
++				struct usb_configuration *c)
++{
++	int i;
++	struct mass_storage_function_config *config = f->config;
++
++	for (i = 0; i < config->instances_on; i++)
++		usb_remove_function(c, config->f_ms[i]);
++}
++
++static ssize_t mass_storage_inquiry_show(struct device *dev,
++				struct device_attribute *attr, char *buf)
++{
++	struct android_usb_function *f = dev_get_drvdata(dev);
++	struct mass_storage_function_config *config = f->config;
++	return sprintf(buf, "%d\n", config->instances);
++}
++
++static ssize_t mass_storage_inquiry_store(struct device *dev,
++		struct device_attribute *attr, const char *buf, size_t size)
++{
++	struct android_usb_function *f = dev_get_drvdata(dev);
++	struct mass_storage_function_config *config = f->config;
++	int value;
++
++	sscanf(buf, "%d", &value);
++	if (value > MAX_MS_INSTANCES)
++		value = MAX_MS_INSTANCES;
++	config->instances = value;
++	return size;
++}
++
++static DEVICE_ATTR(inquiry_string, S_IRUGO | S_IWUSR,
++					mass_storage_inquiry_show,
++					mass_storage_inquiry_store);
++
++static struct device_attribute *mass_storage_function_attributes[] = {
++	&dev_attr_inquiry_string,
++	NULL
++};
++
++static struct android_usb_function mass_storage_function = {
++	.name		= "mass_storage",
++	.init		= mass_storage_function_init,
++	.cleanup	= mass_storage_function_cleanup,
++	.bind_config	= mass_storage_function_bind_config,
++	.attributes	= mass_storage_function_attributes,
++};
++
++
++static int accessory_function_init(struct android_usb_function *f,
++					struct usb_composite_dev *cdev)
++{
++	return acc_setup();
++}
++
++static void accessory_function_cleanup(struct android_usb_function *f)
++{
++	acc_cleanup();
++}
++
++static int accessory_function_bind_config(struct android_usb_function *f,
++						struct usb_configuration *c)
++{
++	return acc_bind_config(c);
++}
++
++static int accessory_function_ctrlrequest(struct android_usb_function *f,
++						struct usb_composite_dev *cdev,
++						const struct usb_ctrlrequest *c)
++{
++	return acc_ctrlrequest(cdev, c);
++}
++
++static struct android_usb_function accessory_function = {
++	.name		= "accessory",
++	.init		= accessory_function_init,
++	.cleanup	= accessory_function_cleanup,
++	.bind_config	= accessory_function_bind_config,
++	.ctrlrequest	= accessory_function_ctrlrequest,
++};
++
++static int audio_source_function_init(struct android_usb_function *f,
++			struct usb_composite_dev *cdev)
++{
++	struct audio_source_config *config;
++
++	config = kzalloc(sizeof(struct audio_source_config), GFP_KERNEL);
++	if (!config)
++		return -ENOMEM;
++	config->card = -1;
++	config->device = -1;
++	f->config = config;
++	return 0;
++}
++
++static void audio_source_function_cleanup(struct android_usb_function *f)
++{
++	kfree(f->config);
++}
++
++static int audio_source_function_bind_config(struct android_usb_function *f,
++						struct usb_configuration *c)
++{
++	struct audio_source_config *config = f->config;
++
++	return audio_source_bind_config(c, config);
++}
++
++static void audio_source_function_unbind_config(struct android_usb_function *f,
++						struct usb_configuration *c)
++{
++	struct audio_source_config *config = f->config;
++
++	config->card = -1;
++	config->device = -1;
++}
++
++static struct android_usb_function audio_source_function = {
++	.name		= "audio_source",
++	.init		= audio_source_function_init,
++	.cleanup	= audio_source_function_cleanup,
++	.bind_config	= audio_source_function_bind_config,
++	.unbind_config	= audio_source_function_unbind_config,
++	.attributes	= audio_source_function_attributes,
++};
++
++static struct android_usb_function *supported_functions[] = {
++	&ffs_function,
++	&acm_function,
++	&mtp_function,
++	&ptp_function,
++	&rndis_function,
++	&mass_storage_function,
++	&accessory_function,
++	&audio_source_function,
++	NULL
++};
++
++
++static int android_init_functions(struct android_usb_function **functions,
++				  struct usb_composite_dev *cdev)
++{
++	struct android_dev *dev = _android_dev;
++	struct android_usb_function *f;
++	struct device_attribute **attrs;
++	struct device_attribute *attr;
++	int err;
++	int index = 0;
++
++	for (; (f = *functions++); index++) {
++		f->dev_name = kasprintf(GFP_KERNEL, "f_%s", f->name);
++		f->dev = device_create(android_class, dev->dev,
++				MKDEV(0, index), f, f->dev_name);
++		if (IS_ERR(f->dev)) {
++			pr_err("%s: Failed to create dev %s", __func__,
++							f->dev_name);
++			err = PTR_ERR(f->dev);
++			goto err_create;
++		}
++
++		if (f->init) {
++			err = f->init(f, cdev);
++			if (err) {
++				pr_err("%s: Failed to init %s", __func__,
++								f->name);
++				goto err_out;
++			}
++		}
++
++		attrs = f->attributes;
++		if (attrs) {
++			while ((attr = *attrs++) && !err)
++				err = device_create_file(f->dev, attr);
++		}
++		if (err) {
++			pr_err("%s: Failed to create function %s attributes",
++					__func__, f->name);
++			goto err_out;
++		}
++	}
++	return 0;
++
++err_out:
++	device_destroy(android_class, f->dev->devt);
++err_create:
++	kfree(f->dev_name);
++	return err;
++}
++
++static void android_cleanup_functions(struct android_usb_function **functions)
++{
++	struct android_usb_function *f;
++
++	while (*functions) {
++		f = *functions++;
++
++		if (f->dev) {
++			device_destroy(android_class, f->dev->devt);
++			kfree(f->dev_name);
++		}
++
++		if (f->cleanup)
++			f->cleanup(f);
++	}
++}
++
++static int
++android_bind_enabled_functions(struct android_dev *dev,
++			       struct usb_configuration *c)
++{
++	struct android_usb_function *f;
++	int ret;
++
++	list_for_each_entry(f, &dev->enabled_functions, enabled_list) {
++		ret = f->bind_config(f, c);
++		if (ret) {
++			pr_err("%s: %s failed", __func__, f->name);
++			return ret;
++		}
++	}
++	return 0;
++}
++
++static void
++android_unbind_enabled_functions(struct android_dev *dev,
++			       struct usb_configuration *c)
++{
++	struct android_usb_function *f;
++
++	list_for_each_entry(f, &dev->enabled_functions, enabled_list) {
++		if (f->unbind_config)
++			f->unbind_config(f, c);
++	}
++}
++
++static int android_enable_function(struct android_dev *dev, char *name)
++{
++	struct android_usb_function **functions = dev->functions;
++	struct android_usb_function *f;
++	while ((f = *functions++)) {
++		if (!strcmp(name, f->name)) {
++			list_add_tail(&f->enabled_list,
++						&dev->enabled_functions);
++			return 0;
++		}
++	}
++	return -EINVAL;
++}
++
++/*-------------------------------------------------------------------------*/
++/* /sys/class/android_usb/android%d/ interface */
++
++static ssize_t
++functions_show(struct device *pdev, struct device_attribute *attr, char *buf)
++{
++	struct android_dev *dev = dev_get_drvdata(pdev);
++	struct android_usb_function *f;
++	char *buff = buf;
++
++	mutex_lock(&dev->mutex);
++
++	list_for_each_entry(f, &dev->enabled_functions, enabled_list)
++		buff += sprintf(buff, "%s,", f->name);
++
++	mutex_unlock(&dev->mutex);
++
++	if (buff != buf)
++		*(buff-1) = '\n';
++	return buff - buf;
++}
++
++static ssize_t
++functions_store(struct device *pdev, struct device_attribute *attr,
++			       const char *buff, size_t size)
++{
++	struct android_dev *dev = dev_get_drvdata(pdev);
++	char *name;
++	char buf[256], *b;
++	char aliases[256], *a;
++	int err;
++	int is_ffs;
++	int ffs_enabled = 0;
++
++	mutex_lock(&dev->mutex);
++
++	if (dev->enabled) {
++		mutex_unlock(&dev->mutex);
++		return -EBUSY;
++	}
++
++	INIT_LIST_HEAD(&dev->enabled_functions);
++
++	strlcpy(buf, buff, sizeof(buf));
++	b = strim(buf);
++
++	while (b) {
++		name = strsep(&b, ",");
++		if (!name)
++			continue;
++
++		is_ffs = 0;
++		strlcpy(aliases, dev->ffs_aliases, sizeof(aliases));
++		a = aliases;
++
++		while (a) {
++			char *alias = strsep(&a, ",");
++			if (alias && !strcmp(name, alias)) {
++				is_ffs = 1;
++				break;
++			}
++		}
++
++		if (is_ffs) {
++			if (ffs_enabled)
++				continue;
++			err = android_enable_function(dev, "ffs");
++			if (err)
++				pr_err("android_usb: Cannot enable ffs (%d)",
++									err);
++			else
++				ffs_enabled = 1;
++			continue;
++		}
++
++		err = android_enable_function(dev, name);
++		if (err)
++			pr_err("android_usb: Cannot enable '%s' (%d)",
++							   name, err);
++	}
++
++	mutex_unlock(&dev->mutex);
++
++	return size;
++}
++
++static ssize_t enable_show(struct device *pdev, struct device_attribute *attr,
++			   char *buf)
++{
++	struct android_dev *dev = dev_get_drvdata(pdev);
++	return sprintf(buf, "%d\n", dev->enabled);
++}
++
++static ssize_t enable_store(struct device *pdev, struct device_attribute *attr,
++			    const char *buff, size_t size)
++{
++	struct android_dev *dev = dev_get_drvdata(pdev);
++	struct usb_composite_dev *cdev = dev->cdev;
++	struct android_usb_function *f;
++	int enabled = 0;
++
++
++	if (!cdev)
++		return -ENODEV;
++
++	mutex_lock(&dev->mutex);
++
++	sscanf(buff, "%d", &enabled);
++	if (enabled && !dev->enabled) {
++		cdev->next_string_id = 0;
++		/*
++		 * Update values in composite driver's copy of
++		 * device descriptor.
++		 */
++		cdev->desc.idVendor = device_desc.idVendor;
++		cdev->desc.idProduct = device_desc.idProduct;
++		cdev->desc.bcdDevice = device_desc.bcdDevice;
++		cdev->desc.bDeviceClass = device_desc.bDeviceClass;
++		cdev->desc.bDeviceSubClass = device_desc.bDeviceSubClass;
++		cdev->desc.bDeviceProtocol = device_desc.bDeviceProtocol;
++		list_for_each_entry(f, &dev->enabled_functions, enabled_list) {
++			if (f->enable)
++				f->enable(f);
++		}
++		android_enable(dev);
++		dev->enabled = true;
++	} else if (!enabled && dev->enabled) {
++		android_disable(dev);
++		list_for_each_entry(f, &dev->enabled_functions, enabled_list) {
++			if (f->disable)
++				f->disable(f);
++		}
++		dev->enabled = false;
++	} else {
++		pr_err("android_usb: already %s\n",
++				dev->enabled ? "enabled" : "disabled");
++	}
++
++	mutex_unlock(&dev->mutex);
++	return size;
++}
++
++static ssize_t state_show(struct device *pdev, struct device_attribute *attr,
++			   char *buf)
++{
++	struct android_dev *dev = dev_get_drvdata(pdev);
++	struct usb_composite_dev *cdev = dev->cdev;
++	char *state = "DISCONNECTED";
++	unsigned long flags;
++
++	if (!cdev)
++		goto out;
++
++	spin_lock_irqsave(&cdev->lock, flags);
++	if (cdev->config)
++		state = "CONFIGURED";
++	else if (dev->connected)
++		state = "CONNECTED";
++	spin_unlock_irqrestore(&cdev->lock, flags);
++out:
++	return sprintf(buf, "%s\n", state);
++}
++
++#define DESCRIPTOR_ATTR(field, format_string)				\
++static ssize_t								\
++field ## _show(struct device *dev, struct device_attribute *attr,	\
++		char *buf)						\
++{									\
++	return sprintf(buf, format_string, device_desc.field);		\
++}									\
++static ssize_t								\
++field ## _store(struct device *dev, struct device_attribute *attr,	\
++		const char *buf, size_t size)				\
++{									\
++	int value;							\
++	if (sscanf(buf, format_string, &value) == 1) {			\
++		device_desc.field = value;				\
++		return size;						\
++	}								\
++	return -1;							\
++}									\
++static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, field ## _show, field ## _store);
++
++#define DESCRIPTOR_STRING_ATTR(field, buffer)				\
++static ssize_t								\
++field ## _show(struct device *dev, struct device_attribute *attr,	\
++		char *buf)						\
++{									\
++	return sprintf(buf, "%s", buffer);				\
++}									\
++static ssize_t								\
++field ## _store(struct device *dev, struct device_attribute *attr,	\
++		const char *buf, size_t size)				\
++{									\
++	if (size >= sizeof(buffer))					\
++		return -EINVAL;						\
++	return strlcpy(buffer, buf, sizeof(buffer));			\
++}									\
++static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, field ## _show, field ## _store);
++
++
++DESCRIPTOR_ATTR(idVendor, "%04x\n")
++DESCRIPTOR_ATTR(idProduct, "%04x\n")
++DESCRIPTOR_ATTR(bcdDevice, "%04x\n")
++DESCRIPTOR_ATTR(bDeviceClass, "%d\n")
++DESCRIPTOR_ATTR(bDeviceSubClass, "%d\n")
++DESCRIPTOR_ATTR(bDeviceProtocol, "%d\n")
++DESCRIPTOR_STRING_ATTR(iManufacturer, manufacturer_string)
++DESCRIPTOR_STRING_ATTR(iProduct, product_string)
++DESCRIPTOR_STRING_ATTR(iSerial, serial_string)
++
++static DEVICE_ATTR(functions, S_IRUGO | S_IWUSR, functions_show,
++						 functions_store);
++static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, enable_show, enable_store);
++static DEVICE_ATTR(state, S_IRUGO, state_show, NULL);
++
++static struct device_attribute *android_usb_attributes[] = {
++	&dev_attr_idVendor,
++	&dev_attr_idProduct,
++	&dev_attr_bcdDevice,
++	&dev_attr_bDeviceClass,
++	&dev_attr_bDeviceSubClass,
++	&dev_attr_bDeviceProtocol,
++	&dev_attr_iManufacturer,
++	&dev_attr_iProduct,
++	&dev_attr_iSerial,
++	&dev_attr_functions,
++	&dev_attr_enable,
++	&dev_attr_state,
++	NULL
++};
++
++/*-------------------------------------------------------------------------*/
++/* Composite driver */
++
++static int android_bind_config(struct usb_configuration *c)
++{
++	struct android_dev *dev = _android_dev;
++	int ret = 0;
++
++	ret = android_bind_enabled_functions(dev, c);
++	if (ret)
++		return ret;
++
++	return 0;
++}
++
++static void android_unbind_config(struct usb_configuration *c)
++{
++	struct android_dev *dev = _android_dev;
++
++	android_unbind_enabled_functions(dev, c);
++}
++
++static int android_bind(struct usb_composite_dev *cdev)
++{
++	struct android_dev *dev = _android_dev;
++	struct usb_gadget	*gadget = cdev->gadget;
++	int			id, ret;
++
++	/* Save the default handler */
++	dev->setup_complete = cdev->req->complete;
++
++	/*
++	 * Start disconnected. Userspace will connect the gadget once
++	 * it is done configuring the functions.
++	 */
++	usb_gadget_disconnect(gadget);
++
++	ret = android_init_functions(dev->functions, cdev);
++	if (ret)
++		return ret;
++
++	/* Allocate string descriptor numbers ... note that string
++	 * contents can be overridden by the composite_dev glue.
++	 */
++	id = usb_string_id(cdev);
++	if (id < 0)
++		return id;
++	strings_dev[STRING_MANUFACTURER_IDX].id = id;
++	device_desc.iManufacturer = id;
++
++	id = usb_string_id(cdev);
++	if (id < 0)
++		return id;
++	strings_dev[STRING_PRODUCT_IDX].id = id;
++	device_desc.iProduct = id;
++
++	/* Default strings - should be updated by userspace */
++	strncpy(manufacturer_string, "Android", sizeof(manufacturer_string)-1);
++	strncpy(product_string, "Android", sizeof(product_string) - 1);
++	strncpy(serial_string, "0123456789ABCDEF", sizeof(serial_string) - 1);
++
++	id = usb_string_id(cdev);
++	if (id < 0)
++		return id;
++	strings_dev[STRING_SERIAL_IDX].id = id;
++	device_desc.iSerialNumber = id;
++
++	usb_gadget_set_selfpowered(gadget);
++	dev->cdev = cdev;
++
++	return 0;
++}
++
++static int android_usb_unbind(struct usb_composite_dev *cdev)
++{
++	struct android_dev *dev = _android_dev;
++
++	cancel_work_sync(&dev->work);
++	android_cleanup_functions(dev->functions);
++	return 0;
++}
++
++/* HACK: android needs to override setup for accessory to work */
++static int (*composite_setup_func)(struct usb_gadget *gadget, const struct usb_ctrlrequest *c);
++
++static int
++android_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *c)
++{
++	struct android_dev		*dev = _android_dev;
++	struct usb_composite_dev	*cdev = get_gadget_data(gadget);
++	struct usb_request		*req = cdev->req;
++	struct android_usb_function	*f;
++	int value = -EOPNOTSUPP;
++	unsigned long flags;
++
++	req->zero = 0;
++	req->length = 0;
++	req->complete = dev->setup_complete;
++	gadget->ep0->driver_data = cdev;
++
++	list_for_each_entry(f, &dev->enabled_functions, enabled_list) {
++		if (f->ctrlrequest) {
++			value = f->ctrlrequest(f, cdev, c);
++			if (value >= 0)
++				break;
++		}
++	}
++
++	/* Special case the accessory function.
++	 * It needs to handle control requests before it is enabled.
++	 */
++	if (value < 0)
++		value = acc_ctrlrequest(cdev, c);
++
++	if (value < 0)
++		value = composite_setup_func(gadget, c);
++
++	spin_lock_irqsave(&cdev->lock, flags);
++	if (!dev->connected) {
++		dev->connected = 1;
++		schedule_work(&dev->work);
++	} else if (c->bRequest == USB_REQ_SET_CONFIGURATION &&
++						cdev->config) {
++		schedule_work(&dev->work);
++	}
++	spin_unlock_irqrestore(&cdev->lock, flags);
++
++	return value;
++}
++
++static void android_disconnect(struct usb_composite_dev *cdev)
++{
++	struct android_dev *dev = _android_dev;
++
++	/* accessory HID support can be active while the
++	   accessory function is not actually enabled,
++	   so we need to inform it when we are disconnected.
++	 */
++	acc_disconnect();
++
++	dev->connected = 0;
++	schedule_work(&dev->work);
++}
++
++static struct usb_composite_driver android_usb_driver = {
++	.name		= "android_usb",
++	.dev		= &device_desc,
++	.strings	= dev_strings,
++	.bind		= android_bind,
++	.unbind		= android_usb_unbind,
++	.disconnect	= android_disconnect,
++	.max_speed	= USB_SPEED_HIGH,
++};
++
++static int android_create_device(struct android_dev *dev)
++{
++	struct device_attribute **attrs = android_usb_attributes;
++	struct device_attribute *attr;
++	int err;
++
++	dev->dev = device_create(android_class, NULL,
++					MKDEV(0, 0), NULL, "android0");
++	if (IS_ERR(dev->dev))
++		return PTR_ERR(dev->dev);
++
++	dev_set_drvdata(dev->dev, dev);
++
++	while ((attr = *attrs++)) {
++		err = device_create_file(dev->dev, attr);
++		if (err) {
++			device_destroy(android_class, dev->dev->devt);
++			return err;
++		}
++	}
++	return 0;
++}
++
++
++static int __init init(void)
++{
++	struct android_dev *dev;
++	int err;
++
++	android_class = class_create(THIS_MODULE, "android_usb");
++	if (IS_ERR(android_class))
++		return PTR_ERR(android_class);
++
++	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
++	if (!dev) {
++		err = -ENOMEM;
++		goto err_dev;
++	}
++
++	dev->disable_depth = 1;
++	dev->functions = supported_functions;
++	INIT_LIST_HEAD(&dev->enabled_functions);
++	INIT_WORK(&dev->work, android_work);
++	mutex_init(&dev->mutex);
++
++	err = android_create_device(dev);
++	if (err) {
++		pr_err("%s: failed to create android device %d", __func__, err);
++		goto err_create;
++	}
++
++	_android_dev = dev;
++
++	err = usb_composite_probe(&android_usb_driver);
++	if (err) {
++		pr_err("%s: failed to probe driver %d", __func__, err);
++		goto err_probe;
++	}
++
++	/* HACK: exchange composite's setup with ours */
++	composite_setup_func = android_usb_driver.gadget_driver.setup;
++	android_usb_driver.gadget_driver.setup = android_setup;
++
++	return 0;
++
++err_probe:
++	device_destroy(android_class, dev->dev->devt);
++err_create:
++	kfree(dev);
++err_dev:
++	class_destroy(android_class);
++	return err;
++}
++late_initcall(init);
++
++static void __exit cleanup(void)
++{
++	usb_composite_unregister(&android_usb_driver);
++	class_destroy(android_class);
++	kfree(_android_dev);
++	_android_dev = NULL;
++}
++module_exit(cleanup);
+diff --git a/drivers/usb/gadget/legacy/audio.c b/drivers/usb/gadget/legacy/audio.c
+index f46a395..1db5181 100644
+--- a/drivers/usb/gadget/legacy/audio.c
++++ b/drivers/usb/gadget/legacy/audio.c
+@@ -15,7 +15,6 @@
+ #include <linux/module.h>
+ #include <linux/usb/composite.h>
+ 
+-#include "gadget_chips.h"
+ #define DRIVER_DESC		"Linux USB Audio Gadget"
+ #define DRIVER_VERSION		"Feb 2, 2012"
+ 
+@@ -54,8 +53,51 @@ static int c_ssize = UAC2_DEF_CSSIZE;
+ module_param(c_ssize, uint, S_IRUGO);
+ MODULE_PARM_DESC(c_ssize, "Capture Sample Size(bytes)");
+ #else
++#ifndef CONFIG_GADGET_UAC1_LEGACY
+ #include "u_uac1.h"
+ 
++/* Playback(USB-IN) Default Stereo - Fl/Fr */
++static int p_chmask = UAC1_DEF_PCHMASK;
++module_param(p_chmask, uint, S_IRUGO);
++MODULE_PARM_DESC(p_chmask, "Playback Channel Mask");
++
++/* Playback Default 48 KHz */
++static int p_srate = UAC1_DEF_PSRATE;
++module_param(p_srate, uint, S_IRUGO);
++MODULE_PARM_DESC(p_srate, "Playback Sampling Rate");
++
++/* Playback Default 16bits/sample */
++static int p_ssize = UAC1_DEF_PSSIZE;
++module_param(p_ssize, uint, S_IRUGO);
++MODULE_PARM_DESC(p_ssize, "Playback Sample Size(bytes)");
++
++/* Capture(USB-OUT) Default Stereo - Fl/Fr */
++static int c_chmask = UAC1_DEF_CCHMASK;
++module_param(c_chmask, uint, S_IRUGO);
++MODULE_PARM_DESC(c_chmask, "Capture Channel Mask");
++
++/* Capture Default 48 KHz */
++static int c_srate = UAC1_DEF_CSRATE;
++module_param(c_srate, uint, S_IRUGO);
++MODULE_PARM_DESC(c_srate, "Capture Sampling Rate");
++
++/* Capture Default 16bits/sample */
++static int c_ssize = UAC1_DEF_CSSIZE;
++module_param(c_ssize, uint, S_IRUGO);
++MODULE_PARM_DESC(c_ssize, "Capture Sample Size(bytes)");
++
++/* req number */
++static int req_num = UAC1_DEF_REQ_NUM;
++module_param(req_num, uint, S_IRUGO);
++MODULE_PARM_DESC(req_num, "req number");
++
++static int req_buf_size = UAC1_OUT_EP_MAX_PACKET_SIZE;
++module_param(req_buf_size, int, S_IRUGO);
++MODULE_PARM_DESC(req_buf_size, "ISO OUT endpoint request buffer size");
++
++#else /* CONFIG_GADGET_UAC1_LEGACY */
++#include "u_uac1_legacy.h"
++
+ static char *fn_play = FILE_PCM_PLAYBACK;
+ module_param(fn_play, charp, S_IRUGO);
+ MODULE_PARM_DESC(fn_play, "Playback PCM device file name");
+@@ -79,6 +121,7 @@ MODULE_PARM_DESC(req_count, "ISO OUT endpoint request count");
+ static int audio_buf_size = UAC1_AUDIO_BUF_SIZE;
+ module_param(audio_buf_size, int, S_IRUGO);
+ MODULE_PARM_DESC(audio_buf_size, "Audio buffer size");
++#endif /* CONFIG_GADGET_UAC1_LEGACY */
+ #endif
+ 
+ /* string IDs are assigned dynamically */
+@@ -124,9 +167,9 @@ static struct usb_device_descriptor device_desc = {
+ 	.bLength =		sizeof device_desc,
+ 	.bDescriptorType =	USB_DT_DEVICE,
+ 
+-	.bcdUSB =		__constant_cpu_to_le16(0x200),
++	/* .bcdUSB = DYNAMIC */
+ 
+-#ifdef CONFIG_GADGET_UAC1
++#ifdef CONFIG_GADGET_UAC1_LEGACY
+ 	.bDeviceClass =		USB_CLASS_PER_INTERFACE,
+ 	.bDeviceSubClass =	0,
+ 	.bDeviceProtocol =	0,
+@@ -141,8 +184,8 @@ static struct usb_device_descriptor device_desc = {
+ 	 * we support.  (As does bNumConfigurations.)  These values can
+ 	 * also be overridden by module parameters.
+ 	 */
+-	.idVendor =		__constant_cpu_to_le16(AUDIO_VENDOR_NUM),
+-	.idProduct =		__constant_cpu_to_le16(AUDIO_PRODUCT_NUM),
++	.idVendor =		cpu_to_le16(AUDIO_VENDOR_NUM),
++	.idProduct =		cpu_to_le16(AUDIO_PRODUCT_NUM),
+ 	/* .bcdDevice = f(hardware) */
+ 	/* .iManufacturer = DYNAMIC */
+ 	/* .iProduct = DYNAMIC */
+@@ -150,24 +193,11 @@ static struct usb_device_descriptor device_desc = {
+ 	.bNumConfigurations =	1,
+ };
+ 
+-static struct usb_otg_descriptor otg_descriptor = {
+-	.bLength =		sizeof otg_descriptor,
+-	.bDescriptorType =	USB_DT_OTG,
+-
+-	/* REVISIT SRP-only hardware is possible, although
+-	 * it would not be called "OTG" ...
+-	 */
+-	.bmAttributes =		USB_OTG_SRP | USB_OTG_HNP,
+-};
+-
+-static const struct usb_descriptor_header *otg_desc[] = {
+-	(struct usb_descriptor_header *) &otg_descriptor,
+-	NULL,
+-};
++static const struct usb_descriptor_header *otg_desc[2];
+ 
+ /*-------------------------------------------------------------------------*/
+ 
+-static int __init audio_do_config(struct usb_configuration *c)
++static int audio_do_config(struct usb_configuration *c)
+ {
+ 	int status;
+ 
+@@ -216,12 +246,16 @@ static struct usb_configuration audio_config_driver = {
+ 
+ /*-------------------------------------------------------------------------*/
+ 
+-static int __init audio_bind(struct usb_composite_dev *cdev)
++static int audio_bind(struct usb_composite_dev *cdev)
+ {
+ #ifndef CONFIG_GADGET_UAC1
+ 	struct f_uac2_opts	*uac2_opts;
+ #else
++#ifndef CONFIG_GADGET_UAC1_LEGACY
+ 	struct f_uac1_opts	*uac1_opts;
++#else
++	struct f_uac1_legacy_opts	*uac1_opts;
++#endif
+ #endif
+ 	int			status;
+ 
+@@ -230,7 +264,11 @@ static int __init audio_bind(struct usb_composite_dev *cdev)
+ 	if (IS_ERR(fi_uac2))
+ 		return PTR_ERR(fi_uac2);
+ #else
++#ifndef CONFIG_GADGET_UAC1_LEGACY
+ 	fi_uac1 = usb_get_function_instance("uac1");
++#else
++	fi_uac1 = usb_get_function_instance("uac1_legacy");
++#endif
+ 	if (IS_ERR(fi_uac1))
+ 		return PTR_ERR(fi_uac1);
+ #endif
+@@ -243,14 +281,29 @@ static int __init audio_bind(struct usb_composite_dev *cdev)
+ 	uac2_opts->c_chmask = c_chmask;
+ 	uac2_opts->c_srate = c_srate;
+ 	uac2_opts->c_ssize = c_ssize;
++	uac2_opts->req_number = UAC2_DEF_REQ_NUM;
+ #else
++#ifndef CONFIG_GADGET_UAC1_LEGACY
+ 	uac1_opts = container_of(fi_uac1, struct f_uac1_opts, func_inst);
++	uac1_opts->p_chmask = p_chmask;
++	uac1_opts->p_srate = p_srate;
++	uac1_opts->p_ssize = p_ssize;
++	uac1_opts->c_chmask = c_chmask;
++	uac1_opts->c_srate = c_srate;
++	uac1_opts->c_ssize = c_ssize;
++	uac1_opts->req_number = UAC1_DEF_REQ_NUM;
++	uac1_opts->req_number = req_num;
++	uac1_opts->req_buf_size = req_buf_size;
++
++#else /* CONFIG_GADGET_UAC1_LEGACY */
++	uac1_opts = container_of(fi_uac1, struct f_uac1_legacy_opts, func_inst);
+ 	uac1_opts->fn_play = fn_play;
+ 	uac1_opts->fn_cap = fn_cap;
+ 	uac1_opts->fn_cntl = fn_cntl;
+ 	uac1_opts->req_buf_size = req_buf_size;
+ 	uac1_opts->req_count = req_count;
+ 	uac1_opts->audio_buf_size = audio_buf_size;
++#endif /* CONFIG_GADGET_UAC1_LEGACY */
+ #endif
+ 
+ 	status = usb_string_ids_tab(cdev, strings_dev);
+@@ -259,14 +312,32 @@ static int __init audio_bind(struct usb_composite_dev *cdev)
+ 	device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
+ 	device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
+ 
++#if 0
++	if (gadget_is_otg(cdev->gadget) && !otg_desc[0]) {
++		struct usb_descriptor_header *usb_desc;
++
++		usb_desc = usb_otg_descriptor_alloc(cdev->gadget);
++		if (!usb_desc)
++			goto fail;
++		usb_otg_descriptor_init(cdev->gadget, usb_desc);
++		otg_desc[0] = usb_desc;
++		otg_desc[1] = NULL;
++	}
++#endif
++
++#if 1
+ 	status = usb_add_config(cdev, &audio_config_driver, audio_do_config);
+ 	if (status < 0)
+-		goto fail;
++		goto fail_otg_desc;
+ 	usb_composite_overwrite_options(cdev, &coverwrite);
++#endif
+ 
+ 	INFO(cdev, "%s, version: %s\n", DRIVER_DESC, DRIVER_VERSION);
+ 	return 0;
+ 
++fail_otg_desc:
++	kfree(otg_desc[0]);
++	otg_desc[0] = NULL;
+ fail:
+ #ifndef CONFIG_GADGET_UAC1
+ 	usb_put_function_instance(fi_uac2);
+@@ -276,7 +347,7 @@ fail:
+ 	return status;
+ }
+ 
+-static int __exit audio_unbind(struct usb_composite_dev *cdev)
++static int audio_unbind(struct usb_composite_dev *cdev)
+ {
+ #ifdef CONFIG_GADGET_UAC1
+ 	if (!IS_ERR_OR_NULL(f_uac1))
+@@ -289,16 +360,20 @@ static int __exit audio_unbind(struct usb_composite_dev *cdev)
+ 	if (!IS_ERR_OR_NULL(fi_uac2))
+ 		usb_put_function_instance(fi_uac2);
+ #endif
++	kfree(otg_desc[0]);
++	otg_desc[0] = NULL;
++
+ 	return 0;
+ }
+ 
+-static __refdata struct usb_composite_driver audio_driver = {
++#if 1
++static struct usb_composite_driver audio_driver = {
+ 	.name		= "g_audio",
+ 	.dev		= &device_desc,
+ 	.strings	= audio_strings,
+ 	.max_speed	= USB_SPEED_HIGH,
+ 	.bind		= audio_bind,
+-	.unbind		= __exit_p(audio_unbind),
++	.unbind		= audio_unbind,
+ };
+ 
+ module_usb_composite_driver(audio_driver);
+@@ -307,3 +382,5 @@ MODULE_DESCRIPTION(DRIVER_DESC);
+ MODULE_AUTHOR("Bryan Wu <cooloney@kernel.org>");
+ MODULE_LICENSE("GPL");
+ 
++#endif
++
+diff --git a/drivers/usb/gadget/legacy/audio.inl b/drivers/usb/gadget/legacy/audio.inl
+new file mode 100644
+index 0000000..6f31cbe
+--- /dev/null
++++ b/drivers/usb/gadget/legacy/audio.inl
+@@ -0,0 +1,328 @@
++/*
++ * audio.c -- Audio gadget driver
++ *
++ * Copyright (C) 2008 Bryan Wu <cooloney@kernel.org>
++ * Copyright (C) 2008 Analog Devices, Inc
++ *
++ * Enter bugs at http://blackfin.uclinux.org/
++ *
++ * Licensed under the GPL-2 or later.
++ */
++
++/* #define VERBOSE_DEBUG */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/usb/composite.h>
++
++#define DRIVER_DESC		"Linux USB Audio Gadget"
++#define DRIVER_VERSION		"Feb 2, 2012"
++
++
++#ifndef CONFIG_GADGET_UAC1
++#include "u_uac2.h"
++
++/* Playback(USB-IN) Default Stereo - Fl/Fr */
++static int p_chmask = UAC2_DEF_PCHMASK;
++module_param(p_chmask, uint, S_IRUGO);
++MODULE_PARM_DESC(p_chmask, "Playback Channel Mask");
++
++/* Playback Default 48 KHz */
++static int p_srate = UAC2_DEF_PSRATE;
++module_param(p_srate, uint, S_IRUGO);
++MODULE_PARM_DESC(p_srate, "Playback Sampling Rate");
++
++/* Playback Default 16bits/sample */
++static int p_ssize = UAC2_DEF_PSSIZE;
++module_param(p_ssize, uint, S_IRUGO);
++MODULE_PARM_DESC(p_ssize, "Playback Sample Size(bytes)");
++
++/* Capture(USB-OUT) Default Stereo - Fl/Fr */
++static int c_chmask = UAC2_DEF_CCHMASK;
++module_param(c_chmask, uint, S_IRUGO);
++MODULE_PARM_DESC(c_chmask, "Capture Channel Mask");
++
++/* Capture Default 64 KHz */
++static int c_srate = UAC2_DEF_CSRATE;
++module_param(c_srate, uint, S_IRUGO);
++MODULE_PARM_DESC(c_srate, "Capture Sampling Rate");
++
++/* Capture Default 16bits/sample */
++static int c_ssize = UAC2_DEF_CSSIZE;
++module_param(c_ssize, uint, S_IRUGO);
++MODULE_PARM_DESC(c_ssize, "Capture Sample Size(bytes)");
++#else
++#ifndef CONFIG_GADGET_UAC1_LEGACY
++#include "u_uac1.h"
++
++/* Playback(USB-IN) Default Stereo - Fl/Fr */
++static int p_chmask = UAC1_DEF_PCHMASK;
++module_param(p_chmask, uint, S_IRUGO);
++MODULE_PARM_DESC(p_chmask, "Playback Channel Mask");
++
++/* Playback Default 48 KHz */
++static int p_srate = UAC1_DEF_PSRATE;
++module_param(p_srate, uint, S_IRUGO);
++MODULE_PARM_DESC(p_srate, "Playback Sampling Rate");
++
++/* Playback Default 16bits/sample */
++static int p_ssize = UAC1_DEF_PSSIZE;
++module_param(p_ssize, uint, S_IRUGO);
++MODULE_PARM_DESC(p_ssize, "Playback Sample Size(bytes)");
++
++/* Capture(USB-OUT) Default Stereo - Fl/Fr */
++static int c_chmask = UAC1_DEF_CCHMASK;
++module_param(c_chmask, uint, S_IRUGO);
++MODULE_PARM_DESC(c_chmask, "Capture Channel Mask");
++
++/* Capture Default 48 KHz */
++static int c_srate = UAC1_DEF_CSRATE;
++module_param(c_srate, uint, S_IRUGO);
++MODULE_PARM_DESC(c_srate, "Capture Sampling Rate");
++
++/* Capture Default 16bits/sample */
++static int c_ssize = UAC1_DEF_CSSIZE;
++module_param(c_ssize, uint, S_IRUGO);
++MODULE_PARM_DESC(c_ssize, "Capture Sample Size(bytes)");
++
++/* req number */
++static int req_num = UAC1_DEF_REQ_NUM;
++module_param(req_num, uint, S_IRUGO);
++MODULE_PARM_DESC(req_num, "req number");
++
++static int req_buf_size = UAC1_OUT_EP_MAX_PACKET_SIZE;
++module_param(req_buf_size, int, S_IRUGO);
++MODULE_PARM_DESC(req_buf_size, "ISO OUT endpoint request buffer size");
++
++#else /* CONFIG_GADGET_UAC1_LEGACY */
++#include "u_uac1_legacy.h"
++
++static char *fn_play = FILE_PCM_PLAYBACK;
++module_param(fn_play, charp, S_IRUGO);
++MODULE_PARM_DESC(fn_play, "Playback PCM device file name");
++
++static char *fn_cap = FILE_PCM_CAPTURE;
++module_param(fn_cap, charp, S_IRUGO);
++MODULE_PARM_DESC(fn_cap, "Capture PCM device file name");
++
++static char *fn_cntl = FILE_CONTROL;
++module_param(fn_cntl, charp, S_IRUGO);
++MODULE_PARM_DESC(fn_cntl, "Control device file name");
++
++static int req_buf_size = UAC1_OUT_EP_MAX_PACKET_SIZE;
++module_param(req_buf_size, int, S_IRUGO);
++MODULE_PARM_DESC(req_buf_size, "ISO OUT endpoint request buffer size");
++
++static int req_count = UAC1_REQ_COUNT;
++module_param(req_count, int, S_IRUGO);
++MODULE_PARM_DESC(req_count, "ISO OUT endpoint request count");
++
++static int audio_buf_size = UAC1_AUDIO_BUF_SIZE;
++module_param(audio_buf_size, int, S_IRUGO);
++MODULE_PARM_DESC(audio_buf_size, "Audio buffer size");
++#endif /* CONFIG_GADGET_UAC1_LEGACY */
++#endif
++
++/* string IDs are assigned dynamically */
++
++static struct usb_string strings_dev[] = {
++	[USB_GADGET_MANUFACTURER_IDX].s = "",
++	[USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC,
++	[USB_GADGET_SERIAL_IDX].s = "",
++	{  } /* end of list */
++};
++
++
++
++#ifndef CONFIG_GADGET_UAC1
++static struct usb_function_instance *fi_uac2;
++static struct usb_function *f_uac2;
++#else
++static struct usb_function_instance *fi_uac1;
++static struct usb_function *f_uac1;
++#endif
++
++/*-------------------------------------------------------------------------*/
++
++/* DO NOT REUSE THESE IDs with a protocol-incompatible driver!!  Ever!!
++ * Instead:  allocate your own, using normal USB-IF procedures.
++ */
++
++/* Thanks to Linux Foundation for donating this product ID. */
++#define AUDIO_VENDOR_NUM		0x1d6b	/* Linux Foundation */
++#define AUDIO_PRODUCT_NUM		0x0101	/* Linux-USB Audio Gadget */
++
++/*-------------------------------------------------------------------------*/
++
++static struct usb_device_descriptor device_desc = {
++	.bLength =		sizeof device_desc,
++	.bDescriptorType =	USB_DT_DEVICE,
++
++	/* .bcdUSB = DYNAMIC */
++
++#ifdef CONFIG_GADGET_UAC1_LEGACY
++	.bDeviceClass =		USB_CLASS_PER_INTERFACE,
++	.bDeviceSubClass =	0,
++	.bDeviceProtocol =	0,
++#else
++	.bDeviceClass =		USB_CLASS_MISC,
++	.bDeviceSubClass =	0x02,
++	.bDeviceProtocol =	0x01,
++#endif
++	/* .bMaxPacketSize0 = f(hardware) */
++
++	/* Vendor and product id defaults change according to what configs
++	 * we support.  (As does bNumConfigurations.)  These values can
++	 * also be overridden by module parameters.
++	 */
++	.idVendor =		cpu_to_le16(AUDIO_VENDOR_NUM),
++	.idProduct =		cpu_to_le16(AUDIO_PRODUCT_NUM),
++	/* .bcdDevice = f(hardware) */
++	/* .iManufacturer = DYNAMIC */
++	/* .iProduct = DYNAMIC */
++	/* NO SERIAL NUMBER */
++	.bNumConfigurations =	1,
++};
++
++static const struct usb_descriptor_header *otg_desc[2];
++
++/*-------------------------------------------------------------------------*/
++
++static int audio_do_config(struct usb_configuration *c)
++{
++	int status;
++
++	/* FIXME alloc iConfiguration string, set it in c->strings */
++
++	if (gadget_is_otg(c->cdev->gadget)) {
++		c->descriptors = otg_desc;
++		c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
++	}
++
++#ifdef CONFIG_GADGET_UAC1
++	f_uac1 = usb_get_function(fi_uac1);
++	if (IS_ERR(f_uac1)) {
++		status = PTR_ERR(f_uac1);
++		return status;
++	}
++
++	status = usb_add_function(c, f_uac1);
++	if (status < 0) {
++		usb_put_function(f_uac1);
++		return status;
++	}
++#else
++	f_uac2 = usb_get_function(fi_uac2);
++	if (IS_ERR(f_uac2)) {
++		status = PTR_ERR(f_uac2);
++		return status;
++	}
++
++	status = usb_add_function(c, f_uac2);
++	if (status < 0) {
++		usb_put_function(f_uac2);
++		return status;
++	}
++#endif
++
++	return 0;
++}
++
++/*-------------------------------------------------------------------------*/
++
++static int audio_bind(struct usb_composite_dev *cdev)
++{
++#ifndef CONFIG_GADGET_UAC1
++	struct f_uac2_opts	*uac2_opts;
++#else
++#ifndef CONFIG_GADGET_UAC1_LEGACY
++	struct f_uac1_opts	*uac1_opts;
++#else
++	struct f_uac1_legacy_opts	*uac1_opts;
++#endif
++#endif
++	int			status;
++
++#ifndef CONFIG_GADGET_UAC1
++	fi_uac2 = usb_get_function_instance("uac2");
++	if (IS_ERR(fi_uac2))
++		return PTR_ERR(fi_uac2);
++#else
++#ifndef CONFIG_GADGET_UAC1_LEGACY
++	fi_uac1 = usb_get_function_instance("uac1");
++#else
++	fi_uac1 = usb_get_function_instance("uac1_legacy");
++#endif
++	if (IS_ERR(fi_uac1))
++		return PTR_ERR(fi_uac1);
++#endif
++
++#ifndef CONFIG_GADGET_UAC1
++	uac2_opts = container_of(fi_uac2, struct f_uac2_opts, func_inst);
++	uac2_opts->p_chmask = p_chmask;
++	uac2_opts->p_srate = p_srate;
++	uac2_opts->p_ssize = p_ssize;
++	uac2_opts->c_chmask = c_chmask;
++	uac2_opts->c_srate = c_srate;
++	uac2_opts->c_ssize = c_ssize;
++	uac2_opts->req_number = UAC2_DEF_REQ_NUM;
++#else
++#ifndef CONFIG_GADGET_UAC1_LEGACY
++	uac1_opts = container_of(fi_uac1, struct f_uac1_opts, func_inst);
++	uac1_opts->p_chmask = p_chmask;
++	uac1_opts->p_srate = p_srate;
++	uac1_opts->p_ssize = p_ssize;
++	uac1_opts->c_chmask = c_chmask;
++	uac1_opts->c_srate = c_srate;
++	uac1_opts->c_ssize = c_ssize;
++	uac1_opts->req_number = UAC1_DEF_REQ_NUM;
++	uac1_opts->req_number = req_num;
++	uac1_opts->req_buf_size = req_buf_size;
++
++#else /* CONFIG_GADGET_UAC1_LEGACY */
++	uac1_opts = container_of(fi_uac1, struct f_uac1_legacy_opts, func_inst);
++	uac1_opts->fn_play = fn_play;
++	uac1_opts->fn_cap = fn_cap;
++	uac1_opts->fn_cntl = fn_cntl;
++	uac1_opts->req_buf_size = req_buf_size;
++	uac1_opts->req_count = req_count;
++	uac1_opts->audio_buf_size = audio_buf_size;
++#endif /* CONFIG_GADGET_UAC1_LEGACY */
++#endif
++
++	status = usb_string_ids_tab(cdev, strings_dev);
++	if (status < 0)
++		goto fail;
++	device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
++	device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
++
++	INFO(cdev, "%s, version: %s\n", DRIVER_DESC, DRIVER_VERSION);
++	return 0;
++
++fail:
++#ifndef CONFIG_GADGET_UAC1
++	usb_put_function_instance(fi_uac2);
++#else
++	usb_put_function_instance(fi_uac1);
++#endif
++	return status;
++}
++
++static int audio_unbind(struct usb_composite_dev *cdev)
++{
++#ifdef CONFIG_GADGET_UAC1
++	if (!IS_ERR_OR_NULL(f_uac1))
++		usb_put_function(f_uac1);
++	if (!IS_ERR_OR_NULL(fi_uac1))
++		usb_put_function_instance(fi_uac1);
++#else
++	if (!IS_ERR_OR_NULL(f_uac2))
++		usb_put_function(f_uac2);
++	if (!IS_ERR_OR_NULL(fi_uac2))
++		usb_put_function_instance(fi_uac2);
++#endif
++
++	return 0;
++}
++
++
+diff --git a/drivers/usb/gadget/legacy/gmidi.c b/drivers/usb/gadget/legacy/gmidi.c
+index 3d696b8..b7c631d 100644
+--- a/drivers/usb/gadget/legacy/gmidi.c
++++ b/drivers/usb/gadget/legacy/gmidi.c
+@@ -37,6 +37,7 @@
+ 
+ #include "gadget_chips.h"
+ 
++#define USBF_MIDI_INCLUDED
+ #include "f_midi.c"
+ 
+ /*-------------------------------------------------------------------------*/
+@@ -115,6 +116,9 @@ static struct usb_gadget_strings *dev_strings[] = {
+ 	NULL,
+ };
+ 
++static struct usb_function_instance *fi_midi;
++static struct usb_function *f_midi;
++
+ static int __exit midi_unbind(struct usb_composite_dev *dev)
+ {
+ 	return 0;
+diff --git a/drivers/usb/gadget/legacy/multi.c b/drivers/usb/gadget/legacy/multi.c
+index 39d27bb..74b258e 100644
+--- a/drivers/usb/gadget/legacy/multi.c
++++ b/drivers/usb/gadget/legacy/multi.c
+@@ -151,7 +151,9 @@ static struct usb_function *f_msg_rndis;
+ 
+ static __init int rndis_do_config(struct usb_configuration *c)
+ {
++#if 0
+ 	struct fsg_opts *fsg_opts;
++#endif
+ 	int ret;
+ 
+ 	if (gadget_is_otg(c->cdev->gadget)) {
+@@ -177,6 +179,7 @@ static __init int rndis_do_config(struct usb_configuration *c)
+ 	if (ret)
+ 		goto err_conf;
+ 
++#if 0
+ 	f_msg_rndis = usb_get_function(fi_msg);
+ 	if (IS_ERR(f_msg_rndis)) {
+ 		ret = PTR_ERR(f_msg_rndis);
+@@ -192,11 +195,14 @@ static __init int rndis_do_config(struct usb_configuration *c)
+ 	if (ret)
+ 		goto err_run;
+ 
++#endif
+ 	return 0;
++#if 0
+ err_run:
+ 	usb_put_function(f_msg_rndis);
+ err_fsg:
+ 	usb_remove_function(c, f_acm_rndis);
++#endif
+ err_conf:
+ 	usb_put_function(f_acm_rndis);
+ err_func_acm:
+@@ -265,7 +271,7 @@ static __init int cdc_do_config(struct usb_configuration *c)
+ 	ret = usb_add_function(c, f_acm_multi);
+ 	if (ret)
+ 		goto err_conf;
+-
++#if 0
+ 	f_msg_multi = usb_get_function(fi_msg);
+ 	if (IS_ERR(f_msg_multi)) {
+ 		ret = PTR_ERR(f_msg_multi);
+@@ -280,6 +286,7 @@ static __init int cdc_do_config(struct usb_configuration *c)
+ 	ret = usb_add_function(c, f_msg_multi);
+ 	if (ret)
+ 		goto err_run;
++#endif
+ 
+ 	return 0;
+ err_run:
+@@ -330,8 +337,10 @@ static int __ref multi_bind(struct usb_composite_dev *cdev)
+ #ifdef USB_ETH_RNDIS
+ 	struct f_rndis_opts *rndis_opts;
+ #endif
++#if 0
+ 	struct fsg_opts *fsg_opts;
+ 	struct fsg_config config;
++#endif
+ 	int status;
+ 
+ 	if (!can_support_ecm(cdev->gadget)) {
+@@ -392,7 +401,7 @@ static int __ref multi_bind(struct usb_composite_dev *cdev)
+ 		status = PTR_ERR(fi_acm);
+ 		goto fail0;
+ 	}
+-
++#if 0
+ 	/* set up mass storage function */
+ 	fi_msg = usb_get_function_instance("mass_storage");
+ 	if (IS_ERR(fi_msg)) {
+@@ -422,7 +431,7 @@ static int __ref multi_bind(struct usb_composite_dev *cdev)
+ 
+ 	fsg_common_set_inquiry_string(fsg_opts->common, config.vendor_name,
+ 				      config.product_name);
+-
++#endif
+ 	/* allocate string IDs */
+ 	status = usb_string_ids_tab(cdev, strings_dev);
+ 	if (unlikely(status < 0))
+@@ -446,6 +455,7 @@ static int __ref multi_bind(struct usb_composite_dev *cdev)
+ 
+ 	/* error recovery */
+ fail_string_ids:
++#if 0
+ 	fsg_common_remove_luns(fsg_opts->common);
+ fail_set_cdev:
+ 	fsg_common_free_luns(fsg_opts->common);
+@@ -455,6 +465,7 @@ fail2:
+ 	usb_put_function_instance(fi_msg);
+ fail1:
+ 	usb_put_function_instance(fi_acm);
++#endif
+ fail0:
+ #ifdef USB_ETH_RNDIS
+ 	usb_put_function_instance(fi_rndis);
+@@ -504,7 +515,7 @@ static __refdata struct usb_composite_driver multi_driver = {
+ 	.max_speed	= USB_SPEED_HIGH,
+ 	.bind		= multi_bind,
+ 	.unbind		= __exit_p(multi_unbind),
+-	.needs_serial	= 1,
++	.needs_serial	= 0,
+ };
+ 
+ module_usb_composite_driver(multi_driver);
+diff --git a/drivers/usb/gadget/legacy/webcam.c b/drivers/usb/gadget/legacy/webcam.c
+index 04a3da2..e1fe6b2 100644
+--- a/drivers/usb/gadget/legacy/webcam.c
++++ b/drivers/usb/gadget/legacy/webcam.c
+@@ -26,11 +26,11 @@ static unsigned int streaming_interval = 1;
+ module_param(streaming_interval, uint, S_IRUGO|S_IWUSR);
+ MODULE_PARM_DESC(streaming_interval, "1 - 16");
+ 
+-static unsigned int streaming_maxpacket = 1024;
++static unsigned int streaming_maxpacket = 3072;
+ module_param(streaming_maxpacket, uint, S_IRUGO|S_IWUSR);
+ MODULE_PARM_DESC(streaming_maxpacket, "1 - 1023 (FS), 1 - 3072 (hs/ss)");
+ 
+-static unsigned int streaming_maxburst;
++static unsigned int streaming_maxburst = 14;
+ module_param(streaming_maxburst, uint, S_IRUGO|S_IWUSR);
+ MODULE_PARM_DESC(streaming_maxburst, "0 - 15 (ss only)");
+ 
+@@ -49,6 +49,17 @@ static char webcam_vendor_label[] = "Linux Foundation";
+ static char webcam_product_label[] = "Webcam gadget";
+ static char webcam_config_label[] = "Video";
+ 
++/* GUID of the UVC H.264 extension unit:
++{A29E7641-DE04-47E3-8B2B-F4341AFF003B} */
++#define GUID_UVCX_H264_XU {0x41, 0x76, 0x9E, 0xA2, 0x04, 0xDE, 0xE3, 0x47, \
++				0x8B, 0x2B, 0xF4, 0x34, 0x1A, 0xFF, 0x00, 0x3B}
++
++#define UVC_GUID_HI_CAMERA {0x91, 0x72, 0x1e, 0x9a, 0x43, 0x68, 0x83, 0x46, \
++				0x6d, 0x92, 0x39, 0xbc, 0x79, 0x06, 0xee, 0x49}
++
++#define UVC_GUID_FORMAT_H264 {0x48, 0x32, 0x36, 0x34, 0x00, 0x00, 0x10, 0x00, \
++				0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
++
+ /* string IDs are assigned dynamically */
+ 
+ #define STRING_DESCRIPTION_IDX		USB_GADGET_FIRST_AVAIL_IDX
+@@ -97,7 +108,7 @@ static const struct UVC_HEADER_DESCRIPTOR(1) uvc_control_header = {
+ 	.bLength		= UVC_DT_HEADER_SIZE(1),
+ 	.bDescriptorType	= USB_DT_CS_INTERFACE,
+ 	.bDescriptorSubType	= UVC_VC_HEADER,
+-	.bcdUVC			= cpu_to_le16(0x0100),
++	.bcdUVC			= cpu_to_le16(0x0110),
+ 	.wTotalLength		= 0, /* dynamic */
+ 	.dwClockFrequency	= cpu_to_le32(48000000),
+ 	.bInCollection		= 0, /* dynamic */
+@@ -108,7 +119,7 @@ static const struct uvc_camera_terminal_descriptor uvc_camera_terminal = {
+ 	.bLength		= UVC_DT_CAMERA_TERMINAL_SIZE(3),
+ 	.bDescriptorType	= USB_DT_CS_INTERFACE,
+ 	.bDescriptorSubType	= UVC_VC_INPUT_TERMINAL,
+-	.bTerminalID		= 1,
++	.bTerminalID		= 2,
+ 	.wTerminalType		= cpu_to_le16(0x0201),
+ 	.bAssocTerminal		= 0,
+ 	.iTerminal		= 0,
+@@ -116,24 +127,56 @@ static const struct uvc_camera_terminal_descriptor uvc_camera_terminal = {
+ 	.wObjectiveFocalLengthMax	= cpu_to_le16(0),
+ 	.wOcularFocalLength		= cpu_to_le16(0),
+ 	.bControlSize		= 3,
+-	.bmControls[0]		= 2,
+-	.bmControls[1]		= 0,
++	.bmControls[0]		= 0x1a,
++	.bmControls[1]		= 0x00,
+ 	.bmControls[2]		= 0,
+ };
+ 
+ static const struct uvc_processing_unit_descriptor uvc_processing = {
+-	.bLength		= UVC_DT_PROCESSING_UNIT_SIZE(2),
++	.bLength		= sizeof(uvc_processing),
+ 	.bDescriptorType	= USB_DT_CS_INTERFACE,
+ 	.bDescriptorSubType	= UVC_VC_PROCESSING_UNIT,
+-	.bUnitID		= 2,
++	.bUnitID		= 5,
+ 	.bSourceID		= 1,
+ 	.wMaxMultiplier		= cpu_to_le16(16*1024),
+ 	.bControlSize		= 2,
+-	.bmControls[0]		= 1,
+-	.bmControls[1]		= 0,
++	.bmControls[0]		= 0xff,
++	.bmControls[1]		= 0xff,
+ 	.iProcessing		= 0,
+ };
+ 
++DECLARE_UVC_EXTENSION_UNIT_DESCRIPTOR(1, 2);
++
++static const struct UVC_EXTENSION_UNIT_DESCRIPTOR(1, 2) uvc_xu_h264_desc = {
++	.bLength		= UVC_DT_EXTENSION_UNIT_SIZE(1, 2),
++	.bDescriptorType	= USB_DT_CS_INTERFACE,
++	.bDescriptorSubType	= UVC_VC_EXTENSION_UNIT,
++	.bUnitID		= 10,
++	.guidExtensionCode	= GUID_UVCX_H264_XU,
++	.bNumControls		= 15,
++	.bNrInPins		= 1,
++	.baSourceID[0]		= 2,
++	.bControlSize		= 2,
++	.bmControls[0]		= 0xff,
++	.bmControls[1]		= 0xff,
++	.iExtension		= 0,
++};
++
++static const struct UVC_EXTENSION_UNIT_DESCRIPTOR(1, 2) uvc_xu_hicamera_desc = {
++	.bLength		= UVC_DT_EXTENSION_UNIT_SIZE(1, 2),
++	.bDescriptorType	= USB_DT_CS_INTERFACE,
++	.bDescriptorSubType	= UVC_VC_EXTENSION_UNIT,
++	.bUnitID		= 0x11,
++	.guidExtensionCode	= UVC_GUID_HI_CAMERA,
++	.bNumControls		= 15,
++	.bNrInPins		= 1,
++	.baSourceID[0]		= 10,
++	.bControlSize		= 2,
++	.bmControls[0]		= 0xff,
++	.bmControls[1]		= 0xff,
++	.iExtension		= 0,
++};
++
+ static const struct uvc_output_terminal_descriptor uvc_output_terminal = {
+ 	.bLength		= UVC_DT_OUTPUT_TERMINAL_SIZE,
+ 	.bDescriptorType	= USB_DT_CS_INTERFACE,
+@@ -141,7 +184,7 @@ static const struct uvc_output_terminal_descriptor uvc_output_terminal = {
+ 	.bTerminalID		= 3,
+ 	.wTerminalType		= cpu_to_le16(0x0101),
+ 	.bAssocTerminal		= 0,
+-	.bSourceID		= 2,
++	.bSourceID		= 0x11,
+ 	.iTerminal		= 0,
+ };
+ 
+@@ -169,7 +212,7 @@ static const struct uvc_format_uncompressed uvc_format_yuv = {
+ 	.bDescriptorType	= USB_DT_CS_INTERFACE,
+ 	.bDescriptorSubType	= UVC_VS_FORMAT_UNCOMPRESSED,
+ 	.bFormatIndex		= 1,
+-	.bNumFrameDescriptors	= 2,
++	.bNumFrameDescriptors	= 5,
+ 	.guidFormat		=
+ 		{ 'Y',  'U',  'Y',  '2', 0x00, 0x00, 0x10, 0x00,
+ 		 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71},
+@@ -183,39 +226,100 @@ static const struct uvc_format_uncompressed uvc_format_yuv = {
+ 
+ DECLARE_UVC_FRAME_UNCOMPRESSED(1);
+ DECLARE_UVC_FRAME_UNCOMPRESSED(3);
+-
+-static const struct UVC_FRAME_UNCOMPRESSED(3) uvc_frame_yuv_360p = {
+-	.bLength		= UVC_DT_FRAME_UNCOMPRESSED_SIZE(3),
++static const struct UVC_FRAME_UNCOMPRESSED(1) uvc_frame_yuv_144p = {
++	.bLength		= UVC_DT_FRAME_UNCOMPRESSED_SIZE(1),
+ 	.bDescriptorType	= USB_DT_CS_INTERFACE,
+ 	.bDescriptorSubType	= UVC_VS_FRAME_UNCOMPRESSED,
+ 	.bFrameIndex		= 1,
+ 	.bmCapabilities		= 0,
++	.wWidth			= cpu_to_le16(176),
++	.wHeight		= cpu_to_le16(144),
++	.dwMinBitRate		= cpu_to_le32(56088),
++	.dwMaxBitRate		= cpu_to_le32(56088),
++	.dwMaxVideoFrameBufferSize	= cpu_to_le32(460800),
++	.dwDefaultFrameInterval	= cpu_to_le32(333333),
++	.bFrameIntervalType	= 1,
++	.dwFrameInterval[0]	= cpu_to_le32(333333),
++};
++
++static const struct UVC_FRAME_UNCOMPRESSED(1) uvc_frame_yuv_240p = {
++	.bLength		= UVC_DT_FRAME_UNCOMPRESSED_SIZE(1),
++	.bDescriptorType	= USB_DT_CS_INTERFACE,
++	.bDescriptorSubType	= UVC_VS_FRAME_UNCOMPRESSED,
++	.bFrameIndex		= 2,
++	.bmCapabilities		= 0,
++	.wWidth			= cpu_to_le16(320),
++	.wHeight		= cpu_to_le16(240),
++	.dwMinBitRate		= cpu_to_le32(55296000),
++	.dwMaxBitRate		= cpu_to_le32(55296000),
++	.dwMaxVideoFrameBufferSize	= cpu_to_le32(460800),
++	.dwDefaultFrameInterval	= cpu_to_le32(333333),
++	.bFrameIntervalType	= 1,
++	.dwFrameInterval[0]	= cpu_to_le32(333333),
++};
++
++static const struct UVC_FRAME_UNCOMPRESSED(1) uvc_frame_yuv_288p = {
++	.bLength		= UVC_DT_FRAME_UNCOMPRESSED_SIZE(1),
++	.bDescriptorType	= USB_DT_CS_INTERFACE,
++	.bDescriptorSubType	= UVC_VS_FRAME_UNCOMPRESSED,
++	.bFrameIndex		= 3,
++	.bmCapabilities		= 0,
++	.wWidth			= cpu_to_le16(352),
++	.wHeight		= cpu_to_le16(288),
++	.dwMinBitRate		= cpu_to_le32(55296000),
++	.dwMaxBitRate		= cpu_to_le32(55296000),
++	.dwMaxVideoFrameBufferSize	= cpu_to_le32(460800),
++	.dwDefaultFrameInterval	= cpu_to_le32(333333),
++	.bFrameIntervalType	= 1,
++	.dwFrameInterval[0]	= cpu_to_le32(333333),
++};
++
++static const struct UVC_FRAME_UNCOMPRESSED(1) uvc_frame_yuv_480p = {
++	.bLength		= UVC_DT_FRAME_UNCOMPRESSED_SIZE(1),
++	.bDescriptorType	= USB_DT_CS_INTERFACE,
++	.bDescriptorSubType	= UVC_VS_FRAME_UNCOMPRESSED,
++	.bFrameIndex		= 4,
++	.bmCapabilities		= 0,
+ 	.wWidth			= cpu_to_le16(640),
+-	.wHeight		= cpu_to_le16(360),
+-	.dwMinBitRate		= cpu_to_le32(18432000),
++	.wHeight		= cpu_to_le16(480),
++	.dwMinBitRate		= cpu_to_le32(55296000),
+ 	.dwMaxBitRate		= cpu_to_le32(55296000),
+ 	.dwMaxVideoFrameBufferSize	= cpu_to_le32(460800),
+-	.dwDefaultFrameInterval	= cpu_to_le32(666666),
+-	.bFrameIntervalType	= 3,
+-	.dwFrameInterval[0]	= cpu_to_le32(666666),
+-	.dwFrameInterval[1]	= cpu_to_le32(1000000),
+-	.dwFrameInterval[2]	= cpu_to_le32(5000000),
++	.dwDefaultFrameInterval	= cpu_to_le32(333333),
++	.bFrameIntervalType	= 1,
++	.dwFrameInterval[0]	= cpu_to_le32(333333),
+ };
+ 
+ static const struct UVC_FRAME_UNCOMPRESSED(1) uvc_frame_yuv_720p = {
+ 	.bLength		= UVC_DT_FRAME_UNCOMPRESSED_SIZE(1),
+ 	.bDescriptorType	= USB_DT_CS_INTERFACE,
+ 	.bDescriptorSubType	= UVC_VS_FRAME_UNCOMPRESSED,
+-	.bFrameIndex		= 2,
++	.bFrameIndex		= 5,
+ 	.bmCapabilities		= 0,
+ 	.wWidth			= cpu_to_le16(1280),
+ 	.wHeight		= cpu_to_le16(720),
+ 	.dwMinBitRate		= cpu_to_le32(29491200),
+ 	.dwMaxBitRate		= cpu_to_le32(29491200),
+ 	.dwMaxVideoFrameBufferSize	= cpu_to_le32(1843200),
+-	.dwDefaultFrameInterval	= cpu_to_le32(5000000),
++	.dwDefaultFrameInterval	= cpu_to_le32(333333),
++	.bFrameIntervalType	= 1,
++	.dwFrameInterval[0]	= cpu_to_le32(333333),
++};
++
++static const struct UVC_FRAME_UNCOMPRESSED(1) uvc_frame_yuv_1080p = {
++	.bLength		= UVC_DT_FRAME_UNCOMPRESSED_SIZE(1),
++	.bDescriptorType	= USB_DT_CS_INTERFACE,
++	.bDescriptorSubType	= UVC_VS_FRAME_UNCOMPRESSED,
++	.bFrameIndex		= 6,
++	.bmCapabilities		= 0,
++	.wWidth			= cpu_to_le16(1920),
++	.wHeight		= cpu_to_le16(1080),
++	.dwMinBitRate		= cpu_to_le32(29491200),
++	.dwMaxBitRate		= cpu_to_le32(29491200),
++	.dwMaxVideoFrameBufferSize	= cpu_to_le32(1843200),
++	.dwDefaultFrameInterval	= cpu_to_le32(333333),
+ 	.bFrameIntervalType	= 1,
+-	.dwFrameInterval[0]	= cpu_to_le32(5000000),
++	.dwFrameInterval[0]	= cpu_to_le32(333333),
+ };
+ 
+ static const struct uvc_format_mjpeg uvc_format_mjpg = {
+@@ -223,7 +327,7 @@ static const struct uvc_format_mjpeg uvc_format_mjpg = {
+ 	.bDescriptorType	= USB_DT_CS_INTERFACE,
+ 	.bDescriptorSubType	= UVC_VS_FORMAT_MJPEG,
+ 	.bFormatIndex		= 2,
+-	.bNumFrameDescriptors	= 2,
++	.bNumFrameDescriptors	= 6,
+ 	.bmFlags		= 0,
+ 	.bDefaultFrameIndex	= 1,
+ 	.bAspectRatioX		= 0,
+@@ -235,38 +339,230 @@ static const struct uvc_format_mjpeg uvc_format_mjpg = {
+ DECLARE_UVC_FRAME_MJPEG(1);
+ DECLARE_UVC_FRAME_MJPEG(3);
+ 
+-static const struct UVC_FRAME_MJPEG(3) uvc_frame_mjpg_360p = {
+-	.bLength		= UVC_DT_FRAME_MJPEG_SIZE(3),
++static const struct UVC_FRAME_MJPEG(1) uvc_frame_mjpg_144p = {
++	.bLength		= UVC_DT_FRAME_MJPEG_SIZE(1),
+ 	.bDescriptorType	= USB_DT_CS_INTERFACE,
+ 	.bDescriptorSubType	= UVC_VS_FRAME_MJPEG,
+ 	.bFrameIndex		= 1,
+ 	.bmCapabilities		= 0,
++	.wWidth			= cpu_to_le16(176),
++	.wHeight		= cpu_to_le16(144),
++	.dwMinBitRate		= cpu_to_le32(55296000),
++	.dwMaxBitRate		= cpu_to_le32(55296000),
++	.dwMaxVideoFrameBufferSize	= cpu_to_le32(460800),
++	.dwDefaultFrameInterval	= cpu_to_le32(333333),
++	.bFrameIntervalType	= 1,
++	.dwFrameInterval[0]	= cpu_to_le32(333333),
++};
++
++static const struct UVC_FRAME_MJPEG(1) uvc_frame_mjpg_240p = {
++	.bLength		= UVC_DT_FRAME_MJPEG_SIZE(1),
++	.bDescriptorType	= USB_DT_CS_INTERFACE,
++	.bDescriptorSubType	= UVC_VS_FRAME_MJPEG,
++	.bFrameIndex		= 2,
++	.bmCapabilities		= 0,
++	.wWidth			= cpu_to_le16(320),
++	.wHeight		= cpu_to_le16(240),
++	.dwMinBitRate		= cpu_to_le32(55296000),
++	.dwMaxBitRate		= cpu_to_le32(55296000),
++	.dwMaxVideoFrameBufferSize	= cpu_to_le32(460800),
++	.dwDefaultFrameInterval	= cpu_to_le32(333333),
++	.bFrameIntervalType	= 1,
++	.dwFrameInterval[0]	= cpu_to_le32(333333),
++};
++
++static const struct UVC_FRAME_MJPEG(1) uvc_frame_mjpg_288p = {
++	.bLength		= UVC_DT_FRAME_MJPEG_SIZE(1),
++	.bDescriptorType	= USB_DT_CS_INTERFACE,
++	.bDescriptorSubType	= UVC_VS_FRAME_MJPEG,
++	.bFrameIndex		= 3,
++	.bmCapabilities		= 0,
++	.wWidth			= cpu_to_le16(352),
++	.wHeight		= cpu_to_le16(288),
++	.dwMinBitRate		= cpu_to_le32(55296000),
++	.dwMaxBitRate		= cpu_to_le32(55296000),
++	.dwMaxVideoFrameBufferSize	= cpu_to_le32(460800),
++	.dwDefaultFrameInterval	= cpu_to_le32(333333),
++	.bFrameIntervalType	= 1,
++	.dwFrameInterval[0]	= cpu_to_le32(333333),
++};
++
++
++static const struct UVC_FRAME_MJPEG(1) uvc_frame_mjpg_480p = {
++	.bLength		= UVC_DT_FRAME_MJPEG_SIZE(1),
++	.bDescriptorType	= USB_DT_CS_INTERFACE,
++	.bDescriptorSubType	= UVC_VS_FRAME_MJPEG,
++	.bFrameIndex		= 4,
++	.bmCapabilities		= 0,
+ 	.wWidth			= cpu_to_le16(640),
+-	.wHeight		= cpu_to_le16(360),
+-	.dwMinBitRate		= cpu_to_le32(18432000),
++	.wHeight		= cpu_to_le16(480),
++	.dwMinBitRate		= cpu_to_le32(55296000),
+ 	.dwMaxBitRate		= cpu_to_le32(55296000),
+ 	.dwMaxVideoFrameBufferSize	= cpu_to_le32(460800),
+-	.dwDefaultFrameInterval	= cpu_to_le32(666666),
+-	.bFrameIntervalType	= 3,
+-	.dwFrameInterval[0]	= cpu_to_le32(666666),
+-	.dwFrameInterval[1]	= cpu_to_le32(1000000),
+-	.dwFrameInterval[2]	= cpu_to_le32(5000000),
++	.dwDefaultFrameInterval	= cpu_to_le32(333333),
++	.bFrameIntervalType	= 1,
++	.dwFrameInterval[0]	= cpu_to_le32(333333),
+ };
+ 
+ static const struct UVC_FRAME_MJPEG(1) uvc_frame_mjpg_720p = {
+ 	.bLength		= UVC_DT_FRAME_MJPEG_SIZE(1),
+ 	.bDescriptorType	= USB_DT_CS_INTERFACE,
+ 	.bDescriptorSubType	= UVC_VS_FRAME_MJPEG,
+-	.bFrameIndex		= 2,
++	.bFrameIndex		= 5,
+ 	.bmCapabilities		= 0,
+ 	.wWidth			= cpu_to_le16(1280),
+ 	.wHeight		= cpu_to_le16(720),
+ 	.dwMinBitRate		= cpu_to_le32(29491200),
+ 	.dwMaxBitRate		= cpu_to_le32(29491200),
+ 	.dwMaxVideoFrameBufferSize	= cpu_to_le32(1843200),
+-	.dwDefaultFrameInterval	= cpu_to_le32(5000000),
++	.dwDefaultFrameInterval	= cpu_to_le32(333333),
++	.bFrameIntervalType	= 1,
++	.dwFrameInterval[0]	= cpu_to_le32(333333),
++};
++
++static const struct UVC_FRAME_MJPEG(1) uvc_frame_mjpg_1080p = {
++	.bLength		= UVC_DT_FRAME_MJPEG_SIZE(1),
++	.bDescriptorType	= USB_DT_CS_INTERFACE,
++	.bDescriptorSubType	= UVC_VS_FRAME_MJPEG,
++	.bFrameIndex		= 6,
++	.bmCapabilities		= 0,
++	.wWidth			= cpu_to_le16(1920),
++	.wHeight		= cpu_to_le16(1080),
++	.dwMinBitRate		= cpu_to_le32(29491200),
++	.dwMaxBitRate		= cpu_to_le32(29491200),
++	.dwMaxVideoFrameBufferSize	= cpu_to_le32(1843200),
++	.dwDefaultFrameInterval	= cpu_to_le32(333333),
++	.bFrameIntervalType	= 1,
++	.dwFrameInterval[0]	= cpu_to_le32(333333),
++};
++
++static const struct uvc_format_h264 uvc_format_h264 = {
++	.bLength		= UVC_DT_FORMAT_H264_SIZE,
++	.bDescriptorType	= USB_DT_CS_INTERFACE,
++	.bDescriptorSubType	= UVC_VS_FORMAT_H264,
++	.bFormatIndex		= 3,
++	.bNumFrameDescriptors	= 6,
++	.bmFlags		= 0,
++	.bDefaultFrameIndex	= 1,
++	.bAspectRatioX		= 0,
++	.bAspectRatioY		= 0,
++	.bmInterfaceFlags	= 0,
++	.bCopyProtect		= 0,
++};
++
++static const struct uvc_format_h264_base uvc_format_h264_base = {
++	.bLength		= sizeof(uvc_format_h264_base),
++	.bDescriptorType	= USB_DT_CS_INTERFACE,
++	.bDescriptorSubType	= UVC_VS_FORMAT_FRAME_BASED,
++	.bFormatIndex		= 3,
++	.bNumFrameDescriptors	= 6,
++	.guidFormat	= UVC_GUID_FORMAT_H264,
++	.bBitsPerPixel	= 16,
++	.bDefaultFrameIndex	= 1,
++	.bAspectRatioX		= 0,
++	.bAspectRatioY		= 0,
++	.bmInterfaceFlags	= 0,
++	.bCopyProtect		= 0,
++	.bVariableSize	= 1,
++};
++
++DECLARE_UVC_FRAME_H264_BASE(1);
++DECLARE_UVC_FRAME_H264_BASE(3);
++
++static const struct UVC_FRAME_H264_BASE(1) uvc_frame_h264_720p = {
++	.bLength		= UVC_DT_FRAME_MJPEG_SIZE(1),
++	.bDescriptorType	= USB_DT_CS_INTERFACE,
++	.bDescriptorSubType	= UVC_VS_FRAME_FRAME_BASED,
++	.bFrameIndex		= 5,
++	.bmCapabilities		= 0,
++	.wWidth			= cpu_to_le16(1280),
++	.wHeight		= cpu_to_le16(720),
++	.dwMinBitRate		= cpu_to_le32(55296000),
++	.dwMaxBitRate		= cpu_to_le32(55296000),
++	.dwDefaultFrameInterval	= cpu_to_le32(333333),
+ 	.bFrameIntervalType	= 1,
+-	.dwFrameInterval[0]	= cpu_to_le32(5000000),
++	.dwBytesPerLine	= 0,
++	.dwFrameInterval[0]	= cpu_to_le32(333333),
++};
++
++static const struct UVC_FRAME_H264_BASE(1) uvc_frame_h264_1080p = {
++	.bLength		= UVC_DT_FRAME_MJPEG_SIZE(1),
++	.bDescriptorType	= USB_DT_CS_INTERFACE,
++	.bDescriptorSubType	= UVC_VS_FRAME_FRAME_BASED,
++	.bFrameIndex		= 6,
++	.bmCapabilities		= 0,
++	.wWidth			= cpu_to_le16(1920),
++	.wHeight		= cpu_to_le16(1080),
++	.dwMinBitRate		= cpu_to_le32(29491200),
++	.dwMaxBitRate		= cpu_to_le32(29491200),
++	.dwDefaultFrameInterval	= cpu_to_le32(333333),
++	.bFrameIntervalType	= 1,
++	.dwBytesPerLine	= 0,
++	.dwFrameInterval[0]	= cpu_to_le32(333333),
++};
++
++static const struct UVC_FRAME_H264_BASE(1) uvc_frame_h264_480p = {
++	.bLength		= UVC_DT_FRAME_MJPEG_SIZE(1),
++	.bDescriptorType	= USB_DT_CS_INTERFACE,
++	.bDescriptorSubType	= UVC_VS_FRAME_FRAME_BASED,
++	.bFrameIndex		= 4,
++	.bmCapabilities		= 0,
++	.wWidth			= cpu_to_le16(640),
++	.wHeight		= cpu_to_le16(480),
++	.dwMinBitRate		= cpu_to_le32(29491200),
++	.dwMaxBitRate		= cpu_to_le32(29491200),
++	.dwDefaultFrameInterval	= cpu_to_le32(333333),
++	.bFrameIntervalType	= 1,
++	.dwBytesPerLine	= 0,
++	.dwFrameInterval[0]	= cpu_to_le32(333333),
++};
++
++static const struct UVC_FRAME_H264_BASE(1) uvc_frame_h264_144p = {
++	.bLength		= UVC_DT_FRAME_MJPEG_SIZE(1),
++	.bDescriptorType	= USB_DT_CS_INTERFACE,
++	.bDescriptorSubType	= UVC_VS_FRAME_FRAME_BASED,
++	.bFrameIndex		= 1,
++	.bmCapabilities		= 0,
++	.wWidth			= cpu_to_le16(176),
++	.wHeight		= cpu_to_le16(144),
++	.dwMinBitRate		= cpu_to_le32(29491200),
++	.dwMaxBitRate		= cpu_to_le32(29491200),
++	.dwDefaultFrameInterval	= cpu_to_le32(333333),
++	.bFrameIntervalType	= 1,
++	.dwBytesPerLine	= 0,
++	.dwFrameInterval[0]	= cpu_to_le32(333333),
++};
++
++static const struct UVC_FRAME_H264_BASE(1) uvc_frame_h264_240p = {
++	.bLength		= UVC_DT_FRAME_MJPEG_SIZE(1),
++	.bDescriptorType	= USB_DT_CS_INTERFACE,
++	.bDescriptorSubType	= UVC_VS_FRAME_FRAME_BASED,
++	.bFrameIndex		= 2,
++	.bmCapabilities		= 0,
++	.wWidth			= cpu_to_le16(320),
++	.wHeight		= cpu_to_le16(240),
++	.dwMinBitRate		= cpu_to_le32(29491200),
++	.dwMaxBitRate		= cpu_to_le32(29491200),
++	.dwDefaultFrameInterval	= cpu_to_le32(333333),
++	.bFrameIntervalType	= 1,
++	.dwBytesPerLine	= 0,
++	.dwFrameInterval[0]	= cpu_to_le32(333333),
++};
++
++static const struct UVC_FRAME_H264_BASE(1) uvc_frame_h264_288p = {
++	.bLength		= UVC_DT_FRAME_MJPEG_SIZE(1),
++	.bDescriptorType	= USB_DT_CS_INTERFACE,
++	.bDescriptorSubType	= UVC_VS_FRAME_FRAME_BASED,
++	.bFrameIndex		= 3,
++	.bmCapabilities		= 0,
++	.wWidth			= cpu_to_le16(352),
++	.wHeight		= cpu_to_le16(288),
++	.dwMinBitRate		= cpu_to_le32(29491200),
++	.dwMaxBitRate		= cpu_to_le32(29491200),
++	.dwDefaultFrameInterval	= cpu_to_le32(333333),
++	.bFrameIntervalType	= 1,
++	.dwBytesPerLine	= 0,
++	.dwFrameInterval[0]	= cpu_to_le32(333333),
+ };
+ 
+ static const struct uvc_color_matching_descriptor uvc_color_matching = {
+@@ -282,6 +578,8 @@ static const struct uvc_descriptor_header * const uvc_fs_control_cls[] = {
+ 	(const struct uvc_descriptor_header *) &uvc_control_header,
+ 	(const struct uvc_descriptor_header *) &uvc_camera_terminal,
+ 	(const struct uvc_descriptor_header *) &uvc_processing,
++	(const struct uvc_descriptor_header *) &uvc_xu_h264_desc,
++	(const struct uvc_descriptor_header *) &uvc_xu_hicamera_desc,
+ 	(const struct uvc_descriptor_header *) &uvc_output_terminal,
+ 	NULL,
+ };
+@@ -290,6 +588,8 @@ static const struct uvc_descriptor_header * const uvc_ss_control_cls[] = {
+ 	(const struct uvc_descriptor_header *) &uvc_control_header,
+ 	(const struct uvc_descriptor_header *) &uvc_camera_terminal,
+ 	(const struct uvc_descriptor_header *) &uvc_processing,
++	(const struct uvc_descriptor_header *) &uvc_xu_h264_desc,
++	(const struct uvc_descriptor_header *) &uvc_xu_hicamera_desc,
+ 	(const struct uvc_descriptor_header *) &uvc_output_terminal,
+ 	NULL,
+ };
+@@ -297,11 +597,25 @@ static const struct uvc_descriptor_header * const uvc_ss_control_cls[] = {
+ static const struct uvc_descriptor_header * const uvc_fs_streaming_cls[] = {
+ 	(const struct uvc_descriptor_header *) &uvc_input_header,
+ 	(const struct uvc_descriptor_header *) &uvc_format_yuv,
+-	(const struct uvc_descriptor_header *) &uvc_frame_yuv_360p,
++	(const struct uvc_descriptor_header *) &uvc_frame_yuv_144p,
++	(const struct uvc_descriptor_header *) &uvc_frame_yuv_240p,
++	(const struct uvc_descriptor_header *) &uvc_frame_yuv_288p,
++	(const struct uvc_descriptor_header *) &uvc_frame_yuv_480p,
+ 	(const struct uvc_descriptor_header *) &uvc_frame_yuv_720p,
+ 	(const struct uvc_descriptor_header *) &uvc_format_mjpg,
+-	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p,
++	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_144p,
++	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_240p,
++	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_288p,
++	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_480p,
+ 	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p,
++	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_1080p,
++	(const struct uvc_descriptor_header *) &uvc_format_h264_base,
++	(const struct uvc_descriptor_header *) &uvc_frame_h264_720p,
++	(const struct uvc_descriptor_header *) &uvc_frame_h264_1080p,
++	(const struct uvc_descriptor_header *) &uvc_frame_h264_480p,
++	(const struct uvc_descriptor_header *) &uvc_frame_h264_144p,
++	(const struct uvc_descriptor_header *) &uvc_frame_h264_240p,
++	(const struct uvc_descriptor_header *) &uvc_frame_h264_288p,
+ 	(const struct uvc_descriptor_header *) &uvc_color_matching,
+ 	NULL,
+ };
+@@ -309,11 +623,25 @@ static const struct uvc_descriptor_header * const uvc_fs_streaming_cls[] = {
+ static const struct uvc_descriptor_header * const uvc_hs_streaming_cls[] = {
+ 	(const struct uvc_descriptor_header *) &uvc_input_header,
+ 	(const struct uvc_descriptor_header *) &uvc_format_yuv,
+-	(const struct uvc_descriptor_header *) &uvc_frame_yuv_360p,
++	(const struct uvc_descriptor_header *) &uvc_frame_yuv_144p,
++	(const struct uvc_descriptor_header *) &uvc_frame_yuv_240p,
++	(const struct uvc_descriptor_header *) &uvc_frame_yuv_288p,
++	(const struct uvc_descriptor_header *) &uvc_frame_yuv_480p,
+ 	(const struct uvc_descriptor_header *) &uvc_frame_yuv_720p,
+ 	(const struct uvc_descriptor_header *) &uvc_format_mjpg,
+-	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p,
++	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_144p,
++	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_240p,
++	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_288p,
++	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_480p,
+ 	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p,
++	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_1080p,
++	(const struct uvc_descriptor_header *) &uvc_format_h264_base,
++	(const struct uvc_descriptor_header *) &uvc_frame_h264_720p,
++	(const struct uvc_descriptor_header *) &uvc_frame_h264_1080p,
++	(const struct uvc_descriptor_header *) &uvc_frame_h264_480p,
++	(const struct uvc_descriptor_header *) &uvc_frame_h264_144p,
++	(const struct uvc_descriptor_header *) &uvc_frame_h264_240p,
++	(const struct uvc_descriptor_header *) &uvc_frame_h264_288p,
+ 	(const struct uvc_descriptor_header *) &uvc_color_matching,
+ 	NULL,
+ };
+@@ -321,11 +649,25 @@ static const struct uvc_descriptor_header * const uvc_hs_streaming_cls[] = {
+ static const struct uvc_descriptor_header * const uvc_ss_streaming_cls[] = {
+ 	(const struct uvc_descriptor_header *) &uvc_input_header,
+ 	(const struct uvc_descriptor_header *) &uvc_format_yuv,
+-	(const struct uvc_descriptor_header *) &uvc_frame_yuv_360p,
++	(const struct uvc_descriptor_header *) &uvc_frame_yuv_144p,
++	(const struct uvc_descriptor_header *) &uvc_frame_yuv_240p,
++	(const struct uvc_descriptor_header *) &uvc_frame_yuv_288p,
++	(const struct uvc_descriptor_header *) &uvc_frame_yuv_480p,
+ 	(const struct uvc_descriptor_header *) &uvc_frame_yuv_720p,
+ 	(const struct uvc_descriptor_header *) &uvc_format_mjpg,
+-	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p,
++	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_144p,
++	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_240p,
++	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_288p,
++	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_480p,
+ 	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p,
++	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_1080p,
++	(const struct uvc_descriptor_header *) &uvc_format_h264_base,
++	(const struct uvc_descriptor_header *) &uvc_frame_h264_720p,
++	(const struct uvc_descriptor_header *) &uvc_frame_h264_1080p,
++	(const struct uvc_descriptor_header *) &uvc_frame_h264_480p,
++	(const struct uvc_descriptor_header *) &uvc_frame_h264_144p,
++	(const struct uvc_descriptor_header *) &uvc_frame_h264_240p,
++	(const struct uvc_descriptor_header *) &uvc_frame_h264_288p,
+ 	(const struct uvc_descriptor_header *) &uvc_color_matching,
+ 	NULL,
+ };
+@@ -346,7 +688,6 @@ webcam_config_bind(struct usb_configuration *c)
+ 	status = usb_add_function(c, f_uvc);
+ 	if (status < 0)
+ 		usb_put_function(f_uvc);
+-
+ 	return status;
+ }
+ 
+diff --git a/drivers/usb/gadget/legacy/webcam_audio.c b/drivers/usb/gadget/legacy/webcam_audio.c
+new file mode 100644
+index 0000000..826c65e
+--- /dev/null
++++ b/drivers/usb/gadget/legacy/webcam_audio.c
+@@ -0,0 +1,791 @@
++/*
++ *	webcam.c -- USB webcam gadget driver
++ *
++ *	Copyright (C) 2009-2010
++ *	    Laurent Pinchart (laurent.pinchart@ideasonboard.com)
++ *
++ *	This program is free software; you can redistribute it and/or modify
++ *	it under the terms of the GNU General Public License as published by
++ *	the Free Software Foundation; either version 2 of the License, or
++ *	(at your option) any later version.
++ */
++
++#include <linux/kernel.h>
++#include <linux/device.h>
++#include <linux/module.h>
++#include <linux/usb/video.h>
++
++#include "u_uvc.h"
++
++USB_GADGET_COMPOSITE_OPTIONS();
++
++#include "audio.inl"
++
++/*-------------------------------------------------------------------------*/
++
++/* module parameters specific to the Video streaming endpoint */
++static unsigned int streaming_interval = 1;
++module_param(streaming_interval, uint, S_IRUGO|S_IWUSR);
++MODULE_PARM_DESC(streaming_interval, "1 - 16");
++
++static unsigned int streaming_maxpacket = 3072;
++module_param(streaming_maxpacket, uint, S_IRUGO|S_IWUSR);
++MODULE_PARM_DESC(streaming_maxpacket, "1 - 1023 (FS), 1 - 3072 (hs/ss)");
++
++static unsigned int streaming_maxburst = 14;
++module_param(streaming_maxburst, uint, S_IRUGO|S_IWUSR);
++MODULE_PARM_DESC(streaming_maxburst, "0 - 15 (ss only)");
++
++static unsigned int trace;
++module_param(trace, uint, S_IRUGO|S_IWUSR);
++MODULE_PARM_DESC(trace, "Trace level bitmask");
++/* --------------------------------------------------------------------------
++ * Device descriptor
++ */
++
++#define WEBCAM_VENDOR_ID		0x1d6b	/* Linux Foundation */
++#define WEBCAM_PRODUCT_ID		0x0102	/* Webcam A/V gadget */
++#define WEBCAM_DEVICE_BCD		0x0010	/* 0.10 */
++
++static char webcam_vendor_label[] = "Linux Foundation";
++static char webcam_product_label[] = "Webcam gadget";
++static char webcam_config_label[] = "Video";
++
++/* GUID of the UVC H.264 extension unit:
++{A29E7641-DE04-47E3-8B2B-F4341AFF003B} */
++#define GUID_UVCX_H264_XU {0x41, 0x76, 0x9E, 0xA2, 0x04, 0xDE, 0xE3, 0x47, \
++				0x8B, 0x2B, 0xF4, 0x34, 0x1A, 0xFF, 0x00, 0x3B}
++
++#define UVC_GUID_HI_CAMERA {0x91, 0x72, 0x1e, 0x9a, 0x43, 0x68, 0x83, 0x46, \
++				0x6d, 0x92, 0x39, 0xbc, 0x79, 0x06, 0xee, 0x49}
++
++#define UVC_GUID_FORMAT_H264 {0x48, 0x32, 0x36, 0x34, 0x00, 0x00, 0x10, 0x00, \
++				0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
++
++/* string IDs are assigned dynamically */
++
++#define STRING_DESCRIPTION_IDX		USB_GADGET_FIRST_AVAIL_IDX
++
++static struct usb_string webcam_strings[] = {
++	[USB_GADGET_MANUFACTURER_IDX].s	= webcam_vendor_label,
++	[USB_GADGET_PRODUCT_IDX].s	= webcam_product_label,
++	[USB_GADGET_SERIAL_IDX].s	= "",
++	[STRING_DESCRIPTION_IDX].s	= webcam_config_label,
++	{  }
++};
++
++static struct usb_gadget_strings webcam_stringtab = {
++	.language	= 0x0409,	/* en-us */
++	.strings	= webcam_strings,
++};
++
++static struct usb_gadget_strings *webcam_device_strings[] = {
++	&webcam_stringtab,
++	NULL,
++};
++
++static struct usb_function_instance *fi_uvc;
++static struct usb_function *f_uvc;
++
++static struct usb_device_descriptor webcam_device_descriptor = {
++	.bLength		= USB_DT_DEVICE_SIZE,
++	.bDescriptorType	= USB_DT_DEVICE,
++	.bcdUSB			= cpu_to_le16(0x0200),
++	.bDeviceClass		= USB_CLASS_MISC,
++	.bDeviceSubClass	= 0x02,
++	.bDeviceProtocol	= 0x01,
++	.bMaxPacketSize0	= 0, /* dynamic */
++	.idVendor		= cpu_to_le16(WEBCAM_VENDOR_ID),
++	.idProduct		= cpu_to_le16(WEBCAM_PRODUCT_ID),
++	.bcdDevice		= cpu_to_le16(WEBCAM_DEVICE_BCD),
++	.iManufacturer		= 0, /* dynamic */
++	.iProduct		= 0, /* dynamic */
++	.iSerialNumber		= 0, /* dynamic */
++	.bNumConfigurations	= 0, /* dynamic */
++};
++
++DECLARE_UVC_HEADER_DESCRIPTOR(1);
++
++static const struct UVC_HEADER_DESCRIPTOR(1) uvc_control_header = {
++	.bLength		= UVC_DT_HEADER_SIZE(1),
++	.bDescriptorType	= USB_DT_CS_INTERFACE,
++	.bDescriptorSubType	= UVC_VC_HEADER,
++	.bcdUVC			= cpu_to_le16(0x0110),
++	.wTotalLength		= 0, /* dynamic */
++	.dwClockFrequency	= cpu_to_le32(48000000),
++	.bInCollection		= 0, /* dynamic */
++	.baInterfaceNr[0]	= 0, /* dynamic */
++};
++
++static const struct uvc_camera_terminal_descriptor uvc_camera_terminal = {
++	.bLength		= UVC_DT_CAMERA_TERMINAL_SIZE(3),
++	.bDescriptorType	= USB_DT_CS_INTERFACE,
++	.bDescriptorSubType	= UVC_VC_INPUT_TERMINAL,
++	.bTerminalID		= 2,
++	.wTerminalType		= cpu_to_le16(0x0201),
++	.bAssocTerminal		= 0,
++	.iTerminal		= 0,
++	.wObjectiveFocalLengthMin	= cpu_to_le16(0),
++	.wObjectiveFocalLengthMax	= cpu_to_le16(0),
++	.wOcularFocalLength		= cpu_to_le16(0),
++	.bControlSize		= 3,
++	.bmControls[0]		= 0x1a,
++	.bmControls[1]		= 0x00,
++	.bmControls[2]		= 0,
++};
++
++static const struct uvc_processing_unit_descriptor uvc_processing = {
++	.bLength		= sizeof(uvc_processing),
++	.bDescriptorType	= USB_DT_CS_INTERFACE,
++	.bDescriptorSubType	= UVC_VC_PROCESSING_UNIT,
++	.bUnitID		= 5,
++	.bSourceID		= 1,
++	.wMaxMultiplier		= cpu_to_le16(16*1024),
++	.bControlSize		= 2,
++	.bmControls[0]		= 0xff,
++	.bmControls[1]		= 0xff,
++	.iProcessing		= 0,
++};
++
++DECLARE_UVC_EXTENSION_UNIT_DESCRIPTOR(1, 2);
++
++static const struct UVC_EXTENSION_UNIT_DESCRIPTOR(1, 2) uvc_xu_h264_desc = {
++	.bLength		= UVC_DT_EXTENSION_UNIT_SIZE(1, 2),
++	.bDescriptorType	= USB_DT_CS_INTERFACE,
++	.bDescriptorSubType	= UVC_VC_EXTENSION_UNIT,
++	.bUnitID		= 10,
++	.guidExtensionCode	= GUID_UVCX_H264_XU,
++	.bNumControls		= 15,
++	.bNrInPins		= 1,
++	.baSourceID[0]		= 2,
++	.bControlSize		= 2,
++	.bmControls[0]		= 0xff,
++	.bmControls[1]		= 0xff,
++	.iExtension		= 0,
++};
++
++static const struct UVC_EXTENSION_UNIT_DESCRIPTOR(1, 2) uvc_xu_hicamera_desc = {
++	.bLength		= UVC_DT_EXTENSION_UNIT_SIZE(1, 2),
++	.bDescriptorType	= USB_DT_CS_INTERFACE,
++	.bDescriptorSubType	= UVC_VC_EXTENSION_UNIT,
++	.bUnitID		= 0x11,
++	.guidExtensionCode	= UVC_GUID_HI_CAMERA,
++	.bNumControls		= 15,
++	.bNrInPins		= 1,
++	.baSourceID[0]		= 10,
++	.bControlSize		= 2,
++	.bmControls[0]		= 0xff,
++	.bmControls[1]		= 0xff,
++	.iExtension		= 0,
++};
++
++static const struct uvc_output_terminal_descriptor uvc_output_terminal = {
++	.bLength		= UVC_DT_OUTPUT_TERMINAL_SIZE,
++	.bDescriptorType	= USB_DT_CS_INTERFACE,
++	.bDescriptorSubType	= UVC_VC_OUTPUT_TERMINAL,
++	.bTerminalID		= 3,
++	.wTerminalType		= cpu_to_le16(0x0101),
++	.bAssocTerminal		= 0,
++	.bSourceID		= 0x11,
++	.iTerminal		= 0,
++};
++
++DECLARE_UVC_INPUT_HEADER_DESCRIPTOR(1, 2);
++
++static const struct UVC_INPUT_HEADER_DESCRIPTOR(1, 2) uvc_input_header = {
++	.bLength		= UVC_DT_INPUT_HEADER_SIZE(1, 2),
++	.bDescriptorType	= USB_DT_CS_INTERFACE,
++	.bDescriptorSubType	= UVC_VS_INPUT_HEADER,
++	.bNumFormats		= 2,
++	.wTotalLength		= 0, /* dynamic */
++	.bEndpointAddress	= 0, /* dynamic */
++	.bmInfo			= 0,
++	.bTerminalLink		= 3,
++	.bStillCaptureMethod	= 0,
++	.bTriggerSupport	= 0,
++	.bTriggerUsage		= 0,
++	.bControlSize		= 1,
++	.bmaControls[0][0]	= 0,
++	.bmaControls[1][0]	= 4,
++};
++
++static const struct uvc_format_uncompressed uvc_format_yuv = {
++	.bLength		= UVC_DT_FORMAT_UNCOMPRESSED_SIZE,
++	.bDescriptorType	= USB_DT_CS_INTERFACE,
++	.bDescriptorSubType	= UVC_VS_FORMAT_UNCOMPRESSED,
++	.bFormatIndex		= 1,
++	.bNumFrameDescriptors	= 5,
++	.guidFormat		=
++		{ 'Y',  'U',  'Y',  '2', 0x00, 0x00, 0x10, 0x00,
++		 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71},
++	.bBitsPerPixel		= 16,
++	.bDefaultFrameIndex	= 1,
++	.bAspectRatioX		= 0,
++	.bAspectRatioY		= 0,
++	.bmInterfaceFlags	= 0,
++	.bCopyProtect		= 0,
++};
++
++DECLARE_UVC_FRAME_UNCOMPRESSED(1);
++DECLARE_UVC_FRAME_UNCOMPRESSED(3);
++static const struct UVC_FRAME_UNCOMPRESSED(1) uvc_frame_yuv_144p = {
++	.bLength		= UVC_DT_FRAME_UNCOMPRESSED_SIZE(1),
++	.bDescriptorType	= USB_DT_CS_INTERFACE,
++	.bDescriptorSubType	= UVC_VS_FRAME_UNCOMPRESSED,
++	.bFrameIndex		= 1,
++	.bmCapabilities		= 0,
++	.wWidth			= cpu_to_le16(176),
++	.wHeight		= cpu_to_le16(144),
++	.dwMinBitRate		= cpu_to_le32(56088),
++	.dwMaxBitRate		= cpu_to_le32(56088),
++	.dwMaxVideoFrameBufferSize	= cpu_to_le32(460800),
++	.dwDefaultFrameInterval	= cpu_to_le32(333333),
++	.bFrameIntervalType	= 1,
++	.dwFrameInterval[0]	= cpu_to_le32(333333),
++};
++
++static const struct UVC_FRAME_UNCOMPRESSED(1) uvc_frame_yuv_240p = {
++	.bLength		= UVC_DT_FRAME_UNCOMPRESSED_SIZE(1),
++	.bDescriptorType	= USB_DT_CS_INTERFACE,
++	.bDescriptorSubType	= UVC_VS_FRAME_UNCOMPRESSED,
++	.bFrameIndex		= 2,
++	.bmCapabilities		= 0,
++	.wWidth			= cpu_to_le16(320),
++	.wHeight		= cpu_to_le16(240),
++	.dwMinBitRate		= cpu_to_le32(55296000),
++	.dwMaxBitRate		= cpu_to_le32(55296000),
++	.dwMaxVideoFrameBufferSize	= cpu_to_le32(460800),
++	.dwDefaultFrameInterval	= cpu_to_le32(333333),
++	.bFrameIntervalType	= 1,
++	.dwFrameInterval[0]	= cpu_to_le32(333333),
++};
++
++static const struct UVC_FRAME_UNCOMPRESSED(1) uvc_frame_yuv_288p = {
++	.bLength		= UVC_DT_FRAME_UNCOMPRESSED_SIZE(1),
++	.bDescriptorType	= USB_DT_CS_INTERFACE,
++	.bDescriptorSubType	= UVC_VS_FRAME_UNCOMPRESSED,
++	.bFrameIndex		= 3,
++	.bmCapabilities		= 0,
++	.wWidth			= cpu_to_le16(352),
++	.wHeight		= cpu_to_le16(288),
++	.dwMinBitRate		= cpu_to_le32(55296000),
++	.dwMaxBitRate		= cpu_to_le32(55296000),
++	.dwMaxVideoFrameBufferSize	= cpu_to_le32(460800),
++	.dwDefaultFrameInterval	= cpu_to_le32(333333),
++	.bFrameIntervalType	= 1,
++	.dwFrameInterval[0]	= cpu_to_le32(333333),
++};
++
++static const struct UVC_FRAME_UNCOMPRESSED(1) uvc_frame_yuv_480p = {
++	.bLength		= UVC_DT_FRAME_UNCOMPRESSED_SIZE(1),
++	.bDescriptorType	= USB_DT_CS_INTERFACE,
++	.bDescriptorSubType	= UVC_VS_FRAME_UNCOMPRESSED,
++	.bFrameIndex		= 4,
++	.bmCapabilities		= 0,
++	.wWidth			= cpu_to_le16(640),
++	.wHeight		= cpu_to_le16(480),
++	.dwMinBitRate		= cpu_to_le32(55296000),
++	.dwMaxBitRate		= cpu_to_le32(55296000),
++	.dwMaxVideoFrameBufferSize	= cpu_to_le32(460800),
++	.dwDefaultFrameInterval	= cpu_to_le32(333333),
++	.bFrameIntervalType	= 1,
++	.dwFrameInterval[0]	= cpu_to_le32(333333),
++};
++
++static const struct UVC_FRAME_UNCOMPRESSED(1) uvc_frame_yuv_720p = {
++	.bLength		= UVC_DT_FRAME_UNCOMPRESSED_SIZE(1),
++	.bDescriptorType	= USB_DT_CS_INTERFACE,
++	.bDescriptorSubType	= UVC_VS_FRAME_UNCOMPRESSED,
++	.bFrameIndex		= 5,
++	.bmCapabilities		= 0,
++	.wWidth			= cpu_to_le16(1280),
++	.wHeight		= cpu_to_le16(720),
++	.dwMinBitRate		= cpu_to_le32(29491200),
++	.dwMaxBitRate		= cpu_to_le32(29491200),
++	.dwMaxVideoFrameBufferSize	= cpu_to_le32(1843200),
++	.dwDefaultFrameInterval	= cpu_to_le32(333333),
++	.bFrameIntervalType	= 1,
++	.dwFrameInterval[0]	= cpu_to_le32(333333),
++};
++
++static const struct UVC_FRAME_UNCOMPRESSED(1) uvc_frame_yuv_1080p = {
++	.bLength		= UVC_DT_FRAME_UNCOMPRESSED_SIZE(1),
++	.bDescriptorType	= USB_DT_CS_INTERFACE,
++	.bDescriptorSubType	= UVC_VS_FRAME_UNCOMPRESSED,
++	.bFrameIndex		= 6,
++	.bmCapabilities		= 0,
++	.wWidth			= cpu_to_le16(1920),
++	.wHeight		= cpu_to_le16(1080),
++	.dwMinBitRate		= cpu_to_le32(29491200),
++	.dwMaxBitRate		= cpu_to_le32(29491200),
++	.dwMaxVideoFrameBufferSize	= cpu_to_le32(1843200),
++	.dwDefaultFrameInterval	= cpu_to_le32(333333),
++	.bFrameIntervalType	= 1,
++	.dwFrameInterval[0]	= cpu_to_le32(333333),
++};
++
++static const struct uvc_format_mjpeg uvc_format_mjpg = {
++	.bLength		= UVC_DT_FORMAT_MJPEG_SIZE,
++	.bDescriptorType	= USB_DT_CS_INTERFACE,
++	.bDescriptorSubType	= UVC_VS_FORMAT_MJPEG,
++	.bFormatIndex		= 2,
++	.bNumFrameDescriptors	= 6,
++	.bmFlags		= 0,
++	.bDefaultFrameIndex	= 1,
++	.bAspectRatioX		= 0,
++	.bAspectRatioY		= 0,
++	.bmInterfaceFlags	= 0,
++	.bCopyProtect		= 0,
++};
++
++DECLARE_UVC_FRAME_MJPEG(1);
++DECLARE_UVC_FRAME_MJPEG(3);
++
++static const struct UVC_FRAME_MJPEG(1) uvc_frame_mjpg_144p = {
++	.bLength		= UVC_DT_FRAME_MJPEG_SIZE(1),
++	.bDescriptorType	= USB_DT_CS_INTERFACE,
++	.bDescriptorSubType	= UVC_VS_FRAME_MJPEG,
++	.bFrameIndex		= 1,
++	.bmCapabilities		= 0,
++	.wWidth			= cpu_to_le16(176),
++	.wHeight		= cpu_to_le16(144),
++	.dwMinBitRate		= cpu_to_le32(55296000),
++	.dwMaxBitRate		= cpu_to_le32(55296000),
++	.dwMaxVideoFrameBufferSize	= cpu_to_le32(460800),
++	.dwDefaultFrameInterval	= cpu_to_le32(333333),
++	.bFrameIntervalType	= 1,
++	.dwFrameInterval[0]	= cpu_to_le32(333333),
++};
++
++static const struct UVC_FRAME_MJPEG(1) uvc_frame_mjpg_240p = {
++	.bLength		= UVC_DT_FRAME_MJPEG_SIZE(1),
++	.bDescriptorType	= USB_DT_CS_INTERFACE,
++	.bDescriptorSubType	= UVC_VS_FRAME_MJPEG,
++	.bFrameIndex		= 2,
++	.bmCapabilities		= 0,
++	.wWidth			= cpu_to_le16(320),
++	.wHeight		= cpu_to_le16(240),
++	.dwMinBitRate		= cpu_to_le32(55296000),
++	.dwMaxBitRate		= cpu_to_le32(55296000),
++	.dwMaxVideoFrameBufferSize	= cpu_to_le32(460800),
++	.dwDefaultFrameInterval	= cpu_to_le32(333333),
++	.bFrameIntervalType	= 1,
++	.dwFrameInterval[0]	= cpu_to_le32(333333),
++};
++
++static const struct UVC_FRAME_MJPEG(1) uvc_frame_mjpg_288p = {
++	.bLength		= UVC_DT_FRAME_MJPEG_SIZE(1),
++	.bDescriptorType	= USB_DT_CS_INTERFACE,
++	.bDescriptorSubType	= UVC_VS_FRAME_MJPEG,
++	.bFrameIndex		= 3,
++	.bmCapabilities		= 0,
++	.wWidth			= cpu_to_le16(352),
++	.wHeight		= cpu_to_le16(288),
++	.dwMinBitRate		= cpu_to_le32(55296000),
++	.dwMaxBitRate		= cpu_to_le32(55296000),
++	.dwMaxVideoFrameBufferSize	= cpu_to_le32(460800),
++	.dwDefaultFrameInterval	= cpu_to_le32(333333),
++	.bFrameIntervalType	= 1,
++	.dwFrameInterval[0]	= cpu_to_le32(333333),
++};
++
++
++static const struct UVC_FRAME_MJPEG(1) uvc_frame_mjpg_480p = {
++	.bLength		= UVC_DT_FRAME_MJPEG_SIZE(1),
++	.bDescriptorType	= USB_DT_CS_INTERFACE,
++	.bDescriptorSubType	= UVC_VS_FRAME_MJPEG,
++	.bFrameIndex		= 4,
++	.bmCapabilities		= 0,
++	.wWidth			= cpu_to_le16(640),
++	.wHeight		= cpu_to_le16(480),
++	.dwMinBitRate		= cpu_to_le32(55296000),
++	.dwMaxBitRate		= cpu_to_le32(55296000),
++	.dwMaxVideoFrameBufferSize	= cpu_to_le32(460800),
++	.dwDefaultFrameInterval	= cpu_to_le32(333333),
++	.bFrameIntervalType	= 1,
++	.dwFrameInterval[0]	= cpu_to_le32(333333),
++};
++
++static const struct UVC_FRAME_MJPEG(1) uvc_frame_mjpg_720p = {
++	.bLength		= UVC_DT_FRAME_MJPEG_SIZE(1),
++	.bDescriptorType	= USB_DT_CS_INTERFACE,
++	.bDescriptorSubType	= UVC_VS_FRAME_MJPEG,
++	.bFrameIndex		= 5,
++	.bmCapabilities		= 0,
++	.wWidth			= cpu_to_le16(1280),
++	.wHeight		= cpu_to_le16(720),
++	.dwMinBitRate		= cpu_to_le32(29491200),
++	.dwMaxBitRate		= cpu_to_le32(29491200),
++	.dwMaxVideoFrameBufferSize	= cpu_to_le32(1843200),
++	.dwDefaultFrameInterval	= cpu_to_le32(333333),
++	.bFrameIntervalType	= 1,
++	.dwFrameInterval[0]	= cpu_to_le32(333333),
++};
++
++static const struct UVC_FRAME_MJPEG(1) uvc_frame_mjpg_1080p = {
++	.bLength		= UVC_DT_FRAME_MJPEG_SIZE(1),
++	.bDescriptorType	= USB_DT_CS_INTERFACE,
++	.bDescriptorSubType	= UVC_VS_FRAME_MJPEG,
++	.bFrameIndex		= 6,
++	.bmCapabilities		= 0,
++	.wWidth			= cpu_to_le16(1920),
++	.wHeight		= cpu_to_le16(1080),
++	.dwMinBitRate		= cpu_to_le32(29491200),
++	.dwMaxBitRate		= cpu_to_le32(29491200),
++	.dwMaxVideoFrameBufferSize	= cpu_to_le32(1843200),
++	.dwDefaultFrameInterval	= cpu_to_le32(333333),
++	.bFrameIntervalType	= 1,
++	.dwFrameInterval[0]	= cpu_to_le32(333333),
++};
++
++static const struct uvc_format_h264 uvc_format_h264 = {
++	.bLength		= UVC_DT_FORMAT_H264_SIZE,
++	.bDescriptorType	= USB_DT_CS_INTERFACE,
++	.bDescriptorSubType	= UVC_VS_FORMAT_H264,
++	.bFormatIndex		= 3,
++	.bNumFrameDescriptors	= 6,
++	.bmFlags		= 0,
++	.bDefaultFrameIndex	= 1,
++	.bAspectRatioX		= 0,
++	.bAspectRatioY		= 0,
++	.bmInterfaceFlags	= 0,
++	.bCopyProtect		= 0,
++};
++
++static const struct uvc_format_h264_base uvc_format_h264_base = {
++	.bLength		= sizeof(uvc_format_h264_base),
++	.bDescriptorType	= USB_DT_CS_INTERFACE,
++	.bDescriptorSubType	= UVC_VS_FORMAT_FRAME_BASED,
++	.bFormatIndex		= 3,
++	.bNumFrameDescriptors	= 6,
++	.guidFormat	= UVC_GUID_FORMAT_H264,
++	.bBitsPerPixel	= 16,
++	.bDefaultFrameIndex	= 1,
++	.bAspectRatioX		= 0,
++	.bAspectRatioY		= 0,
++	.bmInterfaceFlags	= 0,
++	.bCopyProtect		= 0,
++	.bVariableSize	= 1,
++};
++
++DECLARE_UVC_FRAME_H264_BASE(1);
++DECLARE_UVC_FRAME_H264_BASE(3);
++
++static const struct UVC_FRAME_H264_BASE(1) uvc_frame_h264_720p = {
++	.bLength		= UVC_DT_FRAME_MJPEG_SIZE(1),
++	.bDescriptorType	= USB_DT_CS_INTERFACE,
++	.bDescriptorSubType	= UVC_VS_FRAME_FRAME_BASED,
++	.bFrameIndex		= 5,
++	.bmCapabilities		= 0,
++	.wWidth			= cpu_to_le16(1280),
++	.wHeight		= cpu_to_le16(720),
++	.dwMinBitRate		= cpu_to_le32(55296000),
++	.dwMaxBitRate		= cpu_to_le32(55296000),
++	.dwDefaultFrameInterval	= cpu_to_le32(333333),
++	.bFrameIntervalType	= 1,
++	.dwBytesPerLine	= 0,
++	.dwFrameInterval[0]	= cpu_to_le32(333333),
++};
++
++static const struct UVC_FRAME_H264_BASE(1) uvc_frame_h264_1080p = {
++	.bLength		= UVC_DT_FRAME_MJPEG_SIZE(1),
++	.bDescriptorType	= USB_DT_CS_INTERFACE,
++	.bDescriptorSubType	= UVC_VS_FRAME_FRAME_BASED,
++	.bFrameIndex		= 6,
++	.bmCapabilities		= 0,
++	.wWidth			= cpu_to_le16(1920),
++	.wHeight		= cpu_to_le16(1080),
++	.dwMinBitRate		= cpu_to_le32(29491200),
++	.dwMaxBitRate		= cpu_to_le32(29491200),
++	.dwDefaultFrameInterval	= cpu_to_le32(333333),
++	.bFrameIntervalType	= 1,
++	.dwBytesPerLine	= 0,
++	.dwFrameInterval[0]	= cpu_to_le32(333333),
++};
++
++static const struct UVC_FRAME_H264_BASE(1) uvc_frame_h264_480p = {
++	.bLength		= UVC_DT_FRAME_MJPEG_SIZE(1),
++	.bDescriptorType	= USB_DT_CS_INTERFACE,
++	.bDescriptorSubType	= UVC_VS_FRAME_FRAME_BASED,
++	.bFrameIndex		= 4,
++	.bmCapabilities		= 0,
++	.wWidth			= cpu_to_le16(640),
++	.wHeight		= cpu_to_le16(480),
++	.dwMinBitRate		= cpu_to_le32(29491200),
++	.dwMaxBitRate		= cpu_to_le32(29491200),
++	.dwDefaultFrameInterval	= cpu_to_le32(333333),
++	.bFrameIntervalType	= 1,
++	.dwBytesPerLine	= 0,
++	.dwFrameInterval[0]	= cpu_to_le32(333333),
++};
++
++static const struct UVC_FRAME_H264_BASE(1) uvc_frame_h264_144p = {
++	.bLength		= UVC_DT_FRAME_MJPEG_SIZE(1),
++	.bDescriptorType	= USB_DT_CS_INTERFACE,
++	.bDescriptorSubType	= UVC_VS_FRAME_FRAME_BASED,
++	.bFrameIndex		= 1,
++	.bmCapabilities		= 0,
++	.wWidth			= cpu_to_le16(176),
++	.wHeight		= cpu_to_le16(144),
++	.dwMinBitRate		= cpu_to_le32(29491200),
++	.dwMaxBitRate		= cpu_to_le32(29491200),
++	.dwDefaultFrameInterval	= cpu_to_le32(333333),
++	.bFrameIntervalType	= 1,
++	.dwBytesPerLine	= 0,
++	.dwFrameInterval[0]	= cpu_to_le32(333333),
++};
++
++static const struct UVC_FRAME_H264_BASE(1) uvc_frame_h264_240p = {
++	.bLength		= UVC_DT_FRAME_MJPEG_SIZE(1),
++	.bDescriptorType	= USB_DT_CS_INTERFACE,
++	.bDescriptorSubType	= UVC_VS_FRAME_FRAME_BASED,
++	.bFrameIndex		= 2,
++	.bmCapabilities		= 0,
++	.wWidth			= cpu_to_le16(320),
++	.wHeight		= cpu_to_le16(240),
++	.dwMinBitRate		= cpu_to_le32(29491200),
++	.dwMaxBitRate		= cpu_to_le32(29491200),
++	.dwDefaultFrameInterval	= cpu_to_le32(333333),
++	.bFrameIntervalType	= 1,
++	.dwBytesPerLine	= 0,
++	.dwFrameInterval[0]	= cpu_to_le32(333333),
++};
++
++static const struct UVC_FRAME_H264_BASE(1) uvc_frame_h264_288p = {
++	.bLength		= UVC_DT_FRAME_MJPEG_SIZE(1),
++	.bDescriptorType	= USB_DT_CS_INTERFACE,
++	.bDescriptorSubType	= UVC_VS_FRAME_FRAME_BASED,
++	.bFrameIndex		= 3,
++	.bmCapabilities		= 0,
++	.wWidth			= cpu_to_le16(352),
++	.wHeight		= cpu_to_le16(288),
++	.dwMinBitRate		= cpu_to_le32(29491200),
++	.dwMaxBitRate		= cpu_to_le32(29491200),
++	.dwDefaultFrameInterval	= cpu_to_le32(333333),
++	.bFrameIntervalType	= 1,
++	.dwBytesPerLine = 0,
++	.dwFrameInterval[0]	= cpu_to_le32(333333),
++};
++
++static const struct uvc_color_matching_descriptor uvc_color_matching = {
++	.bLength		= UVC_DT_COLOR_MATCHING_SIZE,
++	.bDescriptorType	= USB_DT_CS_INTERFACE,
++	.bDescriptorSubType	= UVC_VS_COLORFORMAT,
++	.bColorPrimaries	= 1,
++	.bTransferCharacteristics	= 1,
++	.bMatrixCoefficients	= 4,
++};
++
++static const struct uvc_descriptor_header * const uvc_fs_control_cls[] = {
++	(const struct uvc_descriptor_header *) &uvc_control_header,
++	(const struct uvc_descriptor_header *) &uvc_camera_terminal,
++	(const struct uvc_descriptor_header *) &uvc_processing,
++	(const struct uvc_descriptor_header *) &uvc_xu_h264_desc,
++	(const struct uvc_descriptor_header *) &uvc_xu_hicamera_desc,
++	(const struct uvc_descriptor_header *) &uvc_output_terminal,
++	NULL,
++};
++
++static const struct uvc_descriptor_header * const uvc_ss_control_cls[] = {
++	(const struct uvc_descriptor_header *) &uvc_control_header,
++	(const struct uvc_descriptor_header *) &uvc_camera_terminal,
++	(const struct uvc_descriptor_header *) &uvc_processing,
++	(const struct uvc_descriptor_header *) &uvc_xu_h264_desc,
++	(const struct uvc_descriptor_header *) &uvc_xu_hicamera_desc,
++	(const struct uvc_descriptor_header *) &uvc_output_terminal,
++	NULL,
++};
++
++static const struct uvc_descriptor_header * const uvc_fs_streaming_cls[] = {
++	(const struct uvc_descriptor_header *) &uvc_input_header,
++	(const struct uvc_descriptor_header *) &uvc_format_yuv,
++	(const struct uvc_descriptor_header *) &uvc_frame_yuv_144p,
++	(const struct uvc_descriptor_header *) &uvc_frame_yuv_240p,
++	(const struct uvc_descriptor_header *) &uvc_frame_yuv_288p,
++	(const struct uvc_descriptor_header *) &uvc_frame_yuv_480p,
++	(const struct uvc_descriptor_header *) &uvc_frame_yuv_720p,
++	(const struct uvc_descriptor_header *) &uvc_format_mjpg,
++	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_144p,
++	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_240p,
++	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_288p,
++	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_480p,
++	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p,
++	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_1080p,
++	(const struct uvc_descriptor_header *) &uvc_format_h264_base,
++	(const struct uvc_descriptor_header *) &uvc_frame_h264_720p,
++	(const struct uvc_descriptor_header *) &uvc_frame_h264_1080p,
++	(const struct uvc_descriptor_header *) &uvc_frame_h264_480p,
++	(const struct uvc_descriptor_header *) &uvc_frame_h264_144p,
++	(const struct uvc_descriptor_header *) &uvc_frame_h264_240p,
++	(const struct uvc_descriptor_header *) &uvc_frame_h264_288p,
++	(const struct uvc_descriptor_header *) &uvc_color_matching,
++	NULL,
++};
++
++static const struct uvc_descriptor_header * const uvc_hs_streaming_cls[] = {
++	(const struct uvc_descriptor_header *) &uvc_input_header,
++	(const struct uvc_descriptor_header *) &uvc_format_yuv,
++	(const struct uvc_descriptor_header *) &uvc_frame_yuv_144p,
++	(const struct uvc_descriptor_header *) &uvc_frame_yuv_240p,
++	(const struct uvc_descriptor_header *) &uvc_frame_yuv_288p,
++	(const struct uvc_descriptor_header *) &uvc_frame_yuv_480p,
++	(const struct uvc_descriptor_header *) &uvc_frame_yuv_720p,
++	(const struct uvc_descriptor_header *) &uvc_format_mjpg,
++	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_144p,
++	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_240p,
++	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_288p,
++	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_480p,
++	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p,
++	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_1080p,
++	(const struct uvc_descriptor_header *) &uvc_format_h264_base,
++	(const struct uvc_descriptor_header *) &uvc_frame_h264_720p,
++	(const struct uvc_descriptor_header *) &uvc_frame_h264_1080p,
++	(const struct uvc_descriptor_header *) &uvc_frame_h264_480p,
++	(const struct uvc_descriptor_header *) &uvc_frame_h264_144p,
++	(const struct uvc_descriptor_header *) &uvc_frame_h264_240p,
++	(const struct uvc_descriptor_header *) &uvc_frame_h264_288p,
++	(const struct uvc_descriptor_header *) &uvc_color_matching,
++	NULL,
++};
++
++static const struct uvc_descriptor_header * const uvc_ss_streaming_cls[] = {
++	(const struct uvc_descriptor_header *) &uvc_input_header,
++	(const struct uvc_descriptor_header *) &uvc_format_yuv,
++	(const struct uvc_descriptor_header *) &uvc_frame_yuv_144p,
++	(const struct uvc_descriptor_header *) &uvc_frame_yuv_240p,
++	(const struct uvc_descriptor_header *) &uvc_frame_yuv_288p,
++	(const struct uvc_descriptor_header *) &uvc_frame_yuv_480p,
++	(const struct uvc_descriptor_header *) &uvc_frame_yuv_720p,
++	(const struct uvc_descriptor_header *) &uvc_format_mjpg,
++	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_144p,
++	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_240p,
++	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_288p,
++	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_480p,
++	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p,
++	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_1080p,
++	(const struct uvc_descriptor_header *) &uvc_format_h264_base,
++	(const struct uvc_descriptor_header *) &uvc_frame_h264_720p,
++	(const struct uvc_descriptor_header *) &uvc_frame_h264_1080p,
++	(const struct uvc_descriptor_header *) &uvc_frame_h264_480p,
++	(const struct uvc_descriptor_header *) &uvc_frame_h264_144p,
++	(const struct uvc_descriptor_header *) &uvc_frame_h264_240p,
++	(const struct uvc_descriptor_header *) &uvc_frame_h264_288p,
++	(const struct uvc_descriptor_header *) &uvc_color_matching,
++	NULL,
++};
++
++/* --------------------------------------------------------------------------
++ * USB configuration
++ */
++static int __init
++webcam_config_bind(struct usb_configuration *c)
++{
++	int status = 0;
++
++	f_uvc = usb_get_function(fi_uvc);
++	if (IS_ERR(f_uvc))
++		return PTR_ERR(f_uvc);
++
++	status = usb_add_function(c, f_uvc);
++	if (status < 0)
++		usb_put_function(f_uvc);
++
++	/* FIXME: add audio device*/
++	audio_do_config(c);
++
++	return status;
++}
++
++static struct usb_configuration webcam_config_driver = {
++	.label			= webcam_config_label,
++	.bConfigurationValue	= 1,
++	.iConfiguration		= 0, /* dynamic */
++	.bmAttributes		= USB_CONFIG_ATT_SELFPOWER,
++	.MaxPower		= CONFIG_USB_GADGET_VBUS_DRAW,
++};
++
++static int /* __init_or_exit */
++webcam_unbind(struct usb_composite_dev *cdev)
++{
++	/* FIXME: add audio device*/
++	audio_unbind(cdev);
++
++	if (!IS_ERR_OR_NULL(f_uvc))
++		usb_put_function(f_uvc);
++	if (!IS_ERR_OR_NULL(fi_uvc))
++		usb_put_function_instance(fi_uvc);
++	return 0;
++}
++
++static int __init
++webcam_bind(struct usb_composite_dev *cdev)
++{
++	struct f_uvc_opts *uvc_opts;
++	int ret;
++
++	/* FIXME: add audio device*/
++	audio_bind(cdev);
++
++	fi_uvc = usb_get_function_instance("uvc");
++	if (IS_ERR(fi_uvc))
++		return PTR_ERR(fi_uvc);
++
++	uvc_opts = container_of(fi_uvc, struct f_uvc_opts, func_inst);
++
++	uvc_opts->streaming_interval = streaming_interval;
++	uvc_opts->streaming_maxpacket = streaming_maxpacket;
++	uvc_opts->streaming_maxburst = streaming_maxburst;
++	uvc_set_trace_param(trace);
++
++	uvc_opts->fs_control = uvc_fs_control_cls;
++	uvc_opts->ss_control = uvc_ss_control_cls;
++	uvc_opts->fs_streaming = uvc_fs_streaming_cls;
++	uvc_opts->hs_streaming = uvc_hs_streaming_cls;
++	uvc_opts->ss_streaming = uvc_ss_streaming_cls;
++
++	/* Allocate string descriptor numbers ... note that string contents
++	 * can be overridden by the composite_dev glue.
++	 */
++	ret = usb_string_ids_tab(cdev, webcam_strings);
++	if (ret < 0)
++		goto error;
++	webcam_device_descriptor.iManufacturer =
++		webcam_strings[USB_GADGET_MANUFACTURER_IDX].id;
++	webcam_device_descriptor.iProduct =
++		webcam_strings[USB_GADGET_PRODUCT_IDX].id;
++	webcam_config_driver.iConfiguration =
++		webcam_strings[STRING_DESCRIPTION_IDX].id;
++
++	/* Register our configuration. */
++	if ((ret = usb_add_config(cdev, &webcam_config_driver,
++					webcam_config_bind)) < 0)
++		goto error;
++
++	usb_composite_overwrite_options(cdev, &coverwrite);
++	INFO(cdev, "Webcam Video Gadget\n");
++	return 0;
++
++error:
++	usb_put_function_instance(fi_uvc);
++	return ret;
++}
++
++/* --------------------------------------------------------------------------
++ * Driver
++ */
++
++static __refdata struct usb_composite_driver webcam_driver = {
++	.name		= "g_webcam",
++	.dev		= &webcam_device_descriptor,
++	.strings	= webcam_device_strings,
++	.max_speed	= USB_SPEED_SUPER,
++	.bind		= webcam_bind,
++	.unbind		= webcam_unbind,
++};
++
++module_usb_composite_driver(webcam_driver);
++
++MODULE_AUTHOR("Laurent Pinchart");
++MODULE_DESCRIPTION("Webcam Video Gadget");
++MODULE_LICENSE("GPL");
++MODULE_VERSION("0.1.0");
+diff --git a/drivers/usb/gadget/udc/Kconfig b/drivers/usb/gadget/udc/Kconfig
+index 217365d..ed58012 100644
+--- a/drivers/usb/gadget/udc/Kconfig
++++ b/drivers/usb/gadget/udc/Kconfig
+@@ -28,7 +28,7 @@ menu "USB Peripheral Controller"
+ #
+ # Integrated controllers
+ #
+-
++#source "drivers/usb/gadget/udc/hiudc3/Kconfig"
+ config USB_AT91
+ 	tristate "Atmel AT91 USB Device Port"
+ 	depends on ARCH_AT91
+@@ -219,6 +219,67 @@ config USB_MV_UDC
+ 	  USB2.0 OTG controller, which can be configured as high speed or
+ 	  full speed USB peripheral.
+ 
++menuconfig HIUSB_DEVICE2_0
++	  bool "Hisilicon USB2.0 Device Controller SUPPORT"
++	  help
++	  This selects the usb(ehci/ohci) family usb device.
++	  Say Y to enable hisi usb2.0 controller driver.
++	  IF you do not use usb2.0 device in your board,
++	  say N to get a smaller uImage. Mostly you need it.
++
++if HIUSB_DEVICE2_0
++	  config USB_HISI_UDC
++	  tristate "hisilicon highspeed device controller version 3.00a driver"
++	  help
++	  You can select device mode by the option.
++	  Enable hisi ehci controller driver.
++	  Say Y to enable hisi usb2.0 ehci controller driver.
++	  IF you do not use usb2.0 ehci device in your board, say N to get a
++	  smaller uImage. Mostly you need it.
++
++config USB_AUTO_SWITCH
++	bool "Hisilicon USB2.0 Device auto switch"
++	depends on HAS_DMA
++	help
++	  Hisilicon Socs include a high speed. The select can auto switch or
++	  not. Default is auto switch. If you want to be auto switch
++	  host/device, you can set 1 the 1st bit of 0x12020150.
++endif # HI_HS_DEVICE
++
++menuconfig HIUSB_DEVICE3_0
++	  bool "Hisilicon USB3.0 Device Controller SUPPORT"
++	  help
++	  This selects the usb(ehci/ohci) family usb device.
++	  Say Y to enable hisi usb3.0 controller driver.
++	  IF you do not use usb3.0 device in your board,
++	  say N to get a smaller uImage. Mostly you need it.
++
++if HIUSB_DEVICE3_0
++	  config HIUSB_SS_DEVICE
++	  boolean "hisilicon susperspeed device controller version 2.50a driver"
++	  help
++	  You can select device mode by the option.
++	  Enable hisi ehci controller driver.
++	  Say Y to enable hisi usb3.0 xhci controller driver.
++	  IF you do not use usb3.0 xhci device in your board, say N to get a
++	  smaller uImage. Mostly you need it.
++
++config USB_HISI_UDC3
++	tristate "Hisilicon USB3.0 Device Controller"
++	depends on HAS_DMA
++	help
++	  Hisilicon Socs include a high speed
++	  USB3.0 Device controller, which can be configured as susperspeed
++	  USB peripheral.
++
++config USB3_DEVICE_GPIO_CTRL
++	tristate "Hisilicon USB3.0 Device Support GPIO CTRL"
++	help
++	  USB3.0 Device mode, it support device and host switch. When you
++	  pull out the device, it can bring gpio interrupt and notify the sw
++	  handle. The sw set the host mode and then set the device mode.
++endif # HI_SS_DEVICE
++
+ config USB_MV_U3D
+ 	depends on HAS_DMA
+ 	tristate "MARVELL PXA2128 USB 3.0 controller"
+diff --git a/drivers/usb/gadget/udc/Makefile b/drivers/usb/gadget/udc/Makefile
+index a7f4491..564a046 100644
+--- a/drivers/usb/gadget/udc/Makefile
++++ b/drivers/usb/gadget/udc/Makefile
+@@ -1,7 +1,11 @@
+ #
+ # USB peripheral controller drivers
+ #
++ifndef CONFIG_USB_HISI_UDC
++ifndef CONFIG_USB_HISI_UDC3
+ obj-$(CONFIG_USB_GADGET)	+= udc-core.o
++endif
++endif
+ obj-$(CONFIG_USB_DUMMY_HCD)	+= dummy_hcd.o
+ obj-$(CONFIG_USB_NET2272)	+= net2272.o
+ obj-$(CONFIG_USB_NET2280)	+= net2280.o
+@@ -30,3 +34,6 @@ obj-$(CONFIG_USB_FOTG210_UDC)	+= fotg210-udc.o
+ obj-$(CONFIG_USB_MV_U3D)	+= mv_u3d_core.o
+ obj-$(CONFIG_USB_GR_UDC)	+= gr_udc.o
+ obj-$(CONFIG_USB_GADGET_XILINX)	+= udc-xilinx.o
++obj-$(CONFIG_USB_HISI_UDC)	+= hiudc/
++#obj-$(CONFIG_USB_HISI_UDC)	+= hiudc_bak/
++obj-$(CONFIG_USB_HISI_UDC3)	+= hiudc3/
+diff --git a/drivers/usb/gadget/udc/hiudc/Makefile b/drivers/usb/gadget/udc/hiudc/Makefile
+new file mode 100644
+index 0000000..28dd23c
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc/Makefile
+@@ -0,0 +1,21 @@
++#
++# USB peripheral controller drivers
++#
++# Use the BUS_INTERFACE variable to compile the software for either
++# PCI(PCI_INTERFACE) or LM(LM_INTERFACE) bus.
++# Use one of the following flags to compile the software in host-only or
++# device-only mode.
++EXTRA_CFLAGS        += -DDWC_DEVICE_ONLY
++EXTRA_CFLAGS		+= -DDWC_LINUX
++EXTRA_CFLAGS		+= -DLM_INTERFACE
++
++obj-$(CONFIG_USB_HISI_UDC)      += udc-hisi.o
++#obj-y	+= udc-hisi.o
++udc-hisi-objs	:= dwc_otg_driver.o dwc_otg_attr.o
++udc-hisi-objs	+= dwc_otg_cil.o dwc_otg_cil_intr.o
++udc-hisi-objs	+= dwc_otg_pcd_linux.o dwc_otg_pcd.o dwc_otg_pcd_intr.o
++udc-hisi-objs	+= dwc_otg_hcd.o dwc_otg_hcd_linux.o dwc_otg_hcd_intr.o dwc_otg_hcd_queue.o dwc_otg_hcd_ddma.o
++udc-hisi-objs	+= dwc_otg_adp.o
++udc-hisi-objs	+= dwc_cc.o dwc_modpow.o dwc_dh.o \
++			    dwc_crypto.o dwc_notifier.o \
++			    dwc_common_linux.o dwc_mem.o
+diff --git a/drivers/usb/gadget/udc/hiudc/dwc_cc.c b/drivers/usb/gadget/udc/hiudc/dwc_cc.c
+new file mode 100644
+index 0000000..a757f4f
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc/dwc_cc.c
+@@ -0,0 +1,532 @@
++/* =========================================================================
++ * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_cc.c $
++ * $Revision: #4 $
++ * $Date: 2010/11/04 $
++ * $Change: 1621692 $
++ *
++ * Synopsys Portability Library Software and documentation
++ * (hereinafter, "Software") is an Unsupported proprietary work of
++ * Synopsys, Inc. unless otherwise expressly agreed to in writing
++ * between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product
++ * under any End User Software License Agreement or Agreement for
++ * Licensed Product with Synopsys or any supplement thereto. You are
++ * permitted to use and redistribute this Software in source and binary
++ * forms, with or without modification, provided that redistributions
++ * of source code must retain this notice. You may not view, use,
++ * disclose, copy or distribute this file or any information contained
++ * herein except pursuant to this license grant from Synopsys. If you
++ * do not agree with this notice, including the disclaimer below, then
++ * you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
++ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
++ * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
++ * SYNOPSYS 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.
++ * ========================================================================= */
++#ifdef DWC_CCLIB
++
++#include "dwc_cc.h"
++
++typedef struct dwc_cc
++{
++	uint32_t uid;
++	uint8_t chid[16];
++	uint8_t cdid[16];
++	uint8_t ck[16];
++	uint8_t *name;
++	uint8_t length;
++        DWC_CIRCLEQ_ENTRY(dwc_cc) list_entry;
++} dwc_cc_t;
++
++DWC_CIRCLEQ_HEAD(context_list, dwc_cc);
++
++/** The main structure for CC management.  */
++struct dwc_cc_if
++{
++	dwc_mutex_t *mutex;
++	char *filename;
++
++	unsigned is_host:1;
++
++	dwc_notifier_t *notifier;
++
++	struct context_list list;
++};
++
++#ifdef DEBUG
++static inline void dump_bytes(char *name, uint8_t *bytes, int len)
++{
++	int i;
++	DWC_PRINTF("%s: ", name);
++	for (i=0; i<len; i++) {
++		DWC_PRINTF("%02x ", bytes[i]);
++	}
++	DWC_PRINTF("\n");
++}
++#else
++#define dump_bytes(x...)
++#endif
++
++static dwc_cc_t *alloc_cc(void *mem_ctx, uint8_t *name, uint32_t length)
++{
++	dwc_cc_t *cc = dwc_alloc(mem_ctx, sizeof(dwc_cc_t));
++	if (!cc) {
++		return NULL;
++	}
++	DWC_MEMSET(cc, 0, sizeof(dwc_cc_t));
++
++	if (name) {
++		cc->length = length;
++		cc->name = dwc_alloc(mem_ctx, length);
++		if (!cc->name) {
++			dwc_free(mem_ctx, cc);
++			return NULL;
++		}
++
++		DWC_MEMCPY(cc->name, name, length);
++	}
++
++	return cc;
++}
++
++static void free_cc(void *mem_ctx, dwc_cc_t *cc)
++{
++	if (cc->name) {
++		dwc_free(mem_ctx, cc->name);
++	}
++	dwc_free(mem_ctx, cc);
++}
++
++static uint32_t next_uid(dwc_cc_if_t *cc_if)
++{
++	uint32_t uid = 0;
++	dwc_cc_t *cc;
++	DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
++		if (cc->uid > uid) {
++			uid = cc->uid;
++		}
++	}
++
++	if (uid == 0) {
++		uid = 255;
++	}
++
++	return uid + 1;
++}
++
++static dwc_cc_t *cc_find(dwc_cc_if_t *cc_if, uint32_t uid)
++{
++	dwc_cc_t *cc;
++	DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
++		if (cc->uid == uid) {
++			return cc;
++		}
++	}
++	return NULL;
++}
++
++static unsigned int cc_data_size(dwc_cc_if_t *cc_if)
++{
++	unsigned int size = 0;
++	dwc_cc_t *cc;
++	DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
++		size += (48 + 1);
++		if (cc->name) {
++			size += cc->length;
++		}
++	}
++	return size;
++}
++
++static uint32_t cc_match_chid(dwc_cc_if_t *cc_if, uint8_t *chid)
++{
++	uint32_t uid = 0;
++	dwc_cc_t *cc;
++
++	DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
++		if (DWC_MEMCMP(cc->chid, chid, 16) == 0) {
++			uid = cc->uid;
++			break;
++		}
++	}
++	return uid;
++}
++static uint32_t cc_match_cdid(dwc_cc_if_t *cc_if, uint8_t *cdid)
++{
++	uint32_t uid = 0;
++	dwc_cc_t *cc;
++
++	DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
++		if (DWC_MEMCMP(cc->cdid, cdid, 16) == 0) {
++			uid = cc->uid;
++			break;
++		}
++	}
++	return uid;
++}
++
++/* Internal cc_add */
++static int32_t cc_add(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *chid,
++		      uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length)
++{
++	dwc_cc_t *cc;
++	uint32_t uid;
++
++	if (cc_if->is_host) {
++		uid = cc_match_cdid(cc_if, cdid);
++	}
++	else {
++		uid = cc_match_chid(cc_if, chid);
++	}
++
++	if (uid) {
++		DWC_DEBUG("Replacing previous connection context id=%d name=%p name_len=%d", uid, name, length);
++		cc = cc_find(cc_if, uid);
++	}
++	else {
++		cc = alloc_cc(mem_ctx, name, length);
++		cc->uid = next_uid(cc_if);
++		DWC_CIRCLEQ_INSERT_TAIL(&cc_if->list, cc, list_entry);
++	}
++
++	DWC_MEMCPY(&(cc->chid[0]), chid, 16);
++	DWC_MEMCPY(&(cc->cdid[0]), cdid, 16);
++	DWC_MEMCPY(&(cc->ck[0]), ck, 16);
++
++	DWC_DEBUG("Added connection context id=%d name=%p name_len=%d", cc->uid, name, length);
++	dump_bytes("CHID", cc->chid, 16);
++	dump_bytes("CDID", cc->cdid, 16);
++	dump_bytes("CK", cc->ck, 16);
++	return cc->uid;
++}
++
++/* Internal cc_clear */
++static void cc_clear(void *mem_ctx, dwc_cc_if_t *cc_if)
++{
++	while (!DWC_CIRCLEQ_EMPTY(&cc_if->list)) {
++		dwc_cc_t *cc = DWC_CIRCLEQ_FIRST(&cc_if->list);
++		DWC_CIRCLEQ_REMOVE_INIT(&cc_if->list, cc, list_entry);
++		free_cc(mem_ctx, cc);
++	}
++}
++
++dwc_cc_if_t *dwc_cc_if_alloc(void *mem_ctx, void *mtx_ctx,
++			     dwc_notifier_t *notifier, unsigned is_host)
++{
++	dwc_cc_if_t *cc_if = NULL;
++
++	/* Allocate a common_cc_if structure */
++	cc_if = dwc_alloc(mem_ctx, sizeof(dwc_cc_if_t));
++
++	if (!cc_if)
++		return NULL;
++
++#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
++	DWC_MUTEX_ALLOC_LINUX_DEBUG(cc_if->mutex);
++#else
++	cc_if->mutex = dwc_mutex_alloc(mtx_ctx);
++#endif
++	if (!cc_if->mutex) {
++		dwc_free(mem_ctx, cc_if);
++		return NULL;
++	}
++
++	DWC_CIRCLEQ_INIT(&cc_if->list);
++	cc_if->is_host = is_host;
++	cc_if->notifier = notifier;
++	return cc_if;
++}
++
++void dwc_cc_if_free(void *mem_ctx, void *mtx_ctx, dwc_cc_if_t *cc_if)
++{
++#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
++	DWC_MUTEX_FREE(cc_if->mutex);
++#else
++	dwc_mutex_free(mtx_ctx, cc_if->mutex);
++#endif
++	cc_clear(mem_ctx, cc_if);
++	dwc_free(mem_ctx, cc_if);
++}
++
++static void cc_changed(dwc_cc_if_t *cc_if)
++{
++	if (cc_if->notifier) {
++		dwc_notify(cc_if->notifier, DWC_CC_LIST_CHANGED_NOTIFICATION, cc_if);
++	}
++}
++
++void dwc_cc_clear(void *mem_ctx, dwc_cc_if_t *cc_if)
++{
++	DWC_MUTEX_LOCK(cc_if->mutex);
++	cc_clear(mem_ctx, cc_if);
++	DWC_MUTEX_UNLOCK(cc_if->mutex);
++	cc_changed(cc_if);
++}
++
++int32_t dwc_cc_add(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *chid,
++		   uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length)
++{
++	uint32_t uid;
++
++	DWC_MUTEX_LOCK(cc_if->mutex);
++	uid = cc_add(mem_ctx, cc_if, chid, cdid, ck, name, length);
++	DWC_MUTEX_UNLOCK(cc_if->mutex);
++	cc_changed(cc_if);
++
++	return uid;
++}
++
++void dwc_cc_change(void *mem_ctx, dwc_cc_if_t *cc_if, int32_t id, uint8_t *chid,
++		   uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length)
++{
++	dwc_cc_t* cc;
++
++	DWC_DEBUG("Change connection context %d", id);
++
++	DWC_MUTEX_LOCK(cc_if->mutex);
++	cc = cc_find(cc_if, id);
++	if (!cc) {
++		DWC_ERROR("Uid %d not found in cc list\n", id);
++		DWC_MUTEX_UNLOCK(cc_if->mutex);
++		return;
++	}
++
++	if (chid) {
++		DWC_MEMCPY(&(cc->chid[0]), chid, 16);
++	}
++	if (cdid) {
++		DWC_MEMCPY(&(cc->cdid[0]), cdid, 16);
++	}
++	if (ck) {
++		DWC_MEMCPY(&(cc->ck[0]), ck, 16);
++	}
++
++	if (name) {
++		if (cc->name) {
++			dwc_free(mem_ctx, cc->name);
++		}
++		cc->name = dwc_alloc(mem_ctx, length);
++		if (!cc->name) {
++			DWC_ERROR("Out of memory in dwc_cc_change()\n");
++			DWC_MUTEX_UNLOCK(cc_if->mutex);
++			return;
++		}
++		cc->length = length;
++		DWC_MEMCPY(cc->name, name, length);
++	}
++
++	DWC_MUTEX_UNLOCK(cc_if->mutex);
++
++	cc_changed(cc_if);
++
++	DWC_DEBUG("Changed connection context id=%d\n", id);
++	dump_bytes("New CHID", cc->chid, 16);
++	dump_bytes("New CDID", cc->cdid, 16);
++	dump_bytes("New CK", cc->ck, 16);
++}
++
++void dwc_cc_remove(void *mem_ctx, dwc_cc_if_t *cc_if, int32_t id)
++{
++	dwc_cc_t *cc;
++
++	DWC_DEBUG("Removing connection context %d", id);
++
++	DWC_MUTEX_LOCK(cc_if->mutex);
++	cc = cc_find(cc_if, id);
++	if (!cc) {
++		DWC_ERROR("Uid %d not found in cc list\n", id);
++		DWC_MUTEX_UNLOCK(cc_if->mutex);
++		return;
++	}
++
++	DWC_CIRCLEQ_REMOVE_INIT(&cc_if->list, cc, list_entry);
++	DWC_MUTEX_UNLOCK(cc_if->mutex);
++	free_cc(mem_ctx, cc);
++
++	cc_changed(cc_if);
++}
++
++uint8_t *dwc_cc_data_for_save(void *mem_ctx, dwc_cc_if_t *cc_if, unsigned int *length)
++{
++	uint8_t *buf, *x;
++	uint8_t zero = 0;
++	dwc_cc_t *cc;
++
++	DWC_MUTEX_LOCK(cc_if->mutex);
++	*length = cc_data_size(cc_if);
++	if (!(*length)) {
++		DWC_MUTEX_UNLOCK(cc_if->mutex);
++		return NULL;
++	}
++
++	DWC_DEBUG("Creating data for saving (length=%d)", *length);
++
++	buf = dwc_alloc(mem_ctx, *length);
++	if (!buf) {
++		*length = 0;
++		DWC_MUTEX_UNLOCK(cc_if->mutex);
++		return NULL;
++	}
++
++	x = buf;
++	DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
++		DWC_MEMCPY(x, cc->chid, 16);
++		x += 16;
++		DWC_MEMCPY(x, cc->cdid, 16);
++		x += 16;
++		DWC_MEMCPY(x, cc->ck, 16);
++		x += 16;
++		if (cc->name) {
++			DWC_MEMCPY(x, &cc->length, 1);
++			x += 1;
++			DWC_MEMCPY(x, cc->name, cc->length);
++			x += cc->length;
++		}
++		else {
++			DWC_MEMCPY(x, &zero, 1);
++			x += 1;
++		}
++	}
++	DWC_MUTEX_UNLOCK(cc_if->mutex);
++
++	return buf;
++}
++
++void dwc_cc_restore_from_data(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *data, uint32_t length)
++{
++	uint8_t name_length;
++	uint8_t *name;
++	uint8_t *chid;
++	uint8_t *cdid;
++	uint8_t *ck;
++	uint32_t i = 0;
++
++	DWC_MUTEX_LOCK(cc_if->mutex);
++	cc_clear(mem_ctx, cc_if);
++
++	while (i < length) {
++		chid = &data[i];
++		i += 16;
++		cdid = &data[i];
++		i += 16;
++		ck = &data[i];
++		i += 16;
++
++		name_length = data[i];
++		i ++;
++
++		if (name_length) {
++			name = &data[i];
++			i += name_length;
++		}
++		else {
++			name = NULL;
++		}
++
++		/* check to see if we haven't overflown the buffer */
++		if (i > length) {
++			DWC_ERROR("Data format error while attempting to load CCs "
++				  "(nlen=%d, iter=%d, buflen=%d).\n", name_length, i, length);
++			break;
++		}
++
++		cc_add(mem_ctx, cc_if, chid, cdid, ck, name, name_length);
++	}
++	DWC_MUTEX_UNLOCK(cc_if->mutex);
++
++	cc_changed(cc_if);
++}
++
++uint32_t dwc_cc_match_chid(dwc_cc_if_t *cc_if, uint8_t *chid)
++{
++	uint32_t uid = 0;
++
++	DWC_MUTEX_LOCK(cc_if->mutex);
++	uid = cc_match_chid(cc_if, chid);
++	DWC_MUTEX_UNLOCK(cc_if->mutex);
++	return uid;
++}
++uint32_t dwc_cc_match_cdid(dwc_cc_if_t *cc_if, uint8_t *cdid)
++{
++	uint32_t uid = 0;
++
++	DWC_MUTEX_LOCK(cc_if->mutex);
++	uid = cc_match_cdid(cc_if, cdid);
++	DWC_MUTEX_UNLOCK(cc_if->mutex);
++	return uid;
++}
++
++uint8_t *dwc_cc_ck(dwc_cc_if_t *cc_if, int32_t id)
++{
++	uint8_t *ck = NULL;
++	dwc_cc_t *cc;
++
++	DWC_MUTEX_LOCK(cc_if->mutex);
++	cc = cc_find(cc_if, id);
++	if (cc) {
++		ck = cc->ck;
++	}
++	DWC_MUTEX_UNLOCK(cc_if->mutex);
++
++	return ck;
++
++}
++
++uint8_t *dwc_cc_chid(dwc_cc_if_t *cc_if, int32_t id)
++{
++	uint8_t *retval = NULL;
++	dwc_cc_t *cc;
++
++	DWC_MUTEX_LOCK(cc_if->mutex);
++	cc = cc_find(cc_if, id);
++	if (cc) {
++		retval = cc->chid;
++	}
++	DWC_MUTEX_UNLOCK(cc_if->mutex);
++
++	return retval;
++}
++
++uint8_t *dwc_cc_cdid(dwc_cc_if_t *cc_if, int32_t id)
++{
++	uint8_t *retval = NULL;
++	dwc_cc_t *cc;
++
++	DWC_MUTEX_LOCK(cc_if->mutex);
++	cc = cc_find(cc_if, id);
++	if (cc) {
++		retval = cc->cdid;
++	}
++	DWC_MUTEX_UNLOCK(cc_if->mutex);
++
++	return retval;
++}
++
++uint8_t *dwc_cc_name(dwc_cc_if_t *cc_if, int32_t id, uint8_t *length)
++{
++	uint8_t *retval = NULL;
++	dwc_cc_t *cc;
++
++	DWC_MUTEX_LOCK(cc_if->mutex);
++	*length = 0;
++	cc = cc_find(cc_if, id);
++	if (cc) {
++		*length = cc->length;
++		retval = cc->name;
++	}
++	DWC_MUTEX_UNLOCK(cc_if->mutex);
++
++	return retval;
++}
++
++#endif	/* DWC_CCLIB */
+diff --git a/drivers/usb/gadget/udc/hiudc/dwc_cc.h b/drivers/usb/gadget/udc/hiudc/dwc_cc.h
+new file mode 100644
+index 0000000..f86e6f2
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc/dwc_cc.h
+@@ -0,0 +1,224 @@
++/* =========================================================================
++ * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_cc.h $
++ * $Revision: #4 $
++ * $Date: 2010/09/28 $
++ * $Change: 1596182 $
++ *
++ * Synopsys Portability Library Software and documentation
++ * (hereinafter, "Software") is an Unsupported proprietary work of
++ * Synopsys, Inc. unless otherwise expressly agreed to in writing
++ * between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product
++ * under any End User Software License Agreement or Agreement for
++ * Licensed Product with Synopsys or any supplement thereto. You are
++ * permitted to use and redistribute this Software in source and binary
++ * forms, with or without modification, provided that redistributions
++ * of source code must retain this notice. You may not view, use,
++ * disclose, copy or distribute this file or any information contained
++ * herein except pursuant to this license grant from Synopsys. If you
++ * do not agree with this notice, including the disclaimer below, then
++ * you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
++ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
++ * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
++ * SYNOPSYS 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.
++ * ========================================================================= */
++#ifndef _DWC_CC_H_
++#define _DWC_CC_H_
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/** @file
++ *
++ * This file defines the Context Context library.
++ *
++ * The main data structure is dwc_cc_if_t which is returned by either the
++ * dwc_cc_if_alloc function or returned by the module to the user via a provided
++ * function. The data structure is opaque and should only be manipulated via the
++ * functions provied in this API.
++ *
++ * It manages a list of connection contexts and operations can be performed to
++ * add, remove, query, search, and change, those contexts.  Additionally,
++ * a dwc_notifier_t object can be requested from the manager so that
++ * the user can be notified whenever the context list has changed.
++ */
++
++#include "dwc_os.h"
++#include "dwc_list.h"
++#include "dwc_notifier.h"
++
++
++/* Notifications */
++#define DWC_CC_LIST_CHANGED_NOTIFICATION "DWC_CC_LIST_CHANGED_NOTIFICATION"
++
++struct dwc_cc_if;
++typedef struct dwc_cc_if dwc_cc_if_t;
++
++
++/** @name Connection Context Operations */
++/** @{ */
++
++/** This function allocates memory for a dwc_cc_if_t structure, initializes
++ * fields to default values, and returns a pointer to the structure or NULL on
++ * error. */
++extern dwc_cc_if_t *dwc_cc_if_alloc(void *mem_ctx, void *mtx_ctx,
++				    dwc_notifier_t *notifier, unsigned is_host);
++
++/** Frees the memory for the specified CC structure allocated from
++ * dwc_cc_if_alloc(). */
++extern void dwc_cc_if_free(void *mem_ctx, void *mtx_ctx, dwc_cc_if_t *cc_if);
++
++/** Removes all contexts from the connection context list */
++extern void dwc_cc_clear(void *mem_ctx, dwc_cc_if_t *cc_if);
++
++/** Adds a connection context (CHID, CK, CDID, Name) to the connection context list.
++ * If a CHID already exists, the CK and name are overwritten.  Statistics are
++ * not overwritten.
++ *
++ * @param cc_if The cc_if structure.
++ * @param chid A pointer to the 16-byte CHID.  This value will be copied.
++ * @param ck A pointer to the 16-byte CK.  This value will be copied.
++ * @param cdid A pointer to the 16-byte CDID.  This value will be copied.
++ * @param name An optional host friendly name as defined in the association model
++ * spec.  Must be a UTF16-LE unicode string.  Can be NULL to indicated no name.
++ * @param length The length othe unicode string.
++ * @return A unique identifier used to refer to this context that is valid for
++ * as long as this context is still in the list. */
++extern int32_t dwc_cc_add(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *chid,
++			  uint8_t *cdid, uint8_t *ck, uint8_t *name,
++			  uint8_t length);
++
++/** Changes the CHID, CK, CDID, or Name values of a connection context in the
++ * list, preserving any accumulated statistics.  This would typically be called
++ * if the host decideds to change the context with a SET_CONNECTION request.
++ *
++ * @param cc_if The cc_if structure.
++ * @param id The identifier of the connection context.
++ * @param chid A pointer to the 16-byte CHID.  This value will be copied.  NULL
++ * indicates no change.
++ * @param cdid A pointer to the 16-byte CDID.  This value will be copied.  NULL
++ * indicates no change.
++ * @param ck A pointer to the 16-byte CK.  This value will be copied.  NULL
++ * indicates no change.
++ * @param name Host friendly name UTF16-LE.  NULL indicates no change.
++ * @param length Length of name. */
++extern void dwc_cc_change(void *mem_ctx, dwc_cc_if_t *cc_if, int32_t id,
++			  uint8_t *chid, uint8_t *cdid, uint8_t *ck,
++			  uint8_t *name, uint8_t length);
++
++/** Remove the specified connection context.
++ * @param cc_if The cc_if structure.
++ * @param id The identifier of the connection context to remove. */
++extern void dwc_cc_remove(void *mem_ctx, dwc_cc_if_t *cc_if, int32_t id);
++
++/** Get a binary block of data for the connection context list and attributes.
++ * This data can be used by the OS specific driver to save the connection
++ * context list into non-volatile memory.
++ *
++ * @param cc_if The cc_if structure.
++ * @param length Return the length of the data buffer.
++ * @return A pointer to the data buffer.  The memory for this buffer should be
++ * freed with DWC_FREE() after use. */
++extern uint8_t *dwc_cc_data_for_save(void *mem_ctx, dwc_cc_if_t *cc_if,
++				     unsigned int *length);
++
++/** Restore the connection context list from the binary data that was previously
++ * returned from a call to dwc_cc_data_for_save.  This can be used by the OS specific
++ * driver to load a connection context list from non-volatile memory.
++ *
++ * @param cc_if The cc_if structure.
++ * @param data The data bytes as returned from dwc_cc_data_for_save.
++ * @param length The length of the data. */
++extern void dwc_cc_restore_from_data(void *mem_ctx, dwc_cc_if_t *cc_if,
++				     uint8_t *data, unsigned int length);
++
++/** Find the connection context from the specified CHID.
++ *
++ * @param cc_if The cc_if structure.
++ * @param chid A pointer to the CHID data.
++ * @return A non-zero identifier of the connection context if the CHID matches.
++ * Otherwise returns 0. */
++extern uint32_t dwc_cc_match_chid(dwc_cc_if_t *cc_if, uint8_t *chid);
++
++/** Find the connection context from the specified CDID.
++ *
++ * @param cc_if The cc_if structure.
++ * @param cdid A pointer to the CDID data.
++ * @return A non-zero identifier of the connection context if the CHID matches.
++ * Otherwise returns 0. */
++extern uint32_t dwc_cc_match_cdid(dwc_cc_if_t *cc_if, uint8_t *cdid);
++
++/** Retrieve the CK from the specified connection context.
++ *
++ * @param cc_if The cc_if structure.
++ * @param id The identifier of the connection context.
++ * @return A pointer to the CK data.  The memory does not need to be freed. */
++extern uint8_t *dwc_cc_ck(dwc_cc_if_t *cc_if, int32_t id);
++
++/** Retrieve the CHID from the specified connection context.
++ *
++ * @param cc_if The cc_if structure.
++ * @param id The identifier of the connection context.
++ * @return A pointer to the CHID data.  The memory does not need to be freed. */
++extern uint8_t *dwc_cc_chid(dwc_cc_if_t *cc_if, int32_t id);
++
++/** Retrieve the CDID from the specified connection context.
++ *
++ * @param cc_if The cc_if structure.
++ * @param id The identifier of the connection context.
++ * @return A pointer to the CDID data.  The memory does not need to be freed. */
++extern uint8_t *dwc_cc_cdid(dwc_cc_if_t *cc_if, int32_t id);
++
++extern uint8_t *dwc_cc_name(dwc_cc_if_t *cc_if, int32_t id, uint8_t *length);
++
++/** Checks a buffer for non-zero.
++ * @param id A pointer to a 16 byte buffer.
++ * @return true if the 16 byte value is non-zero. */
++static inline unsigned dwc_assoc_is_not_zero_id(uint8_t *id) {
++	int i;
++	for (i=0; i<16; i++) {
++		if (id[i]) return 1;
++	}
++	return 0;
++}
++
++/** Checks a buffer for zero.
++ * @param id A pointer to a 16 byte buffer.
++ * @return true if the 16 byte value is zero. */
++static inline unsigned dwc_assoc_is_zero_id(uint8_t *id) {
++	return !dwc_assoc_is_not_zero_id(id);
++}
++
++/** Prints an ASCII representation for the 16-byte chid, cdid, or ck, into
++ * buffer. */
++static inline int dwc_print_id_string(char *buffer, uint8_t *id) {
++	char *ptr = buffer;
++	int i;
++	for (i=0; i<16; i++) {
++		ptr += DWC_SPRINTF(ptr, "%02x", id[i]);
++		if (i < 15) {
++			ptr += DWC_SPRINTF(ptr, " ");
++		}
++	}
++	return ptr - buffer;
++}
++
++/** @} */
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* _DWC_CC_H_ */
+diff --git a/drivers/usb/gadget/udc/hiudc/dwc_common_linux.c b/drivers/usb/gadget/udc/hiudc/dwc_common_linux.c
+new file mode 100644
+index 0000000..1484a31
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc/dwc_common_linux.c
+@@ -0,0 +1,1425 @@
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/kthread.h>
++
++#ifdef DWC_CCLIB
++# include "dwc_cc.h"
++#endif
++
++#ifdef DWC_CRYPTOLIB
++# include "dwc_modpow.h"
++# include "dwc_dh.h"
++# include "dwc_crypto.h"
++#endif
++
++#ifdef DWC_NOTIFYLIB
++# include "dwc_notifier.h"
++#endif
++
++/* OS-Level Implementations */
++
++/* This is the Linux kernel implementation of the DWC platform library. */
++#include <linux/moduleparam.h>
++#include <linux/ctype.h>
++#include <linux/crypto.h>
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <linux/dma-mapping.h>
++#include <linux/cdev.h>
++#include <linux/errno.h>
++#include <linux/interrupt.h>
++#include <linux/jiffies.h>
++#include <linux/list.h>
++#include <linux/pci.h>
++#include <linux/random.h>
++#include <linux/scatterlist.h>
++#include <linux/slab.h>
++#include <linux/stat.h>
++#include <linux/string.h>
++#include <linux/timer.h>
++#include <linux/usb.h>
++
++#include <linux/version.h>
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++# include <linux/usb/gadget.h>
++#else
++# include <linux/usb_gadget.h>
++#endif
++
++#include <asm/io.h>
++#include <asm/page.h>
++#include <asm/uaccess.h>
++#include <asm/unaligned.h>
++
++#include "dwc_os.h"
++#include "dwc_list.h"
++
++
++/* MISC */
++
++void *DWC_MEMSET(void *dest, uint8_t byte, uint32_t size)
++{
++	return memset(dest, byte, size);
++}
++
++void *DWC_MEMCPY(void *dest, void const *src, uint32_t size)
++{
++	return memcpy(dest, src, size);
++}
++
++void *DWC_MEMMOVE(void *dest, void *src, uint32_t size)
++{
++	return memmove(dest, src, size);
++}
++
++int DWC_MEMCMP(void *m1, void *m2, uint32_t size)
++{
++	return memcmp(m1, m2, size);
++}
++
++int DWC_STRNCMP(void *s1, void *s2, uint32_t size)
++{
++	return strncmp(s1, s2, size);
++}
++
++int DWC_STRCMP(void *s1, void *s2)
++{
++	return strcmp(s1, s2);
++}
++
++int DWC_STRLEN(char const *str)
++{
++	return strlen(str);
++}
++
++char *DWC_STRCPY(char *to, char const *from)
++{
++	return strcpy(to, from);
++}
++
++char *DWC_STRDUP(char const *str)
++{
++	int len = DWC_STRLEN(str) + 1;
++	char *new = DWC_ALLOC_ATOMIC(len);
++
++	if (!new) {
++		return NULL;
++	}
++
++	DWC_MEMCPY(new, str, len);
++	return new;
++}
++
++int DWC_ATOI(const char *str, int32_t *value)
++{
++	char *end = NULL;
++
++	*value = simple_strtol(str, &end, 0);
++	if (*end == '\0') {
++		return 0;
++	}
++
++	return -1;
++}
++
++int DWC_ATOUI(const char *str, uint32_t *value)
++{
++	char *end = NULL;
++
++	*value = simple_strtoul(str, &end, 0);
++	if (*end == '\0') {
++		return 0;
++	}
++
++	return -1;
++}
++
++
++#ifdef DWC_UTFLIB
++/* From usbstring.c */
++
++int DWC_UTF8_TO_UTF16LE(uint8_t const *s, uint16_t *cp, unsigned len)
++{
++	int	count = 0;
++	u8	c;
++	u16	uchar;
++
++	/* this insists on correct encodings, though not minimal ones.
++	 * BUT it currently rejects legit 4-byte UTF-8 code points,
++	 * which need surrogate pairs.  (Unicode 3.1 can use them.)
++	 */
++	while (len != 0 && (c = (u8) *s++) != 0) {
++		if (unlikely(c & 0x80)) {
++			// 2-byte sequence:
++			// 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
++			if ((c & 0xe0) == 0xc0) {
++				uchar = (c & 0x1f) << 6;
++
++				c = (u8) *s++;
++				if ((c & 0xc0) != 0xc0)
++					goto fail;
++				c &= 0x3f;
++				uchar |= c;
++
++			// 3-byte sequence (most CJKV characters):
++			// zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
++			} else if ((c & 0xf0) == 0xe0) {
++				uchar = (c & 0x0f) << 12;
++
++				c = (u8) *s++;
++				if ((c & 0xc0) != 0xc0)
++					goto fail;
++				c &= 0x3f;
++				uchar |= c << 6;
++
++				c = (u8) *s++;
++				if ((c & 0xc0) != 0xc0)
++					goto fail;
++				c &= 0x3f;
++				uchar |= c;
++
++				/* no bogus surrogates */
++				if (0xd800 <= uchar && uchar <= 0xdfff)
++					goto fail;
++
++			// 4-byte sequence (surrogate pairs, currently rare):
++			// 11101110wwwwzzzzyy + 110111yyyyxxxxxx
++			//     = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
++			// (uuuuu = wwww + 1)
++			// FIXME accept the surrogate code points (only)
++			} else
++				goto fail;
++		} else
++			uchar = c;
++		put_unaligned (cpu_to_le16 (uchar), cp++);
++		count++;
++		len--;
++	}
++	return count;
++fail:
++	return -1;
++}
++#endif	/* DWC_UTFLIB */
++
++
++/* dwc_debug.h */
++
++dwc_bool_t DWC_IN_IRQ(void)
++{
++	return in_irq();
++}
++
++dwc_bool_t DWC_IN_BH(void)
++{
++	return in_softirq();
++}
++
++void DWC_VPRINTF(char *format, va_list args)
++{
++	vprintk(format, args);
++}
++
++int DWC_VSNPRINTF(char *str, int size, char *format, va_list args)
++{
++	return vsnprintf(str, size, format, args);
++}
++
++void DWC_PRINTF(char *format, ...)
++{
++	va_list args;
++
++	va_start(args, format);
++	DWC_VPRINTF(format, args);
++	va_end(args);
++}
++
++int DWC_SPRINTF(char *buffer, char *format, ...)
++{
++	int retval;
++	va_list args;
++
++	va_start(args, format);
++	retval = vsprintf(buffer, format, args);
++	va_end(args);
++	return retval;
++}
++
++int DWC_SNPRINTF(char *buffer, int size, char *format, ...)
++{
++	int retval;
++	va_list args;
++
++	va_start(args, format);
++	retval = vsnprintf(buffer, size, format, args);
++	va_end(args);
++	return retval;
++}
++
++void __DWC_WARN(char *format, ...)
++{
++	va_list args;
++
++	va_start(args, format);
++	DWC_PRINTF(KERN_WARNING);
++	DWC_VPRINTF(format, args);
++	va_end(args);
++}
++
++void __DWC_ERROR(char *format, ...)
++{
++	va_list args;
++
++	va_start(args, format);
++	DWC_PRINTF(KERN_ERR);
++	DWC_VPRINTF(format, args);
++	va_end(args);
++}
++
++void DWC_EXCEPTION(char *format, ...)
++{
++	va_list args;
++
++	va_start(args, format);
++	DWC_PRINTF(KERN_ERR);
++	DWC_VPRINTF(format, args);
++	va_end(args);
++	BUG_ON(1);
++}
++
++#ifdef DEBUG
++void __DWC_DEBUG(char *format, ...)
++{
++	va_list args;
++
++	va_start(args, format);
++	DWC_PRINTF(KERN_DEBUG);
++	DWC_VPRINTF(format, args);
++	va_end(args);
++}
++#endif
++
++
++/* dwc_mem.h */
++
++#if 0
++dwc_pool_t *DWC_DMA_POOL_CREATE(uint32_t size,
++				uint32_t align,
++				uint32_t alloc)
++{
++	struct dma_pool *pool = dma_pool_create("Pool", NULL,
++						size, align, alloc);
++	return (dwc_pool_t *)pool;
++}
++
++void DWC_DMA_POOL_DESTROY(dwc_pool_t *pool)
++{
++	dma_pool_destroy((struct dma_pool *)pool);
++}
++
++void *DWC_DMA_POOL_ALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
++{
++	return dma_pool_alloc((struct dma_pool *)pool, GFP_KERNEL, dma_addr);
++}
++
++void *DWC_DMA_POOL_ZALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
++{
++	void *vaddr = DWC_DMA_POOL_ALLOC(pool, dma_addr);
++	memset(..);
++}
++
++void DWC_DMA_POOL_FREE(dwc_pool_t *pool, void *vaddr, void *daddr)
++{
++	dma_pool_free(pool, vaddr, daddr);
++}
++#endif
++
++void *__DWC_DMA_ALLOC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr)
++{
++#ifdef xxCOSIM /* Only works for 32-bit cosim */
++	void *buf = dma_alloc_coherent(dma_ctx, (size_t)size, dma_addr, GFP_KERNEL);
++#else
++//	void *buf = dma_alloc_coherent(dma_ctx, (size_t)size, dma_addr, GFP_KERNEL | GFP_DMA32);
++	void *buf = dma_alloc_coherent(NULL, (size_t)size, dma_addr, GFP_ATOMIC);
++#endif
++	if (!buf) {
++		return NULL;
++	}
++
++	memset(buf, 0, (size_t)size);
++	return buf;
++}
++
++void *__DWC_DMA_ALLOC_ATOMIC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr)
++{
++	void *buf = dma_alloc_coherent(NULL, (size_t)size, dma_addr, GFP_ATOMIC);
++	if (!buf) {
++		return NULL;
++	}
++	memset(buf, 0, (size_t)size);
++	return buf;
++}
++
++void __DWC_DMA_FREE(void *dma_ctx, uint32_t size, void *virt_addr, dwc_dma_t dma_addr)
++{
++	dma_free_coherent(dma_ctx, size, virt_addr, dma_addr);
++}
++
++void *__DWC_ALLOC(void *mem_ctx, uint32_t size)
++{
++	return kzalloc(size, GFP_KERNEL);
++}
++
++void *__DWC_ALLOC_ATOMIC(void *mem_ctx, uint32_t size)
++{
++	return kzalloc(size, GFP_ATOMIC);
++}
++
++void __DWC_FREE(void *mem_ctx, void *addr)
++{
++	kfree(addr);
++}
++
++
++#ifdef DWC_CRYPTOLIB
++/* dwc_crypto.h */
++
++void DWC_RANDOM_BYTES(uint8_t *buffer, uint32_t length)
++{
++	get_random_bytes(buffer, length);
++}
++
++int DWC_AES_CBC(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t iv[16], uint8_t *out)
++{
++	struct crypto_blkcipher *tfm;
++	struct blkcipher_desc desc;
++	struct scatterlist sgd;
++	struct scatterlist sgs;
++
++	tfm = crypto_alloc_blkcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC);
++	if (tfm == NULL) {
++		printk("failed to load transform for aes CBC\n");
++		return -1;
++	}
++
++	crypto_blkcipher_setkey(tfm, key, keylen);
++	crypto_blkcipher_set_iv(tfm, iv, 16);
++
++	sg_init_one(&sgd, out, messagelen);
++	sg_init_one(&sgs, message, messagelen);
++
++	desc.tfm = tfm;
++	desc.flags = 0;
++
++	if (crypto_blkcipher_encrypt(&desc, &sgd, &sgs, messagelen)) {
++		crypto_free_blkcipher(tfm);
++		DWC_ERROR("AES CBC encryption failed");
++		return -1;
++	}
++
++	crypto_free_blkcipher(tfm);
++	return 0;
++}
++
++int DWC_SHA256(uint8_t *message, uint32_t len, uint8_t *out)
++{
++	struct crypto_hash *tfm;
++	struct hash_desc desc;
++	struct scatterlist sg;
++
++	tfm = crypto_alloc_hash("sha256", 0, CRYPTO_ALG_ASYNC);
++	if (IS_ERR(tfm)) {
++		DWC_ERROR("Failed to load transform for sha256: %ld\n", PTR_ERR(tfm));
++		return 0;
++	}
++	desc.tfm = tfm;
++	desc.flags = 0;
++
++	sg_init_one(&sg, message, len);
++	crypto_hash_digest(&desc, &sg, len, out);
++	crypto_free_hash(tfm);
++
++	return 1;
++}
++
++int DWC_HMAC_SHA256(uint8_t *message, uint32_t messagelen,
++		    uint8_t *key, uint32_t keylen, uint8_t *out)
++{
++	struct crypto_hash *tfm;
++	struct hash_desc desc;
++	struct scatterlist sg;
++
++	tfm = crypto_alloc_hash("hmac(sha256)", 0, CRYPTO_ALG_ASYNC);
++	if (IS_ERR(tfm)) {
++		DWC_ERROR("Failed to load transform for hmac(sha256): %ld\n", PTR_ERR(tfm));
++		return 0;
++	}
++	desc.tfm = tfm;
++	desc.flags = 0;
++
++	sg_init_one(&sg, message, messagelen);
++	crypto_hash_setkey(tfm, key, keylen);
++	crypto_hash_digest(&desc, &sg, messagelen, out);
++	crypto_free_hash(tfm);
++
++	return 1;
++}
++#endif	/* DWC_CRYPTOLIB */
++
++
++/* Byte Ordering Conversions */
++
++uint32_t DWC_CPU_TO_LE32(uint32_t *p)
++{
++#ifdef __LITTLE_ENDIAN
++	return *p;
++#else
++	uint8_t *u_p = (uint8_t *)p;
++
++	return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
++#endif
++}
++
++uint32_t DWC_CPU_TO_BE32(uint32_t *p)
++{
++#ifdef __BIG_ENDIAN
++	return *p;
++#else
++	uint8_t *u_p = (uint8_t *)p;
++
++	return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
++#endif
++}
++
++uint32_t DWC_LE32_TO_CPU(uint32_t *p)
++{
++#ifdef __LITTLE_ENDIAN
++	return *p;
++#else
++	uint8_t *u_p = (uint8_t *)p;
++
++	return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
++#endif
++}
++
++uint32_t DWC_BE32_TO_CPU(uint32_t *p)
++{
++#ifdef __BIG_ENDIAN
++	return *p;
++#else
++	uint8_t *u_p = (uint8_t *)p;
++
++	return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
++#endif
++}
++
++uint16_t DWC_CPU_TO_LE16(uint16_t *p)
++{
++#ifdef __LITTLE_ENDIAN
++	return *p;
++#else
++	uint8_t *u_p = (uint8_t *)p;
++	return (u_p[1] | (u_p[0] << 8));
++#endif
++}
++
++uint16_t DWC_CPU_TO_BE16(uint16_t *p)
++{
++#ifdef __BIG_ENDIAN
++	return *p;
++#else
++	uint8_t *u_p = (uint8_t *)p;
++	return (u_p[1] | (u_p[0] << 8));
++#endif
++}
++
++uint16_t DWC_LE16_TO_CPU(uint16_t *p)
++{
++#ifdef __LITTLE_ENDIAN
++	return *p;
++#else
++	uint8_t *u_p = (uint8_t *)p;
++	return (u_p[1] | (u_p[0] << 8));
++#endif
++}
++
++uint16_t DWC_BE16_TO_CPU(uint16_t *p)
++{
++#ifdef __BIG_ENDIAN
++	return *p;
++#else
++	uint8_t *u_p = (uint8_t *)p;
++	return (u_p[1] | (u_p[0] << 8));
++#endif
++}
++
++
++/* Registers */
++
++uint32_t DWC_READ_REG32(uint32_t volatile *reg)
++{
++	return readl(reg);
++}
++
++#if 0
++uint64_t DWC_READ_REG64(uint64_t volatile *reg)
++{
++}
++#endif
++
++void DWC_WRITE_REG32(uint32_t volatile *reg, uint32_t value)
++{
++	writel(value, reg);
++}
++
++#if 0
++void DWC_WRITE_REG64(uint64_t volatile *reg, uint64_t value)
++{
++}
++#endif
++
++void DWC_MODIFY_REG32(uint32_t volatile *reg, uint32_t clear_mask, uint32_t set_mask)
++{
++	writel((readl(reg) & ~clear_mask) | set_mask, reg);
++}
++
++#if 0
++void DWC_MODIFY_REG64(uint64_t volatile *reg, uint64_t clear_mask, uint64_t set_mask)
++{
++}
++#endif
++
++
++/* Locking */
++
++dwc_spinlock_t *DWC_SPINLOCK_ALLOC(void)
++{
++	spinlock_t *sl = (spinlock_t *)1;
++
++#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
++	sl = DWC_ALLOC(sizeof(*sl));
++	if (!sl) {
++		DWC_ERROR("Cannot allocate memory for spinlock\n");
++		return NULL;
++	}
++
++	spin_lock_init(sl);
++#endif
++	return (dwc_spinlock_t *)sl;
++}
++
++void DWC_SPINLOCK_FREE(dwc_spinlock_t *lock)
++{
++#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
++	DWC_FREE(lock);
++#endif
++}
++
++void DWC_SPINLOCK(dwc_spinlock_t *lock)
++{
++#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
++	spin_lock((spinlock_t *)lock);
++#endif
++}
++
++void DWC_SPINUNLOCK(dwc_spinlock_t *lock)
++{
++#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
++	spin_unlock((spinlock_t *)lock);
++#endif
++}
++
++void DWC_SPINLOCK_IRQSAVE(dwc_spinlock_t *lock, dwc_irqflags_t *flags)
++{
++	dwc_irqflags_t f;
++
++#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
++	spin_lock_irqsave((spinlock_t *)lock, f);
++#else
++	local_irq_save(f);
++#endif
++	*flags = f;
++}
++
++void DWC_SPINUNLOCK_IRQRESTORE(dwc_spinlock_t *lock, dwc_irqflags_t flags)
++{
++#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
++	spin_unlock_irqrestore((spinlock_t *)lock, flags);
++#else
++	local_irq_restore(flags);
++#endif
++}
++
++dwc_mutex_t *DWC_MUTEX_ALLOC(void)
++{
++	struct mutex *m;
++	dwc_mutex_t *mutex = (dwc_mutex_t *)DWC_ALLOC(sizeof(struct mutex));
++
++	if (!mutex) {
++		DWC_ERROR("Cannot allocate memory for mutex\n");
++		return NULL;
++	}
++
++	m = (struct mutex *)mutex;
++	mutex_init(m);
++	return mutex;
++}
++
++#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
++#else
++void DWC_MUTEX_FREE(dwc_mutex_t *mutex)
++{
++	mutex_destroy((struct mutex *)mutex);
++	DWC_FREE(mutex);
++}
++#endif
++
++void DWC_MUTEX_LOCK(dwc_mutex_t *mutex)
++{
++	struct mutex *m = (struct mutex *)mutex;
++	mutex_lock(m);
++}
++
++int DWC_MUTEX_TRYLOCK(dwc_mutex_t *mutex)
++{
++	struct mutex *m = (struct mutex *)mutex;
++	return mutex_trylock(m);
++}
++
++void DWC_MUTEX_UNLOCK(dwc_mutex_t *mutex)
++{
++	struct mutex *m = (struct mutex *)mutex;
++	mutex_unlock(m);
++}
++
++
++/* Timing */
++
++void DWC_UDELAY(uint32_t usecs)
++{
++	udelay(usecs);
++}
++
++void DWC_MDELAY(uint32_t msecs)
++{
++	if (in_interrupt())
++		mdelay(msecs);
++	else
++		msleep(msecs);
++}
++
++void DWC_MSLEEP(uint32_t msecs)
++{
++	msleep(msecs);
++}
++
++uint32_t DWC_TIME(void)
++{
++	return jiffies_to_msecs(jiffies);
++}
++
++
++/* Timers */
++
++struct dwc_timer {
++	struct timer_list *t;
++	char *name;
++	dwc_timer_callback_t cb;
++	void *data;
++	uint8_t scheduled;
++	dwc_spinlock_t *lock;
++};
++
++static void timer_callback(unsigned long data)
++{
++	dwc_timer_t *timer = (dwc_timer_t *)data;
++	dwc_irqflags_t flags;
++
++	DWC_SPINLOCK_IRQSAVE(timer->lock, &flags);
++	timer->scheduled = 0;
++	DWC_SPINUNLOCK_IRQRESTORE(timer->lock, flags);
++	DWC_DEBUG("Timer %s callback", timer->name);
++	timer->cb(timer->data);
++}
++
++dwc_timer_t *DWC_TIMER_ALLOC(char *name, dwc_timer_callback_t cb, void *data)
++{
++	dwc_timer_t *t = DWC_ALLOC(sizeof(*t));
++
++	if (!t) {
++		DWC_ERROR("Cannot allocate memory for timer");
++		return NULL;
++	}
++
++	t->t = DWC_ALLOC(sizeof(*t->t));
++	if (!t->t) {
++		DWC_ERROR("Cannot allocate memory for timer->t");
++		goto no_timer;
++	}
++
++	t->name = DWC_STRDUP(name);
++	if (!t->name) {
++		DWC_ERROR("Cannot allocate memory for timer->name");
++		goto no_name;
++	}
++
++	t->lock = DWC_SPINLOCK_ALLOC();
++	if (!t->lock) {
++		DWC_ERROR("Cannot allocate memory for lock");
++		goto no_lock;
++	}
++
++	t->scheduled = 0;
++	t->t->base = &boot_tvec_bases;
++	t->t->expires = jiffies;
++	setup_timer(t->t, timer_callback, (unsigned long)t);
++
++	t->cb = cb;
++	t->data = data;
++
++	return t;
++
++ no_lock:
++	DWC_FREE(t->name);
++ no_name:
++	DWC_FREE(t->t);
++ no_timer:
++	DWC_FREE(t);
++	return NULL;
++}
++
++void DWC_TIMER_FREE(dwc_timer_t *timer)
++{
++	dwc_irqflags_t flags;
++
++	DWC_SPINLOCK_IRQSAVE(timer->lock, &flags);
++
++	if (timer->scheduled) {
++		del_timer(timer->t);
++		timer->scheduled = 0;
++	}
++
++	DWC_SPINUNLOCK_IRQRESTORE(timer->lock, flags);
++	DWC_SPINLOCK_FREE(timer->lock);
++	DWC_FREE(timer->t);
++	DWC_FREE(timer->name);
++	DWC_FREE(timer);
++}
++
++void DWC_TIMER_SCHEDULE(dwc_timer_t *timer, uint32_t time)
++{
++	dwc_irqflags_t flags;
++
++	DWC_SPINLOCK_IRQSAVE(timer->lock, &flags);
++
++	if (!timer->scheduled) {
++		timer->scheduled = 1;
++		DWC_DEBUG("Scheduling timer %s to expire in +%d msec", timer->name, time);
++		timer->t->expires = jiffies + msecs_to_jiffies(time);
++		add_timer(timer->t);
++	} else {
++		DWC_DEBUG("Modifying timer %s to expire in +%d msec", timer->name, time);
++		mod_timer(timer->t, jiffies + msecs_to_jiffies(time));
++	}
++
++	DWC_SPINUNLOCK_IRQRESTORE(timer->lock, flags);
++}
++
++void DWC_TIMER_CANCEL(dwc_timer_t *timer)
++{
++	del_timer(timer->t);
++}
++
++
++/* Wait Queues */
++
++struct dwc_waitq {
++	wait_queue_head_t queue;
++	int abort;
++};
++
++dwc_waitq_t *DWC_WAITQ_ALLOC(void)
++{
++	dwc_waitq_t *wq = DWC_ALLOC(sizeof(*wq));
++
++	if (!wq) {
++		DWC_ERROR("Cannot allocate memory for waitqueue\n");
++		return NULL;
++	}
++
++	init_waitqueue_head(&wq->queue);
++	wq->abort = 0;
++	return wq;
++}
++
++void DWC_WAITQ_FREE(dwc_waitq_t *wq)
++{
++	DWC_FREE(wq);
++}
++
++int32_t DWC_WAITQ_WAIT(dwc_waitq_t *wq, dwc_waitq_condition_t cond, void *data)
++{
++	int result = wait_event_interruptible(wq->queue,
++					      cond(data) || wq->abort);
++	if (result == -ERESTARTSYS) {
++		wq->abort = 0;
++		return -DWC_E_RESTART;
++	}
++
++	if (wq->abort == 1) {
++		wq->abort = 0;
++		return -DWC_E_ABORT;
++	}
++
++	wq->abort = 0;
++
++	if (result == 0) {
++		return 0;
++	}
++
++	return -DWC_E_UNKNOWN;
++}
++
++int32_t DWC_WAITQ_WAIT_TIMEOUT(dwc_waitq_t *wq, dwc_waitq_condition_t cond,
++			       void *data, int32_t msecs)
++{
++	int32_t tmsecs;
++	int result = wait_event_interruptible_timeout(wq->queue,
++						      cond(data) || wq->abort,
++						      msecs_to_jiffies(msecs));
++	if (result == -ERESTARTSYS) {
++		wq->abort = 0;
++		return -DWC_E_RESTART;
++	}
++
++	if (wq->abort == 1) {
++		wq->abort = 0;
++		return -DWC_E_ABORT;
++	}
++
++	wq->abort = 0;
++
++	if (result > 0) {
++		tmsecs = jiffies_to_msecs(result);
++		if (!tmsecs) {
++			return 1;
++		}
++
++		return tmsecs;
++	}
++
++	if (result == 0) {
++		return -DWC_E_TIMEOUT;
++	}
++
++	return -DWC_E_UNKNOWN;
++}
++
++void DWC_WAITQ_TRIGGER(dwc_waitq_t *wq)
++{
++	wq->abort = 0;
++	wake_up_interruptible(&wq->queue);
++}
++
++void DWC_WAITQ_ABORT(dwc_waitq_t *wq)
++{
++	wq->abort = 1;
++	wake_up_interruptible(&wq->queue);
++}
++
++
++/* Threading */
++
++dwc_thread_t *DWC_THREAD_RUN(dwc_thread_function_t func, char *name, void *data)
++{
++	struct task_struct *thread = kthread_run(func, data, name);
++
++	if (thread == ERR_PTR(-ENOMEM)) {
++		return NULL;
++	}
++
++	return (dwc_thread_t *)thread;
++}
++
++int DWC_THREAD_STOP(dwc_thread_t *thread)
++{
++	return kthread_stop((struct task_struct *)thread);
++}
++
++dwc_bool_t DWC_THREAD_SHOULD_STOP(void)
++{
++	return kthread_should_stop();
++}
++
++
++/* tasklets
++ - run in interrupt context (cannot sleep)
++ - each tasklet runs on a single CPU
++ - different tasklets can be running simultaneously on different CPUs
++ */
++struct dwc_tasklet {
++	struct tasklet_struct t;
++	dwc_tasklet_callback_t cb;
++	void *data;
++};
++
++static void tasklet_callback(unsigned long data)
++{
++	dwc_tasklet_t *t = (dwc_tasklet_t *)data;
++	t->cb(t->data);
++}
++
++dwc_tasklet_t *DWC_TASK_ALLOC(char *name, dwc_tasklet_callback_t cb, void *data)
++{
++	dwc_tasklet_t *t = DWC_ALLOC(sizeof(*t));
++
++	if (t) {
++		t->cb = cb;
++		t->data = data;
++		tasklet_init(&t->t, tasklet_callback, (unsigned long)t);
++	} else {
++		DWC_ERROR("Cannot allocate memory for tasklet\n");
++	}
++
++	return t;
++}
++
++void DWC_TASK_FREE(dwc_tasklet_t *task)
++{
++	DWC_FREE(task);
++}
++
++void DWC_TASK_SCHEDULE(dwc_tasklet_t *task)
++{
++	tasklet_schedule(&task->t);
++}
++
++
++/* workqueues
++ - run in process context (can sleep)
++ */
++typedef struct work_container {
++	dwc_work_callback_t cb;
++	void *data;
++	dwc_workq_t *wq;
++	char *name;
++
++#ifdef DEBUG
++	DWC_CIRCLEQ_ENTRY(work_container) entry;
++#endif
++	struct delayed_work work;
++} work_container_t;
++
++#ifdef DEBUG
++DWC_CIRCLEQ_HEAD(work_container_queue, work_container);
++#endif
++
++struct dwc_workq {
++	struct workqueue_struct *wq;
++	dwc_spinlock_t *lock;
++	dwc_waitq_t *waitq;
++	int pending;
++
++#ifdef DEBUG
++	struct work_container_queue entries;
++#endif
++};
++
++static void do_work(struct work_struct *work)
++{
++	dwc_irqflags_t flags;
++	struct delayed_work *dw = container_of(work, struct delayed_work, work);
++	work_container_t *container = container_of(dw, struct work_container, work);
++	dwc_workq_t *wq = container->wq;
++
++	container->cb(container->data);
++
++#ifdef DEBUG
++	DWC_CIRCLEQ_REMOVE(&wq->entries, container, entry);
++#endif
++	DWC_DEBUG("Work done: %s, container=%p", container->name, container);
++	if (container->name) {
++		DWC_FREE(container->name);
++	}
++	DWC_FREE(container);
++
++	DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
++	wq->pending--;
++	DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
++	DWC_WAITQ_TRIGGER(wq->waitq);
++}
++
++static int work_done(void *data)
++{
++	dwc_workq_t *workq = (dwc_workq_t *)data;
++	return workq->pending == 0;
++}
++
++int DWC_WORKQ_WAIT_WORK_DONE(dwc_workq_t *workq, int timeout)
++{
++	return DWC_WAITQ_WAIT_TIMEOUT(workq->waitq, work_done, workq, timeout);
++}
++
++dwc_workq_t *DWC_WORKQ_ALLOC(char *name)
++{
++	dwc_workq_t *wq = DWC_ALLOC(sizeof(*wq));
++
++	if (!wq) {
++		return NULL;
++	}
++
++	wq->wq = create_singlethread_workqueue(name);
++	if (!wq->wq) {
++		goto no_wq;
++	}
++
++	wq->pending = 0;
++
++	wq->lock = DWC_SPINLOCK_ALLOC();
++	if (!wq->lock) {
++		goto no_lock;
++	}
++
++	wq->waitq = DWC_WAITQ_ALLOC();
++	if (!wq->waitq) {
++		goto no_waitq;
++	}
++
++#ifdef DEBUG
++	DWC_CIRCLEQ_INIT(&wq->entries);
++#endif
++	return wq;
++
++ no_waitq:
++	DWC_SPINLOCK_FREE(wq->lock);
++ no_lock:
++	destroy_workqueue(wq->wq);
++ no_wq:
++	DWC_FREE(wq);
++
++	return NULL;
++}
++
++void DWC_WORKQ_FREE(dwc_workq_t *wq)
++{
++#ifdef DEBUG
++	if (wq->pending != 0) {
++		struct work_container *wc;
++		DWC_ERROR("Destroying work queue with pending work");
++		DWC_CIRCLEQ_FOREACH(wc, &wq->entries, entry) {
++			DWC_ERROR("Work %s still pending", wc->name);
++		}
++	}
++#endif
++	destroy_workqueue(wq->wq);
++	DWC_SPINLOCK_FREE(wq->lock);
++	DWC_WAITQ_FREE(wq->waitq);
++	DWC_FREE(wq);
++}
++
++void DWC_WORKQ_SCHEDULE(dwc_workq_t *wq, dwc_work_callback_t cb, void *data,
++			char *format, ...)
++{
++	dwc_irqflags_t flags;
++	work_container_t *container;
++	static char name[128];
++	va_list args;
++
++	va_start(args, format);
++	DWC_VSNPRINTF(name, 128, format, args);
++	va_end(args);
++
++	DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
++	wq->pending++;
++	DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
++	DWC_WAITQ_TRIGGER(wq->waitq);
++
++	container = DWC_ALLOC_ATOMIC(sizeof(*container));
++	if (!container) {
++		DWC_ERROR("Cannot allocate memory for container\n");
++		return;
++	}
++
++	container->name = DWC_STRDUP(name);
++	if (!container->name) {
++		DWC_ERROR("Cannot allocate memory for container->name\n");
++		DWC_FREE(container);
++		return;
++	}
++
++	container->cb = cb;
++	container->data = data;
++	container->wq = wq;
++	DWC_DEBUG("Queueing work: %s, container=%p", container->name, container);
++	INIT_WORK(&container->work.work, do_work);
++
++#ifdef DEBUG
++	DWC_CIRCLEQ_INSERT_TAIL(&wq->entries, container, entry);
++#endif
++	queue_work(wq->wq, &container->work.work);
++}
++
++void DWC_WORKQ_SCHEDULE_DELAYED(dwc_workq_t *wq, dwc_work_callback_t cb,
++				void *data, uint32_t time, char *format, ...)
++{
++	dwc_irqflags_t flags;
++	work_container_t *container;
++	static char name[128];
++	va_list args;
++
++	va_start(args, format);
++	DWC_VSNPRINTF(name, 128, format, args);
++	va_end(args);
++
++	DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
++	wq->pending++;
++	DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
++	DWC_WAITQ_TRIGGER(wq->waitq);
++
++	container = DWC_ALLOC_ATOMIC(sizeof(*container));
++	if (!container) {
++		DWC_ERROR("Cannot allocate memory for container\n");
++		return;
++	}
++
++	container->name = DWC_STRDUP(name);
++	if (!container->name) {
++		DWC_ERROR("Cannot allocate memory for container->name\n");
++		DWC_FREE(container);
++		return;
++	}
++
++	container->cb = cb;
++	container->data = data;
++	container->wq = wq;
++	DWC_DEBUG("Queueing work: %s, container=%p", container->name, container);
++	INIT_DELAYED_WORK(&container->work, do_work);
++
++#ifdef DEBUG
++	DWC_CIRCLEQ_INSERT_TAIL(&wq->entries, container, entry);
++#endif
++	queue_delayed_work(wq->wq, &container->work, msecs_to_jiffies(time));
++}
++
++int DWC_WORKQ_PENDING(dwc_workq_t *wq)
++{
++	return wq->pending;
++}
++
++
++#ifdef DWC_LIBMODULE
++
++#ifdef DWC_CCLIB
++/* CC */
++EXPORT_SYMBOL(dwc_cc_if_alloc);
++EXPORT_SYMBOL(dwc_cc_if_free);
++EXPORT_SYMBOL(dwc_cc_clear);
++EXPORT_SYMBOL(dwc_cc_add);
++EXPORT_SYMBOL(dwc_cc_remove);
++EXPORT_SYMBOL(dwc_cc_change);
++EXPORT_SYMBOL(dwc_cc_data_for_save);
++EXPORT_SYMBOL(dwc_cc_restore_from_data);
++EXPORT_SYMBOL(dwc_cc_match_chid);
++EXPORT_SYMBOL(dwc_cc_match_cdid);
++EXPORT_SYMBOL(dwc_cc_ck);
++EXPORT_SYMBOL(dwc_cc_chid);
++EXPORT_SYMBOL(dwc_cc_cdid);
++EXPORT_SYMBOL(dwc_cc_name);
++#endif	/* DWC_CCLIB */
++
++#ifdef DWC_CRYPTOLIB
++# ifndef CONFIG_MACH_IPMATE
++/* Modpow */
++EXPORT_SYMBOL(dwc_modpow);
++
++/* DH */
++EXPORT_SYMBOL(dwc_dh_modpow);
++EXPORT_SYMBOL(dwc_dh_derive_keys);
++EXPORT_SYMBOL(dwc_dh_pk);
++# endif	/* CONFIG_MACH_IPMATE */
++
++/* Crypto */
++EXPORT_SYMBOL(dwc_wusb_aes_encrypt);
++EXPORT_SYMBOL(dwc_wusb_cmf);
++EXPORT_SYMBOL(dwc_wusb_prf);
++EXPORT_SYMBOL(dwc_wusb_fill_ccm_nonce);
++EXPORT_SYMBOL(dwc_wusb_gen_nonce);
++EXPORT_SYMBOL(dwc_wusb_gen_key);
++EXPORT_SYMBOL(dwc_wusb_gen_mic);
++#endif	/* DWC_CRYPTOLIB */
++
++/* Notification */
++#ifdef DWC_NOTIFYLIB
++EXPORT_SYMBOL(dwc_alloc_notification_manager);
++EXPORT_SYMBOL(dwc_free_notification_manager);
++EXPORT_SYMBOL(dwc_register_notifier);
++EXPORT_SYMBOL(dwc_unregister_notifier);
++EXPORT_SYMBOL(dwc_add_observer);
++EXPORT_SYMBOL(dwc_remove_observer);
++EXPORT_SYMBOL(dwc_notify);
++#endif
++
++/* Memory Debugging Routines */
++#ifdef DWC_DEBUG_MEMORY
++EXPORT_SYMBOL(dwc_alloc_debug);
++EXPORT_SYMBOL(dwc_alloc_atomic_debug);
++EXPORT_SYMBOL(dwc_free_debug);
++EXPORT_SYMBOL(dwc_dma_alloc_debug);
++EXPORT_SYMBOL(dwc_dma_free_debug);
++#endif
++
++EXPORT_SYMBOL(DWC_MEMSET);
++EXPORT_SYMBOL(DWC_MEMCPY);
++EXPORT_SYMBOL(DWC_MEMMOVE);
++EXPORT_SYMBOL(DWC_MEMCMP);
++EXPORT_SYMBOL(DWC_STRNCMP);
++EXPORT_SYMBOL(DWC_STRCMP);
++EXPORT_SYMBOL(DWC_STRLEN);
++EXPORT_SYMBOL(DWC_STRCPY);
++EXPORT_SYMBOL(DWC_STRDUP);
++EXPORT_SYMBOL(DWC_ATOI);
++EXPORT_SYMBOL(DWC_ATOUI);
++
++#ifdef DWC_UTFLIB
++EXPORT_SYMBOL(DWC_UTF8_TO_UTF16LE);
++#endif	/* DWC_UTFLIB */
++
++EXPORT_SYMBOL(DWC_IN_IRQ);
++EXPORT_SYMBOL(DWC_IN_BH);
++EXPORT_SYMBOL(DWC_VPRINTF);
++EXPORT_SYMBOL(DWC_VSNPRINTF);
++EXPORT_SYMBOL(DWC_PRINTF);
++EXPORT_SYMBOL(DWC_SPRINTF);
++EXPORT_SYMBOL(DWC_SNPRINTF);
++EXPORT_SYMBOL(__DWC_WARN);
++EXPORT_SYMBOL(__DWC_ERROR);
++EXPORT_SYMBOL(DWC_EXCEPTION);
++
++#ifdef DEBUG
++EXPORT_SYMBOL(__DWC_DEBUG);
++#endif
++
++EXPORT_SYMBOL(__DWC_DMA_ALLOC);
++EXPORT_SYMBOL(__DWC_DMA_ALLOC_ATOMIC);
++EXPORT_SYMBOL(__DWC_DMA_FREE);
++EXPORT_SYMBOL(__DWC_ALLOC);
++EXPORT_SYMBOL(__DWC_ALLOC_ATOMIC);
++EXPORT_SYMBOL(__DWC_FREE);
++
++#ifdef DWC_CRYPTOLIB
++EXPORT_SYMBOL(DWC_RANDOM_BYTES);
++EXPORT_SYMBOL(DWC_AES_CBC);
++EXPORT_SYMBOL(DWC_SHA256);
++EXPORT_SYMBOL(DWC_HMAC_SHA256);
++#endif
++
++EXPORT_SYMBOL(DWC_CPU_TO_LE32);
++EXPORT_SYMBOL(DWC_CPU_TO_BE32);
++EXPORT_SYMBOL(DWC_LE32_TO_CPU);
++EXPORT_SYMBOL(DWC_BE32_TO_CPU);
++EXPORT_SYMBOL(DWC_CPU_TO_LE16);
++EXPORT_SYMBOL(DWC_CPU_TO_BE16);
++EXPORT_SYMBOL(DWC_LE16_TO_CPU);
++EXPORT_SYMBOL(DWC_BE16_TO_CPU);
++EXPORT_SYMBOL(DWC_READ_REG32);
++EXPORT_SYMBOL(DWC_WRITE_REG32);
++EXPORT_SYMBOL(DWC_MODIFY_REG32);
++
++#if 0
++EXPORT_SYMBOL(DWC_READ_REG64);
++EXPORT_SYMBOL(DWC_WRITE_REG64);
++EXPORT_SYMBOL(DWC_MODIFY_REG64);
++#endif
++
++EXPORT_SYMBOL(DWC_SPINLOCK_ALLOC);
++EXPORT_SYMBOL(DWC_SPINLOCK_FREE);
++EXPORT_SYMBOL(DWC_SPINLOCK);
++EXPORT_SYMBOL(DWC_SPINUNLOCK);
++EXPORT_SYMBOL(DWC_SPINLOCK_IRQSAVE);
++EXPORT_SYMBOL(DWC_SPINUNLOCK_IRQRESTORE);
++EXPORT_SYMBOL(DWC_MUTEX_ALLOC);
++
++#if (!defined(DWC_LINUX) || !defined(CONFIG_DEBUG_MUTEXES))
++EXPORT_SYMBOL(DWC_MUTEX_FREE);
++#endif
++
++EXPORT_SYMBOL(DWC_MUTEX_LOCK);
++EXPORT_SYMBOL(DWC_MUTEX_TRYLOCK);
++EXPORT_SYMBOL(DWC_MUTEX_UNLOCK);
++EXPORT_SYMBOL(DWC_UDELAY);
++EXPORT_SYMBOL(DWC_MDELAY);
++EXPORT_SYMBOL(DWC_MSLEEP);
++EXPORT_SYMBOL(DWC_TIME);
++EXPORT_SYMBOL(DWC_TIMER_ALLOC);
++EXPORT_SYMBOL(DWC_TIMER_FREE);
++EXPORT_SYMBOL(DWC_TIMER_SCHEDULE);
++EXPORT_SYMBOL(DWC_TIMER_CANCEL);
++EXPORT_SYMBOL(DWC_WAITQ_ALLOC);
++EXPORT_SYMBOL(DWC_WAITQ_FREE);
++EXPORT_SYMBOL(DWC_WAITQ_WAIT);
++EXPORT_SYMBOL(DWC_WAITQ_WAIT_TIMEOUT);
++EXPORT_SYMBOL(DWC_WAITQ_TRIGGER);
++EXPORT_SYMBOL(DWC_WAITQ_ABORT);
++EXPORT_SYMBOL(DWC_THREAD_RUN);
++EXPORT_SYMBOL(DWC_THREAD_STOP);
++EXPORT_SYMBOL(DWC_THREAD_SHOULD_STOP);
++EXPORT_SYMBOL(DWC_TASK_ALLOC);
++EXPORT_SYMBOL(DWC_TASK_FREE);
++EXPORT_SYMBOL(DWC_TASK_SCHEDULE);
++EXPORT_SYMBOL(DWC_WORKQ_WAIT_WORK_DONE);
++EXPORT_SYMBOL(DWC_WORKQ_ALLOC);
++EXPORT_SYMBOL(DWC_WORKQ_FREE);
++EXPORT_SYMBOL(DWC_WORKQ_SCHEDULE);
++EXPORT_SYMBOL(DWC_WORKQ_SCHEDULE_DELAYED);
++EXPORT_SYMBOL(DWC_WORKQ_PENDING);
++
++static int dwc_common_port_init_module(void)
++{
++	int result = 0;
++
++	printk(KERN_DEBUG "Module dwc_common_port init\n" );
++
++#ifdef DWC_DEBUG_MEMORY
++	result = dwc_memory_debug_start(NULL);
++	if (result) {
++		printk(KERN_ERR
++		       "dwc_memory_debug_start() failed with error %d\n",
++		       result);
++		return result;
++	}
++#endif
++
++#ifdef DWC_NOTIFYLIB
++	result = dwc_alloc_notification_manager(NULL, NULL);
++	if (result) {
++		printk(KERN_ERR
++		       "dwc_alloc_notification_manager() failed with error %d\n",
++		       result);
++		return result;
++	}
++#endif
++	return result;
++}
++
++static void dwc_common_port_exit_module(void)
++{
++	printk(KERN_DEBUG "Module dwc_common_port exit\n" );
++
++#ifdef DWC_NOTIFYLIB
++	dwc_free_notification_manager();
++#endif
++
++#ifdef DWC_DEBUG_MEMORY
++	dwc_memory_debug_stop();
++#endif
++}
++
++module_init(dwc_common_port_init_module);
++module_exit(dwc_common_port_exit_module);
++
++MODULE_DESCRIPTION("DWC Common Library - Portable version");
++MODULE_AUTHOR("Synopsys Inc.");
++MODULE_LICENSE ("GPL");
++
++#endif	/* DWC_LIBMODULE */
+diff --git a/drivers/usb/gadget/udc/hiudc/dwc_crypto.c b/drivers/usb/gadget/udc/hiudc/dwc_crypto.c
+new file mode 100644
+index 0000000..3b03532
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc/dwc_crypto.c
+@@ -0,0 +1,308 @@
++/* =========================================================================
++ * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_crypto.c $
++ * $Revision: #5 $
++ * $Date: 2010/09/28 $
++ * $Change: 1596182 $
++ *
++ * Synopsys Portability Library Software and documentation
++ * (hereinafter, "Software") is an Unsupported proprietary work of
++ * Synopsys, Inc. unless otherwise expressly agreed to in writing
++ * between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product
++ * under any End User Software License Agreement or Agreement for
++ * Licensed Product with Synopsys or any supplement thereto. You are
++ * permitted to use and redistribute this Software in source and binary
++ * forms, with or without modification, provided that redistributions
++ * of source code must retain this notice. You may not view, use,
++ * disclose, copy or distribute this file or any information contained
++ * herein except pursuant to this license grant from Synopsys. If you
++ * do not agree with this notice, including the disclaimer below, then
++ * you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
++ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
++ * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
++ * SYNOPSYS 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.
++ * ========================================================================= */
++
++/** @file
++ * This file contains the WUSB cryptographic routines.
++ */
++
++#ifdef DWC_CRYPTOLIB
++
++#include "dwc_crypto.h"
++#include "usb.h"
++
++#ifdef DEBUG
++static inline void dump_bytes(char *name, uint8_t *bytes, int len)
++{
++	int i;
++	DWC_PRINTF("%s: ", name);
++	for (i=0; i<len; i++) {
++		DWC_PRINTF("%02x ", bytes[i]);
++	}
++	DWC_PRINTF("\n");
++}
++#else
++#define dump_bytes(x...)
++#endif
++
++/* Display a block */
++void show_block(const u8 *blk, const char *prefix, const char *suffix, int a)
++{
++#ifdef DWC_DEBUG_CRYPTO
++	int i, blksize = 16;
++
++	DWC_DEBUG("%s", prefix);
++
++	if (suffix == NULL) {
++		suffix = "\n";
++		blksize = a;
++	}
++
++	for (i = 0; i < blksize; i++)
++		DWC_PRINT("%02x%s", *blk++, ((i & 3) == 3) ? "  " : " ");
++	DWC_PRINT(suffix);
++#endif
++}
++
++/**
++ * Encrypts an array of bytes using the AES encryption engine.
++ * If <code>dst</code> == <code>src</code>, then the bytes will be encrypted
++ * in-place.
++ *
++ * @return  0 on success, negative error code on error.
++ */
++int dwc_wusb_aes_encrypt(u8 *src, u8 *key, u8 *dst)
++{
++	u8 block_t[16];
++	DWC_MEMSET(block_t, 0, 16);
++
++	return DWC_AES_CBC(src, 16, key, 16, block_t, dst);
++}
++
++/**
++ * The CCM-MAC-FUNCTION described in section 6.5 of the WUSB spec.
++ * This function takes a data string and returns the encrypted CBC
++ * Counter-mode MIC.
++ *
++ * @param key     The 128-bit symmetric key.
++ * @param nonce   The CCM nonce.
++ * @param label   The unique 14-byte ASCII text label.
++ * @param bytes   The byte array to be encrypted.
++ * @param len     Length of the byte array.
++ * @param result  Byte array to receive the 8-byte encrypted MIC.
++ */
++void dwc_wusb_cmf(u8 *key, u8 *nonce,
++		  char *label, u8 *bytes, int len, u8 *result)
++{
++	u8 block_m[16];
++	u8 block_x[16];
++	u8 block_t[8];
++	int idx, blkNum;
++	u16 la = (u16)(len + 14);
++
++	/* Set the AES-128 key */
++	//dwc_aes_setkey(tfm, key, 16);
++
++	/* Fill block B0 from flags = 0x59, N, and l(m) = 0 */
++	block_m[0] = 0x59;
++	for (idx = 0; idx < 13; idx++)
++		block_m[idx + 1] = nonce[idx];
++	block_m[14] = 0;
++	block_m[15] = 0;
++
++	/* Produce the CBC IV */
++	dwc_wusb_aes_encrypt(block_m, key, block_x);
++	show_block(block_m, "CBC IV in: ", "\n", 0);
++	show_block(block_x, "CBC IV out:", "\n", 0);
++
++	/* Fill block B1 from l(a) = Blen + 14, and A */
++	block_x[0] ^= (u8)(la >> 8);
++	block_x[1] ^= (u8)la;
++	for (idx = 0; idx < 14; idx++)
++		block_x[idx + 2] ^= label[idx];
++	show_block(block_x, "After xor: ", "b1\n", 16);
++
++	dwc_wusb_aes_encrypt(block_x, key, block_x);
++	show_block(block_x, "After AES: ", "b1\n", 16);
++
++	idx = 0;
++	blkNum = 0;
++
++	/* Fill remaining blocks with B */
++	while (len-- > 0) {
++		block_x[idx] ^= *bytes++;
++		if (++idx >= 16) {
++			idx = 0;
++			show_block(block_x, "After xor: ", "\n", blkNum);
++			dwc_wusb_aes_encrypt(block_x, key, block_x);
++			show_block(block_x, "After AES: ", "\n", blkNum);
++			blkNum++;
++		}
++	}
++
++	/* Handle partial last block */
++	if (idx > 0) {
++		show_block(block_x, "After xor: ", "\n", blkNum);
++		dwc_wusb_aes_encrypt(block_x, key, block_x);
++		show_block(block_x, "After AES: ", "\n", blkNum);
++	}
++
++	/* Save the MIC tag */
++	DWC_MEMCPY(block_t, block_x, 8);
++	show_block(block_t, "MIC tag  : ", NULL, 8);
++
++	/* Fill block A0 from flags = 0x01, N, and counter = 0 */
++	block_m[0] = 0x01;
++	block_m[14] = 0;
++	block_m[15] = 0;
++
++	/* Encrypt the counter */
++	dwc_wusb_aes_encrypt(block_m, key, block_x);
++	show_block(block_x, "CTR[MIC] : ", NULL, 8);
++
++	/* XOR with MIC tag */
++	for (idx = 0; idx < 8; idx++) {
++		block_t[idx] ^= block_x[idx];
++	}
++
++	/* Return result to caller */
++	DWC_MEMCPY(result, block_t, 8);
++	show_block(result, "CCM-MIC  : ", NULL, 8);
++
++}
++
++/**
++ * The PRF function described in section 6.5 of the WUSB spec. This function
++ * concatenates MIC values returned from dwc_cmf() to create a value of
++ * the requested length.
++ *
++ * @param prf_len  Length of the PRF function in bits (64, 128, or 256).
++ * @param key, nonce, label, bytes, len  Same as for dwc_cmf().
++ * @param result   Byte array to receive the result.
++ */
++void dwc_wusb_prf(int prf_len, u8 *key,
++		  u8 *nonce, char *label, u8 *bytes, int len, u8 *result)
++{
++	int i;
++
++	nonce[0] = 0;
++	for (i = 0; i < prf_len >> 6; i++, nonce[0]++) {
++		dwc_wusb_cmf(key, nonce, label, bytes, len, result);
++		result += 8;
++	}
++}
++
++/**
++ * Fills in CCM Nonce per the WUSB spec.
++ *
++ * @param[in] haddr Host address.
++ * @param[in] daddr Device address.
++ * @param[in] tkid Session Key(PTK) identifier.
++ * @param[out] nonce Pointer to where the CCM Nonce output is to be written.
++ */
++void dwc_wusb_fill_ccm_nonce(uint16_t haddr, uint16_t daddr, uint8_t *tkid,
++			     uint8_t *nonce)
++{
++
++	DWC_DEBUG("%s %x %x\n", __func__, daddr, haddr);
++
++	DWC_MEMSET(&nonce[0], 0, 16);
++
++	DWC_MEMCPY(&nonce[6], tkid, 3);
++	nonce[9] = daddr & 0xFF;
++	nonce[10] = (daddr >> 8) & 0xFF;
++	nonce[11] = haddr & 0xFF;
++	nonce[12] = (haddr >> 8) & 0xFF;
++
++	dump_bytes("CCM nonce", nonce, 16);
++}
++
++/**
++ * Generates a 16-byte cryptographic-grade random number for the Host/Device
++ * Nonce.
++ */
++void dwc_wusb_gen_nonce(uint16_t addr, uint8_t *nonce)
++{
++	uint8_t inonce[16];
++	uint32_t temp[4];
++
++	/* Fill in the Nonce */
++	DWC_MEMSET(&inonce[0], 0, sizeof(inonce));
++	inonce[9] = addr & 0xFF;
++	inonce[10] = (addr >> 8) & 0xFF;
++	inonce[11] = inonce[9];
++	inonce[12] = inonce[10];
++
++	/* Collect "randomness samples" */
++	DWC_RANDOM_BYTES((uint8_t *)temp, 16);
++
++	dwc_wusb_prf_128((uint8_t *)temp, nonce,
++			 "Random Numbers", (uint8_t *)temp, sizeof(temp),
++			 nonce);
++}
++
++/**
++ * Generates the Session Key (PTK) and Key Confirmation Key (KCK) per the
++ * WUSB spec.
++ *
++ * @param[in] ccm_nonce Pointer to CCM Nonce.
++ * @param[in] mk Master Key to derive the session from
++ * @param[in] hnonce Pointer to Host Nonce.
++ * @param[in] dnonce Pointer to Device Nonce.
++ * @param[out] kck Pointer to where the KCK output is to be written.
++ * @param[out] ptk Pointer to where the PTK output is to be written.
++ */
++void dwc_wusb_gen_key(uint8_t *ccm_nonce, uint8_t *mk, uint8_t *hnonce,
++		      uint8_t *dnonce, uint8_t *kck, uint8_t *ptk)
++{
++	uint8_t idata[32];
++	uint8_t odata[32];
++
++	dump_bytes("ck", mk, 16);
++	dump_bytes("hnonce", hnonce, 16);
++	dump_bytes("dnonce", dnonce, 16);
++
++	/* The data is the HNonce and DNonce concatenated */
++	DWC_MEMCPY(&idata[0], hnonce, 16);
++	DWC_MEMCPY(&idata[16], dnonce, 16);
++
++	dwc_wusb_prf_256(mk, ccm_nonce, "Pair-wise keys", idata, 32, odata);
++
++	/* Low 16 bytes of the result is the KCK, high 16 is the PTK */
++	DWC_MEMCPY(kck, &odata[0], 16);
++	DWC_MEMCPY(ptk, &odata[16], 16);
++
++	dump_bytes("kck", kck, 16);
++	dump_bytes("ptk", ptk, 16);
++}
++
++/**
++ * Generates the Message Integrity Code over the Handshake data per the
++ * WUSB spec.
++ *
++ * @param ccm_nonce Pointer to CCM Nonce.
++ * @param kck   Pointer to Key Confirmation Key.
++ * @param data  Pointer to Handshake data to be checked.
++ * @param mic   Pointer to where the MIC output is to be written.
++ */
++void dwc_wusb_gen_mic(uint8_t *ccm_nonce, uint8_t *kck,
++		      uint8_t *data, uint8_t *mic)
++{
++
++	dwc_wusb_prf_64(kck, ccm_nonce, "out-of-bandMIC",
++			data, WUSB_HANDSHAKE_LEN_FOR_MIC, mic);
++}
++
++#endif	/* DWC_CRYPTOLIB */
+diff --git a/drivers/usb/gadget/udc/hiudc/dwc_crypto.h b/drivers/usb/gadget/udc/hiudc/dwc_crypto.h
+new file mode 100644
+index 0000000..26fcddc
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc/dwc_crypto.h
+@@ -0,0 +1,111 @@
++/* =========================================================================
++ * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_crypto.h $
++ * $Revision: #3 $
++ * $Date: 2010/09/28 $
++ * $Change: 1596182 $
++ *
++ * Synopsys Portability Library Software and documentation
++ * (hereinafter, "Software") is an Unsupported proprietary work of
++ * Synopsys, Inc. unless otherwise expressly agreed to in writing
++ * between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product
++ * under any End User Software License Agreement or Agreement for
++ * Licensed Product with Synopsys or any supplement thereto. You are
++ * permitted to use and redistribute this Software in source and binary
++ * forms, with or without modification, provided that redistributions
++ * of source code must retain this notice. You may not view, use,
++ * disclose, copy or distribute this file or any information contained
++ * herein except pursuant to this license grant from Synopsys. If you
++ * do not agree with this notice, including the disclaimer below, then
++ * you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
++ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
++ * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
++ * SYNOPSYS 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.
++ * ========================================================================= */
++
++#ifndef _DWC_CRYPTO_H_
++#define _DWC_CRYPTO_H_
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/** @file
++ *
++ * This file contains declarations for the WUSB Cryptographic routines as
++ * defined in the WUSB spec.  They are only to be used internally by the DWC UWB
++ * modules.
++ */
++
++#include "dwc_os.h"
++
++int dwc_wusb_aes_encrypt(u8 *src, u8 *key, u8 *dst);
++
++void dwc_wusb_cmf(u8 *key, u8 *nonce,
++		  char *label, u8 *bytes, int len, u8 *result);
++void dwc_wusb_prf(int prf_len, u8 *key,
++		  u8 *nonce, char *label, u8 *bytes, int len, u8 *result);
++
++/**
++ * The PRF-64 function described in section 6.5 of the WUSB spec.
++ *
++ * @param key, nonce, label, bytes, len, result  Same as for dwc_prf().
++ */
++static inline void dwc_wusb_prf_64(u8 *key, u8 *nonce,
++				   char *label, u8 *bytes, int len, u8 *result)
++{
++	dwc_wusb_prf(64, key, nonce, label, bytes, len, result);
++}
++
++/**
++ * The PRF-128 function described in section 6.5 of the WUSB spec.
++ *
++ * @param key, nonce, label, bytes, len, result  Same as for dwc_prf().
++ */
++static inline void dwc_wusb_prf_128(u8 *key, u8 *nonce,
++				    char *label, u8 *bytes, int len, u8 *result)
++{
++	dwc_wusb_prf(128, key, nonce, label, bytes, len, result);
++}
++
++/**
++ * The PRF-256 function described in section 6.5 of the WUSB spec.
++ *
++ * @param key, nonce, label, bytes, len, result  Same as for dwc_prf().
++ */
++static inline void dwc_wusb_prf_256(u8 *key, u8 *nonce,
++				    char *label, u8 *bytes, int len, u8 *result)
++{
++	dwc_wusb_prf(256, key, nonce, label, bytes, len, result);
++}
++
++
++void dwc_wusb_fill_ccm_nonce(uint16_t haddr, uint16_t daddr, uint8_t *tkid,
++			       uint8_t *nonce);
++void dwc_wusb_gen_nonce(uint16_t addr,
++			  uint8_t *nonce);
++
++void dwc_wusb_gen_key(uint8_t *ccm_nonce, uint8_t *mk,
++			uint8_t *hnonce, uint8_t *dnonce,
++			uint8_t *kck, uint8_t *ptk);
++
++
++void dwc_wusb_gen_mic(uint8_t *ccm_nonce, uint8_t
++			*kck, uint8_t *data, uint8_t *mic);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* _DWC_CRYPTO_H_ */
+diff --git a/drivers/usb/gadget/udc/hiudc/dwc_dh.c b/drivers/usb/gadget/udc/hiudc/dwc_dh.c
+new file mode 100644
+index 0000000..2b429a3
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc/dwc_dh.c
+@@ -0,0 +1,291 @@
++/* =========================================================================
++ * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_dh.c $
++ * $Revision: #3 $
++ * $Date: 2010/09/28 $
++ * $Change: 1596182 $
++ *
++ * Synopsys Portability Library Software and documentation
++ * (hereinafter, "Software") is an Unsupported proprietary work of
++ * Synopsys, Inc. unless otherwise expressly agreed to in writing
++ * between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product
++ * under any End User Software License Agreement or Agreement for
++ * Licensed Product with Synopsys or any supplement thereto. You are
++ * permitted to use and redistribute this Software in source and binary
++ * forms, with or without modification, provided that redistributions
++ * of source code must retain this notice. You may not view, use,
++ * disclose, copy or distribute this file or any information contained
++ * herein except pursuant to this license grant from Synopsys. If you
++ * do not agree with this notice, including the disclaimer below, then
++ * you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
++ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
++ * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
++ * SYNOPSYS 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.
++ * ========================================================================= */
++#ifdef DWC_CRYPTOLIB
++
++#ifndef CONFIG_MACH_IPMATE
++
++#include "dwc_dh.h"
++#include "dwc_modpow.h"
++
++#ifdef DEBUG
++/* This function prints out a buffer in the format described in the Association
++ * Model specification. */
++static void dh_dump(char *str, void *_num, int len)
++{
++	uint8_t *num = _num;
++	int i;
++	DWC_PRINTF("%s\n", str);
++	for (i = 0; i < len; i ++) {
++		DWC_PRINTF("%02x", num[i]);
++		if (((i + 1) % 2) == 0) DWC_PRINTF(" ");
++		if (((i + 1) % 26) == 0) DWC_PRINTF("\n");
++	}
++
++	DWC_PRINTF("\n");
++}
++#else
++#define dh_dump(_x...) do {; } while(0)
++#endif
++
++/* Constant g value */
++static __u32 dh_g[] = {
++	0x02000000,
++};
++
++/* Constant p value */
++static __u32 dh_p[] = {
++	0xFFFFFFFF, 0xFFFFFFFF, 0xA2DA0FC9, 0x34C26821, 0x8B62C6C4, 0xD11CDC80, 0x084E0229, 0x74CC678A,
++	0xA6BE0B02, 0x229B133B, 0x79084A51, 0xDD04348E, 0xB31995EF, 0x1B433ACD, 0x6D0A2B30, 0x37145FF2,
++	0x6D35E14F, 0x45C2516D, 0x76B585E4, 0xC67E5E62, 0xE9424CF4, 0x6BED37A6, 0xB65CFF0B, 0xEDB706F4,
++	0xFB6B38EE, 0xA59F895A, 0x11249FAE, 0xE61F4B7C, 0x51662849, 0x3D5BE4EC, 0xB87C00C2, 0x05BF63A1,
++	0x3648DA98, 0x9AD3551C, 0xA83F1669, 0x5FCF24FD, 0x235D6583, 0x96ADA3DC, 0x56F3621C, 0xBB528520,
++	0x0729D59E, 0x6D969670, 0x4E350C67, 0x0498BC4A, 0x086C74F1, 0x7C2118CA, 0x465E9032, 0x3BCE362E,
++	0x2C779EE3, 0x03860E18, 0xA283279B, 0x8FA207EC, 0xF05DC5B5, 0xC9524C6F, 0xF6CB2BDE, 0x18175895,
++	0x7C499539, 0xE56A95EA, 0x1826D215, 0x1005FA98, 0x5A8E7215, 0x2DC4AA8A, 0x0D1733AD, 0x337A5004,
++	0xAB2155A8, 0x64BA1CDF, 0x0485FBEC, 0x0AEFDB58, 0x5771EA8A, 0x7D0C065D, 0x850F97B3, 0xC7E4E1A6,
++	0x8CAEF5AB, 0xD73309DB, 0xE0948C1E, 0x9D61254A, 0x26D2E3CE, 0x6BEED21A, 0x06FA2FF1, 0x64088AD9,
++	0x730276D8, 0x646AC83E, 0x182B1F52, 0x0C207B17, 0x5717E1BB, 0x6C5D617A, 0xC0880977, 0xE246D9BA,
++	0xA04FE208, 0x31ABE574, 0xFC5BDB43, 0x8E10FDE0, 0x20D1824B, 0xCAD23AA9, 0xFFFFFFFF, 0xFFFFFFFF,
++};
++
++static void dh_swap_bytes(void *_in, void *_out, uint32_t len)
++{
++	uint8_t *in = _in;
++	uint8_t *out = _out;
++	int i;
++	for (i=0; i<len; i++) {
++		out[i] = in[len-1-i];
++	}
++}
++
++/* Computes the modular exponentiation (num^exp % mod).  num, exp, and mod are
++ * big endian numbers of size len, in bytes.  Each len value must be a multiple
++ * of 4. */
++int dwc_dh_modpow(void *mem_ctx, void *num, uint32_t num_len,
++		  void *exp, uint32_t exp_len,
++		  void *mod, uint32_t mod_len,
++		  void *out)
++{
++	/* modpow() takes little endian numbers.  AM uses big-endian.  This
++	 * function swaps bytes of numbers before passing onto modpow. */
++
++	int retval = 0;
++	uint32_t *result;
++
++	uint32_t *bignum_num = dwc_alloc(mem_ctx, num_len + 4);
++	uint32_t *bignum_exp = dwc_alloc(mem_ctx, exp_len + 4);
++	uint32_t *bignum_mod = dwc_alloc(mem_ctx, mod_len + 4);
++
++	dh_swap_bytes(num, &bignum_num[1], num_len);
++	bignum_num[0] = num_len / 4;
++
++	dh_swap_bytes(exp, &bignum_exp[1], exp_len);
++	bignum_exp[0] = exp_len / 4;
++
++	dh_swap_bytes(mod, &bignum_mod[1], mod_len);
++	bignum_mod[0] = mod_len / 4;
++
++	result = dwc_modpow(mem_ctx, bignum_num, bignum_exp, bignum_mod);
++	if (!result) {
++		retval = -1;
++		goto dh_modpow_nomem;
++	}
++
++	dh_swap_bytes(&result[1], out, result[0] * 4);
++	dwc_free(mem_ctx, result);
++
++ dh_modpow_nomem:
++	dwc_free(mem_ctx, bignum_num);
++	dwc_free(mem_ctx, bignum_exp);
++	dwc_free(mem_ctx, bignum_mod);
++	return retval;
++}
++
++
++int dwc_dh_pk(void *mem_ctx, uint8_t nd, uint8_t *exp, uint8_t *pk, uint8_t *hash)
++{
++	int retval;
++	uint8_t m3[385];
++
++#ifndef DH_TEST_VECTORS
++	DWC_RANDOM_BYTES(exp, 32);
++#endif
++
++	/* Compute the pkd */
++	if ((retval = dwc_dh_modpow(mem_ctx, dh_g, 4,
++				    exp, 32,
++				    dh_p, 384, pk))) {
++		return retval;
++	}
++
++	m3[384] = nd;
++	DWC_MEMCPY(&m3[0], pk, 384);
++	DWC_SHA256(m3, 385, hash);
++
++	dh_dump("PK", pk, 384);
++	dh_dump("SHA-256(M3)", hash, 32);
++	return 0;
++}
++
++int dwc_dh_derive_keys(void *mem_ctx, uint8_t nd, uint8_t *pkh, uint8_t *pkd,
++		       uint8_t *exp, int is_host,
++		       char *dd, uint8_t *ck, uint8_t *kdk)
++{
++	int retval;
++	uint8_t mv[784];
++	uint8_t sha_result[32];
++	uint8_t dhkey[384];
++	uint8_t shared_secret[384];
++	char *message;
++	uint32_t vd;
++
++	uint8_t *pk;
++
++	if (is_host) {
++		pk = pkd;
++	}
++	else {
++		pk = pkh;
++	}
++
++	if ((retval = dwc_dh_modpow(mem_ctx, pk, 384,
++				    exp, 32,
++				    dh_p, 384, shared_secret))) {
++		return retval;
++	}
++	dh_dump("Shared Secret", shared_secret, 384);
++
++	DWC_SHA256(shared_secret, 384, dhkey);
++	dh_dump("DHKEY", dhkey, 384);
++
++	DWC_MEMCPY(&mv[0], pkd, 384);
++	DWC_MEMCPY(&mv[384], pkh, 384);
++	DWC_MEMCPY(&mv[768], "displayed digest", 16);
++	dh_dump("MV", mv, 784);
++
++	DWC_SHA256(mv, 784, sha_result);
++	dh_dump("SHA-256(MV)", sha_result, 32);
++	dh_dump("First 32-bits of SHA-256(MV)", sha_result, 4);
++
++	dh_swap_bytes(sha_result, &vd, 4);
++#ifdef DEBUG
++	DWC_PRINTF("Vd (decimal) = %d\n", vd);
++#endif
++
++	switch (nd) {
++	case 2:
++		vd = vd % 100;
++		DWC_SPRINTF(dd, "%02d", vd);
++		break;
++	case 3:
++		vd = vd % 1000;
++		DWC_SPRINTF(dd, "%03d", vd);
++		break;
++	case 4:
++		vd = vd % 10000;
++		DWC_SPRINTF(dd, "%04d", vd);
++		break;
++	}
++#ifdef DEBUG
++	DWC_PRINTF("Display Digits: %s\n", dd);
++#endif
++
++	message = "connection key";
++	DWC_HMAC_SHA256(message, DWC_STRLEN(message), dhkey, 32, sha_result);
++	dh_dump("HMAC(SHA-256, DHKey, connection key)", sha_result, 32);
++	DWC_MEMCPY(ck, sha_result, 16);
++
++	message = "key derivation key";
++	DWC_HMAC_SHA256(message, DWC_STRLEN(message), dhkey, 32, sha_result);
++	dh_dump("HMAC(SHA-256, DHKey, key derivation key)", sha_result, 32);
++	DWC_MEMCPY(kdk, sha_result, 32);
++
++	return 0;
++}
++
++
++#ifdef DH_TEST_VECTORS
++
++static __u8 dh_a[] = {
++	0x44, 0x00, 0x51, 0xd6,
++	0xf0, 0xb5, 0x5e, 0xa9,
++	0x67, 0xab, 0x31, 0xc6,
++	0x8a, 0x8b, 0x5e, 0x37,
++	0xd9, 0x10, 0xda, 0xe0,
++	0xe2, 0xd4, 0x59, 0xa4,
++	0x86, 0x45, 0x9c, 0xaa,
++	0xdf, 0x36, 0x75, 0x16,
++};
++
++static __u8 dh_b[] = {
++	0x5d, 0xae, 0xc7, 0x86,
++	0x79, 0x80, 0xa3, 0x24,
++	0x8c, 0xe3, 0x57, 0x8f,
++	0xc7, 0x5f, 0x1b, 0x0f,
++	0x2d, 0xf8, 0x9d, 0x30,
++	0x6f, 0xa4, 0x52, 0xcd,
++	0xe0, 0x7a, 0x04, 0x8a,
++	0xde, 0xd9, 0x26, 0x56,
++};
++
++void dwc_run_dh_test_vectors(void *mem_ctx)
++{
++	uint8_t pkd[384];
++	uint8_t pkh[384];
++	uint8_t hashd[32];
++	uint8_t hashh[32];
++	uint8_t ck[16];
++	uint8_t kdk[32];
++	char dd[5];
++
++	DWC_PRINTF("\n\n\nDH_TEST_VECTORS\n\n");
++
++	/* compute the PKd and SHA-256(PKd || Nd) */
++	DWC_PRINTF("Computing PKd\n");
++	dwc_dh_pk(mem_ctx, 2, dh_a, pkd, hashd);
++
++	/* compute the PKd and SHA-256(PKh || Nd) */
++	DWC_PRINTF("Computing PKh\n");
++	dwc_dh_pk(mem_ctx, 2, dh_b, pkh, hashh);
++
++	/* compute the dhkey */
++	dwc_dh_derive_keys(mem_ctx, 2, pkh, pkd, dh_a, 0, dd, ck, kdk);
++}
++#endif /* DH_TEST_VECTORS */
++
++#endif /* !CONFIG_MACH_IPMATE */
++
++#endif /* DWC_CRYPTOLIB */
+diff --git a/drivers/usb/gadget/udc/hiudc/dwc_dh.h b/drivers/usb/gadget/udc/hiudc/dwc_dh.h
+new file mode 100644
+index 0000000..25c1cc0
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc/dwc_dh.h
+@@ -0,0 +1,106 @@
++/* =========================================================================
++ * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_dh.h $
++ * $Revision: #4 $
++ * $Date: 2010/09/28 $
++ * $Change: 1596182 $
++ *
++ * Synopsys Portability Library Software and documentation
++ * (hereinafter, "Software") is an Unsupported proprietary work of
++ * Synopsys, Inc. unless otherwise expressly agreed to in writing
++ * between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product
++ * under any End User Software License Agreement or Agreement for
++ * Licensed Product with Synopsys or any supplement thereto. You are
++ * permitted to use and redistribute this Software in source and binary
++ * forms, with or without modification, provided that redistributions
++ * of source code must retain this notice. You may not view, use,
++ * disclose, copy or distribute this file or any information contained
++ * herein except pursuant to this license grant from Synopsys. If you
++ * do not agree with this notice, including the disclaimer below, then
++ * you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
++ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
++ * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
++ * SYNOPSYS 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.
++ * ========================================================================= */
++#ifndef _DWC_DH_H_
++#define _DWC_DH_H_
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++#include "dwc_os.h"
++
++/** @file
++ *
++ * This file defines the common functions on device and host for performing
++ * numeric association as defined in the WUSB spec.  They are only to be
++ * used internally by the DWC UWB modules. */
++
++extern int dwc_dh_sha256(uint8_t *message, uint32_t len, uint8_t *out);
++extern int dwc_dh_hmac_sha256(uint8_t *message, uint32_t messagelen,
++			      uint8_t *key, uint32_t keylen,
++			      uint8_t *out);
++extern int dwc_dh_modpow(void *mem_ctx, void *num, uint32_t num_len,
++			 void *exp, uint32_t exp_len,
++			 void *mod, uint32_t mod_len,
++			 void *out);
++
++/** Computes PKD or PKH, and SHA-256(PKd || Nd)
++ *
++ * PK = g^exp mod p.
++ *
++ * Input:
++ * Nd = Number of digits on the device.
++ *
++ * Output:
++ * exp = A 32-byte buffer to be filled with a randomly generated number.
++ *       used as either A or B.
++ * pk = A 384-byte buffer to be filled with the PKH or PKD.
++ * hash = A 32-byte buffer to be filled with SHA-256(PK || ND).
++ */
++extern int dwc_dh_pk(void *mem_ctx, uint8_t nd, uint8_t *exp, uint8_t *pkd, uint8_t *hash);
++
++/** Computes the DHKEY, and VD.
++ *
++ * If called from host, then it will comput DHKEY=PKD^exp % p.
++ * If called from device, then it will comput DHKEY=PKH^exp % p.
++ *
++ * Input:
++ * pkd = The PKD value.
++ * pkh = The PKH value.
++ * exp = The A value (if device) or B value (if host) generated in dwc_wudev_dh_pk.
++ * is_host = Set to non zero if a WUSB host is calling this function.
++ *
++ * Output:
++
++ * dd = A pointer to an buffer to be set to the displayed digits string to be shown
++ *      to the user.  This buffer should be at 5 bytes long to hold 4 digits plus a
++ *      null termination character.  This buffer can be used directly for display.
++ * ck = A 16-byte buffer to be filled with the CK.
++ * kdk = A 32-byte buffer to be filled with the KDK.
++ */
++extern int dwc_dh_derive_keys(void *mem_ctx, uint8_t nd, uint8_t *pkh, uint8_t *pkd,
++			      uint8_t *exp, int is_host,
++			      char *dd, uint8_t *ck, uint8_t *kdk);
++
++#ifdef DH_TEST_VECTORS
++extern void dwc_run_dh_test_vectors(void);
++#endif
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* _DWC_DH_H_ */
+diff --git a/drivers/usb/gadget/udc/hiudc/dwc_list.h b/drivers/usb/gadget/udc/hiudc/dwc_list.h
+new file mode 100644
+index 0000000..89cc325
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc/dwc_list.h
+@@ -0,0 +1,594 @@
++/*	$OpenBSD: queue.h,v 1.26 2004/05/04 16:59:32 grange Exp $	*/
++/*	$NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $	*/
++
++/*
++ * Copyright (c) 1991, 1993
++ *	The Regents of the University of California.  All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. Neither the name of the University nor the names of its contributors
++ *    may be used to endorse or promote products derived from this software
++ *    without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++ * SUCH DAMAGE.
++ *
++ *	@(#)queue.h	8.5 (Berkeley) 8/20/94
++ */
++
++#ifndef _DWC_LIST_H_
++#define _DWC_LIST_H_
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/** @file
++ *
++ * This file defines linked list operations.  It is derived from BSD with
++ * only the MACRO names being prefixed with DWC_.  This is because a few of
++ * these names conflict with those on Linux.  For documentation on use, see the
++ * inline comments in the source code.  The original license for this source
++ * code applies and is preserved in the dwc_list.h source file.
++ */
++
++/*
++ * This file defines five types of data structures: singly-linked lists,
++ * lists, simple queues, tail queues, and circular queues.
++ *
++ *
++ * A singly-linked list is headed by a single forward pointer. The elements
++ * are singly linked for minimum space and pointer manipulation overhead at
++ * the expense of O(n) removal for arbitrary elements. New elements can be
++ * added to the list after an existing element or at the head of the list.
++ * Elements being removed from the head of the list should use the explicit
++ * macro for this purpose for optimum efficiency. A singly-linked list may
++ * only be traversed in the forward direction.  Singly-linked lists are ideal
++ * for applications with large datasets and few or no removals or for
++ * implementing a LIFO queue.
++ *
++ * A list is headed by a single forward pointer (or an array of forward
++ * pointers for a hash table header). The elements are doubly linked
++ * so that an arbitrary element can be removed without a need to
++ * traverse the list. New elements can be added to the list before
++ * or after an existing element or at the head of the list. A list
++ * may only be traversed in the forward direction.
++ *
++ * A simple queue is headed by a pair of pointers, one the head of the
++ * list and the other to the tail of the list. The elements are singly
++ * linked to save space, so elements can only be removed from the
++ * head of the list. New elements can be added to the list before or after
++ * an existing element, at the head of the list, or at the end of the
++ * list. A simple queue may only be traversed in the forward direction.
++ *
++ * A tail queue is headed by a pair of pointers, one to the head of the
++ * list and the other to the tail of the list. The elements are doubly
++ * linked so that an arbitrary element can be removed without a need to
++ * traverse the list. New elements can be added to the list before or
++ * after an existing element, at the head of the list, or at the end of
++ * the list. A tail queue may be traversed in either direction.
++ *
++ * A circle queue is headed by a pair of pointers, one to the head of the
++ * list and the other to the tail of the list. The elements are doubly
++ * linked so that an arbitrary element can be removed without a need to
++ * traverse the list. New elements can be added to the list before or after
++ * an existing element, at the head of the list, or at the end of the list.
++ * A circle queue may be traversed in either direction, but has a more
++ * complex end of list detection.
++ *
++ * For details on the use of these macros, see the queue(3) manual page.
++ */
++
++/*
++ * Double-linked List.
++ */
++
++typedef struct dwc_list_link {
++	struct dwc_list_link *next;
++	struct dwc_list_link *prev;
++} dwc_list_link_t;
++
++#define DWC_LIST_INIT(link) do {	\
++	(link)->next = (link);		\
++	(link)->prev = (link);		\
++} while (0)
++
++#define DWC_LIST_FIRST(link)	((link)->next)
++#define DWC_LIST_LAST(link)	((link)->prev)
++#define DWC_LIST_END(link)	(link)
++#define DWC_LIST_NEXT(link)	((link)->next)
++#define DWC_LIST_PREV(link)	((link)->prev)
++#define DWC_LIST_EMPTY(link)	\
++	(DWC_LIST_FIRST(link) == DWC_LIST_END(link))
++#define DWC_LIST_ENTRY(link, type, field)			\
++	(type *)((uint8_t *)(link) - (size_t)(&((type *)0)->field))
++
++#if 0
++#define DWC_LIST_INSERT_HEAD(list, link) do {			\
++	(link)->next = (list)->next;				\
++	(link)->prev = (list);					\
++	(list)->next->prev = (link);				\
++	(list)->next = (link);					\
++} while (0)
++
++#define DWC_LIST_INSERT_TAIL(list, link) do {			\
++	(link)->next = (list);					\
++	(link)->prev = (list)->prev;				\
++	(list)->prev->next = (link);				\
++	(list)->prev = (link);					\
++} while (0)
++#else
++#define DWC_LIST_INSERT_HEAD(list, link) do {			\
++	dwc_list_link_t *__next__ = (list)->next;		\
++	__next__->prev = (link);				\
++	(link)->next = __next__;				\
++	(link)->prev = (list);					\
++	(list)->next = (link);					\
++} while (0)
++
++#define DWC_LIST_INSERT_TAIL(list, link) do {			\
++	dwc_list_link_t *__prev__ = (list)->prev;		\
++	(list)->prev = (link);					\
++	(link)->next = (list);					\
++	(link)->prev = __prev__;				\
++	__prev__->next = (link);				\
++} while (0)
++#endif
++
++#if 0
++static inline void __list_add(struct list_head *new,
++                              struct list_head *prev,
++                              struct list_head *next)
++{
++        next->prev = new;
++        new->next = next;
++        new->prev = prev;
++        prev->next = new;
++}
++
++static inline void list_add(struct list_head *new, struct list_head *head)
++{
++        __list_add(new, head, head->next);
++}
++
++static inline void list_add_tail(struct list_head *new, struct list_head *head)
++{
++        __list_add(new, head->prev, head);
++}
++
++static inline void __list_del(struct list_head * prev, struct list_head * next)
++{
++        next->prev = prev;
++        prev->next = next;
++}
++
++static inline void list_del(struct list_head *entry)
++{
++        __list_del(entry->prev, entry->next);
++        entry->next = LIST_POISON1;
++        entry->prev = LIST_POISON2;
++}
++#endif
++
++#define DWC_LIST_REMOVE(link) do {				\
++	(link)->next->prev = (link)->prev;			\
++	(link)->prev->next = (link)->next;			\
++} while (0)
++
++#define DWC_LIST_REMOVE_INIT(link) do {				\
++	DWC_LIST_REMOVE(link);					\
++	DWC_LIST_INIT(link);					\
++} while (0)
++
++#define DWC_LIST_MOVE_HEAD(list, link) do {			\
++	DWC_LIST_REMOVE(link);					\
++	DWC_LIST_INSERT_HEAD(list, link);			\
++} while (0)
++
++#define DWC_LIST_MOVE_TAIL(list, link) do {			\
++	DWC_LIST_REMOVE(link);					\
++	DWC_LIST_INSERT_TAIL(list, link);			\
++} while (0)
++
++#define DWC_LIST_FOREACH(var, list)				\
++	for((var) = DWC_LIST_FIRST(list);			\
++	    (var) != DWC_LIST_END(list);			\
++	    (var) = DWC_LIST_NEXT(var))
++
++#define DWC_LIST_FOREACH_SAFE(var, var2, list)			\
++	for((var) = DWC_LIST_FIRST(list), (var2) = DWC_LIST_NEXT(var);	\
++	    (var) != DWC_LIST_END(list);			\
++	    (var) = (var2), (var2) = DWC_LIST_NEXT(var2))
++
++#define DWC_LIST_FOREACH_REVERSE(var, list)			\
++	for((var) = DWC_LIST_LAST(list);			\
++	    (var) != DWC_LIST_END(list);			\
++	    (var) = DWC_LIST_PREV(var))
++
++/*
++ * Singly-linked List definitions.
++ */
++#define DWC_SLIST_HEAD(name, type)					\
++struct name {								\
++	struct type *slh_first;	/* first element */			\
++}
++
++#define DWC_SLIST_HEAD_INITIALIZER(head)				\
++	{ NULL }
++
++#define DWC_SLIST_ENTRY(type)						\
++struct {								\
++	struct type *sle_next;	/* next element */			\
++}
++
++/*
++ * Singly-linked List access methods.
++ */
++#define DWC_SLIST_FIRST(head)	((head)->slh_first)
++#define DWC_SLIST_END(head)		NULL
++#define DWC_SLIST_EMPTY(head)	(SLIST_FIRST(head) == SLIST_END(head))
++#define DWC_SLIST_NEXT(elm, field)	((elm)->field.sle_next)
++
++#define DWC_SLIST_FOREACH(var, head, field)				\
++	for((var) = SLIST_FIRST(head);					\
++	    (var) != SLIST_END(head);					\
++	    (var) = SLIST_NEXT(var, field))
++
++#define DWC_SLIST_FOREACH_PREVPTR(var, varp, head, field)		\
++	for((varp) = &SLIST_FIRST((head));				\
++	    ((var) = *(varp)) != SLIST_END(head);			\
++	    (varp) = &SLIST_NEXT((var), field))
++
++/*
++ * Singly-linked List functions.
++ */
++#define DWC_SLIST_INIT(head) {						\
++	SLIST_FIRST(head) = SLIST_END(head);				\
++}
++
++#define DWC_SLIST_INSERT_AFTER(slistelm, elm, field) do {		\
++	(elm)->field.sle_next = (slistelm)->field.sle_next;		\
++	(slistelm)->field.sle_next = (elm);				\
++} while (0)
++
++#define DWC_SLIST_INSERT_HEAD(head, elm, field) do {			\
++	(elm)->field.sle_next = (head)->slh_first;			\
++	(head)->slh_first = (elm);					\
++} while (0)
++
++#define DWC_SLIST_REMOVE_NEXT(head, elm, field) do {			\
++	(elm)->field.sle_next = (elm)->field.sle_next->field.sle_next;	\
++} while (0)
++
++#define DWC_SLIST_REMOVE_HEAD(head, field) do {				\
++	(head)->slh_first = (head)->slh_first->field.sle_next;		\
++} while (0)
++
++#define DWC_SLIST_REMOVE(head, elm, type, field) do {			\
++	if ((head)->slh_first == (elm)) {				\
++		SLIST_REMOVE_HEAD((head), field);			\
++	}								\
++	else {								\
++		struct type *curelm = (head)->slh_first;		\
++		while( curelm->field.sle_next != (elm) )		\
++			curelm = curelm->field.sle_next;		\
++		curelm->field.sle_next =				\
++		    curelm->field.sle_next->field.sle_next;		\
++	}								\
++} while (0)
++
++/*
++ * Simple queue definitions.
++ */
++#define DWC_SIMPLEQ_HEAD(name, type)					\
++struct name {								\
++	struct type *sqh_first;	/* first element */			\
++	struct type **sqh_last;	/* addr of last next element */		\
++}
++
++#define DWC_SIMPLEQ_HEAD_INITIALIZER(head)				\
++	{ NULL, &(head).sqh_first }
++
++#define DWC_SIMPLEQ_ENTRY(type)						\
++struct {								\
++	struct type *sqe_next;	/* next element */			\
++}
++
++/*
++ * Simple queue access methods.
++ */
++#define DWC_SIMPLEQ_FIRST(head)	    ((head)->sqh_first)
++#define DWC_SIMPLEQ_END(head)	    NULL
++#define DWC_SIMPLEQ_EMPTY(head)	    (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head))
++#define DWC_SIMPLEQ_NEXT(elm, field)    ((elm)->field.sqe_next)
++
++#define DWC_SIMPLEQ_FOREACH(var, head, field)				\
++	for((var) = SIMPLEQ_FIRST(head);				\
++	    (var) != SIMPLEQ_END(head);					\
++	    (var) = SIMPLEQ_NEXT(var, field))
++
++/*
++ * Simple queue functions.
++ */
++#define DWC_SIMPLEQ_INIT(head) do {					\
++	(head)->sqh_first = NULL;					\
++	(head)->sqh_last = &(head)->sqh_first;				\
++} while (0)
++
++#define DWC_SIMPLEQ_INSERT_HEAD(head, elm, field) do {			\
++	if (((elm)->field.sqe_next = (head)->sqh_first) == NULL)	\
++		(head)->sqh_last = &(elm)->field.sqe_next;		\
++	(head)->sqh_first = (elm);					\
++} while (0)
++
++#define DWC_SIMPLEQ_INSERT_TAIL(head, elm, field) do {			\
++	(elm)->field.sqe_next = NULL;					\
++	*(head)->sqh_last = (elm);					\
++	(head)->sqh_last = &(elm)->field.sqe_next;			\
++} while (0)
++
++#define DWC_SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do {	\
++	if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
++		(head)->sqh_last = &(elm)->field.sqe_next;		\
++	(listelm)->field.sqe_next = (elm);				\
++} while (0)
++
++#define DWC_SIMPLEQ_REMOVE_HEAD(head, field) do {			\
++	if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
++		(head)->sqh_last = &(head)->sqh_first;			\
++} while (0)
++
++/*
++ * Tail queue definitions.
++ */
++#define DWC_TAILQ_HEAD(name, type)					\
++struct name {								\
++	struct type *tqh_first;	/* first element */			\
++	struct type **tqh_last;	/* addr of last next element */		\
++}
++
++#define DWC_TAILQ_HEAD_INITIALIZER(head)				\
++	{ NULL, &(head).tqh_first }
++
++#define DWC_TAILQ_ENTRY(type)						\
++struct {								\
++	struct type *tqe_next;	/* next element */			\
++	struct type **tqe_prev;	/* address of previous next element */	\
++}
++
++/*
++ * tail queue access methods
++ */
++#define DWC_TAILQ_FIRST(head)		((head)->tqh_first)
++#define DWC_TAILQ_END(head)		NULL
++#define DWC_TAILQ_NEXT(elm, field)	((elm)->field.tqe_next)
++#define DWC_TAILQ_LAST(head, headname)					\
++	(*(((struct headname *)((head)->tqh_last))->tqh_last))
++/* XXX */
++#define DWC_TAILQ_PREV(elm, headname, field)				\
++	(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
++#define DWC_TAILQ_EMPTY(head)						\
++	(TAILQ_FIRST(head) == TAILQ_END(head))
++
++#define DWC_TAILQ_FOREACH(var, head, field)				\
++	for((var) = TAILQ_FIRST(head);					\
++	    (var) != TAILQ_END(head);					\
++	    (var) = TAILQ_NEXT(var, field))
++
++#define DWC_TAILQ_FOREACH_REVERSE(var, head, headname, field)		\
++	for((var) = TAILQ_LAST(head, headname);				\
++	    (var) != TAILQ_END(head);					\
++	    (var) = TAILQ_PREV(var, headname, field))
++
++/*
++ * Tail queue functions.
++ */
++#define DWC_TAILQ_INIT(head) do {					\
++	(head)->tqh_first = NULL;					\
++	(head)->tqh_last = &(head)->tqh_first;				\
++} while (0)
++
++#define DWC_TAILQ_INSERT_HEAD(head, elm, field) do {			\
++	if (((elm)->field.tqe_next = (head)->tqh_first) != NULL)	\
++		(head)->tqh_first->field.tqe_prev =			\
++		    &(elm)->field.tqe_next;				\
++	else								\
++		(head)->tqh_last = &(elm)->field.tqe_next;		\
++	(head)->tqh_first = (elm);					\
++	(elm)->field.tqe_prev = &(head)->tqh_first;			\
++} while (0)
++
++#define DWC_TAILQ_INSERT_TAIL(head, elm, field) do {			\
++	(elm)->field.tqe_next = NULL;					\
++	(elm)->field.tqe_prev = (head)->tqh_last;			\
++	*(head)->tqh_last = (elm);					\
++	(head)->tqh_last = &(elm)->field.tqe_next;			\
++} while (0)
++
++#define DWC_TAILQ_INSERT_AFTER(head, listelm, elm, field) do {		\
++	if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
++		(elm)->field.tqe_next->field.tqe_prev =			\
++		    &(elm)->field.tqe_next;				\
++	else								\
++		(head)->tqh_last = &(elm)->field.tqe_next;		\
++	(listelm)->field.tqe_next = (elm);				\
++	(elm)->field.tqe_prev = &(listelm)->field.tqe_next;		\
++} while (0)
++
++#define DWC_TAILQ_INSERT_BEFORE(listelm, elm, field) do {		\
++	(elm)->field.tqe_prev = (listelm)->field.tqe_prev;		\
++	(elm)->field.tqe_next = (listelm);				\
++	*(listelm)->field.tqe_prev = (elm);				\
++	(listelm)->field.tqe_prev = &(elm)->field.tqe_next;		\
++} while (0)
++
++#define DWC_TAILQ_REMOVE(head, elm, field) do {				\
++	if (((elm)->field.tqe_next) != NULL)				\
++		(elm)->field.tqe_next->field.tqe_prev =			\
++		    (elm)->field.tqe_prev;				\
++	else								\
++		(head)->tqh_last = (elm)->field.tqe_prev;		\
++	*(elm)->field.tqe_prev = (elm)->field.tqe_next;			\
++} while (0)
++
++#define DWC_TAILQ_REPLACE(head, elm, elm2, field) do {			\
++	if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL)	\
++		(elm2)->field.tqe_next->field.tqe_prev =		\
++		    &(elm2)->field.tqe_next;				\
++	else								\
++		(head)->tqh_last = &(elm2)->field.tqe_next;		\
++	(elm2)->field.tqe_prev = (elm)->field.tqe_prev;			\
++	*(elm2)->field.tqe_prev = (elm2);				\
++} while (0)
++
++/*
++ * Circular queue definitions.
++ */
++#define DWC_CIRCLEQ_HEAD(name, type)					\
++struct name {								\
++	struct type *cqh_first;		/* first element */		\
++	struct type *cqh_last;		/* last element */		\
++}
++
++#define DWC_CIRCLEQ_HEAD_INITIALIZER(head)				\
++	{ DWC_CIRCLEQ_END(&head), DWC_CIRCLEQ_END(&head) }
++
++#define DWC_CIRCLEQ_ENTRY(type)						\
++struct {								\
++	struct type *cqe_next;		/* next element */		\
++	struct type *cqe_prev;		/* previous element */		\
++}
++
++/*
++ * Circular queue access methods
++ */
++#define DWC_CIRCLEQ_FIRST(head)		((head)->cqh_first)
++#define DWC_CIRCLEQ_LAST(head)		((head)->cqh_last)
++#define DWC_CIRCLEQ_END(head)		((void *)(head))
++#define DWC_CIRCLEQ_NEXT(elm, field)	((elm)->field.cqe_next)
++#define DWC_CIRCLEQ_PREV(elm, field)	((elm)->field.cqe_prev)
++#define DWC_CIRCLEQ_EMPTY(head)						\
++	(DWC_CIRCLEQ_FIRST(head) == DWC_CIRCLEQ_END(head))
++
++#define DWC_CIRCLEQ_EMPTY_ENTRY(elm, field) (((elm)->field.cqe_next == NULL) && ((elm)->field.cqe_prev == NULL))
++
++#define DWC_CIRCLEQ_FOREACH(var, head, field)				\
++	for((var) = DWC_CIRCLEQ_FIRST(head);				\
++	    (var) != DWC_CIRCLEQ_END(head);				\
++	    (var) = DWC_CIRCLEQ_NEXT(var, field))
++
++#define DWC_CIRCLEQ_FOREACH_SAFE(var, var2, head, field)			\
++	for((var) = DWC_CIRCLEQ_FIRST(head), var2 = DWC_CIRCLEQ_NEXT(var, field); \
++	    (var) != DWC_CIRCLEQ_END(head);					\
++	    (var) = var2, var2 = DWC_CIRCLEQ_NEXT(var, field))
++
++#define DWC_CIRCLEQ_FOREACH_REVERSE(var, head, field)			\
++	for((var) = DWC_CIRCLEQ_LAST(head);				\
++	    (var) != DWC_CIRCLEQ_END(head);				\
++	    (var) = DWC_CIRCLEQ_PREV(var, field))
++
++/*
++ * Circular queue functions.
++ */
++#define DWC_CIRCLEQ_INIT(head) do {					\
++	(head)->cqh_first = DWC_CIRCLEQ_END(head);			\
++	(head)->cqh_last = DWC_CIRCLEQ_END(head);			\
++} while (0)
++
++#define DWC_CIRCLEQ_INIT_ENTRY(elm, field) do {				\
++	(elm)->field.cqe_next = NULL;					\
++	(elm)->field.cqe_prev = NULL;					\
++} while (0)
++
++#define DWC_CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do {	\
++	(elm)->field.cqe_next = (listelm)->field.cqe_next;		\
++	(elm)->field.cqe_prev = (listelm);				\
++	if ((listelm)->field.cqe_next == DWC_CIRCLEQ_END(head))		\
++		(head)->cqh_last = (elm);				\
++	else								\
++		(listelm)->field.cqe_next->field.cqe_prev = (elm);	\
++	(listelm)->field.cqe_next = (elm);				\
++} while (0)
++
++#define DWC_CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do {	\
++	(elm)->field.cqe_next = (listelm);				\
++	(elm)->field.cqe_prev = (listelm)->field.cqe_prev;		\
++	if ((listelm)->field.cqe_prev == DWC_CIRCLEQ_END(head))		\
++		(head)->cqh_first = (elm);				\
++	else								\
++		(listelm)->field.cqe_prev->field.cqe_next = (elm);	\
++	(listelm)->field.cqe_prev = (elm);				\
++} while (0)
++
++#define DWC_CIRCLEQ_INSERT_HEAD(head, elm, field) do {			\
++	(elm)->field.cqe_next = (head)->cqh_first;			\
++	(elm)->field.cqe_prev = DWC_CIRCLEQ_END(head);			\
++	if ((head)->cqh_last == DWC_CIRCLEQ_END(head))			\
++		(head)->cqh_last = (elm);				\
++	else								\
++		(head)->cqh_first->field.cqe_prev = (elm);		\
++	(head)->cqh_first = (elm);					\
++} while (0)
++
++#define DWC_CIRCLEQ_INSERT_TAIL(head, elm, field) do {			\
++	(elm)->field.cqe_next = DWC_CIRCLEQ_END(head);			\
++	(elm)->field.cqe_prev = (head)->cqh_last;			\
++	if ((head)->cqh_first == DWC_CIRCLEQ_END(head))			\
++		(head)->cqh_first = (elm);				\
++	else								\
++		(head)->cqh_last->field.cqe_next = (elm);		\
++	(head)->cqh_last = (elm);					\
++} while (0)
++
++#define DWC_CIRCLEQ_REMOVE(head, elm, field) do {			\
++	if ((elm)->field.cqe_next == DWC_CIRCLEQ_END(head))		\
++		(head)->cqh_last = (elm)->field.cqe_prev;		\
++	else								\
++		(elm)->field.cqe_next->field.cqe_prev =			\
++		    (elm)->field.cqe_prev;				\
++	if ((elm)->field.cqe_prev == DWC_CIRCLEQ_END(head))		\
++		(head)->cqh_first = (elm)->field.cqe_next;		\
++	else								\
++		(elm)->field.cqe_prev->field.cqe_next =			\
++		    (elm)->field.cqe_next;				\
++} while (0)
++
++#define DWC_CIRCLEQ_REMOVE_INIT(head, elm, field) do {			\
++	DWC_CIRCLEQ_REMOVE(head, elm, field);				\
++	DWC_CIRCLEQ_INIT_ENTRY(elm, field);				\
++} while (0)
++
++#define DWC_CIRCLEQ_REPLACE(head, elm, elm2, field) do {		\
++	if (((elm2)->field.cqe_next = (elm)->field.cqe_next) ==		\
++	    DWC_CIRCLEQ_END(head))					\
++		(head).cqh_last = (elm2);				\
++	else								\
++		(elm2)->field.cqe_next->field.cqe_prev = (elm2);	\
++	if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) ==		\
++	    DWC_CIRCLEQ_END(head))					\
++		(head).cqh_first = (elm2);				\
++	else								\
++		(elm2)->field.cqe_prev->field.cqe_next = (elm2);	\
++} while (0)
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* _DWC_LIST_H_ */
+diff --git a/drivers/usb/gadget/udc/hiudc/dwc_mem.c b/drivers/usb/gadget/udc/hiudc/dwc_mem.c
+new file mode 100644
+index 0000000..ad645ff
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc/dwc_mem.c
+@@ -0,0 +1,245 @@
++/* Memory Debugging */
++#ifdef DWC_DEBUG_MEMORY
++
++#include "dwc_os.h"
++#include "dwc_list.h"
++
++struct allocation {
++	void *addr;
++	void *ctx;
++	char *func;
++	int line;
++	uint32_t size;
++	int dma;
++	DWC_CIRCLEQ_ENTRY(allocation) entry;
++};
++
++DWC_CIRCLEQ_HEAD(allocation_queue, allocation);
++
++struct allocation_manager {
++	void *mem_ctx;
++	struct allocation_queue allocations;
++
++	/* statistics */
++	int num;
++	int num_freed;
++	int num_active;
++	uint32_t total;
++	uint32_t cur;
++	uint32_t max;
++};
++
++static struct allocation_manager *manager = NULL;
++
++static int add_allocation(void *ctx, uint32_t size, char const *func, int line, void *addr,
++			  int dma)
++{
++	struct allocation *a;
++
++	DWC_ASSERT(manager != NULL, "manager not allocated");
++
++	a = __DWC_ALLOC_ATOMIC(manager->mem_ctx, sizeof(*a));
++	if (!a) {
++		return -DWC_E_NO_MEMORY;
++	}
++
++	a->func = __DWC_ALLOC_ATOMIC(manager->mem_ctx, DWC_STRLEN(func) + 1);
++	if (!a->func) {
++		__DWC_FREE(manager->mem_ctx, a);
++		return -DWC_E_NO_MEMORY;
++	}
++
++	DWC_MEMCPY(a->func, func, DWC_STRLEN(func) + 1);
++	a->addr = addr;
++	a->ctx = ctx;
++	a->line = line;
++	a->size = size;
++	a->dma = dma;
++	DWC_CIRCLEQ_INSERT_TAIL(&manager->allocations, a, entry);
++
++	/* Update stats */
++	manager->num++;
++	manager->num_active++;
++	manager->total += size;
++	manager->cur += size;
++
++	if (manager->max < manager->cur) {
++		manager->max = manager->cur;
++	}
++
++	return 0;
++}
++
++static struct allocation *find_allocation(void *ctx, void *addr)
++{
++	struct allocation *a;
++
++	DWC_CIRCLEQ_FOREACH(a, &manager->allocations, entry) {
++		if (a->ctx == ctx && a->addr == addr) {
++			return a;
++		}
++	}
++
++	return NULL;
++}
++
++static void free_allocation(void *ctx, void *addr, char const *func, int line)
++{
++	struct allocation *a = find_allocation(ctx, addr);
++
++	if (!a) {
++		DWC_ASSERT(0,
++			   "Free of address %p that was never allocated or already freed %s:%d",
++			   addr, func, line);
++		return;
++	}
++
++	DWC_CIRCLEQ_REMOVE(&manager->allocations, a, entry);
++
++	manager->num_active--;
++	manager->num_freed++;
++	manager->cur -= a->size;
++	__DWC_FREE(manager->mem_ctx, a->func);
++	__DWC_FREE(manager->mem_ctx, a);
++}
++
++int dwc_memory_debug_start(void *mem_ctx)
++{
++	DWC_ASSERT(manager == NULL, "Memory debugging has already started\n");
++
++	if (manager) {
++		return -DWC_E_BUSY;
++	}
++
++	manager = __DWC_ALLOC(mem_ctx, sizeof(*manager));
++	if (!manager) {
++		return -DWC_E_NO_MEMORY;
++	}
++
++	DWC_CIRCLEQ_INIT(&manager->allocations);
++	manager->mem_ctx = mem_ctx;
++	manager->num = 0;
++	manager->num_freed = 0;
++	manager->num_active = 0;
++	manager->total = 0;
++	manager->cur = 0;
++	manager->max = 0;
++
++	return 0;
++}
++
++void dwc_memory_debug_stop(void)
++{
++	struct allocation *a;
++
++	dwc_memory_debug_report();
++
++	DWC_CIRCLEQ_FOREACH(a, &manager->allocations, entry) {
++		DWC_ERROR("Memory leaked from %s:%d\n", a->func, a->line);
++		free_allocation(a->ctx, a->addr, NULL, -1);
++	}
++
++	__DWC_FREE(manager->mem_ctx, manager);
++}
++
++void dwc_memory_debug_report(void)
++{
++	struct allocation *a;
++
++	DWC_PRINTF("\n\n\n----------------- Memory Debugging Report -----------------\n\n");
++	DWC_PRINTF("Num Allocations = %d\n", manager->num);
++	DWC_PRINTF("Freed = %d\n", manager->num_freed);
++	DWC_PRINTF("Active = %d\n", manager->num_active);
++	DWC_PRINTF("Current Memory Used = %d\n", manager->cur);
++	DWC_PRINTF("Total Memory Used = %d\n", manager->total);
++	DWC_PRINTF("Maximum Memory Used at Once = %d\n", manager->max);
++	DWC_PRINTF("Unfreed allocations:\n");
++
++	DWC_CIRCLEQ_FOREACH(a, &manager->allocations, entry) {
++		DWC_PRINTF("    addr=%p, size=%d from %s:%d, DMA=%d\n",
++			   a->addr, a->size, a->func, a->line, a->dma);
++	}
++}
++
++/* The replacement functions */
++void *dwc_alloc_debug(void *mem_ctx, uint32_t size, char const *func, int line)
++{
++	void *addr = __DWC_ALLOC(mem_ctx, size);
++
++	if (!addr) {
++		return NULL;
++	}
++
++	if (add_allocation(mem_ctx, size, func, line, addr, 0)) {
++		__DWC_FREE(mem_ctx, addr);
++		return NULL;
++	}
++
++	return addr;
++}
++
++void *dwc_alloc_atomic_debug(void *mem_ctx, uint32_t size, char const *func,
++			     int line)
++{
++	void *addr = __DWC_ALLOC_ATOMIC(mem_ctx, size);
++
++	if (!addr) {
++		return NULL;
++	}
++
++	if (add_allocation(mem_ctx, size, func, line, addr, 0)) {
++		__DWC_FREE(mem_ctx, addr);
++		return NULL;
++	}
++
++	return addr;
++}
++
++void dwc_free_debug(void *mem_ctx, void *addr, char const *func, int line)
++{
++	free_allocation(mem_ctx, addr, func, line);
++	__DWC_FREE(mem_ctx, addr);
++}
++
++void *dwc_dma_alloc_debug(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr,
++			  char const *func, int line)
++{
++	void *addr = __DWC_DMA_ALLOC(dma_ctx, size, dma_addr);
++
++	if (!addr) {
++		return NULL;
++	}
++
++	if (add_allocation(dma_ctx, size, func, line, addr, 1)) {
++		__DWC_DMA_FREE(dma_ctx, size, addr, *dma_addr);
++		return NULL;
++	}
++
++	return addr;
++}
++
++void *dwc_dma_alloc_atomic_debug(void *dma_ctx, uint32_t size,
++				 dwc_dma_t *dma_addr, char const *func, int line)
++{
++	void *addr = __DWC_DMA_ALLOC_ATOMIC(dma_ctx, size, dma_addr);
++
++	if (!addr) {
++		return NULL;
++	}
++
++	if (add_allocation(dma_ctx, size, func, line, addr, 1)) {
++		__DWC_DMA_FREE(dma_ctx, size, addr, *dma_addr);
++		return NULL;
++	}
++
++	return addr;
++}
++
++void dwc_dma_free_debug(void *dma_ctx, uint32_t size, void *virt_addr,
++			dwc_dma_t dma_addr, char const *func, int line)
++{
++	free_allocation(dma_ctx, virt_addr, func, line);
++	__DWC_DMA_FREE(dma_ctx, size, virt_addr, dma_addr);
++}
++
++#endif /* DWC_DEBUG_MEMORY */
+diff --git a/drivers/usb/gadget/udc/hiudc/dwc_modpow.c b/drivers/usb/gadget/udc/hiudc/dwc_modpow.c
+new file mode 100644
+index 0000000..307dbdf
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc/dwc_modpow.c
+@@ -0,0 +1,633 @@
++/* Bignum routines adapted from PUTTY sources.  PuTTY copyright notice follows.
++ *
++ * PuTTY is copyright 1997-2007 Simon Tatham.
++ *
++ * Portions copyright Robert de Bath, Joris van Rantwijk, Delian
++ * Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas Barry,
++ * Justin Bradford, Ben Harris, Malcolm Smith, Ahmad Khalifa, Markus
++ * Kuhn, and CORE SDI S.A.
++ *
++ * Permission is hereby granted, free of charge, to any person
++ * obtaining a copy of this software and associated documentation files
++ * (the "Software"), to deal in the Software without restriction,
++ * including without limitation the rights to use, copy, modify, merge,
++ * publish, distribute, sublicense, and/or sell copies of the Software,
++ * and to permit persons to whom the Software is furnished to do so,
++ * subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be
++ * included in all copies or substantial portions of the Software.
++
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
++ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
++ * NONINFRINGEMENT.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE
++ * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
++ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
++ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
++ *
++ */
++#ifdef DWC_CRYPTOLIB
++
++#ifndef CONFIG_MACH_IPMATE
++
++#include "dwc_modpow.h"
++
++#define BIGNUM_INT_MASK  0xFFFFFFFFUL
++#define BIGNUM_TOP_BIT   0x80000000UL
++#define BIGNUM_INT_BITS  32
++
++
++static void *snmalloc(void *mem_ctx, size_t n, size_t size)
++{
++    void *p;
++    size *= n;
++    if (size == 0) size = 1;
++    p = dwc_alloc(mem_ctx, size);
++    return p;
++}
++
++#define snewn(ctx, n, type) ((type *)snmalloc((ctx), (n), sizeof(type)))
++#define sfree dwc_free
++
++/*
++ * Usage notes:
++ *  * Do not call the DIVMOD_WORD macro with expressions such as array
++ *    subscripts, as some implementations object to this (see below).
++ *  * Note that none of the division methods below will cope if the
++ *    quotient won't fit into BIGNUM_INT_BITS. Callers should be careful
++ *    to avoid this case.
++ *    If this condition occurs, in the case of the x86 DIV instruction,
++ *    an overflow exception will occur, which (according to a correspondent)
++ *    will manifest on Windows as something like
++ *      0xC0000095: Integer overflow
++ *    The C variant won't give the right answer, either.
++ */
++
++#define MUL_WORD(w1, w2) ((BignumDblInt)w1 * w2)
++
++#if defined __GNUC__ && defined __i386__
++#define DIVMOD_WORD(q, r, hi, lo, w) \
++    __asm__("div %2" : \
++	    "=d" (r), "=a" (q) : \
++	    "r" (w), "d" (hi), "a" (lo))
++#else
++#define DIVMOD_WORD(q, r, hi, lo, w) do { \
++    BignumDblInt n = (((BignumDblInt)hi) << BIGNUM_INT_BITS) | lo; \
++    q = n / w; \
++    r = n % w; \
++} while (0)
++#endif
++
++#define BIGNUM_INT_BYTES (BIGNUM_INT_BITS / 8)
++
++#define BIGNUM_INTERNAL
++
++static Bignum newbn(void *mem_ctx, int length)
++{
++    Bignum b = snewn(mem_ctx, length + 1, BignumInt);
++    //if (!b)
++    //abort();		       /* FIXME */
++    DWC_MEMSET(b, 0, (length + 1) * sizeof(*b));
++    b[0] = length;
++    return b;
++}
++
++void freebn(void *mem_ctx, Bignum b)
++{
++    /*
++     * Burn the evidence, just in case.
++     */
++    DWC_MEMSET(b, 0, sizeof(b[0]) * (b[0] + 1));
++    sfree(mem_ctx, b);
++}
++
++/*
++ * Compute c = a * b.
++ * Input is in the first len words of a and b.
++ * Result is returned in the first 2*len words of c.
++ */
++static void internal_mul(BignumInt *a, BignumInt *b,
++			 BignumInt *c, int len)
++{
++    int i, j;
++    BignumDblInt t;
++
++    for (j = 0; j < 2 * len; j++)
++	c[j] = 0;
++
++    for (i = len - 1; i >= 0; i--) {
++	t = 0;
++	for (j = len - 1; j >= 0; j--) {
++	    t += MUL_WORD(a[i], (BignumDblInt) b[j]);
++	    t += (BignumDblInt) c[i + j + 1];
++	    c[i + j + 1] = (BignumInt) t;
++	    t = t >> BIGNUM_INT_BITS;
++	}
++	c[i] = (BignumInt) t;
++    }
++}
++
++static void internal_add_shifted(BignumInt *number,
++				 unsigned n, int shift)
++{
++    int word = 1 + (shift / BIGNUM_INT_BITS);
++    int bshift = shift % BIGNUM_INT_BITS;
++    BignumDblInt addend;
++
++    addend = (BignumDblInt)n << bshift;
++
++    while (addend) {
++	addend += number[word];
++	number[word] = (BignumInt) addend & BIGNUM_INT_MASK;
++	addend >>= BIGNUM_INT_BITS;
++	word++;
++    }
++}
++
++/*
++ * Compute a = a % m.
++ * Input in first alen words of a and first mlen words of m.
++ * Output in first alen words of a
++ * (of which first alen-mlen words will be zero).
++ * The MSW of m MUST have its high bit set.
++ * Quotient is accumulated in the `quotient' array, which is a Bignum
++ * rather than the internal bigendian format. Quotient parts are shifted
++ * left by `qshift' before adding into quot.
++ */
++static void internal_mod(BignumInt *a, int alen,
++			 BignumInt *m, int mlen,
++			 BignumInt *quot, int qshift)
++{
++    BignumInt m0, m1;
++    unsigned int h;
++    int i, k;
++
++    m0 = m[0];
++    if (mlen > 1)
++	m1 = m[1];
++    else
++	m1 = 0;
++
++    for (i = 0; i <= alen - mlen; i++) {
++	BignumDblInt t;
++	unsigned int q, r, c, ai1;
++
++	if (i == 0) {
++	    h = 0;
++	} else {
++	    h = a[i - 1];
++	    a[i - 1] = 0;
++	}
++
++	if (i == alen - 1)
++	    ai1 = 0;
++	else
++	    ai1 = a[i + 1];
++
++	/* Find q = h:a[i] / m0 */
++	if (h >= m0) {
++	    /*
++	     * Special case.
++	     *
++	     * To illustrate it, suppose a BignumInt is 8 bits, and
++	     * we are dividing (say) A1:23:45:67 by A1:B2:C3. Then
++	     * our initial division will be 0xA123 / 0xA1, which
++	     * will give a quotient of 0x100 and a divide overflow.
++	     * However, the invariants in this division algorithm
++	     * are not violated, since the full number A1:23:... is
++	     * _less_ than the quotient prefix A1:B2:... and so the
++	     * following correction loop would have sorted it out.
++	     *
++	     * In this situation we set q to be the largest
++	     * quotient we _can_ stomach (0xFF, of course).
++	     */
++	    q = BIGNUM_INT_MASK;
++	} else {
++	    /* Macro doesn't want an array subscript expression passed
++	     * into it (see definition), so use a temporary. */
++	    BignumInt tmplo = a[i];
++	    DIVMOD_WORD(q, r, h, tmplo, m0);
++
++	    /* Refine our estimate of q by looking at
++	     h:a[i]:a[i+1] / m0:m1 */
++	    t = MUL_WORD(m1, q);
++	    if (t > ((BignumDblInt) r << BIGNUM_INT_BITS) + ai1) {
++		q--;
++		t -= m1;
++		r = (r + m0) & BIGNUM_INT_MASK;     /* overflow? */
++		if (r >= (BignumDblInt) m0 &&
++		    t > ((BignumDblInt) r << BIGNUM_INT_BITS) + ai1) q--;
++	    }
++	}
++
++	/* Subtract q * m from a[i...] */
++	c = 0;
++	for (k = mlen - 1; k >= 0; k--) {
++	    t = MUL_WORD(q, m[k]);
++	    t += c;
++	    c = (unsigned)(t >> BIGNUM_INT_BITS);
++	    if ((BignumInt) t > a[i + k])
++		c++;
++	    a[i + k] -= (BignumInt) t;
++	}
++
++	/* Add back m in case of borrow */
++	if (c != h) {
++	    t = 0;
++	    for (k = mlen - 1; k >= 0; k--) {
++		t += m[k];
++		t += a[i + k];
++		a[i + k] = (BignumInt) t;
++		t = t >> BIGNUM_INT_BITS;
++	    }
++	    q--;
++	}
++	if (quot)
++	    internal_add_shifted(quot, q, qshift + BIGNUM_INT_BITS * (alen - mlen - i));
++    }
++}
++
++/*
++ * Compute p % mod.
++ * The most significant word of mod MUST be non-zero.
++ * We assume that the result array is the same size as the mod array.
++ * We optionally write out a quotient if `quotient' is non-NULL.
++ * We can avoid writing out the result if `result' is NULL.
++ */
++void bigdivmod(void *mem_ctx, Bignum p, Bignum mod, Bignum result, Bignum quotient)
++{
++    BignumInt *n, *m;
++    int mshift;
++    int plen, mlen, i, j;
++
++    /* Allocate m of size mlen, copy mod to m */
++    /* We use big endian internally */
++    mlen = mod[0];
++    m = snewn(mem_ctx, mlen, BignumInt);
++    //if (!m)
++    //abort();		       /* FIXME */
++    for (j = 0; j < mlen; j++)
++	m[j] = mod[mod[0] - j];
++
++    /* Shift m left to make msb bit set */
++    for (mshift = 0; mshift < BIGNUM_INT_BITS-1; mshift++)
++	if ((m[0] << mshift) & BIGNUM_TOP_BIT)
++	    break;
++    if (mshift) {
++	for (i = 0; i < mlen - 1; i++)
++	    m[i] = (m[i] << mshift) | (m[i + 1] >> (BIGNUM_INT_BITS - mshift));
++	m[mlen - 1] = m[mlen - 1] << mshift;
++    }
++
++    plen = p[0];
++    /* Ensure plen > mlen */
++    if (plen <= mlen)
++	plen = mlen + 1;
++
++    /* Allocate n of size plen, copy p to n */
++    n = snewn(mem_ctx, plen, BignumInt);
++    //if (!n)
++    //abort();		       /* FIXME */
++    for (j = 0; j < plen; j++)
++	n[j] = 0;
++    for (j = 1; j <= (int)p[0]; j++)
++	n[plen - j] = p[j];
++
++    /* Main computation */
++    internal_mod(n, plen, m, mlen, quotient, mshift);
++
++    /* Fixup result in case the modulus was shifted */
++    if (mshift) {
++	for (i = plen - mlen - 1; i < plen - 1; i++)
++	    n[i] = (n[i] << mshift) | (n[i + 1] >> (BIGNUM_INT_BITS - mshift));
++	n[plen - 1] = n[plen - 1] << mshift;
++	internal_mod(n, plen, m, mlen, quotient, 0);
++	for (i = plen - 1; i >= plen - mlen; i--)
++	    n[i] = (n[i] >> mshift) | (n[i - 1] << (BIGNUM_INT_BITS - mshift));
++    }
++
++    /* Copy result to buffer */
++    if (result) {
++	for (i = 1; i <= (int)result[0]; i++) {
++	    int j = plen - i;
++	    result[i] = j >= 0 ? n[j] : 0;
++	}
++    }
++
++    /* Free temporary arrays */
++    for (i = 0; i < mlen; i++)
++	m[i] = 0;
++    sfree(mem_ctx, m);
++    for (i = 0; i < plen; i++)
++	n[i] = 0;
++    sfree(mem_ctx, n);
++}
++
++/*
++ * Simple remainder.
++ */
++Bignum bigmod(void *mem_ctx, Bignum a, Bignum b)
++{
++    Bignum r = newbn(mem_ctx, b[0]);
++    bigdivmod(mem_ctx, a, b, r, NULL);
++    return r;
++}
++
++/*
++ * Compute (base ^ exp) % mod.
++ */
++Bignum dwc_modpow(void *mem_ctx, Bignum base_in, Bignum exp, Bignum mod)
++{
++    BignumInt *a, *b, *n, *m;
++    int mshift;
++    int mlen, i, j;
++    Bignum base, result;
++
++    /*
++     * The most significant word of mod needs to be non-zero. It
++     * should already be, but let's make sure.
++     */
++    //assert(mod[mod[0]] != 0);
++
++    /*
++     * Make sure the base is smaller than the modulus, by reducing
++     * it modulo the modulus if not.
++     */
++    base = bigmod(mem_ctx, base_in, mod);
++
++    /* Allocate m of size mlen, copy mod to m */
++    /* We use big endian internally */
++    mlen = mod[0];
++    m = snewn(mem_ctx, mlen, BignumInt);
++    //if (!m)
++    //abort();		       /* FIXME */
++    for (j = 0; j < mlen; j++)
++	m[j] = mod[mod[0] - j];
++
++    /* Shift m left to make msb bit set */
++    for (mshift = 0; mshift < BIGNUM_INT_BITS - 1; mshift++)
++	if ((m[0] << mshift) & BIGNUM_TOP_BIT)
++	    break;
++    if (mshift) {
++	for (i = 0; i < mlen - 1; i++)
++	    m[i] =
++		(m[i] << mshift) | (m[i + 1] >>
++				    (BIGNUM_INT_BITS - mshift));
++	m[mlen - 1] = m[mlen - 1] << mshift;
++    }
++
++    /* Allocate n of size mlen, copy base to n */
++    n = snewn(mem_ctx, mlen, BignumInt);
++    //if (!n)
++    //abort();		       /* FIXME */
++    i = mlen - base[0];
++    for (j = 0; j < i; j++)
++	n[j] = 0;
++    for (j = 0; j < base[0]; j++)
++	n[i + j] = base[base[0] - j];
++
++    /* Allocate a and b of size 2*mlen. Set a = 1 */
++    a = snewn(mem_ctx, 2 * mlen, BignumInt);
++    //if (!a)
++    //abort();		       /* FIXME */
++    b = snewn(mem_ctx, 2 * mlen, BignumInt);
++    //if (!b)
++    //abort();		       /* FIXME */
++    for (i = 0; i < 2 * mlen; i++)
++	a[i] = 0;
++    a[2 * mlen - 1] = 1;
++
++    /* Skip leading zero bits of exp. */
++    i = 0;
++    j = BIGNUM_INT_BITS - 1;
++    while (i < exp[0] && (exp[exp[0] - i] & (1 << j)) == 0) {
++	j--;
++	if (j < 0) {
++	    i++;
++	    j = BIGNUM_INT_BITS - 1;
++	}
++    }
++
++    /* Main computation */
++    while (i < exp[0]) {
++	while (j >= 0) {
++	    internal_mul(a + mlen, a + mlen, b, mlen);
++	    internal_mod(b, mlen * 2, m, mlen, NULL, 0);
++	    if ((exp[exp[0] - i] & (1 << j)) != 0) {
++		internal_mul(b + mlen, n, a, mlen);
++		internal_mod(a, mlen * 2, m, mlen, NULL, 0);
++	    } else {
++		BignumInt *t;
++		t = a;
++		a = b;
++		b = t;
++	    }
++	    j--;
++	}
++	i++;
++	j = BIGNUM_INT_BITS - 1;
++    }
++
++    /* Fixup result in case the modulus was shifted */
++    if (mshift) {
++	for (i = mlen - 1; i < 2 * mlen - 1; i++)
++	    a[i] =
++		(a[i] << mshift) | (a[i + 1] >>
++				    (BIGNUM_INT_BITS - mshift));
++	a[2 * mlen - 1] = a[2 * mlen - 1] << mshift;
++	internal_mod(a, mlen * 2, m, mlen, NULL, 0);
++	for (i = 2 * mlen - 1; i >= mlen; i--)
++	    a[i] =
++		(a[i] >> mshift) | (a[i - 1] <<
++				    (BIGNUM_INT_BITS - mshift));
++    }
++
++    /* Copy result to buffer */
++    result = newbn(mem_ctx, mod[0]);
++    for (i = 0; i < mlen; i++)
++	result[result[0] - i] = a[i + mlen];
++    while (result[0] > 1 && result[result[0]] == 0)
++	result[0]--;
++
++    /* Free temporary arrays */
++    for (i = 0; i < 2 * mlen; i++)
++	a[i] = 0;
++    sfree(mem_ctx, a);
++    for (i = 0; i < 2 * mlen; i++)
++	b[i] = 0;
++    sfree(mem_ctx, b);
++    for (i = 0; i < mlen; i++)
++	m[i] = 0;
++    sfree(mem_ctx, m);
++    for (i = 0; i < mlen; i++)
++	n[i] = 0;
++    sfree(mem_ctx, n);
++
++    freebn(mem_ctx, base);
++
++    return result;
++}
++
++
++#ifdef UNITTEST
++
++static __u32 dh_p[] = {
++	96,
++	0xFFFFFFFF,
++	0xFFFFFFFF,
++	0xA93AD2CA,
++	0x4B82D120,
++	0xE0FD108E,
++	0x43DB5BFC,
++	0x74E5AB31,
++	0x08E24FA0,
++	0xBAD946E2,
++	0x770988C0,
++	0x7A615D6C,
++	0xBBE11757,
++	0x177B200C,
++	0x521F2B18,
++	0x3EC86A64,
++	0xD8760273,
++	0xD98A0864,
++	0xF12FFA06,
++	0x1AD2EE6B,
++	0xCEE3D226,
++	0x4A25619D,
++	0x1E8C94E0,
++	0xDB0933D7,
++	0xABF5AE8C,
++	0xA6E1E4C7,
++	0xB3970F85,
++	0x5D060C7D,
++	0x8AEA7157,
++	0x58DBEF0A,
++	0xECFB8504,
++	0xDF1CBA64,
++	0xA85521AB,
++	0x04507A33,
++	0xAD33170D,
++	0x8AAAC42D,
++	0x15728E5A,
++	0x98FA0510,
++	0x15D22618,
++	0xEA956AE5,
++	0x3995497C,
++	0x95581718,
++	0xDE2BCBF6,
++	0x6F4C52C9,
++	0xB5C55DF0,
++	0xEC07A28F,
++	0x9B2783A2,
++	0x180E8603,
++	0xE39E772C,
++	0x2E36CE3B,
++	0x32905E46,
++	0xCA18217C,
++	0xF1746C08,
++	0x4ABC9804,
++	0x670C354E,
++	0x7096966D,
++	0x9ED52907,
++	0x208552BB,
++	0x1C62F356,
++	0xDCA3AD96,
++	0x83655D23,
++	0xFD24CF5F,
++	0x69163FA8,
++	0x1C55D39A,
++	0x98DA4836,
++	0xA163BF05,
++	0xC2007CB8,
++	0xECE45B3D,
++	0x49286651,
++	0x7C4B1FE6,
++	0xAE9F2411,
++	0x5A899FA5,
++	0xEE386BFB,
++	0xF406B7ED,
++	0x0BFF5CB6,
++	0xA637ED6B,
++	0xF44C42E9,
++	0x625E7EC6,
++	0xE485B576,
++	0x6D51C245,
++	0x4FE1356D,
++	0xF25F1437,
++	0x302B0A6D,
++	0xCD3A431B,
++	0xEF9519B3,
++	0x8E3404DD,
++	0x514A0879,
++	0x3B139B22,
++	0x020BBEA6,
++	0x8A67CC74,
++	0x29024E08,
++	0x80DC1CD1,
++	0xC4C6628B,
++	0x2168C234,
++	0xC90FDAA2,
++	0xFFFFFFFF,
++	0xFFFFFFFF,
++};
++
++static __u32 dh_a[] = {
++	8,
++	0xdf367516,
++	0x86459caa,
++	0xe2d459a4,
++	0xd910dae0,
++	0x8a8b5e37,
++	0x67ab31c6,
++	0xf0b55ea9,
++	0x440051d6,
++};
++
++static __u32 dh_b[] = {
++	8,
++	0xded92656,
++	0xe07a048a,
++	0x6fa452cd,
++	0x2df89d30,
++	0xc75f1b0f,
++	0x8ce3578f,
++	0x7980a324,
++	0x5daec786,
++};
++
++static __u32 dh_g[] = {
++	1,
++	2,
++};
++
++int main(void)
++{
++	int i;
++	__u32 *k;
++	k = dwc_modpow(NULL, dh_g, dh_a, dh_p);
++
++	printf("\n\n");
++	for (i=0; i<k[0]; i++) {
++		__u32 word32 = k[k[0] - i];
++		__u16 l = word32 & 0xffff;
++		__u16 m = (word32 & 0xffff0000) >> 16;
++		printf("%04x %04x ", m, l);
++		if (!((i + 1)%13)) printf("\n");
++	}
++	printf("\n\n");
++
++	if ((k[0] == 0x60) && (k[1] == 0x28e490e5) && (k[0x60] == 0x5a0d3d4e)) {
++		printf("PASS\n\n");
++	}
++	else {
++		printf("FAIL\n\n");
++	}
++
++}
++
++#endif /* UNITTEST */
++
++#endif /* CONFIG_MACH_IPMATE */
++
++#endif /*DWC_CRYPTOLIB */
+diff --git a/drivers/usb/gadget/udc/hiudc/dwc_modpow.h b/drivers/usb/gadget/udc/hiudc/dwc_modpow.h
+new file mode 100644
+index 0000000..64f00c2
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc/dwc_modpow.h
+@@ -0,0 +1,34 @@
++/*
++ * dwc_modpow.h
++ * See dwc_modpow.c for license and changes
++ */
++#ifndef _DWC_MODPOW_H
++#define _DWC_MODPOW_H
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++#include "dwc_os.h"
++
++/** @file
++ *
++ * This file defines the module exponentiation function which is only used
++ * internally by the DWC UWB modules for calculation of PKs during numeric
++ * association.  The routine is taken from the PUTTY, an open source terminal
++ * emulator.  The PUTTY License is preserved in the dwc_modpow.c file.
++ *
++ */
++
++typedef uint32_t BignumInt;
++typedef uint64_t BignumDblInt;
++typedef BignumInt *Bignum;
++
++/* Compute modular exponentiaion */
++extern Bignum dwc_modpow(void *mem_ctx, Bignum base_in, Bignum exp, Bignum mod);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* _LINUX_BIGNUM_H */
+diff --git a/drivers/usb/gadget/udc/hiudc/dwc_notifier.c b/drivers/usb/gadget/udc/hiudc/dwc_notifier.c
+new file mode 100644
+index 0000000..d3dadce
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc/dwc_notifier.c
+@@ -0,0 +1,319 @@
++#ifdef DWC_NOTIFYLIB
++
++#include "dwc_notifier.h"
++#include "dwc_list.h"
++
++typedef struct dwc_observer {
++	void *observer;
++	dwc_notifier_callback_t callback;
++	void *data;
++	char *notification;
++	DWC_CIRCLEQ_ENTRY(dwc_observer) list_entry;
++} observer_t;
++
++DWC_CIRCLEQ_HEAD(observer_queue, dwc_observer);
++
++typedef struct dwc_notifier {
++	void *mem_ctx;
++	void *object;
++	struct observer_queue observers;
++	DWC_CIRCLEQ_ENTRY(dwc_notifier) list_entry;
++} notifier_t;
++
++DWC_CIRCLEQ_HEAD(notifier_queue, dwc_notifier);
++
++typedef struct manager {
++	void *mem_ctx;
++	void *wkq_ctx;
++	dwc_workq_t *wq;
++//	dwc_mutex_t *mutex;
++	struct notifier_queue notifiers;
++} manager_t;
++
++static manager_t *manager = NULL;
++
++static int create_manager(void *mem_ctx, void *wkq_ctx)
++{
++	manager = dwc_alloc(mem_ctx, sizeof(manager_t));
++	if (!manager) {
++		return -DWC_E_NO_MEMORY;
++	}
++
++	DWC_CIRCLEQ_INIT(&manager->notifiers);
++
++	manager->wq = dwc_workq_alloc(wkq_ctx, "DWC Notification WorkQ");
++	if (!manager->wq) {
++		return -DWC_E_NO_MEMORY;
++	}
++
++	return 0;
++}
++
++static void free_manager(void)
++{
++	dwc_workq_free(manager->wq);
++
++	/* All notifiers must have unregistered themselves before this module
++	 * can be removed.  Hitting this assertion indicates a programmer
++	 * error. */
++	DWC_ASSERT(DWC_CIRCLEQ_EMPTY(&manager->notifiers),
++		   "Notification manager being freed before all notifiers have been removed");
++	dwc_free(manager->mem_ctx, manager);
++}
++
++#ifdef DEBUG
++static void dump_manager(void)
++{
++	notifier_t *n;
++	observer_t *o;
++
++	DWC_ASSERT(manager, "Notification manager not found");
++
++	DWC_DEBUG("List of all notifiers and observers:\n");
++	DWC_CIRCLEQ_FOREACH(n, &manager->notifiers, list_entry) {
++		DWC_DEBUG("Notifier %p has observers:\n", n->object);
++		DWC_CIRCLEQ_FOREACH(o, &n->observers, list_entry) {
++			DWC_DEBUG("    %p watching %s\n", o->observer, o->notification);
++		}
++	}
++}
++#else
++#define dump_manager(...)
++#endif
++
++static observer_t *alloc_observer(void *mem_ctx, void *observer, char *notification,
++				  dwc_notifier_callback_t callback, void *data)
++{
++	observer_t *new_observer = dwc_alloc(mem_ctx, sizeof(observer_t));
++
++	if (!new_observer) {
++		return NULL;
++	}
++
++	DWC_CIRCLEQ_INIT_ENTRY(new_observer, list_entry);
++	new_observer->observer = observer;
++	new_observer->notification = notification;
++	new_observer->callback = callback;
++	new_observer->data = data;
++	return new_observer;
++}
++
++static void free_observer(void *mem_ctx, observer_t *observer)
++{
++	dwc_free(mem_ctx, observer);
++}
++
++static notifier_t *alloc_notifier(void *mem_ctx, void *object)
++{
++	notifier_t *notifier;
++
++	if (!object) {
++		return NULL;
++	}
++
++	notifier = dwc_alloc(mem_ctx, sizeof(notifier_t));
++	if (!notifier) {
++		return NULL;
++	}
++
++	DWC_CIRCLEQ_INIT(&notifier->observers);
++	DWC_CIRCLEQ_INIT_ENTRY(notifier, list_entry);
++
++	notifier->mem_ctx = mem_ctx;
++	notifier->object = object;
++	return notifier;
++}
++
++static void free_notifier(notifier_t *notifier)
++{
++	observer_t *observer;
++
++	DWC_CIRCLEQ_FOREACH(observer, &notifier->observers, list_entry) {
++		free_observer(notifier->mem_ctx, observer);
++	}
++
++	dwc_free(notifier->mem_ctx, notifier);
++}
++
++static notifier_t *find_notifier(void *object)
++{
++	notifier_t *notifier;
++
++	DWC_ASSERT(manager, "Notification manager not found");
++
++	if (!object) {
++		return NULL;
++	}
++
++	DWC_CIRCLEQ_FOREACH(notifier, &manager->notifiers, list_entry) {
++		if (notifier->object == object) {
++			return notifier;
++		}
++	}
++
++	return NULL;
++}
++
++int dwc_alloc_notification_manager(void *mem_ctx, void *wkq_ctx)
++{
++	return create_manager(mem_ctx, wkq_ctx);
++}
++
++void dwc_free_notification_manager(void)
++{
++	free_manager();
++}
++
++dwc_notifier_t *dwc_register_notifier(void *mem_ctx, void *object)
++{
++	notifier_t *notifier;
++
++	DWC_ASSERT(manager, "Notification manager not found");
++
++	notifier = find_notifier(object);
++	if (notifier) {
++		DWC_ERROR("Notifier %p is already registered\n", object);
++		return NULL;
++	}
++
++	notifier = alloc_notifier(mem_ctx, object);
++	if (!notifier) {
++		return NULL;
++	}
++
++	DWC_CIRCLEQ_INSERT_TAIL(&manager->notifiers, notifier, list_entry);
++
++	DWC_INFO("Notifier %p registered", object);
++	dump_manager();
++
++	return notifier;
++}
++
++void dwc_unregister_notifier(dwc_notifier_t *notifier)
++{
++	DWC_ASSERT(manager, "Notification manager not found");
++
++	if (!DWC_CIRCLEQ_EMPTY(&notifier->observers)) {
++		observer_t *o;
++
++		DWC_ERROR("Notifier %p has active observers when removing\n", notifier->object);
++		DWC_CIRCLEQ_FOREACH(o, &notifier->observers, list_entry) {
++			DWC_DEBUG("    %p watching %s\n", o->observer, o->notification);
++		}
++
++		DWC_ASSERT(DWC_CIRCLEQ_EMPTY(&notifier->observers),
++			   "Notifier %p has active observers when removing", notifier);
++	}
++
++	DWC_CIRCLEQ_REMOVE_INIT(&manager->notifiers, notifier, list_entry);
++	free_notifier(notifier);
++
++	DWC_INFO("Notifier unregistered");
++	dump_manager();
++}
++
++/* Add an observer to observe the notifier for a particular state, event, or notification. */
++int dwc_add_observer(void *observer, void *object, char *notification,
++		     dwc_notifier_callback_t callback, void *data)
++{
++	notifier_t *notifier = find_notifier(object);
++	observer_t *new_observer;
++
++	if (!notifier) {
++		DWC_ERROR("Notifier %p is not found when adding observer\n", object);
++		return -DWC_E_INVALID;
++	}
++
++	new_observer = alloc_observer(notifier->mem_ctx, observer, notification, callback, data);
++	if (!new_observer) {
++		return -DWC_E_NO_MEMORY;
++	}
++
++	DWC_CIRCLEQ_INSERT_TAIL(&notifier->observers, new_observer, list_entry);
++
++	DWC_INFO("Added observer %p to notifier %p observing notification %s, callback=%p, data=%p",
++		 observer, object, notification, callback, data);
++
++	dump_manager();
++	return 0;
++}
++
++int dwc_remove_observer(void *observer)
++{
++	notifier_t *n;
++
++	DWC_ASSERT(manager, "Notification manager not found");
++
++	DWC_CIRCLEQ_FOREACH(n, &manager->notifiers, list_entry) {
++		observer_t *o;
++		observer_t *o2;
++
++		DWC_CIRCLEQ_FOREACH_SAFE(o, o2, &n->observers, list_entry) {
++			if (o->observer == observer) {
++				DWC_CIRCLEQ_REMOVE_INIT(&n->observers, o, list_entry);
++				DWC_INFO("Removing observer %p from notifier %p watching notification %s:",
++					 o->observer, n->object, o->notification);
++				free_observer(n->mem_ctx, o);
++			}
++		}
++	}
++
++	dump_manager();
++	return 0;
++}
++
++typedef struct callback_data {
++	void *mem_ctx;
++	dwc_notifier_callback_t cb;
++	void *observer;
++	void *data;
++	void *object;
++	char *notification;
++	void *notification_data;
++} cb_data_t;
++
++static void cb_task(void *data)
++{
++	cb_data_t *cb = (cb_data_t *)data;
++
++	cb->cb(cb->object, cb->notification, cb->observer, cb->notification_data, cb->data);
++	dwc_free(cb->mem_ctx, cb);
++}
++
++void dwc_notify(dwc_notifier_t *notifier, char *notification, void *notification_data)
++{
++	observer_t *o;
++
++	DWC_ASSERT(manager, "Notification manager not found");
++
++	DWC_CIRCLEQ_FOREACH(o, &notifier->observers, list_entry) {
++		int len = DWC_STRLEN(notification);
++
++		if (DWC_STRLEN(o->notification) != len) {
++			continue;
++		}
++
++		if (DWC_STRNCMP(o->notification, notification, len) == 0) {
++			cb_data_t *cb_data = dwc_alloc(notifier->mem_ctx, sizeof(cb_data_t));
++
++			if (!cb_data) {
++				DWC_ERROR("Failed to allocate callback data\n");
++				return;
++			}
++
++			cb_data->mem_ctx = notifier->mem_ctx;
++			cb_data->cb = o->callback;
++			cb_data->observer = o->observer;
++			cb_data->data = o->data;
++			cb_data->object = notifier->object;
++			cb_data->notification = notification;
++			cb_data->notification_data = notification_data;
++			DWC_DEBUG("Observer found %p for notification %s\n", o->observer, notification);
++			DWC_WORKQ_SCHEDULE(manager->wq, cb_task, cb_data,
++					   "Notify callback from %p for Notification %s, to observer %p",
++					   cb_data->object, notification, cb_data->observer);
++		}
++	}
++}
++
++#endif	/* DWC_NOTIFYLIB */
+diff --git a/drivers/usb/gadget/udc/hiudc/dwc_notifier.h b/drivers/usb/gadget/udc/hiudc/dwc_notifier.h
+new file mode 100644
+index 0000000..4a8cdfe
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc/dwc_notifier.h
+@@ -0,0 +1,122 @@
++
++#ifndef __DWC_NOTIFIER_H__
++#define __DWC_NOTIFIER_H__
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++#include "dwc_os.h"
++
++/** @file
++ *
++ * A simple implementation of the Observer pattern.  Any "module" can
++ * register as an observer or notifier.  The notion of "module" is abstract and
++ * can mean anything used to identify either an observer or notifier.  Usually
++ * it will be a pointer to a data structure which contains some state, ie an
++ * object.
++ *
++ * Before any notifiers can be added, the global notification manager must be
++ * brought up with dwc_alloc_notification_manager().
++ * dwc_free_notification_manager() will bring it down and free all resources.
++ * These would typically be called upon module load and unload.  The
++ * notification manager is a single global instance that handles all registered
++ * observable modules and observers so this should be done only once.
++ *
++ * A module can be observable by using Notifications to publicize some general
++ * information about it's state or operation.  It does not care who listens, or
++ * even if anyone listens, or what they do with the information.  The observable
++ * modules do not need to know any information about it's observers or their
++ * interface, or their state or data.
++ *
++ * Any module can register to emit Notifications.  It should publish a list of
++ * notifications that it can emit and their behavior, such as when they will get
++ * triggered, and what information will be provided to the observer.  Then it
++ * should register itself as an observable module. See dwc_register_notifier().
++ *
++ * Any module can observe any observable, registered module, provided it has a
++ * handle to the other module and knows what notifications to observe.  See
++ * dwc_add_observer().
++ *
++ * A function of type dwc_notifier_callback_t is called whenever a notification
++ * is triggered with one or more observers observing it.  This function is
++ * called in it's own process so it may sleep or block if needed.  It is
++ * guaranteed to be called sometime after the notification has occurred and will
++ * be called once per each time the notification is triggered.  It will NOT be
++ * called in the same process context used to trigger the notification.
++ *
++ * @section Limitiations
++ *
++ * Keep in mind that Notifications that can be triggered in rapid sucession may
++ * schedule too many processes too handle.  Be aware of this limitation when
++ * designing to use notifications, and only add notifications for appropriate
++ * observable information.
++ *
++ * Also Notification callbacks are not synchronous.  If you need to synchronize
++ * the behavior between module/observer you must use other means.  And perhaps
++ * that will mean Notifications are not the proper solution.
++ */
++
++struct dwc_notifier;
++typedef struct dwc_notifier dwc_notifier_t;
++
++/** The callback function must be of this type.
++ *
++ * @param object This is the object that is being observed.
++ * @param notification This is the notification that was triggered.
++ * @param observer This is the observer
++ * @param notification_data This is notification-specific data that the notifier
++ * has included in this notification.  The value of this should be published in
++ * the documentation of the observable module with the notifications.
++ * @param user_data This is any custom data that the observer provided when
++ * adding itself as an observer to the notification. */
++typedef void (*dwc_notifier_callback_t)(void *object, char *notification, void *observer,
++					void *notification_data, void *user_data);
++
++/** Brings up the notification manager. */
++extern int dwc_alloc_notification_manager(void *mem_ctx, void *wkq_ctx);
++/** Brings down the notification manager. */
++extern void dwc_free_notification_manager(void);
++
++/** This function registers an observable module.  A dwc_notifier_t object is
++ * returned to the observable module.  This is an opaque object that is used by
++ * the observable module to trigger notifications.  This object should only be
++ * accessible to functions that are authorized to trigger notifications for this
++ * module.  Observers do not need this object. */
++extern dwc_notifier_t *dwc_register_notifier(void *mem_ctx, void *object);
++
++/** This function unregisters an observable module.  All observers have to be
++ * removed prior to unregistration. */
++extern void dwc_unregister_notifier(dwc_notifier_t *notifier);
++
++/** Add a module as an observer to the observable module.  The observable module
++ * needs to have previously registered with the notification manager.
++ *
++ * @param observer The observer module
++ * @param object The module to observe
++ * @param notification The notification to observe
++ * @param callback The callback function to call
++ * @param user_data Any additional user data to pass into the callback function */
++extern int dwc_add_observer(void *observer, void *object, char *notification,
++			    dwc_notifier_callback_t callback, void *user_data);
++
++/** Removes the specified observer from all notifications that it is currently
++ * observing. */
++extern int dwc_remove_observer(void *observer);
++
++/** This function triggers a Notification.  It should be called by the
++ * observable module, or any module or library which the observable module
++ * allows to trigger notification on it's behalf.  Such as the dwc_cc_t.
++ *
++ * dwc_notify is a non-blocking function.  Callbacks are scheduled called in
++ * their own process context for each trigger.  Callbacks can be blocking.
++ * dwc_notify can be called from interrupt context if needed.
++ *
++ */
++void dwc_notify(dwc_notifier_t *notifier, char *notification, void *notification_data);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* __DWC_NOTIFIER_H__ */
+diff --git a/drivers/usb/gadget/udc/hiudc/dwc_os.h b/drivers/usb/gadget/udc/hiudc/dwc_os.h
+new file mode 100644
+index 0000000..a64c49a
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc/dwc_os.h
+@@ -0,0 +1,1237 @@
++/* =========================================================================
++ * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_os.h $
++ * $Revision: #14 $
++ * $Date: 2010/11/04 $
++ * $Change: 1621695 $
++ *
++ * Synopsys Portability Library Software and documentation
++ * (hereinafter, "Software") is an Unsupported proprietary work of
++ * Synopsys, Inc. unless otherwise expressly agreed to in writing
++ * between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product
++ * under any End User Software License Agreement or Agreement for
++ * Licensed Product with Synopsys or any supplement thereto. You are
++ * permitted to use and redistribute this Software in source and binary
++ * forms, with or without modification, provided that redistributions
++ * of source code must retain this notice. You may not view, use,
++ * disclose, copy or distribute this file or any information contained
++ * herein except pursuant to this license grant from Synopsys. If you
++ * do not agree with this notice, including the disclaimer below, then
++ * you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
++ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
++ * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
++ * SYNOPSYS 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.
++ * ========================================================================= */
++#ifndef _DWC_OS_H_
++#define _DWC_OS_H_
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/** @file
++ *
++ * DWC portability library, low level os-wrapper functions
++ *
++ */
++
++/* These basic types need to be defined by some OS header file or custom header
++ * file for your specific target architecture.
++ *
++ * uint8_t, int8_t, uint16_t, int16_t, uint32_t, int32_t, uint64_t, int64_t
++ *
++ * Any custom or alternate header file must be added and enabled here.
++ */
++
++#ifdef DWC_LINUX
++# include <linux/types.h>
++# ifdef CONFIG_DEBUG_MUTEXES
++#  include <linux/mutex.h>
++# endif
++# include <linux/errno.h>
++# include <stdarg.h>
++#endif
++
++#if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
++# include <os_dep.h>
++#endif
++
++
++/** @name Primitive Types and Values */
++
++/** We define a boolean type for consistency.  Can be either YES or NO */
++typedef uint8_t dwc_bool_t;
++#define YES  1
++#define NO   0
++
++#ifdef DWC_LINUX
++
++/** @name Error Codes */
++#define DWC_E_INVALID		EINVAL
++#define DWC_E_NO_MEMORY		ENOMEM
++#define DWC_E_NO_DEVICE		ENODEV
++#define DWC_E_NOT_SUPPORTED	EOPNOTSUPP
++#define DWC_E_TIMEOUT		ETIMEDOUT
++#define DWC_E_BUSY		EBUSY
++#define DWC_E_AGAIN		EAGAIN
++#define DWC_E_RESTART		ERESTART
++#define DWC_E_ABORT		ECONNABORTED
++#define DWC_E_SHUTDOWN		ESHUTDOWN
++#define DWC_E_NO_DATA		ENODATA
++#define DWC_E_DISCONNECT	ECONNRESET
++#define DWC_E_UNKNOWN		EINVAL
++#define DWC_E_NO_STREAM_RES	ENOSR
++#define DWC_E_COMMUNICATION	ECOMM
++#define DWC_E_OVERFLOW		EOVERFLOW
++#define DWC_E_PROTOCOL		EPROTO
++#define DWC_E_IN_PROGRESS	EINPROGRESS
++#define DWC_E_PIPE		EPIPE
++#define DWC_E_IO		EIO
++#define DWC_E_NO_SPACE		ENOSPC
++
++#else
++
++/** @name Error Codes */
++#define DWC_E_INVALID		1001
++#define DWC_E_NO_MEMORY		1002
++#define DWC_E_NO_DEVICE		1003
++#define DWC_E_NOT_SUPPORTED	1004
++#define DWC_E_TIMEOUT		1005
++#define DWC_E_BUSY		1006
++#define DWC_E_AGAIN		1007
++#define DWC_E_RESTART		1008
++#define DWC_E_ABORT		1009
++#define DWC_E_SHUTDOWN		1010
++#define DWC_E_NO_DATA		1011
++#define DWC_E_DISCONNECT	2000
++#define DWC_E_UNKNOWN		3000
++#define DWC_E_NO_STREAM_RES	4001
++#define DWC_E_COMMUNICATION	4002
++#define DWC_E_OVERFLOW		4003
++#define DWC_E_PROTOCOL		4004
++#define DWC_E_IN_PROGRESS	4005
++#define DWC_E_PIPE		4006
++#define DWC_E_IO		4007
++#define DWC_E_NO_SPACE		4008
++
++#endif
++
++
++/** @name Tracing/Logging Functions
++ *
++ * These function provide the capability to add tracing, debugging, and error
++ * messages, as well exceptions as assertions.  The WUDEV uses these
++ * extensively.  These could be logged to the main console, the serial port, an
++ * internal buffer, etc.  These functions could also be no-op if they are too
++ * expensive on your system.  By default undefining the DEBUG macro already
++ * no-ops some of these functions. */
++
++/** Returns non-zero if in interrupt context. */
++extern dwc_bool_t DWC_IN_IRQ(void);
++#define dwc_in_irq DWC_IN_IRQ
++
++/** Returns "IRQ" if DWC_IN_IRQ is true. */
++static inline char *dwc_irq(void) {
++	return DWC_IN_IRQ() ? "IRQ" : "";
++}
++
++/** Returns non-zero if in bottom-half context. */
++extern dwc_bool_t DWC_IN_BH(void);
++#define dwc_in_bh DWC_IN_BH
++
++/** Returns "BH" if DWC_IN_BH is true. */
++static inline char *dwc_bh(void) {
++	return DWC_IN_BH() ? "BH" : "";
++}
++
++/**
++ * A vprintf() clone.  Just call vprintf if you've got it.
++ */
++extern void DWC_VPRINTF(char *format, va_list args);
++#define dwc_vprintf DWC_VPRINTF
++
++/**
++ * A vsnprintf() clone.  Just call vprintf if you've got it.
++ */
++extern int DWC_VSNPRINTF(char *str, int size, char *format, va_list args);
++#define dwc_vsnprintf DWC_VSNPRINTF
++
++/**
++ * printf() clone.  Just call printf if you've go it.
++ */
++extern void DWC_PRINTF(char *format, ...)
++/* This provides compiler level static checking of the parameters if you're
++ * using GCC. */
++#ifdef __GNUC__
++	__attribute__ ((format(printf, 1, 2)));
++#else
++	;
++#endif
++#define dwc_printf DWC_PRINTF
++
++/**
++ * sprintf() clone.  Just call sprintf if you've got it.
++ */
++extern int DWC_SPRINTF(char *string, char *format, ...)
++#ifdef __GNUC__
++	__attribute__ ((format(printf, 2, 3)));
++#else
++	;
++#endif
++#define dwc_sprintf DWC_SPRINTF
++
++/**
++ * snprintf() clone.  Just call snprintf if you've got it.
++ */
++extern int DWC_SNPRINTF(char *string, int size, char *format, ...)
++#ifdef __GNUC__
++	__attribute__ ((format(printf, 3, 4)));
++#else
++	;
++#endif
++#define dwc_snprintf DWC_SNPRINTF
++
++/**
++ * Prints a WARNING message.  On systems that don't differentiate between
++ * warnings and regular log messages, just print it.  Indicates that something
++ * may be wrong with the driver.  Works like printf().
++ *
++ * Use the DWC_WARN macro to call this function.
++ */
++extern void __DWC_WARN(char *format, ...)
++#ifdef __GNUC__
++	__attribute__ ((format(printf, 1, 2)));
++#else
++	;
++#endif
++
++/**
++ * Prints an error message.  On systems that don't differentiate between errors
++ * and regular log messages, just print it.  Indicates that something went wrong
++ * with the driver.  Works like printf().
++ *
++ * Use the DWC_ERROR macro to call this function.
++ */
++extern void __DWC_ERROR(char *format, ...)
++#ifdef __GNUC__
++	__attribute__ ((format(printf, 1, 2)));
++#else
++	;
++#endif
++
++/**
++ * Prints an exception error message and takes some user-defined action such as
++ * print out a backtrace or trigger a breakpoint.  Indicates that something went
++ * abnormally wrong with the driver such as programmer error, or other
++ * exceptional condition.  It should not be ignored so even on systems without
++ * printing capability, some action should be taken to notify the developer of
++ * it.  Works like printf().
++ */
++extern void DWC_EXCEPTION(char *format, ...)
++#ifdef __GNUC__
++	__attribute__ ((format(printf, 1, 2)));
++#else
++	;
++#endif
++#define dwc_exception DWC_EXCEPTION
++
++#ifdef DEBUG
++/**
++ * Prints out a debug message.  Used for logging/trace messages.
++ *
++ * Use the DWC_DEBUG macro to call this function
++ */
++extern void __DWC_DEBUG(char *format, ...)
++#ifdef __GNUC__
++	__attribute__ ((format(printf, 1, 2)));
++#else
++	;
++#endif
++#else
++#define __DWC_DEBUG(...)
++#endif
++
++/**
++ * Prints out a Debug message.
++ */
++#define DWC_DEBUG(_format, _args...) __DWC_DEBUG("DEBUG:%s:%s: " _format "\n", \
++						 __func__, dwc_irq(), ## _args)
++#define dwc_debug DWC_DEBUG
++/**
++ * Prints out an informative message.
++ */
++#define DWC_INFO(_format, _args...) DWC_PRINTF("INFO:%s: " _format "\n", \
++					       dwc_irq(), ## _args)
++#define dwc_info DWC_INFO
++/**
++ * Prints out a warning message.
++ */
++#define DWC_WARN(_format, _args...) __DWC_WARN("WARN:%s:%s:%d: " _format "\n", \
++					dwc_irq(), __func__, __LINE__, ## _args)
++#define dwc_warn DWC_WARN
++/**
++ * Prints out an error message.
++ */
++#define DWC_ERROR(_format, _args...) __DWC_ERROR("ERROR:%s:%s:%d: " _format "\n", \
++					dwc_irq(), __func__, __LINE__, ## _args)
++#define dwc_error DWC_ERROR
++
++#define DWC_PROTO_ERROR(_format, _args...) __DWC_WARN("ERROR:%s:%s:%d: " _format "\n", \
++						dwc_irq(), __func__, __LINE__, ## _args)
++#define dwc_proto_error DWC_PROTO_ERROR
++
++#ifdef DEBUG
++/** Prints out a exception error message if the _expr expression fails.  Disabled
++ * if DEBUG is not enabled. */
++#define DWC_ASSERT(_expr, _format, _args...) do { \
++	if (!(_expr)) { DWC_EXCEPTION("%s:%s:%d: " _format "\n", dwc_irq(), \
++				      __FILE__, __LINE__, ## _args); } \
++	} while (0)
++#else
++#define DWC_ASSERT(_x...)
++#endif
++#define dwc_assert DWC_ASSERT
++
++
++/** @name Byte Ordering
++ * The following functions are for conversions between processor's byte ordering
++ * and specific ordering you want.
++ */
++
++/** Converts 32 bit data in CPU byte ordering to little endian. */
++extern uint32_t DWC_CPU_TO_LE32(uint32_t *p);
++#define dwc_cpu_to_le32 DWC_CPU_TO_LE32
++
++/** Converts 32 bit data in CPU byte orderint to big endian. */
++extern uint32_t DWC_CPU_TO_BE32(uint32_t *p);
++#define dwc_cpu_to_be32 DWC_CPU_TO_BE32
++
++/** Converts 32 bit little endian data to CPU byte ordering. */
++extern uint32_t DWC_LE32_TO_CPU(uint32_t *p);
++#define dwc_le32_to_cpu DWC_LE32_TO_CPU
++
++/** Converts 32 bit big endian data to CPU byte ordering. */
++extern uint32_t DWC_BE32_TO_CPU(uint32_t *p);
++#define dwc_be32_to_cpu DWC_BE32_TO_CPU
++
++/** Converts 16 bit data in CPU byte ordering to little endian. */
++extern uint16_t DWC_CPU_TO_LE16(uint16_t *p);
++#define dwc_cpu_to_le16 DWC_CPU_TO_LE16
++
++/** Converts 16 bit data in CPU byte orderint to big endian. */
++extern uint16_t DWC_CPU_TO_BE16(uint16_t *p);
++#define dwc_cpu_to_be16 DWC_CPU_TO_BE16
++
++/** Converts 16 bit little endian data to CPU byte ordering. */
++extern uint16_t DWC_LE16_TO_CPU(uint16_t *p);
++#define dwc_le16_to_cpu DWC_LE16_TO_CPU
++
++/** Converts 16 bit bi endian data to CPU byte ordering. */
++extern uint16_t DWC_BE16_TO_CPU(uint16_t *p);
++#define dwc_be16_to_cpu DWC_BE16_TO_CPU
++
++
++/** @name Register Read/Write
++ *
++ * The following six functions should be implemented to read/write registers of
++ * 32-bit and 64-bit sizes.  All modules use this to read/write register values.
++ * The reg value is a pointer to the register calculated from the void *base
++ * variable passed into the driver when it is started.  */
++
++#ifdef DWC_LINUX
++/* Linux doesn't need any extra parameters for register read/write, so we
++ * just throw away the IO context parameter.
++ */
++/** Reads the content of a 32-bit register. */
++extern uint32_t DWC_READ_REG32(uint32_t volatile *reg);
++#define dwc_read_reg32(_ctx_,_reg_) DWC_READ_REG32(_reg_)
++
++/** Reads the content of a 64-bit register. */
++extern uint64_t DWC_READ_REG64(uint64_t volatile *reg);
++#define dwc_read_reg64(_ctx_,_reg_) DWC_READ_REG64(_reg_)
++
++/** Writes to a 32-bit register. */
++extern void DWC_WRITE_REG32(uint32_t volatile *reg, uint32_t value);
++#define dwc_write_reg32(_ctx_,_reg_,_val_) DWC_WRITE_REG32(_reg_, _val_)
++
++/** Writes to a 64-bit register. */
++extern void DWC_WRITE_REG64(uint64_t volatile *reg, uint64_t value);
++#define dwc_write_reg64(_ctx_,_reg_,_val_) DWC_WRITE_REG64(_reg_, _val_)
++
++/**
++ * Modify bit values in a register.  Using the
++ * algorithm: (reg_contents & ~clear_mask) | set_mask.
++ */
++extern void DWC_MODIFY_REG32(uint32_t volatile *reg, uint32_t clear_mask, uint32_t set_mask);
++#define dwc_modify_reg32(_ctx_,_reg_,_cmsk_,_smsk_) DWC_MODIFY_REG32(_reg_,_cmsk_,_smsk_)
++extern void DWC_MODIFY_REG64(uint64_t volatile *reg, uint64_t clear_mask, uint64_t set_mask);
++#define dwc_modify_reg64(_ctx_,_reg_,_cmsk_,_smsk_) DWC_MODIFY_REG64(_reg_,_cmsk_,_smsk_)
++
++#endif	/* DWC_LINUX */
++
++#if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
++typedef struct dwc_ioctx {
++	struct device *dev;
++	bus_space_tag_t iot;
++	bus_space_handle_t ioh;
++} dwc_ioctx_t;
++
++/** BSD needs two extra parameters for register read/write, so we pass
++ * them in using the IO context parameter.
++ */
++/** Reads the content of a 32-bit register. */
++extern uint32_t DWC_READ_REG32(void *io_ctx, uint32_t volatile *reg);
++#define dwc_read_reg32 DWC_READ_REG32
++
++/** Reads the content of a 64-bit register. */
++extern uint64_t DWC_READ_REG64(void *io_ctx, uint64_t volatile *reg);
++#define dwc_read_reg64 DWC_READ_REG64
++
++/** Writes to a 32-bit register. */
++extern void DWC_WRITE_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t value);
++#define dwc_write_reg32 DWC_WRITE_REG32
++
++/** Writes to a 64-bit register. */
++extern void DWC_WRITE_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t value);
++#define dwc_write_reg64 DWC_WRITE_REG64
++
++/**
++ * Modify bit values in a register.  Using the
++ * algorithm: (reg_contents & ~clear_mask) | set_mask.
++ */
++extern void DWC_MODIFY_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t clear_mask, uint32_t set_mask);
++#define dwc_modify_reg32 DWC_MODIFY_REG32
++extern void DWC_MODIFY_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t clear_mask, uint64_t set_mask);
++#define dwc_modify_reg64 DWC_MODIFY_REG64
++
++#endif	/* DWC_FREEBSD || DWC_NETBSD */
++
++/** @cond */
++
++/** @name Some convenience MACROS used internally.  Define DWC_DEBUG_REGS to log the
++ * register writes. */
++
++#ifdef DWC_LINUX
++
++# ifdef DWC_DEBUG_REGS
++
++#define dwc_define_read_write_reg_n(_reg,_container_type) \
++static inline uint32_t dwc_read_##_reg##_n(_container_type *container, int num) { \
++	return DWC_READ_REG32(&container->regs->_reg[num]); \
++} \
++static inline void dwc_write_##_reg##_n(_container_type *container, int num, uint32_t data) { \
++	DWC_DEBUG("WRITING %8s[%d]: %p: %08x", #_reg, num, \
++		  &(((uint32_t*)container->regs->_reg)[num]), data); \
++	DWC_WRITE_REG32(&(((uint32_t*)container->regs->_reg)[num]), data); \
++}
++
++#define dwc_define_read_write_reg(_reg,_container_type) \
++static inline uint32_t dwc_read_##_reg(_container_type *container) { \
++	return DWC_READ_REG32(&container->regs->_reg); \
++} \
++static inline void dwc_write_##_reg(_container_type *container, uint32_t data) { \
++	DWC_DEBUG("WRITING %11s: %p: %08x", #_reg, &container->regs->_reg, data); \
++	DWC_WRITE_REG32(&container->regs->_reg, data); \
++}
++
++# else	/* DWC_DEBUG_REGS */
++
++#define dwc_define_read_write_reg_n(_reg,_container_type) \
++static inline uint32_t dwc_read_##_reg##_n(_container_type *container, int num) { \
++	return DWC_READ_REG32(&container->regs->_reg[num]); \
++} \
++static inline void dwc_write_##_reg##_n(_container_type *container, int num, uint32_t data) { \
++	DWC_WRITE_REG32(&(((uint32_t*)container->regs->_reg)[num]), data); \
++}
++
++#define dwc_define_read_write_reg(_reg,_container_type) \
++static inline uint32_t dwc_read_##_reg(_container_type *container) { \
++	return DWC_READ_REG32(&container->regs->_reg); \
++} \
++static inline void dwc_write_##_reg(_container_type *container, uint32_t data) { \
++	DWC_WRITE_REG32(&container->regs->_reg, data); \
++}
++
++# endif	/* DWC_DEBUG_REGS */
++
++#endif	/* DWC_LINUX */
++
++#if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
++
++# ifdef DWC_DEBUG_REGS
++
++#define dwc_define_read_write_reg_n(_reg,_container_type) \
++static inline uint32_t dwc_read_##_reg##_n(void *io_ctx, _container_type *container, int num) { \
++	return DWC_READ_REG32(io_ctx, &container->regs->_reg[num]); \
++} \
++static inline void dwc_write_##_reg##_n(void *io_ctx, _container_type *container, int num, uint32_t data) { \
++	DWC_DEBUG("WRITING %8s[%d]: %p: %08x", #_reg, num, \
++		  &(((uint32_t*)container->regs->_reg)[num]), data); \
++	DWC_WRITE_REG32(io_ctx, &(((uint32_t*)container->regs->_reg)[num]), data); \
++}
++
++#define dwc_define_read_write_reg(_reg,_container_type) \
++static inline uint32_t dwc_read_##_reg(void *io_ctx, _container_type *container) { \
++	return DWC_READ_REG32(io_ctx, &container->regs->_reg); \
++} \
++static inline void dwc_write_##_reg(void *io_ctx, _container_type *container, uint32_t data) { \
++	DWC_DEBUG("WRITING %11s: %p: %08x", #_reg, &container->regs->_reg, data); \
++	DWC_WRITE_REG32(io_ctx, &container->regs->_reg, data); \
++}
++
++# else	/* DWC_DEBUG_REGS */
++
++#define dwc_define_read_write_reg_n(_reg,_container_type) \
++static inline uint32_t dwc_read_##_reg##_n(void *io_ctx, _container_type *container, int num) { \
++	return DWC_READ_REG32(io_ctx, &container->regs->_reg[num]); \
++} \
++static inline void dwc_write_##_reg##_n(void *io_ctx, _container_type *container, int num, uint32_t data) { \
++	DWC_WRITE_REG32(io_ctx, &(((uint32_t*)container->regs->_reg)[num]), data); \
++}
++
++#define dwc_define_read_write_reg(_reg,_container_type) \
++static inline uint32_t dwc_read_##_reg(void *io_ctx, _container_type *container) { \
++	return DWC_READ_REG32(io_ctx, &container->regs->_reg); \
++} \
++static inline void dwc_write_##_reg(void *io_ctx, _container_type *container, uint32_t data) { \
++	DWC_WRITE_REG32(io_ctx, &container->regs->_reg, data); \
++}
++
++# endif	/* DWC_DEBUG_REGS */
++
++#endif	/* DWC_FREEBSD || DWC_NETBSD */
++
++/** @endcond */
++
++
++#ifdef DWC_CRYPTOLIB
++/** @name Crypto Functions
++ *
++ * These are the low-level cryptographic functions used by the driver. */
++
++/** Perform AES CBC */
++extern int DWC_AES_CBC(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t iv[16], uint8_t *out);
++#define dwc_aes_cbc DWC_AES_CBC
++
++/** Fill the provided buffer with random bytes.  These should be cryptographic grade random numbers. */
++extern void DWC_RANDOM_BYTES(uint8_t *buffer, uint32_t length);
++#define dwc_random_bytes DWC_RANDOM_BYTES
++
++/** Perform the SHA-256 hash function */
++extern int DWC_SHA256(uint8_t *message, uint32_t len, uint8_t *out);
++#define dwc_sha256 DWC_SHA256
++
++/** Calculated the HMAC-SHA256 */
++extern int DWC_HMAC_SHA256(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t *out);
++#define dwc_hmac_sha256 DWC_HMAC_SHA256
++
++#endif	/* DWC_CRYPTOLIB */
++
++
++/** @name Memory Allocation
++ *
++ * These function provide access to memory allocation.  There are only 2 DMA
++ * functions and 3 Regular memory functions that need to be implemented.  None
++ * of the memory debugging routines need to be implemented.  The allocation
++ * routines all ZERO the contents of the memory.
++ *
++ * Defining DWC_DEBUG_MEMORY turns on memory debugging and statistic gathering.
++ * This checks for memory leaks, keeping track of alloc/free pairs.  It also
++ * keeps track of how much memory the driver is using at any given time. */
++
++#define DWC_PAGE_SIZE 4096
++#define DWC_PAGE_OFFSET(addr) (((uint32_t)addr) & 0xfff)
++#define DWC_PAGE_ALIGNED(addr) ((((uint32_t)addr) & 0xfff) == 0)
++
++#define DWC_INVALID_DMA_ADDR 0x0
++
++#ifdef DWC_LINUX
++/** Type for a DMA address */
++typedef dma_addr_t dwc_dma_t;
++#endif
++
++#if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
++typedef bus_addr_t dwc_dma_t;
++#endif
++
++#ifdef DWC_FREEBSD
++typedef struct dwc_dmactx {
++	struct device *dev;
++	bus_dma_tag_t dma_tag;
++	bus_dmamap_t dma_map;
++	bus_addr_t dma_paddr;
++	void *dma_vaddr;
++} dwc_dmactx_t;
++#endif
++
++#ifdef DWC_NETBSD
++typedef struct dwc_dmactx {
++	struct device *dev;
++	bus_dma_tag_t dma_tag;
++	bus_dmamap_t dma_map;
++	bus_dma_segment_t segs[1];
++	int nsegs;
++	bus_addr_t dma_paddr;
++	void *dma_vaddr;
++} dwc_dmactx_t;
++#endif
++
++/* @todo these functions will be added in the future */
++#if 0
++/**
++ * Creates a DMA pool from which you can allocate DMA buffers.  Buffers
++ * allocated from this pool will be guaranteed to meet the size, alignment, and
++ * boundary requirements specified.
++ *
++ * @param[in] size Specifies the size of the buffers that will be allocated from
++ * this pool.
++ * @param[in] align Specifies the byte alignment requirements of the buffers
++ * allocated from this pool.  Must be a power of 2.
++ * @param[in] boundary Specifies the N-byte boundary that buffers allocated from
++ * this pool must not cross.
++ *
++ * @returns A pointer to an internal opaque structure which is not to be
++ * accessed outside of these library functions.  Use this handle to specify
++ * which pools to allocate/free DMA buffers from and also to destroy the pool,
++ * when you are done with it.
++ */
++extern dwc_pool_t *DWC_DMA_POOL_CREATE(uint32_t size, uint32_t align, uint32_t boundary);
++
++/**
++ * Destroy a DMA pool.  All buffers allocated from that pool must be freed first.
++ */
++extern void DWC_DMA_POOL_DESTROY(dwc_pool_t *pool);
++
++/**
++ * Allocate a buffer from the specified DMA pool and zeros its contents.
++ */
++extern void *DWC_DMA_POOL_ALLOC(dwc_pool_t *pool, uint64_t *dma_addr);
++
++/**
++ * Free a previously allocated buffer from the DMA pool.
++ */
++extern void DWC_DMA_POOL_FREE(dwc_pool_t *pool, void *vaddr, void *daddr);
++#endif
++
++/** Allocates a DMA capable buffer and zeroes its contents. */
++extern void *__DWC_DMA_ALLOC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr);
++
++/** Allocates a DMA capable buffer and zeroes its contents in atomic contest */
++extern void *__DWC_DMA_ALLOC_ATOMIC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr);
++
++/** Frees a previously allocated buffer. */
++extern void __DWC_DMA_FREE(void *dma_ctx, uint32_t size, void *virt_addr, dwc_dma_t dma_addr);
++
++/** Allocates a block of memory and zeroes its contents. */
++extern void *__DWC_ALLOC(void *mem_ctx, uint32_t size);
++
++/** Allocates a block of memory and zeroes its contents, in an atomic manner
++ * which can be used inside interrupt context.  The size should be sufficiently
++ * small, a few KB at most, such that failures are not likely to occur.  Can just call
++ * __DWC_ALLOC if it is atomic. */
++extern void *__DWC_ALLOC_ATOMIC(void *mem_ctx, uint32_t size);
++
++/** Frees a previously allocated buffer. */
++extern void __DWC_FREE(void *mem_ctx, void *addr);
++
++#ifndef DWC_DEBUG_MEMORY
++
++#define DWC_ALLOC(_size_) __DWC_ALLOC(NULL, _size_)
++#define DWC_ALLOC_ATOMIC(_size_) __DWC_ALLOC_ATOMIC(NULL, _size_)
++#define DWC_FREE(_addr_) __DWC_FREE(NULL, _addr_)
++
++# ifdef DWC_LINUX
++#define DWC_DMA_ALLOC(_size_,_dma_) __DWC_DMA_ALLOC(NULL, _size_, _dma_)
++#define DWC_DMA_ALLOC_ATOMIC(_size_,_dma_) __DWC_DMA_ALLOC_ATOMIC(NULL, _size_,_dma_)
++#define DWC_DMA_FREE(_size_,_virt_,_dma_) __DWC_DMA_FREE(NULL, _size_, _virt_, _dma_)
++# endif
++
++# if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
++#define DWC_DMA_ALLOC __DWC_DMA_ALLOC
++#define DWC_DMA_FREE __DWC_DMA_FREE
++# endif
++
++#else	/* DWC_DEBUG_MEMORY */
++
++extern void *dwc_alloc_debug(void *mem_ctx, uint32_t size, char const *func, int line);
++extern void *dwc_alloc_atomic_debug(void *mem_ctx, uint32_t size, char const *func, int line);
++extern void dwc_free_debug(void *mem_ctx, void *addr, char const *func, int line);
++extern void *dwc_dma_alloc_debug(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr,
++				 char const *func, int line);
++extern void *dwc_dma_alloc_atomic_debug(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr,
++				char const *func, int line);
++extern void dwc_dma_free_debug(void *dma_ctx, uint32_t size, void *virt_addr,
++			       dwc_dma_t dma_addr, char const *func, int line);
++
++extern int dwc_memory_debug_start(void *mem_ctx);
++extern void dwc_memory_debug_stop(void);
++extern void dwc_memory_debug_report(void);
++
++#define DWC_ALLOC(_size_) dwc_alloc_debug(NULL, _size_, __func__, __LINE__)
++#define DWC_ALLOC_ATOMIC(_size_) dwc_alloc_atomic_debug(NULL, _size_, \
++							__func__, __LINE__)
++#define DWC_FREE(_addr_) dwc_free_debug(NULL, _addr_, __func__, __LINE__)
++
++# ifdef DWC_LINUX
++#define DWC_DMA_ALLOC(_size_,_dma_) dwc_dma_alloc_debug(NULL, _size_, \
++						_dma_, __func__, __LINE__)
++#define DWC_DMA_ALLOC_ATOMIC(_size_,_dma_) dwc_dma_alloc_atomic_debug(NULL, _size_, \
++						_dma_, __func__, __LINE__)
++#define DWC_DMA_FREE(_size_,_virt_,_dma_) dwc_dma_free_debug(NULL, _size_, \
++						_virt_, _dma_, __func__, __LINE__)
++# endif
++
++# if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
++#define DWC_DMA_ALLOC(_ctx_,_size_,_dma_) dwc_dma_alloc_debug(_ctx_, _size_, \
++						_dma_, __func__, __LINE__)
++#define DWC_DMA_FREE(_ctx_,_size_,_virt_,_dma_) dwc_dma_free_debug(_ctx_, _size_, \
++						 _virt_, _dma_, __func__, __LINE__)
++# endif
++
++#endif /* DWC_DEBUG_MEMORY */
++
++#define dwc_alloc(_ctx_,_size_) DWC_ALLOC(_size_)
++#define dwc_alloc_atomic(_ctx_,_size_) DWC_ALLOC_ATOMIC(_size_)
++#define dwc_free(_ctx_,_addr_) DWC_FREE(_addr_)
++
++#ifdef DWC_LINUX
++/* Linux doesn't need any extra parameters for DMA buffer allocation, so we
++ * just throw away the DMA context parameter.
++ */
++#define dwc_dma_alloc(_ctx_,_size_,_dma_) DWC_DMA_ALLOC(_size_, _dma_)
++#define dwc_dma_alloc_atomic(_ctx_,_size_,_dma_) DWC_DMA_ALLOC_ATOMIC(_size_, _dma_)
++#define dwc_dma_free(_ctx_,_size_,_virt_,_dma_) DWC_DMA_FREE(_size_, _virt_, _dma_)
++#endif
++
++#if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
++/** BSD needs several extra parameters for DMA buffer allocation, so we pass
++ * them in using the DMA context parameter.
++ */
++#define dwc_dma_alloc DWC_DMA_ALLOC
++#define dwc_dma_free DWC_DMA_FREE
++#endif
++
++
++/** @name Memory and String Processing */
++
++/** memset() clone */
++extern void *DWC_MEMSET(void *dest, uint8_t byte, uint32_t size);
++#define dwc_memset DWC_MEMSET
++
++/** memcpy() clone */
++extern void *DWC_MEMCPY(void *dest, void const *src, uint32_t size);
++#define dwc_memcpy DWC_MEMCPY
++
++/** memmove() clone */
++extern void *DWC_MEMMOVE(void *dest, void *src, uint32_t size);
++#define dwc_memmove DWC_MEMMOVE
++
++/** memcmp() clone */
++extern int DWC_MEMCMP(void *m1, void *m2, uint32_t size);
++#define dwc_memcmp DWC_MEMCMP
++
++/** strcmp() clone */
++extern int DWC_STRCMP(void *s1, void *s2);
++#define dwc_strcmp DWC_STRCMP
++
++/** strncmp() clone */
++extern int DWC_STRNCMP(void *s1, void *s2, uint32_t size);
++#define dwc_strncmp DWC_STRNCMP
++
++/** strlen() clone, for NULL terminated ASCII strings */
++extern int DWC_STRLEN(char const *str);
++#define dwc_strlen DWC_STRLEN
++
++/** strcpy() clone, for NULL terminated ASCII strings */
++extern char *DWC_STRCPY(char *to, const char *from);
++#define dwc_strcpy DWC_STRCPY
++
++/** strdup() clone.  If you wish to use memory allocation debugging, this
++ * implementation of strdup should use the DWC_* memory routines instead of
++ * calling a predefined strdup.  Otherwise the memory allocated by this routine
++ * will not be seen by the debugging routines. */
++extern char *DWC_STRDUP(char const *str);
++#define dwc_strdup(_ctx_,_str_) DWC_STRDUP(_str_)
++
++/** NOT an atoi() clone.  Read the description carefully.  Returns an integer
++ * converted from the string str in base 10 unless the string begins with a "0x"
++ * in which case it is base 16.  String must be a NULL terminated sequence of
++ * ASCII characters and may optionally begin with whitespace, a + or -, and a
++ * "0x" prefix if base 16.  The remaining characters must be valid digits for
++ * the number and end with a NULL character.  If any invalid characters are
++ * encountered or it returns with a negative error code and the results of the
++ * conversion are undefined.  On sucess it returns 0.  Overflow conditions are
++ * undefined.  An example implementation using atoi() can be referenced from the
++ * Linux implementation. */
++extern int DWC_ATOI(const char *str, int32_t *value);
++#define dwc_atoi DWC_ATOI
++
++/** Same as above but for unsigned. */
++extern int DWC_ATOUI(const char *str, uint32_t *value);
++#define dwc_atoui DWC_ATOUI
++
++#ifdef DWC_UTFLIB
++/** This routine returns a UTF16LE unicode encoded string from a UTF8 string. */
++extern int DWC_UTF8_TO_UTF16LE(uint8_t const *utf8string, uint16_t *utf16string, unsigned len);
++#define dwc_utf8_to_utf16le DWC_UTF8_TO_UTF16LE
++#endif
++
++
++/** @name Wait queues
++ *
++ * Wait queues provide a means of synchronizing between threads or processes.  A
++ * process can block on a waitq if some condition is not true, waiting for it to
++ * become true.  When the waitq is triggered all waiting process will get
++ * unblocked and the condition will be check again.  Waitqs should be triggered
++ * every time a condition can potentially change.*/
++struct dwc_waitq;
++
++/** Type for a waitq */
++typedef struct dwc_waitq dwc_waitq_t;
++
++/** The type of waitq condition callback function.  This is called every time
++ * condition is evaluated. */
++typedef int (*dwc_waitq_condition_t)(void *data);
++
++/** Allocate a waitq */
++extern dwc_waitq_t *DWC_WAITQ_ALLOC(void);
++#define dwc_waitq_alloc(_ctx_) DWC_WAITQ_ALLOC()
++
++/** Free a waitq */
++extern void DWC_WAITQ_FREE(dwc_waitq_t *wq);
++#define dwc_waitq_free DWC_WAITQ_FREE
++
++/** Check the condition and if it is false, block on the waitq.  When unblocked, check the
++ * condition again.  The function returns when the condition becomes true.  The return value
++ * is 0 on condition true, DWC_WAITQ_ABORTED on abort or killed, or DWC_WAITQ_UNKNOWN on error. */
++extern int32_t DWC_WAITQ_WAIT(dwc_waitq_t *wq, dwc_waitq_condition_t cond, void *data);
++#define dwc_waitq_wait DWC_WAITQ_WAIT
++
++/** Check the condition and if it is false, block on the waitq.  When unblocked,
++ * check the condition again.  The function returns when the condition become
++ * true or the timeout has passed.  The return value is 0 on condition true or
++ * DWC_TIMED_OUT on timeout, or DWC_WAITQ_ABORTED, or DWC_WAITQ_UNKNOWN on
++ * error. */
++extern int32_t DWC_WAITQ_WAIT_TIMEOUT(dwc_waitq_t *wq, dwc_waitq_condition_t cond,
++				      void *data, int32_t msecs);
++#define dwc_waitq_wait_timeout DWC_WAITQ_WAIT_TIMEOUT
++
++/** Trigger a waitq, unblocking all processes.  This should be called whenever a condition
++ * has potentially changed. */
++extern void DWC_WAITQ_TRIGGER(dwc_waitq_t *wq);
++#define dwc_waitq_trigger DWC_WAITQ_TRIGGER
++
++/** Unblock all processes waiting on the waitq with an ABORTED result. */
++extern void DWC_WAITQ_ABORT(dwc_waitq_t *wq);
++#define dwc_waitq_abort DWC_WAITQ_ABORT
++
++
++/** @name Threads
++ *
++ * A thread must be explicitly stopped.  It must check DWC_THREAD_SHOULD_STOP
++ * whenever it is woken up, and then return.  The DWC_THREAD_STOP function
++ * returns the value from the thread.
++ */
++
++struct dwc_thread;
++
++/** Type for a thread */
++typedef struct dwc_thread dwc_thread_t;
++
++/** The thread function */
++typedef int (*dwc_thread_function_t)(void *data);
++
++/** Create a thread and start it running the thread_function.  Returns a handle
++ * to the thread */
++extern dwc_thread_t *DWC_THREAD_RUN(dwc_thread_function_t func, char *name, void *data);
++#define dwc_thread_run(_ctx_,_func_,_name_,_data_) DWC_THREAD_RUN(_func_, _name_, _data_)
++
++/** Stops a thread.  Return the value returned by the thread.  Or will return
++ * DWC_ABORT if the thread never started. */
++extern int DWC_THREAD_STOP(dwc_thread_t *thread);
++#define dwc_thread_stop DWC_THREAD_STOP
++
++/** Signifies to the thread that it must stop. */
++#ifdef DWC_LINUX
++/* Linux doesn't need any parameters for kthread_should_stop() */
++extern dwc_bool_t DWC_THREAD_SHOULD_STOP(void);
++#define dwc_thread_should_stop(_thrd_) DWC_THREAD_SHOULD_STOP()
++
++/* No thread_exit function in Linux */
++#define dwc_thread_exit(_thrd_)
++#endif
++
++#if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
++/** BSD needs the thread pointer for kthread_suspend_check() */
++extern dwc_bool_t DWC_THREAD_SHOULD_STOP(dwc_thread_t *thread);
++#define dwc_thread_should_stop DWC_THREAD_SHOULD_STOP
++
++/** The thread must call this to exit. */
++extern void DWC_THREAD_EXIT(dwc_thread_t *thread);
++#define dwc_thread_exit DWC_THREAD_EXIT
++#endif
++
++
++/** @name Work queues
++ *
++ * Workqs are used to queue a callback function to be called at some later time,
++ * in another thread. */
++struct dwc_workq;
++
++/** Type for a workq */
++typedef struct dwc_workq dwc_workq_t;
++
++/** The type of the callback function to be called. */
++typedef void (*dwc_work_callback_t)(void *data);
++
++/** Allocate a workq */
++extern dwc_workq_t *DWC_WORKQ_ALLOC(char *name);
++#define dwc_workq_alloc(_ctx_,_name_) DWC_WORKQ_ALLOC(_name_)
++
++/** Free a workq.  All work must be completed before being freed. */
++extern void DWC_WORKQ_FREE(dwc_workq_t *workq);
++#define dwc_workq_free DWC_WORKQ_FREE
++
++/** Schedule a callback on the workq, passing in data.  The function will be
++ * scheduled at some later time. */
++extern void DWC_WORKQ_SCHEDULE(dwc_workq_t *workq, dwc_work_callback_t cb,
++			       void *data, char *format, ...)
++#ifdef __GNUC__
++	__attribute__ ((format(printf, 4, 5)));
++#else
++	;
++#endif
++#define dwc_workq_schedule DWC_WORKQ_SCHEDULE
++
++/** Schedule a callback on the workq, that will be called until at least
++ * given number miliseconds have passed. */
++extern void DWC_WORKQ_SCHEDULE_DELAYED(dwc_workq_t *workq, dwc_work_callback_t cb,
++				       void *data, uint32_t time, char *format, ...)
++#ifdef __GNUC__
++	__attribute__ ((format(printf, 5, 6)));
++#else
++	;
++#endif
++#define dwc_workq_schedule_delayed DWC_WORKQ_SCHEDULE_DELAYED
++
++/** The number of processes in the workq */
++extern int DWC_WORKQ_PENDING(dwc_workq_t *workq);
++#define dwc_workq_pending DWC_WORKQ_PENDING
++
++/** Blocks until all the work in the workq is complete or timed out.  Returns <
++ * 0 on timeout. */
++extern int DWC_WORKQ_WAIT_WORK_DONE(dwc_workq_t *workq, int timeout);
++#define dwc_workq_wait_work_done DWC_WORKQ_WAIT_WORK_DONE
++
++
++/** @name Tasklets
++ *
++ */
++struct dwc_tasklet;
++
++/** Type for a tasklet */
++typedef struct dwc_tasklet dwc_tasklet_t;
++
++/** The type of the callback function to be called */
++typedef void (*dwc_tasklet_callback_t)(void *data);
++
++/** Allocates a tasklet */
++extern dwc_tasklet_t *DWC_TASK_ALLOC(char *name, dwc_tasklet_callback_t cb, void *data);
++#define dwc_task_alloc(_ctx_,_name_,_cb_,_data_) DWC_TASK_ALLOC(_name_, _cb_, _data_)
++
++/** Frees a tasklet */
++extern void DWC_TASK_FREE(dwc_tasklet_t *task);
++#define dwc_task_free DWC_TASK_FREE
++
++/** Schedules a tasklet to run */
++extern void DWC_TASK_SCHEDULE(dwc_tasklet_t *task);
++#define dwc_task_schedule DWC_TASK_SCHEDULE
++
++
++/** @name Timer
++ *
++ * Callbacks must be small and atomic.
++ */
++struct dwc_timer;
++
++/** Type for a timer */
++typedef struct dwc_timer dwc_timer_t;
++
++/** The type of the callback function to be called */
++typedef void (*dwc_timer_callback_t)(void *data);
++
++/** Allocates a timer */
++extern dwc_timer_t *DWC_TIMER_ALLOC(char *name, dwc_timer_callback_t cb, void *data);
++#define dwc_timer_alloc(_ctx_,_name_,_cb_,_data_) DWC_TIMER_ALLOC(_name_,_cb_,_data_)
++
++/** Frees a timer */
++extern void DWC_TIMER_FREE(dwc_timer_t *timer);
++#define dwc_timer_free DWC_TIMER_FREE
++
++/** Schedules the timer to run at time ms from now.  And will repeat at every
++ * repeat_interval msec therafter
++ *
++ * Modifies a timer that is still awaiting execution to a new expiration time.
++ * The mod_time is added to the old time.  */
++extern void DWC_TIMER_SCHEDULE(dwc_timer_t *timer, uint32_t time);
++#define dwc_timer_schedule DWC_TIMER_SCHEDULE
++
++/** Disables the timer from execution. */
++extern void DWC_TIMER_CANCEL(dwc_timer_t *timer);
++#define dwc_timer_cancel DWC_TIMER_CANCEL
++
++
++/** @name Spinlocks
++ *
++ * These locks are used when the work between the lock/unlock is atomic and
++ * short.  Interrupts are also disabled during the lock/unlock and thus they are
++ * suitable to lock between interrupt/non-interrupt context.  They also lock
++ * between processes if you have multiple CPUs or Preemption.  If you don't have
++ * multiple CPUS or Preemption, then the you can simply implement the
++ * DWC_SPINLOCK and DWC_SPINUNLOCK to disable and enable interrupts.  Because
++ * the work between the lock/unlock is atomic, the process context will never
++ * change, and so you never have to lock between processes.  */
++
++struct dwc_spinlock;
++
++/** Type for a spinlock */
++typedef struct dwc_spinlock dwc_spinlock_t;
++
++/** Type for the 'flags' argument to spinlock funtions */
++typedef unsigned long dwc_irqflags_t;
++
++/** Returns an initialized lock variable.  This function should allocate and
++ * initialize the OS-specific data structure used for locking.  This data
++ * structure is to be used for the DWC_LOCK and DWC_UNLOCK functions and should
++ * be freed by the DWC_FREE_LOCK when it is no longer used. */
++extern dwc_spinlock_t *DWC_SPINLOCK_ALLOC(void);
++#define dwc_spinlock_alloc(_ctx_) DWC_SPINLOCK_ALLOC()
++
++/** Frees an initialized lock variable. */
++extern void DWC_SPINLOCK_FREE(dwc_spinlock_t *lock);
++#define dwc_spinlock_free(_ctx_,_lock_) DWC_SPINLOCK_FREE(_lock_)
++
++/** Disables interrupts and blocks until it acquires the lock.
++ *
++ * @param lock Pointer to the spinlock.
++ * @param flags Unsigned long for irq flags storage.
++ */
++extern void DWC_SPINLOCK_IRQSAVE(dwc_spinlock_t *lock, dwc_irqflags_t *flags);
++#define dwc_spinlock_irqsave DWC_SPINLOCK_IRQSAVE
++
++/** Re-enables the interrupt and releases the lock.
++ *
++ * @param lock Pointer to the spinlock.
++ * @param flags Unsigned long for irq flags storage.  Must be the same as was
++ * passed into DWC_LOCK.
++ */
++extern void DWC_SPINUNLOCK_IRQRESTORE(dwc_spinlock_t *lock, dwc_irqflags_t flags);
++#define dwc_spinunlock_irqrestore DWC_SPINUNLOCK_IRQRESTORE
++
++/** Blocks until it acquires the lock.
++ *
++ * @param lock Pointer to the spinlock.
++ */
++extern void DWC_SPINLOCK(dwc_spinlock_t *lock);
++#define dwc_spinlock DWC_SPINLOCK
++
++/** Releases the lock.
++ *
++ * @param lock Pointer to the spinlock.
++ */
++extern void DWC_SPINUNLOCK(dwc_spinlock_t *lock);
++#define dwc_spinunlock DWC_SPINUNLOCK
++
++
++/** @name Mutexes
++ *
++ * Unlike spinlocks Mutexes lock only between processes and the work between the
++ * lock/unlock CAN block, therefore it CANNOT be called from interrupt context.
++ */
++
++struct dwc_mutex;
++
++/** Type for a mutex */
++typedef struct dwc_mutex dwc_mutex_t;
++
++/* For Linux Mutex Debugging make it inline because the debugging routines use
++ * the symbol to determine recursive locking.  This makes it falsely think
++ * recursive locking occurs. */
++#if defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES)
++#define DWC_MUTEX_ALLOC_LINUX_DEBUG(__mutexp) ({ \
++	__mutexp = (dwc_mutex_t *)DWC_ALLOC(sizeof(struct mutex)); \
++	mutex_init((struct mutex *)__mutexp); \
++})
++#endif
++
++/** Allocate a mutex */
++extern dwc_mutex_t *DWC_MUTEX_ALLOC(void);
++#define dwc_mutex_alloc(_ctx_) DWC_MUTEX_ALLOC()
++
++/* For memory leak debugging when using Linux Mutex Debugging */
++#if defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES)
++#define DWC_MUTEX_FREE(__mutexp) do { \
++	mutex_destroy((struct mutex *)__mutexp); \
++	DWC_FREE(__mutexp); \
++} while(0)
++#else
++/** Free a mutex */
++extern void DWC_MUTEX_FREE(dwc_mutex_t *mutex);
++#define dwc_mutex_free(_ctx_,_mutex_) DWC_MUTEX_FREE(_mutex_)
++#endif
++
++/** Lock a mutex */
++extern void DWC_MUTEX_LOCK(dwc_mutex_t *mutex);
++#define dwc_mutex_lock DWC_MUTEX_LOCK
++
++/** Non-blocking lock returns 1 on successful lock. */
++extern int DWC_MUTEX_TRYLOCK(dwc_mutex_t *mutex);
++#define dwc_mutex_trylock DWC_MUTEX_TRYLOCK
++
++/** Unlock a mutex */
++extern void DWC_MUTEX_UNLOCK(dwc_mutex_t *mutex);
++#define dwc_mutex_unlock DWC_MUTEX_UNLOCK
++
++
++/** @name Time */
++
++/** Microsecond delay.
++ *
++ * @param usecs  Microseconds to delay.
++ */
++extern void DWC_UDELAY(uint32_t usecs);
++#define dwc_udelay DWC_UDELAY
++
++/** Millisecond delay.
++ *
++ * @param msecs  Milliseconds to delay.
++ */
++extern void DWC_MDELAY(uint32_t msecs);
++#define dwc_mdelay DWC_MDELAY
++
++/** Non-busy waiting.
++ * Sleeps for specified number of milliseconds.
++ *
++ * @param msecs Milliseconds to sleep.
++ */
++extern void DWC_MSLEEP(uint32_t msecs);
++#define dwc_msleep DWC_MSLEEP
++
++/**
++ * Returns number of milliseconds since boot.
++ */
++extern uint32_t DWC_TIME(void);
++#define dwc_time DWC_TIME
++
++
++
++
++/* @mainpage DWC Portability and Common Library
++ *
++ * This is the documentation for the DWC Portability and Common Library.
++ *
++ * @section intro Introduction
++ *
++ * The DWC Portability library consists of wrapper calls and data structures to
++ * all low-level functions which are typically provided by the OS.  The WUDEV
++ * driver uses only these functions.  In order to port the WUDEV driver, only
++ * the functions in this library need to be re-implemented, with the same
++ * behavior as documented here.
++ *
++ * The Common library consists of higher level functions, which rely only on
++ * calling the functions from the DWC Portability library.  These common
++ * routines are shared across modules.  Some of the common libraries need to be
++ * used directly by the driver programmer when porting WUDEV.  Such as the
++ * parameter and notification libraries.
++ *
++ * @section low Portability Library OS Wrapper Functions
++ *
++ * Any function starting with DWC and in all CAPS is a low-level OS-wrapper that
++ * needs to be implemented when porting, for example DWC_MUTEX_ALLOC().  All of
++ * these functions are included in the dwc_os.h file.
++ *
++ * There are many functions here covering a wide array of OS services.  Please
++ * see dwc_os.h for details, and implementation notes for each function.
++ *
++ * @section common Common Library Functions
++ *
++ * Any function starting with dwc and in all lowercase is a common library
++ * routine.  These functions have a portable implementation and do not need to
++ * be reimplemented when porting.  The common routines can be used by any
++ * driver, and some must be used by the end user to control the drivers.  For
++ * example, you must use the Parameter common library in order to set the
++ * parameters in the WUDEV module.
++ *
++ * The common libraries consist of the following:
++ *
++ * - Connection Contexts - Used internally and can be used by end-user.  See dwc_cc.h
++ * - Parameters - Used internally and can be used by end-user.  See dwc_params.h
++ * - Notifications - Used internally and can be used by end-user.  See dwc_notifier.h
++ * - Lists - Used internally and can be used by end-user.  See dwc_list.h
++ * - Memory Debugging - Used internally and can be used by end-user.  See dwc_os.h
++ * - Modpow - Used internally only.  See dwc_modpow.h
++ * - DH - Used internally only.  See dwc_dh.h
++ * - Crypto - Used internally only.  See dwc_crypto.h
++ *
++ *
++ * @section prereq Prerequistes For dwc_os.h
++ * @subsection types Data Types
++ *
++ * The dwc_os.h file assumes that several low-level data types are pre defined for the
++ * compilation environment.  These data types are:
++ *
++ * - uint8_t - unsigned 8-bit data type
++ * - int8_t - signed 8-bit data type
++ * - uint16_t - unsigned 16-bit data type
++ * - int16_t - signed 16-bit data type
++ * - uint32_t - unsigned 32-bit data type
++ * - int32_t - signed 32-bit data type
++ * - uint64_t - unsigned 64-bit data type
++ * - int64_t - signed 64-bit data type
++ *
++ * Ensure that these are defined before using dwc_os.h.  The easiest way to do
++ * that is to modify the top of the file to include the appropriate header.
++ * This is already done for the Linux environment.  If the DWC_LINUX macro is
++ * defined, the correct header will be added.  A standard header <stdint.h> is
++ * also used for environments where standard C headers are available.
++ *
++ * @subsection stdarg Variable Arguments
++ *
++ * Variable arguments are provided by a standard C header <stdarg.h>.  it is
++ * available in Both the Linux and ANSI C enviornment.  An equivalent must be
++ * provided in your enviornment in order to use dwc_os.h with the debug and
++ * tracing message functionality.
++ *
++ * @subsection thread Threading
++ *
++ * WUDEV Core must be run on an operating system that provides for multiple
++ * threads/processes.  Threading can be implemented in many ways, even in
++ * embedded systems without an operating system.  At the bare minimum, the
++ * system should be able to start any number of processes at any time to handle
++ * special work.  It need not be a pre-emptive system.  Process context can
++ * change upon a call to a blocking function.  The hardware interrupt context
++ * that calls the module's ISR() function must be differentiable from process
++ * context, even if your processes are impemented via a hardware interrupt.
++ * Further locking mechanism between process must exist (or be implemented), and
++ * process context must have a way to disable interrupts for a period of time to
++ * lock them out.  If all of this exists, the functions in dwc_os.h related to
++ * threading should be able to be implemented with the defined behavior.
++ *
++ */
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* _DWC_OS_H_ */
+diff --git a/drivers/usb/gadget/udc/hiudc/dwc_otg_adp.c b/drivers/usb/gadget/udc/hiudc/dwc_otg_adp.c
+new file mode 100644
+index 0000000..db309f3
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc/dwc_otg_adp.c
+@@ -0,0 +1,908 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_adp.c $
++ * $Revision: #16 $
++ * $Date: 2013/04/22 $
++ * $Change: 2211149 $
++ *
++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ * ========================================================================== */
++
++#include "dwc_os.h"
++#include "dwc_otg_regs.h"
++#include "dwc_otg_cil.h"
++#include "dwc_otg_adp.h"
++
++/** @file
++ *
++ * This file contains the most of the Attach Detect Protocol implementation for
++ * the driver to support OTG Rev2.0.
++ *
++ */
++
++void dwc_otg_adp_write_reg(dwc_otg_core_if_t * core_if, uint32_t value)
++{
++	adpctl_data_t adpctl;
++
++	adpctl.d32 = value;
++	adpctl.b.ar = 0x2;
++
++	DWC_WRITE_REG32(&core_if->core_global_regs->adpctl, adpctl.d32);
++
++	while (adpctl.b.ar) {
++		adpctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->adpctl);
++	}
++
++}
++
++/**
++ * Function is called to read ADP registers
++ */
++uint32_t dwc_otg_adp_read_reg(dwc_otg_core_if_t * core_if)
++{
++	adpctl_data_t adpctl;
++
++	adpctl.d32 = 0;
++	adpctl.b.ar = 0x1;
++
++	DWC_WRITE_REG32(&core_if->core_global_regs->adpctl, adpctl.d32);
++
++	while (adpctl.b.ar) {
++		adpctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->adpctl);
++	}
++
++	return adpctl.d32;
++}
++
++/**
++ * Function is called to read ADPCTL register and filter Write-clear bits
++ */
++uint32_t dwc_otg_adp_read_reg_filter(dwc_otg_core_if_t * core_if)
++{
++	adpctl_data_t adpctl;
++
++	adpctl.d32 = dwc_otg_adp_read_reg(core_if);
++	adpctl.b.adp_tmout_int = 0;
++	adpctl.b.adp_prb_int = 0;
++	adpctl.b.adp_tmout_int = 0;
++
++	return adpctl.d32;
++}
++
++/**
++ * Function is called to write ADP registers
++ */
++void dwc_otg_adp_modify_reg(dwc_otg_core_if_t * core_if, uint32_t clr,
++			    uint32_t set)
++{
++	dwc_otg_adp_write_reg(core_if,
++			      (dwc_otg_adp_read_reg(core_if) & (~clr)) | set);
++}
++
++static void adp_probe_func(void * ptr)
++{
++	dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) ptr;
++	dwc_otg_adp_probe_start(core_if);
++}
++
++static void adp_sense_timeout(void *ptr)
++{
++	dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) ptr;
++	core_if->adp.sense_timer_started = 0;
++	DWC_DEBUGPL(DBG_PCD, "ADP SENSE TIMEOUT\n");
++	if (core_if->adp_enable) {
++		dwc_otg_adp_sense_stop(core_if);
++		DWC_WORKQ_SCHEDULE_DELAYED(core_if->wq_otg, adp_probe_func,
++						core_if, 100 , "start probe");
++	}
++}
++
++/**
++ * This function is called when the ADP vbus timer expires. Timeout is 1.1s.
++ */
++static void adp_vbuson_timeout(void *ptr)
++{
++	gpwrdn_data_t gpwrdn;
++	dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) ptr;
++	hprt0_data_t hprt0 = {.d32 = 0 };
++	pcgcctl_data_t pcgcctl = {.d32 = 0 };
++	DWC_PRINTF("%s: 1.1 seconds expire after turning on VBUS\n",__FUNCTION__);
++	if (core_if) {
++		core_if->adp.vbuson_timer_started = 0;
++		if(dwc_otg_is_host_mode(core_if)) {
++			/* Turn off vbus */
++			hprt0.b.prtpwr = 1;
++			DWC_MODIFY_REG32(core_if->host_if->hprt0, hprt0.d32, 0);
++			cil_hcd_disconnect(core_if);
++		}
++		gpwrdn.d32 = 0;
++
++		/* Power off the core */
++		if (core_if->power_down == 2) {
++			/* Enable Wakeup Logic */
++//                      gpwrdn.b.wkupactiv = 1;
++			gpwrdn.b.pmuactv = 0;
++			gpwrdn.b.pwrdnrstn = 1;
++			gpwrdn.b.pwrdnclmp = 1;
++			DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0,
++					 gpwrdn.d32);
++
++			/* Suspend the Phy Clock */
++			pcgcctl.b.stoppclk = 1;
++			DWC_MODIFY_REG32(core_if->pcgcctl, 0, pcgcctl.d32);
++
++			/* Switch on VDD */
++//                      gpwrdn.b.wkupactiv = 1;
++			gpwrdn.b.pmuactv = 1;
++			gpwrdn.b.pwrdnrstn = 1;
++			gpwrdn.b.pwrdnclmp = 1;
++			DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0,
++					 gpwrdn.d32);
++		} else {
++			/* Enable Power Down Logic */
++			gpwrdn.b.pmuintsel = 1;
++			gpwrdn.b.pmuactv = 1;
++			if(dwc_otg_is_host_mode(core_if))
++				gpwrdn.b.dis_vbus = 1;
++			DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
++		}
++
++		/* Power off the core */
++		if (core_if->power_down == 2) {
++			gpwrdn.d32 = 0;
++			gpwrdn.b.pwrdnswtch = 1;
++			DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn,
++					 gpwrdn.d32, 0);
++		}
++
++		/* Unmask SRP detected interrupt from Power Down Logic */
++		gpwrdn.d32 = 0;
++		gpwrdn.b.srp_det_msk = 1;
++		DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
++
++		dwc_mdelay(220);
++		dwc_otg_adp_probe_start(core_if);
++	}
++
++}
++
++/**
++ * Start the ADP Initial Probe timer to detect if Port Connected interrupt is
++ * not asserted within 1.1 seconds.
++ *
++ * @param core_if the pointer to core_if strucure.
++ */
++void dwc_otg_adp_vbuson_timer_start(dwc_otg_core_if_t * core_if)
++{
++	core_if->adp.vbuson_timer_started = 1;
++	if (core_if->adp.vbuson_timer)
++	{
++		DWC_PRINTF("SCHEDULING VBUSON TIMER\n");
++		/* 1.1 secs + 60ms necessary for cil_hcd_start*/
++		DWC_TIMER_SCHEDULE(core_if->adp.vbuson_timer, 1160);
++	} else {
++		DWC_WARN("VBUSON_TIMER = %p\n",core_if->adp.vbuson_timer);
++	}
++}
++
++#if 0
++/**
++ * Masks all DWC OTG core interrupts
++ *
++ */
++static void mask_all_interrupts(dwc_otg_core_if_t * core_if)
++{
++	int i;
++	gahbcfg_data_t ahbcfg = {.d32 = 0 };
++
++	/* Mask Host Interrupts */
++
++	/* Clear and disable HCINTs */
++	for (i = 0; i < core_if->core_params->host_channels; i++) {
++		DWC_WRITE_REG32(&core_if->host_if->hc_regs[i]->hcintmsk, 0);
++		DWC_WRITE_REG32(&core_if->host_if->hc_regs[i]->hcint, 0xFFFFFFFF);
++
++	}
++
++	/* Clear and disable HAINT */
++	DWC_WRITE_REG32(&core_if->host_if->host_global_regs->haintmsk, 0x0000);
++	DWC_WRITE_REG32(&core_if->host_if->host_global_regs->haint, 0xFFFFFFFF);
++
++	/* Mask Device Interrupts */
++	if (!core_if->multiproc_int_enable) {
++		/* Clear and disable IN Endpoint interrupts */
++		DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->diepmsk, 0);
++		for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
++			DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[i]->
++					diepint, 0xFFFFFFFF);
++		}
++
++		/* Clear and disable OUT Endpoint interrupts */
++		DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->doepmsk, 0);
++		for (i = 0; i <= core_if->dev_if->num_out_eps; i++) {
++			DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[i]->
++					doepint, 0xFFFFFFFF);
++		}
++
++		/* Clear and disable DAINT */
++		DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->daint,
++				0xFFFFFFFF);
++		DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->daintmsk, 0);
++	} else {
++		for (i = 0; i < core_if->dev_if->num_in_eps; ++i) {
++			DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->
++					diepeachintmsk[i], 0);
++			DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[i]->
++					diepint, 0xFFFFFFFF);
++		}
++
++		for (i = 0; i < core_if->dev_if->num_out_eps; ++i) {
++			DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->
++					doepeachintmsk[i], 0);
++			DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[i]->
++					doepint, 0xFFFFFFFF);
++		}
++
++		DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->deachintmsk,
++				0);
++		DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->deachint,
++				0xFFFFFFFF);
++
++	}
++
++	/* Disable interrupts */
++	ahbcfg.b.glblintrmsk = 1;
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gahbcfg, ahbcfg.d32, 0);
++
++	/* Disable all interrupts. */
++	DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, 0);
++
++	/* Clear any pending interrupts */
++	DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
++
++	/* Clear any pending OTG Interrupts */
++	DWC_WRITE_REG32(&core_if->core_global_regs->gotgint, 0xFFFFFFFF);
++}
++
++/**
++ * Unmask Port Connection Detected interrupt
++ *
++ */
++static void unmask_conn_det_intr(dwc_otg_core_if_t * core_if)
++{
++	gintmsk_data_t gintmsk = {.d32 = 0,.b.portintr = 1 };
++
++	DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, gintmsk.d32);
++}
++#endif
++
++/**
++ * Starts the ADP Probing
++ *
++ * @param core_if the pointer to core_if structure.
++ */
++uint32_t dwc_otg_adp_probe_start(dwc_otg_core_if_t * core_if)
++{
++
++	adpctl_data_t adpctl = {.d32 = 0};
++	gpwrdn_data_t gpwrdn;
++#if 0
++	adpctl_data_t adpctl_int = {.d32 = 0, .b.adp_prb_int = 1,
++				.b.adp_sns_int = 1, b.adp_tmout_int};
++#endif
++	if (core_if->stop_adpprb) {
++		core_if->stop_adpprb = 0;
++		return 0;
++	}
++
++	dwc_otg_disable_global_interrupts(core_if);
++	DWC_DEBUGPL(DBG_ANY, "ADP Probe Start\n");
++	core_if->adp.probe_enabled = 1;
++
++	adpctl.b.adpres = 1;
++	dwc_otg_adp_write_reg(core_if, adpctl.d32);
++
++	while (adpctl.b.adpres) {
++		adpctl.d32 = dwc_otg_adp_read_reg(core_if);
++	}
++
++	adpctl.d32 = 0;
++	gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
++
++	/* In Host mode unmask SRP detected interrupt also change the
++	 * probe preiod accordingly */
++	if (!gpwrdn.b.idsts) {
++		gpwrdn.d32 = 0;
++		gpwrdn.b.srp_det_msk = 1;
++		adpctl.b.prb_per = 0;
++	}
++	else {
++		gpwrdn.d32 = 0;
++		gpwrdn.b.srp_det_msk = 1;
++		DWC_MODIFY_REG32(&core_if->core_global_regs->
++						 gpwrdn, gpwrdn.d32, 0);
++		gpwrdn.d32 = 0;
++		gpwrdn.b.sts_chngint_msk = 1;
++		adpctl.b.prb_per = 1;
++	}
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
++
++	adpctl.b.adp_tmout_int_msk = 1;
++	adpctl.b.adp_prb_int_msk = 1;
++	adpctl.b.prb_dschg = 1;
++	adpctl.b.prb_delta = 1;
++	dwc_otg_adp_write_reg(core_if, adpctl.d32);
++
++	adpctl.b.adpen = 1;
++	adpctl.b.enaprb = 1;
++	dwc_otg_adp_write_reg(core_if, adpctl.d32);
++	DWC_DEBUGPL(DBG_ANY, "ADP Probe Finish\n");
++
++	return 0;
++}
++
++/**
++ * Starts the ADP Sense timer to detect if ADP Sense interrupt is not asserted
++ * within 3 seconds.
++ *
++ * @param core_if the pointer to core_if strucure.
++ */
++void dwc_otg_adp_sense_timer_start(dwc_otg_core_if_t * core_if)
++{
++	core_if->adp.sense_timer_started = 1;
++	DWC_TIMER_SCHEDULE(core_if->adp.sense_timer, 3300 /* 3.3 secs */ );
++}
++
++/**
++ * Starts the ADP Sense
++ *
++ * @param core_if the pointer to core_if strucure.
++ */
++uint32_t dwc_otg_adp_sense_start(dwc_otg_core_if_t * core_if)
++{
++	adpctl_data_t adpctl;
++
++	DWC_DEBUGPL(DBG_PCD, "ADP Sense Start\n");
++
++	/* Set ADP reset bit*/
++	adpctl.d32 = dwc_otg_adp_read_reg_filter(core_if);
++	adpctl.b.adpres = 1;
++	dwc_otg_adp_write_reg(core_if, adpctl.d32);
++
++	while (adpctl.b.adpres) {
++		adpctl.d32 = dwc_otg_adp_read_reg(core_if);
++	}
++
++	/* Unmask ADP sense interrupt and mask all other from the core */
++	adpctl.d32 = dwc_otg_adp_read_reg_filter(core_if);
++	adpctl.b.adp_sns_int_msk = 1;
++	dwc_otg_adp_write_reg(core_if, adpctl.d32);
++	dwc_otg_disable_global_interrupts(core_if);
++
++	adpctl.b.adpres = 0;
++	adpctl.b.adpen = 1;
++	adpctl.b.enasns = 1;
++	dwc_otg_adp_write_reg(core_if, adpctl.d32);
++
++	dwc_otg_adp_sense_timer_start(core_if);
++
++	return 0;
++}
++
++/**
++ * Stops the ADP Probing
++ *
++ * @param core_if the pointer to core_if strucure.
++ */
++uint32_t dwc_otg_adp_probe_stop(dwc_otg_core_if_t * core_if)
++{
++
++	adpctl_data_t adpctl;
++	DWC_DEBUGPL(DBG_ANY, "Stop ADP probe\n");
++	core_if->adp.probe_enabled = 0;
++	//core_if->adp.probe_counter = 0;
++	adpctl.d32 = dwc_otg_adp_read_reg(core_if);
++
++	adpctl.b.adpen = 0;
++	adpctl.b.adp_prb_int = 1;
++	adpctl.b.adp_tmout_int = 1;
++	adpctl.b.adp_sns_int = 1;
++	dwc_otg_adp_write_reg(core_if, adpctl.d32);
++
++	return 0;
++}
++
++/**
++ * Stops the ADP Sensing
++ *
++ * @param core_if the pointer to core_if strucure.
++ */
++uint32_t dwc_otg_adp_sense_stop(dwc_otg_core_if_t * core_if)
++{
++	adpctl_data_t adpctl;
++
++	core_if->adp.sense_enabled = 0;
++
++	adpctl.d32 = dwc_otg_adp_read_reg_filter(core_if);
++	adpctl.b.enasns = 0;
++	adpctl.b.adp_sns_int = 1;
++	dwc_otg_adp_write_reg(core_if, adpctl.d32);
++
++	return 0;
++}
++
++/**
++ * Called to turn on the VBUS after initial ADP probe in host mode.
++ * If port power was already enabled in cil_hcd_start function then
++ * only schedule a timer.
++ *
++ * @param core_if the pointer to core_if structure.
++ */
++void dwc_otg_adp_turnon_vbus(dwc_otg_core_if_t * core_if)
++{
++	hprt0_data_t hprt0 = {.d32 = 0 };
++	hprt0.d32 = dwc_otg_read_hprt0(core_if);
++	DWC_PRINTF("Turn on VBUS for 1.1s, port power is %d\n", hprt0.b.prtpwr);
++
++	if (hprt0.b.prtpwr == 0) {
++		hprt0.b.prtpwr = 1;
++		//DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
++	}
++
++	dwc_otg_adp_vbuson_timer_start(core_if);
++}
++
++/**
++ * Called right after driver is loaded
++ * to perform initial actions for ADP
++ *
++ * @param core_if the pointer to core_if structure.
++ * @param is_host - flag for current mode of operation either from GINTSTS or GPWRDN
++ */
++void dwc_otg_adp_start(dwc_otg_core_if_t * core_if, uint8_t is_host)
++{
++	gpwrdn_data_t gpwrdn;
++
++	DWC_DEBUGPL(DBG_ANY, "ADP Initial Start\n");
++	core_if->adp.adp_started = 1;
++
++	DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
++	dwc_otg_disable_global_interrupts(core_if);
++	if (is_host) {
++		DWC_PRINTF("HOST MODE\n");
++		//core_if->op_state = A_HOST; - vahrama, modified checking in hcd_start()
++		/* Enable Power Down Logic Interrupt*/
++		gpwrdn.d32 = 0;
++		gpwrdn.b.pmuintsel = 1;
++		gpwrdn.b.pmuactv = 1;
++		DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
++		/* Initialize first ADP probe to obtain Ramp Time value */
++		core_if->adp.initial_probe = 1;
++		dwc_otg_adp_probe_start(core_if);
++	} else {
++		gotgctl_data_t gotgctl;
++		gotgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
++		DWC_DEBUGPL(DBG_ANY, "DEVICE MODE\n");
++		//dwc_otg_core_init(core_if);
++		if (gotgctl.b.bsesvld == 0) {
++			/* Enable Power Down Logic Interrupt*/
++			gpwrdn.d32 = 0;
++			DWC_DEBUGPL(DBG_ANY, "VBUS is not valid - start ADP probe\n");
++			gpwrdn.b.pmuintsel = 1;
++			gpwrdn.b.pmuactv = 1;
++			DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
++			/* Do not need to return to inital probe if we are coming back to
++			 * the device mode after HNP */
++			if (core_if->op_state != B_HOST)
++				core_if->adp.initial_probe = 1;
++			dwc_otg_adp_probe_start(core_if);
++		} else {
++			DWC_PRINTF("VBUS is valid - initialize core as a Device\n");
++			core_if->op_state = B_PERIPHERAL;
++			//dwc_otg_core_init(core_if);
++			dwc_otg_enable_global_interrupts(core_if);
++			cil_pcd_start(core_if);
++			dwc_otg_dump_global_registers(core_if);
++			dwc_otg_dump_dev_registers(core_if);
++		}
++	}
++}
++
++void dwc_otg_adp_init(dwc_otg_core_if_t * core_if)
++{
++	core_if->adp.adp_started = 0;
++	core_if->adp.initial_probe = 0;
++	core_if->adp.probe_timer_values[0] = -1;
++	core_if->adp.probe_timer_values[1] = -1;
++	core_if->adp.probe_enabled = 0;
++	core_if->adp.sense_enabled = 0;
++	core_if->adp.sense_timer_started = 0;
++	core_if->adp.vbuson_timer_started = 0;
++	core_if->adp.probe_counter = 0;
++	core_if->adp.gpwrdn = 0;
++	core_if->adp.attached = DWC_OTG_ADP_UNKOWN;
++	/* Initialize timers */
++	core_if->adp.sense_timer =
++	    DWC_TIMER_ALLOC("ADP SENSE TIMER", adp_sense_timeout, core_if);
++	core_if->adp.vbuson_timer =
++	    DWC_TIMER_ALLOC("ADP VBUS ON TIMER", adp_vbuson_timeout, core_if);
++	if (!core_if->adp.sense_timer || !core_if->adp.vbuson_timer)
++	{
++		DWC_ERROR("Could not allocate memory for ADP timers\n");
++	}
++}
++
++void dwc_otg_adp_remove(dwc_otg_core_if_t * core_if)
++{
++	gpwrdn_data_t gpwrdn = { .d32 = 0 };
++	gpwrdn.b.pmuintsel = 1;
++	gpwrdn.b.pmuactv = 1;
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++
++	if (core_if->adp.probe_enabled)
++		dwc_otg_adp_probe_stop(core_if);
++	if (core_if->adp.sense_enabled)
++		dwc_otg_adp_sense_stop(core_if);
++	if (core_if->adp.sense_timer_started)
++		DWC_TIMER_CANCEL(core_if->adp.sense_timer);
++	if (core_if->adp.vbuson_timer_started)
++		DWC_TIMER_CANCEL(core_if->adp.vbuson_timer);
++	DWC_TIMER_FREE(core_if->adp.sense_timer);
++	DWC_TIMER_FREE(core_if->adp.vbuson_timer);
++}
++
++/////////////////////////////////////////////////////////////////////
++////////////// ADP Interrupt Handlers ///////////////////////////////
++/////////////////////////////////////////////////////////////////////
++/**
++ * This function sets Ramp Timer values
++ */
++static uint32_t set_timer_value(dwc_otg_core_if_t * core_if, uint32_t val)
++{
++	if (core_if->adp.probe_timer_values[0] == -1) {
++		core_if->adp.probe_timer_values[0] = val;
++		core_if->adp.probe_timer_values[1] = -1;
++		return 1;
++	} else {
++		core_if->adp.probe_timer_values[1] =
++		    core_if->adp.probe_timer_values[0];
++		core_if->adp.probe_timer_values[0] = val;
++		return 0;
++	}
++}
++
++/**
++ * This function compares Ramp Timer values
++ */
++static uint32_t compare_timer_values(dwc_otg_core_if_t * core_if)
++{
++	uint32_t diff;
++	uint32_t thres;
++	gpwrdn_data_t gpwrdn;
++
++	/* RTIM difference thresold differs for host and device modes */
++	gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
++	if (!gpwrdn.b.idsts)
++		thres = HOST_RTIM_THRESHOLD;
++	else
++		thres = DEVICE_RTIM_THRESHOLD;
++
++	DWC_DEBUGPL(DBG_ANY, "timer value 0 %d timer value 1 %d\n",
++		core_if->adp.probe_timer_values[0], core_if->adp.probe_timer_values[1]);
++	if (core_if->adp.probe_timer_values[0] >= core_if->adp.probe_timer_values[1])
++		diff = core_if->adp.probe_timer_values[0] - core_if->adp.probe_timer_values[1];
++	else
++		diff = core_if->adp.probe_timer_values[1] - core_if->adp.probe_timer_values[0];
++	if (diff < thres)
++		return 0;
++	else
++		return 1;
++}
++
++/**
++ * This function handles ADP Probe Interrupts
++ */
++static int32_t dwc_otg_adp_handle_prb_intr(dwc_otg_core_if_t * core_if,
++						 uint32_t val)
++{
++	adpctl_data_t adpctl = {.d32 = 0 };
++	gpwrdn_data_t gpwrdn, temp;
++	adpctl.d32 = val;
++
++	temp.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
++
++	core_if->adp.gpwrdn = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
++	if (adpctl.b.rtim == 0 /*&& !temp.b.idsts*/){
++		DWC_PRINTF("RTIM value is 0\n");
++		goto exit;
++	}
++	core_if->adp.probe_counter++;
++
++	if (set_timer_value(core_if, adpctl.b.rtim) &&
++	    core_if->adp.initial_probe) {
++		core_if->adp.initial_probe = 0;
++		dwc_otg_adp_probe_stop(core_if);
++		gpwrdn.d32 = 0;
++		gpwrdn.b.pmuactv = 1;
++		gpwrdn.b.pmuintsel = 1;
++		DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++		DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
++
++		/* check which value is for device mode and which for Host mode */
++		if (!temp.b.idsts) {	/* considered host mode value is 0 */
++			/* Choose right op_state depending on previous one */
++			if (core_if->op_state == B_PERIPHERAL)
++				core_if->op_state = B_HOST;
++			else
++				core_if->op_state = A_HOST;
++			dwc_otg_enable_global_interrupts(core_if);
++			/*
++			 * Turn on VBUS after initial ADP probe.
++			 */
++			DWC_SPINUNLOCK(core_if->lock);
++			cil_hcd_start(core_if);
++			dwc_otg_adp_turnon_vbus(core_if);
++			DWC_SPINLOCK(core_if->lock);
++		} else {
++			/*
++			 * Initiate SRP after initial ADP probe.
++			 */
++			dwc_otg_enable_global_interrupts(core_if);
++			dwc_otg_initiate_srp(core_if);
++		}
++	} else if (core_if->adp.probe_counter > 2){
++		gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
++		if (compare_timer_values(core_if)) {
++			DWC_PRINTF("Difference in timer values !!! \n");
++//          core_if->adp.attached = DWC_OTG_ADP_ATTACHED;
++			dwc_otg_adp_probe_stop(core_if);
++
++			/* Power on the core */
++			if (core_if->power_down == 2) {
++				gpwrdn.b.pwrdnswtch = 1;
++				DWC_MODIFY_REG32(&core_if->core_global_regs->
++						 gpwrdn, 0, gpwrdn.d32);
++			}
++
++			/* check which value is for device mode and which for Host mode */
++			if (!temp.b.idsts) {	/* considered host mode value is 0 */
++				/* Disable Interrupt from Power Down Logic */
++				gpwrdn.d32 = 0;
++				gpwrdn.b.pmuintsel = 1;
++				gpwrdn.b.pmuactv = 1;
++				DWC_MODIFY_REG32(&core_if->core_global_regs->
++						 gpwrdn, gpwrdn.d32, 0);
++
++				/*
++				 * Initialize the Core for Host mode.
++				 * Choose right op_state depending on previous one
++				 */
++				if (core_if->op_state == B_PERIPHERAL)
++					core_if->op_state = B_HOST;
++				else
++					core_if->op_state = A_HOST;
++
++				dwc_otg_core_init(core_if);
++				dwc_otg_enable_global_interrupts(core_if);
++				cil_hcd_start(core_if);
++				dwc_otg_adp_turnon_vbus(core_if);
++			} else {
++				gotgctl_data_t gotgctl;
++				/* Mask SRP detected interrupt from Power Down Logic */
++				gpwrdn.d32 = 0;
++				gpwrdn.b.srp_det_msk = 1;
++				DWC_MODIFY_REG32(&core_if->core_global_regs->
++						 gpwrdn, gpwrdn.d32, 0);
++
++				/* Disable Power Down Logic */
++				gpwrdn.d32 = 0;
++				gpwrdn.b.pmuintsel = 1;
++				gpwrdn.b.pmuactv = 1;
++				DWC_MODIFY_REG32(&core_if->core_global_regs->
++						 gpwrdn, gpwrdn.d32, 0);
++
++				/*
++				 * Initialize the Core for Device mode.
++				 */
++				core_if->op_state = B_PERIPHERAL;
++				//dwc_otg_core_init(core_if);
++				cil_pcd_start(core_if);
++				dwc_otg_enable_global_interrupts(core_if);
++
++				gotgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
++				if (!gotgctl.b.bsesvld)
++					dwc_otg_initiate_srp(core_if);
++			}
++		}
++		if (core_if->power_down == 2) {
++			if (gpwrdn.b.bsessvld) {
++				/* Mask SRP detected interrupt from Power Down Logic */
++				gpwrdn.d32 = 0;
++				gpwrdn.b.srp_det_msk = 1;
++				DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++
++				/* Disable Power Down Logic */
++				gpwrdn.d32 = 0;
++				gpwrdn.b.pmuactv = 1;
++				DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++
++				/*
++				 * Initialize the Core for Device mode.
++				 */
++				core_if->op_state = B_PERIPHERAL;
++				dwc_otg_core_init(core_if);
++				dwc_otg_enable_global_interrupts(core_if);
++				cil_pcd_start(core_if);
++			}
++		}
++	}
++exit:
++	/* Clear interrupt */
++	adpctl.d32 = dwc_otg_adp_read_reg(core_if);
++	adpctl.b.adp_prb_int = 1;
++	dwc_otg_adp_write_reg(core_if, adpctl.d32);
++
++	return 0;
++}
++
++/**
++ * This function hadles ADP Sense Interrupt
++ */
++static int32_t dwc_otg_adp_handle_sns_intr(dwc_otg_core_if_t * core_if)
++{
++	adpctl_data_t adpctl;
++	/* Stop ADP Sense timer */
++	DWC_TIMER_CANCEL(core_if->adp.sense_timer);
++
++	/* Restart ADP Sense timer */
++	dwc_otg_adp_sense_timer_start(core_if);
++
++	/* Clear interrupt */
++	adpctl.d32 = dwc_otg_adp_read_reg(core_if);
++	adpctl.b.adp_sns_int = 1;
++	dwc_otg_adp_write_reg(core_if, adpctl.d32);
++
++	return 0;
++}
++
++/**
++ * This function handles ADP Probe Interrupts
++ */
++static int32_t dwc_otg_adp_handle_prb_tmout_intr(dwc_otg_core_if_t * core_if,
++						 uint32_t val)
++{
++	adpctl_data_t adpctl = {.d32 = 0 };
++	adpctl.d32 = val;
++	set_timer_value(core_if, adpctl.b.rtim);
++
++	/* Clear interrupt */
++	adpctl.d32 = dwc_otg_adp_read_reg(core_if);
++	adpctl.b.adp_tmout_int = 1;
++	dwc_otg_adp_write_reg(core_if, adpctl.d32);
++
++	return 0;
++}
++
++/**
++ * ADP Interrupt handler.
++ *
++ */
++int32_t dwc_otg_adp_handle_intr(dwc_otg_core_if_t * core_if)
++{
++	int retval = 0;
++	adpctl_data_t adpctl = {.d32 = 0};
++
++	adpctl.d32 = dwc_otg_adp_read_reg(core_if);
++	DWC_DEBUGPL(DBG_ANY, "ADPCTL = %08x RAMP TIME = %d\n", adpctl.d32, adpctl.b.rtim);
++
++	if (adpctl.b.adp_sns_int & adpctl.b.adp_sns_int_msk) {
++		DWC_DEBUGPL(DBG_ANY, "ADP Sense interrupt\n");
++		retval |= dwc_otg_adp_handle_sns_intr(core_if);
++	}
++	if (adpctl.b.adp_tmout_int & adpctl.b.adp_tmout_int_msk) {
++		DWC_DEBUGPL(DBG_ANY, "ADP timeout interrupt\n");
++		retval |= dwc_otg_adp_handle_prb_tmout_intr(core_if, adpctl.d32);
++	}
++	if (adpctl.b.adp_prb_int & adpctl.b.adp_prb_int_msk) {
++		DWC_DEBUGPL(DBG_ANY, "ADP Probe interrupt\n");
++		adpctl.b.adp_prb_int = 1;
++		retval |= dwc_otg_adp_handle_prb_intr(core_if, adpctl.d32);
++	}
++
++//	dwc_otg_adp_modify_reg(core_if, adpctl.d32, 0);
++	//dwc_otg_adp_write_reg(core_if, adpctl.d32);
++	DWC_DEBUGPL(DBG_ANY, "RETURN FROM ADP ISR\n");
++
++	return retval;
++}
++
++/**
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ */
++int32_t dwc_otg_adp_handle_srp_intr(dwc_otg_core_if_t * core_if)
++{
++
++#ifndef DWC_HOST_ONLY
++	hprt0_data_t hprt0;
++	gpwrdn_data_t gpwrdn;
++	DWC_DEBUGPL(DBG_ANY, "++ Power Down Logic Session Request Interrupt++\n");
++
++	gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
++	/* check which value is for device mode and which for Host mode */
++	if (!gpwrdn.b.idsts) {	/* considered host mode value is 0 */
++		DWC_PRINTF("SRP: Host mode\n");
++
++		if (core_if->adp_enable) {
++			dwc_otg_adp_probe_stop(core_if);
++
++			/* Power on the core */
++			if (core_if->power_down == 2) {
++				gpwrdn.b.pwrdnswtch = 1;
++				DWC_MODIFY_REG32(&core_if->core_global_regs->
++						 gpwrdn, 0, gpwrdn.d32);
++			}
++
++			core_if->op_state = A_HOST;
++			dwc_otg_core_init(core_if);
++			dwc_otg_enable_global_interrupts(core_if);
++			cil_hcd_start(core_if);
++		}
++
++		/* Turn on the port power bit. */
++		hprt0.d32 = dwc_otg_read_hprt0(core_if);
++		hprt0.b.prtpwr = 1;
++		DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
++
++		/* Start the Connection timer. So a message can be displayed
++		 * if connect does not occur within 10 seconds. */
++		cil_hcd_session_start(core_if);
++	} else {
++		DWC_DEBUGPL(DBG_PCD, "SRP: Device mode %s\n", __FUNCTION__);
++		if (core_if->adp_enable) {
++			dwc_otg_adp_probe_stop(core_if);
++
++			/* Power on the core */
++			if (core_if->power_down == 2) {
++				gpwrdn.b.pwrdnswtch = 1;
++				DWC_MODIFY_REG32(&core_if->core_global_regs->
++						 gpwrdn, 0, gpwrdn.d32);
++			}
++
++			gpwrdn.d32 = 0;
++			gpwrdn.b.pmuactv = 0;
++			DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0,
++					 gpwrdn.d32);
++
++			core_if->op_state = B_PERIPHERAL;
++			dwc_otg_core_init(core_if);
++			dwc_otg_enable_global_interrupts(core_if);
++			cil_pcd_start(core_if);
++		}
++	}
++#endif
++	return 1;
++}
+diff --git a/drivers/usb/gadget/udc/hiudc/dwc_otg_adp.h b/drivers/usb/gadget/udc/hiudc/dwc_otg_adp.h
+new file mode 100644
+index 0000000..c21b2f0
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc/dwc_otg_adp.h
+@@ -0,0 +1,82 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_adp.h $
++ * $Revision: #8 $
++ * $Date: 2013/04/09 $
++ * $Change: 2201932 $
++ *
++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
++ * ========================================================================== */
++
++#ifndef __DWC_OTG_ADP_H__
++#define __DWC_OTG_ADP_H__
++
++/**
++ * @file
++ *
++ * This file contains the Attach Detect Protocol interfaces and defines
++ * (functions) and structures for Linux.
++ *
++ */
++
++#define DWC_OTG_ADP_UNATTACHED	0
++#define DWC_OTG_ADP_ATTACHED	1
++#define DWC_OTG_ADP_UNKOWN	2
++#define HOST_RTIM_THRESHOLD 5
++#define DEVICE_RTIM_THRESHOLD 3
++
++typedef struct dwc_otg_adp {
++	uint32_t adp_started;
++	uint32_t initial_probe;
++	int32_t probe_timer_values[2];
++	uint32_t probe_enabled;
++	uint32_t sense_enabled;
++	dwc_timer_t *sense_timer;
++	uint32_t sense_timer_started;
++	dwc_timer_t *vbuson_timer;
++	uint32_t vbuson_timer_started;
++	uint32_t attached;
++	uint32_t probe_counter;
++	uint32_t gpwrdn;
++} dwc_otg_adp_t;
++
++/**
++ * Attach Detect Protocol functions
++ */
++
++extern void dwc_otg_adp_write_reg(dwc_otg_core_if_t * core_if, uint32_t value);
++extern uint32_t dwc_otg_adp_read_reg(dwc_otg_core_if_t * core_if);
++extern uint32_t dwc_otg_adp_probe_start(dwc_otg_core_if_t * core_if);
++extern uint32_t dwc_otg_adp_sense_start(dwc_otg_core_if_t * core_if);
++extern uint32_t dwc_otg_adp_probe_stop(dwc_otg_core_if_t * core_if);
++extern uint32_t dwc_otg_adp_sense_stop(dwc_otg_core_if_t * core_if);
++extern void dwc_otg_adp_start(dwc_otg_core_if_t * core_if, uint8_t is_host);
++extern void dwc_otg_adp_init(dwc_otg_core_if_t * core_if);
++extern void dwc_otg_adp_remove(dwc_otg_core_if_t * core_if);
++extern int32_t dwc_otg_adp_handle_intr(dwc_otg_core_if_t * core_if);
++extern int32_t dwc_otg_adp_handle_srp_intr(dwc_otg_core_if_t * core_if);
++
++#endif //__DWC_OTG_ADP_H__
+diff --git a/drivers/usb/gadget/udc/hiudc/dwc_otg_attr.c b/drivers/usb/gadget/udc/hiudc/dwc_otg_attr.c
+new file mode 100644
+index 0000000..73fc330
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc/dwc_otg_attr.c
+@@ -0,0 +1,1311 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_attr.c $
++ * $Revision: #46 $
++ * $Date: 2012/12/12 $
++ * $Change: 2124654 $
++ *
++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
++ * ========================================================================== */
++
++/** @file
++ *
++ * The diagnostic interface will provide access to the controller for
++ * bringing up the hardware and testing.  The Linux driver attributes
++ * feature will be used to provide the Linux Diagnostic
++ * Interface. These attributes are accessed through sysfs.
++ */
++
++/** @page "Linux Module Attributes"
++ *
++ * The Linux module attributes feature is used to provide the Linux
++ * Diagnostic Interface.  These attributes are accessed through sysfs.
++ * The diagnostic interface will provide access to the controller for
++ * bringing up the hardware and testing.
++
++ The following table shows the attributes.
++ <table>
++ <tr>
++ <td><b> Name</b></td>
++ <td><b> Description</b></td>
++ <td><b> Access</b></td>
++ </tr>
++
++ <tr>
++ <td> mode </td>
++ <td> Returns the current mode: 0 for device mode, 1 for host mode</td>
++ <td> Read</td>
++ </tr>
++
++ <tr>
++ <td> hnpcapable </td>
++ <td> Gets or sets the "HNP-capable" bit in the Core USB Configuraton Register.
++ Read returns the current value.</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> srpcapable </td>
++ <td> Gets or sets the "SRP-capable" bit in the Core USB Configuraton Register.
++ Read returns the current value.</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> hsic_connect </td>
++ <td> Gets or sets the "HSIC-Connect" bit in the GLPMCFG Register.
++ Read returns the current value.</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> inv_sel_hsic </td>
++ <td> Gets or sets the "Invert Select HSIC" bit in the GLPMFG Register.
++ Read returns the current value.</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> hnp </td>
++ <td> Initiates the Host Negotiation Protocol.  Read returns the status.</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> srp </td>
++ <td> Initiates the Session Request Protocol.  Read returns the status.</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> buspower </td>
++ <td> Gets or sets the Power State of the bus (0 - Off or 1 - On)</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> bussuspend </td>
++ <td> Suspends the USB bus.</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> busconnected </td>
++ <td> Gets the connection status of the bus</td>
++ <td> Read</td>
++ </tr>
++
++ <tr>
++ <td> gotgctl </td>
++ <td> Gets or sets the Core Control Status Register.</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> gusbcfg </td>
++ <td> Gets or sets the Core USB Configuration Register</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> grxfsiz </td>
++ <td> Gets or sets the Receive FIFO Size Register</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> gnptxfsiz </td>
++ <td> Gets or sets the non-periodic Transmit Size Register</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> gpvndctl </td>
++ <td> Gets or sets the PHY Vendor Control Register</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> ggpio </td>
++ <td> Gets the value in the lower 16-bits of the General Purpose IO Register
++ or sets the upper 16 bits.</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> guid </td>
++ <td> Gets or sets the value of the User ID Register</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> gsnpsid </td>
++ <td> Gets the value of the Synopsys ID Regester</td>
++ <td> Read</td>
++ </tr>
++
++ <tr>
++ <td> devspeed </td>
++ <td> Gets or sets the device speed setting in the DCFG register</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> enumspeed </td>
++ <td> Gets the device enumeration Speed.</td>
++ <td> Read</td>
++ </tr>
++
++ <tr>
++ <td> hptxfsiz </td>
++ <td> Gets the value of the Host Periodic Transmit FIFO</td>
++ <td> Read</td>
++ </tr>
++
++ <tr>
++ <td> hprt0 </td>
++ <td> Gets or sets the value in the Host Port Control and Status Register</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> regoffset </td>
++ <td> Sets the register offset for the next Register Access</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> regvalue </td>
++ <td> Gets or sets the value of the register at the offset in the regoffset attribute.</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> remote_wakeup </td>
++ <td> On read, shows the status of Remote Wakeup. On write, initiates a remote
++ wakeup of the host. When bit 0 is 1 and Remote Wakeup is enabled, the Remote
++ Wakeup signalling bit in the Device Control Register is set for 1
++ milli-second.</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> rem_wakeup_pwrdn </td>
++ <td> On read, shows the status core - hibernated or not. On write, initiates
++ a remote wakeup of the device from Hibernation. </td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> mode_ch_tim_en </td>
++ <td> This bit is used to enable or disable the host core to wait for 200 PHY
++ clock cycles at the end of Resume to change the opmode signal to the PHY to 00
++ after Suspend or LPM. </td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> fr_interval </td>
++ <td> On read, shows the value of HFIR Frame Interval. On write, dynamically
++ reload HFIR register during runtime. The application can write a value to this
++ register only after the Port Enable bit of the Host Port Control and Status
++ register (HPRT.PrtEnaPort) has been set </td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> disconnect_us </td>
++ <td> On read, shows the status of disconnect_device_us. On write, sets disconnect_us
++ which causes soft disconnect for 100us. Applicable only for device mode of operation.</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> regdump </td>
++ <td> Dumps the contents of core registers.</td>
++ <td> Read</td>
++ </tr>
++
++ <tr>
++ <td> spramdump </td>
++ <td> Dumps the contents of core registers.</td>
++ <td> Read</td>
++ </tr>
++
++ <tr>
++ <td> hcddump </td>
++ <td> Dumps the current HCD state.</td>
++ <td> Read</td>
++ </tr>
++
++ <tr>
++ <td> hcd_frrem </td>
++ <td> Shows the average value of the Frame Remaining
++ field in the Host Frame Number/Frame Remaining register when an SOF interrupt
++ occurs. This can be used to determine the average interrupt latency. Also
++ shows the average Frame Remaining value for start_transfer and the "a" and
++ "b" sample points. The "a" and "b" sample points may be used during debugging
++ bto determine how long it takes to execute a section of the HCD code.</td>
++ <td> Read</td>
++ </tr>
++
++ <tr>
++ <td> rd_reg_test </td>
++ <td> Displays the time required to read the GNPTXFSIZ register many times
++ (the output shows the number of times the register is read).
++ <td> Read</td>
++ </tr>
++
++ <tr>
++ <td> wr_reg_test </td>
++ <td> Displays the time required to write the GNPTXFSIZ register many times
++ (the output shows the number of times the register is written).
++ <td> Read</td>
++ </tr>
++
++ <tr>
++ <td> lpm_response </td>
++ <td> Gets or sets lpm_response mode. Applicable only in device mode.
++ <td> Write</td>
++ </tr>
++
++ <tr>
++ <td> sleep_status </td>
++ <td> Shows sleep status of device.
++ <td> Read</td>
++ </tr>
++
++ <tr>
++ <td> hird_thres </td>
++ <td> Gets or sets the "HIRD_Thres[3:0]" bits in the Core LPM Configuration Register.
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> besl_reject </td>
++ <td> Gets or sets the "besl_reject" bit in the Device Control Register.
++ <td> Read/Write</td>
++ </tr>
++
++ </table>
++
++ Example usage:
++ To get the current mode:
++ cat /sys/devices/lm0/mode
++
++ To power down the USB:
++ echo 0 > /sys/devices/lm0/buspower
++ */
++
++#include "dwc_otg_os_dep.h"
++#include "dwc_os.h"
++#include "dwc_otg_driver.h"
++#include "dwc_otg_attr.h"
++#include "dwc_otg_core_if.h"
++#include "dwc_otg_pcd_if.h"
++#include "dwc_otg_hcd_if.h"
++
++/*
++ * MACROs for defining sysfs attribute
++ */
++
++
++#define DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \
++static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
++{ \
++	struct platform_device *lm_dev = container_of(_dev, struct platform_device, dev); \
++	dwc_otg_device_t *otg_dev = platform_get_drvdata(lm_dev);		\
++	uint32_t val; \
++	val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
++	return sprintf (buf, "%s = 0x%x\n", _string_, val); \
++}
++#define DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_,_string_) \
++static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
++					const char *buf, size_t count) \
++{ \
++	struct platform_device *lm_dev = container_of(_dev, struct platform_device, dev); \
++	dwc_otg_device_t *otg_dev = platform_get_drvdata(lm_dev); \
++	uint32_t set = simple_strtoul(buf, NULL, 16); \
++	dwc_otg_set_##_otg_attr_name_(otg_dev->core_if, set);\
++	return count; \
++}
++
++
++/*
++ * MACROs for defining sysfs attribute for 32-bit registers
++ */
++#define DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \
++static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
++{ \
++	struct platform_device *lm_dev = container_of(_dev, struct platform_device, dev); \
++	dwc_otg_device_t *otg_dev = platform_get_drvdata(lm_dev); \
++	uint32_t val; \
++	val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
++	return sprintf (buf, "%s = 0x%08x\n", _string_, val); \
++}
++#define DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_,_string_) \
++static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
++					const char *buf, size_t count) \
++{ \
++	struct platform_device *lm_dev = container_of(_dev, struct platform_device, dev); \
++	dwc_otg_device_t *otg_dev = platform_get_drvdata(lm_dev); \
++	uint32_t val = simple_strtoul(buf, NULL, 16); \
++	dwc_otg_set_##_otg_attr_name_ (otg_dev->core_if, val); \
++	return count; \
++}
++
++#define DWC_OTG_DEVICE_ATTR_BITFIELD_RW(_otg_attr_name_,_string_) \
++DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \
++DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_,_string_) \
++DEVICE_ATTR(_otg_attr_name_,0644,_otg_attr_name_##_show,_otg_attr_name_##_store);
++
++#define DWC_OTG_DEVICE_ATTR_BITFIELD_RO(_otg_attr_name_,_string_) \
++DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \
++DEVICE_ATTR(_otg_attr_name_,0444,_otg_attr_name_##_show,NULL);
++
++#define DWC_OTG_DEVICE_ATTR_REG32_RW(_otg_attr_name_,_addr_,_string_) \
++DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \
++DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_,_string_) \
++DEVICE_ATTR(_otg_attr_name_,0644,_otg_attr_name_##_show,_otg_attr_name_##_store);
++
++#define DWC_OTG_DEVICE_ATTR_REG32_RO(_otg_attr_name_,_addr_,_string_) \
++DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \
++DEVICE_ATTR(_otg_attr_name_,0444,_otg_attr_name_##_show,NULL);
++
++/** @name Functions for Show/Store of Attributes */
++/**@{*/
++
++/**
++ * Show the register offset of the Register Access.
++ */
++static ssize_t regoffset_show(struct device *_dev,
++			      struct device_attribute *attr, char *buf)
++{
++	struct platform_device *lm_dev = container_of(_dev, struct platform_device, dev);
++	dwc_otg_device_t *otg_dev = platform_get_drvdata(lm_dev);
++
++
++	return snprintf(buf, sizeof("0xFFFFFFFF\n") + 1, "0x%08x\n",
++			otg_dev->os_dep.reg_offset);
++}
++
++/**
++ * Set the register offset for the next Register Access		Read/Write
++ */
++static ssize_t regoffset_store(struct device *_dev,
++			       struct device_attribute *attr,
++			       const char *buf, size_t count)
++{
++
++	struct platform_device *lm_dev = container_of(_dev, struct platform_device, dev);
++	dwc_otg_device_t *otg_dev = platform_get_drvdata(lm_dev);
++
++
++	uint32_t offset = simple_strtoul(buf, NULL, 16);
++	if (offset < SZ_256K) {
++		otg_dev->os_dep.reg_offset = offset;
++	} else {
++		dev_err(_dev, "invalid offset\n");
++	}
++
++	return count;
++}
++
++DEVICE_ATTR(regoffset, S_IRUGO | S_IWUSR, regoffset_show, regoffset_store);
++
++/**
++ * Show the value of the register at the offset in the reg_offset
++ * attribute.
++ */
++static ssize_t regvalue_show(struct device *_dev,
++			     struct device_attribute *attr, char *buf)
++{
++	struct platform_device *lm_dev = container_of(_dev, struct platform_device, dev);
++	dwc_otg_device_t *otg_dev = platform_get_drvdata(lm_dev);
++
++
++	uint32_t val;
++	volatile uint32_t *addr;
++
++	if (otg_dev->os_dep.reg_offset != 0xFFFFFFFF && 0 != otg_dev->os_dep.base) {
++		/* Calculate the address */
++		addr = (uint32_t *) (otg_dev->os_dep.reg_offset +
++				     (uint8_t *) otg_dev->os_dep.base);
++		val = DWC_READ_REG32(addr);
++		return snprintf(buf,
++				sizeof("Reg@0xFFFFFFFF = 0xFFFFFFFF\n") + 1,
++				"Reg@0x%06x = 0x%08x\n", otg_dev->os_dep.reg_offset,
++				val);
++	} else {
++		dev_err(_dev, "Invalid offset (0x%0x)\n", otg_dev->os_dep.reg_offset);
++		return sprintf(buf, "invalid offset\n");
++	}
++}
++
++/**
++ * Store the value in the register at the offset in the reg_offset
++ * attribute.
++ *
++ */
++static ssize_t regvalue_store(struct device *_dev,
++			      struct device_attribute *attr,
++			      const char *buf, size_t count)
++{
++
++	struct platform_device *lm_dev = container_of(_dev, struct platform_device, dev);
++	dwc_otg_device_t *otg_dev = platform_get_drvdata(lm_dev);
++
++
++	volatile uint32_t *addr;
++	uint32_t val = simple_strtoul(buf, NULL, 16);
++	//dev_dbg(_dev, "Offset=0x%08x Val=0x%08x\n", otg_dev->reg_offset, val);
++	if (otg_dev->os_dep.reg_offset != 0xFFFFFFFF && 0 != otg_dev->os_dep.base) {
++		/* Calculate the address */
++		addr = (uint32_t *) (otg_dev->os_dep.reg_offset +
++				     (uint8_t *) otg_dev->os_dep.base);
++		DWC_WRITE_REG32(addr, val);
++	} else {
++		dev_err(_dev, "Invalid Register Offset (0x%08x)\n",
++			otg_dev->os_dep.reg_offset);
++	}
++	return count;
++}
++
++DEVICE_ATTR(regvalue, S_IRUGO | S_IWUSR, regvalue_show, regvalue_store);
++
++/*
++ * Attributes
++ */
++DWC_OTG_DEVICE_ATTR_BITFIELD_RO(mode, "Mode");
++DWC_OTG_DEVICE_ATTR_BITFIELD_RW(hnpcapable, "HNPCapable");
++DWC_OTG_DEVICE_ATTR_BITFIELD_RW(srpcapable, "SRPCapable");
++DWC_OTG_DEVICE_ATTR_BITFIELD_RW(hsic_connect, "HSIC Connect");
++DWC_OTG_DEVICE_ATTR_BITFIELD_RW(inv_sel_hsic, "Invert Select HSIC");
++
++//DWC_OTG_DEVICE_ATTR_BITFIELD_RW(buspower,&(otg_dev->core_if->core_global_regs->gotgctl),(1<<8),8,"Mode");
++//DWC_OTG_DEVICE_ATTR_BITFIELD_RW(bussuspend,&(otg_dev->core_if->core_global_regs->gotgctl),(1<<8),8,"Mode");
++DWC_OTG_DEVICE_ATTR_BITFIELD_RO(busconnected, "Bus Connected");
++
++DWC_OTG_DEVICE_ATTR_REG32_RW(gotgctl, 0, "GOTGCTL");
++DWC_OTG_DEVICE_ATTR_REG32_RW(gusbcfg,
++			     &(otg_dev->core_if->core_global_regs->gusbcfg),
++			     "GUSBCFG");
++DWC_OTG_DEVICE_ATTR_REG32_RW(grxfsiz,
++			     &(otg_dev->core_if->core_global_regs->grxfsiz),
++			     "GRXFSIZ");
++DWC_OTG_DEVICE_ATTR_REG32_RW(gnptxfsiz,
++			     &(otg_dev->core_if->core_global_regs->gnptxfsiz),
++			     "GNPTXFSIZ");
++DWC_OTG_DEVICE_ATTR_REG32_RW(gpvndctl,
++			     &(otg_dev->core_if->core_global_regs->gpvndctl),
++			     "GPVNDCTL");
++DWC_OTG_DEVICE_ATTR_REG32_RW(ggpio,
++			     &(otg_dev->core_if->core_global_regs->ggpio),
++			     "GGPIO");
++DWC_OTG_DEVICE_ATTR_REG32_RW(guid, &(otg_dev->core_if->core_global_regs->guid),
++			     "GUID");
++DWC_OTG_DEVICE_ATTR_REG32_RO(gsnpsid,
++			     &(otg_dev->core_if->core_global_regs->gsnpsid),
++			     "GSNPSID");
++DWC_OTG_DEVICE_ATTR_BITFIELD_RW(devspeed, "Device Speed");
++DWC_OTG_DEVICE_ATTR_BITFIELD_RO(enumspeed, "Device Enumeration Speed");
++
++DWC_OTG_DEVICE_ATTR_REG32_RO(hptxfsiz,
++			     &(otg_dev->core_if->core_global_regs->hptxfsiz),
++			     "HPTXFSIZ");
++DWC_OTG_DEVICE_ATTR_REG32_RW(hprt0, otg_dev->core_if->host_if->hprt0, "HPRT0");
++
++/**
++ * @todo Add code to initiate the HNP.
++ */
++/**
++ * Show the HNP status bit
++ */
++static ssize_t hnp_show(struct device *_dev,
++			struct device_attribute *attr, char *buf)
++{
++
++	struct platform_device *lm_dev = container_of(_dev, struct platform_device, dev);
++	dwc_otg_device_t *otg_dev = platform_get_drvdata(lm_dev);
++
++	return sprintf(buf, "HstNegScs = 0x%x\n",
++		       dwc_otg_get_hnpstatus(otg_dev->core_if));
++}
++
++/**
++ * Set the HNP Request bit
++ */
++static ssize_t hnp_store(struct device *_dev,
++			 struct device_attribute *attr,
++			 const char *buf, size_t count)
++{
++
++	struct platform_device *lm_dev = container_of(_dev, struct platform_device, dev);
++	dwc_otg_device_t *otg_dev = platform_get_drvdata(lm_dev);
++
++	uint32_t in = simple_strtoul(buf, NULL, 16);
++	dwc_otg_set_hnpreq(otg_dev->core_if, in);
++	return count;
++}
++
++DEVICE_ATTR(hnp, 0644, hnp_show, hnp_store);
++
++/**
++ * @todo Add code to initiate the SRP.
++ */
++/**
++ * Show the SRP status bit
++ */
++static ssize_t srp_show(struct device *_dev,
++			struct device_attribute *attr, char *buf)
++{
++#ifndef DWC_HOST_ONLY
++
++	struct platform_device *lm_dev = container_of(_dev, struct platform_device, dev);
++	dwc_otg_device_t *otg_dev = platform_get_drvdata(lm_dev);
++
++	return sprintf(buf, "SesReqScs = 0x%x\n",
++		       dwc_otg_get_srpstatus(otg_dev->core_if));
++#else
++	return sprintf(buf, "Host Only Mode!\n");
++#endif
++}
++
++/**
++ * Set the SRP Request bit
++ */
++static ssize_t srp_store(struct device *_dev,
++			 struct device_attribute *attr,
++			 const char *buf, size_t count)
++{
++#ifndef DWC_HOST_ONLY
++	struct platform_device *lm_dev = container_of(_dev, struct platform_device, dev);
++	dwc_otg_device_t *otg_dev = platform_get_drvdata(lm_dev);
++	dwc_otg_pcd_initiate_srp(otg_dev->pcd);
++#endif
++	return count;
++}
++
++DEVICE_ATTR(srp, 0644, srp_show, srp_store);
++
++/**
++ * @todo Need to do more for power on/off?
++ */
++/**
++ * Show the Bus Power status
++ */
++static ssize_t buspower_show(struct device *_dev,
++			     struct device_attribute *attr, char *buf)
++{
++
++	struct platform_device *lm_dev = container_of(_dev, struct platform_device, dev);
++	dwc_otg_device_t *otg_dev = platform_get_drvdata(lm_dev);
++
++	return sprintf(buf, "Bus Power = 0x%x\n",
++		       dwc_otg_get_prtpower(otg_dev->core_if));
++}
++
++/**
++ * Set the Bus Power status
++ */
++static ssize_t buspower_store(struct device *_dev,
++			      struct device_attribute *attr,
++			      const char *buf, size_t count)
++{
++
++	struct platform_device *lm_dev = container_of(_dev, struct platform_device, dev);
++	dwc_otg_device_t *otg_dev = platform_get_drvdata(lm_dev);
++
++	uint32_t on = simple_strtoul(buf, NULL, 16);
++	dwc_otg_set_prtpower(otg_dev->core_if, on);
++	return count;
++}
++
++DEVICE_ATTR(buspower, 0644, buspower_show, buspower_store);
++
++/**
++ * @todo Need to do more for suspend?
++ */
++/**
++ * Show the Bus Suspend status
++ */
++static ssize_t bussuspend_show(struct device *_dev,
++			       struct device_attribute *attr, char *buf)
++{
++
++	struct platform_device *lm_dev = container_of(_dev, struct platform_device, dev);
++	dwc_otg_device_t *otg_dev = platform_get_drvdata(lm_dev);
++
++	return sprintf(buf, "Bus Suspend = 0x%x\n",
++		       dwc_otg_get_prtsuspend(otg_dev->core_if));
++}
++
++/**
++ * Set the Bus Suspend status
++ */
++static ssize_t bussuspend_store(struct device *_dev,
++				struct device_attribute *attr,
++				const char *buf, size_t count)
++{
++
++	struct platform_device *lm_dev = container_of(_dev, struct platform_device, dev);
++	dwc_otg_device_t *otg_dev = platform_get_drvdata(lm_dev);
++
++
++	uint32_t in = simple_strtoul(buf, NULL, 16);
++	dwc_otg_set_prtsuspend(otg_dev->core_if, in);
++	return count;
++}
++
++DEVICE_ATTR(bussuspend, 0644, bussuspend_show, bussuspend_store);
++
++/**
++ * Show the Mode Change Ready Timer status
++ */
++static ssize_t mode_ch_tim_en_show(struct device *_dev,
++				   struct device_attribute *attr, char *buf)
++{
++	struct platform_device *lm_dev = container_of(_dev, struct platform_device, dev);
++	dwc_otg_device_t *otg_dev = platform_get_drvdata(lm_dev);
++	return sprintf(buf, "Mode Change Ready Timer Enable = 0x%x\n",
++		       dwc_otg_get_mode_ch_tim(otg_dev->core_if));
++}
++
++/**
++ * Set the Mode Change Ready Timer status
++ */
++static ssize_t mode_ch_tim_en_store(struct device *_dev,
++				    struct device_attribute *attr,
++				    const char *buf, size_t count)
++{
++
++	struct platform_device *lm_dev = container_of(_dev, struct platform_device, dev);
++	dwc_otg_device_t *otg_dev = platform_get_drvdata(lm_dev);
++	uint32_t in = simple_strtoul(buf, NULL, 16);
++	dwc_otg_set_mode_ch_tim(otg_dev->core_if, in);
++	return count;
++}
++
++DEVICE_ATTR(mode_ch_tim_en, 0644, mode_ch_tim_en_show, mode_ch_tim_en_store);
++
++/**
++ * Show the value of HFIR Frame Interval bitfield
++ */
++static ssize_t fr_interval_show(struct device *_dev,
++				struct device_attribute *attr, char *buf)
++{
++
++	struct platform_device *lm_dev = container_of(_dev, struct platform_device, dev);
++	dwc_otg_device_t *otg_dev = platform_get_drvdata(lm_dev);
++	return sprintf(buf, "Frame Interval = 0x%x\n",
++		       dwc_otg_get_fr_interval(otg_dev->core_if));
++}
++
++/**
++ * Set the HFIR Frame Interval value
++ */
++static ssize_t fr_interval_store(struct device *_dev,
++				 struct device_attribute *attr,
++				 const char *buf, size_t count)
++{
++
++	struct platform_device *lm_dev = container_of(_dev, struct platform_device, dev);
++	dwc_otg_device_t *otg_dev = platform_get_drvdata(lm_dev);
++
++
++	uint32_t in = simple_strtoul(buf, NULL, 10);
++	dwc_otg_set_fr_interval(otg_dev->core_if, in);
++	return count;
++}
++
++DEVICE_ATTR(fr_interval, 0644, fr_interval_show, fr_interval_store);
++
++/**
++ * Show the status of Remote Wakeup.
++ */
++static ssize_t remote_wakeup_show(struct device *_dev,
++				  struct device_attribute *attr, char *buf)
++{
++#ifndef DWC_HOST_ONLY
++	struct platform_device *lm_dev = container_of(_dev, struct platform_device, dev);
++	dwc_otg_device_t *otg_dev =platform_get_drvdata(lm_dev);
++
++
++	return sprintf(buf,
++		       "Remote Wakeup Sig = %d Enabled = %d LPM Remote Wakeup = %d\n",
++		       dwc_otg_get_remotewakesig(otg_dev->core_if),
++		       dwc_otg_pcd_get_rmwkup_enable(otg_dev->pcd),
++		       dwc_otg_get_lpm_remotewakeenabled(otg_dev->core_if));
++#else
++	return sprintf(buf, "Host Only Mode!\n");
++#endif /* DWC_HOST_ONLY */
++}
++
++/**
++ * Initiate a remote wakeup of the host.  The Device control register
++ * Remote Wakeup Signal bit is written if the PCD Remote wakeup enable
++ * flag is set.
++ *
++ */
++static ssize_t remote_wakeup_store(struct device *_dev,
++				   struct device_attribute *attr,
++				   const char *buf, size_t count)
++{
++#ifndef DWC_HOST_ONLY
++
++	struct platform_device *lm_dev = container_of(_dev, struct platform_device, dev);
++	dwc_otg_device_t *otg_dev = platform_get_drvdata(lm_dev);
++
++
++	uint32_t val = simple_strtoul(buf, NULL, 16);
++
++	if (val & 1) {
++		dwc_otg_pcd_remote_wakeup(otg_dev->pcd, 1);
++	} else {
++		dwc_otg_pcd_remote_wakeup(otg_dev->pcd, 0);
++	}
++#endif /* DWC_HOST_ONLY */
++	return count;
++}
++
++DEVICE_ATTR(remote_wakeup, S_IRUGO | S_IWUSR, remote_wakeup_show,
++	    remote_wakeup_store);
++
++/**
++ * Show the whether core is hibernated or not.
++ */
++static ssize_t rem_wakeup_pwrdn_show(struct device *_dev,
++				     struct device_attribute *attr, char *buf)
++{
++#ifndef DWC_HOST_ONLY
++
++	struct platform_device *lm_dev = container_of(_dev, struct platform_device, dev);
++	dwc_otg_device_t *otg_dev = platform_get_drvdata(lm_dev);
++
++	if (dwc_otg_get_core_state(otg_dev->core_if)) {
++		DWC_PRINTF("Core is in hibernation\n");
++	} else {
++		DWC_PRINTF("Core is not in hibernation\n");
++	}
++#endif /* DWC_HOST_ONLY */
++	return 0;
++}
++
++extern int dwc_otg_device_hibernation_restore(dwc_otg_core_if_t * core_if,
++					      int rem_wakeup, int reset);
++
++/**
++ * Initiate a remote wakeup of the device to exit from hibernation.
++ */
++static ssize_t rem_wakeup_pwrdn_store(struct device *_dev,
++				      struct device_attribute *attr,
++				      const char *buf, size_t count)
++{
++#ifndef DWC_HOST_ONLY
++
++	struct platform_device *lm_dev = container_of(_dev, struct platform_device, dev);
++	dwc_otg_device_t *otg_dev = platform_get_drvdata(lm_dev);
++
++	dwc_otg_device_hibernation_restore(otg_dev->core_if, 1, 0);
++#endif
++	return count;
++}
++
++DEVICE_ATTR(rem_wakeup_pwrdn, S_IRUGO | S_IWUSR, rem_wakeup_pwrdn_show,
++	    rem_wakeup_pwrdn_store);
++
++static ssize_t disconnect_us(struct device *_dev,
++			     struct device_attribute *attr,
++			     const char *buf, size_t count)
++{
++
++#ifndef DWC_HOST_ONLY
++
++	struct platform_device *lm_dev = container_of(_dev, struct platform_device, dev);
++	dwc_otg_device_t *otg_dev = platform_get_drvdata(lm_dev);
++
++	uint32_t val = simple_strtoul(buf, NULL, 16);
++	DWC_PRINTF("The Passed value is %04x\n", val);
++
++	dwc_otg_pcd_disconnect_us(otg_dev->pcd, 50);
++
++#endif /* DWC_HOST_ONLY */
++	return count;
++}
++
++DEVICE_ATTR(disconnect_us, S_IWUSR, 0, disconnect_us);
++
++/**
++ * Dump global registers and either host or device registers (depending on the
++ * current mode of the core).
++ */
++static ssize_t regdump_show(struct device *_dev,
++			    struct device_attribute *attr, char *buf)
++{
++
++	struct platform_device *lm_dev = container_of(_dev, struct platform_device, dev);
++	dwc_otg_device_t *otg_dev = platform_get_drvdata(lm_dev);
++
++
++	dwc_otg_dump_global_registers(otg_dev->core_if);
++	if (dwc_otg_is_host_mode(otg_dev->core_if)) {
++		dwc_otg_dump_host_registers(otg_dev->core_if);
++	} else {
++		dwc_otg_dump_dev_registers(otg_dev->core_if);
++
++	}
++	return sprintf(buf, "Register Dump\n");
++}
++
++DEVICE_ATTR(regdump, S_IRUGO | S_IWUSR, regdump_show, 0);
++
++/**
++ * Dump global registers and either host or device registers (depending on the
++ * current mode of the core).
++ */
++static ssize_t spramdump_show(struct device *_dev,
++			      struct device_attribute *attr, char *buf)
++{
++
++	struct platform_device *lm_dev = container_of(_dev, struct platform_device, dev);
++	dwc_otg_device_t *otg_dev = platform_get_drvdata(lm_dev);
++
++
++	dwc_otg_dump_spram(otg_dev->core_if);
++
++	return sprintf(buf, "SPRAM Dump\n");
++}
++
++DEVICE_ATTR(spramdump, S_IRUGO | S_IWUSR, spramdump_show, 0);
++
++/**
++ * Dump the current hcd state.
++ */
++static ssize_t hcddump_show(struct device *_dev,
++			    struct device_attribute *attr, char *buf)
++{
++#ifndef DWC_DEVICE_ONLY
++
++	struct platform_device *lm_dev = container_of(_dev, struct platform_device, dev);
++	dwc_otg_device_t *otg_dev =platform_get_drvdata(lm_dev);
++
++
++	dwc_otg_hcd_dump_state(otg_dev->hcd);
++#endif /* DWC_DEVICE_ONLY */
++	return sprintf(buf, "HCD Dump\n");
++}
++
++DEVICE_ATTR(hcddump, S_IRUGO | S_IWUSR, hcddump_show, 0);
++
++/**
++ * Dump the average frame remaining at SOF. This can be used to
++ * determine average interrupt latency. Frame remaining is also shown for
++ * start transfer and two additional sample points.
++ */
++static ssize_t hcd_frrem_show(struct device *_dev,
++			      struct device_attribute *attr, char *buf)
++{
++#ifndef DWC_DEVICE_ONLY
++
++	struct platform_device *lm_dev = container_of(_dev, struct platform_device, dev);
++	dwc_otg_device_t *otg_dev = platform_get_drvdata(lm_dev);
++
++
++	dwc_otg_hcd_dump_frrem(otg_dev->hcd);
++#endif /* DWC_DEVICE_ONLY */
++	return sprintf(buf, "HCD Dump Frame Remaining\n");
++}
++
++DEVICE_ATTR(hcd_frrem, S_IRUGO | S_IWUSR, hcd_frrem_show, 0);
++
++/**
++ * Displays the time required to read the GNPTXFSIZ register many times (the
++ * output shows the number of times the register is read).
++ */
++#define RW_REG_COUNT 10000000
++#define MSEC_PER_JIFFIE 1000/HZ
++static ssize_t rd_reg_test_show(struct device *_dev,
++				struct device_attribute *attr, char *buf)
++{
++
++	struct platform_device *lm_dev = container_of(_dev, struct platform_device, dev);
++	dwc_otg_device_t *otg_dev = platform_get_drvdata(lm_dev);
++
++
++	int i;
++	int time;
++	int start_jiffies;
++
++	printk("HZ %d, MSEC_PER_JIFFIE %d, loops_per_jiffy %lu\n",
++	       HZ, MSEC_PER_JIFFIE, loops_per_jiffy);
++	start_jiffies = jiffies;
++	for (i = 0; i < RW_REG_COUNT; i++) {
++		dwc_otg_get_gnptxfsiz(otg_dev->core_if);
++	}
++	time = jiffies - start_jiffies;
++	return sprintf(buf,
++		       "Time to read GNPTXFSIZ reg %d times: %d msecs (%d jiffies)\n",
++		       RW_REG_COUNT, time * MSEC_PER_JIFFIE, time);
++}
++
++DEVICE_ATTR(rd_reg_test, S_IRUGO | S_IWUSR, rd_reg_test_show, 0);
++
++/**
++ * Displays the time required to write the GNPTXFSIZ register many times (the
++ * output shows the number of times the register is written).
++ */
++static ssize_t wr_reg_test_show(struct device *_dev,
++				struct device_attribute *attr, char *buf)
++{
++
++	struct platform_device *lm_dev = container_of(_dev, struct platform_device, dev);
++	dwc_otg_device_t *otg_dev = platform_get_drvdata(lm_dev);
++
++
++	uint32_t reg_val;
++	int i;
++	int time;
++	int start_jiffies;
++
++	printk("HZ %d, MSEC_PER_JIFFIE %d, loops_per_jiffy %lu\n",
++	       HZ, MSEC_PER_JIFFIE, loops_per_jiffy);
++	reg_val = dwc_otg_get_gnptxfsiz(otg_dev->core_if);
++	start_jiffies = jiffies;
++	for (i = 0; i < RW_REG_COUNT; i++) {
++		dwc_otg_set_gnptxfsiz(otg_dev->core_if, reg_val);
++	}
++	time = jiffies - start_jiffies;
++	return sprintf(buf,
++		       "Time to write GNPTXFSIZ reg %d times: %d msecs (%d jiffies)\n",
++		       RW_REG_COUNT, time * MSEC_PER_JIFFIE, time);
++}
++
++DEVICE_ATTR(wr_reg_test, S_IRUGO | S_IWUSR, wr_reg_test_show, 0);
++
++#ifdef CONFIG_USB_DWC_OTG_LPM
++
++/**
++* Show the lpm_response attribute.
++*/
++static ssize_t lpmresp_show(struct device *_dev,
++			    struct device_attribute *attr, char *buf)
++{
++
++	struct platform_device *lm_dev = container_of(_dev, struct platform_device, dev);
++	dwc_otg_device_t *otg_dev = platform_get_drvdata(lm_dev);
++
++
++	if (!dwc_otg_get_param_lpm_enable(otg_dev->core_if))
++		return sprintf(buf, "** LPM is DISABLED **\n");
++
++	if (!dwc_otg_is_device_mode(otg_dev->core_if)) {
++		return sprintf(buf, "** Current mode is not device mode\n");
++	}
++	return sprintf(buf, "lpm_response = %d\n",
++		       dwc_otg_get_lpmresponse(otg_dev->core_if));
++}
++
++/**
++* Store the lpm_response attribute.
++*/
++static ssize_t lpmresp_store(struct device *_dev,
++			     struct device_attribute *attr,
++			     const char *buf, size_t count)
++{
++
++	struct platform_device *lm_dev = container_of(_dev, struct platform_device, dev);
++	dwc_otg_device_t *otg_dev = platform_get_drvdata(lm_dev);
++
++
++	uint32_t val = simple_strtoul(buf, NULL, 16);
++
++	if (!dwc_otg_get_param_lpm_enable(otg_dev->core_if)) {
++		return 0;
++	}
++
++	if (!dwc_otg_is_device_mode(otg_dev->core_if)) {
++		return 0;
++	}
++
++	dwc_otg_set_lpmresponse(otg_dev->core_if, val);
++	return count;
++}
++
++DEVICE_ATTR(lpm_response, S_IRUGO | S_IWUSR, lpmresp_show, lpmresp_store);
++
++/**
++* Show the besl_reject attribute.
++*/
++static ssize_t beslreject_show(struct device *_dev,
++			    struct device_attribute *attr, char *buf)
++{
++
++	struct platform_device *lm_dev = container_of(_dev, struct platform_device, dev);
++	dwc_otg_device_t *otg_dev = platform_get_drvdata(lm_dev);
++
++
++	if (!dwc_otg_get_param_lpm_enable(otg_dev->core_if))
++		return sprintf(buf, "** LPM is DISABLED **\n");
++	if (!dwc_otg_get_param_besl_enable(otg_dev->core_if))
++		return sprintf(buf, "** EnBesl is DISABLED **\n");
++
++	if (!dwc_otg_is_device_mode(otg_dev->core_if)) {
++		return sprintf(buf, "** Current mode is not device mode\n");
++	}
++
++	return sprintf(buf, "besl_reject = %d\n",
++		        dwc_otg_get_beslreject(otg_dev->core_if));
++}
++
++/**
++* Store the besl_reject attribute.
++*/
++static ssize_t beslreject_store(struct device *_dev,
++			     struct device_attribute *attr,
++			     const char *buf, size_t count)
++{
++
++	struct platform_device *lm_dev = container_of(_dev, struct platform_device, dev);
++	dwc_otg_device_t *otg_dev = platform_get_drvdata(lm_dev);
++
++
++	uint32_t val = simple_strtoul(buf, NULL, 16);
++
++	if (!dwc_otg_get_param_lpm_enable(otg_dev->core_if)) {
++		return 0;
++	}
++
++	if (!dwc_otg_get_param_besl_enable(otg_dev->core_if)) {
++		return 0;
++	}
++
++	if (!dwc_otg_is_device_mode(otg_dev->core_if)) {
++		return 0;
++	}
++
++	 dwc_otg_set_beslreject(otg_dev->core_if,val);
++
++	return count;
++}
++
++DEVICE_ATTR(besl_reject, S_IRUGO | S_IWUSR, beslreject_show, beslreject_store);
++
++/**
++* Show the hird_thresh attribute.
++*/
++static ssize_t hirdthresh_show(struct device *_dev,
++			    struct device_attribute *attr, char *buf)
++{
++
++	struct platform_device *lm_dev = container_of(_dev, struct platform_device, dev);
++	dwc_otg_device_t *otg_dev = platform_get_drvdata(lm_dev);
++
++
++	if (!dwc_otg_get_param_lpm_enable(otg_dev->core_if))
++		return sprintf(buf, "** LPM is DISABLED **\n");
++
++	if (!dwc_otg_is_device_mode(otg_dev->core_if)) {
++		return sprintf(buf, "** Current mode is not device mode\n");
++	}
++
++	return sprintf(buf, "hirdthresh = 0x%x\n",
++		        dwc_otg_get_hirdthresh(otg_dev->core_if));
++}
++
++/**
++* Store the hird_thresh attribute.
++*/
++static ssize_t hirdthresh_store(struct device *_dev,
++			     struct device_attribute *attr,
++			     const char *buf, size_t count)
++{
++
++	struct platform_device *lm_dev = container_of(_dev, struct platform_device, dev);
++	dwc_otg_device_t *otg_dev = platform_get_drvdata(lm_dev);
++
++
++	uint32_t val = simple_strtoul(buf, NULL, 16);
++
++	if (!dwc_otg_get_param_lpm_enable(otg_dev->core_if)) {
++		return 0;
++	}
++
++	if (!dwc_otg_is_device_mode(otg_dev->core_if)) {
++		return 0;
++	}
++
++	 dwc_otg_set_hirdthresh(otg_dev->core_if,val);
++
++	return count;
++}
++
++DEVICE_ATTR(hird_thres, S_IRUGO | S_IWUSR, hirdthresh_show, hirdthresh_store);
++
++/**
++* Show the sleep_status attribute.
++*/
++static ssize_t sleepstatus_show(struct device *_dev,
++				struct device_attribute *attr, char *buf)
++{
++
++	struct platform_device *lm_dev = container_of(_dev, struct platform_device, dev);
++	dwc_otg_device_t *otg_dev = platform_get_drvdata(lm_dev);
++
++
++	return sprintf(buf, "Sleep Status = %d\n",
++		       dwc_otg_get_lpm_portsleepstatus(otg_dev->core_if));
++}
++
++/**
++ * Store the sleep_status attribure.
++ */
++static ssize_t sleepstatus_store(struct device *_dev,
++				 struct device_attribute *attr,
++				 const char *buf, size_t count)
++{
++	struct platform_device *lm_dev = container_of(_dev, struct platform_device, dev);
++	dwc_otg_device_t *otg_dev = platform_get_drvdata(lm_dev);
++
++
++	dwc_otg_core_if_t *core_if = otg_dev->core_if;
++
++	if (dwc_otg_get_lpm_portsleepstatus(otg_dev->core_if)) {
++		if (dwc_otg_is_host_mode(core_if)) {
++
++			DWC_PRINTF("Host initiated resume\n");
++			dwc_otg_set_prtresume(otg_dev->core_if, 1);
++		}
++	}
++
++	return count;
++}
++
++DEVICE_ATTR(sleep_status, S_IRUGO | S_IWUSR, sleepstatus_show,
++	    sleepstatus_store);
++
++#endif /* CONFIG_USB_DWC_OTG_LPM_ENABLE */
++
++/**@}*/
++
++/**
++ * Create the device files
++ */
++void dwc_otg_attr_create(struct platform_device *dev)
++{
++	int error;
++
++	error = device_create_file(&dev->dev, &dev_attr_regoffset);
++	error = device_create_file(&dev->dev, &dev_attr_regvalue);
++	error = device_create_file(&dev->dev, &dev_attr_mode);
++	error = device_create_file(&dev->dev, &dev_attr_hnpcapable);
++	error = device_create_file(&dev->dev, &dev_attr_srpcapable);
++	error = device_create_file(&dev->dev, &dev_attr_hsic_connect);
++	error = device_create_file(&dev->dev, &dev_attr_inv_sel_hsic);
++	error = device_create_file(&dev->dev, &dev_attr_hnp);
++	error = device_create_file(&dev->dev, &dev_attr_srp);
++	error = device_create_file(&dev->dev, &dev_attr_buspower);
++	error = device_create_file(&dev->dev, &dev_attr_bussuspend);
++	error = device_create_file(&dev->dev, &dev_attr_mode_ch_tim_en);
++	error = device_create_file(&dev->dev, &dev_attr_fr_interval);
++	error = device_create_file(&dev->dev, &dev_attr_busconnected);
++	error = device_create_file(&dev->dev, &dev_attr_gotgctl);
++	error = device_create_file(&dev->dev, &dev_attr_gusbcfg);
++	error = device_create_file(&dev->dev, &dev_attr_grxfsiz);
++	error = device_create_file(&dev->dev, &dev_attr_gnptxfsiz);
++	error = device_create_file(&dev->dev, &dev_attr_gpvndctl);
++	error = device_create_file(&dev->dev, &dev_attr_ggpio);
++	error = device_create_file(&dev->dev, &dev_attr_guid);
++	error = device_create_file(&dev->dev, &dev_attr_gsnpsid);
++	error = device_create_file(&dev->dev, &dev_attr_devspeed);
++	error = device_create_file(&dev->dev, &dev_attr_enumspeed);
++	error = device_create_file(&dev->dev, &dev_attr_hptxfsiz);
++	error = device_create_file(&dev->dev, &dev_attr_hprt0);
++	error = device_create_file(&dev->dev, &dev_attr_remote_wakeup);
++	error = device_create_file(&dev->dev, &dev_attr_rem_wakeup_pwrdn);
++	error = device_create_file(&dev->dev, &dev_attr_disconnect_us);
++	error = device_create_file(&dev->dev, &dev_attr_regdump);
++	error = device_create_file(&dev->dev, &dev_attr_spramdump);
++	error = device_create_file(&dev->dev, &dev_attr_hcddump);
++	error = device_create_file(&dev->dev, &dev_attr_hcd_frrem);
++	error = device_create_file(&dev->dev, &dev_attr_rd_reg_test);
++	error = device_create_file(&dev->dev, &dev_attr_wr_reg_test);
++#ifdef CONFIG_USB_DWC_OTG_LPM
++	error = device_create_file(&dev->dev, &dev_attr_lpm_response);
++	error = device_create_file(&dev->dev, &dev_attr_sleep_status);
++	error = device_create_file(&dev->dev, &dev_attr_besl_reject);
++	error = device_create_file(&dev->dev, &dev_attr_hird_thres);
++#endif
++}
++
++/**
++ * Remove the device files
++ */
++void dwc_otg_attr_remove(struct platform_device *dev
++
++    )
++{
++	device_remove_file(&dev->dev, &dev_attr_regoffset);
++	device_remove_file(&dev->dev, &dev_attr_regvalue);
++	device_remove_file(&dev->dev, &dev_attr_mode);
++	device_remove_file(&dev->dev, &dev_attr_hnpcapable);
++	device_remove_file(&dev->dev, &dev_attr_srpcapable);
++	device_remove_file(&dev->dev, &dev_attr_hsic_connect);
++	device_remove_file(&dev->dev, &dev_attr_inv_sel_hsic);
++	device_remove_file(&dev->dev, &dev_attr_hnp);
++	device_remove_file(&dev->dev, &dev_attr_srp);
++	device_remove_file(&dev->dev, &dev_attr_buspower);
++	device_remove_file(&dev->dev, &dev_attr_bussuspend);
++	device_remove_file(&dev->dev, &dev_attr_mode_ch_tim_en);
++	device_remove_file(&dev->dev, &dev_attr_fr_interval);
++	device_remove_file(&dev->dev, &dev_attr_busconnected);
++	device_remove_file(&dev->dev, &dev_attr_gotgctl);
++	device_remove_file(&dev->dev, &dev_attr_gusbcfg);
++	device_remove_file(&dev->dev, &dev_attr_grxfsiz);
++	device_remove_file(&dev->dev, &dev_attr_gnptxfsiz);
++	device_remove_file(&dev->dev, &dev_attr_gpvndctl);
++	device_remove_file(&dev->dev, &dev_attr_ggpio);
++	device_remove_file(&dev->dev, &dev_attr_guid);
++	device_remove_file(&dev->dev, &dev_attr_gsnpsid);
++	device_remove_file(&dev->dev, &dev_attr_devspeed);
++	device_remove_file(&dev->dev, &dev_attr_enumspeed);
++	device_remove_file(&dev->dev, &dev_attr_hptxfsiz);
++	device_remove_file(&dev->dev, &dev_attr_hprt0);
++	device_remove_file(&dev->dev, &dev_attr_remote_wakeup);
++	device_remove_file(&dev->dev, &dev_attr_rem_wakeup_pwrdn);
++	device_remove_file(&dev->dev, &dev_attr_disconnect_us);
++	device_remove_file(&dev->dev, &dev_attr_regdump);
++	device_remove_file(&dev->dev, &dev_attr_spramdump);
++	device_remove_file(&dev->dev, &dev_attr_hcddump);
++	device_remove_file(&dev->dev, &dev_attr_hcd_frrem);
++	device_remove_file(&dev->dev, &dev_attr_rd_reg_test);
++	device_remove_file(&dev->dev, &dev_attr_wr_reg_test);
++#ifdef CONFIG_USB_DWC_OTG_LPM
++	device_remove_file(&dev->dev, &dev_attr_lpm_response);
++	device_remove_file(&dev->dev, &dev_attr_sleep_status);
++	device_remove_file(&dev->dev, &dev_attr_besl_reject);
++	device_remove_file(&dev->dev, &dev_attr_hird_thres);
++#endif
++}
+diff --git a/drivers/usb/gadget/udc/hiudc/dwc_otg_attr.h b/drivers/usb/gadget/udc/hiudc/dwc_otg_attr.h
+new file mode 100644
+index 0000000..4d43296
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc/dwc_otg_attr.h
+@@ -0,0 +1,78 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_attr.h $
++ * $Revision: #13 $
++ * $Date: 2010/06/21 $
++ * $Change: 1532021 $
++ *
++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
++ * ========================================================================== */
++
++#if !defined(__DWC_OTG_ATTR_H__)
++#define __DWC_OTG_ATTR_H__
++
++#include <linux/platform_device.h>
++
++/** @file
++ * This file contains the interface to the Linux device attributes.
++ */
++extern struct device_attribute dev_attr_regoffset;
++extern struct device_attribute dev_attr_regvalue;
++
++extern struct device_attribute dev_attr_mode;
++extern struct device_attribute dev_attr_hnpcapable;
++extern struct device_attribute dev_attr_srpcapable;
++extern struct device_attribute dev_attr_hnp;
++extern struct device_attribute dev_attr_srp;
++extern struct device_attribute dev_attr_buspower;
++extern struct device_attribute dev_attr_bussuspend;
++extern struct device_attribute dev_attr_mode_ch_tim_en;
++extern struct device_attribute dev_attr_fr_interval;
++extern struct device_attribute dev_attr_busconnected;
++extern struct device_attribute dev_attr_gotgctl;
++extern struct device_attribute dev_attr_gusbcfg;
++extern struct device_attribute dev_attr_grxfsiz;
++extern struct device_attribute dev_attr_gnptxfsiz;
++extern struct device_attribute dev_attr_gpvndctl;
++extern struct device_attribute dev_attr_ggpio;
++extern struct device_attribute dev_attr_guid;
++extern struct device_attribute dev_attr_gsnpsid;
++extern struct device_attribute dev_attr_devspeed;
++extern struct device_attribute dev_attr_enumspeed;
++extern struct device_attribute dev_attr_hptxfsiz;
++extern struct device_attribute dev_attr_hprt0;
++#ifdef CONFIG_USB_DWC_OTG_LPM
++extern struct device_attribute dev_attr_lpm_response;
++extern struct device_attribute devi_attr_sleep_status;
++#endif
++
++void dwc_otg_attr_create(struct platform_device *dev
++    );
++
++void dwc_otg_attr_remove(struct platform_device *dev
++
++    );
++#endif
+diff --git a/drivers/usb/gadget/udc/hiudc/dwc_otg_cfi.c b/drivers/usb/gadget/udc/hiudc/dwc_otg_cfi.c
+new file mode 100644
+index 0000000..bbb3d32
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc/dwc_otg_cfi.c
+@@ -0,0 +1,1876 @@
++/* ==========================================================================
++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
++ * ========================================================================== */
++
++/** @file
++ *
++ * This file contains the most of the CFI(Core Feature Interface)
++ * implementation for the OTG.
++ */
++
++#ifdef DWC_UTE_CFI
++
++#include "dwc_otg_pcd.h"
++#include "dwc_otg_cfi.h"
++
++/** This definition should actually migrate to the Portability Library */
++#define DWC_CONSTANT_CPU_TO_LE16(x) (x)
++
++extern dwc_otg_pcd_ep_t *get_ep_by_addr(dwc_otg_pcd_t * pcd, u16 wIndex);
++
++static int cfi_core_features_buf(uint8_t * buf, uint16_t buflen);
++static int cfi_get_feature_value(uint8_t * buf, uint16_t buflen,
++				 struct dwc_otg_pcd *pcd,
++				 struct cfi_usb_ctrlrequest *ctrl_req);
++static int cfi_set_feature_value(struct dwc_otg_pcd *pcd);
++static int cfi_ep_get_sg_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
++			     struct cfi_usb_ctrlrequest *req);
++static int cfi_ep_get_concat_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
++				 struct cfi_usb_ctrlrequest *req);
++static int cfi_ep_get_align_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
++				struct cfi_usb_ctrlrequest *req);
++static int cfi_preproc_reset(struct dwc_otg_pcd *pcd,
++			     struct cfi_usb_ctrlrequest *req);
++static void cfi_free_ep_bs_dyn_data(cfi_ep_t * cfiep);
++
++static uint16_t get_dfifo_size(dwc_otg_core_if_t * core_if);
++static int32_t get_rxfifo_size(dwc_otg_core_if_t * core_if, uint16_t wValue);
++static int32_t get_txfifo_size(struct dwc_otg_pcd *pcd, uint16_t wValue);
++
++static uint8_t resize_fifos(dwc_otg_core_if_t * core_if);
++
++/** This is the header of the all features descriptor */
++static cfi_all_features_header_t all_props_desc_header = {
++	.wVersion = DWC_CONSTANT_CPU_TO_LE16(0x100),
++	.wCoreID = DWC_CONSTANT_CPU_TO_LE16(CFI_CORE_ID_OTG),
++	.wNumFeatures = DWC_CONSTANT_CPU_TO_LE16(9),
++};
++
++/** This is an array of statically allocated feature descriptors */
++static cfi_feature_desc_header_t prop_descs[] = {
++
++	/* FT_ID_DMA_MODE */
++	{
++	 .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_MODE),
++	 .bmAttributes = CFI_FEATURE_ATTR_RW,
++	 .wDataLength = DWC_CONSTANT_CPU_TO_LE16(1),
++	 },
++
++	/* FT_ID_DMA_BUFFER_SETUP */
++	{
++	 .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_BUFFER_SETUP),
++	 .bmAttributes = CFI_FEATURE_ATTR_RW,
++	 .wDataLength = DWC_CONSTANT_CPU_TO_LE16(6),
++	 },
++
++	/* FT_ID_DMA_BUFF_ALIGN */
++	{
++	 .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_BUFF_ALIGN),
++	 .bmAttributes = CFI_FEATURE_ATTR_RW,
++	 .wDataLength = DWC_CONSTANT_CPU_TO_LE16(2),
++	 },
++
++	/* FT_ID_DMA_CONCAT_SETUP */
++	{
++	 .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_CONCAT_SETUP),
++	 .bmAttributes = CFI_FEATURE_ATTR_RW,
++	 //.wDataLength  = DWC_CONSTANT_CPU_TO_LE16(6),
++	 },
++
++	/* FT_ID_DMA_CIRCULAR */
++	{
++	 .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_CIRCULAR),
++	 .bmAttributes = CFI_FEATURE_ATTR_RW,
++	 .wDataLength = DWC_CONSTANT_CPU_TO_LE16(6),
++	 },
++
++	/* FT_ID_THRESHOLD_SETUP */
++	{
++	 .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_THRESHOLD_SETUP),
++	 .bmAttributes = CFI_FEATURE_ATTR_RW,
++	 .wDataLength = DWC_CONSTANT_CPU_TO_LE16(6),
++	 },
++
++	/* FT_ID_DFIFO_DEPTH */
++	{
++	 .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DFIFO_DEPTH),
++	 .bmAttributes = CFI_FEATURE_ATTR_RO,
++	 .wDataLength = DWC_CONSTANT_CPU_TO_LE16(2),
++	 },
++
++	/* FT_ID_TX_FIFO_DEPTH */
++	{
++	 .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_TX_FIFO_DEPTH),
++	 .bmAttributes = CFI_FEATURE_ATTR_RW,
++	 .wDataLength = DWC_CONSTANT_CPU_TO_LE16(2),
++	 },
++
++	/* FT_ID_RX_FIFO_DEPTH */
++	{
++	 .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_RX_FIFO_DEPTH),
++	 .bmAttributes = CFI_FEATURE_ATTR_RW,
++	 .wDataLength = DWC_CONSTANT_CPU_TO_LE16(2),
++	 }
++};
++
++/** The table of feature names */
++cfi_string_t prop_name_table[] = {
++	{FT_ID_DMA_MODE, "dma_mode"},
++	{FT_ID_DMA_BUFFER_SETUP, "buffer_setup"},
++	{FT_ID_DMA_BUFF_ALIGN, "buffer_align"},
++	{FT_ID_DMA_CONCAT_SETUP, "concat_setup"},
++	{FT_ID_DMA_CIRCULAR, "buffer_circular"},
++	{FT_ID_THRESHOLD_SETUP, "threshold_setup"},
++	{FT_ID_DFIFO_DEPTH, "dfifo_depth"},
++	{FT_ID_TX_FIFO_DEPTH, "txfifo_depth"},
++	{FT_ID_RX_FIFO_DEPTH, "rxfifo_depth"},
++	{}
++};
++
++/************************************************************************/
++
++/**
++ * Returns the name of the feature by its ID
++ * or NULL if no featute ID matches.
++ *
++ */
++const uint8_t *get_prop_name(uint16_t prop_id, int *len)
++{
++	cfi_string_t *pstr;
++	*len = 0;
++
++	for (pstr = prop_name_table; pstr && pstr->s; pstr++) {
++		if (pstr->id == prop_id) {
++			*len = DWC_STRLEN(pstr->s);
++			return pstr->s;
++		}
++	}
++	return NULL;
++}
++
++/**
++ * This function handles all CFI specific control requests.
++ *
++ * Return a negative value to stall the DCE.
++ */
++int cfi_setup(struct dwc_otg_pcd *pcd, struct cfi_usb_ctrlrequest *ctrl)
++{
++	int retval = 0;
++	dwc_otg_pcd_ep_t *ep = NULL;
++	cfiobject_t *cfi = pcd->cfi;
++	struct dwc_otg_core_if *coreif = GET_CORE_IF(pcd);
++	uint16_t wLen = DWC_LE16_TO_CPU(&ctrl->wLength);
++	uint16_t wValue = DWC_LE16_TO_CPU(&ctrl->wValue);
++	uint16_t wIndex = DWC_LE16_TO_CPU(&ctrl->wIndex);
++	uint32_t regaddr = 0;
++	uint32_t regval = 0;
++
++	/* Save this Control Request in the CFI object.
++	 * The data field will be assigned in the data stage completion CB function.
++	 */
++	cfi->ctrl_req = *ctrl;
++	cfi->ctrl_req.data = NULL;
++
++	cfi->need_gadget_att = 0;
++	cfi->need_status_in_complete = 0;
++
++	switch (ctrl->bRequest) {
++	case VEN_CORE_GET_FEATURES:
++		retval = cfi_core_features_buf(cfi->buf_in.buf, CFI_IN_BUF_LEN);
++		if (retval >= 0) {
++			//dump_msg(cfi->buf_in.buf, retval);
++			ep = &pcd->ep0;
++
++			retval = min((uint16_t) retval, wLen);
++			/* Transfer this buffer to the host through the EP0-IN EP */
++			ep->dwc_ep.dma_addr = cfi->buf_in.addr;
++			ep->dwc_ep.start_xfer_buff = cfi->buf_in.buf;
++			ep->dwc_ep.xfer_buff = cfi->buf_in.buf;
++			ep->dwc_ep.xfer_len = retval;
++			ep->dwc_ep.xfer_count = 0;
++			ep->dwc_ep.sent_zlp = 0;
++			ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
++
++			pcd->ep0_pending = 1;
++			dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep);
++		}
++		retval = 0;
++		break;
++
++	case VEN_CORE_GET_FEATURE:
++		CFI_INFO("VEN_CORE_GET_FEATURE\n");
++		retval = cfi_get_feature_value(cfi->buf_in.buf, CFI_IN_BUF_LEN,
++					       pcd, ctrl);
++		if (retval >= 0) {
++			ep = &pcd->ep0;
++
++			retval = min((uint16_t) retval, wLen);
++			/* Transfer this buffer to the host through the EP0-IN EP */
++			ep->dwc_ep.dma_addr = cfi->buf_in.addr;
++			ep->dwc_ep.start_xfer_buff = cfi->buf_in.buf;
++			ep->dwc_ep.xfer_buff = cfi->buf_in.buf;
++			ep->dwc_ep.xfer_len = retval;
++			ep->dwc_ep.xfer_count = 0;
++			ep->dwc_ep.sent_zlp = 0;
++			ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
++
++			pcd->ep0_pending = 1;
++			dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep);
++		}
++		CFI_INFO("VEN_CORE_GET_FEATURE=%d\n", retval);
++		dump_msg(cfi->buf_in.buf, retval);
++		break;
++
++	case VEN_CORE_SET_FEATURE:
++		CFI_INFO("VEN_CORE_SET_FEATURE\n");
++		/* Set up an XFER to get the data stage of the control request,
++		 * which is the new value of the feature to be modified.
++		 */
++		ep = &pcd->ep0;
++		ep->dwc_ep.is_in = 0;
++		ep->dwc_ep.dma_addr = cfi->buf_out.addr;
++		ep->dwc_ep.start_xfer_buff = cfi->buf_out.buf;
++		ep->dwc_ep.xfer_buff = cfi->buf_out.buf;
++		ep->dwc_ep.xfer_len = wLen;
++		ep->dwc_ep.xfer_count = 0;
++		ep->dwc_ep.sent_zlp = 0;
++		ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
++
++		pcd->ep0_pending = 1;
++		/* Read the control write's data stage */
++		dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep);
++		retval = 0;
++		break;
++
++	case VEN_CORE_RESET_FEATURES:
++		CFI_INFO("VEN_CORE_RESET_FEATURES\n");
++		cfi->need_gadget_att = 1;
++		cfi->need_status_in_complete = 1;
++		retval = cfi_preproc_reset(pcd, ctrl);
++		CFI_INFO("VEN_CORE_RESET_FEATURES = (%d)\n", retval);
++		break;
++
++	case VEN_CORE_ACTIVATE_FEATURES:
++		CFI_INFO("VEN_CORE_ACTIVATE_FEATURES\n");
++		break;
++
++	case VEN_CORE_READ_REGISTER:
++		CFI_INFO("VEN_CORE_READ_REGISTER\n");
++		/* wValue optionally contains the HI WORD of the register offset and
++		 * wIndex contains the LOW WORD of the register offset
++		 */
++		if (wValue == 0) {
++			/* @TODO - MAS - fix the access to the base field */
++			regaddr = 0;
++			//regaddr = (uint32_t) pcd->otg_dev->os_dep.base;
++			//GET_CORE_IF(pcd)->co
++			regaddr |= wIndex;
++		} else {
++			regaddr = (wValue << 16) | wIndex;
++		}
++
++		/* Read a 32-bit value of the memory at the regaddr */
++		regval = DWC_READ_REG32((uint32_t *) regaddr);
++
++		ep = &pcd->ep0;
++		dwc_memcpy(cfi->buf_in.buf, &regval, sizeof(uint32_t));
++		ep->dwc_ep.is_in = 1;
++		ep->dwc_ep.dma_addr = cfi->buf_in.addr;
++		ep->dwc_ep.start_xfer_buff = cfi->buf_in.buf;
++		ep->dwc_ep.xfer_buff = cfi->buf_in.buf;
++		ep->dwc_ep.xfer_len = wLen;
++		ep->dwc_ep.xfer_count = 0;
++		ep->dwc_ep.sent_zlp = 0;
++		ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
++
++		pcd->ep0_pending = 1;
++		dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep);
++		cfi->need_gadget_att = 0;
++		retval = 0;
++		break;
++
++	case VEN_CORE_WRITE_REGISTER:
++		CFI_INFO("VEN_CORE_WRITE_REGISTER\n");
++		/* Set up an XFER to get the data stage of the control request,
++		 * which is the new value of the register to be modified.
++		 */
++		ep = &pcd->ep0;
++		ep->dwc_ep.is_in = 0;
++		ep->dwc_ep.dma_addr = cfi->buf_out.addr;
++		ep->dwc_ep.start_xfer_buff = cfi->buf_out.buf;
++		ep->dwc_ep.xfer_buff = cfi->buf_out.buf;
++		ep->dwc_ep.xfer_len = wLen;
++		ep->dwc_ep.xfer_count = 0;
++		ep->dwc_ep.sent_zlp = 0;
++		ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
++
++		pcd->ep0_pending = 1;
++		/* Read the control write's data stage */
++		dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep);
++		retval = 0;
++		break;
++
++	default:
++		retval = -DWC_E_NOT_SUPPORTED;
++		break;
++	}
++
++	return retval;
++}
++
++/**
++ * This function prepares the core features descriptors and copies its
++ * raw representation into the buffer <buf>.
++ *
++ * The buffer structure is as follows:
++ *	all_features_header (8 bytes)
++ *	features_#1 (8 bytes + feature name string length)
++ *	features_#2 (8 bytes + feature name string length)
++ *	.....
++ *	features_#n - where n=the total count of feature descriptors
++ */
++static int cfi_core_features_buf(uint8_t * buf, uint16_t buflen)
++{
++	cfi_feature_desc_header_t *prop_hdr = prop_descs;
++	cfi_feature_desc_header_t *prop;
++	cfi_all_features_header_t *all_props_hdr = &all_props_desc_header;
++	cfi_all_features_header_t *tmp;
++	uint8_t *tmpbuf = buf;
++	const uint8_t *pname = NULL;
++	int i, j, namelen = 0, totlen;
++
++	/* Prepare and copy the core features into the buffer */
++	CFI_INFO("%s:\n", __func__);
++
++	tmp = (cfi_all_features_header_t *) tmpbuf;
++	*tmp = *all_props_hdr;
++	tmpbuf += CFI_ALL_FEATURES_HDR_LEN;
++
++	j = sizeof(prop_descs) / sizeof(cfi_all_features_header_t);
++	for (i = 0; i < j; i++, prop_hdr++) {
++		pname = get_prop_name(prop_hdr->wFeatureID, &namelen);
++		prop = (cfi_feature_desc_header_t *) tmpbuf;
++		*prop = *prop_hdr;
++
++		prop->bNameLen = namelen;
++		prop->wLength =
++		    DWC_CONSTANT_CPU_TO_LE16(CFI_FEATURE_DESC_HDR_LEN +
++					     namelen);
++
++		tmpbuf += CFI_FEATURE_DESC_HDR_LEN;
++		dwc_memcpy(tmpbuf, pname, namelen);
++		tmpbuf += namelen;
++	}
++
++	totlen = tmpbuf - buf;
++
++	if (totlen > 0) {
++		tmp = (cfi_all_features_header_t *) buf;
++		tmp->wTotalLen = DWC_CONSTANT_CPU_TO_LE16(totlen);
++	}
++
++	return totlen;
++}
++
++/**
++ * This function releases all the dynamic memory in the CFI object.
++ */
++static void cfi_release(cfiobject_t * cfiobj)
++{
++	cfi_ep_t *cfiep;
++	dwc_list_link_t *tmp;
++
++	CFI_INFO("%s\n", __func__);
++
++	if (cfiobj->buf_in.buf) {
++		DWC_DMA_FREE(CFI_IN_BUF_LEN, cfiobj->buf_in.buf,
++			     cfiobj->buf_in.addr);
++		cfiobj->buf_in.buf = NULL;
++	}
++
++	if (cfiobj->buf_out.buf) {
++		DWC_DMA_FREE(CFI_OUT_BUF_LEN, cfiobj->buf_out.buf,
++			     cfiobj->buf_out.addr);
++		cfiobj->buf_out.buf = NULL;
++	}
++
++	/* Free the Buffer Setup values for each EP */
++	//list_for_each_entry(cfiep, &cfiobj->active_eps, lh) {
++	DWC_LIST_FOREACH(tmp, &cfiobj->active_eps) {
++		cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
++		cfi_free_ep_bs_dyn_data(cfiep);
++	}
++}
++
++/**
++ * This function frees the dynamically allocated EP buffer setup data.
++ */
++static void cfi_free_ep_bs_dyn_data(cfi_ep_t * cfiep)
++{
++	if (cfiep->bm_sg) {
++		DWC_FREE(cfiep->bm_sg);
++		cfiep->bm_sg = NULL;
++	}
++
++	if (cfiep->bm_align) {
++		DWC_FREE(cfiep->bm_align);
++		cfiep->bm_align = NULL;
++	}
++
++	if (cfiep->bm_concat) {
++		if (NULL != cfiep->bm_concat->wTxBytes) {
++			DWC_FREE(cfiep->bm_concat->wTxBytes);
++			cfiep->bm_concat->wTxBytes = NULL;
++		}
++		DWC_FREE(cfiep->bm_concat);
++		cfiep->bm_concat = NULL;
++	}
++}
++
++/**
++ * This function initializes the default values of the features
++ * for a specific endpoint and should be called only once when
++ * the EP is enabled first time.
++ */
++static int cfi_ep_init_defaults(struct dwc_otg_pcd *pcd, cfi_ep_t * cfiep)
++{
++	int retval = 0;
++
++	cfiep->bm_sg = DWC_ALLOC(sizeof(ddma_sg_buffer_setup_t));
++	if (NULL == cfiep->bm_sg) {
++		CFI_INFO("Failed to allocate memory for SG feature value\n");
++		return -DWC_E_NO_MEMORY;
++	}
++	dwc_memset(cfiep->bm_sg, 0, sizeof(ddma_sg_buffer_setup_t));
++
++	/* For the Concatenation feature's default value we do not allocate
++	 * memory for the wTxBytes field - it will be done in the set_feature_value
++	 * request handler.
++	 */
++	cfiep->bm_concat = DWC_ALLOC(sizeof(ddma_concat_buffer_setup_t));
++	if (NULL == cfiep->bm_concat) {
++		CFI_INFO
++		    ("Failed to allocate memory for CONCATENATION feature value\n");
++		DWC_FREE(cfiep->bm_sg);
++		return -DWC_E_NO_MEMORY;
++	}
++	dwc_memset(cfiep->bm_concat, 0, sizeof(ddma_concat_buffer_setup_t));
++
++	cfiep->bm_align = DWC_ALLOC(sizeof(ddma_align_buffer_setup_t));
++	if (NULL == cfiep->bm_align) {
++		CFI_INFO
++		    ("Failed to allocate memory for Alignment feature value\n");
++		DWC_FREE(cfiep->bm_sg);
++		DWC_FREE(cfiep->bm_concat);
++		return -DWC_E_NO_MEMORY;
++	}
++	dwc_memset(cfiep->bm_align, 0, sizeof(ddma_align_buffer_setup_t));
++
++	return retval;
++}
++
++/**
++ * The callback function that notifies the CFI on the activation of
++ * an endpoint in the PCD. The following steps are done in this function:
++ *
++ *	Create a dynamically allocated cfi_ep_t object (a CFI wrapper to the PCD's
++ *		active endpoint)
++ *	Create MAX_DMA_DESCS_PER_EP count DMA Descriptors for the EP
++ *	Set the Buffer Mode to standard
++ *	Initialize the default values for all EP modes (SG, Circular, Concat, Align)
++ *	Add the cfi_ep_t object to the list of active endpoints in the CFI object
++ */
++static int cfi_ep_enable(struct cfiobject *cfi, struct dwc_otg_pcd *pcd,
++			 struct dwc_otg_pcd_ep *ep)
++{
++	cfi_ep_t *cfiep;
++	int retval = -DWC_E_NOT_SUPPORTED;
++
++	CFI_INFO("%s: epname=%s; epnum=0x%02x\n", __func__,
++		 "EP_" /*ep->ep.name */ , ep->desc->bEndpointAddress);
++	/* MAS - Check whether this endpoint already is in the list */
++	cfiep = get_cfi_ep_by_pcd_ep(cfi, ep);
++
++	if (NULL == cfiep) {
++		/* Allocate a cfi_ep_t object */
++		cfiep = DWC_ALLOC(sizeof(cfi_ep_t));
++		if (NULL == cfiep) {
++			CFI_INFO
++			    ("Unable to allocate memory for <cfiep> in function %s\n",
++			     __func__);
++			return -DWC_E_NO_MEMORY;
++		}
++		dwc_memset(cfiep, 0, sizeof(cfi_ep_t));
++
++		/* Save the dwc_otg_pcd_ep pointer in the cfiep object */
++		cfiep->ep = ep;
++
++		/* Allocate the DMA Descriptors chain of MAX_DMA_DESCS_PER_EP count */
++		ep->dwc_ep.descs =
++		    DWC_DMA_ALLOC(MAX_DMA_DESCS_PER_EP *
++				  sizeof(dwc_otg_dma_desc_t),
++				  &ep->dwc_ep.descs_dma_addr);
++
++		if (NULL == ep->dwc_ep.descs) {
++			DWC_FREE(cfiep);
++			return -DWC_E_NO_MEMORY;
++		}
++
++		DWC_LIST_INIT(&cfiep->lh);
++
++		/* Set the buffer mode to BM_STANDARD. It will be modified
++		 * when building descriptors for a specific buffer mode */
++		ep->dwc_ep.buff_mode = BM_STANDARD;
++
++		/* Create and initialize the default values for this EP's Buffer modes */
++		if ((retval = cfi_ep_init_defaults(pcd, cfiep)) < 0)
++			return retval;
++
++		/* Add the cfi_ep_t object to the CFI object's list of active endpoints */
++		DWC_LIST_INSERT_TAIL(&cfi->active_eps, &cfiep->lh);
++		retval = 0;
++	} else {		/* The sought EP already is in the list */
++		CFI_INFO("%s: The sought EP already is in the list\n",
++			 __func__);
++	}
++
++	return retval;
++}
++
++/**
++ * This function is called when the data stage of a 3-stage Control Write request
++ * is complete.
++ *
++ */
++static int cfi_ctrl_write_complete(struct cfiobject *cfi,
++				   struct dwc_otg_pcd *pcd)
++{
++	uint32_t addr, reg_value;
++	uint16_t wIndex, wValue;
++	uint8_t bRequest;
++	uint8_t *buf = cfi->buf_out.buf;
++	//struct usb_ctrlrequest *ctrl_req = &cfi->ctrl_req_saved;
++	struct cfi_usb_ctrlrequest *ctrl_req = &cfi->ctrl_req;
++	int retval = -DWC_E_NOT_SUPPORTED;
++
++	CFI_INFO("%s\n", __func__);
++
++	bRequest = ctrl_req->bRequest;
++	wIndex = DWC_CONSTANT_CPU_TO_LE16(ctrl_req->wIndex);
++	wValue = DWC_CONSTANT_CPU_TO_LE16(ctrl_req->wValue);
++
++	/*
++	 * Save the pointer to the data stage in the ctrl_req's <data> field.
++	 * The request should be already saved in the command stage by now.
++	 */
++	ctrl_req->data = cfi->buf_out.buf;
++	cfi->need_status_in_complete = 0;
++	cfi->need_gadget_att = 0;
++
++	switch (bRequest) {
++	case VEN_CORE_WRITE_REGISTER:
++		/* The buffer contains raw data of the new value for the register */
++		reg_value = *((uint32_t *) buf);
++		if (wValue == 0) {
++			addr = 0;
++			//addr = (uint32_t) pcd->otg_dev->os_dep.base;
++			addr += wIndex;
++		} else {
++			addr = (wValue << 16) | wIndex;
++		}
++
++		//writel(reg_value, addr);
++
++		retval = 0;
++		cfi->need_status_in_complete = 1;
++		break;
++
++	case VEN_CORE_SET_FEATURE:
++		/* The buffer contains raw data of the new value of the feature */
++		retval = cfi_set_feature_value(pcd);
++		if (retval < 0)
++			return retval;
++
++		cfi->need_status_in_complete = 1;
++		break;
++
++	default:
++		break;
++	}
++
++	return retval;
++}
++
++/**
++ * This function builds the DMA descriptors for the SG buffer mode.
++ */
++static void cfi_build_sg_descs(struct cfiobject *cfi, cfi_ep_t * cfiep,
++			       dwc_otg_pcd_request_t * req)
++{
++	struct dwc_otg_pcd_ep *ep = cfiep->ep;
++	ddma_sg_buffer_setup_t *sgval = cfiep->bm_sg;
++	struct dwc_otg_dma_desc *desc = cfiep->ep->dwc_ep.descs;
++	struct dwc_otg_dma_desc *desc_last = cfiep->ep->dwc_ep.descs;
++	dma_addr_t buff_addr = req->dma;
++	int i;
++	uint32_t txsize, off;
++
++	txsize = sgval->wSize;
++	off = sgval->bOffset;
++
++//      CFI_INFO("%s: %s TXSIZE=0x%08x; OFFSET=0x%08x\n",
++//              __func__, cfiep->ep->ep.name, txsize, off);
++
++	for (i = 0; i < sgval->bCount; i++) {
++		desc->status.b.bs = BS_HOST_BUSY;
++		desc->buf = buff_addr;
++		desc->status.b.l = 0;
++		desc->status.b.ioc = 0;
++		desc->status.b.sp = 0;
++		desc->status.b.bytes = txsize;
++		desc->status.b.bs = BS_HOST_READY;
++
++		/* Set the next address of the buffer */
++		buff_addr += txsize + off;
++		desc_last = desc;
++		desc++;
++	}
++
++	/* Set the last, ioc and sp bits on the Last DMA Descriptor */
++	desc_last->status.b.l = 1;
++	desc_last->status.b.ioc = 1;
++	desc_last->status.b.sp = ep->dwc_ep.sent_zlp;
++	/* Save the last DMA descriptor pointer */
++	cfiep->dma_desc_last = desc_last;
++	cfiep->desc_count = sgval->bCount;
++}
++
++/**
++ * This function builds the DMA descriptors for the Concatenation buffer mode.
++ */
++static void cfi_build_concat_descs(struct cfiobject *cfi, cfi_ep_t * cfiep,
++				   dwc_otg_pcd_request_t * req)
++{
++	struct dwc_otg_pcd_ep *ep = cfiep->ep;
++	ddma_concat_buffer_setup_t *concatval = cfiep->bm_concat;
++	struct dwc_otg_dma_desc *desc = cfiep->ep->dwc_ep.descs;
++	struct dwc_otg_dma_desc *desc_last = cfiep->ep->dwc_ep.descs;
++	dma_addr_t buff_addr = req->dma;
++	int i;
++	uint16_t *txsize;
++
++	txsize = concatval->wTxBytes;
++
++	for (i = 0; i < concatval->hdr.bDescCount; i++) {
++		desc->buf = buff_addr;
++		desc->status.b.bs = BS_HOST_BUSY;
++		desc->status.b.l = 0;
++		desc->status.b.ioc = 0;
++		desc->status.b.sp = 0;
++		desc->status.b.bytes = *txsize;
++		desc->status.b.bs = BS_HOST_READY;
++
++		txsize++;
++		/* Set the next address of the buffer */
++		buff_addr += UGETW(ep->desc->wMaxPacketSize);
++		desc_last = desc;
++		desc++;
++	}
++
++	/* Set the last, ioc and sp bits on the Last DMA Descriptor */
++	desc_last->status.b.l = 1;
++	desc_last->status.b.ioc = 1;
++	desc_last->status.b.sp = ep->dwc_ep.sent_zlp;
++	cfiep->dma_desc_last = desc_last;
++	cfiep->desc_count = concatval->hdr.bDescCount;
++}
++
++/**
++ * This function builds the DMA descriptors for the Circular buffer mode
++ */
++static void cfi_build_circ_descs(struct cfiobject *cfi, cfi_ep_t * cfiep,
++				 dwc_otg_pcd_request_t * req)
++{
++	/* @todo: MAS - add implementation when this feature needs to be tested */
++}
++
++/**
++ * This function builds the DMA descriptors for the Alignment buffer mode
++ */
++static void cfi_build_align_descs(struct cfiobject *cfi, cfi_ep_t * cfiep,
++				  dwc_otg_pcd_request_t * req)
++{
++	struct dwc_otg_pcd_ep *ep = cfiep->ep;
++	ddma_align_buffer_setup_t *alignval = cfiep->bm_align;
++	struct dwc_otg_dma_desc *desc = cfiep->ep->dwc_ep.descs;
++	dma_addr_t buff_addr = req->dma;
++
++	desc->status.b.bs = BS_HOST_BUSY;
++	desc->status.b.l = 1;
++	desc->status.b.ioc = 1;
++	desc->status.b.sp = ep->dwc_ep.sent_zlp;
++	desc->status.b.bytes = req->length;
++	/* Adjust the buffer alignment */
++	desc->buf = (buff_addr + alignval->bAlign);
++	desc->status.b.bs = BS_HOST_READY;
++	cfiep->dma_desc_last = desc;
++	cfiep->desc_count = 1;
++}
++
++/**
++ * This function builds the DMA descriptors chain for different modes of the
++ * buffer setup of an endpoint.
++ */
++static void cfi_build_descriptors(struct cfiobject *cfi,
++				  struct dwc_otg_pcd *pcd,
++				  struct dwc_otg_pcd_ep *ep,
++				  dwc_otg_pcd_request_t * req)
++{
++	cfi_ep_t *cfiep;
++
++	/* Get the cfiep by the dwc_otg_pcd_ep */
++	cfiep = get_cfi_ep_by_pcd_ep(cfi, ep);
++	if (NULL == cfiep) {
++		CFI_INFO("%s: Unable to find a matching active endpoint\n",
++			 __func__);
++		return;
++	}
++
++	cfiep->xfer_len = req->length;
++
++	/* Iterate through all the DMA descriptors */
++	switch (cfiep->ep->dwc_ep.buff_mode) {
++	case BM_SG:
++		cfi_build_sg_descs(cfi, cfiep, req);
++		break;
++
++	case BM_CONCAT:
++		cfi_build_concat_descs(cfi, cfiep, req);
++		break;
++
++	case BM_CIRCULAR:
++		cfi_build_circ_descs(cfi, cfiep, req);
++		break;
++
++	case BM_ALIGN:
++		cfi_build_align_descs(cfi, cfiep, req);
++		break;
++
++	default:
++		break;
++	}
++}
++
++/**
++ * Allocate DMA buffer for different Buffer modes.
++ */
++static void *cfi_ep_alloc_buf(struct cfiobject *cfi, struct dwc_otg_pcd *pcd,
++			      struct dwc_otg_pcd_ep *ep, dma_addr_t * dma,
++			      unsigned size, gfp_t flags)
++{
++	return DWC_DMA_ALLOC(size, dma);
++}
++
++/**
++ * This function initializes the CFI object.
++ */
++int init_cfi(cfiobject_t * cfiobj)
++{
++	CFI_INFO("%s\n", __func__);
++
++	/* Allocate a buffer for IN XFERs */
++	cfiobj->buf_in.buf =
++	    DWC_DMA_ALLOC(CFI_IN_BUF_LEN, &cfiobj->buf_in.addr);
++	if (NULL == cfiobj->buf_in.buf) {
++		CFI_INFO("Unable to allocate buffer for INs\n");
++		return -DWC_E_NO_MEMORY;
++	}
++
++	/* Allocate a buffer for OUT XFERs */
++	cfiobj->buf_out.buf =
++	    DWC_DMA_ALLOC(CFI_OUT_BUF_LEN, &cfiobj->buf_out.addr);
++	if (NULL == cfiobj->buf_out.buf) {
++		CFI_INFO("Unable to allocate buffer for OUT\n");
++		return -DWC_E_NO_MEMORY;
++	}
++
++	/* Initialize the callback function pointers */
++	cfiobj->ops.release = cfi_release;
++	cfiobj->ops.ep_enable = cfi_ep_enable;
++	cfiobj->ops.ctrl_write_complete = cfi_ctrl_write_complete;
++	cfiobj->ops.build_descriptors = cfi_build_descriptors;
++	cfiobj->ops.ep_alloc_buf = cfi_ep_alloc_buf;
++
++	/* Initialize the list of active endpoints in the CFI object */
++	DWC_LIST_INIT(&cfiobj->active_eps);
++
++	return 0;
++}
++
++/**
++ * This function reads the required feature's current value into the buffer
++ *
++ * @retval: Returns negative as error, or the data length of the feature
++ */
++static int cfi_get_feature_value(uint8_t * buf, uint16_t buflen,
++				 struct dwc_otg_pcd *pcd,
++				 struct cfi_usb_ctrlrequest *ctrl_req)
++{
++	int retval = -DWC_E_NOT_SUPPORTED;
++	struct dwc_otg_core_if *coreif = GET_CORE_IF(pcd);
++	uint16_t dfifo, rxfifo, txfifo;
++
++	switch (ctrl_req->wIndex) {
++		/* Whether the DDMA is enabled or not */
++	case FT_ID_DMA_MODE:
++		*buf = (coreif->dma_enable && coreif->dma_desc_enable) ? 1 : 0;
++		retval = 1;
++		break;
++
++	case FT_ID_DMA_BUFFER_SETUP:
++		retval = cfi_ep_get_sg_val(buf, pcd, ctrl_req);
++		break;
++
++	case FT_ID_DMA_BUFF_ALIGN:
++		retval = cfi_ep_get_align_val(buf, pcd, ctrl_req);
++		break;
++
++	case FT_ID_DMA_CONCAT_SETUP:
++		retval = cfi_ep_get_concat_val(buf, pcd, ctrl_req);
++		break;
++
++	case FT_ID_DMA_CIRCULAR:
++		CFI_INFO("GetFeature value (FT_ID_DMA_CIRCULAR)\n");
++		break;
++
++	case FT_ID_THRESHOLD_SETUP:
++		CFI_INFO("GetFeature value (FT_ID_THRESHOLD_SETUP)\n");
++		break;
++
++	case FT_ID_DFIFO_DEPTH:
++		dfifo = get_dfifo_size(coreif);
++		*((uint16_t *) buf) = dfifo;
++		retval = sizeof(uint16_t);
++		break;
++
++	case FT_ID_TX_FIFO_DEPTH:
++		retval = get_txfifo_size(pcd, ctrl_req->wValue);
++		if (retval >= 0) {
++			txfifo = retval;
++			*((uint16_t *) buf) = txfifo;
++			retval = sizeof(uint16_t);
++		}
++		break;
++
++	case FT_ID_RX_FIFO_DEPTH:
++		retval = get_rxfifo_size(coreif, ctrl_req->wValue);
++		if (retval >= 0) {
++			rxfifo = retval;
++			*((uint16_t *) buf) = rxfifo;
++			retval = sizeof(uint16_t);
++		}
++		break;
++	}
++
++	return retval;
++}
++
++/**
++ * This function resets the SG for the specified EP to its default value
++ */
++static int cfi_reset_sg_val(cfi_ep_t * cfiep)
++{
++	dwc_memset(cfiep->bm_sg, 0, sizeof(ddma_sg_buffer_setup_t));
++	return 0;
++}
++
++/**
++ * This function resets the Alignment for the specified EP to its default value
++ */
++static int cfi_reset_align_val(cfi_ep_t * cfiep)
++{
++	dwc_memset(cfiep->bm_sg, 0, sizeof(ddma_sg_buffer_setup_t));
++	return 0;
++}
++
++/**
++ * This function resets the Concatenation for the specified EP to its default value
++ * This function will also set the value of the wTxBytes field to NULL after
++ * freeing the memory previously allocated for this field.
++ */
++static int cfi_reset_concat_val(cfi_ep_t * cfiep)
++{
++	/* First we need to free the wTxBytes field */
++	if (cfiep->bm_concat->wTxBytes) {
++		DWC_FREE(cfiep->bm_concat->wTxBytes);
++		cfiep->bm_concat->wTxBytes = NULL;
++	}
++
++	dwc_memset(cfiep->bm_concat, 0, sizeof(ddma_concat_buffer_setup_t));
++	return 0;
++}
++
++/**
++ * This function resets all the buffer setups of the specified endpoint
++ */
++static int cfi_ep_reset_all_setup_vals(cfi_ep_t * cfiep)
++{
++	cfi_reset_sg_val(cfiep);
++	cfi_reset_align_val(cfiep);
++	cfi_reset_concat_val(cfiep);
++	return 0;
++}
++
++static int cfi_handle_reset_fifo_val(struct dwc_otg_pcd *pcd, uint8_t ep_addr,
++				     uint8_t rx_rst, uint8_t tx_rst)
++{
++	int retval = -DWC_E_INVALID;
++	uint16_t tx_siz[15];
++	uint16_t rx_siz = 0;
++	dwc_otg_pcd_ep_t *ep = NULL;
++	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
++	dwc_otg_core_params_t *params = GET_CORE_IF(pcd)->core_params;
++
++	if (rx_rst) {
++		rx_siz = params->dev_rx_fifo_size;
++		params->dev_rx_fifo_size = GET_CORE_IF(pcd)->init_rxfsiz;
++	}
++
++	if (tx_rst) {
++		if (ep_addr == 0) {
++			int i;
++
++			for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
++				tx_siz[i] =
++				    core_if->core_params->dev_tx_fifo_size[i];
++				core_if->core_params->dev_tx_fifo_size[i] =
++				    core_if->init_txfsiz[i];
++			}
++		} else {
++
++			ep = get_ep_by_addr(pcd, ep_addr);
++
++			if (NULL == ep) {
++				CFI_INFO
++				    ("%s: Unable to get the endpoint addr=0x%02x\n",
++				     __func__, ep_addr);
++				return -DWC_E_INVALID;
++			}
++
++			tx_siz[0] =
++			    params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num -
++						     1];
++			params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num - 1] =
++			    GET_CORE_IF(pcd)->init_txfsiz[ep->
++							  dwc_ep.tx_fifo_num -
++							  1];
++		}
++	}
++
++	if (resize_fifos(GET_CORE_IF(pcd))) {
++		retval = 0;
++	} else {
++		CFI_INFO
++		    ("%s: Error resetting the feature Reset All(FIFO size)\n",
++		     __func__);
++		if (rx_rst) {
++			params->dev_rx_fifo_size = rx_siz;
++		}
++
++		if (tx_rst) {
++			if (ep_addr == 0) {
++				int i;
++				for (i = 0; i < core_if->hwcfg4.b.num_in_eps;
++				     i++) {
++					core_if->
++					    core_params->dev_tx_fifo_size[i] =
++					    tx_siz[i];
++				}
++			} else {
++				params->dev_tx_fifo_size[ep->
++							 dwc_ep.tx_fifo_num -
++							 1] = tx_siz[0];
++			}
++		}
++		retval = -DWC_E_INVALID;
++	}
++	return retval;
++}
++
++static int cfi_handle_reset_all(struct dwc_otg_pcd *pcd, uint8_t addr)
++{
++	int retval = 0;
++	cfi_ep_t *cfiep;
++	cfiobject_t *cfi = pcd->cfi;
++	dwc_list_link_t *tmp;
++
++	retval = cfi_handle_reset_fifo_val(pcd, addr, 1, 1);
++	if (retval < 0) {
++		return retval;
++	}
++
++	/* If the EP address is known then reset the features for only that EP */
++	if (addr) {
++		cfiep = get_cfi_ep_by_addr(pcd->cfi, addr);
++		if (NULL == cfiep) {
++			CFI_INFO("%s: Error getting the EP address 0x%02x\n",
++				 __func__, addr);
++			return -DWC_E_INVALID;
++		}
++		retval = cfi_ep_reset_all_setup_vals(cfiep);
++		cfiep->ep->dwc_ep.buff_mode = BM_STANDARD;
++	}
++	/* Otherwise (wValue == 0), reset all features of all EP's */
++	else {
++		/* Traverse all the active EP's and reset the feature(s) value(s) */
++		//list_for_each_entry(cfiep, &cfi->active_eps, lh) {
++		DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
++			cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
++			retval = cfi_ep_reset_all_setup_vals(cfiep);
++			cfiep->ep->dwc_ep.buff_mode = BM_STANDARD;
++			if (retval < 0) {
++				CFI_INFO
++				    ("%s: Error resetting the feature Reset All\n",
++				     __func__);
++				return retval;
++			}
++		}
++	}
++	return retval;
++}
++
++static int cfi_handle_reset_dma_buff_setup(struct dwc_otg_pcd *pcd,
++					   uint8_t addr)
++{
++	int retval = 0;
++	cfi_ep_t *cfiep;
++	cfiobject_t *cfi = pcd->cfi;
++	dwc_list_link_t *tmp;
++
++	/* If the EP address is known then reset the features for only that EP */
++	if (addr) {
++		cfiep = get_cfi_ep_by_addr(pcd->cfi, addr);
++		if (NULL == cfiep) {
++			CFI_INFO("%s: Error getting the EP address 0x%02x\n",
++				 __func__, addr);
++			return -DWC_E_INVALID;
++		}
++		retval = cfi_reset_sg_val(cfiep);
++	}
++	/* Otherwise (wValue == 0), reset all features of all EP's */
++	else {
++		/* Traverse all the active EP's and reset the feature(s) value(s) */
++		//list_for_each_entry(cfiep, &cfi->active_eps, lh) {
++		DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
++			cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
++			retval = cfi_reset_sg_val(cfiep);
++			if (retval < 0) {
++				CFI_INFO
++				    ("%s: Error resetting the feature Buffer Setup\n",
++				     __func__);
++				return retval;
++			}
++		}
++	}
++	return retval;
++}
++
++static int cfi_handle_reset_concat_val(struct dwc_otg_pcd *pcd, uint8_t addr)
++{
++	int retval = 0;
++	cfi_ep_t *cfiep;
++	cfiobject_t *cfi = pcd->cfi;
++	dwc_list_link_t *tmp;
++
++	/* If the EP address is known then reset the features for only that EP */
++	if (addr) {
++		cfiep = get_cfi_ep_by_addr(pcd->cfi, addr);
++		if (NULL == cfiep) {
++			CFI_INFO("%s: Error getting the EP address 0x%02x\n",
++				 __func__, addr);
++			return -DWC_E_INVALID;
++		}
++		retval = cfi_reset_concat_val(cfiep);
++	}
++	/* Otherwise (wValue == 0), reset all features of all EP's */
++	else {
++		/* Traverse all the active EP's and reset the feature(s) value(s) */
++		//list_for_each_entry(cfiep, &cfi->active_eps, lh) {
++		DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
++			cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
++			retval = cfi_reset_concat_val(cfiep);
++			if (retval < 0) {
++				CFI_INFO
++				    ("%s: Error resetting the feature Concatenation Value\n",
++				     __func__);
++				return retval;
++			}
++		}
++	}
++	return retval;
++}
++
++static int cfi_handle_reset_align_val(struct dwc_otg_pcd *pcd, uint8_t addr)
++{
++	int retval = 0;
++	cfi_ep_t *cfiep;
++	cfiobject_t *cfi = pcd->cfi;
++	dwc_list_link_t *tmp;
++
++	/* If the EP address is known then reset the features for only that EP */
++	if (addr) {
++		cfiep = get_cfi_ep_by_addr(pcd->cfi, addr);
++		if (NULL == cfiep) {
++			CFI_INFO("%s: Error getting the EP address 0x%02x\n",
++				 __func__, addr);
++			return -DWC_E_INVALID;
++		}
++		retval = cfi_reset_align_val(cfiep);
++	}
++	/* Otherwise (wValue == 0), reset all features of all EP's */
++	else {
++		/* Traverse all the active EP's and reset the feature(s) value(s) */
++		//list_for_each_entry(cfiep, &cfi->active_eps, lh) {
++		DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
++			cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
++			retval = cfi_reset_align_val(cfiep);
++			if (retval < 0) {
++				CFI_INFO
++				    ("%s: Error resetting the feature Aliignment Value\n",
++				     __func__);
++				return retval;
++			}
++		}
++	}
++	return retval;
++
++}
++
++static int cfi_preproc_reset(struct dwc_otg_pcd *pcd,
++			     struct cfi_usb_ctrlrequest *req)
++{
++	int retval = 0;
++
++	switch (req->wIndex) {
++	case 0:
++		/* Reset all features */
++		retval = cfi_handle_reset_all(pcd, req->wValue & 0xff);
++		break;
++
++	case FT_ID_DMA_BUFFER_SETUP:
++		/* Reset the SG buffer setup */
++		retval =
++		    cfi_handle_reset_dma_buff_setup(pcd, req->wValue & 0xff);
++		break;
++
++	case FT_ID_DMA_CONCAT_SETUP:
++		/* Reset the Concatenation buffer setup */
++		retval = cfi_handle_reset_concat_val(pcd, req->wValue & 0xff);
++		break;
++
++	case FT_ID_DMA_BUFF_ALIGN:
++		/* Reset the Alignment buffer setup */
++		retval = cfi_handle_reset_align_val(pcd, req->wValue & 0xff);
++		break;
++
++	case FT_ID_TX_FIFO_DEPTH:
++		retval =
++		    cfi_handle_reset_fifo_val(pcd, req->wValue & 0xff, 0, 1);
++		pcd->cfi->need_gadget_att = 0;
++		break;
++
++	case FT_ID_RX_FIFO_DEPTH:
++		retval = cfi_handle_reset_fifo_val(pcd, 0, 1, 0);
++		pcd->cfi->need_gadget_att = 0;
++		break;
++	default:
++		break;
++	}
++	return retval;
++}
++
++/**
++ * This function sets a new value for the SG buffer setup.
++ */
++static int cfi_ep_set_sg_val(uint8_t * buf, struct dwc_otg_pcd *pcd)
++{
++	uint8_t inaddr, outaddr;
++	cfi_ep_t *epin, *epout;
++	ddma_sg_buffer_setup_t *psgval;
++	uint32_t desccount, size;
++
++	CFI_INFO("%s\n", __func__);
++
++	psgval = (ddma_sg_buffer_setup_t *) buf;
++	desccount = (uint32_t) psgval->bCount;
++	size = (uint32_t) psgval->wSize;
++
++	/* Check the DMA descriptor count */
++	if ((desccount > MAX_DMA_DESCS_PER_EP) || (desccount == 0)) {
++		CFI_INFO
++		    ("%s: The count of DMA Descriptors should be between 1 and %d\n",
++		     __func__, MAX_DMA_DESCS_PER_EP);
++		return -DWC_E_INVALID;
++	}
++
++	/* Check the DMA descriptor count */
++
++	if (size == 0) {
++
++		CFI_INFO("%s: The transfer size should be at least 1 byte\n",
++			 __func__);
++
++		return -DWC_E_INVALID;
++
++	}
++
++	inaddr = psgval->bInEndpointAddress;
++	outaddr = psgval->bOutEndpointAddress;
++
++	epin = get_cfi_ep_by_addr(pcd->cfi, inaddr);
++	epout = get_cfi_ep_by_addr(pcd->cfi, outaddr);
++
++	if (NULL == epin || NULL == epout) {
++		CFI_INFO
++		    ("%s: Unable to get the endpoints inaddr=0x%02x outaddr=0x%02x\n",
++		     __func__, inaddr, outaddr);
++		return -DWC_E_INVALID;
++	}
++
++	epin->ep->dwc_ep.buff_mode = BM_SG;
++	dwc_memcpy(epin->bm_sg, psgval, sizeof(ddma_sg_buffer_setup_t));
++
++	epout->ep->dwc_ep.buff_mode = BM_SG;
++	dwc_memcpy(epout->bm_sg, psgval, sizeof(ddma_sg_buffer_setup_t));
++
++	return 0;
++}
++
++/**
++ * This function sets a new value for the buffer Alignment setup.
++ */
++static int cfi_ep_set_alignment_val(uint8_t * buf, struct dwc_otg_pcd *pcd)
++{
++	cfi_ep_t *ep;
++	uint8_t addr;
++	ddma_align_buffer_setup_t *palignval;
++
++	palignval = (ddma_align_buffer_setup_t *) buf;
++	addr = palignval->bEndpointAddress;
++
++	ep = get_cfi_ep_by_addr(pcd->cfi, addr);
++
++	if (NULL == ep) {
++		CFI_INFO("%s: Unable to get the endpoint addr=0x%02x\n",
++			 __func__, addr);
++		return -DWC_E_INVALID;
++	}
++
++	ep->ep->dwc_ep.buff_mode = BM_ALIGN;
++	dwc_memcpy(ep->bm_align, palignval, sizeof(ddma_align_buffer_setup_t));
++
++	return 0;
++}
++
++/**
++ * This function sets a new value for the Concatenation buffer setup.
++ */
++static int cfi_ep_set_concat_val(uint8_t * buf, struct dwc_otg_pcd *pcd)
++{
++	uint8_t addr;
++	cfi_ep_t *ep;
++	struct _ddma_concat_buffer_setup_hdr *pConcatValHdr;
++	uint16_t *pVals;
++	uint32_t desccount;
++	int i;
++	uint16_t mps;
++
++	pConcatValHdr = (struct _ddma_concat_buffer_setup_hdr *)buf;
++	desccount = (uint32_t) pConcatValHdr->bDescCount;
++	pVals = (uint16_t *) (buf + BS_CONCAT_VAL_HDR_LEN);
++
++	/* Check the DMA descriptor count */
++	if (desccount > MAX_DMA_DESCS_PER_EP) {
++		CFI_INFO("%s: Maximum DMA Descriptor count should be %d\n",
++			 __func__, MAX_DMA_DESCS_PER_EP);
++		return -DWC_E_INVALID;
++	}
++
++	addr = pConcatValHdr->bEndpointAddress;
++	ep = get_cfi_ep_by_addr(pcd->cfi, addr);
++	if (NULL == ep) {
++		CFI_INFO("%s: Unable to get the endpoint addr=0x%02x\n",
++			 __func__, addr);
++		return -DWC_E_INVALID;
++	}
++
++	mps = UGETW(ep->ep->desc->wMaxPacketSize);
++
++#if 0
++	for (i = 0; i < desccount; i++) {
++		CFI_INFO("%s: wTxSize[%d]=0x%04x\n", __func__, i, pVals[i]);
++	}
++	CFI_INFO("%s: epname=%s; mps=%d\n", __func__, ep->ep->ep.name, mps);
++#endif
++
++	/* Check the wTxSizes to be less than or equal to the mps */
++	for (i = 0; i < desccount; i++) {
++		if (pVals[i] > mps) {
++			CFI_INFO
++			    ("%s: ERROR - the wTxSize[%d] should be <= MPS (wTxSize=%d)\n",
++			     __func__, i, pVals[i]);
++			return -DWC_E_INVALID;
++		}
++	}
++
++	ep->ep->dwc_ep.buff_mode = BM_CONCAT;
++	dwc_memcpy(ep->bm_concat, pConcatValHdr, BS_CONCAT_VAL_HDR_LEN);
++
++	/* Free the previously allocated storage for the wTxBytes */
++	if (ep->bm_concat->wTxBytes) {
++		DWC_FREE(ep->bm_concat->wTxBytes);
++	}
++
++	/* Allocate a new storage for the wTxBytes field */
++	ep->bm_concat->wTxBytes =
++	    DWC_ALLOC(sizeof(uint16_t) * pConcatValHdr->bDescCount);
++	if (NULL == ep->bm_concat->wTxBytes) {
++		CFI_INFO("%s: Unable to allocate memory\n", __func__);
++		return -DWC_E_NO_MEMORY;
++	}
++
++	/* Copy the new values into the wTxBytes filed */
++	dwc_memcpy(ep->bm_concat->wTxBytes, buf + BS_CONCAT_VAL_HDR_LEN,
++		   sizeof(uint16_t) * pConcatValHdr->bDescCount);
++
++	return 0;
++}
++
++/**
++ * This function calculates the total of all FIFO sizes
++ *
++ * @param core_if Programming view of DWC_otg controller
++ *
++ * @return The total of data FIFO sizes.
++ *
++ */
++static uint16_t get_dfifo_size(dwc_otg_core_if_t * core_if)
++{
++	dwc_otg_core_params_t *params = core_if->core_params;
++	uint16_t dfifo_total = 0;
++	int i;
++
++	/* The shared RxFIFO size */
++	dfifo_total =
++	    params->dev_rx_fifo_size + params->dev_nperio_tx_fifo_size;
++
++	/* Add up each TxFIFO size to the total */
++	for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
++		dfifo_total += params->dev_tx_fifo_size[i];
++	}
++
++	return dfifo_total;
++}
++
++/**
++ * This function returns Rx FIFO size
++ *
++ * @param core_if Programming view of DWC_otg controller
++ *
++ * @return The total of data FIFO sizes.
++ *
++ */
++static int32_t get_rxfifo_size(dwc_otg_core_if_t * core_if, uint16_t wValue)
++{
++	switch (wValue >> 8) {
++	case 0:
++		return (core_if->pwron_rxfsiz <
++			32768) ? core_if->pwron_rxfsiz : 32768;
++		break;
++	case 1:
++		return core_if->core_params->dev_rx_fifo_size;
++		break;
++	default:
++		return -DWC_E_INVALID;
++		break;
++	}
++}
++
++/**
++ * This function returns Tx FIFO size for IN EP
++ *
++ * @param core_if Programming view of DWC_otg controller
++ *
++ * @return The total of data FIFO sizes.
++ *
++ */
++static int32_t get_txfifo_size(struct dwc_otg_pcd *pcd, uint16_t wValue)
++{
++	dwc_otg_pcd_ep_t *ep;
++
++	ep = get_ep_by_addr(pcd, wValue & 0xff);
++
++	if (NULL == ep) {
++		CFI_INFO("%s: Unable to get the endpoint addr=0x%02x\n",
++			 __func__, wValue & 0xff);
++		return -DWC_E_INVALID;
++	}
++
++	if (!ep->dwc_ep.is_in) {
++		CFI_INFO
++		    ("%s: No Tx FIFO assingned to the Out endpoint addr=0x%02x\n",
++		     __func__, wValue & 0xff);
++		return -DWC_E_INVALID;
++	}
++
++	switch (wValue >> 8) {
++	case 0:
++		return (GET_CORE_IF(pcd)->pwron_txfsiz
++			[ep->dwc_ep.tx_fifo_num - 1] <
++			768) ? GET_CORE_IF(pcd)->pwron_txfsiz[ep->
++							      dwc_ep.tx_fifo_num
++							      - 1] : 32768;
++		break;
++	case 1:
++		return GET_CORE_IF(pcd)->core_params->
++		    dev_tx_fifo_size[ep->dwc_ep.num - 1];
++		break;
++	default:
++		return -DWC_E_INVALID;
++		break;
++	}
++}
++
++/**
++ * This function checks if the submitted combination of
++ * device mode FIFO sizes is possible or not.
++ *
++ * @param core_if Programming view of DWC_otg controller
++ *
++ * @return 1 if possible, 0 otherwise.
++ *
++ */
++static uint8_t check_fifo_sizes(dwc_otg_core_if_t * core_if)
++{
++	uint16_t dfifo_actual = 0;
++	dwc_otg_core_params_t *params = core_if->core_params;
++	uint16_t start_addr = 0;
++	int i;
++
++	dfifo_actual =
++	    params->dev_rx_fifo_size + params->dev_nperio_tx_fifo_size;
++
++	for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
++		dfifo_actual += params->dev_tx_fifo_size[i];
++	}
++
++	if (dfifo_actual > core_if->total_fifo_size) {
++		return 0;
++	}
++
++	if (params->dev_rx_fifo_size > 32768 || params->dev_rx_fifo_size < 16)
++		return 0;
++
++	if (params->dev_nperio_tx_fifo_size > 32768
++	    || params->dev_nperio_tx_fifo_size < 16)
++		return 0;
++
++	for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
++
++		if (params->dev_tx_fifo_size[i] > 768
++		    || params->dev_tx_fifo_size[i] < 4)
++			return 0;
++	}
++
++	if (params->dev_rx_fifo_size > core_if->pwron_rxfsiz)
++		return 0;
++	start_addr = params->dev_rx_fifo_size;
++
++	if (params->dev_nperio_tx_fifo_size > core_if->pwron_gnptxfsiz)
++		return 0;
++	start_addr += params->dev_nperio_tx_fifo_size;
++
++	for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
++
++		if (params->dev_tx_fifo_size[i] > core_if->pwron_txfsiz[i])
++			return 0;
++		start_addr += params->dev_tx_fifo_size[i];
++	}
++
++	return 1;
++}
++
++/**
++ * This function resizes Device mode FIFOs
++ *
++ * @param core_if Programming view of DWC_otg controller
++ *
++ * @return 1 if successful, 0 otherwise
++ *
++ */
++static uint8_t resize_fifos(dwc_otg_core_if_t * core_if)
++{
++	int i = 0;
++	dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
++	dwc_otg_core_params_t *params = core_if->core_params;
++	uint32_t rx_fifo_size;
++	fifosize_data_t nptxfifosize;
++	fifosize_data_t txfifosize[15];
++
++	uint32_t rx_fsz_bak;
++	uint32_t nptxfsz_bak;
++	uint32_t txfsz_bak[15];
++
++	uint16_t start_address;
++	uint8_t retval = 1;
++
++	if (!check_fifo_sizes(core_if)) {
++		return 0;
++	}
++
++	/* Configure data FIFO sizes */
++	if (core_if->hwcfg2.b.dynamic_fifo && params->enable_dynamic_fifo) {
++		rx_fsz_bak = DWC_READ_REG32(&global_regs->grxfsiz);
++		rx_fifo_size = params->dev_rx_fifo_size;
++		DWC_WRITE_REG32(&global_regs->grxfsiz, rx_fifo_size);
++
++		/*
++		 * Tx FIFOs These FIFOs are numbered from 1 to 15.
++		 * Indexes of the FIFO size module parameters in the
++		 * dev_tx_fifo_size array and the FIFO size registers in
++		 * the dtxfsiz array run from 0 to 14.
++		 */
++
++		/* Non-periodic Tx FIFO */
++		nptxfsz_bak = DWC_READ_REG32(&global_regs->gnptxfsiz);
++		nptxfifosize.b.depth = params->dev_nperio_tx_fifo_size;
++		start_address = params->dev_rx_fifo_size;
++		nptxfifosize.b.startaddr = start_address;
++
++		DWC_WRITE_REG32(&global_regs->gnptxfsiz, nptxfifosize.d32);
++
++		start_address += nptxfifosize.b.depth;
++
++		for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
++			txfsz_bak[i] = DWC_READ_REG32(&global_regs->dtxfsiz[i]);
++
++			txfifosize[i].b.depth = params->dev_tx_fifo_size[i];
++			txfifosize[i].b.startaddr = start_address;
++			DWC_WRITE_REG32(&global_regs->dtxfsiz[i],
++					txfifosize[i].d32);
++
++			start_address += txfifosize[i].b.depth;
++		}
++
++		/** Check if register values are set correctly */
++		if (rx_fifo_size != DWC_READ_REG32(&global_regs->grxfsiz)) {
++			retval = 0;
++		}
++
++		if (nptxfifosize.d32 != DWC_READ_REG32(&global_regs->gnptxfsiz)) {
++			retval = 0;
++		}
++
++		for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
++			if (txfifosize[i].d32 !=
++			    DWC_READ_REG32(&global_regs->dtxfsiz[i])) {
++				retval = 0;
++			}
++		}
++
++		/** If register values are not set correctly, reset old values */
++		if (retval == 0) {
++			DWC_WRITE_REG32(&global_regs->grxfsiz, rx_fsz_bak);
++
++			/* Non-periodic Tx FIFO */
++			DWC_WRITE_REG32(&global_regs->gnptxfsiz, nptxfsz_bak);
++
++			for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
++				DWC_WRITE_REG32(&global_regs->dtxfsiz[i],
++						txfsz_bak[i]);
++			}
++		}
++	} else {
++		return 0;
++	}
++
++	/* Flush the FIFOs */
++	dwc_otg_flush_tx_fifo(core_if, 0x10);	/* all Tx FIFOs */
++	dwc_otg_flush_rx_fifo(core_if);
++
++	return retval;
++}
++
++/**
++ * This function sets a new value for the buffer Alignment setup.
++ */
++static int cfi_ep_set_tx_fifo_val(uint8_t * buf, dwc_otg_pcd_t * pcd)
++{
++	int retval;
++	uint32_t fsiz;
++	uint16_t size;
++	uint16_t ep_addr;
++	dwc_otg_pcd_ep_t *ep;
++	dwc_otg_core_params_t *params = GET_CORE_IF(pcd)->core_params;
++	tx_fifo_size_setup_t *ptxfifoval;
++
++	ptxfifoval = (tx_fifo_size_setup_t *) buf;
++	ep_addr = ptxfifoval->bEndpointAddress;
++	size = ptxfifoval->wDepth;
++
++	ep = get_ep_by_addr(pcd, ep_addr);
++
++	CFI_INFO
++	    ("%s: Set Tx FIFO size: endpoint addr=0x%02x, depth=%d, FIFO Num=%d\n",
++	     __func__, ep_addr, size, ep->dwc_ep.tx_fifo_num);
++
++	if (NULL == ep) {
++		CFI_INFO("%s: Unable to get the endpoint addr=0x%02x\n",
++			 __func__, ep_addr);
++		return -DWC_E_INVALID;
++	}
++
++	fsiz = params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num - 1];
++	params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num - 1] = size;
++
++	if (resize_fifos(GET_CORE_IF(pcd))) {
++		retval = 0;
++	} else {
++		CFI_INFO
++		    ("%s: Error setting the feature Tx FIFO Size for EP%d\n",
++		     __func__, ep_addr);
++		params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num - 1] = fsiz;
++		retval = -DWC_E_INVALID;
++	}
++
++	return retval;
++}
++
++/**
++ * This function sets a new value for the buffer Alignment setup.
++ */
++static int cfi_set_rx_fifo_val(uint8_t * buf, dwc_otg_pcd_t * pcd)
++{
++	int retval;
++	uint32_t fsiz;
++	uint16_t size;
++	dwc_otg_core_params_t *params = GET_CORE_IF(pcd)->core_params;
++	rx_fifo_size_setup_t *prxfifoval;
++
++	prxfifoval = (rx_fifo_size_setup_t *) buf;
++	size = prxfifoval->wDepth;
++
++	fsiz = params->dev_rx_fifo_size;
++	params->dev_rx_fifo_size = size;
++
++	if (resize_fifos(GET_CORE_IF(pcd))) {
++		retval = 0;
++	} else {
++		CFI_INFO("%s: Error setting the feature Rx FIFO Size\n",
++			 __func__);
++		params->dev_rx_fifo_size = fsiz;
++		retval = -DWC_E_INVALID;
++	}
++
++	return retval;
++}
++
++/**
++ * This function reads the SG of an EP's buffer setup into the buffer buf
++ */
++static int cfi_ep_get_sg_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
++			     struct cfi_usb_ctrlrequest *req)
++{
++	int retval = -DWC_E_INVALID;
++	uint8_t addr;
++	cfi_ep_t *ep;
++
++	/* The Low Byte of the wValue contains a non-zero address of the endpoint */
++	addr = req->wValue & 0xFF;
++	if (addr == 0)		/* The address should be non-zero */
++		return retval;
++
++	ep = get_cfi_ep_by_addr(pcd->cfi, addr);
++	if (NULL == ep) {
++		CFI_INFO("%s: Unable to get the endpoint address(0x%02x)\n",
++			 __func__, addr);
++		return retval;
++	}
++
++	dwc_memcpy(buf, ep->bm_sg, BS_SG_VAL_DESC_LEN);
++	retval = BS_SG_VAL_DESC_LEN;
++	return retval;
++}
++
++/**
++ * This function reads the Concatenation value of an EP's buffer mode into
++ * the buffer buf
++ */
++static int cfi_ep_get_concat_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
++				 struct cfi_usb_ctrlrequest *req)
++{
++	int retval = -DWC_E_INVALID;
++	uint8_t addr;
++	cfi_ep_t *ep;
++	uint8_t desc_count;
++
++	/* The Low Byte of the wValue contains a non-zero address of the endpoint */
++	addr = req->wValue & 0xFF;
++	if (addr == 0)		/* The address should be non-zero */
++		return retval;
++
++	ep = get_cfi_ep_by_addr(pcd->cfi, addr);
++	if (NULL == ep) {
++		CFI_INFO("%s: Unable to get the endpoint address(0x%02x)\n",
++			 __func__, addr);
++		return retval;
++	}
++
++	/* Copy the header to the buffer */
++	dwc_memcpy(buf, ep->bm_concat, BS_CONCAT_VAL_HDR_LEN);
++	/* Advance the buffer pointer by the header size */
++	buf += BS_CONCAT_VAL_HDR_LEN;
++
++	desc_count = ep->bm_concat->hdr.bDescCount;
++	/* Copy alll the wTxBytes to the buffer */
++	dwc_memcpy(buf, ep->bm_concat->wTxBytes, sizeof(uid16_t) * desc_count);
++
++	retval = BS_CONCAT_VAL_HDR_LEN + sizeof(uid16_t) * desc_count;
++	return retval;
++}
++
++/**
++ * This function reads the buffer Alignment value of an EP's buffer mode into
++ * the buffer buf
++ *
++ * @return The total number of bytes copied to the buffer or negative error code.
++ */
++static int cfi_ep_get_align_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
++				struct cfi_usb_ctrlrequest *req)
++{
++	int retval = -DWC_E_INVALID;
++	uint8_t addr;
++	cfi_ep_t *ep;
++
++	/* The Low Byte of the wValue contains a non-zero address of the endpoint */
++	addr = req->wValue & 0xFF;
++	if (addr == 0)		/* The address should be non-zero */
++		return retval;
++
++	ep = get_cfi_ep_by_addr(pcd->cfi, addr);
++	if (NULL == ep) {
++		CFI_INFO("%s: Unable to get the endpoint address(0x%02x)\n",
++			 __func__, addr);
++		return retval;
++	}
++
++	dwc_memcpy(buf, ep->bm_align, BS_ALIGN_VAL_HDR_LEN);
++	retval = BS_ALIGN_VAL_HDR_LEN;
++
++	return retval;
++}
++
++/**
++ * This function sets a new value for the specified feature
++ *
++ * @param	pcd	A pointer to the PCD object
++ *
++ * @return 0 if successful, negative error code otherwise to stall the DCE.
++ */
++static int cfi_set_feature_value(struct dwc_otg_pcd *pcd)
++{
++	int retval = -DWC_E_NOT_SUPPORTED;
++	uint16_t wIndex, wValue;
++	uint8_t bRequest;
++	struct dwc_otg_core_if *coreif;
++	cfiobject_t *cfi = pcd->cfi;
++	struct cfi_usb_ctrlrequest *ctrl_req;
++	uint8_t *buf;
++	ctrl_req = &cfi->ctrl_req;
++
++	buf = pcd->cfi->ctrl_req.data;
++
++	coreif = GET_CORE_IF(pcd);
++	bRequest = ctrl_req->bRequest;
++	wIndex = DWC_CONSTANT_CPU_TO_LE16(ctrl_req->wIndex);
++	wValue = DWC_CONSTANT_CPU_TO_LE16(ctrl_req->wValue);
++
++	/* See which feature is to be modified */
++	switch (wIndex) {
++	case FT_ID_DMA_BUFFER_SETUP:
++		/* Modify the feature */
++		if ((retval = cfi_ep_set_sg_val(buf, pcd)) < 0)
++			return retval;
++
++		/* And send this request to the gadget */
++		cfi->need_gadget_att = 1;
++		break;
++
++	case FT_ID_DMA_BUFF_ALIGN:
++		if ((retval = cfi_ep_set_alignment_val(buf, pcd)) < 0)
++			return retval;
++		cfi->need_gadget_att = 1;
++		break;
++
++	case FT_ID_DMA_CONCAT_SETUP:
++		/* Modify the feature */
++		if ((retval = cfi_ep_set_concat_val(buf, pcd)) < 0)
++			return retval;
++		cfi->need_gadget_att = 1;
++		break;
++
++	case FT_ID_DMA_CIRCULAR:
++		CFI_INFO("FT_ID_DMA_CIRCULAR\n");
++		break;
++
++	case FT_ID_THRESHOLD_SETUP:
++		CFI_INFO("FT_ID_THRESHOLD_SETUP\n");
++		break;
++
++	case FT_ID_DFIFO_DEPTH:
++		CFI_INFO("FT_ID_DFIFO_DEPTH\n");
++		break;
++
++	case FT_ID_TX_FIFO_DEPTH:
++		CFI_INFO("FT_ID_TX_FIFO_DEPTH\n");
++		if ((retval = cfi_ep_set_tx_fifo_val(buf, pcd)) < 0)
++			return retval;
++		cfi->need_gadget_att = 0;
++		break;
++
++	case FT_ID_RX_FIFO_DEPTH:
++		CFI_INFO("FT_ID_RX_FIFO_DEPTH\n");
++		if ((retval = cfi_set_rx_fifo_val(buf, pcd)) < 0)
++			return retval;
++		cfi->need_gadget_att = 0;
++		break;
++	}
++
++	return retval;
++}
++
++#endif //DWC_UTE_CFI
+diff --git a/drivers/usb/gadget/udc/hiudc/dwc_otg_cfi.h b/drivers/usb/gadget/udc/hiudc/dwc_otg_cfi.h
+new file mode 100644
+index 0000000..55fd337
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc/dwc_otg_cfi.h
+@@ -0,0 +1,320 @@
++/* ==========================================================================
++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
++ * ========================================================================== */
++
++#if !defined(__DWC_OTG_CFI_H__)
++#define __DWC_OTG_CFI_H__
++
++#include "dwc_otg_pcd.h"
++#include "dwc_cfi_common.h"
++
++/**
++ * @file
++ * This file contains the CFI related OTG PCD specific common constants,
++ * interfaces(functions and macros) and data structures.The CFI Protocol is an
++ * optional interface for internal testing purposes that a DUT may implement to
++ * support testing of configurable features.
++ *
++ */
++
++struct dwc_otg_pcd;
++struct dwc_otg_pcd_ep;
++
++/** OTG CFI Features (properties) ID constants */
++/** This is a request for all Core Features */
++#define FT_ID_DMA_MODE					0x0001
++#define FT_ID_DMA_BUFFER_SETUP			0x0002
++#define FT_ID_DMA_BUFF_ALIGN			0x0003
++#define FT_ID_DMA_CONCAT_SETUP			0x0004
++#define FT_ID_DMA_CIRCULAR				0x0005
++#define FT_ID_THRESHOLD_SETUP			0x0006
++#define FT_ID_DFIFO_DEPTH				0x0007
++#define FT_ID_TX_FIFO_DEPTH				0x0008
++#define FT_ID_RX_FIFO_DEPTH				0x0009
++
++/**********************************************************/
++#define CFI_INFO_DEF
++
++#ifdef CFI_INFO_DEF
++#define CFI_INFO(fmt...)	DWC_PRINTF("CFI: " fmt);
++#else
++#define CFI_INFO(fmt...)
++#endif
++
++#define min(x,y) ({ \
++	x < y ? x : y; })
++
++#define max(x,y) ({ \
++	x > y ? x : y; })
++
++/**
++ * Descriptor DMA SG Buffer setup structure (SG buffer). This structure is
++ * also used for setting up a buffer for Circular DDMA.
++ */
++struct _ddma_sg_buffer_setup {
++#define BS_SG_VAL_DESC_LEN	6
++	/* The OUT EP address */
++	uint8_t bOutEndpointAddress;
++	/* The IN EP address */
++	uint8_t bInEndpointAddress;
++	/* Number of bytes to put between transfer segments (must be DWORD boundaries) */
++	uint8_t bOffset;
++	/* The number of transfer segments (a DMA descriptors per each segment) */
++	uint8_t bCount;
++	/* Size (in byte) of each transfer segment */
++	uint16_t wSize;
++} __attribute__ ((packed));
++typedef struct _ddma_sg_buffer_setup ddma_sg_buffer_setup_t;
++
++/** Descriptor DMA Concatenation Buffer setup structure */
++struct _ddma_concat_buffer_setup_hdr {
++#define BS_CONCAT_VAL_HDR_LEN	4
++	/* The endpoint for which the buffer is to be set up */
++	uint8_t bEndpointAddress;
++	/* The count of descriptors to be used */
++	uint8_t bDescCount;
++	/* The total size of the transfer */
++	uint16_t wSize;
++} __attribute__ ((packed));
++typedef struct _ddma_concat_buffer_setup_hdr ddma_concat_buffer_setup_hdr_t;
++
++/** Descriptor DMA Concatenation Buffer setup structure */
++struct _ddma_concat_buffer_setup {
++	/* The SG header */
++	ddma_concat_buffer_setup_hdr_t hdr;
++
++	/* The XFER sizes pointer (allocated dynamically) */
++	uint16_t *wTxBytes;
++} __attribute__ ((packed));
++typedef struct _ddma_concat_buffer_setup ddma_concat_buffer_setup_t;
++
++/** Descriptor DMA Alignment Buffer setup structure */
++struct _ddma_align_buffer_setup {
++#define BS_ALIGN_VAL_HDR_LEN	2
++	uint8_t bEndpointAddress;
++	uint8_t bAlign;
++} __attribute__ ((packed));
++typedef struct _ddma_align_buffer_setup ddma_align_buffer_setup_t;
++
++/** Transmit FIFO Size setup structure */
++struct _tx_fifo_size_setup {
++	uint8_t bEndpointAddress;
++	uint16_t wDepth;
++} __attribute__ ((packed));
++typedef struct _tx_fifo_size_setup tx_fifo_size_setup_t;
++
++/** Transmit FIFO Size setup structure */
++struct _rx_fifo_size_setup {
++	uint16_t wDepth;
++} __attribute__ ((packed));
++typedef struct _rx_fifo_size_setup rx_fifo_size_setup_t;
++
++/**
++ * struct cfi_usb_ctrlrequest - the CFI implementation of the struct usb_ctrlrequest
++ * This structure encapsulates the standard usb_ctrlrequest and adds a pointer
++ * to the data returned in the data stage of a 3-stage Control Write requests.
++ */
++struct cfi_usb_ctrlrequest {
++	uint8_t bRequestType;
++	uint8_t bRequest;
++	uint16_t wValue;
++	uint16_t wIndex;
++	uint16_t wLength;
++	uint8_t *data;
++} UPACKED;
++
++/*---------------------------------------------------------------------------*/
++
++/**
++ * The CFI wrapper of the enabled and activated dwc_otg_pcd_ep structures.
++ * This structure is used to store the buffer setup data for any
++ * enabled endpoint in the PCD.
++ */
++struct cfi_ep {
++	/* Entry for the list container */
++	dwc_list_link_t lh;
++	/* Pointer to the active PCD endpoint structure */
++	struct dwc_otg_pcd_ep *ep;
++	/* The last descriptor in the chain of DMA descriptors of the endpoint */
++	struct dwc_otg_dma_desc *dma_desc_last;
++	/* The SG feature value */
++	ddma_sg_buffer_setup_t *bm_sg;
++	/* The Circular feature value */
++	ddma_sg_buffer_setup_t *bm_circ;
++	/* The Concatenation feature value */
++	ddma_concat_buffer_setup_t *bm_concat;
++	/* The Alignment feature value */
++	ddma_align_buffer_setup_t *bm_align;
++	/* XFER length */
++	uint32_t xfer_len;
++	/*
++	 * Count of DMA descriptors currently used.
++	 * The total should not exceed the MAX_DMA_DESCS_PER_EP value
++	 * defined in the dwc_otg_cil.h
++	 */
++	uint32_t desc_count;
++};
++typedef struct cfi_ep cfi_ep_t;
++
++typedef struct cfi_dma_buff {
++#define CFI_IN_BUF_LEN	1024
++#define CFI_OUT_BUF_LEN	1024
++	dma_addr_t addr;
++	uint8_t *buf;
++} cfi_dma_buff_t;
++
++struct cfiobject;
++
++/**
++ * This is the interface for the CFI operations.
++ *
++ * @param	ep_enable			Called when any endpoint is enabled and activated.
++ * @param	release				Called when the CFI object is released and it needs to correctly
++ *								deallocate the dynamic memory
++ * @param	ctrl_write_complete	Called when the data stage of the request is complete
++ */
++typedef struct cfi_ops {
++	int (*ep_enable) (struct cfiobject * cfi, struct dwc_otg_pcd * pcd,
++			  struct dwc_otg_pcd_ep * ep);
++	void *(*ep_alloc_buf) (struct cfiobject * cfi, struct dwc_otg_pcd * pcd,
++			       struct dwc_otg_pcd_ep * ep, dma_addr_t * dma,
++			       unsigned size, gfp_t flags);
++	void (*release) (struct cfiobject * cfi);
++	int (*ctrl_write_complete) (struct cfiobject * cfi,
++				    struct dwc_otg_pcd * pcd);
++	void (*build_descriptors) (struct cfiobject * cfi,
++				   struct dwc_otg_pcd * pcd,
++				   struct dwc_otg_pcd_ep * ep,
++				   dwc_otg_pcd_request_t * req);
++} cfi_ops_t;
++
++struct cfiobject {
++	cfi_ops_t ops;
++	struct dwc_otg_pcd *pcd;
++	struct usb_gadget *gadget;
++
++	/* Buffers used to send/receive CFI-related request data */
++	cfi_dma_buff_t buf_in;
++	cfi_dma_buff_t buf_out;
++
++	/* CFI specific Control request wrapper */
++	struct cfi_usb_ctrlrequest ctrl_req;
++
++	/* The list of active EP's in the PCD of type cfi_ep_t */
++	dwc_list_link_t active_eps;
++
++	/* This flag shall control the propagation of a specific request
++	 * to the gadget's processing routines.
++	 * 0 - no gadget handling
++	 * 1 - the gadget needs to know about this request (w/o completing a status
++	 * phase - just return a 0 to the _setup callback)
++	 */
++	uint8_t need_gadget_att;
++
++	/* Flag indicating whether the status IN phase needs to be
++	 * completed by the PCD
++	 */
++	uint8_t need_status_in_complete;
++};
++typedef struct cfiobject cfiobject_t;
++
++#define DUMP_MSG
++
++#if defined(DUMP_MSG)
++static inline void dump_msg(const u8 * buf, unsigned int length)
++{
++	unsigned int start, num, i;
++	char line[52], *p;
++
++	if (length >= 512)
++		return;
++
++	start = 0;
++	while (length > 0) {
++		num = min(length, 16u);
++		p = line;
++		for (i = 0; i < num; ++i) {
++			if (i == 8)
++				*p++ = ' ';
++			DWC_SPRINTF(p, " %02x", buf[i]);
++			p += 3;
++		}
++		*p = 0;
++		DWC_DEBUG("%6x: %s\n", start, line);
++		buf += num;
++		start += num;
++		length -= num;
++	}
++}
++#else
++static inline void dump_msg(const u8 * buf, unsigned int length)
++{
++}
++#endif
++
++/**
++ * This function returns a pointer to cfi_ep_t object with the addr address.
++ */
++static inline struct cfi_ep *get_cfi_ep_by_addr(struct cfiobject *cfi,
++						uint8_t addr)
++{
++	struct cfi_ep *pcfiep;
++	dwc_list_link_t *tmp;
++
++	DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
++		pcfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
++
++		if (pcfiep->ep->desc->bEndpointAddress == addr) {
++			return pcfiep;
++		}
++	}
++
++	return NULL;
++}
++
++/**
++ * This function returns a pointer to cfi_ep_t object that matches
++ * the dwc_otg_pcd_ep object.
++ */
++static inline struct cfi_ep *get_cfi_ep_by_pcd_ep(struct cfiobject *cfi,
++						  struct dwc_otg_pcd_ep *ep)
++{
++	struct cfi_ep *pcfiep = NULL;
++	dwc_list_link_t *tmp;
++
++	DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
++		pcfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
++		if (pcfiep->ep == ep) {
++			return pcfiep;
++		}
++	}
++	return NULL;
++}
++
++int cfi_setup(struct dwc_otg_pcd *pcd, struct cfi_usb_ctrlrequest *ctrl);
++
++#endif /* (__DWC_OTG_CFI_H__) */
+diff --git a/drivers/usb/gadget/udc/hiudc/dwc_otg_cil.c b/drivers/usb/gadget/udc/hiudc/dwc_otg_cil.c
+new file mode 100644
+index 0000000..5beb0ff
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc/dwc_otg_cil.c
+@@ -0,0 +1,7362 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_cil.c $
++ * $Revision: #203 $
++ * $Date: 2013/05/16 $
++ * $Change: 2231774 $
++ *
++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
++ * ========================================================================== */
++
++/** @file
++ *
++ * The Core Interface Layer provides basic services for accessing and
++ * managing the DWC_otg hardware. These services are used by both the
++ * Host Controller Driver and the Peripheral Controller Driver.
++ *
++ * The CIL manages the memory map for the core so that the HCD and PCD
++ * don't have to do this separately. It also handles basic tasks like
++ * reading/writing the registers and data FIFOs in the controller.
++ * Some of the data access functions provide encapsulation of several
++ * operations required to perform a task, such as writing multiple
++ * registers to start a transfer. Finally, the CIL performs basic
++ * services that are not specific to either the host or device modes
++ * of operation. These services include management of the OTG Host
++ * Negotiation Protocol (HNP) and Session Request Protocol (SRP). A
++ * Diagnostic API is also provided to allow testing of the controller
++ * hardware.
++ *
++ * The Core Interface Layer has the following requirements:
++ * - Provides basic controller operations.
++ * - Minimal use of OS services.
++ * - The OS services used will be abstracted by using inline functions
++ *	 or macros.
++ *
++ */
++
++#include "dwc_os.h"
++#include "dwc_otg_regs.h"
++#include "dwc_otg_cil.h"
++
++static int dwc_otg_setup_params(dwc_otg_core_if_t * core_if);
++
++/**
++ * This function is called to initialize the DWC_otg CSR data
++ * structures. The register addresses in the device and host
++ * structures are initialized from the base address supplied by the
++ * caller. The calling function must make the OS calls to get the
++ * base address of the DWC_otg controller registers. The core_params
++ * argument holds the parameters that specify how the core should be
++ * configured.
++ *
++ * @param reg_base_addr Base address of DWC_otg core registers
++ *
++ */
++dwc_otg_core_if_t *dwc_otg_cil_init(const uint32_t * reg_base_addr)
++{
++	dwc_otg_core_if_t *core_if = 0;
++	dwc_otg_dev_if_t *dev_if = 0;
++	dwc_otg_host_if_t *host_if = 0;
++	uint8_t *reg_base = (uint8_t *) reg_base_addr;
++	int i = 0;
++
++	DWC_DEBUGPL(DBG_CILV, "%s(%p)\n", __func__, reg_base_addr);
++
++	core_if = DWC_ALLOC(sizeof(dwc_otg_core_if_t));
++
++	if (core_if == NULL) {
++		DWC_DEBUGPL(DBG_CIL,
++			    "Allocation of dwc_otg_core_if_t failed\n");
++		return 0;
++	}
++	core_if->core_global_regs = (dwc_otg_core_global_regs_t *) reg_base;
++
++	/*
++	 * Allocate the Device Mode structures.
++	 */
++	dev_if = DWC_ALLOC(sizeof(dwc_otg_dev_if_t));
++
++	if (dev_if == NULL) {
++		DWC_DEBUGPL(DBG_CIL, "Allocation of dwc_otg_dev_if_t failed\n");
++		DWC_FREE(core_if);
++		return 0;
++	}
++
++	dev_if->dev_global_regs =
++	    (dwc_otg_device_global_regs_t *) (reg_base +
++					      DWC_DEV_GLOBAL_REG_OFFSET);
++
++	for (i = 0; i < MAX_EPS_CHANNELS; i++) {
++		dev_if->in_ep_regs[i] = (dwc_otg_dev_in_ep_regs_t *)
++		    (reg_base + DWC_DEV_IN_EP_REG_OFFSET +
++		     (i * DWC_EP_REG_OFFSET));
++
++		dev_if->out_ep_regs[i] = (dwc_otg_dev_out_ep_regs_t *)
++		    (reg_base + DWC_DEV_OUT_EP_REG_OFFSET +
++		     (i * DWC_EP_REG_OFFSET));
++		DWC_DEBUGPL(DBG_CILV, "in_ep_regs[%d]->diepctl=%p\n",
++			    i, &dev_if->in_ep_regs[i]->diepctl);
++		DWC_DEBUGPL(DBG_CILV, "out_ep_regs[%d]->doepctl=%p\n",
++			    i, &dev_if->out_ep_regs[i]->doepctl);
++	}
++
++	dev_if->speed = 0;	// unknown
++
++	core_if->dev_if = dev_if;
++
++	/*
++	 * Allocate the Host Mode structures.
++	 */
++	host_if = DWC_ALLOC(sizeof(dwc_otg_host_if_t));
++
++	if (host_if == NULL) {
++		DWC_DEBUGPL(DBG_CIL,
++			    "Allocation of dwc_otg_host_if_t failed\n");
++		DWC_FREE(dev_if);
++		DWC_FREE(core_if);
++		return 0;
++	}
++
++	host_if->host_global_regs = (dwc_otg_host_global_regs_t *)
++	    (reg_base + DWC_OTG_HOST_GLOBAL_REG_OFFSET);
++
++	host_if->hprt0 =
++	    (uint32_t *) (reg_base + DWC_OTG_HOST_PORT_REGS_OFFSET);
++
++	for (i = 0; i < MAX_EPS_CHANNELS; i++) {
++		host_if->hc_regs[i] = (dwc_otg_hc_regs_t *)
++		    (reg_base + DWC_OTG_HOST_CHAN_REGS_OFFSET +
++		     (i * DWC_OTG_CHAN_REGS_OFFSET));
++		DWC_DEBUGPL(DBG_CILV, "hc_reg[%d]->hcchar=%p\n",
++			    i, &host_if->hc_regs[i]->hcchar);
++	}
++
++	host_if->num_host_channels = MAX_EPS_CHANNELS;
++	core_if->host_if = host_if;
++
++	for (i = 0; i < MAX_EPS_CHANNELS; i++) {
++		core_if->data_fifo[i] =
++		    (uint32_t *) (reg_base + DWC_OTG_DATA_FIFO_OFFSET +
++				  (i * DWC_OTG_DATA_FIFO_SIZE));
++		DWC_DEBUGPL(DBG_CILV, "data_fifo[%d]=0x%08lx\n",
++			    i, (unsigned long)core_if->data_fifo[i]);
++	}
++
++	core_if->pcgcctl = (uint32_t *) (reg_base + DWC_OTG_PCGCCTL_OFFSET);
++
++	/* Initiate lx_state to L3 disconnected state */
++	core_if->lx_state = DWC_OTG_L3;
++	/*
++	 * Store the contents of the hardware configuration registers here for
++	 * easy access later.
++	 */
++	core_if->hwcfg1.d32 =
++	    DWC_READ_REG32(&core_if->core_global_regs->ghwcfg1);
++	core_if->hwcfg2.d32 =
++	    DWC_READ_REG32(&core_if->core_global_regs->ghwcfg2);
++	core_if->hwcfg3.d32 =
++	    DWC_READ_REG32(&core_if->core_global_regs->ghwcfg3);
++	core_if->hwcfg4.d32 =
++	    DWC_READ_REG32(&core_if->core_global_regs->ghwcfg4);
++
++	/* Force host mode to get HPTXFSIZ exact power on value */
++	{
++		gusbcfg_data_t gusbcfg = {.d32 = 0 };
++		gusbcfg.d32 =  DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
++		gusbcfg.b.force_host_mode = 1;
++		DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, gusbcfg.d32);
++		dwc_mdelay(10);
++		core_if->hptxfsiz.d32 =
++		    DWC_READ_REG32(&core_if->core_global_regs->hptxfsiz);
++		gusbcfg.d32 =  DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
++		gusbcfg.b.force_host_mode = 0;
++		DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, gusbcfg.d32);
++		dwc_mdelay(10);
++
++		gusbcfg.d32 =  DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
++		gusbcfg.b.force_dev_mode = 1;
++		DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, gusbcfg.d32);
++		dwc_mdelay(10);
++	}
++
++	DWC_DEBUGPL(DBG_CILV, "hwcfg1=%08x\n", core_if->hwcfg1.d32);
++	DWC_DEBUGPL(DBG_CILV, "hwcfg2=%08x\n", core_if->hwcfg2.d32);
++	DWC_DEBUGPL(DBG_CILV, "hwcfg3=%08x\n", core_if->hwcfg3.d32);
++	DWC_DEBUGPL(DBG_CILV, "hwcfg4=%08x\n", core_if->hwcfg4.d32);
++
++	core_if->hcfg.d32 =
++	    DWC_READ_REG32(&core_if->host_if->host_global_regs->hcfg);
++	core_if->dcfg.d32 =
++	    DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
++
++	DWC_DEBUGPL(DBG_CILV, "hcfg=%08x\n", core_if->hcfg.d32);
++	DWC_DEBUGPL(DBG_CILV, "dcfg=%08x\n", core_if->dcfg.d32);
++
++	DWC_DEBUGPL(DBG_CILV, "op_mode=%0x\n", core_if->hwcfg2.b.op_mode);
++	DWC_DEBUGPL(DBG_CILV, "arch=%0x\n", core_if->hwcfg2.b.architecture);
++	DWC_DEBUGPL(DBG_CILV, "num_dev_ep=%d\n", core_if->hwcfg2.b.num_dev_ep);
++	DWC_DEBUGPL(DBG_CILV, "num_host_chan=%d\n",
++		    core_if->hwcfg2.b.num_host_chan);
++	DWC_DEBUGPL(DBG_CILV, "nonperio_tx_q_depth=0x%0x\n",
++		    core_if->hwcfg2.b.nonperio_tx_q_depth);
++	DWC_DEBUGPL(DBG_CILV, "host_perio_tx_q_depth=0x%0x\n",
++		    core_if->hwcfg2.b.host_perio_tx_q_depth);
++	DWC_DEBUGPL(DBG_CILV, "dev_token_q_depth=0x%0x\n",
++		    core_if->hwcfg2.b.dev_token_q_depth);
++
++	DWC_DEBUGPL(DBG_CILV, "Total FIFO SZ=%d\n",
++		    core_if->hwcfg3.b.dfifo_depth);
++	DWC_DEBUGPL(DBG_CILV, "xfer_size_cntr_width=%0x\n",
++		    core_if->hwcfg3.b.xfer_size_cntr_width);
++
++	/*
++	 * Set the SRP sucess bit for FS-I2c
++	 */
++	core_if->srp_success = 0;
++	core_if->srp_timer_started = 0;
++
++	/*
++	 * Create new workqueue and init works
++	 */
++	core_if->wq_otg = DWC_WORKQ_ALLOC("dwc_otg");
++	if (core_if->wq_otg == 0) {
++		DWC_WARN("DWC_WORKQ_ALLOC failed\n");
++		DWC_FREE(host_if);
++		DWC_FREE(dev_if);
++		DWC_FREE(core_if);
++		return 0;
++	}
++
++	core_if->snpsid = DWC_READ_REG32(&core_if->core_global_regs->gsnpsid);
++
++	DWC_PRINTF("Core Release: %x.%x%x%x\n",
++		   (core_if->snpsid >> 12 & 0xF),
++		   (core_if->snpsid >> 8 & 0xF),
++		   (core_if->snpsid >> 4 & 0xF), (core_if->snpsid & 0xF));
++
++	core_if->wkp_timer = DWC_TIMER_ALLOC("Wake Up Timer",
++					     w_wakeup_detected, core_if);
++	if (core_if->wkp_timer == 0) {
++		DWC_WARN("DWC_TIMER_ALLOC failed\n");
++		DWC_FREE(host_if);
++		DWC_FREE(dev_if);
++		DWC_WORKQ_FREE(core_if->wq_otg);
++		DWC_FREE(core_if);
++		return 0;
++	}
++
++	if (dwc_otg_setup_params(core_if)) {
++		DWC_WARN("Error while setting core params\n");
++	}
++
++	core_if->hibernation_suspend = 0;
++	if (core_if->otg_ver)
++		core_if->test_mode = 0;
++
++	/** ADP initialization */
++	dwc_otg_adp_init(core_if);
++
++	return core_if;
++}
++
++/**
++ * This function frees the structures allocated by dwc_otg_cil_init().
++ *
++ * @param core_if The core interface pointer returned from
++ *		  dwc_otg_cil_init().
++ *
++ */
++void dwc_otg_cil_remove(dwc_otg_core_if_t * core_if)
++{
++	dctl_data_t dctl = {.d32 = 0 };
++	/* Disable all interrupts */
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gahbcfg, 1, 0);
++	DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, 0);
++
++	dctl.b.sftdiscon = 1;
++	if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
++		DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0,
++				 dctl.d32);
++	}
++
++	if (core_if->wq_otg) {
++		DWC_WORKQ_WAIT_WORK_DONE(core_if->wq_otg, 500);
++		DWC_WORKQ_FREE(core_if->wq_otg);
++	}
++	if (core_if->dev_if) {
++		DWC_FREE(core_if->dev_if);
++	}
++	if (core_if->host_if) {
++		DWC_FREE(core_if->host_if);
++	}
++
++	/** Remove ADP Stuff  */
++	dwc_otg_adp_remove(core_if);
++	if (core_if->core_params) {
++		DWC_FREE(core_if->core_params);
++	}
++	if (core_if->wkp_timer) {
++		DWC_TIMER_FREE(core_if->wkp_timer);
++	}
++	if (core_if->srp_timer) {
++		DWC_TIMER_FREE(core_if->srp_timer);
++	}
++	DWC_FREE(core_if);
++}
++
++/**
++ * This function enables the controller's Global Interrupt in the AHB Config
++ * register.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ */
++void dwc_otg_enable_global_interrupts(dwc_otg_core_if_t * core_if)
++{
++	gahbcfg_data_t ahbcfg = {.d32 = 0 };
++	ahbcfg.b.glblintrmsk = 1;	/* Enable interrupts */
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gahbcfg, 0, ahbcfg.d32);
++}
++
++/**
++ * This function disables the controller's Global Interrupt in the AHB Config
++ * register.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ */
++void dwc_otg_disable_global_interrupts(dwc_otg_core_if_t * core_if)
++{
++	gahbcfg_data_t ahbcfg = {.d32 = 0 };
++	ahbcfg.b.glblintrmsk = 1;	/* Disable interrupts */
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gahbcfg, ahbcfg.d32, 0);
++}
++
++/**
++ * This function initializes the commmon interrupts, used in both
++ * device and host modes.
++ *
++ * @param core_if Programming view of the DWC_otg controller
++ *
++ */
++static void dwc_otg_enable_common_interrupts(dwc_otg_core_if_t * core_if)
++{
++	dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
++	gintmsk_data_t intr_mask = {.d32 = 0 };
++
++	/* Clear any pending OTG Interrupts */
++	DWC_WRITE_REG32(&global_regs->gotgint, 0xFFFFFFFF);
++
++	/* Clear any pending interrupts */
++	DWC_WRITE_REG32(&global_regs->gintsts, 0xFFFFFFFF);
++
++	/*
++	 * Enable the interrupts in the GINTMSK.
++	 */
++	if (!core_if->core_params->otg_ver)
++	/* To avoid system hang during OTG 2.0 role switch */
++		intr_mask.b.modemismatch = 1;
++	intr_mask.b.otgintr = 1;
++
++	if (!core_if->dma_enable) {
++		intr_mask.b.rxstsqlvl = 1;
++	}
++
++	intr_mask.b.conidstschng = 1;
++	intr_mask.b.wkupintr = 1;
++	intr_mask.b.disconnect = 0;
++	intr_mask.b.usbsuspend = 1;
++	intr_mask.b.sessreqintr = 1;
++#ifdef CONFIG_USB_DWC_OTG_LPM
++	if (core_if->core_params->lpm_enable) {
++		intr_mask.b.lpmtranrcvd = 1;
++	}
++#endif
++	DWC_WRITE_REG32(&global_regs->gintmsk, intr_mask.d32);
++}
++
++/*
++ * The restore operation is modified to support Synopsys Emulated Powerdown and
++ * Hibernation. This function is for exiting from Device mode hibernation by
++ * Host Initiated Resume/Reset and Device Initiated Remote-Wakeup.
++ * @param core_if Programming view of DWC_otg controller.
++ * @param rem_wakeup - indicates whether resume is initiated by Device or Host.
++ * @param reset - indicates whether resume is initiated by Reset.
++ */
++int dwc_otg_device_hibernation_restore(dwc_otg_core_if_t * core_if,
++				       int rem_wakeup, int reset)
++{
++	gpwrdn_data_t gpwrdn = {.d32 = 0 };
++	pcgcctl_data_t pcgcctl = {.d32 = 0 };
++	dctl_data_t dctl = {.d32 = 0 };
++
++	int timeout = 2000;
++
++	if (!core_if->hibernation_suspend) {
++		DWC_PRINTF("Already exited from Hibernation\n");
++		return 1;
++	}
++
++	DWC_DEBUGPL(DBG_PCD, "%s called\n", __FUNCTION__);
++	/* Switch-on voltage to the core */
++	gpwrdn.b.pwrdnswtch = 1;
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++	dwc_udelay(10);
++
++	/* Reset core */
++	gpwrdn.d32 = 0;
++	gpwrdn.b.pwrdnrstn = 1;
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++	dwc_udelay(10);
++
++	/* Assert Restore signal */
++	gpwrdn.d32 = 0;
++	gpwrdn.b.restore = 1;
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
++	dwc_udelay(10);
++
++	/* Disable power clamps */
++	gpwrdn.d32 = 0;
++	gpwrdn.b.pwrdnclmp = 1;
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++
++	if (rem_wakeup) {
++		dwc_udelay(70);
++	}
++
++	/* Deassert Reset core */
++	gpwrdn.d32 = 0;
++	gpwrdn.b.pwrdnrstn = 1;
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
++	dwc_udelay(10);
++
++	/* Disable PMU interrupt */
++	gpwrdn.d32 = 0;
++	gpwrdn.b.pmuintsel = 1;
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++
++	/* Mask interrupts from gpwrdn */
++	gpwrdn.d32 = 0;
++	gpwrdn.b.connect_det_msk = 1;
++	gpwrdn.b.srp_det_msk = 1;
++	gpwrdn.b.disconn_det_msk = 1;
++	gpwrdn.b.rst_det_msk = 1;
++	gpwrdn.b.lnstchng_msk = 1;
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++
++	/* Indicates that we are going out from hibernation */
++	core_if->hibernation_suspend = 0;
++
++	/*
++	 * Set Restore Essential Regs bit in PCGCCTL register, restore_mode = 1
++	 * indicates restore from remote_wakeup
++	 */
++	restore_essential_regs(core_if, rem_wakeup, 0);
++
++	/*
++	 * Wait a little for seeing new value of variable hibernation_suspend if
++	 * Restore done interrupt received before polling
++	 */
++	dwc_udelay(10);
++
++	if (core_if->hibernation_suspend == 0) {
++		/*
++		 * Wait For Restore_done Interrupt. This mechanism of polling the
++		 * interrupt is introduced to avoid any possible race conditions
++		 */
++		do {
++			gintsts_data_t gintsts;
++			gintsts.d32 =
++			    DWC_READ_REG32(&core_if->core_global_regs->gintsts);
++			if (gintsts.b.restoredone) {
++				gintsts.d32 = 0;
++				gintsts.b.restoredone = 1;
++				DWC_WRITE_REG32(&core_if->core_global_regs->
++						gintsts, gintsts.d32);
++				DWC_PRINTF("Restore Done Interrupt seen\n");
++				break;
++			}
++			dwc_udelay(10);
++		} while (--timeout);
++		if (!timeout) {
++			DWC_PRINTF("Restore Done interrupt wasn't generated here\n");
++		}
++	}
++	/* Clear all pending interupts */
++	DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
++
++	/* De-assert Restore */
++	gpwrdn.d32 = 0;
++	gpwrdn.b.restore = 1;
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++	dwc_udelay(10);
++
++	if (!rem_wakeup) {
++		pcgcctl.d32 = 0;
++		pcgcctl.b.rstpdwnmodule = 1;
++		DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
++	}
++
++	/* Restore GUSBCFG and DCFG */
++	DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg,
++			core_if->gr_backup->gusbcfg_local);
++	DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg,
++			core_if->dr_backup->dcfg);
++
++	/* De-assert Wakeup Logic */
++	gpwrdn.d32 = 0;
++	gpwrdn.b.pmuactv = 1;
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++	dwc_udelay(10);
++
++	if (!rem_wakeup) {
++		/* Set Device programming done bit */
++		dctl.b.pwronprgdone = 1;
++		DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0, dctl.d32);
++	} else {
++		/* Start Remote Wakeup Signaling */
++		dctl.d32 = core_if->dr_backup->dctl;
++		dctl.b.rmtwkupsig = 1;
++		DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32);
++	}
++
++	dwc_mdelay(2);
++	/* Clear all pending interupts */
++	DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
++
++	/* Restore global registers */
++	dwc_otg_restore_global_regs(core_if);
++	/* Restore device global registers */
++	dwc_otg_restore_dev_regs(core_if, rem_wakeup);
++
++	if (rem_wakeup) {
++		dwc_mdelay(7);
++		dctl.d32 = 0;
++		dctl.b.rmtwkupsig = 1;
++		DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32, 0);
++	}
++
++	core_if->hibernation_suspend = 0;
++	/* The core will be in ON STATE */
++	core_if->lx_state = DWC_OTG_L0;
++	DWC_PRINTF("Hibernation recovery completes here\n");
++
++	return 1;
++}
++
++/*
++ * The restore operation is modified to support Synopsys Emulated Powerdown and
++ * Hibernation. This function is for exiting from Host mode hibernation by
++ * Host Initiated Resume/Reset and Device Initiated Remote-Wakeup.
++ * @param core_if Programming view of DWC_otg controller.
++ * @param rem_wakeup - indicates whether resume is initiated by Device or Host.
++ * @param reset - indicates whether resume is initiated by Reset.
++ */
++int dwc_otg_host_hibernation_restore(dwc_otg_core_if_t * core_if,
++				     int rem_wakeup, int reset)
++{
++	gpwrdn_data_t gpwrdn = {.d32 = 0 };
++	hprt0_data_t hprt0 = {.d32 = 0 };
++
++	int timeout = 2000;
++
++	DWC_DEBUGPL(DBG_HCD, "%s called\n", __FUNCTION__);
++	/* Switch-on voltage to the core */
++	gpwrdn.b.pwrdnswtch = 1;
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++	dwc_udelay(10);
++
++	/* Reset core */
++	gpwrdn.d32 = 0;
++	gpwrdn.b.pwrdnrstn = 1;
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++	dwc_udelay(10);
++
++	/* Assert Restore signal */
++	gpwrdn.d32 = 0;
++	gpwrdn.b.restore = 1;
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
++	dwc_udelay(10);
++
++	/* Disable power clamps */
++	gpwrdn.d32 = 0;
++	gpwrdn.b.pwrdnclmp = 1;
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++
++	if (!rem_wakeup) {
++		dwc_udelay(50);
++	}
++
++	/* Deassert Reset core */
++	gpwrdn.d32 = 0;
++	gpwrdn.b.pwrdnrstn = 1;
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
++	dwc_udelay(10);
++
++	/* Disable PMU interrupt */
++	gpwrdn.d32 = 0;
++	gpwrdn.b.pmuintsel = 1;
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++
++	gpwrdn.d32 = 0;
++	gpwrdn.b.connect_det_msk = 1;
++	gpwrdn.b.srp_det_msk = 1;
++	gpwrdn.b.disconn_det_msk = 1;
++	gpwrdn.b.rst_det_msk = 1;
++	gpwrdn.b.lnstchng_msk = 1;
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++
++	/* Indicates that we are going out from hibernation */
++	core_if->hibernation_suspend = 0;
++
++	/* Set Restore Essential Regs bit in PCGCCTL register */
++	restore_essential_regs(core_if, rem_wakeup, 1);
++
++	/* Wait a little for seeing new value of variable hibernation_suspend if
++	 * Restore done interrupt received before polling */
++	dwc_udelay(10);
++
++	if (core_if->hibernation_suspend == 0) {
++		/* Wait For Restore_done Interrupt. This mechanism of polling the
++		 * interrupt is introduced to avoid any possible race conditions
++		 */
++		do {
++			gintsts_data_t gintsts;
++			gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
++			if (gintsts.b.restoredone) {
++				gintsts.d32 = 0;
++				gintsts.b.restoredone = 1;
++			DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
++				DWC_DEBUGPL(DBG_HCD,"Restore Done Interrupt seen\n");
++				break;
++			}
++			dwc_udelay(10);
++		} while (--timeout);
++		if (!timeout) {
++			DWC_WARN("Restore Done interrupt wasn't generated\n");
++		}
++	}
++
++	/* Set the flag's value to 0 again after receiving restore done interrupt */
++	core_if->hibernation_suspend = 0;
++
++	/* This step is not described in functional spec but if not wait for this
++	 * delay, mismatch interrupts occurred because just after restore core is
++	 * in Device mode(gintsts.curmode == 0) */
++	dwc_mdelay(100);
++
++	/* Clear all pending interrupts */
++	DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
++
++	/* De-assert Restore */
++	gpwrdn.d32 = 0;
++	gpwrdn.b.restore = 1;
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++	dwc_udelay(10);
++
++	/* Restore GUSBCFG and HCFG */
++	DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg,
++			core_if->gr_backup->gusbcfg_local);
++	DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hcfg,
++			core_if->hr_backup->hcfg_local);
++
++	/* De-assert Wakeup Logic */
++	gpwrdn.d32 = 0;
++	gpwrdn.b.pmuactv = 1;
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++	dwc_udelay(10);
++
++	/* Start the Resume operation by programming HPRT0 */
++	hprt0.d32 = core_if->hr_backup->hprt0_local;
++	hprt0.b.prtpwr = 1;
++	hprt0.b.prtena = 0;
++	hprt0.b.prtsusp = 0;
++	DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
++
++	DWC_PRINTF("Resume Starts Now\n");
++	if (!reset) {		// Indicates it is Resume Operation
++		hprt0.d32 = core_if->hr_backup->hprt0_local;
++		hprt0.b.prtres = 1;
++		hprt0.b.prtpwr = 1;
++		hprt0.b.prtena = 0;
++		hprt0.b.prtsusp = 0;
++		DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
++
++		if (!rem_wakeup)
++			hprt0.b.prtres = 0;
++		/* Wait for Resume time and then program HPRT again */
++		dwc_mdelay(100);
++		DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
++
++	} else {		// Indicates it is Reset Operation
++		hprt0.d32 = core_if->hr_backup->hprt0_local;
++		hprt0.b.prtrst = 1;
++		hprt0.b.prtpwr = 1;
++		hprt0.b.prtena = 0;
++		hprt0.b.prtsusp = 0;
++		DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
++		/* Wait for Reset time and then program HPRT again */
++		dwc_mdelay(60);
++		hprt0.b.prtrst = 0;
++		DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
++	}
++	/* Clear all interrupt status */
++	hprt0.d32 = dwc_otg_read_hprt0(core_if);
++	hprt0.b.prtconndet = 1;
++	hprt0.b.prtenchng = 1;
++	DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
++
++	/* Clear all pending interupts */
++	DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
++
++	/* Restore global registers */
++	dwc_otg_restore_global_regs(core_if);
++	/* Restore host global registers */
++	dwc_otg_restore_host_regs(core_if, reset);
++
++	/* The core will be in ON STATE */
++	core_if->lx_state = DWC_OTG_L0;
++	DWC_PRINTF("Hibernation recovery is complete here\n");
++	return 0;
++}
++
++/** Saves some register values into system memory. */
++int dwc_otg_save_global_regs(dwc_otg_core_if_t * core_if)
++{
++	struct dwc_otg_global_regs_backup *gr;
++	int i;
++
++	gr = core_if->gr_backup;
++	if (!gr) {
++		gr = DWC_ALLOC(sizeof(*gr));
++		if (!gr) {
++			return -DWC_E_NO_MEMORY;
++		}
++		core_if->gr_backup = gr;
++	}
++
++	gr->gotgctl_local = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
++	gr->gintmsk_local = DWC_READ_REG32(&core_if->core_global_regs->gintmsk);
++	gr->gahbcfg_local = DWC_READ_REG32(&core_if->core_global_regs->gahbcfg);
++	gr->gusbcfg_local = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
++	gr->grxfsiz_local = DWC_READ_REG32(&core_if->core_global_regs->grxfsiz);
++	gr->gnptxfsiz_local = DWC_READ_REG32(&core_if->core_global_regs->gnptxfsiz);
++	gr->hptxfsiz_local = DWC_READ_REG32(&core_if->core_global_regs->hptxfsiz);
++#ifdef CONFIG_USB_DWC_OTG_LPM
++	gr->glpmcfg_local = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
++#endif
++	gr->gi2cctl_local = DWC_READ_REG32(&core_if->core_global_regs->gi2cctl);
++	gr->pcgcctl_local = DWC_READ_REG32(core_if->pcgcctl);
++	gr->gdfifocfg_local =
++	    DWC_READ_REG32(&core_if->core_global_regs->gdfifocfg);
++	for (i = 0; i < MAX_EPS_CHANNELS; i++) {
++		gr->dtxfsiz_local[i] =
++		    DWC_READ_REG32(&(core_if->core_global_regs->dtxfsiz[i]));
++	}
++
++	DWC_DEBUGPL(DBG_ANY, "===========Backing Global registers==========\n");
++	DWC_DEBUGPL(DBG_ANY, "Backed up gotgctl   = %08x\n", gr->gotgctl_local);
++	DWC_DEBUGPL(DBG_ANY, "Backed up gintmsk   = %08x\n", gr->gintmsk_local);
++	DWC_DEBUGPL(DBG_ANY, "Backed up gahbcfg   = %08x\n", gr->gahbcfg_local);
++	DWC_DEBUGPL(DBG_ANY, "Backed up gusbcfg   = %08x\n", gr->gusbcfg_local);
++	DWC_DEBUGPL(DBG_ANY, "Backed up grxfsiz   = %08x\n", gr->grxfsiz_local);
++	DWC_DEBUGPL(DBG_ANY, "Backed up gnptxfsiz = %08x\n",
++		    gr->gnptxfsiz_local);
++	DWC_DEBUGPL(DBG_ANY, "Backed up hptxfsiz  = %08x\n",
++		    gr->hptxfsiz_local);
++#ifdef CONFIG_USB_DWC_OTG_LPM
++	DWC_DEBUGPL(DBG_ANY, "Backed up glpmcfg   = %08x\n", gr->glpmcfg_local);
++#endif
++	DWC_DEBUGPL(DBG_ANY, "Backed up gi2cctl   = %08x\n", gr->gi2cctl_local);
++	DWC_DEBUGPL(DBG_ANY, "Backed up pcgcctl   = %08x\n", gr->pcgcctl_local);
++	DWC_DEBUGPL(DBG_ANY,"Backed up gdfifocfg   = %08x\n",gr->gdfifocfg_local);
++
++	return 0;
++}
++
++/** Saves GINTMSK register before setting the msk bits. */
++int dwc_otg_save_gintmsk_reg(dwc_otg_core_if_t * core_if)
++{
++	struct dwc_otg_global_regs_backup *gr;
++
++	gr = core_if->gr_backup;
++	if (!gr) {
++		gr = DWC_ALLOC(sizeof(*gr));
++		if (!gr) {
++			return -DWC_E_NO_MEMORY;
++		}
++		core_if->gr_backup = gr;
++	}
++
++	gr->gintmsk_local = DWC_READ_REG32(&core_if->core_global_regs->gintmsk);
++
++	DWC_DEBUGPL(DBG_ANY,"=============Backing GINTMSK registers============\n");
++	DWC_DEBUGPL(DBG_ANY, "Backed up gintmsk   = %08x\n", gr->gintmsk_local);
++
++	return 0;
++}
++
++int dwc_otg_save_dev_regs(dwc_otg_core_if_t * core_if)
++{
++	struct dwc_otg_dev_regs_backup *dr;
++	int i;
++
++	dr = core_if->dr_backup;
++	if (!dr) {
++		dr = DWC_ALLOC(sizeof(*dr));
++		if (!dr) {
++			return -DWC_E_NO_MEMORY;
++		}
++		core_if->dr_backup = dr;
++	}
++
++	dr->dcfg = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
++	dr->dctl = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dctl);
++	dr->daintmsk =
++	    DWC_READ_REG32(&core_if->dev_if->dev_global_regs->daintmsk);
++	dr->diepmsk =
++	    DWC_READ_REG32(&core_if->dev_if->dev_global_regs->diepmsk);
++	dr->doepmsk =
++	    DWC_READ_REG32(&core_if->dev_if->dev_global_regs->doepmsk);
++
++	for (i = 0; i < core_if->dev_if->num_in_eps; ++i) {
++		dr->diepctl[i] =
++		    DWC_READ_REG32(&core_if->dev_if->in_ep_regs[i]->diepctl);
++		dr->dieptsiz[i] =
++		    DWC_READ_REG32(&core_if->dev_if->in_ep_regs[i]->dieptsiz);
++		dr->diepdma[i] =
++		    DWC_READ_REG32(&core_if->dev_if->in_ep_regs[i]->diepdma);
++	}
++
++	DWC_DEBUGPL(DBG_ANY,
++		    "=============Backing Host registers==============\n");
++	DWC_DEBUGPL(DBG_ANY, "Backed up dcfg            = %08x\n", dr->dcfg);
++	DWC_DEBUGPL(DBG_ANY, "Backed up dctl        = %08x\n", dr->dctl);
++	DWC_DEBUGPL(DBG_ANY, "Backed up daintmsk            = %08x\n",
++		    dr->daintmsk);
++	DWC_DEBUGPL(DBG_ANY, "Backed up diepmsk        = %08x\n", dr->diepmsk);
++	DWC_DEBUGPL(DBG_ANY, "Backed up doepmsk        = %08x\n", dr->doepmsk);
++	for (i = 0; i < core_if->dev_if->num_in_eps; ++i) {
++		DWC_DEBUGPL(DBG_ANY, "Backed up diepctl[%d]        = %08x\n", i,
++			    dr->diepctl[i]);
++		DWC_DEBUGPL(DBG_ANY, "Backed up dieptsiz[%d]        = %08x\n",
++			    i, dr->dieptsiz[i]);
++		DWC_DEBUGPL(DBG_ANY, "Backed up diepdma[%d]        = %08x\n", i,
++			    dr->diepdma[i]);
++	}
++
++	return 0;
++}
++
++int dwc_otg_save_host_regs(dwc_otg_core_if_t * core_if)
++{
++	struct dwc_otg_host_regs_backup *hr;
++	int i;
++
++	hr = core_if->hr_backup;
++	if (!hr) {
++		hr = DWC_ALLOC(sizeof(*hr));
++		if (!hr) {
++			return -DWC_E_NO_MEMORY;
++		}
++		core_if->hr_backup = hr;
++	}
++
++	hr->hcfg_local =
++	    DWC_READ_REG32(&core_if->host_if->host_global_regs->hcfg);
++	hr->haintmsk_local =
++	    DWC_READ_REG32(&core_if->host_if->host_global_regs->haintmsk);
++	for (i = 0; i < dwc_otg_get_param_host_channels(core_if); ++i) {
++		hr->hcintmsk_local[i] =
++		    DWC_READ_REG32(&core_if->host_if->hc_regs[i]->hcintmsk);
++	}
++	hr->hprt0_local = DWC_READ_REG32(core_if->host_if->hprt0);
++	hr->hfir_local =
++	    DWC_READ_REG32(&core_if->host_if->host_global_regs->hfir);
++
++	DWC_DEBUGPL(DBG_ANY,
++		    "=============Backing Host registers===============\n");
++	DWC_DEBUGPL(DBG_ANY, "Backed up hcfg		= %08x\n",
++		    hr->hcfg_local);
++	DWC_DEBUGPL(DBG_ANY, "Backed up haintmsk = %08x\n", hr->haintmsk_local);
++	for (i = 0; i < dwc_otg_get_param_host_channels(core_if); ++i) {
++		DWC_DEBUGPL(DBG_ANY, "Backed up hcintmsk[%02d]=%08x\n", i,
++			    hr->hcintmsk_local[i]);
++	}
++	DWC_DEBUGPL(DBG_ANY, "Backed up hprt0           = %08x\n",
++		    hr->hprt0_local);
++	DWC_DEBUGPL(DBG_ANY, "Backed up hfir           = %08x\n",
++		    hr->hfir_local);
++
++	return 0;
++}
++
++int dwc_otg_restore_global_regs(dwc_otg_core_if_t * core_if)
++{
++	struct dwc_otg_global_regs_backup *gr;
++	int i;
++
++	gr = core_if->gr_backup;
++	if (!gr) {
++		return -DWC_E_INVALID;
++	}
++
++	DWC_WRITE_REG32(&core_if->core_global_regs->gotgctl, gr->gotgctl_local);
++	DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, gr->gintmsk_local);
++	DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, gr->gusbcfg_local);
++	DWC_WRITE_REG32(&core_if->core_global_regs->gahbcfg, gr->gahbcfg_local);
++	DWC_WRITE_REG32(&core_if->core_global_regs->grxfsiz, gr->grxfsiz_local);
++	DWC_WRITE_REG32(&core_if->core_global_regs->gnptxfsiz,
++			gr->gnptxfsiz_local);
++	DWC_WRITE_REG32(&core_if->core_global_regs->hptxfsiz,
++			gr->hptxfsiz_local);
++	DWC_WRITE_REG32(&core_if->core_global_regs->gdfifocfg,
++			gr->gdfifocfg_local);
++	for (i = 0; i < MAX_EPS_CHANNELS; i++) {
++		DWC_WRITE_REG32(&core_if->core_global_regs->dtxfsiz[i],
++				gr->dtxfsiz_local[i]);
++	}
++
++	DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
++	DWC_WRITE_REG32(core_if->host_if->hprt0, 0x0000100A);
++	DWC_WRITE_REG32(&core_if->core_global_regs->gahbcfg,
++			(gr->gahbcfg_local));
++	return 0;
++}
++
++int dwc_otg_restore_dev_regs(dwc_otg_core_if_t * core_if, int rem_wakeup)
++{
++	struct dwc_otg_dev_regs_backup *dr;
++	int i;
++
++	dr = core_if->dr_backup;
++
++	if (!dr) {
++		return -DWC_E_INVALID;
++	}
++
++	if (!rem_wakeup) {
++		DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl,
++				dr->dctl);
++	}
++
++	DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->daintmsk, dr->daintmsk);
++	DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->diepmsk, dr->diepmsk);
++	DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->doepmsk, dr->doepmsk);
++
++	for (i = 0; i < core_if->dev_if->num_in_eps; ++i) {
++		DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[i]->dieptsiz, dr->dieptsiz[i]);
++		DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[i]->diepdma, dr->diepdma[i]);
++		DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[i]->diepctl, dr->diepctl[i]);
++	}
++
++	return 0;
++}
++
++int dwc_otg_restore_host_regs(dwc_otg_core_if_t * core_if, int reset)
++{
++	struct dwc_otg_host_regs_backup *hr;
++	int i;
++	hr = core_if->hr_backup;
++
++	if (!hr) {
++		return -DWC_E_INVALID;
++	}
++
++	DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hcfg, hr->hcfg_local);
++	//if (!reset)
++	//{
++	//      DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hfir, hr->hfir_local);
++	//}
++
++	DWC_WRITE_REG32(&core_if->host_if->host_global_regs->haintmsk,
++			hr->haintmsk_local);
++	for (i = 0; i < dwc_otg_get_param_host_channels(core_if); ++i) {
++		DWC_WRITE_REG32(&core_if->host_if->hc_regs[i]->hcintmsk,
++				hr->hcintmsk_local[i]);
++	}
++
++	return 0;
++}
++
++int restore_lpm_i2c_regs(dwc_otg_core_if_t * core_if)
++{
++	struct dwc_otg_global_regs_backup *gr;
++
++	gr = core_if->gr_backup;
++
++	/* Restore values for LPM and I2C */
++#ifdef CONFIG_USB_DWC_OTG_LPM
++	DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg, gr->glpmcfg_local);
++#endif
++	DWC_WRITE_REG32(&core_if->core_global_regs->gi2cctl, gr->gi2cctl_local);
++
++	return 0;
++}
++
++int restore_essential_regs(dwc_otg_core_if_t * core_if, int rmode, int is_host)
++{
++	struct dwc_otg_global_regs_backup *gr;
++	pcgcctl_data_t pcgcctl = {.d32 = 0 };
++	gahbcfg_data_t gahbcfg = {.d32 = 0 };
++	gusbcfg_data_t gusbcfg = {.d32 = 0 };
++	gintmsk_data_t gintmsk = {.d32 = 0 };
++
++	/* Restore LPM and I2C registers */
++	restore_lpm_i2c_regs(core_if);
++
++	/* Set PCGCCTL to 0 */
++	DWC_WRITE_REG32(core_if->pcgcctl, 0x00000000);
++
++	gr = core_if->gr_backup;
++	/* Load restore values for [31:14] bits */
++	DWC_WRITE_REG32(core_if->pcgcctl,
++			((gr->pcgcctl_local & 0xffffc000) | 0x00020000));
++
++	/* Umnask global Interrupt in GAHBCFG and restore it */
++	gahbcfg.d32 = gr->gahbcfg_local;
++	gahbcfg.b.glblintrmsk = 1;
++	DWC_WRITE_REG32(&core_if->core_global_regs->gahbcfg, gahbcfg.d32);
++
++	/* Clear all pending interupts */
++	DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
++
++	/* Unmask restore done interrupt */
++	gintmsk.b.restoredone = 1;
++	DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, gintmsk.d32);
++
++	/* Restore GUSBCFG and HCFG/DCFG */
++	gusbcfg.d32 = core_if->gr_backup->gusbcfg_local;
++	DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, gusbcfg.d32);
++
++	if (is_host) {
++		hcfg_data_t hcfg = {.d32 = 0 };
++		hcfg.d32 = core_if->hr_backup->hcfg_local;
++		DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hcfg,
++				hcfg.d32);
++
++		/* Load restore values for [31:14] bits */
++		pcgcctl.d32 = gr->pcgcctl_local & 0xffffc000;
++		pcgcctl.d32 = gr->pcgcctl_local | 0x00020000;
++
++		if (rmode)
++			pcgcctl.b.restoremode = 1;
++		DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
++		dwc_udelay(10);
++
++		/* Load restore values for [31:14] bits and set EssRegRestored bit */
++		pcgcctl.d32 = gr->pcgcctl_local | 0xffffc000;
++		pcgcctl.d32 = gr->pcgcctl_local & 0xffffc000;
++		pcgcctl.b.ess_reg_restored = 1;
++		if (rmode)
++			pcgcctl.b.restoremode = 1;
++		DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
++	} else {
++		dcfg_data_t dcfg = {.d32 = 0 };
++		dcfg.d32 = core_if->dr_backup->dcfg;
++		DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg, dcfg.d32);
++
++		/* Load restore values for [31:14] bits */
++		pcgcctl.d32 = gr->pcgcctl_local & 0xffffc000;
++		pcgcctl.d32 = gr->pcgcctl_local | 0x00020000;
++		if (!rmode) {
++			pcgcctl.d32 |= 0x208;
++		}
++		DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
++		dwc_udelay(10);
++
++		/* Load restore values for [31:14] bits */
++		pcgcctl.d32 = gr->pcgcctl_local & 0xffffc000;
++		pcgcctl.d32 = gr->pcgcctl_local | 0x00020000;
++		pcgcctl.b.ess_reg_restored = 1;
++		if (!rmode)
++			pcgcctl.d32 |= 0x208;
++		DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
++	}
++
++	return 0;
++}
++
++/**
++ * Initializes the FSLSPClkSel field of the HCFG register depending on the PHY
++ * type.
++ */
++static void init_fslspclksel(dwc_otg_core_if_t * core_if)
++{
++	uint32_t val;
++	hcfg_data_t hcfg;
++
++	if (((core_if->hwcfg2.b.hs_phy_type == 2) &&
++	     (core_if->hwcfg2.b.fs_phy_type == 1) &&
++	     (core_if->core_params->ulpi_fs_ls)) ||
++	    (core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS)) {
++		/* Full speed PHY */
++		val = DWC_HCFG_48_MHZ;
++	} else {
++		/* High speed PHY running at full speed or high speed */
++		val = DWC_HCFG_30_60_MHZ;
++	}
++
++	DWC_DEBUGPL(DBG_CIL, "Initializing HCFG.FSLSPClkSel to 0x%1x\n", val);
++	hcfg.d32 = DWC_READ_REG32(&core_if->host_if->host_global_regs->hcfg);
++	hcfg.b.fslspclksel = val;
++	DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hcfg, hcfg.d32);
++}
++
++/**
++ * Initializes the DevSpd field of the DCFG register depending on the PHY type
++ * and the enumeration speed of the device.
++ */
++static void init_devspd(dwc_otg_core_if_t * core_if)
++{
++	uint32_t val;
++	dcfg_data_t dcfg;
++
++	if (((core_if->hwcfg2.b.hs_phy_type == 2) &&
++	     (core_if->hwcfg2.b.fs_phy_type == 1) &&
++	     (core_if->core_params->ulpi_fs_ls)) ||
++	    (core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS)) {
++		/* Full speed PHY */
++		val = 0x3;
++	} else if (core_if->core_params->speed == DWC_SPEED_PARAM_FULL) {
++		/* High speed PHY running at full speed */
++		val = 0x1;
++	} else {
++		/* High speed PHY running at high speed */
++		val = 0x0;
++	}
++
++	DWC_DEBUGPL(DBG_CIL, "Initializing DCFG.DevSpd to 0x%1x\n", val);
++
++	dcfg.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
++	dcfg.b.devspd = val;
++	DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg, dcfg.d32);
++}
++
++/**
++ * This function calculates the number of IN EPS
++ * using GHWCFG1 and GHWCFG2 registers values
++ *
++ * @param core_if Programming view of the DWC_otg controller
++ */
++static uint32_t calc_num_in_eps(dwc_otg_core_if_t * core_if)
++{
++	uint32_t num_in_eps = 0;
++	uint32_t num_eps = core_if->hwcfg2.b.num_dev_ep;
++	uint32_t hwcfg1 = core_if->hwcfg1.d32 >> 3;
++	uint32_t num_tx_fifos = core_if->hwcfg4.b.num_in_eps;
++	int i;
++
++	for (i = 0; i < num_eps; ++i) {
++		if (!(hwcfg1 & 0x1))
++			num_in_eps++;
++
++		hwcfg1 >>= 2;
++	}
++
++	if (core_if->hwcfg4.b.ded_fifo_en) {
++		num_in_eps =
++		    (num_in_eps > num_tx_fifos) ? num_tx_fifos : num_in_eps;
++	}
++
++	return num_in_eps;
++}
++
++/**
++ * This function calculates the number of OUT EPS
++ * using GHWCFG1 and GHWCFG2 registers values
++ *
++ * @param core_if Programming view of the DWC_otg controller
++ */
++static uint32_t calc_num_out_eps(dwc_otg_core_if_t * core_if)
++{
++	uint32_t num_out_eps = 0;
++	uint32_t num_eps = core_if->hwcfg2.b.num_dev_ep;
++	uint32_t hwcfg1 = core_if->hwcfg1.d32 >> 2;
++	int i;
++
++	for (i = 0; i < num_eps; ++i) {
++		if (!(hwcfg1 & 0x1))
++			num_out_eps++;
++
++		hwcfg1 >>= 2;
++	}
++	return num_out_eps;
++}
++
++/**
++ * This function initializes the DWC_otg controller registers and
++ * prepares the core for device mode or host mode operation.
++ *
++ * @param core_if Programming view of the DWC_otg controller
++ *
++ */
++void dwc_otg_core_init(dwc_otg_core_if_t * core_if)
++{
++	int i = 0;
++	dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
++	dwc_otg_dev_if_t *dev_if = core_if->dev_if;
++	gahbcfg_data_t ahbcfg = {.d32 = 0 };
++	gusbcfg_data_t usbcfg = {.d32 = 0 };
++	gi2cctl_data_t i2cctl = {.d32 = 0 };
++
++	DWC_DEBUGPL(DBG_CILV, "dwc_otg_core_init(%p)\n", core_if);
++
++	/* Common Initialization */
++	usbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
++
++	/* Program the ULPI External VBUS bit if needed */
++	usbcfg.b.ulpi_ext_vbus_drv =
++	    (core_if->core_params->phy_ulpi_ext_vbus ==
++	     DWC_PHY_ULPI_EXTERNAL_VBUS) ? 1 : 0;
++
++	/* Set external TS Dline pulsing */
++	usbcfg.b.term_sel_dl_pulse =
++	    (core_if->core_params->ts_dline == 1) ? 1 : 0;
++	DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
++
++	/* Reset the Controller */
++	dwc_otg_core_reset(core_if);
++
++	core_if->adp_enable = core_if->core_params->adp_supp_enable;
++	core_if->power_down = core_if->core_params->power_down;
++
++	/* Initialize parameters from Hardware configuration registers. */
++	dev_if->num_in_eps = calc_num_in_eps(core_if);
++	dev_if->num_out_eps = calc_num_out_eps(core_if);
++
++	DWC_DEBUGPL(DBG_CIL, "num_dev_perio_in_ep=%d\n",
++		    core_if->hwcfg4.b.num_dev_perio_in_ep);
++
++	for (i = 0; i < core_if->hwcfg4.b.num_dev_perio_in_ep; i++) {
++		dev_if->perio_tx_fifo_size[i] =
++		    DWC_READ_REG32(&global_regs->dtxfsiz[i]) >> 16;
++		DWC_DEBUGPL(DBG_CIL, "Periodic Tx FIFO SZ #%d=0x%0x\n",
++			    i, dev_if->perio_tx_fifo_size[i]);
++	}
++
++	for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
++		dev_if->tx_fifo_size[i] =
++		    DWC_READ_REG32(&global_regs->dtxfsiz[i]) >> 16;
++		DWC_DEBUGPL(DBG_CIL, "Tx FIFO SZ #%d=0x%0x\n",
++			    i, dev_if->tx_fifo_size[i]);
++	}
++
++	core_if->total_fifo_size = core_if->hwcfg3.b.dfifo_depth;
++	core_if->rx_fifo_size = DWC_READ_REG32(&global_regs->grxfsiz);
++	core_if->nperio_tx_fifo_size =
++	    DWC_READ_REG32(&global_regs->gnptxfsiz) >> 16;
++
++	DWC_DEBUGPL(DBG_CIL, "Total FIFO SZ=%d\n", core_if->total_fifo_size);
++	DWC_DEBUGPL(DBG_CIL, "Rx FIFO SZ=%d\n", core_if->rx_fifo_size);
++	DWC_DEBUGPL(DBG_CIL, "NP Tx FIFO SZ=%d\n",
++		    core_if->nperio_tx_fifo_size);
++
++	/* This programming sequence needs to happen in FS mode before any other
++	 * programming occurs */
++	if ((core_if->core_params->speed == DWC_SPEED_PARAM_FULL) &&
++	    (core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS)) {
++		/* If FS mode with FS PHY */
++
++		/* core_init() is now called on every switch so only call the
++		 * following for the first time through. */
++		if (!core_if->phy_init_done) {
++			core_if->phy_init_done = 1;
++			DWC_DEBUGPL(DBG_CIL, "FS_PHY detected\n");
++			usbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
++			usbcfg.b.physel = 1;
++			DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
++
++			/* Reset after a PHY select */
++			dwc_otg_core_reset(core_if);
++		}
++
++		/* Program DCFG.DevSpd or HCFG.FSLSPclkSel to 48Mhz in FS.      Also
++		 * do this on HNP Dev/Host mode switches (done in dev_init and
++		 * host_init). */
++		if (dwc_otg_is_host_mode(core_if)) {
++			init_fslspclksel(core_if);
++		} else {
++			init_devspd(core_if);
++		}
++
++		if (core_if->core_params->i2c_enable) {
++			DWC_DEBUGPL(DBG_CIL, "FS_PHY Enabling I2c\n");
++			/* Program GUSBCFG.OtgUtmifsSel to I2C */
++			usbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
++			usbcfg.b.otgutmifssel = 1;
++			DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
++
++			/* Program GI2CCTL.I2CEn */
++			i2cctl.d32 = DWC_READ_REG32(&global_regs->gi2cctl);
++			i2cctl.b.i2cdevaddr = 1;
++			i2cctl.b.i2cen = 0;
++			DWC_WRITE_REG32(&global_regs->gi2cctl, i2cctl.d32);
++			i2cctl.b.i2cen = 1;
++			DWC_WRITE_REG32(&global_regs->gi2cctl, i2cctl.d32);
++		}
++
++	} /* endif speed == DWC_SPEED_PARAM_FULL */
++	else {
++		/* High speed PHY. */
++		if (!core_if->phy_init_done) {
++			core_if->phy_init_done = 1;
++			/* HS PHY parameters.  These parameters are preserved
++			 * during soft reset so only program the first time.  Do
++			 * a soft reset immediately after setting phyif.  */
++
++			if (core_if->core_params->phy_type == 2) {
++				/* ULPI interface */
++				usbcfg.b.ulpi_utmi_sel = 1;
++				usbcfg.b.phyif = 0;
++				usbcfg.b.ddrsel =
++				    core_if->core_params->phy_ulpi_ddr;
++			} else if (core_if->core_params->phy_type == 1) {
++				/* UTMI+ interface */
++				usbcfg.b.ulpi_utmi_sel = 0;
++				if (core_if->core_params->phy_utmi_width == 16) {
++					usbcfg.b.phyif = 1;
++
++				} else {
++					usbcfg.b.phyif = 0;
++				}
++			} else {
++				DWC_ERROR("FS PHY TYPE\n");
++			}
++			DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
++			/* Reset after setting the PHY parameters */
++			dwc_otg_core_reset(core_if);
++		}
++	}
++
++	if ((core_if->hwcfg2.b.hs_phy_type == 2) &&
++	    (core_if->hwcfg2.b.fs_phy_type == 1) &&
++	    (core_if->core_params->ulpi_fs_ls)) {
++		DWC_DEBUGPL(DBG_CIL, "Setting ULPI FSLS\n");
++		usbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
++		usbcfg.b.ulpi_fsls = 1;
++		usbcfg.b.ulpi_clk_sus_m = 1;
++		DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
++	} else {
++		usbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
++		usbcfg.b.ulpi_fsls = 0;
++		usbcfg.b.ulpi_clk_sus_m = 0;
++		DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
++	}
++
++	/* Program the GAHBCFG Register. */
++	switch (core_if->hwcfg2.b.architecture) {
++
++	case DWC_SLAVE_ONLY_ARCH:
++		DWC_DEBUGPL(DBG_CIL, "Slave Only Mode\n");
++		ahbcfg.b.nptxfemplvl_txfemplvl =
++		    DWC_GAHBCFG_TXFEMPTYLVL_HALFEMPTY;
++		ahbcfg.b.ptxfemplvl = DWC_GAHBCFG_TXFEMPTYLVL_HALFEMPTY;
++		core_if->dma_enable = 0;
++		core_if->dma_desc_enable = 0;
++		break;
++
++	case DWC_EXT_DMA_ARCH:
++		DWC_DEBUGPL(DBG_CIL, "External DMA Mode\n");
++		{
++			uint8_t brst_sz = core_if->core_params->dma_burst_size;
++			ahbcfg.b.hburstlen = 0;
++			while (brst_sz > 1) {
++				ahbcfg.b.hburstlen++;
++				brst_sz >>= 1;
++			}
++		}
++		core_if->dma_enable = (core_if->core_params->dma_enable != 0);
++		core_if->dma_desc_enable =
++		    (core_if->core_params->dma_desc_enable != 0);
++		break;
++
++	case DWC_INT_DMA_ARCH:
++		DWC_DEBUGPL(DBG_CIL, "Internal DMA Mode\n");
++		/* Old value was DWC_GAHBCFG_INT_DMA_BURST_INCR - done for
++		   Host mode ISOC in issue fix - vahrama */
++		ahbcfg.b.hburstlen = DWC_GAHBCFG_INT_DMA_BURST_INCR4;
++		core_if->dma_enable = (core_if->core_params->dma_enable != 0);
++		core_if->dma_desc_enable =
++		    (core_if->core_params->dma_desc_enable != 0);
++		break;
++
++	}
++	if (core_if->dma_enable) {
++		if (core_if->dma_desc_enable) {
++			DWC_PRINTF("Using Descriptor DMA mode\n");
++		} else {
++			DWC_PRINTF("Using Buffer DMA mode\n");
++		}
++	} else {
++		DWC_PRINTF("Using Slave mode\n");
++		core_if->dma_desc_enable = 0;
++	}
++
++	if (core_if->core_params->ahb_single) {
++		ahbcfg.b.ahbsingle = 1;
++	}
++
++	ahbcfg.b.dmaenable = core_if->dma_enable;
++	DWC_WRITE_REG32(&global_regs->gahbcfg, ahbcfg.d32);
++
++	core_if->en_multiple_tx_fifo = core_if->hwcfg4.b.ded_fifo_en;
++
++	core_if->pti_enh_enable = core_if->core_params->pti_enable != 0;
++	core_if->multiproc_int_enable = core_if->core_params->mpi_enable;
++
++	/*
++	 * Program the GUSBCFG register.
++	 */
++	usbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
++
++	switch (core_if->hwcfg2.b.op_mode) {
++	case DWC_MODE_HNP_SRP_CAPABLE:
++		usbcfg.b.hnpcap = (core_if->core_params->otg_cap ==
++				   DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE);
++		usbcfg.b.srpcap = (core_if->core_params->otg_cap !=
++				   DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
++		break;
++
++	case DWC_MODE_SRP_ONLY_CAPABLE:
++		usbcfg.b.hnpcap = 0;
++		usbcfg.b.srpcap = (core_if->core_params->otg_cap !=
++				   DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
++		break;
++
++	case DWC_MODE_NO_HNP_SRP_CAPABLE:
++		usbcfg.b.hnpcap = 0;
++		usbcfg.b.srpcap = 0;
++		break;
++
++	case DWC_MODE_SRP_CAPABLE_DEVICE:
++		usbcfg.b.hnpcap = 0;
++		usbcfg.b.srpcap = (core_if->core_params->otg_cap !=
++				   DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
++		break;
++
++	case DWC_MODE_NO_SRP_CAPABLE_DEVICE:
++		usbcfg.b.hnpcap = 0;
++		usbcfg.b.srpcap = 0;
++		break;
++
++	case DWC_MODE_SRP_CAPABLE_HOST:
++		usbcfg.b.hnpcap = 0;
++		usbcfg.b.srpcap = (core_if->core_params->otg_cap !=
++				   DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
++		break;
++
++	case DWC_MODE_NO_SRP_CAPABLE_HOST:
++		usbcfg.b.hnpcap = 0;
++		usbcfg.b.srpcap = 0;
++		break;
++	}
++
++	DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
++
++#ifdef CONFIG_USB_DWC_OTG_LPM
++	if (core_if->core_params->lpm_enable) {
++		glpmcfg_data_t lpmcfg = {.d32 = 0 };
++
++		/* To enable LPM support set lpm_cap_en bit */
++		lpmcfg.b.lpm_cap_en = 1;
++
++		/* Make AppL1Res ACK */
++		lpmcfg.b.appl_resp = 1;
++
++		/* Retry 3 times */
++		lpmcfg.b.retry_count = 3;
++
++		DWC_MODIFY_REG32(&core_if->core_global_regs->glpmcfg,
++				 0, lpmcfg.d32);
++
++	}
++#endif
++	if (core_if->core_params->ic_usb_cap) {
++		gusbcfg_data_t gusbcfg = {.d32 = 0 };
++		gusbcfg.b.ic_usb_cap = 1;
++		DWC_MODIFY_REG32(&core_if->core_global_regs->gusbcfg,
++				 0, gusbcfg.d32);
++	}
++	{
++		gotgctl_data_t gotgctl = {.d32 = 0 };
++		gotgctl.b.otgver = core_if->core_params->otg_ver;
++		DWC_MODIFY_REG32(&core_if->core_global_regs->gotgctl, 0,
++				 gotgctl.d32);
++		/* Set OTG version supported */
++		core_if->otg_ver = core_if->core_params->otg_ver;
++	}
++
++	/* Enable common interrupts */
++	dwc_otg_enable_common_interrupts(core_if);
++
++	/* Do device or host intialization based on mode during PCD
++	 * and HCD initialization  */
++	if (dwc_otg_is_host_mode(core_if)) {
++		DWC_DEBUGPL(DBG_ANY, "Host Mode\n");
++		core_if->op_state = A_HOST;
++	} else {
++		DWC_DEBUGPL(DBG_ANY, "Device Mode\n");
++		core_if->op_state = B_PERIPHERAL;
++#ifdef DWC_DEVICE_ONLY
++		dwc_otg_core_dev_init(core_if);
++#endif
++	}
++}
++
++/**
++ * This function enables the Device mode interrupts.
++ *
++ * @param core_if Programming view of DWC_otg controller
++ */
++void dwc_otg_enable_device_interrupts(dwc_otg_core_if_t * core_if)
++{
++	gintmsk_data_t intr_mask = {.d32 = 0 };
++	dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
++
++	DWC_DEBUGPL(DBG_CIL, "%s()\n", __func__);
++
++	/* Disable all interrupts. */
++	DWC_WRITE_REG32(&global_regs->gintmsk, 0);
++
++	/* Clear any pending interrupts */
++	DWC_WRITE_REG32(&global_regs->gintsts, 0xFFFFFFFF);
++
++	/* Enable the common interrupts */
++	dwc_otg_enable_common_interrupts(core_if);
++
++	/* Enable interrupts */
++	intr_mask.b.usbreset = 1;
++	intr_mask.b.enumdone = 1;
++	/* Disable Disconnect interrupt in Device mode */
++	intr_mask.b.disconnect = 0;
++
++	if (!core_if->multiproc_int_enable) {
++		intr_mask.b.inepintr = 1;
++		intr_mask.b.outepintr = 1;
++	}
++
++	intr_mask.b.erlysuspend = 1;
++
++	if (core_if->en_multiple_tx_fifo == 0) {
++		intr_mask.b.epmismatch = 1;
++	}
++
++	//intr_mask.b.incomplisoout = 1;
++	if (!core_if->dma_desc_enable)
++		intr_mask.b.incomplisoin = 1;
++
++/* Enable the ignore frame number for ISOC xfers - MAS */
++/* Disable to support high bandwith ISOC transfers - manukz */
++#if 0
++#ifdef DWC_UTE_PER_IO
++	if (core_if->dma_enable) {
++		if (core_if->dma_desc_enable) {
++			dctl_data_t dctl1 = {.d32 = 0 };
++			dctl1.b.ifrmnum = 1;
++			DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
++					 dctl, 0, dctl1.d32);
++			DWC_DEBUG("----Enabled Ignore frame number (0x%08x)",
++				  DWC_READ_REG32(&core_if->dev_if->
++						 dev_global_regs->dctl));
++		}
++	}
++#endif
++#endif
++#ifdef DWC_EN_ISOC
++	if (core_if->dma_enable) {
++		if (core_if->dma_desc_enable == 0) {
++			if (core_if->pti_enh_enable) {
++				dctl_data_t dctl = {.d32 = 0 };
++				dctl.b.ifrmnum = 1;
++				DWC_MODIFY_REG32(&core_if->
++						 dev_if->dev_global_regs->dctl,
++						 0, dctl.d32);
++			} else {
++				intr_mask.b.incomplisoin = 1;
++				intr_mask.b.incomplisoout = 1;
++			}
++		}
++	} else {
++		intr_mask.b.incomplisoin = 1;
++		intr_mask.b.incomplisoout = 1;
++	}
++#endif /* DWC_EN_ISOC */
++
++	/** @todo NGS: Should this be a module parameter? */
++#ifdef USE_PERIODIC_EP
++	intr_mask.b.isooutdrop = 1;
++	intr_mask.b.eopframe = 1;
++	intr_mask.b.incomplisoin = 1;
++	intr_mask.b.incomplisoout = 1;
++#endif
++
++	DWC_MODIFY_REG32(&global_regs->gintmsk, intr_mask.d32, intr_mask.d32);
++
++	DWC_DEBUGPL(DBG_CIL, "%s() gintmsk=%0x\n", __func__,
++		    DWC_READ_REG32(&global_regs->gintmsk));
++}
++
++/**
++ * This function initializes the DWC_otg controller registers for
++ * device mode.
++ *
++ * @param core_if Programming view of DWC_otg controller
++ *
++ */
++void dwc_otg_core_dev_init(dwc_otg_core_if_t * core_if)
++{
++	int i;
++	dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
++	dwc_otg_dev_if_t *dev_if = core_if->dev_if;
++	dwc_otg_core_params_t *params = core_if->core_params;
++	dcfg_data_t dcfg = {.d32 = 0 };
++	depctl_data_t diepctl = {.d32 = 0 };
++	grstctl_t resetctl = {.d32 = 0 };
++	uint32_t rx_fifo_size;
++	fifosize_data_t nptxfifosize;
++	fifosize_data_t txfifosize;
++	dthrctl_data_t dthrctl;
++	fifosize_data_t ptxfifosize;
++	uint16_t rxfsiz, nptxfsiz;
++	gdfifocfg_data_t gdfifocfg = {.d32 = 0 };
++	hwcfg3_data_t hwcfg3 = {.d32 = 0 };
++	gotgctl_data_t gotgctl = {.d32 = 0 };
++
++	/* Restart the Phy Clock */
++	pcgcctl_data_t pcgcctl = {.d32 = 0 };
++	/* Restart the Phy Clock */
++	pcgcctl.b.stoppclk = 1;
++	DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
++	dwc_udelay(10);
++
++	/* Device configuration register */
++	init_devspd(core_if);
++	dcfg.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dcfg);
++	dcfg.b.descdma = (core_if->dma_desc_enable) ? 1 : 0;
++	dcfg.b.perfrint = DWC_DCFG_FRAME_INTERVAL_80;
++	/* Enable Device OUT NAK in case of DDMA mode */
++	if (core_if->core_params->dev_out_nak) {
++		dcfg.b.endevoutnak = 1;
++	}
++
++	if (core_if->core_params->cont_on_bna) {
++		dctl_data_t dctl = {.d32 = 0 };
++		dctl.b.encontonbna = 1;
++		DWC_MODIFY_REG32(&dev_if->dev_global_regs->dctl, 0, dctl.d32);
++	}
++	/** should be done before every reset */
++	if (core_if->otg_ver) {
++		core_if->otg_sts = 0;
++		gotgctl.b.devhnpen = 1;
++		DWC_MODIFY_REG32(&core_if->core_global_regs->gotgctl, gotgctl.d32, 0);
++	}
++
++	DWC_WRITE_REG32(&dev_if->dev_global_regs->dcfg, dcfg.d32);
++
++	/* Configure data FIFO sizes */
++	if (core_if->hwcfg2.b.dynamic_fifo && params->enable_dynamic_fifo) {
++		DWC_DEBUGPL(DBG_CIL, "Total FIFO Size=%d\n",
++			    core_if->total_fifo_size);
++		DWC_DEBUGPL(DBG_CIL, "Rx FIFO Size=%d\n",
++			    params->dev_rx_fifo_size);
++		DWC_DEBUGPL(DBG_CIL, "NP Tx FIFO Size=%d\n",
++			    params->dev_nperio_tx_fifo_size);
++
++		/* Rx FIFO */
++		DWC_DEBUGPL(DBG_CIL, "initial grxfsiz=%08x\n",
++			    DWC_READ_REG32(&global_regs->grxfsiz));
++
++#ifdef DWC_UTE_CFI
++		core_if->pwron_rxfsiz = DWC_READ_REG32(&global_regs->grxfsiz);
++		core_if->init_rxfsiz = params->dev_rx_fifo_size;
++#endif
++		rx_fifo_size = params->dev_rx_fifo_size;
++		DWC_WRITE_REG32(&global_regs->grxfsiz, rx_fifo_size);
++
++		DWC_DEBUGPL(DBG_CIL, "new grxfsiz=%08x\n",
++			    DWC_READ_REG32(&global_regs->grxfsiz));
++
++		/** Set Periodic Tx FIFO Mask all bits 0 */
++		core_if->p_tx_msk = 0;
++
++		/** Set Tx FIFO Mask all bits 0 */
++		core_if->tx_msk = 0;
++
++		if (core_if->en_multiple_tx_fifo == 0) {
++			/* Non-periodic Tx FIFO */
++			DWC_DEBUGPL(DBG_CIL, "initial gnptxfsiz=%08x\n",
++				    DWC_READ_REG32(&global_regs->gnptxfsiz));
++
++			nptxfifosize.b.depth = params->dev_nperio_tx_fifo_size;
++			nptxfifosize.b.startaddr = params->dev_rx_fifo_size;
++
++			DWC_WRITE_REG32(&global_regs->gnptxfsiz,
++					nptxfifosize.d32);
++
++			DWC_DEBUGPL(DBG_CIL, "new gnptxfsiz=%08x\n",
++				    DWC_READ_REG32(&global_regs->gnptxfsiz));
++
++			/**@todo NGS: Fix Periodic FIFO Sizing! */
++			/*
++			 * Periodic Tx FIFOs These FIFOs are numbered from 1 to 15.
++			 * Indexes of the FIFO size module parameters in the
++			 * dev_perio_tx_fifo_size array and the FIFO size registers in
++			 * the dptxfsiz array run from 0 to 14.
++			 */
++			/** @todo Finish debug of this */
++			ptxfifosize.b.startaddr =
++			    nptxfifosize.b.startaddr + nptxfifosize.b.depth;
++			for (i = 0; i < core_if->hwcfg4.b.num_dev_perio_in_ep; i++) {
++				ptxfifosize.b.depth =
++				    params->dev_perio_tx_fifo_size[i];
++				DWC_DEBUGPL(DBG_CIL,
++					    "initial dtxfsiz[%d]=%08x\n", i,
++					    DWC_READ_REG32(&global_regs->dtxfsiz
++							   [i]));
++				DWC_WRITE_REG32(&global_regs->dtxfsiz[i],
++						ptxfifosize.d32);
++				DWC_DEBUGPL(DBG_CIL, "new dtxfsiz[%d]=%08x\n",
++					    i,
++					    DWC_READ_REG32(&global_regs->dtxfsiz
++							   [i]));
++				ptxfifosize.b.startaddr += ptxfifosize.b.depth;
++			}
++		} else {
++			/*
++			 * Tx FIFOs These FIFOs are numbered from 1 to 15.
++			 * Indexes of the FIFO size module parameters in the
++			 * dev_tx_fifo_size array and the FIFO size registers in
++			 * the dtxfsiz array run from 0 to 14.
++			 */
++
++			/* Non-periodic Tx FIFO */
++			DWC_DEBUGPL(DBG_CIL, "initial gnptxfsiz=%08x\n",
++				    DWC_READ_REG32(&global_regs->gnptxfsiz));
++
++#ifdef DWC_UTE_CFI
++			core_if->pwron_gnptxfsiz =
++			    (DWC_READ_REG32(&global_regs->gnptxfsiz) >> 16);
++			core_if->init_gnptxfsiz =
++			    params->dev_nperio_tx_fifo_size;
++#endif
++			nptxfifosize.b.depth = params->dev_nperio_tx_fifo_size;
++			nptxfifosize.b.startaddr = params->dev_rx_fifo_size;
++
++			DWC_WRITE_REG32(&global_regs->gnptxfsiz,
++					nptxfifosize.d32);
++
++			DWC_DEBUGPL(DBG_CIL, "new gnptxfsiz=%08x\n",
++				    DWC_READ_REG32(&global_regs->gnptxfsiz));
++
++			txfifosize.b.startaddr =
++			    nptxfifosize.b.startaddr + nptxfifosize.b.depth;
++
++			for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
++
++				txfifosize.b.depth =
++				    params->dev_tx_fifo_size[i];
++
++				DWC_DEBUGPL(DBG_CIL,
++					    "initial dtxfsiz[%d]=%08x\n",
++					    i,
++					    DWC_READ_REG32(&global_regs->dtxfsiz
++							   [i]));
++
++#ifdef DWC_UTE_CFI
++				core_if->pwron_txfsiz[i] =
++				    (DWC_READ_REG32
++				     (&global_regs->dtxfsiz[i]) >> 16);
++				core_if->init_txfsiz[i] =
++				    params->dev_tx_fifo_size[i];
++#endif
++				DWC_WRITE_REG32(&global_regs->dtxfsiz[i],
++						txfifosize.d32);
++
++				DWC_DEBUGPL(DBG_CIL,
++					    "new dtxfsiz[%d]=%08x\n",
++					    i,
++					    DWC_READ_REG32(&global_regs->dtxfsiz
++							   [i]));
++
++				txfifosize.b.startaddr += txfifosize.b.depth;
++			}
++
++			/* Calculating DFIFOCFG for Device mode to include RxFIFO and NPTXFIFO
++			 * Before 3.00a EpInfoBase was being configured in ep enable/disable
++			 * routine as well. Starting from 3.00a it will be set to the end of
++			 * allocated FIFO space here due to ep 0 OUT always keeping enabled
++			 */
++			gdfifocfg.d32 = DWC_READ_REG32(&global_regs->gdfifocfg);
++			hwcfg3.d32 = DWC_READ_REG32(&global_regs->ghwcfg3);
++			gdfifocfg.b.gdfifocfg = (DWC_READ_REG32(&global_regs->ghwcfg3) >> 16);
++			DWC_WRITE_REG32(&global_regs->gdfifocfg, gdfifocfg.d32);
++			if (core_if->snpsid <= OTG_CORE_REV_2_94a) {
++				rxfsiz = (DWC_READ_REG32(&global_regs->grxfsiz) & 0x0000ffff);
++				nptxfsiz = (DWC_READ_REG32(&global_regs->gnptxfsiz) >> 16);
++				gdfifocfg.b.epinfobase = rxfsiz + nptxfsiz;
++			} else {
++				gdfifocfg.b.epinfobase = txfifosize.b.startaddr;
++			}
++			DWC_WRITE_REG32(&global_regs->gdfifocfg, gdfifocfg.d32);
++		}
++	}
++
++	/* Flush the FIFOs */
++	dwc_otg_flush_tx_fifo(core_if, 0x10);	/* all Tx FIFOs */
++	dwc_otg_flush_rx_fifo(core_if);
++
++	/* Flush the Learning Queue. */
++	resetctl.b.intknqflsh = 1;
++	DWC_WRITE_REG32(&core_if->core_global_regs->grstctl, resetctl.d32);
++
++	if (!core_if->core_params->en_multiple_tx_fifo && core_if->dma_enable) {
++		core_if->start_predict = 0;
++		for (i = 0; i <= core_if->dev_if->num_in_eps; ++i) {
++			core_if->nextep_seq[i] = 0xff;	// 0xff - EP not active
++		}
++		core_if->nextep_seq[0] = 0;
++		core_if->first_in_nextep_seq = 0;
++		diepctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[0]->diepctl);
++		diepctl.b.nextep = 0;
++		DWC_WRITE_REG32(&dev_if->in_ep_regs[0]->diepctl, diepctl.d32);
++
++		/* Update IN Endpoint Mismatch Count by active IN NP EP count + 1 */
++		dcfg.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dcfg);
++		dcfg.b.epmscnt = 2;
++		DWC_WRITE_REG32(&dev_if->dev_global_regs->dcfg, dcfg.d32);
++
++		DWC_DEBUGPL(DBG_CILV,
++			    "%s first_in_nextep_seq= %2d; nextep_seq[]:\n",
++			    __func__, core_if->first_in_nextep_seq);
++		for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
++			DWC_DEBUGPL(DBG_CILV, "%2d ", core_if->nextep_seq[i]);
++		}
++		DWC_DEBUGPL(DBG_CILV, "\n");
++	}
++
++	/* Clear all pending Device Interrupts */
++	/** @todo - if the condition needed to be checked
++	 *  or in any case all pending interrutps should be cleared?
++     */
++	if (core_if->multiproc_int_enable) {
++		for (i = 0; i < core_if->dev_if->num_in_eps; ++i) {
++			DWC_WRITE_REG32(&dev_if->dev_global_regs->
++					diepeachintmsk[i], 0);
++		}
++
++		for (i = 0; i < core_if->dev_if->num_out_eps; ++i) {
++			DWC_WRITE_REG32(&dev_if->dev_global_regs->
++					doepeachintmsk[i], 0);
++		}
++
++		DWC_WRITE_REG32(&dev_if->dev_global_regs->deachint, 0xFFFFFFFF);
++		DWC_WRITE_REG32(&dev_if->dev_global_regs->deachintmsk, 0);
++	} else {
++		DWC_WRITE_REG32(&dev_if->dev_global_regs->diepmsk, 0);
++		DWC_WRITE_REG32(&dev_if->dev_global_regs->doepmsk, 0);
++		DWC_WRITE_REG32(&dev_if->dev_global_regs->daint, 0xFFFFFFFF);
++		DWC_WRITE_REG32(&dev_if->dev_global_regs->daintmsk, 0);
++	}
++
++	for (i = 0; i <= dev_if->num_in_eps; i++) {
++		depctl_data_t depctl;
++		depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
++		if (depctl.b.epena) {
++			depctl.d32 = 0;
++			depctl.b.epdis = 1;
++			depctl.b.snak = 1;
++		} else {
++			depctl.d32 = 0;
++			depctl.b.snak = 1;
++		}
++
++		DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepctl, depctl.d32);
++
++		DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->dieptsiz, 0);
++		DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepdma, 0);
++		DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepint, 0xFF);
++	}
++
++	for (i = 1; i <= dev_if->num_out_eps; i++) {
++		depctl_data_t depctl;
++		depctl.d32 = DWC_READ_REG32(&dev_if->out_ep_regs[i]->doepctl);
++		if (depctl.b.epena) {
++			int j = 0;
++			dctl_data_t dctl = {.d32 = 0 };
++			gintmsk_data_t gintsts = {.d32 = 0 };
++			doepint_data_t doepint = {.d32 = 0 };
++			device_grxsts_data_t status;
++			dctl.b.sgoutnak = 1;
++			DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0, dctl.d32);
++			if (!core_if->dma_enable) {
++				do {
++					j++;
++					dwc_udelay(10);
++					gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
++					if (j == 100000) {
++						DWC_ERROR("SNAK is not set during 10s\n");
++						break;
++					}
++				} while (!gintsts.b.rxstsqlvl);
++				status.d32 = DWC_READ_REG32(&global_regs->grxstsp);
++				if (status.b.pktsts == DWC_DSTS_GOUT_NAK)
++					DWC_DEBUGPL(DBG_PCDV, "Global OUT NAK\n");
++				gintsts.d32 = 0;
++				gintsts.b.rxstsqlvl = 1;
++				DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
++			}
++			j = 0;
++			do {
++				j++;
++				dwc_udelay(10);
++				gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
++				if (j == 100000) {
++					DWC_ERROR("SNAK is not set during 10s\n");
++					break;
++				}
++			} while (!gintsts.b.goutnakeff);
++			gintsts.d32 = 0;
++			gintsts.b.goutnakeff = 1;
++			DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
++
++			depctl.d32 = 0;
++			depctl.b.epdis = 1;
++			depctl.b.snak = 1;
++			j = 0;
++			DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[i]->doepctl, depctl.d32);
++			do {
++				dwc_udelay(10);
++				doepint.d32 = DWC_READ_REG32(&core_if->dev_if->
++					out_ep_regs[i]->doepint);
++				if (j == 100000) {
++					DWC_ERROR("EPDIS was not set during 10s\n");
++					break;
++				}
++			} while (!doepint.b.epdisabled);
++
++			doepint.b.epdisabled = 1;
++			DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[i]->doepint, doepint.d32);
++
++			dctl.d32 = 0;
++			dctl.b.cgoutnak = 1;
++			DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0, dctl.d32);
++		} else {
++			depctl.d32 = 0;
++			depctl.b.snak = 1;
++		}
++
++		DWC_WRITE_REG32(&dev_if->out_ep_regs[i]->doepctl, depctl.d32);
++		DWC_WRITE_REG32(&dev_if->out_ep_regs[i]->doeptsiz, 0);
++		DWC_WRITE_REG32(&dev_if->out_ep_regs[i]->doepdma, 0);
++		DWC_WRITE_REG32(&dev_if->out_ep_regs[i]->doepint, 0xFF);
++	}
++
++	if (core_if->en_multiple_tx_fifo && core_if->dma_enable) {
++		dev_if->non_iso_tx_thr_en = params->thr_ctl & 0x1;
++		dev_if->iso_tx_thr_en = (params->thr_ctl >> 1) & 0x1;
++		dev_if->rx_thr_en = (params->thr_ctl >> 2) & 0x1;
++
++		dev_if->rx_thr_length = params->rx_thr_length;
++		dev_if->tx_thr_length = params->tx_thr_length;
++
++		dev_if->setup_desc_index = 0;
++
++		dthrctl.d32 = 0;
++		dthrctl.b.non_iso_thr_en = dev_if->non_iso_tx_thr_en;
++		dthrctl.b.iso_thr_en = dev_if->iso_tx_thr_en;
++		dthrctl.b.tx_thr_len = dev_if->tx_thr_length;
++		dthrctl.b.rx_thr_en = dev_if->rx_thr_en;
++		dthrctl.b.rx_thr_len = dev_if->rx_thr_length;
++		dthrctl.b.ahb_thr_ratio = params->ahb_thr_ratio;
++
++		DWC_WRITE_REG32(&dev_if->dev_global_regs->dtknqr3_dthrctl,
++				dthrctl.d32);
++
++		DWC_DEBUGPL(DBG_CIL,
++			    "Non ISO Tx Thr - %d\nISO Tx Thr - %d\nRx Thr - %d\nTx Thr Len - %d\nRx Thr Len - %d\n",
++			    dthrctl.b.non_iso_thr_en, dthrctl.b.iso_thr_en,
++			    dthrctl.b.rx_thr_en, dthrctl.b.tx_thr_len,
++			    dthrctl.b.rx_thr_len);
++
++	}
++
++	dwc_otg_enable_device_interrupts(core_if);
++
++	{
++		diepmsk_data_t msk = {.d32 = 0 };
++		msk.b.txfifoundrn = 1;
++		if (core_if->multiproc_int_enable) {
++			DWC_MODIFY_REG32(&dev_if->dev_global_regs->
++					 diepeachintmsk[0], msk.d32, msk.d32);
++		} else {
++			DWC_MODIFY_REG32(&dev_if->dev_global_regs->diepmsk,
++					 msk.d32, msk.d32);
++		}
++	}
++
++	if (core_if->multiproc_int_enable) {
++		/* Set NAK on Babble */
++		dctl_data_t dctl = {.d32 = 0 };
++		dctl.b.nakonbble = 1;
++		DWC_MODIFY_REG32(&dev_if->dev_global_regs->dctl, 0, dctl.d32);
++	}
++
++	if (core_if->snpsid >= OTG_CORE_REV_2_94a) {
++		dctl_data_t dctl = {.d32 = 0 };
++		dctl.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dctl);
++		dctl.b.sftdiscon = 0;
++		DWC_WRITE_REG32(&dev_if->dev_global_regs->dctl, dctl.d32);
++	}
++}
++
++/**
++ * This function enables the Host mode interrupts.
++ *
++ * @param core_if Programming view of DWC_otg controller
++ */
++void dwc_otg_enable_host_interrupts(dwc_otg_core_if_t * core_if)
++{
++	dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
++	gintmsk_data_t intr_mask = {.d32 = 0 };
++
++	DWC_DEBUGPL(DBG_CIL, "%s()\n", __func__);
++
++	/* Disable all interrupts. */
++	DWC_WRITE_REG32(&global_regs->gintmsk, 0);
++
++	/* Clear any pending interrupts. */
++	DWC_WRITE_REG32(&global_regs->gintsts, 0xFFFFFFFF);
++
++	/* Enable the common interrupts */
++	dwc_otg_enable_common_interrupts(core_if);
++
++	/*
++	 * Enable host mode interrupts without disturbing common
++	 * interrupts.
++	 */
++
++	intr_mask.b.disconnect = 1;
++	intr_mask.b.portintr = 1;
++	intr_mask.b.hcintr = 1;
++
++	DWC_MODIFY_REG32(&global_regs->gintmsk, intr_mask.d32, intr_mask.d32);
++}
++
++/**
++ * This function disables the Host Mode interrupts.
++ *
++ * @param core_if Programming view of DWC_otg controller
++ */
++void dwc_otg_disable_host_interrupts(dwc_otg_core_if_t * core_if)
++{
++	dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
++	gintmsk_data_t intr_mask = {.d32 = 0 };
++
++	DWC_DEBUGPL(DBG_CILV, "%s()\n", __func__);
++
++	/*
++	 * Disable host mode interrupts without disturbing common
++	 * interrupts.
++	 */
++	intr_mask.b.sofintr = 1;
++	intr_mask.b.portintr = 1;
++	intr_mask.b.hcintr = 1;
++	intr_mask.b.ptxfempty = 1;
++	intr_mask.b.nptxfempty = 1;
++
++	DWC_MODIFY_REG32(&global_regs->gintmsk, intr_mask.d32, 0);
++}
++
++/**
++ * This function initializes the DWC_otg controller registers for
++ * host mode.
++ *
++ * This function flushes the Tx and Rx FIFOs and it flushes any entries in the
++ * request queues. Host channels are reset to ensure that they are ready for
++ * performing transfers.
++ *
++ * @param core_if Programming view of DWC_otg controller
++ *
++ */
++void dwc_otg_core_host_init(dwc_otg_core_if_t * core_if)
++{
++	dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
++	dwc_otg_host_if_t *host_if = core_if->host_if;
++	dwc_otg_core_params_t *params = core_if->core_params;
++	hprt0_data_t hprt0 = {.d32 = 0 };
++	fifosize_data_t nptxfifosize;
++	fifosize_data_t ptxfifosize;
++	uint16_t rxfsiz, nptxfsiz, hptxfsiz;
++	gdfifocfg_data_t gdfifocfg = {.d32 = 0 };
++	int i;
++	hcchar_data_t hcchar;
++	hcfg_data_t hcfg;
++	hfir_data_t hfir;
++	dwc_otg_hc_regs_t *hc_regs;
++	int num_channels;
++	gotgctl_data_t gotgctl = {.d32 = 0 };
++	pcgcctl_data_t pcgcctl = {.d32 = 0 };
++
++	DWC_DEBUGPL(DBG_CILV, "%s(%p)\n", __func__, core_if);
++
++	/* Restart the Phy Clock */
++	pcgcctl.b.stoppclk = 1;
++	DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
++	dwc_udelay(10);
++
++	if ((core_if->otg_ver == 1) && (core_if->op_state == A_HOST)) {
++		DWC_PRINTF("Init: Port Power? op_state=%d\n", core_if->op_state);
++		hprt0.d32 = dwc_otg_read_hprt0(core_if);
++		DWC_PRINTF("Init: Power Port (%d)\n", hprt0.b.prtpwr);
++		if (hprt0.b.prtpwr == 0) {
++			hprt0.b.prtpwr = 1;
++			DWC_WRITE_REG32(host_if->hprt0, hprt0.d32);
++		}
++	}
++
++	/* Initialize Host Configuration Register */
++	init_fslspclksel(core_if);
++	if (core_if->core_params->speed == DWC_SPEED_PARAM_FULL) {
++		hcfg.d32 = DWC_READ_REG32(&host_if->host_global_regs->hcfg);
++		hcfg.b.fslssupp = 1;
++		DWC_WRITE_REG32(&host_if->host_global_regs->hcfg, hcfg.d32);
++
++	}
++
++	/* This bit allows dynamic reloading of the HFIR register
++	 * during runtime. This bit needs to be programmed during
++	 * initial configuration and its value must not be changed
++	 * during runtime.*/
++	if (core_if->core_params->reload_ctl == 1) {
++		hfir.d32 = DWC_READ_REG32(&host_if->host_global_regs->hfir);
++		hfir.b.hfirrldctrl = 1;
++		DWC_WRITE_REG32(&host_if->host_global_regs->hfir, hfir.d32);
++	}
++
++	if (core_if->core_params->dma_desc_enable) {
++		uint8_t op_mode = core_if->hwcfg2.b.op_mode;
++		if (!
++		    (core_if->hwcfg4.b.desc_dma
++		     && (core_if->snpsid >= OTG_CORE_REV_2_90a)
++		     && ((op_mode == DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG)
++			 || (op_mode == DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG)
++			 || (op_mode ==
++			     DWC_HWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE_OTG)
++			 || (op_mode == DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST)
++			 || (op_mode ==
++			     DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST)))) {
++
++			DWC_ERROR("Host can't operate in Descriptor DMA mode.\n"
++				  "Either core version is below 2.90a or "
++				  "GHWCFG2, GHWCFG4 registers' values do not allow Descriptor DMA in host mode.\n"
++				  "To run the driver in Buffer DMA host mode set dma_desc_enable "
++				  "module parameter to 0.\n");
++			return;
++		}
++		hcfg.d32 = DWC_READ_REG32(&host_if->host_global_regs->hcfg);
++		hcfg.b.descdma = 1;
++		DWC_WRITE_REG32(&host_if->host_global_regs->hcfg, hcfg.d32);
++	}
++
++	/* Configure data FIFO sizes */
++	if (core_if->hwcfg2.b.dynamic_fifo && params->enable_dynamic_fifo) {
++		DWC_DEBUGPL(DBG_CIL, "Total FIFO Size=%d\n",
++			    core_if->total_fifo_size);
++		DWC_DEBUGPL(DBG_CIL, "Rx FIFO Size=%d\n",
++			    params->host_rx_fifo_size);
++		DWC_DEBUGPL(DBG_CIL, "NP Tx FIFO Size=%d\n",
++			    params->host_nperio_tx_fifo_size);
++		DWC_DEBUGPL(DBG_CIL, "P Tx FIFO Size=%d\n",
++			    params->host_perio_tx_fifo_size);
++
++		/* Rx FIFO */
++		DWC_DEBUGPL(DBG_CIL, "initial grxfsiz=%08x\n",
++			    DWC_READ_REG32(&global_regs->grxfsiz));
++		DWC_WRITE_REG32(&global_regs->grxfsiz,
++				params->host_rx_fifo_size);
++		DWC_DEBUGPL(DBG_CIL, "new grxfsiz=%08x\n",
++			    DWC_READ_REG32(&global_regs->grxfsiz));
++
++		/* Non-periodic Tx FIFO */
++		DWC_DEBUGPL(DBG_CIL, "initial gnptxfsiz=%08x\n",
++			    DWC_READ_REG32(&global_regs->gnptxfsiz));
++		nptxfifosize.b.depth = params->host_nperio_tx_fifo_size;
++		nptxfifosize.b.startaddr = params->host_rx_fifo_size;
++		DWC_WRITE_REG32(&global_regs->gnptxfsiz, nptxfifosize.d32);
++		DWC_DEBUGPL(DBG_CIL, "new gnptxfsiz=%08x\n",
++			    DWC_READ_REG32(&global_regs->gnptxfsiz));
++
++		/* Periodic Tx FIFO */
++		DWC_DEBUGPL(DBG_CIL, "initial hptxfsiz=%08x\n",
++			    DWC_READ_REG32(&global_regs->hptxfsiz));
++		ptxfifosize.b.depth = params->host_perio_tx_fifo_size;
++		ptxfifosize.b.startaddr =
++		    nptxfifosize.b.startaddr + nptxfifosize.b.depth;
++		DWC_WRITE_REG32(&global_regs->hptxfsiz, ptxfifosize.d32);
++		DWC_DEBUGPL(DBG_CIL, "new hptxfsiz=%08x\n",
++			    DWC_READ_REG32(&global_regs->hptxfsiz));
++
++		if (core_if->en_multiple_tx_fifo) {
++			/* Global DFIFOCFG calculation for Host mode - include RxFIFO, NPTXFIFO and HPTXFIFO */
++			gdfifocfg.d32 = DWC_READ_REG32(&global_regs->gdfifocfg);
++			rxfsiz = (DWC_READ_REG32(&global_regs->grxfsiz) & 0x0000ffff);
++			nptxfsiz = (DWC_READ_REG32(&global_regs->gnptxfsiz) >> 16);
++			hptxfsiz = (DWC_READ_REG32(&global_regs->hptxfsiz) >> 16);
++			gdfifocfg.b.epinfobase = rxfsiz + nptxfsiz + hptxfsiz;
++			DWC_WRITE_REG32(&global_regs->gdfifocfg, gdfifocfg.d32);
++		}
++	}
++
++	/* TODO - check this */
++	/* Clear Host Set HNP Enable in the OTG Control Register */
++	gotgctl.b.hstsethnpen = 1;
++	DWC_MODIFY_REG32(&global_regs->gotgctl, gotgctl.d32, 0);
++	/* Make sure the FIFOs are flushed. */
++	dwc_otg_flush_tx_fifo(core_if, 0x10 /* all TX FIFOs */ );
++	dwc_otg_flush_rx_fifo(core_if);
++
++	/* Clear Host Set HNP Enable in the OTG Control Register */
++	gotgctl.b.hstsethnpen = 1;
++	DWC_MODIFY_REG32(&global_regs->gotgctl, gotgctl.d32, 0);
++
++	if (!core_if->core_params->dma_desc_enable) {
++		/* Flush out any leftover queued requests. */
++		num_channels = core_if->core_params->host_channels;
++
++		for (i = 0; i < num_channels; i++) {
++			hc_regs = core_if->host_if->hc_regs[i];
++			hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
++			hcchar.b.chen = 0;
++			hcchar.b.chdis = 1;
++			hcchar.b.epdir = 0;
++			DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
++		}
++
++		/* Halt all channels to put them into a known state. */
++		for (i = 0; i < num_channels; i++) {
++			int count = 0;
++			hc_regs = core_if->host_if->hc_regs[i];
++			hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
++			hcchar.b.chen = 1;
++			hcchar.b.chdis = 1;
++			hcchar.b.epdir = 0;
++			DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
++			DWC_DEBUGPL(DBG_HCDV, "%s: Halt channel %d\n", __func__, i);
++			do {
++				hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
++				if (++count > 1000) {
++					DWC_ERROR
++					    ("%s: Unable to clear halt on channel %d\n",
++					     __func__, i);
++					break;
++				}
++				dwc_udelay(1);
++			} while (hcchar.b.chen);
++		}
++	}
++
++	/* Turn on the vbus power. */
++	if ((core_if->otg_ver == 0) && (core_if->op_state == A_HOST)) {
++		hprt0.d32 = dwc_otg_read_hprt0(core_if);
++		DWC_PRINTF("Init: Power Port (%d)\n", hprt0.b.prtpwr);
++		if (hprt0.b.prtpwr == 0) {
++			hprt0.b.prtpwr = 1;
++			DWC_WRITE_REG32(host_if->hprt0, hprt0.d32);
++		}
++	}
++
++	dwc_otg_enable_host_interrupts(core_if);
++}
++
++/**
++ * Prepares a host channel for transferring packets to/from a specific
++ * endpoint. The HCCHARn register is set up with the characteristics specified
++ * in _hc. Host channel interrupts that may need to be serviced while this
++ * transfer is in progress are enabled.
++ *
++ * @param core_if Programming view of DWC_otg controller
++ * @param hc Information needed to initialize the host channel
++ */
++void dwc_otg_hc_init(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
++{
++	uint32_t intr_enable;
++	hcintmsk_data_t hc_intr_mask;
++	gintmsk_data_t gintmsk = {.d32 = 0 };
++	hcchar_data_t hcchar;
++	hcsplt_data_t hcsplt;
++
++	uint8_t hc_num = hc->hc_num;
++	dwc_otg_host_if_t *host_if = core_if->host_if;
++	dwc_otg_hc_regs_t *hc_regs = host_if->hc_regs[hc_num];
++
++	/* Clear old interrupt conditions for this host channel. */
++	hc_intr_mask.d32 = 0xFFFFFFFF;
++	hc_intr_mask.b.reserved14_31 = 0;
++	DWC_WRITE_REG32(&hc_regs->hcint, hc_intr_mask.d32);
++
++	/* Enable channel interrupts required for this transfer. */
++	hc_intr_mask.d32 = 0;
++	hc_intr_mask.b.chhltd = 1;
++	if (core_if->dma_enable) {
++		/* For Descriptor DMA mode core halts the channel on AHB error. Interrupt is not required */
++		if (!core_if->dma_desc_enable)
++			hc_intr_mask.b.ahberr = 1;
++		else {
++			if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)
++				hc_intr_mask.b.xfercompl = 1;
++		}
++
++		if (hc->error_state && !hc->do_split &&
++		    hc->ep_type != DWC_OTG_EP_TYPE_ISOC) {
++			hc_intr_mask.b.ack = 1;
++			if (hc->ep_is_in) {
++				hc_intr_mask.b.datatglerr = 1;
++				if (hc->ep_type != DWC_OTG_EP_TYPE_INTR) {
++					hc_intr_mask.b.nak = 1;
++				}
++			}
++		}
++	} else {
++		switch (hc->ep_type) {
++		case DWC_OTG_EP_TYPE_CONTROL:
++		case DWC_OTG_EP_TYPE_BULK:
++			hc_intr_mask.b.xfercompl = 1;
++			hc_intr_mask.b.stall = 1;
++			hc_intr_mask.b.xacterr = 1;
++			hc_intr_mask.b.datatglerr = 1;
++			if (hc->ep_is_in) {
++				hc_intr_mask.b.bblerr = 1;
++			} else {
++				hc_intr_mask.b.nak = 1;
++				hc_intr_mask.b.nyet = 1;
++				if (hc->do_ping) {
++					hc_intr_mask.b.ack = 1;
++				}
++			}
++
++			if (hc->do_split) {
++				hc_intr_mask.b.nak = 1;
++				if (hc->complete_split) {
++					hc_intr_mask.b.nyet = 1;
++				} else {
++					hc_intr_mask.b.ack = 1;
++				}
++			}
++
++			if (hc->error_state) {
++				hc_intr_mask.b.ack = 1;
++			}
++			break;
++		case DWC_OTG_EP_TYPE_INTR:
++			hc_intr_mask.b.xfercompl = 1;
++			hc_intr_mask.b.nak = 1;
++			hc_intr_mask.b.stall = 1;
++			hc_intr_mask.b.xacterr = 1;
++			hc_intr_mask.b.datatglerr = 1;
++			hc_intr_mask.b.frmovrun = 1;
++
++			if (hc->ep_is_in) {
++				hc_intr_mask.b.bblerr = 1;
++			}
++			if (hc->error_state) {
++				hc_intr_mask.b.ack = 1;
++			}
++			if (hc->do_split) {
++				if (hc->complete_split) {
++					hc_intr_mask.b.nyet = 1;
++				} else {
++					hc_intr_mask.b.ack = 1;
++				}
++			}
++			break;
++		case DWC_OTG_EP_TYPE_ISOC:
++			hc_intr_mask.b.xfercompl = 1;
++			hc_intr_mask.b.frmovrun = 1;
++			hc_intr_mask.b.ack = 1;
++
++			if (hc->ep_is_in) {
++				hc_intr_mask.b.xacterr = 1;
++				hc_intr_mask.b.bblerr = 1;
++			}
++			break;
++		}
++	}
++	DWC_WRITE_REG32(&hc_regs->hcintmsk, hc_intr_mask.d32);
++
++	/* Enable the top level host channel interrupt. */
++	intr_enable = (1 << hc_num);
++	DWC_MODIFY_REG32(&host_if->host_global_regs->haintmsk, 0, intr_enable);
++
++	/* Make sure host channel interrupts are enabled. */
++	gintmsk.b.hcintr = 1;
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, 0, gintmsk.d32);
++
++	/*
++	 * Program the HCCHARn register with the endpoint characteristics for
++	 * the current transfer.
++	 */
++	hcchar.d32 = 0;
++	hcchar.b.devaddr = hc->dev_addr;
++	hcchar.b.epnum = hc->ep_num;
++	hcchar.b.epdir = hc->ep_is_in;
++	hcchar.b.lspddev = (hc->speed == DWC_OTG_EP_SPEED_LOW);
++	hcchar.b.eptype = hc->ep_type;
++	hcchar.b.mps = hc->max_packet;
++
++	DWC_WRITE_REG32(&host_if->hc_regs[hc_num]->hcchar, hcchar.d32);
++
++	DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
++	DWC_DEBUGPL(DBG_HCDV, "	 Dev Addr: %d\n", hcchar.b.devaddr);
++	DWC_DEBUGPL(DBG_HCDV, "	 Ep Num: %d\n", hcchar.b.epnum);
++	DWC_DEBUGPL(DBG_HCDV, "	 Is In: %d\n", hcchar.b.epdir);
++	DWC_DEBUGPL(DBG_HCDV, "	 Is Low Speed: %d\n", hcchar.b.lspddev);
++	DWC_DEBUGPL(DBG_HCDV, "	 Ep Type: %d\n", hcchar.b.eptype);
++	DWC_DEBUGPL(DBG_HCDV, "	 Max Pkt: %d\n", hcchar.b.mps);
++	DWC_DEBUGPL(DBG_HCDV, "	 Multi Cnt: %d\n", hcchar.b.multicnt);
++
++	/*
++	 * Program the HCSPLIT register for SPLITs
++	 */
++	hcsplt.d32 = 0;
++	if (hc->do_split) {
++		DWC_DEBUGPL(DBG_HCDV, "Programming HC %d with split --> %s\n",
++			    hc->hc_num,
++			    hc->complete_split ? "CSPLIT" : "SSPLIT");
++		hcsplt.b.compsplt = hc->complete_split;
++		hcsplt.b.xactpos = hc->xact_pos;
++		hcsplt.b.hubaddr = hc->hub_addr;
++		hcsplt.b.prtaddr = hc->port_addr;
++		DWC_DEBUGPL(DBG_HCDV, "	  comp split %d\n", hc->complete_split);
++		DWC_DEBUGPL(DBG_HCDV, "	  xact pos %d\n", hc->xact_pos);
++		DWC_DEBUGPL(DBG_HCDV, "	  hub addr %d\n", hc->hub_addr);
++		DWC_DEBUGPL(DBG_HCDV, "	  port addr %d\n", hc->port_addr);
++		DWC_DEBUGPL(DBG_HCDV, "	  is_in %d\n", hc->ep_is_in);
++		DWC_DEBUGPL(DBG_HCDV, "	  Max Pkt: %d\n", hcchar.b.mps);
++		DWC_DEBUGPL(DBG_HCDV, "	  xferlen: %d\n", hc->xfer_len);
++	}
++	DWC_WRITE_REG32(&host_if->hc_regs[hc_num]->hcsplt, hcsplt.d32);
++
++}
++
++/**
++ * Attempts to halt a host channel. This function should only be called in
++ * Slave mode or to abort a transfer in either Slave mode or DMA mode. Under
++ * normal circumstances in DMA mode, the controller halts the channel when the
++ * transfer is complete or a condition occurs that requires application
++ * intervention.
++ *
++ * In slave mode, checks for a free request queue entry, then sets the Channel
++ * Enable and Channel Disable bits of the Host Channel Characteristics
++ * register of the specified channel to intiate the halt. If there is no free
++ * request queue entry, sets only the Channel Disable bit of the HCCHARn
++ * register to flush requests for this channel. In the latter case, sets a
++ * flag to indicate that the host channel needs to be halted when a request
++ * queue slot is open.
++ *
++ * In DMA mode, always sets the Channel Enable and Channel Disable bits of the
++ * HCCHARn register. The controller ensures there is space in the request
++ * queue before submitting the halt request.
++ *
++ * Some time may elapse before the core flushes any posted requests for this
++ * host channel and halts. The Channel Halted interrupt handler completes the
++ * deactivation of the host channel.
++ *
++ * @param core_if Controller register interface.
++ * @param hc Host channel to halt.
++ * @param halt_status Reason for halting the channel.
++ */
++void dwc_otg_hc_halt(dwc_otg_core_if_t * core_if,
++		     dwc_hc_t * hc, dwc_otg_halt_status_e halt_status)
++{
++	gnptxsts_data_t nptxsts;
++	hptxsts_data_t hptxsts;
++	hcchar_data_t hcchar;
++	dwc_otg_hc_regs_t *hc_regs;
++	dwc_otg_core_global_regs_t *global_regs;
++	dwc_otg_host_global_regs_t *host_global_regs;
++
++	hc_regs = core_if->host_if->hc_regs[hc->hc_num];
++	global_regs = core_if->core_global_regs;
++	host_global_regs = core_if->host_if->host_global_regs;
++
++	DWC_ASSERT(!(halt_status == DWC_OTG_HC_XFER_NO_HALT_STATUS),
++		   "halt_status = %d\n", halt_status);
++
++	if (halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE ||
++	    halt_status == DWC_OTG_HC_XFER_AHB_ERR) {
++		/*
++		 * Disable all channel interrupts except Ch Halted. The QTD
++		 * and QH state associated with this transfer has been cleared
++		 * (in the case of URB_DEQUEUE), so the channel needs to be
++		 * shut down carefully to prevent crashes.
++		 */
++		hcintmsk_data_t hcintmsk;
++		hcintmsk.d32 = 0;
++		hcintmsk.b.chhltd = 1;
++		DWC_WRITE_REG32(&hc_regs->hcintmsk, hcintmsk.d32);
++
++		/*
++		 * Make sure no other interrupts besides halt are currently
++		 * pending. Handling another interrupt could cause a crash due
++		 * to the QTD and QH state.
++		 */
++		DWC_WRITE_REG32(&hc_regs->hcint, ~hcintmsk.d32);
++
++		/*
++		 * Make sure the halt status is set to URB_DEQUEUE or AHB_ERR
++		 * even if the channel was already halted for some other
++		 * reason.
++		 */
++		hc->halt_status = halt_status;
++
++		hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
++		if (hcchar.b.chen == 0) {
++			/*
++			 * The channel is either already halted or it hasn't
++			 * started yet. In DMA mode, the transfer may halt if
++			 * it finishes normally or a condition occurs that
++			 * requires driver intervention. Don't want to halt
++			 * the channel again. In either Slave or DMA mode,
++			 * it's possible that the transfer has been assigned
++			 * to a channel, but not started yet when an URB is
++			 * dequeued. Don't want to halt a channel that hasn't
++			 * started yet.
++			 */
++			return;
++		}
++	}
++	if (hc->halt_pending) {
++		/*
++		 * A halt has already been issued for this channel. This might
++		 * happen when a transfer is aborted by a higher level in
++		 * the stack.
++		 */
++#ifdef DEBUG
++		DWC_PRINTF
++		    ("*** %s: Channel %d, _hc->halt_pending already set ***\n",
++		     __func__, hc->hc_num);
++
++#endif
++		return;
++	}
++
++	hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
++
++	/* No need to set the bit in DDMA for disabling the channel */
++	//TODO check it everywhere channel is disabled
++	if (!core_if->core_params->dma_desc_enable)
++		hcchar.b.chen = 1;
++	hcchar.b.chdis = 1;
++
++	if (!core_if->dma_enable) {
++		/* Check for space in the request queue to issue the halt. */
++		if (hc->ep_type == DWC_OTG_EP_TYPE_CONTROL ||
++		    hc->ep_type == DWC_OTG_EP_TYPE_BULK) {
++			nptxsts.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
++			if (nptxsts.b.nptxqspcavail == 0) {
++				hcchar.b.chen = 0;
++			}
++		} else {
++			hptxsts.d32 =
++			    DWC_READ_REG32(&host_global_regs->hptxsts);
++			if ((hptxsts.b.ptxqspcavail == 0)
++			    || (core_if->queuing_high_bandwidth)) {
++				hcchar.b.chen = 0;
++			}
++		}
++	}
++	DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
++
++	hc->halt_status = halt_status;
++
++	if (hcchar.b.chen) {
++		hc->halt_pending = 1;
++		hc->halt_on_queue = 0;
++	} else {
++		hc->halt_on_queue = 1;
++	}
++
++	DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
++	DWC_DEBUGPL(DBG_HCDV, "	 hcchar: 0x%08x\n", hcchar.d32);
++	DWC_DEBUGPL(DBG_HCDV, "	 halt_pending: %d\n", hc->halt_pending);
++	DWC_DEBUGPL(DBG_HCDV, "	 halt_on_queue: %d\n", hc->halt_on_queue);
++	DWC_DEBUGPL(DBG_HCDV, "	 halt_status: %d\n", hc->halt_status);
++
++	return;
++}
++
++/**
++ * Clears the transfer state for a host channel. This function is normally
++ * called after a transfer is done and the host channel is being released.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ * @param hc Identifies the host channel to clean up.
++ */
++void dwc_otg_hc_cleanup(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
++{
++	dwc_otg_hc_regs_t *hc_regs;
++
++	hc->xfer_started = 0;
++
++	/*
++	 * Clear channel interrupt enables and any unhandled channel interrupt
++	 * conditions.
++	 */
++	hc_regs = core_if->host_if->hc_regs[hc->hc_num];
++	DWC_WRITE_REG32(&hc_regs->hcintmsk, 0);
++	DWC_WRITE_REG32(&hc_regs->hcint, 0xFFFFFFFF);
++#ifdef DEBUG
++	DWC_TIMER_CANCEL(core_if->hc_xfer_timer[hc->hc_num]);
++#endif
++}
++
++/**
++ * Sets the channel property that indicates in which frame a periodic transfer
++ * should occur. This is always set to the _next_ frame. This function has no
++ * effect on non-periodic transfers.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ * @param hc Identifies the host channel to set up and its properties.
++ * @param hcchar Current value of the HCCHAR register for the specified host
++ * channel.
++ */
++static inline void hc_set_even_odd_frame(dwc_otg_core_if_t * core_if,
++					 dwc_hc_t * hc, hcchar_data_t * hcchar)
++{
++	if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
++	    hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
++		hfnum_data_t hfnum;
++		hfnum.d32 =
++		    DWC_READ_REG32(&core_if->host_if->host_global_regs->hfnum);
++
++		/* 1 if _next_ frame is odd, 0 if it's even */
++		hcchar->b.oddfrm = (hfnum.b.frnum & 0x1) ? 0 : 1;
++#ifdef DEBUG
++		if (hc->ep_type == DWC_OTG_EP_TYPE_INTR && hc->do_split
++		    && !hc->complete_split) {
++			switch (hfnum.b.frnum & 0x7) {
++			case 7:
++				core_if->hfnum_7_samples++;
++				core_if->hfnum_7_frrem_accum += hfnum.b.frrem;
++				break;
++			case 0:
++				core_if->hfnum_0_samples++;
++				core_if->hfnum_0_frrem_accum += hfnum.b.frrem;
++				break;
++			default:
++				core_if->hfnum_other_samples++;
++				core_if->hfnum_other_frrem_accum +=
++				    hfnum.b.frrem;
++				break;
++			}
++		}
++#endif
++	}
++}
++
++#ifdef DEBUG
++void hc_xfer_timeout(void *ptr)
++{
++	hc_xfer_info_t *xfer_info = NULL;
++	int hc_num = 0;
++
++	if (ptr)
++		xfer_info = (hc_xfer_info_t *) ptr;
++
++	if (!xfer_info)
++		return;
++
++	if (!xfer_info->hc) {
++		DWC_ERROR("xfer_info->hc = %p\n", xfer_info->hc);
++		return;
++	}
++
++	hc_num = xfer_info->hc->hc_num;
++	DWC_WARN("%s: timeout on channel %d\n", __func__, hc_num);
++	DWC_WARN("	start_hcchar_val 0x%08x\n",
++		 xfer_info->core_if->start_hcchar_val[hc_num]);
++}
++#endif
++
++void ep_xfer_timeout(void *ptr)
++{
++	ep_xfer_info_t *xfer_info = NULL;
++	int ep_num = 0;
++	dctl_data_t dctl = {.d32 = 0 };
++	gintsts_data_t gintsts = {.d32 = 0 };
++	gintmsk_data_t gintmsk = {.d32 = 0 };
++
++	if (ptr)
++		xfer_info = (ep_xfer_info_t *) ptr;
++
++	if (!xfer_info->ep) {
++		DWC_ERROR("xfer_info->ep = %p\n", xfer_info->ep);
++		return;
++	}
++
++	ep_num = xfer_info->ep->num;
++	DWC_WARN("%s: timeout on endpoit %d\n", __func__, ep_num);
++	/* Put the sate to 2 as it was time outed */
++	xfer_info->state = 2;
++
++	dctl.d32 =
++	    DWC_READ_REG32(&xfer_info->core_if->dev_if->dev_global_regs->dctl);
++	gintsts.d32 =
++	    DWC_READ_REG32(&xfer_info->core_if->core_global_regs->gintsts);
++	gintmsk.d32 =
++	    DWC_READ_REG32(&xfer_info->core_if->core_global_regs->gintmsk);
++
++	if (!gintmsk.b.goutnakeff) {
++		/* Unmask it */
++		gintmsk.b.goutnakeff = 1;
++		DWC_WRITE_REG32(&xfer_info->core_if->core_global_regs->gintmsk,
++				gintmsk.d32);
++
++	}
++
++	if (!gintsts.b.goutnakeff) {
++		dctl.b.sgoutnak = 1;
++	}
++	DWC_WRITE_REG32(&xfer_info->core_if->dev_if->dev_global_regs->dctl,
++			dctl.d32);
++
++}
++
++void set_pid_isoc(dwc_hc_t * hc)
++{
++	/* Set up the initial PID for the transfer. */
++	if (hc->speed == DWC_OTG_EP_SPEED_HIGH) {
++		if (hc->ep_is_in) {
++			if (hc->multi_count == 1) {
++				hc->data_pid_start = DWC_OTG_HC_PID_DATA0;
++			} else if (hc->multi_count == 2) {
++				hc->data_pid_start = DWC_OTG_HC_PID_DATA1;
++			} else {
++				hc->data_pid_start = DWC_OTG_HC_PID_DATA2;
++			}
++		} else {
++			if (hc->multi_count == 1) {
++				hc->data_pid_start = DWC_OTG_HC_PID_DATA0;
++			} else {
++				hc->data_pid_start = DWC_OTG_HC_PID_MDATA;
++			}
++		}
++	} else {
++		hc->data_pid_start = DWC_OTG_HC_PID_DATA0;
++	}
++}
++
++/**
++ * This function does the setup for a data transfer for a host channel and
++ * starts the transfer. May be called in either Slave mode or DMA mode. In
++ * Slave mode, the caller must ensure that there is sufficient space in the
++ * request queue and Tx Data FIFO.
++ *
++ * For an OUT transfer in Slave mode, it loads a data packet into the
++ * appropriate FIFO. If necessary, additional data packets will be loaded in
++ * the Host ISR.
++ *
++ * For an IN transfer in Slave mode, a data packet is requested. The data
++ * packets are unloaded from the Rx FIFO in the Host ISR. If necessary,
++ * additional data packets are requested in the Host ISR.
++ *
++ * For a PING transfer in Slave mode, the Do Ping bit is set in the HCTSIZ
++ * register along with a packet count of 1 and the channel is enabled. This
++ * causes a single PING transaction to occur. Other fields in HCTSIZ are
++ * simply set to 0 since no data transfer occurs in this case.
++ *
++ * For a PING transfer in DMA mode, the HCTSIZ register is initialized with
++ * all the information required to perform the subsequent data transfer. In
++ * addition, the Do Ping bit is set in the HCTSIZ register. In this case, the
++ * controller performs the entire PING protocol, then starts the data
++ * transfer.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ * @param hc Information needed to initialize the host channel. The xfer_len
++ * value may be reduced to accommodate the max widths of the XferSize and
++ * PktCnt fields in the HCTSIZn register. The multi_count value may be changed
++ * to reflect the final xfer_len value.
++ */
++void dwc_otg_hc_start_transfer(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
++{
++	hcchar_data_t hcchar;
++	hctsiz_data_t hctsiz;
++	uint16_t num_packets;
++	uint32_t max_hc_xfer_size = core_if->core_params->max_transfer_size;
++	uint16_t max_hc_pkt_count = core_if->core_params->max_packet_count;
++	dwc_otg_hc_regs_t *hc_regs = core_if->host_if->hc_regs[hc->hc_num];
++
++	hctsiz.d32 = 0;
++
++	if (hc->do_ping) {
++		if (!core_if->dma_enable) {
++			dwc_otg_hc_do_ping(core_if, hc);
++			hc->xfer_started = 1;
++			return;
++		} else {
++			hctsiz.b.dopng = 1;
++		}
++	}
++
++	if (hc->do_split) {
++		num_packets = 1;
++
++		if (hc->complete_split && !hc->ep_is_in) {
++			/* For CSPLIT OUT Transfer, set the size to 0 so the
++			 * core doesn't expect any data written to the FIFO */
++			hc->xfer_len = 0;
++		} else if (hc->ep_is_in || (hc->xfer_len > hc->max_packet)) {
++			hc->xfer_len = hc->max_packet;
++		} else if (!hc->ep_is_in && (hc->xfer_len > 188)) {
++			hc->xfer_len = 188;
++		}
++
++		hctsiz.b.xfersize = hc->xfer_len;
++	} else {
++		/*
++		 * Ensure that the transfer length and packet count will fit
++		 * in the widths allocated for them in the HCTSIZn register.
++		 */
++		if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
++		    hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
++			/*
++			 * Make sure the transfer size is no larger than one
++			 * (micro)frame's worth of data. (A check was done
++			 * when the periodic transfer was accepted to ensure
++			 * that a (micro)frame's worth of data can be
++			 * programmed into a channel.)
++			 */
++			uint32_t max_periodic_len =
++			    hc->multi_count * hc->max_packet;
++			if (hc->xfer_len > max_periodic_len) {
++				hc->xfer_len = max_periodic_len;
++			} else {
++			}
++		} else if (hc->xfer_len > max_hc_xfer_size) {
++			/* Make sure that xfer_len is a multiple of max packet size. */
++			hc->xfer_len = max_hc_xfer_size - hc->max_packet + 1;
++		}
++
++		if (hc->xfer_len > 0) {
++			num_packets =
++			    (hc->xfer_len + hc->max_packet -
++			     1) / hc->max_packet;
++			if (num_packets > max_hc_pkt_count) {
++				num_packets = max_hc_pkt_count;
++				hc->xfer_len = num_packets * hc->max_packet;
++			}
++		} else {
++			/* Need 1 packet for transfer length of 0. */
++			num_packets = 1;
++		}
++
++		if (hc->ep_is_in) {
++			/* Always program an integral # of max packets for IN transfers. */
++			hc->xfer_len = num_packets * hc->max_packet;
++		}
++
++		if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
++		    hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
++			/*
++			 * Make sure that the multi_count field matches the
++			 * actual transfer length.
++			 */
++			hc->multi_count = num_packets;
++		}
++
++		if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)
++			set_pid_isoc(hc);
++
++		hctsiz.b.xfersize = hc->xfer_len;
++	}
++
++	hc->start_pkt_count = num_packets;
++	hctsiz.b.pktcnt = num_packets;
++	hctsiz.b.pid = hc->data_pid_start;
++	DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
++
++	DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
++	DWC_DEBUGPL(DBG_HCDV, "	 Xfer Size: %d\n", hctsiz.b.xfersize);
++	DWC_DEBUGPL(DBG_HCDV, "	 Num Pkts: %d\n", hctsiz.b.pktcnt);
++	DWC_DEBUGPL(DBG_HCDV, "	 Start PID: %d\n", hctsiz.b.pid);
++
++	if (core_if->dma_enable) {
++		dwc_dma_t dma_addr;
++		if (hc->align_buff) {
++			dma_addr = hc->align_buff;
++		} else {
++			dma_addr = ((unsigned long)hc->xfer_buff & 0xffffffff);
++		}
++		DWC_WRITE_REG32(&hc_regs->hcdma, dma_addr);
++	}
++
++	/* Start the split */
++	if (hc->do_split) {
++		hcsplt_data_t hcsplt;
++		hcsplt.d32 = DWC_READ_REG32(&hc_regs->hcsplt);
++		hcsplt.b.spltena = 1;
++		DWC_WRITE_REG32(&hc_regs->hcsplt, hcsplt.d32);
++	}
++
++	hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
++	hcchar.b.multicnt = hc->multi_count;
++	hc_set_even_odd_frame(core_if, hc, &hcchar);
++#ifdef DEBUG
++	core_if->start_hcchar_val[hc->hc_num] = hcchar.d32;
++	if (hcchar.b.chdis) {
++		DWC_WARN("%s: chdis set, channel %d, hcchar 0x%08x\n",
++			 __func__, hc->hc_num, hcchar.d32);
++	}
++#endif
++
++	/* Set host channel enable after all other setup is complete. */
++	hcchar.b.chen = 1;
++	hcchar.b.chdis = 0;
++	DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
++
++	hc->xfer_started = 1;
++	hc->requests++;
++
++	if (!core_if->dma_enable && !hc->ep_is_in && hc->xfer_len > 0) {
++		/* Load OUT packet into the appropriate Tx FIFO. */
++		dwc_otg_hc_write_packet(core_if, hc);
++	}
++#ifdef DEBUG
++	if (hc->ep_type != DWC_OTG_EP_TYPE_INTR) {
++		core_if->hc_xfer_info[hc->hc_num].core_if = core_if;
++		core_if->hc_xfer_info[hc->hc_num].hc = hc;
++
++		/* Start a timer for this transfer. */
++		DWC_TIMER_SCHEDULE(core_if->hc_xfer_timer[hc->hc_num], 10000);
++	}
++#endif
++}
++
++/**
++ * This function does the setup for a data transfer for a host channel
++ * and starts the transfer in Descriptor DMA mode.
++ *
++ * Initializes HCTSIZ register. For a PING transfer the Do Ping bit is set.
++ * Sets PID and NTD values. For periodic transfers
++ * initializes SCHED_INFO field with micro-frame bitmap.
++ *
++ * Initializes HCDMA register with descriptor list address and CTD value
++ * then starts the transfer via enabling the channel.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ * @param hc Information needed to initialize the host channel.
++ */
++void dwc_otg_hc_start_transfer_ddma(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
++{
++	dwc_otg_hc_regs_t *hc_regs = core_if->host_if->hc_regs[hc->hc_num];
++	hcchar_data_t hcchar;
++	hctsiz_data_t hctsiz;
++	hcdma_data_t hcdma;
++
++	hctsiz.d32 = 0;
++
++	if (hc->do_ping)
++		hctsiz.b_ddma.dopng = 1;
++
++	if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)
++		set_pid_isoc(hc);
++
++	/* Packet Count and Xfer Size are not used in Descriptor DMA mode */
++	hctsiz.b_ddma.pid = hc->data_pid_start;
++	hctsiz.b_ddma.ntd = hc->ntd - 1;	/* 0 - 1 descriptor, 1 - 2 descriptors, etc. */
++	hctsiz.b_ddma.schinfo = hc->schinfo;	/* Non-zero only for high-speed interrupt endpoints */
++
++	DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
++	DWC_DEBUGPL(DBG_HCDV, "	 Start PID: %d\n", hctsiz.b.pid);
++	DWC_DEBUGPL(DBG_HCDV, "	 NTD: %d\n", hctsiz.b_ddma.ntd);
++
++	DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
++
++	hcdma.d32 = 0;
++	hcdma.b.dma_addr = ((uint32_t) hc->desc_list_addr) >> 11;
++
++	/* Always start from first descriptor. */
++	hcdma.b.ctd = 0;
++	DWC_WRITE_REG32(&hc_regs->hcdma, hcdma.d32);
++
++	hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
++	hcchar.b.multicnt = hc->multi_count;
++
++#ifdef DEBUG
++	core_if->start_hcchar_val[hc->hc_num] = hcchar.d32;
++	if (hcchar.b.chdis) {
++		DWC_WARN("%s: chdis set, channel %d, hcchar 0x%08x\n",
++			 __func__, hc->hc_num, hcchar.d32);
++	}
++#endif
++
++	/* Set host channel enable after all other setup is complete. */
++	hcchar.b.chen = 1;
++	hcchar.b.chdis = 0;
++
++	DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
++
++	hc->xfer_started = 1;
++	hc->requests++;
++
++#ifdef DEBUG
++	if ((hc->ep_type != DWC_OTG_EP_TYPE_INTR)
++	    && (hc->ep_type != DWC_OTG_EP_TYPE_ISOC)) {
++		core_if->hc_xfer_info[hc->hc_num].core_if = core_if;
++		core_if->hc_xfer_info[hc->hc_num].hc = hc;
++		/* Start a timer for this transfer. */
++		DWC_TIMER_SCHEDULE(core_if->hc_xfer_timer[hc->hc_num], 10000);
++	}
++#endif
++
++}
++
++/**
++ * This function continues a data transfer that was started by previous call
++ * to <code>dwc_otg_hc_start_transfer</code>. The caller must ensure there is
++ * sufficient space in the request queue and Tx Data FIFO. This function
++ * should only be called in Slave mode. In DMA mode, the controller acts
++ * autonomously to complete transfers programmed to a host channel.
++ *
++ * For an OUT transfer, a new data packet is loaded into the appropriate FIFO
++ * if there is any data remaining to be queued. For an IN transfer, another
++ * data packet is always requested. For the SETUP phase of a control transfer,
++ * this function does nothing.
++ *
++ * @return 1 if a new request is queued, 0 if no more requests are required
++ * for this transfer.
++ */
++int dwc_otg_hc_continue_transfer(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
++{
++	DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
++
++	if (hc->do_split) {
++		/* SPLITs always queue just once per channel */
++		return 0;
++	} else if (hc->data_pid_start == DWC_OTG_HC_PID_SETUP) {
++		/* SETUPs are queued only once since they can't be NAKed. */
++		return 0;
++	} else if (hc->ep_is_in) {
++		/*
++		 * Always queue another request for other IN transfers. If
++		 * back-to-back INs are issued and NAKs are received for both,
++		 * the driver may still be processing the first NAK when the
++		 * second NAK is received. When the interrupt handler clears
++		 * the NAK interrupt for the first NAK, the second NAK will
++		 * not be seen. So we can't depend on the NAK interrupt
++		 * handler to requeue a NAKed request. Instead, IN requests
++		 * are issued each time this function is called. When the
++		 * transfer completes, the extra requests for the channel will
++		 * be flushed.
++		 */
++		hcchar_data_t hcchar;
++		dwc_otg_hc_regs_t *hc_regs =
++		    core_if->host_if->hc_regs[hc->hc_num];
++
++		hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
++		hc_set_even_odd_frame(core_if, hc, &hcchar);
++		hcchar.b.chen = 1;
++		hcchar.b.chdis = 0;
++		DWC_DEBUGPL(DBG_HCDV, "	 IN xfer: hcchar = 0x%08x\n",
++			    hcchar.d32);
++		DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
++		hc->requests++;
++		return 1;
++	} else {
++		/* OUT transfers. */
++		if (hc->xfer_count < hc->xfer_len) {
++			if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
++			    hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
++				hcchar_data_t hcchar;
++				dwc_otg_hc_regs_t *hc_regs;
++				hc_regs = core_if->host_if->hc_regs[hc->hc_num];
++				hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
++				hc_set_even_odd_frame(core_if, hc, &hcchar);
++			}
++
++			/* Load OUT packet into the appropriate Tx FIFO. */
++			dwc_otg_hc_write_packet(core_if, hc);
++			hc->requests++;
++			return 1;
++		} else {
++			return 0;
++		}
++	}
++}
++
++/**
++ * Starts a PING transfer. This function should only be called in Slave mode.
++ * The Do Ping bit is set in the HCTSIZ register, then the channel is enabled.
++ */
++void dwc_otg_hc_do_ping(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
++{
++	hcchar_data_t hcchar;
++	hctsiz_data_t hctsiz;
++	dwc_otg_hc_regs_t *hc_regs = core_if->host_if->hc_regs[hc->hc_num];
++
++	DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
++
++	hctsiz.d32 = 0;
++	hctsiz.b.dopng = 1;
++	hctsiz.b.pktcnt = 1;
++	DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
++
++	hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
++	hcchar.b.chen = 1;
++	hcchar.b.chdis = 0;
++	DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
++}
++
++/*
++ * This function writes a packet into the Tx FIFO associated with the Host
++ * Channel. For a channel associated with a non-periodic EP, the non-periodic
++ * Tx FIFO is written. For a channel associated with a periodic EP, the
++ * periodic Tx FIFO is written. This function should only be called in Slave
++ * mode.
++ *
++ * Upon return the xfer_buff and xfer_count fields in _hc are incremented by
++ * then number of bytes written to the Tx FIFO.
++ */
++void dwc_otg_hc_write_packet(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
++{
++	uint32_t i;
++	uint32_t remaining_count;
++	uint32_t byte_count;
++	uint32_t dword_count;
++
++	uint32_t *data_buff = (uint32_t *) (hc->xfer_buff);
++	uint32_t *data_fifo = core_if->data_fifo[hc->hc_num];
++
++	remaining_count = hc->xfer_len - hc->xfer_count;
++	if (remaining_count > hc->max_packet) {
++		byte_count = hc->max_packet;
++	} else {
++		byte_count = remaining_count;
++	}
++
++	dword_count = (byte_count + 3) / 4;
++
++	if ((((unsigned long)data_buff) & 0x3) == 0) {
++		/* xfer_buff is DWORD aligned. */
++		for (i = 0; i < dword_count; i++, data_buff++) {
++			DWC_WRITE_REG32(data_fifo, *data_buff);
++		}
++	} else {
++		/* xfer_buff is not DWORD aligned. */
++		for (i = 0; i < dword_count; i++, data_buff++) {
++			uint32_t data;
++			data =
++			    (data_buff[0] | data_buff[1] << 8 | data_buff[2] <<
++			     16 | data_buff[3] << 24);
++			DWC_WRITE_REG32(data_fifo, data);
++		}
++	}
++
++	hc->xfer_count += byte_count;
++	hc->xfer_buff += byte_count;
++}
++
++/**
++ * Gets the current USB frame number. This is the frame number from the last
++ * SOF packet.
++ */
++uint32_t dwc_otg_get_frame_number(dwc_otg_core_if_t * core_if)
++{
++	dsts_data_t dsts;
++	dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
++
++	/* read current frame/microframe number from DSTS register */
++	return dsts.b.soffn;
++}
++
++/**
++ * Calculates and gets the frame Interval value of HFIR register according PHY
++ * type and speed.The application can modify a value of HFIR register only after
++ * the Port Enable bit of the Host Port Control and Status register
++ * (HPRT.PrtEnaPort) has been set.
++*/
++
++uint32_t calc_frame_interval(dwc_otg_core_if_t * core_if)
++{
++	gusbcfg_data_t usbcfg;
++	hwcfg2_data_t hwcfg2;
++	hprt0_data_t hprt0;
++	int clock = 60;		// default value
++	usbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
++	hwcfg2.d32 = DWC_READ_REG32(&core_if->core_global_regs->ghwcfg2);
++	hprt0.d32 = DWC_READ_REG32(core_if->host_if->hprt0);
++	if (!usbcfg.b.physel && usbcfg.b.ulpi_utmi_sel && !usbcfg.b.phyif)
++		clock = 60;
++	if (usbcfg.b.physel && hwcfg2.b.fs_phy_type == 3)
++		clock = 48;
++	if (!usbcfg.b.phylpwrclksel && !usbcfg.b.physel &&
++	    !usbcfg.b.ulpi_utmi_sel && usbcfg.b.phyif)
++		clock = 30;
++	if (!usbcfg.b.phylpwrclksel && !usbcfg.b.physel &&
++	    !usbcfg.b.ulpi_utmi_sel && !usbcfg.b.phyif)
++		clock = 60;
++	if (usbcfg.b.phylpwrclksel && !usbcfg.b.physel &&
++	    !usbcfg.b.ulpi_utmi_sel && usbcfg.b.phyif)
++		clock = 48;
++	if (usbcfg.b.physel && !usbcfg.b.phyif && hwcfg2.b.fs_phy_type == 2)
++		clock = 48;
++	if (usbcfg.b.physel && hwcfg2.b.fs_phy_type == 1)
++		clock = 48;
++	if (hprt0.b.prtspd == 0)
++		/* High speed case */
++		return 125 * clock;
++	else
++		/* FS/LS case */
++		return 1000 * clock;
++}
++
++/**
++ * This function reads a setup packet from the Rx FIFO into the destination
++ * buffer. This function is called from the Rx Status Queue Level (RxStsQLvl)
++ * Interrupt routine when a SETUP packet has been received in Slave mode.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ * @param dest Destination buffer for packet data.
++ */
++void dwc_otg_read_setup_packet(dwc_otg_core_if_t * core_if, uint32_t * dest)
++{
++	device_grxsts_data_t status;
++	/* Get the 8 bytes of a setup transaction data */
++
++	/* Pop 2 DWORDS off the receive data FIFO into memory */
++	dest[0] = DWC_READ_REG32(core_if->data_fifo[0]);
++	dest[1] = DWC_READ_REG32(core_if->data_fifo[0]);
++	if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
++		status.d32 =
++		    DWC_READ_REG32(&core_if->core_global_regs->grxstsp);
++		DWC_DEBUGPL(DBG_ANY,
++			    "EP:%d BCnt:%d " "pktsts:%x Frame:%d(0x%0x)\n",
++			    status.b.epnum, status.b.bcnt, status.b.pktsts,
++			    status.b.fn, status.b.fn);
++	}
++}
++
++/**
++ * This function enables EP0 OUT to receive SETUP packets and configures EP0
++ * IN for transmitting packets. It is normally called when the
++ * "Enumeration Done" interrupt occurs.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ * @param ep The EP0 data.
++ */
++void dwc_otg_ep0_activate(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
++{
++	dwc_otg_dev_if_t *dev_if = core_if->dev_if;
++	dsts_data_t dsts;
++	depctl_data_t diepctl, depctl_tmp;
++	depctl_data_t doepctl;
++	dctl_data_t dctl = {.d32 = 0 };
++	uint8_t i;
++
++	ep->stp_rollover = 0;
++	/* Read the Device Status and Endpoint 0 Control registers */
++	dsts.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dsts);
++	diepctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[0]->diepctl);
++	doepctl.d32 = DWC_READ_REG32(&dev_if->out_ep_regs[0]->doepctl);
++
++	/* Set the MPS of the IN EP based on the enumeration speed */
++	switch (dsts.b.enumspd) {
++	case DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ:
++	case DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ:
++	case DWC_DSTS_ENUMSPD_FS_PHY_48MHZ:
++		diepctl.b.mps = DWC_DEP0CTL_MPS_64;
++		break;
++	case DWC_DSTS_ENUMSPD_LS_PHY_6MHZ:
++		diepctl.b.mps = DWC_DEP0CTL_MPS_8;
++		break;
++	}
++
++	DWC_WRITE_REG32(&dev_if->in_ep_regs[0]->diepctl, diepctl.d32);
++
++	/* Enable OUT EP for receive */
++	if (core_if->snpsid <= OTG_CORE_REV_2_94a) {
++		doepctl.b.epena = 1;
++		DWC_WRITE_REG32(&dev_if->out_ep_regs[0]->doepctl, doepctl.d32);
++	}
++#ifdef VERBOSE
++	DWC_DEBUGPL(DBG_PCDV, "doepctl0=%0x\n",
++		    DWC_READ_REG32(&dev_if->out_ep_regs[0]->doepctl));
++	DWC_DEBUGPL(DBG_PCDV, "diepctl0=%0x\n",
++		    DWC_READ_REG32(&dev_if->in_ep_regs[0]->diepctl));
++#endif
++	dctl.b.cgnpinnak = 1;
++
++	DWC_MODIFY_REG32(&dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32);
++	DWC_DEBUGPL(DBG_PCDV, "dctl=%0x\n",
++		    DWC_READ_REG32(&dev_if->dev_global_regs->dctl));
++
++	for (i = 1; i <= core_if->dev_if->num_in_eps; i++) {
++		depctl_tmp.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
++		if (depctl_tmp.b.epena) {
++			depctl_tmp.d32 = 0;
++			depctl_tmp.b.epdis = 1;
++			depctl_tmp.b.snak = 1;
++			DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[i]->
++					diepctl, depctl_tmp.d32);
++		}
++	}
++}
++
++/**
++ * This function activates an EP.  The Device EP control register for
++ * the EP is configured as defined in the ep structure. Note: This
++ * function is not used for EP0.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ * @param ep The EP to activate.
++ */
++void dwc_otg_ep_activate(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
++{
++	dwc_otg_dev_if_t *dev_if = core_if->dev_if;
++	depctl_data_t depctl;
++	volatile uint32_t *addr;
++	daint_data_t daintmsk = {.d32 = 0 };
++	dcfg_data_t dcfg;
++	uint8_t i;
++
++	DWC_DEBUGPL(DBG_PCDV, "%s() EP%d-%s\n", __func__, ep->num,
++		    (ep->is_in ? "IN" : "OUT"));
++
++#ifdef DWC_UTE_PER_IO
++	ep->xiso_frame_num = 0xFFFFFFFF;
++	ep->xiso_active_xfers = 0;
++	ep->xiso_queued_xfers = 0;
++#endif
++	/* Read DEPCTLn register */
++	if (ep->is_in == 1) {
++		addr = &dev_if->in_ep_regs[ep->num]->diepctl;
++		daintmsk.ep.in = 1 << ep->num;
++	} else {
++		addr = &dev_if->out_ep_regs[ep->num]->doepctl;
++		daintmsk.ep.out = 1 << ep->num;
++	}
++
++	/* If the EP is already active don't change the EP Control
++	 * register. */
++	depctl.d32 = DWC_READ_REG32(addr);
++	if (!depctl.b.usbactep) {
++		if (ep->type == DWC_OTG_EP_TYPE_ISOC) {
++			if (((ep->num == 4) || (ep->num == 6)) && (ep->maxpacket < 256)) {
++				depctl_data_t depctl_tmp;
++				volatile uint32_t *addr_tmp;
++				ep->maxpacket = 256;
++				addr_tmp = &dev_if->in_ep_regs[3]->diepctl;
++				depctl_tmp.d32 = DWC_READ_REG32(addr_tmp);
++				if (depctl_tmp.b.eptype == 0x2) {
++					dctl_data_t dctl;
++					dctl.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dctl);
++					dctl.b.ifrmnum = 1;
++					DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32);
++				}
++			}
++		}
++		depctl.b.mps = ep->maxpacket;
++		depctl.b.eptype = ep->type;
++
++		if (ep->type == DWC_OTG_EP_TYPE_ISOC) {
++			if (ep->num == 3)
++				ep->tx_fifo_num = 0x2;
++			if (ep->num == 4)
++				ep->tx_fifo_num = 0x3;
++		}
++		depctl.b.txfnum = ep->tx_fifo_num;
++
++		/*
++		   there are some rootcase have to be confirm with SNPS
++		   whether ISOC-xfer need depctl.b.setd0pid = 1.
++		   as current version ,we have to keep the follow opteration.
++		   so, just remove if else, keep depctl.b.setd0pid = 1;
++		   if (ep->type == DWC_OTG_EP_TYPE_ISOC) {
++		   depctl.b.setd0pid = 1;	// ???
++		   } else {
++		   depctl.b.setd0pid = 1;
++		   }
++		   depctl.b.usbactep = 1;
++		*/
++		depctl.b.usbactep = 1;
++
++		/* Update nextep_seq array and EPMSCNT in DCFG */
++		if (!(depctl.b.eptype & 1) && (ep->is_in == 1)) {	// NP IN EP
++			for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
++				if (core_if->nextep_seq[i] == core_if->first_in_nextep_seq)
++					break;
++			}
++			core_if->nextep_seq[i] = ep->num;
++			core_if->nextep_seq[ep->num] = core_if->first_in_nextep_seq;
++			depctl.b.nextep = core_if->nextep_seq[ep->num];
++			dcfg.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dcfg);
++			dcfg.b.epmscnt++;
++			DWC_WRITE_REG32(&dev_if->dev_global_regs->dcfg, dcfg.d32);
++
++			DWC_DEBUGPL(DBG_PCDV,
++				    "%s first_in_nextep_seq= %2d; nextep_seq[]:\n",
++				    __func__, core_if->first_in_nextep_seq);
++			for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
++				DWC_DEBUGPL(DBG_PCDV, "%2d\n",
++					    core_if->nextep_seq[i]);
++			}
++
++		}
++
++
++		DWC_WRITE_REG32(addr, depctl.d32);
++		DWC_DEBUGPL(DBG_PCDV, "DEPCTL=%08x\n", DWC_READ_REG32(addr));
++	}
++
++	/* Enable the Interrupt for this EP */
++	if (core_if->multiproc_int_enable) {
++		if (ep->is_in == 1) {
++			diepmsk_data_t diepmsk = {.d32 = 0 };
++			diepmsk.b.xfercompl = 1;
++			diepmsk.b.timeout = 1;
++			diepmsk.b.epdisabled = 1;
++			diepmsk.b.ahberr = 1;
++			diepmsk.b.intknepmis = 1;
++			if (!core_if->en_multiple_tx_fifo && core_if->dma_enable)
++				diepmsk.b.intknepmis = 0;
++			diepmsk.b.txfifoundrn = 1;	//?????
++			if (ep->type == DWC_OTG_EP_TYPE_ISOC) {
++				diepmsk.b.nak = 1;
++			}
++
++/*
++			if (core_if->dma_desc_enable) {
++				diepmsk.b.bna = 1;
++			}
++*/
++/*
++			if (core_if->dma_enable) {
++				doepmsk.b.nak = 1;
++			}
++*/
++			DWC_WRITE_REG32(&dev_if->dev_global_regs->
++					diepeachintmsk[ep->num], diepmsk.d32);
++
++		} else {
++			doepmsk_data_t doepmsk = {.d32 = 0 };
++			doepmsk.b.xfercompl = 1;
++			doepmsk.b.ahberr = 1;
++			doepmsk.b.epdisabled = 1;
++			if (ep->type == DWC_OTG_EP_TYPE_ISOC)
++				doepmsk.b.outtknepdis = 1;
++
++/*
++
++			if (core_if->dma_desc_enable) {
++				doepmsk.b.bna = 1;
++			}
++*/
++/*
++			doepmsk.b.babble = 1;
++			doepmsk.b.nyet = 1;
++			doepmsk.b.nak = 1;
++*/
++			DWC_WRITE_REG32(&dev_if->dev_global_regs->
++					doepeachintmsk[ep->num], doepmsk.d32);
++		}
++		DWC_MODIFY_REG32(&dev_if->dev_global_regs->deachintmsk,
++				 0, daintmsk.d32);
++	} else {
++		if (ep->type == DWC_OTG_EP_TYPE_ISOC) {
++			if (ep->is_in) {
++				diepmsk_data_t diepmsk = {.d32 = 0 };
++				diepmsk.b.nak = 1;
++				DWC_MODIFY_REG32(&dev_if->dev_global_regs->diepmsk, 0, diepmsk.d32);
++			} else {
++				doepmsk_data_t doepmsk = {.d32 = 0 };
++				doepmsk.b.outtknepdis = 1;
++				DWC_MODIFY_REG32(&dev_if->dev_global_regs->doepmsk, 0, doepmsk.d32);
++			}
++		}
++		DWC_MODIFY_REG32(&dev_if->dev_global_regs->daintmsk,
++				 0, daintmsk.d32);
++	}
++
++	DWC_DEBUGPL(DBG_PCDV, "DAINTMSK=%0x\n",
++		    DWC_READ_REG32(&dev_if->dev_global_regs->daintmsk));
++
++	ep->stall_clear_flag = 0;
++
++	return;
++}
++
++/**
++ * This function deactivates an EP. This is done by clearing the USB Active
++ * EP bit in the Device EP control register. Note: This function is not used
++ * for EP0. EP0 cannot be deactivated.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ * @param ep The EP to deactivate.
++ */
++void dwc_otg_ep_deactivate(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
++{
++	depctl_data_t depctl = {.d32 = 0 };
++	volatile uint32_t *addr;
++	daint_data_t daintmsk = {.d32 = 0 };
++	dcfg_data_t dcfg;
++	uint8_t i = 0;
++
++#ifdef DWC_UTE_PER_IO
++	ep->xiso_frame_num = 0xFFFFFFFF;
++	ep->xiso_active_xfers = 0;
++	ep->xiso_queued_xfers = 0;
++#endif
++
++	/* Read DEPCTLn register */
++	if (ep->is_in == 1) {
++		addr = &core_if->dev_if->in_ep_regs[ep->num]->diepctl;
++		daintmsk.ep.in = 1 << ep->num;
++	} else {
++		addr = &core_if->dev_if->out_ep_regs[ep->num]->doepctl;
++		daintmsk.ep.out = 1 << ep->num;
++	}
++
++	depctl.d32 = DWC_READ_REG32(addr);
++
++	depctl.b.usbactep = 0;
++
++	/* Update nextep_seq array and EPMSCNT in DCFG */
++	if (!(depctl.b.eptype & 1) && ep->is_in == 1) {	// NP EP IN
++		for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
++			if (core_if->nextep_seq[i] == ep->num)
++				break;
++		}
++		core_if->nextep_seq[i] = core_if->nextep_seq[ep->num];
++		if (core_if->first_in_nextep_seq == ep->num)
++			core_if->first_in_nextep_seq = i;
++		core_if->nextep_seq[ep->num] = 0xff;
++		depctl.b.nextep = 0;
++		dcfg.d32 =
++		    DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
++		dcfg.b.epmscnt--;
++		DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg,
++				dcfg.d32);
++
++		DWC_DEBUGPL(DBG_PCDV,
++			    "%s first_in_nextep_seq= %2d; nextep_seq[]:\n",
++			    __func__, core_if->first_in_nextep_seq);
++		for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
++			DWC_DEBUGPL(DBG_PCDV, "%2d\n", core_if->nextep_seq[i]);
++		}
++	}
++
++	if (ep->is_in == 1)
++		depctl.b.txfnum = 0;
++
++	if (core_if->dma_desc_enable)
++		depctl.b.epdis = 1;
++
++	DWC_WRITE_REG32(addr, depctl.d32);
++	depctl.d32 = DWC_READ_REG32(addr);
++	if (core_if->dma_enable && depctl.b.epena) {
++		depctl_data_t depctl = {.d32 = 0 };
++		if (ep->is_in) {
++			diepint_data_t diepint = {.d32 = 0 };
++
++			depctl.b.snak = 1;
++			DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[ep->num]->
++					diepctl, depctl.d32);
++/*			do { */
++				dwc_udelay(10);
++				diepint.d32 =
++				    DWC_READ_REG32(&core_if->
++						   dev_if->in_ep_regs[ep->num]->
++						   diepint);
++/*			} while (!diepint.b.inepnakeff); */
++			diepint.b.inepnakeff = 1;
++			DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[ep->num]->
++					diepint, diepint.d32);
++			depctl.d32 = 0;
++			depctl.b.epdis = 1;
++			DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[ep->num]->
++					diepctl, depctl.d32);
++/*			do {  */
++				dwc_udelay(10);
++				diepint.d32 =
++				    DWC_READ_REG32(&core_if->
++						   dev_if->in_ep_regs[ep->num]->
++						   diepint);
++/*			} while (!diepint.b.epdisabled); */
++			diepint.b.epdisabled = 1;
++			DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[ep->num]->
++					diepint, diepint.d32);
++		} else if (ep->type == DWC_OTG_EP_TYPE_ISOC) {
++			dctl_data_t dctl = {.d32 = 0};
++			gintmsk_data_t gintsts = {.d32 = 0};
++			doepint_data_t doepint = {.d32 = 0};
++			dctl.b.sgoutnak = 1;
++			DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
++					 dctl, 0, dctl.d32);
++			do {
++				dwc_udelay(10);
++				gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
++			} while (!gintsts.b.goutnakeff);
++			gintsts.d32 = 0;
++			gintsts.b.goutnakeff = 1;
++			DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
++
++			depctl.d32 = 0;
++			depctl.b.epdis = 1;
++			depctl.b.snak = 1;
++			DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[ep->num]->doepctl, depctl.d32);
++			do
++			{
++				dwc_udelay(10);
++				doepint.d32 = DWC_READ_REG32(&core_if->dev_if->
++											out_ep_regs[ep->num]->doepint);
++			} while (!doepint.b.epdisabled);
++
++			doepint.b.epdisabled = 1;
++			DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[ep->num]->doepint, doepint.d32);
++
++			dctl.d32 = 0;
++			dctl.b.cgoutnak = 1;
++			DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0, dctl.d32);
++		}
++	}
++
++	/* Disable the Interrupt for this EP */
++	if (core_if->multiproc_int_enable) {
++		DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->deachintmsk,
++				 daintmsk.d32, 0);
++
++		if (ep->is_in == 1) {
++			DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->
++					diepeachintmsk[ep->num], 0);
++		} else {
++			DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->
++					doepeachintmsk[ep->num], 0);
++		}
++	} else {
++		DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->daintmsk,
++				 daintmsk.d32, 0);
++	}
++
++}
++
++/**
++ * This function initializes dma descriptor chain.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ * @param ep The EP to start the transfer on.
++ */
++static void init_dma_desc_chain(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
++{
++	dwc_otg_dev_dma_desc_t *dma_desc;
++	uint32_t offset;
++	uint32_t xfer_est;
++	int i;
++	unsigned maxxfer_local, total_len;
++
++	if (!ep->is_in && ep->type == DWC_OTG_EP_TYPE_INTR &&
++	    (ep->maxpacket % 4)) {
++		maxxfer_local = ep->maxpacket;
++		total_len = ep->xfer_len;
++	} else {
++		maxxfer_local = ep->maxxfer;
++		total_len = ep->total_len;
++	}
++
++	ep->desc_cnt = (total_len / maxxfer_local) +
++	    ((total_len % maxxfer_local) ? 1 : 0);
++
++	if (!ep->desc_cnt)
++		ep->desc_cnt = 1;
++
++	if (ep->desc_cnt > MAX_DMA_DESC_CNT)
++		ep->desc_cnt = MAX_DMA_DESC_CNT;
++
++	dma_desc = ep->desc_addr;
++	if (maxxfer_local == ep->maxpacket) {
++		if ((total_len % maxxfer_local) &&
++		    (total_len / maxxfer_local < MAX_DMA_DESC_CNT)) {
++			xfer_est = (ep->desc_cnt - 1) * maxxfer_local +
++			    (total_len % maxxfer_local);
++		} else
++			xfer_est = ep->desc_cnt * maxxfer_local;
++	} else
++		xfer_est = total_len;
++	offset = 0;
++	for (i = 0; i < ep->desc_cnt; ++i) {
++		/** DMA Descriptor Setup */
++		if (xfer_est > maxxfer_local) {
++			dma_desc->status.b.bs = BS_HOST_BUSY;
++			dma_desc->status.b.l = 0;
++			dma_desc->status.b.ioc = 0;
++			dma_desc->status.b.sp = 0;
++			dma_desc->status.b.bytes = maxxfer_local;
++			dma_desc->buf = ep->dma_addr + offset;
++			dma_desc->status.b.sts = 0;
++			dma_desc->status.b.bs = BS_HOST_READY;
++
++			xfer_est -= maxxfer_local;
++			offset += maxxfer_local;
++		} else {
++			dma_desc->status.b.bs = BS_HOST_BUSY;
++			dma_desc->status.b.l = 1;
++			dma_desc->status.b.ioc = 1;
++			if (ep->is_in) {
++				dma_desc->status.b.sp =
++				    (xfer_est %
++				     ep->maxpacket) ? 1 : ((ep->
++							    sent_zlp) ? 1 : 0);
++				dma_desc->status.b.bytes = xfer_est;
++			} else {
++				if (maxxfer_local == ep->maxpacket)
++					dma_desc->status.b.bytes = xfer_est;
++				else
++					dma_desc->status.b.bytes =
++						xfer_est + ((4 - (xfer_est & 0x3)) & 0x3);
++			}
++
++			dma_desc->buf = ep->dma_addr + offset;
++			dma_desc->status.b.sts = 0;
++			dma_desc->status.b.bs = BS_HOST_READY;
++		}
++		dma_desc++;
++	}
++}
++
++/**
++ * This function is called when to write ISOC data into appropriate dedicated
++ * periodic FIFO.
++ */
++static int32_t write_isoc_tx_fifo(dwc_otg_core_if_t * core_if, dwc_ep_t * dwc_ep)
++{
++	dwc_otg_dev_if_t *dev_if = core_if->dev_if;
++	dwc_otg_dev_in_ep_regs_t *ep_regs;
++	dtxfsts_data_t txstatus = {.d32 = 0 };
++	uint32_t len = 0;
++	int epnum = dwc_ep->num;
++	int dwords;
++
++	DWC_DEBUGPL(DBG_PCD, "Dedicated TxFifo Empty: %d \n", epnum);
++
++	ep_regs = core_if->dev_if->in_ep_regs[epnum];
++
++	len = dwc_ep->xfer_len - dwc_ep->xfer_count;
++
++	if (len > dwc_ep->maxpacket) {
++		len = dwc_ep->maxpacket;
++	}
++
++	dwords = (len + 3) / 4;
++
++	/* While there is space in the queue and space in the FIFO and
++	 * More data to tranfer, Write packets to the Tx FIFO */
++	txstatus.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dtxfsts);
++	DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n", epnum, txstatus.d32);
++
++	while (txstatus.b.txfspcavail >= dwords &&
++	       dwc_ep->xfer_count < dwc_ep->xfer_len && dwc_ep->xfer_len != 0) {
++		/* Write the FIFO */
++		dwc_otg_ep_write_packet(core_if, dwc_ep, 0);
++
++		len = dwc_ep->xfer_len - dwc_ep->xfer_count;
++		if (len > dwc_ep->maxpacket) {
++			len = dwc_ep->maxpacket;
++		}
++
++		dwords = (len + 3) / 4;
++		txstatus.d32 =
++		    DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dtxfsts);
++		DWC_DEBUGPL(DBG_PCDV, "dtxfsts[%d]=0x%08x\n", epnum,
++			    txstatus.d32);
++	}
++
++	DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n", epnum,
++		    DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dtxfsts));
++
++	return 1;
++}
++
++/**
++ * This function does the setup for a data transfer for an EP and
++ * starts the transfer. For an IN transfer, the packets will be
++ * loaded into the appropriate Tx FIFO in the ISR. For OUT transfers,
++ * the packets are unloaded from the Rx FIFO in the ISR.  the ISR.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ * @param ep The EP to start the transfer on.
++ */
++
++void dwc_otg_ep_start_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
++{
++	depctl_data_t depctl;
++	deptsiz_data_t deptsiz;
++	gintmsk_data_t intr_mask = {.d32 = 0 };
++
++	DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s()\n", __func__);
++	DWC_DEBUGPL(DBG_PCD, "ep%d-%s xfer_len=%d xfer_cnt=%d "
++		    "xfer_buff=%p start_xfer_buff=%p, total_len = %d\n",
++		    ep->num, (ep->is_in ? "IN" : "OUT"), ep->xfer_len,
++		    ep->xfer_count, ep->xfer_buff, ep->start_xfer_buff,
++		    ep->total_len);
++	/* IN endpoint */
++	if (ep->is_in == 1) {
++		dwc_otg_dev_in_ep_regs_t *in_regs =
++		    core_if->dev_if->in_ep_regs[ep->num];
++
++		gnptxsts_data_t gtxstatus;
++
++		gtxstatus.d32 =
++		    DWC_READ_REG32(&core_if->core_global_regs->gnptxsts);
++
++		if (core_if->en_multiple_tx_fifo == 0
++		    && gtxstatus.b.nptxqspcavail == 0 && !core_if->dma_enable) {
++#ifdef DEBUG
++			DWC_PRINTF("TX Queue Full (0x%0x)\n", gtxstatus.d32);
++#endif
++			return;
++		}
++
++		depctl.d32 = DWC_READ_REG32(&(in_regs->diepctl));
++		deptsiz.d32 = DWC_READ_REG32(&(in_regs->dieptsiz));
++
++		if (ep->maxpacket > ep->maxxfer / MAX_PKT_CNT)
++			ep->xfer_len += (ep->maxxfer < (ep->total_len - ep->xfer_len)) ?
++				ep->maxxfer : (ep->total_len - ep->xfer_len);
++		else
++			ep->xfer_len += (MAX_PKT_CNT * ep->maxpacket < (ep->total_len - ep->xfer_len)) ?
++				 MAX_PKT_CNT * ep->maxpacket : (ep->total_len - ep->xfer_len);
++
++
++		/* Zero Length Packet? */
++		if ((ep->xfer_len - ep->xfer_count) == 0) {
++			deptsiz.b.xfersize = 0;
++			deptsiz.b.pktcnt = 1;
++		} else {
++			/* Program the transfer size and packet count
++			 *      as follows: xfersize = N * maxpacket +
++			 *      short_packet pktcnt = N + (short_packet
++			 *      exist ? 1 : 0)
++			 */
++			deptsiz.b.xfersize = ep->xfer_len - ep->xfer_count;
++			deptsiz.b.pktcnt =
++			    (ep->xfer_len - ep->xfer_count - 1 +
++			     ep->maxpacket) / ep->maxpacket;
++			if (ep->type == DWC_OTG_EP_TYPE_ISOC)
++				deptsiz.b.mc = deptsiz.b.pktcnt;
++		}
++
++		/* Write the DMA register */
++		if (core_if->dma_enable) {
++			if (core_if->dma_desc_enable == 0) {
++				if (ep->type != DWC_OTG_EP_TYPE_ISOC)
++					deptsiz.b.mc = 1;
++				DWC_WRITE_REG32(&in_regs->dieptsiz,
++						deptsiz.d32);
++				DWC_WRITE_REG32(&(in_regs->diepdma),
++						(uint32_t) ep->dma_addr);
++			} else {
++#ifdef DWC_UTE_CFI
++				/* The descriptor chain should be already initialized by now */
++				if (ep->buff_mode != BM_STANDARD) {
++					DWC_WRITE_REG32(&in_regs->diepdma,
++							ep->descs_dma_addr);
++				} else {
++#endif
++					init_dma_desc_chain(core_if, ep);
++				/** DIEPDMAn Register write */
++					DWC_WRITE_REG32(&in_regs->diepdma,
++							ep->dma_desc_addr);
++#ifdef DWC_UTE_CFI
++				}
++#endif
++			}
++		} else {
++			DWC_WRITE_REG32(&in_regs->dieptsiz, deptsiz.d32);
++			if (ep->type != DWC_OTG_EP_TYPE_ISOC) {
++				/**
++				 * Enable the Non-Periodic Tx FIFO empty interrupt,
++				 * or the Tx FIFO epmty interrupt in dedicated Tx FIFO mode,
++				 * the data will be written into the fifo by the ISR.
++				 */
++				if (core_if->en_multiple_tx_fifo == 0) {
++					intr_mask.b.nptxfempty = 1;
++					DWC_MODIFY_REG32
++					    (&core_if->core_global_regs->gintmsk,
++					     intr_mask.d32, intr_mask.d32);
++				} else {
++					/* Enable the Tx FIFO Empty Interrupt for this EP */
++					if (ep->xfer_len > 0) {
++						uint32_t fifoemptymsk = 0;
++						fifoemptymsk = 1 << ep->num;
++						DWC_MODIFY_REG32
++						    (&core_if->dev_if->dev_global_regs->dtknqr4_fifoemptymsk,
++						     0, fifoemptymsk);
++
++					}
++				}
++			}
++		}
++		if (!core_if->core_params->en_multiple_tx_fifo && core_if->dma_enable)
++			depctl.b.nextep = core_if->nextep_seq[ep->num];
++
++		if (ep->type == DWC_OTG_EP_TYPE_ISOC) {
++			dsts_data_t dsts = {.d32 = 0 };
++			if (ep->bInterval == 1) {
++				dsts.d32 =
++				    DWC_READ_REG32(&core_if->dev_if->
++						   dev_global_regs->dsts);
++				ep->frame_num = dsts.b.soffn + ep->bInterval;
++				if (ep->frame_num > 0x3FFF) {
++					ep->frm_overrun = 1;
++					ep->frame_num &= 0x3FFF;
++				} else
++					ep->frm_overrun = 0;
++				if (ep->frame_num & 0x1) {
++					depctl.b.setd1pid = 1;
++				} else {
++					depctl.b.setd0pid = 1;
++				}
++			}
++		}
++		/* EP enable, IN data in FIFO */
++		depctl.b.cnak = 1;
++		depctl.b.epena = 1;
++		DWC_WRITE_REG32(&in_regs->diepctl, depctl.d32);
++
++		if (!core_if->dma_enable && ep->type == DWC_OTG_EP_TYPE_ISOC) {
++				write_isoc_tx_fifo(core_if, ep);
++		}
++
++	} else {
++		/* OUT endpoint */
++		dwc_otg_dev_out_ep_regs_t *out_regs =
++		    core_if->dev_if->out_ep_regs[ep->num];
++
++		depctl.d32 = DWC_READ_REG32(&(out_regs->doepctl));
++		deptsiz.d32 = DWC_READ_REG32(&(out_regs->doeptsiz));
++
++		if (!core_if->dma_desc_enable) {
++			if (ep->maxpacket > ep->maxxfer / MAX_PKT_CNT)
++				ep->xfer_len += (ep->maxxfer < (ep->total_len - ep->xfer_len)) ?
++				ep->maxxfer : (ep->total_len - ep->xfer_len);
++                else
++					ep->xfer_len += (MAX_PKT_CNT * ep->maxpacket < (ep->total_len
++					- ep->xfer_len)) ? MAX_PKT_CNT * ep->maxpacket : (ep->total_len - ep->xfer_len);
++		}
++
++		/* Program the transfer size and packet count as follows:
++		 *
++		 *      pktcnt = N
++		 *      xfersize = N * maxpacket
++		 */
++		if ((ep->xfer_len - ep->xfer_count) == 0) {
++			/* Zero Length Packet */
++			deptsiz.b.xfersize = ep->maxpacket;
++			deptsiz.b.pktcnt = 1;
++		} else {
++			deptsiz.b.pktcnt =
++			    (ep->xfer_len - ep->xfer_count +
++			     (ep->maxpacket - 1)) / ep->maxpacket;
++			if (!core_if->dma_desc_enable) {
++				ep->xfer_len =
++					deptsiz.b.pktcnt * ep->maxpacket + ep->xfer_count;
++			}
++			deptsiz.b.xfersize = ep->xfer_len - ep->xfer_count;
++		}
++
++		DWC_DEBUGPL(DBG_PCDV, "ep%d xfersize=%d pktcnt=%d\n",
++			    ep->num, deptsiz.b.xfersize, deptsiz.b.pktcnt);
++
++		if (core_if->dma_enable) {
++			if (!core_if->dma_desc_enable) {
++				DWC_WRITE_REG32(&out_regs->doeptsiz,
++						deptsiz.d32);
++
++				DWC_WRITE_REG32(&(out_regs->doepdma),
++						(uint32_t) ep->dma_addr);
++			} else {
++#ifdef DWC_UTE_CFI
++				/* The descriptor chain should be already initialized by now */
++				if (ep->buff_mode != BM_STANDARD) {
++					DWC_WRITE_REG32(&out_regs->doepdma,
++							ep->descs_dma_addr);
++				} else {
++#endif
++					/** This is used for interrupt out transfers*/
++					if (!ep->xfer_len)
++						ep->xfer_len = ep->total_len;
++					init_dma_desc_chain(core_if, ep);
++
++					if (core_if->core_params->dev_out_nak) {
++						if (ep->type == DWC_OTG_EP_TYPE_BULK) {
++							deptsiz.b.pktcnt = (ep->total_len +
++								(ep->maxpacket - 1)) / ep->maxpacket;
++							deptsiz.b.xfersize = ep->total_len;
++							/* Remember initial value of doeptsiz */
++							core_if->start_doeptsiz_val[ep->num] = deptsiz.d32;
++							DWC_WRITE_REG32(&out_regs->doeptsiz,
++								deptsiz.d32);
++						}
++					}
++				/** DOEPDMAn Register write */
++					DWC_WRITE_REG32(&out_regs->doepdma,
++							ep->dma_desc_addr);
++#ifdef DWC_UTE_CFI
++				}
++#endif
++			}
++		} else {
++			DWC_WRITE_REG32(&out_regs->doeptsiz, deptsiz.d32);
++		}
++
++		if (ep->type == DWC_OTG_EP_TYPE_ISOC) {
++			dsts_data_t dsts = {.d32 = 0 };
++			if (ep->bInterval == 1) {
++				dsts.d32 =
++				    DWC_READ_REG32(&core_if->dev_if->
++						   dev_global_regs->dsts);
++				ep->frame_num = dsts.b.soffn + ep->bInterval;
++				if (ep->frame_num > 0x3FFF) {
++					ep->frm_overrun = 1;
++					ep->frame_num &= 0x3FFF;
++				} else
++					ep->frm_overrun = 0;
++
++				if (ep->frame_num & 0x1) {
++					depctl.b.setd1pid = 1;
++				} else {
++					depctl.b.setd0pid = 1;
++				}
++			}
++		}
++
++		/* EP enable */
++		depctl.b.cnak = 1;
++		depctl.b.epena = 1;
++
++		DWC_WRITE_REG32(&out_regs->doepctl, depctl.d32);
++
++		DWC_DEBUGPL(DBG_PCD, "DOEPCTL=%08x DOEPTSIZ=%08x\n",
++			    DWC_READ_REG32(&out_regs->doepctl),
++			    DWC_READ_REG32(&out_regs->doeptsiz));
++		DWC_DEBUGPL(DBG_PCD, "DAINTMSK=%08x GINTMSK=%08x\n",
++			    DWC_READ_REG32(&core_if->dev_if->dev_global_regs->
++					   daintmsk),
++			    DWC_READ_REG32(&core_if->core_global_regs->
++					   gintmsk));
++
++		/* Timer is scheduling only for out bulk transfers for
++		 * "Device DDMA OUT NAK Enhancement" feature to inform user
++		 * about received data payload in case of timeout
++		 */
++		if (core_if->core_params->dev_out_nak) {
++			if (ep->type == DWC_OTG_EP_TYPE_BULK) {
++				core_if->ep_xfer_info[ep->num].core_if = core_if;
++				core_if->ep_xfer_info[ep->num].ep = ep;
++				core_if->ep_xfer_info[ep->num].state = 1;
++
++				/* Start a timer for this transfer. */
++				DWC_TIMER_SCHEDULE(core_if->ep_xfer_timer[ep->num], 10000);
++			}
++		}
++	}
++}
++
++/**
++ * This function setup a zero length transfer in Buffer DMA and
++ * Slave modes for usb requests with zero field set
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ * @param ep The EP to start the transfer on.
++ *
++ */
++void dwc_otg_ep_start_zl_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
++{
++
++	depctl_data_t depctl;
++	deptsiz_data_t deptsiz;
++	gintmsk_data_t intr_mask = {.d32 = 0 };
++
++	DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s()\n", __func__);
++	DWC_PRINTF("zero length transfer is called\n");
++
++	/* IN endpoint */
++	if (ep->is_in == 1) {
++		dwc_otg_dev_in_ep_regs_t *in_regs =
++		    core_if->dev_if->in_ep_regs[ep->num];
++
++		depctl.d32 = DWC_READ_REG32(&(in_regs->diepctl));
++		deptsiz.d32 = DWC_READ_REG32(&(in_regs->dieptsiz));
++
++		deptsiz.b.xfersize = 0;
++		deptsiz.b.pktcnt = 1;
++
++		/* Write the DMA register */
++		if (core_if->dma_enable) {
++			if (core_if->dma_desc_enable == 0) {
++				deptsiz.b.mc = 1;
++				DWC_WRITE_REG32(&in_regs->dieptsiz,
++						deptsiz.d32);
++				DWC_WRITE_REG32(&(in_regs->diepdma),
++						(uint32_t) ep->dma_addr);
++			}
++		} else {
++			DWC_WRITE_REG32(&in_regs->dieptsiz, deptsiz.d32);
++			/**
++			 * Enable the Non-Periodic Tx FIFO empty interrupt,
++			 * or the Tx FIFO epmty interrupt in dedicated Tx FIFO mode,
++			 * the data will be written into the fifo by the ISR.
++			 */
++			if (core_if->en_multiple_tx_fifo == 0) {
++				intr_mask.b.nptxfempty = 1;
++				DWC_MODIFY_REG32(&core_if->
++						 core_global_regs->gintmsk,
++						 intr_mask.d32, intr_mask.d32);
++			} else {
++				/* Enable the Tx FIFO Empty Interrupt for this EP */
++				if (ep->xfer_len > 0) {
++					uint32_t fifoemptymsk = 0;
++					fifoemptymsk = 1 << ep->num;
++					DWC_MODIFY_REG32(&core_if->
++							 dev_if->dev_global_regs->dtknqr4_fifoemptymsk,
++							 0, fifoemptymsk);
++				}
++			}
++		}
++
++		if (!core_if->core_params->en_multiple_tx_fifo && core_if->dma_enable)
++			depctl.b.nextep = core_if->nextep_seq[ep->num];
++		/* EP enable, IN data in FIFO */
++		depctl.b.cnak = 1;
++		depctl.b.epena = 1;
++		DWC_WRITE_REG32(&in_regs->diepctl, depctl.d32);
++
++	} else {
++		/* OUT endpoint */
++		dwc_otg_dev_out_ep_regs_t *out_regs =
++		    core_if->dev_if->out_ep_regs[ep->num];
++
++		depctl.d32 = DWC_READ_REG32(&(out_regs->doepctl));
++		deptsiz.d32 = DWC_READ_REG32(&(out_regs->doeptsiz));
++
++		/* Zero Length Packet */
++		deptsiz.b.xfersize = ep->maxpacket;
++		deptsiz.b.pktcnt = 1;
++
++		if (core_if->dma_enable) {
++			if (!core_if->dma_desc_enable) {
++				DWC_WRITE_REG32(&out_regs->doeptsiz,
++						deptsiz.d32);
++
++				DWC_WRITE_REG32(&(out_regs->doepdma),
++						(uint32_t) ep->dma_addr);
++			}
++		} else {
++			DWC_WRITE_REG32(&out_regs->doeptsiz, deptsiz.d32);
++		}
++
++		/* EP enable */
++		depctl.b.cnak = 1;
++		depctl.b.epena = 1;
++
++		DWC_WRITE_REG32(&out_regs->doepctl, depctl.d32);
++
++	}
++}
++
++/**
++ * This function does the setup for a data transfer for EP0 and starts
++ * the transfer.  For an IN transfer, the packets will be loaded into
++ * the appropriate Tx FIFO in the ISR. For OUT transfers, the packets are
++ * unloaded from the Rx FIFO in the ISR.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ * @param ep The EP0 data.
++ */
++void dwc_otg_ep0_start_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
++{
++	depctl_data_t depctl;
++	deptsiz0_data_t deptsiz;
++	gintmsk_data_t intr_mask = {.d32 = 0 };
++	dwc_otg_dev_dma_desc_t *dma_desc;
++
++	DWC_DEBUGPL(DBG_PCD, "ep%d-%s xfer_len=%d xfer_cnt=%d "
++		    "xfer_buff=%p start_xfer_buff=%p \n",
++		    ep->num, (ep->is_in ? "IN" : "OUT"), ep->xfer_len,
++		    ep->xfer_count, ep->xfer_buff, ep->start_xfer_buff);
++
++	ep->total_len = ep->xfer_len;
++
++	/* IN endpoint */
++	if (ep->is_in == 1) {
++		dwc_otg_dev_in_ep_regs_t *in_regs =
++		    core_if->dev_if->in_ep_regs[0];
++
++		gnptxsts_data_t gtxstatus;
++
++		if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
++			depctl.d32 = DWC_READ_REG32(&in_regs->diepctl);
++			if (depctl.b.epena)
++				return;
++		}
++
++		gtxstatus.d32 =
++		    DWC_READ_REG32(&core_if->core_global_regs->gnptxsts);
++
++		/* If dedicated FIFO every time flush fifo before enable ep*/
++		if (core_if->en_multiple_tx_fifo == 0
++		    && gtxstatus.b.nptxqspcavail == 0
++		    && !core_if->dma_enable) {
++#ifdef DEBUG
++			deptsiz.d32 = DWC_READ_REG32(&in_regs->dieptsiz);
++			DWC_DEBUGPL(DBG_PCD, "DIEPCTL0=%0x\n",
++				    DWC_READ_REG32(&in_regs->diepctl));
++			DWC_DEBUGPL(DBG_PCD, "DIEPTSIZ0=%0x (sz=%d, pcnt=%d)\n",
++				    deptsiz.d32,
++				    deptsiz.b.xfersize, deptsiz.b.pktcnt);
++			DWC_PRINTF("TX Queue or FIFO Full (0x%0x)\n",
++				   gtxstatus.d32);
++#endif
++			return;
++		}
++
++		depctl.d32 = DWC_READ_REG32(&in_regs->diepctl);
++		deptsiz.d32 = DWC_READ_REG32(&in_regs->dieptsiz);
++
++		/* Zero Length Packet? */
++		if (ep->xfer_len == 0) {
++			deptsiz.b.xfersize = 0;
++			deptsiz.b.pktcnt = 1;
++		} else {
++			/* Program the transfer size and packet count
++			 *      as follows: xfersize = N * maxpacket +
++			 *      short_packet pktcnt = N + (short_packet
++			 *      exist ? 1 : 0)
++			 */
++			if (ep->xfer_len > ep->maxpacket) {
++				ep->xfer_len = ep->maxpacket;
++				deptsiz.b.xfersize = ep->maxpacket;
++			} else {
++				deptsiz.b.xfersize = ep->xfer_len;
++			}
++			deptsiz.b.pktcnt = 1;
++
++		}
++		DWC_DEBUGPL(DBG_PCDV,
++			    "IN len=%d  xfersize=%d pktcnt=%d [%08x]\n",
++			    ep->xfer_len, deptsiz.b.xfersize, deptsiz.b.pktcnt,
++			    deptsiz.d32);
++
++		/* Write the DMA register */
++		if (core_if->dma_enable) {
++			if (core_if->dma_desc_enable == 0) {
++				DWC_WRITE_REG32(&in_regs->dieptsiz,
++						deptsiz.d32);
++
++				DWC_WRITE_REG32(&(in_regs->diepdma),
++						(uint32_t) ep->dma_addr);
++			} else {
++				dma_desc = core_if->dev_if->in_desc_addr;
++
++				/** DMA Descriptor Setup */
++				dma_desc->status.b.bs = BS_HOST_BUSY;
++				dma_desc->status.b.l = 1;
++				dma_desc->status.b.ioc = 1;
++				dma_desc->status.b.sp =
++				    (ep->xfer_len == ep->maxpacket) ? 0 : 1;
++				dma_desc->status.b.bytes = ep->xfer_len;
++				dma_desc->buf = ep->dma_addr;
++				dma_desc->status.b.sts = 0;
++				dma_desc->status.b.bs = BS_HOST_READY;
++
++				/** DIEPDMA0 Register write */
++				DWC_WRITE_REG32(&in_regs->diepdma,
++						core_if->
++						dev_if->dma_in_desc_addr);
++			}
++		} else {
++			DWC_WRITE_REG32(&in_regs->dieptsiz, deptsiz.d32);
++		}
++
++		if (!core_if->core_params->en_multiple_tx_fifo && core_if->dma_enable)
++			depctl.b.nextep = core_if->nextep_seq[ep->num];
++		/* EP enable, IN data in FIFO */
++		depctl.b.cnak = 1;
++		depctl.b.epena = 1;
++		DWC_WRITE_REG32(&in_regs->diepctl, depctl.d32);
++
++		/**
++		 * Enable the Non-Periodic Tx FIFO empty interrupt, the
++		 * data will be written into the fifo by the ISR.
++		 */
++		if (!core_if->dma_enable) {
++			if (core_if->en_multiple_tx_fifo == 0) {
++				intr_mask.b.nptxfempty = 1;
++				DWC_MODIFY_REG32(&core_if->
++						 core_global_regs->gintmsk,
++						 intr_mask.d32, intr_mask.d32);
++			} else {
++				/* Enable the Tx FIFO Empty Interrupt for this EP */
++				if (ep->xfer_len > 0) {
++					uint32_t fifoemptymsk = 0;
++					fifoemptymsk |= 1 << ep->num;
++					DWC_MODIFY_REG32(&core_if->
++							 dev_if->dev_global_regs->dtknqr4_fifoemptymsk,
++							 0, fifoemptymsk);
++				}
++			}
++		}
++	} else {
++		/* OUT endpoint */
++		dwc_otg_dev_out_ep_regs_t *out_regs =
++		    core_if->dev_if->out_ep_regs[0];
++
++		depctl.d32 = DWC_READ_REG32(&out_regs->doepctl);
++		deptsiz.d32 = DWC_READ_REG32(&out_regs->doeptsiz);
++
++		/* Program the transfer size and packet count as follows:
++		 *      xfersize = N * (maxpacket + 4 - (maxpacket % 4))
++		 *      pktcnt = N                                                                                      */
++		/* Zero Length Packet */
++		deptsiz.b.xfersize = ep->maxpacket;
++		deptsiz.b.pktcnt = 1;
++		if (core_if->snpsid >= OTG_CORE_REV_3_00a)
++			deptsiz.b.supcnt = 3;
++
++		DWC_DEBUGPL(DBG_PCDV, "len=%d  xfersize=%d pktcnt=%d\n",
++			    ep->xfer_len, deptsiz.b.xfersize, deptsiz.b.pktcnt);
++
++		if (core_if->dma_enable) {
++			if (!core_if->dma_desc_enable) {
++				DWC_WRITE_REG32(&out_regs->doeptsiz,
++						deptsiz.d32);
++
++				DWC_WRITE_REG32(&(out_regs->doepdma),
++						(uint32_t) ep->dma_addr);
++			} else {
++				dma_desc = core_if->dev_if->out_desc_addr;
++
++				/** DMA Descriptor Setup */
++				dma_desc->status.b.bs = BS_HOST_BUSY;
++				if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
++					dma_desc->status.b.mtrf = 0;
++					dma_desc->status.b.sr = 0;
++				}
++				dma_desc->status.b.l = 1;
++				dma_desc->status.b.ioc = 1;
++				dma_desc->status.b.bytes = ep->maxpacket;
++				dma_desc->buf = ep->dma_addr;
++				dma_desc->status.b.sts = 0;
++				dma_desc->status.b.bs = BS_HOST_READY;
++
++				/** DOEPDMA0 Register write */
++				DWC_WRITE_REG32(&out_regs->doepdma,
++						core_if->dev_if->
++						dma_out_desc_addr);
++			}
++		} else {
++			DWC_WRITE_REG32(&out_regs->doeptsiz, deptsiz.d32);
++		}
++
++		/* EP enable */
++		depctl.b.cnak = 1;
++		depctl.b.epena = 1;
++		DWC_WRITE_REG32(&(out_regs->doepctl), depctl.d32);
++	}
++}
++
++/**
++ * This function continues control IN transfers started by
++ * dwc_otg_ep0_start_transfer, when the transfer does not fit in a
++ * single packet.  NOTE: The DIEPCTL0/DOEPCTL0 registers only have one
++ * bit for the packet count.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ * @param ep The EP0 data.
++ */
++void dwc_otg_ep0_continue_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
++{
++	depctl_data_t depctl;
++	deptsiz0_data_t deptsiz;
++	gintmsk_data_t intr_mask = {.d32 = 0 };
++	dwc_otg_dev_dma_desc_t *dma_desc;
++
++	if (ep->is_in == 1) {
++		dwc_otg_dev_in_ep_regs_t *in_regs =
++		    core_if->dev_if->in_ep_regs[0];
++		gnptxsts_data_t tx_status = {.d32 = 0 };
++
++		tx_status.d32 =
++		    DWC_READ_REG32(&core_if->core_global_regs->gnptxsts);
++		/** @todo Should there be check for room in the Tx
++		 * Status Queue.  If not remove the code above this comment. */
++
++		depctl.d32 = DWC_READ_REG32(&in_regs->diepctl);
++		deptsiz.d32 = DWC_READ_REG32(&in_regs->dieptsiz);
++
++		/* Program the transfer size and packet count
++		 *      as follows: xfersize = N * maxpacket +
++		 *      short_packet pktcnt = N + (short_packet
++		 *      exist ? 1 : 0)
++		 */
++
++		if (core_if->dma_desc_enable == 0) {
++			deptsiz.b.xfersize =
++			    (ep->total_len - ep->xfer_count) >
++			    ep->maxpacket ? ep->maxpacket : (ep->total_len -
++							     ep->xfer_count);
++			deptsiz.b.pktcnt = 1;
++			if (core_if->dma_enable == 0) {
++				ep->xfer_len += deptsiz.b.xfersize;
++			} else {
++				ep->xfer_len = deptsiz.b.xfersize;
++			}
++			DWC_WRITE_REG32(&in_regs->dieptsiz, deptsiz.d32);
++		} else {
++			ep->xfer_len =
++			    (ep->total_len - ep->xfer_count) >
++			    ep->maxpacket ? ep->maxpacket : (ep->total_len -
++							     ep->xfer_count);
++
++			dma_desc = core_if->dev_if->in_desc_addr;
++
++			/** DMA Descriptor Setup */
++			dma_desc->status.b.bs = BS_HOST_BUSY;
++			dma_desc->status.b.l = 1;
++			dma_desc->status.b.ioc = 1;
++			dma_desc->status.b.sp =
++			    (ep->xfer_len == ep->maxpacket) ? 0 : 1;
++			dma_desc->status.b.bytes = ep->xfer_len;
++			dma_desc->buf = ep->dma_addr;
++			dma_desc->status.b.sts = 0;
++			dma_desc->status.b.bs = BS_HOST_READY;
++
++			/** DIEPDMA0 Register write */
++			DWC_WRITE_REG32(&in_regs->diepdma,
++					core_if->dev_if->dma_in_desc_addr);
++		}
++
++		DWC_DEBUGPL(DBG_PCDV,
++			    "IN len=%d  xfersize=%d pktcnt=%d [%08x]\n",
++			    ep->xfer_len, deptsiz.b.xfersize, deptsiz.b.pktcnt,
++			    deptsiz.d32);
++
++		/* Write the DMA register */
++		if (core_if->hwcfg2.b.architecture == DWC_INT_DMA_ARCH) {
++			if (core_if->dma_desc_enable == 0)
++				DWC_WRITE_REG32(&(in_regs->diepdma),
++						(uint32_t) ep->dma_addr);
++		}
++		if (!core_if->core_params->en_multiple_tx_fifo && core_if->dma_enable)
++			depctl.b.nextep = core_if->nextep_seq[ep->num];
++		/* EP enable, IN data in FIFO */
++		depctl.b.cnak = 1;
++		depctl.b.epena = 1;
++		DWC_WRITE_REG32(&in_regs->diepctl, depctl.d32);
++
++		/**
++		 * Enable the Non-Periodic Tx FIFO empty interrupt, the
++		 * data will be written into the fifo by the ISR.
++		 */
++		if (!core_if->dma_enable) {
++			if (core_if->en_multiple_tx_fifo == 0) {
++				/* First clear it from GINTSTS */
++				intr_mask.b.nptxfempty = 1;
++				DWC_MODIFY_REG32(&core_if->
++						 core_global_regs->gintmsk,
++						 intr_mask.d32, intr_mask.d32);
++
++			} else {
++				/* Enable the Tx FIFO Empty Interrupt for this EP */
++				if (ep->xfer_len > 0) {
++					uint32_t fifoemptymsk = 0;
++					fifoemptymsk |= 1 << ep->num;
++					DWC_MODIFY_REG32(&core_if->
++							 dev_if->dev_global_regs->dtknqr4_fifoemptymsk,
++							 0, fifoemptymsk);
++				}
++			}
++		}
++	} else {
++		dwc_otg_dev_out_ep_regs_t *out_regs =
++		    core_if->dev_if->out_ep_regs[0];
++
++		depctl.d32 = DWC_READ_REG32(&out_regs->doepctl);
++		deptsiz.d32 = DWC_READ_REG32(&out_regs->doeptsiz);
++
++		/* Program the transfer size and packet count
++		 *      as follows: xfersize = N * maxpacket +
++		 *      short_packet pktcnt = N + (short_packet
++		 *      exist ? 1 : 0)
++		 */
++		deptsiz.b.xfersize = ep->maxpacket;
++		deptsiz.b.pktcnt = 1;
++
++		if (core_if->dma_desc_enable == 0) {
++			DWC_WRITE_REG32(&out_regs->doeptsiz, deptsiz.d32);
++		} else {
++			dma_desc = core_if->dev_if->out_desc_addr;
++
++			/** DMA Descriptor Setup */
++			dma_desc->status.b.bs = BS_HOST_BUSY;
++			dma_desc->status.b.l = 1;
++			dma_desc->status.b.ioc = 1;
++			dma_desc->status.b.bytes = ep->maxpacket;
++			dma_desc->buf = ep->dma_addr;
++			dma_desc->status.b.sts = 0;
++			dma_desc->status.b.bs = BS_HOST_READY;
++
++			/** DOEPDMA0 Register write */
++			DWC_WRITE_REG32(&out_regs->doepdma,
++					core_if->dev_if->dma_out_desc_addr);
++		}
++
++		DWC_DEBUGPL(DBG_PCDV,
++			    "IN len=%d  xfersize=%d pktcnt=%d [%08x]\n",
++			    ep->xfer_len, deptsiz.b.xfersize, deptsiz.b.pktcnt,
++			    deptsiz.d32);
++
++		/* Write the DMA register */
++		if (core_if->hwcfg2.b.architecture == DWC_INT_DMA_ARCH) {
++			if (core_if->dma_desc_enable == 0)
++				DWC_WRITE_REG32(&(out_regs->doepdma),
++						(uint32_t) ep->dma_addr);
++
++		}
++
++		/* EP enable, IN data in FIFO */
++		depctl.b.cnak = 1;
++		depctl.b.epena = 1;
++		DWC_WRITE_REG32(&out_regs->doepctl, depctl.d32);
++
++	}
++}
++
++#ifdef DEBUG
++void dump_msg(const u8 * buf, unsigned int length)
++{
++	unsigned int start, num, i;
++	char line[52], *p;
++
++	if (length >= 512)
++		return;
++	start = 0;
++	while (length > 0) {
++		num = length < 16u ? length : 16u;
++		p = line;
++		for (i = 0; i < num; ++i) {
++			if (i == 8)
++				*p++ = ' ';
++			DWC_SPRINTF(p, " %02x", buf[i]);
++			p += 3;
++		}
++		*p = 0;
++		DWC_PRINTF("%6x: %s\n", start, line);
++		buf += num;
++		start += num;
++		length -= num;
++	}
++}
++#else
++static inline void dump_msg(const u8 * buf, unsigned int length)
++{
++}
++#endif
++
++/**
++ * This function writes a packet into the Tx FIFO associated with the
++ * EP. For non-periodic EPs the non-periodic Tx FIFO is written.  For
++ * periodic EPs the periodic Tx FIFO associated with the EP is written
++ * with all packets for the next micro-frame.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ * @param ep The EP to write packet for.
++ * @param dma Indicates if DMA is being used.
++ */
++void dwc_otg_ep_write_packet(dwc_otg_core_if_t * core_if, dwc_ep_t * ep,
++			     int dma)
++{
++	/**
++	 * The buffer is padded to DWORD on a per packet basis in
++	 * slave/dma mode if the MPS is not DWORD aligned. The last
++	 * packet, if short, is also padded to a multiple of DWORD.
++	 *
++	 * ep->xfer_buff always starts DWORD aligned in memory and is a
++	 * multiple of DWORD in length
++	 *
++	 * ep->xfer_len can be any number of bytes
++	 *
++	 * ep->xfer_count is a multiple of ep->maxpacket until the last
++	 *	packet
++	 *
++	 * FIFO access is DWORD */
++
++	uint32_t i;
++	uint32_t byte_count;
++	uint32_t dword_count;
++	uint32_t *fifo;
++	uint32_t *data_buff = (uint32_t *) ep->xfer_buff;
++
++	DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s(%p,%p)\n", __func__, core_if,
++		    ep);
++	if (ep->xfer_count >= ep->xfer_len) {
++		DWC_WARN("%s() No data for EP%d!!!\n", __func__, ep->num);
++		return;
++	}
++
++	/* Find the byte length of the packet either short packet or MPS */
++	if ((ep->xfer_len - ep->xfer_count) < ep->maxpacket) {
++		byte_count = ep->xfer_len - ep->xfer_count;
++	} else {
++		byte_count = ep->maxpacket;
++	}
++
++	/* Find the DWORD length, padded by extra bytes as neccessary if MPS
++	 * is not a multiple of DWORD */
++	dword_count = (byte_count + 3) / 4;
++
++#ifdef VERBOSE
++	dump_msg(ep->xfer_buff, byte_count);
++#endif
++
++	/**@todo NGS Where are the Periodic Tx FIFO addresses
++	 * intialized?	What should this be? */
++
++	fifo = core_if->data_fifo[ep->num];
++
++	DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "fifo=%p buff=%p *p=%08x bc=%d\n",
++		    fifo, data_buff, *data_buff, byte_count);
++
++	if (!dma) {
++		for (i = 0; i < dword_count; i++, data_buff++) {
++			DWC_WRITE_REG32(fifo, *data_buff);
++		}
++	}
++
++	ep->xfer_count += byte_count;
++	ep->xfer_buff += byte_count;
++	ep->dma_addr += byte_count;
++}
++
++/**
++ * Set the EP STALL.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ * @param ep The EP to set the stall on.
++ */
++void dwc_otg_ep_set_stall(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
++{
++	depctl_data_t depctl;
++	volatile uint32_t *depctl_addr;
++
++	DWC_DEBUGPL(DBG_PCD, "%s ep%d-%s\n", __func__, ep->num,
++		    (ep->is_in ? "IN" : "OUT"));
++
++	if (ep->is_in == 1) {
++		depctl_addr = &(core_if->dev_if->in_ep_regs[ep->num]->diepctl);
++		depctl.d32 = DWC_READ_REG32(depctl_addr);
++
++		/* set the disable and stall bits */
++		if (depctl.b.epena) {
++			depctl.b.epdis = 1;
++		}
++		depctl.b.stall = 1;
++		DWC_WRITE_REG32(depctl_addr, depctl.d32);
++	} else {
++		depctl_addr = &(core_if->dev_if->out_ep_regs[ep->num]->doepctl);
++		depctl.d32 = DWC_READ_REG32(depctl_addr);
++
++		/* set the stall bit */
++		depctl.b.stall = 1;
++		DWC_WRITE_REG32(depctl_addr, depctl.d32);
++	}
++
++	DWC_DEBUGPL(DBG_PCD, "DEPCTL=%0x\n", DWC_READ_REG32(depctl_addr));
++
++	return;
++}
++
++/**
++ * Clear the EP STALL.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ * @param ep The EP to clear stall from.
++ */
++void dwc_otg_ep_clear_stall(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
++{
++	depctl_data_t depctl;
++	volatile uint32_t *depctl_addr;
++
++	DWC_DEBUGPL(DBG_PCD, "%s ep%d-%s\n", __func__, ep->num,
++		    (ep->is_in ? "IN" : "OUT"));
++
++	if (ep->is_in == 1) {
++		depctl_addr = &(core_if->dev_if->in_ep_regs[ep->num]->diepctl);
++	} else {
++		depctl_addr = &(core_if->dev_if->out_ep_regs[ep->num]->doepctl);
++	}
++
++	depctl.d32 = DWC_READ_REG32(depctl_addr);
++
++	/* clear the stall bits */
++	depctl.b.stall = 0;
++
++	/*
++	 * USB Spec 9.4.5: For endpoints using data toggle, regardless
++	 * of whether an endpoint has the Halt feature set, a
++	 * ClearFeature(ENDPOINT_HALT) request always results in the
++	 * data toggle being reinitialized to DATA0.
++	 */
++	if (ep->type == DWC_OTG_EP_TYPE_INTR ||
++	    ep->type == DWC_OTG_EP_TYPE_BULK) {
++		depctl.b.setd0pid = 1;	/* DATA0 */
++	}
++
++	DWC_WRITE_REG32(depctl_addr, depctl.d32);
++	DWC_DEBUGPL(DBG_PCD, "DEPCTL=%0x\n", DWC_READ_REG32(depctl_addr));
++	return;
++}
++
++/**
++ * This function reads a packet from the Rx FIFO into the destination
++ * buffer. To read SETUP data use dwc_otg_read_setup_packet.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ * @param dest	  Destination buffer for the packet.
++ * @param bytes  Number of bytes to copy to the destination.
++ */
++void dwc_otg_read_packet(dwc_otg_core_if_t * core_if,
++			 uint8_t * dest, uint16_t bytes)
++{
++	int i;
++	int word_count = (bytes + 3) / 4;
++
++	volatile uint32_t *fifo = core_if->data_fifo[0];
++	uint32_t *data_buff = (uint32_t *) dest;
++
++	/**
++	 * @todo Account for the case where _dest is not dword aligned. This
++	 * requires reading data from the FIFO into a uint32_t temp buffer,
++	 * then moving it into the data buffer.
++	 */
++
++	DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s(%p,%p,%d)\n", __func__,
++		    core_if, dest, bytes);
++
++	for (i = 0; i < word_count; i++, data_buff++) {
++		*data_buff = DWC_READ_REG32(fifo);
++	}
++
++	return;
++}
++
++/**
++ * This functions reads the device registers and prints them
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ */
++void dwc_otg_dump_dev_registers(dwc_otg_core_if_t * core_if)
++{
++	int i;
++	volatile uint32_t *addr;
++
++	DWC_PRINTF("Device Global Registers\n");
++	addr = &core_if->dev_if->dev_global_regs->dcfg;
++	DWC_PRINTF("DCFG		 @0x%08lX : 0x%08X\n",
++		   (unsigned long)addr, DWC_READ_REG32(addr));
++	addr = &core_if->dev_if->dev_global_regs->dctl;
++	DWC_PRINTF("DCTL		 @0x%08lX : 0x%08X\n",
++		   (unsigned long)addr, DWC_READ_REG32(addr));
++	addr = &core_if->dev_if->dev_global_regs->dsts;
++	DWC_PRINTF("DSTS		 @0x%08lX : 0x%08X\n",
++		   (unsigned long)addr, DWC_READ_REG32(addr));
++	addr = &core_if->dev_if->dev_global_regs->diepmsk;
++	DWC_PRINTF("DIEPMSK	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
++		   DWC_READ_REG32(addr));
++	addr = &core_if->dev_if->dev_global_regs->doepmsk;
++	DWC_PRINTF("DOEPMSK	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
++		   DWC_READ_REG32(addr));
++	addr = &core_if->dev_if->dev_global_regs->daint;
++	DWC_PRINTF("DAINT	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
++		   DWC_READ_REG32(addr));
++	addr = &core_if->dev_if->dev_global_regs->daintmsk;
++	DWC_PRINTF("DAINTMSK	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
++		   DWC_READ_REG32(addr));
++	addr = &core_if->dev_if->dev_global_regs->dtknqr1;
++	DWC_PRINTF("DTKNQR1	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
++		   DWC_READ_REG32(addr));
++	if (core_if->hwcfg2.b.dev_token_q_depth > 6) {
++		addr = &core_if->dev_if->dev_global_regs->dtknqr2;
++		DWC_PRINTF("DTKNQR2	 @0x%08lX : 0x%08X\n",
++			   (unsigned long)addr, DWC_READ_REG32(addr));
++	}
++
++	addr = &core_if->dev_if->dev_global_regs->dvbusdis;
++	DWC_PRINTF("DVBUSID	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
++		   DWC_READ_REG32(addr));
++
++	addr = &core_if->dev_if->dev_global_regs->dvbuspulse;
++	DWC_PRINTF("DVBUSPULSE	@0x%08lX : 0x%08X\n",
++		   (unsigned long)addr, DWC_READ_REG32(addr));
++
++	addr = &core_if->dev_if->dev_global_regs->dtknqr3_dthrctl;
++	DWC_PRINTF("DTKNQR3_DTHRCTL	 @0x%08lX : 0x%08X\n",
++		   (unsigned long)addr, DWC_READ_REG32(addr));
++
++	if (core_if->hwcfg2.b.dev_token_q_depth > 22) {
++		addr = &core_if->dev_if->dev_global_regs->dtknqr4_fifoemptymsk;
++		DWC_PRINTF("DTKNQR4	 @0x%08lX : 0x%08X\n",
++			   (unsigned long)addr, DWC_READ_REG32(addr));
++	}
++
++	addr = &core_if->dev_if->dev_global_regs->dtknqr4_fifoemptymsk;
++	DWC_PRINTF("FIFOEMPMSK	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
++		   DWC_READ_REG32(addr));
++
++	if (core_if->hwcfg2.b.multi_proc_int) {
++
++		addr = &core_if->dev_if->dev_global_regs->deachint;
++		DWC_PRINTF("DEACHINT	 @0x%08lX : 0x%08X\n",
++			   (unsigned long)addr, DWC_READ_REG32(addr));
++		addr = &core_if->dev_if->dev_global_regs->deachintmsk;
++		DWC_PRINTF("DEACHINTMSK	 @0x%08lX : 0x%08X\n",
++			   (unsigned long)addr, DWC_READ_REG32(addr));
++
++		for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
++			addr =
++			    &core_if->dev_if->
++			    dev_global_regs->diepeachintmsk[i];
++			DWC_PRINTF("DIEPEACHINTMSK[%d]	 @0x%08lX : 0x%08X\n",
++				   i, (unsigned long)addr,
++				   DWC_READ_REG32(addr));
++		}
++
++		for (i = 0; i <= core_if->dev_if->num_out_eps; i++) {
++			addr =
++			    &core_if->dev_if->
++			    dev_global_regs->doepeachintmsk[i];
++			DWC_PRINTF("DOEPEACHINTMSK[%d]	 @0x%08lX : 0x%08X\n",
++				   i, (unsigned long)addr,
++				   DWC_READ_REG32(addr));
++		}
++	}
++
++	for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
++		DWC_PRINTF("Device IN EP %d Registers\n", i);
++		addr = &core_if->dev_if->in_ep_regs[i]->diepctl;
++		DWC_PRINTF("DIEPCTL	 @0x%08lX : 0x%08X\n",
++			   (unsigned long)addr, DWC_READ_REG32(addr));
++		addr = &core_if->dev_if->in_ep_regs[i]->diepint;
++		DWC_PRINTF("DIEPINT	 @0x%08lX : 0x%08X\n",
++			   (unsigned long)addr, DWC_READ_REG32(addr));
++		addr = &core_if->dev_if->in_ep_regs[i]->dieptsiz;
++		DWC_PRINTF("DIETSIZ	 @0x%08lX : 0x%08X\n",
++			   (unsigned long)addr, DWC_READ_REG32(addr));
++		addr = &core_if->dev_if->in_ep_regs[i]->diepdma;
++		DWC_PRINTF("DIEPDMA	 @0x%08lX : 0x%08X\n",
++			   (unsigned long)addr, DWC_READ_REG32(addr));
++		addr = &core_if->dev_if->in_ep_regs[i]->dtxfsts;
++		DWC_PRINTF("DTXFSTS	 @0x%08lX : 0x%08X\n",
++			   (unsigned long)addr, DWC_READ_REG32(addr));
++		addr = &core_if->dev_if->in_ep_regs[i]->diepdmab;
++		DWC_PRINTF("DIEPDMAB	 @0x%08lX : 0x%08X\n",
++			   (unsigned long)addr, 0 /*DWC_READ_REG32(addr) */ );
++	}
++
++	for (i = 0; i <= core_if->dev_if->num_out_eps; i++) {
++		DWC_PRINTF("Device OUT EP %d Registers\n", i);
++		addr = &core_if->dev_if->out_ep_regs[i]->doepctl;
++		DWC_PRINTF("DOEPCTL	 @0x%08lX : 0x%08X\n",
++			   (unsigned long)addr, DWC_READ_REG32(addr));
++		addr = &core_if->dev_if->out_ep_regs[i]->doepint;
++		DWC_PRINTF("DOEPINT	 @0x%08lX : 0x%08X\n",
++			   (unsigned long)addr, DWC_READ_REG32(addr));
++		addr = &core_if->dev_if->out_ep_regs[i]->doeptsiz;
++		DWC_PRINTF("DOETSIZ	 @0x%08lX : 0x%08X\n",
++			   (unsigned long)addr, DWC_READ_REG32(addr));
++		addr = &core_if->dev_if->out_ep_regs[i]->doepdma;
++		DWC_PRINTF("DOEPDMA	 @0x%08lX : 0x%08X\n",
++			   (unsigned long)addr, DWC_READ_REG32(addr));
++		if (core_if->dma_enable) {	/* Don't access this register in SLAVE mode */
++			addr = &core_if->dev_if->out_ep_regs[i]->doepdmab;
++			DWC_PRINTF("DOEPDMAB	 @0x%08lX : 0x%08X\n",
++				   (unsigned long)addr, DWC_READ_REG32(addr));
++		}
++
++	}
++}
++
++/**
++ * This functions reads the SPRAM and prints its content
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ */
++void dwc_otg_dump_spram(dwc_otg_core_if_t * core_if)
++{
++	volatile uint8_t *addr, *start_addr, *end_addr;
++
++	DWC_PRINTF("SPRAM Data:\n");
++	start_addr = (void *)core_if->core_global_regs;
++	DWC_PRINTF("Base Address: 0x%8lX\n", (unsigned long)start_addr);
++	start_addr += 0x00028000;
++	end_addr = (void *)core_if->core_global_regs;
++	end_addr += 0x000280e0;
++
++	for (addr = start_addr; addr < end_addr; addr += 16) {
++		DWC_PRINTF
++		    ("0x%8lX:\t%2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X\n",
++		     (unsigned long)addr, addr[0], addr[1], addr[2], addr[3],
++		     addr[4], addr[5], addr[6], addr[7], addr[8], addr[9],
++		     addr[10], addr[11], addr[12], addr[13], addr[14], addr[15]
++		    );
++	}
++
++	return;
++}
++
++/**
++ * This function reads the host registers and prints them
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ */
++void dwc_otg_dump_host_registers(dwc_otg_core_if_t * core_if)
++{
++	int i;
++	volatile uint32_t *addr;
++
++	DWC_PRINTF("Host Global Registers\n");
++	addr = &core_if->host_if->host_global_regs->hcfg;
++	DWC_PRINTF("HCFG		 @0x%08lX : 0x%08X\n",
++		   (unsigned long)addr, DWC_READ_REG32(addr));
++	addr = &core_if->host_if->host_global_regs->hfir;
++	DWC_PRINTF("HFIR		 @0x%08lX : 0x%08X\n",
++		   (unsigned long)addr, DWC_READ_REG32(addr));
++	addr = &core_if->host_if->host_global_regs->hfnum;
++	DWC_PRINTF("HFNUM	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
++		   DWC_READ_REG32(addr));
++	addr = &core_if->host_if->host_global_regs->hptxsts;
++	DWC_PRINTF("HPTXSTS	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
++		   DWC_READ_REG32(addr));
++	addr = &core_if->host_if->host_global_regs->haint;
++	DWC_PRINTF("HAINT	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
++		   DWC_READ_REG32(addr));
++	addr = &core_if->host_if->host_global_regs->haintmsk;
++	DWC_PRINTF("HAINTMSK	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
++		   DWC_READ_REG32(addr));
++	if (core_if->dma_desc_enable) {
++		addr = &core_if->host_if->host_global_regs->hflbaddr;
++		DWC_PRINTF("HFLBADDR	 @0x%08lX : 0x%08X\n",
++			   (unsigned long)addr, DWC_READ_REG32(addr));
++	}
++
++	addr = core_if->host_if->hprt0;
++	DWC_PRINTF("HPRT0	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
++		   DWC_READ_REG32(addr));
++
++	for (i = 0; i < core_if->core_params->host_channels; i++) {
++		DWC_PRINTF("Host Channel %d Specific Registers\n", i);
++		addr = &core_if->host_if->hc_regs[i]->hcchar;
++		DWC_PRINTF("HCCHAR	 @0x%08lX : 0x%08X\n",
++			   (unsigned long)addr, DWC_READ_REG32(addr));
++		addr = &core_if->host_if->hc_regs[i]->hcsplt;
++		DWC_PRINTF("HCSPLT	 @0x%08lX : 0x%08X\n",
++			   (unsigned long)addr, DWC_READ_REG32(addr));
++		addr = &core_if->host_if->hc_regs[i]->hcint;
++		DWC_PRINTF("HCINT	 @0x%08lX : 0x%08X\n",
++			   (unsigned long)addr, DWC_READ_REG32(addr));
++		addr = &core_if->host_if->hc_regs[i]->hcintmsk;
++		DWC_PRINTF("HCINTMSK	 @0x%08lX : 0x%08X\n",
++			   (unsigned long)addr, DWC_READ_REG32(addr));
++		addr = &core_if->host_if->hc_regs[i]->hctsiz;
++		DWC_PRINTF("HCTSIZ	 @0x%08lX : 0x%08X\n",
++			   (unsigned long)addr, DWC_READ_REG32(addr));
++		addr = &core_if->host_if->hc_regs[i]->hcdma;
++		DWC_PRINTF("HCDMA	 @0x%08lX : 0x%08X\n",
++			   (unsigned long)addr, DWC_READ_REG32(addr));
++		if (core_if->dma_desc_enable) {
++			addr = &core_if->host_if->hc_regs[i]->hcdmab;
++			DWC_PRINTF("HCDMAB	 @0x%08lX : 0x%08X\n",
++				   (unsigned long)addr, DWC_READ_REG32(addr));
++		}
++
++	}
++	return;
++}
++
++/**
++ * This function reads the core global registers and prints them
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ */
++void dwc_otg_dump_global_registers(dwc_otg_core_if_t * core_if)
++{
++	int i, ep_num;
++	volatile uint32_t *addr;
++	char *txfsiz;
++
++	DWC_PRINTF("Core Global Registers\n");
++	addr = &core_if->core_global_regs->gotgctl;
++	DWC_PRINTF("GOTGCTL	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
++		   DWC_READ_REG32(addr));
++	addr = &core_if->core_global_regs->gotgint;
++	DWC_PRINTF("GOTGINT	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
++		   DWC_READ_REG32(addr));
++	addr = &core_if->core_global_regs->gahbcfg;
++	DWC_PRINTF("GAHBCFG	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
++		   DWC_READ_REG32(addr));
++	addr = &core_if->core_global_regs->gusbcfg;
++	DWC_PRINTF("GUSBCFG	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
++		   DWC_READ_REG32(addr));
++	addr = &core_if->core_global_regs->grstctl;
++	DWC_PRINTF("GRSTCTL	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
++		   DWC_READ_REG32(addr));
++	addr = &core_if->core_global_regs->gintsts;
++	DWC_PRINTF("GINTSTS	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
++		   DWC_READ_REG32(addr));
++	addr = &core_if->core_global_regs->gintmsk;
++	DWC_PRINTF("GINTMSK	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
++		   DWC_READ_REG32(addr));
++	addr = &core_if->core_global_regs->grxstsr;
++	DWC_PRINTF("GRXSTSR	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
++		   DWC_READ_REG32(addr));
++	addr = &core_if->core_global_regs->grxfsiz;
++	DWC_PRINTF("GRXFSIZ	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
++		   DWC_READ_REG32(addr));
++	addr = &core_if->core_global_regs->gnptxfsiz;
++	DWC_PRINTF("GNPTXFSIZ @0x%08lX : 0x%08X\n", (unsigned long)addr,
++		   DWC_READ_REG32(addr));
++	addr = &core_if->core_global_regs->gnptxsts;
++	DWC_PRINTF("GNPTXSTS	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
++		   DWC_READ_REG32(addr));
++	addr = &core_if->core_global_regs->gi2cctl;
++	DWC_PRINTF("GI2CCTL	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
++		   DWC_READ_REG32(addr));
++	addr = &core_if->core_global_regs->gpvndctl;
++	DWC_PRINTF("GPVNDCTL	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
++		   DWC_READ_REG32(addr));
++	addr = &core_if->core_global_regs->ggpio;
++	DWC_PRINTF("GGPIO	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
++		   DWC_READ_REG32(addr));
++	addr = &core_if->core_global_regs->guid;
++	DWC_PRINTF("GUID		 @0x%08lX : 0x%08X\n",
++		   (unsigned long)addr, DWC_READ_REG32(addr));
++	addr = &core_if->core_global_regs->gsnpsid;
++	DWC_PRINTF("GSNPSID	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
++		   DWC_READ_REG32(addr));
++	addr = &core_if->core_global_regs->ghwcfg1;
++	DWC_PRINTF("GHWCFG1	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
++		   DWC_READ_REG32(addr));
++	addr = &core_if->core_global_regs->ghwcfg2;
++	DWC_PRINTF("GHWCFG2	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
++		   DWC_READ_REG32(addr));
++	addr = &core_if->core_global_regs->ghwcfg3;
++	DWC_PRINTF("GHWCFG3	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
++		   DWC_READ_REG32(addr));
++	addr = &core_if->core_global_regs->ghwcfg4;
++	DWC_PRINTF("GHWCFG4	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
++		   DWC_READ_REG32(addr));
++	addr = &core_if->core_global_regs->glpmcfg;
++	DWC_PRINTF("GLPMCFG	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
++		   DWC_READ_REG32(addr));
++	addr = &core_if->core_global_regs->gpwrdn;
++	DWC_PRINTF("GPWRDN	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
++		   DWC_READ_REG32(addr));
++	addr = &core_if->core_global_regs->gdfifocfg;
++	DWC_PRINTF("GDFIFOCFG	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
++		   DWC_READ_REG32(addr));
++	addr = &core_if->core_global_regs->adpctl;
++	DWC_PRINTF("ADPCTL	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
++		   dwc_otg_adp_read_reg(core_if));
++	addr = &core_if->core_global_regs->hptxfsiz;
++	DWC_PRINTF("HPTXFSIZ	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
++		   DWC_READ_REG32(addr));
++
++	if (core_if->en_multiple_tx_fifo == 0) {
++		ep_num = core_if->hwcfg4.b.num_dev_perio_in_ep;
++		txfsiz = "DPTXFSIZ";
++	} else {
++		ep_num = core_if->hwcfg4.b.num_in_eps;
++		txfsiz = "DIENPTXF";
++	}
++	for (i = 0; i < ep_num; i++) {
++		addr = &core_if->core_global_regs->dtxfsiz[i];
++		DWC_PRINTF("%s[%d] @0x%08lX : 0x%08X\n", txfsiz, i + 1,
++			   (unsigned long)addr, DWC_READ_REG32(addr));
++	}
++	addr = core_if->pcgcctl;
++	DWC_PRINTF("PCGCCTL	 @0x%08lX : 0x%08X\n", (unsigned long)addr,
++		   DWC_READ_REG32(addr));
++}
++
++/**
++ * Flush a Tx FIFO.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ * @param num Tx FIFO to flush.
++ */
++void dwc_otg_flush_tx_fifo(dwc_otg_core_if_t * core_if, const int num)
++{
++	dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
++	volatile grstctl_t greset = {.d32 = 0 };
++	int count = 0;
++
++	DWC_DEBUGPL((DBG_CIL | DBG_PCDV), "Flush Tx FIFO %d\n", num);
++
++	greset.b.txfflsh = 1;
++	greset.b.txfnum = num;
++	DWC_WRITE_REG32(&global_regs->grstctl, greset.d32);
++
++	do {
++		greset.d32 = DWC_READ_REG32(&global_regs->grstctl);
++		if (++count > 10000) {
++			DWC_WARN("%s() HANG! GRSTCTL=%0x GNPTXSTS=0x%08x\n",
++				 __func__, greset.d32,
++				 DWC_READ_REG32(&global_regs->gnptxsts));
++			break;
++		}
++		dwc_udelay(1);
++	} while (greset.b.txfflsh == 1);
++
++	/* Wait for 3 PHY Clocks */
++	dwc_udelay(1);
++}
++
++/**
++ * Flush Rx FIFO.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ */
++void dwc_otg_flush_rx_fifo(dwc_otg_core_if_t * core_if)
++{
++	dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
++	volatile grstctl_t greset = {.d32 = 0 };
++	int count = 0;
++
++	DWC_DEBUGPL((DBG_CIL | DBG_PCDV), "%s\n", __func__);
++	/*
++	 *
++	 */
++	greset.b.rxfflsh = 1;
++	DWC_WRITE_REG32(&global_regs->grstctl, greset.d32);
++
++	do {
++		greset.d32 = DWC_READ_REG32(&global_regs->grstctl);
++		if (++count > 10000) {
++			DWC_WARN("%s() HANG! GRSTCTL=%0x\n", __func__,
++				 greset.d32);
++			break;
++		}
++		dwc_udelay(1);
++	} while (greset.b.rxfflsh == 1);
++
++	/* Wait for 3 PHY Clocks */
++	dwc_udelay(1);
++}
++
++/**
++ * Do core a soft reset of the core.  Be careful with this because it
++ * resets all the internal state machines of the core.
++ */
++void dwc_otg_core_reset(dwc_otg_core_if_t * core_if)
++{
++	dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
++	volatile grstctl_t greset = {.d32 = 0 };
++	int count = 0;
++
++	DWC_DEBUGPL(DBG_CILV, "%s\n", __func__);
++	/* Wait for AHB master IDLE state. */
++	do {
++		dwc_udelay(10);
++		greset.d32 = DWC_READ_REG32(&global_regs->grstctl);
++		if (++count > 100000) {
++			DWC_WARN("%s() HANG! AHB Idle GRSTCTL=%0x\n", __func__,
++				 greset.d32);
++			return;
++		}
++	}
++	while (greset.b.ahbidle == 0);
++
++	/* Core Soft Reset */
++	count = 0;
++	greset.b.csftrst = 1;
++	DWC_WRITE_REG32(&global_regs->grstctl, greset.d32);
++	do {
++		greset.d32 = DWC_READ_REG32(&global_regs->grstctl);
++		if (++count > 10000) {
++			DWC_WARN("%s() HANG! Soft Reset GRSTCTL=%0x\n",
++				 __func__, greset.d32);
++			break;
++		}
++		dwc_udelay(1);
++	}
++	while (greset.b.csftrst == 1);
++
++	/* Wait for 3 PHY Clocks */
++	dwc_mdelay(100);
++}
++
++uint8_t dwc_otg_is_device_mode(dwc_otg_core_if_t * _core_if)
++{
++	return (dwc_otg_mode(_core_if) != DWC_HOST_MODE);
++}
++
++uint8_t dwc_otg_is_host_mode(dwc_otg_core_if_t * _core_if)
++{
++	return (dwc_otg_mode(_core_if) == DWC_HOST_MODE);
++}
++
++/**
++ * Register HCD callbacks. The callbacks are used to start and stop
++ * the HCD for interrupt processing.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ * @param cb the HCD callback structure.
++ * @param p pointer to be passed to callback function (usb_hcd*).
++ */
++void dwc_otg_cil_register_hcd_callbacks(dwc_otg_core_if_t * core_if,
++					dwc_otg_cil_callbacks_t * cb, void *p)
++{
++	core_if->hcd_cb = cb;
++	cb->p = p;
++}
++
++/**
++ * Register PCD callbacks. The callbacks are used to start and stop
++ * the PCD for interrupt processing.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ * @param cb the PCD callback structure.
++ * @param p pointer to be passed to callback function (pcd*).
++ */
++void dwc_otg_cil_register_pcd_callbacks(dwc_otg_core_if_t * core_if,
++					dwc_otg_cil_callbacks_t * cb, void *p)
++{
++	core_if->pcd_cb = cb;
++	cb->p = p;
++}
++
++#ifdef DWC_EN_ISOC
++
++/**
++ * This function writes isoc data per 1 (micro)frame into tx fifo
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ * @param ep The EP to start the transfer on.
++ *
++ */
++void write_isoc_frame_data(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
++{
++	dwc_otg_dev_in_ep_regs_t *ep_regs;
++	dtxfsts_data_t txstatus = {.d32 = 0 };
++	uint32_t len = 0;
++	uint32_t dwords;
++
++	ep->xfer_len = ep->data_per_frame;
++	ep->xfer_count = 0;
++
++	ep_regs = core_if->dev_if->in_ep_regs[ep->num];
++
++	len = ep->xfer_len - ep->xfer_count;
++
++	if (len > ep->maxpacket) {
++		len = ep->maxpacket;
++	}
++
++	dwords = (len + 3) / 4;
++
++	/* While there is space in the queue and space in the FIFO and
++	 * More data to tranfer, Write packets to the Tx FIFO */
++	txstatus.d32 =
++	    DWC_READ_REG32(&core_if->dev_if->in_ep_regs[ep->num]->dtxfsts);
++	DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n", ep->num, txstatus.d32);
++
++	while (txstatus.b.txfspcavail > dwords &&
++	       ep->xfer_count < ep->xfer_len && ep->xfer_len != 0) {
++		/* Write the FIFO */
++		dwc_otg_ep_write_packet(core_if, ep, 0);
++
++		len = ep->xfer_len - ep->xfer_count;
++		if (len > ep->maxpacket) {
++			len = ep->maxpacket;
++		}
++
++		dwords = (len + 3) / 4;
++		txstatus.d32 =
++		    DWC_READ_REG32(&core_if->dev_if->in_ep_regs[ep->num]->
++				   dtxfsts);
++		DWC_DEBUGPL(DBG_PCDV, "dtxfsts[%d]=0x%08x\n", ep->num,
++			    txstatus.d32);
++	}
++}
++
++/**
++ * This function initializes a descriptor chain for Isochronous transfer
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ * @param ep The EP to start the transfer on.
++ *
++ */
++void dwc_otg_iso_ep_start_frm_transfer(dwc_otg_core_if_t * core_if,
++				       dwc_ep_t * ep)
++{
++	deptsiz_data_t deptsiz = {.d32 = 0 };
++	depctl_data_t depctl = {.d32 = 0 };
++	dsts_data_t dsts = {.d32 = 0 };
++	volatile uint32_t *addr;
++
++	if (ep->is_in) {
++		addr = &core_if->dev_if->in_ep_regs[ep->num]->diepctl;
++	} else {
++		addr = &core_if->dev_if->out_ep_regs[ep->num]->doepctl;
++	}
++
++	ep->xfer_len = ep->data_per_frame;
++	ep->xfer_count = 0;
++	ep->xfer_buff = ep->cur_pkt_addr;
++	ep->dma_addr = ep->cur_pkt_dma_addr;
++
++	if (ep->is_in) {
++		/* Program the transfer size and packet count
++		 *      as follows: xfersize = N * maxpacket +
++		 *      short_packet pktcnt = N + (short_packet
++		 *      exist ? 1 : 0)
++		 */
++		deptsiz.b.xfersize = ep->xfer_len;
++		deptsiz.b.pktcnt =
++		    (ep->xfer_len - 1 + ep->maxpacket) / ep->maxpacket;
++		deptsiz.b.mc = deptsiz.b.pktcnt;
++		DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[ep->num]->dieptsiz,
++				deptsiz.d32);
++
++		/* Write the DMA register */
++		if (core_if->dma_enable) {
++			DWC_WRITE_REG32(&
++					(core_if->dev_if->in_ep_regs[ep->num]->
++					 diepdma), (uint32_t) ep->dma_addr);
++		}
++	} else {
++		deptsiz.b.pktcnt =
++		    (ep->xfer_len + (ep->maxpacket - 1)) / ep->maxpacket;
++		deptsiz.b.xfersize = deptsiz.b.pktcnt * ep->maxpacket;
++
++		DWC_WRITE_REG32(&core_if->dev_if->
++				out_ep_regs[ep->num]->doeptsiz, deptsiz.d32);
++
++		if (core_if->dma_enable) {
++			DWC_WRITE_REG32(&
++					(core_if->dev_if->
++					 out_ep_regs[ep->num]->doepdma),
++					(uint32_t) ep->dma_addr);
++		}
++	}
++
++	/** Enable endpoint, clear nak  */
++
++	depctl.d32 = 0;
++	if (ep->bInterval == 1) {
++		dsts.d32 =
++		    DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
++		ep->next_frame = dsts.b.soffn + ep->bInterval;
++
++		if (ep->next_frame & 0x1) {
++			depctl.b.setd1pid = 1;
++		} else {
++			depctl.b.setd0pid = 1;
++		}
++	} else {
++		ep->next_frame += ep->bInterval;
++
++		if (ep->next_frame & 0x1) {
++			depctl.b.setd1pid = 1;
++		} else {
++			depctl.b.setd0pid = 1;
++		}
++	}
++	depctl.b.epena = 1;
++	depctl.b.cnak = 1;
++
++	DWC_MODIFY_REG32(addr, 0, depctl.d32);
++	depctl.d32 = DWC_READ_REG32(addr);
++
++	if (ep->is_in && core_if->dma_enable == 0) {
++		write_isoc_frame_data(core_if, ep);
++	}
++
++}
++#endif /* DWC_EN_ISOC */
++
++static void dwc_otg_set_uninitialized(int32_t * p, int size)
++{
++	int i;
++	for (i = 0; i < size; i++) {
++		p[i] = -1;
++	}
++}
++
++static int dwc_otg_param_initialized(int32_t val)
++{
++	return val != -1;
++}
++
++static int dwc_otg_setup_params(dwc_otg_core_if_t * core_if)
++{
++	int i;
++	gintsts_data_t gintsts;
++	gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
++
++	core_if->core_params = DWC_ALLOC(sizeof(*core_if->core_params));
++	if (!core_if->core_params) {
++		return -DWC_E_NO_MEMORY;
++	}
++	dwc_otg_set_uninitialized((int32_t *) core_if->core_params,
++				  sizeof(*core_if->core_params) /
++				  sizeof(int32_t));
++	DWC_PRINTF("Setting default values for core params\n");
++	dwc_otg_set_param_otg_cap(core_if, dwc_param_otg_cap_default);
++	dwc_otg_set_param_dma_enable(core_if, dwc_param_dma_enable_default);
++	dwc_otg_set_param_dma_desc_enable(core_if,
++					  dwc_param_dma_desc_enable_default);
++	dwc_otg_set_param_opt(core_if, dwc_param_opt_default);
++	dwc_otg_set_param_dma_burst_size(core_if,
++					 dwc_param_dma_burst_size_default);
++	dwc_otg_set_param_host_support_fs_ls_low_power(core_if,
++						       dwc_param_host_support_fs_ls_low_power_default);
++	dwc_otg_set_param_enable_dynamic_fifo(core_if,
++					      dwc_param_enable_dynamic_fifo_default);
++	dwc_otg_set_param_data_fifo_size(core_if,
++					 dwc_param_data_fifo_size_default);
++	dwc_otg_set_param_dev_rx_fifo_size(core_if,
++					   dwc_param_dev_rx_fifo_size_default);
++	dwc_otg_set_param_dev_nperio_tx_fifo_size(core_if,
++						  dwc_param_dev_nperio_tx_fifo_size_default);
++	dwc_otg_set_param_host_rx_fifo_size(core_if,
++					    dwc_param_host_rx_fifo_size_default);
++	dwc_otg_set_param_host_nperio_tx_fifo_size(core_if,
++						   dwc_param_host_nperio_tx_fifo_size_default);
++	dwc_otg_set_param_host_perio_tx_fifo_size(core_if,
++						  dwc_param_host_perio_tx_fifo_size_default);
++	dwc_otg_set_param_max_transfer_size(core_if,
++					    dwc_param_max_transfer_size_default);
++	dwc_otg_set_param_max_packet_count(core_if,
++					   dwc_param_max_packet_count_default);
++	dwc_otg_set_param_host_channels(core_if,
++					dwc_param_host_channels_default);
++	dwc_otg_set_param_dev_endpoints(core_if,
++					dwc_param_dev_endpoints_default);
++	dwc_otg_set_param_phy_type(core_if, dwc_param_phy_type_default);
++	dwc_otg_set_param_speed(core_if, dwc_param_speed_default);
++	dwc_otg_set_param_host_ls_low_power_phy_clk(core_if,
++						    dwc_param_host_ls_low_power_phy_clk_default);
++	dwc_otg_set_param_phy_ulpi_ddr(core_if, dwc_param_phy_ulpi_ddr_default);
++	dwc_otg_set_param_phy_ulpi_ext_vbus(core_if,
++					    dwc_param_phy_ulpi_ext_vbus_default);
++	dwc_otg_set_param_phy_utmi_width(core_if,
++					 dwc_param_phy_utmi_width_default);
++	dwc_otg_set_param_ts_dline(core_if, dwc_param_ts_dline_default);
++	dwc_otg_set_param_i2c_enable(core_if, dwc_param_i2c_enable_default);
++	dwc_otg_set_param_ulpi_fs_ls(core_if, dwc_param_ulpi_fs_ls_default);
++	dwc_otg_set_param_en_multiple_tx_fifo(core_if,
++					      dwc_param_en_multiple_tx_fifo_default);
++
++	if (gintsts.b.curmode) {
++		/* Force device mode to get power-on values of device FIFOs */
++		gusbcfg_data_t gusbcfg = {.d32 = 0 };
++		gusbcfg.d32 =  DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
++		gusbcfg.b.force_dev_mode = 1;
++		DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, gusbcfg.d32);
++		dwc_mdelay(100);
++		for (i = 0; i < 15; i++) {
++		dwc_otg_set_param_dev_perio_tx_fifo_size(core_if,
++							 dwc_param_dev_perio_tx_fifo_size_default, i);
++		}
++		for (i = 0; i < 15; i++) {
++			dwc_otg_set_param_dev_tx_fifo_size(core_if,
++							   dwc_param_dev_tx_fifo_size_default, i);
++		}
++		gusbcfg.d32 =  DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
++		gusbcfg.b.force_dev_mode = 0;
++		DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, gusbcfg.d32);
++		dwc_mdelay(100);
++	} else {
++		for (i = 0; i < 15; i++) {
++			dwc_otg_set_param_dev_perio_tx_fifo_size(core_if,
++				dwc_param_dev_perio_tx_fifo_size_default, i);
++		}
++		for (i = 0; i < 15; i++) {
++			dwc_otg_set_param_dev_tx_fifo_size(core_if,
++				dwc_param_dev_tx_fifo_size_default, i);
++		}
++	}
++
++	dwc_otg_set_param_thr_ctl(core_if, dwc_param_thr_ctl_default);
++	dwc_otg_set_param_mpi_enable(core_if, dwc_param_mpi_enable_default);
++	dwc_otg_set_param_pti_enable(core_if, dwc_param_pti_enable_default);
++	dwc_otg_set_param_lpm_enable(core_if, dwc_param_lpm_enable_default);
++
++	dwc_otg_set_param_besl_enable(core_if, dwc_param_besl_enable_default);
++	dwc_otg_set_param_baseline_besl(core_if, dwc_param_baseline_besl_default);
++	dwc_otg_set_param_deep_besl(core_if, dwc_param_deep_besl_default);
++
++	dwc_otg_set_param_ic_usb_cap(core_if, dwc_param_ic_usb_cap_default);
++	dwc_otg_set_param_tx_thr_length(core_if,
++					dwc_param_tx_thr_length_default);
++	dwc_otg_set_param_rx_thr_length(core_if,
++					dwc_param_rx_thr_length_default);
++	dwc_otg_set_param_ahb_thr_ratio(core_if,
++					dwc_param_ahb_thr_ratio_default);
++	dwc_otg_set_param_power_down(core_if, dwc_param_power_down_default);
++	dwc_otg_set_param_reload_ctl(core_if, dwc_param_reload_ctl_default);
++	dwc_otg_set_param_dev_out_nak(core_if, dwc_param_dev_out_nak_default);
++	dwc_otg_set_param_cont_on_bna(core_if, dwc_param_cont_on_bna_default);
++	dwc_otg_set_param_ahb_single(core_if, dwc_param_ahb_single_default);
++	dwc_otg_set_param_otg_ver(core_if, dwc_param_otg_ver_default);
++	dwc_otg_set_param_adp_enable(core_if, dwc_param_adp_enable_default);
++	return 0;
++}
++
++uint8_t dwc_otg_is_dma_enable(dwc_otg_core_if_t * core_if)
++{
++	return core_if->dma_enable;
++}
++
++/* Checks if the parameter is outside of its valid range of values */
++#define DWC_OTG_PARAM_TEST(_param_, _low_, _high_) \
++		(((_param_) < (_low_)) || \
++		((_param_) > (_high_)))
++
++/* Parameter access functions */
++int dwc_otg_set_param_otg_cap(dwc_otg_core_if_t * core_if, int32_t val)
++{
++	int valid;
++	int retval = 0;
++	if (DWC_OTG_PARAM_TEST(val, 0, 2)) {
++		DWC_WARN("Wrong value for otg_cap parameter\n");
++		DWC_WARN("otg_cap parameter must be 0,1 or 2\n");
++		retval = -DWC_E_INVALID;
++		goto out;
++	}
++
++	valid = 1;
++	switch (val) {
++	case DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE:
++		if (core_if->hwcfg2.b.op_mode !=
++		    DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG)
++			valid = 0;
++		break;
++	case DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE:
++		if ((core_if->hwcfg2.b.op_mode !=
++		     DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG)
++		    && (core_if->hwcfg2.b.op_mode !=
++			DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG)
++		    && (core_if->hwcfg2.b.op_mode !=
++			DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE)
++		    && (core_if->hwcfg2.b.op_mode !=
++			DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST)) {
++			valid = 0;
++		}
++		break;
++	case DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE:
++		/* always valid */
++		break;
++	}
++	if (!valid) {
++		if (dwc_otg_param_initialized(core_if->core_params->otg_cap)) {
++			DWC_ERROR
++			    ("%d invalid for otg_cap paremter. Check HW configuration.\n",
++			     val);
++		}
++		val =
++		    (((core_if->hwcfg2.b.op_mode ==
++		       DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG)
++		      || (core_if->hwcfg2.b.op_mode ==
++			  DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG)
++		      || (core_if->hwcfg2.b.op_mode ==
++			  DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE)
++		      || (core_if->hwcfg2.b.op_mode ==
++			  DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST)) ?
++		     DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE :
++		     DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
++		retval = -DWC_E_INVALID;
++	}
++
++	core_if->core_params->otg_cap = val;
++out:
++	return retval;
++}
++
++int32_t dwc_otg_get_param_otg_cap(dwc_otg_core_if_t * core_if)
++{
++	return core_if->core_params->otg_cap;
++}
++
++int dwc_otg_set_param_opt(dwc_otg_core_if_t * core_if, int32_t val)
++{
++	if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
++		DWC_WARN("Wrong value for opt parameter\n");
++		return -DWC_E_INVALID;
++	}
++	core_if->core_params->opt = val;
++	return 0;
++}
++
++int32_t dwc_otg_get_param_opt(dwc_otg_core_if_t * core_if)
++{
++	return core_if->core_params->opt;
++}
++
++int dwc_otg_set_param_dma_enable(dwc_otg_core_if_t * core_if, int32_t val)
++{
++	int retval = 0;
++	if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
++		DWC_WARN("Wrong value for dma enable\n");
++		return -DWC_E_INVALID;
++	}
++
++	if ((val == 1) && (core_if->hwcfg2.b.architecture == 0)) {
++		if (dwc_otg_param_initialized(core_if->core_params->dma_enable)) {
++			DWC_ERROR
++			    ("%d invalid for dma_enable paremter. Check HW configuration.\n",
++			     val);
++		}
++		val = 0;
++		retval = -DWC_E_INVALID;
++	}
++
++	core_if->core_params->dma_enable = val;
++	if (val == 0) {
++		dwc_otg_set_param_dma_desc_enable(core_if, 0);
++	}
++	return retval;
++}
++
++int32_t dwc_otg_get_param_dma_enable(dwc_otg_core_if_t * core_if)
++{
++	return core_if->core_params->dma_enable;
++}
++
++int dwc_otg_set_param_dma_desc_enable(dwc_otg_core_if_t * core_if, int32_t val)
++{
++	int retval = 0;
++	if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
++		DWC_WARN("Wrong value for dma_enable\n");
++		DWC_WARN("dma_desc_enable must be 0 or 1\n");
++		return -DWC_E_INVALID;
++	}
++
++	if ((val == 1)
++	    && ((dwc_otg_get_param_dma_enable(core_if) == 0)
++		|| (core_if->hwcfg4.b.desc_dma == 0))) {
++		if (dwc_otg_param_initialized
++		    (core_if->core_params->dma_desc_enable)) {
++			DWC_ERROR
++			    ("%d invalid for dma_desc_enable paremter. Check HW configuration.\n",
++			     val);
++		}
++		val = 0;
++		retval = -DWC_E_INVALID;
++	}
++	core_if->core_params->dma_desc_enable = val;
++	return retval;
++}
++
++int32_t dwc_otg_get_param_dma_desc_enable(dwc_otg_core_if_t * core_if)
++{
++	return core_if->core_params->dma_desc_enable;
++}
++
++int dwc_otg_set_param_host_support_fs_ls_low_power(dwc_otg_core_if_t * core_if,
++						   int32_t val)
++{
++	if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
++		DWC_WARN("Wrong value for host_support_fs_low_power\n");
++		DWC_WARN("host_support_fs_low_power must be 0 or 1\n");
++		return -DWC_E_INVALID;
++	}
++	core_if->core_params->host_support_fs_ls_low_power = val;
++	return 0;
++}
++
++int32_t dwc_otg_get_param_host_support_fs_ls_low_power(dwc_otg_core_if_t *
++						       core_if)
++{
++	return core_if->core_params->host_support_fs_ls_low_power;
++}
++
++int dwc_otg_set_param_enable_dynamic_fifo(dwc_otg_core_if_t * core_if,
++					  int32_t val)
++{
++	int retval = 0;
++	if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
++		DWC_WARN("Wrong value for enable_dynamic_fifo\n");
++		DWC_WARN("enable_dynamic_fifo must be 0 or 1\n");
++		return -DWC_E_INVALID;
++	}
++
++	if ((val == 1) && (core_if->hwcfg2.b.dynamic_fifo == 0)) {
++		if (dwc_otg_param_initialized
++		    (core_if->core_params->enable_dynamic_fifo)) {
++			DWC_ERROR
++			    ("%d invalid for enable_dynamic_fifo paremter. Check HW configuration.\n",
++			     val);
++		}
++		val = 0;
++		retval = -DWC_E_INVALID;
++	}
++	core_if->core_params->enable_dynamic_fifo = val;
++	return retval;
++}
++
++int32_t dwc_otg_get_param_enable_dynamic_fifo(dwc_otg_core_if_t * core_if)
++{
++	return core_if->core_params->enable_dynamic_fifo;
++}
++
++int dwc_otg_set_param_data_fifo_size(dwc_otg_core_if_t * core_if, int32_t val)
++{
++	int retval = 0;
++	if (DWC_OTG_PARAM_TEST(val, 32, 32768)) {
++		DWC_WARN("Wrong value for data_fifo_size\n");
++		DWC_WARN("data_fifo_size must be 32-32768\n");
++		return -DWC_E_INVALID;
++	}
++
++	if (val > core_if->hwcfg3.b.dfifo_depth) {
++		if (dwc_otg_param_initialized
++		    (core_if->core_params->data_fifo_size)) {
++			DWC_ERROR
++			    ("%d invalid for data_fifo_size parameter. Check HW configuration.\n",
++			     val);
++		}
++		val = core_if->hwcfg3.b.dfifo_depth;
++		retval = -DWC_E_INVALID;
++	}
++
++	core_if->core_params->data_fifo_size = val;
++	return retval;
++}
++
++int32_t dwc_otg_get_param_data_fifo_size(dwc_otg_core_if_t * core_if)
++{
++	return core_if->core_params->data_fifo_size;
++}
++
++int dwc_otg_set_param_dev_rx_fifo_size(dwc_otg_core_if_t * core_if, int32_t val)
++{
++	int retval = 0;
++	if (DWC_OTG_PARAM_TEST(val, 16, 32768)) {
++		DWC_WARN("Wrong value for dev_rx_fifo_size\n");
++		DWC_WARN("dev_rx_fifo_size must be 16-32768\n");
++		return -DWC_E_INVALID;
++	}
++
++	if (val > DWC_READ_REG32(&core_if->core_global_regs->grxfsiz)) {
++		if (dwc_otg_param_initialized(core_if->core_params->dev_rx_fifo_size)) {
++		DWC_WARN("%d invalid for dev_rx_fifo_size parameter\n", val);
++		}
++		val = DWC_READ_REG32(&core_if->core_global_regs->grxfsiz);
++		retval = -DWC_E_INVALID;
++	}
++
++	core_if->core_params->dev_rx_fifo_size = val;
++	return retval;
++}
++
++int32_t dwc_otg_get_param_dev_rx_fifo_size(dwc_otg_core_if_t * core_if)
++{
++	return core_if->core_params->dev_rx_fifo_size;
++}
++
++int dwc_otg_set_param_dev_nperio_tx_fifo_size(dwc_otg_core_if_t * core_if,
++					      int32_t val)
++{
++	int retval = 0;
++
++	if (DWC_OTG_PARAM_TEST(val, 16, 32768)) {
++		DWC_WARN("Wrong value for dev_nperio_tx_fifo\n");
++		DWC_WARN("dev_nperio_tx_fifo must be 16-32768\n");
++		return -DWC_E_INVALID;
++	}
++
++	if (val > (DWC_READ_REG32(&core_if->core_global_regs->gnptxfsiz) >> 16)) {
++		if (dwc_otg_param_initialized
++		    (core_if->core_params->dev_nperio_tx_fifo_size)) {
++			DWC_ERROR
++			    ("%d invalid for dev_nperio_tx_fifo_size. Check HW configuration.\n",
++			     val);
++		}
++		val =
++		    (DWC_READ_REG32(&core_if->core_global_regs->gnptxfsiz) >>
++		     16);
++		retval = -DWC_E_INVALID;
++	}
++
++	core_if->core_params->dev_nperio_tx_fifo_size = val;
++	return retval;
++}
++
++int32_t dwc_otg_get_param_dev_nperio_tx_fifo_size(dwc_otg_core_if_t * core_if)
++{
++	return core_if->core_params->dev_nperio_tx_fifo_size;
++}
++
++int dwc_otg_set_param_host_rx_fifo_size(dwc_otg_core_if_t * core_if,
++					int32_t val)
++{
++	int retval = 0;
++
++	if (DWC_OTG_PARAM_TEST(val, 16, 32768)) {
++		DWC_WARN("Wrong value for host_rx_fifo_size\n");
++		DWC_WARN("host_rx_fifo_size must be 16-32768\n");
++		return -DWC_E_INVALID;
++	}
++
++	if (val > DWC_READ_REG32(&core_if->core_global_regs->grxfsiz)) {
++		if (dwc_otg_param_initialized
++		    (core_if->core_params->host_rx_fifo_size)) {
++			DWC_ERROR
++			    ("%d invalid for host_rx_fifo_size. Check HW configuration.\n",
++			     val);
++		}
++		val = DWC_READ_REG32(&core_if->core_global_regs->grxfsiz);
++		retval = -DWC_E_INVALID;
++	}
++
++	core_if->core_params->host_rx_fifo_size = val;
++	return retval;
++
++}
++
++int32_t dwc_otg_get_param_host_rx_fifo_size(dwc_otg_core_if_t * core_if)
++{
++	return core_if->core_params->host_rx_fifo_size;
++}
++
++int dwc_otg_set_param_host_nperio_tx_fifo_size(dwc_otg_core_if_t * core_if,
++					       int32_t val)
++{
++	int retval = 0;
++
++	if (DWC_OTG_PARAM_TEST(val, 16, 32768)) {
++		DWC_WARN("Wrong value for host_nperio_tx_fifo_size\n");
++		DWC_WARN("host_nperio_tx_fifo_size must be 16-32768\n");
++		return -DWC_E_INVALID;
++	}
++
++	if (val > (DWC_READ_REG32(&core_if->core_global_regs->gnptxfsiz) >> 16)) {
++		if (dwc_otg_param_initialized
++		    (core_if->core_params->host_nperio_tx_fifo_size)) {
++			DWC_ERROR
++			    ("%d invalid for host_nperio_tx_fifo_size. Check HW configuration.\n",
++			     val);
++		}
++		val =
++		    (DWC_READ_REG32(&core_if->core_global_regs->gnptxfsiz) >>
++		     16);
++		retval = -DWC_E_INVALID;
++	}
++
++	core_if->core_params->host_nperio_tx_fifo_size = val;
++	return retval;
++}
++
++int32_t dwc_otg_get_param_host_nperio_tx_fifo_size(dwc_otg_core_if_t * core_if)
++{
++	return core_if->core_params->host_nperio_tx_fifo_size;
++}
++
++int dwc_otg_set_param_host_perio_tx_fifo_size(dwc_otg_core_if_t * core_if,
++					      int32_t val)
++{
++	int retval = 0;
++	if (DWC_OTG_PARAM_TEST(val, 16, 32768)) {
++		DWC_WARN("Wrong value for host_perio_tx_fifo_size\n");
++		DWC_WARN("host_perio_tx_fifo_size must be 16-32768\n");
++		return -DWC_E_INVALID;
++	}
++
++	if (val > ((core_if->hptxfsiz.d32) >> 16)) {
++		if (dwc_otg_param_initialized
++		    (core_if->core_params->host_perio_tx_fifo_size)) {
++			DWC_ERROR
++			    ("%d invalid for host_perio_tx_fifo_size. Check HW configuration.\n",
++			     val);
++		}
++		val = (core_if->hptxfsiz.d32) >> 16;
++		retval = -DWC_E_INVALID;
++	}
++
++	core_if->core_params->host_perio_tx_fifo_size = val;
++	return retval;
++}
++
++int32_t dwc_otg_get_param_host_perio_tx_fifo_size(dwc_otg_core_if_t * core_if)
++{
++	return core_if->core_params->host_perio_tx_fifo_size;
++}
++
++int dwc_otg_set_param_max_transfer_size(dwc_otg_core_if_t * core_if,
++					int32_t val)
++{
++	int retval = 0;
++
++	if (DWC_OTG_PARAM_TEST(val, 2047, 524288)) {
++		DWC_WARN("Wrong value for max_transfer_size\n");
++		DWC_WARN("max_transfer_size must be 2047-524288\n");
++		return -DWC_E_INVALID;
++	}
++
++	if (val >= (1 << (core_if->hwcfg3.b.xfer_size_cntr_width + 11))) {
++		if (dwc_otg_param_initialized
++		    (core_if->core_params->max_transfer_size)) {
++			DWC_ERROR
++			    ("%d invalid for max_transfer_size. Check HW configuration.\n",
++			     val);
++		}
++		val =
++		    ((1 << (core_if->hwcfg3.b.packet_size_cntr_width + 11)) -
++		     1);
++		retval = -DWC_E_INVALID;
++	}
++
++	core_if->core_params->max_transfer_size = val;
++	return retval;
++}
++
++int32_t dwc_otg_get_param_max_transfer_size(dwc_otg_core_if_t * core_if)
++{
++	return core_if->core_params->max_transfer_size;
++}
++
++int dwc_otg_set_param_max_packet_count(dwc_otg_core_if_t * core_if, int32_t val)
++{
++	int retval = 0;
++
++	if (DWC_OTG_PARAM_TEST(val, 15, 511)) {
++		DWC_WARN("Wrong value for max_packet_count\n");
++		DWC_WARN("max_packet_count must be 15-511\n");
++		return -DWC_E_INVALID;
++	}
++
++	if (val > (1 << (core_if->hwcfg3.b.packet_size_cntr_width + 4))) {
++		if (dwc_otg_param_initialized
++		    (core_if->core_params->max_packet_count)) {
++			DWC_ERROR
++			    ("%d invalid for max_packet_count. Check HW configuration.\n",
++			     val);
++		}
++		val =
++		    ((1 << (core_if->hwcfg3.b.packet_size_cntr_width + 4)) - 1);
++		retval = -DWC_E_INVALID;
++	}
++
++	core_if->core_params->max_packet_count = val;
++	return retval;
++}
++
++int32_t dwc_otg_get_param_max_packet_count(dwc_otg_core_if_t * core_if)
++{
++	return core_if->core_params->max_packet_count;
++}
++
++int dwc_otg_set_param_host_channels(dwc_otg_core_if_t * core_if, int32_t val)
++{
++	int retval = 0;
++
++	if (DWC_OTG_PARAM_TEST(val, 1, 16)) {
++		DWC_WARN("Wrong value for host_channels\n");
++		DWC_WARN("host_channels must be 1-16\n");
++		return -DWC_E_INVALID;
++	}
++
++	if (val > (core_if->hwcfg2.b.num_host_chan + 1)) {
++		if (dwc_otg_param_initialized
++		    (core_if->core_params->host_channels)) {
++			DWC_ERROR
++			    ("%d invalid for host_channels. Check HW configurations.\n",
++			     val);
++		}
++		val = (core_if->hwcfg2.b.num_host_chan + 1);
++		retval = -DWC_E_INVALID;
++	}
++
++	core_if->core_params->host_channels = val;
++	return retval;
++}
++
++int32_t dwc_otg_get_param_host_channels(dwc_otg_core_if_t * core_if)
++{
++	return core_if->core_params->host_channels;
++}
++
++int dwc_otg_set_param_dev_endpoints(dwc_otg_core_if_t * core_if, int32_t val)
++{
++	int retval = 0;
++
++	if (DWC_OTG_PARAM_TEST(val, 1, 15)) {
++		DWC_WARN("Wrong value for dev_endpoints\n");
++		DWC_WARN("dev_endpoints must be 1-15\n");
++		return -DWC_E_INVALID;
++	}
++
++	if (val > (core_if->hwcfg2.b.num_dev_ep)) {
++		if (dwc_otg_param_initialized
++		    (core_if->core_params->dev_endpoints)) {
++			DWC_ERROR
++			    ("%d invalid for dev_endpoints. Check HW configurations.\n",
++			     val);
++		}
++		val = core_if->hwcfg2.b.num_dev_ep;
++		retval = -DWC_E_INVALID;
++	}
++
++	core_if->core_params->dev_endpoints = val;
++	return retval;
++}
++
++int32_t dwc_otg_get_param_dev_endpoints(dwc_otg_core_if_t * core_if)
++{
++	return core_if->core_params->dev_endpoints;
++}
++
++int dwc_otg_set_param_phy_type(dwc_otg_core_if_t * core_if, int32_t val)
++{
++	int retval = 0;
++	int valid = 0;
++
++	if (DWC_OTG_PARAM_TEST(val, 0, 2)) {
++		DWC_WARN("Wrong value for phy_type\n");
++		DWC_WARN("phy_type must be 0,1 or 2\n");
++		return -DWC_E_INVALID;
++	}
++#ifndef NO_FS_PHY_HW_CHECKS
++	if ((val == DWC_PHY_TYPE_PARAM_UTMI) &&
++	    ((core_if->hwcfg2.b.hs_phy_type == 1) ||
++	     (core_if->hwcfg2.b.hs_phy_type == 3))) {
++		valid = 1;
++	} else if ((val == DWC_PHY_TYPE_PARAM_ULPI) &&
++		   ((core_if->hwcfg2.b.hs_phy_type == 2) ||
++		    (core_if->hwcfg2.b.hs_phy_type == 3))) {
++		valid = 1;
++	} else if ((val == DWC_PHY_TYPE_PARAM_FS) &&
++		   (core_if->hwcfg2.b.fs_phy_type == 1)) {
++		valid = 1;
++	}
++	if (!valid) {
++		if (dwc_otg_param_initialized(core_if->core_params->phy_type)) {
++			DWC_ERROR
++			    ("%d invalid for phy_type. Check HW configurations.\n",
++			     val);
++		}
++		if (core_if->hwcfg2.b.hs_phy_type) {
++			if ((core_if->hwcfg2.b.hs_phy_type == 3) ||
++			    (core_if->hwcfg2.b.hs_phy_type == 1)) {
++				val = DWC_PHY_TYPE_PARAM_UTMI;
++			} else {
++				val = DWC_PHY_TYPE_PARAM_ULPI;
++			}
++		}
++		retval = -DWC_E_INVALID;
++	}
++#endif
++	core_if->core_params->phy_type = val;
++	return retval;
++}
++
++int32_t dwc_otg_get_param_phy_type(dwc_otg_core_if_t * core_if)
++{
++	return core_if->core_params->phy_type;
++}
++
++int dwc_otg_set_param_speed(dwc_otg_core_if_t * core_if, int32_t val)
++{
++	int retval = 0;
++	if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
++		DWC_WARN("Wrong value for speed parameter\n");
++		DWC_WARN("max_speed parameter must be 0 or 1\n");
++		return -DWC_E_INVALID;
++	}
++	if ((val == 0)
++	    && dwc_otg_get_param_phy_type(core_if) == DWC_PHY_TYPE_PARAM_FS) {
++		if (dwc_otg_param_initialized(core_if->core_params->speed)) {
++			DWC_ERROR
++			    ("%d invalid for speed paremter. Check HW configuration.\n",
++			     val);
++		}
++		val =
++		    (dwc_otg_get_param_phy_type(core_if) ==
++		     DWC_PHY_TYPE_PARAM_FS ? 1 : 0);
++		retval = -DWC_E_INVALID;
++	}
++	core_if->core_params->speed = val;
++	return retval;
++}
++
++int32_t dwc_otg_get_param_speed(dwc_otg_core_if_t * core_if)
++{
++	return core_if->core_params->speed;
++}
++
++int dwc_otg_set_param_host_ls_low_power_phy_clk(dwc_otg_core_if_t * core_if,
++						int32_t val)
++{
++	int retval = 0;
++
++	if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
++		DWC_WARN
++		    ("Wrong value for host_ls_low_power_phy_clk parameter\n");
++		DWC_WARN("host_ls_low_power_phy_clk must be 0 or 1\n");
++		return -DWC_E_INVALID;
++	}
++
++	if ((val == DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ)
++	    && (dwc_otg_get_param_phy_type(core_if) == DWC_PHY_TYPE_PARAM_FS)) {
++		if (dwc_otg_param_initialized
++		    (core_if->core_params->host_ls_low_power_phy_clk)) {
++			DWC_ERROR
++			    ("%d invalid for host_ls_low_power_phy_clk. Check HW configuration.\n",
++			     val);
++		}
++		val =
++		    (dwc_otg_get_param_phy_type(core_if) ==
++		     DWC_PHY_TYPE_PARAM_FS) ?
++		    DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ :
++		    DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ;
++		retval = -DWC_E_INVALID;
++	}
++
++	core_if->core_params->host_ls_low_power_phy_clk = val;
++	return retval;
++}
++
++int32_t dwc_otg_get_param_host_ls_low_power_phy_clk(dwc_otg_core_if_t * core_if)
++{
++	return core_if->core_params->host_ls_low_power_phy_clk;
++}
++
++int dwc_otg_set_param_phy_ulpi_ddr(dwc_otg_core_if_t * core_if, int32_t val)
++{
++	if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
++		DWC_WARN("Wrong value for phy_ulpi_ddr\n");
++		DWC_WARN("phy_upli_ddr must be 0 or 1\n");
++		return -DWC_E_INVALID;
++	}
++
++	core_if->core_params->phy_ulpi_ddr = val;
++	return 0;
++}
++
++int32_t dwc_otg_get_param_phy_ulpi_ddr(dwc_otg_core_if_t * core_if)
++{
++	return core_if->core_params->phy_ulpi_ddr;
++}
++
++int dwc_otg_set_param_phy_ulpi_ext_vbus(dwc_otg_core_if_t * core_if,
++					int32_t val)
++{
++	if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
++		DWC_WARN("Wrong valaue for phy_ulpi_ext_vbus\n");
++		DWC_WARN("phy_ulpi_ext_vbus must be 0 or 1\n");
++		return -DWC_E_INVALID;
++	}
++
++	core_if->core_params->phy_ulpi_ext_vbus = val;
++	return 0;
++}
++
++int32_t dwc_otg_get_param_phy_ulpi_ext_vbus(dwc_otg_core_if_t * core_if)
++{
++	return core_if->core_params->phy_ulpi_ext_vbus;
++}
++
++int dwc_otg_set_param_phy_utmi_width(dwc_otg_core_if_t * core_if, int32_t val)
++{
++	if (DWC_OTG_PARAM_TEST(val, 8, 8) && DWC_OTG_PARAM_TEST(val, 16, 16)) {
++		DWC_WARN("Wrong valaue for phy_utmi_width\n");
++		DWC_WARN("phy_utmi_width must be 8 or 16\n");
++		return -DWC_E_INVALID;
++	}
++
++	core_if->core_params->phy_utmi_width = val;
++	return 0;
++}
++
++int32_t dwc_otg_get_param_phy_utmi_width(dwc_otg_core_if_t * core_if)
++{
++	return core_if->core_params->phy_utmi_width;
++}
++
++int dwc_otg_set_param_ulpi_fs_ls(dwc_otg_core_if_t * core_if, int32_t val)
++{
++	if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
++		DWC_WARN("Wrong valaue for ulpi_fs_ls\n");
++		DWC_WARN("ulpi_fs_ls must be 0 or 1\n");
++		return -DWC_E_INVALID;
++	}
++
++	core_if->core_params->ulpi_fs_ls = val;
++	return 0;
++}
++
++int32_t dwc_otg_get_param_ulpi_fs_ls(dwc_otg_core_if_t * core_if)
++{
++	return core_if->core_params->ulpi_fs_ls;
++}
++
++int dwc_otg_set_param_ts_dline(dwc_otg_core_if_t * core_if, int32_t val)
++{
++	if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
++		DWC_WARN("Wrong valaue for ts_dline\n");
++		DWC_WARN("ts_dline must be 0 or 1\n");
++		return -DWC_E_INVALID;
++	}
++
++	core_if->core_params->ts_dline = val;
++	return 0;
++}
++
++int32_t dwc_otg_get_param_ts_dline(dwc_otg_core_if_t * core_if)
++{
++	return core_if->core_params->ts_dline;
++}
++
++int dwc_otg_set_param_i2c_enable(dwc_otg_core_if_t * core_if, int32_t val)
++{
++	int retval = 0;
++	if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
++		DWC_WARN("Wrong valaue for i2c_enable\n");
++		DWC_WARN("i2c_enable must be 0 or 1\n");
++		return -DWC_E_INVALID;
++	}
++#ifndef NO_FS_PHY_HW_CHECK
++	if (val == 1 && core_if->hwcfg3.b.i2c == 0) {
++		if (dwc_otg_param_initialized(core_if->core_params->i2c_enable)) {
++			DWC_ERROR
++			    ("%d invalid for i2c_enable. Check HW configuration.\n",
++			     val);
++		}
++		val = 0;
++		retval = -DWC_E_INVALID;
++	}
++#endif
++
++	core_if->core_params->i2c_enable = val;
++	return retval;
++}
++
++int32_t dwc_otg_get_param_i2c_enable(dwc_otg_core_if_t * core_if)
++{
++	return core_if->core_params->i2c_enable;
++}
++
++int dwc_otg_set_param_dev_perio_tx_fifo_size(dwc_otg_core_if_t * core_if,
++					     int32_t val, int fifo_num)
++{
++	int retval = 0;
++	gintsts_data_t gintsts;
++	gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
++
++	if (DWC_OTG_PARAM_TEST(val, 4, 768)) {
++		DWC_WARN("Wrong value for dev_perio_tx_fifo_size\n");
++		DWC_WARN("dev_perio_tx_fifo_size must be 4-768\n");
++		return -DWC_E_INVALID;
++	}
++
++	if (val >
++	    (DWC_READ_REG32(&core_if->core_global_regs->dtxfsiz[fifo_num]) >> 16)) {
++		DWC_WARN("Value is larger then power-on FIFO size\n");
++		if (dwc_otg_param_initialized
++		    (core_if->core_params->dev_perio_tx_fifo_size[fifo_num])) {
++			DWC_ERROR
++			    ("`%d' invalid for parameter `dev_perio_fifo_size_%d'. Check HW configuration.\n",
++			     val, fifo_num);
++		}
++		val = (DWC_READ_REG32(&core_if->core_global_regs->dtxfsiz[fifo_num]) >> 16);
++		retval = -DWC_E_INVALID;
++	}
++
++	core_if->core_params->dev_perio_tx_fifo_size[fifo_num] = val;
++	return retval;
++}
++
++int32_t dwc_otg_get_param_dev_perio_tx_fifo_size(dwc_otg_core_if_t * core_if,
++						 int fifo_num)
++{
++	return core_if->core_params->dev_perio_tx_fifo_size[fifo_num];
++}
++
++int dwc_otg_set_param_en_multiple_tx_fifo(dwc_otg_core_if_t * core_if,
++					  int32_t val)
++{
++	int retval = 0;
++	if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
++		DWC_WARN("Wrong valaue for en_multiple_tx_fifo,\n");
++		DWC_WARN("en_multiple_tx_fifo must be 0 or 1\n");
++		return -DWC_E_INVALID;
++	}
++
++	if (val == 1 && core_if->hwcfg4.b.ded_fifo_en == 0) {
++		if (dwc_otg_param_initialized
++		    (core_if->core_params->en_multiple_tx_fifo)) {
++			DWC_ERROR
++			    ("%d invalid for parameter en_multiple_tx_fifo. Check HW configuration.\n",
++			     val);
++		}
++		val = 0;
++		retval = -DWC_E_INVALID;
++	}
++
++	core_if->core_params->en_multiple_tx_fifo = val;
++	return retval;
++}
++
++int32_t dwc_otg_get_param_en_multiple_tx_fifo(dwc_otg_core_if_t * core_if)
++{
++	return core_if->core_params->en_multiple_tx_fifo;
++}
++
++int dwc_otg_set_param_dev_tx_fifo_size(dwc_otg_core_if_t * core_if, int32_t val,
++				       int fifo_num)
++{
++	int retval = 0;
++	fifosize_data_t txfifosize;
++	txfifosize.d32 = DWC_READ_REG32(&core_if->core_global_regs->dtxfsiz[fifo_num]);
++
++	if (DWC_OTG_PARAM_TEST(val, 16, 32768)) {
++		DWC_WARN("Wrong value for dev_tx_fifo_size\n");
++		DWC_WARN("dev_tx_fifo_size must be 16-32768\n");
++		return -DWC_E_INVALID;
++	}
++
++	if (val > txfifosize.b.depth) {
++		DWC_WARN("Value is larger then power-on FIFO size\n");
++		if (dwc_otg_param_initialized
++		    (core_if->core_params->dev_tx_fifo_size[fifo_num])) {
++			DWC_ERROR
++			    ("`%d' invalid for parameter `dev_tx_fifo_size_%d'. Check HW configuration.\n",
++			     val, fifo_num);
++		}
++		val = txfifosize.b.depth;
++		retval = -DWC_E_INVALID;
++	}
++
++	core_if->core_params->dev_tx_fifo_size[fifo_num] = val;
++	return retval;
++}
++
++int32_t dwc_otg_get_param_dev_tx_fifo_size(dwc_otg_core_if_t * core_if,
++					   int fifo_num)
++{
++	return core_if->core_params->dev_tx_fifo_size[fifo_num];
++}
++
++int dwc_otg_set_param_thr_ctl(dwc_otg_core_if_t * core_if, int32_t val)
++{
++	int retval = 0;
++
++	if (DWC_OTG_PARAM_TEST(val, 0, 7)) {
++		DWC_WARN("Wrong value for thr_ctl\n");
++		DWC_WARN("thr_ctl must be 0-7\n");
++		return -DWC_E_INVALID;
++	}
++
++	if ((val != 0) &&
++	    (!dwc_otg_get_param_dma_enable(core_if) ||
++	     !core_if->hwcfg4.b.ded_fifo_en)) {
++		if (dwc_otg_param_initialized(core_if->core_params->thr_ctl)) {
++			DWC_ERROR
++			    ("%d invalid for parameter thr_ctl. Check HW configuration.\n",
++			     val);
++		}
++		val = 0;
++		retval = -DWC_E_INVALID;
++	}
++
++	core_if->core_params->thr_ctl = val;
++	return retval;
++}
++
++int32_t dwc_otg_get_param_thr_ctl(dwc_otg_core_if_t * core_if)
++{
++	return core_if->core_params->thr_ctl;
++}
++
++int dwc_otg_set_param_lpm_enable(dwc_otg_core_if_t * core_if, int32_t val)
++{
++	int retval = 0;
++
++	if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
++		DWC_WARN("Wrong value for lpm_enable\n");
++		DWC_WARN("lpm_enable must be 0 or 1\n");
++		return -DWC_E_INVALID;
++	}
++
++	if (val && !core_if->hwcfg3.b.otg_lpm_en) {
++		if (dwc_otg_param_initialized(core_if->core_params->lpm_enable)) {
++			DWC_ERROR
++			    ("%d invalid for parameter lpm_enable. Check HW configuration.\n",
++			     val);
++		}
++		val = 0;
++		retval = -DWC_E_INVALID;
++	}
++
++	core_if->core_params->lpm_enable = val;
++	return retval;
++}
++
++int32_t dwc_otg_get_param_lpm_enable(dwc_otg_core_if_t * core_if)
++{
++	return core_if->core_params->lpm_enable;
++}
++
++int dwc_otg_set_param_besl_enable(dwc_otg_core_if_t * core_if, int32_t val)
++{
++	int retval = 0;
++
++	if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
++		DWC_WARN("Wrong value for besl_enable\n");
++		DWC_WARN("besl_enable must be 0 or 1\n");
++		return -DWC_E_INVALID;
++	}
++
++	core_if->core_params->besl_enable = val;
++
++	if(val)
++	{
++		retval += dwc_otg_set_param_lpm_enable(core_if,val);
++	}
++
++	return retval;
++}
++
++int32_t dwc_otg_get_param_besl_enable(dwc_otg_core_if_t * core_if)
++{
++	return core_if->core_params->besl_enable;
++}
++
++int dwc_otg_set_param_baseline_besl(dwc_otg_core_if_t * core_if, int32_t val)
++{
++	int retval = 0;
++
++	if (DWC_OTG_PARAM_TEST(val, 0, 15)) {
++		DWC_WARN("Wrong value for baseline_besl\n");
++		DWC_WARN("baseline_besl must be 0-15\n");
++		return -DWC_E_INVALID;
++	}
++
++	core_if->core_params->baseline_besl = val;
++	return retval;
++}
++
++int32_t dwc_otg_get_param_baseline_besl(dwc_otg_core_if_t * core_if)
++{
++	return core_if->core_params->baseline_besl;
++}
++
++int dwc_otg_set_param_deep_besl(dwc_otg_core_if_t * core_if, int32_t val)
++{
++	int retval = 0;
++
++	if (DWC_OTG_PARAM_TEST(val, 0, 15)) {
++		DWC_WARN("Wrong value for deep_besl\n");
++		DWC_WARN("deep_besl must be 0-15\n");
++		return -DWC_E_INVALID;
++	}
++
++	core_if->core_params->deep_besl = val;
++	return retval;
++}
++
++int32_t dwc_otg_get_param_deep_besl(dwc_otg_core_if_t * core_if)
++{
++	return core_if->core_params->deep_besl;
++}
++
++int dwc_otg_set_param_tx_thr_length(dwc_otg_core_if_t * core_if, int32_t val)
++{
++	if (DWC_OTG_PARAM_TEST(val, 8, 128)) {
++		DWC_WARN("Wrong valaue for tx_thr_length\n");
++		DWC_WARN("tx_thr_length must be 8 - 128\n");
++		return -DWC_E_INVALID;
++	}
++
++	core_if->core_params->tx_thr_length = val;
++	return 0;
++}
++
++int32_t dwc_otg_get_param_tx_thr_length(dwc_otg_core_if_t * core_if)
++{
++	return core_if->core_params->tx_thr_length;
++}
++
++int dwc_otg_set_param_rx_thr_length(dwc_otg_core_if_t * core_if, int32_t val)
++{
++	if (DWC_OTG_PARAM_TEST(val, 8, 128)) {
++		DWC_WARN("Wrong valaue for rx_thr_length\n");
++		DWC_WARN("rx_thr_length must be 8 - 128\n");
++		return -DWC_E_INVALID;
++	}
++
++	core_if->core_params->rx_thr_length = val;
++	return 0;
++}
++
++int32_t dwc_otg_get_param_rx_thr_length(dwc_otg_core_if_t * core_if)
++{
++	return core_if->core_params->rx_thr_length;
++}
++
++int dwc_otg_set_param_dma_burst_size(dwc_otg_core_if_t * core_if, int32_t val)
++{
++	if (DWC_OTG_PARAM_TEST(val, 1, 1) &&
++	    DWC_OTG_PARAM_TEST(val, 4, 4) &&
++	    DWC_OTG_PARAM_TEST(val, 8, 8) &&
++	    DWC_OTG_PARAM_TEST(val, 16, 16) &&
++	    DWC_OTG_PARAM_TEST(val, 32, 32) &&
++	    DWC_OTG_PARAM_TEST(val, 64, 64) &&
++	    DWC_OTG_PARAM_TEST(val, 128, 128) &&
++	    DWC_OTG_PARAM_TEST(val, 256, 256)) {
++		DWC_WARN("`%d' invalid for parameter `dma_burst_size'\n", val);
++		return -DWC_E_INVALID;
++	}
++	core_if->core_params->dma_burst_size = val;
++	return 0;
++}
++
++int32_t dwc_otg_get_param_dma_burst_size(dwc_otg_core_if_t * core_if)
++{
++	return core_if->core_params->dma_burst_size;
++}
++
++int dwc_otg_set_param_pti_enable(dwc_otg_core_if_t * core_if, int32_t val)
++{
++	int retval = 0;
++	if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
++		DWC_WARN("`%d' invalid for parameter `pti_enable'\n", val);
++		return -DWC_E_INVALID;
++	}
++	if (val && (core_if->snpsid < OTG_CORE_REV_2_72a)) {
++		if (dwc_otg_param_initialized(core_if->core_params->pti_enable)) {
++			DWC_ERROR
++			    ("%d invalid for parameter pti_enable. Check HW configuration.\n",
++			     val);
++		}
++		retval = -DWC_E_INVALID;
++		val = 0;
++	}
++	core_if->core_params->pti_enable = val;
++	return retval;
++}
++
++int32_t dwc_otg_get_param_pti_enable(dwc_otg_core_if_t * core_if)
++{
++	return core_if->core_params->pti_enable;
++}
++
++int dwc_otg_set_param_mpi_enable(dwc_otg_core_if_t * core_if, int32_t val)
++{
++	int retval = 0;
++	if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
++		DWC_WARN("`%d' invalid for parameter `mpi_enable'\n", val);
++		return -DWC_E_INVALID;
++	}
++	if (val && (core_if->hwcfg2.b.multi_proc_int == 0)) {
++		if (dwc_otg_param_initialized(core_if->core_params->mpi_enable)) {
++			DWC_ERROR
++			    ("%d invalid for parameter mpi_enable. Check HW configuration.\n",
++			     val);
++		}
++		retval = -DWC_E_INVALID;
++		val = 0;
++	}
++	core_if->core_params->mpi_enable = val;
++	return retval;
++}
++
++int32_t dwc_otg_get_param_mpi_enable(dwc_otg_core_if_t * core_if)
++{
++	return core_if->core_params->mpi_enable;
++}
++
++int dwc_otg_set_param_adp_enable(dwc_otg_core_if_t * core_if, int32_t val)
++{
++	int retval = 0;
++	if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
++		DWC_WARN("`%d' invalid for parameter `adp_enable'\n", val);
++		return -DWC_E_INVALID;
++	}
++	if (val && (core_if->hwcfg3.b.adp_supp == 0)) {
++		if (dwc_otg_param_initialized
++		    (core_if->core_params->adp_supp_enable)) {
++			DWC_ERROR
++			    ("%d invalid for parameter adp_enable. Check HW configuration.\n",
++			     val);
++		}
++		retval = -DWC_E_INVALID;
++		val = 0;
++	}
++	core_if->core_params->adp_supp_enable = val;
++	/* Set OTG version 2.0 in case of enabling ADP */
++	if (val)
++		dwc_otg_set_param_otg_ver(core_if, 1);
++
++	return retval;
++}
++
++int32_t dwc_otg_get_param_adp_enable(dwc_otg_core_if_t * core_if)
++{
++	return core_if->core_params->adp_supp_enable;
++}
++
++int dwc_otg_set_param_ic_usb_cap(dwc_otg_core_if_t * core_if, int32_t val)
++{
++	int retval = 0;
++	if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
++		DWC_WARN("`%d' invalid for parameter `ic_usb_cap'\n", val);
++		DWC_WARN("ic_usb_cap must be 0 or 1\n");
++		return -DWC_E_INVALID;
++	}
++
++	if (val && (core_if->hwcfg2.b.otg_enable_ic_usb == 0)) {
++		if (dwc_otg_param_initialized(core_if->core_params->ic_usb_cap)) {
++			DWC_ERROR
++			    ("%d invalid for parameter ic_usb_cap. Check HW configuration.\n",
++			     val);
++		}
++		retval = -DWC_E_INVALID;
++		val = 0;
++	}
++	core_if->core_params->ic_usb_cap = val;
++	return retval;
++}
++
++int32_t dwc_otg_get_param_ic_usb_cap(dwc_otg_core_if_t * core_if)
++{
++	return core_if->core_params->ic_usb_cap;
++}
++
++int dwc_otg_set_param_ahb_thr_ratio(dwc_otg_core_if_t * core_if, int32_t val)
++{
++	int retval = 0;
++	int valid = 1;
++
++	if (DWC_OTG_PARAM_TEST(val, 0, 3)) {
++		DWC_WARN("`%d' invalid for parameter `ahb_thr_ratio'\n", val);
++		DWC_WARN("ahb_thr_ratio must be 0 - 3\n");
++		return -DWC_E_INVALID;
++	}
++
++	if (val
++	    && (core_if->snpsid < OTG_CORE_REV_2_81a
++		|| !dwc_otg_get_param_thr_ctl(core_if))) {
++		valid = 0;
++	} else if (val
++		   && ((dwc_otg_get_param_tx_thr_length(core_if) / (1 << val)) <
++		       4)) {
++		valid = 0;
++	}
++	if (valid == 0) {
++		if (dwc_otg_param_initialized
++		    (core_if->core_params->ahb_thr_ratio)) {
++			DWC_ERROR
++			    ("%d invalid for parameter ahb_thr_ratio. Check HW configuration.\n",
++			     val);
++		}
++		retval = -DWC_E_INVALID;
++		val = 0;
++	}
++
++	core_if->core_params->ahb_thr_ratio = val;
++	return retval;
++}
++
++int32_t dwc_otg_get_param_ahb_thr_ratio(dwc_otg_core_if_t * core_if)
++{
++	return core_if->core_params->ahb_thr_ratio;
++}
++
++int dwc_otg_set_param_power_down(dwc_otg_core_if_t * core_if, int32_t val)
++{
++	int retval = 0;
++	int valid = 1;
++	hwcfg4_data_t hwcfg4 = {.d32 = 0 };
++	hwcfg4.d32 = DWC_READ_REG32(&core_if->core_global_regs->ghwcfg4);
++
++	if (DWC_OTG_PARAM_TEST(val, 0, 3)) {
++		DWC_WARN("`%d' invalid for parameter `power_down'\n", val);
++		DWC_WARN("power_down must be 0 - 2\n");
++		return -DWC_E_INVALID;
++	}
++
++	if ((val == 2) && (core_if->snpsid < OTG_CORE_REV_2_91a)) {
++		valid = 0;
++	}
++	if ((val == 3)
++	    && ((core_if->snpsid < OTG_CORE_REV_3_00a)
++		|| (hwcfg4.b.xhiber == 0))) {
++		valid = 0;
++	}
++	if (valid == 0) {
++		if (dwc_otg_param_initialized(core_if->core_params->power_down)) {
++			DWC_ERROR
++			    ("%d invalid for parameter power_down. Check HW configuration.\n",
++			     val);
++		}
++		retval = -DWC_E_INVALID;
++		val = 0;
++	}
++	core_if->core_params->power_down = val;
++	return retval;
++}
++
++int32_t dwc_otg_get_param_power_down(dwc_otg_core_if_t * core_if)
++{
++	return core_if->core_params->power_down;
++}
++
++int dwc_otg_set_param_reload_ctl(dwc_otg_core_if_t * core_if, int32_t val)
++{
++	int retval = 0;
++	int valid = 1;
++
++	if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
++		DWC_WARN("`%d' invalid for parameter `reload_ctl'\n", val);
++		DWC_WARN("reload_ctl must be 0 or 1\n");
++		return -DWC_E_INVALID;
++	}
++
++	if ((val == 1) && (core_if->snpsid < OTG_CORE_REV_2_92a)) {
++		valid = 0;
++	}
++	if (valid == 0) {
++		if (dwc_otg_param_initialized(core_if->core_params->reload_ctl)) {
++			DWC_ERROR("%d invalid for parameter reload_ctl."
++				  "Check HW configuration.\n", val);
++		}
++		retval = -DWC_E_INVALID;
++		val = 0;
++	}
++	core_if->core_params->reload_ctl = val;
++	return retval;
++}
++
++int32_t dwc_otg_get_param_reload_ctl(dwc_otg_core_if_t * core_if)
++{
++	return core_if->core_params->reload_ctl;
++}
++
++int dwc_otg_set_param_dev_out_nak(dwc_otg_core_if_t * core_if, int32_t val)
++{
++	int retval = 0;
++	int valid = 1;
++
++	if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
++		DWC_WARN("`%d' invalid for parameter `dev_out_nak'\n", val);
++		DWC_WARN("dev_out_nak must be 0 or 1\n");
++		return -DWC_E_INVALID;
++	}
++
++	if ((val == 1) && ((core_if->snpsid < OTG_CORE_REV_2_93a) ||
++			   !(core_if->core_params->dma_desc_enable))) {
++		valid = 0;
++	}
++	if (valid == 0) {
++		if (dwc_otg_param_initialized(core_if->core_params->dev_out_nak)) {
++			DWC_ERROR("%d invalid for parameter dev_out_nak."
++				  "Check HW configuration.\n", val);
++		}
++		retval = -DWC_E_INVALID;
++		val = 0;
++	}
++	core_if->core_params->dev_out_nak = val;
++	return retval;
++}
++
++int32_t dwc_otg_get_param_dev_out_nak(dwc_otg_core_if_t * core_if)
++{
++	return core_if->core_params->dev_out_nak;
++}
++
++int dwc_otg_set_param_cont_on_bna(dwc_otg_core_if_t * core_if, int32_t val)
++{
++	int retval = 0;
++	int valid = 1;
++
++	if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
++		DWC_WARN("`%d' invalid for parameter `cont_on_bna'\n", val);
++		DWC_WARN("cont_on_bna must be 0 or 1\n");
++		return -DWC_E_INVALID;
++	}
++
++	if ((val == 1) && ((core_if->snpsid < OTG_CORE_REV_2_94a) ||
++			   !(core_if->core_params->dma_desc_enable))) {
++		valid = 0;
++	}
++	if (valid == 0) {
++		if (dwc_otg_param_initialized(core_if->core_params->cont_on_bna)) {
++			DWC_ERROR("%d invalid for parameter cont_on_bna."
++				"Check HW configuration.\n", val);
++		}
++		retval = -DWC_E_INVALID;
++		val = 0;
++	}
++	core_if->core_params->cont_on_bna = val;
++	return retval;
++}
++
++int32_t dwc_otg_get_param_cont_on_bna(dwc_otg_core_if_t * core_if)
++{
++	return core_if->core_params->cont_on_bna;
++}
++
++int dwc_otg_set_param_ahb_single(dwc_otg_core_if_t * core_if, int32_t val)
++{
++	int retval = 0;
++	int valid = 1;
++
++	if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
++		DWC_WARN("`%d' invalid for parameter `ahb_single'\n", val);
++		DWC_WARN("ahb_single must be 0 or 1\n");
++		return -DWC_E_INVALID;
++	}
++
++	if ((val == 1) && (core_if->snpsid < OTG_CORE_REV_2_94a)) {
++		valid = 0;
++	}
++	if (valid == 0) {
++		if (dwc_otg_param_initialized(core_if->core_params->ahb_single)) {
++			DWC_ERROR("%d invalid for parameter ahb_single."
++				  "Check HW configuration.\n", val);
++		}
++		retval = -DWC_E_INVALID;
++		val = 0;
++	}
++	core_if->core_params->ahb_single = val;
++	return retval;
++}
++
++int32_t dwc_otg_get_param_ahb_single(dwc_otg_core_if_t * core_if)
++{
++	return core_if->core_params->ahb_single;
++}
++
++int dwc_otg_set_param_otg_ver(dwc_otg_core_if_t * core_if, int32_t val)
++{
++	int retval = 0;
++
++	if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
++		DWC_WARN("`%d' invalid for parameter `otg_ver'\n", val);
++		DWC_WARN
++		    ("otg_ver must be 0(for OTG 1.3 support) or 1(for OTG 2.0 support)\n");
++		return -DWC_E_INVALID;
++	}
++
++	core_if->core_params->otg_ver = val;
++	return retval;
++}
++
++int32_t dwc_otg_get_param_otg_ver(dwc_otg_core_if_t * core_if)
++{
++	return core_if->core_params->otg_ver;
++}
++
++uint32_t dwc_otg_get_hnpstatus(dwc_otg_core_if_t * core_if)
++{
++	gotgctl_data_t otgctl;
++	otgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
++	return otgctl.b.hstnegscs;
++}
++
++uint32_t dwc_otg_get_srpstatus(dwc_otg_core_if_t * core_if)
++{
++	gotgctl_data_t otgctl;
++	otgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
++	return otgctl.b.sesreqscs;
++}
++
++void dwc_otg_set_hnpreq(dwc_otg_core_if_t * core_if, uint32_t val)
++{
++	if(core_if->otg_ver == 0) {
++		gotgctl_data_t otgctl;
++		otgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
++		otgctl.b.hnpreq = val;
++		DWC_WRITE_REG32(&core_if->core_global_regs->gotgctl, otgctl.d32);
++	} else {
++		core_if->otg_sts = val;
++	}
++}
++
++uint32_t dwc_otg_get_gsnpsid(dwc_otg_core_if_t * core_if)
++{
++	return core_if->snpsid;
++}
++
++uint32_t dwc_otg_get_mode(dwc_otg_core_if_t * core_if)
++{
++	gintsts_data_t gintsts;
++	gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
++	return gintsts.b.curmode;
++}
++
++uint32_t dwc_otg_get_hnpcapable(dwc_otg_core_if_t * core_if)
++{
++	gusbcfg_data_t usbcfg;
++	usbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
++	return usbcfg.b.hnpcap;
++}
++
++void dwc_otg_set_hnpcapable(dwc_otg_core_if_t * core_if, uint32_t val)
++{
++	gusbcfg_data_t usbcfg;
++	usbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
++	usbcfg.b.hnpcap = val;
++	DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, usbcfg.d32);
++}
++
++uint32_t dwc_otg_get_srpcapable(dwc_otg_core_if_t * core_if)
++{
++	gusbcfg_data_t usbcfg;
++	usbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
++	return usbcfg.b.srpcap;
++}
++
++void dwc_otg_set_srpcapable(dwc_otg_core_if_t * core_if, uint32_t val)
++{
++	gusbcfg_data_t usbcfg;
++	usbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
++	usbcfg.b.srpcap = val;
++	DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, usbcfg.d32);
++}
++
++uint32_t dwc_otg_get_devspeed(dwc_otg_core_if_t * core_if)
++{
++	dcfg_data_t dcfg;
++	dcfg.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
++	return dcfg.b.devspd;
++}
++
++void dwc_otg_set_devspeed(dwc_otg_core_if_t * core_if, uint32_t val)
++{
++	dcfg_data_t dcfg;
++	dcfg.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
++	dcfg.b.devspd = val;
++	DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg, dcfg.d32);
++}
++
++uint32_t dwc_otg_get_busconnected(dwc_otg_core_if_t * core_if)
++{
++	hprt0_data_t hprt0;
++	hprt0.d32 = DWC_READ_REG32(core_if->host_if->hprt0);
++	return hprt0.b.prtconnsts;
++}
++
++uint32_t dwc_otg_get_enumspeed(dwc_otg_core_if_t * core_if)
++{
++	dsts_data_t dsts;
++	dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
++	return dsts.b.enumspd;
++}
++
++uint32_t dwc_otg_get_prtpower(dwc_otg_core_if_t * core_if)
++{
++	hprt0_data_t hprt0;
++	hprt0.d32 = DWC_READ_REG32(core_if->host_if->hprt0);
++	return hprt0.b.prtpwr;
++
++}
++
++uint32_t dwc_otg_get_core_state(dwc_otg_core_if_t * core_if)
++{
++	return core_if->hibernation_suspend;
++}
++
++void dwc_otg_set_prtpower(dwc_otg_core_if_t * core_if, uint32_t val)
++{
++	hprt0_data_t hprt0;
++	hprt0.d32 = dwc_otg_read_hprt0(core_if);
++	hprt0.b.prtpwr = val;
++	DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
++}
++
++uint32_t dwc_otg_get_prtsuspend(dwc_otg_core_if_t * core_if)
++{
++	hprt0_data_t hprt0;
++	hprt0.d32 = DWC_READ_REG32(core_if->host_if->hprt0);
++	return hprt0.b.prtsusp;
++
++}
++
++void dwc_otg_set_prtsuspend(dwc_otg_core_if_t * core_if, uint32_t val)
++{
++	hprt0_data_t hprt0;
++	hprt0.d32 = dwc_otg_read_hprt0(core_if);
++	hprt0.b.prtsusp = val;
++	DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
++}
++
++uint32_t dwc_otg_get_fr_interval(dwc_otg_core_if_t * core_if)
++{
++	hfir_data_t hfir;
++	hfir.d32 = DWC_READ_REG32(&core_if->host_if->host_global_regs->hfir);
++	return hfir.b.frint;
++
++}
++
++void dwc_otg_set_fr_interval(dwc_otg_core_if_t * core_if, uint32_t val)
++{
++	hfir_data_t hfir;
++	uint32_t fram_int;
++	fram_int = calc_frame_interval(core_if);
++	hfir.d32 = DWC_READ_REG32(&core_if->host_if->host_global_regs->hfir);
++	if (!core_if->core_params->reload_ctl) {
++		DWC_WARN("\nCannot reload HFIR register.HFIR.HFIRRldCtrl bit is"
++			 "not set to 1.\nShould load driver with reload_ctl=1"
++			 " module parameter\n");
++		return;
++	}
++	switch (fram_int) {
++	case 3750:
++		if ((val < 3350) || (val > 4150)) {
++			DWC_WARN("HFIR interval for HS core and 30 MHz"
++				 "clock freq should be from 3350 to 4150\n");
++			return;
++		}
++		break;
++	case 30000:
++		if ((val < 26820) || (val > 33180)) {
++			DWC_WARN("HFIR interval for FS/LS core and 30 MHz"
++				 "clock freq should be from 26820 to 33180\n");
++			return;
++		}
++		break;
++	case 6000:
++		if ((val < 5360) || (val > 6640)) {
++			DWC_WARN("HFIR interval for HS core and 48 MHz"
++				 "clock freq should be from 5360 to 6640\n");
++			return;
++		}
++		break;
++	case 48000:
++		if ((val < 42912) || (val > 53088)) {
++			DWC_WARN("HFIR interval for FS/LS core and 48 MHz"
++				 "clock freq should be from 42912 to 53088\n");
++			return;
++		}
++		break;
++	case 7500:
++		if ((val < 6700) || (val > 8300)) {
++			DWC_WARN("HFIR interval for HS core and 60 MHz"
++				 "clock freq should be from 6700 to 8300\n");
++			return;
++		}
++		break;
++	case 60000:
++		if ((val < 53640) || (val > 65536)) {
++			DWC_WARN("HFIR interval for FS/LS core and 60 MHz"
++				 "clock freq should be from 53640 to 65536\n");
++			return;
++		}
++		break;
++	default:
++		DWC_WARN("Unknown frame interval\n");
++		return;
++		break;
++
++	}
++	hfir.b.frint = val;
++	DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hfir, hfir.d32);
++}
++
++uint32_t dwc_otg_get_mode_ch_tim(dwc_otg_core_if_t * core_if)
++{
++	hcfg_data_t hcfg;
++	hcfg.d32 = DWC_READ_REG32(&core_if->host_if->host_global_regs->hcfg);
++	return hcfg.b.modechtimen;
++
++}
++
++void dwc_otg_set_mode_ch_tim(dwc_otg_core_if_t * core_if, uint32_t val)
++{
++	hcfg_data_t hcfg;
++	hcfg.d32 = DWC_READ_REG32(&core_if->host_if->host_global_regs->hcfg);
++	hcfg.b.modechtimen = val;
++	DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hcfg, hcfg.d32);
++}
++
++void dwc_otg_set_prtresume(dwc_otg_core_if_t * core_if, uint32_t val)
++{
++	hprt0_data_t hprt0;
++	hprt0.d32 = dwc_otg_read_hprt0(core_if);
++	hprt0.b.prtres = val;
++	DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
++}
++
++uint32_t dwc_otg_get_remotewakesig(dwc_otg_core_if_t * core_if)
++{
++	dctl_data_t dctl;
++	dctl.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dctl);
++	return dctl.b.rmtwkupsig;
++}
++
++uint32_t dwc_otg_get_beslreject(dwc_otg_core_if_t * core_if)
++{
++	dctl_data_t dctl;
++	dctl.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dctl);
++	return dctl.b.besl_reject;
++}
++
++void dwc_otg_set_beslreject(dwc_otg_core_if_t * core_if, uint32_t val)
++{
++    dctl_data_t dctl;
++	dctl.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dctl);
++	dctl.b.besl_reject = val;
++	DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32);
++}
++uint32_t dwc_otg_get_hirdthresh(dwc_otg_core_if_t * core_if)
++{
++	glpmcfg_data_t lpmcfg;
++	lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
++	return lpmcfg.b.hird_thres;
++}
++
++void dwc_otg_set_hirdthresh(dwc_otg_core_if_t * core_if, uint32_t val)
++{
++	glpmcfg_data_t lpmcfg;
++
++	if (val > 15) {
++		DWC_WARN("Wrong valaue for hird_thres\n");
++		DWC_WARN("hird_thres must be 0-f\n");
++		return ;
++	}
++
++	lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
++	lpmcfg.b.hird_thres &= (1<<4);
++	lpmcfg.b.hird_thres |= val;
++	DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg, lpmcfg.d32);
++}
++
++uint32_t dwc_otg_get_lpm_portsleepstatus(dwc_otg_core_if_t * core_if)
++{
++	glpmcfg_data_t lpmcfg;
++	lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
++
++	DWC_ASSERT(!
++		   ((core_if->lx_state == DWC_OTG_L1) ^ lpmcfg.b.prt_sleep_sts),
++		   "lx_state = %d, lmpcfg.prt_sleep_sts = %d\n",
++		   core_if->lx_state, lpmcfg.b.prt_sleep_sts);
++
++	return lpmcfg.b.prt_sleep_sts;
++}
++
++uint32_t dwc_otg_get_lpm_remotewakeenabled(dwc_otg_core_if_t * core_if)
++{
++	glpmcfg_data_t lpmcfg;
++	lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
++	return lpmcfg.b.rem_wkup_en;
++}
++
++uint32_t dwc_otg_get_lpmresponse(dwc_otg_core_if_t * core_if)
++{
++	glpmcfg_data_t lpmcfg;
++	lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
++	return lpmcfg.b.appl_resp;
++}
++
++void dwc_otg_set_lpmresponse(dwc_otg_core_if_t * core_if, uint32_t val)
++{
++	glpmcfg_data_t lpmcfg;
++	lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
++	lpmcfg.b.appl_resp = val;
++	DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg, lpmcfg.d32);
++}
++
++uint32_t dwc_otg_get_hsic_connect(dwc_otg_core_if_t * core_if)
++{
++	glpmcfg_data_t lpmcfg;
++	lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
++	return lpmcfg.b.hsic_connect;
++}
++
++void dwc_otg_set_hsic_connect(dwc_otg_core_if_t * core_if, uint32_t val)
++{
++	glpmcfg_data_t lpmcfg;
++	lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
++	lpmcfg.b.hsic_connect = val;
++	DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg, lpmcfg.d32);
++}
++
++uint32_t dwc_otg_get_inv_sel_hsic(dwc_otg_core_if_t * core_if)
++{
++	glpmcfg_data_t lpmcfg;
++	lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
++	return lpmcfg.b.inv_sel_hsic;
++
++}
++
++void dwc_otg_set_inv_sel_hsic(dwc_otg_core_if_t * core_if, uint32_t val)
++{
++	glpmcfg_data_t lpmcfg;
++	lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
++	lpmcfg.b.inv_sel_hsic = val;
++	DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg, lpmcfg.d32);
++}
++
++uint32_t dwc_otg_get_gotgctl(dwc_otg_core_if_t * core_if)
++{
++	return DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
++}
++
++void dwc_otg_set_gotgctl(dwc_otg_core_if_t * core_if, uint32_t val)
++{
++	DWC_WRITE_REG32(&core_if->core_global_regs->gotgctl, val);
++}
++
++uint32_t dwc_otg_get_gusbcfg(dwc_otg_core_if_t * core_if)
++{
++	return DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
++}
++
++void dwc_otg_set_gusbcfg(dwc_otg_core_if_t * core_if, uint32_t val)
++{
++	DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, val);
++}
++
++uint32_t dwc_otg_get_grxfsiz(dwc_otg_core_if_t * core_if)
++{
++	return DWC_READ_REG32(&core_if->core_global_regs->grxfsiz);
++}
++
++void dwc_otg_set_grxfsiz(dwc_otg_core_if_t * core_if, uint32_t val)
++{
++	DWC_WRITE_REG32(&core_if->core_global_regs->grxfsiz, val);
++}
++
++uint32_t dwc_otg_get_gnptxfsiz(dwc_otg_core_if_t * core_if)
++{
++	return DWC_READ_REG32(&core_if->core_global_regs->gnptxfsiz);
++}
++
++void dwc_otg_set_gnptxfsiz(dwc_otg_core_if_t * core_if, uint32_t val)
++{
++	DWC_WRITE_REG32(&core_if->core_global_regs->gnptxfsiz, val);
++}
++
++uint32_t dwc_otg_get_gpvndctl(dwc_otg_core_if_t * core_if)
++{
++	return DWC_READ_REG32(&core_if->core_global_regs->gpvndctl);
++}
++
++void dwc_otg_set_gpvndctl(dwc_otg_core_if_t * core_if, uint32_t val)
++{
++	DWC_WRITE_REG32(&core_if->core_global_regs->gpvndctl, val);
++}
++
++uint32_t dwc_otg_get_ggpio(dwc_otg_core_if_t * core_if)
++{
++	return DWC_READ_REG32(&core_if->core_global_regs->ggpio);
++}
++
++void dwc_otg_set_ggpio(dwc_otg_core_if_t * core_if, uint32_t val)
++{
++	DWC_WRITE_REG32(&core_if->core_global_regs->ggpio, val);
++}
++
++uint32_t dwc_otg_get_hprt0(dwc_otg_core_if_t * core_if)
++{
++	return DWC_READ_REG32(core_if->host_if->hprt0);
++
++}
++
++void dwc_otg_set_hprt0(dwc_otg_core_if_t * core_if, uint32_t val)
++{
++	DWC_WRITE_REG32(core_if->host_if->hprt0, val);
++}
++
++uint32_t dwc_otg_get_guid(dwc_otg_core_if_t * core_if)
++{
++	return DWC_READ_REG32(&core_if->core_global_regs->guid);
++}
++
++void dwc_otg_set_guid(dwc_otg_core_if_t * core_if, uint32_t val)
++{
++	DWC_WRITE_REG32(&core_if->core_global_regs->guid, val);
++}
++
++uint32_t dwc_otg_get_hptxfsiz(dwc_otg_core_if_t * core_if)
++{
++	return DWC_READ_REG32(&core_if->core_global_regs->hptxfsiz);
++}
++
++uint16_t dwc_otg_get_otg_version(dwc_otg_core_if_t * core_if)
++{
++	return ((core_if->otg_ver == 1) ? (uint16_t)0x0200 : (uint16_t)0x0103);
++}
++
++/**
++ * Start the SRP timer to detect when the SRP does not complete within
++ * 6 seconds.
++ *
++ * @param core_if the pointer to core_if strucure.
++ */
++void dwc_otg_pcd_start_srp_timer(dwc_otg_core_if_t * core_if)
++{
++	core_if->srp_timer_started = 1;
++	DWC_TIMER_SCHEDULE(core_if->srp_timer, 6000 /* 6 secs */ );
++}
++
++void dwc_otg_initiate_srp(void * p)
++{
++	dwc_otg_core_if_t * core_if = p;
++	uint32_t *addr = (uint32_t *) & (core_if->core_global_regs->gotgctl);
++	gotgctl_data_t mem;
++	gotgctl_data_t val;
++
++	val.d32 = DWC_READ_REG32(addr);
++	if (val.b.sesreq) {
++		DWC_ERROR("Session Request Already active!\n");
++		return;
++	}
++
++	DWC_INFO("Session Request Initated\n");	//NOTICE
++	mem.d32 = DWC_READ_REG32(addr);
++	mem.b.sesreq = 1;
++	DWC_WRITE_REG32(addr, mem.d32);
++
++	/* Start the SRP timer */
++	dwc_otg_pcd_start_srp_timer(core_if);
++	return;
++}
++
++int dwc_otg_check_haps_status(dwc_otg_core_if_t * core_if)
++{
++   int retval = 0;
++
++   if(DWC_READ_REG32(&core_if->core_global_regs->gsnpsid) == 0xffffffff)
++   {
++		return -1;
++   } else {
++		return retval;
++   }
++
++}
+diff --git a/drivers/usb/gadget/udc/hiudc/dwc_otg_cil.h b/drivers/usb/gadget/udc/hiudc/dwc_otg_cil.h
+new file mode 100644
+index 0000000..b52a280
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc/dwc_otg_cil.h
+@@ -0,0 +1,1498 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_cil.h $
++ * $Revision: #128 $
++ * $Date: 2013/05/16 $
++ * $Change: 2231774 $
++ *
++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
++ * ========================================================================== */
++
++#if !defined(__DWC_CIL_H__)
++#define __DWC_CIL_H__
++
++#include "dwc_list.h"
++#include "dwc_otg_dbg.h"
++#include "dwc_otg_regs.h"
++
++#include "dwc_otg_core_if.h"
++#include "dwc_otg_adp.h"
++
++/**
++ * @file
++ * This file contains the interface to the Core Interface Layer.
++ */
++
++#ifdef DWC_UTE_CFI
++
++#define MAX_DMA_DESCS_PER_EP	256
++
++/**
++ * Enumeration for the data buffer mode
++ */
++typedef enum _data_buffer_mode {
++	BM_STANDARD = 0,	/* data buffer is in normal mode */
++	BM_SG = 1,		/* data buffer uses the scatter/gather mode */
++	BM_CONCAT = 2,		/* data buffer uses the concatenation mode */
++	BM_CIRCULAR = 3,	/* data buffer uses the circular DMA mode */
++	BM_ALIGN = 4		/* data buffer is in buffer alignment mode */
++} data_buffer_mode_e;
++#endif //DWC_UTE_CFI
++
++/** Macros defined for DWC OTG HW Release version */
++
++#define OTG_CORE_REV_2_60a	0x4F54260A
++#define OTG_CORE_REV_2_71a	0x4F54271A
++#define OTG_CORE_REV_2_72a	0x4F54272A
++#define OTG_CORE_REV_2_80a	0x4F54280A
++#define OTG_CORE_REV_2_81a	0x4F54281A
++#define OTG_CORE_REV_2_90a	0x4F54290A
++#define OTG_CORE_REV_2_91a	0x4F54291A
++#define OTG_CORE_REV_2_92a	0x4F54292A
++#define OTG_CORE_REV_2_93a	0x4F54293A
++#define OTG_CORE_REV_2_94a	0x4F54294A
++#define OTG_CORE_REV_3_00a	0x4F54300A
++#define OTG_CORE_REV_3_10a	0x4F54310A
++
++/**
++ * Information for each ISOC packet.
++ */
++typedef struct iso_pkt_info {
++	uint32_t offset;
++	uint32_t length;
++	int32_t status;
++} iso_pkt_info_t;
++
++/**
++ * The <code>dwc_ep</code> structure represents the state of a single
++ * endpoint when acting in device mode. It contains the data items
++ * needed for an endpoint to be activated and transfer packets.
++ */
++typedef struct dwc_ep {
++	/** EP number used for register address lookup */
++	uint8_t num;
++	/** EP direction 0 = OUT */
++	unsigned is_in:1;
++	/** EP active. */
++	unsigned active:1;
++
++	/**
++	 * Periodic Tx FIFO # for IN EPs For INTR EP set to 0 to use non-periodic
++	 * Tx FIFO. If dedicated Tx FIFOs are enabled Tx FIFO # FOR IN EPs*/
++	unsigned tx_fifo_num:4;
++	/** EP type: 0 - Control, 1 - ISOC,	 2 - BULK,	3 - INTR */
++	unsigned type:2;
++#define DWC_OTG_EP_TYPE_CONTROL	   0
++#define DWC_OTG_EP_TYPE_ISOC	   1
++#define DWC_OTG_EP_TYPE_BULK	   2
++#define DWC_OTG_EP_TYPE_INTR	   3
++
++	/** DATA start PID for INTR and BULK EP */
++	unsigned data_pid_start:1;
++	/** Frame (even/odd) for ISOC EP */
++	unsigned even_odd_frame:1;
++	/** Max Packet bytes */
++	unsigned maxpacket:11;
++
++	/** Max Transfer size */
++	uint32_t maxxfer;
++
++	/** @name Transfer state */
++	/** @{ */
++
++	/**
++	 * Pointer to the beginning of the transfer buffer -- do not modify
++	 * during transfer.
++	 */
++	dwc_dma_t dma_addr;
++
++	dwc_dma_t dma_desc_addr;
++	dwc_otg_dev_dma_desc_t *desc_addr;
++
++	/* Additional desc chain for ISO transfers */
++	dwc_dma_t dma_desc_addr1;
++	dwc_otg_dev_dma_desc_t *desc_addr1;
++	/* Flag indicating which one of two ISO desc chains currently is in use */
++	uint8_t use_add_buf;
++
++	uint8_t *start_xfer_buff;
++	/** pointer to the transfer buffer */
++	uint8_t *xfer_buff;
++	/** Number of bytes to transfer */
++	unsigned xfer_len:19;
++	/** Number of bytes transferred. */
++	unsigned xfer_count:19;
++	/** Sent ZLP */
++	unsigned sent_zlp:1;
++	/** Total len for control transfer */
++	unsigned total_len:19;
++
++	/** stall clear flag */
++	unsigned stall_clear_flag:1;
++
++	/** SETUP pkt cnt rollover flag for EP0 out*/
++	unsigned stp_rollover;
++
++#ifdef DWC_UTE_CFI
++	/* The buffer mode */
++	data_buffer_mode_e buff_mode;
++
++	/* The chain of DMA descriptors.
++	 * MAX_DMA_DESCS_PER_EP will be allocated for each active EP.
++	 */
++	dwc_otg_dma_desc_t *descs;
++
++	/* The DMA address of the descriptors chain start */
++	dma_addr_t descs_dma_addr;
++	/** This variable stores the length of the last enqueued request */
++	uint32_t cfi_req_len;
++#endif				//DWC_UTE_CFI
++
++/** Max DMA Descriptor count for any EP */
++#define MAX_DMA_DESC_CNT 256
++	/** Allocated DMA Desc count */
++	uint32_t desc_cnt;
++
++	/** First ISO Desc in use in the first chain*/
++	uint32_t iso_desc_first;
++	/** Last ISO Desc in use in the second chain */
++	uint32_t iso_desc_second;
++	/** Flag indicated that iso transfers were started */
++	uint8_t iso_transfer_started;
++
++	/** bInterval */
++	uint32_t bInterval;
++	/** Next frame num to setup next ISOC transfer */
++	uint32_t frame_num;
++	/** Indicates SOF number overrun in DSTS */
++	uint8_t frm_overrun;
++
++#ifdef DWC_UTE_PER_IO
++	/** Next frame num for which will be setup DMA Desc */
++	uint32_t xiso_frame_num;
++	/** bInterval */
++	uint32_t xiso_bInterval;
++	/** Count of currently active transfers - shall be either 0 or 1 */
++	int xiso_active_xfers;
++	int xiso_queued_xfers;
++#endif
++#ifdef DWC_EN_ISOC
++	/**
++	 * Variables specific for ISOC EPs
++	 *
++	 */
++	/** DMA addresses of ISOC buffers */
++	dwc_dma_t dma_addr0;
++	dwc_dma_t dma_addr1;
++
++	dwc_dma_t iso_dma_desc_addr;
++	dwc_otg_dev_dma_desc_t *iso_desc_addr;
++
++	/** pointer to the transfer buffers */
++	uint8_t *xfer_buff0;
++	uint8_t *xfer_buff1;
++
++	/** number of ISOC Buffer is processing */
++	uint32_t proc_buf_num;
++	/** Interval of ISOC Buffer processing */
++	uint32_t buf_proc_intrvl;
++	/** Data size for regular frame */
++	uint32_t data_per_frame;
++
++	/* todo - pattern data support is to be implemented in the future */
++	/** Data size for pattern frame */
++	uint32_t data_pattern_frame;
++	/** Frame number of pattern data */
++	uint32_t sync_frame;
++
++	/** bInterval */
++	uint32_t bInterval;
++	/** ISO Packet number per frame */
++	uint32_t pkt_per_frm;
++	/** Next frame num for which will be setup DMA Desc */
++	uint32_t next_frame;
++	/** Number of packets per buffer processing */
++	uint32_t pkt_cnt;
++	/** Info for all isoc packets */
++	iso_pkt_info_t *pkt_info;
++	/** current pkt number */
++	uint32_t cur_pkt;
++	/** current pkt number */
++	uint8_t *cur_pkt_addr;
++	/** current pkt number */
++	uint32_t cur_pkt_dma_addr;
++#endif				/* DWC_EN_ISOC */
++
++/** @} */
++} dwc_ep_t;
++
++/*
++ * Reasons for halting a host channel.
++ */
++typedef enum dwc_otg_halt_status {
++	DWC_OTG_HC_XFER_NO_HALT_STATUS,
++	DWC_OTG_HC_XFER_COMPLETE,
++	DWC_OTG_HC_XFER_URB_COMPLETE,
++	DWC_OTG_HC_XFER_ACK,
++	DWC_OTG_HC_XFER_NAK,
++	DWC_OTG_HC_XFER_NYET,
++	DWC_OTG_HC_XFER_STALL,
++	DWC_OTG_HC_XFER_XACT_ERR,
++	DWC_OTG_HC_XFER_FRAME_OVERRUN,
++	DWC_OTG_HC_XFER_BABBLE_ERR,
++	DWC_OTG_HC_XFER_DATA_TOGGLE_ERR,
++	DWC_OTG_HC_XFER_AHB_ERR,
++	DWC_OTG_HC_XFER_PERIODIC_INCOMPLETE,
++	DWC_OTG_HC_XFER_URB_DEQUEUE
++} dwc_otg_halt_status_e;
++
++/**
++ * Host channel descriptor. This structure represents the state of a single
++ * host channel when acting in host mode. It contains the data items needed to
++ * transfer packets to an endpoint via a host channel.
++ */
++typedef struct dwc_hc {
++	/** Host channel number used for register address lookup */
++	uint8_t hc_num;
++
++	/** Device to access */
++	unsigned dev_addr:7;
++
++	/** EP to access */
++	unsigned ep_num:4;
++
++	/** EP direction. 0: OUT, 1: IN */
++	unsigned ep_is_in:1;
++
++	/**
++	 * EP speed.
++	 * One of the following values:
++	 *	- DWC_OTG_EP_SPEED_LOW
++	 *	- DWC_OTG_EP_SPEED_FULL
++	 *	- DWC_OTG_EP_SPEED_HIGH
++	 */
++	unsigned speed:2;
++#define DWC_OTG_EP_SPEED_LOW	0
++#define DWC_OTG_EP_SPEED_FULL	1
++#define DWC_OTG_EP_SPEED_HIGH	2
++
++	/**
++	 * Endpoint type.
++	 * One of the following values:
++	 *	- DWC_OTG_EP_TYPE_CONTROL: 0
++	 *	- DWC_OTG_EP_TYPE_ISOC: 1
++	 *	- DWC_OTG_EP_TYPE_BULK: 2
++	 *	- DWC_OTG_EP_TYPE_INTR: 3
++	 */
++	unsigned ep_type:2;
++
++	/** Max packet size in bytes */
++	unsigned max_packet:11;
++
++	/**
++	 * PID for initial transaction.
++	 * 0: DATA0,<br>
++	 * 1: DATA2,<br>
++	 * 2: DATA1,<br>
++	 * 3: MDATA (non-Control EP),
++	 *	  SETUP (Control EP)
++	 */
++	unsigned data_pid_start:2;
++#define DWC_OTG_HC_PID_DATA0 0
++#define DWC_OTG_HC_PID_DATA2 1
++#define DWC_OTG_HC_PID_DATA1 2
++#define DWC_OTG_HC_PID_MDATA 3
++#define DWC_OTG_HC_PID_SETUP 3
++
++	/** Number of periodic transactions per (micro)frame */
++	unsigned multi_count:2;
++
++	/** @name Transfer State */
++	/** @{ */
++
++	/** Pointer to the current transfer buffer position. */
++	uint8_t *xfer_buff;
++	/**
++	 * In Buffer DMA mode this buffer will be used
++	 * if xfer_buff is not DWORD aligned.
++	 */
++	dwc_dma_t align_buff;
++	/** Total number of bytes to transfer. */
++	uint32_t xfer_len;
++	/** Number of bytes transferred so far. */
++	uint32_t xfer_count;
++	/** Packet count at start of transfer.*/
++	uint16_t start_pkt_count;
++
++	/**
++	 * Flag to indicate whether the transfer has been started. Set to 1 if
++	 * it has been started, 0 otherwise.
++	 */
++	uint8_t xfer_started;
++
++	/**
++	 * Set to 1 to indicate that a PING request should be issued on this
++	 * channel. If 0, process normally.
++	 */
++	uint8_t do_ping;
++
++	/**
++	 * Set to 1 to indicate that the error count for this transaction is
++	 * non-zero. Set to 0 if the error count is 0.
++	 */
++	uint8_t error_state;
++
++	/**
++	 * Set to 1 to indicate that this channel should be halted the next
++	 * time a request is queued for the channel. This is necessary in
++	 * slave mode if no request queue space is available when an attempt
++	 * is made to halt the channel.
++	 */
++	uint8_t halt_on_queue;
++
++	/**
++	 * Set to 1 if the host channel has been halted, but the core is not
++	 * finished flushing queued requests. Otherwise 0.
++	 */
++	uint8_t halt_pending;
++
++	/**
++	 * Reason for halting the host channel.
++	 */
++	dwc_otg_halt_status_e halt_status;
++
++	/*
++	 * Split settings for the host channel
++	 */
++	uint8_t do_split;		   /**< Enable split for the channel */
++	uint8_t complete_split;	   /**< Enable complete split */
++	uint8_t hub_addr;		   /**< Address of high speed hub */
++
++	uint8_t port_addr;		   /**< Port of the low/full speed device */
++	/** Split transaction position
++	 * One of the following values:
++	 *	  - DWC_HCSPLIT_XACTPOS_MID
++	 *	  - DWC_HCSPLIT_XACTPOS_BEGIN
++	 *	  - DWC_HCSPLIT_XACTPOS_END
++	 *	  - DWC_HCSPLIT_XACTPOS_ALL */
++	uint8_t xact_pos;
++
++	/** Set when the host channel does a short read. */
++	uint8_t short_read;
++
++	/**
++	 * Number of requests issued for this channel since it was assigned to
++	 * the current transfer (not counting PINGs).
++	 */
++	uint8_t requests;
++
++	/**
++	 * Queue Head for the transfer being processed by this channel.
++	 */
++	struct dwc_otg_qh *qh;
++
++	/** @} */
++
++	/** Entry in list of host channels. */
++	 DWC_CIRCLEQ_ENTRY(dwc_hc) hc_list_entry;
++
++	/** @name Descriptor DMA support */
++	/** @{ */
++
++	/** Number of Transfer Descriptors */
++	uint16_t ntd;
++
++	/** Descriptor List DMA address */
++	dwc_dma_t desc_list_addr;
++
++	/** Scheduling micro-frame bitmap. */
++	uint8_t schinfo;
++
++	/** @} */
++} dwc_hc_t;
++
++/**
++ * The following parameters may be specified when starting the module. These
++ * parameters define how the DWC_otg controller should be configured.
++ */
++typedef struct dwc_otg_core_params {
++	int32_t opt;
++
++	/**
++	 * Specifies the OTG capabilities. The driver will automatically
++	 * detect the value for this parameter if none is specified.
++	 * 0 - HNP and SRP capable (default)
++	 * 1 - SRP Only capable
++	 * 2 - No HNP/SRP capable
++	 */
++	int32_t otg_cap;
++
++	/**
++	 * Specifies whether to use slave or DMA mode for accessing the data
++	 * FIFOs. The driver will automatically detect the value for this
++	 * parameter if none is specified.
++	 * 0 - Slave
++	 * 1 - DMA (default, if available)
++	 */
++	int32_t dma_enable;
++
++	/**
++	 * When DMA mode is enabled specifies whether to use address DMA or DMA
++	 * Descriptor mode for accessing the data FIFOs in device mode. The driver
++	 * will automatically detect the value for this if none is specified.
++	 * 0 - address DMA
++	 * 1 - DMA Descriptor(default, if available)
++	 */
++	int32_t dma_desc_enable;
++	/** The DMA Burst size (applicable only for External DMA
++	 * Mode). 1, 4, 8 16, 32, 64, 128, 256 (default 32)
++	 */
++	int32_t dma_burst_size;	/* Translate this to GAHBCFG values */
++
++	/**
++	 * Specifies the maximum speed of operation in host and device mode.
++	 * The actual speed depends on the speed of the attached device and
++	 * the value of phy_type. The actual speed depends on the speed of the
++	 * attached device.
++	 * 0 - High Speed (default)
++	 * 1 - Full Speed
++	 */
++	int32_t speed;
++	/** Specifies whether low power mode is supported when attached
++	 *	to a Full Speed or Low Speed device in host mode.
++	 * 0 - Don't support low power mode (default)
++	 * 1 - Support low power mode
++	 */
++	int32_t host_support_fs_ls_low_power;
++
++	/** Specifies the PHY clock rate in low power mode when connected to a
++	 * Low Speed device in host mode. This parameter is applicable only if
++	 * HOST_SUPPORT_FS_LS_LOW_POWER is enabled. If PHY_TYPE is set to FS
++	 * then defaults to 6 MHZ otherwise 48 MHZ.
++	 *
++	 * 0 - 48 MHz
++	 * 1 - 6 MHz
++	 */
++	int32_t host_ls_low_power_phy_clk;
++
++	/**
++	 * 0 - Use cC FIFO size parameters
++	 * 1 - Allow dynamic FIFO sizing (default)
++	 */
++	int32_t enable_dynamic_fifo;
++
++	/** Total number of 4-byte words in the data FIFO memory. This
++	 * memory includes the Rx FIFO, non-periodic Tx FIFO, and periodic
++	 * Tx FIFOs.
++	 * 32 to 32768 (default 8192)
++	 * Note: The total FIFO memory depth in the FPGA configuration is 8192.
++	 */
++	int32_t data_fifo_size;
++
++	/** Number of 4-byte words in the Rx FIFO in device mode when dynamic
++	 * FIFO sizing is enabled.
++	 * 16 to 32768 (default 1064)
++	 */
++	int32_t dev_rx_fifo_size;
++
++	/** Number of 4-byte words in the non-periodic Tx FIFO in device mode
++	 * when dynamic FIFO sizing is enabled.
++	 * 16 to 32768 (default 1024)
++	 */
++	int32_t dev_nperio_tx_fifo_size;
++
++	/** Number of 4-byte words in each of the periodic Tx FIFOs in device
++	 * mode when dynamic FIFO sizing is enabled.
++	 * 4 to 768 (default 256)
++	 */
++	uint32_t dev_perio_tx_fifo_size[MAX_PERIO_FIFOS];
++
++	/** Number of 4-byte words in the Rx FIFO in host mode when dynamic
++	 * FIFO sizing is enabled.
++	 * 16 to 32768 (default 1024)
++	 */
++	int32_t host_rx_fifo_size;
++
++	/** Number of 4-byte words in the non-periodic Tx FIFO in host mode
++	 * when Dynamic FIFO sizing is enabled in the core.
++	 * 16 to 32768 (default 1024)
++	 */
++	int32_t host_nperio_tx_fifo_size;
++
++	/** Number of 4-byte words in the host periodic Tx FIFO when dynamic
++	 * FIFO sizing is enabled.
++	 * 16 to 32768 (default 1024)
++	 */
++	int32_t host_perio_tx_fifo_size;
++
++	/** The maximum transfer size supported in bytes.
++	 * 2047 to 65,535  (default 65,535)
++	 */
++	int32_t max_transfer_size;
++
++	/** The maximum number of packets in a transfer.
++	 * 15 to 511  (default 511)
++	 */
++	int32_t max_packet_count;
++
++	/** The number of host channel registers to use.
++	 * 1 to 16 (default 12)
++	 * Note: The FPGA configuration supports a maximum of 12 host channels.
++	 */
++	int32_t host_channels;
++
++	/** The number of endpoints in addition to EP0 available for device
++	 * mode operations.
++	 * 1 to 15 (default 6 IN and OUT)
++	 * Note: The FPGA configuration supports a maximum of 6 IN and OUT
++	 * endpoints in addition to EP0.
++	 */
++	int32_t dev_endpoints;
++
++		/**
++		 * Specifies the type of PHY interface to use. By default, the driver
++		 * will automatically detect the phy_type.
++		 *
++		 * 0 - Full Speed PHY
++		 * 1 - UTMI+ (default)
++		 * 2 - ULPI
++		 */
++	int32_t phy_type;
++
++	/**
++	 * Specifies the UTMI+ Data Width. This parameter is
++	 * applicable for a PHY_TYPE of UTMI+ or ULPI. (For a ULPI
++	 * PHY_TYPE, this parameter indicates the data width between
++	 * the MAC and the ULPI Wrapper.) Also, this parameter is
++	 * applicable only if the OTG_HSPHY_WIDTH cC parameter was set
++	 * to "8 and 16 bits", meaning that the core has been
++	 * configured to work at either data path width.
++	 *
++	 * 8 or 16 bits (default 16)
++	 */
++	int32_t phy_utmi_width;
++
++	/**
++	 * Specifies whether the ULPI operates at double or single
++	 * data rate. This parameter is only applicable if PHY_TYPE is
++	 * ULPI.
++	 *
++	 * 0 - single data rate ULPI interface with 8 bit wide data
++	 * bus (default)
++	 * 1 - double data rate ULPI interface with 4 bit wide data
++	 * bus
++	 */
++	int32_t phy_ulpi_ddr;
++
++	/**
++	 * Specifies whether to use the internal or external supply to
++	 * drive the vbus with a ULPI phy.
++	 */
++	int32_t phy_ulpi_ext_vbus;
++
++	/**
++	 * Specifies whether to use the I2Cinterface for full speed PHY. This
++	 * parameter is only applicable if PHY_TYPE is FS.
++	 * 0 - No (default)
++	 * 1 - Yes
++	 */
++	int32_t i2c_enable;
++
++	int32_t ulpi_fs_ls;
++
++	int32_t ts_dline;
++
++	/**
++	 * Specifies whether dedicated transmit FIFOs are
++	 * enabled for non periodic IN endpoints in device mode
++	 * 0 - No
++	 * 1 - Yes
++	 */
++	int32_t en_multiple_tx_fifo;
++
++	/** Number of 4-byte words in each of the Tx FIFOs in device
++	 * mode when dynamic FIFO sizing is enabled.
++	 * 4 to 768 (default 256)
++	 */
++	uint32_t dev_tx_fifo_size[MAX_TX_FIFOS];
++
++	/** Thresholding enable flag-
++	 * bit 0 - enable non-ISO Tx thresholding
++	 * bit 1 - enable ISO Tx thresholding
++	 * bit 2 - enable Rx thresholding
++	 */
++	uint32_t thr_ctl;
++
++	/** Thresholding length for Tx
++	 *	FIFOs in 32 bit DWORDs
++	 */
++	uint32_t tx_thr_length;
++
++	/** Thresholding length for Rx
++	 *	FIFOs in 32 bit DWORDs
++	 */
++	uint32_t rx_thr_length;
++
++	/**
++	 * Specifies whether LPM (Link Power Management) support is enabled
++	 */
++	int32_t lpm_enable;
++
++	/**
++	* Specifies whether LPM Errata (Link Power Management) support is enabled
++	*/
++	int32_t besl_enable;
++
++	/**
++	* Specifies the baseline besl value
++	*/
++	int32_t baseline_besl;
++
++	/**
++	* Specifies the deep besl value
++	*/
++	int32_t deep_besl;
++	/** Per Transfer Interrupt
++	 *	mode enable flag
++	 * 1 - Enabled
++	 * 0 - Disabled
++	 */
++	int32_t pti_enable;
++
++	/** Multi Processor Interrupt
++	 *	mode enable flag
++	 * 1 - Enabled
++	 * 0 - Disabled
++	 */
++	int32_t mpi_enable;
++
++	/** IS_USB Capability
++	 * 1 - Enabled
++	 * 0 - Disabled
++	 */
++	int32_t ic_usb_cap;
++
++	/** AHB Threshold Ratio
++	 * 2'b00 AHB Threshold =	MAC Threshold
++	 * 2'b01 AHB Threshold = 1/2	MAC Threshold
++	 * 2'b10 AHB Threshold = 1/4	MAC Threshold
++	 * 2'b11 AHB Threshold = 1/8	MAC Threshold
++	 */
++	int32_t ahb_thr_ratio;
++
++	/** ADP Support
++	 * 1 - Enabled
++	 * 0 - Disabled
++	 */
++	int32_t adp_supp_enable;
++
++	/** HFIR Reload Control
++	 * 0 - The HFIR cannot be reloaded dynamically.
++	 * 1 - Allow dynamic reloading of the HFIR register during runtime.
++	 */
++	int32_t reload_ctl;
++
++	/** DCFG: Enable device Out NAK
++	 * 0 - The core does not set NAK after Bulk Out transfer complete.
++	 * 1 - The core sets NAK after Bulk OUT transfer complete.
++	 */
++	int32_t dev_out_nak;
++
++	/** DCFG: Enable Continue on BNA
++	 * After receiving BNA interrupt the core disables the endpoint,when the
++	 * endpoint is re-enabled by the application the core starts processing
++	 * 0 - from the DOEPDMA descriptor
++	 * 1 - from the descriptor which received the BNA.
++	 */
++	int32_t cont_on_bna;
++
++	/** GAHBCFG: AHB Single Support
++	 * This bit when programmed supports SINGLE transfers for remainder
++	 * data in a transfer for DMA mode of operation.
++	 * 0 - in this case the remainder data will be sent using INCR burst size.
++	 * 1 - in this case the remainder data will be sent using SINGLE burst size.
++	 */
++	int32_t ahb_single;
++
++	/** Core Power down mode
++	 * 0 - No Power Down is enabled
++	 * 1 - Reserved
++	 * 2 - Complete Power Down (Hibernation)
++	 */
++	int32_t power_down;
++
++	/** OTG revision supported
++	 * 0 - OTG 1.3 revision
++	 * 1 - OTG 2.0 revision
++	 */
++	int32_t otg_ver;
++
++} dwc_otg_core_params_t;
++
++#ifdef DEBUG
++struct dwc_otg_core_if;
++typedef struct hc_xfer_info {
++	struct dwc_otg_core_if *core_if;
++	dwc_hc_t *hc;
++} hc_xfer_info_t;
++#endif
++
++typedef struct ep_xfer_info {
++	struct dwc_otg_core_if *core_if;
++	dwc_ep_t *ep;
++	uint8_t state;
++} ep_xfer_info_t;
++/*
++ * Device States
++ */
++typedef enum dwc_otg_lx_state {
++	/** On state */
++	DWC_OTG_L0,
++	/** LPM sleep state*/
++	DWC_OTG_L1,
++	/** USB suspend state*/
++	DWC_OTG_L2,
++	/** Off state*/
++	DWC_OTG_L3
++} dwc_otg_lx_state_e;
++
++struct dwc_otg_global_regs_backup {
++	uint32_t gotgctl_local;
++	uint32_t gintmsk_local;
++	uint32_t gahbcfg_local;
++	uint32_t gusbcfg_local;
++	uint32_t grxfsiz_local;
++	uint32_t gnptxfsiz_local;
++#ifdef CONFIG_USB_DWC_OTG_LPM
++	uint32_t glpmcfg_local;
++#endif
++	uint32_t gi2cctl_local;
++	uint32_t hptxfsiz_local;
++	uint32_t pcgcctl_local;
++	uint32_t gdfifocfg_local;
++	uint32_t dtxfsiz_local[MAX_EPS_CHANNELS];
++	uint32_t gpwrdn_local;
++	uint32_t xhib_pcgcctl;
++	uint32_t xhib_gpwrdn;
++};
++
++struct dwc_otg_host_regs_backup {
++	uint32_t hcfg_local;
++	uint32_t haintmsk_local;
++	uint32_t hcintmsk_local[MAX_EPS_CHANNELS];
++	uint32_t hprt0_local;
++	uint32_t hfir_local;
++};
++
++struct dwc_otg_dev_regs_backup {
++	uint32_t dcfg;
++	uint32_t dctl;
++	uint32_t daintmsk;
++	uint32_t diepmsk;
++	uint32_t doepmsk;
++	uint32_t diepctl[MAX_EPS_CHANNELS];
++	uint32_t dieptsiz[MAX_EPS_CHANNELS];
++	uint32_t diepdma[MAX_EPS_CHANNELS];
++};
++/**
++ * The <code>dwc_otg_core_if</code> structure contains information needed to manage
++ * the DWC_otg controller acting in either host or device mode. It
++ * represents the programming view of the controller as a whole.
++ */
++struct dwc_otg_core_if {
++	/** Parameters that define how the core should be configured.*/
++	dwc_otg_core_params_t *core_params;
++
++	/** Core Global registers starting at offset 000h. */
++	dwc_otg_core_global_regs_t *core_global_regs;
++
++	/** Device-specific information */
++	dwc_otg_dev_if_t *dev_if;
++	/** Host-specific information */
++	dwc_otg_host_if_t *host_if;
++
++	/** Value from SNPSID register */
++	uint32_t snpsid;
++
++	/*
++	 * Set to 1 if the core PHY interface bits in USBCFG have been
++	 * initialized.
++	 */
++	uint8_t phy_init_done;
++
++	/*
++	 * SRP Success flag, set by srp success interrupt in FS I2C mode
++	 */
++	uint8_t srp_success;
++	uint8_t srp_timer_started;
++	/** Timer for SRP. If it expires before SRP is successful
++	 * clear the SRP. */
++	dwc_timer_t *srp_timer;
++
++#ifdef DWC_DEV_SRPCAP
++	/* This timer is needed to power on the hibernated host core if SRP is not
++	 * initiated on connected SRP capable device for limited period of time
++	 */
++	uint8_t pwron_timer_started;
++	dwc_timer_t *pwron_timer;
++#endif
++	/* Common configuration information */
++	/** Power and Clock Gating Control Register */
++	volatile uint32_t *pcgcctl;
++#define DWC_OTG_PCGCCTL_OFFSET 0xE00
++
++	/** Push/pop addresses for endpoints or host channels.*/
++	uint32_t *data_fifo[MAX_EPS_CHANNELS];
++#define DWC_OTG_DATA_FIFO_OFFSET 0x1000
++#define DWC_OTG_DATA_FIFO_SIZE 0x1000
++
++	/** Total RAM for FIFOs (Bytes) */
++	uint16_t total_fifo_size;
++	/** Size of Rx FIFO (Bytes) */
++	uint16_t rx_fifo_size;
++	/** Size of Non-periodic Tx FIFO (Bytes) */
++	uint16_t nperio_tx_fifo_size;
++
++	/** 1 if DMA is enabled, 0 otherwise. */
++	uint8_t dma_enable;
++
++	/** 1 if DMA descriptor is enabled, 0 otherwise. */
++	uint8_t dma_desc_enable;
++
++	/** 1 if PTI Enhancement mode is enabled, 0 otherwise. */
++	uint8_t pti_enh_enable;
++
++	/** 1 if MPI Enhancement mode is enabled, 0 otherwise. */
++	uint8_t multiproc_int_enable;
++
++	/** 1 if dedicated Tx FIFOs are enabled, 0 otherwise. */
++	uint8_t en_multiple_tx_fifo;
++
++	/** Set to 1 if multiple packets of a high-bandwidth transfer is in
++	 * process of being queued */
++	uint8_t queuing_high_bandwidth;
++
++	/** Hardware Configuration -- stored here for convenience.*/
++	hwcfg1_data_t hwcfg1;
++	hwcfg2_data_t hwcfg2;
++	hwcfg3_data_t hwcfg3;
++	hwcfg4_data_t hwcfg4;
++	fifosize_data_t hptxfsiz;
++
++	/** Host and Device Configuration -- stored here for convenience.*/
++	hcfg_data_t hcfg;
++	dcfg_data_t dcfg;
++
++	/** The operational State, during transations
++	 * (a_host>>a_peripherial and b_device=>b_host) this may not
++	 * match the core but allows the software to determine
++	 * transitions.
++	 */
++	uint8_t op_state;
++
++	/** Test mode for PET testing */
++	uint8_t test_mode;
++
++	/**
++	 * Set to 1 if the HCD needs to be restarted on a session request
++	 * interrupt. This is required if no connector ID status change has
++	 * occurred since the HCD was last disconnected.
++	 */
++	uint8_t restart_hcd_on_session_req;
++
++	/** HCD callbacks */
++	/** A-Device is a_host */
++#define A_HOST		(1)
++	/** A-Device is a_suspend */
++#define A_SUSPEND	(2)
++	/** A-Device is a_peripherial */
++#define A_PERIPHERAL	(3)
++	/** B-Device is operating as a Peripheral. */
++#define B_PERIPHERAL	(4)
++	/** B-Device is operating as a Host. */
++#define B_HOST		(5)
++
++	/** HCD callbacks */
++	struct dwc_otg_cil_callbacks *hcd_cb;
++	/** PCD callbacks */
++	struct dwc_otg_cil_callbacks *pcd_cb;
++
++	/** Device mode Periodic Tx FIFO Mask */
++	uint32_t p_tx_msk;
++	/** Device mode Periodic Tx FIFO Mask */
++	uint32_t tx_msk;
++
++	/** Workqueue object used for handling several interrupts */
++	dwc_workq_t *wq_otg;
++
++	/** Timer object used for handling "Wakeup Detected" Interrupt */
++	dwc_timer_t *wkp_timer;
++	/** This arrays used for debug purposes for DEV OUT NAK enhancement */
++	uint32_t start_doeptsiz_val[MAX_EPS_CHANNELS];
++	ep_xfer_info_t ep_xfer_info[MAX_EPS_CHANNELS];
++	dwc_timer_t *ep_xfer_timer[MAX_EPS_CHANNELS];
++#ifdef DEBUG
++	uint32_t start_hcchar_val[MAX_EPS_CHANNELS];
++
++	hc_xfer_info_t hc_xfer_info[MAX_EPS_CHANNELS];
++	dwc_timer_t *hc_xfer_timer[MAX_EPS_CHANNELS];
++
++	uint32_t hfnum_7_samples;
++	uint64_t hfnum_7_frrem_accum;
++	uint32_t hfnum_0_samples;
++	uint64_t hfnum_0_frrem_accum;
++	uint32_t hfnum_other_samples;
++	uint64_t hfnum_other_frrem_accum;
++#endif
++
++#ifdef DWC_UTE_CFI
++	uint16_t pwron_rxfsiz;
++	uint16_t pwron_gnptxfsiz;
++	uint16_t pwron_txfsiz[15];
++
++	uint16_t init_rxfsiz;
++	uint16_t init_gnptxfsiz;
++	uint16_t init_txfsiz[15];
++#endif
++
++	/** Lx state of device */
++	dwc_otg_lx_state_e lx_state;
++
++	/** Saved Core Global registers */
++	struct dwc_otg_global_regs_backup *gr_backup;
++	/** Saved Host registers */
++	struct dwc_otg_host_regs_backup *hr_backup;
++	/** Saved Device registers */
++	struct dwc_otg_dev_regs_backup *dr_backup;
++
++	/** Power Down Enable */
++	uint32_t power_down;
++
++	/** ADP support Enable */
++	uint32_t adp_enable;
++
++	/** ADP structure object */
++	dwc_otg_adp_t adp;
++
++	/** hibernation/suspend flag */
++	int hibernation_suspend;
++
++	/** Device mode extended hibernation flag */
++	int xhib;
++
++	/** OTG revision supported */
++	uint32_t otg_ver;
++
++	/** OTG status flag used for HNP polling */
++	uint8_t otg_sts;
++
++	/** Pointer to either hcd->lock or pcd->lock */
++	dwc_spinlock_t *lock;
++
++	/** Start predict NextEP based on Learning Queue if equal 1,
++	 * also used as counter of disabled NP IN EP's */
++	uint8_t start_predict;
++
++	/** NextEp sequence, including EP0: nextep_seq[] = EP if non-periodic and
++	 * active, 0xff otherwise */
++	uint8_t nextep_seq[MAX_EPS_CHANNELS];
++
++	/** Index of fisrt EP in nextep_seq array which should be re-enabled **/
++	uint8_t first_in_nextep_seq;
++
++	/** Frame number while entering to ISR - needed for ISOCs **/
++	uint32_t frame_num;
++
++	/** Flag to not perform ADP probing if IDSTS event happened */
++	uint8_t stop_adpprb;
++
++};
++
++#ifdef DEBUG
++/*
++ * This function is called when transfer is timed out.
++ */
++extern void hc_xfer_timeout(void *ptr);
++#endif
++
++/*
++ * This function is called when transfer is timed out on endpoint.
++ */
++extern void ep_xfer_timeout(void *ptr);
++
++/*
++ * The following functions are functions for works
++ * using during handling some interrupts
++ */
++extern void w_conn_id_status_change(void *p);
++
++extern void w_wakeup_detected(void *p);
++
++/** Saves global register values into system memory. */
++extern int dwc_otg_save_global_regs(dwc_otg_core_if_t * core_if);
++/** Saves device register values into system memory. */
++extern int dwc_otg_save_dev_regs(dwc_otg_core_if_t * core_if);
++/** Saves host register values into system memory. */
++extern int dwc_otg_save_host_regs(dwc_otg_core_if_t * core_if);
++/** Restore global register values. */
++extern int dwc_otg_restore_global_regs(dwc_otg_core_if_t * core_if);
++/** Restore host register values. */
++extern int dwc_otg_restore_host_regs(dwc_otg_core_if_t * core_if, int reset);
++/** Restore device register values. */
++extern int dwc_otg_restore_dev_regs(dwc_otg_core_if_t * core_if,
++				    int rem_wakeup);
++extern int restore_lpm_i2c_regs(dwc_otg_core_if_t * core_if);
++extern int restore_essential_regs(dwc_otg_core_if_t * core_if, int rmode,
++				  int is_host);
++
++extern int dwc_otg_host_hibernation_restore(dwc_otg_core_if_t * core_if,
++					    int restore_mode, int reset);
++extern int dwc_otg_device_hibernation_restore(dwc_otg_core_if_t * core_if,
++					      int rem_wakeup, int reset);
++
++/*
++ * The following functions support initialization of the CIL driver component
++ * and the DWC_otg controller.
++ */
++extern void dwc_otg_core_host_init(dwc_otg_core_if_t * _core_if);
++extern void dwc_otg_core_dev_init(dwc_otg_core_if_t * _core_if);
++
++/** @name Device CIL Functions
++ * The following functions support managing the DWC_otg controller in device
++ * mode.
++ */
++/**@{*/
++extern void dwc_otg_wakeup(dwc_otg_core_if_t * _core_if);
++extern void dwc_otg_read_setup_packet(dwc_otg_core_if_t * _core_if,
++				      uint32_t * _dest);
++extern uint32_t dwc_otg_get_frame_number(dwc_otg_core_if_t * _core_if);
++extern void dwc_otg_ep0_activate(dwc_otg_core_if_t * _core_if, dwc_ep_t * _ep);
++extern void dwc_otg_ep_activate(dwc_otg_core_if_t * _core_if, dwc_ep_t * _ep);
++extern void dwc_otg_ep_deactivate(dwc_otg_core_if_t * _core_if, dwc_ep_t * _ep);
++extern void dwc_otg_ep_start_transfer(dwc_otg_core_if_t * _core_if,
++				      dwc_ep_t * _ep);
++extern void dwc_otg_ep_start_zl_transfer(dwc_otg_core_if_t * _core_if,
++					 dwc_ep_t * _ep);
++extern void dwc_otg_ep0_start_transfer(dwc_otg_core_if_t * _core_if,
++				       dwc_ep_t * _ep);
++extern void dwc_otg_ep0_continue_transfer(dwc_otg_core_if_t * _core_if,
++					  dwc_ep_t * _ep);
++extern void dwc_otg_ep_write_packet(dwc_otg_core_if_t * _core_if,
++				    dwc_ep_t * _ep, int _dma);
++extern void dwc_otg_ep_set_stall(dwc_otg_core_if_t * _core_if, dwc_ep_t * _ep);
++extern void dwc_otg_ep_clear_stall(dwc_otg_core_if_t * _core_if,
++				   dwc_ep_t * _ep);
++extern void dwc_otg_enable_device_interrupts(dwc_otg_core_if_t * _core_if);
++
++#ifdef DWC_EN_ISOC
++extern void dwc_otg_iso_ep_start_frm_transfer(dwc_otg_core_if_t * core_if,
++					      dwc_ep_t * ep);
++extern void dwc_otg_iso_ep_start_buf_transfer(dwc_otg_core_if_t * core_if,
++					      dwc_ep_t * ep);
++#endif /* DWC_EN_ISOC */
++/**@}*/
++
++/** @name Host CIL Functions
++ * The following functions support managing the DWC_otg controller in host
++ * mode.
++ */
++/**@{*/
++extern void dwc_otg_hc_init(dwc_otg_core_if_t * _core_if, dwc_hc_t * _hc);
++extern void dwc_otg_hc_halt(dwc_otg_core_if_t * _core_if,
++			    dwc_hc_t * _hc, dwc_otg_halt_status_e _halt_status);
++extern void dwc_otg_hc_cleanup(dwc_otg_core_if_t * _core_if, dwc_hc_t * _hc);
++extern void dwc_otg_hc_start_transfer(dwc_otg_core_if_t * _core_if,
++				      dwc_hc_t * _hc);
++extern int dwc_otg_hc_continue_transfer(dwc_otg_core_if_t * _core_if,
++					dwc_hc_t * _hc);
++extern void dwc_otg_hc_do_ping(dwc_otg_core_if_t * _core_if, dwc_hc_t * _hc);
++extern void dwc_otg_hc_write_packet(dwc_otg_core_if_t * _core_if,
++				    dwc_hc_t * _hc);
++extern void dwc_otg_enable_host_interrupts(dwc_otg_core_if_t * _core_if);
++extern void dwc_otg_disable_host_interrupts(dwc_otg_core_if_t * _core_if);
++
++extern void dwc_otg_hc_start_transfer_ddma(dwc_otg_core_if_t * core_if,
++					   dwc_hc_t * hc);
++
++extern uint32_t calc_frame_interval(dwc_otg_core_if_t * core_if);
++extern int dwc_otg_check_haps_status(dwc_otg_core_if_t * core_if);
++
++/* Macro used to clear one channel interrupt */
++#define clear_hc_int(_hc_regs_, _intr_) \
++do { \
++	hcint_data_t hcint_clear = {.d32 = 0}; \
++	hcint_clear.b._intr_ = 1; \
++	DWC_WRITE_REG32(&(_hc_regs_)->hcint, hcint_clear.d32); \
++} while (0)
++
++/*
++ * Macro used to disable one channel interrupt. Channel interrupts are
++ * disabled when the channel is halted or released by the interrupt handler.
++ * There is no need to handle further interrupts of that type until the
++ * channel is re-assigned. In fact, subsequent handling may cause crashes
++ * because the channel structures are cleaned up when the channel is released.
++ */
++#define disable_hc_int(_hc_regs_, _intr_) \
++do { \
++	hcintmsk_data_t hcintmsk = {.d32 = 0}; \
++	hcintmsk.b._intr_ = 1; \
++	DWC_MODIFY_REG32(&(_hc_regs_)->hcintmsk, hcintmsk.d32, 0); \
++} while (0)
++
++/**
++ * This function Reads HPRT0 in preparation to modify. It keeps the
++ * WC bits 0 so that if they are read as 1, they won't clear when you
++ * write it back
++ */
++static inline uint32_t dwc_otg_read_hprt0(dwc_otg_core_if_t * _core_if)
++{
++	hprt0_data_t hprt0;
++	hprt0.d32 = DWC_READ_REG32(_core_if->host_if->hprt0);
++	hprt0.b.prtena = 0;
++	hprt0.b.prtconndet = 0;
++	hprt0.b.prtenchng = 0;
++	hprt0.b.prtovrcurrchng = 0;
++	return hprt0.d32;
++}
++
++/**@}*/
++
++/** @name Common CIL Functions
++ * The following functions support managing the DWC_otg controller in either
++ * device or host mode.
++ */
++/**@{*/
++
++extern void dwc_otg_read_packet(dwc_otg_core_if_t * core_if,
++				uint8_t * dest, uint16_t bytes);
++
++extern void dwc_otg_flush_tx_fifo(dwc_otg_core_if_t * _core_if, const int _num);
++extern void dwc_otg_flush_rx_fifo(dwc_otg_core_if_t * _core_if);
++extern void dwc_otg_core_reset(dwc_otg_core_if_t * _core_if);
++
++/**
++ * This function returns the Core Interrupt register.
++ */
++static inline uint32_t dwc_otg_read_core_intr(dwc_otg_core_if_t * core_if)
++{
++	return (DWC_READ_REG32(&core_if->core_global_regs->gintsts) &
++		DWC_READ_REG32(&core_if->core_global_regs->gintmsk));
++}
++
++/**
++ * This function returns the OTG Interrupt register.
++ */
++static inline uint32_t dwc_otg_read_otg_intr(dwc_otg_core_if_t * core_if)
++{
++	return (DWC_READ_REG32(&core_if->core_global_regs->gotgint));
++}
++
++/**
++ * This function reads the Device All Endpoints Interrupt register and
++ * returns the IN endpoint interrupt bits.
++ */
++static inline uint32_t dwc_otg_read_dev_all_in_ep_intr(dwc_otg_core_if_t *
++						       core_if)
++{
++
++	uint32_t v;
++
++	if (core_if->multiproc_int_enable) {
++		v = DWC_READ_REG32(&core_if->dev_if->
++				   dev_global_regs->deachint) &
++		    DWC_READ_REG32(&core_if->
++				   dev_if->dev_global_regs->deachintmsk);
++	} else {
++		v = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->daint) &
++		    DWC_READ_REG32(&core_if->dev_if->dev_global_regs->daintmsk);
++	}
++	return (v & 0xffff);
++}
++
++/**
++ * This function reads the Device All Endpoints Interrupt register and
++ * returns the OUT endpoint interrupt bits.
++ */
++static inline uint32_t dwc_otg_read_dev_all_out_ep_intr(dwc_otg_core_if_t *
++							core_if)
++{
++	uint32_t v;
++
++	if (core_if->multiproc_int_enable) {
++		v = DWC_READ_REG32(&core_if->dev_if->
++				   dev_global_regs->deachint) &
++		    DWC_READ_REG32(&core_if->
++				   dev_if->dev_global_regs->deachintmsk);
++	} else {
++		v = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->daint) &
++		    DWC_READ_REG32(&core_if->dev_if->dev_global_regs->daintmsk);
++	}
++
++	return ((v & 0xffff0000) >> 16);
++}
++
++/**
++ * This function returns the Device IN EP Interrupt register
++ */
++static inline uint32_t dwc_otg_read_dev_in_ep_intr(dwc_otg_core_if_t * core_if,
++						   dwc_ep_t * ep)
++{
++	dwc_otg_dev_if_t *dev_if = core_if->dev_if;
++	uint32_t v, msk, emp;
++
++	if (core_if->multiproc_int_enable) {
++		msk =
++		    DWC_READ_REG32(&dev_if->
++				   dev_global_regs->diepeachintmsk[ep->num]);
++		emp =
++		    DWC_READ_REG32(&dev_if->
++				   dev_global_regs->dtknqr4_fifoemptymsk);
++		msk |= ((emp >> ep->num) & 0x1) << 7;
++		v = DWC_READ_REG32(&dev_if->in_ep_regs[ep->num]->diepint) & msk;
++	} else {
++		msk = DWC_READ_REG32(&dev_if->dev_global_regs->diepmsk);
++		emp =
++		    DWC_READ_REG32(&dev_if->
++				   dev_global_regs->dtknqr4_fifoemptymsk);
++		msk |= ((emp >> ep->num) & 0x1) << 7;
++		v = DWC_READ_REG32(&dev_if->in_ep_regs[ep->num]->diepint) & msk;
++	}
++
++	return v;
++}
++
++/**
++ * This function returns the Device OUT EP Interrupt register
++ */
++static inline uint32_t dwc_otg_read_dev_out_ep_intr(dwc_otg_core_if_t *
++						    _core_if, dwc_ep_t * _ep)
++{
++	dwc_otg_dev_if_t *dev_if = _core_if->dev_if;
++	uint32_t v;
++	doepmsk_data_t msk = {.d32 = 0 };
++
++	if (_core_if->multiproc_int_enable) {
++		msk.d32 =
++		    DWC_READ_REG32(&dev_if->
++				   dev_global_regs->doepeachintmsk[_ep->num]);
++		if (_core_if->pti_enh_enable) {
++			msk.b.pktdrpsts = 1;
++		}
++		v = DWC_READ_REG32(&dev_if->
++				   out_ep_regs[_ep->num]->doepint) & msk.d32;
++	} else {
++		msk.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->doepmsk);
++		if (_core_if->pti_enh_enable) {
++			msk.b.pktdrpsts = 1;
++		}
++		v = DWC_READ_REG32(&dev_if->
++				   out_ep_regs[_ep->num]->doepint) & msk.d32;
++	}
++	return v;
++}
++
++/**
++ * This function returns the Host All Channel Interrupt register
++ */
++static inline uint32_t dwc_otg_read_host_all_channels_intr(dwc_otg_core_if_t *
++							   _core_if)
++{
++	return (DWC_READ_REG32(&_core_if->host_if->host_global_regs->haint));
++}
++
++static inline uint32_t dwc_otg_read_host_channel_intr(dwc_otg_core_if_t *
++						      _core_if, dwc_hc_t * _hc)
++{
++	return (DWC_READ_REG32
++		(&_core_if->host_if->hc_regs[_hc->hc_num]->hcint));
++}
++
++/**
++ * This function returns the mode of the operation, host or device.
++ *
++ * @return 0 - Device Mode, 1 - Host Mode
++ */
++static inline uint32_t dwc_otg_mode(dwc_otg_core_if_t * _core_if)
++{
++	return (DWC_READ_REG32(&_core_if->core_global_regs->gintsts) & 0x1);
++}
++
++/**@}*/
++
++/**
++ * DWC_otg CIL callback structure. This structure allows the HCD and
++ * PCD to register functions used for starting and stopping the PCD
++ * and HCD for role change on for a DRD.
++ */
++typedef struct dwc_otg_cil_callbacks {
++	/** Start function for role change */
++	int (*start) (void *_p);
++	/** Stop Function for role change */
++	int (*stop) (void *_p);
++	/** Disconnect Function for role change */
++	int (*disconnect) (void *_p);
++	/** Resume/Remote wakeup Function */
++	int (*resume_wakeup) (void *_p);
++	/** Suspend function */
++	int (*suspend) (void *_p);
++	/** Session Start (SRP) */
++	int (*session_start) (void *_p);
++#ifdef CONFIG_USB_DWC_OTG_LPM
++	/** Sleep (switch to L0 state) */
++	int (*sleep) (void *_p);
++#endif
++	/** Pointer passed to start() and stop() */
++	void *p;
++} dwc_otg_cil_callbacks_t;
++
++extern void dwc_otg_cil_register_pcd_callbacks(dwc_otg_core_if_t * _core_if,
++					       dwc_otg_cil_callbacks_t * _cb,
++					       void *_p);
++extern void dwc_otg_cil_register_hcd_callbacks(dwc_otg_core_if_t * _core_if,
++					       dwc_otg_cil_callbacks_t * _cb,
++					       void *_p);
++
++void dwc_otg_initiate_srp(void * core_if);
++
++//////////////////////////////////////////////////////////////////////
++/** Start the HCD.  Helper function for using the HCD callbacks.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ */
++static inline void cil_hcd_start(dwc_otg_core_if_t * core_if)
++{
++	if (core_if->hcd_cb && core_if->hcd_cb->start) {
++		core_if->hcd_cb->start(core_if->hcd_cb->p);
++	}
++}
++
++/** Stop the HCD.  Helper function for using the HCD callbacks.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ */
++static inline void cil_hcd_stop(dwc_otg_core_if_t * core_if)
++{
++	if (core_if->hcd_cb && core_if->hcd_cb->stop) {
++		core_if->hcd_cb->stop(core_if->hcd_cb->p);
++	}
++}
++
++/** Disconnect the HCD.  Helper function for using the HCD callbacks.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ */
++static inline void cil_hcd_disconnect(dwc_otg_core_if_t * core_if)
++{
++	if (core_if->hcd_cb && core_if->hcd_cb->disconnect) {
++		core_if->hcd_cb->disconnect(core_if->hcd_cb->p);
++	}
++}
++
++/** Inform the HCD the a New Session has begun.  Helper function for
++ * using the HCD callbacks.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ */
++static inline void cil_hcd_session_start(dwc_otg_core_if_t * core_if)
++{
++	if (core_if->hcd_cb && core_if->hcd_cb->session_start) {
++		core_if->hcd_cb->session_start(core_if->hcd_cb->p);
++	}
++}
++
++#ifdef CONFIG_USB_DWC_OTG_LPM
++/**
++ * Inform the HCD about LPM sleep.
++ * Helper function for using the HCD callbacks.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ */
++static inline void cil_hcd_sleep(dwc_otg_core_if_t * core_if)
++{
++	if (core_if->hcd_cb && core_if->hcd_cb->sleep) {
++		core_if->hcd_cb->sleep(core_if->hcd_cb->p);
++	}
++}
++#endif
++
++/** Resume the HCD.  Helper function for using the HCD callbacks.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ */
++static inline void cil_hcd_resume(dwc_otg_core_if_t * core_if)
++{
++	if (core_if->hcd_cb && core_if->hcd_cb->resume_wakeup) {
++		core_if->hcd_cb->resume_wakeup(core_if->hcd_cb->p);
++	}
++}
++
++/** Start the PCD.  Helper function for using the PCD callbacks.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ */
++static inline void cil_pcd_start(dwc_otg_core_if_t * core_if)
++{
++	if (core_if->pcd_cb && core_if->pcd_cb->start) {
++		core_if->pcd_cb->start(core_if->pcd_cb->p);
++	}
++}
++
++/** Stop the PCD.  Helper function for using the PCD callbacks.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ */
++static inline void cil_pcd_stop(dwc_otg_core_if_t * core_if)
++{
++	if (core_if->pcd_cb && core_if->pcd_cb->stop) {
++		core_if->pcd_cb->stop(core_if->pcd_cb->p);
++	}
++}
++
++/** Suspend the PCD.  Helper function for using the PCD callbacks.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ */
++static inline void cil_pcd_suspend(dwc_otg_core_if_t * core_if)
++{
++	if (core_if->pcd_cb && core_if->pcd_cb->suspend) {
++		core_if->pcd_cb->suspend(core_if->pcd_cb->p);
++	}
++}
++
++/** Resume the PCD.  Helper function for using the PCD callbacks.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ */
++static inline void cil_pcd_resume(dwc_otg_core_if_t * core_if)
++{
++	if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup) {
++		core_if->pcd_cb->resume_wakeup(core_if->pcd_cb->p);
++	}
++}
++
++//////////////////////////////////////////////////////////////////////
++
++#endif
+diff --git a/drivers/usb/gadget/udc/hiudc/dwc_otg_cil_intr.c b/drivers/usb/gadget/udc/hiudc/dwc_otg_cil_intr.c
+new file mode 100644
+index 0000000..46c4692
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc/dwc_otg_cil_intr.c
+@@ -0,0 +1,1738 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_cil_intr.c $
++ * $Revision: #37 $
++ * $Date: 2013/04/16 $
++ * $Change: 2207267 $
++ *
++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
++ * ========================================================================== */
++
++/** @file
++ *
++ * The Core Interface Layer provides basic services for accessing and
++ * managing the DWC_otg hardware. These services are used by both the
++ * Host Controller Driver and the Peripheral Controller Driver.
++ *
++ * This file contains the Common Interrupt handlers.
++ */
++#include "dwc_os.h"
++#include "dwc_otg_regs.h"
++#include "dwc_otg_cil.h"
++#include "dwc_otg_driver.h"
++#include "dwc_otg_pcd.h"
++#include "dwc_otg_hcd.h"
++
++#ifdef DEBUG
++inline const char *op_state_str(dwc_otg_core_if_t * core_if)
++{
++	return (core_if->op_state == A_HOST ? "a_host" :
++		(core_if->op_state == A_SUSPEND ? "a_suspend" :
++		 (core_if->op_state == A_PERIPHERAL ? "a_peripheral" :
++		  (core_if->op_state == B_PERIPHERAL ? "b_peripheral" :
++		   (core_if->op_state == B_HOST ? "b_host" : "unknown")))));
++}
++#endif
++
++/** This function will log a debug message
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ */
++int32_t dwc_otg_handle_mode_mismatch_intr(dwc_otg_core_if_t * core_if)
++{
++	gintsts_data_t gintsts;
++	DWC_WARN("Mode Mismatch Interrupt: currently in %s mode\n",
++		 dwc_otg_mode(core_if) ? "Host" : "Device");
++
++	/* Clear interrupt */
++	gintsts.d32 = 0;
++	gintsts.b.modemismatch = 1;
++	DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
++	return 1;
++}
++
++/**
++ * This function handles the OTG Interrupts. It reads the OTG
++ * Interrupt Register (GOTGINT) to determine what interrupt has
++ * occurred.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ */
++int32_t dwc_otg_handle_otg_intr(dwc_otg_core_if_t * core_if)
++{
++	dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
++	gotgint_data_t gotgint;
++	gotgctl_data_t gotgctl;
++	gintmsk_data_t gintmsk;
++	gpwrdn_data_t gpwrdn;
++
++	gotgint.d32 = DWC_READ_REG32(&global_regs->gotgint);
++	gotgctl.d32 = DWC_READ_REG32(&global_regs->gotgctl);
++	DWC_DEBUGPL(DBG_CIL, "++OTG Interrupt gotgint=%0x [%s]\n", gotgint.d32,
++		    op_state_str(core_if));
++
++	if (gotgint.b.sesenddet) {
++		DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
++			    "Session End Detected++ (%s)\n",
++			    op_state_str(core_if));
++		gotgctl.d32 = DWC_READ_REG32(&global_regs->gotgctl);
++
++		if (core_if->op_state == B_HOST) {
++			if (core_if->adp_enable && DWC_WORKQ_PENDING(core_if->wq_otg)) {
++
++				/* During ST_B_ADP test after HNP HSOTG tries to go to B_HOST
++				 * mode but PET is not expecting fully functional host at that
++				 * point and switches off the VBUS expecting immediate ADP probe */
++				gpwrdn.b.pmuintsel = 1;
++				gpwrdn.b.pmuactv = 1;
++				DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
++				dwc_mdelay(20);
++				dwc_otg_adp_probe_start(core_if);
++				goto exit_interrupt;
++			}
++			cil_pcd_start(core_if);
++			core_if->op_state = B_PERIPHERAL;
++		} else {
++			/* If not B_HOST and Device HNP still set. HNP
++			 * Did not succeed!*/
++			if (gotgctl.b.devhnpen) {
++				DWC_DEBUGPL(DBG_ANY, "Session End Detected\n");
++				__DWC_ERROR("Device Not Connected/Responding!\n");
++			}
++
++			/* If Session End Detected the B-Cable has
++			 * been disconnected. */
++			/* Reset PCD and Gadget driver to a
++			 * clean state. */
++			core_if->lx_state = DWC_OTG_L0;
++			DWC_SPINUNLOCK(core_if->lock);
++			cil_pcd_stop(core_if);
++			DWC_SPINLOCK(core_if->lock);
++
++			if (core_if->otg_ver) {
++				/** PET testing*/
++				gotgctl.d32 = 0;
++				gotgctl.b.devhnpen = 1;
++				DWC_MODIFY_REG32(&global_regs->gotgctl, gotgctl.d32, 0);
++				if (core_if->test_mode == 6) {
++					DWC_WORKQ_SCHEDULE_DELAYED(core_if->wq_otg,	dwc_otg_initiate_srp,
++								core_if, 3000, "initate SRP"); //manukz: old value was 50
++					core_if->test_mode = 0;
++				} else	if (core_if->adp_enable) {
++					if (core_if->power_down == 2) {
++						gpwrdn.d32 = 0;
++						gpwrdn.b.pwrdnswtch = 1;
++						DWC_MODIFY_REG32(&core_if->
++								 core_global_regs->
++								 gpwrdn, gpwrdn.d32, 0);
++					}
++
++					gpwrdn.d32 = 0;
++					gpwrdn.b.pmuintsel = 1;
++					gpwrdn.b.pmuactv = 1;
++					DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
++					dwc_otg_adp_sense_start(core_if);
++				}
++			}
++		}
++exit_interrupt:
++		if (core_if->otg_ver == 0) {
++			gotgctl.d32 = 0;
++			gotgctl.b.devhnpen = 1;
++			DWC_MODIFY_REG32(&global_regs->gotgctl, gotgctl.d32, 0);
++		}
++	}
++	if (gotgint.b.sesreqsucstschng) {
++		DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
++			    "Session Reqeust Success Status Change++\n");
++		gotgctl.d32 = DWC_READ_REG32(&global_regs->gotgctl);
++		if (gotgctl.b.sesreqscs) {
++
++			if ((core_if->core_params->phy_type ==
++			     DWC_PHY_TYPE_PARAM_FS) && (core_if->core_params->i2c_enable)) {
++				core_if->srp_success = 1;
++			} else {
++				DWC_SPINUNLOCK(core_if->lock);
++				cil_pcd_resume(core_if);
++				DWC_SPINLOCK(core_if->lock);
++				/* Clear Session Request */
++				gotgctl.d32 = 0;
++				gotgctl.b.sesreq = 1;
++				DWC_MODIFY_REG32(&global_regs->gotgctl,
++						 gotgctl.d32, 0);
++			}
++		}
++	}
++	if (gotgint.b.hstnegsucstschng) {
++		/* Print statements during the HNP interrupt handling
++		 * can cause it to fail.*/
++		gotgctl.d32 = DWC_READ_REG32(&global_regs->gotgctl);
++		/* WA for 3.00a- HW is not setting cur_mode, even sometimes
++		 * this does not help*/
++		if (core_if->snpsid >= OTG_CORE_REV_3_00a)
++			dwc_udelay(100);
++		if (gotgctl.b.hstnegscs) {
++			if (dwc_otg_is_host_mode(core_if)) {
++				core_if->op_state = B_HOST;
++				/*
++				 * Need to disable SOF interrupt immediately.
++				 * When switching from device to host, the PCD
++				 * interrupt handler won't handle the
++				 * interrupt if host mode is already set. The
++				 * HCD interrupt handler won't get called if
++				 * the HCD state is HALT. This means that the
++				 * interrupt does not get handled and Linux
++				 * complains loudly.
++				 */
++				gintmsk.d32 = 0;
++				gintmsk.b.sofintr = 1;
++				/* To avoid multiple USB Suspend interrupts during
++				 * OTG 2.0 role change */
++				if (core_if->otg_ver)
++					gintmsk.b.usbsuspend = 1;
++				DWC_MODIFY_REG32(&global_regs->gintmsk,
++						 gintmsk.d32, 0);
++				/* Call callback function with spin lock released */
++				DWC_SPINUNLOCK(core_if->lock);
++				cil_pcd_stop(core_if);
++				/*
++				 * Initialize the Core for Host mode.
++				 */
++				if (core_if->otg_ver) {
++					dwc_mdelay(100);
++					cil_hcd_start(core_if);
++					cil_hcd_session_start(core_if);
++				} else {
++					cil_hcd_start(core_if);
++				}
++				DWC_SPINLOCK(core_if->lock);
++			}
++		} else {
++			gotgctl.d32 = 0;
++			gotgctl.b.hnpreq = 1;
++			gotgctl.b.devhnpen = 1;
++			DWC_MODIFY_REG32(&global_regs->gotgctl, gotgctl.d32, 0);
++			DWC_DEBUGPL(DBG_ANY, "HNP Failed\n");
++			__DWC_ERROR("Device Not Connected/Responding\n");
++		}
++	}
++	if (gotgint.b.hstnegdet) {
++		/* The disconnect interrupt is set at the same time as
++		 * Host Negotiation Detected.  During the mode
++		 * switch all interrupts are cleared so the disconnect
++		 * interrupt handler will not get executed.
++		 */
++		DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
++			    "Host Negotiation Detected++ (%s)\n",
++			    (dwc_otg_is_host_mode(core_if) ? "Host" :
++			     "Device"));
++		if (dwc_otg_is_device_mode(core_if)) {
++			DWC_DEBUGPL(DBG_ANY, "a_suspend->a_peripheral (%d)\n",
++				    core_if->op_state);
++			DWC_SPINUNLOCK(core_if->lock);
++			cil_hcd_disconnect(core_if);
++			cil_pcd_start(core_if);
++			DWC_SPINLOCK(core_if->lock);
++			core_if->op_state = A_PERIPHERAL;
++		} else {
++			/*
++			 * Need to disable SOF interrupt immediately. When
++			 * switching from device to host, the PCD interrupt
++			 * handler won't handle the interrupt if host mode is
++			 * already set. The HCD interrupt handler won't get
++			 * called if the HCD state is HALT. This means that
++			 * the interrupt does not get handled and Linux
++			 * complains loudly.
++			 */
++			gintmsk.d32 = 0;
++			gintmsk.b.sofintr = 1;
++			DWC_MODIFY_REG32(&global_regs->gintmsk, gintmsk.d32, 0);
++			DWC_SPINUNLOCK(core_if->lock);
++			cil_pcd_stop(core_if);
++			cil_hcd_start(core_if);
++			DWC_SPINLOCK(core_if->lock);
++			core_if->op_state = A_HOST;
++		}
++	}
++	if (gotgint.b.adevtoutchng) {
++		DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
++			    "A-Device Timeout Change++\n");
++	}
++	if (gotgint.b.debdone) {
++		DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: " "Debounce Done++\n");
++		/* Need to power off VBUS after 10s if OTG2 non-hnp capable host*/
++		if (core_if->otg_ver && core_if->op_state == A_PERIPHERAL) {
++			DWC_DEBUGPL(DBG_ANY, "a_peripheral->a_host\n");
++			/* Clear the a_peripheral flag, back to a_host. */
++			DWC_SPINUNLOCK(core_if->lock);
++			cil_pcd_stop(core_if);
++			cil_hcd_start(core_if);
++			DWC_SPINLOCK(core_if->lock);
++			core_if->op_state = A_HOST;
++		}
++
++		if(core_if->otg_ver == 1)
++			cil_hcd_session_start(core_if);
++	}
++
++	/* Clear GOTGINT */
++	DWC_WRITE_REG32(&core_if->core_global_regs->gotgint, gotgint.d32);
++
++	return 1;
++}
++
++void w_conn_id_status_change(void *p)
++{
++	dwc_otg_core_if_t *core_if = p;
++	uint32_t count = 0;
++	gotgctl_data_t gotgctl = {.d32 = 0 };
++
++	gotgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
++	DWC_DEBUGPL(DBG_CIL, "gotgctl=%0x\n", gotgctl.d32);
++	DWC_DEBUGPL(DBG_CIL, "gotgctl.b.conidsts=%d\n", gotgctl.b.conidsts);
++
++	/* B-Device connector (Device Mode) */
++	if (gotgctl.b.conidsts) {
++		gotgctl_data_t gotgctl_local;
++		/* Wait for switch to device mode. */
++		while (!dwc_otg_is_device_mode(core_if)) {
++			gotgctl_local.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
++			DWC_DEBUGPL(DBG_ANY, "Waiting for Peripheral Mode, Mode=%s count = %d gotgctl=%08x\n",
++				   (dwc_otg_is_host_mode(core_if) ? "Host" :
++				    "Peripheral"), count, gotgctl_local.d32);
++			dwc_mdelay(1); //vahrama previous value was 100
++			if(!gotgctl_local.b.conidsts)
++				goto host;
++			if (++count > 10000)
++				break;
++		}
++		DWC_ASSERT(++count < 10000,
++			   "Connection id status change timed out");
++		core_if->op_state = B_PERIPHERAL;
++		if(core_if->otg_ver == 0)
++			dwc_otg_core_init(core_if);
++		dwc_otg_enable_global_interrupts(core_if);
++		cil_pcd_start(core_if);
++	} else {
++host:
++		/* A-Device connector (Host Mode) */
++		while (!dwc_otg_is_host_mode(core_if)) {
++		DWC_DEBUGPL(DBG_ANY,"Waiting for Host Mode, Mode=%s\n",
++				   (dwc_otg_is_host_mode(core_if) ? "Host" :
++				    "Peripheral"));
++			dwc_mdelay(1);	//vahrama previously was 100
++			if (++count > 10000)
++				break;
++		}
++		DWC_ASSERT(++count < 10000,
++			   "Connection id status change timed out");
++		core_if->op_state = A_HOST;
++		/*
++		 * Initialize the Core for Host mode.
++		 */
++		if (core_if->otg_ver)
++			/* To power off the bus in 10s from the beginning
++			 * of test while denounce has not come yet */
++			cil_hcd_session_start(core_if);
++		else
++			dwc_otg_core_init(core_if);
++		dwc_otg_enable_global_interrupts(core_if);
++		cil_hcd_start(core_if);
++	}
++}
++
++/**
++ * This function handles the Connector ID Status Change Interrupt.  It
++ * reads the OTG Interrupt Register (GOTCTL) to determine whether this
++ * is a Device to Host Mode transition or a Host Mode to Device
++ * Transition.
++ *
++ * This only occurs when the cable is connected/removed from the PHY
++ * connector.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ */
++int32_t dwc_otg_handle_conn_id_status_change_intr(dwc_otg_core_if_t * core_if)
++{
++
++	/*
++	 * Need to disable SOF interrupt immediately. If switching from device
++	 * to host, the PCD interrupt handler won't handle the interrupt if
++	 * host mode is already set. The HCD interrupt handler won't get
++	 * called if the HCD state is HALT. This means that the interrupt does
++	 * not get handled and Linux complains loudly.
++	 */
++	gintmsk_data_t gintmsk = {.d32 = 0 };
++	gintsts_data_t gintsts = {.d32 = 0 };
++
++	gintmsk.b.sofintr = 1;
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, gintmsk.d32, 0);
++
++	DWC_DEBUGPL(DBG_CIL,
++		    " ++Connector ID Status Change Interrupt++  (%s)\n",
++		    (dwc_otg_is_host_mode(core_if) ? "Host" : "Device"));
++
++	DWC_SPINUNLOCK(core_if->lock);
++
++	/* Needed to avoit conn_id_status change duplication */
++	//if (core_if->otg_ver)
++		//dwc_mdelay(50);
++	/*
++	 * Need to schedule a work, as there are possible DELAY function calls
++	 * Release lock before scheduling workq as it holds spinlock during scheduling
++	 */
++
++	DWC_WORKQ_SCHEDULE(core_if->wq_otg, w_conn_id_status_change,
++			   core_if, "connection id status change");
++	DWC_SPINLOCK(core_if->lock);
++
++	/* Set flag and clear interrupt */
++	gintsts.b.conidstschng = 1;
++	DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
++
++	return 1;
++}
++
++/**
++ * This interrupt indicates that a device is initiating the Session
++ * Request Protocol to request the host to turn on bus power so a new
++ * session can begin. The handler responds by turning on bus power. If
++ * the DWC_otg controller is in low power mode, the handler brings the
++ * controller out of low power mode before turning on bus power.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ */
++int32_t dwc_otg_handle_session_req_intr(dwc_otg_core_if_t * core_if)
++{
++	gintsts_data_t gintsts;
++
++#ifndef DWC_HOST_ONLY
++	DWC_DEBUGPL(DBG_ANY, "++Session Request Interrupt++\n");
++
++	if (dwc_otg_is_device_mode(core_if)) {
++		gotgctl_data_t gotgctl = {.d32 = 0 };
++		DWC_DEBUGPL(DBG_PCD, "SRP: Device mode\n");
++		gotgctl.d32 =
++			DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
++		if (gotgctl.b.sesreqscs)
++			DWC_PRINTF("SRP Success\n");
++		else
++			DWC_PRINTF("SRP Fail\n");
++		if (core_if->otg_ver) {
++			gotgctl.d32 = 0 ;
++			gotgctl.b.devhnpen = 1;
++			DWC_MODIFY_REG32(&core_if->core_global_regs->gotgctl, gotgctl.d32, 0);
++		}
++	} else {
++		hprt0_data_t hprt0;
++		DWC_PRINTF("SRP: Host mode\n");
++
++		/* Turn on the port power bit. */
++		hprt0.d32 = dwc_otg_read_hprt0(core_if);
++		hprt0.b.prtpwr = 1;
++		DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
++
++		/* Start the Connection timer. So a message can be displayed
++		 * if connect does not occur within 10 seconds. */
++		cil_hcd_session_start(core_if);
++	}
++#endif
++
++	/* Clear interrupt */
++	gintsts.d32 = 0;
++	gintsts.b.sessreqintr = 1;
++	DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
++
++	return 1;
++}
++
++void w_wakeup_detected(void *p)
++{
++	dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) p;
++	/*
++	 * Clear the Resume after 70ms. (Need 20 ms minimum. Use 70 ms
++	 * so that OPT tests pass with all PHYs).
++	 */
++	hprt0_data_t hprt0 = {.d32 = 0 };
++#if 0
++	pcgcctl_data_t pcgcctl = {.d32 = 0 };
++	/* Restart the Phy Clock */
++	pcgcctl.b.stoppclk = 1;
++	DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
++	dwc_udelay(10);
++#endif //0
++	hprt0.d32 = dwc_otg_read_hprt0(core_if);
++	DWC_DEBUGPL(DBG_ANY, "Resume: HPRT0=%0x\n", hprt0.d32);
++//      dwc_mdelay(70);
++	hprt0.b.prtres = 0;	/* Resume */
++	DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
++	DWC_DEBUGPL(DBG_ANY, "Clear Resume: HPRT0=%0x\n",
++		    DWC_READ_REG32(core_if->host_if->hprt0));
++
++	cil_hcd_resume(core_if);
++
++	/** Change to L0 state*/
++	core_if->lx_state = DWC_OTG_L0;
++}
++
++/**
++ * This interrupt indicates that the DWC_otg controller has detected a
++ * resume or remote wakeup sequence. If the DWC_otg controller is in
++ * low power mode, the handler must brings the controller out of low
++ * power mode. The controller automatically begins resume
++ * signaling. The handler schedules a time to stop resume signaling.
++ */
++int32_t dwc_otg_handle_wakeup_detected_intr(dwc_otg_core_if_t * core_if)
++{
++	gintsts_data_t gintsts;
++
++	DWC_DEBUGPL(DBG_ANY,
++		    "++Resume and Remote Wakeup Detected Interrupt++\n");
++
++	DWC_PRINTF("%s lxstate = %d\n", __func__, core_if->lx_state);
++
++	if (dwc_otg_is_device_mode(core_if)) {
++		dctl_data_t dctl = {.d32 = 0 };
++		DWC_DEBUGPL(DBG_PCD, "DSTS=0x%0x\n",
++			    DWC_READ_REG32(&core_if->dev_if->dev_global_regs->
++					   dsts));
++		if (core_if->lx_state == DWC_OTG_L2) {
++#ifdef PARTIAL_POWER_DOWN
++			if (core_if->hwcfg4.b.power_optimiz) {
++				pcgcctl_data_t power = {.d32 = 0 };
++
++				power.d32 = DWC_READ_REG32(core_if->pcgcctl);
++				DWC_DEBUGPL(DBG_CIL, "PCGCCTL=%0x\n",
++					    power.d32);
++
++				power.b.stoppclk = 0;
++				DWC_WRITE_REG32(core_if->pcgcctl, power.d32);
++
++				power.b.pwrclmp = 0;
++				DWC_WRITE_REG32(core_if->pcgcctl, power.d32);
++
++				power.b.rstpdwnmodule = 0;
++				DWC_WRITE_REG32(core_if->pcgcctl, power.d32);
++			}
++#endif
++			/* Clear the Remote Wakeup Signaling */
++			dctl.b.rmtwkupsig = 1;
++			DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
++					 dctl, dctl.d32, 0);
++
++			DWC_SPINUNLOCK(core_if->lock);
++			if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup) {
++				core_if->pcd_cb->resume_wakeup(core_if->pcd_cb->p);
++			}
++			DWC_SPINLOCK(core_if->lock);
++		} else {
++			glpmcfg_data_t lpmcfg;
++			pcgcctl_data_t pcgcctl = {.d32 = 0 };
++
++			lpmcfg.d32 =
++			    DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
++			lpmcfg.b.hird_thres &= (~(1 << 4));
++		lpmcfg.b.en_utmi_sleep = 0;
++
++			/* Clear Enbl_L1Gating bit. */
++			pcgcctl.b.enbl_sleep_gating = 1;
++			DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32,0);
++
++			DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg,
++					lpmcfg.d32);
++		}
++		/** Change to L0 state*/
++		core_if->lx_state = DWC_OTG_L0;
++	} else {
++		if (core_if->lx_state != DWC_OTG_L1) {
++			pcgcctl_data_t pcgcctl = {.d32 = 0 };
++
++			/* Restart the Phy Clock */
++			pcgcctl.b.stoppclk = 1;
++			DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
++			DWC_TIMER_SCHEDULE(core_if->wkp_timer, 71);
++		} else {
++			/** Change to L0 state*/
++			core_if->lx_state = DWC_OTG_L0;
++		}
++	}
++
++	/* Clear interrupt */
++	gintsts.d32 = 0;
++	gintsts.b.wkupintr = 1;
++	DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
++
++	return 1;
++}
++
++/**
++ * This interrupt indicates that the Wakeup Logic has detected a
++ * Device disconnect.
++ */
++static int32_t dwc_otg_handle_pwrdn_disconnect_intr(dwc_otg_core_if_t * core_if)
++{
++	gpwrdn_data_t gpwrdn = {.d32 = 0 };
++	gpwrdn_data_t gpwrdn_temp = {.d32 = 0 };
++	gpwrdn_temp.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
++
++	DWC_PRINTF("%s called\n", __FUNCTION__);
++
++	if (!core_if->hibernation_suspend) {
++		DWC_PRINTF("Already exited from Hibernation\n");
++		return 1;
++	}
++
++	/* Switch on the voltage to the core */
++	gpwrdn.b.pwrdnswtch = 1;
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++	dwc_udelay(10);
++
++	/* Reset the core */
++	gpwrdn.d32 = 0;
++	gpwrdn.b.pwrdnrstn = 1;
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++	dwc_udelay(10);
++
++	/* Disable power clamps */
++	gpwrdn.d32 = 0;
++	gpwrdn.b.pwrdnclmp = 1;
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++
++	/* Remove reset the core signal */
++	gpwrdn.d32 = 0;
++	gpwrdn.b.pwrdnrstn = 1;
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
++	dwc_udelay(10);
++
++	/* Disable PMU interrupt */
++	gpwrdn.d32 = 0;
++	gpwrdn.b.pmuintsel = 1;
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++
++	core_if->hibernation_suspend = 0;
++
++	/* Disable PMU */
++	gpwrdn.d32 = 0;
++	gpwrdn.b.pmuactv = 1;
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++	dwc_udelay(10);
++
++	if (gpwrdn_temp.b.idsts) {
++		core_if->op_state = B_PERIPHERAL;
++		dwc_otg_core_init(core_if);
++		dwc_otg_enable_global_interrupts(core_if);
++		cil_pcd_start(core_if);
++	} else {
++		core_if->op_state = A_HOST;
++		dwc_otg_core_init(core_if);
++		dwc_otg_enable_global_interrupts(core_if);
++		cil_hcd_start(core_if);
++	}
++
++	return 1;
++}
++
++/**
++ * This interrupt indicates that the Wakeup Logic has detected a
++ * remote wakeup sequence.
++ */
++static int32_t dwc_otg_handle_pwrdn_wakeup_detected_intr(dwc_otg_core_if_t * core_if)
++{
++	gpwrdn_data_t gpwrdn = {.d32 = 0 };
++	DWC_DEBUGPL(DBG_ANY,
++		    "++Powerdown Remote Wakeup Detected Interrupt++\n");
++
++	if (!core_if->hibernation_suspend) {
++		DWC_PRINTF("Already exited from Hibernation\n");
++		return 1;
++	}
++
++	gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
++	if (gpwrdn.b.idsts) {	// Device Mode
++		if ((core_if->power_down == 2)
++		    && (core_if->hibernation_suspend == 1)) {
++			dwc_otg_device_hibernation_restore(core_if, 0, 0);
++		}
++	} else {
++		if ((core_if->power_down == 2)
++		    && (core_if->hibernation_suspend == 1)) {
++			dwc_otg_host_hibernation_restore(core_if, 1, 0);
++		}
++	}
++	return 1;
++}
++
++static int32_t dwc_otg_handle_pwrdn_idsts_change(dwc_otg_device_t * otg_dev)
++{
++	gpwrdn_data_t gpwrdn = {.d32 = 0 };
++	gpwrdn_data_t gpwrdn_temp = {.d32 = 0 };
++	dwc_otg_core_if_t *core_if = otg_dev->core_if;
++
++	DWC_DEBUGPL(DBG_ANY, "%s called\n", __FUNCTION__);
++	gpwrdn_temp.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
++	if (core_if->power_down == 2) {
++		if (!core_if->hibernation_suspend) {
++			DWC_PRINTF("Already exited from Hibernation\n");
++			return 1;
++		}
++		DWC_DEBUGPL(DBG_ANY, "Exit from hibernation on ID sts change\n");
++		/* Switch on the voltage to the core */
++		gpwrdn.b.pwrdnswtch = 1;
++		DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++		dwc_udelay(10);
++
++		/* Reset the core */
++		gpwrdn.d32 = 0;
++		gpwrdn.b.pwrdnrstn = 1;
++		DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++		dwc_udelay(10);
++
++		/* Disable power clamps */
++		gpwrdn.d32 = 0;
++		gpwrdn.b.pwrdnclmp = 1;
++		DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++
++		/* Remove reset the core signal */
++		gpwrdn.d32 = 0;
++		gpwrdn.b.pwrdnrstn = 1;
++		DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
++		dwc_udelay(10);
++
++		/* Disable PMU interrupt */
++		gpwrdn.d32 = 0;
++		gpwrdn.b.pmuintsel = 1;
++		DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++
++		/*Indicates that we are exiting from hibernation */
++		core_if->hibernation_suspend = 0;
++
++		/* Disable PMU */
++		gpwrdn.d32 = 0;
++		gpwrdn.b.pmuactv = 1;
++		DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++		dwc_udelay(10);
++
++		gpwrdn.d32 = core_if->gr_backup->gpwrdn_local;
++		if (gpwrdn.b.dis_vbus == 1) {
++			gpwrdn.d32 = 0;
++			gpwrdn.b.dis_vbus = 1;
++			DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++		}
++
++		if (gpwrdn_temp.b.idsts) {
++			core_if->op_state = B_PERIPHERAL;
++			dwc_otg_core_init(core_if);
++			dwc_otg_enable_global_interrupts(core_if);
++			cil_pcd_start(core_if);
++		} else {
++			core_if->op_state = A_HOST;
++			dwc_otg_core_init(core_if);
++			dwc_otg_enable_global_interrupts(core_if);
++			cil_hcd_start(core_if);
++		}
++	}
++
++	if (core_if->adp_enable) {
++		uint8_t is_host = 0;
++		DWC_SPINUNLOCK(core_if->lock);
++		/* Change the core_if's lock to hcd/pcd lock depend on mode? */
++#ifndef DWC_HOST_ONLY
++		if (gpwrdn_temp.b.idsts)
++			core_if->lock = otg_dev->pcd->lock;
++#endif
++#ifndef DWC_DEVICE_ONLY
++		if (!gpwrdn_temp.b.idsts) {
++			core_if->lock = otg_dev->hcd->lock;
++			is_host = 1;
++		}
++#endif
++		DWC_DEBUGPL(DBG_ANY, "RESTART ADP\n");
++		if (core_if->adp.probe_enabled)
++			dwc_otg_adp_probe_stop(core_if);
++		if (core_if->adp.sense_enabled)
++			dwc_otg_adp_sense_stop(core_if);
++		if (core_if->adp.sense_timer_started)
++			DWC_TIMER_CANCEL(core_if->adp.sense_timer);
++		if (core_if->adp.vbuson_timer_started)
++			DWC_TIMER_CANCEL(core_if->adp.vbuson_timer);
++		/* Do not need to reset ADP if we are coming back
++		 * to the device mode after HNP. This is needed
++		 * not to perform SRP after reverse, just do ADP
++		 * probe and compare the RTIM values with the one
++		 * before HNP */
++		if (core_if->op_state != B_HOST) {
++			core_if->adp.probe_timer_values[0] = -1;
++			core_if->adp.probe_timer_values[1] = -1;
++			core_if->adp.probe_counter = 0;
++			core_if->adp.gpwrdn = 0;
++		}
++		core_if->adp.sense_timer_started = 0;
++		core_if->adp.vbuson_timer_started = 0;
++
++		/* Disable PMU and restart ADP */
++		gpwrdn_temp.d32 = 0;
++		gpwrdn_temp.b.pmuactv = 1;
++		gpwrdn_temp.b.pmuintsel = 1;
++		DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++		dwc_mdelay(110);
++		dwc_otg_adp_start(core_if, is_host);
++		DWC_SPINLOCK(core_if->lock);
++	}
++
++	return 1;
++}
++
++static int32_t dwc_otg_handle_pwrdn_session_change(dwc_otg_core_if_t * core_if)
++{
++	gpwrdn_data_t gpwrdn = {.d32 = 0 };
++	int32_t otg_cap_param = core_if->core_params->otg_cap;
++	DWC_DEBUGPL(DBG_ANY, "%s called\n", __FUNCTION__);
++
++	gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
++	if (core_if->power_down == 2) {
++		if (!core_if->hibernation_suspend) {
++			DWC_PRINTF("Already exited from Hibernation\n");
++			return 1;
++		}
++
++		if (gpwrdn.b.bsessvld == 0) {
++			/* Save gpwrdn register for further usage if stschng interrupt */
++			core_if->gr_backup->gpwrdn_local =
++			    DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
++			/*Exit from ISR and wait for stschng interrupt with bsessvld = 1 */
++			return 1;
++		}
++
++		/* Switch on the voltage to the core */
++		gpwrdn.d32 = 0;
++		gpwrdn.b.pwrdnswtch = 1;
++		DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++		dwc_udelay(10);
++
++		/* Reset the core */
++		gpwrdn.d32 = 0;
++		gpwrdn.b.pwrdnrstn = 1;
++		DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++		dwc_udelay(10);
++
++		/* Disable power clamps */
++		gpwrdn.d32 = 0;
++		gpwrdn.b.pwrdnclmp = 1;
++		DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++
++		/* Remove reset the core signal */
++		gpwrdn.d32 = 0;
++		gpwrdn.b.pwrdnrstn = 1;
++		DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
++		dwc_udelay(10);
++
++		/* Disable PMU interrupt */
++		gpwrdn.d32 = 0;
++		gpwrdn.b.pmuintsel = 1;
++		DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++		dwc_udelay(10);
++
++		/*Indicates that we are exiting from hibernation */
++		core_if->hibernation_suspend = 0;
++
++		/* Disable PMU */
++		gpwrdn.d32 = 0;
++		gpwrdn.b.pmuactv = 1;
++		DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++		dwc_udelay(10);
++
++		core_if->op_state = B_PERIPHERAL;
++		dwc_otg_core_init(core_if);
++		dwc_otg_enable_global_interrupts(core_if);
++		cil_pcd_start(core_if);
++
++		if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE ||
++		    otg_cap_param == DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE) {
++			/*
++			 * Initiate SRP after initial ADP probe.
++			 */
++			dwc_otg_initiate_srp(core_if);
++		}
++	} else if (core_if->adp_enable && core_if->op_state != A_HOST){
++		dwc_otg_adp_probe_stop(core_if);
++		if (DWC_WORKQ_PENDING(core_if->wq_otg))
++			core_if->stop_adpprb = 1;
++		/* Disable Power Down Logic */
++		gpwrdn.d32 = 0;
++		gpwrdn.b.pmuintsel = 1;
++		gpwrdn.b.pmuactv = 1;
++		DWC_MODIFY_REG32(&core_if->core_global_regs->
++				 gpwrdn, gpwrdn.d32, 0);
++
++		/*
++		 * Initialize the Core for Device mode.
++		 */
++		core_if->op_state = B_PERIPHERAL;
++		cil_pcd_start(core_if);
++		dwc_otg_enable_global_interrupts(core_if);
++	}
++
++	return 1;
++}
++
++/**
++ * This interrupt indicates that the Wakeup Logic has detected a
++ * status change either on IDDIG or BSessVld.
++ */
++static uint32_t dwc_otg_handle_pwrdn_stschng_intr(dwc_otg_device_t * otg_dev)
++{
++	int retval = 0;
++	gpwrdn_data_t gpwrdn = {.d32 = 0 };
++	gpwrdn_data_t gpwrdn_temp = {.d32 = 0 };
++	dwc_otg_core_if_t *core_if = otg_dev->core_if;
++
++	DWC_DEBUGPL(DBG_CIL, "%s called\n", __FUNCTION__);
++
++	if (core_if->power_down == 2) {
++		if (core_if->hibernation_suspend <= 0) {
++			DWC_PRINTF("Already exited from Hibernation\n");
++			return 1;
++		} else
++			gpwrdn_temp.d32 = core_if->gr_backup->gpwrdn_local;
++
++	} else {
++		gpwrdn_temp.d32 = core_if->adp.gpwrdn;
++	}
++
++	gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
++
++	if (gpwrdn.b.idsts ^ gpwrdn_temp.b.idsts) {
++		retval = dwc_otg_handle_pwrdn_idsts_change(otg_dev);
++	} else if (gpwrdn.b.bsessvld ^ gpwrdn_temp.b.bsessvld) {
++		retval = dwc_otg_handle_pwrdn_session_change(core_if);
++	}
++
++	return retval;
++}
++
++/**
++ * This interrupt indicates that the Wakeup Logic has detected a
++ * SRP.
++ */
++static int32_t dwc_otg_handle_pwrdn_srp_intr(dwc_otg_core_if_t * core_if)
++{
++	gpwrdn_data_t gpwrdn = {.d32 = 0 };
++
++	DWC_PRINTF("%s called\n", __FUNCTION__);
++
++	if (core_if->power_down == 2) {
++		if (!core_if->hibernation_suspend) {
++			DWC_PRINTF("Already exited from Hibernation\n");
++			return 1;
++		}
++#ifdef DWC_DEV_SRPCAP
++		if (core_if->pwron_timer_started) {
++			core_if->pwron_timer_started = 0;
++			DWC_TIMER_CANCEL(core_if->pwron_timer);
++		}
++#endif
++
++		/* Switch on the voltage to the core */
++		gpwrdn.b.pwrdnswtch = 1;
++		DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++		dwc_udelay(10);
++
++		/* Reset the core */
++		gpwrdn.d32 = 0;
++		gpwrdn.b.pwrdnrstn = 1;
++		DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++		dwc_udelay(10);
++
++		/* Disable power clamps */
++		gpwrdn.d32 = 0;
++		gpwrdn.b.pwrdnclmp = 1;
++		DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++
++		/* Remove reset the core signal */
++		gpwrdn.d32 = 0;
++		gpwrdn.b.pwrdnrstn = 1;
++		DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
++		dwc_udelay(10);
++
++		/* Disable PMU interrupt */
++		gpwrdn.d32 = 0;
++		gpwrdn.b.pmuintsel = 1;
++		DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++
++		/* Indicates that we are exiting from hibernation */
++		core_if->hibernation_suspend = 0;
++
++		/* Disable PMU */
++		gpwrdn.d32 = 0;
++		gpwrdn.b.pmuactv = 1;
++		DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++		dwc_udelay(10);
++
++		/* Programm Disable VBUS to 0 */
++		gpwrdn.d32 = 0;
++		gpwrdn.b.dis_vbus = 1;
++		DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++
++		/*Initialize the core as Host */
++		core_if->op_state = A_HOST;
++		dwc_otg_core_init(core_if);
++		dwc_otg_enable_global_interrupts(core_if);
++		cil_hcd_start(core_if);
++	}
++	/* Do not need to du anything if this is "old" SRP and we are already
++	 * in the normal mode of operation */
++	if(core_if->adp_enable) {
++		gpwrdn.d32 =  DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
++		if (!gpwrdn.b.pmuactv) {
++			return 1;
++		}
++
++		dwc_otg_adp_probe_stop(core_if);
++		/* Disable Interrupt from Power Down Logic */
++		gpwrdn.d32 = 0;
++		gpwrdn.b.pmuintsel = 1;
++		gpwrdn.b.pmuactv = 1;
++		DWC_MODIFY_REG32(&core_if->core_global_regs->
++				 gpwrdn, gpwrdn.d32, 0);
++
++		/*
++		 * Initialize the Core for Host mode.
++		 */
++		core_if->op_state = A_HOST;
++		dwc_otg_core_init(core_if);
++		dwc_otg_enable_global_interrupts(core_if);
++		cil_hcd_start(core_if);
++		/* Start the Connection timer. So a message can be displayed
++		 * if connect does not occur within 10 seconds. */
++		cil_hcd_session_start(core_if);
++	}
++
++	return 1;
++}
++
++/** This interrupt indicates that restore command after Hibernation
++ * was completed by the core. */
++int32_t dwc_otg_handle_restore_done_intr(dwc_otg_core_if_t * core_if)
++{
++	pcgcctl_data_t pcgcctl;
++	DWC_DEBUGPL(DBG_ANY, "++Restore Done Interrupt++\n");
++
++	//TODO De-assert restore signal. 8.a
++	pcgcctl.d32 = DWC_READ_REG32(core_if->pcgcctl);
++	if (pcgcctl.b.restoremode == 1) {
++		gintmsk_data_t gintmsk = {.d32 = 0 };
++		/*
++		 * If restore mode is Remote Wakeup,
++		 * unmask Remote Wakeup interrupt.
++		 */
++		gintmsk.b.wkupintr = 1;
++		DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk,
++				 0, gintmsk.d32);
++	}
++
++	return 1;
++}
++
++/**
++ * This interrupt indicates that a device has been disconnected from
++ * the root port.
++ */
++int32_t dwc_otg_handle_disconnect_intr(dwc_otg_core_if_t * core_if)
++{
++	gintsts_data_t gintsts;
++
++	DWC_DEBUGPL(DBG_ANY, "++Disconnect Detected Interrupt++ (%s) %s\n",
++		    (dwc_otg_is_host_mode(core_if) ? "Host" : "Device"),
++		    op_state_str(core_if));
++
++/** @todo Consolidate this if statement. */
++#ifndef DWC_HOST_ONLY
++	if (core_if->op_state == B_HOST) {
++		/* If in device mode Disconnect and stop the HCD, then
++		 * start the PCD. */
++		DWC_SPINUNLOCK(core_if->lock);
++		cil_hcd_disconnect(core_if);
++		cil_pcd_start(core_if);
++		DWC_SPINLOCK(core_if->lock);
++		core_if->op_state = B_PERIPHERAL;
++	} else if (dwc_otg_is_device_mode(core_if)) {
++		gotgctl_data_t gotgctl = {.d32 = 0 };
++		gotgctl.d32 =
++		    DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
++		if (gotgctl.b.hstsethnpen == 1) {
++			/* Do nothing, if HNP in process the OTG
++			 * interrupt "Host Negotiation Detected"
++			 * interrupt will do the mode switch.
++			 */
++		} else if (gotgctl.b.devhnpen == 0) {
++			/* If in device mode Disconnect and stop the HCD, then
++			 * start the PCD. */
++			DWC_SPINUNLOCK(core_if->lock);
++			cil_hcd_disconnect(core_if);
++			cil_pcd_start(core_if);
++			DWC_SPINLOCK(core_if->lock);
++			core_if->op_state = B_PERIPHERAL;
++		} else {
++			DWC_DEBUGPL(DBG_ANY, "!a_peripheral && !devhnpen\n");
++		}
++	} else {
++		if (core_if->op_state == A_HOST) {
++			/* A-Cable still connected but device disconnected. */
++			cil_hcd_disconnect(core_if);
++			if (core_if->adp_enable) {
++				gpwrdn_data_t gpwrdn = {.d32 = 0 };
++				cil_hcd_stop(core_if);
++				/* Enable Power Down Logic */
++				gpwrdn.b.pmuintsel = 1;
++				gpwrdn.b.pmuactv = 1;
++				DWC_MODIFY_REG32(&core_if->core_global_regs->
++						 gpwrdn, 0, gpwrdn.d32);
++				dwc_otg_adp_probe_start(core_if);
++
++				/* Power off the core */
++				if (core_if->power_down == 2) {
++					gpwrdn.d32 = 0;
++					gpwrdn.b.pwrdnswtch = 1;
++					DWC_MODIFY_REG32
++					    (&core_if->core_global_regs->gpwrdn,
++					     gpwrdn.d32, 0);
++				}
++			}
++		}
++	}
++#endif
++	/* Change to L3(OFF) state */
++	core_if->lx_state = DWC_OTG_L3;
++
++	gintsts.d32 = 0;
++	gintsts.b.disconnect = 1;
++	DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
++	return 1;
++}
++
++/**
++ * This interrupt indicates that SUSPEND state has been detected on
++ * the USB.
++ *
++ * For HNP the USB Suspend interrupt signals the change from
++ * "a_peripheral" to "a_host".
++ *
++ * When power management is enabled the core will be put in low power
++ * mode.
++ */
++extern int  otg_usbhost_stat;
++int32_t dwc_otg_handle_usb_suspend_intr(dwc_otg_core_if_t * core_if)
++{
++	dsts_data_t dsts;
++	gintsts_data_t gintsts;
++	dcfg_data_t dcfg;
++
++	DWC_DEBUGPL(DBG_ANY, "USB SUSPEND\n");
++	otg_usbhost_stat = 0;
++
++	if ((core_if->otg_ver == 1) && (core_if->op_state == A_PERIPHERAL)) {
++		core_if->lx_state = DWC_OTG_L2;
++
++		/* Clear interrupt */
++		gintsts.d32 = 0;
++		gintsts.b.usbsuspend = 1;
++		DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
++
++		return 1;
++	}
++
++	if (dwc_otg_is_device_mode(core_if)) {
++		/* Check the Device status register to determine if the Suspend
++		 * state is active. */
++		dsts.d32 =
++		    DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
++		DWC_DEBUGPL(DBG_PCD, "DSTS=0x%0x\n", dsts.d32);
++		DWC_DEBUGPL(DBG_PCD, "DSTS.Suspend Status=%d "
++			    "HWCFG4.power Optimize=%d\n",
++			    dsts.b.suspsts, core_if->hwcfg4.b.power_optimiz);
++
++#ifdef PARTIAL_POWER_DOWN
++/** @todo Add a module parameter for power management. */
++
++		if (dsts.b.suspsts && core_if->hwcfg4.b.power_optimiz) {
++			pcgcctl_data_t power = {.d32 = 0 };
++			DWC_DEBUGPL(DBG_CIL, "suspend\n");
++
++			power.b.pwrclmp = 1;
++			DWC_WRITE_REG32(core_if->pcgcctl, power.d32);
++
++			power.b.rstpdwnmodule = 1;
++			DWC_MODIFY_REG32(core_if->pcgcctl, 0, power.d32);
++
++			power.b.stoppclk = 1;
++			DWC_MODIFY_REG32(core_if->pcgcctl, 0, power.d32);
++
++		} else {
++			DWC_DEBUGPL(DBG_ANY, "disconnect?\n");
++		}
++#endif
++		/* PCD callback for suspend. Release the lock inside of callback function */
++		cil_pcd_suspend(core_if);
++		if (core_if->power_down == 2) {
++			dcfg.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
++			DWC_DEBUGPL(DBG_ANY,"lx_state = %08x\n",core_if->lx_state);
++			DWC_DEBUGPL(DBG_ANY," device address = %08d\n",dcfg.b.devaddr);
++
++			if (core_if->lx_state != DWC_OTG_L3 && dcfg.b.devaddr) {
++				pcgcctl_data_t pcgcctl = {.d32 = 0 };
++				gpwrdn_data_t gpwrdn = {.d32 = 0 };
++				gusbcfg_data_t gusbcfg = {.d32 = 0 };
++
++				/* Change to L2(suspend) state */
++				core_if->lx_state = DWC_OTG_L2;
++
++				/* Clear interrupt in gintsts */
++				gintsts.d32 = 0;
++				gintsts.b.usbsuspend = 1;
++				DWC_WRITE_REG32(&core_if->core_global_regs->
++						gintsts, gintsts.d32);
++				DWC_PRINTF("Start of hibernation completed\n");
++				dwc_otg_save_global_regs(core_if);
++				dwc_otg_save_dev_regs(core_if);
++
++				gusbcfg.d32 =
++				    DWC_READ_REG32(&core_if->core_global_regs->
++						   gusbcfg);
++				if (gusbcfg.b.ulpi_utmi_sel == 1) {
++					/* ULPI interface */
++					/* Suspend the Phy Clock */
++					pcgcctl.d32 = 0;
++					pcgcctl.b.stoppclk = 1;
++					DWC_MODIFY_REG32(core_if->pcgcctl, 0,
++							 pcgcctl.d32);
++					dwc_udelay(10);
++					gpwrdn.b.pmuactv = 1;
++					DWC_MODIFY_REG32(&core_if->
++							 core_global_regs->
++							 gpwrdn, 0, gpwrdn.d32);
++				} else {
++					/* UTMI+ Interface */
++					gpwrdn.b.pmuactv = 1;
++					DWC_MODIFY_REG32(&core_if->
++							 core_global_regs->
++							 gpwrdn, 0, gpwrdn.d32);
++					dwc_udelay(10);
++					pcgcctl.b.stoppclk = 1;
++					DWC_MODIFY_REG32(core_if->pcgcctl, 0,
++							 pcgcctl.d32);
++					dwc_udelay(10);
++				}
++
++				/* Set flag to indicate that we are in hibernation */
++				core_if->hibernation_suspend = 1;
++				/* Enable interrupts from wake up logic */
++				gpwrdn.d32 = 0;
++				gpwrdn.b.pmuintsel = 1;
++				DWC_MODIFY_REG32(&core_if->core_global_regs->
++						 gpwrdn, 0, gpwrdn.d32);
++				dwc_udelay(10);
++
++				/* Unmask device mode interrupts in GPWRDN */
++				gpwrdn.d32 = 0;
++				gpwrdn.b.rst_det_msk = 1;
++				gpwrdn.b.lnstchng_msk = 1;
++				gpwrdn.b.sts_chngint_msk = 1;
++				DWC_MODIFY_REG32(&core_if->core_global_regs->
++						 gpwrdn, 0, gpwrdn.d32);
++				dwc_udelay(10);
++
++				/* Enable Power Down Clamp */
++				gpwrdn.d32 = 0;
++				gpwrdn.b.pwrdnclmp = 1;
++				DWC_MODIFY_REG32(&core_if->core_global_regs->
++						 gpwrdn, 0, gpwrdn.d32);
++				dwc_udelay(10);
++
++				/* Switch off VDD */
++				gpwrdn.d32 = 0;
++				gpwrdn.b.pwrdnswtch = 1;
++				DWC_MODIFY_REG32(&core_if->core_global_regs->
++						 gpwrdn, 0, gpwrdn.d32);
++
++				/* Save gpwrdn register for further usage if stschng interrupt */
++				core_if->gr_backup->gpwrdn_local =
++							DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
++				DWC_PRINTF("Hibernation completed\n");
++
++				return 1;
++			}
++		} else if (core_if->power_down == 3) {
++			pcgcctl_data_t pcgcctl = {.d32 = 0 };
++			dcfg.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
++			DWC_DEBUGPL(DBG_ANY, "lx_state = %08x\n",core_if->lx_state);
++			DWC_DEBUGPL(DBG_ANY, " device address = %08d\n",dcfg.b.devaddr);
++
++			if (core_if->lx_state != DWC_OTG_L3 && dcfg.b.devaddr) {
++				DWC_DEBUGPL(DBG_ANY, "Start entering to extended hibernation\n");
++				core_if->xhib = 1;
++
++				/* Clear interrupt in gintsts */
++				gintsts.d32 = 0;
++				gintsts.b.usbsuspend = 1;
++				DWC_WRITE_REG32(&core_if->core_global_regs->
++					gintsts, gintsts.d32);
++
++				dwc_otg_save_global_regs(core_if);
++				dwc_otg_save_dev_regs(core_if);
++
++				/* Wait for 10 PHY clocks */
++				dwc_udelay(10);
++
++				/* Program GPIO register while entering to xHib */
++				DWC_WRITE_REG32(&core_if->core_global_regs->ggpio, 0x1);
++
++				pcgcctl.b.enbl_extnd_hiber = 1;
++				DWC_MODIFY_REG32(core_if->pcgcctl, 0, pcgcctl.d32);
++				DWC_MODIFY_REG32(core_if->pcgcctl, 0, pcgcctl.d32);
++
++				pcgcctl.d32 = 0;
++				pcgcctl.b.extnd_hiber_pwrclmp = 1;
++				DWC_MODIFY_REG32(core_if->pcgcctl, 0, pcgcctl.d32);
++
++				pcgcctl.d32 = 0;
++				pcgcctl.b.extnd_hiber_switch = 1;
++				core_if->gr_backup->xhib_gpwrdn = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
++				core_if->gr_backup->xhib_pcgcctl = DWC_READ_REG32(core_if->pcgcctl) | pcgcctl.d32;
++				DWC_MODIFY_REG32(core_if->pcgcctl, 0, pcgcctl.d32);
++
++				DWC_DEBUGPL(DBG_ANY, "Finished entering to extended hibernation\n");
++
++				return 1;
++			}
++		}
++		if ((core_if->otg_ver == 1) && (core_if->core_params->otg_cap == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE)) {
++			gotgctl_data_t gotgctl = {.d32 = 0 };
++			gotgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
++			if (gotgctl.b.devhnpen && core_if->otg_ver == 1){
++				gotgctl_data_t gotgctl = {.d32 = 0 };
++				dwc_mdelay(5);
++				/**@todo Is the gotgctl.devhnpen cleared
++				 * by a USB Reset? */
++				gotgctl.b.devhnpen = 1;
++				gotgctl.b.hnpreq = 1;
++				DWC_WRITE_REG32(&core_if->core_global_regs->gotgctl,
++						gotgctl.d32);
++			}
++		}
++	} else {
++		if (core_if->op_state == A_PERIPHERAL) {
++			DWC_DEBUGPL(DBG_ANY, "a_peripheral->a_host\n");
++			/* Clear the a_peripheral flag, back to a_host. */
++			DWC_SPINUNLOCK(core_if->lock);
++			cil_pcd_stop(core_if);
++			cil_hcd_start(core_if);
++			DWC_SPINLOCK(core_if->lock);
++			core_if->op_state = A_HOST;
++		}
++	}
++
++	/* Change to L2(suspend) state */
++	core_if->lx_state = DWC_OTG_L2;
++
++	/* Clear interrupt */
++	gintsts.d32 = 0;
++	gintsts.b.usbsuspend = 1;
++	DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
++
++	return 1;
++}
++
++static int32_t dwc_otg_handle_xhib_exit_intr(dwc_otg_core_if_t * core_if)
++{
++	gpwrdn_data_t gpwrdn = {.d32 = 0 };
++	pcgcctl_data_t pcgcctl = {.d32 = 0 };
++	gahbcfg_data_t gahbcfg = {.d32 = 0 };
++
++	dwc_udelay(10);
++
++	/* Program GPIO register while entering to xHib */
++	DWC_WRITE_REG32(&core_if->core_global_regs->ggpio, 0x0);
++
++	pcgcctl.d32 = core_if->gr_backup->xhib_pcgcctl;
++	pcgcctl.b.extnd_hiber_pwrclmp = 0;
++	DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
++	dwc_udelay(10);
++
++	gpwrdn.d32 = core_if->gr_backup->xhib_gpwrdn;
++	gpwrdn.b.restore = 1;
++	DWC_WRITE_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32);
++	dwc_udelay(10);
++
++	restore_lpm_i2c_regs(core_if);
++
++	pcgcctl.d32 = core_if->gr_backup->pcgcctl_local & (0x3FFFF << 14);
++	pcgcctl.b.max_xcvrselect = 1;
++	pcgcctl.b.ess_reg_restored = 0;
++	pcgcctl.b.extnd_hiber_switch = 0;
++	pcgcctl.b.extnd_hiber_pwrclmp = 0;
++	pcgcctl.b.enbl_extnd_hiber = 1;
++	DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
++
++	gahbcfg.d32 = core_if->gr_backup->gahbcfg_local;
++	gahbcfg.b.glblintrmsk = 1;
++	DWC_WRITE_REG32(&core_if->core_global_regs->gahbcfg, gahbcfg.d32);
++
++	DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
++	DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, 0x1 << 16);
++
++	DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg,
++			core_if->gr_backup->gusbcfg_local);
++	DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg,
++			core_if->dr_backup->dcfg);
++
++	pcgcctl.d32 = 0;
++	pcgcctl.d32 = core_if->gr_backup->pcgcctl_local & (0x3FFFF << 14);
++	pcgcctl.b.max_xcvrselect = 1;
++	pcgcctl.d32 |= 0x608;
++	DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
++	dwc_udelay(10);
++
++	pcgcctl.d32 = 0;
++	pcgcctl.d32 = core_if->gr_backup->pcgcctl_local & (0x3FFFF << 14);
++	pcgcctl.b.max_xcvrselect = 1;
++	pcgcctl.b.ess_reg_restored = 1;
++	pcgcctl.b.enbl_extnd_hiber = 1;
++	pcgcctl.b.rstpdwnmodule = 1;
++	pcgcctl.b.restoremode = 1;
++	DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
++
++	DWC_DEBUGPL(DBG_ANY, "%s called\n", __FUNCTION__);
++
++	return 1;
++}
++
++#ifdef CONFIG_USB_DWC_OTG_LPM
++/**
++ * This function hadles LPM transaction received interrupt.
++ */
++static int32_t dwc_otg_handle_lpm_intr(dwc_otg_core_if_t * core_if)
++{
++	glpmcfg_data_t lpmcfg;
++	gintsts_data_t gintsts;
++
++	if (!core_if->core_params->lpm_enable) {
++		DWC_PRINTF("Unexpected LPM interrupt\n");
++	}
++
++	lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
++	DWC_PRINTF("LPM config register = 0x%08x\n", lpmcfg.d32);
++
++	if (dwc_otg_is_host_mode(core_if)) {
++		cil_hcd_sleep(core_if);
++	} else {
++
++		pcgcctl_data_t pcgcctl = {.d32 = 0 };
++
++		lpmcfg.b.hird_thres |= (1 << 4);
++		lpmcfg.b.en_utmi_sleep = 1;
++
++		pcgcctl.b.enbl_sleep_gating = 1;
++		DWC_MODIFY_REG32(core_if->pcgcctl,0,pcgcctl.d32);
++
++		if(dwc_otg_get_param_besl_enable(core_if)) {
++			lpmcfg.b.en_besl = 1;
++		}
++
++		DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg,
++				lpmcfg.d32);
++	}
++
++	/* Examine prt_sleep_sts after TL1TokenTetry period max (10 us) */
++	dwc_udelay(10);
++	lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
++	if (lpmcfg.b.prt_sleep_sts) {
++		/* Save the current state */
++		core_if->lx_state = DWC_OTG_L1;
++	}
++
++	/* Clear interrupt  */
++	gintsts.d32 = 0;
++	gintsts.b.lpmtranrcvd = 1;
++	DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
++	return 1;
++}
++#endif /* CONFIG_USB_DWC_OTG_LPM */
++
++/**
++ * This function returns the Core Interrupt register.
++ */
++static inline uint32_t dwc_otg_read_common_intr(dwc_otg_core_if_t * core_if)
++{
++	gahbcfg_data_t gahbcfg = {.d32 = 0 };
++	gintsts_data_t gintsts;
++	gintmsk_data_t gintmsk;
++	gintmsk_data_t gintmsk_common = {.d32 = 0 };
++	gintmsk_common.b.wkupintr = 1;
++	gintmsk_common.b.sessreqintr = 1;
++	gintmsk_common.b.conidstschng = 1;
++	gintmsk_common.b.otgintr = 1;
++	gintmsk_common.b.modemismatch = 1;
++	gintmsk_common.b.disconnect = 1;
++	gintmsk_common.b.usbsuspend = 1;
++#ifdef CONFIG_USB_DWC_OTG_LPM
++	gintmsk_common.b.lpmtranrcvd = 1;
++#endif
++	gintmsk_common.b.restoredone = 1;
++	/** @todo: The port interrupt occurs while in device
++         * mode. Added code to CIL to clear the interrupt for now!
++         */
++	gintmsk_common.b.portintr = 1;
++
++	gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
++	gintmsk.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintmsk);
++	gahbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gahbcfg);
++
++#ifdef DEBUG
++	/* if any common interrupts set */
++	if (gintsts.d32 & gintmsk_common.d32) {
++		DWC_DEBUGPL(DBG_ANY, "gintsts=%08x  gintmsk=%08x\n",
++			    gintsts.d32, gintmsk.d32);
++	}
++#endif
++	if (gahbcfg.b.glblintrmsk)
++		return ((gintsts.d32 & gintmsk.d32) & gintmsk_common.d32);
++	else
++		return 0;
++
++}
++
++/* MACRO for clearing interupt bits in GPWRDN register */
++#define CLEAR_GPWRDN_INTR(__core_if,__intr) \
++do { \
++		gpwrdn_data_t gpwrdn = {.d32=0}; \
++		gpwrdn.b.__intr = 1; \
++		DWC_MODIFY_REG32(&__core_if->core_global_regs->gpwrdn, \
++		0, gpwrdn.d32); \
++} while (0)
++
++/**
++ * Common interrupt handler.
++ *
++ * The common interrupts are those that occur in both Host and Device mode.
++ * This handler handles the following interrupts:
++ * - Mode Mismatch Interrupt
++ * - Disconnect Interrupt
++ * - OTG Interrupt
++ * - Connector ID Status Change Interrupt
++ * - Session Request Interrupt.
++ * - Resume / Remote Wakeup Detected Interrupt.
++ * - LPM Transaction Received Interrupt
++ * - ADP Transaction Received Interrupt
++ *
++ */
++int32_t dwc_otg_handle_common_intr(void *dev)
++{
++	int retval = 0;
++	gintsts_data_t gintsts;
++	gpwrdn_data_t gpwrdn = {.d32 = 0 };
++	dwc_otg_device_t *otg_dev = dev;
++	dwc_otg_core_if_t *core_if = otg_dev->core_if;
++	gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
++
++	if (dwc_otg_check_haps_status(core_if) == -1 ) {
++		DWC_WARN("HAPS is disconnected");
++		return retval;
++	}
++
++	if (dwc_otg_is_device_mode(core_if))
++		core_if->frame_num = dwc_otg_get_frame_number(core_if);
++
++	if (core_if->lock)
++		DWC_SPINLOCK(core_if->lock);
++
++	if (core_if->power_down == 3 && core_if->xhib == 1) {
++		DWC_DEBUGPL(DBG_ANY, "Exiting from xHIB state\n");
++		retval |= dwc_otg_handle_xhib_exit_intr(core_if);
++		core_if->xhib = 2;
++		if (core_if->lock)
++			DWC_SPINUNLOCK(core_if->lock);
++
++		return retval;
++	}
++
++	if (core_if->hibernation_suspend <= 0) {
++		gintsts.d32 = dwc_otg_read_common_intr(core_if);
++
++		if (gintsts.b.modemismatch) {
++			retval |= dwc_otg_handle_mode_mismatch_intr(core_if);
++		}
++		if (gintsts.b.otgintr) {
++			retval |= dwc_otg_handle_otg_intr(core_if);
++		}
++		if (gintsts.b.conidstschng) {
++			retval |=
++			    dwc_otg_handle_conn_id_status_change_intr(core_if);
++		}
++		if (gintsts.b.disconnect) {
++			retval |= dwc_otg_handle_disconnect_intr(core_if);
++		}
++		if (gintsts.b.sessreqintr) {
++			retval |= dwc_otg_handle_session_req_intr(core_if);
++		}
++		if (gintsts.b.wkupintr) {
++			retval |= dwc_otg_handle_wakeup_detected_intr(core_if);
++		}
++		if (gintsts.b.usbsuspend) {
++			retval |= dwc_otg_handle_usb_suspend_intr(core_if);
++		}
++#ifdef CONFIG_USB_DWC_OTG_LPM
++		if (gintsts.b.lpmtranrcvd) {
++			retval |= dwc_otg_handle_lpm_intr(core_if);
++		}
++#endif
++		if (gintsts.b.restoredone) {
++			gintsts.d32 = 0;
++			if (core_if->power_down == 2)
++				core_if->hibernation_suspend = -1;
++			else if (core_if->power_down == 3 && core_if->xhib == 2) {
++				gpwrdn_data_t gpwrdn = {.d32 = 0 };
++				pcgcctl_data_t pcgcctl = {.d32 = 0 };
++				dctl_data_t dctl = {.d32 = 0 };
++
++				DWC_WRITE_REG32(&core_if->core_global_regs->
++						gintsts, 0xFFFFFFFF);
++
++				DWC_DEBUGPL(DBG_ANY,
++					    "RESTORE DONE generated\n");
++
++				gpwrdn.b.restore = 1;
++				DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++				dwc_udelay(10);
++
++				pcgcctl.b.rstpdwnmodule = 1;
++				DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
++
++				DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, core_if->gr_backup->gusbcfg_local);
++				DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg, core_if->dr_backup->dcfg);
++				DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl, core_if->dr_backup->dctl);
++				dwc_udelay(50);
++
++				dctl.b.pwronprgdone = 1;
++				DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0, dctl.d32);
++				dwc_udelay(10);
++
++				dwc_otg_restore_global_regs(core_if);
++				dwc_otg_restore_dev_regs(core_if, 0);
++
++				dctl.d32 = 0;
++				dctl.b.pwronprgdone = 1;
++				DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32, 0);
++				dwc_udelay(10);
++
++				pcgcctl.d32 = 0;
++				pcgcctl.b.enbl_extnd_hiber = 1;
++				DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
++
++				/* The core will be in ON STATE */
++				core_if->lx_state = DWC_OTG_L0;
++				core_if->xhib = 0;
++
++				DWC_SPINUNLOCK(core_if->lock);
++				if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup) {
++					core_if->pcd_cb->resume_wakeup(core_if->pcd_cb->p);
++				}
++				DWC_SPINLOCK(core_if->lock);
++
++			}
++
++			gintsts.b.restoredone = 1;
++			DWC_WRITE_REG32(&core_if->core_global_regs->gintsts,gintsts.d32);
++			DWC_PRINTF(" --Restore done interrupt received-- \n");
++			retval |= 1;
++		}
++		if (gintsts.b.portintr && dwc_otg_is_device_mode(core_if)) {
++			/* The port interrupt occurs while in device mode with HPRT0
++			 * Port Enable/Disable.
++			 */
++			gintsts.d32 = 0;
++			gintsts.b.portintr = 1;
++			DWC_WRITE_REG32(&core_if->core_global_regs->gintsts,gintsts.d32);
++			retval |= 1;
++
++		}
++	} else {
++		DWC_DEBUGPL(DBG_ANY, "gpwrdn=%08x\n", gpwrdn.d32);
++
++		if (gpwrdn.b.disconn_det && gpwrdn.b.disconn_det_msk) {
++			CLEAR_GPWRDN_INTR(core_if, disconn_det);
++			if (gpwrdn.b.linestate == 0) {
++				dwc_otg_handle_pwrdn_disconnect_intr(core_if);
++			} else {
++				DWC_PRINTF("Disconnect detected while linestate is not 0\n");
++			}
++
++			retval |= 1;
++		}
++		if (gpwrdn.b.lnstschng && gpwrdn.b.lnstchng_msk) {
++			CLEAR_GPWRDN_INTR(core_if, lnstschng);
++			/* remote wakeup from hibernation */
++			if (gpwrdn.b.linestate == 2 || gpwrdn.b.linestate == 1) {
++				dwc_otg_handle_pwrdn_wakeup_detected_intr(core_if);
++			} else {
++				DWC_PRINTF("gpwrdn.linestate = %d\n", gpwrdn.b.linestate);
++			}
++			retval |= 1;
++		}
++		if (gpwrdn.b.rst_det && gpwrdn.b.rst_det_msk) {
++			CLEAR_GPWRDN_INTR(core_if, rst_det);
++			if (gpwrdn.b.linestate == 0) {
++				DWC_PRINTF("Reset detected\n");
++				retval |= dwc_otg_device_hibernation_restore(core_if, 0, 1);
++			}
++		}
++		if (gpwrdn.b.srp_det && gpwrdn.b.srp_det_msk) {
++			CLEAR_GPWRDN_INTR(core_if, srp_det);
++			dwc_otg_handle_pwrdn_srp_intr(core_if);
++			retval |= 1;
++		}
++	}
++	/* Handle ADP interrupt here */
++	if (gpwrdn.b.adp_int) {
++		CLEAR_GPWRDN_INTR(core_if, adp_int);
++		dwc_otg_adp_handle_intr(core_if);
++		retval |= 1;
++	}
++	if (gpwrdn.b.sts_chngint && gpwrdn.b.sts_chngint_msk) {
++		CLEAR_GPWRDN_INTR(core_if, sts_chngint);
++		dwc_otg_handle_pwrdn_stschng_intr(otg_dev);
++
++		retval |= 1;
++	}
++	if (gpwrdn.b.srp_det && gpwrdn.b.srp_det_msk) {
++		CLEAR_GPWRDN_INTR(core_if, srp_det);
++		dwc_otg_handle_pwrdn_srp_intr(core_if);
++		retval |= 1;
++	}
++	if (core_if->lock)
++		DWC_SPINUNLOCK(core_if->lock);
++
++	return retval;
++}
+diff --git a/drivers/usb/gadget/udc/hiudc/dwc_otg_core_if.h b/drivers/usb/gadget/udc/hiudc/dwc_otg_core_if.h
+new file mode 100644
+index 0000000..c9ab2e5
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc/dwc_otg_core_if.h
+@@ -0,0 +1,743 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_core_if.h $
++ * $Revision: #15 $
++ * $Date: 2012/12/10 $
++ * $Change: 2123206 $
++ *
++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
++ * ========================================================================== */
++#if !defined(__DWC_CORE_IF_H__)
++#define __DWC_CORE_IF_H__
++
++#include "dwc_os.h"
++
++/** @file
++ * This file defines DWC_OTG Core API
++ */
++
++struct dwc_otg_core_if;
++typedef struct dwc_otg_core_if dwc_otg_core_if_t;
++
++/** Maximum number of Periodic FIFOs */
++#define MAX_PERIO_FIFOS 15
++/** Maximum number of Periodic FIFOs */
++#define MAX_TX_FIFOS 15
++
++/** Maximum number of Endpoints/HostChannels */
++#define MAX_EPS_CHANNELS 16
++
++extern dwc_otg_core_if_t *dwc_otg_cil_init(const uint32_t * _reg_base_addr);
++extern void dwc_otg_core_init(dwc_otg_core_if_t * _core_if);
++extern void dwc_otg_cil_remove(dwc_otg_core_if_t * _core_if);
++
++extern void dwc_otg_enable_global_interrupts(dwc_otg_core_if_t * _core_if);
++extern void dwc_otg_disable_global_interrupts(dwc_otg_core_if_t * _core_if);
++
++extern uint8_t dwc_otg_is_device_mode(dwc_otg_core_if_t * _core_if);
++extern uint8_t dwc_otg_is_host_mode(dwc_otg_core_if_t * _core_if);
++
++extern uint8_t dwc_otg_is_dma_enable(dwc_otg_core_if_t * core_if);
++
++/** This function should be called on every hardware interrupt. */
++extern int32_t dwc_otg_handle_common_intr(void *otg_dev);
++
++/** @name OTG Core Parameters */
++/** @{ */
++
++/**
++ * Specifies the OTG capabilities. The driver will automatically
++ * detect the value for this parameter if none is specified.
++ * 0 - HNP and SRP capable (default)
++ * 1 - SRP Only capable
++ * 2 - No HNP/SRP capable
++ */
++extern int dwc_otg_set_param_otg_cap(dwc_otg_core_if_t * core_if, int32_t val);
++extern int32_t dwc_otg_get_param_otg_cap(dwc_otg_core_if_t * core_if);
++#define DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE 0
++#define DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE 1
++#define DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE 2
++#define dwc_param_otg_cap_default DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE
++
++extern int dwc_otg_set_param_opt(dwc_otg_core_if_t * core_if, int32_t val);
++extern int32_t dwc_otg_get_param_opt(dwc_otg_core_if_t * core_if);
++#define dwc_param_opt_default 1
++
++/**
++ * Specifies whether to use slave or DMA mode for accessing the data
++ * FIFOs. The driver will automatically detect the value for this
++ * parameter if none is specified.
++ * 0 - Slave
++ * 1 - DMA (default, if available)
++ */
++extern int dwc_otg_set_param_dma_enable(dwc_otg_core_if_t * core_if,
++					int32_t val);
++extern int32_t dwc_otg_get_param_dma_enable(dwc_otg_core_if_t * core_if);
++#define dwc_param_dma_enable_default 1
++
++/**
++ * When DMA mode is enabled specifies whether to use
++ * address DMA or DMA Descritor mode for accessing the data
++ * FIFOs in device mode. The driver will automatically detect
++ * the value for this parameter if none is specified.
++ * 0 - address DMA
++ * 1 - DMA Descriptor(default, if available)
++ */
++extern int dwc_otg_set_param_dma_desc_enable(dwc_otg_core_if_t * core_if,
++					     int32_t val);
++extern int32_t dwc_otg_get_param_dma_desc_enable(dwc_otg_core_if_t * core_if);
++#define dwc_param_dma_desc_enable_default 1
++
++/** The DMA Burst size (applicable only for External DMA
++ * Mode). 1, 4, 8 16, 32, 64, 128, 256 (default 32)
++ */
++extern int dwc_otg_set_param_dma_burst_size(dwc_otg_core_if_t * core_if,
++					    int32_t val);
++extern int32_t dwc_otg_get_param_dma_burst_size(dwc_otg_core_if_t * core_if);
++#define dwc_param_dma_burst_size_default 32
++
++/**
++ * Specifies the maximum speed of operation in host and device mode.
++ * The actual speed depends on the speed of the attached device and
++ * the value of phy_type. The actual speed depends on the speed of the
++ * attached device.
++ * 0 - High Speed (default)
++ * 1 - Full Speed
++ */
++extern int dwc_otg_set_param_speed(dwc_otg_core_if_t * core_if, int32_t val);
++extern int32_t dwc_otg_get_param_speed(dwc_otg_core_if_t * core_if);
++#define dwc_param_speed_default 0
++#define DWC_SPEED_PARAM_HIGH 0
++#define DWC_SPEED_PARAM_FULL 1
++
++/** Specifies whether low power mode is supported when attached
++ *	to a Full Speed or Low Speed device in host mode.
++ * 0 - Don't support low power mode (default)
++ * 1 - Support low power mode
++ */
++extern int dwc_otg_set_param_host_support_fs_ls_low_power(dwc_otg_core_if_t *
++							  core_if, int32_t val);
++extern int32_t dwc_otg_get_param_host_support_fs_ls_low_power(dwc_otg_core_if_t
++							      * core_if);
++#define dwc_param_host_support_fs_ls_low_power_default 0
++
++/** Specifies the PHY clock rate in low power mode when connected to a
++ * Low Speed device in host mode. This parameter is applicable only if
++ * HOST_SUPPORT_FS_LS_LOW_POWER is enabled. If PHY_TYPE is set to FS
++ * then defaults to 6 MHZ otherwise 48 MHZ.
++ *
++ * 0 - 48 MHz
++ * 1 - 6 MHz
++ */
++extern int dwc_otg_set_param_host_ls_low_power_phy_clk(dwc_otg_core_if_t *
++						       core_if, int32_t val);
++extern int32_t dwc_otg_get_param_host_ls_low_power_phy_clk(dwc_otg_core_if_t *
++							   core_if);
++#define dwc_param_host_ls_low_power_phy_clk_default 0
++#define DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ 0
++#define DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ 1
++
++/**
++ * 0 - Use cC FIFO size parameters
++ * 1 - Allow dynamic FIFO sizing (default)
++ */
++extern int dwc_otg_set_param_enable_dynamic_fifo(dwc_otg_core_if_t * core_if,
++						 int32_t val);
++extern int32_t dwc_otg_get_param_enable_dynamic_fifo(dwc_otg_core_if_t *
++						     core_if);
++#define dwc_param_enable_dynamic_fifo_default 1
++
++/** Total number of 4-byte words in the data FIFO memory. This
++ * memory includes the Rx FIFO, non-periodic Tx FIFO, and periodic
++ * Tx FIFOs.
++ * 32 to 32768 (default 8192)
++ * Note: The total FIFO memory depth in the FPGA configuration is 8192.
++ */
++extern int dwc_otg_set_param_data_fifo_size(dwc_otg_core_if_t * core_if,
++					    int32_t val);
++extern int32_t dwc_otg_get_param_data_fifo_size(dwc_otg_core_if_t * core_if);
++#define dwc_param_data_fifo_size_default 8192
++
++/** Number of 4-byte words in the Rx FIFO in device mode when dynamic
++ * FIFO sizing is enabled.
++ * 16 to 32768 (default 1064)
++ */
++extern int dwc_otg_set_param_dev_rx_fifo_size(dwc_otg_core_if_t * core_if,
++					      int32_t val);
++extern int32_t dwc_otg_get_param_dev_rx_fifo_size(dwc_otg_core_if_t * core_if);
++#define dwc_param_dev_rx_fifo_size_default 1064
++
++/** Number of 4-byte words in the non-periodic Tx FIFO in device mode
++ * when dynamic FIFO sizing is enabled.
++ * 16 to 32768 (default 1024)
++ */
++extern int dwc_otg_set_param_dev_nperio_tx_fifo_size(dwc_otg_core_if_t *
++						     core_if, int32_t val);
++extern int32_t dwc_otg_get_param_dev_nperio_tx_fifo_size(dwc_otg_core_if_t *
++							 core_if);
++#define dwc_param_dev_nperio_tx_fifo_size_default 1024
++
++/** Number of 4-byte words in each of the periodic Tx FIFOs in device
++ * mode when dynamic FIFO sizing is enabled.
++ * 4 to 768 (default 256)
++ */
++extern int dwc_otg_set_param_dev_perio_tx_fifo_size(dwc_otg_core_if_t * core_if,
++						    int32_t val, int fifo_num);
++extern int32_t dwc_otg_get_param_dev_perio_tx_fifo_size(dwc_otg_core_if_t *
++							core_if, int fifo_num);
++#define dwc_param_dev_perio_tx_fifo_size_default 256
++
++/** Number of 4-byte words in the Rx FIFO in host mode when dynamic
++ * FIFO sizing is enabled.
++ * 16 to 32768 (default 1024)
++ */
++extern int dwc_otg_set_param_host_rx_fifo_size(dwc_otg_core_if_t * core_if,
++					       int32_t val);
++extern int32_t dwc_otg_get_param_host_rx_fifo_size(dwc_otg_core_if_t * core_if);
++#define dwc_param_host_rx_fifo_size_default 1024
++
++/** Number of 4-byte words in the non-periodic Tx FIFO in host mode
++ * when Dynamic FIFO sizing is enabled in the core.
++ * 16 to 32768 (default 1024)
++ */
++extern int dwc_otg_set_param_host_nperio_tx_fifo_size(dwc_otg_core_if_t *
++						      core_if, int32_t val);
++extern int32_t dwc_otg_get_param_host_nperio_tx_fifo_size(dwc_otg_core_if_t *
++							  core_if);
++#define dwc_param_host_nperio_tx_fifo_size_default 1024
++
++/** Number of 4-byte words in the host periodic Tx FIFO when dynamic
++ * FIFO sizing is enabled.
++ * 16 to 32768 (default 1024)
++ */
++extern int dwc_otg_set_param_host_perio_tx_fifo_size(dwc_otg_core_if_t *
++						     core_if, int32_t val);
++extern int32_t dwc_otg_get_param_host_perio_tx_fifo_size(dwc_otg_core_if_t *
++							 core_if);
++#define dwc_param_host_perio_tx_fifo_size_default 1024
++
++/** The maximum transfer size supported in bytes.
++ * 2047 to 65,535  (default 65,535)
++ */
++extern int dwc_otg_set_param_max_transfer_size(dwc_otg_core_if_t * core_if,
++					       int32_t val);
++extern int32_t dwc_otg_get_param_max_transfer_size(dwc_otg_core_if_t * core_if);
++#define dwc_param_max_transfer_size_default 65535
++
++/** The maximum number of packets in a transfer.
++ * 15 to 511  (default 511)
++ */
++extern int dwc_otg_set_param_max_packet_count(dwc_otg_core_if_t * core_if,
++					      int32_t val);
++extern int32_t dwc_otg_get_param_max_packet_count(dwc_otg_core_if_t * core_if);
++#define dwc_param_max_packet_count_default 511
++
++/** The number of host channel registers to use.
++ * 1 to 16 (default 12)
++ * Note: The FPGA configuration supports a maximum of 12 host channels.
++ */
++extern int dwc_otg_set_param_host_channels(dwc_otg_core_if_t * core_if,
++					   int32_t val);
++extern int32_t dwc_otg_get_param_host_channels(dwc_otg_core_if_t * core_if);
++#define dwc_param_host_channels_default 12
++
++/** The number of endpoints in addition to EP0 available for device
++ * mode operations.
++ * 1 to 15 (default 6 IN and OUT)
++ * Note: The FPGA configuration supports a maximum of 6 IN and OUT
++ * endpoints in addition to EP0.
++ */
++extern int dwc_otg_set_param_dev_endpoints(dwc_otg_core_if_t * core_if,
++					   int32_t val);
++extern int32_t dwc_otg_get_param_dev_endpoints(dwc_otg_core_if_t * core_if);
++#define dwc_param_dev_endpoints_default 6
++
++/**
++ * Specifies the type of PHY interface to use. By default, the driver
++ * will automatically detect the phy_type.
++ *
++ * 0 - Full Speed PHY
++ * 1 - UTMI+ (default)
++ * 2 - ULPI
++ */
++extern int dwc_otg_set_param_phy_type(dwc_otg_core_if_t * core_if, int32_t val);
++extern int32_t dwc_otg_get_param_phy_type(dwc_otg_core_if_t * core_if);
++#define DWC_PHY_TYPE_PARAM_FS 0
++#define DWC_PHY_TYPE_PARAM_UTMI 1
++#define DWC_PHY_TYPE_PARAM_ULPI 2
++#define dwc_param_phy_type_default DWC_PHY_TYPE_PARAM_UTMI
++
++/**
++ * Specifies the UTMI+ Data Width. This parameter is
++ * applicable for a PHY_TYPE of UTMI+ or ULPI. (For a ULPI
++ * PHY_TYPE, this parameter indicates the data width between
++ * the MAC and the ULPI Wrapper.) Also, this parameter is
++ * applicable only if the OTG_HSPHY_WIDTH cC parameter was set
++ * to "8 and 16 bits", meaning that the core has been
++ * configured to work at either data path width.
++ *
++ * 8 or 16 bits (default 16)
++ */
++extern int dwc_otg_set_param_phy_utmi_width(dwc_otg_core_if_t * core_if,
++					    int32_t val);
++extern int32_t dwc_otg_get_param_phy_utmi_width(dwc_otg_core_if_t * core_if);
++#define dwc_param_phy_utmi_width_default 16
++
++/**
++ * Specifies whether the ULPI operates at double or single
++ * data rate. This parameter is only applicable if PHY_TYPE is
++ * ULPI.
++ *
++ * 0 - single data rate ULPI interface with 8 bit wide data
++ * bus (default)
++ * 1 - double data rate ULPI interface with 4 bit wide data
++ * bus
++ */
++extern int dwc_otg_set_param_phy_ulpi_ddr(dwc_otg_core_if_t * core_if,
++					  int32_t val);
++extern int32_t dwc_otg_get_param_phy_ulpi_ddr(dwc_otg_core_if_t * core_if);
++#define dwc_param_phy_ulpi_ddr_default 0
++
++/**
++ * Specifies whether to use the internal or external supply to
++ * drive the vbus with a ULPI phy.
++ */
++extern int dwc_otg_set_param_phy_ulpi_ext_vbus(dwc_otg_core_if_t * core_if,
++					       int32_t val);
++extern int32_t dwc_otg_get_param_phy_ulpi_ext_vbus(dwc_otg_core_if_t * core_if);
++#define DWC_PHY_ULPI_INTERNAL_VBUS 0
++#define DWC_PHY_ULPI_EXTERNAL_VBUS 1
++#define dwc_param_phy_ulpi_ext_vbus_default DWC_PHY_ULPI_INTERNAL_VBUS
++
++/**
++ * Specifies whether to use the I2Cinterface for full speed PHY. This
++ * parameter is only applicable if PHY_TYPE is FS.
++ * 0 - No (default)
++ * 1 - Yes
++ */
++extern int dwc_otg_set_param_i2c_enable(dwc_otg_core_if_t * core_if,
++					int32_t val);
++extern int32_t dwc_otg_get_param_i2c_enable(dwc_otg_core_if_t * core_if);
++#define dwc_param_i2c_enable_default 0
++
++extern int dwc_otg_set_param_ulpi_fs_ls(dwc_otg_core_if_t * core_if,
++					int32_t val);
++extern int32_t dwc_otg_get_param_ulpi_fs_ls(dwc_otg_core_if_t * core_if);
++#define dwc_param_ulpi_fs_ls_default 0
++
++extern int dwc_otg_set_param_ts_dline(dwc_otg_core_if_t * core_if, int32_t val);
++extern int32_t dwc_otg_get_param_ts_dline(dwc_otg_core_if_t * core_if);
++#define dwc_param_ts_dline_default 0
++
++/**
++ * Specifies whether dedicated transmit FIFOs are
++ * enabled for non periodic IN endpoints in device mode
++ * 0 - No
++ * 1 - Yes
++ */
++extern int dwc_otg_set_param_en_multiple_tx_fifo(dwc_otg_core_if_t * core_if,
++						 int32_t val);
++extern int32_t dwc_otg_get_param_en_multiple_tx_fifo(dwc_otg_core_if_t *
++						     core_if);
++#define dwc_param_en_multiple_tx_fifo_default 1
++
++/** Number of 4-byte words in each of the Tx FIFOs in device
++ * mode when dynamic FIFO sizing is enabled.
++ * 4 to 768 (default 256)
++ */
++extern int dwc_otg_set_param_dev_tx_fifo_size(dwc_otg_core_if_t * core_if,
++					      int fifo_num, int32_t val);
++extern int32_t dwc_otg_get_param_dev_tx_fifo_size(dwc_otg_core_if_t * core_if,
++						  int fifo_num);
++#define dwc_param_dev_tx_fifo_size_default 256
++
++/** Thresholding enable flag-
++ * bit 0 - enable non-ISO Tx thresholding
++ * bit 1 - enable ISO Tx thresholding
++ * bit 2 - enable Rx thresholding
++ */
++extern int dwc_otg_set_param_thr_ctl(dwc_otg_core_if_t * core_if, int32_t val);
++extern int32_t dwc_otg_get_thr_ctl(dwc_otg_core_if_t * core_if, int fifo_num);
++#define dwc_param_thr_ctl_default 0
++
++/** Thresholding length for Tx
++ * FIFOs in 32 bit DWORDs
++ */
++extern int dwc_otg_set_param_tx_thr_length(dwc_otg_core_if_t * core_if,
++					   int32_t val);
++extern int32_t dwc_otg_get_tx_thr_length(dwc_otg_core_if_t * core_if);
++#define dwc_param_tx_thr_length_default 64
++
++/** Thresholding length for Rx
++ *	FIFOs in 32 bit DWORDs
++ */
++extern int dwc_otg_set_param_rx_thr_length(dwc_otg_core_if_t * core_if,
++					   int32_t val);
++extern int32_t dwc_otg_get_rx_thr_length(dwc_otg_core_if_t * core_if);
++#define dwc_param_rx_thr_length_default 64
++
++/**
++ * Specifies whether LPM (Link Power Management) support is enabled
++ */
++extern int dwc_otg_set_param_lpm_enable(dwc_otg_core_if_t * core_if,
++					int32_t val);
++extern int32_t dwc_otg_get_param_lpm_enable(dwc_otg_core_if_t * core_if);
++#define dwc_param_lpm_enable_default 1
++
++/**
++ * Specifies whether LPM Errata (Link Power Management) support is enabled
++ */
++extern int dwc_otg_set_param_besl_enable(dwc_otg_core_if_t * core_if,
++					int32_t val);
++extern int32_t dwc_otg_get_param_besl_enable(dwc_otg_core_if_t * core_if);
++#define dwc_param_besl_enable_default 0
++
++/**
++ * Specifies baseline_besl default value
++ */
++extern int dwc_otg_set_param_baseline_besl(dwc_otg_core_if_t * core_if,
++					int32_t val);
++extern int32_t dwc_otg_get_param_baseline_besl(dwc_otg_core_if_t * core_if);
++#define dwc_param_baseline_besl_default 0
++
++/**
++ * Specifies deep_besl default value
++ */
++extern int dwc_otg_set_param_deep_besl(dwc_otg_core_if_t * core_if,
++					int32_t val);
++extern int32_t dwc_otg_get_param_deep_besl(dwc_otg_core_if_t * core_if);
++#define dwc_param_deep_besl_default 15
++
++/**
++ * Specifies whether PTI enhancement is enabled
++ */
++extern int dwc_otg_set_param_pti_enable(dwc_otg_core_if_t * core_if,
++					int32_t val);
++extern int32_t dwc_otg_get_param_pti_enable(dwc_otg_core_if_t * core_if);
++#define dwc_param_pti_enable_default 0
++
++/**
++ * Specifies whether MPI enhancement is enabled
++ */
++extern int dwc_otg_set_param_mpi_enable(dwc_otg_core_if_t * core_if,
++					int32_t val);
++extern int32_t dwc_otg_get_param_mpi_enable(dwc_otg_core_if_t * core_if);
++#define dwc_param_mpi_enable_default 0
++
++/**
++ * Specifies whether ADP capability is enabled
++ */
++extern int dwc_otg_set_param_adp_enable(dwc_otg_core_if_t * core_if,
++					int32_t val);
++extern int32_t dwc_otg_get_param_adp_enable(dwc_otg_core_if_t * core_if);
++#define dwc_param_adp_enable_default 0
++
++/**
++ * Specifies whether IC_USB capability is enabled
++ */
++
++extern int dwc_otg_set_param_ic_usb_cap(dwc_otg_core_if_t * core_if,
++					int32_t val);
++extern int32_t dwc_otg_get_param_ic_usb_cap(dwc_otg_core_if_t * core_if);
++#define dwc_param_ic_usb_cap_default 0
++
++extern int dwc_otg_set_param_ahb_thr_ratio(dwc_otg_core_if_t * core_if,
++					   int32_t val);
++extern int32_t dwc_otg_get_param_ahb_thr_ratio(dwc_otg_core_if_t * core_if);
++#define dwc_param_ahb_thr_ratio_default 0
++
++extern int dwc_otg_set_param_power_down(dwc_otg_core_if_t * core_if,
++					int32_t val);
++extern int32_t dwc_otg_get_param_power_down(dwc_otg_core_if_t * core_if);
++#define dwc_param_power_down_default 0
++
++extern int dwc_otg_set_param_reload_ctl(dwc_otg_core_if_t * core_if,
++					int32_t val);
++extern int32_t dwc_otg_get_param_reload_ctl(dwc_otg_core_if_t * core_if);
++#define dwc_param_reload_ctl_default 0
++
++extern int dwc_otg_set_param_dev_out_nak(dwc_otg_core_if_t * core_if,
++					 int32_t val);
++extern int32_t dwc_otg_get_param_dev_out_nak(dwc_otg_core_if_t * core_if);
++#define dwc_param_dev_out_nak_default 0
++
++extern int dwc_otg_set_param_cont_on_bna(dwc_otg_core_if_t * core_if,
++					 int32_t val);
++extern int32_t dwc_otg_get_param_cont_on_bna(dwc_otg_core_if_t * core_if);
++#define dwc_param_cont_on_bna_default 0
++
++extern int dwc_otg_set_param_ahb_single(dwc_otg_core_if_t * core_if,
++					int32_t val);
++extern int32_t dwc_otg_get_param_ahb_single(dwc_otg_core_if_t * core_if);
++#define dwc_param_ahb_single_default 0
++
++extern int dwc_otg_set_param_otg_ver(dwc_otg_core_if_t * core_if, int32_t val);
++extern int32_t dwc_otg_get_param_otg_ver(dwc_otg_core_if_t * core_if);
++#define dwc_param_otg_ver_default 0
++
++/** @} */
++
++/** @name Access to registers and bit-fields */
++
++/**
++ * Dump core registers and SPRAM
++ */
++extern void dwc_otg_dump_dev_registers(dwc_otg_core_if_t * _core_if);
++extern void dwc_otg_dump_spram(dwc_otg_core_if_t * _core_if);
++extern void dwc_otg_dump_host_registers(dwc_otg_core_if_t * _core_if);
++extern void dwc_otg_dump_global_registers(dwc_otg_core_if_t * _core_if);
++
++/**
++ * Get host negotiation status.
++ */
++extern uint32_t dwc_otg_get_hnpstatus(dwc_otg_core_if_t * core_if);
++
++/**
++ * Get srp status
++ */
++extern uint32_t dwc_otg_get_srpstatus(dwc_otg_core_if_t * core_if);
++
++/**
++ * Set hnpreq bit in the GOTGCTL register.
++ */
++extern void dwc_otg_set_hnpreq(dwc_otg_core_if_t * core_if, uint32_t val);
++
++/**
++ * Get Content of SNPSID register.
++ */
++extern uint32_t dwc_otg_get_gsnpsid(dwc_otg_core_if_t * core_if);
++
++/**
++ * Get current mode.
++ * Returns 0 if in device mode, and 1 if in host mode.
++ */
++extern uint32_t dwc_otg_get_mode(dwc_otg_core_if_t * core_if);
++
++/**
++ * Get value of hnpcapable field in the GUSBCFG register
++ */
++extern uint32_t dwc_otg_get_hnpcapable(dwc_otg_core_if_t * core_if);
++/**
++ * Set value of hnpcapable field in the GUSBCFG register
++ */
++extern void dwc_otg_set_hnpcapable(dwc_otg_core_if_t * core_if, uint32_t val);
++
++/**
++ * Get value of srpcapable field in the GUSBCFG register
++ */
++extern uint32_t dwc_otg_get_srpcapable(dwc_otg_core_if_t * core_if);
++/**
++ * Set value of srpcapable field in the GUSBCFG register
++ */
++extern void dwc_otg_set_srpcapable(dwc_otg_core_if_t * core_if, uint32_t val);
++
++/**
++ * Get value of devspeed field in the DCFG register
++ */
++extern uint32_t dwc_otg_get_devspeed(dwc_otg_core_if_t * core_if);
++/**
++ * Set value of devspeed field in the DCFG register
++ */
++extern void dwc_otg_set_devspeed(dwc_otg_core_if_t * core_if, uint32_t val);
++
++/**
++ * Get the value of busconnected field from the HPRT0 register
++ */
++extern uint32_t dwc_otg_get_busconnected(dwc_otg_core_if_t * core_if);
++
++/**
++ * Gets the device enumeration Speed.
++ */
++extern uint32_t dwc_otg_get_enumspeed(dwc_otg_core_if_t * core_if);
++
++/**
++ * Get value of prtpwr field from the HPRT0 register
++ */
++extern uint32_t dwc_otg_get_prtpower(dwc_otg_core_if_t * core_if);
++
++/**
++ * Get value of flag indicating core state - hibernated or not
++ */
++extern uint32_t dwc_otg_get_core_state(dwc_otg_core_if_t * core_if);
++
++/**
++ * Set value of prtpwr field from the HPRT0 register
++ */
++extern void dwc_otg_set_prtpower(dwc_otg_core_if_t * core_if, uint32_t val);
++
++/**
++ * Get value of prtsusp field from the HPRT0 regsiter
++ */
++extern uint32_t dwc_otg_get_prtsuspend(dwc_otg_core_if_t * core_if);
++/**
++ * Set value of prtpwr field from the HPRT0 register
++ */
++extern void dwc_otg_set_prtsuspend(dwc_otg_core_if_t * core_if, uint32_t val);
++
++/**
++ * Get value of ModeChTimEn field from the HCFG regsiter
++ */
++extern uint32_t dwc_otg_get_mode_ch_tim(dwc_otg_core_if_t * core_if);
++/**
++ * Set value of ModeChTimEn field from the HCFG regsiter
++ */
++extern void dwc_otg_set_mode_ch_tim(dwc_otg_core_if_t * core_if, uint32_t val);
++
++/**
++ * Get value of Fram Interval field from the HFIR regsiter
++ */
++extern uint32_t dwc_otg_get_fr_interval(dwc_otg_core_if_t * core_if);
++/**
++ * Set value of Frame Interval field from the HFIR regsiter
++ */
++extern void dwc_otg_set_fr_interval(dwc_otg_core_if_t * core_if, uint32_t val);
++
++/**
++ * Set value of prtres field from the HPRT0 register
++ *FIXME Remove?
++ */
++extern void dwc_otg_set_prtresume(dwc_otg_core_if_t * core_if, uint32_t val);
++
++/**
++ * Get value of rmtwkupsig bit in DCTL register
++ */
++extern uint32_t dwc_otg_get_remotewakesig(dwc_otg_core_if_t * core_if);
++
++/**
++ * Get value of besl_reject bit in DCTL register
++ */
++
++extern uint32_t dwc_otg_get_beslreject(dwc_otg_core_if_t * core_if);
++
++/**
++ * Set value of besl_reject bit in DCTL register
++ */
++
++extern void dwc_otg_set_beslreject(dwc_otg_core_if_t * core_if, uint32_t val);
++
++/**
++ * Get value of prt_sleep_sts field from the GLPMCFG register
++ */
++extern uint32_t dwc_otg_get_lpm_portsleepstatus(dwc_otg_core_if_t * core_if);
++
++/**
++ * Get value of rem_wkup_en field from the GLPMCFG register
++ */
++extern uint32_t dwc_otg_get_lpm_remotewakeenabled(dwc_otg_core_if_t * core_if);
++
++/**
++ * Get value of appl_resp field from the GLPMCFG register
++ */
++extern uint32_t dwc_otg_get_lpmresponse(dwc_otg_core_if_t * core_if);
++/**
++ * Set value of appl_resp field from the GLPMCFG register
++ */
++extern void dwc_otg_set_lpmresponse(dwc_otg_core_if_t * core_if, uint32_t val);
++
++/**
++ * Get value of hsic_connect field from the GLPMCFG register
++ */
++extern uint32_t dwc_otg_get_hsic_connect(dwc_otg_core_if_t * core_if);
++/**
++ * Set value of hsic_connect field from the GLPMCFG register
++ */
++extern void dwc_otg_set_hsic_connect(dwc_otg_core_if_t * core_if, uint32_t val);
++
++/**
++ * Get value of inv_sel_hsic field from the GLPMCFG register.
++ */
++extern uint32_t dwc_otg_get_inv_sel_hsic(dwc_otg_core_if_t * core_if);
++/**
++ * Set value of inv_sel_hsic field from the GLPMFG register.
++ */
++extern void dwc_otg_set_inv_sel_hsic(dwc_otg_core_if_t * core_if, uint32_t val);
++/**
++ * Set value of hird_thresh field from the GLPMFG register.
++ */
++extern void dwc_otg_set_hirdthresh(dwc_otg_core_if_t * core_if, uint32_t val);
++/**
++ * Get value of hird_thresh field from the GLPMFG register.
++ */
++extern uint32_t dwc_otg_get_hirdthresh(dwc_otg_core_if_t * core_if);
++
++
++/*
++ * Some functions for accessing registers
++ */
++
++/**
++ *  GOTGCTL register
++ */
++extern uint32_t dwc_otg_get_gotgctl(dwc_otg_core_if_t * core_if);
++extern void dwc_otg_set_gotgctl(dwc_otg_core_if_t * core_if, uint32_t val);
++
++/**
++ * GUSBCFG register
++ */
++extern uint32_t dwc_otg_get_gusbcfg(dwc_otg_core_if_t * core_if);
++extern void dwc_otg_set_gusbcfg(dwc_otg_core_if_t * core_if, uint32_t val);
++
++/**
++ * GRXFSIZ register
++ */
++extern uint32_t dwc_otg_get_grxfsiz(dwc_otg_core_if_t * core_if);
++extern void dwc_otg_set_grxfsiz(dwc_otg_core_if_t * core_if, uint32_t val);
++
++/**
++ * GNPTXFSIZ register
++ */
++extern uint32_t dwc_otg_get_gnptxfsiz(dwc_otg_core_if_t * core_if);
++extern void dwc_otg_set_gnptxfsiz(dwc_otg_core_if_t * core_if, uint32_t val);
++
++extern uint32_t dwc_otg_get_gpvndctl(dwc_otg_core_if_t * core_if);
++extern void dwc_otg_set_gpvndctl(dwc_otg_core_if_t * core_if, uint32_t val);
++
++/**
++ * GGPIO register
++ */
++extern uint32_t dwc_otg_get_ggpio(dwc_otg_core_if_t * core_if);
++extern void dwc_otg_set_ggpio(dwc_otg_core_if_t * core_if, uint32_t val);
++
++/**
++ * GUID register
++ */
++extern uint32_t dwc_otg_get_guid(dwc_otg_core_if_t * core_if);
++extern void dwc_otg_set_guid(dwc_otg_core_if_t * core_if, uint32_t val);
++
++/**
++ * HPRT0 register
++ */
++extern uint32_t dwc_otg_get_hprt0(dwc_otg_core_if_t * core_if);
++extern void dwc_otg_set_hprt0(dwc_otg_core_if_t * core_if, uint32_t val);
++
++/**
++ * GHPTXFSIZE
++ */
++extern uint32_t dwc_otg_get_hptxfsiz(dwc_otg_core_if_t * core_if);
++
++/** @} */
++
++#endif /* __DWC_CORE_IF_H__ */
+diff --git a/drivers/usb/gadget/udc/hiudc/dwc_otg_dbg.h b/drivers/usb/gadget/udc/hiudc/dwc_otg_dbg.h
+new file mode 100644
+index 0000000..32c7d10
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc/dwc_otg_dbg.h
+@@ -0,0 +1,113 @@
++/* ==========================================================================
++ *
++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
++ * ========================================================================== */
++
++#ifndef __DWC_OTG_DBG_H__
++#define __DWC_OTG_DBG_H__
++
++/** @file
++ * This file defines debug levels.
++ * Debugging support vanishes in non-debug builds.
++ */
++
++/**
++ * The Debug Level bit-mask variable.
++ */
++extern uint32_t g_dbg_lvl;
++/**
++ * Set the Debug Level variable.
++ */
++static inline uint32_t SET_DEBUG_LEVEL(const uint32_t new)
++{
++	uint32_t old = g_dbg_lvl;
++	g_dbg_lvl = new;
++	return old;
++}
++
++/** When debug level has the DBG_CIL bit set, display CIL Debug messages. */
++#define DBG_CIL		(0x2)
++/** When debug level has the DBG_CILV bit set, display CIL Verbose debug
++ * messages */
++#define DBG_CILV	(0x20)
++/**  When debug level has the DBG_PCD bit set, display PCD (Device) debug
++ *  messages */
++#define DBG_PCD		(0x4)
++/** When debug level has the DBG_PCDV set, display PCD (Device) Verbose debug
++ * messages */
++#define DBG_PCDV	(0x40)
++/** When debug level has the DBG_HCD bit set, display Host debug messages */
++#define DBG_HCD		(0x8)
++/** When debug level has the DBG_HCDV bit set, display Verbose Host debug
++ * messages */
++#define DBG_HCDV	(0x80)
++/** When debug level has the DBG_HCD_URB bit set, display enqueued URBs in host
++ *  mode. */
++#define DBG_HCD_URB	(0x800)
++
++/** When debug level has any bit set, display debug messages */
++#define DBG_ANY		(0xFF)
++
++/** All debug messages off */
++#define DBG_OFF		0
++
++/** Prefix string for DWC_DEBUG print macros. */
++#define USB_DWC "DWC_otg: "
++
++/**
++ * Print a debug message when the Global debug level variable contains
++ * the bit defined in <code>lvl</code>.
++ *
++ * @param[in] lvl - Debug level, use one of the DBG_ constants above.
++ * @param[in] x - like printf
++ *
++ *    Example:<p>
++ * <code>
++ *      DWC_DEBUGPL( DBG_ANY, "%s(%p)\n", __func__, _reg_base_addr);
++ * </code>
++ * <br>
++ * results in:<br>
++ * <code>
++ * usb-DWC_otg: dwc_otg_cil_init(ca867000)
++ * </code>
++ */
++#ifdef DEBUG
++
++# define DWC_DEBUGPL(lvl, x...) do{ if ((lvl)&g_dbg_lvl)__DWC_DEBUG(USB_DWC x ); }while(0)
++# define DWC_DEBUGP(x...)	DWC_DEBUGPL(DBG_ANY, x )
++
++# define CHK_DEBUG_LEVEL(level) ((level) & g_dbg_lvl)
++
++#else
++
++# define DWC_DEBUGPL(lvl, x...) do{}while(0)
++# define DWC_DEBUGP(x...)
++
++# define CHK_DEBUG_LEVEL(level) (0)
++
++#endif /*DEBUG*/
++#endif
+diff --git a/drivers/usb/gadget/udc/hiudc/dwc_otg_driver.c b/drivers/usb/gadget/udc/hiudc/dwc_otg_driver.c
+new file mode 100644
+index 0000000..7f291c4
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc/dwc_otg_driver.c
+@@ -0,0 +1,812 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_driver.c $
++ * $Revision: #96 $
++ * $Date: 2013/05/20 $
++ * $Change: 2234037 $
++ *
++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
++ * ========================================================================== */
++
++/** @file
++ * The dwc_otg_driver module provides the initialization and cleanup entry
++ * points for the DWC_otg driver. This module will be dynamically installed
++ * after Linux is booted using the insmod command. When the module is
++ * installed, the dwc_otg_driver_init function is called. When the module is
++ * removed (using rmmod), the dwc_otg_driver_cleanup function is called.
++ *
++ * This module also defines a data structure for the dwc_otg_driver, which is
++ * used in conjunction with the standard ARM lm_device structure. These
++ * structures allow the OTG driver to comply with the standard Linux driver
++ * model in which devices and drivers are registered with a bus driver. This
++ * has the benefit that Linux can expose attributes of the driver and device
++ * in its special sysfs file system. Users can then read or write files in
++ * this file system to perform diagnostics on the driver components or the
++ * device.
++ */
++#include <linux/clk.h>
++#include <linux/dma-mapping.h>
++#include <linux/err.h>
++#include <linux/kernel.h>
++#include <linux/hrtimer.h>
++#include <linux/io.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++
++#include "dwc_otg_os_dep.h"
++#include "dwc_os.h"
++#include "dwc_otg_dbg.h"
++#include "dwc_otg_driver.h"
++#include "dwc_otg_attr.h"
++#include "dwc_otg_core_if.h"
++#include "dwc_otg_pcd_if.h"
++#include "dwc_otg_hcd_if.h"
++
++
++#define DWC_DRIVER_VERSION	"3.00a 10-AUG-2012"
++
++static const char driver_name[] = "hiudc";
++
++extern int pcd_init(  struct platform_device *_dev , int irqnum);
++extern int hcd_init(  struct platform_device *_dev );
++extern int pcd_remove(  struct platform_device *_dev );
++extern void hcd_remove(  struct platform_device *_dev );
++extern void dwc_otg_adp_start(dwc_otg_core_if_t * core_if, uint8_t is_host);
++
++/******************************************************************************/
++
++/* Encapsulate the module parameter settings */
++
++struct dwc_otg_driver_module_params {
++	int32_t opt;
++	int32_t otg_cap;
++	int32_t dma_enable;
++	int32_t dma_desc_enable;
++	int32_t dma_burst_size;
++	int32_t speed;
++	int32_t host_support_fs_ls_low_power;
++	int32_t host_ls_low_power_phy_clk;
++	int32_t enable_dynamic_fifo;
++	int32_t data_fifo_size;
++	int32_t dev_rx_fifo_size;
++	int32_t dev_nperio_tx_fifo_size;
++	uint32_t dev_perio_tx_fifo_size[MAX_PERIO_FIFOS];
++	int32_t host_rx_fifo_size;
++	int32_t host_nperio_tx_fifo_size;
++	int32_t host_perio_tx_fifo_size;
++	int32_t max_transfer_size;
++	int32_t max_packet_count;
++	int32_t host_channels;
++	int32_t dev_endpoints;
++	int32_t phy_type;
++	int32_t phy_utmi_width;
++	int32_t phy_ulpi_ddr;
++	int32_t phy_ulpi_ext_vbus;
++	int32_t i2c_enable;
++	int32_t ulpi_fs_ls;
++	int32_t ts_dline;
++	int32_t en_multiple_tx_fifo;
++	uint32_t dev_tx_fifo_size[MAX_TX_FIFOS];
++	uint32_t thr_ctl;
++	uint32_t tx_thr_length;
++	uint32_t rx_thr_length;
++	int32_t pti_enable;
++	int32_t mpi_enable;
++	int32_t lpm_enable;
++	int32_t besl_enable;
++	int32_t baseline_besl;
++	int32_t deep_besl;
++	int32_t ic_usb_cap;
++	int32_t ahb_thr_ratio;
++	int32_t power_down;
++	int32_t reload_ctl;
++	int32_t dev_out_nak;
++	int32_t cont_on_bna;
++	int32_t ahb_single;
++	int32_t otg_ver;
++	int32_t adp_enable;
++};
++/******************************************************************************/
++
++static struct dwc_otg_driver_module_params dwc_otg_module_params = {
++	.opt = -1,
++	.otg_cap = 2, /*non-hnp/srp-capable*/
++	.dma_enable = 1, /* enable */
++	.dma_desc_enable = 1,
++	.dma_burst_size = -1,
++	.speed = -1,/*high-speed*/
++	.host_support_fs_ls_low_power = -1, /* lowpower mode isn't supported */
++	.host_ls_low_power_phy_clk = -1,
++	.enable_dynamic_fifo = -1,  /* use coreconsultant fifo size */
++	.data_fifo_size = -1,
++	.dev_rx_fifo_size = -1,
++	.dev_nperio_tx_fifo_size = -1,
++	.dev_perio_tx_fifo_size = {
++				   /* dev_perio_tx_fifo_size_1 */
++				   -1,
++				   -1,
++				   -1,
++				   -1,
++				   -1,
++				   -1,
++				   -1,
++				   -1,
++				   -1,
++				   -1,
++				   -1,
++				   -1,
++				   -1,
++				   -1,
++				   -1
++				   /* 15 */
++				   },
++	.host_rx_fifo_size = -1,
++	.host_nperio_tx_fifo_size = -1,
++	.host_perio_tx_fifo_size = -1,
++	.max_transfer_size = -1,
++	.max_packet_count = -1,
++	.host_channels = -1,
++	.dev_endpoints = -1,
++	.phy_type = -1,/*utmi+*/
++	.phy_utmi_width = 8,
++	.phy_ulpi_ddr = -1,
++	.phy_ulpi_ext_vbus = -1,
++	.i2c_enable = -1,
++	.ulpi_fs_ls = -1,
++	.ts_dline = -1,
++	.en_multiple_tx_fifo = -1,
++	.dev_tx_fifo_size = {
++			     /* dev_tx_fifo_size */
++			     -1,
++			     -1,
++			     -1,
++			     -1,
++			     -1,
++			     -1,
++			     -1,
++			     -1,
++			     -1,
++			     -1,
++			     -1,
++			     -1,
++			     -1,
++			     -1,
++			     -1
++			     /* 15 */
++			     },
++	.thr_ctl = -1,
++	.tx_thr_length = -1,
++	.rx_thr_length = -1,
++	.pti_enable = -1,
++	.mpi_enable = -1,
++	.lpm_enable = -1,
++	.besl_enable = -1,
++	.baseline_besl = -1,
++	.deep_besl = -1,
++	.ic_usb_cap = -1,
++	.ahb_thr_ratio = -1,
++	.power_down = -1,
++	.reload_ctl = -1,
++	.dev_out_nak = -1,
++	.cont_on_bna = -1,
++	.ahb_single = -1,
++	.otg_ver = -1,
++	.adp_enable = -1,
++};
++/******************************************************************************/
++
++/**
++ * This function is called during module intialization
++ * to pass module parameters to the DWC_OTG CORE.
++ */
++static int set_parameters(dwc_otg_core_if_t * core_if)
++{
++	int retval = 0;
++	int i;
++
++	if (dwc_otg_module_params.otg_cap != -1) {
++		retval +=
++		    dwc_otg_set_param_otg_cap(core_if,
++					      dwc_otg_module_params.otg_cap);
++	}
++	if (dwc_otg_module_params.dma_enable != -1) {
++		retval +=
++		    dwc_otg_set_param_dma_enable(core_if,
++						 dwc_otg_module_params.
++						 dma_enable);
++	}
++	if (dwc_otg_module_params.dma_desc_enable != -1) {
++		retval +=
++		    dwc_otg_set_param_dma_desc_enable(core_if,
++						      dwc_otg_module_params.
++						      dma_desc_enable);
++	}
++	if (dwc_otg_module_params.opt != -1) {
++		retval +=
++		    dwc_otg_set_param_opt(core_if, dwc_otg_module_params.opt);
++	}
++	if (dwc_otg_module_params.dma_burst_size != -1) {
++		retval +=
++		    dwc_otg_set_param_dma_burst_size(core_if,
++						     dwc_otg_module_params.
++						     dma_burst_size);
++	}
++	if (dwc_otg_module_params.host_support_fs_ls_low_power != -1) {
++		retval +=
++		    dwc_otg_set_param_host_support_fs_ls_low_power(core_if,
++								   dwc_otg_module_params.
++								   host_support_fs_ls_low_power);
++	}
++	if (dwc_otg_module_params.enable_dynamic_fifo != -1) {
++		retval +=
++		    dwc_otg_set_param_enable_dynamic_fifo(core_if,
++							  dwc_otg_module_params.
++							  enable_dynamic_fifo);
++	}
++	if (dwc_otg_module_params.data_fifo_size != -1) {
++		retval +=
++		    dwc_otg_set_param_data_fifo_size(core_if,
++						     dwc_otg_module_params.
++						     data_fifo_size);
++	}
++	if (dwc_otg_module_params.dev_rx_fifo_size != -1) {
++		retval +=
++		    dwc_otg_set_param_dev_rx_fifo_size(core_if,
++						       dwc_otg_module_params.
++						       dev_rx_fifo_size);
++	}
++	if (dwc_otg_module_params.dev_nperio_tx_fifo_size != -1) {
++		retval +=
++		    dwc_otg_set_param_dev_nperio_tx_fifo_size(core_if,
++							      dwc_otg_module_params.
++							      dev_nperio_tx_fifo_size);
++	}
++	if (dwc_otg_module_params.host_rx_fifo_size != -1) {
++		retval +=
++		    dwc_otg_set_param_host_rx_fifo_size(core_if,
++							dwc_otg_module_params.host_rx_fifo_size);
++	}
++	if (dwc_otg_module_params.host_nperio_tx_fifo_size != -1) {
++		retval +=
++		    dwc_otg_set_param_host_nperio_tx_fifo_size(core_if,
++							       dwc_otg_module_params.
++							       host_nperio_tx_fifo_size);
++	}
++	if (dwc_otg_module_params.host_perio_tx_fifo_size != -1) {
++		retval +=
++		    dwc_otg_set_param_host_perio_tx_fifo_size(core_if,
++							      dwc_otg_module_params.
++							      host_perio_tx_fifo_size);
++	}
++	if (dwc_otg_module_params.max_transfer_size != -1) {
++		retval +=
++		    dwc_otg_set_param_max_transfer_size(core_if,
++							dwc_otg_module_params.
++							max_transfer_size);
++	}
++	if (dwc_otg_module_params.max_packet_count != -1) {
++		retval +=
++		    dwc_otg_set_param_max_packet_count(core_if,
++						       dwc_otg_module_params.
++						       max_packet_count);
++	}
++	if (dwc_otg_module_params.host_channels != -1) {
++		retval +=
++		    dwc_otg_set_param_host_channels(core_if,
++						    dwc_otg_module_params.
++						    host_channels);
++	}
++	if (dwc_otg_module_params.dev_endpoints != -1) {
++		retval +=
++		    dwc_otg_set_param_dev_endpoints(core_if,
++						    dwc_otg_module_params.
++						    dev_endpoints);
++	}
++	if (dwc_otg_module_params.phy_type != -1) {
++		retval +=
++		    dwc_otg_set_param_phy_type(core_if,
++					       dwc_otg_module_params.phy_type);
++	}
++	if (dwc_otg_module_params.speed != -1) {
++		retval +=
++		    dwc_otg_set_param_speed(core_if,
++					    dwc_otg_module_params.speed);
++	}
++	if (dwc_otg_module_params.host_ls_low_power_phy_clk != -1) {
++		retval +=
++		    dwc_otg_set_param_host_ls_low_power_phy_clk(core_if,
++								dwc_otg_module_params.
++								host_ls_low_power_phy_clk);
++	}
++	if (dwc_otg_module_params.phy_ulpi_ddr != -1) {
++		retval +=
++		    dwc_otg_set_param_phy_ulpi_ddr(core_if,
++						   dwc_otg_module_params.
++						   phy_ulpi_ddr);
++	}
++	if (dwc_otg_module_params.phy_ulpi_ext_vbus != -1) {
++		retval +=
++		    dwc_otg_set_param_phy_ulpi_ext_vbus(core_if,
++							dwc_otg_module_params.
++							phy_ulpi_ext_vbus);
++	}
++	if (dwc_otg_module_params.phy_utmi_width != -1) {
++		retval +=
++		    dwc_otg_set_param_phy_utmi_width(core_if,
++						     dwc_otg_module_params.
++						     phy_utmi_width);
++	}
++	if (dwc_otg_module_params.ulpi_fs_ls != -1) {
++		retval +=
++		    dwc_otg_set_param_ulpi_fs_ls(core_if,
++						 dwc_otg_module_params.ulpi_fs_ls);
++	}
++	if (dwc_otg_module_params.ts_dline != -1) {
++		retval +=
++		    dwc_otg_set_param_ts_dline(core_if,
++					       dwc_otg_module_params.ts_dline);
++	}
++	if (dwc_otg_module_params.i2c_enable != -1) {
++		retval +=
++		    dwc_otg_set_param_i2c_enable(core_if,
++						 dwc_otg_module_params.
++						 i2c_enable);
++	}
++	if (dwc_otg_module_params.en_multiple_tx_fifo != -1) {
++		retval +=
++		    dwc_otg_set_param_en_multiple_tx_fifo(core_if,
++							  dwc_otg_module_params.
++							  en_multiple_tx_fifo);
++	}
++	for (i = 0; i < 15; i++) {
++		if (dwc_otg_module_params.dev_perio_tx_fifo_size[i] != -1) {
++			retval +=
++			    dwc_otg_set_param_dev_perio_tx_fifo_size(core_if,
++								     dwc_otg_module_params.
++								     dev_perio_tx_fifo_size
++								     [i], i);
++		}
++	}
++
++	for (i = 0; i < 15; i++) {
++		if (dwc_otg_module_params.dev_tx_fifo_size[i] != -1) {
++			retval += dwc_otg_set_param_dev_tx_fifo_size(core_if,
++								     dwc_otg_module_params.
++								     dev_tx_fifo_size
++								     [i], i);
++		}
++	}
++	if (dwc_otg_module_params.thr_ctl != -1) {
++		retval +=
++		    dwc_otg_set_param_thr_ctl(core_if,
++					      dwc_otg_module_params.thr_ctl);
++	}
++	if (dwc_otg_module_params.mpi_enable != -1) {
++		retval +=
++		    dwc_otg_set_param_mpi_enable(core_if,
++						 dwc_otg_module_params.
++						 mpi_enable);
++	}
++	if (dwc_otg_module_params.pti_enable != -1) {
++		retval +=
++		    dwc_otg_set_param_pti_enable(core_if,
++						 dwc_otg_module_params.
++						 pti_enable);
++	}
++	if (dwc_otg_module_params.lpm_enable != -1) {
++		retval +=
++		    dwc_otg_set_param_lpm_enable(core_if,
++						 dwc_otg_module_params.
++						 lpm_enable);
++	}
++	if (dwc_otg_module_params.besl_enable != -1) {
++		retval +=
++		    dwc_otg_set_param_besl_enable(core_if,
++						 dwc_otg_module_params.
++						 besl_enable);
++	}
++	if (dwc_otg_module_params.baseline_besl != -1) {
++		retval +=
++		    dwc_otg_set_param_baseline_besl(core_if,
++						 dwc_otg_module_params.
++						 baseline_besl);
++	}
++	if (dwc_otg_module_params.deep_besl != -1) {
++		retval +=
++		    dwc_otg_set_param_deep_besl(core_if,
++						 dwc_otg_module_params.
++						 deep_besl);
++	}
++	if (dwc_otg_module_params.ic_usb_cap != -1) {
++		retval +=
++		    dwc_otg_set_param_ic_usb_cap(core_if,
++						 dwc_otg_module_params.
++						 ic_usb_cap);
++	}
++	if (dwc_otg_module_params.tx_thr_length != -1) {
++		retval +=
++		    dwc_otg_set_param_tx_thr_length(core_if,
++						    dwc_otg_module_params.tx_thr_length);
++	}
++	if (dwc_otg_module_params.rx_thr_length != -1) {
++		retval +=
++		    dwc_otg_set_param_rx_thr_length(core_if,
++						    dwc_otg_module_params.
++						    rx_thr_length);
++	}
++	if (dwc_otg_module_params.ahb_thr_ratio != -1) {
++		retval +=
++		    dwc_otg_set_param_ahb_thr_ratio(core_if,
++						    dwc_otg_module_params.ahb_thr_ratio);
++	}
++	if (dwc_otg_module_params.power_down != -1) {
++		retval +=
++		    dwc_otg_set_param_power_down(core_if,
++						 dwc_otg_module_params.power_down);
++	}
++	if (dwc_otg_module_params.reload_ctl != -1) {
++		retval +=
++		    dwc_otg_set_param_reload_ctl(core_if,
++						 dwc_otg_module_params.reload_ctl);
++	}
++
++	if (dwc_otg_module_params.dev_out_nak != -1) {
++		retval +=
++			dwc_otg_set_param_dev_out_nak(core_if,
++			dwc_otg_module_params.dev_out_nak);
++	}
++
++	if (dwc_otg_module_params.cont_on_bna != -1) {
++		retval +=
++			dwc_otg_set_param_cont_on_bna(core_if,
++			dwc_otg_module_params.cont_on_bna);
++	}
++
++	if (dwc_otg_module_params.ahb_single != -1) {
++		retval +=
++			dwc_otg_set_param_ahb_single(core_if,
++			dwc_otg_module_params.ahb_single);
++	}
++
++	if (dwc_otg_module_params.otg_ver != -1) {
++		retval +=
++		    dwc_otg_set_param_otg_ver(core_if,
++					      dwc_otg_module_params.otg_ver);
++	}
++	if (dwc_otg_module_params.adp_enable != -1) {
++		retval +=
++		    dwc_otg_set_param_adp_enable(core_if,
++						 dwc_otg_module_params.
++						 adp_enable);
++	}
++	return retval;
++}
++/******************************************************************************/
++
++/**
++ * This function is the top level interrupt handler for the Common
++ * (Device and host modes) interrupts.
++ */
++static irqreturn_t dwc_otg_common_irq(int irq, void *dev)
++{
++	int32_t retval = IRQ_NONE;
++
++	retval = dwc_otg_handle_common_intr(dev);
++
++	return IRQ_RETVAL(retval);
++}
++/******************************************************************************/
++
++static int  hisi_udc_remove( struct platform_device *_dev)
++{
++
++	dwc_otg_device_t *otg_dev = platform_get_drvdata(_dev);
++
++	DWC_DEBUGPL(DBG_ANY, "%s(%p)\n", __func__, _dev);
++
++	if (!otg_dev) {
++		/* Memory allocation for the dwc_otg_device failed. */
++		DWC_DEBUGPL(DBG_ANY, "%s: otg_dev NULL!\n", __func__);
++		return -1;
++	}
++
++	if (otg_dev->pcd) {
++		pcd_remove(_dev);
++	} else {
++		DWC_DEBUGPL(DBG_ANY, "%s: otg_dev->pcd NULL!\n", __func__);
++		return -1;
++	}
++
++	/*
++	 * Free the IRQ
++	 */
++	if (otg_dev->common_irq_installed) {
++		free_irq(_dev->resource[1].start, otg_dev);
++	} else {
++		DWC_DEBUGPL(DBG_ANY, "%s: There is no installed irq!\n", __func__);
++		return -1;
++	}
++
++	if (otg_dev->core_if) {
++		dwc_otg_cil_remove(otg_dev->core_if);
++	} else {
++		DWC_DEBUGPL(DBG_ANY, "%s: otg_dev->core_if NULL!\n", __func__);
++		return -1;
++	}
++
++	/*
++	 * Return the memory.
++	 */
++	if (otg_dev->os_dep.base) {
++		iounmap(otg_dev->os_dep.base);
++	}
++
++	clk_disable_unprepare(otg_dev->clk);
++	DWC_FREE(otg_dev);
++	/*
++	 * Clear the drvdata pointer.
++	 */
++	platform_set_drvdata(_dev, NULL);
++
++	return 0;
++
++}
++/******************************************************************************/
++
++static int hisi_udc_probe(struct platform_device *pdev)
++{
++	struct resource *res;
++	dwc_otg_device_t *dwc_otg_device;
++	int irq;
++	int ret;
++
++	irq = platform_get_irq(pdev, 0);
++	if (irq < 0) {
++		dev_err(&pdev->dev, "no irq provided");
++		return irq;
++	}
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	if (!res) {
++		dev_err(&pdev->dev, "no memory resource provided");
++		return -ENXIO;
++	}
++
++	dwc_otg_device = DWC_ALLOC(sizeof(dwc_otg_device_t));
++
++	if (!dwc_otg_device) {
++		dev_err(&pdev->dev, "kmalloc of dwc_otg_device failed\n");
++		return -ENOMEM;
++	}
++
++	memset(dwc_otg_device, 0, sizeof(*dwc_otg_device));
++	dwc_otg_device->os_dep.reg_offset = 0xFFFFFFFF;
++
++	/*
++	 * Map the DWC_otg Core memory into virtual address space.
++	 */
++	dwc_otg_device->os_dep.res_start = res->start;
++	dwc_otg_device->os_dep.base = devm_ioremap_resource(&pdev->dev, res);
++	if (IS_ERR(dwc_otg_device->os_dep.base)) {
++		DWC_FREE(dwc_otg_device);
++		return -ENOMEM;
++	}
++
++	dev_dbg(&pdev->dev, "base=0x%08x\n",(unsigned)dwc_otg_device->os_dep.base);
++
++
++	dwc_otg_device->clk = devm_clk_get(&pdev->dev, "clk");
++	if (IS_ERR_OR_NULL(dwc_otg_device->clk)) {
++		dev_err(&pdev->dev, "get clock fail.\n");
++		ret = PTR_ERR(dwc_otg_device->clk);
++		DWC_FREE(dwc_otg_device);
++		return ret;
++	}
++	clk_prepare_enable(dwc_otg_device->clk);
++
++	/*
++	 * Initialize driver data to point to the global DWC_otg
++	 * Device structure.
++	 */
++	platform_set_drvdata(pdev, dwc_otg_device);
++
++
++	dwc_otg_device->core_if = dwc_otg_cil_init(dwc_otg_device->os_dep.base);
++	if (!dwc_otg_device->core_if) {
++		dev_err(&pdev->dev, "CIL initialization failed!\n");
++		ret = -ENOMEM;
++		goto fail;
++
++	}
++
++	/*
++	 * Attempt to ensure this device is really a DWC_otg Controller.
++	 * Read and verify the SNPSID register contents. The value should be
++	 * 0x45F42XXX or 0x45F42XXX, which corresponds to either "OT2" or "OTG3",
++	 * as in "OTG version 2.XX" or "OTG version 3.XX".
++	 */
++
++	if (((dwc_otg_get_gsnpsid(dwc_otg_device->core_if) & 0xFFFFF000) !=	0x4F542000) &&
++		((dwc_otg_get_gsnpsid(dwc_otg_device->core_if) & 0xFFFFF000) != 0x4F543000)) {
++		dev_err(&pdev->dev, "Bad value for SNPSID: 0x%08x\n",
++			dwc_otg_get_gsnpsid(dwc_otg_device->core_if));
++		ret = -EINVAL;
++		goto fail;
++	}
++
++	/*
++	 * Validate parameter values.
++	 */
++	if (set_parameters(dwc_otg_device->core_if)) {
++		ret = -EINVAL;
++		goto fail;
++	}
++
++
++	/*
++	 * Disable the global interrupt until all the interrupt
++	 * handlers are installed.
++	 */
++	dwc_otg_disable_global_interrupts(dwc_otg_device->core_if);
++
++
++	/*
++	 * Install the interrupt handler for the common interrupts before
++	 * enabling common interrupts in core_init below.
++	 */
++	DWC_DEBUGPL(DBG_CIL, "registering (common) handler for irq%d\n",
++		    pdev->resource[1].start);
++	ret = request_irq(irq, dwc_otg_common_irq,
++			     IRQF_SHARED | IRQF_DISABLED | IRQ_LEVEL, "dwc_otg",
++			     dwc_otg_device);
++	if (ret) {
++		dev_err(&pdev->dev,"request of irq%d failed\n",irq);
++		ret = -EBUSY;
++		goto fail;
++	} else {
++		dwc_otg_device->common_irq_installed = 1;
++	}
++
++
++	/*
++	 * Initialize the DWC_otg core.
++	 */
++	dwc_otg_core_init(dwc_otg_device->core_if);
++
++	/*
++	 * Initialize the PCD
++	 */
++	ret = pcd_init(pdev, irq);
++	if (ret != 0) {
++		dev_err(&pdev->dev,"pcd_init failed\n");
++		dwc_otg_device->pcd = NULL;
++		goto fail;
++	}
++
++
++	/*
++	 * Enable the global interrupt after all the interrupt
++	 * handlers are installed if there is no ADP support else
++	 * perform initial actions required for Internal ADP logic.
++	 */
++	if (!dwc_otg_get_param_adp_enable(dwc_otg_device->core_if))
++		dwc_otg_enable_global_interrupts(dwc_otg_device->core_if);
++	else
++		dwc_otg_adp_start(dwc_otg_device->core_if,
++							dwc_otg_is_host_mode(dwc_otg_device->core_if));
++
++	return 0;
++
++fail:
++	hisi_udc_remove(pdev);
++	return ret;
++}
++/******************************************************************************/
++
++#ifdef CONFIG_PM
++static int hisi_udc_suspend(struct device *dev)
++{
++	dwc_otg_device_t *dwc_otg_device = dev_get_drvdata(dev);
++	int rc = 0;
++
++	dwc_otg_disable_global_interrupts(dwc_otg_device->core_if);
++	clk_disable_unprepare(dwc_otg_device->clk);
++
++	return rc;
++}
++/******************************************************************************/
++
++static int hisi_udc_resume(struct device *dev)
++{
++	dwc_otg_device_t *dwc_otg_device = dev_get_drvdata(dev);
++
++	clk_prepare_enable(dwc_otg_device->clk);
++	dwc_otg_core_init(dwc_otg_device->core_if);
++	dwc_otg_enable_global_interrupts(dwc_otg_device->core_if);
++	return 0;
++}
++#else
++#define hisi_udc_suspend NULL;
++#define hisi_udc_resume NULL;
++#endif
++/******************************************************************************/
++
++static const struct dev_pm_ops hisi_udc_pmops = {
++	.suspend = hisi_udc_suspend,
++	.resume  = hisi_udc_resume,
++#if defined(CONFIG_PM_HIBERNATE) || defined(CONFIG_HISI_SNAPSHOT_BOOT)
++	.freeze = hisi_udc_suspend,
++	.thaw = hisi_udc_resume,
++	.poweroff = hisi_udc_suspend,
++	.restore = hisi_udc_resume,
++#endif
++};
++
++static const struct of_device_id hisi_udc_ids[] = {
++	{ .compatible = "hiudc", },
++	{ /* null */ }
++};
++MODULE_DEVICE_TABLE(of, hisi_udc_ids);
++
++static struct platform_driver  hisi_udc_pltfrm_driver = {
++	.probe = hisi_udc_probe,
++	.remove = hisi_udc_remove,
++	.driver = {
++		.name  = (char *)driver_name,
++		.owner = THIS_MODULE,
++		.of_match_table = hisi_udc_ids,
++		.pm    = &hisi_udc_pmops,
++	},
++};
++/******************************************************************************/
++
++static int __init hisi_udc_module_init(void)
++{
++	int ret;
++
++	printk(KERN_INFO "%s: version %s\n", driver_name,
++	       DWC_DRIVER_VERSION);
++
++	ret = platform_driver_register(&hisi_udc_pltfrm_driver);
++
++	return ret;
++}
++module_init(hisi_udc_module_init);
++/******************************************************************************/
++
++static void __exit hisi_udc_module_exit (void)
++{
++
++	platform_driver_unregister(&hisi_udc_pltfrm_driver);
++
++	printk(KERN_INFO "%s module removed\n", driver_name);
++}
++module_exit(hisi_udc_module_exit);
++
++MODULE_AUTHOR("Hisilicon");
++MODULE_DESCRIPTION("Hisilcon USB Device Controller driver");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/usb/gadget/udc/hiudc/dwc_otg_driver.h b/drivers/usb/gadget/udc/hiudc/dwc_otg_driver.h
+new file mode 100644
+index 0000000..63df919
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc/dwc_otg_driver.h
+@@ -0,0 +1,89 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_driver.h $
++ * $Revision: #19 $
++ * $Date: 2010/11/15 $
++ * $Change: 1627671 $
++ *
++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
++ * ========================================================================== */
++
++#ifndef __DWC_OTG_DRIVER_H__
++#define __DWC_OTG_DRIVER_H__
++
++/** @file
++ * This file contains the interface to the Linux driver.
++ */
++#include "dwc_otg_os_dep.h"
++#include "dwc_otg_core_if.h"
++#include <linux/platform_device.h>
++
++/* Type declarations */
++struct dwc_otg_pcd;
++struct dwc_otg_hcd;
++
++/**
++ * This structure is a wrapper that encapsulates the driver components used to
++ * manage a single DWC_otg controller.
++ */
++typedef struct dwc_otg_device {
++	/** Structure containing OS-dependent stuff. KEEP THIS STRUCT AT THE
++	 * VERY BEGINNING OF THE DEVICE STRUCT. OSes such as FreeBSD and NetBSD
++	 * require this. */
++	struct os_dependent os_dep;
++
++	/** Pointer to the core interface structure. */
++	dwc_otg_core_if_t *core_if;
++
++	/** Pointer to the PCD structure. */
++	struct dwc_otg_pcd *pcd;
++
++	/** Pointer to the HCD structure. */
++	struct dwc_otg_hcd *hcd;
++
++	struct clk *clk;
++
++	/** Flag to indicate whether the common IRQ handler is installed. */
++	uint8_t common_irq_installed;
++
++} dwc_otg_device_t;
++
++/*We must clear S3C24XX_EINTPEND external interrupt register
++ * because after clearing in this register trigerred IRQ from
++ * H/W core in kernel interrupt can be occured again before OTG
++ * handlers clear all IRQ sources of Core registers because of
++ * timing latencies and Low Level IRQ Type.
++ */
++#ifdef CONFIG_MACH_IPMATE
++#define  S3C2410X_CLEAR_EINTPEND()   \
++do { \
++	__raw_writel(1UL << 11,S3C24XX_EINTPEND); \
++} while (0)
++#else
++#define  S3C2410X_CLEAR_EINTPEND()   do { } while (0)
++#endif
++
++#endif
+diff --git a/drivers/usb/gadget/udc/hiudc/dwc_otg_hcd.c b/drivers/usb/gadget/udc/hiudc/dwc_otg_hcd.c
+new file mode 100644
+index 0000000..baebe82
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc/dwc_otg_hcd.c
+@@ -0,0 +1,3431 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd.c $
++ * $Revision: #110 $
++ * $Date: 2013/05/19 $
++ * $Change: 2234022 $
++ *
++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
++ * ========================================================================== */
++#ifndef DWC_DEVICE_ONLY
++
++/** @file
++ * This file implements HCD Core. All code in this file is portable and doesn't
++ * use any OS specific functions.
++ * Interface provided by HCD Core is defined in <code><hcd_if.h></code>
++ * header file.
++ */
++
++#include "dwc_otg_hcd.h"
++#include "dwc_otg_regs.h"
++
++dwc_otg_hcd_t *dwc_otg_hcd_alloc_hcd(void)
++{
++	return DWC_ALLOC(sizeof(dwc_otg_hcd_t));
++}
++
++/**
++ * Connection timeout function.  An OTG host is required to display a
++ * message if the device does not connect within 10 seconds.
++ */
++void dwc_otg_hcd_connect_timeout(void *ptr)
++{
++	dwc_otg_hcd_t *hcd;
++	gpwrdn_data_t gpwrdn;
++	DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, ptr);
++	DWC_PRINTF("Connect Timeout\n");
++	__DWC_ERROR("Device Not Connected/Responding\n");
++	/** Remove buspower after 10s */
++	hcd = ptr;
++	if (hcd->core_if->otg_ver)
++		dwc_otg_set_prtpower(hcd->core_if, 0);
++	if (hcd->core_if->adp_enable && !hcd->core_if->adp.probe_enabled) {
++		cil_hcd_disconnect(hcd->core_if);
++		gpwrdn.d32 = 0;
++		/* Enable Power Down Logic */
++		gpwrdn.b.pmuintsel = 1;
++		gpwrdn.b.pmuactv = 1;
++		gpwrdn.b.dis_vbus = 1;
++		DWC_MODIFY_REG32(&hcd->core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
++
++		/* Unmask SRP detected interrupt from Power Down Logic */
++		gpwrdn.d32 = 0;
++		gpwrdn.b.srp_det_msk = 1;
++		DWC_MODIFY_REG32(&hcd->core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
++
++		dwc_mdelay(220);
++		dwc_otg_adp_probe_start(hcd->core_if);
++	}
++}
++
++#ifdef DEBUG
++static void dump_channel_info(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
++{
++	if (qh->channel != NULL) {
++		dwc_hc_t *hc = qh->channel;
++		dwc_list_link_t *item;
++		dwc_otg_qh_t *qh_item;
++		int num_channels = hcd->core_if->core_params->host_channels;
++		int i;
++
++		dwc_otg_hc_regs_t *hc_regs;
++		hcchar_data_t hcchar;
++		hcsplt_data_t hcsplt;
++		hctsiz_data_t hctsiz;
++		uint32_t hcdma;
++
++		hc_regs = hcd->core_if->host_if->hc_regs[hc->hc_num];
++		hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
++		hcsplt.d32 = DWC_READ_REG32(&hc_regs->hcsplt);
++		hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
++		hcdma = DWC_READ_REG32(&hc_regs->hcdma);
++
++		DWC_PRINTF("  Assigned to channel %p:\n", hc);
++		DWC_PRINTF("    hcchar 0x%08x, hcsplt 0x%08x\n", hcchar.d32,
++			   hcsplt.d32);
++		DWC_PRINTF("    hctsiz 0x%08x, hcdma 0x%08x\n", hctsiz.d32,
++			   hcdma);
++		DWC_PRINTF("    dev_addr: %d, ep_num: %d, ep_is_in: %d\n",
++			   hc->dev_addr, hc->ep_num, hc->ep_is_in);
++		DWC_PRINTF("    ep_type: %d\n", hc->ep_type);
++		DWC_PRINTF("    max_packet: %d\n", hc->max_packet);
++		DWC_PRINTF("    data_pid_start: %d\n", hc->data_pid_start);
++		DWC_PRINTF("    xfer_started: %d\n", hc->xfer_started);
++		DWC_PRINTF("    halt_status: %d\n", hc->halt_status);
++		DWC_PRINTF("    xfer_buff: %p\n", hc->xfer_buff);
++		DWC_PRINTF("    xfer_len: %d\n", hc->xfer_len);
++		DWC_PRINTF("    qh: %p\n", hc->qh);
++		DWC_PRINTF("  NP inactive sched:\n");
++		DWC_LIST_FOREACH(item, &hcd->non_periodic_sched_inactive) {
++			qh_item =
++			    DWC_LIST_ENTRY(item, dwc_otg_qh_t, qh_list_entry);
++			DWC_PRINTF("    %p\n", qh_item);
++		}
++		DWC_PRINTF("  NP active sched:\n");
++		DWC_LIST_FOREACH(item, &hcd->non_periodic_sched_active) {
++			qh_item =
++			    DWC_LIST_ENTRY(item, dwc_otg_qh_t, qh_list_entry);
++			DWC_PRINTF("    %p\n", qh_item);
++		}
++		DWC_PRINTF("  Channels: \n");
++		for (i = 0; i < num_channels; i++) {
++			dwc_hc_t *hc = hcd->hc_ptr_array[i];
++			DWC_PRINTF("    %2d: %p\n", i, hc);
++		}
++	}
++}
++#endif /* DEBUG */
++
++/**
++ * Work queue function for starting the HCD when A-Cable is connected.
++ * The hcd_start() must be called in a process context.
++ */
++static void hcd_start_func(void *_vp)
++{
++	dwc_otg_hcd_t *hcd = (dwc_otg_hcd_t *) _vp;
++
++	DWC_DEBUGPL(DBG_HCDV, "%s() %p\n", __func__, hcd);
++	if (hcd) {
++		hcd->fops->start(hcd);
++	}
++}
++
++static void del_xfer_timers(dwc_otg_hcd_t * hcd)
++{
++#ifdef DEBUG
++	int i;
++	int num_channels = hcd->core_if->core_params->host_channels;
++	for (i = 0; i < num_channels; i++) {
++		DWC_TIMER_CANCEL(hcd->core_if->hc_xfer_timer[i]);
++	}
++#endif
++}
++
++static void del_timers(dwc_otg_hcd_t * hcd)
++{
++	del_xfer_timers(hcd);
++	DWC_TIMER_CANCEL(hcd->conn_timer);
++}
++
++/**
++ * Processes all the URBs in a single list of QHs. Completes them with
++ * -ETIMEDOUT and frees the QTD.
++ */
++static void kill_urbs_in_qh_list(dwc_otg_hcd_t * hcd, dwc_list_link_t * qh_list)
++{
++	dwc_list_link_t *qh_item;
++	dwc_otg_qh_t *qh;
++	dwc_otg_qtd_t *qtd, *qtd_tmp;
++
++	DWC_LIST_FOREACH(qh_item, qh_list) {
++		qh = DWC_LIST_ENTRY(qh_item, dwc_otg_qh_t, qh_list_entry);
++		DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp,
++					 &qh->qtd_list, qtd_list_entry) {
++			qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list);
++			if (qtd->urb != NULL) {
++				if(!qtd->urb->priv) {
++					DWC_ERROR("urb->priv is NULL !!!!\n");
++					return;
++				}
++				if(!hcd->fops)
++					DWC_ERROR("hcd->fops is NULL !!!!!\n");
++				if(!hcd->fops->complete)
++					DWC_ERROR("fops->complete is NULL !!!!\n");
++				hcd->fops->complete(hcd, qtd->urb->priv,
++						    qtd->urb, -DWC_E_TIMEOUT);
++				dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
++			}
++
++		}
++	}
++}
++
++/**
++ * Responds with an error status of ETIMEDOUT to all URBs in the non-periodic
++ * and periodic schedules. The QTD associated with each URB is removed from
++ * the schedule and freed. This function may be called when a disconnect is
++ * detected or when the HCD is being stopped.
++ */
++static void kill_all_urbs(dwc_otg_hcd_t * hcd)
++{
++	kill_urbs_in_qh_list(hcd, &hcd->non_periodic_sched_inactive);
++	kill_urbs_in_qh_list(hcd, &hcd->non_periodic_sched_active);
++	kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_inactive);
++	kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_ready);
++	kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_assigned);
++	kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_queued);
++}
++
++/**
++ * Start the connection timer.  An OTG host is required to display a
++ * message if the device does not connect within 10 seconds.  The
++ * timer is deleted if a port connect interrupt occurs before the
++ * timer expires.
++ */
++static void dwc_otg_hcd_start_connect_timer(dwc_otg_hcd_t * hcd)
++{
++	DWC_TIMER_SCHEDULE(hcd->conn_timer, 10000 /* 10 secs */ );
++}
++
++/**
++ * HCD Callback function for disconnect of the HCD.
++ *
++ * @param p void pointer to the <code>struct usb_hcd</code>
++ */
++static int32_t dwc_otg_hcd_session_start_cb(void *p)
++{
++	dwc_otg_hcd_t *dwc_otg_hcd;
++	DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, p);
++	dwc_otg_hcd = p;
++	dwc_otg_hcd_start_connect_timer(dwc_otg_hcd);
++	return 1;
++}
++
++/**
++ * HCD Callback function for starting the HCD when A-Cable is
++ * connected.
++ *
++ * @param p void pointer to the <code>struct usb_hcd</code>
++ */
++static int32_t dwc_otg_hcd_start_cb(void *p)
++{
++	dwc_otg_hcd_t *dwc_otg_hcd = p;
++	dwc_otg_core_if_t *core_if;
++	hprt0_data_t hprt0;
++	uint32_t timeout = 50;
++
++	core_if = dwc_otg_hcd->core_if;
++	/**@todo vahrama: Check the timeout value for OTG 2.0 */
++	if (core_if->otg_ver)
++		timeout = 25;
++	if (core_if->op_state == B_HOST) {
++		/*
++		 * Reset the port.  During a HNP mode switch the reset
++		 * needs to occur within 1ms and have a duration of at
++		 * least 50ms.
++		 */
++		hprt0.d32 = dwc_otg_read_hprt0(core_if);
++		hprt0.b.prtrst = 1;
++		DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
++		if (core_if->otg_ver) {
++			dwc_mdelay(60);
++			hprt0.d32 = dwc_otg_read_hprt0(core_if);
++			hprt0.b.prtrst = 0;
++			DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
++		}
++	}
++	DWC_WORKQ_SCHEDULE_DELAYED(core_if->wq_otg,
++				hcd_start_func, dwc_otg_hcd, timeout,
++				"start hcd");
++
++	return 1;
++}
++
++/**
++ * HCD Callback function for disconnect of the HCD.
++ *
++ * @param p void pointer to the <code>struct usb_hcd</code>
++ */
++static int32_t dwc_otg_hcd_disconnect_cb(void *p)
++{
++	gintsts_data_t intr;
++	dwc_otg_hcd_t *dwc_otg_hcd = p;
++
++	/*
++	 * Set status flags for the hub driver.
++	 */
++	dwc_otg_hcd->flags.b.port_connect_status_change = 1;
++	dwc_otg_hcd->flags.b.port_connect_status = 0;
++
++	/*
++	 * Shutdown any transfers in process by clearing the Tx FIFO Empty
++	 * interrupt mask and status bits and disabling subsequent host
++	 * channel interrupts.
++	 */
++	intr.d32 = 0;
++	intr.b.nptxfempty = 1;
++	intr.b.ptxfempty = 1;
++	intr.b.hcintr = 1;
++	DWC_MODIFY_REG32(&dwc_otg_hcd->core_if->core_global_regs->gintmsk,
++			 intr.d32, 0);
++	DWC_MODIFY_REG32(&dwc_otg_hcd->core_if->core_global_regs->gintsts,
++			 intr.d32, 0);
++
++	/*
++	 * Turn off the vbus power only if the core has transitioned to device
++	 * mode. If still in host mode, need to keep power on to detect a
++	 * reconnection.
++	 */
++	if (dwc_otg_is_device_mode(dwc_otg_hcd->core_if)) {
++		if (dwc_otg_hcd->core_if->op_state != A_SUSPEND) {
++			hprt0_data_t hprt0 = {.d32 = 0 };
++			DWC_PRINTF("Disconnect: PortPower off\n");
++			hprt0.b.prtpwr = 0;
++			DWC_WRITE_REG32(dwc_otg_hcd->core_if->host_if->hprt0,
++					hprt0.d32);
++		}
++		/** Delete timers if become device */
++		del_timers(dwc_otg_hcd);
++		dwc_otg_disable_host_interrupts(dwc_otg_hcd->core_if);
++	}
++
++	/* Respond with an error status to all URBs in the schedule. */
++	kill_all_urbs(dwc_otg_hcd);
++
++	if (dwc_otg_is_host_mode(dwc_otg_hcd->core_if)) {
++		/* Clean up any host channels that were in use. */
++		int num_channels;
++		int i;
++		dwc_hc_t *channel;
++		dwc_otg_hc_regs_t *hc_regs;
++		hcchar_data_t hcchar;
++
++		if (dwc_otg_hcd->core_if->otg_ver == 1)
++			del_xfer_timers(dwc_otg_hcd);
++		else
++			del_timers(dwc_otg_hcd);
++
++		num_channels = dwc_otg_hcd->core_if->core_params->host_channels;
++
++		if (!dwc_otg_hcd->core_if->dma_enable) {
++			/* Flush out any channel requests in slave mode. */
++			for (i = 0; i < num_channels; i++) {
++				channel = dwc_otg_hcd->hc_ptr_array[i];
++				if (DWC_CIRCLEQ_EMPTY_ENTRY
++				    (channel, hc_list_entry)) {
++					hc_regs =
++					    dwc_otg_hcd->core_if->
++					    host_if->hc_regs[i];
++					hcchar.d32 =
++					    DWC_READ_REG32(&hc_regs->hcchar);
++					if (hcchar.b.chen) {
++						hcchar.b.chen = 0;
++						hcchar.b.chdis = 1;
++						hcchar.b.epdir = 0;
++						DWC_WRITE_REG32
++						    (&hc_regs->hcchar,
++						     hcchar.d32);
++					}
++				}
++			}
++		}
++
++		for (i = 0; i < num_channels; i++) {
++			channel = dwc_otg_hcd->hc_ptr_array[i];
++			if (DWC_CIRCLEQ_EMPTY_ENTRY(channel, hc_list_entry)) {
++				hc_regs =
++				    dwc_otg_hcd->core_if->host_if->hc_regs[i];
++				hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
++				if (hcchar.b.chen) {
++					/* Halt the channel. */
++					hcchar.b.chdis = 1;
++					DWC_WRITE_REG32(&hc_regs->hcchar,
++							hcchar.d32);
++				}
++
++				dwc_otg_hc_cleanup(dwc_otg_hcd->core_if,
++						   channel);
++				DWC_CIRCLEQ_INSERT_TAIL
++				    (&dwc_otg_hcd->free_hc_list, channel,
++				     hc_list_entry);
++				/*
++				 * Added for Descriptor DMA to prevent channel double cleanup
++				 * in release_channel_ddma(). Which called from ep_disable
++				 * when device disconnect.
++				 */
++				channel->qh = NULL;
++			}
++		}
++	}
++
++	if (dwc_otg_hcd->fops->disconnect) {
++		dwc_otg_hcd->fops->disconnect(dwc_otg_hcd);
++	}
++
++	return 1;
++}
++
++/**
++ * HCD Callback function for stopping the HCD.
++ *
++ * @param p void pointer to the <code>struct usb_hcd</code>
++ */
++static int32_t dwc_otg_hcd_stop_cb(void *p)
++{
++	dwc_otg_hcd_t *dwc_otg_hcd = p;
++
++	DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, p);
++	dwc_otg_hcd_stop(dwc_otg_hcd);
++	return 1;
++}
++
++#ifdef CONFIG_USB_DWC_OTG_LPM
++/**
++ * HCD Callback function for sleep of HCD.
++ *
++ * @param p void pointer to the <code>struct usb_hcd</code>
++ */
++static int dwc_otg_hcd_sleep_cb(void *p)
++{
++	dwc_otg_hcd_t *hcd = p;
++
++	dwc_otg_hcd_free_hc_from_lpm(hcd);
++
++	return 0;
++}
++#endif
++
++/**
++ * HCD Callback function for Remote Wakeup.
++ *
++ * @param p void pointer to the <code>struct usb_hcd</code>
++ */
++static int dwc_otg_hcd_rem_wakeup_cb(void *p)
++{
++	dwc_otg_hcd_t *hcd = p;
++
++	if (hcd->core_if->lx_state == DWC_OTG_L2) {
++		hcd->flags.b.port_suspend_change = 1;
++	}
++#ifdef CONFIG_USB_DWC_OTG_LPM
++	else {
++		hcd->flags.b.port_l1_change = 1;
++	}
++#endif
++	return 0;
++}
++
++/**
++ * Halts the DWC_otg host mode operations in a clean manner. USB transfers are
++ * stopped.
++ */
++void dwc_otg_hcd_stop(dwc_otg_hcd_t * hcd)
++{
++	hprt0_data_t hprt0 = {.d32 = 0 };
++
++	DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD STOP\n");
++
++	/*
++	 * The root hub should be disconnected before this function is called.
++	 * The disconnect will clear the QTD lists (via ..._hcd_urb_dequeue)
++	 * and the QH lists (via ..._hcd_endpoint_disable).
++	 */
++
++	/* Turn off all host-specific interrupts. */
++	dwc_otg_disable_host_interrupts(hcd->core_if);
++
++	/* Turn off the vbus power */
++	DWC_PRINTF("PortPower off\n");
++	hprt0.b.prtpwr = 0;
++	DWC_WRITE_REG32(hcd->core_if->host_if->hprt0, hprt0.d32);
++	dwc_mdelay(1);
++}
++
++int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * hcd,
++			    dwc_otg_hcd_urb_t * dwc_otg_urb, void **ep_handle,
++			    int atomic_alloc)
++{
++	dwc_irqflags_t flags;
++	int retval = 0;
++	dwc_otg_qtd_t *qtd;
++	gintmsk_data_t intr_mask = {.d32 = 0 };
++
++	if (!hcd->flags.b.port_connect_status) {
++		/* No longer connected. */
++		DWC_ERROR("Not connected\n");
++		return -DWC_E_NO_DEVICE;
++	}
++
++	qtd = dwc_otg_hcd_qtd_create(dwc_otg_urb, atomic_alloc);
++	if (qtd == NULL) {
++		DWC_ERROR("DWC OTG HCD URB Enqueue failed creating QTD\n");
++		return -DWC_E_NO_MEMORY;
++	}
++
++	retval =
++	    dwc_otg_hcd_qtd_add(qtd, hcd, (dwc_otg_qh_t **) ep_handle, atomic_alloc);
++	if (retval < 0) {
++		DWC_ERROR("DWC OTG HCD URB Enqueue failed adding QTD. "
++			  "Error status %d\n", retval);
++		dwc_otg_hcd_qtd_free(qtd);
++	} else {
++		qtd->qh = *ep_handle;
++	}
++	intr_mask.d32 = DWC_READ_REG32(&hcd->core_if->core_global_regs->gintmsk);
++	if (!intr_mask.b.sofintr && retval == 0) {
++		dwc_otg_transaction_type_e tr_type;
++		if ((qtd->qh->ep_type == UE_BULK)
++		    && !(qtd->urb->flags & URB_GIVEBACK_ASAP)) {
++			/* Do not schedule SG transactions until qtd has URB_GIVEBACK_ASAP set */
++			return 0;
++		}
++		DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
++		tr_type = dwc_otg_hcd_select_transactions(hcd);
++		if (tr_type != DWC_OTG_TRANSACTION_NONE) {
++			dwc_otg_hcd_queue_transactions(hcd, tr_type);
++		}
++		DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
++	}
++
++	return retval;
++}
++
++int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_t * hcd,
++			    dwc_otg_hcd_urb_t * dwc_otg_urb)
++{
++	dwc_otg_qh_t *qh;
++	dwc_otg_qtd_t *urb_qtd;
++
++	urb_qtd = dwc_otg_urb->qtd;
++	qh = urb_qtd->qh;
++#ifdef DEBUG
++	if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
++		if (urb_qtd->in_process) {
++			dump_channel_info(hcd, qh);
++		}
++	}
++#endif
++	if (urb_qtd->in_process && qh->channel) {
++		/* The QTD is in process (it has been assigned to a channel). */
++		if (hcd->flags.b.port_connect_status) {
++			/*
++			 * If still connected (i.e. in host mode), halt the
++			 * channel so it can be used for other transfers. If
++			 * no longer connected, the host registers can't be
++			 * written to halt the channel since the core is in
++			 * device mode.
++			 */
++			dwc_otg_hc_halt(hcd->core_if, qh->channel,
++					DWC_OTG_HC_XFER_URB_DEQUEUE);
++		}
++	}
++
++	/*
++	 * Free the QTD and clean up the associated QH. Leave the QH in the
++	 * schedule if it has any remaining QTDs.
++	 */
++
++	if (!hcd->core_if->dma_desc_enable) {
++		uint8_t b = urb_qtd->in_process;
++		dwc_otg_hcd_qtd_remove_and_free(hcd, urb_qtd, qh);
++		if (b) {
++			dwc_otg_hcd_qh_deactivate(hcd, qh, 0);
++			qh->channel = NULL;
++		} else if (DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
++			dwc_otg_hcd_qh_remove(hcd, qh);
++		}
++	} else {
++		dwc_otg_hcd_qtd_remove_and_free(hcd, urb_qtd, qh);
++	}
++	return 0;
++}
++
++int dwc_otg_hcd_endpoint_disable(dwc_otg_hcd_t * hcd, void *ep_handle,
++				 int retry)
++{
++	dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
++	int retval = 0;
++	dwc_irqflags_t flags;
++
++	if (retry < 0) {
++		retval = -DWC_E_INVALID;
++		goto done;
++	}
++
++	if (!qh) {
++		retval = -DWC_E_INVALID;
++		goto done;
++	}
++
++	DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
++
++	while (!DWC_CIRCLEQ_EMPTY(&qh->qtd_list) && retry) {
++		DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
++		retry--;
++		dwc_msleep(5);
++		DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
++	}
++
++	dwc_otg_hcd_qh_remove(hcd, qh);
++
++	DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
++	/*
++	 * Split dwc_otg_hcd_qh_remove_and_free() into qh_remove
++	 * and qh_free to prevent stack dump on DWC_DMA_FREE() with
++	 * irq_disabled (spinlock_irqsave) in dwc_otg_hcd_desc_list_free()
++	 * and dwc_otg_hcd_frame_list_alloc().
++	 */
++	dwc_otg_hcd_qh_free(hcd, qh);
++
++done:
++	return retval;
++}
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
++int dwc_otg_hcd_endpoint_reset(dwc_otg_hcd_t * hcd, void *ep_handle)
++{
++	int retval = 0;
++	dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
++	if (!qh)
++		return -DWC_E_INVALID;
++
++	qh->data_toggle = DWC_OTG_HC_PID_DATA0;
++	return retval;
++}
++#endif
++
++/**
++ * HCD Callback structure for handling mode switching.
++ */
++static dwc_otg_cil_callbacks_t hcd_cil_callbacks = {
++	.start = dwc_otg_hcd_start_cb,
++	.stop = dwc_otg_hcd_stop_cb,
++	.disconnect = dwc_otg_hcd_disconnect_cb,
++	.session_start = dwc_otg_hcd_session_start_cb,
++	.resume_wakeup = dwc_otg_hcd_rem_wakeup_cb,
++#ifdef CONFIG_USB_DWC_OTG_LPM
++	.sleep = dwc_otg_hcd_sleep_cb,
++#endif
++	.p = 0,
++};
++
++/**
++ * Reset tasklet function
++ */
++static void reset_tasklet_func(void *data)
++{
++	dwc_otg_hcd_t *dwc_otg_hcd = (dwc_otg_hcd_t *) data;
++	dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if;
++	hprt0_data_t hprt0;
++
++	DWC_DEBUGPL(DBG_HCDV, "USB RESET tasklet called\n");
++
++	hprt0.d32 = dwc_otg_read_hprt0(core_if);
++	hprt0.b.prtrst = 1;
++	DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
++	dwc_mdelay(60);
++
++	hprt0.b.prtrst = 0;
++	DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
++	dwc_otg_hcd->flags.b.port_reset_change = 1;
++}
++
++static void qh_list_free(dwc_otg_hcd_t * hcd, dwc_list_link_t * qh_list)
++{
++	dwc_list_link_t *item;
++	dwc_otg_qh_t *qh;
++	dwc_irqflags_t flags;
++
++	if (!qh_list->next) {
++		/* The list hasn't been initialized yet. */
++		return;
++	}
++	/*
++	 * Hold spinlock here. Not needed in that case if bellow
++	 * function is being called from ISR
++	 */
++	DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
++	/* Ensure there are no QTDs or URBs left. */
++	kill_urbs_in_qh_list(hcd, qh_list);
++	DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
++
++	DWC_LIST_FOREACH(item, qh_list) {
++		qh = DWC_LIST_ENTRY(item, dwc_otg_qh_t, qh_list_entry);
++		dwc_otg_hcd_qh_remove_and_free(hcd, qh);
++	}
++}
++
++/**
++ * Exit from Hibernation if Host did not detect SRP from connected SRP capable
++ * Device during SRP time by host power up.
++ */
++void dwc_otg_hcd_power_up(void *ptr)
++{
++	gpwrdn_data_t gpwrdn = {.d32 = 0 };
++	dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) ptr;
++
++	DWC_PRINTF("%s called\n", __FUNCTION__);
++
++	if (!core_if->hibernation_suspend) {
++		DWC_PRINTF("Already exited from Hibernation\n");
++		return;
++	}
++
++	/* Switch on the voltage to the core */
++	gpwrdn.b.pwrdnswtch = 1;
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++	dwc_udelay(10);
++
++	/* Reset the core */
++	gpwrdn.d32 = 0;
++	gpwrdn.b.pwrdnrstn = 1;
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++	dwc_udelay(10);
++
++	/* Disable power clamps */
++	gpwrdn.d32 = 0;
++	gpwrdn.b.pwrdnclmp = 1;
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++
++	/* Remove reset the core signal */
++	gpwrdn.d32 = 0;
++	gpwrdn.b.pwrdnrstn = 1;
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
++	dwc_udelay(10);
++
++	/* Disable PMU interrupt */
++	gpwrdn.d32 = 0;
++	gpwrdn.b.pmuintsel = 1;
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++
++	core_if->hibernation_suspend = 0;
++
++	/* Disable PMU */
++	gpwrdn.d32 = 0;
++	gpwrdn.b.pmuactv = 1;
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++	dwc_udelay(10);
++
++	/* Enable VBUS */
++	gpwrdn.d32 = 0;
++	gpwrdn.b.dis_vbus = 1;
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++
++	core_if->op_state = A_HOST;
++	dwc_otg_core_init(core_if);
++	dwc_otg_enable_global_interrupts(core_if);
++	cil_hcd_start(core_if);
++}
++
++/**
++ * Frees secondary storage associated with the dwc_otg_hcd structure contained
++ * in the struct usb_hcd field.
++ */
++static void dwc_otg_hcd_free(dwc_otg_hcd_t * dwc_otg_hcd)
++{
++	int i;
++
++	DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD FREE\n");
++
++	del_timers(dwc_otg_hcd);
++
++	/* Free memory for QH/QTD lists */
++	qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->non_periodic_sched_inactive);
++	qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->non_periodic_sched_active);
++	qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_inactive);
++	qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_ready);
++	qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_assigned);
++	qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_queued);
++
++	/* Free memory for the host channels. */
++	for (i = 0; i < MAX_EPS_CHANNELS; i++) {
++		dwc_hc_t *hc = dwc_otg_hcd->hc_ptr_array[i];
++
++#ifdef DEBUG
++		if (dwc_otg_hcd->core_if->hc_xfer_timer[i]) {
++			DWC_TIMER_FREE(dwc_otg_hcd->core_if->hc_xfer_timer[i]);
++		}
++#endif
++		if (hc != NULL) {
++			DWC_DEBUGPL(DBG_HCDV, "HCD Free channel #%i, hc=%p\n",
++				    i, hc);
++			DWC_FREE(hc);
++		}
++	}
++
++	if (dwc_otg_hcd->core_if->dma_enable) {
++		if (dwc_otg_hcd->status_buf_dma) {
++			DWC_DMA_FREE(DWC_OTG_HCD_STATUS_BUF_SIZE,
++				     dwc_otg_hcd->status_buf,
++				     dwc_otg_hcd->status_buf_dma);
++		}
++	} else if (dwc_otg_hcd->status_buf != NULL) {
++		DWC_FREE(dwc_otg_hcd->status_buf);
++	}
++	DWC_SPINLOCK_FREE(dwc_otg_hcd->lock);
++	/* Set core_if's lock pointer to NULL */
++	dwc_otg_hcd->core_if->lock = NULL;
++
++	DWC_TIMER_FREE(dwc_otg_hcd->conn_timer);
++	DWC_TASK_FREE(dwc_otg_hcd->reset_tasklet);
++
++#ifdef DWC_DEV_SRPCAP
++	if (dwc_otg_hcd->core_if->power_down == 2 &&
++	    dwc_otg_hcd->core_if->pwron_timer) {
++		DWC_TIMER_FREE(dwc_otg_hcd->core_if->pwron_timer);
++	}
++#endif
++	DWC_FREE(dwc_otg_hcd);
++}
++
++int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd, dwc_otg_core_if_t * core_if)
++{
++	int retval = 0;
++	int num_channels;
++	int i;
++	dwc_hc_t *channel;
++
++	hcd->lock = DWC_SPINLOCK_ALLOC();
++	if (!hcd->lock) {
++		DWC_ERROR("Could not allocate lock for pcd");
++		DWC_FREE(hcd);
++		retval = -DWC_E_NO_MEMORY;
++		goto out;
++	}
++	hcd->core_if = core_if;
++
++	/* Register the HCD CIL Callbacks */
++	dwc_otg_cil_register_hcd_callbacks(hcd->core_if,
++					   &hcd_cil_callbacks, hcd);
++
++	/* Initialize the non-periodic schedule. */
++	DWC_LIST_INIT(&hcd->non_periodic_sched_inactive);
++	DWC_LIST_INIT(&hcd->non_periodic_sched_active);
++
++	/* Initialize the periodic schedule. */
++	DWC_LIST_INIT(&hcd->periodic_sched_inactive);
++	DWC_LIST_INIT(&hcd->periodic_sched_ready);
++	DWC_LIST_INIT(&hcd->periodic_sched_assigned);
++	DWC_LIST_INIT(&hcd->periodic_sched_queued);
++
++	/*
++	 * Create a host channel descriptor for each host channel implemented
++	 * in the controller. Initialize the channel descriptor array.
++	 */
++	DWC_CIRCLEQ_INIT(&hcd->free_hc_list);
++	num_channels = hcd->core_if->core_params->host_channels;
++	DWC_MEMSET(hcd->hc_ptr_array, 0, sizeof(hcd->hc_ptr_array));
++	for (i = 0; i < num_channels; i++) {
++		channel = DWC_ALLOC(sizeof(dwc_hc_t));
++		if (channel == NULL) {
++			retval = -DWC_E_NO_MEMORY;
++			DWC_ERROR("%s: host channel allocation failed\n",
++				  __func__);
++			dwc_otg_hcd_free(hcd);
++			goto out;
++		}
++		channel->hc_num = i;
++		hcd->hc_ptr_array[i] = channel;
++#ifdef DEBUG
++		hcd->core_if->hc_xfer_timer[i] =
++		    DWC_TIMER_ALLOC("hc timer", hc_xfer_timeout,
++				    &hcd->core_if->hc_xfer_info[i]);
++#endif
++		DWC_DEBUGPL(DBG_HCDV, "HCD Added channel #%d, hc=%p\n", i,
++			    channel);
++	}
++
++	/* Initialize the Connection timeout timer. */
++	hcd->conn_timer = DWC_TIMER_ALLOC("Connection timer",
++					  dwc_otg_hcd_connect_timeout, hcd);
++
++	/* Initialize reset tasklet. */
++	hcd->reset_tasklet = DWC_TASK_ALLOC("reset_tasklet", reset_tasklet_func, hcd);
++#ifdef DWC_DEV_SRPCAP
++	if (hcd->core_if->power_down == 2) {
++		/* Initialize Power on timer for Host power up in case hibernation */
++		hcd->core_if->pwron_timer = DWC_TIMER_ALLOC("PWRON TIMER",
++									dwc_otg_hcd_power_up, core_if);
++	}
++#endif
++
++	/*
++	 * Allocate space for storing data on status transactions. Normally no
++	 * data is sent, but this space acts as a bit bucket. This must be
++	 * done after usb_add_hcd since that function allocates the DMA buffer
++	 * pool.
++	 */
++	if (hcd->core_if->dma_enable) {
++		hcd->status_buf =
++		    DWC_DMA_ALLOC(DWC_OTG_HCD_STATUS_BUF_SIZE,
++				  &hcd->status_buf_dma);
++	} else {
++		hcd->status_buf = DWC_ALLOC(DWC_OTG_HCD_STATUS_BUF_SIZE);
++	}
++	if (!hcd->status_buf) {
++		retval = -DWC_E_NO_MEMORY;
++		DWC_ERROR("%s: status_buf allocation failed\n", __func__);
++		dwc_otg_hcd_free(hcd);
++		goto out;
++	}
++
++	hcd->otg_port = 1;
++	hcd->frame_list = NULL;
++	hcd->frame_list_dma = 0;
++	hcd->periodic_qh_count = 0;
++out:
++	return retval;
++}
++
++void dwc_otg_hcd_remove(dwc_otg_hcd_t * hcd)
++{
++	/* Turn off all host-specific interrupts. */
++	dwc_otg_disable_host_interrupts(hcd->core_if);
++
++	dwc_otg_hcd_free(hcd);
++}
++
++/**
++ * Initializes dynamic portions of the DWC_otg HCD state.
++ */
++static void dwc_otg_hcd_reinit(dwc_otg_hcd_t * hcd)
++{
++	int num_channels;
++	int i;
++	dwc_hc_t *channel;
++	dwc_hc_t *channel_tmp;
++
++	hcd->flags.d32 = 0;
++
++	hcd->non_periodic_qh_ptr = &hcd->non_periodic_sched_active;
++	hcd->non_periodic_channels = 0;
++	hcd->periodic_channels = 0;
++
++	/*
++	 * Put all channels in the free channel list and clean up channel
++	 * states.
++	 */
++	DWC_CIRCLEQ_FOREACH_SAFE(channel, channel_tmp,
++				 &hcd->free_hc_list, hc_list_entry) {
++		DWC_CIRCLEQ_REMOVE(&hcd->free_hc_list, channel, hc_list_entry);
++	}
++
++	num_channels = hcd->core_if->core_params->host_channels;
++	for (i = 0; i < num_channels; i++) {
++		channel = hcd->hc_ptr_array[i];
++		DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, channel,
++					hc_list_entry);
++		dwc_otg_hc_cleanup(hcd->core_if, channel);
++	}
++
++	/* Initialize the DWC core for host mode operation. */
++	dwc_otg_core_host_init(hcd->core_if);
++
++	/* Set core_if's lock pointer to the hcd->lock */
++	hcd->core_if->lock = hcd->lock;
++}
++
++/**
++ * Assigns transactions from a QTD to a free host channel and initializes the
++ * host channel to perform the transactions. The host channel is removed from
++ * the free list.
++ *
++ * @param hcd The HCD state structure.
++ * @param qh Transactions from the first QTD for this QH are selected and
++ * assigned to a free host channel.
++ */
++static void assign_and_init_hc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
++{
++	dwc_hc_t *hc = NULL;
++	dwc_otg_qtd_t *qtd;
++	dwc_otg_hcd_urb_t *urb;
++	void* ptr = NULL;
++	hcchar_data_t hcchar;
++	int num_channels;
++	int i;
++
++	DWC_DEBUGPL(DBG_HCDV, "%s(%p,%p)\n", __func__, hcd, qh);
++
++	num_channels = hcd->core_if->core_params->host_channels;
++
++	/* WA to not select channel with chdis bit set, this was
++	 * observed after role switch as part of OTG 2.0 HNP
++	 */
++	for (i = 0; i < num_channels; i++) {
++		hc = DWC_CIRCLEQ_FIRST(&hcd->free_hc_list);
++		hcchar.d32 = DWC_READ_REG32(&hcd->core_if->host_if->hc_regs[hc->hc_num]->hcchar);
++		DWC_DEBUGPL(DBG_HCDV, "HC num = %d HCCHAR %08x\n", hc->hc_num, hcchar.d32);
++		if(!hcchar.b.chdis && !hcchar.b.chen)
++			break;
++		DWC_CIRCLEQ_REMOVE_INIT(&hcd->free_hc_list, hc, hc_list_entry);
++		DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, hc, hc_list_entry);
++		hc = NULL;
++	}
++	if (!hc) {
++		DWC_ERROR("No free channel with en and dis bits 0\n");
++		return;
++	}
++
++
++
++	/* Remove the host channel from the free list. */
++	DWC_CIRCLEQ_REMOVE_INIT(&hcd->free_hc_list, hc, hc_list_entry);
++
++	qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list);
++
++	urb = qtd->urb;
++	qh->channel = hc;
++
++	qtd->in_process = 1;
++
++	/*
++	 * Use usb_pipedevice to determine device address. This address is
++	 * 0 before the SET_ADDRESS command and the correct address afterward.
++	 */
++	hc->dev_addr = dwc_otg_hcd_get_dev_addr(&urb->pipe_info);
++	hc->ep_num = dwc_otg_hcd_get_ep_num(&urb->pipe_info);
++	hc->speed = qh->dev_speed;
++	hc->max_packet = dwc_max_packet(qh->maxp);
++
++	hc->xfer_started = 0;
++	hc->halt_status = DWC_OTG_HC_XFER_NO_HALT_STATUS;
++	hc->error_state = (qtd->error_count > 0);
++	hc->halt_on_queue = 0;
++	hc->halt_pending = 0;
++	hc->requests = 0;
++
++	/*
++	 * The following values may be modified in the transfer type section
++	 * below. The xfer_len value may be reduced when the transfer is
++	 * started to accommodate the max widths of the XferSize and PktCnt
++	 * fields in the HCTSIZn register.
++	 */
++
++	hc->ep_is_in = (dwc_otg_hcd_is_pipe_in(&urb->pipe_info) != 0);
++	if (hc->ep_is_in) {
++		hc->do_ping = 0;
++	} else {
++		hc->do_ping = qh->ping_state;
++	}
++
++	hc->data_pid_start = qh->data_toggle;
++	hc->multi_count = 1;
++
++	if (hcd->core_if->dma_enable) {
++		hc->xfer_buff = (uint8_t *) urb->dma + urb->actual_length;
++
++		/* For non-dword aligned case */
++		if (((unsigned long)hc->xfer_buff & 0x3)
++		    && !hcd->core_if->dma_desc_enable) {
++			ptr = (uint8_t *) urb->buf + urb->actual_length;
++		}
++	} else {
++		hc->xfer_buff = (uint8_t *) urb->buf + urb->actual_length;
++	}
++	hc->xfer_len = urb->length - urb->actual_length;
++	hc->xfer_count = 0;
++
++	/*
++	 * Set the split attributes
++	 */
++	hc->do_split = 0;
++	if (qh->do_split) {
++		uint32_t hub_addr, port_addr;
++		hc->do_split = 1;
++		hc->xact_pos = qtd->isoc_split_pos;
++		hc->complete_split = qtd->complete_split;
++		hcd->fops->hub_info(hcd, urb->priv, &hub_addr, &port_addr);
++		hc->hub_addr = (uint8_t) hub_addr;
++		hc->port_addr = (uint8_t) port_addr;
++	}
++
++	switch (dwc_otg_hcd_get_pipe_type(&urb->pipe_info)) {
++	case UE_CONTROL:
++		hc->ep_type = DWC_OTG_EP_TYPE_CONTROL;
++		switch (qtd->control_phase) {
++		case DWC_OTG_CONTROL_SETUP:
++			DWC_DEBUGPL(DBG_HCDV, "  Control setup transaction\n");
++			hc->do_ping = 0;
++			hc->ep_is_in = 0;
++			hc->data_pid_start = DWC_OTG_HC_PID_SETUP;
++			if (hcd->core_if->dma_enable) {
++				hc->xfer_buff = (uint8_t *) urb->setup_dma;
++			} else {
++				hc->xfer_buff = (uint8_t *) urb->setup_packet;
++			}
++			hc->xfer_len = 8;
++			ptr = NULL;
++			break;
++		case DWC_OTG_CONTROL_DATA:
++			DWC_DEBUGPL(DBG_HCDV, "  Control data transaction\n");
++			hc->data_pid_start = qtd->data_toggle;
++			break;
++		case DWC_OTG_CONTROL_STATUS:
++			/*
++			 * Direction is opposite of data direction or IN if no
++			 * data.
++			 */
++			DWC_DEBUGPL(DBG_HCDV, "  Control status transaction\n");
++			if (urb->length == 0) {
++				hc->ep_is_in = 1;
++			} else {
++				hc->ep_is_in =
++				    dwc_otg_hcd_is_pipe_out(&urb->pipe_info);
++			}
++			if (hc->ep_is_in) {
++				hc->do_ping = 0;
++			}
++
++			hc->data_pid_start = DWC_OTG_HC_PID_DATA1;
++
++			hc->xfer_len = 0;
++			if (hcd->core_if->dma_enable) {
++				hc->xfer_buff = (uint8_t *) hcd->status_buf_dma;
++			} else {
++				hc->xfer_buff = (uint8_t *) hcd->status_buf;
++			}
++			ptr = NULL;
++			break;
++		}
++		break;
++	case UE_BULK:
++		hc->ep_type = DWC_OTG_EP_TYPE_BULK;
++		break;
++	case UE_INTERRUPT:
++		hc->ep_type = DWC_OTG_EP_TYPE_INTR;
++		break;
++	case UE_ISOCHRONOUS:
++		{
++			struct dwc_otg_hcd_iso_packet_desc *frame_desc;
++
++			hc->ep_type = DWC_OTG_EP_TYPE_ISOC;
++
++			if (hcd->core_if->dma_desc_enable)
++				break;
++
++			frame_desc = &urb->iso_descs[qtd->isoc_frame_index];
++
++			frame_desc->status = 0;
++
++			if (hcd->core_if->dma_enable) {
++				hc->xfer_buff = (uint8_t *) urb->dma;
++			} else {
++				hc->xfer_buff = (uint8_t *) urb->buf;
++			}
++			hc->xfer_buff +=
++			    frame_desc->offset + qtd->isoc_split_offset;
++			hc->xfer_len =
++			    frame_desc->length - qtd->isoc_split_offset;
++
++			/* For non-dword aligned buffers */
++			if (((unsigned long)hc->xfer_buff & 0x3)
++			    && hcd->core_if->dma_enable) {
++				ptr =
++				    (uint8_t *) urb->buf + frame_desc->offset +
++				    qtd->isoc_split_offset;
++			} else
++				ptr = NULL;
++
++			if (hc->xact_pos == DWC_HCSPLIT_XACTPOS_ALL) {
++				if (hc->xfer_len <= 188) {
++					hc->xact_pos = DWC_HCSPLIT_XACTPOS_ALL;
++				} else {
++					hc->xact_pos =
++					    DWC_HCSPLIT_XACTPOS_BEGIN;
++				}
++			}
++		}
++		break;
++	}
++	/* non DWORD-aligned buffer case */
++	if (ptr) {
++		uint32_t buf_size;
++		if (hc->ep_type != DWC_OTG_EP_TYPE_ISOC) {
++			buf_size = hcd->core_if->core_params->max_transfer_size;
++		} else {
++			buf_size = 4096;
++		}
++		if (!qh->dw_align_buf) {
++			qh->dw_align_buf = DWC_DMA_ALLOC_ATOMIC(buf_size,
++							 &qh->dw_align_buf_dma);
++			if (!qh->dw_align_buf) {
++				DWC_ERROR
++				    ("%s: Failed to allocate memory to handle "
++				     "non-dword aligned buffer case\n",
++				     __func__);
++				return;
++			}
++		}
++		if (!hc->ep_is_in) {
++			dwc_memcpy(qh->dw_align_buf, ptr, hc->xfer_len);
++		}
++		hc->align_buff = qh->dw_align_buf_dma;
++	} else {
++		hc->align_buff = 0;
++	}
++
++	if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
++	    hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
++		/*
++		 * This value may be modified when the transfer is started to
++		 * reflect the actual transfer length.
++		 */
++		hc->multi_count = dwc_hb_mult(qh->maxp);
++	}
++
++	if (hcd->core_if->dma_desc_enable)
++		hc->desc_list_addr = qh->desc_list_dma;
++
++	dwc_otg_hc_init(hcd->core_if, hc);
++	hc->qh = qh;
++}
++
++/**
++ * This function selects transactions from the HCD transfer schedule and
++ * assigns them to available host channels. It is called from HCD interrupt
++ * handler functions.
++ *
++ * @param hcd The HCD state structure.
++ *
++ * @return The types of new transactions that were assigned to host channels.
++ */
++dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd)
++{
++	dwc_list_link_t *qh_ptr;
++	dwc_otg_qh_t *qh;
++	int num_channels;
++	dwc_otg_transaction_type_e ret_val = DWC_OTG_TRANSACTION_NONE;
++
++#ifdef DEBUG_SOF
++	DWC_DEBUGPL(DBG_HCD, "  Select Transactions\n");
++#endif
++
++	/* Process entries in the periodic ready list. */
++	qh_ptr = DWC_LIST_FIRST(&hcd->periodic_sched_ready);
++
++	while (qh_ptr != &hcd->periodic_sched_ready &&
++	       !DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) {
++
++		qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry);
++		assign_and_init_hc(hcd, qh);
++
++		/*
++		 * Move the QH from the periodic ready schedule to the
++		 * periodic assigned schedule.
++		 */
++		qh_ptr = DWC_LIST_NEXT(qh_ptr);
++		DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_assigned,
++				   &qh->qh_list_entry);
++
++		ret_val = DWC_OTG_TRANSACTION_PERIODIC;
++	}
++
++	/*
++	 * Process entries in the inactive portion of the non-periodic
++	 * schedule. Some free host channels may not be used if they are
++	 * reserved for periodic transfers.
++	 */
++	qh_ptr = hcd->non_periodic_sched_inactive.next;
++	num_channels = hcd->core_if->core_params->host_channels;
++	while (qh_ptr != &hcd->non_periodic_sched_inactive &&
++	       (hcd->non_periodic_channels <
++		num_channels - hcd->periodic_channels) &&
++	       !DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) {
++
++		qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry);
++
++		assign_and_init_hc(hcd, qh);
++
++		/*
++		 * Move the QH from the non-periodic inactive schedule to the
++		 * non-periodic active schedule.
++		 */
++		qh_ptr = DWC_LIST_NEXT(qh_ptr);
++		DWC_LIST_MOVE_HEAD(&hcd->non_periodic_sched_active,
++				   &qh->qh_list_entry);
++
++		if (ret_val == DWC_OTG_TRANSACTION_NONE) {
++			ret_val = DWC_OTG_TRANSACTION_NON_PERIODIC;
++		} else {
++			ret_val = DWC_OTG_TRANSACTION_ALL;
++		}
++
++		hcd->non_periodic_channels++;
++	}
++
++	return ret_val;
++}
++
++/**
++ * Attempts to queue a single transaction request for a host channel
++ * associated with either a periodic or non-periodic transfer. This function
++ * assumes that there is space available in the appropriate request queue. For
++ * an OUT transfer or SETUP transaction in Slave mode, it checks whether space
++ * is available in the appropriate Tx FIFO.
++ *
++ * @param hcd The HCD state structure.
++ * @param hc Host channel descriptor associated with either a periodic or
++ * non-periodic transfer.
++ * @param fifo_dwords_avail Number of DWORDs available in the periodic Tx
++ * FIFO for periodic transfers or the non-periodic Tx FIFO for non-periodic
++ * transfers.
++ *
++ * @return 1 if a request is queued and more requests may be needed to
++ * complete the transfer, 0 if no more requests are required for this
++ * transfer, -1 if there is insufficient space in the Tx FIFO.
++ */
++static int queue_transaction(dwc_otg_hcd_t * hcd,
++			     dwc_hc_t * hc, uint16_t fifo_dwords_avail)
++{
++	int retval;
++
++	if (hcd->core_if->dma_enable) {
++		if (hcd->core_if->dma_desc_enable) {
++			if (!hc->xfer_started
++			    || (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)) {
++				dwc_otg_hcd_start_xfer_ddma(hcd, hc->qh);
++				hc->qh->ping_state = 0;
++			}
++		} else if (!hc->xfer_started) {
++			dwc_otg_hc_start_transfer(hcd->core_if, hc);
++			hc->qh->ping_state = 0;
++		}
++		retval = 0;
++	} else if (hc->halt_pending) {
++		/* Don't queue a request if the channel has been halted. */
++		retval = 0;
++	} else if (hc->halt_on_queue) {
++		dwc_otg_hc_halt(hcd->core_if, hc, hc->halt_status);
++		retval = 0;
++	} else if (hc->do_ping) {
++		if (!hc->xfer_started) {
++			dwc_otg_hc_start_transfer(hcd->core_if, hc);
++		}
++		retval = 0;
++	} else if (!hc->ep_is_in || hc->data_pid_start == DWC_OTG_HC_PID_SETUP) {
++		if ((fifo_dwords_avail * 4) >= hc->max_packet) {
++			if (!hc->xfer_started) {
++				dwc_otg_hc_start_transfer(hcd->core_if, hc);
++				retval = 1;
++			} else {
++				retval =
++				    dwc_otg_hc_continue_transfer(hcd->core_if,
++								 hc);
++			}
++		} else {
++			retval = -1;
++		}
++	} else {
++		if (!hc->xfer_started) {
++			dwc_otg_hc_start_transfer(hcd->core_if, hc);
++			retval = 1;
++		} else {
++			retval = dwc_otg_hc_continue_transfer(hcd->core_if, hc);
++		}
++	}
++
++	return retval;
++}
++
++/**
++ * Processes periodic channels for the next frame and queues transactions for
++ * these channels to the DWC_otg controller. After queueing transactions, the
++ * Periodic Tx FIFO Empty interrupt is enabled if there are more transactions
++ * to queue as Periodic Tx FIFO or request queue space becomes available.
++ * Otherwise, the Periodic Tx FIFO Empty interrupt is disabled.
++ */
++static void process_periodic_channels(dwc_otg_hcd_t * hcd)
++{
++	hptxsts_data_t tx_status;
++	dwc_list_link_t *qh_ptr;
++	dwc_otg_qh_t *qh;
++	int status;
++	int no_queue_space = 0;
++	int no_fifo_space = 0;
++
++	dwc_otg_host_global_regs_t *host_regs;
++	host_regs = hcd->core_if->host_if->host_global_regs;
++
++	DWC_DEBUGPL(DBG_HCDV, "Queue periodic transactions\n");
++#ifdef DEBUG
++	tx_status.d32 = DWC_READ_REG32(&host_regs->hptxsts);
++	DWC_DEBUGPL(DBG_HCDV,
++		    "  P Tx Req Queue Space Avail (before queue): %d\n",
++		    tx_status.b.ptxqspcavail);
++	DWC_DEBUGPL(DBG_HCDV, "  P Tx FIFO Space Avail (before queue): %d\n",
++		    tx_status.b.ptxfspcavail);
++#endif
++
++	qh_ptr = hcd->periodic_sched_assigned.next;
++	while (qh_ptr != &hcd->periodic_sched_assigned) {
++		tx_status.d32 = DWC_READ_REG32(&host_regs->hptxsts);
++		if (tx_status.b.ptxqspcavail == 0) {
++			no_queue_space = 1;
++			break;
++		}
++
++		qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry);
++
++		/*
++		 * Set a flag if we're queuing high-bandwidth in slave mode.
++		 * The flag prevents any halts to get into the request queue in
++		 * the middle of multiple high-bandwidth packets getting queued.
++		 */
++		if (!hcd->core_if->dma_enable && qh->channel->multi_count > 1) {
++			hcd->core_if->queuing_high_bandwidth = 1;
++		}
++		status =
++		    queue_transaction(hcd, qh->channel,
++				      tx_status.b.ptxfspcavail);
++		if (status < 0) {
++			no_fifo_space = 1;
++			break;
++		}
++
++		/*
++		 * In Slave mode, stay on the current transfer until there is
++		 * nothing more to do or the high-bandwidth request count is
++		 * reached. In DMA mode, only need to queue one request. The
++		 * controller automatically handles multiple packets for
++		 * high-bandwidth transfers.
++		 */
++		if (hcd->core_if->dma_enable || status == 0 ||
++		    qh->channel->requests == qh->channel->multi_count) {
++			qh_ptr = qh_ptr->next;
++			/*
++			 * Move the QH from the periodic assigned schedule to
++			 * the periodic queued schedule.
++			 */
++			DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_queued,
++					   &qh->qh_list_entry);
++
++			/* done queuing high bandwidth */
++			hcd->core_if->queuing_high_bandwidth = 0;
++		}
++	}
++
++	if (!hcd->core_if->dma_enable) {
++		dwc_otg_core_global_regs_t *global_regs;
++		gintmsk_data_t intr_mask = {.d32 = 0 };
++
++		global_regs = hcd->core_if->core_global_regs;
++		intr_mask.b.ptxfempty = 1;
++#ifdef DEBUG
++		tx_status.d32 = DWC_READ_REG32(&host_regs->hptxsts);
++		DWC_DEBUGPL(DBG_HCDV,
++			    "  P Tx Req Queue Space Avail (after queue): %d\n",
++			    tx_status.b.ptxqspcavail);
++		DWC_DEBUGPL(DBG_HCDV,
++			    "  P Tx FIFO Space Avail (after queue): %d\n",
++			    tx_status.b.ptxfspcavail);
++#endif
++		if (!DWC_LIST_EMPTY(&hcd->periodic_sched_assigned) ||
++		    no_queue_space || no_fifo_space) {
++			/*
++			 * May need to queue more transactions as the request
++			 * queue or Tx FIFO empties. Enable the periodic Tx
++			 * FIFO empty interrupt. (Always use the half-empty
++			 * level to ensure that new requests are loaded as
++			 * soon as possible.)
++			 */
++			DWC_MODIFY_REG32(&global_regs->gintmsk, 0,
++					 intr_mask.d32);
++		} else {
++			/*
++			 * Disable the Tx FIFO empty interrupt since there are
++			 * no more transactions that need to be queued right
++			 * now. This function is called from interrupt
++			 * handlers to queue more transactions as transfer
++			 * states change.
++			 */
++			DWC_MODIFY_REG32(&global_regs->gintmsk, intr_mask.d32,
++					 0);
++		}
++	}
++}
++
++/**
++ * Processes active non-periodic channels and queues transactions for these
++ * channels to the DWC_otg controller. After queueing transactions, the NP Tx
++ * FIFO Empty interrupt is enabled if there are more transactions to queue as
++ * NP Tx FIFO or request queue space becomes available. Otherwise, the NP Tx
++ * FIFO Empty interrupt is disabled.
++ */
++static void process_non_periodic_channels(dwc_otg_hcd_t * hcd)
++{
++	gnptxsts_data_t tx_status;
++	dwc_list_link_t *orig_qh_ptr;
++	dwc_otg_qh_t *qh;
++	int status;
++	int no_queue_space = 0;
++	int no_fifo_space = 0;
++	int more_to_do = 0;
++
++	dwc_otg_core_global_regs_t *global_regs =
++	    hcd->core_if->core_global_regs;
++
++	DWC_DEBUGPL(DBG_HCDV, "Queue non-periodic transactions\n");
++#ifdef DEBUG
++	tx_status.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
++	DWC_DEBUGPL(DBG_HCDV,
++		    "  NP Tx Req Queue Space Avail (before queue): %d\n",
++		    tx_status.b.nptxqspcavail);
++	DWC_DEBUGPL(DBG_HCDV, "  NP Tx FIFO Space Avail (before queue): %d\n",
++		    tx_status.b.nptxfspcavail);
++#endif
++	/*
++	 * Keep track of the starting point. Skip over the start-of-list
++	 * entry.
++	 */
++	if (hcd->non_periodic_qh_ptr == &hcd->non_periodic_sched_active) {
++		hcd->non_periodic_qh_ptr = hcd->non_periodic_qh_ptr->next;
++	}
++	orig_qh_ptr = hcd->non_periodic_qh_ptr;
++
++	/*
++	 * Process once through the active list or until no more space is
++	 * available in the request queue or the Tx FIFO.
++	 */
++	do {
++		tx_status.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
++		if (!hcd->core_if->dma_enable && tx_status.b.nptxqspcavail == 0) {
++			no_queue_space = 1;
++			break;
++		}
++
++		qh = DWC_LIST_ENTRY(hcd->non_periodic_qh_ptr, dwc_otg_qh_t,
++				    qh_list_entry);
++		status =
++		    queue_transaction(hcd, qh->channel,
++				      tx_status.b.nptxfspcavail);
++
++		if (status > 0) {
++			more_to_do = 1;
++		} else if (status < 0) {
++			no_fifo_space = 1;
++			break;
++		}
++
++		/* Advance to next QH, skipping start-of-list entry. */
++		hcd->non_periodic_qh_ptr = hcd->non_periodic_qh_ptr->next;
++		if (hcd->non_periodic_qh_ptr == &hcd->non_periodic_sched_active) {
++			hcd->non_periodic_qh_ptr =
++			    hcd->non_periodic_qh_ptr->next;
++		}
++
++	} while (hcd->non_periodic_qh_ptr != orig_qh_ptr);
++
++	if (!hcd->core_if->dma_enable) {
++		gintmsk_data_t intr_mask = {.d32 = 0 };
++		intr_mask.b.nptxfempty = 1;
++
++#ifdef DEBUG
++		tx_status.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
++		DWC_DEBUGPL(DBG_HCDV,
++			    "  NP Tx Req Queue Space Avail (after queue): %d\n",
++			    tx_status.b.nptxqspcavail);
++		DWC_DEBUGPL(DBG_HCDV,
++			    "  NP Tx FIFO Space Avail (after queue): %d\n",
++			    tx_status.b.nptxfspcavail);
++#endif
++		if (more_to_do || no_queue_space || no_fifo_space) {
++			/*
++			 * May need to queue more transactions as the request
++			 * queue or Tx FIFO empties. Enable the non-periodic
++			 * Tx FIFO empty interrupt. (Always use the half-empty
++			 * level to ensure that new requests are loaded as
++			 * soon as possible.)
++			 */
++			DWC_MODIFY_REG32(&global_regs->gintmsk, 0,
++					 intr_mask.d32);
++		} else {
++			/*
++			 * Disable the Tx FIFO empty interrupt since there are
++			 * no more transactions that need to be queued right
++			 * now. This function is called from interrupt
++			 * handlers to queue more transactions as transfer
++			 * states change.
++			 */
++			DWC_MODIFY_REG32(&global_regs->gintmsk, intr_mask.d32,
++					 0);
++		}
++	}
++}
++
++/**
++ * This function processes the currently active host channels and queues
++ * transactions for these channels to the DWC_otg controller. It is called
++ * from HCD interrupt handler functions.
++ *
++ * @param hcd The HCD state structure.
++ * @param tr_type The type(s) of transactions to queue (non-periodic,
++ * periodic, or both).
++ */
++void dwc_otg_hcd_queue_transactions(dwc_otg_hcd_t * hcd,
++				    dwc_otg_transaction_type_e tr_type)
++{
++#ifdef DEBUG_SOF
++	DWC_DEBUGPL(DBG_HCD, "Queue Transactions\n");
++#endif
++	/* Process host channels associated with periodic transfers. */
++	if ((tr_type == DWC_OTG_TRANSACTION_PERIODIC ||
++	     tr_type == DWC_OTG_TRANSACTION_ALL) &&
++	    !DWC_LIST_EMPTY(&hcd->periodic_sched_assigned)) {
++
++		process_periodic_channels(hcd);
++	}
++
++	/* Process host channels associated with non-periodic transfers. */
++	if (tr_type == DWC_OTG_TRANSACTION_NON_PERIODIC ||
++	    tr_type == DWC_OTG_TRANSACTION_ALL) {
++		if (!DWC_LIST_EMPTY(&hcd->non_periodic_sched_active)) {
++			process_non_periodic_channels(hcd);
++		} else {
++			/*
++			 * Ensure NP Tx FIFO empty interrupt is disabled when
++			 * there are no non-periodic transfers to process.
++			 */
++			gintmsk_data_t gintmsk = {.d32 = 0 };
++			gintmsk.b.nptxfempty = 1;
++			DWC_MODIFY_REG32(&hcd->core_if->
++					 core_global_regs->gintmsk, gintmsk.d32,
++					 0);
++		}
++	}
++}
++
++#ifdef DWC_HS_ELECT_TST
++/*
++ * Quick and dirty hack to implement the HS Electrical Test
++ * SINGLE_STEP_GET_DEVICE_DESCRIPTOR feature.
++ *
++ * This code was copied from our userspace app "hset". It sends a
++ * Get Device Descriptor control sequence in two parts, first the
++ * Setup packet by itself, followed some time later by the In and
++ * Ack packets. Rather than trying to figure out how to add this
++ * functionality to the normal driver code, we just hijack the
++ * hardware, using these two function to drive the hardware
++ * directly.
++ */
++
++static dwc_otg_core_global_regs_t *global_regs;
++static dwc_otg_host_global_regs_t *hc_global_regs;
++static dwc_otg_hc_regs_t *hc_regs;
++static uint32_t *data_fifo;
++
++static void do_setup(void)
++{
++	gintsts_data_t gintsts;
++	hctsiz_data_t hctsiz;
++	hcchar_data_t hcchar;
++	haint_data_t haint;
++	hcint_data_t hcint;
++
++	/* Enable HAINTs */
++	DWC_WRITE_REG32(&hc_global_regs->haintmsk, 0x0001);
++
++	/* Enable HCINTs */
++	DWC_WRITE_REG32(&hc_regs->hcintmsk, 0x04a3);
++
++	/* Read GINTSTS */
++	gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
++
++	/* Read HAINT */
++	haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
++
++	/* Read HCINT */
++	hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
++
++	/* Read HCCHAR */
++	hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
++
++	/* Clear HCINT */
++	DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
++
++	/* Clear HAINT */
++	DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
++
++	/* Clear GINTSTS */
++	DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
++
++	/* Read GINTSTS */
++	gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
++
++	/*
++	 * Send Setup packet (Get Device Descriptor)
++	 */
++
++	/* Make sure channel is disabled */
++	hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
++	if (hcchar.b.chen) {
++		hcchar.b.chdis = 1;
++//              hcchar.b.chen = 1;
++		DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
++		//sleep(1);
++		dwc_mdelay(1000);
++
++		/* Read GINTSTS */
++		gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
++
++		/* Read HAINT */
++		haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
++
++		/* Read HCINT */
++		hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
++
++		/* Read HCCHAR */
++		hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
++
++		/* Clear HCINT */
++		DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
++
++		/* Clear HAINT */
++		DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
++
++		/* Clear GINTSTS */
++		DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
++
++		hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
++	}
++
++	/* Set HCTSIZ */
++	hctsiz.d32 = 0;
++	hctsiz.b.xfersize = 8;
++	hctsiz.b.pktcnt = 1;
++	hctsiz.b.pid = DWC_OTG_HC_PID_SETUP;
++	DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
++
++	/* Set HCCHAR */
++	hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
++	hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
++	hcchar.b.epdir = 0;
++	hcchar.b.epnum = 0;
++	hcchar.b.mps = 8;
++	hcchar.b.chen = 1;
++	DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
++
++	/* Fill FIFO with Setup data for Get Device Descriptor */
++	data_fifo = (uint32_t *) ((char *)global_regs + 0x1000);
++	DWC_WRITE_REG32(data_fifo++, 0x01000680);
++	DWC_WRITE_REG32(data_fifo++, 0x00080000);
++
++	gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
++
++	/* Wait for host channel interrupt */
++	do {
++		gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
++	} while (gintsts.b.hcintr == 0);
++
++	/* Disable HCINTs */
++	DWC_WRITE_REG32(&hc_regs->hcintmsk, 0x0000);
++
++	/* Disable HAINTs */
++	DWC_WRITE_REG32(&hc_global_regs->haintmsk, 0x0000);
++
++	/* Read HAINT */
++	haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
++
++	/* Read HCINT */
++	hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
++
++	/* Read HCCHAR */
++	hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
++
++	/* Clear HCINT */
++	DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
++
++	/* Clear HAINT */
++	DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
++
++	/* Clear GINTSTS */
++	DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
++
++	/* Read GINTSTS */
++	gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
++}
++
++static void do_in_ack(void)
++{
++	gintsts_data_t gintsts;
++	hctsiz_data_t hctsiz;
++	hcchar_data_t hcchar;
++	haint_data_t haint;
++	hcint_data_t hcint;
++	host_grxsts_data_t grxsts;
++
++	/* Enable HAINTs */
++	DWC_WRITE_REG32(&hc_global_regs->haintmsk, 0x0001);
++
++	/* Enable HCINTs */
++	DWC_WRITE_REG32(&hc_regs->hcintmsk, 0x04a3);
++
++	/* Read GINTSTS */
++	gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
++
++	/* Read HAINT */
++	haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
++
++	/* Read HCINT */
++	hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
++
++	/* Read HCCHAR */
++	hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
++
++	/* Clear HCINT */
++	DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
++
++	/* Clear HAINT */
++	DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
++
++	/* Clear GINTSTS */
++	DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
++
++	/* Read GINTSTS */
++	gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
++
++	/*
++	 * Receive Control In packet
++	 */
++
++	/* Make sure channel is disabled */
++	hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
++	if (hcchar.b.chen) {
++		hcchar.b.chdis = 1;
++		hcchar.b.chen = 1;
++		DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
++		//sleep(1);
++		dwc_mdelay(1000);
++
++		/* Read GINTSTS */
++		gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
++
++		/* Read HAINT */
++		haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
++
++		/* Read HCINT */
++		hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
++
++		/* Read HCCHAR */
++		hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
++
++		/* Clear HCINT */
++		DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
++
++		/* Clear HAINT */
++		DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
++
++		/* Clear GINTSTS */
++		DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
++
++		hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
++	}
++
++	/* Set HCTSIZ */
++	hctsiz.d32 = 0;
++	hctsiz.b.xfersize = 8;
++	hctsiz.b.pktcnt = 1;
++	hctsiz.b.pid = DWC_OTG_HC_PID_DATA1;
++	DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
++
++	/* Set HCCHAR */
++	hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
++	hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
++	hcchar.b.epdir = 1;
++	hcchar.b.epnum = 0;
++	hcchar.b.mps = 8;
++	hcchar.b.chen = 1;
++	DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
++
++	gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
++
++	/* Wait for receive status queue interrupt */
++	do {
++		gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
++	} while (gintsts.b.rxstsqlvl == 0);
++
++	/* Read RXSTS */
++	grxsts.d32 = DWC_READ_REG32(&global_regs->grxstsp);
++
++	/* Clear RXSTSQLVL in GINTSTS */
++	gintsts.d32 = 0;
++	gintsts.b.rxstsqlvl = 1;
++	DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
++
++	switch (grxsts.b.pktsts) {
++	case DWC_GRXSTS_PKTSTS_IN:
++		/* Read the data into the host buffer */
++		if (grxsts.b.bcnt > 0) {
++			int i;
++			int word_count = (grxsts.b.bcnt + 3) / 4;
++
++			data_fifo = (uint32_t *) ((char *)global_regs + 0x1000);
++
++			for (i = 0; i < word_count; i++) {
++				(void)DWC_READ_REG32(data_fifo++);
++			}
++		}
++		break;
++
++	default:
++		break;
++	}
++
++	gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
++
++	/* Wait for receive status queue interrupt */
++	do {
++		gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
++	} while (gintsts.b.rxstsqlvl == 0);
++
++	/* Read RXSTS */
++	grxsts.d32 = DWC_READ_REG32(&global_regs->grxstsp);
++
++	/* Clear RXSTSQLVL in GINTSTS */
++	gintsts.d32 = 0;
++	gintsts.b.rxstsqlvl = 1;
++	DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
++
++	switch (grxsts.b.pktsts) {
++	case DWC_GRXSTS_PKTSTS_IN_XFER_COMP:
++		break;
++
++	default:
++		break;
++	}
++
++	gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
++
++	/* Wait for host channel interrupt */
++	do {
++		gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
++	} while (gintsts.b.hcintr == 0);
++
++	/* Read HAINT */
++	haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
++
++	/* Read HCINT */
++	hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
++
++	/* Read HCCHAR */
++	hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
++
++	/* Clear HCINT */
++	DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
++
++	/* Clear HAINT */
++	DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
++
++	/* Clear GINTSTS */
++	DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
++
++	/* Read GINTSTS */
++	gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
++
++//      usleep(100000);
++//      mdelay(100);
++	dwc_mdelay(1);
++
++	/*
++	 * Send handshake packet
++	 */
++
++	/* Read HAINT */
++	haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
++
++	/* Read HCINT */
++	hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
++
++	/* Read HCCHAR */
++	hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
++
++	/* Clear HCINT */
++	DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
++
++	/* Clear HAINT */
++	DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
++
++	/* Clear GINTSTS */
++	DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
++
++	/* Read GINTSTS */
++	gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
++
++	/* Make sure channel is disabled */
++	hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
++	if (hcchar.b.chen) {
++		hcchar.b.chdis = 1;
++		hcchar.b.chen = 1;
++		DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
++		//sleep(1);
++		dwc_mdelay(1000);
++
++		/* Read GINTSTS */
++		gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
++
++		/* Read HAINT */
++		haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
++
++		/* Read HCINT */
++		hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
++
++		/* Read HCCHAR */
++		hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
++
++		/* Clear HCINT */
++		DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
++
++		/* Clear HAINT */
++		DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
++
++		/* Clear GINTSTS */
++		DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
++
++		hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
++	}
++
++	/* Set HCTSIZ */
++	hctsiz.d32 = 0;
++	hctsiz.b.xfersize = 0;
++	hctsiz.b.pktcnt = 1;
++	hctsiz.b.pid = DWC_OTG_HC_PID_DATA1;
++	DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
++
++	/* Set HCCHAR */
++	hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
++	hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
++	hcchar.b.epdir = 0;
++	hcchar.b.epnum = 0;
++	hcchar.b.mps = 8;
++	hcchar.b.chen = 1;
++	DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
++
++	gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
++
++	/* Wait for host channel interrupt */
++	do {
++		gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
++	} while (gintsts.b.hcintr == 0);
++
++	/* Disable HCINTs */
++	DWC_WRITE_REG32(&hc_regs->hcintmsk, 0x0000);
++
++	/* Disable HAINTs */
++	DWC_WRITE_REG32(&hc_global_regs->haintmsk, 0x0000);
++
++	/* Read HAINT */
++	haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
++
++	/* Read HCINT */
++	hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
++
++	/* Read HCCHAR */
++	hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
++
++	/* Clear HCINT */
++	DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
++
++	/* Clear HAINT */
++	DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
++
++	/* Clear GINTSTS */
++	DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
++
++	/* Read GINTSTS */
++	gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
++}
++#endif
++
++/** Handles hub class-specific requests. */
++int dwc_otg_hcd_hub_control(dwc_otg_hcd_t * dwc_otg_hcd,
++			    uint16_t typeReq,
++			    uint16_t wValue,
++			    uint16_t wIndex, uint8_t * buf, uint16_t wLength)
++{
++	int retval = 0;
++
++	dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if;
++	usb_hub_descriptor_t *hub_desc;
++	hprt0_data_t hprt0 = {.d32 = 0 };
++
++	uint32_t port_status;
++
++	switch (typeReq) {
++	case UCR_CLEAR_HUB_FEATURE:
++		DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
++			    "ClearHubFeature 0x%x\n", wValue);
++		switch (wValue) {
++		case UHF_C_HUB_LOCAL_POWER:
++		case UHF_C_HUB_OVER_CURRENT:
++			/* Nothing required here */
++			break;
++		default:
++			retval = -DWC_E_INVALID;
++			DWC_ERROR("DWC OTG HCD - "
++				  "ClearHubFeature request %xh unknown\n",
++				  wValue);
++		}
++		break;
++	case UCR_CLEAR_PORT_FEATURE:
++#ifdef CONFIG_USB_DWC_OTG_LPM
++		if (wValue != UHF_PORT_L1)
++#endif
++			if (!wIndex || wIndex > 1)
++				goto error;
++
++		switch (wValue) {
++		case UHF_PORT_ENABLE:
++			DWC_DEBUGPL(DBG_ANY, "DWC OTG HCD HUB CONTROL - "
++				    "ClearPortFeature USB_PORT_FEAT_ENABLE\n");
++			hprt0.d32 = dwc_otg_read_hprt0(core_if);
++			hprt0.b.prtena = 1;
++			DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
++			break;
++		case UHF_PORT_SUSPEND:
++			DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
++				    "ClearPortFeature USB_PORT_FEAT_SUSPEND\n");
++
++			if (core_if->power_down == 2) {
++				dwc_otg_host_hibernation_restore(core_if, 0, 0);
++			} else {
++				DWC_WRITE_REG32(core_if->pcgcctl, 0);
++				dwc_mdelay(5);
++
++				hprt0.d32 = dwc_otg_read_hprt0(core_if);
++				hprt0.b.prtres = 1;
++				DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
++				hprt0.b.prtsusp = 0;
++				/* Clear Resume bit */
++				dwc_mdelay(100);
++				hprt0.b.prtres = 0;
++				DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
++			}
++			break;
++#ifdef CONFIG_USB_DWC_OTG_LPM
++		case UHF_PORT_L1:
++			{
++				pcgcctl_data_t pcgcctl = {.d32 = 0 };
++				glpmcfg_data_t lpmcfg = {.d32 = 0 };
++
++				lpmcfg.d32 =
++				    DWC_READ_REG32(&core_if->
++						   core_global_regs->glpmcfg);
++				lpmcfg.b.en_utmi_sleep = 0;
++				lpmcfg.b.hird_thres &= (~(1 << 4));
++				lpmcfg.b.prt_sleep_sts = 1;
++				DWC_WRITE_REG32(&core_if->
++						core_global_regs->glpmcfg,
++						lpmcfg.d32);
++
++				/* Clear Enbl_L1Gating bit. */
++				pcgcctl.b.enbl_sleep_gating = 1;
++				DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32,
++						 0);
++
++				dwc_mdelay(5);
++
++				hprt0.d32 = dwc_otg_read_hprt0(core_if);
++				hprt0.b.prtres = 1;
++				DWC_WRITE_REG32(core_if->host_if->hprt0,
++						hprt0.d32);
++				/* This bit will be cleared in wakeup interrupt handle */
++				break;
++			}
++#endif
++		case UHF_PORT_POWER:
++			DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
++				    "ClearPortFeature USB_PORT_FEAT_POWER\n");
++			hprt0.d32 = dwc_otg_read_hprt0(core_if);
++			hprt0.b.prtpwr = 0;
++			DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
++			break;
++		case UHF_PORT_INDICATOR:
++			DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
++				    "ClearPortFeature USB_PORT_FEAT_INDICATOR\n");
++			/* Port inidicator not supported */
++			break;
++		case UHF_C_PORT_CONNECTION:
++			/* Clears drivers internal connect status change
++			 * flag */
++			DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
++				    "ClearPortFeature USB_PORT_FEAT_C_CONNECTION\n");
++			dwc_otg_hcd->flags.b.port_connect_status_change = 0;
++			break;
++		case UHF_C_PORT_RESET:
++			/* Clears the driver's internal Port Reset Change
++			 * flag */
++			DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
++				    "ClearPortFeature USB_PORT_FEAT_C_RESET\n");
++			dwc_otg_hcd->flags.b.port_reset_change = 0;
++			break;
++		case UHF_C_PORT_ENABLE:
++			/* Clears the driver's internal Port
++			 * Enable/Disable Change flag */
++			DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
++				    "ClearPortFeature USB_PORT_FEAT_C_ENABLE\n");
++			dwc_otg_hcd->flags.b.port_enable_change = 0;
++			break;
++		case UHF_C_PORT_SUSPEND:
++			/* Clears the driver's internal Port Suspend
++			 * Change flag, which is set when resume signaling on
++			 * the host port is complete */
++			DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
++				    "ClearPortFeature USB_PORT_FEAT_C_SUSPEND\n");
++			dwc_otg_hcd->flags.b.port_suspend_change = 0;
++			break;
++#ifdef CONFIG_USB_DWC_OTG_LPM
++		case UHF_C_PORT_L1:
++			dwc_otg_hcd->flags.b.port_l1_change = 0;
++			break;
++#endif
++		case UHF_C_PORT_OVER_CURRENT:
++			DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
++				    "ClearPortFeature USB_PORT_FEAT_C_OVER_CURRENT\n");
++			dwc_otg_hcd->flags.b.port_over_current_change = 0;
++			break;
++		default:
++			retval = -DWC_E_INVALID;
++			DWC_ERROR("DWC OTG HCD - "
++				  "ClearPortFeature request %xh "
++				  "unknown or unsupported\n", wValue);
++		}
++		break;
++	case UCR_GET_HUB_DESCRIPTOR:
++		DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
++			    "GetHubDescriptor\n");
++		hub_desc = (usb_hub_descriptor_t *) buf;
++		hub_desc->bDescLength = 9;
++		hub_desc->bDescriptorType = 0x29;
++		hub_desc->bNbrPorts = 1;
++		USETW(hub_desc->wHubCharacteristics, 0x08);
++		hub_desc->bPwrOn2PwrGood = 1;
++		hub_desc->bHubContrCurrent = 0;
++		hub_desc->DeviceRemovable[0] = 0;
++		hub_desc->DeviceRemovable[1] = 0xff;
++		break;
++	case UCR_GET_HUB_STATUS:
++		DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
++			    "GetHubStatus\n");
++		DWC_MEMSET(buf, 0, 4);
++		break;
++	case UCR_GET_PORT_STATUS:
++		DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
++			    "GetPortStatus wIndex = 0x%04x FLAGS=0x%08x\n",
++			    wIndex, dwc_otg_hcd->flags.d32);
++		if (!wIndex || wIndex > 1)
++			goto error;
++
++		port_status = 0;
++
++		if (dwc_otg_hcd->flags.b.port_connect_status_change)
++			port_status |= (1 << UHF_C_PORT_CONNECTION);
++
++		if (dwc_otg_hcd->flags.b.port_enable_change)
++			port_status |= (1 << UHF_C_PORT_ENABLE);
++
++		if (dwc_otg_hcd->flags.b.port_suspend_change)
++			port_status |= (1 << UHF_C_PORT_SUSPEND);
++
++		if (dwc_otg_hcd->flags.b.port_l1_change)
++			port_status |= (1 << UHF_C_PORT_L1);
++
++		if (dwc_otg_hcd->flags.b.port_reset_change) {
++			port_status |= (1 << UHF_C_PORT_RESET);
++		}
++
++		if (dwc_otg_hcd->flags.b.port_over_current_change) {
++			DWC_WARN("Overcurrent change detected\n");
++			port_status |= (1 << UHF_C_PORT_OVER_CURRENT);
++		}
++
++		if (!dwc_otg_hcd->flags.b.port_connect_status) {
++			/*
++			 * The port is disconnected, which means the core is
++			 * either in device mode or it soon will be. Just
++			 * return 0's for the remainder of the port status
++			 * since the port register can't be read if the core
++			 * is in device mode.
++			 */
++			*((__le32 *) buf) = dwc_cpu_to_le32(&port_status);
++			break;
++		}
++
++		hprt0.d32 = DWC_READ_REG32(core_if->host_if->hprt0);
++		DWC_DEBUGPL(DBG_HCDV, "  HPRT0: 0x%08x\n", hprt0.d32);
++
++		if (hprt0.b.prtconnsts)
++			port_status |= (1 << UHF_PORT_CONNECTION);
++
++		if (hprt0.b.prtena)
++			port_status |= (1 << UHF_PORT_ENABLE);
++
++		if (hprt0.b.prtsusp)
++			port_status |= (1 << UHF_PORT_SUSPEND);
++
++		if (hprt0.b.prtovrcurract)
++			port_status |= (1 << UHF_PORT_OVER_CURRENT);
++
++		if (hprt0.b.prtrst)
++			port_status |= (1 << UHF_PORT_RESET);
++
++		if (hprt0.b.prtpwr)
++			port_status |= (1 << UHF_PORT_POWER);
++
++		if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED)
++			port_status |= (1 << UHF_PORT_HIGH_SPEED);
++		else if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_LOW_SPEED)
++			port_status |= (1 << UHF_PORT_LOW_SPEED);
++
++		if (hprt0.b.prttstctl)
++			port_status |= (1 << UHF_PORT_TEST);
++		if (dwc_otg_get_lpm_portsleepstatus(dwc_otg_hcd->core_if)) {
++			port_status |= (1 << UHF_PORT_L1);
++		}
++		/*
++		   For Synopsys HW emulation of Power down wkup_control asserts the
++		   hreset_n and prst_n on suspned. This causes the HPRT0 to be zero.
++		   We intentionally tell the software that port is in L2Suspend state.
++		   Only for STE.
++		*/
++		if ((core_if->power_down == 2)
++		    && (core_if->hibernation_suspend == 1)) {
++			port_status |= (1 << UHF_PORT_SUSPEND);
++		}
++		/* USB_PORT_FEAT_INDICATOR unsupported always 0 */
++
++		*((__le32 *) buf) = dwc_cpu_to_le32(&port_status);
++
++		break;
++	case UCR_SET_HUB_FEATURE:
++		DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
++			    "SetHubFeature\n");
++		/* No HUB features supported */
++		break;
++	case UCR_SET_PORT_FEATURE:
++		if (wValue != UHF_PORT_TEST && (!wIndex || wIndex > 1))
++			goto error;
++
++		if (!dwc_otg_hcd->flags.b.port_connect_status) {
++			/*
++			 * The port is disconnected, which means the core is
++			 * either in device mode or it soon will be. Just
++			 * return without doing anything since the port
++			 * register can't be written if the core is in device
++			 * mode.
++			 */
++			break;
++		}
++
++		switch (wValue) {
++		case UHF_PORT_SUSPEND:
++			DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
++				    "SetPortFeature - USB_PORT_FEAT_SUSPEND\n");
++			if (dwc_otg_hcd_otg_port(dwc_otg_hcd) != wIndex) {
++				goto error;
++			}
++			if (core_if->power_down == 2) {
++				int timeout = 300;
++				dwc_irqflags_t flags;
++				pcgcctl_data_t pcgcctl = {.d32 = 0 };
++				gpwrdn_data_t gpwrdn = {.d32 = 0 };
++				gusbcfg_data_t gusbcfg = {.d32 = 0 };
++#ifdef DWC_DEV_SRPCAP
++				int32_t otg_cap_param = core_if->core_params->otg_cap;
++#endif
++				DWC_PRINTF("Preparing for complete power-off\n");
++
++				/* Save registers before hibernation */
++				dwc_otg_save_global_regs(core_if);
++				dwc_otg_save_host_regs(core_if);
++
++				hprt0.d32 = dwc_otg_read_hprt0(core_if);
++				hprt0.b.prtsusp = 1;
++				hprt0.b.prtena = 0;
++				DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
++				/* Spin hprt0.b.prtsusp to became 1 */
++				do {
++					hprt0.d32 = dwc_otg_read_hprt0(core_if);
++					if (hprt0.b.prtsusp) {
++						break;
++					}
++					dwc_mdelay(1);
++				} while (--timeout);
++				if (!timeout) {
++					DWC_WARN("Suspend wasn't genereted\n");
++				}
++				dwc_udelay(10);
++
++				/*
++				 * We need to disable interrupts to prevent servicing of any IRQ
++				 * during going to hibernation
++				 */
++				DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &flags);
++				core_if->lx_state = DWC_OTG_L2;
++#ifdef DWC_DEV_SRPCAP
++				hprt0.d32 = dwc_otg_read_hprt0(core_if);
++				hprt0.b.prtpwr = 0;
++				hprt0.b.prtena = 0;
++				DWC_WRITE_REG32(core_if->host_if->hprt0,
++						hprt0.d32);
++#endif
++				gusbcfg.d32 =
++				    DWC_READ_REG32(&core_if->core_global_regs->
++						   gusbcfg);
++				if (gusbcfg.b.ulpi_utmi_sel == 1) {
++					/* ULPI interface */
++					/* Suspend the Phy Clock */
++					pcgcctl.d32 = 0;
++					pcgcctl.b.stoppclk = 1;
++					DWC_MODIFY_REG32(core_if->pcgcctl, 0,
++							 pcgcctl.d32);
++					dwc_udelay(10);
++					gpwrdn.b.pmuactv = 1;
++					DWC_MODIFY_REG32(&core_if->
++							 core_global_regs->
++							 gpwrdn, 0, gpwrdn.d32);
++				} else {
++					/* UTMI+ Interface */
++					gpwrdn.b.pmuactv = 1;
++					DWC_MODIFY_REG32(&core_if->
++							 core_global_regs->
++							 gpwrdn, 0, gpwrdn.d32);
++					dwc_udelay(10);
++					pcgcctl.b.stoppclk = 1;
++					DWC_MODIFY_REG32(core_if->pcgcctl, 0, pcgcctl.d32);
++					dwc_udelay(10);
++				}
++#ifdef DWC_DEV_SRPCAP
++				gpwrdn.d32 = 0;
++				gpwrdn.b.dis_vbus = 1;
++				DWC_MODIFY_REG32(&core_if->core_global_regs->
++						 gpwrdn, 0, gpwrdn.d32);
++#endif
++				gpwrdn.d32 = 0;
++				gpwrdn.b.pmuintsel = 1;
++				DWC_MODIFY_REG32(&core_if->core_global_regs->
++						 gpwrdn, 0, gpwrdn.d32);
++				dwc_udelay(10);
++
++				gpwrdn.d32 = 0;
++#ifdef DWC_DEV_SRPCAP
++				gpwrdn.b.srp_det_msk = 1;
++#endif
++				gpwrdn.b.disconn_det_msk = 1;
++				gpwrdn.b.lnstchng_msk = 1;
++				gpwrdn.b.sts_chngint_msk = 1;
++				DWC_MODIFY_REG32(&core_if->core_global_regs->
++						 gpwrdn, 0, gpwrdn.d32);
++				dwc_udelay(10);
++
++				/* Enable Power Down Clamp and all interrupts in GPWRDN */
++				gpwrdn.d32 = 0;
++				gpwrdn.b.pwrdnclmp = 1;
++				DWC_MODIFY_REG32(&core_if->core_global_regs->
++						 gpwrdn, 0, gpwrdn.d32);
++				dwc_udelay(10);
++
++				/* Switch off VDD */
++				gpwrdn.d32 = 0;
++				gpwrdn.b.pwrdnswtch = 1;
++				DWC_MODIFY_REG32(&core_if->core_global_regs->
++						 gpwrdn, 0, gpwrdn.d32);
++
++#ifdef DWC_DEV_SRPCAP
++				if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE)
++				{
++					core_if->pwron_timer_started = 1;
++					DWC_TIMER_SCHEDULE(core_if->pwron_timer, 6000 /* 6 secs */ );
++				}
++#endif
++				/* Save gpwrdn register for further usage if stschng interrupt */
++				core_if->gr_backup->gpwrdn_local =
++						DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
++
++				/* Set flag to indicate that we are in hibernation */
++				core_if->hibernation_suspend = 1;
++				DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock,flags);
++
++				DWC_PRINTF("Host hibernation completed\n");
++				// Exit from case statement
++				break;
++
++			}
++			if (dwc_otg_hcd_otg_port(dwc_otg_hcd) == wIndex &&
++			    dwc_otg_hcd->fops->get_b_hnp_enable(dwc_otg_hcd)) {
++				gotgctl_data_t gotgctl = {.d32 = 0 };
++				gotgctl.b.hstsethnpen = 1;
++				DWC_MODIFY_REG32(&core_if->core_global_regs->
++						 gotgctl, 0, gotgctl.d32);
++				core_if->op_state = A_SUSPEND;
++			}
++			hprt0.d32 = dwc_otg_read_hprt0(core_if);
++			hprt0.b.prtsusp = 1;
++			DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
++			{
++				dwc_irqflags_t flags;
++				/* Update lx_state */
++				DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &flags);
++				core_if->lx_state = DWC_OTG_L2;
++				DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, flags);
++			}
++			/* Suspend the Phy Clock */
++			if (core_if->otg_ver == 0) {
++				pcgcctl_data_t pcgcctl = {.d32 = 0 };
++				pcgcctl.b.stoppclk = 1;
++				DWC_MODIFY_REG32(core_if->pcgcctl, 0,
++						 pcgcctl.d32);
++				dwc_udelay(10);
++			}
++
++			/* For HNP the bus must be suspended for at least 200ms. */
++			if (dwc_otg_hcd->fops->get_b_hnp_enable(dwc_otg_hcd)) {
++				if (core_if->otg_ver) {
++					pcgcctl_data_t pcgcctl = {.d32 = 0 };
++					pcgcctl.b.stoppclk = 1;
++					DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
++				}
++				dwc_mdelay(200);
++			}
++
++			/** @todo - check how sw can wait for 1 sec to check asesvld??? */
++#if 0 //vahrama !!!!!!!!!!!!!!!!!!
++			if (core_if->adp_enable) {
++				gotgctl_data_t gotgctl = {.d32 = 0 };
++				gpwrdn_data_t gpwrdn;
++
++				while (gotgctl.b.asesvld == 1) {
++					gotgctl.d32 =
++					    DWC_READ_REG32(&core_if->
++							   core_global_regs->
++							   gotgctl);
++					dwc_mdelay(100);
++				}
++
++				/* Enable Power Down Logic */
++				gpwrdn.d32 = 0;
++				gpwrdn.b.pmuactv = 1;
++				DWC_MODIFY_REG32(&core_if->core_global_regs->
++						 gpwrdn, 0, gpwrdn.d32);
++
++				/* Unmask SRP detected interrupt from Power Down Logic */
++				gpwrdn.d32 = 0;
++				gpwrdn.b.srp_det_msk = 1;
++				DWC_MODIFY_REG32(&core_if->core_global_regs->
++						 gpwrdn, 0, gpwrdn.d32);
++
++				dwc_otg_adp_probe_start(core_if);
++			}
++#endif
++			break;
++		case UHF_PORT_POWER:
++			DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
++				    "SetPortFeature - USB_PORT_FEAT_POWER\n");
++			hprt0.d32 = dwc_otg_read_hprt0(core_if);
++			hprt0.b.prtpwr = 1;
++			DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
++			break;
++		case UHF_PORT_RESET:
++			if ((core_if->power_down == 2)
++			    && (core_if->hibernation_suspend == 1)) {
++				/* If we are going to exit from Hibernated
++				 * state via USB RESET.
++				 */
++				dwc_otg_host_hibernation_restore(core_if, 0, 1);
++			} else {
++				hprt0.d32 = dwc_otg_read_hprt0(core_if);
++
++				DWC_DEBUGPL(DBG_HCD,
++					    "DWC OTG HCD HUB CONTROL - "
++					    "SetPortFeature - USB_PORT_FEAT_RESET\n");
++				{
++					pcgcctl_data_t pcgcctl = {.d32 = 0 };
++					pcgcctl.b.enbl_sleep_gating = 1;
++					pcgcctl.b.stoppclk = 1;
++					DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
++					DWC_WRITE_REG32(core_if->pcgcctl, 0);
++				}
++#ifdef CONFIG_USB_DWC_OTG_LPM
++				{
++					glpmcfg_data_t lpmcfg;
++					lpmcfg.d32 =
++						DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
++					if (lpmcfg.b.prt_sleep_sts) {
++						lpmcfg.b.en_utmi_sleep = 0;
++						lpmcfg.b.hird_thres &= (~(1 << 4));
++						DWC_WRITE_REG32
++						    (&core_if->core_global_regs->glpmcfg,
++						     lpmcfg.d32);
++						dwc_mdelay(1);
++					}
++				}
++#endif
++				hprt0.d32 = dwc_otg_read_hprt0(core_if);
++				/* Clear suspend bit if resetting from suspended state. */
++				hprt0.b.prtsusp = 0;
++				/* When B-Host the Port reset bit is set in
++				 * the Start HCD Callback function, so that
++				 * the reset is started within 1ms of the HNP
++				 * success interrupt. */
++				if (!dwc_otg_hcd_is_b_host(dwc_otg_hcd)) {
++					hprt0.b.prtpwr = 1;
++					hprt0.b.prtrst = 1;
++					DWC_PRINTF("Indeed it is in host mode hprt0 = %08x\n",hprt0.d32);
++					DWC_WRITE_REG32(core_if->host_if->hprt0,
++							hprt0.d32);
++				}
++				/* Clear reset bit in 10ms (FS/LS) or 50ms (HS) */
++				dwc_mdelay(60);
++				hprt0.b.prtrst = 0;
++				DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
++				core_if->lx_state = DWC_OTG_L0;	/* Now back to the on state */
++			}
++			break;
++#ifdef DWC_HS_ELECT_TST
++		case UHF_PORT_TEST:
++			{
++				uint32_t t;
++				gintmsk_data_t gintmsk;
++
++				t = (wIndex >> 8);	/* MSB wIndex USB */
++				DWC_DEBUGPL(DBG_HCD,
++					    "DWC OTG HCD HUB CONTROL - "
++					    "SetPortFeature - USB_PORT_FEAT_TEST %d\n",
++					    t);
++				DWC_WARN("USB_PORT_FEAT_TEST %d\n", t);
++				if (t < 6) {
++					hprt0.d32 = dwc_otg_read_hprt0(core_if);
++					hprt0.b.prttstctl = t;
++					DWC_WRITE_REG32(core_if->host_if->hprt0,
++							hprt0.d32);
++				} else {
++					/* Setup global vars with reg addresses (quick and
++					 * dirty hack, should be cleaned up)
++					 */
++					global_regs = core_if->core_global_regs;
++					hc_global_regs =
++					    core_if->host_if->host_global_regs;
++					hc_regs =
++					    (dwc_otg_hc_regs_t *) ((char *)
++								   global_regs +
++								   0x500);
++					data_fifo =
++					    (uint32_t *) ((char *)global_regs +
++							  0x1000);
++
++					if (t == 6) {	/* HS_HOST_PORT_SUSPEND_RESUME */
++						/* Save current interrupt mask */
++						gintmsk.d32 =
++						    DWC_READ_REG32
++						    (&global_regs->gintmsk);
++
++						/* Disable all interrupts while we muck with
++						 * the hardware directly
++						 */
++						DWC_WRITE_REG32(&global_regs->gintmsk, 0);
++
++						/* 15 second delay per the test spec */
++						dwc_mdelay(15000);
++
++						/* Drive suspend on the root port */
++						hprt0.d32 =
++						    dwc_otg_read_hprt0(core_if);
++						hprt0.b.prtsusp = 1;
++						hprt0.b.prtres = 0;
++						DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
++
++						/* 15 second delay per the test spec */
++						dwc_mdelay(15000);
++
++						/* Drive resume on the root port */
++						hprt0.d32 =
++						    dwc_otg_read_hprt0(core_if);
++						hprt0.b.prtsusp = 0;
++						hprt0.b.prtres = 1;
++						DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
++						dwc_mdelay(100);
++
++						/* Clear the resume bit */
++						hprt0.b.prtres = 0;
++						DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
++
++						/* Restore interrupts */
++						DWC_WRITE_REG32(&global_regs->gintmsk, gintmsk.d32);
++					} else if (t == 7) {	/* SINGLE_STEP_GET_DEVICE_DESCRIPTOR setup */
++						/* Save current interrupt mask */
++						gintmsk.d32 =
++						    DWC_READ_REG32
++						    (&global_regs->gintmsk);
++
++						/* Disable all interrupts while we muck with
++						 * the hardware directly
++						 */
++						DWC_WRITE_REG32(&global_regs->gintmsk, 0);
++
++						/* 15 second delay per the test spec */
++						dwc_mdelay(15000);
++
++						/* Send the Setup packet */
++						do_setup();
++
++						/* 15 second delay so nothing else happens for awhile */
++						dwc_mdelay(15000);
++
++						/* Restore interrupts */
++						DWC_WRITE_REG32(&global_regs->gintmsk, gintmsk.d32);
++					} else if (t == 8) {	/* SINGLE_STEP_GET_DEVICE_DESCRIPTOR execute */
++						/* Save current interrupt mask */
++						gintmsk.d32 =
++						    DWC_READ_REG32
++						    (&global_regs->gintmsk);
++
++						/* Disable all interrupts while we muck with
++						 * the hardware directly
++						 */
++						DWC_WRITE_REG32(&global_regs->gintmsk, 0);
++
++						/* Send the Setup packet */
++						do_setup();
++
++						/* 15 second delay so nothing else happens for awhile */
++						dwc_mdelay(15000);
++
++						/* Send the In and Ack packets */
++						do_in_ack();
++
++						/* 15 second delay so nothing else happens for awhile */
++						dwc_mdelay(15000);
++
++						/* Restore interrupts */
++						DWC_WRITE_REG32(&global_regs->gintmsk, gintmsk.d32);
++					}
++				}
++				break;
++			}
++#endif /* DWC_HS_ELECT_TST */
++
++		case UHF_PORT_INDICATOR:
++			DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
++				    "SetPortFeature - USB_PORT_FEAT_INDICATOR\n");
++			/* Not supported */
++			break;
++		default:
++			retval = -DWC_E_INVALID;
++			DWC_ERROR("DWC OTG HCD - "
++				  "SetPortFeature request %xh "
++				  "unknown or unsupported\n", wValue);
++			break;
++		}
++		break;
++#ifdef CONFIG_USB_DWC_OTG_LPM
++	case UCR_SET_AND_TEST_PORT_FEATURE:
++		if (wValue != UHF_PORT_L1) {
++			goto error;
++		}
++		{
++			int portnum, hird, devaddr, remwake;
++			glpmcfg_data_t lpmcfg;
++			uint32_t time_usecs;
++			gintsts_data_t gintsts;
++			gintmsk_data_t gintmsk;
++
++			if (!dwc_otg_get_param_lpm_enable(core_if)) {
++				goto error;
++			}
++			if (wValue != UHF_PORT_L1 || wLength != 1) {
++				goto error;
++			}
++			/* Check if the port currently is in SLEEP state */
++			lpmcfg.d32 =
++			    DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
++			if (lpmcfg.b.prt_sleep_sts) {
++				DWC_INFO("Port is already in sleep mode\n");
++				buf[0] = 0;	/* Return success */
++				break;
++			}
++
++			portnum = wIndex & 0xf;
++			hird = (wIndex >> 4) & 0xf;
++			devaddr = (wIndex >> 8) & 0x7f;
++			remwake = (wIndex >> 15);
++
++			if (portnum != 1) {
++				retval = -DWC_E_INVALID;
++				DWC_WARN
++				    ("Wrong port number(%d) in SetandTestPortFeature request\n",
++				     portnum);
++				break;
++			}
++
++			DWC_PRINTF
++			    ("SetandTestPortFeature request: portnum = %d, hird = %d, devaddr = %d, rewake = %d\n",
++			     portnum, hird, devaddr, remwake);
++			/* Disable LPM interrupt */
++			gintmsk.d32 = 0;
++			gintmsk.b.lpmtranrcvd = 1;
++			DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk,
++					 gintmsk.d32, 0);
++
++			if (dwc_otg_hcd_send_lpm
++			    (dwc_otg_hcd, devaddr, hird, remwake)) {
++				retval = -DWC_E_INVALID;
++				break;
++			}
++
++			time_usecs = 10 * (lpmcfg.b.retry_count + 1);
++			/* We will consider timeout if time_usecs microseconds pass,
++			 * and we don't receive LPM transaction status.
++			 * After receiving non-error responce(ACK/NYET/STALL) from device,
++			 *  core will set lpmtranrcvd bit.
++			 */
++			do {
++				gintsts.d32 =
++				    DWC_READ_REG32(&core_if->core_global_regs->gintsts);
++				if (gintsts.b.lpmtranrcvd) {
++					break;
++				}
++				dwc_udelay(1);
++			} while (--time_usecs);
++			/* lpm_int bit will be cleared in LPM interrupt handler */
++
++			/* Now fill status
++			 * 0x00 - Success
++			 * 0x10 - NYET
++			 * 0x11 - Timeout
++			 */
++			if (!gintsts.b.lpmtranrcvd) {
++				buf[0] = 0x3;	/* Completion code is Timeout */
++				dwc_otg_hcd_free_hc_from_lpm(dwc_otg_hcd);
++			} else {
++				lpmcfg.d32 =
++				    DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
++				if (lpmcfg.b.lpm_resp == 0x3) {
++					/* ACK responce from the device */
++					buf[0] = 0x00;	/* Success */
++				} else if (lpmcfg.b.lpm_resp == 0x2) {
++					/* NYET responce from the device */
++					buf[0] = 0x2;
++				} else {
++					/* Otherwise responce with Timeout */
++					buf[0] = 0x3;
++				}
++			}
++			DWC_PRINTF("Device responce to LPM trans is %x\n",
++				   lpmcfg.b.lpm_resp);
++			DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, 0,
++					 gintmsk.d32);
++
++			break;
++		}
++#endif /* CONFIG_USB_DWC_OTG_LPM */
++	default:
++error:
++		retval = -DWC_E_INVALID;
++		DWC_WARN("DWC OTG HCD - "
++			 "Unknown hub control request type or invalid typeReq: %xh wIndex: %xh wValue: %xh\n",
++			 typeReq, wIndex, wValue);
++		break;
++	}
++
++	return retval;
++}
++
++#ifdef CONFIG_USB_DWC_OTG_LPM
++/** Returns index of host channel to perform LPM transaction. */
++int dwc_otg_hcd_get_hc_for_lpm_tran(dwc_otg_hcd_t * hcd, uint8_t devaddr)
++{
++	dwc_otg_core_if_t *core_if = hcd->core_if;
++	dwc_hc_t *hc;
++	hcchar_data_t hcchar;
++	gintmsk_data_t gintmsk = {.d32 = 0 };
++
++	if (DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) {
++		DWC_PRINTF("No free channel to select for LPM transaction\n");
++		return -1;
++	}
++
++	hc = DWC_CIRCLEQ_FIRST(&hcd->free_hc_list);
++
++	/* Mask host channel interrupts. */
++	gintmsk.b.hcintr = 1;
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, gintmsk.d32, 0);
++
++	/* Fill fields that core needs for LPM transaction */
++	hcchar.b.devaddr = devaddr;
++	hcchar.b.epnum = 0;
++	hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
++	hcchar.b.mps = 64;
++	hcchar.b.lspddev = (hc->speed == DWC_OTG_EP_SPEED_LOW);
++	hcchar.b.epdir = 0;	/* OUT */
++	DWC_WRITE_REG32(&core_if->host_if->hc_regs[hc->hc_num]->hcchar,
++			hcchar.d32);
++
++	/* Remove the host channel from the free list. */
++	DWC_CIRCLEQ_REMOVE_INIT(&hcd->free_hc_list, hc, hc_list_entry);
++
++	DWC_PRINTF("hcnum = %d devaddr = %d\n", hc->hc_num, devaddr);
++
++	return hc->hc_num;
++}
++
++/** Release hc after performing LPM transaction */
++void dwc_otg_hcd_free_hc_from_lpm(dwc_otg_hcd_t * hcd)
++{
++	dwc_hc_t *hc;
++	glpmcfg_data_t lpmcfg;
++	uint8_t hc_num;
++
++	lpmcfg.d32 = DWC_READ_REG32(&hcd->core_if->core_global_regs->glpmcfg);
++	hc_num = lpmcfg.b.lpm_chan_index;
++
++	hc = hcd->hc_ptr_array[hc_num];
++
++	DWC_PRINTF("Freeing channel %d after LPM\n", hc_num);
++	/* Return host channel to free list */
++	DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, hc, hc_list_entry);
++}
++
++int dwc_otg_hcd_send_lpm(dwc_otg_hcd_t * hcd, uint8_t devaddr, uint8_t hird,
++			 uint8_t bRemoteWake)
++{
++	glpmcfg_data_t lpmcfg;
++	pcgcctl_data_t pcgcctl = {.d32 = 0 };
++	int channel;
++
++	channel = dwc_otg_hcd_get_hc_for_lpm_tran(hcd, devaddr);
++	if (channel < 0) {
++		return channel;
++	}
++
++	pcgcctl.b.enbl_sleep_gating = 1;
++	DWC_MODIFY_REG32(hcd->core_if->pcgcctl, 0, pcgcctl.d32);
++
++	/* Read LPM config register */
++	lpmcfg.d32 = DWC_READ_REG32(&hcd->core_if->core_global_regs->glpmcfg);
++
++	/* Program LPM transaction fields */
++	lpmcfg.b.rem_wkup_en = bRemoteWake;
++	lpmcfg.b.hird = hird;
++
++	if(dwc_otg_get_param_besl_enable(hcd->core_if)) {
++		lpmcfg.b.hird_thres = 0x16;
++		lpmcfg.b.en_besl = 1;
++	} else {
++		lpmcfg.b.hird_thres = 0x1c;
++	}
++
++	lpmcfg.b.lpm_chan_index = channel;
++	lpmcfg.b.en_utmi_sleep = 1;
++	/* Program LPM config register */
++	DWC_WRITE_REG32(&hcd->core_if->core_global_regs->glpmcfg, lpmcfg.d32);
++
++	/* Send LPM transaction */
++	lpmcfg.b.send_lpm = 1;
++	DWC_WRITE_REG32(&hcd->core_if->core_global_regs->glpmcfg, lpmcfg.d32);
++
++	return 0;
++}
++
++#endif /* CONFIG_USB_DWC_OTG_LPM */
++
++int dwc_otg_hcd_is_status_changed(dwc_otg_hcd_t * hcd, int port)
++{
++	int retval;
++
++	if (port != 1) {
++		return -DWC_E_INVALID;
++	}
++
++	retval = (hcd->flags.b.port_connect_status_change ||
++		  hcd->flags.b.port_reset_change ||
++		  hcd->flags.b.port_enable_change ||
++		  hcd->flags.b.port_suspend_change ||
++		  hcd->flags.b.port_over_current_change);
++#ifdef DEBUG
++	if (retval) {
++		DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB STATUS DATA:"
++			    " Root port status changed\n");
++		DWC_DEBUGPL(DBG_HCDV, "  port_connect_status_change: %d\n",
++			    hcd->flags.b.port_connect_status_change);
++		DWC_DEBUGPL(DBG_HCDV, "  port_reset_change: %d\n",
++			    hcd->flags.b.port_reset_change);
++		DWC_DEBUGPL(DBG_HCDV, "  port_enable_change: %d\n",
++			    hcd->flags.b.port_enable_change);
++		DWC_DEBUGPL(DBG_HCDV, "  port_suspend_change: %d\n",
++			    hcd->flags.b.port_suspend_change);
++		DWC_DEBUGPL(DBG_HCDV, "  port_over_current_change: %d\n",
++			    hcd->flags.b.port_over_current_change);
++	}
++#endif
++	return retval;
++}
++
++int dwc_otg_hcd_get_frame_number(dwc_otg_hcd_t * dwc_otg_hcd)
++{
++	hfnum_data_t hfnum;
++	hfnum.d32 =
++	    DWC_READ_REG32(&dwc_otg_hcd->core_if->host_if->host_global_regs->
++			   hfnum);
++
++#ifdef DEBUG_SOF
++	DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD GET FRAME NUMBER %d\n",
++		    hfnum.b.frnum);
++#endif
++	return hfnum.b.frnum;
++}
++
++int dwc_otg_hcd_start(dwc_otg_hcd_t * hcd,
++		      struct dwc_otg_hcd_function_ops *fops)
++{
++	int retval = 0;
++	hprt0_data_t hprt0;
++
++	hcd->fops = fops;
++	if (!dwc_otg_is_device_mode(hcd->core_if) &&
++		(!hcd->core_if->adp_enable || hcd->core_if->adp.adp_started)) {
++		dwc_otg_hcd_reinit(hcd);
++	} else {
++		if (hcd->core_if->adp_enable) {
++			/* Clear any interrupt pending in the HPRT, sometimes
++			 * Port Connect Detected is not being cleared*/
++			hprt0.d32 = DWC_READ_REG32(hcd->core_if->host_if->hprt0);
++			DWC_WRITE_REG32(hcd->core_if->host_if->hprt0, hprt0.d32);
++		}
++		retval = -DWC_E_NO_DEVICE;
++	}
++
++	return retval;
++}
++
++void *dwc_otg_hcd_get_priv_data(dwc_otg_hcd_t * hcd)
++{
++	return hcd->priv;
++}
++
++void dwc_otg_hcd_set_priv_data(dwc_otg_hcd_t * hcd, void *priv_data)
++{
++	hcd->priv = priv_data;
++}
++
++uint32_t dwc_otg_hcd_otg_port(dwc_otg_hcd_t * hcd)
++{
++	return hcd->otg_port;
++}
++
++uint32_t dwc_otg_hcd_is_b_host(dwc_otg_hcd_t * hcd)
++{
++	uint32_t is_b_host;
++	if (hcd->core_if->op_state == B_HOST) {
++		is_b_host = 1;
++	} else {
++		is_b_host = 0;
++	}
++
++	return is_b_host;
++}
++
++dwc_otg_hcd_urb_t *dwc_otg_hcd_urb_alloc(dwc_otg_hcd_t * hcd,
++					 int iso_desc_count, int atomic_alloc)
++{
++	dwc_otg_hcd_urb_t *dwc_otg_urb;
++	uint32_t size;
++
++	size =
++	    sizeof(*dwc_otg_urb) +
++	    iso_desc_count * sizeof(struct dwc_otg_hcd_iso_packet_desc);
++	if (atomic_alloc)
++		dwc_otg_urb = DWC_ALLOC_ATOMIC(size);
++	else
++		dwc_otg_urb = DWC_ALLOC(size);
++
++	dwc_otg_urb->packet_count = iso_desc_count;
++
++	return dwc_otg_urb;
++}
++
++void dwc_otg_hcd_urb_set_pipeinfo(dwc_otg_hcd_urb_t * dwc_otg_urb,
++				  uint8_t dev_addr, uint8_t ep_num,
++				  uint8_t ep_type, uint8_t ep_dir, uint16_t mps)
++{
++	dwc_otg_hcd_fill_pipe(&dwc_otg_urb->pipe_info, dev_addr, ep_num,
++			      ep_type, ep_dir, mps);
++#if 0
++	DWC_PRINTF
++	    ("addr = %d, ep_num = %d, ep_dir = 0x%x, ep_type = 0x%x, mps = %d\n",
++	     dev_addr, ep_num, ep_dir, ep_type, mps);
++#endif
++}
++
++void dwc_otg_hcd_urb_set_params(dwc_otg_hcd_urb_t * dwc_otg_urb,
++				void *urb_handle, void *buf, dwc_dma_t dma,
++				uint32_t buflen, void *setup_packet,
++				dwc_dma_t setup_dma, uint32_t flags,
++				uint16_t interval)
++{
++	dwc_otg_urb->priv = urb_handle;
++	dwc_otg_urb->buf = buf;
++	dwc_otg_urb->dma = dma;
++	dwc_otg_urb->length = buflen;
++	dwc_otg_urb->setup_packet = setup_packet;
++	dwc_otg_urb->setup_dma = setup_dma;
++	dwc_otg_urb->flags = flags;
++	dwc_otg_urb->interval = interval;
++	dwc_otg_urb->status = -DWC_E_IN_PROGRESS;
++}
++
++uint32_t dwc_otg_hcd_urb_get_status(dwc_otg_hcd_urb_t * dwc_otg_urb)
++{
++	return dwc_otg_urb->status;
++}
++
++uint32_t dwc_otg_hcd_urb_get_actual_length(dwc_otg_hcd_urb_t * dwc_otg_urb)
++{
++	return dwc_otg_urb->actual_length;
++}
++
++uint32_t dwc_otg_hcd_urb_get_error_count(dwc_otg_hcd_urb_t * dwc_otg_urb)
++{
++	return dwc_otg_urb->error_count;
++}
++
++void dwc_otg_hcd_urb_set_iso_desc_params(dwc_otg_hcd_urb_t * dwc_otg_urb,
++					 int desc_num, uint32_t offset,
++					 uint32_t length)
++{
++	dwc_otg_urb->iso_descs[desc_num].offset = offset;
++	dwc_otg_urb->iso_descs[desc_num].length = length;
++}
++
++uint32_t dwc_otg_hcd_urb_get_iso_desc_status(dwc_otg_hcd_urb_t * dwc_otg_urb,
++					     int desc_num)
++{
++	return dwc_otg_urb->iso_descs[desc_num].status;
++}
++
++uint32_t dwc_otg_hcd_urb_get_iso_desc_actual_length(dwc_otg_hcd_urb_t *
++						    dwc_otg_urb, int desc_num)
++{
++	return dwc_otg_urb->iso_descs[desc_num].actual_length;
++}
++
++int dwc_otg_hcd_is_bandwidth_allocated(dwc_otg_hcd_t * hcd, void *ep_handle)
++{
++	int allocated = 0;
++	dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
++
++	if (qh) {
++		if (!DWC_LIST_EMPTY(&qh->qh_list_entry)) {
++			allocated = 1;
++		}
++	}
++	return allocated;
++}
++
++int dwc_otg_hcd_is_bandwidth_freed(dwc_otg_hcd_t * hcd, void *ep_handle)
++{
++	dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
++	int freed = 0;
++	DWC_ASSERT(qh, "qh is not allocated\n");
++
++	if (DWC_LIST_EMPTY(&qh->qh_list_entry)) {
++		freed = 1;
++	}
++
++	return freed;
++}
++
++uint8_t dwc_otg_hcd_get_ep_bandwidth(dwc_otg_hcd_t * hcd, void *ep_handle)
++{
++	dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
++	DWC_ASSERT(qh, "qh is not allocated\n");
++	return qh->usecs;
++}
++
++void dwc_otg_hcd_dump_state(dwc_otg_hcd_t * hcd)
++{
++#ifdef DEBUG
++	int num_channels;
++	int i;
++	gnptxsts_data_t np_tx_status;
++	hptxsts_data_t p_tx_status;
++
++	num_channels = hcd->core_if->core_params->host_channels;
++	DWC_PRINTF("\n");
++	DWC_PRINTF
++	    ("************************************************************\n");
++	DWC_PRINTF("HCD State:\n");
++	DWC_PRINTF("  Num channels: %d\n", num_channels);
++	for (i = 0; i < num_channels; i++) {
++		dwc_hc_t *hc = hcd->hc_ptr_array[i];
++		DWC_PRINTF("  Channel %d:\n", i);
++		DWC_PRINTF("    dev_addr: %d, ep_num: %d, ep_is_in: %d\n",
++			   hc->dev_addr, hc->ep_num, hc->ep_is_in);
++		DWC_PRINTF("    speed: %d\n", hc->speed);
++		DWC_PRINTF("    ep_type: %d\n", hc->ep_type);
++		DWC_PRINTF("    max_packet: %d\n", hc->max_packet);
++		DWC_PRINTF("    data_pid_start: %d\n", hc->data_pid_start);
++		DWC_PRINTF("    multi_count: %d\n", hc->multi_count);
++		DWC_PRINTF("    xfer_started: %d\n", hc->xfer_started);
++		DWC_PRINTF("    xfer_buff: %p\n", hc->xfer_buff);
++		DWC_PRINTF("    xfer_len: %d\n", hc->xfer_len);
++		DWC_PRINTF("    xfer_count: %d\n", hc->xfer_count);
++		DWC_PRINTF("    halt_on_queue: %d\n", hc->halt_on_queue);
++		DWC_PRINTF("    halt_pending: %d\n", hc->halt_pending);
++		DWC_PRINTF("    halt_status: %d\n", hc->halt_status);
++		DWC_PRINTF("    do_split: %d\n", hc->do_split);
++		DWC_PRINTF("    complete_split: %d\n", hc->complete_split);
++		DWC_PRINTF("    hub_addr: %d\n", hc->hub_addr);
++		DWC_PRINTF("    port_addr: %d\n", hc->port_addr);
++		DWC_PRINTF("    xact_pos: %d\n", hc->xact_pos);
++		DWC_PRINTF("    requests: %d\n", hc->requests);
++		DWC_PRINTF("    qh: %p\n", hc->qh);
++		if (hc->xfer_started) {
++			hfnum_data_t hfnum;
++			hcchar_data_t hcchar;
++			hctsiz_data_t hctsiz;
++			hcint_data_t hcint;
++			hcintmsk_data_t hcintmsk;
++			hfnum.d32 =
++			    DWC_READ_REG32(&hcd->core_if->
++					   host_if->host_global_regs->hfnum);
++			hcchar.d32 =
++			    DWC_READ_REG32(&hcd->core_if->host_if->
++					   hc_regs[i]->hcchar);
++			hctsiz.d32 =
++			    DWC_READ_REG32(&hcd->core_if->host_if->
++					   hc_regs[i]->hctsiz);
++			hcint.d32 =
++			    DWC_READ_REG32(&hcd->core_if->host_if->
++					   hc_regs[i]->hcint);
++			hcintmsk.d32 =
++			    DWC_READ_REG32(&hcd->core_if->host_if->
++					   hc_regs[i]->hcintmsk);
++			DWC_PRINTF("    hfnum: 0x%08x\n", hfnum.d32);
++			DWC_PRINTF("    hcchar: 0x%08x\n", hcchar.d32);
++			DWC_PRINTF("    hctsiz: 0x%08x\n", hctsiz.d32);
++			DWC_PRINTF("    hcint: 0x%08x\n", hcint.d32);
++			DWC_PRINTF("    hcintmsk: 0x%08x\n", hcintmsk.d32);
++		}
++		if (hc->xfer_started && hc->qh) {
++			dwc_otg_qtd_t *qtd;
++			dwc_otg_hcd_urb_t *urb;
++
++			DWC_CIRCLEQ_FOREACH(qtd, &hc->qh->qtd_list, qtd_list_entry) {
++				if (!qtd->in_process)
++					break;
++
++				urb = qtd->urb;
++			DWC_PRINTF("    URB Info:\n");
++			DWC_PRINTF("      qtd: %p, urb: %p\n", qtd, urb);
++			if (urb) {
++				DWC_PRINTF("      Dev: %d, EP: %d %s\n",
++					   dwc_otg_hcd_get_dev_addr(&urb->
++								    pipe_info),
++					   dwc_otg_hcd_get_ep_num(&urb->
++								  pipe_info),
++					   dwc_otg_hcd_is_pipe_in(&urb->
++								  pipe_info) ?
++					   "IN" : "OUT");
++				DWC_PRINTF("      Max packet size: %d\n",
++					   dwc_otg_hcd_get_mps(&urb->
++							       pipe_info));
++				DWC_PRINTF("      transfer_buffer: %p\n",
++					   urb->buf);
++				DWC_PRINTF("      transfer_dma: %p\n",
++					   (void *)urb->dma);
++				DWC_PRINTF("      transfer_buffer_length: %d\n",
++					   urb->length);
++					DWC_PRINTF("      actual_length: %d\n",
++						   urb->actual_length);
++				}
++			}
++		}
++	}
++	DWC_PRINTF("  non_periodic_channels: %d\n", hcd->non_periodic_channels);
++	DWC_PRINTF("  periodic_channels: %d\n", hcd->periodic_channels);
++	DWC_PRINTF("  periodic_usecs: %d\n", hcd->periodic_usecs);
++	np_tx_status.d32 =
++	    DWC_READ_REG32(&hcd->core_if->core_global_regs->gnptxsts);
++	DWC_PRINTF("  NP Tx Req Queue Space Avail: %d\n",
++		   np_tx_status.b.nptxqspcavail);
++	DWC_PRINTF("  NP Tx FIFO Space Avail: %d\n",
++		   np_tx_status.b.nptxfspcavail);
++	p_tx_status.d32 =
++	    DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hptxsts);
++	DWC_PRINTF("  P Tx Req Queue Space Avail: %d\n",
++		   p_tx_status.b.ptxqspcavail);
++	DWC_PRINTF("  P Tx FIFO Space Avail: %d\n", p_tx_status.b.ptxfspcavail);
++	dwc_otg_hcd_dump_frrem(hcd);
++	dwc_otg_dump_global_registers(hcd->core_if);
++	dwc_otg_dump_host_registers(hcd->core_if);
++	DWC_PRINTF
++	    ("************************************************************\n");
++	DWC_PRINTF("\n");
++#endif
++}
++
++#ifdef DEBUG
++void dwc_print_setup_data(uint8_t * setup)
++{
++	int i;
++	if (CHK_DEBUG_LEVEL(DBG_HCD)) {
++		DWC_PRINTF("Setup Data = MSB ");
++		for (i = 7; i >= 0; i--)
++			DWC_PRINTF("%02x ", setup[i]);
++		DWC_PRINTF("\n");
++		DWC_PRINTF("  bmRequestType Tranfer = %s\n",
++			   (setup[0] & 0x80) ? "Device-to-Host" :
++			   "Host-to-Device");
++		DWC_PRINTF("  bmRequestType Type = ");
++		switch ((setup[0] & 0x60) >> 5) {
++		case 0:
++			DWC_PRINTF("Standard\n");
++			break;
++		case 1:
++			DWC_PRINTF("Class\n");
++			break;
++		case 2:
++			DWC_PRINTF("Vendor\n");
++			break;
++		case 3:
++			DWC_PRINTF("Reserved\n");
++			break;
++		}
++		DWC_PRINTF("  bmRequestType Recipient = ");
++		switch (setup[0] & 0x1f) {
++		case 0:
++			DWC_PRINTF("Device\n");
++			break;
++		case 1:
++			DWC_PRINTF("Interface\n");
++			break;
++		case 2:
++			DWC_PRINTF("Endpoint\n");
++			break;
++		case 3:
++			DWC_PRINTF("Other\n");
++			break;
++		default:
++			DWC_PRINTF("Reserved\n");
++			break;
++		}
++		DWC_PRINTF("  bRequest = 0x%0x\n", setup[1]);
++		DWC_PRINTF("  wValue = 0x%0x\n", *((uint16_t *) & setup[2]));
++		DWC_PRINTF("  wIndex = 0x%0x\n", *((uint16_t *) & setup[4]));
++		DWC_PRINTF("  wLength = 0x%0x\n\n", *((uint16_t *) & setup[6]));
++	}
++}
++#endif
++
++void dwc_otg_hcd_dump_frrem(dwc_otg_hcd_t * hcd)
++{
++#if 0
++	DWC_PRINTF("Frame remaining at SOF:\n");
++	DWC_PRINTF("  samples %u, accum %llu, avg %llu\n",
++		   hcd->frrem_samples, hcd->frrem_accum,
++		   (hcd->frrem_samples > 0) ?
++		   hcd->frrem_accum / hcd->frrem_samples : 0);
++
++	DWC_PRINTF("\n");
++	DWC_PRINTF("Frame remaining at start_transfer (uframe 7):\n");
++	DWC_PRINTF("  samples %u, accum %llu, avg %llu\n",
++		   hcd->core_if->hfnum_7_samples,
++		   hcd->core_if->hfnum_7_frrem_accum,
++		   (hcd->core_if->hfnum_7_samples >
++		    0) ? hcd->core_if->hfnum_7_frrem_accum /
++		   hcd->core_if->hfnum_7_samples : 0);
++	DWC_PRINTF("Frame remaining at start_transfer (uframe 0):\n");
++	DWC_PRINTF("  samples %u, accum %llu, avg %llu\n",
++		   hcd->core_if->hfnum_0_samples,
++		   hcd->core_if->hfnum_0_frrem_accum,
++		   (hcd->core_if->hfnum_0_samples >
++		    0) ? hcd->core_if->hfnum_0_frrem_accum /
++		   hcd->core_if->hfnum_0_samples : 0);
++	DWC_PRINTF("Frame remaining at start_transfer (uframe 1-6):\n");
++	DWC_PRINTF("  samples %u, accum %llu, avg %llu\n",
++		   hcd->core_if->hfnum_other_samples,
++		   hcd->core_if->hfnum_other_frrem_accum,
++		   (hcd->core_if->hfnum_other_samples >
++		    0) ? hcd->core_if->hfnum_other_frrem_accum /
++		   hcd->core_if->hfnum_other_samples : 0);
++
++	DWC_PRINTF("\n");
++	DWC_PRINTF("Frame remaining at sample point A (uframe 7):\n");
++	DWC_PRINTF("  samples %u, accum %llu, avg %llu\n",
++		   hcd->hfnum_7_samples_a, hcd->hfnum_7_frrem_accum_a,
++		   (hcd->hfnum_7_samples_a > 0) ?
++		   hcd->hfnum_7_frrem_accum_a / hcd->hfnum_7_samples_a : 0);
++	DWC_PRINTF("Frame remaining at sample point A (uframe 0):\n");
++	DWC_PRINTF("  samples %u, accum %llu, avg %llu\n",
++		   hcd->hfnum_0_samples_a, hcd->hfnum_0_frrem_accum_a,
++		   (hcd->hfnum_0_samples_a > 0) ?
++		   hcd->hfnum_0_frrem_accum_a / hcd->hfnum_0_samples_a : 0);
++	DWC_PRINTF("Frame remaining at sample point A (uframe 1-6):\n");
++	DWC_PRINTF("  samples %u, accum %llu, avg %llu\n",
++		   hcd->hfnum_other_samples_a, hcd->hfnum_other_frrem_accum_a,
++		   (hcd->hfnum_other_samples_a > 0) ?
++		   hcd->hfnum_other_frrem_accum_a /
++		   hcd->hfnum_other_samples_a : 0);
++
++	DWC_PRINTF("\n");
++	DWC_PRINTF("Frame remaining at sample point B (uframe 7):\n");
++	DWC_PRINTF("  samples %u, accum %llu, avg %llu\n",
++		   hcd->hfnum_7_samples_b, hcd->hfnum_7_frrem_accum_b,
++		   (hcd->hfnum_7_samples_b > 0) ?
++		   hcd->hfnum_7_frrem_accum_b / hcd->hfnum_7_samples_b : 0);
++	DWC_PRINTF("Frame remaining at sample point B (uframe 0):\n");
++	DWC_PRINTF("  samples %u, accum %llu, avg %llu\n",
++		   hcd->hfnum_0_samples_b, hcd->hfnum_0_frrem_accum_b,
++		   (hcd->hfnum_0_samples_b > 0) ?
++		   hcd->hfnum_0_frrem_accum_b / hcd->hfnum_0_samples_b : 0);
++	DWC_PRINTF("Frame remaining at sample point B (uframe 1-6):\n");
++	DWC_PRINTF("  samples %u, accum %llu, avg %llu\n",
++		   hcd->hfnum_other_samples_b, hcd->hfnum_other_frrem_accum_b,
++		   (hcd->hfnum_other_samples_b > 0) ?
++		   hcd->hfnum_other_frrem_accum_b /
++		   hcd->hfnum_other_samples_b : 0);
++#endif
++}
++
++#endif /* DWC_DEVICE_ONLY */
+diff --git a/drivers/usb/gadget/udc/hiudc/dwc_otg_hcd.h b/drivers/usb/gadget/udc/hiudc/dwc_otg_hcd.h
+new file mode 100644
+index 0000000..23eea36
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc/dwc_otg_hcd.h
+@@ -0,0 +1,803 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd.h $
++ * $Revision: #58 $
++ * $Date: 2011/09/15 $
++ * $Change: 1846647 $
++ *
++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
++ * ========================================================================== */
++#ifndef DWC_DEVICE_ONLY
++#ifndef __DWC_HCD_H__
++#define __DWC_HCD_H__
++
++#include "dwc_otg_os_dep.h"
++#include "usb.h"
++#include "dwc_otg_hcd_if.h"
++#include "dwc_otg_core_if.h"
++#include "dwc_list.h"
++#include "dwc_otg_cil.h"
++
++/**
++ * @file
++ *
++ * This file contains the structures, constants, and interfaces for
++ * the Host Contoller Driver (HCD).
++ *
++ * The Host Controller Driver (HCD) is responsible for translating requests
++ * from the USB Driver into the appropriate actions on the DWC_otg controller.
++ * It isolates the USBD from the specifics of the controller by providing an
++ * API to the USBD.
++ */
++
++struct dwc_otg_hcd_pipe_info {
++	uint8_t dev_addr;
++	uint8_t ep_num;
++	uint8_t pipe_type;
++	uint8_t pipe_dir;
++	uint16_t mps;
++};
++
++struct dwc_otg_hcd_iso_packet_desc {
++	uint32_t offset;
++	uint32_t length;
++	uint32_t actual_length;
++	uint32_t status;
++};
++
++struct dwc_otg_qtd;
++
++struct dwc_otg_hcd_urb {
++	void *priv;
++	struct dwc_otg_qtd *qtd;
++	void *buf;
++	dwc_dma_t dma;
++	void *setup_packet;
++	dwc_dma_t setup_dma;
++	uint32_t length;
++	uint32_t actual_length;
++	uint32_t status;
++	uint32_t error_count;
++	uint32_t packet_count;
++	uint32_t flags;
++	uint16_t interval;
++	struct dwc_otg_hcd_pipe_info pipe_info;
++	struct dwc_otg_hcd_iso_packet_desc iso_descs[0];
++};
++
++static inline uint8_t dwc_otg_hcd_get_ep_num(struct dwc_otg_hcd_pipe_info *pipe)
++{
++	return pipe->ep_num;
++}
++
++static inline uint8_t dwc_otg_hcd_get_pipe_type(struct dwc_otg_hcd_pipe_info
++						*pipe)
++{
++	return pipe->pipe_type;
++}
++
++static inline uint16_t dwc_otg_hcd_get_mps(struct dwc_otg_hcd_pipe_info *pipe)
++{
++	return pipe->mps;
++}
++
++static inline uint8_t dwc_otg_hcd_get_dev_addr(struct dwc_otg_hcd_pipe_info
++					       *pipe)
++{
++	return pipe->dev_addr;
++}
++
++static inline uint8_t dwc_otg_hcd_is_pipe_isoc(struct dwc_otg_hcd_pipe_info
++					       *pipe)
++{
++	return (pipe->pipe_type == UE_ISOCHRONOUS);
++}
++
++static inline uint8_t dwc_otg_hcd_is_pipe_int(struct dwc_otg_hcd_pipe_info
++					      *pipe)
++{
++	return (pipe->pipe_type == UE_INTERRUPT);
++}
++
++static inline uint8_t dwc_otg_hcd_is_pipe_bulk(struct dwc_otg_hcd_pipe_info
++					       *pipe)
++{
++	return (pipe->pipe_type == UE_BULK);
++}
++
++static inline uint8_t dwc_otg_hcd_is_pipe_control(struct dwc_otg_hcd_pipe_info
++						  *pipe)
++{
++	return (pipe->pipe_type == UE_CONTROL);
++}
++
++static inline uint8_t dwc_otg_hcd_is_pipe_in(struct dwc_otg_hcd_pipe_info *pipe)
++{
++	return (pipe->pipe_dir == UE_DIR_IN);
++}
++
++static inline uint8_t dwc_otg_hcd_is_pipe_out(struct dwc_otg_hcd_pipe_info
++					      *pipe)
++{
++	return (!dwc_otg_hcd_is_pipe_in(pipe));
++}
++
++static inline void dwc_otg_hcd_fill_pipe(struct dwc_otg_hcd_pipe_info *pipe,
++					 uint8_t devaddr, uint8_t ep_num,
++					 uint8_t pipe_type, uint8_t pipe_dir,
++					 uint16_t mps)
++{
++	pipe->dev_addr = devaddr;
++	pipe->ep_num = ep_num;
++	pipe->pipe_type = pipe_type;
++	pipe->pipe_dir = pipe_dir;
++	pipe->mps = mps;
++}
++
++/**
++ * Phases for control transfers.
++ */
++typedef enum dwc_otg_control_phase {
++	DWC_OTG_CONTROL_SETUP,
++	DWC_OTG_CONTROL_DATA,
++	DWC_OTG_CONTROL_STATUS
++} dwc_otg_control_phase_e;
++
++/** Transaction types. */
++typedef enum dwc_otg_transaction_type {
++	DWC_OTG_TRANSACTION_NONE,
++	DWC_OTG_TRANSACTION_PERIODIC,
++	DWC_OTG_TRANSACTION_NON_PERIODIC,
++	DWC_OTG_TRANSACTION_ALL
++} dwc_otg_transaction_type_e;
++
++struct dwc_otg_qh;
++
++/**
++ * A Queue Transfer Descriptor (QTD) holds the state of a bulk, control,
++ * interrupt, or isochronous transfer. A single QTD is created for each URB
++ * (of one of these types) submitted to the HCD. The transfer associated with
++ * a QTD may require one or multiple transactions.
++ *
++ * A QTD is linked to a Queue Head, which is entered in either the
++ * non-periodic or periodic schedule for execution. When a QTD is chosen for
++ * execution, some or all of its transactions may be executed. After
++ * execution, the state of the QTD is updated. The QTD may be retired if all
++ * its transactions are complete or if an error occurred. Otherwise, it
++ * remains in the schedule so more transactions can be executed later.
++ */
++typedef struct dwc_otg_qtd {
++	/**
++	 * Determines the PID of the next data packet for the data phase of
++	 * control transfers. Ignored for other transfer types.<br>
++	 * One of the following values:
++	 *	- DWC_OTG_HC_PID_DATA0
++	 *	- DWC_OTG_HC_PID_DATA1
++	 */
++	uint8_t data_toggle;
++
++	/** Current phase for control transfers (Setup, Data, or Status). */
++	dwc_otg_control_phase_e control_phase;
++
++	/** Keep track of the current split type
++	 * for FS/LS endpoints on a HS Hub */
++	uint8_t complete_split;
++
++	/** How many bytes transferred during SSPLIT OUT */
++	uint32_t ssplit_out_xfer_count;
++
++	/**
++	 * Holds the number of bus errors that have occurred for a transaction
++	 * within this transfer.
++	 */
++	uint8_t error_count;
++
++	/**
++	 * Index of the next frame descriptor for an isochronous transfer. A
++	 * frame descriptor describes the buffer position and length of the
++	 * data to be transferred in the next scheduled (micro)frame of an
++	 * isochronous transfer. It also holds status for that transaction.
++	 * The frame index starts at 0.
++	 */
++	uint16_t isoc_frame_index;
++
++	/** Position of the ISOC split on full/low speed */
++	uint8_t isoc_split_pos;
++
++	/** Position of the ISOC split in the buffer for the current frame */
++	uint16_t isoc_split_offset;
++
++	/** URB for this transfer */
++	struct dwc_otg_hcd_urb *urb;
++
++	struct dwc_otg_qh *qh;
++
++	/** This list of QTDs */
++	 DWC_CIRCLEQ_ENTRY(dwc_otg_qtd) qtd_list_entry;
++
++	/** Indicates if this QTD is currently processed by HW. */
++	uint8_t in_process;
++
++	/** Number of DMA descriptors for this QTD */
++	uint8_t n_desc;
++
++	/**
++	 * Last activated frame(packet) index.
++	 * Used in Descriptor DMA mode only.
++	 */
++	uint16_t isoc_frame_index_last;
++
++} dwc_otg_qtd_t;
++
++DWC_CIRCLEQ_HEAD(dwc_otg_qtd_list, dwc_otg_qtd);
++
++/**
++ * A Queue Head (QH) holds the static characteristics of an endpoint and
++ * maintains a list of transfers (QTDs) for that endpoint. A QH structure may
++ * be entered in either the non-periodic or periodic schedule.
++ */
++typedef struct dwc_otg_qh {
++	/**
++	 * Endpoint type.
++	 * One of the following values:
++	 *	- UE_CONTROL
++	 *	- UE_BULK
++	 *	- UE_INTERRUPT
++	 *	- UE_ISOCHRONOUS
++	 */
++	uint8_t ep_type;
++	uint8_t ep_is_in;
++
++	/** wMaxPacketSize Field of Endpoint Descriptor. */
++	uint16_t maxp;
++
++	/**
++	 * Device speed.
++	 * One of the following values:
++	 *	- DWC_OTG_EP_SPEED_LOW
++	 *	- DWC_OTG_EP_SPEED_FULL
++	 *	- DWC_OTG_EP_SPEED_HIGH
++	 */
++	uint8_t dev_speed;
++
++	/**
++	 * Determines the PID of the next data packet for non-control
++	 * transfers. Ignored for control transfers.<br>
++	 * One of the following values:
++	 *	- DWC_OTG_HC_PID_DATA0
++	 *	- DWC_OTG_HC_PID_DATA1
++	 */
++	uint8_t data_toggle;
++
++	/** Ping state if 1. */
++	uint8_t ping_state;
++
++	/**
++	 * List of QTDs for this QH.
++	 */
++	struct dwc_otg_qtd_list qtd_list;
++
++	/** Host channel currently processing transfers for this QH. */
++	struct dwc_hc *channel;
++
++	/** Full/low speed endpoint on high-speed hub requires split. */
++	uint8_t do_split;
++
++	/** @name Periodic schedule information */
++	/** @{ */
++
++	/** Bandwidth in microseconds per (micro)frame. */
++	uint16_t usecs;
++
++	/** Interval between transfers in (micro)frames. */
++	uint16_t interval;
++
++	/**
++	 * (micro)frame to initialize a periodic transfer. The transfer
++	 * executes in the following (micro)frame.
++	 */
++	uint16_t sched_frame;
++
++	/** (micro)frame at which last start split was initialized. */
++	uint16_t start_split_frame;
++
++	/** @} */
++
++	/**
++	 * Used instead of original buffer if
++	 * it(physical address) is not dword-aligned.
++	 */
++	uint8_t *dw_align_buf;
++	dwc_dma_t dw_align_buf_dma;
++
++	/** Entry for QH in either the periodic or non-periodic schedule. */
++	dwc_list_link_t qh_list_entry;
++
++	/** @name Descriptor DMA support */
++	/** @{ */
++
++	/** Descriptor List. */
++	dwc_otg_host_dma_desc_t *desc_list;
++
++	/** Descriptor List physical address. */
++	dwc_dma_t desc_list_dma;
++
++	/**
++	 * Xfer Bytes array.
++	 * Each element corresponds to a descriptor and indicates
++	 * original XferSize size value for the descriptor.
++	 */
++	uint32_t *n_bytes;
++
++	/** Actual number of transfer descriptors in a list. */
++	uint16_t ntd;
++
++	/** First activated isochronous transfer descriptor index. */
++	uint8_t td_first;
++	/** Last activated isochronous transfer descriptor index. */
++	uint8_t td_last;
++
++	/** @} */
++
++} dwc_otg_qh_t;
++
++DWC_CIRCLEQ_HEAD(hc_list, dwc_hc);
++
++/**
++ * This structure holds the state of the HCD, including the non-periodic and
++ * periodic schedules.
++ */
++struct dwc_otg_hcd {
++	/** The DWC otg device pointer */
++	struct dwc_otg_device *otg_dev;
++	/** DWC OTG Core Interface Layer */
++	dwc_otg_core_if_t *core_if;
++
++	/** Function HCD driver callbacks */
++	struct dwc_otg_hcd_function_ops *fops;
++
++	/** Internal DWC HCD Flags */
++	volatile union dwc_otg_hcd_internal_flags {
++		uint32_t d32;
++		struct {
++			unsigned port_connect_status_change:1;
++			unsigned port_connect_status:1;
++			unsigned port_reset_change:1;
++			unsigned port_enable_change:1;
++			unsigned port_suspend_change:1;
++			unsigned port_over_current_change:1;
++			unsigned port_l1_change:1;
++			unsigned reserved:26;
++		} b;
++	} flags;
++
++	/**
++	 * Inactive items in the non-periodic schedule. This is a list of
++	 * Queue Heads. Transfers associated with these Queue Heads are not
++	 * currently assigned to a host channel.
++	 */
++	dwc_list_link_t non_periodic_sched_inactive;
++
++	/**
++	 * Active items in the non-periodic schedule. This is a list of
++	 * Queue Heads. Transfers associated with these Queue Heads are
++	 * currently assigned to a host channel.
++	 */
++	dwc_list_link_t non_periodic_sched_active;
++
++	/**
++	 * Pointer to the next Queue Head to process in the active
++	 * non-periodic schedule.
++	 */
++	dwc_list_link_t *non_periodic_qh_ptr;
++
++	/**
++	 * Inactive items in the periodic schedule. This is a list of QHs for
++	 * periodic transfers that are _not_ scheduled for the next frame.
++	 * Each QH in the list has an interval counter that determines when it
++	 * needs to be scheduled for execution. This scheduling mechanism
++	 * allows only a simple calculation for periodic bandwidth used (i.e.
++	 * must assume that all periodic transfers may need to execute in the
++	 * same frame). However, it greatly simplifies scheduling and should
++	 * be sufficient for the vast majority of OTG hosts, which need to
++	 * connect to a small number of peripherals at one time.
++	 *
++	 * Items move from this list to periodic_sched_ready when the QH
++	 * interval counter is 0 at SOF.
++	 */
++	dwc_list_link_t periodic_sched_inactive;
++
++	/**
++	 * List of periodic QHs that are ready for execution in the next
++	 * frame, but have not yet been assigned to host channels.
++	 *
++	 * Items move from this list to periodic_sched_assigned as host
++	 * channels become available during the current frame.
++	 */
++	dwc_list_link_t periodic_sched_ready;
++
++	/**
++	 * List of periodic QHs to be executed in the next frame that are
++	 * assigned to host channels.
++	 *
++	 * Items move from this list to periodic_sched_queued as the
++	 * transactions for the QH are queued to the DWC_otg controller.
++	 */
++	dwc_list_link_t periodic_sched_assigned;
++
++	/**
++	 * List of periodic QHs that have been queued for execution.
++	 *
++	 * Items move from this list to either periodic_sched_inactive or
++	 * periodic_sched_ready when the channel associated with the transfer
++	 * is released. If the interval for the QH is 1, the item moves to
++	 * periodic_sched_ready because it must be rescheduled for the next
++	 * frame. Otherwise, the item moves to periodic_sched_inactive.
++	 */
++	dwc_list_link_t periodic_sched_queued;
++
++	/**
++	 * Total bandwidth claimed so far for periodic transfers. This value
++	 * is in microseconds per (micro)frame. The assumption is that all
++	 * periodic transfers may occur in the same (micro)frame.
++	 */
++	uint16_t periodic_usecs;
++
++	/**
++	 * Frame number read from the core at SOF. The value ranges from 0 to
++	 * DWC_HFNUM_MAX_FRNUM.
++	 */
++	uint16_t frame_number;
++
++	/**
++	 * Count of periodic QHs, if using several eps. For SOF enable/disable.
++	 */
++	uint16_t periodic_qh_count;
++
++	/**
++	 * Free host channels in the controller. This is a list of
++	 * dwc_hc_t items.
++	 */
++	struct hc_list free_hc_list;
++	/**
++	 * Number of host channels assigned to periodic transfers. Currently
++	 * assuming that there is a dedicated host channel for each periodic
++	 * transaction and at least one host channel available for
++	 * non-periodic transactions.
++	 */
++	int periodic_channels;
++
++	/**
++	 * Number of host channels assigned to non-periodic transfers.
++	 */
++	int non_periodic_channels;
++
++	/**
++	 * Array of pointers to the host channel descriptors. Allows accessing
++	 * a host channel descriptor given the host channel number. This is
++	 * useful in interrupt handlers.
++	 */
++	struct dwc_hc *hc_ptr_array[MAX_EPS_CHANNELS];
++
++	/**
++	 * Buffer to use for any data received during the status phase of a
++	 * control transfer. Normally no data is transferred during the status
++	 * phase. This buffer is used as a bit bucket.
++	 */
++	uint8_t *status_buf;
++
++	/**
++	 * DMA address for status_buf.
++	 */
++	dma_addr_t status_buf_dma;
++#define DWC_OTG_HCD_STATUS_BUF_SIZE 64
++
++	/**
++	 * Connection timer. An OTG host must display a message if the device
++	 * does not connect. Started when the VBus power is turned on via
++	 * sysfs attribute "buspower".
++	 */
++	dwc_timer_t *conn_timer;
++
++	/* Tasket to do a reset */
++	dwc_tasklet_t *reset_tasklet;
++
++	/*  */
++	dwc_spinlock_t *lock;
++
++	/**
++	 * Private data that could be used by OS wrapper.
++	 */
++	void *priv;
++
++	uint8_t otg_port;
++
++	/** Frame List */
++	uint32_t *frame_list;
++
++	/** Frame List DMA address */
++	dma_addr_t frame_list_dma;
++
++#ifdef DEBUG
++	uint32_t frrem_samples;
++	uint64_t frrem_accum;
++
++	uint32_t hfnum_7_samples_a;
++	uint64_t hfnum_7_frrem_accum_a;
++	uint32_t hfnum_0_samples_a;
++	uint64_t hfnum_0_frrem_accum_a;
++	uint32_t hfnum_other_samples_a;
++	uint64_t hfnum_other_frrem_accum_a;
++
++	uint32_t hfnum_7_samples_b;
++	uint64_t hfnum_7_frrem_accum_b;
++	uint32_t hfnum_0_samples_b;
++	uint64_t hfnum_0_frrem_accum_b;
++	uint32_t hfnum_other_samples_b;
++	uint64_t hfnum_other_frrem_accum_b;
++#endif
++};
++
++/** @name Transaction Execution Functions */
++/** @{ */
++extern dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t
++								  * hcd);
++extern void dwc_otg_hcd_queue_transactions(dwc_otg_hcd_t * hcd,
++					   dwc_otg_transaction_type_e tr_type);
++
++/** @} */
++
++/** @name Interrupt Handler Functions */
++/** @{ */
++extern int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd);
++extern int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * dwc_otg_hcd);
++extern int32_t dwc_otg_hcd_handle_rx_status_q_level_intr(dwc_otg_hcd_t *
++							 dwc_otg_hcd);
++extern int32_t dwc_otg_hcd_handle_np_tx_fifo_empty_intr(dwc_otg_hcd_t *
++							dwc_otg_hcd);
++extern int32_t dwc_otg_hcd_handle_perio_tx_fifo_empty_intr(dwc_otg_hcd_t *
++							   dwc_otg_hcd);
++extern int32_t dwc_otg_hcd_handle_incomplete_periodic_intr(dwc_otg_hcd_t *
++							   dwc_otg_hcd);
++extern int32_t dwc_otg_hcd_handle_port_intr(dwc_otg_hcd_t * dwc_otg_hcd);
++extern int32_t dwc_otg_hcd_handle_conn_id_status_change_intr(dwc_otg_hcd_t *
++							     dwc_otg_hcd);
++extern int32_t dwc_otg_hcd_handle_disconnect_intr(dwc_otg_hcd_t * dwc_otg_hcd);
++extern int32_t dwc_otg_hcd_handle_hc_intr(dwc_otg_hcd_t * dwc_otg_hcd);
++extern int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t * dwc_otg_hcd,
++					    uint32_t num);
++extern int32_t dwc_otg_hcd_handle_session_req_intr(dwc_otg_hcd_t * dwc_otg_hcd);
++extern int32_t dwc_otg_hcd_handle_wakeup_detected_intr(dwc_otg_hcd_t *
++						       dwc_otg_hcd);
++/** @} */
++
++/** @name Schedule Queue Functions */
++/** @{ */
++
++/* Implemented in dwc_otg_hcd_queue.c */
++extern dwc_otg_qh_t *dwc_otg_hcd_qh_create(dwc_otg_hcd_t * hcd,
++					   dwc_otg_hcd_urb_t * urb, int atomic_alloc);
++extern void dwc_otg_hcd_qh_free(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
++extern int dwc_otg_hcd_qh_add(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
++extern void dwc_otg_hcd_qh_remove(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
++extern void dwc_otg_hcd_qh_deactivate(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh,
++				      int sched_csplit);
++
++/** Remove and free a QH */
++static inline void dwc_otg_hcd_qh_remove_and_free(dwc_otg_hcd_t * hcd,
++						  dwc_otg_qh_t * qh)
++{
++	dwc_irqflags_t flags;
++	DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
++	dwc_otg_hcd_qh_remove(hcd, qh);
++	DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
++	dwc_otg_hcd_qh_free(hcd, qh);
++}
++
++/** Allocates memory for a QH structure.
++ * @return Returns the memory allocate or NULL on error. */
++static inline dwc_otg_qh_t *dwc_otg_hcd_qh_alloc(int atomic_alloc)
++{
++	if (atomic_alloc)
++		return (dwc_otg_qh_t *) DWC_ALLOC_ATOMIC(sizeof(dwc_otg_qh_t));
++	else
++		return (dwc_otg_qh_t *) DWC_ALLOC(sizeof(dwc_otg_qh_t));
++}
++
++extern dwc_otg_qtd_t *dwc_otg_hcd_qtd_create(dwc_otg_hcd_urb_t * urb,
++					     int atomic_alloc);
++extern void dwc_otg_hcd_qtd_init(dwc_otg_qtd_t * qtd, dwc_otg_hcd_urb_t * urb);
++extern int dwc_otg_hcd_qtd_add(dwc_otg_qtd_t * qtd, dwc_otg_hcd_t * dwc_otg_hcd,
++			       dwc_otg_qh_t ** qh, int atomic_alloc);
++
++/** Allocates memory for a QTD structure.
++ * @return Returns the memory allocate or NULL on error. */
++static inline dwc_otg_qtd_t *dwc_otg_hcd_qtd_alloc(int atomic_alloc)
++{
++	if (atomic_alloc)
++		return (dwc_otg_qtd_t *) DWC_ALLOC_ATOMIC(sizeof(dwc_otg_qtd_t));
++	else
++		return (dwc_otg_qtd_t *) DWC_ALLOC(sizeof(dwc_otg_qtd_t));
++}
++
++/** Frees the memory for a QTD structure.  QTD should already be removed from
++ * list.
++ * @param qtd QTD to free.*/
++static inline void dwc_otg_hcd_qtd_free(dwc_otg_qtd_t * qtd)
++{
++	DWC_FREE(qtd);
++}
++
++/** Removes a QTD from list.
++ * @param hcd HCD instance.
++ * @param qtd QTD to remove from list.
++ * @param qh QTD belongs to.
++ */
++static inline void dwc_otg_hcd_qtd_remove(dwc_otg_hcd_t * hcd,
++					  dwc_otg_qtd_t * qtd,
++					  dwc_otg_qh_t * qh)
++{
++	DWC_CIRCLEQ_REMOVE(&qh->qtd_list, qtd, qtd_list_entry);
++}
++
++/** Remove and free a QTD
++  * Need to disable IRQ and hold hcd lock while calling this function out of
++  * interrupt servicing chain */
++static inline void dwc_otg_hcd_qtd_remove_and_free(dwc_otg_hcd_t * hcd,
++						   dwc_otg_qtd_t * qtd,
++						   dwc_otg_qh_t * qh)
++{
++	dwc_otg_hcd_qtd_remove(hcd, qtd, qh);
++	dwc_otg_hcd_qtd_free(qtd);
++}
++
++/** @} */
++
++/** @name Descriptor DMA Supporting Functions */
++/** @{ */
++
++extern void dwc_otg_hcd_start_xfer_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
++extern void dwc_otg_hcd_complete_xfer_ddma(dwc_otg_hcd_t * hcd,
++					   dwc_hc_t * hc,
++					   dwc_otg_hc_regs_t * hc_regs,
++					   dwc_otg_halt_status_e halt_status);
++
++extern int dwc_otg_hcd_qh_init_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
++extern void dwc_otg_hcd_qh_free_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
++
++/** @} */
++
++/** @name Internal Functions */
++/** @{ */
++dwc_otg_qh_t *dwc_urb_to_qh(dwc_otg_hcd_urb_t * urb);
++/** @} */
++
++#ifdef CONFIG_USB_DWC_OTG_LPM
++extern int dwc_otg_hcd_get_hc_for_lpm_tran(dwc_otg_hcd_t * hcd,
++					   uint8_t devaddr);
++extern void dwc_otg_hcd_free_hc_from_lpm(dwc_otg_hcd_t * hcd);
++#endif
++
++/** Gets the QH that contains the list_head */
++#define dwc_list_to_qh(_list_head_ptr_) container_of(_list_head_ptr_, dwc_otg_qh_t, qh_list_entry)
++
++/** Gets the QTD that contains the list_head */
++#define dwc_list_to_qtd(_list_head_ptr_) container_of(_list_head_ptr_, dwc_otg_qtd_t, qtd_list_entry)
++
++/** Check if QH is non-periodic  */
++#define dwc_qh_is_non_per(_qh_ptr_) ((_qh_ptr_->ep_type == UE_BULK) || \
++				     (_qh_ptr_->ep_type == UE_CONTROL))
++
++/** High bandwidth multiplier as encoded in highspeed endpoint descriptors */
++#define dwc_hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
++
++/** Packet size for any kind of endpoint descriptor */
++#define dwc_max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff)
++
++/**
++ * Returns true if _frame1 is less than or equal to _frame2. The comparison is
++ * done modulo DWC_HFNUM_MAX_FRNUM. This accounts for the rollover of the
++ * frame number when the max frame number is reached.
++ */
++static inline int dwc_frame_num_le(uint16_t frame1, uint16_t frame2)
++{
++	return ((frame2 - frame1) & DWC_HFNUM_MAX_FRNUM) <=
++	    (DWC_HFNUM_MAX_FRNUM >> 1);
++}
++
++/**
++ * Returns true if _frame1 is greater than _frame2. The comparison is done
++ * modulo DWC_HFNUM_MAX_FRNUM. This accounts for the rollover of the frame
++ * number when the max frame number is reached.
++ */
++static inline int dwc_frame_num_gt(uint16_t frame1, uint16_t frame2)
++{
++	return (frame1 != frame2) &&
++	    (((frame1 - frame2) & DWC_HFNUM_MAX_FRNUM) <
++	     (DWC_HFNUM_MAX_FRNUM >> 1));
++}
++
++/**
++ * Increments _frame by the amount specified by _inc. The addition is done
++ * modulo DWC_HFNUM_MAX_FRNUM. Returns the incremented value.
++ */
++static inline uint16_t dwc_frame_num_inc(uint16_t frame, uint16_t inc)
++{
++	return (frame + inc) & DWC_HFNUM_MAX_FRNUM;
++}
++
++static inline uint16_t dwc_full_frame_num(uint16_t frame)
++{
++	return (frame & DWC_HFNUM_MAX_FRNUM) >> 3;
++}
++
++static inline uint16_t dwc_micro_frame_num(uint16_t frame)
++{
++	return frame & 0x7;
++}
++
++void dwc_otg_hcd_save_data_toggle(dwc_hc_t * hc,
++				  dwc_otg_hc_regs_t * hc_regs,
++				  dwc_otg_qtd_t * qtd);
++
++#ifdef DEBUG
++/**
++ * Macro to sample the remaining PHY clocks left in the current frame. This
++ * may be used during debugging to determine the average time it takes to
++ * execute sections of code. There are two possible sample points, "a" and
++ * "b", so the _letter argument must be one of these values.
++ *
++ * To dump the average sample times, read the "hcd_frrem" sysfs attribute. For
++ * example, "cat /sys/devices/lm0/hcd_frrem".
++ */
++#define dwc_sample_frrem(_hcd, _qh, _letter) \
++{ \
++	hfnum_data_t hfnum; \
++	dwc_otg_qtd_t *qtd; \
++	qtd = list_entry(_qh->qtd_list.next, dwc_otg_qtd_t, qtd_list_entry); \
++	if (usb_pipeint(qtd->urb->pipe) && _qh->start_split_frame != 0 && !qtd->complete_split) { \
++		hfnum.d32 = DWC_READ_REG32(&_hcd->core_if->host_if->host_global_regs->hfnum); \
++		switch (hfnum.b.frnum & 0x7) { \
++		case 7: \
++			_hcd->hfnum_7_samples_##_letter++; \
++			_hcd->hfnum_7_frrem_accum_##_letter += hfnum.b.frrem; \
++			break; \
++		case 0: \
++			_hcd->hfnum_0_samples_##_letter++; \
++			_hcd->hfnum_0_frrem_accum_##_letter += hfnum.b.frrem; \
++			break; \
++		default: \
++			_hcd->hfnum_other_samples_##_letter++; \
++			_hcd->hfnum_other_frrem_accum_##_letter += hfnum.b.frrem; \
++			break; \
++		} \
++	} \
++}
++#else
++#define dwc_sample_frrem(_hcd, _qh, _letter)
++#endif
++#endif
++#endif /* DWC_DEVICE_ONLY */
+diff --git a/drivers/usb/gadget/udc/hiudc/dwc_otg_hcd_ddma.c b/drivers/usb/gadget/udc/hiudc/dwc_otg_hcd_ddma.c
+new file mode 100644
+index 0000000..fd20354
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc/dwc_otg_hcd_ddma.c
+@@ -0,0 +1,1122 @@
++/*==========================================================================
++ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_ddma.c $
++ * $Revision: #11 $
++ * $Date: 2013/01/24 $
++ * $Change: 2150761 $
++ *
++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
++ * ========================================================================== */
++#ifndef DWC_DEVICE_ONLY
++
++/** @file
++ * This file contains Descriptor DMA support implementation for host mode.
++ */
++
++#include "dwc_otg_hcd.h"
++#include "dwc_otg_regs.h"
++
++static inline uint8_t frame_list_idx(uint16_t frame)
++{
++	return (frame & (MAX_FRLIST_EN_NUM - 1));
++}
++
++static inline uint16_t desclist_idx_inc(uint16_t idx, uint16_t inc, uint8_t speed)
++{
++	return (idx + inc) &
++	    (((speed ==
++	       DWC_OTG_EP_SPEED_HIGH) ? MAX_DMA_DESC_NUM_HS_ISOC :
++	      MAX_DMA_DESC_NUM_GENERIC) - 1);
++}
++
++static inline uint16_t desclist_idx_dec(uint16_t idx, uint16_t inc, uint8_t speed)
++{
++	return (idx - inc) &
++	    (((speed ==
++	       DWC_OTG_EP_SPEED_HIGH) ? MAX_DMA_DESC_NUM_HS_ISOC :
++	      MAX_DMA_DESC_NUM_GENERIC) - 1);
++}
++
++static inline uint16_t max_desc_num(dwc_otg_qh_t * qh)
++{
++	return (((qh->ep_type == UE_ISOCHRONOUS)
++		 && (qh->dev_speed == DWC_OTG_EP_SPEED_HIGH))
++		? MAX_DMA_DESC_NUM_HS_ISOC : MAX_DMA_DESC_NUM_GENERIC);
++}
++static inline uint16_t frame_incr_val(dwc_otg_qh_t * qh)
++{
++	return ((qh->dev_speed == DWC_OTG_EP_SPEED_HIGH)
++		? ((qh->interval + 8 - 1) / 8)
++		: qh->interval);
++}
++
++static int desc_list_alloc(dwc_otg_qh_t * qh)
++{
++	int retval = 0;
++
++	qh->desc_list = (dwc_otg_host_dma_desc_t *)
++	    DWC_DMA_ALLOC(sizeof(dwc_otg_host_dma_desc_t) * max_desc_num(qh),
++			  &qh->desc_list_dma);
++
++	if (!qh->desc_list) {
++		retval = -DWC_E_NO_MEMORY;
++		DWC_ERROR("%s: DMA descriptor list allocation failed\n", __func__);
++
++	}
++
++	dwc_memset(qh->desc_list, 0x00,
++		   sizeof(dwc_otg_host_dma_desc_t) * max_desc_num(qh));
++
++	qh->n_bytes =
++	    (uint32_t *) DWC_ALLOC(sizeof(uint32_t) * max_desc_num(qh));
++
++	if (!qh->n_bytes) {
++		retval = -DWC_E_NO_MEMORY;
++		DWC_ERROR
++		    ("%s: Failed to allocate array for descriptors' size actual values\n",
++		     __func__);
++
++	}
++	return retval;
++
++}
++
++static void desc_list_free(dwc_otg_qh_t * qh)
++{
++	if (qh->desc_list) {
++		DWC_DMA_FREE(max_desc_num(qh), qh->desc_list,
++			     qh->desc_list_dma);
++		qh->desc_list = NULL;
++	}
++
++	if (qh->n_bytes) {
++		DWC_FREE(qh->n_bytes);
++		qh->n_bytes = NULL;
++	}
++}
++
++static int frame_list_alloc(dwc_otg_hcd_t * hcd)
++{
++	int retval = 0;
++	if (hcd->frame_list)
++		return 0;
++
++	hcd->frame_list = DWC_DMA_ALLOC(4 * MAX_FRLIST_EN_NUM,
++					&hcd->frame_list_dma);
++	if (!hcd->frame_list) {
++		retval = -DWC_E_NO_MEMORY;
++		DWC_ERROR("%s: Frame List allocation failed\n", __func__);
++	}
++
++	dwc_memset(hcd->frame_list, 0x00, 4 * MAX_FRLIST_EN_NUM);
++
++	return retval;
++}
++
++static void frame_list_free(dwc_otg_hcd_t * hcd)
++{
++	if (!hcd->frame_list)
++		return;
++
++	DWC_DMA_FREE(4 * MAX_FRLIST_EN_NUM, hcd->frame_list, hcd->frame_list_dma);
++	hcd->frame_list = NULL;
++}
++
++static void per_sched_enable(dwc_otg_hcd_t * hcd, uint16_t fr_list_en)
++{
++
++	hcfg_data_t hcfg;
++
++	hcfg.d32 = DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hcfg);
++
++	if (hcfg.b.perschedena) {
++		/* already enabled */
++		return;
++	}
++
++	DWC_WRITE_REG32(&hcd->core_if->host_if->host_global_regs->hflbaddr,
++			hcd->frame_list_dma);
++
++	switch (fr_list_en) {
++	case 64:
++		hcfg.b.frlisten = 3;
++		break;
++	case 32:
++		hcfg.b.frlisten = 2;
++		break;
++	case 16:
++		hcfg.b.frlisten = 1;
++		break;
++	case 8:
++		hcfg.b.frlisten = 0;
++		break;
++	default:
++		break;
++	}
++
++	hcfg.b.perschedena = 1;
++
++	DWC_DEBUGPL(DBG_HCD, "Enabling Periodic schedule\n");
++	DWC_WRITE_REG32(&hcd->core_if->host_if->host_global_regs->hcfg, hcfg.d32);
++
++}
++
++static void per_sched_disable(dwc_otg_hcd_t * hcd)
++{
++	hcfg_data_t hcfg;
++
++	hcfg.d32 = DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hcfg);
++
++	if (!hcfg.b.perschedena) {
++		/* already disabled */
++		return;
++	}
++	hcfg.b.perschedena = 0;
++
++	DWC_DEBUGPL(DBG_HCD, "Disabling Periodic schedule\n");
++	DWC_WRITE_REG32(&hcd->core_if->host_if->host_global_regs->hcfg, hcfg.d32);
++}
++
++/*
++ * Activates/Deactivates FrameList entries for the channel
++ * based on endpoint servicing period.
++ */
++void update_frame_list(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, uint8_t enable)
++{
++	uint16_t i, j, inc;
++	dwc_hc_t *hc = NULL;
++
++	if (!qh->channel) {
++		DWC_ERROR("qh->channel = %p", qh->channel);
++		return;
++	}
++
++	if (!hcd) {
++		DWC_ERROR("------hcd = %p", hcd);
++		return;
++	}
++
++	if (!hcd->frame_list) {
++		DWC_ERROR("-------hcd->frame_list = %p", hcd->frame_list);
++		return;
++	}
++
++	hc = qh->channel;
++	inc = frame_incr_val(qh);
++	if (qh->ep_type == UE_ISOCHRONOUS)
++		i = frame_list_idx(qh->sched_frame);
++	else
++		i = 0;
++
++	j = i;
++	do {
++		if (enable)
++			hcd->frame_list[j] |= (1 << hc->hc_num);
++		else
++			hcd->frame_list[j] &= ~(1 << hc->hc_num);
++		j = (j + inc) & (MAX_FRLIST_EN_NUM - 1);
++	}
++	while (j != i);
++	if (!enable)
++		return;
++	hc->schinfo = 0;
++	if (qh->channel->speed == DWC_OTG_EP_SPEED_HIGH) {
++		j = 1;
++		/* TODO - check this */
++		inc = (8 + qh->interval - 1) / qh->interval;
++		for (i = 0; i < inc; i++) {
++			hc->schinfo |= j;
++			j = j << qh->interval;
++		}
++	} else {
++		hc->schinfo = 0xff;
++	}
++}
++
++#if 1
++void dump_frame_list(dwc_otg_hcd_t * hcd)
++{
++	int i = 0;
++	DWC_PRINTF("--FRAME LIST (hex) --\n");
++	for (i = 0; i < MAX_FRLIST_EN_NUM; i++) {
++		DWC_PRINTF("%x\t", hcd->frame_list[i]);
++		if (!(i % 8) && i)
++			DWC_PRINTF("\n");
++	}
++	DWC_PRINTF("\n----\n");
++
++}
++#endif
++
++static void release_channel_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
++{
++	dwc_hc_t *hc = qh->channel;
++	if (dwc_qh_is_non_per(qh))
++		hcd->non_periodic_channels--;
++	else
++		update_frame_list(hcd, qh, 0);
++
++	/*
++	 * The condition is added to prevent double cleanup try in case of device
++	 * disconnect. See channel cleanup in dwc_otg_hcd_disconnect_cb().
++	 */
++	if (hc->qh) {
++		dwc_otg_hc_cleanup(hcd->core_if, hc);
++		DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, hc, hc_list_entry);
++		hc->qh = NULL;
++	}
++
++	qh->channel = NULL;
++	qh->ntd = 0;
++
++	if (qh->desc_list) {
++		dwc_memset(qh->desc_list, 0x00,
++			   sizeof(dwc_otg_host_dma_desc_t) * max_desc_num(qh));
++	}
++}
++
++/**
++ * Initializes a QH structure's Descriptor DMA related members.
++ * Allocates memory for descriptor list.
++ * On first periodic QH, allocates memory for FrameList
++ * and enables periodic scheduling.
++ *
++ * @param hcd The HCD state structure for the DWC OTG controller.
++ * @param qh The QH to init.
++ *
++ * @return 0 if successful, negative error code otherwise.
++ */
++int dwc_otg_hcd_qh_init_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
++{
++	int retval = 0;
++
++	if (qh->do_split) {
++		DWC_ERROR("SPLIT Transfers are not supported in Descriptor DMA.\n");
++		return -1;
++	}
++
++	retval = desc_list_alloc(qh);
++
++	if ((retval == 0)
++	    && (qh->ep_type == UE_ISOCHRONOUS || qh->ep_type == UE_INTERRUPT)) {
++		if (!hcd->frame_list) {
++			retval = frame_list_alloc(hcd);
++			/* Enable periodic schedule on first periodic QH */
++			if (retval == 0)
++				per_sched_enable(hcd, MAX_FRLIST_EN_NUM);
++		}
++	}
++
++	qh->ntd = 0;
++
++	return retval;
++}
++
++/**
++ * Frees descriptor list memory associated with the QH.
++ * If QH is periodic and the last, frees FrameList memory
++ * and disables periodic scheduling.
++ *
++ * @param hcd The HCD state structure for the DWC OTG controller.
++ * @param qh The QH to init.
++ */
++void dwc_otg_hcd_qh_free_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
++{
++	desc_list_free(qh);
++
++	/*
++	 * Channel still assigned due to some reasons.
++	 * Seen on Isoc URB dequeue. Channel halted but no subsequent
++	 * ChHalted interrupt to release the channel. Afterwards
++	 * when it comes here from endpoint disable routine
++	 * channel remains assigned.
++	 */
++	if (qh->channel)
++		release_channel_ddma(hcd, qh);
++
++	if ((qh->ep_type == UE_ISOCHRONOUS || qh->ep_type == UE_INTERRUPT)
++	    && !hcd->periodic_channels && hcd->frame_list) {
++
++		per_sched_disable(hcd);
++		frame_list_free(hcd);
++	}
++}
++
++static uint8_t frame_to_desc_idx(dwc_otg_qh_t * qh, uint16_t frame_idx)
++{
++	if (qh->dev_speed == DWC_OTG_EP_SPEED_HIGH) {
++		/*
++		 * Descriptor set(8 descriptors) index
++		 * which is 8-aligned.
++		 */
++		return (frame_idx & ((MAX_DMA_DESC_NUM_HS_ISOC / 8) - 1)) * 8;
++	} else {
++		return (frame_idx & (MAX_DMA_DESC_NUM_GENERIC - 1));
++	}
++}
++
++/*
++ * Determine starting frame for Isochronous transfer.
++ * Few frames skipped to prevent race condition with HC.
++ */
++static uint8_t calc_starting_frame(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh,
++				   uint8_t * skip_frames)
++{
++	uint16_t frame = 0;
++	hcd->frame_number = dwc_otg_hcd_get_frame_number(hcd);
++
++	/* sched_frame is always frame number(not uFrame) both in FS and HS !! */
++
++	/*
++	 * skip_frames is used to limit activated descriptors number
++	 * to avoid the situation when HC services the last activated
++	 * descriptor firstly.
++	 * Example for FS:
++	 * Current frame is 1, scheduled frame is 3. Since HC always fetches the descriptor
++	 * corresponding to curr_frame+1, the descriptor corresponding to frame 2
++	 * will be fetched. If the number of descriptors is max=64 (or greather) the
++	 * list will be fully programmed with Active descriptors and it is possible
++	 * case(rare) that the latest descriptor(considering rollback) corresponding
++	 * to frame 2 will be serviced first. HS case is more probable because, in fact,
++	 * up to 11 uframes(16 in the code) may be skipped.
++	 */
++	if (qh->dev_speed == DWC_OTG_EP_SPEED_HIGH) {
++		/*
++		 * Consider uframe counter also, to start xfer asap.
++		 * If half of the frame elapsed skip 2 frames otherwise
++		 * just 1 frame.
++		 * Starting descriptor index must be 8-aligned, so
++		 * if the current frame is near to complete the next one
++		 * is skipped as well.
++		 */
++
++		if (dwc_micro_frame_num(hcd->frame_number) >= 5) {
++			*skip_frames = 2 * 8;
++			frame = dwc_frame_num_inc(hcd->frame_number, *skip_frames);
++		} else {
++			*skip_frames = 1 * 8;
++			frame = dwc_frame_num_inc(hcd->frame_number, *skip_frames);
++		}
++
++		frame = dwc_full_frame_num(frame);
++	} else {
++		/*
++		 * Two frames are skipped for FS - the current and the next.
++		 * But for descriptor programming, 1 frame(descriptor) is enough,
++		 * see example above.
++		 */
++		*skip_frames = 1;
++		frame = dwc_frame_num_inc(hcd->frame_number, 2);
++	}
++
++	return frame;
++}
++
++/*
++ * Calculate initial descriptor index for isochronous transfer
++ * based on scheduled frame.
++ */
++static uint8_t recalc_initial_desc_idx(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
++{
++	uint16_t frame = 0, fr_idx, fr_idx_tmp;
++	uint8_t skip_frames = 0;
++	/*
++	 * With current ISOC processing algorithm the channel is being
++	 * released when no more QTDs in the list(qh->ntd == 0).
++	 * Thus this function is called only when qh->ntd == 0 and qh->channel == 0.
++	 *
++	 * So qh->channel != NULL branch is not used and just not removed from the
++	 * source file. It is required for another possible approach which is,
++	 * do not disable and release the channel when ISOC session completed,
++	 * just move QH to inactive schedule until new QTD arrives.
++	 * On new QTD, the QH moved back to 'ready' schedule,
++	 * starting frame and therefore starting desc_index are recalculated.
++	 * In this case channel is released only on ep_disable.
++	 */
++
++	/* Calculate starting descriptor index. For INTERRUPT endpoint it is always 0. */
++	if (qh->channel) {
++		frame = calc_starting_frame(hcd, qh, &skip_frames);
++		/*
++		 * Calculate initial descriptor index based on FrameList current bitmap
++		 * and servicing period.
++		 */
++		fr_idx_tmp = frame_list_idx(frame);
++		fr_idx =
++		    (MAX_FRLIST_EN_NUM + frame_list_idx(qh->sched_frame) -
++		     fr_idx_tmp)
++		    % frame_incr_val(qh);
++		fr_idx = (fr_idx + fr_idx_tmp) % MAX_FRLIST_EN_NUM;
++	} else {
++		qh->sched_frame = calc_starting_frame(hcd, qh, &skip_frames);
++		fr_idx = frame_list_idx(qh->sched_frame);
++	}
++
++	qh->td_first = qh->td_last = frame_to_desc_idx(qh, fr_idx);
++
++	return skip_frames;
++}
++
++#define	ISOC_URB_GIVEBACK_ASAP
++
++#define MAX_ISOC_XFER_SIZE_FS 1023
++#define MAX_ISOC_XFER_SIZE_HS 3072
++#define DESCNUM_THRESHOLD 4
++
++static void init_isoc_dma_desc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh,
++			       uint8_t skip_frames)
++{
++	struct dwc_otg_hcd_iso_packet_desc *frame_desc;
++	dwc_otg_qtd_t *qtd;
++	dwc_otg_host_dma_desc_t *dma_desc;
++	uint16_t idx, inc, n_desc, ntd_max, max_xfer_size;
++
++	idx = qh->td_last;
++	inc = qh->interval;
++	n_desc = 0;
++
++	ntd_max = (max_desc_num(qh) + qh->interval - 1) / qh->interval;
++	if (skip_frames && !qh->channel)
++		ntd_max = ntd_max - skip_frames / qh->interval;
++
++	max_xfer_size =
++	    (qh->dev_speed ==
++	     DWC_OTG_EP_SPEED_HIGH) ? MAX_ISOC_XFER_SIZE_HS :
++	    MAX_ISOC_XFER_SIZE_FS;
++
++	DWC_CIRCLEQ_FOREACH(qtd, &qh->qtd_list, qtd_list_entry) {
++		while ((qh->ntd < ntd_max)
++		       && (qtd->isoc_frame_index_last <
++			   qtd->urb->packet_count)) {
++
++			dma_desc = &qh->desc_list[idx];
++			dwc_memset(dma_desc, 0x00, sizeof(dwc_otg_host_dma_desc_t));
++
++			frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index_last];
++
++			if (frame_desc->length > max_xfer_size)
++				qh->n_bytes[idx] = max_xfer_size;
++			else
++				qh->n_bytes[idx] = frame_desc->length;
++			dma_desc->status.b_isoc.n_bytes = qh->n_bytes[idx];
++			dma_desc->status.b_isoc.a = 1;
++			dma_desc->status.b_isoc.sts = 0;
++
++			dma_desc->buf = qtd->urb->dma + frame_desc->offset;
++
++			qh->ntd++;
++
++			qtd->isoc_frame_index_last++;
++
++#ifdef	ISOC_URB_GIVEBACK_ASAP
++			/*
++			 * Set IOC for each descriptor corresponding to the
++			 * last frame of the URB.
++			 */
++			if (qtd->isoc_frame_index_last ==
++			    qtd->urb->packet_count)
++				dma_desc->status.b_isoc.ioc = 1;
++
++#endif
++			idx = desclist_idx_inc(idx, inc, qh->dev_speed);
++			n_desc++;
++
++		}
++		qtd->in_process = 1;
++	}
++
++	qh->td_last = idx;
++
++#ifdef	ISOC_URB_GIVEBACK_ASAP
++	/* Set IOC for the last descriptor if descriptor list is full */
++	if (qh->ntd == ntd_max) {
++		idx = desclist_idx_dec(qh->td_last, inc, qh->dev_speed);
++		qh->desc_list[idx].status.b_isoc.ioc = 1;
++	}
++#else
++	/*
++	 * Set IOC bit only for one descriptor.
++	 * Always try to be ahead of HW processing,
++	 * i.e. on IOC generation driver activates next descriptors but
++	 * core continues to process descriptors followed the one with IOC set.
++	 */
++
++	if (n_desc > DESCNUM_THRESHOLD) {
++		/*
++		 * Move IOC "up". Required even if there is only one QTD
++		 * in the list, cause QTDs migth continue to be queued,
++		 * but during the activation it was only one queued.
++		 * Actually more than one QTD might be in the list if this function called
++		 * from XferCompletion - QTDs was queued during HW processing of the previous
++		 * descriptor chunk.
++		 */
++		idx = dwc_desclist_idx_dec(idx, inc * ((qh->ntd + 1) / 2), qh->dev_speed);
++	} else {
++		/*
++		 * Set the IOC for the latest descriptor
++		 * if either number of descriptor is not greather than threshold
++		 * or no more new descriptors activated.
++		 */
++		idx = dwc_desclist_idx_dec(qh->td_last, inc, qh->dev_speed);
++	}
++
++	qh->desc_list[idx].status.b_isoc.ioc = 1;
++#endif
++}
++
++static void init_non_isoc_dma_desc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
++{
++
++	dwc_hc_t *hc;
++	dwc_otg_host_dma_desc_t *dma_desc;
++	dwc_otg_qtd_t *qtd;
++	int num_packets, len, n_desc = 0;
++
++	hc = qh->channel;
++
++	/*
++	 * Start with hc->xfer_buff initialized in
++	 * assign_and_init_hc(), then if SG transfer consists of multiple URBs,
++	 * this pointer re-assigned to the buffer of the currently processed QTD.
++	 * For non-SG request there is always one QTD active.
++	 */
++
++	DWC_CIRCLEQ_FOREACH(qtd, &qh->qtd_list, qtd_list_entry) {
++
++		if (n_desc) {
++			/* SG request - more than 1 QTDs */
++			hc->xfer_buff = (uint8_t *)qtd->urb->dma + qtd->urb->actual_length;
++			hc->xfer_len = qtd->urb->length - qtd->urb->actual_length;
++		}
++
++		qtd->n_desc = 0;
++
++		do {
++			dma_desc = &qh->desc_list[n_desc];
++			len = hc->xfer_len;
++
++			if (len > MAX_DMA_DESC_SIZE)
++				len = MAX_DMA_DESC_SIZE - hc->max_packet + 1;
++
++			if (hc->ep_is_in) {
++				if (len > 0) {
++					num_packets = (len + hc->max_packet - 1) / hc->max_packet;
++				} else {
++					/* Need 1 packet for transfer length of 0. */
++					num_packets = 1;
++				}
++				/* Always program an integral # of max packets for IN transfers. */
++				len = num_packets * hc->max_packet;
++			}
++
++			dma_desc->status.b.n_bytes = len;
++
++			qh->n_bytes[n_desc] = len;
++
++			if ((qh->ep_type == UE_CONTROL)
++			    && (qtd->control_phase == DWC_OTG_CONTROL_SETUP))
++				dma_desc->status.b.sup = 1;	/* Setup Packet */
++
++			dma_desc->status.b.a = 1;	/* Active descriptor */
++			dma_desc->status.b.sts = 0;
++
++			dma_desc->buf =
++			    ((unsigned long)hc->xfer_buff & 0xffffffff);
++
++			/*
++			 * Last descriptor(or single) of IN transfer
++			 * with actual size less than MaxPacket.
++			 */
++			if (len > hc->xfer_len) {
++				hc->xfer_len = 0;
++			} else {
++				hc->xfer_buff += len;
++				hc->xfer_len -= len;
++			}
++
++			qtd->n_desc++;
++			n_desc++;
++		}
++		while ((hc->xfer_len > 0) && (n_desc != MAX_DMA_DESC_NUM_GENERIC));
++
++
++		qtd->in_process = 1;
++
++		if (qh->ep_type == UE_CONTROL)
++			break;
++
++		if (n_desc == MAX_DMA_DESC_NUM_GENERIC)
++			break;
++	}
++
++	if (n_desc) {
++		/* Request Transfer Complete interrupt for the last descriptor */
++		qh->desc_list[n_desc - 1].status.b.ioc = 1;
++		/* End of List indicator */
++		qh->desc_list[n_desc - 1].status.b.eol = 1;
++
++		hc->ntd = n_desc;
++	}
++}
++
++/**
++ * For Control and Bulk endpoints initializes descriptor list
++ * and starts the transfer.
++ *
++ * For Interrupt and Isochronous endpoints initializes descriptor list
++ * then updates FrameList, marking appropriate entries as active.
++ * In case of Isochronous, the starting descriptor index is calculated based
++ * on the scheduled frame, but only on the first transfer descriptor within a session.
++ * Then starts the transfer via enabling the channel.
++ * For Isochronous endpoint the channel is not halted on XferComplete
++ * interrupt so remains assigned to the endpoint(QH) until session is done.
++ *
++ * @param hcd The HCD state structure for the DWC OTG controller.
++ * @param qh The QH to init.
++ *
++ * @return 0 if successful, negative error code otherwise.
++ */
++void dwc_otg_hcd_start_xfer_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
++{
++	/* Channel is already assigned */
++	dwc_hc_t *hc = qh->channel;
++	uint8_t skip_frames = 0;
++
++	switch (hc->ep_type) {
++	case DWC_OTG_EP_TYPE_CONTROL:
++	case DWC_OTG_EP_TYPE_BULK:
++		init_non_isoc_dma_desc(hcd, qh);
++
++		dwc_otg_hc_start_transfer_ddma(hcd->core_if, hc);
++		break;
++	case DWC_OTG_EP_TYPE_INTR:
++		init_non_isoc_dma_desc(hcd, qh);
++
++		update_frame_list(hcd, qh, 1);
++
++		dwc_otg_hc_start_transfer_ddma(hcd->core_if, hc);
++		break;
++	case DWC_OTG_EP_TYPE_ISOC:
++
++		if (!qh->ntd)
++			skip_frames = recalc_initial_desc_idx(hcd, qh);
++
++		init_isoc_dma_desc(hcd, qh, skip_frames);
++
++		if (!hc->xfer_started) {
++
++			update_frame_list(hcd, qh, 1);
++
++			/*
++			 * Always set to max, instead of actual size.
++			 * Otherwise ntd will be changed with
++			 * channel being enabled. Not recommended.
++			 *
++			 */
++			hc->ntd = max_desc_num(qh);
++			/* Enable channel only once for ISOC */
++			dwc_otg_hc_start_transfer_ddma(hcd->core_if, hc);
++		}
++
++		break;
++	default:
++
++		break;
++	}
++}
++
++static void complete_isoc_xfer_ddma(dwc_otg_hcd_t * hcd,
++				    dwc_hc_t * hc,
++				    dwc_otg_hc_regs_t * hc_regs,
++				    dwc_otg_halt_status_e halt_status)
++{
++	struct dwc_otg_hcd_iso_packet_desc *frame_desc;
++	dwc_otg_qtd_t *qtd, *qtd_tmp;
++	dwc_otg_qh_t *qh;
++	dwc_otg_host_dma_desc_t *dma_desc;
++	uint16_t idx, remain;
++	uint8_t urb_compl;
++
++	qh = hc->qh;
++	idx = qh->td_first;
++
++	if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE) {
++		DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry)
++		    qtd->in_process = 0;
++		return;
++	} else if ((halt_status == DWC_OTG_HC_XFER_AHB_ERR) ||
++		   (halt_status == DWC_OTG_HC_XFER_BABBLE_ERR)) {
++		/*
++		 * Channel is halted in these error cases.
++		 * Considered as serious issues.
++		 * Complete all URBs marking all frames as failed,
++		 * irrespective whether some of the descriptors(frames) succeeded or no.
++		 * Pass error code to completion routine as well, to
++		 * update urb->status, some of class drivers might use it to stop
++		 * queing transfer requests.
++		 */
++		int err = (halt_status == DWC_OTG_HC_XFER_AHB_ERR)
++		    ? (-DWC_E_IO)
++		    : (-DWC_E_OVERFLOW);
++
++		DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry) {
++			for (idx = 0; idx < qtd->urb->packet_count; idx++) {
++				frame_desc = &qtd->urb->iso_descs[idx];
++				frame_desc->status = err;
++			}
++			hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, err);
++			dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
++		}
++		return;
++	}
++
++	DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry) {
++
++		if (!qtd->in_process)
++			break;
++
++		urb_compl = 0;
++
++		do {
++
++			dma_desc = &qh->desc_list[idx];
++
++			frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index];
++			remain = hc->ep_is_in ? dma_desc->status.b_isoc.n_bytes : 0;
++
++			if (dma_desc->status.b_isoc.sts == DMA_DESC_STS_PKTERR) {
++				/*
++				 * XactError or, unable to complete all the transactions
++				 * in the scheduled micro-frame/frame,
++				 * both indicated by DMA_DESC_STS_PKTERR.
++				 */
++				qtd->urb->error_count++;
++				frame_desc->actual_length = qh->n_bytes[idx] - remain;
++				frame_desc->status = -DWC_E_PROTOCOL;
++			} else {
++				/* Success */
++
++				frame_desc->actual_length = qh->n_bytes[idx] - remain;
++				frame_desc->status = 0;
++			}
++
++			if (++qtd->isoc_frame_index == qtd->urb->packet_count) {
++				/*
++				 * urb->status is not used for isoc transfers here.
++				 * The individual frame_desc status are used instead.
++				 */
++
++				hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0);
++				dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
++
++				/*
++				 * This check is necessary because urb_dequeue can be called
++				 * from urb complete callback(sound driver example).
++				 * All pending URBs are dequeued there, so no need for
++				 * further processing.
++				 */
++				if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE) {
++					return;
++				}
++
++				urb_compl = 1;
++
++			}
++
++			qh->ntd--;
++
++			/* Stop if IOC requested descriptor reached */
++			if (dma_desc->status.b_isoc.ioc) {
++				idx = desclist_idx_inc(idx, qh->interval, hc->speed);
++				goto stop_scan;
++			}
++
++			idx = desclist_idx_inc(idx, qh->interval, hc->speed);
++
++			if (urb_compl)
++				break;
++		}
++		while (idx != qh->td_first);
++	}
++stop_scan:
++	qh->td_first = idx;
++}
++
++uint8_t update_non_isoc_urb_state_ddma(dwc_otg_hcd_t * hcd,
++				       dwc_hc_t * hc,
++				       dwc_otg_qtd_t * qtd,
++				       dwc_otg_host_dma_desc_t * dma_desc,
++				       dwc_otg_halt_status_e halt_status,
++				       uint32_t n_bytes, uint8_t * xfer_done)
++{
++
++	uint16_t remain = hc->ep_is_in ? dma_desc->status.b.n_bytes : 0;
++	dwc_otg_hcd_urb_t *urb = qtd->urb;
++
++	if (halt_status == DWC_OTG_HC_XFER_AHB_ERR) {
++		urb->status = -DWC_E_IO;
++		return 1;
++	}
++	if (dma_desc->status.b.sts == DMA_DESC_STS_PKTERR) {
++		switch (halt_status) {
++		case DWC_OTG_HC_XFER_STALL:
++			urb->status = -DWC_E_PIPE;
++			break;
++		case DWC_OTG_HC_XFER_BABBLE_ERR:
++			urb->status = -DWC_E_OVERFLOW;
++			break;
++		case DWC_OTG_HC_XFER_XACT_ERR:
++			urb->status = -DWC_E_PROTOCOL;
++			break;
++		default:
++			DWC_ERROR("%s: Unhandled descriptor error status (%d)\n", __func__,
++				  halt_status);
++			break;
++		}
++		return 1;
++	}
++
++	if (dma_desc->status.b.a == 1) {
++		DWC_DEBUGPL(DBG_HCDV,
++			    "Active descriptor encountered on channel %d\n",
++			    hc->hc_num);
++		return 0;
++	}
++
++	if (hc->ep_type == DWC_OTG_EP_TYPE_CONTROL) {
++		if (qtd->control_phase == DWC_OTG_CONTROL_DATA) {
++			urb->actual_length += n_bytes - remain;
++			if (remain || urb->actual_length == urb->length) {
++				/*
++				 * For Control Data stage do not set urb->status=0 to prevent
++				 * URB callback. Set it when Status phase done. See below.
++				 */
++				*xfer_done = 1;
++			}
++
++		} else if (qtd->control_phase == DWC_OTG_CONTROL_STATUS) {
++			urb->status = 0;
++			*xfer_done = 1;
++		}
++		/* No handling for SETUP stage */
++	} else {
++		/* BULK and INTR */
++		urb->actual_length += n_bytes - remain;
++		if (remain || urb->actual_length == urb->length) {
++			urb->status = 0;
++			*xfer_done = 1;
++		}
++	}
++
++	return 0;
++}
++
++static void complete_non_isoc_xfer_ddma(dwc_otg_hcd_t * hcd,
++					dwc_hc_t * hc,
++					dwc_otg_hc_regs_t * hc_regs,
++					dwc_otg_halt_status_e halt_status)
++{
++	dwc_otg_hcd_urb_t *urb = NULL;
++	dwc_otg_qtd_t *qtd, *qtd_tmp;
++	dwc_otg_qh_t *qh;
++	dwc_otg_host_dma_desc_t *dma_desc;
++	uint32_t n_bytes, n_desc, i;
++	uint8_t failed = 0, xfer_done;
++
++	n_desc = 0;
++
++	qh = hc->qh;
++
++	if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE) {
++		DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry) {
++			qtd->in_process = 0;
++		}
++		return;
++	}
++
++	DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &qh->qtd_list, qtd_list_entry) {
++
++		urb = qtd->urb;
++
++		n_bytes = 0;
++		xfer_done = 0;
++
++		for (i = 0; i < qtd->n_desc; i++) {
++			dma_desc = &qh->desc_list[n_desc];
++
++			n_bytes = qh->n_bytes[n_desc];
++
++			failed =
++			    update_non_isoc_urb_state_ddma(hcd, hc, qtd,
++							   dma_desc,
++							   halt_status, n_bytes,
++							   &xfer_done);
++
++			if (failed
++			    || (xfer_done
++				&& (urb->status != -DWC_E_IN_PROGRESS))) {
++
++				hcd->fops->complete(hcd, urb->priv, urb,
++						    urb->status);
++				dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
++
++				if (failed)
++					goto stop_scan;
++			} else if (qh->ep_type == UE_CONTROL) {
++				if (qtd->control_phase == DWC_OTG_CONTROL_SETUP) {
++					if (urb->length > 0) {
++						qtd->control_phase = DWC_OTG_CONTROL_DATA;
++					} else {
++						qtd->control_phase = DWC_OTG_CONTROL_STATUS;
++					}
++					DWC_DEBUGPL(DBG_HCDV, "  Control setup transaction done\n");
++				} else if (qtd->control_phase == DWC_OTG_CONTROL_DATA) {
++					if (xfer_done) {
++						qtd->control_phase = DWC_OTG_CONTROL_STATUS;
++						DWC_DEBUGPL(DBG_HCDV, "  Control data transfer done\n");
++					} else if (i + 1 == qtd->n_desc) {
++						/*
++						 * Last descriptor for Control data stage which is
++						 * not completed yet.
++						 */
++						dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
++					}
++				}
++			}
++
++			n_desc++;
++		}
++
++	}
++
++stop_scan:
++
++	if (qh->ep_type != UE_CONTROL) {
++		/*
++		 * Resetting the data toggle for bulk
++		 * and interrupt endpoints in case of stall. See handle_hc_stall_intr()
++		 */
++		if (halt_status == DWC_OTG_HC_XFER_STALL)
++			qh->data_toggle = DWC_OTG_HC_PID_DATA0;
++		else
++			dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
++	}
++
++	if (halt_status == DWC_OTG_HC_XFER_COMPLETE) {
++		hcint_data_t hcint;
++		hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
++		if (hcint.b.nyet) {
++			/*
++			 * Got a NYET on the last transaction of the transfer. It
++			 * means that the endpoint should be in the PING state at the
++			 * beginning of the next transfer.
++			 */
++			qh->ping_state = 1;
++			clear_hc_int(hc_regs, nyet);
++		}
++
++	}
++
++}
++
++/**
++ * This function is called from interrupt handlers.
++ * Scans the descriptor list, updates URB's status and
++ * calls completion routine for the URB if it's done.
++ * Releases the channel to be used by other transfers.
++ * In case of Isochronous endpoint the channel is not halted until
++ * the end of the session, i.e. QTD list is empty.
++ * If periodic channel released the FrameList is updated accordingly.
++ *
++ * Calls transaction selection routines to activate pending transfers.
++ *
++ * @param hcd The HCD state structure for the DWC OTG controller.
++ * @param hc Host channel, the transfer is completed on.
++ * @param hc_regs Host channel registers.
++ * @param halt_status Reason the channel is being halted,
++ *		      or just XferComplete for isochronous transfer
++ */
++void dwc_otg_hcd_complete_xfer_ddma(dwc_otg_hcd_t * hcd,
++				    dwc_hc_t * hc,
++				    dwc_otg_hc_regs_t * hc_regs,
++				    dwc_otg_halt_status_e halt_status)
++{
++	uint8_t continue_isoc_xfer = 0;
++	dwc_otg_transaction_type_e tr_type;
++	dwc_otg_qh_t *qh = hc->qh;
++
++	if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
++
++		complete_isoc_xfer_ddma(hcd, hc, hc_regs, halt_status);
++
++		/* Release the channel if halted or session completed */
++		if (halt_status != DWC_OTG_HC_XFER_COMPLETE ||
++		    DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
++
++			/* Halt the channel if session completed */
++			if (halt_status == DWC_OTG_HC_XFER_COMPLETE) {
++				dwc_otg_hc_halt(hcd->core_if, hc, halt_status);
++			}
++
++			release_channel_ddma(hcd, qh);
++			dwc_otg_hcd_qh_remove(hcd, qh);
++		} else {
++			/* Keep in assigned schedule to continue transfer */
++			DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_assigned,
++					   &qh->qh_list_entry);
++			continue_isoc_xfer = 1;
++
++		}
++		/** @todo Consider the case when period exceeds FrameList size.
++		 *  Frame Rollover interrupt should be used.
++		 */
++	} else {
++		/* Scan descriptor list to complete the URB(s), then release the channel */
++		complete_non_isoc_xfer_ddma(hcd, hc, hc_regs, halt_status);
++
++		release_channel_ddma(hcd, qh);
++		dwc_otg_hcd_qh_remove(hcd, qh);
++
++		if (!DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
++			/* Add back to inactive non-periodic schedule on normal completion */
++			dwc_otg_hcd_qh_add(hcd, qh);
++		}
++
++	}
++	tr_type = dwc_otg_hcd_select_transactions(hcd);
++	if (tr_type != DWC_OTG_TRANSACTION_NONE || continue_isoc_xfer) {
++		if (continue_isoc_xfer) {
++			if (tr_type == DWC_OTG_TRANSACTION_NONE) {
++				tr_type = DWC_OTG_TRANSACTION_PERIODIC;
++			} else if (tr_type == DWC_OTG_TRANSACTION_NON_PERIODIC) {
++				tr_type = DWC_OTG_TRANSACTION_ALL;
++			}
++		}
++		dwc_otg_hcd_queue_transactions(hcd, tr_type);
++	}
++}
++
++#endif /* DWC_DEVICE_ONLY */
+diff --git a/drivers/usb/gadget/udc/hiudc/dwc_otg_hcd_if.h b/drivers/usb/gadget/udc/hiudc/dwc_otg_hcd_if.h
+new file mode 100644
+index 0000000..4823167
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc/dwc_otg_hcd_if.h
+@@ -0,0 +1,412 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_if.h $
++ * $Revision: #12 $
++ * $Date: 2011/10/26 $
++ * $Change: 1873028 $
++ *
++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
++ * ========================================================================== */
++#ifndef DWC_DEVICE_ONLY
++#ifndef __DWC_HCD_IF_H__
++#define __DWC_HCD_IF_H__
++
++#include "dwc_otg_core_if.h"
++
++/** @file
++ * This file defines DWC_OTG HCD Core API.
++ */
++
++struct dwc_otg_hcd;
++typedef struct dwc_otg_hcd dwc_otg_hcd_t;
++
++struct dwc_otg_hcd_urb;
++typedef struct dwc_otg_hcd_urb dwc_otg_hcd_urb_t;
++
++/** @name HCD Function Driver Callbacks */
++/** @{ */
++
++/** This function is called whenever core switches to host mode. */
++typedef int (*dwc_otg_hcd_start_cb_t) (dwc_otg_hcd_t * hcd);
++
++/** This function is called when device has been disconnected */
++typedef int (*dwc_otg_hcd_disconnect_cb_t) (dwc_otg_hcd_t * hcd);
++
++/** Wrapper provides this function to HCD to core, so it can get hub information to which device is connected */
++typedef int (*dwc_otg_hcd_hub_info_from_urb_cb_t) (dwc_otg_hcd_t * hcd,
++						   void *urb_handle,
++						   uint32_t * hub_addr,
++						   uint32_t * port_addr);
++/** Via this function HCD core gets device speed */
++typedef int (*dwc_otg_hcd_speed_from_urb_cb_t) (dwc_otg_hcd_t * hcd,
++						void *urb_handle);
++
++/** This function is called when urb is completed */
++typedef int (*dwc_otg_hcd_complete_urb_cb_t) (dwc_otg_hcd_t * hcd,
++					      void *urb_handle,
++					      dwc_otg_hcd_urb_t * dwc_otg_urb,
++					      int32_t status);
++
++/** Via this function HCD core gets b_hnp_enable parameter */
++typedef int (*dwc_otg_hcd_get_b_hnp_enable) (dwc_otg_hcd_t * hcd);
++
++struct dwc_otg_hcd_function_ops {
++	dwc_otg_hcd_start_cb_t start;
++	dwc_otg_hcd_disconnect_cb_t disconnect;
++	dwc_otg_hcd_hub_info_from_urb_cb_t hub_info;
++	dwc_otg_hcd_speed_from_urb_cb_t speed;
++	dwc_otg_hcd_complete_urb_cb_t complete;
++	dwc_otg_hcd_get_b_hnp_enable get_b_hnp_enable;
++};
++/** @} */
++
++/** @name HCD Core API */
++/** @{ */
++/** This function allocates dwc_otg_hcd structure and returns pointer on it. */
++extern dwc_otg_hcd_t *dwc_otg_hcd_alloc_hcd(void);
++
++/** This function should be called to initiate HCD Core.
++ *
++ * @param hcd The HCD
++ * @param core_if The DWC_OTG Core
++ *
++ * Returns -DWC_E_NO_MEMORY if no enough memory.
++ * Returns 0 on success
++ */
++extern int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd, dwc_otg_core_if_t * core_if);
++
++/** Frees HCD
++ *
++ * @param hcd The HCD
++ */
++extern void dwc_otg_hcd_remove(dwc_otg_hcd_t * hcd);
++
++/** This function should be called on every hardware interrupt.
++ *
++ * @param dwc_otg_hcd The HCD
++ *
++ * Returns non zero if interrupt is handled
++ * Return 0 if interrupt is not handled
++ */
++extern int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd);
++
++/**
++ * Returns private data set by
++ * dwc_otg_hcd_set_priv_data function.
++ *
++ * @param hcd The HCD
++ */
++extern void *dwc_otg_hcd_get_priv_data(dwc_otg_hcd_t * hcd);
++
++/**
++ * Set private data.
++ *
++ * @param hcd The HCD
++ * @param priv_data pointer to be stored in private data
++ */
++extern void dwc_otg_hcd_set_priv_data(dwc_otg_hcd_t * hcd, void *priv_data);
++
++/**
++ * This function initializes the HCD Core.
++ *
++ * @param hcd The HCD
++ * @param fops The Function Driver Operations data structure containing pointers to all callbacks.
++ *
++ * Returns -DWC_E_NO_DEVICE if Core is currently is in device mode.
++ * Returns 0 on success
++ */
++extern int dwc_otg_hcd_start(dwc_otg_hcd_t * hcd,
++			     struct dwc_otg_hcd_function_ops *fops);
++
++/**
++ * Halts the DWC_otg host mode operations in a clean manner. USB transfers are
++ * stopped.
++ *
++ * @param hcd The HCD
++ */
++extern void dwc_otg_hcd_stop(dwc_otg_hcd_t * hcd);
++
++/**
++ * Handles hub class-specific requests.
++ *
++ * @param dwc_otg_hcd The HCD
++ * @param typeReq Request Type
++ * @param wValue wValue from control request
++ * @param wIndex wIndex from control request
++ * @param buf data buffer
++ * @param wLength data buffer length
++ *
++ * Returns -DWC_E_INVALID if invalid argument is passed
++ * Returns 0 on success
++ */
++extern int dwc_otg_hcd_hub_control(dwc_otg_hcd_t * dwc_otg_hcd,
++				   uint16_t typeReq, uint16_t wValue,
++				   uint16_t wIndex, uint8_t * buf,
++				   uint16_t wLength);
++
++/**
++ * Returns otg port number.
++ *
++ * @param hcd The HCD
++ */
++extern uint32_t dwc_otg_hcd_otg_port(dwc_otg_hcd_t * hcd);
++
++/**
++ * Returns OTG version - either 1.3 or 2.0.
++ *
++ * @param core_if The core_if structure pointer
++ */
++extern uint16_t dwc_otg_get_otg_version(dwc_otg_core_if_t * core_if);
++
++/**
++ * Returns 1 if currently core is acting as B host, and 0 otherwise.
++ *
++ * @param hcd The HCD
++ */
++extern uint32_t dwc_otg_hcd_is_b_host(dwc_otg_hcd_t * hcd);
++
++/**
++ * Returns current frame number.
++ *
++ * @param hcd The HCD
++ */
++extern int dwc_otg_hcd_get_frame_number(dwc_otg_hcd_t * hcd);
++
++/**
++ * Dumps hcd state.
++ *
++ * @param hcd The HCD
++ */
++extern void dwc_otg_hcd_dump_state(dwc_otg_hcd_t * hcd);
++
++/**
++ * Dump the average frame remaining at SOF. This can be used to
++ * determine average interrupt latency. Frame remaining is also shown for
++ * start transfer and two additional sample points.
++ * Currently this function is not implemented.
++ *
++ * @param hcd The HCD
++ */
++extern void dwc_otg_hcd_dump_frrem(dwc_otg_hcd_t * hcd);
++
++/**
++ * Sends LPM transaction to the local device.
++ *
++ * @param hcd The HCD
++ * @param devaddr Device Address
++ * @param hird Host initiated resume duration
++ * @param bRemoteWake Value of bRemoteWake field in LPM transaction
++ *
++ * Returns negative value if sending LPM transaction was not succeeded.
++ * Returns 0 on success.
++ */
++extern int dwc_otg_hcd_send_lpm(dwc_otg_hcd_t * hcd, uint8_t devaddr,
++				uint8_t hird, uint8_t bRemoteWake);
++
++/* URB interface */
++
++/**
++ * Allocates memory for dwc_otg_hcd_urb structure.
++ * Allocated memory should be freed by call of DWC_FREE.
++ *
++ * @param hcd The HCD
++ * @param iso_desc_count Count of ISOC descriptors
++ * @param atomic_alloc Specefies whether to perform atomic allocation.
++ */
++extern dwc_otg_hcd_urb_t *dwc_otg_hcd_urb_alloc(dwc_otg_hcd_t * hcd,
++						int iso_desc_count,
++						int atomic_alloc);
++
++/**
++ * Set pipe information in URB.
++ *
++ * @param hcd_urb DWC_OTG URB
++ * @param devaddr Device Address
++ * @param ep_num Endpoint Number
++ * @param ep_type Endpoint Type
++ * @param ep_dir Endpoint Direction
++ * @param mps Max Packet Size
++ */
++extern void dwc_otg_hcd_urb_set_pipeinfo(dwc_otg_hcd_urb_t * hcd_urb,
++					 uint8_t devaddr, uint8_t ep_num,
++					 uint8_t ep_type, uint8_t ep_dir,
++					 uint16_t mps);
++
++/* Transfer flags */
++#define URB_GIVEBACK_ASAP 0x1
++#define URB_SEND_ZERO_PACKET 0x2
++
++/**
++ * Sets dwc_otg_hcd_urb parameters.
++ *
++ * @param urb DWC_OTG URB allocated by dwc_otg_hcd_urb_alloc function.
++ * @param urb_handle Unique handle for request, this will be passed back
++ * to function driver in completion callback.
++ * @param buf The buffer for the data
++ * @param dma The DMA buffer for the data
++ * @param buflen Transfer length
++ * @param sp Buffer for setup data
++ * @param sp_dma DMA address of setup data buffer
++ * @param flags Transfer flags
++ * @param interval Polling interval for interrupt or isochronous transfers.
++ */
++extern void dwc_otg_hcd_urb_set_params(dwc_otg_hcd_urb_t * urb,
++				       void *urb_handle, void *buf,
++				       dwc_dma_t dma, uint32_t buflen, void *sp,
++				       dwc_dma_t sp_dma, uint32_t flags,
++				       uint16_t interval);
++
++/** Gets status from dwc_otg_hcd_urb
++ *
++ * @param dwc_otg_urb DWC_OTG URB
++ */
++extern uint32_t dwc_otg_hcd_urb_get_status(dwc_otg_hcd_urb_t * dwc_otg_urb);
++
++/** Gets actual length from dwc_otg_hcd_urb
++ *
++ * @param dwc_otg_urb DWC_OTG URB
++ */
++extern uint32_t dwc_otg_hcd_urb_get_actual_length(dwc_otg_hcd_urb_t *
++						  dwc_otg_urb);
++
++/** Gets error count from dwc_otg_hcd_urb. Only for ISOC URBs
++ *
++ * @param dwc_otg_urb DWC_OTG URB
++ */
++extern uint32_t dwc_otg_hcd_urb_get_error_count(dwc_otg_hcd_urb_t *
++						dwc_otg_urb);
++
++/** Set ISOC descriptor offset and length
++ *
++ * @param dwc_otg_urb DWC_OTG URB
++ * @param desc_num ISOC descriptor number
++ * @param offset Offset from beginig of buffer.
++ * @param length Transaction length
++ */
++extern void dwc_otg_hcd_urb_set_iso_desc_params(dwc_otg_hcd_urb_t * dwc_otg_urb,
++						int desc_num, uint32_t offset,
++						uint32_t length);
++
++/** Get status of ISOC descriptor, specified by desc_num
++ *
++ * @param dwc_otg_urb DWC_OTG URB
++ * @param desc_num ISOC descriptor number
++ */
++extern uint32_t dwc_otg_hcd_urb_get_iso_desc_status(dwc_otg_hcd_urb_t *
++						    dwc_otg_urb, int desc_num);
++
++/** Get actual length of ISOC descriptor, specified by desc_num
++ *
++ * @param dwc_otg_urb DWC_OTG URB
++ * @param desc_num ISOC descriptor number
++ */
++extern uint32_t dwc_otg_hcd_urb_get_iso_desc_actual_length(dwc_otg_hcd_urb_t *
++							   dwc_otg_urb,
++							   int desc_num);
++
++/** Queue URB. After transfer is completes, the complete callback will be called with the URB status
++ *
++ * @param dwc_otg_hcd The HCD
++ * @param dwc_otg_urb DWC_OTG URB
++ * @param ep_handle Out parameter for returning endpoint handle
++ * @param atomic_alloc Flag to do atomic allocation if needed
++ *
++ * Returns -DWC_E_NO_DEVICE if no device is connected.
++ * Returns -DWC_E_NO_MEMORY if there is no enough memory.
++ * Returns 0 on success.
++ */
++extern int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * dwc_otg_hcd,
++				   dwc_otg_hcd_urb_t * dwc_otg_urb,
++				   void **ep_handle, int atomic_alloc);
++
++/** De-queue the specified URB
++ *
++ * @param dwc_otg_hcd The HCD
++ * @param dwc_otg_urb DWC_OTG URB
++ */
++extern int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_t * dwc_otg_hcd,
++				   dwc_otg_hcd_urb_t * dwc_otg_urb);
++
++/** Frees resources in the DWC_otg controller related to a given endpoint.
++ * Any URBs for the endpoint must already be dequeued.
++ *
++ * @param hcd The HCD
++ * @param ep_handle Endpoint handle, returned by dwc_otg_hcd_urb_enqueue function
++ * @param retry Number of retries if there are queued transfers.
++ *
++ * Returns -DWC_E_INVALID if invalid arguments are passed.
++ * Returns 0 on success
++ */
++extern int dwc_otg_hcd_endpoint_disable(dwc_otg_hcd_t * hcd, void *ep_handle,
++					int retry);
++
++/* Resets the data toggle in qh structure. This function can be called from
++ * usb_clear_halt routine.
++ *
++ * @param hcd The HCD
++ * @param ep_handle Endpoint handle, returned by dwc_otg_hcd_urb_enqueue function
++ *
++ * Returns -DWC_E_INVALID if invalid arguments are passed.
++ * Returns 0 on success
++ */
++extern int dwc_otg_hcd_endpoint_reset(dwc_otg_hcd_t * hcd, void *ep_handle);
++
++/** Returns 1 if status of specified port is changed and 0 otherwise.
++ *
++ * @param hcd The HCD
++ * @param port Port number
++ */
++extern int dwc_otg_hcd_is_status_changed(dwc_otg_hcd_t * hcd, int port);
++
++/** Call this function to check if bandwidth was allocated for specified endpoint.
++ * Only for ISOC and INTERRUPT endpoints.
++ *
++ * @param hcd The HCD
++ * @param ep_handle Endpoint handle
++ */
++extern int dwc_otg_hcd_is_bandwidth_allocated(dwc_otg_hcd_t * hcd,
++					      void *ep_handle);
++
++/** Call this function to check if bandwidth was freed for specified endpoint.
++ *
++ * @param hcd The HCD
++ * @param ep_handle Endpoint handle
++ */
++extern int dwc_otg_hcd_is_bandwidth_freed(dwc_otg_hcd_t * hcd, void *ep_handle);
++
++/** Returns bandwidth allocated for specified endpoint in microseconds.
++ * Only for ISOC and INTERRUPT endpoints.
++ *
++ * @param hcd The HCD
++ * @param ep_handle Endpoint handle
++ */
++extern uint8_t dwc_otg_hcd_get_ep_bandwidth(dwc_otg_hcd_t * hcd,
++					    void *ep_handle);
++
++/** @} */
++
++#endif /* __DWC_HCD_IF_H__ */
++#endif /* DWC_DEVICE_ONLY */
+diff --git a/drivers/usb/gadget/udc/hiudc/dwc_otg_hcd_intr.c b/drivers/usb/gadget/udc/hiudc/dwc_otg_hcd_intr.c
+new file mode 100644
+index 0000000..23b1d9d
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc/dwc_otg_hcd_intr.c
+@@ -0,0 +1,2105 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_intr.c $
++ * $Revision: #94 $
++ * $Date: 2013/01/31 $
++ * $Change: 2155605 $
++ *
++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
++ * ========================================================================== */
++#ifndef DWC_DEVICE_ONLY
++
++#include "dwc_otg_hcd.h"
++#include "dwc_otg_regs.h"
++
++/** @file
++ * This file contains the implementation of the HCD Interrupt handlers.
++ */
++
++/** This function handles interrupts for the HCD. */
++int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd)
++{
++	int retval = 0;
++
++	dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if;
++	gintsts_data_t gintsts;
++#ifdef DEBUG
++	dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
++#endif
++
++	if (dwc_otg_check_haps_status(core_if) == -1 ) {
++		DWC_WARN("HAPS is disconnected");
++		return retval;
++	}
++
++	/* Exit from ISR if core is hibernated */
++	if (core_if->hibernation_suspend == 1) {
++		return retval;
++	}
++	DWC_SPINLOCK(dwc_otg_hcd->lock);
++	/* Check if HOST Mode */
++	if (dwc_otg_is_host_mode(core_if)) {
++		gintsts.d32 = dwc_otg_read_core_intr(core_if);
++		if (!gintsts.d32) {
++			DWC_SPINUNLOCK(dwc_otg_hcd->lock);
++			return 0;
++		}
++#ifdef DEBUG
++		/* Don't print debug message in the interrupt handler on SOF */
++#ifndef DEBUG_SOF
++		if (gintsts.d32 != DWC_SOF_INTR_MASK)
++#endif
++			DWC_DEBUGPL(DBG_HCD, "\n");
++#endif
++
++#ifdef DEBUG
++#ifndef DEBUG_SOF
++		if (gintsts.d32 != DWC_SOF_INTR_MASK)
++#endif
++			DWC_DEBUGPL(DBG_HCD,
++				    "DWC OTG HCD Interrupt Detected gintsts&gintmsk=0x%08x\n",
++				    gintsts.d32);
++#endif
++
++		if (gintsts.b.sofintr) {
++			retval |= dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd);
++		}
++		if (gintsts.b.rxstsqlvl) {
++			retval |=
++			    dwc_otg_hcd_handle_rx_status_q_level_intr
++			    (dwc_otg_hcd);
++		}
++		if (gintsts.b.nptxfempty) {
++			retval |=
++			    dwc_otg_hcd_handle_np_tx_fifo_empty_intr
++			    (dwc_otg_hcd);
++		}
++		if (gintsts.b.i2cintr) {
++			/** @todo Implement i2cintr handler. */
++		}
++		if (gintsts.b.portintr) {
++			retval |= dwc_otg_hcd_handle_port_intr(dwc_otg_hcd);
++		}
++		if (gintsts.b.hcintr) {
++			retval |= dwc_otg_hcd_handle_hc_intr(dwc_otg_hcd);
++		}
++		if (gintsts.b.ptxfempty) {
++			retval |=
++			    dwc_otg_hcd_handle_perio_tx_fifo_empty_intr
++			    (dwc_otg_hcd);
++		}
++#ifdef DEBUG
++#ifndef DEBUG_SOF
++		if (gintsts.d32 != DWC_SOF_INTR_MASK)
++#endif
++		{
++			DWC_DEBUGPL(DBG_HCD,
++				    "DWC OTG HCD Finished Servicing Interrupts\n");
++			DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD gintsts=0x%08x\n",
++				    DWC_READ_REG32(&global_regs->gintsts));
++			DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD gintmsk=0x%08x\n",
++				    DWC_READ_REG32(&global_regs->gintmsk));
++		}
++#endif
++
++#ifdef DEBUG
++#ifndef DEBUG_SOF
++		if (gintsts.d32 != DWC_SOF_INTR_MASK)
++#endif
++			DWC_DEBUGPL(DBG_HCD, "\n");
++#endif
++
++	}
++	DWC_SPINUNLOCK(dwc_otg_hcd->lock);
++	return retval;
++}
++
++#ifdef DWC_TRACK_MISSED_SOFS
++#warning Compiling code to track missed SOFs
++#define FRAME_NUM_ARRAY_SIZE 1000
++/**
++ * This function is for debug only.
++ */
++static inline void track_missed_sofs(uint16_t curr_frame_number)
++{
++	static uint16_t frame_num_array[FRAME_NUM_ARRAY_SIZE];
++	static uint16_t last_frame_num_array[FRAME_NUM_ARRAY_SIZE];
++	static int frame_num_idx = 0;
++	static uint16_t last_frame_num = DWC_HFNUM_MAX_FRNUM;
++	static int dumped_frame_num_array = 0;
++
++	if (frame_num_idx < FRAME_NUM_ARRAY_SIZE) {
++		if (((last_frame_num + 1) & DWC_HFNUM_MAX_FRNUM) !=
++		    curr_frame_number) {
++			frame_num_array[frame_num_idx] = curr_frame_number;
++			last_frame_num_array[frame_num_idx++] = last_frame_num;
++		}
++	} else if (!dumped_frame_num_array) {
++		int i;
++		DWC_PRINTF("Frame     Last Frame\n");
++		DWC_PRINTF("-----     ----------\n");
++		for (i = 0; i < FRAME_NUM_ARRAY_SIZE; i++) {
++			DWC_PRINTF("0x%04x    0x%04x\n",
++				   frame_num_array[i], last_frame_num_array[i]);
++		}
++		dumped_frame_num_array = 1;
++	}
++	last_frame_num = curr_frame_number;
++}
++#endif
++
++/**
++ * Handles the start-of-frame interrupt in host mode. Non-periodic
++ * transactions may be queued to the DWC_otg controller for the current
++ * (micro)frame. Periodic transactions may be queued to the controller for the
++ * next (micro)frame.
++ */
++int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * hcd)
++{
++	hfnum_data_t hfnum;
++	dwc_list_link_t *qh_entry;
++	dwc_otg_qh_t *qh;
++	dwc_otg_transaction_type_e tr_type;
++	gintsts_data_t gintsts = {.d32 = 0 };
++
++	hfnum.d32 =
++	    DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hfnum);
++
++#ifdef DEBUG_SOF
++	DWC_DEBUGPL(DBG_HCD, "--Start of Frame Interrupt--\n");
++#endif
++	hcd->frame_number = hfnum.b.frnum;
++
++#ifdef DEBUG
++	hcd->frrem_accum += hfnum.b.frrem;
++	hcd->frrem_samples++;
++#endif
++
++#ifdef DWC_TRACK_MISSED_SOFS
++	track_missed_sofs(hcd->frame_number);
++#endif
++	/* Determine whether any periodic QHs should be executed. */
++	qh_entry = DWC_LIST_FIRST(&hcd->periodic_sched_inactive);
++	while (qh_entry != &hcd->periodic_sched_inactive) {
++		qh = DWC_LIST_ENTRY(qh_entry, dwc_otg_qh_t, qh_list_entry);
++		qh_entry = qh_entry->next;
++		if (dwc_frame_num_le(qh->sched_frame, hcd->frame_number)) {
++			/*
++			 * Move QH to the ready list to be executed next
++			 * (micro)frame.
++			 */
++			DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_ready,
++					   &qh->qh_list_entry);
++		}
++	}
++	tr_type = dwc_otg_hcd_select_transactions(hcd);
++	if (tr_type != DWC_OTG_TRANSACTION_NONE) {
++		dwc_otg_hcd_queue_transactions(hcd, tr_type);
++	}
++
++	/* Clear interrupt */
++	gintsts.b.sofintr = 1;
++	DWC_WRITE_REG32(&hcd->core_if->core_global_regs->gintsts, gintsts.d32);
++
++	return 1;
++}
++
++/** Handles the Rx Status Queue Level Interrupt, which indicates that there is at
++ * least one packet in the Rx FIFO.  The packets are moved from the FIFO to
++ * memory if the DWC_otg controller is operating in Slave mode. */
++int32_t dwc_otg_hcd_handle_rx_status_q_level_intr(dwc_otg_hcd_t * dwc_otg_hcd)
++{
++	host_grxsts_data_t grxsts;
++	dwc_hc_t *hc = NULL;
++
++	DWC_DEBUGPL(DBG_HCD, "--RxStsQ Level Interrupt--\n");
++
++	grxsts.d32 =
++	    DWC_READ_REG32(&dwc_otg_hcd->core_if->core_global_regs->grxstsp);
++
++	hc = dwc_otg_hcd->hc_ptr_array[grxsts.b.chnum];
++	if (!hc) {
++		DWC_ERROR("Unable to get corresponding channel\n");
++		return 0;
++	}
++
++	/* Packet Status */
++	DWC_DEBUGPL(DBG_HCDV, "    Ch num = %d\n", grxsts.b.chnum);
++	DWC_DEBUGPL(DBG_HCDV, "    Count = %d\n", grxsts.b.bcnt);
++	DWC_DEBUGPL(DBG_HCDV, "    DPID = %d, hc.dpid = %d\n", grxsts.b.dpid,
++		    hc->data_pid_start);
++	DWC_DEBUGPL(DBG_HCDV, "    PStatus = %d\n", grxsts.b.pktsts);
++
++	switch (grxsts.b.pktsts) {
++	case DWC_GRXSTS_PKTSTS_IN:
++		/* Read the data into the host buffer. */
++		if (grxsts.b.bcnt > 0) {
++			dwc_otg_read_packet(dwc_otg_hcd->core_if,
++					    hc->xfer_buff, grxsts.b.bcnt);
++
++			/* Update the HC fields for the next packet received. */
++			hc->xfer_count += grxsts.b.bcnt;
++			hc->xfer_buff += grxsts.b.bcnt;
++		}
++
++	case DWC_GRXSTS_PKTSTS_IN_XFER_COMP:
++	case DWC_GRXSTS_PKTSTS_DATA_TOGGLE_ERR:
++	case DWC_GRXSTS_PKTSTS_CH_HALTED:
++		/* Handled in interrupt, just ignore data */
++		break;
++	default:
++		DWC_ERROR("RX_STS_Q Interrupt: Unknown status %d\n",
++			  grxsts.b.pktsts);
++		break;
++	}
++
++	return 1;
++}
++
++/** This interrupt occurs when the non-periodic Tx FIFO is half-empty. More
++ * data packets may be written to the FIFO for OUT transfers. More requests
++ * may be written to the non-periodic request queue for IN transfers. This
++ * interrupt is enabled only in Slave mode. */
++int32_t dwc_otg_hcd_handle_np_tx_fifo_empty_intr(dwc_otg_hcd_t * dwc_otg_hcd)
++{
++	DWC_DEBUGPL(DBG_HCD, "--Non-Periodic TxFIFO Empty Interrupt--\n");
++	dwc_otg_hcd_queue_transactions(dwc_otg_hcd,
++				       DWC_OTG_TRANSACTION_NON_PERIODIC);
++	return 1;
++}
++
++/** This interrupt occurs when the periodic Tx FIFO is half-empty. More data
++ * packets may be written to the FIFO for OUT transfers. More requests may be
++ * written to the periodic request queue for IN transfers. This interrupt is
++ * enabled only in Slave mode. */
++int32_t dwc_otg_hcd_handle_perio_tx_fifo_empty_intr(dwc_otg_hcd_t * dwc_otg_hcd)
++{
++	DWC_DEBUGPL(DBG_HCD, "--Periodic TxFIFO Empty Interrupt--\n");
++	dwc_otg_hcd_queue_transactions(dwc_otg_hcd,
++				       DWC_OTG_TRANSACTION_PERIODIC);
++	return 1;
++}
++
++/** There are multiple conditions that can cause a port interrupt. This function
++ * determines which interrupt conditions have occurred and handles them
++ * appropriately. */
++int32_t dwc_otg_hcd_handle_port_intr(dwc_otg_hcd_t * dwc_otg_hcd)
++{
++	int retval = 0;
++	hprt0_data_t hprt0;
++	hprt0_data_t hprt0_modify;
++
++	hprt0.d32 = DWC_READ_REG32(dwc_otg_hcd->core_if->host_if->hprt0);
++	hprt0_modify.d32 = DWC_READ_REG32(dwc_otg_hcd->core_if->host_if->hprt0);
++
++	/* Clear appropriate bits in HPRT0 to clear the interrupt bit in
++	 * GINTSTS */
++
++	hprt0_modify.b.prtena = 0;
++	hprt0_modify.b.prtconndet = 0;
++	hprt0_modify.b.prtenchng = 0;
++	hprt0_modify.b.prtovrcurrchng = 0;
++
++	/* Port Connect Detected
++	 * Set flag and clear if detected */
++	if (dwc_otg_hcd->core_if->hibernation_suspend == 1) {
++		// Dont modify port status if we are in hibernation state
++		hprt0_modify.b.prtconndet = 1;
++		hprt0_modify.b.prtenchng = 1;
++		DWC_WRITE_REG32(dwc_otg_hcd->core_if->host_if->hprt0, hprt0_modify.d32);
++		hprt0.d32 = DWC_READ_REG32(dwc_otg_hcd->core_if->host_if->hprt0);
++		return retval;
++	}
++
++	if (hprt0.b.prtconndet) {
++		/** @todo - check if steps performed in 'else' block should be perfromed regardles adp */
++		if (dwc_otg_hcd->core_if->adp_enable &&
++				dwc_otg_hcd->core_if->adp.vbuson_timer_started == 1) {
++			DWC_PRINTF("PORT CONNECT DETECTED ----------------\n");
++			DWC_TIMER_CANCEL(dwc_otg_hcd->core_if->adp.vbuson_timer);
++			dwc_otg_hcd->core_if->adp.vbuson_timer_started = 0;
++			/* TODO - check if this is required, as
++			 * host initialization was already performed
++			 * after initial ADP probing
++			 */
++			/*dwc_otg_hcd->core_if->adp.vbuson_timer_started = 0;
++			dwc_otg_core_init(dwc_otg_hcd->core_if);
++			dwc_otg_enable_global_interrupts(dwc_otg_hcd->core_if);
++			cil_hcd_start(dwc_otg_hcd->core_if);*/
++		} else {
++			hprt0_data_t hprt0_local;
++			DWC_DEBUGPL(DBG_HCD, "--Port Interrupt HPRT0=0x%08x "
++				    "Port Connect Detected--\n", hprt0.d32);
++			dwc_otg_hcd->flags.b.port_connect_status_change = 1;
++			dwc_otg_hcd->flags.b.port_connect_status = 1;
++			hprt0_modify.b.prtconndet = 1;
++			/* PET testing */
++			if (dwc_otg_hcd->core_if->otg_ver && (dwc_otg_hcd->core_if->test_mode == 7)) {
++				hprt0_local.d32 = dwc_otg_read_hprt0(dwc_otg_hcd->core_if);
++				hprt0_local.b.prtrst = 1;
++				DWC_WRITE_REG32(dwc_otg_hcd->core_if->host_if->hprt0, hprt0_local.d32);
++				dwc_mdelay(60);
++				hprt0.d32 = dwc_otg_read_hprt0(dwc_otg_hcd->core_if);
++				hprt0.b.prtrst = 0;
++				DWC_WRITE_REG32(dwc_otg_hcd->core_if->host_if->hprt0, hprt0.d32);
++			}
++
++			/* B-Device has connected, Delete the connection timer. */
++			DWC_TIMER_CANCEL(dwc_otg_hcd->conn_timer);
++		}
++		/* The Hub driver asserts a reset when it sees port connect
++		 * status change flag */
++		retval |= 1;
++	}
++
++	/* Port Enable Changed
++	 * Clear if detected - Set internal flag if disabled */
++	if (hprt0.b.prtenchng) {
++		DWC_DEBUGPL(DBG_HCD, "  --Port Interrupt HPRT0=0x%08x "
++			    "Port Enable Changed--\n", hprt0.d32);
++		hprt0_modify.b.prtenchng = 1;
++		if (hprt0.b.prtena == 1) {
++			hfir_data_t hfir;
++			int do_reset = 0;
++			dwc_otg_core_params_t *params =
++			    dwc_otg_hcd->core_if->core_params;
++			dwc_otg_core_global_regs_t *global_regs =
++			    dwc_otg_hcd->core_if->core_global_regs;
++			dwc_otg_host_if_t *host_if =
++			    dwc_otg_hcd->core_if->host_if;
++
++			/* Every time when port enables calculate
++			 * HFIR.FrInterval
++			 */
++			hfir.d32 = DWC_READ_REG32(&host_if->host_global_regs->hfir);
++			hfir.b.frint = calc_frame_interval(dwc_otg_hcd->core_if);
++			DWC_WRITE_REG32(&host_if->host_global_regs->hfir, hfir.d32);
++
++			/* Check if we need to adjust the PHY clock speed for
++			 * low power and adjust it */
++			if (params->host_support_fs_ls_low_power) {
++				gusbcfg_data_t usbcfg;
++
++				usbcfg.d32 =
++				    DWC_READ_REG32(&global_regs->gusbcfg);
++
++				if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_LOW_SPEED
++				    || hprt0.b.prtspd ==
++				    DWC_HPRT0_PRTSPD_FULL_SPEED) {
++					/*
++					 * Low power
++					 */
++					hcfg_data_t hcfg;
++					if (usbcfg.b.phylpwrclksel == 0) {
++						/* Set PHY low power clock select for FS/LS devices */
++						usbcfg.b.phylpwrclksel = 1;
++						DWC_WRITE_REG32
++						    (&global_regs->gusbcfg,
++						     usbcfg.d32);
++						do_reset = 1;
++					}
++
++					hcfg.d32 =
++					    DWC_READ_REG32
++					    (&host_if->host_global_regs->hcfg);
++
++					if (hprt0.b.prtspd ==
++					    DWC_HPRT0_PRTSPD_LOW_SPEED
++					    && params->host_ls_low_power_phy_clk
++					    ==
++					    DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ)
++					{
++						/* 6 MHZ */
++						DWC_DEBUGPL(DBG_CIL,
++							    "FS_PHY programming HCFG to 6 MHz (Low Power)\n");
++						if (hcfg.b.fslspclksel !=
++						    DWC_HCFG_6_MHZ) {
++							hcfg.b.fslspclksel =
++							    DWC_HCFG_6_MHZ;
++							DWC_WRITE_REG32
++							    (&host_if->host_global_regs->hcfg,
++							     hcfg.d32);
++							do_reset = 1;
++						}
++					} else {
++						/* 48 MHZ */
++						DWC_DEBUGPL(DBG_CIL,
++							    "FS_PHY programming HCFG to 48 MHz ()\n");
++						if (hcfg.b.fslspclksel !=
++						    DWC_HCFG_48_MHZ) {
++							hcfg.b.fslspclksel =
++							    DWC_HCFG_48_MHZ;
++							DWC_WRITE_REG32
++							    (&host_if->host_global_regs->hcfg,
++							     hcfg.d32);
++							do_reset = 1;
++						}
++					}
++				} else {
++					/*
++					 * Not low power
++					 */
++					if (usbcfg.b.phylpwrclksel == 1) {
++						usbcfg.b.phylpwrclksel = 0;
++						DWC_WRITE_REG32
++						    (&global_regs->gusbcfg,
++						     usbcfg.d32);
++						do_reset = 1;
++					}
++				}
++
++				if (do_reset) {
++					DWC_TASK_SCHEDULE(dwc_otg_hcd->reset_tasklet);
++				}
++			}
++
++			if (!do_reset) {
++				/* Port has been enabled set the reset change flag */
++				dwc_otg_hcd->flags.b.port_reset_change = 1;
++			}
++		} else {
++			dwc_otg_hcd->flags.b.port_enable_change = 1;
++		}
++		retval |= 1;
++	}
++
++	/** Overcurrent Change Interrupt */
++	if (hprt0.b.prtovrcurrchng) {
++		DWC_DEBUGPL(DBG_HCD, "  --Port Interrupt HPRT0=0x%08x "
++			    "Port Overcurrent Changed--\n", hprt0.d32);
++		dwc_otg_hcd->flags.b.port_over_current_change = 1;
++		hprt0_modify.b.prtovrcurrchng = 1;
++		retval |= 1;
++	}
++
++	/* Clear Port Interrupts */
++	DWC_WRITE_REG32(dwc_otg_hcd->core_if->host_if->hprt0, hprt0_modify.d32);
++
++	return retval;
++}
++
++/** This interrupt indicates that one or more host channels has a pending
++ * interrupt. There are multiple conditions that can cause each host channel
++ * interrupt. This function determines which conditions have occurred for each
++ * host channel interrupt and handles them appropriately. */
++int32_t dwc_otg_hcd_handle_hc_intr(dwc_otg_hcd_t * dwc_otg_hcd)
++{
++	int i;
++	int retval = 0;
++	haint_data_t haint;
++
++	/* Clear appropriate bits in HCINTn to clear the interrupt bit in
++	 * GINTSTS */
++
++	haint.d32 = dwc_otg_read_host_all_channels_intr(dwc_otg_hcd->core_if);
++
++	for (i = 0; i < dwc_otg_hcd->core_if->core_params->host_channels; i++) {
++		if (haint.b2.chint & (1 << i)) {
++			retval |= dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd, i);
++		}
++	}
++
++	return retval;
++}
++
++/**
++ * Gets the actual length of a transfer after the transfer halts. _halt_status
++ * holds the reason for the halt.
++ *
++ * For IN transfers where halt_status is DWC_OTG_HC_XFER_COMPLETE,
++ * *short_read is set to 1 upon return if less than the requested
++ * number of bytes were transferred. Otherwise, *short_read is set to 0 upon
++ * return. short_read may also be NULL on entry, in which case it remains
++ * unchanged.
++ */
++static uint32_t get_actual_xfer_length(dwc_hc_t * hc,
++				       dwc_otg_hc_regs_t * hc_regs,
++				       dwc_otg_qtd_t * qtd,
++				       dwc_otg_halt_status_e halt_status,
++				       int *short_read)
++{
++	hctsiz_data_t hctsiz;
++	uint32_t length;
++
++	if (short_read != NULL) {
++		*short_read = 0;
++	}
++	hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
++
++	if (halt_status == DWC_OTG_HC_XFER_COMPLETE) {
++		if (hc->ep_is_in) {
++			length = hc->xfer_len - hctsiz.b.xfersize;
++			if (short_read != NULL) {
++				*short_read = (hctsiz.b.xfersize != 0);
++			}
++		} else if (hc->qh->do_split) {
++			length = qtd->ssplit_out_xfer_count;
++		} else {
++			length = hc->xfer_len;
++		}
++	} else {
++		/*
++		 * Must use the hctsiz.pktcnt field to determine how much data
++		 * has been transferred. This field reflects the number of
++		 * packets that have been transferred via the USB. This is
++		 * always an integral number of packets if the transfer was
++		 * halted before its normal completion. (Can't use the
++		 * hctsiz.xfersize field because that reflects the number of
++		 * bytes transferred via the AHB, not the USB).
++		 */
++		length =
++		    (hc->start_pkt_count - hctsiz.b.pktcnt) * hc->max_packet;
++	}
++
++	return length;
++}
++
++/**
++ * Updates the state of the URB after a Transfer Complete interrupt on the
++ * host channel. Updates the actual_length field of the URB based on the
++ * number of bytes transferred via the host channel. Sets the URB status
++ * if the data transfer is finished.
++ *
++ * @return 1 if the data transfer specified by the URB is completely finished,
++ * 0 otherwise.
++ */
++static int update_urb_state_xfer_comp(dwc_hc_t * hc,
++				      dwc_otg_hc_regs_t * hc_regs,
++				      dwc_otg_hcd_urb_t * urb,
++				      dwc_otg_qtd_t * qtd)
++{
++	int xfer_done = 0;
++	int short_read = 0;
++
++	int xfer_length;
++
++	xfer_length = get_actual_xfer_length(hc, hc_regs, qtd,
++					     DWC_OTG_HC_XFER_COMPLETE,
++					     &short_read);
++
++
++	/* non DWORD-aligned buffer case handling. */
++	if (hc->align_buff && xfer_length && hc->ep_is_in) {
++		dwc_memcpy(urb->buf + urb->actual_length, hc->qh->dw_align_buf,
++			   xfer_length);
++	}
++
++	urb->actual_length += xfer_length;
++
++	if (xfer_length && (hc->ep_type == DWC_OTG_EP_TYPE_BULK) &&
++	    (urb->flags & URB_SEND_ZERO_PACKET)
++	    && (urb->actual_length == urb->length)
++	    && !(urb->length % hc->max_packet)) {
++		xfer_done = 0;
++	} else if (short_read || urb->actual_length == urb->length) {
++		xfer_done = 1;
++		urb->status = 0;
++	}
++
++#ifdef DEBUG
++	{
++		hctsiz_data_t hctsiz;
++		hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
++		DWC_DEBUGPL(DBG_HCDV, "DWC_otg: %s: %s, channel %d\n",
++			    __func__, (hc->ep_is_in ? "IN" : "OUT"),
++			    hc->hc_num);
++		DWC_DEBUGPL(DBG_HCDV, "  hc->xfer_len %d\n", hc->xfer_len);
++		DWC_DEBUGPL(DBG_HCDV, "  hctsiz.xfersize %d\n",
++			    hctsiz.b.xfersize);
++		DWC_DEBUGPL(DBG_HCDV, "  urb->transfer_buffer_length %d\n",
++			    urb->length);
++		DWC_DEBUGPL(DBG_HCDV, "  urb->actual_length %d\n",
++			    urb->actual_length);
++		DWC_DEBUGPL(DBG_HCDV, "  short_read %d, xfer_done %d\n",
++			    short_read, xfer_done);
++	}
++#endif
++
++	return xfer_done;
++}
++
++/*
++ * Save the starting data toggle for the next transfer. The data toggle is
++ * saved in the QH for non-control transfers and it's saved in the QTD for
++ * control transfers.
++ */
++void dwc_otg_hcd_save_data_toggle(dwc_hc_t * hc,
++			     dwc_otg_hc_regs_t * hc_regs, dwc_otg_qtd_t * qtd)
++{
++	hctsiz_data_t hctsiz;
++	hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
++
++	if (hc->ep_type != DWC_OTG_EP_TYPE_CONTROL) {
++		dwc_otg_qh_t *qh = hc->qh;
++		if (hctsiz.b.pid == DWC_HCTSIZ_DATA0) {
++			qh->data_toggle = DWC_OTG_HC_PID_DATA0;
++		} else {
++			qh->data_toggle = DWC_OTG_HC_PID_DATA1;
++		}
++	} else {
++		if (hctsiz.b.pid == DWC_HCTSIZ_DATA0) {
++			qtd->data_toggle = DWC_OTG_HC_PID_DATA0;
++		} else {
++			qtd->data_toggle = DWC_OTG_HC_PID_DATA1;
++		}
++	}
++}
++
++/**
++ * Updates the state of an Isochronous URB when the transfer is stopped for
++ * any reason. The fields of the current entry in the frame descriptor array
++ * are set based on the transfer state and the input _halt_status. Completes
++ * the Isochronous URB if all the URB frames have been completed.
++ *
++ * @return DWC_OTG_HC_XFER_COMPLETE if there are more frames remaining to be
++ * transferred in the URB. Otherwise return DWC_OTG_HC_XFER_URB_COMPLETE.
++ */
++static dwc_otg_halt_status_e
++update_isoc_urb_state(dwc_otg_hcd_t * hcd,
++		      dwc_hc_t * hc,
++		      dwc_otg_hc_regs_t * hc_regs,
++		      dwc_otg_qtd_t * qtd, dwc_otg_halt_status_e halt_status)
++{
++	dwc_otg_hcd_urb_t *urb = qtd->urb;
++	dwc_otg_halt_status_e ret_val = halt_status;
++	struct dwc_otg_hcd_iso_packet_desc *frame_desc;
++
++	frame_desc = &urb->iso_descs[qtd->isoc_frame_index];
++	switch (halt_status) {
++	case DWC_OTG_HC_XFER_COMPLETE:
++		frame_desc->status = 0;
++		frame_desc->actual_length =
++		    get_actual_xfer_length(hc, hc_regs, qtd, halt_status, NULL);
++
++		/* non DWORD-aligned buffer case handling. */
++		if (hc->align_buff && frame_desc->actual_length && hc->ep_is_in) {
++			dwc_memcpy(urb->buf + frame_desc->offset + qtd->isoc_split_offset,
++				   hc->qh->dw_align_buf, frame_desc->actual_length);
++		}
++
++		break;
++	case DWC_OTG_HC_XFER_FRAME_OVERRUN:
++		urb->error_count++;
++		if (hc->ep_is_in) {
++			frame_desc->status = -DWC_E_NO_STREAM_RES;
++		} else {
++			frame_desc->status = -DWC_E_COMMUNICATION;
++		}
++		frame_desc->actual_length = 0;
++		break;
++	case DWC_OTG_HC_XFER_BABBLE_ERR:
++		urb->error_count++;
++		frame_desc->status = -DWC_E_OVERFLOW;
++		/* Don't need to update actual_length in this case. */
++		break;
++	case DWC_OTG_HC_XFER_XACT_ERR:
++		urb->error_count++;
++		frame_desc->status = -DWC_E_PROTOCOL;
++		frame_desc->actual_length =
++		    get_actual_xfer_length(hc, hc_regs, qtd, halt_status, NULL);
++
++		/* non DWORD-aligned buffer case handling. */
++		if (hc->align_buff && frame_desc->actual_length && hc->ep_is_in) {
++			dwc_memcpy(urb->buf + frame_desc->offset + qtd->isoc_split_offset,
++				   hc->qh->dw_align_buf, frame_desc->actual_length);
++		}
++		/* Skip whole frame */
++		if (hc->qh->do_split && (hc->ep_type == DWC_OTG_EP_TYPE_ISOC) &&
++		    hc->ep_is_in && hcd->core_if->dma_enable) {
++			qtd->complete_split = 0;
++			qtd->isoc_split_offset = 0;
++		}
++
++		break;
++	default:
++		DWC_ASSERT(1, "Unhandled _halt_status (%d)\n", halt_status);
++		break;
++	}
++	if (++qtd->isoc_frame_index == urb->packet_count) {
++		/*
++		 * urb->status is not used for isoc transfers.
++		 * The individual frame_desc statuses are used instead.
++		 */
++		hcd->fops->complete(hcd, urb->priv, urb, 0);
++		ret_val = DWC_OTG_HC_XFER_URB_COMPLETE;
++	} else {
++		ret_val = DWC_OTG_HC_XFER_COMPLETE;
++	}
++	return ret_val;
++}
++
++/**
++ * Frees the first QTD in the QH's list if free_qtd is 1. For non-periodic
++ * QHs, removes the QH from the active non-periodic schedule. If any QTDs are
++ * still linked to the QH, the QH is added to the end of the inactive
++ * non-periodic schedule. For periodic QHs, removes the QH from the periodic
++ * schedule if no more QTDs are linked to the QH.
++ */
++static void deactivate_qh(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, int free_qtd)
++{
++	int continue_split = 0;
++	dwc_otg_qtd_t *qtd;
++
++	DWC_DEBUGPL(DBG_HCDV, "  %s(%p,%p,%d)\n", __func__, hcd, qh, free_qtd);
++
++	qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list);
++
++	if (qtd->complete_split) {
++		continue_split = 1;
++	} else if (qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_MID ||
++		   qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_END) {
++		continue_split = 1;
++	}
++
++	if (free_qtd) {
++		dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
++		continue_split = 0;
++	}
++
++	qh->channel = NULL;
++	dwc_otg_hcd_qh_deactivate(hcd, qh, continue_split);
++}
++
++/**
++ * Releases a host channel for use by other transfers. Attempts to select and
++ * queue more transactions since at least one host channel is available.
++ *
++ * @param hcd The HCD state structure.
++ * @param hc The host channel to release.
++ * @param qtd The QTD associated with the host channel. This QTD may be freed
++ * if the transfer is complete or an error has occurred.
++ * @param halt_status Reason the channel is being released. This status
++ * determines the actions taken by this function.
++ */
++static void release_channel(dwc_otg_hcd_t * hcd,
++			    dwc_hc_t * hc,
++			    dwc_otg_qtd_t * qtd,
++			    dwc_otg_halt_status_e halt_status)
++{
++	dwc_otg_transaction_type_e tr_type;
++	int free_qtd;
++
++	DWC_DEBUGPL(DBG_HCDV, "  %s: channel %d, halt_status %d\n",
++		    __func__, hc->hc_num, halt_status);
++
++	switch (halt_status) {
++	case DWC_OTG_HC_XFER_URB_COMPLETE:
++		free_qtd = 1;
++		break;
++	case DWC_OTG_HC_XFER_AHB_ERR:
++	case DWC_OTG_HC_XFER_STALL:
++	case DWC_OTG_HC_XFER_BABBLE_ERR:
++		free_qtd = 1;
++		break;
++	case DWC_OTG_HC_XFER_XACT_ERR:
++		if (qtd->error_count >= 3) {
++			DWC_DEBUGPL(DBG_HCDV,
++				    "  Complete URB with transaction error\n");
++			free_qtd = 1;
++			qtd->urb->status = -DWC_E_PROTOCOL;
++			hcd->fops->complete(hcd, qtd->urb->priv,
++					    qtd->urb, -DWC_E_PROTOCOL);
++		} else {
++			free_qtd = 0;
++		}
++		break;
++	case DWC_OTG_HC_XFER_URB_DEQUEUE:
++		/*
++		 * The QTD has already been removed and the QH has been
++		 * deactivated. Don't want to do anything except release the
++		 * host channel and try to queue more transfers.
++		 */
++		goto cleanup;
++	case DWC_OTG_HC_XFER_NO_HALT_STATUS:
++		free_qtd = 0;
++		break;
++	case DWC_OTG_HC_XFER_PERIODIC_INCOMPLETE:
++		DWC_DEBUGPL(DBG_HCDV,
++			"  Complete URB with I/O error\n");
++		free_qtd = 1;
++		qtd->urb->status = -DWC_E_IO;
++		hcd->fops->complete(hcd, qtd->urb->priv,
++			qtd->urb, -DWC_E_IO);
++		break;
++	default:
++		free_qtd = 0;
++		break;
++	}
++
++	deactivate_qh(hcd, hc->qh, free_qtd);
++
++cleanup:
++	/*
++	 * Release the host channel for use by other transfers. The cleanup
++	 * function clears the channel interrupt enables and conditions, so
++	 * there's no need to clear the Channel Halted interrupt separately.
++	 */
++	dwc_otg_hc_cleanup(hcd->core_if, hc);
++	DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, hc, hc_list_entry);
++
++	switch (hc->ep_type) {
++	case DWC_OTG_EP_TYPE_CONTROL:
++	case DWC_OTG_EP_TYPE_BULK:
++		hcd->non_periodic_channels--;
++		break;
++
++	default:
++		/*
++		 * Don't release reservations for periodic channels here.
++		 * That's done when a periodic transfer is descheduled (i.e.
++		 * when the QH is removed from the periodic schedule).
++		 */
++		break;
++	}
++
++	/* Try to queue more transfers now that there's a free channel. */
++	tr_type = dwc_otg_hcd_select_transactions(hcd);
++	if (tr_type != DWC_OTG_TRANSACTION_NONE) {
++		dwc_otg_hcd_queue_transactions(hcd, tr_type);
++	}
++}
++
++/**
++ * Halts a host channel. If the channel cannot be halted immediately because
++ * the request queue is full, this function ensures that the FIFO empty
++ * interrupt for the appropriate queue is enabled so that the halt request can
++ * be queued when there is space in the request queue.
++ *
++ * This function may also be called in DMA mode. In that case, the channel is
++ * simply released since the core always halts the channel automatically in
++ * DMA mode.
++ */
++static void halt_channel(dwc_otg_hcd_t * hcd,
++			 dwc_hc_t * hc,
++			 dwc_otg_qtd_t * qtd, dwc_otg_halt_status_e halt_status)
++{
++	if (hcd->core_if->dma_enable) {
++		release_channel(hcd, hc, qtd, halt_status);
++		return;
++	}
++
++	/* Slave mode processing... */
++	dwc_otg_hc_halt(hcd->core_if, hc, halt_status);
++
++	if (hc->halt_on_queue) {
++		gintmsk_data_t gintmsk = {.d32 = 0 };
++		dwc_otg_core_global_regs_t *global_regs;
++		global_regs = hcd->core_if->core_global_regs;
++
++		if (hc->ep_type == DWC_OTG_EP_TYPE_CONTROL ||
++		    hc->ep_type == DWC_OTG_EP_TYPE_BULK) {
++			/*
++			 * Make sure the Non-periodic Tx FIFO empty interrupt
++			 * is enabled so that the non-periodic schedule will
++			 * be processed.
++			 */
++			gintmsk.b.nptxfempty = 1;
++			DWC_MODIFY_REG32(&global_regs->gintmsk, 0, gintmsk.d32);
++		} else {
++			/*
++			 * Move the QH from the periodic queued schedule to
++			 * the periodic assigned schedule. This allows the
++			 * halt to be queued when the periodic schedule is
++			 * processed.
++			 */
++			DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_assigned,
++					   &hc->qh->qh_list_entry);
++
++			/*
++			 * Make sure the Periodic Tx FIFO Empty interrupt is
++			 * enabled so that the periodic schedule will be
++			 * processed.
++			 */
++			gintmsk.b.ptxfempty = 1;
++			DWC_MODIFY_REG32(&global_regs->gintmsk, 0, gintmsk.d32);
++		}
++	}
++}
++
++/**
++ * Performs common cleanup for non-periodic transfers after a Transfer
++ * Complete interrupt. This function should be called after any endpoint type
++ * specific handling is finished to release the host channel.
++ */
++static void complete_non_periodic_xfer(dwc_otg_hcd_t * hcd,
++				       dwc_hc_t * hc,
++				       dwc_otg_hc_regs_t * hc_regs,
++				       dwc_otg_qtd_t * qtd,
++				       dwc_otg_halt_status_e halt_status)
++{
++	hcint_data_t hcint;
++
++	qtd->error_count = 0;
++
++	hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
++	if (hcint.b.nyet) {
++		/*
++		 * Got a NYET on the last transaction of the transfer. This
++		 * means that the endpoint should be in the PING state at the
++		 * beginning of the next transfer.
++		 */
++		hc->qh->ping_state = 1;
++		clear_hc_int(hc_regs, nyet);
++	}
++
++	/*
++	 * Always halt and release the host channel to make it available for
++	 * more transfers. There may still be more phases for a control
++	 * transfer or more data packets for a bulk transfer at this point,
++	 * but the host channel is still halted. A channel will be reassigned
++	 * to the transfer when the non-periodic schedule is processed after
++	 * the channel is released. This allows transactions to be queued
++	 * properly via dwc_otg_hcd_queue_transactions, which also enables the
++	 * Tx FIFO Empty interrupt if necessary.
++	 */
++	if (hc->ep_is_in) {
++		/*
++		 * IN transfers in Slave mode require an explicit disable to
++		 * halt the channel. (In DMA mode, this call simply releases
++		 * the channel.)
++		 */
++		halt_channel(hcd, hc, qtd, halt_status);
++	} else {
++		/*
++		 * The channel is automatically disabled by the core for OUT
++		 * transfers in Slave mode.
++		 */
++		release_channel(hcd, hc, qtd, halt_status);
++	}
++}
++
++/**
++ * Performs common cleanup for periodic transfers after a Transfer Complete
++ * interrupt. This function should be called after any endpoint type specific
++ * handling is finished to release the host channel.
++ */
++static void complete_periodic_xfer(dwc_otg_hcd_t * hcd,
++				   dwc_hc_t * hc,
++				   dwc_otg_hc_regs_t * hc_regs,
++				   dwc_otg_qtd_t * qtd,
++				   dwc_otg_halt_status_e halt_status)
++{
++	hctsiz_data_t hctsiz;
++	qtd->error_count = 0;
++
++	hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
++	if (!hc->ep_is_in || hctsiz.b.pktcnt == 0) {
++		/* Core halts channel in these cases. */
++		release_channel(hcd, hc, qtd, halt_status);
++	} else {
++		/* Flush any outstanding requests from the Tx queue. */
++		halt_channel(hcd, hc, qtd, halt_status);
++	}
++}
++
++static int32_t handle_xfercomp_isoc_split_in(dwc_otg_hcd_t * hcd,
++					     dwc_hc_t * hc,
++					     dwc_otg_hc_regs_t * hc_regs,
++					     dwc_otg_qtd_t * qtd)
++{
++	uint32_t len;
++	struct dwc_otg_hcd_iso_packet_desc *frame_desc;
++	frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index];
++
++	len = get_actual_xfer_length(hc, hc_regs, qtd,
++				     DWC_OTG_HC_XFER_COMPLETE, NULL);
++
++	if (!len) {
++		qtd->complete_split = 0;
++		qtd->isoc_split_offset = 0;
++		return 0;
++	}
++	frame_desc->actual_length += len;
++
++	if (hc->align_buff && len)
++		dwc_memcpy(qtd->urb->buf + frame_desc->offset +
++			   qtd->isoc_split_offset, hc->qh->dw_align_buf, len);
++	qtd->isoc_split_offset += len;
++
++	if (frame_desc->length == frame_desc->actual_length) {
++		frame_desc->status = 0;
++		qtd->isoc_frame_index++;
++		qtd->complete_split = 0;
++		qtd->isoc_split_offset = 0;
++	}
++
++	if (qtd->isoc_frame_index == qtd->urb->packet_count) {
++		hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0);
++		release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_URB_COMPLETE);
++	} else {
++		release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NO_HALT_STATUS);
++	}
++
++	return 1;		/* Indicates that channel released */
++}
++
++/**
++ * Handles a host channel Transfer Complete interrupt. This handler may be
++ * called in either DMA mode or Slave mode.
++ */
++static int32_t handle_hc_xfercomp_intr(dwc_otg_hcd_t * hcd,
++				       dwc_hc_t * hc,
++				       dwc_otg_hc_regs_t * hc_regs,
++				       dwc_otg_qtd_t * qtd)
++{
++	int urb_xfer_done;
++	dwc_otg_halt_status_e halt_status = DWC_OTG_HC_XFER_COMPLETE;
++	dwc_otg_hcd_urb_t *urb = qtd->urb;
++	int pipe_type = dwc_otg_hcd_get_pipe_type(&urb->pipe_info);
++
++	DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
++		    "Transfer Complete--\n", hc->hc_num);
++
++	if (hcd->core_if->dma_desc_enable) {
++		dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs, halt_status);
++		if (pipe_type == UE_ISOCHRONOUS) {
++			/* Do not disable the interrupt, just clear it */
++			clear_hc_int(hc_regs, xfercomp);
++			return 1;
++		}
++		goto handle_xfercomp_done;
++	}
++
++	/*
++	 * Handle xfer complete on CSPLIT.
++	 */
++
++	if (hc->qh->do_split) {
++		if ((hc->ep_type == DWC_OTG_EP_TYPE_ISOC) && hc->ep_is_in
++		    && hcd->core_if->dma_enable) {
++			if (qtd->complete_split
++			    && handle_xfercomp_isoc_split_in(hcd, hc, hc_regs,
++							     qtd))
++				goto handle_xfercomp_done;
++		} else {
++			qtd->complete_split = 0;
++		}
++	}
++
++	/* Update the QTD and URB states. */
++	switch (pipe_type) {
++	case UE_CONTROL:
++		switch (qtd->control_phase) {
++		case DWC_OTG_CONTROL_SETUP:
++			if (urb->length > 0) {
++				qtd->control_phase = DWC_OTG_CONTROL_DATA;
++			} else {
++				qtd->control_phase = DWC_OTG_CONTROL_STATUS;
++			}
++			DWC_DEBUGPL(DBG_HCDV,
++				    "  Control setup transaction done\n");
++			halt_status = DWC_OTG_HC_XFER_COMPLETE;
++			break;
++		case DWC_OTG_CONTROL_DATA:{
++				urb_xfer_done =
++				    update_urb_state_xfer_comp(hc, hc_regs, urb,
++							       qtd);
++				if (urb_xfer_done) {
++					qtd->control_phase =
++					    DWC_OTG_CONTROL_STATUS;
++					DWC_DEBUGPL(DBG_HCDV,
++						    "  Control data transfer done\n");
++				} else {
++					dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
++				}
++				halt_status = DWC_OTG_HC_XFER_COMPLETE;
++				break;
++			}
++		case DWC_OTG_CONTROL_STATUS:
++			DWC_DEBUGPL(DBG_HCDV, "  Control transfer complete\n");
++			if (urb->status == -DWC_E_IN_PROGRESS) {
++				urb->status = 0;
++			}
++			hcd->fops->complete(hcd, urb->priv, urb, urb->status);
++			halt_status = DWC_OTG_HC_XFER_URB_COMPLETE;
++			if (!hcd->core_if->dma_enable && hcd->core_if->otg_ver == 1)
++				qtd->urb = NULL;
++			break;
++		}
++
++		complete_non_periodic_xfer(hcd, hc, hc_regs, qtd, halt_status);
++		break;
++	case UE_BULK:
++		DWC_DEBUGPL(DBG_HCDV, "  Bulk transfer complete\n");
++		urb_xfer_done =
++		    update_urb_state_xfer_comp(hc, hc_regs, urb, qtd);
++		if (urb_xfer_done) {
++			hcd->fops->complete(hcd, urb->priv, urb, urb->status);
++			halt_status = DWC_OTG_HC_XFER_URB_COMPLETE;
++		} else {
++			halt_status = DWC_OTG_HC_XFER_COMPLETE;
++		}
++
++		dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
++		complete_non_periodic_xfer(hcd, hc, hc_regs, qtd, halt_status);
++		break;
++	case UE_INTERRUPT:
++		DWC_DEBUGPL(DBG_HCDV, "  Interrupt transfer complete\n");
++		urb_xfer_done =
++			update_urb_state_xfer_comp(hc, hc_regs, urb, qtd);
++
++		/*
++		 * Interrupt URB is done on the first transfer complete
++		 * interrupt.
++		 */
++		if (urb_xfer_done) {
++				hcd->fops->complete(hcd, urb->priv, urb, urb->status);
++				halt_status = DWC_OTG_HC_XFER_URB_COMPLETE;
++		} else {
++				halt_status = DWC_OTG_HC_XFER_COMPLETE;
++		}
++
++		dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
++		complete_periodic_xfer(hcd, hc, hc_regs, qtd, halt_status);
++		break;
++	case UE_ISOCHRONOUS:
++		DWC_DEBUGPL(DBG_HCDV, "  Isochronous transfer complete\n");
++		if (qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_ALL) {
++			halt_status =
++			    update_isoc_urb_state(hcd, hc, hc_regs, qtd,
++						  DWC_OTG_HC_XFER_COMPLETE);
++		}
++		complete_periodic_xfer(hcd, hc, hc_regs, qtd, halt_status);
++		break;
++	}
++
++handle_xfercomp_done:
++	disable_hc_int(hc_regs, xfercompl);
++
++	return 1;
++}
++
++/**
++ * Handles a host channel STALL interrupt. This handler may be called in
++ * either DMA mode or Slave mode.
++ */
++static int32_t handle_hc_stall_intr(dwc_otg_hcd_t * hcd,
++				    dwc_hc_t * hc,
++				    dwc_otg_hc_regs_t * hc_regs,
++				    dwc_otg_qtd_t * qtd)
++{
++	dwc_otg_hcd_urb_t *urb = qtd->urb;
++	int pipe_type = dwc_otg_hcd_get_pipe_type(&urb->pipe_info);
++
++	DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
++		    "STALL Received--\n", hc->hc_num);
++
++	if (hcd->core_if->dma_desc_enable) {
++		dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs, DWC_OTG_HC_XFER_STALL);
++		goto handle_stall_done;
++	}
++
++	if (pipe_type == UE_CONTROL) {
++		hcd->fops->complete(hcd, urb->priv, urb, -DWC_E_PIPE);
++	}
++
++	if (pipe_type == UE_BULK || pipe_type == UE_INTERRUPT) {
++		hcd->fops->complete(hcd, urb->priv, urb, -DWC_E_PIPE);
++		/*
++		 * USB protocol requires resetting the data toggle for bulk
++		 * and interrupt endpoints when a CLEAR_FEATURE(ENDPOINT_HALT)
++		 * setup command is issued to the endpoint. Anticipate the
++		 * CLEAR_FEATURE command since a STALL has occurred and reset
++		 * the data toggle now.
++		 */
++		hc->qh->data_toggle = 0;
++	}
++
++	halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_STALL);
++
++handle_stall_done:
++	disable_hc_int(hc_regs, stall);
++
++	return 1;
++}
++
++/*
++ * Updates the state of the URB when a transfer has been stopped due to an
++ * abnormal condition before the transfer completes. Modifies the
++ * actual_length field of the URB to reflect the number of bytes that have
++ * actually been transferred via the host channel.
++ */
++static void update_urb_state_xfer_intr(dwc_hc_t * hc,
++				       dwc_otg_hc_regs_t * hc_regs,
++				       dwc_otg_hcd_urb_t * urb,
++				       dwc_otg_qtd_t * qtd,
++				       dwc_otg_halt_status_e halt_status)
++{
++	uint32_t bytes_transferred = get_actual_xfer_length(hc, hc_regs, qtd,
++							    halt_status, NULL);
++	/* non DWORD-aligned buffer case handling. */
++	if (hc->align_buff && bytes_transferred && hc->ep_is_in) {
++		dwc_memcpy(urb->buf + urb->actual_length, hc->qh->dw_align_buf,
++			   bytes_transferred);
++	}
++
++	urb->actual_length += bytes_transferred;
++
++#ifdef DEBUG
++	{
++		hctsiz_data_t hctsiz;
++		hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
++		DWC_DEBUGPL(DBG_HCDV, "DWC_otg: %s: %s, channel %d\n",
++			    __func__, (hc->ep_is_in ? "IN" : "OUT"),
++			    hc->hc_num);
++		DWC_DEBUGPL(DBG_HCDV, "  hc->start_pkt_count %d\n",
++			    hc->start_pkt_count);
++		DWC_DEBUGPL(DBG_HCDV, "  hctsiz.pktcnt %d\n", hctsiz.b.pktcnt);
++		DWC_DEBUGPL(DBG_HCDV, "  hc->max_packet %d\n", hc->max_packet);
++		DWC_DEBUGPL(DBG_HCDV, "  bytes_transferred %d\n",
++			    bytes_transferred);
++		DWC_DEBUGPL(DBG_HCDV, "  urb->actual_length %d\n",
++			    urb->actual_length);
++		DWC_DEBUGPL(DBG_HCDV, "  urb->transfer_buffer_length %d\n",
++			    urb->length);
++	}
++#endif
++}
++
++/**
++ * Handles a host channel NAK interrupt. This handler may be called in either
++ * DMA mode or Slave mode.
++ */
++static int32_t handle_hc_nak_intr(dwc_otg_hcd_t * hcd,
++				  dwc_hc_t * hc,
++				  dwc_otg_hc_regs_t * hc_regs,
++				  dwc_otg_qtd_t * qtd)
++{
++	DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
++		    "NAK Received--\n", hc->hc_num);
++
++	/*
++	 * Handle NAK for IN/OUT SSPLIT/CSPLIT transfers, bulk, control, and
++	 * interrupt.  Re-start the SSPLIT transfer.
++	 */
++	if (hc->do_split) {
++		if (hc->complete_split) {
++			qtd->error_count = 0;
++		}
++		qtd->complete_split = 0;
++		halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NAK);
++		goto handle_nak_done;
++	}
++
++	switch (dwc_otg_hcd_get_pipe_type(&qtd->urb->pipe_info)) {
++	case UE_CONTROL:
++	case UE_BULK:
++		if (hcd->core_if->dma_enable && hc->ep_is_in) {
++			/*
++			 * NAK interrupts are enabled on bulk/control IN
++			 * transfers in DMA mode for the sole purpose of
++			 * resetting the error count after a transaction error
++			 * occurs. The core will continue transferring data.
++			 */
++			qtd->error_count = 0;
++			goto handle_nak_done;
++		}
++
++		/*
++		 * NAK interrupts normally occur during OUT transfers in DMA
++		 * or Slave mode. For IN transfers, more requests will be
++		 * queued as request queue space is available.
++		 */
++		qtd->error_count = 0;
++
++		if (!hc->qh->ping_state) {
++			update_urb_state_xfer_intr(hc, hc_regs,
++						   qtd->urb, qtd,
++						   DWC_OTG_HC_XFER_NAK);
++			dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
++
++			if (hc->speed == DWC_OTG_EP_SPEED_HIGH)
++				hc->qh->ping_state = 1;
++		}
++
++		/*
++		 * Halt the channel so the transfer can be re-started from
++		 * the appropriate point or the PING protocol will
++		 * start/continue.
++		 */
++		halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NAK);
++		break;
++	case UE_INTERRUPT:
++		qtd->error_count = 0;
++		halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NAK);
++		break;
++	case UE_ISOCHRONOUS:
++		/* Should never get called for isochronous transfers. */
++		DWC_ASSERT(1, "NACK interrupt for ISOC transfer\n");
++		break;
++	}
++
++handle_nak_done:
++	disable_hc_int(hc_regs, nak);
++
++	return 1;
++}
++
++/**
++ * Handles a host channel ACK interrupt. This interrupt is enabled when
++ * performing the PING protocol in Slave mode, when errors occur during
++ * either Slave mode or DMA mode, and during Start Split transactions.
++ */
++static int32_t handle_hc_ack_intr(dwc_otg_hcd_t * hcd,
++				  dwc_hc_t * hc,
++				  dwc_otg_hc_regs_t * hc_regs,
++				  dwc_otg_qtd_t * qtd)
++{
++	DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
++		    "ACK Received--\n", hc->hc_num);
++
++	if (hc->do_split) {
++		/*
++		 * Handle ACK on SSPLIT.
++		 * ACK should not occur in CSPLIT.
++		 */
++		if (!hc->ep_is_in && hc->data_pid_start != DWC_OTG_HC_PID_SETUP) {
++			qtd->ssplit_out_xfer_count = hc->xfer_len;
++		}
++		if (!(hc->ep_type == DWC_OTG_EP_TYPE_ISOC && !hc->ep_is_in)) {
++			/* Don't need complete for isochronous out transfers. */
++			qtd->complete_split = 1;
++		}
++
++		/* ISOC OUT */
++		if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC && !hc->ep_is_in) {
++			switch (hc->xact_pos) {
++			case DWC_HCSPLIT_XACTPOS_ALL:
++				break;
++			case DWC_HCSPLIT_XACTPOS_END:
++				qtd->isoc_split_pos = DWC_HCSPLIT_XACTPOS_ALL;
++				qtd->isoc_split_offset = 0;
++				break;
++			case DWC_HCSPLIT_XACTPOS_BEGIN:
++			case DWC_HCSPLIT_XACTPOS_MID:
++				/*
++				 * For BEGIN or MID, calculate the length for
++				 * the next microframe to determine the correct
++				 * SSPLIT token, either MID or END.
++				 */
++				{
++					struct dwc_otg_hcd_iso_packet_desc
++					*frame_desc;
++
++					frame_desc =
++					    &qtd->urb->
++					    iso_descs[qtd->isoc_frame_index];
++					qtd->isoc_split_offset += 188;
++
++					if ((frame_desc->length -
++					     qtd->isoc_split_offset) <= 188) {
++						qtd->isoc_split_pos =
++						    DWC_HCSPLIT_XACTPOS_END;
++					} else {
++						qtd->isoc_split_pos =
++						    DWC_HCSPLIT_XACTPOS_MID;
++					}
++
++				}
++				break;
++			}
++		} else {
++			halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_ACK);
++		}
++	} else {
++		qtd->error_count = 0;
++
++		if (hc->qh->ping_state) {
++			hc->qh->ping_state = 0;
++			/*
++			 * Halt the channel so the transfer can be re-started
++			 * from the appropriate point. This only happens in
++			 * Slave mode. In DMA mode, the ping_state is cleared
++			 * when the transfer is started because the core
++			 * automatically executes the PING, then the transfer.
++			 */
++			halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_ACK);
++		}
++	}
++
++	/*
++	 * If the ACK occurred when _not_ in the PING state, let the channel
++	 * continue transferring data after clearing the error count.
++	 */
++
++	disable_hc_int(hc_regs, ack);
++
++	return 1;
++}
++
++/**
++ * Handles a host channel NYET interrupt. This interrupt should only occur on
++ * Bulk and Control OUT endpoints and for complete split transactions. If a
++ * NYET occurs at the same time as a Transfer Complete interrupt, it is
++ * handled in the xfercomp interrupt handler, not here. This handler may be
++ * called in either DMA mode or Slave mode.
++ */
++static int32_t handle_hc_nyet_intr(dwc_otg_hcd_t * hcd,
++				   dwc_hc_t * hc,
++				   dwc_otg_hc_regs_t * hc_regs,
++				   dwc_otg_qtd_t * qtd)
++{
++	DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
++		    "NYET Received--\n", hc->hc_num);
++
++	/*
++	 * NYET on CSPLIT
++	 * re-do the CSPLIT immediately on non-periodic
++	 */
++	if (hc->do_split && hc->complete_split) {
++		if (hc->ep_is_in && (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)
++		    && hcd->core_if->dma_enable) {
++			qtd->complete_split = 0;
++			qtd->isoc_split_offset = 0;
++			if (++qtd->isoc_frame_index == qtd->urb->packet_count) {
++				hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0);
++				release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_URB_COMPLETE);
++			}
++			else
++				release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NO_HALT_STATUS);
++			goto handle_nyet_done;
++		}
++
++		if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
++		    hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
++			int frnum = dwc_otg_hcd_get_frame_number(hcd);
++
++			if (dwc_full_frame_num(frnum) !=
++			    dwc_full_frame_num(hc->qh->sched_frame)) {
++				/*
++				 * No longer in the same full speed frame.
++				 * Treat this as a transaction error.
++				 */
++#if 0
++				/** @todo Fix system performance so this can
++				 * be treated as an error. Right now complete
++				 * splits cannot be scheduled precisely enough
++				 * due to other system activity, so this error
++				 * occurs regularly in Slave mode.
++				 */
++				qtd->error_count++;
++#endif
++				qtd->complete_split = 0;
++				halt_channel(hcd, hc, qtd,
++					     DWC_OTG_HC_XFER_XACT_ERR);
++				/** @todo add support for isoc release */
++				goto handle_nyet_done;
++			}
++		}
++
++		halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NYET);
++		goto handle_nyet_done;
++	}
++
++	hc->qh->ping_state = 1;
++	qtd->error_count = 0;
++
++	update_urb_state_xfer_intr(hc, hc_regs, qtd->urb, qtd,
++				   DWC_OTG_HC_XFER_NYET);
++	dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
++
++	/*
++	 * Halt the channel and re-start the transfer so the PING
++	 * protocol will start.
++	 */
++	halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NYET);
++
++handle_nyet_done:
++	disable_hc_int(hc_regs, nyet);
++	return 1;
++}
++
++/**
++ * Handles a host channel babble interrupt. This handler may be called in
++ * either DMA mode or Slave mode.
++ */
++static int32_t handle_hc_babble_intr(dwc_otg_hcd_t * hcd,
++				     dwc_hc_t * hc,
++				     dwc_otg_hc_regs_t * hc_regs,
++				     dwc_otg_qtd_t * qtd)
++{
++	DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
++		    "Babble Error--\n", hc->hc_num);
++
++	if (hcd->core_if->dma_desc_enable) {
++		dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs,
++					       DWC_OTG_HC_XFER_BABBLE_ERR);
++		goto handle_babble_done;
++	}
++
++	if (hc->ep_type != DWC_OTG_EP_TYPE_ISOC) {
++		hcd->fops->complete(hcd, qtd->urb->priv,
++				    qtd->urb, -DWC_E_OVERFLOW);
++		halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_BABBLE_ERR);
++	} else {
++		dwc_otg_halt_status_e halt_status;
++		halt_status = update_isoc_urb_state(hcd, hc, hc_regs, qtd,
++						    DWC_OTG_HC_XFER_BABBLE_ERR);
++		halt_channel(hcd, hc, qtd, halt_status);
++	}
++
++handle_babble_done:
++	disable_hc_int(hc_regs, bblerr);
++	return 1;
++}
++
++/**
++ * Handles a host channel AHB error interrupt. This handler is only called in
++ * DMA mode.
++ */
++static int32_t handle_hc_ahberr_intr(dwc_otg_hcd_t * hcd,
++				     dwc_hc_t * hc,
++				     dwc_otg_hc_regs_t * hc_regs,
++				     dwc_otg_qtd_t * qtd)
++{
++	hcchar_data_t hcchar;
++	hcsplt_data_t hcsplt;
++	hctsiz_data_t hctsiz;
++	uint32_t hcdma;
++	char *pipetype, *speed;
++
++	dwc_otg_hcd_urb_t *urb = qtd->urb;
++
++	DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
++		    "AHB Error--\n", hc->hc_num);
++
++	hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
++	hcsplt.d32 = DWC_READ_REG32(&hc_regs->hcsplt);
++	hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
++	hcdma = DWC_READ_REG32(&hc_regs->hcdma);
++
++	DWC_ERROR("AHB ERROR, Channel %d\n", hc->hc_num);
++	DWC_ERROR("  hcchar 0x%08x, hcsplt 0x%08x\n", hcchar.d32, hcsplt.d32);
++	DWC_ERROR("  hctsiz 0x%08x, hcdma 0x%08x\n", hctsiz.d32, hcdma);
++	DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Enqueue\n");
++	DWC_ERROR("  Device address: %d\n",
++		  dwc_otg_hcd_get_dev_addr(&urb->pipe_info));
++	DWC_ERROR("  Endpoint: %d, %s\n",
++		  dwc_otg_hcd_get_ep_num(&urb->pipe_info),
++		  (dwc_otg_hcd_is_pipe_in(&urb->pipe_info) ? "IN" : "OUT"));
++
++	switch (dwc_otg_hcd_get_pipe_type(&urb->pipe_info)) {
++	case UE_CONTROL:
++		pipetype = "CONTROL";
++		break;
++	case UE_BULK:
++		pipetype = "BULK";
++		break;
++	case UE_INTERRUPT:
++		pipetype = "INTERRUPT";
++		break;
++	case UE_ISOCHRONOUS:
++		pipetype = "ISOCHRONOUS";
++		break;
++	default:
++		pipetype = "UNKNOWN";
++		break;
++	}
++
++	DWC_ERROR("  Endpoint type: %s\n", pipetype);
++
++	switch (hc->speed) {
++	case DWC_OTG_EP_SPEED_HIGH:
++		speed = "HIGH";
++		break;
++	case DWC_OTG_EP_SPEED_FULL:
++		speed = "FULL";
++		break;
++	case DWC_OTG_EP_SPEED_LOW:
++		speed = "LOW";
++		break;
++	default:
++		speed = "UNKNOWN";
++		break;
++	};
++
++	DWC_ERROR("  Speed: %s\n", speed);
++
++	DWC_ERROR("  Max packet size: %d\n",
++		  dwc_otg_hcd_get_mps(&urb->pipe_info));
++	DWC_ERROR("  Data buffer length: %d\n", urb->length);
++	DWC_ERROR("  Transfer buffer: %p, Transfer DMA: %p\n",
++		  urb->buf, (void *)urb->dma);
++	DWC_ERROR("  Setup buffer: %p, Setup DMA: %p\n",
++		  urb->setup_packet, (void *)urb->setup_dma);
++	DWC_ERROR("  Interval: %d\n", urb->interval);
++
++	/* Core haltes the channel for Descriptor DMA mode */
++	if (hcd->core_if->dma_desc_enable) {
++		dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs,
++					       DWC_OTG_HC_XFER_AHB_ERR);
++		goto handle_ahberr_done;
++	}
++
++	hcd->fops->complete(hcd, urb->priv, urb, -DWC_E_IO);
++
++	/*
++	 * Force a channel halt. Don't call halt_channel because that won't
++	 * write to the HCCHARn register in DMA mode to force the halt.
++	 */
++	dwc_otg_hc_halt(hcd->core_if, hc, DWC_OTG_HC_XFER_AHB_ERR);
++handle_ahberr_done:
++	disable_hc_int(hc_regs, ahberr);
++	return 1;
++}
++
++/**
++ * Handles a host channel transaction error interrupt. This handler may be
++ * called in either DMA mode or Slave mode.
++ */
++static int32_t handle_hc_xacterr_intr(dwc_otg_hcd_t * hcd,
++				      dwc_hc_t * hc,
++				      dwc_otg_hc_regs_t * hc_regs,
++				      dwc_otg_qtd_t * qtd)
++{
++	DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
++		    "Transaction Error--\n", hc->hc_num);
++
++	if (hcd->core_if->dma_desc_enable) {
++		dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs,
++					       DWC_OTG_HC_XFER_XACT_ERR);
++		goto handle_xacterr_done;
++	}
++
++	switch (dwc_otg_hcd_get_pipe_type(&qtd->urb->pipe_info)) {
++	case UE_CONTROL:
++	case UE_BULK:
++		qtd->error_count++;
++		if (!hc->qh->ping_state) {
++
++			update_urb_state_xfer_intr(hc, hc_regs,
++						   qtd->urb, qtd,
++						   DWC_OTG_HC_XFER_XACT_ERR);
++			dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
++			if (!hc->ep_is_in && hc->speed == DWC_OTG_EP_SPEED_HIGH) {
++				hc->qh->ping_state = 1;
++			}
++		}
++
++		/*
++		 * Halt the channel so the transfer can be re-started from
++		 * the appropriate point or the PING protocol will start.
++		 */
++		halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_XACT_ERR);
++		break;
++	case UE_INTERRUPT:
++		qtd->error_count++;
++		if (hc->do_split && hc->complete_split) {
++			qtd->complete_split = 0;
++		}
++		halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_XACT_ERR);
++		break;
++	case UE_ISOCHRONOUS:
++		{
++			dwc_otg_halt_status_e halt_status;
++			halt_status =
++			    update_isoc_urb_state(hcd, hc, hc_regs, qtd,
++						  DWC_OTG_HC_XFER_XACT_ERR);
++
++			halt_channel(hcd, hc, qtd, halt_status);
++		}
++		break;
++	}
++handle_xacterr_done:
++	disable_hc_int(hc_regs, xacterr);
++
++	return 1;
++}
++
++/**
++ * Handles a host channel frame overrun interrupt. This handler may be called
++ * in either DMA mode or Slave mode.
++ */
++static int32_t handle_hc_frmovrun_intr(dwc_otg_hcd_t * hcd,
++				       dwc_hc_t * hc,
++				       dwc_otg_hc_regs_t * hc_regs,
++				       dwc_otg_qtd_t * qtd)
++{
++	DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
++		    "Frame Overrun--\n", hc->hc_num);
++
++	switch (dwc_otg_hcd_get_pipe_type(&qtd->urb->pipe_info)) {
++	case UE_CONTROL:
++	case UE_BULK:
++		break;
++	case UE_INTERRUPT:
++		halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_FRAME_OVERRUN);
++		break;
++	case UE_ISOCHRONOUS:
++		{
++			dwc_otg_halt_status_e halt_status;
++			halt_status =
++			    update_isoc_urb_state(hcd, hc, hc_regs, qtd,
++						  DWC_OTG_HC_XFER_FRAME_OVERRUN);
++
++			halt_channel(hcd, hc, qtd, halt_status);
++		}
++		break;
++	}
++
++	disable_hc_int(hc_regs, frmovrun);
++
++	return 1;
++}
++
++/**
++ * Handles a host channel data toggle error interrupt. This handler may be
++ * called in either DMA mode or Slave mode.
++ */
++static int32_t handle_hc_datatglerr_intr(dwc_otg_hcd_t * hcd,
++					 dwc_hc_t * hc,
++					 dwc_otg_hc_regs_t * hc_regs,
++					 dwc_otg_qtd_t * qtd)
++{
++	DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
++		    "Data Toggle Error--\n", hc->hc_num);
++
++	if (hc->ep_is_in) {
++		qtd->error_count = 0;
++	} else {
++		DWC_ERROR("Data Toggle Error on OUT transfer,"
++			  "channel %d\n", hc->hc_num);
++	}
++
++	disable_hc_int(hc_regs, datatglerr);
++
++	return 1;
++}
++
++#ifdef DEBUG
++/**
++ * This function is for debug only. It checks that a valid halt status is set
++ * and that HCCHARn.chdis is clear. If there's a problem, corrective action is
++ * taken and a warning is issued.
++ * @return 1 if halt status is ok, 0 otherwise.
++ */
++static inline int halt_status_ok(dwc_otg_hcd_t * hcd,
++				 dwc_hc_t * hc,
++				 dwc_otg_hc_regs_t * hc_regs,
++				 dwc_otg_qtd_t * qtd)
++{
++	hcchar_data_t hcchar;
++	hctsiz_data_t hctsiz;
++	hcint_data_t hcint;
++	hcintmsk_data_t hcintmsk;
++	hcsplt_data_t hcsplt;
++
++	if (hc->halt_status == DWC_OTG_HC_XFER_NO_HALT_STATUS) {
++		/*
++		 * This code is here only as a check. This condition should
++		 * never happen. Ignore the halt if it does occur.
++		 */
++		hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
++		hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
++		hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
++		hcintmsk.d32 = DWC_READ_REG32(&hc_regs->hcintmsk);
++		hcsplt.d32 = DWC_READ_REG32(&hc_regs->hcsplt);
++		DWC_WARN
++		    ("%s: hc->halt_status == DWC_OTG_HC_XFER_NO_HALT_STATUS, "
++		     "channel %d, hcchar 0x%08x, hctsiz 0x%08x, "
++		     "hcint 0x%08x, hcintmsk 0x%08x, "
++		     "hcsplt 0x%08x, qtd->complete_split %d\n", __func__,
++		     hc->hc_num, hcchar.d32, hctsiz.d32, hcint.d32,
++		     hcintmsk.d32, hcsplt.d32, qtd->complete_split);
++
++		DWC_WARN("%s: no halt status, channel %d, ignoring interrupt\n",
++			 __func__, hc->hc_num);
++		DWC_WARN("\n");
++		clear_hc_int(hc_regs, chhltd);
++		return 0;
++	}
++
++	/*
++	 * This code is here only as a check. hcchar.chdis should
++	 * never be set when the halt interrupt occurs. Halt the
++	 * channel again if it does occur.
++	 */
++	hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
++	if (hcchar.b.chdis) {
++		DWC_WARN("%s: hcchar.chdis set unexpectedly, "
++			 "hcchar 0x%08x, trying to halt again\n",
++			 __func__, hcchar.d32);
++		clear_hc_int(hc_regs, chhltd);
++		hc->halt_pending = 0;
++		halt_channel(hcd, hc, qtd, hc->halt_status);
++		return 0;
++	}
++
++	return 1;
++}
++#endif
++
++/**
++ * Handles a host Channel Halted interrupt in DMA mode. This handler
++ * determines the reason the channel halted and proceeds accordingly.
++ */
++static void handle_hc_chhltd_intr_dma(dwc_otg_hcd_t * hcd,
++				      dwc_hc_t * hc,
++				      dwc_otg_hc_regs_t * hc_regs,
++				      dwc_otg_qtd_t * qtd)
++{
++	hcint_data_t hcint;
++	hcintmsk_data_t hcintmsk;
++	int out_nak_enh = 0;
++
++	/* For core with OUT NAK enhancement, the flow for high-
++	 * speed CONTROL/BULK OUT is handled a little differently.
++	 */
++	if (hcd->core_if->snpsid >= OTG_CORE_REV_2_71a) {
++		if (hc->speed == DWC_OTG_EP_SPEED_HIGH && !hc->ep_is_in &&
++		    (hc->ep_type == DWC_OTG_EP_TYPE_CONTROL ||
++		     hc->ep_type == DWC_OTG_EP_TYPE_BULK)) {
++			out_nak_enh = 1;
++		}
++	}
++
++	if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE ||
++	    (hc->halt_status == DWC_OTG_HC_XFER_AHB_ERR
++	     && !hcd->core_if->dma_desc_enable)) {
++		/*
++		 * Just release the channel. A dequeue can happen on a
++		 * transfer timeout. In the case of an AHB Error, the channel
++		 * was forced to halt because there's no way to gracefully
++		 * recover.
++		 */
++		if (hcd->core_if->dma_desc_enable)
++			dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs,
++						       hc->halt_status);
++		else
++			release_channel(hcd, hc, qtd, hc->halt_status);
++		return;
++	}
++
++	/* Read the HCINTn register to determine the cause for the halt. */
++	hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
++	hcintmsk.d32 = DWC_READ_REG32(&hc_regs->hcintmsk);
++
++	if (hcint.b.xfercomp) {
++		/** @todo This is here because of a possible hardware bug.  Spec
++		 * says that on SPLIT-ISOC OUT transfers in DMA mode that a HALT
++		 * interrupt w/ACK bit set should occur, but I only see the
++		 * XFERCOMP bit, even with it masked out.  This is a workaround
++		 * for that behavior.  Should fix this when hardware is fixed.
++		 */
++		if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC && !hc->ep_is_in) {
++			handle_hc_ack_intr(hcd, hc, hc_regs, qtd);
++		}
++		handle_hc_xfercomp_intr(hcd, hc, hc_regs, qtd);
++	} else if (hcint.b.stall) {
++		handle_hc_stall_intr(hcd, hc, hc_regs, qtd);
++	} else if (hcint.b.xacterr && !hcd->core_if->dma_desc_enable) {
++		if (out_nak_enh) {
++			if (hcint.b.nyet || hcint.b.nak || hcint.b.ack) {
++				DWC_DEBUG("XactErr with NYET/NAK/ACK\n");
++				qtd->error_count = 0;
++			} else {
++				DWC_DEBUG("XactErr without NYET/NAK/ACK\n");
++			}
++		}
++
++		/*
++		 * Must handle xacterr before nak or ack. Could get a xacterr
++		 * at the same time as either of these on a BULK/CONTROL OUT
++		 * that started with a PING. The xacterr takes precedence.
++		 */
++		handle_hc_xacterr_intr(hcd, hc, hc_regs, qtd);
++	} else if (hcint.b.xcs_xact && hcd->core_if->dma_desc_enable) {
++		handle_hc_xacterr_intr(hcd, hc, hc_regs, qtd);
++	} else if (hcint.b.ahberr && hcd->core_if->dma_desc_enable) {
++		handle_hc_ahberr_intr(hcd, hc, hc_regs, qtd);
++	} else if (hcint.b.bblerr) {
++		handle_hc_babble_intr(hcd, hc, hc_regs, qtd);
++	} else if (hcint.b.frmovrun) {
++		handle_hc_frmovrun_intr(hcd, hc, hc_regs, qtd);
++	} else if (!out_nak_enh) {
++		if (hcint.b.nyet) {
++			/*
++			 * Must handle nyet before nak or ack. Could get a nyet at the
++			 * same time as either of those on a BULK/CONTROL OUT that
++			 * started with a PING. The nyet takes precedence.
++			 */
++			handle_hc_nyet_intr(hcd, hc, hc_regs, qtd);
++		} else if (hcint.b.nak && !hcintmsk.b.nak) {
++			/*
++			 * If nak is not masked, it's because a non-split IN transfer
++			 * is in an error state. In that case, the nak is handled by
++			 * the nak interrupt handler, not here. Handle nak here for
++			 * BULK/CONTROL OUT transfers, which halt on a NAK to allow
++			 * rewinding the buffer pointer.
++			 */
++			handle_hc_nak_intr(hcd, hc, hc_regs, qtd);
++		} else if (hcint.b.ack && !hcintmsk.b.ack) {
++			/*
++			 * If ack is not masked, it's because a non-split IN transfer
++			 * is in an error state. In that case, the ack is handled by
++			 * the ack interrupt handler, not here. Handle ack here for
++			 * split transfers. Start splits halt on ACK.
++			 */
++			handle_hc_ack_intr(hcd, hc, hc_regs, qtd);
++		} else {
++			if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
++			    hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
++				/*
++				 * A periodic transfer halted with no other channel
++				 * interrupts set. Assume it was halted by the core
++				 * because it could not be completed in its scheduled
++				 * (micro)frame.
++				 */
++#ifdef DEBUG
++				DWC_PRINTF
++				    ("%s: Halt channel %d (assume incomplete periodic transfer)\n",
++				     __func__, hc->hc_num);
++#endif
++				halt_channel(hcd, hc, qtd,
++					     DWC_OTG_HC_XFER_PERIODIC_INCOMPLETE);
++			} else {
++				DWC_ERROR
++				    ("%s: Channel %d, DMA Mode -- ChHltd set, but reason "
++				     "for halting is unknown, hcint 0x%08x, intsts 0x%08x\n",
++				     __func__, hc->hc_num, hcint.d32,
++				     DWC_READ_REG32(&hcd->
++						    core_if->core_global_regs->
++						    gintsts));
++				disable_hc_int(hc_regs, chhltd);
++			}
++
++		}
++	} else {
++		DWC_PRINTF("NYET/NAK/ACK/other in non-error case, 0x%08x\n",
++			   hcint.d32);
++		disable_hc_int(hc_regs, chhltd);
++	}
++}
++
++/**
++ * Handles a host channel Channel Halted interrupt.
++ *
++ * In slave mode, this handler is called only when the driver specifically
++ * requests a halt. This occurs during handling other host channel interrupts
++ * (e.g. nak, xacterr, stall, nyet, etc.).
++ *
++ * In DMA mode, this is the interrupt that occurs when the core has finished
++ * processing a transfer on a channel. Other host channel interrupts (except
++ * ahberr) are disabled in DMA mode.
++ */
++static int32_t handle_hc_chhltd_intr(dwc_otg_hcd_t * hcd,
++				     dwc_hc_t * hc,
++				     dwc_otg_hc_regs_t * hc_regs,
++				     dwc_otg_qtd_t * qtd)
++{
++	DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
++		    "Channel Halted--\n", hc->hc_num);
++
++	if (hcd->core_if->dma_enable) {
++		handle_hc_chhltd_intr_dma(hcd, hc, hc_regs, qtd);
++	} else {
++#ifdef DEBUG
++		if (!halt_status_ok(hcd, hc, hc_regs, qtd)) {
++			return 1;
++		}
++#endif
++		release_channel(hcd, hc, qtd, hc->halt_status);
++	}
++
++	return 1;
++}
++
++/** Handles interrupt for a specific Host Channel */
++int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t * dwc_otg_hcd, uint32_t num)
++{
++	int retval = 0;
++	hcint_data_t hcint;
++	hcintmsk_data_t hcintmsk;
++	dwc_hc_t *hc;
++	dwc_otg_hc_regs_t *hc_regs;
++	dwc_otg_qtd_t *qtd;
++
++	DWC_DEBUGPL(DBG_HCDV, "--Host Channel Interrupt--, Channel %d\n", num);
++
++	hc = dwc_otg_hcd->hc_ptr_array[num];
++	hc_regs = dwc_otg_hcd->core_if->host_if->hc_regs[num];
++	qtd = DWC_CIRCLEQ_FIRST(&hc->qh->qtd_list);
++
++	hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
++	hcintmsk.d32 = DWC_READ_REG32(&hc_regs->hcintmsk);
++	DWC_DEBUGPL(DBG_HCDV,
++		    "  hcint 0x%08x, hcintmsk 0x%08x, hcint&hcintmsk 0x%08x\n",
++		    hcint.d32, hcintmsk.d32, (hcint.d32 & hcintmsk.d32));
++	hcint.d32 = hcint.d32 & hcintmsk.d32;
++
++	if (!dwc_otg_hcd->core_if->dma_enable) {
++		if (hcint.b.chhltd && hcint.d32 != 0x2) {
++			hcint.b.chhltd = 0;
++		}
++	}
++
++	if (hcint.b.xfercomp) {
++		retval |=
++		    handle_hc_xfercomp_intr(dwc_otg_hcd, hc, hc_regs, qtd);
++		/*
++		 * If NYET occurred at same time as Xfer Complete, the NYET is
++		 * handled by the Xfer Complete interrupt handler. Don't want
++		 * to call the NYET interrupt handler in this case.
++		 */
++		hcint.b.nyet = 0;
++	}
++	if (hcint.b.chhltd) {
++		retval |= handle_hc_chhltd_intr(dwc_otg_hcd, hc, hc_regs, qtd);
++	}
++	if (hcint.b.ahberr) {
++		retval |= handle_hc_ahberr_intr(dwc_otg_hcd, hc, hc_regs, qtd);
++	}
++	if (hcint.b.stall) {
++		retval |= handle_hc_stall_intr(dwc_otg_hcd, hc, hc_regs, qtd);
++	}
++	if (hcint.b.nak) {
++		retval |= handle_hc_nak_intr(dwc_otg_hcd, hc, hc_regs, qtd);
++	}
++	if (hcint.b.ack) {
++		retval |= handle_hc_ack_intr(dwc_otg_hcd, hc, hc_regs, qtd);
++	}
++	if (hcint.b.nyet) {
++		retval |= handle_hc_nyet_intr(dwc_otg_hcd, hc, hc_regs, qtd);
++	}
++	if (hcint.b.xacterr) {
++		retval |= handle_hc_xacterr_intr(dwc_otg_hcd, hc, hc_regs, qtd);
++	}
++	if (hcint.b.bblerr) {
++		retval |= handle_hc_babble_intr(dwc_otg_hcd, hc, hc_regs, qtd);
++	}
++	if (hcint.b.frmovrun) {
++		retval |=
++		    handle_hc_frmovrun_intr(dwc_otg_hcd, hc, hc_regs, qtd);
++	}
++	if (hcint.b.datatglerr) {
++		retval |=
++		    handle_hc_datatglerr_intr(dwc_otg_hcd, hc, hc_regs, qtd);
++	}
++
++	return retval;
++}
++
++#endif /* DWC_DEVICE_ONLY */
+diff --git a/drivers/usb/gadget/udc/hiudc/dwc_otg_hcd_linux.c b/drivers/usb/gadget/udc/hiudc/dwc_otg_hcd_linux.c
+new file mode 100644
+index 0000000..7323ef3
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc/dwc_otg_hcd_linux.c
+@@ -0,0 +1,840 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_linux.c $
++ * $Revision: #23 $
++ * $Date: 2013/04/22 $
++ * $Change: 2211149 $
++ *
++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
++ * ========================================================================== */
++#ifndef DWC_DEVICE_ONLY
++
++/**
++ * @file
++ *
++ * This file contains the implementation of the HCD. In Linux, the HCD
++ * implements the hc_driver API.
++ */
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/init.h>
++#include <linux/device.h>
++#include <linux/errno.h>
++#include <linux/list.h>
++#include <linux/interrupt.h>
++#include <linux/string.h>
++#include <linux/dma-mapping.h>
++#include <linux/version.h>
++#include <asm/io.h>
++#include <linux/usb.h>
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)
++#include <../drivers/usb/core/hcd.h>
++#else
++#include <linux/usb/hcd.h>
++#endif
++
++#include "dwc_otg_hcd_if.h"
++#include "dwc_otg_dbg.h"
++#include "dwc_otg_driver.h"
++#include "dwc_otg_hcd.h"
++/**
++ * Gets the endpoint number from a _bEndpointAddress argument. The endpoint is
++ * qualified with its direction (possible 32 endpoints per device).
++ */
++#define dwc_ep_addr_to_endpoint(_bEndpointAddress_) ((_bEndpointAddress_ & USB_ENDPOINT_NUMBER_MASK) | \
++						     ((_bEndpointAddress_ & USB_DIR_IN) != 0) << 4)
++
++static const char dwc_otg_hcd_name[] = "dwc_otg_hcd";
++
++/** @name Linux HC Driver API Functions */
++/** @{ */
++static int urb_enqueue(struct usb_hcd *hcd,
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
++		       struct usb_host_endpoint *ep,
++#endif
++		       struct urb *urb, gfp_t mem_flags);
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
++static int urb_dequeue(struct usb_hcd *hcd, struct urb *urb);
++#else
++static int urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status);
++#endif
++
++static void endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep);
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
++static void endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep);
++#endif
++static irqreturn_t dwc_otg_hcd_irq(struct usb_hcd *hcd);
++extern int hcd_start(struct usb_hcd *hcd);
++extern void hcd_stop(struct usb_hcd *hcd);
++static int get_frame_number(struct usb_hcd *hcd);
++extern int hub_status_data(struct usb_hcd *hcd, char *buf);
++extern int hub_control(struct usb_hcd *hcd,
++		       u16 typeReq,
++		       u16 wValue, u16 wIndex, char *buf, u16 wLength);
++
++struct wrapper_priv_data {
++	dwc_otg_hcd_t *dwc_otg_hcd;
++};
++
++/** @} */
++
++static struct hc_driver dwc_otg_hc_driver = {
++
++	.description = dwc_otg_hcd_name,
++	.product_desc = "DWC OTG Controller",
++	.hcd_priv_size = sizeof(struct wrapper_priv_data),
++
++	.irq = dwc_otg_hcd_irq,
++
++	.flags = HCD_MEMORY | HCD_USB2,
++
++	//.reset =
++	.start = hcd_start,
++	//.suspend =
++	//.resume =
++	.stop = hcd_stop,
++
++	.urb_enqueue = urb_enqueue,
++	.urb_dequeue = urb_dequeue,
++	.endpoint_disable = endpoint_disable,
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
++	.endpoint_reset = endpoint_reset,
++#endif
++	.get_frame_number = get_frame_number,
++
++	.hub_status_data = hub_status_data,
++	.hub_control = hub_control,
++	//.bus_suspend =
++	//.bus_resume =
++};
++
++/** Gets the dwc_otg_hcd from a struct usb_hcd */
++static inline dwc_otg_hcd_t *hcd_to_dwc_otg_hcd(struct usb_hcd *hcd)
++{
++	struct wrapper_priv_data *p;
++	p = (struct wrapper_priv_data *)(hcd->hcd_priv);
++	return p->dwc_otg_hcd;
++}
++
++/** Gets the struct usb_hcd that contains a dwc_otg_hcd_t. */
++static inline struct usb_hcd *dwc_otg_hcd_to_hcd(dwc_otg_hcd_t * dwc_otg_hcd)
++{
++	return dwc_otg_hcd_get_priv_data(dwc_otg_hcd);
++}
++
++/** Gets the usb_host_endpoint associated with an URB. */
++inline struct usb_host_endpoint *dwc_urb_to_endpoint(struct urb *urb)
++{
++	struct usb_device *dev = urb->dev;
++	int ep_num = usb_pipeendpoint(urb->pipe);
++
++	if (usb_pipein(urb->pipe))
++		return dev->ep_in[ep_num];
++	else
++		return dev->ep_out[ep_num];
++}
++
++static int _disconnect(dwc_otg_hcd_t * hcd)
++{
++	struct usb_hcd *usb_hcd = dwc_otg_hcd_to_hcd(hcd);
++
++	usb_hcd->self.is_b_host = 0;
++	return 0;
++}
++
++static int _start(dwc_otg_hcd_t * hcd)
++{
++	struct usb_hcd *usb_hcd = dwc_otg_hcd_to_hcd(hcd);
++
++	usb_hcd->self.is_b_host = dwc_otg_hcd_is_b_host(hcd);
++	hcd_start(usb_hcd);
++
++	return 0;
++}
++
++static int _hub_info(dwc_otg_hcd_t * hcd, void *urb_handle, uint32_t * hub_addr,
++		     uint32_t * port_addr)
++{
++	struct urb *urb = (struct urb *)urb_handle;
++	if (urb->dev->tt) {
++		*hub_addr = urb->dev->tt->hub->devnum;
++	} else {
++		*hub_addr = 0;
++	}
++	*port_addr = urb->dev->ttport;
++	return 0;
++}
++
++static int _speed(dwc_otg_hcd_t * hcd, void *urb_handle)
++{
++	struct urb *urb = (struct urb *)urb_handle;
++	return urb->dev->speed;
++}
++
++static int _get_b_hnp_enable(dwc_otg_hcd_t * hcd)
++{
++	struct usb_hcd *usb_hcd = dwc_otg_hcd_to_hcd(hcd);
++	return usb_hcd->self.b_hnp_enable;
++}
++
++static void allocate_bus_bandwidth(struct usb_hcd *hcd, uint32_t bw,
++				   struct urb *urb)
++{
++	hcd_to_bus(hcd)->bandwidth_allocated += bw / urb->interval;
++	if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
++		hcd_to_bus(hcd)->bandwidth_isoc_reqs++;
++	} else {
++		hcd_to_bus(hcd)->bandwidth_int_reqs++;
++	}
++}
++
++static void free_bus_bandwidth(struct usb_hcd *hcd, uint32_t bw,
++			       struct urb *urb)
++{
++	hcd_to_bus(hcd)->bandwidth_allocated -= bw / urb->interval;
++	if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
++		hcd_to_bus(hcd)->bandwidth_isoc_reqs--;
++	} else {
++		hcd_to_bus(hcd)->bandwidth_int_reqs--;
++	}
++}
++
++/**
++ * Sets the final status of an URB and returns it to the device driver. Any
++ * required cleanup of the URB is performed.
++ */
++static int _complete(dwc_otg_hcd_t * hcd, void *urb_handle,
++		     dwc_otg_hcd_urb_t * dwc_otg_urb, int32_t status)
++{
++	struct urb *urb = (struct urb *)urb_handle;
++#ifdef DEBUG
++	if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
++		DWC_PRINTF("%s: urb %p, device %d, ep %d %s, status=%d\n",
++			   __func__, urb, usb_pipedevice(urb->pipe),
++			   usb_pipeendpoint(urb->pipe),
++			   usb_pipein(urb->pipe) ? "IN" : "OUT", status);
++		if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
++			int i;
++			for (i = 0; i < urb->number_of_packets; i++) {
++				DWC_PRINTF("  ISO Desc %d status: %d\n",
++					   i, urb->iso_frame_desc[i].status);
++			}
++		}
++	}
++#endif
++
++	urb->actual_length = dwc_otg_hcd_urb_get_actual_length(dwc_otg_urb);
++	/* Convert status value. */
++	switch (status) {
++	case -DWC_E_PROTOCOL:
++		status = -EPROTO;
++		break;
++	case -DWC_E_IN_PROGRESS:
++		status = -EINPROGRESS;
++		break;
++	case -DWC_E_PIPE:
++		status = -EPIPE;
++		break;
++	case -DWC_E_IO:
++		status = -EIO;
++		break;
++	case -DWC_E_TIMEOUT:
++		status = -ETIMEDOUT;
++		break;
++	case -DWC_E_OVERFLOW:
++		status = -EOVERFLOW;
++		break;
++	default:
++		if (status) {
++			DWC_PRINTF("Uknown urb status %d\n", status);
++
++		}
++	}
++
++	if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
++		int i;
++
++		urb->error_count = dwc_otg_hcd_urb_get_error_count(dwc_otg_urb);
++		for (i = 0; i < urb->number_of_packets; ++i) {
++			urb->iso_frame_desc[i].actual_length =
++			    dwc_otg_hcd_urb_get_iso_desc_actual_length
++			    (dwc_otg_urb, i);
++			urb->iso_frame_desc[i].status =
++			    dwc_otg_hcd_urb_get_iso_desc_status(dwc_otg_urb, i);
++		}
++	}
++
++	urb->status = status;
++	urb->hcpriv = NULL;
++	if (!status) {
++		if ((urb->transfer_flags & URB_SHORT_NOT_OK) &&
++		    (urb->actual_length < urb->transfer_buffer_length)) {
++			urb->status = -EREMOTEIO;
++		}
++	}
++
++	if ((usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) ||
++	    (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) {
++		struct usb_host_endpoint *ep = dwc_urb_to_endpoint(urb);
++		if (ep) {
++			free_bus_bandwidth(dwc_otg_hcd_to_hcd(hcd),
++					   dwc_otg_hcd_get_ep_bandwidth(hcd,
++									ep->hcpriv),
++					   urb);
++		}
++	}
++
++	DWC_FREE(dwc_otg_urb);
++
++	DWC_SPINUNLOCK(hcd->lock);
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
++	usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb);
++#else
++	usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb, status);
++#endif
++	DWC_SPINLOCK(hcd->lock);
++
++	return 0;
++}
++
++static struct dwc_otg_hcd_function_ops hcd_fops = {
++	.start = _start,
++	.disconnect = _disconnect,
++	.hub_info = _hub_info,
++	.speed = _speed,
++	.complete = _complete,
++	.get_b_hnp_enable = _get_b_hnp_enable,
++};
++
++/**
++ * Initializes the HCD. This function allocates memory for and initializes the
++ * static parts of the usb_hcd and dwc_otg_hcd structures. It also registers the
++ * USB bus with the core and calls the hc_driver->start() function. It returns
++ * a negative error on failure.
++ */
++int hcd_init(
++#ifdef LM_INTERFACE
++		    struct lm_device *_dev
++#elif  defined(PCI_INTERFACE)
++		    struct pci_dev *_dev
++#endif
++    )
++{
++	struct usb_hcd *hcd = NULL;
++	dwc_otg_hcd_t *dwc_otg_hcd = NULL;
++#ifdef LM_INTERFACE
++	dwc_otg_device_t *otg_dev = lm_get_drvdata(_dev);
++#elif  defined(PCI_INTERFACE)
++	dwc_otg_device_t *otg_dev = pci_get_drvdata(_dev);
++#endif
++
++	int retval = 0;
++
++	DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD INIT\n");
++
++	/* Set device flags indicating whether the HCD supports DMA. */
++	if (dwc_otg_is_dma_enable(otg_dev->core_if)) {
++#ifdef LM_INTERFACE
++		_dev->dev.dma_mask = (void *)~0;
++		_dev->dev.coherent_dma_mask = ~0;
++#elif  defined(PCI_INTERFACE)
++		pci_set_dma_mask(_dev, DMA_BIT_MASK(32));
++		pci_set_consistent_dma_mask(_dev, DMA_BIT_MASK(32));
++#endif
++
++	} else {
++#ifdef LM_INTERFACE
++		_dev->dev.dma_mask = (void *)0;
++		_dev->dev.coherent_dma_mask = 0;
++#elif  defined(PCI_INTERFACE)
++		pci_set_dma_mask(_dev, 0);
++		pci_set_consistent_dma_mask(_dev, 0);
++#endif
++	}
++
++	/*
++	 * Allocate memory for the base HCD plus the DWC OTG HCD.
++	 * Initialize the base HCD.
++	 */
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
++	hcd = usb_create_hcd(&dwc_otg_hc_driver, &_dev->dev, _dev->dev.bus_id);
++#else
++	hcd = usb_create_hcd(&dwc_otg_hc_driver, &_dev->dev, dev_name(&_dev->dev));
++	hcd->has_tt = 1;
++//      hcd->uses_new_polling = 1;
++//      hcd->poll_rh = 0;
++#endif
++	if (!hcd) {
++		retval = -ENOMEM;
++		goto error1;
++	}
++
++	hcd->regs = otg_dev->os_dep.base;
++
++	/* Initialize the DWC OTG HCD. */
++	dwc_otg_hcd = dwc_otg_hcd_alloc_hcd();
++	if (!dwc_otg_hcd) {
++		goto error2;
++	}
++	((struct wrapper_priv_data *)(hcd->hcd_priv))->dwc_otg_hcd =
++	    dwc_otg_hcd;
++	otg_dev->hcd = dwc_otg_hcd;
++
++	if (dwc_otg_hcd_init(dwc_otg_hcd, otg_dev->core_if)) {
++		goto error2;
++	}
++
++	otg_dev->hcd->otg_dev = otg_dev;
++	hcd->self.otg_port = dwc_otg_hcd_otg_port(dwc_otg_hcd);
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33) //don't support for LM(with 2.6.20.1 kernel)
++	hcd->self.otg_version = dwc_otg_get_otg_version(otg_dev->core_if);
++	/* Don't support SG list at this point */
++	hcd->self.sg_tablesize = 0;
++#endif
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)
++	/* Do not to do HNP polling if not capable */
++	if (otg_dev->core_if->otg_ver)
++		hcd->self.is_hnp_cap = dwc_otg_get_hnpcapable(otg_dev->core_if);
++#endif
++	/*
++	 * Finish generic HCD initialization and start the HCD. This function
++	 * allocates the DMA buffer pool, registers the USB bus, requests the
++	 * IRQ line, and calls hcd_start method.
++	 */
++	retval = usb_add_hcd(hcd, _dev->irq, IRQF_SHARED | IRQF_DISABLED);
++	if (retval < 0) {
++		goto error2;
++	}
++
++	dwc_otg_hcd_set_priv_data(dwc_otg_hcd, hcd);
++	return 0;
++
++error2:
++	usb_put_hcd(hcd);
++error1:
++	return retval;
++}
++
++/**
++ * Removes the HCD.
++ * Frees memory and resources associated with the HCD and deregisters the bus.
++ */
++void hcd_remove(
++#ifdef LM_INTERFACE
++		       struct lm_device *_dev
++#elif  defined(PCI_INTERFACE)
++		       struct pci_dev *_dev
++#endif
++    )
++{
++#ifdef LM_INTERFACE
++	dwc_otg_device_t *otg_dev = lm_get_drvdata(_dev);
++#elif  defined(PCI_INTERFACE)
++	dwc_otg_device_t *otg_dev = pci_get_drvdata(_dev);
++#endif
++
++	dwc_otg_hcd_t *dwc_otg_hcd;
++	struct usb_hcd *hcd;
++
++	DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD REMOVE\n");
++
++	if (!otg_dev) {
++		DWC_DEBUGPL(DBG_ANY, "%s: otg_dev NULL!\n", __func__);
++		return;
++	}
++
++	dwc_otg_hcd = otg_dev->hcd;
++
++	if (!dwc_otg_hcd) {
++		DWC_DEBUGPL(DBG_ANY, "%s: otg_dev->hcd NULL!\n", __func__);
++		return;
++	}
++
++	hcd = dwc_otg_hcd_to_hcd(dwc_otg_hcd);
++
++	if (!hcd) {
++		DWC_DEBUGPL(DBG_ANY,
++			    "%s: dwc_otg_hcd_to_hcd(dwc_otg_hcd) NULL!\n",
++			    __func__);
++		return;
++	}
++	usb_remove_hcd(hcd);
++	dwc_otg_hcd_set_priv_data(dwc_otg_hcd, NULL);
++	dwc_otg_hcd_remove(dwc_otg_hcd);
++	usb_put_hcd(hcd);
++}
++
++/* =========================================================================
++ *  Linux HC Driver Functions
++ * ========================================================================= */
++
++/** Initializes the DWC_otg controller and its root hub and prepares it for host
++ * mode operation. Activates the root port. Returns 0 on success and a negative
++ * error code on failure. */
++int hcd_start(struct usb_hcd *hcd)
++{
++	dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
++	struct usb_bus *bus;
++
++	DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD START\n");
++	bus = hcd_to_bus(hcd);
++
++	hcd->state = HC_STATE_RUNNING;
++	if (dwc_otg_hcd_start(dwc_otg_hcd, &hcd_fops)) {
++		if (dwc_otg_hcd->core_if->otg_ver && dwc_otg_is_device_mode(dwc_otg_hcd->core_if))
++			dwc_otg_hcd->core_if->op_state = B_PERIPHERAL;
++		return 0;
++	}
++
++	/* Initialize and connect root hub if one is not already attached */
++	if (bus->root_hub) {
++		DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD Has Root Hub\n");
++		/* Inform the HUB driver to resume. */
++		usb_hcd_resume_root_hub(hcd);
++	}
++
++	return 0;
++}
++
++/**
++ * Halts the DWC_otg host mode operations in a clean manner. USB transfers are
++ * stopped.
++ */
++void hcd_stop(struct usb_hcd *hcd)
++{
++	dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
++
++	dwc_otg_hcd_stop(dwc_otg_hcd);
++}
++
++/** Returns the current frame number. */
++static int get_frame_number(struct usb_hcd *hcd)
++{
++	dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
++
++	return dwc_otg_hcd_get_frame_number(dwc_otg_hcd);
++}
++
++#ifdef DEBUG
++static void dump_urb_info(struct urb *urb, char *fn_name)
++{
++	DWC_PRINTF("%s, urb %p\n", fn_name, urb);
++	DWC_PRINTF("  Device address: %d\n", usb_pipedevice(urb->pipe));
++	DWC_PRINTF("  Endpoint: %d, %s\n", usb_pipeendpoint(urb->pipe),
++		   (usb_pipein(urb->pipe) ? "IN" : "OUT"));
++	DWC_PRINTF("  Endpoint type: %s\n", ( {
++					     char *pipetype;
++					     switch (usb_pipetype(urb->pipe)) {
++case PIPE_CONTROL:
++pipetype = "CONTROL"; break; case PIPE_BULK:
++pipetype = "BULK"; break; case PIPE_INTERRUPT:
++pipetype = "INTERRUPT"; break; case PIPE_ISOCHRONOUS:
++pipetype = "ISOCHRONOUS"; break; default:
++					     pipetype = "UNKNOWN"; break;};
++					     pipetype;}
++		   )) ;
++	DWC_PRINTF("  Speed: %s\n", ( {
++				     char *speed; switch (urb->dev->speed) {
++case USB_SPEED_HIGH:
++speed = "HIGH"; break; case USB_SPEED_FULL:
++speed = "FULL"; break; case USB_SPEED_LOW:
++speed = "LOW"; break; default:
++				     speed = "UNKNOWN"; break;};
++				     speed;}
++		   )) ;
++	DWC_PRINTF("  Max packet size: %d\n",
++		   usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)));
++	DWC_PRINTF("  Data buffer length: %d\n", urb->transfer_buffer_length);
++	DWC_PRINTF("  Transfer buffer: %p, Transfer DMA: %p\n",
++		   urb->transfer_buffer, (void *)urb->transfer_dma);
++	DWC_PRINTF("  Setup buffer: %p, Setup DMA: %p\n",
++		   urb->setup_packet, (void *)urb->setup_dma);
++	DWC_PRINTF("  Interval: %d\n", urb->interval);
++	if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
++		int i;
++		for (i = 0; i < urb->number_of_packets; i++) {
++			DWC_PRINTF("  ISO Desc %d:\n", i);
++			DWC_PRINTF("    offset: %d, length %d\n",
++				   urb->iso_frame_desc[i].offset,
++				   urb->iso_frame_desc[i].length);
++		}
++	}
++}
++
++#endif
++
++/** Starts processing a USB transfer request specified by a USB Request Block
++ * (URB). mem_flags indicates the type of memory allocation to use while
++ * processing this URB. */
++static int urb_enqueue(struct usb_hcd *hcd,
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
++		       struct usb_host_endpoint *ep,
++#endif
++		       struct urb *urb, gfp_t mem_flags)
++{
++	int retval = 0;
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
++	struct usb_host_endpoint *ep = urb->ep;
++#endif
++	dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
++	dwc_otg_hcd_urb_t *dwc_otg_urb;
++	int i;
++	int alloc_bandwidth = 0;
++	uint8_t ep_type = 0;
++	uint32_t flags = 0;
++	void *buf;
++
++#ifdef DEBUG
++	if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
++		dump_urb_info(urb, "urb_enqueue");
++	}
++#endif
++
++	if ((usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS)
++	    || (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) {
++		if (!dwc_otg_hcd_is_bandwidth_allocated
++		    (dwc_otg_hcd, &ep->hcpriv)) {
++			alloc_bandwidth = 1;
++		}
++	}
++
++	switch (usb_pipetype(urb->pipe)) {
++	case PIPE_CONTROL:
++		ep_type = USB_ENDPOINT_XFER_CONTROL;
++		break;
++	case PIPE_ISOCHRONOUS:
++		ep_type = USB_ENDPOINT_XFER_ISOC;
++		break;
++	case PIPE_BULK:
++		ep_type = USB_ENDPOINT_XFER_BULK;
++		break;
++	case PIPE_INTERRUPT:
++		ep_type = USB_ENDPOINT_XFER_INT;
++		break;
++	default:
++		DWC_WARN("Wrong ep type\n");
++	}
++
++	dwc_otg_urb = dwc_otg_hcd_urb_alloc(dwc_otg_hcd,
++					    urb->number_of_packets,
++					    mem_flags == GFP_ATOMIC ? 1 : 0);
++
++	dwc_otg_hcd_urb_set_pipeinfo(dwc_otg_urb, usb_pipedevice(urb->pipe),
++				     usb_pipeendpoint(urb->pipe), ep_type,
++				     usb_pipein(urb->pipe),
++				     usb_maxpacket(urb->dev, urb->pipe,
++						   !(usb_pipein(urb->pipe))));
++
++	buf = urb->transfer_buffer;
++	if (hcd->self.uses_dma) {
++		/*
++		 * Calculate virtual address from physical address,
++		 * because some class driver may not fill transfer_buffer.
++		 * In Buffer DMA mode virual address is used,
++		 * when handling non DWORD aligned buffers.
++		 */
++		buf = phys_to_virt(urb->transfer_dma);
++	}
++
++	if (!(urb->transfer_flags & URB_NO_INTERRUPT))
++		flags |= URB_GIVEBACK_ASAP;
++	if (urb->transfer_flags & URB_ZERO_PACKET)
++		flags |= URB_SEND_ZERO_PACKET;
++
++	dwc_otg_hcd_urb_set_params(dwc_otg_urb, urb, buf,
++				   urb->transfer_dma,
++				   urb->transfer_buffer_length,
++				   urb->setup_packet,
++				   urb->setup_dma, flags, urb->interval);
++
++	for (i = 0; i < urb->number_of_packets; ++i) {
++		dwc_otg_hcd_urb_set_iso_desc_params(dwc_otg_urb, i,
++						    urb->
++						    iso_frame_desc[i].offset,
++						    urb->
++						    iso_frame_desc[i].length);
++	}
++
++	urb->hcpriv = dwc_otg_urb;
++	retval = dwc_otg_hcd_urb_enqueue(dwc_otg_hcd, dwc_otg_urb, &ep->hcpriv,
++					 mem_flags == GFP_ATOMIC ? 1 : 0);
++	if (!retval) {
++		if (alloc_bandwidth) {
++			allocate_bus_bandwidth(hcd,
++					       dwc_otg_hcd_get_ep_bandwidth
++					       (dwc_otg_hcd, ep->hcpriv), urb);
++		}
++	} else {
++		if (retval == -DWC_E_NO_DEVICE) {
++			retval = -ENODEV;
++		}
++	}
++
++	return retval;
++}
++
++/** Aborts/cancels a USB transfer request. Always returns 0 to indicate
++ * success.  */
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
++static int urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
++#else
++static int urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
++#endif
++{
++	dwc_irqflags_t flags;
++	dwc_otg_hcd_t *dwc_otg_hcd;
++	DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Dequeue\n");
++
++	dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
++
++#ifdef DEBUG
++	if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
++		dump_urb_info(urb, "urb_dequeue");
++	}
++#endif
++
++	DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &flags);
++
++	dwc_otg_hcd_urb_dequeue(dwc_otg_hcd, urb->hcpriv);
++
++	DWC_FREE(urb->hcpriv);
++	urb->hcpriv = NULL;
++	DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, flags);
++
++	/* Higher layer software sets URB status. */
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
++	usb_hcd_giveback_urb(hcd, urb);
++#else
++	usb_hcd_giveback_urb(hcd, urb, status);
++#endif
++	if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
++		DWC_PRINTF("Called usb_hcd_giveback_urb()\n");
++		DWC_PRINTF("  urb->status = %d\n", urb->status);
++	}
++
++	return 0;
++}
++
++/* Frees resources in the DWC_otg controller related to a given endpoint. Also
++ * clears state in the HCD related to the endpoint. Any URBs for the endpoint
++ * must already be dequeued. */
++static void endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
++{
++	dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
++
++	DWC_DEBUGPL(DBG_HCD,
++		    "DWC OTG HCD EP DISABLE: _bEndpointAddress=0x%02x, "
++		    "endpoint=%d\n", ep->desc.bEndpointAddress,
++		    dwc_ep_addr_to_endpoint(ep->desc.bEndpointAddress));
++	dwc_otg_hcd_endpoint_disable(dwc_otg_hcd, ep->hcpriv, 250);
++	ep->hcpriv = NULL;
++}
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
++/* Resets endpoint specific parameter values, in current version used to reset
++ * the data toggle(as a WA). This function can be called from usb_clear_halt routine */
++static void endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
++{
++	dwc_irqflags_t flags;
++	struct usb_device *udev = NULL;
++	int epnum = usb_endpoint_num(&ep->desc);
++	int is_out = usb_endpoint_dir_out(&ep->desc);
++	int is_control = usb_endpoint_xfer_control(&ep->desc);
++	dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
++#ifdef LM_INTERFACE
++	struct lm_device *_dev = dwc_otg_hcd->otg_dev->os_dep.lmdev;
++#elif defined(PCI_INTERFACE)
++	struct pci_dev *_dev = dwc_otg_hcd->otg_dev->os_dep.pcidev;
++#endif
++
++	if (_dev)
++		udev = to_usb_device(&_dev->dev);
++	else
++		return;
++
++	DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD EP RESET: Endpoint Num=0x%02d\n", epnum);
++
++	DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &flags);
++	usb_settoggle(udev, epnum, is_out, 0);
++	if (is_control)
++		usb_settoggle(udev, epnum, !is_out, 0);
++
++	if (ep->hcpriv) {
++		dwc_otg_hcd_endpoint_reset(dwc_otg_hcd, ep->hcpriv);
++	}
++	DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, flags);
++}
++#endif
++
++/** Handles host mode interrupts for the DWC_otg controller. Returns IRQ_NONE if
++ * there was no interrupt to handle. Returns IRQ_HANDLED if there was a valid
++ * interrupt.
++ *
++ * This function is called by the USB core when an interrupt occurs */
++static irqreturn_t dwc_otg_hcd_irq(struct usb_hcd *hcd)
++{
++	dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
++	int32_t retval = dwc_otg_hcd_handle_intr(dwc_otg_hcd);
++	if (retval != 0) {
++		S3C2410X_CLEAR_EINTPEND();
++	}
++	return IRQ_RETVAL(retval);
++}
++
++/** Creates Status Change bitmap for the root hub and root port. The bitmap is
++ * returned in buf. Bit 0 is the status change indicator for the root hub. Bit 1
++ * is the status change indicator for the single root port. Returns 1 if either
++ * change indicator is 1, otherwise returns 0. */
++int hub_status_data(struct usb_hcd *hcd, char *buf)
++{
++	dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
++
++	buf[0] = 0;
++	buf[0] |= (dwc_otg_hcd_is_status_changed(dwc_otg_hcd, 1)) << 1;
++
++	return (buf[0] != 0);
++}
++
++/** Handles hub class-specific requests. */
++int hub_control(struct usb_hcd *hcd,
++		u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength)
++{
++	int retval;
++
++	retval = dwc_otg_hcd_hub_control(hcd_to_dwc_otg_hcd(hcd),
++					 typeReq, wValue, wIndex, buf, wLength);
++
++	switch (retval) {
++	case -DWC_E_INVALID:
++		retval = -EINVAL;
++		break;
++	}
++
++	return retval;
++}
++
++#endif /* DWC_DEVICE_ONLY */
+diff --git a/drivers/usb/gadget/udc/hiudc/dwc_otg_hcd_queue.c b/drivers/usb/gadget/udc/hiudc/dwc_otg_hcd_queue.c
+new file mode 100644
+index 0000000..5682867
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc/dwc_otg_hcd_queue.c
+@@ -0,0 +1,727 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_queue.c $
++ * $Revision: #45 $
++ * $Date: 2013/01/24 $
++ * $Change: 2150293 $
++ *
++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
++ * ========================================================================== */
++#ifndef DWC_DEVICE_ONLY
++
++/**
++ * @file
++ *
++ * This file contains the functions to manage Queue Heads and Queue
++ * Transfer Descriptors.
++ */
++
++#include "dwc_otg_hcd.h"
++#include "dwc_otg_regs.h"
++
++/**
++ * Free each QTD in the QH's QTD-list then free the QH.  QH should already be
++ * removed from a list.  QTD list should already be empty if called from URB
++ * Dequeue.
++ *
++ * @param hcd HCD instance.
++ * @param qh The QH to free.
++ */
++void dwc_otg_hcd_qh_free(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
++{
++	dwc_otg_qtd_t *qtd, *qtd_tmp;
++	dwc_irqflags_t flags;
++
++	/* Free each QTD in the QTD list */
++	DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
++	DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &qh->qtd_list, qtd_list_entry) {
++		DWC_CIRCLEQ_REMOVE(&qh->qtd_list, qtd, qtd_list_entry);
++		dwc_otg_hcd_qtd_free(qtd);
++	}
++
++	if (hcd->core_if->dma_desc_enable) {
++		dwc_otg_hcd_qh_free_ddma(hcd, qh);
++	} else if (qh->dw_align_buf) {
++		uint32_t buf_size;
++		if (qh->ep_type == UE_ISOCHRONOUS) {
++			buf_size = 4096;
++		} else {
++			buf_size = hcd->core_if->core_params->max_transfer_size;
++		}
++		DWC_DMA_FREE(buf_size, qh->dw_align_buf, qh->dw_align_buf_dma);
++	}
++
++	DWC_FREE(qh);
++	DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
++	return;
++}
++
++#define BitStuffTime(bytecount)  ((8 * 7* bytecount) / 6)
++#define HS_HOST_DELAY		5	/* nanoseconds */
++#define FS_LS_HOST_DELAY	1000	/* nanoseconds */
++#define HUB_LS_SETUP		333	/* nanoseconds */
++#define NS_TO_US(ns)		((ns + 500) / 1000)
++				/* convert & round nanoseconds to microseconds */
++
++static uint32_t calc_bus_time(int speed, int is_in, int is_isoc, int bytecount)
++{
++	unsigned long retval;
++
++	switch (speed) {
++	case USB_SPEED_HIGH:
++		if (is_isoc) {
++			retval =
++			    ((38 * 8 * 2083) +
++			     (2083 * (3 + BitStuffTime(bytecount)))) / 1000 +
++			    HS_HOST_DELAY;
++		} else {
++			retval =
++			    ((55 * 8 * 2083) +
++			     (2083 * (3 + BitStuffTime(bytecount)))) / 1000 +
++			    HS_HOST_DELAY;
++		}
++		break;
++	case USB_SPEED_FULL:
++		if (is_isoc) {
++			retval =
++			    (8354 * (31 + 10 * BitStuffTime(bytecount))) / 1000;
++			if (is_in) {
++				retval = 7268 + FS_LS_HOST_DELAY + retval;
++			} else {
++				retval = 6265 + FS_LS_HOST_DELAY + retval;
++			}
++		} else {
++			retval =
++			    (8354 * (31 + 10 * BitStuffTime(bytecount))) / 1000;
++			retval = 9107 + FS_LS_HOST_DELAY + retval;
++		}
++		break;
++	case USB_SPEED_LOW:
++		if (is_in) {
++			retval =
++			    (67667 * (31 + 10 * BitStuffTime(bytecount))) /
++			    1000;
++			retval =
++			    64060 + (2 * HUB_LS_SETUP) + FS_LS_HOST_DELAY +
++			    retval;
++		} else {
++			retval =
++			    (66700 * (31 + 10 * BitStuffTime(bytecount))) /
++			    1000;
++			retval =
++			    64107 + (2 * HUB_LS_SETUP) + FS_LS_HOST_DELAY +
++			    retval;
++		}
++		break;
++	default:
++		DWC_WARN("Unknown device speed\n");
++		retval = -1;
++	}
++
++	return NS_TO_US(retval);
++}
++
++/**
++ * Initializes a QH structure.
++ *
++ * @param hcd The HCD state structure for the DWC OTG controller.
++ * @param qh  The QH to init.
++ * @param urb Holds the information about the device/endpoint that we need
++ *	      to initialize the QH.
++ */
++#define SCHEDULE_SLOP 10
++void qh_init(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, dwc_otg_hcd_urb_t * urb)
++{
++	char *speed, *type;
++	int dev_speed;
++	uint32_t hub_addr, hub_port;
++
++	dwc_memset(qh, 0, sizeof(dwc_otg_qh_t));
++
++	/* Initialize QH */
++	qh->ep_type = dwc_otg_hcd_get_pipe_type(&urb->pipe_info);
++	qh->ep_is_in = dwc_otg_hcd_is_pipe_in(&urb->pipe_info) ? 1 : 0;
++
++	qh->data_toggle = DWC_OTG_HC_PID_DATA0;
++	qh->maxp = dwc_otg_hcd_get_mps(&urb->pipe_info);
++	DWC_CIRCLEQ_INIT(&qh->qtd_list);
++	DWC_LIST_INIT(&qh->qh_list_entry);
++	qh->channel = NULL;
++
++	/* FS/LS Enpoint on HS Hub
++	 * NOT virtual root hub */
++	dev_speed = hcd->fops->speed(hcd, urb->priv);
++
++	hcd->fops->hub_info(hcd, urb->priv, &hub_addr, &hub_port);
++	qh->do_split = 0;
++
++	if (((dev_speed == USB_SPEED_LOW) ||
++	     (dev_speed == USB_SPEED_FULL)) &&
++	    (hub_addr != 0 && hub_addr != 1)) {
++		DWC_DEBUGPL(DBG_HCD,
++			    "QH init: EP %d: TT found at hub addr %d, for port %d\n",
++			    dwc_otg_hcd_get_ep_num(&urb->pipe_info), hub_addr,
++			    hub_port);
++		qh->do_split = 1;
++	}
++
++	if (qh->ep_type == UE_INTERRUPT || qh->ep_type == UE_ISOCHRONOUS) {
++		/* Compute scheduling parameters once and save them. */
++		hprt0_data_t hprt;
++
++		/** @todo Account for split transfers in the bus time. */
++		int bytecount =
++		    dwc_hb_mult(qh->maxp) * dwc_max_packet(qh->maxp);
++
++		qh->usecs =
++		    calc_bus_time((qh->do_split ? USB_SPEED_HIGH : dev_speed),
++				  qh->ep_is_in, (qh->ep_type == UE_ISOCHRONOUS),
++				  bytecount);
++		/* Start in a slightly future (micro)frame. */
++		qh->sched_frame = dwc_frame_num_inc(hcd->frame_number,
++						    SCHEDULE_SLOP);
++		qh->interval = urb->interval;
++
++#if 0
++		/* Increase interrupt polling rate for debugging. */
++		if (qh->ep_type == UE_INTERRUPT) {
++			qh->interval = 8;
++		}
++#endif
++		hprt.d32 = DWC_READ_REG32(hcd->core_if->host_if->hprt0);
++		if ((hprt.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED) &&
++		    ((dev_speed == USB_SPEED_LOW) ||
++		     (dev_speed == USB_SPEED_FULL))) {
++			qh->interval *= 8;
++			qh->sched_frame |= 0x7;
++			qh->start_split_frame = qh->sched_frame;
++		}
++
++	}
++
++	DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD QH Initialized\n");
++	DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH  - qh = %p\n", qh);
++	DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH  - Device Address = %d\n",
++		    dwc_otg_hcd_get_dev_addr(&urb->pipe_info));
++	DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH  - Endpoint %d, %s\n",
++		    dwc_otg_hcd_get_ep_num(&urb->pipe_info),
++		    dwc_otg_hcd_is_pipe_in(&urb->pipe_info) ? "IN" : "OUT");
++	switch (dev_speed) {
++	case USB_SPEED_LOW:
++		qh->dev_speed = DWC_OTG_EP_SPEED_LOW;
++		speed = "low";
++		break;
++	case USB_SPEED_FULL:
++		qh->dev_speed = DWC_OTG_EP_SPEED_FULL;
++		speed = "full";
++		break;
++	case USB_SPEED_HIGH:
++		qh->dev_speed = DWC_OTG_EP_SPEED_HIGH;
++		speed = "high";
++		break;
++	default:
++		speed = "?";
++		break;
++	}
++	DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH  - Speed = %s\n", speed);
++
++	switch (qh->ep_type) {
++	case UE_ISOCHRONOUS:
++		type = "isochronous";
++		break;
++	case UE_INTERRUPT:
++		type = "interrupt";
++		break;
++	case UE_CONTROL:
++		type = "control";
++		break;
++	case UE_BULK:
++		type = "bulk";
++		break;
++	default:
++		type = "?";
++		break;
++	}
++
++	DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH  - Type = %s\n", type);
++
++#ifdef DEBUG
++	if (qh->ep_type == UE_INTERRUPT) {
++		DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - usecs = %d\n",
++			    qh->usecs);
++		DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - interval = %d\n",
++			    qh->interval);
++	}
++#endif
++
++}
++
++/**
++ * This function allocates and initializes a QH.
++ *
++ * @param hcd The HCD state structure for the DWC OTG controller.
++ * @param urb Holds the information about the device/endpoint that we need
++ *	      to initialize the QH.
++ * @param atomic_alloc Flag to do atomic allocation if needed
++ *
++ * @return Returns pointer to the newly allocated QH, or NULL on error. */
++dwc_otg_qh_t *dwc_otg_hcd_qh_create(dwc_otg_hcd_t * hcd,
++				    dwc_otg_hcd_urb_t * urb, int atomic_alloc)
++{
++	dwc_otg_qh_t *qh;
++
++	/* Allocate memory */
++	/** @todo add memflags argument */
++	qh = dwc_otg_hcd_qh_alloc(atomic_alloc);
++	if (qh == NULL) {
++		DWC_ERROR("qh allocation failed");
++		return NULL;
++	}
++
++	qh_init(hcd, qh, urb);
++
++	if (hcd->core_if->dma_desc_enable
++	    && (dwc_otg_hcd_qh_init_ddma(hcd, qh) < 0)) {
++		dwc_otg_hcd_qh_free(hcd, qh);
++		return NULL;
++	}
++
++	return qh;
++}
++
++/**
++ * Checks that a channel is available for a periodic transfer.
++ *
++ * @return 0 if successful, negative error code otherise.
++ */
++static int periodic_channel_available(dwc_otg_hcd_t * hcd)
++{
++	/*
++	 * Currently assuming that there is a dedicated host channnel for each
++	 * periodic transaction plus at least one host channel for
++	 * non-periodic transactions.
++	 */
++	int status;
++	int num_channels;
++
++	num_channels = hcd->core_if->core_params->host_channels;
++	if ((hcd->periodic_channels + hcd->non_periodic_channels < num_channels)
++	    && (hcd->periodic_channels < num_channels - 1)) {
++		status = 0;
++	} else {
++		DWC_INFO("%s: Total channels: %d, Periodic: %d, Non-periodic: %d\n",
++			__func__, num_channels, hcd->periodic_channels, hcd->non_periodic_channels);	//NOTICE
++		status = -DWC_E_NO_SPACE;
++	}
++
++	return status;
++}
++
++/**
++ * Checks that there is sufficient bandwidth for the specified QH in the
++ * periodic schedule. For simplicity, this calculation assumes that all the
++ * transfers in the periodic schedule may occur in the same (micro)frame.
++ *
++ * @param hcd The HCD state structure for the DWC OTG controller.
++ * @param qh QH containing periodic bandwidth required.
++ *
++ * @return 0 if successful, negative error code otherwise.
++ */
++static int check_periodic_bandwidth(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
++{
++	int status;
++	int16_t max_claimed_usecs;
++
++	status = 0;
++
++	if ((qh->dev_speed == DWC_OTG_EP_SPEED_HIGH) || qh->do_split) {
++		/*
++		 * High speed mode.
++		 * Max periodic usecs is 80% x 125 usec = 100 usec.
++		 */
++
++		max_claimed_usecs = 100 - qh->usecs;
++	} else {
++		/*
++		 * Full speed mode.
++		 * Max periodic usecs is 90% x 1000 usec = 900 usec.
++		 */
++		max_claimed_usecs = 900 - qh->usecs;
++	}
++
++	if (hcd->periodic_usecs > max_claimed_usecs) {
++		DWC_INFO("%s: already claimed usecs %d, required usecs %d\n", __func__, hcd->periodic_usecs, qh->usecs);	//NOTICE
++		status = -DWC_E_NO_SPACE;
++	}
++
++	return status;
++}
++
++/**
++ * Checks that the max transfer size allowed in a host channel is large enough
++ * to handle the maximum data transfer in a single (micro)frame for a periodic
++ * transfer.
++ *
++ * @param hcd The HCD state structure for the DWC OTG controller.
++ * @param qh QH for a periodic endpoint.
++ *
++ * @return 0 if successful, negative error code otherwise.
++ */
++static int check_max_xfer_size(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
++{
++	int status;
++	uint32_t max_xfer_size;
++	uint32_t max_channel_xfer_size;
++
++	status = 0;
++
++	max_xfer_size = dwc_max_packet(qh->maxp) * dwc_hb_mult(qh->maxp);
++	max_channel_xfer_size = hcd->core_if->core_params->max_transfer_size;
++
++	if (max_xfer_size > max_channel_xfer_size) {
++		DWC_INFO("%s: Periodic xfer length %d > " "max xfer length for channel %d\n",
++				__func__, max_xfer_size, max_channel_xfer_size);	//NOTICE
++		status = -DWC_E_NO_SPACE;
++	}
++
++	return status;
++}
++
++/**
++ * Schedules an interrupt or isochronous transfer in the periodic schedule.
++ *
++ * @param hcd The HCD state structure for the DWC OTG controller.
++ * @param qh QH for the periodic transfer. The QH should already contain the
++ * scheduling information.
++ *
++ * @return 0 if successful, negative error code otherwise.
++ */
++static int schedule_periodic(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
++{
++	int status = 0;
++
++	status = periodic_channel_available(hcd);
++	if (status) {
++		DWC_INFO("%s: No host channel available for periodic " "transfer.\n", __func__);	//NOTICE
++		return status;
++	}
++
++	status = check_periodic_bandwidth(hcd, qh);
++	if (status) {
++		DWC_INFO("%s: Insufficient periodic bandwidth for " "periodic transfer.\n", __func__);	//NOTICE
++		return status;
++	}
++
++	status = check_max_xfer_size(hcd, qh);
++	if (status) {
++		DWC_INFO("%s: Channel max transfer size too small " "for periodic transfer.\n", __func__);	//NOTICE
++		return status;
++	}
++
++	if (hcd->core_if->dma_desc_enable) {
++		/* Don't rely on SOF and start in ready schedule */
++		DWC_LIST_INSERT_TAIL(&hcd->periodic_sched_ready, &qh->qh_list_entry);
++	}
++	else {
++	/* Always start in the inactive schedule. */
++	DWC_LIST_INSERT_TAIL(&hcd->periodic_sched_inactive, &qh->qh_list_entry);
++	}
++
++	/* Reserve the periodic channel. */
++	hcd->periodic_channels++;
++
++	/* Update claimed usecs per (micro)frame. */
++	hcd->periodic_usecs += qh->usecs;
++
++	return status;
++}
++
++/**
++ * This function adds a QH to either the non periodic or periodic schedule if
++ * it is not already in the schedule. If the QH is already in the schedule, no
++ * action is taken.
++ *
++ * @return 0 if successful, negative error code otherwise.
++ */
++int dwc_otg_hcd_qh_add(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
++{
++	int status = 0;
++	gintmsk_data_t intr_mask = {.d32 = 0 };
++
++	if (!DWC_LIST_EMPTY(&qh->qh_list_entry)) {
++		/* QH already in a schedule. */
++		return status;
++	}
++
++	/* Add the new QH to the appropriate schedule */
++	if (dwc_qh_is_non_per(qh)) {
++		/* Always start in the inactive schedule. */
++		DWC_LIST_INSERT_TAIL(&hcd->non_periodic_sched_inactive,
++				     &qh->qh_list_entry);
++	} else {
++		status = schedule_periodic(hcd, qh);
++		if ( !hcd->periodic_qh_count ) {
++			intr_mask.b.sofintr = 1;
++			DWC_MODIFY_REG32(&hcd->core_if->core_global_regs->gintmsk,
++								intr_mask.d32, intr_mask.d32);
++		}
++		hcd->periodic_qh_count++;
++	}
++
++	return status;
++}
++
++/**
++ * Removes an interrupt or isochronous transfer from the periodic schedule.
++ *
++ * @param hcd The HCD state structure for the DWC OTG controller.
++ * @param qh QH for the periodic transfer.
++ */
++static void deschedule_periodic(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
++{
++	DWC_LIST_REMOVE_INIT(&qh->qh_list_entry);
++
++	/* Release the periodic channel reservation. */
++	hcd->periodic_channels--;
++
++	/* Update claimed usecs per (micro)frame. */
++	hcd->periodic_usecs -= qh->usecs;
++}
++
++/**
++ * Removes a QH from either the non-periodic or periodic schedule.  Memory is
++ * not freed.
++ *
++ * @param hcd The HCD state structure.
++ * @param qh QH to remove from schedule. */
++void dwc_otg_hcd_qh_remove(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
++{
++	gintmsk_data_t intr_mask = {.d32 = 0 };
++
++	if (DWC_LIST_EMPTY(&qh->qh_list_entry)) {
++		/* QH is not in a schedule. */
++		return;
++	}
++
++	if (dwc_qh_is_non_per(qh)) {
++		if (hcd->non_periodic_qh_ptr == &qh->qh_list_entry) {
++			hcd->non_periodic_qh_ptr =
++			    hcd->non_periodic_qh_ptr->next;
++		}
++		DWC_LIST_REMOVE_INIT(&qh->qh_list_entry);
++	} else {
++		deschedule_periodic(hcd, qh);
++		hcd->periodic_qh_count--;
++		if( !hcd->periodic_qh_count ) {
++			intr_mask.b.sofintr = 1;
++				DWC_MODIFY_REG32(&hcd->core_if->core_global_regs->gintmsk,
++									intr_mask.d32, 0);
++		}
++	}
++}
++
++/**
++ * Deactivates a QH. For non-periodic QHs, removes the QH from the active
++ * non-periodic schedule. The QH is added to the inactive non-periodic
++ * schedule if any QTDs are still attached to the QH.
++ *
++ * For periodic QHs, the QH is removed from the periodic queued schedule. If
++ * there are any QTDs still attached to the QH, the QH is added to either the
++ * periodic inactive schedule or the periodic ready schedule and its next
++ * scheduled frame is calculated. The QH is placed in the ready schedule if
++ * the scheduled frame has been reached already. Otherwise it's placed in the
++ * inactive schedule. If there are no QTDs attached to the QH, the QH is
++ * completely removed from the periodic schedule.
++ */
++void dwc_otg_hcd_qh_deactivate(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh,
++			       int sched_next_periodic_split)
++{
++	if (dwc_qh_is_non_per(qh)) {
++		dwc_otg_hcd_qh_remove(hcd, qh);
++		if (!DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
++			/* Add back to inactive non-periodic schedule. */
++			dwc_otg_hcd_qh_add(hcd, qh);
++		}
++	} else {
++		uint16_t frame_number = dwc_otg_hcd_get_frame_number(hcd);
++
++		if (qh->do_split) {
++			/* Schedule the next continuing periodic split transfer */
++			if (sched_next_periodic_split) {
++
++				qh->sched_frame = frame_number;
++				if (dwc_frame_num_le(frame_number,
++						     dwc_frame_num_inc
++						     (qh->start_split_frame,
++						      1))) {
++					/*
++					 * Allow one frame to elapse after start
++					 * split microframe before scheduling
++					 * complete split, but DONT if we are
++					 * doing the next start split in the
++					 * same frame for an ISOC out.
++					 */
++					if ((qh->ep_type != UE_ISOCHRONOUS) ||
++					    (qh->ep_is_in != 0)) {
++						qh->sched_frame =
++						    dwc_frame_num_inc(qh->sched_frame, 1);
++					}
++				}
++			} else {
++				qh->sched_frame =
++				    dwc_frame_num_inc(qh->start_split_frame,
++						      qh->interval);
++				if (dwc_frame_num_le
++				    (qh->sched_frame, frame_number)) {
++					qh->sched_frame = frame_number;
++				}
++				qh->sched_frame |= 0x7;
++				qh->start_split_frame = qh->sched_frame;
++			}
++		} else {
++			qh->sched_frame =
++			    dwc_frame_num_inc(qh->sched_frame, qh->interval);
++			if (dwc_frame_num_le(qh->sched_frame, frame_number)) {
++				qh->sched_frame = frame_number;
++			}
++		}
++
++		if (DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
++			dwc_otg_hcd_qh_remove(hcd, qh);
++		} else {
++			/*
++			 * Remove from periodic_sched_queued and move to
++			 * appropriate queue.
++			 */
++			if (qh->sched_frame == frame_number) {
++				DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_ready,
++						   &qh->qh_list_entry);
++			} else {
++				DWC_LIST_MOVE_HEAD
++				    (&hcd->periodic_sched_inactive,
++				     &qh->qh_list_entry);
++			}
++		}
++	}
++}
++
++/**
++ * This function allocates and initializes a QTD.
++ *
++ * @param urb The URB to create a QTD from.  Each URB-QTD pair will end up
++ *	      pointing to each other so each pair should have a unique correlation.
++ * @param atomic_alloc Flag to do atomic alloc if needed
++ *
++ * @return Returns pointer to the newly allocated QTD, or NULL on error. */
++dwc_otg_qtd_t *dwc_otg_hcd_qtd_create(dwc_otg_hcd_urb_t * urb, int atomic_alloc)
++{
++	dwc_otg_qtd_t *qtd;
++
++	qtd = dwc_otg_hcd_qtd_alloc(atomic_alloc);
++	if (qtd == NULL) {
++		return NULL;
++	}
++
++	dwc_otg_hcd_qtd_init(qtd, urb);
++	return qtd;
++}
++
++/**
++ * Initializes a QTD structure.
++ *
++ * @param qtd The QTD to initialize.
++ * @param urb The URB to use for initialization.  */
++void dwc_otg_hcd_qtd_init(dwc_otg_qtd_t * qtd, dwc_otg_hcd_urb_t * urb)
++{
++	dwc_memset(qtd, 0, sizeof(dwc_otg_qtd_t));
++	qtd->urb = urb;
++	if (dwc_otg_hcd_get_pipe_type(&urb->pipe_info) == UE_CONTROL) {
++		/*
++		 * The only time the QTD data toggle is used is on the data
++		 * phase of control transfers. This phase always starts with
++		 * DATA1.
++		 */
++		qtd->data_toggle = DWC_OTG_HC_PID_DATA1;
++		qtd->control_phase = DWC_OTG_CONTROL_SETUP;
++	}
++
++	/* start split */
++	qtd->complete_split = 0;
++	qtd->isoc_split_pos = DWC_HCSPLIT_XACTPOS_ALL;
++	qtd->isoc_split_offset = 0;
++	qtd->in_process = 0;
++
++	/* Store the qtd ptr in the urb to reference what QTD. */
++	urb->qtd = qtd;
++	return;
++}
++
++/**
++ * This function adds a QTD to the QTD-list of a QH.  It will find the correct
++ * QH to place the QTD into.  If it does not find a QH, then it will create a
++ * new QH. If the QH to which the QTD is added is not currently scheduled, it
++ * is placed into the proper schedule based on its EP type.
++ *
++ * @param[in] qtd The QTD to add
++ * @param[in] hcd The DWC HCD structure
++ * @param[out] qh out parameter to return queue head
++ * @param atomic_alloc Flag to do atomic alloc if needed
++ *
++ * @return 0 if successful, negative error code otherwise.
++ */
++int dwc_otg_hcd_qtd_add(dwc_otg_qtd_t * qtd,
++			dwc_otg_hcd_t * hcd, dwc_otg_qh_t ** qh, int atomic_alloc)
++{
++	int retval = 0;
++	dwc_irqflags_t flags;
++
++	dwc_otg_hcd_urb_t *urb = qtd->urb;
++
++	/*
++	 * Get the QH which holds the QTD-list to insert to. Create QH if it
++	 * doesn't exist.
++	 */
++	if (*qh == NULL) {
++		*qh = dwc_otg_hcd_qh_create(hcd, urb, atomic_alloc);
++		if (*qh == NULL) {
++			retval = -1;
++			goto done;
++		}
++	}
++	DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
++	retval = dwc_otg_hcd_qh_add(hcd, *qh);
++	if (retval == 0) {
++		DWC_CIRCLEQ_INSERT_TAIL(&((*qh)->qtd_list), qtd,
++					qtd_list_entry);
++	}
++	DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
++
++done:
++
++	return retval;
++}
++
++#endif /* DWC_DEVICE_ONLY */
+diff --git a/drivers/usb/gadget/udc/hiudc/dwc_otg_os_dep.h b/drivers/usb/gadget/udc/hiudc/dwc_otg_os_dep.h
+new file mode 100644
+index 0000000..7e491fe
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc/dwc_otg_os_dep.h
+@@ -0,0 +1,88 @@
++#ifndef _DWC_OS_DEP_H_
++#define _DWC_OS_DEP_H_
++
++/**
++ * @file
++ *
++ * This file contains OS dependent structures.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/init.h>
++#include <linux/device.h>
++#include <linux/errno.h>
++#include <linux/types.h>
++#include <linux/slab.h>
++#include <linux/list.h>
++#include <linux/interrupt.h>
++#include <linux/ctype.h>
++#include <linux/string.h>
++#include <linux/dma-mapping.h>
++#include <linux/jiffies.h>
++#include <linux/delay.h>
++#include <linux/timer.h>
++#include <linux/workqueue.h>
++#include <linux/stat.h>
++#include <linux/pci.h>
++
++#include <linux/version.h>
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
++# include <linux/irq.h>
++#endif
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
++# include <linux/usb/ch9.h>
++#else
++# include <linux/usb_ch9.h>
++#endif
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++# include <linux/usb/gadget.h>
++#else
++# include <linux/usb_gadget.h>
++#endif
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
++# include <asm/irq.h>
++#endif
++
++
++#include <asm/unaligned.h>
++#include <asm/sizes.h>
++#include <asm/param.h>
++#include <asm/io.h>
++
++
++/** The OS page size */
++#define DWC_OS_PAGE_SIZE	PAGE_SIZE
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
++typedef int gfp_t;
++#endif
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
++# define IRQF_SHARED SA_SHIRQ
++#endif
++
++typedef struct os_dependent {
++	/** Base address returned from ioremap() */
++	void *base;
++
++	/** Register offset for Diagnostic API */
++	uint32_t reg_offset;
++
++	uint32_t res_start;
++
++	struct platform_device *lmdev;
++
++} os_dependent_t;
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* _DWC_OS_DEP_H_ */
+diff --git a/drivers/usb/gadget/udc/hiudc/dwc_otg_pcd.c b/drivers/usb/gadget/udc/hiudc/dwc_otg_pcd.c
+new file mode 100644
+index 0000000..1382647
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc/dwc_otg_pcd.c
+@@ -0,0 +1,2932 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd.c $
++ * $Revision: #105 $
++ * $Date: 2013/05/16 $
++ * $Change: 2231774 $
++ *
++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
++ * ========================================================================== */
++#ifndef DWC_HOST_ONLY
++
++/** @file
++ * This file implements PCD Core. All code in this file is portable and doesn't
++ * use any OS specific functions.
++ * PCD Core provides Interface, defined in <code><dwc_otg_pcd_if.h></code>
++ * header file, which can be used to implement OS specific PCD interface.
++ *
++ * An important function of the PCD is managing interrupts generated
++ * by the DWC_otg controller. The implementation of the DWC_otg device
++ * mode interrupt service routines is in dwc_otg_pcd_intr.c.
++ *
++ * @todo Add Device Mode test modes (Test J mode, Test K mode, etc).
++ * @todo Does it work when the request size is greater than DEPTSIZ
++ * transfer size
++ *
++ */
++
++#include "dwc_otg_pcd.h"
++
++#ifdef DWC_UTE_CFI
++#include "dwc_otg_cfi.h"
++
++extern int init_cfi(cfiobject_t * cfiobj);
++#endif
++static int bulk_num = 0;
++/**
++ * Choose endpoint from ep arrays using usb_ep structure.
++ */
++static dwc_otg_pcd_ep_t *get_ep_from_handle(dwc_otg_pcd_t * pcd, void *handle)
++{
++	int i;
++	if (pcd->ep0.priv == handle) {
++		return &pcd->ep0;
++	}
++	for (i = 0; i < MAX_EPS_CHANNELS - 1; i++) {
++		if (pcd->in_ep[i].priv == handle)
++			return &pcd->in_ep[i];
++		if (pcd->out_ep[i].priv == handle)
++			return &pcd->out_ep[i];
++	}
++
++	return NULL;
++}
++
++/**
++ * This function completes a request.  It call's the request call back.
++ */
++void dwc_otg_request_done(dwc_otg_pcd_ep_t * ep, dwc_otg_pcd_request_t * req,
++			  int32_t status)
++{
++	unsigned stopped = ep->stopped;
++
++	DWC_DEBUGPL(DBG_PCDV, "%s(ep %p req %p)\n", __func__, ep, req);
++	DWC_CIRCLEQ_REMOVE_INIT(&ep->queue, req, queue_entry);
++
++	/* don't modify queue heads during completion callback */
++	ep->stopped = 1;
++	/* spin_unlock/spin_lock now done in fops->complete() */
++	ep->pcd->fops->complete(ep->pcd, ep->priv, req->priv, status,
++				req->actual);
++
++	if (ep->pcd->request_pending > 0) {
++		--ep->pcd->request_pending;
++	}
++
++	ep->stopped = stopped;
++	DWC_FREE(req);
++}
++
++/**
++ * This function terminates all the requsts in the EP request queue.
++ */
++void dwc_otg_request_nuke(dwc_otg_pcd_ep_t * ep)
++{
++	dwc_otg_pcd_request_t *req;
++
++	ep->stopped = 1;
++
++	/* called with irqs blocked?? */
++	while (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
++		req = DWC_CIRCLEQ_FIRST(&ep->queue);
++		dwc_otg_request_done(ep, req, -DWC_E_SHUTDOWN);
++	}
++}
++
++void dwc_otg_pcd_start(dwc_otg_pcd_t * pcd,
++		       const struct dwc_otg_pcd_function_ops *fops)
++{
++	pcd->fops = fops;
++}
++
++/**
++ * PCD Callback function for initializing the PCD when switching to
++ * device mode.
++ *
++ * @param p void pointer to the <code>dwc_otg_pcd_t</code>
++ */
++static int32_t dwc_otg_pcd_start_cb(void *p)
++{
++	dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) p;
++	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
++
++	/*
++	 * Initialized the Core for Device mode.
++	 */
++	if (dwc_otg_is_device_mode(core_if)) {
++		dwc_otg_core_dev_init(core_if);
++		/* Set core_if's lock pointer to the pcd->lock */
++		core_if->lock = pcd->lock;
++	}
++	return 1;
++}
++
++/** CFI-specific buffer allocation function for EP */
++#ifdef DWC_UTE_CFI
++uint8_t *cfiw_ep_alloc_buffer(dwc_otg_pcd_t * pcd, void *pep, dwc_dma_t * addr,
++			      size_t buflen, int flags)
++{
++	dwc_otg_pcd_ep_t *ep;
++	ep = get_ep_from_handle(pcd, pep);
++	if (!ep) {
++		DWC_WARN("bad ep\n");
++		return -DWC_E_INVALID;
++	}
++
++	return pcd->cfi->ops.ep_alloc_buf(pcd->cfi, pcd, ep, addr, buflen,
++					  flags);
++}
++#else
++uint8_t *cfiw_ep_alloc_buffer(dwc_otg_pcd_t * pcd, void *pep, dwc_dma_t * addr,
++			      size_t buflen, int flags);
++#endif
++
++/**
++ * PCD Callback function for notifying the PCD when resuming from
++ * suspend.
++ *
++ * @param p void pointer to the <code>dwc_otg_pcd_t</code>
++ */
++static int32_t dwc_otg_pcd_resume_cb(void *p)
++{
++	dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) p;
++
++	if (pcd->fops->resume) {
++		pcd->fops->resume(pcd);
++	}
++
++	/* Stop the SRP timeout timer. */
++	if ((GET_CORE_IF(pcd)->core_params->phy_type != DWC_PHY_TYPE_PARAM_FS)
++	    || (!GET_CORE_IF(pcd)->core_params->i2c_enable)) {
++		if (GET_CORE_IF(pcd)->srp_timer_started) {
++			GET_CORE_IF(pcd)->srp_timer_started = 0;
++			DWC_TIMER_CANCEL(GET_CORE_IF(pcd)->srp_timer);
++		}
++	}
++	return 1;
++}
++
++/**
++ * PCD Callback function for notifying the PCD device is suspended.
++ *
++ * @param p void pointer to the <code>dwc_otg_pcd_t</code>
++ */
++static int32_t dwc_otg_pcd_suspend_cb(void *p)
++{
++	dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) p;
++
++	if (pcd->fops->suspend) {
++		DWC_SPINUNLOCK(pcd->lock);
++		pcd->fops->suspend(pcd);
++		DWC_SPINLOCK(pcd->lock);
++	}
++
++	return 1;
++}
++
++/**
++ * PCD Callback function for stopping the PCD when switching to Host
++ * mode.
++ *
++ * @param p void pointer to the <code>dwc_otg_pcd_t</code>
++ */
++static int32_t dwc_otg_pcd_stop_cb(void *p)
++{
++	dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) p;
++	extern void dwc_otg_pcd_stop(dwc_otg_pcd_t * _pcd);
++
++	dwc_otg_pcd_stop(pcd);
++	return 1;
++}
++
++/**
++ * PCD Callback structure for handling mode switching.
++ */
++static dwc_otg_cil_callbacks_t pcd_callbacks = {
++	.start = dwc_otg_pcd_start_cb,
++	.stop = dwc_otg_pcd_stop_cb,
++	.suspend = dwc_otg_pcd_suspend_cb,
++	.resume_wakeup = dwc_otg_pcd_resume_cb,
++	.p = 0,			/* Set at registration */
++};
++
++/**
++ * This function allocates a DMA Descriptor chain for the Endpoint
++ * buffer to be used for a transfer to/from the specified endpoint.
++ */
++dwc_otg_dev_dma_desc_t *dwc_otg_ep_alloc_desc_chain(dwc_dma_t * dma_desc_addr,
++						    uint32_t count)
++{
++	return DWC_DMA_ALLOC_ATOMIC(count * sizeof(dwc_otg_dev_dma_desc_t),
++				    dma_desc_addr);
++}
++
++/**
++ * This function frees a DMA Descriptor chain that was allocated by ep_alloc_desc.
++ */
++void dwc_otg_ep_free_desc_chain(dwc_otg_dev_dma_desc_t * desc_addr,
++				uint32_t dma_desc_addr, uint32_t count)
++{
++	DWC_DMA_FREE(count * sizeof(dwc_otg_dev_dma_desc_t), desc_addr,
++		     dma_desc_addr);
++}
++
++#ifdef DWC_EN_ISOC
++
++/**
++ * This function initializes a descriptor chain for Isochronous transfer
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ * @param dwc_ep The EP to start the transfer on.
++ *
++ */
++void dwc_otg_iso_ep_start_ddma_transfer(dwc_otg_core_if_t * core_if,
++					dwc_ep_t * dwc_ep)
++{
++
++	dsts_data_t dsts = {.d32 = 0 };
++	depctl_data_t depctl = {.d32 = 0 };
++	volatile uint32_t *addr;
++	int i, j;
++	uint32_t len;
++
++	if (dwc_ep->is_in)
++		dwc_ep->desc_cnt = dwc_ep->buf_proc_intrvl / dwc_ep->bInterval;
++	else
++		dwc_ep->desc_cnt =
++		    dwc_ep->buf_proc_intrvl * dwc_ep->pkt_per_frm /
++		    dwc_ep->bInterval;
++
++	/** Allocate descriptors for double buffering */
++	dwc_ep->iso_desc_addr =
++	    dwc_otg_ep_alloc_desc_chain(&dwc_ep->iso_dma_desc_addr,
++					dwc_ep->desc_cnt * 2);
++	if (dwc_ep->desc_addr) {
++		DWC_WARN("%s, can't allocate DMA descriptor chain\n", __func__);
++		return;
++	}
++
++	dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
++
++	/** ISO OUT EP */
++	if (dwc_ep->is_in == 0) {
++		dev_dma_desc_sts_t sts = {.d32 = 0 };
++		dwc_otg_dev_dma_desc_t *dma_desc = dwc_ep->iso_desc_addr;
++		dma_addr_t dma_ad;
++		uint32_t data_per_desc;
++		dwc_otg_dev_out_ep_regs_t *out_regs =
++		    core_if->dev_if->out_ep_regs[dwc_ep->num];
++		int offset;
++
++		addr = &core_if->dev_if->out_ep_regs[dwc_ep->num]->doepctl;
++		dma_ad = (dma_addr_t) DWC_READ_REG32(&(out_regs->doepdma));
++
++		/** Buffer 0 descriptors setup */
++		dma_ad = dwc_ep->dma_addr0;
++
++		sts.b_iso_out.bs = BS_HOST_READY;
++		sts.b_iso_out.rxsts = 0;
++		sts.b_iso_out.l = 0;
++		sts.b_iso_out.sp = 0;
++		sts.b_iso_out.ioc = 0;
++		sts.b_iso_out.pid = 0;
++		sts.b_iso_out.framenum = 0;
++
++		offset = 0;
++		for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm;
++		     i += dwc_ep->pkt_per_frm) {
++
++			for (j = 0; j < dwc_ep->pkt_per_frm; ++j) {
++				uint32_t len = (j + 1) * dwc_ep->maxpacket;
++				if (len > dwc_ep->data_per_frame)
++					data_per_desc =
++					    dwc_ep->data_per_frame -
++					    j * dwc_ep->maxpacket;
++				else
++					data_per_desc = dwc_ep->maxpacket;
++				len = data_per_desc % 4;
++				if (len)
++					data_per_desc += 4 - len;
++
++				sts.b_iso_out.rxbytes = data_per_desc;
++				dma_desc->buf = dma_ad;
++				dma_desc->status.d32 = sts.d32;
++
++				offset += data_per_desc;
++				dma_desc++;
++				dma_ad += data_per_desc;
++			}
++		}
++
++		for (j = 0; j < dwc_ep->pkt_per_frm - 1; ++j) {
++			uint32_t len = (j + 1) * dwc_ep->maxpacket;
++			if (len > dwc_ep->data_per_frame)
++				data_per_desc =
++				    dwc_ep->data_per_frame -
++				    j * dwc_ep->maxpacket;
++			else
++				data_per_desc = dwc_ep->maxpacket;
++			len = data_per_desc % 4;
++			if (len)
++				data_per_desc += 4 - len;
++			sts.b_iso_out.rxbytes = data_per_desc;
++			dma_desc->buf = dma_ad;
++			dma_desc->status.d32 = sts.d32;
++
++			offset += data_per_desc;
++			dma_desc++;
++			dma_ad += data_per_desc;
++		}
++
++		sts.b_iso_out.ioc = 1;
++		len = (j + 1) * dwc_ep->maxpacket;
++		if (len > dwc_ep->data_per_frame)
++			data_per_desc =
++			    dwc_ep->data_per_frame - j * dwc_ep->maxpacket;
++		else
++			data_per_desc = dwc_ep->maxpacket;
++		len = data_per_desc % 4;
++		if (len)
++			data_per_desc += 4 - len;
++		sts.b_iso_out.rxbytes = data_per_desc;
++
++		dma_desc->buf = dma_ad;
++		dma_desc->status.d32 = sts.d32;
++		dma_desc++;
++
++		/** Buffer 1 descriptors setup */
++		sts.b_iso_out.ioc = 0;
++		dma_ad = dwc_ep->dma_addr1;
++
++		offset = 0;
++		for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm;
++		     i += dwc_ep->pkt_per_frm) {
++			for (j = 0; j < dwc_ep->pkt_per_frm; ++j) {
++				uint32_t len = (j + 1) * dwc_ep->maxpacket;
++				if (len > dwc_ep->data_per_frame)
++					data_per_desc =
++					    dwc_ep->data_per_frame -
++					    j * dwc_ep->maxpacket;
++				else
++					data_per_desc = dwc_ep->maxpacket;
++				len = data_per_desc % 4;
++				if (len)
++					data_per_desc += 4 - len;
++
++				data_per_desc =
++				    sts.b_iso_out.rxbytes = data_per_desc;
++				dma_desc->buf = dma_ad;
++				dma_desc->status.d32 = sts.d32;
++
++				offset += data_per_desc;
++				dma_desc++;
++				dma_ad += data_per_desc;
++			}
++		}
++		for (j = 0; j < dwc_ep->pkt_per_frm - 1; ++j) {
++			data_per_desc =
++			    ((j + 1) * dwc_ep->maxpacket >
++			     dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
++			    j * dwc_ep->maxpacket : dwc_ep->maxpacket;
++			data_per_desc +=
++			    (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
++			sts.b_iso_out.rxbytes = data_per_desc;
++			dma_desc->buf = dma_ad;
++			dma_desc->status.d32 = sts.d32;
++
++			offset += data_per_desc;
++			dma_desc++;
++			dma_ad += data_per_desc;
++		}
++
++		sts.b_iso_out.ioc = 1;
++		sts.b_iso_out.l = 1;
++		data_per_desc =
++		    ((j + 1) * dwc_ep->maxpacket >
++		     dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
++		    j * dwc_ep->maxpacket : dwc_ep->maxpacket;
++		data_per_desc +=
++		    (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
++		sts.b_iso_out.rxbytes = data_per_desc;
++
++		dma_desc->buf = dma_ad;
++		dma_desc->status.d32 = sts.d32;
++
++		dwc_ep->next_frame = 0;
++
++		/** Write dma_ad into DOEPDMA register */
++		DWC_WRITE_REG32(&(out_regs->doepdma),
++				(uint32_t) dwc_ep->iso_dma_desc_addr);
++
++	}
++	/** ISO IN EP */
++	else {
++		dev_dma_desc_sts_t sts = {.d32 = 0 };
++		dwc_otg_dev_dma_desc_t *dma_desc = dwc_ep->iso_desc_addr;
++		dma_addr_t dma_ad;
++		dwc_otg_dev_in_ep_regs_t *in_regs =
++		    core_if->dev_if->in_ep_regs[dwc_ep->num];
++		unsigned int frmnumber;
++		fifosize_data_t txfifosize, rxfifosize;
++
++		txfifosize.d32 =
++		    DWC_READ_REG32(&core_if->dev_if->in_ep_regs[dwc_ep->num]->
++				   dtxfsts);
++		rxfifosize.d32 =
++		    DWC_READ_REG32(&core_if->core_global_regs->grxfsiz);
++
++		addr = &core_if->dev_if->in_ep_regs[dwc_ep->num]->diepctl;
++
++		dma_ad = dwc_ep->dma_addr0;
++
++		dsts.d32 =
++		    DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
++
++		sts.b_iso_in.bs = BS_HOST_READY;
++		sts.b_iso_in.txsts = 0;
++		sts.b_iso_in.sp =
++		    (dwc_ep->data_per_frame % dwc_ep->maxpacket) ? 1 : 0;
++		sts.b_iso_in.ioc = 0;
++		sts.b_iso_in.pid = dwc_ep->pkt_per_frm;
++
++		frmnumber = dwc_ep->next_frame;
++
++		sts.b_iso_in.framenum = frmnumber;
++		sts.b_iso_in.txbytes = dwc_ep->data_per_frame;
++		sts.b_iso_in.l = 0;
++
++		/** Buffer 0 descriptors setup */
++		for (i = 0; i < dwc_ep->desc_cnt - 1; i++) {
++			dma_desc->buf = dma_ad;
++			dma_desc->status.d32 = sts.d32;
++			dma_desc++;
++
++			dma_ad += dwc_ep->data_per_frame;
++			sts.b_iso_in.framenum += dwc_ep->bInterval;
++		}
++
++		sts.b_iso_in.ioc = 1;
++		dma_desc->buf = dma_ad;
++		dma_desc->status.d32 = sts.d32;
++		++dma_desc;
++
++		/** Buffer 1 descriptors setup */
++		sts.b_iso_in.ioc = 0;
++		dma_ad = dwc_ep->dma_addr1;
++
++		for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm;
++		     i += dwc_ep->pkt_per_frm) {
++			dma_desc->buf = dma_ad;
++			dma_desc->status.d32 = sts.d32;
++			dma_desc++;
++
++			dma_ad += dwc_ep->data_per_frame;
++			sts.b_iso_in.framenum += dwc_ep->bInterval;
++
++			sts.b_iso_in.ioc = 0;
++		}
++		sts.b_iso_in.ioc = 1;
++		sts.b_iso_in.l = 1;
++
++		dma_desc->buf = dma_ad;
++		dma_desc->status.d32 = sts.d32;
++
++		dwc_ep->next_frame = sts.b_iso_in.framenum + dwc_ep->bInterval;
++
++		/** Write dma_ad into diepdma register */
++		DWC_WRITE_REG32(&(in_regs->diepdma),
++				(uint32_t) dwc_ep->iso_dma_desc_addr);
++	}
++	/** Enable endpoint, clear nak  */
++	depctl.d32 = 0;
++	depctl.b.epena = 1;
++	depctl.b.usbactep = 1;
++	depctl.b.cnak = 1;
++
++	DWC_MODIFY_REG32(addr, depctl.d32, depctl.d32);
++	depctl.d32 = DWC_READ_REG32(addr);
++}
++
++/**
++ * This function initializes a descriptor chain for Isochronous transfer
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ * @param ep The EP to start the transfer on.
++ *
++ */
++void dwc_otg_iso_ep_start_buf_transfer(dwc_otg_core_if_t * core_if,
++				       dwc_ep_t * ep)
++{
++	depctl_data_t depctl = {.d32 = 0 };
++	volatile uint32_t *addr;
++
++	if (ep->is_in) {
++		addr = &core_if->dev_if->in_ep_regs[ep->num]->diepctl;
++	} else {
++		addr = &core_if->dev_if->out_ep_regs[ep->num]->doepctl;
++	}
++
++	if (core_if->dma_enable == 0 || core_if->dma_desc_enable != 0) {
++		return;
++	} else {
++		deptsiz_data_t deptsiz = {.d32 = 0 };
++
++		ep->xfer_len =
++		    ep->data_per_frame * ep->buf_proc_intrvl / ep->bInterval;
++		ep->pkt_cnt =
++		    (ep->xfer_len - 1 + ep->maxpacket) / ep->maxpacket;
++		ep->xfer_count = 0;
++		ep->xfer_buff =
++		    (ep->proc_buf_num) ? ep->xfer_buff1 : ep->xfer_buff0;
++		ep->dma_addr =
++		    (ep->proc_buf_num) ? ep->dma_addr1 : ep->dma_addr0;
++
++		if (ep->is_in) {
++			/* Program the transfer size and packet count
++			 *      as follows: xfersize = N * maxpacket +
++			 *      short_packet pktcnt = N + (short_packet
++			 *      exist ? 1 : 0)
++			 */
++			deptsiz.b.mc = ep->pkt_per_frm;
++			deptsiz.b.xfersize = ep->xfer_len;
++			deptsiz.b.pktcnt =
++			    (ep->xfer_len - 1 + ep->maxpacket) / ep->maxpacket;
++			DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[ep->num]->
++					dieptsiz, deptsiz.d32);
++
++			/* Write the DMA register */
++			DWC_WRITE_REG32(&
++					(core_if->dev_if->in_ep_regs[ep->num]->
++					 diepdma), (uint32_t) ep->dma_addr);
++
++		} else {
++			deptsiz.b.pktcnt =
++			    (ep->xfer_len + (ep->maxpacket - 1)) /
++			    ep->maxpacket;
++			deptsiz.b.xfersize = deptsiz.b.pktcnt * ep->maxpacket;
++
++			DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[ep->num]->
++					doeptsiz, deptsiz.d32);
++
++			/* Write the DMA register */
++			DWC_WRITE_REG32(&
++					(core_if->dev_if->out_ep_regs[ep->num]->
++					 doepdma), (uint32_t) ep->dma_addr);
++
++		}
++		/** Enable endpoint, clear nak  */
++		depctl.d32 = 0;
++		depctl.b.epena = 1;
++		depctl.b.cnak = 1;
++
++		DWC_MODIFY_REG32(addr, depctl.d32, depctl.d32);
++	}
++}
++
++/**
++ * This function does the setup for a data transfer for an EP and
++ * starts the transfer. For an IN transfer, the packets will be
++ * loaded into the appropriate Tx FIFO in the ISR. For OUT transfers,
++ * the packets are unloaded from the Rx FIFO in the ISR.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ * @param ep The EP to start the transfer on.
++ */
++
++static void dwc_otg_iso_ep_start_transfer(dwc_otg_core_if_t * core_if,
++					  dwc_ep_t * ep)
++{
++	if (core_if->dma_enable) {
++		if (core_if->dma_desc_enable) {
++			if (ep->is_in) {
++				ep->desc_cnt = ep->pkt_cnt / ep->pkt_per_frm;
++			} else {
++				ep->desc_cnt = ep->pkt_cnt;
++			}
++			dwc_otg_iso_ep_start_ddma_transfer(core_if, ep);
++		} else {
++			if (core_if->pti_enh_enable) {
++				dwc_otg_iso_ep_start_buf_transfer(core_if, ep);
++			} else {
++				ep->cur_pkt_addr =
++				    (ep->proc_buf_num) ? ep->xfer_buff1 : ep->
++				    xfer_buff0;
++				ep->cur_pkt_dma_addr =
++				    (ep->proc_buf_num) ? ep->dma_addr1 : ep->
++				    dma_addr0;
++				dwc_otg_iso_ep_start_frm_transfer(core_if, ep);
++			}
++		}
++	} else {
++		ep->cur_pkt_addr =
++		    (ep->proc_buf_num) ? ep->xfer_buff1 : ep->xfer_buff0;
++		ep->cur_pkt_dma_addr =
++		    (ep->proc_buf_num) ? ep->dma_addr1 : ep->dma_addr0;
++		dwc_otg_iso_ep_start_frm_transfer(core_if, ep);
++	}
++}
++
++/**
++ * This function stops transfer for an EP and
++ * resets the ep's variables.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ * @param ep The EP to start the transfer on.
++ */
++
++void dwc_otg_iso_ep_stop_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
++{
++	depctl_data_t depctl = {.d32 = 0 };
++	volatile uint32_t *addr;
++
++	if (ep->is_in == 1) {
++		addr = &core_if->dev_if->in_ep_regs[ep->num]->diepctl;
++	} else {
++		addr = &core_if->dev_if->out_ep_regs[ep->num]->doepctl;
++	}
++
++	/* disable the ep */
++	depctl.d32 = DWC_READ_REG32(addr);
++
++	depctl.b.epdis = 1;
++	depctl.b.snak = 1;
++
++	DWC_WRITE_REG32(addr, depctl.d32);
++
++	if (core_if->dma_desc_enable &&
++	    ep->iso_desc_addr && ep->iso_dma_desc_addr) {
++		dwc_otg_ep_free_desc_chain(ep->iso_desc_addr,
++					   ep->iso_dma_desc_addr,
++					   ep->desc_cnt * 2);
++	}
++
++	/* reset varibales */
++	ep->dma_addr0 = 0;
++	ep->dma_addr1 = 0;
++	ep->xfer_buff0 = 0;
++	ep->xfer_buff1 = 0;
++	ep->data_per_frame = 0;
++	ep->data_pattern_frame = 0;
++	ep->sync_frame = 0;
++	ep->buf_proc_intrvl = 0;
++	ep->bInterval = 0;
++	ep->proc_buf_num = 0;
++	ep->pkt_per_frm = 0;
++	ep->pkt_per_frm = 0;
++	ep->desc_cnt = 0;
++	ep->iso_desc_addr = 0;
++	ep->iso_dma_desc_addr = 0;
++}
++
++int dwc_otg_pcd_iso_ep_start(dwc_otg_pcd_t * pcd, void *ep_handle,
++			     uint8_t * buf0, uint8_t * buf1, dwc_dma_t dma0,
++			     dwc_dma_t dma1, int sync_frame, int dp_frame,
++			     int data_per_frame, int start_frame,
++			     int buf_proc_intrvl, void *req_handle,
++			     int atomic_alloc)
++{
++	dwc_otg_pcd_ep_t *ep;
++	dwc_irqflags_t flags = 0;
++	dwc_ep_t *dwc_ep;
++	int32_t frm_data;
++	dsts_data_t dsts;
++	dwc_otg_core_if_t *core_if;
++
++	ep = get_ep_from_handle(pcd, ep_handle);
++
++	if (!ep || !ep->desc || ep->dwc_ep.num == 0) {
++		DWC_WARN("bad ep\n");
++		return -DWC_E_INVALID;
++	}
++
++	DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
++	core_if = GET_CORE_IF(pcd);
++	dwc_ep = &ep->dwc_ep;
++
++	if (ep->iso_req_handle) {
++		DWC_WARN("ISO request in progress\n");
++	}
++
++	dwc_ep->dma_addr0 = dma0;
++	dwc_ep->dma_addr1 = dma1;
++
++	dwc_ep->xfer_buff0 = buf0;
++	dwc_ep->xfer_buff1 = buf1;
++
++	dwc_ep->data_per_frame = data_per_frame;
++
++	/** @todo - pattern data support is to be implemented in the future */
++	dwc_ep->data_pattern_frame = dp_frame;
++	dwc_ep->sync_frame = sync_frame;
++
++	dwc_ep->buf_proc_intrvl = buf_proc_intrvl;
++
++	dwc_ep->bInterval = 1 << (ep->desc->bInterval - 1);
++
++	dwc_ep->proc_buf_num = 0;
++
++	dwc_ep->pkt_per_frm = 0;
++	frm_data = ep->dwc_ep.data_per_frame;
++	while (frm_data > 0) {
++		dwc_ep->pkt_per_frm++;
++		frm_data -= ep->dwc_ep.maxpacket;
++	}
++
++	dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
++
++	if (start_frame == -1) {
++		dwc_ep->next_frame = dsts.b.soffn + 1;
++		if (dwc_ep->bInterval != 1) {
++			dwc_ep->next_frame =
++			    dwc_ep->next_frame + (dwc_ep->bInterval - 1 -
++						  dwc_ep->next_frame %
++						  dwc_ep->bInterval);
++		}
++	} else {
++		dwc_ep->next_frame = start_frame;
++	}
++
++	if (!core_if->pti_enh_enable) {
++		dwc_ep->pkt_cnt =
++		    dwc_ep->buf_proc_intrvl * dwc_ep->pkt_per_frm /
++		    dwc_ep->bInterval;
++	} else {
++		dwc_ep->pkt_cnt =
++		    (dwc_ep->data_per_frame *
++		     (dwc_ep->buf_proc_intrvl / dwc_ep->bInterval)
++		     - 1 + dwc_ep->maxpacket) / dwc_ep->maxpacket;
++	}
++
++	if (core_if->dma_desc_enable) {
++		dwc_ep->desc_cnt =
++		    dwc_ep->buf_proc_intrvl * dwc_ep->pkt_per_frm /
++		    dwc_ep->bInterval;
++	}
++
++	if (atomic_alloc) {
++		dwc_ep->pkt_info =
++		    DWC_ALLOC_ATOMIC(sizeof(iso_pkt_info_t) * dwc_ep->pkt_cnt);
++	} else {
++		dwc_ep->pkt_info =
++		    DWC_ALLOC(sizeof(iso_pkt_info_t) * dwc_ep->pkt_cnt);
++	}
++	if (!dwc_ep->pkt_info) {
++		DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
++		return -DWC_E_NO_MEMORY;
++	}
++	if (core_if->pti_enh_enable) {
++		dwc_memset(dwc_ep->pkt_info, 0,
++			   sizeof(iso_pkt_info_t) * dwc_ep->pkt_cnt);
++	}
++
++	dwc_ep->cur_pkt = 0;
++	ep->iso_req_handle = req_handle;
++
++	DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
++	dwc_otg_iso_ep_start_transfer(core_if, dwc_ep);
++	return 0;
++}
++
++int dwc_otg_pcd_iso_ep_stop(dwc_otg_pcd_t * pcd, void *ep_handle,
++			    void *req_handle)
++{
++	dwc_irqflags_t flags = 0;
++	dwc_otg_pcd_ep_t *ep;
++	dwc_ep_t *dwc_ep;
++
++	ep = get_ep_from_handle(pcd, ep_handle);
++	if (!ep || !ep->desc || ep->dwc_ep.num == 0) {
++		DWC_WARN("bad ep\n");
++		return -DWC_E_INVALID;
++	}
++	dwc_ep = &ep->dwc_ep;
++
++	dwc_otg_iso_ep_stop_transfer(GET_CORE_IF(pcd), dwc_ep);
++
++	DWC_FREE(dwc_ep->pkt_info);
++	DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
++	if (ep->iso_req_handle != req_handle) {
++		DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
++		return -DWC_E_INVALID;
++	}
++
++	DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
++
++	ep->iso_req_handle = 0;
++	return 0;
++}
++
++/**
++ * This function is used for perodical data exchnage between PCD and gadget drivers.
++ * for Isochronous EPs
++ *
++ *	- Every time a sync period completes this function is called to
++ *	  perform data exchange between PCD and gadget
++ */
++void dwc_otg_iso_buffer_done(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * ep,
++			     void *req_handle)
++{
++	int i;
++	dwc_ep_t *dwc_ep;
++
++	dwc_ep = &ep->dwc_ep;
++
++	DWC_SPINUNLOCK(ep->pcd->lock);
++	pcd->fops->isoc_complete(pcd, ep->priv, ep->iso_req_handle,
++				 dwc_ep->proc_buf_num ^ 0x1);
++	DWC_SPINLOCK(ep->pcd->lock);
++
++	for (i = 0; i < dwc_ep->pkt_cnt; ++i) {
++		dwc_ep->pkt_info[i].status = 0;
++		dwc_ep->pkt_info[i].offset = 0;
++		dwc_ep->pkt_info[i].length = 0;
++	}
++}
++
++int dwc_otg_pcd_get_iso_packet_count(dwc_otg_pcd_t * pcd, void *ep_handle,
++				     void *iso_req_handle)
++{
++	dwc_otg_pcd_ep_t *ep;
++	dwc_ep_t *dwc_ep;
++
++	ep = get_ep_from_handle(pcd, ep_handle);
++	if (!ep->desc || ep->dwc_ep.num == 0) {
++		DWC_WARN("bad ep\n");
++		return -DWC_E_INVALID;
++	}
++	dwc_ep = &ep->dwc_ep;
++
++	return dwc_ep->pkt_cnt;
++}
++
++void dwc_otg_pcd_get_iso_packet_params(dwc_otg_pcd_t * pcd, void *ep_handle,
++				       void *iso_req_handle, int packet,
++				       int *status, int *actual, int *offset)
++{
++	dwc_otg_pcd_ep_t *ep;
++	dwc_ep_t *dwc_ep;
++
++	ep = get_ep_from_handle(pcd, ep_handle);
++	if (!ep)
++		DWC_WARN("bad ep\n");
++
++	dwc_ep = &ep->dwc_ep;
++
++	*status = dwc_ep->pkt_info[packet].status;
++	*actual = dwc_ep->pkt_info[packet].length;
++	*offset = dwc_ep->pkt_info[packet].offset;
++}
++
++#endif /* DWC_EN_ISOC */
++
++static void dwc_otg_pcd_init_ep(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * pcd_ep,
++				uint32_t is_in, uint32_t ep_num)
++{
++	/* Init EP structure */
++	pcd_ep->desc = 0;
++	pcd_ep->pcd = pcd;
++	pcd_ep->stopped = 1;
++	pcd_ep->queue_sof = 0;
++
++	/* Init DWC ep structure */
++	pcd_ep->dwc_ep.is_in = is_in;
++	pcd_ep->dwc_ep.num = ep_num;
++	pcd_ep->dwc_ep.active = 0;
++	pcd_ep->dwc_ep.tx_fifo_num = 0;
++	/* Control until ep is actvated */
++	pcd_ep->dwc_ep.type = DWC_OTG_EP_TYPE_CONTROL;
++	pcd_ep->dwc_ep.maxpacket = MAX_PACKET_SIZE;
++	pcd_ep->dwc_ep.dma_addr = 0;
++	pcd_ep->dwc_ep.start_xfer_buff = 0;
++	pcd_ep->dwc_ep.xfer_buff = 0;
++	pcd_ep->dwc_ep.xfer_len = 0;
++	pcd_ep->dwc_ep.xfer_count = 0;
++	pcd_ep->dwc_ep.sent_zlp = 0;
++	pcd_ep->dwc_ep.total_len = 0;
++	pcd_ep->dwc_ep.desc_addr = 0;
++	pcd_ep->dwc_ep.dma_desc_addr = 0;
++	DWC_CIRCLEQ_INIT(&pcd_ep->queue);
++}
++
++/**
++ * Initialize ep's
++ */
++static void dwc_otg_pcd_reinit(dwc_otg_pcd_t * pcd)
++{
++	int i;
++	uint32_t hwcfg1;
++	dwc_otg_pcd_ep_t *ep;
++	int in_ep_cntr, out_ep_cntr;
++	uint32_t num_in_eps = (GET_CORE_IF(pcd))->dev_if->num_in_eps;
++	uint32_t num_out_eps = (GET_CORE_IF(pcd))->dev_if->num_out_eps;
++
++	/**
++	 * Initialize the EP0 structure.
++	 */
++	ep = &pcd->ep0;
++	dwc_otg_pcd_init_ep(pcd, ep, 0, 0);
++
++	in_ep_cntr = 0;
++	hwcfg1 = (GET_CORE_IF(pcd))->hwcfg1.d32 >> 3;
++	for (i = 1; in_ep_cntr < num_in_eps; i++) {
++		if ((hwcfg1 & 0x1) == 0) {
++			dwc_otg_pcd_ep_t *ep = &pcd->in_ep[in_ep_cntr];
++			in_ep_cntr++;
++			/**
++			 * @todo NGS: Add direction to EP, based on contents
++			 * of HWCFG1.  Need a copy of HWCFG1 in pcd structure?
++			 * sprintf(";r
++			 */
++			dwc_otg_pcd_init_ep(pcd, ep, 1 /* IN */ , i);
++
++			DWC_CIRCLEQ_INIT(&ep->queue);
++		}
++		hwcfg1 >>= 2;
++	}
++
++	out_ep_cntr = 0;
++	hwcfg1 = (GET_CORE_IF(pcd))->hwcfg1.d32 >> 2;
++	for (i = 1; out_ep_cntr < num_out_eps; i++) {
++		if ((hwcfg1 & 0x1) == 0) {
++			dwc_otg_pcd_ep_t *ep = &pcd->out_ep[out_ep_cntr];
++			out_ep_cntr++;
++			/**
++			 * @todo NGS: Add direction to EP, based on contents
++			 * of HWCFG1.  Need a copy of HWCFG1 in pcd structure?
++			 * sprintf(";r
++			 */
++			dwc_otg_pcd_init_ep(pcd, ep, 0 /* OUT */ , i);
++			DWC_CIRCLEQ_INIT(&ep->queue);
++		}
++		hwcfg1 >>= 2;
++	}
++
++	pcd->ep0state = EP0_DISCONNECT;
++	pcd->ep0.dwc_ep.maxpacket = MAX_EP0_SIZE;
++	pcd->ep0.dwc_ep.type = DWC_OTG_EP_TYPE_CONTROL;
++}
++
++/**
++ * This function is called when the SRP timer expires. The SRP should
++ * complete within 6 seconds.
++ */
++static void srp_timeout(void *ptr)
++{
++	gotgctl_data_t gotgctl;
++	dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) ptr;
++	volatile uint32_t *addr = &core_if->core_global_regs->gotgctl;
++
++	gotgctl.d32 = DWC_READ_REG32(addr);
++
++	core_if->srp_timer_started = 0;
++
++	if (core_if->adp_enable) {
++		if (gotgctl.b.bsesvld == 0) {
++			gpwrdn_data_t gpwrdn = {.d32 = 0 };
++			DWC_PRINTF("SRP Timeout BSESSVLD = 0\n");
++			/* Power off the core */
++			if (core_if->power_down == 2) {
++				gpwrdn.b.pwrdnswtch = 1;
++				DWC_MODIFY_REG32(&core_if->
++						 core_global_regs->gpwrdn,
++						 gpwrdn.d32, 0);
++			}
++
++			gpwrdn.d32 = 0;
++			gpwrdn.b.pmuintsel = 1;
++			gpwrdn.b.pmuactv = 1;
++			DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0,
++					 gpwrdn.d32);
++			dwc_otg_adp_probe_start(core_if);
++		} else {
++			DWC_PRINTF("SRP Timeout BSESSVLD = 1\n");
++			core_if->op_state = B_PERIPHERAL;
++			dwc_otg_core_init(core_if);
++			dwc_otg_enable_global_interrupts(core_if);
++			cil_pcd_start(core_if);
++		}
++	}
++
++	if ((core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS) &&
++	    (core_if->core_params->i2c_enable)) {
++		DWC_PRINTF("SRP Timeout\n");
++
++		if ((core_if->srp_success) && (gotgctl.b.bsesvld)) {
++			if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup) {
++				core_if->pcd_cb->resume_wakeup(core_if->pcd_cb->p);
++			}
++
++			/* Clear Session Request */
++			gotgctl.d32 = 0;
++			gotgctl.b.sesreq = 1;
++			DWC_MODIFY_REG32(&core_if->core_global_regs->gotgctl,
++					 gotgctl.d32, 0);
++
++			core_if->srp_success = 0;
++		} else {
++			__DWC_ERROR("Device not connected/responding\n");
++			gotgctl.b.sesreq = 0;
++			DWC_WRITE_REG32(addr, gotgctl.d32);
++		}
++	} else if (gotgctl.b.sesreq) {
++		DWC_PRINTF("SRP Timeout\n");
++
++		__DWC_ERROR("Device not connected/responding\n");
++		gotgctl.b.sesreq = 0;
++		DWC_WRITE_REG32(addr, gotgctl.d32);
++	} else {
++		DWC_PRINTF(" SRP GOTGCTL=%0x\n", gotgctl.d32);
++	}
++}
++
++/**
++ * Tasklet
++ *
++ */
++extern void start_next_request(dwc_otg_pcd_ep_t * ep);
++
++static void start_xfer_tasklet_func(void *data)
++{
++	dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) data;
++	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
++
++	int i;
++	depctl_data_t diepctl;
++
++	DWC_DEBUGPL(DBG_PCDV, "Start xfer tasklet\n");
++
++	diepctl.d32 = DWC_READ_REG32(&core_if->dev_if->in_ep_regs[0]->diepctl);
++
++	if (pcd->ep0.queue_sof) {
++		pcd->ep0.queue_sof = 0;
++		start_next_request(&pcd->ep0);
++		// break;
++	}
++
++	for (i = 0; i < core_if->dev_if->num_in_eps; i++) {
++		depctl_data_t diepctl;
++		diepctl.d32 =
++		    DWC_READ_REG32(&core_if->dev_if->in_ep_regs[i]->diepctl);
++
++		if (pcd->in_ep[i].queue_sof) {
++			pcd->in_ep[i].queue_sof = 0;
++			start_next_request(&pcd->in_ep[i]);
++			// break;
++		}
++	}
++
++	return;
++}
++
++/**
++ * This function initialized the PCD portion of the driver.
++ *
++ */
++dwc_otg_pcd_t *dwc_otg_pcd_init(dwc_otg_core_if_t * core_if)
++{
++	dwc_otg_pcd_t *pcd = NULL;
++	dwc_otg_dev_if_t *dev_if;
++	int i;
++
++	/*
++	 * Allocate PCD structure
++	 */
++	pcd = DWC_ALLOC(sizeof(dwc_otg_pcd_t));
++
++	if (pcd == NULL) {
++		return NULL;
++	}
++
++	pcd->lock = DWC_SPINLOCK_ALLOC();
++	if (!pcd->lock) {
++		DWC_ERROR("Could not allocate lock for pcd");
++		DWC_FREE(pcd);
++		return NULL;
++	}
++	/* Set core_if's lock pointer to hcd->lock */
++	core_if->lock = pcd->lock;
++	pcd->core_if = core_if;
++
++	dev_if = core_if->dev_if;
++	dev_if->isoc_ep = NULL;
++
++	if (core_if->hwcfg4.b.ded_fifo_en) {
++		DWC_PRINTF("Dedicated Tx FIFOs mode\n");
++	} else {
++		DWC_PRINTF("Shared Tx FIFO mode\n");
++	}
++
++	/*
++	 * Initialized the Core for Device mode here if there is nod ADP support.
++	 * Otherwise it will be done later in dwc_otg_adp_start routine.
++	 */
++	if (dwc_otg_is_device_mode(core_if) /*&& !core_if->adp_enable */ ) {
++		dwc_otg_core_dev_init(core_if);
++	}
++
++	/*
++	 * Register the PCD Callbacks.
++	 */
++	dwc_otg_cil_register_pcd_callbacks(core_if, &pcd_callbacks, pcd);
++
++	/*
++	 * Initialize the DMA buffer for SETUP packets
++	 */
++	if (GET_CORE_IF(pcd)->dma_enable) {
++		pcd->setup_pkt =
++		    DWC_DMA_ALLOC(sizeof(*pcd->setup_pkt) * 5,
++				  &pcd->setup_pkt_dma_handle);
++		if (pcd->setup_pkt == NULL) {
++			DWC_FREE(pcd);
++			return NULL;
++		}
++
++		pcd->status_buf =
++		    DWC_DMA_ALLOC(sizeof(uint16_t),
++				  &pcd->status_buf_dma_handle);
++		if (pcd->status_buf == NULL) {
++			DWC_DMA_FREE(sizeof(*pcd->setup_pkt) * 5,
++				     pcd->setup_pkt, pcd->setup_pkt_dma_handle);
++			DWC_FREE(pcd);
++			return NULL;
++		}
++
++		if (GET_CORE_IF(pcd)->dma_desc_enable) {
++			dev_if->setup_desc_addr[0] =
++			    dwc_otg_ep_alloc_desc_chain
++			    (&dev_if->dma_setup_desc_addr[0], 1);
++			dev_if->setup_desc_addr[1] =
++			    dwc_otg_ep_alloc_desc_chain
++			    (&dev_if->dma_setup_desc_addr[1], 1);
++			dev_if->in_desc_addr =
++			    dwc_otg_ep_alloc_desc_chain
++			    (&dev_if->dma_in_desc_addr, 1);
++			dev_if->out_desc_addr =
++			    dwc_otg_ep_alloc_desc_chain
++			    (&dev_if->dma_out_desc_addr, 1);
++			pcd->data_terminated = 0;
++
++			if (dev_if->setup_desc_addr[0] == 0
++			    || dev_if->setup_desc_addr[1] == 0
++			    || dev_if->in_desc_addr == 0
++			    || dev_if->out_desc_addr == 0) {
++
++				if (dev_if->out_desc_addr)
++					dwc_otg_ep_free_desc_chain
++					    (dev_if->out_desc_addr,
++					     dev_if->dma_out_desc_addr, 1);
++				if (dev_if->in_desc_addr)
++					dwc_otg_ep_free_desc_chain
++					    (dev_if->in_desc_addr,
++					     dev_if->dma_in_desc_addr, 1);
++				if (dev_if->setup_desc_addr[1])
++					dwc_otg_ep_free_desc_chain
++					    (dev_if->setup_desc_addr[1],
++					     dev_if->dma_setup_desc_addr[1], 1);
++				if (dev_if->setup_desc_addr[0])
++					dwc_otg_ep_free_desc_chain
++					    (dev_if->setup_desc_addr[0],
++					     dev_if->dma_setup_desc_addr[0], 1);
++
++				DWC_DMA_FREE(sizeof(*pcd->setup_pkt) * 5,
++					     pcd->setup_pkt,
++					     pcd->setup_pkt_dma_handle);
++				DWC_DMA_FREE(sizeof(*pcd->status_buf),
++					     pcd->status_buf,
++					     pcd->status_buf_dma_handle);
++
++				DWC_FREE(pcd);
++
++				return NULL;
++			}
++		}
++	} else {
++		pcd->setup_pkt = DWC_ALLOC(sizeof(*pcd->setup_pkt) * 5);
++		if (pcd->setup_pkt == NULL) {
++			DWC_FREE(pcd);
++			return NULL;
++		}
++
++		pcd->status_buf = DWC_ALLOC(sizeof(uint16_t));
++		if (pcd->status_buf == NULL) {
++			DWC_FREE(pcd->setup_pkt);
++			DWC_FREE(pcd);
++			return NULL;
++		}
++	}
++
++	dwc_otg_pcd_reinit(pcd);
++
++	/* Allocate the cfi object for the PCD */
++#ifdef DWC_UTE_CFI
++	pcd->cfi = DWC_ALLOC(sizeof(cfiobject_t));
++	if (NULL == pcd->cfi)
++		goto fail;
++	if (init_cfi(pcd->cfi)) {
++		CFI_INFO("%s: Failed to init the CFI object\n", __func__);
++		goto fail;
++	}
++#endif
++
++	/* Initialize tasklets */
++	pcd->start_xfer_tasklet = DWC_TASK_ALLOC("xfer_tasklet",
++						 start_xfer_tasklet_func, pcd);
++	pcd->test_mode_tasklet = DWC_TASK_ALLOC("test_mode_tasklet",
++						do_test_mode, pcd);
++
++	/* Initialize SRP timer */
++	core_if->srp_timer = DWC_TIMER_ALLOC("SRP TIMER", srp_timeout, core_if);
++
++	if (core_if->core_params->dev_out_nak) {
++		/**
++		* Initialize xfer timeout timer. Implemented for
++		* 2.93a feature "Device DDMA OUT NAK Enhancement"
++		*/
++		for (i = 0; i < MAX_EPS_CHANNELS; i++) {
++			pcd->core_if->ep_xfer_timer[i] =
++			    DWC_TIMER_ALLOC("ep timer", ep_xfer_timeout,
++					    &pcd->core_if->ep_xfer_info[i]);
++		}
++	}
++
++	return pcd;
++#ifdef DWC_UTE_CFI
++fail:
++#endif
++	if (pcd->setup_pkt)
++		DWC_FREE(pcd->setup_pkt);
++	if (pcd->status_buf)
++		DWC_FREE(pcd->status_buf);
++#ifdef DWC_UTE_CFI
++	if (pcd->cfi)
++		DWC_FREE(pcd->cfi);
++#endif
++	if (pcd)
++		DWC_FREE(pcd);
++	return NULL;
++
++}
++
++/**
++ * Remove PCD specific data
++ */
++void dwc_otg_pcd_remove(dwc_otg_pcd_t * pcd)
++{
++	dwc_otg_dev_if_t *dev_if = GET_CORE_IF(pcd)->dev_if;
++	int i;
++	if (pcd->core_if->core_params->dev_out_nak) {
++		for (i = 0; i < MAX_EPS_CHANNELS; i++) {
++			DWC_TIMER_CANCEL(pcd->core_if->ep_xfer_timer[i]);
++			pcd->core_if->ep_xfer_info[i].state = 0;
++		}
++	}
++
++	if (GET_CORE_IF(pcd)->dma_enable) {
++		DWC_DMA_FREE(sizeof(*pcd->setup_pkt) * 5, pcd->setup_pkt,
++			     pcd->setup_pkt_dma_handle);
++		DWC_DMA_FREE(sizeof(uint16_t), pcd->status_buf,
++			     pcd->status_buf_dma_handle);
++		if (GET_CORE_IF(pcd)->dma_desc_enable) {
++			dwc_otg_ep_free_desc_chain(dev_if->setup_desc_addr[0],
++						   dev_if->dma_setup_desc_addr
++						   [0], 1);
++			dwc_otg_ep_free_desc_chain(dev_if->setup_desc_addr[1],
++						   dev_if->dma_setup_desc_addr
++						   [1], 1);
++			dwc_otg_ep_free_desc_chain(dev_if->in_desc_addr,
++						   dev_if->dma_in_desc_addr, 1);
++			dwc_otg_ep_free_desc_chain(dev_if->out_desc_addr,
++						   dev_if->dma_out_desc_addr,
++						   1);
++		}
++	} else {
++		DWC_FREE(pcd->setup_pkt);
++		DWC_FREE(pcd->status_buf);
++	}
++	DWC_SPINLOCK_FREE(pcd->lock);
++	/* Set core_if's lock pointer to NULL */
++	pcd->core_if->lock = NULL;
++
++	DWC_TASK_FREE(pcd->start_xfer_tasklet);
++	DWC_TASK_FREE(pcd->test_mode_tasklet);
++	if (pcd->core_if->core_params->dev_out_nak) {
++		for (i = 0; i < MAX_EPS_CHANNELS; i++) {
++			if (pcd->core_if->ep_xfer_timer[i]) {
++				DWC_TIMER_FREE(pcd->core_if->ep_xfer_timer[i]);
++			}
++		}
++	}
++
++/* Release the CFI object's dynamic memory */
++#ifdef DWC_UTE_CFI
++	if (pcd->cfi->ops.release) {
++		pcd->cfi->ops.release(pcd->cfi);
++	}
++#endif
++
++	DWC_FREE(pcd);
++}
++
++/**
++ * Returns whether registered pcd is dual speed or not
++ */
++uint32_t dwc_otg_pcd_is_dualspeed(dwc_otg_pcd_t * pcd)
++{
++	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
++
++	if ((core_if->core_params->speed == DWC_SPEED_PARAM_FULL) ||
++	    ((core_if->hwcfg2.b.hs_phy_type == 2) &&
++	     (core_if->hwcfg2.b.fs_phy_type == 1) &&
++	     (core_if->core_params->ulpi_fs_ls))) {
++		return 0;
++	}
++
++	return 1;
++}
++
++/**
++ * Returns whether registered pcd is OTG capable or not
++ */
++uint32_t dwc_otg_pcd_is_otg(dwc_otg_pcd_t * pcd)
++{
++	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
++	gusbcfg_data_t usbcfg = {.d32 = 0 };
++	uint32_t retval = 0;
++
++	usbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
++#if LINUX_VERSION_CODE < KERNEL_VERSION(3,6,0)
++	if (!usbcfg.b.srpcap || !usbcfg.b.hnpcap)
++		return 0;
++	else
++		return 1;
++# else
++	if (!usbcfg.b.srpcap)
++		return 0;
++	else
++		retval |= 1;
++
++	if (usbcfg.b.hnpcap)
++		retval |= 2;
++
++	if (core_if->adp_enable)
++		retval |= 4;
++#endif
++
++	return retval;
++}
++
++/**
++ * This function assigns periodic Tx FIFO to an periodic EP
++ * in shared Tx FIFO mode
++ */
++static uint32_t assign_tx_fifo(dwc_otg_core_if_t * core_if)
++{
++	uint32_t TxMsk = 1;
++	int i;
++
++	for (i = 0; i < core_if->hwcfg4.b.num_in_eps; ++i) {
++		if ((TxMsk & core_if->tx_msk) == 0) {
++			core_if->tx_msk |= TxMsk;
++			return i + 1;
++		}
++		TxMsk <<= 1;
++	}
++	return 0;
++}
++
++/**
++ * This function assigns periodic Tx FIFO to an periodic EP
++ * in shared Tx FIFO mode
++ */
++static uint32_t assign_perio_tx_fifo(dwc_otg_core_if_t * core_if)
++{
++	uint32_t PerTxMsk = 1;
++	int i;
++	for (i = 0; i < core_if->hwcfg4.b.num_dev_perio_in_ep; ++i) {
++		if ((PerTxMsk & core_if->p_tx_msk) == 0) {
++			core_if->p_tx_msk |= PerTxMsk;
++			return i + 1;
++		}
++		PerTxMsk <<= 1;
++	}
++	return 0;
++}
++
++/**
++ * This function releases periodic Tx FIFO
++ * in shared Tx FIFO mode
++ */
++static void release_perio_tx_fifo(dwc_otg_core_if_t * core_if,
++				  uint32_t fifo_num)
++{
++	core_if->p_tx_msk =
++	    (core_if->p_tx_msk & (1 << (fifo_num - 1))) ^ core_if->p_tx_msk;
++}
++
++/**
++ * This function releases periodic Tx FIFO
++ * in shared Tx FIFO mode
++ */
++static void release_tx_fifo(dwc_otg_core_if_t * core_if, uint32_t fifo_num)
++{
++	core_if->tx_msk =
++	    (core_if->tx_msk & (1 << (fifo_num - 1))) ^ core_if->tx_msk;
++}
++
++/**
++ * This function is being called from gadget
++ * to enable PCD endpoint.
++ */
++int dwc_otg_pcd_ep_enable(dwc_otg_pcd_t * pcd,
++			  const uint8_t * ep_desc, void *usb_ep)
++{
++	int num, dir;
++	dwc_otg_pcd_ep_t *ep = NULL;
++	const usb_endpoint_descriptor_t *desc;
++	dwc_irqflags_t flags;
++	fifosize_data_t dptxfsiz = {.d32 = 0 };
++	gdfifocfg_data_t gdfifocfg = {.d32 = 0 };
++	gdfifocfg_data_t gdfifocfgbase = {.d32 = 0 };
++	int retval = 0;
++	int i, epcount;
++
++	desc = (const usb_endpoint_descriptor_t *)ep_desc;
++
++	if (!desc) {
++		pcd->ep0.priv = usb_ep;
++		retval = -DWC_E_INVALID;
++		goto out;
++	}
++
++	num = UE_GET_ADDR(desc->bEndpointAddress);
++	dir = UE_GET_DIR(desc->bEndpointAddress);
++
++	if (dir == UE_DIR_IN) {
++		epcount = pcd->core_if->dev_if->num_in_eps;
++		for (i = 0; i < epcount; i++) {
++			if (num == pcd->in_ep[i].dwc_ep.num) {
++				ep = &pcd->in_ep[i];
++				break;
++			}
++		}
++	} else {
++		epcount = pcd->core_if->dev_if->num_out_eps;
++		for (i = 0; i < epcount; i++) {
++			if (num == pcd->out_ep[i].dwc_ep.num) {
++				ep = &pcd->out_ep[i];
++				break;
++			}
++		}
++	}
++
++	if (!ep) {
++		DWC_WARN("bad address\n");
++		retval = -DWC_E_INVALID;
++		goto out;
++	}
++
++	DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
++
++	ep->desc = desc;
++	ep->priv = usb_ep;
++
++	/*
++	 * Activate the EP
++	 */
++	ep->stopped = 0;
++
++	ep->dwc_ep.is_in = (dir == UE_DIR_IN);
++	ep->dwc_ep.maxpacket = UGETW(desc->wMaxPacketSize);
++
++	ep->dwc_ep.type = desc->bmAttributes & UE_XFERTYPE;
++	if (UE_BULK == ep->dwc_ep.type)
++		bulk_num = ep->dwc_ep.num;
++
++	if (ep->dwc_ep.is_in) {
++		if (!GET_CORE_IF(pcd)->en_multiple_tx_fifo) {
++			ep->dwc_ep.tx_fifo_num = 0;
++
++			if (ep->dwc_ep.type == UE_ISOCHRONOUS) {
++				/*
++				 * if ISOC EP then assign a Periodic Tx FIFO.
++				 */
++				ep->dwc_ep.tx_fifo_num =
++				    assign_perio_tx_fifo(GET_CORE_IF(pcd));
++			}
++		} else {
++			/*
++			 * if Dedicated FIFOs mode is on then assign a Tx FIFO.
++			 */
++			ep->dwc_ep.tx_fifo_num =
++			    assign_tx_fifo(GET_CORE_IF(pcd));
++		}
++
++		/* Calculating EP info controller base address */
++		if (ep->dwc_ep.tx_fifo_num
++		    && GET_CORE_IF(pcd)->en_multiple_tx_fifo) {
++			gdfifocfg.d32 =
++			    DWC_READ_REG32(&GET_CORE_IF(pcd)->
++					   core_global_regs->gdfifocfg);
++			gdfifocfgbase.d32 = gdfifocfg.d32 >> 16;
++			dptxfsiz.d32 =
++			    (DWC_READ_REG32
++			     (&GET_CORE_IF(pcd)->core_global_regs->
++			      dtxfsiz[ep->dwc_ep.tx_fifo_num - 1]) >> 16);
++			gdfifocfg.b.epinfobase =
++			    gdfifocfgbase.d32 + dptxfsiz.d32;
++			if (GET_CORE_IF(pcd)->snpsid <= OTG_CORE_REV_2_94a) {
++				DWC_WRITE_REG32(&GET_CORE_IF(pcd)->
++						core_global_regs->gdfifocfg,
++						gdfifocfg.d32);
++			}
++		}
++	}
++	/* Set initial data PID. */
++	if (ep->dwc_ep.type == UE_BULK) {
++		ep->dwc_ep.data_pid_start = 0;
++	}
++
++	/* Alloc DMA Descriptors */
++	if (GET_CORE_IF(pcd)->dma_desc_enable) {
++#ifndef DWC_UTE_PER_IO
++		if (ep->dwc_ep.type != UE_ISOCHRONOUS) {
++#endif
++			ep->dwc_ep.desc_addr =
++			    dwc_otg_ep_alloc_desc_chain(&ep->
++							dwc_ep.dma_desc_addr,
++							MAX_DMA_DESC_CNT);
++			if (!ep->dwc_ep.desc_addr) {
++				DWC_WARN("%s, can't allocate DMA descriptor\n",
++					 __func__);
++				retval = -DWC_E_SHUTDOWN;
++				DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
++				goto out;
++			}
++#ifndef DWC_UTE_PER_IO
++		} else {
++			ep->dwc_ep.desc_addr =
++				dwc_otg_ep_alloc_desc_chain(&ep->
++				dwc_ep.dma_desc_addr,
++				MAX_DMA_DESC_CNT/2);
++			ep->dwc_ep.desc_addr1 =
++				dwc_otg_ep_alloc_desc_chain(&ep->
++				dwc_ep.dma_desc_addr1,
++				MAX_DMA_DESC_CNT/2);
++			if (!ep->dwc_ep.desc_addr || !ep->dwc_ep.desc_addr1) {
++				DWC_WARN("%s, can't allocate DMA descriptor\n",
++					__func__);
++				retval = -DWC_E_SHUTDOWN;
++				DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
++				goto out;
++			}
++			/* Set initial data PID. */
++			if (ep->dwc_ep.type == UE_ISOCHRONOUS) {
++				ep->dwc_ep.iso_desc_first = 0;
++				ep->dwc_ep.iso_desc_second = 0;
++				ep->dwc_ep.iso_transfer_started = 0;
++			}
++		}
++#endif
++	}
++
++	DWC_DEBUGPL(DBG_PCD, "Activate %s: type=%d, mps=%d desc=%p\n",
++		    (ep->dwc_ep.is_in ? "IN" : "OUT"),
++		    ep->dwc_ep.type, ep->dwc_ep.maxpacket, ep->desc);
++#ifdef DWC_UTE_PER_IO
++	ep->dwc_ep.xiso_bInterval = 1 << (ep->desc->bInterval - 1);
++#endif
++	if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
++		ep->dwc_ep.bInterval = 1 << (ep->desc->bInterval - 1);
++		ep->dwc_ep.frame_num = 0xFFFFFFFF;
++	}
++
++	dwc_otg_ep_activate(GET_CORE_IF(pcd), &ep->dwc_ep);
++
++#ifdef DWC_UTE_CFI
++	if (pcd->cfi->ops.ep_enable) {
++		pcd->cfi->ops.ep_enable(pcd->cfi, pcd, ep);
++	}
++#endif
++
++	DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
++
++out:
++	return retval;
++}
++
++/**
++ * This function is being called from gadget
++ * to disable PCD endpoint.
++ */
++int dwc_otg_pcd_ep_disable(dwc_otg_pcd_t * pcd, void *ep_handle)
++{
++	dwc_otg_pcd_ep_t *ep;
++	dwc_irqflags_t flags;
++	dwc_otg_dev_dma_desc_t *desc_addr;
++	dwc_dma_t dma_desc_addr;
++	gdfifocfg_data_t gdfifocfgbase = {.d32 = 0 };
++	gdfifocfg_data_t gdfifocfg = {.d32 = 0 };
++	fifosize_data_t dptxfsiz = {.d32 = 0 };
++
++	ep = get_ep_from_handle(pcd, ep_handle);
++
++	if (!ep || !ep->desc) {
++		DWC_DEBUGPL(DBG_PCD, "bad ep address\n");
++		return -DWC_E_INVALID;
++	}
++
++	DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
++
++	dwc_otg_request_nuke(ep);
++
++	dwc_otg_ep_deactivate(GET_CORE_IF(pcd), &ep->dwc_ep);
++	if (pcd->core_if->core_params->dev_out_nak) {
++		DWC_TIMER_CANCEL(pcd->core_if->ep_xfer_timer[ep->dwc_ep.num]);
++		pcd->core_if->ep_xfer_info[ep->dwc_ep.num].state = 0;
++	}
++	ep->desc = NULL;
++	ep->stopped = 1;
++
++	gdfifocfg.d32 =
++	    DWC_READ_REG32(&GET_CORE_IF(pcd)->core_global_regs->gdfifocfg);
++	gdfifocfgbase.d32 = gdfifocfg.d32 >> 16;
++
++	if (ep->dwc_ep.is_in) {
++		if (GET_CORE_IF(pcd)->en_multiple_tx_fifo) {
++			/* Flush the Tx FIFO */
++			dwc_otg_flush_tx_fifo(GET_CORE_IF(pcd),
++					      ep->dwc_ep.tx_fifo_num);
++		}
++		release_perio_tx_fifo(GET_CORE_IF(pcd), ep->dwc_ep.tx_fifo_num);
++		release_tx_fifo(GET_CORE_IF(pcd), ep->dwc_ep.tx_fifo_num);
++		if (GET_CORE_IF(pcd)->en_multiple_tx_fifo) {
++			/* Decreasing EPinfo Base Addr */
++			dptxfsiz.d32 =
++			    (DWC_READ_REG32
++			     (&GET_CORE_IF(pcd)->
++				core_global_regs->dtxfsiz[ep->dwc_ep.tx_fifo_num-1]) >> 16);
++			gdfifocfg.b.epinfobase = gdfifocfgbase.d32 - dptxfsiz.d32;
++			if (GET_CORE_IF(pcd)->snpsid <= OTG_CORE_REV_2_94a) {
++				DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gdfifocfg,
++						gdfifocfg.d32);
++			}
++		}
++	}
++
++	/* Free DMA Descriptors */
++	if (GET_CORE_IF(pcd)->dma_desc_enable) {
++		if (ep->dwc_ep.type != UE_ISOCHRONOUS) {
++			desc_addr = ep->dwc_ep.desc_addr;
++			dma_desc_addr = ep->dwc_ep.dma_desc_addr;
++
++			/* Cannot call dma_free_coherent() with IRQs disabled */
++			DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
++			dwc_otg_ep_free_desc_chain(desc_addr, dma_desc_addr,
++						   MAX_DMA_DESC_CNT);
++
++		} else {
++			desc_addr = ep->dwc_ep.desc_addr;
++			dma_desc_addr = ep->dwc_ep.dma_desc_addr;
++
++			/* Cannot call dma_free_coherent() with IRQs disabled */
++			DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
++			dwc_otg_ep_free_desc_chain(desc_addr, dma_desc_addr,
++				MAX_DMA_DESC_CNT/2);
++			desc_addr = ep->dwc_ep.desc_addr1;
++			dma_desc_addr = ep->dwc_ep.dma_desc_addr1;
++			dwc_otg_ep_free_desc_chain(desc_addr, dma_desc_addr,
++				MAX_DMA_DESC_CNT/2);
++		}
++		goto out_unlocked;
++	}
++	DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
++
++out_unlocked:
++	DWC_DEBUGPL(DBG_PCD, "%d %s disabled\n", ep->dwc_ep.num,
++		    ep->dwc_ep.is_in ? "IN" : "OUT");
++	return 0;
++
++}
++
++/**
++ * This function initializes dma descriptor chain for ISOC transfers.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ * @param ep The EP to start the transfer on.
++ */
++void dwc_otg_pcd_start_iso_ddma(dwc_otg_core_if_t * core_if, dwc_otg_pcd_ep_t * ep)
++{
++	dwc_otg_dev_dma_desc_t *dma_desc;
++	dwc_otg_pcd_request_t *req = NULL;
++	dwc_ep_t *dwcep = NULL;
++	uint32_t frame_num = 0;
++	int i = 0;
++	int j;
++	int sync_request = 4;
++	uint16_t nat;
++	depctl_data_t depctl;
++
++	dwcep = &ep->dwc_ep;
++	dma_desc = dwcep->desc_addr;
++
++	nat = UGETW(ep->desc->wMaxPacketSize);
++	nat = (nat >> 11) & 0x03;
++	DWC_DEBUGPL(DBG_PCD, "nat=%u binterval =%02x\n",nat, dwcep->bInterval);
++	DWC_DEBUGPL(DBG_PCD, "frame_num =  %d\n", dwcep->frame_num);
++
++	/* Complete first three IN EP requests for the synchronization */
++	if (dwcep->is_in) {
++		if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
++			for (j = 0; j < sync_request; j++) {
++				req = DWC_CIRCLEQ_FIRST(&ep->queue);
++				if (!req) {
++					DWC_PRINTF("ISOC 0x%p, req = NULL!\n", ep);
++					return;
++				} else {
++					/* Complete first request */
++					req->actual = 0;
++					dwc_otg_request_done(ep, req, 0);
++				}
++			}
++		} else {
++			DWC_PRINTF("ISOC ep 0x%p, ep->queue empty!\n", ep);
++			return;
++		}
++
++		frame_num = dwcep->frame_num + (sync_request -1)*dwcep->bInterval;
++
++		DWC_CIRCLEQ_FOREACH(req, &ep->queue, queue_entry) {
++			i = i+1;
++			frame_num = (frame_num + dwcep->bInterval) & 0x3FFF;
++			/** DMA Descriptor Setup */
++			dma_desc->status.b_iso_in.bs = BS_HOST_BUSY;
++			dma_desc->buf = req->dma;
++			dma_desc->status.b_iso_in.txbytes = req->length;
++			dma_desc->status.b_iso_in.framenum = frame_num;
++			dma_desc->status.b_iso_in.txsts = 0;
++			dma_desc->status.b_iso_in.sp = (req->length % dwcep->maxpacket) ? 1 : 0;
++			dma_desc->status.b_iso_in.ioc = 1;
++			dma_desc->status.b_iso_in.pid = nat + 1;
++			dma_desc->status.b_iso_in.l = 0;
++
++			if (req == DWC_CIRCLEQ_LAST(&ep->queue)) {
++				dma_desc->status.b_iso_in.l = 1;
++			}
++			dma_desc->status.b_iso_in.bs = BS_HOST_READY;
++			DWC_DEBUGPL(DBG_PCD, "ISO_DESC #%d %p status = %08x\n", i, dma_desc, dma_desc->status.d32);
++			if (i == MAX_DMA_DESC_CNT/2 - 1) {
++				dma_desc->status.b_iso_in.l = 1;
++				break;
++			}
++			dma_desc++;
++		}
++		DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[dwcep->num]->diepdma, dwcep->dma_desc_addr);
++		DWC_DEBUGPL(DBG_PCD, "%d ISOC IN descs were programmed\n", i-1);
++		depctl.d32 = 0;
++		depctl.b.epena = 1;
++		depctl.b.cnak = 1;
++		DWC_MODIFY_REG32(&core_if->dev_if->in_ep_regs[dwcep->num]->diepctl, 0, depctl.d32);
++	} else {
++		DWC_CIRCLEQ_FOREACH(req, &ep->queue, queue_entry) {
++			i = i+1;
++			frame_num = (frame_num + dwcep->bInterval) & 0x3FFF;
++			/** DMA Descriptor Setup */
++			dma_desc->status.b_iso_out.bs = BS_HOST_BUSY;
++			dma_desc->buf = req->dma;
++			dma_desc->status.b_iso_out.rxbytes = req->length;
++			dma_desc->status.b_iso_out.rxsts = 0;
++			dma_desc->status.b_iso_out.sp = (req->length % dwcep->maxpacket) ? 1 : 0;
++			dma_desc->status.b_iso_out.ioc = 1;
++			dma_desc->status.b_iso_out.pid = nat + 1;
++			dma_desc->status.b_iso_out.l = 0;
++
++			if (req == DWC_CIRCLEQ_LAST(&ep->queue)) {
++				dma_desc->status.b_iso_out.l = 1;
++			}
++			dma_desc->status.b_iso_in.bs = BS_HOST_READY;
++			DWC_DEBUGPL(DBG_PCD, "ISO_DESC #%d %p status = %08x\n", i, dma_desc, dma_desc->status.d32);
++			if (i == MAX_DMA_DESC_CNT/2 - 1) {
++				dma_desc->status.b_iso_out.l = 1;
++				break;
++			}
++			dma_desc++;
++		}
++		DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[dwcep->num]->doepdma, dwcep->dma_desc_addr);
++		DWC_DEBUGPL(DBG_PCD, "%d ISOC OUT descs were programmed\n", i-1);
++		depctl.d32 = 0;
++		depctl.b.epena = 1;
++		depctl.b.cnak = 1;
++		DWC_MODIFY_REG32(&core_if->dev_if->out_ep_regs[dwcep->num]->doepctl, 0, depctl.d32);
++	}
++	dwcep->iso_desc_first = i; //vahrama - pay attention previous one was i-1
++	dwcep->iso_transfer_started = 1;
++	dwcep->frame_num = frame_num;
++	dwcep->use_add_buf = 1;
++}
++/**
++ * Program next ISO request to the DMA chain
++ *
++ */
++static void program_next_iso_request_ddma (dwc_otg_pcd_ep_t * ep, dwc_otg_pcd_request_t * req)
++{
++	dwc_otg_dev_dma_desc_t *dma_desc;
++	dwc_dma_t dma_desc_addr;
++	uint32_t frame_num = 0;
++	uint32_t nat;
++	uint32_t index;
++
++	DWC_DEBUGPL(DBG_PCD, "%s", __FUNCTION__);
++
++	if (ep->dwc_ep.use_add_buf) {
++		index =	ep->dwc_ep.iso_desc_second + 1;
++	} else {
++		index =	ep->dwc_ep.iso_desc_first + 1;
++	}
++
++	if (index > MAX_DMA_DESC_CNT/2) {
++		DWC_PRINTF("There are no free descs in the chain!\n");
++		return;
++	}
++
++	if (ep->dwc_ep.use_add_buf) {
++		dma_desc = &ep->dwc_ep.desc_addr1[ep->dwc_ep.iso_desc_second];
++		dma_desc_addr = ep->dwc_ep.dma_desc_addr1;
++		ep->dwc_ep.iso_desc_second += 1;
++	}  else {
++		dma_desc = &ep->dwc_ep.desc_addr[ep->dwc_ep.iso_desc_first];
++		dma_desc_addr = ep->dwc_ep.dma_desc_addr;
++		ep->dwc_ep.iso_desc_first += 1;
++	}
++	nat = (req->length + ep->dwc_ep.maxpacket - 1)
++		/ ep->dwc_ep.maxpacket;
++
++	if (nat)
++		nat--;
++	frame_num = (ep->dwc_ep.frame_num + ep->dwc_ep.bInterval) & 0x3FFF;
++	if (ep->dwc_ep.is_in) {
++		/** DMA Descriptor Setup */
++		dma_desc->status.b_iso_in.bs = BS_HOST_BUSY;
++		dma_desc->buf = req->dma;
++		dma_desc->status.b_iso_in.txbytes = req->length;
++		dma_desc->status.b_iso_in.framenum = frame_num;
++		dma_desc->status.b_iso_in.txsts = 0;
++		dma_desc->status.b_iso_in.sp = (req->length % ep->dwc_ep.maxpacket) ? 1 : 0;
++		dma_desc->status.b_iso_in.ioc = 1;
++		dma_desc->status.b_iso_in.pid = nat + 1;
++		dma_desc->status.b_iso_in.l = 1;
++
++		dma_desc->status.b_iso_in.bs = BS_HOST_READY;
++
++		/* Clear L bit on the previous desc of the chain */
++		if (index > 1) {
++			dma_desc--;
++			dma_desc->status.b_iso_in.l = 0;
++		}
++	}  else {
++		/** DMA Descriptor Setup */
++		dma_desc->status.b_iso_out.bs = BS_HOST_BUSY;
++		dma_desc->buf = req->dma;
++		dma_desc->status.b_iso_out.rxbytes = req->length;
++		dma_desc->status.b_iso_out.rxsts = 0;
++		dma_desc->status.b_iso_out.sp = (req->length % ep->dwc_ep.maxpacket) ? 1 : 0;
++		dma_desc->status.b_iso_out.ioc = 1;
++		dma_desc->status.b_iso_out.pid = nat + 1;
++		dma_desc->status.b_iso_out.l = 1;
++
++		dma_desc->status.b_iso_out.bs = BS_HOST_READY;
++
++		/* Clear L bit on the previous desc of the chain */
++		if (index > 1) {
++			dma_desc--;
++			dma_desc->status.b_iso_out.l = 0;
++		}
++	}
++	ep->dwc_ep.frame_num = frame_num;
++
++}
++
++/******************************************************************************/
++#ifdef DWC_UTE_PER_IO
++
++/**
++ * Free the request and its extended parts
++ *
++ */
++void dwc_pcd_xiso_ereq_free(dwc_otg_pcd_ep_t * ep, dwc_otg_pcd_request_t * req)
++{
++	DWC_FREE(req->ext_req.per_io_frame_descs);
++	DWC_FREE(req);
++}
++
++/**
++ * Start the next request in the endpoint's queue.
++ *
++ */
++int dwc_otg_pcd_xiso_start_next_request(dwc_otg_pcd_t * pcd,
++					dwc_otg_pcd_ep_t * ep)
++{
++	int i;
++	dwc_otg_pcd_request_t *req = NULL;
++	dwc_ep_t *dwcep = NULL;
++	struct dwc_iso_xreq_port *ereq = NULL;
++	struct dwc_iso_pkt_desc_port *ddesc_iso;
++	uint16_t nat;
++	depctl_data_t diepctl;
++
++	dwcep = &ep->dwc_ep;
++
++	if (dwcep->xiso_active_xfers > 0) {
++#if 0	//Disable this to decrease s/w overhead that is crucial for Isoc transfers
++		DWC_WARN("There are currently active transfers for EP%d \
++				(active=%d; queued=%d)", dwcep->num, dwcep->xiso_active_xfers,
++				dwcep->xiso_queued_xfers);
++#endif
++		return 0;
++	}
++
++	nat = UGETW(ep->desc->wMaxPacketSize);
++	nat = (nat >> 11) & 0x03;
++
++	if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
++		req = DWC_CIRCLEQ_FIRST(&ep->queue);
++		ereq = &req->ext_req;
++		ep->stopped = 0;
++
++		/* Get the frame number */
++		dwcep->xiso_frame_num =
++		    dwc_otg_get_frame_number(GET_CORE_IF(pcd));
++		DWC_DEBUG("FRM_NUM=%d", dwcep->xiso_frame_num);
++
++		ddesc_iso = ereq->per_io_frame_descs;
++
++		if (dwcep->is_in) {
++			/* Setup DMA Descriptor chain for IN Isoc request */
++			for (i = 0; i < ereq->pio_pkt_count; i++) {
++				//if ((i % (nat + 1)) == 0)
++				if (i > 0)
++					dwcep->xiso_frame_num =
++					    (dwcep->xiso_bInterval +
++					     dwcep->xiso_frame_num) & 0x3FFF;
++				dwcep->desc_addr[i].buf =
++				    req->dma + ddesc_iso[i].offset;
++				dwcep->desc_addr[i].status.b_iso_in.txbytes =
++				    ddesc_iso[i].length;
++				dwcep->desc_addr[i].status.b_iso_in.framenum =
++				    dwcep->xiso_frame_num;
++				dwcep->desc_addr[i].status.b_iso_in.bs =
++				    BS_HOST_READY;
++				dwcep->desc_addr[i].status.b_iso_in.txsts = 0;
++				dwcep->desc_addr[i].status.b_iso_in.sp =
++				    (ddesc_iso[i].length %
++				     dwcep->maxpacket) ? 1 : 0;
++				dwcep->desc_addr[i].status.b_iso_in.ioc = 0;
++				dwcep->desc_addr[i].status.b_iso_in.pid = nat + 1;
++				dwcep->desc_addr[i].status.b_iso_in.l = 0;
++
++				/* Process the last descriptor */
++				if (i == ereq->pio_pkt_count - 1) {
++					dwcep->desc_addr[i].status.b_iso_in.ioc = 1;
++					dwcep->desc_addr[i].status.b_iso_in.l = 1;
++				}
++			}
++
++			/* Setup and start the transfer for this endpoint */
++			dwcep->xiso_active_xfers++;
++			DWC_WRITE_REG32(&GET_CORE_IF(pcd)->dev_if->
++					in_ep_regs[dwcep->num]->diepdma,
++					dwcep->dma_desc_addr);
++			diepctl.d32 = 0;
++			diepctl.b.epena = 1;
++			diepctl.b.cnak = 1;
++			DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->dev_if->
++					 in_ep_regs[dwcep->num]->diepctl, 0,
++					 diepctl.d32);
++		} else {
++			/* Setup DMA Descriptor chain for OUT Isoc request */
++			for (i = 0; i < ereq->pio_pkt_count; i++) {
++				//if ((i % (nat + 1)) == 0)
++				dwcep->xiso_frame_num = (dwcep->xiso_bInterval +
++										dwcep->xiso_frame_num) & 0x3FFF;
++				dwcep->desc_addr[i].buf =
++				    req->dma + ddesc_iso[i].offset;
++				dwcep->desc_addr[i].status.b_iso_out.rxbytes =
++				    ddesc_iso[i].length;
++				dwcep->desc_addr[i].status.b_iso_out.framenum =
++				    dwcep->xiso_frame_num;
++				dwcep->desc_addr[i].status.b_iso_out.bs =
++				    BS_HOST_READY;
++				dwcep->desc_addr[i].status.b_iso_out.rxsts = 0;
++				dwcep->desc_addr[i].status.b_iso_out.sp =
++				    (ddesc_iso[i].length %
++				     dwcep->maxpacket) ? 1 : 0;
++				dwcep->desc_addr[i].status.b_iso_out.ioc = 0;
++				dwcep->desc_addr[i].status.b_iso_out.pid = nat + 1;
++				dwcep->desc_addr[i].status.b_iso_out.l = 0;
++
++				/* Process the last descriptor */
++				if (i == ereq->pio_pkt_count - 1) {
++					dwcep->desc_addr[i].status.b_iso_out.ioc = 1;
++					dwcep->desc_addr[i].status.b_iso_out.l = 1;
++				}
++			}
++
++			/* Setup and start the transfer for this endpoint */
++			dwcep->xiso_active_xfers++;
++			DWC_WRITE_REG32(&GET_CORE_IF(pcd)->
++					dev_if->out_ep_regs[dwcep->num]->
++					doepdma, dwcep->dma_desc_addr);
++			diepctl.d32 = 0;
++			diepctl.b.epena = 1;
++			diepctl.b.cnak = 1;
++			DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->
++					 dev_if->out_ep_regs[dwcep->num]->
++					 doepctl, 0, diepctl.d32);
++		}
++
++	} else {
++		ep->stopped = 1;
++	}
++
++	return 0;
++}
++
++/**
++ *	- Remove the request from the queue
++ */
++void complete_xiso_ep(dwc_otg_pcd_ep_t * ep)
++{
++	dwc_otg_pcd_request_t *req = NULL;
++	struct dwc_iso_xreq_port *ereq = NULL;
++	struct dwc_iso_pkt_desc_port *ddesc_iso = NULL;
++	dwc_ep_t *dwcep = NULL;
++	int i;
++
++	//DWC_DEBUG();
++	dwcep = &ep->dwc_ep;
++
++	/* Get the first pending request from the queue */
++	if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
++		req = DWC_CIRCLEQ_FIRST(&ep->queue);
++		if (!req) {
++			DWC_PRINTF("complete_ep 0x%p, req = NULL!\n", ep);
++			return;
++		}
++		dwcep->xiso_active_xfers--;
++		dwcep->xiso_queued_xfers--;
++		/* Remove this request from the queue */
++		DWC_CIRCLEQ_REMOVE_INIT(&ep->queue, req, queue_entry);
++	} else {
++		DWC_PRINTF("complete_ep 0x%p, ep->queue empty!\n", ep);
++		return;
++	}
++
++	ep->stopped = 1;
++	ereq = &req->ext_req;
++	ddesc_iso = ereq->per_io_frame_descs;
++
++	if (dwcep->xiso_active_xfers < 0) {
++		DWC_WARN("EP#%d (xiso_active_xfers=%d)", dwcep->num,
++			 dwcep->xiso_active_xfers);
++	}
++
++	/* Fill the Isoc descs of portable extended req from dma descriptors */
++	for (i = 0; i < ereq->pio_pkt_count; i++) {
++		if (dwcep->is_in) {	/* IN endpoints */
++			ddesc_iso[i].actual_length = ddesc_iso[i].length -
++			    dwcep->desc_addr[i].status.b_iso_in.txbytes;
++			ddesc_iso[i].status =
++			    dwcep->desc_addr[i].status.b_iso_in.txsts;
++		} else {	/* OUT endpoints */
++			ddesc_iso[i].actual_length = ddesc_iso[i].length -
++			    dwcep->desc_addr[i].status.b_iso_out.rxbytes;
++			ddesc_iso[i].status =
++			    dwcep->desc_addr[i].status.b_iso_out.rxsts;
++		}
++	}
++
++	DWC_SPINUNLOCK(ep->pcd->lock);
++
++	/* Call the completion function in the non-portable logic */
++	ep->pcd->fops->xisoc_complete(ep->pcd, ep->priv, req->priv, 0,
++				      &req->ext_req);
++
++	DWC_SPINLOCK(ep->pcd->lock);
++
++	/* Free the request - specific freeing needed for extended request object */
++	dwc_pcd_xiso_ereq_free(ep, req);
++
++	/* Start the next request */
++	dwc_otg_pcd_xiso_start_next_request(ep->pcd, ep);
++
++	return;
++}
++
++/**
++ * Create and initialize the Isoc pkt descriptors of the extended request.
++ *
++ */
++static int dwc_otg_pcd_xiso_create_pkt_descs(dwc_otg_pcd_request_t * req,
++					     void *ereq_nonport,
++					     int atomic_alloc)
++{
++	struct dwc_iso_xreq_port *ereq = NULL;
++	struct dwc_iso_xreq_port *req_mapped = NULL;
++	struct dwc_iso_pkt_desc_port *ipds = NULL;	/* To be created in this function */
++	uint32_t pkt_count;
++	int i;
++
++	ereq = &req->ext_req;
++	req_mapped = (struct dwc_iso_xreq_port *)ereq_nonport;
++	pkt_count = req_mapped->pio_pkt_count;
++
++	/* Create the isoc descs */
++	if (atomic_alloc) {
++		ipds = DWC_ALLOC_ATOMIC(sizeof(*ipds) * pkt_count);
++	} else {
++		ipds = DWC_ALLOC(sizeof(*ipds) * pkt_count);
++	}
++
++	if (!ipds) {
++		DWC_ERROR("Failed to allocate isoc descriptors");
++		return -DWC_E_NO_MEMORY;
++	}
++
++	/* Initialize the extended request fields */
++	ereq->per_io_frame_descs = ipds;
++	ereq->error_count = 0;
++	ereq->pio_alloc_pkt_count = pkt_count;
++	ereq->pio_pkt_count = pkt_count;
++	ereq->tr_sub_flags = req_mapped->tr_sub_flags;
++
++	/* Init the Isoc descriptors */
++	for (i = 0; i < pkt_count; i++) {
++		ipds[i].length = req_mapped->per_io_frame_descs[i].length;
++		ipds[i].offset = req_mapped->per_io_frame_descs[i].offset;
++		ipds[i].status = req_mapped->per_io_frame_descs[i].status;	/* 0 */
++		ipds[i].actual_length =
++		    req_mapped->per_io_frame_descs[i].actual_length;
++	}
++
++	return 0;
++}
++
++static void prn_ext_request(struct dwc_iso_xreq_port *ereq)
++{
++	struct dwc_iso_pkt_desc_port *xfd = NULL;
++	int i;
++
++	DWC_DEBUG("per_io_frame_descs=%p", ereq->per_io_frame_descs);
++	DWC_DEBUG("tr_sub_flags=%d", ereq->tr_sub_flags);
++	DWC_DEBUG("error_count=%d", ereq->error_count);
++	DWC_DEBUG("pio_alloc_pkt_count=%d", ereq->pio_alloc_pkt_count);
++	DWC_DEBUG("pio_pkt_count=%d", ereq->pio_pkt_count);
++	DWC_DEBUG("res=%d", ereq->res);
++
++	for (i = 0; i < ereq->pio_pkt_count; i++) {
++		xfd = &ereq->per_io_frame_descs[0];
++		DWC_DEBUG("FD #%d", i);
++
++		DWC_DEBUG("xfd->actual_length=%d", xfd->actual_length);
++		DWC_DEBUG("xfd->length=%d", xfd->length);
++		DWC_DEBUG("xfd->offset=%d", xfd->offset);
++		DWC_DEBUG("xfd->status=%d", xfd->status);
++	}
++}
++
++/**
++ *
++ */
++int dwc_otg_pcd_xiso_ep_queue(dwc_otg_pcd_t * pcd, void *ep_handle,
++			      uint8_t * buf, dwc_dma_t dma_buf, uint32_t buflen,
++			      int zero, void *req_handle, int atomic_alloc,
++			      void *ereq_nonport)
++{
++	dwc_otg_pcd_request_t *req = NULL;
++	dwc_otg_pcd_ep_t *ep;
++	dwc_irqflags_t flags;
++	int res;
++
++	ep = get_ep_from_handle(pcd, ep_handle);
++	if (!ep) {
++		DWC_WARN("bad ep\n");
++		return -DWC_E_INVALID;
++	}
++
++	/* We support this extension only for DDMA mode */
++	if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC)
++		if (!GET_CORE_IF(pcd)->dma_desc_enable)
++			return -DWC_E_INVALID;
++
++	/* Create a dwc_otg_pcd_request_t object */
++	if (atomic_alloc) {
++		req = DWC_ALLOC_ATOMIC(sizeof(*req));
++	} else {
++		req = DWC_ALLOC(sizeof(*req));
++	}
++
++	if (!req) {
++		return -DWC_E_NO_MEMORY;
++	}
++
++	/* Create the Isoc descs for this request which shall be the exact match
++	 * of the structure sent to us from the non-portable logic */
++	res =
++	    dwc_otg_pcd_xiso_create_pkt_descs(req, ereq_nonport, atomic_alloc);
++	if (res) {
++		DWC_WARN("Failed to init the Isoc descriptors");
++		DWC_FREE(req);
++		return res;
++	}
++
++	DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
++
++	DWC_CIRCLEQ_INIT_ENTRY(req, queue_entry);
++	req->buf = buf;
++	req->dma = dma_buf;
++	req->length = buflen;
++	req->sent_zlp = zero;
++	req->priv = req_handle;
++
++	//DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
++	ep->dwc_ep.dma_addr = dma_buf;
++	ep->dwc_ep.start_xfer_buff = buf;
++	ep->dwc_ep.xfer_buff = buf;
++	ep->dwc_ep.xfer_len = 0;
++	ep->dwc_ep.xfer_count = 0;
++	ep->dwc_ep.sent_zlp = 0;
++	ep->dwc_ep.total_len = buflen;
++
++	/* Add this request to the tail */
++	DWC_CIRCLEQ_INSERT_TAIL(&ep->queue, req, queue_entry);
++	ep->dwc_ep.xiso_queued_xfers++;
++
++//DWC_DEBUG("CP_0");
++//DWC_DEBUG("req->ext_req.tr_sub_flags=%d", req->ext_req.tr_sub_flags);
++//prn_ext_request((struct dwc_iso_xreq_port *) ereq_nonport);
++//prn_ext_request(&req->ext_req);
++
++	//DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
++
++	/* If the req->status == ASAP  then check if there is any active transfer
++	 * for this endpoint. If no active transfers, then get the first entry
++	 * from the queue and start that transfer
++	 */
++	if (req->ext_req.tr_sub_flags == DWC_EREQ_TF_ASAP) {
++		res = dwc_otg_pcd_xiso_start_next_request(pcd, ep);
++		if (res) {
++			DWC_WARN("Failed to start the next Isoc transfer");
++			DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
++			DWC_FREE(req);
++			return res;
++		}
++	}
++
++	DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
++	return 0;
++}
++
++#endif
++/* END ifdef DWC_UTE_PER_IO ***************************************************/
++int dwc_otg_pcd_ep_queue(dwc_otg_pcd_t * pcd, void *ep_handle,
++			 uint8_t * buf, dwc_dma_t dma_buf, uint32_t buflen,
++			 int zero, void *req_handle, int atomic_alloc)
++{
++	dwc_irqflags_t flags;
++	dwc_otg_pcd_request_t *req;
++	dwc_otg_pcd_ep_t *ep;
++	uint32_t max_transfer;
++
++	ep = get_ep_from_handle(pcd, ep_handle);
++	if (!ep || (!ep->desc && ep->dwc_ep.num != 0)) {
++		DWC_WARN("bad ep\n");
++		return -DWC_E_INVALID;
++	}
++
++	if (atomic_alloc) {
++		req = DWC_ALLOC_ATOMIC(sizeof(*req));
++	} else {
++		req = DWC_ALLOC(sizeof(*req));
++	}
++
++	if (!req) {
++		return -DWC_E_NO_MEMORY;
++	}
++	DWC_CIRCLEQ_INIT_ENTRY(req, queue_entry);
++	if (!GET_CORE_IF(pcd)->core_params->opt) {
++		if (ep->dwc_ep.num != 0) {
++			DWC_ERROR("queue req %p, len %d buf %p\n",
++				  req_handle, buflen, buf);
++		}
++	}
++
++	req->buf = buf;
++	req->dma = dma_buf;
++	req->length = buflen;
++	req->sent_zlp = zero;
++	req->priv = req_handle;
++	req->dw_align_buf = NULL;
++	if ((dma_buf & 0x3) && GET_CORE_IF(pcd)->dma_enable
++	    && !GET_CORE_IF(pcd)->dma_desc_enable)
++		req->dw_align_buf = DWC_DMA_ALLOC(buflen,
++						  &req->dw_align_buf_dma);
++	DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
++
++	/*
++	 * After adding request to the queue for IN ISOC wait for In Token Received
++	 * when TX FIFO is empty interrupt and for OUT ISOC wait for OUT Token
++	 * Received when EP is disabled interrupt to obtain starting microframe
++	 * (odd/even) start transfer
++	 */
++	if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
++		if (req != 0) {
++			depctl_data_t depctl = {.d32 =
++				    DWC_READ_REG32(&pcd->core_if->dev_if->
++						   in_ep_regs[ep->dwc_ep.num]->
++						   diepctl) };
++			++pcd->request_pending;
++
++			DWC_CIRCLEQ_INSERT_TAIL(&ep->queue, req, queue_entry);
++			if (ep->dwc_ep.is_in) {
++				depctl.b.cnak = 1;
++				DWC_WRITE_REG32(&pcd->core_if->dev_if->
++						in_ep_regs[ep->dwc_ep.num]->
++						diepctl, depctl.d32);
++			}
++			if (GET_CORE_IF(pcd)->dma_desc_enable) {
++				if (ep->dwc_ep.iso_transfer_started) {
++					/*
++					 * Add next request to the descriptor chain
++					 * currently not in use by HW
++					 */
++					program_next_iso_request_ddma(ep, req);
++				} else if (!ep->dwc_ep.is_in)
++					/* For OUT start first request immediately after queue */
++					dwc_otg_pcd_start_iso_ddma(GET_CORE_IF(pcd), ep);
++			}
++
++			DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
++		}
++		return 0;
++	}
++
++	/*
++	 * For EP0 IN without premature status, zlp is required?
++	 */
++	if (ep->dwc_ep.num == 0 && ep->dwc_ep.is_in) {
++		DWC_DEBUGPL(DBG_PCDV, "%d-OUT ZLP\n", ep->dwc_ep.num);
++		//_req->zero = 1;
++	}
++
++	/* Start the transfer */
++	if (DWC_CIRCLEQ_EMPTY(&ep->queue) && !ep->stopped) {
++		/* EP0 Transfer? */
++		if (ep->dwc_ep.num == 0) {
++			switch (pcd->ep0state) {
++			case EP0_IN_DATA_PHASE:
++				DWC_DEBUGPL(DBG_PCD,
++					    "%s ep0: EP0_IN_DATA_PHASE\n",
++					    __func__);
++				break;
++
++			case EP0_OUT_DATA_PHASE:
++				DWC_DEBUGPL(DBG_PCD,
++					    "%s ep0: EP0_OUT_DATA_PHASE\n",
++					    __func__);
++				if (pcd->request_config) {
++					/* Complete STATUS PHASE */
++					ep->dwc_ep.is_in = 1;
++					pcd->ep0state = EP0_IN_STATUS_PHASE;
++				}
++				break;
++
++			case EP0_IN_STATUS_PHASE:
++				DWC_DEBUGPL(DBG_PCD,
++					    "%s ep0: EP0_IN_STATUS_PHASE\n",
++					    __func__);
++				break;
++
++			default:
++				DWC_DEBUGPL(DBG_ANY, "ep0: odd state %d\n",
++					    pcd->ep0state);
++				DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
++				return -DWC_E_SHUTDOWN;
++			}
++
++			ep->dwc_ep.dma_addr = dma_buf;
++			ep->dwc_ep.start_xfer_buff = buf;
++			ep->dwc_ep.xfer_buff = buf;
++			ep->dwc_ep.xfer_len = buflen;
++			ep->dwc_ep.xfer_count = 0;
++			ep->dwc_ep.sent_zlp = 0;
++			ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
++
++			if (zero) {
++				if ((ep->dwc_ep.xfer_len %
++				     ep->dwc_ep.maxpacket == 0)
++				    && (ep->dwc_ep.xfer_len != 0)) {
++					ep->dwc_ep.sent_zlp = 1;
++				}
++
++			}
++
++			dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd),
++						   &ep->dwc_ep);
++		}		// non-ep0 endpoints
++		else {
++#ifdef DWC_UTE_CFI
++			if (ep->dwc_ep.buff_mode != BM_STANDARD) {
++				/* store the request length */
++				ep->dwc_ep.cfi_req_len = buflen;
++				pcd->cfi->ops.build_descriptors(pcd->cfi, pcd,
++								ep, req);
++			} else {
++#endif
++				max_transfer =
++				    GET_CORE_IF(ep->pcd)->core_params->
++				    max_transfer_size;
++
++				/* Setup and start the Transfer */
++				if (req->dw_align_buf) {
++					if (ep->dwc_ep.is_in)
++						dwc_memcpy(req->dw_align_buf,
++							   buf, buflen);
++					ep->dwc_ep.dma_addr =
++					    req->dw_align_buf_dma;
++					ep->dwc_ep.start_xfer_buff =
++					    req->dw_align_buf;
++					ep->dwc_ep.xfer_buff =
++					    req->dw_align_buf;
++				} else {
++					ep->dwc_ep.dma_addr = dma_buf;
++					ep->dwc_ep.start_xfer_buff = buf;
++					ep->dwc_ep.xfer_buff = buf;
++				}
++				ep->dwc_ep.xfer_len = 0;
++				ep->dwc_ep.xfer_count = 0;
++				ep->dwc_ep.sent_zlp = 0;
++				ep->dwc_ep.total_len = buflen;
++
++				ep->dwc_ep.maxxfer = max_transfer;
++				if (GET_CORE_IF(pcd)->dma_desc_enable) {
++					uint32_t out_max_xfer =
++					    DDMA_MAX_TRANSFER_SIZE -
++					    (DDMA_MAX_TRANSFER_SIZE % 4);
++					if (ep->dwc_ep.is_in) {
++						if (ep->dwc_ep.maxxfer >
++						    DDMA_MAX_TRANSFER_SIZE) {
++							ep->dwc_ep.maxxfer =
++							    DDMA_MAX_TRANSFER_SIZE;
++						}
++					} else {
++						if (ep->dwc_ep.maxxfer >
++						    out_max_xfer) {
++							ep->dwc_ep.maxxfer =
++							    out_max_xfer;
++						}
++					}
++				}
++				if (ep->dwc_ep.maxxfer < ep->dwc_ep.total_len) {
++					ep->dwc_ep.maxxfer -=
++					    (ep->dwc_ep.maxxfer %
++					     ep->dwc_ep.maxpacket);
++				}
++
++				if (zero) {
++					if ((ep->dwc_ep.total_len %
++					     ep->dwc_ep.maxpacket == 0)
++					    && (ep->dwc_ep.total_len != 0)) {
++						ep->dwc_ep.sent_zlp = 1;
++					}
++				}
++#ifdef DWC_UTE_CFI
++			}
++#endif
++			dwc_otg_ep_start_transfer(GET_CORE_IF(pcd),
++						  &ep->dwc_ep);
++		}
++	}
++
++	if (req != 0) {
++		++pcd->request_pending;
++		DWC_CIRCLEQ_INSERT_TAIL(&ep->queue, req, queue_entry);
++		if (ep->dwc_ep.is_in && ep->stopped
++		    && !(GET_CORE_IF(pcd)->dma_enable)) {
++			/** @todo NGS Create a function for this. */
++			diepmsk_data_t diepmsk = {.d32 = 0 };
++			diepmsk.b.intktxfemp = 1;
++			if (GET_CORE_IF(pcd)->multiproc_int_enable) {
++				DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->
++						 dev_if->dev_global_regs->diepeachintmsk
++						 [ep->dwc_ep.num], 0,
++						 diepmsk.d32);
++			} else {
++				DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->
++						 dev_if->dev_global_regs->
++						 diepmsk, 0, diepmsk.d32);
++			}
++
++		}
++	}
++	DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
++
++	return 0;
++}
++
++int dwc_otg_pcd_ep_dequeue(dwc_otg_pcd_t * pcd, void *ep_handle,
++			   void *req_handle)
++{
++	dwc_irqflags_t flags;
++	dwc_otg_pcd_request_t *req;
++	dwc_otg_pcd_ep_t *ep;
++
++	ep = get_ep_from_handle(pcd, ep_handle);
++	if (!ep || (!ep->desc && ep->dwc_ep.num != 0)) {
++		DWC_WARN("bad argument\n");
++		return -DWC_E_INVALID;
++	}
++
++	DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
++
++	/* make sure it's actually queued on this endpoint */
++	DWC_CIRCLEQ_FOREACH(req, &ep->queue, queue_entry) {
++		if (req->priv == (void *)req_handle) {
++			break;
++		}
++	}
++
++	if (req->priv != (void *)req_handle) {
++		DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
++		return -DWC_E_INVALID;
++	}
++
++	if (!DWC_CIRCLEQ_EMPTY_ENTRY(req, queue_entry)) {
++		if(( ep != &pcd->ep0)&&(!ep->dwc_ep.is_in)) {
++			ep->dwc_ep.xfer_buff =NULL;
++		}
++		dwc_otg_request_done(ep, req, -DWC_E_RESTART);
++	} else {
++		req = NULL;
++	}
++
++	DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
++
++	return req ? 0 : -DWC_E_SHUTDOWN;
++
++}
++
++int dwc_otg_pcd_ep_halt(dwc_otg_pcd_t * pcd, void *ep_handle, int value)
++{
++	dwc_otg_pcd_ep_t *ep;
++	dwc_irqflags_t flags;
++	int retval = 0;
++
++	ep = get_ep_from_handle(pcd, ep_handle);
++
++	if (!ep || (!ep->desc && ep != &pcd->ep0) ||
++	    (ep->desc && (ep->desc->bmAttributes == UE_ISOCHRONOUS))) {
++		DWC_WARN("%s, bad ep\n", __func__);
++		return -DWC_E_INVALID;
++	}
++
++	DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
++	if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
++		DWC_WARN("%d %s XFer In process\n", ep->dwc_ep.num,
++			 ep->dwc_ep.is_in ? "IN" : "OUT");
++		retval = -DWC_E_AGAIN;
++	} else if (value == 0) {
++	    ep->dwc_ep.stall_clear_flag = 0;
++		dwc_otg_ep_clear_stall(GET_CORE_IF(pcd), &ep->dwc_ep);
++	} else if (value == 1) {
++	stall:
++		if (ep->dwc_ep.is_in == 1 && GET_CORE_IF(pcd)->dma_desc_enable) {
++			dtxfsts_data_t txstatus;
++			fifosize_data_t txfifosize;
++
++			txfifosize.d32 =
++			    DWC_READ_REG32(&GET_CORE_IF(pcd)->
++					   core_global_regs->dtxfsiz[ep->dwc_ep.
++								     tx_fifo_num]);
++			txstatus.d32 =
++			    DWC_READ_REG32(&GET_CORE_IF(pcd)->
++					   dev_if->in_ep_regs[ep->dwc_ep.num]->
++					   dtxfsts);
++
++			if (txstatus.b.txfspcavail < txfifosize.b.depth) {
++				retval = -DWC_E_AGAIN;
++			} else {
++				if (ep->dwc_ep.num == 0) {
++					pcd->ep0state = EP0_STALL;
++				}
++
++				ep->stopped = 1;
++				dwc_otg_ep_set_stall(GET_CORE_IF(pcd),
++						     &ep->dwc_ep);
++			}
++		} else {
++			if (ep->dwc_ep.num == 0) {
++				pcd->ep0state = EP0_STALL;
++			}
++
++			ep->stopped = 1;
++			dwc_otg_ep_set_stall(GET_CORE_IF(pcd), &ep->dwc_ep);
++		}
++	} else if (value == 2) {
++		ep->dwc_ep.stall_clear_flag = 0;
++	} else if (value == 3) {
++		ep->dwc_ep.stall_clear_flag = 1;
++		goto stall;
++	}
++
++	DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
++
++	return retval;
++}
++
++/**
++ * This function initiates remote wakeup of the host from suspend state.
++ */
++void dwc_otg_pcd_rem_wkup_from_suspend(dwc_otg_pcd_t * pcd, int set)
++{
++	dctl_data_t dctl = { 0 };
++	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
++	dsts_data_t dsts;
++
++	dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
++	if (!dsts.b.suspsts) {
++		DWC_WARN("Remote wakeup while is not in suspend state\n");
++	}
++	/* Check if DEVICE_REMOTE_WAKEUP feature enabled */
++	if (pcd->remote_wakeup_enable) {
++		if (set) {
++
++			if (core_if->adp_enable) {
++				gpwrdn_data_t gpwrdn;
++
++				dwc_otg_adp_probe_stop(core_if);
++
++				/* Mask SRP detected interrupt from Power Down Logic */
++				gpwrdn.d32 = 0;
++				gpwrdn.b.srp_det_msk = 1;
++				DWC_MODIFY_REG32(&core_if->
++						 core_global_regs->gpwrdn,
++						 gpwrdn.d32, 0);
++
++				/* Disable Power Down Logic */
++				gpwrdn.d32 = 0;
++				gpwrdn.b.pmuactv = 1;
++				DWC_MODIFY_REG32(&core_if->
++						 core_global_regs->gpwrdn,
++						 gpwrdn.d32, 0);
++
++				/*
++				 * Initialize the Core for Device mode.
++				 */
++				core_if->op_state = B_PERIPHERAL;
++				dwc_otg_core_init(core_if);
++				dwc_otg_enable_global_interrupts(core_if);
++				cil_pcd_start(core_if);
++
++				dwc_otg_initiate_srp(core_if);
++			}
++
++			dctl.b.rmtwkupsig = 1;
++			DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
++					 dctl, 0, dctl.d32);
++			DWC_DEBUGPL(DBG_PCD, "Set Remote Wakeup\n");
++
++			dwc_mdelay(2);
++			DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
++					 dctl, dctl.d32, 0);
++			DWC_DEBUGPL(DBG_PCD, "Clear Remote Wakeup\n");
++		}
++	} else {
++		DWC_DEBUGPL(DBG_PCD, "Remote Wakeup is disabled\n");
++	}
++}
++
++#ifdef CONFIG_USB_DWC_OTG_LPM
++/**
++ * This function initiates remote wakeup of the host from L1 sleep state.
++ */
++void dwc_otg_pcd_rem_wkup_from_sleep(dwc_otg_pcd_t * pcd, int set)
++{
++	glpmcfg_data_t lpmcfg;
++	pcgcctl_data_t pcgcctl = {.d32 = 0 };
++
++	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
++
++	lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
++
++	/* Check if we are in L1 state */
++	if (!lpmcfg.b.prt_sleep_sts) {
++		DWC_DEBUGPL(DBG_PCD, "Device is not in sleep state\n");
++		return;
++	}
++
++	/* Check if host allows remote wakeup */
++	if (!lpmcfg.b.rem_wkup_en) {
++		DWC_DEBUGPL(DBG_PCD, "Host does not allow remote wakeup\n");
++		return;
++	}
++
++	/* Check if Resume OK */
++	if (!lpmcfg.b.sleep_state_resumeok) {
++		DWC_DEBUGPL(DBG_PCD, "Sleep state resume is not OK\n");
++		return;
++	}
++
++	lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
++	lpmcfg.b.en_utmi_sleep = 0;
++	lpmcfg.b.hird_thres &= (~(1 << 4));
++
++	/* Clear Enbl_L1Gating bit. */
++	pcgcctl.b.enbl_sleep_gating = 1;
++	DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32,0);
++
++	DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg, lpmcfg.d32);
++
++	if (set) {
++		dctl_data_t dctl = {.d32 = 0 };
++		dctl.b.rmtwkupsig = 1;
++		/* Set RmtWkUpSig bit to start remote wakup signaling.
++		 * Hardware will automatically clear this bit.
++		 */
++		DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl,
++				 0, dctl.d32);
++		DWC_DEBUGPL(DBG_PCD, "Set Remote Wakeup\n");
++	}
++
++}
++#endif
++
++/**
++ * Performs remote wakeup.
++ */
++void dwc_otg_pcd_remote_wakeup(dwc_otg_pcd_t * pcd, int set)
++{
++	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
++	dwc_irqflags_t flags;
++	if (dwc_otg_is_device_mode(core_if)) {
++		DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
++#ifdef CONFIG_USB_DWC_OTG_LPM
++		if (core_if->lx_state == DWC_OTG_L1) {
++			dwc_otg_pcd_rem_wkup_from_sleep(pcd, set);
++		} else {
++#endif
++			dwc_otg_pcd_rem_wkup_from_suspend(pcd, set);
++#ifdef CONFIG_USB_DWC_OTG_LPM
++		}
++#endif
++		DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
++	}
++	return;
++}
++
++void dwc_otg_pcd_disconnect_us(dwc_otg_pcd_t * pcd, int no_of_usecs)
++{
++	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
++	dctl_data_t dctl = { 0 };
++
++	if (dwc_otg_is_device_mode(core_if)) {
++		dctl.b.sftdiscon = 1;
++		DWC_PRINTF("Soft disconnect for %d useconds\n",no_of_usecs);
++		DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0, dctl.d32);
++		dwc_udelay(no_of_usecs);
++		DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32,0);
++
++	} else{
++		DWC_PRINTF("NOT SUPPORTED IN HOST MODE\n");
++	}
++	return;
++
++}
++
++int dwc_otg_pcd_wakeup(dwc_otg_pcd_t * pcd)
++{
++	dsts_data_t dsts;
++	gotgctl_data_t gotgctl;
++
++	/*
++	 * This function starts the Protocol if no session is in progress. If
++	 * a session is already in progress, but the device is suspended,
++	 * remote wakeup signaling is started.
++	 */
++
++	/* Check if valid session */
++	gotgctl.d32 =
++	    DWC_READ_REG32(&(GET_CORE_IF(pcd)->core_global_regs->gotgctl));
++	if (gotgctl.b.bsesvld) {
++		/* Check if suspend state */
++		dsts.d32 =
++		    DWC_READ_REG32(&
++				   (GET_CORE_IF(pcd)->dev_if->
++				    dev_global_regs->dsts));
++		if (dsts.b.suspsts) {
++			dwc_otg_pcd_remote_wakeup(pcd, 1);
++		}
++	} else {
++		dwc_otg_pcd_initiate_srp(pcd);
++	}
++
++	return 0;
++
++}
++
++void dwc_otg_pcd_pullup(dwc_otg_pcd_t *pcd)
++{
++	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
++	dwc_otg_dev_if_t *dev_if = core_if->dev_if;
++	depctl_data_t depctl;
++
++	depctl.d32 = 0;
++	depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[bulk_num]->diepctl);
++
++	depctl.b.setd1pid = 0;
++	depctl.b.setd0pid = 1;
++	DWC_WRITE_REG32(&dev_if->in_ep_regs[bulk_num]->diepctl, depctl.d32);
++	depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[3]->diepctl);
++}
++
++/**
++ * Start the SRP timer to detect when the SRP does not complete within
++ * 6 seconds.
++ *
++ * @param pcd the pcd structure.
++ */
++void dwc_otg_pcd_initiate_srp(dwc_otg_pcd_t * pcd)
++{
++	dwc_irqflags_t flags;
++	DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
++	dwc_otg_initiate_srp(GET_CORE_IF(pcd));
++	DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
++}
++
++int dwc_otg_pcd_get_frame_number(dwc_otg_pcd_t * pcd)
++{
++	return dwc_otg_get_frame_number(GET_CORE_IF(pcd));
++}
++
++int dwc_otg_pcd_is_lpm_enabled(dwc_otg_pcd_t * pcd)
++{
++	return GET_CORE_IF(pcd)->core_params->lpm_enable;
++}
++
++int dwc_otg_pcd_is_besl_enabled(dwc_otg_pcd_t * pcd)
++{
++	return GET_CORE_IF(pcd)->core_params->besl_enable;
++}
++
++int dwc_otg_pcd_get_param_baseline_besl(dwc_otg_pcd_t * pcd)
++{
++	return GET_CORE_IF(pcd)->core_params->baseline_besl;
++}
++
++int dwc_otg_pcd_get_param_deep_besl(dwc_otg_pcd_t * pcd)
++{
++	return GET_CORE_IF(pcd)->core_params->deep_besl;
++}
++
++uint32_t get_b_hnp_enable(dwc_otg_pcd_t * pcd)
++{
++	return pcd->b_hnp_enable;
++}
++
++uint32_t get_a_hnp_support(dwc_otg_pcd_t * pcd)
++{
++	return pcd->a_hnp_support;
++}
++
++uint32_t get_a_alt_hnp_support(dwc_otg_pcd_t * pcd)
++{
++	return pcd->a_alt_hnp_support;
++}
++
++int dwc_otg_pcd_get_rmwkup_enable(dwc_otg_pcd_t * pcd)
++{
++	return pcd->remote_wakeup_enable;
++}
++
++#endif /* DWC_HOST_ONLY */
+diff --git a/drivers/usb/gadget/udc/hiudc/dwc_otg_pcd.h b/drivers/usb/gadget/udc/hiudc/dwc_otg_pcd.h
+new file mode 100644
+index 0000000..54ced23
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc/dwc_otg_pcd.h
+@@ -0,0 +1,268 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd.h $
++ * $Revision: #49 $
++ * $Date: 2013/05/16 $
++ * $Change: 2231774 $
++ *
++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
++ * ========================================================================== */
++#ifndef DWC_HOST_ONLY
++#if !defined(__DWC_PCD_H__)
++#define __DWC_PCD_H__
++
++#include "dwc_otg_os_dep.h"
++#include "usb.h"
++#include "dwc_otg_cil.h"
++#include "dwc_otg_pcd_if.h"
++struct cfiobject;
++
++/**
++ * @file
++ *
++ * This file contains the structures, constants, and interfaces for
++ * the Perpherial Contoller Driver (PCD).
++ *
++ * The Peripheral Controller Driver (PCD) for Linux will implement the
++ * Gadget API, so that the existing Gadget drivers can be used. For
++ * the Mass Storage Function driver the File-backed USB Storage Gadget
++ * (FBS) driver will be used.  The FBS driver supports the
++ * Control-Bulk (CB), Control-Bulk-Interrupt (CBI), and Bulk-Only
++ * transports.
++ *
++ */
++
++/** Invalid DMA Address */
++#define DWC_DMA_ADDR_INVALID	(~(dwc_dma_t)0)
++
++/** Max Transfer size for any EP */
++#define DDMA_MAX_TRANSFER_SIZE 65535
++
++/**
++ * Get the pointer to the core_if from the pcd pointer.
++ */
++#define GET_CORE_IF( _pcd ) (_pcd->core_if)
++
++/**
++ * States of EP0.
++ */
++typedef enum ep0_state {
++	EP0_DISCONNECT,		/* no host */
++	EP0_IDLE,
++	EP0_IN_DATA_PHASE,
++	EP0_OUT_DATA_PHASE,
++	EP0_IN_STATUS_PHASE,
++	EP0_OUT_STATUS_PHASE,
++	EP0_STALL,
++} ep0state_e;
++
++/** Fordward declaration.*/
++struct dwc_otg_pcd;
++
++/** DWC_otg iso request structure.
++ *
++ */
++typedef struct usb_iso_request dwc_otg_pcd_iso_request_t;
++
++#ifdef DWC_UTE_PER_IO
++
++/**
++ * This shall be the exact analogy of the same type structure defined in the
++ * usb_gadget.h. Each descriptor contains
++ */
++struct dwc_iso_pkt_desc_port {
++	uint32_t offset;
++	uint32_t length;	/* expected length */
++	uint32_t actual_length;
++	uint32_t status;
++};
++
++struct dwc_iso_xreq_port {
++	/** transfer/submission flag */
++	uint32_t tr_sub_flags;
++	/** Start the request ASAP */
++#define DWC_EREQ_TF_ASAP		0x00000002
++	/** Just enqueue the request w/o initiating a transfer */
++#define DWC_EREQ_TF_ENQUEUE		0x00000004
++
++	/**
++	* count of ISO packets attached to this request - shall
++	* not exceed the pio_alloc_pkt_count
++	*/
++	uint32_t pio_pkt_count;
++	/** count of ISO packets allocated for this request */
++	uint32_t pio_alloc_pkt_count;
++	/** number of ISO packet errors */
++	uint32_t error_count;
++	/** reserved for future extension */
++	uint32_t res;
++	/** Will be allocated and freed in the UTE gadget and based on the CFC value */
++	struct dwc_iso_pkt_desc_port *per_io_frame_descs;
++};
++#endif
++/** DWC_otg request structure.
++ * This structure is a list of requests.
++ */
++typedef struct dwc_otg_pcd_request {
++	void *priv;
++	void *buf;
++	dwc_dma_t dma;
++	uint32_t length;
++	uint32_t actual;
++	unsigned sent_zlp:1;
++    /**
++     * Used instead of original buffer if
++     * it(physical address) is not dword-aligned.
++     **/
++	uint8_t *dw_align_buf;
++	dwc_dma_t dw_align_buf_dma;
++
++	 DWC_CIRCLEQ_ENTRY(dwc_otg_pcd_request) queue_entry;
++#ifdef DWC_UTE_PER_IO
++	struct dwc_iso_xreq_port ext_req;
++	//void *priv_ereq_nport; /*  */
++#endif
++} dwc_otg_pcd_request_t;
++
++DWC_CIRCLEQ_HEAD(req_list, dwc_otg_pcd_request);
++
++/**	  PCD EP structure.
++ * This structure describes an EP, there is an array of EPs in the PCD
++ * structure.
++ */
++typedef struct dwc_otg_pcd_ep {
++	/** USB EP Descriptor */
++	const usb_endpoint_descriptor_t *desc;
++
++	/** queue of dwc_otg_pcd_requests. */
++	struct req_list queue;
++	unsigned stopped:1;
++	unsigned disabling:1;
++	unsigned dma:1;
++	unsigned queue_sof:1;
++
++#ifdef DWC_EN_ISOC
++	/** ISOC req handle passed */
++	void *iso_req_handle;
++#endif				//_EN_ISOC_
++
++	/** DWC_otg ep data. */
++	dwc_ep_t dwc_ep;
++
++	/** Pointer to PCD */
++	struct dwc_otg_pcd *pcd;
++
++	void *priv;
++} dwc_otg_pcd_ep_t;
++
++/** DWC_otg PCD Structure.
++ * This structure encapsulates the data for the dwc_otg PCD.
++ */
++struct dwc_otg_pcd {
++	const struct dwc_otg_pcd_function_ops *fops;
++	/** The DWC otg device pointer */
++	struct dwc_otg_device *otg_dev;
++	/** Core Interface */
++	dwc_otg_core_if_t *core_if;
++	/** State of EP0 */
++	ep0state_e ep0state;
++	/** EP0 Request is pending */
++	unsigned ep0_pending:1;
++	/** Indicates when SET CONFIGURATION Request is in process */
++	unsigned request_config:1;
++	/** The state of the Remote Wakeup Enable. */
++	unsigned remote_wakeup_enable:1;
++	/** The state of the B-Device HNP Enable. */
++	unsigned b_hnp_enable:1;
++	/** The state of A-Device HNP Support. */
++	unsigned a_hnp_support:1;
++	/** The state of the A-Device Alt HNP support. */
++	unsigned a_alt_hnp_support:1;
++	/** Count of pending Requests */
++	unsigned request_pending;
++
++	/** SETUP packet for EP0
++	 * This structure is allocated as a DMA buffer on PCD initialization
++	 * with enough space for up to 3 setup packets.
++	 */
++	union {
++		usb_device_request_t req;
++		uint32_t d32[2];
++	} *setup_pkt;
++
++	dwc_dma_t setup_pkt_dma_handle;
++
++	/* Additional buffer and flag for CTRL_WR premature case */
++	uint8_t *backup_buf;
++	unsigned data_terminated;
++
++	/** 2-byte dma buffer used to return status from GET_STATUS */
++	uint16_t *status_buf;
++	dwc_dma_t status_buf_dma_handle;
++
++	/** EP0 */
++	dwc_otg_pcd_ep_t ep0;
++
++	/** Array of IN EPs. */
++	dwc_otg_pcd_ep_t in_ep[MAX_EPS_CHANNELS - 1];
++	/** Array of OUT EPs. */
++	dwc_otg_pcd_ep_t out_ep[MAX_EPS_CHANNELS - 1];
++	/** number of valid EPs in the above array. */
++//        unsigned      num_eps : 4;
++	dwc_spinlock_t *lock;
++
++	/** Tasklet to defer starting of TEST mode transmissions until
++	 *	Status Phase has been completed.
++	 */
++	dwc_tasklet_t *test_mode_tasklet;
++
++	/** Tasklet to delay starting of xfer in DMA mode */
++	dwc_tasklet_t *start_xfer_tasklet;
++
++	/** The test mode to enter when the tasklet is executed. */
++	unsigned test_mode;
++	/** The cfi_api structure that implements most of the CFI API
++	 * and OTG specific core configuration functionality
++	 */
++#ifdef DWC_UTE_CFI
++	struct cfiobject *cfi;
++#endif
++
++};
++
++//FIXME this functions should be static, and this prototypes should be removed
++extern void dwc_otg_request_nuke(dwc_otg_pcd_ep_t * ep);
++extern void dwc_otg_request_done(dwc_otg_pcd_ep_t * ep,
++				dwc_otg_pcd_request_t * req, int32_t status);
++
++void dwc_otg_iso_buffer_done(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * ep,
++			    void *req_handle);
++extern void dwc_otg_pcd_start_iso_ddma(dwc_otg_core_if_t * core_if,
++				dwc_otg_pcd_ep_t * ep);
++
++extern void do_test_mode(void *data);
++#endif
++#endif /* DWC_HOST_ONLY */
+diff --git a/drivers/usb/gadget/udc/hiudc/dwc_otg_pcd_if.h b/drivers/usb/gadget/udc/hiudc/dwc_otg_pcd_if.h
+new file mode 100644
+index 0000000..6cd75fa
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc/dwc_otg_pcd_if.h
+@@ -0,0 +1,368 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd_if.h $
++ * $Revision: #13 $
++ * $Date: 2012/12/12 $
++ * $Change: 2125019 $
++ *
++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
++ * ========================================================================== */
++#ifndef DWC_HOST_ONLY
++
++#if !defined(__DWC_PCD_IF_H__)
++#define __DWC_PCD_IF_H__
++
++//#include "dwc_os.h"
++#include "dwc_otg_core_if.h"
++
++/** @file
++ * This file defines DWC_OTG PCD Core API.
++ */
++
++struct dwc_otg_pcd;
++typedef struct dwc_otg_pcd dwc_otg_pcd_t;
++
++/** Maxpacket size for EP0 */
++#define MAX_EP0_SIZE	64
++/** Maxpacket size for any EP */
++#define MAX_PACKET_SIZE 1024
++
++/** @name Function Driver Callbacks */
++/** @{ */
++
++/** This function will be called whenever a previously queued request has
++ * completed.  The status value will be set to -DWC_E_SHUTDOWN to indicated a
++ * failed or aborted transfer, or -DWC_E_RESTART to indicate the device was reset,
++ * or -DWC_E_TIMEOUT to indicate it timed out, or -DWC_E_INVALID to indicate invalid
++ * parameters. */
++typedef int (*dwc_completion_cb_t) (dwc_otg_pcd_t * pcd, void *ep_handle,
++				    void *req_handle, int32_t status,
++				    uint32_t actual);
++/**
++ * This function will be called whenever a previousle queued ISOC request has
++ * completed. Count of ISOC packets could be read using dwc_otg_pcd_get_iso_packet_count
++ * function.
++ * The status of each ISOC packet could be read using dwc_otg_pcd_get_iso_packet_*
++ * functions.
++ */
++typedef int (*dwc_isoc_completion_cb_t) (dwc_otg_pcd_t * pcd, void *ep_handle,
++					 void *req_handle, int proc_buf_num);
++/** This function should handle any SETUP request that cannot be handled by the
++ * PCD Core.  This includes most GET_DESCRIPTORs, SET_CONFIGS, Any
++ * class-specific requests, etc.  The function must non-blocking.
++ *
++ * Returns 0 on success.
++ * Returns -DWC_E_NOT_SUPPORTED if the request is not supported.
++ * Returns -DWC_E_INVALID if the setup request had invalid parameters or bytes.
++ * Returns -DWC_E_SHUTDOWN on any other error. */
++typedef int (*dwc_setup_cb_t) (dwc_otg_pcd_t * pcd, uint8_t * bytes);
++/** This is called whenever the device has been disconnected.  The function
++ * driver should take appropriate action to clean up all pending requests in the
++ * PCD Core, remove all endpoints (except ep0), and initialize back to reset
++ * state. */
++typedef int (*dwc_disconnect_cb_t) (dwc_otg_pcd_t * pcd);
++/** This function is called when device has been connected. */
++typedef int (*dwc_connect_cb_t) (dwc_otg_pcd_t * pcd, int speed);
++/** This function is called when device has been suspended */
++typedef int (*dwc_suspend_cb_t) (dwc_otg_pcd_t * pcd);
++/** This function is called when device has received LPM tokens, i.e.
++ * device has been sent to sleep state. */
++typedef int (*dwc_sleep_cb_t) (dwc_otg_pcd_t * pcd);
++/** This function is called when device has been resumed
++ * from suspend(L2) or L1 sleep state. */
++typedef int (*dwc_resume_cb_t) (dwc_otg_pcd_t * pcd);
++/** This function is called whenever hnp params has been changed.
++ * User can call get_b_hnp_enable, get_a_hnp_support, get_a_alt_hnp_support functions
++ * to get hnp parameters. */
++typedef int (*dwc_hnp_params_changed_cb_t) (dwc_otg_pcd_t * pcd);
++/** This function is called whenever USB RESET is detected. */
++typedef int (*dwc_reset_cb_t) (dwc_otg_pcd_t * pcd);
++
++typedef int (*cfi_setup_cb_t) (dwc_otg_pcd_t * pcd, void *ctrl_req_bytes);
++
++/**
++ *
++ * @param ep_handle	Void pointer to the usb_ep structure
++ * @param ereq_port Pointer to the extended request structure created in the
++ *					portable part.
++ */
++typedef int (*xiso_completion_cb_t) (dwc_otg_pcd_t * pcd, void *ep_handle,
++				     void *req_handle, int32_t status,
++				     void *ereq_port);
++/** Function Driver Ops Data Structure */
++struct dwc_otg_pcd_function_ops {
++	dwc_connect_cb_t connect;
++	dwc_disconnect_cb_t disconnect;
++	dwc_setup_cb_t setup;
++	dwc_completion_cb_t complete;
++	dwc_isoc_completion_cb_t isoc_complete;
++	dwc_suspend_cb_t suspend;
++	dwc_sleep_cb_t sleep;
++	dwc_resume_cb_t resume;
++	dwc_reset_cb_t reset;
++	dwc_hnp_params_changed_cb_t hnp_changed;
++	cfi_setup_cb_t cfi_setup;
++#ifdef DWC_UTE_PER_IO
++	xiso_completion_cb_t xisoc_complete;
++#endif
++};
++/** @} */
++
++/** @name Function Driver Functions */
++/** @{ */
++
++/** Call this function to get pointer on dwc_otg_pcd_t,
++ * this pointer will be used for all PCD API functions.
++ *
++ * @param core_if The DWC_OTG Core
++ */
++extern dwc_otg_pcd_t *dwc_otg_pcd_init(dwc_otg_core_if_t * core_if);
++
++/** Frees PCD allocated by dwc_otg_pcd_init
++ *
++ * @param pcd The PCD
++ */
++extern void dwc_otg_pcd_remove(dwc_otg_pcd_t * pcd);
++
++/** Call this to bind the function driver to the PCD Core.
++ *
++ * @param pcd Pointer on dwc_otg_pcd_t returned by dwc_otg_pcd_init function.
++ * @param fops The Function Driver Ops data structure containing pointers to all callbacks.
++ */
++extern void dwc_otg_pcd_start(dwc_otg_pcd_t * pcd,
++			      const struct dwc_otg_pcd_function_ops *fops);
++
++/** Enables an endpoint for use.  This function enables an endpoint in
++ * the PCD.  The endpoint is described by the ep_desc which has the
++ * same format as a USB ep descriptor.  The ep_handle parameter is used to refer
++ * to the endpoint from other API functions and in callbacks.  Normally this
++ * should be called after a SET_CONFIGURATION/SET_INTERFACE to configure the
++ * core for that interface.
++ *
++ * Returns -DWC_E_INVALID if invalid parameters were passed.
++ * Returns -DWC_E_SHUTDOWN if any other error ocurred.
++ * Returns 0 on success.
++ *
++ * @param pcd The PCD
++ * @param ep_desc Endpoint descriptor
++ * @param ep_handle Handle on endpoint, that will be used to identify endpoint.
++ */
++extern int dwc_otg_pcd_ep_enable(dwc_otg_pcd_t * pcd,
++				 const uint8_t * ep_desc, void *ep_handle);
++
++/** Disable the endpoint referenced by ep_handle.
++ *
++ * Returns -DWC_E_INVALID if invalid parameters were passed.
++ * Returns -DWC_E_SHUTDOWN if any other error occurred.
++ * Returns 0 on success. */
++extern int dwc_otg_pcd_ep_disable(dwc_otg_pcd_t * pcd, void *ep_handle);
++
++/** Queue a data transfer request on the endpoint referenced by ep_handle.
++ * After the transfer is completes, the complete callback will be called with
++ * the request status.
++ *
++ * @param pcd The PCD
++ * @param ep_handle The handle of the endpoint
++ * @param buf The buffer for the data
++ * @param dma_buf The DMA buffer for the data
++ * @param buflen The length of the data transfer
++ * @param zero Specifies whether to send zero length last packet.
++ * @param req_handle Set this handle to any value to use to reference this
++ * request in the ep_dequeue function or from the complete callback
++ * @param atomic_alloc If driver need to perform atomic allocations
++ * for internal data structures.
++ *
++ * Returns -DWC_E_INVALID if invalid parameters were passed.
++ * Returns -DWC_E_SHUTDOWN if any other error ocurred.
++ * Returns 0 on success. */
++extern int dwc_otg_pcd_ep_queue(dwc_otg_pcd_t * pcd, void *ep_handle,
++				uint8_t * buf, dwc_dma_t dma_buf,
++				uint32_t buflen, int zero, void *req_handle,
++				int atomic_alloc);
++#ifdef DWC_UTE_PER_IO
++/**
++ *
++ * @param ereq_nonport	Pointer to the extended request part of the
++ *						usb_request structure defined in usb_gadget.h file.
++ */
++extern int dwc_otg_pcd_xiso_ep_queue(dwc_otg_pcd_t * pcd, void *ep_handle,
++				     uint8_t * buf, dwc_dma_t dma_buf,
++				     uint32_t buflen, int zero,
++				     void *req_handle, int atomic_alloc,
++				     void *ereq_nonport);
++
++#endif
++
++/** De-queue the specified data transfer that has not yet completed.
++ *
++ * Returns -DWC_E_INVALID if invalid parameters were passed.
++ * Returns -DWC_E_SHUTDOWN if any other error ocurred.
++ * Returns 0 on success. */
++extern int dwc_otg_pcd_ep_dequeue(dwc_otg_pcd_t * pcd, void *ep_handle,
++				  void *req_handle);
++
++/** Halt (STALL) an endpoint or clear it.
++ *
++ * Returns -DWC_E_INVALID if invalid parameters were passed.
++ * Returns -DWC_E_SHUTDOWN if any other error ocurred.
++ * Returns -DWC_E_AGAIN if the STALL cannot be sent and must be tried again later
++ * Returns 0 on success. */
++extern int dwc_otg_pcd_ep_halt(dwc_otg_pcd_t * pcd, void *ep_handle, int value);
++
++/** This function should be called on every hardware interrupt */
++extern int32_t dwc_otg_pcd_handle_intr(dwc_otg_pcd_t * pcd);
++
++/** This function returns current frame number */
++extern int dwc_otg_pcd_get_frame_number(dwc_otg_pcd_t * pcd);
++
++/**
++ * Start isochronous transfers on the endpoint referenced by ep_handle.
++ * For isochronous transfers duble buffering is used.
++ * After processing each of buffers comlete callback will be called with
++ * status for each transaction.
++ *
++ * @param pcd The PCD
++ * @param ep_handle The handle of the endpoint
++ * @param buf0 The virtual address of first data buffer
++ * @param buf1 The virtual address of second data buffer
++ * @param dma0 The DMA address of first data buffer
++ * @param dma1 The DMA address of second data buffer
++ * @param sync_frame Data pattern frame number
++ * @param dp_frame Data size for pattern frame
++ * @param data_per_frame Data size for regular frame
++ * @param start_frame Frame number to start transfers, if -1 then start transfers ASAP.
++ * @param buf_proc_intrvl Interval of ISOC Buffer processing
++ * @param req_handle Handle of ISOC request
++ * @param atomic_alloc Specefies whether to perform atomic allocation for
++ *			internal data structures.
++ *
++ * Returns -DWC_E_NO_MEMORY if there is no enough memory.
++ * Returns -DWC_E_INVALID if incorrect arguments are passed to the function.
++ * Returns -DW_E_SHUTDOWN for any other error.
++ * Returns 0 on success
++ */
++extern int dwc_otg_pcd_iso_ep_start(dwc_otg_pcd_t * pcd, void *ep_handle,
++				    uint8_t * buf0, uint8_t * buf1,
++				    dwc_dma_t dma0, dwc_dma_t dma1,
++				    int sync_frame, int dp_frame,
++				    int data_per_frame, int start_frame,
++				    int buf_proc_intrvl, void *req_handle,
++				    int atomic_alloc);
++
++/** Stop ISOC transfers on endpoint referenced by ep_handle.
++ *
++ * @param pcd The PCD
++ * @param ep_handle The handle of the endpoint
++ * @param req_handle Handle of ISOC request
++ *
++ * Returns -DWC_E_INVALID if incorrect arguments are passed to the function
++ * Returns 0 on success
++ */
++int dwc_otg_pcd_iso_ep_stop(dwc_otg_pcd_t * pcd, void *ep_handle,
++			    void *req_handle);
++
++/** Get ISOC packet status.
++ *
++ * @param pcd The PCD
++ * @param ep_handle The handle of the endpoint
++ * @param iso_req_handle Isochronoush request handle
++ * @param packet Number of packet
++ * @param status Out parameter for returning status
++ * @param actual Out parameter for returning actual length
++ * @param offset Out parameter for returning offset
++ *
++ */
++extern void dwc_otg_pcd_get_iso_packet_params(dwc_otg_pcd_t * pcd,
++					      void *ep_handle,
++					      void *iso_req_handle, int packet,
++					      int *status, int *actual,
++					      int *offset);
++
++/** Get ISOC packet count.
++ *
++ * @param pcd The PCD
++ * @param ep_handle The handle of the endpoint
++ * @param iso_req_handle
++ */
++extern int dwc_otg_pcd_get_iso_packet_count(dwc_otg_pcd_t * pcd,
++					    void *ep_handle,
++					    void *iso_req_handle);
++
++/** This function starts the SRP Protocol if no session is in progress. If
++ * a session is already in progress, but the device is suspended,
++ * remote wakeup signaling is started.
++ */
++extern int dwc_otg_pcd_wakeup(dwc_otg_pcd_t * pcd);
++
++extern void dwc_otg_pcd_pullup(dwc_otg_pcd_t *pcd);
++
++/** This function returns 1 if LPM support is enabled, and 0 otherwise. */
++extern int dwc_otg_pcd_is_lpm_enabled(dwc_otg_pcd_t * pcd);
++
++/** This function returns 1 if LPM Errata support is enabled, and 0 otherwise. */
++extern int dwc_otg_pcd_is_besl_enabled(dwc_otg_pcd_t * pcd);
++
++/** This function returns baseline_besl module parametr. */
++extern int dwc_otg_pcd_get_param_baseline_besl(dwc_otg_pcd_t * pcd);
++
++/** This function returns deep_besl module parametr. */
++extern int dwc_otg_pcd_get_param_deep_besl(dwc_otg_pcd_t * pcd);
++
++/** This function returns 1 if remote wakeup is allowed and 0, otherwise. */
++extern int dwc_otg_pcd_get_rmwkup_enable(dwc_otg_pcd_t * pcd);
++
++/** Initiate SRP */
++extern void dwc_otg_pcd_initiate_srp(dwc_otg_pcd_t * pcd);
++
++/** Starts remote wakeup signaling. */
++extern void dwc_otg_pcd_remote_wakeup(dwc_otg_pcd_t * pcd, int set);
++
++/** Starts micorsecond soft disconnect. */
++extern void dwc_otg_pcd_disconnect_us(dwc_otg_pcd_t * pcd, int no_of_usecs);
++/** This function returns whether device is dualspeed.*/
++extern uint32_t dwc_otg_pcd_is_dualspeed(dwc_otg_pcd_t * pcd);
++
++/** This function returns whether device is otg. */
++extern uint32_t dwc_otg_pcd_is_otg(dwc_otg_pcd_t * pcd);
++
++/** These functions allow to get hnp parameters */
++extern uint32_t get_b_hnp_enable(dwc_otg_pcd_t * pcd);
++extern uint32_t get_a_hnp_support(dwc_otg_pcd_t * pcd);
++extern uint32_t get_a_alt_hnp_support(dwc_otg_pcd_t * pcd);
++
++/** CFI specific Interface functions */
++/** Allocate a cfi buffer */
++extern uint8_t *cfiw_ep_alloc_buffer(dwc_otg_pcd_t * pcd, void *pep,
++				     dwc_dma_t * addr, size_t buflen,
++				     int flags);
++
++/******************************************************************************/
++
++/** @} */
++
++#endif				/* __DWC_PCD_IF_H__ */
++
++#endif				/* DWC_HOST_ONLY */
+diff --git a/drivers/usb/gadget/udc/hiudc/dwc_otg_pcd_intr.c b/drivers/usb/gadget/udc/hiudc/dwc_otg_pcd_intr.c
+new file mode 100644
+index 0000000..9a151e0
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc/dwc_otg_pcd_intr.c
+@@ -0,0 +1,5463 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd_intr.c $
++ * $Revision: #125 $
++ * $Date: 2013/05/20 $
++ * $Change: 2234037 $
++ *
++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
++ * ========================================================================== */
++#ifndef DWC_HOST_ONLY
++
++#include "dwc_otg_pcd.h"
++
++#ifdef DWC_UTE_CFI
++#include "dwc_otg_cfi.h"
++#endif
++
++//#include <linux/hisilicon/hiotg.h>
++
++#ifdef DWC_UTE_PER_IO
++extern void complete_xiso_ep(dwc_otg_pcd_ep_t * ep);
++#endif
++//#define PRINT_CFI_DMA_DESCS
++
++#define DEBUG_EP0
++
++/* avoid null point */
++uint8_t readpacket_buf[1024];
++
++/**
++ * This function updates OTG.
++ */
++extern int  otg_usbhost_stat;
++extern void hisi_switch_func(int otg);
++static void dwc_otg_pcd_update_otg(dwc_otg_pcd_t * pcd, const unsigned reset)
++{
++
++	if (reset) {
++		pcd->b_hnp_enable = 0;
++		pcd->a_hnp_support = 0;
++		pcd->a_alt_hnp_support = 0;
++	}
++
++	if (pcd->fops->hnp_changed) {
++		pcd->fops->hnp_changed(pcd);
++	}
++}
++
++/** @file
++ * This file contains the implementation of the PCD Interrupt handlers.
++ *
++ * The PCD handles the device interrupts.  Many conditions can cause a
++ * device interrupt. When an interrupt occurs, the device interrupt
++ * service routine determines the cause of the interrupt and
++ * dispatches handling to the appropriate function. These interrupt
++ * handling functions are described below.
++ * All interrupt registers are processed from LSB to MSB.
++ */
++
++/**
++ * This function prints the ep0 state for debug purposes.
++ */
++static inline void print_ep0_state(dwc_otg_pcd_t * pcd)
++{
++#ifdef DEBUG
++	char str[40];
++
++	switch (pcd->ep0state) {
++	case EP0_DISCONNECT:
++		dwc_strcpy(str, "EP0_DISCONNECT");
++		break;
++	case EP0_IDLE:
++		dwc_strcpy(str, "EP0_IDLE");
++		break;
++	case EP0_IN_DATA_PHASE:
++		dwc_strcpy(str, "EP0_IN_DATA_PHASE");
++		break;
++	case EP0_OUT_DATA_PHASE:
++		dwc_strcpy(str, "EP0_OUT_DATA_PHASE");
++		break;
++	case EP0_IN_STATUS_PHASE:
++		dwc_strcpy(str, "EP0_IN_STATUS_PHASE");
++		break;
++	case EP0_OUT_STATUS_PHASE:
++		dwc_strcpy(str, "EP0_OUT_STATUS_PHASE");
++		break;
++	case EP0_STALL:
++		dwc_strcpy(str, "EP0_STALL");
++		break;
++	default:
++		dwc_strcpy(str, "EP0_INVALID");
++	}
++
++	DWC_DEBUGPL(DBG_ANY, "%s(%d)\n", str, pcd->ep0state);
++#endif
++}
++
++/**
++ * This function calculate the size of the payload in the memory
++ * for out endpoints and prints size for debug purposes(used in
++ * 2.93a DevOutNak feature).
++ */
++static inline void print_memory_payload(dwc_otg_pcd_t * pcd,  dwc_ep_t * ep)
++{
++#ifdef DEBUG
++	deptsiz_data_t deptsiz_init = {.d32 = 0 };
++	deptsiz_data_t deptsiz_updt = {.d32 = 0 };
++	int pack_num;
++	unsigned payload;
++
++	deptsiz_init.d32 = pcd->core_if->start_doeptsiz_val[ep->num];
++	deptsiz_updt.d32 =
++		DWC_READ_REG32(&pcd->core_if->dev_if->
++						out_ep_regs[ep->num]->doeptsiz);
++	/* Payload will be */
++	payload = deptsiz_init.b.xfersize - deptsiz_updt.b.xfersize;
++	/* Packet count is decremented every time a packet
++	 * is written to the RxFIFO not in to the external memory
++	 * So, if payload == 0, then it means no packet was sent to ext memory*/
++	pack_num = (!payload) ? 0 : (deptsiz_init.b.pktcnt - deptsiz_updt.b.pktcnt);
++	DWC_DEBUGPL(DBG_PCDV,
++		"Payload for EP%d-%s\n",
++		ep->num, (ep->is_in ? "IN" : "OUT"));
++	DWC_DEBUGPL(DBG_PCDV,
++		"Number of transfered bytes = 0x%08x\n", payload);
++	DWC_DEBUGPL(DBG_PCDV,
++		"Number of transfered packets = %d\n", pack_num);
++#endif
++}
++
++
++#ifdef DWC_UTE_CFI
++static inline void print_desc(struct dwc_otg_dma_desc *ddesc,
++			      const uint8_t * epname, int descnum)
++{
++	CFI_INFO
++	    ("%s DMA_DESC(%d) buf=0x%08x bytes=0x%04x; sp=0x%x; l=0x%x; sts=0x%02x; bs=0x%02x\n",
++	     epname, descnum, ddesc->buf, ddesc->status.b.bytes,
++	     ddesc->status.b.sp, ddesc->status.b.l, ddesc->status.b.sts,
++	     ddesc->status.b.bs);
++}
++#endif
++
++/**
++ * This function returns pointer to in ep struct with number ep_num
++ */
++static inline dwc_otg_pcd_ep_t *get_in_ep(dwc_otg_pcd_t * pcd, uint32_t ep_num)
++{
++	int i;
++	int num_in_eps = GET_CORE_IF(pcd)->dev_if->num_in_eps;
++	if (ep_num == 0) {
++		return &pcd->ep0;
++	} else {
++		for (i = 0; i < num_in_eps; ++i) {
++			if (pcd->in_ep[i].dwc_ep.num == ep_num)
++				return &pcd->in_ep[i];
++		}
++		return 0;
++	}
++}
++
++/**
++ * This function returns pointer to out ep struct with number ep_num
++ */
++static inline dwc_otg_pcd_ep_t *get_out_ep(dwc_otg_pcd_t * pcd, uint32_t ep_num)
++{
++	int i;
++	int num_out_eps = GET_CORE_IF(pcd)->dev_if->num_out_eps;
++	if (ep_num == 0) {
++		return &pcd->ep0;
++	} else {
++		for (i = 0; i < num_out_eps; ++i) {
++			if (pcd->out_ep[i].dwc_ep.num == ep_num)
++				return &pcd->out_ep[i];
++		}
++		return 0;
++	}
++}
++
++/**
++ * This functions gets a pointer to an EP from the wIndex address
++ * value of the control request.
++ */
++dwc_otg_pcd_ep_t *get_ep_by_addr(dwc_otg_pcd_t * pcd, u16 wIndex)
++{
++	dwc_otg_pcd_ep_t *ep;
++	uint32_t ep_num = UE_GET_ADDR(wIndex);
++
++	if (ep_num == 0) {
++		ep = &pcd->ep0;
++	} else if (UE_GET_DIR(wIndex) == UE_DIR_IN) {	/* in ep */
++		ep = &pcd->in_ep[ep_num - 1];
++	} else {
++		ep = &pcd->out_ep[ep_num - 1];
++	}
++
++	return ep;
++}
++
++/**
++ * This function checks the EP request queue, if the queue is not
++ * empty the next request is started.
++ */
++void start_next_request(dwc_otg_pcd_ep_t * ep)
++{
++	dwc_otg_pcd_request_t *req = 0;
++	uint32_t max_transfer =
++	    GET_CORE_IF(ep->pcd)->core_params->max_transfer_size;
++
++#ifdef DWC_UTE_CFI
++	struct dwc_otg_pcd *pcd;
++	pcd = ep->pcd;
++#endif
++
++	if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
++		req = DWC_CIRCLEQ_FIRST(&ep->queue);
++
++#ifdef DWC_UTE_CFI
++		if (ep->dwc_ep.buff_mode != BM_STANDARD) {
++			ep->dwc_ep.cfi_req_len = req->length;
++			pcd->cfi->ops.build_descriptors(pcd->cfi, pcd, ep, req);
++		} else {
++#endif
++			/* Setup and start the Transfer */
++			if (req->dw_align_buf) {
++				ep->dwc_ep.dma_addr = req->dw_align_buf_dma;
++				ep->dwc_ep.start_xfer_buff = req->dw_align_buf;
++				ep->dwc_ep.xfer_buff = req->dw_align_buf;
++			} else {
++				ep->dwc_ep.dma_addr = req->dma;
++				ep->dwc_ep.start_xfer_buff = req->buf;
++				ep->dwc_ep.xfer_buff = req->buf;
++			}
++			ep->dwc_ep.sent_zlp = 0;
++			ep->dwc_ep.total_len = req->length;
++			ep->dwc_ep.xfer_len = 0;
++			ep->dwc_ep.xfer_count = 0;
++
++			ep->dwc_ep.maxxfer = max_transfer;
++			if (GET_CORE_IF(ep->pcd)->dma_desc_enable) {
++				uint32_t out_max_xfer = DDMA_MAX_TRANSFER_SIZE
++				    - (DDMA_MAX_TRANSFER_SIZE % 4);
++				if (ep->dwc_ep.is_in) {
++					if (ep->dwc_ep.maxxfer >
++					    DDMA_MAX_TRANSFER_SIZE) {
++						ep->dwc_ep.maxxfer =
++						    DDMA_MAX_TRANSFER_SIZE;
++					}
++				} else {
++					if (ep->dwc_ep.maxxfer > out_max_xfer) {
++						ep->dwc_ep.maxxfer =
++						    out_max_xfer;
++					}
++				}
++			}
++			if (ep->dwc_ep.maxxfer < ep->dwc_ep.total_len) {
++				ep->dwc_ep.maxxfer -=
++				    (ep->dwc_ep.maxxfer % ep->dwc_ep.maxpacket);
++			}
++			if (req->sent_zlp) {
++				if ((ep->dwc_ep.total_len %
++				     ep->dwc_ep.maxpacket == 0)
++				    && (ep->dwc_ep.total_len != 0)) {
++					ep->dwc_ep.sent_zlp = 1;
++				}
++
++			}
++#ifdef DWC_UTE_CFI
++		}
++#endif
++		dwc_otg_ep_start_transfer(GET_CORE_IF(ep->pcd), &ep->dwc_ep);
++	} else if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
++		diepmsk_data_t intr_mask = {.d32 = 0 };
++
++		intr_mask.b.nak = 1;
++
++		if (GET_CORE_IF(ep->pcd)->multiproc_int_enable) {
++			DWC_MODIFY_REG32(&GET_CORE_IF(ep->pcd)->dev_if->dev_global_regs->
++				diepeachintmsk[ep->dwc_ep.num], intr_mask.d32, 0);
++		} else {
++			DWC_MODIFY_REG32(&GET_CORE_IF(ep->pcd)->dev_if->dev_global_regs->diepmsk,
++				intr_mask.d32, 0);
++		}
++		DWC_PRINTF("There are no more ISOC requests \n");
++		ep->dwc_ep.frame_num = 0xFFFFFFFF;
++	}
++}
++
++/**
++ * This function handles the SOF Interrupts. At this time the SOF
++ * Interrupt is disabled.
++ */
++int32_t dwc_otg_pcd_handle_sof_intr(dwc_otg_pcd_t * pcd)
++{
++	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
++
++	gintsts_data_t gintsts;
++
++	DWC_DEBUGPL(DBG_PCD, "SOF\n");
++
++	/* Clear interrupt */
++	gintsts.d32 = 0;
++	gintsts.b.sofintr = 1;
++	DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
++
++	return 1;
++}
++
++/**
++ * This function handles the Rx Status Queue Level Interrupt, which
++ * indicates that there is a least one packet in the Rx FIFO.  The
++ * packets are moved from the FIFO to memory, where they will be
++ * processed when the Endpoint Interrupt Register indicates Transfer
++ * Complete or SETUP Phase Done.
++ *
++ * Repeat the following until the Rx Status Queue is empty:
++ *	 -# Read the Receive Status Pop Register (GRXSTSP) to get Packet
++ *		info
++ *	 -# If Receive FIFO is empty then skip to step Clear the interrupt
++ *		and exit
++ *	 -# If SETUP Packet call dwc_otg_read_setup_packet to copy the
++ *		SETUP data to the buffer
++ *	 -# If OUT Data Packet call dwc_otg_read_packet to copy the data
++ *		to the destination buffer
++ */
++int32_t dwc_otg_pcd_handle_rx_status_q_level_intr(dwc_otg_pcd_t * pcd)
++{
++	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
++	dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
++	gintmsk_data_t gintmask = {.d32 = 0 };
++	device_grxsts_data_t status;
++	dwc_otg_pcd_ep_t *ep;
++	gintsts_data_t gintsts;
++#ifdef DEBUG
++	static char *dpid_str[] = { "D0", "D2", "D1", "MDATA" };
++#endif
++
++	//DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, _pcd);
++	/* Disable the Rx Status Queue Level interrupt */
++	gintmask.b.rxstsqlvl = 1;
++	DWC_MODIFY_REG32(&global_regs->gintmsk, gintmask.d32, 0);
++
++	/* Get the Status from the top of the FIFO */
++	status.d32 = DWC_READ_REG32(&global_regs->grxstsp);
++
++	DWC_DEBUGPL(DBG_PCD, "EP:%d BCnt:%d DPID:%s "
++		    "pktsts:%x Frame:%d(0x%0x)\n",
++		    status.b.epnum, status.b.bcnt,
++		    dpid_str[status.b.dpid],
++		    status.b.pktsts, status.b.fn, status.b.fn);
++	/* Get pointer to EP structure */
++	ep = get_out_ep(pcd, status.b.epnum);
++	if (!ep)
++		return -EINVAL;
++
++	switch (status.b.pktsts) {
++	case DWC_DSTS_GOUT_NAK:
++		DWC_DEBUGPL(DBG_PCDV, "Global OUT NAK\n");
++		break;
++	case DWC_STS_DATA_UPDT:
++		DWC_DEBUGPL(DBG_PCDV, "OUT Data Packet\n");
++		if (status.b.bcnt && ep->dwc_ep.xfer_buff) {
++			/** @todo NGS Check for buffer overflow? */
++			dwc_otg_read_packet(core_if,
++					    ep->dwc_ep.xfer_buff,
++					    status.b.bcnt);
++			ep->dwc_ep.xfer_count += status.b.bcnt;
++			ep->dwc_ep.xfer_buff += status.b.bcnt;
++		}
++		if (status.b.bcnt &&(status.b.bcnt<1024)
++			&& !ep->dwc_ep.xfer_buff) {
++			dwc_otg_read_packet(core_if,
++					    readpacket_buf,
++					    status.b.bcnt);
++			ep->dwc_ep.xfer_count += status.b.bcnt;
++		}
++		break;
++	case DWC_STS_XFER_COMP:
++		DWC_DEBUGPL(DBG_PCDV, "OUT Complete\n");
++		break;
++	case DWC_DSTS_SETUP_COMP:
++#ifdef DEBUG_EP0
++		DWC_DEBUGPL(DBG_PCDV, "Setup Complete\n");
++#endif
++		break;
++	case DWC_DSTS_SETUP_UPDT:
++		dwc_otg_read_setup_packet(core_if, pcd->setup_pkt->d32);
++#ifdef DEBUG_EP0
++		DWC_DEBUGPL(DBG_PCD,
++			    "SETUP PKT: %02x.%02x v%04x i%04x l%04x\n",
++			    pcd->setup_pkt->req.bmRequestType,
++			    pcd->setup_pkt->req.bRequest,
++			    UGETW(pcd->setup_pkt->req.wValue),
++			    UGETW(pcd->setup_pkt->req.wIndex),
++			    UGETW(pcd->setup_pkt->req.wLength));
++#endif
++		ep->dwc_ep.xfer_count += status.b.bcnt;
++		break;
++	default:
++		DWC_DEBUGPL(DBG_PCDV, "Invalid Packet Status (0x%0x)\n",
++			    status.b.pktsts);
++		break;
++	}
++
++	/* Enable the Rx Status Queue Level interrupt */
++	DWC_MODIFY_REG32(&global_regs->gintmsk, 0, gintmask.d32);
++	/* Clear interrupt */
++	gintsts.d32 = 0;
++	gintsts.b.rxstsqlvl = 1;
++	DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
++
++	//DWC_DEBUGPL(DBG_PCDV, "EXIT: %s\n", __func__);
++	return 1;
++}
++
++/**
++ * This function examines the Device IN Token Learning Queue to
++ * determine the EP number of the last IN token received.  This
++ * implementation is for the Mass Storage device where there are only
++ * 2 IN EPs (Control-IN and BULK-IN).
++ *
++ * The EP numbers for the first six IN Tokens are in DTKNQR1 and there
++ * are 8 EP Numbers in each of the other possible DTKNQ Registers.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ *
++ */
++static inline int get_ep_of_last_in_token(dwc_otg_core_if_t * core_if)
++{
++	dwc_otg_device_global_regs_t *dev_global_regs =
++	    core_if->dev_if->dev_global_regs;
++	const uint32_t TOKEN_Q_DEPTH = core_if->hwcfg2.b.dev_token_q_depth;
++	/* Number of Token Queue Registers */
++	const int DTKNQ_REG_CNT = (TOKEN_Q_DEPTH + 7) / 8;
++	dtknq1_data_t dtknqr1;
++	uint32_t in_tkn_epnums[4];
++	int ndx = 0;
++	int i = 0;
++	volatile uint32_t *addr = &dev_global_regs->dtknqr1;
++	int epnum = 0;
++
++	//DWC_DEBUGPL(DBG_PCD,"dev_token_q_depth=%d\n",TOKEN_Q_DEPTH);
++
++	/* Read the DTKNQ Registers */
++	for (i = 0; i < DTKNQ_REG_CNT; i++) {
++		in_tkn_epnums[i] = DWC_READ_REG32(addr);
++		DWC_DEBUGPL(DBG_PCDV, "DTKNQR%d=0x%08x\n", i + 1,
++			    in_tkn_epnums[i]);
++		if (addr == &dev_global_regs->dvbusdis) {
++			addr = &dev_global_regs->dtknqr3_dthrctl;
++		} else {
++			++addr;
++		}
++
++	}
++
++	/* Copy the DTKNQR1 data to the bit field. */
++	dtknqr1.d32 = in_tkn_epnums[0];
++	/* Get the EP numbers */
++	in_tkn_epnums[0] = dtknqr1.b.epnums0_5;
++	ndx = dtknqr1.b.intknwptr - 1;
++
++	//DWC_DEBUGPL(DBG_PCDV,"ndx=%d\n",ndx);
++	if (ndx == -1) {
++		/** @todo Find a simpler way to calculate the max
++		 * queue position.*/
++		int cnt = TOKEN_Q_DEPTH;
++		if (TOKEN_Q_DEPTH <= 6) {
++			cnt = TOKEN_Q_DEPTH - 1;
++		} else if (TOKEN_Q_DEPTH <= 14) {
++			cnt = TOKEN_Q_DEPTH - 7;
++		} else if (TOKEN_Q_DEPTH <= 22) {
++			cnt = TOKEN_Q_DEPTH - 15;
++		} else {
++			cnt = TOKEN_Q_DEPTH - 23;
++		}
++		epnum = (in_tkn_epnums[DTKNQ_REG_CNT - 1] >> (cnt * 4)) & 0xF;
++	} else {
++		if (ndx <= 5) {
++			epnum = (in_tkn_epnums[0] >> (ndx * 4)) & 0xF;
++		} else if (ndx <= 13) {
++			ndx -= 6;
++			epnum = (in_tkn_epnums[1] >> (ndx * 4)) & 0xF;
++		} else if (ndx <= 21) {
++			ndx -= 14;
++			epnum = (in_tkn_epnums[2] >> (ndx * 4)) & 0xF;
++		} else if (ndx <= 29) {
++			ndx -= 22;
++			epnum = (in_tkn_epnums[3] >> (ndx * 4)) & 0xF;
++		}
++	}
++	//DWC_DEBUGPL(DBG_PCD,"epnum=%d\n",epnum);
++	return epnum;
++}
++
++/**
++ * This interrupt occurs when the non-periodic Tx FIFO is half-empty.
++ * The active request is checked for the next packet to be loaded into
++ * the non-periodic Tx FIFO.
++ */
++int32_t dwc_otg_pcd_handle_np_tx_fifo_empty_intr(dwc_otg_pcd_t * pcd)
++{
++	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
++	dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
++	dwc_otg_dev_in_ep_regs_t *ep_regs;
++	gnptxsts_data_t txstatus = {.d32 = 0 };
++	gintsts_data_t gintsts;
++
++	int epnum = 0;
++	dwc_otg_pcd_ep_t *ep = 0;
++	uint32_t len = 0;
++	int dwords;
++
++	/* Get the epnum from the IN Token Learning Queue. */
++	epnum = get_ep_of_last_in_token(core_if);
++	ep = get_in_ep(pcd, epnum);
++	if (!ep)
++		return -EINVAL;
++
++	DWC_DEBUGPL(DBG_PCD, "NP TxFifo Empty: %d \n", epnum);
++
++	ep_regs = core_if->dev_if->in_ep_regs[epnum];
++
++	len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count;
++	if (len > ep->dwc_ep.maxpacket) {
++		len = ep->dwc_ep.maxpacket;
++	}
++	dwords = (len + 3) / 4;
++
++	/* While there is space in the queue and space in the FIFO and
++	 * More data to tranfer, Write packets to the Tx FIFO */
++	txstatus.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
++	DWC_DEBUGPL(DBG_PCDV, "b4 GNPTXSTS=0x%08x\n", txstatus.d32);
++
++	while (txstatus.b.nptxqspcavail > 0 &&
++	       txstatus.b.nptxfspcavail > dwords &&
++	       ep->dwc_ep.xfer_count < ep->dwc_ep.xfer_len) {
++		/* Write the FIFO */
++		dwc_otg_ep_write_packet(core_if, &ep->dwc_ep, 0);
++		len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count;
++
++		if (len > ep->dwc_ep.maxpacket) {
++			len = ep->dwc_ep.maxpacket;
++		}
++
++		dwords = (len + 3) / 4;
++		txstatus.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
++		DWC_DEBUGPL(DBG_PCDV, "GNPTXSTS=0x%08x\n", txstatus.d32);
++	}
++
++	DWC_DEBUGPL(DBG_PCDV, "GNPTXSTS=0x%08x\n",
++		    DWC_READ_REG32(&global_regs->gnptxsts));
++
++	/* Clear interrupt */
++	gintsts.d32 = 0;
++	gintsts.b.nptxfempty = 1;
++	DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
++
++	return 1;
++}
++
++/**
++ * This function is called when dedicated Tx FIFO Empty interrupt occurs.
++ * The active request is checked for the next packet to be loaded into
++ * apropriate Tx FIFO.
++ */
++static int32_t write_empty_tx_fifo(dwc_otg_pcd_t * pcd, uint32_t epnum)
++{
++	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
++	dwc_otg_dev_if_t *dev_if = core_if->dev_if;
++	dwc_otg_dev_in_ep_regs_t *ep_regs;
++	dtxfsts_data_t txstatus = {.d32 = 0 };
++	dwc_otg_pcd_ep_t *ep = 0;
++	uint32_t len = 0;
++	int dwords;
++
++	ep = get_in_ep(pcd, epnum);
++	if (!ep)
++		return -EINVAL;
++
++	DWC_DEBUGPL(DBG_PCD, "Dedicated TxFifo Empty: %d \n", epnum);
++
++	ep_regs = core_if->dev_if->in_ep_regs[epnum];
++
++	len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count;
++
++	if (len > ep->dwc_ep.maxpacket) {
++		len = ep->dwc_ep.maxpacket;
++	}
++
++	dwords = (len + 3) / 4;
++
++	/* While there is space in the queue and space in the FIFO and
++	 * More data to tranfer, Write packets to the Tx FIFO */
++	txstatus.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dtxfsts);
++	DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n", epnum, txstatus.d32);
++
++	while (txstatus.b.txfspcavail >= dwords &&
++	       ep->dwc_ep.xfer_count < ep->dwc_ep.xfer_len &&
++	       ep->dwc_ep.xfer_len != 0) {
++		/* Write the FIFO */
++		dwc_otg_ep_write_packet(core_if, &ep->dwc_ep, 0);
++
++		len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count;
++		if (len > ep->dwc_ep.maxpacket) {
++			len = ep->dwc_ep.maxpacket;
++		}
++
++		dwords = (len + 3) / 4;
++		txstatus.d32 =
++		    DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dtxfsts);
++		DWC_DEBUGPL(DBG_PCDV, "dtxfsts[%d]=0x%08x\n", epnum,
++			    txstatus.d32);
++	}
++
++	DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n", epnum,
++		    DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dtxfsts));
++
++	return 1;
++}
++
++/**
++ * This function is called when the Device is disconnected. It stops
++ * any active requests and informs the Gadget driver of the
++ * disconnect.
++ */
++void dwc_otg_pcd_stop(dwc_otg_pcd_t * pcd)
++{
++	int i, num_in_eps, num_out_eps;
++	dwc_otg_pcd_ep_t *ep;
++
++	gintmsk_data_t intr_mask = {.d32 = 0 };
++
++	DWC_SPINLOCK(pcd->lock);
++
++	num_in_eps = GET_CORE_IF(pcd)->dev_if->num_in_eps;
++	num_out_eps = GET_CORE_IF(pcd)->dev_if->num_out_eps;
++
++	DWC_DEBUGPL(DBG_PCDV, "%s() \n", __func__);
++	/* don't disconnect drivers more than once */
++	if (pcd->ep0state == EP0_DISCONNECT) {
++		DWC_DEBUGPL(DBG_ANY, "%s() Already Disconnected\n", __func__);
++		DWC_SPINUNLOCK(pcd->lock);
++		return;
++	}
++	pcd->ep0state = EP0_DISCONNECT;
++
++	/* Reset the OTG state. */
++	dwc_otg_pcd_update_otg(pcd, 1);
++
++	/* Disable the NP Tx Fifo Empty Interrupt. */
++	intr_mask.b.nptxfempty = 1;
++	DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
++			 intr_mask.d32, 0);
++
++	/* Flush the FIFOs */
++	/**@todo NGS Flush Periodic FIFOs */
++	dwc_otg_flush_tx_fifo(GET_CORE_IF(pcd), 0x10);
++	dwc_otg_flush_rx_fifo(GET_CORE_IF(pcd));
++
++	/* prevent new request submissions, kill any outstanding requests  */
++	ep = &pcd->ep0;
++	dwc_otg_request_nuke(ep);
++	/* prevent new request submissions, kill any outstanding requests  */
++	for (i = 0; i < num_in_eps; i++) {
++		dwc_otg_pcd_ep_t *ep = &pcd->in_ep[i];
++		dwc_otg_request_nuke(ep);
++	}
++	/* prevent new request submissions, kill any outstanding requests  */
++	for (i = 0; i < num_out_eps; i++) {
++		dwc_otg_pcd_ep_t *ep = &pcd->out_ep[i];
++		dwc_otg_request_nuke(ep);
++	}
++
++	/* report disconnect; the driver is already quiesced */
++	if (pcd->fops->disconnect) {
++		DWC_SPINUNLOCK(pcd->lock);
++		pcd->fops->disconnect(pcd);
++		DWC_SPINLOCK(pcd->lock);
++	}
++	DWC_SPINUNLOCK(pcd->lock);
++}
++
++/**
++ * This interrupt indicates that ...
++ */
++int32_t dwc_otg_pcd_handle_i2c_intr(dwc_otg_pcd_t * pcd)
++{
++	gintmsk_data_t intr_mask = {.d32 = 0 };
++	gintsts_data_t gintsts;
++
++	DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", "i2cintr");
++	intr_mask.b.i2cintr = 1;
++	DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
++			 intr_mask.d32, 0);
++
++	/* Clear interrupt */
++	gintsts.d32 = 0;
++	gintsts.b.i2cintr = 1;
++	DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
++			gintsts.d32);
++	return 1;
++}
++
++/**
++ * This interrupt indicates that ...
++ */
++int32_t dwc_otg_pcd_handle_early_suspend_intr(dwc_otg_pcd_t * pcd)
++{
++	gintsts_data_t gintsts;
++
++	DWC_DEBUGPL(DBG_PCDV,"Early Suspend Detected\n");
++
++
++	/* Clear interrupt */
++	gintsts.d32 = 0;
++	gintsts.b.erlysuspend = 1;
++	DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
++			gintsts.d32);
++
++	return 1;
++}
++
++/**
++ * This function configures EPO to receive SETUP packets.
++ *
++ * @todo NGS: Update the comments from the HW FS.
++ *
++ *	-# Program the following fields in the endpoint specific registers
++ *	for Control OUT EP 0, in order to receive a setup packet
++ *	- DOEPTSIZ0.Packet Count = 3 (To receive up to 3 back to back
++ *	  setup packets)
++ *	- DOEPTSIZE0.Transfer Size = 24 Bytes (To receive up to 3 back
++ *	  to back setup packets)
++ *		- In DMA mode, DOEPDMA0 Register with a memory address to
++ *		  store any setup packets received
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ * @param pcd	  Programming view of the PCD.
++ */
++static inline void ep0_out_start(dwc_otg_core_if_t * core_if,
++				 dwc_otg_pcd_t * pcd)
++{
++	dwc_otg_dev_if_t *dev_if = core_if->dev_if;
++	deptsiz0_data_t doeptsize0 = {.d32 = 0 };
++	dwc_otg_dev_dma_desc_t *dma_desc;
++	depctl_data_t doepctl = {.d32 = 0 };
++
++#ifdef VERBOSE
++	DWC_DEBUGPL(DBG_PCDV, "%s() doepctl0=%0x\n", __func__,
++		    DWC_READ_REG32(&dev_if->out_ep_regs[0]->doepctl));
++#endif
++	if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
++		doepctl.d32 = DWC_READ_REG32(&dev_if->out_ep_regs[0]->doepctl);
++		if (doepctl.b.epena) {
++			return;
++		}
++	}
++
++	doeptsize0.b.supcnt = 3;
++	doeptsize0.b.pktcnt = 1;
++	doeptsize0.b.xfersize = 8 * 3;
++
++	if (core_if->dma_enable) {
++		if (!core_if->dma_desc_enable) {
++			/** put here as for Hermes mode deptisz register should not be written */
++			DWC_WRITE_REG32(&dev_if->out_ep_regs[0]->doeptsiz,
++					doeptsize0.d32);
++
++			/** @todo dma needs to handle multiple setup packets (up to 3) */
++			DWC_WRITE_REG32(&dev_if->out_ep_regs[0]->doepdma,
++					pcd->setup_pkt_dma_handle);
++		} else {
++			dev_if->setup_desc_index =
++			    (dev_if->setup_desc_index + 1) & 1;
++			dma_desc =
++			    dev_if->setup_desc_addr[dev_if->setup_desc_index];
++
++			/** DMA Descriptor Setup */
++			dma_desc->status.b.bs = BS_HOST_BUSY;
++			if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
++				dma_desc->status.b.sr = 0;
++				dma_desc->status.b.mtrf = 0;
++			}
++			dma_desc->status.b.l = 1;
++			dma_desc->status.b.ioc = 1;
++			dma_desc->status.b.bytes = pcd->ep0.dwc_ep.maxpacket;
++			dma_desc->buf = pcd->setup_pkt_dma_handle;
++			dma_desc->status.b.sts = 0;
++			dma_desc->status.b.bs = BS_HOST_READY;
++
++			/** DOEPDMA0 Register write */
++			DWC_WRITE_REG32(&dev_if->out_ep_regs[0]->doepdma,
++					dev_if->dma_setup_desc_addr
++					[dev_if->setup_desc_index]);
++		}
++
++	} else {
++		/** put here as for Hermes mode deptisz register should not be written */
++		DWC_WRITE_REG32(&dev_if->out_ep_regs[0]->doeptsiz,
++				doeptsize0.d32);
++	}
++
++	/** DOEPCTL0 Register write cnak will be set after setup interrupt */
++	doepctl.d32 = 0;
++	doepctl.b.epena = 1;
++	if (core_if->snpsid <= OTG_CORE_REV_2_94a) {
++		doepctl.b.cnak = 1;
++		DWC_WRITE_REG32(&dev_if->out_ep_regs[0]->doepctl, doepctl.d32);
++	} else {
++		DWC_MODIFY_REG32(&dev_if->out_ep_regs[0]->doepctl, 0, doepctl.d32);
++	}
++
++#ifdef VERBOSE
++	DWC_DEBUGPL(DBG_PCDV, "doepctl0=%0x\n",
++		    DWC_READ_REG32(&dev_if->out_ep_regs[0]->doepctl));
++	DWC_DEBUGPL(DBG_PCDV, "diepctl0=%0x\n",
++		    DWC_READ_REG32(&dev_if->in_ep_regs[0]->diepctl));
++#endif
++}
++
++/**
++ * This interrupt occurs when a USB Reset is detected. When the USB
++ * Reset Interrupt occurs the device state is set to DEFAULT and the
++ * EP0 state is set to IDLE.
++ *	-#	Set the NAK bit for all OUT endpoints (DOEPCTLn.SNAK = 1)
++ *	-#	Unmask the following interrupt bits
++ *		- DAINTMSK.INEP0 = 1 (Control 0 IN endpoint)
++ *	- DAINTMSK.OUTEP0 = 1 (Control 0 OUT endpoint)
++ *	- DOEPMSK.SETUP = 1
++ *	- DOEPMSK.XferCompl = 1
++ *	- DIEPMSK.XferCompl = 1
++ *	- DIEPMSK.TimeOut = 1
++ *	-# Program the following fields in the endpoint specific registers
++ *	for Control OUT EP 0, in order to receive a setup packet
++ *	- DOEPTSIZ0.Packet Count = 3 (To receive up to 3 back to back
++ *	  setup packets)
++ *	- DOEPTSIZE0.Transfer Size = 24 Bytes (To receive up to 3 back
++ *	  to back setup packets)
++ *		- In DMA mode, DOEPDMA0 Register with a memory address to
++ *		  store any setup packets received
++ * At this point, all the required initialization, except for enabling
++ * the control 0 OUT endpoint is done, for receiving SETUP packets.
++ */
++int32_t dwc_otg_pcd_handle_usb_reset_intr(dwc_otg_pcd_t * pcd)
++{
++	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
++	dwc_otg_dev_if_t *dev_if = core_if->dev_if;
++	depctl_data_t doepctl = {.d32 = 0 };
++	depctl_data_t diepctl = {.d32 = 0 };
++	daint_data_t daintmsk = {.d32 = 0 };
++	doepmsk_data_t doepmsk = {.d32 = 0 };
++	diepmsk_data_t diepmsk = {.d32 = 0 };
++	dcfg_data_t dcfg = {.d32 = 0 };
++	grstctl_t resetctl = {.d32 = 0 };
++	dctl_data_t dctl = {.d32 = 0 };
++	int i = 0;
++	gintsts_data_t gintsts;
++	pcgcctl_data_t power = {.d32 = 0 };
++
++	power.d32 = DWC_READ_REG32(core_if->pcgcctl);
++	if (power.b.stoppclk) {
++		power.d32 = 0;
++		power.b.stoppclk = 1;
++		DWC_MODIFY_REG32(core_if->pcgcctl, power.d32, 0);
++
++		power.b.pwrclmp = 1;
++		DWC_MODIFY_REG32(core_if->pcgcctl, power.d32, 0);
++
++		power.b.rstpdwnmodule = 1;
++		DWC_MODIFY_REG32(core_if->pcgcctl, power.d32, 0);
++	}
++
++	core_if->lx_state = DWC_OTG_L0;
++	core_if->otg_sts = 0;
++
++
++#ifdef DWC_EN_ISOC
++	for (i = 1; i < 16; ++i) {
++		dwc_otg_pcd_ep_t *ep;
++		dwc_ep_t *dwc_ep;
++		ep = get_in_ep(pcd, i);
++		if (ep != 0) {
++			dwc_ep = &ep->dwc_ep;
++			dwc_ep->next_frame = 0xffffffff;
++		}
++	}
++#endif /* DWC_EN_ISOC */
++
++	/* reset the HNP settings */
++	dwc_otg_pcd_update_otg(pcd, 1);
++
++	/* Clear the Remote Wakeup Signalling */
++	dctl.b.rmtwkupsig = 1;
++	DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32, 0);
++
++	/* Set NAK for all OUT EPs */
++	doepctl.b.snak = 1;
++	for (i = 0; i <= dev_if->num_out_eps; i++) {
++		DWC_WRITE_REG32(&dev_if->out_ep_regs[i]->doepctl, doepctl.d32);
++	}
++
++	/* Flush the NP Tx FIFO */
++	dwc_otg_flush_tx_fifo(core_if, 0x10);
++	/* Flush the Learning Queue */
++	resetctl.b.intknqflsh = 1;
++	DWC_WRITE_REG32(&core_if->core_global_regs->grstctl, resetctl.d32);
++
++	if (!core_if->core_params->en_multiple_tx_fifo && core_if->dma_enable) {
++		core_if->start_predict = 0;
++		for (i = 0; i <= core_if->dev_if->num_in_eps; ++i) {
++			core_if->nextep_seq[i] = 0xff;	// 0xff - EP not active
++		}
++		core_if->nextep_seq[0] = 0;
++		core_if->first_in_nextep_seq = 0;
++		diepctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[0]->diepctl);
++		diepctl.b.nextep = 0;
++		DWC_WRITE_REG32(&dev_if->in_ep_regs[0]->diepctl, diepctl.d32);
++
++		/* Update IN Endpoint Mismatch Count by active IN NP EP count + 1 */
++		dcfg.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dcfg);
++		dcfg.b.epmscnt = 2;
++		DWC_WRITE_REG32(&dev_if->dev_global_regs->dcfg, dcfg.d32);
++
++		DWC_DEBUGPL(DBG_PCDV,
++			    "%s first_in_nextep_seq= %2d; nextep_seq[]:\n",
++			    __func__, core_if->first_in_nextep_seq);
++		for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
++			DWC_DEBUGPL(DBG_PCDV, "%2d\n", core_if->nextep_seq[i]);
++		}
++	}
++
++	if (core_if->multiproc_int_enable) {
++		daintmsk.b.inep0 = 1;
++		daintmsk.b.outep0 = 1;
++		DWC_WRITE_REG32(&dev_if->dev_global_regs->deachintmsk,
++				daintmsk.d32);
++
++		doepmsk.b.setup = 1;
++		doepmsk.b.xfercompl = 1;
++		doepmsk.b.ahberr = 1;
++		doepmsk.b.epdisabled = 1;
++
++		if ((core_if->dma_desc_enable) ||
++		    (core_if->dma_enable
++		     && core_if->snpsid >= OTG_CORE_REV_3_00a)) {
++			doepmsk.b.stsphsercvd = 1;
++		}
++		if (core_if->dma_desc_enable)
++			doepmsk.b.bna = 1;
++/*
++		doepmsk.b.babble = 1;
++		doepmsk.b.nyet = 1;
++
++		if (core_if->dma_enable) {
++			doepmsk.b.nak = 1;
++		}
++*/
++		DWC_WRITE_REG32(&dev_if->dev_global_regs->doepeachintmsk[0],
++				doepmsk.d32);
++
++		diepmsk.b.xfercompl = 1;
++		diepmsk.b.timeout = 1;
++		diepmsk.b.epdisabled = 1;
++		diepmsk.b.ahberr = 1;
++		diepmsk.b.intknepmis = 1;
++		if (!core_if->en_multiple_tx_fifo && core_if->dma_enable)
++			diepmsk.b.intknepmis = 0;
++
++/*		if (core_if->dma_desc_enable) {
++			diepmsk.b.bna = 1;
++		}
++*/
++/*
++		if (core_if->dma_enable) {
++			diepmsk.b.nak = 1;
++		}
++*/
++		DWC_WRITE_REG32(&dev_if->dev_global_regs->diepeachintmsk[0],
++				diepmsk.d32);
++	} else {
++		daintmsk.b.inep0 = 1;
++		daintmsk.b.outep0 = 1;
++		DWC_WRITE_REG32(&dev_if->dev_global_regs->daintmsk,
++				daintmsk.d32);
++
++		doepmsk.b.setup = 1;
++		doepmsk.b.xfercompl = 1;
++		doepmsk.b.ahberr = 1;
++		doepmsk.b.epdisabled = 1;
++
++		if ((core_if->dma_desc_enable) ||
++		    (core_if->dma_enable
++		     && core_if->snpsid >= OTG_CORE_REV_3_00a)) {
++			doepmsk.b.stsphsercvd = 1;
++		}
++		if (core_if->dma_desc_enable)
++			doepmsk.b.bna = 1;
++		DWC_WRITE_REG32(&dev_if->dev_global_regs->doepmsk, doepmsk.d32);
++
++		diepmsk.b.xfercompl = 1;
++		diepmsk.b.timeout = 1;
++		diepmsk.b.epdisabled = 1;
++		diepmsk.b.ahberr = 1;
++		if (!core_if->en_multiple_tx_fifo && core_if->dma_enable)
++			diepmsk.b.intknepmis = 0;
++/*
++		if (core_if->dma_desc_enable) {
++			diepmsk.b.bna = 1;
++		}
++*/
++
++		DWC_WRITE_REG32(&dev_if->dev_global_regs->diepmsk, diepmsk.d32);
++	}
++
++	/* Reset Device Address */
++	dcfg.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dcfg);
++	dcfg.b.devaddr = 0;
++	DWC_WRITE_REG32(&dev_if->dev_global_regs->dcfg, dcfg.d32);
++
++	/* setup EP0 to receive SETUP packets */
++	if (core_if->snpsid <= OTG_CORE_REV_2_94a)
++		ep0_out_start(core_if, pcd);
++
++	/* Clear interrupt */
++	gintsts.d32 = 0;
++	gintsts.b.usbreset = 1;
++	DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
++
++	return 1;
++}
++
++/**
++ * Get the device speed from the device status register and convert it
++ * to USB speed constant.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ */
++static int get_device_speed(dwc_otg_core_if_t * core_if)
++{
++	dsts_data_t dsts;
++	int speed = 0;
++	dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
++
++	switch (dsts.b.enumspd) {
++	case DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ:
++		speed = USB_SPEED_HIGH;
++		break;
++	case DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ:
++	case DWC_DSTS_ENUMSPD_FS_PHY_48MHZ:
++		speed = USB_SPEED_FULL;
++		break;
++
++	case DWC_DSTS_ENUMSPD_LS_PHY_6MHZ:
++		speed = USB_SPEED_LOW;
++		break;
++	}
++
++	return speed;
++}
++
++/**
++ * Read the device status register and set the device speed in the
++ * data structure.
++ * Set up EP0 to receive SETUP packets by calling dwc_ep0_activate.
++ */
++int32_t dwc_otg_pcd_handle_enum_done_intr(dwc_otg_pcd_t * pcd)
++{
++	dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
++	gintsts_data_t gintsts;
++	gusbcfg_data_t gusbcfg;
++	dwc_otg_core_global_regs_t *global_regs =
++	    GET_CORE_IF(pcd)->core_global_regs;
++	uint8_t utmi16b, utmi8b;
++	int speed;
++	dcfg_data_t dcfg;
++
++	DWC_DEBUGPL(DBG_PCD, "SPEED ENUM\n");
++
++	/* WA for the case when SW gets SPEED ENUM without first USB RESET case
++	* due to USB RESET issued by the host earlier. Anyways USB Reset routine
++	* needs to be called to at least program EP 0 OUT - vahrama
++	*/
++	dcfg.d32 = DWC_READ_REG32(&pcd->core_if->dev_if->dev_global_regs->dcfg);
++	if (pcd->core_if->otg_ver && dcfg.b.devaddr)
++		dwc_otg_pcd_handle_usb_reset_intr(pcd);
++
++
++	if (GET_CORE_IF(pcd)->snpsid >= OTG_CORE_REV_2_60a) {
++		utmi16b = 6;	//vahrama old value was 6;
++		utmi8b = 9;
++	} else {
++		utmi16b = 4;
++		utmi8b = 8;
++	}
++	dwc_otg_ep0_activate(GET_CORE_IF(pcd), &ep0->dwc_ep);
++	if (GET_CORE_IF(pcd)->snpsid >= OTG_CORE_REV_3_00a) {
++		ep0_out_start(GET_CORE_IF(pcd), pcd);
++	}
++
++#ifdef DEBUG_EP0
++	print_ep0_state(pcd);
++#endif
++
++	if (pcd->ep0state == EP0_DISCONNECT) {
++		pcd->ep0state = EP0_IDLE;
++	} else if (pcd->ep0state == EP0_STALL) {
++		pcd->ep0state = EP0_IDLE;
++	}
++
++	pcd->ep0state = EP0_IDLE;
++
++	ep0->stopped = 0;
++
++	speed = get_device_speed(GET_CORE_IF(pcd));
++	pcd->fops->connect(pcd, speed);
++
++	/* Set USB turnaround time based on device speed and PHY interface. */
++	gusbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
++	if (speed == USB_SPEED_HIGH) {
++		if (GET_CORE_IF(pcd)->hwcfg2.b.hs_phy_type ==
++		    DWC_HWCFG2_HS_PHY_TYPE_ULPI) {
++			/* ULPI interface */
++			gusbcfg.b.usbtrdtim = 9;
++		}
++		if (GET_CORE_IF(pcd)->hwcfg2.b.hs_phy_type ==
++		    DWC_HWCFG2_HS_PHY_TYPE_UTMI) {
++			/* UTMI+ interface */
++			if (GET_CORE_IF(pcd)->hwcfg4.b.utmi_phy_data_width == 0) {
++				gusbcfg.b.usbtrdtim = utmi8b;
++			} else if (GET_CORE_IF(pcd)->hwcfg4.
++				   b.utmi_phy_data_width == 1) {
++				gusbcfg.b.usbtrdtim = utmi16b;
++			} else if (GET_CORE_IF(pcd)->
++				   core_params->phy_utmi_width == 8) {
++				gusbcfg.b.usbtrdtim = utmi8b;
++			} else {
++				gusbcfg.b.usbtrdtim = utmi16b;
++			}
++		}
++		if (GET_CORE_IF(pcd)->hwcfg2.b.hs_phy_type ==
++		    DWC_HWCFG2_HS_PHY_TYPE_UTMI_ULPI) {
++			/* UTMI+  OR  ULPI interface */
++			if (gusbcfg.b.ulpi_utmi_sel == 1) {
++				/* ULPI interface */
++				gusbcfg.b.usbtrdtim = 9;
++			} else {
++				/* UTMI+ interface */
++				if (GET_CORE_IF(pcd)->
++				    core_params->phy_utmi_width == 16) {
++					gusbcfg.b.usbtrdtim = utmi16b;
++				} else {
++					gusbcfg.b.usbtrdtim = utmi8b;
++				}
++			}
++		}
++	} else {
++		/* Full or low speed */
++		gusbcfg.b.usbtrdtim = 9;
++	}
++	DWC_WRITE_REG32(&global_regs->gusbcfg, gusbcfg.d32);
++
++	/* Clear interrupt */
++	gintsts.d32 = 0;
++	gintsts.b.enumdone = 1;
++	DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
++			gintsts.d32);
++	return 1;
++}
++
++/**
++ * This interrupt indicates that the ISO OUT Packet was dropped due to
++ * Rx FIFO full or Rx Status Queue Full.  If this interrupt occurs
++ * read all the data from the Rx FIFO.
++ */
++int32_t dwc_otg_pcd_handle_isoc_out_packet_dropped_intr(dwc_otg_pcd_t * pcd)
++{
++	gintmsk_data_t intr_mask = {.d32 = 0 };
++	gintsts_data_t gintsts;
++
++	DWC_WARN("INTERRUPT Handler not implemented for %s\n",
++		 "ISOC Out Dropped");
++
++	intr_mask.b.isooutdrop = 1;
++	DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
++			 intr_mask.d32, 0);
++
++	/* Clear interrupt */
++	gintsts.d32 = 0;
++	gintsts.b.isooutdrop = 1;
++	DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
++			gintsts.d32);
++
++	return 1;
++}
++
++/**
++ * This interrupt indicates the end of the portion of the micro-frame
++ * for periodic transactions.  If there is a periodic transaction for
++ * the next frame, load the packets into the EP periodic Tx FIFO.
++ */
++int32_t dwc_otg_pcd_handle_end_periodic_frame_intr(dwc_otg_pcd_t * pcd)
++{
++	gintmsk_data_t intr_mask = {.d32 = 0 };
++	gintsts_data_t gintsts;
++	DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", "EOP");
++
++	intr_mask.b.eopframe = 1;
++	DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
++			 intr_mask.d32, 0);
++
++	/* Clear interrupt */
++	gintsts.d32 = 0;
++	gintsts.b.eopframe = 1;
++	DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
++			gintsts.d32);
++
++	return 1;
++}
++
++/**
++ * This interrupt indicates that EP of the packet on the top of the
++ * non-periodic Tx FIFO does not match EP of the IN Token received.
++ *
++ * The "Device IN Token Queue" Registers are read to determine the
++ * order the IN Tokens have been received. The non-periodic Tx FIFO
++ * is flushed, so it can be reloaded in the order seen in the IN Token
++ * Queue.
++ */
++int32_t dwc_otg_pcd_handle_ep_mismatch_intr(dwc_otg_pcd_t * pcd)
++{
++	gintsts_data_t gintsts;
++	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
++	dctl_data_t dctl;
++	gintmsk_data_t intr_mask = {.d32 = 0 };
++
++	if (!core_if->en_multiple_tx_fifo && core_if->dma_enable) {
++		core_if->start_predict = 1;
++
++		DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, core_if);
++
++		gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
++		if (!gintsts.b.ginnakeff) {
++			/* Disable EP Mismatch interrupt */
++			intr_mask.d32 = 0;
++			intr_mask.b.epmismatch = 1;
++			DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, intr_mask.d32, 0);
++			/* Enable the Global IN NAK Effective Interrupt */
++			intr_mask.d32 = 0;
++			intr_mask.b.ginnakeff = 1;
++			DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, 0, intr_mask.d32);
++			/* Set the global non-periodic IN NAK handshake */
++			dctl.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dctl);
++			dctl.b.sgnpinnak = 1;
++			DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32);
++		} else {
++			DWC_PRINTF("gintsts.b.ginnakeff = 1! dctl.b.sgnpinnak not set\n");
++		}
++		/* Disabling of all EP's will be done in dwc_otg_pcd_handle_in_nak_effective()
++		 * handler after Global IN NAK Effective interrupt will be asserted */
++	}
++	/* Clear interrupt */
++	gintsts.d32 = 0;
++	gintsts.b.epmismatch = 1;
++	DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
++
++	return 1;
++}
++
++/**
++ * This interrupt is valid only in DMA mode. This interrupt indicates that the
++ * core has stopped fetching data for IN endpoints due to the unavailability of
++ * TxFIFO space or Request Queue space. This interrupt is used by the
++ * application for an endpoint mismatch algorithm.
++ *
++ * @param pcd The PCD
++ */
++int32_t dwc_otg_pcd_handle_ep_fetsusp_intr(dwc_otg_pcd_t * pcd)
++{
++	gintsts_data_t gintsts;
++	gintmsk_data_t gintmsk_data;
++	dctl_data_t dctl;
++	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
++	DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, core_if);
++
++	/* Clear the global non-periodic IN NAK handshake */
++	dctl.d32 = 0;
++	dctl.b.cgnpinnak = 1;
++	DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32);
++
++	/* Mask GINTSTS.FETSUSP interrupt */
++	gintmsk_data.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintmsk);
++	gintmsk_data.b.fetsusp = 0;
++	DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, gintmsk_data.d32);
++
++	/* Clear interrupt */
++	gintsts.d32 = 0;
++	gintsts.b.fetsusp = 1;
++	DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
++
++	return 1;
++}
++
++/**
++ * This funcion stalls EP0.
++ */
++static inline void ep0_do_stall(dwc_otg_pcd_t * pcd, const int err_val)
++{
++	dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
++//	usb_device_request_t *ctrl = &pcd->setup_pkt->req;
++//	DWC_WARN("req %02x.%02x protocol STALL; err %d\n",
++//		 ctrl->bmRequestType, ctrl->bRequest, err_val);
++
++	ep0->dwc_ep.is_in = 1;
++	dwc_otg_ep_set_stall(GET_CORE_IF(pcd), &ep0->dwc_ep);
++	ep0->dwc_ep.is_in = 0;
++    dwc_otg_ep_set_stall(GET_CORE_IF(pcd), &ep0->dwc_ep);
++	pcd->ep0.stopped = 1;
++	pcd->ep0state = EP0_IDLE;
++	ep0_out_start(GET_CORE_IF(pcd), pcd);
++}
++
++/**
++ * This functions delegates the setup command to the gadget driver.
++ */
++static inline void do_gadget_setup(dwc_otg_pcd_t * pcd,
++				   usb_device_request_t * ctrl)
++{
++	int ret = 0;
++	DWC_SPINUNLOCK(pcd->lock);
++	ret = pcd->fops->setup(pcd, (uint8_t *) ctrl);
++	DWC_SPINLOCK(pcd->lock);
++	if (ret < 0) {
++		ep0_do_stall(pcd, ret);
++	}
++
++	/** @todo This is a g_file_storage gadget driver specific
++	 * workaround: a DELAYED_STATUS result from the fsg_setup
++	 * routine will result in the gadget queueing a EP0 IN status
++	 * phase for a two-stage control transfer. Exactly the same as
++	 * a SET_CONFIGURATION/SET_INTERFACE except that this is a class
++	 * specific request.  Need a generic way to know when the gadget
++	 * driver will queue the status phase. Can we assume when we
++	 * call the gadget driver setup() function that it will always
++	 * queue and require the following flag? Need to look into
++	 * this.
++	 */
++
++	if (ret == 256 + 999) {
++		pcd->request_config = 1;
++	}
++}
++
++#ifdef DWC_UTE_CFI
++/**
++ * This functions delegates the CFI setup commands to the gadget driver.
++ * This function will return a negative value to indicate a failure.
++ */
++static inline int cfi_gadget_setup(dwc_otg_pcd_t * pcd,
++				   struct cfi_usb_ctrlrequest *ctrl_req)
++{
++	int ret = 0;
++
++	if (pcd->fops && pcd->fops->cfi_setup) {
++		DWC_SPINUNLOCK(pcd->lock);
++		ret = pcd->fops->cfi_setup(pcd, ctrl_req);
++		DWC_SPINLOCK(pcd->lock);
++		if (ret < 0) {
++			ep0_do_stall(pcd, ret);
++			return ret;
++		}
++	}
++
++	return ret;
++}
++#endif
++
++/**
++ * This function starts the Zero-Length Packet for the IN status phase
++ * of a 2 stage control transfer.
++ */
++static inline void do_setup_in_status_phase(dwc_otg_pcd_t * pcd)
++{
++	dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
++	if (pcd->ep0state == EP0_STALL) {
++		return;
++	}
++
++	pcd->ep0state = EP0_IN_STATUS_PHASE;
++
++	/* Prepare for more SETUP Packets */
++	DWC_DEBUGPL(DBG_PCD, "EP0 IN ZLP\n");
++	if ((GET_CORE_IF(pcd)->snpsid >= OTG_CORE_REV_3_00a)
++	    && (pcd->core_if->dma_desc_enable)
++	    && (ep0->dwc_ep.xfer_count < ep0->dwc_ep.total_len)) {
++		DWC_DEBUGPL(DBG_PCDV,
++			    "Data terminated wait next packet in out_desc_addr\n");
++		pcd->backup_buf = phys_to_virt(ep0->dwc_ep.dma_addr);
++		pcd->data_terminated = 1;
++	}
++	ep0->dwc_ep.xfer_len = 0;
++	ep0->dwc_ep.xfer_count = 0;
++	ep0->dwc_ep.is_in = 1;
++	ep0->dwc_ep.dma_addr = pcd->setup_pkt_dma_handle;
++	dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd), &ep0->dwc_ep);
++
++	/* Prepare for more SETUP Packets */
++	//ep0_out_start(GET_CORE_IF(pcd), pcd);
++}
++
++/**
++ * This function starts the Zero-Length Packet for the OUT status phase
++ * of a 2 stage control transfer.
++ */
++static inline void do_setup_out_status_phase(dwc_otg_pcd_t * pcd)
++{
++	dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
++	doepint_data_t doepint;
++	doepint.d32 = DWC_READ_REG32(&pcd->core_if->dev_if->out_ep_regs[0]->doepint);
++	if (pcd->ep0state == EP0_STALL) {
++		DWC_DEBUGPL(DBG_PCD, "EP0 STALLED\n");
++		return;
++	}
++	pcd->ep0state = EP0_OUT_STATUS_PHASE;
++
++	DWC_DEBUGPL(DBG_PCD, "EP0 OUT ZLP\n");
++	ep0->dwc_ep.xfer_len = 0;
++	ep0->dwc_ep.xfer_count = 0;
++	ep0->dwc_ep.is_in = 0;
++	ep0->dwc_ep.dma_addr = pcd->setup_pkt_dma_handle;
++	/* If there is xfercomplete on EP0 OUT do not start OUT Status stage.
++	 * xfercomplete means that ZLP was already received as EP0 OUT is enabled
++	 * during IN Data stage
++	 */
++	if ((doepint.b.xfercompl == 1) && (pcd->core_if->snpsid >= OTG_CORE_REV_3_00a)
++	    && (pcd->core_if->dma_enable == 1) && (pcd->core_if->dma_desc_enable == 0)) {
++		DWC_DEBUGPL(DBG_PCD, "Status stage already completed\n");
++		return;
++	}
++
++	dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd), &ep0->dwc_ep);
++
++	/* Prepare for more SETUP Packets */
++	if (GET_CORE_IF(pcd)->dma_enable == 0) {
++		ep0_out_start(GET_CORE_IF(pcd), pcd);
++	}
++}
++
++/**
++ * Clear the EP halt (STALL) and if pending requests start the
++ * transfer.
++ */
++static inline void pcd_clear_halt(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * ep)
++{
++	if (ep->dwc_ep.stall_clear_flag) {
++		/* Start Control Status Phase */
++		do_setup_in_status_phase(pcd);
++		return;
++	}
++
++	dwc_otg_ep_clear_stall(GET_CORE_IF(pcd), &ep->dwc_ep);
++
++	/* Reactive the EP */
++	dwc_otg_ep_activate(GET_CORE_IF(pcd), &ep->dwc_ep);
++	if (ep->stopped) {
++		ep->stopped = 0;
++		/* If there is a request in the EP queue start it */
++
++		/** @todo FIXME: this causes an EP mismatch in DMA mode.
++		 * epmismatch not yet implemented. */
++
++		/*
++		 * Above fixme is solved by implmenting a tasklet to call the
++		 * start_next_request(), outside of interrupt context at some
++		 * time after the current time, after a clear-halt setup packet.
++		 * Still need to implement ep mismatch in the future if a gadget
++		 * ever uses more than one endpoint at once
++		 */
++		ep->queue_sof = 1;
++		DWC_TASK_SCHEDULE(pcd->start_xfer_tasklet);
++	}
++	/* Start Control Status Phase */
++	do_setup_in_status_phase(pcd);
++}
++
++/**
++ * This function is called when the SET_FEATURE TEST_MODE Setup packet
++ * is sent from the host.  The Device Control register is written with
++ * the Test Mode bits set to the specified Test Mode.  This is done as
++ * a tasklet so that the "Status" phase of the control transfer
++ * completes before transmitting the TEST packets.
++ *
++ * @todo This has not been tested since the tasklet struct was put
++ * into the PCD struct!
++ *
++ */
++void do_test_mode(void *data)
++{
++	dctl_data_t dctl;
++	dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) data;
++	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
++	int test_mode = pcd->test_mode;
++
++//        DWC_WARN("%s() has not been tested since being rewritten!\n", __func__);
++
++	dctl.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dctl);
++	switch (test_mode) {
++	case 1:		// TEST_J
++		dctl.b.tstctl = 1;
++		break;
++
++	case 2:		// TEST_K
++		dctl.b.tstctl = 2;
++		break;
++
++	case 3:		// TEST_SE0_NAK
++		dctl.b.tstctl = 3;
++		break;
++
++	case 4:		// TEST_PACKET
++		dctl.b.tstctl = 4;
++		break;
++
++	case 5:		// TEST_FORCE_ENABLE
++		dctl.b.tstctl = 5;
++		break;
++	case 7:
++		dwc_otg_set_hnpreq(core_if, 1);
++	}
++	DWC_PRINTF("test mode = %d\n",test_mode);
++	core_if->test_mode = test_mode;
++	DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32);
++}
++
++/**
++ * This function process the GET_STATUS Setup Commands.
++ */
++static inline void do_get_status(dwc_otg_pcd_t * pcd)
++{
++	usb_device_request_t ctrl = pcd->setup_pkt->req;
++	dwc_otg_pcd_ep_t *ep;
++	dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
++	uint16_t *status = pcd->status_buf;
++	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
++
++#ifdef DEBUG_EP0
++	DWC_DEBUGPL(DBG_PCD,
++		    "GET_STATUS %02x.%02x v%04x i%04x l%04x\n",
++		    ctrl.bmRequestType, ctrl.bRequest,
++		    UGETW(ctrl.wValue), UGETW(ctrl.wIndex),
++		    UGETW(ctrl.wLength));
++#endif
++
++	switch (UT_GET_RECIPIENT(ctrl.bmRequestType)) {
++	case UT_DEVICE:
++		if (UGETW(ctrl.wIndex) == 0xF000) {	/* OTG Status selector */
++			DWC_PRINTF("wIndex - %d\n", UGETW(ctrl.wIndex));
++			DWC_PRINTF("OTG VERSION - %d\n", core_if->otg_ver);
++			DWC_PRINTF("OTG CAP - %d, %d\n",
++				   core_if->core_params->otg_cap,
++				   DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE);
++			if (core_if->otg_ver == 1
++			    && core_if->core_params->otg_cap ==
++			    DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE) {
++				uint8_t *otgsts = (uint8_t *) pcd->status_buf;
++				*otgsts = (core_if->otg_sts & 0x1);
++				pcd->ep0_pending = 1;
++				ep0->dwc_ep.start_xfer_buff =
++				    (uint8_t *) otgsts;
++				ep0->dwc_ep.xfer_buff = (uint8_t *) otgsts;
++				ep0->dwc_ep.dma_addr =
++				    pcd->status_buf_dma_handle;
++				ep0->dwc_ep.xfer_len = 1;
++				ep0->dwc_ep.xfer_count = 0;
++				ep0->dwc_ep.total_len = ep0->dwc_ep.xfer_len;
++				dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd),
++							   &ep0->dwc_ep);
++				return;
++			} else {
++				ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
++				return;
++			}
++			break;
++		} else {
++			*status = 0x1;	/* Self powered */
++			*status |= pcd->remote_wakeup_enable << 1;
++			break;
++		}
++	case UT_INTERFACE:
++		*status = 0;
++		break;
++
++	case UT_ENDPOINT:
++		ep = get_ep_by_addr(pcd, UGETW(ctrl.wIndex));
++		if (ep == 0 || UGETW(ctrl.wLength) > 2) {
++			ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
++			return;
++		}
++		/** @todo check for EP stall */
++		*status = ep->stopped;
++		break;
++	}
++	pcd->ep0_pending = 1;
++	ep0->dwc_ep.start_xfer_buff = (uint8_t *) status;
++	ep0->dwc_ep.xfer_buff = (uint8_t *) status;
++	ep0->dwc_ep.dma_addr = pcd->status_buf_dma_handle;
++	ep0->dwc_ep.xfer_len = 2;
++	ep0->dwc_ep.xfer_count = 0;
++	ep0->dwc_ep.total_len = ep0->dwc_ep.xfer_len;
++	dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd), &ep0->dwc_ep);
++}
++
++/**
++ * This function process the SET_FEATURE Setup Commands.
++ */
++static inline void do_set_feature(dwc_otg_pcd_t * pcd)
++{
++	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
++	dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
++	usb_device_request_t ctrl = pcd->setup_pkt->req;
++	dwc_otg_pcd_ep_t *ep = 0;
++	int32_t otg_cap_param = core_if->core_params->otg_cap;
++	gotgctl_data_t gotgctl = {.d32 = 0 };
++	gintmsk_data_t gintmsk = {.d32 = 0 };
++
++	DWC_DEBUGPL(DBG_PCD, "SET_FEATURE:%02x.%02x v%04x i%04x l%04x\n",
++		    ctrl.bmRequestType, ctrl.bRequest,
++		    UGETW(ctrl.wValue), UGETW(ctrl.wIndex),
++		    UGETW(ctrl.wLength));
++	DWC_DEBUGPL(DBG_PCD, "otg_cap=%d\n", otg_cap_param);
++
++	switch (UT_GET_RECIPIENT(ctrl.bmRequestType)) {
++	case UT_DEVICE:
++		switch (UGETW(ctrl.wValue)) {
++		case UF_DEVICE_REMOTE_WAKEUP:
++			pcd->remote_wakeup_enable = 1;
++			break;
++
++		case UF_TEST_MODE:
++			/* Setup the Test Mode tasklet to do the Test
++			 * Packet generation after the SETUP Status
++			 * phase has completed. */
++
++			/** @todo This has not been tested since the
++			 * tasklet struct was put into the PCD
++			 * struct! */
++			pcd->test_mode = UGETW(ctrl.wIndex) >> 8;
++			DWC_TASK_SCHEDULE(pcd->test_mode_tasklet);
++			break;
++
++		case UF_DEVICE_B_HNP_ENABLE:
++			DWC_DEBUGPL(DBG_PCDV,
++				    "SET_FEATURE: USB_DEVICE_B_HNP_ENABLE\n");
++
++			/* dev may initiate HNP */
++			if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE) {
++				gotgctl.b.devhnpen = 1;
++				if (core_if->otg_ver) {
++					DWC_MODIFY_REG32(&global_regs->gotgctl, 0, gotgctl.d32);
++					/* Ensure that USB Suspend interrupt is unmasked */
++					gintmsk.b.usbsuspend = 1;
++					DWC_MODIFY_REG32(&global_regs->gintmsk, 0, gintmsk.d32);
++				}
++				else {
++					pcd->b_hnp_enable = 1;
++					dwc_otg_pcd_update_otg(pcd, 0);
++					DWC_DEBUGPL(DBG_PCD, "Request B HNP\n");
++					/**@todo Is the gotgctl.devhnpen cleared
++					 * by a USB Reset? */
++					gotgctl.b.hnpreq = 1;
++					DWC_WRITE_REG32(&global_regs->gotgctl, gotgctl.d32);
++				}
++			} else {
++				ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
++				return;
++			}
++			break;
++
++		case UF_DEVICE_A_HNP_SUPPORT:
++			/* RH port supports HNP */
++			DWC_DEBUGPL(DBG_PCDV,
++				    "SET_FEATURE: USB_DEVICE_A_HNP_SUPPORT\n");
++			if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE) {
++				pcd->a_hnp_support = 1;
++				dwc_otg_pcd_update_otg(pcd, 0);
++			} else {
++				ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
++				return;
++			}
++			break;
++
++		case UF_DEVICE_A_ALT_HNP_SUPPORT:
++			/* other RH port does */
++			DWC_DEBUGPL(DBG_PCDV,
++				    "SET_FEATURE: USB_DEVICE_A_ALT_HNP_SUPPORT\n");
++			if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE) {
++				pcd->a_alt_hnp_support = 1;
++				dwc_otg_pcd_update_otg(pcd, 0);
++			} else {
++				ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
++				return;
++			}
++			break;
++
++		default:
++			ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
++			return;
++
++		}
++		do_setup_in_status_phase(pcd);
++		break;
++
++	case UT_INTERFACE:
++		do_gadget_setup(pcd, &ctrl);
++		break;
++
++	case UT_ENDPOINT:
++		if (UGETW(ctrl.wValue) == UF_ENDPOINT_HALT) {
++			ep = get_ep_by_addr(pcd, UGETW(ctrl.wIndex));
++			if (ep == 0) {
++				ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
++				return;
++			}
++			ep->stopped = 1;
++			dwc_otg_ep_set_stall(core_if, &ep->dwc_ep);
++		}
++		do_setup_in_status_phase(pcd);
++		break;
++	}
++}
++
++/**
++ * This function process the CLEAR_FEATURE Setup Commands.
++ */
++static inline void do_clear_feature(dwc_otg_pcd_t * pcd)
++{
++	usb_device_request_t ctrl = pcd->setup_pkt->req;
++	dwc_otg_pcd_ep_t *ep = 0;
++
++	DWC_DEBUGPL(DBG_PCD,
++		    "CLEAR_FEATURE:%02x.%02x v%04x i%04x l%04x\n",
++		    ctrl.bmRequestType, ctrl.bRequest,
++		    UGETW(ctrl.wValue), UGETW(ctrl.wIndex),
++		    UGETW(ctrl.wLength));
++
++	switch (UT_GET_RECIPIENT(ctrl.bmRequestType)) {
++	case UT_DEVICE:
++		switch (UGETW(ctrl.wValue)) {
++		case UF_DEVICE_REMOTE_WAKEUP:
++			pcd->remote_wakeup_enable = 0;
++			break;
++
++		case UF_TEST_MODE:
++			/** @todo Add CLEAR_FEATURE for TEST modes. */
++			break;
++
++		default:
++			ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
++			return;
++		}
++		do_setup_in_status_phase(pcd);
++		break;
++
++	case UT_ENDPOINT:
++		ep = get_ep_by_addr(pcd, UGETW(ctrl.wIndex));
++		if (ep == 0) {
++			ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
++			return;
++		}
++
++		pcd_clear_halt(pcd, ep);
++
++		break;
++	}
++}
++
++/**
++ * This function process the SET_ADDRESS Setup Commands.
++ */
++static inline void do_set_address(dwc_otg_pcd_t * pcd)
++{
++	dwc_otg_dev_if_t *dev_if = GET_CORE_IF(pcd)->dev_if;
++	usb_device_request_t ctrl = pcd->setup_pkt->req;
++
++	if (ctrl.bmRequestType == UT_DEVICE) {
++		dcfg_data_t dcfg = {.d32 = 0 };
++
++#ifdef DEBUG_EP0
++//                      DWC_DEBUGPL(DBG_PCDV, "SET_ADDRESS:%d\n", ctrl.wValue);
++#endif
++		dcfg.b.devaddr = UGETW(ctrl.wValue);
++		DWC_MODIFY_REG32(&dev_if->dev_global_regs->dcfg, 0, dcfg.d32);
++		do_setup_in_status_phase(pcd);
++	}
++}
++
++/**
++ *	This function processes SETUP commands. In Linux, the USB Command
++ *	processing is done in two places - the first being the PCD and the
++ *	second in the Gadget Driver (for example, the File-Backed Storage
++ *	Gadget Driver).
++ *
++ * <table>
++ * <tr><td>Command	</td><td>Driver </td><td>Description</td></tr>
++ *
++ * <tr><td>GET_STATUS </td><td>PCD </td><td>Command is processed as
++ * defined in chapter 9 of the USB 2.0 Specification chapter 9
++ * </td></tr>
++ *
++ * <tr><td>CLEAR_FEATURE </td><td>PCD </td><td>The Device and Endpoint
++ * requests are the ENDPOINT_HALT feature is procesed, all others the
++ * interface requests are ignored.</td></tr>
++ *
++ * <tr><td>SET_FEATURE </td><td>PCD </td><td>The Device and Endpoint
++ * requests are processed by the PCD.  Interface requests are passed
++ * to the Gadget Driver.</td></tr>
++ *
++ * <tr><td>SET_ADDRESS </td><td>PCD </td><td>Program the DCFG reg,
++ * with device address received </td></tr>
++ *
++ * <tr><td>GET_DESCRIPTOR </td><td>Gadget Driver </td><td>Return the
++ * requested descriptor</td></tr>
++ *
++ * <tr><td>SET_DESCRIPTOR </td><td>Gadget Driver </td><td>Optional -
++ * not implemented by any of the existing Gadget Drivers.</td></tr>
++ *
++ * <tr><td>SET_CONFIGURATION </td><td>Gadget Driver </td><td>Disable
++ * all EPs and enable EPs for new configuration.</td></tr>
++ *
++ * <tr><td>GET_CONFIGURATION </td><td>Gadget Driver </td><td>Return
++ * the current configuration</td></tr>
++ *
++ * <tr><td>SET_INTERFACE </td><td>Gadget Driver </td><td>Disable all
++ * EPs and enable EPs for new configuration.</td></tr>
++ *
++ * <tr><td>GET_INTERFACE </td><td>Gadget Driver </td><td>Return the
++ * current interface.</td></tr>
++ *
++ * <tr><td>SYNC_FRAME </td><td>PCD </td><td>Display debug
++ * message.</td></tr>
++ * </table>
++ *
++ * When the SETUP Phase Done interrupt occurs, the PCD SETUP commands are
++ * processed by pcd_setup. Calling the Function Driver's setup function from
++ * pcd_setup processes the gadget SETUP commands.
++ */
++static inline void pcd_setup(dwc_otg_pcd_t * pcd)
++{
++	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
++	dwc_otg_dev_if_t *dev_if = core_if->dev_if;
++	usb_device_request_t ctrl = pcd->setup_pkt->req;
++	dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
++
++	deptsiz0_data_t doeptsize0 = {.d32 = 0 };
++
++#ifdef DWC_UTE_CFI
++	int retval = 0;
++	struct cfi_usb_ctrlrequest cfi_req;
++#endif
++
++	doeptsize0.d32 = DWC_READ_REG32(&dev_if->out_ep_regs[0]->doeptsiz);
++
++	/** In BDMA more then 1 setup packet is not supported till 3.00a */
++	if (core_if->dma_enable && core_if->dma_desc_enable == 0
++	    && (doeptsize0.b.supcnt < 2)
++	    && (core_if->snpsid < OTG_CORE_REV_2_94a)) {
++		DWC_ERROR
++		    ("\n\n-----------	 CANNOT handle > 1 setup packet in DMA mode\n\n");
++	}
++	if ((core_if->snpsid >= OTG_CORE_REV_3_00a)
++	    && (core_if->dma_enable == 1) && (core_if->dma_desc_enable == 0)) {
++		if (doeptsize0.b.supcnt == 3 && ep0->dwc_ep.stp_rollover == 0) {
++			DWC_ERROR(" !!! Setup packet count was not updated by the core\n");
++			return;
++		}
++		ctrl =
++		    (pcd->setup_pkt +
++		     (3 - doeptsize0.b.supcnt - 1 +
++		      ep0->dwc_ep.stp_rollover))->req;
++	}
++#ifdef DEBUG_EP0
++	DWC_DEBUGPL(DBG_PCD, "SETUP %02x.%02x v%04x i%04x l%04x\n",
++		    ctrl.bmRequestType, ctrl.bRequest,
++		    UGETW(ctrl.wValue), UGETW(ctrl.wIndex),
++		    UGETW(ctrl.wLength));
++#endif
++
++	/* Clean up the request queue */
++	dwc_otg_request_nuke(ep0);
++	ep0->stopped = 0;
++
++	if (ctrl.bmRequestType & UE_DIR_IN) {
++		ep0->dwc_ep.is_in = 1;
++		pcd->ep0state = EP0_IN_DATA_PHASE;
++	} else {
++		ep0->dwc_ep.is_in = 0;
++		pcd->ep0state = EP0_OUT_DATA_PHASE;
++	}
++
++	if (UGETW(ctrl.wLength) == 0) {
++		ep0->dwc_ep.is_in = 1;
++		pcd->ep0state = EP0_IN_STATUS_PHASE;
++	}
++
++	if (UT_GET_TYPE(ctrl.bmRequestType) != UT_STANDARD) {
++
++#ifdef DWC_UTE_CFI
++		DWC_MEMCPY(&cfi_req, &ctrl, sizeof(usb_device_request_t));
++
++		//printk(KERN_ALERT "CFI: req_type=0x%02x; req=0x%02x\n",
++		ctrl.bRequestType, ctrl.bRequest);
++		if (UT_GET_TYPE(cfi_req.bRequestType) == UT_VENDOR) {
++			if (cfi_req.bRequest > 0xB0 && cfi_req.bRequest < 0xBF) {
++				retval = cfi_setup(pcd, &cfi_req);
++				if (retval < 0) {
++					ep0_do_stall(pcd, retval);
++					pcd->ep0_pending = 0;
++					return;
++				}
++
++				/* if need gadget setup then call it and check the retval */
++				if (pcd->cfi->need_gadget_att) {
++					retval =
++					    cfi_gadget_setup(pcd,
++							     &pcd->
++							     cfi->ctrl_req);
++					if (retval < 0) {
++						pcd->ep0_pending = 0;
++						return;
++					}
++				}
++
++				if (pcd->cfi->need_status_in_complete) {
++					do_setup_in_status_phase(pcd);
++				}
++				return;
++			}
++		}
++#endif
++
++		/* handle non-standard (class/vendor) requests in the gadget driver */
++		do_gadget_setup(pcd, &ctrl);
++		return;
++	}
++
++	/** @todo NGS: Handle bad setup packet? */
++
++///////////////////////////////////////////
++//// --- Standard Request handling --- ////
++
++	switch (ctrl.bRequest) {
++	case UR_GET_STATUS:
++		do_get_status(pcd);
++		break;
++
++	case UR_CLEAR_FEATURE:
++		do_clear_feature(pcd);
++		break;
++
++	case UR_SET_FEATURE:
++		do_set_feature(pcd);
++		break;
++
++	case UR_SET_ADDRESS:
++		do_set_address(pcd);
++		break;
++
++	case UR_SET_INTERFACE:
++	case UR_SET_CONFIG:
++//              _pcd->request_config = 1;       /* Configuration changed */
++		do_gadget_setup(pcd, &ctrl);
++		break;
++
++	case UR_SYNCH_FRAME:
++		do_gadget_setup(pcd, &ctrl);
++		break;
++
++	default:
++		/* Call the Gadget Driver's setup functions */
++		do_gadget_setup(pcd, &ctrl);
++		break;
++	}
++}
++
++/**
++ * This function completes the ep0 control transfer.
++ */
++static int32_t ep0_complete_request(dwc_otg_pcd_ep_t * ep)
++{
++	dwc_otg_core_if_t *core_if = GET_CORE_IF(ep->pcd);
++	dwc_otg_dev_if_t *dev_if = core_if->dev_if;
++	dwc_otg_dev_in_ep_regs_t *in_ep_regs =
++	    dev_if->in_ep_regs[ep->dwc_ep.num];
++#ifdef DEBUG_EP0
++	dwc_otg_dev_out_ep_regs_t *out_ep_regs =
++	    dev_if->out_ep_regs[ep->dwc_ep.num];
++#endif
++	deptsiz0_data_t deptsiz;
++	dev_dma_desc_sts_t desc_sts = {.d32 = 0 };
++	dwc_otg_pcd_request_t *req;
++	int is_last = 0;
++	dwc_otg_pcd_t *pcd = ep->pcd;
++
++#ifdef DWC_UTE_CFI
++	struct cfi_usb_ctrlrequest *ctrlreq;
++	int retval = -DWC_E_NOT_SUPPORTED;
++#endif
++
++	if (pcd->ep0_pending && DWC_CIRCLEQ_EMPTY(&ep->queue)) {
++		if (ep->dwc_ep.is_in) {
++#ifdef DEBUG_EP0
++			DWC_DEBUGPL(DBG_PCDV, "Do setup OUT status phase\n");
++#endif
++			do_setup_out_status_phase(pcd);
++		} else {
++#ifdef DEBUG_EP0
++			DWC_DEBUGPL(DBG_PCDV, "Do setup IN status phase\n");
++#endif
++
++#ifdef DWC_UTE_CFI
++			ctrlreq = &pcd->cfi->ctrl_req;
++
++			if (UT_GET_TYPE(ctrlreq->bRequestType) == UT_VENDOR) {
++				if (ctrlreq->bRequest > 0xB0
++				    && ctrlreq->bRequest < 0xBF) {
++
++					/* Return if the PCD failed to handle the request */
++					if ((retval =
++					     pcd->cfi->ops.
++					     ctrl_write_complete(pcd->cfi,
++								 pcd)) < 0) {
++						CFI_INFO
++						    ("ERROR setting a new value in the PCD(%d)\n",
++						     retval);
++						ep0_do_stall(pcd, retval);
++						pcd->ep0_pending = 0;
++						return 0;
++					}
++
++					/* If the gadget needs to be notified on the request */
++					if (pcd->cfi->need_gadget_att == 1) {
++						//retval = do_gadget_setup(pcd, &pcd->cfi->ctrl_req);
++						retval =
++						    cfi_gadget_setup(pcd,
++								     &pcd->cfi->
++								     ctrl_req);
++
++						/* Return from the function if the gadget failed to process
++						 * the request properly - this should never happen !!!
++						 */
++						if (retval < 0) {
++							CFI_INFO
++							    ("ERROR setting a new value in the gadget(%d)\n",
++							     retval);
++							pcd->ep0_pending = 0;
++							return 0;
++						}
++					}
++
++					CFI_INFO("%s: RETVAL=%d\n", __func__,
++						 retval);
++					/* If we hit here then the PCD and the gadget has properly
++					 * handled the request - so send the ZLP IN to the host.
++					 */
++					/* @todo: MAS - decide whether we need to start the setup
++					 * stage based on the need_setup value of the cfi object
++					 */
++					do_setup_in_status_phase(pcd);
++					pcd->ep0_pending = 0;
++					return 1;
++				}
++			}
++#endif
++
++			do_setup_in_status_phase(pcd);
++		}
++		pcd->ep0_pending = 0;
++		return 1;
++	}
++
++	if (DWC_CIRCLEQ_EMPTY(&ep->queue)) {
++		return 0;
++	}
++	req = DWC_CIRCLEQ_FIRST(&ep->queue);
++
++	if (pcd->ep0state == EP0_OUT_STATUS_PHASE
++	    || pcd->ep0state == EP0_IN_STATUS_PHASE) {
++		is_last = 1;
++	} else if (ep->dwc_ep.is_in) {
++		deptsiz.d32 = DWC_READ_REG32(&in_ep_regs->dieptsiz);
++		if (core_if->dma_desc_enable != 0)
++			desc_sts = dev_if->in_desc_addr->status;
++#ifdef DEBUG_EP0
++		DWC_DEBUGPL(DBG_PCDV, "%d len=%d  xfersize=%d pktcnt=%d\n",
++			    ep->dwc_ep.num, ep->dwc_ep.xfer_len,
++			    deptsiz.b.xfersize, deptsiz.b.pktcnt);
++#endif
++
++		if (((core_if->dma_desc_enable == 0)
++		     && (deptsiz.b.xfersize == 0))
++		    || ((core_if->dma_desc_enable != 0)
++			&& (desc_sts.b.bytes == 0))) {
++			req->actual = ep->dwc_ep.xfer_count;
++			/* Is a Zero Len Packet needed? */
++			if (req->sent_zlp) {
++#ifdef DEBUG_EP0
++				DWC_DEBUGPL(DBG_PCD, "Setup Rx ZLP\n");
++#endif
++				req->sent_zlp = 0;
++			}
++			do_setup_out_status_phase(pcd);
++		}
++	} else {
++		/* ep0-OUT */
++#ifdef DEBUG_EP0
++		deptsiz.d32 = DWC_READ_REG32(&out_ep_regs->doeptsiz);
++		DWC_DEBUGPL(DBG_PCDV, "%d len=%d xsize=%d pktcnt=%d\n",
++			    ep->dwc_ep.num, ep->dwc_ep.xfer_len,
++			    deptsiz.b.xfersize, deptsiz.b.pktcnt);
++#endif
++		req->actual = ep->dwc_ep.xfer_count;
++
++		/* Is a Zero Len Packet needed? */
++		if (req->sent_zlp) {
++#ifdef DEBUG_EP0
++			DWC_DEBUGPL(DBG_PCDV, "Setup Tx ZLP\n");
++#endif
++			req->sent_zlp = 0;
++		}
++		/* For older cores do setup in status phase in Slave/BDMA modes,
++		 * starting from 3.00 do that only in slave, and for DMA modes
++		 * just re-enable ep 0 OUT here*/
++		if (core_if->dma_enable == 0
++		    || (core_if->dma_desc_enable == 0
++			&& core_if->snpsid <= OTG_CORE_REV_2_94a)) {
++			do_setup_in_status_phase(pcd);
++		} else if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
++			DWC_DEBUGPL(DBG_PCDV,
++				    "Enable out ep before in status phase\n");
++			ep0_out_start(core_if, pcd);
++		}
++	}
++
++	/* Complete the request */
++	if (is_last) {
++		dwc_otg_request_done(ep, req, 0);
++		ep->dwc_ep.start_xfer_buff = 0;
++		ep->dwc_ep.xfer_buff = 0;
++		ep->dwc_ep.xfer_len = 0;
++		return 1;
++	}
++	return 0;
++}
++
++#ifdef DWC_UTE_CFI
++/**
++ * This function calculates traverses all the CFI DMA descriptors and
++ * and accumulates the bytes that are left to be transfered.
++ *
++ * @return The total bytes left to transfered, or a negative value as failure
++ */
++static inline int cfi_calc_desc_residue(dwc_otg_pcd_ep_t * ep)
++{
++	int32_t ret = 0;
++	int i;
++	struct dwc_otg_dma_desc *ddesc = NULL;
++	struct cfi_ep *cfiep;
++
++	/* See if the pcd_ep has its respective cfi_ep mapped */
++	cfiep = get_cfi_ep_by_pcd_ep(ep->pcd->cfi, ep);
++	if (!cfiep) {
++		CFI_INFO("%s: Failed to find ep\n", __func__);
++		return -1;
++	}
++
++	ddesc = ep->dwc_ep.descs;
++
++	for (i = 0; (i < cfiep->desc_count) && (i < MAX_DMA_DESCS_PER_EP); i++) {
++
++#if defined(PRINT_CFI_DMA_DESCS)
++		print_desc(ddesc, ep->ep.name, i);
++#endif
++		ret += ddesc->status.b.bytes;
++		ddesc++;
++	}
++
++	if (ret)
++		CFI_INFO("!!!!!!!!!! WARNING (%s) - residue=%d\n", __func__,
++			 ret);
++
++	return ret;
++}
++#endif
++
++/**
++ * This function completes the request for the EP. If there are
++ * additional requests for the EP in the queue they will be started.
++ */
++static void complete_ep(dwc_otg_pcd_ep_t * ep)
++{
++	dwc_otg_core_if_t *core_if = GET_CORE_IF(ep->pcd);
++	dwc_otg_dev_if_t *dev_if = core_if->dev_if;
++	dwc_otg_dev_in_ep_regs_t *in_ep_regs =
++	    dev_if->in_ep_regs[ep->dwc_ep.num];
++	deptsiz_data_t deptsiz;
++	dev_dma_desc_sts_t desc_sts;
++	dwc_otg_pcd_request_t *req = 0;
++	dwc_otg_dev_dma_desc_t *dma_desc;
++	uint32_t byte_count = 0;
++	int is_last = 0;
++	int i;
++
++	DWC_DEBUGPL(DBG_PCDV, "%s() %d-%s\n", __func__, ep->dwc_ep.num,
++		    (ep->dwc_ep.is_in ? "IN" : "OUT"));
++
++	/* Get any pending requests */
++	if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
++		req = DWC_CIRCLEQ_FIRST(&ep->queue);
++		if (!req) {
++			DWC_PRINTF("complete_ep 0x%p, req = NULL!\n", ep);
++			return;
++		}
++	} else {
++		DWC_PRINTF("complete_ep 0x%p, ep->queue empty!\n", ep);
++		return;
++	}
++
++	DWC_DEBUGPL(DBG_PCD, "Requests %d\n", ep->pcd->request_pending);
++
++	if (ep->dwc_ep.is_in) {
++		deptsiz.d32 = DWC_READ_REG32(&in_ep_regs->dieptsiz);
++
++		if (core_if->dma_enable) {
++			if (core_if->dma_desc_enable == 0) {
++				if (deptsiz.b.xfersize == 0
++				    && deptsiz.b.pktcnt == 0) {
++					byte_count =
++					    ep->dwc_ep.xfer_len -
++					    ep->dwc_ep.xfer_count;
++
++					ep->dwc_ep.xfer_buff += byte_count;
++					ep->dwc_ep.dma_addr += byte_count;
++					ep->dwc_ep.xfer_count += byte_count;
++
++					DWC_DEBUGPL(DBG_PCDV,
++						    "%d-%s len=%d  xfersize=%d pktcnt=%d\n",
++						    ep->dwc_ep.num,
++						    (ep->dwc_ep.
++						     is_in ? "IN" : "OUT"),
++						    ep->dwc_ep.xfer_len,
++						    deptsiz.b.xfersize,
++						    deptsiz.b.pktcnt);
++
++					if (ep->dwc_ep.xfer_len <
++					    ep->dwc_ep.total_len) {
++						dwc_otg_ep_start_transfer
++						    (core_if, &ep->dwc_ep);
++					} else if (ep->dwc_ep.sent_zlp) {
++						/*
++						 * This fragment of code should initiate 0
++						 * length transfer in case if it is queued
++						 * a transfer with size divisible to EPs max
++						 * packet size and with usb_request zero field
++						 * is set, which means that after data is transfered,
++						 * it is also should be transfered
++						 * a 0 length packet at the end. For Slave and
++						 * Buffer DMA modes in this case SW has
++						 * to initiate 2 transfers one with transfer size,
++						 * and the second with 0 size. For Descriptor
++						 * DMA mode SW is able to initiate a transfer,
++						 * which will handle all the packets including
++						 * the last  0 length.
++						 */
++						ep->dwc_ep.sent_zlp = 0;
++						dwc_otg_ep_start_zl_transfer
++						    (core_if, &ep->dwc_ep);
++					} else {
++						is_last = 1;
++					}
++				} else {
++					if (ep->dwc_ep.type ==
++					    DWC_OTG_EP_TYPE_ISOC) {
++						req->actual = 0;
++						dwc_otg_request_done(ep, req, 0);
++
++						ep->dwc_ep.start_xfer_buff = 0;
++						ep->dwc_ep.xfer_buff = 0;
++						ep->dwc_ep.xfer_len = 0;
++
++						/* If there is a request in the queue start it. */
++						start_next_request(ep);
++					} else
++						DWC_WARN
++						("Incomplete transfer (%d - %s [siz=%d pkt=%d])\n",
++						ep->dwc_ep.num,
++						(ep->dwc_ep.is_in ? "IN" : "OUT"),
++						deptsiz.b.xfersize,
++						deptsiz.b.pktcnt);
++				}
++			} else {
++				dma_desc = ep->dwc_ep.desc_addr;
++				byte_count = 0;
++				ep->dwc_ep.sent_zlp = 0;
++
++#ifdef DWC_UTE_CFI
++				CFI_INFO("%s: BUFFER_MODE=%d\n", __func__,
++					 ep->dwc_ep.buff_mode);
++				if (ep->dwc_ep.buff_mode != BM_STANDARD) {
++					int residue;
++
++					residue = cfi_calc_desc_residue(ep);
++					if (residue < 0)
++						return;
++
++					byte_count = residue;
++				} else {
++#endif
++					for (i = 0; i < ep->dwc_ep.desc_cnt;
++					     ++i) {
++						desc_sts = dma_desc->status;
++						byte_count += desc_sts.b.bytes;
++						dma_desc++;
++					}
++#ifdef DWC_UTE_CFI
++				}
++#endif
++				if (byte_count == 0) {
++					ep->dwc_ep.xfer_count =
++					    ep->dwc_ep.total_len;
++					is_last = 1;
++				} else {
++					DWC_WARN("Incomplete transfer\n");
++				}
++			}
++		} else {
++			if (deptsiz.b.xfersize == 0 && deptsiz.b.pktcnt == 0) {
++				DWC_DEBUGPL(DBG_PCDV,
++					    "%d-%s len=%d  xfersize=%d pktcnt=%d\n",
++					    ep->dwc_ep.num,
++					    ep->dwc_ep.is_in ? "IN" : "OUT",
++					    ep->dwc_ep.xfer_len,
++					    deptsiz.b.xfersize,
++					    deptsiz.b.pktcnt);
++
++				/*      Check if the whole transfer was completed,
++				 *      if no, setup transfer for next portion of data
++				 */
++				if (ep->dwc_ep.xfer_len < ep->dwc_ep.total_len) {
++					dwc_otg_ep_start_transfer(core_if,
++								  &ep->dwc_ep);
++				} else if (ep->dwc_ep.sent_zlp) {
++					/*
++					 * This fragment of code should initiate 0
++					 * length trasfer in case if it is queued
++					 * a trasfer with size divisible to EPs max
++					 * packet size and with usb_request zero field
++					 * is set, which means that after data is transfered,
++					 * it is also should be transfered
++					 * a 0 length packet at the end. For Slave and
++					 * Buffer DMA modes in this case SW has
++					 * to initiate 2 transfers one with transfer size,
++					 * and the second with 0 size. For Desriptor
++					 * DMA mode SW is able to initiate a transfer,
++					 * which will handle all the packets including
++					 * the last  0 legth.
++					 */
++					ep->dwc_ep.sent_zlp = 0;
++					dwc_otg_ep_start_zl_transfer(core_if,
++								     &ep->dwc_ep);
++				} else {
++					is_last = 1;
++				}
++			} else {
++				DWC_WARN
++				    ("Incomplete transfer (%d-%s [siz=%d pkt=%d])\n",
++				     ep->dwc_ep.num,
++				     (ep->dwc_ep.is_in ? "IN" : "OUT"),
++				     deptsiz.b.xfersize, deptsiz.b.pktcnt);
++			}
++		}
++	} else {
++		dwc_otg_dev_out_ep_regs_t *out_ep_regs =
++		    dev_if->out_ep_regs[ep->dwc_ep.num];
++		desc_sts.d32 = 0;
++		if (core_if->dma_enable) {
++			if (core_if->dma_desc_enable) {
++				dma_desc = ep->dwc_ep.desc_addr;
++				byte_count = 0;
++				ep->dwc_ep.sent_zlp = 0;
++
++#ifdef DWC_UTE_CFI
++				CFI_INFO("%s: BUFFER_MODE=%d\n", __func__,
++					 ep->dwc_ep.buff_mode);
++				if (ep->dwc_ep.buff_mode != BM_STANDARD) {
++					int residue;
++					residue = cfi_calc_desc_residue(ep);
++					if (residue < 0)
++						return;
++					byte_count = residue;
++				} else {
++#endif
++
++					for (i = 0; i < ep->dwc_ep.desc_cnt;
++					     ++i) {
++						desc_sts = dma_desc->status;
++						byte_count += desc_sts.b.bytes;
++						dma_desc++;
++					}
++
++#ifdef DWC_UTE_CFI
++				}
++#endif
++				/* Checking for interrupt Out transfers with not
++				 * dword aligned mps sizes
++				 */
++				if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_INTR &&
++				    (ep->dwc_ep.maxpacket % 4)) {
++					ep->dwc_ep.xfer_count =
++					    ep->dwc_ep.total_len - byte_count;
++					if ((ep->dwc_ep.xfer_len %
++					     ep->dwc_ep.maxpacket)
++					    && (ep->dwc_ep.xfer_len /
++						ep->dwc_ep.maxpacket <
++						MAX_DMA_DESC_CNT))
++						ep->dwc_ep.xfer_len -=
++						    (ep->dwc_ep.desc_cnt -
++						     1) * ep->dwc_ep.maxpacket +
++						    ep->dwc_ep.xfer_len %
++						    ep->dwc_ep.maxpacket;
++					else
++						ep->dwc_ep.xfer_len -=
++						    ep->dwc_ep.desc_cnt *
++						    ep->dwc_ep.maxpacket;
++					if (ep->dwc_ep.xfer_len > 0) {
++						dwc_otg_ep_start_transfer
++						    (core_if, &ep->dwc_ep);
++					} else {
++						is_last = 1;
++					}
++				} else {
++					ep->dwc_ep.xfer_count =
++					    ep->dwc_ep.total_len - byte_count +
++					    ((4 -
++					      (ep->dwc_ep.
++					       total_len & 0x3)) & 0x3);
++					is_last = 1;
++				}
++			} else {
++				deptsiz.d32 = 0;
++				deptsiz.d32 =
++				    DWC_READ_REG32(&out_ep_regs->doeptsiz);
++
++				byte_count = (ep->dwc_ep.xfer_len -
++					      ep->dwc_ep.xfer_count -
++					      deptsiz.b.xfersize);
++				ep->dwc_ep.xfer_buff += byte_count;
++				ep->dwc_ep.dma_addr += byte_count;
++				ep->dwc_ep.xfer_count += byte_count;
++
++				/*      Check if the whole transfer was completed,
++				 *      if no, setup transfer for next portion of data
++				 */
++				if (ep->dwc_ep.xfer_len < ep->dwc_ep.total_len) {
++					dwc_otg_ep_start_transfer(core_if,
++								  &ep->dwc_ep);
++				} else if (ep->dwc_ep.sent_zlp) {
++					/*
++					 * This fragment of code should initiate 0
++					 * length trasfer in case if it is queued
++					 * a trasfer with size divisible to EPs max
++					 * packet size and with usb_request zero field
++					 * is set, which means that after data is transfered,
++					 * it is also should be transfered
++					 * a 0 length packet at the end. For Slave and
++					 * Buffer DMA modes in this case SW has
++					 * to initiate 2 transfers one with transfer size,
++					 * and the second with 0 size. For Desriptor
++					 * DMA mode SW is able to initiate a transfer,
++					 * which will handle all the packets including
++					 * the last  0 legth.
++					 */
++					ep->dwc_ep.sent_zlp = 0;
++					dwc_otg_ep_start_zl_transfer(core_if,
++								     &ep->dwc_ep);
++				} else {
++					is_last = 1;
++				}
++			}
++		} else {
++			/*      Check if the whole transfer was completed,
++			 *      if no, setup transfer for next portion of data
++			 */
++			if (ep->dwc_ep.xfer_len < ep->dwc_ep.total_len) {
++				dwc_otg_ep_start_transfer(core_if, &ep->dwc_ep);
++			} else if (ep->dwc_ep.sent_zlp) {
++				/*
++				 * This fragment of code should initiate 0
++				 * length transfer in case if it is queued
++				 * a transfer with size divisible to EPs max
++				 * packet size and with usb_request zero field
++				 * is set, which means that after data is transfered,
++				 * it is also should be transfered
++				 * a 0 length packet at the end. For Slave and
++				 * Buffer DMA modes in this case SW has
++				 * to initiate 2 transfers one with transfer size,
++				 * and the second with 0 size. For Descriptor
++				 * DMA mode SW is able to initiate a transfer,
++				 * which will handle all the packets including
++				 * the last  0 length.
++				 */
++				ep->dwc_ep.sent_zlp = 0;
++				dwc_otg_ep_start_zl_transfer(core_if,
++							     &ep->dwc_ep);
++			} else {
++				is_last = 1;
++			}
++		}
++
++		DWC_DEBUGPL(DBG_PCDV,
++			    "addr %p,	 %d-%s len=%d cnt=%d xsize=%d pktcnt=%d\n",
++			    &out_ep_regs->doeptsiz, ep->dwc_ep.num,
++			    ep->dwc_ep.is_in ? "IN" : "OUT",
++			    ep->dwc_ep.xfer_len, ep->dwc_ep.xfer_count,
++			    deptsiz.b.xfersize, deptsiz.b.pktcnt);
++	}
++
++	/* Complete the request */
++	if (is_last) {
++#ifdef DWC_UTE_CFI
++		if (ep->dwc_ep.buff_mode != BM_STANDARD) {
++			req->actual = ep->dwc_ep.cfi_req_len - byte_count;
++		} else {
++#endif
++			req->actual = ep->dwc_ep.xfer_count;
++#ifdef DWC_UTE_CFI
++		}
++#endif
++		if (req->dw_align_buf) {
++			if (!ep->dwc_ep.is_in) {
++				dwc_memcpy(req->buf, req->dw_align_buf, req->length);
++			}
++			DWC_DMA_FREE(req->length, req->dw_align_buf,
++				     req->dw_align_buf_dma);
++		}
++
++		dwc_otg_request_done(ep, req, 0);
++
++		ep->dwc_ep.start_xfer_buff = 0;
++		ep->dwc_ep.xfer_buff = 0;
++		ep->dwc_ep.xfer_len = 0;
++
++		/* If there is a request in the queue start it. */
++		start_next_request(ep);
++	}
++}
++/**
++ * This function completes the request for the ISO EP in DDMA. If it is last
++ * descriptor and ep was disabled, then program already prepared(during ep_queue)
++ * descriptor chain if there are more requests to process
++ */
++static void complete_ddma_iso_ep(dwc_otg_pcd_ep_t * ep)
++{
++	dwc_otg_core_if_t *core_if = GET_CORE_IF(ep->pcd);
++	dev_dma_desc_sts_t desc_sts;
++	dwc_otg_pcd_request_t *req = 0;
++	dwc_otg_dev_dma_desc_t *dma_desc;
++	dwc_dma_t dma_desc_addr;
++	dwc_ep_t *dwc_ep;
++	uint32_t depdma;
++	uint32_t index;
++
++	DWC_DEBUGPL(DBG_PCDV, "%s() %d-%s\n", __func__, ep->dwc_ep.num,
++		    (ep->dwc_ep.is_in ? "IN" : "OUT"));
++	dwc_ep = &ep->dwc_ep;
++	if (dwc_ep->use_add_buf) {
++		dma_desc_addr = dwc_ep->dma_desc_addr;
++		dma_desc = dwc_ep->desc_addr;
++	} else {
++		dma_desc_addr = dwc_ep->dma_desc_addr1;
++		dma_desc = dwc_ep->desc_addr1;
++	}
++	/* Get any pending requests */
++	if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
++		req = DWC_CIRCLEQ_FIRST(&ep->queue);
++		if (!req) {
++			DWC_PRINTF("complete_ep 0x%p, req = NULL!\n", ep);
++			return;
++		}
++	} else {
++		DWC_PRINTF("complete_ep 0x%p, ep->queue empty!\n", ep);
++		return;
++	}
++
++	if (dwc_ep->is_in) {
++		depdma = DWC_READ_REG32(&core_if->dev_if->in_ep_regs[dwc_ep->num]->diepdma);
++		index = (depdma - dma_desc_addr)/sizeof(dwc_otg_dev_dma_desc_t) - 1;
++		desc_sts = dma_desc[index].status;
++		req->actual = req->length - desc_sts.b_iso_in.txbytes;
++	} else {
++		depdma = DWC_READ_REG32(&core_if->dev_if->out_ep_regs[dwc_ep->num]->doepdma);
++		index = (depdma - dma_desc_addr)/sizeof(dwc_otg_dev_dma_desc_t) - 1;
++		desc_sts = dma_desc[index].status;
++		if (req->length%4)
++			req->actual = req->length - desc_sts.b_iso_out.rxbytes + (4 - req->length%4);
++		else
++			req->actual = req->length - desc_sts.b_iso_out.rxbytes;
++	}
++
++	/* Complete the request */
++	dwc_otg_request_done(ep, req, 0);
++}
++
++#ifdef DWC_EN_ISOC
++
++/**
++ * This function BNA interrupt for Isochronous EPs
++ *
++ */
++static void dwc_otg_pcd_handle_iso_bna(dwc_otg_pcd_ep_t * ep)
++{
++	dwc_ep_t *dwc_ep = &ep->dwc_ep;
++	volatile uint32_t *addr;
++	depctl_data_t depctl = {.d32 = 0 };
++	dwc_otg_pcd_t *pcd = ep->pcd;
++	dwc_otg_dev_dma_desc_t *dma_desc;
++	int i;
++
++	dma_desc =
++	    dwc_ep->iso_desc_addr + dwc_ep->desc_cnt * (dwc_ep->proc_buf_num);
++
++	if (dwc_ep->is_in) {
++		dev_dma_desc_sts_t sts = {.d32 = 0 };
++		for (i = 0; i < dwc_ep->desc_cnt; ++i, ++dma_desc) {
++			sts.d32 = dma_desc->status.d32;
++			sts.b_iso_in.bs = BS_HOST_READY;
++			dma_desc->status.d32 = sts.d32;
++		}
++	} else {
++		dev_dma_desc_sts_t sts = {.d32 = 0 };
++		for (i = 0; i < dwc_ep->desc_cnt; ++i, ++dma_desc) {
++			sts.d32 = dma_desc->status.d32;
++			sts.b_iso_out.bs = BS_HOST_READY;
++			dma_desc->status.d32 = sts.d32;
++		}
++	}
++
++	if (dwc_ep->is_in == 0) {
++		addr =
++		    &GET_CORE_IF(pcd)->dev_if->out_ep_regs[dwc_ep->
++							   num]->doepctl;
++	} else {
++		addr =
++		    &GET_CORE_IF(pcd)->dev_if->in_ep_regs[dwc_ep->num]->diepctl;
++	}
++	depctl.b.epena = 1;
++	DWC_MODIFY_REG32(addr, depctl.d32, depctl.d32);
++}
++
++/**
++ * This function sets latest iso packet information(non-PTI mode)
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ * @param ep The EP to start the transfer on.
++ *
++ */
++void set_current_pkt_info(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
++{
++	deptsiz_data_t deptsiz = {.d32 = 0 };
++	dma_addr_t dma_addr;
++	uint32_t offset;
++
++	if (ep->proc_buf_num)
++		dma_addr = ep->dma_addr1;
++	else
++		dma_addr = ep->dma_addr0;
++
++	if (ep->is_in) {
++		deptsiz.d32 =
++		    DWC_READ_REG32(&core_if->dev_if->
++				   in_ep_regs[ep->num]->dieptsiz);
++		offset = ep->data_per_frame;
++	} else {
++		deptsiz.d32 =
++		    DWC_READ_REG32(&core_if->dev_if->
++				   out_ep_regs[ep->num]->doeptsiz);
++		offset =
++		    ep->data_per_frame +
++		    (0x4 & (0x4 - (ep->data_per_frame & 0x3)));
++	}
++
++	if (!deptsiz.b.xfersize) {
++		ep->pkt_info[ep->cur_pkt].length = ep->data_per_frame;
++		ep->pkt_info[ep->cur_pkt].offset =
++		    ep->cur_pkt_dma_addr - dma_addr;
++		ep->pkt_info[ep->cur_pkt].status = 0;
++	} else {
++		ep->pkt_info[ep->cur_pkt].length = ep->data_per_frame;
++		ep->pkt_info[ep->cur_pkt].offset =
++		    ep->cur_pkt_dma_addr - dma_addr;
++		ep->pkt_info[ep->cur_pkt].status = -DWC_E_NO_DATA;
++	}
++	ep->cur_pkt_addr += offset;
++	ep->cur_pkt_dma_addr += offset;
++	ep->cur_pkt++;
++}
++
++/**
++ * This function sets latest iso packet information(DDMA mode)
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ * @param dwc_ep The EP to start the transfer on.
++ *
++ */
++static void set_ddma_iso_pkts_info(dwc_otg_core_if_t * core_if,
++				   dwc_ep_t * dwc_ep)
++{
++	dwc_otg_dev_dma_desc_t *dma_desc;
++	dev_dma_desc_sts_t sts = {.d32 = 0 };
++	iso_pkt_info_t *iso_packet;
++	uint32_t data_per_desc;
++	uint32_t offset;
++	int i, j;
++
++	iso_packet = dwc_ep->pkt_info;
++
++	/** Reinit closed DMA Descriptors*/
++	/** ISO OUT EP */
++	if (dwc_ep->is_in == 0) {
++		dma_desc =
++		    dwc_ep->iso_desc_addr +
++		    dwc_ep->desc_cnt * dwc_ep->proc_buf_num;
++		offset = 0;
++
++		for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm;
++		     i += dwc_ep->pkt_per_frm) {
++			for (j = 0; j < dwc_ep->pkt_per_frm; ++j) {
++				data_per_desc =
++				    ((j + 1) * dwc_ep->maxpacket >
++				     dwc_ep->
++				     data_per_frame) ? dwc_ep->data_per_frame -
++				    j * dwc_ep->maxpacket : dwc_ep->maxpacket;
++				data_per_desc +=
++				    (data_per_desc % 4) ? (4 -
++							   data_per_desc %
++							   4) : 0;
++
++				sts.d32 = dma_desc->status.d32;
++
++				/* Write status in iso_packet_decsriptor  */
++				iso_packet->status =
++				    sts.b_iso_out.rxsts +
++				    (sts.b_iso_out.bs ^ BS_DMA_DONE);
++				if (iso_packet->status) {
++					iso_packet->status = -DWC_E_NO_DATA;
++				}
++
++				/* Received data length */
++				if (!sts.b_iso_out.rxbytes) {
++					iso_packet->length =
++					    data_per_desc -
++					    sts.b_iso_out.rxbytes;
++				} else {
++					iso_packet->length =
++					    data_per_desc -
++					    sts.b_iso_out.rxbytes + (4 -
++								     dwc_ep->data_per_frame
++								     % 4);
++				}
++
++				iso_packet->offset = offset;
++
++				offset += data_per_desc;
++				dma_desc++;
++				iso_packet++;
++			}
++		}
++
++		for (j = 0; j < dwc_ep->pkt_per_frm - 1; ++j) {
++			data_per_desc =
++			    ((j + 1) * dwc_ep->maxpacket >
++			     dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
++			    j * dwc_ep->maxpacket : dwc_ep->maxpacket;
++			data_per_desc +=
++			    (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
++
++			sts.d32 = dma_desc->status.d32;
++
++			/* Write status in iso_packet_decsriptor  */
++			iso_packet->status =
++			    sts.b_iso_out.rxsts +
++			    (sts.b_iso_out.bs ^ BS_DMA_DONE);
++			if (iso_packet->status) {
++				iso_packet->status = -DWC_E_NO_DATA;
++			}
++
++			/* Received data length */
++			iso_packet->length =
++			    dwc_ep->data_per_frame - sts.b_iso_out.rxbytes;
++
++			iso_packet->offset = offset;
++
++			offset += data_per_desc;
++			iso_packet++;
++			dma_desc++;
++		}
++
++		sts.d32 = dma_desc->status.d32;
++
++		/* Write status in iso_packet_decsriptor  */
++		iso_packet->status =
++		    sts.b_iso_out.rxsts + (sts.b_iso_out.bs ^ BS_DMA_DONE);
++		if (iso_packet->status) {
++			iso_packet->status = -DWC_E_NO_DATA;
++		}
++		/* Received data length */
++		if (!sts.b_iso_out.rxbytes) {
++			iso_packet->length =
++			    dwc_ep->data_per_frame - sts.b_iso_out.rxbytes;
++		} else {
++			iso_packet->length =
++			    dwc_ep->data_per_frame - sts.b_iso_out.rxbytes +
++			    (4 - dwc_ep->data_per_frame % 4);
++		}
++
++		iso_packet->offset = offset;
++	} else {
++/** ISO IN EP */
++
++		dma_desc =
++		    dwc_ep->iso_desc_addr +
++		    dwc_ep->desc_cnt * dwc_ep->proc_buf_num;
++
++		for (i = 0; i < dwc_ep->desc_cnt - 1; i++) {
++			sts.d32 = dma_desc->status.d32;
++
++			/* Write status in iso packet descriptor */
++			iso_packet->status =
++			    sts.b_iso_in.txsts +
++			    (sts.b_iso_in.bs ^ BS_DMA_DONE);
++			if (iso_packet->status != 0) {
++				iso_packet->status = -DWC_E_NO_DATA;
++
++			}
++			/* Bytes has been transfered */
++			iso_packet->length =
++			    dwc_ep->data_per_frame - sts.b_iso_in.txbytes;
++
++			dma_desc++;
++			iso_packet++;
++		}
++
++		sts.d32 = dma_desc->status.d32;
++		while (sts.b_iso_in.bs == BS_DMA_BUSY) {
++			sts.d32 = dma_desc->status.d32;
++		}
++
++		/* Write status in iso packet descriptor ??? do be done with ERROR codes */
++		iso_packet->status =
++		    sts.b_iso_in.txsts + (sts.b_iso_in.bs ^ BS_DMA_DONE);
++		if (iso_packet->status != 0) {
++			iso_packet->status = -DWC_E_NO_DATA;
++		}
++
++		/* Bytes has been transfered */
++		iso_packet->length =
++		    dwc_ep->data_per_frame - sts.b_iso_in.txbytes;
++	}
++}
++
++/**
++ * This function reinitialize DMA Descriptors for Isochronous transfer
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ * @param dwc_ep The EP to start the transfer on.
++ *
++ */
++static void reinit_ddma_iso_xfer(dwc_otg_core_if_t * core_if, dwc_ep_t * dwc_ep)
++{
++	int i, j;
++	dwc_otg_dev_dma_desc_t *dma_desc;
++	dma_addr_t dma_ad;
++	volatile uint32_t *addr;
++	dev_dma_desc_sts_t sts = {.d32 = 0 };
++	uint32_t data_per_desc;
++
++	if (dwc_ep->is_in == 0) {
++		addr = &core_if->dev_if->out_ep_regs[dwc_ep->num]->doepctl;
++	} else {
++		addr = &core_if->dev_if->in_ep_regs[dwc_ep->num]->diepctl;
++	}
++
++	if (dwc_ep->proc_buf_num == 0) {
++		/** Buffer 0 descriptors setup */
++		dma_ad = dwc_ep->dma_addr0;
++	} else {
++		/** Buffer 1 descriptors setup */
++		dma_ad = dwc_ep->dma_addr1;
++	}
++
++	/** Reinit closed DMA Descriptors*/
++	/** ISO OUT EP */
++	if (dwc_ep->is_in == 0) {
++		dma_desc =
++		    dwc_ep->iso_desc_addr +
++		    dwc_ep->desc_cnt * dwc_ep->proc_buf_num;
++
++		sts.b_iso_out.bs = BS_HOST_READY;
++		sts.b_iso_out.rxsts = 0;
++		sts.b_iso_out.l = 0;
++		sts.b_iso_out.sp = 0;
++		sts.b_iso_out.ioc = 0;
++		sts.b_iso_out.pid = 0;
++		sts.b_iso_out.framenum = 0;
++
++		for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm;
++		     i += dwc_ep->pkt_per_frm) {
++			for (j = 0; j < dwc_ep->pkt_per_frm; ++j) {
++				data_per_desc =
++				    ((j + 1) * dwc_ep->maxpacket >
++				     dwc_ep->
++				     data_per_frame) ? dwc_ep->data_per_frame -
++				    j * dwc_ep->maxpacket : dwc_ep->maxpacket;
++				data_per_desc +=
++				    (data_per_desc % 4) ? (4 -
++							   data_per_desc %
++							   4) : 0;
++				sts.b_iso_out.rxbytes = data_per_desc;
++				dma_desc->buf = dma_ad;
++				dma_desc->status.d32 = sts.d32;
++
++				dma_ad += data_per_desc;
++				dma_desc++;
++			}
++		}
++
++		for (j = 0; j < dwc_ep->pkt_per_frm - 1; ++j) {
++
++			data_per_desc =
++			    ((j + 1) * dwc_ep->maxpacket >
++			     dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
++			    j * dwc_ep->maxpacket : dwc_ep->maxpacket;
++			data_per_desc +=
++			    (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
++			sts.b_iso_out.rxbytes = data_per_desc;
++
++			dma_desc->buf = dma_ad;
++			dma_desc->status.d32 = sts.d32;
++
++			dma_desc++;
++			dma_ad += data_per_desc;
++		}
++
++		sts.b_iso_out.ioc = 1;
++		sts.b_iso_out.l = dwc_ep->proc_buf_num;
++
++		data_per_desc =
++		    ((j + 1) * dwc_ep->maxpacket >
++		     dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
++		    j * dwc_ep->maxpacket : dwc_ep->maxpacket;
++		data_per_desc +=
++		    (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
++		sts.b_iso_out.rxbytes = data_per_desc;
++
++		dma_desc->buf = dma_ad;
++		dma_desc->status.d32 = sts.d32;
++	} else {
++/** ISO IN EP */
++
++		dma_desc =
++		    dwc_ep->iso_desc_addr +
++		    dwc_ep->desc_cnt * dwc_ep->proc_buf_num;
++
++		sts.b_iso_in.bs = BS_HOST_READY;
++		sts.b_iso_in.txsts = 0;
++		sts.b_iso_in.sp = 0;
++		sts.b_iso_in.ioc = 0;
++		sts.b_iso_in.pid = dwc_ep->pkt_per_frm;
++		sts.b_iso_in.framenum = dwc_ep->next_frame;
++		sts.b_iso_in.txbytes = dwc_ep->data_per_frame;
++		sts.b_iso_in.l = 0;
++
++		for (i = 0; i < dwc_ep->desc_cnt - 1; i++) {
++			dma_desc->buf = dma_ad;
++			dma_desc->status.d32 = sts.d32;
++
++			sts.b_iso_in.framenum += dwc_ep->bInterval;
++			dma_ad += dwc_ep->data_per_frame;
++			dma_desc++;
++		}
++
++		sts.b_iso_in.ioc = 1;
++		sts.b_iso_in.l = dwc_ep->proc_buf_num;
++
++		dma_desc->buf = dma_ad;
++		dma_desc->status.d32 = sts.d32;
++
++		dwc_ep->next_frame =
++		    sts.b_iso_in.framenum + dwc_ep->bInterval * 1;
++	}
++	dwc_ep->proc_buf_num = (dwc_ep->proc_buf_num ^ 1) & 0x1;
++}
++
++/**
++ * This function is to handle Iso EP transfer complete interrupt
++ * in case Iso out packet was dropped
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ * @param dwc_ep The EP for wihich transfer complete was asserted
++ *
++ */
++static uint32_t handle_iso_out_pkt_dropped(dwc_otg_core_if_t * core_if,
++					   dwc_ep_t * dwc_ep)
++{
++	uint32_t dma_addr;
++	uint32_t drp_pkt;
++	uint32_t drp_pkt_cnt;
++	deptsiz_data_t deptsiz = {.d32 = 0 };
++	depctl_data_t depctl = {.d32 = 0 };
++	int i;
++
++	deptsiz.d32 =
++	    DWC_READ_REG32(&core_if->dev_if->
++			   out_ep_regs[dwc_ep->num]->doeptsiz);
++
++	drp_pkt = dwc_ep->pkt_cnt - deptsiz.b.pktcnt;
++	drp_pkt_cnt = dwc_ep->pkt_per_frm - (drp_pkt % dwc_ep->pkt_per_frm);
++
++	/* Setting dropped packets status */
++	for (i = 0; i < drp_pkt_cnt; ++i) {
++		dwc_ep->pkt_info[drp_pkt].status = -DWC_E_NO_DATA;
++		drp_pkt++;
++		deptsiz.b.pktcnt--;
++	}
++
++	if (deptsiz.b.pktcnt > 0) {
++		deptsiz.b.xfersize =
++		    dwc_ep->xfer_len - (dwc_ep->pkt_cnt -
++					deptsiz.b.pktcnt) * dwc_ep->maxpacket;
++	} else {
++		deptsiz.b.xfersize = 0;
++		deptsiz.b.pktcnt = 0;
++	}
++
++	DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[dwc_ep->num]->doeptsiz,
++			deptsiz.d32);
++
++	if (deptsiz.b.pktcnt > 0) {
++		if (dwc_ep->proc_buf_num) {
++			dma_addr =
++			    dwc_ep->dma_addr1 + dwc_ep->xfer_len -
++			    deptsiz.b.xfersize;
++		} else {
++			dma_addr =
++			    dwc_ep->dma_addr0 + dwc_ep->xfer_len -
++			    deptsiz.b.xfersize;;
++		}
++
++		DWC_WRITE_REG32(&core_if->dev_if->
++				out_ep_regs[dwc_ep->num]->doepdma, dma_addr);
++
++		/** Re-enable endpoint, clear nak  */
++		depctl.d32 = 0;
++		depctl.b.epena = 1;
++		depctl.b.cnak = 1;
++
++		DWC_MODIFY_REG32(&core_if->dev_if->
++				 out_ep_regs[dwc_ep->num]->doepctl, depctl.d32,
++				 depctl.d32);
++		return 0;
++	} else {
++		return 1;
++	}
++}
++
++/**
++ * This function sets iso packets information(PTI mode)
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ * @param ep The EP to start the transfer on.
++ *
++ */
++static uint32_t set_iso_pkts_info(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
++{
++	int i, j;
++	dma_addr_t dma_ad;
++	iso_pkt_info_t *packet_info = ep->pkt_info;
++	uint32_t offset;
++	uint32_t frame_data;
++	deptsiz_data_t deptsiz;
++
++	if (ep->proc_buf_num == 0) {
++		/** Buffer 0 descriptors setup */
++		dma_ad = ep->dma_addr0;
++	} else {
++		/** Buffer 1 descriptors setup */
++		dma_ad = ep->dma_addr1;
++	}
++
++	if (ep->is_in) {
++		deptsiz.d32 =
++		    DWC_READ_REG32(&core_if->dev_if->in_ep_regs[ep->num]->
++				   dieptsiz);
++	} else {
++		deptsiz.d32 =
++		    DWC_READ_REG32(&core_if->dev_if->out_ep_regs[ep->num]->
++				   doeptsiz);
++	}
++
++	if (!deptsiz.b.xfersize) {
++		offset = 0;
++		for (i = 0; i < ep->pkt_cnt; i += ep->pkt_per_frm) {
++			frame_data = ep->data_per_frame;
++			for (j = 0; j < ep->pkt_per_frm; ++j) {
++
++				/* Packet status - is not set as initially
++				 * it is set to 0 and if packet was sent
++				 successfully, status field will remain 0*/
++
++				/* Bytes has been transfered */
++				packet_info->length =
++				    (ep->maxpacket <
++				     frame_data) ? ep->maxpacket : frame_data;
++
++				/* Received packet offset */
++				packet_info->offset = offset;
++				offset += packet_info->length;
++				frame_data -= packet_info->length;
++
++				packet_info++;
++			}
++		}
++		return 1;
++	} else {
++		/* This is a workaround for in case of Transfer Complete with
++		 * PktDrpSts interrupts merging - in this case Transfer complete
++		 * interrupt for Isoc Out Endpoint is asserted without PktDrpSts
++		 * set and with DOEPTSIZ register non zero. Investigations showed,
++		 * that this happens when Out packet is dropped, but because of
++		 * interrupts merging during first interrupt handling PktDrpSts
++		 * bit is cleared and for next merged interrupts it is not reset.
++		 * In this case SW hadles the interrupt as if PktDrpSts bit is set.
++		 */
++		if (ep->is_in) {
++			return 1;
++		} else {
++			return handle_iso_out_pkt_dropped(core_if, ep);
++		}
++	}
++}
++
++/**
++ * This function is to handle Iso EP transfer complete interrupt
++ *
++ * @param pcd The PCD
++ * @param ep The EP for which transfer complete was asserted
++ *
++ */
++static void complete_iso_ep(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * ep)
++{
++	dwc_otg_core_if_t *core_if = GET_CORE_IF(ep->pcd);
++	dwc_ep_t *dwc_ep = &ep->dwc_ep;
++	uint8_t is_last = 0;
++
++	if (ep->dwc_ep.next_frame == 0xffffffff) {
++		DWC_WARN("Next frame is not set!\n");
++		return;
++	}
++
++	if (core_if->dma_enable) {
++		if (core_if->dma_desc_enable) {
++			set_ddma_iso_pkts_info(core_if, dwc_ep);
++			reinit_ddma_iso_xfer(core_if, dwc_ep);
++			is_last = 1;
++		} else {
++			if (core_if->pti_enh_enable) {
++				if (set_iso_pkts_info(core_if, dwc_ep)) {
++					dwc_ep->proc_buf_num =
++					    (dwc_ep->proc_buf_num ^ 1) & 0x1;
++					dwc_otg_iso_ep_start_buf_transfer
++					    (core_if, dwc_ep);
++					is_last = 1;
++				}
++			} else {
++				set_current_pkt_info(core_if, dwc_ep);
++				if (dwc_ep->cur_pkt >= dwc_ep->pkt_cnt) {
++					is_last = 1;
++					dwc_ep->cur_pkt = 0;
++					dwc_ep->proc_buf_num =
++					    (dwc_ep->proc_buf_num ^ 1) & 0x1;
++					if (dwc_ep->proc_buf_num) {
++						dwc_ep->cur_pkt_addr =
++						    dwc_ep->xfer_buff1;
++						dwc_ep->cur_pkt_dma_addr =
++						    dwc_ep->dma_addr1;
++					} else {
++						dwc_ep->cur_pkt_addr =
++						    dwc_ep->xfer_buff0;
++						dwc_ep->cur_pkt_dma_addr =
++						    dwc_ep->dma_addr0;
++					}
++
++				}
++				dwc_otg_iso_ep_start_frm_transfer(core_if,
++								  dwc_ep);
++			}
++		}
++	} else {
++		set_current_pkt_info(core_if, dwc_ep);
++		if (dwc_ep->cur_pkt >= dwc_ep->pkt_cnt) {
++			is_last = 1;
++			dwc_ep->cur_pkt = 0;
++			dwc_ep->proc_buf_num = (dwc_ep->proc_buf_num ^ 1) & 0x1;
++			if (dwc_ep->proc_buf_num) {
++				dwc_ep->cur_pkt_addr = dwc_ep->xfer_buff1;
++				dwc_ep->cur_pkt_dma_addr = dwc_ep->dma_addr1;
++			} else {
++				dwc_ep->cur_pkt_addr = dwc_ep->xfer_buff0;
++				dwc_ep->cur_pkt_dma_addr = dwc_ep->dma_addr0;
++			}
++
++		}
++		dwc_otg_iso_ep_start_frm_transfer(core_if, dwc_ep);
++	}
++	if (is_last)
++		dwc_otg_iso_buffer_done(pcd, ep, ep->iso_req_handle);
++}
++#endif /* DWC_EN_ISOC */
++
++/**
++ * This function handle BNA interrupt for Non Isochronous EPs
++ *
++ */
++static void dwc_otg_pcd_handle_noniso_bna(dwc_otg_pcd_ep_t * ep)
++{
++	dwc_ep_t *dwc_ep = &ep->dwc_ep;
++	volatile uint32_t *addr;
++	depctl_data_t depctl = {.d32 = 0 };
++	dwc_otg_pcd_t *pcd = ep->pcd;
++	dwc_otg_dev_dma_desc_t *dma_desc;
++	dev_dma_desc_sts_t sts = {.d32 = 0 };
++	dwc_otg_core_if_t *core_if = ep->pcd->core_if;
++	int i, start;
++
++	if (!dwc_ep->desc_cnt)
++		DWC_WARN("Ep%d %s Descriptor count = %d \n", dwc_ep->num,
++			 (dwc_ep->is_in ? "IN" : "OUT"), dwc_ep->desc_cnt);
++
++	if (core_if->core_params->cont_on_bna && !dwc_ep->is_in
++							&& dwc_ep->type != DWC_OTG_EP_TYPE_CONTROL) {
++		uint32_t doepdma;
++		dwc_otg_dev_out_ep_regs_t *out_regs =
++			core_if->dev_if->out_ep_regs[dwc_ep->num];
++		doepdma = DWC_READ_REG32(&(out_regs->doepdma));
++		start = (doepdma - dwc_ep->dma_desc_addr)/sizeof(dwc_otg_dev_dma_desc_t);
++		dma_desc = &(dwc_ep->desc_addr[start]);
++	} else {
++		start = 0;
++		dma_desc = dwc_ep->desc_addr;
++	}
++
++
++	for (i = start; i < dwc_ep->desc_cnt; ++i, ++dma_desc) {
++		sts.d32 = dma_desc->status.d32;
++		sts.b.bs = BS_HOST_READY;
++		dma_desc->status.d32 = sts.d32;
++	}
++
++	if (dwc_ep->is_in == 0) {
++		addr =
++		    &GET_CORE_IF(pcd)->dev_if->out_ep_regs[dwc_ep->num]->
++		    doepctl;
++	} else {
++		addr =
++		    &GET_CORE_IF(pcd)->dev_if->in_ep_regs[dwc_ep->num]->diepctl;
++	}
++	depctl.b.epena = 1;
++	depctl.b.cnak = 1;
++	DWC_MODIFY_REG32(addr, 0, depctl.d32);
++}
++
++/**
++ * This function handles EP0 Control transfers.
++ *
++ * The state of the control transfers are tracked in
++ * <code>ep0state</code>.
++ */
++static void handle_ep0(dwc_otg_pcd_t * pcd)
++{
++	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
++	dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
++	dev_dma_desc_sts_t desc_sts;
++	deptsiz0_data_t deptsiz;
++	uint32_t byte_count;
++
++#ifdef DEBUG_EP0
++	DWC_DEBUGPL(DBG_PCDV, "%s()\n", __func__);
++	print_ep0_state(pcd);
++#endif
++
++	switch (pcd->ep0state) {
++	case EP0_DISCONNECT:
++		break;
++
++	case EP0_IDLE:
++		pcd->request_config = 0;
++
++		pcd_setup(pcd);
++		break;
++
++	case EP0_IN_DATA_PHASE:
++#ifdef DEBUG_EP0
++		DWC_DEBUGPL(DBG_PCD, "DATA_IN EP%d-%s: type=%d, mps=%d\n",
++			    ep0->dwc_ep.num, (ep0->dwc_ep.is_in ? "IN" : "OUT"),
++			    ep0->dwc_ep.type, ep0->dwc_ep.maxpacket);
++#endif
++
++		if (core_if->dma_enable != 0) {
++			/*
++			 * For EP0 we can only program 1 packet at a time so we
++			 * need to do the make calculations after each complete.
++			 * Call write_packet to make the calculations, as in
++			 * slave mode, and use those values to determine if we
++			 * can complete.
++			 */
++			if (core_if->dma_desc_enable == 0) {
++				deptsiz.d32 =
++				    DWC_READ_REG32(&core_if->
++						   dev_if->in_ep_regs[0]->
++						   dieptsiz);
++				byte_count =
++				    ep0->dwc_ep.xfer_len - deptsiz.b.xfersize;
++			} else {
++				desc_sts =
++				    core_if->dev_if->in_desc_addr->status;
++				byte_count =
++				    ep0->dwc_ep.xfer_len - desc_sts.b.bytes;
++			}
++			ep0->dwc_ep.xfer_count += byte_count;
++			ep0->dwc_ep.xfer_buff += byte_count;
++			ep0->dwc_ep.dma_addr += byte_count;
++		}
++		if (ep0->dwc_ep.xfer_count < ep0->dwc_ep.total_len) {
++			dwc_otg_ep0_continue_transfer(GET_CORE_IF(pcd),
++						      &ep0->dwc_ep);
++			DWC_DEBUGPL(DBG_PCD, "CONTINUE TRANSFER\n");
++		} else if (ep0->dwc_ep.sent_zlp) {
++			dwc_otg_ep0_continue_transfer(GET_CORE_IF(pcd),
++						      &ep0->dwc_ep);
++			ep0->dwc_ep.sent_zlp = 0;
++			DWC_DEBUGPL(DBG_PCD, "CONTINUE TRANSFER sent zlp\n");
++		} else {
++			ep0_complete_request(ep0);
++			DWC_DEBUGPL(DBG_PCD, "COMPLETE TRANSFER\n");
++		}
++		break;
++	case EP0_OUT_DATA_PHASE:
++#ifdef DEBUG_EP0
++		DWC_DEBUGPL(DBG_PCD, "DATA_OUT EP%d-%s: type=%d, mps=%d\n",
++			    ep0->dwc_ep.num, (ep0->dwc_ep.is_in ? "IN" : "OUT"),
++			    ep0->dwc_ep.type, ep0->dwc_ep.maxpacket);
++#endif
++		if (core_if->dma_enable != 0) {
++			if (core_if->dma_desc_enable == 0) {
++				deptsiz.d32 =
++				    DWC_READ_REG32(&core_if->
++						   dev_if->out_ep_regs[0]->
++						   doeptsiz);
++				byte_count =
++				    ep0->dwc_ep.maxpacket - deptsiz.b.xfersize;
++			} else {
++				desc_sts =
++				    core_if->dev_if->out_desc_addr->status;
++				byte_count =
++				    ep0->dwc_ep.maxpacket - desc_sts.b.bytes;
++			}
++			ep0->dwc_ep.xfer_count += byte_count;
++			ep0->dwc_ep.xfer_buff += byte_count;
++			ep0->dwc_ep.dma_addr += byte_count;
++		}
++		if (ep0->dwc_ep.xfer_count < ep0->dwc_ep.total_len) {
++			dwc_otg_ep0_continue_transfer(GET_CORE_IF(pcd),
++						      &ep0->dwc_ep);
++			DWC_DEBUGPL(DBG_PCD, "CONTINUE TRANSFER\n");
++		} else if (ep0->dwc_ep.sent_zlp) {
++			dwc_otg_ep0_continue_transfer(GET_CORE_IF(pcd),
++						      &ep0->dwc_ep);
++			ep0->dwc_ep.sent_zlp = 0;
++			DWC_DEBUGPL(DBG_PCD, "CONTINUE TRANSFER sent zlp\n");
++		} else {
++			ep0_complete_request(ep0);
++			DWC_DEBUGPL(DBG_PCD, "COMPLETE TRANSFER\n");
++		}
++		break;
++
++	case EP0_IN_STATUS_PHASE:
++	case EP0_OUT_STATUS_PHASE:
++		DWC_DEBUGPL(DBG_PCD, "CASE: EP0_STATUS\n");
++		ep0_complete_request(ep0);
++		pcd->ep0state = EP0_IDLE;
++		ep0->stopped = 1;
++		ep0->dwc_ep.is_in = 0;	/* OUT for next SETUP */
++
++		/* Prepare for more SETUP Packets */
++		if (core_if->dma_enable) {
++			ep0_out_start(core_if, pcd);
++		}
++		break;
++
++	case EP0_STALL:
++		DWC_ERROR("EP0 STALLed, should not get here pcd_setup()\n");
++		break;
++	}
++#ifdef DEBUG_EP0
++	print_ep0_state(pcd);
++#endif
++}
++
++/**
++ * Restart transfer
++ */
++static void restart_transfer(dwc_otg_pcd_t * pcd, const uint32_t epnum)
++{
++	dwc_otg_core_if_t *core_if;
++	dwc_otg_dev_if_t *dev_if;
++	deptsiz_data_t dieptsiz = {.d32 = 0 };
++	dwc_otg_pcd_ep_t *ep;
++
++	ep = get_in_ep(pcd, epnum);
++	if (!ep)
++		return;
++
++#ifdef DWC_EN_ISOC
++	if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
++		return;
++	}
++#endif /* DWC_EN_ISOC  */
++
++	core_if = GET_CORE_IF(pcd);
++	dev_if = core_if->dev_if;
++
++	dieptsiz.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dieptsiz);
++
++	DWC_DEBUGPL(DBG_PCD, "xfer_buff=%p xfer_count=%0x xfer_len=%0x"
++		    " stopped=%d\n", ep->dwc_ep.xfer_buff,
++		    ep->dwc_ep.xfer_count, ep->dwc_ep.xfer_len, ep->stopped);
++	/*
++	 * If xfersize is 0 and pktcnt in not 0, resend the last packet.
++	 */
++	if (dieptsiz.b.pktcnt && dieptsiz.b.xfersize == 0 &&
++	    ep->dwc_ep.start_xfer_buff != 0) {
++		if (ep->dwc_ep.total_len <= ep->dwc_ep.maxpacket) {
++			ep->dwc_ep.xfer_count = 0;
++			ep->dwc_ep.xfer_buff = ep->dwc_ep.start_xfer_buff;
++			ep->dwc_ep.xfer_len = ep->dwc_ep.xfer_count;
++		} else {
++			ep->dwc_ep.xfer_count -= ep->dwc_ep.maxpacket;
++			/* convert packet size to dwords. */
++			ep->dwc_ep.xfer_buff -= ep->dwc_ep.maxpacket;
++			ep->dwc_ep.xfer_len = ep->dwc_ep.xfer_count;
++		}
++		ep->stopped = 0;
++		DWC_DEBUGPL(DBG_PCD, "xfer_buff=%p xfer_count=%0x "
++			    "xfer_len=%0x stopped=%d\n",
++			    ep->dwc_ep.xfer_buff,
++			    ep->dwc_ep.xfer_count, ep->dwc_ep.xfer_len,
++			    ep->stopped);
++		if (epnum == 0) {
++			dwc_otg_ep0_start_transfer(core_if, &ep->dwc_ep);
++		} else {
++			dwc_otg_ep_start_transfer(core_if, &ep->dwc_ep);
++		}
++	}
++}
++
++/*
++ * This function create new nextep sequnce based on Learn Queue.
++ *
++ * @param core_if Programming view of DWC_otg controller
++ */
++void predict_nextep_seq( dwc_otg_core_if_t * core_if)
++{
++	dwc_otg_device_global_regs_t *dev_global_regs =
++	    core_if->dev_if->dev_global_regs;
++	const uint32_t TOKEN_Q_DEPTH = core_if->hwcfg2.b.dev_token_q_depth;
++	/* Number of Token Queue Registers */
++	const int DTKNQ_REG_CNT = (TOKEN_Q_DEPTH + 7) / 8;
++	dtknq1_data_t dtknqr1;
++	uint32_t in_tkn_epnums[4];
++	uint8_t seqnum[MAX_EPS_CHANNELS];
++	uint8_t intkn_seq[TOKEN_Q_DEPTH];
++	grstctl_t resetctl = {.d32 = 0 };
++	uint8_t temp;
++	int ndx = 0;
++	int start = 0;
++	int end = 0;
++	int sort_done = 0;
++	int i = 0;
++	volatile uint32_t *addr = &dev_global_regs->dtknqr1;
++
++	DWC_DEBUGPL(DBG_PCD, "dev_token_q_depth=%d\n", TOKEN_Q_DEPTH);
++
++	/* Read the DTKNQ Registers */
++	for (i = 0; i < DTKNQ_REG_CNT; i++) {
++		in_tkn_epnums[i] = DWC_READ_REG32(addr);
++		DWC_DEBUGPL(DBG_PCDV, "DTKNQR%d=0x%08x\n", i + 1,
++			    in_tkn_epnums[i]);
++		if (addr == &dev_global_regs->dvbusdis) {
++			addr = &dev_global_regs->dtknqr3_dthrctl;
++		} else {
++			++addr;
++		}
++
++	}
++
++	/* Copy the DTKNQR1 data to the bit field. */
++	dtknqr1.d32 = in_tkn_epnums[0];
++	if (dtknqr1.b.wrap_bit) {
++		ndx = dtknqr1.b.intknwptr;
++		end = ndx - 1;
++		if (end < 0)
++			end = TOKEN_Q_DEPTH - 1;
++	} else {
++		ndx = 0;
++		end = dtknqr1.b.intknwptr - 1;
++		if (end < 0)
++			end = 0;
++	}
++	start = ndx;
++
++	/* Fill seqnum[] by initial values: EP number + 31 */
++	for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
++		seqnum[i] = i + 31;
++	}
++
++	/* Fill intkn_seq[] from in_tkn_epnums[0] */
++	for (i = 0; i < 6; i++)
++		intkn_seq[i] = (in_tkn_epnums[0] >> ((7 - i) * 4)) & 0xf;
++
++	if (TOKEN_Q_DEPTH > 6) {
++		/* Fill intkn_seq[] from in_tkn_epnums[1] */
++		for (i = 6; i < 14; i++)
++			intkn_seq[i] =
++			    (in_tkn_epnums[1] >> ((7 - (i - 6)) * 4)) & 0xf;
++	}
++
++	if (TOKEN_Q_DEPTH > 14) {
++		/* Fill intkn_seq[] from in_tkn_epnums[1] */
++		for (i = 14; i < 22; i++)
++			intkn_seq[i] =
++			    (in_tkn_epnums[2] >> ((7 - (i - 14)) * 4)) & 0xf;
++	}
++
++	if (TOKEN_Q_DEPTH > 22) {
++		/* Fill intkn_seq[] from in_tkn_epnums[1] */
++		for (i = 22; i < 30; i++)
++			intkn_seq[i] =
++			    (in_tkn_epnums[3] >> ((7 - (i - 22)) * 4)) & 0xf;
++	}
++
++	DWC_DEBUGPL(DBG_PCDV, "%s start=%d end=%d intkn_seq[]:\n", __func__,
++		    start, end);
++	for (i = 0; i < TOKEN_Q_DEPTH; i++)
++		DWC_DEBUGPL(DBG_PCDV, "%d\n", intkn_seq[i]);
++
++	/* Update seqnum based on intkn_seq[] */
++	i = 0;
++	do {
++		seqnum[intkn_seq[ndx]] = i;
++		ndx++;
++		i++;
++		if (ndx == TOKEN_Q_DEPTH)
++			ndx = 0;
++	} while (i < TOKEN_Q_DEPTH);
++
++	/* Mark non active EP's in seqnum[] by 0xff */
++	for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
++		if (core_if->nextep_seq[i] == 0xff)
++			seqnum[i] = 0xff;
++	}
++
++	/* Sort seqnum[] */
++	sort_done = 0;
++	while (!sort_done) {
++		sort_done = 1;
++		for (i = 0; i < core_if->dev_if->num_in_eps; i++) {
++			if (seqnum[i] > seqnum[i + 1]) {
++				temp = seqnum[i];
++				seqnum[i] = seqnum[i + 1];
++				seqnum[i + 1] = temp;
++				sort_done = 0;
++			}
++		}
++	}
++
++	ndx = start + seqnum[0];
++	if (ndx >= TOKEN_Q_DEPTH)
++		ndx = ndx % TOKEN_Q_DEPTH;
++	core_if->first_in_nextep_seq = intkn_seq[ndx];
++
++	/* Update seqnum[] by EP numbers  */
++	for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
++		ndx = start + i;
++		if (seqnum[i] < 31) {
++			ndx = start + seqnum[i];
++			if (ndx >= TOKEN_Q_DEPTH)
++				ndx = ndx % TOKEN_Q_DEPTH;
++			seqnum[i] = intkn_seq[ndx];
++		} else {
++			if (seqnum[i] < 0xff) {
++				seqnum[i] = seqnum[i] - 31;
++			} else {
++				break;
++			}
++		}
++	}
++
++	/* Update nextep_seq[] based on seqnum[] */
++	for (i = 0; i < core_if->dev_if->num_in_eps; i++) {
++		if (seqnum[i] != 0xff) {
++			if (seqnum[i + 1] != 0xff) {
++				core_if->nextep_seq[seqnum[i]] = seqnum[i + 1];
++			} else {
++				core_if->nextep_seq[seqnum[i]] = core_if->first_in_nextep_seq;
++				break;
++			}
++		} else {
++			break;
++		}
++	}
++
++	DWC_DEBUGPL(DBG_PCDV, "%s first_in_nextep_seq= %2d; nextep_seq[]:\n",
++		    __func__, core_if->first_in_nextep_seq);
++	for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
++		DWC_DEBUGPL(DBG_PCDV, "%2d\n", core_if->nextep_seq[i]);
++	}
++
++	/* Flush the Learning Queue */
++	resetctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->grstctl);
++	resetctl.b.intknqflsh = 1;
++	DWC_WRITE_REG32(&core_if->core_global_regs->grstctl, resetctl.d32);
++
++
++}
++
++/**
++ * handle the IN EP disable interrupt.
++ */
++static inline void handle_in_ep_disable_intr(dwc_otg_pcd_t * pcd,
++					     const uint32_t epnum)
++{
++	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
++	dwc_otg_dev_if_t *dev_if = core_if->dev_if;
++	deptsiz_data_t dieptsiz = {.d32 = 0 };
++	dctl_data_t dctl = {.d32 = 0 };
++	dwc_otg_pcd_ep_t *ep;
++	dwc_ep_t *dwc_ep;
++	gintmsk_data_t gintmsk_data;
++	depctl_data_t depctl;
++	uint32_t diepdma;
++	uint32_t remain_to_transfer = 0;
++	uint8_t i;
++	uint32_t xfer_size;
++
++	ep = get_in_ep(pcd, epnum);
++	if (!ep)
++		return;
++
++	dwc_ep = &ep->dwc_ep;
++	if (!dwc_ep)
++		return;
++
++	if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
++		dwc_otg_flush_tx_fifo(core_if, dwc_ep->tx_fifo_num);
++		complete_ep(ep);
++		return;
++	}
++
++	DWC_DEBUGPL(DBG_PCD, "diepctl%d=%0x\n", epnum,
++		    DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->diepctl));
++	dieptsiz.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dieptsiz);
++	depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->diepctl);
++
++	DWC_DEBUGPL(DBG_ANY, "pktcnt=%d size=%d\n",
++		    dieptsiz.b.pktcnt, dieptsiz.b.xfersize);
++
++	if ((core_if->start_predict == 0) || (depctl.b.eptype & 1)) {
++		if (ep->stopped) {
++			if (core_if->en_multiple_tx_fifo)
++				/* Flush the Tx FIFO */
++				dwc_otg_flush_tx_fifo(core_if, dwc_ep->tx_fifo_num);
++			/* Clear the Global IN NP NAK */
++			dctl.d32 = 0;
++			dctl.b.cgnpinnak = 1;
++			DWC_MODIFY_REG32(&dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32);
++			/* Restart the transaction */
++			if (dieptsiz.b.pktcnt != 0 || dieptsiz.b.xfersize != 0) {
++				restart_transfer(pcd, epnum);
++			}
++		} else {
++			/* Restart the transaction */
++			if (dieptsiz.b.pktcnt != 0 || dieptsiz.b.xfersize != 0) {
++				restart_transfer(pcd, epnum);
++			}
++			DWC_DEBUGPL(DBG_ANY, "STOPPED!!!\n");
++		}
++		return;
++	}
++
++	if (core_if->start_predict > 2) {	// NP IN EP
++		core_if->start_predict--;
++		return;
++	}
++
++	core_if->start_predict--;
++
++	if (core_if->start_predict == 1) {	// All NP IN Ep's disabled now
++
++		predict_nextep_seq(core_if);
++
++		/* Update all active IN EP's NextEP field based of nextep_seq[] */
++		for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
++			depctl.d32 =
++			    DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
++			if (core_if->nextep_seq[i] != 0xff) {	// Active NP IN EP
++				depctl.b.nextep = core_if->nextep_seq[i];
++				DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepctl, depctl.d32);
++			}
++		}
++		/* Flush Shared NP TxFIFO */
++		dwc_otg_flush_tx_fifo(core_if, 0);
++		/* Rewind buffers */
++		if (!core_if->dma_desc_enable) {
++			i = core_if->first_in_nextep_seq;
++			do {
++				ep = get_in_ep(pcd, i);
++				if (!ep)
++					return;
++
++				dieptsiz.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->dieptsiz);
++				xfer_size = ep->dwc_ep.total_len - ep->dwc_ep.xfer_count;
++				if (xfer_size > ep->dwc_ep.maxxfer)
++					xfer_size = ep->dwc_ep.maxxfer;
++				depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
++				if (dieptsiz.b.pktcnt != 0) {
++					if (xfer_size == 0) {
++						remain_to_transfer = 0;
++					} else {
++						if ((xfer_size % ep->dwc_ep.maxpacket) == 0) {
++							remain_to_transfer =
++								dieptsiz.b.pktcnt * ep->dwc_ep.maxpacket;
++						} else {
++							remain_to_transfer = ((dieptsiz.b.pktcnt -1) * ep->dwc_ep.maxpacket)
++								+ (xfer_size % ep->dwc_ep.maxpacket);
++						}
++					}
++					diepdma = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepdma);
++					dieptsiz.b.xfersize = remain_to_transfer;
++					DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->dieptsiz, dieptsiz.d32);
++					diepdma = ep->dwc_ep.dma_addr + (xfer_size - remain_to_transfer);
++					DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepdma, diepdma);
++				}
++				i = core_if->nextep_seq[i];
++			} while (i != core_if->first_in_nextep_seq);
++		} else { // dma_desc_enable
++				DWC_PRINTF("%s Learning Queue not supported in DDMA\n", __func__);
++		}
++
++		/* Restart transfers in predicted sequences */
++		i = core_if->first_in_nextep_seq;
++		do {
++			dieptsiz.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->dieptsiz);
++			depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
++			if (dieptsiz.b.pktcnt != 0) {
++				depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
++				depctl.b.epena = 1;
++				depctl.b.cnak = 1;
++				DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepctl, depctl.d32);
++			}
++			i = core_if->nextep_seq[i];
++		} while (i != core_if->first_in_nextep_seq);
++
++		/* Clear the global non-periodic IN NAK handshake */
++		dctl.d32 = 0;
++		dctl.b.cgnpinnak = 1;
++		DWC_MODIFY_REG32(&dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32);
++
++		/* Unmask EP Mismatch interrupt */
++		gintmsk_data.d32 = 0;
++		gintmsk_data.b.epmismatch = 1;
++		DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, 0, gintmsk_data.d32);
++
++		core_if->start_predict = 0;
++
++	}
++}
++
++/**
++ * Handler for the IN EP timeout handshake interrupt.
++ */
++static inline void handle_in_ep_timeout_intr(dwc_otg_pcd_t * pcd,
++					     const uint32_t epnum)
++{
++	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
++	dwc_otg_dev_if_t *dev_if = core_if->dev_if;
++
++#ifdef DEBUG
++	deptsiz_data_t dieptsiz = {.d32 = 0 };
++	uint32_t num = 0;
++#endif
++	dctl_data_t dctl = {.d32 = 0 };
++	dwc_otg_pcd_ep_t *ep;
++
++	gintmsk_data_t intr_mask = {.d32 = 0 };
++
++	ep = get_in_ep(pcd, epnum);
++	if (!ep)
++		return;
++
++	/* Disable the NP Tx Fifo Empty Interrrupt */
++	if (!core_if->dma_enable) {
++		intr_mask.b.nptxfempty = 1;
++		DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk,
++				 intr_mask.d32, 0);
++	}
++	/** @todo NGS Check EP type.
++	 * Implement for Periodic EPs */
++	/*
++	 * Non-periodic EP
++	 */
++	/* Enable the Global IN NAK Effective Interrupt */
++	intr_mask.b.ginnakeff = 1;
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, 0, intr_mask.d32);
++
++	/* Set Global IN NAK */
++	dctl.b.sgnpinnak = 1;
++	DWC_MODIFY_REG32(&dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32);
++
++	ep->stopped = 1;
++
++#ifdef DEBUG
++	dieptsiz.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[num]->dieptsiz);
++	DWC_DEBUGPL(DBG_ANY, "pktcnt=%d size=%d\n",
++		    dieptsiz.b.pktcnt, dieptsiz.b.xfersize);
++#endif
++
++#ifdef DISABLE_PERIODIC_EP
++	/*
++	 * Set the NAK bit for this EP to
++	 * start the disable process.
++	 */
++	diepctl.d32 = 0;
++	diepctl.b.snak = 1;
++	DWC_MODIFY_REG32(&dev_if->in_ep_regs[num]->diepctl, diepctl.d32,
++			 diepctl.d32);
++	ep->disabling = 1;
++	ep->stopped = 1;
++#endif
++}
++
++/**
++ * Handler for the IN EP NAK interrupt.
++ */
++static inline int32_t handle_in_ep_nak_intr(dwc_otg_pcd_t * pcd,
++					    const uint32_t epnum)
++{
++	/** @todo implement ISR */
++	dwc_otg_core_if_t *core_if;
++	diepmsk_data_t intr_mask = {.d32 = 0 };
++
++	DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", "IN EP NAK");
++	core_if = GET_CORE_IF(pcd);
++	intr_mask.b.nak = 1;
++
++	if (core_if->multiproc_int_enable) {
++		DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
++				 diepeachintmsk[epnum], intr_mask.d32, 0);
++	} else {
++		DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->diepmsk,
++				 intr_mask.d32, 0);
++	}
++
++	return 1;
++}
++
++/**
++ * Handler for the OUT EP Babble interrupt.
++ */
++static inline int32_t handle_out_ep_babble_intr(dwc_otg_pcd_t * pcd,
++						const uint32_t epnum)
++{
++	/** @todo implement ISR */
++	dwc_otg_core_if_t *core_if;
++	doepmsk_data_t intr_mask = {.d32 = 0 };
++
++	DWC_PRINTF("INTERRUPT Handler not implemented for %s\n",
++		   "OUT EP Babble");
++	core_if = GET_CORE_IF(pcd);
++	intr_mask.b.babble = 1;
++
++	if (core_if->multiproc_int_enable) {
++		DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
++				 doepeachintmsk[epnum], intr_mask.d32, 0);
++	} else {
++		DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->doepmsk,
++				 intr_mask.d32, 0);
++	}
++
++	return 1;
++}
++
++/**
++ * Handler for the OUT EP NAK interrupt.
++ */
++static inline int32_t handle_out_ep_nak_intr(dwc_otg_pcd_t * pcd,
++					     const uint32_t epnum)
++{
++	/** @todo implement ISR */
++	dwc_otg_core_if_t *core_if;
++	doepmsk_data_t intr_mask = {.d32 = 0 };
++
++	DWC_DEBUGPL(DBG_ANY, "INTERRUPT Handler not implemented for %s\n", "OUT EP NAK");
++	core_if = GET_CORE_IF(pcd);
++	intr_mask.b.nak = 1;
++
++	if (core_if->multiproc_int_enable) {
++		DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
++				 doepeachintmsk[epnum], intr_mask.d32, 0);
++	} else {
++		DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->doepmsk,
++				 intr_mask.d32, 0);
++	}
++
++	return 1;
++}
++
++/**
++ * Handler for the OUT EP NYET interrupt.
++ */
++static inline int32_t handle_out_ep_nyet_intr(dwc_otg_pcd_t * pcd,
++					      const uint32_t epnum)
++{
++	/** @todo implement ISR */
++	dwc_otg_core_if_t *core_if;
++	doepmsk_data_t intr_mask = {.d32 = 0 };
++
++	DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", "OUT EP NYET");
++	core_if = GET_CORE_IF(pcd);
++	intr_mask.b.nyet = 1;
++
++	if (core_if->multiproc_int_enable) {
++		DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
++				 doepeachintmsk[epnum], intr_mask.d32, 0);
++	} else {
++		DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->doepmsk,
++				 intr_mask.d32, 0);
++	}
++
++	return 1;
++}
++static void handle_xfercompl_iso_ddma (dwc_otg_dev_if_t *dev_if, dwc_otg_pcd_ep_t *ep)
++{
++	 depctl_data_t depctl;
++	 dwc_ep_t *dwc_ep;
++	 uint32_t doepdma;
++	 dwc_dma_t dma_desc_addr;
++	 dwc_otg_dev_dma_desc_t *dma_desc;
++	 int index = 0, i = 0;
++	 uint8_t epnum;
++
++	 dwc_ep = &ep->dwc_ep;
++	 epnum = dwc_ep->num;
++
++	 complete_ddma_iso_ep(ep);
++
++	 if (dwc_ep->is_in) {
++		 do {
++			 depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->diepctl);
++			 if (!depctl.b.epena)
++				 break;
++			 udelay(1);
++		 } while (i++ < 125);
++
++		 depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->diepctl);
++		 if (!depctl.b.epena) {
++			 if (dwc_ep->use_add_buf) {
++				 DWC_DEBUGPL(DBG_PCD, "go to second buffer \n");
++				 dwc_ep->use_add_buf = 0;
++				 dwc_ep->iso_desc_first = 0;
++				 if (dwc_ep->iso_desc_second) {
++					 depctl_data_t diepctl;
++					 DWC_WRITE_REG32(&dev_if->in_ep_regs[epnum]->diepdma,
++						 dwc_ep->dma_desc_addr1);
++					 diepctl.d32 = 0;
++					 diepctl.b.epena = 1;
++					 diepctl.b.cnak = 1;
++					 DWC_MODIFY_REG32(&dev_if->in_ep_regs[epnum]->diepctl,
++						 0, diepctl.d32);
++				 } else {
++					 DWC_DEBUGPL(DBG_PCD, "DDMA: No more ISOC requests 1\n");
++				 }
++			 } else {
++				 DWC_DEBUGPL(DBG_PCD, "go to first buffer \n");
++				 dwc_ep->use_add_buf = 1;
++				 dwc_ep->iso_desc_second = 0;
++				 if (dwc_ep->iso_desc_first) {
++					 depctl_data_t diepctl;
++					 DWC_WRITE_REG32(&dev_if->in_ep_regs[epnum]->diepdma,
++						 dwc_ep->dma_desc_addr);
++					 diepctl.d32 = 0;
++					 diepctl.b.epena = 1;
++					 diepctl.b.cnak = 1;
++					 DWC_MODIFY_REG32(&dev_if->in_ep_regs[epnum]->diepctl,
++						 0, diepctl.d32);
++				 } else {
++					 DWC_DEBUGPL(DBG_PCD, "DDMA: No more ISOC requests 2\n");
++				 }
++			 }
++		 }
++	 } else {
++		 depctl.d32 = DWC_READ_REG32(&dev_if->out_ep_regs[epnum]->doepctl);
++		 doepdma = DWC_READ_REG32(&dev_if->out_ep_regs[epnum]->doepdma);
++
++		 if (dwc_ep->use_add_buf) {
++			 index = dwc_ep->iso_desc_first;
++			 dma_desc_addr = dwc_ep->dma_desc_addr;
++		 } else {
++			 index = dwc_ep->iso_desc_second;
++			 dma_desc_addr = dwc_ep->dma_desc_addr1;
++		 }
++
++		 if (index == (doepdma - dma_desc_addr)/sizeof(dwc_otg_dev_dma_desc_t)) {
++			 depctl.d32 = 0;
++			 depctl.b.epdis = 1;
++			 DWC_MODIFY_REG32(&dev_if->out_ep_regs[epnum]->doepctl, 0, depctl.d32);
++		 }
++		 dma_desc = dwc_ep->desc_addr + dwc_ep->iso_desc_first;
++		 if (!depctl.b.epena) {
++			 if (dwc_ep->use_add_buf) {
++				 DWC_DEBUGPL(DBG_PCD, "go to second buffer \n");
++				 dwc_ep->use_add_buf = 0;
++				 dwc_ep->iso_desc_first = 0;
++				 if (dwc_ep->iso_desc_second) {
++					 DWC_WRITE_REG32(&dev_if->out_ep_regs[epnum]->doepdma, dwc_ep->dma_desc_addr1);
++					 depctl.d32 = 0;
++					 depctl.b.epena = 1;
++					 depctl.b.cnak = 1;
++					 DWC_MODIFY_REG32(&dev_if->out_ep_regs[epnum]->doepctl, 0, depctl.d32);
++				 } else {
++					 DWC_DEBUGPL(DBG_PCD, "DDMA: There are no more ISOC requests 1!!! \n");
++				 }
++			 } else {
++				 dwc_ep->use_add_buf = 1;
++				 dwc_ep->iso_desc_second = 0;
++				 if (dwc_ep->iso_desc_first) {
++					 DWC_DEBUGPL(DBG_PCD, "go to first buffer");
++					 DWC_WRITE_REG32(&dev_if->out_ep_regs[epnum]->doepdma, dwc_ep->dma_desc_addr);
++					 depctl.d32 = 0;
++					 depctl.b.epena = 1;
++					 depctl.b.cnak = 1;
++					 DWC_MODIFY_REG32(&dev_if->out_ep_regs[epnum]->doepctl, 0, depctl.d32);
++				 } else {
++					 DWC_DEBUGPL(DBG_PCD, "DDMA: There are no more ISOC requests 2!!! \n");
++				 }
++			 }
++		 }
++	 }
++}
++/**
++ * This interrupt indicates that an IN EP has a pending Interrupt.
++ * The sequence for handling the IN EP interrupt is shown below:
++ * -#	Read the Device All Endpoint Interrupt register
++ * -#	Repeat the following for each IN EP interrupt bit set (from
++ *		LSB to MSB).
++ * -#	Read the Device Endpoint Interrupt (DIEPINTn) register
++ * -#	If "Transfer Complete" call the request complete function
++ * -#	If "Endpoint Disabled" complete the EP disable procedure.
++ * -#	If "AHB Error Interrupt" log error
++ * -#	If "Time-out Handshake" log error
++ * -#	If "IN Token Received when TxFIFO Empty" write packet to Tx
++ *		FIFO.
++ * -#	If "IN Token EP Mismatch" (disable, this is handled by EP
++ *		Mismatch Interrupt)
++ */
++static int32_t dwc_otg_pcd_handle_in_ep_intr(dwc_otg_pcd_t * pcd)
++{
++#define CLEAR_IN_EP_INTR(__core_if,__epnum,__intr) \
++do { \
++		diepint_data_t diepint = {.d32=0}; \
++		diepint.b.__intr = 1; \
++		DWC_WRITE_REG32(&__core_if->dev_if->in_ep_regs[__epnum]->diepint, \
++		diepint.d32); \
++} while (0)
++
++	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
++	dwc_otg_dev_if_t *dev_if = core_if->dev_if;
++	diepint_data_t diepint = {.d32 = 0 };
++	depctl_data_t depctl = {.d32 = 0 };
++	uint32_t ep_intr;
++	uint32_t epnum = 0;
++	dwc_otg_pcd_ep_t *ep;
++	dwc_ep_t *dwc_ep;
++	gintmsk_data_t intr_mask = {.d32 = 0 };
++
++	DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, pcd);
++
++	/* Read in the device interrupt bits */
++	ep_intr = dwc_otg_read_dev_all_in_ep_intr(core_if);
++
++	/* Service the Device IN interrupts for each endpoint */
++	while (ep_intr) {
++		if (ep_intr & 0x1) {
++			uint32_t empty_msk;
++			/* Get EP pointer */
++			ep = get_in_ep(pcd, epnum);
++			if (!ep)
++				return -EINVAL;
++
++			dwc_ep = &ep->dwc_ep;
++			if (!dwc_ep)
++				return -EINVAL;
++
++			depctl.d32 =
++			    DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->diepctl);
++			empty_msk =
++			    DWC_READ_REG32(&dev_if->
++					   dev_global_regs->dtknqr4_fifoemptymsk);
++
++			DWC_DEBUGPL(DBG_PCDV,
++				    "IN EP INTERRUPT - %d\nepmty_msk - %8x  diepctl - %8x\n",
++				    epnum, empty_msk, depctl.d32);
++
++			DWC_DEBUGPL(DBG_PCD,
++				    "EP%d-%s: type=%d, mps=%d\n",
++				    dwc_ep->num, (dwc_ep->is_in ? "IN" : "OUT"),
++				    dwc_ep->type, dwc_ep->maxpacket);
++
++			diepint.d32 =
++			    dwc_otg_read_dev_in_ep_intr(core_if, dwc_ep);
++
++			DWC_DEBUGPL(DBG_PCDV,
++				    "EP %d Interrupt Register - 0x%x\n", epnum,
++				    diepint.d32);
++			/* Transfer complete */
++			if (diepint.b.xfercompl) {
++				/* Disable the NP Tx FIFO Empty
++				 * Interrupt */
++				if (core_if->en_multiple_tx_fifo == 0) {
++					intr_mask.b.nptxfempty = 1;
++					DWC_MODIFY_REG32
++					    (&core_if->core_global_regs->gintmsk,
++					     intr_mask.d32, 0);
++				} else {
++					/* Disable the Tx FIFO Empty Interrupt for this EP */
++					uint32_t fifoemptymsk =
++					    0x1 << dwc_ep->num;
++					DWC_MODIFY_REG32(&core_if->
++							 dev_if->dev_global_regs->dtknqr4_fifoemptymsk,
++							 fifoemptymsk, 0);
++				}
++				/* Clear the bit in DIEPINTn for this interrupt */
++				CLEAR_IN_EP_INTR(core_if, epnum, xfercompl);
++
++				/* Complete the transfer */
++				if (epnum == 0) {
++					handle_ep0(pcd);
++				}
++#ifdef DWC_EN_ISOC
++				else if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
++					if (!ep->stopped)
++						complete_iso_ep(pcd, ep);
++				}
++#endif /* DWC_EN_ISOC */
++#ifdef DWC_UTE_PER_IO
++				else if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
++					if (!ep->stopped)
++						complete_xiso_ep(ep);
++				}
++#endif /* DWC_UTE_PER_IO */
++				else {
++					if (core_if->dma_desc_enable && dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
++						handle_xfercompl_iso_ddma(dev_if, ep);
++					} else {
++						if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC &&
++								dwc_ep->bInterval > 1) {
++							dwc_ep->frame_num += dwc_ep->bInterval;
++							if (dwc_ep->frame_num > 0x3FFF)
++							{
++								dwc_ep->frm_overrun = 1;
++								dwc_ep->frame_num &= 0x3FFF;
++							} else
++								dwc_ep->frm_overrun = 0;
++						}
++						complete_ep(ep);
++						if(diepint.b.nak)
++							CLEAR_IN_EP_INTR(core_if, epnum, nak);
++					}
++				}
++			}
++			/* Endpoint disable      */
++			if (diepint.b.epdisabled) {
++				DWC_DEBUGPL(DBG_ANY, "EP%d IN disabled\n",
++					    epnum);
++				handle_in_ep_disable_intr(pcd, epnum);
++
++				/* Clear the bit in DIEPINTn for this interrupt */
++				CLEAR_IN_EP_INTR(core_if, epnum, epdisabled);
++			}
++			/* AHB Error */
++			if (diepint.b.ahberr) {
++				DWC_ERROR("EP%d IN AHB Error\n", epnum);
++				/* Clear the bit in DIEPINTn for this interrupt */
++				CLEAR_IN_EP_INTR(core_if, epnum, ahberr);
++			}
++			/* TimeOUT Handshake (non-ISOC IN EPs) */
++			if (diepint.b.timeout) {
++				DWC_ERROR("EP%d IN Time-out\n", epnum);
++				handle_in_ep_timeout_intr(pcd, epnum);
++
++				CLEAR_IN_EP_INTR(core_if, epnum, timeout);
++			}
++			/** IN Token received with TxF Empty */
++			if (diepint.b.intktxfemp) {
++				DWC_DEBUGPL(DBG_ANY,
++					    "EP%d IN TKN TxFifo Empty\n",
++					    epnum);
++				if (!ep->stopped && epnum != 0) {
++
++					diepmsk_data_t diepmsk = {.d32 = 0 };
++					diepmsk.b.intktxfemp = 1;
++
++					if (core_if->multiproc_int_enable) {
++						DWC_MODIFY_REG32
++						    (&dev_if->dev_global_regs->diepeachintmsk
++						     [epnum], diepmsk.d32, 0);
++					} else {
++						DWC_MODIFY_REG32
++						    (&dev_if->dev_global_regs->diepmsk,
++						     diepmsk.d32, 0);
++					}
++				} else if (core_if->dma_desc_enable
++					   && epnum == 0
++					   && pcd->ep0state ==
++					   EP0_OUT_STATUS_PHASE) {
++					// EP0 IN set STALL
++					depctl.d32 =
++					    DWC_READ_REG32(&dev_if->in_ep_regs
++							   [epnum]->diepctl);
++
++					/* set the disable and stall bits */
++					if (depctl.b.epena) {
++						depctl.b.epdis = 1;
++					}
++					depctl.b.stall = 1;
++					DWC_WRITE_REG32(&dev_if->in_ep_regs
++							[epnum]->diepctl,
++							depctl.d32);
++				}
++				CLEAR_IN_EP_INTR(core_if, epnum, intktxfemp);
++			}
++			/** IN Token Received with EP mismatch */
++			if (diepint.b.intknepmis) {
++				DWC_DEBUGPL(DBG_ANY,
++					    "EP%d IN TKN EP Mismatch\n", epnum);
++				CLEAR_IN_EP_INTR(core_if, epnum, intknepmis);
++			}
++			/** IN Endpoint NAK Effective */
++			if (diepint.b.inepnakeff) {
++				DWC_DEBUGPL(DBG_ANY,
++					    "EP%d IN EP NAK Effective\n",
++					    epnum);
++				/* Periodic EP */
++				if (ep->disabling) {
++					depctl.d32 = 0;
++					depctl.b.snak = 1;
++					depctl.b.epdis = 1;
++					DWC_MODIFY_REG32(&dev_if->in_ep_regs
++							 [epnum]->diepctl,
++							 depctl.d32,
++							 depctl.d32);
++				}
++				CLEAR_IN_EP_INTR(core_if, epnum, inepnakeff);
++
++			}
++
++			/** IN EP Tx FIFO Empty Intr */
++			if (diepint.b.emptyintr) {
++				DWC_DEBUGPL(DBG_ANY,
++					    "EP%d Tx FIFO Empty Intr \n",
++					    epnum);
++				write_empty_tx_fifo(pcd, epnum);
++
++				CLEAR_IN_EP_INTR(core_if, epnum, emptyintr);
++
++			}
++
++			/** IN EP BNA Intr */
++			if (diepint.b.bna) {
++				CLEAR_IN_EP_INTR(core_if, epnum, bna);
++				if (core_if->dma_desc_enable) {
++#ifdef DWC_EN_ISOC
++					if (dwc_ep->type ==
++					    DWC_OTG_EP_TYPE_ISOC) {
++						/*
++						 * This checking is performed to prevent first "false" BNA
++						 * handling occuring right after reconnect
++						 */
++						if (dwc_ep->next_frame !=
++						    0xffffffff)
++							dwc_otg_pcd_handle_iso_bna(ep);
++					} else
++#endif				/* DWC_EN_ISOC */
++					{
++						dwc_otg_pcd_handle_noniso_bna(ep);
++					}
++				}
++			}
++			/* NAK Interrupt */
++			if (diepint.b.nak) {
++				DWC_DEBUGPL(DBG_ANY, "EP%d IN NAK Interrupt\n",
++					    epnum);
++				if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
++					if (core_if->dma_desc_enable) {
++						if (ep->dwc_ep.frame_num == 0xFFFFFFFF) {
++							ep->dwc_ep.frame_num = core_if->frame_num;
++							dwc_otg_pcd_start_iso_ddma(core_if, ep);
++						} else {
++							ep->dwc_ep.frame_num = core_if->frame_num + ep->dwc_ep.bInterval;
++							CLEAR_IN_EP_INTR(core_if, epnum, nak);
++						}
++					} else {
++						depctl_data_t depctl;
++						if (ep->dwc_ep.frame_num == 0xFFFFFFFF) {
++							ep->dwc_ep.frame_num = core_if->frame_num;
++							if (ep->dwc_ep.bInterval > 1) {
++								depctl.d32 = 0;
++								depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->diepctl);
++								if (ep->dwc_ep.frame_num & 0x1) {
++									depctl.b.setd1pid = 1;
++									depctl.b.setd0pid = 0;
++								} else {
++									depctl.b.setd0pid = 1;
++									depctl.b.setd1pid = 0;
++								}
++								DWC_WRITE_REG32(&dev_if->in_ep_regs[epnum]->diepctl, depctl.d32);
++							}
++							start_next_request(ep);
++						}
++						ep->dwc_ep.frame_num += ep->dwc_ep.bInterval;
++						if (dwc_ep->frame_num > 0x3FFF)	{
++							dwc_ep->frm_overrun = 1;
++							dwc_ep->frame_num &= 0x3FFF;
++						} else {
++							dwc_ep->frm_overrun = 0;
++						}
++					}
++				}
++
++				CLEAR_IN_EP_INTR(core_if, epnum, nak);
++			}
++		}
++		epnum++;
++		ep_intr >>= 1;
++	}
++
++	return 1;
++#undef CLEAR_IN_EP_INTR
++}
++
++/**
++ * This interrupt indicates that an OUT EP has a pending Interrupt.
++ * The sequence for handling the OUT EP interrupt is shown below:
++ * -#	Read the Device All Endpoint Interrupt register
++ * -#	Repeat the following for each OUT EP interrupt bit set (from
++ *		LSB to MSB).
++ * -#	Read the Device Endpoint Interrupt (DOEPINTn) register
++ * -#	If "Transfer Complete" call the request complete function
++ * -#	If "Endpoint Disabled" complete the EP disable procedure.
++ * -#	If "AHB Error Interrupt" log error
++ * -#	If "Setup Phase Done" process Setup Packet (See Standard USB
++ *		Command Processing)
++ */
++static int32_t dwc_otg_pcd_handle_out_ep_intr(dwc_otg_pcd_t * pcd)
++{
++#define CLEAR_OUT_EP_INTR(__core_if,__epnum,__intr) \
++do { \
++		doepint_data_t doepint = {.d32=0}; \
++		doepint.b.__intr = 1; \
++		DWC_WRITE_REG32(&__core_if->dev_if->out_ep_regs[__epnum]->doepint, \
++		doepint.d32); \
++} while (0)
++
++	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
++	uint32_t ep_intr;
++	doepint_data_t doepint = {.d32 = 0 };
++	uint32_t epnum = 0;
++	dwc_otg_pcd_ep_t *ep;
++	dwc_ep_t *dwc_ep;
++	dctl_data_t dctl = {.d32 = 0 };
++	gintmsk_data_t gintmsk = {.d32 = 0 };
++
++
++	DWC_DEBUGPL(DBG_PCDV, "%s()\n", __func__);
++
++	/* Read in the device interrupt bits */
++	ep_intr = dwc_otg_read_dev_all_out_ep_intr(core_if);
++
++	while (ep_intr) {
++		if (ep_intr & 0x1) {
++			/* Get EP pointer */
++			ep = get_out_ep(pcd, epnum);
++			if (!ep)
++				return -EINVAL;
++
++			dwc_ep = &ep->dwc_ep;
++			if (!dwc_ep)
++				return -EINVAL;
++
++#ifdef VERBOSE
++			DWC_DEBUGPL(DBG_PCDV,
++				    "EP%d-%s: type=%d, mps=%d\n",
++				    dwc_ep->num, (dwc_ep->is_in ? "IN" : "OUT"),
++				    dwc_ep->type, dwc_ep->maxpacket);
++#endif
++			doepint.d32 =
++			    dwc_otg_read_dev_out_ep_intr(core_if, dwc_ep);
++
++			/* Transfer complete */
++			if (doepint.b.xfercompl) {
++
++				if (epnum == 0) {
++					/* Clear the bit in DOEPINTn for this interrupt */
++					CLEAR_OUT_EP_INTR(core_if, epnum, xfercompl);
++					if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
++						DWC_DEBUGPL(DBG_PCDV, "in xfer xomplete DOEPINT=%x doepint=%x\n",
++							DWC_READ_REG32(&core_if->dev_if->out_ep_regs[0]->doepint),
++							doepint.d32);
++						DWC_DEBUGPL(DBG_PCDV, "DOEPCTL=%x \n",
++							DWC_READ_REG32(&core_if->dev_if->out_ep_regs[0]->doepctl));
++
++						if (core_if->snpsid >= OTG_CORE_REV_3_00a
++							&& core_if->dma_enable == 0) {
++							doepint_data_t doepint;
++							doepint.d32 = DWC_READ_REG32(&core_if->dev_if->
++														out_ep_regs[0]->doepint);
++							if (pcd->ep0state == EP0_IDLE && doepint.b.sr) {
++								CLEAR_OUT_EP_INTR(core_if, epnum, sr);
++								if (doepint.b.stsphsercvd)
++									CLEAR_OUT_EP_INTR(core_if, epnum, stsphsercvd);
++								goto exit_xfercompl;
++							}
++						}
++						/* In case of DDMA  look at SR bit to go to the Data Stage */
++						if (core_if->dma_desc_enable) {
++							dev_dma_desc_sts_t status = {.d32 = 0};
++							if (pcd->ep0state == EP0_IDLE) {
++								status.d32 = core_if->dev_if->setup_desc_addr[core_if->
++											dev_if->setup_desc_index]->status.d32;
++								if(pcd->data_terminated) {
++									 pcd->data_terminated = 0;
++									 status.d32 = core_if->dev_if->out_desc_addr->status.d32;
++									 dwc_memcpy(&pcd->setup_pkt->req, pcd->backup_buf, 8);
++								}
++								if (status.b.sr) {
++									if (doepint.b.setup) {
++										DWC_DEBUGPL(DBG_PCDV, "DMA DESC EP0_IDLE SR=1 setup=1\n");
++										/* Already started data stage, clear setup */
++										CLEAR_OUT_EP_INTR(core_if, epnum, setup);
++										doepint.b.setup = 0;
++										handle_ep0(pcd);
++										/* Prepare for more setup packets */
++										if (pcd->ep0state == EP0_IN_STATUS_PHASE ||
++											pcd->ep0state == EP0_IN_DATA_PHASE) {
++											ep0_out_start(core_if, pcd);
++										}
++
++										goto exit_xfercompl;
++									} else {
++										/* Prepare for more setup packets */
++										DWC_DEBUGPL(DBG_PCDV,
++											"EP0_IDLE SR=1 setup=0 new setup comes\n");
++										ep0_out_start(core_if, pcd);
++									}
++								}
++							} else {
++								dwc_otg_pcd_request_t *req;
++								dev_dma_desc_sts_t status = {.d32 = 0};
++								diepint_data_t diepint0;
++								diepint0.d32 = DWC_READ_REG32(&core_if->dev_if->
++															in_ep_regs[0]->diepint);
++
++								if (pcd->ep0state == EP0_STALL || pcd->ep0state == EP0_DISCONNECT) {
++									DWC_ERROR("EP0 is stalled/disconnected\n");
++								}
++
++								/* Clear IN xfercompl if set */
++								if (diepint0.b.xfercompl && (pcd->ep0state == EP0_IN_STATUS_PHASE
++									|| pcd->ep0state == EP0_IN_DATA_PHASE)) {
++									DWC_WRITE_REG32(&core_if->dev_if->
++										in_ep_regs[0]->diepint, diepint0.d32);
++								}
++
++								status.d32 = core_if->dev_if->setup_desc_addr[core_if->
++									dev_if->setup_desc_index]->status.d32;
++
++								if ((pcd->ep0state == EP0_OUT_STATUS_PHASE) ||
++									(ep->dwc_ep.xfer_count != ep->dwc_ep.total_len
++									&& pcd->ep0state == EP0_OUT_DATA_PHASE))
++									status.d32 = core_if->dev_if->out_desc_addr->status.d32;
++								if (status.b.sr) {
++									if (DWC_CIRCLEQ_EMPTY(&ep->queue)) {
++										DWC_DEBUGPL(DBG_PCDV, "Request queue empty!!\n");
++									} else {
++										DWC_DEBUGPL(DBG_PCDV, "complete req!!\n");
++										req = DWC_CIRCLEQ_FIRST(&ep->queue);
++										if (ep->dwc_ep.xfer_count != ep->dwc_ep.total_len &&
++											pcd->ep0state == EP0_OUT_DATA_PHASE) {
++												/* Read arrived setup packet from req->buf */
++												dwc_memcpy(&pcd->setup_pkt->req,
++													req->buf + ep->dwc_ep.xfer_count, 8);
++										}
++										req->actual = ep->dwc_ep.xfer_count;
++										dwc_otg_request_done(ep, req, -ECONNRESET);
++										ep->dwc_ep.start_xfer_buff = 0;
++										ep->dwc_ep.xfer_buff = 0;
++										ep->dwc_ep.xfer_len = 0;
++									}
++									pcd->ep0state = EP0_IDLE;
++									if (doepint.b.setup) {
++										DWC_DEBUGPL(DBG_PCDV, "EP0_IDLE SR=1 setup=1\n");
++										/* Data stage started, clear setup */
++										CLEAR_OUT_EP_INTR(core_if, epnum, setup);
++										doepint.b.setup = 0;
++										handle_ep0(pcd);
++										/* Prepare for setup packets if ep0in was enabled*/
++										if (pcd->ep0state == EP0_IN_STATUS_PHASE) {
++											ep0_out_start(core_if, pcd);
++										}
++
++										goto exit_xfercompl;
++									} else {
++										/* Prepare for more setup packets */
++										DWC_DEBUGPL(DBG_PCDV,
++											"EP0_IDLE SR=1 setup=0 new setup comes 2\n");
++										ep0_out_start(core_if, pcd);
++									}
++								}
++							}
++						}
++						if (core_if->snpsid >= OTG_CORE_REV_3_00a && core_if->dma_enable
++							&& core_if->dma_desc_enable == 0) {
++							doepint_data_t doepint_temp = {.d32 = 0};
++							deptsiz0_data_t doeptsize0 = {.d32 = 0 };
++							doepint_temp.d32 = DWC_READ_REG32(&core_if->dev_if->
++															out_ep_regs[ep->dwc_ep.num]->doepint);
++							doeptsize0.d32 = DWC_READ_REG32(&core_if->dev_if->
++															out_ep_regs[ep->dwc_ep.num]->doeptsiz);
++							if (((ep->dwc_ep.xfer_count == ep->dwc_ep.total_len || doeptsize0.b.xfersize == 64) &&
++								pcd->ep0state == EP0_OUT_DATA_PHASE && doepint.b.stsphsercvd) ||
++								(doeptsize0.b.xfersize == 24 && pcd->ep0state == EP0_IN_STATUS_PHASE)) {
++									CLEAR_OUT_EP_INTR(core_if, epnum, xfercompl);
++									DWC_DEBUGPL(DBG_PCDV, "WA for xfercompl along with stsphs \n");
++									doepint.b.xfercompl = 0;
++									ep0_out_start(core_if, pcd);
++									goto exit_xfercompl;
++							}
++
++							if (pcd->ep0state == EP0_IDLE) {
++								if (doepint_temp.b.sr) {
++									CLEAR_OUT_EP_INTR(core_if, epnum, sr);
++								}
++									/* Delay is needed for core to update setup
++									 * packet count from 3 to 2 after receiving
++									 * setup packet*/
++									dwc_udelay(100);
++									doepint.d32 = DWC_READ_REG32(&core_if->dev_if->
++																	out_ep_regs[0]->doepint);
++									if (doeptsize0.b.supcnt == 3) {
++										DWC_DEBUGPL(DBG_ANY, "Rolling over!!!!!!!\n");
++										ep->dwc_ep.stp_rollover = 1;
++									}
++									if (doepint.b.setup) {
++retry:
++										/* Already started data stage, clear setup */
++										CLEAR_OUT_EP_INTR(core_if, epnum, setup);
++										doepint.b.setup = 0;
++										handle_ep0(pcd);
++										ep->dwc_ep.stp_rollover = 0;
++										/* Prepare for more setup packets */
++										if (pcd->ep0state == EP0_IN_STATUS_PHASE ||
++											pcd->ep0state == EP0_IN_DATA_PHASE) {
++											depctl_data_t depctl = {.d32 = 0};
++											depctl.b.cnak = 1;
++											ep0_out_start(core_if, pcd);
++											/* Core not updating setup packet count
++											 * in case of PET testing - @TODO vahrama
++											 * to check with HW team further */
++											if (!core_if->otg_ver) {
++												DWC_MODIFY_REG32(&core_if->dev_if->
++													out_ep_regs[0]->doepctl, 0, depctl.d32);
++											}
++										}
++										goto exit_xfercompl;
++									} else {
++										/* Prepare for more setup packets */
++										DWC_DEBUGPL(DBG_ANY,
++											"EP0_IDLE SR=1 setup=0 new setup comes\n");
++										doepint.d32 = DWC_READ_REG32(&core_if->dev_if->
++																	out_ep_regs[0]->doepint);
++										if(doepint.b.setup)
++											goto retry;
++										ep0_out_start(core_if, pcd);
++									}
++							} else {
++								dwc_otg_pcd_request_t *req;
++								diepint_data_t diepint0 = {.d32 = 0};
++								doepint_data_t doepint_temp = {.d32 = 0};
++								depctl_data_t diepctl0;
++								diepint0.d32 = DWC_READ_REG32(&core_if->dev_if->
++																in_ep_regs[0]->diepint);
++								diepctl0.d32 = DWC_READ_REG32(&core_if->dev_if->
++																in_ep_regs[0]->diepctl);
++
++								if (pcd->ep0state == EP0_IN_DATA_PHASE
++									|| pcd->ep0state == EP0_IN_STATUS_PHASE) {
++									if (diepint0.b.xfercompl) {
++										DWC_WRITE_REG32(&core_if->dev_if->
++											in_ep_regs[0]->diepint, diepint0.d32);
++									}
++									if (diepctl0.b.epena) {
++										diepint_data_t diepint = {.d32 = 0};
++										diepctl0.b.snak = 1;
++										DWC_WRITE_REG32(&core_if->dev_if->
++														in_ep_regs[0]->diepctl, diepctl0.d32);
++										do {
++											dwc_udelay(10);
++											diepint.d32 = DWC_READ_REG32(&core_if->dev_if->
++												in_ep_regs[0]->diepint);
++										} while (!diepint.b.inepnakeff);
++										diepint.b.inepnakeff = 1;
++										DWC_WRITE_REG32(&core_if->dev_if->
++											in_ep_regs[0]->diepint, diepint.d32);
++										diepctl0.d32 = 0;
++										diepctl0.b.epdis = 1;
++										DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[0]->diepctl,
++														diepctl0.d32);
++										do {
++											dwc_udelay(10);
++											diepint.d32 = DWC_READ_REG32(&core_if->dev_if->
++												in_ep_regs[0]->diepint);
++										} while (!diepint.b.epdisabled);
++										diepint.b.epdisabled = 1;
++										DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[0]->diepint,
++															diepint.d32);
++									}
++								}
++								doepint_temp.d32 = DWC_READ_REG32(&core_if->dev_if->
++																out_ep_regs[ep->dwc_ep.num]->doepint);
++								if (doepint_temp.b.sr) {
++									CLEAR_OUT_EP_INTR(core_if, epnum, sr);
++									if (DWC_CIRCLEQ_EMPTY(&ep->queue)) {
++										DWC_DEBUGPL(DBG_PCDV, "Request queue empty!!\n");
++									} else {
++										DWC_DEBUGPL(DBG_PCDV, "complete req!!\n");
++										req = DWC_CIRCLEQ_FIRST(&ep->queue);
++										if (ep->dwc_ep.xfer_count != ep->dwc_ep.total_len &&
++											pcd->ep0state == EP0_OUT_DATA_PHASE) {
++												/* Read arrived setup packet from req->buf */
++												dwc_memcpy(&pcd->setup_pkt->req,
++													req->buf + ep->dwc_ep.xfer_count, 8);
++										}
++										req->actual = ep->dwc_ep.xfer_count;
++										dwc_otg_request_done(ep, req, -ECONNRESET);
++										ep->dwc_ep.start_xfer_buff = 0;
++										ep->dwc_ep.xfer_buff = 0;
++										ep->dwc_ep.xfer_len = 0;
++									}
++									pcd->ep0state = EP0_IDLE;
++									if (doepint.b.setup) {
++										DWC_DEBUGPL(DBG_PCDV, "EP0_IDLE SR=1 setup=1\n");
++										/* Data stage started, clear setup */
++										CLEAR_OUT_EP_INTR(core_if, epnum, setup);
++										doepint.b.setup = 0;
++										handle_ep0(pcd);
++										/* Prepare for setup packets if ep0in was enabled*/
++										if (pcd->ep0state == EP0_IN_STATUS_PHASE) {
++											depctl_data_t depctl = {.d32 = 0};
++											depctl.b.cnak = 1;
++											ep0_out_start(core_if, pcd);
++											/* Core not updating setup packet count
++											* in case of PET testing - @TODO vahrama
++											* to check with HW team further */
++											if (!core_if->otg_ver) {
++												DWC_MODIFY_REG32(&core_if->dev_if->
++														out_ep_regs[0]->doepctl, 0, depctl.d32);
++											}
++										}
++										goto exit_xfercompl;
++									} else {
++										/* Prepare for more setup packets */
++										DWC_DEBUGPL(DBG_PCDV,
++											"EP0_IDLE SR=1 setup=0 new setup comes 2\n");
++										ep0_out_start(core_if, pcd);
++									}
++								}
++							}
++						}
++						if (core_if->dma_enable == 0 || pcd->ep0state != EP0_IDLE)
++							handle_ep0(pcd);
++exit_xfercompl:
++						DWC_DEBUGPL(DBG_PCDV, "after DOEPINT=%x doepint=%x\n",
++							dwc_otg_read_dev_out_ep_intr(core_if, dwc_ep), doepint.d32);
++					} else {
++						if (core_if->dma_desc_enable == 0
++							|| pcd->ep0state != EP0_IDLE)
++							handle_ep0(pcd);
++					}
++#ifdef DWC_EN_ISOC
++				} else if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
++					if (doepint.b.pktdrpsts == 0) {
++						/* Clear the bit in DOEPINTn for this interrupt */
++						CLEAR_OUT_EP_INTR(core_if,
++								  epnum,
++								  xfercompl);
++						complete_iso_ep(pcd, ep);
++					} else {
++
++						doepint_data_t doepint = {.d32 = 0 };
++						doepint.b.xfercompl = 1;
++						doepint.b.pktdrpsts = 1;
++						DWC_WRITE_REG32
++						    (&core_if->dev_if->out_ep_regs
++						     [epnum]->doepint,
++						     doepint.d32);
++						if (handle_iso_out_pkt_dropped
++						    (core_if, dwc_ep)) {
++							complete_iso_ep(pcd,
++									ep);
++						}
++					}
++#endif /* DWC_EN_ISOC */
++#ifdef DWC_UTE_PER_IO
++				} else if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
++					CLEAR_OUT_EP_INTR(core_if, epnum, xfercompl);
++					if (!ep->stopped)
++						complete_xiso_ep(ep);
++#endif /* DWC_UTE_PER_IO */
++				} else {
++					/* Clear the bit in DOEPINTn for this interrupt */
++					CLEAR_OUT_EP_INTR(core_if, epnum,
++							  xfercompl);
++
++					if (core_if->core_params->dev_out_nak) {
++						DWC_TIMER_CANCEL(pcd->core_if->ep_xfer_timer[epnum]);
++						pcd->core_if->ep_xfer_info[epnum].state = 0;
++#ifdef DEBUG
++						print_memory_payload(pcd, dwc_ep);
++#endif
++					}
++					if (core_if->dma_desc_enable && dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
++						handle_xfercompl_iso_ddma(core_if->dev_if, ep);
++					} else {
++						complete_ep(ep);
++					}
++				}
++
++			}
++			if (doepint.b.stsphsercvd) {
++				deptsiz0_data_t deptsiz;
++				CLEAR_OUT_EP_INTR(core_if, epnum, stsphsercvd);
++				deptsiz.d32 =
++					DWC_READ_REG32(&core_if->dev_if->
++					out_ep_regs[0]->doeptsiz);
++				if ((core_if->dma_desc_enable) || (core_if->dma_enable &&
++					core_if->snpsid >= OTG_CORE_REV_3_00a)) {
++						do_setup_in_status_phase(pcd);
++				}
++			}
++
++			/* Endpoint disable      */
++			if (doepint.b.epdisabled) {
++
++				/* Clear the bit in DOEPINTn for this interrupt */
++				CLEAR_OUT_EP_INTR(core_if, epnum, epdisabled);
++				if (core_if->core_params->dev_out_nak) {
++#ifdef DEBUG
++					print_memory_payload(pcd, dwc_ep);
++#endif
++					/* In case of timeout condition */
++					if (core_if->ep_xfer_info[epnum].state == 2) {
++						dctl.d32 = DWC_READ_REG32(&core_if->dev_if->
++										dev_global_regs->dctl);
++						dctl.b.cgoutnak = 1;
++						DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl,
++																dctl.d32);
++						/* Unmask goutnakeff interrupt which was masked
++						 * during handle nak out interrupt */
++						gintmsk.b.goutnakeff = 1;
++						DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk,
++																0, gintmsk.d32);
++
++						complete_ep(ep);
++					}
++				}
++				if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC)
++				{
++					dctl_data_t dctl;
++					gintmsk_data_t intr_mask = {.d32 = 0};
++					dwc_otg_pcd_request_t *req = 0;
++
++					dctl.d32 = DWC_READ_REG32(&core_if->dev_if->
++						dev_global_regs->dctl);
++					dctl.b.cgoutnak = 1;
++					DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl,
++						dctl.d32);
++
++					intr_mask.d32 = 0;
++					intr_mask.b.incomplisoout = 1;
++
++					/* Get any pending requests */
++					if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
++						req = DWC_CIRCLEQ_FIRST(&ep->queue);
++						if (!req) {
++							DWC_PRINTF("complete_ep 0x%p, req = NULL!\n", ep);
++						} else {
++							dwc_otg_request_done(ep, req, 0);
++							start_next_request(ep);
++						}
++					} else {
++						DWC_PRINTF("complete_ep 0x%p, ep->queue empty!\n", ep);
++					}
++				}
++			}
++			/* AHB Error */
++			if (doepint.b.ahberr) {
++				DWC_ERROR("EP%d OUT AHB Error\n", epnum);
++				DWC_ERROR("EP%d DEPDMA=0x%08x \n",
++					  epnum, core_if->dev_if->out_ep_regs[epnum]->doepdma);
++				CLEAR_OUT_EP_INTR(core_if, epnum, ahberr);
++			}
++			/* Setup Phase Done (contorl EPs) */
++			if (doepint.b.setup) {
++#ifdef DEBUG_EP0
++				DWC_DEBUGPL(DBG_PCD, "EP%d SETUP Done\n", epnum);
++#endif
++				CLEAR_OUT_EP_INTR(core_if, epnum, setup);
++
++				handle_ep0(pcd);
++			}
++
++			/** OUT EP BNA Intr */
++			if (doepint.b.bna) {
++				CLEAR_OUT_EP_INTR(core_if, epnum, bna);
++				if (core_if->dma_desc_enable) {
++#ifdef DWC_EN_ISOC
++					if (dwc_ep->type ==
++					    DWC_OTG_EP_TYPE_ISOC) {
++						/*
++						 * This checking is performed to prevent first "false" BNA
++						 * handling occuring right after reconnect
++						 */
++						if (dwc_ep->next_frame !=
++						    0xffffffff)
++							dwc_otg_pcd_handle_iso_bna(ep);
++					} else
++#endif				/* DWC_EN_ISOC */
++					if (ep->dwc_ep.type != DWC_OTG_EP_TYPE_ISOC) {
++						dwc_otg_pcd_handle_noniso_bna(ep);
++					}
++				}
++			}
++			/* Babble Interrupt */
++			if (doepint.b.babble) {
++				DWC_DEBUGPL(DBG_ANY, "EP%d OUT Babble\n",
++					    epnum);
++				handle_out_ep_babble_intr(pcd, epnum);
++
++				CLEAR_OUT_EP_INTR(core_if, epnum, babble);
++			}
++			if (doepint.b.outtknepdis) {
++				DWC_DEBUGPL(DBG_ANY, "EP%d OUT Token received when EP is \
++					disabled\n",epnum);
++				if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
++					if (core_if->dma_desc_enable) {
++						if (!ep->dwc_ep.iso_transfer_started) {
++							ep->dwc_ep.frame_num = core_if->frame_num;
++							dwc_otg_pcd_start_iso_ddma(core_if, ep);
++						}
++					} else {
++						doepmsk_data_t doepmsk = {.d32 = 0};
++						ep->dwc_ep.frame_num = core_if->frame_num;
++						if (ep->dwc_ep.bInterval > 1) {
++							depctl_data_t depctl;
++							depctl.d32 = DWC_READ_REG32(&core_if->dev_if->
++														out_ep_regs[epnum]->doepctl);
++							if (ep->dwc_ep.frame_num & 0x1) {
++								depctl.b.setd1pid = 1;
++								depctl.b.setd0pid = 0;
++							} else {
++								depctl.b.setd0pid = 1;
++								depctl.b.setd1pid = 0;
++							}
++							DWC_WRITE_REG32(&core_if->dev_if->
++											out_ep_regs[epnum]->doepctl, depctl.d32);
++						}
++
++						start_next_request(ep);
++						doepmsk.b.outtknepdis = 1;
++						DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->doepmsk,
++								 doepmsk.d32, 0);
++					}
++				}
++				CLEAR_OUT_EP_INTR(core_if, epnum, outtknepdis);
++			}
++
++			/* NAK Interrutp */
++			if (doepint.b.nak) {
++				DWC_DEBUGPL(DBG_ANY, "EP%d OUT NAK\n", epnum);
++				handle_out_ep_nak_intr(pcd, epnum);
++
++				CLEAR_OUT_EP_INTR(core_if, epnum, nak);
++			}
++			/* NYET Interrutp */
++			if (doepint.b.nyet) {
++				DWC_DEBUGPL(DBG_ANY, "EP%d OUT NYET\n", epnum);
++				handle_out_ep_nyet_intr(pcd, epnum);
++
++				CLEAR_OUT_EP_INTR(core_if, epnum, nyet);
++			}
++		}
++
++		epnum++;
++		ep_intr >>= 1;
++	}
++
++	return 1;
++
++#undef CLEAR_OUT_EP_INTR
++}
++static int drop_transfer(uint32_t trgt_fr, uint32_t curr_fr, uint8_t frm_overrun)
++{
++	int retval = 0;
++	if(!frm_overrun && curr_fr >= trgt_fr)
++		retval = 1;
++	else if (frm_overrun
++		 && (curr_fr >= trgt_fr && ((curr_fr - trgt_fr) < 0x3FFF / 2)))
++		retval = 1;
++	return retval;
++}
++
++/**
++ * Incomplete ISO IN Transfer Interrupt.
++ * This interrupt indicates one of the following conditions occurred
++ * while transmitting an ISOC transaction.
++ * - Corrupted IN Token for ISOC EP.
++ * - Packet not complete in FIFO.
++ * The follow actions will be taken:
++ *	-#	Determine the EP
++ *	-#	Set incomplete flag in dwc_ep structure
++ *	-#	Disable EP; when "Endpoint Disabled" interrupt is received
++ *		Flush FIFO
++ */
++int32_t dwc_otg_pcd_handle_incomplete_isoc_in_intr(dwc_otg_pcd_t * pcd)
++{
++	gintsts_data_t gintsts;
++
++#ifdef DWC_EN_ISOC
++	dwc_otg_dev_if_t *dev_if;
++	deptsiz_data_t deptsiz = {.d32 = 0 };
++	depctl_data_t depctl = {.d32 = 0 };
++	dsts_data_t dsts = {.d32 = 0 };
++	dwc_ep_t *dwc_ep;
++	int i;
++
++	dev_if = GET_CORE_IF(pcd)->dev_if;
++
++	for (i = 1; i <= dev_if->num_in_eps; ++i) {
++		dwc_ep = &pcd->in_ep[i].dwc_ep;
++		if (dwc_ep->active && dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
++			deptsiz.d32 =
++			    DWC_READ_REG32(&dev_if->in_ep_regs[i]->dieptsiz);
++			depctl.d32 =
++			    DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
++
++			if (depctl.b.epdis && deptsiz.d32) {
++				set_current_pkt_info(GET_CORE_IF(pcd), dwc_ep);
++				if (dwc_ep->cur_pkt >= dwc_ep->pkt_cnt) {
++					dwc_ep->cur_pkt = 0;
++					dwc_ep->proc_buf_num =
++					    (dwc_ep->proc_buf_num ^ 1) & 0x1;
++
++					if (dwc_ep->proc_buf_num) {
++						dwc_ep->cur_pkt_addr =
++						    dwc_ep->xfer_buff1;
++						dwc_ep->cur_pkt_dma_addr =
++						    dwc_ep->dma_addr1;
++					} else {
++						dwc_ep->cur_pkt_addr =
++						    dwc_ep->xfer_buff0;
++						dwc_ep->cur_pkt_dma_addr =
++						    dwc_ep->dma_addr0;
++					}
++
++				}
++
++				dsts.d32 =
++				    DWC_READ_REG32(&GET_CORE_IF(pcd)->dev_if->
++						   dev_global_regs->dsts);
++				dwc_ep->next_frame = dsts.b.soffn;
++
++				dwc_otg_iso_ep_start_frm_transfer(GET_CORE_IF
++								  (pcd),
++								  dwc_ep);
++			}
++		}
++	}
++
++#else
++	depctl_data_t depctl = {.d32 = 0 };
++	dwc_ep_t *dwc_ep;
++	dwc_otg_dev_if_t *dev_if;
++	int i;
++	dev_if = GET_CORE_IF(pcd)->dev_if;
++
++	DWC_DEBUGPL(DBG_PCD,"Incomplete ISO IN \n");
++
++	for (i = 1; i <= dev_if->num_in_eps; ++i) {
++		dwc_ep = &pcd->in_ep[i-1].dwc_ep;
++		depctl.d32 =
++			DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
++		if (depctl.b.epena && dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
++			if (drop_transfer(dwc_ep->frame_num, GET_CORE_IF(pcd)->frame_num,
++							dwc_ep->frm_overrun))
++			{
++				depctl.d32 =
++					DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
++				depctl.b.snak = 1;
++				depctl.b.epdis = 1;
++				DWC_MODIFY_REG32(&dev_if->in_ep_regs[i]->diepctl, depctl.d32, depctl.d32);
++			}
++		}
++	}
++
++	/*intr_mask.b.incomplisoin = 1;
++	   DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
++	   intr_mask.d32, 0);    */
++#endif //DWC_EN_ISOC
++
++	/* Clear interrupt */
++	gintsts.d32 = 0;
++	gintsts.b.incomplisoin = 1;
++	DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
++			gintsts.d32);
++
++	return 1;
++}
++
++/**
++ * Incomplete ISO OUT Transfer Interrupt.
++ *
++ * This interrupt indicates that the core has dropped an ISO OUT
++ * packet. The following conditions can be the cause:
++ * - FIFO Full, the entire packet would not fit in the FIFO.
++ * - CRC Error
++ * - Corrupted Token
++ * The follow actions will be taken:
++ *	-#	Determine the EP
++ *	-#	Set incomplete flag in dwc_ep structure
++ *	-#	Read any data from the FIFO
++ *	-#	Disable EP. When "Endpoint Disabled" interrupt is received
++ *		re-enable EP.
++ */
++int32_t dwc_otg_pcd_handle_incomplete_isoc_out_intr(dwc_otg_pcd_t * pcd)
++{
++
++	gintsts_data_t gintsts;
++
++#ifdef DWC_EN_ISOC
++	dwc_otg_dev_if_t *dev_if;
++	deptsiz_data_t deptsiz = {.d32 = 0 };
++	depctl_data_t depctl = {.d32 = 0 };
++	dsts_data_t dsts = {.d32 = 0 };
++	dwc_ep_t *dwc_ep;
++	int i;
++
++	dev_if = GET_CORE_IF(pcd)->dev_if;
++
++	for (i = 1; i <= dev_if->num_out_eps; ++i) {
++		dwc_ep = &pcd->in_ep[i].dwc_ep;
++		if (pcd->out_ep[i].dwc_ep.active &&
++		    pcd->out_ep[i].dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
++			deptsiz.d32 =
++			    DWC_READ_REG32(&dev_if->out_ep_regs[i]->doeptsiz);
++			depctl.d32 =
++			    DWC_READ_REG32(&dev_if->out_ep_regs[i]->doepctl);
++
++			if (depctl.b.epdis && deptsiz.d32) {
++				set_current_pkt_info(GET_CORE_IF(pcd),
++						     &pcd->out_ep[i].dwc_ep);
++				if (dwc_ep->cur_pkt >= dwc_ep->pkt_cnt) {
++					dwc_ep->cur_pkt = 0;
++					dwc_ep->proc_buf_num =
++					    (dwc_ep->proc_buf_num ^ 1) & 0x1;
++
++					if (dwc_ep->proc_buf_num) {
++						dwc_ep->cur_pkt_addr =
++						    dwc_ep->xfer_buff1;
++						dwc_ep->cur_pkt_dma_addr =
++						    dwc_ep->dma_addr1;
++					} else {
++						dwc_ep->cur_pkt_addr =
++						    dwc_ep->xfer_buff0;
++						dwc_ep->cur_pkt_dma_addr =
++						    dwc_ep->dma_addr0;
++					}
++
++				}
++
++				dsts.d32 =
++				    DWC_READ_REG32(&GET_CORE_IF(pcd)->dev_if->
++						   dev_global_regs->dsts);
++				dwc_ep->next_frame = dsts.b.soffn;
++
++				dwc_otg_iso_ep_start_frm_transfer(GET_CORE_IF
++								  (pcd),
++								  dwc_ep);
++			}
++		}
++	}
++#else
++	/** @todo implement ISR */
++	gintmsk_data_t intr_mask = {.d32 = 0 };
++	dwc_otg_core_if_t *core_if;
++	deptsiz_data_t deptsiz = {.d32 = 0 };
++	depctl_data_t depctl = {.d32 = 0 };
++	dctl_data_t dctl = {.d32 = 0 };
++	dwc_ep_t *dwc_ep = NULL;
++	int i;
++	core_if = GET_CORE_IF(pcd);
++
++	for (i = 0; i < core_if->dev_if->num_out_eps; ++i) {
++		dwc_ep = &pcd->out_ep[i].dwc_ep;
++		depctl.d32 =
++			DWC_READ_REG32(&core_if->dev_if->out_ep_regs[dwc_ep->num]->doepctl);
++		if (depctl.b.epena && depctl.b.dpid == (core_if->frame_num & 0x1)) {
++			core_if->dev_if->isoc_ep = dwc_ep;
++			deptsiz.d32 =
++					DWC_READ_REG32(&core_if->dev_if->out_ep_regs[dwc_ep->num]->doeptsiz);
++				break;
++		}
++	}
++	dctl.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dctl);
++	gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
++	intr_mask.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintmsk);
++
++	if (!intr_mask.b.goutnakeff) {
++		/* Unmask it */
++		intr_mask.b.goutnakeff = 1;
++		DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, intr_mask.d32);
++	}
++	if (!gintsts.b.goutnakeff) {
++		dctl.b.sgoutnak = 1;
++	}
++	DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32);
++
++	depctl.d32 = DWC_READ_REG32(&core_if->dev_if->out_ep_regs[dwc_ep->num]->doepctl);
++	if (depctl.b.epena) {
++		depctl.b.epdis = 1;
++		depctl.b.snak = 1;
++	}
++	DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[dwc_ep->num]->doepctl, depctl.d32);
++
++	intr_mask.d32 = 0;
++	intr_mask.b.incomplisoout = 1;
++
++#endif /* DWC_EN_ISOC */
++
++	/* Clear interrupt */
++	gintsts.d32 = 0;
++	gintsts.b.incomplisoout = 1;
++	DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
++			gintsts.d32);
++
++	return 1;
++}
++
++/**
++ * This function handles the Global IN NAK Effective interrupt.
++ *
++ */
++int32_t dwc_otg_pcd_handle_in_nak_effective(dwc_otg_pcd_t * pcd)
++{
++	dwc_otg_dev_if_t *dev_if = GET_CORE_IF(pcd)->dev_if;
++	depctl_data_t diepctl = {.d32 = 0 };
++	gintmsk_data_t intr_mask = {.d32 = 0 };
++	gintsts_data_t gintsts;
++	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
++	int i;
++
++	DWC_DEBUGPL(DBG_PCD, "Global IN NAK Effective\n");
++
++	/* Disable all active IN EPs */
++	for (i = 0; i <= dev_if->num_in_eps; i++) {
++		diepctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
++		if (!(diepctl.b.eptype & 1) && diepctl.b.epena) {
++			if (core_if->start_predict > 0)
++				core_if->start_predict++;
++			diepctl.b.epdis = 1;
++			diepctl.b.snak = 1;
++			DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepctl, diepctl.d32);
++		}
++	}
++
++
++	/* Disable the Global IN NAK Effective Interrupt */
++	intr_mask.b.ginnakeff = 1;
++	DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
++			 intr_mask.d32, 0);
++
++	/* Clear interrupt */
++	gintsts.d32 = 0;
++	gintsts.b.ginnakeff = 1;
++	DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
++			gintsts.d32);
++
++	return 1;
++}
++
++/**
++ * OUT NAK Effective.
++ *
++ */
++int32_t dwc_otg_pcd_handle_out_nak_effective(dwc_otg_pcd_t * pcd)
++{
++	dwc_otg_dev_if_t *dev_if = GET_CORE_IF(pcd)->dev_if;
++	gintmsk_data_t intr_mask = {.d32 = 0 };
++	gintsts_data_t gintsts;
++	depctl_data_t doepctl;
++	int i;
++
++	/* Disable the Global OUT NAK Effective Interrupt */
++	intr_mask.b.goutnakeff = 1;
++	DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
++			 intr_mask.d32, 0);
++
++	/* If DEV OUT NAK enabled */
++	if (pcd->core_if->core_params->dev_out_nak) {
++		/* Run over all out endpoints to determine the ep number on
++		 * which the timeout has happened
++		 */
++		for (i = 0; i <= dev_if->num_out_eps; i++) {
++			if (pcd->core_if->ep_xfer_info[i].state == 2)
++				break;
++		}
++		if (i > dev_if->num_out_eps) {
++			dctl_data_t dctl;
++			dctl.d32 =
++			    DWC_READ_REG32(&dev_if->dev_global_regs->dctl);
++			dctl.b.cgoutnak = 1;
++			DWC_WRITE_REG32(&dev_if->dev_global_regs->dctl,
++					dctl.d32);
++			goto out;
++		}
++
++		/* Disable the endpoint */
++		doepctl.d32 = DWC_READ_REG32(&dev_if->out_ep_regs[i]->doepctl);
++		if (doepctl.b.epena) {
++			doepctl.b.epdis = 1;
++			doepctl.b.snak = 1;
++		}
++		DWC_WRITE_REG32(&dev_if->out_ep_regs[i]->doepctl, doepctl.d32);
++		return 1;
++	}
++	/* We come here from Incomplete ISO OUT handler */
++	if (dev_if->isoc_ep) {
++		dwc_ep_t *dwc_ep = (dwc_ep_t *) dev_if->isoc_ep;
++		uint32_t epnum = dwc_ep->num;
++		doepint_data_t doepint;
++		doepint.d32 =
++		    DWC_READ_REG32(&dev_if->out_ep_regs[dwc_ep->num]->doepint);
++		dev_if->isoc_ep = NULL;
++		doepctl.d32 =
++		    DWC_READ_REG32(&dev_if->out_ep_regs[epnum]->doepctl);
++		DWC_PRINTF("Before disable DOEPCTL = %08x\n", doepctl.d32);
++		if (doepctl.b.epena) {
++			doepctl.b.epdis = 1;
++			doepctl.b.snak = 1;
++		}
++		DWC_WRITE_REG32(&dev_if->out_ep_regs[epnum]->doepctl,
++				doepctl.d32);
++		return 1;
++	} else
++		DWC_PRINTF("INTERRUPT Handler not implemented for %s\n",
++			   "Global OUT NAK Effective\n");
++
++out:
++	/* Clear interrupt */
++	gintsts.d32 = 0;
++	gintsts.b.goutnakeff = 1;
++	DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
++			gintsts.d32);
++
++	return 1;
++}
++
++/**
++ * PCD interrupt handler.
++ *
++ * The PCD handles the device interrupts.  Many conditions can cause a
++ * device interrupt. When an interrupt occurs, the device interrupt
++ * service routine determines the cause of the interrupt and
++ * dispatches handling to the appropriate function. These interrupt
++ * handling functions are described below.
++ *
++ * All interrupt registers are processed from LSB to MSB.
++ *
++ */
++int32_t dwc_otg_pcd_handle_intr(dwc_otg_pcd_t * pcd)
++{
++	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
++#ifdef VERBOSE
++	dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
++#endif
++	gintsts_data_t gintr_status;
++	int32_t retval = 0;
++
++	if (dwc_otg_check_haps_status(core_if) == -1 ) {
++		DWC_WARN("HAPS is disconnected");
++		return retval;
++	}
++
++	/* Exit from ISR if core is hibernated */
++	if (core_if->hibernation_suspend == 1) {
++		return retval;
++	}
++#ifdef VERBOSE
++	DWC_DEBUGPL(DBG_ANY, "%s() gintsts=%08x	 gintmsk=%08x\n",
++		    __func__,
++		    DWC_READ_REG32(&global_regs->gintsts),
++		    DWC_READ_REG32(&global_regs->gintmsk));
++#endif
++
++	if (dwc_otg_is_device_mode(core_if)) {
++		DWC_SPINLOCK(pcd->lock);
++#ifdef VERBOSE
++		DWC_DEBUGPL(DBG_PCDV, "%s() gintsts=%08x  gintmsk=%08x\n",
++			    __func__,
++			    DWC_READ_REG32(&global_regs->gintsts),
++			    DWC_READ_REG32(&global_regs->gintmsk));
++#endif
++
++		gintr_status.d32 = dwc_otg_read_core_intr(core_if);
++
++		DWC_DEBUGPL(DBG_PCDV, "%s: gintsts&gintmsk=%08x\n",
++			    __func__, gintr_status.d32);
++
++		if (gintr_status.b.sofintr) {
++			retval |= dwc_otg_pcd_handle_sof_intr(pcd);
++		}
++		if (gintr_status.b.rxstsqlvl) {
++			retval |=
++			    dwc_otg_pcd_handle_rx_status_q_level_intr(pcd);
++		}
++		if (gintr_status.b.nptxfempty) {
++			retval |= dwc_otg_pcd_handle_np_tx_fifo_empty_intr(pcd);
++		}
++		if (gintr_status.b.goutnakeff) {
++			retval |= dwc_otg_pcd_handle_out_nak_effective(pcd);
++		}
++		if (gintr_status.b.i2cintr) {
++			retval |= dwc_otg_pcd_handle_i2c_intr(pcd);
++		}
++		if (gintr_status.b.erlysuspend) {
++			retval |= dwc_otg_pcd_handle_early_suspend_intr(pcd);
++			otg_usbhost_stat = 0;
++			hisi_switch_func(0);
++		}
++		if (gintr_status.b.usbreset) {
++			otg_usbhost_stat = 1;
++			retval |= dwc_otg_pcd_handle_usb_reset_intr(pcd);
++			hisi_switch_func(0);
++		}
++		if (gintr_status.b.enumdone) {
++			retval |= dwc_otg_pcd_handle_enum_done_intr(pcd);
++		}
++		if (gintr_status.b.isooutdrop) {
++			retval |=
++			    dwc_otg_pcd_handle_isoc_out_packet_dropped_intr
++			    (pcd);
++		}
++		if (gintr_status.b.eopframe) {
++			retval |=
++			    dwc_otg_pcd_handle_end_periodic_frame_intr(pcd);
++		}
++		if (gintr_status.b.inepint) {
++			if (!core_if->multiproc_int_enable) {
++				retval |= dwc_otg_pcd_handle_in_ep_intr(pcd);
++			}
++		}
++		if (gintr_status.b.outepintr) {
++			otg_usbhost_stat = 1;
++			if (!core_if->multiproc_int_enable) {
++				retval |= dwc_otg_pcd_handle_out_ep_intr(pcd);
++			}
++		}
++		if (gintr_status.b.epmismatch) {
++			retval |= dwc_otg_pcd_handle_ep_mismatch_intr(pcd);
++		}
++		if (gintr_status.b.fetsusp) {
++			retval |= dwc_otg_pcd_handle_ep_fetsusp_intr(pcd);
++		}
++		if (gintr_status.b.ginnakeff) {
++			retval |= dwc_otg_pcd_handle_in_nak_effective(pcd);
++		}
++		if (gintr_status.b.incomplisoin) {
++			retval |=
++			    dwc_otg_pcd_handle_incomplete_isoc_in_intr(pcd);
++		}
++		if (gintr_status.b.incomplisoout) {
++			retval |=
++			    dwc_otg_pcd_handle_incomplete_isoc_out_intr(pcd);
++		}
++
++		/* In MPI mode Device Endpoints interrupts are asserted
++		 * without setting outepintr and inepint bits set, so these
++		 * Interrupt handlers are called without checking these bit-fields
++		 */
++		if (core_if->multiproc_int_enable) {
++			retval |= dwc_otg_pcd_handle_in_ep_intr(pcd);
++			retval |= dwc_otg_pcd_handle_out_ep_intr(pcd);
++		}
++#ifdef VERBOSE
++		DWC_DEBUGPL(DBG_PCDV, "%s() gintsts=%0x\n", __func__,
++			    DWC_READ_REG32(&global_regs->gintsts));
++#endif
++		DWC_SPINUNLOCK(pcd->lock);
++	}
++	return retval;
++}
++
++#endif /* DWC_HOST_ONLY */
+diff --git a/drivers/usb/gadget/udc/hiudc/dwc_otg_pcd_linux.c b/drivers/usb/gadget/udc/hiudc/dwc_otg_pcd_linux.c
+new file mode 100644
+index 0000000..109ac01
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc/dwc_otg_pcd_linux.c
+@@ -0,0 +1,1460 @@
++ /* ==========================================================================
++  * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd_linux.c $
++  * $Revision: #28 $
++  * $Date: 2013/05/07 $
++  * $Change: 2224063 $
++  *
++  * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
++  * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++  * otherwise expressly agreed to in writing between Synopsys and you.
++  *
++  * The Software IS NOT an item of Licensed Software or Licensed Product under
++  * any End User Software License Agreement or Agreement for Licensed Product
++  * with Synopsys or any supplement thereto. You are permitted to use and
++  * redistribute this Software in source and binary forms, with or without
++  * modification, provided that redistributions of source code must retain this
++  * notice. You may not view, use, disclose, copy or distribute this file or
++  * any information contained herein except pursuant to this license grant from
++  * Synopsys. If you do not agree with this notice, including the disclaimer
++  * below, then you are not authorized to use the Software.
++  *
++  * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++  * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
++  * ========================================================================== */
++#ifndef DWC_HOST_ONLY
++
++/** @file
++ * This file implements the Peripheral Controller Driver.
++ *
++ * The Peripheral Controller Driver (PCD) is responsible for
++ * translating requests from the Function Driver into the appropriate
++ * actions on the DWC_otg controller. It isolates the Function Driver
++ * from the specifics of the controller by providing an API to the
++ * Function Driver.
++ *
++ * The Peripheral Controller Driver for Linux will implement the
++ * Gadget API, so that the existing Gadget drivers can be used.
++ * (Gadget Driver is the Linux terminology for a Function Driver.)
++ *
++ * The Linux Gadget API is defined in the header file
++ * <code><linux/usb_gadget.h></code>.  The USB EP operations API is
++ * defined in the structure <code>usb_ep_ops</code> and the USB
++ * Controller API is defined in the structure
++ * <code>usb_gadget_ops</code>.
++ *
++ */
++
++#include "dwc_otg_os_dep.h"
++#include "dwc_otg_pcd_if.h"
++#include "dwc_otg_pcd.h"
++#include "dwc_otg_driver.h"
++#include "dwc_otg_dbg.h"
++
++static struct gadget_wrapper {
++	dwc_otg_pcd_t *pcd;
++
++	struct usb_gadget gadget;
++	struct usb_gadget_driver *driver;
++
++	struct usb_ep ep0;
++	struct usb_ep in_ep[16];
++	struct usb_ep out_ep[16];
++
++} *gadget_wrapper;
++
++/* Display the contents of the buffer */
++extern void dump_msg(const u8 * buf, unsigned int length);
++
++int udc_attach_driver(const char *name, struct usb_gadget_driver *driver)
++{
++	//do nothing ,only make
++	return 0;
++}
++EXPORT_SYMBOL_GPL(udc_attach_driver);
++
++void usb_gadget_set_state(struct usb_gadget *gadget,
++		enum usb_device_state state)
++{
++	gadget->state = state;
++}
++EXPORT_SYMBOL_GPL(usb_gadget_set_state);
++
++static int usb_gadget_map_req(struct usb_gadget *gadget,
++		struct usb_request *req, struct dwc_otg_pcd_ep *ep)
++{
++	if (req->length == 0)
++		return 0;
++
++	if (req->num_sgs) {
++		dev_err(&gadget->dev, "controller not support scatter/gather dma\n");
++		return -EFAULT;
++
++	} else {
++
++		if (ep == &gadget_wrapper->pcd->ep0) {
++			req->dma = dma_map_single(&gadget->dev, req->buf, req->length,
++				DMA_BIDIRECTIONAL);
++		} else {
++			req->dma = dma_map_single(&gadget->dev, req->buf, req->length,
++				ep->dwc_ep.is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
++		}
++
++		if (dma_mapping_error(&gadget->dev, req->dma)) {
++			dev_err(&gadget->dev, "failed to map buffer\n");
++			return -EFAULT;
++		}
++	}
++
++	return 0;
++}
++
++static void usb_gadget_unmap_req(struct usb_gadget *gadget,
++		struct usb_request *req, struct dwc_otg_pcd_ep *ep)
++{
++	if (req->length == 0)
++		return;
++
++	if (req->num_mapped_sgs) {
++		dev_err(&gadget->dev, "controller not support scatter/gather dma\n");
++	} else {
++
++		if (ep == &gadget_wrapper->pcd->ep0) {
++			dma_unmap_single(&gadget->dev, req->dma, req->length,
++				DMA_BIDIRECTIONAL);
++		} else {
++			dma_unmap_single(&gadget->dev, req->dma, req->length,
++				ep->dwc_ep.is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
++		}
++	}
++}
++
++/**
++ * Get the dwc_otg_pcd_ep_t* from usb_ep* pointer - NULL in case
++ * if the endpoint is not found
++ */
++static struct dwc_otg_pcd_ep *ep_from_handle(dwc_otg_pcd_t * pcd, void *handle)
++{
++	int i;
++	if (pcd->ep0.priv == handle) {
++		return &pcd->ep0;
++	}
++
++	for (i = 0; i < MAX_EPS_CHANNELS - 1; i++) {
++		if (pcd->in_ep[i].priv == handle)
++			return &pcd->in_ep[i];
++		if (pcd->out_ep[i].priv == handle)
++			return &pcd->out_ep[i];
++	}
++
++	return NULL;
++}
++
++/* USB Endpoint Operations */
++/*
++ * The following sections briefly describe the behavior of the Gadget
++ * API endpoint operations implemented in the DWC_otg driver
++ * software. Detailed descriptions of the generic behavior of each of
++ * these functions can be found in the Linux header file
++ * include/linux/usb_gadget.h.
++ *
++ * The Gadget API provides wrapper functions for each of the function
++ * pointers defined in usb_ep_ops. The Gadget Driver calls the wrapper
++ * function, which then calls the underlying PCD function. The
++ * following sections are named according to the wrapper
++ * functions. Within each section, the corresponding DWC_otg PCD
++ * function name is specified.
++ *
++ */
++
++/**
++ * This function is called by the Gadget Driver for each EP to be
++ * configured for the current configuration (SET_CONFIGURATION).
++ *
++ * This function initializes the dwc_otg_ep_t data structure, and then
++ * calls dwc_otg_ep_activate.
++ */
++static int ep_enable(struct usb_ep *usb_ep,
++		     const struct usb_endpoint_descriptor *ep_desc)
++{
++	int retval;
++
++	DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p)\n", __func__, usb_ep, ep_desc);
++
++	if (!usb_ep || !ep_desc || ep_desc->bDescriptorType != USB_DT_ENDPOINT) {
++		DWC_WARN("%s, bad ep or descriptor\n", __func__);
++		return -EINVAL;
++	}
++	if (usb_ep == &gadget_wrapper->ep0) {
++		DWC_WARN("%s, bad ep(0)\n", __func__);
++		return -EINVAL;
++	}
++
++	/* Check FIFO size? */
++	if (!ep_desc->wMaxPacketSize) {
++		DWC_WARN("%s, bad %s maxpacket\n", __func__, usb_ep->name);
++		return -ERANGE;
++	}
++
++	if (!gadget_wrapper->driver ||
++	    gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
++		DWC_WARN("%s, bogus device state\n", __func__);
++		return -ESHUTDOWN;
++	}
++
++	/* Delete after check - MAS */
++#if 0
++	nat = (uint32_t) ep_desc->wMaxPacketSize;
++	printk(KERN_ALERT "%s: nat (before) =%d\n", __func__, nat);
++	nat = (nat >> 11) & 0x03;
++	printk(KERN_ALERT "%s: nat (after) =%d\n", __func__, nat);
++#endif
++	retval = dwc_otg_pcd_ep_enable(gadget_wrapper->pcd,
++				       (const uint8_t *)ep_desc,
++				       (void *)usb_ep);
++	if (retval) {
++		DWC_WARN("dwc_otg_pcd_ep_enable failed\n");
++		return -EINVAL;
++	}
++
++	usb_ep->maxpacket = le16_to_cpu(ep_desc->wMaxPacketSize);
++
++	if (usb_ep->maxpacket == 5120)
++		usb_ep->maxpacket = 3072;
++	else if (usb_ep->maxpacket == 3072)
++		usb_ep->maxpacket = 2048;
++
++	return 0;
++}
++
++/**
++ * This function is called when an EP is disabled due to disconnect or
++ * change in configuration. Any pending requests will terminate with a
++ * status of -ESHUTDOWN.
++ *
++ * This function modifies the dwc_otg_ep_t data structure for this EP,
++ * and then calls dwc_otg_ep_deactivate.
++ */
++static int ep_disable(struct usb_ep *usb_ep)
++{
++	int retval;
++
++	DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, usb_ep);
++	if (!usb_ep) {
++		DWC_DEBUGPL(DBG_PCD, "%s, %s not enabled\n", __func__,
++			    usb_ep ? usb_ep->name : NULL);
++		return -EINVAL;
++	}
++
++	retval = dwc_otg_pcd_ep_disable(gadget_wrapper->pcd, usb_ep);
++	if (retval) {
++		retval = -EINVAL;
++	}
++
++	return retval;
++}
++
++/**
++ * This function allocates a request object to use with the specified
++ * endpoint.
++ *
++ * @param ep The endpoint to be used with with the request
++ * @param gfp_flags the GFP_* flags to use.
++ */
++static struct usb_request *dwc_otg_pcd_alloc_request(struct usb_ep *ep,
++						     gfp_t gfp_flags)
++{
++	struct usb_request *usb_req;
++
++	DWC_DEBUGPL(DBG_PCDV, "%s(%p,%d)\n", __func__, ep, gfp_flags);
++	if (0 == ep) {
++		DWC_WARN("%s() %s\n", __func__, "Invalid EP!\n");
++		return 0;
++	}
++	usb_req = kmalloc(sizeof(*usb_req), gfp_flags);
++	if (0 == usb_req) {
++		DWC_WARN("%s() %s\n", __func__, "request allocation failed!\n");
++		return 0;
++	}
++	memset(usb_req, 0, sizeof(*usb_req));
++	usb_req->dma = DWC_DMA_ADDR_INVALID;
++
++	return usb_req;
++}
++
++/**
++ * This function frees a request object.
++ *
++ * @param ep The endpoint associated with the request
++ * @param req The request being freed
++ */
++static void dwc_otg_pcd_free_request(struct usb_ep *ep, struct usb_request *req)
++{
++	DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p)\n", __func__, ep, req);
++
++	if (0 == ep || 0 == req) {
++		DWC_WARN("%s() %s\n", __func__,
++			 "Invalid ep or req argument!\n");
++		return;
++	}
++
++	kfree(req);
++}
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
++/**
++ * This function allocates an I/O buffer to be used for a transfer
++ * to/from the specified endpoint.
++ *
++ * @param usb_ep The endpoint to be used with with the request
++ * @param bytes The desired number of bytes for the buffer
++ * @param dma Pointer to the buffer's DMA address; must be valid
++ * @param gfp_flags the GFP_* flags to use.
++ * @return address of a new buffer or null is buffer could not be allocated.
++ */
++static void *dwc_otg_pcd_alloc_buffer(struct usb_ep *usb_ep, unsigned bytes,
++				      dma_addr_t * dma, gfp_t gfp_flags)
++{
++	void *buf;
++	dwc_otg_pcd_t *pcd = 0;
++
++	pcd = gadget_wrapper->pcd;
++
++	DWC_DEBUGPL(DBG_PCDV, "%s(%p,%d,%p,%0x)\n", __func__, usb_ep, bytes,
++		    dma, gfp_flags);
++
++	/* Check dword alignment */
++	if ((bytes & 0x3UL) != 0) {
++		DWC_WARN("%s() Buffer size is not a multiple of"
++			 "DWORD size (%d)", __func__, bytes);
++	}
++
++	buf = dma_alloc_coherent(NULL, bytes, dma, gfp_flags);
++
++	/* Check dword alignment */
++	if (((int)buf & 0x3UL) != 0) {
++		DWC_WARN("%s() Buffer is not DWORD aligned (%p)",
++			 __func__, buf);
++	}
++
++	return buf;
++}
++
++/**
++ * This function frees an I/O buffer that was allocated by alloc_buffer.
++ *
++ * @param usb_ep the endpoint associated with the buffer
++ * @param buf address of the buffer
++ * @param dma The buffer's DMA address
++ * @param bytes The number of bytes of the buffer
++ */
++static void dwc_otg_pcd_free_buffer(struct usb_ep *usb_ep, void *buf,
++				    dma_addr_t dma, unsigned bytes)
++{
++	dwc_otg_pcd_t *pcd = 0;
++
++	pcd = gadget_wrapper->pcd;
++
++	DWC_DEBUGPL(DBG_PCDV, "%s(%p,%0x,%d)\n", __func__, buf, dma, bytes);
++
++	dma_free_coherent(NULL, bytes, buf, dma);
++}
++#endif
++
++/**
++ * This function is used to submit an I/O Request to an EP.
++ *
++ *	- When the request completes the request's completion callback
++ *	  is called to return the request to the driver.
++ *	- An EP, except control EPs, may have multiple requests
++ *	  pending.
++ *	- Once submitted the request cannot be examined or modified.
++ *	- Each request is turned into one or more packets.
++ *	- A BULK EP can queue any amount of data; the transfer is
++ *	  packetized.
++ *	- Zero length Packets are specified with the request 'zero'
++ *	  flag.
++ */
++static int ep_queue(struct usb_ep *usb_ep, struct usb_request *usb_req,
++		    gfp_t gfp_flags)
++{
++	dwc_otg_pcd_t *pcd;
++	struct dwc_otg_pcd_ep *ep;
++	int retval, is_isoc_ep;
++	dma_addr_t dma_addr = 0;
++
++	DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p,%d)\n",
++		    __func__, usb_ep, usb_req, gfp_flags);
++
++	if (!usb_req || !usb_req->complete || !usb_req->buf) {
++		DWC_WARN("bad params\n");
++		return -EINVAL;
++	}
++
++	if (!usb_ep) {
++		DWC_WARN("bad ep\n");
++		return -EINVAL;
++	}
++
++	pcd = gadget_wrapper->pcd;
++	if (!gadget_wrapper->driver ||
++	    gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
++		DWC_DEBUGPL(DBG_PCDV, "gadget.speed=%d\n",
++			    gadget_wrapper->gadget.speed);
++		DWC_WARN("bogus device state\n");
++		return -ESHUTDOWN;
++	}
++
++	DWC_DEBUGPL(DBG_PCD, "%s queue req %p, len %d buf %p\n",
++		    usb_ep->name, usb_req, usb_req->length, usb_req->buf);
++
++	usb_req->status = -EINPROGRESS;
++	usb_req->actual = 0;
++
++	ep = ep_from_handle(pcd, usb_ep);
++	if (ep == NULL)
++		return -EINVAL;
++	else
++		is_isoc_ep = (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) ? 1 : 0;
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
++	dma_addr = usb_req->dma;
++#else
++	if (GET_CORE_IF(pcd)->dma_enable) {
++		retval = usb_gadget_map_req(&gadget_wrapper->gadget,
++					usb_req, ep);
++		if (retval) {
++			return -EINVAL;
++		}
++		dma_addr =usb_req->dma;
++	}
++#endif
++
++#ifdef DWC_UTE_PER_IO
++	if (is_isoc_ep == 1) {
++		retval =
++		    dwc_otg_pcd_xiso_ep_queue(pcd, usb_ep, usb_req->buf,
++					      dma_addr, usb_req->length,
++					      usb_req->zero, usb_req,
++					      gfp_flags == GFP_ATOMIC ? 1 : 0,
++					      &usb_req->ext_req);
++		if (retval)
++			return -EINVAL;
++
++		return 0;
++	}
++#endif
++	retval = dwc_otg_pcd_ep_queue(pcd, usb_ep, usb_req->buf, dma_addr,
++				      usb_req->length, usb_req->zero, usb_req,
++				      gfp_flags == GFP_ATOMIC ? 1 : 0);
++	if (retval) {
++		return -EINVAL;
++	}
++
++	return 0;
++}
++
++/**
++ * This function cancels an I/O request from an EP.
++ */
++static int ep_dequeue(struct usb_ep *usb_ep, struct usb_request *usb_req)
++{
++	DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p)\n", __func__, usb_ep, usb_req);
++
++	if (!usb_ep || !usb_req) {
++		DWC_WARN("bad argument\n");
++		return -EINVAL;
++	}
++	if (!gadget_wrapper->driver ||
++	    gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
++		DWC_WARN("bogus device state\n");
++		return -ESHUTDOWN;
++	}
++	if (dwc_otg_pcd_ep_dequeue(gadget_wrapper->pcd, usb_ep, usb_req)) {
++		return -EINVAL;
++	}
++
++	return 0;
++}
++
++/**
++ * usb_ep_set_halt stalls an endpoint.
++ *
++ * usb_ep_clear_halt clears an endpoint halt and resets its data
++ * toggle.
++ *
++ * Both of these functions are implemented with the same underlying
++ * function. The behavior depends on the value argument.
++ *
++ * @param[in] usb_ep the Endpoint to halt or clear halt.
++ * @param[in] value
++ *	- 0 means clear_halt.
++ *	- 1 means set_halt,
++ *	- 2 means clear stall lock flag.
++ *	- 3 means set  stall lock flag.
++ */
++static int ep_halt(struct usb_ep *usb_ep, int value)
++{
++	int retval = 0;
++
++	DWC_DEBUGPL(DBG_PCD, "HALT %s %d\n", usb_ep->name, value);
++
++	if (!usb_ep) {
++		DWC_WARN("bad ep\n");
++		return -EINVAL;
++	}
++
++	retval = dwc_otg_pcd_ep_halt(gadget_wrapper->pcd, usb_ep, value);
++	if (retval == -DWC_E_AGAIN) {
++		return -EAGAIN;
++	} else if (retval) {
++		retval = -EINVAL;
++	}
++
++	return retval;
++}
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
++static int ep_wedge(struct usb_ep *usb_ep)
++{
++	DWC_DEBUGPL(DBG_PCD, "WEDGE %s\n", usb_ep->name);
++
++	return ep_halt(usb_ep, 3);
++}
++#endif
++
++#ifdef DWC_EN_ISOC
++/**
++ * This function is used to submit an ISOC Transfer Request to an EP.
++ *
++ *	- Every time a sync period completes the request's completion callback
++ *	  is called to provide data to the gadget driver.
++ *	- Once submitted the request cannot be modified.
++ *	- Each request is turned into periodic data packets untill ISO
++ *	  Transfer is stopped..
++ */
++static int iso_ep_start(struct usb_ep *usb_ep, struct usb_iso_request *req,
++			gfp_t gfp_flags)
++{
++	int retval = 0;
++
++	if (!req || !req->process_buffer || !req->buf0 || !req->buf1) {
++		DWC_WARN("bad params\n");
++		return -EINVAL;
++	}
++
++	if (!usb_ep) {
++		DWC_PRINTF("bad params\n");
++		return -EINVAL;
++	}
++
++	req->status = -EINPROGRESS;
++
++	retval =
++	    dwc_otg_pcd_iso_ep_start(gadget_wrapper->pcd, usb_ep, req->buf0,
++				     req->buf1, req->dma0, req->dma1,
++				     req->sync_frame, req->data_pattern_frame,
++				     req->data_per_frame,
++				     req->
++				     flags & USB_REQ_ISO_ASAP ? -1 :
++				     req->start_frame, req->buf_proc_intrvl,
++				     req, gfp_flags == GFP_ATOMIC ? 1 : 0);
++
++	if (retval) {
++		return -EINVAL;
++	}
++
++	return retval;
++}
++
++/**
++ * This function stops ISO EP Periodic Data Transfer.
++ */
++static int iso_ep_stop(struct usb_ep *usb_ep, struct usb_iso_request *req)
++{
++	int retval = 0;
++	if (!usb_ep) {
++		DWC_WARN("bad ep\n");
++	}
++
++	if (!gadget_wrapper->driver ||
++	    gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
++		DWC_DEBUGPL(DBG_PCDV, "gadget.speed=%d\n",
++			    gadget_wrapper->gadget.speed);
++		DWC_WARN("bogus device state\n");
++	}
++
++	dwc_otg_pcd_iso_ep_stop(gadget_wrapper->pcd, usb_ep, req);
++	if (retval) {
++		retval = -EINVAL;
++	}
++
++	return retval;
++}
++
++static struct usb_iso_request *alloc_iso_request(struct usb_ep *ep,
++						 int packets, gfp_t gfp_flags)
++{
++	struct usb_iso_request *pReq = NULL;
++	uint32_t req_size;
++
++	req_size = sizeof(struct usb_iso_request);
++	req_size +=
++	    (2 * packets * (sizeof(struct usb_gadget_iso_packet_descriptor)));
++
++	pReq = kmalloc(req_size, gfp_flags);
++	if (!pReq) {
++		DWC_WARN("Can't allocate Iso Request\n");
++		return 0;
++	}
++	pReq->iso_packet_desc0 = (void *)(pReq + 1);
++
++	pReq->iso_packet_desc1 = pReq->iso_packet_desc0 + packets;
++
++	return pReq;
++}
++
++static void free_iso_request(struct usb_ep *ep, struct usb_iso_request *req)
++{
++	kfree(req);
++}
++
++static struct usb_isoc_ep_ops dwc_otg_pcd_ep_ops = {
++	.ep_ops = {
++		   .enable = ep_enable,
++		   .disable = ep_disable,
++
++		   .alloc_request = dwc_otg_pcd_alloc_request,
++		   .free_request = dwc_otg_pcd_free_request,
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
++		   .alloc_buffer = dwc_otg_pcd_alloc_buffer,
++		   .free_buffer = dwc_otg_pcd_free_buffer,
++#endif
++
++		   .queue = ep_queue,
++		   .dequeue = ep_dequeue,
++
++		   .set_halt = ep_halt,
++
++		    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
++					.set_wedge = ep_wedge,
++			#endif
++					.fifo_status = 0,
++					.fifo_flush = 0,
++			},
++
++	.iso_ep_start = iso_ep_start,
++	.iso_ep_stop = iso_ep_stop,
++	.alloc_iso_request = alloc_iso_request,
++	.free_iso_request = free_iso_request,
++};
++
++#else
++
++static struct usb_ep_ops dwc_otg_pcd_ep_ops = {
++	.enable = ep_enable,
++	.disable = ep_disable,
++
++	.alloc_request = dwc_otg_pcd_alloc_request,
++	.free_request = dwc_otg_pcd_free_request,
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
++	.alloc_buffer = dwc_otg_pcd_alloc_buffer,
++	.free_buffer = dwc_otg_pcd_free_buffer,
++#endif
++
++	.queue = ep_queue,
++	.dequeue = ep_dequeue,
++
++	.set_halt = ep_halt,
++
++	#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
++		.set_wedge = ep_wedge,
++    #endif
++
++	.fifo_status = 0,
++	.fifo_flush = 0,
++
++};
++
++#endif /* _EN_ISOC_ */
++/*	Gadget Operations */
++/**
++ * The following gadget operations will be implemented in the DWC_otg
++ * PCD. Functions in the API that are not described below are not
++ * implemented.
++ *
++ * The Gadget API provides wrapper functions for each of the function
++ * pointers defined in usb_gadget_ops. The Gadget Driver calls the
++ * wrapper function, which then calls the underlying PCD function. The
++ * following sections are named according to the wrapper functions
++ * (except for ioctl, which doesn't have a wrapper function). Within
++ * each section, the corresponding DWC_otg PCD function name is
++ * specified.
++ *
++ */
++
++/**
++ *Gets the USB Frame number of the last SOF.
++ */
++static int get_frame_number(struct usb_gadget *gadget)
++{
++	struct gadget_wrapper *d;
++
++	DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, gadget);
++
++	if (gadget == 0) {
++		return -ENODEV;
++	}
++
++	d = container_of(gadget, struct gadget_wrapper, gadget);
++	return dwc_otg_pcd_get_frame_number(d->pcd);
++}
++
++#ifdef CONFIG_USB_DWC_OTG_LPM
++static int test_lpm_enabled(struct usb_gadget *gadget)
++{
++	struct gadget_wrapper *d;
++
++	d = container_of(gadget, struct gadget_wrapper, gadget);
++
++	return dwc_otg_pcd_is_lpm_enabled(d->pcd);
++}
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)
++static int test_besl_enabled(struct usb_gadget *gadget)
++{
++	struct gadget_wrapper *d;
++
++	d = container_of(gadget, struct gadget_wrapper, gadget);
++
++	return dwc_otg_pcd_is_besl_enabled(d->pcd);
++}
++static int get_param_baseline_besl(struct usb_gadget *gadget)
++{
++	struct gadget_wrapper *d;
++
++	d = container_of(gadget, struct gadget_wrapper, gadget);
++
++	return dwc_otg_pcd_get_param_baseline_besl(d->pcd);
++}
++static int get_param_deep_besl(struct usb_gadget *gadget)
++{
++	struct gadget_wrapper *d;
++
++	d = container_of(gadget, struct gadget_wrapper, gadget);
++
++	return dwc_otg_pcd_get_param_deep_besl(d->pcd);
++}
++#endif
++#endif
++
++/**
++ * Initiates Session Request Protocol (SRP) to wakeup the host if no
++ * session is in progress. If a session is already in progress, but
++ * the device is suspended, remote wakeup signaling is started.
++ *
++ */
++static int wakeup(struct usb_gadget *gadget)
++{
++	struct gadget_wrapper *d;
++
++	DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, gadget);
++
++	if (gadget == 0) {
++		return -ENODEV;
++	} else {
++		d = container_of(gadget, struct gadget_wrapper, gadget);
++	}
++	dwc_otg_pcd_wakeup(d->pcd);
++	return 0;
++}
++
++static int pullup(struct usb_gadget *gadget, int is_on)
++{
++	struct gadget_wrapper *d;
++
++	DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, gadget);
++
++	if (gadget == 0) {
++		return -ENODEV;
++	} else {
++		d = container_of(gadget, struct gadget_wrapper, gadget);
++	}
++
++	if (!is_on)
++		dwc_otg_pcd_pullup(d->pcd);
++
++	return 0;
++}
++
++static const struct usb_gadget_ops dwc_otg_pcd_ops = {
++	.get_frame = get_frame_number,
++	.wakeup = wakeup,
++	.pullup = pullup,
++#ifdef CONFIG_USB_DWC_OTG_LPM
++	.lpm_support = test_lpm_enabled,
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)
++	.besl_support = test_besl_enabled,
++	.get_baseline_besl = get_param_baseline_besl,
++	.get_deep_besl = get_param_deep_besl,
++#endif
++#endif
++	// current versions must always be self-powered
++};
++
++static int _setup(dwc_otg_pcd_t * pcd, uint8_t * bytes)
++{
++	int retval = -DWC_E_NOT_SUPPORTED;
++	if (gadget_wrapper->driver && gadget_wrapper->driver->setup) {
++		retval = gadget_wrapper->driver->setup(&gadget_wrapper->gadget,
++						       (struct usb_ctrlrequest
++							*)bytes);
++	}
++
++	if (retval == -ENOTSUPP) {
++		retval = -DWC_E_NOT_SUPPORTED;
++	} else if (retval < 0) {
++		retval = -DWC_E_INVALID;
++	}
++
++	return retval;
++}
++
++#ifdef DWC_EN_ISOC
++static int _isoc_complete(dwc_otg_pcd_t * pcd, void *ep_handle,
++			  void *req_handle, int proc_buf_num)
++{
++	int i, packet_count;
++	struct usb_gadget_iso_packet_descriptor *iso_packet = 0;
++	struct usb_iso_request *iso_req = req_handle;
++
++	if (proc_buf_num) {
++		iso_packet = iso_req->iso_packet_desc1;
++	} else {
++		iso_packet = iso_req->iso_packet_desc0;
++	}
++	packet_count =
++	    dwc_otg_pcd_get_iso_packet_count(pcd, ep_handle, req_handle);
++	for (i = 0; i < packet_count; ++i) {
++		int status;
++		int actual;
++		int offset;
++		dwc_otg_pcd_get_iso_packet_params(pcd, ep_handle, req_handle,
++						  i, &status, &actual, &offset);
++		switch (status) {
++		case -DWC_E_NO_DATA:
++			status = -ENODATA;
++			break;
++		default:
++			if (status) {
++				DWC_PRINTF("unknown status in isoc packet\n");
++			}
++
++		}
++		iso_packet[i].status = status;
++		iso_packet[i].offset = offset;
++		iso_packet[i].actual_length = actual;
++	}
++
++	iso_req->status = 0;
++	iso_req->process_buffer(ep_handle, iso_req);
++
++	return 0;
++}
++#endif /* DWC_EN_ISOC */
++
++#ifdef DWC_UTE_PER_IO
++/**
++ * Copy the contents of the extended request to the Linux usb_request's
++ * extended part and call the gadget's completion.
++ *
++ * @param pcd			Pointer to the pcd structure
++ * @param ep_handle		Void pointer to the usb_ep structure
++ * @param req_handle	Void pointer to the usb_request structure
++ * @param status		Request status returned from the portable logic
++ * @param ereq_port		Void pointer to the extended request structure
++ *						created in the the portable part that contains the
++ *						results of the processed iso packets.
++ */
++static int _xisoc_complete(dwc_otg_pcd_t * pcd, void *ep_handle,
++			   void *req_handle, int32_t status, void *ereq_port)
++{
++	struct dwc_ute_iso_req_ext *ereqorg = NULL;
++	struct dwc_iso_xreq_port *ereqport = NULL;
++	struct dwc_ute_iso_packet_descriptor *desc_org = NULL;
++	int i;
++	struct usb_request *req;
++	//struct dwc_ute_iso_packet_descriptor *
++	//int status = 0;
++
++	req = (struct usb_request *)req_handle;
++	ereqorg = &req->ext_req;
++	ereqport = (struct dwc_iso_xreq_port *)ereq_port;
++	desc_org = ereqorg->per_io_frame_descs;
++
++	if (req && req->complete) {
++		/* Copy the request data from the portable logic to our request */
++		for (i = 0; i < ereqport->pio_pkt_count; i++) {
++			desc_org[i].actual_length =
++			    ereqport->per_io_frame_descs[i].actual_length;
++			desc_org[i].status =
++			    ereqport->per_io_frame_descs[i].status;
++		}
++
++		switch (status) {
++		case -DWC_E_SHUTDOWN:
++			req->status = -ESHUTDOWN;
++			break;
++		case -DWC_E_RESTART:
++			req->status = -ECONNRESET;
++			break;
++		case -DWC_E_INVALID:
++			req->status = -EINVAL;
++			break;
++		case -DWC_E_TIMEOUT:
++			req->status = -ETIMEDOUT;
++			break;
++		default:
++			req->status = status;
++		}
++
++		/* And call the gadget's completion */
++		req->complete(ep_handle, req);
++	}
++
++	return 0;
++}
++#endif /* DWC_UTE_PER_IO */
++static int _complete(dwc_otg_pcd_t * pcd, void *ep_handle,
++		     void *req_handle, int32_t status, uint32_t actual)
++{
++	struct usb_request *req = (struct usb_request *)req_handle;
++	struct dwc_otg_pcd_ep *ep = NULL;
++
++	ep = ep_from_handle(pcd, ep_handle);
++	if (!ep)
++		return -EINVAL;
++
++	if (GET_CORE_IF(pcd)->dma_enable) {
++		if (req->dma)
++			usb_gadget_unmap_req(&gadget_wrapper->gadget,
++						req, ep);
++		req->dma = (dma_addr_t)0;
++	}
++
++	if (req && req->complete) {
++		switch (status) {
++		case -DWC_E_SHUTDOWN:
++			req->status = -ESHUTDOWN;
++			break;
++		case -DWC_E_RESTART:
++			req->status = -ECONNRESET;
++			break;
++		case -DWC_E_INVALID:
++			req->status = -EINVAL;
++			break;
++		case -DWC_E_TIMEOUT:
++			req->status = -ETIMEDOUT;
++			break;
++		default:
++			req->status = status;
++
++		}
++
++		req->actual = actual;
++		DWC_SPINUNLOCK(pcd->lock);
++		req->complete(ep_handle, req);
++		DWC_SPINLOCK(pcd->lock);
++	}
++#ifdef PCI_INTERFACE
++	dev = gadget_wrapper->pcd->otg_dev->os_dep.pcidev;
++	ep = ep_from_handle(pcd, ep_handle);
++	if (GET_CORE_IF(pcd)->dma_enable) {
++		if (req->length != 0)
++			pci_unmap_single(dev, req->dma, req->length,
++					 ep->dwc_ep.is_in ? PCI_DMA_TODEVICE :
++					 PCI_DMA_FROMDEVICE);
++	}
++#endif
++
++	return 0;
++}
++
++static int _connect(dwc_otg_pcd_t * pcd, int speed)
++{
++	gadget_wrapper->gadget.speed = speed;
++	return 0;
++}
++
++static int _disconnect(dwc_otg_pcd_t * pcd)
++{
++	if (gadget_wrapper->driver && gadget_wrapper->driver->disconnect) {
++		gadget_wrapper->driver->disconnect(&gadget_wrapper->gadget);
++	}
++	return 0;
++}
++
++static int _resume(dwc_otg_pcd_t * pcd)
++{
++	if (gadget_wrapper->driver && gadget_wrapper->driver->resume) {
++		gadget_wrapper->driver->resume(&gadget_wrapper->gadget);
++	}
++
++	return 0;
++}
++
++static int _suspend(dwc_otg_pcd_t * pcd)
++{
++	if (gadget_wrapper->driver && gadget_wrapper->driver->suspend) {
++		gadget_wrapper->driver->suspend(&gadget_wrapper->gadget);
++	}
++	return 0;
++}
++
++/**
++ * This function updates the otg values in the gadget structure.
++ */
++static int _hnp_changed(dwc_otg_pcd_t * pcd)
++{
++
++	if (!gadget_wrapper->gadget.is_otg)
++		return 0;
++
++	gadget_wrapper->gadget.b_hnp_enable = get_b_hnp_enable(pcd);
++	gadget_wrapper->gadget.a_hnp_support = get_a_hnp_support(pcd);
++	gadget_wrapper->gadget.a_alt_hnp_support = get_a_alt_hnp_support(pcd);
++	return 0;
++}
++
++static int _reset(dwc_otg_pcd_t * pcd)
++{
++	return 0;
++}
++
++#ifdef DWC_UTE_CFI
++static int _cfi_setup(dwc_otg_pcd_t * pcd, void *cfi_req)
++{
++	int retval = -DWC_E_INVALID;
++	if (gadget_wrapper->driver->cfi_feature_setup) {
++		retval =
++		    gadget_wrapper->driver->
++		    cfi_feature_setup(&gadget_wrapper->gadget,
++				      (struct cfi_usb_ctrlrequest *)cfi_req);
++	}
++
++	return retval;
++}
++#endif
++
++static const struct dwc_otg_pcd_function_ops fops = {
++	.complete = _complete,
++#ifdef DWC_EN_ISOC
++	.isoc_complete = _isoc_complete,
++#endif
++	.setup = _setup,
++	.disconnect = _disconnect,
++	.connect = _connect,
++	.resume = _resume,
++	.suspend = _suspend,
++	.hnp_changed = _hnp_changed,
++	.reset = _reset,
++#ifdef DWC_UTE_CFI
++	.cfi_setup = _cfi_setup,
++#endif
++#ifdef DWC_UTE_PER_IO
++	.xisoc_complete = _xisoc_complete,
++#endif
++};
++
++/**
++ * This function is the top level PCD interrupt handler.
++ */
++static irqreturn_t dwc_otg_pcd_irq(int irq, void *dev)
++{
++	dwc_otg_pcd_t *pcd = dev;
++	int32_t retval = IRQ_NONE;
++
++	retval = dwc_otg_pcd_handle_intr(pcd);
++	if (retval != 0) {
++		S3C2410X_CLEAR_EINTPEND();
++	}
++	return IRQ_RETVAL(retval);
++}
++
++/**
++ * This function initialized the usb_ep structures to there default
++ * state.
++ *
++ * @param d Pointer on gadget_wrapper.
++ */
++void gadget_add_eps(struct gadget_wrapper *d)
++{
++	static const char *names[] = {
++
++		"ep0",
++		"ep1in",
++		"ep2in",
++		"ep3in",
++		"ep4in",
++		"ep5in",
++		"ep6in",
++		"ep7in",
++		"ep8in",
++		"ep9in",
++		"ep10in",
++		"ep11in",
++		"ep12in",
++		"ep13in",
++		"ep14in",
++		"ep15in",
++		"ep1out",
++		"ep2out",
++		"ep3out",
++		"ep4out",
++		"ep5out",
++		"ep6out",
++		"ep7out",
++		"ep8out",
++		"ep9out",
++		"ep10out",
++		"ep11out",
++		"ep12out",
++		"ep13out",
++		"ep14out",
++		"ep15out"
++	};
++
++	int i;
++	struct usb_ep *ep;
++	int8_t dev_endpoints;
++
++	DWC_DEBUGPL(DBG_PCDV, "%s\n", __func__);
++
++	INIT_LIST_HEAD(&d->gadget.ep_list);
++	d->gadget.ep0 = &d->ep0;
++	d->gadget.speed = USB_SPEED_UNKNOWN;
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0)
++	d->gadget.max_speed = USB_SPEED_HIGH;
++#endif
++
++	INIT_LIST_HEAD(&d->gadget.ep0->ep_list);
++
++	/**
++	 * Initialize the EP0 structure.
++	 */
++	ep = &d->ep0;
++
++	/* Init the usb_ep structure. */
++	ep->name = names[0];
++	ep->ops = (struct usb_ep_ops *)&dwc_otg_pcd_ep_ops;
++
++	/**
++	 * @todo NGS: What should the max packet size be set to
++	 * here?  Before EP type is set?
++	 */
++	ep->maxpacket = MAX_PACKET_SIZE;
++	dwc_otg_pcd_ep_enable(d->pcd, NULL, ep);
++
++	list_add_tail(&ep->ep_list, &d->gadget.ep_list);
++
++	/**
++	 * Initialize the EP structures.
++	 */
++	dev_endpoints = d->pcd->core_if->dev_if->num_in_eps;
++
++	for (i = 0; i < dev_endpoints; i++) {
++		ep = &d->in_ep[i];
++
++		/* Init the usb_ep structure. */
++		ep->name = names[d->pcd->in_ep[i].dwc_ep.num];
++		ep->ops = (struct usb_ep_ops *)&dwc_otg_pcd_ep_ops;
++
++		/**
++		 * @todo NGS: What should the max packet size be set to
++		 * here?  Before EP type is set?
++		 */
++		ep->maxpacket = MAX_PACKET_SIZE;
++		ep->maxpacket_limit = MAX_PACKET_SIZE;
++		list_add_tail(&ep->ep_list, &d->gadget.ep_list);
++	}
++
++	dev_endpoints = d->pcd->core_if->dev_if->num_out_eps;
++
++	for (i = 0; i < dev_endpoints; i++) {
++		ep = &d->out_ep[i];
++
++		/* Init the usb_ep structure. */
++		ep->name = names[15 + d->pcd->out_ep[i].dwc_ep.num];
++		ep->ops = (struct usb_ep_ops *)&dwc_otg_pcd_ep_ops;
++
++		/**
++		 * @todo NGS: What should the max packet size be set to
++		 * here?  Before EP type is set?
++		 */
++		ep->maxpacket = MAX_PACKET_SIZE;
++		ep->maxpacket_limit = MAX_PACKET_SIZE;
++
++		list_add_tail(&ep->ep_list, &d->gadget.ep_list);
++	}
++
++	/* remove ep0 from the list.  There is a ep0 pointer. */
++	list_del_init(&d->ep0.ep_list);
++
++	d->ep0.maxpacket = MAX_EP0_SIZE;
++}
++
++/**
++ * This function releases the Gadget device.
++ * required by device_unregister().
++ *
++ * @todo Should this do something?	Should it free the PCD?
++ */
++static void dwc_otg_pcd_gadget_release(struct device *dev)
++{
++	DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, dev);
++}
++
++static struct gadget_wrapper *alloc_wrapper(
++	struct platform_device *_dev
++    )
++{
++	static char pcd_name[] = "dwc_otg_pcd";
++
++	dwc_otg_device_t *otg_dev =platform_get_drvdata(_dev);
++
++
++	struct gadget_wrapper *d;
++	int retval;
++
++	d = DWC_ALLOC(sizeof(*d));
++	if (d == NULL) {
++		return NULL;
++	}
++
++	memset(d, 0, sizeof(*d));
++
++	d->gadget.name = pcd_name;
++	d->pcd = otg_dev->pcd;
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
++	strcpy(d->gadget.dev.bus_id, "gadget");
++#else
++	dev_set_name(&d->gadget.dev, "%s", "gadget");
++#endif
++
++	d->gadget.dev.parent = &_dev->dev;
++	d->gadget.dev.release = dwc_otg_pcd_gadget_release;
++	d->gadget.ops = &dwc_otg_pcd_ops;
++#if LINUX_VERSION_CODE < KERNEL_VERSION(3,3,0)
++	d->gadget.is_dualspeed = dwc_otg_pcd_is_dualspeed(otg_dev->pcd);
++#endif
++	d->gadget.is_otg = dwc_otg_pcd_is_otg(otg_dev->pcd);
++
++	d->driver = 0;
++	/* Register the gadget device */
++	retval = device_register(&d->gadget.dev);
++	if (retval != 0) {
++		DWC_ERROR("device_register failed\n");
++		DWC_FREE(d);
++		return NULL;
++	}
++
++	return d;
++}
++
++static void free_wrapper(struct gadget_wrapper *d)
++{
++	if (d->driver) {
++		/* should have been done already by driver model core */
++		DWC_WARN("driver '%s' is still registered\n",
++			 d->driver->driver.name);
++		usb_gadget_unregister_driver(d->driver);
++	}
++
++	device_unregister(&d->gadget.dev);
++	DWC_FREE(d);
++}
++
++/**
++ * This function initialized the PCD portion of the driver.
++ *
++ */
++int pcd_init(struct platform_device *_dev, int irqnum )
++{
++	dwc_otg_device_t *otg_dev = platform_get_drvdata(_dev);
++
++	int retval = 0;
++
++	DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, _dev);
++
++	otg_dev->pcd = dwc_otg_pcd_init(otg_dev->core_if);
++
++	if (!otg_dev->pcd) {
++		DWC_ERROR("dwc_otg_pcd_init failed\n");
++		return -ENOMEM;
++	}
++
++	otg_dev->pcd->otg_dev = otg_dev;
++	gadget_wrapper = alloc_wrapper(_dev);
++
++	/*
++	 * Initialize EP structures
++	 */
++	gadget_add_eps(gadget_wrapper);
++	/*
++	 * Setup interupt handler
++	 */
++	DWC_DEBUGPL(DBG_ANY, "registering handler for irq%d\n", irqnum);
++	retval = request_irq(irqnum, dwc_otg_pcd_irq,
++			     IRQF_SHARED | IRQF_DISABLED,
++			     gadget_wrapper->gadget.name, otg_dev->pcd);
++	if (retval != 0) {
++		DWC_ERROR("request of irq%d failed\n", irqnum);
++		free_wrapper(gadget_wrapper);
++		return -EBUSY;
++	}
++
++
++	dwc_otg_pcd_start(gadget_wrapper->pcd, &fops);
++
++	return retval;
++}
++
++/**
++ * Cleanup the PCD.
++ */
++void pcd_remove(	struct platform_device *_dev   )
++{
++
++	dwc_otg_device_t *otg_dev = platform_get_drvdata(_dev);
++
++	dwc_otg_pcd_t *pcd = otg_dev->pcd;
++
++	DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, _dev);
++
++	/*
++	 * Free the IRQ
++	 */
++	free_irq(_dev->resource[1].start, pcd);
++	free_wrapper(gadget_wrapper);
++	dwc_otg_pcd_remove(otg_dev->pcd);
++	otg_dev->pcd = 0;
++}
++
++/**
++ * This function registers a gadget driver with the PCD.
++ *
++ * When a driver is successfully registered, it will receive control
++ * requests including set_configuration(), which enables non-control
++ * requests.  then usb traffic follows until a disconnect is reported.
++ * then a host may connect again, or the driver might get unbound.
++ *
++ * @param driver The driver being registered
++ * @param bind The bind function of gadget driver
++ */
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)
++int usb_gadget_register_driver(struct usb_gadget_driver *driver)
++#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
++	int usb_gadget_probe_driver(struct usb_gadget_driver *driver)
++#else
++int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
++		int (*bind)(struct usb_gadget *))
++#endif
++{
++	int retval;
++
++	DWC_DEBUGPL(DBG_PCD, "registering gadget driver '%s'\n",
++		    driver->driver.name);
++
++	if (!driver ||
++#if LINUX_VERSION_CODE < KERNEL_VERSION(3,3,0)
++		driver->speed == USB_SPEED_UNKNOWN ||
++#else
++		driver->max_speed == USB_SPEED_UNKNOWN ||
++#endif
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37) || LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
++	    !driver->bind ||
++#else
++		!bind ||
++#endif
++	    !driver->unbind || !driver->disconnect || !driver->setup) {
++		DWC_DEBUGPL(DBG_PCDV, "EINVAL\n");
++		return -EINVAL;
++	}
++	if (gadget_wrapper == 0) {
++		DWC_DEBUGPL(DBG_PCDV, "ENODEV\n");
++		return -ENODEV;
++	}
++	if (gadget_wrapper->driver != 0) {
++		DWC_DEBUGPL(DBG_PCDV, "EBUSY (%p)\n", gadget_wrapper->driver);
++		return -EBUSY;
++	}
++
++	/* hook up the driver */
++	gadget_wrapper->driver = driver;
++	gadget_wrapper->gadget.dev.driver = &driver->driver;
++
++	DWC_DEBUGPL(DBG_PCD, "bind to driver %s\n", driver->driver.name);
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)
++	retval = driver->bind(&gadget_wrapper->gadget);
++#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
++	retval = driver->bind(&gadget_wrapper->gadget,gadget_wrapper->driver);
++#else
++	retval = bind(&gadget_wrapper->gadget);
++#endif
++	if (retval) {
++		DWC_ERROR("bind to driver %s --> error %d\n",
++			  driver->driver.name, retval);
++		gadget_wrapper->driver = 0;
++		gadget_wrapper->gadget.dev.driver = 0;
++		return retval;
++	}
++	DWC_DEBUGPL(DBG_ANY, "registered gadget driver '%s'\n",
++		    driver->driver.name);
++	return 0;
++}
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)
++EXPORT_SYMBOL(usb_gadget_register_driver);
++#else
++EXPORT_SYMBOL(usb_gadget_probe_driver);
++#endif
++
++/**
++ * This function unregisters a gadget driver
++ *
++ * @param driver The driver being unregistered
++ */
++int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
++{
++	//DWC_DEBUGPL(DBG_PCDV,"%s(%p)\n", __func__, _driver);
++
++	if (gadget_wrapper == 0) {
++		DWC_DEBUGPL(DBG_ANY, "%s Return(%d): s_pcd==0\n", __func__,
++			    -ENODEV);
++		return -ENODEV;
++	}
++	if (driver == 0 || driver != gadget_wrapper->driver) {
++		DWC_DEBUGPL(DBG_ANY, "%s Return(%d): driver?\n", __func__,
++			    -EINVAL);
++		return -EINVAL;
++	}
++
++	driver->disconnect(&gadget_wrapper->gadget);
++	driver->unbind(&gadget_wrapper->gadget);
++	gadget_wrapper->driver = 0;
++
++	DWC_DEBUGPL(DBG_ANY, "unregistered driver '%s'\n", driver->driver.name);
++	return 0;
++}
++
++EXPORT_SYMBOL(usb_gadget_unregister_driver);
++
++#endif /* DWC_HOST_ONLY */
+diff --git a/drivers/usb/gadget/udc/hiudc/dwc_otg_regs.h b/drivers/usb/gadget/udc/hiudc/dwc_otg_regs.h
+new file mode 100644
+index 0000000..782976b
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc/dwc_otg_regs.h
+@@ -0,0 +1,2557 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_regs.h $
++ * $Revision: #99 $
++ * $Date: 2012/12/10 $
++ * $Change: 2123206 $
++ *
++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
++ * ========================================================================== */
++
++#ifndef __DWC_OTG_REGS_H__
++#define __DWC_OTG_REGS_H__
++
++#include "dwc_otg_core_if.h"
++
++/**
++ * @file
++ *
++ * This file contains the data structures for accessing the DWC_otg core registers.
++ *
++ * The application interfaces with the HS OTG core by reading from and
++ * writing to the Control and Status Register (CSR) space through the
++ * AHB Slave interface. These registers are 32 bits wide, and the
++ * addresses are 32-bit-block aligned.
++ * CSRs are classified as follows:
++ * - Core Global Registers
++ * - Device Mode Registers
++ * - Device Global Registers
++ * - Device Endpoint Specific Registers
++ * - Host Mode Registers
++ * - Host Global Registers
++ * - Host Port CSRs
++ * - Host Channel Specific Registers
++ *
++ * Only the Core Global registers can be accessed in both Device and
++ * Host modes. When the HS OTG core is operating in one mode, either
++ * Device or Host, the application must not access registers from the
++ * other mode. When the core switches from one mode to another, the
++ * registers in the new mode of operation must be reprogrammed as they
++ * would be after a power-on reset.
++ */
++
++/****************************************************************************/
++/** DWC_otg Core registers .
++ * The dwc_otg_core_global_regs structure defines the size
++ * and relative field offsets for the Core Global registers.
++ */
++typedef struct dwc_otg_core_global_regs {
++	/** OTG Control and Status Register.  <i>Offset: 000h</i> */
++	volatile uint32_t gotgctl;
++	/** OTG Interrupt Register.	 <i>Offset: 004h</i> */
++	volatile uint32_t gotgint;
++	/**Core AHB Configuration Register.	 <i>Offset: 008h</i> */
++	volatile uint32_t gahbcfg;
++
++#define DWC_GLBINTRMASK		0x0001
++#define DWC_DMAENABLE		0x0020
++#define DWC_NPTXEMPTYLVL_EMPTY	0x0080
++#define DWC_NPTXEMPTYLVL_HALFEMPTY	0x0000
++#define DWC_PTXEMPTYLVL_EMPTY	0x0100
++#define DWC_PTXEMPTYLVL_HALFEMPTY	0x0000
++
++	/**Core USB Configuration Register.	 <i>Offset: 00Ch</i> */
++	volatile uint32_t gusbcfg;
++	/**Core Reset Register.	 <i>Offset: 010h</i> */
++	volatile uint32_t grstctl;
++	/**Core Interrupt Register.	 <i>Offset: 014h</i> */
++	volatile uint32_t gintsts;
++	/**Core Interrupt Mask Register.  <i>Offset: 018h</i> */
++	volatile uint32_t gintmsk;
++	/**Receive Status Queue Read Register (Read Only).	<i>Offset: 01Ch</i> */
++	volatile uint32_t grxstsr;
++	/**Receive Status Queue Read & POP Register (Read Only).  <i>Offset: 020h</i>*/
++	volatile uint32_t grxstsp;
++	/**Receive FIFO Size Register.	<i>Offset: 024h</i> */
++	volatile uint32_t grxfsiz;
++	/**Non Periodic Transmit FIFO Size Register.  <i>Offset: 028h</i> */
++	volatile uint32_t gnptxfsiz;
++	/**Non Periodic Transmit FIFO/Queue Status Register (Read
++	 * Only). <i>Offset: 02Ch</i> */
++	volatile uint32_t gnptxsts;
++	/**I2C Access Register.	 <i>Offset: 030h</i> */
++	volatile uint32_t gi2cctl;
++	/**PHY Vendor Control Register.	 <i>Offset: 034h</i> */
++	volatile uint32_t gpvndctl;
++	/**General Purpose Input/Output Register.  <i>Offset: 038h</i> */
++	volatile uint32_t ggpio;
++	/**User ID Register.  <i>Offset: 03Ch</i> */
++	volatile uint32_t guid;
++	/**Synopsys ID Register (Read Only).  <i>Offset: 040h</i> */
++	volatile uint32_t gsnpsid;
++	/**User HW Config1 Register (Read Only).  <i>Offset: 044h</i> */
++	volatile uint32_t ghwcfg1;
++	/**User HW Config2 Register (Read Only).  <i>Offset: 048h</i> */
++	volatile uint32_t ghwcfg2;
++#define DWC_SLAVE_ONLY_ARCH 0
++#define DWC_EXT_DMA_ARCH 1
++#define DWC_INT_DMA_ARCH 2
++
++#define DWC_MODE_HNP_SRP_CAPABLE	0
++#define DWC_MODE_SRP_ONLY_CAPABLE	1
++#define DWC_MODE_NO_HNP_SRP_CAPABLE		2
++#define DWC_MODE_SRP_CAPABLE_DEVICE		3
++#define DWC_MODE_NO_SRP_CAPABLE_DEVICE	4
++#define DWC_MODE_SRP_CAPABLE_HOST	5
++#define DWC_MODE_NO_SRP_CAPABLE_HOST	6
++
++	/**User HW Config3 Register (Read Only).  <i>Offset: 04Ch</i> */
++	volatile uint32_t ghwcfg3;
++	/**User HW Config4 Register (Read Only).  <i>Offset: 050h</i>*/
++	volatile uint32_t ghwcfg4;
++	/** Core LPM Configuration register <i>Offset: 054h</i>*/
++	volatile uint32_t glpmcfg;
++	/** Global PowerDn Register <i>Offset: 058h</i> */
++	volatile uint32_t gpwrdn;
++	/** Global DFIFO SW Config Register  <i>Offset: 05Ch</i> */
++	volatile uint32_t gdfifocfg;
++	/** ADP Control Register  <i>Offset: 060h</i> */
++	volatile uint32_t adpctl;
++	/** Reserved  <i>Offset: 064h-0FFh</i> */
++	volatile uint32_t reserved39[39];
++	/** Host Periodic Transmit FIFO Size Register. <i>Offset: 100h</i> */
++	volatile uint32_t hptxfsiz;
++	/** Device Periodic Transmit FIFO#n Register if dedicated fifos are disabled,
++		otherwise Device Transmit FIFO#n Register.
++	 * <i>Offset: 104h + (FIFO_Number-1)*04h, 1 <= FIFO Number <= 15 (1<=n<=15).</i> */
++	volatile uint32_t dtxfsiz[MAX_EPS_CHANNELS];
++} dwc_otg_core_global_regs_t;
++
++/**
++ * This union represents the bit fields of the Core OTG Control
++ * and Status Register (GOTGCTL).  Set the bits using the bit
++ * fields then write the <i>d32</i> value to the register.
++ */
++typedef union gotgctl_data {
++	/** raw register data */
++	uint32_t d32;
++	/** register bits */
++	struct {
++		unsigned sesreqscs:1;
++		unsigned sesreq:1;
++		unsigned vbvalidoven:1;
++		unsigned vbvalidovval:1;
++		unsigned avalidoven:1;
++		unsigned avalidovval:1;
++		unsigned bvalidoven:1;
++		unsigned bvalidovval:1;
++		unsigned hstnegscs:1;
++		unsigned hnpreq:1;
++		unsigned hstsethnpen:1;
++		unsigned devhnpen:1;
++		unsigned reserved12_15:4;
++		unsigned conidsts:1;
++		unsigned dbnctime:1;
++		unsigned asesvld:1;
++		unsigned bsesvld:1;
++		unsigned otgver:1;
++		unsigned reserved1:1;
++		unsigned multvalidbc:5;
++		unsigned chirpen:1;
++		unsigned reserved28_31:4;
++	} b;
++} gotgctl_data_t;
++
++/**
++ * This union represents the bit fields of the Core OTG Interrupt Register
++ * (GOTGINT).  Set/clear the bits using the bit fields then write the <i>d32</i>
++ * value to the register.
++ */
++typedef union gotgint_data {
++	/** raw register data */
++	uint32_t d32;
++	/** register bits */
++	struct {
++		/** Current Mode */
++		unsigned reserved0_1:2;
++
++		/** Session End Detected */
++		unsigned sesenddet:1;
++
++		unsigned reserved3_7:5;
++
++		/** Session Request Success Status Change */
++		unsigned sesreqsucstschng:1;
++		/** Host Negotiation Success Status Change */
++		unsigned hstnegsucstschng:1;
++
++		unsigned reserved10_16:7;
++
++		/** Host Negotiation Detected */
++		unsigned hstnegdet:1;
++		/** A-Device Timeout Change */
++		unsigned adevtoutchng:1;
++		/** Debounce Done */
++		unsigned debdone:1;
++		/** Multi-Valued input changed */
++		unsigned mvic:1;
++
++		unsigned reserved31_21:11;
++
++	} b;
++} gotgint_data_t;
++
++/**
++ * This union represents the bit fields of the Core AHB Configuration
++ * Register (GAHBCFG). Set/clear the bits using the bit fields then
++ * write the <i>d32</i> value to the register.
++ */
++typedef union gahbcfg_data {
++	/** raw register data */
++	uint32_t d32;
++	/** register bits */
++	struct {
++		unsigned glblintrmsk:1;
++#define DWC_GAHBCFG_GLBINT_ENABLE		1
++
++		unsigned hburstlen:4;
++#define DWC_GAHBCFG_INT_DMA_BURST_SINGLE	0
++#define DWC_GAHBCFG_INT_DMA_BURST_INCR		1
++#define DWC_GAHBCFG_INT_DMA_BURST_INCR4		3
++#define DWC_GAHBCFG_INT_DMA_BURST_INCR8		5
++#define DWC_GAHBCFG_INT_DMA_BURST_INCR16	7
++
++		unsigned dmaenable:1;
++#define DWC_GAHBCFG_DMAENABLE			1
++		unsigned reserved:1;
++		unsigned nptxfemplvl_txfemplvl:1;
++		unsigned ptxfemplvl:1;
++#define DWC_GAHBCFG_TXFEMPTYLVL_EMPTY		1
++#define DWC_GAHBCFG_TXFEMPTYLVL_HALFEMPTY	0
++		unsigned reserved9_20:12;
++		unsigned remmemsupp:1;
++		unsigned notialldmawrit:1;
++		unsigned ahbsingle:1;
++		unsigned reserved24_31:8;
++	} b;
++} gahbcfg_data_t;
++
++/**
++ * This union represents the bit fields of the Core USB Configuration
++ * Register (GUSBCFG). Set the bits using the bit fields then write
++ * the <i>d32</i> value to the register.
++ */
++typedef union gusbcfg_data {
++	/** raw register data */
++	uint32_t d32;
++	/** register bits */
++	struct {
++		unsigned toutcal:3;
++		unsigned phyif:1;
++		unsigned ulpi_utmi_sel:1;
++		unsigned fsintf:1;
++		unsigned physel:1;
++		unsigned ddrsel:1;
++		unsigned srpcap:1;
++		unsigned hnpcap:1;
++		unsigned usbtrdtim:4;
++		unsigned reserved1:1;
++		unsigned phylpwrclksel:1;
++		unsigned otgutmifssel:1;
++		unsigned ulpi_fsls:1;
++		unsigned ulpi_auto_res:1;
++		unsigned ulpi_clk_sus_m:1;
++		unsigned ulpi_ext_vbus_drv:1;
++		unsigned ulpi_int_vbus_indicator:1;
++		unsigned term_sel_dl_pulse:1;
++		unsigned indicator_complement:1;
++		unsigned indicator_pass_through:1;
++		unsigned ulpi_int_prot_dis:1;
++		unsigned ic_usb_cap:1;
++		unsigned ic_traffic_pull_remove:1;
++		unsigned tx_end_delay:1;
++		unsigned force_host_mode:1;
++		unsigned force_dev_mode:1;
++		unsigned reserved31:1;
++	} b;
++} gusbcfg_data_t;
++
++/**
++ * This union represents the bit fields of the Core Reset Register
++ * (GRSTCTL).  Set/clear the bits using the bit fields then write the
++ * <i>d32</i> value to the register.
++ */
++typedef union grstctl_data {
++	/** raw register data */
++	uint32_t d32;
++	/** register bits */
++	struct {
++		/** Core Soft Reset (CSftRst) (Device and Host)
++		 *
++		 * The application can flush the control logic in the
++		 * entire core using this bit. This bit resets the
++		 * pipelines in the AHB Clock domain as well as the
++		 * PHY Clock domain.
++		 *
++		 * The state machines are reset to an IDLE state, the
++		 * control bits in the CSRs are cleared, all the
++		 * transmit FIFOs and the receive FIFO are flushed.
++		 *
++		 * The status mask bits that control the generation of
++		 * the interrupt, are cleared, to clear the
++		 * interrupt. The interrupt status bits are not
++		 * cleared, so the application can get the status of
++		 * any events that occurred in the core after it has
++		 * set this bit.
++		 *
++		 * Any transactions on the AHB are terminated as soon
++		 * as possible following the protocol. Any
++		 * transactions on the USB are terminated immediately.
++		 *
++		 * The configuration settings in the CSRs are
++		 * unchanged, so the software doesn't have to
++		 * reprogram these registers (Device
++		 * Configuration/Host Configuration/Core System
++		 * Configuration/Core PHY Configuration).
++		 *
++		 * The application can write to this bit, any time it
++		 * wants to reset the core. This is a self clearing
++		 * bit and the core clears this bit after all the
++		 * necessary logic is reset in the core, which may
++		 * take several clocks, depending on the current state
++		 * of the core.
++		 */
++		unsigned csftrst:1;
++		/** Hclk Soft Reset
++		 *
++		 * The application uses this bit to reset the control logic in
++		 * the AHB clock domain. Only AHB clock domain pipelines are
++		 * reset.
++		 */
++		unsigned hsftrst:1;
++		/** Host Frame Counter Reset (Host Only)<br>
++		 *
++		 * The application can reset the (micro)frame number
++		 * counter inside the core, using this bit. When the
++		 * (micro)frame counter is reset, the subsequent SOF
++		 * sent out by the core, will have a (micro)frame
++		 * number of 0.
++		 */
++		unsigned hstfrm:1;
++		/** In Token Sequence Learning Queue Flush
++		 * (INTknQFlsh) (Device Only)
++		 */
++		unsigned intknqflsh:1;
++		/** RxFIFO Flush (RxFFlsh) (Device and Host)
++		 *
++		 * The application can flush the entire Receive FIFO
++		 * using this bit. The application must first
++		 * ensure that the core is not in the middle of a
++		 * transaction. The application should write into
++		 * this bit, only after making sure that neither the
++		 * DMA engine is reading from the RxFIFO nor the MAC
++		 * is writing the data in to the FIFO. The
++		 * application should wait until the bit is cleared
++		 * before performing any other operations. This bit
++		 * will takes 8 clocks (slowest of PHY or AHB clock)
++		 * to clear.
++		 */
++		unsigned rxfflsh:1;
++		/** TxFIFO Flush (TxFFlsh) (Device and Host).
++		 *
++		 * This bit is used to selectively flush a single or
++		 * all transmit FIFOs. The application must first
++		 * ensure that the core is not in the middle of a
++		 * transaction. The application should write into
++		 * this bit, only after making sure that neither the
++		 * DMA engine is writing into the TxFIFO nor the MAC
++		 * is reading the data out of the FIFO. The
++		 * application should wait until the core clears this
++		 * bit, before performing any operations. This bit
++		 * will takes 8 clocks (slowest of PHY or AHB clock)
++		 * to clear.
++		 */
++		unsigned txfflsh:1;
++
++		/** TxFIFO Number (TxFNum) (Device and Host).
++		 *
++		 * This is the FIFO number which needs to be flushed,
++		 * using the TxFIFO Flush bit. This field should not
++		 * be changed until the TxFIFO Flush bit is cleared by
++		 * the core.
++		 *	 - 0x0 : Non Periodic TxFIFO Flush
++		 *	 - 0x1 : Periodic TxFIFO #1 Flush in device mode
++		 *	   or Periodic TxFIFO in host mode
++		 *	 - 0x2 : Periodic TxFIFO #2 Flush in device mode.
++		 *	 - ...
++		 *	 - 0xF : Periodic TxFIFO #15 Flush in device mode
++		 *	 - 0x10: Flush all the Transmit NonPeriodic and
++		 *	   Transmit Periodic FIFOs in the core
++		 */
++		unsigned txfnum:5;
++		/** Reserved */
++		unsigned reserved11_29:19;
++		/** DMA Request Signal.	 Indicated DMA request is in
++		 * probress. Used for debug purpose. */
++		unsigned dmareq:1;
++		/** AHB Master Idle.  Indicates the AHB Master State
++		 * Machine is in IDLE condition. */
++		unsigned ahbidle:1;
++	} b;
++} grstctl_t;
++
++/**
++ * This union represents the bit fields of the Core Interrupt Mask
++ * Register (GINTMSK). Set/clear the bits using the bit fields then
++ * write the <i>d32</i> value to the register.
++ */
++typedef union gintmsk_data {
++	/** raw register data */
++	uint32_t d32;
++	/** register bits */
++	struct {
++		unsigned reserved0:1;
++		unsigned modemismatch:1;
++		unsigned otgintr:1;
++		unsigned sofintr:1;
++		unsigned rxstsqlvl:1;
++		unsigned nptxfempty:1;
++		unsigned ginnakeff:1;
++		unsigned goutnakeff:1;
++		unsigned ulpickint:1;
++		unsigned i2cintr:1;
++		unsigned erlysuspend:1;
++		unsigned usbsuspend:1;
++		unsigned usbreset:1;
++		unsigned enumdone:1;
++		unsigned isooutdrop:1;
++		unsigned eopframe:1;
++		unsigned restoredone:1;
++		unsigned epmismatch:1;
++		unsigned inepintr:1;
++		unsigned outepintr:1;
++		unsigned incomplisoin:1;
++		unsigned incomplisoout:1;
++		unsigned fetsusp:1;
++		unsigned resetdet:1;
++		unsigned portintr:1;
++		unsigned hcintr:1;
++		unsigned ptxfempty:1;
++		unsigned lpmtranrcvd:1;
++		unsigned conidstschng:1;
++		unsigned disconnect:1;
++		unsigned sessreqintr:1;
++		unsigned wkupintr:1;
++	} b;
++} gintmsk_data_t;
++/**
++ * This union represents the bit fields of the Core Interrupt Register
++ * (GINTSTS).  Set/clear the bits using the bit fields then write the
++ * <i>d32</i> value to the register.
++ */
++typedef union gintsts_data {
++	/** raw register data */
++	uint32_t d32;
++#define DWC_SOF_INTR_MASK 0x0008
++	/** register bits */
++	struct {
++#define DWC_HOST_MODE 1
++		unsigned curmode:1;
++		unsigned modemismatch:1;
++		unsigned otgintr:1;
++		unsigned sofintr:1;
++		unsigned rxstsqlvl:1;
++		unsigned nptxfempty:1;
++		unsigned ginnakeff:1;
++		unsigned goutnakeff:1;
++		unsigned ulpickint:1;
++		unsigned i2cintr:1;
++		unsigned erlysuspend:1;
++		unsigned usbsuspend:1;
++		unsigned usbreset:1;
++		unsigned enumdone:1;
++		unsigned isooutdrop:1;
++		unsigned eopframe:1;
++		unsigned restoredone:1;
++		unsigned epmismatch:1;
++		unsigned inepint:1;
++		unsigned outepintr:1;
++		unsigned incomplisoin:1;
++		unsigned incomplisoout:1;
++		unsigned fetsusp:1;
++		unsigned resetdet:1;
++		unsigned portintr:1;
++		unsigned hcintr:1;
++		unsigned ptxfempty:1;
++		unsigned lpmtranrcvd:1;
++		unsigned conidstschng:1;
++		unsigned disconnect:1;
++		unsigned sessreqintr:1;
++		unsigned wkupintr:1;
++	} b;
++} gintsts_data_t;
++
++/**
++ * This union represents the bit fields in the Device Receive Status Read and
++ * Pop Registers (GRXSTSR, GRXSTSP) Read the register into the <i>d32</i>
++ * element then read out the bits using the <i>b</i>it elements.
++ */
++typedef union device_grxsts_data {
++	/** raw register data */
++	uint32_t d32;
++	/** register bits */
++	struct {
++		unsigned epnum:4;
++		unsigned bcnt:11;
++		unsigned dpid:2;
++
++#define DWC_STS_DATA_UPDT		0x2	// OUT Data Packet
++#define DWC_STS_XFER_COMP		0x3	// OUT Data Transfer Complete
++
++#define DWC_DSTS_GOUT_NAK		0x1	// Global OUT NAK
++#define DWC_DSTS_SETUP_COMP		0x4	// Setup Phase Complete
++#define DWC_DSTS_SETUP_UPDT 0x6	// SETUP Packet
++		unsigned pktsts:4;
++		unsigned fn:4;
++		unsigned reserved25_31:7;
++	} b;
++} device_grxsts_data_t;
++
++/**
++ * This union represents the bit fields in the Host Receive Status Read and
++ * Pop Registers (GRXSTSR, GRXSTSP) Read the register into the <i>d32</i>
++ * element then read out the bits using the <i>b</i>it elements.
++ */
++typedef union host_grxsts_data {
++	/** raw register data */
++	uint32_t d32;
++	/** register bits */
++	struct {
++		unsigned chnum:4;
++		unsigned bcnt:11;
++		unsigned dpid:2;
++
++		unsigned pktsts:4;
++#define DWC_GRXSTS_PKTSTS_IN			  0x2
++#define DWC_GRXSTS_PKTSTS_IN_XFER_COMP	  0x3
++#define DWC_GRXSTS_PKTSTS_DATA_TOGGLE_ERR 0x5
++#define DWC_GRXSTS_PKTSTS_CH_HALTED		  0x7
++
++		unsigned reserved21_31:11;
++	} b;
++} host_grxsts_data_t;
++
++/**
++ * This union represents the bit fields in the FIFO Size Registers (HPTXFSIZ,
++ * GNPTXFSIZ, DPTXFSIZn, DIEPTXFn). Read the register into the <i>d32</i> element
++ * then read out the bits using the <i>b</i>it elements.
++ */
++typedef union fifosize_data {
++	/** raw register data */
++	uint32_t d32;
++	/** register bits */
++	struct {
++		unsigned startaddr:16;
++		unsigned depth:16;
++	} b;
++} fifosize_data_t;
++
++/**
++ * This union represents the bit fields in the Non-Periodic Transmit
++ * FIFO/Queue Status Register (GNPTXSTS). Read the register into the
++ * <i>d32</i> element then read out the bits using the <i>b</i>it
++ * elements.
++ */
++typedef union gnptxsts_data {
++	/** raw register data */
++	uint32_t d32;
++	/** register bits */
++	struct {
++		unsigned nptxfspcavail:16;
++		unsigned nptxqspcavail:8;
++		/** Top of the Non-Periodic Transmit Request Queue
++		 *	- bit 24 - Terminate (Last entry for the selected
++		 *	  channel/EP)
++		 *	- bits 26:25 - Token Type
++		 *	  - 2'b00 - IN/OUT
++		 *	  - 2'b01 - Zero Length OUT
++		 *	  - 2'b10 - PING/Complete Split
++		 *	  - 2'b11 - Channel Halt
++		 *	- bits 30:27 - Channel/EP Number
++		 */
++		unsigned nptxqtop_terminate:1;
++		unsigned nptxqtop_token:2;
++		unsigned nptxqtop_chnep:4;
++		unsigned reserved:1;
++	} b;
++} gnptxsts_data_t;
++
++/**
++ * This union represents the bit fields in the Transmit
++ * FIFO Status Register (DTXFSTS). Read the register into the
++ * <i>d32</i> element then read out the bits using the <i>b</i>it
++ * elements.
++ */
++typedef union dtxfsts_data {
++	/** raw register data */
++	uint32_t d32;
++	/** register bits */
++	struct {
++		unsigned txfspcavail:16;
++		unsigned reserved:16;
++	} b;
++} dtxfsts_data_t;
++
++/**
++ * This union represents the bit fields in the I2C Control Register
++ * (I2CCTL). Read the register into the <i>d32</i> element then read out the
++ * bits using the <i>b</i>it elements.
++ */
++typedef union gi2cctl_data {
++	/** raw register data */
++	uint32_t d32;
++	/** register bits */
++	struct {
++		unsigned rwdata:8;
++		unsigned regaddr:8;
++		unsigned addr:7;
++		unsigned i2cen:1;
++		unsigned ack:1;
++		unsigned i2csuspctl:1;
++		unsigned i2cdevaddr:2;
++		unsigned i2cdatse0:1;
++		unsigned reserved:1;
++		unsigned rw:1;
++		unsigned bsydne:1;
++	} b;
++} gi2cctl_data_t;
++
++/**
++ * This union represents the bit fields in the PHY Vendor Control Register
++ * (GPVNDCTL). Read the register into the <i>d32</i> element then read out the
++ * bits using the <i>b</i>it elements.
++ */
++typedef union gpvndctl_data {
++	/** raw register data */
++	uint32_t d32;
++	/** register bits */
++	struct {
++		unsigned regdata:8;
++		unsigned vctrl:8;
++		unsigned regaddr16_21:6;
++		unsigned regwr:1;
++		unsigned reserved23_24:2;
++		unsigned newregreq:1;
++		unsigned vstsbsy:1;
++		unsigned vstsdone:1;
++		unsigned reserved28_30:3;
++		unsigned disulpidrvr:1;
++	} b;
++} gpvndctl_data_t;
++
++/**
++ * This union represents the bit fields in the General Purpose
++ * Input/Output Register (GGPIO).
++ * Read the register into the <i>d32</i> element then read out the
++ * bits using the <i>b</i>it elements.
++ */
++typedef union ggpio_data {
++	/** raw register data */
++	uint32_t d32;
++	/** register bits */
++	struct {
++		unsigned gpi:16;
++		unsigned gpo:16;
++	} b;
++} ggpio_data_t;
++
++/**
++ * This union represents the bit fields in the User ID Register
++ * (GUID). Read the register into the <i>d32</i> element then read out the
++ * bits using the <i>b</i>it elements.
++ */
++typedef union guid_data {
++	/** raw register data */
++	uint32_t d32;
++	/** register bits */
++	struct {
++		unsigned rwdata:32;
++	} b;
++} guid_data_t;
++
++/**
++ * This union represents the bit fields in the Synopsys ID Register
++ * (GSNPSID). Read the register into the <i>d32</i> element then read out the
++ * bits using the <i>b</i>it elements.
++ */
++typedef union gsnpsid_data {
++	/** raw register data */
++	uint32_t d32;
++	/** register bits */
++	struct {
++		unsigned rwdata:32;
++	} b;
++} gsnpsid_data_t;
++
++/**
++ * This union represents the bit fields in the User HW Config1
++ * Register.  Read the register into the <i>d32</i> element then read
++ * out the bits using the <i>b</i>it elements.
++ */
++typedef union hwcfg1_data {
++	/** raw register data */
++	uint32_t d32;
++	/** register bits */
++	struct {
++		unsigned ep_dir0:2;
++		unsigned ep_dir1:2;
++		unsigned ep_dir2:2;
++		unsigned ep_dir3:2;
++		unsigned ep_dir4:2;
++		unsigned ep_dir5:2;
++		unsigned ep_dir6:2;
++		unsigned ep_dir7:2;
++		unsigned ep_dir8:2;
++		unsigned ep_dir9:2;
++		unsigned ep_dir10:2;
++		unsigned ep_dir11:2;
++		unsigned ep_dir12:2;
++		unsigned ep_dir13:2;
++		unsigned ep_dir14:2;
++		unsigned ep_dir15:2;
++	} b;
++} hwcfg1_data_t;
++
++/**
++ * This union represents the bit fields in the User HW Config2
++ * Register.  Read the register into the <i>d32</i> element then read
++ * out the bits using the <i>b</i>it elements.
++ */
++typedef union hwcfg2_data {
++	/** raw register data */
++	uint32_t d32;
++	/** register bits */
++	struct {
++		/* GHWCFG2 */
++		unsigned op_mode:3;
++#define DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG 0
++#define DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG 1
++#define DWC_HWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE_OTG 2
++#define DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE 3
++#define DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE 4
++#define DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST 5
++#define DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST 6
++
++		unsigned architecture:2;
++		unsigned point2point:1;
++		unsigned hs_phy_type:2;
++#define DWC_HWCFG2_HS_PHY_TYPE_NOT_SUPPORTED 0
++#define DWC_HWCFG2_HS_PHY_TYPE_UTMI 1
++#define DWC_HWCFG2_HS_PHY_TYPE_ULPI 2
++#define DWC_HWCFG2_HS_PHY_TYPE_UTMI_ULPI 3
++
++		unsigned fs_phy_type:2;
++		unsigned num_dev_ep:4;
++		unsigned num_host_chan:4;
++		unsigned perio_ep_supported:1;
++		unsigned dynamic_fifo:1;
++		unsigned multi_proc_int:1;
++		unsigned reserved21:1;
++		unsigned nonperio_tx_q_depth:2;
++		unsigned host_perio_tx_q_depth:2;
++		unsigned dev_token_q_depth:5;
++		unsigned otg_enable_ic_usb:1;
++	} b;
++} hwcfg2_data_t;
++
++/**
++ * This union represents the bit fields in the User HW Config3
++ * Register.  Read the register into the <i>d32</i> element then read
++ * out the bits using the <i>b</i>it elements.
++ */
++typedef union hwcfg3_data {
++	/** raw register data */
++	uint32_t d32;
++	/** register bits */
++	struct {
++		/* GHWCFG3 */
++		unsigned xfer_size_cntr_width:4;
++		unsigned packet_size_cntr_width:3;
++		unsigned otg_func:1;
++		unsigned i2c:1;
++		unsigned vendor_ctrl_if:1;
++		unsigned optional_features:1;
++		unsigned synch_reset_type:1;
++		unsigned adp_supp:1;
++		unsigned otg_enable_hsic:1;
++		unsigned bc_support:1;
++		unsigned otg_lpm_en:1;
++		unsigned dfifo_depth:16;
++	} b;
++} hwcfg3_data_t;
++
++/**
++ * This union represents the bit fields in the User HW Config4
++ * Register.  Read the register into the <i>d32</i> element then read
++ * out the bits using the <i>b</i>it elements.
++ */
++typedef union hwcfg4_data {
++	/** raw register data */
++	uint32_t d32;
++	/** register bits */
++	struct {
++		unsigned num_dev_perio_in_ep:4;
++		unsigned power_optimiz:1;
++		unsigned min_ahb_freq:1;
++		unsigned hiber:1;
++		unsigned xhiber:1;
++		unsigned reserved:6;
++		unsigned utmi_phy_data_width:2;
++		unsigned num_dev_mode_ctrl_ep:4;
++		unsigned iddig_filt_en:1;
++		unsigned vbus_valid_filt_en:1;
++		unsigned a_valid_filt_en:1;
++		unsigned b_valid_filt_en:1;
++		unsigned session_end_filt_en:1;
++		unsigned ded_fifo_en:1;
++		unsigned num_in_eps:4;
++		unsigned desc_dma:1;
++		unsigned desc_dma_dyn:1;
++	} b;
++} hwcfg4_data_t;
++
++/**
++ * This union represents the bit fields of the Core LPM Configuration
++ * Register (GLPMCFG). Set the bits using bit fields then write
++ * the <i>d32</i> value to the register.
++ */
++typedef union glpmctl_data {
++	/** raw register data */
++	uint32_t d32;
++	/** register bits */
++	struct {
++		/** LPM-Capable (LPMCap) (Device and Host)
++		 * The application uses this bit to control
++		 * the DWC_otg core LPM capabilities.
++		 */
++		unsigned lpm_cap_en:1;
++		/** LPM response programmed by application (AppL1Res) (Device)
++		 * Handshake response to LPM token pre-programmed
++		 * by device application software.
++		 */
++		unsigned appl_resp:1;
++		/** Host Initiated Resume Duration (HIRD) (Device and Host)
++		 * In Host mode this field indicates the value of HIRD
++		 * to be sent in an LPM transaction.
++		 * In Device mode this field is updated with the
++		 * Received LPM Token HIRD bmAttribute
++		 * when an ACK/NYET/STALL response is sent
++		 * to an LPM transaction.
++		 */
++		unsigned hird:4;
++		/** RemoteWakeEnable (bRemoteWake) (Device and Host)
++		 * In Host mode this bit indicates the value of remote
++		 * wake up to be sent in wIndex field of LPM transaction.
++		 * In Device mode this field is updated with the
++		 * Received LPM Token bRemoteWake bmAttribute
++		 * when an ACK/NYET/STALL response is sent
++		 * to an LPM transaction.
++		 */
++		unsigned rem_wkup_en:1;
++		/** Enable utmi_sleep_n (EnblSlpM) (Device and Host)
++		 * The application uses this bit to control
++		 * the utmi_sleep_n assertion to the PHY when in L1 state.
++		 */
++		unsigned en_utmi_sleep:1;
++		/** HIRD Threshold (HIRD_Thres) (Device and Host)
++		 */
++		unsigned hird_thres:5;
++		/** LPM Response (CoreL1Res) (Device and Host)
++		 * In Host mode this bit contains handsake response to
++		 * LPM transaction.
++		 * In Device mode the response of the core to
++		 * LPM transaction received is reflected in these two bits.
++			- 0x0 : ERROR (No handshake response)
++			- 0x1 : STALL
++			- 0x2 : NYET
++			- 0x3 : ACK
++		 */
++		unsigned lpm_resp:2;
++		/** Port Sleep Status (SlpSts) (Device and Host)
++		 * This bit is set as long as a Sleep condition
++		 * is present on the USB bus.
++		 */
++		unsigned prt_sleep_sts:1;
++		/** Sleep State Resume OK (L1ResumeOK) (Device and Host)
++		 * Indicates that the application or host
++		 * can start resume from Sleep state.
++		 */
++		unsigned sleep_state_resumeok:1;
++		/** LPM channel Index (LPM_Chnl_Indx) (Host)
++		 * The channel number on which the LPM transaction
++		 * has to be applied while sending
++		 * an LPM transaction to the local device.
++		 */
++		unsigned lpm_chan_index:4;
++		/** LPM Retry Count (LPM_Retry_Cnt) (Host)
++		 * Number host retries that would be performed
++		 * if the device response was not valid response.
++		 */
++		unsigned retry_count:3;
++		/** Send LPM Transaction (SndLPM) (Host)
++		 * When set by application software,
++		 * an LPM transaction containing two tokens
++		 * is sent.
++		 */
++		unsigned send_lpm:1;
++		/** LPM Retry status (LPM_RetryCnt_Sts) (Host)
++		 * Number of LPM Host Retries still remaining
++		 * to be transmitted for the current LPM sequence
++		 */
++		unsigned retry_count_sts:3;
++		/** Enable Best Effort Service Latency (BESL) (Device and Host)
++		 *  This bit enables the BESL features as defined in the LPM errata
++		 */
++		unsigned en_besl:1;
++
++		unsigned reserved29:1;
++		/** In host mode once this bit is set, the host
++		 * configures to drive the HSIC Idle state on the bus.
++		 * It then waits for the  device to initiate the Connect sequence.
++		 * In device mode once this bit is set, the device waits for
++		 * the HSIC Idle line state on the bus. Upon receving the Idle
++		 * line state, it initiates the HSIC Connect sequence.
++		 */
++		unsigned hsic_connect:1;
++		/** This bit overrides and functionally inverts
++		 * the if_select_hsic input port signal.
++		 */
++		unsigned inv_sel_hsic:1;
++	} b;
++} glpmcfg_data_t;
++
++/**
++ * This union represents the bit fields of the Core ADP Timer, Control and
++ * Status Register (ADPTIMCTLSTS). Set the bits using bit fields then write
++ * the <i>d32</i> value to the register.
++ */
++typedef union adpctl_data {
++	/** raw register data */
++	uint32_t d32;
++	/** register bits */
++	struct {
++		/** Probe Discharge (PRB_DSCHG)
++		 *  These bits set the times for TADP_DSCHG.
++		 *  These bits are defined as follows:
++		 *  2'b00 - 4 msec
++		 *  2'b01 - 8 msec
++		 *  2'b10 - 16 msec
++		 *  2'b11 - 32 msec
++		 */
++		unsigned prb_dschg:2;
++		/** Probe Delta (PRB_DELTA)
++		 *  These bits set the resolution for RTIM   value.
++		 *  The bits are defined in units of 32 kHz clock cycles as follows:
++		 *  2'b00  -  1 cycles
++		 *  2'b01  -  2 cycles
++		 *  2'b10 -  3 cycles
++		 *  2'b11 - 4 cycles
++		 *  For example if this value is chosen to 2'b01, it means that RTIM
++		 *  increments for every 3(three) 32Khz clock cycles.
++		 */
++		unsigned prb_delta:2;
++		/** Probe Period (PRB_PER)
++		 *  These bits sets the TADP_PRD as shown in Figure 4 as follows:
++		 *  2'b00  -  0.625 to 0.925 sec (typical 0.775 sec)
++		 *  2'b01  -  1.25 to 1.85 sec (typical 1.55 sec)
++		 *  2'b10  -  1.9 to 2.6 sec (typical 2.275 sec)
++		 *  2'b11  -  Reserved
++		 */
++		unsigned prb_per:2;
++		/** These bits capture the latest time it took for VBUS to ramp from
++		 *  VADP_SINK to VADP_PRB.
++		 *  0x000  -  1 cycles
++		 *  0x001  -  2 cycles
++		 *  0x002  -  3 cycles
++		 *  etc
++		 *  0x7FF  -  2048 cycles
++		 *  A time of 1024 cycles at 32 kHz corresponds to a time of 32 msec.
++		*/
++		unsigned rtim:11;
++		/** Enable Probe (EnaPrb)
++		 *  When programmed to 1'b1, the core performs a probe operation.
++		 *  This bit is valid only if OTG_Ver = 1'b1.
++		 */
++		unsigned enaprb:1;
++		/** Enable Sense (EnaSns)
++		 *  When programmed to 1'b1, the core performs a Sense operation.
++		 *  This bit is valid only if OTG_Ver = 1'b1.
++		 */
++		unsigned enasns:1;
++		/** ADP Reset (ADPRes)
++		 *  When set, ADP controller is reset.
++		 *  This bit is valid only if OTG_Ver = 1'b1.
++		 */
++		unsigned adpres:1;
++		/** ADP Enable (ADPEn)
++		 *  When set, the core performs either ADP probing or sensing
++		 *  based on EnaPrb or EnaSns.
++		 *  This bit is valid only if OTG_Ver = 1'b1.
++		 */
++		unsigned adpen:1;
++		/** ADP Probe Interrupt (ADP_PRB_INT)
++		 *  When this bit is set, it means that the VBUS
++		 *  voltage is greater than VADP_PRB or VADP_PRB is reached.
++		 *  This bit is valid only if OTG_Ver = 1'b1.
++		 */
++		unsigned adp_prb_int:1;
++		/**
++		 *  ADP Sense Interrupt (ADP_SNS_INT)
++		 *  When this bit is set, it means that the VBUS voltage is greater than
++		 *  VADP_SNS value or VADP_SNS is reached.
++		 *  This bit is valid only if OTG_Ver = 1'b1.
++		 */
++		unsigned adp_sns_int:1;
++		/** ADP Tomeout Interrupt (ADP_TMOUT_INT)
++		 *  This bit is relevant only for an ADP probe.
++		 *  When this bit is set, it means that the ramp time has
++		 *  completed ie ADPCTL.RTIM has reached its terminal value
++		 *  of 0x7FF.  This is a debug feature that allows software
++		 *  to read the ramp time after each cycle.
++		 *  This bit is valid only if OTG_Ver = 1'b1.
++		 */
++		unsigned adp_tmout_int:1;
++		/** ADP Probe Interrupt Mask (ADP_PRB_INT_MSK)
++		 *  When this bit is set, it unmasks the interrupt due to ADP_PRB_INT.
++		 *  This bit is valid only if OTG_Ver = 1'b1.
++		 */
++		unsigned adp_prb_int_msk:1;
++		/** ADP Sense Interrupt Mask (ADP_SNS_INT_MSK)
++		 *  When this bit is set, it unmasks the interrupt due to ADP_SNS_INT.
++		 *  This bit is valid only if OTG_Ver = 1'b1.
++		 */
++		unsigned adp_sns_int_msk:1;
++		/** ADP Timoeout Interrupt Mask (ADP_TMOUT_MSK)
++		 *  When this bit is set, it unmasks the interrupt due to ADP_TMOUT_INT.
++		 *  This bit is valid only if OTG_Ver = 1'b1.
++		 */
++		unsigned adp_tmout_int_msk:1;
++		/** Access Request
++		 * 2'b00 - Read/Write Valid (updated by the core)
++		 * 2'b01 - Read
++		 * 2'b00 - Write
++		 * 2'b00 - Reserved
++		 */
++		unsigned ar:2;
++		 /** Reserved */
++		unsigned reserved29_31:3;
++	} b;
++} adpctl_data_t;
++
++////////////////////////////////////////////
++// Device Registers
++/**
++ * Device Global Registers. <i>Offsets 800h-BFFh</i>
++ *
++ * The following structures define the size and relative field offsets
++ * for the Device Mode Registers.
++ *
++ * <i>These registers are visible only in Device mode and must not be
++ * accessed in Host mode, as the results are unknown.</i>
++ */
++typedef struct dwc_otg_dev_global_regs {
++	/** Device Configuration Register. <i>Offset 800h</i> */
++	volatile uint32_t dcfg;
++	/** Device Control Register. <i>Offset: 804h</i> */
++	volatile uint32_t dctl;
++	/** Device Status Register (Read Only). <i>Offset: 808h</i> */
++	volatile uint32_t dsts;
++	/** Reserved. <i>Offset: 80Ch</i> */
++	uint32_t unused;
++	/** Device IN Endpoint Common Interrupt Mask
++	 * Register. <i>Offset: 810h</i> */
++	volatile uint32_t diepmsk;
++	/** Device OUT Endpoint Common Interrupt Mask
++	 * Register. <i>Offset: 814h</i> */
++	volatile uint32_t doepmsk;
++	/** Device All Endpoints Interrupt Register.  <i>Offset: 818h</i> */
++	volatile uint32_t daint;
++	/** Device All Endpoints Interrupt Mask Register.  <i>Offset:
++	 * 81Ch</i> */
++	volatile uint32_t daintmsk;
++	/** Device IN Token Queue Read Register-1 (Read Only).
++	 * <i>Offset: 820h</i> */
++	volatile uint32_t dtknqr1;
++	/** Device IN Token Queue Read Register-2 (Read Only).
++	 * <i>Offset: 824h</i> */
++	volatile uint32_t dtknqr2;
++	/** Device VBUS	 discharge Register.  <i>Offset: 828h</i> */
++	volatile uint32_t dvbusdis;
++	/** Device VBUS Pulse Register.	 <i>Offset: 82Ch</i> */
++	volatile uint32_t dvbuspulse;
++	/** Device IN Token Queue Read Register-3 (Read Only). /
++	 *	Device Thresholding control register (Read/Write)
++	 * <i>Offset: 830h</i> */
++	volatile uint32_t dtknqr3_dthrctl;
++	/** Device IN Token Queue Read Register-4 (Read Only). /
++	 *	Device IN EPs empty Inr. Mask Register (Read/Write)
++	 * <i>Offset: 834h</i> */
++	volatile uint32_t dtknqr4_fifoemptymsk;
++	/** Device Each Endpoint Interrupt Register (Read Only). /
++	 * <i>Offset: 838h</i> */
++	volatile uint32_t deachint;
++	/** Device Each Endpoint Interrupt mask Register (Read/Write). /
++	 * <i>Offset: 83Ch</i> */
++	volatile uint32_t deachintmsk;
++	/** Device Each In Endpoint Interrupt mask Register (Read/Write). /
++	 * <i>Offset: 840h</i> */
++	volatile uint32_t diepeachintmsk[MAX_EPS_CHANNELS];
++	/** Device Each Out Endpoint Interrupt mask Register (Read/Write). /
++	 * <i>Offset: 880h</i> */
++	volatile uint32_t doepeachintmsk[MAX_EPS_CHANNELS];
++} dwc_otg_device_global_regs_t;
++
++/**
++ * This union represents the bit fields in the Device Configuration
++ * Register.  Read the register into the <i>d32</i> member then
++ * set/clear the bits using the <i>b</i>it elements.  Write the
++ * <i>d32</i> member to the dcfg register.
++ */
++typedef union dcfg_data {
++	/** raw register data */
++	uint32_t d32;
++	/** register bits */
++	struct {
++		/** Device Speed */
++		unsigned devspd:2;
++		/** Non Zero Length Status OUT Handshake */
++		unsigned nzstsouthshk:1;
++#define DWC_DCFG_SEND_STALL 1
++
++		unsigned ena32khzs:1;
++		/** Device Addresses */
++		unsigned devaddr:7;
++		/** Periodic Frame Interval */
++		unsigned perfrint:2;
++#define DWC_DCFG_FRAME_INTERVAL_80 0
++#define DWC_DCFG_FRAME_INTERVAL_85 1
++#define DWC_DCFG_FRAME_INTERVAL_90 2
++#define DWC_DCFG_FRAME_INTERVAL_95 3
++
++		/** Enable Device OUT NAK for bulk in DDMA mode */
++		unsigned endevoutnak:1;
++
++		unsigned reserved14_17:4;
++		/** In Endpoint Mis-match count */
++		unsigned epmscnt:5;
++		/** Enable Descriptor DMA in Device mode */
++		unsigned descdma:1;
++		unsigned perschintvl:2;
++		unsigned resvalid:6;
++	} b;
++} dcfg_data_t;
++
++/**
++ * This union represents the bit fields in the Device Control
++ * Register.  Read the register into the <i>d32</i> member then
++ * set/clear the bits using the <i>b</i>it elements.
++ */
++typedef union dctl_data {
++	/** raw register data */
++	uint32_t d32;
++	/** register bits */
++	struct {
++		/** Remote Wakeup */
++		unsigned rmtwkupsig:1;
++		/** Soft Disconnect */
++		unsigned sftdiscon:1;
++		/** Global Non-Periodic IN NAK Status */
++		unsigned gnpinnaksts:1;
++		/** Global OUT NAK Status */
++		unsigned goutnaksts:1;
++		/** Test Control */
++		unsigned tstctl:3;
++		/** Set Global Non-Periodic IN NAK */
++		unsigned sgnpinnak:1;
++		/** Clear Global Non-Periodic IN NAK */
++		unsigned cgnpinnak:1;
++		/** Set Global OUT NAK */
++		unsigned sgoutnak:1;
++		/** Clear Global OUT NAK */
++		unsigned cgoutnak:1;
++		/** Power-On Programming Done */
++		unsigned pwronprgdone:1;
++		/** Reserved */
++		unsigned reserved:1;
++		/** Global Multi Count */
++		unsigned gmc:2;
++		/** Ignore Frame Number for ISOC EPs */
++		unsigned ifrmnum:1;
++		/** NAK on Babble */
++		unsigned nakonbble:1;
++		/** Enable Continue on BNA */
++		unsigned encontonbna:1;
++		/** Enable deep sleep besl reject feature*/
++		unsigned besl_reject:1;
++
++		unsigned reserved17_31:13;
++	} b;
++} dctl_data_t;
++
++/**
++ * This union represents the bit fields in the Device Status
++ * Register.  Read the register into the <i>d32</i> member then
++ * set/clear the bits using the <i>b</i>it elements.
++ */
++typedef union dsts_data {
++	/** raw register data */
++	uint32_t d32;
++	/** register bits */
++	struct {
++		/** Suspend Status */
++		unsigned suspsts:1;
++		/** Enumerated Speed */
++		unsigned enumspd:2;
++#define DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ 0
++#define DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ 1
++#define DWC_DSTS_ENUMSPD_LS_PHY_6MHZ		   2
++#define DWC_DSTS_ENUMSPD_FS_PHY_48MHZ		   3
++		/** Erratic Error */
++		unsigned errticerr:1;
++		unsigned reserved4_7:4;
++		/** Frame or Microframe Number of the received SOF */
++		unsigned soffn:14;
++		unsigned reserved22_31:10;
++	} b;
++} dsts_data_t;
++
++/**
++ * This union represents the bit fields in the Device IN EP Interrupt
++ * Register and the Device IN EP Common Mask Register.
++ *
++ * - Read the register into the <i>d32</i> member then set/clear the
++ *	 bits using the <i>b</i>it elements.
++ */
++typedef union diepint_data {
++	/** raw register data */
++	uint32_t d32;
++	/** register bits */
++	struct {
++		/** Transfer complete mask */
++		unsigned xfercompl:1;
++		/** Endpoint disable mask */
++		unsigned epdisabled:1;
++		/** AHB Error mask */
++		unsigned ahberr:1;
++		/** TimeOUT Handshake mask (non-ISOC EPs) */
++		unsigned timeout:1;
++		/** IN Token received with TxF Empty mask */
++		unsigned intktxfemp:1;
++		/** IN Token Received with EP mismatch mask */
++		unsigned intknepmis:1;
++		/** IN Endpoint NAK Effective mask */
++		unsigned inepnakeff:1;
++		/** Reserved */
++		unsigned emptyintr:1;
++
++		unsigned txfifoundrn:1;
++
++		/** BNA Interrupt mask */
++		unsigned bna:1;
++
++		unsigned reserved10_12:3;
++		/** BNA Interrupt mask */
++		unsigned nak:1;
++
++		unsigned reserved14_31:18;
++	} b;
++} diepint_data_t;
++
++/**
++ * This union represents the bit fields in the Device IN EP
++ * Common/Dedicated Interrupt Mask Register.
++ */
++typedef union diepint_data diepmsk_data_t;
++
++/**
++ * This union represents the bit fields in the Device OUT EP Interrupt
++ * Registerand Device OUT EP Common Interrupt Mask Register.
++ *
++ * - Read the register into the <i>d32</i> member then set/clear the
++ *	 bits using the <i>b</i>it elements.
++ */
++typedef union doepint_data {
++	/** raw register data */
++	uint32_t d32;
++	/** register bits */
++	struct {
++		/** Transfer complete */
++		unsigned xfercompl:1;
++		/** Endpoint disable  */
++		unsigned epdisabled:1;
++		/** AHB Error */
++		unsigned ahberr:1;
++		/** Setup Phase Done (contorl EPs) */
++		unsigned setup:1;
++		/** OUT Token Received when Endpoint Disabled */
++		unsigned outtknepdis:1;
++
++		unsigned stsphsercvd:1;
++		/** Back-to-Back SETUP Packets Received */
++		unsigned back2backsetup:1;
++
++		unsigned reserved7:1;
++		/** OUT packet Error */
++		unsigned outpkterr:1;
++		/** BNA Interrupt */
++		unsigned bna:1;
++
++		unsigned reserved10:1;
++		/** Packet Drop Status */
++		unsigned pktdrpsts:1;
++		/** Babble Interrupt */
++		unsigned babble:1;
++		/** NAK Interrupt */
++		unsigned nak:1;
++		/** NYET Interrupt */
++		unsigned nyet:1;
++		/** Bit indicating setup packet received */
++		unsigned sr:1;
++
++		unsigned reserved16_31:16;
++	} b;
++} doepint_data_t;
++
++/**
++ * This union represents the bit fields in the Device OUT EP
++ * Common/Dedicated Interrupt Mask Register.
++ */
++typedef union doepint_data doepmsk_data_t;
++
++/**
++ * This union represents the bit fields in the Device All EP Interrupt
++ * and Mask Registers.
++ * - Read the register into the <i>d32</i> member then set/clear the
++ *	 bits using the <i>b</i>it elements.
++ */
++typedef union daint_data {
++	/** raw register data */
++	uint32_t d32;
++	/** register bits */
++	struct {
++		/** IN Endpoint bits */
++		unsigned in:16;
++		/** OUT Endpoint bits */
++		unsigned out:16;
++	} ep;
++	struct {
++		/** IN Endpoint bits */
++		unsigned inep0:1;
++		unsigned inep1:1;
++		unsigned inep2:1;
++		unsigned inep3:1;
++		unsigned inep4:1;
++		unsigned inep5:1;
++		unsigned inep6:1;
++		unsigned inep7:1;
++		unsigned inep8:1;
++		unsigned inep9:1;
++		unsigned inep10:1;
++		unsigned inep11:1;
++		unsigned inep12:1;
++		unsigned inep13:1;
++		unsigned inep14:1;
++		unsigned inep15:1;
++		/** OUT Endpoint bits */
++		unsigned outep0:1;
++		unsigned outep1:1;
++		unsigned outep2:1;
++		unsigned outep3:1;
++		unsigned outep4:1;
++		unsigned outep5:1;
++		unsigned outep6:1;
++		unsigned outep7:1;
++		unsigned outep8:1;
++		unsigned outep9:1;
++		unsigned outep10:1;
++		unsigned outep11:1;
++		unsigned outep12:1;
++		unsigned outep13:1;
++		unsigned outep14:1;
++		unsigned outep15:1;
++	} b;
++} daint_data_t;
++
++/**
++ * This union represents the bit fields in the Device IN Token Queue
++ * Read Registers.
++ * - Read the register into the <i>d32</i> member.
++ * - READ-ONLY Register
++ */
++typedef union dtknq1_data {
++	/** raw register data */
++	uint32_t d32;
++	/** register bits */
++	struct {
++		/** In Token Queue Write Pointer */
++		unsigned intknwptr:5;
++		/** Reserved */
++		unsigned reserved05_06:2;
++		/** write pointer has wrapped. */
++		unsigned wrap_bit:1;
++		/** EP Numbers of IN Tokens 0 ... 4 */
++		unsigned epnums0_5:24;
++	} b;
++} dtknq1_data_t;
++
++/**
++ * This union represents Threshold control Register
++ * - Read and write the register into the <i>d32</i> member.
++ * - READ-WRITABLE Register
++ */
++typedef union dthrctl_data {
++	/** raw register data */
++	uint32_t d32;
++	/** register bits */
++	struct {
++		/** non ISO Tx Thr. Enable */
++		unsigned non_iso_thr_en:1;
++		/** ISO Tx Thr. Enable */
++		unsigned iso_thr_en:1;
++		/** Tx Thr. Length */
++		unsigned tx_thr_len:9;
++		/** AHB Threshold ratio */
++		unsigned ahb_thr_ratio:2;
++		/** Reserved */
++		unsigned reserved13_15:3;
++		/** Rx Thr. Enable */
++		unsigned rx_thr_en:1;
++		/** Rx Thr. Length */
++		unsigned rx_thr_len:9;
++		unsigned reserved26:1;
++		/** Arbiter Parking Enable*/
++		unsigned arbprken:1;
++		/** Reserved */
++		unsigned reserved28_31:4;
++	} b;
++} dthrctl_data_t;
++
++/**
++ * Device Logical IN Endpoint-Specific Registers. <i>Offsets
++ * 900h-AFCh</i>
++ *
++ * There will be one set of endpoint registers per logical endpoint
++ * implemented.
++ *
++ * <i>These registers are visible only in Device mode and must not be
++ * accessed in Host mode, as the results are unknown.</i>
++ */
++typedef struct dwc_otg_dev_in_ep_regs {
++	/** Device IN Endpoint Control Register. <i>Offset:900h +
++	 * (ep_num * 20h) + 00h</i> */
++	volatile uint32_t diepctl;
++	/** Reserved. <i>Offset:900h + (ep_num * 20h) + 04h</i> */
++	uint32_t reserved04;
++	/** Device IN Endpoint Interrupt Register. <i>Offset:900h +
++	 * (ep_num * 20h) + 08h</i> */
++	volatile uint32_t diepint;
++	/** Reserved. <i>Offset:900h + (ep_num * 20h) + 0Ch</i> */
++	uint32_t reserved0C;
++	/** Device IN Endpoint Transfer Size
++	 * Register. <i>Offset:900h + (ep_num * 20h) + 10h</i> */
++	volatile uint32_t dieptsiz;
++	/** Device IN Endpoint DMA Address Register. <i>Offset:900h +
++	 * (ep_num * 20h) + 14h</i> */
++	volatile uint32_t diepdma;
++	/** Device IN Endpoint Transmit FIFO Status Register. <i>Offset:900h +
++	 * (ep_num * 20h) + 18h</i> */
++	volatile uint32_t dtxfsts;
++	/** Device IN Endpoint DMA Buffer Register. <i>Offset:900h +
++	 * (ep_num * 20h) + 1Ch</i> */
++	volatile uint32_t diepdmab;
++} dwc_otg_dev_in_ep_regs_t;
++
++/**
++ * Device Logical OUT Endpoint-Specific Registers. <i>Offsets:
++ * B00h-CFCh</i>
++ *
++ * There will be one set of endpoint registers per logical endpoint
++ * implemented.
++ *
++ * <i>These registers are visible only in Device mode and must not be
++ * accessed in Host mode, as the results are unknown.</i>
++ */
++typedef struct dwc_otg_dev_out_ep_regs {
++	/** Device OUT Endpoint Control Register. <i>Offset:B00h +
++	 * (ep_num * 20h) + 00h</i> */
++	volatile uint32_t doepctl;
++	/** Reserved. <i>Offset:B00h + (ep_num * 20h) + 04h</i> */
++	uint32_t reserved04;
++	/** Device OUT Endpoint Interrupt Register. <i>Offset:B00h +
++	 * (ep_num * 20h) + 08h</i> */
++	volatile uint32_t doepint;
++	/** Reserved. <i>Offset:B00h + (ep_num * 20h) + 0Ch</i> */
++	uint32_t reserved0C;
++	/** Device OUT Endpoint Transfer Size Register. <i>Offset:
++	 * B00h + (ep_num * 20h) + 10h</i> */
++	volatile uint32_t doeptsiz;
++	/** Device OUT Endpoint DMA Address Register. <i>Offset:B00h
++	 * + (ep_num * 20h) + 14h</i> */
++	volatile uint32_t doepdma;
++	/** Reserved. <i>Offset:B00h +	 * (ep_num * 20h) + 18h</i> */
++	uint32_t unused;
++	/** Device OUT Endpoint DMA Buffer Register. <i>Offset:B00h
++	 * + (ep_num * 20h) + 1Ch</i> */
++	uint32_t doepdmab;
++} dwc_otg_dev_out_ep_regs_t;
++
++/**
++ * This union represents the bit fields in the Device EP Control
++ * Register.  Read the register into the <i>d32</i> member then
++ * set/clear the bits using the <i>b</i>it elements.
++ */
++typedef union depctl_data {
++	/** raw register data */
++	uint32_t d32;
++	/** register bits */
++	struct {
++		/** Maximum Packet Size
++		 * IN/OUT EPn
++		 * IN/OUT EP0 - 2 bits
++		 *	 2'b00: 64 Bytes
++		 *	 2'b01: 32
++		 *	 2'b10: 16
++		 *	 2'b11: 8 */
++		unsigned mps:11;
++#define DWC_DEP0CTL_MPS_64	 0
++#define DWC_DEP0CTL_MPS_32	 1
++#define DWC_DEP0CTL_MPS_16	 2
++#define DWC_DEP0CTL_MPS_8	 3
++
++		/** Next Endpoint
++		 * IN EPn/IN EP0
++		 * OUT EPn/OUT EP0 - reserved */
++		unsigned nextep:4;
++
++		/** USB Active Endpoint */
++		unsigned usbactep:1;
++
++		/** Endpoint DPID (INTR/Bulk IN and OUT endpoints)
++		 * This field contains the PID of the packet going to
++		 * be received or transmitted on this endpoint. The
++		 * application should program the PID of the first
++		 * packet going to be received or transmitted on this
++		 * endpoint , after the endpoint is
++		 * activated. Application use the SetD1PID and
++		 * SetD0PID fields of this register to program either
++		 * D0 or D1 PID.
++		 *
++		 * The encoding for this field is
++		 *	 - 0: D0
++		 *	 - 1: D1
++		 */
++		unsigned dpid:1;
++
++		/** NAK Status */
++		unsigned naksts:1;
++
++		/** Endpoint Type
++		 *	2'b00: Control
++		 *	2'b01: Isochronous
++		 *	2'b10: Bulk
++		 *	2'b11: Interrupt */
++		unsigned eptype:2;
++
++		/** Snoop Mode
++		 * OUT EPn/OUT EP0
++		 * IN EPn/IN EP0 - reserved */
++		unsigned snp:1;
++
++		/** Stall Handshake */
++		unsigned stall:1;
++
++		/** Tx Fifo Number
++		 * IN EPn/IN EP0
++		 * OUT EPn/OUT EP0 - reserved */
++		unsigned txfnum:4;
++
++		/** Clear NAK */
++		unsigned cnak:1;
++		/** Set NAK */
++		unsigned snak:1;
++		/** Set DATA0 PID (INTR/Bulk IN and OUT endpoints)
++		 * Writing to this field sets the Endpoint DPID (DPID)
++		 * field in this register to DATA0. Set Even
++		 * (micro)frame (SetEvenFr) (ISO IN and OUT Endpoints)
++		 * Writing to this field sets the Even/Odd
++		 * (micro)frame (EO_FrNum) field to even (micro)
++		 * frame.
++		 */
++		unsigned setd0pid:1;
++		/** Set DATA1 PID (INTR/Bulk IN and OUT endpoints)
++		 * Writing to this field sets the Endpoint DPID (DPID)
++		 * field in this register to DATA1 Set Odd
++		 * (micro)frame (SetOddFr) (ISO IN and OUT Endpoints)
++		 * Writing to this field sets the Even/Odd
++		 * (micro)frame (EO_FrNum) field to odd (micro) frame.
++		 */
++		unsigned setd1pid:1;
++
++		/** Endpoint Disable */
++		unsigned epdis:1;
++		/** Endpoint Enable */
++		unsigned epena:1;
++	} b;
++} depctl_data_t;
++
++/**
++ * This union represents the bit fields in the Device EP Transfer
++ * Size Register.  Read the register into the <i>d32</i> member then
++ * set/clear the bits using the <i>b</i>it elements.
++ */
++typedef union deptsiz_data {
++		/** raw register data */
++	uint32_t d32;
++		/** register bits */
++	struct {
++		/** Transfer size */
++		unsigned xfersize:19;
++/** Max packet count for EP (pow(2,10)-1) */
++#define MAX_PKT_CNT 1023
++		/** Packet Count */
++		unsigned pktcnt:10;
++		/** Multi Count - Periodic IN endpoints */
++		unsigned mc:2;
++		unsigned reserved:1;
++	} b;
++} deptsiz_data_t;
++
++/**
++ * This union represents the bit fields in the Device EP 0 Transfer
++ * Size Register.  Read the register into the <i>d32</i> member then
++ * set/clear the bits using the <i>b</i>it elements.
++ */
++typedef union deptsiz0_data {
++		/** raw register data */
++	uint32_t d32;
++		/** register bits */
++	struct {
++		/** Transfer size */
++		unsigned xfersize:7;
++				/** Reserved */
++		unsigned reserved7_18:12;
++		/** Packet Count */
++		unsigned pktcnt:2;
++				/** Reserved */
++		unsigned reserved21_28:8;
++				/**Setup Packet Count (DOEPTSIZ0 Only) */
++		unsigned supcnt:2;
++		unsigned reserved31;
++	} b;
++} deptsiz0_data_t;
++
++/////////////////////////////////////////////////
++// DMA Descriptor Specific Structures
++//
++
++/** Buffer status definitions */
++
++#define BS_HOST_READY	0x0
++#define BS_DMA_BUSY		0x1
++#define BS_DMA_DONE		0x2
++#define BS_HOST_BUSY	0x3
++
++/** Receive/Transmit status definitions */
++
++#define RTS_SUCCESS		0x0
++#define RTS_BUFFLUSH	0x1
++#define RTS_RESERVED	0x2
++#define RTS_BUFERR		0x3
++
++/**
++ * This union represents the bit fields in the DMA Descriptor
++ * status quadlet. Read the quadlet into the <i>d32</i> member then
++ * set/clear the bits using the <i>b</i>it, <i>b_iso_out</i> and
++ * <i>b_iso_in</i> elements.
++ */
++typedef union dev_dma_desc_sts {
++		/** raw register data */
++	uint32_t d32;
++		/** quadlet bits */
++	struct {
++		/** Received number of bytes */
++		unsigned bytes:16;
++		/** NAK bit - only for OUT EPs */
++		unsigned nak:1;
++		unsigned reserved17_22:6;
++		/** Multiple Transfer - only for OUT EPs */
++		unsigned mtrf:1;
++		/** Setup Packet received - only for OUT EPs */
++		unsigned sr:1;
++		/** Interrupt On Complete */
++		unsigned ioc:1;
++		/** Short Packet */
++		unsigned sp:1;
++		/** Last */
++		unsigned l:1;
++		/** Receive Status */
++		unsigned sts:2;
++		/** Buffer Status */
++		unsigned bs:2;
++	} b;
++
++//#ifdef DWC_EN_ISOC
++		/** iso out quadlet bits */
++	struct {
++		/** Received number of bytes */
++		unsigned rxbytes:11;
++
++		unsigned reserved11:1;
++		/** Frame Number */
++		unsigned framenum:11;
++		/** Received ISO Data PID */
++		unsigned pid:2;
++		/** Interrupt On Complete */
++		unsigned ioc:1;
++		/** Short Packet */
++		unsigned sp:1;
++		/** Last */
++		unsigned l:1;
++		/** Receive Status */
++		unsigned rxsts:2;
++		/** Buffer Status */
++		unsigned bs:2;
++	} b_iso_out;
++
++		/** iso in quadlet bits */
++	struct {
++		/** Transmited number of bytes */
++		unsigned txbytes:12;
++		/** Frame Number */
++		unsigned framenum:11;
++		/** Transmited ISO Data PID */
++		unsigned pid:2;
++		/** Interrupt On Complete */
++		unsigned ioc:1;
++		/** Short Packet */
++		unsigned sp:1;
++		/** Last */
++		unsigned l:1;
++		/** Transmit Status */
++		unsigned txsts:2;
++		/** Buffer Status */
++		unsigned bs:2;
++	} b_iso_in;
++//#endif                                /* DWC_EN_ISOC */
++} dev_dma_desc_sts_t;
++
++/**
++ * DMA Descriptor structure
++ *
++ * DMA Descriptor structure contains two quadlets:
++ * Status quadlet and Data buffer pointer.
++ */
++typedef struct dwc_otg_dev_dma_desc {
++	/** DMA Descriptor status quadlet */
++	dev_dma_desc_sts_t status;
++	/** DMA Descriptor data buffer pointer */
++	uint32_t buf;
++} dwc_otg_dev_dma_desc_t;
++
++/**
++ * The dwc_otg_dev_if structure contains information needed to manage
++ * the DWC_otg controller acting in device mode. It represents the
++ * programming view of the device-specific aspects of the controller.
++ */
++typedef struct dwc_otg_dev_if {
++	/** Pointer to device Global registers.
++	 * Device Global Registers starting at offset 800h
++	 */
++	dwc_otg_device_global_regs_t *dev_global_regs;
++#define DWC_DEV_GLOBAL_REG_OFFSET 0x800
++
++	/**
++	 * Device Logical IN Endpoint-Specific Registers 900h-AFCh
++	 */
++	dwc_otg_dev_in_ep_regs_t *in_ep_regs[MAX_EPS_CHANNELS];
++#define DWC_DEV_IN_EP_REG_OFFSET 0x900
++#define DWC_EP_REG_OFFSET 0x20
++
++	/** Device Logical OUT Endpoint-Specific Registers B00h-CFCh */
++	dwc_otg_dev_out_ep_regs_t *out_ep_regs[MAX_EPS_CHANNELS];
++#define DWC_DEV_OUT_EP_REG_OFFSET 0xB00
++
++	/* Device configuration information */
++	uint8_t speed;				 /**< Device Speed	0: Unknown, 1: LS, 2:FS, 3: HS */
++	uint8_t num_in_eps;		 /**< Number # of Tx EP range: 0-15 exept ep0 */
++	uint8_t num_out_eps;		 /**< Number # of Rx EP range: 0-15 exept ep 0*/
++
++	/** Size of periodic FIFOs (Bytes) */
++	uint16_t perio_tx_fifo_size[MAX_PERIO_FIFOS];
++
++	/** Size of Tx FIFOs (Bytes) */
++	uint16_t tx_fifo_size[MAX_TX_FIFOS];
++
++	/** Thresholding enable flags and length varaiables **/
++	uint16_t rx_thr_en;
++	uint16_t iso_tx_thr_en;
++	uint16_t non_iso_tx_thr_en;
++
++	uint16_t rx_thr_length;
++	uint16_t tx_thr_length;
++
++	/**
++	 * Pointers to the DMA Descriptors for EP0 Control
++	 * transfers (virtual and physical)
++	 */
++
++	/** 2 descriptors for SETUP packets */
++	dwc_dma_t dma_setup_desc_addr[2];
++	dwc_otg_dev_dma_desc_t *setup_desc_addr[2];
++
++	/** Pointer to Descriptor with latest SETUP packet */
++	dwc_otg_dev_dma_desc_t *psetup;
++
++	/** Index of current SETUP handler descriptor */
++	uint32_t setup_desc_index;
++
++	/** Descriptor for Data In or Status In phases */
++	dwc_dma_t dma_in_desc_addr;
++	dwc_otg_dev_dma_desc_t *in_desc_addr;
++
++	/** Descriptor for Data Out or Status Out phases */
++	dwc_dma_t dma_out_desc_addr;
++	dwc_otg_dev_dma_desc_t *out_desc_addr;
++
++	/** Setup Packet Detected - if set clear NAK when queueing */
++	uint32_t spd;
++	/** Isoc ep pointer on which incomplete happens */
++	void *isoc_ep;
++
++} dwc_otg_dev_if_t;
++
++/////////////////////////////////////////////////
++// Host Mode Register Structures
++//
++/**
++ * The Host Global Registers structure defines the size and relative
++ * field offsets for the Host Mode Global Registers.  Host Global
++ * Registers offsets 400h-7FFh.
++*/
++typedef struct dwc_otg_host_global_regs {
++	/** Host Configuration Register.   <i>Offset: 400h</i> */
++	volatile uint32_t hcfg;
++	/** Host Frame Interval Register.	<i>Offset: 404h</i> */
++	volatile uint32_t hfir;
++	/** Host Frame Number / Frame Remaining Register. <i>Offset: 408h</i> */
++	volatile uint32_t hfnum;
++	/** Reserved.	<i>Offset: 40Ch</i> */
++	uint32_t reserved40C;
++	/** Host Periodic Transmit FIFO/ Queue Status Register. <i>Offset: 410h</i> */
++	volatile uint32_t hptxsts;
++	/** Host All Channels Interrupt Register. <i>Offset: 414h</i> */
++	volatile uint32_t haint;
++	/** Host All Channels Interrupt Mask Register. <i>Offset: 418h</i> */
++	volatile uint32_t haintmsk;
++	/** Host Frame List Base Address Register . <i>Offset: 41Ch</i> */
++	volatile uint32_t hflbaddr;
++} dwc_otg_host_global_regs_t;
++
++/**
++ * This union represents the bit fields in the Host Configuration Register.
++ * Read the register into the <i>d32</i> member then set/clear the bits using
++ * the <i>b</i>it elements. Write the <i>d32</i> member to the hcfg register.
++ */
++typedef union hcfg_data {
++	/** raw register data */
++	uint32_t d32;
++
++	/** register bits */
++	struct {
++		/** FS/LS Phy Clock Select */
++		unsigned fslspclksel:2;
++#define DWC_HCFG_30_60_MHZ 0
++#define DWC_HCFG_48_MHZ	   1
++#define DWC_HCFG_6_MHZ	   2
++
++		/** FS/LS Only Support */
++		unsigned fslssupp:1;
++		unsigned reserved3_6:4;
++		/** Enable 32-KHz Suspend Mode */
++		unsigned ena32khzs:1;
++		/** Resume Validation Periiod */
++		unsigned resvalid:8;
++		unsigned reserved16_22:7;
++		/** Enable Scatter/gather DMA in Host mode */
++		unsigned descdma:1;
++		/** Frame List Entries */
++		unsigned frlisten:2;
++		/** Enable Periodic Scheduling */
++		unsigned perschedena:1;
++		unsigned reserved27_30:4;
++		unsigned modechtimen:1;
++	} b;
++} hcfg_data_t;
++
++/**
++ * This union represents the bit fields in the Host Frame Remaing/Number
++ * Register.
++ */
++typedef union hfir_data {
++	/** raw register data */
++	uint32_t d32;
++
++	/** register bits */
++	struct {
++		unsigned frint:16;
++		unsigned hfirrldctrl:1;
++		unsigned reserved:15;
++	} b;
++} hfir_data_t;
++
++/**
++ * This union represents the bit fields in the Host Frame Remaing/Number
++ * Register.
++ */
++typedef union hfnum_data {
++	/** raw register data */
++	uint32_t d32;
++
++	/** register bits */
++	struct {
++		unsigned frnum:16;
++#define DWC_HFNUM_MAX_FRNUM 0x3FFF
++		unsigned frrem:16;
++	} b;
++} hfnum_data_t;
++
++typedef union hptxsts_data {
++	/** raw register data */
++	uint32_t d32;
++
++	/** register bits */
++	struct {
++		unsigned ptxfspcavail:16;
++		unsigned ptxqspcavail:8;
++		/** Top of the Periodic Transmit Request Queue
++		 *	- bit 24 - Terminate (last entry for the selected channel)
++		 *	- bits 26:25 - Token Type
++		 *	  - 2'b00 - Zero length
++		 *	  - 2'b01 - Ping
++		 *	  - 2'b10 - Disable
++		 *	- bits 30:27 - Channel Number
++		 *	- bit 31 - Odd/even microframe
++		 */
++		unsigned ptxqtop_terminate:1;
++		unsigned ptxqtop_token:2;
++		unsigned ptxqtop_chnum:4;
++		unsigned ptxqtop_odd:1;
++	} b;
++} hptxsts_data_t;
++
++/**
++ * This union represents the bit fields in the Host Port Control and Status
++ * Register. Read the register into the <i>d32</i> member then set/clear the
++ * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the
++ * hprt0 register.
++ */
++typedef union hprt0_data {
++	/** raw register data */
++	uint32_t d32;
++	/** register bits */
++	struct {
++		unsigned prtconnsts:1;
++		unsigned prtconndet:1;
++		unsigned prtena:1;
++		unsigned prtenchng:1;
++		unsigned prtovrcurract:1;
++		unsigned prtovrcurrchng:1;
++		unsigned prtres:1;
++		unsigned prtsusp:1;
++		unsigned prtrst:1;
++		unsigned reserved9:1;
++		unsigned prtlnsts:2;
++		unsigned prtpwr:1;
++		unsigned prttstctl:4;
++		unsigned prtspd:2;
++#define DWC_HPRT0_PRTSPD_HIGH_SPEED 0
++#define DWC_HPRT0_PRTSPD_FULL_SPEED 1
++#define DWC_HPRT0_PRTSPD_LOW_SPEED	2
++		unsigned reserved19_31:13;
++	} b;
++} hprt0_data_t;
++
++/**
++ * This union represents the bit fields in the Host All Interrupt
++ * Register.
++ */
++typedef union haint_data {
++	/** raw register data */
++	uint32_t d32;
++	/** register bits */
++	struct {
++		unsigned ch0:1;
++		unsigned ch1:1;
++		unsigned ch2:1;
++		unsigned ch3:1;
++		unsigned ch4:1;
++		unsigned ch5:1;
++		unsigned ch6:1;
++		unsigned ch7:1;
++		unsigned ch8:1;
++		unsigned ch9:1;
++		unsigned ch10:1;
++		unsigned ch11:1;
++		unsigned ch12:1;
++		unsigned ch13:1;
++		unsigned ch14:1;
++		unsigned ch15:1;
++		unsigned reserved:16;
++	} b;
++
++	struct {
++		unsigned chint:16;
++		unsigned reserved:16;
++	} b2;
++} haint_data_t;
++
++/**
++ * This union represents the bit fields in the Host All Interrupt
++ * Register.
++ */
++typedef union haintmsk_data {
++	/** raw register data */
++	uint32_t d32;
++	/** register bits */
++	struct {
++		unsigned ch0:1;
++		unsigned ch1:1;
++		unsigned ch2:1;
++		unsigned ch3:1;
++		unsigned ch4:1;
++		unsigned ch5:1;
++		unsigned ch6:1;
++		unsigned ch7:1;
++		unsigned ch8:1;
++		unsigned ch9:1;
++		unsigned ch10:1;
++		unsigned ch11:1;
++		unsigned ch12:1;
++		unsigned ch13:1;
++		unsigned ch14:1;
++		unsigned ch15:1;
++		unsigned reserved:16;
++	} b;
++
++	struct {
++		unsigned chint:16;
++		unsigned reserved:16;
++	} b2;
++} haintmsk_data_t;
++
++/**
++ * Host Channel Specific Registers. <i>500h-5FCh</i>
++ */
++typedef struct dwc_otg_hc_regs {
++	/** Host Channel 0 Characteristic Register. <i>Offset: 500h + (chan_num * 20h) + 00h</i> */
++	volatile uint32_t hcchar;
++	/** Host Channel 0 Split Control Register. <i>Offset: 500h + (chan_num * 20h) + 04h</i> */
++	volatile uint32_t hcsplt;
++	/** Host Channel 0 Interrupt Register. <i>Offset: 500h + (chan_num * 20h) + 08h</i> */
++	volatile uint32_t hcint;
++	/** Host Channel 0 Interrupt Mask Register. <i>Offset: 500h + (chan_num * 20h) + 0Ch</i> */
++	volatile uint32_t hcintmsk;
++	/** Host Channel 0 Transfer Size Register. <i>Offset: 500h + (chan_num * 20h) + 10h</i> */
++	volatile uint32_t hctsiz;
++	/** Host Channel 0 DMA Address Register. <i>Offset: 500h + (chan_num * 20h) + 14h</i> */
++	volatile uint32_t hcdma;
++	volatile uint32_t reserved;
++	/** Host Channel 0 DMA Buffer Address Register. <i>Offset: 500h + (chan_num * 20h) + 1Ch</i> */
++	volatile uint32_t hcdmab;
++} dwc_otg_hc_regs_t;
++
++/**
++ * This union represents the bit fields in the Host Channel Characteristics
++ * Register. Read the register into the <i>d32</i> member then set/clear the
++ * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the
++ * hcchar register.
++ */
++typedef union hcchar_data {
++	/** raw register data */
++	uint32_t d32;
++
++	/** register bits */
++	struct {
++		/** Maximum packet size in bytes */
++		unsigned mps:11;
++
++		/** Endpoint number */
++		unsigned epnum:4;
++
++		/** 0: OUT, 1: IN */
++		unsigned epdir:1;
++
++		unsigned reserved:1;
++
++		/** 0: Full/high speed device, 1: Low speed device */
++		unsigned lspddev:1;
++
++		/** 0: Control, 1: Isoc, 2: Bulk, 3: Intr */
++		unsigned eptype:2;
++
++		/** Packets per frame for periodic transfers. 0 is reserved. */
++		unsigned multicnt:2;
++
++		/** Device address */
++		unsigned devaddr:7;
++
++		/**
++		 * Frame to transmit periodic transaction.
++		 * 0: even, 1: odd
++		 */
++		unsigned oddfrm:1;
++
++		/** Channel disable */
++		unsigned chdis:1;
++
++		/** Channel enable */
++		unsigned chen:1;
++	} b;
++} hcchar_data_t;
++
++typedef union hcsplt_data {
++	/** raw register data */
++	uint32_t d32;
++
++	/** register bits */
++	struct {
++		/** Port Address */
++		unsigned prtaddr:7;
++
++		/** Hub Address */
++		unsigned hubaddr:7;
++
++		/** Transaction Position */
++		unsigned xactpos:2;
++#define DWC_HCSPLIT_XACTPOS_MID 0
++#define DWC_HCSPLIT_XACTPOS_END 1
++#define DWC_HCSPLIT_XACTPOS_BEGIN 2
++#define DWC_HCSPLIT_XACTPOS_ALL 3
++
++		/** Do Complete Split */
++		unsigned compsplt:1;
++
++		/** Reserved */
++		unsigned reserved:14;
++
++		/** Split Enble */
++		unsigned spltena:1;
++	} b;
++} hcsplt_data_t;
++
++/**
++ * This union represents the bit fields in the Host All Interrupt
++ * Register.
++ */
++typedef union hcint_data {
++	/** raw register data */
++	uint32_t d32;
++	/** register bits */
++	struct {
++		/** Transfer Complete */
++		unsigned xfercomp:1;
++		/** Channel Halted */
++		unsigned chhltd:1;
++		/** AHB Error */
++		unsigned ahberr:1;
++		/** STALL Response Received */
++		unsigned stall:1;
++		/** NAK Response Received */
++		unsigned nak:1;
++		/** ACK Response Received */
++		unsigned ack:1;
++		/** NYET Response Received */
++		unsigned nyet:1;
++		/** Transaction Err */
++		unsigned xacterr:1;
++		/** Babble Error */
++		unsigned bblerr:1;
++		/** Frame Overrun */
++		unsigned frmovrun:1;
++		/** Data Toggle Error */
++		unsigned datatglerr:1;
++		/** Buffer Not Available (only for DDMA mode) */
++		unsigned bna:1;
++		/** Exessive transaction error (only for DDMA mode) */
++		unsigned xcs_xact:1;
++		/** Frame List Rollover interrupt */
++		unsigned frm_list_roll:1;
++		/** Reserved */
++		unsigned reserved14_31:18;
++	} b;
++} hcint_data_t;
++
++/**
++ * This union represents the bit fields in the Host Channel Interrupt Mask
++ * Register. Read the register into the <i>d32</i> member then set/clear the
++ * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the
++ * hcintmsk register.
++ */
++typedef union hcintmsk_data {
++	/** raw register data */
++	uint32_t d32;
++
++	/** register bits */
++	struct {
++		unsigned xfercompl:1;
++		unsigned chhltd:1;
++		unsigned ahberr:1;
++		unsigned stall:1;
++		unsigned nak:1;
++		unsigned ack:1;
++		unsigned nyet:1;
++		unsigned xacterr:1;
++		unsigned bblerr:1;
++		unsigned frmovrun:1;
++		unsigned datatglerr:1;
++		unsigned bna:1;
++		unsigned xcs_xact:1;
++		unsigned frm_list_roll:1;
++		unsigned reserved14_31:18;
++	} b;
++} hcintmsk_data_t;
++
++/**
++ * This union represents the bit fields in the Host Channel Transfer Size
++ * Register. Read the register into the <i>d32</i> member then set/clear the
++ * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the
++ * hcchar register.
++ */
++
++typedef union hctsiz_data {
++	/** raw register data */
++	uint32_t d32;
++
++	/** register bits */
++	struct {
++		/** Total transfer size in bytes */
++		unsigned xfersize:19;
++
++		/** Data packets to transfer */
++		unsigned pktcnt:10;
++
++		/**
++		 * Packet ID for next data packet
++		 * 0: DATA0
++		 * 1: DATA2
++		 * 2: DATA1
++		 * 3: MDATA (non-Control), SETUP (Control)
++		 */
++		unsigned pid:2;
++#define DWC_HCTSIZ_DATA0 0
++#define DWC_HCTSIZ_DATA1 2
++#define DWC_HCTSIZ_DATA2 1
++#define DWC_HCTSIZ_MDATA 3
++#define DWC_HCTSIZ_SETUP 3
++
++		/** Do PING protocol when 1 */
++		unsigned dopng:1;
++	} b;
++
++	/** register bits */
++	struct {
++		/** Scheduling information */
++		unsigned schinfo:8;
++
++		/** Number of transfer descriptors.
++		 * Max value:
++		 * 64 in general,
++		 * 256 only for HS isochronous endpoint.
++		 */
++		unsigned ntd:8;
++
++		/** Data packets to transfer */
++		unsigned reserved16_28:13;
++
++		/**
++		 * Packet ID for next data packet
++		 * 0: DATA0
++		 * 1: DATA2
++		 * 2: DATA1
++		 * 3: MDATA (non-Control)
++		 */
++		unsigned pid:2;
++
++		/** Do PING protocol when 1 */
++		unsigned dopng:1;
++	} b_ddma;
++} hctsiz_data_t;
++
++/**
++ * This union represents the bit fields in the Host DMA Address
++ * Register used in Descriptor DMA mode.
++ */
++typedef union hcdma_data {
++	/** raw register data */
++	uint32_t d32;
++	/** register bits */
++	struct {
++		unsigned reserved0_2:3;
++		/** Current Transfer Descriptor. Not used for ISOC */
++		unsigned ctd:8;
++		/** Start Address of Descriptor List */
++		unsigned dma_addr:21;
++	} b;
++} hcdma_data_t;
++
++/**
++ * This union represents the bit fields in the DMA Descriptor
++ * status quadlet for host mode. Read the quadlet into the <i>d32</i> member then
++ * set/clear the bits using the <i>b</i>it elements.
++ */
++typedef union host_dma_desc_sts {
++	/** raw register data */
++	uint32_t d32;
++	/** quadlet bits */
++
++	/* for non-isochronous  */
++	struct {
++		/** Number of bytes */
++		unsigned n_bytes:17;
++		/** QTD offset to jump when Short Packet received - only for IN EPs */
++		unsigned qtd_offset:6;
++		/**
++		 * Set to request the core to jump to alternate QTD if
++		 * Short Packet received - only for IN EPs
++		 */
++		unsigned a_qtd:1;
++		 /**
++		  * Setup Packet bit. When set indicates that buffer contains
++		  * setup packet.
++		  */
++		unsigned sup:1;
++		/** Interrupt On Complete */
++		unsigned ioc:1;
++		/** End of List */
++		unsigned eol:1;
++		unsigned reserved27:1;
++		/** Rx/Tx Status */
++		unsigned sts:2;
++#define DMA_DESC_STS_PKTERR	1
++		unsigned reserved30:1;
++		/** Active Bit */
++		unsigned a:1;
++	} b;
++	/* for isochronous */
++	struct {
++		/** Number of bytes */
++		unsigned n_bytes:12;
++		unsigned reserved12_24:13;
++		/** Interrupt On Complete */
++		unsigned ioc:1;
++		unsigned reserved26_27:2;
++		/** Rx/Tx Status */
++		unsigned sts:2;
++		unsigned reserved30:1;
++		/** Active Bit */
++		unsigned a:1;
++	} b_isoc;
++} host_dma_desc_sts_t;
++
++#define	MAX_DMA_DESC_SIZE		131071
++#define MAX_DMA_DESC_NUM_GENERIC	64
++#define MAX_DMA_DESC_NUM_HS_ISOC	256
++#define MAX_FRLIST_EN_NUM		64
++/**
++ * Host-mode DMA Descriptor structure
++ *
++ * DMA Descriptor structure contains two quadlets:
++ * Status quadlet and Data buffer pointer.
++ */
++typedef struct dwc_otg_host_dma_desc {
++	/** DMA Descriptor status quadlet */
++	host_dma_desc_sts_t status;
++	/** DMA Descriptor data buffer pointer */
++	uint32_t buf;
++} dwc_otg_host_dma_desc_t;
++
++/** OTG Host Interface Structure.
++ *
++ * The OTG Host Interface Structure structure contains information
++ * needed to manage the DWC_otg controller acting in host mode. It
++ * represents the programming view of the host-specific aspects of the
++ * controller.
++ */
++typedef struct dwc_otg_host_if {
++	/** Host Global Registers starting at offset 400h.*/
++	dwc_otg_host_global_regs_t *host_global_regs;
++#define DWC_OTG_HOST_GLOBAL_REG_OFFSET 0x400
++
++	/** Host Port 0 Control and Status Register */
++	volatile uint32_t *hprt0;
++#define DWC_OTG_HOST_PORT_REGS_OFFSET 0x440
++
++	/** Host Channel Specific Registers at offsets 500h-5FCh. */
++	dwc_otg_hc_regs_t *hc_regs[MAX_EPS_CHANNELS];
++#define DWC_OTG_HOST_CHAN_REGS_OFFSET 0x500
++#define DWC_OTG_CHAN_REGS_OFFSET 0x20
++
++	/* Host configuration information */
++	/** Number of Host Channels (range: 1-16) */
++	uint8_t num_host_channels;
++	/** Periodic EPs supported (0: no, 1: yes) */
++	uint8_t perio_eps_supported;
++	/** Periodic Tx FIFO Size (Only 1 host periodic Tx FIFO) */
++	uint16_t perio_tx_fifo_size;
++
++} dwc_otg_host_if_t;
++
++/**
++ * This union represents the bit fields in the Power and Clock Gating Control
++ * Register. Read the register into the <i>d32</i> member then set/clear the
++ * bits using the <i>b</i>it elements.
++ */
++typedef union pcgcctl_data {
++	/** raw register data */
++	uint32_t d32;
++
++	/** register bits */
++	struct {
++		/** Stop Pclk */
++		unsigned stoppclk:1;
++		/** Gate Hclk */
++		unsigned gatehclk:1;
++		/** Power Clamp */
++		unsigned pwrclmp:1;
++		/** Reset Power Down Modules */
++		unsigned rstpdwnmodule:1;
++		/** Reserved */
++		unsigned reserved:1;
++		/** Enable Sleep Clock Gating (Enbl_L1Gating) */
++		unsigned enbl_sleep_gating:1;
++		/** PHY In Sleep (PhySleep) */
++		unsigned phy_in_sleep:1;
++		/** Deep Sleep*/
++		unsigned deep_sleep:1;
++		unsigned resetaftsusp:1;
++		unsigned restoremode:1;
++		unsigned enbl_extnd_hiber:1;
++		unsigned extnd_hiber_pwrclmp:1;
++		unsigned extnd_hiber_switch:1;
++		unsigned ess_reg_restored:1;
++		unsigned prt_clk_sel:2;
++		unsigned port_power:1;
++		unsigned max_xcvrselect:2;
++		unsigned max_termsel:1;
++		unsigned mac_dev_addr:7;
++		unsigned p2hd_dev_enum_spd:2;
++		unsigned p2hd_prt_spd:2;
++		unsigned if_dev_mode:1;
++	} b;
++} pcgcctl_data_t;
++
++/**
++ * This union represents the bit fields in the Global Data FIFO Software
++ * Configuration Register. Read the register into the <i>d32</i> member then
++ * set/clear the bits using the <i>b</i>it elements.
++ */
++typedef union gdfifocfg_data {
++	/* raw register data */
++	uint32_t d32;
++	/** register bits */
++	struct {
++		/** OTG Data FIFO depth */
++		unsigned gdfifocfg:16;
++		/** Start address of EP info controller */
++		unsigned epinfobase:16;
++	} b;
++} gdfifocfg_data_t;
++
++/**
++ * This union represents the bit fields in the Global Power Down Register
++ * Register. Read the register into the <i>d32</i> member then set/clear the
++ * bits using the <i>b</i>it elements.
++ */
++typedef union gpwrdn_data {
++	/* raw register data */
++	uint32_t d32;
++
++	/** register bits */
++	struct {
++		/** PMU Interrupt Select */
++		unsigned pmuintsel:1;
++		/** PMU Active */
++		unsigned pmuactv:1;
++		/** Restore */
++		unsigned restore:1;
++		/** Power Down Clamp */
++		unsigned pwrdnclmp:1;
++		/** Power Down Reset */
++		unsigned pwrdnrstn:1;
++		/** Power Down Switch */
++		unsigned pwrdnswtch:1;
++		/** Disable VBUS */
++		unsigned dis_vbus:1;
++		/** Line State Change */
++		unsigned lnstschng:1;
++		/** Line state change mask */
++		unsigned lnstchng_msk:1;
++		/** Reset Detected */
++		unsigned rst_det:1;
++		/** Reset Detect mask */
++		unsigned rst_det_msk:1;
++		/** Disconnect Detected */
++		unsigned disconn_det:1;
++		/** Disconnect Detect mask */
++		unsigned disconn_det_msk:1;
++		/** Connect Detected*/
++		unsigned connect_det:1;
++		/** Connect Detected Mask*/
++		unsigned connect_det_msk:1;
++		/** SRP Detected */
++		unsigned srp_det:1;
++		/** SRP Detect mask */
++		unsigned srp_det_msk:1;
++		/** Status Change Interrupt */
++		unsigned sts_chngint:1;
++		/** Status Change Interrupt Mask */
++		unsigned sts_chngint_msk:1;
++		/** Line State */
++		unsigned linestate:2;
++		/** Indicates current mode(status of IDDIG signal) */
++		unsigned idsts:1;
++		/** B Session Valid signal status*/
++		unsigned bsessvld:1;
++		/** ADP Event Detected */
++		unsigned adp_int:1;
++		/** Multi Valued ID pin */
++		unsigned mult_val_id_bc:5;
++		/** Reserved 24_31 */
++		unsigned reserved29_31:3;
++	} b;
++} gpwrdn_data_t;
++
++#endif
+diff --git a/drivers/usb/gadget/udc/hiudc/usb.h b/drivers/usb/gadget/udc/hiudc/usb.h
+new file mode 100644
+index 0000000..27bda82
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc/usb.h
+@@ -0,0 +1,946 @@
++/*
++ * Copyright (c) 1998 The NetBSD Foundation, Inc.
++ * All rights reserved.
++ *
++ * This code is derived from software contributed to The NetBSD Foundation
++ * by Lennart Augustsson (lennart@augustsson.net) at
++ * Carlstedt Research & Technology.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. All advertising materials mentioning features or use of this software
++ *    must display the following acknowledgement:
++ *        This product includes software developed by the NetBSD
++ *        Foundation, Inc. and its contributors.
++ * 4. Neither the name of The NetBSD Foundation nor the names of its
++ *    contributors may be used to endorse or promote products derived
++ *    from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
++ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
++ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
++ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
++ * POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/* Modified by Synopsys, Inc, 12/12/2007 */
++
++
++#ifndef _USB_H_
++#define _USB_H_
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/*
++ * The USB records contain some unaligned little-endian word
++ * components.  The U[SG]ETW macros take care of both the alignment
++ * and endian problem and should always be used to access non-byte
++ * values.
++ */
++typedef u_int8_t uByte;
++typedef u_int8_t uWord[2];
++typedef u_int8_t uDWord[4];
++
++#define USETW2(w,h,l) ((w)[0] = (u_int8_t)(l), (w)[1] = (u_int8_t)(h))
++#define UCONSTW(x)	{ (x) & 0xff, ((x) >> 8) & 0xff }
++#define UCONSTDW(x)	{ (x) & 0xff, ((x) >> 8) & 0xff, \
++			  ((x) >> 16) & 0xff, ((x) >> 24) & 0xff }
++
++#if 1
++#define UGETW(w) ((w)[0] | ((w)[1] << 8))
++#define USETW(w,v) ((w)[0] = (u_int8_t)(v), (w)[1] = (u_int8_t)((v) >> 8))
++#define UGETDW(w) ((w)[0] | ((w)[1] << 8) | ((w)[2] << 16) | ((w)[3] << 24))
++#define USETDW(w,v) ((w)[0] = (u_int8_t)(v), \
++		     (w)[1] = (u_int8_t)((v) >> 8), \
++		     (w)[2] = (u_int8_t)((v) >> 16), \
++		     (w)[3] = (u_int8_t)((v) >> 24))
++#else
++/*
++ * On little-endian machines that can handle unanliged accesses
++ * (e.g. i386) these macros can be replaced by the following.
++ */
++#define UGETW(w) (*(u_int16_t *)(w))
++#define USETW(w,v) (*(u_int16_t *)(w) = (v))
++#define UGETDW(w) (*(u_int32_t *)(w))
++#define USETDW(w,v) (*(u_int32_t *)(w) = (v))
++#endif
++
++/*
++ * Macros for accessing UAS IU fields, which are big-endian
++ */
++#define IUSETW2(w,h,l) ((w)[0] = (u_int8_t)(h), (w)[1] = (u_int8_t)(l))
++#define IUCONSTW(x)	{ ((x) >> 8) & 0xff, (x) & 0xff }
++#define IUCONSTDW(x)	{ ((x) >> 24) & 0xff, ((x) >> 16) & 0xff, \
++			((x) >> 8) & 0xff, (x) & 0xff }
++#define IUGETW(w) (((w)[0] << 8) | (w)[1])
++#define IUSETW(w,v) ((w)[0] = (u_int8_t)((v) >> 8), (w)[1] = (u_int8_t)(v))
++#define IUGETDW(w) (((w)[0] << 24) | ((w)[1] << 16) | ((w)[2] << 8) | (w)[3])
++#define IUSETDW(w,v) ((w)[0] = (u_int8_t)((v) >> 24), \
++		      (w)[1] = (u_int8_t)((v) >> 16), \
++		      (w)[2] = (u_int8_t)((v) >> 8), \
++		      (w)[3] = (u_int8_t)(v))
++
++#define UPACKED __attribute__((__packed__))
++
++typedef struct {
++	uByte		bmRequestType;
++	uByte		bRequest;
++	uWord		wValue;
++	uWord		wIndex;
++	uWord		wLength;
++} UPACKED usb_device_request_t;
++
++#define UT_GET_DIR(a) ((a) & 0x80)
++#define UT_WRITE		0x00
++#define UT_READ			0x80
++
++#define UT_GET_TYPE(a) ((a) & 0x60)
++#define UT_STANDARD		0x00
++#define UT_CLASS		0x20
++#define UT_VENDOR		0x40
++
++#define UT_GET_RECIPIENT(a) ((a) & 0x1f)
++#define UT_DEVICE		0x00
++#define UT_INTERFACE		0x01
++#define UT_ENDPOINT		0x02
++#define UT_OTHER		0x03
++
++#define UT_READ_DEVICE		(UT_READ  | UT_STANDARD | UT_DEVICE)
++#define UT_READ_INTERFACE	(UT_READ  | UT_STANDARD | UT_INTERFACE)
++#define UT_READ_ENDPOINT	(UT_READ  | UT_STANDARD | UT_ENDPOINT)
++#define UT_WRITE_DEVICE		(UT_WRITE | UT_STANDARD | UT_DEVICE)
++#define UT_WRITE_INTERFACE	(UT_WRITE | UT_STANDARD | UT_INTERFACE)
++#define UT_WRITE_ENDPOINT	(UT_WRITE | UT_STANDARD | UT_ENDPOINT)
++#define UT_READ_CLASS_DEVICE	(UT_READ  | UT_CLASS | UT_DEVICE)
++#define UT_READ_CLASS_INTERFACE	(UT_READ  | UT_CLASS | UT_INTERFACE)
++#define UT_READ_CLASS_OTHER	(UT_READ  | UT_CLASS | UT_OTHER)
++#define UT_READ_CLASS_ENDPOINT	(UT_READ  | UT_CLASS | UT_ENDPOINT)
++#define UT_WRITE_CLASS_DEVICE	(UT_WRITE | UT_CLASS | UT_DEVICE)
++#define UT_WRITE_CLASS_INTERFACE (UT_WRITE | UT_CLASS | UT_INTERFACE)
++#define UT_WRITE_CLASS_OTHER	(UT_WRITE | UT_CLASS | UT_OTHER)
++#define UT_WRITE_CLASS_ENDPOINT	(UT_WRITE | UT_CLASS | UT_ENDPOINT)
++#define UT_READ_VENDOR_DEVICE	(UT_READ  | UT_VENDOR | UT_DEVICE)
++#define UT_READ_VENDOR_INTERFACE (UT_READ  | UT_VENDOR | UT_INTERFACE)
++#define UT_READ_VENDOR_OTHER	(UT_READ  | UT_VENDOR | UT_OTHER)
++#define UT_READ_VENDOR_ENDPOINT	(UT_READ  | UT_VENDOR | UT_ENDPOINT)
++#define UT_WRITE_VENDOR_DEVICE	(UT_WRITE | UT_VENDOR | UT_DEVICE)
++#define UT_WRITE_VENDOR_INTERFACE (UT_WRITE | UT_VENDOR | UT_INTERFACE)
++#define UT_WRITE_VENDOR_OTHER	(UT_WRITE | UT_VENDOR | UT_OTHER)
++#define UT_WRITE_VENDOR_ENDPOINT (UT_WRITE | UT_VENDOR | UT_ENDPOINT)
++
++/* Requests */
++#define UR_GET_STATUS		0x00
++#define  USTAT_STANDARD_STATUS  0x00
++#define  WUSTAT_WUSB_FEATURE    0x01
++#define  WUSTAT_CHANNEL_INFO    0x02
++#define  WUSTAT_RECEIVED_DATA   0x03
++#define  WUSTAT_MAS_AVAILABILITY 0x04
++#define  WUSTAT_CURRENT_TRANSMIT_POWER 0x05
++#define UR_CLEAR_FEATURE	0x01
++#define UR_SET_FEATURE		0x03
++#define UR_SET_AND_TEST_FEATURE 0x0c
++#define UR_SET_ADDRESS		0x05
++#define UR_GET_DESCRIPTOR	0x06
++#define  UDESC_DEVICE		0x01
++#define  UDESC_CONFIG		0x02
++#define  UDESC_STRING		0x03
++#define  UDESC_INTERFACE	0x04
++#define  UDESC_ENDPOINT		0x05
++#define  UDESC_SS_USB_COMPANION	0x30
++#define  UDESC_DEVICE_QUALIFIER	0x06
++#define  UDESC_OTHER_SPEED_CONFIGURATION 0x07
++#define  UDESC_INTERFACE_POWER	0x08
++#define  UDESC_OTG		0x09
++#define  WUDESC_SECURITY	0x0c
++#define  WUDESC_KEY		0x0d
++#define   WUD_GET_KEY_INDEX(_wValue_) ((_wValue_) & 0xf)
++#define   WUD_GET_KEY_TYPE(_wValue_) (((_wValue_) & 0x30) >> 4)
++#define    WUD_KEY_TYPE_ASSOC    0x01
++#define    WUD_KEY_TYPE_GTK      0x02
++#define   WUD_GET_KEY_ORIGIN(_wValue_) (((_wValue_) & 0x40) >> 6)
++#define    WUD_KEY_ORIGIN_HOST   0x00
++#define    WUD_KEY_ORIGIN_DEVICE 0x01
++#define  WUDESC_ENCRYPTION_TYPE	0x0e
++#define  WUDESC_BOS		0x0f
++#define  WUDESC_DEVICE_CAPABILITY 0x10
++#define  WUDESC_WIRELESS_ENDPOINT_COMPANION 0x11
++#define  UDESC_BOS		0x0f
++#define  UDESC_DEVICE_CAPABILITY 0x10
++#define  UDESC_CS_DEVICE	0x21	/* class specific */
++#define  UDESC_CS_CONFIG	0x22
++#define  UDESC_CS_STRING	0x23
++#define  UDESC_CS_INTERFACE	0x24
++#define  UDESC_CS_ENDPOINT	0x25
++#define  UDESC_HUB		0x29
++#define UR_SET_DESCRIPTOR	0x07
++#define UR_GET_CONFIG		0x08
++#define UR_SET_CONFIG		0x09
++#define UR_GET_INTERFACE	0x0a
++#define UR_SET_INTERFACE	0x0b
++#define UR_SYNCH_FRAME		0x0c
++#define WUR_SET_ENCRYPTION      0x0d
++#define WUR_GET_ENCRYPTION	0x0e
++#define WUR_SET_HANDSHAKE	0x0f
++#define WUR_GET_HANDSHAKE	0x10
++#define WUR_SET_CONNECTION	0x11
++#define WUR_SET_SECURITY_DATA	0x12
++#define WUR_GET_SECURITY_DATA	0x13
++#define WUR_SET_WUSB_DATA	0x14
++#define  WUDATA_DRPIE_INFO	0x01
++#define  WUDATA_TRANSMIT_DATA	0x02
++#define  WUDATA_TRANSMIT_PARAMS	0x03
++#define  WUDATA_RECEIVE_PARAMS	0x04
++#define  WUDATA_TRANSMIT_POWER	0x05
++#define WUR_LOOPBACK_DATA_WRITE	0x15
++#define WUR_LOOPBACK_DATA_READ	0x16
++#define WUR_SET_INTERFACE_DS	0x17
++
++/* Feature numbers */
++#define UF_ENDPOINT_HALT	0
++#define UF_DEVICE_REMOTE_WAKEUP	1
++#define UF_TEST_MODE		2
++#define UF_DEVICE_B_HNP_ENABLE	3
++#define UF_DEVICE_A_HNP_SUPPORT	4
++#define UF_DEVICE_A_ALT_HNP_SUPPORT 5
++#define WUF_WUSB		3
++#define  WUF_TX_DRPIE		0x0
++#define  WUF_DEV_XMIT_PACKET	0x1
++#define  WUF_COUNT_PACKETS	0x2
++#define  WUF_CAPTURE_PACKETS	0x3
++#define UF_FUNCTION_SUSPEND	0
++#define UF_U1_ENABLE		48
++#define UF_U2_ENABLE		49
++#define UF_LTM_ENABLE		50
++
++/* Class requests from the USB 2.0 hub spec, table 11-15 */
++#define UCR_CLEAR_HUB_FEATURE		(0x2000 | UR_CLEAR_FEATURE)
++#define UCR_CLEAR_PORT_FEATURE		(0x2300 | UR_CLEAR_FEATURE)
++#define UCR_GET_HUB_DESCRIPTOR		(0xa000 | UR_GET_DESCRIPTOR)
++#define UCR_GET_HUB_STATUS		(0xa000 | UR_GET_STATUS)
++#define UCR_GET_PORT_STATUS		(0xa300 | UR_GET_STATUS)
++#define UCR_SET_HUB_FEATURE		(0x2000 | UR_SET_FEATURE)
++#define UCR_SET_PORT_FEATURE		(0x2300 | UR_SET_FEATURE)
++#define UCR_SET_AND_TEST_PORT_FEATURE	(0xa300 | UR_SET_AND_TEST_FEATURE)
++
++#ifdef _MSC_VER
++#include <pshpack1.h>
++#endif
++
++typedef struct {
++	uByte		bLength;
++	uByte		bDescriptorType;
++	uByte		bDescriptorSubtype;
++} UPACKED usb_descriptor_t;
++
++typedef struct {
++	uByte		bLength;
++	uByte		bDescriptorType;
++} UPACKED usb_descriptor_header_t;
++
++typedef struct {
++	uByte		bLength;
++	uByte		bDescriptorType;
++	uWord		bcdUSB;
++#define UD_USB_2_0		0x0200
++#define UD_IS_USB2(d) (UGETW((d)->bcdUSB) >= UD_USB_2_0)
++	uByte		bDeviceClass;
++	uByte		bDeviceSubClass;
++	uByte		bDeviceProtocol;
++	uByte		bMaxPacketSize;
++	/* The fields below are not part of the initial descriptor. */
++	uWord		idVendor;
++	uWord		idProduct;
++	uWord		bcdDevice;
++	uByte		iManufacturer;
++	uByte		iProduct;
++	uByte		iSerialNumber;
++	uByte		bNumConfigurations;
++} UPACKED usb_device_descriptor_t;
++#define USB_DEVICE_DESCRIPTOR_SIZE 18
++
++typedef struct {
++	uByte		bLength;
++	uByte		bDescriptorType;
++	uWord		wTotalLength;
++	uByte		bNumInterface;
++	uByte		bConfigurationValue;
++	uByte		iConfiguration;
++#define UC_ATT_ONE		(1 << 7)	/* must be set */
++#define UC_ATT_SELFPOWER	(1 << 6)	/* self powered */
++#define UC_ATT_WAKEUP		(1 << 5)	/* can wakeup */
++#define UC_ATT_BATTERY		(1 << 4)	/* battery powered */
++	uByte		bmAttributes;
++#define UC_BUS_POWERED		0x80
++#define UC_SELF_POWERED		0x40
++#define UC_REMOTE_WAKEUP	0x20
++	uByte		bMaxPower; /* max current in 2 mA units */
++#define UC_POWER_FACTOR 2
++} UPACKED usb_config_descriptor_t;
++#define USB_CONFIG_DESCRIPTOR_SIZE 9
++
++typedef struct {
++	uByte		bLength;
++	uByte		bDescriptorType;
++	uByte		bInterfaceNumber;
++	uByte		bAlternateSetting;
++	uByte		bNumEndpoints;
++	uByte		bInterfaceClass;
++	uByte		bInterfaceSubClass;
++	uByte		bInterfaceProtocol;
++	uByte		iInterface;
++} UPACKED usb_interface_descriptor_t;
++#define USB_INTERFACE_DESCRIPTOR_SIZE 9
++
++typedef struct {
++	uByte		bLength;
++	uByte		bDescriptorType;
++	uByte		bEndpointAddress;
++#define UE_GET_DIR(a)	((a) & 0x80)
++#define UE_SET_DIR(a,d)	((a) | (((d)&1) << 7))
++#define UE_DIR_IN	0x80
++#define UE_DIR_OUT	0x00
++#define UE_ADDR		0x0f
++#define UE_GET_ADDR(a)	((a) & UE_ADDR)
++	uByte		bmAttributes;
++#define UE_XFERTYPE	0x03
++#define  UE_CONTROL	0x00
++#define  UE_ISOCHRONOUS	0x01
++#define  UE_BULK	0x02
++#define  UE_INTERRUPT	0x03
++#define UE_GET_XFERTYPE(a)	((a) & UE_XFERTYPE)
++#define UE_ISO_TYPE	0x0c
++#define  UE_ISO_ASYNC	0x04
++#define  UE_ISO_ADAPT	0x08
++#define  UE_ISO_SYNC	0x0c
++#define UE_GET_ISO_TYPE(a)	((a) & UE_ISO_TYPE)
++	uWord		wMaxPacketSize;
++	uByte		bInterval;
++} UPACKED usb_endpoint_descriptor_t;
++#define USB_ENDPOINT_DESCRIPTOR_SIZE 7
++
++typedef struct ss_endpoint_companion_descriptor {
++	uByte bLength;
++	uByte bDescriptorType;
++	uByte bMaxBurst;
++#define USSE_GET_MAX_STREAMS(a)		((a) & 0x1f)
++#define USSE_SET_MAX_STREAMS(a, b)	((a) | ((b) & 0x1f))
++#define USSE_GET_MAX_PACKET_NUM(a)	((a) & 0x03)
++#define USSE_SET_MAX_PACKET_NUM(a, b)	((a) | ((b) & 0x03))
++	uByte bmAttributes;
++	uWord wBytesPerInterval;
++} UPACKED ss_endpoint_companion_descriptor_t;
++#define USB_SS_ENDPOINT_COMPANION_DESCRIPTOR_SIZE 6
++
++typedef struct {
++	uByte		bLength;
++	uByte		bDescriptorType;
++	uWord		bString[127];
++} UPACKED usb_string_descriptor_t;
++#define USB_MAX_STRING_LEN 128
++#define USB_LANGUAGE_TABLE 0	/* # of the string language id table */
++
++/* Hub specific request */
++#define UR_GET_BUS_STATE	0x02
++#define UR_CLEAR_TT_BUFFER	0x08
++#define UR_RESET_TT		0x09
++#define UR_GET_TT_STATE		0x0a
++#define UR_STOP_TT		0x0b
++
++/* Hub features */
++#define UHF_C_HUB_LOCAL_POWER	0
++#define UHF_C_HUB_OVER_CURRENT	1
++#define UHF_PORT_CONNECTION	0
++#define UHF_PORT_ENABLE		1
++#define UHF_PORT_SUSPEND	2
++#define UHF_PORT_OVER_CURRENT	3
++#define UHF_PORT_RESET		4
++#define UHF_PORT_L1		5
++#define UHF_PORT_POWER		8
++#define UHF_PORT_LOW_SPEED	9
++#define UHF_PORT_HIGH_SPEED	10
++#define UHF_C_PORT_CONNECTION	16
++#define UHF_C_PORT_ENABLE	17
++#define UHF_C_PORT_SUSPEND	18
++#define UHF_C_PORT_OVER_CURRENT	19
++#define UHF_C_PORT_RESET	20
++#define UHF_C_PORT_L1		23
++#define UHF_PORT_TEST		21
++#define UHF_PORT_INDICATOR	22
++
++typedef struct {
++	uByte		bDescLength;
++	uByte		bDescriptorType;
++	uByte		bNbrPorts;
++	uWord		wHubCharacteristics;
++#define UHD_PWR			0x0003
++#define  UHD_PWR_GANGED		0x0000
++#define  UHD_PWR_INDIVIDUAL	0x0001
++#define  UHD_PWR_NO_SWITCH	0x0002
++#define UHD_COMPOUND		0x0004
++#define UHD_OC			0x0018
++#define  UHD_OC_GLOBAL		0x0000
++#define  UHD_OC_INDIVIDUAL	0x0008
++#define  UHD_OC_NONE		0x0010
++#define UHD_TT_THINK		0x0060
++#define  UHD_TT_THINK_8		0x0000
++#define  UHD_TT_THINK_16	0x0020
++#define  UHD_TT_THINK_24	0x0040
++#define  UHD_TT_THINK_32	0x0060
++#define UHD_PORT_IND		0x0080
++	uByte		bPwrOn2PwrGood;	/* delay in 2 ms units */
++#define UHD_PWRON_FACTOR 2
++	uByte		bHubContrCurrent;
++	uByte		DeviceRemovable[32]; /* max 255 ports */
++#define UHD_NOT_REMOV(desc, i) \
++    (((desc)->DeviceRemovable[(i)/8] >> ((i) % 8)) & 1)
++	/* deprecated */ uByte		PortPowerCtrlMask[1];
++} UPACKED usb_hub_descriptor_t;
++#define USB_HUB_DESCRIPTOR_SIZE 9 /* includes deprecated PortPowerCtrlMask */
++
++typedef struct {
++	uByte		bLength;
++	uByte		bDescriptorType;
++	uWord		bcdUSB;
++	uByte		bDeviceClass;
++	uByte		bDeviceSubClass;
++	uByte		bDeviceProtocol;
++	uByte		bMaxPacketSize0;
++	uByte		bNumConfigurations;
++	uByte		bReserved;
++} UPACKED usb_device_qualifier_t;
++#define USB_DEVICE_QUALIFIER_SIZE 10
++
++typedef struct {
++	uByte		bLength;
++	uByte		bDescriptorType;
++	uByte		bmAttributes;
++#define UOTG_SRP	0x01
++#define UOTG_HNP	0x02
++} UPACKED usb_otg_descriptor_t;
++
++/* OTG feature selectors */
++#define UOTG_B_HNP_ENABLE	3
++#define UOTG_A_HNP_SUPPORT	4
++#define UOTG_A_ALT_HNP_SUPPORT	5
++
++typedef struct {
++	uWord		wStatus;
++/* Device status flags */
++#define UDS_SELF_POWERED		0x0001
++#define UDS_REMOTE_WAKEUP		0x0002
++/* Endpoint status flags */
++#define UES_HALT			0x0001
++} UPACKED usb_status_t;
++
++typedef struct {
++	uWord		wHubStatus;
++#define UHS_LOCAL_POWER			0x0001
++#define UHS_OVER_CURRENT		0x0002
++	uWord		wHubChange;
++} UPACKED usb_hub_status_t;
++
++typedef struct {
++	uWord		wPortStatus;
++#define UPS_CURRENT_CONNECT_STATUS	0x0001
++#define UPS_PORT_ENABLED		0x0002
++#define UPS_SUSPEND			0x0004
++#define UPS_OVERCURRENT_INDICATOR	0x0008
++#define UPS_RESET			0x0010
++#define UPS_PORT_POWER			0x0100
++#define UPS_LOW_SPEED			0x0200
++#define UPS_HIGH_SPEED			0x0400
++#define UPS_PORT_TEST			0x0800
++#define UPS_PORT_INDICATOR		0x1000
++	uWord		wPortChange;
++#define UPS_C_CONNECT_STATUS		0x0001
++#define UPS_C_PORT_ENABLED		0x0002
++#define UPS_C_SUSPEND			0x0004
++#define UPS_C_OVERCURRENT_INDICATOR	0x0008
++#define UPS_C_PORT_RESET		0x0010
++} UPACKED usb_port_status_t;
++
++#ifdef _MSC_VER
++#include <poppack.h>
++#endif
++
++/* Device class codes */
++#define UDCLASS_IN_INTERFACE	0x00
++#define UDCLASS_COMM		0x02
++#define UDCLASS_HUB		0x09
++#define  UDSUBCLASS_HUB		0x00
++#define  UDPROTO_FSHUB		0x00
++#define  UDPROTO_HSHUBSTT	0x01
++#define  UDPROTO_HSHUBMTT	0x02
++#define UDCLASS_DIAGNOSTIC	0xdc
++#define UDCLASS_WIRELESS	0xe0
++#define  UDSUBCLASS_RF		0x01
++#define   UDPROTO_BLUETOOTH	0x01
++#define UDCLASS_VENDOR		0xff
++
++/* Interface class codes */
++#define UICLASS_UNSPEC		0x00
++
++#define UICLASS_AUDIO		0x01
++#define  UISUBCLASS_AUDIOCONTROL	1
++#define  UISUBCLASS_AUDIOSTREAM		2
++#define  UISUBCLASS_MIDISTREAM		3
++
++#define UICLASS_CDC		0x02 /* communication */
++#define  UISUBCLASS_DIRECT_LINE_CONTROL_MODEL	1
++#define  UISUBCLASS_ABSTRACT_CONTROL_MODEL	2
++#define  UISUBCLASS_TELEPHONE_CONTROL_MODEL	3
++#define  UISUBCLASS_MULTICHANNEL_CONTROL_MODEL	4
++#define  UISUBCLASS_CAPI_CONTROLMODEL		5
++#define  UISUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL 6
++#define  UISUBCLASS_ATM_NETWORKING_CONTROL_MODEL 7
++#define   UIPROTO_CDC_AT			1
++
++#define UICLASS_HID		0x03
++#define  UISUBCLASS_BOOT	1
++#define  UIPROTO_BOOT_KEYBOARD	1
++
++#define UICLASS_PHYSICAL	0x05
++
++#define UICLASS_IMAGE		0x06
++
++#define UICLASS_PRINTER		0x07
++#define  UISUBCLASS_PRINTER	1
++#define  UIPROTO_PRINTER_UNI	1
++#define  UIPROTO_PRINTER_BI	2
++#define  UIPROTO_PRINTER_1284	3
++
++#define UICLASS_MASS		0x08
++#define  UISUBCLASS_RBC		1
++#define  UISUBCLASS_SFF8020I	2
++#define  UISUBCLASS_QIC157	3
++#define  UISUBCLASS_UFI		4
++#define  UISUBCLASS_SFF8070I	5
++#define  UISUBCLASS_SCSI	6
++#define  UIPROTO_MASS_CBI_I	0
++#define  UIPROTO_MASS_CBI	1
++#define  UIPROTO_MASS_BBB_OLD	2	/* Not in the spec anymore */
++#define  UIPROTO_MASS_BBB	80	/* 'P' for the Iomega Zip drive */
++
++#define UICLASS_HUB		0x09
++#define  UISUBCLASS_HUB		0
++#define  UIPROTO_FSHUB		0
++#define  UIPROTO_HSHUBSTT	0 /* Yes, same as previous */
++#define  UIPROTO_HSHUBMTT	1
++
++#define UICLASS_CDC_DATA	0x0a
++#define  UISUBCLASS_DATA		0
++#define   UIPROTO_DATA_ISDNBRI		0x30    /* Physical iface */
++#define   UIPROTO_DATA_HDLC		0x31    /* HDLC */
++#define   UIPROTO_DATA_TRANSPARENT	0x32    /* Transparent */
++#define   UIPROTO_DATA_Q921M		0x50    /* Management for Q921 */
++#define   UIPROTO_DATA_Q921		0x51    /* Data for Q921 */
++#define   UIPROTO_DATA_Q921TM		0x52    /* TEI multiplexer for Q921 */
++#define   UIPROTO_DATA_V42BIS		0x90    /* Data compression */
++#define   UIPROTO_DATA_Q931		0x91    /* Euro-ISDN */
++#define   UIPROTO_DATA_V120		0x92    /* V.24 rate adaption */
++#define   UIPROTO_DATA_CAPI		0x93    /* CAPI 2.0 commands */
++#define   UIPROTO_DATA_HOST_BASED	0xfd    /* Host based driver */
++#define   UIPROTO_DATA_PUF		0xfe    /* see Prot. Unit Func. Desc.*/
++#define   UIPROTO_DATA_VENDOR		0xff    /* Vendor specific */
++
++#define UICLASS_SMARTCARD	0x0b
++
++/*#define UICLASS_FIRM_UPD	0x0c*/
++
++#define UICLASS_SECURITY	0x0d
++
++#define UICLASS_DIAGNOSTIC	0xdc
++
++#define UICLASS_WIRELESS	0xe0
++#define  UISUBCLASS_RF			0x01
++#define   UIPROTO_BLUETOOTH		0x01
++
++#define UICLASS_APPL_SPEC	0xfe
++#define  UISUBCLASS_FIRMWARE_DOWNLOAD	1
++#define  UISUBCLASS_IRDA		2
++#define  UIPROTO_IRDA			0
++
++#define UICLASS_VENDOR		0xff
++
++#define USB_HUB_MAX_DEPTH 5
++
++/*
++ * Minimum time a device needs to be powered down to go through
++ * a power cycle.  XXX Are these time in the spec?
++ */
++#define USB_POWER_DOWN_TIME	200 /* ms */
++#define USB_PORT_POWER_DOWN_TIME	100 /* ms */
++
++#if 0
++/* These are the values from the spec. */
++#define USB_PORT_RESET_DELAY	10  /* ms */
++#define USB_PORT_ROOT_RESET_DELAY 50  /* ms */
++#define USB_PORT_RESET_RECOVERY	10  /* ms */
++#define USB_PORT_POWERUP_DELAY	100 /* ms */
++#define USB_SET_ADDRESS_SETTLE	2   /* ms */
++#define USB_RESUME_DELAY	(20*5)  /* ms */
++#define USB_RESUME_WAIT		10  /* ms */
++#define USB_RESUME_RECOVERY	10  /* ms */
++#define USB_EXTRA_POWER_UP_TIME	0   /* ms */
++#else
++/* Allow for marginal (i.e. non-conforming) devices. */
++#define USB_PORT_RESET_DELAY	50  /* ms */
++#define USB_PORT_ROOT_RESET_DELAY 250  /* ms */
++#define USB_PORT_RESET_RECOVERY	250  /* ms */
++#define USB_PORT_POWERUP_DELAY	300 /* ms */
++#define USB_SET_ADDRESS_SETTLE	10  /* ms */
++#define USB_RESUME_DELAY	(50*5)  /* ms */
++#define USB_RESUME_WAIT		50  /* ms */
++#define USB_RESUME_RECOVERY	50  /* ms */
++#define USB_EXTRA_POWER_UP_TIME	20  /* ms */
++#endif
++
++#define USB_MIN_POWER		100 /* mA */
++#define USB_MAX_POWER		500 /* mA */
++
++#define USB_BUS_RESET_DELAY	100 /* ms XXX?*/
++
++#define USB_UNCONFIG_NO 0
++#define USB_UNCONFIG_INDEX (-1)
++
++/*** ioctl() related stuff ***/
++
++struct usb_ctl_request {
++	int	ucr_addr;
++	usb_device_request_t ucr_request;
++	void	*ucr_data;
++	int	ucr_flags;
++#define USBD_SHORT_XFER_OK	0x04	/* allow short reads */
++	int	ucr_actlen;		/* actual length transferred */
++};
++
++struct usb_alt_interface {
++	int	uai_config_index;
++	int	uai_interface_index;
++	int	uai_alt_no;
++};
++
++#define USB_CURRENT_CONFIG_INDEX (-1)
++#define USB_CURRENT_ALT_INDEX (-1)
++
++struct usb_config_desc {
++	int	ucd_config_index;
++	usb_config_descriptor_t ucd_desc;
++};
++
++struct usb_interface_desc {
++	int	uid_config_index;
++	int	uid_interface_index;
++	int	uid_alt_index;
++	usb_interface_descriptor_t uid_desc;
++};
++
++struct usb_endpoint_desc {
++	int	ued_config_index;
++	int	ued_interface_index;
++	int	ued_alt_index;
++	int	ued_endpoint_index;
++	usb_endpoint_descriptor_t ued_desc;
++};
++
++struct usb_full_desc {
++	int	ufd_config_index;
++	u_int	ufd_size;
++	u_char	*ufd_data;
++};
++
++struct usb_string_desc {
++	int	usd_string_index;
++	int	usd_language_id;
++	usb_string_descriptor_t usd_desc;
++};
++
++struct usb_ctl_report_desc {
++	int	ucrd_size;
++	u_char	ucrd_data[1024];	/* filled data size will vary */
++};
++
++typedef struct { u_int32_t cookie; } usb_event_cookie_t;
++
++#define USB_MAX_DEVNAMES 4
++#define USB_MAX_DEVNAMELEN 16
++struct usb_device_info {
++	u_int8_t	udi_bus;
++	u_int8_t	udi_addr;	/* device address */
++	usb_event_cookie_t udi_cookie;
++	char		udi_product[USB_MAX_STRING_LEN];
++	char		udi_vendor[USB_MAX_STRING_LEN];
++	char		udi_release[8];
++	u_int16_t	udi_productNo;
++	u_int16_t	udi_vendorNo;
++	u_int16_t	udi_releaseNo;
++	u_int8_t	udi_class;
++	u_int8_t	udi_subclass;
++	u_int8_t	udi_protocol;
++	u_int8_t	udi_config;
++	u_int8_t	udi_speed;
++#define USB_SPEED_UNKNOWN	0
++#define USB_SPEED_LOW		1
++#define USB_SPEED_FULL		2
++#define USB_SPEED_HIGH		3
++#define USB_SPEED_VARIABLE	4
++#define USB_SPEED_SUPER		5
++	int		udi_power;	/* power consumption in mA, 0 if selfpowered */
++	int		udi_nports;
++	char		udi_devnames[USB_MAX_DEVNAMES][USB_MAX_DEVNAMELEN];
++	u_int8_t	udi_ports[16];/* hub only: addresses of devices on ports */
++#define USB_PORT_ENABLED 0xff
++#define USB_PORT_SUSPENDED 0xfe
++#define USB_PORT_POWERED 0xfd
++#define USB_PORT_DISABLED 0xfc
++};
++
++struct usb_ctl_report {
++	int	ucr_report;
++	u_char	ucr_data[1024];	/* filled data size will vary */
++};
++
++struct usb_device_stats {
++	u_long	uds_requests[4];	/* indexed by transfer type UE_* */
++};
++
++#define WUSB_MIN_IE			0x80
++#define WUSB_WCTA_IE			0x80
++#define WUSB_WCONNECTACK_IE		0x81
++#define WUSB_WHOSTINFO_IE		0x82
++#define  WUHI_GET_CA(_bmAttributes_) ((_bmAttributes_) & 0x3)
++#define   WUHI_CA_RECONN		0x00
++#define   WUHI_CA_LIMITED		0x01
++#define   WUHI_CA_ALL			0x03
++#define  WUHI_GET_MLSI(_bmAttributes_) (((_bmAttributes_) & 0x38) >> 3)
++#define WUSB_WCHCHANGEANNOUNCE_IE	0x83
++#define WUSB_WDEV_DISCONNECT_IE		0x84
++#define WUSB_WHOST_DISCONNECT_IE	0x85
++#define WUSB_WRELEASE_CHANNEL_IE	0x86
++#define WUSB_WWORK_IE			0x87
++#define WUSB_WCHANNEL_STOP_IE		0x88
++#define WUSB_WDEV_KEEPALIVE_IE		0x89
++#define WUSB_WISOCH_DISCARD_IE		0x8A
++#define WUSB_WRESETDEVICE_IE		0x8B
++#define WUSB_WXMIT_PACKET_ADJUST_IE	0x8C
++#define WUSB_MAX_IE			0x8C
++
++/* Device Notification Types */
++
++#define WUSB_DN_MIN			0x01
++#define WUSB_DN_CONNECT			0x01
++# define WUSB_DA_OLDCONN	0x00
++# define WUSB_DA_NEWCONN	0x01
++# define WUSB_DA_SELF_BEACON	0x02
++# define WUSB_DA_DIR_BEACON	0x04
++# define WUSB_DA_NO_BEACON	0x06
++#define WUSB_DN_DISCONNECT		0x02
++#define WUSB_DN_EPRDY			0x03
++#define WUSB_DN_MASAVAILCHANGED		0x04
++#define WUSB_DN_REMOTEWAKEUP		0x05
++#define WUSB_DN_SLEEP			0x06
++#define WUSB_DN_ALIVE			0x07
++#define WUSB_DN_MAX			0x07
++
++#ifdef _MSC_VER
++#include <pshpack1.h>
++#endif
++
++/* WUSB Handshake Data.  Used during the SET/GET HANDSHAKE requests */
++typedef struct wusb_hndshk_data {
++	uByte bMessageNumber;
++	uByte bStatus;
++	uByte tTKID[3];
++	uByte bReserved;
++	uByte CDID[16];
++	uByte Nonce[16];
++	uByte MIC[8];
++} UPACKED wusb_hndshk_data_t;
++#define WUSB_HANDSHAKE_LEN_FOR_MIC	38
++
++/* WUSB Connection Context */
++typedef struct wusb_conn_context {
++	uByte CHID [16];
++	uByte CDID [16];
++	uByte CK [16];
++} UPACKED wusb_conn_context_t;
++
++/* WUSB Security Descriptor */
++typedef struct wusb_security_desc {
++	uByte bLength;
++	uByte bDescriptorType;
++	uWord wTotalLength;
++	uByte bNumEncryptionTypes;
++} UPACKED wusb_security_desc_t;
++
++/* WUSB Encryption Type Descriptor */
++typedef struct wusb_encrypt_type_desc {
++	uByte bLength;
++	uByte bDescriptorType;
++
++	uByte bEncryptionType;
++#define WUETD_UNSECURE		0
++#define WUETD_WIRED		1
++#define WUETD_CCM_1		2
++#define WUETD_RSA_1		3
++
++	uByte bEncryptionValue;
++	uByte bAuthKeyIndex;
++} UPACKED wusb_encrypt_type_desc_t;
++
++/* WUSB Key Descriptor */
++typedef struct wusb_key_desc {
++	uByte bLength;
++	uByte bDescriptorType;
++	uByte tTKID[3];
++	uByte bReserved;
++	uByte KeyData[1];	/* variable length */
++} UPACKED wusb_key_desc_t;
++
++/* WUSB BOS Descriptor (Binary device Object Store) */
++typedef struct wusb_bos_desc {
++	uByte bLength;
++	uByte bDescriptorType;
++	uWord wTotalLength;
++	uByte bNumDeviceCaps;
++} UPACKED wusb_bos_desc_t;
++
++#define USB_DEVICE_CAPABILITY_20_EXTENSION	0x02
++typedef struct usb_dev_cap_20_ext_desc {
++	uByte bLength;
++	uByte bDescriptorType;
++	uByte bDevCapabilityType;
++#define USB_20_EXT_LPM				0x02
++	uDWord bmAttributes;
++} UPACKED usb_dev_cap_20_ext_desc_t;
++
++#define USB_DEVICE_CAPABILITY_SS_USB		0x03
++typedef struct usb_dev_cap_ss_usb {
++	uByte bLength;
++	uByte bDescriptorType;
++	uByte bDevCapabilityType;
++#define USB_DC_SS_USB_LTM_CAPABLE		0x02
++	uByte bmAttributes;
++#define USB_DC_SS_USB_SPEED_SUPPORT_LOW		0x01
++#define USB_DC_SS_USB_SPEED_SUPPORT_FULL	0x02
++#define USB_DC_SS_USB_SPEED_SUPPORT_HIGH	0x04
++#define USB_DC_SS_USB_SPEED_SUPPORT_SS		0x08
++	uWord wSpeedsSupported;
++	uByte bFunctionalitySupport;
++	uByte bU1DevExitLat;
++	uWord wU2DevExitLat;
++} UPACKED usb_dev_cap_ss_usb_t;
++
++#define USB_DEVICE_CAPABILITY_CONTAINER_ID	0x04
++typedef struct usb_dev_cap_container_id {
++	uByte bLength;
++	uByte bDescriptorType;
++	uByte bDevCapabilityType;
++	uByte bReserved;
++	uByte containerID[16];
++} UPACKED usb_dev_cap_container_id_t;
++
++/* Device Capability Type Codes */
++#define WUSB_DEVICE_CAPABILITY_WIRELESS_USB 0x01
++
++/* Device Capability Descriptor */
++typedef struct wusb_dev_cap_desc {
++	uByte bLength;
++	uByte bDescriptorType;
++	uByte bDevCapabilityType;
++	uByte caps[1];	/* Variable length */
++} UPACKED wusb_dev_cap_desc_t;
++
++/* Device Capability Descriptor */
++typedef struct wusb_dev_cap_uwb_desc {
++	uByte bLength;
++	uByte bDescriptorType;
++	uByte bDevCapabilityType;
++	uByte bmAttributes;
++	uWord wPHYRates;	/* Bitmap */
++	uByte bmTFITXPowerInfo;
++	uByte bmFFITXPowerInfo;
++	uWord bmBandGroup;
++	uByte bReserved;
++} UPACKED wusb_dev_cap_uwb_desc_t;
++
++/* Wireless USB Endpoint Companion Descriptor */
++typedef struct wusb_endpoint_companion_desc {
++	uByte bLength;
++	uByte bDescriptorType;
++	uByte bMaxBurst;
++	uByte bMaxSequence;
++	uWord wMaxStreamDelay;
++	uWord wOverTheAirPacketSize;
++	uByte bOverTheAirInterval;
++	uByte bmCompAttributes;
++} UPACKED wusb_endpoint_companion_desc_t;
++
++/* Wireless USB Numeric Association M1 Data Structure */
++typedef struct wusb_m1_data {
++	uByte version;
++	uWord langId;
++	uByte deviceFriendlyNameLength;
++	uByte sha_256_m3[32];
++	uByte deviceFriendlyName[256];
++} UPACKED wusb_m1_data_t;
++
++typedef struct wusb_m2_data {
++	uByte version;
++	uWord langId;
++	uByte hostFriendlyNameLength;
++	uByte pkh[384];
++	uByte hostFriendlyName[256];
++} UPACKED wusb_m2_data_t;
++
++typedef struct wusb_m3_data {
++	uByte pkd[384];
++	uByte nd;
++} UPACKED wusb_m3_data_t;
++
++typedef struct wusb_m4_data {
++	uDWord _attributeTypeIdAndLength_1;
++	uWord  associationTypeId;
++
++	uDWord _attributeTypeIdAndLength_2;
++	uWord  associationSubTypeId;
++
++	uDWord _attributeTypeIdAndLength_3;
++	uDWord length;
++
++	uDWord _attributeTypeIdAndLength_4;
++	uDWord associationStatus;
++
++	uDWord _attributeTypeIdAndLength_5;
++	uByte  chid[16];
++
++	uDWord _attributeTypeIdAndLength_6;
++	uByte  cdid[16];
++
++	uDWord _attributeTypeIdAndLength_7;
++	uByte  bandGroups[2];
++} UPACKED wusb_m4_data_t;
++
++#ifdef _MSC_VER
++#include <poppack.h>
++#endif
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* _USB_H_ */
+diff --git a/drivers/usb/gadget/udc/hiudc3/Kconfig b/drivers/usb/gadget/udc/hiudc3/Kconfig
+new file mode 100644
+index 0000000..dc4c087
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc3/Kconfig
+@@ -0,0 +1,44 @@
++#
++# hisilicon usb2 device controller version 3.00a
++#
++
++menuconfig HI_SS_DEVICE
++	tristate "hisilicon usb3 device controller version 2.50a driver"
++	default n
++	select USB_GADGET_DUALSPEED
++	select USB_GADGET_SELECTED
++	help
++	  hisilicon usb3 device controller version 3.00a.
++
++if HI_SS_DEVICE
++
++config HIUSB_XHCI_REG_BASE_ADDRESS
++	hex "hiusb3dev system control register base address"
++	default "0xf98a0000" if ARCH_S40
++	default "0x60180000" if ARCH_GODBOX
++	default "0x10180000" if ARCH_HI3519
++	default "0x10180000" if ARCH_HI3519V101
++	default "0x10180000" if ARCH_HI3559
++	default "0x10180000" if ARCH_HI3556
++	default "0x10180000" if ARCH_HI3516AV200
++
++config HIUSB_XHCI_REG_BASE_ADDRESS_LEN
++	hex "hiusb3dev system control register size length"
++	default "0x10000" if ARCH_S40
++	default "0x10000" if ARCH_GODBOX
++	default "0x10000" if ARCH_HI3519
++	default "0x10000" if ARCH_HI3519V101
++	default "0x10000" if ARCH_HI3559
++	default "0x10000" if ARCH_HI3556
++	default "0x10000" if ARCH_HI3516AV200
++
++config HIUSB_XHCI_IRQ_NUMBER
++	int "hiusb3dev system control register interrupt number"
++	default "100" if ARCH_S40
++	default "103" if ARCH_GODBOX
++	default "54" if ARCH_HI3519
++	default "54" if ARCH_HI3519V101
++	default "54" if ARCH_HI3559
++	default "54" if ARCH_HI3556
++	default "54" if ARCH_HI3516AV200
++endif # HI_SS_DEVICE
+diff --git a/drivers/usb/gadget/udc/hiudc3/Makefile b/drivers/usb/gadget/udc/hiudc3/Makefile
+new file mode 100644
+index 0000000..094fdbd
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc3/Makefile
+@@ -0,0 +1,99 @@
++#
++# Makefile for DWC_usb3 SuperSpeed USB controller driver
++#
++
++ifneq ($(KERNELRELEASE),)
++
++# This line is required for 2.6.37 era kernels, or else files in
++# subdirectories won't compile
++EXTRA_CFLAGS	+= -I$(KBUILD_EXTMOD)
++
++ifneq ($(NOOS),)
++EXTRA_CFLAGS	+= -DLINUXTEST
++else
++ifneq ($(SELA),)
++EXTRA_CFLAGS	+= -DLINUXTEST
++else
++ifneq ($(PLATFORM),)
++EXTRA_CFLAGS	+= -DDWC_PLATFORM_DEV
++endif
++endif
++endif
++
++# Uncomment these for debug messages
++EXTRA_CFLAGS	+= -DDEBUG
++EXTRA_CFLAGS	+= -DVERBOSE
++EXTRA_CFLAGS	+= -DDEBUG_EP0
++
++# Uncomment this, and comment out the previous 3, for minimal debug for ISOC
++#EXTRA_CFLAGS	+= -DISOC_DEBUG
++
++# Uncomment to force gasket regs to be accessed in BAR 2. Not needed if the
++# PCI device ID is 0xabce.
++#EXTRA_CFLAGS	+= -DDWC_BAR2_GASKET_REG
++
++# Uncomment for OTG
++#EXTRA_CFLAGS	+= -DCONFIG_USB_OTG_DWC
++
++# Uncomment for SSIC
++#EXTRA_CFLAGS	+= -DSSIC
++
++# Uncomment this to support the UTE gadget, and also uncomment the line with
++# "dwc_usb3-objs += linux/ute_if.o" below
++#EXTRA_CFLAGS	+= -DDWC_UTE -I$(KBUILD_SRC)/../UTE-3.0/common -I$(KBUILD_EXTMOD)/../UTE-3.0/common
++
++#EXTRA_CFLAGS	+= -DDWC_ISOC_INTR_MODERATION
++#EXTRA_CFLAGS	+= -DDWC_TEST_ISOC_CHAIN
++#EXTRA_CFLAGS	+= -DLECROY
++
++#EXTRA_CFLAGS	+= -DDWC_STAR_9000446947_WORKAROUND
++#EXTRA_CFLAGS	+= -DDWC_STAR_9000449814_WORKAROUND
++#EXTRA_CFLAGS	+= -DDWC_STAR_9000459034_WORKAROUND
++#EXTRA_CFLAGS	+= -DDWC_STAR_9000463548_WORKAROUND
++#EXTRA_CFLAGS	+= -DDWC_STAR_9000468158_WORKAROUND
++#EXTRA_CFLAGS	+= -DDWC_STAR_9000483510_WORKAROUND
++
++#obj-m		:= dwc_usb3.o
++obj-$(CONFIG_USB_HISI_UDC3)	:= dwc_usb3.o
++
++dwc_usb3-objs	:= cil.o cil_intr.o
++dwc_usb3-objs	+= pcd.o pcd_intr.o pcd_hiber.o ep0.o
++#dwc_usb3-objs   += hiusb3.o
++
++ifneq ($(NOOS),)
++dwc_usb3-objs	+= no_os/no_os_init.o no_os/no_os_hiber.o no_os/no_os_ep0.o
++dwc_usb3-objs	+= no_os/no_os_gadget.o no_os/no_os_src_sink_lpbk.o
++else
++ifneq ($(SELA),)
++dwc_usb3-objs	+= sela/sela_bm_defs.o sela/sela_driver.o sela/sela_ep0.o
++dwc_usb3-objs	+= sela/sela_funcs.o sela/sela_gadget.o
++else
++dwc_usb3-objs	+= linux_gadget.o linux_hiber.o linux_sysfs.o
++#ifneq ($(PLATFORM),)
++dwc_usb3-objs	+= linux_plat.o
++#else
++#dwc_usb3-objs	+= linux/linux_pci.o
++#endif
++endif
++endif
++
++# Uncomment this to support the UTE gadget, and also uncomment the line with
++# "-DDWC_UTE" above
++#dwc_usb3-objs	+= linux/ute_if.o
++
++else
++endif
++
++#ifneq ($(NOOS),)
++#	ln -s no_os/no_os_defs.h os_defs.h
++#	ln -s no_os/no_os_dev.h os_dev.h
++#else
++#ifneq ($(SELA),)
++#	ln -s sela/sela_defs.h os_defs.h
++#	ln -s sela/sela_dev.h os_dev.h
++#else
++#	ln -s linux/linux_defs.h os_defs.h
++#	ln -s linux/linux_dev.h os_dev.h
++#	ln -s linux/ute_if.h ute_if.h
++#endif
++#endif
+diff --git a/drivers/usb/gadget/udc/hiudc3/Makefile.no_os b/drivers/usb/gadget/udc/hiudc3/Makefile.no_os
+new file mode 100644
+index 0000000..b0074d4
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc3/Makefile.no_os
+@@ -0,0 +1,84 @@
++#
++# Makefile for DWC_usb3 SuperSpeed USB controller driver
++#
++
++CFLAGS	:= -O2 -Wall -Wno-pointer-sign -g -I.
++LDFLAGS	:= -g
++
++CFLAGS	+= -DTESTCOMPILE
++
++# Uncomment these for debug messages
++CFLAGS	+= -DDEBUG
++CFLAGS	+= -DVERBOSE
++CFLAGS	+= -DDEBUG_EP0
++
++# Uncomment this, and comment out the previous 3, for minimal debug for ISOC
++#CFLAGS	+= -DISOC_DEBUG
++
++# Uncomment this to enable Bulk Streams, to support the UASP gadget
++CFLAGS	+= -DDWC_UASP_GADGET_STREAMS
++
++# Uncomment this to support the UTE gadget, and also uncomment the line with
++# "dwc_usb3-objs += ute_if.o" below
++#CFLAGS	+= -DDWC_UTE -I$(KBUILD_SRC)/../UTE-3.0/common
++
++#CFLAGS	+= -DDWC_ISOC_INTR_MODERATION
++#CFLAGS	+= -DDWC_TEST_ISOC_CHAIN
++#CFLAGS	+= -DLECROY
++
++#CFLAGS	+= -DDWC_STAR_9000446947_WORKAROUND
++#CFLAGS	+= -DDWC_STAR_9000449814_WORKAROUND
++#CFLAGS	+= -DDWC_STAR_9000459034_WORKAROUND
++#CFLAGS	+= -DDWC_STAR_9000463548_WORKAROUND
++#CFLAGS	+= -DDWC_STAR_9000468158_WORKAROUND
++#CFLAGS	+= -DDWC_STAR_9000483510_WORKAROUND
++
++obj-m		:= dwc_usb3
++
++dwc_usb3-objs	:= cil.o cil_intr.o
++dwc_usb3-objs	+= pcd.o pcd_intr.o pcd_hiber.o ep0.o
++dwc_usb3-objs	+= no_os/no_os_init.o no_os/no_os_hiber.o no_os/no_os_ep0.o
++dwc_usb3-objs	+= no_os/no_os_gadget.o no_os/no_os_src_sink_lpbk.o
++
++# Uncomment this to support the UTE gadget, and also uncomment the line with
++# "-DDWC_UTE" above
++#dwc_usb3-objs	+= ute_if.o
++
++PWD		:= $(shell pwd)
++
++# Command paths
++CTAGS		:= /usr/bin/ctags
++DOXYGEN		:= /depot/doxygen-1.5.8/bin/doxygen
++
++default: all
++
++docs:
++	cd doc ; \
++	$(DOXYGEN) ; \
++	cp doxygen.sty latex/ ; \
++	cp synopsys.eps latex/ ; \
++	cp synopsys.pdf latex/ ; \
++	make -C latex/ ; \
++	cd ..
++
++tags:	$(wildcard *.[ch])
++	$(CTAGS) -e $(wildcard *.[ch]) $(wildcard linux/*.[ch]) \
++            $(wildcard $(KDIR)/include/linux/usb*.h)
++
++driver: links $(obj-m)
++
++$(obj-m): $(dwc_usb3-objs)
++	$(CC) $(LDFLAGS) -o $(obj-m) $(dwc_usb3-objs)
++
++links:
++	rm -f os_defs.h os_dev.h
++	ln -s no_os/no_os_defs.h os_defs.h
++	ln -s no_os/no_os_dev.h os_dev.h
++
++clean:
++	rm -rf $(obj-m) *.o no_os/*.o
++
++cleanall: clean
++	rm -rf doc/html doc/latex doc/rtf
++
++all: driver
+diff --git a/drivers/usb/gadget/udc/hiudc3/cil.c b/drivers/usb/gadget/udc/hiudc3/cil.c
+new file mode 100644
+index 0000000..66601ac
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc3/cil.c
+@@ -0,0 +1,2066 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/DWC_usb3/driver/cil.c $
++ * $Revision: #110 $
++ * $Date: 2014/11/11 $
++ * $Change: 2664766 $
++ *
++ * Synopsys SS USB3 Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
++ * ========================================================================== */
++
++/** @file
++ *
++ * The Core Interface Layer provides basic services for accessing and
++ * managing the DWC_usb3 hardware. These services are used by both the
++ * Peripheral Controller Driver and the On The Go Driver.
++ *
++ * The CIL manages the memory map for the core so that the PCD and OTG drivers
++ * don't have to do this separately. The CIL also performs basic services
++ * that are not specific to either the Device or OTG modes of operation.
++ * These services include all functionality that requires specific
++ * knowledge of the CSR layout or the DMA descriptor (TRB) layout. Also
++ * included are services for invoking each of the commands provided by
++ * the DGCMD and DEPCMD registers (see the "Control and Status Registers"
++ * chapter of the USB3 controller databook for details).
++ *
++ * The Core Interface Layer has the following requirements:
++ * - Provides basic controller operations.
++ * - Minimal use of OS services.
++ * - The OS services used will be abstracted by using inline functions
++ *   or macros.
++ *
++ */
++
++#include "os_defs.h"
++#include "hw.h"
++#include "usb.h"
++#include "pcd.h"
++#include "dev.h"
++#include "os_dev.h"
++#include "cil.h"
++
++/**
++ * Fill in the four dwords of a DMA descriptor (aka a TRB).
++ */
++void dwc_usb3_fill_desc(dwc_usb3_dma_desc_t *desc, dwc_dma_t dma_addr,
++			u32 dma_len, u32 stream, u32 type,
++			u32 ctrlbits, int own)
++{
++	desc->bptl = (u32)(dma_addr & 0xffffffffU);
++#ifdef DWC_64_BIT_ARCH
++	desc->bpth = (u32)(dma_addr >> 32U & 0xffffffffU);
++#else
++	desc->bpth = 0;
++#endif
++	desc->status = dma_len << DWC_DSCSTS_XFRCNT_SHIFT;
++
++	/* Note: If type is 0, leave original control bits intact (for isoc) */
++	if (type)
++		desc->control = type << DWC_DSCCTL_TRBCTL_SHIFT;
++
++	desc->control |= stream << DWC_DSCCTL_STRMID_SOFN_SHIFT | ctrlbits;
++
++	/* Must do this last! */
++	if (own) {
++		wmb();
++		desc->control |= DWC_DSCCTL_HWO_BIT;
++	}
++}
++
++/**
++ * Make a DMA descriptor the start of a chain by setting its CHN bit and
++ * clearing its IOC bit.
++ *
++ * @param desc  The DMA descriptor (TRB) to operate on.
++ */
++void dwc_usb3_start_desc_chain(dwc_usb3_dma_desc_t *desc)
++{
++	desc->control |= DWC_DSCCTL_CHN_BIT;
++	desc->control &= ~DWC_DSCCTL_IOC_BIT;
++}
++
++/**
++ * Make a DMA descriptor the end of a chain by clearing its CHN bit and
++ * setting its IOC bit.
++ *
++ * @param desc  The DMA descriptor (TRB) to operate on.
++ */
++void dwc_usb3_end_desc_chain(dwc_usb3_dma_desc_t *desc)
++{
++	desc->control &= ~DWC_DSCCTL_CHN_BIT;
++	desc->control |= DWC_DSCCTL_IOC_BIT;
++}
++
++/**
++ * Enable a DMA descriptor by setting its HWO bit.
++ *
++ * @param desc  The DMA descriptor (TRB) to operate on.
++ */
++void dwc_usb3_enable_desc(dwc_usb3_dma_desc_t *desc)
++{
++	wmb();
++	desc->control |= DWC_DSCCTL_HWO_BIT;
++}
++
++/**
++ * Disable a DMA descriptor by clearing its HWO bit.
++ *
++ * NOTE: This must only be called if it is known that the hardware has finished
++ * with the DMA descriptor, but for some reason the hardware has not cleared
++ * the HWO bit.
++ *
++ * @param desc  The DMA descriptor (TRB) to operate on.
++ */
++void dwc_usb3_disable_desc(dwc_usb3_dma_desc_t *desc)
++{
++	desc->control &= ~DWC_DSCCTL_HWO_BIT;
++	wmb();
++}
++
++/**
++ * Spin on register bit until handshake completes or times out.
++ *
++ * @param dev   Programming view of DWC_usb3 controller.
++ * @param ptr   Address of register to read.
++ * @param mask  Bit to look at in result of read.
++ * @param done  Value of the bit when handshake succeeds.
++ * @return      1 when the mask bit has the specified value (handshake done),
++ *              0 when timeout has passed (handshake failed).
++ */
++static int _handshake(dwc_usb3_device_t *dev, volatile u32 __iomem *ptr,
++		      u32 mask, u32 done)
++{
++	u32 usec = 100000;
++	u32 result;
++
++	dwc_debug1(dev, "%s()\n", __func__);
++
++	do {
++		result = dwc_rd32(dev, ptr);
++		if ((result & mask) == done) {
++			dwc_debug1(dev, "after DEPCMD=%08x\n", result);
++			return 1;
++		}
++
++		dwc_udelay(dev, 1);
++		usec -= 1;
++	} while (usec > 0);
++
++	return 0;
++}
++
++/*
++ * Routines for sending the various Device commands to the hardware.
++ * See description of DGCMD register in "Control and Status Registers"
++ * section of the USB3 controller databook.
++ */
++
++/**
++ * Send TRANSMIT FUNCTION WAKE DEVICE NOTIFICATION command to Device
++ */
++int dwc_usb3_xmit_fn_remote_wake(dwc_usb3_pcd_t *pcd, u32 intf)
++{
++	dwc_debug1(pcd->usb3_dev, "%s()\n", __func__);
++
++	/* Use the generic Transmit Device Notification command if the core
++	 * supports it
++	 */
++	if (pcd->usb3_dev->snpsid >= 0x5533210a) {
++		/* Set param */
++		dwc_wr32(pcd->usb3_dev, &pcd->dev_global_regs->dgcmdpar,
++			 intf << DWC_DGCMDPAR_DEV_NOTIF_PARAM_SHIFT |
++			 DWC_DGCMD_FUNCTION_WAKE_DEV_NOTIF);
++		dwc_debug1(pcd->usb3_dev, "DGCMDPAR=%08x\n",
++			   intf << DWC_DGCMDPAR_DEV_NOTIF_PARAM_SHIFT |
++			   DWC_DGCMD_FUNCTION_WAKE_DEV_NOTIF);
++
++		/* Start the command */
++		dwc_wr32(pcd->usb3_dev, &pcd->dev_global_regs->dgcmd,
++			 DWC_DGCMD_XMIT_DEV_NOTIF | DWC_DGCMD_ACT_BIT);
++		dwc_debug1(pcd->usb3_dev, "DGCMD=%08x\n",
++			   DWC_DGCMD_XMIT_DEV_NOTIF | DWC_DGCMD_ACT_BIT);
++	} else {
++		/* Set param */
++		dwc_wr32(pcd->usb3_dev, &pcd->dev_global_regs->dgcmdpar, intf);
++		dwc_debug1(pcd->usb3_dev, "DGCMDPAR=%08x\n", intf);
++
++		/* Start the command */
++		dwc_wr32(pcd->usb3_dev, &pcd->dev_global_regs->dgcmd,
++			 DWC_DGCMD_XMIT_FUNC_WAKE_DEV_NOTIF | DWC_DGCMD_ACT_BIT);
++		dwc_debug1(pcd->usb3_dev, "DGCMD=%08x\n",
++			   DWC_DGCMD_XMIT_FUNC_WAKE_DEV_NOTIF | DWC_DGCMD_ACT_BIT);
++	}
++
++	/* Wait for command completion */
++	handshake(pcd->usb3_dev, &pcd->dev_global_regs->dgcmd,
++		  DWC_DGCMD_ACT_BIT, 0);
++
++	return 0;
++}
++
++/**
++ * Send LATENCY TOLERANCE MESSAGE DEVICE NOTIFICATION command to Device
++ */
++int dwc_usb3_xmit_ltm(dwc_usb3_pcd_t *pcd, u32 value)
++{
++	dwc_debug1(pcd->usb3_dev, "%s()\n", __func__);
++
++	/* Use the generic Transmit Device Notification command if the core
++	 * supports it. Otherwise this function is a no-op.
++	 */
++	if (pcd->usb3_dev->snpsid >= 0x5533210a) {
++		/* Set param */
++		dwc_wr32(pcd->usb3_dev, &pcd->dev_global_regs->dgcmdpar,
++			 value << DWC_DGCMDPAR_DEV_NOTIF_PARAM_SHIFT |
++			 DWC_DGCMD_LATENCY_TOL_DEV_NOTIF);
++		dwc_debug1(pcd->usb3_dev, "DGCMDPAR=%08x\n",
++			   value << DWC_DGCMDPAR_DEV_NOTIF_PARAM_SHIFT |
++			   DWC_DGCMD_LATENCY_TOL_DEV_NOTIF);
++
++		/* Start the command */
++		dwc_wr32(pcd->usb3_dev, &pcd->dev_global_regs->dgcmd,
++			 DWC_DGCMD_XMIT_DEV_NOTIF | DWC_DGCMD_ACT_BIT);
++		dwc_debug1(pcd->usb3_dev, "DGCMD=%08x\n",
++			   DWC_DGCMD_XMIT_DEV_NOTIF | DWC_DGCMD_ACT_BIT);
++
++		/* Wait for command completion */
++		handshake(pcd->usb3_dev, &pcd->dev_global_regs->dgcmd,
++			  DWC_DGCMD_ACT_BIT, 0);
++	}
++
++	return 0;
++}
++
++#ifdef CONFIG_USB_OTG_DWC
++/**
++ * Send ROLE REQUEST DEVICE NOTIFICATION command to Device
++ */
++int dwc_usb3_xmit_host_role_request(dwc_usb3_pcd_t *pcd, u32 param)
++{
++#ifdef DEBUG
++	char *type = "UNKNOWN";
++
++	if (param == DWC_DGCMDPAR_HOST_ROLE_REQ_INITIATE)
++		type = "INITIATE";
++	else if (param == DWC_DGCMDPAR_HOST_ROLE_REQ_CONFIRM)
++		type = "CONFIRM";
++
++	dwc_debug2(pcd->usb3_dev, "%s() - %s\n", __func__, type);
++#endif
++
++	/* Use the generic Transmit Device Notification command if the core
++	 * supports it
++	 */
++	if (pcd->usb3_dev->snpsid >= 0x5533210a) {
++		/* Set param */
++		dwc_wr32(pcd->usb3_dev, &pcd->dev_global_regs->dgcmdpar,
++			 param << DWC_DGCMDPAR_DEV_NOTIF_PARAM_SHIFT |
++			 DWC_DGCMD_HOST_ROLE_REQ_DEV_NOTIF);
++		dwc_debug1(pcd->usb3_dev, "DGCMDPAR=%08x\n",
++			   param << DWC_DGCMDPAR_DEV_NOTIF_PARAM_SHIFT |
++			   DWC_DGCMD_HOST_ROLE_REQ_DEV_NOTIF);
++
++		/* Start the command */
++		dwc_wr32(pcd->usb3_dev, &pcd->dev_global_regs->dgcmd,
++			 DWC_DGCMD_XMIT_DEV_NOTIF | DWC_DGCMD_ACT_BIT);
++		dwc_debug1(pcd->usb3_dev, "DGCMD=%08x\n",
++			   DWC_DGCMD_XMIT_DEV_NOTIF | DWC_DGCMD_ACT_BIT);
++	} else {
++		/* Set param */
++		dwc_wr32(pcd->usb3_dev, &pcd->dev_global_regs->dgcmdpar, param);
++		dwc_debug1(pcd->usb3_dev, "DGCMDPAR=%08x\n", param);
++
++		/* Start the command */
++		dwc_wr32(pcd->usb3_dev, &pcd->dev_global_regs->dgcmd,
++			 DWC_DGCMD_XMIT_HOST_ROLE_REQUEST | DWC_DGCMD_ACT_BIT);
++
++		dwc_debug1(pcd->usb3_dev, "DGCMD=%08x\n",
++			   DWC_DGCMD_XMIT_HOST_ROLE_REQUEST | DWC_DGCMD_ACT_BIT);
++	}
++
++	/* Wait for command completion */
++	handshake(pcd->usb3_dev, &pcd->dev_global_regs->dgcmd,
++		  DWC_DGCMD_ACT_BIT, 0);
++
++	return 0;
++}
++#endif
++
++/**
++ * Send SET SCRATCHPAD BUFFER ARRAY command to Device
++ */
++int dwc_usb3_set_scratchpad_buf_array(dwc_usb3_pcd_t *pcd, dwc_dma_t dma_addr)
++{
++	dwc_debug2(pcd->usb3_dev, "%s(%lx)\n", __func__,
++		   (unsigned long)dma_addr);
++
++	/* Set param */
++	dwc_wr32(pcd->usb3_dev, &pcd->dev_global_regs->dgcmdpar,
++		 dma_addr & 0xffffffffU);
++	dwc_debug1(pcd->usb3_dev, "DGCMDPAR=%08lx\n",
++		   (unsigned long)(dma_addr & 0xffffffffU));
++
++	/* Start the command */
++	dwc_wr32(pcd->usb3_dev, &pcd->dev_global_regs->dgcmd,
++		 DWC_DGCMD_SET_SCRATCHPAD_ARRAY_ADR_LO | DWC_DGCMD_ACT_BIT);
++	dwc_debug1(pcd->usb3_dev, "DGCMD=%08x\n",
++		   DWC_DGCMD_SET_SCRATCHPAD_ARRAY_ADR_LO | DWC_DGCMD_ACT_BIT);
++
++	/* Wait for command completion */
++	handshake(pcd->usb3_dev, &pcd->dev_global_regs->dgcmd,
++		  DWC_DGCMD_ACT_BIT, 0);
++
++	return 0;
++}
++
++/**
++ * Send SELECTED FIFO FLUSH command to Device
++ */
++int dwc_usb3_flush_fifo(dwc_usb3_pcd_t *pcd, u32 fifo_sel)
++{
++	dwc_debug1(pcd->usb3_dev, "%s()\n", __func__);
++
++	/* Set param */
++	dwc_wr32(pcd->usb3_dev, &pcd->dev_global_regs->dgcmdpar, fifo_sel);
++	dwc_debug1(pcd->usb3_dev, "DGCMDPAR=%08x\n", fifo_sel);
++
++	/* Start the command */
++	dwc_wr32(pcd->usb3_dev, &pcd->dev_global_regs->dgcmd,
++		 DWC_DGCMD_SELECTED_FIFO_FLUSH | DWC_DGCMD_ACT_BIT);
++	dwc_debug1(pcd->usb3_dev, "DGCMD=%08x\n",
++		   DWC_DGCMD_SELECTED_FIFO_FLUSH | DWC_DGCMD_ACT_BIT);
++
++	/* Wait for command completion */
++	handshake(pcd->usb3_dev, &pcd->dev_global_regs->dgcmd,
++		  DWC_DGCMD_ACT_BIT, 0);
++
++	return 0;
++}
++
++/*
++ * Routines for sending the various Endpoint commands to the hardware.
++ * See description of DEPCMDn register in "Control and Status Registers"
++ * section of the USB3 controller databook.
++ */
++
++/**
++ * Send DEPCFG command to EP
++ */
++int dwc_usb3_dep_cfg(dwc_usb3_pcd_t *pcd,
++		     dwc_usb3_dev_ep_regs_t __iomem *ep_reg,
++		     u32 depcfg0, u32 depcfg1, u32 depcfg2)
++{
++	dwc_debug1(pcd->usb3_dev, "dep_cfg, ep_reg=%lx\n",
++		   (unsigned long)ep_reg);
++
++	/* Set param 2 */
++	dwc_wr32(pcd->usb3_dev, &ep_reg->depcmdpar2, depcfg2);
++	dwc_debug1(pcd->usb3_dev, "DEPCFG2=%08x\n", depcfg2);
++
++	/* Set param 1 */
++	dwc_wr32(pcd->usb3_dev, &ep_reg->depcmdpar1, depcfg1);
++	dwc_debug1(pcd->usb3_dev, "DEPCFG1=%08x\n", depcfg1);
++
++	/* Set param 0 */
++	dwc_wr32(pcd->usb3_dev, &ep_reg->depcmdpar0, depcfg0);
++	dwc_debug1(pcd->usb3_dev, "DEPCFG0=%08x\n", depcfg0);
++
++	/* Start the command */
++	dwc_wr32(pcd->usb3_dev, &ep_reg->depcmd,
++		 DWC_EPCMD_SET_EP_CFG | DWC_EPCMD_ACT_BIT);
++	dwc_debug1(pcd->usb3_dev, "DEPCMD=%08x\n",
++		   DWC_EPCMD_SET_EP_CFG | DWC_EPCMD_ACT_BIT);
++
++	/* Wait for command completion */
++	handshake(pcd->usb3_dev, &ep_reg->depcmd, DWC_EPCMD_ACT_BIT, 0);
++
++	return 0;
++}
++
++/**
++ * Send DEPXFERCFG command to EP
++ */
++int dwc_usb3_dep_xfercfg(dwc_usb3_pcd_t *pcd,
++			 dwc_usb3_dev_ep_regs_t __iomem *ep_reg,
++			 u32 depstrmcfg)
++{
++	dwc_debug1(pcd->usb3_dev, "dep_xfercfg, ep_reg=%lx\n",
++		   (unsigned long)ep_reg);
++
++	/* Set param 0 */
++	dwc_wr32(pcd->usb3_dev, &ep_reg->depcmdpar0, depstrmcfg);
++	dwc_debug1(pcd->usb3_dev, "DEPSTRMCFG=%08x\n", depstrmcfg);
++
++	/* Start the command */
++	dwc_wr32(pcd->usb3_dev, &ep_reg->depcmd,
++		 DWC_EPCMD_SET_XFER_CFG | DWC_EPCMD_ACT_BIT);
++	dwc_debug1(pcd->usb3_dev, "DEPCMD=%08x\n",
++		   DWC_EPCMD_SET_XFER_CFG | DWC_EPCMD_ACT_BIT);
++
++	/* Wait for command completion */
++	handshake(pcd->usb3_dev, &ep_reg->depcmd, DWC_EPCMD_ACT_BIT, 0);
++
++	return 0;
++}
++
++/**
++ * Send DEPGETEPSTATE command to EP
++ */
++u32 dwc_usb3_dep_getepstate(dwc_usb3_pcd_t *pcd,
++				 dwc_usb3_dev_ep_regs_t __iomem *ep_reg)
++{
++	u32 retval;
++
++	dwc_debug1(pcd->usb3_dev, "dep_getepstate, ep_reg=%lx\n",
++		   (unsigned long)ep_reg);
++
++	/* Start the command */
++	dwc_wr32(pcd->usb3_dev, &ep_reg->depcmd,
++		 DWC_EPCMD_GET_EP_STATE | DWC_EPCMD_ACT_BIT);
++	dwc_debug1(pcd->usb3_dev, "DEPCMD=%08x\n",
++		   DWC_EPCMD_GET_EP_STATE | DWC_EPCMD_ACT_BIT);
++
++	/* Wait for command completion */
++	handshake(pcd->usb3_dev, &ep_reg->depcmd, DWC_EPCMD_ACT_BIT, 0);
++
++	/* Get state returned in DEPCMDPAR2 */
++	retval = dwc_rd32(pcd->usb3_dev, &ep_reg->depcmdpar2);
++
++	return retval;
++}
++
++/**
++ * Send DEPSSTALL command to EP
++ */
++int dwc_usb3_dep_sstall(dwc_usb3_pcd_t *pcd,
++			dwc_usb3_dev_ep_regs_t __iomem *ep_reg)
++{
++	dwc_debug1(pcd->usb3_dev, "dep_sstall, ep_reg=%lx\n",
++		   (unsigned long)ep_reg);
++
++	/* Start the command */
++	dwc_wr32(pcd->usb3_dev, &ep_reg->depcmd,
++		 DWC_EPCMD_SET_STALL | DWC_EPCMD_ACT_BIT);
++	dwc_debug1(pcd->usb3_dev, "DEPCMD=%08x\n",
++		   DWC_EPCMD_SET_STALL | DWC_EPCMD_ACT_BIT);
++
++	/* Wait for command completion */
++	handshake(pcd->usb3_dev, &ep_reg->depcmd, DWC_EPCMD_ACT_BIT, 0);
++
++	return 0;
++}
++
++/**
++ * Send DEPCSTALL command to EP
++ */
++int dwc_usb3_dep_cstall(dwc_usb3_pcd_t *pcd,
++			dwc_usb3_dev_ep_regs_t __iomem *ep_reg, int clr_pend)
++{
++	u32 depcmd;
++
++	dwc_debug1(pcd->usb3_dev, "dep_cstall, ep_reg=%lx\n",
++		   (unsigned long)ep_reg);
++
++	/* Fill clear stall command */
++	depcmd = DWC_EPCMD_CLR_STALL | DWC_EPCMD_ACT_BIT;
++	if (clr_pend)
++		depcmd |= DWC_EPCMD_HP_FRM_BIT;
++
++	/* Start the command */
++	dwc_wr32(pcd->usb3_dev, &ep_reg->depcmd, depcmd);
++	dwc_debug1(pcd->usb3_dev, "DEPCMD=%08x\n", depcmd);
++
++	/* Wait for command completion */
++	handshake(pcd->usb3_dev, &ep_reg->depcmd, DWC_EPCMD_ACT_BIT, 0);
++
++	return 0;
++}
++
++/**
++ * Send DEPSTRTXFER command to EP
++ */
++int dwc_usb3_dep_startxfer(dwc_usb3_pcd_t *pcd,
++			   dwc_usb3_dev_ep_regs_t __iomem *ep_reg,
++			   dwc_dma_t dma_addr, u32 stream_or_uf)
++{
++	u32 retval;
++
++	dwc_debug1(pcd->usb3_dev, "dep_startxfer, ep_reg=%lx\n",
++		   (unsigned long)ep_reg);
++
++	/* Set param 1 */
++	dwc_wr32(pcd->usb3_dev, &ep_reg->depcmdpar1, dma_addr & 0xffffffffU);
++	dwc_debug1(pcd->usb3_dev, "TDADDRLO=%08lx\n",
++		   (unsigned long)(dma_addr & 0xffffffffU));
++
++	/* Set param 0 */
++#ifdef DWC_64_BIT_ARCH
++	dwc_wr32(pcd->usb3_dev, &ep_reg->depcmdpar0,
++		 dma_addr >> 32U & 0xffffffffU);
++	dwc_debug1(pcd->usb3_dev, "TDADDRHI=%08lx\n",
++		   (unsigned long)(dma_addr >> 32U & 0xffffffffU));
++#else
++	dwc_wr32(pcd->usb3_dev, &ep_reg->depcmdpar0, 0);
++	dwc_debug1(pcd->usb3_dev, "TDADDRHI=%08x\n", 0);
++#endif
++	/* Start the command */
++	dwc_wr32(pcd->usb3_dev, &ep_reg->depcmd,
++		 stream_or_uf << DWC_EPCMD_STR_NUM_OR_UF_SHIFT |
++		 DWC_EPCMD_START_XFER | DWC_EPCMD_ACT_BIT);
++	dwc_debug1(pcd->usb3_dev, "DEPCMD=%08x\n",
++		   stream_or_uf << DWC_EPCMD_STR_NUM_OR_UF_SHIFT |
++		   DWC_EPCMD_START_XFER | DWC_EPCMD_ACT_BIT);
++
++	/* Wait for command completion */
++	handshake(pcd->usb3_dev, &ep_reg->depcmd, DWC_EPCMD_ACT_BIT, 0);
++
++	retval = dwc_rd32(pcd->usb3_dev, &ep_reg->depcmd);
++
++	return retval >> DWC_EPCMD_XFER_RSRC_IDX_SHIFT &
++	       DWC_EPCMD_XFER_RSRC_IDX_BITS >> DWC_EPCMD_XFER_RSRC_IDX_SHIFT;
++}
++
++/**
++ * Send DEPUPDTXFER command to EP
++ */
++int dwc_usb3_dep_updatexfer(dwc_usb3_pcd_t *pcd,
++			    dwc_usb3_dev_ep_regs_t __iomem *ep_reg,
++			    u32 tri)
++{
++	dwc_debug1(pcd->usb3_dev, "dep_updxfer, ep_reg=%lx\n",
++		   (unsigned long)ep_reg);
++
++	/* Start the command */
++	dwc_wr32(pcd->usb3_dev, &ep_reg->depcmd,
++		 tri << DWC_EPCMD_XFER_RSRC_IDX_SHIFT |
++		 DWC_EPCMD_UPDATE_XFER | DWC_EPCMD_ACT_BIT);
++	dwc_debug1(pcd->usb3_dev, "DEPCMD=%08x\n",
++		   tri << DWC_EPCMD_XFER_RSRC_IDX_SHIFT |
++		   DWC_EPCMD_UPDATE_XFER | DWC_EPCMD_ACT_BIT);
++
++	/* Wait for command completion */
++	handshake(pcd->usb3_dev, &ep_reg->depcmd, DWC_EPCMD_ACT_BIT, 0);
++
++	return 0;
++}
++
++/**
++ * Send DEPENDXFER command to EP
++ */
++int dwc_usb3_dep_endxfer(dwc_usb3_pcd_t *pcd,
++			 dwc_usb3_dev_ep_regs_t __iomem *ep_reg,
++			 u32 tri, int flags, void *condition)
++{
++	u32 depcmd;
++
++	dwc_debug1(pcd->usb3_dev, "dep_endxfer, ep_reg=%lx\n",
++		   (unsigned long)ep_reg);
++
++	/* Fill end transfer command */
++	depcmd = tri << DWC_EPCMD_XFER_RSRC_IDX_SHIFT | DWC_EPCMD_END_XFER;
++	depcmd |= DWC_EPCMD_ACT_BIT;
++	if (flags & DWC_ENDXFER_FORCE)
++		depcmd |= DWC_EPCMD_HP_FRM_BIT;
++
++	/* Start the command. */
++	dwc_wr32(pcd->usb3_dev, &ep_reg->depcmd, depcmd);
++	dwc_debug1(pcd->usb3_dev, "DEPCMD=%08x\n", depcmd);
++
++	/* Wait for command completion */
++	handshake(pcd->usb3_dev, &ep_reg->depcmd, DWC_EPCMD_ACT_BIT, 0);
++	if (!(flags & DWC_ENDXFER_NODELAY))
++		dwc_udelay(dev, 100);
++
++	return 0;
++}
++
++#ifdef DWC_STAR_9000463548_WORKAROUND
++int dwc_usb3_dep_endxfer_nowait(dwc_usb3_pcd_t *pcd,
++				dwc_usb3_dev_ep_regs_t __iomem *ep_reg,
++				u32 tri, int flags)
++{
++	u32 depcmd;
++
++	dwc_debug1(pcd->usb3_dev, "dep_endxfer_nowait, ep_reg=%lx\n",
++		   (unsigned long)ep_reg);
++
++	/* Fill end transfer command */
++	depcmd = tri << DWC_EPCMD_XFER_RSRC_IDX_SHIFT | DWC_EPCMD_END_XFER;
++	depcmd |= DWC_EPCMD_ACT_BIT;
++	if (flags & DWC_ENDXFER_FORCE)
++		depcmd |= DWC_EPCMD_HP_FRM_BIT;
++
++	/* Start the command. */
++	dwc_wr32(pcd->usb3_dev, &ep_reg->depcmd, depcmd);
++	dwc_debug1(pcd->usb3_dev, "DEPCMD=%08x\n", depcmd);
++
++	return 0;
++}
++
++int dwc_usb3_dep_wait_endxfer(dwc_usb3_pcd_t *pcd,
++			      dwc_usb3_dev_ep_regs_t __iomem *ep_reg,
++			      void *condition)
++{
++	/* Wait for command completion */
++	handshake(pcd->usb3_dev, &ep_reg->depcmd, DWC_EPCMD_ACT_BIT, 0);
++	dwc_udelay(dev, 100);
++
++	return 0;
++}
++#endif
++
++/**
++ * Send DEPSTRTNEWCFG command to EP
++ */
++int dwc_usb3_dep_startnewcfg(dwc_usb3_pcd_t *pcd,
++			     dwc_usb3_dev_ep_regs_t __iomem *ep_reg,
++			     u32 rsrcidx)
++{
++	dwc_debug1(pcd->usb3_dev, "dep_startnewcfg, ep_reg=%lx\n",
++		   (unsigned long)ep_reg);
++
++	/* Start the command */
++	dwc_wr32(pcd->usb3_dev, &ep_reg->depcmd,
++		 rsrcidx << DWC_EPCMD_XFER_RSRC_IDX_SHIFT |
++		 DWC_EPCMD_START_NEW_CFG | DWC_EPCMD_ACT_BIT);
++	dwc_debug1(pcd->usb3_dev, "DEPCMD=%08x\n",
++		   rsrcidx << DWC_EPCMD_XFER_RSRC_IDX_SHIFT |
++		   DWC_EPCMD_START_NEW_CFG | DWC_EPCMD_ACT_BIT);
++
++	/* Wait for command completion */
++	handshake(pcd->usb3_dev, &ep_reg->depcmd, DWC_EPCMD_ACT_BIT, 0);
++
++	return 0;
++}
++
++/**********************/
++
++/**
++ * Enable an EP in the DALEPENA register.
++ *
++ * @param pcd   Programming view of DWC_usb3 peripheral controller.
++ * @param ep    The EP to enable.
++ * @return      0 if succesful, -DWC_E_BUSY if already enabled.
++ */
++int dwc_usb3_enable_ep(dwc_usb3_pcd_t *pcd, dwc_usb3_pcd_ep_t *ep)
++{
++	u32 ep_index_num, dalepena;
++
++	ep_index_num = ep->dwc_ep.num * 2;
++
++	if (ep->dwc_ep.is_in)
++		ep_index_num += 1;
++
++	dalepena = dwc_rd32(pcd->usb3_dev, &pcd->dev_global_regs->dalepena);
++
++	/* If we have already enabled this EP, leave it alone
++	 * (shouldn't happen)
++	 */
++	if (dalepena & 1 << ep_index_num)
++		return -DWC_E_BUSY;
++
++	dalepena |= 1 << ep_index_num;
++	dwc_wr32(pcd->usb3_dev, &pcd->dev_global_regs->dalepena, dalepena);
++	dwc_debug1(pcd->usb3_dev, "enable_ep: DALEPENA=%08x\n", dalepena);
++	return 0;
++}
++
++/**
++ * Disable an EP in the DALEPENA register.
++ *
++ * @param pcd   Programming view of DWC_usb3 peripheral controller.
++ * @param ep    The EP to disable.
++ * @return      0 if succesful, -DWC_E_INVALID if already disabled.
++ */
++int dwc_usb3_disable_ep(dwc_usb3_pcd_t *pcd, dwc_usb3_pcd_ep_t *ep)
++{
++	u32 ep_index_num, dalepena;
++
++	ep_index_num = ep->dwc_ep.num * 2;
++
++	if (ep->dwc_ep.is_in)
++		ep_index_num += 1;
++
++	dalepena = dwc_rd32(pcd->usb3_dev, &pcd->dev_global_regs->dalepena);
++
++	/* If we have already disabled this EP, leave it alone
++	 * (shouldn't happen)
++	 */
++	if (!(dalepena & 1 << ep_index_num))
++		return -DWC_E_INVALID;
++
++	dalepena &= ~(1 << ep_index_num);
++	dwc_wr32(pcd->usb3_dev, &pcd->dev_global_regs->dalepena, dalepena);
++	dwc_debug1(pcd->usb3_dev, "disable_ep: DALEPENA=%08x\n", dalepena);
++	return 0;
++}
++
++/**
++ * Get the device speed from the device status register and convert it
++ * to USB speed constant.
++ *
++ * @param pcd   Programming view of DWC_usb3 peripheral controller.
++ * @return      The device speed.
++ */
++int dwc_usb3_get_device_speed(dwc_usb3_pcd_t *pcd)
++{
++	u32 dsts;
++	int speed = USB_SPEED_UNKNOWN;
++
++	dsts = dwc_rd32(pcd->usb3_dev, &pcd->dev_global_regs->dsts);
++
++	switch (dsts >> DWC_DSTS_CONNSPD_SHIFT &
++		DWC_DSTS_CONNSPD_BITS >> DWC_DSTS_CONNSPD_SHIFT) {
++	case DWC_SPEED_HS_PHY_30MHZ_OR_60MHZ:
++		dwc_debug0(pcd->usb3_dev, "HIGH SPEED\n");
++		speed = USB_SPEED_HIGH;
++		break;
++
++	case DWC_SPEED_FS_PHY_30MHZ_OR_60MHZ:
++	case DWC_SPEED_FS_PHY_48MHZ:
++		dwc_debug0(pcd->usb3_dev, "FULL SPEED\n");
++		speed = USB_SPEED_FULL;
++		break;
++
++	case DWC_SPEED_LS_PHY_6MHZ:
++		dwc_debug0(pcd->usb3_dev, "LOW SPEED\n");
++		speed = USB_SPEED_LOW;
++		break;
++
++	case DWC_SPEED_SS_PHY_125MHZ_OR_250MHZ:
++		dwc_debug0(pcd->usb3_dev, "SUPER SPEED\n");
++		speed = USB_SPEED_SUPER;
++		break;
++	}
++
++	return speed;
++}
++
++/**
++ * Get the current microframe number.
++ *
++ * @param pcd   Programming view of DWC_usb3 peripheral controller.
++ * @return      The current microframe number.
++ */
++int dwc_usb3_get_frame(dwc_usb3_pcd_t *pcd)
++{
++	u32 dsts;
++
++	/* read current frame/microframe number from DSTS register */
++	dsts = dwc_rd32(pcd->usb3_dev, &pcd->dev_global_regs->dsts);
++
++	return dsts >> DWC_DSTS_SOF_FN_SHIFT &
++	       DWC_DSTS_SOF_FN_BITS >> DWC_DSTS_SOF_FN_SHIFT;
++}
++
++/**
++ * Get the current link state.
++ *
++ * @param pcd   Programming view of DWC_usb3 peripheral controller.
++ * @return      The current link state.
++ */
++int dwc_usb3_pcd_get_link_state(dwc_usb3_pcd_t *pcd)
++{
++	u32 status, state;
++
++	status = dwc_rd32(pcd->usb3_dev, &pcd->dev_global_regs->dsts);
++	state = status >> DWC_DSTS_USBLNK_STATE_SHIFT &
++		DWC_DSTS_USBLNK_STATE_BITS >> DWC_DSTS_USBLNK_STATE_SHIFT;
++	dwc_debug2(pcd->usb3_dev, "status=0x%08x state=%d\n", status, state);
++
++	return state;
++}
++
++/**
++ * Set state of USB link.
++ *
++ * @param pcd   Programming view of DWC_usb3 peripheral controller.
++ * @param state Link state to set.
++ */
++void dwc_usb3_pcd_set_link_state(dwc_usb3_pcd_t *pcd, int state)
++{
++	u32 dctl;
++
++	dctl = dwc_rd32(pcd->usb3_dev, &pcd->dev_global_regs->dctl);
++	dctl &= ~DWC_DCTL_ULST_CHNG_REQ_BITS;
++	dwc_wr32(pcd->usb3_dev, &pcd->dev_global_regs->dctl, dctl);
++
++	dctl = dwc_rd32(pcd->usb3_dev, &pcd->dev_global_regs->dctl);
++	dctl &= ~DWC_DCTL_ULST_CHNG_REQ_BITS;
++	dctl |= state << DWC_DCTL_ULST_CHNG_REQ_SHIFT;
++	dwc_wr32(pcd->usb3_dev, &pcd->dev_global_regs->dctl, dctl);
++}
++
++/**
++ * Send a Remote Wakeup to the host.
++ *
++ * @param pcd           Programming view of DWC_usb3 peripheral controller.
++ * @param function      Function that caused the remote wakeup.
++ */
++void dwc_usb3_pcd_remote_wake(dwc_usb3_pcd_t *pcd, int function)
++{
++	/* For USB 3.0, send function remote wake notification */
++	if (pcd->speed == USB_SPEED_SUPER)
++		dwc_usb3_xmit_fn_remote_wake(pcd, function);
++}
++
++/**
++ * Set the Device Address.
++ *
++ * @param pcd   Programming view of DWC_usb3 peripheral controller.
++ * @param addr  The address to set.
++ */
++void dwc_usb3_set_address(dwc_usb3_pcd_t *pcd, int addr)
++{
++	u32 dcfg;
++
++	dcfg = dwc_rd32(pcd->usb3_dev, &pcd->dev_global_regs->dcfg);
++	dcfg &= ~DWC_DCFG_DEVADDR_BITS;
++	dcfg |= addr << DWC_DCFG_DEVADDR_SHIFT;
++	dwc_wr32(pcd->usb3_dev, &pcd->dev_global_regs->dcfg, dcfg);
++}
++
++/**
++ * Enable USB2 Phy suspend.
++ *
++ * @param pcd   Programming view of DWC_usb3 peripheral controller.
++ */
++static void dwc_usb3_ena_usb2_phy_suspend(dwc_usb3_pcd_t *pcd)
++{
++	dwc_usb3_device_t *dev = pcd->usb3_dev;
++	int hiber = dev->core_params->hibernate &&
++		    (dev->hwparams1 & DWC_HWP1_EN_PWROPT_BITS) ==
++		    DWC_EN_PWROPT_HIBERNATION << DWC_HWP1_EN_PWROPT_SHIFT;
++	int writeit = 0;
++	u32 usb2phycfg;
++
++	if (dev->core_params->phyctl || hiber || dev->core_params->lpmctl) {
++		usb2phycfg = dwc_rd32(dev,
++				&dev->core_global_regs->gusb2phycfg[0]);
++
++		if ((dev->core_params->phyctl || hiber) &&
++		    !(usb2phycfg & DWC_USB2PHYCFG_SUS_PHY_BIT)) {
++			usb2phycfg |= DWC_USB2PHYCFG_SUS_PHY_BIT;
++			writeit = 1;
++		}
++
++		if (dev->core_params->lpmctl &&
++		    !(usb2phycfg & DWC_USB2PHYCFG_ENBL_SLP_M_BIT)) {
++			usb2phycfg |= DWC_USB2PHYCFG_ENBL_SLP_M_BIT;
++			writeit = 1;
++		}
++
++		if (writeit)
++			dwc_wr32(dev, &dev->core_global_regs->gusb2phycfg[0],
++				 usb2phycfg);
++	}
++}
++
++/**
++ * Disable USB2 Phy suspend.
++ *
++ * @param pcd   Programming view of DWC_usb3 peripheral controller.
++ */
++static void dwc_usb3_dis_usb2_phy_suspend(dwc_usb3_pcd_t *pcd)
++{
++	u32 usb2phycfg;
++
++	usb2phycfg = dwc_rd32(pcd->usb3_dev,
++			      &pcd->usb3_dev->core_global_regs->gusb2phycfg[0]);
++
++	if (usb2phycfg & (DWC_USB2PHYCFG_SUS_PHY_BIT |
++			  DWC_USB2PHYCFG_ENBL_SLP_M_BIT)) {
++		usb2phycfg &= ~DWC_USB2PHYCFG_SUS_PHY_BIT;
++		usb2phycfg &= ~DWC_USB2PHYCFG_ENBL_SLP_M_BIT;
++		dwc_wr32(pcd->usb3_dev,
++			 &pcd->usb3_dev->core_global_regs->gusb2phycfg[0],
++			 usb2phycfg);
++	}
++}
++
++/**
++ * Enable USB3 Phy suspend.
++ *
++ * @param pcd   Programming view of DWC_usb3 peripheral controller.
++ */
++static void dwc_usb3_ena_usb3_phy_suspend(dwc_usb3_pcd_t *pcd)
++{
++#ifndef SELA_PLATFORM
++	u32 pipectl;
++
++	pipectl = dwc_rd32(pcd->usb3_dev,
++			   &pcd->usb3_dev->core_global_regs->gusb3pipectl[0]);
++	if (!(pipectl & DWC_PIPECTL_SUS_PHY_BIT)) {
++		pipectl |= DWC_PIPECTL_SUS_PHY_BIT;
++		dwc_wr32(pcd->usb3_dev,
++			 &pcd->usb3_dev->core_global_regs->gusb3pipectl[0],
++			 pipectl);
++	}
++#endif
++}
++
++/**
++ * Disable USB3 Phy suspend.
++ *
++ * @param pcd   Programming view of DWC_usb3 peripheral controller.
++ */
++static void dwc_usb3_dis_usb3_phy_suspend(dwc_usb3_pcd_t *pcd)
++{
++#ifndef SELA_PLATFORM
++	u32 pipectl;
++
++	pipectl = dwc_rd32(pcd->usb3_dev,
++			   &pcd->usb3_dev->core_global_regs->gusb3pipectl[0]);
++	if (pipectl & DWC_PIPECTL_SUS_PHY_BIT) {
++		pipectl &= ~DWC_PIPECTL_SUS_PHY_BIT;
++		dwc_wr32(pcd->usb3_dev,
++			 &pcd->usb3_dev->core_global_regs->gusb3pipectl[0],
++			 pipectl);
++	}
++#endif
++}
++
++/**
++ * Enable USB2 Phy suspend if the device is connected at HS or FS.
++ *
++ * @param pcd   Programming view of DWC_usb3 peripheral controller.
++ */
++void dwc_usb3_ena_usb2_suspend(dwc_usb3_pcd_t *pcd)
++{
++	if (pcd->speed == USB_SPEED_SUPER)
++		return;
++
++	dwc_usb3_ena_usb2_phy_suspend(pcd);
++}
++
++/**
++ * Disable USB2 Phy suspend if the device is connected at HS or FS.
++ *
++ * @param pcd   Programming view of DWC_usb3 peripheral controller.
++ */
++void dwc_usb3_dis_usb2_suspend(dwc_usb3_pcd_t *pcd)
++{
++	if (pcd->speed == USB_SPEED_SUPER)
++		return;
++
++	dwc_usb3_dis_usb2_phy_suspend(pcd);
++}
++
++/**
++ * Enable the Device to accept U1 control commands from the Host.
++ *
++ * @param pcd   Programming view of DWC_usb3 peripheral controller.
++ */
++void dwc_usb3_accept_u1(dwc_usb3_pcd_t *pcd)
++{
++	u32 dctl;
++
++	dctl = dwc_rd32(pcd->usb3_dev, &pcd->dev_global_regs->dctl);
++	dctl |= DWC_DCTL_ACCEPT_U1_EN_BIT;
++	dwc_wr32(pcd->usb3_dev, &pcd->dev_global_regs->dctl, dctl);
++}
++
++/**
++ * Enable the Device to accept U2 control commands from the Host.
++ *
++ * @param pcd   Programming view of DWC_usb3 peripheral controller.
++ */
++void dwc_usb3_accept_u2(dwc_usb3_pcd_t *pcd)
++{
++#if 0
++	u32 dctl;
++
++	dctl = dwc_rd32(pcd->usb3_dev, &pcd->dev_global_regs->dctl);
++	dctl |= DWC_DCTL_ACCEPT_U2_EN_BIT;
++	dwc_wr32(pcd->usb3_dev, &pcd->dev_global_regs->dctl, dctl);
++#endif
++}
++
++/**
++ * Enable U1 sleep.
++ *
++ * @param pcd   Programming view of DWC_usb3 peripheral controller.
++ */
++void dwc_usb3_enable_u1(dwc_usb3_pcd_t *pcd)
++{
++	u32 dctl;
++
++	dctl = dwc_rd32(pcd->usb3_dev, &pcd->dev_global_regs->dctl);
++	dctl |= DWC_DCTL_INIT_U1_EN_BIT;
++	dwc_wr32(pcd->usb3_dev, &pcd->dev_global_regs->dctl, dctl);
++}
++
++/**
++ * Enable U2 sleep.
++ *
++ * @param pcd   Programming view of DWC_usb3 peripheral controller.
++ */
++void dwc_usb3_enable_u2(dwc_usb3_pcd_t *pcd)
++{
++}
++
++/**
++ * Disable U1 sleep.
++ *
++ * @param pcd   Programming view of DWC_usb3 peripheral controller.
++ */
++void dwc_usb3_disable_u1(dwc_usb3_pcd_t *pcd)
++{
++}
++
++/**
++ * Disable U2 sleep.
++ *
++ * @param pcd   Programming view of DWC_usb3 peripheral controller.
++ */
++void dwc_usb3_disable_u2(dwc_usb3_pcd_t *pcd)
++{
++	u32 dctl;
++
++	dctl = dwc_rd32(pcd->usb3_dev, &pcd->dev_global_regs->dctl);
++	dctl &= ~DWC_DCTL_INIT_U2_EN_BIT;
++	dwc_wr32(pcd->usb3_dev, &pcd->dev_global_regs->dctl, dctl);
++}
++
++/**
++ * Test whether U1 sleep is enabled.
++ *
++ * @param pcd   Programming view of DWC_usb3 peripheral controller.
++ * @return      1 if enabled, 0 if not.
++ */
++int dwc_usb3_u1_enabled(dwc_usb3_pcd_t *pcd)
++{
++	u32 dctl;
++
++	dctl = dwc_rd32(pcd->usb3_dev, &pcd->dev_global_regs->dctl);
++	return !!(dctl & DWC_DCTL_INIT_U1_EN_BIT);
++}
++
++/**
++ * Test whether U2 sleep is enabled.
++ *
++ * @param pcd   Programming view of DWC_usb3 peripheral controller.
++ * @return      1 if enabled, 0 if not.
++ */
++int dwc_usb3_u2_enabled(dwc_usb3_pcd_t *pcd)
++{
++	u32 dctl;
++
++	dctl = dwc_rd32(pcd->usb3_dev, &pcd->dev_global_regs->dctl);
++	return !!(dctl & DWC_DCTL_INIT_U2_EN_BIT);
++}
++
++/**
++ * Clear 'eps_enabled' flag and 'ena_once' flags for all EPs, so EPs will get
++ * completely reconfigured by SetConfig and SetInterface.
++ */
++void dwc_usb3_clr_eps_enabled(dwc_usb3_pcd_t *pcd)
++{
++	dwc_usb3_pcd_ep_t *ep;
++	int i;
++
++	pcd->eps_enabled = 0;
++
++	for (i = 0; i < pcd->num_in_eps; i++) {
++		ep = pcd->in_ep[i];
++		if (ep)
++			ep->dwc_ep.ena_once = 0;
++	}
++
++	for (i = 0; i < pcd->num_out_eps; i++) {
++		ep = pcd->out_ep[i];
++		if (ep)
++			ep->dwc_ep.ena_once = 0;
++	}
++}
++
++/**
++ * This routine is called when the SET_FEATURE TEST_MODE Setup packet
++ * is sent from the host. The Device Control register is written with
++ * the Test Mode bits set to the specified Test Mode. This is done as
++ * a tasklet so that the "Status" phase of the control transfer
++ * completes before transmitting the TEST packets.
++ */
++void dwc_usb3_pcd_do_test_mode(unsigned long data)
++{
++	dwc_usb3_pcd_t *pcd = (dwc_usb3_pcd_t *)data;
++	int test_mode = pcd->test_mode;
++	u32 dctl;
++
++#ifdef CONFIG_USB_OTG_DWC
++	struct usb_phy *phy;
++	struct usb_otg *otg;
++#endif
++
++	dctl = dwc_rd32(pcd->usb3_dev, &pcd->dev_global_regs->dctl);
++	dctl &= ~DWC_DCTL_TSTCTL_BITS;
++
++	switch (test_mode) {
++	case 1: // TEST_J
++		dctl |= 1 << DWC_DCTL_TSTCTL_SHIFT;
++		break;
++
++	case 2: // TEST_K
++		dctl |= 2 << DWC_DCTL_TSTCTL_SHIFT;
++		break;
++
++	case 3: // TEST_SE0_NAK
++		dctl |= 3 << DWC_DCTL_TSTCTL_SHIFT;
++		break;
++
++	case 4: // TEST_PACKET
++		dctl |= 4 << DWC_DCTL_TSTCTL_SHIFT;
++		break;
++
++	case 5: // TEST_FORCE_ENABLE
++		dctl |= 5 << DWC_DCTL_TSTCTL_SHIFT;
++		break;
++
++#ifdef CONFIG_USB_OTG_DWC
++	case 6: // otg_srp_reqd
++		dwc_error0(pcd->usb3_dev, "otg_srp_reqd\n");
++		phy = usb_get_phy(USB_PHY_TYPE_USB3);
++		if (IS_ERR(phy))
++			break;
++		if (!phy) {
++			usb_put_phy(phy);
++			break;
++		}
++		otg = phy->otg;
++		if (!otg) {
++			usb_put_phy(phy);
++			break;
++		}
++		otg_start_srp(otg);
++		usb_put_phy(phy);
++		return;
++
++	case 7: // otg_hnp_reqd
++		dwc_error0(pcd->usb3_dev, "otg_hnp_reqd\n");
++		phy = usb_get_phy(USB_PHY_TYPE_USB3);
++		if (IS_ERR(phy))
++			break;
++		if (!phy) {
++			usb_put_phy(phy);
++			break;
++		}
++		otg = phy->otg;
++		if (!otg) {
++			usb_put_phy(phy);
++			break;
++		}
++		otg_start_hnp(otg);
++		usb_put_phy(phy);
++		return;
++#endif
++	}
++
++	dwc_wr32(pcd->usb3_dev, &pcd->dev_global_regs->dctl, dctl);
++}
++
++/**
++ * This routine calculates the number of IN EPs (excluding EP0)
++ * using GHWPARAMS3 register values
++ *
++ * @param dev   Programming view of DWC_usb3 controller.
++ */
++static int calc_num_in_eps(dwc_usb3_device_t *dev)
++{
++	u32 num_in_eps = dev->hwparams3 >> DWC_HWP3_NUM_IN_EPS_SHIFT &
++		DWC_HWP3_NUM_IN_EPS_BITS >> DWC_HWP3_NUM_IN_EPS_SHIFT;
++
++	return num_in_eps - 1;
++}
++
++/**
++ * This routine calculates the number of OUT EPs (excluding EP0)
++ * using GHWPARAMS3 register values
++ *
++ * @param dev   Programming view of DWC_usb3 controller.
++ */
++static int calc_num_out_eps(dwc_usb3_device_t *dev)
++{
++	u32 num_eps = dev->hwparams3 >> DWC_HWP3_NUM_EPS_SHIFT &
++		DWC_HWP3_NUM_EPS_BITS >> DWC_HWP3_NUM_EPS_SHIFT;
++	u32 num_in_eps = dev->hwparams3 >> DWC_HWP3_NUM_IN_EPS_SHIFT &
++		DWC_HWP3_NUM_IN_EPS_BITS >> DWC_HWP3_NUM_IN_EPS_SHIFT;
++
++	return num_eps - num_in_eps - 1;
++}
++
++/**
++ * This routine is called to initialize the DWC_usb3 CSR data structures. The
++ * register addresses in the device structures are initialized from the
++ * <strong><em>base</em></strong> address supplied by the caller. The calling
++ * routine must make the OS calls to get the base address of the DWC_usb3
++ * controller registers. The <strong><em>core_params</em></strong> argument
++ * holds the parameters that specify how the core should be configured.
++ *
++ * @param dev           Programming view of DWC_usb3 controller.
++ * @param base          Base address of DWC_usb3 core registers.
++ * @param core_params   Pointer to the core configuration parameters.
++ */
++int dwc_usb3_pcd_common_init(dwc_usb3_device_t *dev, volatile u8 __iomem *base,
++			     dwc_usb3_core_params_t *core_params)
++{
++	dwc_usb3_pcd_t *pcd;
++	u32 temp;
++
++	dwc_debug3(dev, "%s(%lx,%lx)\n", __func__, (unsigned long)base,
++		   (unsigned long)core_params);
++
++	dev->core_params = core_params;
++	dev->core_global_regs = (dwc_usb3_core_global_regs_t __iomem *)
++					(base + DWC_CORE_GLOBAL_REG_OFFSET);
++
++#ifdef COSIM
++	/* scramble-off, scaledown */
++	dwc_wr32(dev, &dev->core_global_regs->gctl, 0x38);
++#endif
++
++	pcd = &dev->pcd;
++
++	pcd->dev_global_regs = (dwc_usb3_dev_global_regs_t __iomem *)
++					(base + DWC_DEV_GLOBAL_REG_OFFSET);
++	pcd->in_ep_regs = (dwc_usb3_dev_ep_regs_t __iomem *)
++					(base + DWC_DEV_IN_EP_REG_OFFSET);
++	pcd->out_ep_regs = (dwc_usb3_dev_ep_regs_t __iomem *)
++					(base + DWC_DEV_OUT_EP_REG_OFFSET);
++
++#ifdef SSIC
++	dev->ssic_regs = (dwc_usb3_ssic_regs_t __iomem *)
++					(base + DWC_SSIC_REG_OFFSET);
++#endif
++
++	/*
++	 * Store the contents of the hardware configuration registers here for
++	 * easy access later.
++	 */
++	dev->hwparams0 = dwc_rd32(dev, &dev->core_global_regs->ghwparams0);
++	dev->hwparams1 = dwc_rd32(dev, &dev->core_global_regs->ghwparams1);
++	dev->hwparams2 = dwc_rd32(dev, &dev->core_global_regs->ghwparams2);
++	dev->hwparams3 = dwc_rd32(dev, &dev->core_global_regs->ghwparams3);
++	dev->hwparams4 = dwc_rd32(dev, &dev->core_global_regs->ghwparams4);
++	dev->hwparams5 = dwc_rd32(dev, &dev->core_global_regs->ghwparams5);
++	dev->hwparams6 = dwc_rd32(dev, &dev->core_global_regs->ghwparams6);
++	dev->hwparams7 = dwc_rd32(dev, &dev->core_global_regs->ghwparams7);
++	dev->hwparams8 = dwc_rd32(dev, &dev->core_global_regs->ghwparams8);
++
++	temp = dwc_rd32(dev, &pcd->dev_global_regs->dcfg);
++	dwc_debug1(dev, "dcfg=%08x\n", temp);
++
++#ifndef SELA_PLATFORM
++	dwc_debug1(dev, "mode=%0x\n",
++		   dev->hwparams0 >> DWC_HWP0_MODE_SHIFT &
++		   DWC_HWP0_MODE_BITS >> DWC_HWP0_MODE_SHIFT);
++	dwc_debug1(dev, "num_ep=%d\n",
++		   dev->hwparams3 >> DWC_HWP3_NUM_EPS_SHIFT &
++		   DWC_HWP3_NUM_EPS_BITS >> DWC_HWP3_NUM_EPS_SHIFT);
++	dwc_debug1(dev, "num_in_ep=%d\n",
++		   dev->hwparams3 >> DWC_HWP3_NUM_IN_EPS_SHIFT &
++		   DWC_HWP3_NUM_IN_EPS_BITS >> DWC_HWP3_NUM_IN_EPS_SHIFT);
++	dwc_debug1(dev, "dfq_fifo_depth=%d\n",
++	       dev->hwparams5 >> DWC_HWP5_DFQ_FIFO_DEPTH_SHIFT &
++	       DWC_HWP5_DFQ_FIFO_DEPTH_BITS >> DWC_HWP5_DFQ_FIFO_DEPTH_SHIFT);
++	dwc_debug1(dev, "dwq_fifo_depth=%d\n",
++	       dev->hwparams5 >> DWC_HWP5_DWQ_FIFO_DEPTH_SHIFT &
++	       DWC_HWP5_DWQ_FIFO_DEPTH_BITS >> DWC_HWP5_DWQ_FIFO_DEPTH_SHIFT);
++	dwc_debug1(dev, "txq_fifo_depth=%d\n",
++	       dev->hwparams5 >> DWC_HWP5_TXQ_FIFO_DEPTH_SHIFT &
++	       DWC_HWP5_TXQ_FIFO_DEPTH_BITS >> DWC_HWP5_TXQ_FIFO_DEPTH_SHIFT);
++	dwc_debug1(dev, "rxq_fifo_depth=%d\n",
++	       dev->hwparams5 >> DWC_HWP5_RXQ_FIFO_DEPTH_SHIFT &
++	       DWC_HWP5_RXQ_FIFO_DEPTH_BITS >> DWC_HWP5_RXQ_FIFO_DEPTH_SHIFT);
++#endif
++
++	/* Initialize parameters from Hardware configuration registers. */
++	dev->pcd.num_in_eps = calc_num_in_eps(dev);
++	dev->pcd.num_in_eps = 4;
++	printk("\n###%s,%d,dev->pcd.num_in_eps=0x%x\n",__func__,__LINE__,dev->pcd.num_in_eps);
++	if (dev->pcd.num_in_eps > 15) {
++		dwc_debug1(dev, "Number of IN endpoints (%d) too large\n",
++			   dev->pcd.num_in_eps);
++		return -DWC_E_INVALID;
++	}
++
++	dev->pcd.num_out_eps = calc_num_out_eps(dev);
++	dev->pcd.num_out_eps = 2;
++	printk("\n###%s,%d,dev->pcd.num_out_eps=0x%x\n",__func__,__LINE__,dev->pcd.num_out_eps);
++	if (dev->pcd.num_out_eps > 15) {
++		dwc_debug1(dev, "Number of OUT endpoints (%d) too large\n",
++			   dev->pcd.num_out_eps);
++		return -DWC_E_INVALID;
++	}
++
++#ifdef SELA_PLATFORM
++	/* Limit the number of EPs to speed up simulation */
++	if (dev->pcd.num_in_eps > dev->pcd.max_in_eps)
++		dev->pcd.num_in_eps = dev->pcd.max_in_eps;
++	if (dev->pcd.num_out_eps > dev->pcd.max_out_eps)
++		dev->pcd.num_out_eps = dev->pcd.max_out_eps;
++#endif
++
++	return 0;
++}
++
++/**
++ * This routine frees any allocations made by dwc_usb3_pcd_common_init().
++ *
++ * @param dev   Programming view of DWC_usb3 controller.
++ */
++void dwc_usb3_pcd_common_remove(dwc_usb3_device_t *dev)
++{
++}
++
++/**
++ * This routine ensures the device is really a DWC_usb3 controller, by reading
++ * and verifying the SNPSID register contents. The value should be 0x5533XXXX,
++ * which corresponds to "U3", as in "USB3 version X.XXX".
++ *
++ * The SNPSID value is also saved in <em>dev->snpsid</em> for later use in
++ * determining if any version-specific operations need to be performed.
++ *
++ * This routine should be called before any other initialization routines, to
++ * ensure that the <em>dev->snpsid</em> value is set in case any of the other
++ * routines need it.
++ *
++ * @param dev           Programming view of DWC_usb3 controller.
++ * @param addr_ofs      Offset to the Device registers in the CSR space. It is
++ *                      needed because this routine is called early, before the
++ *                      normal register access routines are functional.
++ * @return              0 if the SNPSID value is valid, -DWC_E_INVALID if not.
++ */
++int dwc_usb3_pcd_check_snpsid(dwc_usb3_device_t *dev, u32 addr_ofs)
++{
++	dev->snpsid = dwc_rd32(dev, (volatile u32 __iomem *)
++					(dev->base + addr_ofs + 0x120));
++	if ((dev->snpsid & 0xffff0000) != 0x55330000) {
++		dwc_error1(dev, "bad value for SNPSID: 0x%08x!\n", dev->snpsid);
++		return -DWC_E_INVALID;
++	}
++
++	return 0;
++}
++
++/**
++ * This routine dumps the core's internal debug registers
++ *
++ * @param dev   Programming view of DWC_usb3 controller.
++ */
++void dwc_usb3_dump_dbgregs(dwc_usb3_device_t *dev)
++{
++	u32 rd_data, rd_data2;
++	unsigned int i, num_eps;
++
++	/* Dump the 11 LSP debug registers */
++	for (i = 0; i < 11; i++) {
++		dwc_wr32(dev, &dev->core_global_regs->gdbglspmux, i << 4);
++		rd_data = dwc_rd32(dev, &dev->core_global_regs->gdbglsp);
++		dwc_info2(dev, "lsp%d: %08x\n", i, rd_data);
++	}
++
++	/* Dump the EP debug registers */
++	num_eps = dev->hwparams3 >> DWC_HWP3_NUM_EPS_SHIFT &
++		  DWC_HWP3_NUM_EPS_BITS >> DWC_HWP3_NUM_EPS_SHIFT;
++	for (i = 0; i < num_eps; i++) {
++		dwc_wr32(dev, &dev->core_global_regs->gdbglspmux, i);
++		rd_data = dwc_rd32(dev, &dev->core_global_regs->gdbgepinfo0);
++		rd_data2 = dwc_rd32(dev, &dev->core_global_regs->gdbgepinfo1);
++		dwc_info3(dev, " ep%d: %08x %08x\n", i, rd_data, rd_data2);
++	}
++
++	/* Dump the BMU debug register */
++	rd_data = dwc_rd32(dev, &dev->core_global_regs->gdbgbmu);
++	dwc_info1(dev, "bmu: %08x\n", rd_data);
++}
++
++/**
++ * This routine reads the core global registers and prints them
++ *
++ * @param dev   Programming view of DWC_usb3 controller.
++ */
++void dwc_usb3_dump_global_registers(dwc_usb3_device_t *dev)
++{
++	volatile u32 __iomem *addr;
++
++	dwc_print0(dev, "Core Global Registers\n");
++	addr = &dev->core_global_regs->gsbuscfg0;
++	dwc_print2(dev, "GSBUSCFG0	@0x%08lx : 0x%08x\n",
++		   (unsigned long)addr, dwc_rd32(dev, addr));
++	addr = &dev->core_global_regs->gsbuscfg1;
++	dwc_print2(dev, "GSBUSCFG1	@0x%08lx : 0x%08x\n",
++		   (unsigned long)addr, dwc_rd32(dev, addr));
++	addr = &dev->core_global_regs->gusb2phycfg[0];
++	dwc_print2(dev, "USB2PHYCFG0	@0x%08lx : 0x%08x\n",
++		   (unsigned long)addr, dwc_rd32(dev, addr));
++	addr = &dev->core_global_regs->gevten;
++	dwc_print2(dev, "GEVTEN		@0x%08lx : 0x%08x\n",
++		   (unsigned long)addr, dwc_rd32(dev, addr));
++	addr = &dev->core_global_regs->grxfifosiz[0];
++	dwc_print2(dev, "GRXFIFOSIZ0	@0x%08lx : 0x%08x\n",
++		   (unsigned long)addr, dwc_rd32(dev, addr));
++	addr = &dev->core_global_regs->gtxfifosiz[0];
++	dwc_print2(dev, "GTXFIFOSIZ0	@0x%08lx : 0x%08x\n",
++		   (unsigned long)addr, dwc_rd32(dev, addr));
++	addr = &dev->core_global_regs->gtxfifosiz[1];
++	dwc_print2(dev, "GTXFIFOSIZ1	@0x%08lx : 0x%08x\n",
++		   (unsigned long)addr, dwc_rd32(dev, addr));
++	addr = &dev->core_global_regs->gtxfifosiz[2];
++	dwc_print2(dev, "GTXFIFOSIZ2	@0x%08lx : 0x%08x\n",
++		   (unsigned long)addr, dwc_rd32(dev, addr));
++	addr = &dev->core_global_regs->gtxfifosiz[3];
++	dwc_print2(dev, "GTXFIFOSIZ3	@0x%08lx : 0x%08x\n",
++		   (unsigned long)addr, dwc_rd32(dev, addr));
++	addr = &dev->core_global_regs->gusb2i2cctl[0];
++	dwc_print2(dev, "GUSB2I2CCTL0	@0x%08lx : 0x%08x\n",
++		   (unsigned long)addr, dwc_rd32(dev, addr));
++	addr = &dev->core_global_regs->ggpio;
++	dwc_print2(dev, "GGPIO		@0x%08lx : 0x%08x\n",
++		   (unsigned long)addr, dwc_rd32(dev, addr));
++	addr = &dev->core_global_regs->guid;
++	dwc_print2(dev, "GUID		@0x%08lx : 0x%08x\n",
++		   (unsigned long)addr, dwc_rd32(dev, addr));
++	addr = &dev->core_global_regs->gsnpsid;
++	dwc_print2(dev, "GSNPSID		@0x%08lx : 0x%08x\n",
++		   (unsigned long)addr, dwc_rd32(dev, addr));
++}
++
++/**
++ * This routine reads the device registers and prints them
++ *
++ * @param pcd   Programming view of DWC_usb3 peripheral controller.
++ */
++void dwc_usb3_dump_dev_registers(dwc_usb3_pcd_t *pcd)
++{
++	volatile u32 __iomem *addr;
++
++	dwc_print0(pcd->usb3_dev, "Device Global Registers\n");
++	addr = &pcd->dev_global_regs->dcfg;
++	dwc_print2(pcd->usb3_dev, "DCFG		@0x%08lx : 0x%08x\n",
++		   (unsigned long)addr, dwc_rd32(pcd->usb3_dev, addr));
++	addr = &pcd->dev_global_regs->dctl;
++	dwc_print2(pcd->usb3_dev, "DCTL		@0x%08lx : 0x%08x\n",
++		   (unsigned long)addr, dwc_rd32(pcd->usb3_dev, addr));
++	addr = &pcd->dev_global_regs->dsts;
++	dwc_print2(pcd->usb3_dev, "DSTS		@0x%08lx : 0x%08x\n",
++		   (unsigned long)addr, dwc_rd32(pcd->usb3_dev, addr));
++}
++
++/**
++ * Set the size of the Tx FIFOs
++ *
++ * NOTE: The following code for setting the FIFO sizes only
++ * works for cores configured with the 3 RAM option. Setting
++ * FIFO sizes for the 2 RAM option is not implemented.
++ *
++ * @param dev   Programming view of DWC_usb3 controller.
++ * @param sz    New sizes for the FIFOs.
++ */
++void dwc_usb3_set_tx_fifo_size(dwc_usb3_device_t *dev, int *sz)
++{
++	dwc_usb3_core_global_regs_t __iomem *global_regs =
++						dev->core_global_regs;
++	int i, ram_width, ram_depth, size, prev_start, txsz[DWC_MAX_TX_FIFOS];
++
++	ram_width = (dev->hwparams0 >> DWC_HWP0_MDWIDTH_SHIFT &
++		     DWC_HWP0_MDWIDTH_BITS >> DWC_HWP0_MDWIDTH_SHIFT)
++		    / 8;
++	ram_depth = (dev->hwparams7 >> DWC_HWP7_RAM1_DEPTH_SHIFT &
++		     DWC_HWP7_RAM1_DEPTH_BITS >> DWC_HWP7_RAM1_DEPTH_SHIFT)
++		    * ram_width;
++	size = dwc_rd32(dev, &global_regs->gtxfifosiz[0]);
++	prev_start = size >> DWC_FIFOSZ_STARTADDR_SHIFT &
++		DWC_FIFOSZ_STARTADDR_BITS >> DWC_FIFOSZ_STARTADDR_SHIFT;
++
++	for (i = 0; i < dev->pcd.num_in_eps + 1; i++) {
++		size = sz[i];
++
++		if (i == 0 && size && size < 512 + 2 * ram_width) {
++			dwc_print1(dev, "Requested Tx FIFO %d size too small\n",
++				   i);
++			dwc_print0(dev, "Not setting Tx FIFO sizes\n");
++			goto txerr;
++		}
++
++		if (!size) {
++			/* Default to 512 for EP0, 1K for others */
++			size = i ? 1024 : 512;
++			size += 2 * ram_width;
++		}
++
++		size = (size + ram_width - 1) & ~(ram_width - 1);
++		dwc_debug3(dev,
++			   "Tx FIFO %d size = %d bytes out of %d available\n",
++			   i, size, ram_depth);
++		if (size > ram_depth) {
++			dwc_print1(dev, "Requested Tx FIFO %d size too large\n",
++				   i);
++			dwc_print0(dev, "Not setting Tx FIFO sizes\n");
++			goto txerr;
++		}
++
++		txsz[i] = size;
++		ram_depth -= size;
++	}
++
++	for (i = 0; i < dev->pcd.num_in_eps + 1; i++) {
++		size = txsz[i];
++		dwc_debug2(dev, "Setting GTXFIFOSIZ%d = 0x%08x\n", i,
++			   (size / ram_width) << DWC_FIFOSZ_DEPTH_SHIFT |
++			   prev_start << DWC_FIFOSZ_STARTADDR_SHIFT);
++		dwc_wr32(dev, &global_regs->gtxfifosiz[i],
++			 (size / ram_width) << DWC_FIFOSZ_DEPTH_SHIFT |
++			 prev_start << DWC_FIFOSZ_STARTADDR_SHIFT);
++		dwc_debug2(dev, "GTXFIFOSIZ%d = 0x%08x\n", i,
++			   dwc_rd32(dev, &global_regs->gtxfifosiz[i]));
++		prev_start += size / ram_width;
++	}
++txerr:
++	return;
++}
++
++/**
++ * Set the size of the Rx FIFO
++ *
++ * NOTE: The following code for setting the FIFO sizes only
++ * works for cores configured with the 3 RAM option. Setting
++ * FIFO sizes for the 2 RAM option is not implemented.
++ *
++ * @param dev   Programming view of DWC_usb3 controller.
++ * @param size  New size for the FIFO.
++ */
++void dwc_usb3_set_rx_fifo_size(dwc_usb3_device_t *dev, int size)
++{
++	dwc_usb3_core_global_regs_t __iomem *global_regs =
++						dev->core_global_regs;
++	u32 sz, rxthrcfg;
++	int ram_width, ram_depth, prev_start, cnt, bst;
++
++	ram_width = (dev->hwparams0 >> DWC_HWP0_MDWIDTH_SHIFT &
++		     DWC_HWP0_MDWIDTH_BITS >> DWC_HWP0_MDWIDTH_SHIFT)
++		    / 8;
++	ram_depth = (dev->hwparams7 >> DWC_HWP7_RAM2_DEPTH_SHIFT &
++		     DWC_HWP7_RAM2_DEPTH_BITS >> DWC_HWP7_RAM2_DEPTH_SHIFT)
++		    * ram_width;
++	sz = dwc_rd32(dev, &global_regs->grxfifosiz[0]);
++	prev_start = sz >> DWC_FIFOSZ_STARTADDR_SHIFT &
++		     DWC_FIFOSZ_STARTADDR_BITS >> DWC_FIFOSZ_STARTADDR_SHIFT;
++
++	if (size < 512 + 24 + 16 + (ram_width == 16 ? 24 : 0)) {
++		dwc_print0(dev, "Requested Rx FIFO size too small\n");
++		dwc_print0(dev, "Not setting Rx FIFO size\n");
++		goto rxerr;
++	}
++
++	size = (size + ram_width - 1) & ~(ram_width - 1);
++	if (size > ram_depth) {
++		dwc_print0(dev, "Requested Rx FIFO size too large\n");
++		dwc_print0(dev, "Not setting Rx FIFO size\n");
++		goto rxerr;
++	}
++
++	dwc_debug1(dev, "Setting GRXFIFOSIZ0 = 0x%08x\n",
++		   (size / ram_width) << DWC_FIFOSZ_DEPTH_SHIFT |
++		   prev_start << DWC_FIFOSZ_STARTADDR_SHIFT);
++	dwc_wr32(dev, &global_regs->grxfifosiz[0],
++		 (size / ram_width) << DWC_FIFOSZ_DEPTH_SHIFT |
++		 prev_start << DWC_FIFOSZ_STARTADDR_SHIFT);
++	dwc_debug1(dev, "GRXFIFOSIZ0 = 0x%08x\n",
++		   dwc_rd32(dev, &global_regs->grxfifosiz[0]));
++	dwc_debug2(dev, "Rx FIFO size = %d bytes out of %d available\n",
++		   size, ram_depth);
++
++	/*
++	 * If thresholding is enabled in GRXTHRCFG, update USBRxPktCnt according
++	 * to the new FIFO size
++	 */
++	rxthrcfg = dwc_rd32(dev, &global_regs->grxthrcfg);
++	dwc_debug1(dev, "GRXTHRCFG = 0x%08x\n", rxthrcfg);
++	if (rxthrcfg & DWC_RXTHRCTL_USB_RX_PKT_CNT_EN_BIT) {
++		cnt = (size - ram_width * 4) / 1024;
++		if (cnt > 0) {
++			if (cnt > DWC_RXTHRCTL_USB_RX_PKT_CNT_BITS >>
++					DWC_RXTHRCTL_USB_RX_PKT_CNT_SHIFT)
++				cnt = DWC_RXTHRCTL_USB_RX_PKT_CNT_BITS >>
++					DWC_RXTHRCTL_USB_RX_PKT_CNT_SHIFT;
++			bst = rxthrcfg >>
++				DWC_RXTHRCTL_USB_MAX_RX_BURST_SIZE_SHIFT &
++			     DWC_RXTHRCTL_USB_MAX_RX_BURST_SIZE_BITS >>
++				DWC_RXTHRCTL_USB_MAX_RX_BURST_SIZE_SHIFT;
++			if (cnt > bst)
++				cnt = bst;
++			if (cnt < 1)
++				goto disable;
++			rxthrcfg &= ~DWC_RXTHRCTL_USB_RX_PKT_CNT_BITS;
++			rxthrcfg |= cnt << DWC_RXTHRCTL_USB_RX_PKT_CNT_SHIFT;
++		} else {
++disable:
++			rxthrcfg &= ~DWC_RXTHRCTL_USB_RX_PKT_CNT_EN_BIT;
++		}
++		dwc_debug1(dev, "Setting GRXTHRCFG = 0x%08x\n", rxthrcfg);
++		dwc_wr32(dev, &global_regs->grxthrcfg, rxthrcfg);
++	}
++rxerr:
++	return;
++}
++
++/**
++ * This routine initializes the DWC_usb3 controller registers.
++ *
++ * If the <strong><em>soft_reset</em></strong> parameter is
++ * <strong>true</strong>, then this routine must be called in a context that
++ * allows <em>dwc_msleep()</em> to be used, because that function is called
++ * while waiting for the core to come out of reset.
++ *
++ * This routine is called by dwc_usb3_pcd_init() when the driver is loaded,
++ * so it normally does not need to be called separately, except in special
++ * circumstances, such as when exiting from hibernation.
++ *
++ * @param dev           Programming view of DWC_usb3 controller.
++ * @param soft_reset    True if doing a soft reset of the core.
++ * @param restore       True if restoring register state after hibernation.
++ */
++void dwc_usb3_pcd_device_init(dwc_usb3_device_t *dev, int soft_reset,
++			      int restore)
++{
++	dwc_usb3_core_global_regs_t __iomem *global_regs =
++						dev->core_global_regs;
++	dwc_usb3_pcd_t *pcd = &dev->pcd;
++	u32 temp;
++	int i, ram_width, ram_depth, size;
++
++	dwc_debug1(dev, "%s()\n", __func__);
++
++	if (dev->program_gsbuscfg) {
++		dwc_debug2(dev, "Programming SBUSCFG0,1 to %08x %08x\n",
++			   dev->gsbuscfg0, dev->gsbuscfg1);
++		dwc_wr32(dev, &global_regs->gsbuscfg0, dev->gsbuscfg0);
++		dwc_wr32(dev, &global_regs->gsbuscfg1, dev->gsbuscfg1);
++	}
++
++	if (dev->soft_reset_hook) {
++		dev->soft_reset_hook(dev, soft_reset, restore);
++	} else {
++		/*
++		 * TODO Workaround: PCD can't handle soft reset during HNP.
++		 * RTL issue will be fixed. Skip the reset when called with
++		 * soft_reset=0. When not configured for OTG do the reset
++		 * unconditionally.
++		 */
++		if (soft_reset) {
++			/* Soft-reset the core */
++			temp = dwc_rd32(dev, &pcd->dev_global_regs->dctl);
++			temp &= ~DWC_DCTL_RUN_STOP_BIT;
++			temp |= DWC_DCTL_CSFT_RST_BIT;
++			dwc_wr32(dev, &pcd->dev_global_regs->dctl, temp);
++
++			/* Wait for core to come out of reset */
++			do {
++				dwc_msleep(dev, 1);
++				temp = dwc_rd32(dev, &pcd->dev_global_regs->dctl);
++			} while (temp & DWC_DCTL_CSFT_RST_BIT);
++
++			/* Wait for at least 3 PHY clocks */
++			dwc_msleep(dev, 1);
++		}
++	}
++
++	/* Soft reset clears the GSBUSCFG registers, so write them again */
++	if (dev->program_gsbuscfg) {
++		dwc_debug2(dev, "Programming SBUSCFG0,1 to %08x %08x\n",
++			   dev->gsbuscfg0, dev->gsbuscfg1);
++		dwc_wr32(dev, &global_regs->gsbuscfg0, dev->gsbuscfg0);
++		dwc_wr32(dev, &global_regs->gsbuscfg1, dev->gsbuscfg1);
++	}
++
++	pcd->link_state = 0;
++	pcd->wkup_rdy = 0;
++
++	if (dev->phy_config_hook) {
++		dev->phy_config_hook(dev, soft_reset, restore);
++	}
++
++	if (dev->fifo_sizing_hook) {
++		dev->fifo_sizing_hook(dev, soft_reset, restore);
++	} else {
++		/*
++		 * Set Tx FIFO sizes
++		 */
++		ram_width = (dev->hwparams0 >> DWC_HWP0_MDWIDTH_SHIFT &
++			     DWC_HWP0_MDWIDTH_BITS >> DWC_HWP0_MDWIDTH_SHIFT)
++			/ 8;
++		ram_depth = (dev->hwparams7 >> DWC_HWP7_RAM1_DEPTH_SHIFT &
++			     DWC_HWP7_RAM1_DEPTH_BITS >> DWC_HWP7_RAM1_DEPTH_SHIFT)
++			* ram_width;
++		dwc_debug2(dev, "RAM width:%d RAM1 depth:%d\n", ram_width, ram_depth);
++
++		for (i = 0; i < pcd->num_in_eps + 1; i++) {
++			size = dwc_rd32(dev, &global_regs->gtxfifosiz[i]);
++			dwc_debug2(dev, "Initial GTXFIFOSIZ%d = 0x%08x\n", i, size);
++		}
++
++		/* Only set if non-default Tx FIFO sizes were requested */
++		if (dev->core_params->txfsz_cnt)
++			dwc_usb3_set_tx_fifo_size(dev, dev->core_params->txfsz);
++
++		/*
++		 * Set Rx FIFO size
++		 */
++		ram_depth = (dev->hwparams7 >> DWC_HWP7_RAM2_DEPTH_SHIFT &
++			     DWC_HWP7_RAM2_DEPTH_BITS >> DWC_HWP7_RAM2_DEPTH_SHIFT)
++			* ram_width;
++		dwc_debug1(dev, "RAM2 depth:%d\n", ram_depth);
++		size = dwc_rd32(dev, &global_regs->grxfifosiz[0]);
++		dwc_debug1(dev, "Initial GRXFIFOSIZ0 = 0x%08x\n", size);
++		size = dev->core_params->rxfsz;
++
++		/* Only set if non-default Rx FIFO size was requested */
++		if (size)
++			dwc_usb3_set_rx_fifo_size(dev, size);
++	}
++
++#if 1
++	if (dev->gctl_init_hook) {
++		dev->gctl_init_hook(dev, soft_reset, restore);
++	} else {
++		temp = dwc_rd32(dev, &global_regs->gctl);
++		temp &= ~(DWC_GCTL_PRT_CAP_DIR_BITS | DWC_GCTL_SCALE_DOWN_BITS);
++
++#ifdef DWC_STAR_9000468158_WORKAROUND
++		temp |= DWC_GCTL_U2RSTECN_BIT;
++#endif
++#ifdef CONFIG_USB_OTG_DWC
++		temp |= DWC_GCTL_PRT_CAP_OTG << DWC_GCTL_PRT_CAP_DIR_SHIFT;
++#else
++		temp |= DWC_GCTL_PRT_CAP_DEVICE << DWC_GCTL_PRT_CAP_DIR_SHIFT;
++#endif
++#ifdef COSIM
++		/* Scale down, disable scrambling */
++		temp |= 3 << DWC_GCTL_SCALE_DOWN_SHIFT | DWC_GCTL_DIS_SCRAMBLE_BIT;
++#else
++# if 1
++		temp &= ~DWC_GCTL_PWR_DN_SCALE_BITS;
++
++		switch (dev->core_params->phy) {
++		case 3:		// 16-bit UTMI+ SNPS Phy
++		case 2:		// 8-bit UTMI+ / ULPI TI or SNPS Phy
++			/* Set power down scale */
++			temp |= 0x270 << DWC_GCTL_PWR_DN_SCALE_SHIFT;
++			break;
++		case 1:		// old 8-bit UTMI+ SNPS Phy
++			/* Set LFPS filter */
++			dwc_wr32(dev, &global_regs->gusb3pipectl[0],
++				 DWC_PIPECTL_LFPS_FILTER_BIT |
++				 1 << DWC_PIPECTL_TX_DEMPH_SHIFT);
++
++			/* Set power down scale */
++			temp |= 0x270 << DWC_GCTL_PWR_DN_SCALE_SHIFT;
++			break;
++		default:	// RocketIO Phy
++			/* Set power down scale, disable scrambling */
++			temp |= 0x1e84 << DWC_GCTL_PWR_DN_SCALE_SHIFT |
++				DWC_GCTL_DEBUG_ATTACH_BIT |
++				DWC_GCTL_DIS_SCRAMBLE_BIT;
++		}
++# endif
++#endif
++		dwc_wr32(dev, &global_regs->gctl, temp);
++	}
++#endif
++	/* Initialize the Event Buffer registers */
++	dwc_usb3_init_eventbuf(dev, 0, dev->event_buf[0], DWC_EVENT_BUF_SIZE,
++			       dev->event_buf_dma[0]);
++	dev->event_ptr[0] = dev->event_buf[0];
++
++#ifdef CONFIG_USB_OTG_DWC
++	/* TODO Workaround: this is a workaround for OTG 3.0 where the utmi
++	 * clock doesn't come unless the device speed is momentarily programmed
++	 * to HS. This causes the peripheral state on OSTS to not get set
++	 * properly.
++	 */
++	temp = dwc_rd32(dev, &pcd->dev_global_regs->dcfg);
++	temp &= ~(DWC_DCFG_DEVSPD_BITS << DWC_DCFG_DEVSPD_SHIFT);
++	temp |= DWC_SPEED_HS_PHY_30MHZ_OR_60MHZ	<< DWC_DCFG_DEVSPD_SHIFT;
++	dwc_wr32(dev, &pcd->dev_global_regs->dcfg, temp);
++	dwc_udelay(dev, 200);
++#endif
++
++	/* If forcing to a USB2 mode was requested */
++	if (dev->core_params->usb2mode == 1) {
++		/* Set speed to Full */
++		temp = dwc_rd32(dev, &pcd->dev_global_regs->dcfg);
++		temp &= ~(DWC_DCFG_DEVSPD_BITS << DWC_DCFG_DEVSPD_SHIFT);
++		temp |= DWC_SPEED_FS_PHY_30MHZ_OR_60MHZ
++						<< DWC_DCFG_DEVSPD_SHIFT;
++		dwc_wr32(dev, &pcd->dev_global_regs->dcfg, temp);
++
++	} else if ((dev->core_params->usb2mode == 2)
++#ifdef CONFIG_USB_OTG_DWC
++		 /* Check the OTG_SS bit when in OTG mode to see if superspeed
++		  * is supported
++		  */
++		|| !(dev->hwparams6 & DWC_HWP6_EN_OTG_BIT)
++#endif
++	) {
++		/* Set speed to High */
++		temp = dwc_rd32(dev, &pcd->dev_global_regs->dcfg);
++		temp &= ~(DWC_DCFG_DEVSPD_BITS << DWC_DCFG_DEVSPD_SHIFT);
++		temp |= DWC_SPEED_HS_PHY_30MHZ_OR_60MHZ
++						<< DWC_DCFG_DEVSPD_SHIFT;
++		dwc_wr32(dev, &pcd->dev_global_regs->dcfg, temp);
++
++	} else {
++		/* Set speed to Super */
++		temp = dwc_rd32(dev, &pcd->dev_global_regs->dcfg);
++		temp &= ~(DWC_DCFG_DEVSPD_BITS << DWC_DCFG_DEVSPD_SHIFT);
++
++		if ((dev->hwparams3 & DWC_HWP3_SSPHY_IFC_BITS) == 0)
++			temp |= DWC_SPEED_HS_PHY_30MHZ_OR_60MHZ
++						<< DWC_DCFG_DEVSPD_SHIFT;
++		else
++			temp |= DWC_SPEED_SS_PHY_125MHZ_OR_250MHZ
++						<< DWC_DCFG_DEVSPD_SHIFT;
++		dwc_wr32(dev, &pcd->dev_global_regs->dcfg, temp);
++	}
++
++	/* If LPM enable was requested */
++	if (dev->core_params->lpmctl) {
++		/* Set LPMCap bit */
++		temp = dwc_rd32(dev, &pcd->dev_global_regs->dcfg);
++		temp |= DWC_DCFG_LPM_CAP_BIT;
++		dwc_wr32(dev, &pcd->dev_global_regs->dcfg, temp);
++
++		if (dev->core_params->lpmctl > 1) {
++			/* Set AppL1Res bit */
++			temp = dwc_rd32(dev, &pcd->dev_global_regs->dctl);
++			temp |= DWC_DCTL_APP_L1_RES_BIT;
++			dwc_wr32(dev, &pcd->dev_global_regs->dctl, temp);
++		}
++	}
++
++	/* If non-default NUMP was requested */
++	if (dev->core_params->nump > 0 && dev->core_params->nump <= 16) {
++		/* Set NUMP */
++		temp = dwc_rd32(dev, &pcd->dev_global_regs->dcfg);
++		temp &= ~DWC_DCFG_NUM_RCV_BUF_BITS;
++		temp |= dev->core_params->nump << DWC_DCFG_NUM_RCV_BUF_SHIFT;
++		dwc_wr32(dev, &pcd->dev_global_regs->dcfg, temp);
++	}
++
++	if (dev->set_address_hook) {
++		dev->set_address_hook(dev, soft_reset, restore);
++	} else {
++		if (!restore)
++			/* Set device address to 0 */
++			dwc_usb3_set_address(pcd, 0);
++	}
++
++	/* Enable hibernation if supported */
++	if (dev->core_params->hibernate &&
++	    (dev->hwparams1 & DWC_HWP1_EN_PWROPT_BITS) ==
++	    DWC_EN_PWROPT_HIBERNATION << DWC_HWP1_EN_PWROPT_SHIFT) {
++		/* Enable global hibernation bit */
++		temp = dwc_rd32(dev, &global_regs->gctl);
++		temp |= DWC_GCTL_GBL_HIBER_EN_BIT;
++		if (dev->core_params->clkgatingen)
++			temp &= ~DWC_GCTL_DSBL_CLCK_GTNG_BIT;
++		else
++			temp |= DWC_GCTL_DSBL_CLCK_GTNG_BIT;
++		dwc_wr32(dev, &global_regs->gctl, temp);
++
++		if (dev->core_params->lpmctl) {
++			/* Set L1 hibernation values */
++			temp = dwc_rd32(dev, &pcd->dev_global_regs->dctl);
++			temp &= ~DWC_DCTL_HIRD_THR_BITS;
++			if (dev->hird_thresh)
++				temp |= dev->hird_thresh << DWC_DCTL_HIRD_THR_SHIFT &
++					DWC_DCTL_HIRD_THR_BITS;
++			else
++				temp |= 0x1c << DWC_DCTL_HIRD_THR_SHIFT;
++
++			/* Enable L1 hibernation */
++			temp |= DWC_DCTL_L1_HIBER_EN_BIT;
++			dwc_wr32(dev, &pcd->dev_global_regs->dctl, temp);
++		}
++
++		if (!restore) {
++			/* Issue Set Scratchpad Buffer Array command */
++			dwc_usb3_set_scratchpad_buf_array(pcd,
++					pcd->hiber_scratchpad_array_dma);
++		}
++
++		/* Set GUSB2PHYCFG[6] (suspend 2.0 phy) */
++		temp = dwc_rd32(dev, &global_regs->gusb2phycfg[0]);
++		temp |= DWC_USB2PHYCFG_SUS_PHY_BIT;
++		if (dev->core_params->lpmctl)
++			temp |= DWC_USB2PHYCFG_ENBL_SLP_M_BIT;
++		dwc_wr32(dev, &global_regs->gusb2phycfg[0], temp);
++
++#ifndef SELA_PLATFORM
++		/* Set GUSB3PIPECTL[17] (suspend SS phy) */
++		temp = dwc_rd32(dev, &global_regs->gusb3pipectl[0]);
++		temp |= DWC_PIPECTL_SUS_PHY_BIT;
++		dwc_wr32(dev, &global_regs->gusb3pipectl[0], temp);
++#endif
++	} else {
++		if (dev->core_params->phyctl) {
++			/* Enable Phy suspend */
++			dwc_usb3_ena_usb3_phy_suspend(pcd);
++			dwc_usb3_ena_usb2_phy_suspend(pcd);
++		} else {
++			/* Disable Phy suspend */
++			dwc_usb3_dis_usb3_phy_suspend(pcd);
++			dwc_usb3_dis_usb2_phy_suspend(pcd);
++		}
++	}
++
++#ifndef CONFIG_USB_OTG_DWC
++	/* Enable Global and Device interrupts */
++	dwc_usb3_enable_device_interrupts(dev);
++#endif
++	/* Activate EP0 */
++	dwc_usb3_ep0_activate(pcd, restore);
++
++	if (dev->ep0_start_hook) {
++		dev->ep0_start_hook(dev, soft_reset, restore);
++	} else {
++		/* Start EP0 to receive SETUP packets */
++		dwc_usb3_pcd_ep0_out_start(pcd);
++	}
++
++	/* Enable EP0-OUT/IN in DALEPENA register */
++	dwc_wr32(dev, &pcd->dev_global_regs->dalepena, 3);
++
++	pcd->eps_enabled = 0;
++
++#ifndef CONFIG_USB_OTG_DWC
++	/* Set Run/Stop bit, and Keep-Connect bit if hibernation enabled */
++	temp = dwc_rd32(dev, &pcd->dev_global_regs->dctl);
++	temp |= DWC_DCTL_RUN_STOP_BIT;
++	if (dev->core_params->hibernate &&
++	    (dev->hwparams1 & DWC_HWP1_EN_PWROPT_BITS) ==
++	    DWC_EN_PWROPT_HIBERNATION << DWC_HWP1_EN_PWROPT_SHIFT)
++		temp |= DWC_DCTL_KEEP_CONNECT_BIT;
++	dwc_wr32(dev, &pcd->dev_global_regs->dctl, temp);
++#endif
++
++#ifdef SSIC
++	dwc_debug(dev, "SSIC Initialization\n");
++	temp = dwc_rd32(dev, &dev->core_global_regs->gusb3pipectl[0]);
++	temp |= DWC_PIPECTL_SSIC_EN_BIT;
++	temp |= DWC_PIPECTL_PHY_SOFT_RST_BIT;
++	dwc_wr32(dev, &dev->core_global_regs->gusb3pipectl[0], temp);
++	dwc_wr32(dev, &dev->ssic_regs->sctl[0], 0);
++	dwc_wr32(dev, &dev->ssic_regs->sevt[0], 0xffffffff);
++	dwc_wr32(dev, &dev->ssic_regs->sevten[0], 0);
++	dwc_wr32(dev, &dev->ssic_regs->sevten[0],
++		 DWC_SEVTEN_ROM_INIT_CMPLT_EN_BIT | DWC_SEVTEN_MPHY_ST_CHNGD_EN_BIT);
++
++	temp = dwc_rd32(dev, &dev->core_global_regs->gusb3rmmictl[0]);
++	temp &= ~(DWC_RMMICTL_AUTO_EXIT_RRAP_BIT | DWC_RMMICTL_AUTO_ROM_RRAP_BIT |
++		DWC_RMMICTL_AUTO_EXIT_H8_BIT | DWC_RMMICTL_AUTO_ROM_H8_BIT);
++	dwc_wr32(dev, &dev->core_global_regs->gusb3rmmictl[0], temp);
++
++	temp = dwc_rd32(dev, &dev->core_global_regs->gusb3pipectl[0]);
++	temp &= ~DWC_PIPECTL_PHY_SOFT_RST_BIT;
++	dwc_wr32(dev, &dev->core_global_regs->gusb3pipectl[0], temp);
++
++	if (!handshake(dev, &dev->core_global_regs->gusb3rmmictl[0],
++			DWC_RMMICTL_MPHY_STATE_BITS,
++			(DWC_MPHY_STATE_HIBERN8 << DWC_RMMICTL_MPHY_STATE_SHIFT))) {
++		dwc_error(dev, "%s: wait for mphy state hibern8 timed out\n", __func__);
++	}
++
++	temp = dwc_rd32(dev, &dev->ssic_regs->sevten[0]);
++	temp |= (DWC_SEVTEN_RCMD_RES_SENT_EN_BIT |
++		DWC_SEVTEN_RCMD_RES_RCVD_EN_BIT |
++		DWC_SEVTEN_LACC_CMPLT_EN_BIT);
++	dwc_wr32(dev, &dev->ssic_regs->sevten[0], temp);
++
++	temp = dwc_rd32(dev, &dev->ssic_regs->sctl[0]);
++	temp |= DWC_SCTL_CFG_DONE_BIT;
++	dwc_wr32(dev, &dev->ssic_regs->sctl[0], temp);
++
++	if (!handshake(dev, &dev->ssic_regs->sctl[0],
++			DWC_SCTL_CFG_DONE_BIT, 0)) {
++		dwc_error(dev, "%s: cfg done timed out\n", __func__);
++	}
++#endif
++}
++
++/**
++ * This routine deinitializes the DWC_usb3 controller registers.
++ *
++ * This routine is called by dwc_usb3_pcd_remove() when the driver is unloaded,
++ * so it normally does not need to be called separately,
++ *
++ * @param dev   Programming view of DWC_usb3 controller.
++ */
++void dwc_usb3_pcd_device_remove(dwc_usb3_device_t *dev)
++{
++	dwc_usb3_core_global_regs_t __iomem *global_regs =
++						dev->core_global_regs;
++	dwc_usb3_pcd_t *pcd = &dev->pcd;
++	u32 temp;
++
++	if (dev->hibernate >= DWC_HIBER_SLEEPING)
++		return;
++
++	/* Clear the Run/Stop and Keep-Connect bits */
++	temp = dwc_rd32(dev, &pcd->dev_global_regs->dctl);
++	temp &= ~(DWC_DCTL_RUN_STOP_BIT | DWC_DCTL_KEEP_CONNECT_BIT);
++	dwc_wr32(dev, &pcd->dev_global_regs->dctl, temp);
++
++	/* Disable device interrupts */
++	dwc_wr32(dev, &pcd->dev_global_regs->devten, 0);
++
++	/* Disable hibernation if supported */
++	if (dev->core_params->hibernate &&
++	    (dev->hwparams1 & DWC_HWP1_EN_PWROPT_BITS) ==
++	    DWC_EN_PWROPT_HIBERNATION << DWC_HWP1_EN_PWROPT_SHIFT) {
++		/* Clear GUSB3PIPECTL[17] (suspend SS phy) */
++		temp = dwc_rd32(dev, &global_regs->gusb3pipectl[0]);
++		temp &= ~DWC_PIPECTL_SUS_PHY_BIT;
++		dwc_wr32(dev, &global_regs->gusb3pipectl[0], temp);
++
++		/* Clear GUSB2PHYCFG[6] (suspend 2.0 phy) */
++		temp = dwc_rd32(dev, &global_regs->gusb2phycfg[0]);
++		temp &= ~DWC_USB2PHYCFG_SUS_PHY_BIT;
++		temp &= ~DWC_USB2PHYCFG_ENBL_SLP_M_BIT;
++		dwc_wr32(dev, &global_regs->gusb2phycfg[0], temp);
++
++		/* Disable L1 hibernation */
++		temp = dwc_rd32(dev, &pcd->dev_global_regs->dctl);
++		temp &= ~DWC_DCTL_L1_HIBER_EN_BIT;
++		dwc_wr32(dev, &pcd->dev_global_regs->dctl, temp);
++
++		/* Disable global hibernation bit */
++		temp = dwc_rd32(dev, &global_regs->gctl);
++		temp &= ~DWC_GCTL_GBL_HIBER_EN_BIT;
++		temp |= DWC_GCTL_DSBL_CLCK_GTNG_BIT;
++		dwc_wr32(dev, &global_regs->gctl, temp);
++	}
++}
+diff --git a/drivers/usb/gadget/udc/hiudc3/cil.h b/drivers/usb/gadget/udc/hiudc3/cil.h
+new file mode 100644
+index 0000000..1799e2a
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc3/cil.h
+@@ -0,0 +1,211 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/DWC_usb3/driver/cil.h $
++ * $Revision: #45 $
++ * $Date: 2014/11/11 $
++ * $Change: 2664766 $
++ *
++ * Synopsys SS USB3 Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
++ * ========================================================================== */
++
++#ifndef _DWC_CIL_H_
++#define _DWC_CIL_H_
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/**
++ * @file
++ * This file contains the interface to the Core Interface Layer.
++ */
++
++/** @addtogroup init_api_grp Initialization API Routines
++ *
++ * These routines handle initialization of the CIL and PCD driver components
++ * and the DWC_usb3 controller.
++ */
++/** @{ */
++extern int dwc_usb3_pcd_check_snpsid(dwc_usb3_device_t *dev, u32 addr_ofs);
++extern int dwc_usb3_pcd_common_init(dwc_usb3_device_t *dev,
++				    volatile u8 __iomem *base,
++				    dwc_usb3_core_params_t *core_params);
++extern void dwc_usb3_pcd_common_remove(dwc_usb3_device_t *dev);
++extern void dwc_usb3_pcd_device_init(dwc_usb3_device_t *dev, int soft_reset,
++				     int restore);
++extern void dwc_usb3_pcd_device_remove(dwc_usb3_device_t *dev);
++/** @} */
++
++/** @addtogroup misc_api_grp */
++/** @{ */
++extern int dwc_usb3_pcd_get_link_state(dwc_usb3_pcd_t *pcd);
++extern void dwc_usb3_pcd_set_link_state(dwc_usb3_pcd_t *pcd, int state);
++extern void dwc_usb3_pcd_remote_wake(dwc_usb3_pcd_t *pcd, int function);
++extern void dwc_usb3_pcd_do_test_mode(unsigned long data);
++/** @} */
++
++/* Peripheral CIL Routines
++ *
++ * The following routines support managing the DWC_usb3 controller in
++ * peripheral mode.
++ */
++extern void dwc_usb3_fill_desc(dwc_usb3_dma_desc_t *desc, dwc_dma_t dma_addr,
++			       u32 dma_len, u32 stream, u32 type,
++			       u32 ctrlbits, int own);
++extern void dwc_usb3_start_desc_chain(dwc_usb3_dma_desc_t *desc);
++extern void dwc_usb3_end_desc_chain(dwc_usb3_dma_desc_t *desc);
++extern void dwc_usb3_enable_desc(dwc_usb3_dma_desc_t *desc);
++extern void dwc_usb3_disable_desc(dwc_usb3_dma_desc_t *desc);
++extern int dwc_usb3_xmit_fn_remote_wake(dwc_usb3_pcd_t *pcd, u32 intf);
++extern int dwc_usb3_xmit_ltm(dwc_usb3_pcd_t *pcd, u32 value);
++extern int dwc_usb3_xmit_host_role_request(dwc_usb3_pcd_t *pcd, u32 param);
++extern int dwc_usb3_set_scratchpad_buf_array(dwc_usb3_pcd_t *pcd,
++					     dwc_dma_t dma_addr);
++extern int dwc_usb3_flush_fifo(dwc_usb3_pcd_t *pcd, u32 fifo_sel);
++extern int dwc_usb3_dep_cfg(dwc_usb3_pcd_t *pcd,
++			    dwc_usb3_dev_ep_regs_t __iomem *ep_reg,
++			    u32 depcfg0, u32 depcfg1,
++			    u32 depcfg2);
++extern int dwc_usb3_dep_xfercfg(dwc_usb3_pcd_t *pcd,
++				dwc_usb3_dev_ep_regs_t __iomem *ep_reg,
++				u32 depstrmcfg);
++extern u32 dwc_usb3_dep_getepstate(dwc_usb3_pcd_t *pcd,
++				   dwc_usb3_dev_ep_regs_t __iomem *ep_reg);
++extern int dwc_usb3_dep_sstall(dwc_usb3_pcd_t *pcd,
++			       dwc_usb3_dev_ep_regs_t __iomem *ep_reg);
++extern int dwc_usb3_dep_cstall(dwc_usb3_pcd_t *pcd,
++			       dwc_usb3_dev_ep_regs_t __iomem *ep_reg,
++			       int clr_pend);
++extern int dwc_usb3_dep_startxfer(dwc_usb3_pcd_t *pcd,
++				  dwc_usb3_dev_ep_regs_t __iomem *ep_reg,
++				  dwc_dma_t dma_addr, u32 stream_or_uf);
++extern int dwc_usb3_dep_updatexfer(dwc_usb3_pcd_t *pcd,
++				   dwc_usb3_dev_ep_regs_t __iomem *ep_reg,
++				   u32 tri);
++extern int dwc_usb3_dep_endxfer(dwc_usb3_pcd_t *pcd,
++				dwc_usb3_dev_ep_regs_t __iomem *ep_reg,
++				u32 tri, int flags, void *condition);
++#define DWC_ENDXFER_FORCE	1
++#define DWC_ENDXFER_NODELAY	2
++
++#ifdef DWC_STAR_9000463548_WORKAROUND
++extern int dwc_usb3_dep_endxfer_nowait(dwc_usb3_pcd_t *pcd,
++				       dwc_usb3_dev_ep_regs_t __iomem *ep_reg,
++				       u32 tri, int flags);
++extern int dwc_usb3_dep_wait_endxfer(dwc_usb3_pcd_t *pcd,
++				     dwc_usb3_dev_ep_regs_t __iomem *ep_reg,
++				     void *condition);
++#endif
++extern int dwc_usb3_dep_startnewcfg(dwc_usb3_pcd_t *pcd,
++				    dwc_usb3_dev_ep_regs_t __iomem *ep_reg,
++				    u32 rsrcidx);
++extern int dwc_usb3_enable_ep(dwc_usb3_pcd_t *pcd, dwc_usb3_pcd_ep_t *ep);
++extern int dwc_usb3_disable_ep(dwc_usb3_pcd_t *pcd, dwc_usb3_pcd_ep_t *ep);
++extern int dwc_usb3_get_device_speed(dwc_usb3_pcd_t *pcd);
++extern int dwc_usb3_get_frame(dwc_usb3_pcd_t *pcd);
++extern void dwc_usb3_set_address(dwc_usb3_pcd_t *pcd, int addr);
++extern void dwc_usb3_ena_usb2_suspend(dwc_usb3_pcd_t *pcd);
++extern void dwc_usb3_dis_usb2_suspend(dwc_usb3_pcd_t *pcd);
++extern void dwc_usb3_accept_u1(dwc_usb3_pcd_t *pcd);
++extern void dwc_usb3_accept_u2(dwc_usb3_pcd_t *pcd);
++extern void dwc_usb3_enable_u1(dwc_usb3_pcd_t *pcd);
++extern void dwc_usb3_enable_u2(dwc_usb3_pcd_t *pcd);
++extern void dwc_usb3_disable_u1(dwc_usb3_pcd_t *pcd);
++extern void dwc_usb3_disable_u2(dwc_usb3_pcd_t *pcd);
++extern int dwc_usb3_u1_enabled(dwc_usb3_pcd_t *pcd);
++extern int dwc_usb3_u2_enabled(dwc_usb3_pcd_t *pcd);
++extern void dwc_usb3_clr_eps_enabled(dwc_usb3_pcd_t *pcd);
++
++extern void dwc_usb3_dump_dev_registers(dwc_usb3_pcd_t *pcd);
++
++#define dwc_usb3_is_hwo(desc)	((desc)->control & DWC_DSCCTL_HWO_BIT)
++#define dwc_usb3_is_ioc(desc)	((desc)->control & DWC_DSCCTL_IOC_BIT)
++
++#define dwc_usb3_get_xfercnt(desc)				\
++	((desc)->status >> DWC_DSCSTS_XFRCNT_SHIFT &		\
++	 DWC_DSCSTS_XFRCNT_BITS >> DWC_DSCSTS_XFRCNT_SHIFT)
++
++#define dwc_usb3_get_xfersts(desc)				\
++	((desc)->status >> DWC_DSCSTS_TRBRSP_SHIFT &		\
++	 DWC_DSCSTS_TRBRSP_BITS >> DWC_DSCSTS_TRBRSP_SHIFT)
++
++#define dwc_usb3_get_xfersofn(desc)				\
++	((desc)->control >> DWC_DSCCTL_STRMID_SOFN_SHIFT &	\
++	 DWC_DSCCTL_STRMID_SOFN_BITS >> DWC_DSCCTL_STRMID_SOFN_SHIFT)
++
++#define dwc_usb3_get_eventsofn(event)				\
++	((event) >> DWC_DEPEVT_ISOC_UFRAME_NUM_SHIFT &	\
++	 DWC_DEPEVT_ISOC_UFRAME_NUM_BITS >> DWC_DEPEVT_ISOC_UFRAME_NUM_SHIFT)
++
++/* Common CIL Routines
++ */
++extern void dwc_usb3_dump_dbgregs(dwc_usb3_device_t *dev);
++extern void dwc_usb3_dump_global_registers(dwc_usb3_device_t *dev);
++extern void dwc_usb3_set_tx_fifo_size(dwc_usb3_device_t *dev, int *sz);
++extern void dwc_usb3_set_rx_fifo_size(dwc_usb3_device_t *dev, int size);
++extern void dwc_usb3_init_eventbuf(dwc_usb3_device_t *dev, int bufno,
++			u32 *addr, unsigned int size, dwc_dma_t dma_addr);
++extern void dwc_usb3_dis_flush_eventbuf_intr(dwc_usb3_device_t *dev, int bufno);
++extern void dwc_usb3_enable_common_interrupts(dwc_usb3_device_t *dev);
++extern void dwc_usb3_enable_device_interrupts(dwc_usb3_device_t *dev);
++extern int dwc_usb3_handle_event(dwc_usb3_device_t *dev);
++extern int dwc_usb3_irq(dwc_usb3_device_t *dev, int irq);
++
++/**
++ * This routine returns the current operating mode, host or device.
++ *
++ * @return 0 - Device Mode, 1 - Host Mode
++ */
++static __inline u32 dwc_usb3_mode(dwc_usb3_device_t *dev)
++{
++	return dwc_rd32(dev, &dev->core_global_regs->gsts) & 0x1;
++}
++
++/**
++ * This routine returns true if the current operating mode is Device.
++ *
++ * @return 1 - Device mode, 0 - Not Device mode
++ */
++static __inline int dwc_usb3_is_device_mode(dwc_usb3_device_t *dev)
++{
++	return dwc_usb3_mode(dev) != DWC_GSTS_HOST_MODE;
++}
++
++/**
++ * This routine returns true if the current operating mode is Host.
++ *
++ * @return 1 - Host mode, 0 - Not Host mode
++ */
++static __inline int dwc_usb3_is_host_mode(dwc_usb3_device_t *dev)
++{
++	return dwc_usb3_mode(dev) == DWC_GSTS_HOST_MODE;
++}
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* _DWC_CIL_H_ */
+diff --git a/drivers/usb/gadget/udc/hiudc3/cil_intr.c b/drivers/usb/gadget/udc/hiudc3/cil_intr.c
+new file mode 100644
+index 0000000..300faca
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc3/cil_intr.c
+@@ -0,0 +1,596 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/DWC_usb3/driver/cil_intr.c $
++ * $Revision: #39 $
++ * $Date: 2014/11/11 $
++ * $Change: 2664766 $
++ *
++ * Synopsys SS USB3 Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
++ * ========================================================================== */
++
++/** @file
++ *
++ * The Core Interface Layer provides basic services for accessing and
++ * managing the DWC_usb3 hardware. These services are used by both the
++ * Peripheral Controller Driver and the On The Go Driver.
++ *
++ * This file contains the common interrupt handling functions.
++ */
++
++#include "os_defs.h"
++#include "hw.h"
++#include "usb.h"
++#include "pcd.h"
++#include "dev.h"
++#include "os_dev.h"
++#include "cil.h"
++
++/**
++ * This routine enables the Event Buffer interrupt.
++ */
++static void ena_eventbuf_intr(dwc_usb3_device_t *dev, int bufno)
++{
++	u32 eventsiz;
++
++	eventsiz =
++	      dwc_rd32(dev, &dev->core_global_regs->geventbuf[bufno].geventsiz);
++	eventsiz &= ~DWC_EVENTSIZ_INT_MSK_BIT;
++	dwc_wr32(dev, &dev->core_global_regs->geventbuf[bufno].geventsiz,
++		 eventsiz);
++}
++
++/**
++ * This routine disables the Event Buffer interrupt.
++ */
++static void dis_eventbuf_intr(dwc_usb3_device_t *dev, int bufno)
++{
++	u32 eventsiz;
++
++	eventsiz =
++	      dwc_rd32(dev, &dev->core_global_regs->geventbuf[bufno].geventsiz);
++	eventsiz |= DWC_EVENTSIZ_INT_MSK_BIT;
++	dwc_wr32(dev, &dev->core_global_regs->geventbuf[bufno].geventsiz,
++		 eventsiz);
++}
++
++/**
++ * This routine disables the Event Buffer interrupt and flushes any pending
++ * events from the buffer.
++ */
++void dwc_usb3_dis_flush_eventbuf_intr(dwc_usb3_device_t *dev, int bufno)
++{
++	u32 cnt;
++
++	if (dev->hibernate >= DWC_HIBER_SLEEPING)
++		return;
++
++	dis_eventbuf_intr(dev, bufno);
++	cnt = dwc_rd32(dev, &dev->core_global_regs->geventbuf[bufno].geventcnt);
++	dwc_wr32(dev, &dev->core_global_regs->geventbuf[bufno].geventcnt, cnt);
++}
++
++/**
++ * This routine reads the current Event Buffer count.
++ */
++static int get_eventbuf_count(dwc_usb3_device_t *dev, int bufno)
++{
++	u32 cnt;
++
++	cnt = dwc_rd32(dev, &dev->core_global_regs->geventbuf[bufno].geventcnt);
++	return cnt & DWC_EVENTCNT_CNT_BITS;
++}
++
++/**
++ * This routine writes the Event Buffer count.
++ */
++static void update_eventbuf_count(dwc_usb3_device_t *dev, int bufno, int cnt)
++{
++	dwc_wr32(dev, &dev->core_global_regs->geventbuf[bufno].geventcnt, cnt);
++}
++
++/**
++ * This routine fetches the next event from the Event Buffer.
++ */
++static u32 get_eventbuf_event(dwc_usb3_device_t *dev, int bufno, int size)
++{
++	u32 event;
++
++	event = *dev->event_ptr[bufno]++;
++	if (dev->event_ptr[bufno] >= dev->event_buf[bufno] + size)
++		dev->event_ptr[bufno] = dev->event_buf[bufno];
++	return event;
++}
++
++/**
++ * This routine initializes an Event Buffer.
++ */
++void dwc_usb3_init_eventbuf(dwc_usb3_device_t *dev, int bufno,
++			    u32 *addr, unsigned int size, dwc_dma_t dma_addr)
++{
++	dwc_debug4(dev, "Event buf %d addr 0x%08lx phys 0x%08lx size %d\n",
++		   bufno, (unsigned long)addr, (unsigned long)dma_addr, size);
++	dwc_wr32(dev, &dev->core_global_regs->geventbuf[bufno].geventadr_lo,
++		 dma_addr & 0xffffffffU);
++#ifdef DWC_64_BIT_ARCH
++	dwc_wr32(dev, &dev->core_global_regs->geventbuf[bufno].geventadr_hi,
++		 dma_addr >> 32U & 0xffffffffU);
++#else
++	dwc_wr32(dev, &dev->core_global_regs->geventbuf[bufno].geventadr_hi, 0);
++#endif
++	dwc_wr32(dev, &dev->core_global_regs->geventbuf[bufno].geventsiz,
++		 size << 2);
++	dwc_wr32(dev, &dev->core_global_regs->geventbuf[bufno].geventcnt, 0);
++}
++
++/**
++ * This routine initializes the commmon interrupts.
++ *
++ * @param dev   Programming view of DWC_usb3 controller.
++ */
++void dwc_usb3_enable_common_interrupts(dwc_usb3_device_t *dev)
++{
++	/* Clear any pending interrupts */
++	dwc_usb3_dis_flush_eventbuf_intr(dev, 0);
++
++	ena_eventbuf_intr(dev, 0);
++}
++
++/**
++ * This routine enables the Device mode interrupts.
++ *
++ * @param dev   Programming view of DWC_usb3 controller.
++ */
++void dwc_usb3_enable_device_interrupts(dwc_usb3_device_t *dev)
++{
++	u32 devten;
++
++	dwc_debug1(dev, "%s()\n", __func__);
++
++	/* Enable global interrupts */
++	dwc_usb3_enable_common_interrupts(dev);
++
++	devten = DWC_DEVTEN_DISCONN_BIT | DWC_DEVTEN_CONNDONE_BIT |
++		 DWC_DEVTEN_USBRESET_BIT | DWC_DEVTEN_HIBER_REQ_BIT |
++		 DWC_DEVTEN_WKUP_BIT;
++
++	if (dev->snpsid >= 0x5533230a)
++		devten |= DWC_DEVTEN_U3_L2L1_SUSP_BIT;
++	else
++		devten |= DWC_DEVTEN_ULST_CHNG_BIT;
++
++	/* Enable device interrupts */
++	dwc_wr32(dev, &dev->pcd.dev_global_regs->devten, devten);
++
++	dwc_debug2(dev, "%s() devten=%0x\n", __func__,
++		   dwc_rd32(dev, &dev->pcd.dev_global_regs->devten));
++}
++
++/**
++ * This routine handles all interrupt events. It is called by the
++ * dwc_usb3_irq() interrupt handler routine, and by the enter_hibernation()
++ * routine after clearing the Run/Stop bit and waiting for the Halted bit to
++ * be set.
++ *
++ * @param dev   Programming view of DWC_usb3 controller.
++ * return       1 if an interrupt event was seen, 0 if not.
++ */
++int dwc_usb3_handle_event(dwc_usb3_device_t *dev)
++{
++	dwc_usb3_pcd_t *pcd = &dev->pcd;
++	u32 event;
++	int count, intr, physep, i;
++	int ret = 0;
++	static int msg_cnt;
++
++	count = get_eventbuf_count(dev, 0);
++	if (count)
++		dwc_debug1(dev, "Interrupt count %d\n", count);
++
++	if ((count & DWC_EVENTCNT_CNT_BITS) ==
++					(0xffffffff & DWC_EVENTCNT_CNT_BITS) ||
++	    count >= DWC_EVENT_BUF_SIZE * 4) {
++		if (msg_cnt > 100) {
++			msg_cnt = 100;
++			dwc_warn0(dev, "Too many bad events!!\n");
++		} else {
++			msg_cnt++;
++			dwc_warn1(dev,
++				"Bad event count 0x%01x in dwc_usb3_irq() !!\n",
++				count);
++		}
++
++		dis_eventbuf_intr(dev, 0);
++		update_eventbuf_count(dev, 0, count);
++		count = 0;
++	}
++
++	if (!count)
++		goto out;
++	ret = 1;
++
++#if defined(CONFIG_IPMATE) || defined(COSIM) || defined(VIRTIO_MODEL)
++	dis_eventbuf_intr(dev, 0);
++#endif
++
++	for (i = 0; i < count; i += 4) {
++		dwc_debug1(dev, "Event addr 0x%08lx\n",
++			   (unsigned long)dev->event_ptr[0]);
++		event = get_eventbuf_event(dev, 0, DWC_EVENT_BUF_SIZE);
++		update_eventbuf_count(dev, 0, 4);
++		if (event == 0) {
++			dwc_print0(dev, "## Null event! ##\n");
++
++			/* Ignore null events */
++			continue;
++		}
++
++		//dwc_debug1(dev, "Interrupt event 0x%08x\n", event);
++		if (event & DWC_EVENT_NON_EP_BIT) {
++			//dwc_debug0(dev, "Non-EP interrupt event\n");
++			intr = event & DWC_EVENT_INTTYPE_BITS;
++
++			if (intr ==
++			    DWC_EVENT_DEV_INT << DWC_EVENT_INTTYPE_SHIFT) {
++				dwc_debug1(dev,
++					   "## Device interrupt 0x%08x ##\n",
++					   event);
++				ret = dwc_usb3_handle_dev_intr(pcd, event);
++				if (ret) {
++					ret = 2;
++					goto out;
++				}
++				ret = 1;
++			} else {
++				dwc_debug1(dev, "## Core interrupt 0x%08x ##\n",
++					   event);
++
++				/* @todo Handle non-Device interrupts
++				 * (OTG, CarKit, I2C)
++				 */
++			}
++		} else {
++			physep = event >> DWC_DEPEVT_EPNUM_SHIFT &
++				DWC_DEPEVT_EPNUM_BITS >> DWC_DEPEVT_EPNUM_SHIFT;
++			dwc_debug2(dev,
++				   "## Physical EP%d interrupt 0x%08x ##\n",
++				   physep, event);
++			dwc_debug2(dev, "[EP%d] %s\n", physep >> 1 & 0xf,
++				   physep & 1 ? "IN" : "OUT");
++			dwc_usb3_handle_ep_intr(pcd, physep, event);
++		}
++	}
++
++#if defined(CONFIG_IPMATE) || defined(COSIM) || defined(VIRTIO_MODEL)
++	ena_eventbuf_intr(dev, 0);
++#endif
++out:
++	return ret;
++}
++
++#ifdef SSIC
++
++static int ssic_read_attr(dwc_usb3_device_t *dev, u32 aid, u32 *aval)
++{
++	int i;
++	u32 sevt = 0;
++	u32 sctl = 0;
++	u32 data = 0;
++
++	dwc_debug(dev, "%s: aid=0x%0x\n", __func__, aid);
++
++	sctl |= DWC_SCTL_GO_ACC_BIT;
++	sctl |= (aid << DWC_SCTL_AID_SHIFT);
++
++	dwc_debug(dev, "%s: writing sctl=0x%08x\n", __func__, sctl);
++	dwc_wr32(dev, &dev->ssic_regs->sctl[0], sctl);
++
++	i = 100000;
++	do {
++		sevt = dwc_rd32(dev, &dev->ssic_regs->sevt[0]);
++		if (sevt & DWC_SEVT_LACC_CMPLT_BIT)
++			break;
++		dwc_udelay(dev, 1);
++	} while (--i > 0);
++
++	if (i == 0) {
++		dwc_error(dev, "%s: lacc timeout\n", __func__);
++		return -1;
++	}
++
++	data = (sevt & DWC_SEVT_RDATA_RCVD_BITS) >> DWC_SEVT_RDATA_RCVD_SHIFT;
++	if (aval)
++		*aval = (u8)data;
++
++	dwc_debug(dev, "%s: rdata=%02x\n", __func__, data);
++	return 0;
++}
++
++static int ssic_write_attr(dwc_usb3_device_t *dev, u32 aid, u32 aval)
++{
++	int i;
++	u32 sctl = 0;
++	u32 sevt = 0;
++
++	dwc_debug(dev, "%s: aid=0x%0x aval=%0x\n", __func__, aid, aval);
++	sctl |= (DWC_SCTL_GO_ACC_BIT | DWC_SCTL_RD_WR_N_BIT);
++	sctl |= (aid << DWC_SCTL_AID_SHIFT);
++	sctl |= (aval << DWC_SCTL_ADATA_SHIFT);
++	dwc_debug(dev, "%s: writing sctl=0x%08x\n", __func__, sctl);
++	dwc_wr32(dev, &dev->ssic_regs->sctl[0], sctl);
++
++	i = 100000;
++	do {
++		sevt = dwc_rd32(dev, &dev->ssic_regs->sevt[0]);
++		if (sevt & DWC_SEVT_LACC_CMPLT_BIT)
++			break;
++		dwc_udelay(dev, 1);
++	} while (--i > 0);
++
++	if (i == 0 ) {
++		dwc_error(dev, "%s: lacc timeout\n", __func__);
++		return -1;
++	}
++
++	return 0;
++}
++
++static int ssic_rrap_response(dwc_usb3_device_t *dev, int write, u32 aid, u32 aeid, u32 aval)
++{
++	int i;
++	u32 sctl = 0;
++	u32 sevt = 0;
++
++	dwc_debug(dev, "%s: aid=0x%0x, aeid=%0x, aval=%0x, write=%d\n",
++		  __func__, aid, aeid, aval, write);
++
++	sctl |= (DWC_SCTL_GO_ACC_BIT | DWC_SCTL_RACC_BIT);
++	if (write)
++		sctl |= (DWC_SCTL_RD_WR_N_BIT);
++
++	sctl |= ((aid << DWC_SCTL_AID_SHIFT) & DWC_SCTL_AID_BITS);
++	sctl |= ((aeid << DWC_SCTL_EAID_SHIFT) & DWC_SCTL_EAID_BITS);
++	sctl |= ((aval << DWC_SCTL_ADATA_SHIFT) & DWC_SCTL_ADATA_BITS);
++
++	dwc_debug(dev, "%s: writing sctl=0x%08x\n", __func__, sctl);
++	dwc_wr32(dev, &dev->ssic_regs->sctl[0], sctl);
++
++	i = 100000;
++	do {
++		sevt = dwc_rd32(dev, &dev->ssic_regs->sevt[0]);
++		if (sevt & DWC_SEVT_RCMD_RES_SENT_BIT)
++			break;
++		dwc_udelay(dev, 1);
++	} while(--i > 0);
++
++	if (i == 0) {
++		dwc_error(dev, "%s: racc response send timeout\n", __func__);
++		return -1;
++	}
++
++	dwc_debug(dev, "%s: racc response sent result=0x%0x\n", __func__,
++		(sevt & DWC_SEVT_RACC_RESULT_BITS) >> DWC_SEVT_RACC_RESULT_SHIFT);
++
++	return 0;
++}
++
++static int ssic_cfg_done(dwc_usb3_device_t *dev)
++{
++	u32 temp;
++	int usec = 100000;
++	dwc_debug1(dev, "%s\n", __func__);
++
++	temp = dwc_rd32(dev, &dev->ssic_regs->sctl[0]);
++	temp |= DWC_SCTL_CFG_DONE_BIT;
++	dwc_wr32(dev, &dev->ssic_regs->sctl[0], temp);
++
++	do {
++		u32 result = dwc_rd32(dev, &dev->core_global_regs->gusb3rmmictl[0]);
++		if (((result & DWC_RMMICTL_MPHY_STATE_BITS) >>
++		     DWC_RMMICTL_MPHY_STATE_SHIFT) != DWC_MPHY_STATE_HIBERN8) {
++			break;
++		}
++
++		dwc_udelay(dev, 1);
++		usec -= 1;
++	} while (usec > 0);
++
++	if (!usec) {
++		dwc_error(dev, "%s: cfg done timed out\n", __func__);
++		return -1;
++	}
++
++	return 0;
++}
++
++static int dwc_usb3_handle_ssic_event(dwc_usb3_device_t *dev)
++{
++	int retval = -1;
++	u32 sevt = dwc_rd32(dev, &dev->ssic_regs->sevt[0]);
++	u32 temp = sevt;
++	dwc_debug(dev, "%s: SSIC Event 0x%08x\n", __func__, sevt);
++
++	sevt &= (DWC_SEVT_ROM_INIT_CMPLT_BIT |
++		DWC_SEVT_LACC_CMPLT_BIT |
++		DWC_SEVT_RCMD_RES_RCVD_BIT |
++		DWC_SEVT_RCMD_RES_SENT_BIT |
++		DWC_SEVT_MPHY_ST_CHNG_BIT |
++		DWC_SEVT_OK_STRT_RRAP_BIT |
++		DWC_SEVT_RRAP_ERROR_BIT);
++
++	dwc_wr32(dev, &dev->ssic_regs->sevt[0], sevt);
++
++	sevt = temp;
++
++	if (sevt & DWC_SEVT_MPHY_ST_CHNG_BIT) {
++		u32 rmmictl = dwc_rd32(dev, &dev->core_global_regs->gusb3rmmictl[0]);
++		if (((rmmictl & DWC_RMMICTL_MPHY_STATE_BITS) >> DWC_RMMICTL_MPHY_STATE_SHIFT) ==
++		    DWC_MPHY_STATE_HIBERN8) {
++			ssic_cfg_done(dev);
++		}
++	}
++
++	if (sevt & DWC_SEVT_RCMD_RES_RCVD_BIT) {
++		u8 rdata = (sevt & DWC_SEVT_RDATA_RCVD_BITS) >> DWC_SEVT_RDATA_RCVD_SHIFT;
++		u8 rladdr = (sevt & DWC_SEVT_RLADDR_RCVD_BITS) >> DWC_SEVT_RLADDR_RCVD_SHIFT;
++		u8 ruaddr = (sevt & DWC_SEVT_RUADDR_RCVD_BITS) >> DWC_SEVT_RUADDR_RCVD_SHIFT;
++		int read = !!(sevt & DWC_SEVT_READ_RCVD_BIT);
++
++		dwc_debug4(dev, "rdata=0x%02x, rladdr=0x%02x, ruaddr=0x%02x, read=%d\n",
++			   rdata, rladdr, ruaddr, read);
++
++		if (ruaddr <= 0x3) {
++			if (read)
++				dwc_error(dev, "Read not handled\n");
++			else
++				dwc_error(dev, "Write not handled\n");
++		} else if (ruaddr == 0x4) {
++			/* DSP_DISCONNECT */
++			if (rladdr == 0x0) {
++				dwc_error(dev, "DSP_DISCONNECT not handled\n");
++			/* CONFIGURE_FOR_HS */
++			} else if (rladdr == 0x1) {
++				dwc_debug(dev, "CONFIGURE_FOR_HS\n");
++				ssic_rrap_response(dev, !read, rladdr, ruaddr, 0x0);
++				ssic_write_attr(dev, 0x21, 0x2);
++				ssic_write_attr(dev, 0xa1, 0x2);
++				retval = 0;
++			/* BURST_CLOSURE */
++			} else if (rladdr == 0x2) {
++				dwc_debug(dev, "BURST_CLOSURE\n");
++				ssic_rrap_response(dev, !read, rladdr, ruaddr, 0x0);
++				ssic_cfg_done(dev);
++			/* DISABLE_SCRAMBLING */
++			} else if (rladdr == 0x3) {
++				dwc_error(dev, "DISABLE_SCRAMBLING not handled\n");
++			/* DISABLE_STALL_IN_U0 */
++			} else if (rladdr == 0x4) {
++				dwc_error(dev, "DISABLE_STALL_IN_U0 not handled\n");
++			/* TEST_MODE */
++			} else if (rladdr == 0xff) {
++				dwc_error(dev, "DISABLE_TEST_MODE not handled\n");
++			} else {
++				dwc_error(dev, "UNKNOWN\n");
++			}
++		} else if (ruaddr == 0x5) {
++			dwc_error(dev, "UNKNOWN\n");
++		} else if (ruaddr == 0x6) {
++			dwc_error(dev, "UNKNOWN\n");
++		} else {
++			dwc_error(dev, "UNKNOWN\n");
++		}
++	}
++
++	return retval;
++}
++
++#endif
++
++
++/**
++ * This is the common interrupt handler routine.
++ *
++ * @param dev   Programming view of DWC_usb3 controller.
++ * @param irq   IRQ number passed in by Linux kernel.
++ * @return      1 if an interrupt event was seen, 0 if not.
++ */
++int dwc_usb3_irq(dwc_usb3_device_t *dev, int irq)
++{
++	int state, temp, ret;
++
++#ifdef SSIC
++	u32 gsts, sevt;
++
++	gsts = dwc_rd32(dev, &dev->core_global_regs->gsts);
++	sevt = dwc_rd32(dev, &dev->ssic_regs->sevt[0]);
++	dwc_debug(dev, "%s: gsts=0x%08x, sevt=0x%08x\n", __func__, gsts, sevt);
++#endif
++
++	if (!dev->cmn_irq_installed)
++		return 0;
++
++#ifdef SSIC
++	gsts = dwc_rd32(dev, &dev->core_global_regs->gsts);
++	if (gsts & DWC_GSTS_SSIC_IP_BIT) {
++		dwc_usb3_handle_ssic_event(dev);
++		ret = 1;
++	}
++#endif
++
++	state = dev->hibernate;
++
++	if (state != DWC_HIBER_SLEEPING && dev->snpsid >= 0x5533230a &&
++							dev->hiber_wait_u0) {
++		/* Handle waiting for U0 after requesting link state RECOVERY,
++		 * because we don't have the link state change event enabled.
++		 * We also do this in dwc_wait_pme_thread() in case an event
++		 * doesn't come.
++		 */
++		temp = dwc_usb3_pcd_get_link_state(&dev->pcd);
++		dev->pcd.link_state = temp;
++		dwc_debug1(dev, "intr WAIT_U0 state=%d\n", temp);
++
++		if (temp == DWC_LINK_STATE_U0) {
++			dwc_debug0(dev, "intr WAIT_U0 setting speed\n");
++			dev->pcd.speed = dwc_usb3_get_device_speed(&dev->pcd);
++			if (dev->pcd.remote_wakeup_enable)
++				dwc_usb3_pcd_remote_wake(&dev->pcd, 0);
++			dev->hiber_wait_u0 = 0;
++		}
++	}
++
++	if (state >= DWC_HIBER_SLEEPING) {
++		if (state == DWC_HIBER_WAIT_U0 ||
++		    state == DWC_HIBER_SS_DIS_QUIRK) {
++			dev->hibernate = DWC_HIBER_AWAKE;
++		} else {
++			if (dev->pme_ready) {
++#ifndef SELA_PLATFORM
++				ret = dwc_usb3_handle_pme_intr(dev);
++				return ret;
++#else
++				return 1;
++#endif
++			} else {
++				if (state != DWC_HIBER_WAIT_LINK_UP)
++					dwc_info0(dev, "Intr in hibernate but"
++						       " pme_ready not set\n");
++				return 1;
++			}
++		}
++	}
++
++	ret = dwc_usb3_handle_event(dev);
++	if (ret == 2)
++		ret = 1;
++
++#ifdef SSIC
++	gsts = dwc_rd32(dev, &dev->core_global_regs->gsts);
++	sevt = dwc_rd32(dev, &dev->ssic_regs->sevt[0]);
++	dwc_debug(dev, "%s DONE: gsts=0x%08x, sevt=0x%08x\n", __func__, gsts, sevt);
++#endif
++
++	return ret;
++}
+diff --git a/drivers/usb/gadget/udc/hiudc3/dev.h b/drivers/usb/gadget/udc/hiudc3/dev.h
+new file mode 100644
+index 0000000..5f6a303
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc3/dev.h
+@@ -0,0 +1,210 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/DWC_usb3/driver/dev.h $
++ * $Revision: #12 $
++ * $Date: 2014/11/11 $
++ * $Change: 2664766 $
++ *
++ * Synopsys SS USB3 Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
++ * ========================================================================== */
++
++#ifndef _DWC_DEV_H_
++#define _DWC_DEV_H_
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/** @file
++ * This file contains the interface to the Linux driver.
++ */
++
++/**
++ * This structure is a wrapper that encapsulates the driver components used to
++ * manage a single DWC_usb3 controller.
++ */
++typedef struct dwc_usb3_device {
++	/**
++	 * OS-specific stuff. KEEP THIS AT THE VERY BEGINNING OF THE DEVICE
++	 * STRUCT. OSes such as FreeBSD and NetBSD require this.
++	 */
++
++	/** Base address returned from ioremap() */
++	volatile u8 __iomem *base;
++	volatile u8 __iomem *gasket_base;
++
++	/** Offset to 'gasket' registers (Synopsys FPGA only) */
++	int gasket_ofs;
++
++#if defined(__linux__) || defined(LINUXTEST)
++	/** Device context */
++	struct device *dev;
++
++	/** Start address of IOMEM region */
++	resource_size_t rsrc_start;
++	resource_size_t gasket_start;
++
++	/** Length of IOMEM region */
++	resource_size_t rsrc_len;
++	resource_size_t gasket_len;
++
++	/** IRQ resource */
++	int irq;
++
++	struct task_struct *pme_thread;
++#endif
++	/* ==== End of OS-specific stuff ==== */
++
++	/** Count of threads inside Gadget API */
++	int hiber_cnt;
++
++	/** Hibernation state */
++	int hibernate;
++
++#define DWC_HIBER_AWAKE		0
++#define DWC_HIBER_ENTER_NOSAVE	1
++#define DWC_HIBER_ENTER_SAVE	2
++#define DWC_HIBER_SLEEPING	3
++#define DWC_HIBER_WAIT_LINK_UP	4
++#define DWC_HIBER_WAIT_U0	5
++#define DWC_HIBER_SS_DIS_QUIRK	6
++
++	int pme_ready;
++
++	/** PCD structure */
++	struct dwc_usb3_pcd pcd;
++
++	/** Value from SNPSID register */
++	u32 snpsid;
++
++	/** Parameters that define how the core should be configured */
++	dwc_usb3_core_params_t *core_params;
++
++	/** Core Global registers starting at offset 100h */
++	dwc_usb3_core_global_regs_t __iomem *core_global_regs;
++
++#ifdef SSIC
++	dwc_usb3_ssic_regs_t __iomem *ssic_regs;
++#endif
++
++	/** @{ */
++#define DWC_EVENT_BUF_SIZE	256	// size in dwords
++#define DWC_NUM_EVENT_BUFS	1
++	/** Event Buffers for receiving interrupts. Up to 32 buffers are
++	 * supported by the hardware, but we only use 1.
++	 */
++	u32 *event_ptr[DWC_NUM_EVENT_BUFS];
++	u32 *event_buf[DWC_NUM_EVENT_BUFS];
++	dwc_dma_t event_buf_dma[DWC_NUM_EVENT_BUFS];
++	/** @} */
++
++	/** Total RAM for FIFOs (Bytes) */
++	u16 total_fifo_size;
++
++	/** Size of Rx FIFO (Bytes) */
++	u16 rx_fifo_size;
++
++	/** @{ */
++	/** Hardware Configuration - stored here for convenience */
++	u32 hwparams0;
++	u32 hwparams1;
++	u32 hwparams2;
++	u32 hwparams3;
++	u32 hwparams4;
++	u32 hwparams5;
++	u32 hwparams6;
++	u32 hwparams7;
++	u32 hwparams8;
++	/** @} */
++
++	/** @{ */
++	/** Register state, saved across core hibernation */
++	u32 dcfg_save;
++	u32 dctl_save;
++	u32 gtxfifosiz0_save;
++	u32 gtxfifosiz1_save;
++	u32 gtxfifosiz2_save;
++	u32 gtxfifosiz3_save;
++	u32 grxfifosiz0_save;
++	u32 guctl_save;
++	u32 guctl1_save;
++	/** @} */
++
++	/** @{ */
++	/** Hooks for customizing device initialization. See
++	 *  dwc_usb3_pcd_device_init() in cil.c to see how these work.
++	 */
++	void (*soft_reset_hook)(struct dwc_usb3_device *dev, int softrst, int rstor);
++	void (*phy_config_hook)(struct dwc_usb3_device *dev, int softrst, int rstor);
++	void (*fifo_sizing_hook)(struct dwc_usb3_device *dev, int softrst, int rstor);
++	void (*gctl_init_hook)(struct dwc_usb3_device *dev, int softrst, int rstor);
++	void (*set_address_hook)(struct dwc_usb3_device *dev, int softrst, int rstor);
++	void (*ep0_start_hook)(struct dwc_usb3_device *dev, int softrst, int rstor);
++	/** @} */
++
++	/** Value to write into the DCTL HIRD_Thresh field on register
++	 * initialization. If 0 then a default value of 0x1c will be used.
++	 */
++	u32 hird_thresh;
++
++	/** Values to write into GSBUSCFG0 and GSBUSCFG1 on initialization or
++	 * when exiting from hibernation. 'program_gsbuscfg' below must also be
++	 * set to 1 to enable the writing of these values.
++	 */
++	u32 gsbuscfg0;
++	u32 gsbuscfg1;
++
++	/** True if common functionality has been initialized */
++	unsigned int cmn_initialized		: 1;
++
++	/** True if Gadget has been initialized */
++	unsigned int gadget_initialized		: 1;
++
++	/** True if PCD has been initialized */
++	unsigned int pcd_initialized		: 1;
++
++	/** True if common IRQ handler has been installed */
++	unsigned int cmn_irq_installed		: 1;
++
++	/** True if sysfs functions have been installed */
++	unsigned int sysfs_initialized		: 1;
++
++	/** True if waiting for connect before resuming from hibernation */
++	unsigned int hiber_wait_connect		: 1;
++
++	/** True if waiting for U0 state before sending remote wake */
++	unsigned int hiber_wait_u0		: 1;
++
++	/** True if GBUSCFG0/GBUSCFG1 should be written with the above
++	 * values when exiting hibernation */
++	unsigned int program_gsbuscfg		: 1;
++} dwc_usb3_device_t;
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* _DWC_DEV_H_ */
+diff --git a/drivers/usb/gadget/udc/hiudc3/dox.h b/drivers/usb/gadget/udc/hiudc3/dox.h
+new file mode 100644
+index 0000000..d58532b
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc3/dox.h
+@@ -0,0 +1,615 @@
++#ifndef _DWC_DOX_H_
++#define _DWC_DOX_H_
++
++/**
++ * @file
++ *
++ * image html synopsys.png "Synopsys Logo"
++ * image latex synopsys.eps "Synopsys Logo"
++ *
++ * This file contains the Doxygen comments that create the Functional
++ * Specification document for the driver.
++ *
++ * @page intro_chapter Introduction
++ *
++ * The DWC_usb3 Subsystem Version 2.90b is a host and peripheral controller
++ * that is compliant with the USB 3.0 specification. The peripheral controller
++ * has a Synopsys-proprietary programming interface, which bears some
++ * resemblance to the Intel xHCI host interface. This is because the controller
++ * supports xHCI when acting as a host, and some of the logic is shared between
++ * the host and peripheral modes.
++ *
++ * The 2.90b version supports SuperSpeed USB 3.0, and HS and FS USB 2.0.
++ *
++ * Source level driver software will be shipped with the controller. Customers
++ * can use this software as a reference for developing drivers for other
++ * platforms or operating environments.
++ *
++ * @section scope_sec Scope
++ *
++ * This document defines the functionality of the driver software that will
++ * be shipped with the DWC_usb3 Version 2.90b controller. It specifies what
++ * the software will do, not how it will accomplish these tasks.
++ *
++ * The driver software for DWC_usb3 Version 2.90b will support only Linux as
++ * its operating environment. Therefore, this document currently defines
++ * behavior under Linux. However, it is desired that many aspects of the driver
++ * software can be easily ported to other operating systems or environments,
++ * and towards that end, it has been written in a way to ease the porting
++ * effort (see section 1.2.3 @ref env_and_hw_deps_subsec).
++ *
++ * For subsequent releases of the DWC_usb3 controller, this document will be
++ * modified to include updates required in the driver software. These updates
++ * may be made to support new features in the controller or to support new
++ * operating environments.
++ *
++ * @section overview_sec Overview
++ *
++ * @subsection sw_arch_subsec Software Architecture
++ *
++ * The DWC_usb3 controller can act as either a host or a peripheral on the
++ * USB. Figure 1.1 shows the software architecture for the DWC_usb3 controller.
++ *
++ * There are two stacks in the software architecture - the Host Stack and the
++ * Peripheral Stack. Brief descriptions of each of these stacks are given
++ * below to set the context for the driver software. Since the host part of
++ * the DWC_usb3 controller conforms to the xHCI standard, the xHCI HCD
++ * driver in the host OS will provide the host stack functionality. Therefore,
++ * only the peripheral stack functionality will be implemented in the DWC_usb3
++ * controller driver software. See the OTG 3.0 user manual for a description
++ * of the DRD/OTG functionality.
++ *
++ * The Host Stack is used to request transfers to or from USB devices when
++ * the DWC_usb3 component is acting in the role of a host. The top-level
++ * component in this stack is a Host Application that acts as a producer or
++ * consumer of data. The Class Drivers translate application requests into a
++ * protocol specific to a certain type (or class) of devices. They use I/O
++ * Request Packets (IRPs) to transfer data to or from USB devices. The USB
++ * Driver (USBD) provides services to allow multiple Class Drivers to
++ * configure, control, and exchange data with their associated devices. The
++ * Hub Driver is also involved in the configuration process. The USBD handles
++ * all communication with the Host Controller Driver (HCD), which must
++ * understand the hardware architecture of the host controller. The HCD
++ * interacts with the host controller hardware to execute the USB transfers
++ * requested by the USBD.
++ *
++ * The Peripheral Stack is used to respond to requests received from a USB
++ * host when the DWC_usb3 component is acting in the role of a peripheral.
++ * The Peripheral Function is the sink or source of data requested by the host.
++ * The Function Driver handles some USB requests directly. It also provides
++ * endpoint read/write data interfaces and notification services to the
++ * Peripheral Function. The Peripheral Controller Driver (PCD) understands
++ * the hardware architecture of the peripheral controller. The PCD interacts
++ * with the peripheral controller hardware to transfer data via the USB and
++ * notifies the Function Driver of USB requests.
++ *
++ * @image html sw_stack.png "Figure 1.1: Generic USB Software Architecture"
++ * @image latex sw_stack.eps "Generic USB Software Architecture" width=6.50in
++ *
++ * @subsection driver_sw_comp_subsec Driver Software Components
++ *
++ * There are two main driver software components - the Peripheral Controller
++ * Driver and the Core Interface Layer (CIL). Basic functionality of the PCD
++ * is described in section 1.2.1 @ref sw_arch_subsec above. A little more
++ * elaboration of the PCD and a description of the CIL are given below.
++ *
++ * The PCD and CIL can be viewed as a hardware abstraction layer. In other
++ * words, the Function Driver does not know or care about the underlying
++ * hardware of the peripheral controller. It merely transfers data and
++ * transmits commands via a software interface with the PCD. Changes made to
++ * the peripheral controller do not require changes to this interface
++ * (although the internal operation of the PCD and CIL would have to be
++ * modified).
++ *
++ * The CIL provides common services for accessing and managing the DWC_usb3
++ * hardware. These services include initialization, mapping of registers,
++ * interrupt control, and low-level access to the CSRs and DMA descriptors
++ * (TRBs).
++ *
++ * @subsection env_and_hw_deps_subsec Environment and Hardware Dependencies
++ *
++ * As noted above, changes to the underlying hardware will require changes to
++ * the internal operation of the driver components. This is true for both of the
++ * driver components (PCD and CIL). Both of these components are aware of the
++ * internal architecture of the controller, so each of these components may need
++ * to change to adapt to any hardware changes. However, for a given operating
++ * system (such as Linux), the layers above the PCD would not require any
++ * changes. They would continue to use the same API to communicate with the PCD.
++ * That is why the PCD is considered a hardware abstraction layer.
++ *
++ * Most of the driver components are designed to be reasonably operating system
++ * independent, by making the low-level routines OS-agnostic and placing them
++ * into separate source files. The Linux-specific code is likewise contained in
++ * a few separate source files. That should simplify porting the driver software
++ * between operating environments.
++ *
++ * Starting with the 2.20a release, the software provides support for an
++ * additional platform, called No-OS. No-OS means the code contains no
++ * OS-specific dependencies at all. See the Porting Guide document for more
++ * information about the No-OS platform, and for general information about
++ * porting the driver to platforms other than Linux.
++ *
++ * Note, however, that the driver has only been completely tested under Linux
++ * 3.6.3.
++ *
++ * @section deliverables_sec Deliverables
++ *
++ * This section describes the driver components, documentation, and demo
++ * software included with the SuperSpeed USB3 Controller Linux Driver
++ * Software.
++ *
++ * @subsection driver_sw_subsec Driver Software
++ *
++ * All driver components will be developed for the Linux operating
++ * system on a PC + HAPS platform. The following components will be
++ * packaged and released:
++ *
++ * - Peripheral Controller Driver source code
++ * - Core Interface Layer source code
++ * - USB Attached SCSI Protocol (UASP) Gadget Driver source code
++ *
++ * These components will support the following features:
++ *
++ * - Control and Bulk transfers in Peripheral Mode using the legacy Mass
++ *   Storage Class protocol
++ * - Control and Bulk transfers in Peripheral Mode using the new USB Attached
++ *   SCSI protocol
++ *
++ * New for the 2.50b release:
++ *
++ * - "Bringup" driver source code. This is a stripped-down version of the PCD,
++ *   with just enough logic for testing the registers, event interrupt, and DMA
++ *   loopback features of the controller. It is intended to verify the basic
++ *   functionality of the controller without needing any USB-specific support
++ *   code in the OS.
++ *
++ *   The bringup driver source, along with a README file describing how to build
++ *   and run the driver, can be found in the bringup/ directory.
++ *
++ * @subsection sw_doc_subsec Software Documentation
++ *
++ * Source documentation in HTML or PDF format will be delivered for the driver
++ * components released with the DWC_usb3 controller. This will include
++ * documentation of the API for each of the driver components.
++ *
++ * Instructions for acquiring and installing the Linux kernel sources and
++ * applying any required patches will be included in the release.
++ *
++ * @subsection demo_sw_subsec Demo Software
++ *
++ * No need for special demo software is anticipated for the 2.90b release.
++ * The demo will consist of using the controller as a mass-storage device,
++ * and copying/streaming large files to and from the device from a host PC.
++ *
++ * @subsection bin_subsec Binaries
++ *
++ * No binaries will be distributed with the 2.90b release.
++ *
++ */
++
++/**
++ * @page env_chapter Environment Specific Features
++ *
++ * This section defines functionality of the driver software that depends on
++ * a particular operating system or operating environment. Since Linux is the
++ * only environment currently supported, the Linux implementation is described
++ * here. In the future, this section may include descriptions of wrappers to
++ * glue generic driver components into various operating system environments.
++ *
++ * @section linux_arch_sec Linux Architecture
++ *
++ * The Linux architecture is very similar to the generic DWC_usb3 software
++ * architecture shown in Figure 1.1. Figure 2.1 shows the Linux version of this
++ * architecture.
++ *
++ * The USB Core component in Linux includes the USB Driver functionality plus a
++ * framework to support Host Controller Drivers. The HCD framework is intended
++ * to allow different HCDs to share code. This makes it easier to write new
++ * HCDs and reduces the number of bugs. Only functionality that needs to be
++ * aware of the underlying hardware is implemented in the HCD. This is
++ * accomplished by defining the hc_driver interface. This interface consists of
++ * the functions and data that must be supplied by an HCD in order to plug into
++ * the Linux HCD framework. The OS-supplied xHCI HCD will implement the
++ * hc_driver interface.
++ *
++ * In Linux, peripheral devices are called gadgets. So the Peripheral Function
++ * is called a Gadget Application and the Function Driver is called a Gadget
++ * Driver. Linux defines a Gadget API which is the interface between the Gadget
++ * Driver and the Peripheral Controller Driver. Similar to the hc_driver
++ * interface, the Gadget API is intended to isolate hardware-specific behavior
++ * to the Peripheral Controller Driver. The Linux version of the DWC_usb3 PCD
++ * will implement the Gadget API. See section 4.2.1 @ref gadget_api_subsec for
++ * more information.
++ *
++ * The API of the Core Interface Layer is independent of the operating system.
++ * Services provided by this component are the same regardless of the operating
++ * system.
++ *
++ * @image html linux_stack.png "Figure 2.1: Linux USB Software Architecture with UASP Gadget"
++ * @image latex linux_stack.eps "Linux USB Software Architecture with UASP Gadget" width=6.50in
++ *
++ * @section linux_driver_sec Linux Driver Module
++ *
++ * All of the driver components are contained in a single driver module. The
++ * module wrapper code, including the module initialization and cleanup
++ * functions, is Linux dependent. This section describes the Linux module
++ * functionality.
++ *
++ * The dwc_usb3 module provides the initialization and cleanup entry points for
++ * the DWC_usb3 driver. This module will be dynamically installed after Linux is
++ * booted using the insmod command. When the module is installed, the
++ * dwc_usb3_driver_init function is called. When the module is removed (using
++ * rmmod), the dwc_usb3_driver_exit function is called.
++ *
++ * This module also defines a data structure for the dwc_usb3_device. This
++ * structure allows the DWC_usb3 driver to comply with the standard Linux driver
++ * model in which devices and drivers are registered with a bus driver. This has
++ * the benefit that Linux can expose attributes of the driver and device in its
++ * special sysfs file system. Users can then read or write files in this file
++ * system to perform diagnostics on the driver components or the device.
++ *
++ * @subsection data_struct_subsec Data Structures
++ *
++ * These are the main data structures used by the DWC_usb3 driver module.
++ *
++ * - struct dwc_usb3_device
++ *
++ * @subsection init_and_clean_subsec Initialization and Cleanup Functions
++ *
++ * These are the initialization and cleanup functions of the DWC_usb3 driver
++ * module.
++ *
++ * - dwc_usb3_driver_init()
++ * - dwc_usb3_driver_probe()
++ * - dwc_usb3_driver_remove()
++ * - dwc_usb3_driver_exit()
++ *
++ */
++
++/**
++ * @page cil_chapter Core Interface Layer
++ *
++ * The Core Interface Layer provides basic services for accessing and managing
++ * the DWC_usb3 hardware. The CIL also manages the memory map for the core so
++ * that the PCD doesn't have to do this separately.
++ *
++ * @section csr_sec Control and Status Register Structures
++ *
++ * The following structures define the size and relative field offsets for
++ * each register in the DWC_usb3 controller. These structures are not created
++ * in memory through normal memory allocation methods. After mapping memory
++ * for the controller into the OS memory space, these structures are overlaid
++ * on the mapped memory by setting the appropriate base address for each
++ * structure. Each register can then be accessed via its address in one of
++ * these structures.
++ *
++ * The precise method for accessing registers is OS-specific. It may be as
++ * simple as directly reading or writing a register field in one of these
++ * structures. Or it may require passing the mapped register address to a
++ * read/write method defined by the OS.
++ *
++ * @subsection core_glbl_regs_subsec Core Global Registers Structure
++ *
++ * The following structure defines the size and relative field offsets for
++ * the Core Global registers.
++ *
++ * - struct dwc_usb3_core_global_regs
++ *
++ * @subsection dev_glbl_regs_subsec Peripheral Mode Global Registers Structure
++ *
++ * The following structure defines the size and relative field offsets for
++ * the Peripheral Mode Global Registers.
++ *
++ * - struct dwc_usb3_dev_global_regs
++ *
++ * @subsection dev_ep_regs_subsec Peripheral Mode Per-Endpoint Registers Structures
++ *
++ * The following structure defines the size and relative field offsets for
++ * the Peripheral Mode Per-Endpoint Registers. There is one set of these
++ * registers for each endpoint that is instantiated in the core.
++ *
++ * - struct dwc_usb3_dev_ep_regs
++ *
++ * @section cil_func_sec Functions
++ *
++ * These are the main functions provided by the CIL.
++ *
++ * - dwc_usb3_pcd_common_init()
++ * - dwc_usb3_pcd_common_remove()
++ * - dwc_usb3_pcd_device_init()
++ * - dwc_usb3_enable_common_interrupts()
++ * - dwc_usb3_enable_device_interrupts()
++ * - dwc_usb3_mode()
++ * - dwc_usb3_is_device_mode()
++ * - dwc_usb3_is_host_mode()
++ * - dwc_usb3_dump_global_registers()
++ * - dwc_usb3_fill_desc()
++ * - dwc_usb3_start_desc_chain()
++ * - dwc_usb3_end_desc_chain()
++ * - dwc_usb3_enable_desc()
++ * - dwc_usb3_xmit_fn_remote_wake()
++ * - dwc_usb3_dep_cfg()
++ * - dwc_usb3_dep_xfercfg()
++ * - dwc_usb3_dep_sstall()
++ * - dwc_usb3_dep_cstall()
++ * - dwc_usb3_dep_startxfer()
++ * - dwc_usb3_dep_updatexfer()
++ * - dwc_usb3_dep_endxfer()
++ * - dwc_usb3_dep_startnewcfg()
++ * - dwc_usb3_enable_ep()
++ * - dwc_usb3_disable_ep()
++ * - dwc_usb3_get_device_speed()
++ * - dwc_usb3_get_frame()
++ * - dwc_usb3_pcd_get_link_state()
++ * - dwc_usb3_pcd_set_link_state()
++ * - dwc_usb3_set_address()
++ * - dwc_usb3_ena_usb2_suspend()
++ * - dwc_usb3_dis_usb2_suspend()
++ * - dwc_usb3_accept_u1()
++ * - dwc_usb3_accept_u2()
++ * - dwc_usb3_enable_u1()
++ * - dwc_usb3_enable_u2()
++ * - dwc_usb3_disable_u1()
++ * - dwc_usb3_disable_u2()
++ * - dwc_usb3_u1_enabled()
++ * - dwc_usb3_u2_enabled()
++ * - dwc_usb3_pcd_remote_wake()
++ */
++
++/**
++ * @page pcd_chapter Peripheral Controller Driver
++ *
++ * The Peripheral Controller Driver (PCD) is responsible for translating
++ * requests from the Function Driver into the appropriate actions on the
++ * DWC_usb3 controller. It isolates the Function Driver from the specifics of
++ * the controller by providing an API to the Function Driver. This API may
++ * vary between operating systems, but it remains constant within a given OS.
++ * Section 4.2 @ref fun_drvr_ifc_sec describes this API for supported
++ * operating systems.
++ *
++ * A USB device responds to commands issued from the host. Section 4.3
++ * @ref std_usb_cmd_proc_sec describes handling of the standard USB
++ * commands within the DWC_usb3 software environment.
++ *
++ * An important function of the PCD is managing interrupts generated by the
++ * DWC_usb3 controller. The behaviors for each DWC_usb3 peripheral mode
++ * interrupt are described in section 4.4 @ref dev_intr_svc_rtn_sec.
++ *
++ * @section pcd_data_st_sec Data Structures
++ *
++ * These are the main data structures used by the PCD.
++ *
++ * @subsection pcd_subsec PCD Data Structure
++ *
++ * The following structure encapsulates the data for the dwc_usb3 PCD.
++ *
++ * - struct dwc_usb3_pcd
++ *
++ * @subsection pcd_ep_subsec Endpoint Data Structure
++ *
++ * The following structure describes an endpoint. There is an array of these
++ * in the PCD structure, one for each endpoint.
++ *
++ * - struct dwc_usb3_pcd_ep
++ *
++ * @subsection ep_subsec Endpoint State Structure
++ *
++ * The following structure represents the state of a single endpoint when
++ * acting in peripheral mode. It contains the data items needed for an endpoint
++ * to be activated and transfer packets. One of these structures is contained
++ * in each dwc_usb3_pcd_ep structure.
++ *
++ * - struct dwc_ep
++ *
++ * @subsection pcd_req_subsec Transfer Request Data Structure
++ *
++ * The following structure describes a transfer request. It is used to form
++ * a list of requests.
++ *
++ * - struct dwc_usb3_pcd_req
++ *
++ * @subsection req_subsec Transfer Request State Structure
++ *
++ * The following structure represents the state of a single transfer request
++ * when acting in peripheral mode. It contains the data items needed for a
++ * request to be started and completed.
++ *
++ * - struct dwc_req
++ *
++ * @subsection dev_dma_subsec DMA Descriptor Structure
++ *
++ * The following structure represents the DMA descriptors used by the dwc_usb3
++ * controller in peripheral mode. These descriptors are also referred to as
++ * Transfer Request Blocks or TRBs (as in the xHCI spec).
++ *
++ * - struct dwc_usb3_dma_desc
++ *
++ * @section fun_drvr_ifc_sec Function Driver Interface
++ *
++ * This section describes the API that the PCD presents to the Function Driver
++ * for each supported operating system. Currently, Linux is the only supported
++ * OS.
++ *
++ * @subsection gadget_api_subsec Linux Gadget API
++ *
++ * The Peripheral Controller Driver for Linux will implement the Gadget API,
++ * so that the existing Gadget drivers can be used. (Gadget Driver is the
++ * Linux terminology for a Function Driver.)
++ *
++ * The Linux Gadget API is defined in the header file <linux/usb_gadget.h>.
++ * The following data structures define the functions implemented in the PCD
++ * to provide the interface. The USB EP operations API is defined in the
++ * structure usb_ep_ops and the USB Controller API is defined in the structure
++ * struct usb_gadget_ops.
++ *
++ * @subsection usb_ep_ops_subsec USB Endpoint Operations
++ *
++ * The following sections briefly describe the behavior of the Gadget API
++ * endpoint operations implemented in the DWC_usb3 driver software. Detailed
++ * descriptions of the generic behavior of each of these functions can be
++ * found in the Linux header file include/linux/usb_gadget.h.
++ *
++ * The Gadget API provides wrapper functions for each of the function pointers
++ * defined in usb_ep_ops. The Gadget Driver calls the wrapper function, which
++ * then calls the underlying PCD function. The following sections are named
++ * according to the wrapper functions. Within each section, the corresponding
++ * DWC_usb3 PCD function name is specified.
++ *
++ * Functions in the API that are not described below are not implemented.
++ *
++ * <strong><em>usb_ep_enable</em></strong>
++ *
++ * - ep_enable()
++ *
++ * <strong><em>usb_ep_disable</em></strong>
++ *
++ * - ep_disable()
++ *
++ * <strong><em>usb_ep_alloc_request</em></strong>
++ *
++ * - alloc_request()
++ *
++ * <strong><em>usb_ep_free_request</em></strong>
++ *
++ * - free_request()
++ *
++ * <strong><em>usb_ep_queue</em></strong>
++ *
++ * - ep_queue()
++ *
++ * <strong><em>usb_ep_dequeue</em></strong>
++ *
++ * - ep_dequeue()
++ *
++ * <strong><em>usb_ep_set_halt, usb_ep_clear_halt</em></strong>
++ *
++ * - ep_set_halt()
++ *
++ * @subsection gadget_ops_subsec Gadget Operations
++ *
++ * The following gadget operations will be implemented in the DWC_usb3 PCD.
++ * Functions in the API that are not described below are not implemented.
++ *
++ * The Gadget API provides wrapper functions for each of the function pointers
++ * defined in usb_gadget_ops. The Gadget Driver calls the wrapper function,
++ * which then calls the underlying PCD function. The following sections are
++ * named according to the wrapper functions. Within each section, the
++ * corresponding DWC_usb3 PCD function name is specified.
++ *
++ * <strong><em>usb_gadget_get_frame</em></strong>
++ *
++ * - dwc_get_frame()
++ *
++ * <strong><em>usb_gadget_wakeup</em></strong>
++ *
++ * - dwc_usb3_wakeup()
++ *
++ * @subsection streams_ext_subsec USB 3.0 Bulk Streams Extension
++ *
++ * USB 3.0 introduces the concept of <em>Bulk Streams</em>. Bulk Streams provide
++ * the ability to move multiple streams of data over a single Bulk endpoint.
++ * This is used by a new version of the Mass Storage Class protocol, called USB
++ * Attached SCSI Protocol (UASP). It allows multiple transfer requests to be
++ * queued up by the Host, which can then be completed in whatever order the data
++ * becomes available from the Peripheral.
++ *
++ * This requires some modifications to the Gadget API and the underlying USB
++ * request functions, to allow the stream capabilities of an endpoint to be set,
++ * and to indicate the stream ID associated with a transfer request. It also
++ * requires a new File Storage gadget which has the needed Bulk Streams support.
++ *
++ * @section std_usb_cmd_proc_sec Standard USB Command Processing
++ *
++ * In Linux, the USB Command processing is done in two places - the first
++ * being the PCD and the second being the Gadget Driver (for example, the
++ * Mass Storage Gadget Driver). See pcd_setup() for a detailed explanation.
++ *
++ * @section dev_intr_svc_rtn_sec Peripheral Interrupt Service Routine
++ *
++ * The PCD handles the peripheral interrupts. Many conditions can cause a
++ * peripheral interrupt. When an interrupt occurs, the peripheral interrupt
++ * service routine determines the cause of the interrupt and dispatches
++ * handling to the appropriate function. These interrupt handling functions
++ * are described below.
++ *
++ * <strong><em>Global Peripheral Interrupts</em></strong>
++ *
++ * - dwc_usb3_handle_dev_intr()
++ * - handle_disconnect_intr()
++ * - handle_usb_reset_intr()
++ * - dwc_usb3_handle_connect_done_intr()
++ * - handle_link_status_change_intr()
++ * - handle_wakeup_detected_intr()
++ * - handle_sof_intr()
++ * - handle_hiber_req_intr()
++ *
++ * <strong><em>Endpoint-Specific Peripheral Interrupts</em></strong>
++ *
++ * - dwc_usb3_handle_ep_intr()
++ *
++ * @section pcd_func_sec Other Functions
++ *
++ * These are the remaining functions provided by the PCD.
++ *
++ * - dwc_usb3_pcd_init()
++ * - dwc_usb3_pcd_remove()
++ * - dwc_usb3_pcd_ep_enable()
++ * - dwc_usb3_pcd_ep_disable()
++ * - dwc_usb3_pcd_ep_submit_req()
++ * - dwc_usb3_pcd_ep_cancel_req()
++ * - dwc_usb3_pcd_ep_set_halt()
++ * - dwc_usb3_pcd_get_frame_number()
++ * - dwc_usb3_ep0_activate()
++ * - dwc_usb3_pcd_ep0_out_start()
++ * - dwc_usb3_stop_all_xfers()
++ * - dwc_usb3_get_out_ep()
++ * - dwc_usb3_get_in_ep()
++ * - dwc_usb3_handle_ep0()
++ * - dwc_usb3_ep_complete_request()
++ * - usb_gadget_register_driver() / usb_gadget_probe_driver()
++ * - usb_gadget_unregister_driver()
++ */
++
++/**
++ * @page hiber_chapter Hibernation
++ *
++ * DWC_usb3 Subsystem Version 2.00a and above implements a new functionality,
++ * hibernation. Hibernation allows power to be removed from most parts of the
++ * controller during periods of inactivity. This is done through a combination
++ * of hardware and software.
++ *
++ * The controller signals a device event when the host has requested a low-power
++ * state suitable for the device to enter hibernation. When this event is
++ * received, the PCD will stop the controller, command it to save critical state
++ * information to main memory, save the content of the CSRs, and then shut off
++ * Vcc power to the core.
++ *
++ * When a condition is detected that requires the core to resume operation, the
++ * driver will receive an interrupt from the monitoring hardware, causing it to
++ * switch Vcc back on, restore the content of the CSRs, and command the
++ * controller to restore its critical state from main memory.
++ *
++ * The bulk of the hibernation code is contained in the files pcd_hiber.c and
++ * linux_hiber.c. Note that this is not a complete implementation; the HAPS
++ * platform on which it has been tested does not provide the normal PCIe PME
++ * mechanism, instead there is special logic in the custom PCIe "gasket" to
++ * handle power control and provide an interrupt to awaken the core from
++ * hibernation. Therefore, the code in linux_hiber.c which handles power
++ * control and wakeup will need to be rewritten for a "real" implementation.
++ * Also, since the CPU is still running while the controller is in the
++ * hibernated state, code has been added to linux_gadget.c to prevent any calls
++ * that would try to touch the controller hardware from entering the driver
++ * while hibernation is active. A "real" implementation should not require this.
++ *
++ * @section hiber_func_sec Hibernation Functions
++ *
++ * These are the functions provided by pcd_hiber.c and linux_hiber.c
++ *
++ * - dwc_enter_hibernation()
++ * - dwc_exit_hibernation_after_connect()
++ * - dwc_exit_hibernation()
++ * - dwc_wait_pme_thread()
++ * - dwc_usb3_handle_pme_intr()
++ * - dwc_usb3_power_ctl()
++ */
++#endif /* _DWC_DOX_H_ */
+diff --git a/drivers/usb/gadget/udc/hiudc3/dox_port.h b/drivers/usb/gadget/udc/hiudc3/dox_port.h
+new file mode 100644
+index 0000000..4cd573e
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc3/dox_port.h
+@@ -0,0 +1,619 @@
++#ifndef _DWC_DOX_PORT_H_
++#define _DWC_DOX_PORT_H_
++
++/**
++ * @file
++ *
++ * image html synopsys.png "Synopsys Logo"
++ * image latex synopsys.eps "Synopsys Logo"
++ *
++ * This file contains the Doxygen comments that create the Porting Guide
++ * document for the driver.
++ *
++ * @page intro_chap Introduction
++ *
++ * This document gives some tips on how to port the DWC_usb3 example drivers to
++ * an operating system other than Linux. This document focuses on the Peripheral
++ * Controller Driver (PCD) in the \a driver/ source directory. The OTG3 and UAS
++ * Gadget drivers in the \a otg3/ and \a gadget/ directories are not covered.
++ *
++ * The PCD source code includes an example platform port in the \a driver/no_os/
++ * directory. \a no_os stands for "No OS", which means the code contains no
++ * OS-specific dependencies at all.
++ *
++ * The \a no_os/ code also contains an implementation of a simple loopback-class
++ * Function Driver. This driver provides one Bulk OUT and one Bulk IN endpoint,
++ * and can either loop all packets received on the OUT endpoint back to the IN
++ * endpoint, or can sink any packets received on the OUT endpoint while
++ * simultaneously sourcing 0-filled packets on the IN endpoint. One of these two
++ * behaviors can be selected at compile time by changing a single line of source
++ * code.
++ *
++ * @page pcd_chap The PCD
++ *
++ * @section pcd_rules_sec Rules When Calling Into the PCD
++ *
++ * - The @ref dwc_usb3_pcd_init API routine in pcd.c must be called from process
++ * context or equivalent, because it uses the @ref dwc_msleep routine to delay
++ * while waiting for the DWC_usb3 core to come out of reset. The same is true
++ * for @ref dwc_usb3_pcd_device_init if its <strong><em>soft_reset</em></strong>
++ * parameter is <strong>true</strong>.
++ *
++ * - To protect against the IRQ handler corrupting core registers or data
++ * structures, interrupts should be disabled before calling any of the
++ * non-initialization routines in the PCD API. In addition, on multiprocessor
++ * platforms a spinlock should also be taken, to protect against two CPUs
++ * running at the same time and causing corruption. The <em>lock</em> field in
++ * struct dwc_usb3_pcd is provided for this purpose.
++ *
++ * - If the above spinlock is used, then it must be released in the @ref
++ * dwc_usb3_gadget_complete API routine before calling any Function Driver
++ * routines which may try to take the spinlock again to call back into the PCD.
++ * The spinlock must be retaken before @ref dwc_usb3_gadget_complete returns.
++ *
++ * @section comp_pcd_sec Porting the PCD
++ *
++ * First, try porting just the PCD code, which is cil.c, cil_intr.c, pcd.c,
++ * pcd_intr.c, pcd_hiber.c, and ep0.c. This code should be easy to port because
++ * it uses very few OS services. The following sections will walk you through
++ * how to do this.
++ *
++ * @subsection os_defs_and_dev_sec Create the os_defs.h and os_dev.h Files
++ *
++ * Create \a os_defs.h and \a os_dev.h files for your platform. You can
++ * either create a subdirectory (e.g. \a driver/myplat/) to contain these
++ * files, and replace the existing \a os_defs.h and \a os_dev.h symlinks with
++ * links to these files, or you can remove the symlinks and create these files
++ * directly in the \a driver/ directory.
++ *
++ * We recommend that you start with the no_os_defs.h and no_os_dev.h files and
++ * modify them as needed for your platform.
++ *
++ * @subsubsection os_defs_sec The os_defs.h File
++ *
++ * The \a os_defs.h file should contain all the \a \#include directives
++ * needed to compile the PCD code on your platform, as well as definitions
++ * needed to provide any missing types etc. that the PCD code requires.
++ *
++ * Specific things that need to be defined here include:
++ * <ul>
++ *  <li> Definitions of the types \a u8, \a u16, \a u32, \a u64, \a u_int8_t,
++ *  \a u_int16_t, \a u_int32_t, \a u_char, \a u_short, \a u_int, and \a
++ *  u_long.
++ *
++ *  <li> Definition of the type \a dwc_dma_t to hold a DMA address for your
++ *  platform. This must be an integral type, not a pointer.
++ *
++ *  <li> Definition of the \a UPACKED attribute for the compiler. If you are
++ *  using GCC, or ARMCC with the \a --gnu flag, this should be:
++ *  <code><p> &nbsp;&nbsp;&nbsp; \#define UPACKED __attribute__ ((__packed__))
++ *  </p></code>
++ *
++ *  <p> If you are using a Microsoft compiler, you should define this to
++ *  nothing: </p>
++ *  <code><p> &nbsp;&nbsp;&nbsp; \#define UPACKED </p></code>
++ *
++ *  <p> The \a \#include&nbsp;<pshpack1.h> and \a \#include&nbsp;<poppack.h>
++ *  directives, as shown in the usb.h file, handle structure packing for
++ *  Microsoft compilers. </p>
++ *
++ *  <p> If you are using some other compiler, check the compiler manual to see
++ *  how to accomplish this. </p>
++ *
++ *  <li> Definition of the \a __iomem data attribute. For any platform except
++ *  Linux, this should be defined to nothing:
++ *  <code><p> &nbsp;&nbsp;&nbsp; \#define __iomem </p></code>
++ *
++ *  <li> Definition of the @ref wmb macro (write memory barrier). For
++ *  uniprocessor platforms, this can be defined to a null function. For
++ *  multiprocessor platforms, the definition of this macro is highly
++ *  platform-dependent.
++ *
++ *  <p> This macro is only used by the DWC_usb3 hibernation code, so
++ *  if you are not using the hibernation feature you can safely
++ *  define it to a null function: </p>
++ *  <code><p> &nbsp;&nbsp;&nbsp; \#define wmb() do {} while (0) </p></code>
++ *
++ *  <li> Definitions of the usb_request and usb_ep data types. The content of
++ *  these structures is completely user-defined, but they must be defined here
++ *  because the PCD embeds them into its own request and endpoint structures.
++ *  This allows them to be passed back to the platform code when the PCD
++ *  completes a USB transfer.
++ *
++ *  <li> Definitions of all the \a DWC_E_* error codes that the PCD uses. If
++ *  your platform uses POSIX error codes, they can be easily mapped to the
++ *  \a DWC_E_* error codes.
++ *
++ *  <p> The only error codes with any operational significance are \a
++ *  DWC_E_NOT_SUPPORTED, \a DWC_E_IN_PROGRESS, and \a DWC_E_SHUTDOWN, so these
++ *  three error codes must be distinct, while the rest can be mapped to a
++ *  single value if so desired. </p>
++ *
++ *  <p> See the no_os_defs.h file for a complete list of the DWC_E_* error
++ *  codes. </p>
++ *
++ *  <li> Definition of the dwc_usb3_core_params struct. This contains an entry
++ *  for each option that the PCD driver supports. It is defined here so that you
++ *  can add additional options for your platform code if you wish. See the
++ *  no_os_defs.h file for a minimal implementation of this structure.
++ * </ul>
++ *
++ * @subsubsection os_dev_sec The os_dev.h File
++ *
++ * Because the \a os_defs.h file is included first by the PCD code, it does not
++ * have access to any of the definitions in the PCD header files. Therefore, any
++ * of your definitions which need such access should be placed in the \a
++ * os_dev.h file instead, which is included last by the PCD code. Specific
++ * things that need to be defined here include:
++ * <ul>
++ *  <li> Definitions of the @ref dwc_rd32 and @ref dwc_wr32 inline functions.
++ *  Given an offset from the beginning of the DWC_usb3 core address space to a
++ *  particular register, these functions read from or write to that register.
++ *
++ *  <li> Definitions of the @ref dwc_usb3_get_pcd_req and @ref dwc_usb3_get_pcd_ep
++ *  macros. Given a pointer to a usb_request or usb_ep, these macros return a
++ *  pointer to the enclosing dwc_usb3_pcd_req or dwc_usb3_pcd_ep struct. For
++ *  any compiler that provides the \a offsetof macro, these should be:
++ *  <code>
++ *  <p> &nbsp;&nbsp;&nbsp; \#define dwc_usb3_get_pcd_req(usbreq)&nbsp;\\ \n
++ *  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
++ *  ((dwc_usb3_pcd_req_t *)((char *)(usbreq)&nbsp;-&nbsp;\\ \n
++ *  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
++ *  offsetof(struct dwc_usb3_pcd_req, usb_req))) </p>
++ *  <p> &nbsp; </p>
++ *  <p> &nbsp;&nbsp;&nbsp; \#define dwc_usb3_get_pcd_ep(usbep)&nbsp;\\ \n
++ *  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
++ *  ((dwc_usb3_pcd_ep_t *)((char *)(usbep)&nbsp;-&nbsp;\\ \n
++ *  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
++ *  offsetof(struct dwc_usb3_pcd_ep, usb_ep))) </p>
++ *  </code>
++ *
++ *  <li> Definitions of the @ref dwc_udelay and @ref dwc_mdelay non-sleeping delay
++ *  routines. Given a delay value in microseconds or milliseconds respectively,
++ *  these routines must delay for at least as long as the delay value.
++ *  Non-sleeping means these routines may be called from any context, including
++ *  interrupt context, so they must not reschedule or require an interrupt to
++ *  indicate the end of the delay. Typically these routines would be implemented
++ *  using a calibrated busy loop or a dedicated hardware timer.
++ *
++ *  <li> Definition of the @ref dwc_msleep sleeping delay routine. Given a delay
++ *  value in milliseconds, this routine must delay for at least as long as the
++ *  delay value. Sleeping means this routine will only be called from process
++ *  context, so it can reschedule or require an interrupt to indicate the end of
++ *  the delay. Typically this routine would be implemented using a system timer.
++ *
++ *  <li> Definitions of the @ref dwc_print\<n\>, @ref dwc_error\<n\>, @ref
++ *  dwc_warn\<n\>, @ref dwc_info\<n\>, @ref dwc_isocdbg\<n\>, and @ref dwc_debug\<n\>
++ *  logging routines.
++ *  Given a \a printf style format string and the number of arguments indicated
++ *  by the last digit of the routine's name, they print a message to the system
++ *  message log, or to the console.
++ *
++ *  <p> The different routine names indicate the importance of the message,
++ *  where @ref dwc_print\<n\> is the highest importance and @ref dwc_debug\<n\>
++ *  is the lowest. </p>
++ *
++ *  <p> Typically these routines would be implemented using a \a printf type
++ *  function if one is available, but the explicit argument count means they
++ *  can be implemented without needing a \a varargs facility, if necessary. </p>
++ * </ul>
++ *
++ * @subsection modify_pcd_h_sec Modify the pcd.h File
++ *
++ * The pcd.h file contains a few platform-dependent definitions, and may need
++ * some minor modifications to work on your platform:
++ * <ul>
++ *  <li> dwc_usb3_pcd_req contains an \a entry field, which is used to link a
++ *  request into the queue of requests for an endpoint. If your platform will
++ *  use request queuing, then this field may need to be modified.
++ *
++ *  <p> Since the \a entry field is not used by the PCD, it can be commented out
++ *  for the purpose of test-compiling the PCD. </p>
++ *
++ *  <li> dwc_ep contains a \a queue field, which is the head of the request
++ *  queue for an endpoint. Again, this field may need to be modified for your
++ *  platform, or it can be commented out for the purpose of test-compiling the
++ *  PCD.
++ *
++ *  <li> dwc_usb3_pcd contains a \a lock field, which is used for protecting
++ *  the driver data from simultaneous access by multiple processors. If your
++ *  platform is uniprocessor, then this field is not needed and you can comment
++ *  it out, otherwise it may need to be modified for your platform.
++ *
++ *  <p> Since the \a lock field is not used by the PCD, it can be commented out
++ *  for the purpose of test-compiling the PCD. </p>
++ * </ul>
++ *
++ * @subsection makefile_or_project_sec Create the Makefile / Project File
++ *
++ * Create a makefile / project file for your platform, and add \a cil.o, \a
++ * cil_intr.o, \a pcd.o, \a pcd_intr.o, \a pcd_hiber.o, and \a ep0.o as the
++ * target object files. Because the result will not link successfully yet due
++ * to missing Function Driver routines, you should omit the link step, if
++ * possible.
++ *
++ * @subsection test_compile_sec Test Compile the PCD
++ *
++ * <p> Now try compiling your project. </p>
++ *
++ * <p> If there are errors during the compile phase, you must modify your \a
++ * os_defs.h and \a os_dev.h files, and/or pcd.h, to attempt to eliminate them.
++ * </p>
++ *
++ * <p> You may need to modify some of the other PCD source files to achieve a
++ * successful compile. For example, your compiler may require a different method
++ * of packing data structures, which may require you to modify usb.h. </p>
++ *
++ * <p> If there are warnings during the compile phase, you should investigate
++ * each one carefully to determine whether it signifies a real problem or not.
++ * </p>
++ *
++ * <p> If your makefile / project file contains a link step, you should expect
++ * it to fail, since at this point all of the Function Driver routines are
++ * missing. </p>
++ *
++ * <p> If there are no errors or warnings during the compile phase, then the
++ * initial porting phase is complete. </p>
++ *
++ * @page func_drvr_chap The Function Driver
++ *
++ * Porting the Function Driver is not as straightforward as the PCD, because
++ * there are more external factors to take into account.
++ *
++ * Because of this, we have provided the No-OS platform port. This port needs
++ * minimal support from the operating environment, and is designed to run as
++ * close to the hardware as possible. It is also self-contained, implementing
++ * its own Function Driver, so no OS support for USB functions is required.
++ *
++ * The Function implements a simple loopback test mode, where any data received
++ * from the host on the OUT endpoint is sent back to the host on the IN
++ * endpoint. Or, by changing the second line in
++ * no_os_src_sink_lpbk.c:dwc_usb3_function_init() to this:
++ *
++ * <code><p>&nbsp;&nbsp;&nbsp; loopbk.src_sink = 1; </p></code>
++ *
++ * the Function will implement a source/sink test mode, which sinks any packets
++ * received on the OUT endpoint while simultaneously sourcing 0-filled packets
++ * on the IN endpoint.
++ *
++ * The major limitation of the No-OS port is that all DMA data structures are
++ * statically allocated in the C code. This will only work in very simple
++ * operating environments where the system memory is mapped with virtual
++ * address == physical address. If you have an environment where this is not the
++ * case, then at a minimum you will need to replace these static allocations
++ * with calls to OS routines to perform proper DMA allocations.
++ *
++ * To help while debugging the No-OS port, we have included Linux code that is
++ * conditionally compiled if the LINUXTEST macro is defined. This allows the
++ * No-OS code to compile and run on a Linux platform, as a completely
++ * self-contained driver that does not use the Linux Gadget framework. The
++ * No-OS port can be built for Linux in this way by invoking "make" as follows:
++ *
++ * <code><p>&nbsp;&nbsp;&nbsp; make NOOS=1 </p></code>
++ *
++ * The no_os/ platform code consists of the following files:
++ *
++ * - no_os_init.c: Initialization code and "bus glue".
++ * - no_os_gadget.c: Implements a custom Function Driver API.
++ * - no_os_ep0.c: Contains the USB descriptors for the Function.
++ * - no_os_src_sink_lpbk.c: Contains an implementation of a simple
++ *   source-sink/loopback Function.
++ * - no_os_hiber.c: Implements the platform-specific code needed to support the
++ *   DWC_usb3 hibernation feature. Note: This code is incomplete, so you should
++ *   consider DWC_usb3 hibernation as unsupported by the No-OS Function Driver
++ *   at this time.
++ *
++ * @section func_walk_sec Code Walkthrough of the No-OS Function Driver
++ *
++ * @subsection func_init_sec Initialization
++ *
++ * At initialization time, @ref dwc_usb3_driver_init in no_os_init.c is called,
++ * which does the following:
++ * - Allocates memory for the \a usb3_dev driver data struct.
++ * - Maps the DWC_usb3 registers into the processor's memory space.
++ * - Calls the @ref dwc_usb3_pcd_check_snpsid API routine to make sure this is a
++ *   DWC_usb3 device, and to save the value from the SNPSID register in the
++ *   \a usb3_dev struct.
++ * - Allocates DMAable memory for the event buffer, and for the EP0 DMA
++ *   descriptors and data buffers.
++ * - Calls the @ref dwc_usb3_pcd_common_init API routine.
++ * - Calls the @ref dwc_usb3_gadget_init API routine in no_os_gadget.c, which
++ *   does the following:
++ *   - Sets the dwc_ep.num field for each physical endpoint to the USB endpoint
++ *     number associated with that endpoint.
++ *   - Initializes the dwc_ep.queue field for each physical endpoint. This is
++ *     the head of the queue where each transfer request for that endpoint will
++ *     be queued.
++ * - Calls @ref dwc_usb3_function_init in no_os_src_sink_lpbk.c, which allocates
++ *   data buffers for each Bulk endpoint.
++ * - Calls the @ref dwc_usb3_pcd_init API routine.
++ * - Hooks the @ref dwc_usb3_common_irq top-level interrupt handler routine to
++ *   the DWC_usb3 IRQ vector.
++ *
++ * At this point the DWC_usb3 core and the driver are initialized, and waiting
++ * for the Device to be connected to a Host.
++ *
++ * @subsection func_conn_enum_sec Connection and Enumeration
++ *
++ * When a connection to a Host is established, a <strong>USBRst</strong> event
++ * is generated, followed by a <strong>ConnectDone</strong> event.
++ *
++ * The <strong>USBRst</strong> event is handled internally by the PCD.
++ *
++ * The <strong>ConnectDone</strong> event results in the following:
++ * - The PCD calls the @ref dwc_usb3_gadget_connect API routine in no_os_gadget.c.
++ * - @ref dwc_usb3_gadget_connect in turn calls @ref dwc_usb3_function_connect
++ *   in no_os_src_sink_lpbk.c.
++ * - @ref dwc_usb3_function_connect sets the function's Bulk max packet size
++ *   according to the connection speed.
++ *
++ * Once the connection sequence completes, the Host starts sending Control
++ * requests to the Device to enumerate it. The general flow for Control requests
++ * is as follows:
++ * - The PCD code in ep0.c handles most Control requests internally.
++ * - For those requests it cannot handle, the PCD calls the
++ *   @ref dwc_usb3_gadget_setup API routine in no_os_gadget.c.
++ * - @ref dwc_usb3_gadget_setup in turn calls @ref dwc_usb3_no_os_setup in
++ *   no_os_ep0.c.
++ * - @ref dwc_usb3_no_os_setup handles <strong>GET_DESCRIPTOR</strong> Control
++ *   requests (except for the BOS descriptor, which is handled by ep0.c), using
++ *   the information encoded in the USB descriptors in no_os_ep0.c. See @ref
++ *   usb_desc_sec for details.
++ * - For all remaining Control requests, the no_os_ep0.c code calls @ref
++ *   dwc_usb3_function_setup in no_os_src_sink_lpbk.c.
++ *
++ * @subsection func_config_sec Configuration
++ *
++ * Once the Host has enumerated the Device, it will configure it as follows:
++ * - The host sends a <strong>SET_CONFIGURATION</strong> Control request with a
++ *   <strong>bConfigurationValue</strong> of <strong>1</strong> (since that is
++ *   the value given in the Config descriptors in no_os_ep0.c), followed by a
++ *   <strong>SET_INTERFACE</strong> Control request with a
++ *   <strong>bInterfaceNumber</strong> of <strong>0</strong> and a
++ *   <strong>bAlternateSetting</strong> of <strong>0</strong> (since those are
++ *   the values given in the Interface descriptors in no_os_ep0.c).
++ * - <strong>SET_CONFIGURATION</strong> and <strong>SET_INTERFACE</strong> are
++ *   two of the Control requests that are handled by @ref dwc_usb3_function_setup
++ *   in no_os_src_sink_lpbk.c, so that routine will be called.
++ * - @ref dwc_usb3_function_setup in turn calls @ref set_interface (in the same file)
++ *   with an <strong><em>alt</em></strong> parameter of <strong>0</strong>.
++ * - @ref set_interface calls @ref enable_eps (in the same file).
++ * - @ref enable_eps calls @ref dwc_usb3_ep_enable in no_os_gadget.c for each of
++ *   the Bulk endpoints, with pointers to the USB descriptors from no_os_ep0.c
++ *   corresponding to the speed of the connection.
++ * - @ref dwc_usb3_ep_enable does the following:
++ *   - Gets the endpoint info from the Endpoint descriptor for that EP.
++ *   - Decides how many TRBs to allocate for the EP.
++ *   - Calls the @ref dwc_usb3_pcd_trb_alloc API routine to allocate the TRBs.
++ *     Note: @ref dwc_usb3_pcd_trb_alloc will call back to the @ref
++ *     dwc_usb3_gadget_alloc_dma API routine in no_os_gadget.c to do the
++ *     memory allocation.
++ *   - Calls the @ref dwc_usb3_pcd_ep_enable API routine to enable the endpoint
++ *     in the DWC_usb3 core.
++ * - @ref set_interface then calls @ref dwc_usb3_alloc_request in no_os_gadget.c
++ *   repeatedly, to allocate a number of transfer requests for each of the Bulk
++ *   endpoints.
++ * - @ref dwc_usb3_alloc_request does the following:
++ *   - Allocates a PCD request from the gadget's pool of requests.
++ *   - Returns a pointer to the usb_request member of the PCD request.
++ * - @ref set_interface then fills in a number of fields in each usb_request,
++ *   among them the \a complete function pointer, then calls @ref dwc_usb3_ep_queue
++ *   in no_os_gadget.c to queue it for transfer.
++ * - @ref dwc_usb3_ep_queue does the following:
++ *   - Sets the usb_request \a status field to -DWC_E_IN_PROGRESS.
++ *   - Fills in a number of required fields in the PCD request.
++ *   - Decides whether to start the request immediately, or to queue it to be
++ *     started later. If it decides to start the request immediately, it:
++ *     - Calls the @ref dwc_usb3_pcd_fill_trbs API routine to fill in the TRB
++ *       for the request.
++ *     - Calls the @ref dwc_usb3_pcd_ep_submit_req API routine to start the
++ *       transfer in the DWC_usb3 core.
++ *   - Adds the request to the endpoint's request queue.
++ *
++ * At this point the Device is in the Configured state, ready to receive Bulk
++ * transfers from the Host.
++ *
++ * @subsection func_oper_sec Operation
++ *
++ * When the Host requests a Bulk data transfer to or from the Device, the PCD
++ * will receive a <strong>XferComplete</strong> event from the DWC_usb3 core
++ * when the transfer completes. This will result in the following:
++ * - The PCD calls the @ref dwc_usb3_gadget_get_request API routine in
++ *   no_os_gadget.c.
++ * - @ref dwc_usb3_gadget_get_request returns the request that is at the head of
++ *   the endpoint's request queue. This will be the request whose transfer has
++ *   just completed.
++ * - The PCD then calls the @ref dwc_usb3_gadget_complete API routine in
++ *   no_os_gadget.c.
++ * - @ref dwc_usb3_gadget_complete removes the request from the endpoint's queue,
++ *   fills in the \a status and \a actual fields in the usb_request, and calls
++ *   the \a complete function pointer in the usb_request.
++ * - The \a complete function pointer points to @ref loopbk_complete in
++ *   no_os_src_sink_lpbk.c, which does the following:
++ *   - Checks the \a status field in the usb_request. If it is not
++ *     <strong>0</strong> then an error or a disconnect occurred, which are
++ *     handled appropriately.
++ *   - If the \a status field is <strong>0</strong>, then the endpoint is
++ *     checked. If it is the OUT EP, @ref dwc_usb3_ep_queue in no_os_gadget.c is
++ *     called to requeue the usb_request on the IN EP for sending the data back
++ *     to the host. If it is the IN EP, @ref dwc_usb3_ep_queue is called to requeue
++ *     the usb_request on the OUT EP for receiving more data from the host.
++ * - The PCD then calls the @ref dwc_usb3_gadget_start_next_request API routine
++ *   in no_os_gadget.c.
++ * - If there are any more requests queued for the endpoint,
++ *   @ref dwc_usb3_gadget_start_next_request takes the first one and does the
++ *   following:
++ *   - Calls the @ref dwc_usb3_pcd_fill_trbs API routine to fill in the TRB for
++ *     the request.
++ *   - Calls the @ref dwc_usb3_pcd_ep_submit_req API routine to start the
++ *     transfer in the DWC_usb3 core.
++ *
++ * @section usb_desc_sec USB Descriptors
++ *
++ * no_os_ep0.c contains a minimal set of USB descriptors - a set of String
++ * descriptors, a Device descriptor, a Device Qualifier descriptor, and three
++ * Configuration descriptors, one for each of the speeds that the DWC_usb3 core
++ * supports. Each of the Configuration descriptors contains two Endpoint
++ * descriptors, one for a Bulk IN endpoint and one for a Bulk OUT endpoint. The
++ * Super Speed Configuration descriptor also contains two Super Speed Endpoint
++ * Companion descriptors, one for each of the Bulk endpoints. All of these
++ * descriptors may need to be modified for your platform's particular Function
++ * implementation.
++ *
++ * ep0.c contains the required BOS descriptor. Fields that must be modified here
++ * are \a bU1DevExitLat and \a wU2DevExitLat in the Super Speed Device
++ * Capability descriptor, and \a containerID in the optional Container ID
++ * Capability descriptor (if used).
++ *
++ * The compiler must be instructed not to add padding between the fields in any
++ * of these descriptors. This is the purpose of the \a UPACKED attribute macro
++ * for the GCC compiler (or the ARMCC compiler with the \a --gnu flag). The
++ * \a \#include&nbsp;<pshpack1.h> and \a \#include&nbsp;<poppack.h> directives,
++ * as shown in usb.h and no_os_ep0.c, accomplish the same thing for the
++ * Microsoft compilers.
++ *
++ * The exact format for all of these descriptors is described in detail in
++ * Chapter 9 of the USB 3.0 specification.
++ *
++ * @section comp_func_sec Porting the No-OS Function Driver
++ *
++ * Copy all the .c files from the \a driver/no_os/ directory into the platform
++ * directory that you created earlier to hold your \a os_defs.h and \a os_dev.h
++ * files (e.g. \a driver/myplat/). Rename all the .c files accordingly (e.g.
++ * \a no_os_init.c -> \a myplat_init.c, \a no_os_gadget.c -> \a myplat_gadget.c
++ * ...).
++ *
++ * Modify the source code as necessary to work on your platform.
++ *
++ * Modify the makefile / project file for your platform and add e.g. \a
++ * myplat_init.o, \a myplat_gadget.o ... to the target object files. You should
++ * also add a link step if one does not exist already.
++ *
++ * Now try compiling your project. As with @ref test_compile_sec, you must
++ * modify the source files as necessary until the compile phase completes
++ * successfully.
++ *
++ * Once the compile phase is successful, try to resolve any errors that occur
++ * in the link phase. Most likely these will be due to missing support routines,
++ * such as \a memcpy or \a printf. You must either add libraries to the link step
++ * to provide these routines, write your own routines and include them in the
++ * build, or modify the driver source files to use alternate versions of these
++ * routines.
++ *
++ * @page pcd_api_chap PCD to Function Driver API
++ *
++ * @section pcd_funcs_sec API Routines in the PCD
++ *
++ * These routines are provided by the PCD (and the CIL), and make up the PCD
++ * side of the API.
++ *
++ * @subsection init_funcs_sec Initialization Routines
++ *
++ * These routines handle initialization of the CIL and PCD driver components
++ * and the DWC_usb3 core.
++ *
++ * See @ref init_api_grp for a detailed description of these routines.
++ *
++ * - dwc_usb3_pcd_check_snpsid()
++ * - dwc_usb3_pcd_common_init()
++ * - dwc_usb3_pcd_common_remove()
++ * - dwc_usb3_pcd_init()
++ * - dwc_usb3_pcd_remove()
++ * - dwc_usb3_pcd_device_init()
++ * - dwc_usb3_pcd_device_remove()
++ *
++ * @subsection trb_funcs_sec TRB Routines
++ *
++ * These routines handle the allocation, deallocation, and setup of TRBs.
++ *
++ * See @ref trb_api_grp for a detailed description of these routines.
++ *
++ * - dwc_usb3_pcd_trb_alloc()
++ * - dwc_usb3_pcd_trb_free()
++ * - dwc_usb3_pcd_fill_trbs()
++ *
++ * @subsection ep_funcs_sec Endpoint Routines
++ *
++ * These routines handle all the functionality required for configuring,
++ * enabling, controlling, and submitting transfers to an endpoint.
++ *
++ * Note: For Control endpoint 0, only the submit_req, cancel_req, request_done,
++ * and set_halt routines are used; the remaining functionality is handled either
++ * by the @ref ep0_funcs_sec below or internally by the PCD.
++ *
++ * See @ref ep_api_grp for a detailed description of these routines.
++ *
++ * - dwc_usb3_pcd_ep_enable()
++ * - dwc_usb3_pcd_ep_disable()
++ * - dwc_usb3_pcd_ep_submit_req()
++ * - dwc_usb3_pcd_ep_cancel_req()
++ * - dwc_usb3_pcd_request_done()
++ * - dwc_usb3_pcd_ep_start_transfer()
++ * - dwc_usb3_pcd_ep_set_stall()
++ * - dwc_usb3_pcd_ep_clear_stall()
++ * - dwc_usb3_pcd_ep_set_halt()
++ *
++ * @subsection ep0_funcs_sec Control Endpoint 0 Routines
++ *
++ * These routines are only used for Control endpoint 0.
++ *
++ * See @ref ep0_api_grp for a detailed description of these routines.
++ *
++ * - dwc_usb3_pcd_ep0_out_start()
++ * - dwc_usb3_pcd_ep0_start_transfer()
++ * - dwc_usb3_pcd_ep0_continue_transfer()
++ * - dwc_usb3_pcd_ep0_data_stage()
++ *
++ * @subsection misc_funcs_sec Miscellaneous Routines
++ *
++ * These are miscellaneous routines that don't fit into any of the other
++ * categories.
++ *
++ * See @ref misc_api_grp for a detailed description of these routines.
++ *
++ * - dwc_usb3_pcd_get_ep_by_addr()
++ * - dwc_usb3_pcd_get_frame_number()
++ * - dwc_usb3_pcd_isoc_ep_hiber_restart()
++ * - dwc_usb3_pcd_stop()
++ * - dwc_usb3_pcd_get_link_state()
++ * - dwc_usb3_pcd_set_link_state()
++ * - dwc_usb3_pcd_remote_wake()
++ * - dwc_usb3_pcd_do_test_mode()
++ *
++ * @section gadget_funcs_sec API Routines in the Function Driver
++ *
++ * These routines need to be implemented by the platform code, and make up the
++ * Function Driver side of the API.
++ *
++ * @subsection gadget_notif_sec Function Driver Notification Routines
++ *
++ * These routines receive notifications from the PCD when certain events occur
++ * which the Function Driver may need to be aware of.
++ *
++ * See @ref gadget_notif_grp for a detailed description of these routines.
++ *
++ * - dwc_usb3_gadget_connect()
++ * - dwc_usb3_gadget_disconnect()
++ * - dwc_usb3_gadget_suspend()
++ * - dwc_usb3_gadget_resume()
++ * - dwc_usb3_gadget_setup()
++ * - dwc_usb3_gadget_complete()
++ *
++ * @subsection gadget_callbk_sec Function Driver Callback Routines
++ *
++ * The PCD calls these routines when it needs something from the Function
++ * Driver.
++ *
++ * See @ref gadget_callbk_grp for a detailed description of these routines.
++ *
++ * - dwc_usb3_gadget_alloc_dma()
++ * - dwc_usb3_gadget_free_dma()
++ * - dwc_usb3_gadget_get_request()
++ * - dwc_usb3_gadget_start_next_request()
++ * - dwc_usb3_gadget_isoc_ep_start()
++ * - dwc_usb3_gadget_request_nuke()
++ * - dwc_usb3_gadget_set_ep_not_started()
++ *
++ */
++
++#endif /* _DWC_DOX_PORT_H_ */
+diff --git a/drivers/usb/gadget/udc/hiudc3/driver.sln b/drivers/usb/gadget/udc/hiudc3/driver.sln
+new file mode 100644
+index 0000000..849a645
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc3/driver.sln
+@@ -0,0 +1,20 @@
++
++Microsoft Visual Studio Solution File, Format Version 12.00
++# Visual Studio 11
++Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "driver", "driver.vcxproj", "{876C75FB-DB73-46F3-9ED0-92D9FA45FCA4}"
++EndProject
++Global
++	GlobalSection(SolutionConfigurationPlatforms) = preSolution
++		Debug|Win32 = Debug|Win32
++		Release|Win32 = Release|Win32
++	EndGlobalSection
++	GlobalSection(ProjectConfigurationPlatforms) = postSolution
++		{876C75FB-DB73-46F3-9ED0-92D9FA45FCA4}.Debug|Win32.ActiveCfg = Debug|Win32
++		{876C75FB-DB73-46F3-9ED0-92D9FA45FCA4}.Debug|Win32.Build.0 = Debug|Win32
++		{876C75FB-DB73-46F3-9ED0-92D9FA45FCA4}.Release|Win32.ActiveCfg = Release|Win32
++		{876C75FB-DB73-46F3-9ED0-92D9FA45FCA4}.Release|Win32.Build.0 = Release|Win32
++	EndGlobalSection
++	GlobalSection(SolutionProperties) = preSolution
++		HideSolutionNode = FALSE
++	EndGlobalSection
++EndGlobal
+diff --git a/drivers/usb/gadget/udc/hiudc3/driver.vcxproj b/drivers/usb/gadget/udc/hiudc3/driver.vcxproj
+new file mode 100644
+index 0000000..b6d357d
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc3/driver.vcxproj
+@@ -0,0 +1,91 @@
++<?xml version="1.0" encoding="utf-8"?>
++<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
++  <ItemGroup Label="ProjectConfigurations">
++    <ProjectConfiguration Include="Debug|Win32">
++      <Configuration>Debug</Configuration>
++      <Platform>Win32</Platform>
++    </ProjectConfiguration>
++    <ProjectConfiguration Include="Release|Win32">
++      <Configuration>Release</Configuration>
++      <Platform>Win32</Platform>
++    </ProjectConfiguration>
++  </ItemGroup>
++  <PropertyGroup Label="Globals">
++    <VCTargetsPath Condition="'$(VCTargetsPath11)' != '' and '$(VSVersion)' == '' and '$(VisualStudioVersion)' == ''">$(VCTargetsPath11)</VCTargetsPath>
++  </PropertyGroup>
++  <PropertyGroup Label="Globals">
++    <ProjectGuid>{876C75FB-DB73-46F3-9ED0-92D9FA45FCA4}</ProjectGuid>
++    <RootNamespace>driver</RootNamespace>
++  </PropertyGroup>
++  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
++  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
++    <ConfigurationType>Application</ConfigurationType>
++    <UseDebugLibraries>true</UseDebugLibraries>
++    <PlatformToolset>v110</PlatformToolset>
++    <CharacterSet>MultiByte</CharacterSet>
++  </PropertyGroup>
++  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
++    <ConfigurationType>Application</ConfigurationType>
++    <UseDebugLibraries>false</UseDebugLibraries>
++    <PlatformToolset>v110</PlatformToolset>
++    <WholeProgramOptimization>true</WholeProgramOptimization>
++    <CharacterSet>MultiByte</CharacterSet>
++  </PropertyGroup>
++  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
++  <ImportGroup Label="ExtensionSettings">
++  </ImportGroup>
++  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
++    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
++  </ImportGroup>
++  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
++    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
++  </ImportGroup>
++  <PropertyGroup Label="UserMacros" />
++  <PropertyGroup />
++  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
++    <ClCompile>
++      <WarningLevel>Level3</WarningLevel>
++      <Optimization>Disabled</Optimization>
++      <AdditionalIncludeDirectories>$(ProjectDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
++    </ClCompile>
++    <Link>
++      <GenerateDebugInformation>true</GenerateDebugInformation>
++    </Link>
++  </ItemDefinitionGroup>
++  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
++    <ClCompile>
++      <WarningLevel>Level3</WarningLevel>
++      <Optimization>MaxSpeed</Optimization>
++      <FunctionLevelLinking>true</FunctionLevelLinking>
++      <IntrinsicFunctions>true</IntrinsicFunctions>
++      <AdditionalIncludeDirectories>$(ProjectDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
++    </ClCompile>
++    <Link>
++      <GenerateDebugInformation>true</GenerateDebugInformation>
++      <EnableCOMDATFolding>true</EnableCOMDATFolding>
++      <OptimizeReferences>true</OptimizeReferences>
++    </Link>
++  </ItemDefinitionGroup>
++  <ItemGroup>
++    <ClInclude Include="cil.h" />
++    <ClInclude Include="dev.h" />
++    <ClInclude Include="hw.h" />
++    <ClInclude Include="os_defs.h" />
++    <ClInclude Include="os_dev.h" />
++    <ClInclude Include="pcd.h" />
++    <ClInclude Include="usb.h" />
++  </ItemGroup>
++  <ItemGroup>
++    <ClCompile Include="cil.c" />
++    <ClCompile Include="cil_intr.c" />
++    <ClCompile Include="ep0.c" />
++    <ClCompile Include="pcd.c" />
++    <ClCompile Include="pcd_hiber.c" />
++    <ClCompile Include="pcd_intr.c" />
++    <ClCompile Include="win\win_gadget.c" />
++    <ClCompile Include="win\win_hiber.c" />
++  </ItemGroup>
++  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
++  <ImportGroup Label="ExtensionTargets">
++  </ImportGroup>
++</Project>
+\ No newline at end of file
+diff --git a/drivers/usb/gadget/udc/hiudc3/driver.vcxproj.filters b/drivers/usb/gadget/udc/hiudc3/driver.vcxproj.filters
+new file mode 100644
+index 0000000..b25fc0c
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc3/driver.vcxproj.filters
+@@ -0,0 +1,66 @@
++<?xml version="1.0" encoding="utf-8"?>
++<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
++  <ItemGroup>
++    <Filter Include="Source Files">
++      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
++      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
++    </Filter>
++    <Filter Include="Header Files">
++      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
++      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
++    </Filter>
++    <Filter Include="Resource Files">
++      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
++      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
++    </Filter>
++  </ItemGroup>
++  <ItemGroup>
++    <ClInclude Include="cil.h">
++      <Filter>Header Files</Filter>
++    </ClInclude>
++    <ClInclude Include="dev.h">
++      <Filter>Header Files</Filter>
++    </ClInclude>
++    <ClInclude Include="hw.h">
++      <Filter>Header Files</Filter>
++    </ClInclude>
++    <ClInclude Include="os_defs.h">
++      <Filter>Header Files</Filter>
++    </ClInclude>
++    <ClInclude Include="os_dev.h">
++      <Filter>Header Files</Filter>
++    </ClInclude>
++    <ClInclude Include="pcd.h">
++      <Filter>Header Files</Filter>
++    </ClInclude>
++    <ClInclude Include="usb.h">
++      <Filter>Header Files</Filter>
++    </ClInclude>
++  </ItemGroup>
++  <ItemGroup>
++    <ClCompile Include="cil.c">
++      <Filter>Source Files</Filter>
++    </ClCompile>
++    <ClCompile Include="cil_intr.c">
++      <Filter>Source Files</Filter>
++    </ClCompile>
++    <ClCompile Include="ep0.c">
++      <Filter>Source Files</Filter>
++    </ClCompile>
++    <ClCompile Include="pcd.c">
++      <Filter>Source Files</Filter>
++    </ClCompile>
++    <ClCompile Include="pcd_hiber.c">
++      <Filter>Source Files</Filter>
++    </ClCompile>
++    <ClCompile Include="pcd_intr.c">
++      <Filter>Source Files</Filter>
++    </ClCompile>
++    <ClCompile Include="win\win_gadget.c">
++      <Filter>Source Files</Filter>
++    </ClCompile>
++    <ClCompile Include="win\win_hiber.c">
++      <Filter>Source Files</Filter>
++    </ClCompile>
++  </ItemGroup>
++</Project>
+\ No newline at end of file
+diff --git a/drivers/usb/gadget/udc/hiudc3/dwc_list.h b/drivers/usb/gadget/udc/hiudc3/dwc_list.h
+new file mode 100644
+index 0000000..9224bd6
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc3/dwc_list.h
+@@ -0,0 +1,468 @@
++/*	$OpenBSD: queue.h,v 1.26 2004/05/04 16:59:32 grange Exp $	*/
++/*	$NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $	*/
++
++/*
++ * Copyright (c) 1991, 1993
++ *	The Regents of the University of California.  All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. Neither the name of the University nor the names of its contributors
++ *    may be used to endorse or promote products derived from this software
++ *    without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++ * SUCH DAMAGE.
++ *
++ *	@(#)queue.h	8.5 (Berkeley) 8/20/94
++ */
++
++#ifndef _DWC_LIST_H_
++#define _DWC_LIST_H_
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/** @file
++ *
++ * This file defines linked list operations.  It is derived from BSD with
++ * only the MACRO names being prefixed with DWC_.  This is because a few of
++ * these names conflict with those on Linux.  For documentation on use, see the
++ * inline comments in the source code.  The original license for this source
++ * code applies and is preserved in the dwc_list.h source file.
++ */
++
++/*
++ * This file defines five types of data structures: singly-linked lists,
++ * lists, simple queues, tail queues, and circular queues.
++ *
++ *
++ * A singly-linked list is headed by a single forward pointer. The elements
++ * are singly linked for minimum space and pointer manipulation overhead at
++ * the expense of O(n) removal for arbitrary elements. New elements can be
++ * added to the list after an existing element or at the head of the list.
++ * Elements being removed from the head of the list should use the explicit
++ * macro for this purpose for optimum efficiency. A singly-linked list may
++ * only be traversed in the forward direction.  Singly-linked lists are ideal
++ * for applications with large datasets and few or no removals or for
++ * implementing a LIFO queue.
++ *
++ * A list is headed by a single forward pointer (or an array of forward
++ * pointers for a hash table header). The elements are doubly linked
++ * so that an arbitrary element can be removed without a need to
++ * traverse the list. New elements can be added to the list before
++ * or after an existing element or at the head of the list. A list
++ * may only be traversed in the forward direction.
++ *
++ * A simple queue is headed by a pair of pointers, one the head of the
++ * list and the other to the tail of the list. The elements are singly
++ * linked to save space, so elements can only be removed from the
++ * head of the list. New elements can be added to the list before or after
++ * an existing element, at the head of the list, or at the end of the
++ * list. A simple queue may only be traversed in the forward direction.
++ *
++ * A tail queue is headed by a pair of pointers, one to the head of the
++ * list and the other to the tail of the list. The elements are doubly
++ * linked so that an arbitrary element can be removed without a need to
++ * traverse the list. New elements can be added to the list before or
++ * after an existing element, at the head of the list, or at the end of
++ * the list. A tail queue may be traversed in either direction.
++ *
++ * A circle queue is headed by a pair of pointers, one to the head of the
++ * list and the other to the tail of the list. The elements are doubly
++ * linked so that an arbitrary element can be removed without a need to
++ * traverse the list. New elements can be added to the list before or after
++ * an existing element, at the head of the list, or at the end of the list.
++ * A circle queue may be traversed in either direction, but has a more
++ * complex end of list detection.
++ *
++ * For details on the use of these macros, see the queue(3) manual page.
++ */
++
++/*
++ * Singly-linked List definitions.
++ */
++#define DWC_SLIST_HEAD(name, type)					\
++struct name {								\
++	struct type *slh_first;	/* first element */			\
++}
++
++#define DWC_SLIST_HEAD_INITIALIZER(head)				\
++	{ NULL }
++
++#define DWC_SLIST_ENTRY(type)						\
++struct {								\
++	struct type *sle_next;	/* next element */			\
++}
++
++/*
++ * Singly-linked List access methods.
++ */
++#define DWC_SLIST_FIRST(head)	((head)->slh_first)
++#define DWC_SLIST_END(head)		NULL
++#define DWC_SLIST_EMPTY(head)	(SLIST_FIRST(head) == SLIST_END(head))
++#define DWC_SLIST_NEXT(elm, field)	((elm)->field.sle_next)
++
++#define DWC_SLIST_FOREACH(var, head, field)				\
++	for((var) = SLIST_FIRST(head);					\
++	    (var) != SLIST_END(head);					\
++	    (var) = SLIST_NEXT(var, field))
++
++#define DWC_SLIST_FOREACH_PREVPTR(var, varp, head, field)		\
++	for((varp) = &SLIST_FIRST((head));				\
++	    ((var) = *(varp)) != SLIST_END(head);			\
++	    (varp) = &SLIST_NEXT((var), field))
++
++/*
++ * Singly-linked List functions.
++ */
++#define DWC_SLIST_INIT(head) {						\
++	SLIST_FIRST(head) = SLIST_END(head);				\
++}
++
++#define DWC_SLIST_INSERT_AFTER(slistelm, elm, field) do {		\
++	(elm)->field.sle_next = (slistelm)->field.sle_next;		\
++	(slistelm)->field.sle_next = (elm);				\
++} while (0)
++
++#define DWC_SLIST_INSERT_HEAD(head, elm, field) do {			\
++	(elm)->field.sle_next = (head)->slh_first;			\
++	(head)->slh_first = (elm);					\
++} while (0)
++
++#define DWC_SLIST_REMOVE_NEXT(head, elm, field) do {			\
++	(elm)->field.sle_next = (elm)->field.sle_next->field.sle_next;	\
++} while (0)
++
++#define DWC_SLIST_REMOVE_HEAD(head, field) do {				\
++	(head)->slh_first = (head)->slh_first->field.sle_next;		\
++} while (0)
++
++#define DWC_SLIST_REMOVE(head, elm, type, field) do {			\
++	if ((head)->slh_first == (elm)) {				\
++		SLIST_REMOVE_HEAD((head), field);			\
++	}								\
++	else {								\
++		struct type *curelm = (head)->slh_first;		\
++		while( curelm->field.sle_next != (elm) )		\
++			curelm = curelm->field.sle_next;		\
++		curelm->field.sle_next =				\
++		    curelm->field.sle_next->field.sle_next;		\
++	}								\
++} while (0)
++
++/*
++ * Simple queue definitions.
++ */
++#define DWC_SIMPLEQ_HEAD(name, type)					\
++struct name {								\
++	struct type *sqh_first;	/* first element */			\
++	struct type **sqh_last;	/* addr of last next element */		\
++}
++
++#define DWC_SIMPLEQ_HEAD_INITIALIZER(head)				\
++	{ NULL, &(head).sqh_first }
++
++#define DWC_SIMPLEQ_ENTRY(type)						\
++struct {								\
++	struct type *sqe_next;	/* next element */			\
++}
++
++/*
++ * Simple queue access methods.
++ */
++#define DWC_SIMPLEQ_FIRST(head)	    ((head)->sqh_first)
++#define DWC_SIMPLEQ_END(head)	    NULL
++#define DWC_SIMPLEQ_EMPTY(head)	    (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head))
++#define DWC_SIMPLEQ_NEXT(elm, field)    ((elm)->field.sqe_next)
++
++#define DWC_SIMPLEQ_FOREACH(var, head, field)				\
++	for((var) = SIMPLEQ_FIRST(head);				\
++	    (var) != SIMPLEQ_END(head);					\
++	    (var) = SIMPLEQ_NEXT(var, field))
++
++/*
++ * Simple queue functions.
++ */
++#define DWC_SIMPLEQ_INIT(head) do {					\
++	(head)->sqh_first = NULL;					\
++	(head)->sqh_last = &(head)->sqh_first;				\
++} while (0)
++
++#define DWC_SIMPLEQ_INSERT_HEAD(head, elm, field) do {			\
++	if (((elm)->field.sqe_next = (head)->sqh_first) == NULL)	\
++		(head)->sqh_last = &(elm)->field.sqe_next;		\
++	(head)->sqh_first = (elm);					\
++} while (0)
++
++#define DWC_SIMPLEQ_INSERT_TAIL(head, elm, field) do {			\
++	(elm)->field.sqe_next = NULL;					\
++	*(head)->sqh_last = (elm);					\
++	(head)->sqh_last = &(elm)->field.sqe_next;			\
++} while (0)
++
++#define DWC_SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do {	\
++	if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
++		(head)->sqh_last = &(elm)->field.sqe_next;		\
++	(listelm)->field.sqe_next = (elm);				\
++} while (0)
++
++#define DWC_SIMPLEQ_REMOVE_HEAD(head, field) do {			\
++	if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
++		(head)->sqh_last = &(head)->sqh_first;			\
++} while (0)
++
++/*
++ * Tail queue definitions.
++ */
++#define DWC_TAILQ_HEAD(name, type)					\
++struct name {								\
++	struct type *tqh_first;	/* first element */			\
++	struct type **tqh_last;	/* addr of last next element */		\
++}
++
++#define DWC_TAILQ_HEAD_INITIALIZER(head)				\
++	{ NULL, &(head).tqh_first }
++
++#define DWC_TAILQ_ENTRY(type)						\
++struct {								\
++	struct type *tqe_next;	/* next element */			\
++	struct type **tqe_prev;	/* address of previous next element */	\
++}
++
++/*
++ * tail queue access methods
++ */
++#define DWC_TAILQ_FIRST(head)		((head)->tqh_first)
++#define DWC_TAILQ_END(head)		NULL
++#define DWC_TAILQ_NEXT(elm, field)	((elm)->field.tqe_next)
++#define DWC_TAILQ_LAST(head, headname)					\
++	(*(((struct headname *)((head)->tqh_last))->tqh_last))
++/* XXX */
++#define DWC_TAILQ_PREV(elm, headname, field)				\
++	(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
++#define DWC_TAILQ_EMPTY(head)						\
++	(TAILQ_FIRST(head) == TAILQ_END(head))
++
++#define DWC_TAILQ_FOREACH(var, head, field)				\
++	for((var) = TAILQ_FIRST(head);					\
++	    (var) != TAILQ_END(head);					\
++	    (var) = TAILQ_NEXT(var, field))
++
++#define DWC_TAILQ_FOREACH_REVERSE(var, head, headname, field)		\
++	for((var) = TAILQ_LAST(head, headname);				\
++	    (var) != TAILQ_END(head);					\
++	    (var) = TAILQ_PREV(var, headname, field))
++
++/*
++ * Tail queue functions.
++ */
++#define DWC_TAILQ_INIT(head) do {					\
++	(head)->tqh_first = NULL;					\
++	(head)->tqh_last = &(head)->tqh_first;				\
++} while (0)
++
++#define DWC_TAILQ_INSERT_HEAD(head, elm, field) do {			\
++	if (((elm)->field.tqe_next = (head)->tqh_first) != NULL)	\
++		(head)->tqh_first->field.tqe_prev =			\
++		    &(elm)->field.tqe_next;				\
++	else								\
++		(head)->tqh_last = &(elm)->field.tqe_next;		\
++	(head)->tqh_first = (elm);					\
++	(elm)->field.tqe_prev = &(head)->tqh_first;			\
++} while (0)
++
++#define DWC_TAILQ_INSERT_TAIL(head, elm, field) do {			\
++	(elm)->field.tqe_next = NULL;					\
++	(elm)->field.tqe_prev = (head)->tqh_last;			\
++	*(head)->tqh_last = (elm);					\
++	(head)->tqh_last = &(elm)->field.tqe_next;			\
++} while (0)
++
++#define DWC_TAILQ_INSERT_AFTER(head, listelm, elm, field) do {		\
++	if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
++		(elm)->field.tqe_next->field.tqe_prev =			\
++		    &(elm)->field.tqe_next;				\
++	else								\
++		(head)->tqh_last = &(elm)->field.tqe_next;		\
++	(listelm)->field.tqe_next = (elm);				\
++	(elm)->field.tqe_prev = &(listelm)->field.tqe_next;		\
++} while (0)
++
++#define DWC_TAILQ_INSERT_BEFORE(listelm, elm, field) do {		\
++	(elm)->field.tqe_prev = (listelm)->field.tqe_prev;		\
++	(elm)->field.tqe_next = (listelm);				\
++	*(listelm)->field.tqe_prev = (elm);				\
++	(listelm)->field.tqe_prev = &(elm)->field.tqe_next;		\
++} while (0)
++
++#define DWC_TAILQ_REMOVE(head, elm, field) do {				\
++	if (((elm)->field.tqe_next) != NULL)				\
++		(elm)->field.tqe_next->field.tqe_prev =			\
++		    (elm)->field.tqe_prev;				\
++	else								\
++		(head)->tqh_last = (elm)->field.tqe_prev;		\
++	*(elm)->field.tqe_prev = (elm)->field.tqe_next;			\
++} while (0)
++
++#define DWC_TAILQ_REPLACE(head, elm, elm2, field) do {			\
++	if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL)	\
++		(elm2)->field.tqe_next->field.tqe_prev =		\
++		    &(elm2)->field.tqe_next;				\
++	else								\
++		(head)->tqh_last = &(elm2)->field.tqe_next;		\
++	(elm2)->field.tqe_prev = (elm)->field.tqe_prev;			\
++	*(elm2)->field.tqe_prev = (elm2);				\
++} while (0)
++
++/*
++ * Circular queue definitions.
++ */
++#define DWC_CIRCLEQ_HEAD(name, type)					\
++struct name {								\
++	struct type *cqh_first;		/* first element */		\
++	struct type *cqh_last;		/* last element */		\
++}
++
++#define DWC_CIRCLEQ_HEAD_INITIALIZER(head)				\
++	{ DWC_CIRCLEQ_END(&head), DWC_CIRCLEQ_END(&head) }
++
++#define DWC_CIRCLEQ_ENTRY(type)						\
++struct {								\
++	struct type *cqe_next;		/* next element */		\
++	struct type *cqe_prev;		/* previous element */		\
++}
++
++/*
++ * Circular queue access methods
++ */
++#define DWC_CIRCLEQ_FIRST(head)		((head)->cqh_first)
++#define DWC_CIRCLEQ_LAST(head)		((head)->cqh_last)
++#define DWC_CIRCLEQ_END(head)		((void *)(head))
++#define DWC_CIRCLEQ_NEXT(elm, field)	((elm)->field.cqe_next)
++#define DWC_CIRCLEQ_PREV(elm, field)	((elm)->field.cqe_prev)
++#define DWC_CIRCLEQ_EMPTY(head)						\
++	(DWC_CIRCLEQ_FIRST(head) == DWC_CIRCLEQ_END(head))
++
++#define DWC_CIRCLEQ_EMPTY_ENTRY(elm, field) (((elm)->field.cqe_next == NULL) && ((elm)->field.cqe_prev == NULL))
++
++#define DWC_CIRCLEQ_FOREACH(var, head, field)				\
++	for((var) = DWC_CIRCLEQ_FIRST(head);				\
++	    (var) != DWC_CIRCLEQ_END(head);				\
++	    (var) = DWC_CIRCLEQ_NEXT(var, field))
++
++#define DWC_CIRCLEQ_FOREACH_SAFE(var, var2, head, field)			\
++	for((var) = DWC_CIRCLEQ_FIRST(head), var2 = DWC_CIRCLEQ_NEXT(var, field); \
++	    (var) != DWC_CIRCLEQ_END(head);					\
++	    (var) = var2, var2 = DWC_CIRCLEQ_NEXT(var, field))
++
++#define DWC_CIRCLEQ_FOREACH_REVERSE(var, head, field)			\
++	for((var) = DWC_CIRCLEQ_LAST(head);				\
++	    (var) != DWC_CIRCLEQ_END(head);				\
++	    (var) = DWC_CIRCLEQ_PREV(var, field))
++
++/*
++ * Circular queue functions.
++ */
++#define DWC_CIRCLEQ_INIT(head) do {					\
++	(head)->cqh_first = DWC_CIRCLEQ_END(head);			\
++	(head)->cqh_last = DWC_CIRCLEQ_END(head);			\
++} while (0)
++
++#define DWC_CIRCLEQ_INIT_ENTRY(elm, field) do {				\
++	(elm)->field.cqe_next = NULL;					\
++	(elm)->field.cqe_prev = NULL;					\
++} while (0)
++
++#define DWC_CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do {	\
++	(elm)->field.cqe_next = (listelm)->field.cqe_next;		\
++	(elm)->field.cqe_prev = (listelm);				\
++	if ((listelm)->field.cqe_next == DWC_CIRCLEQ_END(head))		\
++		(head)->cqh_last = (elm);				\
++	else								\
++		(listelm)->field.cqe_next->field.cqe_prev = (elm);	\
++	(listelm)->field.cqe_next = (elm);				\
++} while (0)
++
++#define DWC_CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do {	\
++	(elm)->field.cqe_next = (listelm);				\
++	(elm)->field.cqe_prev = (listelm)->field.cqe_prev;		\
++	if ((listelm)->field.cqe_prev == DWC_CIRCLEQ_END(head))		\
++		(head)->cqh_first = (elm);				\
++	else								\
++		(listelm)->field.cqe_prev->field.cqe_next = (elm);	\
++	(listelm)->field.cqe_prev = (elm);				\
++} while (0)
++
++#define DWC_CIRCLEQ_INSERT_HEAD(head, elm, field) do {			\
++	(elm)->field.cqe_next = (head)->cqh_first;			\
++	(elm)->field.cqe_prev = DWC_CIRCLEQ_END(head);			\
++	if ((head)->cqh_last == DWC_CIRCLEQ_END(head))			\
++		(head)->cqh_last = (elm);				\
++	else								\
++		(head)->cqh_first->field.cqe_prev = (elm);		\
++	(head)->cqh_first = (elm);					\
++} while (0)
++
++#define DWC_CIRCLEQ_INSERT_TAIL(head, elm, field) do {			\
++	(elm)->field.cqe_next = DWC_CIRCLEQ_END(head);			\
++	(elm)->field.cqe_prev = (head)->cqh_last;			\
++	if ((head)->cqh_first == DWC_CIRCLEQ_END(head))			\
++		(head)->cqh_first = (elm);				\
++	else								\
++		(head)->cqh_last->field.cqe_next = (elm);		\
++	(head)->cqh_last = (elm);					\
++} while (0)
++
++#define DWC_CIRCLEQ_REMOVE(head, elm, field) do {			\
++	if ((elm)->field.cqe_next == DWC_CIRCLEQ_END(head))		\
++		(head)->cqh_last = (elm)->field.cqe_prev;		\
++	else								\
++		(elm)->field.cqe_next->field.cqe_prev =			\
++		    (elm)->field.cqe_prev;				\
++	if ((elm)->field.cqe_prev == DWC_CIRCLEQ_END(head))		\
++		(head)->cqh_first = (elm)->field.cqe_next;		\
++	else								\
++		(elm)->field.cqe_prev->field.cqe_next =			\
++		    (elm)->field.cqe_next;				\
++} while (0)
++
++#define DWC_CIRCLEQ_REMOVE_INIT(head, elm, field) do {			\
++	DWC_CIRCLEQ_REMOVE(head, elm, field);				\
++	DWC_CIRCLEQ_INIT_ENTRY(elm, field);				\
++} while (0)
++
++#define DWC_CIRCLEQ_REPLACE(head, elm, elm2, field) do {		\
++	if (((elm2)->field.cqe_next = (elm)->field.cqe_next) ==		\
++	    DWC_CIRCLEQ_END(head))					\
++		(head).cqh_last = (elm2);				\
++	else								\
++		(elm2)->field.cqe_next->field.cqe_prev = (elm2);	\
++	if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) ==		\
++	    DWC_CIRCLEQ_END(head))					\
++		(head).cqh_first = (elm2);				\
++	else								\
++		(elm2)->field.cqe_prev->field.cqe_next = (elm2);	\
++} while (0)
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* _DWC_LIST_H_ */
+diff --git a/drivers/usb/gadget/udc/hiudc3/ep0.c b/drivers/usb/gadget/udc/hiudc3/ep0.c
+new file mode 100644
+index 0000000..da09604
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc3/ep0.c
+@@ -0,0 +1,1252 @@
++/** @file
++ */
++
++#include "os_defs.h"
++#include "hw.h"
++#include "usb.h"
++#include "pcd.h"
++#include "dev.h"
++#include "os_dev.h"
++#include "cil.h"
++
++#ifdef DWC_UTE
++#include "ute_if.h"
++#endif
++
++/*=======================================================================*/
++/*
++ * EP0 routines
++ */
++
++#if !defined(__linux__) || !defined(DWC_BOS_IN_GADGET)
++
++/** The BOS Descriptor */
++
++static usb_dev_cap_20_ext_desc_t cap1_desc = {
++	sizeof(usb_dev_cap_20_ext_desc_t),	/* bLength */
++	UDESC_DEVICE_CAPABILITY,		/* bDescriptorType */
++	USB_DEVICE_CAPABILITY_20_EXTENSION,	/* bDevCapabilityType */
++	UCONSTDW(USB_20_EXT_LPM),		/* bmAttributes */
++};
++
++static usb_dev_cap_ss_usb_t cap2_desc = {
++	sizeof(usb_dev_cap_ss_usb_t),		/* bLength */
++	UDESC_DEVICE_CAPABILITY,		/* bDescriptorType */
++	USB_DEVICE_CAPABILITY_SS_USB,		/* bDevCapabilityType */
++	0x0,					/* bmAttributes */
++	UCONSTW(USB_DC_SS_USB_SPEED_SUPPORT_SS	/* wSpeedsSupported */
++	    | USB_DC_SS_USB_SPEED_SUPPORT_HIGH
++	    | USB_DC_SS_USB_SPEED_SUPPORT_FULL),
++	USB_DC_SS_USB_SPEED_SUPPORT_FULL,	/* bFunctionalitySupport */
++	/* @todo set these to correct values */
++	10,					/* bU1DevExitLat (10 us) */
++	UCONSTW(256),				/* wU2DevExitLat (256 us) */
++};
++
++#ifdef DWC_OPTIONAL_UUID
++	/* The Denali host (and Win8) chokes on the optional container ID */
++
++static usb_dev_cap_container_id_t cap3_desc = {
++	sizeof(usb_dev_cap_container_id_t),	/* bLength */
++	UDESC_DEVICE_CAPABILITY,		/* bDescriptorType */
++	USB_DEVICE_CAPABILITY_CONTAINER_ID,	/* bDevCapabilityType */
++	0,					/* bReserved */
++	/* @todo Create UUID */
++	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, /* containerID */
++};
++#endif
++
++static wusb_bos_desc_t bos_desc = {
++	sizeof(wusb_bos_desc_t),		/* bLength */
++	WUDESC_BOS,				/* bDescriptorType */
++
++#ifdef DWC_OPTIONAL_UUID
++	UCONSTW(sizeof(wusb_bos_desc_t)		/* wTotalLength */
++		+ sizeof(cap1_desc) + sizeof(cap2_desc) + sizeof(cap3_desc)),
++	3,					/* bNumDeviceCaps */
++#else
++	UCONSTW(sizeof(wusb_bos_desc_t)		/* wTotalLength */
++		+ sizeof(cap1_desc) + sizeof(cap2_desc)),
++	2,					/* bNumDeviceCaps */
++#endif
++};
++
++#endif /* !__linux__ || ... */
++
++/**
++ * This routine starts the data stage of a 3-stage control command.
++ * pcd->ep0state must be set to EP0_OUT_DATA_PHASE or EP0_IN_DATA_PHASE, and
++ * pcd->ep0->dwc_ep.is_in must be set to 0 or 1 before calling this routine.
++ * For IN, the data to be sent must be placed in pcd->ep0_status_buf before
++ * the call.
++ */
++void dwc_usb3_pcd_ep0_data_stage(dwc_usb3_pcd_t *pcd, int length)
++{
++	pcd->ep0_req->dwc_req.buf[0] = (char *)pcd->ep0_status_buf;
++	pcd->ep0_req->dwc_req.bufdma[0] = pcd->ep0_status_buf_dma;
++	pcd->ep0_req->dwc_req.length = length;
++	pcd->ep0_req->dwc_req.actual = 0;
++	pcd->ep0_status_pending = 1;
++	pcd->ep0->dwc_ep.send_zlp = 0;
++	dwc_usb3_pcd_ep0_start_transfer(pcd, pcd->ep0_req);
++}
++
++/**
++ * This routine processes the SET_ADDRESS Setup Commands.
++ */
++static void do_set_address(dwc_usb3_pcd_t *pcd)
++{
++	usb_device_request_t ctrl = pcd->ep0_setup_pkt->req;
++
++	dwc_debug0(pcd->usb3_dev, "SET ADDRESS\n");
++
++	if (ctrl.bmRequestType == UT_DEVICE) {
++#ifdef DEBUG_EP0
++		dwc_debug1(pcd->usb3_dev, "SET_ADDRESS %d\n",
++			   UGETW(ctrl.wValue));
++#endif
++		dwc_usb3_set_address(pcd, UGETW(ctrl.wValue));
++		pcd->ep0->dwc_ep.is_in = 1;
++		pcd->ep0state = EP0_IN_WAIT_NRDY;
++		if (UGETW(ctrl.wValue))
++			pcd->state = DWC_STATE_ADDRESSED;
++		else
++			pcd->state = DWC_STATE_DEFAULT;
++	}
++}
++
++/**
++ * This routine stalls EP0.
++ */
++static void ep0_do_stall(dwc_usb3_pcd_t *pcd, int err_val)
++{
++	usb_device_request_t ctrl = pcd->ep0_setup_pkt->req;
++	dwc_usb3_pcd_ep_t *ep0 = pcd->ep0;
++
++	dwc_print3(pcd->usb3_dev, "req %02x.%02x protocol STALL; err %d\n",
++		   ctrl.bmRequestType, ctrl.bRequest, err_val);
++	ep0->dwc_ep.is_in = 0;
++	dwc_usb3_pcd_ep_set_stall(pcd, ep0);
++	ep0->dwc_ep.stopped = 1;
++	pcd->ep0state = EP0_IDLE;
++	dwc_usb3_pcd_ep0_out_start(pcd);
++}
++
++/**
++ * Clear the EP halt (STALL), and if there are pending requests start
++ * the transfer.
++ */
++static void do_clear_halt(dwc_usb3_pcd_t *pcd, dwc_usb3_pcd_ep_t *ep)
++{
++	dwc_usb3_dev_ep_regs_t __iomem *ep_reg;
++
++	dwc_debug1(pcd->usb3_dev, "%s()\n", __func__);
++
++	if (ep->dwc_ep.stall_clear_flag == 0) {
++		if (ep != pcd->ep0)
++			dwc_usb3_pcd_ep_clear_stall(pcd, ep);
++
++		if (ep->dwc_ep.stopped) {
++			ep->dwc_ep.stopped = 0;
++
++			/* If there is a request in the EP queue start it */
++			if (ep != pcd->ep0 && ep->dwc_ep.is_in)
++				dwc_usb3_gadget_start_next_request(pcd, ep);
++		}
++	} else {
++		dwc_usb3_dis_usb2_suspend(pcd);
++
++		/* Clear sequence number using DEPCFG */
++		if (ep->dwc_ep.is_in) {
++			ep_reg = ep->dwc_ep.in_ep_reg;
++			dwc_usb3_dep_cfg(pcd, ep_reg, ep->dwc_ep.param0in,
++					 ep->dwc_ep.param1in, 0);
++		} else {
++			ep_reg = ep->dwc_ep.out_ep_reg;
++			dwc_usb3_dep_cfg(pcd, ep_reg, ep->dwc_ep.param0out,
++					 ep->dwc_ep.param1out, 0);
++		}
++
++		dwc_usb3_ena_usb2_suspend(pcd);
++	}
++
++	/* Start Control Status Phase */
++	pcd->ep0->dwc_ep.is_in = 1;
++	pcd->ep0state = EP0_IN_WAIT_NRDY;
++}
++
++/**
++ * This routine handles the Get Descriptor request for the BOS descriptor
++ * and the OTG descriptor, and passes all other requests to the Gadget driver.
++ */
++static void do_get_descriptor(dwc_usb3_pcd_t *pcd)
++{
++	usb_device_request_t ctrl = pcd->ep0_setup_pkt->req;
++	u8 desc_type = UGETW(ctrl.wValue) >> 8;
++	int ret;
++
++#if defined(CONFIG_USB_OTG_DWC) || !defined(__linux__) || !defined(DWC_BOS_IN_GADGET)
++	u16 max = UGETW(ctrl.wLength);
++	u8 *buf = pcd->ep0_status_buf;
++	int length;
++#endif
++
++#ifdef DEBUG_EP0
++	dwc_debug5(pcd->usb3_dev, "GET_DESCRIPTOR %02x.%02x v%04x i%04x l%04x\n",
++		   ctrl.bmRequestType, ctrl.bRequest, UGETW(ctrl.wValue),
++		   UGETW(ctrl.wIndex), UGETW(ctrl.wLength));
++#endif
++
++	switch (desc_type) {
++
++#ifdef CONFIG_USB_OTG_DWC
++	case UDESC_OTG:
++		dwc_debug0(pcd->usb3_dev, "\nGET_DESCRIPTOR(OTG)\n\n");
++		buf[0] = 5;
++		buf[1] = UDESC_OTG;
++		if (pcd->speed == USB_SPEED_SUPER)
++			buf[2] = 0xd;
++		else
++			buf[2] = 0x7;
++
++		buf[3] = 0;
++		if (pcd->speed == USB_SPEED_SUPER)
++			buf[4] = 0x3;
++		else
++			buf[4] = 0x2;
++
++		length = 5;
++		dwc_usb3_pcd_ep0_data_stage(pcd, length < max ? length : max);
++		break;
++#endif
++
++	case UDESC_BOS:
++		dwc_debug0(pcd->usb3_dev, "\nGET_DESCRIPTOR(BOS)\n\n");
++		if (pcd->speed != USB_SPEED_SUPER &&
++		    pcd->usb3_dev->core_params->nobos) {
++			ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
++			return;
++		}
++
++#if !defined(__linux__) || !defined(DWC_BOS_IN_GADGET)
++		memcpy(buf, &bos_desc, sizeof(bos_desc));
++		buf += sizeof(bos_desc);
++
++		if (pcd->usb3_dev->core_params->besl) {
++			u32 d = UGETDW(cap1_desc.bmAttributes);
++
++			d |= USB_20_EXT_BESL | USB_20_EXT_BASELINE_BESL_VALID |
++				USB_20_EXT_DEEP_BESL_VALID;
++			d &= ~(USB_20_EXT_BASELINE_BESL_BITS |
++			       USB_20_EXT_DEEP_BESL_BITS);
++			d |= pcd->usb3_dev->core_params->baseline_besl <<
++				USB_20_EXT_BASELINE_BESL_SHIFT;
++			d |= pcd->usb3_dev->core_params->deep_besl <<
++				USB_20_EXT_DEEP_BESL_SHIFT;
++			USETDW(cap1_desc.bmAttributes, d);
++		}
++
++		if (pcd->usb3_dev->core_params->lpmctl == 0)
++			USETDW(cap1_desc.bmAttributes, 0);
++
++		memcpy(buf, &cap1_desc, sizeof(cap1_desc));
++		buf += sizeof(cap1_desc);
++		memcpy(buf, &cap2_desc, sizeof(cap2_desc));
++
++#ifdef DWC_OPTIONAL_UUID
++		buf += sizeof(cap2_desc);
++		memcpy(buf, &cap3_desc, sizeof(cap3_desc));
++#endif
++		length = UGETW(bos_desc.wTotalLength);
++		dwc_usb3_pcd_ep0_data_stage(pcd, length < max ? length : max);
++		break;
++#else
++		/* FALL THROUGH */
++#endif
++
++	default:
++		/* Call the Gadget driver's setup routine */
++		ret = dwc_usb3_gadget_setup(pcd, &ctrl);
++		if (ret < 0)
++			ep0_do_stall(pcd, ret);
++		break;
++	}
++}
++
++/**
++ * This routine processes the GET_STATUS Setup Commands.
++ */
++static void do_get_status(dwc_usb3_pcd_t *pcd)
++{
++	usb_device_request_t ctrl = pcd->ep0_setup_pkt->req;
++	u8 *status = pcd->ep0_status_buf;
++	dwc_usb3_pcd_ep_t *ep;
++	int length;
++
++#ifdef DEBUG_EP0
++	dwc_debug5(pcd->usb3_dev, "GET_STATUS %02x.%02x v%04x i%04x l%04x\n",
++		   ctrl.bmRequestType, ctrl.bRequest, UGETW(ctrl.wValue),
++		   UGETW(ctrl.wIndex), UGETW(ctrl.wLength));
++#endif
++
++	if (UGETW(ctrl.wLength) != 2
++#ifdef CONFIG_USB_OTG_DWC
++	    && UGETW(ctrl.wIndex) != 0xf000
++#endif
++	) {
++		ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
++		return;
++	}
++
++	switch (UT_GET_RECIPIENT(ctrl.bmRequestType)) {
++	case UT_DEVICE:
++#ifdef CONFIG_USB_OTG_DWC
++		/* HNP Polling */
++		if (UGETW(ctrl.wIndex) == 0xf000)
++			*status = pcd->wants_host ? 1 : 0;
++		else
++#endif
++		{
++			*status = 1; /* Self powered */
++
++			if (pcd->speed == USB_SPEED_SUPER) {
++				if (pcd->state == DWC_STATE_CONFIGURED) {
++					if (dwc_usb3_u1_enabled(pcd))
++						*status |= 1 << 2;
++
++					if (dwc_usb3_u2_enabled(pcd))
++						*status |= 1 << 3;
++
++					*status |= pcd->ltm_enable << 4;
++				}
++			} else {
++				*status |= pcd->remote_wakeup_enable << 1;
++			}
++		}
++
++		dwc_debug1(pcd->usb3_dev, "GET_STATUS(Device)=%02x\n", *status);
++		*(status + 1) = 0;
++		break;
++
++	case UT_INTERFACE:
++		*status = 0;
++		if (pcd->usb3_dev->core_params->wakeup)
++			*status |= 1;
++		*status |= pcd->remote_wakeup_enable << 1;
++		dwc_debug2(pcd->usb3_dev, "GET_STATUS(Interface %d)=%02x\n",
++			   UGETW(ctrl.wIndex), *status);
++		*(status + 1) = 0;
++		break;
++
++	case UT_ENDPOINT:
++		ep = dwc_usb3_pcd_get_ep_by_addr(pcd, UGETW(ctrl.wIndex));
++
++		/* @todo check for EP stall */
++		*status = ep->dwc_ep.stopped;
++		dwc_debug2(pcd->usb3_dev, "GET_STATUS(Endpoint %d)=%02x\n",
++			   UGETW(ctrl.wIndex), *status);
++		*(status + 1) = 0;
++		break;
++
++	default:
++		ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
++		return;
++	}
++
++#ifdef CONFIG_USB_OTG_DWC
++	if (UGETW(ctrl.wIndex) == 0xf000)
++		length = 1;
++	else
++#endif
++		length = 2;
++	dwc_usb3_pcd_ep0_data_stage(pcd, length);
++}
++
++/**
++ * This routine processes the SET_FEATURE Setup Commands.
++ */
++static void do_set_feature(dwc_usb3_pcd_t *pcd)
++{
++	usb_device_request_t ctrl = pcd->ep0_setup_pkt->req;
++	dwc_usb3_pcd_ep_t *ep;
++	int ret;
++
++#ifdef DEBUG_EP0
++	dwc_debug5(pcd->usb3_dev, "SET_FEATURE %02x.%02x v%04x i%04x l%04x\n",
++		   ctrl.bmRequestType, ctrl.bRequest, UGETW(ctrl.wValue),
++		   UGETW(ctrl.wIndex), UGETW(ctrl.wLength));
++#endif
++
++	switch (UT_GET_RECIPIENT(ctrl.bmRequestType)) {
++	case UT_DEVICE:
++		switch (UGETW(ctrl.wValue)) {
++		case UF_DEVICE_REMOTE_WAKEUP:
++			pcd->remote_wakeup_enable = 1;
++			break;
++
++		case UF_TEST_MODE:
++			/* Setup the Test Mode tasklet to do the Test
++			 * Packet generation after the SETUP Status
++			 * phase has completed. */
++			pcd->test_mode = UGETW(ctrl.wIndex) >> 8;
++			dwc_usb3_task_schedule(&pcd->test_mode_tasklet);
++			break;
++
++		case UF_DEVICE_B_HNP_ENABLE:
++			dwc_debug0(pcd->usb3_dev,
++				   "SET_FEATURE: USB_DEVICE_B_HNP_ENABLE\n");
++#ifdef CONFIG_USB_OTG_DWC
++			if (pcd->wants_host) {
++				pcd->b_hnp_enable = 0;
++				pcd->wants_host = 0;
++				dwc_usb3_start_hnp(pcd);
++			} else {
++				pcd->b_hnp_enable = 1;
++			}
++#endif
++			break;
++
++		case UOTG_NTF_HOST_REL:
++			dwc_debug0(pcd->usb3_dev,
++				   "SET_FEATURE: USB_NTF_HOST_REL\n");
++#ifdef CONFIG_USB_OTG_DWC
++			dwc_usb3_host_release(pcd);
++#endif
++			break;
++
++		case UOTG_B3_RSP_ENABLE:
++			dwc_debug0(pcd->usb3_dev,
++				   "SET_FEATURE: USB_B3_RSP_ENABLE\n");
++			break;
++
++		case UF_DEVICE_A_HNP_SUPPORT:
++			/* RH port supports HNP */
++			dwc_debug0(pcd->usb3_dev,
++				   "SET_FEATURE: USB_DEVICE_A_HNP_SUPPORT\n");
++			break;
++
++		case UF_DEVICE_A_ALT_HNP_SUPPORT:
++			/* other RH port does */
++			dwc_debug0(pcd->usb3_dev,
++				   "SET_FEATURE: USB_DEVICE_A_ALT_HNP_SUPPORT\n");
++			break;
++
++		case UF_U1_ENABLE:
++			dwc_debug0(pcd->usb3_dev, "SET_FEATURE: UF_U1_ENABLE\n");
++			if (pcd->speed != USB_SPEED_SUPER ||
++			    pcd->state != DWC_STATE_CONFIGURED) {
++				ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
++				return;
++			}
++
++			if (pcd->usb3_dev->core_params->pwrctl & 1)
++				dwc_usb3_enable_u1(pcd);
++			break;
++
++		case UF_U2_ENABLE:
++			dwc_debug0(pcd->usb3_dev, "SET_FEATURE: UF_U2_ENABLE\n");
++			if (pcd->speed != USB_SPEED_SUPER ||
++			    pcd->state != DWC_STATE_CONFIGURED) {
++				ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
++				return;
++			}
++
++			if (pcd->usb3_dev->core_params->pwrctl & 2)
++				dwc_usb3_enable_u2(pcd);
++			break;
++
++		case UF_LTM_ENABLE:
++			dwc_debug0(pcd->usb3_dev,
++				   "SET_FEATURE: UF_LTM_ENABLE\n");
++			if (pcd->speed != USB_SPEED_SUPER ||
++			    pcd->state != DWC_STATE_CONFIGURED ||
++			    UGETW(ctrl.wIndex) != 0) {
++				ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
++				return;
++			}
++
++			pcd->ltm_enable = 1;
++			pcd->send_lpm = 1;
++			break;
++
++		default:
++			ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
++			return;
++		}
++
++		break;
++
++	case UT_INTERFACE:
++		/* if FUNCTION_SUSPEND ... */
++		if (UGETW(ctrl.wValue) == 0) {
++			/* if Function Remote Wake Enabled ... */
++			if (UGETW(ctrl.wIndex) >> 8 & 2)
++				pcd->remote_wakeup_enable = 1;
++			else
++				pcd->remote_wakeup_enable = 0;
++
++			/* if Function Low Power Suspend ... */
++			// TODO
++
++			break;
++		}
++
++		ret = dwc_usb3_gadget_setup(pcd, &ctrl);
++		if (ret < 0)
++			ep0_do_stall(pcd, ret);
++		return;
++
++	case UT_ENDPOINT:
++		ep = dwc_usb3_pcd_get_ep_by_addr(pcd, UGETW(ctrl.wIndex));
++		if (UGETW(ctrl.wValue) != UF_ENDPOINT_HALT) {
++			ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
++			return;
++		}
++
++		ep->dwc_ep.stopped = 1;
++		dwc_usb3_pcd_ep_set_stall(pcd, ep);
++		break;
++	}
++
++	pcd->ep0->dwc_ep.is_in = 1;
++	pcd->ep0state = EP0_IN_WAIT_NRDY;
++}
++
++/**
++ * This routine processes the CLEAR_FEATURE Setup Commands.
++ */
++static void do_clear_feature(dwc_usb3_pcd_t *pcd)
++{
++	usb_device_request_t ctrl = pcd->ep0_setup_pkt->req;
++	dwc_usb3_pcd_ep_t *ep;
++
++#ifdef DEBUG_EP0
++	dwc_debug5(pcd->usb3_dev, "CLEAR_FEATURE %02x.%02x v%04x i%04x l%04x\n",
++		   ctrl.bmRequestType, ctrl.bRequest, UGETW(ctrl.wValue),
++		   UGETW(ctrl.wIndex), UGETW(ctrl.wLength));
++#endif
++
++	switch (UT_GET_RECIPIENT(ctrl.bmRequestType)) {
++	case UT_DEVICE:
++		switch (UGETW(ctrl.wValue)) {
++		case UF_DEVICE_REMOTE_WAKEUP:
++			pcd->remote_wakeup_enable = 0;
++			break;
++
++		case UF_TEST_MODE:
++			/* @todo Add CLEAR_FEATURE for TEST modes. */
++			break;
++
++		case UF_U1_ENABLE:
++			dwc_debug0(pcd->usb3_dev,
++				   "CLEAR_FEATURE: UF_U1_ENABLE\n");
++			if (pcd->speed != USB_SPEED_SUPER ||
++			    pcd->state != DWC_STATE_CONFIGURED) {
++				ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
++				return;
++			}
++
++			dwc_usb3_disable_u1(pcd);
++			break;
++
++		case UF_U2_ENABLE:
++			dwc_debug0(pcd->usb3_dev,
++				   "CLEAR_FEATURE: UF_U2_ENABLE\n");
++			if (pcd->speed != USB_SPEED_SUPER ||
++			    pcd->state != DWC_STATE_CONFIGURED) {
++				ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
++				return;
++			}
++
++			dwc_usb3_disable_u2(pcd);
++			break;
++
++		case UF_LTM_ENABLE:
++			dwc_debug0(pcd->usb3_dev,
++				   "CLEAR_FEATURE: UF_LTM_ENABLE\n");
++			if (pcd->speed != USB_SPEED_SUPER ||
++			    pcd->state != DWC_STATE_CONFIGURED ||
++			    UGETW(ctrl.wIndex) != 0) {
++				ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
++				return;
++			}
++
++			pcd->ltm_enable = 0;
++			pcd->send_lpm = 1;
++			break;
++
++		default:
++			ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
++			return;
++		}
++
++		break;
++
++	case UT_INTERFACE:
++		/* if FUNCTION_SUSPEND ... */
++		if (UGETW(ctrl.wValue) == 0) {
++			/* if Function Remote Wake Enabled ... */
++			if (UGETW(ctrl.wIndex) >> 8 & 2) {
++				pcd->remote_wakeup_enable = 0;
++			}
++
++			/* if Function Low Power Suspend ... */
++			// TODO
++
++			break;
++		}
++
++		ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
++		return;
++
++	case UT_ENDPOINT:
++		ep = dwc_usb3_pcd_get_ep_by_addr(pcd, UGETW(ctrl.wIndex));
++		if (UGETW(ctrl.wValue) != UF_ENDPOINT_HALT) {
++			ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
++			return;
++		}
++
++		do_clear_halt(pcd, ep);
++		return;
++	}
++
++	pcd->ep0->dwc_ep.is_in = 1;
++	pcd->ep0state = EP0_IN_WAIT_NRDY;
++}
++
++/**
++ * This routine processes SETUP commands. The USB Command processing is
++ * done in two places - the first being the PCD and the second being the
++ * Gadget driver (for example, the File-Backed Storage Gadget driver).
++ *
++ * <table>
++ * <tr><td> Command </td><td> Driver </td><td> Description </td></tr>
++ *
++ * <tr><td> GET_STATUS </td><td> PCD </td><td> Command is processed
++ * as defined in chapter 9 of the USB 2.0 Specification. </td></tr>
++ *
++ * <tr><td> SET_FEATURE </td><td> PCD / Gadget driver </td><td> Device
++ * and Endpoint requests are processed by the PCD. Interface requests
++ * are passed to the Gadget driver. </td></tr>
++ *
++ * <tr><td> CLEAR_FEATURE </td><td> PCD </td><td> Device and Endpoint
++ * requests are processed by the PCD. Interface requests are ignored.
++ * The only Endpoint feature handled is ENDPOINT_HALT. </td></tr>
++ *
++ * <tr><td> SET_ADDRESS </td><td> PCD </td><td> Program the DCFG register
++ * with device address received. </td></tr>
++ *
++ * <tr><td> GET_DESCRIPTOR </td><td> Gadget driver </td><td> Return the
++ * requested descriptor. </td></tr>
++ *
++ * <tr><td> SET_DESCRIPTOR </td><td> Gadget driver </td><td> Optional -
++ * not implemented by any of the existing Gadget drivers. </td></tr>
++ *
++ * <tr><td> GET_CONFIGURATION </td><td> Gadget driver </td><td> Return
++ * the current configuration. </td></tr>
++ *
++ * <tr><td> SET_CONFIGURATION </td><td> Gadget driver </td><td> Disable
++ * all EPs and enable EPs for new configuration. </td></tr>
++ *
++ * <tr><td> GET_INTERFACE </td><td> Gadget driver </td><td> Return the
++ * current interface. </td></tr>
++ *
++ * <tr><td> SET_INTERFACE </td><td> Gadget driver </td><td> Disable all
++ * EPs and enable EPs for new interface. </td></tr>
++ * </table>
++ *
++ * When the SETUP Phase Done interrupt occurs, the generic SETUP commands
++ * are processed by this routine. Calling the Gadget driver's
++ * dwc_usb3_gadget_setup() routine from here processes the gadget-specific
++ * SETUP commands.
++ */
++void dwc_usb3_pcd_do_setup(dwc_usb3_pcd_t *pcd)
++{
++	usb_device_request_t ctrl = pcd->ep0_setup_pkt->req;
++	dwc_usb3_pcd_ep_t *ep0 = pcd->ep0;
++	u16 wvalue, wlength;
++	int ret;
++
++	dwc_debug2(pcd->usb3_dev, "%s(%lx)\n", __func__, (unsigned long)pcd);
++	wvalue = UGETW(ctrl.wValue);
++	wlength = UGETW(ctrl.wLength);
++#if 0
++#ifdef DEBUG_EP0
++	dwc_debug0(pcd->usb3_dev, "\n");
++	dwc_print1(pcd->usb3_dev, "setup_pkt[0]=0x%08x\n",
++		   pcd->ep0_setup_pkt->d32[0]);
++	dwc_print1(pcd->usb3_dev, "setup_pkt[1]=0x%08x\n",
++		   pcd->ep0_setup_pkt->d32[1]);
++	dwc_print5(pcd->usb3_dev, "SETUP %02x.%02x v%04x i%04x l%04x\n",
++		   ctrl.bmRequestType, ctrl.bRequest, wvalue,
++		   UGETW(ctrl.wIndex), wlength);
++	dwc_debug0(pcd->usb3_dev, "\n");
++#endif
++#endif
++	/* Clean up the request queue */
++	dwc_usb3_gadget_request_nuke(pcd, ep0);
++	ep0->dwc_ep.stopped = 0;
++	ep0->dwc_ep.three_stage = 1;
++
++	if (ctrl.bmRequestType & UE_DIR_IN) {
++		ep0->dwc_ep.is_in = 1;
++		pcd->ep0state = EP0_IN_DATA_PHASE;
++	} else {
++		ep0->dwc_ep.is_in = 0;
++		pcd->ep0state = EP0_OUT_DATA_PHASE;
++	}
++
++	if (wlength == 0) {
++		ep0->dwc_ep.is_in = 1;
++		pcd->ep0state = EP0_IN_WAIT_GADGET;
++		ep0->dwc_ep.three_stage = 0;
++	}
++
++	if ((UT_GET_TYPE(ctrl.bmRequestType)) != UT_STANDARD) {
++		/* handle non-standard (class/vendor) requests
++		 * in the gadget driver
++		 */
++		ret = dwc_usb3_gadget_setup(pcd, &ctrl);
++		if (ret < 0)
++			ep0_do_stall(pcd, ret);
++		return;
++	}
++
++	/* @todo NGS: Handle bad setup packet? */
++
++///////////////////////////////////////////
++//// --- Standard Request handling --- ////
++
++	switch (ctrl.bRequest) {
++	case UR_GET_STATUS:
++		do_get_status(pcd);
++		break;
++
++	case UR_CLEAR_FEATURE:
++		do_clear_feature(pcd);
++		break;
++
++	case UR_SET_FEATURE:
++		do_set_feature(pcd);
++		break;
++
++	case UR_SET_ADDRESS:
++		do_set_address(pcd);
++		break;
++
++	case UR_SET_INTERFACE:
++		dwc_debug0(pcd->usb3_dev, "USB_REQ_SET_INTERFACE\n");
++#ifndef DWC_UTE
++		dwc_usb3_clr_eps_enabled(pcd);
++
++# ifdef DWC_STAR_9000463548_WORKAROUND
++		pcd->configuring = 1;
++# endif
++#endif
++		ret = dwc_usb3_gadget_setup(pcd, &ctrl);
++		if (ret < 0) {
++#ifndef DWC_UTE
++# ifdef DWC_STAR_9000463548_WORKAROUND
++			pcd->configuring = 0;
++# endif
++#endif
++			ep0_do_stall(pcd, ret);
++			return;
++		}
++
++		break;
++
++	case UR_SET_CONFIG:
++		dwc_debug0(pcd->usb3_dev, "USB_REQ_SET_CONFIGURATION\n");
++#ifdef DWC_UTE
++		if (wvalue != 0)
++			dwc_usb3_ute_config(pcd->usb3_dev);
++#endif
++		dwc_usb3_clr_eps_enabled(pcd);
++
++#ifdef DWC_STAR_9000463548_WORKAROUND
++		pcd->configuring = 1;
++#endif
++		if (pcd->ltm_enable)
++			pcd->send_lpm = 1;
++
++		ret = dwc_usb3_gadget_setup(pcd, &ctrl);
++		if (ret >= 0) {
++			if (wvalue != 0)
++				pcd->state = DWC_STATE_CONFIGURED;
++			else
++				pcd->state = DWC_STATE_ADDRESSED;
++		} else {
++			ep0_do_stall(pcd, ret);
++#ifdef DWC_STAR_9000463548_WORKAROUND
++			pcd->configuring = 0;
++#endif
++			return;
++		}
++
++		/* Must wait until SetConfig before accepting U1/U2 link
++		 * control, otherwise we have problems with VIA hubs
++		 */
++		if (pcd->usb3_dev->core_params->pwrctl & 1)
++			dwc_usb3_accept_u1(pcd);
++		if (pcd->usb3_dev->core_params->pwrctl & 2)
++			dwc_usb3_accept_u2(pcd);
++
++		pcd->ltm_enable = 0;
++		break;
++
++	case UR_GET_DESCRIPTOR:
++		do_get_descriptor(pcd);
++		break;
++
++	case UR_SET_SEL:
++		dwc_debug0(pcd->usb3_dev, "USB_REQ_SET_SEL\n");
++
++		/* For now this is a no-op */
++		dwc_usb3_pcd_ep0_data_stage(pcd, DWC_STATUS_BUF_SIZE < wlength ?
++					    DWC_STATUS_BUF_SIZE : wlength);
++		break;
++
++	case UR_SET_ISOC_DELAY:
++		dwc_debug0(pcd->usb3_dev, "USB_REQ_SET_ISOC_DELAY\n");
++
++		/* For now this is a no-op */
++		pcd->ep0->dwc_ep.is_in = 1;
++		pcd->ep0state = EP0_IN_WAIT_NRDY;
++		break;
++
++	default:
++		/* Call the Gadget driver's setup routine */
++		ret = dwc_usb3_gadget_setup(pcd, &ctrl);
++		if (ret < 0)
++			ep0_do_stall(pcd, ret);
++		break;
++	}
++}
++
++/**
++ * This routine starts the Zero-Length Packet for the IN status phase of a
++ * control write transfer.
++ */
++static void setup_in_status_phase(dwc_usb3_pcd_t *pcd, void *buf,
++				  dwc_dma_t dma)
++{
++	dwc_usb3_pcd_ep_t *ep0 = pcd->ep0;
++
++	dwc_debug1(pcd->usb3_dev, "%s()\n", __func__);
++
++	if (pcd->ep0state == EP0_STALL) {
++		dwc_debug0(pcd->usb3_dev, "EP0 STALLED\n");
++		return;
++	}
++
++	ep0->dwc_ep.is_in = 1;
++	pcd->ep0state = EP0_IN_STATUS_PHASE;
++
++	dwc_debug0(pcd->usb3_dev, "EP0 IN ZLP\n");
++
++	pcd->ep0_req->dwc_req.buf[0] = buf;
++	pcd->ep0_req->dwc_req.bufdma[0] = dma;
++	pcd->ep0_req->dwc_req.length = 0;
++	pcd->ep0_req->dwc_req.actual = 0;
++	dwc_usb3_pcd_ep0_start_transfer(pcd, pcd->ep0_req);
++}
++
++/**
++ * This routine starts the Zero-Length Packet for the OUT status phase of a
++ * control read transfer.
++ */
++static void setup_out_status_phase(dwc_usb3_pcd_t *pcd, void *buf,
++				   dwc_dma_t dma)
++{
++	dwc_usb3_pcd_ep_t *ep0 = pcd->ep0;
++
++	dwc_debug1(pcd->usb3_dev, "%s()\n", __func__);
++
++	if (pcd->ep0state == EP0_STALL) {
++		dwc_debug0(pcd->usb3_dev, "EP0 STALLED\n");
++		return;
++	}
++
++	ep0->dwc_ep.is_in = 0;
++	pcd->ep0state = EP0_OUT_STATUS_PHASE;
++
++	dwc_debug0(pcd->usb3_dev, "EP0 OUT ZLP\n");
++
++	pcd->ep0_req->dwc_req.buf[0] = buf;
++	pcd->ep0_req->dwc_req.bufdma[0] = dma;
++	pcd->ep0_req->dwc_req.length = 0;
++	pcd->ep0_req->dwc_req.actual = 0;
++	dwc_usb3_pcd_ep0_start_transfer(pcd, pcd->ep0_req);
++}
++
++#ifdef DEBUG_EP0
++/**
++ * This routine prints the ep0 state for debug purposes.
++ */
++void dwc_usb3_print_ep0_state(dwc_usb3_pcd_t *pcd)
++{
++#ifdef DEBUG
++	char *str;
++
++	switch (pcd->ep0state) {
++	case EP0_IDLE:
++		str = "EP0_IDLE";
++		break;
++	case EP0_IN_DATA_PHASE:
++		str = "EP0_IN_DATA_PHASE";
++		break;
++	case EP0_OUT_DATA_PHASE:
++		str = "EP0_OUT_DATA_PHASE";
++		break;
++	case EP0_IN_WAIT_GADGET:
++		str = "EP0_IN_WAIT_GADGET";
++		break;
++	case EP0_OUT_WAIT_GADGET:
++		str = "EP0_OUT_WAIT_GADGET";
++		break;
++	case EP0_IN_WAIT_NRDY:
++		str = "EP0_IN_WAIT_NRDY";
++		break;
++	case EP0_OUT_WAIT_NRDY:
++		str = "EP0_OUT_WAIT_NRDY";
++		break;
++	case EP0_IN_STATUS_PHASE:
++		str = "EP0_IN_STATUS_PHASE";
++		break;
++	case EP0_OUT_STATUS_PHASE:
++		str = "EP0_OUT_STATUS_PHASE";
++		break;
++	case EP0_STALL:
++		str = "EP0_STALL";
++		break;
++	default:
++		str = "EP0_INVALID";
++	}
++
++	dwc_debug2(pcd->usb3_dev, "%s(%d)\n", str, pcd->ep0state);
++#endif
++}
++#endif
++
++/**
++ * This routine completes the ep0 control transfer.
++ */
++static int ep0_complete_request(dwc_usb3_pcd_t *pcd, dwc_usb3_pcd_req_t *req,
++				dwc_usb3_dma_desc_t *desc, int status)
++{
++	dwc_usb3_pcd_ep_t *ep = pcd->ep0;
++	int is_last = 0;
++
++	dwc_debug4(pcd->usb3_dev, "%s(%lx,%lx,%d)\n", __func__,
++		   (unsigned long)req, (unsigned long)desc, status);
++
++	if (pcd->ep0_status_pending && !req) {
++		if (ep->dwc_ep.is_in) {
++#ifdef DEBUG_EP0
++			dwc_debug0(pcd->usb3_dev,
++				   "Do setup OUT status phase\n");
++#endif
++			pcd->ep0->dwc_ep.is_in = 0;
++			pcd->ep0state = EP0_OUT_WAIT_NRDY;
++		} else {
++#ifdef DEBUG_EP0
++			dwc_debug0(pcd->usb3_dev, "Do setup IN status phase\n");
++#endif
++			pcd->ep0->dwc_ep.is_in = 1;
++			pcd->ep0state = EP0_IN_WAIT_NRDY;
++		}
++
++		pcd->ep0_status_pending = 0;
++		return 1;
++	}
++
++	if (!req)
++		return 0;
++
++	dwc_debug1(pcd->usb3_dev, "req=%lx\n", (unsigned long)req);
++
++	if (pcd->ep0state == EP0_OUT_STATUS_PHASE ||
++	    pcd->ep0state == EP0_IN_STATUS_PHASE) {
++		is_last = 1;
++
++	} else if (ep->dwc_ep.is_in) {
++#ifdef DEBUG_EP0
++		dwc_debug4(pcd->usb3_dev,
++			   "IN len=%d actual=%d xfrcnt=%d trbrsp=0x%02x\n",
++			   req->dwc_req.length, req->dwc_req.actual,
++			   dwc_usb3_get_xfercnt(desc),
++			   dwc_usb3_get_xfersts(desc));
++#endif
++		if (dwc_usb3_get_xfercnt(desc) == 0) {
++			/* Is a Zero Len Packet needed? */
++			if (req->dwc_req.flags & DWC_PCD_REQ_ZERO) {
++#ifdef DEBUG_EP0
++				dwc_debug0(pcd->usb3_dev, "Setup Rx ZLP\n");
++#endif
++				req->dwc_req.flags &= ~DWC_PCD_REQ_ZERO;
++			}
++
++			pcd->ep0->dwc_ep.is_in = 0;
++			pcd->ep0state = EP0_OUT_WAIT_NRDY;
++		}
++	} else {
++#ifdef DEBUG_EP0
++		dwc_debug4(pcd->usb3_dev,
++			   "OUT len=%d actual=%d xfrcnt=%d trbrsp=0x%02x\n",
++			   req->dwc_req.length, req->dwc_req.actual,
++			   dwc_usb3_get_xfercnt(desc),
++			   dwc_usb3_get_xfersts(desc));
++#endif
++		/* Is a Zero Len Packet needed? */
++		if (req->dwc_req.flags & DWC_PCD_REQ_ZERO) {
++#ifdef DEBUG_EP0
++			dwc_debug0(pcd->usb3_dev, "Setup Tx ZLP\n");
++#endif
++			req->dwc_req.flags &= ~DWC_PCD_REQ_ZERO;
++		}
++
++		pcd->ep0->dwc_ep.is_in = 1;
++		pcd->ep0state = EP0_IN_WAIT_NRDY;
++	}
++
++	/* Complete the request */
++	if (is_last) {
++		dwc_debug2(pcd->usb3_dev, "is_last len=%d actual=%d\n",
++			   req->dwc_req.length, req->dwc_req.actual);
++		dwc_usb3_pcd_request_done(pcd, ep, req, status);
++		return 1;
++	}
++
++	return 0;
++}
++
++/**
++ * This routine handles EP0 Control transfers.
++ *
++ * The state of the control tranfers are tracked in <code>ep0state</code>.
++ */
++static void dwc_usb3_handle_ep0(dwc_usb3_pcd_t *pcd, dwc_usb3_pcd_req_t *req,
++				u32 event)
++{
++	dwc_usb3_pcd_ep_t *ep0 = pcd->ep0;
++	dwc_usb3_dma_desc_t *desc;
++	u32 byte_count, len;
++	int status;
++
++#ifdef DEBUG_EP0
++	dwc_debug1(pcd->usb3_dev, "%s()\n", __func__);
++	dwc_usb3_print_ep0_state(pcd);
++#endif
++	dwc_debug0(pcd->usb3_dev, "HANDLE EP0\n");
++
++	switch (pcd->ep0state) {
++	case EP0_IN_DATA_PHASE:
++		if (!req)
++			req = pcd->ep0_req;
++		desc = dwc_usb3_ep0_in_desc(pcd);
++		dwc_debug1(pcd->usb3_dev, "req=%lx\n", (unsigned long)req);
++#ifdef DEBUG_EP0
++		dwc_debug5(pcd->usb3_dev,
++			"DATA_IN EP%d-%s: type=%d mps=%d trb.status=0x%08x\n",
++			ep0->dwc_ep.num, (ep0->dwc_ep.is_in ? "IN" : "OUT"),
++			ep0->dwc_ep.type, ep0->dwc_ep.maxpacket, desc->status);
++#endif
++		if (dwc_usb3_is_hwo(desc)) {
++			dwc_print3(pcd->usb3_dev,
++				"### %s, EP%d-%s HWO bit set 1! ###\n",
++				__func__, ep0->dwc_ep.num, ep0->dwc_ep.is_in ?
++				"IN" : "OUT");
++			goto out;
++		}
++
++		status = dwc_usb3_get_xfersts(desc);
++		if (status & DWC_TRBRSP_SETUP_PEND) {
++			/* Start of a new Control transfer */
++			dwc_debug0(pcd->usb3_dev, "IN SETUP PENDING\n");
++			desc->status = 0;
++		}
++
++		byte_count = req->dwc_req.length - dwc_usb3_get_xfercnt(desc);
++		req->dwc_req.actual += byte_count;
++		req->dwc_req.buf[0] += byte_count;
++		req->dwc_req.bufdma[0] += byte_count;
++		dwc_debug3(pcd->usb3_dev, "length=%d byte_count=%d actual=%d\n",
++			req->dwc_req.length, byte_count, req->dwc_req.actual);
++
++		if (req->dwc_req.actual < req->dwc_req.length) {
++#ifdef DEBUG_EP0
++			dwc_usb3_dump_dbgregs(pcd->usb3_dev);
++#endif
++			dwc_debug0(pcd->usb3_dev, "IN CONTINUE\n");
++			//dwc_usb3_pcd_ep0_continue_transfer(pcd, req);
++			//dwc_debug0(pcd->usb3_dev, "CONTINUE TRANSFER\n");
++			dwc_debug0(pcd->usb3_dev, "Stall EP0\n");
++			ep0->dwc_ep.is_in = 0;
++			dwc_usb3_pcd_ep_set_stall(pcd, ep0);
++			ep0->dwc_ep.stopped = 1;
++			pcd->ep0state = EP0_IDLE;
++			dwc_usb3_pcd_ep0_out_start(pcd);
++
++		} else if (ep0->dwc_ep.send_zlp) {
++			dwc_debug0(pcd->usb3_dev, "IN ZLP\n");
++			dwc_usb3_pcd_ep0_continue_transfer(pcd, req);
++			ep0->dwc_ep.send_zlp = 0;
++			dwc_debug0(pcd->usb3_dev, "CONTINUE TRANSFER\n");
++
++		} else {
++			dwc_debug0(pcd->usb3_dev, "IN COMPLETE\n");
++			/* This sets ep0state = EP0_IN/OUT_WAIT_NRDY */
++			ep0_complete_request(pcd, req, desc, 0);
++			dwc_debug0(pcd->usb3_dev, "COMPLETE TRANSFER\n");
++		}
++
++		break;
++
++	case EP0_OUT_DATA_PHASE:
++		if (!req)
++			req = pcd->ep0_req;
++		desc = dwc_usb3_ep0_out_desc(pcd);
++		dwc_debug1(pcd->usb3_dev, "req=%lx\n", (unsigned long)req);
++#ifdef DEBUG_EP0
++		dwc_debug5(pcd->usb3_dev,
++			"DATA_OUT EP%d-%s: type=%d mps=%d trb.status=0x%08x\n",
++			ep0->dwc_ep.num, (ep0->dwc_ep.is_in ? "IN" : "OUT"),
++			ep0->dwc_ep.type, ep0->dwc_ep.maxpacket, desc->status);
++#endif
++		if (dwc_usb3_is_hwo(desc)) {
++			dwc_print3(pcd->usb3_dev,
++				"### %s, EP%d-%s HWO bit set 2! ###\n",
++				__func__, ep0->dwc_ep.num, ep0->dwc_ep.is_in ?
++				"IN" : "OUT");
++			goto out;
++		}
++
++		status = dwc_usb3_get_xfersts(desc);
++		if (status & DWC_TRBRSP_SETUP_PEND) {
++			/* Start of a new Control transfer */
++			dwc_debug0(pcd->usb3_dev, "OUT SETUP PENDING\n");
++		}
++
++		len = (req->dwc_req.length + ep0->dwc_ep.maxpacket - 1) &
++			~(ep0->dwc_ep.maxpacket - 1);
++		byte_count = len - dwc_usb3_get_xfercnt(desc);
++		req->dwc_req.actual += byte_count;
++		req->dwc_req.buf[0] += byte_count;
++		req->dwc_req.bufdma[0] += byte_count;
++		dwc_debug3(pcd->usb3_dev, "length=%d byte_count=%d actual=%d\n",
++			req->dwc_req.length, byte_count, req->dwc_req.actual);
++
++		/*if (req->dwc_req.actual < req->dwc_req.length) {
++			dwc_debug0(pcd->usb3_dev, "OUT CONTINUE\n");
++			dwc_usb3_pcd_ep0_continue_transfer(pcd, req);
++			dwc_debug0(pcd->usb3_dev, "CONTINUE TRANSFER\n");
++
++		} else*/ if (ep0->dwc_ep.send_zlp) {
++			dwc_debug0(pcd->usb3_dev, "OUT ZLP\n");
++			dwc_usb3_pcd_ep0_continue_transfer(pcd, req);
++			ep0->dwc_ep.send_zlp = 0;
++			dwc_debug0(pcd->usb3_dev, "CONTINUE TRANSFER\n");
++
++		} else {
++			dwc_debug0(pcd->usb3_dev, "OUT COMPLETE\n");
++			/* This sets ep0state = EP0_IN/OUT_WAIT_NRDY */
++			ep0_complete_request(pcd, req, desc, 0);
++			dwc_debug0(pcd->usb3_dev, "COMPLETE TRANSFER\n");
++		}
++
++		break;
++
++	case EP0_IN_WAIT_GADGET:
++		pcd->ep0state = EP0_IN_WAIT_NRDY;
++		break;
++
++	case EP0_OUT_WAIT_GADGET:
++		pcd->ep0state = EP0_OUT_WAIT_NRDY;
++		break;
++
++	case EP0_IN_WAIT_NRDY:
++	case EP0_OUT_WAIT_NRDY:
++		if (ep0->dwc_ep.is_in)
++			setup_in_status_phase(pcd, dwc_usb3_ep0_setup_pkt(pcd),
++					      dwc_usb3_ep0_setup_pkt_dma(pcd));
++		else
++			setup_out_status_phase(pcd, dwc_usb3_ep0_setup_pkt(pcd),
++					       dwc_usb3_ep0_setup_pkt_dma(pcd));
++		break;
++
++	case EP0_IN_STATUS_PHASE:
++	case EP0_OUT_STATUS_PHASE:
++		if (ep0->dwc_ep.is_in)
++			desc = dwc_usb3_ep0_in_desc(pcd);
++		else
++			desc = dwc_usb3_ep0_out_desc(pcd);
++#ifdef DEBUG_EP0
++		dwc_debug2(pcd->usb3_dev, "STATUS EP%d-%s\n", ep0->dwc_ep.num,
++			   (ep0->dwc_ep.is_in ? "IN" : "OUT"));
++#endif
++		ep0_complete_request(pcd, req, desc, 0);
++		pcd->ep0state = EP0_IDLE;
++		ep0->dwc_ep.stopped = 1;
++		ep0->dwc_ep.is_in = 0;	/* OUT for next SETUP */
++
++		if (pcd->send_lpm) {
++			pcd->send_lpm = 0;
++
++#if 0	// This is only for testing
++			dwc_usb3_xmit_ltm(pcd,
++					32 << DWC_DGCMDPAR_BELT_VALUE_SHIFT |
++					DWC_LATENCY_VALUE_MULT_32768 <<
++					DWC_DGCMDPAR_BELT_SCALE_SHIFT);
++#endif
++		}
++
++		/* Prepare for more SETUP Packets */
++		dwc_usb3_pcd_ep0_out_start(pcd);
++		break;
++
++	case EP0_STALL:
++		dwc_error0(pcd->usb3_dev, "EP0 STALLed, should not get here\n");
++		break;
++
++	case EP0_IDLE:
++		dwc_error0(pcd->usb3_dev, "EP0 IDLE, should not get here\n");
++		break;
++	}
++out:
++#ifdef DEBUG_EP0
++	dwc_usb3_print_ep0_state(pcd);
++#endif
++	return;
++}
++
++/**
++ * This routine handles EP0 transfers.
++ *
++ * This routine gets the request corresponding to the current EP0 transfer. If
++ * EP0 is in IDLE state, it calls dwc_usb3_do_setup() to begin processing
++ * the next Setup request, otherwise it calls dwc_usb3_handle_ep0() to handle
++ * the next stage of the current transfer.
++ */
++void dwc_usb3_handle_ep0_xfer(dwc_usb3_pcd_t *pcd, u32 event)
++{
++	dwc_usb3_pcd_ep_t *ep0 = pcd->ep0;
++	dwc_usb3_pcd_req_t *req = NULL;
++
++#ifdef DEBUG_EP0
++	dwc_debug1(pcd->usb3_dev, "%s()\n", __func__);
++#endif
++	req = dwc_usb3_gadget_get_request(pcd, ep0);
++
++	if (pcd->ep0state == EP0_IDLE) {
++#ifdef DEBUG_EP0
++		dwc_usb3_print_ep0_state(pcd);
++		dwc_debug2(pcd->usb3_dev, "IDLE EP%d-%s\n", ep0->dwc_ep.num,
++			   (ep0->dwc_ep.is_in ? "IN" : "OUT"));
++#endif
++		pcd->request_config = 0;
++		dwc_usb3_gadget_do_setup(pcd);
++	} else {
++		dwc_usb3_handle_ep0(pcd, req, event);
++	}
++}
+diff --git a/drivers/usb/gadget/udc/hiudc3/hiusb3.c b/drivers/usb/gadget/udc/hiudc3/hiusb3.c
+new file mode 100644
+index 0000000..85e981f
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc3/hiusb3.c
+@@ -0,0 +1,64 @@
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/dma-mapping.h>
++#include <linux/types.h>
++#include "os_dev.h"
++//#include "xhci.h"
++//#include "hiusb3.h"
++
++
++MODULE_LICENSE("Dual MIT/GPL");
++
++static struct resource hiusb_xhci_res[] = {
++    [0] = {
++        .start  = CONFIG_HIUSB_XHCI_REG_BASE_ADDRESS,
++        .end    = CONFIG_HIUSB_XHCI_REG_BASE_ADDRESS
++            + CONFIG_HIUSB_XHCI_REG_BASE_ADDRESS_LEN - 1,
++        .flags  = IORESOURCE_MEM,
++    },
++    [1] = {
++        .start  = CONFIG_HIUSB_XHCI_IRQ_NUMBER,
++        .end    = CONFIG_HIUSB_XHCI_IRQ_NUMBER,
++        .flags  = IORESOURCE_IRQ,
++    },
++};
++static void usb_xhci_platdev_release(struct device *dev)
++{
++                /* These don't need to do anything because the
++                 pdev structures are statically allocated. */
++}
++
++//u64 usb_dmamask = DMA_BIT_MASK(32);
++
++static struct platform_device hiusb_xhci_platdev = {
++    .name = "dwc_usb3",
++    .id = -1,
++    .dev = {
++        .init_name = "dwc_usb3",
++        .platform_data = NULL,
++        .dma_mask = DMA_BIT_MASK(32),
++        .coherent_dma_mask = DMA_BIT_MASK(32),
++	.release = usb_xhci_platdev_release,
++    },
++    .num_resources = ARRAY_SIZE(hiusb_xhci_res),
++    .resource = hiusb_xhci_res,
++};
++
++static int __init xhci_device_init(void)
++{
++//    if (usb_disabled())
++  //      return -ENODEV;
++        int reg;
++//	reg = readl(IO_ADDRESS(0x11080430));
++	printk("\n########################################################%s,%d\n",__func__,__LINE__);
++	return 0;
++	return platform_device_register(&hiusb_xhci_platdev);
++}
++
++static void __exit xhci_device_exit(void)
++{
++    platform_device_unregister(&hiusb_xhci_platdev);
++}
++
++module_init(xhci_device_init);
++module_exit(xhci_device_exit);
+diff --git a/drivers/usb/gadget/udc/hiudc3/hw.h b/drivers/usb/gadget/udc/hiudc3/hw.h
+new file mode 100644
+index 0000000..5967a13
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc3/hw.h
+@@ -0,0 +1,1967 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/DWC_usb3/driver/hw.h $
++ * $Revision: #65 $
++ * $Date: 2014/11/11 $
++ * $Change: 2664766 $
++ *
++ * Synopsys SS USB3 Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
++ * ========================================================================== */
++
++#ifndef _DWC_USB3_REGS_H_
++#define _DWC_USB3_REGS_H_
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/**
++ * @file
++ *
++ * This file contains the data structures for accessing the DWC_usb3 core
++ * registers and DMA descriptor fields.
++ *
++ * The application interfaces with the HS OTG core by reading from and
++ * writing to the Control and Status Register (CSR) space through the
++ * AHB Slave interface. These registers are 32 bits wide, and the
++ * addresses are 32-bit-block aligned.
++ * CSRs are classified as follows:
++ * - Core Global Registers
++ * - Device Global Registers
++ * - Device Endpoint Specific Registers
++ */
++
++
++/****************************************************************************/
++/* Core Global Registers */
++
++/**
++ * This enum represents the bit fields of the Core SoC Bus Configuration 0
++ * Register (GSBUSCFG0).
++ */
++typedef enum gsbuscfg0_data {
++	/** Bus Burst Len			<i>Access: R_W</i>.
++	 * - 0:   single
++	 * - 1:   incr
++	 * - 3:   incr4
++	 * - 7:   incr8
++	 * - 15:  incr16
++	 * - 31:  incr32  (non-AHB mode only)
++	 * - 63:  incr64  (non-AHB mode only)
++	 * - 127: incr128 (non-AHB mode only)
++	 * - 255: incr256 (non-AHB mode only)
++	 */
++	DWC_SBUSCFG0_HBURSTLEN_BITS		= 0x000000ff,
++	DWC_SBUSCFG0_HBURSTLEN_SHIFT		= 0,
++
++	DWC_SBUSCFG0_INT_DMA_BURST_SINGLE	= 0,
++	DWC_SBUSCFG0_INT_DMA_BURST_INCR		= 1,
++	DWC_SBUSCFG0_INT_DMA_BURST_INCR4	= 3,
++	DWC_SBUSCFG0_INT_DMA_BURST_INCR8	= 7,
++	DWC_SBUSCFG0_INT_DMA_BURST_INCR16	= 15,
++	DWC_SBUSCFG0_INT_DMA_BURST_INCR32	= 31,
++	DWC_SBUSCFG0_INT_DMA_BURST_INCR64	= 63,
++	DWC_SBUSCFG0_INT_DMA_BURST_INCR128	= 127,
++	DWC_SBUSCFG0_INT_DMA_BURST_INCR256	= 255,
++
++	/** Descriptor Write is Posted		<i>Access: R_W</i> */
++	DWC_SBUSCFG0_DES_WR_POST_BIT		= 0x00000100,
++	DWC_SBUSCFG0_DES_WR_POST_SHIFT		= 8,
++
++	/** Data Write is Posted		<i>Access: R_W</i> */
++	DWC_SBUSCFG0_DAT_WR_POST_BIT		= 0x00000200,
++	DWC_SBUSCFG0_DAT_WR_POST_SHIFT		= 9,
++
++	/** Descriptor Access is Big-Endian	<i>Access: R_W</i> */
++	DWC_SBUSCFG0_DES_BIG_END_BIT		= 0x00000400,
++	DWC_SBUSCFG0_DES_BIG_END_SHIFT		= 10,
++
++	/** Data Access is Big-Endian		<i>Access: R_W</i> */
++	DWC_SBUSCFG0_DAT_BIG_END_BIT		= 0x00000800,
++	DWC_SBUSCFG0_DAT_BIG_END_SHIFT		= 11,
++
++	/** Store and Forward Mode		<i>Access: R_W</i> */
++	DWC_SBUSCFG0_STORE_AND_FORWARD_BIT	= 0x00001000,
++	DWC_SBUSCFG0_STORE_AND_FORWARD_SHIFT	= 12,
++
++	/** Force Single Request		<i>Access: R_W</i> */
++	DWC_SBUSCFG0_SING_REQ_BIT		= 0x00004000,
++	DWC_SBUSCFG0_SING_REQ_SHIFT		= 14,
++
++	/** Descriptor Readback Enable		<i>Access: R_W</i> */
++	DWC_SBUSCFG0_READ_AFTER_WRITE_BIT	= 0x00008000,
++	DWC_SBUSCFG0_READ_AFTER_WRITE_SHIFT	= 15,
++
++	/** Descriptor Write Request Info	<i>Access: R_W</i> */
++	DWC_SBUSCFG0_DES_WR_REQ_INFO_BITS	= 0x000f0000,
++	DWC_SBUSCFG0_DES_WR_REQ_INFO_SHIFT	= 16,
++
++	/** Data Write Request Info		<i>Access: R_W</i> */
++	DWC_SBUSCFG0_DAT_WR_REQ_INFO_BITS	= 0x00f00000,
++	DWC_SBUSCFG0_DAT_WR_REQ_INFO_SHIFT	= 20,
++
++	/** Descriptor Read Request Info	<i>Access: R_W</i> */
++	DWC_SBUSCFG0_DES_RD_REQ_INFO_BITS	= 0x0f000000,
++	DWC_SBUSCFG0_DES_RD_REQ_INFO_SHIFT	= 24,
++
++	/** Data Read Request Info		<i>Access: R_W</i> */
++	DWC_SBUSCFG0_DAT_RD_REQ_INFO_BITS	= 0xf0000000,
++	DWC_SBUSCFG0_DAT_RD_REQ_INFO_SHIFT	= 28,
++} gsbuscfg0_data_t;
++
++/**
++ * This enum represents the bit fields of the Core SoC Bus Configuration 1
++ * Register (GSBUSCFG1).
++ */
++typedef enum gsbuscfg1_data {
++	/** OCP Address Space For Descriptor	<i>Access: R_W</i> */
++	DWC_SBUSCFG1_DES_ADDR_SPC_BITS		= 0x0000000f,
++	DWC_SBUSCFG1_DES_ADDR_SPC_SHIFT		= 0,
++
++	/** OCP Address Space For Data		<i>Access: R_W</i> */
++	DWC_SBUSCFG1_DAT_ADDR_SPC_BITS		= 0x000000f0,
++	DWC_SBUSCFG1_DAT_ADDR_SPC_SHIFT		= 4,
++} gsbuscfg1_data_t;
++
++/**
++ * This enum represents the bit fields of the Core Tx Threshold Control
++ * Register (GTXTHRCFG).
++ */
++typedef enum gtxthrcfg_data {
++	/** Maximum Tx Burst Size		<i>Access: R_W</i> */
++	DWC_TXTHRCTL_USB_MAX_TX_BURST_SIZE_BITS		= 0x00ff0000,
++	DWC_TXTHRCTL_USB_MAX_TX_BURST_SIZE_SHIFT	= 16,
++
++	/** Tx Multi-Packet Threshold Count	<i>Access: R_W</i> */
++	DWC_TXTHRCTL_USB_TX_PKT_CNT_BITS		= 0x1f000000,
++	DWC_TXTHRCTL_USB_TX_PKT_CNT_SHIFT		= 24,
++
++	/** Tx Multi-Packet Threshold Enable	<i>Access: R_W</i> */
++	DWC_TXTHRCTL_USB_TX_PKT_CNT_EN_BIT		= 0x20000000,
++	DWC_TXTHRCTL_USB_TX_PKT_CNT_EN_SHIFT		= 29,
++} gtxthrcfg_data_t;
++
++/**
++ * This enum represents the bit fields of the Core Rx Threshold Control
++ * Register (GRXTHRCFG).
++ */
++typedef enum grxthrcfg_data {
++	/** Maximum Rx Burst Size		<i>Access: R_W</i> */
++	DWC_RXTHRCTL_USB_MAX_RX_BURST_SIZE_BITS		= 0x00f80000,
++	DWC_RXTHRCTL_USB_MAX_RX_BURST_SIZE_SHIFT	= 19,
++
++	/** Rx Multi-Packet Threshold Count	<i>Access: R_W</i> */
++	DWC_RXTHRCTL_USB_RX_PKT_CNT_BITS		= 0x0f000000,
++	DWC_RXTHRCTL_USB_RX_PKT_CNT_SHIFT		= 24,
++
++	/** Rx Multi-Packet Threshold Enable	<i>Access: R_W</i> */
++	DWC_RXTHRCTL_USB_RX_PKT_CNT_EN_BIT		= 0x20000000,
++	DWC_RXTHRCTL_USB_RX_PKT_CNT_EN_SHIFT		= 29,
++} grxthrcfg_data_t;
++
++/**
++ * This enum represents the bit fields of the Core Control
++ * Register (GCTL).
++ */
++typedef enum gctl_data {
++	/** Disable Clock Gating		<i>Access: R_W</i> */
++	DWC_GCTL_DSBL_CLCK_GTNG_BIT	= 0x00000001,
++	DWC_GCTL_DSBL_CLCK_GTNG_SHIFT	= 0,
++
++	/** Global Hibernation Enable		<i>Access: R_W</i> */
++	DWC_GCTL_GBL_HIBER_EN_BIT	= 0x00000002,
++	DWC_GCTL_GBL_HIBER_EN_SHIFT	= 1,
++
++	/** Disable Scrambling			<i>Access: R_W</i> */
++	DWC_GCTL_DIS_SCRAMBLE_BIT	= 0x00000008,
++	DWC_GCTL_DIS_SCRAMBLE_SHIFT	= 3,
++
++	/** Scale-down Mode			<i>Access: R_W</i> */
++	DWC_GCTL_SCALE_DOWN_BITS	= 0x00000030,
++	DWC_GCTL_SCALE_DOWN_SHIFT	= 4,
++
++	/** RAM Clock Select			<i>Access: R_W</i> */
++	DWC_GCTL_RAM_CLK_SEL_BITS	= 0x000000c0,
++	DWC_GCTL_RAM_CLK_SEL_SHIFT	= 6,
++
++	/** Debug Attach			<i>Access: R_W</i> */
++	DWC_GCTL_DEBUG_ATTACH_BIT	= 0x00000100,
++	DWC_GCTL_DEBUG_ATTACH_SHIFT	= 8,
++
++	/** Disable U1/U2 Timer Scaledown	<i>Access: R_W</i> */
++	DWC_GCTL_U1U2_TIMER_SCALE_BIT	= 0x00000200,
++	DWC_GCTL_U1U2_TIMER_SCALE_SHIFT	= 9,
++
++	/** SOF ITP SYNC			<i>Access: R_W</i> */
++	DWC_GCTL_SOFITPSYNC_BIT		= 0x00000400,
++	DWC_GCTL_SOFITPSYNC_SHIFT	= 10,
++
++	/** Core Soft Reset			<i>Access: R_W</i> */
++	DWC_GCTL_CORE_SOFT_RST_BIT	= 0x00000800,
++	DWC_GCTL_CORE_SOFT_RST_SHIFT	= 11,
++
++	/** Port Capability Direction		<i>Access: R_W</i> */
++	DWC_GCTL_PRT_CAP_DIR_BITS	= 0x00003000,
++	DWC_GCTL_PRT_CAP_DIR_SHIFT	= 12,
++
++	/** Port Capability Values */
++	DWC_GCTL_PRT_CAP_HOST		= 1,
++	DWC_GCTL_PRT_CAP_DEVICE		= 2,
++	DWC_GCTL_PRT_CAP_OTG		= 3,
++
++	/** Frame Scale Down			<i>Access: R_W</i> */
++	DWC_GCTL_FRMSCLDWN_BITS		= 0x0000c000,
++	DWC_GCTL_FRMSCLDWN_SHIFT	= 14,
++
++	/** U2 Reset ECN			<i>Access: R_W</i> */
++	DWC_GCTL_U2RSTECN_BIT		= 0x00010000,
++	DWC_GCTL_U2RSTECN_SHIFT		= 16,
++
++	/** Bypass SetAddress			<i>Access: R_W</i> */
++	DWC_GCTL_BYPSSETADDR_BIT	= 0x00020000,
++	DWC_GCTL_BYPSSETADDR_SHIFT	= 17,
++
++	/** Master Filter Bypass		<i>Access: R_W</i> */
++	DWC_GCTL_MASTERFILTBYPASS_BIT	= 0x00040000,
++	DWC_GCTL_MASTERFILTBYPASS_SHIFT	= 18,
++
++	/** Power Down Scale			<i>Access: R_W</i> */
++	DWC_GCTL_PWR_DN_SCALE_BITS	= 0xfff80000,
++	DWC_GCTL_PWR_DN_SCALE_SHIFT	= 19,
++} gctl_data_t;
++
++/**
++ * This enum represents the bit fields of the Core Interrupt Mask
++ * Register (GEVTEN).
++ */
++typedef enum gevten_data {
++	/** ULPI Carkit Event Enable		<i>Access: R_W</i> */
++	DWC_GEVTEN_ULPI_CK_EVT_EN_BIT	= 0x00000001,
++	DWC_GEVTEN_ULPI_CK_EVT_SHIFT	= 0,
++
++	/** I2C Event Enable			<i>Access: R_W</i> */
++	DWC_GEVTEN_I2C_EVT_EN_BIT	= 0x00000002,
++	DWC_GEVTEN_I2C_EVT_EN_SHIFT	= 1,
++} gevten_data_t;
++
++/**
++ * This enum represents the bit fields of the Core Status
++ * Register (GSTS).
++ */
++typedef enum gsts_data {
++	/** Current Mode			<i>Access: RO</i>.
++	 * - 0: Device Mode
++	 * - 1: Host Mode
++	 * - 2: DRD Mode
++	 */
++	DWC_GSTS_CURMODE_BITS		= 0x00000003,
++	DWC_GSTS_CURMODE_SHIFT		= 0,
++
++	DWC_GSTS_DEVICE_MODE		= 0,
++	DWC_GSTS_HOST_MODE		= 1,
++	DWC_GSTS_DRD_MODE		= 2,
++
++	/** Bus Error Address Valid		<i>Access: RO</i> */
++	DWC_GSTS_BUS_ERR_ADDR_VLD_BIT	= 0x00000010,
++	DWC_GSTS_BUS_ERR_ADDR_VLD_SHIFT	= 4,
++
++	/** CSR Timeout */
++	DWC_GSTS_CSR_TIMEOUT_BIT	= 0x00000020,
++	DWC_GSTS_CSR_TIMEOUT_SHIFT	= 5,
++
++	/** Device Interrupt Pending */
++	DWC_GSTS_DEV_EVT_PENDING_BIT	= 0x00000040,
++	DWC_GSTS_DEV_EVT_PENDING_SHIFT	= 6,
++
++	/** Host Interrupt Pending */
++	DWC_GSTS_HOST_EVT_PENDING_BIT	= 0x00000080,
++	DWC_GSTS_HOST_EVT_PENDING_SHIFT	= 7,
++
++	/** ADP Interrupt Pending */
++	DWC_GSTS_ADP_EVT_PENDING_BIT	= 0x00000100,
++	DWC_GSTS_ADP_EVT_PENDING_SHIFT	= 8,
++
++	/** BC Interrupt Pending */
++	DWC_GSTS_BC_EVT_PENDING_BIT	= 0x00000200,
++	DWC_GSTS_BC_EVT_PENDING_SHIFT	= 9,
++
++	/** OTG Interrupt Pending */
++	DWC_GSTS_OTG_EVT_PENDING_BIT	= 0x00000400,
++	DWC_GSTS_OTG_EVT_PENDING_SHIFT	= 10,
++
++	/** SSIC Interrupt Pending */
++	DWC_GSTS_SSIC_IP_BIT		= 0x00000800,
++	DWC_GSTS_SSIC_IP_SHIFT		= 11,
++
++	/** Current BELT Value			<i>Access: RO</i> */
++	DWC_GSTS_CBELT_BITS		= 0xfff00000,
++	DWC_GSTS_CBELT_SHIFT		= 20,
++} gsts_data_t;
++
++/**
++ * This enum represents the bit fields of the Hardware Parameters 0
++ * Register (GHWPARAMS0).
++ */
++typedef enum ghwparams0_data {
++	DWC_HWP0_MODE_BITS		= 0x00000007,
++	DWC_HWP0_MODE_SHIFT		= 0,
++
++	DWC_HWP0_MBUS_TYPE_BITS		= 0x00000038,
++	DWC_HWP0_MBUS_TYPE_SHIFT	= 3,
++
++	DWC_HWP0_SBUS_TYPE_BITS		= 0x000000c0,
++	DWC_HWP0_SBUS_TYPE_SHIFT	= 6,
++
++	DWC_HWP0_MDWIDTH_BITS		= 0x0000ff00,
++	DWC_HWP0_MDWIDTH_SHIFT		= 8,
++
++	DWC_HWP0_SDWIDTH_BITS		= 0x00ff0000,
++	DWC_HWP0_SDWIDTH_SHIFT		= 16,
++
++	DWC_HWP0_AWIDTH_BITS		= 0x3f000000,
++	DWC_HWP0_AWIDTH_SHIFT		= 24,
++} ghwparams0_data_t;
++
++/**
++ * This enum represents the bit fields of the Hardware Parameters 1
++ * Register (GHWPARAMS1).
++ */
++typedef enum ghwparams1_data {
++	DWC_HWP1_IDWIDTH_M1_BITS		= 0x00000007,
++	DWC_HWP1_IDWIDTH_M1_SHIFT		= 0,
++
++	DWC_HWP1_BURSTWIDTH_M1_BITS		= 0x00000038,
++	DWC_HWP1_BURSTWIDTH_M1_SHIFT		= 3,
++
++	DWC_HWP1_DATAINFOWIDTH_BITS		= 0x000001c0,
++	DWC_HWP1_DATAINFOWIDTH_SHIFT		= 6,
++
++	DWC_HWP1_REQINFOWIDTH_BITS		= 0x00000e00,
++	DWC_HWP1_REQINFOWIDTH_SHIFT		= 9,
++
++	DWC_HWP1_ASPACEWIDTH_BITS		= 0x00007000,
++	DWC_HWP1_ASPACEWIDTH_SHIFT		= 12,
++
++	DWC_HWP1_DEV_NUM_INT_BITS		= 0x001f8000,
++	DWC_HWP1_DEV_NUM_INT_SHIFT		= 15,
++
++	DWC_HWP1_NUM_RAMS_BITS			= 0x00600000,
++	DWC_HWP1_NUM_RAMS_SHIFT			= 21,
++
++	DWC_HWP1_SPRAM_TYP_BIT			= 0x00800000,
++	DWC_HWP1_SPRAM_TYP_SHIFT		= 23,
++
++	DWC_HWP1_EN_PWROPT_BITS			= 0x03000000,
++	DWC_HWP1_EN_PWROPT_SHIFT		= 24,
++
++	DWC_EN_PWROPT_NONE		= 0,
++	DWC_EN_PWROPT_CLK_GATING_ONLY	= 1,
++	DWC_EN_PWROPT_HIBERNATION	= 2,
++
++	DWC_HWP1_MAC_PHY_CLKS_SYNC_BIT		= 0x04000000,
++	DWC_HWP1_MAC_PHY_CLKS_SYNC_SHIFT	= 26,
++
++	DWC_HWP1_MAC_RAM_CLKS_SYNC_BIT		= 0x08000000,
++	DWC_HWP1_MAC_RAM_CLKS_SYNC_SHIFT	= 27,
++
++	DWC_HWP1_RAM_BUS_CLKS_SYNC_BIT		= 0x10000000,
++	DWC_HWP1_RAM_BUS_CLKS_SYNC_SHIFT	= 28,
++
++	DWC_HWP1_RM_OPT_FEATURES_BIT		= 0x40000000,
++	DWC_HWP1_RM_OPT_FEATURES_SHIFT		= 30,
++} ghwparams1_data_t;
++
++/**
++ * This enum represents the bit fields of the Hardware Parameters 2
++ * Register (GHWPARAMS2).
++ */
++typedef enum ghwparams2_data {
++	DWC_HWP2_USERID_BITS	= 0xffffffff,
++	DWC_HWP2_USERID_SHIFT	= 0,
++} ghwparams2_data_t;
++
++/**
++ * This enum represents the bit fields of the Hardware Parameters 3
++ * Register (GHWPARAMS3).
++ */
++typedef enum ghwparams3_data {
++	DWC_HWP3_SSPHY_IFC_BITS		= 0x00000003,
++	DWC_HWP3_SSPHY_IFC_SHIFT	= 0,
++
++	DWC_HWP3_HSPHY_IFC_BITS		= 0x0000000c,
++	DWC_HWP3_HSPHY_IFC_SHIFT	= 2,
++
++	DWC_HWP3_FSPHY_IFC_BITS		= 0x00000030,
++	DWC_HWP3_FSPHY_IFC_SHIFT	= 4,
++
++	DWC_HWP3_HSPHY_DWIDTH_BITS	= 0x000000c0,
++	DWC_HWP3_HSPHY_DWIDTH_SHIFT	= 6,
++
++	DWC_HWP3_VEND_CTL_IFC_BIT	= 0x00000400,
++	DWC_HWP3_VEND_CTL_IFC_SHIFT	= 10,
++
++	DWC_HWP3_ULPI_CARKIT_BIT	= 0x00000800,
++	DWC_HWP3_ULPI_CARKIT_SHIFT	= 11,
++
++	DWC_HWP3_NUM_EPS_BITS		= 0x0003f000,
++	DWC_HWP3_NUM_EPS_SHIFT		= 12,
++
++	DWC_HWP3_NUM_IN_EPS_BITS	= 0x007c0000,
++	DWC_HWP3_NUM_IN_EPS_SHIFT	= 18,
++
++	DWC_HWP3_TOT_XFR_RSRC_BITS	= 0x7f800000,
++	DWC_HWP3_TOT_XFR_RSRC_SHIFT	= 23,
++} ghwparams3_data_t;
++
++/**
++ * This enum represents the bit fields of the Hardware Parameters 4
++ * Register (GHWPARAMS4).
++ */
++typedef enum ghwparams4_data {
++	DWC_HWP4_TRBS_PER_XFER_BITS	= 0x0000003f,
++	DWC_HWP4_TRBS_PER_XFER_SHIFT	= 0,
++
++	DWC_HWP4_HIBER_SPAD_BITS	= 0x0001e000,
++	DWC_HWP4_HIBER_SPAD_SHIFT	= 13,
++
++	DWC_HWP4_NUM_SS_USB_INST_BITS	= 0x001e0000,
++	DWC_HWP4_NUM_SS_USB_INST_SHIFT	= 17,
++
++	DWC_HWP4_EN_ISOC_SUPT_BIT	= 0x00800000,
++	DWC_HWP4_EN_ISOC_SUPT_SHIFT	= 23,
++
++	DWC_HWP4_BMU_PTL_DEPTH_BITS	= 0x0f000000,
++	DWC_HWP4_BMU_PTL_DEPTH_SHIFT	= 24,
++
++	DWC_HWP4_BMU_LSP_DEPTH_BITS	= 0xf0000000,
++	DWC_HWP4_BMU_LSP_DEPTH_SHIFT	= 28,
++} ghwparams4_data_t;
++
++/**
++ * This enum represents the bit fields of the Hardware Parameters 5
++ * Register (GHWPARAMS5).
++ */
++typedef enum ghwparams5_data {
++	DWC_HWP5_BMU_BUSGM_DEPTH_BITS	= 0x0000000f,
++	DWC_HWP5_BMU_BUSGM_DEPTH_SHIFT	= 0,
++
++	DWC_HWP5_RXQ_FIFO_DEPTH_BITS	= 0x000003f0,
++	DWC_HWP5_RXQ_FIFO_DEPTH_SHIFT	= 4,
++
++	DWC_HWP5_TXQ_FIFO_DEPTH_BITS	= 0x0000fc00,
++	DWC_HWP5_TXQ_FIFO_DEPTH_SHIFT	= 10,
++
++	DWC_HWP5_DWQ_FIFO_DEPTH_BITS	= 0x003f0000,
++	DWC_HWP5_DWQ_FIFO_DEPTH_SHIFT	= 16,
++
++	DWC_HWP5_DFQ_FIFO_DEPTH_BITS	= 0x0fc00000,
++	DWC_HWP5_DFQ_FIFO_DEPTH_SHIFT	= 22,
++} ghwparams5_data_t;
++
++/**
++ * This enum represents the bit fields of the Hardware Parameters 6
++ * Register (GHWPARAMS6).
++ */
++typedef enum ghwparams6_data {
++	DWC_HWP6_PSQ_FIFO_DEPTH_BITS	= 0x0000003f,
++	DWC_HWP6_PSQ_FIFO_DEPTH_SHIFT	= 0,
++
++	DWC_HWP6_EN_DBG_PORTS_BIT	= 0x00000040,
++	DWC_HWP6_EN_DBG_PORTS_SHIFT	= 6,
++
++	DWC_HWP6_EN_FPGA_BIT		= 0x00000080,
++	DWC_HWP6_EN_FPGA_SHIFT		= 7,
++
++	DWC_HWP6_EN_SRP_BIT		= 0x00000400,
++	DWC_HWP6_EN_SRP_SHIFT		= 10,
++
++	DWC_HWP6_EN_HNP_BIT		= 0x00000800,
++	DWC_HWP6_EN_HNP_SHIFT		= 11,
++
++	DWC_HWP6_EN_ADP_BIT		= 0x00001000,
++	DWC_HWP6_EN_ADP_SHIFT		= 12,
++
++	DWC_HWP6_EN_OTG_BIT		= 0x00002000,
++	DWC_HWP6_EN_OTG_SHIFT		= 13,
++
++	DWC_HWP6_EN_BC_BIT		= 0x00004000,
++	DWC_HWP6_EN_BC_SHIFT		= 14,
++
++	DWC_HWP6_EN_BUS_FILTERS_BIT	= 0x00008000,
++	DWC_HWP6_EN_BUS_FILTERS_SHIFT	= 15,
++
++	DWC_HWP6_RAM0_DEPTH_BITS	= 0xffff0000,
++	DWC_HWP6_RAM0_DEPTH_SHIFT	= 16,
++} ghwparams6_data_t;
++
++/**
++ * This enum represents the bit fields of the Hardware Parameters 7
++ * Register (GHWPARAMS7).
++ */
++typedef enum ghwparams7_data {
++	DWC_HWP7_RAM1_DEPTH_BITS	= 0x0000ffff,
++	DWC_HWP7_RAM1_DEPTH_SHIFT	= 0,
++
++	DWC_HWP7_RAM2_DEPTH_BITS	= 0xffff0000,
++	DWC_HWP7_RAM2_DEPTH_SHIFT	= 16,
++} ghwparams7_data_t;
++
++/**
++ * This enum represents the bit fields of the Hardware Parameters 8
++ * Register (GHWPARAMS8).
++ */
++typedef enum ghwparams8_data {
++	DWC_HWP8_DCACHE_DEPTH_BITS	= 0xffffffff,
++	DWC_HWP8_DCACHE_DEPTH_SHIFT	= 0,
++} ghwparams8_data_t;
++
++/**
++ * This enum represents the bit fields of the Debug Queue/FIFO Space
++ * Register (GDBGFIFOSPACE).
++ */
++typedef enum gdbgfifospace_data {
++	/** FIFO/Queue Select			<i>Access: R_W</i> */
++	DWC_DBGFIFOSPACE_FIFO_QUEUE_SEL_BITS	= 0x000000ff,
++	DWC_DBGFIFOSPACE_FIFO_QUEUE_SEL_SHIFT	= 0,
++
++	/*   0 - 31  TxFIFO Number   */
++	/*  32 - 63  RxFIFO Number   */
++	/*  64 - 95  TxReqQ Number   */
++	/*  96 - 127 RxReqQ Number   */
++	/* 128 - 159 RxInfoQ Number  */
++	/* 160       DescFetchQ      */
++	/* 161       EventQ          */
++	/* 162       ProtocolStatusQ */
++
++	/** Space Available			<i>Access: R</i> */
++	DWC_DBGFIFOSPACE_SPACE_AVAIL_BITS	= 0xffff0000,
++	DWC_DBGFIFOSPACE_SPACE_AVAIL_SHIFT	= 16,
++} gdbgfifospace_data_t;
++
++/**
++ * This enum represents the bit fields of the Debug LTSSM
++ * Register (GDBGLTSSM).
++ */
++typedef enum gdbgltssm_data {
++	/** Pipe Status				<i>Access: R</i> */
++	DWC_DBGLTSSM_PIPE_STATUS_BITS		= 0x0003ffff,
++	DWC_DBGLTSSM_PIPE_STATUS_SHIFT		= 0,
++
++	/** LTDB SubState			<i>Access: R</i> */
++	DWC_DBGLTSSM_LTDB_SUB_STATE_BITS	= 0x003c0000,
++	DWC_DBGLTSSM_LTDB_SUB_STATE_SHIFT	= 18,
++
++	/** LTDB State				<i>Access: R</i> */
++	DWC_DBGLTSSM_LTDB_STATE_BITS		= 0x03c00000,
++	DWC_DBGLTSSM_LTDB_STATE_SHIFT		= 22,
++
++	/** LTDB Timeout			<i>Access: R</i> */
++	DWC_DBGLTSSM_LTDB_TIMEOUT_BIT		= 0x04000000,
++	DWC_DBGLTSSM_LTDB_TIMEOUT_SHIFT		= 26,
++} gdbgltssm_data_t;
++
++/**
++ * This enum represents the bit fields of the Core RMMI PHY Control
++ * Registers (GUSB3RMMICTLn).
++ */
++typedef enum gusb3rmmictl_data {
++	DWC_RMMICTL_MPHY_STATE_BITS		= 0x0e000000,
++	DWC_RMMICTL_MPHY_STATE_SHIFT		= 25,
++
++#define DWC_MPHY_STATE_DISABLED		0
++#define DWC_MPHY_STATE_HIBERN8		1
++#define DWC_MPHY_STATE_SLEEP		2
++#define DWC_MPHY_STATE_STALL		3
++#define DWC_MPHY_STATE_PWM_BURST	4
++#define DWC_MPHY_STATE_HS_BURST		5
++#define DWC_MPHY_STATE_LINE_CFG		6
++#define DWC_MPHY_STATE_LINE_RESET	7
++
++	DWC_RMMICTL_AUTO_EXIT_RRAP_BIT		= 0x10000000,
++	DWC_RMMICTL_AUTO_EXIT_RRAP_SHIFT	= 28,
++
++	DWC_RMMICTL_AUTO_ROM_RRAP_BIT		= 0x20000000,
++	DWC_RMMICTL_AUTO_ROM_RRAP_SHIFT		= 29,
++
++	DWC_RMMICTL_AUTO_EXIT_H8_BIT		= 0x40000000,
++	DWC_RMMICTL_AUTO_EXIT_H8_SHIFT		= 30,
++
++	DWC_RMMICTL_AUTO_ROM_H8_BIT		= 0x80000000,
++	DWC_RMMICTL_AUTO_ROM_H8_SHIFT		= 31,
++} gusb3rmmictl_data_t;
++
++/**
++ * This enum represents the bit fields of the Core USB2 PHY Configuration
++ * Registers (GUSB2PHYCFGn).
++ */
++typedef enum gusb2phycfg_data {
++	/** HS/FS Timeout Calibration			<i>Access: R_W</i> */
++	DWC_USB2PHYCFG_TOUT_CAL_BITS		= 0x00000007,
++	DWC_USB2PHYCFG_TOUT_CAL_SHIFT		= 0,
++
++	/** UTMI+ PHY Intf Width (8-bit/16-bit) SelecT	<i>Access: R_W</i> */
++	DWC_USB2PHYCFG_16B_PHY_IF_BIT		= 0x00000008,
++	DWC_USB2PHYCFG_16B_PHY_IF_SHIFT		= 3,
++	/*--------*/
++	/** ULPI DDR Select				<i>Access: R_W</i> */
++	DWC_USB2PHYCFG_DDR_SEL_BIT		= 0x00000008,
++	DWC_USB2PHYCFG_DDR_SEL_SHIFT		= 3,
++
++	/** UTMI+ / ULPI Select				<i>Access: R_W</i> */
++	DWC_USB2PHYCFG_UTMI_ULPI_BIT		= 0x00000010,
++	DWC_USB2PHYCFG_UTMI_ULPI_SHIFT		= 4,
++
++	/** Full-speed Serial Interface Select		<i>Access: R_W</i> */
++	DWC_USB2PHYCFG_FSINTF_BIT		= 0x00000020,
++	DWC_USB2PHYCFG_FSINTF_SHIFT		= 5,
++
++	/** Suspend USB2 Phy				<i>Access: R_W</i> */
++	DWC_USB2PHYCFG_SUS_PHY_BIT		= 0x00000040,
++	DWC_USB2PHYCFG_SUS_PHY_SHIFT		= 6,
++
++	/** USB2.0 HS PHY/USB1.1 FS Serial Xcvr Select	<i>Access: R_W</i> */
++	DWC_USB2PHYCFG_PHY_SEL_BIT		= 0x00000080,
++	DWC_USB2PHYCFG_PHY_SEL_SHIFT		= 7,
++
++	/** Enable UTMI Sleep				<i>Access: R_W</i> */
++	DWC_USB2PHYCFG_ENBL_SLP_M_BIT		= 0x00000100,
++	DWC_USB2PHYCFG_ENBL_SLP_M_SHIFT		= 8,
++
++	/** USB2.0 Turnaround Time			<i>Access: R_W</i> */
++	DWC_USB2PHYCFG_USB_TRD_TIM_BITS		= 0x00003c00,
++	DWC_USB2PHYCFG_USB_TRD_TIM_SHIFT	= 10,
++
++	/** PHY Low-power Clock Select			<i>Access: R_W</i> */
++	DWC_USB2PHYCFG_PHY_LPWR_CLK_SEL_BIT	= 0x00004000,
++	DWC_USB2PHYCFG_PHY_LPWR_CLK_SEL_SHIFT	= 14,
++
++	/** ULPI Auto Resume				<i>Access: R_W</i> */
++	DWC_USB2PHYCFG_ULPI_AUTO_RES_BIT	= 0x00008000,
++	DWC_USB2PHYCFG_ULPI_AUTO_RES_SHIFT	= 15,
++
++	/** ULPI Clock SuspendM				<i>Access: R_W</i> */
++	DWC_USB2PHYCFG_ULPI_CLK_SUS_M_BIT	= 0x00010000,
++	DWC_USB2PHYCFG_ULPI_CLK_SUS_M_SHIFT	= 16,
++
++	/** ULPI External Vbus Drive			<i>Access: R_W</i> */
++	DWC_USB2PHYCFG_ULPI_EXT_VBUS_DRV_BIT	= 0x00020000,
++	DWC_USB2PHYCFG_ULPI_EXT_VBUS_DRV_SHIFT	= 17,
++
++	/** ULPI External Vbus Indicator		<i>Access: R_W</i> */
++	DWC_USB2PHYCFG_ULPI_EXT_VBUS_IND_BIT	= 0x00040000,
++	DWC_USB2PHYCFG_ULPI_EXT_VBUS_IND_SHIFT	= 18,
++
++	/** PHY Interrupt Number			<i>Access: R_W</i> */
++	DWC_USB2PHYCFG_PHY_INTR_NUM_BITS	= 0x01f80000,
++	DWC_USB2PHYCFG_PHY_INTR_NUM_SHIFT	= 19,
++
++	/** OTG Interrupt Number			<i>Access: R_W</i> */
++	DWC_USB2PHYCFG_OTG_INTR_NUM_BITS	= 0x7e000000,
++	DWC_USB2PHYCFG_OTG_INTR_NUM_SHIFT	= 25,
++
++	/** PHY Soft Reset				<i>Access: R_W</i> */
++	DWC_USB2PHYCFG_PHY_SOFT_RST_BIT		= 0x80000000,
++	DWC_USB2PHYCFG_PHY_SOFT_RST_SHIFT	= 31,
++} gusb2phycfg_data_t;
++
++/**
++ * This enum represents the bit fields in the USB2 I2C Control
++ * Registers (GUSB2I2CCTLn).
++ */
++typedef enum gusb2i2cctl_data {
++	/** All bits are reserved */
++	DWC_USB2I2C_RSVD_BITS		= 0xffffffff,
++	DWC_USB2I2C_RSVD_SHIFT		= 0,
++} gusb2i2cctl_data_t;
++
++/**
++ * This enum represents the bit fields in the USB2 Phy Vendor Control
++ * Registers (GUSB2PHYACCn).
++ */
++typedef enum gusb2phyacc_data {
++	/** Register Data			<i>Access: R_W</i> */
++	DWC_USB2PHY_REGDATA_BITS	= 0x000000ff,
++	DWC_USB2PHY_REGDATA_SHIFT	= 0,
++
++	/** UTMI+ Vendor Ctrl Register Address	<i>Access: R_W</i> */
++	DWC_USB2PHY_VCTRL_BITS		= 0x0000ff00,
++	DWC_USB2PHY_VCTRL_SHIFT		= 8,
++	/*--------*/
++	/** ULPI Extended Register Address	<i>Access: R_W</i> */
++	DWC_USB2PHY_EXTREGADDR_BITS	= 0x00003f00,
++	DWC_USB2PHY_EXTREGADDR_SHIFT	= 8,
++
++	/** Register Address			<i>Access: R_W</i> */
++	DWC_USB2PHY_REGADDR_BITS	= 0x003f0000,
++	DWC_USB2PHY_REGADDR_SHIFT	= 16,
++
++	/** Register Write			<i>Access: R_W</i> */
++	DWC_USB2PHY_REGWR_BIT		= 0x00400000,
++	DWC_USB2PHY_REGWR_SHIFT		= 22,
++
++	/** VStatus Busy			<i>Access: RO</i> */
++	DWC_USB2PHY_VSTSBSY_BIT		= 0x00800000,
++	DWC_USB2PHY_VSTSBSY_SHIFT	= 23,
++
++	/** VStatus Done			<i>Access: R_SS_SC</i> */
++	DWC_USB2PHY_VSTSDONE_BIT	= 0x01000000,
++	DWC_USB2PHY_VSTSDONE_SHIFT	= 24,
++
++	/** New Register Request		<i>Access: R_WS_SC</i> */
++	DWC_USB2PHY_NEWREGREQ_BIT	= 0x02000000,
++	DWC_USB2PHY_NEWREGREQ_SHIFT	= 25,
++
++	/** Disable ULPI Drivers		<i>Access: R_WS_SC</i> */
++	DWC_USB2PHY_DIS_ULPI_DRVR_BIT	= 0x04000000,
++	DWC_USB2PHY_DIS_ULPI_DRVR_SHIFT	= 26,
++} gusb2phyacc_data_t;
++
++/**
++ * This enum represents the bit fields of the USB3 Pipe Control
++ * Registers (GUSB3PIPECTLn).
++ */
++typedef enum gusb3pipectl_data {
++	/** Elastic Buffer Mode			<i>Access: R_W</i> */
++	DWC_PIPECTL_ELAS_BUF_MODE_BIT		= 0x00000001,
++	DWC_PIPECTL_ELAS_BUF_MODE_SHIFT		= 0,
++
++	/** Tx De-Emphasis			<i>Access: R_W</i> */
++	DWC_PIPECTL_TX_DEMPH_BITS		= 0x00000006,
++	DWC_PIPECTL_TX_DEMPH_SHIFT		= 1,
++
++	/** Tx Margin				<i>Access: R_W</i> */
++	DWC_PIPECTL_TX_MARGIN_BITS		= 0x00000038,
++	DWC_PIPECTL_TX_MARGIN_SHIFT		= 3,
++
++	/** Tx Swing				<i>Access: R_W</i> */
++	DWC_PIPECTL_TX_SWING_BIT		= 0x00000040,
++	DWC_PIPECTL_TX_SWING_SHIFT		= 6,
++
++	/** USB3 SSIC Enable			<i>Access: R_W</i> */
++	DWC_PIPECTL_SSIC_EN_BIT			= 0x00000080,
++	DWC_PIPECTL_SSIC_EN_SHIFT		= 7,
++
++	/** LFPS Filter				<i>Access: R_W</i> */
++	DWC_PIPECTL_LFPS_FILTER_BIT		= 0x00000200,
++	DWC_PIPECTL_LFPS_FILTER_SHIFT		= 9,
++
++	/** P3 Exit Signal In P2		<i>Access: R_W</i> */
++	DWC_PIPECTL_P3_EX_SIG_P2_BIT		= 0x00000400,
++	DWC_PIPECTL_P3_EX_SIG_P2_SHIFT		= 10,
++
++	/** P3-P2 Transitions OK		<i>Access: R_W</i> */
++	DWC_PIPECTL_P3_P2_TRAN_OK_BIT		= 0x00000800,
++	DWC_PIPECTL_P3_P2_TRAN_OK_SHIFT		= 11,
++
++	/** LFPS P0 Align			<i>Access: R_W</i> */
++	DWC_PIPECTL_LFPS_P0_ALGN_BIT		= 0x00001000,
++	DWC_PIPECTL_LFPS_P0_ALGN_SHIFT		= 12,
++
++	/** Pipe Data Width			<i>Access: R_W</i> */
++	DWC_PIPECTL_DATA_WIDTH_BITS		= 0x00018000,
++	DWC_PIPECTL_DATA_WIDTH_SHIFT		= 15,
++
++	/** Suspend USB3 Phy			<i>Access: R_W</i> */
++	DWC_PIPECTL_SUS_PHY_BIT			= 0x00020000,
++	DWC_PIPECTL_SUS_PHY_SHIFT		= 17,
++
++	/** PHY Soft Reset			<i>Access: R_W</i> */
++	DWC_PIPECTL_PHY_SOFT_RST_BIT		= 0x80000000,
++	DWC_PIPECTL_PHY_SOFT_RST_SHIFT		= 31,
++} gusb3pipectl_data_t;
++
++/**
++ * This enum represents the bit fields in the FIFO Size Registers.
++ */
++typedef enum gfifosize_data {
++	/** Depth				<i>Access: R_W</i> */
++	DWC_FIFOSZ_DEPTH_BITS		= 0x0000ffff,
++	DWC_FIFOSZ_DEPTH_SHIFT		= 0,
++
++	/** Starting Address			<i>Access: RO or R_W</i> */
++	DWC_FIFOSZ_STARTADDR_BITS	= 0xffff0000,
++	DWC_FIFOSZ_STARTADDR_SHIFT	= 16,
++} gfifosize_data_t;
++
++/**
++ * This enum represents the bit fields of the Event Buffer Size
++ * Registers (GEVENTSIZn).
++ */
++typedef enum geventsiz_data {
++	/** Event Buffer Size			<i>Access: R_W</i> */
++	DWC_EVENTSIZ_SIZ_BITS		= 0x0000ffff,
++	DWC_EVENTSIZ_SIZ_SHIFT		= 0,
++
++	/** Event Interrupt Mask (1 == disable)	<i>Access: R_W</i> */
++	DWC_EVENTSIZ_INT_MSK_BIT	= 0x80000000,
++	DWC_EVENTSIZ_INT_MSK_SHIFT	= 31,
++} geventsiz_data_t;
++
++/**
++ * This enum represents the bit fields of the Event Buffer Count
++ * Registers (GEVENTCNTn).
++ */
++typedef enum geventcnt_data {
++	/** Event Count				<i>Access: R_W</i> */
++	DWC_EVENTCNT_CNT_BITS		= 0x0000ffff,
++	DWC_EVENTCNT_CNT_SHIFT		= 0,
++} geventcnt_data_t;
++
++/**
++ * This enum represents the bit fields of a generic Event Buffer entry.
++ */
++typedef enum gevent_data {
++	/** Non-Endpoint Specific Event flag */
++	DWC_EVENT_NON_EP_BIT			= 0x01,
++	DWC_EVENT_NON_EP_SHIFT			= 0,
++
++	/** Non-Endpoint Specific Event Type */
++	DWC_EVENT_INTTYPE_BITS			= 0xfe,
++	DWC_EVENT_INTTYPE_SHIFT			= 1,
++
++	/** Non-Endpoint Specific Event Type values */
++	DWC_EVENT_DEV_INT		= 0,	/** @< */
++	DWC_EVENT_OTG_INT		= 1,	/** @< */
++	DWC_EVENT_CARKIT_INT		= 3,	/** @< */
++	DWC_EVENT_I2C_INT		= 4,
++} gevent_data_t;
++
++/**
++ * This enum represents the non-generic bit fields of an Event Buffer entry
++ * for Device Specific events (DEVT).
++ */
++typedef enum devt_data {
++	/** Device Specific Event Type */
++	DWC_DEVT_BITS				= 0x00000f00,
++	DWC_DEVT_SHIFT				= 8,
++
++	/** Device Specific Event Type values */
++	DWC_DEVT_DISCONN		= 0,	/** @< */
++	DWC_DEVT_USBRESET		= 1,	/** @< */
++	DWC_DEVT_CONNDONE		= 2,	/** @< */
++	DWC_DEVT_ULST_CHNG		= 3,	/** @< */
++	DWC_DEVT_WKUP			= 4,	/** @< */
++	DWC_DEVT_HIBER_REQ		= 5,	/** @< */
++	DWC_DEVT_U3_L2L1_SUSP		= 6,	/** @< */
++	DWC_DEVT_SOF			= 7,	/** @< */
++	DWC_DEVT_ERRATICERR		= 9,	/** @< */
++	DWC_DEVT_CMD_CMPL		= 10,	/** @< */
++	DWC_DEVT_OVERFLOW		= 11,	/** @< */
++	DWC_DEVT_VNDR_DEV_TST_RCVD	= 12,	/** @< */
++	DWC_DEVT_INACT_TIMEOUT_RCVD	= 13,
++
++	/** Event Information */
++	DWC_DEVT_EVT_INFO_BITS			= 0xffff0000,
++	DWC_DEVT_EVT_INFO_SHIFT			= 16,
++
++	/** USB/Link State */
++	DWC_DEVT_ULST_STATE_BITS		= 0x000f0000,
++	DWC_DEVT_ULST_STATE_SHIFT		= 16,
++
++	/** USB/Link State values in SS */
++	DWC_LINK_STATE_U0		= 0,	/** @< */
++	DWC_LINK_STATE_U1		= 1,	/** @< */
++	DWC_LINK_STATE_U2		= 2,	/** @< */
++	DWC_LINK_STATE_U3		= 3,	/** @< */
++	DWC_LINK_STATE_SS_DIS		= 4,	/** @< */
++	DWC_LINK_STATE_RX_DET		= 5,	/** @< */
++	DWC_LINK_STATE_SS_INACT		= 6,	/** @< */
++	DWC_LINK_STATE_POLL		= 7,	/** @< */
++	DWC_LINK_STATE_RECOV		= 8,	/** @< */
++	DWC_LINK_STATE_HRESET		= 9,	/** @< */
++	DWC_LINK_STATE_CMPLY		= 10,	/** @< */
++	DWC_LINK_STATE_LPBK		= 11,	/** @< */
++	DWC_LINK_STATE_RESET		= 14,	/** @< */
++	DWC_LINK_STATE_RESUME		= 15,
++
++	/** USB/Link State values in HS/FS/LS */
++	DWC_LINK_STATE_ON		= 0,	/** @< */
++	DWC_LINK_STATE_SLEEP		= 2,	/** @< */
++	DWC_LINK_STATE_SUSPEND		= 3,	/** @< */
++	DWC_LINK_STATE_EARLY_SUSPEND	= 5,
++
++	DWC_DEVT_ULST_SS_BIT			= 0x00100000,
++	DWC_DEVT_ULST_SS_SHIFT			= 20,
++
++#define DWC_DEVT_HIBER_STATE_BITS	DWC_DEVT_ULST_STATE_BITS
++#define DWC_DEVT_HIBER_STATE_SHIFT	DWC_DEVT_ULST_STATE_SHIFT
++
++#define DWC_DEVT_HIBER_SS_BIT		DWC_DEVT_ULST_SS_BIT
++#define DWC_DEVT_HIBER_SS_SHIFT		DWC_DEVT_ULST_SS_SHIFT
++
++	DWC_DEVT_HIBER_HIRD_BITS		= 0x0f000000,
++	DWC_DEVT_HIBER_HIRD_SHIFT		= 24,
++} devt_data_t;
++
++/**
++ * This enum represents the bit fields of an Event Buffer entry for
++ * Endpoint Specific events (DEPEVT).
++ */
++typedef enum depevt_data {
++	/** Endpoint Number */
++	DWC_DEPEVT_EPNUM_BITS			= 0x0000003e,
++	DWC_DEPEVT_EPNUM_SHIFT			= 1,
++
++	/** Endpoint Event Type */
++	DWC_DEPEVT_INTTYPE_BITS			= 0x000003c0,
++	DWC_DEPEVT_INTTYPE_SHIFT		= 6,
++
++	/** Endpoint Event Type values */
++	DWC_DEPEVT_XFER_CMPL		= 1,	/** @< */
++	DWC_DEPEVT_XFER_IN_PROG		= 2,	/** @< */
++	DWC_DEPEVT_XFER_NRDY		= 3,	/** @< */
++	DWC_DEPEVT_FIFOXRUN		= 4,	/** @< */
++	DWC_DEPEVT_STRM_EVT		= 6,	/** @< */
++	DWC_DEPEVT_EPCMD_CMPL		= 7,
++
++	/** Event Status for Start Xfer Command */
++	DWC_DEPEVT_NO_MORE_RSCS_BIT		= 0x00001000,
++	DWC_DEPEVT_NO_MORE_RSCS_SHIFT		= 12,
++	DWC_DEPEVT_ISOC_TIME_PASSED_BIT		= 0x00002000,
++	DWC_DEPEVT_ISOC_TIME_PASSED_SHIFT	= 13,
++
++	/** Event Status for Stream Event */
++	DWC_DEPEVT_STRM_EVT_BITS		= 0x0000f000,
++	DWC_DEPEVT_STRM_EVT_SHIFT		= 12,
++
++	/** Stream Event Status values */
++	DWC_DEPEVT_STRM_FOUND		= 1,	/** @< */
++	DWC_DEPEVT_STRM_NOT_FOUND	= 2,
++
++	/** Event Status for Xfer Complete or Xfer In Progress Event */
++	DWC_DEPEVT_BUS_ERR_BIT			= 0x00001000,
++	DWC_DEPEVT_BUS_ERR_SHIFT		= 12,
++	DWC_DEPEVT_SHORT_PKT_BIT		= 0x00002000,
++	DWC_DEPEVT_SHORT_PKT_SHIFT		= 13,
++	DWC_DEPEVT_IOC_BIT			= 0x00004000,
++	DWC_DEPEVT_IOC_SHIFT			= 14,
++	DWC_DEPEVT_LST_BIT			= 0x00008000,
++	DWC_DEPEVT_LST_SHIFT			= 15,
++#define DWC_DEPEVT_MISSED_ISOC_BIT	DWC_DEPEVT_LST_BIT
++#define DWC_DEPEVT_MISSED_ISOC_SHIFT	DWC_DEPEVT_LST_SHIFT
++
++	/** Event Status for Xfer Not Ready Event */
++	DWC_DEPEVT_CTRL_BITS			= 0x00003000,
++	DWC_DEPEVT_CTRL_SHIFT			= 12,
++	DWC_DEPEVT_XFER_ACTIVE_BIT		= 0x00008000,
++	DWC_DEPEVT_XFER_ACTIVE_SHIFT		= 15,
++
++	/** Xfer Not Ready Event Status values */
++	DWC_DEPEVT_CTRL_SETUP		= 0,	/** @< */
++	DWC_DEPEVT_CTRL_DATA		= 1,	/** @< */
++	DWC_DEPEVT_CTRL_STATUS		= 2,
++
++	/** Stream ID */
++	DWC_DEPEVT_STRM_ID_BITS			= 0xffff0000,
++	DWC_DEPEVT_STRM_ID_SHIFT		= 16,
++
++	/** Isoc uFrame Number (for Xfer Not Ready on Isoc EP) */
++	DWC_DEPEVT_ISOC_UFRAME_NUM_BITS		= 0xffff0000,
++	DWC_DEPEVT_ISOC_UFRAME_NUM_SHIFT	= 16,
++
++	/** Xfer Resource Index (for Start Xfer Command) */
++	DWC_DEPEVT_XFER_RSC_IDX_BITS		= 0x007f0000,
++	DWC_DEPEVT_XFER_RSC_IDX_SHIFT		= 16,
++
++	/** Current Data Sequence Number (for Get Endpoint State Command) */
++	DWC_DEPEVT_CUR_DAT_SEQ_NUM_BITS		= 0x001f0000,
++	DWC_DEPEVT_CUR_DAT_SEQ_NUM_SHIFT	= 16,
++
++	/** Flow Control State (for Get Endpoint State Command) */
++	DWC_DEPEVT_FLOW_CTRL_BIT		= 0x00200000,
++	DWC_DEPEVT_FLOW_CTRL_SHIFT		= 21,
++} depevt_data_t;
++
++/**
++ * This enum represents the non-generic bit fields of an Event Buffer entry
++ * for other Core events (GEVT).
++ */
++typedef enum gevt_data {
++	/** PHY Port Number */
++	DWC_GINT_PHY_PORT_BITS		= 0xf00,
++	DWC_GINT_PHY_PORT_SHIFT		= 8,
++} gevt_data_t;
++
++/**
++ * This struct represents the 32-bit register fields of the Event Buffer
++ * Registers (GEVENTBUFn).
++ */
++typedef struct geventbuf_data {
++	/** Event Buffer Address Register Low Word */
++	volatile u32 geventadr_lo;
++
++	/** Event Buffer Address Register High Word */
++	volatile u32 geventadr_hi;
++
++	/** Event Buffer Size Register.
++	 * Fields defined in enum @ref geventsiz_data. */
++	volatile u32 geventsiz;
++
++	/** Event Buffer Count Register.
++	 * Fields defined in enum @ref geventcnt_data. */
++	volatile u32 geventcnt;
++} geventbuf_data_t;
++
++/**
++ * Core Global Registers	<i>Offsets 100h-5FCh</i>.
++ *
++ * The dwc_usb3_core_global_regs structure defines the size
++ * and relative field offsets for the Core Global Registers.
++ */
++typedef struct dwc_usb3_core_global_regs {
++
++#define DWC_CORE_GLOBAL_REG_OFFSET	0x100
++
++	/** Core BIU Configuration 0 Register	<i>Offset: 100h</i>.
++	 * Fields defined in enum @ref gsbuscfg0_data. */
++	volatile u32 gsbuscfg0;
++
++	/** Core BIU Configuration 1 Register	<i>Offset: 104h</i>.
++	 * Fields defined in enum @ref gsbuscfg1_data. */
++	volatile u32 gsbuscfg1;
++
++	/** Core Tx Threshold Control Register	<i>Offset: 108h</i>.
++	 * Fields defined in enum @ref gtxthrcfg_data. */
++	volatile u32 gtxthrcfg;
++
++	/** Core Threshold Control Register	<i>Offset: 10Ch</i>.
++	 * Fields defined in enum @ref grxthrcfg_data. */
++	volatile u32 grxthrcfg;
++
++	/** Core Control Register		<i>Offset: 110h</i>.
++	 * Fields defined in enum @ref gctl_data. */
++	volatile u32 gctl;
++
++	/** Core Interrupt Mask Register	<i>Offset: 114h</i>.
++	 * Fields defined in enum @ref gevten_data. */
++	volatile u32 gevten;
++
++	/** Core Status Register		<i>Offset: 118h</i>.
++	 * Fields defined in enum @ref gsts_data. */
++	volatile u32 gsts;
++
++	/** Core User Control 1 Register	<i>Offset: 11Ch</i> */
++	volatile u32 guctl1;
++
++	/** Synopsys ID Register		<i>Offset: 120h</i> */
++	volatile u32 gsnpsid;
++
++	/** General Purpose I/O Register	<i>Offset: 124h</i> */
++	volatile u32 ggpio;
++
++	/** User ID Register			<i>Offset: 128h</i> */
++	volatile u32 guid;
++
++	/** Core User Control Register		<i>Offset: 12Ch</i> */
++	volatile u32 guctl;
++
++	/** Bus Error Address Register		<i>Offset: 130h</i> */
++	volatile u32 gbuserraddrlo;
++
++	/** Bus Error Address Register		<i>Offset: 134h</i> */
++	volatile u32 gbuserraddrhi;
++
++	/** SS Port to Bus Instance Mapping Register	<i>Offset: 138h</i> */
++	volatile u32 gprtbimap_lo;
++
++	/** SS Port to Bus Instance Mapping Register	<i>Offset: 13Ch</i> */
++	volatile u32 gprtbimap_hi;
++
++	/** Hardware Parameter 0 Register	<i>Offset: 140h</i>.
++	 * Fields defined in enum @ref ghwparams0_data. */
++	volatile u32 ghwparams0;
++
++	/** Hardware Parameter 1 Register	<i>Offset: 144h</i>.
++	 * Fields defined in enum @ref ghwparams1_data. */
++	volatile u32 ghwparams1;
++
++	/** Hardware Parameter 2 Register	<i>Offset: 148h</i>.
++	 * Fields defined in enum @ref ghwparams2_data. */
++	volatile u32 ghwparams2;
++
++	/** Hardware Parameter 3 Register	<i>Offset: 14Ch</i>.
++	 * Fields defined in enum @ref ghwparams3_data. */
++	volatile u32 ghwparams3;
++
++	/** Hardware Parameter 4 Register	<i>Offset: 150h</i>.
++	 * Fields defined in enum @ref ghwparams4_data. */
++	volatile u32 ghwparams4;
++
++	/** Hardware Parameter 5 Register	<i>Offset: 154h</i>.
++	 * Fields defined in enum @ref ghwparams5_data. */
++	volatile u32 ghwparams5;
++
++	/** Hardware Parameter 6 Register	<i>Offset: 158h</i>.
++	 * Fields defined in enum @ref ghwparams6_data. */
++	volatile u32 ghwparams6;
++
++	/** Hardware Parameter 7 Register	<i>Offset: 15Ch</i>.
++	 * Fields defined in enum @ref ghwparams7_data. */
++	volatile u32 ghwparams7;
++
++	/** Debug Queue/FIFO Space Register	<i>Offset: 160h</i>.
++	 * Fields defined in enum @ref gdbgfifospace_data. */
++	volatile u32 gdbgfifospace;
++
++	/** Debug LTSSM Register		<i>Offset: 164h</i>.
++	 * Fields defined in enum @ref gdbgltssm_data */
++	volatile u32 gdbgltssm;
++
++	/** Debug LNMCC Register		<i>Offset: 168h</i> */
++	volatile u32 gdbglnmcc;
++
++	/** Debug BMU Register			<i>Offset: 16Ch</i> */
++	volatile u32 gdbgbmu;
++
++	/** Debug LSP Mux Register		<i>Offset: 170h</i> */
++	volatile u32 gdbglspmux;
++
++	/** Debug LSP Register			<i>Offset: 174h</i> */
++	volatile u32 gdbglsp;
++
++	/** Debug EP Info 0 Register		<i>Offset: 178h</i> */
++	volatile u32 gdbgepinfo0;
++
++	/** Debug EP Info 1 Register		<i>Offset: 17Ch</i> */
++	volatile u32 gdbgepinfo1;
++
++	/** HS Port to Bus Instance Mapping Register	<i>Offset: 180h</i> */
++	volatile u32 gprtbimap_hs_lo;
++
++	/** HS Port to Bus Instance Mapping Register	<i>Offset: 184h</i> */
++	volatile u32 gprtbimap_hs_hi;
++
++	/** FS Port to Bus Instance Mapping Register	<i>Offset: 188h</i> */
++	volatile u32 gprtbimap_fs_lo;
++
++	/** FS Port to Bus Instance Mapping Register	<i>Offset: 18Ch</i> */
++	volatile u32 gprtbimap_fs_hi;
++
++	/** reserved				<i>Offset: 190h-1BCh</i> */
++	volatile u32 reserved4[12];
++
++	/** Global RMMI PHY Control Register	<i>Offset: 1C0h-200h</i> */
++	volatile u32 gusb3rmmictl[16];
++
++	/** USB2 Configuration Registers	<i>Offset: 200h-23Ch</i>.
++	 * Fields defined in enum @ref gusb2phycfg_data. */
++	volatile u32 gusb2phycfg[16];
++
++	/** USB2 I2C Access Registers		<i>Offset: 240h-27Ch</i>.
++	 * Fields defined in enum @ref gusb2i2cctl_data. */
++	volatile u32 gusb2i2cctl[16];
++
++	/** USB2 PHY Vendor Control Registers	<i>Offset: 280h-2BCh</i>.
++	 * Fields defined in enum @ref gusb2phyacc_data. */
++	volatile u32 gusb2phyacc[16];
++
++	/** USB3 Pipe Control Registers		<i>Offset: 2C0h-2FCh</i>.
++	 * Fields defined in enum @ref gusb3pipectl_data. */
++	volatile u32 gusb3pipectl[16];
++
++	/** Transmit FIFO Size Registers	<i>Offset: 300h-37Ch</i>.
++	 * Fields defined in enum @ref gfifosize_data. */
++	volatile u32 gtxfifosiz[32];
++
++	/** Receive FIFO Size Registers		<i>Offset: 380h-3FC0h</i>.
++	 * Fields defined in enum @ref gfifosize_data. */
++	volatile u32 grxfifosiz[32];
++
++	/** Event Buffer Registers		<i>Offset: 400h-5FCh</i>.
++	 * Fields defined in struct @ref geventbuf_data. */
++	struct geventbuf_data geventbuf[32];
++
++	/** Hardware Parameter 8 Register	<i>Offset: 600h</i>.
++	 * Fields defined in enum @ref ghwparams8_data. */
++	volatile u32 ghwparams8;
++} dwc_usb3_core_global_regs_t;
++
++
++/****************************************************************************/
++/* Device Global Registers */
++
++/**
++ * This enum represents the bit fields in the Device Configuration
++ * Register (DCFG).
++ */
++typedef enum dcfg_data {
++	/** Device Speed			<i>Access: R_W</i> */
++	DWC_DCFG_DEVSPD_BITS		= 0x000007,
++	DWC_DCFG_DEVSPD_SHIFT		= 0,
++
++	/** Device Speed values */
++	DWC_SPEED_HS_PHY_30MHZ_OR_60MHZ		= 0,	/** @< */
++	DWC_SPEED_FS_PHY_30MHZ_OR_60MHZ		= 1,	/** @< */
++	DWC_SPEED_LS_PHY_6MHZ			= 2,	/** @< */
++	DWC_SPEED_FS_PHY_48MHZ			= 3,	/** @< */
++	DWC_SPEED_SS_PHY_125MHZ_OR_250MHZ	= 4,
++
++	/** Device Address			<i>Access: R_W</i> */
++	DWC_DCFG_DEVADDR_BITS		= 0x0003f8,
++	DWC_DCFG_DEVADDR_SHIFT		= 3,
++
++	/** Periodic Frame Interval		<i>Access: R_W</i> */
++	DWC_DCFG_PER_FR_INTVL_BITS	= 0x000c00,
++	DWC_DCFG_PER_FR_INTVL_SHIFT	= 10,
++
++	/** Periodic Frame Interval values */
++	DWC_DCFG_PER_FR_INTVL_80		= 0,	/** @< */
++	DWC_DCFG_PER_FR_INTVL_85		= 1,	/** @< */
++	DWC_DCFG_PER_FR_INTVL_90		= 2,	/** @< */
++	DWC_DCFG_PER_FR_INTVL_95		= 3,
++
++	/** Device Interrupt Number		<i>Access: R_W</i> */
++	DWC_DCFG_DEV_INTR_NUM_BITS	= 0x01f000,
++	DWC_DCFG_DEV_INTR_NUM_SHIFT	= 12,
++
++	/** Number of Receive Buffers		<i>Access: R_W</i> */
++	DWC_DCFG_NUM_RCV_BUF_BITS	= 0x3e0000,
++	DWC_DCFG_NUM_RCV_BUF_SHIFT	= 17,
++
++	/** LPM Capable				<i>Access: R_W</i> */
++	DWC_DCFG_LPM_CAP_BIT		= 0x400000,
++	DWC_DCFG_LPM_CAP_SHIFT		= 22,
++} dcfg_data_t;
++
++/**
++ * This enum represents the bit fields in the Device Control
++ * Register (DCTL).
++ */
++typedef enum dctl_data {
++	/** Soft Disconnect			<i>Access: R_W</i> */
++	DWC_DCTL_SFT_DISCONN_BIT		= 0x00000001,
++	DWC_DCTL_SFT_DISCONN_SHIFT		= 0,
++
++	/** Test Control			<i>Access: R_W</i> */
++	DWC_DCTL_TSTCTL_BITS			= 0x0000001e,
++	DWC_DCTL_TSTCTL_SHIFT			= 1,
++
++	/** USB/Link State Change Request	<i>Access: R_W</i> */
++	DWC_DCTL_ULST_CHNG_REQ_BITS		= 0x000001e0,
++	DWC_DCTL_ULST_CHNG_REQ_SHIFT		= 5,
++
++	/** Requested Link State Transition/Action In SS Mode */
++	DWC_LINK_STATE_REQ_NO_ACTION		= 0,	/** @< */
++	DWC_LINK_STATE_REQ_SS_DISABLED		= 4,	/** @< */
++	DWC_LINK_STATE_REQ_RX_DETECT		= 5,	/** @< */
++	DWC_LINK_STATE_REQ_INACTIVE		= 6,	/** @< */
++	DWC_LINK_STATE_REQ_RECOVERY		= 8,	/** @< */
++	DWC_LINK_STATE_REQ_COMPLIANCE		= 10,	/** @< */
++	DWC_LINK_STATE_REQ_LOOPBACK		= 11,	/** @< */
++	DWC_LINK_STATE_REQ_HOST_MODE_ONLY	= 15,
++
++	/** Requested Link State Transition/Action In HS/FS/LS Mode */
++	DWC_LINK_STATE_REQ_REMOTE_WAKEUP	= 8,
++
++	/** U1/U2 control			<i>Access: R_W</i> */
++	DWC_DCTL_ACCEPT_U1_EN_BIT		= 0x00000200,
++	DWC_DCTL_ACCEPT_U1_EN_SHIFT		= 9,
++	DWC_DCTL_INIT_U1_EN_BIT			= 0x00000400,
++	DWC_DCTL_INIT_U1_EN_SHIFT		= 10,
++	DWC_DCTL_ACCEPT_U2_EN_BIT		= 0x00000800,
++	DWC_DCTL_ACCEPT_U2_EN_SHIFT		= 11,
++	DWC_DCTL_INIT_U2_EN_BIT			= 0x00001000,
++	DWC_DCTL_INIT_U2_EN_SHIFT		= 12,
++
++	/** Controller Save State		<i>Access: R_W</i> */
++	DWC_DCTL_CSS_BIT			= 0x00010000,
++	DWC_DCTL_CSS_SHIFT			= 16,
++
++	/** Controller Restore State		<i>Access: R_W</i> */
++	DWC_DCTL_CRS_BIT			= 0x00020000,
++	DWC_DCTL_CRS_SHIFT			= 17,
++
++	/** L1 Hibernation Enable		<i>Access: R_W</i> */
++	DWC_DCTL_L1_HIBER_EN_BIT		= 0x00040000,
++	DWC_DCTL_L1_HIBER_EN_RES_SHIFT		= 18,
++
++	/** Keep Connect (for hibernation)	<i>Access: R_W</i> */
++	DWC_DCTL_KEEP_CONNECT_BIT		= 0x00080000,
++	DWC_DCTL_KEEP_CONNECT_SHIFT		= 19,
++
++	/** LPM NYET Response Threshold		<i>Access: R_W</i> */
++	DWC_DCTL_LPM_NYET_THRESH_BITS		= 0x00f00000,
++	DWC_DCTL_LPM_NYET_THRESH_SHIFT		= 20,
++
++	/** LPM Response			<i>Access: R_W</i> */
++	DWC_DCTL_APP_L1_RES_BIT			= 0x00800000,
++	DWC_DCTL_APP_L1_RES_SHIFT		= 23,
++
++	/* HIRD Threshold			<i>Access: R_W</i> */
++	DWC_DCTL_HIRD_THR_BITS			= 0x1f000000,
++	DWC_DCTL_HIRD_THR_SHIFT			= 24,
++
++	/** Light Soft Reset			<i>Access: R_W</i> */
++	DWC_DCTL_LSFT_RST_BIT			= 0x20000000,
++	DWC_DCTL_LSFT_RST_SHIFT			= 29,
++
++	/** Core Soft Reset			<i>Access: R_W</i> */
++	DWC_DCTL_CSFT_RST_BIT			= 0x40000000,
++	DWC_DCTL_CSFT_RST_SHIFT			= 30,
++
++	/** Run/Stop				<i>Access: R_W</i> */
++	DWC_DCTL_RUN_STOP_BIT			= 0x80000000,
++	DWC_DCTL_RUN_STOP_SHIFT			= 31,
++} dctl_data_t;
++
++/**
++ * This enum represents the bit fields of the Device Event Enable
++ * Register (DEVTEN).
++ */
++typedef enum devten_data {
++	/** Disconnect Detected Event Enable	<i>Access: R_W</i> */
++	DWC_DEVTEN_DISCONN_BIT		= 0x0001,
++	DWC_DEVTEN_DISCONN_SHIFT	= 0,
++
++	/** USB Reset Enable			<i>Access: R_W</i> */
++	DWC_DEVTEN_USBRESET_BIT		= 0x0002,
++	DWC_DEVTEN_USBRESET_SHIFT	= 1,
++
++	/** Connect Done Enable			<i>Access: R_W</i> */
++	DWC_DEVTEN_CONNDONE_BIT		= 0x0004,
++	DWC_DEVTEN_CONNDONE_SHIFT	= 2,
++
++	/** USB/Link State Change Event Enable	<i>Access: R_W</i> */
++	DWC_DEVTEN_ULST_CHNG_BIT	= 0x0008,
++	DWC_DEVTEN_ULST_CHNG_SHIFT	= 3,
++
++	/** Resume/Remote-Wakeup Event Enable	<i>Access: R_W</i> */
++	DWC_DEVTEN_WKUP_BIT		= 0x0010,
++	DWC_DEVTEN_WKUP_SHIFT		= 4,
++
++	/** Hibernation Request Event Enable	<i>Access: R_W</i> */
++	DWC_DEVTEN_HIBER_REQ_BIT	= 0x0020,
++	DWC_DEVTEN_HIBER_REQ_SHIFT	= 5,
++
++	/** End of Periodic Frame Event Enable	<i>Access: R_W</i> */
++	DWC_DEVTEN_U3_L2L1_SUSP_BIT	= 0x0040,
++	DWC_DEVTEN_U3_L2L1_SUSP_SHIFT	= 6,
++
++	/** Start of (Micro)Frame Enable	<i>Access: R_W</i> */
++	DWC_DEVTEN_SOF_BIT		= 0x0080,
++	DWC_DEVTEN_SOF_SHIFT		= 7,
++
++	/** Erratic Error Event Enable		<i>Access: R_W</i> */
++	DWC_DEVTEN_ERRATICERR_BIT	= 0x0200,
++	DWC_DEVTEN_ERRATICERR_SHIFT	= 9,
++
++	/** U2 Inactivity Timeout Enable	<i>Access: R_W</i> */
++	DWC_DEVTEN_INACT_TIMEOUT_BIT	= 0x2000,
++	DWC_DEVTEN_INACT_TIMEOUT_SHIFT	= 13,
++} devten_data_t;
++
++/**
++ * This enum represents the bit fields in the Device Status
++ * Register (DSTS).
++ */
++typedef enum dsts_data {
++	/** Connected Speed			<i>Access: RO</i>.
++	 * (see enum @ref dcfg_data for values) */
++	DWC_DSTS_CONNSPD_BITS		= 0x00000007,
++	DWC_DSTS_CONNSPD_SHIFT		= 0,
++
++	/** (Micro)Frame Number of Received SOF	<i>Access: RO</i> */
++	DWC_DSTS_SOF_FN_BITS		= 0x0001fff8,
++	DWC_DSTS_SOF_FN_SHIFT		= 3,
++
++	/** RX Fifo Empty			<i>Access: RO</i> */
++	DWC_DSTS_RXFIFO_EMPTY_BIT	= 0x00020000,
++	DWC_DSTS_RXFIFO_EMPTY_SHIFT	= 17,
++
++	/** USB/Link State			<i>Access: RO</i> */
++	DWC_DSTS_USBLNK_STATE_BITS	= 0x003c0000,
++	DWC_DSTS_USBLNK_STATE_SHIFT	= 18,
++
++	/** USB/Link State values same as for devt_data_t */
++
++	/** Device Controller Halted		<i>Access: RO</i> */
++	DWC_DSTS_DEV_CTRL_HLT_BIT	= 0x00400000,
++	DWC_DSTS_DEV_CTRL_HLT_SHIFT	= 22,
++
++	/** Core Idle				<i>Access: RO</i> */
++	DWC_DSTS_CORE_IDLE_BIT		= 0x00800000,
++	DWC_DSTS_CORE_IDLE_SHIFT	= 23,
++
++	/** Save State Status			<i>Access: RO</i> */
++	DWC_DSTS_SSS_BIT		= 0x01000000,
++	DWC_DSTS_SSS_SHIFT		= 24,
++
++	/** Restore State Status		<i>Access: RO</i> */
++	DWC_DSTS_RSS_BIT		= 0x02000000,
++	DWC_DSTS_RSS_SHIFT		= 25,
++
++	/** Save/Restore Error			<i>Access: RO</i> */
++	DWC_DSTS_SRE_BIT		= 0x10000000,
++	DWC_DSTS_SRE_SHIFT		= 28,
++
++	/** Link-state Not Ready		<i>Access: RO</i> */
++	DWC_DSTS_LNR_BIT		= 0x20000000,
++	DWC_DSTS_LNR_SHIFT		= 29,
++} dsts_data_t;
++
++/**
++ * This enum represents the bit fields in the Device Generic Command Parameter
++ * Register (DGCMDPARn) for the various commands.
++ */
++typedef enum dgcmdpar_data {
++	/** Periodic Parameters - for DWC_DGCMD_SET_PERIODIC_PARAMS command */
++	DWC_DGCMD_PER_PARAM_SEL_BITS		= 0x000003ff,
++	DWC_DGCMD_PER_PARAM_SEL_SHIFT		= 0,
++
++	/** Host Role Request - for DWC_DGCMD_XMIT_HOST_ROLE_REQUEST command */
++	DWC_DGCMDPAR_HOST_ROLE_REQ_BITS		= 0x00000003,
++	DWC_DGCMDPAR_HOST_ROLE_REQ_SHIFT	= 0,
++
++	/** RSP Phase values - for DWC_DGCMD_XMIT_HOST_ROLE_REQUEST (older
++	 * cores) or DWC_DGCMD_HOST_ROLE_REQ_DEV_NOTIF (newer cores) */
++	DWC_DGCMDPAR_HOST_ROLE_REQ_INITIATE		= 1,	/** @< */
++	DWC_DGCMDPAR_HOST_ROLE_REQ_CONFIRM		= 2,
++
++	/** Notification Type - for DWC_DGCMD_XMIT_DEV_NOTIF command */
++	DWC_DGCMDPAR_DEV_NOTIF_TYPE_BITS	= 0x0000000f,
++	DWC_DGCMDPAR_DEV_NOTIF_TYPE_SHIFT	= 0,
++
++	/** Notification Type values - for DWC_DGCMD_XMIT_DEV_NOTIF command */
++	DWC_DGCMD_FUNCTION_WAKE_DEV_NOTIF		= 1,	/** @< */
++	DWC_DGCMD_LATENCY_TOL_DEV_NOTIF			= 2,	/** @< */
++	DWC_DGCMD_BUS_INTVL_ADJ_DEV_NOTIF		= 3,	/** @< */
++	DWC_DGCMD_HOST_ROLE_REQ_DEV_NOTIF		= 4,
++
++	/** Notification Parameters - for DWC_DGCMD_XMIT_DEV_NOTIF command */
++	DWC_DGCMDPAR_DEV_NOTIF_PARAM_BITS	= 0xfffffff0,
++	DWC_DGCMDPAR_DEV_NOTIF_PARAM_SHIFT	= 4,
++
++	/** Best Effort Latency Tolerance Value - for
++	 * DWC_DGCMD_LATENCY_TOL_DEV_NOTIF command type */
++	DWC_DGCMDPAR_BELT_VALUE_BITS		= 0x000003ff,
++	DWC_DGCMDPAR_BELT_VALUE_SHIFT		= 0,
++
++	/** Best Effort Latency Tolerance Scale - for
++	 * DWC_DGCMD_LATENCY_TOL_DEV_NOTIF command type */
++	DWC_DGCMDPAR_BELT_SCALE_BITS		= 0x00000c00,
++	DWC_DGCMDPAR_BELT_SCALE_SHIFT		= 10,
++
++	/** Latency Scale values (ns) */
++	DWC_LATENCY_VALUE_MULT_1024			= 1,	/** @< */
++	DWC_LATENCY_VALUE_MULT_32768			= 2,	/** @< */
++	DWC_LATENCY_VALUE_MULT_1048576			= 3,
++} dgcmdpar_data_t;
++
++/**
++ * This enum represents the bit fields in the Device Generic Command
++ * Register (DGCMDn).
++ */
++typedef enum dgcmd_data {
++	/** Command Type			<i>Access: R_W</i> */
++	DWC_DGCMD_TYP_BITS			= 0x0ff,
++	DWC_DGCMD_TYP_SHIFT			= 0,
++
++	/** Command Type values */
++	DWC_DGCMD_SET_PERIODIC_PARAMS			= 2,	/** @< */
++	DWC_DGCMD_XMIT_FUNC_WAKE_DEV_NOTIF		= 3,	/** @< */
++	DWC_DGCMD_SET_SCRATCHPAD_ARRAY_ADR_LO		= 4,	/** @< */
++	DWC_DGCMD_SET_SCRATCHPAD_ARRAY_ADR_HI		= 5,	/** @< */
++	DWC_DGCMD_XMIT_HOST_ROLE_REQUEST		= 6,	/** @< */
++	DWC_DGCMD_XMIT_DEV_NOTIF			= 7,	/** @< */
++	DWC_DGCMD_SELECTED_FIFO_FLUSH			= 9,	/** @< */
++	DWC_DGCMD_ALL_FIFO_FLUSH			= 10,	/** @< */
++	DWC_DGCMD_SET_EP_NRDY				= 12,	/** @< */
++	DWC_DGCMD_RUN_SOC_BUS_LOOPBK_TST		= 16,
++
++	/** Command Interrupt on Complete	<i>Access: R_W</i> */
++	DWC_DGCMD_IOC_BIT			= 0x100,
++	DWC_DGCMD_IOC_SHIFT			= 8,
++
++	/** Command Active			<i>Access: R_W</i> */
++	DWC_DGCMD_ACT_BIT			= 0x400,
++	DWC_DGCMD_ACT_SHIFT			= 10,
++
++	/** Command Status			<i>Access: R_W</i> */
++	DWC_DGCMD_STS_BITS			= 0xf000,
++	DWC_DGCMD_STS_SHIFT			= 12,
++
++	/** Command Status values */
++	DWC_DGCMD_STS_ERROR				= 15,
++} dgcmd_data_t;
++
++/**
++ * This enum represents the bit fields in the Device Endpoint Mapping
++ * Registers (DEPMAPn).
++ */
++typedef enum depmap_data {
++	/** Resource Number			<i>Access: R_W / RO</i> */
++	DWC_EPMAP_RES_NUM_BITS		= 0x1f,
++	DWC_EPMAP_RES_NUM_SHIFT		= 0,
++} depmap_data_t;
++
++/**
++ * Device Global Registers	<i>Offsets 700h-7FCh</i>.
++ *
++ * The following structures define the size and relative field offsets
++ * for the Device Mode Global Registers.
++ */
++typedef struct dwc_usb3_dev_global_regs {
++
++#define DWC_DEV_GLOBAL_REG_OFFSET	0x700
++
++	/** Device Configuration Register		<i>Offset: 700h</i>.
++	 * Fields defined in enum @ref dcfg_data. */
++	volatile u32 dcfg;
++
++	/** Device Control Register			<i>Offset: 704h</i>.
++	 * Fields defined in enum @ref dctl_data. */
++	volatile u32 dctl;
++
++	/** Device All Endpoints Interrupt Mask Register <i>Offset: 708h</i>.
++	 * Fields defined in enum @ref devten_data. */
++	volatile u32 devten;
++
++	/** Device Status Register			<i>Offset: 70Ch</i>.
++	 * Fields defined in enum @ref dsts_data. */
++	volatile u32 dsts;
++
++	/** Device Generic Command Parameter Register	<i>Offset: 710h</i>.
++	 * Fields defined in enum @ref dgcmdpar_data. */
++	volatile u32 dgcmdpar;
++
++	/** Device Generic Command Register		<i>Offset: 714h</i>.
++	 * Fields defined in enum @ref dgcmd_data. */
++	volatile u32 dgcmd;
++
++	/** reserved				<i>Offset: 718h-71Ch</i> */
++	volatile u32 reserved[2];
++
++	/** Device Active Logical Endpoint Enable Register <i>Offset: 720h</i>.
++	 * One bit per logical endpoint, bit0=EP0 ... bit31=EP31. */
++	volatile u32 dalepena;
++} dwc_usb3_dev_global_regs_t;
++
++
++/****************************************************************************/
++/* Device Endpoint Specific Registers */
++
++/**
++ * This enum represents the bit fields in the Device Endpoint Command
++ * Parameter 1 Register (DEPCMDPAR1n) for the Set Endpoint Configuration
++ * (DEPCFG) command.
++ */
++typedef enum depcfgpar1_data {
++	/** Interrupt number */
++	DWC_EPCFG1_INTRNUM_BITS		= 0x0000003f,
++	DWC_EPCFG1_INTRNUM_SHIFT	= 0,
++
++	/** Stream Completed */
++	DWC_EPCFG1_XFER_CMPL_BIT	= 0x00000100,
++	DWC_EPCFG1_XFER_CMPL_SHIFT	= 8,
++
++	/** Stream In Progress */
++	DWC_EPCFG1_XFER_IN_PROG_BIT	= 0x00000200,
++	DWC_EPCFG1_XFER_IN_PROG_SHIFT	= 9,
++
++	/** Stream Not Ready */
++	DWC_EPCFG1_XFER_NRDY_BIT	= 0x00000400,
++	DWC_EPCFG1_XFER_NRDY_SHIFT	= 10,
++
++	/** Rx FIFO Underrun / Tx FIFO Overrun */
++	DWC_EPCFG1_FIFOXRUN_BIT		= 0x00000800,
++	DWC_EPCFG1_FIFOXRUN_SHIFT	= 11,
++
++	/** Back-to-Back Setup Packets Received	 */
++	DWC_EPCFG1_SETUP_PNDG_BIT	= 0x00001000,
++	DWC_EPCFG1_SETUP_PNDG_SHIFT	= 12,
++
++	/** Endpoint Command Complete */
++	DWC_EPCFG1_EPCMD_CMPL_BIT	= 0x00002000,
++	DWC_EPCFG1_EPCMD_CMPL_SHIFT	= 13,
++
++	/** Endpoint EBC Mode */
++	DWC_EPCFG1_EBC_MODE_BIT		= 0x00008000,
++	DWC_EPCFG1_EBC_MODE_SHIFT	= 15,
++
++	/** Endpoint bInterval */
++	DWC_EPCFG1_BINTERVAL_BITS	= 0x00ff0000,
++	DWC_EPCFG1_BINTERVAL_SHIFT	= 16,
++
++	/** Endpoint Stream Capability */
++	DWC_EPCFG1_STRM_CAP_BIT		= 0x01000000,
++	DWC_EPCFG1_STRM_CAP_SHIFT	= 24,
++
++	/** Endpoint Direction */
++	DWC_EPCFG1_EP_DIR_BIT		= 0x02000000,
++	DWC_EPCFG1_EP_DIR_SHIFT		= 25,
++
++	/** Endpoint Number */
++	DWC_EPCFG1_EP_NUM_BITS		= 0x3c000000,
++	DWC_EPCFG1_EP_NUM_SHIFT		= 26,
++} depcfgpar1_data_t;
++
++/**
++ * This enum represents the bit fields in the Device Endpoint Command
++ * Parameter 0 Register (DEPCMDPAR0n) for the Set Endpoint Configuration
++ * (DWC_EPCMD_SET_EP_CFG) command.
++ */
++typedef enum depcfgpar0_data {
++	/** Endpoint Type			<i>Access: R_W</i> */
++	DWC_EPCFG0_EPTYPE_BITS			= 0x00000006,
++	DWC_EPCFG0_EPTYPE_SHIFT			= 1,
++
++	/** Endpoint Type values */
++	DWC_USB3_EP_TYPE_CONTROL	= 0,	/** @< */
++	DWC_USB3_EP_TYPE_ISOC		= 1,	/** @< */
++	DWC_USB3_EP_TYPE_BULK		= 2,	/** @< */
++	DWC_USB3_EP_TYPE_INTR		= 3,
++
++	/** Maximum Packet Size			<i>Access: R_W</i> */
++	DWC_EPCFG0_MPS_BITS			= 0x00003ff8,
++	DWC_EPCFG0_MPS_SHIFT			= 3,
++
++	/** Flow Control State			<i>Access: R_W</i> */
++	DWC_EPCFG0_FLOW_CTRL_STATE_BIT		= 0x00010000,
++	DWC_EPCFG0_FLOW_CTRL_STATE_SHIFT	= 16,
++
++	/** Tx Fifo Number (IN endpoints only)	<i>Access: R_W</i> */
++	DWC_EPCFG0_TXFNUM_BITS			= 0x003e0000,
++	DWC_EPCFG0_TXFNUM_SHIFT			= 17,
++
++	/** Burst Size				<i>Access: R_W</i> */
++	DWC_EPCFG0_BRSTSIZ_BITS			= 0x03c00000,
++	DWC_EPCFG0_BRSTSIZ_SHIFT		= 22,
++
++	/** Data Sequence Num (old)		<i>Access: R_W</i> */
++	DWC_EPCFG0_DSNUM_BITS			= 0x7c000000,
++	DWC_EPCFG0_DSNUM_SHIFT			= 26,
++
++	/** Ignore Data Sequence Num (old)	<i>Access: R_W</i> */
++	DWC_EPCFG0_IGN_DSNUM_BIT		= 0x80000000,
++	DWC_EPCFG0_IGN_DSNUM_SHIFT		= 31,
++
++	/** Config Action (new)			<i>Access: R_W</i> */
++	DWC_EPCFG0_CFG_ACTION_BITS		= 0xc0000000,
++	DWC_EPCFG0_CFG_ACTION_SHIFT		= 30,
++
++	/** Config Action values (new) */
++	DWC_CFG_ACTION_INIT		= 0,	/** @< */
++	DWC_CFG_ACTION_RESTORE		= 1,	/** @< */
++	DWC_CFG_ACTION_MODIFY		= 2,
++} depcfgpar0_data_t;
++
++/**
++ * This enum represents the bit fields in the Device Endpoint Command
++ * Register (DEPCMDn).
++ */
++typedef enum depcmd_data {
++	/** Command Type			<i>Access: R_W</i> */
++	DWC_EPCMD_TYP_BITS		= 0x0ff,
++	DWC_EPCMD_TYP_SHIFT		= 0,
++
++	/** Command Type values */
++	DWC_EPCMD_SET_EP_CFG	= 1,	/** @< */
++	DWC_EPCMD_SET_XFER_CFG	= 2,	/** @< */
++	DWC_EPCMD_GET_EP_STATE	= 3,	/** @< */
++	DWC_EPCMD_SET_STALL	= 4,	/** @< */
++	DWC_EPCMD_CLR_STALL	= 5,	/** @< */
++	DWC_EPCMD_START_XFER	= 6,	/** @< */
++	DWC_EPCMD_UPDATE_XFER	= 7,	/** @< */
++	DWC_EPCMD_END_XFER	= 8,	/** @< */
++	DWC_EPCMD_START_NEW_CFG	= 9,
++
++	/** Command Interrupt on Complete	<i>Access: R_W</i> */
++	DWC_EPCMD_IOC_BIT		= 0x100,
++	DWC_EPCMD_IOC_SHIFT		= 8,
++
++	/** Command Active			<i>Access: R_W</i> */
++	DWC_EPCMD_ACT_BIT		= 0x400,
++	DWC_EPCMD_ACT_SHIFT		= 10,
++
++	/** High Priority / Force RM Bit	<i>Access: R_W</i> */
++	DWC_EPCMD_HP_FRM_BIT		= 0x800,
++	DWC_EPCMD_HP_FRM_SHIFT		= 11,
++
++	/** Command Completion Status		<i>Access: R_W</i> */
++	DWC_EPCMD_CMPL_STS_BITS		= 0xf000,
++	DWC_EPCMD_CMPL_STS_SHIFT	= 12,
++
++	/** Stream Number or uFrame (input)	<i>Access: R_W</i> */
++	DWC_EPCMD_STR_NUM_OR_UF_BITS	= 0xffff0000,
++	DWC_EPCMD_STR_NUM_OR_UF_SHIFT	= 16,
++
++	/** Transfer Resource Index (output)	<i>Access: R_W</i> */
++	DWC_EPCMD_XFER_RSRC_IDX_BITS	= 0x007f0000,
++	DWC_EPCMD_XFER_RSRC_IDX_SHIFT	= 16,
++} depcmd_data_t;
++
++/**
++ * Device Endpoint Specific Registers <i>Offsets 800h-9ECh for OUT,
++ *						 810h-9FCh for IN</i>.
++ * There will be one set of endpoint registers per logical endpoint
++ * implemented.
++ */
++typedef struct dwc_usb3_dev_ep_regs {
++
++#define DWC_DEV_OUT_EP_REG_OFFSET	0x800
++#define DWC_DEV_IN_EP_REG_OFFSET	0x810
++#define DWC_EP_REG_OFFSET		0x20
++
++	/** Device Endpoint Command Parameter 2 Register <i>Offset: 800h/810h +
++	 *					(ep_num * 20h) + 00h</i> */
++	volatile u32 depcmdpar2;
++
++	/** Device Endpoint Command Parameter 1 Register <i>Offset: 800h/810h +
++	 *					(ep_num * 20h) + 04h</i> */
++	volatile u32 depcmdpar1;
++
++	/** Device Endpoint Command Parameter 0 Register <i>Offset: 800h/810h +
++	 *					(ep_num * 20h) + 08h</i> */
++	volatile u32 depcmdpar0;
++
++	/** Device Endpoint Command Register	<i>Offset: 800h/810h +
++	 *					(ep_num * 20h) + 0Ch</i>.
++	 * Fields defined in enum @ref depcmd_data. */
++	volatile u32 depcmd;
++
++	/** reserved				<i>Offset: 800h/810h +
++	 *					(ep_num * 20h) + 10h-1Ch</i> */
++	volatile u32 reserved[4];
++} dwc_usb3_dev_ep_regs_t;
++
++
++/****************************************************************************/
++/* DMA Descriptor Specific Structures */
++
++/**
++ * This enum represents the bit fields in the DMA Descriptor
++ * Status quadlet.
++ */
++typedef enum desc_sts_data {
++	/** Transfer Count */
++	DWC_DSCSTS_XFRCNT_BITS	= 0x00ffffff,
++	DWC_DSCSTS_XFRCNT_SHIFT	= 0,
++
++	/** Packet Count Minus 1 (for HS IN transfers) */
++	DWC_DSCSTS_PCM1_BITS	= 0x03000000,
++	DWC_DSCSTS_PCM1_SHIFT	= 24,
++
++	/** Transfer Request Block Response */
++	DWC_DSCSTS_TRBRSP_BITS	= 0xf0000000,
++	DWC_DSCSTS_TRBRSP_SHIFT	= 28,
++
++	/** Response values */
++	DWC_TRBRSP_MISSED_ISOC_IN	= 1,	/** @< */
++	DWC_TRBRSP_SETUP_PEND		= 2,	/** @< */
++	DWC_TRBRSP_XFER_IN_PROG		= 4,
++} desc_sts_data_t;
++
++/**
++ * This enum represents the bit fields in the DMA Descriptor
++ * Control quadlet.
++ */
++typedef enum desc_ctl_data {
++	/** Hardware-Owned bit */
++	DWC_DSCCTL_HWO_BIT		= 0x00000001,
++	DWC_DSCCTL_HWO_SHIFT		= 0,
++
++	/** Last Descriptor bit */
++	DWC_DSCCTL_LST_BIT		= 0x00000002,
++	DWC_DSCCTL_LST_SHIFT		= 1,
++
++	/** Chain Buffer bit */
++	DWC_DSCCTL_CHN_BIT		= 0x00000004,
++	DWC_DSCCTL_CHN_SHIFT		= 2,
++
++	/** Continue on Short Packet bit */
++	DWC_DSCCTL_CSP_BIT		= 0x00000008,
++	DWC_DSCCTL_CSP_SHIFT		= 3,
++
++	/** Transfer Request Block Control field */
++	DWC_DSCCTL_TRBCTL_BITS		= 0x000003f0,
++	DWC_DSCCTL_TRBCTL_SHIFT		= 4,
++
++	/** Transfer Request Block Control types */
++	DWC_DSCCTL_TRBCTL_NORMAL		= 1,	/** @< */
++	DWC_DSCCTL_TRBCTL_SETUP			= 2,	/** @< */
++	DWC_DSCCTL_TRBCTL_STATUS_2		= 3,	/** @< */
++	DWC_DSCCTL_TRBCTL_STATUS_3		= 4,	/** @< */
++	DWC_DSCCTL_TRBCTL_CTLDATA_1ST		= 5,	/** @< */
++	DWC_DSCCTL_TRBCTL_ISOC_1ST		= 6,	/** @< */
++	DWC_DSCCTL_TRBCTL_ISOC			= 7,	/** @< */
++	DWC_DSCCTL_TRBCTL_LINK			= 8,
++
++	/** Interrupt on Short Packet bit */
++	DWC_DSCCTL_ISP_BIT		= 0x00000400,
++	DWC_DSCCTL_ISP_SHIFT		= 10,
++#define DWC_DSCCTL_IMI_BIT	DWC_DSCCTL_ISP_BIT
++#define DWC_DSCCTL_IMI_SHIFT	DWC_DSCCTL_ISP_SHIFT
++
++	/** Interrupt on Completion bit */
++	DWC_DSCCTL_IOC_BIT		= 0x00000800,
++	DWC_DSCCTL_IOC_SHIFT		= 11,
++
++	/** Stream ID / SOF Number */
++	DWC_DSCCTL_STRMID_SOFN_BITS	= 0x3fffc000,
++	DWC_DSCCTL_STRMID_SOFN_SHIFT	= 14,
++} desc_ctl_data_t;
++
++/**
++ * DMA Descriptor structure
++ *
++ * DMA Descriptor structure contains 4 quadlets:
++ * Buffer Pointer Low address, Buffer Pointer High address, Status, and Control.
++ */
++typedef struct dwc_usb3_dma_desc {
++	/** Buffer Pointer - Low address quadlet */
++	u32	bptl;
++
++	/** Buffer Pointer - High address quadlet */
++	u32	bpth;
++
++	/** Status quadlet. Fields defined in enum @ref desc_sts_data. */
++	u32	status;
++
++	/** Control quadlet. Fields defined in enum @ref desc_ctl_data. */
++	u32	control;
++} dwc_usb3_dma_desc_t;
++
++#ifdef SSIC
++
++/* SSIC Registers */
++typedef struct dwc_usb3_ssic_regs {
++
++#define DWC_SSIC_REG_OFFSET	0xc40
++
++	volatile u32 sctl[16];
++	volatile u32 sevt[16];
++	volatile u32 sevten[16];
++	volatile u32 gscfg;
++	volatile u32 gsser;
++	volatile u32 gsdbg;
++} dwc_usb3_ssic_regs_t;
++
++typedef enum sevten_data {
++	DWC_SEVTEN_ROM_INIT_CMPLT_EN_BIT	= 0x00000001,
++	DWC_SEVTEN_ROM_INIT_CMPLT_EN_SHIFT	= 0,
++
++	DWC_SEVTEN_LACC_CMPLT_EN_BIT		= 0x00000002,
++	DWC_SEVTEN_LACC_CMPLT_EN_SHIFT		= 1,
++
++	DWC_SEVTEN_RCMD_RES_RCVD_EN_BIT		= 0x00000004,
++	DWC_SEVTEN_RCMD_RES_RCVD_EN_SHIFT	= 2,
++
++	DWC_SEVTEN_RCMD_RES_SENT_EN_BIT		= 0x00000008,
++	DWC_SEVTEN_RCMD_RES_SENT_EN_SHIFT	= 3,
++
++	DWC_SEVTEN_MPHY_ST_CHNGD_EN_BIT		= 0x00000010,
++	DWC_SEVTEN_MPHY_ST_CHNGD_EN_SHIFT	= 4,
++
++	DWC_SEVTEN_OK_STRT_RRAP_EN_BIT		= 0x00000020,
++	DWC_SEVTEN_OK_STRT_RRAP_EN_SHIFT	= 5,
++
++	DWC_SEVTEN_RRAP_ERROR_EN_BIT		= 0x00000040,
++	DWC_SEVTEN_RRAP_ERROR_EN_SHIFT		= 6,
++} sevten_data_t;
++
++typedef enum sevt_data {
++	DWC_SEVT_ROM_INIT_CMPLT_BIT	= 0x00000001,
++	DWC_SEVT_ROM_INIT_CMPLT_SHIFT	= 0,
++
++	DWC_SEVT_LACC_CMPLT_BIT		= 0x00000002,
++	DWC_SEVT_LACC_CMPLT_SHIFT	= 1,
++
++	DWC_SEVT_RCMD_RES_RCVD_BIT	= 0x00000004,
++	DWC_SEVT_RCMD_RES_RCVD_SHIFT	= 2,
++
++	DWC_SEVT_RCMD_RES_SENT_BIT	= 0x00000008,
++	DWC_SEVT_RCMD_RES_SENT_SHIFT	= 3,
++
++	DWC_SEVT_MPHY_ST_CHNG_BIT	= 0x00000010,
++	DWC_SEVT_MPHY_ST_CHNG_SHIFT	= 4,
++
++	DWC_SEVT_OK_STRT_RRAP_BIT	= 0x00000020,
++	DWC_SEVT_OK_STRT_RRAP_SHIFT	= 5,
++
++	DWC_SEVT_RRAP_ERROR_BIT		= 0x00000040,
++	DWC_SEVT_RRAP_ERROR_SHIFT	= 6,
++
++	DWC_SEVT_RACC_RESULT_BITS	= 0x00000300,
++	DWC_SEVT_RACC_RESULT_SHIFT	= 8,
++
++	DWC_SEVT_LACC_RESULT_BIT	= 0x00000400,
++	DWC_SEVT_LACC_RESULT_SHIFT	= 10,
++
++	DWC_SEVT_READ_RCVD_BIT		= 0x00000800,
++	DWC_SEVT_READ_RCVD_SHIFT	= 11,
++
++	DWC_SEVT_RUADDR_RCVD_BITS	= 0x0000f000,
++	DWC_SEVT_RUADDR_RCVD_SHIFT	= 12,
++
++	DWC_SEVT_RLADDR_RCVD_BITS	= 0x00ff0000,
++	DWC_SEVT_RLADDR_RCVD_SHIFT	= 16,
++
++	DWC_SEVT_RDATA_RCVD_BITS	= 0xff000000,
++	DWC_SEVT_RDATA_RCVD_SHIFT	= 24,
++} sevt_data_t;
++
++typedef enum sctl_data {
++	DWC_SCTL_GO_ACC_BIT		= 0x00000001,
++	DWC_SCTL_GO_ACC_SHIFT		= 0,
++
++	DWC_SCTL_RACC_BIT		= 0x00000002,
++	DWC_SCTL_RACC_SHIFT		= 1,
++
++	DWC_SCTL_RD_WR_N_BIT		= 0x00000004,
++	DWC_SCTL_RD_WR_N_SHIFT		= 2,
++
++	DWC_SCTL_BCW_BIT		= 0x00000008,
++	DWC_SCTL_BCW_SHIFT		= 3,
++
++	DWC_SCTL_IN_LN_CFG_BIT		= 0x00000010,
++	DWC_SCTL_IN_LN_CFG_SHIFT	= 4,
++
++	DWC_SCTL_CFG_DONE_BIT		= 0x00000020,
++	DWC_SCTL_CFG_DEON_SHIFT		= 5,
++
++	DWC_SCTL_CBS_ACC_BIT		= 0x00000040,
++	DWC_SCTL_CBS_ACC_SHIFT		= 6,
++
++	DWC_SCTL_RXS_ACC_BIT		= 0x00000080,
++	DWC_SCTL_RXS_ACC_SHIFT		= 7,
++
++	DWC_SCTL_EAID_BITS		= 0x0000f000,
++	DWC_SCTL_EAID_SHIFT		= 12,
++
++	DWC_SCTL_AID_BITS		= 0x00ff0000,
++	DWC_SCTL_AID_SHIFT		= 16,
++
++	DWC_SCTL_ADATA_BITS		= 0xff000000,
++	DWC_SCTL_ADATA_SHIFT		= 24,
++} sctl_data_t;
++
++#endif /* SSIC */
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* _DWC_USB3_REGS_H_ */
+diff --git a/drivers/usb/gadget/udc/hiudc3/linux_defs.h b/drivers/usb/gadget/udc/hiudc3/linux_defs.h
+new file mode 100644
+index 0000000..b013072
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc3/linux_defs.h
+@@ -0,0 +1,162 @@
++#ifndef _DWC_LINUX_DEFS_H_
++#define _DWC_LINUX_DEFS_H_
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/**
++ * @file
++ *
++ * This file contains OS-specific includes and definitions.
++ *
++ */
++
++#define DWC_DRIVER_VERSION	"2.90b - November 2014"
++#define DWC_DRIVER_DESC		"SS USB3 Controller driver"
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/init.h>
++#include <linux/device.h>
++#include <linux/platform_device.h>
++#include <linux/sysfs.h>
++#include <linux/errno.h>
++#include <linux/types.h>
++#include <linux/slab.h>
++#include <linux/list.h>
++#include <linux/interrupt.h>
++#include <linux/ctype.h>
++#include <linux/string.h>
++#include <linux/dma-mapping.h>
++#include <linux/jiffies.h>
++#include <linux/delay.h>
++#include <linux/timer.h>
++#include <linux/kthread.h>
++#include <linux/workqueue.h>
++#include <linux/freezer.h>
++#include <linux/stat.h>
++#include <linux/pci.h>
++
++#include <linux/version.h>
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
++# include <linux/irq.h>
++#endif
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
++# include <linux/usb/ch9.h>
++#else
++# include <linux/usb_ch9.h>
++#endif
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++# include <linux/usb/gadget.h>
++# include <linux/usb/otg.h>
++#else
++# include <linux/usb_gadget.h>
++# include <linux/usb_otg.h>
++#endif
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
++# include <asm/irq.h>
++#endif
++
++# include <asm/unaligned.h>
++# include <asm/param.h>
++# include <asm/io.h>
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
++typedef int		gfp_t;
++#endif
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
++# define IRQF_SHARED	SA_SHIRQ
++#endif
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,1,0)
++# define DWC_BOS_IN_GADGET
++#endif
++
++/** @name Error Codes */
++/** @{ */
++#define DWC_E_INVALID		EINVAL
++#define DWC_E_NO_MEMORY		ENOMEM
++#define DWC_E_NO_DEVICE		ENODEV
++#define DWC_E_NOT_SUPPORTED	EOPNOTSUPP
++#define DWC_E_TIMEOUT		ETIMEDOUT
++#define DWC_E_BUSY		EBUSY
++#define DWC_E_AGAIN		EAGAIN
++#define DWC_E_ABORT		ECONNABORTED
++#define DWC_E_SHUTDOWN		ESHUTDOWN
++#define DWC_E_NO_DATA		ENODATA
++#define DWC_E_DISCONNECT	ECONNRESET
++#define DWC_E_UNKNOWN		EINVAL
++#define DWC_E_NO_STREAM_RES	ENOSR
++#define DWC_E_COMMUNICATION	ECOMM
++#define DWC_E_OVERFLOW		EOVERFLOW
++#define DWC_E_PROTOCOL		EPROTO
++#define DWC_E_IN_PROGRESS	EINPROGRESS
++#define DWC_E_PIPE		EPIPE
++#define DWC_E_IO		EIO
++#define DWC_E_NO_SPACE		ENOSPC
++#define DWC_E_DOMAIN		EDOM
++/** @} */
++
++/** Compiler 'packed' attribute for structs */
++#define UPACKED	__attribute__ ((__packed__))
++
++/** @{ */
++/** Type for DMA addresses */
++typedef dma_addr_t		dwc_dma_t;
++#define DWC_DMA_ADDR_INVALID	(~(dwc_dma_t)0)
++/** @} */
++
++/**
++ * The number of DMA Descriptors (TRBs) to allocate for each endpoint type.
++ * NOTE: The driver currently supports more than 1 TRB for Isoc EPs only.
++ * So the values for Bulk and Intr must be 1.
++ */
++#define DWC_NUM_BULK_TRBS	1
++#define DWC_NUM_INTR_TRBS	1
++#define DWC_NUM_ISOC_TRBS	256
++
++/**
++ * These parameters may be specified when loading the module. They define how
++ * the DWC_usb3 controller should be configured. The parameter values are passed
++ * to the CIL initialization routine dwc_usb3_pcd_common_init().
++ */
++typedef struct dwc_usb3_core_params {
++	int burst;
++	int newcore;
++	int phy;
++	int wakeup;
++	int pwrctl;
++	int lpmctl;
++	int phyctl;
++	int usb2mode;
++	int hibernate;
++	int hiberdisc;
++	int clkgatingen;
++	int ssdisquirk;
++	int nobos;
++	int loop;
++	int nump;
++	int newcsr;
++	int rxfsz;
++	int txfsz[16];
++	int txfsz_cnt;
++	int baseline_besl;
++	int deep_besl;
++	int besl;
++	int ebc;
++} dwc_usb3_core_params_t;
++
++extern dwc_usb3_core_params_t dwc_usb3_module_params;
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* _DWC_LINUX_DEFS_H_ */
+diff --git a/drivers/usb/gadget/udc/hiudc3/linux_dev.h b/drivers/usb/gadget/udc/hiudc3/linux_dev.h
+new file mode 100644
+index 0000000..fb30136
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc3/linux_dev.h
+@@ -0,0 +1,165 @@
++#ifndef _DWC_LINUX_DEV_H_
++#define _DWC_LINUX_DEV_H_
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/** @file
++ */
++
++/** Wrapper function for _handshake(), shows the source line for any failure */
++#define handshake(_dev_, _ptr_, _mask_, _done_) ({			\
++	int _retval_ = _handshake(_dev_, _ptr_, _mask_, _done_);	\
++	if (!_retval_)							\
++		dwc_error2(_dev_, "handshake failed in %s():%d\n",	\
++			   __func__, __LINE__);				\
++	_retval_;							\
++})
++
++/** Takes a usb req pointer and returns the associated pcd req pointer */
++#define dwc_usb3_get_pcd_req(usbreq) \
++	container_of((usbreq), dwc_usb3_pcd_req_t, usb_req)
++
++/** Takes a usb ep pointer and returns the associated pcd ep pointer */
++#define dwc_usb3_get_pcd_ep(usbep) \
++	container_of((usbep), dwc_usb3_pcd_ep_t, usb_ep)
++
++/** @{ */
++/**
++ * Register read/write.
++ */
++static inline u32 dwc_rd32(struct dwc_usb3_device *dev,
++			   volatile u32 __iomem *adr)
++{
++	return readl(adr);
++}
++
++static inline void dwc_wr32(struct dwc_usb3_device *dev,
++			    volatile u32 __iomem *adr, u32 val)
++{
++	writel(val, adr);
++}
++/** @} */
++
++/** @{ */
++/**
++ * Non-sleeping delays.
++ */
++#define dwc_udelay(dev, us)	udelay(us)
++#define dwc_mdelay(dev, ms)	mdelay(ms)
++/** @} */
++
++/**
++ * Sleeping delay.
++ */
++#define dwc_msleep(dev, ms)	msleep(ms)
++
++/**
++ * Debugging support - vanishes in non-debug builds.
++ */
++
++/** Prefix string for print macros. */
++#define USB3_DWC	"dwc_usb3: "
++#ifdef DEBUG
++//# define dwc_debug(dev, x...)	printk(KERN_DEBUG USB3_DWC x )
++# define dwc_debug(dev, x...)	printk(KERN_ERR USB3_DWC x )
++#else
++# define dwc_debug(dev, x...)	printk(KERN_ERR USB3_DWC x )
++//# define dwc_debug(dev, x...)	do {} while (0)
++#endif /* DEBUG */
++
++# define dwc_debug0(dev, fmt)			dwc_debug(dev, fmt)
++# define dwc_debug1(dev, fmt, a)		dwc_debug(dev, fmt, a)
++# define dwc_debug2(dev, fmt, a, b)		dwc_debug(dev, fmt, a, b)
++# define dwc_debug3(dev, fmt, a, b, c)		dwc_debug(dev, fmt, a, b, c)
++# define dwc_debug4(dev, fmt, a, b, c, d)	dwc_debug(dev, fmt, a, b, c, d)
++# define dwc_debug5(dev, fmt, a, b, c, d, e) \
++			dwc_debug(dev, fmt, a, b, c, d, e)
++# define dwc_debug6(dev, fmt, a, b, c, d, e, f) \
++			dwc_debug(dev, fmt, a, b, c, d, e, f)
++# define dwc_debug7(dev, fmt, a, b, c, d, e, f, g) \
++			dwc_debug(dev, fmt, a, b, c, d, e, f, g)
++# define dwc_debug8(dev, fmt, a, b, c, d, e, f, g, h) \
++			dwc_debug(dev, fmt, a, b, c, d, e, f, g, h)
++# define dwc_debug9(dev, fmt, a, b, c, d, e, f, g, h, i) \
++			dwc_debug(dev, fmt, a, b, c, d, e, f, g, h, i)
++# define dwc_debug10(dev, fmt, a, b, c, d, e, f, g, h, i, j) \
++			dwc_debug(dev, fmt, a, b, c, d, e, f, g, h, i, j)
++
++#if defined(DEBUG) || defined(ISOC_DEBUG)
++# define dwc_isocdbg(dev, x...)	printk(USB3_DWC x )
++#else
++# define dwc_isocdbg(dev, x...)	do {} while (0)
++#endif
++
++# define dwc_isocdbg0(dev, fmt)			dwc_isocdbg(dev, fmt)
++# define dwc_isocdbg1(dev, fmt, a)		dwc_isocdbg(dev, fmt, a)
++# define dwc_isocdbg2(dev, fmt, a, b)		dwc_isocdbg(dev, fmt, a, b)
++# define dwc_isocdbg3(dev, fmt, a, b, c)	dwc_isocdbg(dev, fmt, a, b, c)
++# define dwc_isocdbg4(dev, fmt, a, b, c, d) \
++			dwc_isocdbg(dev, fmt, a, b, c, d)
++# define dwc_isocdbg5(dev, fmt, a, b, c, d, e) \
++			dwc_isocdbg(dev, fmt, a, b, c, d, e)
++# define dwc_isocdbg6(dev, fmt, a, b, c, d, e, f) \
++			dwc_isocdbg(dev, fmt, a, b, c, d, e, f)
++
++/**
++ * Print an Error message.
++ */
++#define dwc_error(dev, x...)	printk(KERN_ERR USB3_DWC x )
++
++#define dwc_error0(dev, fmt)			dwc_error(dev, fmt)
++#define dwc_error1(dev, fmt, a)			dwc_error(dev, fmt, a)
++#define dwc_error2(dev, fmt, a, b)		dwc_error(dev, fmt, a, b)
++#define dwc_error3(dev, fmt, a, b, c)		dwc_error(dev, fmt, a, b, c)
++#define dwc_error4(dev, fmt, a, b, c, d)	dwc_error(dev, fmt, a, b, c, d)
++
++/**
++ * Print a Warning message.
++ */
++#define dwc_warn(dev, x...)	printk(KERN_WARNING USB3_DWC x )
++
++#define dwc_warn0(dev, fmt)			dwc_warn(dev, fmt)
++#define dwc_warn1(dev, fmt, a)			dwc_warn(dev, fmt, a)
++#define dwc_warn2(dev, fmt, a, b)		dwc_warn(dev, fmt, a, b)
++#define dwc_warn3(dev, fmt, a, b, c)		dwc_warn(dev, fmt, a, b, c)
++#define dwc_warn4(dev, fmt, a, b, c, d)		dwc_warn(dev, fmt, a, b, c, d)
++
++/**
++ * Print an Informational message (normal but significant).
++ */
++#define dwc_info(dev, x...)	printk(KERN_INFO USB3_DWC x )
++
++#define dwc_info0(dev, fmt)			dwc_info(dev, fmt)
++#define dwc_info1(dev, fmt, a)			dwc_info(dev, fmt, a)
++#define dwc_info2(dev, fmt, a, b)		dwc_info(dev, fmt, a, b)
++#define dwc_info3(dev, fmt, a, b, c)		dwc_info(dev, fmt, a, b, c)
++#define dwc_info4(dev, fmt, a, b, c, d)		dwc_info(dev, fmt, a, b, c, d)
++
++/**
++ * Basic message printing.
++ */
++#define dwc_print(dev, x...)	0
++//#define dwc_print(dev, x...)	printk(USB3_DWC x )
++
++#define dwc_print0(dev, fmt)			dwc_print(dev, fmt)
++#define dwc_print1(dev, fmt, a)			dwc_print(dev, fmt, a)
++#define dwc_print2(dev, fmt, a, b)		dwc_print(dev, fmt, a, b)
++#define dwc_print3(dev, fmt, a, b, c)		dwc_print(dev, fmt, a, b, c)
++#define dwc_print4(dev, fmt, a, b, c, d)	dwc_print(dev, fmt, a, b, c, d)
++#define dwc_print5(dev, fmt, a, b, c, d, e) \
++			dwc_print(dev, fmt, a, b, c, d, e)
++
++extern int dwc_usb3_gadget_init(struct dwc_usb3_device *usb3_dev, struct device *dev);
++extern void dwc_usb3_gadget_remove(struct dwc_usb3_device *usb3_dev, struct device *dev);
++extern int dwc_usb3_create_dev_files(struct device *dev);
++extern void dwc_usb3_remove_dev_files(struct device *dev);
++extern int dwc_usb3_wakeup(struct usb_gadget *gadget);
++extern int dwc_wait_pme_thread(void *data);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* _DWC_LINUX_DEV_H_ */
+diff --git a/drivers/usb/gadget/udc/hiudc3/linux_gadget.c b/drivers/usb/gadget/udc/hiudc3/linux_gadget.c
+new file mode 100644
+index 0000000..d6e2656
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc3/linux_gadget.c
+@@ -0,0 +1,2693 @@
++/** @file
++ */
++
++#include "os_defs.h"
++#include "hw.h"
++#include "usb.h"
++#include "pcd.h"
++#include "dev.h"
++#include "os_dev.h"
++#include "cil.h"
++
++#ifdef DWC_UTE
++# include "ute_if.h"
++#endif
++
++#ifdef CONFIG_USB_OTG_DWC
++extern void dwc_otg3_set_peripheral(struct usb_otg *otg, int yes);
++extern int otg_host_release(struct usb_otg *otg);
++extern int otg_start_rsp(struct usb_otg *otg);
++#endif
++
++#define dwc_wait_if_hibernating(_pcd_, _flags_)				\
++{									\
++	int _temp_ = (_pcd_)->usb3_dev->hibernate;			\
++	while (_temp_ >= DWC_HIBER_SLEEPING &&				\
++	       _temp_ != DWC_HIBER_WAIT_U0 &&				\
++	       _temp_ != DWC_HIBER_SS_DIS_QUIRK) {			\
++		spin_unlock_irqrestore(&(_pcd_)->lock, (_flags_));	\
++		msleep(1);						\
++		spin_lock_irqsave(&(_pcd_)->lock, (_flags_));		\
++		_temp_ = (_pcd_)->usb3_dev->hibernate;			\
++	}								\
++}
++
++/**
++ * NOTE: These strings MUST reflect the number and type of endpoints that the
++ * core was configured with in CoreConsultant, and their intended usage. In
++ * particular, the type (bulk/int/iso) determines how many TRBs will be
++ * allocated for each endpoint. See gadget_init_eps() and trb_alloc() below.
++ *
++ * Naming convention is described in drivers/usb/gadget/epautoconf.c
++ */
++#if 0
++static const char *g_ep_names[] = { "ep0", "ep1out", "ep1in", "ep2out",
++	"ep2in", "ep3out", "ep3in", "ep4out", "ep4in", "ep5out", "ep5in",
++	"ep6out", "ep6in", "ep7out", "ep7in", "ep8out", "ep8in", "ep9out",
++	"ep9in", "ep10out", "ep10in", "ep11out", "ep11in", "ep12out", "ep12in",
++	"ep13out", "ep13in", "ep14out", "ep14in", "ep15out", "ep15in" };
++#endif
++#if 0
++static const char *g_ep_names[] = { "ep0", "ep1out", "ep1in", "ep2out",
++	"ep3in", "ep2in", "ep4in", "ep4out", "ep5out", "ep5in",
++	"ep6out", "ep6in", "ep7out", "ep7in", "ep8out", "ep8in", "ep9out",
++	"ep9in", "ep10out", "ep10in", "ep11out", "ep11in", "ep12out", "ep12in",
++	"ep13out", "ep13in", "ep14out", "ep14in", "ep15out", "ep15in" };
++#endif
++static const char *g_ep_names[] = { "ep0", "ep1out", "ep1in", "ep2out",
++	"ep2in", "ep3in", "ep4in", "ep4out", "ep4in", "ep5out", "ep5in",
++	"ep6out", "ep6in", "ep7out", "ep7in", "ep8out", "ep8in", "ep9out",
++	"ep9in", "ep10out", "ep10in", "ep11out", "ep11in", "ep12out", "ep12in",
++	"ep13out", "ep13in", "ep14out", "ep14in", "ep15out", "ep15in" };
++/*========================================================================*/
++/*
++ * Linux Gadget API related functions
++ */
++
++/* Gadget wrapper */
++
++static struct gadget_wrapper {
++	dwc_usb3_pcd_t *pcd;
++
++	char ep_names[DWC_MAX_EPS * 2 - 1][16];
++
++	struct usb_gadget gadget;
++	struct usb_gadget_driver *driver;
++
++	dwc_usb3_pcd_req_t ep0_req;
++
++	dwc_usb3_pcd_ep_t ep0;
++	dwc_usb3_pcd_ep_t out_ep[DWC_MAX_EPS - 1];
++	dwc_usb3_pcd_ep_t in_ep[DWC_MAX_EPS - 1];
++} *gadget_wrapper;
++
++
++/**
++ * Passes a Setup request to the Gadget driver
++ */
++static int gadget_setup(dwc_usb3_pcd_t *pcd, void *data)
++{
++	int retval = -DWC_E_NOT_SUPPORTED;
++
++	dwc_debug(pcd->usb3_dev, "%s()\n", __func__);
++
++	if (!gadget_wrapper) {
++		dwc_warn(pcd->usb3_dev, "%s null wrapper!\n", __func__);
++		return -DWC_E_INVALID;
++	}
++
++	if (gadget_wrapper->driver && gadget_wrapper->driver->setup) {
++		spin_unlock(&pcd->lock);
++		retval = gadget_wrapper->driver->setup(&gadget_wrapper->gadget,
++					(struct usb_ctrlrequest *)data);
++		spin_lock(&pcd->lock);
++		if (retval == -ENOTSUPP)
++			retval = -DWC_E_NOT_SUPPORTED;
++		else if (retval < 0)
++			retval = -DWC_E_INVALID;
++	}
++
++	return retval;
++}
++
++/*****************************************************************************
++ * Gadget notification functions
++ *
++ * These functions receive notifications from the PCD when certain events
++ * occur which the Gadget must be aware of.
++ *
++ * These functions *must* have the exact names and parameters shown here,
++ * since they are part of the API between the PCD and the Gadget.
++ *
++ *****************************************************************************/
++
++/**
++ * This function receives Connect notifications from the PCD
++ */
++int dwc_usb3_gadget_connect(dwc_usb3_pcd_t *pcd, int speed)
++{
++	dwc_debug(pcd->usb3_dev, "%s()\n", __func__);
++
++	if (!gadget_wrapper) {
++		dwc_warn(pcd->usb3_dev, "%s null wrapper!\n", __func__);
++		return -DWC_E_INVALID;
++	}
++
++	gadget_wrapper->gadget.speed = speed;
++	pcd->ep0->usb_ep.maxpacket = pcd->ep0->dwc_ep.maxpacket;
++
++	return 0;
++}
++
++/**
++ * This function receives Disconnect notifications from the PCD
++ */
++int dwc_usb3_gadget_disconnect(dwc_usb3_pcd_t *pcd)
++{
++	dwc_debug(pcd->usb3_dev, "%s()\n", __func__);
++
++	if (!gadget_wrapper) {
++		dwc_warn(pcd->usb3_dev, "%s null wrapper!\n", __func__);
++		return -DWC_E_INVALID;
++	}
++
++	if (gadget_wrapper->driver && gadget_wrapper->driver->disconnect) {
++		spin_unlock(&pcd->lock);
++		gadget_wrapper->driver->disconnect(&gadget_wrapper->gadget);
++		spin_lock(&pcd->lock);
++	}
++
++	return 0;
++}
++
++/**
++ * This function receives Setup request notifications from the PCD
++ */
++int dwc_usb3_gadget_setup(dwc_usb3_pcd_t *pcd, usb_device_request_t *ctrl)
++{
++	int ret;
++
++	dwc_debug(pcd->usb3_dev, "%s()\n", __func__);
++
++	ret = gadget_setup(pcd, ctrl);
++
++	/* @todo This is a g_file_storage gadget driver specific
++	 * workaround: a DELAYED_STATUS result from the fsg_setup
++	 * routine will result in the gadget queueing a EP0 IN status
++	 * phase for a two-stage control transfer. Exactly the same as
++	 * a SET_CONFIGURATION/SET_INTERFACE except that this is a class
++	 * specific request. Need a generic way to know when the gadget
++	 * driver will queue the status phase. Can we assume when we
++	 * call the gadget driver setup() function that it will always
++	 * queue and require the following flag? Need to look into
++	 * this.
++	 */
++	if (ret >= 256 + 999)
++		pcd->request_config = 1;
++
++	return ret;
++}
++
++/**
++ * This function receives Suspend notifications from the PCD
++ */
++int dwc_usb3_gadget_suspend(dwc_usb3_pcd_t *pcd)
++{
++	dwc_debug(pcd->usb3_dev, "%s()\n", __func__);
++
++	if (!gadget_wrapper) {
++		dwc_warn(pcd->usb3_dev, "%s null wrapper!\n", __func__);
++		return -DWC_E_INVALID;
++	}
++
++	if (gadget_wrapper->driver && gadget_wrapper->driver->suspend) {
++		spin_unlock(&pcd->lock);
++		gadget_wrapper->driver->suspend(&gadget_wrapper->gadget);
++		spin_lock(&pcd->lock);
++	}
++
++	return 0;
++}
++
++/**
++ * This function receives Resume notifications from the PCD
++ */
++int dwc_usb3_gadget_resume(dwc_usb3_pcd_t *pcd)
++{
++	dwc_debug(pcd->usb3_dev, "%s()\n", __func__);
++
++	if (!gadget_wrapper) {
++		dwc_warn(pcd->usb3_dev, "%s null wrapper!\n", __func__);
++		return -DWC_E_INVALID;
++	}
++
++	if (gadget_wrapper->driver && gadget_wrapper->driver->resume) {
++		spin_unlock(&pcd->lock);
++		gadget_wrapper->driver->resume(&gadget_wrapper->gadget);
++		spin_lock(&pcd->lock);
++	}
++
++	return 0;
++}
++
++static void map_buffers(struct device *dev, struct usb_request *usb_req,
++			dwc_usb3_pcd_ep_t *pcd_ep, int *req_flags)
++{
++	if (dwc_usb3_pcd_ep_is_in(pcd_ep)) {
++# ifdef DWC_TEST_ISOC_CHAIN
++		if (dwc_usb3_pcd_ep_type(pcd_ep) == UE_ISOCHRONOUS) {
++			if (usb_req->length > 58 && usb_req->buf2[0]) {
++				usb_req->dma2[0] = dma_map_single(dev,
++					usb_req->buf2[0], 29, DMA_TO_DEVICE);
++			}
++			if (usb_req->length > 58) {
++				usb_req->dma = dma_map_single(dev, usb_req->buf,
++					usb_req->length - 58, DMA_TO_DEVICE);
++			} else {
++				usb_req->dma = dma_map_single(dev, usb_req->buf,
++					usb_req->length, DMA_TO_DEVICE);
++			}
++			if (usb_req->length > 58 && usb_req->buf2[1]) {
++				usb_req->dma2[1] = dma_map_single(dev,
++					usb_req->buf2[1], 29, DMA_TO_DEVICE);
++			}
++		} else
++# endif
++			usb_req->dma = dma_map_single(dev, usb_req->buf,
++					usb_req->length, DMA_TO_DEVICE);
++		*req_flags |= DWC_PCD_REQ_MAP_DMA | DWC_PCD_REQ_IN;
++	} else {
++# ifdef DWC_TEST_ISOC_CHAIN
++		if (dwc_usb3_pcd_ep_type(pcd_ep) == UE_ISOCHRONOUS) {
++			if (usb_req->length > 58 && usb_req->buf2[0]) {
++				usb_req->dma2[0] = dma_map_single(dev,
++				      usb_req->buf2[0], 29, DMA_FROM_DEVICE);
++			}
++			if (usb_req->length > 58) {
++				usb_req->dma = dma_map_single(dev, usb_req->buf,
++				      usb_req->length - 58, DMA_FROM_DEVICE);
++			} else {
++				usb_req->dma = dma_map_single(dev, usb_req->buf,
++				      usb_req->length, DMA_FROM_DEVICE);
++			}
++			if (usb_req->length > 58 && usb_req->buf2[1]) {
++				usb_req->dma2[1] = dma_map_single(dev,
++				      usb_req->buf2[1], 29, DMA_FROM_DEVICE);
++			}
++		} else
++# endif
++			usb_req->dma = dma_map_single(dev, usb_req->buf,
++					usb_req->length, DMA_FROM_DEVICE);
++		*req_flags |= DWC_PCD_REQ_MAP_DMA;
++	}
++}
++
++static void unmap_buffers(struct device *dev, struct usb_request *usb_req,
++			  dwc_usb3_pcd_ep_t *pcd_ep, int *req_flags)
++{
++	if (*req_flags & DWC_PCD_REQ_IN) {
++# ifdef DWC_TEST_ISOC_CHAIN
++		if (dwc_usb3_pcd_ep_type(pcd_ep) == UE_ISOCHRONOUS) {
++			if (usb_req->dma2[1] != DWC_DMA_ADDR_INVALID) {
++				dma_unmap_single(dev, usb_req->dma2[1], 29,
++						 DMA_TO_DEVICE);
++			}
++			if (usb_req->dma2[1] != DWC_DMA_ADDR_INVALID ||
++			    usb_req->dma2[0] != DWC_DMA_ADDR_INVALID) {
++				dma_unmap_single(dev, usb_req->dma,
++					usb_req->length - 58, DMA_TO_DEVICE);
++			} else {
++				dma_unmap_single(dev, usb_req->dma,
++					usb_req->length, DMA_TO_DEVICE);
++			}
++			if (usb_req->dma2[0] != DWC_DMA_ADDR_INVALID) {
++				dma_unmap_single(dev, usb_req->dma2[0], 29,
++						 DMA_TO_DEVICE);
++			}
++		} else
++# endif
++			dma_unmap_single(dev, usb_req->dma, usb_req->length,
++					 DMA_TO_DEVICE);
++	} else {
++# ifdef DWC_TEST_ISOC_CHAIN
++		if (dwc_usb3_pcd_ep_type(pcd_ep) == UE_ISOCHRONOUS) {
++			if (usb_req->dma2[1] != DWC_DMA_ADDR_INVALID) {
++				dma_unmap_single(dev, usb_req->dma2[1], 29,
++						 DMA_FROM_DEVICE);
++			}
++			if (usb_req->dma2[1] != DWC_DMA_ADDR_INVALID ||
++			    usb_req->dma2[0] != DWC_DMA_ADDR_INVALID) {
++				dma_unmap_single(dev, usb_req->dma,
++				      usb_req->length - 58, DMA_FROM_DEVICE);
++			} else {
++				dma_unmap_single(dev, usb_req->dma,
++				      usb_req->length, DMA_FROM_DEVICE);
++			}
++			if (usb_req->dma2[0] != DWC_DMA_ADDR_INVALID) {
++				dma_unmap_single(dev, usb_req->dma2[0], 29,
++						 DMA_FROM_DEVICE);
++			}
++		} else
++# endif
++			dma_unmap_single(dev, usb_req->dma, usb_req->length,
++					 DMA_FROM_DEVICE);
++	}
++
++	*req_flags &= ~(DWC_PCD_REQ_MAP_DMA | DWC_PCD_REQ_IN);
++
++# ifdef DWC_TEST_ISOC_CHAIN
++	usb_req->dma2[0] = DWC_DMA_ADDR_INVALID;
++	usb_req->dma2[1] = DWC_DMA_ADDR_INVALID;
++# endif
++	usb_req->dma = DWC_DMA_ADDR_INVALID;
++}
++
++#if defined(DEBUG) || defined(ISOC_DEBUG)
++static void dbg_databuf(dwc_usb3_pcd_t *pcd, struct usb_request *usb_req,
++			dwc_usb3_pcd_ep_t *pcd_ep, u32 actual,
++			dma_addr_t dma
++#ifdef DWC_TEST_ISOC_CHAIN
++		       , dma_addr_t dma2[2]
++#endif
++		      )
++{
++	if (dwc_usb3_pcd_ep_type(pcd_ep) == UE_ISOCHRONOUS) {
++		unsigned char *buf = (unsigned char *)usb_req->buf;
++# ifdef DWC_TEST_ISOC_CHAIN
++		unsigned char *buf0 = (unsigned char *)usb_req->buf2[0];
++		unsigned char *buf1 = (unsigned char *)usb_req->buf2[1];
++# endif
++		if (buf) {
++			if (actual >= 4) {
++# ifdef DWC_TEST_ISOC_CHAIN
++				dwc_isocdbg(pcd->usb3_dev,
++					"%p %1lx %1lx %1lx bdata: %02x %02x %02x "
++					"%02x .. %02x %02x %02x %02x .. %02x "
++					"%02x %02x %02x\n",
++					buf,
++					(unsigned long)dma,
++					(unsigned long)dma2[0],
++					(unsigned long)dma2[1],
++					buf[0], buf[1], buf[2], buf[3],
++					buf0[0], buf0[1], buf0[2], buf0[3],
++					buf1[0], buf1[1], buf1[2], buf1[3]);
++# else
++				dwc_isocdbg(pcd->usb3_dev,
++					    "%p %1lx bdata: %02x %02x %02x %02x\n",
++					    buf,
++					    (unsigned long)dma,
++					    buf[0], buf[1], buf[2], buf[3]);
++# endif
++			} else if (actual > 0) {
++				dwc_isocdbg(pcd->usb3_dev,
++					    "%p %1lx bdata: %02x ...\n",
++					    buf,
++					    (unsigned long)dma, buf[0]);
++			} else {
++				dwc_isocdbg(pcd->usb3_dev,
++					    "%p %1lx bdata: 0-len!\n",
++					    buf,
++					    (unsigned long)dma);
++			}
++		} else {
++			dwc_isocdbg(pcd->usb3_dev, "bdata: buf NULL!\n");
++		}
++	}
++}
++#endif
++
++/**
++ * This function receives Transfer Complete notifications from the PCD
++ */
++int dwc_usb3_gadget_complete(dwc_usb3_pcd_t *pcd, dwc_usb3_pcd_ep_t *pcd_ep,
++			     dwc_usb3_pcd_req_t *pcd_req, int status)
++{
++	struct usb_ep *usb_ep = &pcd_ep->usb_ep;
++	struct usb_request *usb_req = &pcd_req->usb_req;
++	u32 actual = pcd_req->dwc_req.actual;
++	int *req_flags = &pcd_req->dwc_req.flags;
++	dma_addr_t dma;
++#ifdef DWC_TEST_ISOC_CHAIN
++	dma_addr_t dma2[2];
++#endif
++
++	/* Remove the request from the queue */
++	list_del_init(&pcd_req->entry);
++
++	/* Save DMA address for debug */
++	dma = usb_req->dma;
++#ifdef DWC_TEST_ISOC_CHAIN
++	dma2[0] = usb_req->dma2[0];
++	dma2[1] = usb_req->dma2[1];
++#endif
++
++	/* Unmap DMA */
++	if (*req_flags & DWC_PCD_REQ_MAP_DMA) {
++		dwc_debug(pcd->usb3_dev, "DMA unmap req %p\n", usb_req);
++		unmap_buffers(pcd->usb3_dev->dev, usb_req, pcd_ep, req_flags);
++	}
++
++#if defined(DEBUG) || defined(ISOC_DEBUG)
++	dbg_databuf(pcd, usb_req, pcd_ep, actual, dma
++# ifdef DWC_TEST_ISOC_CHAIN
++		    , dma2
++# endif
++		   );
++#endif
++
++	if (usb_req->complete) {
++		usb_req->status = status;
++		usb_req->actual = actual;
++		spin_unlock(&pcd->lock);
++		usb_req->complete(usb_ep, usb_req);
++		spin_lock(&pcd->lock);
++	}
++
++	if (pcd->request_pending > 0)
++		--pcd->request_pending;
++
++	return 0;
++}
++
++/**
++ * This function allows overriding the standard Control transfer handling
++ * (currently only done by the axs101 test gadget)
++ *
++ * @param pcd           Programming view of DWC_usb3 peripheral controller.
++ */
++void dwc_usb3_gadget_do_setup(dwc_usb3_pcd_t *pcd)
++{
++	/* Call the standard Control transfer handler */
++	dwc_usb3_pcd_do_setup(pcd);
++}
++
++/*
++ * Gadget EP ops
++ */
++
++/**
++ * This function fills in an I/O Request for an EP.
++ */
++static void fill_req(dwc_usb3_pcd_t *pcd, dwc_usb3_pcd_ep_t *ep,
++		     dwc_usb3_pcd_req_t *req, int numbuf, char **buf,
++		     dwc_dma_t *bufdma, u32 *buflen, u32 stream, int req_flags)
++{
++	int i;
++
++	dwc_debug(pcd->usb3_dev, "req_flags=0x%1x\n", req_flags);
++
++	req->dwc_req.length = 0;
++	req->dwc_req.numbuf = numbuf;
++
++	for (i = 0; i < numbuf; i++) {
++		req->dwc_req.buf[i] = buf[i];
++		req->dwc_req.bufdma[i] = bufdma[i];
++		req->dwc_req.buflen[i] = buflen[i];
++		req->dwc_req.length += buflen[i];
++	}
++
++	req->dwc_req.actual = 0;
++	req->dwc_req.stream = stream;
++	req->dwc_req.flags = req_flags;
++
++	/* For EP0 IN without premature status, zlp is required? */
++	if (ep == pcd->ep0 && ep->dwc_ep.is_in) {
++		dwc_debug(pcd->usb3_dev, "%d-OUT ZLP\n", ep->dwc_ep.num);
++		//req->dwc_req.flags |= DWC_PCD_REQ_ZERO;
++	}
++}
++
++/**
++ * This function enables an EP
++ */
++static int ep_enable(struct usb_ep *usb_ep,
++		     const struct usb_endpoint_descriptor *ep_desc)
++{
++	dwc_usb3_pcd_ep_t *pcd_ep;
++	dwc_usb3_pcd_t *pcd;
++	dwc_usb3_dma_desc_t *desc;
++	dma_addr_t desc_dma;
++	int num, dir, type, num_trbs, maxpacket, link;
++	int retval = 0;
++	unsigned long flags;
++	ss_endpoint_companion_descriptor_t ep_comp = { 0, };
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,1,0)
++	int maxstreams = 0, mult = 0, maxburst = 0;
++#endif
++
++#if defined(DEBUG) || defined(ISOC_DEBUG)
++	printk(KERN_DEBUG USB3_DWC "%s(%p,%p)\n", __func__, usb_ep, ep_desc);
++#endif
++	if (!gadget_wrapper) {
++		printk(KERN_WARNING USB3_DWC "%s null wrapper!\n", __func__);
++		return -EINVAL;
++	}
++
++	if (!usb_ep || !ep_desc ||
++	    ep_desc->bDescriptorType != USB_DT_ENDPOINT) {
++		printk(KERN_WARNING USB3_DWC
++		       "%s, bad ep or descriptor %p %p %d!\n",
++		       __func__, usb_ep, ep_desc,
++		       ep_desc ? ep_desc->bDescriptorType : 0);
++		return -EINVAL;
++	}
++
++#if defined(DEBUG) || defined(ISOC_DEBUG)
++	printk(USB3_DWC "usb_ep->name = %s\n", usb_ep->name);
++#endif
++	if (usb_ep == &gadget_wrapper->ep0.usb_ep) {
++		printk(KERN_WARNING USB3_DWC "%s called for EP0!\n", __func__);
++		return -EINVAL;
++	}
++
++	if (!ep_desc->wMaxPacketSize) {
++		printk(KERN_WARNING USB3_DWC "%s, zero %s wMaxPacketSize!\n",
++		       __func__, usb_ep->name);
++		return -ERANGE;
++	}
++
++	if (!gadget_wrapper->driver ||
++	    gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
++		printk(KERN_WARNING USB3_DWC "%s, bogus device state!\n",
++		       __func__);
++		return -ESHUTDOWN;
++	}
++
++#if defined(DEBUG) || defined(ISOC_DEBUG)
++	printk(KERN_DEBUG USB3_DWC "usb_ep->maxpacket = %d\n",
++	       le16_to_cpu(ep_desc->wMaxPacketSize));
++#endif
++	pcd = gadget_wrapper->pcd;
++	pcd_ep = dwc_usb3_get_pcd_ep(usb_ep);
++
++	if (pcd_ep->dwc_ep.phys >= DWC_MAX_PHYS_EP) {
++		dwc_warn(pcd->usb3_dev, "%s, bad %s phys EP # %d!\n",
++			 __func__, usb_ep->name, pcd_ep->dwc_ep.phys);
++		return -ERANGE;
++	}
++
++	/* Free any existing TRB allocation for this EP */
++	dwc_usb3_pcd_trb_free(pcd_ep);
++
++	num = UE_GET_ADDR(ep_desc->bEndpointAddress);
++	dir = UE_GET_DIR(ep_desc->bEndpointAddress);
++	type = UE_GET_XFERTYPE(ep_desc->bmAttributes);
++	link = 0;
++
++	/* Allocate the number of TRBs based on EP type */
++	switch (type) {
++	case UE_INTERRUPT:
++		num_trbs = DWC_NUM_INTR_TRBS;
++		break;
++	case UE_ISOCHRONOUS:
++		num_trbs = DWC_NUM_ISOC_TRBS;
++		link = 1;
++		break;
++	default:
++		num_trbs = DWC_NUM_BULK_TRBS;
++		break;
++	}
++
++	dwc_debug(pcd->usb3_dev, "ep%d-%s=%p phys=%d pcd_ep=%p\n",
++		  num, dir == UE_DIR_IN ? "IN" : "OUT", usb_ep,
++		  pcd_ep->dwc_ep.phys, pcd_ep);
++
++	/* Set the TRB allocation for this EP */
++	desc = dwc_usb3_pcd_trb_alloc(pcd_ep, num_trbs, type,
++				      ep_desc->bInterval - 1, link,
++				      &desc_dma);
++	if (!desc)
++		return -ENOMEM;
++
++	maxpacket = le16_to_cpu(ep_desc->wMaxPacketSize);
++
++	spin_lock_irqsave(&pcd->lock, flags);
++	dwc_wait_if_hibernating(pcd, flags);
++	pcd->usb3_dev->hiber_cnt++;
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,1,0)
++	if (gadget_wrapper->gadget.speed == USB_SPEED_SUPER) {
++		if (usb_ep->comp_desc) {
++			if (type == UE_ISOCHRONOUS)
++				mult = usb_ep->comp_desc->bmAttributes;
++			maxburst = usb_ep->comp_desc->bMaxBurst;
++			if (type == UE_BULK)
++				maxstreams = usb_ep->comp_desc->bmAttributes;
++		}
++	} else {
++		if (type == UE_ISOCHRONOUS)
++			mult = maxpacket >> 11 & 3;
++	}
++
++	if (mult > 2 || maxburst > 15 || maxstreams > 16) {
++		pcd->usb3_dev->hiber_cnt--;
++		spin_unlock_irqrestore(&pcd->lock, flags);
++		dwc_usb3_pcd_trb_free(pcd_ep);
++		return -EINVAL;
++	}
++
++	ep_comp.bmAttributes = USSE_SET_MAX_STREAMS(0, maxstreams);
++	ep_comp.bmAttributes = USSE_SET_MAX_PACKET_NUM(ep_comp.bmAttributes,
++						       mult);
++	ep_comp.bMaxBurst = maxburst;
++#else
++	if (type == UE_BULK)
++		ep_comp.bmAttributes = USSE_SET_MAX_STREAMS(0,
++						usb_ep->numstreams);
++	if (type == UE_ISOCHRONOUS)
++		ep_comp.bmAttributes = USSE_SET_MAX_PACKET_NUM(0, usb_ep->mult);
++
++	ep_comp.bMaxBurst = usb_ep->maxburst;
++#endif
++
++	retval = dwc_usb3_pcd_ep_enable(pcd, pcd_ep,
++		(usb_endpoint_descriptor_t *)ep_desc, &ep_comp);
++	if (!retval)
++		usb_ep->maxpacket = maxpacket;
++
++	if (gadget_wrapper->gadget.speed == USB_SPEED_HIGH) {
++		if (usb_ep->maxpacket == 5120)
++			usb_ep->maxpacket = 3072;
++		else if (usb_ep->maxpacket == 3072)
++			usb_ep->maxpacket = 2048;
++	}
++
++	pcd->usb3_dev->hiber_cnt--;
++	spin_unlock_irqrestore(&pcd->lock, flags);
++
++	if (retval) {
++		dwc_usb3_pcd_trb_free(pcd_ep);
++		retval = -ENOMEM;
++	}
++
++	return retval;
++}
++
++/**
++ * This function disables an EP
++ */
++static int ep_disable(struct usb_ep *usb_ep)
++{
++	int retval = 0;
++	dwc_usb3_pcd_ep_t *pcd_ep;
++	dwc_usb3_pcd_t *pcd;
++	unsigned long flags;
++
++#if defined(DEBUG) || defined(ISOC_DEBUG)
++	printk(KERN_DEBUG USB3_DWC "%s()\n", __func__);
++#endif
++	if (!gadget_wrapper) {
++		printk(KERN_WARNING USB3_DWC "%s null wrapper!\n", __func__);
++		return -EINVAL;
++	}
++
++	if (!usb_ep) {
++		printk(KERN_WARNING USB3_DWC "EP not enabled!\n");
++		return -EINVAL;
++	}
++
++	pcd = gadget_wrapper->pcd;
++
++	spin_lock_irqsave(&pcd->lock, flags);
++	dwc_wait_if_hibernating(pcd, flags);
++	pcd->usb3_dev->hiber_cnt++;
++
++	pcd_ep = dwc_usb3_get_pcd_ep(usb_ep);
++	retval = dwc_usb3_pcd_ep_disable(pcd, pcd_ep);
++
++	pcd->usb3_dev->hiber_cnt--;
++	spin_unlock_irqrestore(&pcd->lock, flags);
++
++	/* Free any existing TRB allocation for this EP */
++	dwc_usb3_pcd_trb_free(pcd_ep);
++
++	return retval ? -EINVAL : 0;
++}
++
++/**
++ * This function allocates a request object to use with the specified USB EP.
++ *
++ * @param usb_ep    The USB EP to be used with with the request.
++ * @param gfp_flags The GFP_* flags to use.
++ */
++static struct usb_request *alloc_request(struct usb_ep *usb_ep, gfp_t gfp_flags)
++{
++	dwc_usb3_pcd_req_t *pcd_req;
++
++#if defined(DEBUG) || defined(ISOC_DEBUG)
++	printk(KERN_DEBUG USB3_DWC "%s(%p,%d)\n", __func__, usb_ep, gfp_flags);
++#endif
++	if (!usb_ep) {
++		printk(USB3_DWC "%s() %s\n", __func__, "Invalid EP!\n");
++		return NULL;
++	}
++
++	pcd_req = kmalloc(sizeof(dwc_usb3_pcd_req_t), gfp_flags);
++	if (!pcd_req) {
++		printk(USB3_DWC "%s() pcd request allocation failed!\n",
++		       __func__);
++		return NULL;
++	}
++
++#if defined(DEBUG) || defined(ISOC_DEBUG)
++	//printk(USB3_DWC "%s() allocated %p\n", __func__, pcd_req);
++#endif
++	memset(pcd_req, 0, sizeof(dwc_usb3_pcd_req_t));
++	pcd_req->usb_req.dma = DWC_DMA_ADDR_INVALID;
++
++#ifdef DWC_TEST_ISOC_CHAIN
++	pcd_req->usb_req.dma2[0] = DWC_DMA_ADDR_INVALID;
++	pcd_req->usb_req.dma2[1] = DWC_DMA_ADDR_INVALID;
++#endif
++	return &pcd_req->usb_req;
++}
++
++/**
++ * This function frees a request object.
++ *
++ * @param usb_ep  The USB EP associated with the request.
++ * @param usb_req The request being freed.
++ */
++static void free_request(struct usb_ep *usb_ep, struct usb_request *usb_req)
++{
++	dwc_usb3_pcd_req_t *pcd_req;
++
++#if defined(DEBUG) || defined(ISOC_DEBUG)
++	printk(KERN_DEBUG USB3_DWC "%s(%p,%p)\n", __func__, usb_ep, usb_req);
++#endif
++	if (!usb_ep || !usb_req) {
++		printk(KERN_WARNING USB3_DWC "%s() %s\n", __func__,
++		       "Invalid ep or req argument!");
++		return;
++	}
++
++	pcd_req = dwc_usb3_get_pcd_req(usb_req);
++
++#if defined(DEBUG) || defined(ISOC_DEBUG)
++	//printk(USB3_DWC "%s() freed %p\n", __func__, pcd_req);
++#endif
++	kfree(pcd_req);
++}
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
++/**
++ * This function allocates an I/O buffer to be used for a transfer
++ * to/from the specified USB EP.
++ *
++ * @param usb_ep    The USB EP to be used with with the request.
++ * @param bytes     The desired number of bytes for the buffer.
++ * @param dma       Pointer to the buffer's DMA address; must be valid.
++ * @param gfp_flags The GFP_* flags to use.
++ * @return          Address of a new buffer or null if buffer could not be
++ *                  allocated.
++ */
++static void *alloc_buffer(struct usb_ep *usb_ep, unsigned bytes,
++			  dma_addr_t *dma, gfp_t gfp_flags)
++{
++	gfp_t gfp_flags = GFP_KERNEL | GFP_DMA32;
++	void *buf;
++
++#if defined(DEBUG) || defined(ISOC_DEBUG)
++	printk(KERN_DEBUG USB3_DWC "%s(%p,%d,%p,%0x)\n", __func__,
++	       usb_ep, bytes, dma, gfp_flags);
++#endif
++	/* Check dword alignment */
++	if ((bytes & 0x3) != 0) {
++		printk(KERN_WARNING USB3_DWC
++		      "%s() Buffer size is not a multiple of DWORD size (%d)\n",
++		      __func__, bytes);
++	}
++
++	buf = dma_alloc_coherent(NULL, bytes, dma, gfp_flags);
++	if (buf) {
++		/* Check dword alignment */
++		if (((unsigned long)buf & 0x3) != 0) {
++			printk(KERN_WARNING USB3_DWC
++			       "%s() Buffer is not DWORD aligned (%p)\n",
++			       __func__, buf);
++		}
++	}
++
++	return buf;
++}
++
++/**
++ * This function frees an I/O buffer that was allocated by alloc_buffer.
++ *
++ * @param usb_ep The USB EP associated with the buffer.
++ * @param buf    Address of the buffer.
++ * @param dma    The buffer's DMA address.
++ * @param bytes  The number of bytes of the buffer.
++ */
++static void free_buffer(struct usb_ep *usb_ep, void *buf,
++			dma_addr_t dma, unsigned bytes)
++{
++#if defined(DEBUG) || defined(ISOC_DEBUG)
++	printk(KERN_DEBUG USB3_DWC "%s(%p,%p,%0x,%d)\n", __func__,
++	       usb_ep, buf, dma, bytes);
++#endif
++	dma_free_coherent(NULL, bytes, buf, dma);
++}
++#endif
++
++/**
++ * This function queues a request to a USB EP
++ */
++static int ep_queue(struct usb_ep *usb_ep, struct usb_request *usb_req,
++		    gfp_t gfp_flags)
++{
++	int is_atomic = 0;
++	int retval = 0;
++	int req_flags = 0;
++	dwc_usb3_pcd_ep_t *pcd_ep;
++	dwc_usb3_pcd_req_t *pcd_req;
++	int numbufs;
++	char *bufs[3];
++	dma_addr_t bufdmas[3];
++	u32 buflens[3];
++	dwc_usb3_pcd_t *pcd;
++	unsigned long flags;
++
++#ifdef DEBUG
++	printk(KERN_DEBUG USB3_DWC "%s(%p,%p,%d)\n", __func__,
++	       usb_ep, usb_req, gfp_flags);
++#endif
++	if (!gadget_wrapper) {
++		printk(KERN_WARNING USB3_DWC "%s null wrapper!\n", __func__);
++		return -EINVAL;
++	}
++
++#ifdef DEBUG
++	printk(KERN_DEBUG USB3_DWC "pcd=%p\n", gadget_wrapper->pcd);
++#endif
++	if (!usb_req || !usb_req->complete || !usb_req->buf) {
++		printk(KERN_WARNING USB3_DWC "%s, bad params\n", __func__);
++		return -EINVAL;
++	}
++
++	if (!usb_ep) {
++		printk(KERN_WARNING USB3_DWC "%s, bad ep\n", __func__);
++		return -EINVAL;
++	}
++
++	if (!gadget_wrapper->driver ||
++	    gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
++		printk(KERN_DEBUG USB3_DWC "gadget.speed=%d\n",
++		       gadget_wrapper->gadget.speed);
++		printk(KERN_WARNING USB3_DWC "%s, bogus device state\n",
++		       __func__);
++		return -ESHUTDOWN;
++	}
++
++	if (!gadget_wrapper->pcd) {
++		printk(KERN_WARNING USB3_DWC
++		       "%s, gadget_wrapper->pcd is NULL!\n", __func__);
++		return -EINVAL;
++	}
++
++	pcd_ep = dwc_usb3_get_pcd_ep(usb_ep);
++	pcd_req = dwc_usb3_get_pcd_req(usb_req);
++	pcd = dwc_usb3_pcd_ep_to_pcd(pcd_ep);
++
++#ifdef DEBUG
++	printk(KERN_DEBUG USB3_DWC "%s 0x%p queue req 0x%p, len %d buf 0x%p\n",
++	       usb_ep->name, pcd_ep, usb_req, usb_req->length, usb_req->buf);
++#endif
++	usb_req->status = -EINPROGRESS;
++	usb_req->actual = 0;
++
++	if (gfp_flags == GFP_ATOMIC)
++		is_atomic = 1;
++
++	if (usb_req->zero)
++		req_flags |= DWC_PCD_REQ_ZERO;
++
++	if (usb_req->length != 0 && usb_req->dma == DWC_DMA_ADDR_INVALID) {
++		dwc_debug(pcd->usb3_dev, "DMA map req %p\n", usb_req);
++		dwc_debug(pcd->usb3_dev, "dev=%p\n", pcd->usb3_dev->dev);
++		map_buffers(pcd->usb3_dev->dev, usb_req, pcd_ep, &req_flags);
++	}
++
++	bufs[0] = usb_req->buf;
++	bufdmas[0] = usb_req->dma;
++	buflens[0] = usb_req->length;
++	numbufs = 1;
++
++#ifdef DWC_TEST_ISOC_CHAIN
++	if (dwc_usb3_pcd_ep_type(pcd_ep) == UE_ISOCHRONOUS) {
++		buflens[0] = usb_req->length - 58;
++
++		bufs[1] = usb_req->buf2[0];
++		bufdmas[1] = usb_req->dma2[0];
++		buflens[1] = 29;
++
++		bufs[2] = usb_req->buf2[1];
++		bufdmas[2] = usb_req->dma2[1];
++		buflens[2] = 29;
++
++		numbufs = 3;
++	}
++#endif
++	if (dwc_usb3_pcd_ep_num(pcd_ep) != 0 && !pcd_ep->dwc_ep.usb_ep_desc) {
++		dwc_debug(pcd->usb3_dev, "%s, bad ep!\n", __func__);
++		return -EINVAL;
++	}
++
++	spin_lock_irqsave(&pcd->lock, flags);
++	dwc_wait_if_hibernating(pcd, flags);
++	pcd->usb3_dev->hiber_cnt++;
++
++	dwc_debug(pcd->usb3_dev, "%s: EP%d-%s %p stream %d req %p\n",
++		  __func__, dwc_usb3_pcd_ep_num(pcd_ep),
++		  dwc_usb3_pcd_ep_is_in(pcd_ep) ? "IN" : "OUT",
++		  pcd_ep, usb_req->stream_id, pcd_req);
++
++	dwc_debug(pcd->usb3_dev, "%s(%p,%p,%p,%p,%lx)\n", __func__, pcd,
++		  usb_ep, usb_req, bufs[0], (unsigned long)bufdmas[0]);
++
++	INIT_LIST_HEAD(&pcd_req->entry);
++
++	fill_req(pcd, pcd_ep, pcd_req, numbufs, bufs, bufdmas, buflens,
++		 usb_req->stream_id, req_flags);
++
++	if (!list_empty(&pcd_ep->dwc_ep.queue)) {
++		/* If queue is not empty, then don't start the transfer, unless
++		 * this is an Isoc transfer. But we still queue the request.
++		 */
++		dwc_debug(pcd->usb3_dev,
++			  " q not empty %d, stopped %d, avail %d, istart %d\n",
++			  pcd->request_pending, pcd_ep->dwc_ep.stopped,
++			  pcd_ep->dwc_ep.desc_avail,
++			  pcd_ep->dwc_ep.xfer_started);
++
++		if (!pcd_ep->dwc_ep.stopped &&
++		    pcd_ep->dwc_ep.type == UE_ISOCHRONOUS &&
++		    pcd_ep->dwc_ep.desc_avail > 0 &&
++		    pcd_ep->dwc_ep.xfer_started)
++			goto do_start;
++
++	} else if (pcd_ep->dwc_ep.stopped ||
++		   (pcd_ep != pcd->ep0 && pcd_ep->dwc_ep.desc_avail <= 0) ||
++		   (pcd_ep->dwc_ep.type == UE_ISOCHRONOUS &&
++						!pcd_ep->dwc_ep.xfer_started)) {
++		/* If EP is stopped, or there is no TRB available, or this
++		 * is an Isoc transfer and the EP is not started, then don't
++		 * start the transfer. But we still queue the request.
++		 */
++		dwc_debug(pcd->usb3_dev,
++			  " q empty %d, stopped %d, avail %d, istart %d\n",
++			  pcd->request_pending, pcd_ep->dwc_ep.stopped,
++			  pcd_ep->dwc_ep.desc_avail, pcd_ep->dwc_ep.xfer_started);
++	} else {
++do_start:
++		/* Setup and start the transfer */
++		dwc_usb3_pcd_fill_trbs(pcd, pcd_ep, pcd_req);
++		retval = dwc_usb3_pcd_ep_submit_req(pcd, pcd_ep, pcd_req,
++						    req_flags);
++	}
++
++	if (!retval) {
++		list_add_tail(&pcd_req->entry, &pcd_ep->dwc_ep.queue);
++		++pcd->request_pending;
++	}
++
++	pcd->usb3_dev->hiber_cnt--;
++	spin_unlock_irqrestore(&pcd->lock, flags);
++
++	/* dwc_usb3_pcd_ep_submit_req() can return positive values for
++	 * Control transfers, don't propagate those from this function
++	 */
++	if (retval < 0)
++		return -EINVAL;
++	return 0;
++}
++
++/**
++ * This function dequeues a request from a USB EP
++ */
++static int ep_dequeue(struct usb_ep *usb_ep, struct usb_request *usb_req)
++{
++	dwc_usb3_pcd_req_t *pcd_req = NULL;
++	dwc_usb3_pcd_ep_t *pcd_ep;
++	dwc_usb3_pcd_t *pcd;
++	struct list_head *list_item;
++	unsigned long flags;
++
++#ifdef DEBUG
++	printk(KERN_DEBUG USB3_DWC "%s(%p,%p)\n", __func__, usb_ep, usb_req);
++#endif
++	if (!gadget_wrapper) {
++		printk(KERN_WARNING USB3_DWC "%s null wrapper!\n", __func__);
++		return -EINVAL;
++	}
++
++	if (!usb_ep || !usb_req) {
++		printk(KERN_WARNING USB3_DWC "%s, bad argument!\n", __func__);
++		return -EINVAL;
++	}
++
++	if (!gadget_wrapper->driver ||
++	    gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
++		printk(KERN_WARNING USB3_DWC "%s, bogus device state!\n",
++		       __func__);
++		return -ESHUTDOWN;
++	}
++
++	if (!gadget_wrapper->pcd) {
++		printk(KERN_WARNING USB3_DWC
++		       "%s, gadget_wrapper->pcd is NULL!\n", __func__);
++		return -EINVAL;
++	}
++
++	pcd = gadget_wrapper->pcd;
++
++	spin_lock_irqsave(&pcd->lock, flags);
++	dwc_wait_if_hibernating(pcd, flags);
++	pcd->usb3_dev->hiber_cnt++;
++
++	pcd_ep = dwc_usb3_get_pcd_ep(usb_ep);
++
++	if (dwc_usb3_pcd_ep_num(pcd_ep) != 0 && !pcd_ep->dwc_ep.usb_ep_desc) {
++		//dwc_warn(pcd->usb3_dev, "%s, bad pcd_ep!\n", __func__);
++		pcd->usb3_dev->hiber_cnt--;
++		spin_unlock_irqrestore(&pcd->lock, flags);
++		return -EINVAL;
++	}
++
++	/* make sure it's actually queued on this EP */
++	list_for_each (list_item, &pcd_ep->dwc_ep.queue) {
++		pcd_req = list_entry(list_item, dwc_usb3_pcd_req_t, entry);
++		if (&pcd_req->usb_req == usb_req)
++			break;
++	}
++
++	if (!pcd_req) {
++		dwc_warn(pcd->usb3_dev, "%s, no request in queue!\n", __func__);
++		pcd->usb3_dev->hiber_cnt--;
++		spin_unlock_irqrestore(&pcd->lock, flags);
++		return 0;
++	}
++
++	dwc_usb3_pcd_ep_cancel_req(pcd, pcd_ep, pcd_req, usb_req->stream_id);
++
++	pcd->usb3_dev->hiber_cnt--;
++	spin_unlock_irqrestore(&pcd->lock, flags);
++	return 0;
++}
++
++/**
++ * This routine allocates coherent DMA memory. It is used by the PCD to
++ * allocate memory for TRBs. The block of memory returned must have a start
++ * address aligned to a 16-byte boundary.
++ *
++ * @param ep            PCD EP that memory block will be associated with.
++ * @param size          Size of memory block to allocate, in bytes.
++ * @param mem_dma_ret   DMA address of allocated memory block is returned
++ *                      through this pointer.
++ * @return              Address of allocated memory block, or NULL if allocation
++ *                      fails.
++ */
++void *dwc_usb3_gadget_alloc_dma(dwc_usb3_pcd_ep_t *ep, int size,
++				dwc_dma_t *mem_dma_ret)
++{
++	void *mem;
++
++	mem = dma_alloc_coherent(NULL, size, mem_dma_ret,
++				 GFP_ATOMIC | GFP_DMA32);
++	if (!mem)
++		return NULL;
++	memset(mem, 0, size);
++	return mem;
++}
++
++/**
++ * This routine frees DMA memory allocated by dwc_usb3_gadget_alloc_dma().
++ *
++ * @param ep            PCD EP that memory block is associated with.
++ * @param size          Size of memory block to free, in bytes.
++ * @param mem           Address of memory block.
++ * @param mem_dma       DMA address of memory block.
++ */
++void dwc_usb3_gadget_free_dma(dwc_usb3_pcd_ep_t *ep, int size, void *mem,
++			      dwc_dma_t mem_dma)
++{
++	dma_free_coherent(NULL, size, mem, mem_dma);
++}
++
++/**
++ * This routine returns the PCD request corresponding to the current transfer
++ * request for an endpoint. The current transfer request is the first request
++ * submitted that has not been completed yet.
++ */
++dwc_usb3_pcd_req_t *dwc_usb3_gadget_get_request(dwc_usb3_pcd_t *pcd,
++						dwc_usb3_pcd_ep_t *ep)
++{
++	dwc_usb3_pcd_req_t *req;
++
++	/* Check for a pending request */
++	if (list_empty(&ep->dwc_ep.queue)) {
++		dwc_debug(pcd->usb3_dev, "%s(%p), ep->dwc_ep.queue empty!\n",
++			  __func__, ep);
++		return NULL;
++	}
++
++	req = list_first_entry(&ep->dwc_ep.queue, dwc_usb3_pcd_req_t, entry);
++	return req;
++}
++
++/**
++ * This function checks the EP request queue, if the queue is not empty then
++ * the next transfer is started.
++ *
++ * @param pcd   Programming view of DWC_usb3 peripheral controller.
++ * @param ep    EP to operate on.
++ */
++void dwc_usb3_gadget_start_next_request(dwc_usb3_pcd_t *pcd,
++					dwc_usb3_pcd_ep_t *ep)
++{
++	dwc_usb3_pcd_req_t *req = NULL;
++	struct list_head *list_item;
++
++	dwc_debug(pcd->usb3_dev, "%s(%p)\n", __func__, ep);
++
++	if (list_empty(&ep->dwc_ep.queue)) {
++		dwc_debug(pcd->usb3_dev, "start_next EP%d-%s: queue empty\n",
++			  ep->dwc_ep.num, ep->dwc_ep.is_in ? "IN" : "OUT");
++		return;
++	}
++
++	list_for_each (list_item, &ep->dwc_ep.queue) {
++		req = list_entry(list_item, dwc_usb3_pcd_req_t, entry);
++		if (!(req->dwc_req.flags & DWC_PCD_REQ_STARTED)) {
++			if (ep->dwc_ep.desc_avail <= 0) {
++				dwc_debug(pcd->usb3_dev,
++					  "start_next EP%d-%s: no TRB avail\n",
++					  ep->dwc_ep.num, ep->dwc_ep.is_in ?
++					  "IN" : "OUT");
++				return;
++			}
++
++			dwc_debug(pcd->usb3_dev, "start_next EP%d-%s: OK\n",
++				  ep->dwc_ep.num,
++				  ep->dwc_ep.is_in ? "IN" : "OUT");
++
++			/* Setup and start the transfer */
++			//dwc_debug(pcd->usb3_dev,
++			//	  " -> starting xfer (start_next_req) %s %s\n",
++			//	  ep->dwc_ep.ep.name,
++			//	  ep->dwc_ep.is_in ? "IN" : "OUT");
++			dwc_usb3_pcd_fill_trbs(pcd, ep, req);
++			dwc_usb3_pcd_ep_start_transfer(pcd, ep, req, 0);
++			return;
++		}
++	}
++
++	dwc_debug(pcd->usb3_dev, "start_next EP%d-%s: all req active\n",
++		  ep->dwc_ep.num, ep->dwc_ep.is_in ? "IN" : "OUT");
++}
++
++/**
++ * This function terminates all the requests in the EP request queue.
++ */
++void dwc_usb3_gadget_request_nuke(dwc_usb3_pcd_t *pcd, dwc_usb3_pcd_ep_t *ep)
++{
++	dwc_usb3_pcd_req_t *req;
++
++	dwc_debug(pcd->usb3_dev, "%s(%p)\n", __func__, ep);
++	ep->dwc_ep.stopped = 1;
++
++	/* called with irqs blocked?? */
++	while (!list_empty(&ep->dwc_ep.queue)) {
++		req = list_first_entry(&ep->dwc_ep.queue, dwc_usb3_pcd_req_t,
++				       entry);
++		dwc_usb3_pcd_request_done(pcd, ep, req, -DWC_E_SHUTDOWN);
++	}
++
++	if (ep != pcd->ep0) {
++		ep->dwc_ep.desc_idx = 0;
++		ep->dwc_ep.hiber_desc_idx = 0;
++	}
++}
++
++/**
++ * This function marks all requests in an EP queue as not started.
++ */
++void dwc_usb3_gadget_set_ep_not_started(dwc_usb3_pcd_t *pcd,
++					dwc_usb3_pcd_ep_t *ep)
++{
++	dwc_usb3_pcd_req_t *req;
++	struct list_head *list_item;
++
++	list_for_each (list_item, &ep->dwc_ep.queue) {
++		req = list_entry(list_item, dwc_usb3_pcd_req_t, entry);
++		if (req->dwc_req.flags & DWC_PCD_REQ_STARTED)
++			req->dwc_req.flags &= ~DWC_PCD_REQ_STARTED;
++		if (req->dwc_req.trb) {
++			dwc_usb3_disable_desc(req->dwc_req.trb);
++			(req->dwc_req.trb)->bpth = ep->dwc_ep.desc_avail;
++			ep->dwc_ep.desc_avail++;
++			req->dwc_req.trb = NULL;
++		}
++
++	}
++}
++
++/**
++ * Start an Isoc EP running at the proper interval, after receiving the initial
++ * XferNrdy event.
++ */
++void dwc_usb3_gadget_isoc_ep_start(dwc_usb3_pcd_t *pcd, dwc_usb3_pcd_ep_t *ep,
++				   u32 event)
++{
++	dwc_usb3_pcd_req_t *req = NULL;
++	struct list_head *list_item;
++
++	dwc_debug(pcd->usb3_dev, "%s(%p,%p,%x)\n", __func__, pcd, ep, event);
++	dwc_isocdbg(pcd->usb3_dev, "%s(%08x)\n", __func__, event);
++
++	if (list_empty(&ep->dwc_ep.queue)) {
++		dwc_debug(pcd->usb3_dev, "%s(%p), ep->dwc_ep.queue empty!\n",
++			  __func__, ep);
++		return;
++	}
++
++	if (ep->dwc_ep.desc_avail <= 0) {
++		dwc_print(pcd->usb3_dev, "EP%d-%s: no TRB avail!\n",
++			  ep->dwc_ep.num, ep->dwc_ep.is_in ? "IN" : "OUT");
++		return;
++	}
++
++	/* If need to restart after hibernation, handle that and return */
++	if (dwc_usb3_pcd_isoc_ep_hiber_restart(pcd, ep))
++		return;
++
++	/*
++	 * Start the next queued transfer at the target uFrame
++	 */
++
++	list_for_each (list_item, &ep->dwc_ep.queue) {
++		req = list_entry(list_item, dwc_usb3_pcd_req_t, entry);
++		if (req->dwc_req.flags & DWC_PCD_REQ_STARTED)
++			req = NULL;
++		else
++			break;
++	}
++
++	dwc_debug(pcd->usb3_dev, "req=%p\n", req);
++	if (!req) {
++		dwc_print(pcd->usb3_dev, "EP%d-%s: no requests to start!\n",
++			  ep->dwc_ep.num, ep->dwc_ep.is_in ? "IN" : "OUT");
++		return;
++	}
++
++	dwc_usb3_pcd_fill_trbs(pcd, ep, req);
++	dwc_usb3_pcd_ep_start_transfer(pcd, ep, req, event);
++
++	/*
++	 * Now start any remaining queued transfers
++	 */
++
++	while (!list_is_last(list_item, &ep->dwc_ep.queue)) {
++		list_item = list_item->next;
++		req = list_entry(list_item, dwc_usb3_pcd_req_t, entry);
++		if (!(req->dwc_req.flags & DWC_PCD_REQ_STARTED)) {
++			if (ep->dwc_ep.desc_avail <= 0) {
++				dwc_debug(pcd->usb3_dev,
++					  "start_next EP%d-%s: no TRB avail!\n",
++					  ep->dwc_ep.num, ep->dwc_ep.is_in ?
++					  "IN" : "OUT");
++				return;
++			}
++
++			dwc_usb3_pcd_fill_trbs(pcd, ep, req);
++			dwc_usb3_pcd_ep_start_transfer(pcd, ep, req, 0);
++		}
++	}
++}
++
++/**
++ * This function sets/clears halt on a USB EP
++ */
++static int ep_set_halt(struct usb_ep *usb_ep, int value)
++{
++	dwc_usb3_pcd_ep_t *pcd_ep;
++	dwc_usb3_pcd_t *pcd;
++	unsigned long flags;
++
++	if (!gadget_wrapper) {
++		printk(KERN_WARNING USB3_DWC "%s null wrapper!\n", __func__);
++		return -EINVAL;
++	}
++
++	if (!usb_ep) {
++		printk(KERN_WARNING USB3_DWC "%s, bad usb_ep!\n", __func__);
++		return -EINVAL;
++	}
++
++#if defined(DEBUG) || defined(ISOC_DEBUG)
++	printk(KERN_DEBUG USB3_DWC "HALT %s %d\n", usb_ep->name, value);
++#endif
++
++	pcd = gadget_wrapper->pcd;
++
++	spin_lock_irqsave(&pcd->lock, flags);
++	dwc_wait_if_hibernating(pcd, flags);
++	pcd->usb3_dev->hiber_cnt++;
++
++	pcd_ep = dwc_usb3_get_pcd_ep(usb_ep);
++	dwc_debug(pcd->usb3_dev, "pcd_ep=%p\n", pcd_ep);
++	dwc_debug(pcd->usb3_dev, "pcd->ep0=%p\n", pcd->ep0);
++	dwc_debug(pcd->usb3_dev, "epnum=%d is_in=%d\n",
++		  dwc_usb3_pcd_ep_num(pcd_ep), dwc_usb3_pcd_ep_is_in(pcd_ep));
++
++	if ((!pcd_ep->dwc_ep.usb_ep_desc && dwc_usb3_pcd_ep_num(pcd_ep) != 0) ||
++	    (pcd_ep->dwc_ep.usb_ep_desc && dwc_usb3_pcd_ep_type(pcd_ep)
++							== UE_ISOCHRONOUS)) {
++		dwc_warn(pcd->usb3_dev, "%s, bad pcd_ep!\n", __func__);
++		pcd->usb3_dev->hiber_cnt--;
++		spin_unlock_irqrestore(&pcd->lock, flags);
++		return -EINVAL;
++	}
++
++	if (!list_empty(&pcd_ep->dwc_ep.queue)) {
++		dwc_warn(pcd->usb3_dev, "%s, Xfer in process!\n", __func__);
++		pcd->usb3_dev->hiber_cnt--;
++		spin_unlock_irqrestore(&pcd->lock, flags);
++		return -EAGAIN;
++	}
++
++	dwc_usb3_pcd_ep_set_halt(pcd, pcd_ep, value);
++
++	pcd->usb3_dev->hiber_cnt--;
++	spin_unlock_irqrestore(&pcd->lock, flags);
++	return 0;
++}
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
++static int ep_set_wedge(struct usb_ep *usb_ep)
++{
++#if defined(DEBUG) || defined(ISOC_DEBUG)
++	printk(KERN_DEBUG USB3_DWC "WEDGE %s\n", usb_ep->name);
++#endif
++	return ep_set_halt(usb_ep, 3);
++}
++#endif
++
++static struct usb_ep_ops pcd_ep_ops = {
++	.enable		= ep_enable,
++	.disable	= ep_disable,
++
++	.alloc_request	= alloc_request,
++	.free_request	= free_request,
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
++	.alloc_buffer	= alloc_buffer,
++	.free_buffer	= free_buffer,
++#endif
++	.queue		= ep_queue,
++	.dequeue	= ep_dequeue,
++
++	.set_halt	= ep_set_halt,
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
++	.set_wedge	= ep_set_wedge,
++#endif
++	.fifo_status	= NULL,
++	.fifo_flush	= NULL,
++};
++
++
++/* Gadget ops */
++
++#ifdef CONFIG_USB_OTG_DWC
++
++void dwc_usb3_start_hnp(dwc_usb3_pcd_t *pcd)
++{
++	struct usb_phy *phy = usb_get_phy(USB_PHY_TYPE_USB3);
++	struct usb_otg *otg;
++
++	dwc_debug(pcd->usb3_dev, "%s()\n", __func__);
++	if (IS_ERR(phy) || !phy) {
++		dwc_info(pcd->usb3_dev, "NO PHY!!\n");
++		if (!IS_ERR(phy))
++			usb_put_phy(phy);
++		return;
++	}
++
++	otg = phy->otg;
++	if (!otg) {
++		dwc_info(pcd->usb3_dev, "NO OTG!!\n");
++		usb_put_phy(phy);
++		return;
++	}
++
++	otg_start_hnp(otg);
++	usb_put_phy(phy);
++}
++
++void dwc_usb3_host_release(dwc_usb3_pcd_t *pcd)
++{
++	struct usb_phy *phy = usb_get_phy(USB_PHY_TYPE_USB3);
++	struct usb_otg *otg;
++
++	dwc_debug(pcd->usb3_dev, "%s()\n", __func__);
++	if (IS_ERR(phy) || !phy) {
++		dwc_info(pcd->usb3_dev, "NO PHY!!\n");
++		if (!IS_ERR(phy))
++			usb_put_phy(phy);
++		return;
++	}
++
++	otg = phy->otg;
++	if (!otg) {
++		dwc_info(pcd->usb3_dev, "NO OTG!!\n");
++		usb_put_phy(phy);
++		return;
++	}
++
++	otg_host_release(otg);
++	usb_put_phy(phy);
++}
++
++static int pcd_stop_peripheral(struct usb_gadget *gadget,
++			       struct usb_gadget_driver *driver)
++{
++	struct gadget_wrapper *d;
++	dwc_usb3_pcd_t *pcd;
++	unsigned long flags;
++	u32 temp;
++	int count = 0;
++
++	d = container_of(gadget, struct gadget_wrapper, gadget);
++	pcd = d->pcd;
++
++	spin_lock_irqsave(&pcd->lock, flags);
++
++	dwc_usb3_pcd_stop(pcd);
++
++	/* Disable device interrupts */
++	dwc_wr32(pcd->usb3_dev, &pcd->dev_global_regs->devten, 0);
++
++	/* Clear Run/Stop bit */
++	temp = dwc_rd32(pcd->usb3_dev, &pcd->dev_global_regs->dctl);
++	temp &= ~DWC_DCTL_RUN_STOP_BIT;
++	dwc_wr32(pcd->usb3_dev, &pcd->dev_global_regs->dctl, temp);
++
++	spin_unlock_irqrestore(&pcd->lock, flags);
++
++	/* Wait for core stopped */
++	do {
++		msleep(1);
++		temp = dwc_rd32(pcd->usb3_dev, &pcd->dev_global_regs->dsts);
++	} while (!(temp & DWC_DSTS_DEV_CTRL_HLT_BIT) && (++count < 30));
++
++	return 0;
++}
++
++static int pcd_start_peripheral(struct usb_gadget *gadget,
++				struct usb_gadget_driver *driver)
++{
++	struct gadget_wrapper *d;
++	dwc_usb3_pcd_t *pcd;
++	unsigned long flags;
++	u32 temp;
++
++	d = container_of(gadget, struct gadget_wrapper, gadget);
++	pcd = d->pcd;
++
++	spin_lock_irqsave(&pcd->lock, flags);
++
++	dwc_usb3_pcd_device_init(pcd->usb3_dev, 0, 0);
++
++	/* Enable Device mode interrupts */
++	dwc_usb3_enable_device_interrupts(pcd->usb3_dev);
++
++	/* Set Run/Stop bit, and Keep-Connect bit if hibernation enabled */
++	temp = dwc_rd32(pcd->usb3_dev, &pcd->dev_global_regs->dctl);
++	temp |= DWC_DCTL_RUN_STOP_BIT;
++
++	if (pcd->usb3_dev->core_params->hibernate &&
++	    (pcd->usb3_dev->hwparams1 & DWC_HWP1_EN_PWROPT_BITS) ==
++	    DWC_EN_PWROPT_HIBERNATION << DWC_HWP1_EN_PWROPT_SHIFT)
++		temp |= DWC_DCTL_KEEP_CONNECT_BIT;
++
++	dwc_wr32(pcd->usb3_dev, &pcd->dev_global_regs->dctl, temp);
++	pcd->wants_host = 0;
++
++	spin_unlock_irqrestore(&pcd->lock, flags);
++
++	return 0;
++}
++
++static int pcd_send_hrr(struct usb_gadget *gadget, int is_init)
++{
++	struct gadget_wrapper *d;
++	dwc_usb3_pcd_t *pcd;
++	unsigned long flags;
++	u32 param;
++
++	d = container_of(gadget, struct gadget_wrapper, gadget);
++	pcd = d->pcd;
++
++	spin_lock_irqsave(&pcd->lock, flags);
++
++	param = is_init ? DWC_DGCMDPAR_HOST_ROLE_REQ_INITIATE :
++		DWC_DGCMDPAR_HOST_ROLE_REQ_CONFIRM;
++	dwc_usb3_xmit_host_role_request(pcd, param);
++
++	spin_unlock_irqrestore(&pcd->lock, flags);
++
++	return 0;
++}
++
++#endif /* CONFIG_USB_OTG_DWC */
++
++/**
++ * This function returns the current USB frame number.
++ *
++ * @param gadget The gadget context.
++ */
++static int dwc_get_frame(struct usb_gadget *gadget)
++{
++	struct gadget_wrapper	*d;
++	dwc_usb3_pcd_t		*pcd;
++	dwc_usb3_device_t	*dev;
++	unsigned long		flags;
++	int			ret;
++
++#if defined(DEBUG) || defined(ISOC_DEBUG)
++	printk(KERN_DEBUG USB3_DWC "%s()\n", __func__);
++#endif
++	if (!gadget)
++		return -ENODEV;
++
++	d = container_of(gadget, struct gadget_wrapper, gadget);
++	pcd = d->pcd;
++	dev = pcd->usb3_dev;
++
++	spin_lock_irqsave(&pcd->lock, flags);
++	dwc_wait_if_hibernating(pcd, flags);
++	pcd->usb3_dev->hiber_cnt++;
++
++	ret = dwc_usb3_pcd_get_frame_number(pcd);
++
++	pcd->usb3_dev->hiber_cnt--;
++	spin_unlock_irqrestore(&pcd->lock, flags);
++	return ret;
++}
++
++/**
++ * This function sends a remote wakeup to the host.
++ *
++ * @param gadget The gadget context.
++ */
++int dwc_usb3_wakeup(struct usb_gadget *gadget)
++{
++	struct gadget_wrapper	*d;
++	dwc_usb3_pcd_t		*pcd;
++	dwc_usb3_device_t	*dev;
++	unsigned long		timeout, flags;
++	int			state;
++
++#if defined(DEBUG) || defined(ISOC_DEBUG)
++	printk(KERN_DEBUG USB3_DWC "%s()\n", __func__);
++#endif
++	if (!gadget)
++		return -ENODEV;
++
++	d = container_of(gadget, struct gadget_wrapper, gadget);
++	pcd = d->pcd;
++	dev = pcd->usb3_dev;
++
++	if (!pcd->remote_wakeup_enable) {
++		dwc_info(dev, "hardware not enabled for wakeup\n");
++		return -ENOTSUPP;
++	}
++
++	spin_lock_irqsave(&pcd->lock, flags);
++
++	if (dev->hibernate != DWC_HIBER_AWAKE) {
++		state = dwc_exit_hibernation(pcd, 1);
++		spin_unlock_irqrestore(&pcd->lock, flags);
++		printk(USB3_DWC "dwc_exit_hibernation() returned %d\n", state);
++		return 0;
++	}
++
++	dwc_wait_if_hibernating(pcd, flags);
++	pcd->usb3_dev->hiber_cnt++;
++
++	state = dwc_usb3_pcd_get_link_state(pcd);
++	pcd->link_state = state;
++	dwc_usb3_pcd_set_link_state(pcd, DWC_LINK_STATE_REQ_REMOTE_WAKEUP);
++	spin_unlock_irqrestore(&pcd->lock, flags);
++
++	dwc_info(dev, "link state before: %d\n", state);
++#if 0
++	/* Clear DCTL bits after 2 ms */
++	msleep(2);
++
++	spin_lock_irqsave(&pcd->lock, flags);
++	dwc_usb3_pcd_set_link_state(pcd, 0);
++	spin_unlock_irqrestore(&pcd->lock, flags);
++#endif
++	/* Wait 500 ms for link state to go to U0 */
++	timeout = jiffies + msecs_to_jiffies(500);
++
++	while (!time_after(jiffies, timeout)) {
++		spin_lock_irqsave(&pcd->lock, flags);
++		state = dwc_usb3_pcd_get_link_state(pcd);
++		pcd->link_state = state;
++		spin_unlock_irqrestore(&pcd->lock, flags);
++		if (state == DWC_LINK_STATE_U0)
++			break;
++		else
++			msleep(1);
++	}
++
++	dwc_info(dev, "link state after: %d\n", state);
++
++	if (state != DWC_LINK_STATE_U0) {
++		spin_lock_irqsave(&pcd->lock, flags);
++		pcd->usb3_dev->hiber_cnt--;
++		spin_unlock_irqrestore(&pcd->lock, flags);
++		return -ETIMEDOUT;
++	}
++
++	/* Send function remote wake notification */
++	spin_lock_irqsave(&pcd->lock, flags);
++	dwc_usb3_pcd_remote_wake(pcd, 0);
++	pcd->wkup_rdy = 0;
++	pcd->usb3_dev->hiber_cnt--;
++	spin_unlock_irqrestore(&pcd->lock, flags);
++	dwc_info(dev, "remote wake sent\n");
++
++	return 0;
++}
++
++static int dwc_usb3_pullup(struct usb_gadget *gadget, int is_on)
++{
++	return 0;
++}
++
++static const struct usb_gadget_ops pcd_ops = {
++	.get_frame	= dwc_get_frame,
++	.wakeup		= dwc_usb3_wakeup,
++	.pullup		= dwc_usb3_pullup,
++	// current versions must always be self-powered
++
++#ifdef CONFIG_USB_OTG_DWC
++	.udc_start	= pcd_start_peripheral,
++	.udc_stop	= pcd_stop_peripheral,
++
++	.send_hrr	= pcd_send_hrr,
++#endif
++};
++
++
++/*=======================================================================*/
++
++/**
++ * Initialize the Linux gadget specific parts of the default Control EP (EP0).
++ */
++static void gadget_init_ep0(dwc_usb3_pcd_t *pcd, struct gadget_wrapper *d)
++{
++	dwc_usb3_pcd_ep_t *pcd_ep;
++	struct usb_ep *ep0;
++
++	dwc_debug(pcd->usb3_dev, "%s()\n", __func__);
++
++	d->gadget.ep0 = &d->ep0.usb_ep;
++	INIT_LIST_HEAD(&d->gadget.ep0->ep_list);
++
++	pcd_ep = &d->ep0;
++	ep0 = &pcd_ep->usb_ep;
++	dwc_debug(pcd->usb3_dev, "ep0=%p\n", ep0);
++
++	INIT_LIST_HEAD(&pcd_ep->dwc_ep.queue);
++
++	/* Init the usb_ep structure */
++	ep0->name = d->ep_names[0];
++	ep0->ops = (struct usb_ep_ops *)&pcd_ep_ops;
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0)
++	ep0->maxpacket = DWC_MAX_EP0_SIZE;
++#else
++	usb_ep_set_maxpacket_limit(ep0, DWC_MAX_EP0_SIZE);
++#endif
++
++	dwc_debug(pcd->usb3_dev, "EP0 name=%s\n", ep0->name);
++	dwc_debug(pcd->usb3_dev, "ep0 eplist: %p(%p,%p) = %p(%p,%p)\n",
++		  &d->gadget.ep0->ep_list, d->gadget.ep0->ep_list.prev,
++		  d->gadget.ep0->ep_list.next, &ep0->ep_list,
++		  ep0->ep_list.prev, ep0->ep_list.next);
++}
++
++/**
++ * Initialize the Linux gadget specific parts of the non-EP0 EPs.
++ */
++static int gadget_init_eps(dwc_usb3_pcd_t *pcd, struct gadget_wrapper *d)
++{
++	dwc_usb3_pcd_ep_t *pcd_ep;
++	struct usb_ep *ep;
++	const char *name, *tmp, *ttmp;
++	int i, num, ep_in, ep_out;
++
++	dwc_debug(pcd->usb3_dev, "%s()\n", __func__);
++
++	INIT_LIST_HEAD(&d->gadget.ep_list);
++
++	for (i = 1, ep_in = 0, ep_out = 0; i < ARRAY_SIZE(d->ep_names); i++) {
++		name = d->ep_names[i];
++		if (!name || !name[0])
++			break;
++
++		/* Find '-' in e.g. "ep1in-bulk" */
++		tmp = strrchr(name, '-');
++		if (!tmp)
++			/* If no '-' then find end of string */
++			tmp = name + strlen(name);
++
++		/* If not 0-len string then back up 1 char */
++		if (tmp != name)
++			tmp--;
++
++		/* Get the EP number */
++		num = 0;
++		ttmp = tmp;
++
++		if (*tmp == 't') {
++			/* If "out", back up to the number before the 'o' */
++			if (tmp >= name + 3)
++				tmp -= 3;
++		} else if (*tmp == 'n') {
++			/* If "in", back up to the number before the 'i' */
++			if (tmp >= name + 2)
++				tmp -= 2;
++		}
++
++		if (isdigit(*tmp)) {
++			/* If numeric, handle 1 or 2 digits */
++			if (tmp > name && isdigit(*(tmp - 1)))
++				num = simple_strtol(tmp - 1, NULL, 10);
++			else
++				num = simple_strtol(tmp, NULL, 10);
++		}
++
++		dwc_debug(pcd->usb3_dev, "num=%d\n", num);
++		tmp = ttmp;
++		if (num < 1 || num >= DWC_MAX_EPS)
++			goto bad;
++
++		/* If e.g. "ep1" or "ep1out" then OUT ep */
++		if ((isdigit(*tmp) || *tmp == 't') && (ep_out < 2)) {
++			ep_out++;
++			pcd_ep = &d->out_ep[ep_out - 1];
++			ep = &pcd_ep->usb_ep;
++			dwc_debug(pcd->usb3_dev,
++				  "ep%d-OUT=%p name=%s phys=%d pcd_ep=%p\n",
++				  num, ep, name, ep_out, pcd_ep);
++			dwc_error(pcd->usb3_dev,
++				  "ep%d-OUT=%p name=%s phys=%d pcd_ep=%p\n",
++				  num, ep, name, ep_out, pcd_ep);
++
++			pcd_ep->dwc_ep.num = num;
++			INIT_LIST_HEAD(&pcd_ep->dwc_ep.queue);
++
++			/* Init the usb_ep structure */
++			ep->name = name;
++			ep->ops = (struct usb_ep_ops *)&pcd_ep_ops;
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0)
++			ep->maxpacket = DWC_MAX_PACKET_SIZE;
++#else
++			usb_ep_set_maxpacket_limit(ep, DWC_MAX_PACKET_SIZE);
++#endif
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,1,0)
++			ep->max_streams = 15;
++#else
++			ep->numstreams = 0;
++#endif
++			ep->mult = 0;
++			ep->maxburst = 0;
++
++			dwc_debug(pcd->usb3_dev,
++				"ep%d-OUT eplist pre: %p(%p,%p) = %p(%p,%p)\n",
++				num, &d->gadget.ep_list, d->gadget.ep_list.prev,
++				d->gadget.ep_list.next, &ep->ep_list,
++				ep->ep_list.prev, ep->ep_list.next);
++			list_add_tail(&ep->ep_list, &d->gadget.ep_list);
++			dwc_debug(pcd->usb3_dev,
++				"ep%d-OUT eplist post: %p(%p,%p) = %p(%p,%p)\n",
++				num, &d->gadget.ep_list, d->gadget.ep_list.prev,
++				d->gadget.ep_list.next, &ep->ep_list,
++				ep->ep_list.prev, ep->ep_list.next);
++		}
++
++		/* If e.g. "ep1" or "ep1in" then IN ep */
++		if ((isdigit(*tmp) || *tmp == 'n')&&(ep_in < 4)) {
++			ep_in++;
++			pcd_ep = &d->in_ep[ep_in - 1];
++			ep = &pcd_ep->usb_ep;
++			dwc_debug(pcd->usb3_dev,
++				"ep%d-IN=%p name=%s phys=%d pcd_ep=%p\n",
++				num, ep, name, ep_in, pcd_ep);
++			dwc_error(pcd->usb3_dev,
++				"ep%d-IN=%p name=%s phys=%d pcd_ep=%p\n",
++				num, ep, name, ep_in, pcd_ep);
++
++			pcd_ep->dwc_ep.num = num;
++			INIT_LIST_HEAD(&pcd_ep->dwc_ep.queue);
++			/* Init the usb_ep structure */
++			ep->name = name;
++			ep->ops = (struct usb_ep_ops *)&pcd_ep_ops;
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0)
++			ep->maxpacket = DWC_MAX_PACKET_SIZE;
++#else
++			usb_ep_set_maxpacket_limit(ep, DWC_MAX_PACKET_SIZE);
++#endif
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,1,0)
++			ep->max_streams = 15;
++#else
++			ep->numstreams = 0;
++#endif
++			ep->mult = 0;
++			ep->maxburst = 0;
++
++			dwc_debug(pcd->usb3_dev,
++				"ep%d-IN eplist pre: %p(%p,%p) = %p(%p,%p)\n",
++				num, &d->gadget.ep_list, d->gadget.ep_list.prev,
++				d->gadget.ep_list.next, &ep->ep_list,
++				ep->ep_list.prev, ep->ep_list.next);
++			list_add_tail(&ep->ep_list, &d->gadget.ep_list);
++			dwc_debug(pcd->usb3_dev,
++				"ep%d-IN eplist post: %p(%p,%p) = %p(%p,%p)\n",
++				num, &d->gadget.ep_list, d->gadget.ep_list.prev,
++				d->gadget.ep_list.next, &ep->ep_list,
++				ep->ep_list.prev, ep->ep_list.next);
++		}
++
++		if (!isdigit(*tmp) && *tmp != 't' && *tmp != 'n') {
++bad:
++			dwc_debug(pcd->usb3_dev, "ep%d ????\n", num);
++			return -EINVAL;
++		}
++	}
++
++	return 0;
++}
++
++/**
++ * Free any descriptor allocations made for each non-EP0 EP.
++ */
++static void gadget_free_ep_allocations(dwc_usb3_pcd_t *pcd,
++				       struct gadget_wrapper *d)
++{
++	dwc_usb3_pcd_ep_t *pcd_ep;
++	int i;
++
++	for (i = DWC_MAX_EPS - 1; i > 0; i--) {
++		pcd_ep = &d->in_ep[i - 1];
++		dwc_debug(pcd->usb3_dev, "physpair%d-IN=%p\n", i, pcd_ep);
++		dwc_usb3_pcd_trb_free(pcd_ep);
++
++		pcd_ep = &d->out_ep[i - 1];
++		dwc_debug(pcd->usb3_dev, "physpair%d-OUT=%p\n", i, pcd_ep);
++		dwc_usb3_pcd_trb_free(pcd_ep);
++	}
++}
++
++/**
++ * This function releases the Gadget device.
++ * Required by device_unregister().
++ *
++ * @param dev The device context.
++ */
++static void gadget_release(struct device *dev)
++{
++	/* @todo Should this do something? Should it free the PCD?
++	 */
++#if defined(DEBUG) || defined(ISOC_DEBUG)
++	printk(KERN_DEBUG USB3_DWC "%s()\n", __func__);
++#endif
++}
++
++
++#ifdef DWC_UTE
++/*=======================================================================*/
++/*
++ * UTE support functions
++ */
++
++/**
++ * Return the PCD pointer for a given gadget instance.
++ */
++dwc_usb3_pcd_t *dwc_usb3_get_pcd_instance(unsigned devnum)
++{
++	if (!gadget_wrapper) {
++		printk(KERN_WARNING USB3_DWC "%s null wrapper!\n", __func__);
++		return NULL;
++	}
++
++	return gadget_wrapper->pcd;
++}
++
++/**
++ * Set mapping of a USB EP to a physical EP, by changing the contents of the
++ * gadget instance's ep_names[] array.
++ */
++int dwc_usb3_set_usb_ep_map(unsigned devnum, unsigned phys_ep_num,
++			    unsigned usb_ep_num)
++{
++	unsigned usb_ep, usb_dir, usb_type;
++	char *dirstr, *typestr, *buf;
++	static char *ep_type_str[] = { "ctrl", "iso", "bulk", "int" };
++
++	if (!gadget_wrapper) {
++		printk(KERN_WARNING USB3_DWC "%s null wrapper!\n", __func__);
++		return -ENODEV;
++	}
++
++	/* Phys EP 0 & 1 cannot be remapped */
++	if (phys_ep_num < 2 || phys_ep_num >= DWC_MAX_PHYS_EP)
++		return -EINVAL;
++
++	/* ep_names[] has a single entry for both EP0 IN & OUT */
++	phys_ep_num--;
++
++	/* These fields are defined by UTE */
++	usb_ep = usb_ep_num & 0xf;
++	usb_dir = usb_ep_num >> 4 & 0x3;
++	usb_type = usb_ep_num >> 6 & 0x7;
++
++	/* Cannot remap the default Control EP */
++	if (usb_ep == 0)
++		return -EINVAL;
++
++	switch (usb_dir) {
++	case 0:
++		dirstr = "out";
++		break;
++	case 1:
++		dirstr = "in";
++		break;
++	default:
++		/* USB3 does not have bidirectional physical EPs */
++		return -EINVAL;
++	}
++
++	buf = gadget_wrapper->ep_names[phys_ep_num];
++
++	if (usb_type >= 4) {
++		snprintf(buf, sizeof(gadget_wrapper->ep_names[0]),
++			 "ep%u%s", usb_ep, dirstr);
++	} else {
++		typestr = ep_type_str[usb_type];
++		snprintf(buf, sizeof(gadget_wrapper->ep_names[0]),
++			 "ep%u%s-%s", usb_ep, dirstr, typestr);
++	}
++
++	return 0;
++}
++
++/**
++ * Get mapping of a USB EP to a physical EP, by reading the contents of the
++ * gadget instance's ep_names[] array.
++ */
++int dwc_usb3_get_usb_ep_map(unsigned devnum, unsigned phys_ep_num,
++			    unsigned *usb_ep_num_ret)
++{
++	unsigned usb_ep, usb_dir, usb_type;
++	char dirstr[16], typestr[16], *dashp, *buf;
++	int ret;
++
++	if (!gadget_wrapper) {
++		printk(KERN_WARNING USB3_DWC "%s null wrapper!\n", __func__);
++		return -ENODEV;
++	}
++
++	/* Phys EP 0 & 1 cannot be remapped */
++	if (phys_ep_num < 2 || phys_ep_num >= DWC_MAX_PHYS_EP)
++		return -EINVAL;
++
++	/* ep_names[] has a single entry for both EP0 IN & OUT */
++	phys_ep_num--;
++
++	buf = gadget_wrapper->ep_names[phys_ep_num];
++	printk("phys EP %d, config=\"%s\"\n", phys_ep_num, buf);
++	usb_ep=16;
++	dirstr[0] = 0;
++	typestr[0] = 0;
++	dashp = strchr(buf, '-');
++	if (dashp) {
++		*dashp = ' ';
++		ret = sscanf(buf, "ep%u%15s %15s", &usb_ep, dirstr, typestr);
++		*dashp = '-';
++		printk("sscanf() ret=%d\n", ret);
++		if (ret != 3)
++			return -EINVAL;
++	} else {
++		ret = sscanf(buf, "ep%u%15s", &usb_ep, dirstr);
++		printk("sscanf() ret=%d\n", ret);
++		if (ret != 2)
++			return -EINVAL;
++	}
++
++	if (usb_ep > 15)
++		return -ERANGE;
++
++	if (strcmp(dirstr, "out") == 0)
++		usb_dir = 0;
++	else if (strcmp(dirstr, "in") == 0)
++		usb_dir = 1;
++	else
++		return -ERANGE;
++
++	if (strcmp(typestr, "ctrl") == 0)
++		usb_type = 0;
++	else if (strcmp(typestr, "iso") == 0)
++		usb_type = 1;
++	else if (strcmp(typestr, "bulk") == 0)
++		usb_type = 2;
++	else if (strcmp(typestr, "int") == 0)
++		usb_type = 3;
++	else
++		usb_type = 4;
++
++	*usb_ep_num_ret = usb_ep | usb_dir << 4 | usb_type << 6;
++	return 0;
++}
++
++/**
++ * Activate the changes made by the UTE to the core's features.
++ */
++void dwc_usb3_ute_config(dwc_usb3_device_t *usb3_dev)
++{
++	dwc_usb3_pcd_t *pcd = &usb3_dev->pcd;
++	int i, cnt, txsz[DWC_MAX_TX_FIFOS];
++
++	dwc_debug(usb3_dev, "%s()\n", __func__);
++
++	if (!gadget_wrapper) {
++		dwc_warn(usb3_dev, "%s null wrapper!\n", __func__);
++		return;
++	}
++
++	if (pcd->ute_change) {
++		/* Free any remaining descriptor allocations made for
++		 * non-EP0 EPs
++		 */
++		gadget_free_ep_allocations(pcd, gadget_wrapper);
++
++		/* Set the Tx FIFO sizes */
++		for (i = 0, cnt = 0; i < pcd->num_in_eps + 1; i++) {
++			txsz[i] = pcd->txf_size[i];
++			if (txsz[i])
++				cnt++;
++		}
++		if (cnt)
++			dwc_usb3_set_tx_fifo_size(usb3_dev, txsz);
++
++		/* Set the Rx FIFO size */
++		if (pcd->rxf_size)
++			dwc_usb3_set_rx_fifo_size(usb3_dev, pcd->rxf_size);
++
++		/* Re-initialize non-EP0 EPs to pick up any mapping changes */
++		if (gadget_init_eps(pcd, gadget_wrapper)) {
++			dwc_error(usb3_dev, "%s, gadget_init_eps error!\n",
++				  __func__);
++		}
++
++		pcd->ute_change = 0;
++	}
++}
++
++/**
++ * Reset usb endpoint mapping to it's default state.
++ */
++int dwc_usb3_reset_usb_ep_map(unsigned devnum)
++{
++	struct gadget_wrapper *d;
++	dwc_usb3_pcd_t *pcd;
++	int i;
++
++	if (!gadget_wrapper) {
++		printk(KERN_WARNING USB3_DWC "%s null wrapper!\n", __func__);
++		return -ENODEV;
++	}
++
++	d = gadget_wrapper;
++	pcd = d->pcd;
++
++	for (i = 0; i < ARRAY_SIZE(g_ep_names) &&
++	     i < ARRAY_SIZE(d->ep_names) &&
++	     i < pcd->num_in_eps + pcd->num_out_eps + 1; i++) {
++		strncpy(d->ep_names[i], g_ep_names[i],
++			sizeof(d->ep_names[0]) - 1);
++		d->ep_names[i][sizeof(d->ep_names[0]) - 1] = 0;
++		dwc_debug(pcd->usb3_dev, "~phys EP%d name=%s\n", i, d->ep_names[i]);
++	}
++
++	return gadget_init_eps(pcd, d);
++}
++
++int dwc_usb3_switch_speed(unsigned devnum, int speed)
++{
++	int ret = 0;
++	struct gadget_wrapper *d;
++	dwc_usb3_pcd_t *pcd;
++	dwc_usb3_device_t *usb3_dev;
++	//u32 temp;
++
++	if (!gadget_wrapper) {
++		printk(KERN_WARNING USB3_DWC "%s null wrapper!\n", __func__);
++		return -ENODEV;
++	}
++
++	d = gadget_wrapper;
++	pcd = d->pcd;
++	usb3_dev = pcd->usb3_dev;
++	/*
++	temp = dwc_rd32(usb3_dev, &pcd->dev_global_regs->dctl);
++	temp &= ~DWC_DCTL_RUN_STOP_BIT;
++	dwc_wr32(usb3_dev, &pcd->dev_global_regs->dctl, temp);
++
++	dwc_udelay(usb3_dev, 1500); */
++	/* Soft-reset the core */
++	/* temp = dwc_rd32(usb3_dev, &pcd->dev_global_regs->dctl);
++	temp &= ~DWC_DCTL_RUN_STOP_BIT;
++	temp |= DWC_DCTL_CSFT_RST_BIT;
++	dwc_wr32(usb3_dev, &pcd->dev_global_regs->dctl, temp); */
++
++	/* Wait for core to come out of reset */
++	/* do {
++		dwc_udelay(usb3_dev, 1);
++		temp = dwc_rd32(usb3_dev, &pcd->dev_global_regs->dctl);
++	} while (temp & DWC_DCTL_CSFT_RST_BIT);
++
++	dwc_mdelay(usb3_dev, 2); */
++
++	if (speed == 3) {
++		/* Set device speed feature to Super Speed */
++		speed = 0;
++	}
++	usb3_dev->core_params->usb2mode = speed;
++
++	dwc_usb3_pcd_device_init(usb3_dev, 1, 0);
++
++	return ret;
++}
++
++int dwc_usb3_get_dev_speed(unsigned devnum)
++{
++	struct gadget_wrapper *d;
++	dwc_usb3_pcd_t *pcd;
++	int ret;
++
++	if (!gadget_wrapper) {
++		printk(KERN_WARNING USB3_DWC "%s null wrapper!\n", __func__);
++		return -ENODEV;
++	}
++
++	d = gadget_wrapper;
++	pcd = d->pcd;
++
++	ret = pcd->usb3_dev->core_params->usb2mode;
++	if (ret == 0) {
++		/* If speed feature is set to Super Speed */
++		ret = 3;
++	}
++	return ret;
++}
++
++#endif /* DWC_UTE */
++
++/**
++ * This function initializes the Gadget portion of the driver.
++ *
++ * @param usb3_dev Programming view of DWC_usb3 controller.
++ * @param dev      The device context.
++ */
++int dwc_usb3_gadget_init(dwc_usb3_device_t *usb3_dev, struct device *dev)
++{
++	dwc_usb3_pcd_t *pcd = &usb3_dev->pcd;
++	int retval = -ENOMEM;
++	int hiberbufs = 0;
++	dma_addr_t dma_addr = 0;
++	int i;
++
++	dwc_debug(usb3_dev, "%s()\n", __func__);
++	dwc_debug(usb3_dev, "pcd=%p\n", pcd);
++
++	gadget_wrapper = kmalloc(sizeof(struct gadget_wrapper), GFP_KERNEL);
++	if (!gadget_wrapper)
++		goto out1;
++
++	memset(gadget_wrapper, 0, sizeof(*gadget_wrapper));
++	gadget_wrapper->pcd = pcd;
++
++	for (i = 0; i < ARRAY_SIZE(g_ep_names) &&
++	     i < ARRAY_SIZE(gadget_wrapper->ep_names) &&
++	     i < pcd->num_in_eps + pcd->num_out_eps + 1; i++) {
++		strncpy(gadget_wrapper->ep_names[i], g_ep_names[i],
++			sizeof(gadget_wrapper->ep_names[0]) - 1);
++		gadget_wrapper->ep_names[i][sizeof(gadget_wrapper->ep_names[0]) - 1] = 0;
++		dwc_debug(usb3_dev, "~phys EP%d name=%s\n", i,
++			  gadget_wrapper->ep_names[i]);
++	}
++
++	gadget_wrapper->gadget.name = "dwc_usb3_pcd";
++	dwc_debug(usb3_dev, "gadget.name=%s\n", gadget_wrapper->gadget.name);
++
++#ifdef CONFIG_USB_OTG_DWC
++	gadget_wrapper->gadget.is_otg = 1;
++#endif
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
++	strcpy(gadget_wrapper->gadget.dev.bus_id, "gadget");
++#else
++	dev_set_name(&gadget_wrapper->gadget.dev, "%s", "gadget");
++#endif
++	gadget_wrapper->gadget.dev.parent = dev;
++	gadget_wrapper->gadget.dev.release = gadget_release;
++	gadget_wrapper->gadget.speed = USB_SPEED_UNKNOWN;
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(3,3,0)
++	gadget_wrapper->gadget.is_dualspeed = 1;
++#else
++	gadget_wrapper->gadget.max_speed = USB_SPEED_SUPER;
++#endif
++	gadget_wrapper->gadget.ops = &pcd_ops;
++	gadget_wrapper->driver = NULL;
++	dwc_debug(usb3_dev, "gadget=%p ops=%p\n", &gadget_wrapper->gadget,
++		  gadget_wrapper->gadget.ops);
++
++	/* Set the PCD's EP0 request pointer to the wrapper's request */
++	pcd->ep0_req = &gadget_wrapper->ep0_req;
++
++	/* Set the PCD's EP array pointers to the wrapper's EPs */
++	pcd->ep0 = &gadget_wrapper->ep0;
++	for (i = 0; i < DWC_MAX_EPS - 1; i++) {
++		pcd->out_ep[i] = &gadget_wrapper->out_ep[i];
++		pcd->in_ep[i] = &gadget_wrapper->in_ep[i];
++	}
++
++	/* Allocate the EP0 packet buffers */
++	pcd->ep0_setup_pkt = dma_alloc_coherent(NULL,
++			sizeof(*pcd->ep0_setup_pkt) * 5,
++			&pcd->ep0_setup_pkt_dma, GFP_KERNEL | GFP_DMA32);
++	if (!pcd->ep0_setup_pkt)
++		goto out2;
++
++	pcd->ep0_status_buf = dma_alloc_coherent(NULL, DWC_STATUS_BUF_SIZE,
++			 &pcd->ep0_status_buf_dma, GFP_KERNEL | GFP_DMA32);
++	if (!pcd->ep0_status_buf)
++		goto out3;
++
++	/* Allocate the EP0 DMA descriptors */
++	pcd->ep0_setup_desc = dma_alloc_coherent(NULL,
++			 sizeof(dwc_usb3_dma_desc_t), &pcd->ep0_setup_desc_dma,
++			 GFP_KERNEL | GFP_DMA32);
++	if (!pcd->ep0_setup_desc)
++		goto out4;
++
++	pcd->ep0_in_desc = dma_alloc_coherent(NULL, sizeof(dwc_usb3_dma_desc_t),
++			&pcd->ep0_in_desc_dma, GFP_KERNEL | GFP_DMA32);
++	if (!pcd->ep0_in_desc)
++		goto out5;
++
++	pcd->ep0_out_desc = dma_alloc_coherent(NULL,
++			sizeof(dwc_usb3_dma_desc_t), &pcd->ep0_out_desc_dma,
++			GFP_KERNEL | GFP_DMA32);
++	if (!pcd->ep0_out_desc)
++		goto out6;
++
++	/* If hibernation is supported */
++	if (usb3_dev->core_params->hibernate &&
++	    (usb3_dev->hwparams1 & DWC_HWP1_EN_PWROPT_BITS) ==
++	    DWC_EN_PWROPT_HIBERNATION << DWC_HWP1_EN_PWROPT_SHIFT) {
++		hiberbufs = usb3_dev->hwparams4 >> DWC_HWP4_HIBER_SPAD_SHIFT &
++			DWC_HWP4_HIBER_SPAD_BITS >> DWC_HWP4_HIBER_SPAD_SHIFT;
++		if (hiberbufs) {
++			/* Allocate scratch buffer pointer array */
++			pcd->hiber_scratchpad_array =
++				dma_alloc_coherent(NULL,
++					sizeof(*pcd->hiber_scratchpad_array),
++					&pcd->hiber_scratchpad_array_dma,
++					GFP_KERNEL | GFP_DMA32);
++			if (!pcd->hiber_scratchpad_array) {
++				dwc_debug(usb3_dev,
++				      "%s hibernation array allocation error\n",
++				      __func__);
++				goto out7;
++			}
++		}
++
++		/* Allocate scratch buffers */
++		for (i = 0; i < hiberbufs; i++) {
++			pcd->hiber_scratchpad[i] =
++				dma_alloc_coherent(NULL, 4096, &dma_addr,
++						   GFP_KERNEL | GFP_DMA32);
++			if (!pcd->hiber_scratchpad[i]) {
++				dwc_debug(usb3_dev,
++					"%s hibernation buf allocation error\n",
++					__func__);
++				while (i-- > 0) {
++					dma_addr = (dma_addr_t)pcd->
++						hiber_scratchpad_array->dma_addr[i];
++					dma_free_coherent(NULL, 4096,
++						pcd->hiber_scratchpad[i],
++						dma_addr);
++					pcd->hiber_scratchpad[i] = NULL;
++				}
++
++				goto out8;
++			}
++
++			pcd->hiber_scratchpad_array->dma_addr[i] = (u64)dma_addr;
++		}
++	}
++
++	/* Initialize all the EP structures */
++	gadget_init_ep0(pcd, gadget_wrapper);
++	retval = gadget_init_eps(pcd, gadget_wrapper);
++	if (retval) {
++		dwc_debug(usb3_dev, "%s gadget_init_eps error\n", __func__);
++		goto out9;
++	}
++
++	/* Register the gadget device */
++	retval = device_register(&gadget_wrapper->gadget.dev);
++	if (retval) {
++		dwc_debug(usb3_dev, "%s cannot register gadget device\n",
++			  __func__);
++		goto out10;
++	}
++
++	return 0;
++
++out10:
++	gadget_free_ep_allocations(pcd, gadget_wrapper);
++out9:
++	for (i = hiberbufs - 1; i >= 0; i--) {
++		if (pcd->hiber_scratchpad[i]) {
++			dma_addr = (dma_addr_t)
++				pcd->hiber_scratchpad_array->dma_addr[i];
++			dma_free_coherent(NULL, 4096, pcd->hiber_scratchpad[i],
++					  dma_addr);
++			pcd->hiber_scratchpad[i] = NULL;
++		}
++	}
++out8:
++	if (hiberbufs)
++		dma_free_coherent(NULL, sizeof(*pcd->hiber_scratchpad_array),
++				  pcd->hiber_scratchpad_array,
++				  pcd->hiber_scratchpad_array_dma);
++out7:
++	dma_free_coherent(NULL, sizeof(dwc_usb3_dma_desc_t), pcd->ep0_out_desc,
++			  pcd->ep0_out_desc_dma);
++out6:
++	dma_free_coherent(NULL, sizeof(dwc_usb3_dma_desc_t), pcd->ep0_in_desc,
++			  pcd->ep0_in_desc_dma);
++out5:
++	dma_free_coherent(NULL, sizeof(dwc_usb3_dma_desc_t),
++			  pcd->ep0_setup_desc, pcd->ep0_setup_desc_dma);
++out4:
++	dma_free_coherent(NULL, DWC_STATUS_BUF_SIZE, pcd->ep0_status_buf,
++			  pcd->ep0_status_buf_dma);
++out3:
++	dma_free_coherent(NULL, sizeof(*pcd->ep0_setup_pkt) * 5,
++			  pcd->ep0_setup_pkt, pcd->ep0_setup_pkt_dma);
++out2:
++	kfree(gadget_wrapper);
++	gadget_wrapper = NULL;
++out1:
++	return retval;
++}
++
++/**
++ * Cleanup the Gadget.
++ *
++ * @param usb3_dev Programming view of DWC_usb3 controller.
++ * @param dev      The device context.
++ */
++void dwc_usb3_gadget_remove(dwc_usb3_device_t *usb3_dev, struct device *dev)
++{
++	dwc_usb3_pcd_t *pcd = &usb3_dev->pcd;
++	int hiberbufs, i;
++	void *addr;
++	dma_addr_t dma_addr;
++
++	dwc_debug(usb3_dev, "%s()\n", __func__);
++	dwc_debug(usb3_dev, "pcd=%p\n", pcd);
++
++	if (!gadget_wrapper) {
++		dwc_warn(usb3_dev, "%s null wrapper!\n", __func__);
++		return;
++	}
++
++	/* start with the driver above us */
++	if (gadget_wrapper->driver) {
++		/* should have been done already by driver model core */
++		dwc_warn(usb3_dev, "driver '%s' is still registered!\n",
++			 gadget_wrapper->driver->driver.name);
++		usb_gadget_unregister_driver(gadget_wrapper->driver);
++	}
++
++	device_unregister(&gadget_wrapper->gadget.dev);
++	gadget_free_ep_allocations(pcd, gadget_wrapper);
++
++	/* If hibernation is supported */
++	if (usb3_dev->core_params->hibernate &&
++	    (usb3_dev->hwparams1 & DWC_HWP1_EN_PWROPT_BITS) ==
++	    DWC_EN_PWROPT_HIBERNATION << DWC_HWP1_EN_PWROPT_SHIFT) {
++		hiberbufs = usb3_dev->hwparams4 >> DWC_HWP4_HIBER_SPAD_SHIFT &
++			DWC_HWP4_HIBER_SPAD_BITS >> DWC_HWP4_HIBER_SPAD_SHIFT;
++
++		/* Free hibernation scratch buffers */
++		for (i = hiberbufs - 1; i >= 0; i--) {
++			addr = pcd->hiber_scratchpad[i];
++			dma_addr = (dma_addr_t)pcd->hiber_scratchpad_array->dma_addr[i];
++			pcd->hiber_scratchpad[i] = NULL;
++			if (addr)
++				dma_free_coherent(NULL, 4096, addr, dma_addr);
++		}
++
++		if (hiberbufs)
++			dma_free_coherent(NULL,
++					  sizeof(*pcd->hiber_scratchpad_array),
++					  pcd->hiber_scratchpad_array,
++					  pcd->hiber_scratchpad_array_dma);
++	}
++
++	dma_free_coherent(NULL, sizeof(dwc_usb3_dma_desc_t), pcd->ep0_out_desc,
++			  pcd->ep0_out_desc_dma);
++	dma_free_coherent(NULL, sizeof(dwc_usb3_dma_desc_t), pcd->ep0_in_desc,
++			  pcd->ep0_in_desc_dma);
++	dma_free_coherent(NULL, sizeof(dwc_usb3_dma_desc_t), pcd->ep0_setup_desc,
++			  pcd->ep0_setup_desc_dma);
++	dma_free_coherent(NULL, DWC_STATUS_BUF_SIZE, pcd->ep0_status_buf,
++			  pcd->ep0_status_buf_dma);
++	dma_free_coherent(NULL, sizeof(*pcd->ep0_setup_pkt) * 5,
++			  pcd->ep0_setup_pkt, pcd->ep0_setup_pkt_dma);
++
++	kfree(gadget_wrapper);
++	gadget_wrapper = NULL;
++}
++
++/**
++ * This function registers a gadget driver with the PCD.
++ *
++ * When a driver is successfully registered, it will receive control
++ * requests including set_configuration(), which enables non-control
++ * requests. Then usb traffic follows until a disconnect is reported.
++ * Then a host may connect again, or the driver might get unbound.
++ *
++ * @param driver The driver being registered.
++ * @param bind   The gadget driver's bind function.
++ */
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)
++int usb_gadget_register_driver(struct usb_gadget_driver *driver)
++#else
++int usb_gadget_probe_driver(struct usb_gadget_driver *driver
++# if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)
++			    , int (*bind)(struct usb_gadget *)
++# endif
++			   )
++#endif
++{
++	dwc_usb3_pcd_t *pcd;
++	int retval = -ENODEV;
++#ifdef CONFIG_USB_OTG_DWC
++	struct usb_phy *phy;
++	struct usb_otg *otg;
++#endif
++
++	printk(KERN_DEBUG USB3_DWC "%s(%p)\n", __func__, driver);
++	printk(KERN_DEBUG USB3_DWC "gdt_wrp=%p\n", gadget_wrapper);
++
++	if (!gadget_wrapper)
++		goto out;
++
++	pcd = gadget_wrapper->pcd;
++	printk(KERN_DEBUG USB3_DWC "pcd=%p\n", pcd);
++
++	if (!pcd) {
++		printk(KERN_DEBUG USB3_DWC "ENODEV\n");
++		goto out;
++	}
++
++	if (!driver ||
++#if LINUX_VERSION_CODE < KERNEL_VERSION(3,3,0)
++	    driver->speed == USB_SPEED_UNKNOWN ||
++#else
++	    driver->max_speed == USB_SPEED_UNKNOWN ||
++#endif
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37) || \
++    LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
++	    !driver->bind ||
++#endif
++	    !driver->unbind ||
++	    !driver->disconnect || !driver->setup) {
++		printk(KERN_DEBUG USB3_DWC "EINVAL\n");
++		retval = -EINVAL;
++		goto out;
++	}
++
++	printk(KERN_DEBUG USB3_DWC "registering gadget driver '%s'\n",
++	       driver->driver.name);
++
++	if (gadget_wrapper->driver) {
++		printk(KERN_DEBUG USB3_DWC "EBUSY (%p)\n",
++		       gadget_wrapper->driver);
++		retval = -EBUSY;
++		goto out;
++	}
++
++#ifdef CONFIG_USB_OTG_DWC
++	/* Check that the otg transceiver driver is loaded */
++	phy = usb_get_phy(USB_PHY_TYPE_USB3);
++	if (IS_ERR(phy) || !phy) {
++		printk(KERN_DEBUG USB3_DWC "OTG PHY not available!\n");
++		if (!IS_ERR(phy))
++			usb_put_phy(phy);
++		goto out;
++	}
++
++	otg = phy->otg;
++	usb_put_phy(phy);
++	if (!otg) {
++		printk(KERN_DEBUG USB3_DWC "OTG not available!\n");
++		goto out;
++	}
++#endif
++
++	/* hook up the driver */
++	gadget_wrapper->driver = driver;
++	gadget_wrapper->gadget.dev.driver = &driver->driver;
++	pcd->gadget = &gadget_wrapper->gadget;
++
++	dwc_debug(pcd->usb3_dev, "bind to driver %s\n", driver->driver.name);
++	dwc_debug(pcd->usb3_dev, "&gadget_gadget_wrapper->gadget = %p\n",
++		  &gadget_wrapper->gadget);
++	dwc_debug(pcd->usb3_dev, "gadget_gadget_wrapper->driver = %p\n",
++		  gadget_wrapper->driver);
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)
++	retval = driver->bind(&gadget_wrapper->gadget);
++#else
++# if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
++	retval = driver->bind(&gadget_wrapper->gadget,
++			      gadget_wrapper->driver);
++# else
++	retval = bind(&gadget_wrapper->gadget);
++# endif
++#endif
++	if (retval) {
++		dwc_error(pcd->usb3_dev, "bind to driver %s --> error %d\n",
++			  driver->driver.name, retval);
++		gadget_wrapper->driver = NULL;
++		gadget_wrapper->gadget.dev.driver = NULL;
++		pcd->gadget = NULL;
++		goto out;
++	}
++
++#ifdef CONFIG_USB_OTG_DWC
++	phy = usb_get_phy(USB_PHY_TYPE_USB3);
++	if (!IS_ERR(phy)) {
++		if (phy && phy->otg)
++			otg_set_peripheral(phy->otg, &gadget_wrapper->gadget);
++		usb_put_phy(phy);
++	}
++#endif
++
++	printk(KERN_DEBUG USB3_DWC "registered gadget driver '%s'\n",
++	       driver->driver.name);
++out:
++#ifdef CONFIG_USB_OTG_DWC
++	/* Switch otg to host mode now that gadget is bound */
++	phy = usb_get_phy(USB_PHY_TYPE_USB3);
++	if (!IS_ERR(phy)) {
++		if (phy && phy->otg)
++			dwc_otg3_set_peripheral(phy->otg, 0);
++		usb_put_phy(phy);
++	}
++#endif
++	return retval;
++}
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)
++EXPORT_SYMBOL_GPL(usb_gadget_register_driver);
++#else
++EXPORT_SYMBOL_GPL(usb_gadget_probe_driver);
++#endif
++
++/**
++ * This function unregisters a gadget driver
++ *
++ * @param driver The driver being unregistered.
++ */
++int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
++{
++#ifdef CONFIG_USB_OTG_DWC
++	struct usb_phy *phy;
++	struct usb_otg *otg;
++#endif
++
++	printk(KERN_DEBUG USB3_DWC "%s(%p)\n", __func__, driver);
++	printk(KERN_DEBUG USB3_DWC "unregistering gadget driver '%s'\n",
++	       driver->driver.name);
++
++	if (!gadget_wrapper)
++		return -ENODEV;
++
++	if (!gadget_wrapper->pcd) {
++		printk(KERN_DEBUG USB3_DWC "%s Return(%d): pcd==NULL\n",
++		       __func__, -ENODEV);
++		return -ENODEV;
++	}
++
++	if (!gadget_wrapper->driver || driver != gadget_wrapper->driver) {
++		printk(KERN_DEBUG USB3_DWC "%s Return(%d): driver?\n",
++		       __func__, -EINVAL);
++		return -EINVAL;
++	}
++
++#ifdef CONFIG_USB_OTG_DWC
++	phy = usb_get_phy(USB_PHY_TYPE_USB3);
++	otg = phy->otg;
++	otg_set_peripheral(otg, NULL);
++	usb_put_phy(phy);
++#endif
++
++	driver->disconnect(&gadget_wrapper->gadget);
++	driver->unbind(&gadget_wrapper->gadget);
++	gadget_wrapper->driver = NULL;
++	gadget_wrapper->gadget.dev.driver = NULL;
++	gadget_wrapper->pcd->gadget = NULL;
++
++	printk(KERN_DEBUG USB3_DWC "unregistered gadget driver '%s'\n",
++	       driver->driver.name);
++	return 0;
++}
++EXPORT_SYMBOL_GPL(usb_gadget_unregister_driver);
++
++//#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0)
++int udc_attach_driver(const char *name, struct usb_gadget_driver *driver)
++{
++	return 0;
++}
++EXPORT_SYMBOL_GPL(udc_attach_driver);
++//#endif
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,15,0)
++void usb_gadget_set_state(struct usb_gadget *gadget,
++		enum usb_device_state state)
++{
++	gadget->state = state;
++}
++EXPORT_SYMBOL_GPL(usb_gadget_set_state);
++#endif
++
++MODULE_DESCRIPTION(DWC_DRIVER_DESC);
++MODULE_AUTHOR("Synopsys Inc.");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/usb/gadget/udc/hiudc3/linux_hiber.c b/drivers/usb/gadget/udc/hiudc3/linux_hiber.c
+new file mode 100644
+index 0000000..8e77e97
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc3/linux_hiber.c
+@@ -0,0 +1,282 @@
++/** @file
++ */
++
++#include "os_defs.h"
++#include "hw.h"
++#include "usb.h"
++#include "pcd.h"
++#include "dev.h"
++#include "os_dev.h"
++#include "cil.h"
++
++void dwc_usb3_task_schedule(struct tasklet_struct *tasklet)
++{
++	tasklet_schedule(tasklet);
++}
++
++/**
++ * Helper routine for dwc_wait_pme_thread()
++ */
++static void dwc_wait_for_link_up(dwc_usb3_pcd_t *pcd)
++{
++	unsigned long flags;
++	u32 state;
++	int count = 5;
++
++	while (count-- > 0) {
++		msleep(20);
++		spin_lock_irqsave(&pcd->lock, flags);
++		state = dwc_usb3_pcd_get_link_state(pcd);
++		pcd->link_state = state;
++		if (state == DWC_LINK_STATE_U0) {
++			dwc_debug(pcd->usb3_dev,
++				  "Exiting from hibernation 2\n");
++			pcd->usb3_dev->hiber_wait_connect = 0;
++
++			/* Perform the steps in Section 9.1.3 "Initialization on
++			 * Connect Done" in [DWSS].
++			 */
++			dwc_usb3_handle_connect_done_intr(pcd);
++			dwc_exit_hibernation_after_connect(pcd, 0);
++			count = 0;
++		}
++
++		spin_unlock_irqrestore(&pcd->lock, flags);
++	}
++}
++
++/**
++ * Kernel thread that monitors the usb3_dev->hibernate variable. usb3_dev->
++ * hibernate is set to 1 or 2 from the interrupt handler when the core is
++ * requesting to enter hibernation. This thread checks whether it is safe to
++ * do so (usb3_dev->hiber_cnt == 0) and then sets usb3_dev->hibernate to 3 and
++ * puts the core into hibernation. usb3_dev->hibernate >= 3 tells the rest of
++ * the driver that it cannot access the hardware.
++ *
++ * This thread also handles some housekeeping work that must be done after the
++ * core has exited from hibernation.
++ *
++ * Note that this is NOT the way a "real" device would enter hibernation. This
++ * code is ONLY for testing hibernation on the Synopsys HAPS platform.
++ */
++int dwc_wait_pme_thread(void *data)
++{
++	dwc_usb3_pcd_t *pcd = (dwc_usb3_pcd_t *)data;
++	dwc_usb3_device_t *dev = pcd->usb3_dev;
++	unsigned long flags;
++	u32 state, temp;
++	int i;
++	int cnt = 0;
++
++	dwc_debug(dev, "%s(%p)\n", __func__, data);
++
++	/* Allow the thread to be killed by a signal, but set the signal mask
++	 * to block everything but INT, TERM, KILL, and USR1. */
++	allow_signal(SIGINT);
++	allow_signal(SIGTERM);
++	allow_signal(SIGKILL);
++	allow_signal(SIGUSR1);
++
++	set_user_nice(current, -10);
++
++	/* Allow the thread to be frozen */
++	set_freezable();
++
++	for (;;) {
++		spin_lock_irqsave(&pcd->lock, flags);
++		state = dev->hibernate;
++
++		if (dev->hiber_cnt == 0) {
++			if (state == DWC_HIBER_ENTER_NOSAVE ||
++			    state == DWC_HIBER_ENTER_SAVE) {
++				dwc_enter_hibernation(pcd,
++						state == DWC_HIBER_ENTER_SAVE);
++				state = DWC_HIBER_SLEEPING;
++			}
++		}
++
++		if (state != DWC_HIBER_SLEEPING && dev->snpsid >= 0x5533230a &&
++							dev->hiber_wait_u0) {
++			/* Handle waiting for U0 after requesting link state
++			 * RECOVERY, because we don't have the link state
++			 * change event enabled. We also do this in
++			 * dwc_usb3_irq() in case an event comes first.
++			 */
++			temp = dwc_usb3_pcd_get_link_state(pcd);
++			pcd->link_state = temp;
++
++			if (cnt-- == 0) {
++				cnt = 500;
++				dwc_debug1(pcd->usb3_dev,
++					   "thread WAIT_U0 state=%d\n", temp);
++			}
++
++			if (temp == DWC_LINK_STATE_U0) {
++				dwc_debug0(dev,
++					   "thread WAIT_U0 setting speed\n");
++				pcd->speed = dwc_usb3_get_device_speed(pcd);
++				if (pcd->remote_wakeup_enable)
++					dwc_usb3_pcd_remote_wake(pcd, 0);
++				dev->hiber_wait_u0 = 0;
++			}
++		}
++
++		if (state == DWC_HIBER_WAIT_LINK_UP) {
++			dev->hibernate = DWC_HIBER_AWAKE;
++			state = DWC_HIBER_AWAKE;
++			spin_unlock_irqrestore(&pcd->lock, flags);
++			dwc_wait_for_link_up(pcd);
++			spin_lock_irqsave(&pcd->lock, flags);
++		}
++
++		if (state == DWC_HIBER_SS_DIS_QUIRK) {
++			for (i = 0; i < 500; i++) {
++				if (dev->hibernate != DWC_HIBER_SS_DIS_QUIRK) {
++					dwc_info(dev,
++						 "breaking loop after %d ms\n",
++						 i);
++					break;
++				}
++
++				spin_unlock_irqrestore(&pcd->lock, flags);
++				msleep(1);
++				spin_lock_irqsave(&pcd->lock, flags);
++			}
++
++			if (dev->hibernate == DWC_HIBER_SS_DIS_QUIRK) {
++				temp = dwc_usb3_pcd_get_link_state(pcd);
++				pcd->link_state = temp;
++				if (temp == DWC_LINK_STATE_SS_DIS)
++					dwc_enter_hibernation(pcd, 0);
++				else
++					dev->hibernate = DWC_HIBER_AWAKE;
++			}
++		}
++
++		spin_unlock_irqrestore(&pcd->lock, flags);
++		if (kthread_should_stop())
++			break;
++		msleep(1);
++	}
++
++	return 0;
++}
++
++/**
++ * Fake PME interrupt handler, called from dwc_usb3_irq() in cil_intr.c if
++ * the core is in hibernation and any interrupt is received. The custom PCIe
++ * "gasket" on the HAPS platform generates an interrupt when the core requests
++ * to exit hibernation.
++ *
++ * This function reads the Debug register at offset 16 in the gasket, to make
++ * sure the core is requesting to exit hibernation. If so, it brings the core
++ * out of hibernation.
++ *
++ * Note that this is NOT the way a "real" device would exit hibernation. This
++ * code is ONLY for testing hibernation on the Synopsys HAPS platform.
++ */
++int dwc_usb3_handle_pme_intr(dwc_usb3_device_t *dev)
++{
++	u32 temp, test1, test2;
++	u8 __iomem *base_addr;
++	int ret;
++
++	dwc_debug(dev, "%s()\n", __func__);
++
++	if (dev->gasket_base)
++		base_addr = (u8 __iomem *)dev->gasket_base;
++	else
++		base_addr = (u8 __iomem *)dev->base + dev->gasket_ofs;
++
++	if ((dev->hwparams3 & DWC_HWP3_SSPHY_IFC_BITS) == 0) {
++		test1 = 0x40;
++		test2 = 0x80;
++	} else {
++		test1 = 0x44;
++		test2 = 0x88;
++	}
++
++	temp = dwc_rd32(dev, (volatile u32 __iomem *)(base_addr + 16));
++	if ((temp & test1) != 0) {
++		dwc_debug(dev, "calling dwc_exit_hibernation() Debug=%01x\n",
++			  temp);
++		ret = dwc_exit_hibernation(&dev->pcd, (temp & test2) != 0);
++		if (ret)
++			dwc_debug(dev, "dwc_exit_hibernation() returned %d\n",
++				  ret);
++	}
++
++	return 1;
++}
++
++/**
++ * Routine to enable and disable power to the core. The custom PCIe "gasket" on
++ * the HAPS platform provides this capability through the R1 register at offset
++ * 4.
++ *
++ * Note that this is NOT the way a "real" device would control the power. This
++ * code is ONLY for testing hibernation on the Synopsys HAPS platform.
++ */
++void dwc_usb3_power_ctl(dwc_usb3_device_t *dev, int on)
++{
++	u32 temp, test;
++	u8 __iomem *base_addr;
++	int cnt;
++
++	dwc_debug(dev, "%s(%1x)\n", __func__, on);
++
++	if (dev->gasket_base)
++		base_addr = (u8 __iomem *)dev->gasket_base;
++	else
++		base_addr = (u8 __iomem *)dev->base + dev->gasket_ofs;
++
++	if ((dev->hwparams3 & DWC_HWP3_SSPHY_IFC_BITS) == 0)
++		test = 0x30;
++	else
++		test = 0x33;
++
++	if (on) {
++		temp = dwc_rd32(dev, (volatile u32 __iomem *)(base_addr + 4));
++		dwc_debug(dev, "R1=%01x before write\n", temp);
++		temp &= ~0x3000;
++		dwc_wr32(dev, (volatile u32 __iomem *)(base_addr + 4), temp);
++		temp = dwc_rd32(dev, (volatile u32 __iomem *)(base_addr + 4));
++		dwc_debug(dev, "R1=%01x after write\n", temp);
++
++		/* Wait until both PMUs confirm that they have entered D0 */
++		dwc_debug(dev, "Asked for D0 state, waiting for response\n");
++		cnt = 0;
++		do {
++			udelay(1);
++			temp = dwc_rd32(dev, (volatile u32 __iomem *)
++					(base_addr + 16));
++			if (++cnt > 10000000) {
++				cnt = 0;
++				dwc_debug(dev, "%01x\n", temp);
++				//break;
++			}
++		} while ((temp & test) != 0);
++	} else {
++		temp = dwc_rd32(dev, (volatile u32 __iomem *)(base_addr + 4));
++		dwc_debug(dev, "R1=%01x before write\n", temp);
++		temp |= 0x3000;
++		dwc_wr32(dev, (volatile u32 __iomem *)(base_addr + 4), temp);
++		temp = dwc_rd32(dev, (volatile u32 __iomem *)(base_addr + 4));
++		dwc_debug(dev, "R1=%01x after write\n", temp);
++
++		/* Wait until both PMUs confirm that they have entered D3 */
++		dwc_debug(dev, "Asked for D3 state, waiting for response\n");
++
++		cnt = 0;
++		do {
++			udelay(1);
++			temp = dwc_rd32(dev, (volatile u32 __iomem *)
++					(base_addr + 16));
++			if (++cnt > 10000000) {
++				cnt = 0;
++				dwc_debug(dev, "%01x\n", temp);
++				//break;
++			}
++		} while ((temp & test) != test);
++	}
++}
+diff --git a/drivers/usb/gadget/udc/hiudc3/linux_pci.c b/drivers/usb/gadget/udc/hiudc3/linux_pci.c
+new file mode 100644
+index 0000000..fd27cfa
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc3/linux_pci.c
+@@ -0,0 +1,689 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/DWC_usb3/driver/linux/linux_pci.c $
++ * $Revision: #16 $
++ * $Date: 2014/11/11 $
++ * $Change: 2664766 $
++ *
++ * Synopsys SS USB3 Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
++ * ========================================================================== */
++
++/** @file
++ * The driver module provides the initialization and cleanup entry
++ * points for the DWC_usb3 driver. This module will be dynamically installed
++ * after Linux is booted using the insmod command. When the module is
++ * installed, the driver_init function is called. When the module is
++ * removed (using rmmod), the driver_cleanup function is called.
++ *
++ * This module also defines a data structure for the driver, which is
++ * used in conjunction with the standard pci_dev structure. These
++ * structures allow the USB3 driver to comply with the standard Linux driver
++ * model in which devices and drivers are registered with a bus driver. This
++ * has the benefit that Linux can expose attributes of the driver and device
++ * in its special sysfs file system. Users can then read or write files in
++ * this file system to perform diagnostics on the driver components or the
++ * device.
++ */
++
++#include "os_defs.h"
++#include "hw.h"
++#include "usb.h"
++#include "pcd.h"
++#include "dev.h"
++#include "os_dev.h"
++#include "cil.h"
++
++#ifdef CONFIG_USB_OTG_DWC
++extern int dwc_otg3_irq(struct usb_otg *otg);
++extern void dwc_otg3_set_peripheral(struct usb_otg *otg, int yes);
++#endif
++
++#define PCI_VENDOR_ID_SYNOPSYS		0x16c3
++#define PCI_DEVICE_ID_SYNOPSYS_SITKA	0xabcd
++#define PCI_DEVICE_ID_SYNOPSYS_HAPS_AXI	0xabce
++
++static const char dwc_driver_name[] = "dwc_usb3";
++
++/*
++ * Hook to override the default Phy configuration in dwc_usb3_pcd_device_init()
++ * with a HAPS-specific one
++ */
++static void haps_phy_config_hook(struct dwc_usb3_device *dev, int soft_reset,
++				 int restore)
++{
++	dwc_usb3_core_global_regs_t __iomem *global_regs =
++						dev->core_global_regs;
++	u32 temp;
++
++	switch (dev->core_params->phy) {
++	case 3:		// 16-bit UTMI+ SNPS Phy
++		temp = dwc_rd32(dev, &global_regs->gusb2phycfg[0]);
++		temp &= ~DWC_USB2PHYCFG_USB_TRD_TIM_BITS;
++		temp |= DWC_USB2PHYCFG_16B_PHY_IF_BIT;
++		temp |= 5 << DWC_USB2PHYCFG_USB_TRD_TIM_SHIFT;
++		dwc_wr32(dev, &global_regs->gusb2phycfg[0], temp);
++		break;
++	case 2:		// 8-bit UTMI+ / ULPI TI or SNPS Phy
++	case 1:		// old 8-bit UTMI+ SNPS Phy
++		temp = dwc_rd32(dev, &global_regs->gusb2phycfg[0]);
++		temp &= ~DWC_USB2PHYCFG_USB_TRD_TIM_BITS;
++		temp &= ~DWC_USB2PHYCFG_16B_PHY_IF_BIT;
++		temp |= 9 << DWC_USB2PHYCFG_USB_TRD_TIM_SHIFT;
++		dwc_wr32(dev, &global_regs->gusb2phycfg[0], temp);
++		break;
++	default:	// RocketIO Phy
++		if (dev->core_params->usb2mode == 0) {
++			/* Set rx-eq, differential swing */
++			dwc_wr32(dev, (volatile u32 __iomem *)
++				 (dev->base + dev->gasket_ofs + 8), 0x41);
++#ifdef LECROY
++			/* Rx-detect for LeCroy */
++			dwc_wr32(dev, (volatile u32 __iomem *)
++				 (dev->base + dev->gasket_ofs + 4), 0x200);
++#else
++			dwc_wr32(dev, (volatile u32 __iomem *)
++				 (dev->base + dev->gasket_ofs + 4), 0);
++#endif
++		}
++	}
++}
++
++/**
++ * This function is the top level interrupt handler for the Common
++ * (Core and Device) interrupts.
++ */
++static irqreturn_t dwc_usb3_common_irq(int irq, void *dev
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
++				       , struct pt_regs *regs
++#endif
++				      )
++{
++	dwc_usb3_device_t *usb3_dev = dev;
++	int retval = 0;
++
++#ifdef CONFIG_USB_OTG_DWC
++	u32 gsts = 0;
++	int temp = usb3_dev->hibernate;
++
++	/* Skip OTG IRQ handler if in hibernation */
++	if (temp < DWC_HIBER_SLEEPING) {
++		gsts = dwc_rd32(usb3_dev, &usb3_dev->core_global_regs->gsts);
++	} else {
++		dwc_info(usb3_dev, "%s() possible OTG IRQ in hibernation\n",
++			 __func__);
++		retval = 1;
++	}
++
++	if (gsts & DWC_GSTS_OTG_EVT_PENDING_BIT ||
++	    gsts & DWC_GSTS_ADP_EVT_PENDING_BIT ||
++	    gsts & DWC_GSTS_BC_EVT_PENDING_BIT) {
++		struct usb_phy *phy = usb_get_phy(USB_PHY_TYPE_USB3);
++
++		if (!IS_ERR(phy)) {
++			dwc_info(usb3_dev, "%s() OTG IRQ\n", __func__);
++			dwc_info(usb3_dev, "gsts = %08x\n", gsts);
++			if (phy && phy->otg)
++				dwc_otg3_irq(phy->otg);
++			else
++				dwc_info(usb3_dev, "OTG IRQ but no OTG\n");
++			usb_put_phy(phy);
++		} else {
++			dwc_info(usb3_dev, "%s() OTG IRQ but no PHY\n",
++				 __func__);
++		}
++
++		retval = 1;
++	}
++
++	if (temp >= DWC_HIBER_SLEEPING || (gsts & DWC_GSTS_DEV_EVT_PENDING_BIT))
++#endif
++	{
++		spin_lock(&usb3_dev->pcd.lock);
++		retval = dwc_usb3_irq(usb3_dev, irq);
++		spin_unlock(&usb3_dev->pcd.lock);
++	}
++
++	return IRQ_RETVAL(retval);
++}
++
++#ifdef DWC_UTE
++static void dwc_usb3_save_fifosiz_def_vals(dwc_usb3_device_t *dev)
++{
++	unsigned i, size;
++	dwc_usb3_pcd_t *pcd;
++
++	if (!dev)
++		return;
++
++	pcd = &dev->pcd;
++
++	for (i = 0; i < pcd->num_in_eps + 1; i++) {
++		size = dwc_rd32(dev, &dev->core_global_regs->gtxfifosiz[i]) &
++							DWC_FIFOSZ_DEPTH_BITS;
++		dwc_print(dev, "Saving %d TxFIFO default size: %d\n", i, size);
++		pcd->def_txf_size[i] = size;
++	}
++
++	size = dwc_rd32(dev, &dev->core_global_regs->grxfifosiz[0]) &
++							DWC_FIFOSZ_DEPTH_BITS;
++	pcd->def_rxf_size = size;
++
++	dwc_print(dev, "Saving RxFIFO default size: %d\n", size);
++}
++#endif
++
++/**
++ * This function is called when a pci_dev is unregistered with the
++ * dwc_usb3_driver. This happens, for example, when the rmmod command is
++ * executed. The device may or may not be electrically present. If it is
++ * present, the driver stops device processing. Any resources used on behalf
++ * of this device are freed.
++ *
++ * @param dev pci_dev struct
++ */
++static void dwc_usb3_driver_remove(struct pci_dev *dev)
++{
++	dwc_usb3_device_t *usb3_dev = pci_get_drvdata(dev);
++	u32 *event_buf;
++	dwc_dma_t event_buf_dma;
++
++#ifdef CONFIG_USB_OTG_DWC
++	struct usb_phy *phy;
++#endif
++
++	dev_dbg(&dev->dev, "%s(%p)\n", __func__, dev);
++
++	if (!usb3_dev) {
++		/* Memory allocation for the dwc_usb3_device failed */
++		dev_dbg(&dev->dev, "%s: usb3_dev NULL\n", __func__);
++		goto disable;
++	}
++
++#ifdef CONFIG_USB_OTG_DWC
++	/* Switch otg to peripheral mode */
++	phy = usb_get_phy(USB_PHY_TYPE_USB3);
++	if (!IS_ERR(phy)) {
++		if (phy && phy->otg)
++			dwc_otg3_set_peripheral(phy->otg, 1);
++		usb_put_phy(phy);
++	}
++#endif
++
++	/*
++	 * Free the IRQ
++	 */
++	if (usb3_dev->cmn_irq_installed) {
++		usb3_dev->cmn_irq_installed = 0;
++		free_irq(dev->irq, usb3_dev);
++	}
++
++	if (usb3_dev->pme_thread) {
++		kthread_stop(usb3_dev->pme_thread);
++		usb3_dev->pme_thread = NULL;
++	}
++
++	if (usb3_dev->pcd_initialized) {
++		usb3_dev->pcd_initialized = 0;
++		dwc_usb3_pcd_remove(usb3_dev);
++	}
++
++	if (usb3_dev->gadget_initialized) {
++		usb3_dev->gadget_initialized = 0;
++		dwc_usb3_gadget_remove(usb3_dev, &dev->dev);
++	}
++
++	if (usb3_dev->cmn_initialized) {
++		usb3_dev->cmn_initialized = 0;
++		dwc_usb3_pcd_common_remove(usb3_dev);
++	}
++
++	event_buf = usb3_dev->event_buf[0];
++	event_buf_dma = usb3_dev->event_buf_dma[0];
++	if (event_buf) {
++		dwc_usb3_dis_flush_eventbuf_intr(usb3_dev, 0);
++		usb3_dev->event_buf[0] = NULL;
++		dma_free_coherent(NULL, DWC_EVENT_BUF_SIZE * sizeof(u32),
++				  event_buf, event_buf_dma);
++	}
++
++	if (usb3_dev->sysfs_initialized) {
++		dwc_usb3_remove_dev_files(&dev->dev);
++		usb3_dev->sysfs_initialized = 0;
++	}
++
++	/*
++	 * Clear the drvdata pointer.
++	 */
++	pci_set_drvdata(dev, NULL);
++
++	/*
++	 * Return the memory.
++	 */
++	if (usb3_dev->base)
++		iounmap((void __iomem *)usb3_dev->base);
++	if (usb3_dev->rsrc_start)
++		release_mem_region(usb3_dev->rsrc_start, usb3_dev->rsrc_len);
++	if (usb3_dev->gasket_base)
++		iounmap((void __iomem *)usb3_dev->gasket_base);
++	if (usb3_dev->gasket_start)
++		release_mem_region(usb3_dev->gasket_start, usb3_dev->gasket_len);
++
++	kfree(usb3_dev);
++
++disable:
++	//pci_disable_device(dev);
++	return;
++}
++
++/**
++ * This function is called when a pci_dev is bound to a
++ * dwc_usb3_driver. It creates the driver components required to
++ * control the device (CIL and PCD) and it initializes the
++ * device. The driver components are stored in a dwc_usb3_device
++ * structure. A reference to the dwc_usb3_device is saved in the
++ * pci_dev. This allows the driver to access the dwc_usb3_device
++ * structure on subsequent calls to driver methods for this device.
++ *
++ * @param dev pci_dev struct
++ * @param id  pci_dev_id struct
++ */
++static int dwc_usb3_driver_probe(struct pci_dev *dev, const struct pci_device_id *id)
++{
++	dwc_usb3_device_t *usb3_dev;
++	u32 addr_ofs = 0xc000;
++	int retval = 0;
++
++#ifdef CONFIG_USB_OTG_DWC
++	struct usb_phy *phy;
++	struct usb_otg *otg;
++#endif
++
++	printk(KERN_DEBUG "%s: driver_probe()\n", dwc_driver_name);
++	dev_dbg(&dev->dev, "dwc_usb3_driver_probe(%p)\n", dev);
++
++	dev_dbg(&dev->dev, "start=0x%08x\n",
++		(unsigned)pci_resource_start(dev, 0));
++	dev_dbg(&dev->dev, "len=0x%08x\n", (unsigned)pci_resource_len(dev, 0));
++
++#ifndef DWC_BAR2_GASKET_REG
++	if (id->device == PCI_DEVICE_ID_SYNOPSYS_HAPS_AXI)
++#endif
++	{
++		dev_dbg(&dev->dev, "start2=0x%08x\n",
++			(unsigned)pci_resource_start(dev, 2));
++		dev_dbg(&dev->dev, "len2=0x%08x\n",
++			(unsigned)pci_resource_len(dev, 2));
++	}
++
++	if (!id) {
++		dev_err(&dev->dev, "id parameter NULL!\n");
++		return -EINVAL;
++	}
++
++	if (pci_enable_device(dev) < 0) {
++		dev_err(&dev->dev, "pci_enable_device() failed!\n");
++		return -ENODEV;
++	}
++
++	dev->current_state = PCI_D0;
++	dev->dev.power.power_state = PMSG_ON;
++
++	if (!dev->irq) {
++		dev_err(&dev->dev, "no IRQ for PCI device!\n");
++		retval = -ENODEV;
++		goto fail;
++	}
++
++	usb3_dev = kmalloc(sizeof(dwc_usb3_device_t), GFP_KERNEL);
++	if (!usb3_dev) {
++		dev_err(&dev->dev, "kmalloc of dwc_usb3_device failed!\n");
++		retval = -ENOMEM;
++		goto fail;
++	}
++
++	memset(usb3_dev, 0, sizeof(*usb3_dev));
++	usb3_dev->dev = &dev->dev;
++	usb3_dev->rsrc_start = pci_resource_start(dev, 0);
++	usb3_dev->rsrc_len = pci_resource_len(dev, 0);
++
++#ifndef DWC_BAR2_GASKET_REG
++	if (id->device == PCI_DEVICE_ID_SYNOPSYS_HAPS_AXI)
++#endif
++	{
++		usb3_dev->gasket_start = pci_resource_start(dev, 2);
++		usb3_dev->gasket_len = pci_resource_len(dev, 2);
++	}
++
++	/*
++	 * Initialize driver data to point to the global DWC_usb3
++	 * Device structure.
++	 */
++	pci_set_drvdata(dev, usb3_dev);
++	dev_dbg(&dev->dev, "dwc_usb3_device=0x%p\n", usb3_dev);
++
++	if (!usb3_dev->rsrc_start || !usb3_dev->rsrc_len) {
++		dev_err(&dev->dev, "bad PCI resource!\n");
++		retval = -ENOMEM;
++		goto fail;
++	}
++
++#ifndef DWC_BAR2_GASKET_REG
++	if (id->device == PCI_DEVICE_ID_SYNOPSYS_HAPS_AXI)
++#endif
++	{
++		if (!usb3_dev->gasket_start || !usb3_dev->gasket_len) {
++			dev_err(&dev->dev, "bad PCI resource 2!\n");
++			retval = -ENOMEM;
++			goto fail;
++		}
++	}
++
++	/*
++	 * Map the DWC_usb3 Core memory into virtual address space.
++	 */
++	if (!request_mem_region(usb3_dev->rsrc_start, usb3_dev->rsrc_len,
++				"usb3")) {
++		dev_err(&dev->dev, "request_mem_region() failed!\n");
++
++		/* Flag for dwc_usb3_driver_remove() that we failed */
++		usb3_dev->rsrc_start = 0;
++
++		retval = -EBUSY;
++		goto fail;
++	}
++
++	usb3_dev->base = ioremap_nocache(usb3_dev->rsrc_start,
++					 usb3_dev->rsrc_len);
++	if (!usb3_dev->base) {
++		dev_err(&dev->dev, "ioremap_nocache() failed!\n");
++		retval = -ENOMEM;
++		goto fail;
++	}
++
++	dev_dbg(&dev->dev, "base=%p\n", usb3_dev->base);
++
++#ifndef DWC_BAR2_GASKET_REG
++	if (id->device == PCI_DEVICE_ID_SYNOPSYS_HAPS_AXI)
++#endif
++	{
++		if (!request_mem_region(usb3_dev->gasket_start,
++					usb3_dev->gasket_len, "usb3")) {
++			dev_err(&dev->dev, "request_mem_region() 2 failed!\n");
++
++			/* Flag for dwc_usb3_driver_remove() that we failed */
++			usb3_dev->gasket_start = 0;
++
++			retval = -EBUSY;
++			goto fail;
++		}
++
++		usb3_dev->gasket_base = ioremap_nocache(usb3_dev->gasket_start,
++							usb3_dev->gasket_len);
++		if (!usb3_dev->gasket_base) {
++			dev_err(&dev->dev, "ioremap_nocache() 2 failed!\n");
++			retval = -ENOMEM;
++			goto fail;
++		}
++
++		dev_dbg(&dev->dev, "gasket_base=%p\n", usb3_dev->gasket_base);
++	}
++
++	if (dwc_usb3_module_params.newcsr)
++		usb3_dev->gasket_ofs = 0xf000;
++	else
++		usb3_dev->gasket_ofs = 0x80000;
++
++#ifdef CONFIG_USB_OTG_DWC
++	/* Switch otg to peripheral mode */
++	phy = usb_get_phy(USB_PHY_TYPE_USB3);
++	if (IS_ERR(phy) || !phy) {
++		dev_err(&dev->dev, "OTG PHY not available!\n");
++		if (!IS_ERR(phy))
++			usb_put_phy(phy);
++		retval = -ENODEV;
++		goto fail;
++	}
++
++	otg = phy->otg;
++	if (!otg) {
++		dev_err(&dev->dev, "OTG not available!\n");
++		usb_put_phy(phy);
++		retval = -ENODEV;
++		goto fail;
++	}
++
++	phy->io_priv = (void __iomem *)usb3_dev->base;
++	dwc_otg3_set_peripheral(otg, 1);
++	usb_put_phy(phy);
++#endif
++
++	retval = dwc_usb3_create_dev_files(&dev->dev);
++	if (retval) {
++		dev_err(&dev->dev, "sysfs initialization failed!\n");
++		goto fail;
++	}
++
++	usb3_dev->sysfs_initialized = 1;
++
++	/*
++	 * Checks that this device is really a DWC_usb3 controller. Also saves
++	 * the SNPSID register value in usb3_dev->snpsid for later use by the
++	 * PCD.
++	 */
++	retval = dwc_usb3_pcd_check_snpsid(usb3_dev, addr_ofs);
++	if (retval) {
++		dev_err(&dev->dev, "bad value for SNPSID!\n");
++		goto fail;
++	}
++
++	if (dwc_usb3_module_params.newcore && usb3_dev->snpsid < 0x5533109a)
++		usb3_dev->snpsid = 0x5533109a;
++
++	/*
++	 * Up to 32 Event Buffers are supported by the hardware,
++	 * but we only use 1
++	 */
++	usb3_dev->event_buf[0] = dma_alloc_coherent(NULL,
++					DWC_EVENT_BUF_SIZE * sizeof(u32),
++					&usb3_dev->event_buf_dma[0],
++					GFP_KERNEL | GFP_DMA32);
++	if (!usb3_dev->event_buf[0]) {
++		dev_err(&dev->dev, "allocation of event_buf failed!\n");
++		retval = -ENOMEM;
++		goto fail;
++	}
++
++	/*
++	 * Add our hook to override the default Phy register setup
++	 */
++	usb3_dev->phy_config_hook = haps_phy_config_hook;
++
++	/*
++	 * Initialize the DWC_usb3 Core.
++	 */
++	retval = dwc_usb3_pcd_common_init(usb3_dev, usb3_dev->base + addr_ofs,
++					  &dwc_usb3_module_params);
++	if (retval) {
++		dev_err(&dev->dev, "CIL initialization failed!\n");
++		goto fail;
++	}
++
++	usb3_dev->cmn_initialized = 1;
++
++#ifdef DWC_UTE
++	dwc_usb3_save_fifosiz_def_vals(usb3_dev);
++#endif
++
++	spin_lock_init(&usb3_dev->pcd.lock);
++
++	/*
++	 * Initialize the Gadget
++	 */
++	retval = dwc_usb3_gadget_init(usb3_dev, &dev->dev);
++	if (retval) {
++		dev_err(&dev->dev, "gadget initialization failed!\n");
++		goto fail;
++	}
++
++	usb3_dev->gadget_initialized = 1;
++
++	/*
++	 * Initialize the PCD
++	 */
++	retval = dwc_usb3_pcd_init(usb3_dev);
++	if (retval) {
++		dev_err(&dev->dev, "PCD initialization failed!\n");
++		goto fail;
++	}
++
++	usb3_dev->pcd_initialized = 1;
++
++	/* Allocate the test mode tasklet */
++	tasklet_init(&usb3_dev->pcd.test_mode_tasklet,
++		     dwc_usb3_pcd_do_test_mode,
++		     (unsigned long)&usb3_dev->pcd);
++
++	/* Start the hibernation thread */
++	usb3_dev->pme_thread = kthread_run(dwc_wait_pme_thread, &usb3_dev->pcd,
++					   "pmethr");
++	if (IS_ERR(usb3_dev->pme_thread)) {
++		retval = PTR_ERR(usb3_dev->pme_thread);
++		usb3_dev->pme_thread = NULL;
++		goto fail;
++	}
++
++	/*
++	 * Install the interrupt handler for the common interrupts.
++	 */
++	dev_dbg(&dev->dev, "registering (common) handler for irq%d\n",
++		dev->irq);
++	retval = request_irq(dev->irq, dwc_usb3_common_irq,
++			     IRQF_SHARED | IRQF_DISABLED,
++			     dwc_driver_name, usb3_dev);
++	if (retval) {
++		dev_err(&dev->dev, "request of irq%d failed!\n", dev->irq);
++		goto fail;
++	}
++
++	usb3_dev->cmn_irq_installed = 1;
++#if 0
++	if (dwc_usb3_module_params.hibernate &&
++	    (usb3_dev->hwparams1 & DWC_HWP1_EN_PWROPT_BITS) ==
++	    DWC_EN_PWROPT_HIBERNATION << DWC_HWP1_EN_PWROPT_SHIFT) {
++		unsigned long flags;
++
++		spin_lock_irqsave(&usb3_dev->pcd.lock, flags);
++		dwc_enter_hibernation(&usb3_dev->pcd, 0);
++		spin_unlock_irqrestore(&usb3_dev->pcd.lock, flags);
++	}
++#endif
++	return 0;
++
++fail:
++	dwc_usb3_driver_remove(dev);
++	return retval;
++}
++
++static const struct pci_device_id pci_ids[] = {
++	{
++		/* The Synopsys PCIe card */
++		PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,
++			   PCI_DEVICE_ID_SYNOPSYS_SITKA),
++		.driver_data = (unsigned long)0xdeadbeef,
++	},
++	{
++		/* The Synopsys HAPS PCIe card with AXI, with gasket registers
++		 * moved to 2nd BAR
++		 */
++		PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,
++			   PCI_DEVICE_ID_SYNOPSYS_HAPS_AXI),
++		.driver_data = (unsigned long)0xdeadbeef,
++	},
++	{ 0, }	/* end: all zeroes */
++};
++MODULE_DEVICE_TABLE(pci, pci_ids);
++
++/**
++ * This structure defines the methods to be called by a bus driver
++ * during the lifecycle of a device on that bus. Both drivers and
++ * devices are registered with a bus driver. The bus driver matches
++ * devices to drivers based on information in the device and driver
++ * structures.
++ *
++ * The probe function is called when the bus driver matches a device
++ * to this driver. The remove function is called when a device is
++ * unregistered with the bus driver.
++ */
++static struct pci_driver dwc_usb3_driver = {
++	.name		= (char *)dwc_driver_name,
++	.id_table	= pci_ids,
++	.probe		= dwc_usb3_driver_probe,
++	.remove		= dwc_usb3_driver_remove,
++	.driver		= {
++		.name	= (char *)dwc_driver_name,
++	},
++};
++
++/**
++ * This function is called when the DWC_usb3 driver is loaded into the kernel
++ * with the insmod command. It registers the dwc_usb3_driver structure with the
++ * appropriate bus driver. This will cause the dwc_usb3_driver_probe function
++ * to be called. In addition, the bus driver will automatically expose
++ * attributes defined for the device and driver in the special sysfs file
++ * system.
++ */
++static int __init dwc_usb3_driver_init(void)
++{
++	int retval;
++
++	printk(KERN_INFO "%s: %s version %s\n", dwc_driver_name,
++	       DWC_DRIVER_DESC, DWC_DRIVER_VERSION);
++
++	retval = pci_register_driver(&dwc_usb3_driver);
++	if (retval < 0) {
++		printk(KERN_ERR "%s retval=%d\n", __func__, retval);
++		return retval;
++	}
++
++	printk(KERN_INFO "%s: module installed\n", dwc_driver_name);
++	return retval;
++}
++module_init(dwc_usb3_driver_init);
++
++/**
++ * This function is called when the DWC_usb3 driver is removed from the kernel
++ * with the rmmod command. The driver unregisters itself with its bus driver.
++ *
++ */
++static void __exit dwc_usb3_driver_exit(void)
++{
++	printk(KERN_DEBUG "%s: driver_exit()\n", dwc_driver_name);
++
++	pci_unregister_driver(&dwc_usb3_driver);
++
++	printk(KERN_INFO "%s: module removed\n", dwc_driver_name);
++}
++module_exit(dwc_usb3_driver_exit);
+diff --git a/drivers/usb/gadget/udc/hiudc3/linux_plat.c b/drivers/usb/gadget/udc/hiudc3/linux_plat.c
+new file mode 100644
+index 0000000..3102844
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc3/linux_plat.c
+@@ -0,0 +1,701 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/DWC_usb3/driver/linux/linux_plat.c $
++ * $Revision: #16 $
++ * $Date: 2014/11/11 $
++ * $Change: 2664766 $
++ *
++ * Synopsys SS USB3 Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
++ * ========================================================================== */
++
++/** @file
++ * The driver module provides the initialization and cleanup entry
++ * points for the DWC_usb3 driver. This module will be dynamically installed
++ * after Linux is booted using the insmod command. When the module is
++ * installed, the driver_init function is called. When the module is
++ * removed (using rmmod), the driver_cleanup function is called.
++ *
++ * This module also defines a data structure for the driver, which is
++ * used in conjunction with the standard pci_dev structure. These
++ * structures allow the USB3 driver to comply with the standard Linux driver
++ * model in which devices and drivers are registered with a bus driver. This
++ * has the benefit that Linux can expose attributes of the driver and device
++ * in its special sysfs file system. Users can then read or write files in
++ * this file system to perform diagnostics on the driver components or the
++ * device.
++ */
++
++#include "os_defs.h"
++#include "hw.h"
++#include "usb.h"
++#include "pcd.h"
++#include "dev.h"
++#include "os_dev.h"
++#include "cil.h"
++#include <linux/of.h>
++#include <mach/io.h>
++//#include "../../host/hiusb.h"
++
++#ifndef __devinit
++# define __devinit
++# define __devexit
++# define __devexit_p(x)	x
++#endif
++
++#ifdef CONFIG_USB_OTG_DWC
++extern int dwc_otg3_irq(struct usb_otg *otg);
++extern void dwc_otg3_set_peripheral(struct usb_otg *otg, int yes);
++#endif
++
++//#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)
++//#if LINUX_VERSION_CODE < KERNEL_VERSION(3,6,0)
++/* Enable this to replace the DWC3 driver in recent Linux kernels */
++# define DWC_REPLACE_DWC3
++//#endif
++
++/* Enable this to support the Synopsys Xplorer platform */
++//#define DWC_XPLORER
++
++static const char dwc_driver_name[] = "dwc_usb3";
++
++/*
++ * Hook to override the default Phy configuration in dwc_usb3_pcd_device_init()
++ * with a HAPS-specific one
++ */
++static void haps_phy_config_hook(struct dwc_usb3_device *dev, int soft_reset,
++				 int restore)
++{
++	dwc_usb3_core_global_regs_t __iomem *global_regs =
++						dev->core_global_regs;
++	u32 temp;
++
++	switch (dev->core_params->phy) {
++	case 3:		// 16-bit UTMI+ SNPS Phy
++		temp = dwc_rd32(dev, &global_regs->gusb2phycfg[0]);
++		temp &= ~DWC_USB2PHYCFG_USB_TRD_TIM_BITS;
++		temp |= DWC_USB2PHYCFG_16B_PHY_IF_BIT;
++		temp |= 5 << DWC_USB2PHYCFG_USB_TRD_TIM_SHIFT;
++		dwc_wr32(dev, &global_regs->gusb2phycfg[0], temp);
++		break;
++	case 2:		// 8-bit UTMI+ / ULPI TI or SNPS Phy
++	case 1:		// old 8-bit UTMI+ SNPS Phy
++		temp = dwc_rd32(dev, &global_regs->gusb2phycfg[0]);
++		temp &= ~DWC_USB2PHYCFG_USB_TRD_TIM_BITS;
++		temp &= ~DWC_USB2PHYCFG_16B_PHY_IF_BIT;
++		temp |= 9 << DWC_USB2PHYCFG_USB_TRD_TIM_SHIFT;
++		dwc_wr32(dev, &global_regs->gusb2phycfg[0], temp);
++		break;
++	default:	// RocketIO Phy
++		if (dev->core_params->usb2mode == 0) {
++			/* Set rx-eq, differential swing */
++			dwc_wr32(dev, (volatile u32 __iomem *)
++				 (dev->base + dev->gasket_ofs + 8), 0x41);
++#ifdef LECROY
++			/* Rx-detect for LeCroy */
++			dwc_wr32(dev, (volatile u32 __iomem *)
++				 (dev->base + dev->gasket_ofs + 4), 0x200);
++#else
++			dwc_wr32(dev, (volatile u32 __iomem *)
++				 (dev->base + dev->gasket_ofs + 4), 0);
++#endif
++		}
++	}
++}
++
++/**
++ * This function is the top level interrupt handler for the Common
++ * (Core and Device) interrupts.
++ */
++static irqreturn_t dwc_usb3_common_irq(int irq, void *dev
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
++				       , struct pt_regs *regs
++#endif
++				      )
++{
++	dwc_usb3_device_t *usb3_dev = dev;
++	int retval = 0;
++
++#ifdef CONFIG_USB_OTG_DWC
++	u32 gsts = 0;
++	int temp = usb3_dev->hibernate;
++
++	/* Skip OTG IRQ handler if in hibernation */
++	if (temp < DWC_HIBER_SLEEPING) {
++		gsts = dwc_rd32(usb3_dev, &usb3_dev->core_global_regs->gsts);
++	} else {
++		dwc_info(usb3_dev, "%s() possible OTG IRQ in hibernation\n",
++			 __func__);
++		retval = 1;
++	}
++
++	if (gsts & DWC_GSTS_OTG_EVT_PENDING_BIT ||
++	    gsts & DWC_GSTS_ADP_EVT_PENDING_BIT ||
++	    gsts & DWC_GSTS_BC_EVT_PENDING_BIT) {
++		struct usb_phy *phy = usb_get_phy(USB_PHY_TYPE_USB3);
++
++		if (!IS_ERR(phy)) {
++			dwc_info(usb3_dev, "%s() OTG IRQ\n", __func__);
++			dwc_info(usb3_dev, "gsts = %08x\n", gsts);
++			if (phy && phy->otg)
++				dwc_otg3_irq(phy->otg);
++			else
++				dwc_info(usb3_dev, "OTG IRQ but no OTG\n");
++			usb_put_phy(phy);
++		} else {
++			dwc_info(usb3_dev, "%s() OTG IRQ but no PHY\n",
++				 __func__);
++		}
++
++		retval = 1;
++	}
++
++	if (temp >= DWC_HIBER_SLEEPING || (gsts & DWC_GSTS_DEV_EVT_PENDING_BIT))
++#endif
++	{
++		spin_lock(&usb3_dev->pcd.lock);
++		retval = dwc_usb3_irq(usb3_dev, irq);
++		spin_unlock(&usb3_dev->pcd.lock);
++	}
++
++	return IRQ_RETVAL(retval);
++}
++
++#ifdef DWC_UTE
++static void dwc_usb3_save_fifosiz_def_vals(dwc_usb3_device_t *dev)
++{
++	unsigned i, size;
++	dwc_usb3_pcd_t *pcd;
++
++	if (!dev)
++		return;
++
++	pcd = &dev->pcd;
++
++	for (i = 0; i < pcd->num_in_eps + 1; i++) {
++		size = dwc_rd32(dev, &dev->core_global_regs->gtxfifosiz[i]) &
++							DWC_FIFOSZ_DEPTH_BITS;
++		dwc_print(dev, "Saving %d TxFIFO default size: %d\n", i, size);
++		pcd->def_txf_size[i] = size;
++	}
++
++	size = dwc_rd32(dev, &dev->core_global_regs->grxfifosiz[0]) &
++							DWC_FIFOSZ_DEPTH_BITS;
++	pcd->def_rxf_size = size;
++
++	dwc_print(dev, "Saving RxFIFO default size: %d\n", size);
++}
++#endif
++
++/**
++ * This function is called when a platform_device is unregistered with the
++ * dwc_usb3_driver. This happens, for example, when the rmmod command is
++ * executed. The device may or may not be electrically present. If it is
++ * present, the driver stops device processing. Any resources used on behalf
++ * of this device are freed.
++ *
++ * @param dev platform_device struct
++ */
++static int dwc_usb3_platform_remove(struct platform_device *dev)
++{
++	dwc_usb3_device_t *usb3_dev = platform_get_drvdata(dev);
++	u32 *event_buf;
++	dwc_dma_t event_buf_dma;
++
++#ifdef CONFIG_USB_OTG_DWC
++	struct usb_phy *phy;
++#endif
++
++	dev_dbg(&dev->dev, "%s(%p)\n", __func__, dev);
++
++	if (!usb3_dev) {
++		/* Memory allocation for the dwc_usb3_device failed */
++		dev_dbg(&dev->dev, "%s: usb3_dev NULL\n", __func__);
++		goto disable;
++	}
++
++#ifdef CONFIG_USB_OTG_DWC
++	/* Switch otg to peripheral mode */
++	phy = usb_get_phy(USB_PHY_TYPE_USB3);
++	if (!IS_ERR(phy)) {
++		if (phy && phy->otg)
++			dwc_otg3_set_peripheral(phy->otg, 1);
++		usb_put_phy(phy);
++	}
++#endif
++
++	/*
++	 * Free the IRQ
++	 */
++	if (usb3_dev->cmn_irq_installed) {
++		usb3_dev->cmn_irq_installed = 0;
++		free_irq(usb3_dev->irq, usb3_dev);
++	}
++
++	if (usb3_dev->pme_thread) {
++		kthread_stop(usb3_dev->pme_thread);
++		usb3_dev->pme_thread = NULL;
++	}
++
++	if (usb3_dev->pcd_initialized) {
++		usb3_dev->pcd_initialized = 0;
++		dwc_usb3_pcd_remove(usb3_dev);
++	}
++
++	if (usb3_dev->gadget_initialized) {
++		usb3_dev->gadget_initialized = 0;
++		dwc_usb3_gadget_remove(usb3_dev, &dev->dev);
++	}
++
++	if (usb3_dev->cmn_initialized) {
++		usb3_dev->cmn_initialized = 0;
++		dwc_usb3_pcd_common_remove(usb3_dev);
++	}
++
++	event_buf = usb3_dev->event_buf[0];
++	event_buf_dma = usb3_dev->event_buf_dma[0];
++	if (event_buf) {
++		dwc_usb3_dis_flush_eventbuf_intr(usb3_dev, 0);
++		usb3_dev->event_buf[0] = NULL;
++		dma_free_coherent(NULL, DWC_EVENT_BUF_SIZE * sizeof(u32),
++				  event_buf, event_buf_dma);
++	}
++
++	if (usb3_dev->sysfs_initialized) {
++		dwc_usb3_remove_dev_files(&dev->dev);
++		usb3_dev->sysfs_initialized = 0;
++	}
++
++	/*
++	 * Clear the drvdata pointer.
++	 */
++	platform_set_drvdata(dev, NULL);
++
++	/*
++	 * Return the memory.
++	 */
++	if (usb3_dev->base)
++		iounmap((void __iomem *)usb3_dev->base);
++	if (usb3_dev->rsrc_start)
++		release_mem_region(usb3_dev->rsrc_start, usb3_dev->rsrc_len);
++	if (usb3_dev->gasket_base)
++		iounmap((void __iomem *)usb3_dev->gasket_base);
++	if (usb3_dev->gasket_start)
++		release_mem_region(usb3_dev->gasket_start, usb3_dev->gasket_len);
++
++	kfree(usb3_dev);
++
++disable:
++	return 0;
++}
++
++static u64 dwc3_vexpress_dma_mask = DMA_BIT_MASK(32);
++
++/**
++ * This function is called when a platform_device is bound to a
++ * dwc_usb3_driver. It creates the driver components required to
++ * control the device (CIL and PCD) and it initializes the
++ * device. The driver components are stored in a dwc_usb3_device
++ * structure. A reference to the dwc_usb3_device is saved in the
++ * platform_device. This allows the driver to access the dwc_usb3_device
++ * structure on subsequent calls to driver methods for this device.
++ *
++ * @param dev platform_device struct
++ */
++static int __devinit dwc_usb3_platform_probe(struct platform_device *dev)
++{
++#if 0
++	int reg;
++	reg = dwc_rd32(dev, IO_ADDRESS(0x10180430));
++	reg = dwc_rd32(dev, IO_ADDRESS(0x1018c110));
++	reg &= ~(3 << 12);
++	reg |= (2 << 12);
++	dwc_wr32(dev, IO_ADDRESS(0x1018c110), reg);
++#endif
++	dwc_usb3_device_t *usb3_dev;
++	struct resource *res_mem;
++	u32 addr_ofs = 0xc000;
++	int irq, retval = 0;
++
++#ifdef DWC_BAR2_GASKET_REG
++	struct resource *res_mem2;
++#endif
++
++#ifdef CONFIG_USB_OTG_DWC
++	struct usb_phy *phy;
++	struct usb_otg *otg;
++#endif
++
++	printk(KERN_DEBUG "%s: platform_probe()\n", dwc_driver_name);
++	dev_dbg(&dev->dev, "dwc_usb3_platform_probe(%p)\n", dev);
++
++	if (!dev->dev.dma_mask)
++		dev->dev.dma_mask = &dwc3_vexpress_dma_mask;
++
++	irq = platform_get_irq(dev, 0);
++	if (irq < 0) {
++		dev_err(&dev->dev, "no irq provided");
++		return irq;
++	}
++
++	res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0);
++	if (!res_mem) {
++		dev_err(&dev->dev, "no memory resource provided");
++		return -ENXIO;
++	}
++
++#ifdef DWC_BAR2_GASKET_REG
++	res_mem2 = platform_get_resource(dev, IORESOURCE_MEM, 2);
++	if (!res_mem2) {
++		dev_err(&dev->dev, "no memory resource 2 provided");
++		return -ENXIO;
++	}
++#endif
++
++	usb3_dev = kmalloc(sizeof(dwc_usb3_device_t), GFP_KERNEL);
++	if (!usb3_dev) {
++		dev_err(&dev->dev, "kmalloc of dwc_usb3_device failed!\n");
++		retval = -ENOMEM;
++		goto fail;
++	}
++
++	memset(usb3_dev, 0, sizeof(*usb3_dev));
++	usb3_dev->dev = &dev->dev;
++	usb3_dev->irq = irq;
++
++	/*
++	 * Initialize driver data to point to the global DWC_usb3
++	 * Device structure.
++	 */
++	platform_set_drvdata(dev, usb3_dev);
++	dev_dbg(&dev->dev, "dwc_usb3_device=0x%p\n", usb3_dev);
++
++	/*
++	 * Map the DWC_usb3 Core memory into virtual address space.
++	 */
++#if 0
++	if (!request_mem_region(res_mem->start, resource_size(res_mem),
++				"usb3")) {
++		dev_err(&dev->dev, "request_mem_region() failed!\n");
++		retval = -EBUSY;
++		goto fail;
++	}
++#endif
++	usb3_dev->rsrc_start = res_mem->start;
++	usb3_dev->rsrc_len = resource_size(res_mem);
++
++	usb3_dev->base = ioremap_nocache(usb3_dev->rsrc_start,
++					 usb3_dev->rsrc_len);
++	if (!usb3_dev->base) {
++		dev_err(&dev->dev, "ioremap_nocache() failed!\n");
++		retval = -ENOMEM;
++		goto fail;
++	}
++
++	dev_dbg(&dev->dev, "base=%p\n", usb3_dev->base);
++
++#ifdef DWC_BAR2_GASKET_REG
++	if (!request_mem_region(res_mem2->start, resource_size(res_mem2),
++				"usb3")) {
++		dev_err(&dev->dev, "request_mem_region() 2 failed!\n");
++		retval = -EBUSY;
++		goto fail;
++	}
++
++	usb3_dev->gasket_start = res_mem2->start;
++	usb3_dev->gasket_len = resource_size(res_mem2);
++
++	usb3_dev->gasket_base = ioremap_nocache(usb3_dev->gasket_start,
++						usb3_dev->gasket_len);
++	if (!usb3_dev->gasket_base) {
++		dev_err(&dev->dev, "ioremap_nocache() 2 failed!\n");
++		retval = -ENOMEM;
++		goto fail;
++	}
++
++	dev_dbg(&dev->dev, "gasket_base=%p\n", usb3_dev->gasket_base);
++#endif
++
++	if (dwc_usb3_module_params.newcsr)
++		usb3_dev->gasket_ofs = 0xf000;
++	else
++		usb3_dev->gasket_ofs = 0x80000;
++
++#ifdef CONFIG_USB_OTG_DWC
++	/* Switch otg to peripheral mode */
++	phy = usb_get_phy(USB_PHY_TYPE_USB3);
++	if (IS_ERR(phy) || !phy) {
++		dev_err(&dev->dev, "OTG PHY not available!\n");
++		if (!IS_ERR(phy))
++			usb_put_phy(phy);
++		retval = -ENODEV;
++		goto fail;
++	}
++
++	otg = phy->otg;
++	if (!otg) {
++		dev_err(&dev->dev, "OTG not available!\n");
++		usb_put_phy(phy);
++		retval = -ENODEV;
++		goto fail;
++	}
++
++	phy->io_priv = (void __iomem *)usb3_dev->base;
++	dwc_otg3_set_peripheral(otg, 1);
++	usb_put_phy(phy);
++#endif
++
++	retval = dwc_usb3_create_dev_files(&dev->dev);
++	if (retval) {
++		dev_err(&dev->dev, "sysfs initialization failed!\n");
++		goto fail;
++	}
++
++	usb3_dev->sysfs_initialized = 1;
++
++	/*
++	 * Checks that this device is really a DWC_usb3 controller. Also saves
++	 * the SNPSID register value in usb3_dev->snpsid for later use by the
++	 * PCD.
++	 */
++	retval = dwc_usb3_pcd_check_snpsid(usb3_dev, addr_ofs);
++	if (retval) {
++		dev_err(&dev->dev, "bad value for SNPSID!\n");
++		goto fail;
++	}
++
++	if (dwc_usb3_module_params.newcore && usb3_dev->snpsid < 0x5533109a)
++		usb3_dev->snpsid = 0x5533109a;
++
++	/*
++	 * Up to 32 Event Buffers are supported by the hardware,
++	 * but we only use 1
++	 */
++	usb3_dev->event_buf[0] = dma_alloc_coherent(NULL,
++					DWC_EVENT_BUF_SIZE * sizeof(u32),
++					&usb3_dev->event_buf_dma[0],
++					GFP_KERNEL | GFP_DMA32);
++	if (!usb3_dev->event_buf[0]) {
++		dev_err(&dev->dev, "allocation of event_buf failed!\n");
++		retval = -ENOMEM;
++		goto fail;
++	}
++
++	/*
++	 * Add our hook to override the default Phy register setup
++	 */
++	usb3_dev->phy_config_hook = haps_phy_config_hook;
++
++	/*
++	 * Initialize the DWC_usb3 Core.
++	 */
++	retval = dwc_usb3_pcd_common_init(usb3_dev, usb3_dev->base + addr_ofs,
++					  &dwc_usb3_module_params);
++	if (retval) {
++		dev_err(&dev->dev, "CIL initialization failed!\n");
++		goto fail;
++	}
++
++	usb3_dev->cmn_initialized = 1;
++
++#ifdef DWC_UTE
++	dwc_usb3_save_fifosiz_def_vals(usb3_dev);
++#endif
++
++	spin_lock_init(&usb3_dev->pcd.lock);
++
++	/*
++	 * Initialize the Gadget
++	 */
++	retval = dwc_usb3_gadget_init(usb3_dev, &dev->dev);
++	if (retval) {
++		dev_err(&dev->dev, "gadget initialization failed!\n");
++		goto fail;
++	}
++
++	usb3_dev->gadget_initialized = 1;
++
++	/*
++	 * Initialize the PCD
++	 */
++	retval = dwc_usb3_pcd_init(usb3_dev);
++	if (retval) {
++		dev_err(&dev->dev, "PCD initialization failed!\n");
++		goto fail;
++	}
++
++	usb3_dev->pcd_initialized = 1;
++
++	/* Allocate the test mode tasklet */
++	tasklet_init(&usb3_dev->pcd.test_mode_tasklet,
++		     dwc_usb3_pcd_do_test_mode,
++		     (unsigned long)&usb3_dev->pcd);
++
++	/* Start the hibernation thread */
++	usb3_dev->pme_thread = kthread_run(dwc_wait_pme_thread, &usb3_dev->pcd,
++					   "pmethr");
++	if (IS_ERR(usb3_dev->pme_thread)) {
++		retval = PTR_ERR(usb3_dev->pme_thread);
++		usb3_dev->pme_thread = NULL;
++		goto fail;
++	}
++
++	/*
++	 * Install the interrupt handler for the common interrupts.
++	 */
++	dev_dbg(&dev->dev, "registering (common) handler for irq%d\n",
++		usb3_dev->irq);
++	retval = request_irq(usb3_dev->irq, dwc_usb3_common_irq,
++			     IRQF_SHARED | IRQF_DISABLED,
++			     dwc_driver_name, usb3_dev);
++	if (retval) {
++		dev_err(&dev->dev, "request of irq%d failed!\n", usb3_dev->irq);
++		goto fail;
++	}
++
++	usb3_dev->cmn_irq_installed = 1;
++#if 0
++	if (dwc_usb3_module_params.hibernate &&
++	    (usb3_dev->hwparams1 & DWC_HWP1_EN_PWROPT_BITS) ==
++	    DWC_EN_PWROPT_HIBERNATION << DWC_HWP1_EN_PWROPT_SHIFT) {
++		unsigned long flags;
++
++		spin_lock_irqsave(&usb3_dev->pcd.lock, flags);
++		dwc_enter_hibernation(&usb3_dev->pcd, 0);
++		spin_unlock_irqrestore(&usb3_dev->pcd.lock, flags);
++	}
++#endif
++	return 0;
++
++fail:
++	dwc_usb3_platform_remove(dev);
++	return retval;
++}
++
++#ifdef DWC_REPLACE_DWC3
++
++#ifdef CONFIG_OF
++static const struct of_device_id of_dwc_usb3_match[] = {
++#if 0
++#ifdef DWC_XPLORER
++	{
++		.compatible = "snps,xplorer-dwusb3"
++	},
++#else
++	{
++		.compatible = "synopsys,dwc3"
++	},
++#endif
++#endif
++	{ .compatible = "dwc_usb3", },
++	{ },
++};
++MODULE_DEVICE_TABLE(of, of_dwc_usb3_match);
++#endif
++
++static struct platform_driver dwc_usb3_platform_driver = {
++	.probe		= dwc_usb3_platform_probe,
++	.remove		= dwc_usb3_platform_remove,
++	.driver		= {
++#ifdef DWC_XPLORER
++		.name	= "xplorer-dwc3",
++#else
++		.name  = (char *)dwc_driver_name,
++//		.name	= "dwc3",
++#endif
++		.of_match_table	= of_dwc_usb3_match,
++	},
++};
++
++module_platform_driver(dwc_usb3_platform_driver);
++
++#ifdef DWC_XPLORER
++MODULE_ALIAS("platform:xplorer-dwc3");
++#else
++MODULE_ALIAS("platform:dwc3");
++#endif
++
++#else /* DWC_REPLACE_DWC3 */
++
++static const struct platform_device_id dwc_usb3_platform_ids[] = {
++	{ "dwc-usb3-platform", 0 },
++	{ "dwc_usb3", 0 },
++	{ }
++};
++MODULE_DEVICE_TABLE(platform, dwc_usb3_platform_ids);
++
++static struct platform_driver dwc_usb3_platform_driver = {
++	.id_table	= dwc_usb3_platform_ids,
++	.probe		= dwc_usb3_platform_probe,
++	.remove		= __devexit_p(dwc_usb3_platform_remove),
++	.driver		= {
++		.owner	= THIS_MODULE,
++		.name	= "dwc_usb3",
++	}
++};
++
++/**
++ * This function is called when the DWC_usb3 driver is loaded into the kernel
++ * with the insmod command. It registers the dwc_usb3_driver structure with the
++ * appropriate bus driver. This will cause the dwc_usb3_platform_probe function
++ * to be called. In addition, the bus driver will automatically expose
++ * attributes defined for the device and driver in the special sysfs file
++ * system.
++ */
++static int __init dwc_usb3_driver_init(void)
++{
++	int retval;
++
++	printk("\n###%s,%d,reg(c110)=0x%x\n",__func__,__LINE__,readl((IO_ADDRESS(0x1018c110))));
++	printk("\n###%s,%d\n",__func__,__LINE__);
++	printk(KERN_INFO "%s: %s version %s\n", dwc_driver_name,
++	       DWC_DRIVER_DESC, DWC_DRIVER_VERSION);
++
++	retval = platform_driver_register(&dwc_usb3_platform_driver);
++	if (retval < 0) {
++		printk(KERN_ERR "%s retval=%d\n", __func__, retval);
++		return retval;
++	}
++
++	printk(KERN_INFO "%s: module installed\n", dwc_driver_name);
++	return retval;
++}
++module_init(dwc_usb3_driver_init);
++
++/**
++ * This function is called when the DWC_usb3 driver is removed from the kernel
++ * with the rmmod command. The driver unregisters itself with its bus driver.
++ *
++ */
++static void __exit dwc_usb3_driver_exit(void)
++{
++	printk(KERN_DEBUG "%s: driver_exit()\n", dwc_driver_name);
++
++	platform_driver_unregister(&dwc_usb3_platform_driver);
++
++	printk(KERN_INFO "%s: module removed\n", dwc_driver_name);
++}
++module_exit(dwc_usb3_driver_exit);
++#endif
+diff --git a/drivers/usb/gadget/udc/hiudc3/linux_sysfs.c b/drivers/usb/gadget/udc/hiudc3/linux_sysfs.c
+new file mode 100644
+index 0000000..5502de1
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc3/linux_sysfs.c
+@@ -0,0 +1,469 @@
++/** @file
++ */
++
++#include "os_defs.h"
++#include "hw.h"
++#include "usb.h"
++#include "pcd.h"
++#include "dev.h"
++#include "os_dev.h"
++#include "cil.h"
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,17,0)
++# undef VERIFY_OCTAL_PERMISSIONS
++# define VERIFY_OCTAL_PERMISSIONS(perms)				\
++	(BUILD_BUG_ON_ZERO((perms) < 0) +				\
++	 BUILD_BUG_ON_ZERO((perms) > 0777) +				\
++	/* User perms >= group perms >= other perms */			\
++	 BUILD_BUG_ON_ZERO(((perms) >> 6) < (((perms) >> 3) & 7)) +	\
++	 BUILD_BUG_ON_ZERO((((perms) >> 3) & 7) < ((perms) & 7)) +	\
++	 (perms))
++#endif
++
++#ifdef CONFIG_USB_OTG_DWC
++extern int otg_start_rsp(struct usb_otg *otg);
++extern int otg_end_session(struct usb_otg *otg);
++#endif
++
++/*-------------------------------------------------------------------------*/
++/* Encapsulate the module parameter settings */
++
++dwc_usb3_core_params_t dwc_usb3_module_params = {
++	.burst = 1,
++	.newcore = 0,
++	.phy = 2,
++	.wakeup = 0,
++#ifdef DWC_STAR_9000446947_WORKAROUND
++	.pwrctl = 0,
++#else
++# if defined(DWC_STAR_9000449814_WORKAROUND) || \
++     defined(DWC_STAR_9000459034_WORKAROUND)
++	.pwrctl = 2,
++# else
++	.pwrctl = 3,
++# endif
++#endif
++	.lpmctl = 1,
++	.phyctl = 1,
++	.usb2mode = 0,
++	.hibernate = 0,
++	.hiberdisc = 1,
++	.clkgatingen = 1,
++	.ssdisquirk = 1,
++	.nobos = 0,
++	.loop = 0,
++	.nump = 16,
++	.newcsr = 1,
++	.rxfsz = 0,
++	.txfsz = { 0, },
++	.txfsz_cnt = 0,
++	.besl = 0,
++	.baseline_besl = 0,
++	.deep_besl = 0,
++	.ebc = 0,
++};
++
++module_param_named(burst, dwc_usb3_module_params.burst, int, S_IRUGO|S_IWUSR);
++MODULE_PARM_DESC(burst, "Enable gadget to set USB 3.0 max burst size "
++			"(0=no, 1=yes) (default=yes)");
++
++module_param_named(new, dwc_usb3_module_params.newcore, int, S_IRUGO|S_IWUSR);
++MODULE_PARM_DESC(new, "Force new core behavior [rev >= 1.09a] (0=no, 1=yes) "
++		      "(default=no)");
++
++module_param_named(phy, dwc_usb3_module_params.phy, int, S_IRUGO|S_IWUSR);
++MODULE_PARM_DESC(phy, "Select PHY type (0=RocketIO, 1=old-Synopsys, "
++		      "2=TI/Synopsys-8bit-UTMI/ULPI 3=Synopsys-16bit-UTMI) "
++		      "(default=2)");
++
++module_param_named(wakeup, dwc_usb3_module_params.wakeup, int, S_IRUGO|S_IWUSR);
++MODULE_PARM_DESC(wakeup, "Enable remote wakeup (0=no, 1=yes) (default=no)");
++
++module_param_named(pwrctl, dwc_usb3_module_params.pwrctl, int, S_IRUGO|S_IWUSR);
++MODULE_PARM_DESC(pwrctl, "Enable U1/U2 power states (bit0=U1, bit1=U2) "
++			 "(default=U1+U2)");
++
++module_param_named(lpmctl, dwc_usb3_module_params.lpmctl, int, S_IRUGO|S_IWUSR);
++MODULE_PARM_DESC(lpmctl, "Enable LPM power control (0=no, 1=AppL1Res-0, "
++			 "2=AppL1Res-1) (default=1)");
++
++module_param_named(phyctl, dwc_usb3_module_params.phyctl, int, S_IRUGO|S_IWUSR);
++MODULE_PARM_DESC(phyctl, "Enable PHY suspend (0=no, 1=yes) (default=yes)");
++
++module_param_named(usb2mode, dwc_usb3_module_params.usb2mode, int,
++		   S_IRUGO|S_IWUSR);
++MODULE_PARM_DESC(usb2mode, "Force the core to connect in USB 2.0 mode at the "
++			   "given speed (0=no, 1=FS, 2=HS) (default=no)");
++
++module_param_named(hibernate, dwc_usb3_module_params.hibernate, int,
++		   S_IRUGO|S_IWUSR);
++MODULE_PARM_DESC(hibernate, "Enable hibernation mode (0=no, 1=yes) "
++			    "(default=no)");
++
++module_param_named(hiberdisc, dwc_usb3_module_params.hiberdisc, int,
++		   S_IRUGO|S_IWUSR);
++MODULE_PARM_DESC(hiberdisc, "Enter hibernation when disconnected "
++			    "(0=no, 1=yes) (default=yes)");
++
++module_param_named(clkgatingen, dwc_usb3_module_params.clkgatingen, int,
++		   S_IRUGO|S_IWUSR);
++MODULE_PARM_DESC(clkgatingen, "Enable clock gating (0=no, 1=yes) "
++			      "(default=yes)");
++
++module_param_named(ssdisquirk, dwc_usb3_module_params.ssdisquirk, int,
++		   S_IRUGO|S_IWUSR);
++MODULE_PARM_DESC(ssdisquirk, "Enable SS_DIS Quirk (0=no, 1=yes) (default=yes)");
++
++module_param_named(nobos, dwc_usb3_module_params.nobos, int, S_IRUGO|S_IWUSR);
++MODULE_PARM_DESC(nobos, "Fail GetDescriptor(BOS) request at USB2 speeds "
++			"(0=no, 1=yes) (default=no)");
++
++module_param_named(nump, dwc_usb3_module_params.nump, int, S_IRUGO|S_IWUSR);
++MODULE_PARM_DESC(nump, "Set NUMP to given value (1-16) (default=16)");
++
++module_param_named(newcsr, dwc_usb3_module_params.newcsr, int, S_IRUGO|S_IWUSR);
++MODULE_PARM_DESC(newcsr, "Use a newer HAPS bitfile with a 64K PCI BAR size "
++			 "instead of the older 1MB PCI BAR size (0=no, 1=yes) "
++			 "(default=yes)");
++
++module_param_named(loop, dwc_usb3_module_params.loop, int, S_IRUGO|S_IWUSR);
++MODULE_PARM_DESC(loop, "Number of times to loop in reset (for debug only)");
++
++module_param_named(rxfsz, dwc_usb3_module_params.rxfsz, int, S_IRUGO|S_IWUSR);
++MODULE_PARM_DESC(rxfsz, "Size of Rx FIFO in bytes");
++
++module_param_array_named(txfsz, dwc_usb3_module_params.txfsz, int,
++			 &dwc_usb3_module_params.txfsz_cnt, S_IRUGO|S_IWUSR);
++MODULE_PARM_DESC(txfsz, "Size of Tx FIFOs in bytes");
++
++module_param_named(besl, dwc_usb3_module_params.besl, int, S_IRUGO|S_IWUSR);
++MODULE_PARM_DESC(besl, "Enable besl support");
++
++module_param_named(baseline_besl, dwc_usb3_module_params.baseline_besl, int,
++		   S_IRUGO|S_IWUSR);
++MODULE_PARM_DESC(baseline_besl, "Set the baseline besl value");
++
++module_param_named(deep_besl, dwc_usb3_module_params.deep_besl, int,
++		   S_IRUGO|S_IWUSR);
++MODULE_PARM_DESC(deep_besl, "Set the deep besl value");
++
++module_param_named(ebc, dwc_usb3_module_params.ebc, int, S_IRUGO|S_IWUSR);
++MODULE_PARM_DESC(ebc, "Enable EBC support on all Bulk endpoints");
++
++static dwc_usb3_device_t *get_usb3_device(struct device *dev)
++{
++#ifdef DWC_PLATFORM_DEV
++	struct platform_device *device =
++			container_of(dev, struct platform_device, dev);
++	dwc_usb3_device_t *usb3_dev = platform_get_drvdata(device);
++#else
++	struct pci_dev *device = container_of(dev, struct pci_dev, dev);
++	dwc_usb3_device_t *usb3_dev = pci_get_drvdata(device);
++#endif
++
++	return usb3_dev;
++}
++
++static ssize_t show_wakeup(struct device *dev, struct device_attribute *attr,
++			   char *buf)
++{
++	dwc_usb3_device_t *usb3_dev = get_usb3_device(dev);
++
++	return sprintf(buf, "%d\n", usb3_dev->pcd.wkup_rdy);
++}
++
++static ssize_t store_wakeup(struct device *dev, struct device_attribute *attr,
++			    const char *buf, size_t count)
++{
++	dwc_usb3_device_t	*usb3_dev = get_usb3_device(dev);
++	int			ret;
++
++	ret = dwc_usb3_wakeup(usb3_dev->pcd.gadget);
++
++	return ret < 0 ? ret : count;
++}
++
++/* /sys/module/dwc_usb3/drivers/pci:dwc_usb3/nnnn:nn:nn.n/wakeup */
++static DEVICE_ATTR(wakeup, 0666, show_wakeup, store_wakeup);
++
++static ssize_t show_disrupt(struct device *dev, struct device_attribute *attr,
++			    char *buf)
++{
++	return sprintf(buf, "%d\n", 0);
++}
++
++static ssize_t store_disrupt(struct device *dev, struct device_attribute *attr,
++			     const char *buf, size_t count)
++{
++	dwc_usb3_device_t	*usb3_dev = get_usb3_device(dev);
++	unsigned long		tmp = 0;
++	ssize_t			rc;
++	unsigned long		flags;
++
++	sscanf(buf, "%ld", &tmp);
++	rc = strnlen(buf, count);
++	printk(USB3_DWC "disrupt: %ld ms\n", tmp);
++
++	spin_lock_irqsave(&usb3_dev->pcd.lock, flags);
++	mdelay(tmp);
++	spin_unlock_irqrestore(&usb3_dev->pcd.lock, flags);
++	return rc;
++}
++
++/* /sys/module/dwc_usb3/drivers/pci:dwc_usb3/nnnn:nn:nn.n/disrupt */
++static DEVICE_ATTR(disrupt, 0666, show_disrupt, store_disrupt);
++
++static ssize_t show_hiber(struct device *dev, struct device_attribute *attr,
++			  char *buf)
++{
++	return sprintf(buf, "%d\n", 0);
++}
++
++static ssize_t store_hiber(struct device *dev, struct device_attribute *attr,
++			   const char *buf, size_t count)
++{
++	dwc_usb3_device_t	*usb3_dev = get_usb3_device(dev);
++	int			tmp = 0;
++	ssize_t			rc;
++	unsigned long		flags;
++
++	sscanf(buf, "%d", &tmp);
++	rc = strnlen(buf, count);
++	printk(USB3_DWC "hibernate: save_state=%d\n", tmp);
++
++	spin_lock_irqsave(&usb3_dev->pcd.lock, flags);
++	dwc_enter_hibernation(&usb3_dev->pcd, tmp);
++	spin_unlock_irqrestore(&usb3_dev->pcd.lock, flags);
++	return rc;
++}
++
++/* /sys/module/dwc_usb3/drivers/pci:dwc_usb3/nnnn:nn:nn.n/hibernate */
++static DEVICE_ATTR(hibernate, 0666, show_hiber, store_hiber);
++
++static ssize_t show_restore(struct device *dev, struct device_attribute *attr,
++			    char *buf)
++{
++	return sprintf(buf, "%d\n", 0);
++}
++
++static ssize_t store_restore(struct device *dev, struct device_attribute *attr,
++			     const char *buf, size_t count)
++{
++	dwc_usb3_device_t	*usb3_dev = get_usb3_device(dev);
++	int			tmp = 0;
++	ssize_t			rc;
++	unsigned long		flags;
++
++	sscanf(buf, "%d", &tmp);
++	rc = strnlen(buf, count);
++	printk(USB3_DWC "restore: restore_state=%d\n", tmp);
++
++	spin_lock_irqsave(&usb3_dev->pcd.lock, flags);
++	tmp = dwc_exit_hibernation(&usb3_dev->pcd, tmp);
++	spin_unlock_irqrestore(&usb3_dev->pcd.lock, flags);
++	printk(USB3_DWC "dwc_exit_hibernation() returned %d\n", tmp);
++	return rc;
++}
++
++/* /sys/module/dwc_usb3/drivers/pci:dwc_usb3/nnnn:nn:nn.n/restore */
++static DEVICE_ATTR(restore, 0666, show_restore, store_restore);
++
++#ifdef CONFIG_USB_OTG_DWC
++
++static ssize_t store_srp(struct device *dev, struct device_attribute *attr,
++			 const char *buf, size_t count)
++{
++	struct usb_phy *phy;
++	struct usb_otg *otg;
++
++	phy = usb_get_phy(USB_PHY_TYPE_USB3);
++	if (IS_ERR(phy) || !phy) {
++		if (!IS_ERR(phy))
++			usb_put_phy(phy);
++		return count;
++	}
++
++	otg = phy->otg;
++	if (!otg) {
++		usb_put_phy(phy);
++		return count;
++	}
++
++	otg_start_srp(otg);
++	usb_put_phy(phy);
++	return count;
++}
++static DEVICE_ATTR(srp, 0222, NULL, store_srp);
++
++static ssize_t store_end(struct device *dev, struct device_attribute *attr,
++			 const char *buf, size_t count)
++{
++	struct usb_phy *phy;
++	struct usb_otg *otg;
++
++	phy = usb_get_phy(USB_PHY_TYPE_USB3);
++	if (IS_ERR(phy) || !phy) {
++		if (!IS_ERR(phy))
++			usb_put_phy(phy);
++		return count;
++	}
++
++	otg = phy->otg;
++	if (!otg) {
++		usb_put_phy(phy);
++		return count;
++	}
++
++	otg_end_session(otg);
++	usb_put_phy(phy);
++	return count;
++}
++static DEVICE_ATTR(end, 0222, NULL, store_end);
++
++static ssize_t store_hnp(struct device *dev, struct device_attribute *attr,
++			 const char *buf, size_t count)
++{
++	dwc_usb3_device_t *usb3_dev = get_usb3_device(dev);
++
++	if (usb3_dev->pcd.b_hnp_enable) {
++		dev_info(dev, "b_hnp_enable is TRUE\n");
++		usb3_dev->pcd.b_hnp_enable = 0;
++		usb3_dev->pcd.wants_host = 0;
++		dwc_usb3_start_hnp(&usb3_dev->pcd);
++	} else {
++		dev_info(dev, "b_hnp_enable is FALSE\n");
++		usb3_dev->pcd.wants_host = 1;
++		/* TODO if we don't receive the SET_FEATURE within 4 secs,
++		 * reset this value
++		 */
++	}
++	return count;
++}
++static DEVICE_ATTR(hnp, 0222, NULL, store_hnp);
++
++static ssize_t store_rsp(struct device *dev, struct device_attribute *attr,
++			 const char *buf, size_t count)
++{
++	struct usb_phy *phy;
++	struct usb_otg *otg;
++
++	phy = usb_get_phy(USB_PHY_TYPE_USB3);
++	if (IS_ERR(phy) || !phy) {
++		if (!IS_ERR(phy))
++			usb_put_phy(phy);
++		return count;
++	}
++
++	otg = phy->otg;
++	if (!otg) {
++		usb_put_phy(phy);
++		return count;
++	}
++
++	otg_start_rsp(otg);
++	usb_put_phy(phy);
++	return count;
++}
++static DEVICE_ATTR(rsp, 0222, NULL, store_rsp);
++
++#endif /* CONFIG_USB_OTG_DWC */
++
++static ssize_t show_lpm_nyet(struct device *dev,
++			struct device_attribute *attr, char *buf)
++{
++	dwc_usb3_device_t *usb3_dev = get_usb3_device(dev);
++	dwc_usb3_dev_global_regs_t __iomem *regs =
++			usb3_dev->pcd.dev_global_regs;
++	u32 dctl = dwc_rd32(usb3_dev, &regs->dctl);
++	u32 nyet = (dctl & DWC_DCTL_LPM_NYET_THRESH_BITS) >>
++			DWC_DCTL_LPM_NYET_THRESH_SHIFT;
++
++	return sprintf(buf, "0x%x\n", nyet);
++}
++
++static ssize_t store_lpm_nyet(struct device *dev,
++			struct device_attribute *attr,
++			const char *buf, size_t count)
++{
++	dwc_usb3_device_t *usb3_dev = get_usb3_device(dev);
++	dwc_usb3_dev_global_regs_t __iomem *regs =
++			usb3_dev->pcd.dev_global_regs;
++	u32 dctl = dwc_rd32(usb3_dev, &regs->dctl);
++	u32 value = simple_strtol(buf, NULL, 16);
++
++	value = (value << DWC_DCTL_LPM_NYET_THRESH_SHIFT) &
++			DWC_DCTL_LPM_NYET_THRESH_BITS;
++
++	dctl &= ~(DWC_DCTL_LPM_NYET_THRESH_BITS);
++	dctl |= value;
++
++	dwc_wr32(usb3_dev, &regs->dctl, dctl);
++	return count;
++}
++
++/* /sys/module/dwc_usb3/drivers/pci:dwc_usb3/nnnn:nn:nn.n/wakeup */
++static DEVICE_ATTR(lpm_nyet, 0666, show_lpm_nyet, store_lpm_nyet);
++
++void dwc_usb3_remove_dev_files(struct device *dev)
++{
++#ifdef CONFIG_USB_OTG_DWC
++	device_remove_file(dev, &dev_attr_end);
++	device_remove_file(dev, &dev_attr_srp);
++	device_remove_file(dev, &dev_attr_rsp);
++	device_remove_file(dev, &dev_attr_hnp);
++#endif
++	device_remove_file(dev, &dev_attr_restore);
++	device_remove_file(dev, &dev_attr_hibernate);
++	device_remove_file(dev, &dev_attr_disrupt);
++	device_remove_file(dev, &dev_attr_wakeup);
++	device_remove_file(dev, &dev_attr_lpm_nyet);
++}
++
++int dwc_usb3_create_dev_files(struct device *dev)
++{
++	int retval;
++
++	retval = device_create_file(dev, &dev_attr_wakeup);
++	if (retval)
++		goto fail;
++
++	retval = device_create_file(dev, &dev_attr_disrupt);
++	if (retval)
++		goto fail;
++
++	retval = device_create_file(dev, &dev_attr_hibernate);
++	if (retval)
++		goto fail;
++
++	retval = device_create_file(dev, &dev_attr_restore);
++	if (retval)
++		goto fail;
++
++#ifdef CONFIG_USB_OTG_DWC
++	retval = device_create_file(dev, &dev_attr_hnp);
++	if (retval)
++		goto fail;
++
++	retval = device_create_file(dev, &dev_attr_rsp);
++	if (retval)
++		goto fail;
++
++	retval = device_create_file(dev, &dev_attr_srp);
++	if (retval)
++		goto fail;
++
++	retval = device_create_file(dev, &dev_attr_end);
++	if (retval)
++		goto fail;
++#endif
++
++	retval = device_create_file(dev, &dev_attr_lpm_nyet);
++	if (retval)
++		goto fail;
++
++	return 0;
++
++fail:
++	dev_err(dev, "Failed to create one or more sysfs files!!\n");
++	return retval;
++}
+diff --git a/drivers/usb/gadget/udc/hiudc3/no_os/no_os_defs.h b/drivers/usb/gadget/udc/hiudc3/no_os/no_os_defs.h
+new file mode 100644
+index 0000000..54d2af2
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc3/no_os/no_os_defs.h
+@@ -0,0 +1,363 @@
++#ifndef _DWC_NO_OS_DEFS_H_
++#define _DWC_NO_OS_DEFS_H_
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/**
++ * @file
++ *
++ * This file contains OS-specific includes and definitions.
++ *
++ */
++
++#undef linux
++#undef __linux
++#undef __linux__
++
++#ifdef LINUXTEST
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/init.h>
++#include <linux/device.h>
++#include <linux/errno.h>
++#include <linux/types.h>
++#include <linux/slab.h>
++#include <linux/list.h>
++#include <linux/interrupt.h>
++#include <linux/ctype.h>
++#include <linux/string.h>
++#include <linux/dma-mapping.h>
++#include <linux/jiffies.h>
++#include <linux/delay.h>
++#include <linux/timer.h>
++#include <linux/kthread.h>
++#include <linux/workqueue.h>
++#include <linux/freezer.h>
++#include <linux/stat.h>
++#include <linux/pci.h>
++
++#include <linux/version.h>
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
++# include <linux/irq.h>
++#endif
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
++# include <asm/irq.h>
++#endif
++
++#include <asm/io.h>
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
++typedef int		gfp_t;
++#endif
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
++# define IRQF_SHARED	SA_SHIRQ
++#endif
++
++/** @{ */
++/** Data type for DMA addresses */
++typedef dma_addr_t		dwc_dma_t;
++#define DWC_DMA_ADDR_INVALID	(~(dwc_dma_t)0)
++/** @} */
++
++/** Compiler 'packed' attribute */
++#define UPACKED		__attribute__ ((__packed__))
++
++/** Compiler 'aligned(16)' attribute */
++#define UALIGNED16	__attribute__ ((__aligned__(16)))
++
++#define dwc_init_spinlock(d, p)			spin_lock_init(p)
++#define dwc_acquire_spinlock(d, p)		spin_lock(p)
++#define dwc_release_spinlock(d, p)		spin_unlock(p)
++#define dwc_acquire_spinlock_irq(d, p, f)	spin_lock_irqsave(p, f)
++#define dwc_release_spinlock_irq(d, p, f)	spin_unlock_irqrestore(p, f)
++
++#else /* !LINUXTEST */
++
++#include <stdint.h>
++#include <stddef.h>
++#include <stdarg.h>
++#include <stdio.h>	// for printf
++#include <string.h>	// for memcpy
++
++/** @{ */
++/** Data types needed by the PCD */
++typedef uint64_t	u64, u_int64_t;
++typedef uint32_t	u32, u_int32_t;
++typedef uint16_t	u16, u_int16_t;
++typedef uint8_t		u8, u_int8_t;
++
++typedef int64_t		s64;
++typedef int32_t		s32;
++typedef int16_t		s16;
++typedef int8_t		s8;
++
++typedef unsigned long	u_long;
++typedef unsigned int	u_int;
++typedef unsigned short	u_short;
++typedef unsigned char	u_char;
++/** @} */
++
++/** @{ */
++/** Data type for DMA addresses */
++typedef unsigned long		dwc_dma_t;
++#define DWC_DMA_ADDR_INVALID	(~(dwc_dma_t)0)
++/** @} */
++
++/** Compiler 'packed' attribute */
++#define UPACKED		__attribute__ ((__packed__))
++
++/** Compiler 'aligned(16)' attribute */
++#define UALIGNED16	__attribute__ ((__aligned__(16)))
++
++/** I/O memory attribute for pointers. Needed for Linux "sparse" tool. */
++#define __iomem		/* */
++
++#define KERN_DEBUG	""	/* debug messages */
++#define KERN_INFO	""	/* informational messages */
++#define KERN_WARNING	""	/* warning messages */
++#define KERN_ERR	""	/* error messages */
++
++// from /usr/include/asm-x86_64/errno.h
++#define EIO		5	/* I/O error */
++#define EAGAIN		11	/* Try again */
++#define ENOMEM		12	/* Out of memory */
++#define EBUSY		16	/* Device or resource busy */
++#define ENODEV		19	/* No such device */
++#define EINVAL		22	/* Invalid argument */
++#define ENOSPC		28	/* No space left on device */
++#define EPIPE		32	/* Broken pipe */
++#define EDOM		33	/* Math argument out of domain of func */
++#define ENODATA		61	/* No data available */
++#define ENOSR		63	/* Out of streams resources */
++#define ECOMM		70	/* Communication error on send */
++#define EPROTO		71	/* Protocol error */
++#define EOVERFLOW	75	/* Value too large for defined data type */
++#define ERESTART	85	/* Interrupted system call should be restarted */
++#define EOPNOTSUPP	95	/* Operation not supported on transport endpoint */
++#define ECONNABORTED	103	/* Software caused connection abort */
++#define ECONNRESET	104	/* Connection reset by peer */
++#define ESHUTDOWN	108	/* Cannot send after transport endpoint shutdown */
++#define ETIMEDOUT	110	/* Connection timed out */
++#define EINPROGRESS	115	/* Operation now in progress */
++
++/** Write memory barrier macro */
++#define wmb()		do {} while (0)
++
++#define interrupt_disable()	0
++#define interrupt_enable()	do {} while (0)
++
++#define dwc_init_spinlock(d, p)			do {} while (0)
++#define dwc_acquire_spinlock(d, p)		do {} while (0)
++#define dwc_release_spinlock(d, p)		do {} while (0)
++#define dwc_acquire_spinlock_irq(d, p, f)	do { (f) = interrupt_disable(); } while (0)
++#define dwc_release_spinlock_irq(d, p, f)	do { if (f) interrupt_enable(); } while (0)
++
++struct task_struct {
++	int dummy;
++};
++
++struct tasklet_struct {
++	int dummy;
++};
++
++#endif /* !LINUXTEST */
++
++#include "usb.h"
++#include "dwc_list.h"
++
++/** @name Error Codes */
++/** @{ */
++#define DWC_E_INVALID		EINVAL
++#define DWC_E_NO_MEMORY		ENOMEM
++#define DWC_E_NO_DEVICE		ENODEV
++#define DWC_E_NOT_SUPPORTED	EOPNOTSUPP
++#define DWC_E_TIMEOUT		ETIMEDOUT
++#define DWC_E_BUSY		EBUSY
++#define DWC_E_AGAIN		EAGAIN
++#define DWC_E_RESTART		ERESTART
++#define DWC_E_ABORT		ECONNABORTED
++#define DWC_E_SHUTDOWN		ESHUTDOWN
++#define DWC_E_NO_DATA		ENODATA
++#define DWC_E_DISCONNECT	ECONNRESET
++#define DWC_E_UNKNOWN		EINVAL
++#define DWC_E_NO_STREAM_RES	ENOSR
++#define DWC_E_COMMUNICATION	ECOMM
++#define DWC_E_OVERFLOW		EOVERFLOW
++#define DWC_E_PROTOCOL		EPROTO
++#define DWC_E_IN_PROGRESS	EINPROGRESS
++#define DWC_E_PIPE		EPIPE
++#define DWC_E_IO		EIO
++#define DWC_E_NO_SPACE		ENOSPC
++#define DWC_E_DOMAIN		EDOM
++/** @} */
++
++/**
++ * The number of DMA Descriptors (TRBs) to allocate for each endpoint type.
++ * NOTE: The driver currently supports more than 1 TRB for Isoc EPs only.
++ * So the values for Bulk and Intr must be 1.
++ */
++#define DWC_NUM_BULK_TRBS	1
++#define DWC_NUM_INTR_TRBS	1
++#define DWC_NUM_ISOC_TRBS	32
++
++/**
++ * These parameters may be specified when loading the module. They define how
++ * the DWC_usb3 controller should be configured. The parameter values are passed
++ * to the CIL initialization routine dwc_usb3_pcd_common_init().
++ */
++typedef struct dwc_usb3_core_params {
++	int burst;
++	int newcore;
++	int phy;
++	int wakeup;
++	int pwrctl;
++	int lpmctl;
++	int phyctl;
++	int usb2mode;
++	int hibernate;
++	int hiberdisc;
++	int clkgatingen;
++	int ssdisquirk;
++	int nobos;
++	int loop;
++	int nump;
++	int newcsr;
++	int rxfsz;
++	int txfsz[16];
++	int txfsz_cnt;
++	int baseline_besl;
++	int deep_besl;
++	int besl;
++	int ebc;
++} dwc_usb3_core_params_t;
++
++// linux/usb/gadget.h
++
++/**
++ * Platform-specific USB endpoint
++ */
++typedef struct usb_ep {
++	const void	*desc;
++	const void	*comp_desc;
++	unsigned	maxpacket:16;
++	u8		address;
++} usb_ep_t;
++
++/**
++ * Platform-specific USB request
++ */
++typedef struct usb_request {
++	void		*buf;
++	unsigned	length;
++	dwc_dma_t	dma;
++
++	unsigned	stream_id:16;
++	unsigned	zero:1;
++
++	void		(*complete)(usb_ep_t *ep, struct usb_request *req);
++
++	int		status;
++	unsigned	actual;
++} usb_request_t;
++
++/**
++ */
++static inline void dwc_usb3_task_schedule(struct tasklet_struct *tasklet)
++{
++#ifdef LINUXTEST
++	tasklet_schedule(tasklet);
++#endif
++}
++
++/* Make the following structure type definitions "packed" if using a Microsoft
++ * compiler. The UPACKED attribute (defined above) embedded in the structure
++ * type definitions does the same thing for GCC. Other compilers may need
++ * something different.
++ */
++#ifdef _MSC_VER
++#include <pshpack1.h>
++#endif
++
++/**
++ */
++typedef struct fs_config_desc_st {
++	usb_config_descriptor_t			config_desc;
++	usb_interface_descriptor_t		intf_desc;
++	usb_endpoint_descriptor_t		bulk_in_ep_desc;
++	usb_endpoint_descriptor_t		bulk_out_ep_desc;
++} UPACKED fs_config_desc_t;
++
++/**
++ */
++typedef struct hs_config_desc_st {
++	usb_config_descriptor_t			config_desc;
++	usb_interface_descriptor_t		intf_desc;
++	usb_endpoint_descriptor_t		bulk_in_ep_desc;
++	usb_endpoint_descriptor_t		bulk_out_ep_desc;
++} UPACKED hs_config_desc_t;
++
++/**
++ */
++typedef struct ss_config_desc_st {
++	usb_config_descriptor_t			config_desc;
++	usb_interface_descriptor_t		intf_desc;
++	usb_endpoint_descriptor_t		bulk_in_ep_desc;
++	ss_endpoint_companion_descriptor_t	bulk_in_ss_ep_comp_desc;
++	usb_endpoint_descriptor_t		bulk_out_ep_desc;
++	ss_endpoint_companion_descriptor_t	bulk_out_ss_ep_comp_desc;
++} UPACKED ss_config_desc_t;
++
++/* Stop packing structure type definitions */
++#ifdef _MSC_VER
++#include <poppack.h>
++#endif
++
++/* These structures are defined in no_os_ep0.c */
++extern fs_config_desc_t fs_config_desc;
++extern hs_config_desc_t hs_config_desc;
++extern ss_config_desc_t ss_config_desc;
++
++/**
++ * Function driver API routines
++ */
++
++struct dwc_usb3_device;	/* so the simulation code can include just this file */
++
++extern dwc_usb3_core_params_t usb3ss_module_params;
++
++#ifndef LINUXTEST
++extern struct dwc_usb3_device *dwc_usb3_driver_init(u32 base_addr_dwc);
++extern void dwc_usb3_driver_remove(void);
++extern void dwc_usb3_common_irq(int irq, void *dev);
++#endif
++
++extern usb_ep_t *dwc_usb3_ep_enable(struct dwc_usb3_device *usb3_dev, const void *epdesc,
++				    const void *epcomp);
++extern int dwc_usb3_ep_disable(struct dwc_usb3_device *usb3_dev, usb_ep_t *usb_ep);
++extern usb_request_t *dwc_usb3_alloc_request(struct dwc_usb3_device *usb3_dev, usb_ep_t *usb_ep);
++extern void dwc_usb3_free_request(struct dwc_usb3_device *usb3_dev, usb_ep_t *usb_ep,
++				  usb_request_t *usb_req);
++extern int dwc_usb3_ep_queue(struct dwc_usb3_device *usb3_dev, usb_ep_t *usb_ep,
++			     usb_request_t *usb_req);
++extern int dwc_usb3_ep_dequeue(struct dwc_usb3_device *usb3_dev, usb_ep_t *usb_ep,
++			       usb_request_t *usb_req);
++extern int dwc_usb3_wait_pme(struct dwc_usb3_device *usb3_dev);
++extern int dwc_usb3_handle_pme_intr(struct dwc_usb3_device *usb3_dev);
++
++extern int dwc_usb3_function_init(struct dwc_usb3_device *usb3_dev);
++extern void dwc_usb3_function_remove(struct dwc_usb3_device *usb3_dev);
++extern int dwc_usb3_function_connect(struct dwc_usb3_device *usb3_dev, int speed);
++extern int dwc_usb3_function_disconnect(struct dwc_usb3_device *usb3_dev);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* _DWC_NO_OS_DEFS_H_ */
+diff --git a/drivers/usb/gadget/udc/hiudc3/no_os/no_os_dev.h b/drivers/usb/gadget/udc/hiudc3/no_os/no_os_dev.h
+new file mode 100644
+index 0000000..0daeb86
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc3/no_os/no_os_dev.h
+@@ -0,0 +1,198 @@
++#ifndef _DWC_NO_OS_DEV_H_
++#define _DWC_NO_OS_DEV_H_
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/** @file
++ */
++
++/** Wrapper routine for _handshake() */
++#define handshake(_dev_, _ptr_, _mask_, _done_)	\
++	_handshake(_dev_, _ptr_, _mask_, _done_)
++
++/** Takes a usb req pointer and returns the associated pcd req pointer */
++#define dwc_usb3_get_pcd_req(usbreq)			\
++	((dwc_usb3_pcd_req_t *)((char *)(usbreq) -	\
++		offsetof(struct dwc_usb3_pcd_req, usb_req)))
++
++/** Takes a usb ep pointer and returns the associated pcd ep pointer */
++#define dwc_usb3_get_pcd_ep(usbep)			\
++	((dwc_usb3_pcd_ep_t *)((char *)(usbep) -	\
++		offsetof(struct dwc_usb3_pcd_ep, usb_ep)))
++
++#ifdef LINUXTEST
++
++#define printf	printk
++
++/** @{ */
++/**
++ * Register read/write.
++ */
++static inline u32 dwc_rd32(struct dwc_usb3_device *dev, volatile u32 __iomem *adr)
++{
++	return readl(adr);
++}
++
++static inline void dwc_wr32(struct dwc_usb3_device *dev, volatile u32 __iomem *adr, u32 val)
++{
++	writel(val, adr);
++}
++/** @} */
++
++/** @{ */
++/**
++ * Non-sleeping delays.
++ */
++#define dwc_udelay(dev, us)	udelay(us)
++#define dwc_mdelay(dev, ms)	mdelay(ms)
++/** @} */
++
++/**
++ * Sleeping delay.
++ */
++#define dwc_msleep(dev, ms)	msleep(ms)
++
++#else /* !LINUXTEST */
++
++/** @{ */
++/**
++ * Register read/write.
++ */
++static inline u32 dwc_rd32(struct dwc_usb3_device *dev, volatile u32 __iomem *adr)
++{
++	return *adr;
++}
++
++static inline void dwc_wr32(struct dwc_usb3_device *dev, volatile u32 __iomem *adr, u32 val)
++{
++	*adr = val;
++}
++/** @} */
++
++/** @{ */
++/**
++ * Non-sleeping delays.
++ */
++#define dwc_udelay(dev, us)	do {} while (0)
++#define dwc_mdelay(dev, ms)	do {} while (0)
++/** @} */
++
++/**
++ * Sleeping delay.
++ */
++#define dwc_msleep(dev, ms)	do {} while (0)
++
++#endif /* LINUXTEST */
++
++/*
++ * Debugging support - vanishes in non-debug builds.
++ */
++
++/** Prefix string for print macros */
++#define USB3_DWC	"dwc_usb3: "
++
++/** @{ */
++/** Print a debug message */
++#ifdef DEBUG
++# define dwc_debug(dev, x...)	printf(KERN_DEBUG USB3_DWC x )
++#else
++# define dwc_debug(dev, x...)	do {} while (0)
++#endif /* DEBUG */
++
++# define dwc_debug0(dev, fmt)			dwc_debug(dev, fmt)
++# define dwc_debug1(dev, fmt, a)		dwc_debug(dev, fmt, a)
++# define dwc_debug2(dev, fmt, a, b)		dwc_debug(dev, fmt, a, b)
++# define dwc_debug3(dev, fmt, a, b, c)		dwc_debug(dev, fmt, a, b, c)
++# define dwc_debug4(dev, fmt, a, b, c, d)	dwc_debug(dev, fmt, a, b, c, d)
++# define dwc_debug5(dev, fmt, a, b, c, d, e) \
++			dwc_debug(dev, fmt, a, b, c, d, e)
++# define dwc_debug6(dev, fmt, a, b, c, d, e, f) \
++			dwc_debug(dev, fmt, a, b, c, d, e, f)
++# define dwc_debug7(dev, fmt, a, b, c, d, e, f, g) \
++			dwc_debug(dev, fmt, a, b, c, d, e, f, g)
++# define dwc_debug8(dev, fmt, a, b, c, d, e, f, g, h) \
++			dwc_debug(dev, fmt, a, b, c, d, e, f, g, h)
++# define dwc_debug9(dev, fmt, a, b, c, d, e, f, g, h, i) \
++			dwc_debug(dev, fmt, a, b, c, d, e, f, g, h, i)
++# define dwc_debug10(dev, fmt, a, b, c, d, e, f, g, h, i, j) \
++			dwc_debug(dev, fmt, a, b, c, d, e, f, g, h, i, j)
++/** @} */
++
++/** @{ */
++/** Print an isochronous debug message */
++#if defined(DEBUG) || defined(ISOC_DEBUG)
++# define dwc_isocdbg(dev, x...)		printf(KERN_DEBUG USB3_DWC x )
++#else
++# define dwc_isocdbg(dev, x...)		do {} while (0)
++#endif
++
++# define dwc_isocdbg0(dev, fmt)			dwc_isocdbg(dev, fmt)
++# define dwc_isocdbg1(dev, fmt, a)		dwc_isocdbg(dev, fmt, a)
++# define dwc_isocdbg2(dev, fmt, a, b)		dwc_isocdbg(dev, fmt, a, b)
++# define dwc_isocdbg3(dev, fmt, a, b, c)	dwc_isocdbg(dev, fmt, a, b, c)
++# define dwc_isocdbg4(dev, fmt, a, b, c, d) \
++			dwc_isocdbg(dev, fmt, a, b, c, d)
++# define dwc_isocdbg5(dev, fmt, a, b, c, d, e) \
++			dwc_isocdbg(dev, fmt, a, b, c, d, e)
++# define dwc_isocdbg6(dev, fmt, a, b, c, d, e, f) \
++			dwc_isocdbg(dev, fmt, a, b, c, d, e, f)
++/** @} */
++
++/** @{ */
++/** Print an Error message */
++#define dwc_error(dev, x...)	printf(KERN_ERR USB3_DWC x )
++
++#define dwc_error0(dev, fmt)			dwc_error(dev, fmt)
++#define dwc_error1(dev, fmt, a)			dwc_error(dev, fmt, a)
++#define dwc_error2(dev, fmt, a, b)		dwc_error(dev, fmt, a, b)
++#define dwc_error3(dev, fmt, a, b, c)		dwc_error(dev, fmt, a, b, c)
++#define dwc_error4(dev, fmt, a, b, c, d)	dwc_error(dev, fmt, a, b, c, d)
++/** @} */
++
++/** @{ */
++/** Print a Warning message */
++#define dwc_warn(dev, x...)	printf(KERN_WARNING USB3_DWC x )
++
++#define dwc_warn0(dev, fmt)			dwc_warn(dev, fmt)
++#define dwc_warn1(dev, fmt, a)			dwc_warn(dev, fmt, a)
++#define dwc_warn2(dev, fmt, a, b)		dwc_warn(dev, fmt, a, b)
++#define dwc_warn3(dev, fmt, a, b, c)		dwc_warn(dev, fmt, a, b, c)
++#define dwc_warn4(dev, fmt, a, b, c, d)		dwc_warn(dev, fmt, a, b, c, d)
++/** @} */
++
++/** @{ */
++/** Print an Informational message (normal but significant) */
++#define dwc_info(dev, x...)	printf(KERN_INFO USB3_DWC x )
++
++#define dwc_info0(dev, fmt)			dwc_info(dev, fmt)
++#define dwc_info1(dev, fmt, a)			dwc_info(dev, fmt, a)
++#define dwc_info2(dev, fmt, a, b)		dwc_info(dev, fmt, a, b)
++#define dwc_info3(dev, fmt, a, b, c)		dwc_info(dev, fmt, a, b, c)
++#define dwc_info4(dev, fmt, a, b, c, d)		dwc_info(dev, fmt, a, b, c, d)
++/** @} */
++
++/** @{ */
++/** Basic message printing */
++#define dwc_print(dev, x...)	printf(USB3_DWC x )
++
++#define dwc_print0(dev, fmt)			dwc_print(dev, fmt)
++#define dwc_print1(dev, fmt, a)			dwc_print(dev, fmt, a)
++#define dwc_print2(dev, fmt, a, b)		dwc_print(dev, fmt, a, b)
++#define dwc_print3(dev, fmt, a, b, c)		dwc_print(dev, fmt, a, b, c)
++#define dwc_print4(dev, fmt, a, b, c, d)	dwc_print(dev, fmt, a, b, c, d)
++#define dwc_print5(dev, fmt, a, b, c, d, e) \
++			dwc_print(dev, fmt, a, b, c, d, e)
++/** @} */
++
++extern int dwc_usb3_gadget_init(struct dwc_usb3_device *usb3_dev);
++extern void dwc_usb3_gadget_remove(struct dwc_usb3_device *usb3_dev);
++extern int dwc_usb3_no_os_setup(dwc_usb3_pcd_t *pcd, usb_device_request_t *ctrl);
++extern int dwc_usb3_function_setup(dwc_usb3_pcd_t *pcd, usb_device_request_t *ctrl);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* _DWC_NO_OS_DEV_H_ */
+diff --git a/drivers/usb/gadget/udc/hiudc3/no_os/no_os_ep0.c b/drivers/usb/gadget/udc/hiudc3/no_os/no_os_ep0.c
+new file mode 100644
+index 0000000..26bab51
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc3/no_os/no_os_ep0.c
+@@ -0,0 +1,560 @@
++/** @file
++ */
++
++#include "os_defs.h"
++#include "hw.h"
++#include "usb.h"
++#include "pcd.h"
++#include "dev.h"
++#include "os_dev.h"
++#include "cil.h"
++
++#ifdef DWC_UTE
++#include "ute_if.h"
++#endif
++
++/*=======================================================================*/
++/*
++ * EP0 routines
++ */
++
++#ifdef DWC_MASS_STORAGE_GADGET
++# define DWC_VENDOR_ID	0x16c3
++# define DWC_PRODUCT_ID	0x1234
++#else
++/* We simulate the Linux gadget-zero device */
++//# define DWC_VENDOR_ID	0x0525
++//# define DWC_PRODUCT_ID	0xa4a0
++# define DWC_VENDOR_ID	0x1e08
++# define DWC_PRODUCT_ID	0x0001
++#endif
++
++/* Make the following structure type definitions "packed" if using a Microsoft
++ * compiler. The UPACKED attribute (defined in no_os_defs.h) embedded in the
++ * structure type definitions does the same thing for GCC. Other compilers may
++ * need something different.
++ */
++#ifdef _MSC_VER
++#include <pshpack1.h>
++#endif
++
++/* The language string always has string index 0 */
++static struct {
++	uByte		bLength;
++	uByte		bDescriptorType;
++	uWord		wString[1];
++} UPACKED language_string = {
++	4,				/* bLength (size of string array + 2) */
++	UDESC_STRING,			/* bDescriptorType */
++	{				/* wString[] */
++		UCONSTW(0x0409),	/* US English */
++		/* others can be added here */
++	},
++};
++
++static struct {
++	uByte		bLength;
++	uByte		bDescriptorType;
++	uWord		wString[8];
++} UPACKED manuf_string = {
++	18,				/* bLength (size of string array + 2) */
++	UDESC_STRING,			/* bDescriptorType */
++	{				/* wString[] */
++		UCONSTW('S'), UCONSTW('y'), UCONSTW('n'), UCONSTW('o'),
++		UCONSTW('p'), UCONSTW('s'), UCONSTW('y'), UCONSTW('s'),
++	},
++};
++#define DWC_STRING_MANUFACTURER	1
++
++static struct {
++	uByte		bLength;
++	uByte		bDescriptorType;
++	uWord		wString[8];
++} UPACKED product_string = {
++	18,				/* bLength (size of string array + 2) */
++	UDESC_STRING,			/* bDescriptorType */
++	{				/* wString[] */
++		UCONSTW('D'), UCONSTW('W'), UCONSTW('C'), UCONSTW(' '),
++		UCONSTW('U'), UCONSTW('S'), UCONSTW('B'), UCONSTW('3'),
++	},
++};
++#define DWC_STRING_PRODUCT	2
++
++static struct {
++	uByte		bLength;
++	uByte		bDescriptorType;
++	uWord		wString[10];
++} UPACKED serial_string = {
++	22,				/* bLength (size of string array + 2) */
++	UDESC_STRING,			/* bDescriptorType */
++	{				/* wString[] */
++		UCONSTW('0'), UCONSTW('1'), UCONSTW('2'), UCONSTW('3'),
++		UCONSTW('4'), UCONSTW('5'), UCONSTW('6'), UCONSTW('7'),
++		UCONSTW('8'), UCONSTW('9'),
++	},
++};
++#define DWC_STRING_SERIAL	3
++
++/* Stop packing structure type definitions */
++#ifdef _MSC_VER
++#include <poppack.h>
++#endif
++
++/* These standard USB descriptor types are defined in usb.h */
++
++static usb_device_descriptor_t device_desc = {
++	USB_DEVICE_DESCRIPTOR_SIZE,		/* bLength */
++	UDESC_DEVICE,				/* bDescriptorType */
++
++	UCONSTW(0),				/* bcdUSB (filled in later) */
++
++#ifdef DWC_MASS_STORAGE_GADGET
++	UDCLASS_IN_INTERFACE,			/* bDeviceClass */
++#else
++	UDCLASS_VENDOR,				/* bDeviceClass */
++#endif
++	0,					/* bDeviceSubClass */
++	0,					/* bDeviceProtocol */
++	0,					/* bMaxPacketSize */
++
++	UCONSTW(DWC_VENDOR_ID),			/* idVendor */
++	UCONSTW(DWC_PRODUCT_ID),		/* idProduct */
++	UCONSTW(0xffff),			/* bcdDevice */
++
++	DWC_STRING_MANUFACTURER,		/* iManufacturer */
++	DWC_STRING_PRODUCT,			/* iProduct */
++	DWC_STRING_SERIAL,			/* iSerialNumber */
++
++	1,					/* bNumConfigurations */
++};
++
++static usb_device_qualifier_t dev_qualifier = {
++	USB_DEVICE_QUALIFIER_SIZE,		/* bLength */
++	UDESC_DEVICE_QUALIFIER,			/* bDescriptorType */
++
++	UCONSTW(0),				/* bcdUSB (filled in later) */
++
++#ifdef DWC_MASS_STORAGE_GADGET
++	UDCLASS_IN_INTERFACE,			/* bDeviceClass */
++#else
++	UDCLASS_VENDOR,				/* bDeviceClass */
++#endif
++	0,					/* bDeviceSubClass */
++	0,					/* bDeviceProtocol */
++	0,					/* bMaxPacketSize0 */
++	1,					/* bNumConfigurations */
++	0,					/* bReserved */
++};
++
++/* These application-specific config descriptor types are defined in
++ * no_os_defs.h
++ */
++
++fs_config_desc_t fs_config_desc = {
++	/* config descriptor */
++	{
++		USB_CONFIG_DESCRIPTOR_SIZE,	/* bLength */
++		UDESC_CONFIG,			/* bDescriptorType */
++		UCONSTW(0),			/* wTotalLength (filled in later) */
++		1,				/* bNumInterface */
++		1,				/* bConfigurationValue */
++		0,				/* iConfiguration */
++		UC_ATT_ONE | UC_ATT_SELFPOWER,	/* bmAttributes */
++		100 / UC_POWER_FACTOR,		/* bMaxPower (100 ma) */
++	},
++	/* interface descriptor */
++	{
++		USB_INTERFACE_DESCRIPTOR_SIZE,	/* bLength */
++		UDESC_INTERFACE,		/* bDescriptorType */
++		0,				/* bInterfaceNumber */
++		0,				/* bAlternateSetting */
++		2,				/* bNumEndpoints */
++
++#ifdef DWC_MASS_STORAGE_GADGET
++		UICLASS_MASS,			/* bInterfaceClass */
++		UISUBCLASS_SCSI,		/* bInterfaceSubClass */
++		UIPROTO_MASS_BBB,		/* bInterfaceProtocol */
++#else
++		UICLASS_VENDOR,			/* bInterfaceClass */
++		0,				/* bInterfaceSubClass */
++		0,				/* bInterfaceProtocol */
++#endif
++		0,				/* iInterface */
++	},
++	/* bulk IN endpoint descriptor */
++	{
++		USB_ENDPOINT_DESCRIPTOR_SIZE,	/* bLength */
++		UDESC_ENDPOINT,			/* bDescriptorType */
++		1 | UE_DIR_IN,			/* bEndpointAddress */
++		UE_BULK,			/* bmAttributes */
++		UCONSTW(64),			/* wMaxPacketSize */
++		0,				/* bInterval */
++	},
++	/* bulk OUT endpoint descriptor */
++	{
++		USB_ENDPOINT_DESCRIPTOR_SIZE,	/* bLength */
++		UDESC_ENDPOINT,			/* bDescriptorType */
++		2 | UE_DIR_OUT,			/* bEndpointAddress */
++		UE_BULK,			/* bmAttributes */
++		UCONSTW(64),			/* wMaxPacketSize */
++		0,				/* bInterval */
++	},
++};
++
++hs_config_desc_t hs_config_desc = {
++	/* config descriptor */
++	{
++		USB_CONFIG_DESCRIPTOR_SIZE,	/* bLength */
++		UDESC_CONFIG,			/* bDescriptorType */
++		UCONSTW(0),			/* wTotalLength (filled in later) */
++		1,				/* bNumInterface */
++		1,				/* bConfigurationValue */
++		0,				/* iConfiguration */
++		UC_ATT_ONE | UC_ATT_SELFPOWER,	/* bmAttributes */
++		100 / UC_POWER_FACTOR,		/* bMaxPower (100 ma) */
++	},
++	/* interface descriptor */
++	{
++		USB_INTERFACE_DESCRIPTOR_SIZE,	/* bLength */
++		UDESC_INTERFACE,		/* bDescriptorType */
++		0,				/* bInterfaceNumber */
++		0,				/* bAlternateSetting */
++		2,				/* bNumEndpoints */
++
++#ifdef DWC_MASS_STORAGE_GADGET
++		UICLASS_MASS,			/* bInterfaceClass */
++		UISUBCLASS_SCSI,		/* bInterfaceSubClass */
++		UIPROTO_MASS_BBB,		/* bInterfaceProtocol */
++#else
++		UICLASS_VENDOR,			/* bInterfaceClass */
++		0,				/* bInterfaceSubClass */
++		0,				/* bInterfaceProtocol */
++#endif
++		0,				/* iInterface */
++	},
++	/* bulk IN endpoint descriptor */
++	{
++		USB_ENDPOINT_DESCRIPTOR_SIZE,	/* bLength */
++		UDESC_ENDPOINT,			/* bDescriptorType */
++		1 | UE_DIR_IN,			/* bEndpointAddress */
++		UE_BULK,			/* bmAttributes */
++		UCONSTW(512),			/* wMaxPacketSize */
++		0,				/* bInterval */
++	},
++	/* bulk OUT endpoint descriptor */
++	{
++		USB_ENDPOINT_DESCRIPTOR_SIZE,	/* bLength */
++		UDESC_ENDPOINT,			/* bDescriptorType */
++		2 | UE_DIR_OUT,			/* bEndpointAddress */
++		UE_BULK,			/* bmAttributes */
++		UCONSTW(512),			/* wMaxPacketSize */
++		1,				/* bInterval (every uframe) */
++	},
++};
++
++ss_config_desc_t ss_config_desc = {
++	/* config descriptor */
++	{
++		USB_CONFIG_DESCRIPTOR_SIZE,	/* bLength */
++		UDESC_CONFIG,			/* bDescriptorType */
++		UCONSTW(0),			/* wTotalLength (filled in later) */
++		1,				/* bNumInterface */
++		1,				/* bConfigurationValue */
++		0,				/* iConfiguration */
++		UC_ATT_ONE | UC_ATT_SELFPOWER,	/* bmAttributes */
++		100 / UC_POWER_FACTOR,		/* bMaxPower (100 ma) */
++	},
++	/* interface descriptor */
++	{
++		USB_INTERFACE_DESCRIPTOR_SIZE,	/* bLength */
++		UDESC_INTERFACE,		/* bDescriptorType */
++		0,				/* bInterfaceNumber */
++		0,				/* bAlternateSetting */
++		2,				/* bNumEndpoints */
++
++#ifdef DWC_MASS_STORAGE_GADGET
++		UICLASS_MASS,			/* bInterfaceClass */
++		UISUBCLASS_SCSI,		/* bInterfaceSubClass */
++		UIPROTO_MASS_BBB,		/* bInterfaceProtocol */
++#else
++		UICLASS_VENDOR,			/* bInterfaceClass */
++		0,				/* bInterfaceSubClass */
++		0,				/* bInterfaceProtocol */
++#endif
++		0,				/* iInterface */
++	},
++	/* bulk IN endpoint descriptor */
++	{
++		USB_ENDPOINT_DESCRIPTOR_SIZE,	/* bLength */
++		UDESC_ENDPOINT,			/* bDescriptorType */
++		1 | UE_DIR_IN,			/* bEndpointAddress */
++		UE_BULK,			/* bmAttributes */
++		UCONSTW(1024),			/* wMaxPacketSize */
++		0,				/* bInterval */
++	},
++	/* bulk IN companion descriptor */
++	{
++		USB_SS_ENDPOINT_COMPANION_DESCRIPTOR_SIZE, /* bLength */
++		UDESC_SS_USB_COMPANION,		/* bDescriptorType */
++		15,				/* bMaxBurst */
++		0,				/* bmAttributes */
++		UCONSTW(0),			/* wBytesPerInterval */
++	},
++	/* bulk OUT endpoint descriptor */
++	{
++		USB_ENDPOINT_DESCRIPTOR_SIZE,	/* bLength */
++		UDESC_ENDPOINT,			/* bDescriptorType */
++		2 | UE_DIR_OUT,			/* bEndpointAddress */
++		UE_BULK,			/* bmAttributes */
++		UCONSTW(1024),			/* wMaxPacketSize */
++		0,				/* bInterval */
++	},
++	/* bulk OUT companion descriptor */
++	{
++		USB_SS_ENDPOINT_COMPANION_DESCRIPTOR_SIZE, /* bLength */
++		UDESC_SS_USB_COMPANION,		/* bDescriptorType */
++		15,				/* bMaxBurst */
++		0,				/* bmAttributes */
++		UCONSTW(0),			/* wBytesPerInterval */
++	},
++};
++
++/**
++ * This routine handles Get Descriptor requests.
++ */
++static int no_os_get_descriptor(dwc_usb3_pcd_t *pcd, usb_device_request_t *ctrl)
++{
++	u8 desc_type = UGETW(ctrl->wValue) >> 8;
++	u8 desc_idx = UGETW(ctrl->wValue);
++	u16 max = UGETW(ctrl->wLength);
++	u8 *buf = pcd->ep0_status_buf;
++	u16 len;
++
++#ifdef DEBUG_EP0
++	dwc_debug5(pcd->usb3_dev, "GET_DESCRIPTOR %02x.%02x v%04x i%04x l%04x\n",
++		   ctrl->bmRequestType, ctrl->bRequest, UGETW(ctrl->wValue),
++		   UGETW(ctrl->wIndex), UGETW(ctrl->wLength));
++#endif
++	switch (desc_type) {
++	case UDESC_DEVICE:
++		if (desc_idx)
++			return -DWC_E_NOT_SUPPORTED;
++
++		switch (pcd->speed) {
++		case USB_SPEED_SUPER:
++			USETW(device_desc.bcdUSB, 0x300);
++			device_desc.bMaxPacketSize = 9;
++			break;
++
++		case USB_SPEED_HIGH:
++			USETW(device_desc.bcdUSB, 0x200);
++			device_desc.bMaxPacketSize = 64;
++			break;
++
++		default:
++			USETW(device_desc.bcdUSB, 0x200);
++			device_desc.bMaxPacketSize = 64;
++			break;
++		}
++
++		memcpy(buf, &device_desc, sizeof(device_desc));
++		len = sizeof(device_desc);
++		break;
++
++	case UDESC_CONFIG:
++		if (desc_idx)
++			return -DWC_E_NOT_SUPPORTED;
++
++		switch (pcd->speed) {
++		case USB_SPEED_SUPER:
++			USETW(ss_config_desc.config_desc.wTotalLength,
++			      sizeof(ss_config_desc));
++			memcpy(buf, &ss_config_desc, sizeof(ss_config_desc));
++			len = sizeof(ss_config_desc);
++			break;
++
++		case USB_SPEED_HIGH:
++			USETW(hs_config_desc.config_desc.wTotalLength,
++			      sizeof(hs_config_desc));
++			memcpy(buf, &hs_config_desc, sizeof(hs_config_desc));
++			len = sizeof(hs_config_desc);
++			break;
++
++		default:
++			USETW(fs_config_desc.config_desc.wTotalLength,
++			      sizeof(fs_config_desc));
++			memcpy(buf, &fs_config_desc, sizeof(fs_config_desc));
++			len = sizeof(fs_config_desc);
++			break;
++		}
++
++		break;
++
++	case UDESC_STRING:
++		switch (desc_idx) {
++		case 0:
++			memcpy(buf, &language_string, sizeof(language_string));
++			len = sizeof(language_string);
++			break;
++
++		case DWC_STRING_MANUFACTURER:
++			memcpy(buf, &manuf_string, sizeof(manuf_string));
++			len = sizeof(manuf_string);
++			break;
++
++		case DWC_STRING_PRODUCT:
++			memcpy(buf, &product_string, sizeof(product_string));
++			len = sizeof(product_string);
++			break;
++
++		case DWC_STRING_SERIAL:
++			memcpy(buf, &serial_string, sizeof(serial_string));
++			len = sizeof(serial_string);
++			break;
++
++		default:
++			return -DWC_E_NOT_SUPPORTED;
++		}
++
++		break;
++
++	case UDESC_DEVICE_QUALIFIER:
++		if (desc_idx || pcd->speed == USB_SPEED_SUPER)
++			return -DWC_E_NOT_SUPPORTED;
++
++		USETW(dev_qualifier.bcdUSB, 0x200);
++		dev_qualifier.bMaxPacketSize0 = 9;
++		memcpy(buf, &dev_qualifier, sizeof(dev_qualifier));
++		len = sizeof(dev_qualifier);
++		break;
++
++	case UDESC_OTHER_SPEED_CONFIGURATION:
++		if (desc_idx || pcd->speed == USB_SPEED_SUPER)
++			return -DWC_E_NOT_SUPPORTED;
++
++		switch (pcd->speed) {
++		case USB_SPEED_HIGH:
++			ss_config_desc.config_desc.bDescriptorType =
++					UDESC_OTHER_SPEED_CONFIGURATION;
++			USETW(ss_config_desc.config_desc.wTotalLength,
++			      sizeof(ss_config_desc));
++			memcpy(buf, &ss_config_desc, sizeof(ss_config_desc));
++			ss_config_desc.config_desc.bDescriptorType = UDESC_CONFIG;
++			len = sizeof(ss_config_desc);
++			break;
++
++		default:
++			hs_config_desc.config_desc.bDescriptorType =
++					UDESC_OTHER_SPEED_CONFIGURATION;
++			USETW(hs_config_desc.config_desc.wTotalLength,
++			      sizeof(hs_config_desc));
++			memcpy(buf, &hs_config_desc, sizeof(hs_config_desc));
++			hs_config_desc.config_desc.bDescriptorType = UDESC_CONFIG;
++			len = sizeof(hs_config_desc);
++			break;
++		}
++
++		break;
++
++	default:
++		return -DWC_E_NOT_SUPPORTED;
++	}
++
++	pcd->ep0state = EP0_IN_DATA_PHASE;
++	pcd->ep0_req->dwc_req.length = len < max ? len : max;
++	pcd->ep0_status_pending = 1;
++	pcd->ep0_req->dwc_req.buf[0] = pcd->ep0_status_buf;
++	pcd->ep0_req->dwc_req.bufdma[0] = pcd->ep0_status_buf_dma;
++	pcd->ep0_req->dwc_req.actual = 0;
++	dwc_usb3_pcd_ep0_start_transfer(pcd, pcd->ep0_req);
++
++	return 0;
++}
++
++/**
++ * This routine processes SETUP commands. The USB Command processing is
++ * done in two places - the first being the PCD and the second being the
++ * Gadget driver (for example, the File-Backed Storage Gadget driver).
++ *
++ * <table>
++ * <tr><td> Command </td><td> Driver </td><td> Description </td></tr>
++ *
++ * <tr><td> SET_FEATURE </td><td> PCD / Gadget driver </td><td> Device
++ * and Endpoint requests are processed by the PCD. Interface requests
++ * are passed to the Gadget driver. </td></tr>
++ *
++ * <tr><td> CLEAR_FEATURE </td><td> PCD </td><td> Device and Endpoint
++ * requests are processed by the PCD. Interface requests are ignored.
++ * The only Endpoint feature handled is ENDPOINT_HALT. </td></tr>
++ *
++ * <tr><td> GET_DESCRIPTOR </td><td> Gadget driver </td><td> Return the
++ * requested descriptor. </td></tr>
++ *
++ * <tr><td> SET_DESCRIPTOR </td><td> Gadget driver </td><td> Optional -
++ * not implemented by any of the existing Gadget drivers. </td></tr>
++ *
++ * <tr><td> GET_CONFIGURATION </td><td> Gadget driver </td><td> Return
++ * the current configuration. </td></tr>
++ *
++ * <tr><td> SET_CONFIGURATION </td><td> Gadget driver </td><td> Disable
++ * all EPs and enable EPs for new configuration. </td></tr>
++ *
++ * <tr><td> GET_INTERFACE </td><td> Gadget driver </td><td> Return the
++ * current interface. </td></tr>
++ *
++ * <tr><td> SET_INTERFACE </td><td> Gadget driver </td><td> Disable all
++ * EPs and enable EPs for new interface. </td></tr>
++ * </table>
++ *
++ * When the SETUP Phase Done interrupt occurs, the generic SETUP commands
++ * are processed by dwc_usb3_do_setup(). Calling the gadget driver's
++ * dwc_usb3_gadget_setup() routine from dwc_usb3_do_setup() in turn calls
++ * this routine to process the gadget-specific SETUP commands. Any requests
++ * not handled here are passed to the Function Driver's
++ * dwc_usb3_function_setup() routine.
++ */
++int dwc_usb3_no_os_setup(dwc_usb3_pcd_t *pcd, usb_device_request_t *ctrl)
++{
++	dwc_debug2(pcd->usb3_dev, "%s(%lx)\n", __func__, (unsigned long)pcd);
++
++	if ((UT_GET_TYPE(ctrl->bmRequestType)) != UT_STANDARD) {
++		/* handle non-standard (class/vendor) requests
++		 * in the Function Driver
++		 */
++		return dwc_usb3_function_setup(pcd, ctrl);
++	}
++
++	/* @todo NGS: Handle bad setup packet? */
++
++///////////////////////////////////////////
++//// --- Standard Request handling --- ////
++
++	switch (ctrl->bRequest) {
++	case UR_SET_FEATURE:
++		return dwc_usb3_function_setup(pcd, ctrl);
++
++	case UR_SET_INTERFACE:
++		return dwc_usb3_function_setup(pcd, ctrl);
++
++	case UR_GET_INTERFACE:
++		return dwc_usb3_function_setup(pcd, ctrl);
++
++	case UR_SET_CONFIG:
++		return dwc_usb3_function_setup(pcd, ctrl);
++
++	case UR_GET_CONFIG:
++		return dwc_usb3_function_setup(pcd, ctrl);
++
++	case UR_SYNCH_FRAME:
++		return dwc_usb3_function_setup(pcd, ctrl);
++
++	case UR_GET_DESCRIPTOR:
++		return no_os_get_descriptor(pcd, ctrl);
++
++	default:
++		/* Call the Function Driver setup routines */
++		return dwc_usb3_function_setup(pcd, ctrl);
++	}
++
++	return 0;
++}
+diff --git a/drivers/usb/gadget/udc/hiudc3/no_os/no_os_gadget.c b/drivers/usb/gadget/udc/hiudc3/no_os/no_os_gadget.c
+new file mode 100644
+index 0000000..5bd2c6a
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc3/no_os/no_os_gadget.c
+@@ -0,0 +1,733 @@
++/** @file
++ *
++ * Application-specific Function Driver interface
++ *
++ * Simple applications may wish to implement their entire Function Driver here.
++ *
++ * More complex applications, or environments with an existing Function Driver
++ * framework (such as the Linux Gadget framework) will implement the interface
++ * to their Function Driver here.
++ *
++ * See the linux/ subdirectory for an example implementation of a Linux Gadget
++ * framework interface.
++ *
++ * For historical reasons, the PCD API uses the Linux term "gadget" to refer to
++ * a Function Driver.
++ */
++
++#include "os_defs.h"
++#include "hw.h"
++#include "usb.h"
++#include "pcd.h"
++#include "dev.h"
++#include "os_dev.h"
++#include "cil.h"
++
++/** Driver context struct - defined in no_os_init.c */
++extern dwc_usb3_device_t	g_usb3_dev;
++
++/** @{ */
++/** PCD request pool - defined in no_os_init.c */
++extern dwc_usb3_pcd_req_t	g_pcd_req[];
++extern u32			g_pcd_req_bm;
++/** @} */
++
++#ifndef LINUXTEST
++/** @{ */
++/** DMA descriptor (TRB) pools for non-EP0 EPs - defined in no_os_init.c */
++extern dwc_usb3_dma_desc_t	g_out_trb_pool[][DWC_NUM_ISOC_TRBS + 1];
++extern dwc_usb3_dma_desc_t	g_in_trb_pool[][DWC_NUM_ISOC_TRBS + 1];
++/** @} */
++#endif
++
++/******************************************************************************
++ * Function Driver notification routines
++ *
++ * These routines receive notifications from the PCD when certain events occur
++ * which the Function Driver may need to be aware of.
++ *
++ * These routines *must* have the exact names and parameters shown here,
++ * because they are part of the API between the PCD and the Function Driver.
++ ******************************************************************************/
++
++/**
++ * This routine receives Connect notifications from the PCD
++ *
++ * @param pcd   Programming view of DWC_usb3 peripheral controller.
++ * @param speed Speed of the connection (as defined in usb.h).
++ * @return      0 for success, else negative error code.
++ */
++int dwc_usb3_gadget_connect(dwc_usb3_pcd_t *pcd, int speed)
++{
++	dwc_debug1(pcd->usb3_dev, "%s()\n", __func__);
++	dwc_usb3_function_connect(pcd->usb3_dev, speed);
++	return 0;
++}
++
++/**
++ * This routine receives Disconnect notifications from the PCD
++ *
++ * @param pcd   Programming view of DWC_usb3 peripheral controller.
++ * @return      0 for success, else negative error code.
++ */
++int dwc_usb3_gadget_disconnect(dwc_usb3_pcd_t *pcd)
++{
++	dwc_debug1(pcd->usb3_dev, "%s()\n", __func__);
++	dwc_usb3_function_disconnect(pcd->usb3_dev);
++	return 0;
++}
++
++/**
++ * This routine receives Suspend notifications from the PCD
++ *
++ * @param pcd   Programming view of DWC_usb3 peripheral controller.
++ * @return      0 for success, else negative error code.
++ */
++int dwc_usb3_gadget_suspend(dwc_usb3_pcd_t *pcd)
++{
++	dwc_debug1(pcd->usb3_dev, "%s()\n", __func__);
++	return 0;
++}
++
++/**
++ * This routine receives Resume notifications from the PCD
++ *
++ * @param pcd   Programming view of DWC_usb3 peripheral controller.
++ * @return      0 for success, else negative error code.
++ */
++int dwc_usb3_gadget_resume(dwc_usb3_pcd_t *pcd)
++{
++	dwc_debug1(pcd->usb3_dev, "%s()\n", __func__);
++	return 0;
++}
++
++/**
++ * This routine receives Setup request notifications from the PCD
++ *
++ * @param pcd   Programming view of DWC_usb3 peripheral controller.
++ * @param ctrl  Pointer to the Setup packet for the request.
++ * @return      0 for success, else negative error code.
++ */
++int dwc_usb3_gadget_setup(dwc_usb3_pcd_t *pcd, usb_device_request_t *ctrl)
++{
++	int ret;
++
++	dwc_debug1(pcd->usb3_dev, "%s()\n", __func__);
++
++	ret = dwc_usb3_no_os_setup(pcd, ctrl);
++
++	return ret;
++}
++
++/**
++ * This routine receives Transfer Complete notifications from the PCD
++ *
++ * @param pcd           Programming view of DWC_usb3 peripheral controller.
++ * @param pcd_ep        PCD EP for the transfer.
++ * @param pcd_req       PCD request for the transfer.
++ * @param status        Transfer status, 0 for success else negative error code.
++ * @return              0 for success, else negative error code.
++ */
++int dwc_usb3_gadget_complete(dwc_usb3_pcd_t *pcd, dwc_usb3_pcd_ep_t *pcd_ep,
++			     dwc_usb3_pcd_req_t *pcd_req, int status)
++{
++	usb_ep_t	*usb_ep = &pcd_ep->usb_ep;
++	usb_request_t	*usb_req = &pcd_req->usb_req;
++	u32		actual = pcd_req->dwc_req.actual;
++
++	dwc_debug2(pcd->usb3_dev, "%s(%lx)\n", __func__, (unsigned long)pcd_ep);
++
++	/* Remove the request from the queue */
++	DWC_CIRCLEQ_REMOVE_INIT(&pcd_ep->dwc_ep.queue, pcd_req, entry);
++
++	usb_req->status = status;
++	usb_req->actual = actual;
++
++	if (usb_req->complete) {
++		dwc_release_spinlock(pcd->usb3_dev, &pcd->lock);
++		usb_req->complete(usb_ep, usb_req);
++		dwc_acquire_spinlock(pcd->usb3_dev, &pcd->lock);
++	}
++
++	if (pcd->request_pending > 0)
++		--pcd->request_pending;
++
++	return 0;
++}
++
++/**
++ * This routine allows overriding the standard Control transfer handling
++ * (currently only done by the axs101 test gadget)
++ *
++ * @param pcd           Programming view of DWC_usb3 peripheral controller.
++ */
++void dwc_usb3_gadget_do_setup(dwc_usb3_pcd_t *pcd)
++{
++	/* Call the standard Control transfer handler */
++	dwc_usb3_pcd_do_setup(pcd);
++}
++
++/******************************************************************************
++ * Function Driver callback routines
++ *
++ * The PCD calls these routines when it needs something from the Function
++ * Driver.
++ *
++ * These routines *must* have the exact names and parameters shown here,
++ * because they are part of the API between the PCD and the Function Driver.
++ ******************************************************************************/
++
++/**
++ * This routine allocates coherent DMA memory. It is used by the PCD to
++ * allocate memory for TRBs. The block of memory returned must have a start
++ * address aligned to a 16-byte boundary.
++ *
++ * This routine may be called from interrupt context, so it must be able to
++ * allocate coherent DMA memory in that context. One strategy would be to
++ * preallocate a block of memory at initialization time, and hand out chunks
++ * from that block in this routine.
++ *
++ * @param pcd_ep        PCD EP that memory block will be associated with.
++ * @param size          Size of memory block to allocate, in bytes.
++ * @param mem_dma_ret   Physical address of allocated memory block is returned
++ *                      through this pointer.
++ * @return              Address of allocated memory block, or NULL if allocation
++ *                      fails.
++ */
++void *dwc_usb3_gadget_alloc_dma(dwc_usb3_pcd_ep_t *pcd_ep, int size, dwc_dma_t *mem_dma_ret)
++{
++	void		*mem;
++	dwc_dma_t	mem_dma;
++
++	dwc_debug2(pcd_ep->dwc_ep.pcd->usb3_dev, "%s(%lx)\n", __func__, (unsigned long)pcd_ep);
++
++	if (!pcd_ep->dwc_ep.num) {
++		dwc_error0(pcd_ep->dwc_ep.pcd->usb3_dev, "USB epnum is 0 for pcd_ep\n");
++		return NULL;
++	}
++
++#ifdef LINUXTEST
++	mem = dma_alloc_coherent(g_usb3_dev.dev, size, &mem_dma, GFP_ATOMIC | GFP_DMA32);
++	if (!mem)
++		return NULL;
++#else
++	if (pcd_ep->dwc_ep.is_in)
++		mem = (void *)&g_in_trb_pool[pcd_ep->dwc_ep.num - 1];
++	else
++		mem = (void *)&g_out_trb_pool[pcd_ep->dwc_ep.num - 1];
++
++	mem_dma = (dwc_dma_t)mem;
++#endif
++	*mem_dma_ret = mem_dma;
++
++	return mem;
++}
++
++/**
++ * This routine frees DMA memory allocated by dwc_usb3_gadget_alloc_dma().
++ *
++ * @param pcd_ep        PCD EP that memory block is associated with.
++ * @param size          Size of memory block to free, in bytes.
++ * @param mem           Address of memory block.
++ * @param mem_dma       Physical address of memory block.
++ */
++void dwc_usb3_gadget_free_dma(dwc_usb3_pcd_ep_t *pcd_ep, int size, void *mem, dwc_dma_t mem_dma)
++{
++	dwc_debug2(pcd_ep->dwc_ep.pcd->usb3_dev, "%s(%lx)\n", __func__, (unsigned long)pcd_ep);
++
++#ifdef LINUXTEST
++	dma_free_coherent(g_usb3_dev.dev, size, mem, mem_dma);
++#endif
++}
++
++/**
++ * This routine returns the PCD request corresponding to the current transfer
++ * request for an endpoint. The current transfer request is the first request
++ * submitted that has not been completed yet.
++ *
++ * @param pcd           Programming view of DWC_usb3 peripheral controller.
++ * @param pcd_ep        PCD EP to operate on.
++ * @return              Pointer to PCD request, or NULL if no request available.
++ */
++dwc_usb3_pcd_req_t *dwc_usb3_gadget_get_request(dwc_usb3_pcd_t *pcd, dwc_usb3_pcd_ep_t *pcd_ep)
++{
++	dwc_usb3_pcd_req_t *pcd_req;
++
++	dwc_debug2(pcd->usb3_dev, "%s(%lx)\n", __func__, (unsigned long)pcd_ep);
++
++	/* Check for a pending request */
++	if (DWC_CIRCLEQ_EMPTY(&pcd_ep->dwc_ep.queue)) {
++		dwc_debug0(pcd->usb3_dev, "ep->dwc_ep.queue empty\n");
++		return NULL;
++	}
++
++	pcd_req = DWC_CIRCLEQ_FIRST(&pcd_ep->dwc_ep.queue);
++	return pcd_req;
++}
++
++/**
++ * This routine checks to see if there is another transfer request waiting
++ * on an endpoint that has not been started yet. If so then that transfer is
++ * started.
++ *
++ * @param pcd           Programming view of DWC_usb3 peripheral controller.
++ * @param pcd_ep        PCD EP to operate on.
++ */
++void dwc_usb3_gadget_start_next_request(dwc_usb3_pcd_t *pcd, dwc_usb3_pcd_ep_t *pcd_ep)
++{
++	dwc_usb3_pcd_req_t *pcd_req = NULL;
++
++	dwc_debug2(pcd->usb3_dev, "%s(%lx)\n", __func__, (unsigned long)pcd_ep);
++
++	if (DWC_CIRCLEQ_EMPTY(&pcd_ep->dwc_ep.queue)) {
++		dwc_debug2(pcd->usb3_dev, "start_next EP%d-%s: queue empty\n",
++			   pcd_ep->dwc_ep.num, pcd_ep->dwc_ep.is_in ? "IN" : "OUT");
++		return;
++	}
++
++	DWC_CIRCLEQ_FOREACH(pcd_req, &pcd_ep->dwc_ep.queue, entry) {
++		if (!(pcd_req->dwc_req.flags & DWC_PCD_REQ_STARTED)) {
++			dwc_debug2(pcd->usb3_dev, "start_next EP%d-%s: OK\n",
++				   pcd_ep->dwc_ep.num, pcd_ep->dwc_ep.is_in ? "IN" : "OUT");
++
++			/* Setup and start the transfer */
++			dwc_usb3_pcd_fill_trbs(pcd, pcd_ep, pcd_req);
++			dwc_usb3_pcd_ep_start_transfer(pcd, pcd_ep, pcd_req, 0);
++			return;
++		}
++	}
++
++	dwc_debug2(pcd->usb3_dev, "start_next EP%d-%s: all req active\n",
++		   pcd_ep->dwc_ep.num, pcd_ep->dwc_ep.is_in ? "IN" : "OUT");
++}
++
++/**
++ * Start an Isoc EP running at the proper interval, after receiving the initial
++ * XferNrdy event.
++ *
++ * @param pcd           Programming view of DWC_usb3 peripheral controller.
++ * @param pcd_ep        EP to operate on.
++ * @param event         Event data containing the XferNrdy microframe.
++ */
++void dwc_usb3_gadget_isoc_ep_start(dwc_usb3_pcd_t *pcd, dwc_usb3_pcd_ep_t *pcd_ep, u32 event)
++{
++	dwc_usb3_pcd_req_t *pcd_req = NULL;
++
++	dwc_debug3(pcd->usb3_dev, "%s(%lx,%x)\n", __func__, (unsigned long)pcd_ep, event);
++	dwc_isocdbg2(pcd->usb3_dev, "%s(%08x)\n", __func__, event);
++
++	if (DWC_CIRCLEQ_EMPTY(&pcd_ep->dwc_ep.queue)) {
++		dwc_debug2(pcd->usb3_dev, "%s(%lx), ep->dwc_ep.queue empty\n",
++			   __func__, (unsigned long)pcd_ep);
++		return;
++	}
++
++	if (pcd_ep->dwc_ep.desc_avail <= 0) {
++		dwc_debug2(pcd->usb3_dev, "EP%d-%s: no TRB avail\n",
++			   pcd_ep->dwc_ep.num, pcd_ep->dwc_ep.is_in ? "IN" : "OUT");
++		return;
++	}
++
++	/* If need to restart after hibernation, handle that and return */
++	if (dwc_usb3_pcd_isoc_ep_hiber_restart(pcd, pcd_ep))
++		return;
++
++	/*
++	 * Start the next queued transfer at the target uFrame
++	 */
++
++	DWC_CIRCLEQ_FOREACH(pcd_req, &pcd_ep->dwc_ep.queue, entry) {
++		if (pcd_req->dwc_req.flags & DWC_PCD_REQ_STARTED)
++			pcd_req = NULL;
++		else
++			break;
++	}
++
++	dwc_debug1(pcd->usb3_dev, "req=%lx\n", (unsigned long)pcd_req);
++	if (!pcd_req) {
++		dwc_debug2(pcd->usb3_dev, "EP%d-%s: no requests to start\n",
++			   pcd_ep->dwc_ep.num, pcd_ep->dwc_ep.is_in ? "IN" : "OUT");
++		return;
++	}
++
++	dwc_usb3_pcd_fill_trbs(pcd, pcd_ep, pcd_req);
++	dwc_usb3_pcd_ep_start_transfer(pcd, pcd_ep, pcd_req, event);
++
++	/*
++	 * Now start any remaining queued transfers
++	 */
++
++	while (pcd_req != DWC_CIRCLEQ_LAST(&pcd_ep->dwc_ep.queue)) {
++		pcd_req = DWC_CIRCLEQ_NEXT(pcd_req, entry);
++		if (!(pcd_req->dwc_req.flags & DWC_PCD_REQ_STARTED)) {
++			dwc_usb3_pcd_fill_trbs(pcd, pcd_ep, pcd_req);
++			dwc_usb3_pcd_ep_start_transfer(pcd, pcd_ep, pcd_req, 0);
++		}
++	}
++}
++
++/**
++ * This routine terminates all requests which are pending on an endpoint.
++ *
++ * @param pcd           Programming view of DWC_usb3 peripheral controller.
++ * @param pcd_ep        EP to operate on.
++ */
++void dwc_usb3_gadget_request_nuke(dwc_usb3_pcd_t *pcd, dwc_usb3_pcd_ep_t *pcd_ep)
++{
++	dwc_usb3_pcd_req_t *pcd_req;
++
++	dwc_debug2(pcd->usb3_dev, "%s(%lx)\n", __func__, (unsigned long)pcd_ep);
++	pcd_ep->dwc_ep.stopped = 1;
++
++	while (!DWC_CIRCLEQ_EMPTY(&pcd_ep->dwc_ep.queue)) {
++		pcd_req = DWC_CIRCLEQ_FIRST(&pcd_ep->dwc_ep.queue);
++		dwc_usb3_pcd_request_done(pcd, pcd_ep, pcd_req, -DWC_E_SHUTDOWN);
++	}
++
++	if (pcd_ep != pcd->ep0)
++		pcd_ep->dwc_ep.hiber_desc_idx = 0;
++}
++
++/**
++ * This routine marks all pending requests for an EP as not started.
++ *
++ * @param pcd           Programming view of DWC_usb3 peripheral controller.
++ * @param pcd_ep        EP to operate on.
++ */
++void dwc_usb3_gadget_set_ep_not_started(dwc_usb3_pcd_t *pcd, dwc_usb3_pcd_ep_t *pcd_ep)
++{
++	dwc_usb3_pcd_req_t *pcd_req;
++
++	dwc_debug2(pcd->usb3_dev, "%s(%lx)\n", __func__, (unsigned long)pcd_ep);
++
++	DWC_CIRCLEQ_FOREACH(pcd_req, &pcd_ep->dwc_ep.queue, entry) {
++		if (pcd_req->dwc_req.flags & DWC_PCD_REQ_STARTED)
++			pcd_req->dwc_req.flags &= ~DWC_PCD_REQ_STARTED;
++	}
++}
++
++/******************************************************************************
++ * Function Driver user-defined routines
++ *
++ * These routines are completely user-defined, and can implement whatever is
++ * required for the application's Function Driver.
++ *
++ * The example code here implements a simple interface which allows external
++ * code to implement the application's Function Driver by calling these
++ * routines.
++ ******************************************************************************/
++
++/**
++ * This routine enables a USB endpoint
++ *
++ * @param usb3_dev      Programming view of DWC_usb3 device.
++ * @param epdesc        USB endpoint descriptor for the EP.
++ * @param epcomp        USB SS endpoint companion descriptor for the EP.
++ * @return              Pointer to USB EP context, or NULL on failure.
++ */
++usb_ep_t *dwc_usb3_ep_enable(struct dwc_usb3_device *usb3_dev, const void *epdesc, const void *epcomp)
++{
++	const usb_endpoint_descriptor_t			*ep_desc = epdesc;
++	const ss_endpoint_companion_descriptor_t	*ep_comp = epcomp;
++	dwc_usb3_pcd_t					*pcd = &usb3_dev->pcd;
++	dwc_usb3_pcd_ep_t				*pcd_ep;
++	dwc_usb3_dma_desc_t				*desc;
++	dwc_dma_t					desc_dma;
++	usb_ep_t					*usb_ep;
++	int						ep_num, ep_dir, ep_type;
++	int						link, num_trbs, retval;
++
++	dwc_debug1(usb3_dev, "%s()\n", __func__);
++
++	ep_num = UE_GET_ADDR(ep_desc->bEndpointAddress);
++	ep_dir = UE_GET_DIR(ep_desc->bEndpointAddress);
++	ep_type = UE_GET_XFERTYPE(ep_desc->bmAttributes);
++	link = 0;
++
++	if (ep_num < 1 || ep_num >= DWC_MAX_EPS)
++		return NULL;
++
++	if (ep_dir == UE_DIR_IN)
++		pcd_ep = pcd->in_ep[ep_num - 1];
++	else
++		pcd_ep = pcd->out_ep[ep_num - 1];
++	usb_ep = &pcd_ep->usb_ep;
++
++	/* Allocate the number of TRBs based on EP type */
++	switch (ep_type) {
++	case UE_INTERRUPT:
++		num_trbs = DWC_NUM_INTR_TRBS;
++		break;
++	case UE_ISOCHRONOUS:
++		num_trbs = DWC_NUM_ISOC_TRBS;
++		link = 1;
++		break;
++	default:
++		num_trbs = DWC_NUM_BULK_TRBS;
++		break;
++	}
++
++	dwc_debug5(usb3_dev, "ep%d-%s=%lx phys=%d pcd_ep=%lx\n", ep_num,
++		   ep_dir == UE_DIR_IN ? "IN" : "OUT", (unsigned long)usb_ep,
++		   pcd_ep->dwc_ep.phys, (unsigned long)pcd_ep);
++
++	/* Set the TRB allocation for this EP */
++	desc = dwc_usb3_pcd_trb_alloc(pcd_ep, num_trbs, ep_type, ep_desc->bInterval - 1,
++				      link, &desc_dma);
++	if (!desc)
++		return NULL;
++
++	/* Call the PCD API routine to enable the endpoint */
++	retval = dwc_usb3_pcd_ep_enable(pcd, pcd_ep, ep_desc, ep_comp);
++	if (retval) {
++		dwc_usb3_pcd_trb_free(pcd_ep);
++		return NULL;
++	}
++
++	usb_ep->maxpacket = UGETW(ep_desc->wMaxPacketSize);
++	usb_ep->desc = epdesc;
++
++	return usb_ep;
++}
++
++/**
++ * This routine disables a USB endpoint
++ *
++ * @param usb3_dev      Programming view of DWC_usb3 device.
++ * @param usb_ep        USB EP to disable.
++ * @return              0 for success, else negative error code.
++ */
++int dwc_usb3_ep_disable(struct dwc_usb3_device *usb3_dev, usb_ep_t *usb_ep)
++{
++	dwc_usb3_pcd_t		*pcd = &usb3_dev->pcd;
++	dwc_usb3_pcd_ep_t	*pcd_ep;
++	int			retval;
++
++	dwc_debug2(usb3_dev, "%s(%lx)\n", __func__, (unsigned long)usb_ep);
++	pcd_ep = dwc_usb3_get_pcd_ep(usb_ep);
++
++	/* Call the PCD API routine to disable the endpoint */
++	retval = dwc_usb3_pcd_ep_disable(pcd, pcd_ep);
++
++	dwc_usb3_pcd_trb_free(pcd_ep);
++
++	return retval;
++}
++
++/**
++ * This routine allocates a USB request object to use with the specified USB
++ * endpoint. The contents of a USB request are defined by the Function Driver,
++ * and are opaque to the PCD. The USB request is embedded inside of an enclosing
++ * PCD request object (see the definition of struct dwc_usb3_pcd_req in pcd.h).
++ * One request object is needed for each transfer that is submitted to the PCD.
++ *
++ * @param usb3_dev      Programming view of DWC_usb3 device.
++ * @param usb_ep        USB EP for the request.
++ */
++usb_request_t *dwc_usb3_alloc_request(struct dwc_usb3_device *usb3_dev, usb_ep_t *usb_ep)
++{
++	dwc_usb3_pcd_req_t	*pcd_req;
++	unsigned int		req_idx;
++
++	dwc_debug2(usb3_dev, "%s(%lx)\n", __func__, (unsigned long)usb_ep);
++
++	for (req_idx = 0; req_idx < 32; req_idx++) {
++		if (g_pcd_req_bm & (1 << req_idx)) {
++			g_pcd_req_bm &= ~(1 << req_idx);
++			pcd_req = &g_pcd_req[req_idx];
++			memset(pcd_req, 0, sizeof(*pcd_req));
++			pcd_req->usb_req.dma = DWC_DMA_ADDR_INVALID;
++			return &pcd_req->usb_req;
++		}
++	}
++
++	return NULL;
++}
++
++/**
++ * This routine frees a USB request object
++ *
++ * @param usb3_dev      Programming view of DWC_usb3 device.
++ * @param usb_ep        USB EP for the request.
++ * @param usb_req       USB request to be freed.
++ */
++void dwc_usb3_free_request(struct dwc_usb3_device *usb3_dev, usb_ep_t *usb_ep, usb_request_t *usb_req)
++{
++	dwc_usb3_pcd_req_t	*pcd_req = dwc_usb3_get_pcd_req(usb_req);
++	unsigned int		req_idx = pcd_req - &g_pcd_req[0];
++
++	dwc_debug2(usb3_dev, "%s(%lx)\n", __func__, (unsigned long)usb_ep);
++
++	if (req_idx >= 32) {
++		dwc_error1(usb3_dev, "Bad request index %u\n", req_idx);
++		return;
++	}
++
++	g_pcd_req_bm |= 1 << req_idx;
++}
++
++/**
++ * This routine submits a transfer request for a USB endpoint. The example code
++ * maintains a queue of requests for each endpoint, so that the application can
++ * start another transfer on the same endpoint without having to wait for the
++ * first transfer to complete.
++ *
++ * @param usb3_dev      Programming view of DWC_usb3 device.
++ * @param usb_ep        USB EP for the transfer.
++ * @param usb_req       USB request for the transfer.
++ * @return              0 for success, else negative error code.
++ */
++int dwc_usb3_ep_queue(struct dwc_usb3_device *usb3_dev, usb_ep_t *usb_ep, usb_request_t *usb_req)
++{
++	dwc_usb3_pcd_t		*pcd = &usb3_dev->pcd;
++	dwc_usb3_pcd_ep_t	*pcd_ep = dwc_usb3_get_pcd_ep(usb_ep);
++	dwc_usb3_pcd_req_t	*pcd_req = dwc_usb3_get_pcd_req(usb_req);
++	int			retval = 0, req_flags = 0;
++
++	dwc_debug2(usb3_dev, "%s(%lx)\n", __func__, (unsigned long)usb_ep);
++
++	usb_req->status = -DWC_E_IN_PROGRESS;
++	usb_req->actual = 0;
++
++	if (usb_req->zero)
++		req_flags |= DWC_PCD_REQ_ZERO;
++
++	pcd_req->dwc_req.buf[0] = usb_req->buf;
++	pcd_req->dwc_req.bufdma[0] = usb_req->dma;
++	pcd_req->dwc_req.buflen[0] = usb_req->length;
++	pcd_req->dwc_req.numbuf = 1;
++	pcd_req->dwc_req.length = usb_req->length;
++	pcd_req->dwc_req.actual = 0;
++	pcd_req->dwc_req.stream = usb_req->stream_id;
++	pcd_req->dwc_req.flags = req_flags;
++
++	DWC_CIRCLEQ_INIT_ENTRY(pcd_req, entry);
++#if 1
++	if (!DWC_CIRCLEQ_EMPTY(&pcd_ep->dwc_ep.queue)) {
++		/* If queue is not empty, and this is not an Isoc transfer, then
++		 * don't submit the transfer. But we still queue the request so
++		 * it can be submitted later.
++		 */
++		dwc_debug4(usb3_dev, "q !empty, pend %d, stop %d, avail %d, start %d\n",
++			   pcd->request_pending, pcd_ep->dwc_ep.stopped,
++			   pcd_ep->dwc_ep.desc_avail, pcd_ep->dwc_ep.xfer_started);
++
++		if (!pcd_ep->dwc_ep.stopped && pcd_ep->dwc_ep.type == UE_ISOCHRONOUS &&
++		    pcd_ep->dwc_ep.desc_avail > 0 && pcd_ep->dwc_ep.xfer_started)
++			goto do_start;
++	} else
++#endif
++	if (pcd_ep->dwc_ep.stopped || (pcd_ep != pcd->ep0 && pcd_ep->dwc_ep.desc_avail <= 0) ||
++	    (pcd_ep->dwc_ep.type == UE_ISOCHRONOUS && !pcd_ep->dwc_ep.xfer_started)) {
++		/* If EP is stopped, or there is no TRB available, or this
++		 * is an Isoc transfer and the EP is not started, then don't
++		 * submit the transfer. But we still queue the request so it
++		 * can be submitted later.
++		 */
++		dwc_debug4(usb3_dev,
++			   " q empty, pend %d, stop %d, avail %d, start %d\n",
++//			   " pend %d, stop %d, avail %d, start %d\n",
++			   pcd->request_pending, pcd_ep->dwc_ep.stopped,
++			   pcd_ep->dwc_ep.desc_avail, pcd_ep->dwc_ep.xfer_started);
++	} else {
++do_start:
++		/* Call the PCD API routine to set up the request TRBs */
++		dwc_usb3_pcd_fill_trbs(pcd, pcd_ep, pcd_req);
++
++		/* Call the PCD API routine to submit the transfer request */
++		retval = dwc_usb3_pcd_ep_submit_req(pcd, pcd_ep, pcd_req, req_flags);
++	}
++
++	if (!retval) {
++		DWC_CIRCLEQ_INSERT_TAIL(&pcd_ep->dwc_ep.queue, pcd_req, entry);
++		++pcd->request_pending;
++	}
++
++	/* dwc_usb3_pcd_ep_submit_req() can return positive values for
++	 * Control transfers, don't propagate those from this function
++	 */
++	return retval < 0 ? retval : 0;
++}
++
++/**
++ * This routine cancels a transfer request for a USB endpoint. This is only
++ * needed in exceptional cases, a normal transfer completion does not require
++ * this.
++ *
++ * @param usb3_dev      Programming view of DWC_usb3 device.
++ * @param usb_ep        USB EP for the transfer.
++ * @param usb_req       USB request for the transfer.
++ * @return              0 for success, else negative error code.
++ */
++int dwc_usb3_ep_dequeue(struct dwc_usb3_device *usb3_dev, usb_ep_t *usb_ep, usb_request_t *usb_req)
++{
++	dwc_usb3_pcd_t		*pcd = &usb3_dev->pcd;
++	dwc_usb3_pcd_ep_t	*pcd_ep = dwc_usb3_get_pcd_ep(usb_ep);
++	dwc_usb3_pcd_req_t	*pcd_req;
++
++	dwc_debug2(usb3_dev, "%s(%lx)\n", __func__, (unsigned long)usb_ep);
++
++	if (dwc_usb3_pcd_ep_num(pcd_ep) != 0 && !pcd_ep->dwc_ep.usb_ep_desc) {
++		dwc_warn1(usb3_dev, "%s, bad pcd_ep\n", __func__);
++		return -DWC_E_INVALID;
++	}
++
++	/* Make sure it's actually queued on this EP */
++	DWC_CIRCLEQ_FOREACH(pcd_req, &pcd_ep->dwc_ep.queue, entry) {
++		if (&pcd_req->usb_req == usb_req)
++			break;
++	}
++
++	if (!pcd_req) {
++		dwc_warn1(usb3_dev, "%s, no request in queue\n", __func__);
++		return 0;
++	}
++
++	/* Call the PCD API routine to cancel the transfer request */
++	dwc_usb3_pcd_ep_cancel_req(pcd, pcd_ep, pcd_req, usb_req->stream_id);
++
++	return 0;
++}
++
++/**
++ * Function Driver initialization routine
++ *
++ * @param usb3_dev      Programming view of DWC_usb3 device.
++ * @return              0 for success, else negative error code.
++ */
++int dwc_usb3_gadget_init(dwc_usb3_device_t *usb3_dev)
++{
++	dwc_usb3_pcd_t		*pcd = &usb3_dev->pcd;
++	dwc_usb3_pcd_ep_t	*ep;
++	int			i;
++
++	dwc_debug1(usb3_dev, "%s()\n", __func__);
++
++	ep = pcd->ep0;
++	ep->dwc_ep.num = 0;
++	DWC_CIRCLEQ_INIT(&ep->dwc_ep.queue);
++
++	for (i = 0; i < pcd->num_out_eps; i++) {
++		ep = pcd->out_ep[i];
++		ep->dwc_ep.num = i + 1;
++		DWC_CIRCLEQ_INIT(&ep->dwc_ep.queue);
++	}
++
++	for (i = 0; i < pcd->num_in_eps; i++) {
++		ep = pcd->in_ep[i];
++		ep->dwc_ep.num = i + 1;
++		DWC_CIRCLEQ_INIT(&ep->dwc_ep.queue);
++	}
++
++	return 0;
++}
++
++/**
++ * Function Driver removal routine
++ *
++ * @param usb3_dev      Programming view of DWC_usb3 device.
++ */
++void dwc_usb3_gadget_remove(dwc_usb3_device_t *usb3_dev)
++{
++	dwc_debug1(usb3_dev, "%s()\n", __func__);
++}
+diff --git a/drivers/usb/gadget/udc/hiudc3/no_os/no_os_hiber.c b/drivers/usb/gadget/udc/hiudc3/no_os/no_os_hiber.c
+new file mode 100644
+index 0000000..995eb40
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc3/no_os/no_os_hiber.c
+@@ -0,0 +1,136 @@
++/** @file
++ */
++
++#include "os_defs.h"
++#include "hw.h"
++#include "usb.h"
++#include "pcd.h"
++#include "dev.h"
++#include "os_dev.h"
++#include "cil.h"
++
++/**
++ * Helper routine for dwc_wait_pme_thread()
++ */
++static void dwc_wait_for_link_up(dwc_usb3_pcd_t *pcd)
++{
++	unsigned long flags;
++	u32 temp;
++	int count = 5;
++
++	while (count-- > 0) {
++		dwc_msleep(pcd->usb3_dev, 20);
++		dwc_acquire_spinlock_irq(pcd->usb3_dev, &pcd->lock, flags);
++		temp = dwc_usb3_pcd_get_link_state(pcd);
++		if (temp == 0) {
++			dwc_info0(pcd->usb3_dev, "Exiting from hibernation 2\n");
++			pcd->usb3_dev->hiber_wait_connect = 0;
++
++			/* Perform the steps in Section 9.1.3 "Initialization on
++			 * Connect Done" in [DWSS].
++			 */
++			dwc_usb3_handle_connect_done_intr(pcd);
++			dwc_exit_hibernation_after_connect(pcd, 0);
++			count = 0;
++		}
++
++		dwc_release_spinlock_irq(pcd->usb3_dev, &pcd->lock, flags);
++	}
++}
++
++/**
++ * Routine that monitors the dev->hibernate variable and the 'debug'
++ * register in the FPGA. dev->hibernate is set to 1 or 2 from the interrupt
++ * handler when the core is requesting to enter hibernation. This routine
++ * checks whether it is safe to do so (dev->hiber_cnt == 0) and then sets
++ * dev->hibernate to 3 and puts the core into hibernation. dev->hibernate >= 3
++ * tells the rest of the driver that it cannot access the hardware.
++ *
++ * When the core is in hibernation, this routine should be called periodically
++ * to read the 'debug' register to see if the core is requesting to exit
++ * hibernation. If so, it brings the core out of hibernation.
++ *
++ * Note that this is NOT the way a "real" device would enter and exit
++ * hibernation. This code is ONLY for testing hibernation on the Synopsys
++ * HAPS platform.
++ */
++int dwc_usb3_wait_pme(dwc_usb3_device_t *dev)
++{
++	dwc_usb3_pcd_t *pcd = &dev->pcd;
++	unsigned long flags;
++	u32 temp;
++	int state, i;
++
++	dwc_acquire_spinlock_irq(dev, &pcd->lock, flags);
++	temp = dev->hibernate;
++
++	if (dev->hiber_cnt == 0) {
++		if (temp == DWC_HIBER_ENTER_NOSAVE || temp == DWC_HIBER_ENTER_SAVE) {
++			dwc_enter_hibernation(pcd, temp == DWC_HIBER_ENTER_SAVE);
++			temp = DWC_HIBER_SLEEPING;
++		}
++	}
++
++	if (temp == DWC_HIBER_WAIT_LINK_UP) {
++		dev->hibernate = DWC_HIBER_AWAKE;
++		temp = DWC_HIBER_AWAKE;
++		dwc_release_spinlock_irq(dev, &pcd->lock, flags);
++		dwc_wait_for_link_up(pcd);
++		dwc_acquire_spinlock_irq(dev, &pcd->lock, flags);
++	}
++
++	if (temp == DWC_HIBER_WAIT_U0) {
++		state = dwc_usb3_pcd_get_link_state(pcd);
++		if (state == 0) {
++			dev->hibernate = DWC_HIBER_AWAKE;
++			temp = DWC_HIBER_AWAKE;
++		}
++	}
++
++	if (temp == DWC_HIBER_SS_DIS_QUIRK) {
++		for (i = 0; i < 500; i++) {
++			temp = dev->hibernate;
++			if (temp != DWC_HIBER_SS_DIS_QUIRK) {
++				dwc_debug1(dev, "breaking loop after %d ms\n", i);
++				break;
++			}
++
++			dwc_release_spinlock_irq(dev, &pcd->lock, flags);
++			dwc_msleep(dev, 1);
++			dwc_acquire_spinlock_irq(dev, &pcd->lock, flags);
++		}
++
++		if (temp == DWC_HIBER_SS_DIS_QUIRK) {
++			if (dwc_usb3_pcd_get_link_state(pcd) == DWC_LINK_STATE_SS_DIS) {
++				dwc_enter_hibernation(pcd, 0);
++				temp = DWC_HIBER_SLEEPING;
++			} else {
++				dev->hibernate = DWC_HIBER_AWAKE;
++				temp = DWC_HIBER_AWAKE;
++			}
++		}
++	}
++
++	dwc_release_spinlock_irq(dev, &pcd->lock, flags);
++	dwc_msleep(dev, 1);
++
++	return temp;
++}
++
++int dwc_usb3_handle_pme_intr(dwc_usb3_device_t *dev)
++{
++	int ret;
++
++	dwc_debug1(dev, "%s()\n", __func__);
++
++	dwc_debug0(dev, "calling dwc_exit_hibernation()\n");
++	ret = dwc_exit_hibernation(&dev->pcd, 1);
++	if (ret)
++		dwc_info1(dev, "dwc_exit_hibernation() returned %d\n", ret);
++
++	return 1;
++}
++
++void dwc_usb3_power_ctl(dwc_usb3_device_t *dev, int on)
++{
++}
+diff --git a/drivers/usb/gadget/udc/hiudc3/no_os/no_os_init.c b/drivers/usb/gadget/udc/hiudc3/no_os/no_os_init.c
+new file mode 100644
+index 0000000..939b323
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc3/no_os/no_os_init.c
+@@ -0,0 +1,674 @@
++/** @file
++ */
++
++#include "os_defs.h"
++#include "hw.h"
++#include "usb.h"
++#include "pcd.h"
++#include "dev.h"
++#include "os_dev.h"
++#include "cil.h"
++
++#ifdef LINUXTEST
++#define DWC_DRIVER_VERSION	"2.90b - November 2014"
++#define DWC_DRIVER_DESC		"SS USB3 Controller driver"
++
++static const char dwc_driver_name[] = "dwc_usb3";
++#endif
++
++/**
++ * The simulation environment doesn't have a malloc() function, so all data
++ * structures are statically allocated
++ */
++
++/** Driver context struct */
++dwc_usb3_device_t			g_usb3_dev;
++
++/** @{ */
++/** Endpoint context structs */
++static dwc_usb3_pcd_ep_t		g_ep0;
++static dwc_usb3_pcd_ep_t		g_out_ep[DWC_MAX_EPS - 1];
++static dwc_usb3_pcd_ep_t		g_in_ep[DWC_MAX_EPS - 1];
++/** @} */
++
++/** EP0 PCD request */
++static dwc_usb3_pcd_req_t		g_ep0_req;
++
++/** @{ */
++/** PCD request pool */
++dwc_usb3_pcd_req_t			g_pcd_req[32];
++u32					g_pcd_req_bm;
++/** @} */
++
++/** Driver options struct, default values are defined here */
++dwc_usb3_core_params_t usb3ss_module_params = {
++	.burst = 1,
++	.newcore = 0,
++	.phy = 2,
++	.wakeup = 0,
++	.pwrctl = 3,
++	.lpmctl = 1,
++	.phyctl = 1,
++	.usb2mode = 0,
++	.hibernate = 0,
++	.hiberdisc = 1,
++	.clkgatingen = 0,
++	.ssdisquirk = 0,
++	.nobos = 0,
++	.loop = 0,
++	.nump = 16,
++	.newcsr = 0,
++	.rxfsz = 0,
++	.txfsz = { 0, },
++	.txfsz_cnt = 0,
++};
++
++#ifndef LINUXTEST
++/*** The following data structures must be in coherent DMA capable memory.
++ *** All memory in the simulation environment is such, and physical address
++ *** == virtual address, so we can just allocate these statically.
++ ***/
++
++/** Event buffer */
++static u32				g_event_buf[DWC_EVENT_BUF_SIZE];
++
++/** EP0 SETUP packet buffer */
++static char				g_ep0_setup_pkt[8];
++
++/** Data packet buffer used to return data for GET_STATUS and
++ *  GET_DESCRIPTOR requests, up to 512 bytes in length
++ */
++static u8				g_ep0_status_buf[DWC_STATUS_BUF_SIZE];
++
++/** DMA descriptor (TRB) for EP0 SETUP packets */
++static UALIGNED16 dwc_usb3_dma_desc_t	g_ep0_setup_desc;
++
++/** DMA descriptor (TRB) for EP0 Data Out and Status Out phases */
++static UALIGNED16 dwc_usb3_dma_desc_t	g_ep0_out_desc;
++
++/** DMA descriptor (TRB) for EP0 Data In and Status In phases */
++static UALIGNED16 dwc_usb3_dma_desc_t	g_ep0_in_desc;
++
++/** @{ */
++/** DMA descriptor (TRB) pools for non-EP0 EPs */
++UALIGNED16 dwc_usb3_dma_desc_t	g_out_trb_pool[DWC_MAX_EPS - 1][DWC_NUM_ISOC_TRBS + 1];
++UALIGNED16 dwc_usb3_dma_desc_t	g_in_trb_pool[DWC_MAX_EPS - 1][DWC_NUM_ISOC_TRBS + 1];
++/** @} */
++
++/** @{ */
++/** Scratchpad buffers for hibernation support */
++static char				g_hiber_scratchpad[15][64];
++static struct dwc_hiber_scratchpad_array g_hiber_scratchpad_array;
++/** @} */
++#endif
++
++#ifdef LINUXTEST
++module_param_named(newcsr, usb3ss_module_params.newcsr, int, S_IRUGO|S_IWUSR);
++MODULE_PARM_DESC(newcsr, "'gasket' has new, smaller CSR space (0=no, 1=yes)");
++#endif
++
++/*
++ * Hook to override the default Phy configuration in dwc_usb3_pcd_device_init()
++ * with a HAPS-specific one
++ */
++static void haps_phy_config_hook(struct dwc_usb3_device *dev, int soft_reset,
++				 int restore)
++{
++	dwc_usb3_core_global_regs_t __iomem *global_regs =
++						dev->core_global_regs;
++	u32 temp;
++
++	switch (dev->core_params->phy) {
++	case 3:		// 16-bit UTMI+ SNPS Phy
++		temp = dwc_rd32(dev, &global_regs->gusb2phycfg[0]);
++		temp &= ~DWC_USB2PHYCFG_USB_TRD_TIM_BITS;
++		temp |= DWC_USB2PHYCFG_16B_PHY_IF_BIT;
++		temp |= 5 << DWC_USB2PHYCFG_USB_TRD_TIM_SHIFT;
++		dwc_wr32(dev, &global_regs->gusb2phycfg[0], temp);
++		break;
++	case 2:		// 8-bit UTMI+ / ULPI TI or SNPS Phy
++	case 1:		// old 8-bit UTMI+ SNPS Phy
++		temp = dwc_rd32(dev, &global_regs->gusb2phycfg[0]);
++		temp &= ~DWC_USB2PHYCFG_USB_TRD_TIM_BITS;
++		temp &= ~DWC_USB2PHYCFG_16B_PHY_IF_BIT;
++		temp |= 9 << DWC_USB2PHYCFG_USB_TRD_TIM_SHIFT;
++		dwc_wr32(dev, &global_regs->gusb2phycfg[0], temp);
++		break;
++	default:	// RocketIO Phy
++		if (dev->core_params->usb2mode == 0) {
++			/* Set rx-eq, differential swing */
++			dwc_wr32(dev, (volatile u32 __iomem *)
++				 (dev->base + dev->gasket_ofs + 8), 0x41);
++#ifdef LECROY
++			/* Rx-detect for LeCroy */
++			dwc_wr32(dev, (volatile u32 __iomem *)
++				 (dev->base + dev->gasket_ofs + 4), 0x200);
++#else
++			dwc_wr32(dev, (volatile u32 __iomem *)
++				 (dev->base + dev->gasket_ofs + 4), 0);
++#endif
++		}
++	}
++}
++
++#ifdef LINUXTEST
++static irqreturn_t dwc_usb3_common_irq(int irq, void *dev
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
++				       , struct pt_regs *regs
++#endif
++				      )
++{
++	dwc_usb3_device_t *usb3_dev = dev;
++	int retval;
++
++	dwc_acquire_spinlock(usb3_dev, &usb3_dev->pcd.lock);
++	retval = dwc_usb3_irq(usb3_dev, irq);
++	dwc_release_spinlock(usb3_dev, &usb3_dev->pcd.lock);
++
++	return IRQ_RETVAL(retval);
++}
++#else
++/**
++ * This routine is the top level interrupt handler for the Common
++ * (Core and Device) interrupts
++ */
++void dwc_usb3_common_irq(int irq, void *dev)
++{
++	dwc_usb3_device_t *usb3_dev = dev;
++
++	dwc_acquire_spinlock(usb3_dev, &usb3_dev->pcd.lock);
++	dwc_usb3_irq(usb3_dev, irq);
++	dwc_release_spinlock(usb3_dev, &usb3_dev->pcd.lock);
++}
++#endif
++
++/**
++ * This routine de-initializes the driver
++ */
++#ifdef LINUXTEST
++static void dwc_usb3_driver_remove(struct pci_dev *dev)
++#else
++void dwc_usb3_driver_remove(void)
++#endif
++{
++	dwc_usb3_device_t *usb3_dev = &g_usb3_dev;
++	u32 *event_buf;
++	dwc_dma_t event_buf_dma;
++
++	dwc_debug0(usb3_dev, "usb3ss_driver_remove()\n");
++
++	if (usb3_dev->cmn_irq_installed) {
++		usb3_dev->cmn_irq_installed = 0;
++#ifdef LINUXTEST
++		free_irq(dev->irq, usb3_dev);
++#endif
++	}
++
++	if (usb3_dev->pcd_initialized) {
++		usb3_dev->pcd_initialized = 0;
++		dwc_usb3_pcd_remove(usb3_dev);
++	}
++
++	if (usb3_dev->gadget_initialized) {
++		usb3_dev->gadget_initialized = 0;
++		dwc_usb3_function_remove(usb3_dev);
++		dwc_usb3_gadget_remove(usb3_dev);
++	}
++
++	if (usb3_dev->cmn_initialized) {
++		usb3_dev->cmn_initialized = 0;
++		dwc_usb3_pcd_common_remove(usb3_dev);
++	}
++
++#ifdef LINUXTEST
++	if (usb3_dev->pcd.ep0_setup_pkt)
++		dma_free_coherent(&dev->dev,
++				  sizeof(*usb3_dev->pcd.ep0_setup_pkt) * 5,
++				  usb3_dev->pcd.ep0_setup_pkt,
++				  usb3_dev->pcd.ep0_setup_pkt_dma);
++
++	if (usb3_dev->pcd.ep0_status_buf)
++		dma_free_coherent(&dev->dev,
++				  DWC_STATUS_BUF_SIZE,
++				  usb3_dev->pcd.ep0_status_buf,
++				  usb3_dev->pcd.ep0_status_buf_dma);
++
++	if (usb3_dev->pcd.ep0_in_desc)
++		dma_free_coherent(&dev->dev,
++				  sizeof(dwc_usb3_dma_desc_t),
++				  usb3_dev->pcd.ep0_in_desc,
++				  usb3_dev->pcd.ep0_in_desc_dma);
++
++	if (usb3_dev->pcd.ep0_out_desc)
++		dma_free_coherent(&dev->dev,
++				  sizeof(dwc_usb3_dma_desc_t),
++				  usb3_dev->pcd.ep0_out_desc,
++				  usb3_dev->pcd.ep0_out_desc_dma);
++
++	if (usb3_dev->pcd.ep0_setup_desc)
++		dma_free_coherent(&dev->dev,
++				  sizeof(dwc_usb3_dma_desc_t),
++				  usb3_dev->pcd.ep0_setup_desc,
++				  usb3_dev->pcd.ep0_setup_desc_dma);
++#endif
++
++	event_buf = usb3_dev->event_buf[0];
++	event_buf_dma = usb3_dev->event_buf_dma[0];
++	if (event_buf) {
++		dwc_usb3_dis_flush_eventbuf_intr(usb3_dev, 0);
++		usb3_dev->event_buf[0] = NULL;
++#ifdef LINUXTEST
++		dma_free_coherent(&dev->dev, DWC_EVENT_BUF_SIZE * sizeof(u32),
++				  event_buf, event_buf_dma);
++#endif
++	}
++
++	if (usb3_dev->sysfs_initialized)
++		usb3_dev->sysfs_initialized = 0;
++
++#ifdef LINUXTEST
++	/*
++	 * Clear the drvdata pointer.
++	 */
++	pci_set_drvdata(dev, NULL);
++
++	/*
++	 * Return the memory.
++	 */
++	if (usb3_dev->base)
++		iounmap(usb3_dev->base);
++	if (usb3_dev->rsrc_start)
++		release_mem_region(usb3_dev->rsrc_start, usb3_dev->rsrc_len);
++
++	//pci_disable_device(dev);
++#endif
++
++	return;
++}
++
++/**
++ * This routine initializes the driver
++ *
++ * This routine must be called in a context that allows <strong>dwc_msleep()
++ * </strong> to be used, because that function is called while waiting for the
++ * core to come out of reset.
++ */
++#ifdef LINUXTEST
++static int dwc_usb3_driver_probe(struct pci_dev *dev,
++				 const struct pci_device_id *id)
++#else
++dwc_usb3_device_t *dwc_usb3_driver_init(u32 base_addr_dwc)
++#endif
++{
++	dwc_usb3_device_t *usb3_dev = &g_usb3_dev;
++	u32 addr_ofs = 0xc000;
++	int retval, i;
++
++	dwc_debug0(usb3_dev, "usb3ss_driver_init()\n");
++
++	memset(usb3_dev, 0, sizeof(*usb3_dev));
++	dwc_init_spinlock(usb3_dev, &usb3_dev->pcd.lock);
++
++#ifdef LINUXTEST
++	dev_dbg(&dev->dev, "start=0x%08x\n", (unsigned)pci_resource_start(dev, 0));
++	dev_dbg(&dev->dev, "len=0x%08x\n", (unsigned)pci_resource_len(dev, 0));
++
++	if (!id) {
++		dev_err(&dev->dev, "id parameter NULL!\n");
++		return -EINVAL;
++	}
++
++	if (pci_enable_device(dev) < 0) {
++		dev_err(&dev->dev, "pci_enable_device() failed!\n");
++		return -ENODEV;
++	}
++
++	dev->current_state = PCI_D0;
++	dev->dev.power.power_state = PMSG_ON;
++
++	if (!dev->irq) {
++		dev_err(&dev->dev, "no IRQ for PCI device!\n");
++		retval = -ENODEV;
++		goto fail;
++	}
++
++	usb3_dev->dev = &dev->dev;
++	pci_set_drvdata(dev, usb3_dev);
++
++	dev_dbg(&dev->dev, "dwc_usb3_device=%lx\n", (unsigned long)usb3_dev);
++
++	usb3_dev->rsrc_start = pci_resource_start(dev, 0);
++	usb3_dev->rsrc_len = pci_resource_len(dev, 0);
++
++	if (!usb3_dev->rsrc_start || !usb3_dev->rsrc_len) {
++		dev_err(&dev->dev, "bad PCI resource!\n");
++		retval = -ENOMEM;
++		goto fail;
++	}
++
++	/*
++	 * Map the DWC_usb3 Core memory into virtual address space.
++	 */
++	if (!request_mem_region(usb3_dev->rsrc_start,
++				usb3_dev->rsrc_len, "usb3")) {
++		dev_err(&dev->dev, "request_mem_region() failed!\n");
++
++		/* Flag for dwc_usb3_driver_remove() that we failed */
++		usb3_dev->rsrc_start = 0;
++
++		retval = -EBUSY;
++		goto fail;
++	}
++
++	usb3_dev->base = ioremap_nocache(usb3_dev->rsrc_start,
++					 usb3_dev->rsrc_len);
++	if (!usb3_dev->base) {
++		dev_err(&dev->dev, "ioremap_nocache() failed!\n");
++		retval = -ENOMEM;
++		goto fail;
++	}
++
++	if (usb3ss_module_params.newcsr)
++		usb3_dev->gasket_ofs = 0xf000;
++	else
++		usb3_dev->gasket_ofs = 0x80000;
++
++	dev_dbg(&dev->dev, "base=%lx\n", (unsigned long)usb3_dev->base);
++
++	usb3_dev->sysfs_initialized = 1;
++#else
++	usb3_dev->base = (volatile u8 __iomem *)(long)base_addr_dwc;
++#endif
++
++	/*
++	 * Checks that this device is really a DWC_usb3 controller. Also saves
++	 * the SNPSID register value in usb3_dev->snpsid for later use by the
++	 * PCD.
++	 */
++	retval = dwc_usb3_pcd_check_snpsid(usb3_dev, addr_ofs);
++	if (retval) {
++		dwc_error0(&dev->dev, "bad value for SNPSID!\n");
++		goto fail;
++	}
++
++	if (usb3ss_module_params.newcore && usb3_dev->snpsid < 0x5533109a)
++		usb3_dev->snpsid = 0x5533109a;
++
++#ifdef LINUXTEST
++	retval = -ENOMEM;
++
++	/*
++	 * Up to 32 Event Buffers are supported by the hardware, but we only
++	 * use 1
++	 */
++	usb3_dev->event_buf[0] = dma_alloc_coherent(&dev->dev,
++					DWC_EVENT_BUF_SIZE * sizeof(u32),
++					&usb3_dev->event_buf_dma[0],
++					GFP_KERNEL | GFP_DMA32);
++	if (!usb3_dev->event_buf[0]) {
++		dev_err(&dev->dev, "allocation of event_buf failed!\n");
++		goto fail;
++	}
++
++	/*
++	 * Allocate all the data structures that must be in DMA memory
++	 */
++	usb3_dev->pcd.ep0_setup_desc = dma_alloc_coherent(
++			&dev->dev, sizeof(dwc_usb3_dma_desc_t),
++			&usb3_dev->pcd.ep0_setup_desc_dma,
++			GFP_KERNEL | GFP_DMA32);
++	if (!usb3_dev->pcd.ep0_setup_desc)
++		goto fail;
++
++	usb3_dev->pcd.ep0_out_desc = dma_alloc_coherent(
++			&dev->dev, sizeof(dwc_usb3_dma_desc_t),
++			&usb3_dev->pcd.ep0_out_desc_dma,
++			GFP_KERNEL | GFP_DMA32);
++	if (!usb3_dev->pcd.ep0_out_desc)
++		goto fail;
++
++	usb3_dev->pcd.ep0_in_desc = dma_alloc_coherent(
++			&dev->dev, sizeof(dwc_usb3_dma_desc_t),
++			&usb3_dev->pcd.ep0_in_desc_dma,
++			GFP_KERNEL | GFP_DMA32);
++	if (!usb3_dev->pcd.ep0_in_desc)
++		goto fail;
++
++	usb3_dev->pcd.ep0_status_buf = dma_alloc_coherent(
++			&dev->dev, DWC_STATUS_BUF_SIZE,
++			&usb3_dev->pcd.ep0_status_buf_dma,
++			GFP_KERNEL | GFP_DMA32);
++	if (!usb3_dev->pcd.ep0_status_buf)
++		goto fail;
++
++	usb3_dev->pcd.ep0_setup_pkt = dma_alloc_coherent(
++			&dev->dev, sizeof(*usb3_dev->pcd.ep0_setup_pkt) * 5,
++			&usb3_dev->pcd.ep0_setup_pkt_dma,
++			GFP_KERNEL | GFP_DMA32);
++	if (!usb3_dev->pcd.ep0_setup_pkt)
++		goto fail;
++#else
++	/*
++	 * Up to 32 Event Buffers are supported by the hardware, but we only
++	 * use 1
++	 */
++	usb3_dev->event_buf[0] = g_event_buf;
++	usb3_dev->event_buf_dma[0] = (dwc_dma_t)g_event_buf;
++
++	/*
++	 * "allocate" all the data structures that must be in DMA memory
++	 */
++	usb3_dev->pcd.ep0_setup_desc = &g_ep0_setup_desc;
++	usb3_dev->pcd.ep0_setup_desc_dma = (dwc_dma_t)&g_ep0_setup_desc;
++	usb3_dev->pcd.ep0_out_desc = &g_ep0_out_desc;
++	usb3_dev->pcd.ep0_out_desc_dma = (dwc_dma_t)&g_ep0_out_desc;
++	usb3_dev->pcd.ep0_in_desc = &g_ep0_in_desc;
++	usb3_dev->pcd.ep0_in_desc_dma = (dwc_dma_t)&g_ep0_in_desc;
++	usb3_dev->pcd.ep0_status_buf = g_ep0_status_buf;
++	usb3_dev->pcd.ep0_status_buf_dma = (dwc_dma_t)g_ep0_status_buf;
++	usb3_dev->pcd.ep0_setup_pkt = (union dwc_setup_pkt *)g_ep0_setup_pkt;
++	usb3_dev->pcd.ep0_setup_pkt_dma = (dwc_dma_t)g_ep0_setup_pkt;
++
++	for (i = 0; i < 15; i++) {
++		g_hiber_scratchpad_array.dma_addr[i] = (u64)(long)&g_hiber_scratchpad[i];
++		usb3_dev->pcd.hiber_scratchpad[i] = &g_hiber_scratchpad[i];
++	}
++
++	usb3_dev->pcd.hiber_scratchpad_array = &g_hiber_scratchpad_array;
++	usb3_dev->pcd.hiber_scratchpad_array_dma = (dwc_dma_t)&g_hiber_scratchpad_array;
++#endif
++
++	/*
++	 * Now "allocate" the remaining data structures
++	 */
++	usb3_dev->pcd.ep0_req = &g_ep0_req;
++	usb3_dev->pcd.ep0 = &g_ep0;
++	for (i = 0; i < DWC_MAX_EPS - 1; i++) {
++		usb3_dev->pcd.out_ep[i] = &g_out_ep[i];
++		usb3_dev->pcd.in_ep[i] = &g_in_ep[i];
++	}
++
++	g_pcd_req_bm = 0xffffffff;
++
++	/*
++	 * Add our hook to override the default Phy register setup
++	 */
++	usb3_dev->phy_config_hook = haps_phy_config_hook;
++
++	/*
++	 * Initialize the DWC_usb3 core
++	 */
++	retval = dwc_usb3_pcd_common_init(usb3_dev, usb3_dev->base + addr_ofs,
++					  &usb3ss_module_params);
++	if (retval) {
++		dwc_error0(usb3_dev, "CIL initialization failed!\n");
++		goto fail;
++	}
++
++	usb3_dev->cmn_initialized = 1;
++
++	/*
++	 * Initialize the Function Driver interface
++	 */
++	retval = dwc_usb3_gadget_init(usb3_dev);
++	if (retval) {
++		dwc_error0(usb3_dev, "gadget initialization failed!\n");
++		goto fail;
++	}
++
++	/*
++	 * Initialize the Function Driver
++	 */
++	retval = dwc_usb3_function_init(usb3_dev);
++	if (retval) {
++		dwc_error0(usb3_dev, "loopback gadget initialization failed!\n");
++		dwc_usb3_gadget_remove(usb3_dev);
++		goto fail;
++	}
++
++	usb3_dev->gadget_initialized = 1;
++
++	/*
++	 * Initialize the PCD
++	 */
++	retval = dwc_usb3_pcd_init(usb3_dev);
++	if (retval) {
++		dwc_error0(usb3_dev, "PCD initialization failed!\n");
++		goto fail;
++	}
++
++	usb3_dev->pcd_initialized = 1;
++
++#ifdef LINUXTEST
++	/*
++	 * Install the interrupt handler for the common interrupts.
++	 */
++	dev_dbg(&dev->dev, "registering (common) handler for irq%d\n",
++		dev->irq);
++	retval = request_irq(dev->irq, dwc_usb3_common_irq,
++			     IRQF_SHARED | IRQF_DISABLED,
++			     dwc_driver_name, usb3_dev);
++	if (retval) {
++		dev_err(&dev->dev, "request of irq%d failed!\n", dev->irq);
++		retval = -EBUSY;
++		goto fail;
++	}
++#else
++# if 0 // Interrupt handler is hooked up before this routine is called
++	// Register interrupt service routine for DWC interrupt
++	interrupt_priority_set(USB3SS_DWC_INT, 5);
++	interrupt_target_set(USB3SS_DWC_INT, CPU0, 1);
++	intRegister(USB3SS_DWC_INT, usb3ss_common_irq, usb3_dev);
++	interrupt_enable(USB3SS_DWC_INT, 1);
++# endif
++#endif
++	usb3_dev->cmn_irq_installed = 1;
++
++#ifdef LINUXTEST
++	return 0;
++#else
++	return usb3_dev;
++#endif
++
++fail:
++#ifdef LINUXTEST
++	dwc_usb3_driver_remove(dev);
++
++	return retval;
++#else
++	dwc_usb3_driver_remove();
++
++	return NULL;
++#endif
++}
++
++#ifdef LINUXTEST
++
++#define PCI_VENDOR_ID_SYNOPSYS		0x16c3
++#define PCI_DEVICE_ID_SYNOPSYS_SITKA	0xabcd
++
++static const struct pci_device_id pci_ids[] = {
++	{
++		/* The Synopsys PCIe card */
++		PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,
++			   PCI_DEVICE_ID_SYNOPSYS_SITKA),
++		.driver_data = (unsigned long)0xdeadbeef,
++	},
++	{ 0, }	/* end: all zeroes */
++};
++MODULE_DEVICE_TABLE(pci, pci_ids);
++
++/**
++ * This structure defines the methods to be called by a bus driver
++ * during the lifecycle of a device on that bus. Both drivers and
++ * devices are registered with a bus driver. The bus driver matches
++ * devices to drivers based on information in the device and driver
++ * structures.
++ *
++ * The probe routine is called when the bus driver matches a device
++ * to this driver. The remove routine is called when a device is
++ * unregistered with the bus driver.
++ */
++static struct pci_driver dwc_usb3_driver = {
++	.name		= (char *)dwc_driver_name,
++	.id_table	= pci_ids,
++	.probe		= dwc_usb3_driver_probe,
++	.remove		= dwc_usb3_driver_remove,
++	.driver = {
++		.name		= (char *)dwc_driver_name,
++	},
++};
++
++/**
++ * This routine is called when the DWC_usb3 driver is loaded into the kernel
++ * with the insmod command. It registers the dwc_usb3_driver structure with the
++ * appropriate bus driver. This will cause the dwc_usb3_driver_probe routine
++ * to be called. In addition, the bus driver will automatically expose
++ * attributes defined for the device and driver in the special sysfs file
++ * system.
++ */
++static int __init dwc_usb3_driver_init(void)
++{
++	int retval = 0;
++
++	printk(KERN_INFO "%s: %s version %s\n", dwc_driver_name,
++	       DWC_DRIVER_DESC, DWC_DRIVER_VERSION);
++	retval = pci_register_driver(&dwc_usb3_driver);
++
++	if (retval < 0) {
++		printk(KERN_ERR "%s retval=%d\n", __func__, retval);
++		return retval;
++	}
++
++	printk(KERN_INFO "%s: module installed\n", dwc_driver_name);
++	return retval;
++}
++module_init(dwc_usb3_driver_init);
++
++/**
++ * This routine is called when the DWC_usb3 driver is removed from the kernel
++ * with the rmmod command. The driver unregisters itself with its bus driver.
++ *
++ */
++static void __exit dwc_usb3_driver_exit(void)
++{
++	printk(KERN_DEBUG "%s: driver_exit()\n", dwc_driver_name);
++
++	pci_unregister_driver(&dwc_usb3_driver);
++
++	printk(KERN_INFO "%s: module removed\n", dwc_driver_name);
++}
++module_exit(dwc_usb3_driver_exit);
++
++MODULE_DESCRIPTION(DWC_DRIVER_DESC);
++MODULE_AUTHOR("Synopsys Inc.");
++MODULE_LICENSE("GPL");
++
++#else /* !LINUXTEST */
++
++int main(int argc, char *argv[])
++{
++	return 0;
++}
++
++#endif
+diff --git a/drivers/usb/gadget/udc/hiudc3/no_os/no_os_src_sink_lpbk.c b/drivers/usb/gadget/udc/hiudc3/no_os/no_os_src_sink_lpbk.c
+new file mode 100644
+index 0000000..66f3efa
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc3/no_os/no_os_src_sink_lpbk.c
+@@ -0,0 +1,485 @@
++/** @file
++ *
++ * Loopback/source-sink Function Driver which uses the application-specific
++ * interface in no_os_gadget.c
++ */
++
++#include "os_defs.h"
++#include "hw.h"
++#include "usb.h"
++#include "pcd.h"
++#include "dev.h"
++#include "os_dev.h"
++#include "cil.h"
++
++#define DWC_BUF_SIZ	(1024 * 1024)
++
++/** Driver context struct - defined in no_os_init.c */
++extern dwc_usb3_device_t	g_usb3_dev;
++
++#ifndef LINUXTEST
++/** @{ */
++/** Transfer buffers - 1MB each */
++static char		g_in_buf[DWC_BUF_SIZ];
++static char		g_out_buf[DWC_BUF_SIZ];
++/** @} */
++#endif
++
++/**
++ * The FPGA configuration is limited to a maximum transfer size of 128K by
++ * default, so allocate 8 128K requests for each 1MB buffer.
++ * NOTE: DWC_NUM_REQ * DWC_REQ_SIZ must be <= DWC_BUF_SIZ !
++ */
++/** @{ */
++#define DWC_NUM_REQ	8
++#define DWC_REQ_SIZ	(128 * 1024)
++/** @} */
++
++/**
++ * Function Driver context struct
++ */
++typedef struct dwc_usb3_loopbk {
++	usb_ep_t	*in_ep, *out_ep;
++	char		*in_buf, *out_buf;
++	dwc_dma_t	in_dma, out_dma;
++	int		speed, maxp;
++	u8		cfg, ifc, next0, src_sink;
++} dwc_usb3_loopbk_t;
++
++/**
++ * The Function Driver context
++ */
++static dwc_usb3_loopbk_t	loopbk;
++
++/**
++ * Function Driver transfer complete callback routine
++ */
++static void loopbk_complete(usb_ep_t *ep, usb_request_t *req)
++{
++	int ret;
++
++	dwc_debug1(&g_usb3_dev, "%s()\n", __func__);
++
++	switch (req->status) {
++	case 0:
++		if (loopbk.src_sink) {
++			if (ep == loopbk.out_ep) {
++				dwc_debug0(&g_usb3_dev, "OUT req, requeuing\n");
++				req->length = DWC_REQ_SIZ;
++				ret = dwc_usb3_ep_queue(&g_usb3_dev, loopbk.out_ep, req);
++				if (ret == 0)
++					return;
++				dwc_error0(&g_usb3_dev, "Failed to requeue OUT req\n");
++			} else {
++				dwc_debug0(&g_usb3_dev, "IN req, requeuing\n");
++				req->length = DWC_REQ_SIZ;
++				ret = dwc_usb3_ep_queue(&g_usb3_dev, loopbk.in_ep, req);
++				if (ret == 0)
++					return;
++				dwc_error0(&g_usb3_dev, "Failed to requeue IN req\n");
++			}
++		} else {
++			if (ep == loopbk.out_ep) {
++				dwc_debug0(&g_usb3_dev, "OUT req, requeuing on IN\n");
++
++				/* Handle 0-length marker packet */
++				if (req->actual && (req->actual & (loopbk.maxp - 1)) == 0)
++					loopbk.next0 = 1;
++
++				/* Echo packet back to host on IN EP */
++				req->length = req->actual;
++				ret = dwc_usb3_ep_queue(&g_usb3_dev, loopbk.in_ep, req);
++				if (ret == 0)
++					return;
++				loopbk.next0 = 0;
++				dwc_error0(&g_usb3_dev, "Failed to queue IN req, requeuing on OUT\n");
++			} else {
++				dwc_debug0(&g_usb3_dev, "IN req, requeuing on OUT\n");
++			}
++
++			/* Handle 0-length marker packet */
++			if (loopbk.next0) {
++				loopbk.next0 = 0;
++				req->length = 0;
++				ret = dwc_usb3_ep_queue(&g_usb3_dev, loopbk.in_ep, req);
++				if (ret == 0)
++					return;
++				dwc_error0(&g_usb3_dev, "Failed to queue IN 0-length req, requeuing on OUT\n");
++			}
++
++			/* Requeue for a future OUT EP transfer */
++			req->length = DWC_REQ_SIZ;
++			ret = dwc_usb3_ep_queue(&g_usb3_dev, loopbk.out_ep, req);
++			if (ret == 0)
++				return;
++			dwc_error0(&g_usb3_dev, "Failed to queue OUT req\n");
++		}
++
++		dwc_usb3_free_request(&g_usb3_dev, ep, req);
++		break;
++
++	default:
++		dwc_error0(&g_usb3_dev, "Bad completion status\n");
++
++		/* Requeue for a future OUT EP transfer */
++		req->length = DWC_REQ_SIZ;
++		ret = dwc_usb3_ep_queue(&g_usb3_dev, loopbk.out_ep, req);
++		if (ret == 0)
++			return;
++		dwc_error0(&g_usb3_dev, "Failed to queue OUT req\n");
++		/* FALL-THRU */
++
++	case -DWC_E_SHUTDOWN:
++		dwc_debug0(&g_usb3_dev, "Shutdown status\n");
++		dwc_usb3_free_request(&g_usb3_dev, ep, req);
++		break;
++	}
++}
++
++/**
++ * Function Driver EP enable routine
++ */
++static int enable_eps(dwc_usb3_device_t *usb3_dev, dwc_usb3_loopbk_t *loopbk)
++{
++	usb_ep_t *in_ep, *out_ep;
++
++	switch (loopbk->speed) {
++	case USB_SPEED_SUPER:
++		in_ep = dwc_usb3_ep_enable(usb3_dev, &ss_config_desc.bulk_in_ep_desc,
++					   &ss_config_desc.bulk_in_ss_ep_comp_desc);
++		if (!in_ep)
++			return -DWC_E_INVALID;
++
++		out_ep = dwc_usb3_ep_enable(usb3_dev, &ss_config_desc.bulk_out_ep_desc,
++					    &ss_config_desc.bulk_out_ss_ep_comp_desc);
++		if (!out_ep) {
++			dwc_usb3_ep_disable(usb3_dev, in_ep);
++			return -DWC_E_INVALID;
++		}
++
++		break;
++
++	case USB_SPEED_HIGH:
++		in_ep = dwc_usb3_ep_enable(usb3_dev, &hs_config_desc.bulk_in_ep_desc, NULL);
++		if (!in_ep)
++			return -DWC_E_INVALID;
++
++		out_ep = dwc_usb3_ep_enable(usb3_dev, &hs_config_desc.bulk_out_ep_desc, NULL);
++		if (!out_ep) {
++			dwc_usb3_ep_disable(usb3_dev, in_ep);
++			return -DWC_E_INVALID;
++		}
++
++		break;
++
++	case USB_SPEED_FULL:
++		in_ep = dwc_usb3_ep_enable(usb3_dev, &fs_config_desc.bulk_in_ep_desc, NULL);
++		if (!in_ep)
++			return -DWC_E_INVALID;
++
++		out_ep = dwc_usb3_ep_enable(usb3_dev, &fs_config_desc.bulk_out_ep_desc, NULL);
++		if (!out_ep) {
++			dwc_usb3_ep_disable(usb3_dev, in_ep);
++			return -DWC_E_INVALID;
++		}
++
++		break;
++
++	default:
++		return -DWC_E_INVALID;
++	}
++
++	loopbk->in_ep = in_ep;
++	loopbk->out_ep = out_ep;
++
++	return 0;
++}
++
++/**
++ * Function Driver EP disable routine
++ */
++static void disable_eps(dwc_usb3_device_t *usb3_dev, dwc_usb3_loopbk_t *loopbk)
++{
++	if (loopbk->out_ep) {
++		dwc_usb3_ep_disable(usb3_dev, loopbk->out_ep);
++		loopbk->out_ep = NULL;
++	}
++
++	if (loopbk->in_ep) {
++		dwc_usb3_ep_disable(usb3_dev, loopbk->in_ep);
++		loopbk->in_ep = NULL;
++	}
++}
++
++/**
++ * Function Driver SET_INTERFACE routine
++ */
++static int set_interface(dwc_usb3_device_t *usb3_dev, dwc_usb3_loopbk_t *loopbk, int alt)
++{
++	usb_request_t	*req;
++	int		i, ret = 0;
++
++	if (alt == -1)
++		goto cleanup;
++
++	/* Already set? */
++	if (loopbk->out_ep)
++		return 0;
++
++	ret = enable_eps(usb3_dev, loopbk);
++	if (ret)
++		return ret;
++
++	ret = -DWC_E_NO_MEMORY;
++
++	if (loopbk->src_sink) {
++		for (i = 0; i < DWC_NUM_REQ; i++) {
++			req = dwc_usb3_alloc_request(usb3_dev, loopbk->in_ep);
++			if (!req)
++				goto cleanup;
++			req->buf = loopbk->in_buf + DWC_REQ_SIZ * i;
++			req->dma = loopbk->in_dma + DWC_REQ_SIZ * i;
++			req->length = DWC_REQ_SIZ;
++			req->complete = loopbk_complete;
++			ret = dwc_usb3_ep_queue(usb3_dev, loopbk->in_ep, req);
++			if (ret)
++				goto cleanup;
++		}
++	}
++
++	for (i = 0; i < DWC_NUM_REQ; i++) {
++		req = dwc_usb3_alloc_request(usb3_dev, loopbk->out_ep);
++		if (!req)
++			goto cleanup;
++		req->buf = loopbk->out_buf + DWC_REQ_SIZ * i;
++		req->dma = loopbk->out_dma + DWC_REQ_SIZ * i;
++		req->length = DWC_REQ_SIZ;
++		req->complete = loopbk_complete;
++		ret = dwc_usb3_ep_queue(usb3_dev, loopbk->out_ep, req);
++		if (ret)
++			goto cleanup;
++	}
++
++	return 0;
++
++cleanup:
++	/* disable_eps() will eventually dequeue all requests queued on each EP,
++	 * and call the ->complete routine with -DWC_E_SHUTDOWN status for each
++	 * one. That in turn will free the request. So all cleanup is done for
++	 * us by this one call.
++	 */
++	disable_eps(usb3_dev, loopbk);
++	loopbk->next0 = 0;
++	return ret;
++}
++
++/**
++ * This routine handles Function Driver specific Setup requests. Generic
++ * requests are handled in ep0.c and no_os_ep0.c.
++ *
++ * @param pcd   Programming view of DWC_usb3 peripheral controller.
++ * @param ctrl  Pointer to the Setup packet for the request.
++ * @return      0 for success, else negative error code.
++ */
++int dwc_usb3_function_setup(dwc_usb3_pcd_t *pcd, usb_device_request_t *ctrl)
++{
++	u16	windex = UGETW(ctrl->wIndex);
++	u16	wvalue = UGETW(ctrl->wValue);
++	u16	wlength = UGETW(ctrl->wLength);
++	int	len = 0, ret = 0;
++
++	switch (ctrl->bRequest) {
++	case UR_SET_FEATURE:
++		dwc_debug0(pcd->usb3_dev, "USB_REQ_SET_FEATURE\n");
++
++		/* We don't need to do anything for this */
++		pcd->ep0->dwc_ep.is_in = 1;
++		pcd->ep0state = EP0_IN_WAIT_NRDY;
++		return 0;
++
++	case UR_SET_INTERFACE:
++		dwc_debug0(pcd->usb3_dev, "USB_REQ_SET_INTERFACE\n");
++		if (!loopbk.cfg || windex) {
++			dwc_error2(pcd->usb3_dev, "cfg=%x wIndex=%x\n", loopbk.cfg, windex);
++			return -DWC_E_NOT_SUPPORTED;
++		}
++
++		dwc_debug1(pcd->usb3_dev, "ifc=%x\n", wvalue);
++
++		/* If interface has changed, disable the old EPs and enable the new ones */
++		if (loopbk.ifc != wvalue) {
++			set_interface(pcd->usb3_dev, &loopbk, -1);
++			ret = set_interface(pcd->usb3_dev, &loopbk, wvalue);
++			if (ret)
++				return ret;
++		}
++
++		loopbk.ifc = wvalue;
++		pcd->ep0->dwc_ep.is_in = 1;
++		pcd->ep0state = EP0_IN_WAIT_NRDY;
++		return 0;
++
++	case UR_GET_INTERFACE:
++		dwc_debug0(pcd->usb3_dev, "USB_REQ_GET_INTERFACE\n");
++		if (!loopbk.cfg) {
++			dwc_error1(pcd->usb3_dev, "cfg=%x\n", loopbk.cfg);
++			return -DWC_E_NOT_SUPPORTED;
++		}
++
++		if (windex) {
++			dwc_error1(pcd->usb3_dev, "wIndex=%x\n", windex);
++			return -DWC_E_DOMAIN;
++		}
++
++		pcd->ep0_status_buf[0] = loopbk.ifc;
++		len = 1;
++		break;
++
++	case UR_SET_CONFIG:
++		dwc_debug0(pcd->usb3_dev, "USB_REQ_SET_CONFIG\n");
++		if (wvalue != 0 && wvalue != 1) { // we only have one configuration
++			dwc_error1(pcd->usb3_dev, "wValue=%x\n", wvalue);
++			return -DWC_E_NOT_SUPPORTED;
++		}
++
++		/* If config already set, clear it and disable the EPs */
++		if (loopbk.cfg) {
++			loopbk.cfg = 0;
++			loopbk.ifc = 0;
++			set_interface(pcd->usb3_dev, &loopbk, -1);
++		}
++
++		/* If new config is 1, enable the EPs for interface 0 */
++		if (wvalue) {
++			loopbk.cfg = wvalue;
++			loopbk.ifc = 0;
++			ret = set_interface(pcd->usb3_dev, &loopbk, 0);
++			if (ret)
++				loopbk.cfg = 0;
++		}
++
++		dwc_debug1(pcd->usb3_dev, "cfg=%x\n", loopbk.cfg);
++		if (ret)
++			return ret;
++		pcd->ep0->dwc_ep.is_in = 1;
++		pcd->ep0state = EP0_IN_WAIT_NRDY;
++		return 0;
++
++	case UR_GET_CONFIG:
++		dwc_debug0(pcd->usb3_dev, "USB_REQ_GET_CONFIG\n");
++		pcd->ep0_status_buf[0] = loopbk.cfg;
++		len = 1;
++		break;
++
++	case UR_SYNCH_FRAME:
++		dwc_debug0(pcd->usb3_dev, "USB_REQ_SYNCH_FRAME\n");
++
++		/* We don't need to do anything for this */
++		pcd->ep0->dwc_ep.is_in = 1;
++		pcd->ep0state = EP0_IN_WAIT_NRDY;
++		return 0;
++
++	default:
++		dwc_debug0(pcd->usb3_dev, "Unknown request!\n");
++		return -DWC_E_NOT_SUPPORTED;
++	}
++
++	/* Start the data phase for 3-stage transfers */
++	pcd->ep0state = EP0_IN_DATA_PHASE;
++	dwc_usb3_pcd_ep0_data_stage(pcd, len < wlength ? len : wlength);
++
++	return 0;
++}
++
++/**
++ * Function Driver CONNECT routine
++ */
++int dwc_usb3_function_connect(struct dwc_usb3_device *usb3_dev, int speed)
++{
++	loopbk.speed = speed;
++
++	switch (speed) {
++	case USB_SPEED_SUPER:
++		loopbk.maxp = 1024;
++		break;
++
++	case USB_SPEED_HIGH:
++		loopbk.maxp = 512;
++		break;
++
++	case USB_SPEED_FULL:
++		loopbk.maxp = 64;
++		break;
++	}
++
++	return 0;
++}
++
++/**
++ * Function Driver DISCONNECT routine
++ */
++int dwc_usb3_function_disconnect(struct dwc_usb3_device *usb3_dev)
++{
++	return 0;
++}
++
++/**
++ * Function Driver initialization routine
++ *
++ * @param usb3_dev      Programming view of DWC_usb3 device.
++ * @return              0 for success, else negative error code.
++ */
++int dwc_usb3_function_init(dwc_usb3_device_t *usb3_dev)
++{
++	dwc_debug1(usb3_dev, "%s()\n", __func__);
++
++	loopbk.src_sink = 0;	/* for now */
++
++#ifndef LINUXTEST
++	if (loopbk.src_sink) {
++		loopbk.in_buf = g_in_buf;
++		loopbk.in_dma = (dwc_dma_t)g_in_buf;
++	}
++
++	loopbk.out_buf = g_out_buf;
++	loopbk.out_dma = (dwc_dma_t)g_out_buf;
++
++	return 0;
++#else
++	if (loopbk.src_sink) {
++		loopbk.in_buf = dma_alloc_coherent(usb3_dev->dev, DWC_BUF_SIZ,
++						   &loopbk.in_dma, GFP_KERNEL | GFP_DMA32);
++		if (!loopbk.in_buf)
++			goto out0;
++	}
++
++	loopbk.out_buf = dma_alloc_coherent(usb3_dev->dev, DWC_BUF_SIZ,
++					    &loopbk.out_dma, GFP_KERNEL | GFP_DMA32);
++	if (!loopbk.out_buf)
++		goto out1;
++
++	return 0;
++
++out1:
++	if (loopbk.src_sink)
++		dma_free_coherent(usb3_dev->dev, DWC_BUF_SIZ, loopbk.in_buf, loopbk.in_dma);
++out0:
++	return -DWC_E_NO_MEMORY;
++#endif
++}
++
++/**
++ * Function Driver removal routine
++ *
++ * @param usb3_dev      Programming view of DWC_usb3 device.
++ */
++void dwc_usb3_function_remove(dwc_usb3_device_t *usb3_dev)
++{
++	dwc_debug1(usb3_dev, "%s()\n", __func__);
++
++#ifdef LINUXTEST
++	dma_free_coherent(usb3_dev->dev, DWC_BUF_SIZ, loopbk.out_buf, loopbk.out_dma);
++	if (loopbk.src_sink)
++		dma_free_coherent(usb3_dev->dev, DWC_BUF_SIZ, loopbk.in_buf, loopbk.in_dma);
++#endif
++}
+diff --git a/drivers/usb/gadget/udc/hiudc3/os_defs.h b/drivers/usb/gadget/udc/hiudc3/os_defs.h
+new file mode 100644
+index 0000000..b013072
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc3/os_defs.h
+@@ -0,0 +1,162 @@
++#ifndef _DWC_LINUX_DEFS_H_
++#define _DWC_LINUX_DEFS_H_
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/**
++ * @file
++ *
++ * This file contains OS-specific includes and definitions.
++ *
++ */
++
++#define DWC_DRIVER_VERSION	"2.90b - November 2014"
++#define DWC_DRIVER_DESC		"SS USB3 Controller driver"
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/init.h>
++#include <linux/device.h>
++#include <linux/platform_device.h>
++#include <linux/sysfs.h>
++#include <linux/errno.h>
++#include <linux/types.h>
++#include <linux/slab.h>
++#include <linux/list.h>
++#include <linux/interrupt.h>
++#include <linux/ctype.h>
++#include <linux/string.h>
++#include <linux/dma-mapping.h>
++#include <linux/jiffies.h>
++#include <linux/delay.h>
++#include <linux/timer.h>
++#include <linux/kthread.h>
++#include <linux/workqueue.h>
++#include <linux/freezer.h>
++#include <linux/stat.h>
++#include <linux/pci.h>
++
++#include <linux/version.h>
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
++# include <linux/irq.h>
++#endif
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
++# include <linux/usb/ch9.h>
++#else
++# include <linux/usb_ch9.h>
++#endif
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++# include <linux/usb/gadget.h>
++# include <linux/usb/otg.h>
++#else
++# include <linux/usb_gadget.h>
++# include <linux/usb_otg.h>
++#endif
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
++# include <asm/irq.h>
++#endif
++
++# include <asm/unaligned.h>
++# include <asm/param.h>
++# include <asm/io.h>
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
++typedef int		gfp_t;
++#endif
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
++# define IRQF_SHARED	SA_SHIRQ
++#endif
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,1,0)
++# define DWC_BOS_IN_GADGET
++#endif
++
++/** @name Error Codes */
++/** @{ */
++#define DWC_E_INVALID		EINVAL
++#define DWC_E_NO_MEMORY		ENOMEM
++#define DWC_E_NO_DEVICE		ENODEV
++#define DWC_E_NOT_SUPPORTED	EOPNOTSUPP
++#define DWC_E_TIMEOUT		ETIMEDOUT
++#define DWC_E_BUSY		EBUSY
++#define DWC_E_AGAIN		EAGAIN
++#define DWC_E_ABORT		ECONNABORTED
++#define DWC_E_SHUTDOWN		ESHUTDOWN
++#define DWC_E_NO_DATA		ENODATA
++#define DWC_E_DISCONNECT	ECONNRESET
++#define DWC_E_UNKNOWN		EINVAL
++#define DWC_E_NO_STREAM_RES	ENOSR
++#define DWC_E_COMMUNICATION	ECOMM
++#define DWC_E_OVERFLOW		EOVERFLOW
++#define DWC_E_PROTOCOL		EPROTO
++#define DWC_E_IN_PROGRESS	EINPROGRESS
++#define DWC_E_PIPE		EPIPE
++#define DWC_E_IO		EIO
++#define DWC_E_NO_SPACE		ENOSPC
++#define DWC_E_DOMAIN		EDOM
++/** @} */
++
++/** Compiler 'packed' attribute for structs */
++#define UPACKED	__attribute__ ((__packed__))
++
++/** @{ */
++/** Type for DMA addresses */
++typedef dma_addr_t		dwc_dma_t;
++#define DWC_DMA_ADDR_INVALID	(~(dwc_dma_t)0)
++/** @} */
++
++/**
++ * The number of DMA Descriptors (TRBs) to allocate for each endpoint type.
++ * NOTE: The driver currently supports more than 1 TRB for Isoc EPs only.
++ * So the values for Bulk and Intr must be 1.
++ */
++#define DWC_NUM_BULK_TRBS	1
++#define DWC_NUM_INTR_TRBS	1
++#define DWC_NUM_ISOC_TRBS	256
++
++/**
++ * These parameters may be specified when loading the module. They define how
++ * the DWC_usb3 controller should be configured. The parameter values are passed
++ * to the CIL initialization routine dwc_usb3_pcd_common_init().
++ */
++typedef struct dwc_usb3_core_params {
++	int burst;
++	int newcore;
++	int phy;
++	int wakeup;
++	int pwrctl;
++	int lpmctl;
++	int phyctl;
++	int usb2mode;
++	int hibernate;
++	int hiberdisc;
++	int clkgatingen;
++	int ssdisquirk;
++	int nobos;
++	int loop;
++	int nump;
++	int newcsr;
++	int rxfsz;
++	int txfsz[16];
++	int txfsz_cnt;
++	int baseline_besl;
++	int deep_besl;
++	int besl;
++	int ebc;
++} dwc_usb3_core_params_t;
++
++extern dwc_usb3_core_params_t dwc_usb3_module_params;
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* _DWC_LINUX_DEFS_H_ */
+diff --git a/drivers/usb/gadget/udc/hiudc3/os_dev.h b/drivers/usb/gadget/udc/hiudc3/os_dev.h
+new file mode 100644
+index 0000000..1c5cd83
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc3/os_dev.h
+@@ -0,0 +1,176 @@
++#ifndef _DWC_LINUX_DEV_H_
++#define _DWC_LINUX_DEV_H_
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++#if defined(CONFIG_ARCH_HI3519) || defined(CONFIG_ARCH_HI3519V101) || defined(CONFIG_ARCH_HI3516AV200)
++#ifdef readl
++#undef readl
++#undef readl_relaxed
++#undef writel
++#undef writel_relaxed
++#define readl		hi_readl
++#define readl_relaxed	hi_readl_relaxed
++#define writel		hi_writel
++#define writel_relaxed	hi_writel_relaxed
++#endif /* readl */
++#endif /* defined(CONFIG_ARCH_HI3519) || defined(CONFIG_ARCH_HI3519V101) || defined(CONFIG_ARCH_HI3516AV200)*/
++
++/** @file
++ */
++
++/** Wrapper function for _handshake(), shows the source line for any failure */
++#define handshake(_dev_, _ptr_, _mask_, _done_) ({			\
++	int _retval_ = _handshake(_dev_, _ptr_, _mask_, _done_);	\
++	if (!_retval_)							\
++		dwc_error2(_dev_, "handshake failed in %s():%d\n",	\
++			   __func__, __LINE__);				\
++	_retval_;							\
++})
++
++/** Takes a usb req pointer and returns the associated pcd req pointer */
++#define dwc_usb3_get_pcd_req(usbreq) \
++	container_of((usbreq), dwc_usb3_pcd_req_t, usb_req)
++
++/** Takes a usb ep pointer and returns the associated pcd ep pointer */
++#define dwc_usb3_get_pcd_ep(usbep) \
++	container_of((usbep), dwc_usb3_pcd_ep_t, usb_ep)
++
++/** @{ */
++/**
++ * Register read/write.
++ */
++static inline u32 dwc_rd32(struct dwc_usb3_device *dev,
++			   volatile u32 __iomem *adr)
++{
++	return readl(adr);
++}
++
++static inline void dwc_wr32(struct dwc_usb3_device *dev,
++			    volatile u32 __iomem *adr, u32 val)
++{
++	writel(val, adr);
++}
++/** @} */
++
++/** @{ */
++/**
++ * Non-sleeping delays.
++ */
++#define dwc_udelay(dev, us)	udelay(us)
++#define dwc_mdelay(dev, ms)	mdelay(ms)
++/** @} */
++
++/**
++ * Sleeping delay.
++ */
++#define dwc_msleep(dev, ms)	msleep(ms)
++
++/**
++ * Debugging support - vanishes in non-debug builds.
++ */
++
++/** Prefix string for print macros. */
++#define USB3_DWC	"dwc_usb3: "
++/* #define DEBUG */
++#ifdef DEBUG
++# define dwc_debug(dev, x...)	printk(KERN_DEBUG USB3_DWC x )
++#else
++# define dwc_debug(dev, x...)	do {} while (0)
++#endif /* DEBUG */
++
++# define dwc_debug0(dev, fmt)			dwc_debug(dev, fmt)
++# define dwc_debug1(dev, fmt, a)		dwc_debug(dev, fmt, a)
++# define dwc_debug2(dev, fmt, a, b)		dwc_debug(dev, fmt, a, b)
++# define dwc_debug3(dev, fmt, a, b, c)		dwc_debug(dev, fmt, a, b, c)
++# define dwc_debug4(dev, fmt, a, b, c, d)	dwc_debug(dev, fmt, a, b, c, d)
++# define dwc_debug5(dev, fmt, a, b, c, d, e) \
++			dwc_debug(dev, fmt, a, b, c, d, e)
++# define dwc_debug6(dev, fmt, a, b, c, d, e, f) \
++			dwc_debug(dev, fmt, a, b, c, d, e, f)
++# define dwc_debug7(dev, fmt, a, b, c, d, e, f, g) \
++			dwc_debug(dev, fmt, a, b, c, d, e, f, g)
++# define dwc_debug8(dev, fmt, a, b, c, d, e, f, g, h) \
++			dwc_debug(dev, fmt, a, b, c, d, e, f, g, h)
++# define dwc_debug9(dev, fmt, a, b, c, d, e, f, g, h, i) \
++			dwc_debug(dev, fmt, a, b, c, d, e, f, g, h, i)
++# define dwc_debug10(dev, fmt, a, b, c, d, e, f, g, h, i, j) \
++			dwc_debug(dev, fmt, a, b, c, d, e, f, g, h, i, j)
++
++#if defined(DEBUG) || defined(ISOC_DEBUG)
++# define dwc_isocdbg(dev, x...)	printk(USB3_DWC x )
++#else
++# define dwc_isocdbg(dev, x...)	do {} while (0)
++#endif
++
++# define dwc_isocdbg0(dev, fmt)			dwc_isocdbg(dev, fmt)
++# define dwc_isocdbg1(dev, fmt, a)		dwc_isocdbg(dev, fmt, a)
++# define dwc_isocdbg2(dev, fmt, a, b)		dwc_isocdbg(dev, fmt, a, b)
++# define dwc_isocdbg3(dev, fmt, a, b, c)	dwc_isocdbg(dev, fmt, a, b, c)
++# define dwc_isocdbg4(dev, fmt, a, b, c, d) \
++			dwc_isocdbg(dev, fmt, a, b, c, d)
++# define dwc_isocdbg5(dev, fmt, a, b, c, d, e) \
++			dwc_isocdbg(dev, fmt, a, b, c, d, e)
++# define dwc_isocdbg6(dev, fmt, a, b, c, d, e, f) \
++			dwc_isocdbg(dev, fmt, a, b, c, d, e, f)
++
++/**
++ * Print an Error message.
++ */
++#define dwc_error(dev, x...)	printk(KERN_ERR USB3_DWC x )
++
++#define dwc_error0(dev, fmt)			dwc_error(dev, fmt)
++#define dwc_error1(dev, fmt, a)			dwc_error(dev, fmt, a)
++#define dwc_error2(dev, fmt, a, b)		dwc_error(dev, fmt, a, b)
++#define dwc_error3(dev, fmt, a, b, c)		dwc_error(dev, fmt, a, b, c)
++#define dwc_error4(dev, fmt, a, b, c, d)	dwc_error(dev, fmt, a, b, c, d)
++
++/**
++ * Print a Warning message.
++ */
++#define dwc_warn(dev, x...)	printk(KERN_WARNING USB3_DWC x )
++
++#define dwc_warn0(dev, fmt)			dwc_warn(dev, fmt)
++#define dwc_warn1(dev, fmt, a)			dwc_warn(dev, fmt, a)
++#define dwc_warn2(dev, fmt, a, b)		dwc_warn(dev, fmt, a, b)
++#define dwc_warn3(dev, fmt, a, b, c)		dwc_warn(dev, fmt, a, b, c)
++#define dwc_warn4(dev, fmt, a, b, c, d)		dwc_warn(dev, fmt, a, b, c, d)
++
++/**
++ * Print an Informational message (normal but significant).
++ */
++#define dwc_info(dev, x...)	printk(KERN_INFO USB3_DWC x )
++
++#define dwc_info0(dev, fmt)			dwc_info(dev, fmt)
++#define dwc_info1(dev, fmt, a)			dwc_info(dev, fmt, a)
++#define dwc_info2(dev, fmt, a, b)		dwc_info(dev, fmt, a, b)
++#define dwc_info3(dev, fmt, a, b, c)		dwc_info(dev, fmt, a, b, c)
++#define dwc_info4(dev, fmt, a, b, c, d)		dwc_info(dev, fmt, a, b, c, d)
++
++/**
++ * Basic message printing.
++ */
++#define dwc_print(dev, x...)	printk(USB3_DWC x )
++
++#define dwc_print0(dev, fmt)			dwc_print(dev, fmt)
++#define dwc_print1(dev, fmt, a)			dwc_print(dev, fmt, a)
++#define dwc_print2(dev, fmt, a, b)		dwc_print(dev, fmt, a, b)
++#define dwc_print3(dev, fmt, a, b, c)		dwc_print(dev, fmt, a, b, c)
++#define dwc_print4(dev, fmt, a, b, c, d)	dwc_print(dev, fmt, a, b, c, d)
++#define dwc_print5(dev, fmt, a, b, c, d, e) \
++			dwc_print(dev, fmt, a, b, c, d, e)
++
++extern int dwc_usb3_gadget_init(struct dwc_usb3_device *usb3_dev, struct device *dev);
++extern void dwc_usb3_gadget_remove(struct dwc_usb3_device *usb3_dev, struct device *dev);
++extern int dwc_usb3_create_dev_files(struct device *dev);
++extern void dwc_usb3_remove_dev_files(struct device *dev);
++extern int dwc_usb3_wakeup(struct usb_gadget *gadget);
++extern int dwc_wait_pme_thread(void *data);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* _DWC_LINUX_DEV_H_ */
+diff --git a/drivers/usb/gadget/udc/hiudc3/pcd.c b/drivers/usb/gadget/udc/hiudc3/pcd.c
+new file mode 100644
+index 0000000..6bf93aa
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc3/pcd.c
+@@ -0,0 +1,1992 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/DWC_usb3/driver/pcd.c $
++ * $Revision: #110 $
++ * $Date: 2014/11/11 $
++ * $Change: 2664766 $
++ *
++ * Synopsys SS USB3 Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
++ * ========================================================================== */
++
++/** @file
++ * This file implements the Peripheral Controller Driver.
++ *
++ * The Peripheral Controller Driver (PCD) is responsible for translating
++ * requests from the Function Driver into the appropriate actions on the
++ * DWC_usb3 controller. It isolates the Function Driver from the specifics
++ * of the controller by providing an API to the Function Driver.
++ *
++ * The Peripheral Controller Driver for Linux will implement the Gadget API,
++ * so that the existing Gadget drivers can be used. (Gadget Driver is the
++ * Linux terminology for a Function Driver.)
++ *
++ * The Linux Gadget API is defined in the header file
++ * <code><linux/usb/gadget.h></code>. The USB EP operations API is defined
++ * in the structure <code>usb_ep_ops</code> and the USB Controller API is
++ * defined in the structure <code>usb_gadget_ops</code>.
++ *
++ * An important function of the PCD is managing interrupts generated by the
++ * DWC_usb3 controller. The implementation of the DWC_usb3 device mode
++ * interrupt service routines is in pcd_intr.c.
++ */
++/*
++ * todo  Add Device Mode test modes (Test J mode, Test K mode, etc).
++ */
++
++#include "os_defs.h"
++#include "hw.h"
++#include "usb.h"
++#include "pcd.h"
++#include "dev.h"
++#include "os_dev.h"
++#include "cil.h"
++
++#ifdef DWC_UTE
++# include "ute_if.h"
++#endif
++
++/**
++ * This routine allocates the TRBs for an EP.
++ *
++ * @param ep            The EP for the allocation.
++ * @param num_trbs      Number of TRBs to allocate.
++ * @param trb_type      Type of the TRB.
++ * @param iso_intvl     bInterval if this is an Isoc EP.
++ * @param link          True if the TRBs should be linked in a circular chain
++ *                      (only supported for Isoc EPs for now).
++ * @param trbs_dma_ret  The DMA address of the allocation is returned through
++ *                      this pointer.
++ * @return              The address of the allocated memory, or NULL if the
++ *                      allocation fails.
++ */
++dwc_usb3_dma_desc_t *dwc_usb3_pcd_trb_alloc(dwc_usb3_pcd_ep_t *ep, int num_trbs,
++		int trb_type, int iso_intvl, int link, dwc_dma_t *trbs_dma_ret)
++{
++	dwc_usb3_dma_desc_t *trbs, *cur_trb;
++	dwc_dma_t trbs_dma = 0;
++	int size, i;
++#ifdef DWC_TEST_ISOC_CHAIN
++	int j;
++#endif
++
++#ifdef DWC_TEST_ISOC_CHAIN
++	size = num_trbs * 3 * 16;
++	if (link)
++		size += 16 * 3;
++#else
++	size = num_trbs * 16;
++	if (link)
++		size += 16;
++#endif
++
++	trbs = cur_trb = dwc_usb3_gadget_alloc_dma(ep, size, &trbs_dma);
++	if (!trbs)
++		return NULL;
++
++	/* Now initialize the TRBs */
++	for (i = 0; i < num_trbs; i++, cur_trb++) {
++		if (trb_type == UE_ISOCHRONOUS) {
++#ifdef DWC_ISOC_INTR_MODERATION
++			/*
++			 * For small intervals, only set the IOC bit in every
++			 * 8th TRB, for interrupt moderation purposes
++			 */
++			if (iso_intvl > 3 || (i & 7) == 7 || i == num_trbs - 1)
++#endif
++				dwc_usb3_fill_desc(cur_trb, 0, 0, 0,
++						   DWC_DSCCTL_TRBCTL_ISOC_1ST,
++						   DWC_DSCCTL_IOC_BIT |
++						   DWC_DSCCTL_IMI_BIT |
++						   DWC_DSCCTL_CSP_BIT, 0);
++#ifdef DWC_ISOC_INTR_MODERATION
++			else
++				dwc_usb3_fill_desc(cur_trb, 0, 0, 0,
++						   DWC_DSCCTL_TRBCTL_ISOC_1ST,
++						   DWC_DSCCTL_IMI_BIT |
++						   DWC_DSCCTL_CSP_BIT, 0);
++#endif
++#ifdef DWC_TEST_ISOC_CHAIN
++			/* Add 2 more TRBs per entry, chain them to the 1st */
++			dwc_usb3_start_desc_chain(cur_trb);
++			cur_trb++;
++
++			for (j = 0; j < 2; j++, cur_trb++)
++				dwc_usb3_fill_desc(cur_trb, 0, 0, 0,
++						   DWC_DSCCTL_TRBCTL_ISOC,
++						   DWC_DSCCTL_IMI_BIT |
++						   DWC_DSCCTL_CSP_BIT |
++						   DWC_DSCCTL_CHN_BIT, 0);
++			cur_trb--;
++			dwc_usb3_end_desc_chain(cur_trb);
++#endif
++		}
++
++		/* For types other than Isoc, the TRBs are initialized just
++		 * before the transfer is started.
++		 */
++	}
++
++	if (link) {
++		dwc_usb3_fill_desc(cur_trb, trbs_dma, 0, 0,
++				   DWC_DSCCTL_TRBCTL_LINK, 0, 1);
++	}
++
++	/* Init the pcd_ep structure */
++	ep->dwc_ep.dma_desc = trbs;
++	ep->dwc_ep.dma_desc_dma = trbs_dma;
++	ep->dwc_ep.desc_size = size;
++	ep->dwc_ep.desc_link = link;
++	ep->dwc_ep.num_desc = num_trbs;
++	ep->dwc_ep.desc_avail = num_trbs;
++	ep->dwc_ep.desc_idx = 0;
++	ep->dwc_ep.hiber_desc_idx = 0;
++
++	if (trbs_dma_ret)
++		*trbs_dma_ret = trbs_dma;
++	return trbs;
++}
++
++/**
++ * This routine frees the TRBs allocated by dwc_usb3_pcd_trb_alloc().
++ *
++ * @param ep    The EP for the allocation.
++ */
++void dwc_usb3_pcd_trb_free(dwc_usb3_pcd_ep_t *ep)
++{
++	dwc_usb3_dma_desc_t *trbs;
++	dwc_dma_t trbs_dma;
++	int size;
++
++	if (ep->dwc_ep.dma_desc) {
++		trbs = ep->dwc_ep.dma_desc;
++		trbs_dma = ep->dwc_ep.dma_desc_dma;
++		size = ep->dwc_ep.desc_size;
++		ep->dwc_ep.dma_desc = NULL;
++		ep->dwc_ep.dma_desc_dma = 0;
++
++		dwc_usb3_gadget_free_dma(ep, size, trbs, trbs_dma);
++	}
++}
++
++/**
++ * This routine assigns and fills in the TRBs for a request.
++ *
++ * @param pcd   Programming view of DWC_usb3 peripheral controller.
++ * @param ep    The EP for the transfer.
++ * @param req   The request that needs the TRBs.
++ */
++void dwc_usb3_pcd_fill_trbs(dwc_usb3_pcd_t *pcd, dwc_usb3_pcd_ep_t *ep,
++			    dwc_usb3_pcd_req_t *req)
++{
++	dwc_usb3_dma_desc_t *desc;
++	dwc_dma_t desc_dma;
++	u32 len, tlen, pkts, ctrl;
++	int i;
++
++	if (ep == pcd->ep0)
++		return;
++
++	/* Get the next DMA Descriptor (TRB) for this EP */
++	desc = ep->dwc_ep.dma_desc + ep->dwc_ep.desc_idx * req->dwc_req.numbuf;
++	desc_dma = (dwc_dma_t)((unsigned long)ep->dwc_ep.dma_desc_dma +
++		(unsigned long)ep->dwc_ep.desc_idx * req->dwc_req.numbuf * 16);
++
++	if (++ep->dwc_ep.desc_idx >= ep->dwc_ep.num_desc)
++		ep->dwc_ep.desc_idx = 0;
++	ep->dwc_ep.desc_avail--;
++
++	req->dwc_req.trb = desc;
++	req->dwc_req.trbdma = desc_dma;
++
++	pkts = 0;
++
++	if (ep->dwc_ep.is_in) {
++		/* For IN, TRB length is just xfer length */
++		len = req->dwc_req.length;
++
++		if (ep->dwc_ep.type == UE_ISOCHRONOUS &&
++				pcd->speed == USB_SPEED_HIGH) {
++			pkts = (len + ep->dwc_ep.maxpacket - 1)
++					/ ep->dwc_ep.maxpacket;
++			if (pkts)
++				pkts--;
++		}
++	} else {
++		/* For OUT, TRB length must be multiple of maxpacket */
++		if ((ep->dwc_ep.type == UE_ISOCHRONOUS ||
++				ep->dwc_ep.type == UE_INTERRUPT) &&
++						ep->dwc_ep.maxpacket != 1024)
++			/* Might not be power of 2, so use (expensive?)
++			 * divide/multiply
++			 */
++			len = ((req->dwc_req.length + ep->dwc_ep.maxpacket - 1)
++			       / ep->dwc_ep.maxpacket) * ep->dwc_ep.maxpacket;
++		else
++			/* Must be power of 2, use cheap AND */
++			len = (req->dwc_req.length + ep->dwc_ep.maxpacket - 1)
++			      & ~(ep->dwc_ep.maxpacket - 1);
++
++		req->dwc_req.length = len;
++	}
++
++	/* DMA Descriptor Setup */
++	for (i = 0; i < req->dwc_req.numbuf; i++, desc++) {
++		if (ep->dwc_ep.type == UE_ISOCHRONOUS) {
++			if (i != req->dwc_req.numbuf - 1) {
++				tlen = req->dwc_req.buflen[i];
++				len -= tlen;
++			} else {
++				tlen = len;
++			}
++
++			if (i == 0)
++				tlen |= pkts << DWC_DSCSTS_PCM1_SHIFT;
++
++			dwc_usb3_fill_desc(desc, req->dwc_req.bufdma[i], tlen,
++					   0, 0, 0, i != 0);
++		} else {
++			if (i != req->dwc_req.numbuf - 1) {
++				ctrl = 0;
++				tlen = req->dwc_req.buflen[i];
++				len -= tlen;
++			} else {
++				ctrl = DWC_DSCCTL_LST_BIT;
++				tlen = len;
++			}
++
++			dwc_usb3_fill_desc(desc, req->dwc_req.bufdma[i], tlen,
++					   req->dwc_req.stream,
++					   DWC_DSCCTL_TRBCTL_NORMAL, ctrl,
++					   i != 0);
++		}
++	}
++
++	/* Must do this last! */
++	desc = req->dwc_req.trb;
++	dwc_usb3_enable_desc(desc);
++}
++
++/**
++ * This routine configures EP0 OUT to receive SETUP packets and configures
++ * EP0 IN for transmitting packets.
++ *
++ * @param pcd           Programming view of DWC_usb3 peripheral controller.
++ * @param restore       True if restoring endpoint state after hibernation.
++ */
++void dwc_usb3_ep0_activate(dwc_usb3_pcd_t *pcd, int restore)
++{
++	u32 diepcfg0, doepcfg0, diepcfg1, doepcfg1;
++	u32 diepcfg2 = 0, doepcfg2 = 0;
++	dwc_usb3_dev_ep_regs_t __iomem *ep_reg;
++
++	dwc_debug1(pcd->usb3_dev, "%s()\n", __func__);
++
++	diepcfg0 = DWC_USB3_EP_TYPE_CONTROL << DWC_EPCFG0_EPTYPE_SHIFT;
++	diepcfg1 = DWC_EPCFG1_XFER_CMPL_BIT | DWC_EPCFG1_XFER_IN_PROG_BIT |
++		   DWC_EPCFG1_XFER_NRDY_BIT | DWC_EPCFG1_EP_DIR_BIT;
++
++	doepcfg0 = DWC_USB3_EP_TYPE_CONTROL << DWC_EPCFG0_EPTYPE_SHIFT;
++	doepcfg1 = DWC_EPCFG1_XFER_CMPL_BIT | DWC_EPCFG1_XFER_IN_PROG_BIT |
++		   DWC_EPCFG1_XFER_NRDY_BIT;
++
++	/* Default to MPS of 512 (will reconfigure after ConnectDone event) */
++	diepcfg0 |= 512 << DWC_EPCFG0_MPS_SHIFT;
++	doepcfg0 |= 512 << DWC_EPCFG0_MPS_SHIFT;
++
++#ifdef DWC_UTE
++	pcd->ep0->dwc_ep.tx_fifo_num = pcd->txf_map[1];
++#endif
++	diepcfg0 |= pcd->ep0->dwc_ep.tx_fifo_num << DWC_EPCFG0_TXFNUM_SHIFT;
++
++	if (restore) {
++		diepcfg0 |= DWC_CFG_ACTION_RESTORE
++					<< DWC_EPCFG0_CFG_ACTION_SHIFT;
++		diepcfg2 = pcd->ep0_in_save_state;
++		dwc_debug1(pcd->usb3_dev, "IN restore state=%08x\n", diepcfg2);
++		doepcfg0 |= DWC_CFG_ACTION_RESTORE
++					<< DWC_EPCFG0_CFG_ACTION_SHIFT;
++		doepcfg2 = pcd->ep0_out_save_state;
++		dwc_debug1(pcd->usb3_dev, "OUT restore state=%08x\n", doepcfg2);
++	}
++
++	/*
++	 * Issue "DEPCFG" command to EP0-OUT
++	 */
++
++	ep_reg = &pcd->out_ep_regs[0];
++	dwc_usb3_dis_usb2_suspend(pcd);
++
++	/* If core is version 1.09a or later */
++	if ((pcd->usb3_dev->snpsid & 0xffff) >= 0x109a) {
++		/* Must issue DEPSTRTNEWCFG command first */
++		dwc_usb3_dep_startnewcfg(pcd, ep_reg, 0);
++	}
++
++	dwc_usb3_dep_cfg(pcd, ep_reg, doepcfg0, doepcfg1, doepcfg2);
++
++	/*
++	 * Issue "DEPSTRMCFG" command to EP0-OUT
++	 */
++
++	/* One stream */
++	dwc_usb3_dep_xfercfg(pcd, ep_reg, 1);
++
++	/*
++	 * Issue "DEPCFG" command to EP0-IN
++	 */
++
++	ep_reg = &pcd->in_ep_regs[0];
++	dwc_usb3_dep_cfg(pcd, ep_reg, diepcfg0, diepcfg1, diepcfg2);
++
++	/*
++	 * Issue "DEPSTRMCFG" command to EP0-IN
++	 */
++
++	/* One stream */
++	dwc_usb3_dep_xfercfg(pcd, ep_reg, 1);
++
++	dwc_usb3_ena_usb2_suspend(pcd);
++	pcd->ep0->dwc_ep.active = 1;
++}
++
++/**
++ * This routine activates an EP. The Device EP control registers for the EP
++ * are configured as defined in the EP structure.
++ *
++ * @param pcd           Programming view of DWC_usb3 peripheral controller.
++ * @param ep            The EP to activate.
++ * @param restore       True if restoring endpoint state after hibernation.
++ */
++void dwc_usb3_ep_activate(dwc_usb3_pcd_t *pcd, dwc_usb3_pcd_ep_t *ep,
++			  int restore)
++{
++	dwc_usb3_dev_ep_regs_t __iomem *ep_reg, *ep0_reg;
++	u32 depcfg0, depcfg1, depcfg2 = 0;
++
++	dwc_debug3(pcd->usb3_dev, "%s() EP%d-%s\n", __func__, ep->dwc_ep.num,
++		   (ep->dwc_ep.is_in ? "IN" : "OUT"));
++
++	ep->dwc_ep.hiber_desc_idx = 0;
++
++#ifdef DWC_STAR_9000463548_WORKAROUND
++	if (pcd->configuring)
++		goto skip;
++#endif
++	/*
++	 * Get the appropriate EP registers
++	 */
++	if (ep->dwc_ep.is_in)
++		ep_reg = ep->dwc_ep.in_ep_reg;
++	else
++		ep_reg = ep->dwc_ep.out_ep_reg;
++
++	dwc_usb3_dis_usb2_suspend(pcd);
++
++	/* If this is first EP enable (ie. start of a new configuration) */
++	if (!pcd->eps_enabled) {
++
++#ifdef DWC_STAR_9000463548_WORKAROUND
++		dwc_usb3_dev_ep_regs_t __iomem *eptmp_reg;
++		dwc_usb3_pcd_ep_t *eptmp;
++		int i;
++
++		/* For the workaround, we must wait for all EndXfers on all EPs
++		 * to complete before continuing
++		 */
++		for (i = 0; i < pcd->num_in_eps; i++) {
++			eptmp = pcd->in_ep[i];
++			dwc_print3(pcd->usb3_dev, "DWC IN EP%d=%lx tri-in=%d\n",
++				   i, (unsigned long)eptmp, eptmp->dwc_ep.tri_in);
++			if (eptmp->dwc_ep.tri_in) {
++				eptmp_reg = eptmp->dwc_ep.in_ep_reg;
++				eptmp->dwc_ep.condition = 0;
++				dwc_usb3_dep_wait_endxfer(pcd, eptmp_reg,
++						&eptmp->dwc_ep.condition);
++				eptmp->dwc_ep.tri_in = 0;
++			}
++		}
++
++		for (i = 0; i < pcd->num_out_eps; i++) {
++			eptmp = pcd->out_ep[i];
++			dwc_print3(pcd->usb3_dev,
++				   "DWC OUT EP%d=%lx tri-out=%d\n",
++				   i, (unsigned long)eptmp, eptmp->dwc_ep.tri_out);
++			if (eptmp->dwc_ep.tri_out) {
++				eptmp_reg = eptmp->dwc_ep.out_ep_reg;
++				eptmp->dwc_ep.condition = 0;
++				dwc_usb3_dep_wait_endxfer(pcd, eptmp_reg,
++						&eptmp->dwc_ep.condition);
++				eptmp->dwc_ep.tri_out = 0;
++			}
++		}
++#endif
++		pcd->eps_enabled = 1;
++
++		/* NOTE: When setting a new configuration, we must issue a
++		 * "DEPCFG" command to physical EP1 (logical EP0-IN) first.
++		 * This resets the core's Tx FIFO mapping table
++		 */
++		depcfg0 = DWC_USB3_EP_TYPE_CONTROL << DWC_EPCFG0_EPTYPE_SHIFT;
++		depcfg0 |= DWC_CFG_ACTION_MODIFY << DWC_EPCFG0_CFG_ACTION_SHIFT;
++		depcfg1 = DWC_EPCFG1_XFER_CMPL_BIT | DWC_EPCFG1_XFER_IN_PROG_BIT
++			| DWC_EPCFG1_XFER_NRDY_BIT | DWC_EPCFG1_EP_DIR_BIT;
++
++		switch (pcd->speed) {
++		case USB_SPEED_SUPER:
++			depcfg0 |= 512 << DWC_EPCFG0_MPS_SHIFT;
++			break;
++
++		case USB_SPEED_HIGH:
++		case USB_SPEED_FULL:
++			depcfg0 |= 64 << DWC_EPCFG0_MPS_SHIFT;
++			break;
++
++		case USB_SPEED_LOW:
++			depcfg0 |= 8 << DWC_EPCFG0_MPS_SHIFT;
++			break;
++		}
++
++		ep0_reg = &pcd->in_ep_regs[0];
++		dwc_usb3_dep_cfg(pcd, ep0_reg, depcfg0, depcfg1, 0);
++
++		/* If core is version 1.09a or later */
++		if ((pcd->usb3_dev->snpsid & 0xffff) >= 0x109a) {
++			/* Must issue DEPSTRTNEWCFG command first */
++			ep0_reg = &pcd->out_ep_regs[0];
++			dwc_usb3_dep_startnewcfg(pcd, ep0_reg, 2);
++		}
++	}
++
++	/*
++	 * Issue "DEPCFG" command to EP
++	 */
++	depcfg0 = ep->dwc_ep.type << DWC_EPCFG0_EPTYPE_SHIFT;
++	depcfg0 |= ep->dwc_ep.maxpacket << DWC_EPCFG0_MPS_SHIFT;
++
++	if (ep->dwc_ep.is_in) {
++#ifdef DWC_UTE
++		ep->dwc_ep.tx_fifo_num = pcd->txf_map[ep->dwc_ep.phys];
++#endif
++		depcfg0 |= ep->dwc_ep.tx_fifo_num << DWC_EPCFG0_TXFNUM_SHIFT;
++	}
++
++	if (pcd->usb3_dev->core_params->burst) {
++		dwc_debug1(pcd->usb3_dev, "Setting maxburst to %u\n",
++			   ep->dwc_ep.maxburst);
++		depcfg0 |= ep->dwc_ep.maxburst << DWC_EPCFG0_BRSTSIZ_SHIFT;
++	}
++
++	if (restore) {
++		depcfg0 |= DWC_CFG_ACTION_RESTORE
++					<< DWC_EPCFG0_CFG_ACTION_SHIFT;
++		depcfg2 = ep->dwc_ep.save_state;
++	}
++
++	depcfg1 = ep->dwc_ep.num << DWC_EPCFG1_EP_NUM_SHIFT;
++	if (ep->dwc_ep.is_in)
++		depcfg1 |= DWC_EPCFG1_EP_DIR_BIT;
++
++	depcfg1 |= DWC_EPCFG1_XFER_CMPL_BIT;
++	depcfg1 |= DWC_EPCFG1_XFER_IN_PROG_BIT;
++	depcfg1 |= DWC_EPCFG1_XFER_NRDY_BIT;
++	dwc_isocdbg1(pcd->usb3_dev, "Setting bInterval-1 to %u\n",
++		     ep->dwc_ep.intvl);
++	depcfg1 |= ep->dwc_ep.intvl << DWC_EPCFG1_BINTERVAL_SHIFT;
++
++	if (ep->dwc_ep.num_streams) {
++		dwc_debug0(pcd->usb3_dev, "Setting stream-capable bit\n");
++		depcfg1 |= DWC_EPCFG1_STRM_CAP_BIT;
++	}
++
++	if (pcd->usb3_dev->core_params->ebc) {
++		if (pcd->speed == USB_SPEED_SUPER ||
++		    pcd->speed == USB_SPEED_HIGH) {
++			dwc_debug0(pcd->usb3_dev, "Setting EBC enable bit\n");
++			depcfg1 |= DWC_EPCFG1_EBC_MODE_BIT;
++		}
++	}
++
++	/* Save the DEPCFG parameters for later */
++	if (ep->dwc_ep.is_in) {
++		ep->dwc_ep.param0in = depcfg0 & ~DWC_EPCFG0_CFG_ACTION_BITS;
++		ep->dwc_ep.param1in = depcfg1;
++	} else {
++		ep->dwc_ep.param0out = depcfg0 & ~DWC_EPCFG0_CFG_ACTION_BITS;
++		ep->dwc_ep.param1out = depcfg1;
++	}
++
++	dwc_usb3_dep_cfg(pcd, ep_reg, depcfg0, depcfg1, depcfg2);
++
++	/*
++	 * Issue "DEPSTRMCFG" command to EP
++	 */
++
++	/* If this EP hasn't been enabled yet in this configuration */
++	if (!ep->dwc_ep.ena_once) {
++		ep->dwc_ep.ena_once = 1;
++
++		/* One stream */
++		dwc_debug0(pcd->usb3_dev, "Setting 1 stream resource\n");
++		dwc_usb3_dep_xfercfg(pcd, ep_reg, 1);
++	}
++
++	dwc_usb3_ena_usb2_suspend(pcd);
++
++#ifdef DWC_STAR_9000463548_WORKAROUND
++skip:
++#endif
++	/* Enable EP in DALEPENA reg */
++	dwc_usb3_enable_ep(pcd, ep);
++
++	ep->dwc_ep.active = 1;
++	ep->dwc_ep.stall_clear_flag = 0;
++}
++
++/**
++ * This routine deactivates an EP.
++ *
++ * @param pcd   Programming view of DWC_usb3 peripheral controller.
++ * @param ep    The EP to deactivate.
++ */
++static void ep_deactivate(dwc_usb3_pcd_t *pcd, dwc_usb3_pcd_ep_t *ep)
++{
++	dwc_usb3_dev_ep_regs_t __iomem *ep_reg;
++	u8 tri;
++
++	dwc_debug3(pcd->usb3_dev, "%s() EP%d-%s\n", __func__, ep->dwc_ep.num,
++		   (ep->dwc_ep.is_in ? "IN" : "OUT"));
++	/*
++	 * Get the appropriate EP registers
++	 */
++	if (ep->dwc_ep.is_in) {
++		ep_reg = ep->dwc_ep.in_ep_reg;
++		tri = ep->dwc_ep.tri_in;
++		ep->dwc_ep.tri_in = 0;
++	} else {
++		ep_reg = ep->dwc_ep.out_ep_reg;
++		tri = ep->dwc_ep.tri_out;
++		ep->dwc_ep.tri_out = 0;
++	}
++
++	dwc_print2(pcd->usb3_dev, "end: DWC EP=%lx tri=%d\n",
++		   (unsigned long)ep, tri);
++	dwc_usb3_dis_usb2_suspend(pcd);
++
++	/* Execute clear stall command */
++	dwc_usb3_dep_cstall(pcd, ep_reg, 0);
++
++	if (tri) {
++#ifdef DWC_STAR_9000463548_WORKAROUND
++		/* For the workaround, we wait until the EP is re-enabled
++		 * before waiting for the end transfer to complete
++		 */
++		dwc_usb3_dep_endxfer_nowait(pcd, ep_reg, tri - 1,
++					    DWC_ENDXFER_FORCE);
++		if (ep->dwc_ep.is_in)
++			ep->dwc_ep.tri_in = tri;
++		else
++			ep->dwc_ep.tri_out = tri;
++#else
++		/* Execute end transfer command */
++		ep->dwc_ep.condition = 0;
++		dwc_usb3_dep_endxfer(pcd, ep_reg, tri - 1, DWC_ENDXFER_FORCE,
++				     &ep->dwc_ep.condition);
++#endif
++	}
++
++	dwc_usb3_ena_usb2_suspend(pcd);
++	ep->dwc_ep.xfer_started = 0;
++
++	/* Disable EP in DALEPENA reg */
++	dwc_usb3_disable_ep(pcd, ep);
++
++	ep->dwc_ep.active = 0;
++}
++
++/**
++ * This routine sets up a SETUP stage transfer for EP0 and starts the transfer.
++ *
++ * @param pcd   Programming view of the PCD.
++ */
++void dwc_usb3_pcd_ep0_out_start(dwc_usb3_pcd_t *pcd)
++{
++	dwc_usb3_dev_ep_regs_t __iomem *ep_reg;
++	dwc_usb3_dma_desc_t *desc;
++	dwc_dma_t desc_dma;
++	u8 tri;
++
++	/* Get the SETUP packet DMA Descriptor (TRB) */
++	desc = dwc_usb3_ep0_setup_desc(pcd);
++	desc_dma = dwc_usb3_ep0_setup_desc_dma(pcd);
++
++	/* DMA Descriptor setup */
++	dwc_usb3_fill_desc(desc, dwc_usb3_ep0_setup_pkt_dma(pcd),
++			   pcd->ep0->dwc_ep.maxpacket, 0,
++			   DWC_DSCCTL_TRBCTL_SETUP, DWC_DSCCTL_LST_BIT, 1);
++	dwc_debug5(pcd->usb3_dev,
++		   "%s() desc=0x%08lx xfercnt=%u bptr=0x%08x:%08x\n",
++		   __func__, (unsigned long)desc, dwc_usb3_get_xfercnt(desc),
++		   desc->bpth, desc->bptl);
++#ifdef VERBOSE
++	dwc_debug4(pcd->usb3_dev, "0x%08x 0x%08x 0x%08x 0x%08x\n",
++		   *((unsigned *)desc), *((unsigned *)desc + 1),
++		   *((unsigned *)desc + 2), *((unsigned *)desc + 3));
++#endif
++
++	ep_reg = &pcd->out_ep_regs[0];
++	dwc_usb3_dis_usb2_suspend(pcd);
++
++	/* Issue "DEPSTRTXFER" command to EP0-OUT */
++	wmb();
++	tri = dwc_usb3_dep_startxfer(pcd, ep_reg, desc_dma, 0);
++	pcd->ep0->dwc_ep.tri_out = tri + 1;
++
++	dwc_usb3_ena_usb2_suspend(pcd);
++}
++
++/**
++ * This routine sets up a data/status stage transfer for EP0 and starts the
++ * transfer. If pcd->ep0->dwc_ep.is_in is 0 it will be an OUT transfer,
++ * otherwise it will be an IN transfer.
++ *
++ * @param pcd   Programming view of DWC_usb3 peripheral controller.
++ * @param req   The request to start.
++ */
++void dwc_usb3_pcd_ep0_start_transfer(dwc_usb3_pcd_t *pcd,
++				     dwc_usb3_pcd_req_t *req)
++{
++	dwc_usb3_pcd_ep_t *ep0 = pcd->ep0;
++	dwc_usb3_dev_ep_regs_t __iomem *ep_reg;
++	dwc_usb3_dma_desc_t *desc;
++	dwc_dma_t desc_dma;
++	u32 desc_type, len;
++	u8 tri;
++
++	dwc_debug7(pcd->usb3_dev,
++		"%s(): ep%d-%s req=%lx xfer_len=%d xfer_cnt=%d xfer_buf=%lx\n",
++		__func__, ep0->dwc_ep.num, (ep0->dwc_ep.is_in ? "IN" : "OUT"),
++		(unsigned long)req, req->dwc_req.length, req->dwc_req.actual,
++		(unsigned long)req->dwc_req.buf[0]);
++
++	/* Get the DMA Descriptor (TRB) for this request */
++	if (ep0->dwc_ep.is_in) {
++		req->dwc_req.trb = dwc_usb3_ep0_in_desc(pcd);
++		req->dwc_req.trbdma = dwc_usb3_ep0_in_desc_dma(pcd);
++	} else {
++		req->dwc_req.trb = dwc_usb3_ep0_out_desc(pcd);
++		req->dwc_req.trbdma = dwc_usb3_ep0_out_desc_dma(pcd);
++	}
++
++	desc = req->dwc_req.trb;
++	desc_dma = req->dwc_req.trbdma;
++	dwc_usb3_dis_usb2_suspend(pcd);
++
++	if (ep0->dwc_ep.is_in) {
++		/*
++		 * Start DMA on EP0-IN
++		 */
++		ep_reg = ep0->dwc_ep.in_ep_reg;
++
++		/* DMA Descriptor (TRB) setup */
++		len = req->dwc_req.length;
++
++		dwc_debug1(pcd->usb3_dev, "IN EP0STATE=%d\n", pcd->ep0state);
++
++		if (pcd->ep0state == EP0_IN_STATUS_PHASE) {
++			if (ep0->dwc_ep.three_stage)
++				desc_type = DWC_DSCCTL_TRBCTL_STATUS_3;
++			else
++				desc_type = DWC_DSCCTL_TRBCTL_STATUS_2;
++		} else {
++			desc_type = DWC_DSCCTL_TRBCTL_CTLDATA_1ST;
++		}
++
++		dwc_usb3_fill_desc(desc, req->dwc_req.bufdma[0],
++				   len, 0, desc_type, DWC_DSCCTL_LST_BIT, 1);
++		dwc_debug4(pcd->usb3_dev,
++			   "IN desc=0x%08lx xferlen=%u bptr=0x%08x:%08x\n",
++			   (unsigned long)desc, dwc_usb3_get_xfercnt(desc),
++			   desc->bpth, desc->bptl);
++#ifdef VERBOSE
++		dwc_debug4(pcd->usb3_dev, "0x%08x 0x%08x 0x%08x 0x%08x\n",
++			   *((unsigned *)desc), *((unsigned *)desc + 1),
++			   *((unsigned *)desc + 2), *((unsigned *)desc + 3));
++#endif
++		/* Issue "DEPSTRTXFER" command to EP0-IN */
++		wmb();
++		tri = dwc_usb3_dep_startxfer(pcd, ep_reg, desc_dma, 0);
++		ep0->dwc_ep.tri_in = tri + 1;
++	} else {
++		/*
++		 * Start DMA on EP0-OUT
++		 */
++		ep_reg = ep0->dwc_ep.out_ep_reg;
++
++		/* DMA Descriptor (TRB) setup */
++		len = (req->dwc_req.length + ep0->dwc_ep.maxpacket - 1) &
++			~(ep0->dwc_ep.maxpacket - 1);
++
++		dwc_debug1(pcd->usb3_dev, "OUT EP0STATE=%d\n", pcd->ep0state);
++
++		if (pcd->ep0state == EP0_OUT_STATUS_PHASE) {
++			if (ep0->dwc_ep.three_stage)
++				desc_type = DWC_DSCCTL_TRBCTL_STATUS_3;
++			else
++				desc_type = DWC_DSCCTL_TRBCTL_STATUS_2;
++		} else {
++			desc_type = DWC_DSCCTL_TRBCTL_CTLDATA_1ST;
++		}
++
++		dwc_usb3_fill_desc(desc, req->dwc_req.bufdma[0],
++				   len, 0, desc_type, DWC_DSCCTL_LST_BIT, 1);
++		dwc_debug4(pcd->usb3_dev,
++			   "OUT desc=0x%08lx xferlen=%u bptr=0x%08x:%08x\n",
++			   (unsigned long)desc, dwc_usb3_get_xfercnt(desc),
++			   desc->bpth, desc->bptl);
++#ifdef VERBOSE
++		dwc_debug4(pcd->usb3_dev, "0x%08x 0x%08x 0x%08x 0x%08x\n",
++			   *((unsigned *)desc), *((unsigned *)desc + 1),
++			   *((unsigned *)desc + 2), *((unsigned *)desc + 3));
++#endif
++		/* Issue "DEPSTRTXFER" command to EP0-OUT */
++		wmb();
++		tri = dwc_usb3_dep_startxfer(pcd, ep_reg, desc_dma, 0);
++		ep0->dwc_ep.tri_out = tri + 1;
++	}
++
++	dwc_usb3_ena_usb2_suspend(pcd);
++}
++
++/**
++ * This routine continues control IN transfers started by ep0_start_transfer,
++ * when the transfer does not fit in a single request.
++ *
++ * @param pcd Programming view of DWC_usb3 peripheral controller.
++ * @param req The request to continue.
++ */
++void dwc_usb3_pcd_ep0_continue_transfer(dwc_usb3_pcd_t *pcd,
++					dwc_usb3_pcd_req_t *req)
++{
++	dwc_usb3_pcd_ep_t *ep0 = pcd->ep0;
++	dwc_usb3_dev_ep_regs_t __iomem *ep_reg;
++	dwc_usb3_dma_desc_t *desc;
++	dwc_dma_t desc_dma;
++	u8 tri;
++
++	/* Currently the EP0 buffer size in the gadget is at least 256 bytes,
++	 * and all control transfers are smaller than that, so this routine is
++	 * never called to continue a transfer. However it can be called to
++	 * send a 0-length packet after the end of a transfer, so the code here
++	 * only supports that case.
++	 */
++
++	dwc_debug1(pcd->usb3_dev, "%s()\n", __func__);
++
++	if (ep0->dwc_ep.is_in) {
++		desc = dwc_usb3_ep0_in_desc(pcd);
++		desc_dma = dwc_usb3_ep0_in_desc_dma(pcd);
++		ep_reg = ep0->dwc_ep.in_ep_reg;
++
++		/* DMA Descriptor Setup */
++		dwc_usb3_fill_desc(desc, req->dwc_req.bufdma[0], 0, 0,
++				   DWC_DSCCTL_TRBCTL_NORMAL, DWC_DSCCTL_LST_BIT,
++				   1);
++
++		/* Make sure all writes to TRB have completed */
++		wmb();
++
++		dwc_usb3_dis_usb2_suspend(pcd);
++		tri = dwc_usb3_dep_startxfer(pcd, ep_reg, desc_dma, 0);
++		ep0->dwc_ep.tri_in = tri + 1;
++		dwc_usb3_ena_usb2_suspend(pcd);
++	}
++}
++
++/**
++ * This routine does the setup for a data transfer for an EP and starts
++ * the transfer.
++ *
++ * @param pcd   Programming view of DWC_usb3 peripheral controller.
++ * @param ep    The EP to start the transfer on.
++ * @param req   The request to start.
++ * @param event If non-zero, this is the first transfer for an Isoc EP, so we
++ *              must calculate the starting uFrame and do a startxfer instead
++ *              of an updatexfer.
++ */
++void dwc_usb3_pcd_ep_start_transfer(dwc_usb3_pcd_t *pcd, dwc_usb3_pcd_ep_t *ep,
++				    dwc_usb3_pcd_req_t *req, u32 event)
++{
++	dwc_usb3_dev_ep_regs_t __iomem *ep_reg;
++	dwc_usb3_dma_desc_t *desc;
++	dwc_dma_t desc_dma;
++	u32 dsts;
++	u16 current_uf, intvl, mask, now, target_uf = 0;
++	u8 tri;
++#if defined(DEBUG) || defined(ISOC_DEBUG)
++	u32 dcfg;
++#endif
++
++	dwc_debug10(pcd->usb3_dev,
++		    "%s(): ep%d-%s (%d phys) %lx max_pkt=%d req=%lx"
++		    " xfer_len=%d xfer_cnt=%d xfer_buf=%lx\n",
++		    __func__, ep->dwc_ep.num, (ep->dwc_ep.is_in ? "IN" : "OUT"),
++		    ep->dwc_ep.phys, (unsigned long)ep, ep->dwc_ep.maxpacket,
++		    (unsigned long)req, req->dwc_req.length,
++		    req->dwc_req.actual, (unsigned long)req->dwc_req.buf[0]);
++
++	ep->dwc_ep.hiber_desc_idx = 0;
++
++	/* If first transfer for Isoc */
++	if (event) {
++		/* Get the uFrame of the host request */
++		current_uf = event >> DWC_DEPEVT_ISOC_UFRAME_NUM_SHIFT &
++			     DWC_DEPEVT_ISOC_UFRAME_NUM_BITS >>
++					DWC_DEPEVT_ISOC_UFRAME_NUM_SHIFT;
++
++		/* Get the EP's interval */
++		intvl = 1 << ep->dwc_ep.intvl;
++
++		/* Get the EP's interval mask */
++		mask = ~(intvl - 1);
++
++		dsts = dwc_rd32(pcd->usb3_dev, &pcd->dev_global_regs->dsts);
++		now = dsts >> DWC_DSTS_SOF_FN_SHIFT &
++		      DWC_DSTS_SOF_FN_BITS >> DWC_DSTS_SOF_FN_SHIFT;
++		if (now < (current_uf & 0x3fff))
++			now += 0x4000;
++		now += current_uf & 0xc000;
++
++		/* Calculate a start time which is 2 or 4 intervals in the
++		 * future
++		 */
++		target_uf = current_uf & mask;
++again:
++#ifdef SELA_PLATFORM
++		target_uf += intvl;
++#else
++		if (intvl <= 8)
++			target_uf += intvl << 2;
++		else
++			target_uf += intvl << 1;
++#endif
++		dwc_isocdbg3(pcd->usb3_dev, "tgt:%1x now:%1x tgt-now:%1x\n",
++			     target_uf, now, target_uf - now);
++		if (target_uf - now >= 0x8000U)
++			goto again;
++
++#if defined(DEBUG) || defined(ISOC_DEBUG)
++		dcfg = dwc_rd32(pcd->usb3_dev, &pcd->dev_global_regs->dcfg);
++		dwc_debug6(pcd->usb3_dev,
++			   "dcfg:0x%1x dsts:0x%1x uf:0x%1x"
++			   " intvl:0x%1x cur_uf:0x%1x tgt_uf:0x%1x\n",
++			   dcfg, dsts, dsts >> 3 & 0x3fff, intvl, current_uf,
++			   target_uf);
++		dwc_isocdbg4(pcd->usb3_dev,
++			     "now:%1x bIvl:%1x ivl:%1x(u)f tgt:%1x\n",
++			     now, ep->dwc_ep.intvl + 1, intvl, target_uf);
++#endif
++		/* Make sure 'target_uf' is non-zero so the code below knows
++		 * that this is the first Isoc xfer. It will decrement the
++		 * value by 1 before using it
++		 */
++		target_uf++;
++	}
++
++	ep->dwc_ep.send_zlp = 0;
++	req->dwc_req.flags |= DWC_PCD_REQ_STARTED;
++	desc = req->dwc_req.trb;
++	desc_dma = req->dwc_req.trbdma;
++	dwc_usb3_dis_usb2_suspend(pcd);
++	wmb();
++
++	if (ep->dwc_ep.is_in) {
++		/*
++		 * Start DMA on EPn-IN
++		 */
++		ep_reg = ep->dwc_ep.in_ep_reg;
++		dwc_debug4(pcd->usb3_dev,
++			   "IN desc=0x%08lx xferlen=%u bptr=0x%08x:%08x\n",
++			   (unsigned long)desc, dwc_usb3_get_xfercnt(desc),
++			   desc->bpth, desc->bptl);
++#ifdef VERBOSE
++		dwc_debug5(pcd->usb3_dev, "%08x %08x %08x %08x (%08x)\n",
++			   *((unsigned *)desc), *((unsigned *)desc + 1),
++			   *((unsigned *)desc + 2), *((unsigned *)desc + 3),
++			   (unsigned)desc_dma);
++#endif
++		/* If Isoc */
++		if (ep->dwc_ep.type == UE_ISOCHRONOUS) {
++			if (ep->dwc_ep.xfer_started) {
++				/* Issue "DEPUPDTXFER" command to EP */
++				dwc_usb3_dep_updatexfer(pcd, ep_reg,
++							ep->dwc_ep.tri_in - 1);
++			} else if (target_uf) {
++				/* Issue "DEPSTRTXFER" command to EP */
++				tri = dwc_usb3_dep_startxfer(pcd, ep_reg,
++							     desc_dma,
++							     target_uf - 1);
++				ep->dwc_ep.tri_in = tri + 1;
++				ep->dwc_ep.xfer_started = 1;
++			} else {
++				//dwc_print0(pcd->usb3_dev,
++				//	   "Not starting isoc IN!\n");
++			}
++		} else {
++			if (ep->dwc_ep.xfer_started) {
++				/* Issue "DEPUPDTXFER" command to EP */
++				dwc_usb3_dep_updatexfer(pcd, ep_reg,
++							ep->dwc_ep.tri_in - 1);
++			} else {
++				/* Issue "DEPSTRTXFER" command to EP */
++				tri = dwc_usb3_dep_startxfer(pcd, ep_reg,
++							desc_dma,
++							req->dwc_req.stream);
++				ep->dwc_ep.tri_in = tri + 1;
++				ep->dwc_ep.xfer_started = 1;
++			}
++		}
++	} else {
++		/*
++		 * Start DMA on EPn-OUT
++		 */
++		ep_reg = ep->dwc_ep.out_ep_reg;
++		dwc_debug4(pcd->usb3_dev,
++			   "OUT desc=0x%08lx xferlen=%u bptr=0x%08x:%08x\n",
++			   (unsigned long)desc, dwc_usb3_get_xfercnt(desc),
++			   desc->bpth, desc->bptl);
++#ifdef VERBOSE
++		dwc_debug5(pcd->usb3_dev, "%08x %08x %08x %08x (%08x)\n",
++			   *((unsigned *)desc), *((unsigned *)desc + 1),
++			   *((unsigned *)desc + 2), *((unsigned *)desc + 3),
++			   (unsigned)desc_dma);
++#endif
++		/* If Isoc */
++		if (ep->dwc_ep.type == UE_ISOCHRONOUS) {
++			if (ep->dwc_ep.xfer_started) {
++				/* Issue "DEPUPDTXFER" command to EP */
++				dwc_usb3_dep_updatexfer(pcd, ep_reg,
++							ep->dwc_ep.tri_out - 1);
++			} else if (target_uf) {
++				/* Issue "DEPSTRTXFER" command to EP */
++				tri = dwc_usb3_dep_startxfer(pcd, ep_reg,
++							     desc_dma,
++							     target_uf - 1);
++				ep->dwc_ep.tri_out = tri + 1;
++				ep->dwc_ep.xfer_started = 1;
++			} else {
++				//dwc_print0(pcd->usb3_dev,
++				//	   "Not starting isoc OUT!\n");
++			}
++		} else {
++			if (ep->dwc_ep.xfer_started) {
++				/* Issue "DEPUPDTXFER" command to EP */
++				dwc_usb3_dep_updatexfer(pcd, ep_reg,
++							ep->dwc_ep.tri_out - 1);
++			} else {
++				/* Issue "DEPSTRTXFER" command to EP */
++				tri = dwc_usb3_dep_startxfer(pcd, ep_reg,
++							desc_dma,
++							req->dwc_req.stream);
++				ep->dwc_ep.tri_out = tri + 1;
++				ep->dwc_ep.xfer_started = 1;
++			}
++		}
++	}
++
++	dwc_usb3_ena_usb2_suspend(pcd);
++}
++
++/**
++ * For restart after hibernation, we need to restart the transfer with the
++ * address of the TRB that was last active before the hibernation. That address
++ * was saved in the <em>hiber_desc_idx</em> field of struct dwc_ep by the
++ * hibernation wakeup code.
++ *
++ * @param pcd   Programming view of DWC_usb3 peripheral controller.
++ * @param ep    The EP to restart the transfer on.
++ * @return      1 if a transfer was restarted, 0 if not.
++ */
++int dwc_usb3_pcd_isoc_ep_hiber_restart(dwc_usb3_pcd_t *pcd,
++				       dwc_usb3_pcd_ep_t *ep)
++{
++	dwc_usb3_dev_ep_regs_t __iomem *ep_reg;
++	dwc_usb3_dma_desc_t *desc;
++	dwc_dma_t desc_dma;
++	int owned;
++	u8 *tri;
++
++	/* Need to restart after hibernation? */
++	owned = ep->dwc_ep.hiber_desc_idx - 1;
++	if (owned < 0)
++		return 0;
++
++	if (ep->dwc_ep.is_in) {
++		ep_reg = ep->dwc_ep.in_ep_reg;
++		tri = &ep->dwc_ep.tri_in;
++	} else {
++		ep_reg = ep->dwc_ep.out_ep_reg;
++		tri = &ep->dwc_ep.tri_out;
++	}
++
++	dwc_debug0(pcd->usb3_dev, "Restarting Isoc xfer\n");
++	desc = ep->dwc_ep.dma_desc + owned;
++	desc_dma = (dwc_dma_t)
++		((unsigned long)ep->dwc_ep.dma_desc_dma + owned * 16);
++	dwc_debug1(pcd->usb3_dev, "desc=%08lx\n", (unsigned long)desc);
++
++#ifdef VERBOSE
++	dwc_debug5(pcd->usb3_dev, "%08x %08x %08x %08x (%08x)\n",
++		   *((unsigned *)desc), *((unsigned *)desc + 1),
++		   *((unsigned *)desc + 2), *((unsigned *)desc + 3),
++		   (unsigned)desc_dma);
++#endif
++
++	dwc_usb3_dis_usb2_suspend(pcd);
++	wmb();
++	*tri = dwc_usb3_dep_startxfer(pcd, ep_reg, desc_dma, 0) + 1;
++	dwc_usb3_ena_usb2_suspend(pcd);
++
++	return 1;
++}
++
++/**
++ * Stop any active xfer on a non-EP0 endpoint.
++ */
++static void dwc_usb3_stop_xfer(dwc_usb3_pcd_t *pcd, dwc_usb3_pcd_ep_t *ep)
++{
++	dwc_usb3_dev_ep_regs_t __iomem *ep_reg;
++
++	dwc_debug1(pcd->usb3_dev, "%s()\n", __func__);
++
++	if (ep->dwc_ep.is_in) {
++		if (ep->dwc_ep.active && ep->dwc_ep.tri_in) {
++			ep_reg = ep->dwc_ep.in_ep_reg;
++			ep->dwc_ep.condition = 0;
++			dwc_usb3_dep_endxfer(pcd, ep_reg, ep->dwc_ep.tri_in - 1,
++					     DWC_ENDXFER_FORCE,
++					     &ep->dwc_ep.condition);
++			ep->dwc_ep.tri_in = 0;
++		}
++	} else {
++		if (ep->dwc_ep.active && ep->dwc_ep.tri_out) {
++			ep_reg = ep->dwc_ep.out_ep_reg;
++			ep->dwc_ep.condition = 0;
++			dwc_usb3_dep_endxfer(pcd, ep_reg, ep->dwc_ep.tri_out - 1,
++					     DWC_ENDXFER_FORCE,
++					     &ep->dwc_ep.condition);
++			ep->dwc_ep.tri_out = 0;
++		}
++	}
++}
++
++/**
++ * Stop any active xfers on the non-EP0 endpoints.
++ */
++void dwc_usb3_stop_all_xfers(dwc_usb3_pcd_t *pcd)
++{
++	int i;
++	dwc_usb3_pcd_ep_t *ep;
++
++	dwc_debug1(pcd->usb3_dev, "%s()\n", __func__);
++	dwc_usb3_dis_usb2_suspend(pcd);
++
++	/* Stop any active xfers on the non-EP0 IN endpoints */
++	printk("\n####%s,%d,pcd->num_in_eps=0x%x,pcd->num_out_eps=0x%x\n",__func__,__LINE__,pcd->num_in_eps,pcd->num_out_eps);
++	for (i = pcd->num_in_eps; i > 0; i--) {
++		ep = pcd->in_ep[i - 1];
++		dwc_debug3(pcd->usb3_dev, "DWC IN EP%d=%lx tri-in=%d\n",
++			   i, (unsigned long)ep, ep->dwc_ep.tri_in);
++		dwc_error(pcd->usb3_dev, "DWC IN EP%d=%lx tri-in=%d\n",
++			   i, (unsigned long)ep, ep->dwc_ep.tri_in);
++		dwc_usb3_stop_xfer(pcd, ep);
++		dwc_usb3_gadget_request_nuke(pcd, ep);
++		ep->dwc_ep.xfer_started = 0;
++	}
++
++	/* Stop any active xfers on the non-EP0 OUT endpoints */
++	for (i = pcd->num_out_eps; i > 0; i--) {
++		ep = pcd->out_ep[i - 1];
++		dwc_debug3(pcd->usb3_dev, "DWC OUT EP%d=%lx tri-out=%d\n",
++			   i, (unsigned long)ep, ep->dwc_ep.tri_out);
++		dwc_error(pcd->usb3_dev, "DWC OUT EP%d=%lx tri-out=%d\n",
++			   i, (unsigned long)ep, ep->dwc_ep.tri_out);
++		dwc_usb3_stop_xfer(pcd, ep);
++		dwc_usb3_gadget_request_nuke(pcd, ep);
++		ep->dwc_ep.xfer_started = 0;
++	}
++
++	dwc_usb3_ena_usb2_suspend(pcd);
++}
++
++/**
++ * This routine completes the request for the EP. If there are additional
++ * requests for the EP in the queue they will be started.
++ */
++static int dwc_usb3_ep_complete_request(dwc_usb3_pcd_t *pcd,
++					dwc_usb3_pcd_ep_t *ep,
++					dwc_usb3_pcd_req_t *req, u32 event)
++{
++	int is_last = 0, ret = 0;
++	int now_uf, evt_uf, i;
++	dwc_usb3_dma_desc_t *desc;
++	u32 byte_count;
++#if defined(DEBUG) || defined(ISOC_DEBUG)
++	dwc_usb3_device_t *dev = pcd->usb3_dev;
++	u32 bmudbg;
++	static u32 old0, old1, old2, old3, old4;
++#endif
++
++	dwc_debug1(dev, "%s()\n", __func__);
++
++	ep->dwc_ep.send_zlp = 0;
++	desc = req->dwc_req.trb;
++	dwc_debug2(dev, "req=%lx desc=%lx\n", (unsigned long)req,
++		   (unsigned long)desc);
++
++	if (!desc) {
++		dwc_isocdbg3(dev, "### %s, EP%d-%s request TRB is NULL! ###\n",
++			     __func__, ep->dwc_ep.num, ep->dwc_ep.is_in ?
++			     "IN" : "OUT");
++		return ret;
++	}
++
++	if (!(req->dwc_req.flags & DWC_PCD_REQ_STARTED)) {
++		dwc_isocdbg3(dev, "### %s, EP%d-%s request not started! ###\n",
++			     __func__, ep->dwc_ep.num, ep->dwc_ep.is_in ?
++			     "IN" : "OUT");
++		if (ep->dwc_ep.type == UE_ISOCHRONOUS &&
++		    (event & DWC_DEPEVT_INTTYPE_BITS) ==
++		    DWC_DEPEVT_XFER_IN_PROG << DWC_DEPEVT_INTTYPE_SHIFT &&
++		    ep->dwc_ep.xfer_started == 0) {
++			is_last = 1;
++			goto done;
++		}
++		return ret;
++	}
++
++	if (dwc_usb3_is_hwo(desc)) {
++		dwc_isocdbg3(dev, "### %s, EP%d-%s HWO bit set! ###\n",
++			     __func__, ep->dwc_ep.num, ep->dwc_ep.is_in ?
++			     "IN" : "OUT");
++		return ret;
++	}
++
++	if (ep->dwc_ep.type == UE_ISOCHRONOUS) {
++		now_uf = dwc_usb3_get_frame(pcd);
++		evt_uf = dwc_usb3_get_eventsofn(event);
++		dwc_isocdbg6(dev,
++			"ep:%1x evt:%08x frm:%04x now:%04x trb:%1lx len:%04x\n",
++			ep->dwc_ep.num, event, evt_uf, now_uf,
++			((unsigned long)req->dwc_req.trbdma -
++			 (unsigned long)ep->dwc_ep.dma_desc_dma) /
++			(req->dwc_req.numbuf * 16), dwc_usb3_get_xfercnt(desc));
++		/*dwc_isocdbg4(dev, "this trb: %08x %08x %08x %08x\n",
++			*((unsigned *)desc), *((unsigned *)desc + 1),
++			*((unsigned *)desc + 2), *((unsigned *)desc + 3));
++		dwc_isocdbg4(dev, "next trb: %08x %08x %08x %08x\n",
++			*((unsigned *)desc + 4), *((unsigned *)desc + 5),
++			*((unsigned *)desc + 6), *((unsigned *)desc + 7));*/
++	}
++
++	if (ep->dwc_ep.is_in) {	/* IN endpoint */
++		for (i = 0; i < req->dwc_req.numbuf; i++, desc++) {
++				req->dwc_req.actual += req->dwc_req.length;
++				if (i == req->dwc_req.numbuf - 1)
++					is_last = 1;
++		}
++
++		if (i)
++			desc--;
++		dwc_debug3(dev, "IN len=%d cnt=%d rem=%d\n",
++			   req->dwc_req.length, req->dwc_req.actual,
++			   dwc_usb3_get_xfercnt(desc));
++
++	} else {		/* OUT endpoint */
++		for (i = 0; i < req->dwc_req.numbuf; i++, desc++) {
++			byte_count = req->dwc_req.length -
++						dwc_usb3_get_xfercnt(desc);
++			req->dwc_req.actual += byte_count;
++		}
++
++		if (i)
++			desc--;
++		dwc_debug3(dev, "OUT len=%d cnt=%d rem=%d\n",
++			   req->dwc_req.length, req->dwc_req.actual,
++			   dwc_usb3_get_xfercnt(desc));
++		is_last = 1;
++	}
++done:
++	if ((event & DWC_DEPEVT_INTTYPE_BITS) ==
++	    DWC_DEPEVT_XFER_CMPL << DWC_DEPEVT_INTTYPE_SHIFT) {
++		if (ep->dwc_ep.is_in)
++			ep->dwc_ep.tri_in = 0;
++		else
++			ep->dwc_ep.tri_out = 0;
++	}
++
++	/* Complete the request */
++	if (is_last) {
++		dwc_usb3_pcd_request_done(pcd, ep, req, 0);
++		//dwc_info2(dev, "ep_complete_request - start req %d-%s\n",
++		//	  ep->dwc_ep.num, ep->dwc_ep.is_in ? "IN" : "OUT");
++		if (ep->dwc_ep.type != UE_ISOCHRONOUS ||
++						ep->dwc_ep.xfer_started)
++			/* If there is a request in the queue start it. */
++			dwc_usb3_gadget_start_next_request(pcd, ep);
++
++#ifdef DWC_ISOC_INTR_MODERATION
++		/* Handle Isoc interrupt moderation */
++		if (ep->dwc_ep.type == UE_ISOCHRONOUS &&
++		    ep->dwc_ep.xfer_started && !dwc_usb3_is_ioc(desc))
++			/* Tell caller we want to process next TRB */
++			ret = 1;
++#endif
++	} else {
++		dwc_print2(dev, "### EP%d-%s is_last not set! ###\n",
++			   ep->dwc_ep.num, ep->dwc_ep.is_in ? "IN" : "OUT");
++	}
++
++	return ret;
++}
++
++/**
++ * This routine handles non-EP0 transfers.
++ *
++ * This routine gets the request corresponding to the completed transfer
++ * and then calls the core routine for handling the completion.
++ */
++void dwc_usb3_complete_request(dwc_usb3_pcd_t *pcd, dwc_usb3_pcd_ep_t *ep,
++			       u32 event)
++{
++	dwc_usb3_pcd_req_t *req;
++	dwc_usb3_dma_desc_t *desc;
++	int ret;
++
++	dwc_debug1(pcd->usb3_dev, "%s()\n", __func__);
++	dwc_debug1(pcd->usb3_dev, "Requests %d\n", pcd->request_pending);
++
++	req = dwc_usb3_gadget_get_request(pcd, ep);
++	if (!req) {
++		dwc_print2(pcd->usb3_dev, "%s(%lx), ep->dwc_ep.queue empty!\n",
++			   __func__, (unsigned long)ep);
++		return;
++	}
++next:
++	ret = dwc_usb3_ep_complete_request(pcd, ep, req, event);
++	dwc_debug1(pcd->usb3_dev,
++		   "dwc_usb3_ep_complete_request() returned %d\n", ret);
++	if (!ret)
++		return;
++
++	req = dwc_usb3_gadget_get_request(pcd, ep);
++	if (!req)
++		return;
++
++	if (ret < 0) {
++		/* Isoc restart - mark all requests in queue as not started */
++		dwc_usb3_gadget_set_ep_not_started(pcd, ep);
++	} else {
++		/* ep_complete_request() wants to process next TRB */
++		dwc_debug1(pcd->usb3_dev, "Requests2 %d\n",
++			   pcd->request_pending);
++		desc = req->dwc_req.trb;
++		if (desc && (req->dwc_req.flags & DWC_PCD_REQ_STARTED) &&
++		    !dwc_usb3_is_hwo(desc)) {
++			dwc_debug0(pcd->usb3_dev, "Processing next TRB\n");
++			goto next;
++		}
++	}
++}
++
++/**
++ * Set the EP STALL.
++ *
++ * @param pcd   Programming view of DWC_usb3 peripheral controller.
++ * @param ep    The EP to set the stall on.
++ */
++void dwc_usb3_pcd_ep_set_stall(dwc_usb3_pcd_t *pcd, dwc_usb3_pcd_ep_t *ep)
++{
++	dwc_usb3_dev_ep_regs_t __iomem *ep_reg;
++
++	dwc_info2(pcd->usb3_dev, "%s(%lx)\n", __func__, (unsigned long)ep);
++	dwc_info2(pcd->usb3_dev, "ep_num=%d is_in=%d\n",
++		  ep->dwc_ep.num, ep->dwc_ep.is_in);
++
++	if (ep->dwc_ep.is_in)
++		ep_reg = ep->dwc_ep.in_ep_reg;
++	else
++		ep_reg = ep->dwc_ep.out_ep_reg;
++
++	dwc_usb3_dis_usb2_suspend(pcd);
++	dwc_usb3_dep_sstall(pcd, ep_reg);
++	dwc_usb3_ena_usb2_suspend(pcd);
++}
++
++/**
++ * Clear the EP STALL.
++ *
++ * @param pcd   Programming view of DWC_usb3 peripheral controller.
++ * @param ep    The EP to clear the stall on.
++ */
++void dwc_usb3_pcd_ep_clear_stall(dwc_usb3_pcd_t *pcd, dwc_usb3_pcd_ep_t *ep)
++{
++	dwc_usb3_dev_ep_regs_t __iomem *ep_reg;
++
++	dwc_debug1(pcd->usb3_dev, "%s()\n", __func__);
++	dwc_debug2(pcd->usb3_dev, "ep_num=%d is_in=%d\n",
++		   ep->dwc_ep.num, ep->dwc_ep.is_in);
++
++	if (ep->dwc_ep.is_in)
++		ep_reg = ep->dwc_ep.in_ep_reg;
++	else
++		ep_reg = ep->dwc_ep.out_ep_reg;
++
++	dwc_usb3_dis_usb2_suspend(pcd);
++	dwc_usb3_dep_cstall(pcd, ep_reg, 0);
++	dwc_usb3_ena_usb2_suspend(pcd);
++}
++
++/**
++ * This routine returns a pointer to Out EP struct with number ep_num.
++ */
++dwc_usb3_pcd_ep_t *dwc_usb3_get_out_ep(dwc_usb3_pcd_t *pcd, u32 ep_num)
++{
++	//dwc_debug2(pcd->usb3_dev, "%s(%d)\n", __func__, ep_num);
++
++	if (ep_num == 0)
++		return pcd->ep0;
++	else
++		return pcd->out_ep[ep_num - 1];
++}
++
++/**
++ * This routine returns a pointer to In EP struct with number ep_num.
++ */
++dwc_usb3_pcd_ep_t *dwc_usb3_get_in_ep(dwc_usb3_pcd_t *pcd, u32 ep_num)
++{
++	//dwc_debug2(pcd->usb3_dev, "%s(%d)\n", __func__, ep_num);
++
++	if (ep_num == 0)
++		return pcd->ep0;
++	else
++		return pcd->in_ep[ep_num - 1];
++}
++
++/**
++ * This routine gets a pointer to an EP from the wIndex address value of the
++ * control request.
++ */
++dwc_usb3_pcd_ep_t *dwc_usb3_pcd_get_ep_by_addr(dwc_usb3_pcd_t *pcd, u16 index)
++{
++	u32 ep_num = UE_GET_ADDR(index);
++
++	//dwc_debug2(pcd->usb3_dev, "%s(%d)\n", __func__, index);
++
++	if (UE_GET_DIR(index) == UE_DIR_IN)
++		return dwc_usb3_get_in_ep(pcd, ep_num);
++	else
++		return dwc_usb3_get_out_ep(pcd, ep_num);
++}
++
++/* USB Endpoint Operations */
++/*
++ * The following sections briefly describe the behavior of the Gadget API
++ * endpoint operations implemented in the DWC_usb3 driver software. Detailed
++ * descriptions of the generic behavior of each of these routines can be
++ * found in the Linux header file include/linux/usb_gadget.h.
++ *
++ * The Gadget API provides wrapper routines for each of the function
++ * pointers defined in usb_ep_ops. The Gadget Driver calls the wrapper
++ * routine, which then calls the underlying PCD routine. The following
++ * sections are named according to the wrapper routines. Within each
++ * section, the corresponding DWC_usb3 PCD routine name is specified.
++ *
++ */
++
++/**
++ * This routine is called by the Function Driver for each EP (except EP0) to
++ * be configured for the current configuration (SET_CONFIGURATION).
++ *
++ * This routine initializes the dwc_usb3_ep_t data structure, and then
++ * calls dwc_usb3_ep_activate.
++ */
++int dwc_usb3_pcd_ep_enable(dwc_usb3_pcd_t *pcd, dwc_usb3_pcd_ep_t *ep,
++			   const usb_endpoint_descriptor_t *ep_desc,
++			   const ss_endpoint_companion_descriptor_t *ep_comp)
++{
++	int num, dir;
++	u16 maxpacket;
++	u8 type;
++
++	dwc_debug5(pcd->usb3_dev, "%s(%lx,%lx,%lx,%lx)\n", __func__,
++		   (unsigned long)pcd, (unsigned long)ep,
++		   (unsigned long)ep_desc, (unsigned long)ep_comp);
++	dwc_debug2(pcd->usb3_dev, "ep=%lx is_in=%d\n", (unsigned long)ep,
++		   ep->dwc_ep.is_in);
++
++	if (ep->dwc_ep.usb_ep_desc) {
++		dwc_print1(pcd->usb3_dev, "%s, bad ep or descriptor!\n",
++			   __func__);
++		return -DWC_E_INVALID;
++	}
++
++	ep->dwc_ep.usb_ep_desc = ep_desc;
++
++	/*
++	 * Activate the EP
++	 */
++	ep->dwc_ep.stopped = 0;
++
++	num = UE_GET_ADDR(ep_desc->bEndpointAddress);
++	if (ep->dwc_ep.num != num) {
++		dwc_print3(pcd->usb3_dev,
++			   "%s, EP num mismatch, is %d asked %d!\n",
++			   __func__, ep->dwc_ep.num, num);
++	}
++
++	dir = UE_GET_DIR(ep_desc->bEndpointAddress);
++	if (ep->dwc_ep.is_in != (dir == UE_DIR_IN)) {
++		dwc_print3(pcd->usb3_dev,
++			   "%s, EP dir mismatch, is %d asked %d!\n",
++			   __func__, ep->dwc_ep.is_in, dir == UE_DIR_IN);
++	}
++
++	type = UE_GET_XFERTYPE(ep_desc->bmAttributes);
++	maxpacket = UGETW(ep_desc->wMaxPacketSize);
++
++	ep->dwc_ep.type = type;
++	ep->dwc_ep.maxpacket = maxpacket & 0x7ff;
++	ep->dwc_ep.intvl = 0;
++	ep->dwc_ep.mult = 0;
++	ep->dwc_ep.maxburst = 0;
++	ep->dwc_ep.num_streams = 0;
++	ep->dwc_ep.xfer_started = 0;
++
++	if (pcd->speed == USB_SPEED_SUPER && ep_comp)
++		ep->dwc_ep.maxburst = ep_comp->bMaxBurst;
++
++	switch (type) {
++	case UE_ISOCHRONOUS:
++		if (pcd->speed == USB_SPEED_SUPER && ep_comp) {
++			ep->dwc_ep.mult = USSE_GET_MAX_PACKET_NUM(
++						ep_comp->bmAttributes) + 1;
++			/* 3 packets at most */
++			if (ep->dwc_ep.mult > 3)
++				return -DWC_E_INVALID;
++		}
++		/* FALL THRU */
++	case UE_INTERRUPT:
++		if (pcd->speed == USB_SPEED_SUPER) {
++			ep->dwc_ep.intvl = ep_desc->bInterval - 1;
++			break;
++		}
++
++		ep->dwc_ep.intvl = ep_desc->bInterval - 1;
++
++		/*
++		 * Bits 12:11 specify number of _additional_
++		 * packets per microframe.
++		 */
++		ep->dwc_ep.mult = (maxpacket >> 11 & 3) + 1;
++
++		/* 3 packets at most */
++		if (ep->dwc_ep.mult > 3)
++			return -DWC_E_INVALID;
++
++		break;
++
++	case UE_BULK:
++		if (pcd->speed == USB_SPEED_SUPER && ep_comp)
++			ep->dwc_ep.num_streams =
++				USSE_GET_MAX_STREAMS(ep_comp->bmAttributes);
++
++		/* Set initial data PID */
++		ep->dwc_ep.data_pid_start = 0;
++		break;
++	}
++
++	dwc_debug5(pcd->usb3_dev,
++		   "type=%u maxpkt=%u mult=%u maxbst=%u numstrm=%u\n",
++		   type, maxpacket, ep->dwc_ep.mult, ep->dwc_ep.maxburst,
++		   ep->dwc_ep.num_streams);
++
++	dwc_usb3_ep_activate(pcd, ep, 0);
++	return 0;
++}
++
++/**
++ * This routine is called when an EP (except EP0) is disabled due to
++ * disconnect or change in configuration. Any pending requests will
++ * terminate with a status of -ESHUTDOWN.
++ *
++ * This routine modifies the dwc_usb3_ep_t data structure for this EP,
++ * and then calls ep_deactivate.
++ */
++int dwc_usb3_pcd_ep_disable(dwc_usb3_pcd_t *pcd, dwc_usb3_pcd_ep_t *ep)
++{
++	dwc_debug2(pcd->usb3_dev, "%s(%lx)\n", __func__, (unsigned long)ep);
++	dwc_debug2(pcd->usb3_dev, "ep=%lx is_in=%d\n", (unsigned long)ep,
++		   ep->dwc_ep.is_in);
++
++	if (!ep->dwc_ep.usb_ep_desc)
++		return -DWC_E_INVALID;
++
++	ep_deactivate(ep->dwc_ep.pcd, ep);
++	dwc_usb3_gadget_request_nuke(pcd, ep);
++	ep->dwc_ep.usb_ep_desc = NULL;
++
++	return 0;
++}
++
++/**
++ * This routine submits an I/O Request to an EP.
++ *
++ * - When the request completes the request's completion callback is called
++ *   to return the request to the driver.
++ * - An EP, except control EPs, may have multiple requests pending.
++ * - Once submitted the request cannot be examined or modified.
++ * - Each request is turned into one or more packets.
++ * - A BULK EP can queue any amount of data; the transfer is packetized.
++ * - Zero-length packets are specified with the request 'zero' flag.
++ */
++int dwc_usb3_pcd_ep_submit_req(dwc_usb3_pcd_t *pcd, dwc_usb3_pcd_ep_t *ep,
++			       dwc_usb3_pcd_req_t *req, int req_flags)
++{
++	dwc_debug1(pcd->usb3_dev, "%s()\n", __func__);
++
++	/* EP0 Transfer? */
++	if (ep == pcd->ep0) {
++		switch (pcd->ep0state) {
++		case EP0_IN_DATA_PHASE:
++			dwc_debug1(pcd->usb3_dev, "%s ep0: EP0_IN_DATA_PHASE\n",
++				   __func__);
++			break;
++
++		case EP0_OUT_DATA_PHASE:
++			dwc_debug1(pcd->usb3_dev,
++				   "%s ep0: EP0_OUT_DATA_PHASE\n", __func__);
++			if (pcd->request_config) {
++				/* Complete STATUS PHASE */
++				ep->dwc_ep.is_in = 1;
++				pcd->ep0state = EP0_IN_WAIT_NRDY;
++				return 1;
++			}
++
++			break;
++
++		case EP0_IN_WAIT_GADGET:
++			dwc_debug1(pcd->usb3_dev,
++				   "%s ep0: EP0_IN_WAIT_GADGET\n", __func__);
++			pcd->ep0state = EP0_IN_WAIT_NRDY;
++			return 2;
++
++		case EP0_OUT_WAIT_GADGET:
++			dwc_debug1(pcd->usb3_dev,
++				   "%s ep0: EP0_OUT_WAIT_GADGET\n", __func__);
++			pcd->ep0state = EP0_OUT_WAIT_NRDY;
++			return 3;
++
++		case EP0_IN_WAIT_NRDY:
++			dwc_debug1(pcd->usb3_dev, "%s ep0: EP0_IN_WAIT_NRDY\n",
++				   __func__);
++			pcd->ep0state = EP0_IN_STATUS_PHASE;
++			break;
++
++		case EP0_OUT_WAIT_NRDY:
++			dwc_debug1(pcd->usb3_dev, "%s ep0: EP0_OUT_WAIT_NRDY\n",
++				   __func__);
++			pcd->ep0state = EP0_OUT_STATUS_PHASE;
++			break;
++
++		default:
++			dwc_print2(pcd->usb3_dev, "%s ep0: odd state %d!\n",
++				   __func__, pcd->ep0state);
++			return -DWC_E_SHUTDOWN;
++		}
++
++		ep->dwc_ep.send_zlp = 0;
++
++		if ((req_flags & DWC_PCD_REQ_ZERO) &&
++				req->dwc_req.length != 0 &&
++				(req->dwc_req.length &
++					(ep->dwc_ep.maxpacket - 1)) == 0) {
++			ep->dwc_ep.send_zlp = 1;
++		}
++
++		dwc_usb3_pcd_ep0_start_transfer(pcd, req);
++
++#ifdef DWC_STAR_9000463548_WORKAROUND
++		if (pcd->configuring) {
++			dwc_usb3_pcd_ep_t *ept;
++			int i;
++
++			pcd->configuring = 0;
++
++			for (i = 0; i < pcd->num_in_eps; i++) {
++				ept = pcd->in_ep[i];
++				if (ept->dwc_ep.active)
++					dwc_usb3_ep_activate(pcd, ept, 0);
++			}
++
++			for (i = 0; i < pcd->num_out_eps; i++) {
++				ept = pcd->out_ep[i];
++				if (ept->dwc_ep.active)
++					dwc_usb3_ep_activate(pcd, ept, 0);
++			}
++		}
++#endif
++	} else {
++		/* Setup and start the Transfer */
++		dwc_usb3_pcd_ep_start_transfer(pcd, ep, req, 0);
++	}
++
++	return 0;
++}
++
++/**
++ * This routine cancels an I/O request from an EP.
++ */
++void dwc_usb3_pcd_ep_cancel_req(dwc_usb3_pcd_t *pcd, dwc_usb3_pcd_ep_t *ep,
++				dwc_usb3_pcd_req_t *req, u32 stream)
++{
++	dwc_debug4(pcd->usb3_dev, "%s(%lx,%lx) stream %d\n", __func__,
++		   (unsigned long)ep, (unsigned long)req, stream);
++
++	dwc_usb3_dis_usb2_suspend(pcd);
++	dwc_usb3_stop_xfer(pcd, ep);
++	dwc_usb3_ena_usb2_suspend(pcd);
++
++	ep->dwc_ep.xfer_started = 0;
++	dwc_usb3_pcd_request_done(pcd, ep, req, -DWC_E_DISCONNECT);
++}
++
++/**
++ * usb_ep_set_halt stalls an endpoint.
++ *
++ * usb_ep_clear_halt clears an endpoint stall and resets its data toggle.
++ *
++ * Both of these routines are implemented with the same underlying routine.
++ * The behavior depends on the value argument.
++ *
++ * @param pcd   The PCD structure.
++ * @param ep    The endpoint to set halt or clear halt.
++ * @param value - 0 means clear_halt.
++ *              - 1 means set_halt.
++ *              - 2 means clear stall lock flag.
++ *              - 3 means set stall lock flag.
++ */
++void dwc_usb3_pcd_ep_set_halt(dwc_usb3_pcd_t *pcd, dwc_usb3_pcd_ep_t *ep,
++			      int value)
++{
++	dwc_debug3(pcd->usb3_dev, "%s(%lx,%d)\n", __func__,
++		   (unsigned long)ep, value);
++
++	if (value == 0) {
++		ep->dwc_ep.stall_clear_flag = 0;
++		if (ep != pcd->ep0)
++			dwc_usb3_pcd_ep_clear_stall(pcd, ep);
++
++		if (ep->dwc_ep.stopped) {
++			ep->dwc_ep.stopped = 0;
++
++			/* If there is a request in the EP queue start it */
++			if (ep != pcd->ep0 && ep->dwc_ep.is_in)
++				dwc_usb3_gadget_start_next_request(pcd, ep);
++		}
++	} else if (value == 1) {
++stall:
++		if (ep == pcd->ep0) {
++			ep->dwc_ep.is_in = 0;
++			dwc_usb3_pcd_ep_set_stall(pcd, ep);
++			pcd->ep0state = EP0_STALL;
++		} else {
++			dwc_usb3_pcd_ep_set_stall(pcd, ep);
++		}
++
++		ep->dwc_ep.stopped = 1;
++
++	} else if (value == 2) {
++		ep->dwc_ep.stall_clear_flag = 0;
++
++	} else if (value == 3) {
++		ep->dwc_ep.stall_clear_flag = 1;
++		goto stall;
++	}
++}
++
++/**
++ * This routine completes a request. It calls the request callback.
++ */
++void dwc_usb3_pcd_request_done(dwc_usb3_pcd_t *pcd, dwc_usb3_pcd_ep_t *ep,
++			       dwc_usb3_pcd_req_t *req, int status)
++{
++	unsigned stopped = ep->dwc_ep.stopped;
++
++	dwc_debug4(pcd->usb3_dev, "%s(%lx,%lx,%d)\n", __func__,
++		   (unsigned long)ep, (unsigned long)req, status);
++
++//	printk("\n###%s,%d,=0x%x\n",__func__,__LINE__,req->dwc_req);
++//	printk("\n###%s,%d\n",__func__,__LINE__);
++	if (ep != pcd->ep0) {
++//	printk("\n###%s,%d\n",__func__,__LINE__);
++		req->dwc_req.flags &= ~DWC_PCD_REQ_STARTED;
++//	printk("\n###%s,%d\n",__func__,__LINE__);
++		if (req->dwc_req.trb) {
++
++//	printk("\n###%s,%d\n",__func__,__LINE__);
++			dwc_usb3_disable_desc(req->dwc_req.trb);
++//	printk("\n###%s,%d\n",__func__,__LINE__);
++			ep->dwc_ep.desc_avail++;
++//	printk("\n###%s,%d\n",__func__,__LINE__);
++			req->dwc_req.trb = NULL;
++		}
++	}
++
++	/* don't modify queue heads during completion callback */
++	ep->dwc_ep.stopped = 1;
++
++	dwc_usb3_gadget_complete(pcd, ep, req, status);
++//	printk("\n###%s,%d\n",__func__,__LINE__);
++
++	//req->dwc_req.actual = 0;
++	ep->dwc_ep.stopped = stopped;
++//	printk("\n###%s,%d\n",__func__,__LINE__);
++}
++
++/**
++ * This routine is called when the Device is disconnected. It stops any
++ * active requests and informs the Function Driver of the disconnect.
++ */
++void dwc_usb3_pcd_stop(dwc_usb3_pcd_t *pcd)
++{
++	dwc_usb3_pcd_ep_t *ep;
++	int i;
++
++	dwc_debug1(pcd->usb3_dev, "%s()\n", __func__);
++
++	/* don't disconnect drivers more than once */
++	if (pcd->state == DWC_STATE_UNCONNECTED) {
++		dwc_debug1(pcd->usb3_dev, "%s() Already Disconnected\n",
++			   __func__);
++	} else {
++		pcd->state = DWC_STATE_UNCONNECTED;
++
++		/* report disconnect; the driver is already quiesced */
++		dwc_usb3_gadget_disconnect(pcd);
++	}
++
++	dwc_usb3_dis_usb2_suspend(pcd);
++
++	/* kill any outstanding requests, prevent new request submissions */
++	for (i = 0; i < pcd->num_in_eps; i++) {
++		ep = pcd->in_ep[i];
++		dwc_usb3_stop_xfer(pcd, ep);
++		dwc_usb3_gadget_request_nuke(pcd, ep);
++		ep->dwc_ep.xfer_started = 0;
++	}
++
++	for (i = 0; i < pcd->num_out_eps; i++) {
++		ep = pcd->out_ep[i];
++		dwc_usb3_stop_xfer(pcd, ep);
++		dwc_usb3_gadget_request_nuke(pcd, ep);
++		ep->dwc_ep.xfer_started = 0;
++	}
++
++	dwc_usb3_ena_usb2_suspend(pcd);
++}
++
++/**
++ * Gets the current USB frame number.
++ */
++int dwc_usb3_pcd_get_frame_number(dwc_usb3_pcd_t *pcd)
++{
++	return dwc_usb3_get_frame(pcd);
++}
++
++/**
++ * Initialize the PCD EP structures to their default state.
++ *
++ * @param pcd   The PCD structure.
++ */
++static void pcd_epinit(dwc_usb3_pcd_t *pcd)
++{
++	int num_out_eps = pcd->num_out_eps;
++	int num_in_eps = pcd->num_in_eps;
++	int ep_cntr, i;
++	dwc_usb3_pcd_ep_t *ep;
++
++	dwc_debug2(pcd->usb3_dev, "%s(%lx)\n", __func__, (unsigned long)pcd);
++	dwc_debug1(pcd->usb3_dev, "num_out_eps=%d\n", num_out_eps);
++	dwc_debug1(pcd->usb3_dev, "num_in_eps=%d\n", num_in_eps);
++
++	/*
++	 * Initialize the EP0 structure
++	 */
++	ep = pcd->ep0;
++
++	/* Init EP structure */
++	ep->dwc_ep.dma_desc = NULL;
++	ep->dwc_ep.dma_desc_dma = 0;
++	ep->dwc_ep.usb_ep_desc = NULL;
++	ep->dwc_ep.pcd = pcd;
++	ep->dwc_ep.stopped = 1;
++	ep->dwc_ep.is_in = 0;
++	ep->dwc_ep.active = 0;
++	ep->dwc_ep.phys = 0;
++	ep->dwc_ep.num = 0;
++#ifdef DWC_UTE
++	pcd->txf_map[1] = 0;
++#endif
++	ep->dwc_ep.tx_fifo_num = 0;
++	ep->dwc_ep.out_ep_reg = &pcd->out_ep_regs[0];
++	ep->dwc_ep.in_ep_reg = &pcd->in_ep_regs[0];
++
++	ep->dwc_ep.type = DWC_USB3_EP_TYPE_CONTROL;
++	ep->dwc_ep.maxpacket = DWC_MAX_EP0_SIZE;
++	ep->dwc_ep.send_zlp = 0;
++	ep->dwc_ep.queue_sof = 0;
++
++	pcd->ep0_req->dwc_req.buf[0] = NULL;
++	pcd->ep0_req->dwc_req.bufdma[0] = 0;
++	pcd->ep0_req->dwc_req.buflen[0] = 0;
++	pcd->ep0_req->dwc_req.length = 0;
++	pcd->ep0_req->dwc_req.actual = 0;
++
++	/*
++	 * Initialize the EP1-n structures
++	 */
++	ep_cntr = 0;
++
++	for (i = 1; ep_cntr < num_out_eps; i++) {
++		dwc_debug2(pcd->usb3_dev,
++			   "initializing EP%d-OUT (out_ep[%d])\n", i, ep_cntr);
++		ep = pcd->out_ep[ep_cntr];
++		ep_cntr++;
++
++		/* Init EP structure - but don't overwrite '.num', the gadget
++		 * has already set that
++		 */
++		ep->dwc_ep.dma_desc = NULL;
++		ep->dwc_ep.dma_desc_dma = 0;
++		ep->dwc_ep.usb_ep_desc = NULL;
++		ep->dwc_ep.pcd = pcd;
++		ep->dwc_ep.stopped = 1;
++		ep->dwc_ep.is_in = 0;
++		ep->dwc_ep.active = 0;
++		ep->dwc_ep.phys = ep_cntr << 1;
++		ep->dwc_ep.tx_fifo_num = 0;
++		ep->dwc_ep.out_ep_reg = &pcd->out_ep_regs[ep_cntr];
++
++		/* Control until EP is activated */
++		ep->dwc_ep.type = DWC_USB3_EP_TYPE_CONTROL;
++		ep->dwc_ep.maxpacket = DWC_MAX_EP0_SIZE;
++		ep->dwc_ep.send_zlp = 0;
++		ep->dwc_ep.queue_sof = 0;
++	}
++
++	ep_cntr = 0;
++
++	for (i = 1; ep_cntr < num_in_eps; i++) {
++		dwc_debug2(pcd->usb3_dev,
++			   "initializing EP%d-IN (in_ep[%d])\n", i, ep_cntr);
++		ep = pcd->in_ep[ep_cntr];
++		ep_cntr++;
++
++		/* Init EP structure - but don't overwrite '.num', the gadget
++		 * has already set that
++		 */
++		ep->dwc_ep.dma_desc = NULL;
++		ep->dwc_ep.dma_desc_dma = 0;
++		ep->dwc_ep.usb_ep_desc = NULL;
++		ep->dwc_ep.pcd = pcd;
++		ep->dwc_ep.stopped = 1;
++		ep->dwc_ep.is_in = 1;
++		ep->dwc_ep.active = 0;
++		ep->dwc_ep.phys = ep_cntr << 1 | 1;
++#ifdef DWC_UTE
++		pcd->txf_map[ep_cntr << 1 | 1] = ep_cntr;
++#endif
++		ep->dwc_ep.tx_fifo_num = ep_cntr;
++		ep->dwc_ep.in_ep_reg = &pcd->in_ep_regs[ep_cntr];
++
++		/* Control until EP is activated */
++		ep->dwc_ep.type = DWC_USB3_EP_TYPE_CONTROL;
++		ep->dwc_ep.maxpacket = DWC_MAX_EP0_SIZE;
++		ep->dwc_ep.send_zlp = 0;
++		ep->dwc_ep.queue_sof = 0;
++	}
++
++	pcd->ep0state = EP0_IDLE;
++	pcd->ep0->dwc_ep.maxpacket = DWC_MAX_EP0_SIZE;
++	pcd->ep0->dwc_ep.type = DWC_USB3_EP_TYPE_CONTROL;
++}
++
++/**
++ * Initialize the PCD portion of the driver.
++ *
++ * This routine should be called after dwc_usb3_pcd_common_init() and any
++ * platform-specific initialization routines have been called.
++ *
++ * This routine must be called in a context that allows <em>dwc_msleep()</em>
++ * to be used, because that function is called while waiting for the core to
++ * come out of reset.
++ *
++ * @param dev   Programming view of DWC_usb3 controller.
++ */
++int dwc_usb3_pcd_init(dwc_usb3_device_t *dev)
++{
++	dwc_debug1(dev, "%s()\n", __func__);
++
++	dev->pcd.usb3_dev = dev;
++	dev->pcd.speed = USB_SPEED_UNKNOWN;
++
++	/*
++	 * Initialize EP structures
++	 */
++	pcd_epinit(&dev->pcd);
++
++	/*
++	 * Initialize the Core (also enables interrupts and sets Run/Stop bit)
++	 */
++	dwc_usb3_pcd_device_init(dev, 1, 0);
++
++	return 0;
++}
++
++/**
++ * Deinitialize the PCD portion of the driver.
++ *
++ * This routine should be called before any platform-specific deinitialization
++ * routines and dwc_usb3_pcd_common_remove() are called.
++ *
++ * @param dev   Programming view of DWC_usb3 controller.
++ */
++void dwc_usb3_pcd_remove(dwc_usb3_device_t *dev)
++{
++	dwc_debug1(dev, "%s()\n", __func__);
++
++	dwc_usb3_pcd_device_remove(dev);
++}
+diff --git a/drivers/usb/gadget/udc/hiudc3/pcd.h b/drivers/usb/gadget/udc/hiudc3/pcd.h
+new file mode 100644
+index 0000000..a71bc86
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc3/pcd.h
+@@ -0,0 +1,658 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/DWC_usb3/driver/pcd.h $
++ * $Revision: #71 $
++ * $Date: 2014/11/11 $
++ * $Change: 2664766 $
++ *
++ * Synopsys SS USB3 Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
++ * ========================================================================== */
++#ifndef _DWC_PCD_H_
++#define _DWC_PCD_H_
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/**
++ * @file
++ *
++ * This file contains the structures, constants, and interfaces for
++ * the Perpherial Contoller Driver (PCD).
++ *
++ * The Peripheral Controller Driver (PCD) for Linux will implement the
++ * Gadget API, so that the existing Gadget drivers can be used. For
++ * the Mass Storage function, the File-backed USB Storage Gadget (FBS)
++ * driver will be used. The FBS driver supports the Control-Bulk (CB),
++ * Control-Bulk-Interrupt (CBI), and Bulk-Only transports.
++ *
++ */
++
++/** Maximum number of Tx FIFOs. Depends on the RTL configuration. No way to
++ * probe the value at runtime
++ */
++#define DWC_MAX_TX_FIFOS	16
++
++/** Maximum number of physical EPs. Depends on the RTL configuration. No way to
++ * probe the value at runtime
++ */
++#define DWC_MAX_PHYS_EP		32
++
++/** Maximum number of data buffers per TRB. OS/application specific */
++#define DWC_MAX_DATA_BUFS	13
++
++/** Maximum number of EPs, defined by USB spec */
++#define DWC_MAX_EPS		16
++
++/** Maxpacket size for EP0, defined by USB3 spec */
++#define DWC_MAX_EP0_SIZE	512
++
++/** Maxpacket size for any EP, defined by USB3 spec */
++#define DWC_MAX_PACKET_SIZE	1024
++
++/**
++ * States of EP0
++ */
++typedef enum ep0_state {
++	EP0_IDLE,
++	EP0_IN_DATA_PHASE,
++	EP0_OUT_DATA_PHASE,
++	EP0_IN_WAIT_GADGET,
++	EP0_OUT_WAIT_GADGET,
++	EP0_IN_WAIT_NRDY,
++	EP0_OUT_WAIT_NRDY,
++	EP0_IN_STATUS_PHASE,
++	EP0_OUT_STATUS_PHASE,
++	EP0_STALL,
++} ep0state_e;
++
++typedef enum pcd_state {
++	DWC_STATE_UNCONNECTED,	/* no host */
++	DWC_STATE_DEFAULT,
++	DWC_STATE_ADDRESSED,
++	DWC_STATE_CONFIGURED,
++} pcdstate_e;
++
++struct dwc_usb3_device;
++struct dwc_usb3_pcd;
++
++/**
++ * The <code>dwc_req</code> structure represents the state of a single
++ * transfer request when acting in device mode. It contains the data items
++ * needed for a request to be started and completed.
++ */
++typedef struct dwc_req {
++	dwc_usb3_dma_desc_t *trb;	/**< TRB or TRB chain for this req */
++	dwc_dma_t trbdma;		/**< DMA address of TRB or TRB chain */
++	u32 length;			/**< total length of data bufs */
++	u32 actual;			/**< actual amt of data transferred */
++	u32 stream;			/**< stream # of this request */
++
++	int flags;	/**< request flags - bits 8-31 are OS-specific */
++#define DWC_PCD_REQ_ZERO	0x001
++#define DWC_PCD_REQ_STARTED	0x002
++#define DWC_PCD_REQ_MAP_DMA	0x100
++#define DWC_PCD_REQ_IN		0x200
++
++	int numbuf;				/**< number of data bufs */
++	char *buf[DWC_MAX_DATA_BUFS];		/**< data buffers */
++	dwc_dma_t bufdma[DWC_MAX_DATA_BUFS];	/**< DMA addrs of data bufs */
++	u32 buflen[DWC_MAX_DATA_BUFS];		/**< length of data bufs */
++} dwc_req_t;
++
++/** DWC_usb3 request structure.
++ * This structure is used to form a list of requests.
++ */
++typedef struct dwc_usb3_pcd_req {
++	/** DWC_usb3 request data */
++	dwc_req_t dwc_req;
++
++	/* ==== The rest is OS-specific ==== */
++
++	/** List entry for EP queue */
++#if defined(__linux__) || defined(SELA_PLATFORM)
++	struct list_head entry;
++#else
++	DWC_CIRCLEQ_ENTRY(dwc_usb3_pcd_req) entry;
++#endif
++	/** USB request */
++	struct usb_request usb_req;
++} dwc_usb3_pcd_req_t;
++
++/**
++ * The <code>dwc_ep</code> structure represents the state of a single EP
++ * when acting in device mode. It contains the data items needed for an EP
++ * to be activated and transfer packets.
++ */
++typedef struct dwc_ep {
++	/** Pointer to PCD */
++	struct dwc_usb3_pcd *pcd;
++
++	/** Pointer to OUT EP register */
++	dwc_usb3_dev_ep_regs_t __iomem *out_ep_reg;
++
++	/** Pointer to IN EP register */
++	dwc_usb3_dev_ep_regs_t __iomem *in_ep_reg;
++
++	/** Physical EP number */
++	u8 phys;
++
++	/** USB EP number */
++	u8 num;
++
++	/** EP type: 0 - Control, 1 - ISOC, 2 - BULK, 3 - INTR */
++	u8 type;
++
++	/** 'bInterval' value for Isoc EPs */
++	u8 intvl;
++
++	/** Max Packet bytes */
++	u16 maxpacket;
++
++	/** 'mult' value for SS Isoc EPs */
++	u8 mult;
++
++	/** Max burst size for SS EPs (0 - 15, actual burst is 1 - 16) */
++	u8 maxburst;
++
++	/** Number of streams for SS Bulk EPs (0 - 16, actual number is 2^n) */
++	u8 num_streams;
++
++	/** Tx FIFO # for IN EPs */
++	u8 tx_fifo_num;
++
++	/** @{ */
++	/** Transfer Resource Index from the Start Transfer command */
++	u8 tri_out;
++	u8 tri_in;
++	/** @} */
++
++	/** @{ */
++	/** Status of the queue */
++	unsigned int stopped		: 1;
++	unsigned int disabling		: 1;
++	unsigned int queue_sof		: 1;
++	/** @} */
++
++	/** @{ */
++	/** Send ZLP */
++	unsigned int send_zlp		: 1;
++
++	/** Stall clear flag */
++	unsigned int stall_clear_flag	: 1;
++
++	/** True if 3-stage control transfer */
++	unsigned int three_stage	: 1;
++
++	/** True if transfer has been started on EP */
++	unsigned int xfer_started	: 1;
++	/** @} */
++
++	/** EP direction 0 = OUT */
++	unsigned int is_in		: 1;
++
++	/** EP active */
++	unsigned int active		: 1;
++
++	/** True if TRB array has a link TRB at the end */
++	unsigned int desc_link		: 1;
++
++	/** DATA start PID for INTR and BULK EP */
++	unsigned int data_pid_start	: 1;
++
++	/** EP has been enabled for this configuration */
++	unsigned int ena_once		: 1;
++
++	/** EP was in stalled state when entering hibernation */
++	unsigned int stalled_save	: 1;
++
++	/** @{ */
++	/** Saved parameters from the last DEPCFG for this EP. Used when
++	 * resetting the sequence number
++	 */
++	u32 param0out;
++	u32 param1out;
++	u32 param0in;
++	u32 param1in;
++	/** @} */
++
++	/** EP state, saved across core hibernation */
++	u32 save_state;
++
++	/** Pointer to USB EP descriptor */
++	const usb_endpoint_descriptor_t *usb_ep_desc;
++
++	/** @{ */
++	/** Array of DMA descriptors (TRBs) for this EP */
++	dwc_usb3_dma_desc_t *dma_desc;
++	dwc_dma_t dma_desc_dma;
++	int desc_size;
++	int num_desc;
++	/** @} */
++
++	/** Number of DMA descriptors available */
++	int desc_avail;
++
++	/** Index to next free DMA descriptor in array */
++	int desc_idx;
++
++	/** Index to DMA descriptor that was active before hibernation */
++	int hiber_desc_idx;
++
++	/* ==== The rest is OS-specific ==== */
++
++	/** Condition variable for EPCMD_CMPL interrupt */
++	u32 condition;
++
++	/** Queue of dwc_usb3_pcd_reqs */
++#if defined(__linux__) || defined(SELA_PLATFORM)
++	struct list_head queue;
++#else
++	DWC_CIRCLEQ_HEAD(circleq, dwc_usb3_pcd_req) queue;
++#endif
++} dwc_ep_t;
++
++/** PCD EP structure.
++ * This structure describes an EP, there is an array of EP pointers in the
++ * PCD structure.
++ */
++typedef struct dwc_usb3_pcd_ep {
++	/** DWC_usb3 EP data */
++	dwc_ep_t dwc_ep;
++
++	/* ==== The rest is OS-specific ==== */
++
++	/** USB EP */
++	struct usb_ep usb_ep;
++} dwc_usb3_pcd_ep_t;
++
++/** @{ */
++/** PCD EP accessor functions */
++#define dwc_usb3_pcd_ep_to_pcd(pcd_ep)	((pcd_ep)->dwc_ep.pcd)
++#define dwc_usb3_pcd_ep_num(pcd_ep)	((pcd_ep)->dwc_ep.num)
++#define dwc_usb3_pcd_ep_type(pcd_ep)	((pcd_ep)->dwc_ep.type)
++#define dwc_usb3_pcd_ep_is_in(pcd_ep)	((pcd_ep)->dwc_ep.is_in)
++/** @} */
++
++struct dwc_hiber_scratchpad_array {
++	u64	dma_addr[15];
++};
++
++/** DWC_usb3 PCD Structure.
++ * This structure encapsulates the data for the dwc_usb3 PCD.
++ */
++typedef struct dwc_usb3_pcd {
++	/** The DWC otg device pointer */
++	struct dwc_usb3_device *usb3_dev;
++
++	/** USB3 link state */
++	int link_state;
++
++	/** State of the device */
++	pcdstate_e state;
++
++	/** State of EP0 */
++	ep0state_e ep0state;
++
++	/** EP0 Status Request is pending */
++	unsigned int ep0_status_pending		: 1;
++
++	/** Indicates when SET CONFIGURATION Request is in process */
++	unsigned int request_config		: 1;
++
++	/** State of the Remote Wakeup Enable */
++	unsigned int remote_wakeup_enable	: 1;
++
++	/** State of the Latency Tolerance Messaging Enable */
++	unsigned int ltm_enable			: 1;
++
++	/** True if we should send an LPM notification after the status stage */
++	unsigned int send_lpm			: 1;
++
++	/** True if ready for remote wakeup request from user */
++	unsigned int wkup_rdy			: 1;
++
++	/** True if we have enabled some EPs */
++	unsigned int eps_enabled		: 1;
++
++	/** True if UTE has made some config changes */
++	unsigned int ute_change			: 1;
++
++#ifdef DWC_STAR_9000463548_WORKAROUND
++	unsigned int configuring		: 1;
++#endif
++
++#ifdef CONFIG_USB_OTG_DWC
++	/** Set when user writes to 'hnp' sysfs attribute */
++	unsigned int wants_host			: 1;
++
++	/** For set feature (b_hnp_enable) */
++	unsigned int b_hnp_enable		: 1;
++#endif
++	/** EP0 */
++	dwc_usb3_pcd_ep_t *ep0;
++
++	/** Array of OUT EPs (not including EP0) */
++	dwc_usb3_pcd_ep_t *out_ep[DWC_MAX_EPS - 1];
++
++	/** Array of IN EPs (not including EP0) */
++	dwc_usb3_pcd_ep_t *in_ep[DWC_MAX_EPS - 1];
++
++	/** Pointer to device Global registers.
++	 * Device Global Registers starting at offset 700h
++	 */
++	dwc_usb3_dev_global_regs_t __iomem *dev_global_regs;
++
++	/** Device Logical OUT EP-Specific Registers 800h-9ECh */
++	dwc_usb3_dev_ep_regs_t __iomem *out_ep_regs;
++
++	/** Device Logical IN EP-Specific Registers 810h-9FCh */
++	dwc_usb3_dev_ep_regs_t __iomem *in_ep_regs;
++
++	/** @{ */
++	/** Scratchpad buffers for hibernation support */
++	void *hiber_scratchpad[15];
++	struct dwc_hiber_scratchpad_array *hiber_scratchpad_array;
++	dwc_dma_t hiber_scratchpad_array_dma;
++	/** @} */
++
++	/** @{ */
++	/** EP0 state, saved across core hibernation */
++	u32 ep0_out_save_state;
++	u32 ep0_in_save_state;
++	/** @} */
++
++	/** 'dummy' request, for EP0 only */
++	dwc_usb3_pcd_req_t *ep0_req;
++
++#ifdef DWC_UTE
++	/** size of Rx FIFO, requested by UTE */
++	unsigned rxf_size;
++
++	/** size of Tx FIFOs, requested by UTE */
++	unsigned txf_size[DWC_MAX_TX_FIFOS];
++
++	/** mapping of Tx FIFO for each physical EP, requested by UTE */
++	unsigned txf_map[DWC_MAX_PHYS_EP];
++
++	/** Rx FIFO default size */
++	unsigned def_rxf_size;
++
++	/** Tx FIFOs, default size */
++	unsigned def_txf_size[DWC_MAX_TX_FIFOS];
++#endif
++
++	/** @{ */
++	/** Thresholding enable flags and length variables */
++	u16 rx_thr_en;
++	u16 iso_tx_thr_en;
++	u16 non_iso_tx_thr_en;
++	u16 rx_thr_length;
++	u16 tx_thr_length;
++	/** @} */
++
++	/** Device configuration information */
++	u8 speed;	/**< Device Speed - 0:Unk 1:LS 2:FS 3:HS 4:Var 5:SS */
++	u8 num_out_eps;	/**< Number # of Rx EP range: 0-15 except ep0 */
++	u8 num_in_eps;	/**< Number # of Tx EP range: 0-15 except ep0 */
++
++	/** The TEST mode to enter when test_mode_tasklet is executed */
++	u8 test_mode;
++
++	/** Count of pending Requests */
++	unsigned request_pending;
++
++	/* ==== The rest is OS-specific ==== */
++#ifdef SELA_PLATFORM
++	/** Limit the number of EPs to speed up simulation */
++	int max_in_eps, max_out_eps;
++
++	/** Pointers for passing event codes back to the test code */
++	int *dev_event, *ep_event;
++#endif
++#if defined(__linux__) || defined(LINUXTEST)
++	/** The spinlock for the PCD */
++	spinlock_t lock;
++#endif
++#ifdef __linux__
++	/** The associated gadget */
++	struct usb_gadget *gadget;
++#endif
++	/** Tasklet to defer starting of TEST mode transmissions until
++	 * Status Phase has been completed
++	 */
++	struct tasklet_struct test_mode_tasklet;
++
++	/**
++	 * Pointers to the DMA Descriptors for EP0 Control transfers
++	 * (virtual and physical)
++	 */
++
++	/** @{ */
++	/** Descriptor for SETUP packets */
++	dwc_usb3_dma_desc_t *ep0_setup_desc;
++	dwc_dma_t ep0_setup_desc_dma;
++	/** @} */
++
++	/** @{ */
++	/** Descriptor for Data Out or Status Out phases */
++	dwc_usb3_dma_desc_t *ep0_out_desc;
++	dwc_dma_t ep0_out_desc_dma;
++	/** @} */
++
++	/** @{ */
++	/** Descriptor for Data In or Status In phases */
++	dwc_usb3_dma_desc_t *ep0_in_desc;
++	dwc_dma_t ep0_in_desc_dma;
++	/** @} */
++
++	/** @{ */
++	/** Data packet buffer used to return data for GET_STATUS and
++	 *  GET_DESCRIPTOR(BOS) up to 512 bytes in length
++	 */
++	u8 *ep0_status_buf;
++	dwc_dma_t ep0_status_buf_dma;
++#define DWC_STATUS_BUF_SIZE 512
++	/** @} */
++
++	/** @{ */
++	/** SETUP packet buffer for EP0 */
++	union dwc_setup_pkt {
++		usb_device_request_t req;
++		u32 d32[2];
++		char d8[8];
++	} *ep0_setup_pkt;
++	dwc_dma_t ep0_setup_pkt_dma;
++	/** @} */
++} dwc_usb3_pcd_t;
++
++/** @{ */
++/** PCD accessor functions */
++#define dwc_usb3_ep0_setup_desc(pcd)		(pcd)->ep0_setup_desc
++#define dwc_usb3_ep0_setup_desc_dma(pcd)	(pcd)->ep0_setup_desc_dma
++#define dwc_usb3_ep0_out_desc(pcd)		(pcd)->ep0_out_desc
++#define dwc_usb3_ep0_out_desc_dma(pcd)		(pcd)->ep0_out_desc_dma
++#define dwc_usb3_ep0_in_desc(pcd)		(pcd)->ep0_in_desc
++#define dwc_usb3_ep0_in_desc_dma(pcd)		(pcd)->ep0_in_desc_dma
++#define dwc_usb3_ep0_setup_pkt(pcd)		(pcd)->ep0_setup_pkt
++#define dwc_usb3_ep0_setup_pkt_dma(pcd)		(pcd)->ep0_setup_pkt_dma
++/** @} */
++
++extern void dwc_usb3_ep0_activate(dwc_usb3_pcd_t *pcd, int restore);
++extern void dwc_usb3_ep_activate(dwc_usb3_pcd_t *pcd, dwc_usb3_pcd_ep_t *ep,
++				 int restore);
++extern void dwc_usb3_stop_all_xfers(dwc_usb3_pcd_t *pcd);
++extern void dwc_usb3_complete_request(dwc_usb3_pcd_t *pcd,
++				      dwc_usb3_pcd_ep_t *ep, u32 event);
++extern dwc_usb3_pcd_ep_t *dwc_usb3_get_out_ep(dwc_usb3_pcd_t *pcd, u32 ep_num);
++extern dwc_usb3_pcd_ep_t *dwc_usb3_get_in_ep(dwc_usb3_pcd_t *pcd, u32 ep_num);
++extern void dwc_usb3_handle_ep0_xfer(dwc_usb3_pcd_t *pcd, u32 event);
++#ifdef DEBUG_EP0
++extern void dwc_usb3_print_ep0_state(dwc_usb3_pcd_t *pcd);
++#endif
++extern void dwc_usb3_handle_ep_intr(dwc_usb3_pcd_t *pcd, int physep, u32 event);
++extern int dwc_usb3_handle_dev_intr(dwc_usb3_pcd_t *pcd, u32 event);
++extern void dwc_usb3_handle_connect_done_intr(dwc_usb3_pcd_t *pcd);
++extern void dwc_enter_hibernation(dwc_usb3_pcd_t *pcd, int save_state);
++extern void dwc_exit_hibernation_after_connect(dwc_usb3_pcd_t *pcd,
++					       int connected);
++extern int dwc_exit_hibernation(dwc_usb3_pcd_t *pcd, int restore_state);
++extern int dwc_usb3_handle_pme_intr(struct dwc_usb3_device *dev);
++extern void dwc_usb3_power_ctl(struct dwc_usb3_device *dev, int on);
++
++/** @addtogroup init_api_grp */
++/** @{ */
++extern int dwc_usb3_pcd_init(struct dwc_usb3_device *dev);
++extern void dwc_usb3_pcd_remove(struct dwc_usb3_device *dev);
++/** @} */
++
++/** @addtogroup trb_api_grp TRB API Routines
++ *
++ * These routines handle the allocation, deallocation, and setup of TRBs.
++ */
++/** @{ */
++extern dwc_usb3_dma_desc_t *dwc_usb3_pcd_trb_alloc(dwc_usb3_pcd_ep_t *ep,
++		int num_trbs, int trb_type, int iso_intvl, int link,
++		dwc_dma_t *trbs_dma_ret);
++extern void dwc_usb3_pcd_trb_free(dwc_usb3_pcd_ep_t *ep /*, int num_trbs, int link,
++				  void *trbs, dwc_dma_t trbs_dma*/);
++extern void dwc_usb3_pcd_fill_trbs(dwc_usb3_pcd_t *pcd, dwc_usb3_pcd_ep_t *ep,
++				   dwc_usb3_pcd_req_t *req);
++/** @} */
++
++/** @addtogroup ep_api_grp Endpoint API Routines
++ *
++ * These routines handle all the functionality required for configuring,
++ * enabling, controlling, and submitting transfers to an endpoint\n\n
++ * Note: For Control endpoint 0, only the submit_req, cancel_req, request_done,
++ * and set_halt routines are used; the remaining functionality is handled either
++ * by the @ref ep0_api_grp below or internally by the PCD.
++ */
++/** @{ */
++extern int dwc_usb3_pcd_ep_enable(dwc_usb3_pcd_t *pcd, dwc_usb3_pcd_ep_t *ep,
++			const usb_endpoint_descriptor_t *ep_desc,
++			const ss_endpoint_companion_descriptor_t *ep_comp);
++extern int dwc_usb3_pcd_ep_disable(dwc_usb3_pcd_t *pcd, dwc_usb3_pcd_ep_t *ep);
++extern int dwc_usb3_pcd_ep_submit_req(dwc_usb3_pcd_t *pcd,
++				      dwc_usb3_pcd_ep_t *ep,
++				      dwc_usb3_pcd_req_t *req, int req_flags);
++extern void dwc_usb3_pcd_ep_cancel_req(dwc_usb3_pcd_t *pcd,
++				       dwc_usb3_pcd_ep_t *ep,
++				       dwc_usb3_pcd_req_t *req, u32 stream);
++extern void dwc_usb3_pcd_request_done(dwc_usb3_pcd_t *pcd,
++				      dwc_usb3_pcd_ep_t *ep,
++				      dwc_usb3_pcd_req_t *req, int status);
++extern void dwc_usb3_pcd_ep_start_transfer(dwc_usb3_pcd_t *pcd,
++					   dwc_usb3_pcd_ep_t *ep,
++					   dwc_usb3_pcd_req_t *req, u32 event);
++extern void dwc_usb3_pcd_ep_set_stall(dwc_usb3_pcd_t *pcd,
++				      dwc_usb3_pcd_ep_t *ep);
++extern void dwc_usb3_pcd_ep_clear_stall(dwc_usb3_pcd_t *pcd,
++					dwc_usb3_pcd_ep_t *ep);
++extern void dwc_usb3_pcd_ep_set_halt(dwc_usb3_pcd_t *pcd, dwc_usb3_pcd_ep_t *ep,
++				     int value);
++/** @} */
++
++/** @addtogroup ep0_api_grp Control Endpoint 0 API Routines
++ *
++ * These routines are only used for Control endpoint 0.
++ */
++/** @{ */
++extern void dwc_usb3_pcd_do_setup(dwc_usb3_pcd_t *pcd);
++extern void dwc_usb3_pcd_ep0_out_start(dwc_usb3_pcd_t *pcd);
++extern void dwc_usb3_pcd_ep0_start_transfer(dwc_usb3_pcd_t *pcd,
++					    dwc_usb3_pcd_req_t *req);
++extern void dwc_usb3_pcd_ep0_continue_transfer(dwc_usb3_pcd_t *pcd,
++					       dwc_usb3_pcd_req_t *req);
++extern void dwc_usb3_pcd_ep0_data_stage(dwc_usb3_pcd_t *pcd, int length);
++/** @} */
++
++/** @addtogroup misc_api_grp Miscellaneous API Routines
++ *
++ * These are miscellaneous routines that don't fit into any of the other
++ * categories.
++ */
++/** @{ */
++extern dwc_usb3_pcd_ep_t *dwc_usb3_pcd_get_ep_by_addr(dwc_usb3_pcd_t *pcd,
++						      u16 index);
++extern int dwc_usb3_pcd_get_frame_number(dwc_usb3_pcd_t *pcd);
++extern int dwc_usb3_pcd_isoc_ep_hiber_restart(dwc_usb3_pcd_t *pcd,
++					      dwc_usb3_pcd_ep_t *ep);
++extern void dwc_usb3_pcd_stop(dwc_usb3_pcd_t *pcd);
++/** @} */
++
++/** @addtogroup gadget_notif_grp Function Driver notification routines
++ *
++ * These routines receive notifications from the PCD when certain events occur
++ * which the Function Driver may need to be aware of.
++ */
++/** @{ */
++extern int dwc_usb3_gadget_connect(dwc_usb3_pcd_t *pcd, int speed);
++extern int dwc_usb3_gadget_disconnect(dwc_usb3_pcd_t *pcd);
++extern int dwc_usb3_gadget_suspend(dwc_usb3_pcd_t *pcd);
++extern int dwc_usb3_gadget_resume(dwc_usb3_pcd_t *pcd);
++extern int dwc_usb3_gadget_setup(dwc_usb3_pcd_t *pcd,
++				 usb_device_request_t *ctrl);
++extern int dwc_usb3_gadget_complete(dwc_usb3_pcd_t *pcd, dwc_usb3_pcd_ep_t *ep,
++				    dwc_usb3_pcd_req_t *pcd_req, int status);
++extern void dwc_usb3_gadget_do_setup(dwc_usb3_pcd_t *pcd);
++/** @} */
++
++/** @addtogroup gadget_callbk_grp Function Driver callback routines
++ *
++ * The PCD calls these routines when it needs something from the Function
++ * Driver.
++ */
++/** @{ */
++extern void *dwc_usb3_gadget_alloc_dma(dwc_usb3_pcd_ep_t *ep, int size,
++				       dwc_dma_t *mem_dma_ret);
++extern void dwc_usb3_gadget_free_dma(dwc_usb3_pcd_ep_t *ep, int size, void *mem,
++				     dwc_dma_t mem_dma);
++extern dwc_usb3_pcd_req_t *dwc_usb3_gadget_get_request(dwc_usb3_pcd_t *pcd,
++						       dwc_usb3_pcd_ep_t *ep);
++extern void dwc_usb3_gadget_start_next_request(dwc_usb3_pcd_t *pcd,
++					       dwc_usb3_pcd_ep_t *ep);
++extern void dwc_usb3_gadget_isoc_ep_start(dwc_usb3_pcd_t *pcd,
++					  dwc_usb3_pcd_ep_t *ep, u32 event);
++extern void dwc_usb3_gadget_request_nuke(dwc_usb3_pcd_t *pcd,
++					 dwc_usb3_pcd_ep_t *ep);
++extern void dwc_usb3_gadget_set_ep_not_started(dwc_usb3_pcd_t *pcd,
++					       dwc_usb3_pcd_ep_t *ep);
++/** @} */
++
++/* OS-specific routines called from core code */
++extern void dwc_usb3_task_schedule(struct tasklet_struct *tasklet);
++
++#ifdef CONFIG_USB_OTG_DWC
++extern void dwc_usb3_start_hnp(dwc_usb3_pcd_t *pcd);
++extern void dwc_usb3_host_release(dwc_usb3_pcd_t *pcd);
++#endif
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* _DWC_PCD_H_ */
+diff --git a/drivers/usb/gadget/udc/hiudc3/pcd_hiber.c b/drivers/usb/gadget/udc/hiudc3/pcd_hiber.c
+new file mode 100644
+index 0000000..d401ef1
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc3/pcd_hiber.c
+@@ -0,0 +1,679 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/DWC_usb3/driver/pcd_hiber.c $
++ * $Revision: #16 $
++ * $Date: 2014/11/11 $
++ * $Change: 2664766 $
++ *
++ * Synopsys SS USB3 Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
++ * ========================================================================== */
++
++/** @file
++ * This file contains the PCD hibernation code.
++ */
++
++#include "os_defs.h"
++#include "hw.h"
++#include "usb.h"
++#include "pcd.h"
++#include "dev.h"
++#include "os_dev.h"
++#include "cil.h"
++
++/**
++ * This routine sends the core into hibernation, saving the core's runtime
++ * state if requested.
++ */
++void dwc_enter_hibernation(dwc_usb3_pcd_t *pcd, int save_state)
++{
++	dwc_usb3_device_t *dev = pcd->usb3_dev;
++	dwc_usb3_dev_ep_regs_t __iomem *ep_reg;
++	dwc_usb3_pcd_ep_t *ep;
++	int num_in_eps, num_out_eps, i;
++	u32 temp;
++
++	dwc_debug2(dev, "%s(%d)\n", __func__, save_state);
++	num_in_eps = pcd->num_in_eps;
++	num_out_eps = pcd->num_out_eps;
++
++	dev->hiber_wait_u0 = 0;
++	dwc_usb3_dis_usb2_suspend(pcd);
++
++	/* Issue an "End Transfer" command for all active transfers with the
++	 * ForceRM field set to 0, including the default control endpoint 0.
++	 */
++	ep = pcd->ep0;
++	if (ep->dwc_ep.active) {
++		if (ep->dwc_ep.tri_in) {
++			dwc_debug0(dev, "EndXfer on phys EP1 (IN)\n");
++			ep_reg = ep->dwc_ep.in_ep_reg;
++			ep->dwc_ep.condition = 0;
++			dwc_usb3_dep_endxfer(pcd, ep_reg, ep->dwc_ep.tri_in - 1,
++					     0, &ep->dwc_ep.condition);
++			ep->dwc_ep.tri_in = 0;
++		}
++
++		if (ep->dwc_ep.tri_out) {
++			dwc_debug0(dev, "EndXfer on phys EP0 (OUT)\n");
++			ep_reg = ep->dwc_ep.out_ep_reg;
++			ep->dwc_ep.condition = 0;
++			dwc_usb3_dep_endxfer(pcd, ep_reg, ep->dwc_ep.tri_out - 1,
++					     0, &ep->dwc_ep.condition);
++			ep->dwc_ep.tri_out = 0;
++		}
++	}
++
++	for (i = 0; i < num_in_eps; i++) {
++		ep = pcd->in_ep[i];
++		if (ep->dwc_ep.active && ep->dwc_ep.tri_in) {
++			dwc_debug1(dev, "EndXfer on phys EP%d (IN)\n",
++				   i * 2 + 3);
++			ep_reg = ep->dwc_ep.in_ep_reg;
++			ep->dwc_ep.condition = 0;
++			dwc_usb3_dep_endxfer(pcd, ep_reg, ep->dwc_ep.tri_in - 1,
++					     0, &ep->dwc_ep.condition);
++			ep->dwc_ep.tri_in = 0;
++		}
++		ep->dwc_ep.xfer_started = 0;
++	}
++
++	for (i = 0; i < num_out_eps; i++) {
++		ep = pcd->out_ep[i];
++		if (ep->dwc_ep.active && ep->dwc_ep.tri_out) {
++			dwc_debug1(dev, "EndXfer on phys EP%d (OUT)\n",
++				   i * 2 + 2);
++			ep_reg = ep->dwc_ep.out_ep_reg;
++			ep->dwc_ep.condition = 0;
++			dwc_usb3_dep_endxfer(pcd, ep_reg, ep->dwc_ep.tri_out - 1,
++					     0, &ep->dwc_ep.condition);
++			ep->dwc_ep.tri_out = 0;
++		}
++		ep->dwc_ep.xfer_started = 0;
++	}
++
++	if (save_state) {
++		dwc_debug0(dev, "Saving state - 1\n");
++
++		/* Issue a "Get Endpoint State" endpoint command for each active
++		 * endpoint, and save the bits that are returned for use after
++		 * coming out of hibernation.
++		 *
++		 * In addition, software must remember if the endpoint is
++		 * currently in a Halted state. The endpoint is in a Halted
++		 * state if software has issued a "Set STALL" command and has
++		 * not issued a "Clear STALL" command.
++		 */
++		ep = pcd->ep0;
++		if (ep->dwc_ep.active) {
++			dwc_debug0(dev, "Saving state of phys EP1 (IN)\n");
++			ep_reg = ep->dwc_ep.in_ep_reg;
++			pcd->ep0_in_save_state =
++				dwc_usb3_dep_getepstate(pcd, ep_reg);
++			dwc_debug1(dev, "IN save state=%08x\n",
++				   pcd->ep0_in_save_state);
++			dwc_debug0(dev, "Saving state of phys EP0 (OUT)\n");
++			ep_reg = ep->dwc_ep.out_ep_reg;
++			pcd->ep0_out_save_state =
++				dwc_usb3_dep_getepstate(pcd, ep_reg);
++			dwc_debug1(dev, "OUT save state=%08x\n",
++				   pcd->ep0_out_save_state);
++			ep->dwc_ep.stalled_save = ep->dwc_ep.stopped;
++		}
++
++		for (i = 0; i < num_in_eps; i++) {
++			ep = pcd->in_ep[i];
++			if (ep->dwc_ep.active) {
++				dwc_debug1(dev,
++					   "Saving state of phys EP%d (IN)\n",
++					   i * 2 + 3);
++				ep_reg = ep->dwc_ep.in_ep_reg;
++				ep->dwc_ep.save_state =
++					dwc_usb3_dep_getepstate(pcd, ep_reg);
++				ep->dwc_ep.stalled_save = ep->dwc_ep.stopped;
++			}
++		}
++
++		for (i = 0; i < num_out_eps; i++) {
++			ep = pcd->out_ep[i];
++			if (ep->dwc_ep.active) {
++				dwc_debug1(dev,
++					   "Saving state of phys EP%d (OUT)\n",
++					   i * 2 + 2);
++				ep_reg = ep->dwc_ep.out_ep_reg;
++				ep->dwc_ep.save_state =
++					dwc_usb3_dep_getepstate(pcd, ep_reg);
++				ep->dwc_ep.stalled_save = ep->dwc_ep.stopped;
++			}
++		}
++	} else {
++		pcd->ep0state = EP0_IDLE;
++	}
++
++	dwc_usb3_ena_usb2_suspend(pcd);
++	dev->hibernate = DWC_HIBER_SLEEPING;
++
++	/* Set DCTL.RunStop to 0, DCTL.KeepConnect to 1 (or 0 if disconnected),
++	 * and wait for DSTS.Halted to be set to 1. Software must service any
++	 * events that are generated while it is waiting for Halted to be set
++	 * to 1.
++	 */
++	temp = dwc_rd32(dev, &pcd->dev_global_regs->dctl);
++	temp &= ~DWC_DCTL_RUN_STOP_BIT;
++	if (!save_state)
++		temp &= ~DWC_DCTL_KEEP_CONNECT_BIT;
++	dwc_wr32(dev, &pcd->dev_global_regs->dctl, temp);
++
++	dwc_debug0(dev, "Cleared Run/Stop bit, waiting for Halt bit\n");
++	i = 25000;
++	do {
++		if (!dwc_usb3_handle_event(dev))
++			dwc_udelay(dev, 1);
++		temp = dwc_rd32(dev, &pcd->dev_global_regs->dsts);
++		if (--i == 0) {
++			/* If there is data stuck in the Rx FIFO, then the
++			 * controller will never set the DevCtrlHlt bit. To
++			 * handle that case, after about 25ms flush any data
++			 * that remains in the Rx FIFO.
++			 */
++			if (!(temp & DWC_DSTS_RXFIFO_EMPTY_BIT))
++				dwc_usb3_flush_fifo(pcd, 0); // 0 = Rx FIFO
++		}
++	} while (!(temp & DWC_DSTS_DEV_CTRL_HLT_BIT));
++
++	/* Unconditionally save GUCTL/GUCTL1 */
++	dev->guctl_save = dwc_rd32(dev, &dev->core_global_regs->guctl);
++	dev->guctl1_save = dwc_rd32(dev, &dev->core_global_regs->guctl1);
++
++	if (save_state) {
++		dwc_debug0(dev, "Saving state - 2\n");
++
++		/* Read the D* registers (DCTL, DCFG, DEVTEN) and G* registers
++		 * (GSBUSCFG0/1, GCTL, GTXTHRCFG, GRXTHRCFG, GTXFIFOSIZn,
++		 * GRXFIFOSIZ0, GUSB3PIPECTL0, GUSB2PHYCFG0) and save their
++		 * state.
++		 */
++		dev->dcfg_save = dwc_rd32(dev, &pcd->dev_global_regs->dcfg);
++		dwc_debug1(dev, "DCFG=%08x\n", dev->dcfg_save);
++		dev->dctl_save = dwc_rd32(dev, &pcd->dev_global_regs->dctl);
++		dev->gtxfifosiz0_save =
++			dwc_rd32(dev, &dev->core_global_regs->gtxfifosiz[0]);
++		dev->gtxfifosiz1_save =
++			dwc_rd32(dev, &dev->core_global_regs->gtxfifosiz[1]);
++		dev->gtxfifosiz2_save =
++			dwc_rd32(dev, &dev->core_global_regs->gtxfifosiz[2]);
++		dev->gtxfifosiz3_save =
++			dwc_rd32(dev, &dev->core_global_regs->gtxfifosiz[3]);
++		dev->grxfifosiz0_save =
++			dwc_rd32(dev, &dev->core_global_regs->grxfifosiz[0]);
++		dwc_usb3_set_scratchpad_buf_array(pcd,
++					pcd->hiber_scratchpad_array_dma);
++
++		/* Set the DCTL.CSS bit and wait for the save state process to
++		 * complete by polling for DSTS.SSS to equal 0.
++		 */
++		temp = dwc_rd32(dev, &pcd->dev_global_regs->dsts);
++		dwc_debug1(dev, "DSTS before=%1x\n", temp);
++		temp = dwc_rd32(dev, &pcd->dev_global_regs->dctl);
++		dwc_debug1(dev, "DCTL before=%1x\n", temp);
++		temp |= DWC_DCTL_CSS_BIT;
++		dwc_wr32(dev, &pcd->dev_global_regs->dctl, temp);
++		temp = dwc_rd32(dev, &pcd->dev_global_regs->dctl);
++		dwc_debug1(dev, "DCTL after=%1x\n", temp);
++
++		dwc_debug0(dev, "Set CSS bit, waiting for SSS bit clear\n");
++		do {
++			dwc_udelay(dev, 1);
++			temp = dwc_rd32(dev, &pcd->dev_global_regs->dsts);
++		} while (temp & DWC_DSTS_SSS_BIT);
++		dwc_debug1(dev, "DSTS after=%1x\n", temp);
++#if 0
++		/* If the save failed, the DSTS.SRE field will indicate an
++		 * error.
++		 */
++		if (temp & DWC_DSTS_SRE_BIT) {
++			dwc_error0(dev, "### Save state failed! ###\n");
++
++			/* What should we do here ?? */
++			return;
++		}
++#endif
++	}
++
++	/* Communicate with the power controller to set the power state to D3 */
++	dwc_usb3_power_ctl(dev, 0);
++	dev->pme_ready = 1;
++
++	dwc_info0(dev, "In D3\n");
++
++	/* Remove core well power */
++	// This is "faked" by the FPGA
++}
++
++/**
++ * This routine restarts any transfer that was in progress on an EP when the
++ * core entered hibernation.
++ */
++static void dwc_reenable_xfer_and_restart(dwc_usb3_pcd_t *pcd,
++					  dwc_usb3_pcd_ep_t *ep)
++{
++	dwc_usb3_dev_ep_regs_t __iomem *ep_reg;
++	dwc_usb3_dma_desc_t *desc;
++	dwc_dma_t desc_dma;
++	u8 *tri;
++	int i, owned;
++
++	dwc_debug1(pcd->usb3_dev, "%s()\n", __func__);
++	dwc_debug2(pcd->usb3_dev, "phys EP%d-%s\n", ep->dwc_ep.phys,
++		   ep->dwc_ep.is_in ? "IN" : "OUT");
++	desc = ep->dwc_ep.dma_desc;
++
++	/* Find the first non-hw-owned TRB */
++	for (i = 0; i < ep->dwc_ep.num_desc; i++, desc++) {
++		if (!dwc_usb3_is_hwo(desc) &&
++		    !(dwc_usb3_get_xfersts(desc) & DWC_TRBRSP_XFER_IN_PROG)) {
++			dwc_debug1(pcd->usb3_dev,
++				   "Found non-hw-owned TRB at %d\n", i);
++			break;
++		}
++	}
++
++	if (i == ep->dwc_ep.num_desc)
++		desc = ep->dwc_ep.dma_desc;
++
++	/* Find the first hw-owned TRB */
++	for (i = 0, owned = -1; i < ep->dwc_ep.num_desc; i++) {
++		/* If status == 4, this TRB's xfer was in progress prior to
++		 * entering hibernation
++		 */
++		if (dwc_usb3_get_xfersts(desc) & DWC_TRBRSP_XFER_IN_PROG) {
++			dwc_debug1(pcd->usb3_dev,
++				   "Found in-progress TRB at %d\n", i);
++
++			/* Set HWO back to 1 so the xfer can continue */
++			desc->control |= DWC_DSCCTL_HWO_BIT;
++			owned = i;
++			break;
++		}
++
++		/* Save the index of the first TRB with the HWO bit set */
++		if (dwc_usb3_is_hwo(desc)) {
++			dwc_debug1(pcd->usb3_dev, "Found hw-owned TRB at %d\n",
++				   i);
++
++			owned = i;
++			break;
++		}
++
++		desc++;
++		if (desc == ep->dwc_ep.dma_desc + ep->dwc_ep.num_desc)
++			desc = ep->dwc_ep.dma_desc;
++	}
++
++	wmb();
++	ep->dwc_ep.hiber_desc_idx = 0;
++
++	if (owned < 0)
++		/* No TRB had HWO bit set, fine */
++		return;
++
++	dwc_debug1(pcd->usb3_dev, "desc=%08lx\n", (unsigned long)desc);
++
++	/* Restart of Isoc EPs is deferred until the host polls the EP */
++	if (ep->dwc_ep.type == UE_ISOCHRONOUS) {
++		dwc_debug0(pcd->usb3_dev,
++			   "Deferring restart until host polls\n");
++		ep->dwc_ep.hiber_desc_idx = owned + 1;
++		return;
++	}
++
++#ifdef VERBOSE
++	dwc_debug4(pcd->usb3_dev, "%08x %08x %08x %08x\n",
++		   *((unsigned *)desc), *((unsigned *)desc + 1),
++		   *((unsigned *)desc + 2), *((unsigned *)desc + 3));
++#endif
++	/* Now restart at the first TRB found with HWO set */
++	if (ep->dwc_ep.is_in) {
++		ep_reg = ep->dwc_ep.in_ep_reg;
++		tri = &ep->dwc_ep.tri_in;
++	} else {
++		ep_reg = ep->dwc_ep.out_ep_reg;
++		tri = &ep->dwc_ep.tri_out;
++	}
++
++	dwc_debug0(pcd->usb3_dev, "Restarting xfer\n");
++	desc = ep->dwc_ep.dma_desc + owned;
++	desc_dma = (dwc_dma_t)
++		((unsigned long)ep->dwc_ep.dma_desc_dma + owned * 16);
++	dwc_debug1(pcd->usb3_dev, "desc=%08lx\n", (unsigned long)desc);
++
++#ifdef VERBOSE
++	dwc_debug5(pcd->usb3_dev, "%08x %08x %08x %08x (%08x)\n",
++		   *((unsigned *)desc), *((unsigned *)desc + 1),
++		   *((unsigned *)desc + 2), *((unsigned *)desc + 3),
++		   (unsigned)desc_dma);
++#endif
++
++	dwc_usb3_dis_usb2_suspend(pcd);
++	*tri = dwc_usb3_dep_startxfer(pcd, ep_reg, desc_dma, 0) + 1;
++	dwc_usb3_ena_usb2_suspend(pcd);
++}
++
++/**
++ * This routine finishes exiting from hibernation once the device is connected.
++ */
++void dwc_exit_hibernation_after_connect(dwc_usb3_pcd_t *pcd, int connected)
++{
++	dwc_usb3_pcd_ep_t *ep;
++	int num_in_eps, num_out_eps, i;
++	u32 temp;
++
++	dwc_debug2(pcd->usb3_dev, "%s(%d)\n", __func__, connected);
++
++	/* Perform the steps in Section 9.1.5 "Initialization on
++	 * SetConfiguration or SetInterface Command" in [DWSS].
++	 *
++	 * While issuing the DEPCFG commands, set each endpoint's sequence
++	 * number and flow control state to the value read during the save.
++	 *
++	 * If the endpoint was in the Halted state prior to entering
++	 * hibernation, software must issue the "Set STALL" endpoint command
++	 * to put the endpoint back into the Halted state.
++	 */
++	num_in_eps = pcd->num_in_eps;
++	num_out_eps = pcd->num_out_eps;
++
++	pcd->eps_enabled = 0;
++
++	ep = pcd->ep0;
++	if (ep->dwc_ep.active)
++		/* Setting STALL on EP0 caused problems */
++		ep->dwc_ep.stalled_save = 0;
++
++	for (i = 0; i < num_in_eps; i++) {
++		ep = pcd->in_ep[i];
++		if (ep->dwc_ep.active) {
++			ep->dwc_ep.ena_once = 0;
++			dwc_debug1(pcd->usb3_dev, "Activating phys EP%d (IN)\n",
++				   i * 2 + 3);
++			dwc_usb3_ep_activate(pcd, ep, 1);
++			if (ep->dwc_ep.stalled_save) {
++				ep->dwc_ep.stalled_save = 0;
++				dwc_debug1(pcd->usb3_dev,
++					   "Stalling phys EP%d (IN)\n",
++					   i * 2 + 3);
++				dwc_usb3_pcd_ep_set_stall(pcd, ep);
++				ep->dwc_ep.stopped = 1;
++			}
++		}
++	}
++
++	for (i = 0; i < num_out_eps; i++) {
++		ep = pcd->out_ep[i];
++		if (ep->dwc_ep.active) {
++			ep->dwc_ep.ena_once = 0;
++			dwc_debug1(pcd->usb3_dev,
++				   "Activating phys EP%d (OUT)\n", i * 2 + 2);
++			dwc_usb3_ep_activate(pcd, ep, 1);
++			if (ep->dwc_ep.stalled_save) {
++				ep->dwc_ep.stalled_save = 0;
++				dwc_debug1(pcd->usb3_dev,
++					   "Stalling phys EP%d (OUT)\n",
++					   i * 2 + 2);
++				dwc_usb3_pcd_ep_set_stall(pcd, ep);
++				ep->dwc_ep.stopped = 1;
++			}
++		}
++	}
++
++	/* (In this step, software re-configures the existing endpoints and
++	 * starts their transfers).
++	 *
++	 * When software issued the EndXfer command with the ForceRM field set
++	 * to '0' prior to entering hibernation, the core may have written back
++	 * an active TRB for the transfer, setting the HWO bit to '0'. Software
++	 * must ensure that the TRB is valid and set the HWO bit back to '1'
++	 * prior to re-starting the transfer in this step.
++	 */
++	for (i = 0; i < num_in_eps; i++) {
++		ep = pcd->in_ep[i];
++		if (ep->dwc_ep.active) {
++			dwc_debug1(pcd->usb3_dev,
++				   "Restarting xfer on phys EP%d (IN)\n",
++				   i * 2 + 3);
++			dwc_reenable_xfer_and_restart(pcd, ep);
++		}
++	}
++
++	for (i = 0; i < num_out_eps; i++) {
++		ep = pcd->out_ep[i];
++		if (ep->dwc_ep.active) {
++			dwc_debug1(pcd->usb3_dev,
++				   "Restarting xfer on phys EP%d (OUT)\n",
++				   i * 2 + 2);
++			dwc_reenable_xfer_and_restart(pcd, ep);
++		}
++	}
++
++	/* If the core is already connected to the host (DSTS.USBLnkSt == 0, 2,
++	 * 3, 14, or 15), set DCTL.ULStChngReq to '8' as described in Table 7-47
++	 * of [DWSS].
++	 *
++	 * If the host initiated resume, this step completes the transition to
++	 * U0. If the host did not initiate resume, this step causes the device
++	 * to initiate resume (remote wakeup).
++	 */
++	if (connected) {
++		dwc_debug0(pcd->usb3_dev, "Already connected,"
++			   " requesting link state Recovery\n");
++		dwc_usb3_pcd_set_link_state(pcd, DWC_LINK_STATE_REQ_RECOVERY);
++		//dwc_udelay(pcd->usb3_dev, 1);
++		//dwc_usb3_pcd_set_link_state(pcd, 0);
++		pcd->usb3_dev->hiber_wait_u0 = 1;
++		pcd->usb3_dev->hibernate = DWC_HIBER_WAIT_U0;
++		temp = dwc_usb3_pcd_get_link_state(pcd);
++		dwc_debug1(pcd->usb3_dev, "Link state %d\n", temp);
++		pcd->link_state = temp;
++	} else {
++		pcd->usb3_dev->hiber_wait_u0 = 0;
++	}
++}
++
++/**
++ * This routine wakes the core from hibernation.
++ */
++int dwc_exit_hibernation(dwc_usb3_pcd_t *pcd, int restore_state)
++{
++	dwc_usb3_device_t *dev = pcd->usb3_dev;
++	u32 temp;
++
++	dwc_debug2(dev, "%s(%d)\n", __func__, restore_state);
++
++	/* Enable core well power */
++	// This is "faked" by the FPGA
++
++	/* Communicate with the power controller to set the power state to D0 */
++	dwc_usb3_power_ctl(dev, 1);
++	dev->pme_ready = 0;
++
++	dwc_info0(dev, "In D0\n");
++	dev->hibernate = DWC_HIBER_AWAKE;
++
++	/* Unconditionally restore GUCTL/GUCTL1 */
++	dwc_wr32(dev, &dev->core_global_regs->guctl, dev->guctl_save);
++	dwc_wr32(dev, &dev->core_global_regs->guctl1, dev->guctl1_save);
++
++	/* If the reset value of GSBUSCFG0/1 is not correct, write these
++	 * registers with the desired values.
++	 */
++	if (dev->program_gsbuscfg) {
++		dwc_wr32(dev, &dev->core_global_regs->gsbuscfg0,
++			 dev->gsbuscfg0);
++		dwc_wr32(dev, &dev->core_global_regs->gsbuscfg1,
++			 dev->gsbuscfg1);
++	}
++
++	if (restore_state) {
++		dwc_debug0(dev, "Restoring state\n");
++
++		/* Issue a "Set Scratchpad Buffer Array" device generic command
++		 * and wait for completion by polling the DGCMD.CmdAct bit.
++		 */
++		dwc_usb3_set_scratchpad_buf_array(pcd,
++					pcd->hiber_scratchpad_array_dma);
++
++		/* Write '1' to DCTL.CRS to start the restore process and wait
++		 * for completion by polling the DSTS.RSS bit.
++		 */
++		temp = dwc_rd32(dev, &pcd->dev_global_regs->dsts);
++		dwc_debug1(dev, "DSTS before=%1x\n", temp);
++		temp = dwc_rd32(dev, &pcd->dev_global_regs->dctl);
++		dwc_debug1(dev, "DCTL before=%1x\n", temp);
++		temp |= DWC_DCTL_CRS_BIT;
++		dwc_wr32(dev, &pcd->dev_global_regs->dctl, temp);
++		temp = dwc_rd32(dev, &pcd->dev_global_regs->dctl);
++		dwc_debug1(dev, "DCTL after=%1x\n", temp);
++
++		dwc_debug0(dev, "Set CRS bit, waiting for RSS bit clear\n");
++		do {
++			dwc_udelay(dev, 1);
++			temp = dwc_rd32(dev, &pcd->dev_global_regs->dsts);
++		} while (temp & DWC_DSTS_RSS_BIT);
++		dwc_debug1(dev, "DSTS after=%1x\n", temp);
++#if 0
++		/* If the restore failed, the DSTS.SRE field will indicate an
++		 * error.
++		 */
++		if (temp & DWC_DSTS_SRE_BIT) {
++			dwc_error0(dev, "### Restore state failed! ###\n");
++
++			/* What should we do here ?? */
++			return 1;
++		}
++#endif
++		/* (Restore the remaining D* and G* registers) */
++		dwc_wr32(dev, &pcd->dev_global_regs->dcfg, dev->dcfg_save);
++		dwc_debug1(dev, "DCFG=%08x\n", dev->dcfg_save);
++		temp = dwc_rd32(dev, &pcd->dev_global_regs->dcfg);
++		dwc_debug1(dev, "DCFG read back %08x\n", temp);
++		dwc_wr32(dev, &pcd->dev_global_regs->dctl, dev->dctl_save);
++		dwc_wr32(dev, &dev->core_global_regs->gtxfifosiz[0],
++			 dev->gtxfifosiz0_save);
++		dwc_wr32(dev, &dev->core_global_regs->gtxfifosiz[1],
++			 dev->gtxfifosiz1_save);
++		dwc_wr32(dev, &dev->core_global_regs->gtxfifosiz[2],
++			 dev->gtxfifosiz2_save);
++		dwc_wr32(dev, &dev->core_global_regs->gtxfifosiz[3],
++			 dev->gtxfifosiz3_save);
++		dwc_wr32(dev, &dev->core_global_regs->grxfifosiz[0],
++			 dev->grxfifosiz0_save);
++	}
++
++	/* Configure the core as described in [DWSS] Section 9.1.1 "Device
++	 * Power-On or Soft Reset," excluding the first step (Soft Reset).
++	 */
++	dwc_usb3_pcd_device_init(dev, 0, restore_state);
++
++#ifdef CONFIG_USB_OTG_DWC
++	/* Enable Device mode interrupts */
++	dwc_usb3_enable_device_interrupts(dev);
++
++	/* Set Run/Stop bit, and Keep-Connect bit if hibernation enabled */
++	temp = dwc_rd32(dev, &pcd->dev_global_regs->dctl);
++	temp |= DWC_DCTL_RUN_STOP_BIT;
++	if (dev->core_params->hibernate &&
++	    (dev->hwparams1 & DWC_HWP1_EN_PWROPT_BITS) ==
++	    DWC_EN_PWROPT_HIBERNATION << DWC_HWP1_EN_PWROPT_SHIFT)
++		temp |= DWC_DCTL_KEEP_CONNECT_BIT;
++	dwc_wr32(dev, &pcd->dev_global_regs->dctl, temp);
++#endif
++
++	/*
++	 * If the LNR (Link-state Not Ready) field of DSTS is set to 1,
++	 * continue polling the DSTS register until LNR=0.
++	 */
++	for (;;) {
++		temp = dwc_rd32(dev, &pcd->dev_global_regs->dsts);
++		if (temp & DWC_DSTS_LNR_BIT)
++			dwc_udelay(dev, 1);
++		else
++			break;
++	}
++
++	/* Read the DSTS register to see the current link state. */
++	temp = dwc_usb3_pcd_get_link_state(pcd);
++	pcd->link_state = temp;
++
++	if (temp > DWC_LINK_STATE_U3 && temp != DWC_LINK_STATE_EARLY_SUSPEND &&
++	    temp != DWC_LINK_STATE_RESUME) {
++		/* If the core is not connected to the host, wait for a Connect
++		 * Done event.
++		 */
++		if (temp != DWC_LINK_STATE_RESET) {
++			dev->hiber_wait_connect = 1;
++
++			if (temp == DWC_LINK_STATE_SS_DIS &&
++			    /*pcd->speed != USB_SPEED_SUPER &&*/
++			    dev->core_params->ssdisquirk) {
++				dwc_debug0(dev,
++					"Link state SS_DIS, enabling quirk\n");
++				dev->hibernate = DWC_HIBER_SS_DIS_QUIRK;
++				return DWC_HIBER_SS_DIS_QUIRK;
++			}
++
++			dwc_debug1(dev, "Link state %d, waiting for connect"
++				   " before exiting from hibernation\n", temp);
++		} else {
++			/* If the DSTS.USBLnkSt equals 14, it means a USB reset
++			 * was received while the core was entering or exiting
++			 * hibernation. Prior to performing the steps in
++			 * sections 9.1.2 and 9.1.3, software must write Resume
++			 * (8) into the DCTL.ULStChngReq field.
++			 */
++			dwc_debug0(dev, "USB Reset received during hibernation,"
++				   " requesting link state Recovery\n");
++			dwc_usb3_pcd_set_link_state(pcd,
++						DWC_LINK_STATE_REQ_RECOVERY);
++			//dwc_mdelay(dev, 1);
++			//dwc_usb3_pcd_set_link_state(pcd, 0);
++			dwc_usb3_set_address(pcd, 0);
++			dev->hibernate = DWC_HIBER_WAIT_LINK_UP;
++			return DWC_HIBER_WAIT_LINK_UP;
++		}
++	} else {
++		dwc_debug1(dev, "Link state %d, exiting from hibernation\n",
++			   temp);
++		dev->hiber_wait_connect = 0;
++
++		/* Perform the steps in Section 9.1.3 "Initialization on
++		 * Connect Done" in [DWSS].
++		 */
++		dwc_usb3_handle_connect_done_intr(pcd);
++
++		dwc_exit_hibernation_after_connect(pcd, 1);
++	}
++
++	return 0;
++}
+diff --git a/drivers/usb/gadget/udc/hiudc3/pcd_intr.c b/drivers/usb/gadget/udc/hiudc3/pcd_intr.c
+new file mode 100644
+index 0000000..fbdc652
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc3/pcd_intr.c
+@@ -0,0 +1,691 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/DWC_usb3/driver/pcd_intr.c $
++ * $Revision: #114 $
++ * $Date: 2014/11/11 $
++ * $Change: 2664766 $
++ *
++ * Synopsys SS USB3 Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
++ * ========================================================================== */
++
++/** @file
++ * This file contains the implementation of the PCD Interrupt handlers.
++ *
++ * The PCD handles the device interrupts. Many conditions can cause a
++ * device interrupt. When an interrupt occurs, the device interrupt
++ * service routine determines the cause of the interrupt and
++ * dispatches handling to the appropriate routine. These interrupt
++ * handling routines are described below.
++ */
++
++#include "os_defs.h"
++#include "hw.h"
++#include "usb.h"
++#include "pcd.h"
++#include "dev.h"
++#include "os_dev.h"
++#include "cil.h"
++
++#ifdef DWC_UTE
++# include "ute_if.h"
++#endif
++
++/**
++ * This interrupt indicates that the USB link state has changed to L2, U3, or
++ * (if L1 Hibernation is enabled) L1, and software intervention is required.
++ */
++static int handle_hiber_req_intr(dwc_usb3_pcd_t *pcd, u32 event)
++{
++	int hird, is_superspeed;
++	u32 state;
++
++	dwc_print0(pcd->usb3_dev, "HIBERNATION REQUEST\n");
++
++	is_superspeed = !!(event & DWC_DEVT_HIBER_SS_BIT);
++	state = event >> DWC_DEVT_HIBER_STATE_SHIFT &
++		DWC_DEVT_HIBER_STATE_BITS >> DWC_DEVT_HIBER_STATE_SHIFT;
++	dwc_print2(pcd->usb3_dev, "state=%x, is_superspeed=%d\n",
++		   state, is_superspeed);
++
++	/* TODO: Workaround */
++	if (!(state == DWC_LINK_STATE_U3 ||
++	      //state == DWC_LINK_STATE_SS_DIS ||
++	      (!is_superspeed && (state == DWC_LINK_STATE_SLEEP)))) {
++		dwc_print0(pcd->usb3_dev, "HIBERNATION not handled\n");
++		return 1;
++	} /* End workaround */
++
++	hird = event >> DWC_DEVT_HIBER_HIRD_SHIFT &
++	       DWC_DEVT_HIBER_HIRD_BITS >> DWC_DEVT_HIBER_HIRD_SHIFT;
++	dwc_debug5(pcd->usb3_dev, "%s(%u), state=%d hird=%d ss=%d\n",
++		   __func__, event, state, hird, is_superspeed);
++
++	/* Enter hibernation if supported */
++	if (pcd->usb3_dev->core_params->hibernate &&
++	    (pcd->usb3_dev->hwparams1 & DWC_HWP1_EN_PWROPT_BITS) ==
++	    DWC_EN_PWROPT_HIBERNATION << DWC_HWP1_EN_PWROPT_SHIFT) {
++		/* Tell kernel thread to save state and enter hibernation */
++		pcd->usb3_dev->hibernate = DWC_HIBER_ENTER_SAVE;
++		return 1;
++	}
++
++	return 0;
++}
++
++/**
++ * This interrupt indicates that the device has been disconnected.
++ */
++static int handle_disconnect_intr(dwc_usb3_pcd_t *pcd)
++{
++	dwc_usb3_device_t *dev = pcd->usb3_dev;
++	u32 temp;
++
++	dwc_print0(dev, "DISCONNECT\n");
++
++	/* Must set DCTL[8:5] to 5, according to 2.40a and later databook.
++	 * Assuming here this will be harmless on earlier cores.
++	 */
++	temp = dwc_rd32(dev, &pcd->dev_global_regs->dctl);
++	temp &= ~DWC_DCTL_ULST_CHNG_REQ_BITS;
++	temp |= DWC_LINK_STATE_REQ_RX_DETECT << DWC_DCTL_ULST_CHNG_REQ_SHIFT;
++	dwc_wr32(dev, &pcd->dev_global_regs->dctl, temp);
++
++	dwc_usb3_clr_eps_enabled(pcd);
++	dwc_usb3_pcd_stop(pcd);
++
++	/* Enter hibernation if supported */
++	if (dev->core_params->hibernate && dev->core_params->hiberdisc &&
++	    (dev->hwparams1 & DWC_HWP1_EN_PWROPT_BITS) ==
++	    DWC_EN_PWROPT_HIBERNATION << DWC_HWP1_EN_PWROPT_SHIFT) {
++		/* Tell kernel thread to enter hibernation */
++		dev->hibernate = DWC_HIBER_ENTER_NOSAVE;
++		return 1;
++	}
++
++	return 0;
++}
++
++/**
++ * This interrupt occurs when a USB Reset is detected. When the USB Reset
++ * Interrupt occurs, all transfers are stopped and the device state is set
++ * to DEFAULT.
++ */
++static void handle_usb_reset_intr(dwc_usb3_pcd_t *pcd)
++{
++	dwc_usb3_pcd_ep_t *ep;
++	int i;
++
++	dwc_print0(pcd->usb3_dev, "USB RESET\n");
++
++	/* If UsbReset comes without Disconnect first, fake it, because the
++	 * gadget may need to see a disconnect first. The Synopsys UAS gadget
++	 * needs this.
++	 */
++#if 1
++	if (pcd->state != DWC_STATE_UNCONNECTED) {
++//		dwc_print0(pcd->usb3_dev, "fake DISCONNECT\n");
++		dwc_usb3_clr_eps_enabled(pcd);
++		dwc_usb3_pcd_stop(pcd);
++	} else
++#endif
++	{
++		/* Stop any active xfers on the non-EP0 endpoints */
++		dwc_usb3_stop_all_xfers(pcd);
++		dwc_usb3_clr_eps_enabled(pcd);
++	}
++
++	/* Clear stall on each EP */
++	for (i = 0; i < pcd->num_in_eps; i++) {
++		ep = pcd->in_ep[i];
++		if (ep->dwc_ep.active && ep->dwc_ep.stopped)
++			dwc_usb3_pcd_ep_clear_stall(pcd, ep);
++	}
++	for (i = 0; i < pcd->num_out_eps; i++) {
++		ep = pcd->out_ep[i];
++		if (ep->dwc_ep.active && ep->dwc_ep.stopped)
++			dwc_usb3_pcd_ep_clear_stall(pcd, ep);
++	}
++
++#ifndef SELA_PLATFORM_NOCTL
++	/* Set Device Address to 0 */
++	dwc_usb3_set_address(pcd, 0);
++#endif
++
++	pcd->remote_wakeup_enable = 0;
++	pcd->ltm_enable = 0;
++}
++
++/**
++ * This interrupt occurs when a Connect Done is detected.
++ * Read the device status register and set the device speed in the data
++ * structure. Set up EP0 to receive SETUP packets.
++ */
++void dwc_usb3_handle_connect_done_intr(dwc_usb3_pcd_t *pcd)
++{
++	dwc_usb3_device_t *dev = pcd->usb3_dev;
++	dwc_usb3_pcd_ep_t *ep0 = pcd->ep0;
++	int speed;
++#ifndef SELA_PLATFORM_NOCTL
++	u32 temp;
++	u32 diepcfg0, doepcfg0, diepcfg1, doepcfg1;
++	dwc_usb3_dev_ep_regs_t __iomem *ep_reg;
++#endif
++
++#ifndef SELA_PLATFORM_NOCTL
++	/* The timing on reconnect after hibernation is so tight that we
++	 * cannot afford the overhead of printing this to the dmesg log!
++	 */
++	if (!dev->core_params->hibernate ||
++	    (dev->hwparams1 & DWC_HWP1_EN_PWROPT_BITS) !=
++	    DWC_EN_PWROPT_HIBERNATION << DWC_HWP1_EN_PWROPT_SHIFT)
++		dwc_print0(dev, "CONNECT\n");
++
++//	printk("\n###%s,%d\n",__func__,__LINE__);
++# ifdef DEBUG_EP0
++	dwc_usb3_print_ep0_state(pcd);
++# endif
++#endif /* SELA_PLATFORM_NOCTL */
++
++	ep0->dwc_ep.stopped = 0;
++	speed = dwc_usb3_get_device_speed(pcd);
++//	printk("\n###%s,%d\n",__func__,__LINE__);
++	pcd->speed = speed;
++
++#ifndef SELA_PLATFORM_NOCTL
++# ifdef DWC_STAR_9000483510_WORKAROUND
++	if (speed == USB_SPEED_SUPER)
++		handle_usb_reset_intr(pcd);
++# endif
++
++	/* If LPM enable was requested */
++//	printk("\n###%s,%d\n",__func__,__LINE__);
++	if (dev->core_params->lpmctl) {
++		temp = dwc_rd32(dev, &pcd->dev_global_regs->dctl);
++
++		/* HIRD threshold must be set to 0 when in SS */
++		temp &= ~DWC_DCTL_HIRD_THR_BITS;
++
++		/* If not SS */
++		if (speed != USB_SPEED_SUPER) {
++			/* If hibernation enabled and non-default threshold */
++			if (dev->core_params->hibernate &&
++			    (dev->hwparams1 & DWC_HWP1_EN_PWROPT_BITS) ==
++			    DWC_EN_PWROPT_HIBERNATION << DWC_HWP1_EN_PWROPT_SHIFT &&
++			    dev->hird_thresh) {
++				/* Set requested threshold value */
++				temp |= dev->hird_thresh << DWC_DCTL_HIRD_THR_SHIFT &
++						DWC_DCTL_HIRD_THR_BITS;
++			} else {
++				/* Set default threshold value */
++				temp |= 0x1c << DWC_DCTL_HIRD_THR_SHIFT;
++			}
++		}
++
++		dwc_wr32(dev, &pcd->dev_global_regs->dctl, temp);
++	}
++
++//	printk("\n###%s,%d\n",__func__,__LINE__);
++	/* Set the MPS of EP0 based on the connection speed */
++	switch (speed) {
++	case USB_SPEED_SUPER:
++		pcd->ep0->dwc_ep.maxpacket = 512;
++		break;
++
++	case USB_SPEED_HIGH:
++	case USB_SPEED_FULL:
++		pcd->ep0->dwc_ep.maxpacket = 64;
++		break;
++
++	case USB_SPEED_LOW:
++		pcd->ep0->dwc_ep.maxpacket = 8;
++		break;
++	}
++
++	diepcfg0 = DWC_USB3_EP_TYPE_CONTROL << DWC_EPCFG0_EPTYPE_SHIFT;
++	diepcfg0 |= DWC_CFG_ACTION_MODIFY << DWC_EPCFG0_CFG_ACTION_SHIFT;
++	diepcfg1 = DWC_EPCFG1_XFER_CMPL_BIT | DWC_EPCFG1_XFER_IN_PROG_BIT |
++		   DWC_EPCFG1_XFER_NRDY_BIT | DWC_EPCFG1_EP_DIR_BIT;
++
++	doepcfg0 = DWC_USB3_EP_TYPE_CONTROL << DWC_EPCFG0_EPTYPE_SHIFT;
++	doepcfg0 |= DWC_CFG_ACTION_MODIFY << DWC_EPCFG0_CFG_ACTION_SHIFT;
++	doepcfg1 = DWC_EPCFG1_XFER_CMPL_BIT | DWC_EPCFG1_XFER_IN_PROG_BIT |
++		   DWC_EPCFG1_XFER_NRDY_BIT;
++
++	diepcfg0 |= pcd->ep0->dwc_ep.maxpacket << DWC_EPCFG0_MPS_SHIFT;
++	doepcfg0 |= pcd->ep0->dwc_ep.maxpacket << DWC_EPCFG0_MPS_SHIFT;
++
++# ifdef DWC_UTE
++	ep0->dwc_ep.tx_fifo_num = pcd->txf_map[0];
++# endif
++	diepcfg0 |= ep0->dwc_ep.tx_fifo_num << DWC_EPCFG0_TXFNUM_SHIFT;
++
++	dwc_usb3_dis_usb2_suspend(pcd);
++
++	/* Issue "DEPCFG" command to EP0-OUT */
++	ep_reg = &pcd->out_ep_regs[0];
++//	printk("\n###%s,%d\n",__func__,__LINE__);
++	dwc_usb3_dep_cfg(pcd, ep_reg, doepcfg0, doepcfg1, 0);
++
++//	printk("\n###%s,%d\n",__func__,__LINE__);
++	/* Issue "DEPCFG" command to EP0-IN */
++	ep_reg = &pcd->in_ep_regs[0];
++	dwc_usb3_dep_cfg(pcd, ep_reg, diepcfg0, diepcfg1, 0);
++//	printk("\n###%s,%d\n",__func__,__LINE__);
++
++	dwc_usb3_ena_usb2_suspend(pcd);
++//	printk("\n###%s,%d\n",__func__,__LINE__);
++#endif /* SELA_PLATFORM_NOCTL */
++
++	if (pcd->state == DWC_STATE_UNCONNECTED)
++		pcd->state = DWC_STATE_DEFAULT;
++
++	/* Inform the gadget of the connection and the speed */
++//	printk("\n###%s,%d\n",__func__,__LINE__);
++	dwc_usb3_gadget_connect(pcd, speed);
++//	printk("\n###%s,%d\n",__func__,__LINE__);
++
++	if (dev->hiber_wait_connect) {
++		/* Already did 'Perform the steps in Section 9.1.3
++		 * "Initialization on Connect Done" in [DWSS]'.
++		 */
++
++		dwc_debug0(dev, "Hibernation wait connect\n");
++		dev->hiber_wait_connect = 0;
++		dwc_exit_hibernation_after_connect(pcd, 0);
++	}
++}
++
++/**
++ * This interrupt indicates that the USB link state has changed.
++ */
++static void handle_link_status_change_intr(dwc_usb3_pcd_t *pcd)
++{
++	int state;
++	int speed;
++
++	if (pcd->usb3_dev->snpsid >= 0x5533230a)
++		return;
++
++	state = dwc_usb3_pcd_get_link_state(pcd);
++	speed = dwc_usb3_get_device_speed(pcd);
++	pcd->speed = speed;
++	dwc_debug2(pcd->usb3_dev, "LINK state=%d speed=%d\n", state, speed);
++
++	switch (state) {
++	case DWC_LINK_STATE_U0:
++		if (pcd->usb3_dev->hiber_wait_u0) {
++			pcd->speed = speed;
++			if (pcd->remote_wakeup_enable)
++				dwc_usb3_pcd_remote_wake(pcd, 0);
++			pcd->usb3_dev->hiber_wait_u0 = 0;
++		}
++
++		/* If transitioning from 3->0 */
++		if (pcd->link_state == DWC_LINK_STATE_U3) {
++			dwc_debug0(pcd->usb3_dev,
++				   "Enabling function remote wake\n");
++			pcd->wkup_rdy = 1;
++		} else {
++			pcd->wkup_rdy = 0;
++		}
++
++		pcd->link_state = state;
++		break;
++
++	case DWC_LINK_STATE_U3:
++		/* If transitioning to 3 */
++		if (pcd->link_state != DWC_LINK_STATE_U3)
++			dwc_usb3_gadget_suspend(pcd);
++		/* FALL-THRU */
++
++	default:
++		pcd->link_state = state;
++		pcd->wkup_rdy = 0;
++		break;
++	}
++}
++
++/**
++ * This interrupt indicates that the DWC_usb3 controller has detected a
++ * resume or remote wakeup sequence.
++ */
++static void handle_wakeup_detected_intr(dwc_usb3_pcd_t *pcd)
++{
++	int state;
++
++	dwc_debug0(pcd->usb3_dev,
++		   "++Resume or Remote Wakeup Detected Interrupt++\n");
++	dwc_debug1(pcd->usb3_dev, "DSTS=0x%01x\n",
++		   dwc_rd32(pcd->usb3_dev, &pcd->dev_global_regs->dsts));
++	state = dwc_usb3_pcd_get_link_state(pcd);
++	pcd->link_state = state;
++
++	if (state == DWC_LINK_STATE_U0)
++		dwc_usb3_gadget_resume(pcd);
++}
++
++/**
++ * This interrupt indicates that a U3/L2-L1 Suspend event has occurred.
++ */
++static void handle_u3_l2l1_susp_intr(dwc_usb3_pcd_t *pcd)
++{
++	int state;
++
++	if (pcd->usb3_dev->snpsid < 0x5533230a)
++		return;
++
++	state = dwc_usb3_pcd_get_link_state(pcd);
++	dwc_debug1(pcd->usb3_dev, "LINK state=%d\n", state);
++
++	switch (state) {
++	case DWC_LINK_STATE_U0:
++		/* If transitioning from 3->0 */
++		if (pcd->link_state == DWC_LINK_STATE_U3) {
++			dwc_debug0(pcd->usb3_dev,
++				   "Enabling function remote wake\n");
++			pcd->wkup_rdy = 1;
++		} else {
++			pcd->wkup_rdy = 0;
++		}
++
++		pcd->link_state = state;
++		break;
++
++	case DWC_LINK_STATE_U3:
++		/* If transitioning to 3 */
++		if (pcd->link_state != DWC_LINK_STATE_U3)
++			dwc_usb3_gadget_suspend(pcd);
++		/* FALL-THRU */
++
++	default:
++		pcd->link_state = state;
++		pcd->wkup_rdy = 0;
++		break;
++	}
++}
++
++/**
++ * This routine handles the SOF Interrupts. At this time the SOF Interrupt
++ * is disabled.
++ */
++static void handle_sof_intr(dwc_usb3_pcd_t *pcd)
++{
++	dwc_debug0(pcd->usb3_dev, "SOF\n");
++}
++
++/**
++ * This interrupt indicates that an EP has a pending interrupt.
++ */
++void dwc_usb3_handle_ep_intr(dwc_usb3_pcd_t *pcd, int physep, u32 event)
++{
++	dwc_usb3_pcd_ep_t *ep;
++	int epnum, is_in, temp;
++	char *dir;
++
++	dwc_debug4(pcd->usb3_dev, "%s(%lx,%d,0x%08x)\n", __func__,
++		   (unsigned long)pcd, physep, event);
++
++	/* Physical Out EPs are even, physical In EPs are odd */
++	is_in = physep & 1;
++	epnum = physep >> 1 & 0xf;
++
++	/* Get EP pointer */
++	if (is_in) {
++		ep = dwc_usb3_get_in_ep(pcd, epnum);
++		dir = "IN";
++	} else {
++		ep = dwc_usb3_get_out_ep(pcd, epnum);
++		dir = "OUT";
++	}
++
++	dwc_debug1(pcd->usb3_dev, "%s EP intr\n", dir);
++
++#ifdef VERBOSE
++	dwc_debug4(pcd->usb3_dev, "EP%d-%s: type=%d mps=%d\n",
++		   ep->dwc_ep.num, (ep->dwc_ep.is_in ? "IN" : "OUT"),
++		   ep->dwc_ep.type, ep->dwc_ep.maxpacket);
++#endif
++#ifdef SELA_PLATFORM
++	if (pcd->ep_event) {
++		int evt = event >> DWC_DEPEVT_INTTYPE_SHIFT &
++			  DWC_DEPEVT_INTTYPE_BITS >> DWC_DEPEVT_INTTYPE_SHIFT;
++		evt |= epnum << 8 | is_in << 15;
++		*pcd->ep_event = evt;
++	}
++#endif
++
++	temp = pcd->usb3_dev->hibernate;
++	if (temp >= DWC_HIBER_SLEEPING && temp != DWC_HIBER_WAIT_U0 &&
++	    temp != DWC_HIBER_SS_DIS_QUIRK) {
++		dwc_info3(pcd->usb3_dev,
++			  "EP%d-%s: got event 0x%08x while hibernating\n",
++			  ep->dwc_ep.num, (ep->dwc_ep.is_in ? "IN" : "OUT"),
++			  event);
++		return;
++	}
++
++	switch (event & DWC_DEPEVT_INTTYPE_BITS) {
++	case DWC_DEPEVT_XFER_CMPL << DWC_DEPEVT_INTTYPE_SHIFT:
++#ifdef VERBOSE
++		dwc_debug2(pcd->usb3_dev, "[EP%d] %s xfer complete\n",
++			   epnum, dir);
++#endif
++		ep->dwc_ep.xfer_started = 0;
++
++		if (ep->dwc_ep.type != UE_ISOCHRONOUS) {
++			/* Complete the transfer */
++			if (epnum == 0)
++				dwc_usb3_handle_ep0_xfer(pcd, event);
++			else
++				dwc_usb3_complete_request(pcd, ep, event);
++		} else {
++			dwc_print2(pcd->usb3_dev,
++				   "[EP%d] %s xfer complete for ISOC EP!\n",
++				   epnum, dir);
++		}
++
++		break;
++
++	case DWC_DEPEVT_XFER_IN_PROG << DWC_DEPEVT_INTTYPE_SHIFT:
++#ifdef VERBOSE
++		dwc_debug2(pcd->usb3_dev, "[EP%d] %s xfer in progress\n",
++			   epnum, dir);
++#endif
++		if (ep->dwc_ep.type == UE_ISOCHRONOUS) {
++#if 0
++			u32 now_uf, evt_uf;
++
++			/* Don't complete transfer if it's way in the past */
++			now_uf = dwc_usb3_get_frame(pcd);
++			evt_uf = dwc_usb3_get_eventsofn(event);
++			now_uf &= DWC_DEPEVT_ISOC_UFRAME_NUM_BITS >>
++				  DWC_DEPEVT_ISOC_UFRAME_NUM_SHIFT;
++			if (now_uf - evt_uf < 0x8000)
++#endif
++				/* Complete the transfer */
++				dwc_usb3_complete_request(pcd, ep, event);
++		} else {
++//			dwc_print2(pcd->usb3_dev,
++//				"[EP%d] %s xfer in progress for non-ISOC EP!\n",
++//				 epnum, dir);
++
++			/* Complete the transfer */
++			if (epnum == 0)
++				dwc_usb3_handle_ep0_xfer(pcd, event);
++			else
++				dwc_usb3_complete_request(pcd, ep, event);
++		}
++
++		break;
++
++	case DWC_DEPEVT_XFER_NRDY << DWC_DEPEVT_INTTYPE_SHIFT:
++		dwc_debug2(pcd->usb3_dev, "[EP%d] %s xfer not ready\n",
++			   epnum, dir);
++
++		if (epnum == 0) {
++			switch (pcd->ep0state) {
++			case EP0_IN_WAIT_GADGET:
++			case EP0_IN_WAIT_NRDY:
++				if (is_in)
++					dwc_usb3_handle_ep0_xfer(pcd, event);
++				break;
++			case EP0_OUT_WAIT_GADGET:
++			case EP0_OUT_WAIT_NRDY:
++				if (!is_in)
++					dwc_usb3_handle_ep0_xfer(pcd, event);
++				break;
++			default:
++				break;
++			}
++		} else if (ep->dwc_ep.type == UE_ISOCHRONOUS) {
++			dwc_isocdbg2(pcd->usb3_dev,
++				     "[EP%d] %s xfer not ready for ISOC EP!\n",
++				     epnum, dir);
++			if (!ep->dwc_ep.xfer_started)
++				dwc_usb3_gadget_isoc_ep_start(pcd, ep, event);
++		}
++
++		break;
++
++	case DWC_DEPEVT_FIFOXRUN << DWC_DEPEVT_INTTYPE_SHIFT:
++		dwc_error2(pcd->usb3_dev, "[EP%d] %s FIFO Underrun Error!\n",
++			   epnum, dir);
++		break;
++
++	case DWC_DEPEVT_EPCMD_CMPL << DWC_DEPEVT_INTTYPE_SHIFT:
++		dwc_error2(pcd->usb3_dev, "[EP%d] %s Command Complete!\n",
++			   epnum, dir);
++		break;
++
++	default:
++		dwc_error2(pcd->usb3_dev, "[EP%d] %s Unknown event!\n",
++			   epnum, dir);
++		break;
++	}
++}
++
++/**
++ * PCD interrupt handler.
++ *
++ * The PCD handles the device interrupts. Many conditions can cause a
++ * device interrupt. When an interrupt occurs, the device interrupt
++ * service routine determines the cause of the interrupt and
++ * dispatches handling to the appropriate routine.
++ */
++int dwc_usb3_handle_dev_intr(dwc_usb3_pcd_t *pcd, u32 event)
++{
++	u32 dint = event >> DWC_DEVT_SHIFT & DWC_DEVT_BITS >> DWC_DEVT_SHIFT;
++	int temp, ret = 0;
++
++#ifdef VERBOSE
++	dwc_debug2(pcd->usb3_dev, "%s() event=%08x\n", __func__, event);
++#endif
++#ifdef SELA_PLATFORM
++	if (pcd->dev_event)
++		*pcd->dev_event = dint;
++#endif
++
++	temp = pcd->usb3_dev->hibernate;
++	if (temp >= DWC_HIBER_SLEEPING && temp != DWC_HIBER_WAIT_U0 &&
++	    temp != DWC_HIBER_SS_DIS_QUIRK) {
++		dwc_info1(pcd->usb3_dev,
++			  "Device: got event 0x%08x while hibernating\n",
++			  event);
++		return 0;
++	}
++
++//	printk("\n#####%s,%d,dint=0x%x\n",__func__,__LINE__,dint);
++	switch (dint) {
++	case DWC_DEVT_DISCONN:
++		dwc_debug0(pcd->usb3_dev, "Disconnect\n");
++		printk("Disconnect\n");
++		ret = handle_disconnect_intr(pcd);
++		break;
++
++	case DWC_DEVT_USBRESET:
++		dwc_debug0(pcd->usb3_dev, "USB Reset\n");
++		printk("USB Reset\n");
++		handle_usb_reset_intr(pcd);
++		break;
++
++	case DWC_DEVT_CONNDONE:
++		dwc_debug0(pcd->usb3_dev, "Connect Done\n");
++		printk("Connect Done\n");
++		dwc_usb3_handle_connect_done_intr(pcd);
++		break;
++
++	case DWC_DEVT_ULST_CHNG:
++		printk("Link Status Change\n");
++		handle_link_status_change_intr(pcd);
++		break;
++
++	case DWC_DEVT_WKUP:
++		dwc_debug0(pcd->usb3_dev, "Wakeup\n");
++		printk("Wakeup\n");
++		handle_wakeup_detected_intr(pcd);
++		break;
++
++	case DWC_DEVT_HIBER_REQ:
++		dwc_debug0(pcd->usb3_dev, "Hibernation Request\n");
++		printk("Hibernation Request\n");
++		ret = handle_hiber_req_intr(pcd, event);
++		break;
++
++	case DWC_DEVT_U3_L2L1_SUSP:
++		dwc_debug0(pcd->usb3_dev, "U3/L2-L1 Suspend Event\n");
++		printk("U3/L2-L1 Suspend Event\n");
++		handle_u3_l2l1_susp_intr(pcd);
++		break;
++
++	case DWC_DEVT_SOF:
++		dwc_debug0(pcd->usb3_dev, "Start of Frame\n");
++		printk("Start of Frame\n");
++		handle_sof_intr(pcd);
++		break;
++
++	case DWC_DEVT_ERRATICERR:
++		dwc_debug0(pcd->usb3_dev, "Erratic Error\n");
++		printk("Erratic Error\n");
++		break;
++
++	case DWC_DEVT_CMD_CMPL:
++		dwc_debug0(pcd->usb3_dev, "Command Complete\n");
++		printk("Command Complete\n");
++		break;
++
++	case DWC_DEVT_OVERFLOW:
++		dwc_debug0(pcd->usb3_dev, "Overflow\n");
++		printk("Overflow\n");
++		break;
++
++	default:
++		dwc_debug0(pcd->usb3_dev, "Unknown event!\n");
++		printk("Unknown event!\n");
++		break;
++	}
++
++	return ret;
++}
+diff --git a/drivers/usb/gadget/udc/hiudc3/usb.h b/drivers/usb/gadget/udc/hiudc3/usb.h
+new file mode 100644
+index 0000000..3317776
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc3/usb.h
+@@ -0,0 +1,961 @@
++/*
++ * Copyright (c) 1998 The NetBSD Foundation, Inc.
++ * All rights reserved.
++ *
++ * This code is derived from software contributed to The NetBSD Foundation
++ * by Lennart Augustsson (lennart@augustsson.net) at
++ * Carlstedt Research & Technology.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. All advertising materials mentioning features or use of this software
++ *    must display the following acknowledgement:
++ *        This product includes software developed by the NetBSD
++ *        Foundation, Inc. and its contributors.
++ * 4. Neither the name of The NetBSD Foundation nor the names of its
++ *    contributors may be used to endorse or promote products derived
++ *    from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
++ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
++ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
++ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
++ * POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/* Modified by Synopsys, Inc, 12/12/2007 */
++
++
++#ifndef _USB_H_
++#define _USB_H_
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/**
++ * @file
++ */
++
++/*
++ * The USB records contain some unaligned little-endian word
++ * components.  The U[SG]ETW macros take care of both the alignment
++ * and endian problem and should always be used to access non-byte
++ * values.
++ */
++typedef u_int8_t uByte;
++typedef u_int8_t uWord[2];
++typedef u_int8_t uDWord[4];
++
++#define USETW2(w,h,l) ((w)[0] = (u_int8_t)(l), (w)[1] = (u_int8_t)(h))
++#define UCONSTW(x)	{ (x) & 0xff, ((x) >> 8) & 0xff }
++#define UCONSTDW(x)	{ (x) & 0xff, ((x) >> 8) & 0xff, \
++			  ((x) >> 16) & 0xff, ((x) >> 24) & 0xff }
++
++#if 1
++#define UGETW(w) ((w)[0] | ((w)[1] << 8))
++#define USETW(w,v) ((w)[0] = (u_int8_t)(v), (w)[1] = (u_int8_t)((v) >> 8))
++#define UGETDW(w) ((w)[0] | ((w)[1] << 8) | ((w)[2] << 16) | ((w)[3] << 24))
++#define USETDW(w,v) ((w)[0] = (u_int8_t)(v), \
++		     (w)[1] = (u_int8_t)((v) >> 8), \
++		     (w)[2] = (u_int8_t)((v) >> 16), \
++		     (w)[3] = (u_int8_t)((v) >> 24))
++#else
++/*
++ * On little-endian machines that can handle unaligned accesses
++ * (e.g. i386) these macros can be replaced by the following.
++ */
++#define UGETW(w) (*(u_int16_t *)(w))
++#define USETW(w,v) (*(u_int16_t *)(w) = (v))
++#define UGETDW(w) (*(u_int32_t *)(w))
++#define USETDW(w,v) (*(u_int32_t *)(w) = (v))
++#endif
++
++/*
++ * Macros for accessing UAS IU fields, which are big-endian
++ */
++#define IUSETW2(w,h,l) ((w)[0] = (u_int8_t)(h), (w)[1] = (u_int8_t)(l))
++#define IUCONSTW(x)	{ ((x) >> 8) & 0xff, (x) & 0xff }
++#define IUCONSTDW(x)	{ ((x) >> 24) & 0xff, ((x) >> 16) & 0xff, \
++			((x) >> 8) & 0xff, (x) & 0xff }
++#define IUGETW(w) (((w)[0] << 8) | (w)[1])
++#define IUSETW(w,v) ((w)[0] = (u_int8_t)((v) >> 8), (w)[1] = (u_int8_t)(v))
++#define IUGETDW(w) (((w)[0] << 24) | ((w)[1] << 16) | ((w)[2] << 8) | (w)[3])
++#define IUSETDW(w,v) ((w)[0] = (u_int8_t)((v) >> 24), \
++		      (w)[1] = (u_int8_t)((v) >> 16), \
++		      (w)[2] = (u_int8_t)((v) >> 8), \
++		      (w)[3] = (u_int8_t)(v))
++
++//#define UPACKED __attribute__ ((__packed__))
++
++typedef struct {
++	uByte		bmRequestType;
++	uByte		bRequest;
++	uWord		wValue;
++	uWord		wIndex;
++	uWord		wLength;
++} UPACKED usb_device_request_t;
++
++#define UT_GET_DIR(a) ((a) & 0x80)
++#define UT_WRITE		0x00
++#define UT_READ			0x80
++
++#define UT_GET_TYPE(a) ((a) & 0x60)
++#define UT_STANDARD		0x00
++#define UT_CLASS		0x20
++#define UT_VENDOR		0x40
++
++#define UT_GET_RECIPIENT(a) ((a) & 0x1f)
++#define UT_DEVICE		0x00
++#define UT_INTERFACE		0x01
++#define UT_ENDPOINT		0x02
++#define UT_OTHER		0x03
++
++#define UT_READ_DEVICE		(UT_READ  | UT_STANDARD | UT_DEVICE)
++#define UT_READ_INTERFACE	(UT_READ  | UT_STANDARD | UT_INTERFACE)
++#define UT_READ_ENDPOINT	(UT_READ  | UT_STANDARD | UT_ENDPOINT)
++#define UT_WRITE_DEVICE		(UT_WRITE | UT_STANDARD | UT_DEVICE)
++#define UT_WRITE_INTERFACE	(UT_WRITE | UT_STANDARD | UT_INTERFACE)
++#define UT_WRITE_ENDPOINT	(UT_WRITE | UT_STANDARD | UT_ENDPOINT)
++#define UT_READ_CLASS_DEVICE	(UT_READ  | UT_CLASS | UT_DEVICE)
++#define UT_READ_CLASS_INTERFACE	(UT_READ  | UT_CLASS | UT_INTERFACE)
++#define UT_READ_CLASS_OTHER	(UT_READ  | UT_CLASS | UT_OTHER)
++#define UT_READ_CLASS_ENDPOINT	(UT_READ  | UT_CLASS | UT_ENDPOINT)
++#define UT_WRITE_CLASS_DEVICE	(UT_WRITE | UT_CLASS | UT_DEVICE)
++#define UT_WRITE_CLASS_INTERFACE (UT_WRITE | UT_CLASS | UT_INTERFACE)
++#define UT_WRITE_CLASS_OTHER	(UT_WRITE | UT_CLASS | UT_OTHER)
++#define UT_WRITE_CLASS_ENDPOINT	(UT_WRITE | UT_CLASS | UT_ENDPOINT)
++#define UT_READ_VENDOR_DEVICE	(UT_READ  | UT_VENDOR | UT_DEVICE)
++#define UT_READ_VENDOR_INTERFACE (UT_READ  | UT_VENDOR | UT_INTERFACE)
++#define UT_READ_VENDOR_OTHER	(UT_READ  | UT_VENDOR | UT_OTHER)
++#define UT_READ_VENDOR_ENDPOINT	(UT_READ  | UT_VENDOR | UT_ENDPOINT)
++#define UT_WRITE_VENDOR_DEVICE	(UT_WRITE | UT_VENDOR | UT_DEVICE)
++#define UT_WRITE_VENDOR_INTERFACE (UT_WRITE | UT_VENDOR | UT_INTERFACE)
++#define UT_WRITE_VENDOR_OTHER	(UT_WRITE | UT_VENDOR | UT_OTHER)
++#define UT_WRITE_VENDOR_ENDPOINT (UT_WRITE | UT_VENDOR | UT_ENDPOINT)
++
++/* Requests */
++#define UR_GET_STATUS		0x00
++#define  USTAT_STANDARD_STATUS	0x00
++#define  WUSTAT_WUSB_FEATURE	0x01
++#define  WUSTAT_CHANNEL_INFO	0x02
++#define  WUSTAT_RECEIVED_DATA	0x03
++#define  WUSTAT_MAS_AVAILABILITY 0x04
++#define  WUSTAT_CURRENT_TRANSMIT_POWER 0x05
++#define UR_CLEAR_FEATURE	0x01
++#define UR_SET_FEATURE		0x03
++#define UR_SET_AND_TEST_FEATURE	0x0c
++#define UR_SET_ADDRESS		0x05
++#define UR_GET_DESCRIPTOR	0x06
++#define  UDESC_DEVICE		0x01
++#define  UDESC_CONFIG		0x02
++#define  UDESC_STRING		0x03
++#define  UDESC_INTERFACE	0x04
++#define  UDESC_ENDPOINT		0x05
++#define  UDESC_SS_USB_COMPANION	0x30
++#define  UDESC_DEVICE_QUALIFIER	0x06
++#define  UDESC_OTHER_SPEED_CONFIGURATION 0x07
++#define  UDESC_INTERFACE_POWER	0x08
++#define  UDESC_OTG		0x09
++#define  WUDESC_SECURITY	0x0c
++#define  WUDESC_KEY		0x0d
++#define   WUD_GET_KEY_INDEX(_wValue_) ((_wValue_) & 0xf)
++#define   WUD_GET_KEY_TYPE(_wValue_) (((_wValue_) & 0x30) >> 4)
++#define    WUD_KEY_TYPE_ASSOC	0x01
++#define    WUD_KEY_TYPE_GTK	0x02
++#define   WUD_GET_KEY_ORIGIN(_wValue_) (((_wValue_) & 0x40) >> 6)
++#define    WUD_KEY_ORIGIN_HOST	0x00
++#define    WUD_KEY_ORIGIN_DEVICE 0x01
++#define  WUDESC_ENCRYPTION_TYPE	0x0e
++#define  WUDESC_BOS		0x0f
++#define  WUDESC_DEVICE_CAPABILITY 0x10
++#define  WUDESC_WIRELESS_ENDPOINT_COMPANION 0x11
++#define  UDESC_BOS		0x0f
++#define  UDESC_DEVICE_CAPABILITY 0x10
++#define  UDESC_CS_DEVICE	0x21	/* class specific */
++#define  UDESC_CS_CONFIG	0x22
++#define  UDESC_CS_STRING	0x23
++#define  UDESC_CS_INTERFACE	0x24
++#define  UDESC_CS_ENDPOINT	0x25
++#define  UDESC_HUB		0x29
++#define UR_SET_DESCRIPTOR	0x07
++#define UR_GET_CONFIG		0x08
++#define UR_SET_CONFIG		0x09
++#define UR_GET_INTERFACE	0x0a
++#define UR_SET_INTERFACE	0x0b
++#define UR_SYNCH_FRAME		0x0c
++#define UR_SET_SEL		0x30
++#define UR_SET_ISOC_DELAY	0x31
++#define WUR_SET_ENCRYPTION	0x0d
++#define WUR_GET_ENCRYPTION	0x0e
++#define WUR_SET_HANDSHAKE	0x0f
++#define WUR_GET_HANDSHAKE	0x10
++#define WUR_SET_CONNECTION	0x11
++#define WUR_SET_SECURITY_DATA	0x12
++#define WUR_GET_SECURITY_DATA	0x13
++#define WUR_SET_WUSB_DATA	0x14
++#define  WUDATA_DRPIE_INFO	0x01
++#define  WUDATA_TRANSMIT_DATA	0x02
++#define  WUDATA_TRANSMIT_PARAMS	0x03
++#define  WUDATA_RECEIVE_PARAMS	0x04
++#define  WUDATA_TRANSMIT_POWER	0x05
++#define WUR_LOOPBACK_DATA_WRITE	0x15
++#define WUR_LOOPBACK_DATA_READ	0x16
++#define WUR_SET_INTERFACE_DS	0x17
++
++/* Feature numbers */
++#define UF_ENDPOINT_HALT	0
++#define UF_DEVICE_REMOTE_WAKEUP	1
++#define UF_TEST_MODE		2
++#define UF_DEVICE_B_HNP_ENABLE	3
++#define UF_DEVICE_A_HNP_SUPPORT	4
++#define UF_DEVICE_A_ALT_HNP_SUPPORT 5
++#define WUF_WUSB		3
++#define  WUF_TX_DRPIE		0x0
++#define  WUF_DEV_XMIT_PACKET	0x1
++#define  WUF_COUNT_PACKETS	0x2
++#define  WUF_CAPTURE_PACKETS	0x3
++#define UF_FUNCTION_SUSPEND	0
++#define UF_U1_ENABLE		48
++#define UF_U2_ENABLE		49
++#define UF_LTM_ENABLE		50
++
++/* Class requests from the USB 2.0 hub spec, table 11-15 */
++#define UCR_CLEAR_HUB_FEATURE		(0x2000 | UR_CLEAR_FEATURE)
++#define UCR_CLEAR_PORT_FEATURE		(0x2300 | UR_CLEAR_FEATURE)
++#define UCR_GET_HUB_DESCRIPTOR		(0xa000 | UR_GET_DESCRIPTOR)
++#define UCR_GET_HUB_STATUS		(0xa000 | UR_GET_STATUS)
++#define UCR_GET_PORT_STATUS		(0xa300 | UR_GET_STATUS)
++#define UCR_SET_HUB_FEATURE		(0x2000 | UR_SET_FEATURE)
++#define UCR_SET_PORT_FEATURE		(0x2300 | UR_SET_FEATURE)
++#define UCR_SET_AND_TEST_PORT_FEATURE	(0xa300 | UR_SET_AND_TEST_FEATURE)
++
++#ifdef _MSC_VER
++#include <pshpack1.h>
++#endif
++
++typedef struct {
++	uByte		bLength;
++	uByte		bDescriptorType;
++	uByte		bDescriptorSubtype;
++} UPACKED usb_descriptor_t;
++
++typedef struct {
++	uByte		bLength;
++	uByte		bDescriptorType;
++} UPACKED usb_descriptor_header_t;
++
++typedef struct {
++	uByte		bLength;
++	uByte		bDescriptorType;
++	uWord		bcdUSB;
++#define UD_USB_2_0		0x0200
++#define UD_IS_USB2(d) (UGETW((d)->bcdUSB) >= UD_USB_2_0)
++	uByte		bDeviceClass;
++	uByte		bDeviceSubClass;
++	uByte		bDeviceProtocol;
++	uByte		bMaxPacketSize;
++	/* The fields below are not part of the initial descriptor. */
++	uWord		idVendor;
++	uWord		idProduct;
++	uWord		bcdDevice;
++	uByte		iManufacturer;
++	uByte		iProduct;
++	uByte		iSerialNumber;
++	uByte		bNumConfigurations;
++} UPACKED usb_device_descriptor_t;
++#define USB_DEVICE_DESCRIPTOR_SIZE 18
++
++typedef struct {
++	uByte		bLength;
++	uByte		bDescriptorType;
++	uWord		wTotalLength;
++	uByte		bNumInterface;
++	uByte		bConfigurationValue;
++	uByte		iConfiguration;
++#define UC_ATT_ONE		(1 << 7)	/* must be set */
++#define UC_ATT_SELFPOWER	(1 << 6)	/* self powered */
++#define UC_ATT_WAKEUP		(1 << 5)	/* can wakeup */
++#define UC_ATT_BATTERY		(1 << 4)	/* battery powered */
++	uByte		bmAttributes;
++#define UC_BUS_POWERED		0x80
++#define UC_SELF_POWERED		0x40
++#define UC_REMOTE_WAKEUP	0x20
++	uByte		bMaxPower; /* max current in 2 mA units */
++#define UC_POWER_FACTOR 2
++} UPACKED usb_config_descriptor_t;
++#define USB_CONFIG_DESCRIPTOR_SIZE 9
++
++typedef struct {
++	uByte		bLength;
++	uByte		bDescriptorType;
++	uByte		bInterfaceNumber;
++	uByte		bAlternateSetting;
++	uByte		bNumEndpoints;
++	uByte		bInterfaceClass;
++	uByte		bInterfaceSubClass;
++	uByte		bInterfaceProtocol;
++	uByte		iInterface;
++} UPACKED usb_interface_descriptor_t;
++#define USB_INTERFACE_DESCRIPTOR_SIZE 9
++
++typedef struct {
++	uByte		bLength;
++	uByte		bDescriptorType;
++	uByte		bEndpointAddress;
++#define UE_GET_DIR(a)	((a) & 0x80)
++#define UE_SET_DIR(a,d)	((a) | (((d)&1) << 7))
++#define UE_DIR_IN	0x80
++#define UE_DIR_OUT	0x00
++#define UE_ADDR		0x0f
++#define UE_GET_ADDR(a)	((a) & UE_ADDR)
++	uByte		bmAttributes;
++#define UE_XFERTYPE	0x03
++#define  UE_CONTROL	0x00
++#define  UE_ISOCHRONOUS	0x01
++#define  UE_BULK	0x02
++#define  UE_INTERRUPT	0x03
++#define UE_GET_XFERTYPE(a)	((a) & UE_XFERTYPE)
++#define UE_ISO_TYPE	0x0c
++#define  UE_ISO_ASYNC	0x04
++#define  UE_ISO_ADAPT	0x08
++#define  UE_ISO_SYNC	0x0c
++#define UE_GET_ISO_TYPE(a)	((a) & UE_ISO_TYPE)
++	uWord		wMaxPacketSize;
++	uByte		bInterval;
++} UPACKED usb_endpoint_descriptor_t;
++#define USB_ENDPOINT_DESCRIPTOR_SIZE 7
++
++typedef struct ss_endpoint_companion_descriptor {
++	uByte bLength;
++	uByte bDescriptorType;
++	uByte bMaxBurst;
++#define USSE_GET_MAX_STREAMS(a)		((a) & 0x1f)
++#define USSE_SET_MAX_STREAMS(a, b)	((a) | ((b) & 0x1f))
++#define USSE_GET_MAX_PACKET_NUM(a)	((a) & 0x03)
++#define USSE_SET_MAX_PACKET_NUM(a, b)	((a) | ((b) & 0x03))
++	uByte bmAttributes;
++	uWord wBytesPerInterval;
++} UPACKED ss_endpoint_companion_descriptor_t;
++#define USB_SS_ENDPOINT_COMPANION_DESCRIPTOR_SIZE 6
++
++typedef struct {
++	uByte		bLength;
++	uByte		bDescriptorType;
++	uWord		bString[127];
++} UPACKED usb_string_descriptor_t;
++#define USB_MAX_STRING_LEN 128
++#define USB_LANGUAGE_TABLE 0	/* # of the string language id table */
++
++/* Hub specific request */
++#define UR_GET_BUS_STATE	0x02
++#define UR_CLEAR_TT_BUFFER	0x08
++#define UR_RESET_TT		0x09
++#define UR_GET_TT_STATE		0x0a
++#define UR_STOP_TT		0x0b
++
++/* Hub features */
++#define UHF_C_HUB_LOCAL_POWER	0
++#define UHF_C_HUB_OVER_CURRENT	1
++#define UHF_PORT_CONNECTION	0
++#define UHF_PORT_ENABLE		1
++#define UHF_PORT_SUSPEND	2
++#define UHF_PORT_OVER_CURRENT	3
++#define UHF_PORT_RESET		4
++#define UHF_PORT_L1		5
++#define UHF_PORT_POWER		8
++#define UHF_PORT_LOW_SPEED	9
++#define UHF_PORT_HIGH_SPEED	10
++#define UHF_C_PORT_CONNECTION	16
++#define UHF_C_PORT_ENABLE	17
++#define UHF_C_PORT_SUSPEND	18
++#define UHF_C_PORT_OVER_CURRENT	19
++#define UHF_C_PORT_RESET	20
++#define UHF_C_PORT_L1		23
++#define UHF_PORT_TEST		21
++#define UHF_PORT_INDICATOR	22
++
++typedef struct {
++	uByte		bDescLength;
++	uByte		bDescriptorType;
++	uByte		bNbrPorts;
++	uWord		wHubCharacteristics;
++#define UHD_PWR			0x0003
++#define  UHD_PWR_GANGED		0x0000
++#define  UHD_PWR_INDIVIDUAL	0x0001
++#define  UHD_PWR_NO_SWITCH	0x0002
++#define UHD_COMPOUND		0x0004
++#define UHD_OC			0x0018
++#define  UHD_OC_GLOBAL		0x0000
++#define  UHD_OC_INDIVIDUAL	0x0008
++#define  UHD_OC_NONE		0x0010
++#define UHD_TT_THINK		0x0060
++#define  UHD_TT_THINK_8		0x0000
++#define  UHD_TT_THINK_16	0x0020
++#define  UHD_TT_THINK_24	0x0040
++#define  UHD_TT_THINK_32	0x0060
++#define UHD_PORT_IND		0x0080
++	uByte		bPwrOn2PwrGood;	/* delay in 2 ms units */
++#define UHD_PWRON_FACTOR 2
++	uByte		bHubContrCurrent;
++	uByte		DeviceRemovable[32]; /* max 255 ports */
++#define UHD_NOT_REMOV(desc, i) \
++    (((desc)->DeviceRemovable[(i)/8] >> ((i) % 8)) & 1)
++	/* deprecated */ uByte		PortPowerCtrlMask[1];
++} UPACKED usb_hub_descriptor_t;
++#define USB_HUB_DESCRIPTOR_SIZE 9 /* includes deprecated PortPowerCtrlMask */
++
++typedef struct {
++	uByte		bLength;
++	uByte		bDescriptorType;
++	uWord		bcdUSB;
++	uByte		bDeviceClass;
++	uByte		bDeviceSubClass;
++	uByte		bDeviceProtocol;
++	uByte		bMaxPacketSize0;
++	uByte		bNumConfigurations;
++	uByte		bReserved;
++} UPACKED usb_device_qualifier_t;
++#define USB_DEVICE_QUALIFIER_SIZE 10
++
++typedef struct {
++	uByte		bLength;
++	uByte		bDescriptorType;
++	uByte		bmAttributes;
++#define UOTG_SRP	0x01
++#define UOTG_HNP	0x02
++} UPACKED usb_otg_descriptor_t;
++
++/* OTG feature selectors */
++#define UOTG_B_HNP_ENABLE	3
++#define UOTG_A_HNP_SUPPORT	4
++#define UOTG_A_ALT_HNP_SUPPORT	5
++#define UOTG_NTF_HOST_REL	51
++#define UOTG_B3_RSP_ENABLE	52
++
++typedef struct {
++	uWord		wStatus;
++/* Device status flags */
++#define UDS_SELF_POWERED		0x0001
++#define UDS_REMOTE_WAKEUP		0x0002
++/* Endpoint status flags */
++#define UES_HALT			0x0001
++} UPACKED usb_status_t;
++
++typedef struct {
++	uWord		wHubStatus;
++#define UHS_LOCAL_POWER			0x0001
++#define UHS_OVER_CURRENT		0x0002
++	uWord		wHubChange;
++} UPACKED usb_hub_status_t;
++
++typedef struct {
++	uWord		wPortStatus;
++#define UPS_CURRENT_CONNECT_STATUS	0x0001
++#define UPS_PORT_ENABLED		0x0002
++#define UPS_SUSPEND			0x0004
++#define UPS_OVERCURRENT_INDICATOR	0x0008
++#define UPS_RESET			0x0010
++#define UPS_PORT_POWER			0x0100
++#define UPS_LOW_SPEED			0x0200
++#define UPS_HIGH_SPEED			0x0400
++#define UPS_PORT_TEST			0x0800
++#define UPS_PORT_INDICATOR		0x1000
++	uWord		wPortChange;
++#define UPS_C_CONNECT_STATUS		0x0001
++#define UPS_C_PORT_ENABLED		0x0002
++#define UPS_C_SUSPEND			0x0004
++#define UPS_C_OVERCURRENT_INDICATOR	0x0008
++#define UPS_C_PORT_RESET		0x0010
++} UPACKED usb_port_status_t;
++
++#ifdef _MSC_VER
++#include <poppack.h>
++#endif
++
++/* Device class codes */
++#define UDCLASS_IN_INTERFACE	0x00
++#define UDCLASS_COMM		0x02
++#define UDCLASS_HUB		0x09
++#define  UDSUBCLASS_HUB		0x00
++#define  UDPROTO_FSHUB		0x00
++#define  UDPROTO_HSHUBSTT	0x01
++#define  UDPROTO_HSHUBMTT	0x02
++#define UDCLASS_DIAGNOSTIC	0xdc
++#define UDCLASS_WIRELESS	0xe0
++#define  UDSUBCLASS_RF		0x01
++#define   UDPROTO_BLUETOOTH	0x01
++#define UDCLASS_VENDOR		0xff
++
++/* Interface class codes */
++#define UICLASS_UNSPEC		0x00
++
++#define UICLASS_AUDIO		0x01
++#define  UISUBCLASS_AUDIOCONTROL	1
++#define  UISUBCLASS_AUDIOSTREAM		2
++#define  UISUBCLASS_MIDISTREAM		3
++
++#define UICLASS_CDC		0x02 /* communication */
++#define  UISUBCLASS_DIRECT_LINE_CONTROL_MODEL	1
++#define  UISUBCLASS_ABSTRACT_CONTROL_MODEL	2
++#define  UISUBCLASS_TELEPHONE_CONTROL_MODEL	3
++#define  UISUBCLASS_MULTICHANNEL_CONTROL_MODEL	4
++#define  UISUBCLASS_CAPI_CONTROLMODEL		5
++#define  UISUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL 6
++#define  UISUBCLASS_ATM_NETWORKING_CONTROL_MODEL 7
++#define   UIPROTO_CDC_AT			1
++
++#define UICLASS_HID		0x03
++#define  UISUBCLASS_BOOT	1
++#define  UIPROTO_BOOT_KEYBOARD	1
++
++#define UICLASS_PHYSICAL	0x05
++
++#define UICLASS_IMAGE		0x06
++
++#define UICLASS_PRINTER		0x07
++#define  UISUBCLASS_PRINTER	1
++#define  UIPROTO_PRINTER_UNI	1
++#define  UIPROTO_PRINTER_BI	2
++#define  UIPROTO_PRINTER_1284	3
++
++#define UICLASS_MASS		0x08
++#define  UISUBCLASS_RBC		1
++#define  UISUBCLASS_SFF8020I	2
++#define  UISUBCLASS_QIC157	3
++#define  UISUBCLASS_UFI		4
++#define  UISUBCLASS_SFF8070I	5
++#define  UISUBCLASS_SCSI	6
++#define  UIPROTO_MASS_CBI_I	0
++#define  UIPROTO_MASS_CBI	1
++#define  UIPROTO_MASS_BBB_OLD	2	/* Not in the spec anymore */
++#define  UIPROTO_MASS_BBB	80	/* 'P' for the Iomega Zip drive */
++
++#define UICLASS_HUB		0x09
++#define  UISUBCLASS_HUB		0
++#define  UIPROTO_FSHUB		0
++#define  UIPROTO_HSHUBSTT	0 /* Yes, same as previous */
++#define  UIPROTO_HSHUBMTT	1
++
++#define UICLASS_CDC_DATA	0x0a
++#define  UISUBCLASS_DATA		0
++#define   UIPROTO_DATA_ISDNBRI		0x30    /* Physical iface */
++#define   UIPROTO_DATA_HDLC		0x31    /* HDLC */
++#define   UIPROTO_DATA_TRANSPARENT	0x32    /* Transparent */
++#define   UIPROTO_DATA_Q921M		0x50    /* Management for Q921 */
++#define   UIPROTO_DATA_Q921		0x51    /* Data for Q921 */
++#define   UIPROTO_DATA_Q921TM		0x52    /* TEI multiplexer for Q921 */
++#define   UIPROTO_DATA_V42BIS		0x90    /* Data compression */
++#define   UIPROTO_DATA_Q931		0x91    /* Euro-ISDN */
++#define   UIPROTO_DATA_V120		0x92    /* V.24 rate adaption */
++#define   UIPROTO_DATA_CAPI		0x93    /* CAPI 2.0 commands */
++#define   UIPROTO_DATA_HOST_BASED	0xfd    /* Host based driver */
++#define   UIPROTO_DATA_PUF		0xfe    /* see Prot. Unit Func. Desc.*/
++#define   UIPROTO_DATA_VENDOR		0xff    /* Vendor specific */
++
++#define UICLASS_SMARTCARD	0x0b
++
++/*#define UICLASS_FIRM_UPD	0x0c*/
++
++#define UICLASS_SECURITY	0x0d
++
++#define UICLASS_DIAGNOSTIC	0xdc
++
++#define UICLASS_WIRELESS	0xe0
++#define  UISUBCLASS_RF			0x01
++#define   UIPROTO_BLUETOOTH		0x01
++
++#define UICLASS_APPL_SPEC	0xfe
++#define  UISUBCLASS_FIRMWARE_DOWNLOAD	1
++#define  UISUBCLASS_IRDA		2
++#define  UIPROTO_IRDA			0
++
++#define UICLASS_VENDOR		0xff
++
++#define USB_HUB_MAX_DEPTH 5
++
++/*
++ * Minimum time a device needs to be powered down to go through
++ * a power cycle.  XXX Are these time in the spec?
++ */
++#define USB_POWER_DOWN_TIME	200 /* ms */
++#define USB_PORT_POWER_DOWN_TIME	100 /* ms */
++
++#if 0
++/* These are the values from the spec. */
++#define USB_PORT_RESET_DELAY	10  /* ms */
++#define USB_PORT_ROOT_RESET_DELAY 50  /* ms */
++#define USB_PORT_RESET_RECOVERY	10  /* ms */
++#define USB_PORT_POWERUP_DELAY	100 /* ms */
++#define USB_SET_ADDRESS_SETTLE	2   /* ms */
++#define USB_RESUME_DELAY	(20*5)  /* ms */
++#define USB_RESUME_WAIT		10  /* ms */
++#define USB_RESUME_RECOVERY	10  /* ms */
++#define USB_EXTRA_POWER_UP_TIME	0   /* ms */
++#else
++/* Allow for marginal (i.e. non-conforming) devices. */
++#define USB_PORT_RESET_DELAY	50  /* ms */
++#define USB_PORT_ROOT_RESET_DELAY 250  /* ms */
++#define USB_PORT_RESET_RECOVERY	250  /* ms */
++#define USB_PORT_POWERUP_DELAY	300 /* ms */
++#define USB_SET_ADDRESS_SETTLE	10  /* ms */
++#define USB_RESUME_DELAY	(50*5)  /* ms */
++#define USB_RESUME_WAIT		50  /* ms */
++#define USB_RESUME_RECOVERY	50  /* ms */
++#define USB_EXTRA_POWER_UP_TIME	20  /* ms */
++#endif
++
++#define USB_MIN_POWER		100 /* mA */
++#define USB_MAX_POWER		500 /* mA */
++
++#define USB_BUS_RESET_DELAY	100 /* ms XXX?*/
++
++#define USB_UNCONFIG_NO 0
++#define USB_UNCONFIG_INDEX (-1)
++
++/*** ioctl() related stuff ***/
++
++struct usb_ctl_request {
++	int	ucr_addr;
++	usb_device_request_t ucr_request;
++	void	*ucr_data;
++	int	ucr_flags;
++#define USBD_SHORT_XFER_OK	0x04	/* allow short reads */
++	int	ucr_actlen;		/* actual length transferred */
++};
++
++struct usb_alt_interface {
++	int	uai_config_index;
++	int	uai_interface_index;
++	int	uai_alt_no;
++};
++
++#define USB_CURRENT_CONFIG_INDEX (-1)
++#define USB_CURRENT_ALT_INDEX (-1)
++
++struct usb_config_desc {
++	int	ucd_config_index;
++	usb_config_descriptor_t ucd_desc;
++};
++
++struct usb_interface_desc {
++	int	uid_config_index;
++	int	uid_interface_index;
++	int	uid_alt_index;
++	usb_interface_descriptor_t uid_desc;
++};
++
++struct usb_endpoint_desc {
++	int	ued_config_index;
++	int	ued_interface_index;
++	int	ued_alt_index;
++	int	ued_endpoint_index;
++	usb_endpoint_descriptor_t ued_desc;
++};
++
++struct usb_full_desc {
++	int	ufd_config_index;
++	u_int	ufd_size;
++	u_char	*ufd_data;
++};
++
++struct usb_string_desc {
++	int	usd_string_index;
++	int	usd_language_id;
++	usb_string_descriptor_t usd_desc;
++};
++
++struct usb_ctl_report_desc {
++	int	ucrd_size;
++	u_char	ucrd_data[1024];	/* filled data size will vary */
++};
++
++typedef struct { u_int32_t cookie; } usb_event_cookie_t;
++
++#define USB_MAX_DEVNAMES 4
++#define USB_MAX_DEVNAMELEN 16
++struct usb_device_info {
++	u_int8_t	udi_bus;
++	u_int8_t	udi_addr;	/* device address */
++	usb_event_cookie_t udi_cookie;
++	char		udi_product[USB_MAX_STRING_LEN];
++	char		udi_vendor[USB_MAX_STRING_LEN];
++	char		udi_release[8];
++	u_int16_t	udi_productNo;
++	u_int16_t	udi_vendorNo;
++	u_int16_t	udi_releaseNo;
++	u_int8_t	udi_class;
++	u_int8_t	udi_subclass;
++	u_int8_t	udi_protocol;
++	u_int8_t	udi_config;
++	u_int8_t	udi_speed;
++#define USB_SPEED_UNKNOWN	0
++#define USB_SPEED_LOW		1
++#define USB_SPEED_FULL		2
++#define USB_SPEED_HIGH		3
++#define USB_SPEED_VARIABLE	4
++#define USB_SPEED_SUPER		5
++	int		udi_power;	/* power consumption in mA, 0 if selfpowered */
++	int		udi_nports;
++	char		udi_devnames[USB_MAX_DEVNAMES][USB_MAX_DEVNAMELEN];
++	u_int8_t	udi_ports[16];/* hub only: addresses of devices on ports */
++#define USB_PORT_ENABLED 0xff
++#define USB_PORT_SUSPENDED 0xfe
++#define USB_PORT_POWERED 0xfd
++#define USB_PORT_DISABLED 0xfc
++};
++
++struct usb_ctl_report {
++	int	ucr_report;
++	u_char	ucr_data[1024];	/* filled data size will vary */
++};
++
++struct usb_device_stats {
++	u_long	uds_requests[4];	/* indexed by transfer type UE_* */
++};
++
++#define WUSB_MIN_IE			0x80
++#define WUSB_WCTA_IE			0x80
++#define WUSB_WCONNECTACK_IE		0x81
++#define WUSB_WHOSTINFO_IE		0x82
++#define  WUHI_GET_CA(_bmAttributes_) ((_bmAttributes_) & 0x3)
++#define   WUHI_CA_RECONN		0x00
++#define   WUHI_CA_LIMITED		0x01
++#define   WUHI_CA_ALL			0x03
++#define  WUHI_GET_MLSI(_bmAttributes_) (((_bmAttributes_) & 0x38) >> 3)
++#define WUSB_WCHCHANGEANNOUNCE_IE	0x83
++#define WUSB_WDEV_DISCONNECT_IE		0x84
++#define WUSB_WHOST_DISCONNECT_IE	0x85
++#define WUSB_WRELEASE_CHANNEL_IE	0x86
++#define WUSB_WWORK_IE			0x87
++#define WUSB_WCHANNEL_STOP_IE		0x88
++#define WUSB_WDEV_KEEPALIVE_IE		0x89
++#define WUSB_WISOCH_DISCARD_IE		0x8A
++#define WUSB_WRESETDEVICE_IE		0x8B
++#define WUSB_WXMIT_PACKET_ADJUST_IE	0x8C
++#define WUSB_MAX_IE			0x8C
++
++/* Device Notification Types */
++
++#define WUSB_DN_MIN			0x01
++#define WUSB_DN_CONNECT			0x01
++# define WUSB_DA_OLDCONN	0x00
++# define WUSB_DA_NEWCONN	0x01
++# define WUSB_DA_SELF_BEACON	0x02
++# define WUSB_DA_DIR_BEACON	0x04
++# define WUSB_DA_NO_BEACON	0x06
++#define WUSB_DN_DISCONNECT		0x02
++#define WUSB_DN_EPRDY			0x03
++#define WUSB_DN_MASAVAILCHANGED		0x04
++#define WUSB_DN_REMOTEWAKEUP		0x05
++#define WUSB_DN_SLEEP			0x06
++#define WUSB_DN_ALIVE			0x07
++#define WUSB_DN_MAX			0x07
++
++#ifdef _MSC_VER
++#include <pshpack1.h>
++#endif
++
++/* WUSB Handshake Data.  Used during the SET/GET HANDSHAKE requests */
++typedef struct wusb_hndshk_data {
++	uByte bMessageNumber;
++	uByte bStatus;
++	uByte tTKID[3];
++	uByte bReserved;
++	uByte CDID[16];
++	uByte Nonce[16];
++	uByte MIC[8];
++} UPACKED wusb_hndshk_data_t;
++#define WUSB_HANDSHAKE_LEN_FOR_MIC	38
++
++/* WUSB Connection Context */
++typedef struct wusb_conn_context {
++	uByte CHID [16];
++	uByte CDID [16];
++	uByte CK [16];
++} UPACKED wusb_conn_context_t;
++
++/* WUSB Security Descriptor */
++typedef struct wusb_security_desc {
++	uByte bLength;
++	uByte bDescriptorType;
++	uWord wTotalLength;
++	uByte bNumEncryptionTypes;
++} UPACKED wusb_security_desc_t;
++
++/* WUSB Encryption Type Descriptor */
++typedef struct wusb_encrypt_type_desc {
++	uByte bLength;
++	uByte bDescriptorType;
++
++	uByte bEncryptionType;
++#define WUETD_UNSECURE		0
++#define WUETD_WIRED		1
++#define WUETD_CCM_1		2
++#define WUETD_RSA_1		3
++
++	uByte bEncryptionValue;
++	uByte bAuthKeyIndex;
++} UPACKED wusb_encrypt_type_desc_t;
++
++/* WUSB Key Descriptor */
++typedef struct wusb_key_desc {
++	uByte bLength;
++	uByte bDescriptorType;
++	uByte tTKID[3];
++	uByte bReserved;
++	uByte KeyData[1];	/* variable length */
++} UPACKED wusb_key_desc_t;
++
++/* WUSB BOS Descriptor (Binary device Object Store) */
++typedef struct wusb_bos_desc {
++	uByte bLength;
++	uByte bDescriptorType;
++	uWord wTotalLength;
++	uByte bNumDeviceCaps;
++} UPACKED wusb_bos_desc_t;
++
++#define USB_DEVICE_CAPABILITY_20_EXTENSION	0x02
++typedef struct usb_dev_cap_20_ext_desc {
++	uByte bLength;
++	uByte bDescriptorType;
++	uByte bDevCapabilityType;
++#define USB_20_EXT_LPM				0x02
++#define USB_20_EXT_BESL				0x04
++#define USB_20_EXT_BASELINE_BESL_VALID		0x08
++#define USB_20_EXT_DEEP_BESL_VALID		0x10
++#define USB_20_EXT_BASELINE_BESL_BITS		0x00f00
++#define USB_20_EXT_BASELINE_BESL_SHIFT		8
++#define USB_20_EXT_DEEP_BESL_BITS		0x0f000
++#define USB_20_EXT_DEEP_BESL_SHIFT		12
++	uDWord bmAttributes;
++} UPACKED usb_dev_cap_20_ext_desc_t;
++
++#define USB_DEVICE_CAPABILITY_SS_USB		0x03
++typedef struct usb_dev_cap_ss_usb {
++	uByte bLength;
++	uByte bDescriptorType;
++	uByte bDevCapabilityType;
++#define USB_DC_SS_USB_LTM_CAPABLE		0x02
++	uByte bmAttributes;
++#define USB_DC_SS_USB_SPEED_SUPPORT_LOW		0x01
++#define USB_DC_SS_USB_SPEED_SUPPORT_FULL	0x02
++#define USB_DC_SS_USB_SPEED_SUPPORT_HIGH	0x04
++#define USB_DC_SS_USB_SPEED_SUPPORT_SS		0x08
++	uWord wSpeedsSupported;
++	uByte bFunctionalitySupport;
++	uByte bU1DevExitLat;
++	uWord wU2DevExitLat;
++} UPACKED usb_dev_cap_ss_usb_t;
++
++#define USB_DEVICE_CAPABILITY_CONTAINER_ID	0x04
++typedef struct usb_dev_cap_container_id {
++	uByte bLength;
++	uByte bDescriptorType;
++	uByte bDevCapabilityType;
++	uByte bReserved;
++	uByte containerID[16];
++} UPACKED usb_dev_cap_container_id_t;
++
++/* Device Capability Type Codes */
++#define WUSB_DEVICE_CAPABILITY_WIRELESS_USB 0x01
++
++/* Device Capability Descriptor */
++typedef struct wusb_dev_cap_desc {
++	uByte bLength;
++	uByte bDescriptorType;
++	uByte bDevCapabilityType;
++	uByte caps[1];	/* Variable length */
++} UPACKED wusb_dev_cap_desc_t;
++
++/* Device Capability Descriptor */
++typedef struct wusb_dev_cap_uwb_desc {
++	uByte bLength;
++	uByte bDescriptorType;
++	uByte bDevCapabilityType;
++	uByte bmAttributes;
++	uWord wPHYRates;	/* Bitmap */
++	uByte bmTFITXPowerInfo;
++	uByte bmFFITXPowerInfo;
++	uWord bmBandGroup;
++	uByte bReserved;
++} UPACKED wusb_dev_cap_uwb_desc_t;
++
++/* Wireless USB Endpoint Companion Descriptor */
++typedef struct wusb_endpoint_companion_desc {
++	uByte bLength;
++	uByte bDescriptorType;
++	uByte bMaxBurst;
++	uByte bMaxSequence;
++	uWord wMaxStreamDelay;
++	uWord wOverTheAirPacketSize;
++	uByte bOverTheAirInterval;
++	uByte bmCompAttributes;
++} UPACKED wusb_endpoint_companion_desc_t;
++
++/* Wireless USB Numeric Association M1 Data Structure */
++typedef struct wusb_m1_data {
++	uByte version;
++	uWord langId;
++	uByte deviceFriendlyNameLength;
++	uByte sha_256_m3[32];
++	uByte deviceFriendlyName[256];
++} UPACKED wusb_m1_data_t;
++
++typedef struct wusb_m2_data {
++	uByte version;
++	uWord langId;
++	uByte hostFriendlyNameLength;
++	uByte pkh[384];
++	uByte hostFriendlyName[256];
++} UPACKED wusb_m2_data_t;
++
++typedef struct wusb_m3_data {
++	uByte pkd[384];
++	uByte nd;
++} UPACKED wusb_m3_data_t;
++
++typedef struct wusb_m4_data {
++	uDWord _attributeTypeIdAndLength_1;
++	uWord  associationTypeId;
++
++	uDWord _attributeTypeIdAndLength_2;
++	uWord  associationSubTypeId;
++
++	uDWord _attributeTypeIdAndLength_3;
++	uDWord length;
++
++	uDWord _attributeTypeIdAndLength_4;
++	uDWord associationStatus;
++
++	uDWord _attributeTypeIdAndLength_5;
++	uByte  chid[16];
++
++	uDWord _attributeTypeIdAndLength_6;
++	uByte  cdid[16];
++
++	uDWord _attributeTypeIdAndLength_7;
++	uByte  bandGroups[2];
++} UPACKED wusb_m4_data_t;
++
++#ifdef _MSC_VER
++#include <poppack.h>
++#endif
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* _USB_H_ */
+diff --git a/drivers/usb/gadget/udc/hiudc3/ute_if.c b/drivers/usb/gadget/udc/hiudc3/ute_if.c
+new file mode 100644
+index 0000000..0e00835
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc3/ute_if.c
+@@ -0,0 +1,574 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/DWC_usb3/driver/linux/ute_if.c $
++ * $Revision: #11 $
++ * $Date: 2014/11/11 $
++ * $Change: 2664766 $
++ *
++ * Synopsys SS USB3 Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
++ * ========================================================================== */
++
++/** @file
++ *
++ */
++
++#include "os_defs.h"
++#include "hw.h"
++#include "usb.h"
++#include "pcd.h"
++#include "dev.h"
++#include "os_dev.h"
++#include "cil.h"
++#include "dwc_pcd_cfi.h"
++#include "ute_if.h"
++
++static struct cfi_ft_lst pcd_feats = {
++	.hdr = {
++		//.totlen		= (set at runtime),
++		.cfiver			= 0x100,
++		.coreID			= 4,
++		//.ftcount		= (set at runtime),
++	},
++	.desc[0] = {		/* Rx FIFO size */
++		.ftparm = {
++			.fid		= UTE_FID_RXFIFO_SIZE,
++			.paramcount	= 1,
++			.param1		= 0xffffffff,	/* shared */
++		},
++		//.fdlen		= sizeof(struct cfi_feature_desc),
++		.dlen			= 4,
++		.bmattr			= FT_ATTR_RW,
++		.ftname			= "rxfsz",
++	},
++	.desc[1] = {		/* Tx FIFO 0 size */
++		.ftparm = {
++			.fid		= UTE_FID_TXFIFO_SIZE,
++			.paramcount	= 1,
++			.param1		= 0,
++		},
++		//.fdlen		= sizeof(struct cfi_feature_desc),
++		.dlen			= 4,
++		.bmattr			= FT_ATTR_RW,
++		.ftname			= "txfsz0",
++	},
++	.desc[2] = {		/* Tx FIFO 1 size */
++		.ftparm = {
++			.fid		= UTE_FID_TXFIFO_SIZE,
++			.paramcount	= 1,
++			.param1		= 1,
++		},
++		//.fdlen		= sizeof(struct cfi_feature_desc),
++		.dlen			= 4,
++		.bmattr			= FT_ATTR_RW,
++		.ftname			= "txfsiz1",
++	},
++	.desc[3] = {		/* Tx FIFO 2 size */
++		.ftparm = {
++			.fid		= UTE_FID_TXFIFO_SIZE,
++			.paramcount	= 1,
++			.param1		= 2,
++		},
++		//.fdlen		= sizeof(struct cfi_feature_desc),
++		.dlen			= 4,
++		.bmattr			= FT_ATTR_RW,
++		.ftname			= "txfsz2",
++	},
++	.desc[4] = {		/* Tx FIFO 3 size */
++		.ftparm = {
++			.fid		= UTE_FID_TXFIFO_SIZE,
++			.paramcount	= 1,
++			.param1		= 3,
++		},
++		//.fdlen		= sizeof(struct cfi_feature_desc),
++		.dlen			= 4,
++		.bmattr			= FT_ATTR_RW,
++		.ftname			= "txfsz3",
++	},
++	.desc[5] = {		/* FIFO 0 physical EP mapping */
++		.ftparm = {
++			.fid		= UTE_FID_TXFIFO_MAP,
++			.paramcount	= 1,
++			.param1		= 0,
++		},
++		//.fdlen		= sizeof(struct cfi_feature_desc),
++		.dlen			= 4,
++		.bmattr			= FT_ATTR_RW,
++		.ftname			= "txfmap0",
++	},
++	.desc[6] = {		/* FIFO 1 physical EP mapping */
++		.ftparm = {
++			.fid		= UTE_FID_TXFIFO_MAP,
++			.paramcount	= 1,
++			.param1		= 1,
++		},
++		//.fdlen		= sizeof(struct cfi_feature_desc),
++		.dlen			= 4,
++		.bmattr			= FT_ATTR_RW,
++		.ftname			= "txfmap1",
++	},
++	.desc[7] = {		/* FIFO 2 physical EP mapping */
++		.ftparm = {
++			.fid		= UTE_FID_TXFIFO_MAP,
++			.paramcount	= 1,
++			.param1		= 2,
++		},
++		//.fdlen		= sizeof(struct cfi_feature_desc),
++		.dlen			= 4,
++		.bmattr			= FT_ATTR_RW,
++		.ftname			= "txfmap2",
++	},
++	.desc[8] = {		/* FIFO 3 physical EP mapping */
++		.ftparm = {
++			.fid		= UTE_FID_TXFIFO_MAP,
++			.paramcount	= 1,
++			.param1		= 3,
++		},
++		//.fdlen		= sizeof(struct cfi_feature_desc),
++		.dlen			= 4,
++		.bmattr			= FT_ATTR_RW,
++		.ftname			= "txfmap3",
++	},
++	.desc[9] = {		/* Physical OUT EP 1 USB EP mapping */
++		.ftparm = {
++			.fid		= UTE_FID_EP_MAP,
++			.paramcount	= 1,
++			.param1		= 0x01,
++		},
++		//.fdlen		= sizeof(struct cfi_feature_desc),
++		.dlen			= 4,
++		.bmattr			= FT_ATTR_RW,
++		.ftname			= "epmap1-out",
++	},
++	.desc[10] = {		/* Physical IN EP 1 USB EP mapping */
++		.ftparm = {
++			.fid		= UTE_FID_EP_MAP,
++			.paramcount	= 1,
++			.param1		= 0x11,
++		},
++		//.fdlen		= sizeof(struct cfi_feature_desc),
++		.dlen			= 4,
++		.bmattr			= FT_ATTR_RW,
++		.ftname			= "epmap1-in",
++	},
++	.desc[11] = {		/* Physical OUT EP 2 USB EP mapping */
++		.ftparm = {
++			.fid		= UTE_FID_EP_MAP,
++			.paramcount	= 1,
++			.param1		= 0x02,
++		},
++		//.fdlen		= sizeof(struct cfi_feature_desc),
++		.dlen			= 4,
++		.bmattr			= FT_ATTR_RW,
++		.ftname			= "epmap2-out",
++	},
++	.desc[12] = {		/* Physical IN EP 2 USB EP mapping */
++		.ftparm = {
++			.fid		= UTE_FID_EP_MAP,
++			.paramcount	= 1,
++			.param1		= 0x12,
++		},
++		//.fdlen		= sizeof(struct cfi_feature_desc),
++		.dlen			= 4,
++		.bmattr			= FT_ATTR_RW,
++		.ftname			= "epmap2-in",
++	},
++	.desc[13] = {		/* Physical OUT EP 3 USB EP mapping */
++		.ftparm = {
++			.fid		= UTE_FID_EP_MAP,
++			.paramcount	= 1,
++			.param1		= 0x03,
++		},
++		//.fdlen		= sizeof(struct cfi_feature_desc),
++		.dlen			= 4,
++		.bmattr			= FT_ATTR_RW,
++		.ftname			= "epmap3-out",
++	},
++	.desc[14] = {		/* Physical IN EP 3 USB EP mapping */
++		.ftparm = {
++			.fid		= UTE_FID_EP_MAP,
++			.paramcount	= 1,
++			.param1		= 0x13,
++		},
++		//.fdlen		= sizeof(struct cfi_feature_desc),
++		.dlen			= 4,
++		.bmattr			= FT_ATTR_RW,
++		.ftname			= "epmap3-in",
++	},
++	.desc[15] = {		/* Super Speed */
++		.ftparm = {
++			.fid		= UTE_FID_DEV_SPEED,
++			.paramcount	= 1,
++			.param1		= 0xffffffff,
++		},
++		//.fdlen		= sizeof(struct cfi_feature_desc),
++		.dlen			= 4,
++		.bmattr			= FT_ATTR_RW,
++		.ftname			= "dev speed",
++	},
++};
++
++static void *cficb_get_ft_list(struct cfiobject *cfi)
++{
++	return cfi->features;
++}
++
++static int cficb_get_ft_value(struct cfiobject *cfi,
++			      struct cfi_ft_params *params,
++			      unsigned long valptr)
++{
++	dwc_usb3_pcd_t *pcd;
++	dwc_usb3_device_t *dev;
++	dwc_usb3_core_global_regs_t __iomem *global_regs;
++	unsigned val, index, ram_width;
++	int ret = 0;
++
++	printk(KERN_DEBUG USB3_DWC "%s(%p,%p,%1lx)\n", __func__,
++	       cfi, params, valptr);
++	pcd = cfi->pcd;
++	printk(KERN_DEBUG USB3_DWC "pcd=%p\n", pcd);
++	dev = pcd->usb3_dev;
++	if (params) {
++		printk(KERN_DEBUG USB3_DWC "params->param1=%1x ->fid=%1d\n",
++		       params->param1, params->fid);
++	} else {
++		printk(KERN_ERR USB3_DWC "params=NULL!\n");
++		return -EINVAL;
++	}
++	if (!valptr) {
++		printk(KERN_ERR USB3_DWC "valptr=NULL!\n");
++		return -EINVAL;
++	}
++
++	switch (params->fid) {
++	case UTE_FID_RXFIFO_SIZE:
++		/* get Rx FIFO size */
++		/* val is FIFO size in bytes */
++		if (params->param1 != 0xffffffff) {
++			ret = -EINVAL;
++		} else {
++			global_regs = dev->core_global_regs;
++			val = dwc_rd32(dev, &global_regs->grxfifosiz[0]);
++			val = (val >> DWC_FIFOSZ_DEPTH_SHIFT) &
++			      (DWC_FIFOSZ_DEPTH_BITS >> DWC_FIFOSZ_DEPTH_SHIFT);
++			ram_width =
++			     ((dev->hwparams0 >> DWC_HWP0_MDWIDTH_SHIFT) &
++			      (DWC_HWP0_MDWIDTH_BITS >> DWC_HWP0_MDWIDTH_SHIFT))
++			     / 8;
++			val *= ram_width;
++			*(unsigned *)valptr = val;
++		}
++		break;
++
++	case UTE_FID_TXFIFO_SIZE:
++		/* get Tx FIFO size */
++		/* param1 is Tx FIFO #, val is FIFO size in bytes */
++		if (params->param1 >= DWC_MAX_TX_FIFOS) {
++			ret = -EINVAL;
++		} else {
++			global_regs = dev->core_global_regs;
++			val = dwc_rd32(dev,
++				&global_regs->gtxfifosiz[params->param1]);
++			val = (val >> DWC_FIFOSZ_DEPTH_SHIFT) &
++			      (DWC_FIFOSZ_DEPTH_BITS >> DWC_FIFOSZ_DEPTH_SHIFT);
++			ram_width =
++			     ((dev->hwparams0 >> DWC_HWP0_MDWIDTH_SHIFT) &
++			      (DWC_HWP0_MDWIDTH_BITS >> DWC_HWP0_MDWIDTH_SHIFT))
++			     / 8;
++			val *= ram_width;
++			*(unsigned *)valptr = val;
++		}
++		break;
++
++	case UTE_FID_RXFIFO_MAP:
++		/* Rx FIFO mapping not possible for USB3 core */
++		ret = -EINVAL;
++		break;
++
++	case UTE_FID_TXFIFO_MAP:
++		/* get Tx FIFO mapping */
++		/* param1 is Tx FIFO #, val is physical EP # */
++		if (params->param1 >= DWC_MAX_TX_FIFOS) {
++			ret = -EINVAL;
++		} else {
++			/* find matching FIFO # in EP array */
++			for (index = 1; index < DWC_MAX_PHYS_EP; index += 2) {
++				if (pcd->txf_map[index] == params->param1)
++					break;
++			}
++			if (index >= DWC_MAX_PHYS_EP) {
++				ret = -EINVAL;
++			} else {
++				/* convert EP array index to physical EP # */
++				/* Note: have to drop the direction bit, UTE
++				 * doesn't expect it to be set
++				 */
++				val = (index >> 1) & 0xf;
++				*(unsigned *)valptr = val;
++			}
++		}
++		break;
++
++	case UTE_FID_EP_MAP:
++		/* get EP mapping */
++		/* param1 is physical EP #, val is USB EP # */
++		index = (params->param1 & 0xf) << 1 |
++			((params->param1 >> 4) & 0x1);
++		ret = dwc_usb3_get_usb_ep_map(0, index, &val);
++		if (!ret)
++			*(unsigned *)valptr = val;
++		break;
++	case UTE_FID_DEV_SPEED:
++		/* get current device speed */
++		val = dwc_usb3_get_dev_speed(0);
++		*(unsigned *)valptr = val;
++		break;
++
++	default:
++		ret = -EINVAL;
++	}
++
++	if (ret == 0)
++		printk(KERN_DEBUG USB3_DWC "*valptr=%1x\n",
++		       *(unsigned *)valptr);
++	return ret;
++}
++
++static void reset_txfifosize_ft_value(struct cfiobject *cfi)
++{
++	int i;
++	dwc_usb3_pcd_t *pcd = cfi->pcd;
++
++	for (i = 0; i < DWC_MAX_TX_FIFOS; i++) {
++		pcd->txf_size[i] = pcd->def_txf_size[i];
++	}
++}
++
++static void reset_txfifomap_ft_value(struct cfiobject *cfi)
++{
++	int i;
++	dwc_usb3_pcd_t *pcd = cfi->pcd;
++
++	for (i = 0; i < pcd->num_in_eps + 1; i++) {
++		pcd->txf_map[(i << 1) | 1] = i;
++	}
++}
++
++static int cficb_reset_ft_value(struct cfiobject *cfi,
++				struct cfi_ft_params *params)
++{
++	int ret = 0;
++	dwc_usb3_pcd_t *pcd = cfi->pcd;
++
++	printk(KERN_DEBUG USB3_DWC "%s(%p,%p)\n", __func__, cfi, params);
++
++	if (params) {
++		printk(KERN_DEBUG USB3_DWC "params->param1=%1x ->fid=%1d\n",
++		       params->param1, params->fid);
++	} else {
++		printk(KERN_ERR USB3_DWC "params=NULL!\n");
++		return -EINVAL;
++	}
++
++	switch (params->fid) {
++		case UTE_FID_EP_MAP:
++			if (params->param1 == 0)
++				ret = dwc_usb3_reset_usb_ep_map(0);
++			break;
++		case UTE_FID_RXFIFO_SIZE:
++			if (params->param1 == 0 && pcd->rxf_size != 0) {
++				pcd->rxf_size = pcd->def_rxf_size;
++				pcd->ute_change = 1;
++			}
++			break;
++		case UTE_FID_TXFIFO_SIZE:
++			if (params->param1 == 0) {
++				reset_txfifosize_ft_value(cfi);
++				pcd->ute_change = 1;
++			}
++			break;
++		case UTE_FID_TXFIFO_MAP:
++			if (params->param1) {
++				reset_txfifomap_ft_value(cfi);
++				pcd->ute_change = 1;
++			}
++			break;
++		default:
++			ret = -ENOTSUPP;
++			break;
++	}
++
++	if (ret == 0)
++		pcd->ute_change = 1;
++
++	return ret;
++}
++
++
++static int cficb_set_ft_value(struct cfiobject *cfi,
++			      struct cfi_ft_params *params,
++			      unsigned long valptr)
++{
++	dwc_usb3_pcd_t *pcd;
++	unsigned val, index;
++	int ret = 0;
++
++	printk(KERN_DEBUG USB3_DWC "%s(%p,%p,%1lx)\n", __func__,
++	       cfi, params, valptr);
++	pcd = cfi->pcd;
++	printk(KERN_DEBUG USB3_DWC "pcd=%p\n", pcd);
++	if (params) {
++		printk(KERN_DEBUG USB3_DWC "params->param1=%1x ->fid=%1d\n",
++		       params->param1, params->fid);
++	} else {
++		printk(KERN_ERR USB3_DWC "params=NULL!\n");
++		return -EINVAL;
++	}
++	if (valptr) {
++		printk(KERN_DEBUG USB3_DWC "*valptr=%1x\n",
++		       *(unsigned *)valptr);
++	} else {
++		printk(KERN_ERR USB3_DWC "valptr=NULL!\n");
++		return -EINVAL;
++	}
++
++	switch (params->fid) {
++	case UTE_FID_RXFIFO_SIZE:
++		/* set Rx FIFO size */
++		/* val is FIFO size in bytes */
++		val = *(unsigned *)valptr;
++		if (params->param1 != 0xffffffff)
++			ret = -EINVAL;
++		else
++			pcd->rxf_size = val;
++		break;
++
++	case UTE_FID_TXFIFO_SIZE:
++		/* set Tx FIFO size */
++		/* param1 is Tx FIFO #, val is FIFO size in bytes */
++		val = *(unsigned *)valptr;
++		if (params->param1 >= DWC_MAX_TX_FIFOS)
++			ret = -EINVAL;
++		else
++			pcd->txf_size[params->param1] = val;
++		break;
++
++	case UTE_FID_RXFIFO_MAP:
++		/* Rx FIFO mapping not possible for USB3 core */
++		ret = -EINVAL;
++		break;
++
++	case UTE_FID_TXFIFO_MAP:
++		/* set Tx FIFO mapping */
++		/* param1 is Tx FIFO #, val is physical EP # */
++		val = *(unsigned *)valptr;
++		/* convert physical EP # to EP array index */
++		/* Note: have to force the direction bit to 1, UTE
++		 * doesn't set it
++		 */
++		index = ((val & 0xf) << 1) | 1;
++		if (params->param1 >= DWC_MAX_TX_FIFOS ||
++		    index >= DWC_MAX_PHYS_EP)
++			ret = -EINVAL;
++		else
++			pcd->txf_map[index] = params->param1;
++		break;
++
++	case UTE_FID_EP_MAP:
++		/* set EP mapping */
++		/* param1 is physical EP #, val is USB EP # */
++		val = *(unsigned *)valptr;
++		index = (params->param1 & 0xf) << 1 |
++			((params->param1 >> 4) & 0x1);
++		ret = dwc_usb3_set_usb_ep_map(0, index, val);
++		break;
++	case UTE_FID_DEV_SPEED:
++		index = params->param1;
++		printk("UTE_FID_DEV_SPEED is received: new speed %d", index);
++		ret = dwc_usb3_switch_speed(0, index);
++		break;
++	default:
++		ret = -EINVAL;
++	}
++
++	if (ret == 0) {
++		pcd->ute_change = 1;
++		printk(KERN_DEBUG USB3_DWC "Set UTE change bit\n");
++	}
++
++	return ret;
++}
++
++static struct cfiobject *cfi_create_object(dwc_usb3_pcd_t *pcd)
++{
++	struct cfiobject *cfi;
++
++	/* Set the ftcount field in the features header */
++	pcd_feats.hdr.ftcount = 16;
++
++	/* Calculate the total length of the feature descriptors for all
++	 * features plus the features header descriptor length, and write it
++	 * to the totlen field in the features header
++	 */
++	pcd_feats.hdr.totlen = sizeof(struct cfi_features_hdr) +
++			sizeof(struct cfi_feature_desc) * pcd_feats.hdr.ftcount;
++
++	/* Allocate the cfi object */
++	cfi = kmalloc(sizeof(*cfi), GFP_KERNEL);
++	if (!cfi)
++		return NULL;
++	memset(cfi, 0, sizeof(*cfi));
++
++	/* Assign the PCD pointer */
++	cfi->pcd = pcd;
++
++	/* Assign the features pointer */
++	cfi->features = &pcd_feats;
++
++	/* Assign the callbacks */
++	cfi->ops.get_ft_list = cficb_get_ft_list;
++	cfi->ops.get_ft_value = cficb_get_ft_value;
++	cfi->ops.set_ft_value = cficb_set_ft_value;
++	cfi->ops.reset_ft_value = cficb_reset_ft_value;
++
++	return cfi;
++}
++
++static void *dwc_cfi_get_object(void)
++{
++	struct cfiobject *cfi;
++	dwc_usb3_pcd_t *pcd;
++
++	pcd = dwc_usb3_get_pcd_instance(0);
++	if (!pcd)
++		return NULL;
++
++	cfi = cfi_create_object(pcd);
++	if (!cfi)
++		return NULL;
++
++	return cfi;
++};
++EXPORT_SYMBOL(dwc_cfi_get_object);
+diff --git a/drivers/usb/gadget/udc/hiudc3/ute_if.h b/drivers/usb/gadget/udc/hiudc3/ute_if.h
+new file mode 100644
+index 0000000..ec05269
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc3/ute_if.h
+@@ -0,0 +1,60 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/DWC_usb3/driver/linux/ute_if.h $
++ * $Revision: #10 $
++ * $Date: 2014/11/11 $
++ * $Change: 2664766 $
++ *
++ * Synopsys SS USB3 Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
++ * ========================================================================== */
++
++#ifndef _DWC_UTE_IFC_H_
++#define _DWC_UTE_IFC_H_
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/** @file
++ *
++ */
++
++extern dwc_usb3_pcd_t *dwc_usb3_get_pcd_instance(unsigned devnum);
++extern int dwc_usb3_set_usb_ep_map(unsigned devnum, unsigned phys_ep_num,
++				   unsigned usb_ep_num);
++extern int dwc_usb3_get_usb_ep_map(unsigned devnum, unsigned phys_ep_num,
++				   unsigned *usb_ep_num_ret);
++extern void dwc_usb3_ute_config(dwc_usb3_device_t *usb3_dev);
++
++extern int dwc_usb3_reset_usb_ep_map(unsigned devnum);
++extern int dwc_usb3_switch_speed(unsigned devnum, int speed);
++extern int dwc_usb3_get_dev_speed(unsigned devnum);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif	/* _DWC_UTE_IFC_H_ */
+diff --git a/drivers/usb/gadget/udc/hiudc3/win/win_defs.h b/drivers/usb/gadget/udc/hiudc3/win/win_defs.h
+new file mode 100644
+index 0000000..042614f
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc3/win/win_defs.h
+@@ -0,0 +1,145 @@
++#ifndef _DWC_WIN_DEFS_H_
++#define _DWC_WIN_DEFS_H_
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/**
++ * @file
++ *
++ * This file contains OS-specific includes and definitions.
++ *
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <errno.h>
++#include <string.h>
++#include <sys/types.h>
++
++typedef unsigned long long	u64, u_int64_t;
++typedef unsigned long		u_long;
++typedef unsigned int		u32, u_int32_t, u_int;
++typedef unsigned short		u16, u_int16_t, u_short;
++typedef unsigned char		u8, u_int8_t, u_char;
++
++typedef long long		s64;
++typedef int			s32;
++typedef short			s16;
++typedef char			s8;
++
++/** Type for DMA addresses */
++typedef unsigned long		dwc_dma_t;
++#define DWC_DMA_ADDR_INVALID	(~(dwc_dma_t)0)
++
++/** Compiler 'packed' attribute for structs */
++#define UPACKED			/* */
++
++#define __iomem			/* */
++#define __func__		__FUNCTION__
++
++#define KERN_DEBUG	""	/* debug messages */
++#define KERN_INFO	""	/* informational messages */
++#define KERN_WARNING	""	/* warning messages */
++#define KERN_ERR	""	/* error messages */
++
++#define ESHUTDOWN	1001
++
++#include "dwc_list.h"
++
++/** @name Error Codes */
++#define DWC_E_INVALID		EINVAL
++#define DWC_E_NO_MEMORY		ENOMEM
++#define DWC_E_NO_DEVICE		ENODEV
++#define DWC_E_NOT_SUPPORTED	EOPNOTSUPP
++#define DWC_E_TIMEOUT		ETIMEDOUT
++#define DWC_E_BUSY		EBUSY
++#define DWC_E_AGAIN		EAGAIN
++#define DWC_E_ABORT		ECONNABORTED
++#define DWC_E_SHUTDOWN		ESHUTDOWN
++#define DWC_E_NO_DATA		ENODATA
++#define DWC_E_DISCONNECT	ECONNRESET
++#define DWC_E_UNKNOWN		EINVAL
++#define DWC_E_NO_STREAM_RES	ENOSR
++#define DWC_E_COMMUNICATION	ECOMM
++#define DWC_E_OVERFLOW		EOVERFLOW
++#define DWC_E_PROTOCOL		EPROTO
++#define DWC_E_IN_PROGRESS	EINPROGRESS
++#define DWC_E_PIPE		EPIPE
++#define DWC_E_IO		EIO
++#define DWC_E_NO_SPACE		ENOSPC
++#define DWC_E_DOMAIN		EDOM
++
++/**
++ * The number of DMA Descriptors (TRBs) to allocate for each endpoint type.
++ * NOTE: The driver currently supports more than 1 TRB for Isoc EPs only.
++ * So the values for Bulk and Intr must be 1.
++ */
++#define DWC_NUM_BULK_TRBS	1
++#define DWC_NUM_INTR_TRBS	1
++#define DWC_NUM_ISOC_TRBS	32
++
++/**
++ * These parameters may be specified when loading the module. They define how
++ * the DWC_usb3 controller should be configured. The parameter values are passed
++ * to the CIL initialization routine dwc_usb3_pcd_common_init().
++ */
++typedef struct dwc_usb3_core_params {
++	int burst;
++	int newcore;
++	int phy;
++	int wakeup;
++	int pwrctl;
++	int lpmctl;
++	int phyctl;
++	int usb2mode;
++	int hibernate;
++	int hiberdisc;
++	int clkgatingen;
++	int ssdisquirk;
++	int nobos;
++	int loop;
++	int nump;
++	int newcsr;
++	int rxfsz;
++	int txfsz[16];
++	int txfsz_cnt;
++	int baseline_besl;
++	int deep_besl;
++	int besl;
++	int ebc;
++} dwc_usb3_core_params_t;
++
++#define wmb()				do {} while (0)
++
++#define interrupt_disable()		0
++#define interrupt_enable()		do {} while (0)
++
++#define spin_lock_init(p)		do {} while (0)
++#define spin_lock(p)			do {} while (0)
++#define spin_unlock(p)			do {} while (0)
++#define spin_lock_irqsave(p, f)		do { (f) = interrupt_disable(); } while (0)
++#define spin_unlock_irqrestore(p, f)	do { if (f) interrupt_enable(); } while (0)
++
++struct task_struct {
++	int dummy;
++};
++
++struct tasklet_struct {
++	int dummy;
++};
++
++struct usb_ep {
++	int dummy;
++};
++
++struct usb_request {
++	int dummy;
++};
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* _DWC_WIN_DEFS_H_ */
+diff --git a/drivers/usb/gadget/udc/hiudc3/win/win_dev.h b/drivers/usb/gadget/udc/hiudc3/win/win_dev.h
+new file mode 100644
+index 0000000..c20e5f2
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc3/win/win_dev.h
+@@ -0,0 +1,183 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/DWC_usb3/driver/win/win_dev.h $
++ * $Revision: #9 $
++ * $Date: 2014/11/11 $
++ * $Change: 2664766 $
++ *
++ * Synopsys SS USB3 Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
++ * ========================================================================== */
++
++#ifndef _DWC_WIN_DEV_H_
++#define _DWC_WIN_DEV_H_
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/** @file
++ */
++
++/** Wrapper function for _handshake() */
++#define handshake(_dev_, _ptr_, _mask_, _done_)	\
++	_handshake(_dev_, _ptr_, _mask_, _done_)
++
++/** Takes a usb req pointer and returns the associated pcd req pointer */
++#define dwc_usb3_get_pcd_req(usbreq)			\
++	((dwc_usb3_pcd_req_t *)((char *)(usbreq) -	\
++		offsetof(struct dwc_usb3_pcd_req, usb_req)))
++
++/** Takes a usb ep pointer and returns the associated pcd ep pointer */
++#define dwc_usb3_get_pcd_ep(usbep)			\
++	((dwc_usb3_pcd_ep_t *)((char *)(usbep) -	\
++		offsetof(struct dwc_usb3_pcd_ep, usb_ep)))
++
++/**
++ * Register read/write.
++ */
++static __inline u32 dwc_rd32(struct dwc_usb3_device *dev, volatile u32 *adr)
++{
++	return *adr;
++}
++
++static __inline void dwc_wr32(struct dwc_usb3_device *dev, volatile u32 *adr, u32 val)
++{
++	*adr = val;
++}
++
++/**
++ * Non-sleeping delays.
++ */
++#define dwc_udelay(dev, us)	do {} while (0)
++#define dwc_mdelay(dev, ms)	do {} while (0)
++
++/**
++ * Sleeping delay.
++ */
++#define dwc_msleep(dev, ms)	do {} while (0)
++
++/**
++ * Debugging support - vanishes in non-debug builds.
++ */
++
++/** Prefix string for print macros. */
++#define USB3_DWC	"dwc_usb3: "
++
++//#ifdef DEBUG
++# define dwc_debug	printf
++//#else
++//# define dwc_debug(dev, x)	do {} while (0)
++//#endif /* DEBUG */
++
++# define dwc_debug0(dev, fmt)			dwc_debug(fmt)
++# define dwc_debug1(dev, fmt, a)		dwc_debug(fmt, a)
++# define dwc_debug2(dev, fmt, a, b)		dwc_debug(fmt, a, b)
++# define dwc_debug3(dev, fmt, a, b, c)		dwc_debug(fmt, a, b, c)
++# define dwc_debug4(dev, fmt, a, b, c, d)	dwc_debug(fmt, a, b, c, d)
++# define dwc_debug5(dev, fmt, a, b, c, d, e) \
++			dwc_debug(fmt, a, b, c, d, e)
++# define dwc_debug6(dev, fmt, a, b, c, d, e, f) \
++			dwc_debug(fmt, a, b, c, d, e, f)
++# define dwc_debug7(dev, fmt, a, b, c, d, e, f, g) \
++			dwc_debug(fmt, a, b, c, d, e, f, g)
++# define dwc_debug8(dev, fmt, a, b, c, d, e, f, g, h) \
++			dwc_debug(fmt, a, b, c, d, e, f, g, h)
++# define dwc_debug9(dev, fmt, a, b, c, d, e, f, g, h, i) \
++			dwc_debug(fmt, a, b, c, d, e, f, g, h, i)
++# define dwc_debug10(dev, fmt, a, b, c, d, e, f, g, h, i, j) \
++			dwc_debug(fmt, a, b, c, d, e, f, g, h, i, j)
++
++//#if defined(DEBUG) || defined(ISOC_DEBUG)
++# define dwc_isocdbg	printf
++//#else
++//# define dwc_isocdbg(dev, x)	do {} while (0)
++//#endif
++
++# define dwc_isocdbg0(dev, fmt)			dwc_isocdbg(fmt)
++# define dwc_isocdbg1(dev, fmt, a)		dwc_isocdbg(fmt, a)
++# define dwc_isocdbg2(dev, fmt, a, b)		dwc_isocdbg(fmt, a, b)
++# define dwc_isocdbg3(dev, fmt, a, b, c)	dwc_isocdbg(fmt, a, b, c)
++# define dwc_isocdbg4(dev, fmt, a, b, c, d) \
++			dwc_isocdbg(fmt, a, b, c, d)
++# define dwc_isocdbg5(dev, fmt, a, b, c, d, e) \
++			dwc_isocdbg(fmt, a, b, c, d, e)
++# define dwc_isocdbg6(dev, fmt, a, b, c, d, e, f) \
++			dwc_isocdbg(fmt, a, b, c, d, e, f)
++
++/**
++ * Print an Error message.
++ */
++#define dwc_error	printf
++
++#define dwc_error0(dev, fmt)			dwc_error(fmt)
++#define dwc_error1(dev, fmt, a)			dwc_error(fmt, a)
++#define dwc_error2(dev, fmt, a, b)		dwc_error(fmt, a, b)
++#define dwc_error3(dev, fmt, a, b, c)		dwc_error(fmt, a, b, c)
++#define dwc_error4(dev, fmt, a, b, c, d)	dwc_error(fmt, a, b, c, d)
++
++/**
++ * Print a Warning message.
++ */
++#define dwc_warn	printf
++
++#define dwc_warn0(dev, fmt)			dwc_warn(fmt)
++#define dwc_warn1(dev, fmt, a)			dwc_warn(fmt, a)
++#define dwc_warn2(dev, fmt, a, b)		dwc_warn(fmt, a, b)
++#define dwc_warn3(dev, fmt, a, b, c)		dwc_warn(fmt, a, b, c)
++#define dwc_warn4(dev, fmt, a, b, c, d)		dwc_warn(fmt, a, b, c, d)
++
++/**
++ * Print an Informational message (normal but significant).
++ */
++#define dwc_info	printf
++
++#define dwc_info0(dev, fmt)			dwc_info(fmt)
++#define dwc_info1(dev, fmt, a)			dwc_info(fmt, a)
++#define dwc_info2(dev, fmt, a, b)		dwc_info(fmt, a, b)
++#define dwc_info3(dev, fmt, a, b, c)		dwc_info(fmt, a, b, c)
++#define dwc_info4(dev, fmt, a, b, c, d)		dwc_info(fmt, a, b, c, d)
++
++/**
++ * Basic message printing.
++ */
++#define dwc_print	printf
++
++#define dwc_print0(dev, fmt)			dwc_print(fmt)
++#define dwc_print1(dev, fmt, a)			dwc_print(fmt, a)
++#define dwc_print2(dev, fmt, a, b)		dwc_print(fmt, a, b)
++#define dwc_print3(dev, fmt, a, b, c)		dwc_print(fmt, a, b, c)
++#define dwc_print4(dev, fmt, a, b, c, d)	dwc_print(fmt, a, b, c, d)
++#define dwc_print5(dev, fmt, a, b, c, d, e) \
++			dwc_print(fmt, a, b, c, d, e)
++
++extern int dwc_usb3_gadget_init(struct dwc_usb3_device *usb3_dev, struct device *dev);
++extern void dwc_usb3_gadget_remove(struct dwc_usb3_device *usb3_dev, struct device *dev);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* _DWC_WIN_DEV_H_ */
+diff --git a/drivers/usb/gadget/udc/hiudc3/win/win_gadget.c b/drivers/usb/gadget/udc/hiudc3/win/win_gadget.c
+new file mode 100644
+index 0000000..a15da82
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc3/win/win_gadget.c
+@@ -0,0 +1,205 @@
++/** @file
++ */
++
++#include "os_defs.h"
++#include "hw.h"
++#include "usb.h"
++#include "pcd.h"
++#include "dev.h"
++#include "os_dev.h"
++#include "cil.h"
++
++int main(int argc, char *argv[])
++{
++	return 0;
++}
++
++/******************************************************************************
++ * Function driver notification routines
++ *
++ * These routines receive notifications from the PCD when certain events
++ * occur which the Function driver may need to be aware of.
++ *
++ * These routines *must* have the exact names and parameters shown here,
++ * because they are part of the API between the PCD and the Function driver.
++ ******************************************************************************/
++
++/**
++ * This routine receives Connect notifications from the PCD
++ *
++ * @param pcd   Programming view of DWC_usb3 peripheral controller.
++ * @param speed Speed of the connection (as defined in usb.h)
++ * @return      0 for success, else negative error code.
++ */
++int dwc_usb3_gadget_connect(dwc_usb3_pcd_t *pcd, int speed)
++{
++	return 0;
++}
++
++/**
++ * This routine receives Disconnect notifications from the PCD
++ *
++ * @param pcd   Programming view of DWC_usb3 peripheral controller.
++ * @return      0 for success, else negative error code.
++ */
++int dwc_usb3_gadget_disconnect(dwc_usb3_pcd_t *pcd)
++{
++	return 0;
++}
++
++/**
++ * This routine receives Setup request notifications from the PCD
++ *
++ * @param pcd   Programming view of DWC_usb3 peripheral controller.
++ * @param ctrl  Pointer to the Setup packet for the request.
++ * @return      0 for success, else negative error code.
++ */
++int dwc_usb3_gadget_setup(dwc_usb3_pcd_t *pcd, usb_device_request_t *ctrl)
++{
++	return 0;
++}
++
++/**
++ * This routine receives Suspend notifications from the PCD
++ *
++ * @param pcd   Programming view of DWC_usb3 peripheral controller.
++ * @return      0 for success, else negative error code.
++ */
++int dwc_usb3_gadget_suspend(dwc_usb3_pcd_t *pcd)
++{
++	return 0;
++}
++
++/**
++ * This routine receives Resume notifications from the PCD
++ *
++ * @param pcd   Programming view of DWC_usb3 peripheral controller.
++ * @return      0 for success, else negative error code.
++ */
++int dwc_usb3_gadget_resume(dwc_usb3_pcd_t *pcd)
++{
++	return 0;
++}
++
++/**
++ * This routine receives Transfer Complete notifications from the PCD
++ *
++ * @param pcd           Programming view of DWC_usb3 peripheral controller.
++ * @param pcd_ep        PCD EP for the transfer.
++ * @param pcd_req       PCD request for the transfer.
++ * @param status        Transfer status, 0 for success else negative error code.
++ * @return              0 for success, else negative error code.
++ */
++int dwc_usb3_gadget_complete(dwc_usb3_pcd_t *pcd, dwc_usb3_pcd_ep_t *pcd_ep,
++			     dwc_usb3_pcd_req_t *pcd_req, int status)
++{
++	return 0;
++}
++
++/**
++ * This routine allows overriding the standard Control transfer handling
++ * (currently only done by the axs101 test gadget)
++ *
++ * @param pcd           Programming view of DWC_usb3 peripheral controller.
++ */
++void dwc_usb3_gadget_do_setup(dwc_usb3_pcd_t *pcd)
++{
++	/* TODO */
++}
++
++/******************************************************************************
++ * Function driver callback routines
++ *
++ * The PCD calls these routines when it needs something from the Function
++ * driver.
++ *
++ * These routines *must* have the exact names and parameters shown here,
++ * because they are part of the API between the PCD and the Function driver.
++ ******************************************************************************/
++
++/**
++ * This routine allocates coherent DMA memory. It is used by the PCD to
++ * allocate memory for TRBs. The block of memory returned must have a start
++ * address aligned to a 16-byte boundary.
++ *
++ * @param pcd_ep        PCD EP that memory block will be associated with.
++ * @param size          Size of memory block to allocate, in bytes.
++ * @param mem_dma_ret   Physical address of allocated memory block is returned
++ *                      through this pointer.
++ * @return              Address of allocated memory block, or NULL if allocation
++ *                      fails.
++ */
++void *dwc_usb3_gadget_alloc_dma(dwc_usb3_pcd_ep_t *pcd_ep, int size, dwc_dma_t *mem_dma_ret)
++{
++	return NULL;
++}
++
++/**
++ * This routine frees DMA memory allocated by dwc_usb3_gadget_alloc_dma().
++ *
++ * @param pcd_ep        PCD EP that memory block is associated with.
++ * @param size          Size of memory block to free, in bytes.
++ * @param mem           Address of memory block.
++ * @param mem_dma       Physical address of memory block.
++ */
++void dwc_usb3_gadget_free_dma(dwc_usb3_pcd_ep_t *pcd_ep, int size, void *mem, dwc_dma_t mem_dma)
++{
++}
++
++/**
++ * This routine returns the PCD request corresponding to the current transfer
++ * request for an endpoint. The current transfer request is the first request
++ * submitted that has not been completed yet.
++ *
++ * @param pcd           Programming view of DWC_usb3 peripheral controller.
++ * @param pcd_ep        PCD EP to operate on.
++ * @return              Pointer to PCD request, or NULL if no request available.
++ */
++dwc_usb3_pcd_req_t *dwc_usb3_gadget_get_request(dwc_usb3_pcd_t *pcd, dwc_usb3_pcd_ep_t *pcd_ep)
++{
++	return NULL;
++}
++
++/**
++ * This routine checks to see if there is another transfer request waiting
++ * on an endpoint that has not been started yet. If so then that transfer is
++ * started.
++ *
++ * @param pcd           Programming view of DWC_usb3 peripheral controller.
++ * @param pcd_ep        PCD EP to operate on.
++ */
++void dwc_usb3_gadget_start_next_request(dwc_usb3_pcd_t *pcd, dwc_usb3_pcd_ep_t *pcd_ep)
++{
++}
++
++/**
++ * This routine terminates all requests which are pending on an endpoint.
++ *
++ * @param pcd           Programming view of DWC_usb3 peripheral controller.
++ * @param pcd_ep        EP to operate on.
++ */
++void dwc_usb3_gadget_request_nuke(dwc_usb3_pcd_t *pcd, dwc_usb3_pcd_ep_t *pcd_ep)
++{
++}
++
++/**
++ * This routine marks all pending requests for an EP as not started.
++ *
++ * @param pcd           Programming view of DWC_usb3 peripheral controller.
++ * @param pcd_ep        EP to operate on.
++ */
++void dwc_usb3_gadget_set_ep_not_started(dwc_usb3_pcd_t *pcd, dwc_usb3_pcd_ep_t *pcd_ep)
++{
++}
++
++/**
++ * Start an Isoc EP running at the proper interval, after receiving the initial
++ * XferNrdy event.
++ *
++ * @param pcd           Programming view of DWC_usb3 peripheral controller.
++ * @param pcd_ep        EP to operate on.
++ * @param event         Event data containing the XferNrdy microframe.
++ */
++void dwc_usb3_gadget_isoc_ep_start(dwc_usb3_pcd_t *pcd, dwc_usb3_pcd_ep_t *pcd_ep, u32 event)
++{
++}
+diff --git a/drivers/usb/gadget/udc/hiudc3/win/win_hiber.c b/drivers/usb/gadget/udc/hiudc3/win/win_hiber.c
+new file mode 100644
+index 0000000..303f08c
+--- /dev/null
++++ b/drivers/usb/gadget/udc/hiudc3/win/win_hiber.c
+@@ -0,0 +1,35 @@
++/** @file
++ */
++
++#include "os_defs.h"
++#include "hw.h"
++#include "usb.h"
++#include "pcd.h"
++#include "dev.h"
++#include "os_dev.h"
++#include "cil.h"
++
++void dwc_usb3_task_schedule(struct tasklet_struct *tasklet)
++{
++}
++
++/**
++ * Helper routine for dwc_wait_pme_thread()
++ */
++static void dwc_wait_for_link_up(dwc_usb3_pcd_t *pcd)
++{
++}
++
++int dwc_wait_pme_thread(void *data)
++{
++	return 0;
++}
++
++int dwc_usb3_handle_pme_intr(dwc_usb3_device_t *dev)
++{
++	return 0;
++}
++
++void dwc_usb3_power_ctl(dwc_usb3_device_t *dev, int on)
++{
++}
+diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c
+index f205465..382d8b6 100644
+--- a/drivers/usb/gadget/udc/udc-core.c
++++ b/drivers/usb/gadget/udc/udc-core.c
+@@ -400,7 +400,15 @@ static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *dri
+ 		driver->unbind(udc->gadget);
+ 		goto err1;
+ 	}
+-	usb_gadget_connect(udc->gadget);
++	/*
++	 * HACK: The Android gadget driver disconnects the gadget
++	 * on bind and expects the gadget to stay disconnected until
++	 * it calls usb_gadget_connect when userspace is ready. Remove
++	 * the call to usb_gadget_connect bellow to avoid enabling the
++	 * pullup before userspace is ready.
++	 *
++	 * usb_gadget_connect(udc->gadget);
++	 */
+ 
+ 	kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
+ 	return 0;
+diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
+index a3ca137..aa0fd91 100644
+--- a/drivers/usb/host/Kconfig
++++ b/drivers/usb/host/Kconfig
+@@ -50,6 +50,14 @@ config USB_XHCI_RCAR
+ 	  Say 'Y' to enable the support for the xHCI host controller
+ 	  found in Renesas R-Car ARM SoCs.
+ 
++config USB_XHCI_HISILICON
++	tristate "xHCI support for Hisilicon SoCs"
++	select USB_XHCI_PLATFORM
++	---help---
++	  Say 'Y' to enable the support for the xHCI host controller
++	  found in Hisilicon ARM SOCs. When you select the option, usb
++	  driver can be loaded.
++
+ endif # USB_XHCI_HCD
+ 
+ config USB_EHCI_HCD
+diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
+index 3df32fa..9dadcba 100644
+--- a/drivers/usb/host/ehci-hcd.c
++++ b/drivers/usb/host/ehci-hcd.c
+@@ -109,6 +109,9 @@ MODULE_PARM_DESC (ignore_oc, "ignore bogus hardware overcurrent indications");
+ #include "ehci.h"
+ #include "pci-quirks.h"
+ 
++#ifdef CONFIG_ARCH_HI3516CV300
++void usb2_low_power(int);
++#endif
+ static void compute_tt_budget(u8 budget_table[EHCI_BANDWIDTH_SIZE],
+ 		struct ehci_tt *tt);
+ 
+@@ -777,7 +780,9 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
+ 				continue;
+ 			pstatus = ehci_readl(ehci,
+ 					 &ehci->regs->port_status[i]);
+-
++#ifdef CONFIG_ARCH_HI3516CV300
++			usb2_low_power(pstatus);
++#endif
+ 			if (pstatus & PORT_OWNER)
+ 				continue;
+ 			if (!(test_bit(i, &ehci->suspended_ports) &&
+diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
+index ecd5d6a..bf45624 100644
+--- a/drivers/usb/host/ehci-hub.c
++++ b/drivers/usb/host/ehci-hub.c
+@@ -30,7 +30,21 @@
+ #include <linux/usb/otg.h>
+ 
+ #define	PORT_WAKE_BITS	(PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E)
++#if defined(CONFIG_ARCH_HI3519) || defined(CONFIG_ARCH_HI3519V101) \
++	|| defined(CONFIG_ARCH_HI3559) || defined(CONFIG_ARCH_HI3556) \
++	|| defined(CONFIG_ARCH_HI3516AV200)
++#define BASE_REG	0x120100b4
++#define USBPHY_PORT0_TREQ	(0x1 << 2)
++#endif
++#ifdef CONFIG_ARCH_HI3531D
++#define BASE_REG			0x12040000
++#define USBPHY_PORT0_TREQ		0x0134
++#endif
+ 
++#ifdef CONFIG_ARCH_HI3516CV300
++#define BASE_REG	0x120100b8
++#define USBPHY_PORT0_TREQ	(0x1 << 14)
++#endif
+ #ifdef	CONFIG_PM
+ 
+ static int persist_enabled_on_companion(struct usb_device *udev, void *unused)
+@@ -1219,7 +1233,32 @@ int ehci_hub_control(
+ 				ehci->reset_done [wIndex] = jiffies
+ 						+ msecs_to_jiffies (50);
+ 			}
++
++			if (!(temp & PORT_CONNECT) && !PORT_USB11 (temp))
++				mdelay(100);
++
++#if defined(CONFIG_ARCH_HI3519) || defined(CONFIG_ARCH_HI3559) || defined(CONFIG_ARCH_HI3556)\
++	|| defined(CONFIG_ARCH_HI3519V101) ||  defined(CONFIG_ARCH_HI3516CV300) || defined(CONFIG_ARCH_HI3516AV200) \
++	|| defined(CONFIG_ARCH_HI3531D)
++			if (ehci_readl(ehci, status_reg) == 0x1005) {
++				unsigned int reg, reg1;
++				void __iomem *base_reg;
++
++				base_reg = ioremap_nocache(BASE_REG, 0x4);
++
++				ehci_writel(ehci, temp, status_reg);
++				reg = reg1 = ehci_readl(ehci, base_reg);
++				reg1 |= USBPHY_PORT0_TREQ;
++				ehci_writel(ehci, reg1, base_reg);
++				ehci_writel(ehci, reg, base_reg);
++
++				iounmap(base_reg);
++			} else
++				ehci_writel(ehci, temp, status_reg);
++
++#else
+ 			ehci_writel(ehci, temp, status_reg);
++#endif
+ 			break;
+ 
+ 		/* For downstream facing ports (these):  one hub port is put
+diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c
+index 2f5b9ce..2ea6968 100644
+--- a/drivers/usb/host/ehci-platform.c
++++ b/drivers/usb/host/ehci-platform.c
+@@ -43,7 +43,8 @@
+ struct ehci_platform_priv {
+ 	struct clk *clks[EHCI_MAX_CLKS];
+ 	struct reset_control *rst;
+-	struct phy *phy;
++	struct phy **phys;
++	int num_phys;
+ };
+ 
+ static const char hcd_name[] = "ehci-platform";
+@@ -78,7 +79,7 @@ static int ehci_platform_power_on(struct platform_device *dev)
+ {
+ 	struct usb_hcd *hcd = platform_get_drvdata(dev);
+ 	struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd);
+-	int clk, ret;
++	int clk, ret, phy_num;
+ 
+ 	for (clk = 0; clk < EHCI_MAX_CLKS && priv->clks[clk]; clk++) {
+ 		ret = clk_prepare_enable(priv->clks[clk]);
+@@ -86,20 +87,24 @@ static int ehci_platform_power_on(struct platform_device *dev)
+ 			goto err_disable_clks;
+ 	}
+ 
+-	if (priv->phy) {
+-		ret = phy_init(priv->phy);
+-		if (ret)
+-			goto err_disable_clks;
+-
+-		ret = phy_power_on(priv->phy);
++	for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
++		ret = phy_init(priv->phys[phy_num]);
+ 		if (ret)
+ 			goto err_exit_phy;
++		ret = phy_power_on(priv->phys[phy_num]);
++		if (ret) {
++			phy_exit(priv->phys[phy_num]);
++			goto err_exit_phy;
++		}
+ 	}
+ 
+ 	return 0;
+ 
+ err_exit_phy:
+-	phy_exit(priv->phy);
++	while (--phy_num >= 0) {
++		phy_power_off(priv->phys[phy_num]);
++		phy_exit(priv->phys[phy_num]);
++	}
+ err_disable_clks:
+ 	while (--clk >= 0)
+ 		clk_disable_unprepare(priv->clks[clk]);
+@@ -111,11 +116,11 @@ static void ehci_platform_power_off(struct platform_device *dev)
+ {
+ 	struct usb_hcd *hcd = platform_get_drvdata(dev);
+ 	struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd);
+-	int clk;
++	int clk, phy_num;
+ 
+-	if (priv->phy) {
+-		phy_power_off(priv->phy);
+-		phy_exit(priv->phy);
++	for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
++		phy_power_off(priv->phys[phy_num]);
++		phy_exit(priv->phys[phy_num]);
+ 	}
+ 
+ 	for (clk = EHCI_MAX_CLKS - 1; clk >= 0; clk--)
+@@ -143,7 +148,7 @@ static int ehci_platform_probe(struct platform_device *dev)
+ 	struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev);
+ 	struct ehci_platform_priv *priv;
+ 	struct ehci_hcd *ehci;
+-	int err, irq, clk = 0;
++	int err, irq, phy_num, clk = 0;
+ 
+ 	if (usb_disabled())
+ 		return -ENODEV;
+@@ -190,12 +195,24 @@ static int ehci_platform_probe(struct platform_device *dev)
+ 		if (of_property_read_bool(dev->dev.of_node, "big-endian"))
+ 			ehci->big_endian_mmio = ehci->big_endian_desc = 1;
+ 
+-		priv->phy = devm_phy_get(&dev->dev, "usb");
+-		if (IS_ERR(priv->phy)) {
+-			err = PTR_ERR(priv->phy);
+-			if (err == -EPROBE_DEFER)
+-				goto err_put_hcd;
+-			priv->phy = NULL;
++		priv->num_phys = of_count_phandle_with_args(dev->dev.of_node,
++				"phys", "#phy-cells");
++
++		if (priv->num_phys > 0) {
++			priv->phys = devm_kcalloc(&dev->dev, priv->num_phys,
++					    sizeof(struct phy *), GFP_KERNEL);
++			if (!priv->phys)
++				return -ENOMEM;
++		} else
++			priv->num_phys = 0;
++
++		for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
++			priv->phys[phy_num] = devm_of_phy_get_by_index(
++					&dev->dev, dev->dev.of_node, phy_num);
++			if (IS_ERR(priv->phys[phy_num])) {
++				err = PTR_ERR(priv->phys[phy_num]);
++					goto err_put_hcd;
++			}
+ 		}
+ 
+ 		for (clk = 0; clk < EHCI_MAX_CLKS; clk++) {
+@@ -311,7 +328,7 @@ static int ehci_platform_remove(struct platform_device *dev)
+ 	return 0;
+ }
+ 
+-#ifdef CONFIG_PM
++#ifdef CONFIG_PM_SLEEP
+ 
+ static int ehci_platform_suspend(struct device *dev)
+ {
+@@ -349,10 +366,7 @@ static int ehci_platform_resume(struct device *dev)
+ 	return 0;
+ }
+ 
+-#else /* !CONFIG_PM */
+-#define ehci_platform_suspend	NULL
+-#define ehci_platform_resume	NULL
+-#endif /* CONFIG_PM */
++#endif /* CONFIG_PM_SLEEP */
+ 
+ static const struct of_device_id vt8500_ehci_ids[] = {
+ 	{ .compatible = "via,vt8500-ehci", },
+@@ -368,10 +382,8 @@ static const struct platform_device_id ehci_platform_table[] = {
+ };
+ MODULE_DEVICE_TABLE(platform, ehci_platform_table);
+ 
+-static const struct dev_pm_ops ehci_platform_pm_ops = {
+-	.suspend	= ehci_platform_suspend,
+-	.resume		= ehci_platform_resume,
+-};
++static SIMPLE_DEV_PM_OPS(ehci_platform_pm_ops, ehci_platform_suspend,
++		       ehci_platform_resume);
+ 
+ static struct platform_driver ehci_platform_driver = {
+ 	.id_table	= ehci_platform_table,
+diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
+index d664eda..098de14 100644
+--- a/drivers/usb/host/ohci-hcd.c
++++ b/drivers/usb/host/ohci-hcd.c
+@@ -97,7 +97,9 @@ static void io_watchdog_func(unsigned long _ohci);
+ #define IRQ_NOTMINE	IRQ_NONE
+ #endif
+ 
+-
++#ifdef CONFIG_ARCH_HI3516CV300
++void usb2_low_power(int);
++#endif
+ /* Some boards misreport power switching/overcurrent */
+ static bool distrust_firmware = 1;
+ module_param (distrust_firmware, bool, 0);
+@@ -231,7 +233,6 @@ static int ohci_urb_enqueue (
+ 		/* Start up the I/O watchdog timer, if it's not running */
+ 		if (!timer_pending(&ohci->io_watchdog) &&
+ 				list_empty(&ohci->eds_in_use)) {
+-			ohci->prev_frame_no = ohci_frame_no(ohci);
+ 			mod_timer(&ohci->io_watchdog,
+ 					jiffies + IO_WATCHDOG_DELAY);
+ 		}
+@@ -729,7 +730,6 @@ static void io_watchdog_func(unsigned long _ohci)
+ 	u32		head;
+ 	struct ed	*ed;
+ 	struct td	*td, *td_start, *td_next;
+-	unsigned	frame_no;
+ 	unsigned long	flags;
+ 
+ 	spin_lock_irqsave(&ohci->lock, flags);
+@@ -745,7 +745,6 @@ static void io_watchdog_func(unsigned long _ohci)
+ 	if (!(status & OHCI_INTR_WDH) && ohci->wdh_cnt == ohci->prev_wdh_cnt) {
+ 		if (ohci->prev_donehead) {
+ 			ohci_err(ohci, "HcDoneHead not written back; disabled\n");
+- died:
+ 			usb_hc_died(ohci_to_hcd(ohci));
+ 			ohci_dump(ohci);
+ 			ohci_shutdown(ohci_to_hcd(ohci));
+@@ -806,35 +805,7 @@ static void io_watchdog_func(unsigned long _ohci)
+ 	ohci_work(ohci);
+ 
+ 	if (ohci->rh_state == OHCI_RH_RUNNING) {
+-
+-		/*
+-		 * Sometimes a controller just stops working.  We can tell
+-		 * by checking that the frame counter has advanced since
+-		 * the last time we ran.
+-		 *
+-		 * But be careful: Some controllers violate the spec by
+-		 * stopping their frame counter when no ports are active.
+-		 */
+-		frame_no = ohci_frame_no(ohci);
+-		if (frame_no == ohci->prev_frame_no) {
+-			int		active_cnt = 0;
+-			int		i;
+-			unsigned	tmp;
+-
+-			for (i = 0; i < ohci->num_ports; ++i) {
+-				tmp = roothub_portstatus(ohci, i);
+-				/* Enabled and not suspended? */
+-				if ((tmp & RH_PS_PES) && !(tmp & RH_PS_PSS))
+-					++active_cnt;
+-			}
+-
+-			if (active_cnt > 0) {
+-				ohci_err(ohci, "frame counter not updating; disabled\n");
+-				goto died;
+-			}
+-		}
+ 		if (!list_empty(&ohci->eds_in_use)) {
+-			ohci->prev_frame_no = frame_no;
+ 			ohci->prev_wdh_cnt = ohci->wdh_cnt;
+ 			ohci->prev_donehead = ohci_readl(ohci,
+ 					&ohci->regs->donehead);
+@@ -900,6 +871,16 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
+ 	}
+ 
+ 	if (ints & OHCI_INTR_RHSC) {
++#ifdef CONFIG_ARCH_HI3516CV300
++		unsigned        i = ohci->num_ports;
++
++		while (i--) {
++			int pstatus;
++
++			pstatus = roothub_portstatus (ohci, i);
++			usb2_low_power(pstatus);
++		}
++#endif
+ 		ohci_dbg(ohci, "rhsc\n");
+ 		ohci->next_statechange = jiffies + STATECHANGE_DELAY;
+ 		ohci_writel(ohci, OHCI_INTR_RD | OHCI_INTR_RHSC,
+diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c
+index 4369299..00a6b0f 100644
+--- a/drivers/usb/host/ohci-platform.c
++++ b/drivers/usb/host/ohci-platform.c
+@@ -38,7 +38,8 @@
+ struct ohci_platform_priv {
+ 	struct clk *clks[OHCI_MAX_CLKS];
+ 	struct reset_control *rst;
+-	struct phy *phy;
++	struct phy **phys;
++	int num_phys;
+ };
+ 
+ static const char hcd_name[] = "ohci-platform";
+@@ -61,7 +62,7 @@ static int ohci_platform_power_on(struct platform_device *dev)
+ {
+ 	struct usb_hcd *hcd = platform_get_drvdata(dev);
+ 	struct ohci_platform_priv *priv = hcd_to_ohci_priv(hcd);
+-	int clk, ret;
++	int clk, ret, phy_num;
+ 
+ 	for (clk = 0; clk < OHCI_MAX_CLKS && priv->clks[clk]; clk++) {
+ 		ret = clk_prepare_enable(priv->clks[clk]);
+@@ -69,20 +70,24 @@ static int ohci_platform_power_on(struct platform_device *dev)
+ 			goto err_disable_clks;
+ 	}
+ 
+-	if (priv->phy) {
+-		ret = phy_init(priv->phy);
+-		if (ret)
+-			goto err_disable_clks;
+-
+-		ret = phy_power_on(priv->phy);
++	for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
++		ret = phy_init(priv->phys[phy_num]);
+ 		if (ret)
+ 			goto err_exit_phy;
++		ret = phy_power_on(priv->phys[phy_num]);
++		if (ret) {
++			phy_exit(priv->phys[phy_num]);
++			goto err_exit_phy;
++		}
+ 	}
+ 
+ 	return 0;
+ 
+ err_exit_phy:
+-	phy_exit(priv->phy);
++	while (--phy_num >= 0) {
++		phy_power_off(priv->phys[phy_num]);
++		phy_exit(priv->phys[phy_num]);
++	}
+ err_disable_clks:
+ 	while (--clk >= 0)
+ 		clk_disable_unprepare(priv->clks[clk]);
+@@ -94,11 +99,11 @@ static void ohci_platform_power_off(struct platform_device *dev)
+ {
+ 	struct usb_hcd *hcd = platform_get_drvdata(dev);
+ 	struct ohci_platform_priv *priv = hcd_to_ohci_priv(hcd);
+-	int clk;
++	int clk, phy_num;
+ 
+-	if (priv->phy) {
+-		phy_power_off(priv->phy);
+-		phy_exit(priv->phy);
++	for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
++		phy_power_off(priv->phys[phy_num]);
++		phy_exit(priv->phys[phy_num]);
+ 	}
+ 
+ 	for (clk = OHCI_MAX_CLKS - 1; clk >= 0; clk--)
+@@ -127,7 +132,7 @@ static int ohci_platform_probe(struct platform_device *dev)
+ 	struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev);
+ 	struct ohci_platform_priv *priv;
+ 	struct ohci_hcd *ohci;
+-	int err, irq, clk = 0;
++	int err, irq, phy_num, clk = 0;
+ 
+ 	if (usb_disabled())
+ 		return -ENODEV;
+@@ -175,12 +180,24 @@ static int ohci_platform_probe(struct platform_device *dev)
+ 		if (of_property_read_bool(dev->dev.of_node, "big-endian"))
+ 			ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;
+ 
+-		priv->phy = devm_phy_get(&dev->dev, "usb");
+-		if (IS_ERR(priv->phy)) {
+-			err = PTR_ERR(priv->phy);
+-			if (err == -EPROBE_DEFER)
++		priv->num_phys = of_count_phandle_with_args(dev->dev.of_node,
++				"phys", "#phy-cells");
++
++		if (priv->num_phys > 0) {
++			priv->phys = devm_kcalloc(&dev->dev, priv->num_phys,
++					    sizeof(struct phy *), GFP_KERNEL);
++			if (!priv->phys)
++				return -ENOMEM;
++		} else
++			priv->num_phys = 0;
++
++		for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
++			priv->phys[phy_num] = devm_of_phy_get_by_index(
++					&dev->dev, dev->dev.of_node, phy_num);
++			if (IS_ERR(priv->phys[phy_num])) {
++				err = PTR_ERR(priv->phys[phy_num]);
+ 				goto err_put_hcd;
+-			priv->phy = NULL;
++			}
+ 		}
+ 
+ 		for (clk = 0; clk < OHCI_MAX_CLKS; clk++) {
+@@ -298,7 +315,7 @@ static int ohci_platform_remove(struct platform_device *dev)
+ 	return 0;
+ }
+ 
+-#ifdef CONFIG_PM
++#ifdef CONFIG_PM_SLEEP
+ 
+ static int ohci_platform_suspend(struct device *dev)
+ {
+@@ -335,11 +352,7 @@ static int ohci_platform_resume(struct device *dev)
+ 	ohci_resume(hcd, false);
+ 	return 0;
+ }
+-
+-#else /* !CONFIG_PM */
+-#define ohci_platform_suspend	NULL
+-#define ohci_platform_resume	NULL
+-#endif /* CONFIG_PM */
++#endif /* CONFIG_PM_SLEEP */
+ 
+ static const struct of_device_id ohci_platform_ids[] = {
+ 	{ .compatible = "generic-ohci", },
+@@ -353,10 +366,8 @@ static const struct platform_device_id ohci_platform_table[] = {
+ };
+ MODULE_DEVICE_TABLE(platform, ohci_platform_table);
+ 
+-static const struct dev_pm_ops ohci_platform_pm_ops = {
+-	.suspend	= ohci_platform_suspend,
+-	.resume		= ohci_platform_resume,
+-};
++static SIMPLE_DEV_PM_OPS(ohci_platform_pm_ops, ohci_platform_suspend,
++		       ohci_platform_resume);
+ 
+ static struct platform_driver ohci_platform_driver = {
+ 	.id_table	= ohci_platform_table,
+diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
+index 59f4245..0548f5c 100644
+--- a/drivers/usb/host/ohci.h
++++ b/drivers/usb/host/ohci.h
+@@ -421,7 +421,6 @@ struct ohci_hcd {
+ 
+ 	// there are also chip quirks/bugs in init logic
+ 
+-	unsigned		prev_frame_no;
+ 	unsigned		wdh_cnt, prev_wdh_cnt;
+ 	u32			prev_donehead;
+ 	struct timer_list	io_watchdog;
+diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
+index 54f386f..8a6354b 100644
+--- a/drivers/usb/host/xhci.h
++++ b/drivers/usb/host/xhci.h
+@@ -33,6 +33,19 @@
+ #include	"xhci-ext-caps.h"
+ #include "pci-quirks.h"
+ 
++#if defined(CONFIG_ARCH_HI3519) || defined(CONFIG_ARCH_HI3519V101) || defined(CONFIG_ARCH_HI3516AV200)
++#ifdef readl
++#undef readl
++#undef readl_relaxed
++#undef writel
++#undef writel_relaxed
++#define readl		hi_readl
++#define readl_relaxed	hi_readl_relaxed
++#define writel		hi_writel
++#define writel_relaxed	hi_writel_relaxed
++#endif /* readl */
++#endif /* defined(CONFIG_ARCH_HI3519) || defined(CONFIG_ARCH_HI3519V101) || defined(CONFIG_ARCH_HI3516AV200) */
++
+ /* xHCI PCI Configuration Registers */
+ #define XHCI_SBRN_OFFSET	(0x60)
+ 
+diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig
+index 0cd1f44..77ef4bb 100644
+--- a/drivers/usb/phy/Kconfig
++++ b/drivers/usb/phy/Kconfig
+@@ -6,6 +6,14 @@ menu "USB Physical Layer drivers"
+ config USB_PHY
+ 	def_bool n
+ 
++config USB_OTG_WAKELOCK
++	bool "Hold a wakelock when USB connected"
++	depends on WAKELOCK
++	select USB_OTG_UTILS
++	help
++	  Select this to automatically hold a wakelock when USB is
++	  connected, preventing suspend.
++
+ #
+ # USB Transceiver Drivers
+ #
+@@ -213,4 +221,13 @@ config USB_ULPI_VIEWPORT
+ 	  Provides read/write operations to the ULPI phy register set for
+ 	  controllers with a viewport register (e.g. Chipidea/ARC controllers).
+ 
++config DUAL_ROLE_USB_INTF
++	bool "Generic DUAL ROLE sysfs interface"
++	depends on SYSFS && USB_PHY
++	help
++	  A generic sysfs interface to track and change the state of
++	  dual role usb phys. The usb phy drivers can register to
++	  this interface to expose it capabilities to the userspace
++	  and thereby allowing userspace to change the port mode.
++
+ endmenu
+diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile
+index 75f2bba..5cd7871 100644
+--- a/drivers/usb/phy/Makefile
++++ b/drivers/usb/phy/Makefile
+@@ -3,6 +3,8 @@
+ #
+ obj-$(CONFIG_USB_PHY)			+= phy.o
+ obj-$(CONFIG_OF)			+= of.o
++obj-$(CONFIG_USB_OTG_WAKELOCK)		+= otg-wakelock.o
++obj-$(CONFIG_DUAL_ROLE_USB_INTF)	+= class-dual-role.o
+ 
+ # transceiver drivers, keep the list sorted
+ 
+diff --git a/drivers/usb/phy/class-dual-role.c b/drivers/usb/phy/class-dual-role.c
+new file mode 100644
+index 0000000..51fcb54
+--- /dev/null
++++ b/drivers/usb/phy/class-dual-role.c
+@@ -0,0 +1,529 @@
++/*
++ * class-dual-role.c
++ *
++ * Copyright (C) 2015 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#include <linux/ctype.h>
++#include <linux/device.h>
++#include <linux/usb/class-dual-role.h>
++#include <linux/err.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/stat.h>
++#include <linux/types.h>
++
++#define DUAL_ROLE_NOTIFICATION_TIMEOUT 2000
++
++static ssize_t dual_role_store_property(struct device *dev,
++					struct device_attribute *attr,
++					const char *buf, size_t count);
++static ssize_t dual_role_show_property(struct device *dev,
++				       struct device_attribute *attr,
++				       char *buf);
++
++#define DUAL_ROLE_ATTR(_name)				\
++{							\
++	.attr = { .name = #_name },			\
++	.show = dual_role_show_property,		\
++	.store = dual_role_store_property,		\
++}
++
++static struct device_attribute dual_role_attrs[] = {
++	DUAL_ROLE_ATTR(supported_modes),
++	DUAL_ROLE_ATTR(mode),
++	DUAL_ROLE_ATTR(power_role),
++	DUAL_ROLE_ATTR(data_role),
++	DUAL_ROLE_ATTR(powers_vconn),
++};
++
++struct class *dual_role_class;
++EXPORT_SYMBOL_GPL(dual_role_class);
++
++static struct device_type dual_role_dev_type;
++
++static char *kstrdupcase(const char *str, gfp_t gfp, bool to_upper)
++{
++	char *ret, *ustr;
++
++	ustr = ret = kmalloc(strlen(str) + 1, gfp);
++
++	if (!ret)
++		return NULL;
++
++	while (*str)
++		*ustr++ = to_upper ? toupper(*str++) : tolower(*str++);
++
++	*ustr = 0;
++
++	return ret;
++}
++
++static void dual_role_changed_work(struct work_struct *work)
++{
++	struct dual_role_phy_instance *dual_role =
++	    container_of(work, struct dual_role_phy_instance,
++			 changed_work);
++
++	dev_dbg(&dual_role->dev, "%s\n", __func__);
++	kobject_uevent(&dual_role->dev.kobj, KOBJ_CHANGE);
++}
++
++void dual_role_instance_changed(struct dual_role_phy_instance *dual_role)
++{
++	dev_dbg(&dual_role->dev, "%s\n", __func__);
++	pm_wakeup_event(&dual_role->dev, DUAL_ROLE_NOTIFICATION_TIMEOUT);
++	schedule_work(&dual_role->changed_work);
++}
++EXPORT_SYMBOL_GPL(dual_role_instance_changed);
++
++int dual_role_get_property(struct dual_role_phy_instance *dual_role,
++			   enum dual_role_property prop,
++			   unsigned int *val)
++{
++	return dual_role->desc->get_property(dual_role, prop, val);
++}
++EXPORT_SYMBOL_GPL(dual_role_get_property);
++
++int dual_role_set_property(struct dual_role_phy_instance *dual_role,
++			   enum dual_role_property prop,
++			   const unsigned int *val)
++{
++	if (!dual_role->desc->set_property)
++		return -ENODEV;
++
++	return dual_role->desc->set_property(dual_role, prop, val);
++}
++EXPORT_SYMBOL_GPL(dual_role_set_property);
++
++int dual_role_property_is_writeable(struct dual_role_phy_instance *dual_role,
++				    enum dual_role_property prop)
++{
++	if (!dual_role->desc->property_is_writeable)
++		return -ENODEV;
++
++	return dual_role->desc->property_is_writeable(dual_role, prop);
++}
++EXPORT_SYMBOL_GPL(dual_role_property_is_writeable);
++
++static void dual_role_dev_release(struct device *dev)
++{
++	struct dual_role_phy_instance *dual_role =
++	    container_of(dev, struct dual_role_phy_instance, dev);
++	pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
++	kfree(dual_role);
++}
++
++static struct dual_role_phy_instance *__must_check
++__dual_role_register(struct device *parent,
++		     const struct dual_role_phy_desc *desc)
++{
++	struct device *dev;
++	struct dual_role_phy_instance *dual_role;
++	int rc;
++
++	dual_role = kzalloc(sizeof(*dual_role), GFP_KERNEL);
++	if (!dual_role)
++		return ERR_PTR(-ENOMEM);
++
++	dev = &dual_role->dev;
++
++	device_initialize(dev);
++
++	dev->class = dual_role_class;
++	dev->type = &dual_role_dev_type;
++	dev->parent = parent;
++	dev->release = dual_role_dev_release;
++	dev_set_drvdata(dev, dual_role);
++	dual_role->desc = desc;
++
++	rc = dev_set_name(dev, "%s", desc->name);
++	if (rc)
++		goto dev_set_name_failed;
++
++	INIT_WORK(&dual_role->changed_work, dual_role_changed_work);
++
++	rc = device_init_wakeup(dev, true);
++	if (rc)
++		goto wakeup_init_failed;
++
++	rc = device_add(dev);
++	if (rc)
++		goto device_add_failed;
++
++	dual_role_instance_changed(dual_role);
++
++	return dual_role;
++
++device_add_failed:
++	device_init_wakeup(dev, false);
++wakeup_init_failed:
++dev_set_name_failed:
++	put_device(dev);
++	kfree(dual_role);
++
++	return ERR_PTR(rc);
++}
++
++static void dual_role_instance_unregister(struct dual_role_phy_instance
++					  *dual_role)
++{
++	cancel_work_sync(&dual_role->changed_work);
++	device_init_wakeup(&dual_role->dev, false);
++	device_unregister(&dual_role->dev);
++}
++
++static void devm_dual_role_release(struct device *dev, void *res)
++{
++	struct dual_role_phy_instance **dual_role = res;
++
++	dual_role_instance_unregister(*dual_role);
++}
++
++struct dual_role_phy_instance *__must_check
++devm_dual_role_instance_register(struct device *parent,
++				 const struct dual_role_phy_desc *desc)
++{
++	struct dual_role_phy_instance **ptr, *dual_role;
++
++	ptr = devres_alloc(devm_dual_role_release, sizeof(*ptr), GFP_KERNEL);
++
++	if (!ptr)
++		return ERR_PTR(-ENOMEM);
++	dual_role = __dual_role_register(parent, desc);
++	if (IS_ERR(dual_role)) {
++		devres_free(ptr);
++	} else {
++		*ptr = dual_role;
++		devres_add(parent, ptr);
++	}
++	return dual_role;
++}
++EXPORT_SYMBOL_GPL(devm_dual_role_instance_register);
++
++static int devm_dual_role_match(struct device *dev, void *res, void *data)
++{
++	struct dual_role_phy_instance **r = res;
++
++	if (WARN_ON(!r || !*r))
++		return 0;
++
++	return *r == data;
++}
++
++void devm_dual_role_instance_unregister(struct device *dev,
++					struct dual_role_phy_instance
++					*dual_role)
++{
++	int rc;
++
++	rc = devres_release(dev, devm_dual_role_release,
++			    devm_dual_role_match, dual_role);
++	WARN_ON(rc);
++}
++EXPORT_SYMBOL_GPL(devm_dual_role_instance_unregister);
++
++void *dual_role_get_drvdata(struct dual_role_phy_instance *dual_role)
++{
++	return dual_role->drv_data;
++}
++EXPORT_SYMBOL_GPL(dual_role_get_drvdata);
++
++/***************** Device attribute functions **************************/
++
++/* port type */
++static char *supported_modes_text[] = {
++	"ufp dfp", "dfp", "ufp"
++};
++
++/* current mode */
++static char *mode_text[] = {
++	"ufp", "dfp", "none"
++};
++
++/* Power role */
++static char *pr_text[] = {
++	"source", "sink", "none"
++};
++
++/* Data role */
++static char *dr_text[] = {
++	"host", "device", "none"
++};
++
++/* Vconn supply */
++static char *vconn_supply_text[] = {
++	"n", "y"
++};
++
++static ssize_t dual_role_show_property(struct device *dev,
++				       struct device_attribute *attr, char *buf)
++{
++	ssize_t ret = 0;
++	struct dual_role_phy_instance *dual_role = dev_get_drvdata(dev);
++	const ptrdiff_t off = attr - dual_role_attrs;
++	unsigned int value;
++
++	if (off == DUAL_ROLE_PROP_SUPPORTED_MODES) {
++		value = dual_role->desc->supported_modes;
++	} else {
++		ret = dual_role_get_property(dual_role, off, &value);
++
++		if (ret < 0) {
++			if (ret == -ENODATA)
++				dev_dbg(dev,
++					"driver has no data for `%s' property\n",
++					attr->attr.name);
++			else if (ret != -ENODEV)
++				dev_err(dev,
++					"driver failed to report `%s' property: %zd\n",
++					attr->attr.name, ret);
++			return ret;
++		}
++	}
++
++	if (off == DUAL_ROLE_PROP_SUPPORTED_MODES) {
++		BUILD_BUG_ON(DUAL_ROLE_PROP_SUPPORTED_MODES_TOTAL !=
++			ARRAY_SIZE(supported_modes_text));
++		if (value < DUAL_ROLE_PROP_SUPPORTED_MODES_TOTAL)
++			return snprintf(buf, PAGE_SIZE, "%s\n",
++					supported_modes_text[value]);
++		else
++			return -EIO;
++	} else if (off == DUAL_ROLE_PROP_MODE) {
++		BUILD_BUG_ON(DUAL_ROLE_PROP_MODE_TOTAL !=
++			ARRAY_SIZE(mode_text));
++		if (value < DUAL_ROLE_PROP_MODE_TOTAL)
++			return snprintf(buf, PAGE_SIZE, "%s\n",
++					mode_text[value]);
++		else
++			return -EIO;
++	} else if (off == DUAL_ROLE_PROP_PR) {
++		BUILD_BUG_ON(DUAL_ROLE_PROP_PR_TOTAL != ARRAY_SIZE(pr_text));
++		if (value < DUAL_ROLE_PROP_PR_TOTAL)
++			return snprintf(buf, PAGE_SIZE, "%s\n",
++					pr_text[value]);
++		else
++			return -EIO;
++	} else if (off == DUAL_ROLE_PROP_DR) {
++		BUILD_BUG_ON(DUAL_ROLE_PROP_DR_TOTAL != ARRAY_SIZE(dr_text));
++		if (value < DUAL_ROLE_PROP_DR_TOTAL)
++			return snprintf(buf, PAGE_SIZE, "%s\n",
++					dr_text[value]);
++		else
++			return -EIO;
++	} else if (off == DUAL_ROLE_PROP_VCONN_SUPPLY) {
++		BUILD_BUG_ON(DUAL_ROLE_PROP_VCONN_SUPPLY_TOTAL !=
++				ARRAY_SIZE(vconn_supply_text));
++		if (value < DUAL_ROLE_PROP_VCONN_SUPPLY_TOTAL)
++			return snprintf(buf, PAGE_SIZE, "%s\n",
++					vconn_supply_text[value]);
++		else
++			return -EIO;
++	} else
++		return -EIO;
++}
++
++static ssize_t dual_role_store_property(struct device *dev,
++					struct device_attribute *attr,
++					const char *buf, size_t count)
++{
++	ssize_t ret;
++	struct dual_role_phy_instance *dual_role = dev_get_drvdata(dev);
++	const ptrdiff_t off = attr - dual_role_attrs;
++	unsigned int value;
++	int total, i;
++	char *dup_buf, **text_array;
++	bool result = false;
++
++	dup_buf = kstrdupcase(buf, GFP_KERNEL, false);
++	switch (off) {
++	case DUAL_ROLE_PROP_MODE:
++		total = DUAL_ROLE_PROP_MODE_TOTAL;
++		text_array = mode_text;
++		break;
++	case DUAL_ROLE_PROP_PR:
++		total = DUAL_ROLE_PROP_PR_TOTAL;
++		text_array = pr_text;
++		break;
++	case DUAL_ROLE_PROP_DR:
++		total = DUAL_ROLE_PROP_DR_TOTAL;
++		text_array = dr_text;
++		break;
++	case DUAL_ROLE_PROP_VCONN_SUPPLY:
++		ret = strtobool(dup_buf, &result);
++		value = result;
++		if (!ret)
++			goto setprop;
++	default:
++		ret = -EINVAL;
++		goto error;
++	}
++
++	for (i = 0; i <= total; i++) {
++		if (i == total) {
++			ret = -ENOTSUPP;
++			goto error;
++		}
++		if (!strncmp(*(text_array + i), dup_buf,
++			     strlen(*(text_array + i)))) {
++			value = i;
++			break;
++		}
++	}
++
++setprop:
++	ret = dual_role->desc->set_property(dual_role, off, &value);
++
++error:
++	kfree(dup_buf);
++
++	if (ret < 0)
++		return ret;
++
++	return count;
++}
++
++static umode_t dual_role_attr_is_visible(struct kobject *kobj,
++					 struct attribute *attr, int attrno)
++{
++	struct device *dev = container_of(kobj, struct device, kobj);
++	struct dual_role_phy_instance *dual_role = dev_get_drvdata(dev);
++	umode_t mode = S_IRUSR | S_IRGRP | S_IROTH;
++	int i;
++
++	if (attrno == DUAL_ROLE_PROP_SUPPORTED_MODES)
++		return mode;
++
++	for (i = 0; i < dual_role->desc->num_properties; i++) {
++		int property = dual_role->desc->properties[i];
++
++		if (property == attrno) {
++			if (dual_role->desc->property_is_writeable &&
++			    dual_role_property_is_writeable(dual_role, property)
++			    > 0)
++				mode |= S_IWUSR;
++
++			return mode;
++		}
++	}
++
++	return 0;
++}
++
++static struct attribute *__dual_role_attrs[ARRAY_SIZE(dual_role_attrs) + 1];
++
++static struct attribute_group dual_role_attr_group = {
++	.attrs = __dual_role_attrs,
++	.is_visible = dual_role_attr_is_visible,
++};
++
++static const struct attribute_group *dual_role_attr_groups[] = {
++	&dual_role_attr_group,
++	NULL,
++};
++
++void dual_role_init_attrs(struct device_type *dev_type)
++{
++	int i;
++
++	dev_type->groups = dual_role_attr_groups;
++
++	for (i = 0; i < ARRAY_SIZE(dual_role_attrs); i++)
++		__dual_role_attrs[i] = &dual_role_attrs[i].attr;
++}
++
++int dual_role_uevent(struct device *dev, struct kobj_uevent_env *env)
++{
++	struct dual_role_phy_instance *dual_role = dev_get_drvdata(dev);
++	int ret = 0, j;
++	char *prop_buf;
++	char *attrname;
++
++	dev_dbg(dev, "uevent\n");
++
++	if (!dual_role || !dual_role->desc) {
++		dev_dbg(dev, "No dual_role phy yet\n");
++		return ret;
++	}
++
++	dev_dbg(dev, "DUAL_ROLE_NAME=%s\n", dual_role->desc->name);
++
++	ret = add_uevent_var(env, "DUAL_ROLE_NAME=%s", dual_role->desc->name);
++	if (ret)
++		return ret;
++
++	prop_buf = (char *)get_zeroed_page(GFP_KERNEL);
++	if (!prop_buf)
++		return -ENOMEM;
++
++	for (j = 0; j < dual_role->desc->num_properties; j++) {
++		struct device_attribute *attr;
++		char *line;
++
++		attr = &dual_role_attrs[dual_role->desc->properties[j]];
++
++		ret = dual_role_show_property(dev, attr, prop_buf);
++		if (ret == -ENODEV || ret == -ENODATA) {
++			ret = 0;
++			continue;
++		}
++
++		if (ret < 0)
++			goto out;
++		line = strnchr(prop_buf, PAGE_SIZE, '\n');
++		if (line)
++			*line = 0;
++
++		attrname = kstrdupcase(attr->attr.name, GFP_KERNEL, true);
++		if (!attrname)
++			ret = -ENOMEM;
++
++		dev_dbg(dev, "prop %s=%s\n", attrname, prop_buf);
++
++		ret = add_uevent_var(env, "DUAL_ROLE_%s=%s", attrname,
++				     prop_buf);
++		kfree(attrname);
++		if (ret)
++			goto out;
++	}
++
++out:
++	free_page((unsigned long)prop_buf);
++
++	return ret;
++}
++
++/******************* Module Init ***********************************/
++
++static int __init dual_role_class_init(void)
++{
++	dual_role_class = class_create(THIS_MODULE, "dual_role_usb");
++
++	if (IS_ERR(dual_role_class))
++		return PTR_ERR(dual_role_class);
++
++	dual_role_class->dev_uevent = dual_role_uevent;
++	dual_role_init_attrs(&dual_role_dev_type);
++
++	return 0;
++}
++
++static void __exit dual_role_class_exit(void)
++{
++	class_destroy(dual_role_class);
++}
++
++subsys_initcall(dual_role_class_init);
++module_exit(dual_role_class_exit);
+diff --git a/drivers/usb/phy/otg-wakelock.c b/drivers/usb/phy/otg-wakelock.c
+new file mode 100644
+index 0000000..479376b
+--- /dev/null
++++ b/drivers/usb/phy/otg-wakelock.c
+@@ -0,0 +1,173 @@
++/*
++ * otg-wakelock.c
++ *
++ * Copyright (C) 2011 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/device.h>
++#include <linux/err.h>
++#include <linux/module.h>
++#include <linux/notifier.h>
++#include <linux/wakelock.h>
++#include <linux/spinlock.h>
++#include <linux/usb/otg.h>
++
++#define TEMPORARY_HOLD_TIME	2000
++
++static bool enabled = true;
++static struct usb_phy *otgwl_xceiv;
++static struct notifier_block otgwl_nb;
++
++/*
++ * otgwl_spinlock is held while the VBUS lock is grabbed or dropped and the
++ * held field is updated to match.
++ */
++
++static DEFINE_SPINLOCK(otgwl_spinlock);
++
++/*
++ * Only one lock, but since these 3 fields are associated with each other...
++ */
++
++struct otgwl_lock {
++	char name[40];
++	struct wake_lock wakelock;
++	bool held;
++};
++
++/*
++ * VBUS present lock.  Also used as a timed lock on charger
++ * connect/disconnect and USB host disconnect, to allow the system
++ * to react to the change in power.
++ */
++
++static struct otgwl_lock vbus_lock;
++
++static void otgwl_hold(struct otgwl_lock *lock)
++{
++	if (!lock->held) {
++		wake_lock(&lock->wakelock);
++		lock->held = true;
++	}
++}
++
++static void otgwl_temporary_hold(struct otgwl_lock *lock)
++{
++	wake_lock_timeout(&lock->wakelock,
++			  msecs_to_jiffies(TEMPORARY_HOLD_TIME));
++	lock->held = false;
++}
++
++static void otgwl_drop(struct otgwl_lock *lock)
++{
++	if (lock->held) {
++		wake_unlock(&lock->wakelock);
++		lock->held = false;
++	}
++}
++
++static void otgwl_handle_event(unsigned long event)
++{
++	unsigned long irqflags;
++
++	spin_lock_irqsave(&otgwl_spinlock, irqflags);
++
++	if (!enabled) {
++		otgwl_drop(&vbus_lock);
++		spin_unlock_irqrestore(&otgwl_spinlock, irqflags);
++		return;
++	}
++
++	switch (event) {
++	case USB_EVENT_VBUS:
++	case USB_EVENT_ENUMERATED:
++		otgwl_hold(&vbus_lock);
++		break;
++
++	case USB_EVENT_NONE:
++	case USB_EVENT_ID:
++	case USB_EVENT_CHARGER:
++		otgwl_temporary_hold(&vbus_lock);
++		break;
++
++	default:
++		break;
++	}
++
++	spin_unlock_irqrestore(&otgwl_spinlock, irqflags);
++}
++
++static int otgwl_otg_notifications(struct notifier_block *nb,
++				   unsigned long event, void *unused)
++{
++	otgwl_handle_event(event);
++	return NOTIFY_OK;
++}
++
++static int set_enabled(const char *val, const struct kernel_param *kp)
++{
++	int rv = param_set_bool(val, kp);
++
++	if (rv)
++		return rv;
++
++	if (otgwl_xceiv)
++		otgwl_handle_event(otgwl_xceiv->last_event);
++
++	return 0;
++}
++
++static struct kernel_param_ops enabled_param_ops = {
++	.set = set_enabled,
++	.get = param_get_bool,
++};
++
++module_param_cb(enabled, &enabled_param_ops, &enabled, 0644);
++MODULE_PARM_DESC(enabled, "enable wakelock when VBUS present");
++
++static int __init otg_wakelock_init(void)
++{
++	int ret;
++	struct usb_phy *phy;
++
++	phy = usb_get_phy(USB_PHY_TYPE_USB2);
++
++	if (IS_ERR(phy)) {
++		pr_err("%s: No USB transceiver found\n", __func__);
++		return PTR_ERR(phy);
++	}
++	otgwl_xceiv = phy;
++
++	snprintf(vbus_lock.name, sizeof(vbus_lock.name), "vbus-%s",
++		 dev_name(otgwl_xceiv->dev));
++	wake_lock_init(&vbus_lock.wakelock, WAKE_LOCK_SUSPEND,
++		       vbus_lock.name);
++
++	otgwl_nb.notifier_call = otgwl_otg_notifications;
++	ret = usb_register_notifier(otgwl_xceiv, &otgwl_nb);
++
++	if (ret) {
++		pr_err("%s: usb_register_notifier on transceiver %s"
++		       " failed\n", __func__,
++		       dev_name(otgwl_xceiv->dev));
++		otgwl_xceiv = NULL;
++		wake_lock_destroy(&vbus_lock.wakelock);
++		return ret;
++	}
++
++	otgwl_handle_event(otgwl_xceiv->last_event);
++	return ret;
++}
++
++late_initcall(otg_wakelock_init);
+diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c
+index cb84f69..313f09a 100644
+--- a/drivers/vhost/scsi.c
++++ b/drivers/vhost/scsi.c
+@@ -1251,7 +1251,7 @@ tcm_vhost_send_evt(struct vhost_scsi *vs,
+ 		 * lun[4-7] need to be zero according to virtio-scsi spec.
+ 		 */
+ 		evt->event.lun[0] = 0x01;
+-		evt->event.lun[1] = tpg->tport_tpgt & 0xFF;
++		evt->event.lun[1] = tpg->tport_tpgt;
+ 		if (lun->unpacked_lun >= 256)
+ 			evt->event.lun[2] = lun->unpacked_lun >> 8 | 0x40 ;
+ 		evt->event.lun[3] = lun->unpacked_lun & 0xFF;
+@@ -2122,12 +2122,12 @@ tcm_vhost_make_tpg(struct se_wwn *wwn,
+ 			struct tcm_vhost_tport, tport_wwn);
+ 
+ 	struct tcm_vhost_tpg *tpg;
+-	unsigned long tpgt;
++	u16 tpgt;
+ 	int ret;
+ 
+ 	if (strstr(name, "tpgt_") != name)
+ 		return ERR_PTR(-EINVAL);
+-	if (kstrtoul(name + 5, 10, &tpgt) || tpgt > UINT_MAX)
++	if (kstrtou16(name + 5, 10, &tpgt) || tpgt >= VHOST_SCSI_MAX_TARGET)
+ 		return ERR_PTR(-EINVAL);
+ 
+ 	tpg = kzalloc(sizeof(struct tcm_vhost_tpg), GFP_KERNEL);
+diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
+index 8bf495f..49fcbb1 100644
+--- a/drivers/video/Kconfig
++++ b/drivers/video/Kconfig
+@@ -31,6 +31,7 @@ source "drivers/video/fbdev/Kconfig"
+ endmenu
+ 
+ source "drivers/video/backlight/Kconfig"
++source "drivers/video/adf/Kconfig"
+ 
+ config VGASTATE
+        tristate
+diff --git a/drivers/video/Makefile b/drivers/video/Makefile
+index 9ad3c17..1a8c4ce 100644
+--- a/drivers/video/Makefile
++++ b/drivers/video/Makefile
+@@ -1,6 +1,7 @@
+ obj-$(CONFIG_VGASTATE)            += vgastate.o
+ obj-$(CONFIG_HDMI)                += hdmi.o
+ 
++obj-$(CONFIG_ADF)		  += adf/
+ obj-$(CONFIG_VT)		  += console/
+ obj-$(CONFIG_LOGO)		  += logo/
+ obj-y				  += backlight/
+diff --git a/drivers/video/adf/Kconfig b/drivers/video/adf/Kconfig
+new file mode 100644
+index 0000000..33858b7
+--- /dev/null
++++ b/drivers/video/adf/Kconfig
+@@ -0,0 +1,14 @@
++menuconfig ADF
++	depends on SYNC
++	depends on DMA_SHARED_BUFFER
++	tristate "Atomic Display Framework"
++
++menuconfig ADF_FBDEV
++	depends on ADF
++	depends on FB
++	tristate "Helper for implementing the fbdev API in ADF drivers"
++
++menuconfig ADF_MEMBLOCK
++	depends on ADF
++	depends on HAVE_MEMBLOCK
++	tristate "Helper for using memblocks as buffers in ADF drivers"
+diff --git a/drivers/video/adf/Makefile b/drivers/video/adf/Makefile
+new file mode 100644
+index 0000000..78d0915
+--- /dev/null
++++ b/drivers/video/adf/Makefile
+@@ -0,0 +1,15 @@
++ccflags-y := -Idrivers/staging/android
++
++CFLAGS_adf.o := -I$(src)
++
++obj-$(CONFIG_ADF) += adf.o \
++	adf_client.o \
++	adf_fops.o \
++	adf_format.o \
++	adf_sysfs.o
++
++obj-$(CONFIG_COMPAT) += adf_fops32.o
++
++obj-$(CONFIG_ADF_FBDEV) += adf_fbdev.o
++
++obj-$(CONFIG_ADF_MEMBLOCK) += adf_memblock.o
+diff --git a/drivers/video/adf/adf.c b/drivers/video/adf/adf.c
+new file mode 100644
+index 0000000..42c30c0
+--- /dev/null
++++ b/drivers/video/adf/adf.c
+@@ -0,0 +1,1188 @@
++/*
++ * Copyright (C) 2013 Google, Inc.
++ * adf_modeinfo_{set_name,set_vrefresh} modified from
++ * drivers/gpu/drm/drm_modes.c
++ * adf_format_validate_yuv modified from framebuffer_check in
++ * drivers/gpu/drm/drm_crtc.c
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#include <linux/device.h>
++#include <linux/idr.h>
++#include <linux/highmem.h>
++#include <linux/memblock.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++
++#include <video/adf_format.h>
++
++#include "sw_sync.h"
++#include "sync.h"
++
++#include "adf.h"
++#include "adf_fops.h"
++#include "adf_sysfs.h"
++
++#define CREATE_TRACE_POINTS
++#include "adf_trace.h"
++
++#define ADF_SHORT_FENCE_TIMEOUT (1 * MSEC_PER_SEC)
++#define ADF_LONG_FENCE_TIMEOUT (10 * MSEC_PER_SEC)
++
++static DEFINE_IDR(adf_devices);
++
++static void adf_fence_wait(struct adf_device *dev, struct sync_fence *fence)
++{
++	/* sync_fence_wait() dumps debug information on timeout.  Experience
++	   has shown that if the pipeline gets stuck, a short timeout followed
++	   by a longer one provides useful information for debugging. */
++	int err = sync_fence_wait(fence, ADF_SHORT_FENCE_TIMEOUT);
++	if (err >= 0)
++		return;
++
++	if (err == -ETIME)
++		err = sync_fence_wait(fence, ADF_LONG_FENCE_TIMEOUT);
++
++	if (err < 0)
++		dev_warn(&dev->base.dev, "error waiting on fence: %d\n", err);
++}
++
++void adf_buffer_cleanup(struct adf_buffer *buf)
++{
++	size_t i;
++	for (i = 0; i < ARRAY_SIZE(buf->dma_bufs); i++)
++		if (buf->dma_bufs[i])
++			dma_buf_put(buf->dma_bufs[i]);
++
++	if (buf->acquire_fence)
++		sync_fence_put(buf->acquire_fence);
++}
++
++void adf_buffer_mapping_cleanup(struct adf_buffer_mapping *mapping,
++		struct adf_buffer *buf)
++{
++	/* calling adf_buffer_mapping_cleanup() is safe even if mapping is
++	   uninitialized or partially-initialized, as long as it was
++	   zeroed on allocation */
++	size_t i;
++	for (i = 0; i < ARRAY_SIZE(mapping->sg_tables); i++) {
++		if (mapping->sg_tables[i])
++			dma_buf_unmap_attachment(mapping->attachments[i],
++					mapping->sg_tables[i], DMA_TO_DEVICE);
++		if (mapping->attachments[i])
++			dma_buf_detach(buf->dma_bufs[i],
++					mapping->attachments[i]);
++	}
++}
++
++void adf_post_cleanup(struct adf_device *dev, struct adf_pending_post *post)
++{
++	size_t i;
++
++	if (post->state)
++		dev->ops->state_free(dev, post->state);
++
++	for (i = 0; i < post->config.n_bufs; i++) {
++		adf_buffer_mapping_cleanup(&post->config.mappings[i],
++				&post->config.bufs[i]);
++		adf_buffer_cleanup(&post->config.bufs[i]);
++	}
++
++	kfree(post->config.custom_data);
++	kfree(post->config.mappings);
++	kfree(post->config.bufs);
++	kfree(post);
++}
++
++static void adf_sw_advance_timeline(struct adf_device *dev)
++{
++#ifdef CONFIG_SW_SYNC
++	sw_sync_timeline_inc(dev->timeline, 1);
++#else
++	BUG();
++#endif
++}
++
++static void adf_post_work_func(struct kthread_work *work)
++{
++	struct adf_device *dev =
++			container_of(work, struct adf_device, post_work);
++	struct adf_pending_post *post, *next;
++	struct list_head saved_list;
++
++	mutex_lock(&dev->post_lock);
++	memcpy(&saved_list, &dev->post_list, sizeof(saved_list));
++	list_replace_init(&dev->post_list, &saved_list);
++	mutex_unlock(&dev->post_lock);
++
++	list_for_each_entry_safe(post, next, &saved_list, head) {
++		int i;
++
++		for (i = 0; i < post->config.n_bufs; i++) {
++			struct sync_fence *fence =
++					post->config.bufs[i].acquire_fence;
++			if (fence)
++				adf_fence_wait(dev, fence);
++		}
++
++		dev->ops->post(dev, &post->config, post->state);
++
++		if (dev->ops->advance_timeline)
++			dev->ops->advance_timeline(dev, &post->config,
++					post->state);
++		else
++			adf_sw_advance_timeline(dev);
++
++		list_del(&post->head);
++		if (dev->onscreen)
++			adf_post_cleanup(dev, dev->onscreen);
++		dev->onscreen = post;
++	}
++}
++
++void adf_attachment_free(struct adf_attachment_list *attachment)
++{
++	list_del(&attachment->head);
++	kfree(attachment);
++}
++
++struct adf_event_refcount *adf_obj_find_event_refcount(struct adf_obj *obj,
++		enum adf_event_type type)
++{
++	struct rb_root *root = &obj->event_refcount;
++	struct rb_node **new = &(root->rb_node);
++	struct rb_node *parent = NULL;
++	struct adf_event_refcount *refcount;
++
++	while (*new) {
++		refcount = container_of(*new, struct adf_event_refcount, node);
++		parent = *new;
++
++		if (refcount->type > type)
++			new = &(*new)->rb_left;
++		else if (refcount->type < type)
++			new = &(*new)->rb_right;
++		else
++			return refcount;
++	}
++
++	refcount = kzalloc(sizeof(*refcount), GFP_KERNEL);
++	if (!refcount)
++		return NULL;
++	refcount->type = type;
++
++	rb_link_node(&refcount->node, parent, new);
++	rb_insert_color(&refcount->node, root);
++	return refcount;
++}
++
++/**
++ * adf_event_get - increase the refcount for an event
++ *
++ * @obj: the object that produces the event
++ * @type: the event type
++ *
++ * ADF will call the object's set_event() op if needed.  ops are allowed
++ * to sleep, so adf_event_get() must NOT be called from an atomic context.
++ *
++ * Returns 0 if successful, or -%EINVAL if the object does not support the
++ * requested event type.
++ */
++int adf_event_get(struct adf_obj *obj, enum adf_event_type type)
++{
++	struct adf_event_refcount *refcount;
++	int old_refcount;
++	int ret;
++
++	ret = adf_obj_check_supports_event(obj, type);
++	if (ret < 0)
++		return ret;
++
++	mutex_lock(&obj->event_lock);
++
++	refcount = adf_obj_find_event_refcount(obj, type);
++	if (!refcount) {
++		ret = -ENOMEM;
++		goto done;
++	}
++
++	old_refcount = refcount->refcount++;
++
++	if (old_refcount == 0) {
++		obj->ops->set_event(obj, type, true);
++		trace_adf_event_enable(obj, type);
++	}
++
++done:
++	mutex_unlock(&obj->event_lock);
++	return ret;
++}
++EXPORT_SYMBOL(adf_event_get);
++
++/**
++ * adf_event_put - decrease the refcount for an event
++ *
++ * @obj: the object that produces the event
++ * @type: the event type
++ *
++ * ADF will call the object's set_event() op if needed.  ops are allowed
++ * to sleep, so adf_event_put() must NOT be called from an atomic context.
++ *
++ * Returns 0 if successful, -%EINVAL if the object does not support the
++ * requested event type, or -%EALREADY if the refcount is already 0.
++ */
++int adf_event_put(struct adf_obj *obj, enum adf_event_type type)
++{
++	struct adf_event_refcount *refcount;
++	int old_refcount;
++	int ret;
++
++	ret = adf_obj_check_supports_event(obj, type);
++	if (ret < 0)
++		return ret;
++
++
++	mutex_lock(&obj->event_lock);
++
++	refcount = adf_obj_find_event_refcount(obj, type);
++	if (!refcount) {
++		ret = -ENOMEM;
++		goto done;
++	}
++
++	old_refcount = refcount->refcount--;
++
++	if (WARN_ON(old_refcount == 0)) {
++		refcount->refcount++;
++		ret = -EALREADY;
++	} else if (old_refcount == 1) {
++		obj->ops->set_event(obj, type, false);
++		trace_adf_event_disable(obj, type);
++	}
++
++done:
++	mutex_unlock(&obj->event_lock);
++	return ret;
++}
++EXPORT_SYMBOL(adf_event_put);
++
++/**
++ * adf_vsync_wait - wait for a vsync event on a display interface
++ *
++ * @intf: the display interface
++ * @timeout: timeout in jiffies (0 = wait indefinitely)
++ *
++ * adf_vsync_wait() may sleep, so it must NOT be called from an atomic context.
++ *
++ * This function returns -%ERESTARTSYS if it is interrupted by a signal.
++ * If @timeout == 0 then this function returns 0 on vsync. If @timeout > 0 then
++ * this function returns the number of remaining jiffies or -%ETIMEDOUT on
++ * timeout.
++ */
++int adf_vsync_wait(struct adf_interface *intf, long timeout)
++{
++	ktime_t timestamp;
++	int ret;
++	unsigned long flags;
++
++	read_lock_irqsave(&intf->vsync_lock, flags);
++	timestamp = intf->vsync_timestamp;
++	read_unlock_irqrestore(&intf->vsync_lock, flags);
++
++	adf_vsync_get(intf);
++	if (timeout) {
++		ret = wait_event_interruptible_timeout(intf->vsync_wait,
++				!ktime_equal(timestamp,
++						intf->vsync_timestamp),
++				msecs_to_jiffies(timeout));
++		if (ret == 0 && ktime_equal(timestamp, intf->vsync_timestamp))
++			ret = -ETIMEDOUT;
++	} else {
++		ret = wait_event_interruptible(intf->vsync_wait,
++				!ktime_equal(timestamp,
++						intf->vsync_timestamp));
++	}
++	adf_vsync_put(intf);
++
++	return ret;
++}
++EXPORT_SYMBOL(adf_vsync_wait);
++
++static void adf_event_queue(struct adf_obj *obj, struct adf_event *event)
++{
++	struct adf_file *file;
++	unsigned long flags;
++
++	trace_adf_event(obj, event->type);
++
++	spin_lock_irqsave(&obj->file_lock, flags);
++
++	list_for_each_entry(file, &obj->file_list, head)
++		if (test_bit(event->type, file->event_subscriptions))
++			adf_file_queue_event(file, event);
++
++	spin_unlock_irqrestore(&obj->file_lock, flags);
++}
++
++/**
++ * adf_event_notify - notify userspace of a driver-private event
++ *
++ * @obj: the ADF object that produced the event
++ * @event: the event
++ *
++ * adf_event_notify() may be called safely from an atomic context.  It will
++ * copy @event if needed, so @event may point to a variable on the stack.
++ *
++ * Drivers must NOT call adf_event_notify() for vsync and hotplug events.
++ * ADF provides adf_vsync_notify() and
++ * adf_hotplug_notify_{connected,disconnected}() for these events.
++ */
++int adf_event_notify(struct adf_obj *obj, struct adf_event *event)
++{
++	if (WARN_ON(event->type == ADF_EVENT_VSYNC ||
++			event->type == ADF_EVENT_HOTPLUG))
++		return -EINVAL;
++
++	adf_event_queue(obj, event);
++	return 0;
++}
++EXPORT_SYMBOL(adf_event_notify);
++
++/**
++ * adf_vsync_notify - notify ADF of a display interface's vsync event
++ *
++ * @intf: the display interface
++ * @timestamp: the time the vsync occurred
++ *
++ * adf_vsync_notify() may be called safely from an atomic context.
++ */
++void adf_vsync_notify(struct adf_interface *intf, ktime_t timestamp)
++{
++	unsigned long flags;
++	struct adf_vsync_event event;
++
++	write_lock_irqsave(&intf->vsync_lock, flags);
++	intf->vsync_timestamp = timestamp;
++	write_unlock_irqrestore(&intf->vsync_lock, flags);
++
++	wake_up_interruptible_all(&intf->vsync_wait);
++
++	event.base.type = ADF_EVENT_VSYNC;
++	event.base.length = sizeof(event);
++	event.timestamp = ktime_to_ns(timestamp);
++	adf_event_queue(&intf->base, &event.base);
++}
++EXPORT_SYMBOL(adf_vsync_notify);
++
++void adf_hotplug_notify(struct adf_interface *intf, bool connected,
++		struct drm_mode_modeinfo *modelist, size_t n_modes)
++{
++	unsigned long flags;
++	struct adf_hotplug_event event;
++	struct drm_mode_modeinfo *old_modelist;
++
++	write_lock_irqsave(&intf->hotplug_modelist_lock, flags);
++	old_modelist = intf->modelist;
++	intf->hotplug_detect = connected;
++	intf->modelist = modelist;
++	intf->n_modes = n_modes;
++	write_unlock_irqrestore(&intf->hotplug_modelist_lock, flags);
++
++	kfree(old_modelist);
++
++	event.base.length = sizeof(event);
++	event.base.type = ADF_EVENT_HOTPLUG;
++	event.connected = connected;
++	adf_event_queue(&intf->base, &event.base);
++}
++
++/**
++ * adf_hotplug_notify_connected - notify ADF of a display interface being
++ * connected to a display
++ *
++ * @intf: the display interface
++ * @modelist: hardware modes supported by display
++ * @n_modes: length of modelist
++ *
++ * @modelist is copied as needed, so it may point to a variable on the stack.
++ *
++ * adf_hotplug_notify_connected() may NOT be called safely from an atomic
++ * context.
++ *
++ * Returns 0 on success or error code (<0) on error.
++ */
++int adf_hotplug_notify_connected(struct adf_interface *intf,
++		struct drm_mode_modeinfo *modelist, size_t n_modes)
++{
++	struct drm_mode_modeinfo *modelist_copy;
++
++	if (n_modes > ADF_MAX_MODES)
++		return -ENOMEM;
++
++	modelist_copy = kzalloc(sizeof(modelist_copy[0]) * n_modes,
++			GFP_KERNEL);
++	if (!modelist_copy)
++		return -ENOMEM;
++	memcpy(modelist_copy, modelist, sizeof(modelist_copy[0]) * n_modes);
++
++	adf_hotplug_notify(intf, true, modelist_copy, n_modes);
++	return 0;
++}
++EXPORT_SYMBOL(adf_hotplug_notify_connected);
++
++/**
++ * adf_hotplug_notify_disconnected - notify ADF of a display interface being
++ * disconnected from a display
++ *
++ * @intf: the display interface
++ *
++ * adf_hotplug_notify_disconnected() may be called safely from an atomic
++ * context.
++ */
++void adf_hotplug_notify_disconnected(struct adf_interface *intf)
++{
++	adf_hotplug_notify(intf, false, NULL, 0);
++}
++EXPORT_SYMBOL(adf_hotplug_notify_disconnected);
++
++static int adf_obj_init(struct adf_obj *obj, enum adf_obj_type type,
++		struct idr *idr, struct adf_device *parent,
++		const struct adf_obj_ops *ops, const char *fmt, va_list args)
++{
++	int ret;
++
++	if (ops && ops->supports_event && !ops->set_event) {
++		pr_err("%s: %s implements supports_event but not set_event\n",
++				__func__, adf_obj_type_str(type));
++		return -EINVAL;
++	}
++
++	ret = idr_alloc(idr, obj, 0, 0, GFP_KERNEL);
++	if (ret < 0) {
++		pr_err("%s: allocating object id failed: %d\n", __func__, ret);
++		return ret;
++	}
++	obj->id = ret;
++
++	vscnprintf(obj->name, sizeof(obj->name), fmt, args);
++
++	obj->type = type;
++	obj->ops = ops;
++	obj->parent = parent;
++	mutex_init(&obj->event_lock);
++	obj->event_refcount = RB_ROOT;
++	spin_lock_init(&obj->file_lock);
++	INIT_LIST_HEAD(&obj->file_list);
++	return 0;
++}
++
++static void adf_obj_destroy(struct adf_obj *obj, struct idr *idr)
++{
++	struct rb_node *node = rb_first(&obj->event_refcount);
++
++	while (node) {
++		struct adf_event_refcount *refcount =
++				container_of(node, struct adf_event_refcount,
++						node);
++		rb_erase(&refcount->node, &obj->event_refcount);
++		kfree(refcount);
++		node = rb_first(&obj->event_refcount);
++	}
++
++	mutex_destroy(&obj->event_lock);
++	idr_remove(idr, obj->id);
++}
++
++/**
++ * adf_device_init - initialize ADF-internal data for a display device
++ * and create sysfs entries
++ *
++ * @dev: the display device
++ * @parent: the device's parent device
++ * @ops: the device's associated ops
++ * @fmt: formatting string for the display device's name
++ *
++ * @fmt specifies the device's sysfs filename and the name returned to
++ * userspace through the %ADF_GET_DEVICE_DATA ioctl.
++ *
++ * Returns 0 on success or error code (<0) on failure.
++ */
++int adf_device_init(struct adf_device *dev, struct device *parent,
++		const struct adf_device_ops *ops, const char *fmt, ...)
++{
++	int ret;
++	va_list args;
++
++	if (!ops->validate || !ops->post) {
++		pr_err("%s: device must implement validate and post\n",
++				__func__);
++		return -EINVAL;
++	}
++
++	if (!ops->complete_fence && !ops->advance_timeline) {
++		if (!IS_ENABLED(CONFIG_SW_SYNC)) {
++			pr_err("%s: device requires sw_sync but it is not enabled in the kernel\n",
++					__func__);
++			return -EINVAL;
++		}
++	} else if (!(ops->complete_fence && ops->advance_timeline)) {
++		pr_err("%s: device must implement both complete_fence and advance_timeline, or implement neither\n",
++				__func__);
++		return -EINVAL;
++	}
++
++	memset(dev, 0, sizeof(*dev));
++
++	va_start(args, fmt);
++	ret = adf_obj_init(&dev->base, ADF_OBJ_DEVICE, &adf_devices, dev,
++			&ops->base, fmt, args);
++	va_end(args);
++	if (ret < 0)
++		return ret;
++
++	dev->dev = parent;
++	dev->ops = ops;
++	idr_init(&dev->overlay_engines);
++	idr_init(&dev->interfaces);
++	mutex_init(&dev->client_lock);
++	INIT_LIST_HEAD(&dev->post_list);
++	mutex_init(&dev->post_lock);
++	init_kthread_worker(&dev->post_worker);
++	INIT_LIST_HEAD(&dev->attached);
++	INIT_LIST_HEAD(&dev->attach_allowed);
++
++	dev->post_thread = kthread_run(kthread_worker_fn,
++			&dev->post_worker, dev->base.name);
++	if (IS_ERR(dev->post_thread)) {
++		ret = PTR_ERR(dev->post_thread);
++		dev->post_thread = NULL;
++
++		pr_err("%s: failed to run config posting thread: %d\n",
++				__func__, ret);
++		goto err;
++	}
++	init_kthread_work(&dev->post_work, adf_post_work_func);
++
++	ret = adf_device_sysfs_init(dev);
++	if (ret < 0)
++		goto err;
++
++	return 0;
++
++err:
++	adf_device_destroy(dev);
++	return ret;
++}
++EXPORT_SYMBOL(adf_device_init);
++
++/**
++ * adf_device_destroy - clean up ADF-internal data for a display device
++ *
++ * @dev: the display device
++ */
++void adf_device_destroy(struct adf_device *dev)
++{
++	struct adf_attachment_list *entry, *next;
++
++	idr_destroy(&dev->interfaces);
++	idr_destroy(&dev->overlay_engines);
++
++	if (dev->post_thread) {
++		flush_kthread_worker(&dev->post_worker);
++		kthread_stop(dev->post_thread);
++	}
++
++	if (dev->onscreen)
++		adf_post_cleanup(dev, dev->onscreen);
++	adf_device_sysfs_destroy(dev);
++	list_for_each_entry_safe(entry, next, &dev->attach_allowed, head) {
++		adf_attachment_free(entry);
++	}
++	list_for_each_entry_safe(entry, next, &dev->attached, head) {
++		adf_attachment_free(entry);
++	}
++	mutex_destroy(&dev->post_lock);
++	mutex_destroy(&dev->client_lock);
++
++	if (dev->timeline)
++		sync_timeline_destroy(&dev->timeline->obj);
++
++	adf_obj_destroy(&dev->base, &adf_devices);
++}
++EXPORT_SYMBOL(adf_device_destroy);
++
++/**
++ * adf_interface_init - initialize ADF-internal data for a display interface
++ * and create sysfs entries
++ *
++ * @intf: the display interface
++ * @dev: the interface's "parent" display device
++ * @type: interface type (see enum @adf_interface_type)
++ * @idx: which interface of type @type;
++ *	e.g. interface DSI.1 -> @type=%ADF_INTF_TYPE_DSI, @idx=1
++ * @flags: informational flags (bitmask of %ADF_INTF_FLAG_* values)
++ * @ops: the interface's associated ops
++ * @fmt: formatting string for the display interface's name
++ *
++ * @dev must have previously been initialized with adf_device_init().
++ *
++ * @fmt affects the name returned to userspace through the
++ * %ADF_GET_INTERFACE_DATA ioctl.  It does not affect the sysfs filename,
++ * which is derived from @dev's name.
++ *
++ * Returns 0 on success or error code (<0) on failure.
++ */
++int adf_interface_init(struct adf_interface *intf, struct adf_device *dev,
++		enum adf_interface_type type, u32 idx, u32 flags,
++		const struct adf_interface_ops *ops, const char *fmt, ...)
++{
++	int ret;
++	va_list args;
++	const u32 allowed_flags = ADF_INTF_FLAG_PRIMARY |
++			ADF_INTF_FLAG_EXTERNAL;
++
++	if (dev->n_interfaces == ADF_MAX_INTERFACES) {
++		pr_err("%s: parent device %s has too many interfaces\n",
++				__func__, dev->base.name);
++		return -ENOMEM;
++	}
++
++	if (type >= ADF_INTF_MEMORY && type <= ADF_INTF_TYPE_DEVICE_CUSTOM) {
++		pr_err("%s: invalid interface type %u\n", __func__, type);
++		return -EINVAL;
++	}
++
++	if (flags & ~allowed_flags) {
++		pr_err("%s: invalid interface flags 0x%X\n", __func__,
++				flags & ~allowed_flags);
++		return -EINVAL;
++	}
++
++	memset(intf, 0, sizeof(*intf));
++
++	va_start(args, fmt);
++	ret = adf_obj_init(&intf->base, ADF_OBJ_INTERFACE, &dev->interfaces,
++			dev, ops ? &ops->base : NULL, fmt, args);
++	va_end(args);
++	if (ret < 0)
++		return ret;
++
++	intf->type = type;
++	intf->idx = idx;
++	intf->flags = flags;
++	intf->ops = ops;
++	intf->dpms_state = DRM_MODE_DPMS_OFF;
++	init_waitqueue_head(&intf->vsync_wait);
++	rwlock_init(&intf->vsync_lock);
++	rwlock_init(&intf->hotplug_modelist_lock);
++
++	ret = adf_interface_sysfs_init(intf);
++	if (ret < 0)
++		goto err;
++	dev->n_interfaces++;
++
++	return 0;
++
++err:
++	adf_obj_destroy(&intf->base, &dev->interfaces);
++	return ret;
++}
++EXPORT_SYMBOL(adf_interface_init);
++
++/**
++ * adf_interface_destroy - clean up ADF-internal data for a display interface
++ *
++ * @intf: the display interface
++ */
++void adf_interface_destroy(struct adf_interface *intf)
++{
++	struct adf_device *dev = adf_interface_parent(intf);
++	struct adf_attachment_list *entry, *next;
++
++	mutex_lock(&dev->client_lock);
++	list_for_each_entry_safe(entry, next, &dev->attach_allowed, head) {
++		if (entry->attachment.interface == intf) {
++			adf_attachment_free(entry);
++			dev->n_attach_allowed--;
++		}
++	}
++	list_for_each_entry_safe(entry, next, &dev->attached, head) {
++		if (entry->attachment.interface == intf) {
++			adf_device_detach_op(dev,
++					entry->attachment.overlay_engine, intf);
++			adf_attachment_free(entry);
++			dev->n_attached--;
++		}
++	}
++	kfree(intf->modelist);
++	adf_interface_sysfs_destroy(intf);
++	adf_obj_destroy(&intf->base, &dev->interfaces);
++	dev->n_interfaces--;
++	mutex_unlock(&dev->client_lock);
++}
++EXPORT_SYMBOL(adf_interface_destroy);
++
++static bool adf_overlay_engine_has_custom_formats(
++		const struct adf_overlay_engine_ops *ops)
++{
++	size_t i;
++	for (i = 0; i < ops->n_supported_formats; i++)
++		if (!adf_format_is_standard(ops->supported_formats[i]))
++			return true;
++	return false;
++}
++
++/**
++ * adf_overlay_engine_init - initialize ADF-internal data for an
++ * overlay engine and create sysfs entries
++ *
++ * @eng: the overlay engine
++ * @dev: the overlay engine's "parent" display device
++ * @ops: the overlay engine's associated ops
++ * @fmt: formatting string for the overlay engine's name
++ *
++ * @dev must have previously been initialized with adf_device_init().
++ *
++ * @fmt affects the name returned to userspace through the
++ * %ADF_GET_OVERLAY_ENGINE_DATA ioctl.  It does not affect the sysfs filename,
++ * which is derived from @dev's name.
++ *
++ * Returns 0 on success or error code (<0) on failure.
++ */
++int adf_overlay_engine_init(struct adf_overlay_engine *eng,
++		struct adf_device *dev,
++		const struct adf_overlay_engine_ops *ops, const char *fmt, ...)
++{
++	int ret;
++	va_list args;
++
++	if (!ops->supported_formats) {
++		pr_err("%s: overlay engine must support at least one format\n",
++				__func__);
++		return -EINVAL;
++	}
++
++	if (ops->n_supported_formats > ADF_MAX_SUPPORTED_FORMATS) {
++		pr_err("%s: overlay engine supports too many formats\n",
++				__func__);
++		return -EINVAL;
++	}
++
++	if (adf_overlay_engine_has_custom_formats(ops) &&
++			!dev->ops->validate_custom_format) {
++		pr_err("%s: overlay engine has custom formats but parent device %s does not implement validate_custom_format\n",
++				__func__, dev->base.name);
++		return -EINVAL;
++	}
++
++	memset(eng, 0, sizeof(*eng));
++
++	va_start(args, fmt);
++	ret = adf_obj_init(&eng->base, ADF_OBJ_OVERLAY_ENGINE,
++			&dev->overlay_engines, dev, &ops->base, fmt, args);
++	va_end(args);
++	if (ret < 0)
++		return ret;
++
++	eng->ops = ops;
++
++	ret = adf_overlay_engine_sysfs_init(eng);
++	if (ret < 0)
++		goto err;
++
++	return 0;
++
++err:
++	adf_obj_destroy(&eng->base, &dev->overlay_engines);
++	return ret;
++}
++EXPORT_SYMBOL(adf_overlay_engine_init);
++
++/**
++ * adf_interface_destroy - clean up ADF-internal data for an overlay engine
++ *
++ * @eng: the overlay engine
++ */
++void adf_overlay_engine_destroy(struct adf_overlay_engine *eng)
++{
++	struct adf_device *dev = adf_overlay_engine_parent(eng);
++	struct adf_attachment_list *entry, *next;
++
++	mutex_lock(&dev->client_lock);
++	list_for_each_entry_safe(entry, next, &dev->attach_allowed, head) {
++		if (entry->attachment.overlay_engine == eng) {
++			adf_attachment_free(entry);
++			dev->n_attach_allowed--;
++		}
++	}
++	list_for_each_entry_safe(entry, next, &dev->attached, head) {
++		if (entry->attachment.overlay_engine == eng) {
++			adf_device_detach_op(dev, eng,
++					entry->attachment.interface);
++			adf_attachment_free(entry);
++			dev->n_attached--;
++		}
++	}
++	adf_overlay_engine_sysfs_destroy(eng);
++	adf_obj_destroy(&eng->base, &dev->overlay_engines);
++	mutex_unlock(&dev->client_lock);
++}
++EXPORT_SYMBOL(adf_overlay_engine_destroy);
++
++struct adf_attachment_list *adf_attachment_find(struct list_head *list,
++		struct adf_overlay_engine *eng, struct adf_interface *intf)
++{
++	struct adf_attachment_list *entry;
++	list_for_each_entry(entry, list, head) {
++		if (entry->attachment.interface == intf &&
++				entry->attachment.overlay_engine == eng)
++			return entry;
++	}
++	return NULL;
++}
++
++int adf_attachment_validate(struct adf_device *dev,
++		struct adf_overlay_engine *eng, struct adf_interface *intf)
++{
++	struct adf_device *intf_dev = adf_interface_parent(intf);
++	struct adf_device *eng_dev = adf_overlay_engine_parent(eng);
++
++	if (intf_dev != dev) {
++		dev_err(&dev->base.dev, "can't attach interface %s belonging to device %s\n",
++				intf->base.name, intf_dev->base.name);
++		return -EINVAL;
++	}
++
++	if (eng_dev != dev) {
++		dev_err(&dev->base.dev, "can't attach overlay engine %s belonging to device %s\n",
++				eng->base.name, eng_dev->base.name);
++		return -EINVAL;
++	}
++
++	return 0;
++}
++
++/**
++ * adf_attachment_allow - add a new entry to the list of allowed
++ * attachments
++ *
++ * @dev: the parent device
++ * @eng: the overlay engine
++ * @intf: the interface
++ *
++ * adf_attachment_allow() indicates that the underlying display hardware allows
++ * @intf to scan out @eng's output.  It is intended to be called at
++ * driver initialization for each supported overlay engine + interface pair.
++ *
++ * Returns 0 on success, -%EALREADY if the entry already exists, or -errno on
++ * any other failure.
++ */
++int adf_attachment_allow(struct adf_device *dev,
++		struct adf_overlay_engine *eng, struct adf_interface *intf)
++{
++	int ret;
++	struct adf_attachment_list *entry = NULL;
++
++	ret = adf_attachment_validate(dev, eng, intf);
++	if (ret < 0)
++		return ret;
++
++	mutex_lock(&dev->client_lock);
++
++	if (dev->n_attach_allowed == ADF_MAX_ATTACHMENTS) {
++		ret = -ENOMEM;
++		goto done;
++	}
++
++	if (adf_attachment_find(&dev->attach_allowed, eng, intf)) {
++		ret = -EALREADY;
++		goto done;
++	}
++
++	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
++	if (!entry) {
++		ret = -ENOMEM;
++		goto done;
++	}
++
++	entry->attachment.interface = intf;
++	entry->attachment.overlay_engine = eng;
++	list_add_tail(&entry->head, &dev->attach_allowed);
++	dev->n_attach_allowed++;
++
++done:
++	mutex_unlock(&dev->client_lock);
++	if (ret < 0)
++		kfree(entry);
++
++	return ret;
++}
++EXPORT_SYMBOL(adf_attachment_allow);
++
++/**
++ * adf_obj_type_str - string representation of an adf_obj_type
++ *
++ * @type: the object type
++ */
++const char *adf_obj_type_str(enum adf_obj_type type)
++{
++	switch (type) {
++	case ADF_OBJ_OVERLAY_ENGINE:
++		return "overlay engine";
++
++	case ADF_OBJ_INTERFACE:
++		return "interface";
++
++	case ADF_OBJ_DEVICE:
++		return "device";
++
++	default:
++		return "unknown";
++	}
++}
++EXPORT_SYMBOL(adf_obj_type_str);
++
++/**
++ * adf_interface_type_str - string representation of an adf_interface's type
++ *
++ * @intf: the interface
++ */
++const char *adf_interface_type_str(struct adf_interface *intf)
++{
++	switch (intf->type) {
++	case ADF_INTF_DSI:
++		return "DSI";
++
++	case ADF_INTF_eDP:
++		return "eDP";
++
++	case ADF_INTF_DPI:
++		return "DPI";
++
++	case ADF_INTF_VGA:
++		return "VGA";
++
++	case ADF_INTF_DVI:
++		return "DVI";
++
++	case ADF_INTF_HDMI:
++		return "HDMI";
++
++	case ADF_INTF_MEMORY:
++		return "memory";
++
++	default:
++		if (intf->type >= ADF_INTF_TYPE_DEVICE_CUSTOM) {
++			if (intf->ops && intf->ops->type_str)
++				return intf->ops->type_str(intf);
++			return "custom";
++		}
++		return "unknown";
++	}
++}
++EXPORT_SYMBOL(adf_interface_type_str);
++
++/**
++ * adf_event_type_str - string representation of an adf_event_type
++ *
++ * @obj: ADF object that produced the event
++ * @type: event type
++ */
++const char *adf_event_type_str(struct adf_obj *obj, enum adf_event_type type)
++{
++	switch (type) {
++	case ADF_EVENT_VSYNC:
++		return "vsync";
++
++	case ADF_EVENT_HOTPLUG:
++		return "hotplug";
++
++	default:
++		if (type >= ADF_EVENT_DEVICE_CUSTOM) {
++			if (obj->ops && obj->ops->event_type_str)
++				return obj->ops->event_type_str(obj, type);
++			return "custom";
++		}
++		return "unknown";
++	}
++}
++EXPORT_SYMBOL(adf_event_type_str);
++
++/**
++ * adf_format_str - string representation of an ADF/DRM fourcc format
++ *
++ * @format: format fourcc
++ * @buf: target buffer for the format's string representation
++ */
++void adf_format_str(u32 format, char buf[ADF_FORMAT_STR_SIZE])
++{
++	buf[0] = format & 0xFF;
++	buf[1] = (format >> 8) & 0xFF;
++	buf[2] = (format >> 16) & 0xFF;
++	buf[3] = (format >> 24) & 0xFF;
++	buf[4] = '\0';
++}
++EXPORT_SYMBOL(adf_format_str);
++
++/**
++ * adf_format_validate_yuv - validate the number and size of planes in buffers
++ * with a custom YUV format.
++ *
++ * @dev: ADF device performing the validation
++ * @buf: buffer to validate
++ * @num_planes: expected number of planes
++ * @hsub: expected horizontal chroma subsampling factor, in pixels
++ * @vsub: expected vertical chroma subsampling factor, in pixels
++ * @cpp: expected bytes per pixel for each plane (length @num_planes)
++ *
++ * adf_format_validate_yuv() is intended to be called as a helper from @dev's
++ * validate_custom_format() op.
++ *
++ * Returns 0 if @buf has the expected number of planes and each plane
++ * has sufficient size, or -EINVAL otherwise.
++ */
++int adf_format_validate_yuv(struct adf_device *dev, struct adf_buffer *buf,
++		u8 num_planes, u8 hsub, u8 vsub, u8 cpp[])
++{
++	u8 i;
++
++	if (num_planes != buf->n_planes) {
++		char format_str[ADF_FORMAT_STR_SIZE];
++		adf_format_str(buf->format, format_str);
++		dev_err(&dev->base.dev, "%u planes expected for format %s but %u planes provided\n",
++				num_planes, format_str, buf->n_planes);
++		return -EINVAL;
++	}
++
++	if (buf->w == 0 || buf->w % hsub) {
++		dev_err(&dev->base.dev, "bad buffer width %u\n", buf->w);
++		return -EINVAL;
++	}
++
++	if (buf->h == 0 || buf->h % vsub) {
++		dev_err(&dev->base.dev, "bad buffer height %u\n", buf->h);
++		return -EINVAL;
++	}
++
++	for (i = 0; i < num_planes; i++) {
++		u32 width = buf->w / (i != 0 ? hsub : 1);
++		u32 height = buf->h / (i != 0 ? vsub : 1);
++		u8 cpp = adf_format_plane_cpp(buf->format, i);
++		u32 last_line_size;
++
++		if (buf->pitch[i] < (u64) width * cpp) {
++			dev_err(&dev->base.dev, "plane %u pitch is shorter than buffer width (pitch = %u, width = %u, bpp = %u)\n",
++					i, buf->pitch[i], width, cpp * 8);
++			return -EINVAL;
++		}
++
++		switch (dev->ops->quirks.buffer_padding) {
++		case ADF_BUFFER_PADDED_TO_PITCH:
++			last_line_size = buf->pitch[i];
++			break;
++
++		case ADF_BUFFER_UNPADDED:
++			last_line_size = width * cpp;
++			break;
++
++		default:
++			BUG();
++		}
++
++		if ((u64) (height - 1) * buf->pitch[i] + last_line_size +
++				buf->offset[i] > buf->dma_bufs[i]->size) {
++			dev_err(&dev->base.dev, "plane %u buffer too small (height = %u, pitch = %u, offset = %u, size = %zu)\n",
++					i, height, buf->pitch[i],
++					buf->offset[i], buf->dma_bufs[i]->size);
++			return -EINVAL;
++		}
++	}
++
++	return 0;
++}
++EXPORT_SYMBOL(adf_format_validate_yuv);
++
++/**
++ * adf_modeinfo_set_name - sets the name of a mode from its display resolution
++ *
++ * @mode: mode
++ *
++ * adf_modeinfo_set_name() fills in @mode->name in the format
++ * "[hdisplay]x[vdisplay](i)".  It is intended to help drivers create
++ * ADF/DRM-style modelists from other mode formats.
++ */
++void adf_modeinfo_set_name(struct drm_mode_modeinfo *mode)
++{
++	bool interlaced = mode->flags & DRM_MODE_FLAG_INTERLACE;
++
++	snprintf(mode->name, DRM_DISPLAY_MODE_LEN, "%dx%d%s",
++		 mode->hdisplay, mode->vdisplay,
++		 interlaced ? "i" : "");
++}
++EXPORT_SYMBOL(adf_modeinfo_set_name);
++
++/**
++ * adf_modeinfo_set_vrefresh - sets the vrefresh of a mode from its other
++ * timing data
++ *
++ * @mode: mode
++ *
++ * adf_modeinfo_set_vrefresh() calculates @mode->vrefresh from
++ * @mode->{h,v}display and @mode->flags.  It is intended to help drivers
++ * create ADF/DRM-style modelists from other mode formats.
++ */
++void adf_modeinfo_set_vrefresh(struct drm_mode_modeinfo *mode)
++{
++	int refresh = 0;
++	unsigned int calc_val;
++
++	if (mode->vrefresh > 0)
++		return;
++
++	if (mode->htotal <= 0 || mode->vtotal <= 0)
++		return;
++
++	/* work out vrefresh the value will be x1000 */
++	calc_val = (mode->clock * 1000);
++	calc_val /= mode->htotal;
++	refresh = (calc_val + mode->vtotal / 2) / mode->vtotal;
++
++	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
++		refresh *= 2;
++	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
++		refresh /= 2;
++	if (mode->vscan > 1)
++		refresh /= mode->vscan;
++
++	mode->vrefresh = refresh;
++}
++EXPORT_SYMBOL(adf_modeinfo_set_vrefresh);
++
++static int __init adf_init(void)
++{
++	int err;
++
++	err = adf_sysfs_init();
++	if (err < 0)
++		return err;
++
++	return 0;
++}
++
++static void __exit adf_exit(void)
++{
++	adf_sysfs_destroy();
++}
++
++module_init(adf_init);
++module_exit(adf_exit);
+diff --git a/drivers/video/adf/adf.h b/drivers/video/adf/adf.h
+new file mode 100644
+index 0000000..3bcf1fa
+--- /dev/null
++++ b/drivers/video/adf/adf.h
+@@ -0,0 +1,71 @@
++/*
++ * Copyright (C) 2013 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#ifndef __VIDEO_ADF_ADF_H
++#define __VIDEO_ADF_ADF_H
++
++#include <linux/idr.h>
++#include <linux/list.h>
++#include <video/adf.h>
++#include "sync.h"
++
++struct adf_event_refcount {
++	struct rb_node node;
++	enum adf_event_type type;
++	int refcount;
++};
++
++void adf_buffer_cleanup(struct adf_buffer *buf);
++void adf_buffer_mapping_cleanup(struct adf_buffer_mapping *mapping,
++		struct adf_buffer *buf);
++void adf_post_cleanup(struct adf_device *dev, struct adf_pending_post *post);
++
++struct adf_attachment_list *adf_attachment_find(struct list_head *list,
++		struct adf_overlay_engine *eng, struct adf_interface *intf);
++int adf_attachment_validate(struct adf_device *dev,
++		struct adf_overlay_engine *eng, struct adf_interface *intf);
++void adf_attachment_free(struct adf_attachment_list *attachment);
++
++struct adf_event_refcount *adf_obj_find_event_refcount(struct adf_obj *obj,
++		enum adf_event_type type);
++
++static inline int adf_obj_check_supports_event(struct adf_obj *obj,
++		enum adf_event_type type)
++{
++	if (!obj->ops || !obj->ops->supports_event)
++		return -EOPNOTSUPP;
++	if (!obj->ops->supports_event(obj, type))
++		return -EINVAL;
++	return 0;
++}
++
++static inline int adf_device_attach_op(struct adf_device *dev,
++		struct adf_overlay_engine *eng, struct adf_interface *intf)
++{
++	if (!dev->ops->attach)
++		return 0;
++
++	return dev->ops->attach(dev, eng, intf);
++}
++
++static inline int adf_device_detach_op(struct adf_device *dev,
++		struct adf_overlay_engine *eng, struct adf_interface *intf)
++{
++	if (!dev->ops->detach)
++		return 0;
++
++	return dev->ops->detach(dev, eng, intf);
++}
++
++#endif /* __VIDEO_ADF_ADF_H */
+diff --git a/drivers/video/adf/adf_client.c b/drivers/video/adf/adf_client.c
+new file mode 100644
+index 0000000..8061d8e
+--- /dev/null
++++ b/drivers/video/adf/adf_client.c
+@@ -0,0 +1,811 @@
++/*
++ * Copyright (C) 2013 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#include <linux/kthread.h>
++#include <linux/mutex.h>
++#include <linux/slab.h>
++
++#include "sw_sync.h"
++
++#include <video/adf.h>
++#include <video/adf_client.h>
++#include <video/adf_format.h>
++
++#include "adf.h"
++
++static inline bool vsync_active(u8 state)
++{
++	return state == DRM_MODE_DPMS_ON || state == DRM_MODE_DPMS_STANDBY;
++}
++
++/**
++ * adf_interface_blank - set interface's DPMS state
++ *
++ * @intf: the interface
++ * @state: one of %DRM_MODE_DPMS_*
++ *
++ * Returns 0 on success or -errno on failure.
++ */
++int adf_interface_blank(struct adf_interface *intf, u8 state)
++{
++	struct adf_device *dev = adf_interface_parent(intf);
++	u8 prev_state;
++	bool disable_vsync;
++	bool enable_vsync;
++	int ret = 0;
++	struct adf_event_refcount *vsync_refcount;
++
++	if (!intf->ops || !intf->ops->blank)
++		return -EOPNOTSUPP;
++
++	if (state > DRM_MODE_DPMS_OFF)
++		return -EINVAL;
++
++	mutex_lock(&dev->client_lock);
++	if (state != DRM_MODE_DPMS_ON)
++		flush_kthread_worker(&dev->post_worker);
++	mutex_lock(&intf->base.event_lock);
++
++	vsync_refcount = adf_obj_find_event_refcount(&intf->base,
++			ADF_EVENT_VSYNC);
++	if (!vsync_refcount) {
++		ret = -ENOMEM;
++		goto done;
++	}
++
++	prev_state = intf->dpms_state;
++	if (prev_state == state) {
++		ret = -EBUSY;
++		goto done;
++	}
++
++	disable_vsync = vsync_active(prev_state) &&
++			!vsync_active(state) &&
++			vsync_refcount->refcount;
++	enable_vsync = !vsync_active(prev_state) &&
++			vsync_active(state) &&
++			vsync_refcount->refcount;
++
++	if (disable_vsync)
++		intf->base.ops->set_event(&intf->base, ADF_EVENT_VSYNC,
++				false);
++
++	ret = intf->ops->blank(intf, state);
++	if (ret < 0) {
++		if (disable_vsync)
++			intf->base.ops->set_event(&intf->base, ADF_EVENT_VSYNC,
++					true);
++		goto done;
++	}
++
++	if (enable_vsync)
++		intf->base.ops->set_event(&intf->base, ADF_EVENT_VSYNC,
++				true);
++
++	intf->dpms_state = state;
++done:
++	mutex_unlock(&intf->base.event_lock);
++	mutex_unlock(&dev->client_lock);
++	return ret;
++}
++EXPORT_SYMBOL(adf_interface_blank);
++
++/**
++ * adf_interface_blank - get interface's current DPMS state
++ *
++ * @intf: the interface
++ *
++ * Returns one of %DRM_MODE_DPMS_*.
++ */
++u8 adf_interface_dpms_state(struct adf_interface *intf)
++{
++	struct adf_device *dev = adf_interface_parent(intf);
++	u8 dpms_state;
++
++	mutex_lock(&dev->client_lock);
++	dpms_state = intf->dpms_state;
++	mutex_unlock(&dev->client_lock);
++
++	return dpms_state;
++}
++EXPORT_SYMBOL(adf_interface_dpms_state);
++
++/**
++ * adf_interface_current_mode - get interface's current display mode
++ *
++ * @intf: the interface
++ * @mode: returns the current mode
++ */
++void adf_interface_current_mode(struct adf_interface *intf,
++		struct drm_mode_modeinfo *mode)
++{
++	struct adf_device *dev = adf_interface_parent(intf);
++
++	mutex_lock(&dev->client_lock);
++	memcpy(mode, &intf->current_mode, sizeof(*mode));
++	mutex_unlock(&dev->client_lock);
++}
++EXPORT_SYMBOL(adf_interface_current_mode);
++
++/**
++ * adf_interface_modelist - get interface's modelist
++ *
++ * @intf: the interface
++ * @modelist: storage for the modelist (optional)
++ * @n_modes: length of @modelist
++ *
++ * If @modelist is not NULL, adf_interface_modelist() will copy up to @n_modes
++ * modelist entries into @modelist.
++ *
++ * Returns the length of the modelist.
++ */
++size_t adf_interface_modelist(struct adf_interface *intf,
++		struct drm_mode_modeinfo *modelist, size_t n_modes)
++{
++	unsigned long flags;
++	size_t retval;
++
++	read_lock_irqsave(&intf->hotplug_modelist_lock, flags);
++	if (modelist)
++		memcpy(modelist, intf->modelist, sizeof(modelist[0]) *
++				min(n_modes, intf->n_modes));
++	retval = intf->n_modes;
++	read_unlock_irqrestore(&intf->hotplug_modelist_lock, flags);
++
++	return retval;
++}
++EXPORT_SYMBOL(adf_interface_modelist);
++
++/**
++ * adf_interface_set_mode - set interface's display mode
++ *
++ * @intf: the interface
++ * @mode: the new mode
++ *
++ * Returns 0 on success or -errno on failure.
++ */
++int adf_interface_set_mode(struct adf_interface *intf,
++		struct drm_mode_modeinfo *mode)
++{
++	struct adf_device *dev = adf_interface_parent(intf);
++	int ret = 0;
++
++	if (!intf->ops || !intf->ops->modeset)
++		return -EOPNOTSUPP;
++
++	mutex_lock(&dev->client_lock);
++	flush_kthread_worker(&dev->post_worker);
++
++	ret = intf->ops->modeset(intf, mode);
++	if (ret < 0)
++		goto done;
++
++	memcpy(&intf->current_mode, mode, sizeof(*mode));
++done:
++	mutex_unlock(&dev->client_lock);
++	return ret;
++}
++EXPORT_SYMBOL(adf_interface_set_mode);
++
++/**
++ * adf_interface_screen_size - get size of screen connected to interface
++ *
++ * @intf: the interface
++ * @width_mm: returns the screen width in mm
++ * @height_mm: returns the screen width in mm
++ *
++ * Returns 0 on success or -errno on failure.
++ */
++int adf_interface_get_screen_size(struct adf_interface *intf, u16 *width_mm,
++		u16 *height_mm)
++{
++	struct adf_device *dev = adf_interface_parent(intf);
++	int ret;
++
++	if (!intf->ops || !intf->ops->screen_size)
++		return -EOPNOTSUPP;
++
++	mutex_lock(&dev->client_lock);
++	ret = intf->ops->screen_size(intf, width_mm, height_mm);
++	mutex_unlock(&dev->client_lock);
++
++	return ret;
++}
++EXPORT_SYMBOL(adf_interface_get_screen_size);
++
++/**
++ * adf_overlay_engine_supports_format - returns whether a format is in an
++ * overlay engine's supported list
++ *
++ * @eng: the overlay engine
++ * @format: format fourcc
++ */
++bool adf_overlay_engine_supports_format(struct adf_overlay_engine *eng,
++		u32 format)
++{
++	size_t i;
++	for (i = 0; i < eng->ops->n_supported_formats; i++)
++		if (format == eng->ops->supported_formats[i])
++			return true;
++
++	return false;
++}
++EXPORT_SYMBOL(adf_overlay_engine_supports_format);
++
++static int adf_buffer_validate(struct adf_buffer *buf)
++{
++	struct adf_overlay_engine *eng = buf->overlay_engine;
++	struct device *dev = &eng->base.dev;
++	struct adf_device *parent = adf_overlay_engine_parent(eng);
++	u8 hsub, vsub, num_planes, cpp[ADF_MAX_PLANES], i;
++
++	if (!adf_overlay_engine_supports_format(eng, buf->format)) {
++		char format_str[ADF_FORMAT_STR_SIZE];
++		adf_format_str(buf->format, format_str);
++		dev_err(dev, "unsupported format %s\n", format_str);
++		return -EINVAL;
++	}
++
++	if (!adf_format_is_standard(buf->format))
++		return parent->ops->validate_custom_format(parent, buf);
++
++	hsub = adf_format_horz_chroma_subsampling(buf->format);
++	vsub = adf_format_vert_chroma_subsampling(buf->format);
++	num_planes = adf_format_num_planes(buf->format);
++	for (i = 0; i < num_planes; i++)
++		cpp[i] = adf_format_plane_cpp(buf->format, i);
++
++	return adf_format_validate_yuv(parent, buf, num_planes, hsub, vsub,
++			cpp);
++}
++
++static int adf_buffer_map(struct adf_device *dev, struct adf_buffer *buf,
++		struct adf_buffer_mapping *mapping)
++{
++	int ret = 0;
++	size_t i;
++
++	for (i = 0; i < buf->n_planes; i++) {
++		struct dma_buf_attachment *attachment;
++		struct sg_table *sg_table;
++
++		attachment = dma_buf_attach(buf->dma_bufs[i], dev->dev);
++		if (IS_ERR(attachment)) {
++			ret = PTR_ERR(attachment);
++			dev_err(&dev->base.dev, "attaching plane %zu failed: %d\n",
++					i, ret);
++			goto done;
++		}
++		mapping->attachments[i] = attachment;
++
++		sg_table = dma_buf_map_attachment(attachment, DMA_TO_DEVICE);
++		if (IS_ERR(sg_table)) {
++			ret = PTR_ERR(sg_table);
++			dev_err(&dev->base.dev, "mapping plane %zu failed: %d",
++					i, ret);
++			goto done;
++		} else if (!sg_table) {
++			ret = -ENOMEM;
++			dev_err(&dev->base.dev, "mapping plane %zu failed\n",
++					i);
++			goto done;
++		}
++		mapping->sg_tables[i] = sg_table;
++	}
++
++done:
++	if (ret < 0)
++		adf_buffer_mapping_cleanup(mapping, buf);
++
++	return ret;
++}
++
++static struct sync_fence *adf_sw_complete_fence(struct adf_device *dev)
++{
++	struct sync_pt *pt;
++	struct sync_fence *complete_fence;
++
++	if (!dev->timeline) {
++		dev->timeline = sw_sync_timeline_create(dev->base.name);
++		if (!dev->timeline)
++			return ERR_PTR(-ENOMEM);
++		dev->timeline_max = 1;
++	}
++
++	dev->timeline_max++;
++	pt = sw_sync_pt_create(dev->timeline, dev->timeline_max);
++	if (!pt)
++		goto err_pt_create;
++	complete_fence = sync_fence_create(dev->base.name, pt);
++	if (!complete_fence)
++		goto err_fence_create;
++
++	return complete_fence;
++
++err_fence_create:
++	sync_pt_free(pt);
++err_pt_create:
++	dev->timeline_max--;
++	return ERR_PTR(-ENOSYS);
++}
++
++/**
++ * adf_device_post - flip to a new set of buffers
++ *
++ * @dev: device targeted by the flip
++ * @intfs: interfaces targeted by the flip
++ * @n_intfs: number of targeted interfaces
++ * @bufs: description of buffers displayed
++ * @n_bufs: number of buffers displayed
++ * @custom_data: driver-private data
++ * @custom_data_size: size of driver-private data
++ *
++ * adf_device_post() will copy @intfs, @bufs, and @custom_data, so they may
++ * point to variables on the stack.  adf_device_post() also takes its own
++ * reference on each of the dma-bufs in @bufs.  The adf_device_post_nocopy()
++ * variant transfers ownership of these resources to ADF instead.
++ *
++ * On success, returns a sync fence which signals when the buffers are removed
++ * from the screen.  On failure, returns ERR_PTR(-errno).
++ */
++struct sync_fence *adf_device_post(struct adf_device *dev,
++		struct adf_interface **intfs, size_t n_intfs,
++		struct adf_buffer *bufs, size_t n_bufs, void *custom_data,
++		size_t custom_data_size)
++{
++	struct adf_interface **intfs_copy = NULL;
++	struct adf_buffer *bufs_copy = NULL;
++	void *custom_data_copy = NULL;
++	struct sync_fence *ret;
++	size_t i;
++
++	intfs_copy = kzalloc(sizeof(intfs_copy[0]) * n_intfs, GFP_KERNEL);
++	if (!intfs_copy)
++		return ERR_PTR(-ENOMEM);
++
++	bufs_copy = kzalloc(sizeof(bufs_copy[0]) * n_bufs, GFP_KERNEL);
++	if (!bufs_copy) {
++		ret = ERR_PTR(-ENOMEM);
++		goto err_alloc;
++	}
++
++	custom_data_copy = kzalloc(custom_data_size, GFP_KERNEL);
++	if (!custom_data_copy) {
++		ret = ERR_PTR(-ENOMEM);
++		goto err_alloc;
++	}
++
++	for (i = 0; i < n_bufs; i++) {
++		size_t j;
++		for (j = 0; j < bufs[i].n_planes; j++)
++			get_dma_buf(bufs[i].dma_bufs[j]);
++	}
++
++	memcpy(intfs_copy, intfs, sizeof(intfs_copy[0]) * n_intfs);
++	memcpy(bufs_copy, bufs, sizeof(bufs_copy[0]) * n_bufs);
++	memcpy(custom_data_copy, custom_data, custom_data_size);
++
++	ret = adf_device_post_nocopy(dev, intfs_copy, n_intfs, bufs_copy,
++			n_bufs, custom_data_copy, custom_data_size);
++	if (IS_ERR(ret))
++		goto err_post;
++
++	return ret;
++
++err_post:
++	for (i = 0; i < n_bufs; i++) {
++		size_t j;
++		for (j = 0; j < bufs[i].n_planes; j++)
++			dma_buf_put(bufs[i].dma_bufs[j]);
++	}
++err_alloc:
++	kfree(custom_data_copy);
++	kfree(bufs_copy);
++	kfree(intfs_copy);
++	return ret;
++}
++EXPORT_SYMBOL(adf_device_post);
++
++/**
++ * adf_device_post_nocopy - flip to a new set of buffers
++ *
++ * adf_device_post_nocopy() has the same behavior as adf_device_post(),
++ * except ADF does not copy @intfs, @bufs, or @custom_data, and it does
++ * not take an extra reference on the dma-bufs in @bufs.
++ *
++ * @intfs, @bufs, and @custom_data must point to buffers allocated by
++ * kmalloc().  On success, ADF takes ownership of these buffers and the dma-bufs
++ * in @bufs, and will kfree()/dma_buf_put() them when they are no longer needed.
++ * On failure, adf_device_post_nocopy() does NOT take ownership of these
++ * buffers or the dma-bufs, and the caller must clean them up.
++ *
++ * adf_device_post_nocopy() is mainly intended for implementing ADF's ioctls.
++ * Clients may find the nocopy variant useful in limited cases, but most should
++ * call adf_device_post() instead.
++ */
++struct sync_fence *adf_device_post_nocopy(struct adf_device *dev,
++		struct adf_interface **intfs, size_t n_intfs,
++		struct adf_buffer *bufs, size_t n_bufs,
++		void *custom_data, size_t custom_data_size)
++{
++	struct adf_pending_post *cfg;
++	struct adf_buffer_mapping *mappings;
++	struct sync_fence *ret;
++	size_t i;
++	int err;
++
++	cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
++	if (!cfg)
++		return ERR_PTR(-ENOMEM);
++
++	mappings = kzalloc(sizeof(mappings[0]) * n_bufs, GFP_KERNEL);
++	if (!mappings) {
++		ret = ERR_PTR(-ENOMEM);
++		goto err_alloc;
++	}
++
++	mutex_lock(&dev->client_lock);
++
++	for (i = 0; i < n_bufs; i++) {
++		err = adf_buffer_validate(&bufs[i]);
++		if (err < 0) {
++			ret = ERR_PTR(err);
++			goto err_buf;
++		}
++
++		err = adf_buffer_map(dev, &bufs[i], &mappings[i]);
++		if (err < 0) {
++			ret = ERR_PTR(err);
++			goto err_buf;
++		}
++	}
++
++	INIT_LIST_HEAD(&cfg->head);
++	cfg->config.n_bufs = n_bufs;
++	cfg->config.bufs = bufs;
++	cfg->config.mappings = mappings;
++	cfg->config.custom_data = custom_data;
++	cfg->config.custom_data_size = custom_data_size;
++
++	err = dev->ops->validate(dev, &cfg->config, &cfg->state);
++	if (err < 0) {
++		ret = ERR_PTR(err);
++		goto err_buf;
++	}
++
++	mutex_lock(&dev->post_lock);
++
++	if (dev->ops->complete_fence)
++		ret = dev->ops->complete_fence(dev, &cfg->config,
++				cfg->state);
++	else
++		ret = adf_sw_complete_fence(dev);
++
++	if (IS_ERR(ret))
++		goto err_fence;
++
++	list_add_tail(&cfg->head, &dev->post_list);
++	queue_kthread_work(&dev->post_worker, &dev->post_work);
++	mutex_unlock(&dev->post_lock);
++	mutex_unlock(&dev->client_lock);
++	kfree(intfs);
++	return ret;
++
++err_fence:
++	mutex_unlock(&dev->post_lock);
++
++err_buf:
++	for (i = 0; i < n_bufs; i++)
++		adf_buffer_mapping_cleanup(&mappings[i], &bufs[i]);
++
++	mutex_unlock(&dev->client_lock);
++	kfree(mappings);
++
++err_alloc:
++	kfree(cfg);
++	return ret;
++}
++EXPORT_SYMBOL(adf_device_post_nocopy);
++
++static void adf_attachment_list_to_array(struct adf_device *dev,
++		struct list_head *src, struct adf_attachment *dst, size_t size)
++{
++	struct adf_attachment_list *entry;
++	size_t i = 0;
++
++	if (!dst)
++		return;
++
++	list_for_each_entry(entry, src, head) {
++		if (i == size)
++			return;
++		dst[i] = entry->attachment;
++		i++;
++	}
++}
++
++/**
++ * adf_device_attachments - get device's list of active attachments
++ *
++ * @dev: the device
++ * @attachments: storage for the attachment list (optional)
++ * @n_attachments: length of @attachments
++ *
++ * If @attachments is not NULL, adf_device_attachments() will copy up to
++ * @n_attachments entries into @attachments.
++ *
++ * Returns the length of the active attachment list.
++ */
++size_t adf_device_attachments(struct adf_device *dev,
++		struct adf_attachment *attachments, size_t n_attachments)
++{
++	size_t retval;
++
++	mutex_lock(&dev->client_lock);
++	adf_attachment_list_to_array(dev, &dev->attached, attachments,
++			n_attachments);
++	retval = dev->n_attached;
++	mutex_unlock(&dev->client_lock);
++
++	return retval;
++}
++EXPORT_SYMBOL(adf_device_attachments);
++
++/**
++ * adf_device_attachments_allowed - get device's list of allowed attachments
++ *
++ * @dev: the device
++ * @attachments: storage for the attachment list (optional)
++ * @n_attachments: length of @attachments
++ *
++ * If @attachments is not NULL, adf_device_attachments_allowed() will copy up to
++ * @n_attachments entries into @attachments.
++ *
++ * Returns the length of the allowed attachment list.
++ */
++size_t adf_device_attachments_allowed(struct adf_device *dev,
++		struct adf_attachment *attachments, size_t n_attachments)
++{
++	size_t retval;
++
++	mutex_lock(&dev->client_lock);
++	adf_attachment_list_to_array(dev, &dev->attach_allowed, attachments,
++			n_attachments);
++	retval = dev->n_attach_allowed;
++	mutex_unlock(&dev->client_lock);
++
++	return retval;
++}
++EXPORT_SYMBOL(adf_device_attachments_allowed);
++
++/**
++ * adf_device_attached - return whether an overlay engine and interface are
++ * attached
++ *
++ * @dev: the parent device
++ * @eng: the overlay engine
++ * @intf: the interface
++ */
++bool adf_device_attached(struct adf_device *dev, struct adf_overlay_engine *eng,
++		struct adf_interface *intf)
++{
++	struct adf_attachment_list *attachment;
++
++	mutex_lock(&dev->client_lock);
++	attachment = adf_attachment_find(&dev->attached, eng, intf);
++	mutex_unlock(&dev->client_lock);
++
++	return attachment != NULL;
++}
++EXPORT_SYMBOL(adf_device_attached);
++
++/**
++ * adf_device_attach_allowed - return whether the ADF device supports attaching
++ * an overlay engine and interface
++ *
++ * @dev: the parent device
++ * @eng: the overlay engine
++ * @intf: the interface
++ */
++bool adf_device_attach_allowed(struct adf_device *dev,
++		struct adf_overlay_engine *eng, struct adf_interface *intf)
++{
++	struct adf_attachment_list *attachment;
++
++	mutex_lock(&dev->client_lock);
++	attachment = adf_attachment_find(&dev->attach_allowed, eng, intf);
++	mutex_unlock(&dev->client_lock);
++
++	return attachment != NULL;
++}
++EXPORT_SYMBOL(adf_device_attach_allowed);
++/**
++ * adf_device_attach - attach an overlay engine to an interface
++ *
++ * @dev: the parent device
++ * @eng: the overlay engine
++ * @intf: the interface
++ *
++ * Returns 0 on success, -%EINVAL if attaching @intf and @eng is not allowed,
++ * -%EALREADY if @intf and @eng are already attached, or -errno on any other
++ * failure.
++ */
++int adf_device_attach(struct adf_device *dev, struct adf_overlay_engine *eng,
++		struct adf_interface *intf)
++{
++	int ret;
++	struct adf_attachment_list *attachment = NULL;
++
++	ret = adf_attachment_validate(dev, eng, intf);
++	if (ret < 0)
++		return ret;
++
++	mutex_lock(&dev->client_lock);
++
++	if (dev->n_attached == ADF_MAX_ATTACHMENTS) {
++		ret = -ENOMEM;
++		goto done;
++	}
++
++	if (!adf_attachment_find(&dev->attach_allowed, eng, intf)) {
++		ret = -EINVAL;
++		goto done;
++	}
++
++	if (adf_attachment_find(&dev->attached, eng, intf)) {
++		ret = -EALREADY;
++		goto done;
++	}
++
++	ret = adf_device_attach_op(dev, eng, intf);
++	if (ret < 0)
++		goto done;
++
++	attachment = kzalloc(sizeof(*attachment), GFP_KERNEL);
++	if (!attachment) {
++		ret = -ENOMEM;
++		goto done;
++	}
++
++	attachment->attachment.interface = intf;
++	attachment->attachment.overlay_engine = eng;
++	list_add_tail(&attachment->head, &dev->attached);
++	dev->n_attached++;
++
++done:
++	mutex_unlock(&dev->client_lock);
++	if (ret < 0)
++		kfree(attachment);
++
++	return ret;
++}
++EXPORT_SYMBOL(adf_device_attach);
++
++/**
++ * adf_device_detach - detach an overlay engine from an interface
++ *
++ * @dev: the parent device
++ * @eng: the overlay engine
++ * @intf: the interface
++ *
++ * Returns 0 on success, -%EINVAL if @intf and @eng are not attached,
++ * or -errno on any other failure.
++ */
++int adf_device_detach(struct adf_device *dev, struct adf_overlay_engine *eng,
++		struct adf_interface *intf)
++{
++	int ret;
++	struct adf_attachment_list *attachment;
++
++	ret = adf_attachment_validate(dev, eng, intf);
++	if (ret < 0)
++		return ret;
++
++	mutex_lock(&dev->client_lock);
++
++	attachment = adf_attachment_find(&dev->attached, eng, intf);
++	if (!attachment) {
++		ret = -EINVAL;
++		goto done;
++	}
++
++	ret = adf_device_detach_op(dev, eng, intf);
++	if (ret < 0)
++		goto done;
++
++	adf_attachment_free(attachment);
++	dev->n_attached--;
++done:
++	mutex_unlock(&dev->client_lock);
++	return ret;
++}
++EXPORT_SYMBOL(adf_device_detach);
++
++/**
++ * adf_interface_simple_buffer_alloc - allocate a simple buffer
++ *
++ * @intf: target interface
++ * @w: width in pixels
++ * @h: height in pixels
++ * @format: format fourcc
++ * @dma_buf: returns the allocated buffer
++ * @offset: returns the byte offset of the allocated buffer's first pixel
++ * @pitch: returns the allocated buffer's pitch
++ *
++ * See &struct adf_simple_buffer_alloc for a description of simple buffers and
++ * their limitations.
++ *
++ * Returns 0 on success or -errno on failure.
++ */
++int adf_interface_simple_buffer_alloc(struct adf_interface *intf, u16 w, u16 h,
++		u32 format, struct dma_buf **dma_buf, u32 *offset, u32 *pitch)
++{
++	if (!intf->ops || !intf->ops->alloc_simple_buffer)
++		return -EOPNOTSUPP;
++
++	if (!adf_format_is_rgb(format))
++		return -EINVAL;
++
++	return intf->ops->alloc_simple_buffer(intf, w, h, format, dma_buf,
++			offset, pitch);
++}
++EXPORT_SYMBOL(adf_interface_simple_buffer_alloc);
++
++/**
++ * adf_interface_simple_post - flip to a single buffer
++ *
++ * @intf: interface targeted by the flip
++ * @buf: buffer to display
++ *
++ * adf_interface_simple_post() can be used generically for simple display
++ * configurations, since the client does not need to provide any driver-private
++ * configuration data.
++ *
++ * adf_interface_simple_post() has the same copying semantics as
++ * adf_device_post().
++ *
++ * On success, returns a sync fence which signals when the buffer is removed
++ * from the screen.  On failure, returns ERR_PTR(-errno).
++ */
++struct sync_fence *adf_interface_simple_post(struct adf_interface *intf,
++		struct adf_buffer *buf)
++{
++	size_t custom_data_size = 0;
++	void *custom_data = NULL;
++	struct sync_fence *ret;
++
++	if (intf->ops && intf->ops->describe_simple_post) {
++		int err;
++
++		custom_data = kzalloc(ADF_MAX_CUSTOM_DATA_SIZE, GFP_KERNEL);
++		if (!custom_data) {
++			ret = ERR_PTR(-ENOMEM);
++			goto done;
++		}
++
++		err = intf->ops->describe_simple_post(intf, buf, custom_data,
++				&custom_data_size);
++		if (err < 0) {
++			ret = ERR_PTR(err);
++			goto done;
++		}
++	}
++
++	ret = adf_device_post(adf_interface_parent(intf), &intf, 1, buf, 1,
++			custom_data, custom_data_size);
++done:
++	kfree(custom_data);
++	return ret;
++}
++EXPORT_SYMBOL(adf_interface_simple_post);
+diff --git a/drivers/video/adf/adf_fbdev.c b/drivers/video/adf/adf_fbdev.c
+new file mode 100644
+index 0000000..a5b53bc
+--- /dev/null
++++ b/drivers/video/adf/adf_fbdev.c
+@@ -0,0 +1,665 @@
++/*
++ * Copyright (C) 2013 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#include <linux/vmalloc.h>
++
++#include <video/adf.h>
++#include <video/adf_client.h>
++#include <video/adf_fbdev.h>
++#include <video/adf_format.h>
++
++#include "adf.h"
++
++struct adf_fbdev_format {
++	u32 fourcc;
++	u32 bpp;
++	u32 r_length;
++	u32 g_length;
++	u32 b_length;
++	u32 a_length;
++	u32 r_offset;
++	u32 g_offset;
++	u32 b_offset;
++	u32 a_offset;
++};
++
++static const struct adf_fbdev_format format_table[] = {
++	{DRM_FORMAT_RGB332, 8, 3, 3, 2, 0, 5, 2, 0, 0},
++	{DRM_FORMAT_BGR233, 8, 3, 3, 2, 0, 0, 3, 5, 0},
++
++	{DRM_FORMAT_XRGB4444, 16, 4, 4, 4, 0, 8, 4, 0, 0},
++	{DRM_FORMAT_XBGR4444, 16, 4, 4, 4, 0, 0, 4, 8, 0},
++	{DRM_FORMAT_RGBX4444, 16, 4, 4, 4, 0, 12, 8, 4, 0},
++	{DRM_FORMAT_BGRX4444, 16, 4, 4, 4, 0, 0, 4, 8, 0},
++
++	{DRM_FORMAT_ARGB4444, 16, 4, 4, 4, 4, 8, 4, 0, 12},
++	{DRM_FORMAT_ABGR4444, 16, 4, 4, 4, 4, 0, 4, 8, 12},
++	{DRM_FORMAT_RGBA4444, 16, 4, 4, 4, 4, 12, 8, 4, 0},
++	{DRM_FORMAT_BGRA4444, 16, 4, 4, 4, 4, 0, 4, 8, 0},
++
++	{DRM_FORMAT_XRGB1555, 16, 5, 5, 5, 0, 10, 5, 0, 0},
++	{DRM_FORMAT_XBGR1555, 16, 5, 5, 5, 0, 0, 5, 10, 0},
++	{DRM_FORMAT_RGBX5551, 16, 5, 5, 5, 0, 11, 6, 1, 0},
++	{DRM_FORMAT_BGRX5551, 16, 5, 5, 5, 0, 1, 6, 11, 0},
++
++	{DRM_FORMAT_ARGB1555, 16, 5, 5, 5, 1, 10, 5, 0, 15},
++	{DRM_FORMAT_ABGR1555, 16, 5, 5, 5, 1, 0, 5, 10, 15},
++	{DRM_FORMAT_RGBA5551, 16, 5, 5, 5, 1, 11, 6, 1, 0},
++	{DRM_FORMAT_BGRA5551, 16, 5, 5, 5, 1, 1, 6, 11, 0},
++
++	{DRM_FORMAT_RGB565, 16, 5, 6, 5, 0, 11, 5, 0, 0},
++	{DRM_FORMAT_BGR565, 16, 5, 6, 5, 0, 0, 5, 11, 0},
++
++	{DRM_FORMAT_RGB888, 24, 8, 8, 8, 0, 16, 8, 0, 0},
++	{DRM_FORMAT_BGR888, 24, 8, 8, 8, 0, 0, 8, 16, 0},
++
++	{DRM_FORMAT_XRGB8888, 32, 8, 8, 8, 0, 16, 8, 0, 0},
++	{DRM_FORMAT_XBGR8888, 32, 8, 8, 8, 0, 0, 8, 16, 0},
++	{DRM_FORMAT_RGBX8888, 32, 8, 8, 8, 0, 24, 16, 8, 0},
++	{DRM_FORMAT_BGRX8888, 32, 8, 8, 8, 0, 8, 16, 24, 0},
++
++	{DRM_FORMAT_ARGB8888, 32, 8, 8, 8, 8, 16, 8, 0, 24},
++	{DRM_FORMAT_ABGR8888, 32, 8, 8, 8, 8, 0, 8, 16, 24},
++	{DRM_FORMAT_RGBA8888, 32, 8, 8, 8, 8, 24, 16, 8, 0},
++	{DRM_FORMAT_BGRA8888, 32, 8, 8, 8, 8, 8, 16, 24, 0},
++
++	{DRM_FORMAT_XRGB2101010, 32, 10, 10, 10, 0, 20, 10, 0, 0},
++	{DRM_FORMAT_XBGR2101010, 32, 10, 10, 10, 0, 0, 10, 20, 0},
++	{DRM_FORMAT_RGBX1010102, 32, 10, 10, 10, 0, 22, 12, 2, 0},
++	{DRM_FORMAT_BGRX1010102, 32, 10, 10, 10, 0, 2, 12, 22, 0},
++
++	{DRM_FORMAT_ARGB2101010, 32, 10, 10, 10, 2, 20, 10, 0, 30},
++	{DRM_FORMAT_ABGR2101010, 32, 10, 10, 10, 2, 0, 10, 20, 30},
++	{DRM_FORMAT_RGBA1010102, 32, 10, 10, 10, 2, 22, 12, 2, 0},
++	{DRM_FORMAT_BGRA1010102, 32, 10, 10, 10, 2, 2, 12, 22, 0},
++};
++
++static u32 drm_fourcc_from_fb_var(struct fb_var_screeninfo *var)
++{
++	size_t i;
++	for (i = 0; i < ARRAY_SIZE(format_table); i++) {
++		const struct adf_fbdev_format *f = &format_table[i];
++		if (var->red.length == f->r_length &&
++			var->red.offset == f->r_offset &&
++			var->green.length == f->g_length &&
++			var->green.offset == f->g_offset &&
++			var->blue.length == f->b_length &&
++			var->blue.offset == f->b_offset &&
++			var->transp.length == f->a_length &&
++			(var->transp.length == 0 ||
++					var->transp.offset == f->a_offset))
++			return f->fourcc;
++	}
++
++	return 0;
++}
++
++static const struct adf_fbdev_format *fbdev_format_info(u32 format)
++{
++	size_t i;
++	for (i = 0; i < ARRAY_SIZE(format_table); i++) {
++		const struct adf_fbdev_format *f = &format_table[i];
++		if (f->fourcc == format)
++			return f;
++	}
++
++	BUG();
++}
++
++void adf_modeinfo_to_fb_videomode(const struct drm_mode_modeinfo *mode,
++		struct fb_videomode *vmode)
++{
++	memset(vmode, 0, sizeof(*vmode));
++
++	vmode->refresh = mode->vrefresh;
++
++	vmode->xres = mode->hdisplay;
++	vmode->yres = mode->vdisplay;
++
++	vmode->pixclock = mode->clock ? KHZ2PICOS(mode->clock) : 0;
++	vmode->left_margin = mode->htotal - mode->hsync_end;
++	vmode->right_margin = mode->hsync_start - mode->hdisplay;
++	vmode->upper_margin = mode->vtotal - mode->vsync_end;
++	vmode->lower_margin = mode->vsync_start - mode->vdisplay;
++	vmode->hsync_len = mode->hsync_end - mode->hsync_start;
++	vmode->vsync_len = mode->vsync_end - mode->vsync_start;
++
++	vmode->sync = 0;
++	if (mode->flags & DRM_MODE_FLAG_PHSYNC)
++		vmode->sync |= FB_SYNC_HOR_HIGH_ACT;
++	if (mode->flags & DRM_MODE_FLAG_PVSYNC)
++		vmode->sync |= FB_SYNC_VERT_HIGH_ACT;
++	if (mode->flags & DRM_MODE_FLAG_PCSYNC)
++		vmode->sync |= FB_SYNC_COMP_HIGH_ACT;
++	if (mode->flags & DRM_MODE_FLAG_BCAST)
++		vmode->sync |= FB_SYNC_BROADCAST;
++
++	vmode->vmode = 0;
++	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
++		vmode->vmode |= FB_VMODE_INTERLACED;
++	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
++		vmode->vmode |= FB_VMODE_DOUBLE;
++}
++EXPORT_SYMBOL(adf_modeinfo_to_fb_videomode);
++
++void adf_modeinfo_from_fb_videomode(const struct fb_videomode *vmode,
++		struct drm_mode_modeinfo *mode)
++{
++	memset(mode, 0, sizeof(*mode));
++
++	mode->hdisplay = vmode->xres;
++	mode->hsync_start = mode->hdisplay + vmode->right_margin;
++	mode->hsync_end = mode->hsync_start + vmode->hsync_len;
++	mode->htotal = mode->hsync_end + vmode->left_margin;
++
++	mode->vdisplay = vmode->yres;
++	mode->vsync_start = mode->vdisplay + vmode->lower_margin;
++	mode->vsync_end = mode->vsync_start + vmode->vsync_len;
++	mode->vtotal = mode->vsync_end + vmode->upper_margin;
++
++	mode->clock = vmode->pixclock ? PICOS2KHZ(vmode->pixclock) : 0;
++
++	mode->flags = 0;
++	if (vmode->sync & FB_SYNC_HOR_HIGH_ACT)
++		mode->flags |= DRM_MODE_FLAG_PHSYNC;
++	if (vmode->sync & FB_SYNC_VERT_HIGH_ACT)
++		mode->flags |= DRM_MODE_FLAG_PVSYNC;
++	if (vmode->sync & FB_SYNC_COMP_HIGH_ACT)
++		mode->flags |= DRM_MODE_FLAG_PCSYNC;
++	if (vmode->sync & FB_SYNC_BROADCAST)
++		mode->flags |= DRM_MODE_FLAG_BCAST;
++	if (vmode->vmode & FB_VMODE_INTERLACED)
++		mode->flags |= DRM_MODE_FLAG_INTERLACE;
++	if (vmode->vmode & FB_VMODE_DOUBLE)
++		mode->flags |= DRM_MODE_FLAG_DBLSCAN;
++
++	if (vmode->refresh)
++		mode->vrefresh = vmode->refresh;
++	else
++		adf_modeinfo_set_vrefresh(mode);
++
++	if (vmode->name)
++		strlcpy(mode->name, vmode->name, sizeof(mode->name));
++	else
++		adf_modeinfo_set_name(mode);
++}
++EXPORT_SYMBOL(adf_modeinfo_from_fb_videomode);
++
++static int adf_fbdev_post(struct adf_fbdev *fbdev)
++{
++	struct adf_buffer buf;
++	struct sync_fence *complete_fence;
++	int ret = 0;
++
++	memset(&buf, 0, sizeof(buf));
++	buf.overlay_engine = fbdev->eng;
++	buf.w = fbdev->info->var.xres;
++	buf.h = fbdev->info->var.yres;
++	buf.format = fbdev->format;
++	buf.dma_bufs[0] = fbdev->dma_buf;
++	buf.offset[0] = fbdev->offset +
++			fbdev->info->var.yoffset * fbdev->pitch +
++			fbdev->info->var.xoffset *
++			(fbdev->info->var.bits_per_pixel / 8);
++	buf.pitch[0] = fbdev->pitch;
++	buf.n_planes = 1;
++
++	complete_fence = adf_interface_simple_post(fbdev->intf, &buf);
++	if (IS_ERR(complete_fence)) {
++		ret = PTR_ERR(complete_fence);
++		goto done;
++	}
++
++	sync_fence_put(complete_fence);
++done:
++	return ret;
++}
++
++static const u16 vga_palette[][3] = {
++	{0x0000, 0x0000, 0x0000},
++	{0x0000, 0x0000, 0xAAAA},
++	{0x0000, 0xAAAA, 0x0000},
++	{0x0000, 0xAAAA, 0xAAAA},
++	{0xAAAA, 0x0000, 0x0000},
++	{0xAAAA, 0x0000, 0xAAAA},
++	{0xAAAA, 0x5555, 0x0000},
++	{0xAAAA, 0xAAAA, 0xAAAA},
++	{0x5555, 0x5555, 0x5555},
++	{0x5555, 0x5555, 0xFFFF},
++	{0x5555, 0xFFFF, 0x5555},
++	{0x5555, 0xFFFF, 0xFFFF},
++	{0xFFFF, 0x5555, 0x5555},
++	{0xFFFF, 0x5555, 0xFFFF},
++	{0xFFFF, 0xFFFF, 0x5555},
++	{0xFFFF, 0xFFFF, 0xFFFF},
++};
++
++static int adf_fb_alloc(struct adf_fbdev *fbdev)
++{
++	int ret;
++
++	ret = adf_interface_simple_buffer_alloc(fbdev->intf,
++			fbdev->default_xres_virtual,
++			fbdev->default_yres_virtual,
++			fbdev->default_format,
++			&fbdev->dma_buf, &fbdev->offset, &fbdev->pitch);
++	if (ret < 0) {
++		dev_err(fbdev->info->dev, "allocating fb failed: %d\n", ret);
++		return ret;
++	}
++
++	fbdev->vaddr = dma_buf_vmap(fbdev->dma_buf);
++	if (!fbdev->vaddr) {
++		ret = -ENOMEM;
++		dev_err(fbdev->info->dev, "vmapping fb failed\n");
++		goto err_vmap;
++	}
++	fbdev->info->fix.line_length = fbdev->pitch;
++	fbdev->info->var.xres_virtual = fbdev->default_xres_virtual;
++	fbdev->info->var.yres_virtual = fbdev->default_yres_virtual;
++	fbdev->info->fix.smem_len = fbdev->dma_buf->size;
++	fbdev->info->screen_base = fbdev->vaddr;
++
++	return 0;
++
++err_vmap:
++	dma_buf_put(fbdev->dma_buf);
++	return ret;
++}
++
++static void adf_fb_destroy(struct adf_fbdev *fbdev)
++{
++	dma_buf_vunmap(fbdev->dma_buf, fbdev->vaddr);
++	dma_buf_put(fbdev->dma_buf);
++}
++
++static void adf_fbdev_set_format(struct adf_fbdev *fbdev, u32 format)
++{
++	size_t i;
++	const struct adf_fbdev_format *info = fbdev_format_info(format);
++	for (i = 0; i < ARRAY_SIZE(vga_palette); i++) {
++		u16 r = vga_palette[i][0];
++		u16 g = vga_palette[i][1];
++		u16 b = vga_palette[i][2];
++
++		r >>= (16 - info->r_length);
++		g >>= (16 - info->g_length);
++		b >>= (16 - info->b_length);
++
++		fbdev->pseudo_palette[i] =
++			(r << info->r_offset) |
++			(g << info->g_offset) |
++			(b << info->b_offset);
++
++		if (info->a_length) {
++			u16 a = BIT(info->a_length) - 1;
++			fbdev->pseudo_palette[i] |= (a << info->a_offset);
++		}
++	}
++
++	fbdev->info->var.bits_per_pixel = adf_format_bpp(format);
++	fbdev->info->var.red.length = info->r_length;
++	fbdev->info->var.red.offset = info->r_offset;
++	fbdev->info->var.green.length = info->g_length;
++	fbdev->info->var.green.offset = info->g_offset;
++	fbdev->info->var.blue.length = info->b_length;
++	fbdev->info->var.blue.offset = info->b_offset;
++	fbdev->info->var.transp.length = info->a_length;
++	fbdev->info->var.transp.offset = info->a_offset;
++	fbdev->format = format;
++}
++
++static void adf_fbdev_fill_modelist(struct adf_fbdev *fbdev)
++{
++	struct drm_mode_modeinfo *modelist;
++	struct fb_videomode fbmode;
++	size_t n_modes, i;
++	int ret = 0;
++
++	n_modes = adf_interface_modelist(fbdev->intf, NULL, 0);
++	modelist = kzalloc(sizeof(modelist[0]) * n_modes, GFP_KERNEL);
++	if (!modelist) {
++		dev_warn(fbdev->info->dev, "allocating new modelist failed; keeping old modelist\n");
++		return;
++	}
++	adf_interface_modelist(fbdev->intf, modelist, n_modes);
++
++	fb_destroy_modelist(&fbdev->info->modelist);
++
++	for (i = 0; i < n_modes; i++) {
++		adf_modeinfo_to_fb_videomode(&modelist[i], &fbmode);
++		ret = fb_add_videomode(&fbmode, &fbdev->info->modelist);
++		if (ret < 0)
++			dev_warn(fbdev->info->dev, "adding mode %s to modelist failed: %d\n",
++					modelist[i].name, ret);
++	}
++
++	kfree(modelist);
++}
++
++/**
++ * adf_fbdev_open - default implementation of fbdev open op
++ */
++int adf_fbdev_open(struct fb_info *info, int user)
++{
++	struct adf_fbdev *fbdev = info->par;
++	int ret;
++
++	mutex_lock(&fbdev->refcount_lock);
++
++	if (unlikely(fbdev->refcount == UINT_MAX)) {
++		ret = -EMFILE;
++		goto done;
++	}
++
++	if (!fbdev->refcount) {
++		struct drm_mode_modeinfo mode;
++		struct fb_videomode fbmode;
++		struct adf_device *dev = adf_interface_parent(fbdev->intf);
++
++		ret = adf_device_attach(dev, fbdev->eng, fbdev->intf);
++		if (ret < 0 && ret != -EALREADY)
++			goto done;
++
++		ret = adf_fb_alloc(fbdev);
++		if (ret < 0)
++			goto done;
++
++		adf_interface_current_mode(fbdev->intf, &mode);
++		adf_modeinfo_to_fb_videomode(&mode, &fbmode);
++		fb_videomode_to_var(&fbdev->info->var, &fbmode);
++
++		adf_fbdev_set_format(fbdev, fbdev->default_format);
++		adf_fbdev_fill_modelist(fbdev);
++	}
++
++	ret = adf_fbdev_post(fbdev);
++	if (ret < 0) {
++		if (!fbdev->refcount)
++			adf_fb_destroy(fbdev);
++		goto done;
++	}
++
++	fbdev->refcount++;
++done:
++	mutex_unlock(&fbdev->refcount_lock);
++	return ret;
++}
++EXPORT_SYMBOL(adf_fbdev_open);
++
++/**
++ * adf_fbdev_release - default implementation of fbdev release op
++ */
++int adf_fbdev_release(struct fb_info *info, int user)
++{
++	struct adf_fbdev *fbdev = info->par;
++	mutex_lock(&fbdev->refcount_lock);
++	BUG_ON(!fbdev->refcount);
++	fbdev->refcount--;
++	if (!fbdev->refcount)
++		adf_fb_destroy(fbdev);
++	mutex_unlock(&fbdev->refcount_lock);
++	return 0;
++}
++EXPORT_SYMBOL(adf_fbdev_release);
++
++/**
++ * adf_fbdev_check_var - default implementation of fbdev check_var op
++ */
++int adf_fbdev_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
++{
++	struct adf_fbdev *fbdev = info->par;
++	bool valid_format = true;
++	u32 format = drm_fourcc_from_fb_var(var);
++	u32 pitch = var->xres_virtual * var->bits_per_pixel / 8;
++
++	if (!format) {
++		dev_dbg(info->dev, "%s: unrecognized format\n", __func__);
++		valid_format = false;
++	}
++
++	if (valid_format && var->grayscale) {
++		dev_dbg(info->dev, "%s: grayscale modes not supported\n",
++				__func__);
++		valid_format = false;
++	}
++
++	if (valid_format && var->nonstd) {
++		dev_dbg(info->dev, "%s: nonstandard formats not supported\n",
++				__func__);
++		valid_format = false;
++	}
++
++	if (valid_format && !adf_overlay_engine_supports_format(fbdev->eng,
++			format)) {
++		char format_str[ADF_FORMAT_STR_SIZE];
++		adf_format_str(format, format_str);
++		dev_dbg(info->dev, "%s: format %s not supported by overlay engine %s\n",
++				__func__, format_str, fbdev->eng->base.name);
++		valid_format = false;
++	}
++
++	if (valid_format && pitch > fbdev->pitch) {
++		dev_dbg(info->dev, "%s: fb pitch too small for var (pitch = %u, xres_virtual = %u, bits_per_pixel = %u)\n",
++				__func__, fbdev->pitch, var->xres_virtual,
++				var->bits_per_pixel);
++		valid_format = false;
++	}
++
++	if (valid_format && var->yres_virtual > fbdev->default_yres_virtual) {
++		dev_dbg(info->dev, "%s: fb height too small for var (h = %u, yres_virtual = %u)\n",
++				__func__, fbdev->default_yres_virtual,
++				var->yres_virtual);
++		valid_format = false;
++	}
++
++	if (valid_format) {
++		var->activate = info->var.activate;
++		var->height = info->var.height;
++		var->width = info->var.width;
++		var->accel_flags = info->var.accel_flags;
++		var->rotate = info->var.rotate;
++		var->colorspace = info->var.colorspace;
++		/* userspace can't change these */
++	} else {
++		/* if any part of the format is invalid then fixing it up is
++		   impractical, so save just the modesetting bits and
++		   overwrite everything else */
++		struct fb_videomode mode;
++		fb_var_to_videomode(&mode, var);
++		memcpy(var, &info->var, sizeof(*var));
++		fb_videomode_to_var(var, &mode);
++	}
++
++	return 0;
++}
++EXPORT_SYMBOL(adf_fbdev_check_var);
++
++/**
++ * adf_fbdev_set_par - default implementation of fbdev set_par op
++ */
++int adf_fbdev_set_par(struct fb_info *info)
++{
++	struct adf_fbdev *fbdev = info->par;
++	struct adf_interface *intf = fbdev->intf;
++	struct fb_videomode vmode;
++	struct drm_mode_modeinfo mode;
++	int ret;
++	u32 format = drm_fourcc_from_fb_var(&info->var);
++
++	fb_var_to_videomode(&vmode, &info->var);
++	adf_modeinfo_from_fb_videomode(&vmode, &mode);
++	ret = adf_interface_set_mode(intf, &mode);
++	if (ret < 0)
++		return ret;
++
++	ret = adf_fbdev_post(fbdev);
++	if (ret < 0)
++		return ret;
++
++	if (format != fbdev->format)
++		adf_fbdev_set_format(fbdev, format);
++
++	return 0;
++}
++EXPORT_SYMBOL(adf_fbdev_set_par);
++
++/**
++ * adf_fbdev_blank - default implementation of fbdev blank op
++ */
++int adf_fbdev_blank(int blank, struct fb_info *info)
++{
++	struct adf_fbdev *fbdev = info->par;
++	struct adf_interface *intf = fbdev->intf;
++	u8 dpms_state;
++
++	switch (blank) {
++	case FB_BLANK_UNBLANK:
++		dpms_state = DRM_MODE_DPMS_ON;
++		break;
++	case FB_BLANK_NORMAL:
++		dpms_state = DRM_MODE_DPMS_STANDBY;
++		break;
++	case FB_BLANK_VSYNC_SUSPEND:
++		dpms_state = DRM_MODE_DPMS_SUSPEND;
++		break;
++	case FB_BLANK_HSYNC_SUSPEND:
++		dpms_state = DRM_MODE_DPMS_STANDBY;
++		break;
++	case FB_BLANK_POWERDOWN:
++		dpms_state = DRM_MODE_DPMS_OFF;
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	return adf_interface_blank(intf, dpms_state);
++}
++EXPORT_SYMBOL(adf_fbdev_blank);
++
++/**
++ * adf_fbdev_pan_display - default implementation of fbdev pan_display op
++ */
++int adf_fbdev_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
++{
++	struct adf_fbdev *fbdev = info->par;
++	return adf_fbdev_post(fbdev);
++}
++EXPORT_SYMBOL(adf_fbdev_pan_display);
++
++/**
++ * adf_fbdev_mmap - default implementation of fbdev mmap op
++ */
++int adf_fbdev_mmap(struct fb_info *info, struct vm_area_struct *vma)
++{
++	struct adf_fbdev *fbdev = info->par;
++
++	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
++	return dma_buf_mmap(fbdev->dma_buf, vma, 0);
++}
++EXPORT_SYMBOL(adf_fbdev_mmap);
++
++/**
++ * adf_fbdev_init - initialize helper to wrap ADF device in fbdev API
++ *
++ * @fbdev: the fbdev helper
++ * @interface: the ADF interface that will display the framebuffer
++ * @eng: the ADF overlay engine that will scan out the framebuffer
++ * @xres_virtual: the virtual width of the framebuffer
++ * @yres_virtual: the virtual height of the framebuffer
++ * @format: the format of the framebuffer
++ * @fbops: the device's fbdev ops
++ * @fmt: formatting for the framebuffer identification string
++ * @...: variable arguments
++ *
++ * @format must be a standard, non-indexed RGB format, i.e.,
++ * adf_format_is_rgb(@format) && @format != @DRM_FORMAT_C8.
++ *
++ * Returns 0 on success or -errno on failure.
++ */
++int adf_fbdev_init(struct adf_fbdev *fbdev, struct adf_interface *interface,
++		struct adf_overlay_engine *eng,
++		u16 xres_virtual, u16 yres_virtual, u32 format,
++		struct fb_ops *fbops, const char *fmt, ...)
++{
++	struct adf_device *parent = adf_interface_parent(interface);
++	struct device *dev = &parent->base.dev;
++	u16 width_mm, height_mm;
++	va_list args;
++	int ret;
++
++	if (!adf_format_is_rgb(format) ||
++			format == DRM_FORMAT_C8) {
++		dev_err(dev, "fbdev helper does not support format %u\n",
++				format);
++		return -EINVAL;
++	}
++
++	memset(fbdev, 0, sizeof(*fbdev));
++	fbdev->intf = interface;
++	fbdev->eng = eng;
++	fbdev->info = framebuffer_alloc(0, dev);
++	if (!fbdev->info) {
++		dev_err(dev, "allocating framebuffer device failed\n");
++		return -ENOMEM;
++	}
++	mutex_init(&fbdev->refcount_lock);
++	fbdev->default_xres_virtual = xres_virtual;
++	fbdev->default_yres_virtual = yres_virtual;
++	fbdev->default_format = format;
++
++	fbdev->info->flags = FBINFO_FLAG_DEFAULT;
++	ret = adf_interface_get_screen_size(interface, &width_mm, &height_mm);
++	if (ret < 0) {
++		width_mm = 0;
++		height_mm = 0;
++	}
++	fbdev->info->var.width = width_mm;
++	fbdev->info->var.height = height_mm;
++	fbdev->info->var.activate = FB_ACTIVATE_VBL;
++	va_start(args, fmt);
++	vsnprintf(fbdev->info->fix.id, sizeof(fbdev->info->fix.id), fmt, args);
++	va_end(args);
++	fbdev->info->fix.type = FB_TYPE_PACKED_PIXELS;
++	fbdev->info->fix.visual = FB_VISUAL_TRUECOLOR;
++	fbdev->info->fix.xpanstep = 1;
++	fbdev->info->fix.ypanstep = 1;
++	INIT_LIST_HEAD(&fbdev->info->modelist);
++	fbdev->info->fbops = fbops;
++	fbdev->info->pseudo_palette = fbdev->pseudo_palette;
++	fbdev->info->par = fbdev;
++
++	ret = register_framebuffer(fbdev->info);
++	if (ret < 0) {
++		dev_err(dev, "registering framebuffer failed: %d\n", ret);
++		return ret;
++	}
++
++	return 0;
++}
++EXPORT_SYMBOL(adf_fbdev_init);
++
++/**
++ * adf_fbdev_destroy - destroy helper to wrap ADF device in fbdev API
++ *
++ * @fbdev: the fbdev helper
++ */
++void adf_fbdev_destroy(struct adf_fbdev *fbdev)
++{
++	unregister_framebuffer(fbdev->info);
++	BUG_ON(fbdev->refcount);
++	mutex_destroy(&fbdev->refcount_lock);
++	framebuffer_release(fbdev->info);
++}
++EXPORT_SYMBOL(adf_fbdev_destroy);
+diff --git a/drivers/video/adf/adf_fops.c b/drivers/video/adf/adf_fops.c
+new file mode 100644
+index 0000000..7fbf33e
+--- /dev/null
++++ b/drivers/video/adf/adf_fops.c
+@@ -0,0 +1,957 @@
++/*
++ * Copyright (C) 2013 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#include <linux/bitops.h>
++#include <linux/circ_buf.h>
++#include <linux/fs.h>
++#include <linux/module.h>
++#include <linux/poll.h>
++#include <linux/slab.h>
++#include <linux/uaccess.h>
++
++#include <video/adf_client.h>
++#include <video/adf_format.h>
++
++#include "sw_sync.h"
++#include "sync.h"
++
++#include "adf.h"
++#include "adf_fops.h"
++#include "adf_sysfs.h"
++
++#ifdef CONFIG_COMPAT
++#include "adf_fops32.h"
++#endif
++
++static int adf_obj_set_event(struct adf_obj *obj, struct adf_file *file,
++		struct adf_set_event __user *arg)
++{
++	struct adf_set_event data;
++	bool enabled;
++	unsigned long flags;
++	int err;
++
++	if (copy_from_user(&data, arg, sizeof(data)))
++		return -EFAULT;
++
++	err = adf_obj_check_supports_event(obj, data.type);
++	if (err < 0)
++		return err;
++
++	spin_lock_irqsave(&obj->file_lock, flags);
++	if (data.enabled)
++		enabled = test_and_set_bit(data.type,
++				file->event_subscriptions);
++	else
++		enabled = test_and_clear_bit(data.type,
++				file->event_subscriptions);
++	spin_unlock_irqrestore(&obj->file_lock, flags);
++
++	if (data.enabled == enabled)
++		return -EALREADY;
++
++	if (data.enabled)
++		adf_event_get(obj, data.type);
++	else
++		adf_event_put(obj, data.type);
++
++	return 0;
++}
++
++static int adf_obj_copy_custom_data_to_user(struct adf_obj *obj,
++		void __user *dst, size_t *dst_size)
++{
++	void *custom_data;
++	size_t custom_data_size;
++	int ret;
++
++	if (!obj->ops || !obj->ops->custom_data) {
++		dev_dbg(&obj->dev, "%s: no custom_data op\n", __func__);
++		return 0;
++	}
++
++	custom_data = kzalloc(ADF_MAX_CUSTOM_DATA_SIZE, GFP_KERNEL);
++	if (!custom_data)
++		return -ENOMEM;
++
++	ret = obj->ops->custom_data(obj, custom_data, &custom_data_size);
++	if (ret < 0)
++		goto done;
++
++	if (copy_to_user(dst, custom_data, min(*dst_size, custom_data_size))) {
++		ret = -EFAULT;
++		goto done;
++	}
++	*dst_size = custom_data_size;
++
++done:
++	kfree(custom_data);
++	return ret;
++}
++
++static int adf_eng_get_data(struct adf_overlay_engine *eng,
++		struct adf_overlay_engine_data __user *arg)
++{
++	struct adf_device *dev = adf_overlay_engine_parent(eng);
++	struct adf_overlay_engine_data data;
++	size_t n_supported_formats;
++	u32 *supported_formats = NULL;
++	int ret = 0;
++
++	if (copy_from_user(&data, arg, sizeof(data)))
++		return -EFAULT;
++
++	strlcpy(data.name, eng->base.name, sizeof(data.name));
++
++	if (data.n_supported_formats > ADF_MAX_SUPPORTED_FORMATS)
++		return -EINVAL;
++
++	n_supported_formats = data.n_supported_formats;
++	data.n_supported_formats = eng->ops->n_supported_formats;
++
++	if (n_supported_formats) {
++		supported_formats = kzalloc(n_supported_formats *
++				sizeof(supported_formats[0]), GFP_KERNEL);
++		if (!supported_formats)
++			return -ENOMEM;
++	}
++
++	memcpy(supported_formats, eng->ops->supported_formats,
++			sizeof(u32) * min(n_supported_formats,
++					eng->ops->n_supported_formats));
++
++	mutex_lock(&dev->client_lock);
++	ret = adf_obj_copy_custom_data_to_user(&eng->base, arg->custom_data,
++			&data.custom_data_size);
++	mutex_unlock(&dev->client_lock);
++
++	if (ret < 0)
++		goto done;
++
++	if (copy_to_user(arg, &data, sizeof(data))) {
++		ret = -EFAULT;
++		goto done;
++	}
++
++	if (supported_formats && copy_to_user(arg->supported_formats,
++			supported_formats,
++			n_supported_formats * sizeof(supported_formats[0])))
++		ret = -EFAULT;
++
++done:
++	kfree(supported_formats);
++	return ret;
++}
++
++static int adf_buffer_import(struct adf_device *dev,
++		struct adf_buffer_config __user *cfg, struct adf_buffer *buf)
++{
++	struct adf_buffer_config user_buf;
++	size_t i;
++	int ret = 0;
++
++	if (copy_from_user(&user_buf, cfg, sizeof(user_buf)))
++		return -EFAULT;
++
++	memset(buf, 0, sizeof(*buf));
++
++	if (user_buf.n_planes > ADF_MAX_PLANES) {
++		dev_err(&dev->base.dev, "invalid plane count %u\n",
++				user_buf.n_planes);
++		return -EINVAL;
++	}
++
++	buf->overlay_engine = idr_find(&dev->overlay_engines,
++			user_buf.overlay_engine);
++	if (!buf->overlay_engine) {
++		dev_err(&dev->base.dev, "invalid overlay engine id %u\n",
++				user_buf.overlay_engine);
++		return -ENOENT;
++	}
++
++	buf->w = user_buf.w;
++	buf->h = user_buf.h;
++	buf->format = user_buf.format;
++	for (i = 0; i < user_buf.n_planes; i++) {
++		buf->dma_bufs[i] = dma_buf_get(user_buf.fd[i]);
++		if (IS_ERR(buf->dma_bufs[i])) {
++			ret = PTR_ERR(buf->dma_bufs[i]);
++			dev_err(&dev->base.dev, "importing dma_buf fd %d failed: %d\n",
++					user_buf.fd[i], ret);
++			buf->dma_bufs[i] = NULL;
++			goto done;
++		}
++		buf->offset[i] = user_buf.offset[i];
++		buf->pitch[i] = user_buf.pitch[i];
++	}
++	buf->n_planes = user_buf.n_planes;
++
++	if (user_buf.acquire_fence >= 0) {
++		buf->acquire_fence = sync_fence_fdget(user_buf.acquire_fence);
++		if (!buf->acquire_fence) {
++			dev_err(&dev->base.dev, "getting fence fd %d failed\n",
++					user_buf.acquire_fence);
++			ret = -EINVAL;
++			goto done;
++		}
++	}
++
++done:
++	if (ret < 0)
++		adf_buffer_cleanup(buf);
++	return ret;
++}
++
++static int adf_device_post_config(struct adf_device *dev,
++		struct adf_post_config __user *arg)
++{
++	struct sync_fence *complete_fence;
++	int complete_fence_fd;
++	struct adf_buffer *bufs = NULL;
++	struct adf_interface **intfs = NULL;
++	size_t n_intfs, n_bufs, i;
++	void *custom_data = NULL;
++	size_t custom_data_size;
++	int ret = 0;
++
++	complete_fence_fd = get_unused_fd();
++	if (complete_fence_fd < 0)
++		return complete_fence_fd;
++
++	if (get_user(n_intfs, &arg->n_interfaces)) {
++		ret = -EFAULT;
++		goto err_get_user;
++	}
++
++	if (n_intfs > ADF_MAX_INTERFACES) {
++		ret = -EINVAL;
++		goto err_get_user;
++	}
++
++	if (get_user(n_bufs, &arg->n_bufs)) {
++		ret = -EFAULT;
++		goto err_get_user;
++	}
++
++	if (n_bufs > ADF_MAX_BUFFERS) {
++		ret = -EINVAL;
++		goto err_get_user;
++	}
++
++	if (get_user(custom_data_size, &arg->custom_data_size)) {
++		ret = -EFAULT;
++		goto err_get_user;
++	}
++
++	if (custom_data_size > ADF_MAX_CUSTOM_DATA_SIZE) {
++		ret = -EINVAL;
++		goto err_get_user;
++	}
++
++	if (n_intfs) {
++		intfs = kmalloc(sizeof(intfs[0]) * n_intfs, GFP_KERNEL);
++		if (!intfs) {
++			ret = -ENOMEM;
++			goto err_get_user;
++		}
++	}
++
++	for (i = 0; i < n_intfs; i++) {
++		u32 intf_id;
++		if (get_user(intf_id, &arg->interfaces[i])) {
++			ret = -EFAULT;
++			goto err_get_user;
++		}
++
++		intfs[i] = idr_find(&dev->interfaces, intf_id);
++		if (!intfs[i]) {
++			ret = -EINVAL;
++			goto err_get_user;
++		}
++	}
++
++	if (n_bufs) {
++		bufs = kzalloc(sizeof(bufs[0]) * n_bufs, GFP_KERNEL);
++		if (!bufs) {
++			ret = -ENOMEM;
++			goto err_get_user;
++		}
++	}
++
++	for (i = 0; i < n_bufs; i++) {
++		ret = adf_buffer_import(dev, &arg->bufs[i], &bufs[i]);
++		if (ret < 0) {
++			memset(&bufs[i], 0, sizeof(bufs[i]));
++			goto err_import;
++		}
++	}
++
++	if (custom_data_size) {
++		custom_data = kzalloc(custom_data_size, GFP_KERNEL);
++		if (!custom_data) {
++			ret = -ENOMEM;
++			goto err_import;
++		}
++
++		if (copy_from_user(custom_data, arg->custom_data,
++				custom_data_size)) {
++			ret = -EFAULT;
++			goto err_import;
++		}
++	}
++
++	if (put_user(complete_fence_fd, &arg->complete_fence)) {
++		ret = -EFAULT;
++		goto err_import;
++	}
++
++	complete_fence = adf_device_post_nocopy(dev, intfs, n_intfs, bufs,
++			n_bufs, custom_data, custom_data_size);
++	if (IS_ERR(complete_fence)) {
++		ret = PTR_ERR(complete_fence);
++		goto err_import;
++	}
++
++	sync_fence_install(complete_fence, complete_fence_fd);
++	return 0;
++
++err_import:
++	for (i = 0; i < n_bufs; i++)
++		adf_buffer_cleanup(&bufs[i]);
++
++err_get_user:
++	kfree(custom_data);
++	kfree(bufs);
++	kfree(intfs);
++	put_unused_fd(complete_fence_fd);
++	return ret;
++}
++
++static int adf_intf_simple_post_config(struct adf_interface *intf,
++		struct adf_simple_post_config __user *arg)
++{
++	struct adf_device *dev = intf->base.parent;
++	struct sync_fence *complete_fence;
++	int complete_fence_fd;
++	struct adf_buffer buf;
++	int ret = 0;
++
++	complete_fence_fd = get_unused_fd();
++	if (complete_fence_fd < 0)
++		return complete_fence_fd;
++
++	ret = adf_buffer_import(dev, &arg->buf, &buf);
++	if (ret < 0)
++		goto err_import;
++
++	if (put_user(complete_fence_fd, &arg->complete_fence)) {
++		ret = -EFAULT;
++		goto err_put_user;
++	}
++
++	complete_fence = adf_interface_simple_post(intf, &buf);
++	if (IS_ERR(complete_fence)) {
++		ret = PTR_ERR(complete_fence);
++		goto err_put_user;
++	}
++
++	sync_fence_install(complete_fence, complete_fence_fd);
++	return 0;
++
++err_put_user:
++	adf_buffer_cleanup(&buf);
++err_import:
++	put_unused_fd(complete_fence_fd);
++	return ret;
++}
++
++static int adf_intf_simple_buffer_alloc(struct adf_interface *intf,
++		struct adf_simple_buffer_alloc __user *arg)
++{
++	struct adf_simple_buffer_alloc data;
++	struct dma_buf *dma_buf;
++	int ret = 0;
++
++	if (copy_from_user(&data, arg, sizeof(data)))
++		return -EFAULT;
++
++	data.fd = get_unused_fd_flags(O_CLOEXEC);
++	if (data.fd < 0)
++		return data.fd;
++
++	ret = adf_interface_simple_buffer_alloc(intf, data.w, data.h,
++			data.format, &dma_buf, &data.offset, &data.pitch);
++	if (ret < 0)
++		goto err_alloc;
++
++	if (copy_to_user(arg, &data, sizeof(*arg))) {
++		ret = -EFAULT;
++		goto err_copy;
++	}
++
++	fd_install(data.fd, dma_buf->file);
++	return 0;
++
++err_copy:
++	dma_buf_put(dma_buf);
++
++err_alloc:
++	put_unused_fd(data.fd);
++	return ret;
++}
++
++static int adf_copy_attachment_list_to_user(
++		struct adf_attachment_config __user *to, size_t n_to,
++		struct adf_attachment *from, size_t n_from)
++{
++	struct adf_attachment_config *temp;
++	size_t n = min(n_to, n_from);
++	size_t i;
++	int ret = 0;
++
++	if (!n)
++		return 0;
++
++	temp = kzalloc(n * sizeof(temp[0]), GFP_KERNEL);
++	if (!temp)
++		return -ENOMEM;
++
++	for (i = 0; i < n; i++) {
++		temp[i].interface = from[i].interface->base.id;
++		temp[i].overlay_engine = from[i].overlay_engine->base.id;
++	}
++
++	if (copy_to_user(to, temp, n * sizeof(to[0]))) {
++		ret = -EFAULT;
++		goto done;
++	}
++
++done:
++	kfree(temp);
++	return ret;
++}
++
++static int adf_device_get_data(struct adf_device *dev,
++		struct adf_device_data __user *arg)
++{
++	struct adf_device_data data;
++	size_t n_attach;
++	struct adf_attachment *attach = NULL;
++	size_t n_allowed_attach;
++	struct adf_attachment *allowed_attach = NULL;
++	int ret = 0;
++
++	if (copy_from_user(&data, arg, sizeof(data)))
++		return -EFAULT;
++
++	if (data.n_attachments > ADF_MAX_ATTACHMENTS ||
++			data.n_allowed_attachments > ADF_MAX_ATTACHMENTS)
++		return -EINVAL;
++
++	strlcpy(data.name, dev->base.name, sizeof(data.name));
++
++	if (data.n_attachments) {
++		attach = kzalloc(data.n_attachments * sizeof(attach[0]),
++				GFP_KERNEL);
++		if (!attach)
++			return -ENOMEM;
++	}
++	n_attach = adf_device_attachments(dev, attach, data.n_attachments);
++
++	if (data.n_allowed_attachments) {
++		allowed_attach = kzalloc(data.n_allowed_attachments *
++				sizeof(allowed_attach[0]), GFP_KERNEL);
++		if (!allowed_attach) {
++			ret = -ENOMEM;
++			goto done;
++		}
++	}
++	n_allowed_attach = adf_device_attachments_allowed(dev, allowed_attach,
++			data.n_allowed_attachments);
++
++	mutex_lock(&dev->client_lock);
++	ret = adf_obj_copy_custom_data_to_user(&dev->base, arg->custom_data,
++			&data.custom_data_size);
++	mutex_unlock(&dev->client_lock);
++
++	if (ret < 0)
++		goto done;
++
++	ret = adf_copy_attachment_list_to_user(arg->attachments,
++			data.n_attachments, attach, n_attach);
++	if (ret < 0)
++		goto done;
++
++	ret = adf_copy_attachment_list_to_user(arg->allowed_attachments,
++			data.n_allowed_attachments, allowed_attach,
++			n_allowed_attach);
++	if (ret < 0)
++		goto done;
++
++	data.n_attachments = n_attach;
++	data.n_allowed_attachments = n_allowed_attach;
++
++	if (copy_to_user(arg, &data, sizeof(data)))
++		ret = -EFAULT;
++
++done:
++	kfree(allowed_attach);
++	kfree(attach);
++	return ret;
++}
++
++static int adf_device_handle_attachment(struct adf_device *dev,
++		struct adf_attachment_config __user *arg, bool attach)
++{
++	struct adf_attachment_config data;
++	struct adf_overlay_engine *eng;
++	struct adf_interface *intf;
++
++	if (copy_from_user(&data, arg, sizeof(data)))
++		return -EFAULT;
++
++	eng = idr_find(&dev->overlay_engines, data.overlay_engine);
++	if (!eng) {
++		dev_err(&dev->base.dev, "invalid overlay engine id %u\n",
++				data.overlay_engine);
++		return -EINVAL;
++	}
++
++	intf = idr_find(&dev->interfaces, data.interface);
++	if (!intf) {
++		dev_err(&dev->base.dev, "invalid interface id %u\n",
++				data.interface);
++		return -EINVAL;
++	}
++
++	if (attach)
++		return adf_device_attach(dev, eng, intf);
++	else
++		return adf_device_detach(dev, eng, intf);
++}
++
++static int adf_intf_set_mode(struct adf_interface *intf,
++		struct drm_mode_modeinfo __user *arg)
++{
++	struct drm_mode_modeinfo mode;
++
++	if (copy_from_user(&mode, arg, sizeof(mode)))
++		return -EFAULT;
++
++	return adf_interface_set_mode(intf, &mode);
++}
++
++static int adf_intf_get_data(struct adf_interface *intf,
++		struct adf_interface_data __user *arg)
++{
++	struct adf_device *dev = adf_interface_parent(intf);
++	struct adf_interface_data data;
++	struct drm_mode_modeinfo *modelist;
++	size_t modelist_size;
++	int err;
++	int ret = 0;
++	unsigned long flags;
++
++	if (copy_from_user(&data, arg, sizeof(data)))
++		return -EFAULT;
++
++	strlcpy(data.name, intf->base.name, sizeof(data.name));
++
++	data.type = intf->type;
++	data.id = intf->idx;
++	data.flags = intf->flags;
++
++	err = adf_interface_get_screen_size(intf, &data.width_mm,
++			&data.height_mm);
++	if (err < 0) {
++		data.width_mm = 0;
++		data.height_mm = 0;
++	}
++
++	modelist = kmalloc(sizeof(modelist[0]) * ADF_MAX_MODES, GFP_KERNEL);
++	if (!modelist)
++		return -ENOMEM;
++
++	mutex_lock(&dev->client_lock);
++	read_lock_irqsave(&intf->hotplug_modelist_lock, flags);
++	data.hotplug_detect = intf->hotplug_detect;
++	modelist_size = min(data.n_available_modes, intf->n_modes) *
++			sizeof(intf->modelist[0]);
++	memcpy(modelist, intf->modelist, modelist_size);
++	data.n_available_modes = intf->n_modes;
++	read_unlock_irqrestore(&intf->hotplug_modelist_lock, flags);
++
++	if (copy_to_user(arg->available_modes, modelist, modelist_size)) {
++		ret = -EFAULT;
++		goto done;
++	}
++
++	data.dpms_state = intf->dpms_state;
++	memcpy(&data.current_mode, &intf->current_mode,
++			sizeof(intf->current_mode));
++
++	ret = adf_obj_copy_custom_data_to_user(&intf->base, arg->custom_data,
++			&data.custom_data_size);
++done:
++	mutex_unlock(&dev->client_lock);
++	kfree(modelist);
++
++	if (ret < 0)
++		return ret;
++
++	if (copy_to_user(arg, &data, sizeof(data)))
++		ret = -EFAULT;
++
++	return ret;
++}
++
++static inline long adf_obj_custom_ioctl(struct adf_obj *obj, unsigned int cmd,
++		unsigned long arg)
++{
++	if (obj->ops && obj->ops->ioctl)
++		return obj->ops->ioctl(obj, cmd, arg);
++	return -ENOTTY;
++}
++
++static long adf_overlay_engine_ioctl(struct adf_overlay_engine *eng,
++		struct adf_file *file, unsigned int cmd, unsigned long arg)
++{
++	switch (cmd) {
++	case ADF_SET_EVENT:
++		return adf_obj_set_event(&eng->base, file,
++				(struct adf_set_event __user *)arg);
++
++	case ADF_GET_OVERLAY_ENGINE_DATA:
++		return adf_eng_get_data(eng,
++			(struct adf_overlay_engine_data __user *)arg);
++
++	case ADF_BLANK:
++	case ADF_POST_CONFIG:
++	case ADF_SET_MODE:
++	case ADF_GET_DEVICE_DATA:
++	case ADF_GET_INTERFACE_DATA:
++	case ADF_SIMPLE_POST_CONFIG:
++	case ADF_SIMPLE_BUFFER_ALLOC:
++	case ADF_ATTACH:
++	case ADF_DETACH:
++		return -EINVAL;
++
++	default:
++		return adf_obj_custom_ioctl(&eng->base, cmd, arg);
++	}
++}
++
++static long adf_interface_ioctl(struct adf_interface *intf,
++		struct adf_file *file, unsigned int cmd, unsigned long arg)
++{
++	switch (cmd) {
++	case ADF_SET_EVENT:
++		return adf_obj_set_event(&intf->base, file,
++				(struct adf_set_event __user *)arg);
++
++	case ADF_BLANK:
++		return adf_interface_blank(intf, arg);
++
++	case ADF_SET_MODE:
++		return adf_intf_set_mode(intf,
++				(struct drm_mode_modeinfo __user *)arg);
++
++	case ADF_GET_INTERFACE_DATA:
++		return adf_intf_get_data(intf,
++				(struct adf_interface_data __user *)arg);
++
++	case ADF_SIMPLE_POST_CONFIG:
++		return adf_intf_simple_post_config(intf,
++				(struct adf_simple_post_config __user *)arg);
++
++	case ADF_SIMPLE_BUFFER_ALLOC:
++		return adf_intf_simple_buffer_alloc(intf,
++				(struct adf_simple_buffer_alloc __user *)arg);
++
++	case ADF_POST_CONFIG:
++	case ADF_GET_DEVICE_DATA:
++	case ADF_GET_OVERLAY_ENGINE_DATA:
++	case ADF_ATTACH:
++	case ADF_DETACH:
++		return -EINVAL;
++
++	default:
++		return adf_obj_custom_ioctl(&intf->base, cmd, arg);
++	}
++}
++
++static long adf_device_ioctl(struct adf_device *dev, struct adf_file *file,
++		unsigned int cmd, unsigned long arg)
++{
++	switch (cmd) {
++	case ADF_SET_EVENT:
++		return adf_obj_set_event(&dev->base, file,
++				(struct adf_set_event __user *)arg);
++
++	case ADF_POST_CONFIG:
++		return adf_device_post_config(dev,
++				(struct adf_post_config __user *)arg);
++
++	case ADF_GET_DEVICE_DATA:
++		return adf_device_get_data(dev,
++				(struct adf_device_data __user *)arg);
++
++	case ADF_ATTACH:
++		return adf_device_handle_attachment(dev,
++				(struct adf_attachment_config __user *)arg,
++				true);
++
++	case ADF_DETACH:
++		return adf_device_handle_attachment(dev,
++				(struct adf_attachment_config __user *)arg,
++				false);
++
++	case ADF_BLANK:
++	case ADF_SET_MODE:
++	case ADF_GET_INTERFACE_DATA:
++	case ADF_GET_OVERLAY_ENGINE_DATA:
++	case ADF_SIMPLE_POST_CONFIG:
++	case ADF_SIMPLE_BUFFER_ALLOC:
++		return -EINVAL;
++
++	default:
++		return adf_obj_custom_ioctl(&dev->base, cmd, arg);
++	}
++}
++
++static int adf_file_open(struct inode *inode, struct file *file)
++{
++	struct adf_obj *obj;
++	struct adf_file *fpriv = NULL;
++	unsigned long flags;
++	int ret = 0;
++
++	obj = adf_obj_sysfs_find(iminor(inode));
++	if (!obj)
++		return -ENODEV;
++
++	dev_dbg(&obj->dev, "opening %s\n", dev_name(&obj->dev));
++
++	if (!try_module_get(obj->parent->ops->owner)) {
++		dev_err(&obj->dev, "getting owner module failed\n");
++		return -ENODEV;
++	}
++
++	fpriv = kzalloc(sizeof(*fpriv), GFP_KERNEL);
++	if (!fpriv) {
++		ret = -ENOMEM;
++		goto done;
++	}
++
++	INIT_LIST_HEAD(&fpriv->head);
++	fpriv->obj = obj;
++	init_waitqueue_head(&fpriv->event_wait);
++
++	file->private_data = fpriv;
++
++	if (obj->ops && obj->ops->open) {
++		ret = obj->ops->open(obj, inode, file);
++		if (ret < 0)
++			goto done;
++	}
++
++	spin_lock_irqsave(&obj->file_lock, flags);
++	list_add_tail(&fpriv->head, &obj->file_list);
++	spin_unlock_irqrestore(&obj->file_lock, flags);
++
++done:
++	if (ret < 0) {
++		kfree(fpriv);
++		module_put(obj->parent->ops->owner);
++	}
++	return ret;
++}
++
++static int adf_file_release(struct inode *inode, struct file *file)
++{
++	struct adf_file *fpriv = file->private_data;
++	struct adf_obj *obj = fpriv->obj;
++	enum adf_event_type event_type;
++	unsigned long flags;
++
++	if (obj->ops && obj->ops->release)
++		obj->ops->release(obj, inode, file);
++
++	spin_lock_irqsave(&obj->file_lock, flags);
++	list_del(&fpriv->head);
++	spin_unlock_irqrestore(&obj->file_lock, flags);
++
++	for_each_set_bit(event_type, fpriv->event_subscriptions,
++			ADF_EVENT_TYPE_MAX) {
++		adf_event_put(obj, event_type);
++	}
++
++	kfree(fpriv);
++	module_put(obj->parent->ops->owner);
++
++	dev_dbg(&obj->dev, "released %s\n", dev_name(&obj->dev));
++	return 0;
++}
++
++long adf_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
++{
++	struct adf_file *fpriv = file->private_data;
++	struct adf_obj *obj = fpriv->obj;
++	long ret = -EINVAL;
++
++	dev_dbg(&obj->dev, "%s ioctl %u\n", dev_name(&obj->dev), _IOC_NR(cmd));
++
++	switch (obj->type) {
++	case ADF_OBJ_OVERLAY_ENGINE:
++		ret = adf_overlay_engine_ioctl(adf_obj_to_overlay_engine(obj),
++				fpriv, cmd, arg);
++		break;
++
++	case ADF_OBJ_INTERFACE:
++		ret = adf_interface_ioctl(adf_obj_to_interface(obj), fpriv, cmd,
++				arg);
++		break;
++
++	case ADF_OBJ_DEVICE:
++		ret = adf_device_ioctl(adf_obj_to_device(obj), fpriv, cmd, arg);
++		break;
++	}
++
++	return ret;
++}
++
++static inline bool adf_file_event_available(struct adf_file *fpriv)
++{
++	int head = fpriv->event_head;
++	int tail = fpriv->event_tail;
++	return CIRC_CNT(head, tail, sizeof(fpriv->event_buf)) != 0;
++}
++
++void adf_file_queue_event(struct adf_file *fpriv, struct adf_event *event)
++{
++	int head = fpriv->event_head;
++	int tail = fpriv->event_tail;
++	size_t space = CIRC_SPACE(head, tail, sizeof(fpriv->event_buf));
++	size_t space_to_end =
++			CIRC_SPACE_TO_END(head, tail, sizeof(fpriv->event_buf));
++
++	if (space < event->length) {
++		dev_dbg(&fpriv->obj->dev,
++				"insufficient buffer space for event %u\n",
++				event->type);
++		return;
++	}
++
++	if (space_to_end >= event->length) {
++		memcpy(fpriv->event_buf + head, event, event->length);
++	} else {
++		memcpy(fpriv->event_buf + head, event, space_to_end);
++		memcpy(fpriv->event_buf, (u8 *)event + space_to_end,
++				event->length - space_to_end);
++	}
++
++	smp_wmb();
++	fpriv->event_head = (fpriv->event_head + event->length) &
++			(sizeof(fpriv->event_buf) - 1);
++	wake_up_interruptible_all(&fpriv->event_wait);
++}
++
++static ssize_t adf_file_copy_to_user(struct adf_file *fpriv,
++		char __user *buffer, size_t buffer_size)
++{
++	int head, tail;
++	u8 *event_buf;
++	size_t cnt, cnt_to_end, copy_size = 0;
++	ssize_t ret = 0;
++	unsigned long flags;
++
++	event_buf = kmalloc(min(buffer_size, sizeof(fpriv->event_buf)),
++			GFP_KERNEL);
++	if (!event_buf)
++		return -ENOMEM;
++
++	spin_lock_irqsave(&fpriv->obj->file_lock, flags);
++
++	if (!adf_file_event_available(fpriv))
++		goto out;
++
++	head = fpriv->event_head;
++	tail = fpriv->event_tail;
++
++	cnt = CIRC_CNT(head, tail, sizeof(fpriv->event_buf));
++	cnt_to_end = CIRC_CNT_TO_END(head, tail, sizeof(fpriv->event_buf));
++	copy_size = min(buffer_size, cnt);
++
++	if (cnt_to_end >= copy_size) {
++		memcpy(event_buf, fpriv->event_buf + tail, copy_size);
++	} else {
++		memcpy(event_buf, fpriv->event_buf + tail, cnt_to_end);
++		memcpy(event_buf + cnt_to_end, fpriv->event_buf,
++				copy_size - cnt_to_end);
++	}
++
++	fpriv->event_tail = (fpriv->event_tail + copy_size) &
++			(sizeof(fpriv->event_buf) - 1);
++
++out:
++	spin_unlock_irqrestore(&fpriv->obj->file_lock, flags);
++	if (copy_size) {
++		if (copy_to_user(buffer, event_buf, copy_size))
++			ret = -EFAULT;
++		else
++			ret = copy_size;
++	}
++	kfree(event_buf);
++	return ret;
++}
++
++ssize_t adf_file_read(struct file *filp, char __user *buffer,
++		 size_t count, loff_t *offset)
++{
++	struct adf_file *fpriv = filp->private_data;
++	int err;
++
++	err = wait_event_interruptible(fpriv->event_wait,
++			adf_file_event_available(fpriv));
++	if (err < 0)
++		return err;
++
++	return adf_file_copy_to_user(fpriv, buffer, count);
++}
++
++unsigned int adf_file_poll(struct file *filp, struct poll_table_struct *wait)
++{
++	struct adf_file *fpriv = filp->private_data;
++	unsigned int mask = 0;
++
++	poll_wait(filp, &fpriv->event_wait, wait);
++
++	if (adf_file_event_available(fpriv))
++		mask |= POLLIN | POLLRDNORM;
++
++	return mask;
++}
++
++const struct file_operations adf_fops = {
++	.owner = THIS_MODULE,
++	.unlocked_ioctl = adf_file_ioctl,
++#ifdef CONFIG_COMPAT
++	.compat_ioctl = adf_file_compat_ioctl,
++#endif
++	.open = adf_file_open,
++	.release = adf_file_release,
++	.llseek = default_llseek,
++	.read = adf_file_read,
++	.poll = adf_file_poll,
++};
+diff --git a/drivers/video/adf/adf_fops.h b/drivers/video/adf/adf_fops.h
+new file mode 100644
+index 0000000..90a3a74
+--- /dev/null
++++ b/drivers/video/adf/adf_fops.h
+@@ -0,0 +1,37 @@
++/*
++ * Copyright (C) 2013 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#ifndef __VIDEO_ADF_ADF_FOPS_H
++#define __VIDEO_ADF_ADF_FOPS_H
++
++#include <linux/bitmap.h>
++#include <linux/fs.h>
++
++extern const struct file_operations adf_fops;
++
++struct adf_file {
++	struct list_head head;
++	struct adf_obj *obj;
++
++	DECLARE_BITMAP(event_subscriptions, ADF_EVENT_TYPE_MAX);
++	u8 event_buf[4096];
++	int event_head;
++	int event_tail;
++	wait_queue_head_t event_wait;
++};
++
++void adf_file_queue_event(struct adf_file *file, struct adf_event *event);
++long adf_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
++
++#endif /* __VIDEO_ADF_ADF_FOPS_H */
+diff --git a/drivers/video/adf/adf_fops32.c b/drivers/video/adf/adf_fops32.c
+new file mode 100644
+index 0000000..d299a81
+--- /dev/null
++++ b/drivers/video/adf/adf_fops32.c
+@@ -0,0 +1,217 @@
++/*
++ * Copyright (C) 2013 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#include <linux/uaccess.h>
++#include <video/adf.h>
++
++#include "adf_fops.h"
++#include "adf_fops32.h"
++
++long adf_compat_post_config(struct file *file,
++		struct adf_post_config32 __user *arg)
++{
++	struct adf_post_config32 cfg32;
++	struct adf_post_config __user *cfg;
++	int ret;
++
++	if (copy_from_user(&cfg32, arg, sizeof(cfg32)))
++		return -EFAULT;
++
++	cfg = compat_alloc_user_space(sizeof(*cfg));
++	if (!access_ok(VERIFY_WRITE, cfg, sizeof(*cfg)))
++		return -EFAULT;
++
++	if (put_user(cfg32.n_interfaces, &cfg->n_interfaces) ||
++			put_user(compat_ptr(cfg32.interfaces),
++					&cfg->interfaces) ||
++			put_user(cfg32.n_bufs, &cfg->n_bufs) ||
++			put_user(compat_ptr(cfg32.bufs), &cfg->bufs) ||
++			put_user(cfg32.custom_data_size,
++					&cfg->custom_data_size) ||
++			put_user(compat_ptr(cfg32.custom_data),
++					&cfg->custom_data))
++		return -EFAULT;
++
++	ret = adf_file_ioctl(file, ADF_POST_CONFIG, (unsigned long)cfg);
++	if (ret < 0)
++		return ret;
++
++	if (copy_in_user(&arg->complete_fence, &cfg->complete_fence,
++			sizeof(cfg->complete_fence)))
++		return -EFAULT;
++
++	return 0;
++}
++
++long adf_compat_get_device_data(struct file *file,
++		struct adf_device_data32 __user *arg)
++{
++	struct adf_device_data32 data32;
++	struct adf_device_data __user *data;
++	int ret;
++
++	if (copy_from_user(&data32, arg, sizeof(data32)))
++		return -EFAULT;
++
++	data = compat_alloc_user_space(sizeof(*data));
++	if (!access_ok(VERIFY_WRITE, data, sizeof(*data)))
++		return -EFAULT;
++
++	if (put_user(data32.n_attachments, &data->n_attachments) ||
++			put_user(compat_ptr(data32.attachments),
++					&data->attachments) ||
++			put_user(data32.n_allowed_attachments,
++					&data->n_allowed_attachments) ||
++			put_user(compat_ptr(data32.allowed_attachments),
++					&data->allowed_attachments) ||
++			put_user(data32.custom_data_size,
++					&data->custom_data_size) ||
++			put_user(compat_ptr(data32.custom_data),
++					&data->custom_data))
++		return -EFAULT;
++
++	ret = adf_file_ioctl(file, ADF_GET_DEVICE_DATA, (unsigned long)data);
++	if (ret < 0)
++		return ret;
++
++	if (copy_in_user(arg->name, data->name, sizeof(arg->name)) ||
++			copy_in_user(&arg->n_attachments, &data->n_attachments,
++					sizeof(arg->n_attachments)) ||
++			copy_in_user(&arg->n_allowed_attachments,
++					&data->n_allowed_attachments,
++					sizeof(arg->n_allowed_attachments)) ||
++			copy_in_user(&arg->custom_data_size,
++					&data->custom_data_size,
++					sizeof(arg->custom_data_size)))
++		return -EFAULT;
++
++	return 0;
++}
++
++long adf_compat_get_interface_data(struct file *file,
++		struct adf_interface_data32 __user *arg)
++{
++	struct adf_interface_data32 data32;
++	struct adf_interface_data __user *data;
++	int ret;
++
++	if (copy_from_user(&data32, arg, sizeof(data32)))
++		return -EFAULT;
++
++	data = compat_alloc_user_space(sizeof(*data));
++	if (!access_ok(VERIFY_WRITE, data, sizeof(*data)))
++		return -EFAULT;
++
++	if (put_user(data32.n_available_modes, &data->n_available_modes) ||
++			put_user(compat_ptr(data32.available_modes),
++					&data->available_modes) ||
++			put_user(data32.custom_data_size,
++					&data->custom_data_size) ||
++			put_user(compat_ptr(data32.custom_data),
++					&data->custom_data))
++		return -EFAULT;
++
++	ret = adf_file_ioctl(file, ADF_GET_INTERFACE_DATA, (unsigned long)data);
++	if (ret < 0)
++		return ret;
++
++	if (copy_in_user(arg->name, data->name, sizeof(arg->name)) ||
++			copy_in_user(&arg->type, &data->type,
++					sizeof(arg->type)) ||
++			copy_in_user(&arg->id, &data->id, sizeof(arg->id)) ||
++			copy_in_user(&arg->flags, &data->flags,
++					sizeof(arg->flags)) ||
++			copy_in_user(&arg->dpms_state, &data->dpms_state,
++					sizeof(arg->dpms_state)) ||
++			copy_in_user(&arg->hotplug_detect,
++					&data->hotplug_detect,
++					sizeof(arg->hotplug_detect)) ||
++			copy_in_user(&arg->width_mm, &data->width_mm,
++					sizeof(arg->width_mm)) ||
++			copy_in_user(&arg->height_mm, &data->height_mm,
++					sizeof(arg->height_mm)) ||
++			copy_in_user(&arg->current_mode, &data->current_mode,
++					sizeof(arg->current_mode)) ||
++			copy_in_user(&arg->n_available_modes,
++					&data->n_available_modes,
++					sizeof(arg->n_available_modes)) ||
++			copy_in_user(&arg->custom_data_size,
++					&data->custom_data_size,
++					sizeof(arg->custom_data_size)))
++		return -EFAULT;
++
++	return 0;
++}
++
++long adf_compat_get_overlay_engine_data(struct file *file,
++		struct adf_overlay_engine_data32 __user *arg)
++{
++	struct adf_overlay_engine_data32 data32;
++	struct adf_overlay_engine_data __user *data;
++	int ret;
++
++	if (copy_from_user(&data32, arg, sizeof(data32)))
++		return -EFAULT;
++
++	data = compat_alloc_user_space(sizeof(*data));
++	if (!access_ok(VERIFY_WRITE, data, sizeof(*data)))
++		return -EFAULT;
++
++	if (put_user(data32.n_supported_formats, &data->n_supported_formats) ||
++			put_user(compat_ptr(data32.supported_formats),
++					&data->supported_formats) ||
++			put_user(data32.custom_data_size,
++					&data->custom_data_size) ||
++			put_user(compat_ptr(data32.custom_data),
++					&data->custom_data))
++		return -EFAULT;
++
++	ret = adf_file_ioctl(file, ADF_GET_OVERLAY_ENGINE_DATA,
++			(unsigned long)data);
++	if (ret < 0)
++		return ret;
++
++	if (copy_in_user(arg->name, data->name, sizeof(arg->name)) ||
++			copy_in_user(&arg->n_supported_formats,
++					&data->n_supported_formats,
++					sizeof(arg->n_supported_formats)) ||
++			copy_in_user(&arg->custom_data_size,
++					&data->custom_data_size,
++					sizeof(arg->custom_data_size)))
++		return -EFAULT;
++
++	return 0;
++}
++
++long adf_file_compat_ioctl(struct file *file, unsigned int cmd,
++		unsigned long arg)
++{
++	switch (cmd) {
++	case ADF_POST_CONFIG32:
++		return adf_compat_post_config(file, compat_ptr(arg));
++
++	case ADF_GET_DEVICE_DATA32:
++		return adf_compat_get_device_data(file, compat_ptr(arg));
++
++	case ADF_GET_INTERFACE_DATA32:
++		return adf_compat_get_interface_data(file, compat_ptr(arg));
++
++	case ADF_GET_OVERLAY_ENGINE_DATA32:
++		return adf_compat_get_overlay_engine_data(file,
++				compat_ptr(arg));
++
++	default:
++		return adf_file_ioctl(file, cmd, arg);
++	}
++}
+diff --git a/drivers/video/adf/adf_fops32.h b/drivers/video/adf/adf_fops32.h
+new file mode 100644
+index 0000000..64034ce
+--- /dev/null
++++ b/drivers/video/adf/adf_fops32.h
+@@ -0,0 +1,78 @@
++#ifndef __VIDEO_ADF_ADF_FOPS32_H
++#define __VIDEO_ADF_ADF_FOPS32_H
++
++#include <linux/compat.h>
++#include <linux/ioctl.h>
++
++#include <video/adf.h>
++
++#define ADF_POST_CONFIG32 \
++		_IOW(ADF_IOCTL_TYPE, 2, struct adf_post_config32)
++#define ADF_GET_DEVICE_DATA32 \
++		_IOR(ADF_IOCTL_TYPE, 4, struct adf_device_data32)
++#define ADF_GET_INTERFACE_DATA32 \
++		_IOR(ADF_IOCTL_TYPE, 5, struct adf_interface_data32)
++#define ADF_GET_OVERLAY_ENGINE_DATA32 \
++		_IOR(ADF_IOCTL_TYPE, 6, struct adf_overlay_engine_data32)
++
++struct adf_post_config32 {
++	compat_size_t n_interfaces;
++	compat_uptr_t interfaces;
++
++	compat_size_t n_bufs;
++	compat_uptr_t bufs;
++
++	compat_size_t custom_data_size;
++	compat_uptr_t custom_data;
++
++	__s32 complete_fence;
++};
++
++struct adf_device_data32 {
++	char name[ADF_NAME_LEN];
++
++	compat_size_t n_attachments;
++	compat_uptr_t attachments;
++
++	compat_size_t n_allowed_attachments;
++	compat_uptr_t allowed_attachments;
++
++	compat_size_t custom_data_size;
++	compat_uptr_t custom_data;
++};
++
++struct adf_interface_data32 {
++	char name[ADF_NAME_LEN];
++
++	__u8 type;
++	__u32 id;
++	/* e.g. type=ADF_INTF_TYPE_DSI, id=1 => DSI.1 */
++	__u32 flags;
++
++	__u8 dpms_state;
++	__u8 hotplug_detect;
++	__u16 width_mm;
++	__u16 height_mm;
++
++	struct drm_mode_modeinfo current_mode;
++	compat_size_t n_available_modes;
++	compat_uptr_t available_modes;
++
++	compat_size_t custom_data_size;
++	compat_uptr_t custom_data;
++};
++
++struct adf_overlay_engine_data32 {
++	char name[ADF_NAME_LEN];
++
++	compat_size_t n_supported_formats;
++	compat_uptr_t supported_formats;
++
++	compat_size_t custom_data_size;
++	compat_uptr_t custom_data;
++};
++
++long adf_file_compat_ioctl(struct file *file, unsigned int cmd,
++		unsigned long arg);
++
++#endif /* __VIDEO_ADF_ADF_FOPS32_H */
+diff --git a/drivers/video/adf/adf_format.c b/drivers/video/adf/adf_format.c
+new file mode 100644
+index 0000000..e3f22c7
+--- /dev/null
++++ b/drivers/video/adf/adf_format.c
+@@ -0,0 +1,280 @@
++/*
++ * Copyright (C) 2013 Google, Inc.
++ * modified from drivers/gpu/drm/drm_crtc.c
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#include <linux/export.h>
++#include <linux/kernel.h>
++#include <drm/drm_fourcc.h>
++#include <video/adf_format.h>
++
++bool adf_format_is_standard(u32 format)
++{
++	switch (format) {
++	case DRM_FORMAT_C8:
++	case DRM_FORMAT_RGB332:
++	case DRM_FORMAT_BGR233:
++	case DRM_FORMAT_XRGB4444:
++	case DRM_FORMAT_XBGR4444:
++	case DRM_FORMAT_RGBX4444:
++	case DRM_FORMAT_BGRX4444:
++	case DRM_FORMAT_ARGB4444:
++	case DRM_FORMAT_ABGR4444:
++	case DRM_FORMAT_RGBA4444:
++	case DRM_FORMAT_BGRA4444:
++	case DRM_FORMAT_XRGB1555:
++	case DRM_FORMAT_XBGR1555:
++	case DRM_FORMAT_RGBX5551:
++	case DRM_FORMAT_BGRX5551:
++	case DRM_FORMAT_ARGB1555:
++	case DRM_FORMAT_ABGR1555:
++	case DRM_FORMAT_RGBA5551:
++	case DRM_FORMAT_BGRA5551:
++	case DRM_FORMAT_RGB565:
++	case DRM_FORMAT_BGR565:
++	case DRM_FORMAT_RGB888:
++	case DRM_FORMAT_BGR888:
++	case DRM_FORMAT_XRGB8888:
++	case DRM_FORMAT_XBGR8888:
++	case DRM_FORMAT_RGBX8888:
++	case DRM_FORMAT_BGRX8888:
++	case DRM_FORMAT_ARGB8888:
++	case DRM_FORMAT_ABGR8888:
++	case DRM_FORMAT_RGBA8888:
++	case DRM_FORMAT_BGRA8888:
++	case DRM_FORMAT_XRGB2101010:
++	case DRM_FORMAT_XBGR2101010:
++	case DRM_FORMAT_RGBX1010102:
++	case DRM_FORMAT_BGRX1010102:
++	case DRM_FORMAT_ARGB2101010:
++	case DRM_FORMAT_ABGR2101010:
++	case DRM_FORMAT_RGBA1010102:
++	case DRM_FORMAT_BGRA1010102:
++	case DRM_FORMAT_YUYV:
++	case DRM_FORMAT_YVYU:
++	case DRM_FORMAT_UYVY:
++	case DRM_FORMAT_VYUY:
++	case DRM_FORMAT_AYUV:
++	case DRM_FORMAT_NV12:
++	case DRM_FORMAT_NV21:
++	case DRM_FORMAT_NV16:
++	case DRM_FORMAT_NV61:
++	case DRM_FORMAT_YUV410:
++	case DRM_FORMAT_YVU410:
++	case DRM_FORMAT_YUV411:
++	case DRM_FORMAT_YVU411:
++	case DRM_FORMAT_YUV420:
++	case DRM_FORMAT_YVU420:
++	case DRM_FORMAT_YUV422:
++	case DRM_FORMAT_YVU422:
++	case DRM_FORMAT_YUV444:
++	case DRM_FORMAT_YVU444:
++		return true;
++	default:
++		return false;
++	}
++}
++EXPORT_SYMBOL(adf_format_is_standard);
++
++bool adf_format_is_rgb(u32 format)
++{
++	switch (format) {
++	case DRM_FORMAT_C8:
++	case DRM_FORMAT_RGB332:
++	case DRM_FORMAT_BGR233:
++	case DRM_FORMAT_XRGB1555:
++	case DRM_FORMAT_XBGR1555:
++	case DRM_FORMAT_RGBX5551:
++	case DRM_FORMAT_BGRX5551:
++	case DRM_FORMAT_ARGB1555:
++	case DRM_FORMAT_ABGR1555:
++	case DRM_FORMAT_RGBA5551:
++	case DRM_FORMAT_BGRA5551:
++	case DRM_FORMAT_RGB565:
++	case DRM_FORMAT_BGR565:
++	case DRM_FORMAT_RGB888:
++	case DRM_FORMAT_BGR888:
++	case DRM_FORMAT_XRGB8888:
++	case DRM_FORMAT_XBGR8888:
++	case DRM_FORMAT_RGBX8888:
++	case DRM_FORMAT_BGRX8888:
++	case DRM_FORMAT_XRGB2101010:
++	case DRM_FORMAT_XBGR2101010:
++	case DRM_FORMAT_RGBX1010102:
++	case DRM_FORMAT_BGRX1010102:
++	case DRM_FORMAT_ARGB2101010:
++	case DRM_FORMAT_ABGR2101010:
++	case DRM_FORMAT_RGBA1010102:
++	case DRM_FORMAT_BGRA1010102:
++	case DRM_FORMAT_ARGB8888:
++	case DRM_FORMAT_ABGR8888:
++	case DRM_FORMAT_RGBA8888:
++	case DRM_FORMAT_BGRA8888:
++		return true;
++
++	default:
++		return false;
++	}
++}
++EXPORT_SYMBOL(adf_format_is_rgb);
++
++u8 adf_format_num_planes(u32 format)
++{
++	switch (format) {
++	case DRM_FORMAT_YUV410:
++	case DRM_FORMAT_YVU410:
++	case DRM_FORMAT_YUV411:
++	case DRM_FORMAT_YVU411:
++	case DRM_FORMAT_YUV420:
++	case DRM_FORMAT_YVU420:
++	case DRM_FORMAT_YUV422:
++	case DRM_FORMAT_YVU422:
++	case DRM_FORMAT_YUV444:
++	case DRM_FORMAT_YVU444:
++		return 3;
++	case DRM_FORMAT_NV12:
++	case DRM_FORMAT_NV21:
++	case DRM_FORMAT_NV16:
++	case DRM_FORMAT_NV61:
++		return 2;
++	default:
++		return 1;
++	}
++}
++EXPORT_SYMBOL(adf_format_num_planes);
++
++u8 adf_format_bpp(u32 format)
++{
++	switch (format) {
++	case DRM_FORMAT_C8:
++	case DRM_FORMAT_RGB332:
++	case DRM_FORMAT_BGR233:
++		return 8;
++
++	case DRM_FORMAT_XRGB1555:
++	case DRM_FORMAT_XBGR1555:
++	case DRM_FORMAT_RGBX5551:
++	case DRM_FORMAT_BGRX5551:
++	case DRM_FORMAT_ARGB1555:
++	case DRM_FORMAT_ABGR1555:
++	case DRM_FORMAT_RGBA5551:
++	case DRM_FORMAT_BGRA5551:
++	case DRM_FORMAT_RGB565:
++	case DRM_FORMAT_BGR565:
++		return 16;
++
++	case DRM_FORMAT_RGB888:
++	case DRM_FORMAT_BGR888:
++		return 24;
++
++	case DRM_FORMAT_XRGB8888:
++	case DRM_FORMAT_XBGR8888:
++	case DRM_FORMAT_RGBX8888:
++	case DRM_FORMAT_BGRX8888:
++	case DRM_FORMAT_XRGB2101010:
++	case DRM_FORMAT_XBGR2101010:
++	case DRM_FORMAT_RGBX1010102:
++	case DRM_FORMAT_BGRX1010102:
++	case DRM_FORMAT_ARGB2101010:
++	case DRM_FORMAT_ABGR2101010:
++	case DRM_FORMAT_RGBA1010102:
++	case DRM_FORMAT_BGRA1010102:
++	case DRM_FORMAT_ARGB8888:
++	case DRM_FORMAT_ABGR8888:
++	case DRM_FORMAT_RGBA8888:
++	case DRM_FORMAT_BGRA8888:
++		return 32;
++
++	default:
++		pr_debug("%s: unsupported pixel format %u\n", __func__, format);
++		return 0;
++	}
++}
++EXPORT_SYMBOL(adf_format_bpp);
++
++u8 adf_format_plane_cpp(u32 format, int plane)
++{
++	if (plane >= adf_format_num_planes(format))
++		return 0;
++
++	switch (format) {
++	case DRM_FORMAT_YUYV:
++	case DRM_FORMAT_YVYU:
++	case DRM_FORMAT_UYVY:
++	case DRM_FORMAT_VYUY:
++		return 2;
++	case DRM_FORMAT_NV12:
++	case DRM_FORMAT_NV21:
++	case DRM_FORMAT_NV16:
++	case DRM_FORMAT_NV61:
++		return plane ? 2 : 1;
++	case DRM_FORMAT_YUV410:
++	case DRM_FORMAT_YVU410:
++	case DRM_FORMAT_YUV411:
++	case DRM_FORMAT_YVU411:
++	case DRM_FORMAT_YUV420:
++	case DRM_FORMAT_YVU420:
++	case DRM_FORMAT_YUV422:
++	case DRM_FORMAT_YVU422:
++	case DRM_FORMAT_YUV444:
++	case DRM_FORMAT_YVU444:
++		return 1;
++	default:
++		return adf_format_bpp(format) / 8;
++	}
++}
++EXPORT_SYMBOL(adf_format_plane_cpp);
++
++u8 adf_format_horz_chroma_subsampling(u32 format)
++{
++	switch (format) {
++	case DRM_FORMAT_YUV411:
++	case DRM_FORMAT_YVU411:
++	case DRM_FORMAT_YUV410:
++	case DRM_FORMAT_YVU410:
++		return 4;
++	case DRM_FORMAT_YUYV:
++	case DRM_FORMAT_YVYU:
++	case DRM_FORMAT_UYVY:
++	case DRM_FORMAT_VYUY:
++	case DRM_FORMAT_NV12:
++	case DRM_FORMAT_NV21:
++	case DRM_FORMAT_NV16:
++	case DRM_FORMAT_NV61:
++	case DRM_FORMAT_YUV422:
++	case DRM_FORMAT_YVU422:
++	case DRM_FORMAT_YUV420:
++	case DRM_FORMAT_YVU420:
++		return 2;
++	default:
++		return 1;
++	}
++}
++EXPORT_SYMBOL(adf_format_horz_chroma_subsampling);
++
++u8 adf_format_vert_chroma_subsampling(u32 format)
++{
++	switch (format) {
++	case DRM_FORMAT_YUV410:
++	case DRM_FORMAT_YVU410:
++		return 4;
++	case DRM_FORMAT_YUV420:
++	case DRM_FORMAT_YVU420:
++	case DRM_FORMAT_NV12:
++	case DRM_FORMAT_NV21:
++		return 2;
++	default:
++		return 1;
++	}
++}
++EXPORT_SYMBOL(adf_format_vert_chroma_subsampling);
+diff --git a/drivers/video/adf/adf_memblock.c b/drivers/video/adf/adf_memblock.c
+new file mode 100644
+index 0000000..ab583f8
+--- /dev/null
++++ b/drivers/video/adf/adf_memblock.c
+@@ -0,0 +1,160 @@
++/*
++ * Copyright (C) 2013 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#include <linux/dma-buf.h>
++#include <linux/highmem.h>
++#include <linux/memblock.h>
++#include <linux/slab.h>
++
++struct adf_memblock_pdata {
++	phys_addr_t base;
++};
++
++static struct sg_table *adf_memblock_map(struct dma_buf_attachment *attach,
++		enum dma_data_direction direction)
++{
++	struct adf_memblock_pdata *pdata = attach->dmabuf->priv;
++	unsigned long pfn = PFN_DOWN(pdata->base);
++	struct page *page = pfn_to_page(pfn);
++	struct sg_table *table;
++	int nents, ret;
++
++	table = kzalloc(sizeof(*table), GFP_KERNEL);
++	if (!table)
++		return ERR_PTR(-ENOMEM);
++
++	ret = sg_alloc_table(table, 1, GFP_KERNEL);
++	if (ret < 0)
++		goto err_alloc;
++
++	sg_set_page(table->sgl, page, attach->dmabuf->size, 0);
++
++	nents = dma_map_sg(attach->dev, table->sgl, 1, direction);
++	if (!nents) {
++		ret = -EINVAL;
++		goto err_map;
++	}
++
++	return table;
++
++err_map:
++	sg_free_table(table);
++err_alloc:
++	kfree(table);
++	return ERR_PTR(ret);
++}
++
++static void adf_memblock_unmap(struct dma_buf_attachment *attach,
++		struct sg_table *table, enum dma_data_direction direction)
++{
++	dma_unmap_sg(attach->dev, table->sgl, 1, direction);
++	sg_free_table(table);
++}
++
++static void __init_memblock adf_memblock_release(struct dma_buf *buf)
++{
++	struct adf_memblock_pdata *pdata = buf->priv;
++	int err = memblock_free(pdata->base, buf->size);
++
++	if (err < 0)
++		pr_warn("%s: freeing memblock failed: %d\n", __func__, err);
++	kfree(pdata);
++}
++
++static void *adf_memblock_do_kmap(struct dma_buf *buf, unsigned long pgoffset,
++		bool atomic)
++{
++	struct adf_memblock_pdata *pdata = buf->priv;
++	unsigned long pfn = PFN_DOWN(pdata->base) + pgoffset;
++	struct page *page = pfn_to_page(pfn);
++
++	if (atomic)
++		return kmap_atomic(page);
++	else
++		return kmap(page);
++}
++
++static void *adf_memblock_kmap_atomic(struct dma_buf *buf,
++		unsigned long pgoffset)
++{
++	return adf_memblock_do_kmap(buf, pgoffset, true);
++}
++
++static void adf_memblock_kunmap_atomic(struct dma_buf *buf,
++		unsigned long pgoffset, void *vaddr)
++{
++	kunmap_atomic(vaddr);
++}
++
++static void *adf_memblock_kmap(struct dma_buf *buf, unsigned long pgoffset)
++{
++	return adf_memblock_do_kmap(buf, pgoffset, false);
++}
++
++static void adf_memblock_kunmap(struct dma_buf *buf, unsigned long pgoffset,
++		void *vaddr)
++{
++	kunmap(vaddr);
++}
++
++static int adf_memblock_mmap(struct dma_buf *buf, struct vm_area_struct *vma)
++{
++	struct adf_memblock_pdata *pdata = buf->priv;
++
++	return remap_pfn_range(vma, vma->vm_start, PFN_DOWN(pdata->base),
++			vma->vm_end - vma->vm_start, vma->vm_page_prot);
++}
++
++struct dma_buf_ops adf_memblock_ops = {
++	.map_dma_buf = adf_memblock_map,
++	.unmap_dma_buf = adf_memblock_unmap,
++	.release = adf_memblock_release,
++	.kmap_atomic = adf_memblock_kmap_atomic,
++	.kunmap_atomic = adf_memblock_kunmap_atomic,
++	.kmap = adf_memblock_kmap,
++	.kunmap = adf_memblock_kunmap,
++	.mmap = adf_memblock_mmap,
++};
++
++/**
++ * adf_memblock_export - export a memblock reserved area as a dma-buf
++ *
++ * @base: base physical address
++ * @size: memblock size
++ * @flags: mode flags for the dma-buf's file
++ *
++ * @base and @size must be page-aligned.
++ *
++ * Returns a dma-buf on success or ERR_PTR(-errno) on failure.
++ */
++struct dma_buf *adf_memblock_export(phys_addr_t base, size_t size, int flags)
++{
++	struct adf_memblock_pdata *pdata;
++	struct dma_buf *buf;
++
++	if (PAGE_ALIGN(base) != base || PAGE_ALIGN(size) != size)
++		return ERR_PTR(-EINVAL);
++
++	pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
++	if (!pdata)
++		return ERR_PTR(-ENOMEM);
++
++	pdata->base = base;
++	buf = dma_buf_export(pdata, &adf_memblock_ops, size, flags, NULL);
++	if (IS_ERR(buf))
++		kfree(pdata);
++
++	return buf;
++}
++EXPORT_SYMBOL(adf_memblock_export);
+diff --git a/drivers/video/adf/adf_sysfs.c b/drivers/video/adf/adf_sysfs.c
+new file mode 100644
+index 0000000..8c659c7
+--- /dev/null
++++ b/drivers/video/adf/adf_sysfs.c
+@@ -0,0 +1,296 @@
++/*
++ * Copyright (C) 2013 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#include <video/adf_client.h>
++
++#include "adf.h"
++#include "adf_fops.h"
++#include "adf_sysfs.h"
++
++static struct class *adf_class;
++static int adf_major;
++static DEFINE_IDR(adf_minors);
++
++#define dev_to_adf_interface(p) \
++	adf_obj_to_interface(container_of(p, struct adf_obj, dev))
++
++static ssize_t dpms_state_show(struct device *dev,
++		struct device_attribute *attr, char *buf)
++{
++	struct adf_interface *intf = dev_to_adf_interface(dev);
++	return scnprintf(buf, PAGE_SIZE, "%u\n",
++			adf_interface_dpms_state(intf));
++}
++
++static ssize_t dpms_state_store(struct device *dev,
++		struct device_attribute *attr, const char *buf, size_t count)
++{
++	struct adf_interface *intf = dev_to_adf_interface(dev);
++	u8 dpms_state;
++	int err;
++
++	err = kstrtou8(buf, 0, &dpms_state);
++	if (err < 0)
++		return err;
++
++	err = adf_interface_blank(intf, dpms_state);
++	if (err < 0)
++		return err;
++
++	return count;
++}
++
++static ssize_t current_mode_show(struct device *dev,
++		struct device_attribute *attr, char *buf)
++{
++	struct adf_interface *intf = dev_to_adf_interface(dev);
++	struct drm_mode_modeinfo mode;
++
++	adf_interface_current_mode(intf, &mode);
++
++	if (mode.name[0]) {
++		return scnprintf(buf, PAGE_SIZE, "%s\n", mode.name);
++	} else {
++		bool interlaced = !!(mode.flags & DRM_MODE_FLAG_INTERLACE);
++		return scnprintf(buf, PAGE_SIZE, "%ux%u%s\n", mode.hdisplay,
++				mode.vdisplay, interlaced ? "i" : "");
++	}
++}
++
++static ssize_t type_show(struct device *dev, struct device_attribute *attr,
++			char *buf)
++{
++	struct adf_interface *intf = dev_to_adf_interface(dev);
++	return scnprintf(buf, PAGE_SIZE, "%s\n",
++			adf_interface_type_str(intf));
++}
++
++static ssize_t vsync_timestamp_show(struct device *dev,
++		struct device_attribute *attr, char *buf)
++{
++	struct adf_interface *intf = dev_to_adf_interface(dev);
++	ktime_t timestamp;
++	unsigned long flags;
++
++	read_lock_irqsave(&intf->vsync_lock, flags);
++	memcpy(&timestamp, &intf->vsync_timestamp, sizeof(timestamp));
++	read_unlock_irqrestore(&intf->vsync_lock, flags);
++
++	return scnprintf(buf, PAGE_SIZE, "%llu\n", ktime_to_ns(timestamp));
++}
++
++static ssize_t hotplug_detect_show(struct device *dev,
++		struct device_attribute *attr, char *buf)
++{
++	struct adf_interface *intf = dev_to_adf_interface(dev);
++	return scnprintf(buf, PAGE_SIZE, "%u\n", intf->hotplug_detect);
++}
++
++static struct device_attribute adf_interface_attrs[] = {
++	__ATTR(dpms_state, S_IRUGO|S_IWUSR, dpms_state_show, dpms_state_store),
++	__ATTR_RO(current_mode),
++	__ATTR_RO(hotplug_detect),
++	__ATTR_RO(type),
++	__ATTR_RO(vsync_timestamp),
++};
++
++int adf_obj_sysfs_init(struct adf_obj *obj, struct device *parent)
++{
++	int ret = idr_alloc(&adf_minors, obj, 0, 0, GFP_KERNEL);
++	if (ret < 0) {
++		pr_err("%s: allocating adf minor failed: %d\n", __func__,
++				ret);
++		return ret;
++	}
++
++	obj->minor = ret;
++	obj->dev.parent = parent;
++	obj->dev.class = adf_class;
++	obj->dev.devt = MKDEV(adf_major, obj->minor);
++
++	ret = device_register(&obj->dev);
++	if (ret < 0) {
++		pr_err("%s: registering adf object failed: %d\n", __func__,
++				ret);
++		goto err_device_register;
++	}
++
++	return 0;
++
++err_device_register:
++	idr_remove(&adf_minors, obj->minor);
++	return ret;
++}
++
++static char *adf_device_devnode(struct device *dev, umode_t *mode,
++		kuid_t *uid, kgid_t *gid)
++{
++	struct adf_obj *obj = container_of(dev, struct adf_obj, dev);
++	return kasprintf(GFP_KERNEL, "adf%d", obj->id);
++}
++
++static char *adf_interface_devnode(struct device *dev, umode_t *mode,
++		kuid_t *uid, kgid_t *gid)
++{
++	struct adf_obj *obj = container_of(dev, struct adf_obj, dev);
++	struct adf_interface *intf = adf_obj_to_interface(obj);
++	struct adf_device *parent = adf_interface_parent(intf);
++	return kasprintf(GFP_KERNEL, "adf-interface%d.%d",
++			parent->base.id, intf->base.id);
++}
++
++static char *adf_overlay_engine_devnode(struct device *dev, umode_t *mode,
++		kuid_t *uid, kgid_t *gid)
++{
++	struct adf_obj *obj = container_of(dev, struct adf_obj, dev);
++	struct adf_overlay_engine *eng = adf_obj_to_overlay_engine(obj);
++	struct adf_device *parent = adf_overlay_engine_parent(eng);
++	return kasprintf(GFP_KERNEL, "adf-overlay-engine%d.%d",
++			parent->base.id, eng->base.id);
++}
++
++static void adf_noop_release(struct device *dev)
++{
++}
++
++static struct device_type adf_device_type = {
++	.name = "adf_device",
++	.devnode = adf_device_devnode,
++	.release = adf_noop_release,
++};
++
++static struct device_type adf_interface_type = {
++	.name = "adf_interface",
++	.devnode = adf_interface_devnode,
++	.release = adf_noop_release,
++};
++
++static struct device_type adf_overlay_engine_type = {
++	.name = "adf_overlay_engine",
++	.devnode = adf_overlay_engine_devnode,
++	.release = adf_noop_release,
++};
++
++int adf_device_sysfs_init(struct adf_device *dev)
++{
++	dev->base.dev.type = &adf_device_type;
++	dev_set_name(&dev->base.dev, "%s", dev->base.name);
++	return adf_obj_sysfs_init(&dev->base, dev->dev);
++}
++
++int adf_interface_sysfs_init(struct adf_interface *intf)
++{
++	struct adf_device *parent = adf_interface_parent(intf);
++	size_t i, j;
++	int ret;
++
++	intf->base.dev.type = &adf_interface_type;
++	dev_set_name(&intf->base.dev, "%s-interface%d", parent->base.name,
++			intf->base.id);
++
++	ret = adf_obj_sysfs_init(&intf->base, &parent->base.dev);
++	if (ret < 0)
++		return ret;
++
++	for (i = 0; i < ARRAY_SIZE(adf_interface_attrs); i++) {
++		ret = device_create_file(&intf->base.dev,
++				&adf_interface_attrs[i]);
++		if (ret < 0) {
++			dev_err(&intf->base.dev, "creating sysfs attribute %s failed: %d\n",
++					adf_interface_attrs[i].attr.name, ret);
++			goto err;
++		}
++	}
++
++	return 0;
++
++err:
++	for (j = 0; j < i; j++)
++		device_remove_file(&intf->base.dev, &adf_interface_attrs[j]);
++	return ret;
++}
++
++int adf_overlay_engine_sysfs_init(struct adf_overlay_engine *eng)
++{
++	struct adf_device *parent = adf_overlay_engine_parent(eng);
++
++	eng->base.dev.type = &adf_overlay_engine_type;
++	dev_set_name(&eng->base.dev, "%s-overlay-engine%d", parent->base.name,
++			eng->base.id);
++
++	return adf_obj_sysfs_init(&eng->base, &parent->base.dev);
++}
++
++struct adf_obj *adf_obj_sysfs_find(int minor)
++{
++	return idr_find(&adf_minors, minor);
++}
++
++void adf_obj_sysfs_destroy(struct adf_obj *obj)
++{
++	idr_remove(&adf_minors, obj->minor);
++	device_unregister(&obj->dev);
++}
++
++void adf_device_sysfs_destroy(struct adf_device *dev)
++{
++	adf_obj_sysfs_destroy(&dev->base);
++}
++
++void adf_interface_sysfs_destroy(struct adf_interface *intf)
++{
++	size_t i;
++
++	for (i = 0; i < ARRAY_SIZE(adf_interface_attrs); i++)
++		device_remove_file(&intf->base.dev, &adf_interface_attrs[i]);
++	adf_obj_sysfs_destroy(&intf->base);
++}
++
++void adf_overlay_engine_sysfs_destroy(struct adf_overlay_engine *eng)
++{
++	adf_obj_sysfs_destroy(&eng->base);
++}
++
++int adf_sysfs_init(void)
++{
++	struct class *class;
++	int ret;
++
++	class = class_create(THIS_MODULE, "adf");
++	if (IS_ERR(class)) {
++		ret = PTR_ERR(class);
++		pr_err("%s: creating class failed: %d\n", __func__, ret);
++		return ret;
++	}
++
++	ret = register_chrdev(0, "adf", &adf_fops);
++	if (ret < 0) {
++		pr_err("%s: registering device failed: %d\n", __func__, ret);
++		goto err_chrdev;
++	}
++
++	adf_class = class;
++	adf_major = ret;
++	return 0;
++
++err_chrdev:
++	class_destroy(adf_class);
++	return ret;
++}
++
++void adf_sysfs_destroy(void)
++{
++	idr_destroy(&adf_minors);
++	class_destroy(adf_class);
++}
+diff --git a/drivers/video/adf/adf_sysfs.h b/drivers/video/adf/adf_sysfs.h
+new file mode 100644
+index 0000000..0613ac3
+--- /dev/null
++++ b/drivers/video/adf/adf_sysfs.h
+@@ -0,0 +1,33 @@
++/*
++ * Copyright (C) 2013 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#ifndef __VIDEO_ADF_ADF_SYSFS_H
++#define __VIDEO_ADF_ADF_SYSFS_H
++
++struct adf_device;
++struct adf_interface;
++struct adf_overlay_engine;
++
++int adf_device_sysfs_init(struct adf_device *dev);
++void adf_device_sysfs_destroy(struct adf_device *dev);
++int adf_interface_sysfs_init(struct adf_interface *intf);
++void adf_interface_sysfs_destroy(struct adf_interface *intf);
++int adf_overlay_engine_sysfs_init(struct adf_overlay_engine *eng);
++void adf_overlay_engine_sysfs_destroy(struct adf_overlay_engine *eng);
++struct adf_obj *adf_obj_sysfs_find(int minor);
++
++int adf_sysfs_init(void);
++void adf_sysfs_destroy(void);
++
++#endif /* __VIDEO_ADF_ADF_SYSFS_H */
+diff --git a/drivers/video/adf/adf_trace.h b/drivers/video/adf/adf_trace.h
+new file mode 100644
+index 0000000..3cb2a84
+--- /dev/null
++++ b/drivers/video/adf/adf_trace.h
+@@ -0,0 +1,93 @@
++/*
++ * Copyright (C) 2013 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * 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.
++ *
++ */
++
++#undef TRACE_SYSTEM
++#define TRACE_SYSTEM adf
++
++#if !defined(__VIDEO_ADF_ADF_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
++#define __VIDEO_ADF_ADF_TRACE_H
++
++#include <linux/tracepoint.h>
++#include <video/adf.h>
++
++TRACE_EVENT(adf_event,
++	TP_PROTO(struct adf_obj *obj, enum adf_event_type type),
++	TP_ARGS(obj, type),
++
++	TP_STRUCT__entry(
++		__string(name, obj->name)
++		__field(enum adf_event_type, type)
++		__array(char, type_str, 32)
++	),
++	TP_fast_assign(
++		__assign_str(name, obj->name);
++		__entry->type = type;
++		strlcpy(__entry->type_str, adf_event_type_str(obj, type),
++				sizeof(__entry->type_str));
++	),
++	TP_printk("obj=%s type=%u (%s)",
++			__get_str(name),
++			__entry->type,
++			__entry->type_str)
++);
++
++TRACE_EVENT(adf_event_enable,
++	TP_PROTO(struct adf_obj *obj, enum adf_event_type type),
++	TP_ARGS(obj, type),
++
++	TP_STRUCT__entry(
++		__string(name, obj->name)
++		__field(enum adf_event_type, type)
++		__array(char, type_str, 32)
++	),
++	TP_fast_assign(
++		__assign_str(name, obj->name);
++		__entry->type = type;
++		strlcpy(__entry->type_str, adf_event_type_str(obj, type),
++				sizeof(__entry->type_str));
++	),
++	TP_printk("obj=%s type=%u (%s)",
++			__get_str(name),
++			__entry->type,
++			__entry->type_str)
++);
++
++TRACE_EVENT(adf_event_disable,
++	TP_PROTO(struct adf_obj *obj, enum adf_event_type type),
++	TP_ARGS(obj, type),
++
++	TP_STRUCT__entry(
++		__string(name, obj->name)
++		__field(enum adf_event_type, type)
++		__array(char, type_str, 32)
++	),
++	TP_fast_assign(
++		__assign_str(name, obj->name);
++		__entry->type = type;
++		strlcpy(__entry->type_str, adf_event_type_str(obj, type),
++				sizeof(__entry->type_str));
++	),
++	TP_printk("obj=%s type=%u (%s)",
++			__get_str(name),
++			__entry->type,
++			__entry->type_str)
++);
++
++#endif /* __VIDEO_ADF_ADF_TRACE_H */
++
++#undef TRACE_INCLUDE_PATH
++#undef TRACE_INCLUDE_FILE
++#define TRACE_INCLUDE_PATH .
++#define TRACE_INCLUDE_FILE adf_trace
++#include <trace/define_trace.h>
+diff --git a/drivers/w1/masters/ds2482.c b/drivers/w1/masters/ds2482.c
+index e76a9b3..5e505d4 100644
+--- a/drivers/w1/masters/ds2482.c
++++ b/drivers/w1/masters/ds2482.c
+@@ -18,6 +18,8 @@
+ #include <linux/slab.h>
+ #include <linux/i2c.h>
+ #include <linux/delay.h>
++#include <linux/gpio.h>
++#include <linux/platform_data/ds2482.h>
+ #include <asm/delay.h>
+ 
+ #include "../w1.h"
+@@ -84,7 +86,8 @@ static const u8 ds2482_chan_rd[8] =
+ static int ds2482_probe(struct i2c_client *client,
+ 			const struct i2c_device_id *id);
+ static int ds2482_remove(struct i2c_client *client);
+-
++static int ds2482_suspend(struct device *dev);
++static int ds2482_resume(struct device *dev);
+ 
+ /**
+  * Driver data (common to all clients)
+@@ -94,10 +97,16 @@ static const struct i2c_device_id ds2482_id[] = {
+ 	{ }
+ };
+ 
++static const struct dev_pm_ops ds2482_pm_ops = {
++	.suspend = ds2482_suspend,
++	.resume = ds2482_resume,
++};
++
+ static struct i2c_driver ds2482_driver = {
+ 	.driver = {
+ 		.owner	= THIS_MODULE,
+ 		.name	= "ds2482",
++		.pm = &ds2482_pm_ops,
+ 	},
+ 	.probe		= ds2482_probe,
+ 	.remove		= ds2482_remove,
+@@ -119,6 +128,7 @@ struct ds2482_w1_chan {
+ struct ds2482_data {
+ 	struct i2c_client	*client;
+ 	struct mutex		access_lock;
++	int			slpz_gpio;
+ 
+ 	/* 1-wire interface(s) */
+ 	int			w1_count;	/* 1 or 8 */
+@@ -444,11 +454,31 @@ static u8 ds2482_w1_set_pullup(void *data, int delay)
+ 	return retval;
+ }
+ 
++static int ds2482_suspend(struct device *dev)
++{
++	struct i2c_client *client = to_i2c_client(dev);
++	struct ds2482_data *data = i2c_get_clientdata(client);
++
++	if (data->slpz_gpio >= 0)
++		gpio_set_value(data->slpz_gpio, 0);
++	return 0;
++}
++
++static int ds2482_resume(struct device *dev)
++{
++	struct i2c_client *client = to_i2c_client(dev);
++	struct ds2482_data *data = i2c_get_clientdata(client);
++
++	if (data->slpz_gpio >= 0)
++		gpio_set_value(data->slpz_gpio, 1);
++	return 0;
++}
+ 
+ static int ds2482_probe(struct i2c_client *client,
+ 			const struct i2c_device_id *id)
+ {
+ 	struct ds2482_data *data;
++	struct ds2482_platform_data *pdata;
+ 	int err = -ENODEV;
+ 	int temp1;
+ 	int idx;
+@@ -515,6 +545,16 @@ static int ds2482_probe(struct i2c_client *client,
+ 		}
+ 	}
+ 
++	pdata = client->dev.platform_data;
++	data->slpz_gpio = pdata ? pdata->slpz_gpio : -1;
++
++	if (data->slpz_gpio >= 0) {
++		err = gpio_request_one(data->slpz_gpio, GPIOF_OUT_INIT_HIGH,
++				       "ds2482.slpz");
++		if (err < 0)
++			goto exit_w1_remove;
++	}
++
+ 	return 0;
+ 
+ exit_w1_remove:
+@@ -539,6 +579,11 @@ static int ds2482_remove(struct i2c_client *client)
+ 			w1_remove_master_device(&data->w1_ch[idx].w1_bm);
+ 	}
+ 
++	if (data->slpz_gpio >= 0) {
++		gpio_set_value(data->slpz_gpio, 0);
++		gpio_free(data->slpz_gpio);
++	}
++
+ 	/* Free the memory */
+ 	kfree(data);
+ 	return 0;
+diff --git a/fs/9p/acl.c b/fs/9p/acl.c
+index 8482f2d..d3f5d48 100644
+--- a/fs/9p/acl.c
++++ b/fs/9p/acl.c
+@@ -320,32 +320,26 @@ static int v9fs_xattr_set_acl(struct dentry *dentry, const char *name,
+ 	case ACL_TYPE_ACCESS:
+ 		name = POSIX_ACL_XATTR_ACCESS;
+ 		if (acl) {
+-			umode_t mode = inode->i_mode;
+-			retval = posix_acl_equiv_mode(acl, &mode);
+-			if (retval < 0)
++			struct iattr iattr;
++
++			retval = posix_acl_update_mode(inode, &iattr.ia_mode, &acl);
++			if (retval)
+ 				goto err_out;
+-			else {
+-				struct iattr iattr;
+-				if (retval == 0) {
+-					/*
+-					 * ACL can be represented
+-					 * by the mode bits. So don't
+-					 * update ACL.
+-					 */
+-					acl = NULL;
+-					value = NULL;
+-					size = 0;
+-				}
+-				/* Updte the mode bits */
+-				iattr.ia_mode = ((mode & S_IALLUGO) |
+-						 (inode->i_mode & ~S_IALLUGO));
+-				iattr.ia_valid = ATTR_MODE;
+-				/* FIXME should we update ctime ?
+-				 * What is the following setxattr update the
+-				 * mode ?
++			if (!acl) {
++				/*
++				 * ACL can be represented
++				 * by the mode bits. So don't
++				 * update ACL.
+ 				 */
+-				v9fs_vfs_setattr_dotl(dentry, &iattr);
++				value = NULL;
++				size = 0;
+ 			}
++			iattr.ia_valid = ATTR_MODE;
++			/* FIXME should we update ctime ?
++			 * What is the following setxattr update the
++			 * mode ?
++			 */
++			v9fs_vfs_setattr_dotl(dentry, &iattr);
+ 		}
+ 		break;
+ 	case ACL_TYPE_DEFAULT:
+diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
+index a2f6e9a..2cec576 100644
+--- a/fs/9p/vfs_inode.c
++++ b/fs/9p/vfs_inode.c
+@@ -1129,6 +1129,10 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
+ 	if (S_ISREG(dentry->d_inode->i_mode))
+ 		filemap_write_and_wait(dentry->d_inode->i_mapping);
+ 
++	retval = setattr_killpriv(dentry, iattr);
++	if (retval)
++		return retval;
++
+ 	retval = p9_client_wstat(fid, &wstat);
+ 	if (retval < 0)
+ 		return retval;
+diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c
+index 092d20c..3ab6527 100644
+--- a/fs/9p/vfs_inode_dotl.c
++++ b/fs/9p/vfs_inode_dotl.c
+@@ -582,6 +582,10 @@ int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr)
+ 	if (S_ISREG(inode->i_mode))
+ 		filemap_write_and_wait(inode->i_mapping);
+ 
++	retval = setattr_killpriv(dentry, iattr);
++	if (retval)
++		return retval;
++
+ 	retval = p9_client_setattr(fid, &p9attr);
+ 	if (retval < 0)
+ 		return retval;
+diff --git a/fs/Kconfig b/fs/Kconfig
+index 664991a..6ccbee1 100644
+--- a/fs/Kconfig
++++ b/fs/Kconfig
+@@ -191,6 +191,7 @@ source "fs/hfsplus/Kconfig"
+ source "fs/befs/Kconfig"
+ source "fs/bfs/Kconfig"
+ source "fs/efs/Kconfig"
++source "fs/yaffs2/Kconfig"
+ source "fs/jffs2/Kconfig"
+ # UBIFS File system configuration
+ source "fs/ubifs/Kconfig"
+diff --git a/fs/Makefile b/fs/Makefile
+index da0bbb4..4b5887c 100644
+--- a/fs/Makefile
++++ b/fs/Makefile
+@@ -126,3 +126,4 @@ obj-y				+= exofs/ # Multiple modules
+ obj-$(CONFIG_CEPH_FS)		+= ceph/
+ obj-$(CONFIG_PSTORE)		+= pstore/
+ obj-$(CONFIG_EFIVAR_FS)		+= efivarfs/
++obj-$(CONFIG_YAFFS_FS)		+= yaffs2/
+diff --git a/fs/aio.c b/fs/aio.c
+index 58caa7e..41e6a77 100644
+--- a/fs/aio.c
++++ b/fs/aio.c
+@@ -1325,7 +1325,8 @@ static ssize_t aio_setup_vectored_rw(struct kiocb *kiocb,
+ 				     int rw, char __user *buf,
+ 				     unsigned long *nr_segs,
+ 				     struct iovec **iovec,
+-				     bool compat)
++				     bool compat,
++				     struct iov_iter *iter)
+ {
+ 	ssize_t ret;
+ 
+@@ -1346,20 +1347,26 @@ static ssize_t aio_setup_vectored_rw(struct kiocb *kiocb,
+ 
+ 	/* ki_nbytes now reflect bytes instead of segs */
+ 	kiocb->ki_nbytes = ret;
++	iov_iter_init(iter, rw, *iovec, *nr_segs, kiocb->ki_nbytes);
+ 	return 0;
+ }
+ 
+ static ssize_t aio_setup_single_vector(struct kiocb *kiocb,
+ 				       int rw, char __user *buf,
+ 				       unsigned long *nr_segs,
+-				       struct iovec *iovec)
++				       struct iovec *iovec,
++				       struct iov_iter *iter)
+ {
++	if (kiocb->ki_nbytes > MAX_RW_COUNT)
++		kiocb->ki_nbytes = MAX_RW_COUNT;
++
+ 	if (unlikely(!access_ok(!rw, buf, kiocb->ki_nbytes)))
+ 		return -EFAULT;
+ 
+ 	iovec->iov_base = buf;
+ 	iovec->iov_len = kiocb->ki_nbytes;
+ 	*nr_segs = 1;
++	iov_iter_init(iter, rw, iovec, *nr_segs, kiocb->ki_nbytes);
+ 	return 0;
+ }
+ 
+@@ -1406,9 +1413,9 @@ rw_common:
+ 		ret = (opcode == IOCB_CMD_PREADV ||
+ 		       opcode == IOCB_CMD_PWRITEV)
+ 			? aio_setup_vectored_rw(req, rw, buf, &nr_segs,
+-						&iovec, compat)
++						&iovec, compat, &iter)
+ 			: aio_setup_single_vector(req, rw, buf, &nr_segs,
+-						  iovec);
++						  iovec, &iter);
+ 		if (!ret)
+ 			ret = rw_verify_area(rw, file, &req->ki_pos, req->ki_nbytes);
+ 		if (ret < 0) {
+@@ -1430,10 +1437,9 @@ rw_common:
+ 			file_start_write(file);
+ 
+ 		if (iter_op) {
+-			iov_iter_init(&iter, rw, iovec, nr_segs, req->ki_nbytes);
+ 			ret = iter_op(req, &iter);
+ 		} else {
+-			ret = rw_op(req, iovec, nr_segs, req->ki_pos);
++			ret = rw_op(req, iter.iov, iter.nr_segs, req->ki_pos);
+ 		}
+ 
+ 		if (rw == WRITE)
+diff --git a/fs/attr.c b/fs/attr.c
+index 6530ced..2052234 100644
+--- a/fs/attr.c
++++ b/fs/attr.c
+@@ -167,6 +167,28 @@ void setattr_copy(struct inode *inode, const struct iattr *attr)
+ }
+ EXPORT_SYMBOL(setattr_copy);
+ 
++ /**
++  * setattr_killpriv - remove extended privilege attributes from a file
++  * @dentry: Directory entry passed to the setattr operation
++  * @iattr: New attributes pased to the setattr operation
++  *
++  * All filesystems that can carry extended privilege attributes
++  * should call this from their setattr operation *after* validating
++  * the attribute changes.
++  *
++  * It does nothing if !(iattr->ia_valid & ATTR_KILL_PRIV), so
++  * it is not necessary to call it in that case.
++  */
++int setattr_killpriv(struct dentry *dentry, struct iattr *iattr)
++{
++	if (!(iattr->ia_valid & ATTR_KILL_PRIV))
++		return 0;
++
++	iattr->ia_valid &= ~ATTR_KILL_PRIV;
++	return security_inode_killpriv(dentry);
++}
++EXPORT_SYMBOL(setattr_killpriv);
++
+ /**
+  * notify_change - modify attributes of a filesytem object
+  * @dentry:	object affected
+@@ -217,13 +239,13 @@ int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **de
+ 	if (!(ia_valid & ATTR_MTIME_SET))
+ 		attr->ia_mtime = now;
+ 	if (ia_valid & ATTR_KILL_PRIV) {
+-		attr->ia_valid &= ~ATTR_KILL_PRIV;
+-		ia_valid &= ~ATTR_KILL_PRIV;
+ 		error = security_inode_need_killpriv(dentry);
+-		if (error > 0)
+-			error = security_inode_killpriv(dentry);
+-		if (error)
++		if (error < 0)
+ 			return error;
++		if (error == 0) {
++			attr->ia_valid &= ~ATTR_KILL_PRIV;
++			ia_valid &= ~ATTR_KILL_PRIV;
++		}
+ 	}
+ 
+ 	/*
+diff --git a/fs/btrfs/acl.c b/fs/btrfs/acl.c
+index 9a0124a..fb3e64d 100644
+--- a/fs/btrfs/acl.c
++++ b/fs/btrfs/acl.c
+@@ -83,11 +83,9 @@ static int __btrfs_set_acl(struct btrfs_trans_handle *trans,
+ 	case ACL_TYPE_ACCESS:
+ 		name = POSIX_ACL_XATTR_ACCESS;
+ 		if (acl) {
+-			ret = posix_acl_equiv_mode(acl, &inode->i_mode);
+-			if (ret < 0)
++			ret = posix_acl_update_mode(inode, &inode->i_mode, &acl);
++			if (ret)
+ 				return ret;
+-			if (ret == 0)
+-				acl = NULL;
+ 		}
+ 		ret = 0;
+ 		break;
+diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
+index edaa617..793419c 100644
+--- a/fs/btrfs/inode.c
++++ b/fs/btrfs/inode.c
+@@ -4697,6 +4697,10 @@ static int btrfs_setattr(struct dentry *dentry, struct iattr *attr)
+ 	if (err)
+ 		return err;
+ 
++	err = setattr_killpriv(dentry, attr);
++	if (err)
++		return err;
++
+ 	if (S_ISREG(inode->i_mode) && (attr->ia_valid & ATTR_SIZE)) {
+ 		err = btrfs_setsize(inode, attr);
+ 		if (err)
+diff --git a/fs/ceph/acl.c b/fs/ceph/acl.c
+index 5bd853b..6a4a3e2 100644
+--- a/fs/ceph/acl.c
++++ b/fs/ceph/acl.c
+@@ -108,11 +108,9 @@ int ceph_set_acl(struct inode *inode, struct posix_acl *acl, int type)
+ 	case ACL_TYPE_ACCESS:
+ 		name = POSIX_ACL_XATTR_ACCESS;
+ 		if (acl) {
+-			ret = posix_acl_equiv_mode(acl, &new_mode);
+-			if (ret < 0)
++			ret = posix_acl_update_mode(inode, &new_mode, &acl);
++			if (ret)
+ 				goto out;
+-			if (ret == 0)
+-				acl = NULL;
+ 		}
+ 		break;
+ 	case ACL_TYPE_DEFAULT:
+diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c
+index 7a1df90..b0e9198 100644
+--- a/fs/ceph/inode.c
++++ b/fs/ceph/inode.c
+@@ -1712,6 +1712,10 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr)
+ 	if (err != 0)
+ 		return err;
+ 
++	err = setattr_killpriv(dentry, attr);
++	if (err != 0)
++		return err;
++
+ 	req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_SETATTR,
+ 				       USE_AUTH_MDS);
+ 	if (IS_ERR(req))
+diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
+index 0c3ce46..0eba18c 100644
+--- a/fs/cifs/inode.c
++++ b/fs/cifs/inode.c
+@@ -2151,6 +2151,10 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
+ 	mapping_set_error(inode->i_mapping, rc);
+ 	rc = 0;
+ 
++	rc = setattr_killpriv(direntry, attrs);
++	if (rc)
++		goto out;
++
+ 	if (attrs->ia_valid & ATTR_SIZE) {
+ 		rc = cifs_set_file_size(inode, attrs, xid, full_path);
+ 		if (rc != 0)
+@@ -2273,6 +2277,12 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
+ 		return rc;
+ 	}
+ 
++	rc = setattr_killpriv(direntry, attrs);
++	if (rc) {
++		free_xid(xid);
++		return rc;
++	}
++
+ 	full_path = build_path_from_dentry(direntry);
+ 	if (full_path == NULL) {
+ 		rc = -ENOMEM;
+diff --git a/fs/dcache.c b/fs/dcache.c
+index d0539a4..2ffac07 100644
+--- a/fs/dcache.c
++++ b/fs/dcache.c
+@@ -2886,6 +2886,13 @@ restart:
+ 
+ 		if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
+ 			struct mount *parent = ACCESS_ONCE(mnt->mnt_parent);
++			/* Escaped? */
++			if (dentry != vfsmnt->mnt_root) {
++				bptr = *buffer;
++				blen = *buflen;
++				error = 3;
++				break;
++			}
+ 			/* Global root? */
+ 			if (mnt != parent) {
+ 				dentry = ACCESS_ONCE(mnt->mnt_mountpoint);
+diff --git a/fs/eventpoll.c b/fs/eventpoll.c
+index 7bcfff9..1c6bba7 100644
+--- a/fs/eventpoll.c
++++ b/fs/eventpoll.c
+@@ -34,6 +34,7 @@
+ #include <linux/mutex.h>
+ #include <linux/anon_inodes.h>
+ #include <linux/device.h>
++#include <linux/freezer.h>
+ #include <asm/uaccess.h>
+ #include <asm/io.h>
+ #include <asm/mman.h>
+@@ -1637,7 +1638,8 @@ fetch_events:
+ 			}
+ 
+ 			spin_unlock_irqrestore(&ep->lock, flags);
+-			if (!schedule_hrtimeout_range(to, slack, HRTIMER_MODE_ABS))
++			if (!freezable_schedule_hrtimeout_range(to, slack,
++								HRTIMER_MODE_ABS))
+ 				timed_out = 1;
+ 
+ 			spin_lock_irqsave(&ep->lock, flags);
+diff --git a/fs/exec.c b/fs/exec.c
+index b7a5f46..969c650 100644
+--- a/fs/exec.c
++++ b/fs/exec.c
+@@ -199,11 +199,21 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
+ 
+ 	if (write) {
+ 		unsigned long size = bprm->vma->vm_end - bprm->vma->vm_start;
++		unsigned long ptr_size;
+ 		struct rlimit *rlim;
+ 
+ 		acct_arg_size(bprm, size / PAGE_SIZE);
+ 
+ 		/*
++		 * Since the stack will hold pointers to the strings, we
++		 * must account for them as well.
++		 */
++		ptr_size = (bprm->argc + bprm->envc) * sizeof(void *);
++		if (ptr_size > ULONG_MAX - size)
++			goto fail;
++		size += ptr_size;
++
++		/*
+ 		 * We've historically supported up to 32 pages (ARG_MAX)
+ 		 * of argument strings even with small stacks
+ 		 */
+@@ -218,13 +228,15 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
+ 		 *    to work from.
+ 		 */
+ 		rlim = current->signal->rlim;
+-		if (size > ACCESS_ONCE(rlim[RLIMIT_STACK].rlim_cur) / 4) {
+-			put_page(page);
+-			return NULL;
+-		}
++		if (size > READ_ONCE(rlim[RLIMIT_STACK].rlim_cur) / 4)
++			goto fail;
+ 	}
+ 
+ 	return page;
++
++fail:
++	put_page(page);
++	return NULL;
+ }
+ 
+ static void put_arg_page(struct page *page)
+diff --git a/fs/ext2/acl.c b/fs/ext2/acl.c
+index 27695e6..d6aeb84 100644
+--- a/fs/ext2/acl.c
++++ b/fs/ext2/acl.c
+@@ -193,15 +193,11 @@ ext2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
+ 		case ACL_TYPE_ACCESS:
+ 			name_index = EXT2_XATTR_INDEX_POSIX_ACL_ACCESS;
+ 			if (acl) {
+-				error = posix_acl_equiv_mode(acl, &inode->i_mode);
+-				if (error < 0)
++				error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
++				if (error)
+ 					return error;
+-				else {
+-					inode->i_ctime = CURRENT_TIME_SEC;
+-					mark_inode_dirty(inode);
+-					if (error == 0)
+-						acl = NULL;
+-				}
++				inode->i_ctime = CURRENT_TIME_SEC;
++				mark_inode_dirty(inode);
+ 			}
+ 			break;
+ 
+diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
+index 36d35c3..9e245af 100644
+--- a/fs/ext2/inode.c
++++ b/fs/ext2/inode.c
+@@ -1551,6 +1551,10 @@ int ext2_setattr(struct dentry *dentry, struct iattr *iattr)
+ 	if (error)
+ 		return error;
+ 
++	error = setattr_killpriv(dentry, iattr);
++	if (error)
++		return error;
++
+ 	if (is_quota_modification(inode, iattr))
+ 		dquot_initialize(inode);
+ 	if ((iattr->ia_valid & ATTR_UID && !uid_eq(iattr->ia_uid, inode->i_uid)) ||
+diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
+index 2c6ccc4..ec4dffa 100644
+--- a/fs/ext3/inode.c
++++ b/fs/ext3/inode.c
+@@ -3248,6 +3248,10 @@ int ext3_setattr(struct dentry *dentry, struct iattr *attr)
+ 	if (error)
+ 		return error;
+ 
++	error = setattr_killpriv(dentry, attr);
++	if (error)
++		return error;
++
+ 	if (is_quota_modification(inode, attr))
+ 		dquot_initialize(inode);
+ 	if ((ia_valid & ATTR_UID && !uid_eq(attr->ia_uid, inode->i_uid)) ||
+diff --git a/fs/ext4/acl.c b/fs/ext4/acl.c
+index d40c8db..87d9bbf 100644
+--- a/fs/ext4/acl.c
++++ b/fs/ext4/acl.c
+@@ -201,15 +201,11 @@ __ext4_set_acl(handle_t *handle, struct inode *inode, int type,
+ 	case ACL_TYPE_ACCESS:
+ 		name_index = EXT4_XATTR_INDEX_POSIX_ACL_ACCESS;
+ 		if (acl) {
+-			error = posix_acl_equiv_mode(acl, &inode->i_mode);
+-			if (error < 0)
++			error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
++			if (error)
+ 				return error;
+-			else {
+-				inode->i_ctime = ext4_current_time(inode);
+-				ext4_mark_inode_dirty(handle, inode);
+-				if (error == 0)
+-					acl = NULL;
+-			}
++			inode->i_ctime = ext4_current_time(inode);
++			ext4_mark_inode_dirty(handle, inode);
+ 		}
+ 		break;
+ 
+diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
+index c55a1fa..a2f4422 100644
+--- a/fs/ext4/ext4.h
++++ b/fs/ext4/ext4.h
+@@ -2085,7 +2085,8 @@ extern int ext4_mb_add_groupinfo(struct super_block *sb,
+ 		ext4_group_t i, struct ext4_group_desc *desc);
+ extern int ext4_group_add_blocks(handle_t *handle, struct super_block *sb,
+ 				ext4_fsblk_t block, unsigned long count);
+-extern int ext4_trim_fs(struct super_block *, struct fstrim_range *);
++extern int ext4_trim_fs(struct super_block *, struct fstrim_range *,
++				unsigned long blkdev_flags);
+ 
+ /* inode.c */
+ struct buffer_head *ext4_getblk(handle_t *, struct inode *, ext4_lblk_t, int);
+diff --git a/fs/ext4/ext4_jbd2.c b/fs/ext4/ext4_jbd2.c
+index d418431..e770c1e 100644
+--- a/fs/ext4/ext4_jbd2.c
++++ b/fs/ext4/ext4_jbd2.c
+@@ -88,13 +88,13 @@ int __ext4_journal_stop(const char *where, unsigned int line, handle_t *handle)
+ 		return 0;
+ 	}
+ 
++	err = handle->h_err;
+ 	if (!handle->h_transaction) {
+-		err = jbd2_journal_stop(handle);
+-		return handle->h_err ? handle->h_err : err;
++		rc = jbd2_journal_stop(handle);
++		return err ? err : rc;
+ 	}
+ 
+ 	sb = handle->h_transaction->t_journal->j_private;
+-	err = handle->h_err;
+ 	rc = jbd2_journal_stop(handle);
+ 
+ 	if (!err)
+diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
+index b5fcb1a..c56f72f 100644
+--- a/fs/ext4/extents.c
++++ b/fs/ext4/extents.c
+@@ -4792,12 +4792,6 @@ static long ext4_zero_range(struct file *file, loff_t offset,
+ 	else
+ 		max_blocks -= lblk;
+ 
+-	flags = EXT4_GET_BLOCKS_CREATE_UNWRIT_EXT |
+-		EXT4_GET_BLOCKS_CONVERT_UNWRITTEN |
+-		EXT4_EX_NOCACHE;
+-	if (mode & FALLOC_FL_KEEP_SIZE)
+-		flags |= EXT4_GET_BLOCKS_KEEP_SIZE;
+-
+ 	mutex_lock(&inode->i_mutex);
+ 
+ 	/*
+@@ -4814,15 +4808,28 @@ static long ext4_zero_range(struct file *file, loff_t offset,
+ 		ret = inode_newsize_ok(inode, new_size);
+ 		if (ret)
+ 			goto out_mutex;
+-		/*
+-		 * If we have a partial block after EOF we have to allocate
+-		 * the entire block.
+-		 */
+-		if (partial_end)
+-			max_blocks += 1;
+ 	}
+ 
++	flags = EXT4_GET_BLOCKS_CREATE_UNWRIT_EXT;
++	if (mode & FALLOC_FL_KEEP_SIZE)
++		flags |= EXT4_GET_BLOCKS_KEEP_SIZE;
++
++	/* Preallocate the range including the unaligned edges */
++	if (partial_begin || partial_end) {
++		ret = ext4_alloc_file_blocks(file,
++				round_down(offset, 1 << blkbits) >> blkbits,
++				(round_up((offset + len), 1 << blkbits) -
++				 round_down(offset, 1 << blkbits)) >> blkbits,
++				new_size, flags, mode);
++		if (ret)
++			goto out_mutex;
++
++	}
++
++	/* Zero range excluding the unaligned edges */
+ 	if (max_blocks > 0) {
++		flags |= (EXT4_GET_BLOCKS_CONVERT_UNWRITTEN |
++				EXT4_EX_NOCACHE);
+ 
+ 		/* Now release the pages and zero block aligned part of pages*/
+ 		truncate_pagecache_range(inode, start, end - 1);
+diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
+index 777f743..fc46254 100644
+--- a/fs/ext4/inode.c
++++ b/fs/ext4/inode.c
+@@ -4481,6 +4481,10 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
+ 	if (error)
+ 		return error;
+ 
++	error = setattr_killpriv(dentry, attr);
++	if (error)
++		return error;
++
+ 	if (is_quota_modification(inode, attr))
+ 		dquot_initialize(inode);
+ 	if ((ia_valid & ATTR_UID && !uid_eq(attr->ia_uid, inode->i_uid)) ||
+diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c
+index bfda18a..e75462a 100644
+--- a/fs/ext4/ioctl.c
++++ b/fs/ext4/ioctl.c
+@@ -587,11 +587,13 @@ resizefs_out:
+ 		return err;
+ 	}
+ 
++	case FIDTRIM:
+ 	case FITRIM:
+ 	{
+ 		struct request_queue *q = bdev_get_queue(sb->s_bdev);
+ 		struct fstrim_range range;
+ 		int ret = 0;
++		int flags  = cmd == FIDTRIM ? BLKDEV_DISCARD_SECURE : 0;
+ 
+ 		if (!capable(CAP_SYS_ADMIN))
+ 			return -EPERM;
+@@ -599,13 +601,15 @@ resizefs_out:
+ 		if (!blk_queue_discard(q))
+ 			return -EOPNOTSUPP;
+ 
++		if ((flags & BLKDEV_DISCARD_SECURE) && !blk_queue_secdiscard(q))
++			return -EOPNOTSUPP;
+ 		if (copy_from_user(&range, (struct fstrim_range __user *)arg,
+ 		    sizeof(range)))
+ 			return -EFAULT;
+ 
+ 		range.minlen = max((unsigned int)range.minlen,
+ 				   q->limits.discard_granularity);
+-		ret = ext4_trim_fs(sb, &range);
++		ret = ext4_trim_fs(sb, &range, flags);
+ 		if (ret < 0)
+ 			return ret;
+ 
+diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
+index 99c8e38..07b13c1 100644
+--- a/fs/ext4/mballoc.c
++++ b/fs/ext4/mballoc.c
+@@ -2744,7 +2744,8 @@ int ext4_mb_release(struct super_block *sb)
+ }
+ 
+ static inline int ext4_issue_discard(struct super_block *sb,
+-		ext4_group_t block_group, ext4_grpblk_t cluster, int count)
++		ext4_group_t block_group, ext4_grpblk_t cluster, int count,
++		unsigned long flags)
+ {
+ 	ext4_fsblk_t discard_block;
+ 
+@@ -2753,7 +2754,7 @@ static inline int ext4_issue_discard(struct super_block *sb,
+ 	count = EXT4_C2B(EXT4_SB(sb), count);
+ 	trace_ext4_discard_blocks(sb,
+ 			(unsigned long long) discard_block, count);
+-	return sb_issue_discard(sb, discard_block, count, GFP_NOFS, 0);
++	return sb_issue_discard(sb, discard_block, count, GFP_NOFS, flags);
+ }
+ 
+ /*
+@@ -2775,7 +2776,7 @@ static void ext4_free_data_callback(struct super_block *sb,
+ 	if (test_opt(sb, DISCARD)) {
+ 		err = ext4_issue_discard(sb, entry->efd_group,
+ 					 entry->efd_start_cluster,
+-					 entry->efd_count);
++					 entry->efd_count, 0);
+ 		if (err && err != -EOPNOTSUPP)
+ 			ext4_msg(sb, KERN_WARNING, "discard request in"
+ 				 " group:%d block:%d count:%d failed"
+@@ -4821,7 +4822,8 @@ do_more:
+ 		 * them with group lock_held
+ 		 */
+ 		if (test_opt(sb, DISCARD)) {
+-			err = ext4_issue_discard(sb, block_group, bit, count);
++			err = ext4_issue_discard(sb, block_group, bit, count,
++						 0);
+ 			if (err && err != -EOPNOTSUPP)
+ 				ext4_msg(sb, KERN_WARNING, "discard request in"
+ 					 " group:%d block:%d count:%lu failed"
+@@ -5016,13 +5018,15 @@ error_return:
+  * @count:	number of blocks to TRIM
+  * @group:	alloc. group we are working with
+  * @e4b:	ext4 buddy for the group
++ * @blkdev_flags: flags for the block device
+  *
+  * Trim "count" blocks starting at "start" in the "group". To assure that no
+  * one will allocate those blocks, mark it as used in buddy bitmap. This must
+  * be called with under the group lock.
+  */
+ static int ext4_trim_extent(struct super_block *sb, int start, int count,
+-			     ext4_group_t group, struct ext4_buddy *e4b)
++			    ext4_group_t group, struct ext4_buddy *e4b,
++			    unsigned long blkdev_flags)
+ __releases(bitlock)
+ __acquires(bitlock)
+ {
+@@ -5043,7 +5047,7 @@ __acquires(bitlock)
+ 	 */
+ 	mb_mark_used(e4b, &ex);
+ 	ext4_unlock_group(sb, group);
+-	ret = ext4_issue_discard(sb, group, start, count);
++	ret = ext4_issue_discard(sb, group, start, count, blkdev_flags);
+ 	ext4_lock_group(sb, group);
+ 	mb_free_blocks(NULL, e4b, start, ex.fe_len);
+ 	return ret;
+@@ -5056,6 +5060,7 @@ __acquires(bitlock)
+  * @start:		first group block to examine
+  * @max:		last group block to examine
+  * @minblocks:		minimum extent block count
++ * @blkdev_flags:	flags for the block device
+  *
+  * ext4_trim_all_free walks through group's buddy bitmap searching for free
+  * extents. When the free block is found, ext4_trim_extent is called to TRIM
+@@ -5070,7 +5075,7 @@ __acquires(bitlock)
+ static ext4_grpblk_t
+ ext4_trim_all_free(struct super_block *sb, ext4_group_t group,
+ 		   ext4_grpblk_t start, ext4_grpblk_t max,
+-		   ext4_grpblk_t minblocks)
++		   ext4_grpblk_t minblocks, unsigned long blkdev_flags)
+ {
+ 	void *bitmap;
+ 	ext4_grpblk_t next, count = 0, free_count = 0;
+@@ -5103,7 +5108,8 @@ ext4_trim_all_free(struct super_block *sb, ext4_group_t group,
+ 
+ 		if ((next - start) >= minblocks) {
+ 			ret = ext4_trim_extent(sb, start,
+-					       next - start, group, &e4b);
++					       next - start, group, &e4b,
++					       blkdev_flags);
+ 			if (ret && ret != -EOPNOTSUPP)
+ 				break;
+ 			ret = 0;
+@@ -5145,6 +5151,7 @@ out:
+  * ext4_trim_fs() -- trim ioctl handle function
+  * @sb:			superblock for filesystem
+  * @range:		fstrim_range structure
++ * @blkdev_flags:	flags for the block device
+  *
+  * start:	First Byte to trim
+  * len:		number of Bytes to trim from start
+@@ -5153,7 +5160,8 @@ out:
+  * start to start+len. For each such a group ext4_trim_all_free function
+  * is invoked to trim all free space.
+  */
+-int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range)
++int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range,
++			unsigned long blkdev_flags)
+ {
+ 	struct ext4_group_info *grp;
+ 	ext4_group_t group, first_group, last_group;
+@@ -5209,7 +5217,7 @@ int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range)
+ 
+ 		if (grp->bb_free >= minlen) {
+ 			cnt = ext4_trim_all_free(sb, group, first_cluster,
+-						end, minlen);
++						end, minlen, blkdev_flags);
+ 			if (cnt < 0) {
+ 				ret = cnt;
+ 				break;
+diff --git a/fs/ext4/super.c b/fs/ext4/super.c
+index bf03846..86dc226 100644
+--- a/fs/ext4/super.c
++++ b/fs/ext4/super.c
+@@ -304,6 +304,8 @@ static void __save_error_info(struct super_block *sb, const char *func,
+ 	struct ext4_super_block *es = EXT4_SB(sb)->s_es;
+ 
+ 	EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS;
++	if (bdev_read_only(sb->s_bdev))
++		return;
+ 	es->s_state |= cpu_to_le16(EXT4_ERROR_FS);
+ 	es->s_last_error_time = cpu_to_le32(get_seconds());
+ 	strncpy(es->s_last_error_func, func, sizeof(es->s_last_error_func));
+diff --git a/fs/f2fs/acl.c b/fs/f2fs/acl.c
+index 83b9b5a..f12d5c5 100644
+--- a/fs/f2fs/acl.c
++++ b/fs/f2fs/acl.c
+@@ -207,12 +207,10 @@ static int __f2fs_set_acl(struct inode *inode, int 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)
++			error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
++			if (error)
+ 				return error;
+ 			set_acl_inode(fi, inode->i_mode);
+-			if (error == 0)
+-				acl = NULL;
+ 		}
+ 		break;
+ 
+diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
+index 8e68bb6..c9371d2 100644
+--- a/fs/f2fs/file.c
++++ b/fs/f2fs/file.c
+@@ -560,6 +560,10 @@ int f2fs_setattr(struct dentry *dentry, struct iattr *attr)
+ 	if (err)
+ 		return err;
+ 
++	err = setattr_killpriv(dentry, attr);
++	if (err)
++		return err;
++
+ 	if (attr->ia_valid & ATTR_SIZE) {
+ 		err = f2fs_convert_inline_data(inode, attr->ia_size, NULL);
+ 		if (err)
+diff --git a/fs/fat/cache.c b/fs/fat/cache.c
+index 91ad9e1..5d38492 100644
+--- a/fs/fat/cache.c
++++ b/fs/fat/cache.c
+@@ -8,9 +8,7 @@
+  *  May 1999. AV. Fixed the bogosity with FAT32 (read "FAT28"). Fscking lusers.
+  */
+ 
+-#include <linux/fs.h>
+ #include <linux/slab.h>
+-#include <linux/buffer_head.h>
+ #include "fat.h"
+ 
+ /* this must be > 0. */
+@@ -303,15 +301,59 @@ static int fat_bmap_cluster(struct inode *inode, int cluster)
+ 	return dclus;
+ }
+ 
+-int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys,
+-	     unsigned long *mapped_blocks, int create)
++int fat_get_mapped_cluster(struct inode *inode, sector_t sector,
++			   sector_t last_block,
++			   unsigned long *mapped_blocks, sector_t *bmap)
+ {
+ 	struct super_block *sb = inode->i_sb;
+ 	struct msdos_sb_info *sbi = MSDOS_SB(sb);
++	int cluster, offset;
++
++	cluster = sector >> (sbi->cluster_bits - sb->s_blocksize_bits);
++	offset  = sector & (sbi->sec_per_clus - 1);
++	cluster = fat_bmap_cluster(inode, cluster);
++	if (cluster < 0)
++		return cluster;
++	else if (cluster) {
++		*bmap = fat_clus_to_blknr(sbi, cluster) + offset;
++		*mapped_blocks = sbi->sec_per_clus - offset;
++		if (*mapped_blocks > last_block - sector)
++			*mapped_blocks = last_block - sector;
++	}
++
++	return 0;
++}
++
++static int is_exceed_eof(struct inode *inode, sector_t sector,
++			 sector_t *last_block, int create)
++{
++	struct super_block *sb = inode->i_sb;
+ 	const unsigned long blocksize = sb->s_blocksize;
+ 	const unsigned char blocksize_bits = sb->s_blocksize_bits;
++
++	*last_block = (i_size_read(inode) + (blocksize - 1)) >> blocksize_bits;
++	if (sector >= *last_block) {
++		if (!create)
++			return 1;
++
++		/*
++		 * ->mmu_private can access on only allocation path.
++		 * (caller must hold ->i_mutex)
++		 */
++		*last_block = (MSDOS_I(inode)->mmu_private + (blocksize - 1))
++			>> blocksize_bits;
++		if (sector >= *last_block)
++			return 1;
++	}
++
++	return 0;
++}
++
++int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys,
++	     unsigned long *mapped_blocks, int create, bool from_bmap)
++{
++	struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
+ 	sector_t last_block;
+-	int cluster, offset;
+ 
+ 	*phys = 0;
+ 	*mapped_blocks = 0;
+@@ -323,31 +365,16 @@ int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys,
+ 		return 0;
+ 	}
+ 
+-	last_block = (i_size_read(inode) + (blocksize - 1)) >> blocksize_bits;
+-	if (sector >= last_block) {
+-		if (!create)
++	if (!from_bmap) {
++		if (is_exceed_eof(inode, sector, &last_block, create))
+ 			return 0;
+-
+-		/*
+-		 * ->mmu_private can access on only allocation path.
+-		 * (caller must hold ->i_mutex)
+-		 */
+-		last_block = (MSDOS_I(inode)->mmu_private + (blocksize - 1))
+-			>> blocksize_bits;
++	} else {
++		last_block = inode->i_blocks >>
++				(inode->i_sb->s_blocksize_bits - 9);
+ 		if (sector >= last_block)
+ 			return 0;
+ 	}
+ 
+-	cluster = sector >> (sbi->cluster_bits - sb->s_blocksize_bits);
+-	offset  = sector & (sbi->sec_per_clus - 1);
+-	cluster = fat_bmap_cluster(inode, cluster);
+-	if (cluster < 0)
+-		return cluster;
+-	else if (cluster) {
+-		*phys = fat_clus_to_blknr(sbi, cluster) + offset;
+-		*mapped_blocks = sbi->sec_per_clus - offset;
+-		if (*mapped_blocks > last_block - sector)
+-			*mapped_blocks = last_block - sector;
+-	}
+-	return 0;
++	return fat_get_mapped_cluster(inode, sector, last_block, mapped_blocks,
++				      phys);
+ }
+diff --git a/fs/fat/dir.c b/fs/fat/dir.c
+index 3963ede..bfd5d55 100644
+--- a/fs/fat/dir.c
++++ b/fs/fat/dir.c
+@@ -13,13 +13,9 @@
+  *  Short name translation 1999, 2001 by Wolfram Pienkoss <wp@bszh.de>
+  */
+ 
+-#include <linux/module.h>
+ #include <linux/slab.h>
+-#include <linux/time.h>
+-#include <linux/buffer_head.h>
+ #include <linux/compat.h>
+ #include <linux/uaccess.h>
+-#include <linux/kernel.h>
+ #include "fat.h"
+ 
+ /*
+@@ -95,7 +91,7 @@ next:
+ 
+ 	*bh = NULL;
+ 	iblock = *pos >> sb->s_blocksize_bits;
+-	err = fat_bmap(dir, iblock, &phys, &mapped_blocks, 0);
++	err = fat_bmap(dir, iblock, &phys, &mapped_blocks, 0, false);
+ 	if (err || !phys)
+ 		return -1;	/* beyond EOF or error */
+ 
+@@ -614,9 +610,9 @@ parse_record:
+ 		int status = fat_parse_long(inode, &cpos, &bh, &de,
+ 					    &unicode, &nr_slots);
+ 		if (status < 0) {
+-			ctx->pos = cpos;
++			bh = NULL;
+ 			ret = status;
+-			goto out;
++			goto end_of_dir;
+ 		} else if (status == PARSE_INVALID)
+ 			goto record_end;
+ 		else if (status == PARSE_NOT_LONGNAME)
+@@ -658,8 +654,9 @@ parse_record:
+ 	fill_len = short_len;
+ 
+ start_filldir:
+-	if (!fake_offset)
+-		ctx->pos = cpos - (nr_slots + 1) * sizeof(struct msdos_dir_entry);
++	ctx->pos = cpos - (nr_slots + 1) * sizeof(struct msdos_dir_entry);
++	if (fake_offset && ctx->pos < 2)
++		ctx->pos = 2;
+ 
+ 	if (!memcmp(de->name, MSDOS_DOT, MSDOS_NAME)) {
+ 		if (!dir_emit_dot(file, ctx))
+@@ -685,14 +682,19 @@ record_end:
+ 	fake_offset = 0;
+ 	ctx->pos = cpos;
+ 	goto get_new;
++
+ end_of_dir:
+-	ctx->pos = cpos;
++	if (fake_offset && cpos < 2)
++		ctx->pos = 2;
++	else
++		ctx->pos = cpos;
+ fill_failed:
+ 	brelse(bh);
+ 	if (unicode)
+ 		__putname(unicode);
+ out:
+ 	mutex_unlock(&sbi->s_lock);
++
+ 	return ret;
+ }
+ 
+@@ -702,10 +704,12 @@ static int fat_readdir(struct file *file, struct dir_context *ctx)
+ }
+ 
+ #define FAT_IOCTL_FILLDIR_FUNC(func, dirent_type)			   \
+-static int func(void *__buf, const char *name, int name_len,		   \
++static int func(void *_ctx, const char *name, int name_len,   \
+ 			     loff_t offset, u64 ino, unsigned int d_type)  \
+ {									   \
+-	struct fat_ioctl_filldir_callback *buf = __buf;			   \
++    struct dir_context * ctx = (struct dir_context *)_ctx; \
++	struct fat_ioctl_filldir_callback *buf =			   \
++		container_of(ctx, struct fat_ioctl_filldir_callback, ctx); \
+ 	struct dirent_type __user *d1 = buf->dirent;			   \
+ 	struct dirent_type __user *d2 = d1 + 1;				   \
+ 									   \
+@@ -766,7 +770,7 @@ static int fat_ioctl_readdir(struct inode *inode, struct file *file,
+ 
+ 	buf.dirent = dirent;
+ 	buf.result = 0;
+-	mutex_lock(&inode->i_mutex);
++	inode_lock(inode);
+ 	buf.ctx.pos = file->f_pos;
+ 	ret = -ENOENT;
+ 	if (!IS_DEADDIR(inode)) {
+@@ -774,12 +778,392 @@ static int fat_ioctl_readdir(struct inode *inode, struct file *file,
+ 				    short_only, both ? &buf : NULL);
+ 		file->f_pos = buf.ctx.pos;
+ 	}
++	inode_unlock(inode);
++	if (ret >= 0)
++		ret = buf.result;
++	return ret;
++}
++
++/*
++ * This is the "fatfilldirall_t" function type,
++ * used by fat_ioctl_filldirall to let
++ * the kernel specify what kind of dirent layout it wants to have.
++ * This allows the kernel to read directories into kernel space or
++ * to have different dirent layouts depending on the binary type.
++ */
++typedef int (*fatfilldirall_t)(void *__buf, const char *name,
++		int name_len, loff_t offset, u64 ino,
++		unsigned int d_type, struct msdos_dir_entry *de,
++		char *d_createtime);
++struct fatdirall_context {
++	const fatfilldirall_t actor;
++	loff_t pos;
++};
++
++struct fat_ioctl_filldirall_callback {
++	struct fatdirall_context ctx;
++	struct fat_direntall __user *current_dir;
++	struct fat_direntall __user *previous;
++	int count;
++	int usecount;
++	int error;
++	int result;
++	const char *longname;
++	int long_len;
++	const char *shortname;
++	int short_len;
++};
++
++static inline bool fat_dir_emit(struct fatdirall_context *ctx,
++		const char *name, int namelen,
++		u64 ino, unsigned type,
++		struct msdos_dir_entry *de,
++		char *d_createtime)
++{
++	return ctx->actor(ctx, name, namelen, ctx->pos, ino,
++			type, de, d_createtime) == 0;
++}
++static inline bool fat_dir_emit_dot(struct file *file,
++					struct fatdirall_context *ctx,
++					struct msdos_dir_entry *de,
++					char *d_createtime)
++{
++	return ctx->actor(ctx, ".", 1, ctx->pos,
++			file->f_path.dentry->d_inode->i_ino,
++			DT_DIR, de, d_createtime) == 0;
++}
++static inline bool fat_dir_emit_dotdot(struct file *file,
++					struct fatdirall_context *ctx,
++					struct msdos_dir_entry *de,
++					char *d_createtime)
++{
++	return ctx->actor(ctx, "..", 2, ctx->pos,
++			parent_ino(file->f_path.dentry),
++			DT_DIR, de, d_createtime) == 0;
++}
++
++static inline bool fat_dir_emit_dots(struct file *file,
++					struct fatdirall_context *ctx,
++					struct msdos_dir_entry *de,
++					char *d_createtime)
++{
++	if (ctx->pos == 0) {
++		if (!fat_dir_emit_dot(file, ctx, de, d_createtime))
++			return false;
++		ctx->pos = 1;
++	}
++	if (ctx->pos == 1) {
++		if (!fat_dir_emit_dotdot(file, ctx, de, d_createtime))
++			return false;
++		ctx->pos = 2;
++	}
++	return true;
++}
++
++
++static int __fat_readdirall(struct inode *inode, struct file *file,
++		struct fatdirall_context *ctx, int short_only,
++		struct fat_ioctl_filldirall_callback *both)
++{
++	struct super_block *sb = inode->i_sb;
++	struct msdos_sb_info *sbi = MSDOS_SB(sb);
++	struct buffer_head *bh;
++	struct msdos_dir_entry *de;
++	unsigned char nr_slots;
++	wchar_t *unicode = NULL;
++	unsigned char bufname[FAT_MAX_SHORT_SIZE];
++	int isvfat = sbi->options.isvfat;
++	const char *fill_name = NULL;
++	int fake_offset = 0;
++	loff_t cpos;
++	int short_len = 0, fill_len = 0;
++	int ret = 0;
++	char d_createtime[8];
++
++	mutex_lock(&sbi->s_lock);
++
++	cpos = ctx->pos;
++	/* Fake . and .. for the root directory. */
++	if (inode->i_ino == MSDOS_ROOT_INO) {
++		if (!fat_dir_emit_dots(file, ctx, NULL, NULL))
++			goto out;
++		if (ctx->pos == 2) {
++			fake_offset = 1;
++			cpos = 0;
++		}
++	}
++	if (cpos & (sizeof(struct msdos_dir_entry) - 1)) {
++		ret = -ENOENT;
++		goto out;
++	}
++
++	bh = NULL;
++get_new:
++	if (fat_get_entry(inode, &cpos, &bh, &de) == -1)
++		goto end_of_dir;
++parse_record:
++	nr_slots = 0;
++	/*
++	 * Check for long filename entry, but if short_only, we don't
++	 * need to parse long filename.
++	 */
++	if (isvfat && !short_only) {
++		if (de->name[0] == DELETED_FLAG)
++			goto record_end;
++		if (de->attr != ATTR_EXT && (de->attr & ATTR_VOLUME))
++			goto record_end;
++		if (de->attr != ATTR_EXT && IS_FREE(de->name))
++			goto record_end;
++	} else {
++		if ((de->attr & ATTR_VOLUME) || IS_FREE(de->name))
++			goto record_end;
++	}
++
++	if (isvfat && de->attr == ATTR_EXT) {
++		int status = fat_parse_long(inode, &cpos, &bh, &de,
++				&unicode, &nr_slots);
++		if (status < 0) {
++			ctx->pos = cpos;
++			ret = status;
++			goto out;
++		} else if (status == PARSE_INVALID)
++			goto record_end;
++		else if (status == PARSE_NOT_LONGNAME)
++			goto parse_record;
++		else if (status == PARSE_EOF)
++			goto end_of_dir;
++
++		if (nr_slots) {
++			void *longname = unicode + FAT_MAX_UNI_CHARS;
++			int size = PATH_MAX - FAT_MAX_UNI_SIZE;
++			int len = fat_uni_to_x8(sb, unicode, longname, size);
++
++			fill_name = longname;
++			fill_len = len;
++
++			short_len = fat_parse_short(sb, de, bufname,
++					sbi->options.dotsOK);
++			if (short_len == 0)
++				goto record_end;
++
++			/* hack for fat_ioctl_filldir() */
++			both->longname = fill_name;
++			both->long_len = fill_len;
++			both->shortname = bufname;
++			both->short_len = short_len;
++			fill_name = NULL;
++			fill_len = 0;
++			goto start_filldir;
++		}
++	}
++
++	short_len = fat_parse_short(sb, de, bufname, sbi->options.dotsOK);
++	if (short_len == 0)
++		goto record_end;
++
++	fill_name = bufname;
++	fill_len = short_len;
++
++start_filldir:
++	if (!fake_offset)
++		ctx->pos = cpos - (nr_slots + 1)
++			* sizeof(struct msdos_dir_entry);
++
++	memset(d_createtime, 0, 8);
++	fat_time_fat2str(sbi, d_createtime, de->ctime,
++			de->cdate, de->ctime_cs);
++
++	if (!memcmp(de->name, MSDOS_DOT, MSDOS_NAME)) {
++		if (!fat_dir_emit_dot(file, ctx, de, d_createtime))
++			goto fill_failed;
++	} else if (!memcmp(de->name, MSDOS_DOTDOT, MSDOS_NAME)) {
++		if (!fat_dir_emit_dotdot(file, ctx, de, d_createtime))
++			goto fill_failed;
++	} else {
++		unsigned long inum;
++		loff_t i_pos = fat_make_i_pos(sb, bh, de);
++		struct inode *tmp = fat_iget(sb, i_pos);
++
++		if (tmp) {
++			inum = tmp->i_ino;
++			iput(tmp);
++		} else
++			inum = iunique(sb, MSDOS_ROOT_INO);
++		if (!fat_dir_emit(ctx, fill_name, fill_len, inum,
++					(de->attr & ATTR_DIR) ? DT_DIR : DT_REG,
++					de, d_createtime))
++			goto fill_failed;
++	}
++
++record_end:
++	fake_offset = 0;
++	ctx->pos = cpos;
++	goto get_new;
++end_of_dir:
++	ctx->pos = cpos;
++fill_failed:
++	brelse(bh);
++	if (unicode)
++		__putname(unicode);
++out:
++	mutex_unlock(&sbi->s_lock);
++	return ret;
++}
++
++static int fat_ioctl_filldirall(void *__buf, const char *name,
++				int name_len, loff_t offset,
++				u64 ino, unsigned int d_type,
++				struct msdos_dir_entry *de,
++				char *d_createtime)
++{
++	struct fat_direntall __user *dirent;
++	struct fat_ioctl_filldirall_callback *buf;
++	unsigned long d_ino;
++	int reclen = 0;
++	const char *longname = NULL;
++	int long_len = 0;
++	const char *shortname = NULL;
++	int short_len = 0;
++
++	buf = (struct fat_ioctl_filldirall_callback *) __buf;
++
++	if (name != NULL) {
++		reclen = ALIGN(offsetof(struct fat_direntall, d_name)
++				+ name_len + 2, sizeof(long));
++	} else {
++		longname = buf->longname;
++		long_len = buf->long_len;
++		shortname = buf->shortname;
++		short_len = buf->short_len;
++		reclen = ALIGN(offsetof(struct fat_direntall, d_name)
++				+ long_len + 2, sizeof(long));
++	}
++
++	buf->error = -EINVAL;   /* only used if we fail.. */
++
++	if (reclen >= buf->count)
++		return -EINVAL;
++
++	d_ino = ino;
++
++	if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
++		buf->error = -EOVERFLOW;
++		return -EOVERFLOW;
++	}
++
++	dirent = buf->previous;
++
++	if (dirent) {
++		if (__put_user(offset, &dirent->d_off))
++			goto efault;
++	}
++
++	dirent = buf->current_dir;
++
++	if (__put_user(d_ino, &dirent->d_ino))
++		goto efault;
++
++	if (__put_user(reclen, &dirent->d_reclen))
++		goto efault;
++
++	if (name != NULL) {
++		if (copy_to_user(dirent->d_name, name, name_len))
++			goto efault;
++		if (__put_user(0, dirent->d_name + name_len))
++			goto efault;
++	} else {
++		if (copy_to_user(dirent->d_name, longname, long_len))
++			goto efault;
++		if (__put_user(0, dirent->d_name + long_len))
++			goto efault;
++	}
++
++	if (__put_user(d_type, &dirent->d_type))
++		goto efault;
++
++	if (de != NULL) {
++		u64 u_size = 0;
++		if (copy_to_user(&dirent->d_size, &u_size, sizeof(u64)))
++			goto efault;
++		if (copy_to_user(&dirent->d_size, &de->size, sizeof(u32)))
++			goto efault;
++	}
++
++	if (d_createtime != NULL) {
++		if (copy_to_user(dirent->d_createtime, d_createtime, 8))
++			goto efault;
++	}
++	buf->previous = dirent;
++	dirent = (void __user *)dirent + reclen;
++	buf->current_dir = dirent;
++	buf->count -= reclen;
++	buf->usecount += reclen;
++	return 0;
++efault:
++	buf->error = -EFAULT;
++	return -EFAULT;
++}
++
++
++static int fat_ioctl_readdirall(struct inode *inode, struct file *file,
++		void __user *dirent,
++		int short_only, int both)
++{
++	struct fat_ioctl_filldirall_callback buf = {
++		.ctx.actor = fat_ioctl_filldirall,
++	};
++
++	struct fat_direntall_buf __user *userbuf = dirent;
++	int ret;
++
++	buf.current_dir = &(userbuf->direntall);
++	buf.previous = NULL;
++	buf.error = 0;
++	buf.result = 0;
++	buf.usecount = 0;
++
++	if (get_user(buf.count, &(userbuf->d_count)))
++		return -EFAULT;
++
++	mutex_lock(&inode->i_mutex);
++	buf.ctx.pos = file->f_pos;
++	ret = -ENOENT;
++	if (!IS_DEADDIR(inode)) {
++		ret = __fat_readdirall(inode, file, &buf.ctx,
++				short_only, both ? &buf : NULL);
++		file->f_pos = buf.ctx.pos;
++	}
+ 	mutex_unlock(&inode->i_mutex);
++
++	if (__put_user(buf.usecount, &(userbuf->d_usecount)))
++		return -EFAULT;
+ 	if (ret >= 0)
+ 		ret = buf.result;
+ 	return ret;
+ }
+ 
++static int fat_dir_ioctl_readdirall(struct file *filp, unsigned int cmd,
++					unsigned long arg)
++{
++	struct inode *inode = filp->f_path.dentry->d_inode;
++	struct fat_direntall_buf __user *direntallbuf;
++	int short_only, both;
++
++	direntallbuf = (struct fat_direntall_buf __user *)arg;
++
++	if (!access_ok(VERIFY_WRITE, direntallbuf,
++			sizeof(struct fat_direntall_buf)))
++		return -EFAULT;
++	if (put_user(0, &(direntallbuf->direntall.d_reclen)))
++		return -EFAULT;
++	if (put_user(0, &(direntallbuf->d_usecount)))
++		return -EFAULT;
++	short_only = 0;
++	both = 1;
++	return fat_ioctl_readdirall(inode, filp, direntallbuf,
++			short_only, both);
++}
++
+ static long fat_dir_ioctl(struct file *filp, unsigned int cmd,
+ 			  unsigned long arg)
+ {
+@@ -787,6 +1171,9 @@ static long fat_dir_ioctl(struct file *filp, unsigned int cmd,
+ 	struct __fat_dirent __user *d1 = (struct __fat_dirent __user *)arg;
+ 	int short_only, both;
+ 
++	if (VFAT_IOCTL_READDIR_ALL == cmd)
++		return fat_dir_ioctl_readdirall(filp, cmd, arg);
++
+ 	switch (cmd) {
+ 	case VFAT_IOCTL_READDIR_SHORT:
+ 		short_only = 1;
+diff --git a/fs/fat/fat.h b/fs/fat/fat.h
+index e0c4ba3..6cb4ba3 100644
+--- a/fs/fat/fat.h
++++ b/fs/fat/fat.h
+@@ -2,11 +2,8 @@
+ #define _FAT_H
+ 
+ #include <linux/buffer_head.h>
+-#include <linux/string.h>
+ #include <linux/nls.h>
+-#include <linux/fs.h>
+ #include <linux/hash.h>
+-#include <linux/mutex.h>
+ #include <linux/ratelimit.h>
+ #include <linux/msdos_fs.h>
+ 
+@@ -66,7 +63,7 @@ struct msdos_sb_info {
+ 	unsigned short sec_per_clus;  /* sectors/cluster */
+ 	unsigned short cluster_bits;  /* log2(cluster_size) */
+ 	unsigned int cluster_size;    /* cluster size */
+-	unsigned char fats, fat_bits; /* number of FATs, FAT bits (12 or 16) */
++	unsigned char fats, fat_bits; /* number of FATs, FAT bits (12,16 or 32) */
+ 	unsigned short fat_start;
+ 	unsigned long fat_length;     /* FAT start & length (sec.) */
+ 	unsigned long dir_start;
+@@ -90,7 +87,7 @@ struct msdos_sb_info {
+ 	unsigned int vol_id;		/*volume ID*/
+ 
+ 	int fatent_shift;
+-	struct fatent_operations *fatent_ops;
++	const struct fatent_operations *fatent_ops;
+ 	struct inode *fat_inode;
+ 	struct inode *fsinfo_inode;
+ 
+@@ -288,8 +285,11 @@ static inline void fatwchar_to16(__u8 *dst, const wchar_t *src, size_t len)
+ extern void fat_cache_inval_inode(struct inode *inode);
+ extern int fat_get_cluster(struct inode *inode, int cluster,
+ 			   int *fclus, int *dclus);
++extern int fat_get_mapped_cluster(struct inode *inode, sector_t sector,
++				  sector_t last_block,
++				  unsigned long *mapped_blocks, sector_t *bmap);
+ extern int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys,
+-		    unsigned long *mapped_blocks, int create);
++		    unsigned long *mapped_blocks, int create, bool from_bmap);
+ 
+ /* fat/dir.c */
+ extern const struct file_operations fat_dir_operations;
+@@ -370,6 +370,7 @@ extern int fat_file_fsync(struct file *file, loff_t start, loff_t end,
+ 			  int datasync);
+ 
+ /* fat/inode.c */
++extern int fat_block_truncate_page(struct inode *inode, loff_t from);
+ extern void fat_attach(struct inode *inode, loff_t i_pos);
+ extern void fat_detach(struct inode *inode);
+ extern struct inode *fat_iget(struct super_block *sb, loff_t i_pos);
+@@ -386,6 +387,7 @@ static inline unsigned long fat_dir_hash(int logstart)
+ {
+ 	return hash_32(logstart, FAT_HASH_BITS);
+ }
++extern int fat_add_cluster(struct inode *inode);
+ 
+ /* fat/misc.c */
+ extern __printf(3, 4) __cold
+@@ -407,6 +409,8 @@ extern void fat_time_fat2unix(struct msdos_sb_info *sbi, struct timespec *ts,
+ 			      __le16 __time, __le16 __date, u8 time_cs);
+ extern void fat_time_unix2fat(struct msdos_sb_info *sbi, struct timespec *ts,
+ 			      __le16 *time, __le16 *date, u8 *time_cs);
++extern void fat_time_fat2str(struct msdos_sb_info *sbi, char *d_createtime,
++		__le16 __time, __le16 __date, u8 time_cs);
+ extern int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs);
+ 
+ int fat_cache_init(void);
+diff --git a/fs/fat/fatent.c b/fs/fat/fatent.c
+index 260705c..1d9a8c4 100644
+--- a/fs/fat/fatent.c
++++ b/fs/fat/fatent.c
+@@ -3,9 +3,6 @@
+  * Released under GPL v2.
+  */
+ 
+-#include <linux/module.h>
+-#include <linux/fs.h>
+-#include <linux/msdos_fs.h>
+ #include <linux/blkdev.h>
+ #include "fat.h"
+ 
+@@ -102,7 +99,7 @@ err:
+ static int fat_ent_bread(struct super_block *sb, struct fat_entry *fatent,
+ 			 int offset, sector_t blocknr)
+ {
+-	struct fatent_operations *ops = MSDOS_SB(sb)->fatent_ops;
++	const struct fatent_operations *ops = MSDOS_SB(sb)->fatent_ops;
+ 
+ 	WARN_ON(blocknr < MSDOS_SB(sb)->fat_start);
+ 	fatent->fat_inode = MSDOS_SB(sb)->fat_inode;
+@@ -249,7 +246,7 @@ static int fat32_ent_next(struct fat_entry *fatent)
+ 	return 0;
+ }
+ 
+-static struct fatent_operations fat12_ops = {
++static const struct fatent_operations fat12_ops = {
+ 	.ent_blocknr	= fat12_ent_blocknr,
+ 	.ent_set_ptr	= fat12_ent_set_ptr,
+ 	.ent_bread	= fat12_ent_bread,
+@@ -258,7 +255,7 @@ static struct fatent_operations fat12_ops = {
+ 	.ent_next	= fat12_ent_next,
+ };
+ 
+-static struct fatent_operations fat16_ops = {
++static const struct fatent_operations fat16_ops = {
+ 	.ent_blocknr	= fat_ent_blocknr,
+ 	.ent_set_ptr	= fat16_ent_set_ptr,
+ 	.ent_bread	= fat_ent_bread,
+@@ -267,7 +264,7 @@ static struct fatent_operations fat16_ops = {
+ 	.ent_next	= fat16_ent_next,
+ };
+ 
+-static struct fatent_operations fat32_ops = {
++static const struct fatent_operations fat32_ops = {
+ 	.ent_blocknr	= fat_ent_blocknr,
+ 	.ent_set_ptr	= fat32_ent_set_ptr,
+ 	.ent_bread	= fat_ent_bread,
+@@ -323,7 +320,7 @@ static inline int fat_ent_update_ptr(struct super_block *sb,
+ 				     int offset, sector_t blocknr)
+ {
+ 	struct msdos_sb_info *sbi = MSDOS_SB(sb);
+-	struct fatent_operations *ops = sbi->fatent_ops;
++	const struct fatent_operations *ops = sbi->fatent_ops;
+ 	struct buffer_head **bhs = fatent->bhs;
+ 
+ 	/* Is this fatent's blocks including this entry? */
+@@ -352,7 +349,7 @@ int fat_ent_read(struct inode *inode, struct fat_entry *fatent, int entry)
+ {
+ 	struct super_block *sb = inode->i_sb;
+ 	struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
+-	struct fatent_operations *ops = sbi->fatent_ops;
++	const struct fatent_operations *ops = sbi->fatent_ops;
+ 	int err, offset;
+ 	sector_t blocknr;
+ 
+@@ -410,7 +407,7 @@ int fat_ent_write(struct inode *inode, struct fat_entry *fatent,
+ 		  int new, int wait)
+ {
+ 	struct super_block *sb = inode->i_sb;
+-	struct fatent_operations *ops = MSDOS_SB(sb)->fatent_ops;
++	const struct fatent_operations *ops = MSDOS_SB(sb)->fatent_ops;
+ 	int err;
+ 
+ 	ops->ent_put(fatent, new);
+@@ -435,7 +432,7 @@ static inline int fat_ent_next(struct msdos_sb_info *sbi,
+ static inline int fat_ent_read_block(struct super_block *sb,
+ 				     struct fat_entry *fatent)
+ {
+-	struct fatent_operations *ops = MSDOS_SB(sb)->fatent_ops;
++	const struct fatent_operations *ops = MSDOS_SB(sb)->fatent_ops;
+ 	sector_t blocknr;
+ 	int offset;
+ 
+@@ -466,7 +463,7 @@ int fat_alloc_clusters(struct inode *inode, int *cluster, int nr_cluster)
+ {
+ 	struct super_block *sb = inode->i_sb;
+ 	struct msdos_sb_info *sbi = MSDOS_SB(sb);
+-	struct fatent_operations *ops = sbi->fatent_ops;
++	const struct fatent_operations *ops = sbi->fatent_ops;
+ 	struct fat_entry fatent, prev_ent;
+ 	struct buffer_head *bhs[MAX_BUF_PER_PAGE];
+ 	int i, count, err, nr_bhs, idx_clus;
+@@ -554,7 +551,7 @@ int fat_free_clusters(struct inode *inode, int cluster)
+ {
+ 	struct super_block *sb = inode->i_sb;
+ 	struct msdos_sb_info *sbi = MSDOS_SB(sb);
+-	struct fatent_operations *ops = sbi->fatent_ops;
++	const struct fatent_operations *ops = sbi->fatent_ops;
+ 	struct fat_entry fatent;
+ 	struct buffer_head *bhs[MAX_BUF_PER_PAGE];
+ 	int i, err, nr_bhs;
+@@ -639,7 +636,7 @@ EXPORT_SYMBOL_GPL(fat_free_clusters);
+ static void fat_ent_reada(struct super_block *sb, struct fat_entry *fatent,
+ 			  unsigned long reada_blocks)
+ {
+-	struct fatent_operations *ops = MSDOS_SB(sb)->fatent_ops;
++	const struct fatent_operations *ops = MSDOS_SB(sb)->fatent_ops;
+ 	sector_t blocknr;
+ 	int i, offset;
+ 
+@@ -652,7 +649,7 @@ static void fat_ent_reada(struct super_block *sb, struct fat_entry *fatent,
+ int fat_count_free_clusters(struct super_block *sb)
+ {
+ 	struct msdos_sb_info *sbi = MSDOS_SB(sb);
+-	struct fatent_operations *ops = sbi->fatent_ops;
++	const struct fatent_operations *ops = sbi->fatent_ops;
+ 	struct fat_entry fatent;
+ 	unsigned long reada_blocks, reada_mask, cur_block;
+ 	int err = 0, free;
+diff --git a/fs/fat/file.c b/fs/fat/file.c
+index 85f79a8..25543e6 100644
+--- a/fs/fat/file.c
++++ b/fs/fat/file.c
+@@ -10,22 +10,23 @@
+ #include <linux/module.h>
+ #include <linux/compat.h>
+ #include <linux/mount.h>
+-#include <linux/time.h>
+-#include <linux/buffer_head.h>
+-#include <linux/writeback.h>
+-#include <linux/backing-dev.h>
+ #include <linux/blkdev.h>
++#include <linux/backing-dev.h>
+ #include <linux/fsnotify.h>
+ #include <linux/security.h>
++#include <linux/falloc.h>
+ #include "fat.h"
+ 
++static long fat_fallocate(struct file *file, int mode,
++			  loff_t offset, loff_t len);
++
+ static int fat_ioctl_get_attributes(struct inode *inode, u32 __user *user_attr)
+ {
+ 	u32 attr;
+ 
+-	mutex_lock(&inode->i_mutex);
++	inode_lock(inode);
+ 	attr = fat_make_attrs(inode);
+-	mutex_unlock(&inode->i_mutex);
++	inode_unlock(inode);
+ 
+ 	return put_user(attr, user_attr);
+ }
+@@ -46,7 +47,7 @@ static int fat_ioctl_set_attributes(struct file *file, u32 __user *user_attr)
+ 	err = mnt_want_write_file(file);
+ 	if (err)
+ 		goto out;
+-	mutex_lock(&inode->i_mutex);
++	inode_lock(inode);
+ 
+ 	/*
+ 	 * ATTR_VOLUME and ATTR_DIR cannot be changed; this also
+@@ -108,7 +109,7 @@ static int fat_ioctl_set_attributes(struct file *file, u32 __user *user_attr)
+ 	fat_save_attrs(inode, attr);
+ 	mark_inode_dirty(inode);
+ out_unlock_inode:
+-	mutex_unlock(&inode->i_mutex);
++	inode_unlock(inode);
+ 	mnt_drop_write_file(file);
+ out:
+ 	return err;
+@@ -170,8 +171,6 @@ int fat_file_fsync(struct file *filp, loff_t start, loff_t end, int datasync)
+ 
+ const struct file_operations fat_file_operations = {
+ 	.llseek		= generic_file_llseek,
+-	.read		= new_sync_read,
+-	.write		= new_sync_write,
+ 	.read_iter	= generic_file_read_iter,
+ 	.write_iter	= generic_file_write_iter,
+ 	.mmap		= generic_file_mmap,
+@@ -182,6 +181,7 @@ const struct file_operations fat_file_operations = {
+ #endif
+ 	.fsync		= fat_file_fsync,
+ 	.splice_read	= generic_file_splice_read,
++	.fallocate	= fat_fallocate,
+ };
+ 
+ static int fat_cont_expand(struct inode *inode, loff_t size)
+@@ -220,6 +220,62 @@ out:
+ 	return err;
+ }
+ 
++/*
++ * Preallocate space for a file. This implements fat's fallocate file
++ * operation, which gets called from sys_fallocate system call. User
++ * space requests len bytes at offset. If FALLOC_FL_KEEP_SIZE is set
++ * we just allocate clusters without zeroing them out. Otherwise we
++ * allocate and zero out clusters via an expanding truncate.
++ */
++static long fat_fallocate(struct file *file, int mode,
++			  loff_t offset, loff_t len)
++{
++	int nr_cluster; /* Number of clusters to be allocated */
++	loff_t mm_bytes; /* Number of bytes to be allocated for file */
++	loff_t ondisksize; /* block aligned on-disk size in bytes*/
++	struct inode *inode = file->f_mapping->host;
++	struct super_block *sb = inode->i_sb;
++	struct msdos_sb_info *sbi = MSDOS_SB(sb);
++	int err = 0;
++
++	/* No support for hole punch or other fallocate flags. */
++	if (mode & ~FALLOC_FL_KEEP_SIZE)
++		return -EOPNOTSUPP;
++
++	/* No support for dir */
++	if (!S_ISREG(inode->i_mode))
++		return -EOPNOTSUPP;
++
++	inode_lock(inode);
++	if (mode & FALLOC_FL_KEEP_SIZE) {
++		ondisksize = inode->i_blocks << 9;
++		if ((offset + len) <= ondisksize)
++			goto error;
++
++		/* First compute the number of clusters to be allocated */
++		mm_bytes = offset + len - ondisksize;
++		nr_cluster = (mm_bytes + (sbi->cluster_size - 1)) >>
++			sbi->cluster_bits;
++
++		/* Start the allocation.We are not zeroing out the clusters */
++		while (nr_cluster-- > 0) {
++			err = fat_add_cluster(inode);
++			if (err)
++				goto error;
++		}
++	} else {
++		if ((offset + len) <= i_size_read(inode))
++			goto error;
++
++		/* This is just an expanding truncate */
++		err = fat_cont_expand(inode, (offset + len));
++	}
++
++error:
++	inode_unlock(inode);
++	return err;
++}
++
+ /* Free all clusters after the skip'th cluster. */
+ static int fat_free(struct inode *inode, int skip)
+ {
+@@ -311,7 +367,7 @@ void fat_truncate_blocks(struct inode *inode, loff_t offset)
+ 
+ int fat_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
+ {
+-	struct inode *inode = dentry->d_inode;
++	struct inode *inode = d_inode(dentry);
+ 	generic_fillattr(inode, stat);
+ 	stat->blksize = MSDOS_SB(inode->i_sb)->cluster_size;
+ 
+@@ -380,10 +436,22 @@ static int fat_allow_set_time(struct msdos_sb_info *sbi, struct inode *inode)
+ /* valid file mode bits */
+ #define FAT_VALID_MODE	(S_IFREG | S_IFDIR | S_IRWXUGO)
+ 
++
++#if defined(CONFIG_ARCH_HI3559) || defined(CONFIG_ARCH_HI3556)
++void reset_mmu_private(struct inode *inode, loff_t offset)
++{
++	/**set the inode mmu_private**/
++	MSDOS_I(inode)->mmu_private = offset;
++	/**set the inode time**/
++	inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC;
++}
++#endif
++
++
+ int fat_setattr(struct dentry *dentry, struct iattr *attr)
+ {
+ 	struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb);
+-	struct inode *inode = dentry->d_inode;
++	struct inode *inode = d_inode(dentry);
+ 	unsigned int ia_valid;
+ 	int error;
+ 
+@@ -408,6 +476,7 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr)
+ 	 * hole before it. XXX: this is no longer true with new truncate
+ 	 * sequence.
+ 	 */
++#if !defined(CONFIG_ARCH_HI3559) && !defined(CONFIG_ARCH_HI3556)
+ 	if (attr->ia_valid & ATTR_SIZE) {
+ 		inode_dio_wait(inode);
+ 
+@@ -418,6 +487,7 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr)
+ 			attr->ia_valid &= ~ATTR_SIZE;
+ 		}
+ 	}
++#endif
+ 
+ 	if (((attr->ia_valid & ATTR_UID) &&
+ 	     (!uid_eq(attr->ia_uid, sbi->options.fs_uid))) ||
+@@ -443,8 +513,14 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr)
+ 	}
+ 
+ 	if (attr->ia_valid & ATTR_SIZE) {
++		error = fat_block_truncate_page(inode, attr->ia_size);
++		if (error)
++			goto out;
+ 		down_write(&MSDOS_I(inode)->truncate_lock);
+ 		truncate_setsize(inode, attr->ia_size);
++#if defined(CONFIG_ARCH_HI3559) || defined(CONFIG_ARCH_HI3556)
++		reset_mmu_private(inode, attr->ia_size);
++#endif
+ 		fat_truncate_blocks(inode, attr->ia_size);
+ 		up_write(&MSDOS_I(inode)->truncate_lock);
+ 	}
+diff --git a/fs/fat/inode.c b/fs/fat/inode.c
+index 756aead..41ea0da 100644
+--- a/fs/fat/inode.c
++++ b/fs/fat/inode.c
+@@ -11,22 +11,15 @@
+  */
+ 
+ #include <linux/module.h>
+-#include <linux/init.h>
+-#include <linux/time.h>
+-#include <linux/slab.h>
+-#include <linux/seq_file.h>
+ #include <linux/pagemap.h>
+ #include <linux/mpage.h>
+-#include <linux/buffer_head.h>
+-#include <linux/mount.h>
+-#include <linux/aio.h>
+ #include <linux/vfs.h>
++#include <linux/seq_file.h>
+ #include <linux/parser.h>
+ #include <linux/uio.h>
+-#include <linux/writeback.h>
+-#include <linux/log2.h>
+-#include <linux/hash.h>
++#include <linux/aio.h>
+ #include <linux/blkdev.h>
++#include <linux/backing-dev.h>
+ #include <asm/unaligned.h>
+ #include "fat.h"
+ 
+@@ -101,7 +94,7 @@ static struct fat_floppy_defaults {
+ },
+ };
+ 
+-static int fat_add_cluster(struct inode *inode)
++int fat_add_cluster(struct inode *inode)
+ {
+ 	int err, cluster;
+ 
+@@ -123,10 +116,10 @@ static inline int __fat_get_block(struct inode *inode, sector_t iblock,
+ 	struct super_block *sb = inode->i_sb;
+ 	struct msdos_sb_info *sbi = MSDOS_SB(sb);
+ 	unsigned long mapped_blocks;
+-	sector_t phys;
++	sector_t phys, last_block;
+ 	int err, offset;
+ 
+-	err = fat_bmap(inode, iblock, &phys, &mapped_blocks, create);
++	err = fat_bmap(inode, iblock, &phys, &mapped_blocks, create, false);
+ 	if (err)
+ 		return err;
+ 	if (phys) {
+@@ -143,8 +136,14 @@ static inline int __fat_get_block(struct inode *inode, sector_t iblock,
+ 		return -EIO;
+ 	}
+ 
++	last_block = inode->i_blocks >> (sb->s_blocksize_bits - 9);
+ 	offset = (unsigned long)iblock & (sbi->sec_per_clus - 1);
+-	if (!offset) {
++	/*
++	 * allocate a cluster according to the following.
++	 * 1) no more available blocks
++	 * 2) not part of fallocate region
++	 */
++	if (!offset && !(iblock < last_block)) {
+ 		/* TODO: multiple cluster allocation would be desirable. */
+ 		err = fat_add_cluster(inode);
+ 		if (err)
+@@ -156,7 +155,7 @@ static inline int __fat_get_block(struct inode *inode, sector_t iblock,
+ 	*max_blocks = min(mapped_blocks, *max_blocks);
+ 	MSDOS_I(inode)->mmu_private += *max_blocks << sb->s_blocksize_bits;
+ 
+-	err = fat_bmap(inode, iblock, &phys, &mapped_blocks, create);
++	err = fat_bmap(inode, iblock, &phys, &mapped_blocks, create, false);
+ 	if (err)
+ 		return err;
+ 
+@@ -246,8 +245,7 @@ static int fat_write_end(struct file *file, struct address_space *mapping,
+ 	return err;
+ }
+ 
+-static ssize_t fat_direct_IO(int rw, struct kiocb *iocb,
+-			     struct iov_iter *iter,
++static ssize_t fat_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter,
+ 			     loff_t offset)
+ {
+ 	struct file *file = iocb->ki_filp;
+@@ -256,7 +254,7 @@ static ssize_t fat_direct_IO(int rw, struct kiocb *iocb,
+ 	size_t count = iov_iter_count(iter);
+ 	ssize_t ret;
+ 
+-	if (rw == WRITE) {
++	if (iov_iter_rw(iter) == WRITE) {
+ 		/*
+ 		 * FIXME: blockdev_direct_IO() doesn't use ->write_begin(),
+ 		 * so we need to update the ->mmu_private to block boundary.
+@@ -276,24 +274,61 @@ static ssize_t fat_direct_IO(int rw, struct kiocb *iocb,
+ 	 * condition of fat_get_block() and ->truncate().
+ 	 */
+ 	ret = blockdev_direct_IO(rw, iocb, inode, iter, offset, fat_get_block);
+-	if (ret < 0 && (rw & WRITE))
++	if (ret < 0 && iov_iter_rw(iter) == WRITE)
+ 		fat_write_failed(mapping, offset + count);
+ 
+ 	return ret;
+ }
+ 
++static int fat_get_block_bmap(struct inode *inode, sector_t iblock,
++		struct buffer_head *bh_result, int create)
++{
++	struct super_block *sb = inode->i_sb;
++	unsigned long max_blocks = bh_result->b_size >> inode->i_blkbits;
++	int err;
++	sector_t bmap;
++	unsigned long mapped_blocks;
++
++	BUG_ON(create != 0);
++
++	err = fat_bmap(inode, iblock, &bmap, &mapped_blocks, create, true);
++	if (err)
++		return err;
++
++	if (bmap) {
++		map_bh(bh_result, sb, bmap);
++		max_blocks = min(mapped_blocks, max_blocks);
++	}
++
++	bh_result->b_size = max_blocks << sb->s_blocksize_bits;
++
++	return 0;
++}
++
+ static sector_t _fat_bmap(struct address_space *mapping, sector_t block)
+ {
+ 	sector_t blocknr;
+ 
+ 	/* fat_get_cluster() assumes the requested blocknr isn't truncated. */
+ 	down_read(&MSDOS_I(mapping->host)->truncate_lock);
+-	blocknr = generic_block_bmap(mapping, block, fat_get_block);
++	blocknr = generic_block_bmap(mapping, block, fat_get_block_bmap);
+ 	up_read(&MSDOS_I(mapping->host)->truncate_lock);
+ 
+ 	return blocknr;
+ }
+ 
++/*
++ * fat_block_truncate_page() zeroes out a mapping from file offset `from'
++ * up to the end of the block which corresponds to `from'.
++ * This is required during truncate to physically zeroout the tail end
++ * of that block so it doesn't yield old data if the file is later grown.
++ * Also, avoid causing failure from fsx for cases of "data past EOF"
++ */
++int fat_block_truncate_page(struct inode *inode, loff_t from)
++{
++	return block_truncate_page(inode->i_mapping, from, fat_get_block);
++}
++
+ static const struct address_space_operations fat_aops = {
+ 	.readpage	= fat_readpage,
+ 	.readpages	= fat_readpages,
+@@ -446,6 +481,24 @@ static int fat_calc_dir_size(struct inode *inode)
+ 	return 0;
+ }
+ 
++static int fat_validate_dir(struct inode *dir)
++{
++	struct super_block *sb = dir->i_sb;
++
++	if (dir->i_nlink < 2) {
++		/* Directory should have "."/".." entries at least. */
++		fat_fs_error(sb, "corrupted directory (invalid entries)");
++		return -EIO;
++	}
++	if (MSDOS_I(dir)->i_start == 0 ||
++	    MSDOS_I(dir)->i_start == MSDOS_SB(sb)->root_cluster) {
++		/* Directory should point valid cluster. */
++		fat_fs_error(sb, "corrupted directory (invalid i_start)");
++		return -EIO;
++	}
++	return 0;
++}
++
+ /* doesn't deal with root inode */
+ int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
+ {
+@@ -472,6 +525,10 @@ int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
+ 		MSDOS_I(inode)->mmu_private = inode->i_size;
+ 
+ 		set_nlink(inode, fat_subdirs(inode));
++
++		error = fat_validate_dir(inode);
++		if (error < 0)
++			return error;
+ 	} else { /* not a directory */
+ 		inode->i_generation |= 1;
+ 		inode->i_mode = fat_make_mode(sbi, de->attr,
+@@ -550,13 +607,46 @@ out:
+ 
+ EXPORT_SYMBOL_GPL(fat_build_inode);
+ 
++static int __fat_write_inode(struct inode *inode, int wait);
++
++static void fat_free_eofblocks(struct inode *inode)
++{
++	/* Release unwritten fallocated blocks on inode eviction. */
++	if ((inode->i_blocks << 9) >
++			round_up(MSDOS_I(inode)->mmu_private,
++				MSDOS_SB(inode->i_sb)->cluster_size)) {
++		int err;
++
++#if !defined(CONFIG_ARCH_HI3559) && !defined(CONFIG_ARCH_HI3556)
++		fat_truncate_blocks(inode, MSDOS_I(inode)->mmu_private);
++#endif
++
++		/* Fallocate results in updating the i_start/iogstart
++		 * for the zero byte file. So, make it return to
++		 * original state during evict and commit it to avoid
++		 * any corruption on the next access to the cluster
++		 * chain for the file.
++		 */
++		err = __fat_write_inode(inode, inode_needs_sync(inode));
++		if (err) {
++			fat_msg(inode->i_sb, KERN_WARNING, "Failed to "
++					"update on disk inode for unused "
++					"fallocated blocks, inode could be "
++					"corrupted. Please run fsck");
++		}
++
++	}
++}
++
+ static void fat_evict_inode(struct inode *inode)
+ {
+ 	truncate_inode_pages_final(&inode->i_data);
+ 	if (!inode->i_nlink) {
+ 		inode->i_size = 0;
+ 		fat_truncate_blocks(inode, 0);
+-	}
++	} else
++		fat_free_eofblocks(inode);
++
+ 	invalidate_inode_buffers(inode);
+ 	clear_inode(inode);
+ 	fat_cache_inval_inode(inode);
+@@ -568,7 +658,7 @@ static void fat_set_state(struct super_block *sb,
+ {
+ 	struct buffer_head *bh;
+ 	struct fat_boot_sector *b;
+-	struct msdos_sb_info *sbi = sb->s_fs_info;
++	struct msdos_sb_info *sbi = MSDOS_SB(sb);
+ 
+ 	/* do not change any thing if mounted read only */
+ 	if ((sb->s_flags & MS_RDONLY) && !force)
+@@ -674,7 +764,7 @@ static int __init fat_init_inodecache(void)
+ 	fat_inode_cachep = kmem_cache_create("fat_inode_cache",
+ 					     sizeof(struct msdos_inode_info),
+ 					     0, (SLAB_RECLAIM_ACCOUNT|
+-						SLAB_MEM_SPREAD),
++						SLAB_MEM_SPREAD|SLAB_ACCOUNT),
+ 					     init_once);
+ 	if (fat_inode_cachep == NULL)
+ 		return -ENOMEM;
+@@ -1143,7 +1233,12 @@ static int parse_options(struct super_block *sb, char *options, int is_vfat,
+ 		case Opt_time_offset:
+ 			if (match_int(&args[0], &option))
+ 				return -EINVAL;
+-			if (option < -12 * 60 || option > 12 * 60)
++			/*
++			 * GMT+-12 zones may have DST corrections so at least
++			 * 13 hours difference is needed. Make the limit 24
++			 * just in case someone invents something unusual.
++			 */
++			if (option < -24 * 60 || option > 24 * 60)
+ 				return -EINVAL;
+ 			opts->tz_set = 1;
+ 			opts->time_offset = option;
+@@ -1266,10 +1361,19 @@ out:
+ 	return 0;
+ }
+ 
++static void fat_dummy_inode_init(struct inode *inode)
++{
++	/* Initialize this dummy inode to work as no-op. */
++	MSDOS_I(inode)->mmu_private = 0;
++	MSDOS_I(inode)->i_start = 0;
++	MSDOS_I(inode)->i_logstart = 0;
++	MSDOS_I(inode)->i_attrs = 0;
++	MSDOS_I(inode)->i_pos = 0;
++}
++
+ static int fat_read_root(struct inode *inode)
+ {
+-	struct super_block *sb = inode->i_sb;
+-	struct msdos_sb_info *sbi = MSDOS_SB(sb);
++	struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
+ 	int error;
+ 
+ 	MSDOS_I(inode)->i_pos = MSDOS_ROOT_INO;
+@@ -1711,12 +1815,13 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat,
+ 	fat_inode = new_inode(sb);
+ 	if (!fat_inode)
+ 		goto out_fail;
+-	MSDOS_I(fat_inode)->i_pos = 0;
++	fat_dummy_inode_init(fat_inode);
+ 	sbi->fat_inode = fat_inode;
+ 
+ 	fsinfo_inode = new_inode(sb);
+ 	if (!fsinfo_inode)
+ 		goto out_fail;
++	fat_dummy_inode_init(fsinfo_inode);
+ 	fsinfo_inode->i_ino = MSDOS_FSINFO_INO;
+ 	sbi->fsinfo_inode = fsinfo_inode;
+ 	insert_inode_hash(fsinfo_inode);
+diff --git a/fs/fat/misc.c b/fs/fat/misc.c
+index d8da2d2..0287b52 100644
+--- a/fs/fat/misc.c
++++ b/fs/fat/misc.c
+@@ -266,6 +266,37 @@ void fat_time_unix2fat(struct msdos_sb_info *sbi, struct timespec *ts,
+ }
+ EXPORT_SYMBOL_GPL(fat_time_unix2fat);
+ 
++void fat_time_fat2str(struct msdos_sb_info *sbi, char *d_createtime,
++		__le16 __time, __le16 __date, u8 time_cs)
++{
++	u16 time = le16_to_cpu(__time), date = le16_to_cpu(__date);
++	time_t day, month, year;
++
++	year  = date >> 9;
++	month = max(1, (date >> 5) & 0xf);
++	day   = max(1, date & 0x1f);
++
++	d_createtime[0] = year;
++	d_createtime[1] = month;
++	d_createtime[2] = day;
++	d_createtime[3] = (time >> 11);  /*hour*/
++	d_createtime[4] = ((time >> 5) & 0x3f);  /*min*/
++	d_createtime[5] = (time & 0x1f);  /*second 2s*/
++
++
++	if (!sbi->options.tz_set)
++		d_createtime[4] += sys_tz.tz_minuteswest;
++	else
++		d_createtime[4] -= sbi->options.time_offset;
++
++	if (time_cs) {
++		/*second 1s*/
++		d_createtime[5] += (time_cs / 100);
++	}
++}
++EXPORT_SYMBOL_GPL(fat_time_fat2str);
++
++
+ int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs)
+ {
+ 	int i, err = 0;
+diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c
+index a783b0e..b7e2b33 100644
+--- a/fs/fat/namei_msdos.c
++++ b/fs/fat/namei_msdos.c
+@@ -7,8 +7,6 @@
+  */
+ 
+ #include <linux/module.h>
+-#include <linux/time.h>
+-#include <linux/buffer_head.h>
+ #include "fat.h"
+ 
+ /* Characters that are undesirable in an MS-DOS file name */
+@@ -310,7 +308,7 @@ out:
+ static int msdos_rmdir(struct inode *dir, struct dentry *dentry)
+ {
+ 	struct super_block *sb = dir->i_sb;
+-	struct inode *inode = dentry->d_inode;
++	struct inode *inode = d_inode(dentry);
+ 	struct fat_slot_info sinfo;
+ 	int err;
+ 
+@@ -404,7 +402,7 @@ out:
+ /***** Unlink a file */
+ static int msdos_unlink(struct inode *dir, struct dentry *dentry)
+ {
+-	struct inode *inode = dentry->d_inode;
++	struct inode *inode = d_inode(dentry);
+ 	struct super_block *sb = inode->i_sb;
+ 	struct fat_slot_info sinfo;
+ 	int err;
+@@ -442,8 +440,8 @@ static int do_msdos_rename(struct inode *old_dir, unsigned char *old_name,
+ 	int err, old_attrs, is_dir, update_dotdot, corrupt = 0;
+ 
+ 	old_sinfo.bh = sinfo.bh = dotdot_bh = NULL;
+-	old_inode = old_dentry->d_inode;
+-	new_inode = new_dentry->d_inode;
++	old_inode = d_inode(old_dentry);
++	new_inode = d_inode(new_dentry);
+ 
+ 	err = fat_scan(old_dir, old_name, &old_sinfo);
+ 	if (err) {
+diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c
+index b8b92c2..7092584 100644
+--- a/fs/fat/namei_vfat.c
++++ b/fs/fat/namei_vfat.c
+@@ -16,10 +16,8 @@
+  */
+ 
+ #include <linux/module.h>
+-#include <linux/jiffies.h>
+ #include <linux/ctype.h>
+ #include <linux/slab.h>
+-#include <linux/buffer_head.h>
+ #include <linux/namei.h>
+ #include "fat.h"
+ 
+@@ -35,7 +33,7 @@ static int vfat_revalidate_shortname(struct dentry *dentry)
+ {
+ 	int ret = 1;
+ 	spin_lock(&dentry->d_lock);
+-	if (dentry->d_time != dentry->d_parent->d_inode->i_version)
++	if (dentry->d_time != d_inode(dentry->d_parent)->i_version)
+ 		ret = 0;
+ 	spin_unlock(&dentry->d_lock);
+ 	return ret;
+@@ -47,7 +45,7 @@ static int vfat_revalidate(struct dentry *dentry, unsigned int flags)
+ 		return -ECHILD;
+ 
+ 	/* This is not negative dentry. Always valid. */
+-	if (dentry->d_inode)
++	if (d_really_is_positive(dentry))
+ 		return 1;
+ 	return vfat_revalidate_shortname(dentry);
+ }
+@@ -67,7 +65,7 @@ static int vfat_revalidate_ci(struct dentry *dentry, unsigned int flags)
+ 	 * positive dentry isn't good idea. So it's unsupported like
+ 	 * rename("filename", "FILENAME") for now.
+ 	 */
+-	if (dentry->d_inode)
++	if (d_really_is_positive(dentry))
+ 		return 1;
+ 
+ 	/*
+@@ -803,7 +801,7 @@ out:
+ 
+ static int vfat_rmdir(struct inode *dir, struct dentry *dentry)
+ {
+-	struct inode *inode = dentry->d_inode;
++	struct inode *inode = d_inode(dentry);
+ 	struct super_block *sb = dir->i_sb;
+ 	struct fat_slot_info sinfo;
+ 	int err;
+@@ -834,7 +832,7 @@ out:
+ 
+ static int vfat_unlink(struct inode *dir, struct dentry *dentry)
+ {
+-	struct inode *inode = dentry->d_inode;
++	struct inode *inode = d_inode(dentry);
+ 	struct super_block *sb = dir->i_sb;
+ 	struct fat_slot_info sinfo;
+ 	int err;
+@@ -917,8 +915,8 @@ static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry,
+ 	struct super_block *sb = old_dir->i_sb;
+ 
+ 	old_sinfo.bh = sinfo.bh = dotdot_bh = NULL;
+-	old_inode = old_dentry->d_inode;
+-	new_inode = new_dentry->d_inode;
++	old_inode = d_inode(old_dentry);
++	new_inode = d_inode(new_dentry);
+ 	mutex_lock(&MSDOS_SB(sb)->s_lock);
+ 	err = vfat_find(old_dir, &old_dentry->d_name, &old_sinfo);
+ 	if (err)
+diff --git a/fs/fat/nfs.c b/fs/fat/nfs.c
+index 93e1493..eb19265 100644
+--- a/fs/fat/nfs.c
++++ b/fs/fat/nfs.c
+@@ -266,7 +266,7 @@ struct inode *fat_rebuild_parent(struct super_block *sb, int parent_logstart)
+  * Find the parent for a directory that is not currently connected to
+  * the filesystem root.
+  *
+- * On entry, the caller holds child_dir->d_inode->i_mutex.
++ * On entry, the caller holds d_inode(child_dir)->i_mutex.
+  */
+ static struct dentry *fat_get_parent(struct dentry *child_dir)
+ {
+@@ -276,7 +276,7 @@ static struct dentry *fat_get_parent(struct dentry *child_dir)
+ 	struct inode *parent_inode = NULL;
+ 	struct msdos_sb_info *sbi = MSDOS_SB(sb);
+ 
+-	if (!fat_get_dotdot_entry(child_dir->d_inode, &bh, &de)) {
++	if (!fat_get_dotdot_entry(d_inode(child_dir), &bh, &de)) {
+ 		int parent_logstart = fat_get_start(sbi, de);
+ 		parent_inode = fat_dget(sb, parent_logstart);
+ 		if (!parent_inode && sbi->options.nfs == FAT_NFS_NOSTALE_RO)
+diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
+index 2d609a5..4bc7cbe 100644
+--- a/fs/fs-writeback.c
++++ b/fs/fs-writeback.c
+@@ -1172,7 +1172,7 @@ void __mark_inode_dirty(struct inode *inode, int flags)
+ 	if ((inode->i_state & flags) == flags)
+ 		return;
+ 
+-	if (unlikely(block_dump))
++	if (unlikely(block_dump > 1))
+ 		block_dump___mark_inode_dirty(inode);
+ 
+ 	spin_lock(&inode->i_lock);
+diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
+index f2bbb85..3f00d67 100644
+--- a/fs/fuse/dev.c
++++ b/fs/fuse/dev.c
+@@ -20,6 +20,7 @@
+ #include <linux/swap.h>
+ #include <linux/splice.h>
+ #include <linux/aio.h>
++#include <linux/freezer.h>
+ 
+ MODULE_ALIAS_MISCDEV(FUSE_MINOR);
+ MODULE_ALIAS("devname:fuse");
+@@ -464,7 +465,10 @@ __acquires(fc->lock)
+ 	 * Wait it out.
+ 	 */
+ 	spin_unlock(&fc->lock);
+-	wait_event(req->waitq, req->state == FUSE_REQ_FINISHED);
++
++	while (req->state != FUSE_REQ_FINISHED)
++		wait_event_freezable(req->waitq,
++				     req->state == FUSE_REQ_FINISHED);
+ 	spin_lock(&fc->lock);
+ 
+ 	if (!req->aborted)
+diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
+index dbab798..40d2409 100644
+--- a/fs/fuse/dir.c
++++ b/fs/fuse/dir.c
+@@ -1693,9 +1693,10 @@ int fuse_flush_times(struct inode *inode, struct fuse_file *ff)
+  * vmtruncate() doesn't allow for this case, so do the rlimit checking
+  * and the actual truncation by hand.
+  */
+-int fuse_do_setattr(struct inode *inode, struct iattr *attr,
++int fuse_do_setattr(struct dentry *entry, struct iattr *attr,
+ 		    struct file *file)
+ {
++	struct inode *inode = entry->d_inode;
+ 	struct fuse_conn *fc = get_fuse_conn(inode);
+ 	struct fuse_inode *fi = get_fuse_inode(inode);
+ 	struct fuse_req *req;
+@@ -1714,6 +1715,10 @@ int fuse_do_setattr(struct inode *inode, struct iattr *attr,
+ 	if (err)
+ 		return err;
+ 
++	err = setattr_killpriv(entry, attr);
++	if (err)
++		return err;
++
+ 	if (attr->ia_valid & ATTR_OPEN) {
+ 		if (fc->atomic_o_trunc)
+ 			return 0;
+@@ -1809,15 +1814,13 @@ error:
+ 
+ static int fuse_setattr(struct dentry *entry, struct iattr *attr)
+ {
+-	struct inode *inode = entry->d_inode;
+-
+-	if (!fuse_allow_current_process(get_fuse_conn(inode)))
++	if (!fuse_allow_current_process(get_fuse_conn(entry->d_inode)))	
+ 		return -EACCES;
+ 
+ 	if (attr->ia_valid & ATTR_FILE)
+-		return fuse_do_setattr(inode, attr, attr->ia_file);
++		return fuse_do_setattr(entry, attr, attr->ia_file);	
+ 	else
+-		return fuse_do_setattr(inode, attr, NULL);
++		return fuse_do_setattr(entry, attr, NULL);
+ }
+ 
+ static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
+diff --git a/fs/fuse/file.c b/fs/fuse/file.c
+index caa8d95..ffdc363 100644
+--- a/fs/fuse/file.c
++++ b/fs/fuse/file.c
+@@ -2855,7 +2855,8 @@ static void fuse_do_truncate(struct file *file)
+ 	attr.ia_file = file;
+ 	attr.ia_valid |= ATTR_FILE;
+ 
+-	fuse_do_setattr(inode, &attr, file);
++	/* XXX Is file->f_dentry->d_inode always the same as inode? */
++	fuse_do_setattr(file->f_dentry, &attr, file);
+ }
+ 
+ static inline loff_t fuse_round_up(loff_t off)
+diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
+index e8e47a6..163de1f 100644
+--- a/fs/fuse/fuse_i.h
++++ b/fs/fuse/fuse_i.h
+@@ -894,7 +894,7 @@ bool fuse_write_update_size(struct inode *inode, loff_t pos);
+ int fuse_flush_times(struct inode *inode, struct fuse_file *ff);
+ int fuse_write_inode(struct inode *inode, struct writeback_control *wbc);
+ 
+-int fuse_do_setattr(struct inode *inode, struct iattr *attr,
++int fuse_do_setattr(struct dentry *entry, struct iattr *attr,
+ 		    struct file *file);
+ 
+ #endif /* _FS_FUSE_I_H */
+diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c
+index 7b31430..88e66aa 100644
+--- a/fs/gfs2/acl.c
++++ b/fs/gfs2/acl.c
+@@ -79,17 +79,11 @@ int gfs2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
+ 	if (type == ACL_TYPE_ACCESS) {
+ 		umode_t mode = inode->i_mode;
+ 
+-		error = posix_acl_equiv_mode(acl, &mode);
+-		if (error < 0)
++		error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
++		if (error)
+ 			return error;
+-
+-		if (error == 0)
+-			acl = NULL;
+-
+-		if (mode != inode->i_mode) {
+-			inode->i_mode = mode;
++		if (mode != inode->i_mode)
+ 			mark_inode_dirty(inode);
+-		}
+ 	}
+ 
+ 	if (acl) {
+diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
+index c4ed823..23ba265 100644
+--- a/fs/gfs2/inode.c
++++ b/fs/gfs2/inode.c
+@@ -1786,6 +1786,10 @@ static int gfs2_setattr(struct dentry *dentry, struct iattr *attr)
+ 	if (error)
+ 		goto out;
+ 
++	error = setattr_killpriv(dentry, attr);
++	if (error)
++		goto out;
++
+ 	if (attr->ia_valid & ATTR_SIZE)
+ 		error = gfs2_setattr_size(inode, attr->ia_size);
+ 	else if (attr->ia_valid & (ATTR_UID | ATTR_GID))
+diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c
+index d0929bc..817f7a5 100644
+--- a/fs/hfs/inode.c
++++ b/fs/hfs/inode.c
+@@ -620,6 +620,10 @@ int hfs_inode_setattr(struct dentry *dentry, struct iattr * attr)
+ 		return hsb->s_quiet ? 0 : error;
+ 	}
+ 
++	error = setattr_killpriv(dentry, attr);
++	if (error)
++		return error;
++
+ 	if (attr->ia_valid & ATTR_MODE) {
+ 		/* Only the 'w' bits can ever change and only all together. */
+ 		if (attr->ia_mode & S_IWUSR)
+diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c
+index 0cf786f..12549bc 100644
+--- a/fs/hfsplus/inode.c
++++ b/fs/hfsplus/inode.c
+@@ -251,6 +251,10 @@ static int hfsplus_setattr(struct dentry *dentry, struct iattr *attr)
+ 	if (error)
+ 		return error;
+ 
++	error = setattr_killpriv(dentry, attr);
++	if (error)
++		return error;
++
+ 	if ((attr->ia_valid & ATTR_SIZE) &&
+ 	    attr->ia_size != i_size_read(inode)) {
+ 		inode_dio_wait(inode);
+diff --git a/fs/hfsplus/posix_acl.c b/fs/hfsplus/posix_acl.c
+index df0c9af..71b3087 100644
+--- a/fs/hfsplus/posix_acl.c
++++ b/fs/hfsplus/posix_acl.c
+@@ -68,8 +68,8 @@ int hfsplus_set_posix_acl(struct inode *inode, struct posix_acl *acl,
+ 	case ACL_TYPE_ACCESS:
+ 		xattr_name = POSIX_ACL_XATTR_ACCESS;
+ 		if (acl) {
+-			err = posix_acl_equiv_mode(acl, &inode->i_mode);
+-			if (err < 0)
++			err = posix_acl_update_mode(inode, &inode->i_mode, &acl);
++			if (err)
+ 				return err;
+ 		}
+ 		err = 0;
+diff --git a/fs/jffs2/acl.c b/fs/jffs2/acl.c
+index 2f7a3c0..f9f86f8 100644
+--- a/fs/jffs2/acl.c
++++ b/fs/jffs2/acl.c
+@@ -235,9 +235,10 @@ int jffs2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
+ 	case ACL_TYPE_ACCESS:
+ 		xprefix = JFFS2_XPREFIX_ACL_ACCESS;
+ 		if (acl) {
+-			umode_t mode = inode->i_mode;
+-			rc = posix_acl_equiv_mode(acl, &mode);
+-			if (rc < 0)
++			umode_t mode;
++
++			rc = posix_acl_update_mode(inode, &mode, &acl);
++			if (rc)
+ 				return rc;
+ 			if (inode->i_mode != mode) {
+ 				struct iattr attr;
+@@ -249,8 +250,6 @@ int jffs2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
+ 				if (rc < 0)
+ 					return rc;
+ 			}
+-			if (rc == 0)
+-				acl = NULL;
+ 		}
+ 		break;
+ 	case ACL_TYPE_DEFAULT:
+diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c
+index 601afd1..b260789 100644
+--- a/fs/jffs2/fs.c
++++ b/fs/jffs2/fs.c
+@@ -197,6 +197,10 @@ int jffs2_setattr(struct dentry *dentry, struct iattr *iattr)
+ 	if (rc)
+ 		return rc;
+ 
++	rc = setattr_killpriv(dentry, iattr);
++	if (rc)
++		return rc;
++
+ 	rc = jffs2_do_setattr(inode, iattr);
+ 	if (!rc && (iattr->ia_valid & ATTR_MODE))
+ 		rc = posix_acl_chmod(inode, inode->i_mode);
+diff --git a/fs/jfs/acl.c b/fs/jfs/acl.c
+index 0c8ca83..9fad9f4 100644
+--- a/fs/jfs/acl.c
++++ b/fs/jfs/acl.c
+@@ -84,13 +84,11 @@ static int __jfs_set_acl(tid_t tid, struct inode *inode, int type,
+ 	case ACL_TYPE_ACCESS:
+ 		ea_name = POSIX_ACL_XATTR_ACCESS;
+ 		if (acl) {
+-			rc = posix_acl_equiv_mode(acl, &inode->i_mode);
+-			if (rc < 0)
++			rc = posix_acl_update_mode(inode, &inode->i_mode, &acl);
++			if (rc)
+ 				return rc;
+ 			inode->i_ctime = CURRENT_TIME;
+ 			mark_inode_dirty(inode);
+-			if (rc == 0)
+-				acl = NULL;
+ 		}
+ 		break;
+ 	case ACL_TYPE_DEFAULT:
+diff --git a/fs/jfs/file.c b/fs/jfs/file.c
+index 33aa0cc..4008313 100644
+--- a/fs/jfs/file.c
++++ b/fs/jfs/file.c
+@@ -107,6 +107,10 @@ int jfs_setattr(struct dentry *dentry, struct iattr *iattr)
+ 	if (rc)
+ 		return rc;
+ 
++	rc = setattr_killpriv(dentry, iattr);
++	if (rc)
++		return rc;
++
+ 	if (is_quota_modification(inode, iattr))
+ 		dquot_initialize(inode);
+ 	if ((iattr->ia_valid & ATTR_UID && !uid_eq(iattr->ia_uid, inode->i_uid)) ||
+diff --git a/fs/kernfs/inode.c b/fs/kernfs/inode.c
+index 9852176..6a70fc5 100644
+--- a/fs/kernfs/inode.c
++++ b/fs/kernfs/inode.c
+@@ -135,6 +135,23 @@ int kernfs_iop_setattr(struct dentry *dentry, struct iattr *iattr)
+ 	if (error)
+ 		goto out;
+ 
++	/*
++	 * If we need to remove privileges, drop the mutex to do that
++	 * first and then re-validate the remaining changes.
++	 */
++	if (iattr->ia_valid & ATTR_KILL_PRIV) {
++		mutex_unlock(&kernfs_mutex);
++
++		error = setattr_killpriv(dentry, iattr);
++		if (error)
++			return error;
++
++		mutex_lock(&kernfs_mutex);
++		error = inode_change_ok(inode, iattr);
++		if (error)
++			goto out;
++	}
++
+ 	error = __kernfs_setattr(kn, iattr);
+ 	if (error)
+ 		goto out;
+diff --git a/fs/libfs.c b/fs/libfs.c
+index 005843c..10afa14 100644
+--- a/fs/libfs.c
++++ b/fs/libfs.c
+@@ -375,6 +375,10 @@ int simple_setattr(struct dentry *dentry, struct iattr *iattr)
+ 	if (error)
+ 		return error;
+ 
++	error = setattr_killpriv(dentry, iattr);
++	if (error)
++		return error;
++
+ 	if (iattr->ia_valid & ATTR_SIZE)
+ 		truncate_setsize(inode, iattr->ia_size);
+ 	setattr_copy(inode, iattr);
+diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
+index 00689a8..5446180 100644
+--- a/fs/nfs/inode.c
++++ b/fs/nfs/inode.c
+@@ -496,7 +496,7 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr)
+ {
+ 	struct inode *inode = dentry->d_inode;
+ 	struct nfs_fattr *fattr;
+-	int error = -ENOMEM;
++	int error;
+ 
+ 	nfs_inc_stats(inode, NFSIOS_VFSSETATTR);
+ 
+@@ -524,9 +524,17 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr)
+ 		nfs_wb_all(inode);
+ 	}
+ 
++	/* XXX Can we assume the server's permission checks are sufficient? */
++	error = setattr_killpriv(dentry, attr);
++	if (error)
++		goto out;
++
+ 	fattr = nfs_alloc_fattr();
+-	if (fattr == NULL)
++	if (fattr == NULL) {
++		error = -ENOMEM;
+ 		goto out;
++	}
++
+ 	/*
+ 	 * Return any delegations if we're going to change ACLs
+ 	 */
+diff --git a/fs/ocfs2/acl.c b/fs/ocfs2/acl.c
+index 7e8282d..eefcacf 100644
+--- a/fs/ocfs2/acl.c
++++ b/fs/ocfs2/acl.c
+@@ -241,20 +241,16 @@ int ocfs2_set_acl(handle_t *handle,
+ 	case ACL_TYPE_ACCESS:
+ 		name_index = OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS;
+ 		if (acl) {
+-			umode_t mode = inode->i_mode;
+-			ret = posix_acl_equiv_mode(acl, &mode);
+-			if (ret < 0)
+-				return ret;
+-			else {
+-				if (ret == 0)
+-					acl = NULL;
++			umode_t mode;
+ 
+-				ret = ocfs2_acl_set_mode(inode, di_bh,
+-							 handle, mode);
+-				if (ret)
+-					return ret;
++			ret = posix_acl_update_mode(inode, &mode, &acl);
++			if (ret)
++				return ret;
+ 
+-			}
++			ret = ocfs2_acl_set_mode(inode, di_bh,
++						 handle, mode);
++			if (ret)
++				return ret;
+ 		}
+ 		break;
+ 	case ACL_TYPE_DEFAULT:
+diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
+index e6e8d64..8d2e7b2 100644
+--- a/fs/ocfs2/file.c
++++ b/fs/ocfs2/file.c
+@@ -1139,7 +1139,7 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
+ 		attr->ia_valid &= ~ATTR_SIZE;
+ 
+ #define OCFS2_VALID_ATTRS (ATTR_ATIME | ATTR_MTIME | ATTR_CTIME | ATTR_SIZE \
+-			   | ATTR_GID | ATTR_UID | ATTR_MODE)
++			   | ATTR_GID | ATTR_UID | ATTR_MODE | ATTR_KILL_PRIV)
+ 	if (!(attr->ia_valid & OCFS2_VALID_ATTRS))
+ 		return 0;
+ 
+@@ -1147,6 +1147,10 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
+ 	if (status)
+ 		return status;
+ 
++	status = setattr_killpriv(dentry, attr);
++	if (status)
++		return status;
++
+ 	if (is_quota_modification(inode, attr))
+ 		dquot_initialize(inode);
+ 	size_change = S_ISREG(inode->i_mode) && attr->ia_valid & ATTR_SIZE;
+diff --git a/fs/open.c b/fs/open.c
+index 4a8a355..200dca8 100644
+--- a/fs/open.c
++++ b/fs/open.c
+@@ -231,8 +231,7 @@ int do_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
+ 		return -EINVAL;
+ 
+ 	/* Return error if mode is not supported */
+-	if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE |
+-		     FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_ZERO_RANGE))
++	if (mode & ~FALLOC_FL_SUPPORTED_MASK)
+ 		return -EOPNOTSUPP;
+ 
+ 	/* Punch hole and zero range are mutually exclusive */
+@@ -249,6 +248,9 @@ int do_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
+ 	if ((mode & FALLOC_FL_COLLAPSE_RANGE) &&
+ 	    (mode & ~FALLOC_FL_COLLAPSE_RANGE))
+ 		return -EINVAL;
++	if ((mode & FALLOC_FL_INSERT_RANGE) &&
++	    (mode & ~FALLOC_FL_INSERT_RANGE))
++		return -EINVAL;
+ 
+ 	if (!(file->f_mode & FMODE_WRITE))
+ 		return -EBADF;
+@@ -295,6 +297,8 @@ int do_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
+ 
+ 	sb_start_write(inode->i_sb);
+ 	ret = file->f_op->fallocate(file, mode, offset, len);
++	if (ret == 0)
++		fsnotify_modify(file);
+ 	sb_end_write(inode->i_sb);
+ 	return ret;
+ }
+diff --git a/fs/pipe.c b/fs/pipe.c
+index 21981e5..e3ba6c3 100644
+--- a/fs/pipe.c
++++ b/fs/pipe.c
+@@ -39,6 +39,12 @@ unsigned int pipe_max_size = 1048576;
+  */
+ unsigned int pipe_min_size = PAGE_SIZE;
+ 
++/* Maximum allocatable pages per user. Hard limit is unset by default, soft
++ * matches default values.
++ */
++unsigned long pipe_user_pages_hard;
++unsigned long pipe_user_pages_soft = PIPE_DEF_BUFFERS * INR_OPEN_CUR;
++
+ /*
+  * We use a start+len construction, which provides full use of the 
+  * allocated memory.
+@@ -585,20 +591,49 @@ pipe_fasync(int fd, struct file *filp, int on)
+ 	return retval;
+ }
+ 
++static void account_pipe_buffers(struct pipe_inode_info *pipe,
++                                 unsigned long old, unsigned long new)
++{
++	atomic_long_add(new - old, &pipe->user->pipe_bufs);
++}
++
++static bool too_many_pipe_buffers_soft(struct user_struct *user)
++{
++	return pipe_user_pages_soft &&
++	       atomic_long_read(&user->pipe_bufs) >= pipe_user_pages_soft;
++}
++
++static bool too_many_pipe_buffers_hard(struct user_struct *user)
++{
++	return pipe_user_pages_hard &&
++	       atomic_long_read(&user->pipe_bufs) >= pipe_user_pages_hard;
++}
++
+ struct pipe_inode_info *alloc_pipe_info(void)
+ {
+ 	struct pipe_inode_info *pipe;
+ 
+ 	pipe = kzalloc(sizeof(struct pipe_inode_info), GFP_KERNEL);
+ 	if (pipe) {
+-		pipe->bufs = kzalloc(sizeof(struct pipe_buffer) * PIPE_DEF_BUFFERS, GFP_KERNEL);
++		unsigned long pipe_bufs = PIPE_DEF_BUFFERS;
++		struct user_struct *user = get_current_user();
++
++		if (!too_many_pipe_buffers_hard(user)) {
++			if (too_many_pipe_buffers_soft(user))
++				pipe_bufs = 1;
++			pipe->bufs = kzalloc(sizeof(struct pipe_buffer) * pipe_bufs, GFP_KERNEL);
++		}
++
+ 		if (pipe->bufs) {
+ 			init_waitqueue_head(&pipe->wait);
+ 			pipe->r_counter = pipe->w_counter = 1;
+-			pipe->buffers = PIPE_DEF_BUFFERS;
++			pipe->buffers = pipe_bufs;
++			pipe->user = user;
++			account_pipe_buffers(pipe, 0, pipe_bufs);
+ 			mutex_init(&pipe->mutex);
+ 			return pipe;
+ 		}
++		free_uid(user);
+ 		kfree(pipe);
+ 	}
+ 
+@@ -609,6 +644,8 @@ void free_pipe_info(struct pipe_inode_info *pipe)
+ {
+ 	int i;
+ 
++	account_pipe_buffers(pipe, pipe->buffers, 0);
++	free_uid(pipe->user);
+ 	for (i = 0; i < pipe->buffers; i++) {
+ 		struct pipe_buffer *buf = pipe->bufs + i;
+ 		if (buf->ops)
+@@ -999,6 +1036,7 @@ static long pipe_set_size(struct pipe_inode_info *pipe, unsigned long nr_pages)
+ 			memcpy(bufs + head, pipe->bufs, tail * sizeof(struct pipe_buffer));
+ 	}
+ 
++	account_pipe_buffers(pipe, pipe->buffers, nr_pages);
+ 	pipe->curbuf = 0;
+ 	kfree(pipe->bufs);
+ 	pipe->bufs = bufs;
+@@ -1070,6 +1108,11 @@ long pipe_fcntl(struct file *file, unsigned int cmd, unsigned long arg)
+ 		if (!capable(CAP_SYS_RESOURCE) && size > pipe_max_size) {
+ 			ret = -EPERM;
+ 			goto out;
++		} else if ((too_many_pipe_buffers_hard(pipe->user) ||
++			    too_many_pipe_buffers_soft(pipe->user)) &&
++		           !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN)) {
++			ret = -EPERM;
++			goto out;
+ 		}
+ 		ret = pipe_set_size(pipe, nr_pages);
+ 		break;
+diff --git a/fs/pnode.c b/fs/pnode.c
+index aae331a..18e56fc 100644
+--- a/fs/pnode.c
++++ b/fs/pnode.c
+@@ -198,10 +198,15 @@ static struct mount *next_group(struct mount *m, struct mount *origin)
+ 
+ /* all accesses are serialized by namespace_sem */
+ static struct user_namespace *user_ns;
+-static struct mount *last_dest, *last_source, *dest_master;
++static struct mount *last_dest, *first_source, *last_source, *dest_master;
+ static struct mountpoint *mp;
+ static struct hlist_head *list;
+ 
++static inline bool peers(struct mount *m1, struct mount *m2)
++{
++	return m1->mnt_group_id == m2->mnt_group_id && m1->mnt_group_id;
++}
++
+ static int propagate_one(struct mount *m)
+ {
+ 	struct mount *child;
+@@ -212,24 +217,26 @@ static int propagate_one(struct mount *m)
+ 	/* skip if mountpoint isn't covered by it */
+ 	if (!is_subdir(mp->m_dentry, m->mnt.mnt_root))
+ 		return 0;
+-	if (m->mnt_group_id == last_dest->mnt_group_id) {
++	if (peers(m, last_dest)) {
+ 		type = CL_MAKE_SHARED;
+ 	} else {
+ 		struct mount *n, *p;
++		bool done;
+ 		for (n = m; ; n = p) {
+ 			p = n->mnt_master;
+-			if (p == dest_master || IS_MNT_MARKED(p)) {
+-				while (last_dest->mnt_master != p) {
+-					last_source = last_source->mnt_master;
+-					last_dest = last_source->mnt_parent;
+-				}
+-				if (n->mnt_group_id != last_dest->mnt_group_id) {
+-					last_source = last_source->mnt_master;
+-					last_dest = last_source->mnt_parent;
+-				}
++			if (p == dest_master || IS_MNT_MARKED(p))
+ 				break;
+-			}
+ 		}
++		do {
++			struct mount *parent = last_source->mnt_parent;
++			if (last_source == first_source)
++				break;
++			done = parent->mnt_master == p;
++			if (done && peers(n, parent))
++				break;
++			last_source = last_source->mnt_master;
++		} while (!done);
++
+ 		type = CL_SLAVE;
+ 		/* beginning of peer group among the slaves? */
+ 		if (IS_MNT_SHARED(m))
+@@ -280,6 +287,7 @@ int propagate_mnt(struct mount *dest_mnt, struct mountpoint *dest_mp,
+ 	 */
+ 	user_ns = current->nsproxy->mnt_ns->user_ns;
+ 	last_dest = dest_mnt;
++	first_source = source_mnt;
+ 	last_source = source_mnt;
+ 	mp = dest_mp;
+ 	list = tree_list;
+diff --git a/fs/posix_acl.c b/fs/posix_acl.c
+index 0855f77..94e6826 100644
+--- a/fs/posix_acl.c
++++ b/fs/posix_acl.c
+@@ -594,6 +594,37 @@ no_acl:
+ }
+ EXPORT_SYMBOL_GPL(posix_acl_create);
+ 
++/**
++ * posix_acl_update_mode  -  update mode in set_acl
++ *
++ * Update the file mode when setting an ACL: compute the new file permission
++ * bits based on the ACL.  In addition, if the ACL is equivalent to the new
++ * file mode, set *acl to NULL to indicate that no ACL should be set.
++ *
++ * As with chmod, clear the setgit bit if the caller is not in the owning group
++ * or capable of CAP_FSETID (see inode_change_ok).
++ *
++ * Called from set_acl inode operations.
++ */
++int posix_acl_update_mode(struct inode *inode, umode_t *mode_p,
++			  struct posix_acl **acl)
++{
++	umode_t mode = inode->i_mode;
++	int error;
++
++	error = posix_acl_equiv_mode(*acl, &mode);
++	if (error < 0)
++		return error;
++	if (error == 0)
++		*acl = NULL;
++	if (!in_group_p(inode->i_gid) &&
++	    !capable_wrt_inode_uidgid(inode, CAP_FSETID))
++		mode &= ~S_ISGID;
++	*mode_p = mode;
++	return 0;
++}
++EXPORT_SYMBOL(posix_acl_update_mode);
++
+ /*
+  * Fix up the uids and gids in posix acl extended attributes in place.
+  */
+@@ -869,11 +900,10 @@ int simple_set_acl(struct inode *inode, struct posix_acl *acl, int type)
+ 	int error;
+ 
+ 	if (type == ACL_TYPE_ACCESS) {
+-		error = posix_acl_equiv_mode(acl, &inode->i_mode);
+-		if (error < 0)
+-			return 0;
+-		if (error == 0)
+-			acl = NULL;
++		error = posix_acl_update_mode(inode,
++				&inode->i_mode, &acl);
++		if (error)
++			return error;
+ 	}
+ 
+ 	inode->i_ctime = CURRENT_TIME;
+diff --git a/fs/proc/base.c b/fs/proc/base.c
+index 7dc3ea8..bbda576 100644
+--- a/fs/proc/base.c
++++ b/fs/proc/base.c
+@@ -752,7 +752,8 @@ static ssize_t environ_read(struct file *file, char __user *buf,
+ 	int ret = 0;
+ 	struct mm_struct *mm = file->private_data;
+ 
+-	if (!mm)
++	/* Ensure the process spawned far enough to have an environment. */
++	if (!mm || !mm->env_end)
+ 		return 0;
+ 
+ 	page = (char *)__get_free_page(GFP_TEMPORARY);
+@@ -2601,8 +2602,8 @@ static const struct pid_entry tgid_base_stuff[] = {
+ 	ONE("cgroup",  S_IRUGO, proc_cgroup_show),
+ #endif
+ 	ONE("oom_score",  S_IRUGO, proc_oom_score),
+-	REG("oom_adj",    S_IRUGO|S_IWUSR, proc_oom_adj_operations),
+-	REG("oom_score_adj", S_IRUGO|S_IWUSR, proc_oom_score_adj_operations),
++	REG("oom_adj",    S_IRUSR, proc_oom_adj_operations),
++	REG("oom_score_adj", S_IRUSR, proc_oom_score_adj_operations),
+ #ifdef CONFIG_AUDITSYSCALL
+ 	REG("loginuid",   S_IWUSR|S_IRUGO, proc_loginuid_operations),
+ 	REG("sessionid",  S_IRUGO, proc_sessionid_operations),
+@@ -2946,8 +2947,8 @@ static const struct pid_entry tid_base_stuff[] = {
+ 	ONE("cgroup",  S_IRUGO, proc_cgroup_show),
+ #endif
+ 	ONE("oom_score", S_IRUGO, proc_oom_score),
+-	REG("oom_adj",   S_IRUGO|S_IWUSR, proc_oom_adj_operations),
+-	REG("oom_score_adj", S_IRUGO|S_IWUSR, proc_oom_score_adj_operations),
++	REG("oom_adj",   S_IRUSR, proc_oom_adj_operations),
++	REG("oom_score_adj", S_IRUSR, proc_oom_score_adj_operations),
+ #ifdef CONFIG_AUDITSYSCALL
+ 	REG("loginuid",  S_IWUSR|S_IRUGO, proc_loginuid_operations),
+ 	REG("sessionid",  S_IRUGO, proc_sessionid_operations),
+diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
+index f92d5dd..f81d63d 100644
+--- a/fs/proc/proc_sysctl.c
++++ b/fs/proc/proc_sysctl.c
+@@ -666,7 +666,7 @@ static int proc_sys_readdir(struct file *file, struct dir_context *ctx)
+ 	ctl_dir = container_of(head, struct ctl_dir, header);
+ 
+ 	if (!dir_emit_dots(file, ctx))
+-		return 0;
++		goto out;
+ 
+ 	pos = 2;
+ 
+@@ -676,6 +676,7 @@ static int proc_sys_readdir(struct file *file, struct dir_context *ctx)
+ 			break;
+ 		}
+ 	}
++out:
+ 	sysctl_head_finish(head);
+ 	return 0;
+ }
+diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
+index 69aa378..23c697e 100644
+--- a/fs/proc/task_mmu.c
++++ b/fs/proc/task_mmu.c
+@@ -111,6 +111,56 @@ static void release_task_mempolicy(struct proc_maps_private *priv)
+ }
+ #endif
+ 
++static void seq_print_vma_name(struct seq_file *m, struct vm_area_struct *vma)
++{
++	const char __user *name = vma_get_anon_name(vma);
++	struct mm_struct *mm = vma->vm_mm;
++
++	unsigned long page_start_vaddr;
++	unsigned long page_offset;
++	unsigned long num_pages;
++	unsigned long max_len = NAME_MAX;
++	int i;
++
++	page_start_vaddr = (unsigned long)name & PAGE_MASK;
++	page_offset = (unsigned long)name - page_start_vaddr;
++	num_pages = DIV_ROUND_UP(page_offset + max_len, PAGE_SIZE);
++
++	seq_puts(m, "[anon:");
++
++	for (i = 0; i < num_pages; i++) {
++		int len;
++		int write_len;
++		const char *kaddr;
++		long pages_pinned;
++		struct page *page;
++
++		pages_pinned = get_user_pages(current, mm, page_start_vaddr,
++				1, 0, 0, &page, NULL);
++		if (pages_pinned < 1) {
++			seq_puts(m, "<fault>]");
++			return;
++		}
++
++		kaddr = (const char *)kmap(page);
++		len = min(max_len, PAGE_SIZE - page_offset);
++		write_len = strnlen(kaddr + page_offset, len);
++		seq_write(m, kaddr + page_offset, write_len);
++		kunmap(page);
++		put_page(page);
++
++		/* if strnlen hit a null terminator then we're done */
++		if (write_len != len)
++			break;
++
++		max_len -= len;
++		page_offset = 0;
++		page_start_vaddr += PAGE_SIZE;
++	}
++
++	seq_putc(m, ']');
++}
++
+ static void vma_stop(struct proc_maps_private *priv)
+ {
+ 	struct mm_struct *mm = priv->mm;
+@@ -346,6 +396,12 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid)
+ 				seq_pad(m, ' ');
+ 				seq_printf(m, "[stack:%d]", tid);
+ 			}
++			goto done;
++		}
++
++		if (vma_get_anon_name(vma)) {
++			seq_pad(m, ' ');
++			seq_print_vma_name(m, vma);
+ 		}
+ 	}
+ 
+@@ -602,6 +658,12 @@ static int show_smap(struct seq_file *m, void *v, int is_pid)
+ 
+ 	show_map_vma(m, vma, is_pid);
+ 
++	if (vma_get_anon_name(vma)) {
++		seq_puts(m, "Name:           ");
++		seq_print_vma_name(m, vma);
++		seq_putc(m, '\n');
++	}
++
+ 	seq_printf(m,
+ 		   "Size:           %8lu kB\n"
+ 		   "Rss:            %8lu kB\n"
+@@ -712,6 +774,7 @@ enum clear_refs_types {
+ 	CLEAR_REFS_ANON,
+ 	CLEAR_REFS_MAPPED,
+ 	CLEAR_REFS_SOFT_DIRTY,
++	CLEAR_REFS_MM_HIWATER_RSS,
+ 	CLEAR_REFS_LAST,
+ };
+ 
+@@ -826,6 +889,18 @@ static ssize_t clear_refs_write(struct file *file, const char __user *buf,
+ 			.mm = mm,
+ 			.private = &cp,
+ 		};
++
++		if (type == CLEAR_REFS_MM_HIWATER_RSS) {
++			/*
++			 * Writing 5 to /proc/pid/clear_refs resets the peak
++			 * resident set size to this mm's current rss value.
++			 */
++			down_write(&mm->mmap_sem);
++			reset_mm_hiwater_rss(mm);
++			up_write(&mm->mmap_sem);
++			goto out_mm;
++		}
++
+ 		down_read(&mm->mmap_sem);
+ 		if (type == CLEAR_REFS_SOFT_DIRTY) {
+ 			for (vma = mm->mmap; vma; vma = vma->vm_next) {
+@@ -868,6 +943,7 @@ static ssize_t clear_refs_write(struct file *file, const char __user *buf,
+ 			mmu_notifier_invalidate_range_end(mm, 0, -1);
+ 		flush_tlb_mm(mm);
+ 		up_read(&mm->mmap_sem);
++out_mm:
+ 		mmput(mm);
+ 	}
+ 	put_task_struct(task);
+diff --git a/fs/pstore/Kconfig b/fs/pstore/Kconfig
+index 983d951..916b8e2 100644
+--- a/fs/pstore/Kconfig
++++ b/fs/pstore/Kconfig
+@@ -21,6 +21,16 @@ config PSTORE_CONSOLE
+ 	  When the option is enabled, pstore will log all kernel
+ 	  messages, even if no oops or panic happened.
+ 
++config PSTORE_PMSG
++	bool "Log user space messages"
++	depends on PSTORE
++	help
++	  When the option is enabled, pstore will export a character
++	  interface /dev/pmsg0 to log user space messages. On reboot
++	  data can be retrieved from /sys/fs/pstore/pmsg-ramoops-[ID].
++
++	  If unsure, say N.
++
+ config PSTORE_FTRACE
+ 	bool "Persistent function tracer"
+ 	depends on PSTORE
+diff --git a/fs/pstore/Makefile b/fs/pstore/Makefile
+index 4c9095c..e647d8e 100644
+--- a/fs/pstore/Makefile
++++ b/fs/pstore/Makefile
+@@ -7,5 +7,7 @@ obj-y += pstore.o
+ pstore-objs += inode.o platform.o
+ obj-$(CONFIG_PSTORE_FTRACE)	+= ftrace.o
+ 
++obj-$(CONFIG_PSTORE_PMSG)	+= pmsg.o
++
+ ramoops-objs += ram.o ram_core.o
+ obj-$(CONFIG_PSTORE_RAM)	+= ramoops.o
+diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c
+index fafb7a0..6dce93c 100644
+--- a/fs/pstore/inode.c
++++ b/fs/pstore/inode.c
+@@ -316,32 +316,38 @@ int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id, int count,
+ 
+ 	switch (type) {
+ 	case PSTORE_TYPE_DMESG:
+-		sprintf(name, "dmesg-%s-%lld%s", psname, id,
+-						compressed ? ".enc.z" : "");
++		scnprintf(name, sizeof(name), "dmesg-%s-%lld%s",
++			  psname, id, compressed ? ".enc.z" : "");
+ 		break;
+ 	case PSTORE_TYPE_CONSOLE:
+-		sprintf(name, "console-%s-%lld", psname, id);
++		scnprintf(name, sizeof(name), "console-%s", psname);
+ 		break;
+ 	case PSTORE_TYPE_FTRACE:
+-		sprintf(name, "ftrace-%s-%lld", psname, id);
++		scnprintf(name, sizeof(name), "ftrace-%s", psname);
+ 		break;
+ 	case PSTORE_TYPE_MCE:
+-		sprintf(name, "mce-%s-%lld", psname, id);
++		scnprintf(name, sizeof(name), "mce-%s-%lld", psname, id);
+ 		break;
+ 	case PSTORE_TYPE_PPC_RTAS:
+-		sprintf(name, "rtas-%s-%lld", psname, id);
++		scnprintf(name, sizeof(name), "rtas-%s-%lld", psname, id);
+ 		break;
+ 	case PSTORE_TYPE_PPC_OF:
+-		sprintf(name, "powerpc-ofw-%s-%lld", psname, id);
++		scnprintf(name, sizeof(name), "powerpc-ofw-%s-%lld",
++			  psname, id);
+ 		break;
+ 	case PSTORE_TYPE_PPC_COMMON:
+-		sprintf(name, "powerpc-common-%s-%lld", psname, id);
++		scnprintf(name, sizeof(name), "powerpc-common-%s-%lld",
++			  psname, id);
++		break;
++	case PSTORE_TYPE_PMSG:
++		scnprintf(name, sizeof(name), "pmsg-%s-%lld", psname, id);
+ 		break;
+ 	case PSTORE_TYPE_UNKNOWN:
+-		sprintf(name, "unknown-%s-%lld", psname, id);
++		scnprintf(name, sizeof(name), "unknown-%s-%lld", psname, id);
+ 		break;
+ 	default:
+-		sprintf(name, "type%d-%s-%lld", type, psname, id);
++		scnprintf(name, sizeof(name), "type%d-%s-%lld",
++			  type, psname, id);
+ 		break;
+ 	}
+ 
+diff --git a/fs/pstore/internal.h b/fs/pstore/internal.h
+index 3b3d305..c36ba2c 100644
+--- a/fs/pstore/internal.h
++++ b/fs/pstore/internal.h
+@@ -45,6 +45,12 @@ extern void pstore_register_ftrace(void);
+ static inline void pstore_register_ftrace(void) {}
+ #endif
+ 
++#ifdef CONFIG_PSTORE_PMSG
++extern void pstore_register_pmsg(void);
++#else
++static inline void pstore_register_pmsg(void) {}
++#endif
++
+ extern struct pstore_info *psinfo;
+ 
+ extern void	pstore_set_kmsg_bytes(int);
+diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c
+index 0a9b72c..15ee78c 100644
+--- a/fs/pstore/platform.c
++++ b/fs/pstore/platform.c
+@@ -447,6 +447,7 @@ int pstore_register(struct pstore_info *psi)
+ 	if ((psi->flags & PSTORE_FLAGS_FRAGILE) == 0) {
+ 		pstore_register_console();
+ 		pstore_register_ftrace();
++		pstore_register_pmsg();
+ 	}
+ 
+ 	if (pstore_update_ms >= 0) {
+diff --git a/fs/pstore/pmsg.c b/fs/pstore/pmsg.c
+new file mode 100644
+index 0000000..5a2f05a
+--- /dev/null
++++ b/fs/pstore/pmsg.c
+@@ -0,0 +1,116 @@
++/*
++ * Copyright 2014  Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/cdev.h>
++#include <linux/device.h>
++#include <linux/fs.h>
++#include <linux/uaccess.h>
++#include <linux/vmalloc.h>
++#include "internal.h"
++
++static DEFINE_MUTEX(pmsg_lock);
++#define PMSG_MAX_BOUNCE_BUFFER_SIZE (2*PAGE_SIZE)
++
++static ssize_t write_pmsg(struct file *file, const char __user *buf,
++			  size_t count, loff_t *ppos)
++{
++	size_t i, buffer_size;
++	char *buffer;
++
++	if (!count)
++		return 0;
++
++	if (!access_ok(VERIFY_READ, buf, count))
++		return -EFAULT;
++
++	buffer_size = count;
++	if (buffer_size > PMSG_MAX_BOUNCE_BUFFER_SIZE)
++		buffer_size = PMSG_MAX_BOUNCE_BUFFER_SIZE;
++	buffer = vmalloc(buffer_size);
++	if (!buffer)
++		return -ENOMEM;
++
++	mutex_lock(&pmsg_lock);
++	for (i = 0; i < count; ) {
++		size_t c = min(count - i, buffer_size);
++		u64 id;
++		long ret;
++
++		ret = __copy_from_user(buffer, buf + i, c);
++		if (unlikely(ret != 0)) {
++			mutex_unlock(&pmsg_lock);
++			vfree(buffer);
++			return -EFAULT;
++		}
++		psinfo->write_buf(PSTORE_TYPE_PMSG, 0, &id, 0, buffer, 0, c,
++				  psinfo);
++
++		i += c;
++	}
++
++	mutex_unlock(&pmsg_lock);
++	vfree(buffer);
++	return count;
++}
++
++static const struct file_operations pmsg_fops = {
++	.owner		= THIS_MODULE,
++	.llseek		= noop_llseek,
++	.write		= write_pmsg,
++};
++
++static struct class *pmsg_class;
++static int pmsg_major;
++#define PMSG_NAME "pmsg"
++#undef pr_fmt
++#define pr_fmt(fmt) PMSG_NAME ": " fmt
++
++static char *pmsg_devnode(struct device *dev, umode_t *mode)
++{
++	if (mode)
++		*mode = 0220;
++	return NULL;
++}
++
++void pstore_register_pmsg(void)
++{
++	struct device *pmsg_device;
++
++	pmsg_major = register_chrdev(0, PMSG_NAME, &pmsg_fops);
++	if (pmsg_major < 0) {
++		pr_err("register_chrdev failed\n");
++		goto err;
++	}
++
++	pmsg_class = class_create(THIS_MODULE, PMSG_NAME);
++	if (IS_ERR(pmsg_class)) {
++		pr_err("device class file already in use\n");
++		goto err_class;
++	}
++	pmsg_class->devnode = pmsg_devnode;
++
++	pmsg_device = device_create(pmsg_class, NULL, MKDEV(pmsg_major, 0),
++					NULL, "%s%d", PMSG_NAME, 0);
++	if (IS_ERR(pmsg_device)) {
++		pr_err("failed to create device\n");
++		goto err_device;
++	}
++	return;
++
++err_device:
++	class_destroy(pmsg_class);
++err_class:
++	unregister_chrdev(pmsg_major, PMSG_NAME);
++err:
++	return;
++}
+diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c
+index 5fa3424..c28dc68 100644
+--- a/fs/pstore/ram.c
++++ b/fs/pstore/ram.c
+@@ -51,6 +51,10 @@ static ulong ramoops_ftrace_size = MIN_MEM_SIZE;
+ module_param_named(ftrace_size, ramoops_ftrace_size, ulong, 0400);
+ MODULE_PARM_DESC(ftrace_size, "size of ftrace log");
+ 
++static ulong ramoops_pmsg_size = MIN_MEM_SIZE;
++module_param_named(pmsg_size, ramoops_pmsg_size, ulong, 0400);
++MODULE_PARM_DESC(pmsg_size, "size of user space message log");
++
+ static ulong mem_address;
+ module_param(mem_address, ulong, 0400);
+ MODULE_PARM_DESC(mem_address,
+@@ -82,12 +86,14 @@ struct ramoops_context {
+ 	struct persistent_ram_zone **przs;
+ 	struct persistent_ram_zone *cprz;
+ 	struct persistent_ram_zone *fprz;
++	struct persistent_ram_zone *mprz;
+ 	phys_addr_t phys_addr;
+ 	unsigned long size;
+ 	unsigned int memtype;
+ 	size_t record_size;
+ 	size_t console_size;
+ 	size_t ftrace_size;
++	size_t pmsg_size;
+ 	int dump_oops;
+ 	struct persistent_ram_ecc_info ecc_info;
+ 	unsigned int max_dump_cnt;
+@@ -96,6 +102,7 @@ struct ramoops_context {
+ 	unsigned int dump_read_cnt;
+ 	unsigned int console_read_cnt;
+ 	unsigned int ftrace_read_cnt;
++	unsigned int pmsg_read_cnt;
+ 	struct pstore_info pstore;
+ };
+ 
+@@ -109,6 +116,7 @@ static int ramoops_pstore_open(struct pstore_info *psi)
+ 	cxt->dump_read_cnt = 0;
+ 	cxt->console_read_cnt = 0;
+ 	cxt->ftrace_read_cnt = 0;
++	cxt->pmsg_read_cnt = 0;
+ 	return 0;
+ }
+ 
+@@ -162,6 +170,12 @@ static void ramoops_read_kmsg_hdr(char *buffer, struct timespec *time,
+ 	}
+ }
+ 
++static bool prz_ok(struct persistent_ram_zone *prz)
++{
++	return !!prz && !!(persistent_ram_old_size(prz) +
++			   persistent_ram_ecc_string(prz, NULL, 0));
++}
++
+ static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type,
+ 				   int *count, struct timespec *time,
+ 				   char **buf, bool *compressed,
+@@ -175,13 +189,16 @@ static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type,
+ 	prz = ramoops_get_next_prz(cxt->przs, &cxt->dump_read_cnt,
+ 				   cxt->max_dump_cnt, id, type,
+ 				   PSTORE_TYPE_DMESG, 1);
+-	if (!prz)
++	if (!prz_ok(prz))
+ 		prz = ramoops_get_next_prz(&cxt->cprz, &cxt->console_read_cnt,
+ 					   1, id, type, PSTORE_TYPE_CONSOLE, 0);
+-	if (!prz)
++	if (!prz_ok(prz))
+ 		prz = ramoops_get_next_prz(&cxt->fprz, &cxt->ftrace_read_cnt,
+ 					   1, id, type, PSTORE_TYPE_FTRACE, 0);
+-	if (!prz)
++	if (!prz_ok(prz))
++		prz = ramoops_get_next_prz(&cxt->mprz, &cxt->pmsg_read_cnt,
++					   1, id, type, PSTORE_TYPE_PMSG, 0);
++	if (!prz_ok(prz))
+ 		return 0;
+ 
+ 	size = persistent_ram_old_size(prz);
+@@ -244,6 +261,11 @@ static int notrace ramoops_pstore_write_buf(enum pstore_type_id type,
+ 			return -ENOMEM;
+ 		persistent_ram_write(cxt->fprz, buf, size);
+ 		return 0;
++	} else if (type == PSTORE_TYPE_PMSG) {
++		if (!cxt->mprz)
++			return -ENOMEM;
++		persistent_ram_write(cxt->mprz, buf, size);
++		return 0;
+ 	}
+ 
+ 	if (type != PSTORE_TYPE_DMESG)
+@@ -301,6 +323,9 @@ static int ramoops_pstore_erase(enum pstore_type_id type, u64 id, int count,
+ 	case PSTORE_TYPE_FTRACE:
+ 		prz = cxt->fprz;
+ 		break;
++	case PSTORE_TYPE_PMSG:
++		prz = cxt->mprz;
++		break;
+ 	default:
+ 		return -EINVAL;
+ 	}
+@@ -411,6 +436,12 @@ static int ramoops_init_prz(struct device *dev, struct ramoops_context *cxt,
+ 	return 0;
+ }
+ 
++void notrace ramoops_console_write_buf(const char *buf, size_t size)
++{
++	struct ramoops_context *cxt = &oops_cxt;
++	persistent_ram_write(cxt->cprz, buf, size);
++}
++
+ static int ramoops_probe(struct platform_device *pdev)
+ {
+ 	struct device *dev = &pdev->dev;
+@@ -427,7 +458,7 @@ static int ramoops_probe(struct platform_device *pdev)
+ 		goto fail_out;
+ 
+ 	if (!pdata->mem_size || (!pdata->record_size && !pdata->console_size &&
+-			!pdata->ftrace_size)) {
++			!pdata->ftrace_size && !pdata->pmsg_size)) {
+ 		pr_err("The memory size and the record/console size must be "
+ 			"non-zero\n");
+ 		goto fail_out;
+@@ -439,6 +470,8 @@ static int ramoops_probe(struct platform_device *pdev)
+ 		pdata->console_size = rounddown_pow_of_two(pdata->console_size);
+ 	if (pdata->ftrace_size && !is_power_of_2(pdata->ftrace_size))
+ 		pdata->ftrace_size = rounddown_pow_of_two(pdata->ftrace_size);
++	if (pdata->pmsg_size && !is_power_of_2(pdata->pmsg_size))
++		pdata->pmsg_size = rounddown_pow_of_two(pdata->pmsg_size);
+ 
+ 	cxt->size = pdata->mem_size;
+ 	cxt->phys_addr = pdata->mem_address;
+@@ -446,12 +479,14 @@ static int ramoops_probe(struct platform_device *pdev)
+ 	cxt->record_size = pdata->record_size;
+ 	cxt->console_size = pdata->console_size;
+ 	cxt->ftrace_size = pdata->ftrace_size;
++	cxt->pmsg_size = pdata->pmsg_size;
+ 	cxt->dump_oops = pdata->dump_oops;
+ 	cxt->ecc_info = pdata->ecc_info;
+ 
+ 	paddr = cxt->phys_addr;
+ 
+-	dump_mem_sz = cxt->size - cxt->console_size - cxt->ftrace_size;
++	dump_mem_sz = cxt->size - cxt->console_size - cxt->ftrace_size
++			- cxt->pmsg_size;
+ 	err = ramoops_init_przs(dev, cxt, &paddr, dump_mem_sz);
+ 	if (err)
+ 		goto fail_out;
+@@ -466,13 +501,9 @@ static int ramoops_probe(struct platform_device *pdev)
+ 	if (err)
+ 		goto fail_init_fprz;
+ 
+-	if (!cxt->przs && !cxt->cprz && !cxt->fprz) {
+-		pr_err("memory size too small, minimum is %zu\n",
+-			cxt->console_size + cxt->record_size +
+-			cxt->ftrace_size);
+-		err = -EINVAL;
+-		goto fail_cnt;
+-	}
++	err = ramoops_init_prz(dev, cxt, &cxt->mprz, &paddr, cxt->pmsg_size, 0);
++	if (err)
++		goto fail_init_mprz;
+ 
+ 	cxt->pstore.data = cxt;
+ 	/*
+@@ -517,7 +548,9 @@ fail_buf:
+ 	kfree(cxt->pstore.buf);
+ fail_clear:
+ 	cxt->pstore.bufsize = 0;
+-fail_cnt:
++	cxt->max_dump_cnt = 0;
++	kfree(cxt->mprz);
++fail_init_mprz:
+ 	kfree(cxt->fprz);
+ fail_init_fprz:
+ 	kfree(cxt->cprz);
+@@ -576,6 +609,7 @@ static void ramoops_register_dummy(void)
+ 	dummy_data->record_size = record_size;
+ 	dummy_data->console_size = ramoops_console_size;
+ 	dummy_data->ftrace_size = ramoops_ftrace_size;
++	dummy_data->pmsg_size = ramoops_pmsg_size;
+ 	dummy_data->dump_oops = dump_oops;
+ 	/*
+ 	 * For backwards compatibility ramoops.ecc=1 means 16 bytes ECC
+diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c
+index a7eec98..a458c12 100644
+--- a/fs/reiserfs/inode.c
++++ b/fs/reiserfs/inode.c
+@@ -3316,6 +3316,10 @@ int reiserfs_setattr(struct dentry *dentry, struct iattr *attr)
+ 	if (error)
+ 		return error;
+ 
++	error = setattr_killpriv(dentry, attr);
++	if (error)
++		return error;
++
+ 	/* must be turned off for recursive notify_change calls */
+ 	ia_valid = attr->ia_valid &= ~(ATTR_KILL_SUID|ATTR_KILL_SGID);
+ 
+diff --git a/fs/reiserfs/xattr_acl.c b/fs/reiserfs/xattr_acl.c
+index 4b34b9d..9b1824f 100644
+--- a/fs/reiserfs/xattr_acl.c
++++ b/fs/reiserfs/xattr_acl.c
+@@ -246,13 +246,9 @@ __reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode,
+ 	case ACL_TYPE_ACCESS:
+ 		name = POSIX_ACL_XATTR_ACCESS;
+ 		if (acl) {
+-			error = posix_acl_equiv_mode(acl, &inode->i_mode);
+-			if (error < 0)
++			error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
++			if (error)
+ 				return error;
+-			else {
+-				if (error == 0)
+-					acl = NULL;
+-			}
+ 		}
+ 		break;
+ 	case ACL_TYPE_DEFAULT:
+diff --git a/fs/super.c b/fs/super.c
+index eae088f..cdf6dec 100644
+--- a/fs/super.c
++++ b/fs/super.c
+@@ -769,7 +769,7 @@ static void do_emergency_remount(struct work_struct *work)
+ 	struct super_block *sb, *p = NULL;
+ 
+ 	spin_lock(&sb_lock);
+-	list_for_each_entry(sb, &super_blocks, s_list) {
++	list_for_each_entry_reverse(sb, &super_blocks, s_list) {
+ 		if (hlist_unhashed(&sb->s_instances))
+ 			continue;
+ 		sb->s_count++;
+diff --git a/fs/timerfd.c b/fs/timerfd.c
+index b46ffa9..21ea542 100644
+--- a/fs/timerfd.c
++++ b/fs/timerfd.c
+@@ -40,6 +40,7 @@ struct timerfd_ctx {
+ 	short unsigned settime_flags;	/* to show in fdinfo */
+ 	struct rcu_head rcu;
+ 	struct list_head clist;
++	spinlock_t cancel_lock;
+ 	bool might_cancel;
+ };
+ 
+@@ -112,7 +113,7 @@ void timerfd_clock_was_set(void)
+ 	rcu_read_unlock();
+ }
+ 
+-static void timerfd_remove_cancel(struct timerfd_ctx *ctx)
++static void __timerfd_remove_cancel(struct timerfd_ctx *ctx)
+ {
+ 	if (ctx->might_cancel) {
+ 		ctx->might_cancel = false;
+@@ -122,6 +123,13 @@ static void timerfd_remove_cancel(struct timerfd_ctx *ctx)
+ 	}
+ }
+ 
++static void timerfd_remove_cancel(struct timerfd_ctx *ctx)
++{
++	spin_lock(&ctx->cancel_lock);
++	__timerfd_remove_cancel(ctx);
++	spin_unlock(&ctx->cancel_lock);
++}
++
+ static bool timerfd_canceled(struct timerfd_ctx *ctx)
+ {
+ 	if (!ctx->might_cancel || ctx->moffs.tv64 != KTIME_MAX)
+@@ -132,6 +140,7 @@ static bool timerfd_canceled(struct timerfd_ctx *ctx)
+ 
+ static void timerfd_setup_cancel(struct timerfd_ctx *ctx, int flags)
+ {
++	spin_lock(&ctx->cancel_lock);
+ 	if ((ctx->clockid == CLOCK_REALTIME ||
+ 	     ctx->clockid == CLOCK_REALTIME_ALARM) &&
+ 	    (flags & TFD_TIMER_ABSTIME) && (flags & TFD_TIMER_CANCEL_ON_SET)) {
+@@ -141,9 +150,10 @@ static void timerfd_setup_cancel(struct timerfd_ctx *ctx, int flags)
+ 			list_add_rcu(&ctx->clist, &cancel_list);
+ 			spin_unlock(&cancel_lock);
+ 		}
+-	} else if (ctx->might_cancel) {
+-		timerfd_remove_cancel(ctx);
++	} else {
++		__timerfd_remove_cancel(ctx);
+ 	}
++	spin_unlock(&ctx->cancel_lock);
+ }
+ 
+ static ktime_t timerfd_get_remaining(struct timerfd_ctx *ctx)
+@@ -394,6 +404,7 @@ SYSCALL_DEFINE2(timerfd_create, int, clockid, int, flags)
+ 		return -ENOMEM;
+ 
+ 	init_waitqueue_head(&ctx->wqh);
++	spin_lock_init(&ctx->cancel_lock);
+ 	ctx->clockid = clockid;
+ 
+ 	if (isalarm(ctx))
+@@ -414,7 +425,7 @@ SYSCALL_DEFINE2(timerfd_create, int, clockid, int, flags)
+ 	return ufd;
+ }
+ 
+-static int do_timerfd_settime(int ufd, int flags, 
++static int do_timerfd_settime(int ufd, int flags,
+ 		const struct itimerspec *new,
+ 		struct itimerspec *old)
+ {
+diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c
+index b5b593c..73d2e87 100644
+--- a/fs/ubifs/file.c
++++ b/fs/ubifs/file.c
+@@ -1269,6 +1269,10 @@ int ubifs_setattr(struct dentry *dentry, struct iattr *attr)
+ 	if (err)
+ 		return err;
+ 
++	err = setattr_killpriv(dentry, attr);
++	if (err)
++		return err;
++
+ 	if ((attr->ia_valid & ATTR_SIZE) && attr->ia_size < inode->i_size)
+ 		/* Truncation to a smaller size */
+ 		err = do_truncation(c, inode, attr);
+diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c
+index a65fa5d..90d6d8a 100644
+--- a/fs/xfs/xfs_acl.c
++++ b/fs/xfs/xfs_acl.c
+@@ -244,7 +244,8 @@ xfs_set_mode(struct inode *inode, umode_t mode)
+ 		iattr.ia_mode = mode;
+ 		iattr.ia_ctime = current_fs_time(inode->i_sb);
+ 
+-		error = xfs_setattr_nonsize(XFS_I(inode), &iattr, XFS_ATTR_NOACL);
++		error = xfs_setattr_nonsize(NULL, XFS_I(inode), &iattr,
++					    XFS_ATTR_NOACL);
+ 	}
+ 
+ 	return error;
+@@ -286,16 +287,11 @@ xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
+ 		return error;
+ 
+ 	if (type == ACL_TYPE_ACCESS) {
+-		umode_t mode = inode->i_mode;
+-		error = posix_acl_equiv_mode(acl, &mode);
+-
+-		if (error <= 0) {
+-			acl = NULL;
+-
+-			if (error < 0)
+-				return error;
+-		}
++		umode_t mode;
+ 
++		error = posix_acl_update_mode(inode, &mode, &acl);
++		if (error)
++			return error;
+ 		error = xfs_set_mode(inode, mode);
+ 		if (error)
+ 			return error;
+diff --git a/fs/xfs/xfs_attr_list.c b/fs/xfs/xfs_attr_list.c
+index 62db83a..ae64625 100644
+--- a/fs/xfs/xfs_attr_list.c
++++ b/fs/xfs/xfs_attr_list.c
+@@ -205,8 +205,10 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context)
+ 					sbp->namelen,
+ 					sbp->valuelen,
+ 					&sbp->name[sbp->namelen]);
+-		if (error)
++		if (error) {
++			kmem_free(sbuf);
+ 			return error;
++		}
+ 		if (context->seen_enough)
+ 			break;
+ 		cursor->offset++;
+@@ -454,14 +456,13 @@ xfs_attr3_leaf_list_int(
+ 				args.rmtblkcnt = xfs_attr3_rmt_blocks(
+ 							args.dp->i_mount, valuelen);
+ 				retval = xfs_attr_rmtval_get(&args);
+-				if (retval)
+-					return retval;
+-				retval = context->put_listent(context,
+-						entry->flags,
+-						name_rmt->name,
+-						(int)name_rmt->namelen,
+-						valuelen,
+-						args.value);
++				if (!retval)
++					retval = context->put_listent(context,
++							entry->flags,
++							name_rmt->name,
++							(int)name_rmt->namelen,
++							valuelen,
++							args.value);
+ 				kmem_free(args.value);
+ 			} else {
+ 				retval = context->put_listent(context,
+diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
+index ba8b158..a1295b0 100644
+--- a/fs/xfs/xfs_file.c
++++ b/fs/xfs/xfs_file.c
+@@ -879,7 +879,7 @@ xfs_file_fallocate(
+ 
+ 		iattr.ia_valid = ATTR_SIZE;
+ 		iattr.ia_size = new_size;
+-		error = xfs_setattr_size(ip, &iattr);
++		error = xfs_setattr_size(NULL, ip, &iattr);
+ 	}
+ 
+ out_unlock:
+diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
+index 24c926b..3e0dc56 100644
+--- a/fs/xfs/xfs_ioctl.c
++++ b/fs/xfs/xfs_ioctl.c
+@@ -714,7 +714,7 @@ xfs_ioc_space(
+ 		iattr.ia_valid = ATTR_SIZE;
+ 		iattr.ia_size = bf->l_start;
+ 
+-		error = xfs_setattr_size(ip, &iattr);
++		error = xfs_setattr_size(NULL, ip, &iattr);
+ 		if (!error)
+ 			clrprealloc = true;
+ 		break;
+diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
+index d2273d2..129d03c 100644
+--- a/fs/xfs/xfs_iops.c
++++ b/fs/xfs/xfs_iops.c
+@@ -527,6 +527,7 @@ xfs_setattr_time(
+ 
+ int
+ xfs_setattr_nonsize(
++	struct dentry		*dentry,
+ 	struct xfs_inode	*ip,
+ 	struct iattr		*iattr,
+ 	int			flags)
+@@ -554,6 +555,11 @@ xfs_setattr_nonsize(
+ 		error = inode_change_ok(inode, iattr);
+ 		if (error)
+ 			return error;
++
++
++		error = setattr_killpriv(dentry, iattr);
++		if (error)
++			return error;
+ 	}
+ 
+ 	ASSERT((mask & ATTR_SIZE) == 0);
+@@ -734,6 +740,7 @@ out_dqrele:
+  */
+ int
+ xfs_setattr_size(
++	struct dentry		*dentry,
+ 	struct xfs_inode	*ip,
+ 	struct iattr		*iattr)
+ {
+@@ -777,9 +784,13 @@ xfs_setattr_size(
+ 		 * Use the regular setattr path to update the timestamps.
+ 		 */
+ 		iattr->ia_valid &= ~ATTR_SIZE;
+-		return xfs_setattr_nonsize(ip, iattr, 0);
++		return xfs_setattr_nonsize(dentry, ip, iattr, 0);
+ 	}
+ 
++	error = setattr_killpriv(dentry, iattr);
++	if (error)
++		return error;
++	
+ 	/*
+ 	 * Make sure that the dquots are attached to the inode.
+ 	 */
+@@ -966,10 +977,10 @@ xfs_vn_setattr(
+ 
+ 	if (iattr->ia_valid & ATTR_SIZE) {
+ 		xfs_ilock(ip, XFS_IOLOCK_EXCL);
+-		error = xfs_setattr_size(ip, iattr);
++		error = xfs_setattr_size(dentry, ip, iattr);
+ 		xfs_iunlock(ip, XFS_IOLOCK_EXCL);
+ 	} else {
+-		error = xfs_setattr_nonsize(ip, iattr, 0);
++		error = xfs_setattr_nonsize(dentry, ip, iattr, 0);
+ 	}
+ 
+ 	return error;
+diff --git a/fs/xfs/xfs_iops.h b/fs/xfs/xfs_iops.h
+index 1c34e43..04cd5da 100644
+--- a/fs/xfs/xfs_iops.h
++++ b/fs/xfs/xfs_iops.h
+@@ -32,8 +32,14 @@ extern void xfs_setup_inode(struct xfs_inode *);
+  */
+ #define XFS_ATTR_NOACL		0x01	/* Don't call posix_acl_chmod */
+ 
+-extern int xfs_setattr_nonsize(struct xfs_inode *ip, struct iattr *vap,
+-			       int flags);
+-extern int xfs_setattr_size(struct xfs_inode *ip, struct iattr *vap);
++/*
++ * XXX Several callers have to pass dentry = NULL and this should
++ * work but it's really ugly.
++ */
++extern int xfs_setattr_nonsize(struct dentry *dentry,
++			       struct xfs_inode *ip, struct iattr *vap,
++ 			       int flags);
+ 
++extern int xfs_setattr_size(struct dentry *dentry,
++			    struct xfs_inode *ip, struct iattr *vap);
+ #endif /* __XFS_IOPS_H__ */
+diff --git a/fs/yaffs2/Kconfig b/fs/yaffs2/Kconfig
+new file mode 100644
+index 0000000..408570f
+--- /dev/null
++++ b/fs/yaffs2/Kconfig
+@@ -0,0 +1,171 @@
++#
++# yaffs file system configurations
++#
++
++config YAFFS_FS
++	tristate "yaffs2 file system support"
++	default n
++	depends on MTD_BLOCK
++	select YAFFS_YAFFS1
++	select YAFFS_YAFFS2
++	help
++	  yaffs2, or Yet Another Flash File System, is a file system
++	  optimised for NAND Flash chips.
++
++	  To compile the yaffs2 file system support as a module, choose M
++	  here: the module will be called yaffs2.
++
++	  If unsure, say N.
++
++	  Further information on yaffs2 is available at
++	  <http://www.aleph1.co.uk/yaffs/>.
++
++config YAFFS_YAFFS1
++	bool "512 byte / page devices"
++	depends on YAFFS_FS
++	default y
++	help
++	  Enable yaffs1 support -- yaffs for 512 byte / page devices
++
++	  Not needed for 2K-page devices.
++
++	  If unsure, say Y.
++
++config YAFFS_9BYTE_TAGS
++	bool "Use older-style on-NAND data format with pageStatus byte"
++	depends on YAFFS_YAFFS1
++	default n
++	help
++
++	  Older-style on-NAND data format has a "pageStatus" byte to record
++	  chunk/page state.  This byte is zero when the page is discarded.
++	  Choose this option if you have existing on-NAND data using this
++	  format that you need to continue to support.  New data written
++	  also uses the older-style format.  Note: Use of this option
++	  generally requires that MTD's oob layout be adjusted to use the
++	  older-style format.  See notes on tags formats and MTD versions
++	  in yaffs_mtdif1.c.
++
++	  If unsure, say N.
++
++config YAFFS_DOES_ECC
++	bool "Lets yaffs do its own ECC"
++	depends on YAFFS_FS && YAFFS_YAFFS1 && !YAFFS_9BYTE_TAGS
++	default n
++	help
++	  This enables yaffs to use its own ECC functions instead of using
++	  the ones from the generic MTD-NAND driver.
++
++	  If unsure, say N.
++
++config YAFFS_ECC_WRONG_ORDER
++	bool "Use the same ecc byte order as Steven Hill's nand_ecc.c"
++	depends on YAFFS_FS && YAFFS_DOES_ECC && !YAFFS_9BYTE_TAGS
++	default n
++	help
++	  This makes yaffs_ecc.c use the same ecc byte order as Steven
++	  Hill's nand_ecc.c. If not set, then you get the same ecc byte
++	  order as SmartMedia.
++
++	  If unsure, say N.
++
++config YAFFS_YAFFS2
++	bool "2048 byte (or larger) / page devices"
++	depends on YAFFS_FS
++	default y
++	help
++	  Enable yaffs2 support -- yaffs for >= 2K bytes per page devices
++
++	  If unsure, say Y.
++
++config YAFFS_AUTO_YAFFS2
++	bool "Autoselect yaffs2 format"
++	depends on YAFFS_YAFFS2
++	default y
++	help
++	  Without this, you need to explicitely use yaffs2 as the file
++	  system type. With this, you can say "yaffs" and yaffs or yaffs2
++	  will be used depending on the device page size (yaffs on
++	  512-byte page devices, yaffs2 on 2K page devices).
++
++	  If unsure, say Y.
++
++config YAFFS_DISABLE_TAGS_ECC
++	bool "Disable yaffs from doing ECC on tags by default"
++	depends on YAFFS_FS && YAFFS_YAFFS2
++	default n
++	help
++	  This defaults yaffs to using its own ECC calculations on tags instead of
++	  just relying on the MTD.
++	  This behavior can also be overridden with tags_ecc_on and
++	  tags_ecc_off mount options.
++
++	  If unsure, say N.
++
++config YAFFS_ALWAYS_CHECK_CHUNK_ERASED
++	bool "Force chunk erase check"
++	depends on YAFFS_FS
++	default n
++	help
++          Normally yaffs only checks chunks before writing until an erased
++	  chunk is found. This helps to detect any partially written
++	  chunks that might have happened due to power loss.
++
++	  Enabling this forces on the test that chunks are erased in flash
++	  before writing to them. This takes more time but is potentially
++	  a bit more secure.
++
++	  Suggest setting Y during development and ironing out driver
++	  issues etc. Suggest setting to N if you want faster writing.
++
++	  If unsure, say Y.
++
++config YAFFS_EMPTY_LOST_AND_FOUND
++	bool "Empty lost and found on boot"
++	depends on YAFFS_FS
++	default n
++	help
++	  If this is enabled then the contents of lost and found is
++	  automatically dumped at mount.
++
++	  If unsure, say N.
++
++config YAFFS_DISABLE_BLOCK_REFRESHING
++	bool "Disable yaffs2 block refreshing"
++	depends on YAFFS_FS
++	default n
++	help
++	 If this is set, then block refreshing is disabled.
++	 Block refreshing infrequently refreshes the oldest block in
++	 a yaffs2 file system. This mechanism helps to refresh flash to
++	 mitigate against data loss. This is particularly useful for MLC.
++
++	  If unsure, say N.
++
++config YAFFS_DISABLE_BACKGROUND
++	bool "Disable yaffs2 background processing"
++	depends on YAFFS_FS
++	default n
++	help
++	 If this is set, then background processing is disabled.
++	 Background processing makes many foreground activities faster.
++
++	 If unsure, say N.
++
++config YAFFS_DISABLE_BAD_BLOCK_MARKING
++	bool "Disable yaffs2 bad block marking"
++	depends on YAFFS_FS
++	default n
++	help
++	 Useful during early flash bring up to prevent problems causing
++	 lots of bad block marking.
++
++	 If unsure, say N.
++
++config YAFFS_XATTR
++	bool "Enable yaffs2 xattr support"
++	depends on YAFFS_FS
++	default y
++	help
++	 If this is set then yaffs2 will provide xattr support.
++	 If unsure, say Y.
+diff --git a/fs/yaffs2/Makefile b/fs/yaffs2/Makefile
+new file mode 100644
+index 0000000..7a10847
+--- /dev/null
++++ b/fs/yaffs2/Makefile
+@@ -0,0 +1,17 @@
++#
++# Makefile for the linux YAFFS filesystem routines.
++#
++
++obj-$(CONFIG_YAFFS_FS) += yaffs.o
++
++yaffs-y := yaffs_ecc.o yaffs_vfs.o yaffs_guts.o yaffs_checkptrw.o
++yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o
++yaffs-y += yaffs_tagscompat.o yaffs_tagsmarshall.o
++yaffs-y += yaffs_mtdif.o
++yaffs-y += yaffs_nameval.o yaffs_attribs.o
++yaffs-y += yaffs_allocator.o
++yaffs-y += yaffs_yaffs1.o
++yaffs-y += yaffs_yaffs2.o
++yaffs-y += yaffs_bitmap.o
++yaffs-y += yaffs_summary.o
++yaffs-y += yaffs_verify.o
+diff --git a/fs/yaffs2/yaffs_allocator.c b/fs/yaffs2/yaffs_allocator.c
+new file mode 100644
+index 0000000..611061f
+--- /dev/null
++++ b/fs/yaffs2/yaffs_allocator.c
+@@ -0,0 +1,356 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ *   for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * 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 "yaffs_allocator.h"
++#include "yaffs_guts.h"
++#include "yaffs_trace.h"
++#include "yportenv.h"
++
++/*
++ * Each entry in yaffs_tnode_list and yaffs_obj_list hold blocks
++ * of approx 100 objects that are themn allocated singly.
++ * This is basically a simplified slab allocator.
++ *
++ * We don't use the Linux slab allocator because slab does not allow
++ * us to dump all the objects in one hit when we do a umount and tear
++ * down  all the tnodes and objects. slab requires that we first free
++ * the individual objects.
++ *
++ * Once yaffs has been mainlined I shall try to motivate for a change
++ * to slab to provide the extra features we need here.
++ */
++
++struct yaffs_tnode_list {
++	struct yaffs_tnode_list *next;
++	struct yaffs_tnode *tnodes;
++};
++
++struct yaffs_obj_list {
++	struct yaffs_obj_list *next;
++	struct yaffs_obj *objects;
++};
++
++struct yaffs_allocator {
++	int n_tnodes_created;
++	struct yaffs_tnode *free_tnodes;
++	int n_free_tnodes;
++	struct yaffs_tnode_list *alloc_tnode_list;
++
++	int n_obj_created;
++	struct list_head free_objs;
++	int n_free_objects;
++
++	struct yaffs_obj_list *allocated_obj_list;
++};
++
++static void yaffs_deinit_raw_tnodes(struct yaffs_dev *dev)
++{
++	struct yaffs_allocator *allocator =
++	    (struct yaffs_allocator *)dev->allocator;
++	struct yaffs_tnode_list *tmp;
++
++	if (!allocator) {
++		BUG();
++		return;
++	}
++
++	while (allocator->alloc_tnode_list) {
++		tmp = allocator->alloc_tnode_list->next;
++
++		kfree(allocator->alloc_tnode_list->tnodes);
++		kfree(allocator->alloc_tnode_list);
++		allocator->alloc_tnode_list = tmp;
++	}
++
++	allocator->free_tnodes = NULL;
++	allocator->n_free_tnodes = 0;
++	allocator->n_tnodes_created = 0;
++}
++
++static void yaffs_init_raw_tnodes(struct yaffs_dev *dev)
++{
++	struct yaffs_allocator *allocator = dev->allocator;
++
++	if (!allocator) {
++		BUG();
++		return;
++	}
++
++	allocator->alloc_tnode_list = NULL;
++	allocator->free_tnodes = NULL;
++	allocator->n_free_tnodes = 0;
++	allocator->n_tnodes_created = 0;
++}
++
++static int yaffs_create_tnodes(struct yaffs_dev *dev, int n_tnodes)
++{
++	struct yaffs_allocator *allocator =
++	    (struct yaffs_allocator *)dev->allocator;
++	int i;
++	struct yaffs_tnode *new_tnodes;
++	u8 *mem;
++	struct yaffs_tnode *curr;
++	struct yaffs_tnode *next;
++	struct yaffs_tnode_list *tnl;
++
++	if (!allocator) {
++		BUG();
++		return YAFFS_FAIL;
++	}
++
++	if (n_tnodes < 1)
++		return YAFFS_OK;
++
++	/* make these things */
++	new_tnodes = kmalloc(n_tnodes * dev->tnode_size, GFP_NOFS);
++	mem = (u8 *) new_tnodes;
++
++	if (!new_tnodes) {
++		yaffs_trace(YAFFS_TRACE_ERROR,
++			"yaffs: Could not allocate Tnodes");
++		return YAFFS_FAIL;
++	}
++
++	/* New hookup for wide tnodes */
++	for (i = 0; i < n_tnodes - 1; i++) {
++		curr = (struct yaffs_tnode *)&mem[i * dev->tnode_size];
++		next = (struct yaffs_tnode *)&mem[(i + 1) * dev->tnode_size];
++		curr->internal[0] = next;
++	}
++
++	curr = (struct yaffs_tnode *)&mem[(n_tnodes - 1) * dev->tnode_size];
++	curr->internal[0] = allocator->free_tnodes;
++	allocator->free_tnodes = (struct yaffs_tnode *)mem;
++
++	allocator->n_free_tnodes += n_tnodes;
++	allocator->n_tnodes_created += n_tnodes;
++
++	/* Now add this bunch of tnodes to a list for freeing up.
++	 * NB If we can't add this to the management list it isn't fatal
++	 * but it just means we can't free this bunch of tnodes later.
++	 */
++	tnl = kmalloc(sizeof(struct yaffs_tnode_list), GFP_NOFS);
++	if (!tnl) {
++		yaffs_trace(YAFFS_TRACE_ERROR,
++			"Could not add tnodes to management list");
++		return YAFFS_FAIL;
++	} else {
++		tnl->tnodes = new_tnodes;
++		tnl->next = allocator->alloc_tnode_list;
++		allocator->alloc_tnode_list = tnl;
++	}
++
++	yaffs_trace(YAFFS_TRACE_ALLOCATE, "Tnodes added");
++
++	return YAFFS_OK;
++}
++
++struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev)
++{
++	struct yaffs_allocator *allocator =
++	    (struct yaffs_allocator *)dev->allocator;
++	struct yaffs_tnode *tn = NULL;
++
++	if (!allocator) {
++		BUG();
++		return NULL;
++	}
++
++	/* If there are none left make more */
++	if (!allocator->free_tnodes)
++		yaffs_create_tnodes(dev, YAFFS_ALLOCATION_NTNODES);
++
++	if (allocator->free_tnodes) {
++		tn = allocator->free_tnodes;
++		allocator->free_tnodes = allocator->free_tnodes->internal[0];
++		allocator->n_free_tnodes--;
++	}
++
++	return tn;
++}
++
++/* FreeTnode frees up a tnode and puts it back on the free list */
++void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn)
++{
++	struct yaffs_allocator *allocator = dev->allocator;
++
++	if (!allocator) {
++		BUG();
++		return;
++	}
++
++	if (tn) {
++		tn->internal[0] = allocator->free_tnodes;
++		allocator->free_tnodes = tn;
++		allocator->n_free_tnodes++;
++	}
++	dev->checkpoint_blocks_required = 0;	/* force recalculation */
++}
++
++/*--------------- yaffs_obj alloaction ------------------------
++ *
++ * Free yaffs_objs are stored in a list using obj->siblings.
++ * The blocks of allocated objects are stored in a linked list.
++ */
++
++static void yaffs_init_raw_objs(struct yaffs_dev *dev)
++{
++	struct yaffs_allocator *allocator = dev->allocator;
++
++	if (!allocator) {
++		BUG();
++		return;
++	}
++
++	allocator->allocated_obj_list = NULL;
++	INIT_LIST_HEAD(&allocator->free_objs);
++	allocator->n_free_objects = 0;
++}
++
++static void yaffs_deinit_raw_objs(struct yaffs_dev *dev)
++{
++	struct yaffs_allocator *allocator = dev->allocator;
++	struct yaffs_obj_list *tmp;
++
++	if (!allocator) {
++		BUG();
++		return;
++	}
++
++	while (allocator->allocated_obj_list) {
++		tmp = allocator->allocated_obj_list->next;
++		kfree(allocator->allocated_obj_list->objects);
++		kfree(allocator->allocated_obj_list);
++		allocator->allocated_obj_list = tmp;
++	}
++
++	INIT_LIST_HEAD(&allocator->free_objs);
++	allocator->n_free_objects = 0;
++	allocator->n_obj_created = 0;
++}
++
++static int yaffs_create_free_objs(struct yaffs_dev *dev, int n_obj)
++{
++	struct yaffs_allocator *allocator = dev->allocator;
++	int i;
++	struct yaffs_obj *new_objs;
++	struct yaffs_obj_list *list;
++
++	if (!allocator) {
++		BUG();
++		return YAFFS_FAIL;
++	}
++
++	if (n_obj < 1)
++		return YAFFS_OK;
++
++	/* make these things */
++	new_objs = kmalloc(n_obj * sizeof(struct yaffs_obj), GFP_NOFS);
++	list = kmalloc(sizeof(struct yaffs_obj_list), GFP_NOFS);
++
++	if (!new_objs || !list) {
++		kfree(new_objs);
++		new_objs = NULL;
++		kfree(list);
++		list = NULL;
++		yaffs_trace(YAFFS_TRACE_ALLOCATE,
++			"Could not allocate more objects");
++		return YAFFS_FAIL;
++	}
++
++	/* Hook them into the free list */
++	for (i = 0; i < n_obj; i++)
++		list_add(&new_objs[i].siblings, &allocator->free_objs);
++
++	allocator->n_free_objects += n_obj;
++	allocator->n_obj_created += n_obj;
++
++	/* Now add this bunch of Objects to a list for freeing up. */
++
++	list->objects = new_objs;
++	list->next = allocator->allocated_obj_list;
++	allocator->allocated_obj_list = list;
++
++	return YAFFS_OK;
++}
++
++struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev)
++{
++	struct yaffs_obj *obj = NULL;
++	struct list_head *lh;
++	struct yaffs_allocator *allocator = dev->allocator;
++
++	if (!allocator) {
++		BUG();
++		return obj;
++	}
++
++	/* If there are none left make more */
++	if (list_empty(&allocator->free_objs))
++		yaffs_create_free_objs(dev, YAFFS_ALLOCATION_NOBJECTS);
++
++	if (!list_empty(&allocator->free_objs)) {
++		lh = allocator->free_objs.next;
++		obj = list_entry(lh, struct yaffs_obj, siblings);
++		list_del_init(lh);
++		allocator->n_free_objects--;
++	}
++
++	return obj;
++}
++
++void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj)
++{
++
++	struct yaffs_allocator *allocator = dev->allocator;
++
++	if (!allocator) {
++		BUG();
++		return;
++	}
++
++	/* Link into the free list. */
++	list_add(&obj->siblings, &allocator->free_objs);
++	allocator->n_free_objects++;
++}
++
++void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev)
++{
++
++	if (!dev->allocator) {
++		BUG();
++		return;
++	}
++
++	yaffs_deinit_raw_tnodes(dev);
++	yaffs_deinit_raw_objs(dev);
++	kfree(dev->allocator);
++	dev->allocator = NULL;
++}
++
++void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev)
++{
++	struct yaffs_allocator *allocator;
++
++	if (dev->allocator) {
++		BUG();
++		return;
++	}
++
++	allocator = kmalloc(sizeof(struct yaffs_allocator), GFP_NOFS);
++	if (allocator) {
++		dev->allocator = allocator;
++		yaffs_init_raw_tnodes(dev);
++		yaffs_init_raw_objs(dev);
++	}
++}
+diff --git a/fs/yaffs2/yaffs_allocator.h b/fs/yaffs2/yaffs_allocator.h
+new file mode 100644
+index 0000000..a8cc322
+--- /dev/null
++++ b/fs/yaffs2/yaffs_allocator.h
+@@ -0,0 +1,30 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ *   for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_ALLOCATOR_H__
++#define __YAFFS_ALLOCATOR_H__
++
++#include "yaffs_guts.h"
++
++void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev);
++void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev);
++
++struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev);
++void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn);
++
++struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev);
++void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj);
++
++#endif
+diff --git a/fs/yaffs2/yaffs_attribs.c b/fs/yaffs2/yaffs_attribs.c
+new file mode 100644
+index 0000000..711941f
+--- /dev/null
++++ b/fs/yaffs2/yaffs_attribs.c
+@@ -0,0 +1,132 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ *   for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * 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 "yaffs_guts.h"
++#include "yaffs_attribs.h"
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
++#define IATTR_UID ia_uid
++#define IATTR_GID ia_gid
++#else
++#define IATTR_UID ia_uid.val
++#define IATTR_GID ia_gid.val
++#endif
++
++void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh)
++{
++	obj->yst_uid = oh->yst_uid;
++	obj->yst_gid = oh->yst_gid;
++	obj->yst_atime = oh->yst_atime;
++	obj->yst_mtime = oh->yst_mtime;
++	obj->yst_ctime = oh->yst_ctime;
++	obj->yst_rdev = oh->yst_rdev;
++}
++
++void yaffs_load_attribs_oh(struct yaffs_obj_hdr *oh, struct yaffs_obj *obj)
++{
++	oh->yst_uid = obj->yst_uid;
++	oh->yst_gid = obj->yst_gid;
++	oh->yst_atime = obj->yst_atime;
++	oh->yst_mtime = obj->yst_mtime;
++	oh->yst_ctime = obj->yst_ctime;
++	oh->yst_rdev = obj->yst_rdev;
++
++}
++
++void yaffs_load_current_time(struct yaffs_obj *obj, int do_a, int do_c)
++{
++	obj->yst_mtime = Y_CURRENT_TIME;
++	if (do_a)
++		obj->yst_atime = obj->yst_mtime;
++	if (do_c)
++		obj->yst_ctime = obj->yst_mtime;
++}
++
++void yaffs_attribs_init(struct yaffs_obj *obj, u32 gid, u32 uid, u32 rdev)
++{
++	yaffs_load_current_time(obj, 1, 1);
++	obj->yst_rdev = rdev;
++	obj->yst_uid = uid;
++	obj->yst_gid = gid;
++}
++
++static loff_t yaffs_get_file_size(struct yaffs_obj *obj)
++{
++	YCHAR *alias = NULL;
++	obj = yaffs_get_equivalent_obj(obj);
++
++	switch (obj->variant_type) {
++	case YAFFS_OBJECT_TYPE_FILE:
++		return obj->variant.file_variant.file_size;
++	case YAFFS_OBJECT_TYPE_SYMLINK:
++		alias = obj->variant.symlink_variant.alias;
++		if (!alias)
++			return 0;
++		return strnlen(alias, YAFFS_MAX_ALIAS_LENGTH);
++	default:
++		return 0;
++	}
++}
++
++int yaffs_set_attribs(struct yaffs_obj *obj, struct iattr *attr)
++{
++	unsigned int valid = attr->ia_valid;
++
++	if (valid & ATTR_MODE)
++		obj->yst_mode = attr->ia_mode;
++	if (valid & ATTR_UID)
++		obj->yst_uid = attr->IATTR_UID;
++	if (valid & ATTR_GID)
++		obj->yst_gid = attr->IATTR_GID;
++
++	if (valid & ATTR_ATIME)
++		obj->yst_atime = Y_TIME_CONVERT(attr->ia_atime);
++	if (valid & ATTR_CTIME)
++		obj->yst_ctime = Y_TIME_CONVERT(attr->ia_ctime);
++	if (valid & ATTR_MTIME)
++		obj->yst_mtime = Y_TIME_CONVERT(attr->ia_mtime);
++
++	if (valid & ATTR_SIZE)
++		yaffs_resize_file(obj, attr->ia_size);
++
++	yaffs_update_oh(obj, NULL, 1, 0, 0, NULL);
++
++	return YAFFS_OK;
++
++}
++
++int yaffs_get_attribs(struct yaffs_obj *obj, struct iattr *attr)
++{
++	unsigned int valid = 0;
++
++	attr->ia_mode = obj->yst_mode;
++	valid |= ATTR_MODE;
++	attr->IATTR_UID = obj->yst_uid;
++	valid |= ATTR_UID;
++	attr->IATTR_GID = obj->yst_gid;
++	valid |= ATTR_GID;
++
++	Y_TIME_CONVERT(attr->ia_atime) = obj->yst_atime;
++	valid |= ATTR_ATIME;
++	Y_TIME_CONVERT(attr->ia_ctime) = obj->yst_ctime;
++	valid |= ATTR_CTIME;
++	Y_TIME_CONVERT(attr->ia_mtime) = obj->yst_mtime;
++	valid |= ATTR_MTIME;
++
++	attr->ia_size = yaffs_get_file_size(obj);
++	valid |= ATTR_SIZE;
++
++	attr->ia_valid = valid;
++
++	return YAFFS_OK;
++}
+diff --git a/fs/yaffs2/yaffs_attribs.h b/fs/yaffs2/yaffs_attribs.h
+new file mode 100644
+index 0000000..5b21b08
+--- /dev/null
++++ b/fs/yaffs2/yaffs_attribs.h
+@@ -0,0 +1,28 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ *   for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_ATTRIBS_H__
++#define __YAFFS_ATTRIBS_H__
++
++#include "yaffs_guts.h"
++
++void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh);
++void yaffs_load_attribs_oh(struct yaffs_obj_hdr *oh, struct yaffs_obj *obj);
++void yaffs_attribs_init(struct yaffs_obj *obj, u32 gid, u32 uid, u32 rdev);
++void yaffs_load_current_time(struct yaffs_obj *obj, int do_a, int do_c);
++int yaffs_set_attribs(struct yaffs_obj *obj, struct iattr *attr);
++int yaffs_get_attribs(struct yaffs_obj *obj, struct iattr *attr);
++
++#endif
+diff --git a/fs/yaffs2/yaffs_bitmap.c b/fs/yaffs2/yaffs_bitmap.c
+new file mode 100644
+index 0000000..4440e93
+--- /dev/null
++++ b/fs/yaffs2/yaffs_bitmap.c
+@@ -0,0 +1,97 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ *   for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * 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 "yaffs_bitmap.h"
++#include "yaffs_trace.h"
++/*
++ * Chunk bitmap manipulations
++ */
++
++static inline u8 *yaffs_block_bits(struct yaffs_dev *dev, int blk)
++{
++	if (blk < dev->internal_start_block || blk > dev->internal_end_block) {
++		yaffs_trace(YAFFS_TRACE_ERROR,
++			"BlockBits block %d is not valid",
++			blk);
++		BUG();
++	}
++	return dev->chunk_bits +
++	    (dev->chunk_bit_stride * (blk - dev->internal_start_block));
++}
++
++void yaffs_verify_chunk_bit_id(struct yaffs_dev *dev, int blk, int chunk)
++{
++	if (blk < dev->internal_start_block || blk > dev->internal_end_block ||
++	    chunk < 0 || chunk >= dev->param.chunks_per_block) {
++		yaffs_trace(YAFFS_TRACE_ERROR,
++			"Chunk Id (%d:%d) invalid",
++			blk, chunk);
++		BUG();
++	}
++}
++
++void yaffs_clear_chunk_bits(struct yaffs_dev *dev, int blk)
++{
++	u8 *blk_bits = yaffs_block_bits(dev, blk);
++
++	memset(blk_bits, 0, dev->chunk_bit_stride);
++}
++
++void yaffs_clear_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
++{
++	u8 *blk_bits = yaffs_block_bits(dev, blk);
++
++	yaffs_verify_chunk_bit_id(dev, blk, chunk);
++	blk_bits[chunk / 8] &= ~(1 << (chunk & 7));
++}
++
++void yaffs_set_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
++{
++	u8 *blk_bits = yaffs_block_bits(dev, blk);
++
++	yaffs_verify_chunk_bit_id(dev, blk, chunk);
++	blk_bits[chunk / 8] |= (1 << (chunk & 7));
++}
++
++int yaffs_check_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
++{
++	u8 *blk_bits = yaffs_block_bits(dev, blk);
++
++	yaffs_verify_chunk_bit_id(dev, blk, chunk);
++	return (blk_bits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0;
++}
++
++int yaffs_still_some_chunks(struct yaffs_dev *dev, int blk)
++{
++	u8 *blk_bits = yaffs_block_bits(dev, blk);
++	int i;
++
++	for (i = 0; i < dev->chunk_bit_stride; i++) {
++		if (*blk_bits)
++			return 1;
++		blk_bits++;
++	}
++	return 0;
++}
++
++int yaffs_count_chunk_bits(struct yaffs_dev *dev, int blk)
++{
++	u8 *blk_bits = yaffs_block_bits(dev, blk);
++	int i;
++	int n = 0;
++
++	for (i = 0; i < dev->chunk_bit_stride; i++, blk_bits++)
++		n += hweight8(*blk_bits);
++
++	return n;
++}
+diff --git a/fs/yaffs2/yaffs_bitmap.h b/fs/yaffs2/yaffs_bitmap.h
+new file mode 100644
+index 0000000..e26b37d
+--- /dev/null
++++ b/fs/yaffs2/yaffs_bitmap.h
+@@ -0,0 +1,33 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ *   for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++/*
++ * Chunk bitmap manipulations
++ */
++
++#ifndef __YAFFS_BITMAP_H__
++#define __YAFFS_BITMAP_H__
++
++#include "yaffs_guts.h"
++
++void yaffs_verify_chunk_bit_id(struct yaffs_dev *dev, int blk, int chunk);
++void yaffs_clear_chunk_bits(struct yaffs_dev *dev, int blk);
++void yaffs_clear_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);
++void yaffs_set_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);
++int yaffs_check_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);
++int yaffs_still_some_chunks(struct yaffs_dev *dev, int blk);
++int yaffs_count_chunk_bits(struct yaffs_dev *dev, int blk);
++
++#endif
+diff --git a/fs/yaffs2/yaffs_checkptrw.c b/fs/yaffs2/yaffs_checkptrw.c
+new file mode 100644
+index 0000000..16ee1e0
+--- /dev/null
++++ b/fs/yaffs2/yaffs_checkptrw.c
+@@ -0,0 +1,466 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ *   for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * 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 "yaffs_checkptrw.h"
++#include "yaffs_getblockinfo.h"
++
++struct yaffs_checkpt_chunk_hdr {
++	int version;
++	int seq;
++	u32 sum;
++	u32 xor;
++} ;
++
++
++static int apply_chunk_offset(struct yaffs_dev *dev, int chunk)
++{
++	return chunk - dev->chunk_offset;
++}
++
++static int apply_block_offset(struct yaffs_dev *dev, int block)
++{
++	return block - dev->block_offset;
++}
++
++static void yaffs2_checkpt_init_chunk_hdr(struct yaffs_dev *dev)
++{
++	struct yaffs_checkpt_chunk_hdr hdr;
++
++	hdr.version = YAFFS_CHECKPOINT_VERSION;
++	hdr.seq = dev->checkpt_page_seq;
++	hdr.sum = dev->checkpt_sum;
++	hdr.xor = dev->checkpt_xor;
++
++	dev->checkpt_byte_offs = sizeof(hdr);
++
++	memcpy(dev->checkpt_buffer, &hdr, sizeof(hdr));
++}
++
++static int yaffs2_checkpt_check_chunk_hdr(struct yaffs_dev *dev)
++{
++	struct yaffs_checkpt_chunk_hdr hdr;
++
++	memcpy(&hdr, dev->checkpt_buffer, sizeof(hdr));
++
++	dev->checkpt_byte_offs = sizeof(hdr);
++
++	return hdr.version == YAFFS_CHECKPOINT_VERSION &&
++		hdr.seq == dev->checkpt_page_seq &&
++		hdr.sum == dev->checkpt_sum &&
++		hdr.xor == dev->checkpt_xor;
++}
++
++static int yaffs2_checkpt_space_ok(struct yaffs_dev *dev)
++{
++	int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks;
++
++	yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++		"checkpt blocks_avail = %d", blocks_avail);
++
++	return (blocks_avail <= 0) ? 0 : 1;
++}
++
++static int yaffs_checkpt_erase(struct yaffs_dev *dev)
++{
++	int i;
++
++	if (!dev->drv.drv_erase_fn)
++		return 0;
++	yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++		"checking blocks %d to %d",
++		dev->internal_start_block, dev->internal_end_block);
++
++	for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
++		struct yaffs_block_info *bi = yaffs_get_block_info(dev, i);
++		int offset_i = apply_block_offset(dev, i);
++		int result;
++
++		if (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT) {
++			yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++			"erasing checkpt block %d", i);
++
++			dev->n_erasures++;
++
++			result = dev->drv.drv_erase_fn(dev, offset_i);
++			if(result) {
++				bi->block_state = YAFFS_BLOCK_STATE_EMPTY;
++				dev->n_erased_blocks++;
++				dev->n_free_chunks +=
++				    dev->param.chunks_per_block;
++			} else {
++				dev->drv.drv_mark_bad_fn(dev, offset_i);
++				bi->block_state = YAFFS_BLOCK_STATE_DEAD;
++			}
++		}
++	}
++
++	dev->blocks_in_checkpt = 0;
++
++	return 1;
++}
++
++static void yaffs2_checkpt_find_erased_block(struct yaffs_dev *dev)
++{
++	int i;
++	int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks;
++
++	yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++		"allocating checkpt block: erased %d reserved %d avail %d next %d ",
++		dev->n_erased_blocks, dev->param.n_reserved_blocks,
++		blocks_avail, dev->checkpt_next_block);
++
++	if (dev->checkpt_next_block >= 0 &&
++	    dev->checkpt_next_block <= dev->internal_end_block &&
++	    blocks_avail > 0) {
++
++		for (i = dev->checkpt_next_block; i <= dev->internal_end_block;
++		     i++) {
++			struct yaffs_block_info *bi;
++
++			bi = yaffs_get_block_info(dev, i);
++			if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {
++				dev->checkpt_next_block = i + 1;
++				dev->checkpt_cur_block = i;
++				yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++					"allocating checkpt block %d", i);
++				return;
++			}
++		}
++	}
++	yaffs_trace(YAFFS_TRACE_CHECKPOINT, "out of checkpt blocks");
++
++	dev->checkpt_next_block = -1;
++	dev->checkpt_cur_block = -1;
++}
++
++static void yaffs2_checkpt_find_block(struct yaffs_dev *dev)
++{
++	int i;
++	struct yaffs_ext_tags tags;
++
++	yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++		"find next checkpt block: start:  blocks %d next %d",
++		dev->blocks_in_checkpt, dev->checkpt_next_block);
++
++	if (dev->blocks_in_checkpt < dev->checkpt_max_blocks)
++		for (i = dev->checkpt_next_block; i <= dev->internal_end_block;
++		     i++) {
++			int chunk = i * dev->param.chunks_per_block;
++			enum yaffs_block_state state;
++			u32 seq;
++
++			dev->tagger.read_chunk_tags_fn(dev,
++					apply_chunk_offset(dev, chunk),
++					NULL, &tags);
++			yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++				"find next checkpt block: search: block %d state %d oid %d seq %d eccr %d",
++				i, (int) state,
++				tags.obj_id, tags.seq_number,
++				tags.ecc_result);
++
++			if (tags.seq_number != YAFFS_SEQUENCE_CHECKPOINT_DATA)
++				continue;
++
++			dev->tagger.query_block_fn(dev,
++						apply_block_offset(dev, i),
++						&state, &seq);
++			if (state == YAFFS_BLOCK_STATE_DEAD)
++				continue;
++
++			/* Right kind of block */
++			dev->checkpt_next_block = tags.obj_id;
++			dev->checkpt_cur_block = i;
++			dev->checkpt_block_list[dev->blocks_in_checkpt] = i;
++			dev->blocks_in_checkpt++;
++			yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++				"found checkpt block %d", i);
++			return;
++		}
++
++	yaffs_trace(YAFFS_TRACE_CHECKPOINT, "found no more checkpt blocks");
++
++	dev->checkpt_next_block = -1;
++	dev->checkpt_cur_block = -1;
++}
++
++int yaffs2_checkpt_open(struct yaffs_dev *dev, int writing)
++{
++	int i;
++
++	dev->checkpt_open_write = writing;
++
++	/* Got the functions we need? */
++	if (!dev->tagger.write_chunk_tags_fn ||
++	    !dev->tagger.read_chunk_tags_fn ||
++	    !dev->drv.drv_erase_fn ||
++	    !dev->drv.drv_mark_bad_fn)
++		return 0;
++
++	if (writing && !yaffs2_checkpt_space_ok(dev))
++		return 0;
++
++	if (!dev->checkpt_buffer)
++		dev->checkpt_buffer =
++		    kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS);
++	if (!dev->checkpt_buffer)
++		return 0;
++
++	dev->checkpt_page_seq = 0;
++	dev->checkpt_byte_count = 0;
++	dev->checkpt_sum = 0;
++	dev->checkpt_xor = 0;
++	dev->checkpt_cur_block = -1;
++	dev->checkpt_cur_chunk = -1;
++	dev->checkpt_next_block = dev->internal_start_block;
++
++	if (writing) {
++		memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk);
++		yaffs2_checkpt_init_chunk_hdr(dev);
++		return yaffs_checkpt_erase(dev);
++	}
++
++	/* Opening for a read */
++	/* Set to a value that will kick off a read */
++	dev->checkpt_byte_offs = dev->data_bytes_per_chunk;
++	/* A checkpoint block list of 1 checkpoint block per 16 block is
++	 * (hopefully) going to be way more than we need */
++	dev->blocks_in_checkpt = 0;
++	dev->checkpt_max_blocks =
++	    (dev->internal_end_block - dev->internal_start_block) / 16 + 2;
++	if (!dev->checkpt_block_list)
++		dev->checkpt_block_list =
++		      kmalloc(sizeof(int) * dev->checkpt_max_blocks, GFP_NOFS);
++
++	if (!dev->checkpt_block_list)
++		return 0;
++
++	for (i = 0; i < dev->checkpt_max_blocks; i++)
++		dev->checkpt_block_list[i] = -1;
++
++	return 1;
++}
++
++int yaffs2_get_checkpt_sum(struct yaffs_dev *dev, u32 * sum)
++{
++	u32 composite_sum;
++
++	composite_sum = (dev->checkpt_sum << 8) | (dev->checkpt_xor & 0xff);
++	*sum = composite_sum;
++	return 1;
++}
++
++static int yaffs2_checkpt_flush_buffer(struct yaffs_dev *dev)
++{
++	int chunk;
++	int offset_chunk;
++	struct yaffs_ext_tags tags;
++
++	if (dev->checkpt_cur_block < 0) {
++		yaffs2_checkpt_find_erased_block(dev);
++		dev->checkpt_cur_chunk = 0;
++	}
++
++	if (dev->checkpt_cur_block < 0)
++		return 0;
++
++	tags.is_deleted = 0;
++	tags.obj_id = dev->checkpt_next_block;	/* Hint to next place to look */
++	tags.chunk_id = dev->checkpt_page_seq + 1;
++	tags.seq_number = YAFFS_SEQUENCE_CHECKPOINT_DATA;
++	tags.n_bytes = dev->data_bytes_per_chunk;
++	if (dev->checkpt_cur_chunk == 0) {
++		/* First chunk we write for the block? Set block state to
++		   checkpoint */
++		struct yaffs_block_info *bi =
++		    yaffs_get_block_info(dev, dev->checkpt_cur_block);
++		bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;
++		dev->blocks_in_checkpt++;
++	}
++
++	chunk =
++	    dev->checkpt_cur_block * dev->param.chunks_per_block +
++	    dev->checkpt_cur_chunk;
++
++	yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++		"checkpoint wite buffer nand %d(%d:%d) objid %d chId %d",
++		chunk, dev->checkpt_cur_block, dev->checkpt_cur_chunk,
++		tags.obj_id, tags.chunk_id);
++
++	offset_chunk = apply_chunk_offset(dev, chunk);
++
++	dev->n_page_writes++;
++
++	dev->tagger.write_chunk_tags_fn(dev, offset_chunk,
++				       dev->checkpt_buffer, &tags);
++	dev->checkpt_page_seq++;
++	dev->checkpt_cur_chunk++;
++	if (dev->checkpt_cur_chunk >= dev->param.chunks_per_block) {
++		dev->checkpt_cur_chunk = 0;
++		dev->checkpt_cur_block = -1;
++	}
++	memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk);
++
++	yaffs2_checkpt_init_chunk_hdr(dev);
++
++
++	return 1;
++}
++
++int yaffs2_checkpt_wr(struct yaffs_dev *dev, const void *data, int n_bytes)
++{
++	int i = 0;
++	int ok = 1;
++	u8 *data_bytes = (u8 *) data;
++
++	if (!dev->checkpt_buffer)
++		return 0;
++
++	if (!dev->checkpt_open_write)
++		return -1;
++
++	while (i < n_bytes && ok) {
++		dev->checkpt_buffer[dev->checkpt_byte_offs] = *data_bytes;
++		dev->checkpt_sum += *data_bytes;
++		dev->checkpt_xor ^= *data_bytes;
++
++		dev->checkpt_byte_offs++;
++		i++;
++		data_bytes++;
++		dev->checkpt_byte_count++;
++
++		if (dev->checkpt_byte_offs < 0 ||
++		    dev->checkpt_byte_offs >= dev->data_bytes_per_chunk)
++			ok = yaffs2_checkpt_flush_buffer(dev);
++	}
++
++	return i;
++}
++
++int yaffs2_checkpt_rd(struct yaffs_dev *dev, void *data, int n_bytes)
++{
++	int i = 0;
++	struct yaffs_ext_tags tags;
++	int chunk;
++	int offset_chunk;
++	u8 *data_bytes = (u8 *) data;
++
++	if (!dev->checkpt_buffer)
++		return 0;
++
++	if (dev->checkpt_open_write)
++		return -1;
++
++	while (i < n_bytes) {
++
++		if (dev->checkpt_byte_offs < 0 ||
++		    dev->checkpt_byte_offs >= dev->data_bytes_per_chunk) {
++
++			if (dev->checkpt_cur_block < 0) {
++				yaffs2_checkpt_find_block(dev);
++				dev->checkpt_cur_chunk = 0;
++			}
++
++			/* Bail out if we can't find a checpoint block */
++			if (dev->checkpt_cur_block < 0)
++				break;
++
++			chunk = dev->checkpt_cur_block *
++			    dev->param.chunks_per_block +
++			    dev->checkpt_cur_chunk;
++
++			offset_chunk = apply_chunk_offset(dev, chunk);
++			dev->n_page_reads++;
++
++			/* Read in the next chunk */
++			dev->tagger.read_chunk_tags_fn(dev,
++						offset_chunk,
++						dev->checkpt_buffer,
++						&tags);
++
++			/* Bail out if the chunk is corrupted. */
++			if (tags.chunk_id != (dev->checkpt_page_seq + 1) ||
++			    tags.ecc_result > YAFFS_ECC_RESULT_FIXED ||
++			    tags.seq_number != YAFFS_SEQUENCE_CHECKPOINT_DATA)
++				break;
++
++			/* Bail out if it is not a checkpoint chunk. */
++			if(!yaffs2_checkpt_check_chunk_hdr(dev))
++				break;
++
++			dev->checkpt_page_seq++;
++			dev->checkpt_cur_chunk++;
++
++			if (dev->checkpt_cur_chunk >=
++					dev->param.chunks_per_block)
++				dev->checkpt_cur_block = -1;
++
++		}
++
++		*data_bytes = dev->checkpt_buffer[dev->checkpt_byte_offs];
++		dev->checkpt_sum += *data_bytes;
++		dev->checkpt_xor ^= *data_bytes;
++		dev->checkpt_byte_offs++;
++		i++;
++		data_bytes++;
++		dev->checkpt_byte_count++;
++	}
++
++	return i; /* Number of bytes read */
++}
++
++int yaffs_checkpt_close(struct yaffs_dev *dev)
++{
++	int i;
++
++	if (dev->checkpt_open_write) {
++		if (dev->checkpt_byte_offs !=
++			sizeof(sizeof(struct yaffs_checkpt_chunk_hdr)))
++			yaffs2_checkpt_flush_buffer(dev);
++	} else if (dev->checkpt_block_list) {
++		for (i = 0;
++		     i < dev->blocks_in_checkpt &&
++		     dev->checkpt_block_list[i] >= 0; i++) {
++			int blk = dev->checkpt_block_list[i];
++			struct yaffs_block_info *bi = NULL;
++
++			if (dev->internal_start_block <= blk &&
++			    blk <= dev->internal_end_block)
++				bi = yaffs_get_block_info(dev, blk);
++			if (bi && bi->block_state == YAFFS_BLOCK_STATE_EMPTY)
++				bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;
++		}
++	}
++
++	dev->n_free_chunks -=
++		dev->blocks_in_checkpt * dev->param.chunks_per_block;
++	dev->n_erased_blocks -= dev->blocks_in_checkpt;
++
++	yaffs_trace(YAFFS_TRACE_CHECKPOINT, "checkpoint byte count %d",
++		dev->checkpt_byte_count);
++
++	if (dev->checkpt_buffer)
++		return 1;
++	else
++		return 0;
++}
++
++int yaffs2_checkpt_invalidate_stream(struct yaffs_dev *dev)
++{
++	/* Erase the checkpoint data */
++
++	yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++		"checkpoint invalidate of %d blocks",
++		dev->blocks_in_checkpt);
++
++	return yaffs_checkpt_erase(dev);
++}
+diff --git a/fs/yaffs2/yaffs_checkptrw.h b/fs/yaffs2/yaffs_checkptrw.h
+new file mode 100644
+index 0000000..cdbaba7
+--- /dev/null
++++ b/fs/yaffs2/yaffs_checkptrw.h
+@@ -0,0 +1,33 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ *   for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_CHECKPTRW_H__
++#define __YAFFS_CHECKPTRW_H__
++
++#include "yaffs_guts.h"
++
++int yaffs2_checkpt_open(struct yaffs_dev *dev, int writing);
++
++int yaffs2_checkpt_wr(struct yaffs_dev *dev, const void *data, int n_bytes);
++
++int yaffs2_checkpt_rd(struct yaffs_dev *dev, void *data, int n_bytes);
++
++int yaffs2_get_checkpt_sum(struct yaffs_dev *dev, u32 * sum);
++
++int yaffs_checkpt_close(struct yaffs_dev *dev);
++
++int yaffs2_checkpt_invalidate_stream(struct yaffs_dev *dev);
++
++#endif
+diff --git a/fs/yaffs2/yaffs_ecc.c b/fs/yaffs2/yaffs_ecc.c
+new file mode 100644
+index 0000000..9294107
+--- /dev/null
++++ b/fs/yaffs2/yaffs_ecc.c
+@@ -0,0 +1,281 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ *   for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++/*
++ * This code implements the ECC algorithm used in SmartMedia.
++ *
++ * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.
++ * The two unused bit are set to 1.
++ * The ECC can correct single bit errors in a 256-byte page of data. Thus, two
++ * such ECC blocks are used on a 512-byte NAND page.
++ *
++ */
++
++#include "yportenv.h"
++
++#include "yaffs_ecc.h"
++
++/* Table generated by gen-ecc.c
++ * Using a table means we do not have to calculate p1..p4 and p1'..p4'
++ * for each byte of data. These are instead provided in a table in bits7..2.
++ * Bit 0 of each entry indicates whether the entry has an odd or even parity,
++ * and therefore this bytes influence on the line parity.
++ */
++
++static const unsigned char column_parity_table[] = {
++	0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
++	0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
++	0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
++	0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
++	0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
++	0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
++	0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
++	0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
++	0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
++	0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
++	0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
++	0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
++	0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
++	0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
++	0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
++	0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
++	0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
++	0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
++	0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
++	0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
++	0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
++	0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
++	0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
++	0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
++	0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
++	0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
++	0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
++	0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
++	0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
++	0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
++	0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
++	0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
++};
++
++
++/* Calculate the ECC for a 256-byte block of data */
++void yaffs_ecc_calc(const unsigned char *data, unsigned char *ecc)
++{
++	unsigned int i;
++	unsigned char col_parity = 0;
++	unsigned char line_parity = 0;
++	unsigned char line_parity_prime = 0;
++	unsigned char t;
++	unsigned char b;
++
++	for (i = 0; i < 256; i++) {
++		b = column_parity_table[*data++];
++		col_parity ^= b;
++
++		if (b & 0x01) {	/* odd number of bits in the byte */
++			line_parity ^= i;
++			line_parity_prime ^= ~i;
++		}
++	}
++
++	ecc[2] = (~col_parity) | 0x03;
++
++	t = 0;
++	if (line_parity & 0x80)
++		t |= 0x80;
++	if (line_parity_prime & 0x80)
++		t |= 0x40;
++	if (line_parity & 0x40)
++		t |= 0x20;
++	if (line_parity_prime & 0x40)
++		t |= 0x10;
++	if (line_parity & 0x20)
++		t |= 0x08;
++	if (line_parity_prime & 0x20)
++		t |= 0x04;
++	if (line_parity & 0x10)
++		t |= 0x02;
++	if (line_parity_prime & 0x10)
++		t |= 0x01;
++	ecc[1] = ~t;
++
++	t = 0;
++	if (line_parity & 0x08)
++		t |= 0x80;
++	if (line_parity_prime & 0x08)
++		t |= 0x40;
++	if (line_parity & 0x04)
++		t |= 0x20;
++	if (line_parity_prime & 0x04)
++		t |= 0x10;
++	if (line_parity & 0x02)
++		t |= 0x08;
++	if (line_parity_prime & 0x02)
++		t |= 0x04;
++	if (line_parity & 0x01)
++		t |= 0x02;
++	if (line_parity_prime & 0x01)
++		t |= 0x01;
++	ecc[0] = ~t;
++
++}
++
++/* Correct the ECC on a 256 byte block of data */
++
++int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc,
++		      const unsigned char *test_ecc)
++{
++	unsigned char d0, d1, d2;	/* deltas */
++
++	d0 = read_ecc[0] ^ test_ecc[0];
++	d1 = read_ecc[1] ^ test_ecc[1];
++	d2 = read_ecc[2] ^ test_ecc[2];
++
++	if ((d0 | d1 | d2) == 0)
++		return 0;	/* no error */
++
++	if (((d0 ^ (d0 >> 1)) & 0x55) == 0x55 &&
++	    ((d1 ^ (d1 >> 1)) & 0x55) == 0x55 &&
++	    ((d2 ^ (d2 >> 1)) & 0x54) == 0x54) {
++		/* Single bit (recoverable) error in data */
++
++		unsigned byte;
++		unsigned bit;
++
++		bit = byte = 0;
++
++		if (d1 & 0x80)
++			byte |= 0x80;
++		if (d1 & 0x20)
++			byte |= 0x40;
++		if (d1 & 0x08)
++			byte |= 0x20;
++		if (d1 & 0x02)
++			byte |= 0x10;
++		if (d0 & 0x80)
++			byte |= 0x08;
++		if (d0 & 0x20)
++			byte |= 0x04;
++		if (d0 & 0x08)
++			byte |= 0x02;
++		if (d0 & 0x02)
++			byte |= 0x01;
++
++		if (d2 & 0x80)
++			bit |= 0x04;
++		if (d2 & 0x20)
++			bit |= 0x02;
++		if (d2 & 0x08)
++			bit |= 0x01;
++
++		data[byte] ^= (1 << bit);
++
++		return 1;	/* Corrected the error */
++	}
++
++	if ((hweight8(d0) + hweight8(d1) + hweight8(d2)) == 1) {
++		/* Reccoverable error in ecc */
++
++		read_ecc[0] = test_ecc[0];
++		read_ecc[1] = test_ecc[1];
++		read_ecc[2] = test_ecc[2];
++
++		return 1;	/* Corrected the error */
++	}
++
++	/* Unrecoverable error */
++
++	return -1;
++
++}
++
++/*
++ * ECCxxxOther does ECC calcs on arbitrary n bytes of data
++ */
++void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes,
++			  struct yaffs_ecc_other *ecc_other)
++{
++	unsigned int i;
++	unsigned char col_parity = 0;
++	unsigned line_parity = 0;
++	unsigned line_parity_prime = 0;
++	unsigned char b;
++
++	for (i = 0; i < n_bytes; i++) {
++		b = column_parity_table[*data++];
++		col_parity ^= b;
++
++		if (b & 0x01) {
++			/* odd number of bits in the byte */
++			line_parity ^= i;
++			line_parity_prime ^= ~i;
++		}
++
++	}
++
++	ecc_other->col_parity = (col_parity >> 2) & 0x3f;
++	ecc_other->line_parity = line_parity;
++	ecc_other->line_parity_prime = line_parity_prime;
++}
++
++int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes,
++			    struct yaffs_ecc_other *read_ecc,
++			    const struct yaffs_ecc_other *test_ecc)
++{
++	unsigned char delta_col;	/* column parity delta */
++	unsigned delta_line;	/* line parity delta */
++	unsigned delta_line_prime;	/* line parity delta */
++	unsigned bit;
++
++	delta_col = read_ecc->col_parity ^ test_ecc->col_parity;
++	delta_line = read_ecc->line_parity ^ test_ecc->line_parity;
++	delta_line_prime =
++	    read_ecc->line_parity_prime ^ test_ecc->line_parity_prime;
++
++	if ((delta_col | delta_line | delta_line_prime) == 0)
++		return 0;	/* no error */
++
++	if (delta_line == ~delta_line_prime &&
++	    (((delta_col ^ (delta_col >> 1)) & 0x15) == 0x15)) {
++		/* Single bit (recoverable) error in data */
++
++		bit = 0;
++
++		if (delta_col & 0x20)
++			bit |= 0x04;
++		if (delta_col & 0x08)
++			bit |= 0x02;
++		if (delta_col & 0x02)
++			bit |= 0x01;
++
++		if (delta_line >= n_bytes)
++			return -1;
++
++		data[delta_line] ^= (1 << bit);
++
++		return 1;	/* corrected */
++	}
++
++	if ((hweight32(delta_line) +
++	     hweight32(delta_line_prime) +
++	     hweight8(delta_col)) == 1) {
++		/* Reccoverable error in ecc */
++
++		*read_ecc = *test_ecc;
++		return 1;	/* corrected */
++	}
++
++	/* Unrecoverable error */
++
++	return -1;
++}
+diff --git a/fs/yaffs2/yaffs_ecc.h b/fs/yaffs2/yaffs_ecc.h
+new file mode 100644
+index 0000000..17d47bd
+--- /dev/null
++++ b/fs/yaffs2/yaffs_ecc.h
+@@ -0,0 +1,44 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ *   for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++/*
++ * This code implements the ECC algorithm used in SmartMedia.
++ *
++ * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.
++ * The two unused bit are set to 1.
++ * The ECC can correct single bit errors in a 256-byte page of data.
++ * Thus, two such ECC blocks are used on a 512-byte NAND page.
++ *
++ */
++
++#ifndef __YAFFS_ECC_H__
++#define __YAFFS_ECC_H__
++
++struct yaffs_ecc_other {
++	unsigned char col_parity;
++	unsigned line_parity;
++	unsigned line_parity_prime;
++};
++
++void yaffs_ecc_calc(const unsigned char *data, unsigned char *ecc);
++int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc,
++		      const unsigned char *test_ecc);
++
++void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes,
++			  struct yaffs_ecc_other *ecc);
++int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes,
++			    struct yaffs_ecc_other *read_ecc,
++			    const struct yaffs_ecc_other *test_ecc);
++#endif
+diff --git a/fs/yaffs2/yaffs_getblockinfo.h b/fs/yaffs2/yaffs_getblockinfo.h
+new file mode 100644
+index 0000000..8fd0802
+--- /dev/null
++++ b/fs/yaffs2/yaffs_getblockinfo.h
+@@ -0,0 +1,35 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ *   for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_GETBLOCKINFO_H__
++#define __YAFFS_GETBLOCKINFO_H__
++
++#include "yaffs_guts.h"
++#include "yaffs_trace.h"
++
++/* Function to manipulate block info */
++static inline struct yaffs_block_info *yaffs_get_block_info(struct yaffs_dev
++							      *dev, int blk)
++{
++	if (blk < dev->internal_start_block || blk > dev->internal_end_block) {
++		yaffs_trace(YAFFS_TRACE_ERROR,
++			"**>> yaffs: get_block_info block %d is not valid",
++			blk);
++		BUG();
++	}
++	return &dev->block_info[blk - dev->internal_start_block];
++}
++
++#endif
+diff --git a/fs/yaffs2/yaffs_guts.c b/fs/yaffs2/yaffs_guts.c
+new file mode 100644
+index 0000000..89fb2a9
+--- /dev/null
++++ b/fs/yaffs2/yaffs_guts.c
+@@ -0,0 +1,5140 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ *   for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * 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 "yportenv.h"
++#include "yaffs_trace.h"
++
++#include "yaffs_guts.h"
++#include "yaffs_getblockinfo.h"
++#include "yaffs_tagscompat.h"
++#include "yaffs_tagsmarshall.h"
++#include "yaffs_nand.h"
++#include "yaffs_yaffs1.h"
++#include "yaffs_yaffs2.h"
++#include "yaffs_bitmap.h"
++#include "yaffs_verify.h"
++#include "yaffs_nand.h"
++#include "yaffs_packedtags2.h"
++#include "yaffs_nameval.h"
++#include "yaffs_allocator.h"
++#include "yaffs_attribs.h"
++#include "yaffs_summary.h"
++
++/* Note YAFFS_GC_GOOD_ENOUGH must be <= YAFFS_GC_PASSIVE_THRESHOLD */
++#define YAFFS_GC_GOOD_ENOUGH 2
++#define YAFFS_GC_PASSIVE_THRESHOLD 4
++
++#include "yaffs_ecc.h"
++
++/* Forward declarations */
++
++static int yaffs_wr_data_obj(struct yaffs_obj *in, int inode_chunk,
++			     const u8 *buffer, int n_bytes, int use_reserve);
++
++static void yaffs_fix_null_name(struct yaffs_obj *obj, YCHAR *name,
++				int buffer_size);
++
++/* Function to calculate chunk and offset */
++
++void yaffs_addr_to_chunk(struct yaffs_dev *dev, loff_t addr,
++				int *chunk_out, u32 *offset_out)
++{
++	int chunk;
++	u32 offset;
++
++	chunk = (u32) (addr >> dev->chunk_shift);
++
++	if (dev->chunk_div == 1) {
++		/* easy power of 2 case */
++		offset = (u32) (addr & dev->chunk_mask);
++	} else {
++		/* Non power-of-2 case */
++
++		loff_t chunk_base;
++
++		chunk /= dev->chunk_div;
++
++		chunk_base = ((loff_t) chunk) * dev->data_bytes_per_chunk;
++		offset = (u32) (addr - chunk_base);
++	}
++
++	*chunk_out = chunk;
++	*offset_out = offset;
++}
++
++/* Function to return the number of shifts for a power of 2 greater than or
++ * equal to the given number
++ * Note we don't try to cater for all possible numbers and this does not have to
++ * be hellishly efficient.
++ */
++
++static inline u32 calc_shifts_ceiling(u32 x)
++{
++	int extra_bits;
++	int shifts;
++
++	shifts = extra_bits = 0;
++
++	while (x > 1) {
++		if (x & 1)
++			extra_bits++;
++		x >>= 1;
++		shifts++;
++	}
++
++	if (extra_bits)
++		shifts++;
++
++	return shifts;
++}
++
++/* Function to return the number of shifts to get a 1 in bit 0
++ */
++
++static inline u32 calc_shifts(u32 x)
++{
++	u32 shifts;
++
++	shifts = 0;
++
++	if (!x)
++		return 0;
++
++	while (!(x & 1)) {
++		x >>= 1;
++		shifts++;
++	}
++
++	return shifts;
++}
++
++/*
++ * Temporary buffer manipulations.
++ */
++
++static int yaffs_init_tmp_buffers(struct yaffs_dev *dev)
++{
++	int i;
++	u8 *buf = (u8 *) 1;
++
++	memset(dev->temp_buffer, 0, sizeof(dev->temp_buffer));
++
++	for (i = 0; buf && i < YAFFS_N_TEMP_BUFFERS; i++) {
++		dev->temp_buffer[i].in_use = 0;
++		buf = kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS);
++		dev->temp_buffer[i].buffer = buf;
++	}
++
++	return buf ? YAFFS_OK : YAFFS_FAIL;
++}
++
++u8 *yaffs_get_temp_buffer(struct yaffs_dev * dev)
++{
++	int i;
++
++	dev->temp_in_use++;
++	if (dev->temp_in_use > dev->max_temp)
++		dev->max_temp = dev->temp_in_use;
++
++	for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
++		if (dev->temp_buffer[i].in_use == 0) {
++			dev->temp_buffer[i].in_use = 1;
++			return dev->temp_buffer[i].buffer;
++		}
++	}
++
++	yaffs_trace(YAFFS_TRACE_BUFFERS, "Out of temp buffers");
++	/*
++	 * If we got here then we have to allocate an unmanaged one
++	 * This is not good.
++	 */
++
++	dev->unmanaged_buffer_allocs++;
++	return kmalloc(dev->data_bytes_per_chunk, GFP_NOFS);
++
++}
++
++void yaffs_release_temp_buffer(struct yaffs_dev *dev, u8 *buffer)
++{
++	int i;
++
++	dev->temp_in_use--;
++
++	for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
++		if (dev->temp_buffer[i].buffer == buffer) {
++			dev->temp_buffer[i].in_use = 0;
++			return;
++		}
++	}
++
++	if (buffer) {
++		/* assume it is an unmanaged one. */
++		yaffs_trace(YAFFS_TRACE_BUFFERS,
++			"Releasing unmanaged temp buffer");
++		kfree(buffer);
++		dev->unmanaged_buffer_deallocs++;
++	}
++
++}
++
++/*
++ * Functions for robustisizing TODO
++ *
++ */
++
++static void yaffs_handle_chunk_wr_ok(struct yaffs_dev *dev, int nand_chunk,
++				     const u8 *data,
++				     const struct yaffs_ext_tags *tags)
++{
++	(void) dev;
++	(void) nand_chunk;
++	(void) data;
++	(void) tags;
++}
++
++static void yaffs_handle_chunk_update(struct yaffs_dev *dev, int nand_chunk,
++				      const struct yaffs_ext_tags *tags)
++{
++	(void) dev;
++	(void) nand_chunk;
++	(void) tags;
++}
++
++void yaffs_handle_chunk_error(struct yaffs_dev *dev,
++			      struct yaffs_block_info *bi)
++{
++	if (!bi->gc_prioritise) {
++		bi->gc_prioritise = 1;
++		dev->has_pending_prioritised_gc = 1;
++		bi->chunk_error_strikes++;
++
++		if (bi->chunk_error_strikes > 3) {
++			bi->needs_retiring = 1;	/* Too many stikes, so retire */
++			yaffs_trace(YAFFS_TRACE_ALWAYS,
++				"yaffs: Block struck out");
++
++		}
++	}
++}
++
++static void yaffs_handle_chunk_wr_error(struct yaffs_dev *dev, int nand_chunk,
++					int erased_ok)
++{
++	int flash_block = nand_chunk / dev->param.chunks_per_block;
++	struct yaffs_block_info *bi = yaffs_get_block_info(dev, flash_block);
++
++	yaffs_handle_chunk_error(dev, bi);
++
++	if (erased_ok) {
++		/* Was an actual write failure,
++		 * so mark the block for retirement.*/
++		bi->needs_retiring = 1;
++		yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
++		  "**>> Block %d needs retiring", flash_block);
++	}
++
++	/* Delete the chunk */
++	yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);
++	yaffs_skip_rest_of_block(dev);
++}
++
++/*
++ * Verification code
++ */
++
++/*
++ *  Simple hash function. Needs to have a reasonable spread
++ */
++
++static inline int yaffs_hash_fn(int n)
++{
++	if (n < 0)
++		n = -n;
++	return n % YAFFS_NOBJECT_BUCKETS;
++}
++
++/*
++ * Access functions to useful fake objects.
++ * Note that root might have a presence in NAND if permissions are set.
++ */
++
++struct yaffs_obj *yaffs_root(struct yaffs_dev *dev)
++{
++	return dev->root_dir;
++}
++
++struct yaffs_obj *yaffs_lost_n_found(struct yaffs_dev *dev)
++{
++	return dev->lost_n_found;
++}
++
++/*
++ *  Erased NAND checking functions
++ */
++
++int yaffs_check_ff(u8 *buffer, int n_bytes)
++{
++	/* Horrible, slow implementation */
++	while (n_bytes--) {
++		if (*buffer != 0xff)
++			return 0;
++		buffer++;
++	}
++	return 1;
++}
++
++static int yaffs_check_chunk_erased(struct yaffs_dev *dev, int nand_chunk)
++{
++	int retval = YAFFS_OK;
++	u8 *data = yaffs_get_temp_buffer(dev);
++	struct yaffs_ext_tags tags;
++	int result;
++
++	result = yaffs_rd_chunk_tags_nand(dev, nand_chunk, data, &tags);
++
++	if (tags.ecc_result > YAFFS_ECC_RESULT_NO_ERROR)
++		retval = YAFFS_FAIL;
++
++	if (!yaffs_check_ff(data, dev->data_bytes_per_chunk) ||
++		tags.chunk_used) {
++		yaffs_trace(YAFFS_TRACE_NANDACCESS,
++			"Chunk %d not erased", nand_chunk);
++		retval = YAFFS_FAIL;
++	}
++
++	yaffs_release_temp_buffer(dev, data);
++
++	return retval;
++
++}
++
++static int yaffs_verify_chunk_written(struct yaffs_dev *dev,
++				      int nand_chunk,
++				      const u8 *data,
++				      struct yaffs_ext_tags *tags)
++{
++	int retval = YAFFS_OK;
++	struct yaffs_ext_tags temp_tags;
++	u8 *buffer = yaffs_get_temp_buffer(dev);
++	int result;
++
++	result = yaffs_rd_chunk_tags_nand(dev, nand_chunk, buffer, &temp_tags);
++	if (memcmp(buffer, data, dev->data_bytes_per_chunk) ||
++	    temp_tags.obj_id != tags->obj_id ||
++	    temp_tags.chunk_id != tags->chunk_id ||
++	    temp_tags.n_bytes != tags->n_bytes)
++		retval = YAFFS_FAIL;
++
++	yaffs_release_temp_buffer(dev, buffer);
++
++	return retval;
++}
++
++
++int yaffs_check_alloc_available(struct yaffs_dev *dev, int n_chunks)
++{
++	int reserved_chunks;
++	int reserved_blocks = dev->param.n_reserved_blocks;
++	int checkpt_blocks;
++
++	checkpt_blocks = yaffs_calc_checkpt_blocks_required(dev);
++
++	reserved_chunks =
++	    (reserved_blocks + checkpt_blocks) * dev->param.chunks_per_block;
++
++	return (dev->n_free_chunks > (reserved_chunks + n_chunks));
++}
++
++static int yaffs_find_alloc_block(struct yaffs_dev *dev)
++{
++	int i;
++	struct yaffs_block_info *bi;
++
++	if (dev->n_erased_blocks < 1) {
++		/* Hoosterman we've got a problem.
++		 * Can't get space to gc
++		 */
++		yaffs_trace(YAFFS_TRACE_ERROR,
++		  "yaffs tragedy: no more erased blocks");
++
++		return -1;
++	}
++
++	/* Find an empty block. */
++
++	for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
++		dev->alloc_block_finder++;
++		if (dev->alloc_block_finder < dev->internal_start_block
++		    || dev->alloc_block_finder > dev->internal_end_block) {
++			dev->alloc_block_finder = dev->internal_start_block;
++		}
++
++		bi = yaffs_get_block_info(dev, dev->alloc_block_finder);
++
++		if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {
++			bi->block_state = YAFFS_BLOCK_STATE_ALLOCATING;
++			dev->seq_number++;
++			bi->seq_number = dev->seq_number;
++			dev->n_erased_blocks--;
++			yaffs_trace(YAFFS_TRACE_ALLOCATE,
++			  "Allocated block %d, seq  %d, %d left" ,
++			   dev->alloc_block_finder, dev->seq_number,
++			   dev->n_erased_blocks);
++			return dev->alloc_block_finder;
++		}
++	}
++
++	yaffs_trace(YAFFS_TRACE_ALWAYS,
++		"yaffs tragedy: no more erased blocks, but there should have been %d",
++		dev->n_erased_blocks);
++
++	return -1;
++}
++
++static int yaffs_alloc_chunk(struct yaffs_dev *dev, int use_reserver,
++			     struct yaffs_block_info **block_ptr)
++{
++	int ret_val;
++	struct yaffs_block_info *bi;
++
++	if (dev->alloc_block < 0) {
++		/* Get next block to allocate off */
++		dev->alloc_block = yaffs_find_alloc_block(dev);
++		dev->alloc_page = 0;
++	}
++
++	if (!use_reserver && !yaffs_check_alloc_available(dev, 1)) {
++		/* No space unless we're allowed to use the reserve. */
++		return -1;
++	}
++
++	if (dev->n_erased_blocks < dev->param.n_reserved_blocks
++	    && dev->alloc_page == 0)
++		yaffs_trace(YAFFS_TRACE_ALLOCATE, "Allocating reserve");
++
++	/* Next page please.... */
++	if (dev->alloc_block >= 0) {
++		bi = yaffs_get_block_info(dev, dev->alloc_block);
++
++		ret_val = (dev->alloc_block * dev->param.chunks_per_block) +
++		    dev->alloc_page;
++		bi->pages_in_use++;
++		yaffs_set_chunk_bit(dev, dev->alloc_block, dev->alloc_page);
++
++		dev->alloc_page++;
++
++		dev->n_free_chunks--;
++
++		/* If the block is full set the state to full */
++		if (dev->alloc_page >= dev->param.chunks_per_block) {
++			bi->block_state = YAFFS_BLOCK_STATE_FULL;
++			dev->alloc_block = -1;
++		}
++
++		if (block_ptr)
++			*block_ptr = bi;
++
++		return ret_val;
++	}
++
++	yaffs_trace(YAFFS_TRACE_ERROR,
++		"!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!");
++
++	return -1;
++}
++
++static int yaffs_get_erased_chunks(struct yaffs_dev *dev)
++{
++	int n;
++
++	n = dev->n_erased_blocks * dev->param.chunks_per_block;
++
++	if (dev->alloc_block > 0)
++		n += (dev->param.chunks_per_block - dev->alloc_page);
++
++	return n;
++
++}
++
++/*
++ * yaffs_skip_rest_of_block() skips over the rest of the allocation block
++ * if we don't want to write to it.
++ */
++void yaffs_skip_rest_of_block(struct yaffs_dev *dev)
++{
++	struct yaffs_block_info *bi;
++
++	if (dev->alloc_block > 0) {
++		bi = yaffs_get_block_info(dev, dev->alloc_block);
++		if (bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING) {
++			bi->block_state = YAFFS_BLOCK_STATE_FULL;
++			dev->alloc_block = -1;
++		}
++	}
++}
++
++static int yaffs_write_new_chunk(struct yaffs_dev *dev,
++				 const u8 *data,
++				 struct yaffs_ext_tags *tags, int use_reserver)
++{
++	int attempts = 0;
++	int write_ok = 0;
++	int chunk;
++
++	yaffs2_checkpt_invalidate(dev);
++
++	do {
++		struct yaffs_block_info *bi = 0;
++		int erased_ok = 0;
++
++		chunk = yaffs_alloc_chunk(dev, use_reserver, &bi);
++		if (chunk < 0) {
++			/* no space */
++			break;
++		}
++
++		/* First check this chunk is erased, if it needs
++		 * checking.  The checking policy (unless forced
++		 * always on) is as follows:
++		 *
++		 * Check the first page we try to write in a block.
++		 * If the check passes then we don't need to check any
++		 * more.        If the check fails, we check again...
++		 * If the block has been erased, we don't need to check.
++		 *
++		 * However, if the block has been prioritised for gc,
++		 * then we think there might be something odd about
++		 * this block and stop using it.
++		 *
++		 * Rationale: We should only ever see chunks that have
++		 * not been erased if there was a partially written
++		 * chunk due to power loss.  This checking policy should
++		 * catch that case with very few checks and thus save a
++		 * lot of checks that are most likely not needed.
++		 *
++		 * Mods to the above
++		 * If an erase check fails or the write fails we skip the
++		 * rest of the block.
++		 */
++
++		/* let's give it a try */
++		attempts++;
++
++		if (dev->param.always_check_erased)
++			bi->skip_erased_check = 0;
++
++		if (!bi->skip_erased_check) {
++			erased_ok = yaffs_check_chunk_erased(dev, chunk);
++			if (erased_ok != YAFFS_OK) {
++				yaffs_trace(YAFFS_TRACE_ERROR,
++				  "**>> yaffs chunk %d was not erased",
++				  chunk);
++
++				/* If not erased, delete this one,
++				 * skip rest of block and
++				 * try another chunk */
++				yaffs_chunk_del(dev, chunk, 1, __LINE__);
++				yaffs_skip_rest_of_block(dev);
++				continue;
++			}
++		}
++
++		write_ok = yaffs_wr_chunk_tags_nand(dev, chunk, data, tags);
++
++		if (!bi->skip_erased_check)
++			write_ok =
++			    yaffs_verify_chunk_written(dev, chunk, data, tags);
++
++		if (write_ok != YAFFS_OK) {
++			/* Clean up aborted write, skip to next block and
++			 * try another chunk */
++			yaffs_handle_chunk_wr_error(dev, chunk, erased_ok);
++			continue;
++		}
++
++		bi->skip_erased_check = 1;
++
++		/* Copy the data into the robustification buffer */
++		yaffs_handle_chunk_wr_ok(dev, chunk, data, tags);
++
++	} while (write_ok != YAFFS_OK &&
++		 (yaffs_wr_attempts <= 0 || attempts <= yaffs_wr_attempts));
++
++	if (!write_ok)
++		chunk = -1;
++
++	if (attempts > 1) {
++		yaffs_trace(YAFFS_TRACE_ERROR,
++			"**>> yaffs write required %d attempts",
++			attempts);
++		dev->n_retried_writes += (attempts - 1);
++	}
++
++	return chunk;
++}
++
++/*
++ * Block retiring for handling a broken block.
++ */
++
++static void yaffs_retire_block(struct yaffs_dev *dev, int flash_block)
++{
++	struct yaffs_block_info *bi = yaffs_get_block_info(dev, flash_block);
++
++	yaffs2_checkpt_invalidate(dev);
++
++	yaffs2_clear_oldest_dirty_seq(dev, bi);
++
++	if (yaffs_mark_bad(dev, flash_block) != YAFFS_OK) {
++		if (yaffs_erase_block(dev, flash_block) != YAFFS_OK) {
++			yaffs_trace(YAFFS_TRACE_ALWAYS,
++				"yaffs: Failed to mark bad and erase block %d",
++				flash_block);
++		} else {
++			struct yaffs_ext_tags tags;
++			int chunk_id =
++			    flash_block * dev->param.chunks_per_block;
++
++			u8 *buffer = yaffs_get_temp_buffer(dev);
++
++			memset(buffer, 0xff, dev->data_bytes_per_chunk);
++			memset(&tags, 0, sizeof(tags));
++			tags.seq_number = YAFFS_SEQUENCE_BAD_BLOCK;
++			if (dev->tagger.write_chunk_tags_fn(dev, chunk_id -
++							dev->chunk_offset,
++							buffer,
++							&tags) != YAFFS_OK)
++				yaffs_trace(YAFFS_TRACE_ALWAYS,
++					"yaffs: Failed to write bad block marker to block %d",
++					flash_block);
++
++			yaffs_release_temp_buffer(dev, buffer);
++		}
++	}
++
++	bi->block_state = YAFFS_BLOCK_STATE_DEAD;
++	bi->gc_prioritise = 0;
++	bi->needs_retiring = 0;
++
++	dev->n_retired_blocks++;
++}
++
++/*---------------- Name handling functions ------------*/
++
++static void yaffs_load_name_from_oh(struct yaffs_dev *dev, YCHAR *name,
++				    const YCHAR *oh_name, int buff_size)
++{
++#ifdef CONFIG_YAFFS_AUTO_UNICODE
++	if (dev->param.auto_unicode) {
++		if (*oh_name) {
++			/* It is an ASCII name, do an ASCII to
++			 * unicode conversion */
++			const char *ascii_oh_name = (const char *)oh_name;
++			int n = buff_size - 1;
++			while (n > 0 && *ascii_oh_name) {
++				*name = *ascii_oh_name;
++				name++;
++				ascii_oh_name++;
++				n--;
++			}
++		} else {
++			strncpy(name, oh_name + 1, buff_size - 1);
++		}
++	} else {
++#else
++	(void) dev;
++	{
++#endif
++		strncpy(name, oh_name, buff_size - 1);
++	}
++}
++
++static void yaffs_load_oh_from_name(struct yaffs_dev *dev, YCHAR *oh_name,
++				    const YCHAR *name)
++{
++#ifdef CONFIG_YAFFS_AUTO_UNICODE
++
++	int is_ascii;
++	const YCHAR *w;
++
++	if (dev->param.auto_unicode) {
++
++		is_ascii = 1;
++		w = name;
++
++		/* Figure out if the name will fit in ascii character set */
++		while (is_ascii && *w) {
++			if ((*w) & 0xff00)
++				is_ascii = 0;
++			w++;
++		}
++
++		if (is_ascii) {
++			/* It is an ASCII name, so convert unicode to ascii */
++			char *ascii_oh_name = (char *)oh_name;
++			int n = YAFFS_MAX_NAME_LENGTH - 1;
++			while (n > 0 && *name) {
++				*ascii_oh_name = *name;
++				name++;
++				ascii_oh_name++;
++				n--;
++			}
++		} else {
++			/* Unicode name, so save starting at the second YCHAR */
++			*oh_name = 0;
++			strncpy(oh_name + 1, name, YAFFS_MAX_NAME_LENGTH - 2);
++		}
++	} else {
++#else
++	dev = dev;
++	{
++#endif
++		strncpy(oh_name, name, YAFFS_MAX_NAME_LENGTH - 1);
++	}
++}
++
++static u16 yaffs_calc_name_sum(const YCHAR *name)
++{
++	u16 sum = 0;
++	u16 i = 1;
++
++	if (!name)
++		return 0;
++
++	while ((*name) && i < (YAFFS_MAX_NAME_LENGTH / 2)) {
++
++		/* 0x1f mask is case insensitive */
++		sum += ((*name) & 0x1f) * i;
++		i++;
++		name++;
++	}
++	return sum;
++}
++
++
++void yaffs_set_obj_name(struct yaffs_obj *obj, const YCHAR * name)
++{
++	memset(obj->short_name, 0, sizeof(obj->short_name));
++
++	if (name && !name[0]) {
++		yaffs_fix_null_name(obj, obj->short_name,
++				YAFFS_SHORT_NAME_LENGTH);
++		name = obj->short_name;
++	} else if (name &&
++		strnlen(name, YAFFS_SHORT_NAME_LENGTH + 1) <=
++		YAFFS_SHORT_NAME_LENGTH)  {
++		strcpy(obj->short_name, name);
++	}
++
++	obj->sum = yaffs_calc_name_sum(name);
++}
++
++void yaffs_set_obj_name_from_oh(struct yaffs_obj *obj,
++				const struct yaffs_obj_hdr *oh)
++{
++#ifdef CONFIG_YAFFS_AUTO_UNICODE
++	YCHAR tmp_name[YAFFS_MAX_NAME_LENGTH + 1];
++	memset(tmp_name, 0, sizeof(tmp_name));
++	yaffs_load_name_from_oh(obj->my_dev, tmp_name, oh->name,
++				YAFFS_MAX_NAME_LENGTH + 1);
++	yaffs_set_obj_name(obj, tmp_name);
++#else
++	yaffs_set_obj_name(obj, oh->name);
++#endif
++}
++
++loff_t yaffs_max_file_size(struct yaffs_dev *dev)
++{
++	if(sizeof(loff_t) < 8)
++		return YAFFS_MAX_FILE_SIZE_32;
++	else
++		return ((loff_t) YAFFS_MAX_CHUNK_ID) * dev->data_bytes_per_chunk;
++}
++
++/*-------------------- TNODES -------------------
++
++ * List of spare tnodes
++ * The list is hooked together using the first pointer
++ * in the tnode.
++ */
++
++struct yaffs_tnode *yaffs_get_tnode(struct yaffs_dev *dev)
++{
++	struct yaffs_tnode *tn = yaffs_alloc_raw_tnode(dev);
++
++	if (tn) {
++		memset(tn, 0, dev->tnode_size);
++		dev->n_tnodes++;
++	}
++
++	dev->checkpoint_blocks_required = 0;	/* force recalculation */
++
++	return tn;
++}
++
++/* FreeTnode frees up a tnode and puts it back on the free list */
++static void yaffs_free_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn)
++{
++	yaffs_free_raw_tnode(dev, tn);
++	dev->n_tnodes--;
++	dev->checkpoint_blocks_required = 0;	/* force recalculation */
++}
++
++static void yaffs_deinit_tnodes_and_objs(struct yaffs_dev *dev)
++{
++	yaffs_deinit_raw_tnodes_and_objs(dev);
++	dev->n_obj = 0;
++	dev->n_tnodes = 0;
++}
++
++static void yaffs_load_tnode_0(struct yaffs_dev *dev, struct yaffs_tnode *tn,
++			unsigned pos, unsigned val)
++{
++	u32 *map = (u32 *) tn;
++	u32 bit_in_map;
++	u32 bit_in_word;
++	u32 word_in_map;
++	u32 mask;
++
++	pos &= YAFFS_TNODES_LEVEL0_MASK;
++	val >>= dev->chunk_grp_bits;
++
++	bit_in_map = pos * dev->tnode_width;
++	word_in_map = bit_in_map / 32;
++	bit_in_word = bit_in_map & (32 - 1);
++
++	mask = dev->tnode_mask << bit_in_word;
++
++	map[word_in_map] &= ~mask;
++	map[word_in_map] |= (mask & (val << bit_in_word));
++
++	if (dev->tnode_width > (32 - bit_in_word)) {
++		bit_in_word = (32 - bit_in_word);
++		word_in_map++;
++		mask =
++		    dev->tnode_mask >> bit_in_word;
++		map[word_in_map] &= ~mask;
++		map[word_in_map] |= (mask & (val >> bit_in_word));
++	}
++}
++
++u32 yaffs_get_group_base(struct yaffs_dev *dev, struct yaffs_tnode *tn,
++			 unsigned pos)
++{
++	u32 *map = (u32 *) tn;
++	u32 bit_in_map;
++	u32 bit_in_word;
++	u32 word_in_map;
++	u32 val;
++
++	pos &= YAFFS_TNODES_LEVEL0_MASK;
++
++	bit_in_map = pos * dev->tnode_width;
++	word_in_map = bit_in_map / 32;
++	bit_in_word = bit_in_map & (32 - 1);
++
++	val = map[word_in_map] >> bit_in_word;
++
++	if (dev->tnode_width > (32 - bit_in_word)) {
++		bit_in_word = (32 - bit_in_word);
++		word_in_map++;
++		val |= (map[word_in_map] << bit_in_word);
++	}
++
++	val &= dev->tnode_mask;
++	val <<= dev->chunk_grp_bits;
++
++	return val;
++}
++
++/* ------------------- End of individual tnode manipulation -----------------*/
++
++/* ---------Functions to manipulate the look-up tree (made up of tnodes) ------
++ * The look up tree is represented by the top tnode and the number of top_level
++ * in the tree. 0 means only the level 0 tnode is in the tree.
++ */
++
++/* FindLevel0Tnode finds the level 0 tnode, if one exists. */
++struct yaffs_tnode *yaffs_find_tnode_0(struct yaffs_dev *dev,
++				       struct yaffs_file_var *file_struct,
++				       u32 chunk_id)
++{
++	struct yaffs_tnode *tn = file_struct->top;
++	u32 i;
++	int required_depth;
++	int level = file_struct->top_level;
++
++	(void) dev;
++
++	/* Check sane level and chunk Id */
++	if (level < 0 || level > YAFFS_TNODES_MAX_LEVEL)
++		return NULL;
++
++	if (chunk_id > YAFFS_MAX_CHUNK_ID)
++		return NULL;
++
++	/* First check we're tall enough (ie enough top_level) */
++
++	i = chunk_id >> YAFFS_TNODES_LEVEL0_BITS;
++	required_depth = 0;
++	while (i) {
++		i >>= YAFFS_TNODES_INTERNAL_BITS;
++		required_depth++;
++	}
++
++	if (required_depth > file_struct->top_level)
++		return NULL;	/* Not tall enough, so we can't find it */
++
++	/* Traverse down to level 0 */
++	while (level > 0 && tn) {
++		tn = tn->internal[(chunk_id >>
++				   (YAFFS_TNODES_LEVEL0_BITS +
++				    (level - 1) *
++				    YAFFS_TNODES_INTERNAL_BITS)) &
++				  YAFFS_TNODES_INTERNAL_MASK];
++		level--;
++	}
++
++	return tn;
++}
++
++/* add_find_tnode_0 finds the level 0 tnode if it exists,
++ * otherwise first expands the tree.
++ * This happens in two steps:
++ *  1. If the tree isn't tall enough, then make it taller.
++ *  2. Scan down the tree towards the level 0 tnode adding tnodes if required.
++ *
++ * Used when modifying the tree.
++ *
++ *  If the tn argument is NULL, then a fresh tnode will be added otherwise the
++ *  specified tn will be plugged into the ttree.
++ */
++
++struct yaffs_tnode *yaffs_add_find_tnode_0(struct yaffs_dev *dev,
++					   struct yaffs_file_var *file_struct,
++					   u32 chunk_id,
++					   struct yaffs_tnode *passed_tn)
++{
++	int required_depth;
++	int i;
++	int l;
++	struct yaffs_tnode *tn;
++	u32 x;
++
++	/* Check sane level and page Id */
++	if (file_struct->top_level < 0 ||
++	    file_struct->top_level > YAFFS_TNODES_MAX_LEVEL)
++		return NULL;
++
++	if (chunk_id > YAFFS_MAX_CHUNK_ID)
++		return NULL;
++
++	/* First check we're tall enough (ie enough top_level) */
++
++	x = chunk_id >> YAFFS_TNODES_LEVEL0_BITS;
++	required_depth = 0;
++	while (x) {
++		x >>= YAFFS_TNODES_INTERNAL_BITS;
++		required_depth++;
++	}
++
++	if (required_depth > file_struct->top_level) {
++		/* Not tall enough, gotta make the tree taller */
++		for (i = file_struct->top_level; i < required_depth; i++) {
++
++			tn = yaffs_get_tnode(dev);
++
++			if (tn) {
++				tn->internal[0] = file_struct->top;
++				file_struct->top = tn;
++				file_struct->top_level++;
++			} else {
++				yaffs_trace(YAFFS_TRACE_ERROR,
++					"yaffs: no more tnodes");
++				return NULL;
++			}
++		}
++	}
++
++	/* Traverse down to level 0, adding anything we need */
++
++	l = file_struct->top_level;
++	tn = file_struct->top;
++
++	if (l > 0) {
++		while (l > 0 && tn) {
++			x = (chunk_id >>
++			     (YAFFS_TNODES_LEVEL0_BITS +
++			      (l - 1) * YAFFS_TNODES_INTERNAL_BITS)) &
++			    YAFFS_TNODES_INTERNAL_MASK;
++
++			if ((l > 1) && !tn->internal[x]) {
++				/* Add missing non-level-zero tnode */
++				tn->internal[x] = yaffs_get_tnode(dev);
++				if (!tn->internal[x])
++					return NULL;
++			} else if (l == 1) {
++				/* Looking from level 1 at level 0 */
++				if (passed_tn) {
++					/* If we already have one, release it */
++					if (tn->internal[x])
++						yaffs_free_tnode(dev,
++							tn->internal[x]);
++					tn->internal[x] = passed_tn;
++
++				} else if (!tn->internal[x]) {
++					/* Don't have one, none passed in */
++					tn->internal[x] = yaffs_get_tnode(dev);
++					if (!tn->internal[x])
++						return NULL;
++				}
++			}
++
++			tn = tn->internal[x];
++			l--;
++		}
++	} else {
++		/* top is level 0 */
++		if (passed_tn) {
++			memcpy(tn, passed_tn,
++			       (dev->tnode_width * YAFFS_NTNODES_LEVEL0) / 8);
++			yaffs_free_tnode(dev, passed_tn);
++		}
++	}
++
++	return tn;
++}
++
++static int yaffs_tags_match(const struct yaffs_ext_tags *tags, int obj_id,
++			    int chunk_obj)
++{
++	return (tags->chunk_id == chunk_obj &&
++		tags->obj_id == obj_id &&
++		!tags->is_deleted) ? 1 : 0;
++
++}
++
++static int yaffs_find_chunk_in_group(struct yaffs_dev *dev, int the_chunk,
++					struct yaffs_ext_tags *tags, int obj_id,
++					int inode_chunk)
++{
++	int j;
++
++	for (j = 0; the_chunk && j < dev->chunk_grp_size; j++) {
++		if (yaffs_check_chunk_bit
++		    (dev, the_chunk / dev->param.chunks_per_block,
++		     the_chunk % dev->param.chunks_per_block)) {
++
++			if (dev->chunk_grp_size == 1)
++				return the_chunk;
++			else {
++				yaffs_rd_chunk_tags_nand(dev, the_chunk, NULL,
++							 tags);
++				if (yaffs_tags_match(tags,
++							obj_id, inode_chunk)) {
++					/* found it; */
++					return the_chunk;
++				}
++			}
++		}
++		the_chunk++;
++	}
++	return -1;
++}
++
++int yaffs_find_chunk_in_file(struct yaffs_obj *in, int inode_chunk,
++				    struct yaffs_ext_tags *tags)
++{
++	/*Get the Tnode, then get the level 0 offset chunk offset */
++	struct yaffs_tnode *tn;
++	int the_chunk = -1;
++	struct yaffs_ext_tags local_tags;
++	int ret_val = -1;
++	struct yaffs_dev *dev = in->my_dev;
++
++	if (!tags) {
++		/* Passed a NULL, so use our own tags space */
++		tags = &local_tags;
++	}
++
++	tn = yaffs_find_tnode_0(dev, &in->variant.file_variant, inode_chunk);
++
++	if (!tn)
++		return ret_val;
++
++	the_chunk = yaffs_get_group_base(dev, tn, inode_chunk);
++
++	ret_val = yaffs_find_chunk_in_group(dev, the_chunk, tags, in->obj_id,
++					      inode_chunk);
++	return ret_val;
++}
++
++static int yaffs_find_del_file_chunk(struct yaffs_obj *in, int inode_chunk,
++				     struct yaffs_ext_tags *tags)
++{
++	/* Get the Tnode, then get the level 0 offset chunk offset */
++	struct yaffs_tnode *tn;
++	int the_chunk = -1;
++	struct yaffs_ext_tags local_tags;
++	struct yaffs_dev *dev = in->my_dev;
++	int ret_val = -1;
++
++	if (!tags) {
++		/* Passed a NULL, so use our own tags space */
++		tags = &local_tags;
++	}
++
++	tn = yaffs_find_tnode_0(dev, &in->variant.file_variant, inode_chunk);
++
++	if (!tn)
++		return ret_val;
++
++	the_chunk = yaffs_get_group_base(dev, tn, inode_chunk);
++
++	ret_val = yaffs_find_chunk_in_group(dev, the_chunk, tags, in->obj_id,
++					      inode_chunk);
++
++	/* Delete the entry in the filestructure (if found) */
++	if (ret_val != -1)
++		yaffs_load_tnode_0(dev, tn, inode_chunk, 0);
++
++	return ret_val;
++}
++
++int yaffs_put_chunk_in_file(struct yaffs_obj *in, int inode_chunk,
++			    int nand_chunk, int in_scan)
++{
++	/* NB in_scan is zero unless scanning.
++	 * For forward scanning, in_scan is > 0;
++	 * for backward scanning in_scan is < 0
++	 *
++	 * nand_chunk = 0 is a dummy insert to make sure the tnodes are there.
++	 */
++
++	struct yaffs_tnode *tn;
++	struct yaffs_dev *dev = in->my_dev;
++	int existing_cunk;
++	struct yaffs_ext_tags existing_tags;
++	struct yaffs_ext_tags new_tags;
++	unsigned existing_serial, new_serial;
++
++	if (in->variant_type != YAFFS_OBJECT_TYPE_FILE) {
++		/* Just ignore an attempt at putting a chunk into a non-file
++		 * during scanning.
++		 * If it is not during Scanning then something went wrong!
++		 */
++		if (!in_scan) {
++			yaffs_trace(YAFFS_TRACE_ERROR,
++				"yaffs tragedy:attempt to put data chunk into a non-file"
++				);
++			BUG();
++		}
++
++		yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);
++		return YAFFS_OK;
++	}
++
++	tn = yaffs_add_find_tnode_0(dev,
++				    &in->variant.file_variant,
++				    inode_chunk, NULL);
++	if (!tn)
++		return YAFFS_FAIL;
++
++	if (!nand_chunk)
++		/* Dummy insert, bail now */
++		return YAFFS_OK;
++
++	existing_cunk = yaffs_get_group_base(dev, tn, inode_chunk);
++
++	if (in_scan != 0) {
++		/* If we're scanning then we need to test for duplicates
++		 * NB This does not need to be efficient since it should only
++		 * happen when the power fails during a write, then only one
++		 * chunk should ever be affected.
++		 *
++		 * Correction for YAFFS2: This could happen quite a lot and we
++		 * need to think about efficiency! TODO
++		 * Update: For backward scanning we don't need to re-read tags
++		 * so this is quite cheap.
++		 */
++
++		if (existing_cunk > 0) {
++			/* NB Right now existing chunk will not be real
++			 * chunk_id if the chunk group size > 1
++			 * thus we have to do a FindChunkInFile to get the
++			 * real chunk id.
++			 *
++			 * We have a duplicate now we need to decide which
++			 * one to use:
++			 *
++			 * Backwards scanning YAFFS2: The old one is what
++			 * we use, dump the new one.
++			 * YAFFS1: Get both sets of tags and compare serial
++			 * numbers.
++			 */
++
++			if (in_scan > 0) {
++				/* Only do this for forward scanning */
++				yaffs_rd_chunk_tags_nand(dev,
++							 nand_chunk,
++							 NULL, &new_tags);
++
++				/* Do a proper find */
++				existing_cunk =
++				    yaffs_find_chunk_in_file(in, inode_chunk,
++							     &existing_tags);
++			}
++
++			if (existing_cunk <= 0) {
++				/*Hoosterman - how did this happen? */
++
++				yaffs_trace(YAFFS_TRACE_ERROR,
++					"yaffs tragedy: existing chunk < 0 in scan"
++					);
++
++			}
++
++			/* NB The deleted flags should be false, otherwise
++			 * the chunks will not be loaded during a scan
++			 */
++
++			if (in_scan > 0) {
++				new_serial = new_tags.serial_number;
++				existing_serial = existing_tags.serial_number;
++			}
++
++			if ((in_scan > 0) &&
++			    (existing_cunk <= 0 ||
++			     ((existing_serial + 1) & 3) == new_serial)) {
++				/* Forward scanning.
++				 * Use new
++				 * Delete the old one and drop through to
++				 * update the tnode
++				 */
++				yaffs_chunk_del(dev, existing_cunk, 1,
++						__LINE__);
++			} else {
++				/* Backward scanning or we want to use the
++				 * existing one
++				 * Delete the new one and return early so that
++				 * the tnode isn't changed
++				 */
++				yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);
++				return YAFFS_OK;
++			}
++		}
++
++	}
++
++	if (existing_cunk == 0)
++		in->n_data_chunks++;
++
++	yaffs_load_tnode_0(dev, tn, inode_chunk, nand_chunk);
++
++	return YAFFS_OK;
++}
++
++static void yaffs_soft_del_chunk(struct yaffs_dev *dev, int chunk)
++{
++	struct yaffs_block_info *the_block;
++	unsigned block_no;
++
++	yaffs_trace(YAFFS_TRACE_DELETION, "soft delete chunk %d", chunk);
++
++	block_no = chunk / dev->param.chunks_per_block;
++	the_block = yaffs_get_block_info(dev, block_no);
++	if (the_block) {
++		the_block->soft_del_pages++;
++		dev->n_free_chunks++;
++		yaffs2_update_oldest_dirty_seq(dev, block_no, the_block);
++	}
++}
++
++/* SoftDeleteWorker scans backwards through the tnode tree and soft deletes all
++ * the chunks in the file.
++ * All soft deleting does is increment the block's softdelete count and pulls
++ * the chunk out of the tnode.
++ * Thus, essentially this is the same as DeleteWorker except that the chunks
++ * are soft deleted.
++ */
++
++static int yaffs_soft_del_worker(struct yaffs_obj *in, struct yaffs_tnode *tn,
++				 u32 level, int chunk_offset)
++{
++	int i;
++	int the_chunk;
++	int all_done = 1;
++	struct yaffs_dev *dev = in->my_dev;
++
++	if (!tn)
++		return 1;
++
++	if (level > 0) {
++		for (i = YAFFS_NTNODES_INTERNAL - 1;
++			all_done && i >= 0;
++			i--) {
++			if (tn->internal[i]) {
++				all_done =
++				    yaffs_soft_del_worker(in,
++					tn->internal[i],
++					level - 1,
++					(chunk_offset <<
++					YAFFS_TNODES_INTERNAL_BITS)
++					+ i);
++				if (all_done) {
++					yaffs_free_tnode(dev,
++						tn->internal[i]);
++					tn->internal[i] = NULL;
++				} else {
++					/* Can this happen? */
++				}
++			}
++		}
++		return (all_done) ? 1 : 0;
++	}
++
++	/* level 0 */
++	 for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0; i--) {
++		the_chunk = yaffs_get_group_base(dev, tn, i);
++		if (the_chunk) {
++			yaffs_soft_del_chunk(dev, the_chunk);
++			yaffs_load_tnode_0(dev, tn, i, 0);
++		}
++	}
++	return 1;
++}
++
++static void yaffs_remove_obj_from_dir(struct yaffs_obj *obj)
++{
++	struct yaffs_dev *dev = obj->my_dev;
++	struct yaffs_obj *parent;
++
++	yaffs_verify_obj_in_dir(obj);
++	parent = obj->parent;
++
++	yaffs_verify_dir(parent);
++
++	if (dev && dev->param.remove_obj_fn)
++		dev->param.remove_obj_fn(obj);
++
++	list_del_init(&obj->siblings);
++	obj->parent = NULL;
++
++	yaffs_verify_dir(parent);
++}
++
++void yaffs_add_obj_to_dir(struct yaffs_obj *directory, struct yaffs_obj *obj)
++{
++	if (!directory) {
++		yaffs_trace(YAFFS_TRACE_ALWAYS,
++			"tragedy: Trying to add an object to a null pointer directory"
++			);
++		BUG();
++		return;
++	}
++	if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
++		yaffs_trace(YAFFS_TRACE_ALWAYS,
++			"tragedy: Trying to add an object to a non-directory"
++			);
++		BUG();
++	}
++
++	if (obj->siblings.prev == NULL) {
++		/* Not initialised */
++		BUG();
++	}
++
++	yaffs_verify_dir(directory);
++
++	yaffs_remove_obj_from_dir(obj);
++
++	/* Now add it */
++	list_add(&obj->siblings, &directory->variant.dir_variant.children);
++	obj->parent = directory;
++
++	if (directory == obj->my_dev->unlinked_dir
++	    || directory == obj->my_dev->del_dir) {
++		obj->unlinked = 1;
++		obj->my_dev->n_unlinked_files++;
++		obj->rename_allowed = 0;
++	}
++
++	yaffs_verify_dir(directory);
++	yaffs_verify_obj_in_dir(obj);
++}
++
++static int yaffs_change_obj_name(struct yaffs_obj *obj,
++				 struct yaffs_obj *new_dir,
++				 const YCHAR *new_name, int force, int shadows)
++{
++	int unlink_op;
++	int del_op;
++	struct yaffs_obj *existing_target;
++
++	if (new_dir == NULL)
++		new_dir = obj->parent;	/* use the old directory */
++
++	if (new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
++		yaffs_trace(YAFFS_TRACE_ALWAYS,
++			"tragedy: yaffs_change_obj_name: new_dir is not a directory"
++			);
++		BUG();
++	}
++
++	unlink_op = (new_dir == obj->my_dev->unlinked_dir);
++	del_op = (new_dir == obj->my_dev->del_dir);
++
++	existing_target = yaffs_find_by_name(new_dir, new_name);
++
++	/* If the object is a file going into the unlinked directory,
++	 *   then it is OK to just stuff it in since duplicate names are OK.
++	 *   else only proceed if the new name does not exist and we're putting
++	 *   it into a directory.
++	 */
++	if (!(unlink_op || del_op || force ||
++	      shadows > 0 || !existing_target) ||
++	      new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
++		return YAFFS_FAIL;
++
++	yaffs_set_obj_name(obj, new_name);
++	obj->dirty = 1;
++	yaffs_add_obj_to_dir(new_dir, obj);
++
++	if (unlink_op)
++		obj->unlinked = 1;
++
++	/* If it is a deletion then we mark it as a shrink for gc  */
++	if (yaffs_update_oh(obj, new_name, 0, del_op, shadows, NULL) >= 0)
++		return YAFFS_OK;
++
++	return YAFFS_FAIL;
++}
++
++/*------------------------ Short Operations Cache ------------------------------
++ *   In many situations where there is no high level buffering  a lot of
++ *   reads might be short sequential reads, and a lot of writes may be short
++ *   sequential writes. eg. scanning/writing a jpeg file.
++ *   In these cases, a short read/write cache can provide a huge perfomance
++ *   benefit with dumb-as-a-rock code.
++ *   In Linux, the page cache provides read buffering and the short op cache
++ *   provides write buffering.
++ *
++ *   There are a small number (~10) of cache chunks per device so that we don't
++ *   need a very intelligent search.
++ */
++
++static int yaffs_obj_cache_dirty(struct yaffs_obj *obj)
++{
++	struct yaffs_dev *dev = obj->my_dev;
++	int i;
++	struct yaffs_cache *cache;
++	int n_caches = obj->my_dev->param.n_caches;
++
++	for (i = 0; i < n_caches; i++) {
++		cache = &dev->cache[i];
++		if (cache->object == obj && cache->dirty)
++			return 1;
++	}
++
++	return 0;
++}
++
++static void yaffs_flush_single_cache(struct yaffs_cache *cache, int discard)
++{
++
++	if (!cache || cache->locked)
++		return;
++
++	/* Write it out and free it up  if need be.*/
++	if (cache->dirty) {
++		yaffs_wr_data_obj(cache->object,
++				  cache->chunk_id,
++				  cache->data,
++				  cache->n_bytes,
++				  1);
++
++		cache->dirty = 0;
++	}
++
++	if (discard)
++		cache->object = NULL;
++}
++
++static void yaffs_flush_file_cache(struct yaffs_obj *obj, int discard)
++{
++	struct yaffs_dev *dev = obj->my_dev;
++	int i;
++	struct yaffs_cache *cache;
++	int n_caches = obj->my_dev->param.n_caches;
++
++	if (n_caches < 1)
++		return;
++
++
++	/* Find the chunks for this object and flush them. */
++	for (i = 0; i < n_caches; i++) {
++		cache = &dev->cache[i];
++		if (cache->object == obj)
++			yaffs_flush_single_cache(cache, discard);
++	}
++
++}
++
++
++void yaffs_flush_whole_cache(struct yaffs_dev *dev, int discard)
++{
++	struct yaffs_obj *obj;
++	int n_caches = dev->param.n_caches;
++	int i;
++
++	/* Find a dirty object in the cache and flush it...
++	 * until there are no further dirty objects.
++	 */
++	do {
++		obj = NULL;
++		for (i = 0; i < n_caches && !obj; i++) {
++			if (dev->cache[i].object && dev->cache[i].dirty)
++				obj = dev->cache[i].object;
++		}
++		if (obj)
++			yaffs_flush_file_cache(obj, discard);
++	} while (obj);
++
++}
++
++/* Grab us an unused cache chunk for use.
++ * First look for an empty one.
++ * Then look for the least recently used non-dirty one.
++ * Then look for the least recently used dirty one...., flush and look again.
++ */
++static struct yaffs_cache *yaffs_grab_chunk_worker(struct yaffs_dev *dev)
++{
++	int i;
++
++	if (dev->param.n_caches > 0) {
++		for (i = 0; i < dev->param.n_caches; i++) {
++			if (!dev->cache[i].object)
++				return &dev->cache[i];
++		}
++	}
++
++	return NULL;
++}
++
++static struct yaffs_cache *yaffs_grab_chunk_cache(struct yaffs_dev *dev)
++{
++	struct yaffs_cache *cache;
++	int usage;
++	int i;
++
++	if (dev->param.n_caches < 1)
++		return NULL;
++
++	/* First look for an unused cache */
++
++	cache = yaffs_grab_chunk_worker(dev);
++
++	if (cache)
++		return cache;
++
++	/*
++	 * Thery were all in use.
++	 * Find the LRU cache and flush it if it is dirty.
++	 */
++
++	usage = -1;
++	cache = NULL;
++
++	for (i = 0; i < dev->param.n_caches; i++) {
++		if (dev->cache[i].object &&
++		    !dev->cache[i].locked &&
++		    (dev->cache[i].last_use < usage || !cache)) {
++				usage = dev->cache[i].last_use;
++				cache = &dev->cache[i];
++		}
++	}
++
++#if 1
++	yaffs_flush_single_cache(cache, 1);
++#else
++	yaffs_flush_file_cache(cache->object, 1);
++	cache = yaffs_grab_chunk_worker(dev);
++#endif
++
++	return cache;
++}
++
++/* Find a cached chunk */
++static struct yaffs_cache *yaffs_find_chunk_cache(const struct yaffs_obj *obj,
++						  int chunk_id)
++{
++	struct yaffs_dev *dev = obj->my_dev;
++	int i;
++
++	if (dev->param.n_caches < 1)
++		return NULL;
++
++	for (i = 0; i < dev->param.n_caches; i++) {
++		if (dev->cache[i].object == obj &&
++		    dev->cache[i].chunk_id == chunk_id) {
++			dev->cache_hits++;
++
++			return &dev->cache[i];
++		}
++	}
++	return NULL;
++}
++
++/* Mark the chunk for the least recently used algorithym */
++static void yaffs_use_cache(struct yaffs_dev *dev, struct yaffs_cache *cache,
++			    int is_write)
++{
++	int i;
++
++	if (dev->param.n_caches < 1)
++		return;
++
++	if (dev->cache_last_use < 0 ||
++		dev->cache_last_use > 100000000) {
++		/* Reset the cache usages */
++		for (i = 1; i < dev->param.n_caches; i++)
++			dev->cache[i].last_use = 0;
++
++		dev->cache_last_use = 0;
++	}
++	dev->cache_last_use++;
++	cache->last_use = dev->cache_last_use;
++
++	if (is_write)
++		cache->dirty = 1;
++}
++
++/* Invalidate a single cache page.
++ * Do this when a whole page gets written,
++ * ie the short cache for this page is no longer valid.
++ */
++static void yaffs_invalidate_chunk_cache(struct yaffs_obj *object, int chunk_id)
++{
++	struct yaffs_cache *cache;
++
++	if (object->my_dev->param.n_caches > 0) {
++		cache = yaffs_find_chunk_cache(object, chunk_id);
++
++		if (cache)
++			cache->object = NULL;
++	}
++}
++
++/* Invalidate all the cache pages associated with this object
++ * Do this whenever ther file is deleted or resized.
++ */
++static void yaffs_invalidate_whole_cache(struct yaffs_obj *in)
++{
++	int i;
++	struct yaffs_dev *dev = in->my_dev;
++
++	if (dev->param.n_caches > 0) {
++		/* Invalidate it. */
++		for (i = 0; i < dev->param.n_caches; i++) {
++			if (dev->cache[i].object == in)
++				dev->cache[i].object = NULL;
++		}
++	}
++}
++
++static void yaffs_unhash_obj(struct yaffs_obj *obj)
++{
++	int bucket;
++	struct yaffs_dev *dev = obj->my_dev;
++
++	/* If it is still linked into the bucket list, free from the list */
++	if (!list_empty(&obj->hash_link)) {
++		list_del_init(&obj->hash_link);
++		bucket = yaffs_hash_fn(obj->obj_id);
++		dev->obj_bucket[bucket].count--;
++	}
++}
++
++/*  FreeObject frees up a Object and puts it back on the free list */
++static void yaffs_free_obj(struct yaffs_obj *obj)
++{
++	struct yaffs_dev *dev;
++
++	if (!obj) {
++		BUG();
++		return;
++	}
++	dev = obj->my_dev;
++	yaffs_trace(YAFFS_TRACE_OS, "FreeObject %p inode %p",
++		obj, obj->my_inode);
++	if (obj->parent)
++		BUG();
++	if (!list_empty(&obj->siblings))
++		BUG();
++
++	if (obj->my_inode) {
++		/* We're still hooked up to a cached inode.
++		 * Don't delete now, but mark for later deletion
++		 */
++		obj->defered_free = 1;
++		return;
++	}
++
++	yaffs_unhash_obj(obj);
++
++	yaffs_free_raw_obj(dev, obj);
++	dev->n_obj--;
++	dev->checkpoint_blocks_required = 0;	/* force recalculation */
++}
++
++void yaffs_handle_defered_free(struct yaffs_obj *obj)
++{
++	if (obj->defered_free)
++		yaffs_free_obj(obj);
++}
++
++static int yaffs_generic_obj_del(struct yaffs_obj *in)
++{
++	/* Iinvalidate the file's data in the cache, without flushing. */
++	yaffs_invalidate_whole_cache(in);
++
++	if (in->my_dev->param.is_yaffs2 && in->parent != in->my_dev->del_dir) {
++		/* Move to unlinked directory so we have a deletion record */
++		yaffs_change_obj_name(in, in->my_dev->del_dir, _Y("deleted"), 0,
++				      0);
++	}
++
++	yaffs_remove_obj_from_dir(in);
++	yaffs_chunk_del(in->my_dev, in->hdr_chunk, 1, __LINE__);
++	in->hdr_chunk = 0;
++
++	yaffs_free_obj(in);
++	return YAFFS_OK;
++
++}
++
++static void yaffs_soft_del_file(struct yaffs_obj *obj)
++{
++	if (!obj->deleted ||
++	    obj->variant_type != YAFFS_OBJECT_TYPE_FILE ||
++	    obj->soft_del)
++		return;
++
++	if (obj->n_data_chunks <= 0) {
++		/* Empty file with no duplicate object headers,
++		 * just delete it immediately */
++		yaffs_free_tnode(obj->my_dev, obj->variant.file_variant.top);
++		obj->variant.file_variant.top = NULL;
++		yaffs_trace(YAFFS_TRACE_TRACING,
++			"yaffs: Deleting empty file %d",
++			obj->obj_id);
++		yaffs_generic_obj_del(obj);
++	} else {
++		yaffs_soft_del_worker(obj,
++				      obj->variant.file_variant.top,
++				      obj->variant.
++				      file_variant.top_level, 0);
++		obj->soft_del = 1;
++	}
++}
++
++/* Pruning removes any part of the file structure tree that is beyond the
++ * bounds of the file (ie that does not point to chunks).
++ *
++ * A file should only get pruned when its size is reduced.
++ *
++ * Before pruning, the chunks must be pulled from the tree and the
++ * level 0 tnode entries must be zeroed out.
++ * Could also use this for file deletion, but that's probably better handled
++ * by a special case.
++ *
++ * This function is recursive. For levels > 0 the function is called again on
++ * any sub-tree. For level == 0 we just check if the sub-tree has data.
++ * If there is no data in a subtree then it is pruned.
++ */
++
++static struct yaffs_tnode *yaffs_prune_worker(struct yaffs_dev *dev,
++					      struct yaffs_tnode *tn, u32 level,
++					      int del0)
++{
++	int i;
++	int has_data;
++
++	if (!tn)
++		return tn;
++
++	has_data = 0;
++
++	if (level > 0) {
++		for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) {
++			if (tn->internal[i]) {
++				tn->internal[i] =
++				    yaffs_prune_worker(dev,
++						tn->internal[i],
++						level - 1,
++						(i == 0) ? del0 : 1);
++			}
++
++			if (tn->internal[i])
++				has_data++;
++		}
++	} else {
++		int tnode_size_u32 = dev->tnode_size / sizeof(u32);
++		u32 *map = (u32 *) tn;
++
++		for (i = 0; !has_data && i < tnode_size_u32; i++) {
++			if (map[i])
++				has_data++;
++		}
++	}
++
++	if (has_data == 0 && del0) {
++		/* Free and return NULL */
++		yaffs_free_tnode(dev, tn);
++		tn = NULL;
++	}
++	return tn;
++}
++
++static int yaffs_prune_tree(struct yaffs_dev *dev,
++			    struct yaffs_file_var *file_struct)
++{
++	int i;
++	int has_data;
++	int done = 0;
++	struct yaffs_tnode *tn;
++
++	if (file_struct->top_level < 1)
++		return YAFFS_OK;
++
++	file_struct->top =
++	   yaffs_prune_worker(dev, file_struct->top, file_struct->top_level, 0);
++
++	/* Now we have a tree with all the non-zero branches NULL but
++	 * the height is the same as it was.
++	 * Let's see if we can trim internal tnodes to shorten the tree.
++	 * We can do this if only the 0th element in the tnode is in use
++	 * (ie all the non-zero are NULL)
++	 */
++
++	while (file_struct->top_level && !done) {
++		tn = file_struct->top;
++
++		has_data = 0;
++		for (i = 1; i < YAFFS_NTNODES_INTERNAL; i++) {
++			if (tn->internal[i])
++				has_data++;
++		}
++
++		if (!has_data) {
++			file_struct->top = tn->internal[0];
++			file_struct->top_level--;
++			yaffs_free_tnode(dev, tn);
++		} else {
++			done = 1;
++		}
++	}
++
++	return YAFFS_OK;
++}
++
++/*-------------------- End of File Structure functions.-------------------*/
++
++/* alloc_empty_obj gets us a clean Object.*/
++static struct yaffs_obj *yaffs_alloc_empty_obj(struct yaffs_dev *dev)
++{
++	struct yaffs_obj *obj = yaffs_alloc_raw_obj(dev);
++
++	if (!obj)
++		return obj;
++
++	dev->n_obj++;
++
++	/* Now sweeten it up... */
++
++	memset(obj, 0, sizeof(struct yaffs_obj));
++	obj->being_created = 1;
++
++	obj->my_dev = dev;
++	obj->hdr_chunk = 0;
++	obj->variant_type = YAFFS_OBJECT_TYPE_UNKNOWN;
++	INIT_LIST_HEAD(&(obj->hard_links));
++	INIT_LIST_HEAD(&(obj->hash_link));
++	INIT_LIST_HEAD(&obj->siblings);
++
++	/* Now make the directory sane */
++	if (dev->root_dir) {
++		obj->parent = dev->root_dir;
++		list_add(&(obj->siblings),
++			 &dev->root_dir->variant.dir_variant.children);
++	}
++
++	/* Add it to the lost and found directory.
++	 * NB Can't put root or lost-n-found in lost-n-found so
++	 * check if lost-n-found exists first
++	 */
++	if (dev->lost_n_found)
++		yaffs_add_obj_to_dir(dev->lost_n_found, obj);
++
++	obj->being_created = 0;
++
++	dev->checkpoint_blocks_required = 0;	/* force recalculation */
++
++	return obj;
++}
++
++static int yaffs_find_nice_bucket(struct yaffs_dev *dev)
++{
++	int i;
++	int l = 999;
++	int lowest = 999999;
++
++	/* Search for the shortest list or one that
++	 * isn't too long.
++	 */
++
++	for (i = 0; i < 10 && lowest > 4; i++) {
++		dev->bucket_finder++;
++		dev->bucket_finder %= YAFFS_NOBJECT_BUCKETS;
++		if (dev->obj_bucket[dev->bucket_finder].count < lowest) {
++			lowest = dev->obj_bucket[dev->bucket_finder].count;
++			l = dev->bucket_finder;
++		}
++	}
++
++	return l;
++}
++
++static int yaffs_new_obj_id(struct yaffs_dev *dev)
++{
++	int bucket = yaffs_find_nice_bucket(dev);
++	int found = 0;
++	struct list_head *i;
++	u32 n = (u32) bucket;
++
++	/*
++	 * Now find an object value that has not already been taken
++	 * by scanning the list, incrementing each time by number of buckets.
++	 */
++	while (!found) {
++		found = 1;
++		n += YAFFS_NOBJECT_BUCKETS;
++		list_for_each(i, &dev->obj_bucket[bucket].list) {
++			/* Check if this value is already taken. */
++			if (i && list_entry(i, struct yaffs_obj,
++					    hash_link)->obj_id == n)
++				found = 0;
++		}
++	}
++	return n;
++}
++
++static void yaffs_hash_obj(struct yaffs_obj *in)
++{
++	int bucket = yaffs_hash_fn(in->obj_id);
++	struct yaffs_dev *dev = in->my_dev;
++
++	list_add(&in->hash_link, &dev->obj_bucket[bucket].list);
++	dev->obj_bucket[bucket].count++;
++}
++
++struct yaffs_obj *yaffs_find_by_number(struct yaffs_dev *dev, u32 number)
++{
++	int bucket = yaffs_hash_fn(number);
++	struct list_head *i;
++	struct yaffs_obj *in;
++
++	list_for_each(i, &dev->obj_bucket[bucket].list) {
++		/* Look if it is in the list */
++		in = list_entry(i, struct yaffs_obj, hash_link);
++		if (in->obj_id == number) {
++			/* Don't show if it is defered free */
++			if (in->defered_free)
++				return NULL;
++			return in;
++		}
++	}
++
++	return NULL;
++}
++
++static struct yaffs_obj *yaffs_new_obj(struct yaffs_dev *dev, int number,
++				enum yaffs_obj_type type)
++{
++	struct yaffs_obj *the_obj = NULL;
++	struct yaffs_tnode *tn = NULL;
++
++	if (number < 0)
++		number = yaffs_new_obj_id(dev);
++
++	if (type == YAFFS_OBJECT_TYPE_FILE) {
++		tn = yaffs_get_tnode(dev);
++		if (!tn)
++			return NULL;
++	}
++
++	the_obj = yaffs_alloc_empty_obj(dev);
++	if (!the_obj) {
++		if (tn)
++			yaffs_free_tnode(dev, tn);
++		return NULL;
++	}
++
++	the_obj->fake = 0;
++	the_obj->rename_allowed = 1;
++	the_obj->unlink_allowed = 1;
++	the_obj->obj_id = number;
++	yaffs_hash_obj(the_obj);
++	the_obj->variant_type = type;
++	yaffs_load_current_time(the_obj, 1, 1);
++
++	switch (type) {
++	case YAFFS_OBJECT_TYPE_FILE:
++		the_obj->variant.file_variant.file_size = 0;
++		the_obj->variant.file_variant.scanned_size = 0;
++		the_obj->variant.file_variant.shrink_size =
++						yaffs_max_file_size(dev);
++		the_obj->variant.file_variant.top_level = 0;
++		the_obj->variant.file_variant.top = tn;
++		break;
++	case YAFFS_OBJECT_TYPE_DIRECTORY:
++		INIT_LIST_HEAD(&the_obj->variant.dir_variant.children);
++		INIT_LIST_HEAD(&the_obj->variant.dir_variant.dirty);
++		break;
++	case YAFFS_OBJECT_TYPE_SYMLINK:
++	case YAFFS_OBJECT_TYPE_HARDLINK:
++	case YAFFS_OBJECT_TYPE_SPECIAL:
++		/* No action required */
++		break;
++	case YAFFS_OBJECT_TYPE_UNKNOWN:
++		/* todo this should not happen */
++		break;
++	}
++	return the_obj;
++}
++
++static struct yaffs_obj *yaffs_create_fake_dir(struct yaffs_dev *dev,
++					       int number, u32 mode)
++{
++
++	struct yaffs_obj *obj =
++	    yaffs_new_obj(dev, number, YAFFS_OBJECT_TYPE_DIRECTORY);
++
++	if (!obj)
++		return NULL;
++
++	obj->fake = 1;	/* it is fake so it might not use NAND */
++	obj->rename_allowed = 0;
++	obj->unlink_allowed = 0;
++	obj->deleted = 0;
++	obj->unlinked = 0;
++	obj->yst_mode = mode;
++	obj->my_dev = dev;
++	obj->hdr_chunk = 0;	/* Not a valid chunk. */
++	return obj;
++
++}
++
++
++static void yaffs_init_tnodes_and_objs(struct yaffs_dev *dev)
++{
++	int i;
++
++	dev->n_obj = 0;
++	dev->n_tnodes = 0;
++	yaffs_init_raw_tnodes_and_objs(dev);
++
++	for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
++		INIT_LIST_HEAD(&dev->obj_bucket[i].list);
++		dev->obj_bucket[i].count = 0;
++	}
++}
++
++struct yaffs_obj *yaffs_find_or_create_by_number(struct yaffs_dev *dev,
++						 int number,
++						 enum yaffs_obj_type type)
++{
++	struct yaffs_obj *the_obj = NULL;
++
++	if (number > 0)
++		the_obj = yaffs_find_by_number(dev, number);
++
++	if (!the_obj)
++		the_obj = yaffs_new_obj(dev, number, type);
++
++	return the_obj;
++
++}
++
++YCHAR *yaffs_clone_str(const YCHAR *str)
++{
++	YCHAR *new_str = NULL;
++	int len;
++
++	if (!str)
++		str = _Y("");
++
++	len = strnlen(str, YAFFS_MAX_ALIAS_LENGTH);
++	new_str = kmalloc((len + 1) * sizeof(YCHAR), GFP_NOFS);
++	if (new_str) {
++		strncpy(new_str, str, len);
++		new_str[len] = 0;
++	}
++	return new_str;
++
++}
++/*
++ *yaffs_update_parent() handles fixing a directories mtime and ctime when a new
++ * link (ie. name) is created or deleted in the directory.
++ *
++ * ie.
++ *   create dir/a : update dir's mtime/ctime
++ *   rm dir/a:   update dir's mtime/ctime
++ *   modify dir/a: don't update dir's mtimme/ctime
++ *
++ * This can be handled immediately or defered. Defering helps reduce the number
++ * of updates when many files in a directory are changed within a brief period.
++ *
++ * If the directory updating is defered then yaffs_update_dirty_dirs must be
++ * called periodically.
++ */
++
++static void yaffs_update_parent(struct yaffs_obj *obj)
++{
++	struct yaffs_dev *dev;
++
++	if (!obj)
++		return;
++	dev = obj->my_dev;
++	obj->dirty = 1;
++	yaffs_load_current_time(obj, 0, 1);
++	if (dev->param.defered_dir_update) {
++		struct list_head *link = &obj->variant.dir_variant.dirty;
++
++		if (list_empty(link)) {
++			list_add(link, &dev->dirty_dirs);
++			yaffs_trace(YAFFS_TRACE_BACKGROUND,
++			  "Added object %d to dirty directories",
++			   obj->obj_id);
++		}
++
++	} else {
++		yaffs_update_oh(obj, NULL, 0, 0, 0, NULL);
++	}
++}
++
++void yaffs_update_dirty_dirs(struct yaffs_dev *dev)
++{
++	struct list_head *link;
++	struct yaffs_obj *obj;
++	struct yaffs_dir_var *d_s;
++	union yaffs_obj_var *o_v;
++
++	yaffs_trace(YAFFS_TRACE_BACKGROUND, "Update dirty directories");
++
++	while (!list_empty(&dev->dirty_dirs)) {
++		link = dev->dirty_dirs.next;
++		list_del_init(link);
++
++		d_s = list_entry(link, struct yaffs_dir_var, dirty);
++		o_v = list_entry(d_s, union yaffs_obj_var, dir_variant);
++		obj = list_entry(o_v, struct yaffs_obj, variant);
++
++		yaffs_trace(YAFFS_TRACE_BACKGROUND, "Update directory %d",
++			obj->obj_id);
++
++		if (obj->dirty)
++			yaffs_update_oh(obj, NULL, 0, 0, 0, NULL);
++	}
++}
++
++/*
++ * Mknod (create) a new object.
++ * equiv_obj only has meaning for a hard link;
++ * alias_str only has meaning for a symlink.
++ * rdev only has meaning for devices (a subset of special objects)
++ */
++
++static struct yaffs_obj *yaffs_create_obj(enum yaffs_obj_type type,
++					  struct yaffs_obj *parent,
++					  const YCHAR *name,
++					  u32 mode,
++					  u32 uid,
++					  u32 gid,
++					  struct yaffs_obj *equiv_obj,
++					  const YCHAR *alias_str, u32 rdev)
++{
++	struct yaffs_obj *in;
++	YCHAR *str = NULL;
++	struct yaffs_dev *dev = parent->my_dev;
++
++	/* Check if the entry exists.
++	 * If it does then fail the call since we don't want a dup. */
++	if (yaffs_find_by_name(parent, name))
++		return NULL;
++
++	if (type == YAFFS_OBJECT_TYPE_SYMLINK) {
++		str = yaffs_clone_str(alias_str);
++		if (!str)
++			return NULL;
++	}
++
++	in = yaffs_new_obj(dev, -1, type);
++
++	if (!in) {
++		kfree(str);
++		return NULL;
++	}
++
++	in->hdr_chunk = 0;
++	in->valid = 1;
++	in->variant_type = type;
++
++	in->yst_mode = mode;
++
++	yaffs_attribs_init(in, gid, uid, rdev);
++
++	in->n_data_chunks = 0;
++
++	yaffs_set_obj_name(in, name);
++	in->dirty = 1;
++
++	yaffs_add_obj_to_dir(parent, in);
++
++	in->my_dev = parent->my_dev;
++
++	switch (type) {
++	case YAFFS_OBJECT_TYPE_SYMLINK:
++		in->variant.symlink_variant.alias = str;
++		break;
++	case YAFFS_OBJECT_TYPE_HARDLINK:
++		in->variant.hardlink_variant.equiv_obj = equiv_obj;
++		in->variant.hardlink_variant.equiv_id = equiv_obj->obj_id;
++		list_add(&in->hard_links, &equiv_obj->hard_links);
++		break;
++	case YAFFS_OBJECT_TYPE_FILE:
++	case YAFFS_OBJECT_TYPE_DIRECTORY:
++	case YAFFS_OBJECT_TYPE_SPECIAL:
++	case YAFFS_OBJECT_TYPE_UNKNOWN:
++		/* do nothing */
++		break;
++	}
++
++	if (yaffs_update_oh(in, name, 0, 0, 0, NULL) < 0) {
++		/* Could not create the object header, fail */
++		yaffs_del_obj(in);
++		in = NULL;
++	}
++
++	if (in)
++		yaffs_update_parent(parent);
++
++	return in;
++}
++
++struct yaffs_obj *yaffs_create_file(struct yaffs_obj *parent,
++				    const YCHAR *name, u32 mode, u32 uid,
++				    u32 gid)
++{
++	return yaffs_create_obj(YAFFS_OBJECT_TYPE_FILE, parent, name, mode,
++				uid, gid, NULL, NULL, 0);
++}
++
++struct yaffs_obj *yaffs_create_dir(struct yaffs_obj *parent, const YCHAR *name,
++				   u32 mode, u32 uid, u32 gid)
++{
++	return yaffs_create_obj(YAFFS_OBJECT_TYPE_DIRECTORY, parent, name,
++				mode, uid, gid, NULL, NULL, 0);
++}
++
++struct yaffs_obj *yaffs_create_special(struct yaffs_obj *parent,
++				       const YCHAR *name, u32 mode, u32 uid,
++				       u32 gid, u32 rdev)
++{
++	return yaffs_create_obj(YAFFS_OBJECT_TYPE_SPECIAL, parent, name, mode,
++				uid, gid, NULL, NULL, rdev);
++}
++
++struct yaffs_obj *yaffs_create_symlink(struct yaffs_obj *parent,
++				       const YCHAR *name, u32 mode, u32 uid,
++				       u32 gid, const YCHAR *alias)
++{
++	return yaffs_create_obj(YAFFS_OBJECT_TYPE_SYMLINK, parent, name, mode,
++				uid, gid, NULL, alias, 0);
++}
++
++/* yaffs_link_obj returns the object id of the equivalent object.*/
++struct yaffs_obj *yaffs_link_obj(struct yaffs_obj *parent, const YCHAR * name,
++				 struct yaffs_obj *equiv_obj)
++{
++	/* Get the real object in case we were fed a hard link obj */
++	equiv_obj = yaffs_get_equivalent_obj(equiv_obj);
++
++	if (yaffs_create_obj(YAFFS_OBJECT_TYPE_HARDLINK,
++			parent, name, 0, 0, 0,
++			equiv_obj, NULL, 0))
++		return equiv_obj;
++
++	return NULL;
++
++}
++
++
++
++/*---------------------- Block Management and Page Allocation -------------*/
++
++static void yaffs_deinit_blocks(struct yaffs_dev *dev)
++{
++	if (dev->block_info_alt && dev->block_info)
++		vfree(dev->block_info);
++	else
++		kfree(dev->block_info);
++
++	dev->block_info_alt = 0;
++
++	dev->block_info = NULL;
++
++	if (dev->chunk_bits_alt && dev->chunk_bits)
++		vfree(dev->chunk_bits);
++	else
++		kfree(dev->chunk_bits);
++	dev->chunk_bits_alt = 0;
++	dev->chunk_bits = NULL;
++}
++
++static int yaffs_init_blocks(struct yaffs_dev *dev)
++{
++	int n_blocks = dev->internal_end_block - dev->internal_start_block + 1;
++
++	dev->block_info = NULL;
++	dev->chunk_bits = NULL;
++	dev->alloc_block = -1;	/* force it to get a new one */
++
++	/* If the first allocation strategy fails, thry the alternate one */
++	dev->block_info =
++		kmalloc(n_blocks * sizeof(struct yaffs_block_info), GFP_NOFS);
++	if (!dev->block_info) {
++		dev->block_info =
++		    vmalloc(n_blocks * sizeof(struct yaffs_block_info));
++		dev->block_info_alt = 1;
++	} else {
++		dev->block_info_alt = 0;
++	}
++
++	if (!dev->block_info)
++		goto alloc_error;
++
++	/* Set up dynamic blockinfo stuff. Round up bytes. */
++	dev->chunk_bit_stride = (dev->param.chunks_per_block + 7) / 8;
++	dev->chunk_bits =
++		kmalloc(dev->chunk_bit_stride * n_blocks, GFP_NOFS);
++	if (!dev->chunk_bits) {
++		dev->chunk_bits =
++		    vmalloc(dev->chunk_bit_stride * n_blocks);
++		dev->chunk_bits_alt = 1;
++	} else {
++		dev->chunk_bits_alt = 0;
++	}
++	if (!dev->chunk_bits)
++		goto alloc_error;
++
++
++	memset(dev->block_info, 0, n_blocks * sizeof(struct yaffs_block_info));
++	memset(dev->chunk_bits, 0, dev->chunk_bit_stride * n_blocks);
++	return YAFFS_OK;
++
++alloc_error:
++	yaffs_deinit_blocks(dev);
++	return YAFFS_FAIL;
++}
++
++
++void yaffs_block_became_dirty(struct yaffs_dev *dev, int block_no)
++{
++	struct yaffs_block_info *bi = yaffs_get_block_info(dev, block_no);
++	int erased_ok = 0;
++	int i;
++
++	/* If the block is still healthy erase it and mark as clean.
++	 * If the block has had a data failure, then retire it.
++	 */
++
++	yaffs_trace(YAFFS_TRACE_GC | YAFFS_TRACE_ERASE,
++		"yaffs_block_became_dirty block %d state %d %s",
++		block_no, bi->block_state,
++		(bi->needs_retiring) ? "needs retiring" : "");
++
++	yaffs2_clear_oldest_dirty_seq(dev, bi);
++
++	bi->block_state = YAFFS_BLOCK_STATE_DIRTY;
++
++	/* If this is the block being garbage collected then stop gc'ing */
++	if (block_no == dev->gc_block)
++		dev->gc_block = 0;
++
++	/* If this block is currently the best candidate for gc
++	 * then drop as a candidate */
++	if (block_no == dev->gc_dirtiest) {
++		dev->gc_dirtiest = 0;
++		dev->gc_pages_in_use = 0;
++	}
++
++	if (!bi->needs_retiring) {
++		yaffs2_checkpt_invalidate(dev);
++		erased_ok = yaffs_erase_block(dev, block_no);
++		if (!erased_ok) {
++			dev->n_erase_failures++;
++			yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
++			  "**>> Erasure failed %d", block_no);
++		}
++	}
++
++	/* Verify erasure if needed */
++	if (erased_ok &&
++	    ((yaffs_trace_mask & YAFFS_TRACE_ERASE) ||
++	     !yaffs_skip_verification(dev))) {
++		for (i = 0; i < dev->param.chunks_per_block; i++) {
++			if (!yaffs_check_chunk_erased(dev,
++				block_no * dev->param.chunks_per_block + i)) {
++				yaffs_trace(YAFFS_TRACE_ERROR,
++					">>Block %d erasure supposedly OK, but chunk %d not erased",
++					block_no, i);
++			}
++		}
++	}
++
++	if (!erased_ok) {
++		/* We lost a block of free space */
++		dev->n_free_chunks -= dev->param.chunks_per_block;
++		yaffs_retire_block(dev, block_no);
++		yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
++			"**>> Block %d retired", block_no);
++		return;
++	}
++
++	/* Clean it up... */
++	bi->block_state = YAFFS_BLOCK_STATE_EMPTY;
++	bi->seq_number = 0;
++	dev->n_erased_blocks++;
++	bi->pages_in_use = 0;
++	bi->soft_del_pages = 0;
++	bi->has_shrink_hdr = 0;
++	bi->skip_erased_check = 1;	/* Clean, so no need to check */
++	bi->gc_prioritise = 0;
++	bi->has_summary = 0;
++
++	yaffs_clear_chunk_bits(dev, block_no);
++
++	yaffs_trace(YAFFS_TRACE_ERASE, "Erased block %d", block_no);
++}
++
++static inline int yaffs_gc_process_chunk(struct yaffs_dev *dev,
++					struct yaffs_block_info *bi,
++					int old_chunk, u8 *buffer)
++{
++	int new_chunk;
++	int mark_flash = 1;
++	struct yaffs_ext_tags tags;
++	struct yaffs_obj *object;
++	int matching_chunk;
++	int ret_val = YAFFS_OK;
++
++	memset(&tags, 0, sizeof(tags));
++	yaffs_rd_chunk_tags_nand(dev, old_chunk,
++				 buffer, &tags);
++	object = yaffs_find_by_number(dev, tags.obj_id);
++
++	yaffs_trace(YAFFS_TRACE_GC_DETAIL,
++		"Collecting chunk in block %d, %d %d %d ",
++		dev->gc_chunk, tags.obj_id,
++		tags.chunk_id, tags.n_bytes);
++
++	if (object && !yaffs_skip_verification(dev)) {
++		if (tags.chunk_id == 0)
++			matching_chunk =
++			    object->hdr_chunk;
++		else if (object->soft_del)
++			/* Defeat the test */
++			matching_chunk = old_chunk;
++		else
++			matching_chunk =
++			    yaffs_find_chunk_in_file
++			    (object, tags.chunk_id,
++			     NULL);
++
++		if (old_chunk != matching_chunk)
++			yaffs_trace(YAFFS_TRACE_ERROR,
++				"gc: page in gc mismatch: %d %d %d %d",
++				old_chunk,
++				matching_chunk,
++				tags.obj_id,
++				tags.chunk_id);
++	}
++
++	if (!object) {
++		yaffs_trace(YAFFS_TRACE_ERROR,
++			"page %d in gc has no object: %d %d %d ",
++			old_chunk,
++			tags.obj_id, tags.chunk_id,
++			tags.n_bytes);
++	}
++
++	if (object &&
++	    object->deleted &&
++	    object->soft_del && tags.chunk_id != 0) {
++		/* Data chunk in a soft deleted file,
++		 * throw it away.
++		 * It's a soft deleted data chunk,
++		 * No need to copy this, just forget
++		 * about it and fix up the object.
++		 */
++
++		/* Free chunks already includes
++		 * softdeleted chunks, how ever this
++		 * chunk is going to soon be really
++		 * deleted which will increment free
++		 * chunks. We have to decrement free
++		 * chunks so this works out properly.
++		 */
++		dev->n_free_chunks--;
++		bi->soft_del_pages--;
++
++		object->n_data_chunks--;
++		if (object->n_data_chunks <= 0) {
++			/* remeber to clean up obj */
++			dev->gc_cleanup_list[dev->n_clean_ups] = tags.obj_id;
++			dev->n_clean_ups++;
++		}
++		mark_flash = 0;
++	} else if (object) {
++		/* It's either a data chunk in a live
++		 * file or an ObjectHeader, so we're
++		 * interested in it.
++		 * NB Need to keep the ObjectHeaders of
++		 * deleted files until the whole file
++		 * has been deleted off
++		 */
++		tags.serial_number++;
++		dev->n_gc_copies++;
++
++		if (tags.chunk_id == 0) {
++			/* It is an object Id,
++			 * We need to nuke the
++			 * shrinkheader flags since its
++			 * work is done.
++			 * Also need to clean up
++			 * shadowing.
++			 */
++			struct yaffs_obj_hdr *oh;
++			oh = (struct yaffs_obj_hdr *) buffer;
++
++			oh->is_shrink = 0;
++			tags.extra_is_shrink = 0;
++			oh->shadows_obj = 0;
++			oh->inband_shadowed_obj_id = 0;
++			tags.extra_shadows = 0;
++
++			/* Update file size */
++			if (object->variant_type == YAFFS_OBJECT_TYPE_FILE) {
++				yaffs_oh_size_load(oh,
++				    object->variant.file_variant.file_size);
++				tags.extra_file_size =
++				    object->variant.file_variant.file_size;
++			}
++
++			yaffs_verify_oh(object, oh, &tags, 1);
++			new_chunk =
++			    yaffs_write_new_chunk(dev, (u8 *) oh, &tags, 1);
++		} else {
++			new_chunk =
++			    yaffs_write_new_chunk(dev, buffer, &tags, 1);
++		}
++
++		if (new_chunk < 0) {
++			ret_val = YAFFS_FAIL;
++		} else {
++
++			/* Now fix up the Tnodes etc. */
++
++			if (tags.chunk_id == 0) {
++				/* It's a header */
++				object->hdr_chunk = new_chunk;
++				object->serial = tags.serial_number;
++			} else {
++				/* It's a data chunk */
++				yaffs_put_chunk_in_file(object, tags.chunk_id,
++							new_chunk, 0);
++			}
++		}
++	}
++	if (ret_val == YAFFS_OK)
++		yaffs_chunk_del(dev, old_chunk, mark_flash, __LINE__);
++	return ret_val;
++}
++
++static int yaffs_gc_block(struct yaffs_dev *dev, int block, int whole_block)
++{
++	int old_chunk;
++	int ret_val = YAFFS_OK;
++	int i;
++	int is_checkpt_block;
++	int max_copies;
++	int chunks_before = yaffs_get_erased_chunks(dev);
++	int chunks_after;
++	struct yaffs_block_info *bi = yaffs_get_block_info(dev, block);
++
++	is_checkpt_block = (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT);
++
++	yaffs_trace(YAFFS_TRACE_TRACING,
++		"Collecting block %d, in use %d, shrink %d, whole_block %d",
++		block, bi->pages_in_use, bi->has_shrink_hdr,
++		whole_block);
++
++	/*yaffs_verify_free_chunks(dev); */
++
++	if (bi->block_state == YAFFS_BLOCK_STATE_FULL)
++		bi->block_state = YAFFS_BLOCK_STATE_COLLECTING;
++
++	bi->has_shrink_hdr = 0;	/* clear the flag so that the block can erase */
++
++	dev->gc_disable = 1;
++
++	yaffs_summary_gc(dev, block);
++
++	if (is_checkpt_block || !yaffs_still_some_chunks(dev, block)) {
++		yaffs_trace(YAFFS_TRACE_TRACING,
++			"Collecting block %d that has no chunks in use",
++			block);
++		yaffs_block_became_dirty(dev, block);
++	} else {
++
++		u8 *buffer = yaffs_get_temp_buffer(dev);
++
++		yaffs_verify_blk(dev, bi, block);
++
++		max_copies = (whole_block) ? dev->param.chunks_per_block : 5;
++		old_chunk = block * dev->param.chunks_per_block + dev->gc_chunk;
++
++		for (/* init already done */ ;
++		     ret_val == YAFFS_OK &&
++		     dev->gc_chunk < dev->param.chunks_per_block &&
++		     (bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) &&
++		     max_copies > 0;
++		     dev->gc_chunk++, old_chunk++) {
++			if (yaffs_check_chunk_bit(dev, block, dev->gc_chunk)) {
++				/* Page is in use and might need to be copied */
++				max_copies--;
++				ret_val = yaffs_gc_process_chunk(dev, bi,
++							old_chunk, buffer);
++			}
++		}
++		yaffs_release_temp_buffer(dev, buffer);
++	}
++
++	yaffs_verify_collected_blk(dev, bi, block);
++
++	if (bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) {
++		/*
++		 * The gc did not complete. Set block state back to FULL
++		 * because checkpointing does not restore gc.
++		 */
++		bi->block_state = YAFFS_BLOCK_STATE_FULL;
++	} else {
++		/* The gc completed. */
++		/* Do any required cleanups */
++		for (i = 0; i < dev->n_clean_ups; i++) {
++			/* Time to delete the file too */
++			struct yaffs_obj *object =
++			    yaffs_find_by_number(dev, dev->gc_cleanup_list[i]);
++			if (object) {
++				yaffs_free_tnode(dev,
++					  object->variant.file_variant.top);
++				object->variant.file_variant.top = NULL;
++				yaffs_trace(YAFFS_TRACE_GC,
++					"yaffs: About to finally delete object %d",
++					object->obj_id);
++				yaffs_generic_obj_del(object);
++				object->my_dev->n_deleted_files--;
++			}
++
++		}
++		chunks_after = yaffs_get_erased_chunks(dev);
++		if (chunks_before >= chunks_after)
++			yaffs_trace(YAFFS_TRACE_GC,
++				"gc did not increase free chunks before %d after %d",
++				chunks_before, chunks_after);
++		dev->gc_block = 0;
++		dev->gc_chunk = 0;
++		dev->n_clean_ups = 0;
++	}
++
++	dev->gc_disable = 0;
++
++	return ret_val;
++}
++
++/*
++ * find_gc_block() selects the dirtiest block (or close enough)
++ * for garbage collection.
++ */
++
++static unsigned yaffs_find_gc_block(struct yaffs_dev *dev,
++				    int aggressive, int background)
++{
++	int i;
++	int iterations;
++	unsigned selected = 0;
++	int prioritised = 0;
++	int prioritised_exist = 0;
++	struct yaffs_block_info *bi;
++	int threshold;
++
++	/* First let's see if we need to grab a prioritised block */
++	if (dev->has_pending_prioritised_gc && !aggressive) {
++		dev->gc_dirtiest = 0;
++		bi = dev->block_info;
++		for (i = dev->internal_start_block;
++		     i <= dev->internal_end_block && !selected; i++) {
++
++			if (bi->gc_prioritise) {
++				prioritised_exist = 1;
++				if (bi->block_state == YAFFS_BLOCK_STATE_FULL &&
++				    yaffs_block_ok_for_gc(dev, bi)) {
++					selected = i;
++					prioritised = 1;
++				}
++			}
++			bi++;
++		}
++
++		/*
++		 * If there is a prioritised block and none was selected then
++		 * this happened because there is at least one old dirty block
++		 * gumming up the works. Let's gc the oldest dirty block.
++		 */
++
++		if (prioritised_exist &&
++		    !selected && dev->oldest_dirty_block > 0)
++			selected = dev->oldest_dirty_block;
++
++		if (!prioritised_exist)	/* None found, so we can clear this */
++			dev->has_pending_prioritised_gc = 0;
++	}
++
++	/* If we're doing aggressive GC then we are happy to take a less-dirty
++	 * block, and search harder.
++	 * else (leasurely gc), then we only bother to do this if the
++	 * block has only a few pages in use.
++	 */
++
++	if (!selected) {
++		int pages_used;
++		int n_blocks =
++		    dev->internal_end_block - dev->internal_start_block + 1;
++		if (aggressive) {
++			threshold = dev->param.chunks_per_block;
++			iterations = n_blocks;
++		} else {
++			int max_threshold;
++
++			if (background)
++				max_threshold = dev->param.chunks_per_block / 2;
++			else
++				max_threshold = dev->param.chunks_per_block / 8;
++
++			if (max_threshold < YAFFS_GC_PASSIVE_THRESHOLD)
++				max_threshold = YAFFS_GC_PASSIVE_THRESHOLD;
++
++			threshold = background ? (dev->gc_not_done + 2) * 2 : 0;
++			if (threshold < YAFFS_GC_PASSIVE_THRESHOLD)
++				threshold = YAFFS_GC_PASSIVE_THRESHOLD;
++			if (threshold > max_threshold)
++				threshold = max_threshold;
++
++			iterations = n_blocks / 16 + 1;
++			if (iterations > 100)
++				iterations = 100;
++		}
++
++		for (i = 0;
++		     i < iterations &&
++		     (dev->gc_dirtiest < 1 ||
++		      dev->gc_pages_in_use > YAFFS_GC_GOOD_ENOUGH);
++		     i++) {
++			dev->gc_block_finder++;
++			if (dev->gc_block_finder < dev->internal_start_block ||
++			    dev->gc_block_finder > dev->internal_end_block)
++				dev->gc_block_finder =
++				    dev->internal_start_block;
++
++			bi = yaffs_get_block_info(dev, dev->gc_block_finder);
++
++			pages_used = bi->pages_in_use - bi->soft_del_pages;
++
++			if (bi->block_state == YAFFS_BLOCK_STATE_FULL &&
++			    pages_used < dev->param.chunks_per_block &&
++			    (dev->gc_dirtiest < 1 ||
++			     pages_used < dev->gc_pages_in_use) &&
++			    yaffs_block_ok_for_gc(dev, bi)) {
++				dev->gc_dirtiest = dev->gc_block_finder;
++				dev->gc_pages_in_use = pages_used;
++			}
++		}
++
++		if (dev->gc_dirtiest > 0 && dev->gc_pages_in_use <= threshold)
++			selected = dev->gc_dirtiest;
++	}
++
++	/*
++	 * If nothing has been selected for a while, try the oldest dirty
++	 * because that's gumming up the works.
++	 */
++
++	if (!selected && dev->param.is_yaffs2 &&
++	    dev->gc_not_done >= (background ? 10 : 20)) {
++		yaffs2_find_oldest_dirty_seq(dev);
++		if (dev->oldest_dirty_block > 0) {
++			selected = dev->oldest_dirty_block;
++			dev->gc_dirtiest = selected;
++			dev->oldest_dirty_gc_count++;
++			bi = yaffs_get_block_info(dev, selected);
++			dev->gc_pages_in_use =
++			    bi->pages_in_use - bi->soft_del_pages;
++		} else {
++			dev->gc_not_done = 0;
++		}
++	}
++
++	if (selected) {
++		yaffs_trace(YAFFS_TRACE_GC,
++			"GC Selected block %d with %d free, prioritised:%d",
++			selected,
++			dev->param.chunks_per_block - dev->gc_pages_in_use,
++			prioritised);
++
++		dev->n_gc_blocks++;
++		if (background)
++			dev->bg_gcs++;
++
++		dev->gc_dirtiest = 0;
++		dev->gc_pages_in_use = 0;
++		dev->gc_not_done = 0;
++		if (dev->refresh_skip > 0)
++			dev->refresh_skip--;
++	} else {
++		dev->gc_not_done++;
++		yaffs_trace(YAFFS_TRACE_GC,
++			"GC none: finder %d skip %d threshold %d dirtiest %d using %d oldest %d%s",
++			dev->gc_block_finder, dev->gc_not_done, threshold,
++			dev->gc_dirtiest, dev->gc_pages_in_use,
++			dev->oldest_dirty_block, background ? " bg" : "");
++	}
++
++	return selected;
++}
++
++/* New garbage collector
++ * If we're very low on erased blocks then we do aggressive garbage collection
++ * otherwise we do "leasurely" garbage collection.
++ * Aggressive gc looks further (whole array) and will accept less dirty blocks.
++ * Passive gc only inspects smaller areas and only accepts more dirty blocks.
++ *
++ * The idea is to help clear out space in a more spread-out manner.
++ * Dunno if it really does anything useful.
++ */
++static int yaffs_check_gc(struct yaffs_dev *dev, int background)
++{
++	int aggressive = 0;
++	int gc_ok = YAFFS_OK;
++	int max_tries = 0;
++	int min_erased;
++	int erased_chunks;
++	int checkpt_block_adjust;
++
++	if (dev->param.gc_control_fn &&
++		(dev->param.gc_control_fn(dev) & 1) == 0)
++		return YAFFS_OK;
++
++	if (dev->gc_disable)
++		/* Bail out so we don't get recursive gc */
++		return YAFFS_OK;
++
++	/* This loop should pass the first time.
++	 * Only loops here if the collection does not increase space.
++	 */
++
++	do {
++		max_tries++;
++
++		checkpt_block_adjust = yaffs_calc_checkpt_blocks_required(dev);
++
++		min_erased =
++		    dev->param.n_reserved_blocks + checkpt_block_adjust + 1;
++		erased_chunks =
++		    dev->n_erased_blocks * dev->param.chunks_per_block;
++
++		/* If we need a block soon then do aggressive gc. */
++		if (dev->n_erased_blocks < min_erased)
++			aggressive = 1;
++		else {
++			if (!background
++			    && erased_chunks > (dev->n_free_chunks / 4))
++				break;
++
++			if (dev->gc_skip > 20)
++				dev->gc_skip = 20;
++			if (erased_chunks < dev->n_free_chunks / 2 ||
++			    dev->gc_skip < 1 || background)
++				aggressive = 0;
++			else {
++				dev->gc_skip--;
++				break;
++			}
++		}
++
++		dev->gc_skip = 5;
++
++		/* If we don't already have a block being gc'd then see if we
++		 * should start another */
++
++		if (dev->gc_block < 1 && !aggressive) {
++			dev->gc_block = yaffs2_find_refresh_block(dev);
++			dev->gc_chunk = 0;
++			dev->n_clean_ups = 0;
++		}
++		if (dev->gc_block < 1) {
++			dev->gc_block =
++			    yaffs_find_gc_block(dev, aggressive, background);
++			dev->gc_chunk = 0;
++			dev->n_clean_ups = 0;
++		}
++
++		if (dev->gc_block > 0) {
++			dev->all_gcs++;
++			if (!aggressive)
++				dev->passive_gc_count++;
++
++			yaffs_trace(YAFFS_TRACE_GC,
++				"yaffs: GC n_erased_blocks %d aggressive %d",
++				dev->n_erased_blocks, aggressive);
++
++			gc_ok = yaffs_gc_block(dev, dev->gc_block, aggressive);
++		}
++
++		if (dev->n_erased_blocks < (dev->param.n_reserved_blocks) &&
++		    dev->gc_block > 0) {
++			yaffs_trace(YAFFS_TRACE_GC,
++				"yaffs: GC !!!no reclaim!!! n_erased_blocks %d after try %d block %d",
++				dev->n_erased_blocks, max_tries,
++				dev->gc_block);
++		}
++	} while ((dev->n_erased_blocks < dev->param.n_reserved_blocks) &&
++		 (dev->gc_block > 0) && (max_tries < 2));
++
++	return aggressive ? gc_ok : YAFFS_OK;
++}
++
++/*
++ * yaffs_bg_gc()
++ * Garbage collects. Intended to be called from a background thread.
++ * Returns non-zero if at least half the free chunks are erased.
++ */
++int yaffs_bg_gc(struct yaffs_dev *dev, unsigned urgency)
++{
++	int erased_chunks = dev->n_erased_blocks * dev->param.chunks_per_block;
++
++	yaffs_trace(YAFFS_TRACE_BACKGROUND, "Background gc %u", urgency);
++
++	yaffs_check_gc(dev, 1);
++	return erased_chunks > dev->n_free_chunks / 2;
++}
++
++/*-------------------- Data file manipulation -----------------*/
++
++static int yaffs_rd_data_obj(struct yaffs_obj *in, int inode_chunk, u8 * buffer)
++{
++	int nand_chunk = yaffs_find_chunk_in_file(in, inode_chunk, NULL);
++
++	if (nand_chunk >= 0)
++		return yaffs_rd_chunk_tags_nand(in->my_dev, nand_chunk,
++						buffer, NULL);
++	else {
++		yaffs_trace(YAFFS_TRACE_NANDACCESS,
++			"Chunk %d not found zero instead",
++			nand_chunk);
++		/* get sane (zero) data if you read a hole */
++		memset(buffer, 0, in->my_dev->data_bytes_per_chunk);
++		return 0;
++	}
++
++}
++
++void yaffs_chunk_del(struct yaffs_dev *dev, int chunk_id, int mark_flash,
++		     int lyn)
++{
++	int block;
++	int page;
++	struct yaffs_ext_tags tags;
++	struct yaffs_block_info *bi;
++
++	if (chunk_id <= 0)
++		return;
++
++	dev->n_deletions++;
++	block = chunk_id / dev->param.chunks_per_block;
++	page = chunk_id % dev->param.chunks_per_block;
++
++	if (!yaffs_check_chunk_bit(dev, block, page))
++		yaffs_trace(YAFFS_TRACE_VERIFY,
++			"Deleting invalid chunk %d", chunk_id);
++
++	bi = yaffs_get_block_info(dev, block);
++
++	yaffs2_update_oldest_dirty_seq(dev, block, bi);
++
++	yaffs_trace(YAFFS_TRACE_DELETION,
++		"line %d delete of chunk %d",
++		lyn, chunk_id);
++
++	if (!dev->param.is_yaffs2 && mark_flash &&
++	    bi->block_state != YAFFS_BLOCK_STATE_COLLECTING) {
++
++		memset(&tags, 0, sizeof(tags));
++		tags.is_deleted = 1;
++		yaffs_wr_chunk_tags_nand(dev, chunk_id, NULL, &tags);
++		yaffs_handle_chunk_update(dev, chunk_id, &tags);
++	} else {
++		dev->n_unmarked_deletions++;
++	}
++
++	/* Pull out of the management area.
++	 * If the whole block became dirty, this will kick off an erasure.
++	 */
++	if (bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING ||
++	    bi->block_state == YAFFS_BLOCK_STATE_FULL ||
++	    bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN ||
++	    bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) {
++		dev->n_free_chunks++;
++		yaffs_clear_chunk_bit(dev, block, page);
++		bi->pages_in_use--;
++
++		if (bi->pages_in_use == 0 &&
++		    !bi->has_shrink_hdr &&
++		    bi->block_state != YAFFS_BLOCK_STATE_ALLOCATING &&
++		    bi->block_state != YAFFS_BLOCK_STATE_NEEDS_SCAN) {
++			yaffs_block_became_dirty(dev, block);
++		}
++	}
++}
++
++static int yaffs_wr_data_obj(struct yaffs_obj *in, int inode_chunk,
++			     const u8 *buffer, int n_bytes, int use_reserve)
++{
++	/* Find old chunk Need to do this to get serial number
++	 * Write new one and patch into tree.
++	 * Invalidate old tags.
++	 */
++
++	int prev_chunk_id;
++	struct yaffs_ext_tags prev_tags;
++	int new_chunk_id;
++	struct yaffs_ext_tags new_tags;
++	struct yaffs_dev *dev = in->my_dev;
++
++	yaffs_check_gc(dev, 0);
++
++	/* Get the previous chunk at this location in the file if it exists.
++	 * If it does not exist then put a zero into the tree. This creates
++	 * the tnode now, rather than later when it is harder to clean up.
++	 */
++	prev_chunk_id = yaffs_find_chunk_in_file(in, inode_chunk, &prev_tags);
++	if (prev_chunk_id < 1 &&
++	    !yaffs_put_chunk_in_file(in, inode_chunk, 0, 0))
++		return 0;
++
++	/* Set up new tags */
++	memset(&new_tags, 0, sizeof(new_tags));
++
++	new_tags.chunk_id = inode_chunk;
++	new_tags.obj_id = in->obj_id;
++	new_tags.serial_number =
++	    (prev_chunk_id > 0) ? prev_tags.serial_number + 1 : 1;
++	new_tags.n_bytes = n_bytes;
++
++	if (n_bytes < 1 || n_bytes > dev->param.total_bytes_per_chunk) {
++		yaffs_trace(YAFFS_TRACE_ERROR,
++		  "Writing %d bytes to chunk!!!!!!!!!",
++		   n_bytes);
++		BUG();
++	}
++
++	new_chunk_id =
++	    yaffs_write_new_chunk(dev, buffer, &new_tags, use_reserve);
++
++	if (new_chunk_id > 0) {
++		yaffs_put_chunk_in_file(in, inode_chunk, new_chunk_id, 0);
++
++		if (prev_chunk_id > 0)
++			yaffs_chunk_del(dev, prev_chunk_id, 1, __LINE__);
++
++		yaffs_verify_file_sane(in);
++	}
++	return new_chunk_id;
++
++}
++
++
++
++static int yaffs_do_xattrib_mod(struct yaffs_obj *obj, int set,
++				const YCHAR *name, const void *value, int size,
++				int flags)
++{
++	struct yaffs_xattr_mod xmod;
++	int result;
++
++	xmod.set = set;
++	xmod.name = name;
++	xmod.data = value;
++	xmod.size = size;
++	xmod.flags = flags;
++	xmod.result = -ENOSPC;
++
++	result = yaffs_update_oh(obj, NULL, 0, 0, 0, &xmod);
++
++	if (result > 0)
++		return xmod.result;
++	else
++		return -ENOSPC;
++}
++
++static int yaffs_apply_xattrib_mod(struct yaffs_obj *obj, char *buffer,
++				   struct yaffs_xattr_mod *xmod)
++{
++	int retval = 0;
++	int x_offs = sizeof(struct yaffs_obj_hdr);
++	struct yaffs_dev *dev = obj->my_dev;
++	int x_size = dev->data_bytes_per_chunk - sizeof(struct yaffs_obj_hdr);
++	char *x_buffer = buffer + x_offs;
++
++	if (xmod->set)
++		retval =
++		    nval_set(x_buffer, x_size, xmod->name, xmod->data,
++			     xmod->size, xmod->flags);
++	else
++		retval = nval_del(x_buffer, x_size, xmod->name);
++
++	obj->has_xattr = nval_hasvalues(x_buffer, x_size);
++	obj->xattr_known = 1;
++	xmod->result = retval;
++
++	return retval;
++}
++
++static int yaffs_do_xattrib_fetch(struct yaffs_obj *obj, const YCHAR *name,
++				  void *value, int size)
++{
++	char *buffer = NULL;
++	int result;
++	struct yaffs_ext_tags tags;
++	struct yaffs_dev *dev = obj->my_dev;
++	int x_offs = sizeof(struct yaffs_obj_hdr);
++	int x_size = dev->data_bytes_per_chunk - sizeof(struct yaffs_obj_hdr);
++	char *x_buffer;
++	int retval = 0;
++
++	if (obj->hdr_chunk < 1)
++		return -ENODATA;
++
++	/* If we know that the object has no xattribs then don't do all the
++	 * reading and parsing.
++	 */
++	if (obj->xattr_known && !obj->has_xattr) {
++		if (name)
++			return -ENODATA;
++		else
++			return 0;
++	}
++
++	buffer = (char *)yaffs_get_temp_buffer(dev);
++	if (!buffer)
++		return -ENOMEM;
++
++	result =
++	    yaffs_rd_chunk_tags_nand(dev, obj->hdr_chunk, (u8 *) buffer, &tags);
++
++	if (result != YAFFS_OK)
++		retval = -ENOENT;
++	else {
++		x_buffer = buffer + x_offs;
++
++		if (!obj->xattr_known) {
++			obj->has_xattr = nval_hasvalues(x_buffer, x_size);
++			obj->xattr_known = 1;
++		}
++
++		if (name)
++			retval = nval_get(x_buffer, x_size, name, value, size);
++		else
++			retval = nval_list(x_buffer, x_size, value, size);
++	}
++	yaffs_release_temp_buffer(dev, (u8 *) buffer);
++	return retval;
++}
++
++int yaffs_set_xattrib(struct yaffs_obj *obj, const YCHAR * name,
++		      const void *value, int size, int flags)
++{
++	return yaffs_do_xattrib_mod(obj, 1, name, value, size, flags);
++}
++
++int yaffs_remove_xattrib(struct yaffs_obj *obj, const YCHAR * name)
++{
++	return yaffs_do_xattrib_mod(obj, 0, name, NULL, 0, 0);
++}
++
++int yaffs_get_xattrib(struct yaffs_obj *obj, const YCHAR * name, void *value,
++		      int size)
++{
++	return yaffs_do_xattrib_fetch(obj, name, value, size);
++}
++
++int yaffs_list_xattrib(struct yaffs_obj *obj, char *buffer, int size)
++{
++	return yaffs_do_xattrib_fetch(obj, NULL, buffer, size);
++}
++
++static void yaffs_check_obj_details_loaded(struct yaffs_obj *in)
++{
++	u8 *buf;
++	struct yaffs_obj_hdr *oh;
++	struct yaffs_dev *dev;
++	struct yaffs_ext_tags tags;
++	int result;
++	int alloc_failed = 0;
++
++	if (!in || !in->lazy_loaded || in->hdr_chunk < 1)
++		return;
++
++	dev = in->my_dev;
++	in->lazy_loaded = 0;
++	buf = yaffs_get_temp_buffer(dev);
++
++	result = yaffs_rd_chunk_tags_nand(dev, in->hdr_chunk, buf, &tags);
++	oh = (struct yaffs_obj_hdr *)buf;
++
++	in->yst_mode = oh->yst_mode;
++	yaffs_load_attribs(in, oh);
++	yaffs_set_obj_name_from_oh(in, oh);
++
++	if (in->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) {
++		in->variant.symlink_variant.alias =
++		    yaffs_clone_str(oh->alias);
++		if (!in->variant.symlink_variant.alias)
++			alloc_failed = 1;	/* Not returned */
++	}
++	yaffs_release_temp_buffer(dev, buf);
++}
++
++/* UpdateObjectHeader updates the header on NAND for an object.
++ * If name is not NULL, then that new name is used.
++ */
++int yaffs_update_oh(struct yaffs_obj *in, const YCHAR *name, int force,
++		    int is_shrink, int shadows, struct yaffs_xattr_mod *xmod)
++{
++
++	struct yaffs_block_info *bi;
++	struct yaffs_dev *dev = in->my_dev;
++	int prev_chunk_id;
++	int ret_val = 0;
++	int result = 0;
++	int new_chunk_id;
++	struct yaffs_ext_tags new_tags;
++	struct yaffs_ext_tags old_tags;
++	const YCHAR *alias = NULL;
++	u8 *buffer = NULL;
++	YCHAR old_name[YAFFS_MAX_NAME_LENGTH + 1];
++	struct yaffs_obj_hdr *oh = NULL;
++	loff_t file_size = 0;
++
++	strcpy(old_name, _Y("silly old name"));
++
++	if (in->fake && in != dev->root_dir && !force && !xmod)
++		return ret_val;
++
++	yaffs_check_gc(dev, 0);
++	yaffs_check_obj_details_loaded(in);
++
++	buffer = yaffs_get_temp_buffer(in->my_dev);
++	oh = (struct yaffs_obj_hdr *)buffer;
++
++	prev_chunk_id = in->hdr_chunk;
++
++	if (prev_chunk_id > 0) {
++		result = yaffs_rd_chunk_tags_nand(dev, prev_chunk_id,
++						  buffer, &old_tags);
++
++		yaffs_verify_oh(in, oh, &old_tags, 0);
++		memcpy(old_name, oh->name, sizeof(oh->name));
++		memset(buffer, 0xff, sizeof(struct yaffs_obj_hdr));
++	} else {
++		memset(buffer, 0xff, dev->data_bytes_per_chunk);
++	}
++
++	oh->type = in->variant_type;
++	oh->yst_mode = in->yst_mode;
++	oh->shadows_obj = oh->inband_shadowed_obj_id = shadows;
++
++	yaffs_load_attribs_oh(oh, in);
++
++	if (in->parent)
++		oh->parent_obj_id = in->parent->obj_id;
++	else
++		oh->parent_obj_id = 0;
++
++	if (name && *name) {
++		memset(oh->name, 0, sizeof(oh->name));
++		yaffs_load_oh_from_name(dev, oh->name, name);
++	} else if (prev_chunk_id > 0) {
++		memcpy(oh->name, old_name, sizeof(oh->name));
++	} else {
++		memset(oh->name, 0, sizeof(oh->name));
++	}
++
++	oh->is_shrink = is_shrink;
++
++	switch (in->variant_type) {
++	case YAFFS_OBJECT_TYPE_UNKNOWN:
++		/* Should not happen */
++		break;
++	case YAFFS_OBJECT_TYPE_FILE:
++		if (oh->parent_obj_id != YAFFS_OBJECTID_DELETED &&
++		    oh->parent_obj_id != YAFFS_OBJECTID_UNLINKED)
++			file_size = in->variant.file_variant.file_size;
++		yaffs_oh_size_load(oh, file_size);
++		break;
++	case YAFFS_OBJECT_TYPE_HARDLINK:
++		oh->equiv_id = in->variant.hardlink_variant.equiv_id;
++		break;
++	case YAFFS_OBJECT_TYPE_SPECIAL:
++		/* Do nothing */
++		break;
++	case YAFFS_OBJECT_TYPE_DIRECTORY:
++		/* Do nothing */
++		break;
++	case YAFFS_OBJECT_TYPE_SYMLINK:
++		alias = in->variant.symlink_variant.alias;
++		if (!alias)
++			alias = _Y("no alias");
++		strncpy(oh->alias, alias, YAFFS_MAX_ALIAS_LENGTH);
++		oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0;
++		break;
++	}
++
++	/* process any xattrib modifications */
++	if (xmod)
++		yaffs_apply_xattrib_mod(in, (char *)buffer, xmod);
++
++	/* Tags */
++	memset(&new_tags, 0, sizeof(new_tags));
++	in->serial++;
++	new_tags.chunk_id = 0;
++	new_tags.obj_id = in->obj_id;
++	new_tags.serial_number = in->serial;
++
++	/* Add extra info for file header */
++	new_tags.extra_available = 1;
++	new_tags.extra_parent_id = oh->parent_obj_id;
++	new_tags.extra_file_size = file_size;
++	new_tags.extra_is_shrink = oh->is_shrink;
++	new_tags.extra_equiv_id = oh->equiv_id;
++	new_tags.extra_shadows = (oh->shadows_obj > 0) ? 1 : 0;
++	new_tags.extra_obj_type = in->variant_type;
++	yaffs_verify_oh(in, oh, &new_tags, 1);
++
++	/* Create new chunk in NAND */
++	new_chunk_id =
++	    yaffs_write_new_chunk(dev, buffer, &new_tags,
++				  (prev_chunk_id > 0) ? 1 : 0);
++
++	if (buffer)
++		yaffs_release_temp_buffer(dev, buffer);
++
++	if (new_chunk_id < 0)
++		return new_chunk_id;
++
++	in->hdr_chunk = new_chunk_id;
++
++	if (prev_chunk_id > 0)
++		yaffs_chunk_del(dev, prev_chunk_id, 1, __LINE__);
++
++	if (!yaffs_obj_cache_dirty(in))
++		in->dirty = 0;
++
++	/* If this was a shrink, then mark the block
++	 * that the chunk lives on */
++	if (is_shrink) {
++		bi = yaffs_get_block_info(in->my_dev,
++					  new_chunk_id /
++					  in->my_dev->param.chunks_per_block);
++		bi->has_shrink_hdr = 1;
++	}
++
++
++	return new_chunk_id;
++}
++
++/*--------------------- File read/write ------------------------
++ * Read and write have very similar structures.
++ * In general the read/write has three parts to it
++ * An incomplete chunk to start with (if the read/write is not chunk-aligned)
++ * Some complete chunks
++ * An incomplete chunk to end off with
++ *
++ * Curve-balls: the first chunk might also be the last chunk.
++ */
++
++int yaffs_file_rd(struct yaffs_obj *in, u8 * buffer, loff_t offset, int n_bytes)
++{
++	int chunk;
++	u32 start;
++	int n_copy;
++	int n = n_bytes;
++	int n_done = 0;
++	struct yaffs_cache *cache;
++	struct yaffs_dev *dev;
++
++	dev = in->my_dev;
++
++	while (n > 0) {
++		yaffs_addr_to_chunk(dev, offset, &chunk, &start);
++		chunk++;
++
++		/* OK now check for the curveball where the start and end are in
++		 * the same chunk.
++		 */
++		if ((start + n) < dev->data_bytes_per_chunk)
++			n_copy = n;
++		else
++			n_copy = dev->data_bytes_per_chunk - start;
++
++		cache = yaffs_find_chunk_cache(in, chunk);
++
++		/* If the chunk is already in the cache or it is less than
++		 * a whole chunk or we're using inband tags then use the cache
++		 * (if there is caching) else bypass the cache.
++		 */
++		if (cache || n_copy != dev->data_bytes_per_chunk ||
++		    dev->param.inband_tags) {
++			if (dev->param.n_caches > 0) {
++
++				/* If we can't find the data in the cache,
++				 * then load it up. */
++
++				if (!cache) {
++					cache =
++					    yaffs_grab_chunk_cache(in->my_dev);
++					cache->object = in;
++					cache->chunk_id = chunk;
++					cache->dirty = 0;
++					cache->locked = 0;
++					yaffs_rd_data_obj(in, chunk,
++							  cache->data);
++					cache->n_bytes = 0;
++				}
++
++				yaffs_use_cache(dev, cache, 0);
++
++				cache->locked = 1;
++
++				memcpy(buffer, &cache->data[start], n_copy);
++
++				cache->locked = 0;
++			} else {
++				/* Read into the local buffer then copy.. */
++
++				u8 *local_buffer =
++				    yaffs_get_temp_buffer(dev);
++				yaffs_rd_data_obj(in, chunk, local_buffer);
++
++				memcpy(buffer, &local_buffer[start], n_copy);
++
++				yaffs_release_temp_buffer(dev, local_buffer);
++			}
++		} else {
++			/* A full chunk. Read directly into the buffer. */
++			yaffs_rd_data_obj(in, chunk, buffer);
++		}
++		n -= n_copy;
++		offset += n_copy;
++		buffer += n_copy;
++		n_done += n_copy;
++	}
++	return n_done;
++}
++
++int yaffs_do_file_wr(struct yaffs_obj *in, const u8 *buffer, loff_t offset,
++		     int n_bytes, int write_through)
++{
++
++	int chunk;
++	u32 start;
++	int n_copy;
++	int n = n_bytes;
++	int n_done = 0;
++	int n_writeback;
++	loff_t start_write = offset;
++	int chunk_written = 0;
++	u32 n_bytes_read;
++	loff_t chunk_start;
++	struct yaffs_dev *dev;
++
++	dev = in->my_dev;
++
++	while (n > 0 && chunk_written >= 0) {
++		yaffs_addr_to_chunk(dev, offset, &chunk, &start);
++
++		if (((loff_t)chunk) *
++		    dev->data_bytes_per_chunk + start != offset ||
++		    start >= dev->data_bytes_per_chunk) {
++			yaffs_trace(YAFFS_TRACE_ERROR,
++				"AddrToChunk of offset %lld gives chunk %d start %d",
++				offset, chunk, start);
++		}
++		chunk++;	/* File pos to chunk in file offset */
++
++		/* OK now check for the curveball where the start and end are in
++		 * the same chunk.
++		 */
++
++		if ((start + n) < dev->data_bytes_per_chunk) {
++			n_copy = n;
++
++			/* Now calculate how many bytes to write back....
++			 * If we're overwriting and not writing to then end of
++			 * file then we need to write back as much as was there
++			 * before.
++			 */
++
++			chunk_start = (((loff_t)(chunk - 1)) *
++					dev->data_bytes_per_chunk);
++
++			if (chunk_start > in->variant.file_variant.file_size)
++				n_bytes_read = 0;	/* Past end of file */
++			else
++				n_bytes_read =
++				    in->variant.file_variant.file_size -
++				    chunk_start;
++
++			if (n_bytes_read > dev->data_bytes_per_chunk)
++				n_bytes_read = dev->data_bytes_per_chunk;
++
++			n_writeback =
++			    (n_bytes_read >
++			     (start + n)) ? n_bytes_read : (start + n);
++
++			if (n_writeback < 0 ||
++			    n_writeback > dev->data_bytes_per_chunk)
++				BUG();
++
++		} else {
++			n_copy = dev->data_bytes_per_chunk - start;
++			n_writeback = dev->data_bytes_per_chunk;
++		}
++
++		if (n_copy != dev->data_bytes_per_chunk ||
++		    !dev->param.cache_bypass_aligned ||
++		    dev->param.inband_tags) {
++			/* An incomplete start or end chunk (or maybe both
++			 * start and end chunk), or we're using inband tags,
++			 * or we're forcing writes through the cache,
++			 * so we want to use the cache buffers.
++			 */
++			if (dev->param.n_caches > 0) {
++				struct yaffs_cache *cache;
++
++				/* If we can't find the data in the cache, then
++				 * load the cache */
++				cache = yaffs_find_chunk_cache(in, chunk);
++
++				if (!cache &&
++				    yaffs_check_alloc_available(dev, 1)) {
++					cache = yaffs_grab_chunk_cache(dev);
++					cache->object = in;
++					cache->chunk_id = chunk;
++					cache->dirty = 0;
++					cache->locked = 0;
++					yaffs_rd_data_obj(in, chunk,
++							  cache->data);
++				} else if (cache &&
++					   !cache->dirty &&
++					   !yaffs_check_alloc_available(dev,
++									1)) {
++					/* Drop the cache if it was a read cache
++					 * item and no space check has been made
++					 * for it.
++					 */
++					cache = NULL;
++				}
++
++				if (cache) {
++					yaffs_use_cache(dev, cache, 1);
++					cache->locked = 1;
++
++					memcpy(&cache->data[start], buffer,
++					       n_copy);
++
++					cache->locked = 0;
++					cache->n_bytes = n_writeback;
++
++					if (write_through) {
++						chunk_written =
++						    yaffs_wr_data_obj
++						    (cache->object,
++						     cache->chunk_id,
++						     cache->data,
++						     cache->n_bytes, 1);
++						cache->dirty = 0;
++					}
++				} else {
++					chunk_written = -1;	/* fail write */
++				}
++			} else {
++				/* An incomplete start or end chunk (or maybe
++				 * both start and end chunk). Read into the
++				 * local buffer then copy over and write back.
++				 */
++
++				u8 *local_buffer = yaffs_get_temp_buffer(dev);
++
++				yaffs_rd_data_obj(in, chunk, local_buffer);
++				memcpy(&local_buffer[start], buffer, n_copy);
++
++				chunk_written =
++				    yaffs_wr_data_obj(in, chunk,
++						      local_buffer,
++						      n_writeback, 0);
++
++				yaffs_release_temp_buffer(dev, local_buffer);
++			}
++		} else {
++			/* A full chunk. Write directly from the buffer. */
++
++			chunk_written =
++			    yaffs_wr_data_obj(in, chunk, buffer,
++					      dev->data_bytes_per_chunk, 0);
++
++			/* Since we've overwritten the cached data,
++			 * we better invalidate it. */
++			yaffs_invalidate_chunk_cache(in, chunk);
++		}
++
++		if (chunk_written >= 0) {
++			n -= n_copy;
++			offset += n_copy;
++			buffer += n_copy;
++			n_done += n_copy;
++		}
++	}
++
++	/* Update file object */
++
++	if ((start_write + n_done) > in->variant.file_variant.file_size)
++		in->variant.file_variant.file_size = (start_write + n_done);
++
++	in->dirty = 1;
++	return n_done;
++}
++
++int yaffs_wr_file(struct yaffs_obj *in, const u8 *buffer, loff_t offset,
++		  int n_bytes, int write_through)
++{
++	yaffs2_handle_hole(in, offset);
++	return yaffs_do_file_wr(in, buffer, offset, n_bytes, write_through);
++}
++
++/* ---------------------- File resizing stuff ------------------ */
++
++static void yaffs_prune_chunks(struct yaffs_obj *in, loff_t new_size)
++{
++
++	struct yaffs_dev *dev = in->my_dev;
++	loff_t old_size = in->variant.file_variant.file_size;
++	int i;
++	int chunk_id;
++	u32 dummy;
++	int last_del;
++	int start_del;
++
++	if (old_size > 0)
++		yaffs_addr_to_chunk(dev, old_size - 1, &last_del, &dummy);
++	else
++		last_del = 0;
++
++	yaffs_addr_to_chunk(dev, new_size + dev->data_bytes_per_chunk - 1,
++				&start_del, &dummy);
++	last_del++;
++	start_del++;
++
++	/* Delete backwards so that we don't end up with holes if
++	 * power is lost part-way through the operation.
++	 */
++	for (i = last_del; i >= start_del; i--) {
++		/* NB this could be optimised somewhat,
++		 * eg. could retrieve the tags and write them without
++		 * using yaffs_chunk_del
++		 */
++
++		chunk_id = yaffs_find_del_file_chunk(in, i, NULL);
++
++		if (chunk_id < 1)
++			continue;
++
++		if (chunk_id <
++		    (dev->internal_start_block * dev->param.chunks_per_block) ||
++		    chunk_id >=
++		    ((dev->internal_end_block + 1) *
++		      dev->param.chunks_per_block)) {
++			yaffs_trace(YAFFS_TRACE_ALWAYS,
++				"Found daft chunk_id %d for %d",
++				chunk_id, i);
++		} else {
++			in->n_data_chunks--;
++			yaffs_chunk_del(dev, chunk_id, 1, __LINE__);
++		}
++	}
++}
++
++void yaffs_resize_file_down(struct yaffs_obj *obj, loff_t new_size)
++{
++	int new_full;
++	u32 new_partial;
++	struct yaffs_dev *dev = obj->my_dev;
++
++	yaffs_addr_to_chunk(dev, new_size, &new_full, &new_partial);
++
++	yaffs_prune_chunks(obj, new_size);
++
++	if (new_partial != 0) {
++		int last_chunk = 1 + new_full;
++		u8 *local_buffer = yaffs_get_temp_buffer(dev);
++
++		/* Rewrite the last chunk with its new size and zero pad */
++		yaffs_rd_data_obj(obj, last_chunk, local_buffer);
++		memset(local_buffer + new_partial, 0,
++		       dev->data_bytes_per_chunk - new_partial);
++
++		yaffs_wr_data_obj(obj, last_chunk, local_buffer,
++				  new_partial, 1);
++
++		yaffs_release_temp_buffer(dev, local_buffer);
++	}
++
++	obj->variant.file_variant.file_size = new_size;
++
++	yaffs_prune_tree(dev, &obj->variant.file_variant);
++}
++
++int yaffs_resize_file(struct yaffs_obj *in, loff_t new_size)
++{
++	struct yaffs_dev *dev = in->my_dev;
++	loff_t old_size = in->variant.file_variant.file_size;
++
++	yaffs_flush_file_cache(in, 1);
++	yaffs_invalidate_whole_cache(in);
++
++	yaffs_check_gc(dev, 0);
++
++	if (in->variant_type != YAFFS_OBJECT_TYPE_FILE)
++		return YAFFS_FAIL;
++
++	if (new_size == old_size)
++		return YAFFS_OK;
++
++	if (new_size > old_size) {
++		yaffs2_handle_hole(in, new_size);
++		in->variant.file_variant.file_size = new_size;
++	} else {
++		/* new_size < old_size */
++		yaffs_resize_file_down(in, new_size);
++	}
++
++	/* Write a new object header to reflect the resize.
++	 * show we've shrunk the file, if need be
++	 * Do this only if the file is not in the deleted directories
++	 * and is not shadowed.
++	 */
++	if (in->parent &&
++	    !in->is_shadowed &&
++	    in->parent->obj_id != YAFFS_OBJECTID_UNLINKED &&
++	    in->parent->obj_id != YAFFS_OBJECTID_DELETED)
++		yaffs_update_oh(in, NULL, 0, 0, 0, NULL);
++
++	return YAFFS_OK;
++}
++
++int yaffs_flush_file(struct yaffs_obj *in,
++		     int update_time,
++		     int data_sync,
++		     int discard_cache)
++{
++	if (!in->dirty)
++		return YAFFS_OK;
++
++	yaffs_flush_file_cache(in, discard_cache);
++
++	if (data_sync)
++		return YAFFS_OK;
++
++	if (update_time)
++		yaffs_load_current_time(in, 0, 0);
++
++	return (yaffs_update_oh(in, NULL, 0, 0, 0, NULL) >= 0) ?
++				YAFFS_OK : YAFFS_FAIL;
++}
++
++
++/* yaffs_del_file deletes the whole file data
++ * and the inode associated with the file.
++ * It does not delete the links associated with the file.
++ */
++static int yaffs_unlink_file_if_needed(struct yaffs_obj *in)
++{
++	int ret_val;
++	int del_now = 0;
++	struct yaffs_dev *dev = in->my_dev;
++
++	if (!in->my_inode)
++		del_now = 1;
++
++	if (del_now) {
++		ret_val =
++		    yaffs_change_obj_name(in, in->my_dev->del_dir,
++					  _Y("deleted"), 0, 0);
++		yaffs_trace(YAFFS_TRACE_TRACING,
++			"yaffs: immediate deletion of file %d",
++			in->obj_id);
++		in->deleted = 1;
++		in->my_dev->n_deleted_files++;
++		if (dev->param.disable_soft_del || dev->param.is_yaffs2)
++			yaffs_resize_file(in, 0);
++		yaffs_soft_del_file(in);
++	} else {
++		ret_val =
++		    yaffs_change_obj_name(in, in->my_dev->unlinked_dir,
++					  _Y("unlinked"), 0, 0);
++	}
++	return ret_val;
++}
++
++static int yaffs_del_file(struct yaffs_obj *in)
++{
++	int ret_val = YAFFS_OK;
++	int deleted;	/* Need to cache value on stack if in is freed */
++	struct yaffs_dev *dev = in->my_dev;
++
++	if (dev->param.disable_soft_del || dev->param.is_yaffs2)
++		yaffs_resize_file(in, 0);
++
++	if (in->n_data_chunks > 0) {
++		/* Use soft deletion if there is data in the file.
++		 * That won't be the case if it has been resized to zero.
++		 */
++		if (!in->unlinked)
++			ret_val = yaffs_unlink_file_if_needed(in);
++
++		deleted = in->deleted;
++
++		if (ret_val == YAFFS_OK && in->unlinked && !in->deleted) {
++			in->deleted = 1;
++			deleted = 1;
++			in->my_dev->n_deleted_files++;
++			yaffs_soft_del_file(in);
++		}
++		return deleted ? YAFFS_OK : YAFFS_FAIL;
++	} else {
++		/* The file has no data chunks so we toss it immediately */
++		yaffs_free_tnode(in->my_dev, in->variant.file_variant.top);
++		in->variant.file_variant.top = NULL;
++		yaffs_generic_obj_del(in);
++
++		return YAFFS_OK;
++	}
++}
++
++int yaffs_is_non_empty_dir(struct yaffs_obj *obj)
++{
++	return (obj &&
++		obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) &&
++		!(list_empty(&obj->variant.dir_variant.children));
++}
++
++static int yaffs_del_dir(struct yaffs_obj *obj)
++{
++	/* First check that the directory is empty. */
++	if (yaffs_is_non_empty_dir(obj))
++		return YAFFS_FAIL;
++
++	return yaffs_generic_obj_del(obj);
++}
++
++static int yaffs_del_symlink(struct yaffs_obj *in)
++{
++	kfree(in->variant.symlink_variant.alias);
++	in->variant.symlink_variant.alias = NULL;
++
++	return yaffs_generic_obj_del(in);
++}
++
++static int yaffs_del_link(struct yaffs_obj *in)
++{
++	/* remove this hardlink from the list associated with the equivalent
++	 * object
++	 */
++	list_del_init(&in->hard_links);
++	return yaffs_generic_obj_del(in);
++}
++
++int yaffs_del_obj(struct yaffs_obj *obj)
++{
++	int ret_val = -1;
++
++	switch (obj->variant_type) {
++	case YAFFS_OBJECT_TYPE_FILE:
++		ret_val = yaffs_del_file(obj);
++		break;
++	case YAFFS_OBJECT_TYPE_DIRECTORY:
++		if (!list_empty(&obj->variant.dir_variant.dirty)) {
++			yaffs_trace(YAFFS_TRACE_BACKGROUND,
++				"Remove object %d from dirty directories",
++				obj->obj_id);
++			list_del_init(&obj->variant.dir_variant.dirty);
++		}
++		return yaffs_del_dir(obj);
++		break;
++	case YAFFS_OBJECT_TYPE_SYMLINK:
++		ret_val = yaffs_del_symlink(obj);
++		break;
++	case YAFFS_OBJECT_TYPE_HARDLINK:
++		ret_val = yaffs_del_link(obj);
++		break;
++	case YAFFS_OBJECT_TYPE_SPECIAL:
++		ret_val = yaffs_generic_obj_del(obj);
++		break;
++	case YAFFS_OBJECT_TYPE_UNKNOWN:
++		ret_val = 0;
++		break;		/* should not happen. */
++	}
++	return ret_val;
++}
++
++
++static void yaffs_empty_dir_to_dir(struct yaffs_obj *from_dir,
++				   struct yaffs_obj *to_dir)
++{
++	struct yaffs_obj *obj;
++	struct list_head *lh;
++	struct list_head *n;
++
++	list_for_each_safe(lh, n, &from_dir->variant.dir_variant.children) {
++		obj = list_entry(lh, struct yaffs_obj, siblings);
++		yaffs_add_obj_to_dir(to_dir, obj);
++	}
++}
++
++struct yaffs_obj *yaffs_retype_obj(struct yaffs_obj *obj,
++				   enum yaffs_obj_type type)
++{
++	/* Tear down the old variant */
++	switch (obj->variant_type) {
++	case YAFFS_OBJECT_TYPE_FILE:
++		/* Nuke file data */
++		yaffs_resize_file(obj, 0);
++		yaffs_free_tnode(obj->my_dev, obj->variant.file_variant.top);
++		obj->variant.file_variant.top = NULL;
++		break;
++	case YAFFS_OBJECT_TYPE_DIRECTORY:
++		/* Put the children in lost and found. */
++		yaffs_empty_dir_to_dir(obj, obj->my_dev->lost_n_found);
++		if (!list_empty(&obj->variant.dir_variant.dirty))
++			list_del_init(&obj->variant.dir_variant.dirty);
++		break;
++	case YAFFS_OBJECT_TYPE_SYMLINK:
++		/* Nuke symplink data */
++		kfree(obj->variant.symlink_variant.alias);
++		obj->variant.symlink_variant.alias = NULL;
++		break;
++	case YAFFS_OBJECT_TYPE_HARDLINK:
++		list_del_init(&obj->hard_links);
++		break;
++	default:
++		break;
++	}
++
++	memset(&obj->variant, 0, sizeof(obj->variant));
++
++	/*Set up new variant if the memset is not enough. */
++	switch (type) {
++	case YAFFS_OBJECT_TYPE_DIRECTORY:
++		INIT_LIST_HEAD(&obj->variant.dir_variant.children);
++		INIT_LIST_HEAD(&obj->variant.dir_variant.dirty);
++		break;
++	case YAFFS_OBJECT_TYPE_FILE:
++	case YAFFS_OBJECT_TYPE_SYMLINK:
++	case YAFFS_OBJECT_TYPE_HARDLINK:
++	default:
++		break;
++	}
++
++	obj->variant_type = type;
++
++	return obj;
++
++}
++
++static int yaffs_unlink_worker(struct yaffs_obj *obj)
++{
++	int del_now = 0;
++
++	if (!obj)
++		return YAFFS_FAIL;
++
++	if (!obj->my_inode)
++		del_now = 1;
++
++	yaffs_update_parent(obj->parent);
++
++	if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) {
++		return yaffs_del_link(obj);
++	} else if (!list_empty(&obj->hard_links)) {
++		/* Curve ball: We're unlinking an object that has a hardlink.
++		 *
++		 * This problem arises because we are not strictly following
++		 * The Linux link/inode model.
++		 *
++		 * We can't really delete the object.
++		 * Instead, we do the following:
++		 * - Select a hardlink.
++		 * - Unhook it from the hard links
++		 * - Move it from its parent directory so that the rename works.
++		 * - Rename the object to the hardlink's name.
++		 * - Delete the hardlink
++		 */
++
++		struct yaffs_obj *hl;
++		struct yaffs_obj *parent;
++		int ret_val;
++		YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
++
++		hl = list_entry(obj->hard_links.next, struct yaffs_obj,
++				hard_links);
++
++		yaffs_get_obj_name(hl, name, YAFFS_MAX_NAME_LENGTH + 1);
++		parent = hl->parent;
++
++		list_del_init(&hl->hard_links);
++
++		yaffs_add_obj_to_dir(obj->my_dev->unlinked_dir, hl);
++
++		ret_val = yaffs_change_obj_name(obj, parent, name, 0, 0);
++
++		if (ret_val == YAFFS_OK)
++			ret_val = yaffs_generic_obj_del(hl);
++
++		return ret_val;
++
++	} else if (del_now) {
++		switch (obj->variant_type) {
++		case YAFFS_OBJECT_TYPE_FILE:
++			return yaffs_del_file(obj);
++			break;
++		case YAFFS_OBJECT_TYPE_DIRECTORY:
++			list_del_init(&obj->variant.dir_variant.dirty);
++			return yaffs_del_dir(obj);
++			break;
++		case YAFFS_OBJECT_TYPE_SYMLINK:
++			return yaffs_del_symlink(obj);
++			break;
++		case YAFFS_OBJECT_TYPE_SPECIAL:
++			return yaffs_generic_obj_del(obj);
++			break;
++		case YAFFS_OBJECT_TYPE_HARDLINK:
++		case YAFFS_OBJECT_TYPE_UNKNOWN:
++		default:
++			return YAFFS_FAIL;
++		}
++	} else if (yaffs_is_non_empty_dir(obj)) {
++		return YAFFS_FAIL;
++	} else {
++		return yaffs_change_obj_name(obj, obj->my_dev->unlinked_dir,
++						_Y("unlinked"), 0, 0);
++	}
++}
++
++static int yaffs_unlink_obj(struct yaffs_obj *obj)
++{
++	if (obj && obj->unlink_allowed)
++		return yaffs_unlink_worker(obj);
++
++	return YAFFS_FAIL;
++}
++
++int yaffs_unlinker(struct yaffs_obj *dir, const YCHAR *name)
++{
++	struct yaffs_obj *obj;
++
++	obj = yaffs_find_by_name(dir, name);
++	return yaffs_unlink_obj(obj);
++}
++
++/* Note:
++ * If old_name is NULL then we take old_dir as the object to be renamed.
++ */
++int yaffs_rename_obj(struct yaffs_obj *old_dir, const YCHAR *old_name,
++		     struct yaffs_obj *new_dir, const YCHAR *new_name)
++{
++	struct yaffs_obj *obj = NULL;
++	struct yaffs_obj *existing_target = NULL;
++	int force = 0;
++	int result;
++	struct yaffs_dev *dev;
++
++	if (!old_dir || old_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
++		BUG();
++		return YAFFS_FAIL;
++	}
++	if (!new_dir || new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
++		BUG();
++		return YAFFS_FAIL;
++	}
++
++	dev = old_dir->my_dev;
++
++#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
++	/* Special case for case insemsitive systems.
++	 * While look-up is case insensitive, the name isn't.
++	 * Therefore we might want to change x.txt to X.txt
++	 */
++	if (old_dir == new_dir &&
++		old_name && new_name &&
++		strcmp(old_name, new_name) == 0)
++		force = 1;
++#endif
++
++	if (strnlen(new_name, YAFFS_MAX_NAME_LENGTH + 1) >
++	    YAFFS_MAX_NAME_LENGTH)
++		/* ENAMETOOLONG */
++		return YAFFS_FAIL;
++
++	if (old_name)
++		obj = yaffs_find_by_name(old_dir, old_name);
++	else{
++		obj = old_dir;
++		old_dir = obj->parent;
++	}
++
++	if (obj && obj->rename_allowed) {
++		/* Now handle an existing target, if there is one */
++		existing_target = yaffs_find_by_name(new_dir, new_name);
++		if (yaffs_is_non_empty_dir(existing_target)) {
++			return YAFFS_FAIL;	/* ENOTEMPTY */
++		} else if (existing_target && existing_target != obj) {
++			/* Nuke the target first, using shadowing,
++			 * but only if it isn't the same object.
++			 *
++			 * Note we must disable gc here otherwise it can mess
++			 * up the shadowing.
++			 *
++			 */
++			dev->gc_disable = 1;
++			yaffs_change_obj_name(obj, new_dir, new_name, force,
++					      existing_target->obj_id);
++			existing_target->is_shadowed = 1;
++			yaffs_unlink_obj(existing_target);
++			dev->gc_disable = 0;
++		}
++
++		result = yaffs_change_obj_name(obj, new_dir, new_name, 1, 0);
++
++		yaffs_update_parent(old_dir);
++		if (new_dir != old_dir)
++			yaffs_update_parent(new_dir);
++
++		return result;
++	}
++	return YAFFS_FAIL;
++}
++
++/*----------------------- Initialisation Scanning ---------------------- */
++
++void yaffs_handle_shadowed_obj(struct yaffs_dev *dev, int obj_id,
++			       int backward_scanning)
++{
++	struct yaffs_obj *obj;
++
++	if (backward_scanning) {
++		/* Handle YAFFS2 case (backward scanning)
++		 * If the shadowed object exists then ignore.
++		 */
++		obj = yaffs_find_by_number(dev, obj_id);
++		if (obj)
++			return;
++	}
++
++	/* Let's create it (if it does not exist) assuming it is a file so that
++	 * it can do shrinking etc.
++	 * We put it in unlinked dir to be cleaned up after the scanning
++	 */
++	obj =
++	    yaffs_find_or_create_by_number(dev, obj_id, YAFFS_OBJECT_TYPE_FILE);
++	if (!obj)
++		return;
++	obj->is_shadowed = 1;
++	yaffs_add_obj_to_dir(dev->unlinked_dir, obj);
++	obj->variant.file_variant.shrink_size = 0;
++	obj->valid = 1;		/* So that we don't read any other info. */
++}
++
++void yaffs_link_fixup(struct yaffs_dev *dev, struct list_head *hard_list)
++{
++	struct list_head *lh;
++	struct list_head *save;
++	struct yaffs_obj *hl;
++	struct yaffs_obj *in;
++
++	list_for_each_safe(lh, save, hard_list) {
++		hl = list_entry(lh, struct yaffs_obj, hard_links);
++		in = yaffs_find_by_number(dev,
++					hl->variant.hardlink_variant.equiv_id);
++
++		if (in) {
++			/* Add the hardlink pointers */
++			hl->variant.hardlink_variant.equiv_obj = in;
++			list_add(&hl->hard_links, &in->hard_links);
++		} else {
++			/* Todo Need to report/handle this better.
++			 * Got a problem... hardlink to a non-existant object
++			 */
++			hl->variant.hardlink_variant.equiv_obj = NULL;
++			INIT_LIST_HEAD(&hl->hard_links);
++		}
++	}
++}
++
++static void yaffs_strip_deleted_objs(struct yaffs_dev *dev)
++{
++	/*
++	 *  Sort out state of unlinked and deleted objects after scanning.
++	 */
++	struct list_head *i;
++	struct list_head *n;
++	struct yaffs_obj *l;
++
++	if (dev->read_only)
++		return;
++
++	/* Soft delete all the unlinked files */
++	list_for_each_safe(i, n,
++			   &dev->unlinked_dir->variant.dir_variant.children) {
++		l = list_entry(i, struct yaffs_obj, siblings);
++		yaffs_del_obj(l);
++	}
++
++	list_for_each_safe(i, n, &dev->del_dir->variant.dir_variant.children) {
++		l = list_entry(i, struct yaffs_obj, siblings);
++		yaffs_del_obj(l);
++	}
++}
++
++/*
++ * This code iterates through all the objects making sure that they are rooted.
++ * Any unrooted objects are re-rooted in lost+found.
++ * An object needs to be in one of:
++ * - Directly under deleted, unlinked
++ * - Directly or indirectly under root.
++ *
++ * Note:
++ *  This code assumes that we don't ever change the current relationships
++ *  between directories:
++ *   root_dir->parent == unlinked_dir->parent == del_dir->parent == NULL
++ *   lost-n-found->parent == root_dir
++ *
++ * This fixes the problem where directories might have inadvertently been
++ * deleted leaving the object "hanging" without being rooted in the
++ * directory tree.
++ */
++
++static int yaffs_has_null_parent(struct yaffs_dev *dev, struct yaffs_obj *obj)
++{
++	return (obj == dev->del_dir ||
++		obj == dev->unlinked_dir || obj == dev->root_dir);
++}
++
++static void yaffs_fix_hanging_objs(struct yaffs_dev *dev)
++{
++	struct yaffs_obj *obj;
++	struct yaffs_obj *parent;
++	int i;
++	struct list_head *lh;
++	struct list_head *n;
++	int depth_limit;
++	int hanging;
++
++	if (dev->read_only)
++		return;
++
++	/* Iterate through the objects in each hash entry,
++	 * looking at each object.
++	 * Make sure it is rooted.
++	 */
++
++	for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
++		list_for_each_safe(lh, n, &dev->obj_bucket[i].list) {
++			obj = list_entry(lh, struct yaffs_obj, hash_link);
++			parent = obj->parent;
++
++			if (yaffs_has_null_parent(dev, obj)) {
++				/* These directories are not hanging */
++				hanging = 0;
++			} else if (!parent ||
++				   parent->variant_type !=
++				   YAFFS_OBJECT_TYPE_DIRECTORY) {
++				hanging = 1;
++			} else if (yaffs_has_null_parent(dev, parent)) {
++				hanging = 0;
++			} else {
++				/*
++				 * Need to follow the parent chain to
++				 * see if it is hanging.
++				 */
++				hanging = 0;
++				depth_limit = 100;
++
++				while (parent != dev->root_dir &&
++				       parent->parent &&
++				       parent->parent->variant_type ==
++				       YAFFS_OBJECT_TYPE_DIRECTORY &&
++				       depth_limit > 0) {
++					parent = parent->parent;
++					depth_limit--;
++				}
++				if (parent != dev->root_dir)
++					hanging = 1;
++			}
++			if (hanging) {
++				yaffs_trace(YAFFS_TRACE_SCAN,
++					"Hanging object %d moved to lost and found",
++					obj->obj_id);
++				yaffs_add_obj_to_dir(dev->lost_n_found, obj);
++			}
++		}
++	}
++}
++
++/*
++ * Delete directory contents for cleaning up lost and found.
++ */
++static void yaffs_del_dir_contents(struct yaffs_obj *dir)
++{
++	struct yaffs_obj *obj;
++	struct list_head *lh;
++	struct list_head *n;
++
++	if (dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
++		BUG();
++
++	list_for_each_safe(lh, n, &dir->variant.dir_variant.children) {
++		obj = list_entry(lh, struct yaffs_obj, siblings);
++		if (obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY)
++			yaffs_del_dir_contents(obj);
++		yaffs_trace(YAFFS_TRACE_SCAN,
++			"Deleting lost_found object %d",
++			obj->obj_id);
++		yaffs_unlink_obj(obj);
++	}
++}
++
++static void yaffs_empty_l_n_f(struct yaffs_dev *dev)
++{
++	yaffs_del_dir_contents(dev->lost_n_found);
++}
++
++
++struct yaffs_obj *yaffs_find_by_name(struct yaffs_obj *directory,
++				     const YCHAR *name)
++{
++	int sum;
++	struct list_head *i;
++	YCHAR buffer[YAFFS_MAX_NAME_LENGTH + 1];
++	struct yaffs_obj *l;
++
++	if (!name)
++		return NULL;
++
++	if (!directory) {
++		yaffs_trace(YAFFS_TRACE_ALWAYS,
++			"tragedy: yaffs_find_by_name: null pointer directory"
++			);
++		BUG();
++		return NULL;
++	}
++	if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
++		yaffs_trace(YAFFS_TRACE_ALWAYS,
++			"tragedy: yaffs_find_by_name: non-directory"
++			);
++		BUG();
++	}
++
++	sum = yaffs_calc_name_sum(name);
++
++	list_for_each(i, &directory->variant.dir_variant.children) {
++		l = list_entry(i, struct yaffs_obj, siblings);
++
++		if (l->parent != directory)
++			BUG();
++
++		yaffs_check_obj_details_loaded(l);
++
++		/* Special case for lost-n-found */
++		if (l->obj_id == YAFFS_OBJECTID_LOSTNFOUND) {
++			if (!strcmp(name, YAFFS_LOSTNFOUND_NAME))
++				return l;
++		} else if (l->sum == sum || l->hdr_chunk <= 0) {
++			/* LostnFound chunk called Objxxx
++			 * Do a real check
++			 */
++			yaffs_get_obj_name(l, buffer,
++				YAFFS_MAX_NAME_LENGTH + 1);
++			if (!strncmp(name, buffer, YAFFS_MAX_NAME_LENGTH))
++				return l;
++		}
++	}
++	return NULL;
++}
++
++/* GetEquivalentObject dereferences any hard links to get to the
++ * actual object.
++ */
++
++struct yaffs_obj *yaffs_get_equivalent_obj(struct yaffs_obj *obj)
++{
++	if (obj && obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) {
++		obj = obj->variant.hardlink_variant.equiv_obj;
++		yaffs_check_obj_details_loaded(obj);
++	}
++	return obj;
++}
++
++/*
++ *  A note or two on object names.
++ *  * If the object name is missing, we then make one up in the form objnnn
++ *
++ *  * ASCII names are stored in the object header's name field from byte zero
++ *  * Unicode names are historically stored starting from byte zero.
++ *
++ * Then there are automatic Unicode names...
++ * The purpose of these is to save names in a way that can be read as
++ * ASCII or Unicode names as appropriate, thus allowing a Unicode and ASCII
++ * system to share files.
++ *
++ * These automatic unicode are stored slightly differently...
++ *  - If the name can fit in the ASCII character space then they are saved as
++ *    ascii names as per above.
++ *  - If the name needs Unicode then the name is saved in Unicode
++ *    starting at oh->name[1].
++
++ */
++static void yaffs_fix_null_name(struct yaffs_obj *obj, YCHAR *name,
++				int buffer_size)
++{
++	/* Create an object name if we could not find one. */
++	if (strnlen(name, YAFFS_MAX_NAME_LENGTH) == 0) {
++		YCHAR local_name[20];
++		YCHAR num_string[20];
++		YCHAR *x = &num_string[19];
++		unsigned v = obj->obj_id;
++		num_string[19] = 0;
++		while (v > 0) {
++			x--;
++			*x = '0' + (v % 10);
++			v /= 10;
++		}
++		/* make up a name */
++		strcpy(local_name, YAFFS_LOSTNFOUND_PREFIX);
++		strcat(local_name, x);
++		strncpy(name, local_name, buffer_size - 1);
++	}
++}
++
++int yaffs_get_obj_name(struct yaffs_obj *obj, YCHAR *name, int buffer_size)
++{
++	memset(name, 0, buffer_size * sizeof(YCHAR));
++	yaffs_check_obj_details_loaded(obj);
++	if (obj->obj_id == YAFFS_OBJECTID_LOSTNFOUND) {
++		strncpy(name, YAFFS_LOSTNFOUND_NAME, buffer_size - 1);
++	} else if (obj->short_name[0]) {
++		strcpy(name, obj->short_name);
++	} else if (obj->hdr_chunk > 0) {
++		int result;
++		u8 *buffer = yaffs_get_temp_buffer(obj->my_dev);
++
++		struct yaffs_obj_hdr *oh = (struct yaffs_obj_hdr *)buffer;
++
++		memset(buffer, 0, obj->my_dev->data_bytes_per_chunk);
++
++		if (obj->hdr_chunk > 0) {
++			result = yaffs_rd_chunk_tags_nand(obj->my_dev,
++							  obj->hdr_chunk,
++							  buffer, NULL);
++		}
++		yaffs_load_name_from_oh(obj->my_dev, name, oh->name,
++					buffer_size);
++
++		yaffs_release_temp_buffer(obj->my_dev, buffer);
++	}
++
++	yaffs_fix_null_name(obj, name, buffer_size);
++
++	return strnlen(name, YAFFS_MAX_NAME_LENGTH);
++}
++
++loff_t yaffs_get_obj_length(struct yaffs_obj *obj)
++{
++	/* Dereference any hard linking */
++	obj = yaffs_get_equivalent_obj(obj);
++
++	if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
++		return obj->variant.file_variant.file_size;
++	if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) {
++		if (!obj->variant.symlink_variant.alias)
++			return 0;
++		return strnlen(obj->variant.symlink_variant.alias,
++				     YAFFS_MAX_ALIAS_LENGTH);
++	} else {
++		/* Only a directory should drop through to here */
++		return obj->my_dev->data_bytes_per_chunk;
++	}
++}
++
++int yaffs_get_obj_link_count(struct yaffs_obj *obj)
++{
++	int count = 0;
++	struct list_head *i;
++
++	if (!obj->unlinked)
++		count++;	/* the object itself */
++
++	list_for_each(i, &obj->hard_links)
++	    count++;		/* add the hard links; */
++
++	return count;
++}
++
++int yaffs_get_obj_inode(struct yaffs_obj *obj)
++{
++	obj = yaffs_get_equivalent_obj(obj);
++
++	return obj->obj_id;
++}
++
++unsigned yaffs_get_obj_type(struct yaffs_obj *obj)
++{
++	obj = yaffs_get_equivalent_obj(obj);
++
++	switch (obj->variant_type) {
++	case YAFFS_OBJECT_TYPE_FILE:
++		return DT_REG;
++		break;
++	case YAFFS_OBJECT_TYPE_DIRECTORY:
++		return DT_DIR;
++		break;
++	case YAFFS_OBJECT_TYPE_SYMLINK:
++		return DT_LNK;
++		break;
++	case YAFFS_OBJECT_TYPE_HARDLINK:
++		return DT_REG;
++		break;
++	case YAFFS_OBJECT_TYPE_SPECIAL:
++		if (S_ISFIFO(obj->yst_mode))
++			return DT_FIFO;
++		if (S_ISCHR(obj->yst_mode))
++			return DT_CHR;
++		if (S_ISBLK(obj->yst_mode))
++			return DT_BLK;
++		if (S_ISSOCK(obj->yst_mode))
++			return DT_SOCK;
++		return DT_REG;
++		break;
++	default:
++		return DT_REG;
++		break;
++	}
++}
++
++YCHAR *yaffs_get_symlink_alias(struct yaffs_obj *obj)
++{
++	obj = yaffs_get_equivalent_obj(obj);
++	if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK)
++		return yaffs_clone_str(obj->variant.symlink_variant.alias);
++	else
++		return yaffs_clone_str(_Y(""));
++}
++
++/*--------------------------- Initialisation code -------------------------- */
++
++static int yaffs_check_dev_fns(struct yaffs_dev *dev)
++{
++	struct yaffs_driver *drv = &dev->drv;
++	struct yaffs_tags_handler *tagger = &dev->tagger;
++
++	/* Common functions, gotta have */
++	if (!drv->drv_read_chunk_fn ||
++	    !drv->drv_write_chunk_fn ||
++	    !drv->drv_erase_fn)
++		return 0;
++
++	if (dev->param.is_yaffs2 &&
++	     (!drv->drv_mark_bad_fn  || !drv->drv_check_bad_fn))
++		return 0;
++
++	/* Install the default tags marshalling functions if needed. */
++	yaffs_tags_compat_install(dev);
++	yaffs_tags_marshall_install(dev);
++
++	/* Check we now have the marshalling functions required. */
++	if (!tagger->write_chunk_tags_fn ||
++	    !tagger->read_chunk_tags_fn ||
++	    !tagger->query_block_fn ||
++	    !tagger->mark_bad_fn)
++		return 0;
++
++	return 1;
++}
++
++static int yaffs_create_initial_dir(struct yaffs_dev *dev)
++{
++	/* Initialise the unlinked, deleted, root and lost+found directories */
++	dev->lost_n_found = dev->root_dir = NULL;
++	dev->unlinked_dir = dev->del_dir = NULL;
++	dev->unlinked_dir =
++	    yaffs_create_fake_dir(dev, YAFFS_OBJECTID_UNLINKED, S_IFDIR);
++	dev->del_dir =
++	    yaffs_create_fake_dir(dev, YAFFS_OBJECTID_DELETED, S_IFDIR);
++	dev->root_dir =
++	    yaffs_create_fake_dir(dev, YAFFS_OBJECTID_ROOT,
++				  YAFFS_ROOT_MODE | S_IFDIR);
++	dev->lost_n_found =
++	    yaffs_create_fake_dir(dev, YAFFS_OBJECTID_LOSTNFOUND,
++				  YAFFS_LOSTNFOUND_MODE | S_IFDIR);
++
++	if (dev->lost_n_found && dev->root_dir && dev->unlinked_dir
++	    && dev->del_dir) {
++		yaffs_add_obj_to_dir(dev->root_dir, dev->lost_n_found);
++		return YAFFS_OK;
++	}
++	return YAFFS_FAIL;
++}
++
++/* Low level init.
++ * Typically only used by yaffs_guts_initialise, but also used by the
++ * Low level yaffs driver tests.
++ */
++
++int yaffs_guts_ll_init(struct yaffs_dev *dev)
++{
++
++
++	yaffs_trace(YAFFS_TRACE_TRACING, "yaffs: yaffs_ll_init()");
++
++	if (!dev) {
++		yaffs_trace(YAFFS_TRACE_ALWAYS,
++			"yaffs: Need a device"
++			);
++		return YAFFS_FAIL;
++	}
++
++	if (dev->ll_init)
++		return YAFFS_OK;
++
++	dev->internal_start_block = dev->param.start_block;
++	dev->internal_end_block = dev->param.end_block;
++	dev->block_offset = 0;
++	dev->chunk_offset = 0;
++	dev->n_free_chunks = 0;
++
++	dev->gc_block = 0;
++
++	if (dev->param.start_block == 0) {
++		dev->internal_start_block = dev->param.start_block + 1;
++		dev->internal_end_block = dev->param.end_block + 1;
++		dev->block_offset = 1;
++		dev->chunk_offset = dev->param.chunks_per_block;
++	}
++
++	/* Check geometry parameters. */
++
++	if ((!dev->param.inband_tags && dev->param.is_yaffs2 &&
++		dev->param.total_bytes_per_chunk < 1024) ||
++		(!dev->param.is_yaffs2 &&
++			dev->param.total_bytes_per_chunk < 512) ||
++		(dev->param.inband_tags && !dev->param.is_yaffs2) ||
++		 dev->param.chunks_per_block < 2 ||
++		 dev->param.n_reserved_blocks < 2 ||
++		dev->internal_start_block <= 0 ||
++		dev->internal_end_block <= 0 ||
++		dev->internal_end_block <=
++		(dev->internal_start_block + dev->param.n_reserved_blocks + 2)
++		) {
++		/* otherwise it is too small */
++		yaffs_trace(YAFFS_TRACE_ALWAYS,
++			"NAND geometry problems: chunk size %d, type is yaffs%s, inband_tags %d ",
++			dev->param.total_bytes_per_chunk,
++			dev->param.is_yaffs2 ? "2" : "",
++			dev->param.inband_tags);
++		return YAFFS_FAIL;
++	}
++
++	/* Sort out space for inband tags, if required */
++	if (dev->param.inband_tags)
++		dev->data_bytes_per_chunk =
++		    dev->param.total_bytes_per_chunk -
++		    sizeof(struct yaffs_packed_tags2_tags_only);
++	else
++		dev->data_bytes_per_chunk = dev->param.total_bytes_per_chunk;
++
++	/* Got the right mix of functions? */
++	if (!yaffs_check_dev_fns(dev)) {
++		/* Function missing */
++		yaffs_trace(YAFFS_TRACE_ALWAYS,
++			"device function(s) missing or wrong");
++
++		return YAFFS_FAIL;
++	}
++
++	if (yaffs_init_nand(dev) != YAFFS_OK) {
++		yaffs_trace(YAFFS_TRACE_ALWAYS, "InitialiseNAND failed");
++		return YAFFS_FAIL;
++	}
++
++	return YAFFS_OK;
++}
++
++
++int yaffs_guts_format_dev(struct yaffs_dev *dev)
++{
++	int i;
++	enum yaffs_block_state state;
++	u32 dummy;
++
++	if(yaffs_guts_ll_init(dev) != YAFFS_OK)
++		return YAFFS_FAIL;
++
++	if(dev->is_mounted)
++		return YAFFS_FAIL;
++
++	for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
++		yaffs_query_init_block_state(dev, i, &state, &dummy);
++		if (state != YAFFS_BLOCK_STATE_DEAD)
++			yaffs_erase_block(dev, i);
++	}
++
++	return YAFFS_OK;
++}
++
++
++int yaffs_guts_initialise(struct yaffs_dev *dev)
++{
++	int init_failed = 0;
++	unsigned x;
++	int bits;
++
++	if(yaffs_guts_ll_init(dev) != YAFFS_OK)
++		return YAFFS_FAIL;
++
++	if (dev->is_mounted) {
++		yaffs_trace(YAFFS_TRACE_ALWAYS, "device already mounted");
++		return YAFFS_FAIL;
++	}
++
++	dev->is_mounted = 1;
++
++	/* OK now calculate a few things for the device */
++
++	/*
++	 *  Calculate all the chunk size manipulation numbers:
++	 */
++	x = dev->data_bytes_per_chunk;
++	/* We always use dev->chunk_shift and dev->chunk_div */
++	dev->chunk_shift = calc_shifts(x);
++	x >>= dev->chunk_shift;
++	dev->chunk_div = x;
++	/* We only use chunk mask if chunk_div is 1 */
++	dev->chunk_mask = (1 << dev->chunk_shift) - 1;
++
++	/*
++	 * Calculate chunk_grp_bits.
++	 * We need to find the next power of 2 > than internal_end_block
++	 */
++
++	x = dev->param.chunks_per_block * (dev->internal_end_block + 1);
++
++	bits = calc_shifts_ceiling(x);
++
++	/* Set up tnode width if wide tnodes are enabled. */
++	if (!dev->param.wide_tnodes_disabled) {
++		/* bits must be even so that we end up with 32-bit words */
++		if (bits & 1)
++			bits++;
++		if (bits < 16)
++			dev->tnode_width = 16;
++		else
++			dev->tnode_width = bits;
++	} else {
++		dev->tnode_width = 16;
++	}
++
++	dev->tnode_mask = (1 << dev->tnode_width) - 1;
++
++	/* Level0 Tnodes are 16 bits or wider (if wide tnodes are enabled),
++	 * so if the bitwidth of the
++	 * chunk range we're using is greater than 16 we need
++	 * to figure out chunk shift and chunk_grp_size
++	 */
++
++	if (bits <= dev->tnode_width)
++		dev->chunk_grp_bits = 0;
++	else
++		dev->chunk_grp_bits = bits - dev->tnode_width;
++
++	dev->tnode_size = (dev->tnode_width * YAFFS_NTNODES_LEVEL0) / 8;
++	if (dev->tnode_size < sizeof(struct yaffs_tnode))
++		dev->tnode_size = sizeof(struct yaffs_tnode);
++
++	dev->chunk_grp_size = 1 << dev->chunk_grp_bits;
++
++	if (dev->param.chunks_per_block < dev->chunk_grp_size) {
++		/* We have a problem because the soft delete won't work if
++		 * the chunk group size > chunks per block.
++		 * This can be remedied by using larger "virtual blocks".
++		 */
++		yaffs_trace(YAFFS_TRACE_ALWAYS, "chunk group too large");
++
++		return YAFFS_FAIL;
++	}
++
++	/* Finished verifying the device, continue with initialisation */
++
++	/* More device initialisation */
++	dev->all_gcs = 0;
++	dev->passive_gc_count = 0;
++	dev->oldest_dirty_gc_count = 0;
++	dev->bg_gcs = 0;
++	dev->gc_block_finder = 0;
++	dev->buffered_block = -1;
++	dev->doing_buffered_block_rewrite = 0;
++	dev->n_deleted_files = 0;
++	dev->n_bg_deletions = 0;
++	dev->n_unlinked_files = 0;
++	dev->n_ecc_fixed = 0;
++	dev->n_ecc_unfixed = 0;
++	dev->n_tags_ecc_fixed = 0;
++	dev->n_tags_ecc_unfixed = 0;
++	dev->n_erase_failures = 0;
++	dev->n_erased_blocks = 0;
++	dev->gc_disable = 0;
++	dev->has_pending_prioritised_gc = 1;
++		/* Assume the worst for now, will get fixed on first GC */
++	INIT_LIST_HEAD(&dev->dirty_dirs);
++	dev->oldest_dirty_seq = 0;
++	dev->oldest_dirty_block = 0;
++
++	/* Initialise temporary buffers and caches. */
++	if (!yaffs_init_tmp_buffers(dev))
++		init_failed = 1;
++
++	dev->cache = NULL;
++	dev->gc_cleanup_list = NULL;
++
++	if (!init_failed && dev->param.n_caches > 0) {
++		int i;
++		void *buf;
++		int cache_bytes =
++		    dev->param.n_caches * sizeof(struct yaffs_cache);
++
++		if (dev->param.n_caches > YAFFS_MAX_SHORT_OP_CACHES)
++			dev->param.n_caches = YAFFS_MAX_SHORT_OP_CACHES;
++
++		dev->cache = kmalloc(cache_bytes, GFP_NOFS);
++
++		buf = (u8 *) dev->cache;
++
++		if (dev->cache)
++			memset(dev->cache, 0, cache_bytes);
++
++		for (i = 0; i < dev->param.n_caches && buf; i++) {
++			dev->cache[i].object = NULL;
++			dev->cache[i].last_use = 0;
++			dev->cache[i].dirty = 0;
++			dev->cache[i].data = buf =
++			    kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS);
++		}
++		if (!buf)
++			init_failed = 1;
++
++		dev->cache_last_use = 0;
++	}
++
++	dev->cache_hits = 0;
++
++	if (!init_failed) {
++		dev->gc_cleanup_list =
++		    kmalloc(dev->param.chunks_per_block * sizeof(u32),
++					GFP_NOFS);
++		if (!dev->gc_cleanup_list)
++			init_failed = 1;
++	}
++
++	if (dev->param.is_yaffs2)
++		dev->param.use_header_file_size = 1;
++
++	if (!init_failed && !yaffs_init_blocks(dev))
++		init_failed = 1;
++
++	yaffs_init_tnodes_and_objs(dev);
++
++	if (!init_failed && !yaffs_create_initial_dir(dev))
++		init_failed = 1;
++
++	if (!init_failed && dev->param.is_yaffs2 &&
++		!dev->param.disable_summary &&
++		!yaffs_summary_init(dev))
++		init_failed = 1;
++
++	if (!init_failed) {
++		/* Now scan the flash. */
++		if (dev->param.is_yaffs2) {
++			if (yaffs2_checkpt_restore(dev)) {
++				yaffs_check_obj_details_loaded(dev->root_dir);
++				yaffs_trace(YAFFS_TRACE_CHECKPOINT |
++					YAFFS_TRACE_MOUNT,
++					"yaffs: restored from checkpoint"
++					);
++			} else {
++
++				/* Clean up the mess caused by an aborted
++				 * checkpoint load then scan backwards.
++				 */
++				yaffs_deinit_blocks(dev);
++
++				yaffs_deinit_tnodes_and_objs(dev);
++
++				dev->n_erased_blocks = 0;
++				dev->n_free_chunks = 0;
++				dev->alloc_block = -1;
++				dev->alloc_page = -1;
++				dev->n_deleted_files = 0;
++				dev->n_unlinked_files = 0;
++				dev->n_bg_deletions = 0;
++
++				if (!init_failed && !yaffs_init_blocks(dev))
++					init_failed = 1;
++
++				yaffs_init_tnodes_and_objs(dev);
++
++				if (!init_failed
++				    && !yaffs_create_initial_dir(dev))
++					init_failed = 1;
++
++				if (!init_failed && !yaffs2_scan_backwards(dev))
++					init_failed = 1;
++			}
++		} else if (!yaffs1_scan(dev)) {
++			init_failed = 1;
++		}
++
++		yaffs_strip_deleted_objs(dev);
++		yaffs_fix_hanging_objs(dev);
++		if (dev->param.empty_lost_n_found)
++			yaffs_empty_l_n_f(dev);
++	}
++
++	if (init_failed) {
++		/* Clean up the mess */
++		yaffs_trace(YAFFS_TRACE_TRACING,
++		  "yaffs: yaffs_guts_initialise() aborted.");
++
++		yaffs_deinitialise(dev);
++		return YAFFS_FAIL;
++	}
++
++	/* Zero out stats */
++	dev->n_page_reads = 0;
++	dev->n_page_writes = 0;
++	dev->n_erasures = 0;
++	dev->n_gc_copies = 0;
++	dev->n_retried_writes = 0;
++
++	dev->n_retired_blocks = 0;
++
++	yaffs_verify_free_chunks(dev);
++	yaffs_verify_blocks(dev);
++
++	/* Clean up any aborted checkpoint data */
++	if (!dev->is_checkpointed && dev->blocks_in_checkpt > 0)
++		yaffs2_checkpt_invalidate(dev);
++
++	yaffs_trace(YAFFS_TRACE_TRACING,
++	  "yaffs: yaffs_guts_initialise() done.");
++	return YAFFS_OK;
++}
++
++void yaffs_deinitialise(struct yaffs_dev *dev)
++{
++	if (dev->is_mounted) {
++		int i;
++
++		yaffs_deinit_blocks(dev);
++		yaffs_deinit_tnodes_and_objs(dev);
++		yaffs_summary_deinit(dev);
++
++		if (dev->param.n_caches > 0 && dev->cache) {
++
++			for (i = 0; i < dev->param.n_caches; i++) {
++				kfree(dev->cache[i].data);
++				dev->cache[i].data = NULL;
++			}
++
++			kfree(dev->cache);
++			dev->cache = NULL;
++		}
++
++		kfree(dev->gc_cleanup_list);
++
++		for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
++			kfree(dev->temp_buffer[i].buffer);
++			dev->temp_buffer[i].buffer = NULL;
++		}
++
++		kfree(dev->checkpt_buffer);
++		dev->checkpt_buffer = NULL;
++		kfree(dev->checkpt_block_list);
++		dev->checkpt_block_list = NULL;
++
++		dev->is_mounted = 0;
++
++		yaffs_deinit_nand(dev);
++	}
++}
++
++int yaffs_count_free_chunks(struct yaffs_dev *dev)
++{
++	int n_free = 0;
++	int b;
++	struct yaffs_block_info *blk;
++
++	blk = dev->block_info;
++	for (b = dev->internal_start_block; b <= dev->internal_end_block; b++) {
++		switch (blk->block_state) {
++		case YAFFS_BLOCK_STATE_EMPTY:
++		case YAFFS_BLOCK_STATE_ALLOCATING:
++		case YAFFS_BLOCK_STATE_COLLECTING:
++		case YAFFS_BLOCK_STATE_FULL:
++			n_free +=
++			    (dev->param.chunks_per_block - blk->pages_in_use +
++			     blk->soft_del_pages);
++			break;
++		default:
++			break;
++		}
++		blk++;
++	}
++	return n_free;
++}
++
++int yaffs_get_n_free_chunks(struct yaffs_dev *dev)
++{
++	/* This is what we report to the outside world */
++	int n_free;
++	int n_dirty_caches;
++	int blocks_for_checkpt;
++	int i;
++
++	n_free = dev->n_free_chunks;
++	n_free += dev->n_deleted_files;
++
++	/* Now count and subtract the number of dirty chunks in the cache. */
++
++	for (n_dirty_caches = 0, i = 0; i < dev->param.n_caches; i++) {
++		if (dev->cache[i].dirty)
++			n_dirty_caches++;
++	}
++
++	n_free -= n_dirty_caches;
++
++	n_free -=
++	    ((dev->param.n_reserved_blocks + 1) * dev->param.chunks_per_block);
++
++	/* Now figure checkpoint space and report that... */
++	blocks_for_checkpt = yaffs_calc_checkpt_blocks_required(dev);
++
++	n_free -= (blocks_for_checkpt * dev->param.chunks_per_block);
++
++	if (n_free < 0)
++		n_free = 0;
++
++	return n_free;
++}
++
++
++
++/*
++ * Marshalling functions to get loff_t file sizes into and out of
++ * object headers.
++ */
++void yaffs_oh_size_load(struct yaffs_obj_hdr *oh, loff_t fsize)
++{
++	oh->file_size_low = (fsize & 0xFFFFFFFF);
++	oh->file_size_high = ((fsize >> 32) & 0xFFFFFFFF);
++}
++
++loff_t yaffs_oh_to_size(struct yaffs_obj_hdr *oh)
++{
++	loff_t retval;
++
++	if (sizeof(loff_t) >= 8 && ~(oh->file_size_high))
++		retval = (((loff_t) oh->file_size_high) << 32) |
++			(((loff_t) oh->file_size_low) & 0xFFFFFFFF);
++	else
++		retval = (loff_t) oh->file_size_low;
++
++	return retval;
++}
++
++
++void yaffs_count_blocks_by_state(struct yaffs_dev *dev, int bs[10])
++{
++	int i;
++	struct yaffs_block_info *bi;
++	int s;
++
++	for(i = 0; i < 10; i++)
++		bs[i] = 0;
++
++	for(i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
++		bi = yaffs_get_block_info(dev, i);
++		s = bi->block_state;
++		if(s > YAFFS_BLOCK_STATE_DEAD || s < YAFFS_BLOCK_STATE_UNKNOWN)
++			bs[0]++;
++		else
++			bs[s]++;
++	}
++}
+diff --git a/fs/yaffs2/yaffs_guts.h b/fs/yaffs2/yaffs_guts.h
+new file mode 100644
+index 0000000..231f8ac
+--- /dev/null
++++ b/fs/yaffs2/yaffs_guts.h
+@@ -0,0 +1,1010 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ *   for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_GUTS_H__
++#define __YAFFS_GUTS_H__
++
++#include "yportenv.h"
++
++#define YAFFS_OK	1
++#define YAFFS_FAIL  0
++
++/* Give us a  Y=0x59,
++ * Give us an A=0x41,
++ * Give us an FF=0xff
++ * Give us an S=0x53
++ * And what have we got...
++ */
++#define YAFFS_MAGIC			0x5941ff53
++
++/*
++ * Tnodes form a tree with the tnodes in "levels"
++ * Levels greater than 0 hold 8 slots which point to other tnodes.
++ * Those at level 0 hold 16 slots which point to chunks in NAND.
++ *
++ * A maximum level of 8 thust supports files of size up to:
++ *
++ * 2^(3*MAX_LEVEL+4)
++ *
++ * Thus a max level of 8 supports files with up to 2^^28 chunks which gives
++ * a maximum file size of around 512Gbytees with 2k chunks.
++ */
++#define YAFFS_NTNODES_LEVEL0		16
++#define YAFFS_TNODES_LEVEL0_BITS	4
++#define YAFFS_TNODES_LEVEL0_MASK	0xf
++
++#define YAFFS_NTNODES_INTERNAL		(YAFFS_NTNODES_LEVEL0 / 2)
++#define YAFFS_TNODES_INTERNAL_BITS	(YAFFS_TNODES_LEVEL0_BITS - 1)
++#define YAFFS_TNODES_INTERNAL_MASK	0x7
++#define YAFFS_TNODES_MAX_LEVEL		8
++#define YAFFS_TNODES_MAX_BITS		(YAFFS_TNODES_LEVEL0_BITS + \
++					YAFFS_TNODES_INTERNAL_BITS * \
++					YAFFS_TNODES_MAX_LEVEL)
++#define YAFFS_MAX_CHUNK_ID		((1 << YAFFS_TNODES_MAX_BITS) - 1)
++
++#define YAFFS_MAX_FILE_SIZE_32		0x7fffffff
++
++/* Constants for YAFFS1 mode */
++#define YAFFS_BYTES_PER_SPARE		16
++#define YAFFS_BYTES_PER_CHUNK		512
++#define YAFFS_CHUNK_SIZE_SHIFT		9
++#define YAFFS_CHUNKS_PER_BLOCK		32
++#define YAFFS_BYTES_PER_BLOCK	(YAFFS_CHUNKS_PER_BLOCK*YAFFS_BYTES_PER_CHUNK)
++
++#define YAFFS_MIN_YAFFS2_CHUNK_SIZE	1024
++#define YAFFS_MIN_YAFFS2_SPARE_SIZE	32
++
++
++
++#define YAFFS_ALLOCATION_NOBJECTS	100
++#define YAFFS_ALLOCATION_NTNODES	100
++#define YAFFS_ALLOCATION_NLINKS		100
++
++#define YAFFS_NOBJECT_BUCKETS		256
++
++#define YAFFS_OBJECT_SPACE		0x40000
++#define YAFFS_MAX_OBJECT_ID		(YAFFS_OBJECT_SPACE - 1)
++
++/* Binary data version stamps */
++#define YAFFS_SUMMARY_VERSION		1
++#define YAFFS_CHECKPOINT_VERSION	7
++
++#ifdef CONFIG_YAFFS_UNICODE
++#define YAFFS_MAX_NAME_LENGTH		127
++#define YAFFS_MAX_ALIAS_LENGTH		79
++#else
++#define YAFFS_MAX_NAME_LENGTH		255
++#define YAFFS_MAX_ALIAS_LENGTH		159
++#endif
++
++#define YAFFS_SHORT_NAME_LENGTH		15
++
++/* Some special object ids for pseudo objects */
++#define YAFFS_OBJECTID_ROOT		1
++#define YAFFS_OBJECTID_LOSTNFOUND	2
++#define YAFFS_OBJECTID_UNLINKED		3
++#define YAFFS_OBJECTID_DELETED		4
++
++/* Fake object Id for summary data */
++#define YAFFS_OBJECTID_SUMMARY		0x10
++
++/* Pseudo object ids for checkpointing */
++#define YAFFS_OBJECTID_CHECKPOINT_DATA	0x20
++#define YAFFS_SEQUENCE_CHECKPOINT_DATA	0x21
++
++#define YAFFS_MAX_SHORT_OP_CACHES	20
++
++#define YAFFS_N_TEMP_BUFFERS		6
++
++/* We limit the number attempts at sucessfully saving a chunk of data.
++ * Small-page devices have 32 pages per block; large-page devices have 64.
++ * Default to something in the order of 5 to 10 blocks worth of chunks.
++ */
++#define YAFFS_WR_ATTEMPTS		(5*64)
++
++/* Sequence numbers are used in YAFFS2 to determine block allocation order.
++ * The range is limited slightly to help distinguish bad numbers from good.
++ * This also allows us to perhaps in the future use special numbers for
++ * special purposes.
++ * EFFFFF00 allows the allocation of 8 blocks/second (~1Mbytes) for 15 years,
++ * and is a larger number than the lifetime of a 2GB device.
++ */
++#define YAFFS_LOWEST_SEQUENCE_NUMBER	0x00001000
++#define YAFFS_HIGHEST_SEQUENCE_NUMBER	0xefffff00
++
++/* Special sequence number for bad block that failed to be marked bad */
++#define YAFFS_SEQUENCE_BAD_BLOCK	0xffff0000
++
++/* ChunkCache is used for short read/write operations.*/
++struct yaffs_cache {
++	struct yaffs_obj *object;
++	int chunk_id;
++	int last_use;
++	int dirty;
++	int n_bytes;		/* Only valid if the cache is dirty */
++	int locked;		/* Can't push out or flush while locked. */
++	u8 *data;
++};
++
++/* yaffs1 tags structures in RAM
++ * NB This uses bitfield. Bitfields should not straddle a u32 boundary
++ * otherwise the structure size will get blown out.
++ */
++
++struct yaffs_tags {
++	u32 chunk_id:20;
++	u32 serial_number:2;
++	u32 n_bytes_lsb:10;
++	u32 obj_id:18;
++	u32 ecc:12;
++	u32 n_bytes_msb:2;
++};
++
++union yaffs_tags_union {
++	struct yaffs_tags as_tags;
++	u8 as_bytes[8];
++};
++
++
++/* Stuff used for extended tags in YAFFS2 */
++
++enum yaffs_ecc_result {
++	YAFFS_ECC_RESULT_UNKNOWN,
++	YAFFS_ECC_RESULT_NO_ERROR,
++	YAFFS_ECC_RESULT_FIXED,
++	YAFFS_ECC_RESULT_UNFIXED
++};
++
++enum yaffs_obj_type {
++	YAFFS_OBJECT_TYPE_UNKNOWN,
++	YAFFS_OBJECT_TYPE_FILE,
++	YAFFS_OBJECT_TYPE_SYMLINK,
++	YAFFS_OBJECT_TYPE_DIRECTORY,
++	YAFFS_OBJECT_TYPE_HARDLINK,
++	YAFFS_OBJECT_TYPE_SPECIAL
++};
++
++#define YAFFS_OBJECT_TYPE_MAX YAFFS_OBJECT_TYPE_SPECIAL
++
++struct yaffs_ext_tags {
++	unsigned chunk_used;	/*  Status of the chunk: used or unused */
++	unsigned obj_id;	/* If 0 this is not used */
++	unsigned chunk_id;	/* If 0 this is a header, else a data chunk */
++	unsigned n_bytes;	/* Only valid for data chunks */
++
++	/* The following stuff only has meaning when we read */
++	enum yaffs_ecc_result ecc_result;
++	unsigned block_bad;
++
++	/* YAFFS 1 stuff */
++	unsigned is_deleted;	/* The chunk is marked deleted */
++	unsigned serial_number;	/* Yaffs1 2-bit serial number */
++
++	/* YAFFS2 stuff */
++	unsigned seq_number;	/* The sequence number of this block */
++
++	/* Extra info if this is an object header (YAFFS2 only) */
++
++	unsigned extra_available;	/* Extra info available if not zero */
++	unsigned extra_parent_id;	/* The parent object */
++	unsigned extra_is_shrink;	/* Is it a shrink header? */
++	unsigned extra_shadows;	/* Does this shadow another object? */
++
++	enum yaffs_obj_type extra_obj_type;	/* What object type? */
++
++	loff_t extra_file_size;		/* Length if it is a file */
++	unsigned extra_equiv_id;	/* Equivalent object for a hard link */
++};
++
++/* Spare structure for YAFFS1 */
++struct yaffs_spare {
++	u8 tb0;
++	u8 tb1;
++	u8 tb2;
++	u8 tb3;
++	u8 page_status;		/* set to 0 to delete the chunk */
++	u8 block_status;
++	u8 tb4;
++	u8 tb5;
++	u8 ecc1[3];
++	u8 tb6;
++	u8 tb7;
++	u8 ecc2[3];
++};
++
++/*Special structure for passing through to mtd */
++struct yaffs_nand_spare {
++	struct yaffs_spare spare;
++	int eccres1;
++	int eccres2;
++};
++
++/* Block data in RAM */
++
++enum yaffs_block_state {
++	YAFFS_BLOCK_STATE_UNKNOWN = 0,
++
++	YAFFS_BLOCK_STATE_SCANNING,
++	/* Being scanned */
++
++	YAFFS_BLOCK_STATE_NEEDS_SCAN,
++	/* The block might have something on it (ie it is allocating or full,
++	 * perhaps empty) but it needs to be scanned to determine its true
++	 * state.
++	 * This state is only valid during scanning.
++	 * NB We tolerate empty because the pre-scanner might be incapable of
++	 * deciding
++	 * However, if this state is returned on a YAFFS2 device,
++	 * then we expect a sequence number
++	 */
++
++	YAFFS_BLOCK_STATE_EMPTY,
++	/* This block is empty */
++
++	YAFFS_BLOCK_STATE_ALLOCATING,
++	/* This block is partially allocated.
++	 * At least one page holds valid data.
++	 * This is the one currently being used for page
++	 * allocation. Should never be more than one of these.
++	 * If a block is only partially allocated at mount it is treated as
++	 * full.
++	 */
++
++	YAFFS_BLOCK_STATE_FULL,
++	/* All the pages in this block have been allocated.
++	 * If a block was only partially allocated when mounted we treat
++	 * it as fully allocated.
++	 */
++
++	YAFFS_BLOCK_STATE_DIRTY,
++	/* The block was full and now all chunks have been deleted.
++	 * Erase me, reuse me.
++	 */
++
++	YAFFS_BLOCK_STATE_CHECKPOINT,
++	/* This block is assigned to holding checkpoint data. */
++
++	YAFFS_BLOCK_STATE_COLLECTING,
++	/* This block is being garbage collected */
++
++	YAFFS_BLOCK_STATE_DEAD
++	    /* This block has failed and is not in use */
++};
++
++#define	YAFFS_NUMBER_OF_BLOCK_STATES (YAFFS_BLOCK_STATE_DEAD + 1)
++
++struct yaffs_block_info {
++
++	s32 soft_del_pages:10;	/* number of soft deleted pages */
++	s32 pages_in_use:10;	/* number of pages in use */
++	u32 block_state:4;	/* One of the above block states. */
++				/* NB use unsigned because enum is sometimes
++				 * an int */
++	u32 needs_retiring:1;	/* Data has failed on this block, */
++				/*need to get valid data off and retire*/
++	u32 skip_erased_check:1;/* Skip the erased check on this block */
++	u32 gc_prioritise:1;	/* An ECC check or blank check has failed.
++				   Block should be prioritised for GC */
++	u32 chunk_error_strikes:3;	/* How many times we've had ecc etc
++				failures on this block and tried to reuse it */
++	u32 has_summary:1;	/* The block has a summary */
++
++	u32 has_shrink_hdr:1;	/* This block has at least one shrink header */
++	u32 seq_number;		/* block sequence number for yaffs2 */
++
++};
++
++/* -------------------------- Object structure -------------------------------*/
++/* This is the object structure as stored on NAND */
++
++struct yaffs_obj_hdr {
++	enum yaffs_obj_type type;
++
++	/* Apply to everything  */
++	int parent_obj_id;
++	u16 sum_no_longer_used;	/* checksum of name. No longer used */
++	YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
++
++	/* The following apply to all object types except for hard links */
++	u32 yst_mode;		/* protection */
++
++	u32 yst_uid;
++	u32 yst_gid;
++	u32 yst_atime;
++	u32 yst_mtime;
++	u32 yst_ctime;
++
++	/* File size  applies to files only */
++	u32 file_size_low;
++
++	/* Equivalent object id applies to hard links only. */
++	int equiv_id;
++
++	/* Alias is for symlinks only. */
++	YCHAR alias[YAFFS_MAX_ALIAS_LENGTH + 1];
++
++	u32 yst_rdev;	/* stuff for block and char devices (major/min) */
++
++	u32 win_ctime[2];
++	u32 win_atime[2];
++	u32 win_mtime[2];
++
++	u32 inband_shadowed_obj_id;
++	u32 inband_is_shrink;
++
++	u32 file_size_high;
++	u32 reserved[1];
++	int shadows_obj;	/* This object header shadows the
++				specified object if > 0 */
++
++	/* is_shrink applies to object headers written when wemake a hole. */
++	u32 is_shrink;
++
++};
++
++/*--------------------------- Tnode -------------------------- */
++
++struct yaffs_tnode {
++	struct yaffs_tnode *internal[YAFFS_NTNODES_INTERNAL];
++};
++
++/*------------------------  Object -----------------------------*/
++/* An object can be one of:
++ * - a directory (no data, has children links
++ * - a regular file (data.... not prunes :->).
++ * - a symlink [symbolic link] (the alias).
++ * - a hard link
++ */
++
++struct yaffs_file_var {
++	loff_t file_size;
++	loff_t scanned_size;
++	loff_t shrink_size;
++	int top_level;
++	struct yaffs_tnode *top;
++};
++
++struct yaffs_dir_var {
++	struct list_head children;	/* list of child links */
++	struct list_head dirty;	/* Entry for list of dirty directories */
++};
++
++struct yaffs_symlink_var {
++	YCHAR *alias;
++};
++
++struct yaffs_hardlink_var {
++	struct yaffs_obj *equiv_obj;
++	u32 equiv_id;
++};
++
++union yaffs_obj_var {
++	struct yaffs_file_var file_variant;
++	struct yaffs_dir_var dir_variant;
++	struct yaffs_symlink_var symlink_variant;
++	struct yaffs_hardlink_var hardlink_variant;
++};
++
++struct yaffs_obj {
++	u8 deleted:1;		/* This should only apply to unlinked files. */
++	u8 soft_del:1;		/* it has also been soft deleted */
++	u8 unlinked:1;		/* An unlinked file.*/
++	u8 fake:1;		/* A fake object has no presence on NAND. */
++	u8 rename_allowed:1;	/* Some objects cannot be renamed. */
++	u8 unlink_allowed:1;
++	u8 dirty:1;		/* the object needs to be written to flash */
++	u8 valid:1;		/* When the file system is being loaded up, this
++				 * object might be created before the data
++				 * is available
++				 * ie. file data chunks encountered before
++				* the header.
++				 */
++	u8 lazy_loaded:1;	/* This object has been lazy loaded and
++				 * is missing some detail */
++
++	u8 defered_free:1;	/* Object is removed from NAND, but is
++				 * still in the inode cache.
++				 * Free of object is defered.
++				 * until the inode is released.
++				 */
++	u8 being_created:1;	/* This object is still being created
++				 * so skip some verification checks. */
++	u8 is_shadowed:1;	/* This object is shadowed on the way
++				 * to being renamed. */
++
++	u8 xattr_known:1;	/* We know if this has object has xattribs
++				 * or not. */
++	u8 has_xattr:1;		/* This object has xattribs.
++				 * Only valid if xattr_known. */
++
++	u8 serial;		/* serial number of chunk in NAND.*/
++	u16 sum;		/* sum of the name to speed searching */
++
++	struct yaffs_dev *my_dev;	/* The device I'm on */
++
++	struct list_head hash_link;	/* list of objects in hash bucket */
++
++	struct list_head hard_links;	/* hard linked object chain*/
++
++	/* directory structure stuff */
++	/* also used for linking up the free list */
++	struct yaffs_obj *parent;
++	struct list_head siblings;
++
++	/* Where's my object header in NAND? */
++	int hdr_chunk;
++
++	int n_data_chunks;	/* Number of data chunks for this file. */
++
++	u32 obj_id;		/* the object id value */
++
++	u32 yst_mode;
++
++	YCHAR short_name[YAFFS_SHORT_NAME_LENGTH + 1];
++
++#ifdef CONFIG_YAFFS_WINCE
++	u32 win_ctime[2];
++	u32 win_mtime[2];
++	u32 win_atime[2];
++#else
++	u32 yst_uid;
++	u32 yst_gid;
++	u32 yst_atime;
++	u32 yst_mtime;
++	u32 yst_ctime;
++#endif
++
++	u32 yst_rdev;
++
++	void *my_inode;
++
++	enum yaffs_obj_type variant_type;
++
++	union yaffs_obj_var variant;
++
++};
++
++struct yaffs_obj_bucket {
++	struct list_head list;
++	int count;
++};
++
++/* yaffs_checkpt_obj holds the definition of an object as dumped
++ * by checkpointing.
++ */
++
++struct yaffs_checkpt_obj {
++	int struct_type;
++	u32 obj_id;
++	u32 parent_id;
++	int hdr_chunk;
++	enum yaffs_obj_type variant_type:3;
++	u8 deleted:1;
++	u8 soft_del:1;
++	u8 unlinked:1;
++	u8 fake:1;
++	u8 rename_allowed:1;
++	u8 unlink_allowed:1;
++	u8 serial;
++	int n_data_chunks;
++	loff_t size_or_equiv_obj;
++};
++
++/*--------------------- Temporary buffers ----------------
++ *
++ * These are chunk-sized working buffers. Each device has a few.
++ */
++
++struct yaffs_buffer {
++	u8 *buffer;
++	int in_use;
++};
++
++/*----------------- Device ---------------------------------*/
++
++struct yaffs_param {
++	const YCHAR *name;
++
++	/*
++	 * Entry parameters set up way early. Yaffs sets up the rest.
++	 * The structure should be zeroed out before use so that unused
++	 * and default values are zero.
++	 */
++
++	int inband_tags;	/* Use unband tags */
++	u32 total_bytes_per_chunk;	/* Should be >= 512, does not need to
++					 be a power of 2 */
++	int chunks_per_block;	/* does not need to be a power of 2 */
++	int spare_bytes_per_chunk;	/* spare area size */
++	int start_block;	/* Start block we're allowed to use */
++	int end_block;		/* End block we're allowed to use */
++	int n_reserved_blocks;	/* Tuneable so that we can reduce
++				 * reserved blocks on NOR and RAM. */
++
++	int n_caches;		/* If <= 0, then short op caching is disabled,
++				 * else the number of short op caches.
++				 */
++	int cache_bypass_aligned; /* If non-zero then bypass the cache for
++				   * aligned writes.
++				   */
++
++	int use_nand_ecc;	/* Flag to decide whether or not to use
++				 * NAND driver ECC on data (yaffs1) */
++	int tags_9bytes;	/* Use 9 byte tags */
++	int no_tags_ecc;	/* Flag to decide whether or not to do ECC
++				 * on packed tags (yaffs2) */
++
++	int is_yaffs2;		/* Use yaffs2 mode on this device */
++
++	int empty_lost_n_found;	/* Auto-empty lost+found directory on mount */
++
++	int refresh_period;	/* How often to check for a block refresh */
++
++	/* Checkpoint control. Can be set before or after initialisation */
++	u8 skip_checkpt_rd;
++	u8 skip_checkpt_wr;
++
++	int enable_xattr;	/* Enable xattribs */
++
++	int max_objects;	/*
++				 * Set to limit the number of objects created.
++				 * 0 = no limit.
++				*/
++
++	/* The remove_obj_fn function must be supplied by OS flavours that
++	 * need it.
++	 * yaffs direct uses it to implement the faster readdir.
++	 * Linux uses it to protect the directory during unlocking.
++	 */
++	void (*remove_obj_fn) (struct yaffs_obj *obj);
++
++	/* Callback to mark the superblock dirty */
++	void (*sb_dirty_fn) (struct yaffs_dev *dev);
++
++	/*  Callback to control garbage collection. */
++	unsigned (*gc_control_fn) (struct yaffs_dev *dev);
++
++	/* Debug control flags. Don't use unless you know what you're doing */
++	int use_header_file_size;	/* Flag to determine if we should use
++					 * file sizes from the header */
++	int disable_lazy_load;	/* Disable lazy loading on this device */
++	int wide_tnodes_disabled;	/* Set to disable wide tnodes */
++	int disable_soft_del;	/* yaffs 1 only: Set to disable the use of
++				 * softdeletion. */
++
++	int defered_dir_update;	/* Set to defer directory updates */
++
++#ifdef CONFIG_YAFFS_AUTO_UNICODE
++	int auto_unicode;
++#endif
++	int always_check_erased;	/* Force chunk erased check always on */
++
++	int disable_summary;
++	int disable_bad_block_marking;
++
++};
++
++struct yaffs_driver {
++	int (*drv_write_chunk_fn) (struct yaffs_dev *dev, int nand_chunk,
++				   const u8 *data, int data_len,
++				   const u8 *oob, int oob_len);
++	int (*drv_read_chunk_fn) (struct yaffs_dev *dev, int nand_chunk,
++				   u8 *data, int data_len,
++				   u8 *oob, int oob_len,
++				   enum yaffs_ecc_result *ecc_result);
++	int (*drv_erase_fn) (struct yaffs_dev *dev, int block_no);
++	int (*drv_mark_bad_fn) (struct yaffs_dev *dev, int block_no);
++	int (*drv_check_bad_fn) (struct yaffs_dev *dev, int block_no);
++	int (*drv_initialise_fn) (struct yaffs_dev *dev);
++	int (*drv_deinitialise_fn) (struct yaffs_dev *dev);
++};
++
++struct yaffs_tags_handler {
++	int (*write_chunk_tags_fn) (struct yaffs_dev *dev,
++				    int nand_chunk, const u8 *data,
++				    const struct yaffs_ext_tags *tags);
++	int (*read_chunk_tags_fn) (struct yaffs_dev *dev,
++				   int nand_chunk, u8 *data,
++				   struct yaffs_ext_tags *tags);
++
++	int (*query_block_fn) (struct yaffs_dev *dev, int block_no,
++			       enum yaffs_block_state *state,
++			       u32 *seq_number);
++	int (*mark_bad_fn) (struct yaffs_dev *dev, int block_no);
++};
++
++struct yaffs_dev {
++	struct yaffs_param param;
++	struct yaffs_driver drv;
++	struct yaffs_tags_handler tagger;
++
++	/* Context storage. Holds extra OS specific data for this device */
++
++	void *os_context;
++	void *driver_context;
++
++	struct list_head dev_list;
++
++	int ll_init;
++	/* Runtime parameters. Set up by YAFFS. */
++	int data_bytes_per_chunk;
++
++	/* Non-wide tnode stuff */
++	u16 chunk_grp_bits;	/* Number of bits that need to be resolved if
++				 * the tnodes are not wide enough.
++				 */
++	u16 chunk_grp_size;	/* == 2^^chunk_grp_bits */
++
++	/* Stuff to support wide tnodes */
++	u32 tnode_width;
++	u32 tnode_mask;
++	u32 tnode_size;
++
++	/* Stuff for figuring out file offset to chunk conversions */
++	u32 chunk_shift;	/* Shift value */
++	u32 chunk_div;		/* Divisor after shifting: 1 for 2^n sizes */
++	u32 chunk_mask;		/* Mask to use for power-of-2 case */
++
++	int is_mounted;
++	int read_only;
++	int is_checkpointed;
++
++	/* Stuff to support block offsetting to support start block zero */
++	int internal_start_block;
++	int internal_end_block;
++	int block_offset;
++	int chunk_offset;
++
++	/* Runtime checkpointing stuff */
++	int checkpt_page_seq;	/* running sequence number of checkpt pages */
++	int checkpt_byte_count;
++	int checkpt_byte_offs;
++	u8 *checkpt_buffer;
++	int checkpt_open_write;
++	int blocks_in_checkpt;
++	int checkpt_cur_chunk;
++	int checkpt_cur_block;
++	int checkpt_next_block;
++	int *checkpt_block_list;
++	int checkpt_max_blocks;
++	u32 checkpt_sum;
++	u32 checkpt_xor;
++
++	int checkpoint_blocks_required;	/* Number of blocks needed to store
++					 * current checkpoint set */
++
++	/* Block Info */
++	struct yaffs_block_info *block_info;
++	u8 *chunk_bits;		/* bitmap of chunks in use */
++	u8 block_info_alt:1;	/* allocated using alternative alloc */
++	u8 chunk_bits_alt:1;	/* allocated using alternative alloc */
++	int chunk_bit_stride;	/* Number of bytes of chunk_bits per block.
++				 * Must be consistent with chunks_per_block.
++				 */
++
++	int n_erased_blocks;
++	int alloc_block;	/* Current block being allocated off */
++	u32 alloc_page;
++	int alloc_block_finder;	/* Used to search for next allocation block */
++
++	/* Object and Tnode memory management */
++	void *allocator;
++	int n_obj;
++	int n_tnodes;
++
++	int n_hardlinks;
++
++	struct yaffs_obj_bucket obj_bucket[YAFFS_NOBJECT_BUCKETS];
++	u32 bucket_finder;
++
++	int n_free_chunks;
++
++	/* Garbage collection control */
++	u32 *gc_cleanup_list;	/* objects to delete at the end of a GC. */
++	u32 n_clean_ups;
++
++	unsigned has_pending_prioritised_gc;	/* We think this device might
++						have pending prioritised gcs */
++	unsigned gc_disable;
++	unsigned gc_block_finder;
++	unsigned gc_dirtiest;
++	unsigned gc_pages_in_use;
++	unsigned gc_not_done;
++	unsigned gc_block;
++	unsigned gc_chunk;
++	unsigned gc_skip;
++	struct yaffs_summary_tags *gc_sum_tags;
++
++	/* Special directories */
++	struct yaffs_obj *root_dir;
++	struct yaffs_obj *lost_n_found;
++
++	int buffered_block;	/* Which block is buffered here? */
++	int doing_buffered_block_rewrite;
++
++	struct yaffs_cache *cache;
++	int cache_last_use;
++
++	/* Stuff for background deletion and unlinked files. */
++	struct yaffs_obj *unlinked_dir;	/* Directory where unlinked and deleted
++					 files live. */
++	struct yaffs_obj *del_dir;	/* Directory where deleted objects are
++					sent to disappear. */
++	struct yaffs_obj *unlinked_deletion;	/* Current file being
++							background deleted. */
++	int n_deleted_files;	/* Count of files awaiting deletion; */
++	int n_unlinked_files;	/* Count of unlinked files. */
++	int n_bg_deletions;	/* Count of background deletions. */
++
++	/* Temporary buffer management */
++	struct yaffs_buffer temp_buffer[YAFFS_N_TEMP_BUFFERS];
++	int max_temp;
++	int temp_in_use;
++	int unmanaged_buffer_allocs;
++	int unmanaged_buffer_deallocs;
++
++	/* yaffs2 runtime stuff */
++	unsigned seq_number;	/* Sequence number of currently
++					allocating block */
++	unsigned oldest_dirty_seq;
++	unsigned oldest_dirty_block;
++
++	/* Block refreshing */
++	int refresh_skip;	/* A skip down counter.
++				 * Refresh happens when this gets to zero. */
++
++	/* Dirty directory handling */
++	struct list_head dirty_dirs;	/* List of dirty directories */
++
++	/* Summary */
++	int chunks_per_summary;
++	struct yaffs_summary_tags *sum_tags;
++
++	/* Statistics */
++	u32 n_page_writes;
++	u32 n_page_reads;
++	u32 n_erasures;
++	u32 n_bad_queries;
++	u32 n_bad_markings;
++	u32 n_erase_failures;
++	u32 n_gc_copies;
++	u32 all_gcs;
++	u32 passive_gc_count;
++	u32 oldest_dirty_gc_count;
++	u32 n_gc_blocks;
++	u32 bg_gcs;
++	u32 n_retried_writes;
++	u32 n_retired_blocks;
++	u32 n_ecc_fixed;
++	u32 n_ecc_unfixed;
++	u32 n_tags_ecc_fixed;
++	u32 n_tags_ecc_unfixed;
++	u32 n_deletions;
++	u32 n_unmarked_deletions;
++	u32 refresh_count;
++	u32 cache_hits;
++	u32 tags_used;
++	u32 summary_used;
++
++};
++
++/* The CheckpointDevice structure holds the device information that changes
++ *at runtime and must be preserved over unmount/mount cycles.
++ */
++struct yaffs_checkpt_dev {
++	int struct_type;
++	int n_erased_blocks;
++	int alloc_block;	/* Current block being allocated off */
++	u32 alloc_page;
++	int n_free_chunks;
++
++	int n_deleted_files;	/* Count of files awaiting deletion; */
++	int n_unlinked_files;	/* Count of unlinked files. */
++	int n_bg_deletions;	/* Count of background deletions. */
++
++	/* yaffs2 runtime stuff */
++	unsigned seq_number;	/* Sequence number of currently
++				 * allocating block */
++
++};
++
++struct yaffs_checkpt_validity {
++	int struct_type;
++	u32 magic;
++	u32 version;
++	u32 head;
++};
++
++struct yaffs_shadow_fixer {
++	int obj_id;
++	int shadowed_id;
++	struct yaffs_shadow_fixer *next;
++};
++
++/* Structure for doing xattr modifications */
++struct yaffs_xattr_mod {
++	int set;		/* If 0 then this is a deletion */
++	const YCHAR *name;
++	const void *data;
++	int size;
++	int flags;
++	int result;
++};
++
++/*----------------------- YAFFS Functions -----------------------*/
++
++int yaffs_guts_initialise(struct yaffs_dev *dev);
++void yaffs_deinitialise(struct yaffs_dev *dev);
++
++int yaffs_get_n_free_chunks(struct yaffs_dev *dev);
++
++int yaffs_rename_obj(struct yaffs_obj *old_dir, const YCHAR * old_name,
++		     struct yaffs_obj *new_dir, const YCHAR * new_name);
++
++int yaffs_unlinker(struct yaffs_obj *dir, const YCHAR * name);
++int yaffs_del_obj(struct yaffs_obj *obj);
++struct yaffs_obj *yaffs_retype_obj(struct yaffs_obj *obj,
++				   enum yaffs_obj_type type);
++
++
++int yaffs_get_obj_name(struct yaffs_obj *obj, YCHAR * name, int buffer_size);
++loff_t yaffs_get_obj_length(struct yaffs_obj *obj);
++int yaffs_get_obj_inode(struct yaffs_obj *obj);
++unsigned yaffs_get_obj_type(struct yaffs_obj *obj);
++int yaffs_get_obj_link_count(struct yaffs_obj *obj);
++
++/* File operations */
++int yaffs_file_rd(struct yaffs_obj *obj, u8 * buffer, loff_t offset,
++		  int n_bytes);
++int yaffs_wr_file(struct yaffs_obj *obj, const u8 * buffer, loff_t offset,
++		  int n_bytes, int write_trhrough);
++int yaffs_resize_file(struct yaffs_obj *obj, loff_t new_size);
++
++struct yaffs_obj *yaffs_create_file(struct yaffs_obj *parent,
++				    const YCHAR *name, u32 mode, u32 uid,
++				    u32 gid);
++
++int yaffs_flush_file(struct yaffs_obj *in,
++		     int update_time,
++		     int data_sync,
++		     int discard_cache);
++
++/* Flushing and checkpointing */
++void yaffs_flush_whole_cache(struct yaffs_dev *dev, int discard);
++
++int yaffs_checkpoint_save(struct yaffs_dev *dev);
++int yaffs_checkpoint_restore(struct yaffs_dev *dev);
++
++/* Directory operations */
++struct yaffs_obj *yaffs_create_dir(struct yaffs_obj *parent, const YCHAR *name,
++				   u32 mode, u32 uid, u32 gid);
++struct yaffs_obj *yaffs_find_by_name(struct yaffs_obj *the_dir,
++				     const YCHAR *name);
++struct yaffs_obj *yaffs_find_by_number(struct yaffs_dev *dev, u32 number);
++
++/* Link operations */
++struct yaffs_obj *yaffs_link_obj(struct yaffs_obj *parent, const YCHAR *name,
++				 struct yaffs_obj *equiv_obj);
++
++struct yaffs_obj *yaffs_get_equivalent_obj(struct yaffs_obj *obj);
++
++/* Symlink operations */
++struct yaffs_obj *yaffs_create_symlink(struct yaffs_obj *parent,
++				       const YCHAR *name, u32 mode, u32 uid,
++				       u32 gid, const YCHAR *alias);
++YCHAR *yaffs_get_symlink_alias(struct yaffs_obj *obj);
++
++/* Special inodes (fifos, sockets and devices) */
++struct yaffs_obj *yaffs_create_special(struct yaffs_obj *parent,
++				       const YCHAR *name, u32 mode, u32 uid,
++				       u32 gid, u32 rdev);
++
++int yaffs_set_xattrib(struct yaffs_obj *obj, const YCHAR *name,
++		      const void *value, int size, int flags);
++int yaffs_get_xattrib(struct yaffs_obj *obj, const YCHAR *name, void *value,
++		      int size);
++int yaffs_list_xattrib(struct yaffs_obj *obj, char *buffer, int size);
++int yaffs_remove_xattrib(struct yaffs_obj *obj, const YCHAR *name);
++
++/* Special directories */
++struct yaffs_obj *yaffs_root(struct yaffs_dev *dev);
++struct yaffs_obj *yaffs_lost_n_found(struct yaffs_dev *dev);
++
++void yaffs_handle_defered_free(struct yaffs_obj *obj);
++
++void yaffs_update_dirty_dirs(struct yaffs_dev *dev);
++
++int yaffs_bg_gc(struct yaffs_dev *dev, unsigned urgency);
++
++/* Debug dump  */
++int yaffs_dump_obj(struct yaffs_obj *obj);
++
++void yaffs_guts_test(struct yaffs_dev *dev);
++int yaffs_guts_ll_init(struct yaffs_dev *dev);
++
++
++/* A few useful functions to be used within the core files*/
++void yaffs_chunk_del(struct yaffs_dev *dev, int chunk_id, int mark_flash,
++		     int lyn);
++int yaffs_check_ff(u8 *buffer, int n_bytes);
++void yaffs_handle_chunk_error(struct yaffs_dev *dev,
++			      struct yaffs_block_info *bi);
++
++u8 *yaffs_get_temp_buffer(struct yaffs_dev *dev);
++void yaffs_release_temp_buffer(struct yaffs_dev *dev, u8 *buffer);
++
++struct yaffs_obj *yaffs_find_or_create_by_number(struct yaffs_dev *dev,
++						 int number,
++						 enum yaffs_obj_type type);
++int yaffs_put_chunk_in_file(struct yaffs_obj *in, int inode_chunk,
++			    int nand_chunk, int in_scan);
++void yaffs_set_obj_name(struct yaffs_obj *obj, const YCHAR *name);
++void yaffs_set_obj_name_from_oh(struct yaffs_obj *obj,
++				const struct yaffs_obj_hdr *oh);
++void yaffs_add_obj_to_dir(struct yaffs_obj *directory, struct yaffs_obj *obj);
++YCHAR *yaffs_clone_str(const YCHAR *str);
++void yaffs_link_fixup(struct yaffs_dev *dev, struct list_head *hard_list);
++void yaffs_block_became_dirty(struct yaffs_dev *dev, int block_no);
++int yaffs_update_oh(struct yaffs_obj *in, const YCHAR *name,
++		    int force, int is_shrink, int shadows,
++		    struct yaffs_xattr_mod *xop);
++void yaffs_handle_shadowed_obj(struct yaffs_dev *dev, int obj_id,
++			       int backward_scanning);
++int yaffs_check_alloc_available(struct yaffs_dev *dev, int n_chunks);
++struct yaffs_tnode *yaffs_get_tnode(struct yaffs_dev *dev);
++struct yaffs_tnode *yaffs_add_find_tnode_0(struct yaffs_dev *dev,
++					   struct yaffs_file_var *file_struct,
++					   u32 chunk_id,
++					   struct yaffs_tnode *passed_tn);
++
++int yaffs_do_file_wr(struct yaffs_obj *in, const u8 *buffer, loff_t offset,
++		     int n_bytes, int write_trhrough);
++void yaffs_resize_file_down(struct yaffs_obj *obj, loff_t new_size);
++void yaffs_skip_rest_of_block(struct yaffs_dev *dev);
++
++int yaffs_count_free_chunks(struct yaffs_dev *dev);
++
++struct yaffs_tnode *yaffs_find_tnode_0(struct yaffs_dev *dev,
++				       struct yaffs_file_var *file_struct,
++				       u32 chunk_id);
++
++u32 yaffs_get_group_base(struct yaffs_dev *dev, struct yaffs_tnode *tn,
++			 unsigned pos);
++
++int yaffs_is_non_empty_dir(struct yaffs_obj *obj);
++
++int yaffs_guts_format_dev(struct yaffs_dev *dev);
++
++void yaffs_addr_to_chunk(struct yaffs_dev *dev, loff_t addr,
++				int *chunk_out, u32 *offset_out);
++/*
++ * Marshalling functions to get loff_t file sizes into aand out of
++ * object headers.
++ */
++void yaffs_oh_size_load(struct yaffs_obj_hdr *oh, loff_t fsize);
++loff_t yaffs_oh_to_size(struct yaffs_obj_hdr *oh);
++loff_t yaffs_max_file_size(struct yaffs_dev *dev);
++
++/*
++ * Debug function to count number of blocks in each state
++ * NB Needs to be called with correct number of integers
++ */
++
++void yaffs_count_blocks_by_state(struct yaffs_dev *dev, int bs[10]);
++
++int yaffs_find_chunk_in_file(struct yaffs_obj *in, int inode_chunk,
++				    struct yaffs_ext_tags *tags);
++
++#endif
+diff --git a/fs/yaffs2/yaffs_linux.h b/fs/yaffs2/yaffs_linux.h
+new file mode 100644
+index 0000000..c20ab14
+--- /dev/null
++++ b/fs/yaffs2/yaffs_linux.h
+@@ -0,0 +1,48 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ *   for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_LINUX_H__
++#define __YAFFS_LINUX_H__
++
++#include "yportenv.h"
++
++struct yaffs_linux_context {
++	struct list_head context_list;	/* List of these we have mounted */
++	struct yaffs_dev *dev;
++	struct super_block *super;
++	struct task_struct *bg_thread;	/* Background thread for this device */
++	int bg_running;
++	struct mutex gross_lock;	/* Gross locking mutex*/
++	u8 *spare_buffer;	/* For mtdif2 use. Don't know the buffer size
++				 * at compile time so we have to allocate it.
++				 */
++	struct list_head search_contexts;
++	struct task_struct *readdir_process;
++	unsigned mount_id;
++	int dirty;
++};
++
++#define yaffs_dev_to_lc(dev) ((struct yaffs_linux_context *)((dev)->os_context))
++#define yaffs_dev_to_mtd(dev) ((struct mtd_info *)((dev)->driver_context))
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
++#define WRITE_SIZE_STR "writesize"
++#define WRITE_SIZE(mtd) ((mtd)->writesize)
++#else
++#define WRITE_SIZE_STR "oobblock"
++#define WRITE_SIZE(mtd) ((mtd)->oobblock)
++#endif
++
++#endif
+diff --git a/fs/yaffs2/yaffs_mtdif.c b/fs/yaffs2/yaffs_mtdif.c
+new file mode 100644
+index 0000000..1858b4f
+--- /dev/null
++++ b/fs/yaffs2/yaffs_mtdif.c
+@@ -0,0 +1,310 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ *   for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * 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 "yportenv.h"
++
++#include "yaffs_mtdif.h"
++
++#include "linux/mtd/mtd.h"
++#include "linux/types.h"
++#include "linux/time.h"
++#include "linux/mtd/nand.h"
++#include "linux/kernel.h"
++#include "linux/version.h"
++#include "linux/types.h"
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
++#include "uapi/linux/major.h"
++#endif
++
++#include "yaffs_trace.h"
++#include "yaffs_guts.h"
++#include "yaffs_linux.h"
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
++#define MTD_OPS_AUTO_OOB MTD_OOB_AUTO
++#endif
++
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0))
++#define mtd_erase(m, ei) (m)->erase(m, ei)
++#define mtd_write_oob(m, addr, pops) (m)->write_oob(m, addr, pops)
++#define mtd_read_oob(m, addr, pops) (m)->read_oob(m, addr, pops)
++#define mtd_block_isbad(m, offs) (m)->block_isbad(m, offs)
++#define mtd_block_markbad(m, offs) (m)->block_markbad(m, offs)
++#endif
++
++
++
++int nandmtd_erase_block(struct yaffs_dev *dev, int block_no)
++{
++	struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
++	u32 addr =
++	    ((loff_t) block_no) * dev->param.total_bytes_per_chunk *
++	    dev->param.chunks_per_block;
++	struct erase_info ei;
++	int retval = 0;
++
++	ei.mtd = mtd;
++	ei.addr = addr;
++	ei.len = dev->param.total_bytes_per_chunk * dev->param.chunks_per_block;
++	ei.time = 1000;
++	ei.retries = 2;
++	ei.callback = NULL;
++	ei.priv = (u_long) dev;
++
++	retval = mtd_erase(mtd, &ei);
++
++	if (retval == 0)
++		return YAFFS_OK;
++
++	return YAFFS_FAIL;
++}
++
++
++static	int yaffs_mtd_write(struct yaffs_dev *dev, int nand_chunk,
++				   const u8 *data, int data_len,
++				   const u8 *oob, int oob_len)
++{
++	struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
++	loff_t addr;
++	struct mtd_oob_ops ops;
++	int retval;
++
++	yaffs_trace(YAFFS_TRACE_MTD,
++			"yaffs_mtd_write(%p, %d, %p, %d, %p, %d)\n",
++			dev, nand_chunk, data, data_len, oob, oob_len);
++
++	if (!data || !data_len) {
++		data = NULL;
++		data_len = 0;
++	}
++
++	if (!oob || !oob_len) {
++		oob = NULL;
++		oob_len = 0;
++	}
++
++	addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
++	memset(&ops, 0, sizeof(ops));
++	ops.mode = MTD_OPS_AUTO_OOB;
++	ops.len = (data) ? data_len : 0;
++	ops.ooblen = oob_len;
++	ops.datbuf = (u8 *)data;
++	ops.oobbuf = (u8 *)oob;
++
++	retval = mtd_write_oob(mtd, addr, &ops);
++	if (retval) {
++		yaffs_trace(YAFFS_TRACE_MTD,
++			"write_oob failed, chunk %d, mtd error %d",
++			nand_chunk, retval);
++	}
++	return retval ? YAFFS_FAIL : YAFFS_OK;
++}
++
++static int yaffs_mtd_read(struct yaffs_dev *dev, int nand_chunk,
++				   u8 *data, int data_len,
++				   u8 *oob, int oob_len,
++				   enum yaffs_ecc_result *ecc_result)
++{
++	struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
++	loff_t addr;
++	struct mtd_oob_ops ops;
++	int retval;
++
++	addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
++	memset(&ops, 0, sizeof(ops));
++	ops.mode = MTD_OPS_AUTO_OOB;
++	ops.len = (data) ? data_len : 0;
++	ops.ooblen = oob_len;
++	ops.datbuf = data;
++	ops.oobbuf = oob;
++
++#if (MTD_VERSION_CODE < MTD_VERSION(2, 6, 20))
++	/* In MTD 2.6.18 to 2.6.19 nand_base.c:nand_do_read_oob() has a bug;
++	 * help it out with ops.len = ops.ooblen when ops.datbuf == NULL.
++	 */
++	ops.len = (ops.datbuf) ? ops.len : ops.ooblen;
++#endif
++	/* Read page and oob using MTD.
++	 * Check status and determine ECC result.
++	 */
++	retval = mtd_read_oob(mtd, addr, &ops);
++	if (retval)
++		yaffs_trace(YAFFS_TRACE_MTD,
++			"read_oob failed, chunk %d, mtd error %d",
++			nand_chunk, retval);
++
++	switch (retval) {
++	case 0:
++		/* no error */
++		if(ecc_result)
++			*ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
++		break;
++
++	case -EUCLEAN:
++		/* MTD's ECC fixed the data */
++		if(ecc_result)
++			*ecc_result = YAFFS_ECC_RESULT_FIXED;
++		dev->n_ecc_fixed++;
++		break;
++
++	case -EBADMSG:
++	default:
++		/* MTD's ECC could not fix the data */
++		dev->n_ecc_unfixed++;
++		if(ecc_result)
++			*ecc_result = YAFFS_ECC_RESULT_UNFIXED;
++		return YAFFS_FAIL;
++	}
++
++	return YAFFS_OK;
++}
++
++static	int yaffs_mtd_erase(struct yaffs_dev *dev, int block_no)
++{
++	struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
++
++	loff_t addr;
++	struct erase_info ei;
++	int retval = 0;
++	u32 block_size;
++
++	block_size = dev->param.total_bytes_per_chunk *
++		     dev->param.chunks_per_block;
++	addr = ((loff_t) block_no) * block_size;
++
++	ei.mtd = mtd;
++	ei.addr = addr;
++	ei.len = block_size;
++	ei.time = 1000;
++	ei.retries = 2;
++	ei.callback = NULL;
++	ei.priv = (u_long) dev;
++
++	retval = mtd_erase(mtd, &ei);
++
++	if (retval == 0)
++		return YAFFS_OK;
++
++	return YAFFS_FAIL;
++}
++
++static int yaffs_mtd_mark_bad(struct yaffs_dev *dev, int block_no)
++{
++	struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
++	int blocksize = dev->param.chunks_per_block * dev->param.total_bytes_per_chunk;
++	int retval;
++
++	yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad", block_no);
++
++	retval = mtd_block_markbad(mtd, (loff_t) blocksize * block_no);
++	return (retval) ? YAFFS_FAIL : YAFFS_OK;
++}
++
++static int yaffs_mtd_check_bad(struct yaffs_dev *dev, int block_no)
++{
++	struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
++	int blocksize = dev->param.chunks_per_block * dev->param.total_bytes_per_chunk;
++	int retval;
++
++	yaffs_trace(YAFFS_TRACE_MTD, "checking block %d bad", block_no);
++
++	retval = mtd_block_isbad(mtd, (loff_t) blocksize * block_no);
++	return (retval) ? YAFFS_FAIL : YAFFS_OK;
++}
++
++static int yaffs_mtd_initialise(struct yaffs_dev *dev)
++{
++	return YAFFS_OK;
++}
++
++static int yaffs_mtd_deinitialise(struct yaffs_dev *dev)
++{
++	return YAFFS_OK;
++}
++
++
++void yaffs_mtd_drv_install(struct yaffs_dev *dev)
++{
++	struct yaffs_driver *drv = &dev->drv;
++
++	drv->drv_write_chunk_fn = yaffs_mtd_write;
++	drv->drv_read_chunk_fn = yaffs_mtd_read;
++	drv->drv_erase_fn = yaffs_mtd_erase;
++	drv->drv_mark_bad_fn = yaffs_mtd_mark_bad;
++	drv->drv_check_bad_fn = yaffs_mtd_check_bad;
++	drv->drv_initialise_fn = yaffs_mtd_initialise;
++	drv->drv_deinitialise_fn = yaffs_mtd_deinitialise;
++}
++
++
++struct mtd_info * yaffs_get_mtd_device(dev_t sdev)
++{
++	struct mtd_info *mtd;
++
++	mtd = yaffs_get_mtd_device(sdev);
++
++	/* Check it's an mtd device..... */
++	if (MAJOR(sdev) != MTD_BLOCK_MAJOR)
++		return NULL;	/* This isn't an mtd device */
++
++	/* Check it's NAND */
++	if (mtd->type != MTD_NANDFLASH) {
++		yaffs_trace(YAFFS_TRACE_ALWAYS,
++			"yaffs: MTD device is not NAND it's type %d",
++			mtd->type);
++		return NULL;
++	}
++
++	yaffs_trace(YAFFS_TRACE_OS, " %s %d", WRITE_SIZE_STR, WRITE_SIZE(mtd));
++	yaffs_trace(YAFFS_TRACE_OS, " oobsize %d", mtd->oobsize);
++	yaffs_trace(YAFFS_TRACE_OS, " erasesize %d", mtd->erasesize);
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
++	yaffs_trace(YAFFS_TRACE_OS, " size %u", mtd->size);
++#else
++	yaffs_trace(YAFFS_TRACE_OS, " size %lld", mtd->size);
++#endif
++
++	return mtd;
++}
++
++int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags)
++{
++	if (yaffs_version == 2) {
++		if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
++		     mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) &&
++		    !inband_tags) {
++			yaffs_trace(YAFFS_TRACE_ALWAYS,
++				"MTD device does not have the right page sizes"
++			);
++			return -1;
++		}
++	} else {
++		if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK ||
++		    mtd->oobsize != YAFFS_BYTES_PER_SPARE) {
++			yaffs_trace(YAFFS_TRACE_ALWAYS,
++				"MTD device does not support have the right page sizes"
++			);
++			return -1;
++		}
++	}
++
++	return 0;
++}
++
++
++void yaffs_put_mtd_device(struct mtd_info *mtd)
++{
++	if(mtd)
++		put_mtd_device(mtd);
++}
+diff --git a/fs/yaffs2/yaffs_mtdif.h b/fs/yaffs2/yaffs_mtdif.h
+new file mode 100644
+index 0000000..9cff224
+--- /dev/null
++++ b/fs/yaffs2/yaffs_mtdif.h
+@@ -0,0 +1,25 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ *   for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_MTDIF_H__
++#define __YAFFS_MTDIF_H__
++
++#include "yaffs_guts.h"
++
++void yaffs_mtd_drv_install(struct yaffs_dev *dev);
++struct mtd_info * yaffs_get_mtd_device(dev_t sdev);
++void yaffs_put_mtd_device(struct mtd_info *mtd);
++int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags);
++#endif
+diff --git a/fs/yaffs2/yaffs_nameval.c b/fs/yaffs2/yaffs_nameval.c
+new file mode 100644
+index 0000000..4bdf4ed
+--- /dev/null
++++ b/fs/yaffs2/yaffs_nameval.c
+@@ -0,0 +1,208 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ *   for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++/*
++ * This simple implementation of a name-value store assumes a small number of
++* values and fits into a small finite buffer.
++ *
++ * Each attribute is stored as a record:
++ *  sizeof(int) bytes   record size.
++ *  strnlen+1 bytes name null terminated.
++ *  nbytes    value.
++ *  ----------
++ *  total size  stored in record size
++ *
++ * This code has not been tested with unicode yet.
++ */
++
++#include "yaffs_nameval.h"
++
++#include "yportenv.h"
++
++static int nval_find(const char *xb, int xb_size, const YCHAR *name,
++		     int *exist_size)
++{
++	int pos = 0;
++	int size;
++
++	memcpy(&size, xb, sizeof(int));
++	while (size > 0 && (size < xb_size) && (pos + size < xb_size)) {
++		if (!strncmp((YCHAR *) (xb + pos + sizeof(int)),
++				name, size)) {
++			if (exist_size)
++				*exist_size = size;
++			return pos;
++		}
++		pos += size;
++		if (pos < xb_size - sizeof(int))
++			memcpy(&size, xb + pos, sizeof(int));
++		else
++			size = 0;
++	}
++	if (exist_size)
++		*exist_size = 0;
++	return -ENODATA;
++}
++
++static int nval_used(const char *xb, int xb_size)
++{
++	int pos = 0;
++	int size;
++
++	memcpy(&size, xb + pos, sizeof(int));
++	while (size > 0 && (size < xb_size) && (pos + size < xb_size)) {
++		pos += size;
++		if (pos < xb_size - sizeof(int))
++			memcpy(&size, xb + pos, sizeof(int));
++		else
++			size = 0;
++	}
++	return pos;
++}
++
++int nval_del(char *xb, int xb_size, const YCHAR *name)
++{
++	int pos = nval_find(xb, xb_size, name, NULL);
++	int size;
++
++	if (pos < 0 || pos >= xb_size)
++		return -ENODATA;
++
++	/* Find size, shift rest over this record,
++	 * then zero out the rest of buffer */
++	memcpy(&size, xb + pos, sizeof(int));
++	memcpy(xb + pos, xb + pos + size, xb_size - (pos + size));
++	memset(xb + (xb_size - size), 0, size);
++	return 0;
++}
++
++int nval_set(char *xb, int xb_size, const YCHAR *name, const char *buf,
++		int bsize, int flags)
++{
++	int pos;
++	int namelen = strnlen(name, xb_size);
++	int reclen;
++	int size_exist = 0;
++	int space;
++	int start;
++
++	pos = nval_find(xb, xb_size, name, &size_exist);
++
++	if (flags & XATTR_CREATE && pos >= 0)
++		return -EEXIST;
++	if (flags & XATTR_REPLACE && pos < 0)
++		return -ENODATA;
++
++	start = nval_used(xb, xb_size);
++	space = xb_size - start + size_exist;
++
++	reclen = (sizeof(int) + namelen + 1 + bsize);
++
++	if (reclen > space)
++		return -ENOSPC;
++
++	if (pos >= 0) {
++		nval_del(xb, xb_size, name);
++		start = nval_used(xb, xb_size);
++	}
++
++	pos = start;
++
++	memcpy(xb + pos, &reclen, sizeof(int));
++	pos += sizeof(int);
++	strncpy((YCHAR *) (xb + pos), name, reclen);
++	pos += (namelen + 1);
++	memcpy(xb + pos, buf, bsize);
++	return 0;
++}
++
++int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf,
++	     int bsize)
++{
++	int pos = nval_find(xb, xb_size, name, NULL);
++	int size;
++
++	if (pos >= 0 && pos < xb_size) {
++
++		memcpy(&size, xb + pos, sizeof(int));
++		pos += sizeof(int);	/* advance past record length */
++		size -= sizeof(int);
++
++		/* Advance over name string */
++		while (xb[pos] && size > 0 && pos < xb_size) {
++			pos++;
++			size--;
++		}
++		/*Advance over NUL */
++		pos++;
++		size--;
++
++		/* If bsize is zero then this is a size query.
++		 * Return the size, but don't copy.
++		 */
++		if (!bsize)
++			return size;
++
++		if (size <= bsize) {
++			memcpy(buf, xb + pos, size);
++			return size;
++		}
++	}
++	if (pos >= 0)
++		return -ERANGE;
++
++	return -ENODATA;
++}
++
++int nval_list(const char *xb, int xb_size, char *buf, int bsize)
++{
++	int pos = 0;
++	int size;
++	int name_len;
++	int ncopied = 0;
++	int filled = 0;
++
++	memcpy(&size, xb + pos, sizeof(int));
++	while (size > sizeof(int) &&
++		size <= xb_size &&
++		(pos + size) < xb_size &&
++		!filled) {
++		pos += sizeof(int);
++		size -= sizeof(int);
++		name_len = strnlen((YCHAR *) (xb + pos), size);
++		if (ncopied + name_len + 1 < bsize) {
++			memcpy(buf, xb + pos, name_len * sizeof(YCHAR));
++			buf += name_len;
++			*buf = '\0';
++			buf++;
++			if (sizeof(YCHAR) > 1) {
++				*buf = '\0';
++				buf++;
++			}
++			ncopied += (name_len + 1);
++		} else {
++			filled = 1;
++		}
++		pos += size;
++		if (pos < xb_size - sizeof(int))
++			memcpy(&size, xb + pos, sizeof(int));
++		else
++			size = 0;
++	}
++	return ncopied;
++}
++
++int nval_hasvalues(const char *xb, int xb_size)
++{
++	return nval_used(xb, xb_size) > 0;
++}
+diff --git a/fs/yaffs2/yaffs_nameval.h b/fs/yaffs2/yaffs_nameval.h
+new file mode 100644
+index 0000000..951e64f
+--- /dev/null
++++ b/fs/yaffs2/yaffs_nameval.h
+@@ -0,0 +1,28 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ *   for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __NAMEVAL_H__
++#define __NAMEVAL_H__
++
++#include "yportenv.h"
++
++int nval_del(char *xb, int xb_size, const YCHAR * name);
++int nval_set(char *xb, int xb_size, const YCHAR * name, const char *buf,
++	     int bsize, int flags);
++int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf,
++	     int bsize);
++int nval_list(const char *xb, int xb_size, char *buf, int bsize);
++int nval_hasvalues(const char *xb, int xb_size);
++#endif
+diff --git a/fs/yaffs2/yaffs_nand.c b/fs/yaffs2/yaffs_nand.c
+new file mode 100644
+index 0000000..0d8499b
+--- /dev/null
++++ b/fs/yaffs2/yaffs_nand.c
+@@ -0,0 +1,122 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ *   for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * 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 "yaffs_nand.h"
++#include "yaffs_tagscompat.h"
++
++#include "yaffs_getblockinfo.h"
++#include "yaffs_summary.h"
++
++static int apply_chunk_offset(struct yaffs_dev *dev, int chunk)
++{
++	return chunk - dev->chunk_offset;
++}
++
++int yaffs_rd_chunk_tags_nand(struct yaffs_dev *dev, int nand_chunk,
++			     u8 *buffer, struct yaffs_ext_tags *tags)
++{
++	int result;
++	struct yaffs_ext_tags local_tags;
++	int flash_chunk = apply_chunk_offset(dev, nand_chunk);
++
++	dev->n_page_reads++;
++
++	/* If there are no tags provided use local tags. */
++	if (!tags)
++		tags = &local_tags;
++
++	result = dev->tagger.read_chunk_tags_fn(dev, flash_chunk, buffer, tags);
++	if (tags && tags->ecc_result > YAFFS_ECC_RESULT_NO_ERROR) {
++
++		struct yaffs_block_info *bi;
++		bi = yaffs_get_block_info(dev,
++					  nand_chunk /
++					  dev->param.chunks_per_block);
++		yaffs_handle_chunk_error(dev, bi);
++	}
++	return result;
++}
++
++int yaffs_wr_chunk_tags_nand(struct yaffs_dev *dev,
++				int nand_chunk,
++				const u8 *buffer, struct yaffs_ext_tags *tags)
++{
++	int result;
++	int flash_chunk = apply_chunk_offset(dev, nand_chunk);
++
++	dev->n_page_writes++;
++
++	if (!tags) {
++		yaffs_trace(YAFFS_TRACE_ERROR, "Writing with no tags");
++		BUG();
++		return YAFFS_FAIL;
++	}
++
++	tags->seq_number = dev->seq_number;
++	tags->chunk_used = 1;
++	yaffs_trace(YAFFS_TRACE_WRITE,
++		"Writing chunk %d tags %d %d",
++		nand_chunk, tags->obj_id, tags->chunk_id);
++
++	result = dev->tagger.write_chunk_tags_fn(dev, flash_chunk,
++							buffer, tags);
++
++	yaffs_summary_add(dev, tags, nand_chunk);
++
++	return result;
++}
++
++int yaffs_mark_bad(struct yaffs_dev *dev, int block_no)
++{
++	block_no -= dev->block_offset;
++	dev->n_bad_markings++;
++
++	if (dev->param.disable_bad_block_marking)
++		return YAFFS_OK;
++
++	return dev->tagger.mark_bad_fn(dev, block_no);
++}
++
++
++int yaffs_query_init_block_state(struct yaffs_dev *dev,
++				 int block_no,
++				 enum yaffs_block_state *state,
++				 u32 *seq_number)
++{
++	block_no -= dev->block_offset;
++	return dev->tagger.query_block_fn(dev, block_no, state, seq_number);
++}
++
++int yaffs_erase_block(struct yaffs_dev *dev, int block_no)
++{
++	int result;
++
++	block_no -= dev->block_offset;
++	dev->n_erasures++;
++	result = dev->drv.drv_erase_fn(dev, block_no);
++	return result;
++}
++
++int yaffs_init_nand(struct yaffs_dev *dev)
++{
++	if (dev->drv.drv_initialise_fn)
++		return dev->drv.drv_initialise_fn(dev);
++	return YAFFS_OK;
++}
++
++int yaffs_deinit_nand(struct yaffs_dev *dev)
++{
++	if (dev->drv.drv_deinitialise_fn)
++		return dev->drv.drv_deinitialise_fn(dev);
++	return YAFFS_OK;
++}
+diff --git a/fs/yaffs2/yaffs_nand.h b/fs/yaffs2/yaffs_nand.h
+new file mode 100644
+index 0000000..804e97a
+--- /dev/null
++++ b/fs/yaffs2/yaffs_nand.h
+@@ -0,0 +1,39 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ *   for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_NAND_H__
++#define __YAFFS_NAND_H__
++#include "yaffs_guts.h"
++
++int yaffs_rd_chunk_tags_nand(struct yaffs_dev *dev, int nand_chunk,
++			     u8 *buffer, struct yaffs_ext_tags *tags);
++
++int yaffs_wr_chunk_tags_nand(struct yaffs_dev *dev,
++			     int nand_chunk,
++			     const u8 *buffer, struct yaffs_ext_tags *tags);
++
++int yaffs_mark_bad(struct yaffs_dev *dev, int block_no);
++
++int yaffs_query_init_block_state(struct yaffs_dev *dev,
++				 int block_no,
++				 enum yaffs_block_state *state,
++				 unsigned *seq_number);
++
++int yaffs_erase_block(struct yaffs_dev *dev, int flash_block);
++
++int yaffs_init_nand(struct yaffs_dev *dev);
++int yaffs_deinit_nand(struct yaffs_dev *dev);
++
++#endif
+diff --git a/fs/yaffs2/yaffs_packedtags1.c b/fs/yaffs2/yaffs_packedtags1.c
+new file mode 100644
+index 0000000..dd9a331
+--- /dev/null
++++ b/fs/yaffs2/yaffs_packedtags1.c
+@@ -0,0 +1,56 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ *   for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * 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 "yaffs_packedtags1.h"
++#include "yportenv.h"
++
++static const u8 all_ff[20] = {
++	0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff
++};
++
++void yaffs_pack_tags1(struct yaffs_packed_tags1 *pt,
++		      const struct yaffs_ext_tags *t)
++{
++	pt->chunk_id = t->chunk_id;
++	pt->serial_number = t->serial_number;
++	pt->n_bytes = t->n_bytes;
++	pt->obj_id = t->obj_id;
++	pt->ecc = 0;
++	pt->deleted = (t->is_deleted) ? 0 : 1;
++	pt->unused_stuff = 0;
++	pt->should_be_ff = 0xffffffff;
++}
++
++void yaffs_unpack_tags1(struct yaffs_ext_tags *t,
++			const struct yaffs_packed_tags1 *pt)
++{
++
++	if (memcmp(all_ff, pt, sizeof(struct yaffs_packed_tags1))) {
++		t->block_bad = 0;
++		if (pt->should_be_ff != 0xffffffff)
++			t->block_bad = 1;
++		t->chunk_used = 1;
++		t->obj_id = pt->obj_id;
++		t->chunk_id = pt->chunk_id;
++		t->n_bytes = pt->n_bytes;
++		t->ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
++		t->is_deleted = (pt->deleted) ? 0 : 1;
++		t->serial_number = pt->serial_number;
++	} else {
++		memset(t, 0, sizeof(struct yaffs_ext_tags));
++	}
++}
+diff --git a/fs/yaffs2/yaffs_packedtags1.h b/fs/yaffs2/yaffs_packedtags1.h
+new file mode 100644
+index 0000000..3015d58
+--- /dev/null
++++ b/fs/yaffs2/yaffs_packedtags1.h
+@@ -0,0 +1,39 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ *   for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++/* This is used to pack YAFFS1 tags, not YAFFS2 tags. */
++
++#ifndef __YAFFS_PACKEDTAGS1_H__
++#define __YAFFS_PACKEDTAGS1_H__
++
++#include "yaffs_guts.h"
++
++struct yaffs_packed_tags1 {
++	u32 chunk_id:20;
++	u32 serial_number:2;
++	u32 n_bytes:10;
++	u32 obj_id:18;
++	u32 ecc:12;
++	u32 deleted:1;
++	u32 unused_stuff:1;
++	unsigned should_be_ff;
++
++};
++
++void yaffs_pack_tags1(struct yaffs_packed_tags1 *pt,
++		      const struct yaffs_ext_tags *t);
++void yaffs_unpack_tags1(struct yaffs_ext_tags *t,
++			const struct yaffs_packed_tags1 *pt);
++#endif
+diff --git a/fs/yaffs2/yaffs_packedtags2.c b/fs/yaffs2/yaffs_packedtags2.c
+new file mode 100644
+index 0000000..e1d18cc
+--- /dev/null
++++ b/fs/yaffs2/yaffs_packedtags2.c
+@@ -0,0 +1,197 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ *   for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * 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 "yaffs_packedtags2.h"
++#include "yportenv.h"
++#include "yaffs_trace.h"
++
++/* This code packs a set of extended tags into a binary structure for
++ * NAND storage
++ */
++
++/* Some of the information is "extra" struff which can be packed in to
++ * speed scanning
++ * This is defined by having the EXTRA_HEADER_INFO_FLAG set.
++ */
++
++/* Extra flags applied to chunk_id */
++
++#define EXTRA_HEADER_INFO_FLAG	0x80000000
++#define EXTRA_SHRINK_FLAG	0x40000000
++#define EXTRA_SHADOWS_FLAG	0x20000000
++#define EXTRA_SPARE_FLAGS	0x10000000
++
++#define ALL_EXTRA_FLAGS		0xf0000000
++
++/* Also, the top 4 bits of the object Id are set to the object type. */
++#define EXTRA_OBJECT_TYPE_SHIFT (28)
++#define EXTRA_OBJECT_TYPE_MASK  ((0x0f) << EXTRA_OBJECT_TYPE_SHIFT)
++
++static void yaffs_dump_packed_tags2_tags_only(
++				const struct yaffs_packed_tags2_tags_only *ptt)
++{
++	yaffs_trace(YAFFS_TRACE_MTD,
++		"packed tags obj %d chunk %d byte %d seq %d",
++		ptt->obj_id, ptt->chunk_id, ptt->n_bytes, ptt->seq_number);
++}
++
++static void yaffs_dump_packed_tags2(const struct yaffs_packed_tags2 *pt)
++{
++	yaffs_dump_packed_tags2_tags_only(&pt->t);
++}
++
++static void yaffs_dump_tags2(const struct yaffs_ext_tags *t)
++{
++	yaffs_trace(YAFFS_TRACE_MTD,
++		"ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte %d del %d ser %d seq %d",
++		t->ecc_result, t->block_bad, t->chunk_used, t->obj_id,
++		t->chunk_id, t->n_bytes, t->is_deleted, t->serial_number,
++		t->seq_number);
++
++}
++
++static int yaffs_check_tags_extra_packable(const struct yaffs_ext_tags *t)
++{
++	if (t->chunk_id != 0 || !t->extra_available)
++		return 0;
++
++	/* Check if the file size is too long to store */
++	if (t->extra_obj_type == YAFFS_OBJECT_TYPE_FILE &&
++	    (t->extra_file_size >> 31) != 0)
++		return 0;
++	return 1;
++}
++
++void yaffs_pack_tags2_tags_only(struct yaffs_packed_tags2_tags_only *ptt,
++				const struct yaffs_ext_tags *t)
++{
++	ptt->chunk_id = t->chunk_id;
++	ptt->seq_number = t->seq_number;
++	ptt->n_bytes = t->n_bytes;
++	ptt->obj_id = t->obj_id;
++
++	/* Only store extra tags for object headers.
++	 * If it is a file then only store  if the file size is short\
++	 * enough to fit.
++	 */
++	if (yaffs_check_tags_extra_packable(t)) {
++		/* Store the extra header info instead */
++		/* We save the parent object in the chunk_id */
++		ptt->chunk_id = EXTRA_HEADER_INFO_FLAG | t->extra_parent_id;
++		if (t->extra_is_shrink)
++			ptt->chunk_id |= EXTRA_SHRINK_FLAG;
++		if (t->extra_shadows)
++			ptt->chunk_id |= EXTRA_SHADOWS_FLAG;
++
++		ptt->obj_id &= ~EXTRA_OBJECT_TYPE_MASK;
++		ptt->obj_id |= (t->extra_obj_type << EXTRA_OBJECT_TYPE_SHIFT);
++
++		if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK)
++			ptt->n_bytes = t->extra_equiv_id;
++		else if (t->extra_obj_type == YAFFS_OBJECT_TYPE_FILE)
++			ptt->n_bytes = (unsigned) t->extra_file_size;
++		else
++			ptt->n_bytes = 0;
++	}
++
++	yaffs_dump_packed_tags2_tags_only(ptt);
++	yaffs_dump_tags2(t);
++}
++
++void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt,
++		      const struct yaffs_ext_tags *t, int tags_ecc)
++{
++	yaffs_pack_tags2_tags_only(&pt->t, t);
++
++	if (tags_ecc)
++		yaffs_ecc_calc_other((unsigned char *)&pt->t,
++				    sizeof(struct yaffs_packed_tags2_tags_only),
++				    &pt->ecc);
++}
++
++void yaffs_unpack_tags2_tags_only(struct yaffs_ext_tags *t,
++				  struct yaffs_packed_tags2_tags_only *ptt)
++{
++	memset(t, 0, sizeof(struct yaffs_ext_tags));
++
++	if (ptt->seq_number == 0xffffffff)
++		return;
++
++	t->block_bad = 0;
++	t->chunk_used = 1;
++	t->obj_id = ptt->obj_id;
++	t->chunk_id = ptt->chunk_id;
++	t->n_bytes = ptt->n_bytes;
++	t->is_deleted = 0;
++	t->serial_number = 0;
++	t->seq_number = ptt->seq_number;
++
++	/* Do extra header info stuff */
++	if (ptt->chunk_id & EXTRA_HEADER_INFO_FLAG) {
++		t->chunk_id = 0;
++		t->n_bytes = 0;
++
++		t->extra_available = 1;
++		t->extra_parent_id = ptt->chunk_id & (~(ALL_EXTRA_FLAGS));
++		t->extra_is_shrink = ptt->chunk_id & EXTRA_SHRINK_FLAG ? 1 : 0;
++		t->extra_shadows = ptt->chunk_id & EXTRA_SHADOWS_FLAG ? 1 : 0;
++		t->extra_obj_type = ptt->obj_id >> EXTRA_OBJECT_TYPE_SHIFT;
++		t->obj_id &= ~EXTRA_OBJECT_TYPE_MASK;
++
++		if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK)
++			t->extra_equiv_id = ptt->n_bytes;
++		else
++			t->extra_file_size = ptt->n_bytes;
++	}
++	yaffs_dump_packed_tags2_tags_only(ptt);
++	yaffs_dump_tags2(t);
++}
++
++void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt,
++			int tags_ecc)
++{
++	enum yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
++
++	if (pt->t.seq_number != 0xffffffff && tags_ecc) {
++		/* Chunk is in use and we need to do ECC */
++
++		struct yaffs_ecc_other ecc;
++		int result;
++		yaffs_ecc_calc_other((unsigned char *)&pt->t,
++				sizeof(struct yaffs_packed_tags2_tags_only),
++				&ecc);
++		result =
++		    yaffs_ecc_correct_other((unsigned char *)&pt->t,
++				sizeof(struct yaffs_packed_tags2_tags_only),
++				&pt->ecc, &ecc);
++		switch (result) {
++		case 0:
++			ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
++			break;
++		case 1:
++			ecc_result = YAFFS_ECC_RESULT_FIXED;
++			break;
++		case -1:
++			ecc_result = YAFFS_ECC_RESULT_UNFIXED;
++			break;
++		default:
++			ecc_result = YAFFS_ECC_RESULT_UNKNOWN;
++		}
++	}
++	yaffs_unpack_tags2_tags_only(t, &pt->t);
++
++	t->ecc_result = ecc_result;
++
++	yaffs_dump_packed_tags2(pt);
++	yaffs_dump_tags2(t);
++}
+diff --git a/fs/yaffs2/yaffs_packedtags2.h b/fs/yaffs2/yaffs_packedtags2.h
+new file mode 100644
+index 0000000..675e719
+--- /dev/null
++++ b/fs/yaffs2/yaffs_packedtags2.h
+@@ -0,0 +1,47 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ *   for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++/* This is used to pack YAFFS2 tags, not YAFFS1tags. */
++
++#ifndef __YAFFS_PACKEDTAGS2_H__
++#define __YAFFS_PACKEDTAGS2_H__
++
++#include "yaffs_guts.h"
++#include "yaffs_ecc.h"
++
++struct yaffs_packed_tags2_tags_only {
++	unsigned seq_number;
++	unsigned obj_id;
++	unsigned chunk_id;
++	unsigned n_bytes;
++};
++
++struct yaffs_packed_tags2 {
++	struct yaffs_packed_tags2_tags_only t;
++	struct yaffs_ecc_other ecc;
++};
++
++/* Full packed tags with ECC, used for oob tags */
++void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt,
++		      const struct yaffs_ext_tags *t, int tags_ecc);
++void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt,
++			int tags_ecc);
++
++/* Only the tags part (no ECC for use with inband tags */
++void yaffs_pack_tags2_tags_only(struct yaffs_packed_tags2_tags_only *pt,
++				const struct yaffs_ext_tags *t);
++void yaffs_unpack_tags2_tags_only(struct yaffs_ext_tags *t,
++				  struct yaffs_packed_tags2_tags_only *pt);
++#endif
+diff --git a/fs/yaffs2/yaffs_summary.c b/fs/yaffs2/yaffs_summary.c
+new file mode 100644
+index 0000000..3c9e723
+--- /dev/null
++++ b/fs/yaffs2/yaffs_summary.c
+@@ -0,0 +1,312 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ *   for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * 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.
++ */
++
++/* Summaries write the useful part of the tags for the chunks in a block into an
++ * an array which is written to the last n chunks of the block.
++ * Reading the summaries gives all the tags for the block in one read. Much
++ * faster.
++ *
++ * Chunks holding summaries are marked with tags making it look like
++ * they are part of a fake file.
++ *
++ * The summary could also be used during gc.
++ *
++ */
++
++#include "yaffs_summary.h"
++#include "yaffs_packedtags2.h"
++#include "yaffs_nand.h"
++#include "yaffs_getblockinfo.h"
++#include "yaffs_bitmap.h"
++
++/*
++ * The summary is built up in an array of summary tags.
++ * This gets written to the last one or two (maybe more) chunks in a block.
++ * A summary header is written as the first part of each chunk of summary data.
++ * The summary header must match or the summary is rejected.
++ */
++
++/* Summary tags don't need the sequence number because that is redundant. */
++struct yaffs_summary_tags {
++	unsigned obj_id;
++	unsigned chunk_id;
++	unsigned n_bytes;
++};
++
++/* Summary header */
++struct yaffs_summary_header {
++	unsigned version;	/* Must match current version */
++	unsigned block;		/* Must be this block */
++	unsigned seq;		/* Must be this sequence number */
++	unsigned sum;		/* Just add up all the bytes in the tags */
++};
++
++
++static void yaffs_summary_clear(struct yaffs_dev *dev)
++{
++	if (!dev->sum_tags)
++		return;
++	memset(dev->sum_tags, 0, dev->chunks_per_summary *
++		sizeof(struct yaffs_summary_tags));
++}
++
++
++void yaffs_summary_deinit(struct yaffs_dev *dev)
++{
++	kfree(dev->sum_tags);
++	dev->sum_tags = NULL;
++	kfree(dev->gc_sum_tags);
++	dev->gc_sum_tags = NULL;
++	dev->chunks_per_summary = 0;
++}
++
++int yaffs_summary_init(struct yaffs_dev *dev)
++{
++	int sum_bytes;
++	int chunks_used; /* Number of chunks used by summary */
++	int sum_tags_bytes;
++
++	sum_bytes = dev->param.chunks_per_block *
++			sizeof(struct yaffs_summary_tags);
++
++	chunks_used = (sum_bytes + dev->data_bytes_per_chunk - 1)/
++			(dev->data_bytes_per_chunk -
++				sizeof(struct yaffs_summary_header));
++
++	dev->chunks_per_summary = dev->param.chunks_per_block - chunks_used;
++	sum_tags_bytes = sizeof(struct yaffs_summary_tags) *
++				dev->chunks_per_summary;
++	dev->sum_tags = kmalloc(sum_tags_bytes, GFP_NOFS);
++	dev->gc_sum_tags = kmalloc(sum_tags_bytes, GFP_NOFS);
++	if (!dev->sum_tags || !dev->gc_sum_tags) {
++		yaffs_summary_deinit(dev);
++		return YAFFS_FAIL;
++	}
++
++	yaffs_summary_clear(dev);
++
++	return YAFFS_OK;
++}
++
++static unsigned yaffs_summary_sum(struct yaffs_dev *dev)
++{
++	u8 *sum_buffer = (u8 *)dev->sum_tags;
++	int i;
++	unsigned sum = 0;
++
++	i = sizeof(struct yaffs_summary_tags) *
++				dev->chunks_per_summary;
++	while (i > 0) {
++		sum += *sum_buffer;
++		sum_buffer++;
++		i--;
++	}
++
++	return sum;
++}
++
++static int yaffs_summary_write(struct yaffs_dev *dev, int blk)
++{
++	struct yaffs_ext_tags tags;
++	u8 *buffer;
++	u8 *sum_buffer = (u8 *)dev->sum_tags;
++	int n_bytes;
++	int chunk_in_nand;
++	int chunk_in_block;
++	int result;
++	int this_tx;
++	struct yaffs_summary_header hdr;
++	int sum_bytes_per_chunk = dev->data_bytes_per_chunk - sizeof(hdr);
++	struct yaffs_block_info *bi = yaffs_get_block_info(dev, blk);
++
++	buffer = yaffs_get_temp_buffer(dev);
++	n_bytes = sizeof(struct yaffs_summary_tags) *
++				dev->chunks_per_summary;
++	memset(&tags, 0, sizeof(struct yaffs_ext_tags));
++	tags.obj_id = YAFFS_OBJECTID_SUMMARY;
++	tags.chunk_id = 1;
++	chunk_in_block = dev->chunks_per_summary;
++	chunk_in_nand = dev->alloc_block * dev->param.chunks_per_block +
++						dev->chunks_per_summary;
++	hdr.version = YAFFS_SUMMARY_VERSION;
++	hdr.block = blk;
++	hdr.seq = bi->seq_number;
++	hdr.sum = yaffs_summary_sum(dev);
++
++	do {
++		this_tx = n_bytes;
++		if (this_tx > sum_bytes_per_chunk)
++			this_tx = sum_bytes_per_chunk;
++		memcpy(buffer, &hdr, sizeof(hdr));
++		memcpy(buffer + sizeof(hdr), sum_buffer, this_tx);
++		tags.n_bytes = this_tx + sizeof(hdr);
++		result = yaffs_wr_chunk_tags_nand(dev, chunk_in_nand,
++						buffer, &tags);
++
++		if (result != YAFFS_OK)
++			break;
++		yaffs_set_chunk_bit(dev, blk, chunk_in_block);
++		bi->pages_in_use++;
++		dev->n_free_chunks--;
++
++		n_bytes -= this_tx;
++		sum_buffer += this_tx;
++		chunk_in_nand++;
++		chunk_in_block++;
++		tags.chunk_id++;
++	} while (result == YAFFS_OK && n_bytes > 0);
++	yaffs_release_temp_buffer(dev, buffer);
++
++
++	if (result == YAFFS_OK)
++		bi->has_summary = 1;
++
++
++	return result;
++}
++
++int yaffs_summary_read(struct yaffs_dev *dev,
++			struct yaffs_summary_tags *st,
++			int blk)
++{
++	struct yaffs_ext_tags tags;
++	u8 *buffer;
++	u8 *sum_buffer = (u8 *)st;
++	int n_bytes;
++	int chunk_id;
++	int chunk_in_nand;
++	int chunk_in_block;
++	int result;
++	int this_tx;
++	struct yaffs_summary_header hdr;
++	struct yaffs_block_info *bi = yaffs_get_block_info(dev, blk);
++	int sum_bytes_per_chunk = dev->data_bytes_per_chunk - sizeof(hdr);
++	int sum_tags_bytes;
++
++	sum_tags_bytes = sizeof(struct yaffs_summary_tags) *
++				dev->chunks_per_summary;
++	buffer = yaffs_get_temp_buffer(dev);
++	n_bytes = sizeof(struct yaffs_summary_tags) * dev->chunks_per_summary;
++	chunk_in_block = dev->chunks_per_summary;
++	chunk_in_nand = blk * dev->param.chunks_per_block +
++							dev->chunks_per_summary;
++	chunk_id = 1;
++	do {
++		this_tx = n_bytes;
++		if (this_tx > sum_bytes_per_chunk)
++			this_tx = sum_bytes_per_chunk;
++		result = yaffs_rd_chunk_tags_nand(dev, chunk_in_nand,
++						buffer, &tags);
++
++		if (tags.chunk_id != chunk_id ||
++			tags.obj_id != YAFFS_OBJECTID_SUMMARY ||
++			tags.chunk_used == 0 ||
++			tags.ecc_result > YAFFS_ECC_RESULT_FIXED ||
++			tags.n_bytes != (this_tx + sizeof(hdr)))
++				result = YAFFS_FAIL;
++		if (result != YAFFS_OK)
++			break;
++
++		if (st == dev->sum_tags) {
++			/* If we're scanning then update the block info */
++			yaffs_set_chunk_bit(dev, blk, chunk_in_block);
++			bi->pages_in_use++;
++		}
++		memcpy(&hdr, buffer, sizeof(hdr));
++		memcpy(sum_buffer, buffer + sizeof(hdr), this_tx);
++		n_bytes -= this_tx;
++		sum_buffer += this_tx;
++		chunk_in_nand++;
++		chunk_in_block++;
++		chunk_id++;
++	} while (result == YAFFS_OK && n_bytes > 0);
++	yaffs_release_temp_buffer(dev, buffer);
++
++	if (result == YAFFS_OK) {
++		/* Verify header */
++		if (hdr.version != YAFFS_SUMMARY_VERSION ||
++		    hdr.seq != bi->seq_number ||
++		    hdr.sum != yaffs_summary_sum(dev))
++			result = YAFFS_FAIL;
++	}
++
++	if (st == dev->sum_tags && result == YAFFS_OK)
++		bi->has_summary = 1;
++
++	return result;
++}
++
++int yaffs_summary_add(struct yaffs_dev *dev,
++			struct yaffs_ext_tags *tags,
++			int chunk_in_nand)
++{
++	struct yaffs_packed_tags2_tags_only tags_only;
++	struct yaffs_summary_tags *sum_tags;
++	int block_in_nand = chunk_in_nand / dev->param.chunks_per_block;
++	int chunk_in_block = chunk_in_nand % dev->param.chunks_per_block;
++
++	if (!dev->sum_tags)
++		return YAFFS_OK;
++
++	if (chunk_in_block >= 0 && chunk_in_block < dev->chunks_per_summary) {
++		yaffs_pack_tags2_tags_only(&tags_only, tags);
++		sum_tags = &dev->sum_tags[chunk_in_block];
++		sum_tags->chunk_id = tags_only.chunk_id;
++		sum_tags->n_bytes = tags_only.n_bytes;
++		sum_tags->obj_id = tags_only.obj_id;
++
++		if (chunk_in_block == dev->chunks_per_summary - 1) {
++			/* Time to write out the summary */
++			yaffs_summary_write(dev, block_in_nand);
++			yaffs_summary_clear(dev);
++			yaffs_skip_rest_of_block(dev);
++		}
++	}
++	return YAFFS_OK;
++}
++
++int yaffs_summary_fetch(struct yaffs_dev *dev,
++			struct yaffs_ext_tags *tags,
++			int chunk_in_block)
++{
++	struct yaffs_packed_tags2_tags_only tags_only;
++	struct yaffs_summary_tags *sum_tags;
++	if (chunk_in_block >= 0 && chunk_in_block < dev->chunks_per_summary) {
++		sum_tags = &dev->sum_tags[chunk_in_block];
++		tags_only.chunk_id = sum_tags->chunk_id;
++		tags_only.n_bytes = sum_tags->n_bytes;
++		tags_only.obj_id = sum_tags->obj_id;
++		yaffs_unpack_tags2_tags_only(tags, &tags_only);
++		return YAFFS_OK;
++	}
++	return YAFFS_FAIL;
++}
++
++void yaffs_summary_gc(struct yaffs_dev *dev, int blk)
++{
++	struct yaffs_block_info *bi = yaffs_get_block_info(dev, blk);
++	int i;
++
++	if (!bi->has_summary)
++		return;
++
++	for (i = dev->chunks_per_summary;
++	     i < dev->param.chunks_per_block;
++	     i++) {
++		if (yaffs_check_chunk_bit(dev, blk, i)) {
++			yaffs_clear_chunk_bit(dev, blk, i);
++			bi->pages_in_use--;
++			dev->n_free_chunks++;
++		}
++	}
++}
+diff --git a/fs/yaffs2/yaffs_summary.h b/fs/yaffs2/yaffs_summary.h
+new file mode 100644
+index 0000000..be141d0
+--- /dev/null
++++ b/fs/yaffs2/yaffs_summary.h
+@@ -0,0 +1,37 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ *   for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_SUMMARY_H__
++#define __YAFFS_SUMMARY_H__
++
++#include "yaffs_packedtags2.h"
++
++
++int yaffs_summary_init(struct yaffs_dev *dev);
++void yaffs_summary_deinit(struct yaffs_dev *dev);
++
++int yaffs_summary_add(struct yaffs_dev *dev,
++			struct yaffs_ext_tags *tags,
++			int chunk_in_block);
++int yaffs_summary_fetch(struct yaffs_dev *dev,
++			struct yaffs_ext_tags *tags,
++			int chunk_in_block);
++int yaffs_summary_read(struct yaffs_dev *dev,
++			struct yaffs_summary_tags *st,
++			int blk);
++void yaffs_summary_gc(struct yaffs_dev *dev, int blk);
++
++
++#endif
+diff --git a/fs/yaffs2/yaffs_tagscompat.c b/fs/yaffs2/yaffs_tagscompat.c
+new file mode 100644
+index 0000000..092430b
+--- /dev/null
++++ b/fs/yaffs2/yaffs_tagscompat.c
+@@ -0,0 +1,381 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ *   for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * 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 "yaffs_guts.h"
++#include "yaffs_tagscompat.h"
++#include "yaffs_ecc.h"
++#include "yaffs_getblockinfo.h"
++#include "yaffs_trace.h"
++
++static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk);
++
++
++/********** Tags ECC calculations  *********/
++
++
++void yaffs_calc_tags_ecc(struct yaffs_tags *tags)
++{
++	/* Calculate an ecc */
++	unsigned char *b = ((union yaffs_tags_union *)tags)->as_bytes;
++	unsigned i, j;
++	unsigned ecc = 0;
++	unsigned bit = 0;
++
++	tags->ecc = 0;
++
++	for (i = 0; i < 8; i++) {
++		for (j = 1; j & 0xff; j <<= 1) {
++			bit++;
++			if (b[i] & j)
++				ecc ^= bit;
++		}
++	}
++	tags->ecc = ecc;
++}
++
++int yaffs_check_tags_ecc(struct yaffs_tags *tags)
++{
++	unsigned ecc = tags->ecc;
++
++	yaffs_calc_tags_ecc(tags);
++
++	ecc ^= tags->ecc;
++
++	if (ecc && ecc <= 64) {
++		/* TODO: Handle the failure better. Retire? */
++		unsigned char *b = ((union yaffs_tags_union *)tags)->as_bytes;
++
++		ecc--;
++
++		b[ecc / 8] ^= (1 << (ecc & 7));
++
++		/* Now recvalc the ecc */
++		yaffs_calc_tags_ecc(tags);
++
++		return 1;	/* recovered error */
++	} else if (ecc) {
++		/* Wierd ecc failure value */
++		/* TODO Need to do somethiong here */
++		return -1;	/* unrecovered error */
++	}
++	return 0;
++}
++
++/********** Tags **********/
++
++static void yaffs_load_tags_to_spare(struct yaffs_spare *spare_ptr,
++				     struct yaffs_tags *tags_ptr)
++{
++	union yaffs_tags_union *tu = (union yaffs_tags_union *)tags_ptr;
++
++	yaffs_calc_tags_ecc(tags_ptr);
++
++	spare_ptr->tb0 = tu->as_bytes[0];
++	spare_ptr->tb1 = tu->as_bytes[1];
++	spare_ptr->tb2 = tu->as_bytes[2];
++	spare_ptr->tb3 = tu->as_bytes[3];
++	spare_ptr->tb4 = tu->as_bytes[4];
++	spare_ptr->tb5 = tu->as_bytes[5];
++	spare_ptr->tb6 = tu->as_bytes[6];
++	spare_ptr->tb7 = tu->as_bytes[7];
++}
++
++static void yaffs_get_tags_from_spare(struct yaffs_dev *dev,
++				      struct yaffs_spare *spare_ptr,
++				      struct yaffs_tags *tags_ptr)
++{
++	union yaffs_tags_union *tu = (union yaffs_tags_union *)tags_ptr;
++	int result;
++
++	tu->as_bytes[0] = spare_ptr->tb0;
++	tu->as_bytes[1] = spare_ptr->tb1;
++	tu->as_bytes[2] = spare_ptr->tb2;
++	tu->as_bytes[3] = spare_ptr->tb3;
++	tu->as_bytes[4] = spare_ptr->tb4;
++	tu->as_bytes[5] = spare_ptr->tb5;
++	tu->as_bytes[6] = spare_ptr->tb6;
++	tu->as_bytes[7] = spare_ptr->tb7;
++
++	result = yaffs_check_tags_ecc(tags_ptr);
++	if (result > 0)
++		dev->n_tags_ecc_fixed++;
++	else if (result < 0)
++		dev->n_tags_ecc_unfixed++;
++}
++
++static void yaffs_spare_init(struct yaffs_spare *spare)
++{
++	memset(spare, 0xff, sizeof(struct yaffs_spare));
++}
++
++static int yaffs_wr_nand(struct yaffs_dev *dev,
++			 int nand_chunk, const u8 *data,
++			 struct yaffs_spare *spare)
++{
++	int data_size = dev->data_bytes_per_chunk;
++
++	return dev->drv.drv_write_chunk_fn(dev, nand_chunk,
++				data, data_size,
++				(u8 *) spare, sizeof(*spare));
++}
++
++static int yaffs_rd_chunk_nand(struct yaffs_dev *dev,
++			       int nand_chunk,
++			       u8 *data,
++			       struct yaffs_spare *spare,
++			       enum yaffs_ecc_result *ecc_result,
++			       int correct_errors)
++{
++	int ret_val;
++	struct yaffs_spare local_spare;
++	int data_size;
++	int spare_size;
++	int ecc_result1, ecc_result2;
++	u8 calc_ecc[3];
++
++	if (!spare) {
++		/* If we don't have a real spare, then we use a local one. */
++		/* Need this for the calculation of the ecc */
++		spare = &local_spare;
++	}
++	data_size = dev->data_bytes_per_chunk;
++	spare_size = sizeof(struct yaffs_spare);
++
++	if (dev->param.use_nand_ecc)
++		return dev->drv.drv_read_chunk_fn(dev, nand_chunk,
++						data, data_size,
++						(u8 *) spare, spare_size,
++						ecc_result);
++
++
++	/* Handle the ECC at this level. */
++
++	ret_val = dev->drv.drv_read_chunk_fn(dev, nand_chunk,
++						 data, data_size,
++						 (u8 *)spare, spare_size,
++						NULL);
++	if (!data || !correct_errors)
++		return ret_val;
++
++	/* Do ECC correction if needed. */
++	yaffs_ecc_calc(data, calc_ecc);
++	ecc_result1 = yaffs_ecc_correct(data, spare->ecc1, calc_ecc);
++	yaffs_ecc_calc(&data[256], calc_ecc);
++	ecc_result2 = yaffs_ecc_correct(&data[256], spare->ecc2, calc_ecc);
++
++	if (ecc_result1 > 0) {
++		yaffs_trace(YAFFS_TRACE_ERROR,
++			"**>>yaffs ecc error fix performed on chunk %d:0",
++			nand_chunk);
++		dev->n_ecc_fixed++;
++	} else if (ecc_result1 < 0) {
++		yaffs_trace(YAFFS_TRACE_ERROR,
++			"**>>yaffs ecc error unfixed on chunk %d:0",
++			nand_chunk);
++		dev->n_ecc_unfixed++;
++	}
++
++	if (ecc_result2 > 0) {
++		yaffs_trace(YAFFS_TRACE_ERROR,
++			"**>>yaffs ecc error fix performed on chunk %d:1",
++			nand_chunk);
++		dev->n_ecc_fixed++;
++	} else if (ecc_result2 < 0) {
++		yaffs_trace(YAFFS_TRACE_ERROR,
++			"**>>yaffs ecc error unfixed on chunk %d:1",
++			nand_chunk);
++		dev->n_ecc_unfixed++;
++	}
++
++	if (ecc_result1 || ecc_result2) {
++		/* We had a data problem on this page */
++		yaffs_handle_rd_data_error(dev, nand_chunk);
++	}
++
++	if (ecc_result1 < 0 || ecc_result2 < 0)
++		*ecc_result = YAFFS_ECC_RESULT_UNFIXED;
++	else if (ecc_result1 > 0 || ecc_result2 > 0)
++		*ecc_result = YAFFS_ECC_RESULT_FIXED;
++	else
++		*ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
++
++	return ret_val;
++}
++
++/*
++ * Functions for robustisizing
++ */
++
++static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk)
++{
++	int flash_block = nand_chunk / dev->param.chunks_per_block;
++
++	/* Mark the block for retirement */
++	yaffs_get_block_info(dev, flash_block + dev->block_offset)->
++		needs_retiring = 1;
++	yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
++		"**>>Block %d marked for retirement",
++		flash_block);
++
++	/* TODO:
++	 * Just do a garbage collection on the affected block
++	 * then retire the block
++	 * NB recursion
++	 */
++}
++
++static int yaffs_tags_compat_wr(struct yaffs_dev *dev,
++			 int nand_chunk,
++			 const u8 *data, const struct yaffs_ext_tags *ext_tags)
++{
++	struct yaffs_spare spare;
++	struct yaffs_tags tags;
++
++	yaffs_spare_init(&spare);
++
++	if (ext_tags->is_deleted)
++		spare.page_status = 0;
++	else {
++		tags.obj_id = ext_tags->obj_id;
++		tags.chunk_id = ext_tags->chunk_id;
++
++		tags.n_bytes_lsb = ext_tags->n_bytes & (1024 - 1);
++
++		if (dev->data_bytes_per_chunk >= 1024)
++			tags.n_bytes_msb = (ext_tags->n_bytes >> 10) & 3;
++		else
++			tags.n_bytes_msb = 3;
++
++		tags.serial_number = ext_tags->serial_number;
++
++		if (!dev->param.use_nand_ecc && data) {
++			yaffs_ecc_calc(data, spare.ecc1);
++			yaffs_ecc_calc(&data[256], spare.ecc2);
++		}
++
++		yaffs_load_tags_to_spare(&spare, &tags);
++	}
++	return yaffs_wr_nand(dev, nand_chunk, data, &spare);
++}
++
++static int yaffs_tags_compat_rd(struct yaffs_dev *dev,
++			 int nand_chunk,
++			 u8 *data, struct yaffs_ext_tags *ext_tags)
++{
++	struct yaffs_spare spare;
++	struct yaffs_tags tags;
++	enum yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_UNKNOWN;
++	static struct yaffs_spare spare_ff;
++	static int init;
++	int deleted;
++
++	if (!init) {
++		memset(&spare_ff, 0xff, sizeof(spare_ff));
++		init = 1;
++	}
++
++	if (!yaffs_rd_chunk_nand(dev, nand_chunk,
++					data, &spare, &ecc_result, 1))
++		return YAFFS_FAIL;
++
++	/* ext_tags may be NULL */
++	if (!ext_tags)
++		return YAFFS_OK;
++
++	deleted = (hweight8(spare.page_status) < 7) ? 1 : 0;
++
++	ext_tags->is_deleted = deleted;
++	ext_tags->ecc_result = ecc_result;
++	ext_tags->block_bad = 0;	/* We're reading it */
++	/* therefore it is not a bad block */
++	ext_tags->chunk_used =
++		memcmp(&spare_ff, &spare, sizeof(spare_ff)) ? 1 : 0;
++
++	if (ext_tags->chunk_used) {
++		yaffs_get_tags_from_spare(dev, &spare, &tags);
++		ext_tags->obj_id = tags.obj_id;
++		ext_tags->chunk_id = tags.chunk_id;
++		ext_tags->n_bytes = tags.n_bytes_lsb;
++
++		if (dev->data_bytes_per_chunk >= 1024)
++			ext_tags->n_bytes |=
++				(((unsigned)tags.n_bytes_msb) << 10);
++
++		ext_tags->serial_number = tags.serial_number;
++	}
++
++	return YAFFS_OK;
++}
++
++static int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int flash_block)
++{
++	struct yaffs_spare spare;
++
++	memset(&spare, 0xff, sizeof(struct yaffs_spare));
++
++	spare.block_status = 'Y';
++
++	yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block, NULL,
++		      &spare);
++	yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block + 1,
++		      NULL, &spare);
++
++	return YAFFS_OK;
++}
++
++static int yaffs_tags_compat_query_block(struct yaffs_dev *dev,
++				  int block_no,
++				  enum yaffs_block_state *state,
++				  u32 *seq_number)
++{
++	struct yaffs_spare spare0, spare1;
++	static struct yaffs_spare spare_ff;
++	static int init;
++	enum yaffs_ecc_result dummy;
++
++	if (!init) {
++		memset(&spare_ff, 0xff, sizeof(spare_ff));
++		init = 1;
++	}
++
++	*seq_number = 0;
++
++	/* Look for bad block markers in the first two chunks */
++	yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block,
++			    NULL, &spare0, &dummy, 0);
++	yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block + 1,
++			    NULL, &spare1, &dummy, 0);
++
++	if (hweight8(spare0.block_status & spare1.block_status) < 7)
++		*state = YAFFS_BLOCK_STATE_DEAD;
++	else if (memcmp(&spare_ff, &spare0, sizeof(spare_ff)) == 0)
++		*state = YAFFS_BLOCK_STATE_EMPTY;
++	else
++		*state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
++
++	return YAFFS_OK;
++}
++
++void yaffs_tags_compat_install(struct yaffs_dev *dev)
++{
++	if(dev->param.is_yaffs2)
++		return;
++	if(!dev->tagger.write_chunk_tags_fn)
++		dev->tagger.write_chunk_tags_fn = yaffs_tags_compat_wr;
++	if(!dev->tagger.read_chunk_tags_fn)
++		dev->tagger.read_chunk_tags_fn = yaffs_tags_compat_rd;
++	if(!dev->tagger.query_block_fn)
++		dev->tagger.query_block_fn = yaffs_tags_compat_query_block;
++	if(!dev->tagger.mark_bad_fn)
++		dev->tagger.mark_bad_fn = yaffs_tags_compat_mark_bad;
++}
+diff --git a/fs/yaffs2/yaffs_tagscompat.h b/fs/yaffs2/yaffs_tagscompat.h
+new file mode 100644
+index 0000000..92d298a
+--- /dev/null
++++ b/fs/yaffs2/yaffs_tagscompat.h
+@@ -0,0 +1,44 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ *   for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_TAGSCOMPAT_H__
++#define __YAFFS_TAGSCOMPAT_H__
++
++
++#include "yaffs_guts.h"
++
++#if 0
++
++
++int yaffs_tags_compat_wr(struct yaffs_dev *dev,
++			 int nand_chunk,
++			 const u8 *data, const struct yaffs_ext_tags *tags);
++int yaffs_tags_compat_rd(struct yaffs_dev *dev,
++			 int nand_chunk,
++			 u8 *data, struct yaffs_ext_tags *tags);
++int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int block_no);
++int yaffs_tags_compat_query_block(struct yaffs_dev *dev,
++				  int block_no,
++				  enum yaffs_block_state *state,
++				  u32 *seq_number);
++
++#endif
++
++
++void yaffs_tags_compat_install(struct yaffs_dev *dev);
++void yaffs_calc_tags_ecc(struct yaffs_tags *tags);
++int yaffs_check_tags_ecc(struct yaffs_tags *tags);
++
++#endif
+diff --git a/fs/yaffs2/yaffs_tagsmarshall.c b/fs/yaffs2/yaffs_tagsmarshall.c
+new file mode 100644
+index 0000000..44a83b1
+--- /dev/null
++++ b/fs/yaffs2/yaffs_tagsmarshall.c
+@@ -0,0 +1,199 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ *   for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * 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 "yaffs_guts.h"
++#include "yaffs_trace.h"
++#include "yaffs_packedtags2.h"
++
++static int yaffs_tags_marshall_write(struct yaffs_dev *dev,
++				    int nand_chunk, const u8 *data,
++				    const struct yaffs_ext_tags *tags)
++{
++	struct yaffs_packed_tags2 pt;
++	int retval;
++
++	int packed_tags_size =
++	    dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
++	void *packed_tags_ptr =
++	    dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt;
++
++	yaffs_trace(YAFFS_TRACE_MTD,
++		"yaffs_tags_marshall_write chunk %d data %p tags %p",
++		nand_chunk, data, tags);
++
++	/* For yaffs2 writing there must be both data and tags.
++	 * If we're using inband tags, then the tags are stuffed into
++	 * the end of the data buffer.
++	 */
++	if (!data || !tags)
++		BUG();
++	else if (dev->param.inband_tags) {
++		struct yaffs_packed_tags2_tags_only *pt2tp;
++		pt2tp =
++		    (struct yaffs_packed_tags2_tags_only *)(data +
++							dev->
++							data_bytes_per_chunk);
++		yaffs_pack_tags2_tags_only(pt2tp, tags);
++	} else {
++		yaffs_pack_tags2(&pt, tags, !dev->param.no_tags_ecc);
++	}
++
++	retval = dev->drv.drv_write_chunk_fn(dev, nand_chunk,
++			data, dev->param.total_bytes_per_chunk,
++			(dev->param.inband_tags) ? NULL : packed_tags_ptr,
++			(dev->param.inband_tags) ? 0 : packed_tags_size);
++
++	return retval;
++}
++
++static int yaffs_tags_marshall_read(struct yaffs_dev *dev,
++				   int nand_chunk, u8 *data,
++				   struct yaffs_ext_tags *tags)
++{
++	int retval = 0;
++	int local_data = 0;
++	u8 spare_buffer[100];
++	enum yaffs_ecc_result ecc_result;
++
++	struct yaffs_packed_tags2 pt;
++
++	int packed_tags_size =
++	    dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
++	void *packed_tags_ptr =
++	    dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt;
++
++	yaffs_trace(YAFFS_TRACE_MTD,
++		"yaffs_tags_marshall_read chunk %d data %p tags %p",
++		nand_chunk, data, tags);
++
++	if (dev->param.inband_tags) {
++		if (!data) {
++			local_data = 1;
++			data = yaffs_get_temp_buffer(dev);
++		}
++	}
++
++	if (dev->param.inband_tags || (data && !tags))
++		retval = dev->drv.drv_read_chunk_fn(dev, nand_chunk,
++					data, dev->param.total_bytes_per_chunk,
++					NULL, 0,
++					&ecc_result);
++	else if (tags)
++		retval = dev->drv.drv_read_chunk_fn(dev, nand_chunk,
++					data, dev->param.total_bytes_per_chunk,
++					spare_buffer, packed_tags_size,
++					&ecc_result);
++	else
++		BUG();
++
++
++	if (dev->param.inband_tags) {
++		if (tags) {
++			struct yaffs_packed_tags2_tags_only *pt2tp;
++			pt2tp =
++				(struct yaffs_packed_tags2_tags_only *)
++				&data[dev->data_bytes_per_chunk];
++			yaffs_unpack_tags2_tags_only(tags, pt2tp);
++		}
++	} else if (tags) {
++		memcpy(packed_tags_ptr, spare_buffer, packed_tags_size);
++		yaffs_unpack_tags2(tags, &pt, !dev->param.no_tags_ecc);
++	}
++
++	if (local_data)
++		yaffs_release_temp_buffer(dev, data);
++
++	if (tags && ecc_result == YAFFS_ECC_RESULT_UNFIXED) {
++		tags->ecc_result = YAFFS_ECC_RESULT_UNFIXED;
++		dev->n_ecc_unfixed++;
++	}
++
++	if (tags && ecc_result == -YAFFS_ECC_RESULT_FIXED) {
++		if (tags->ecc_result <= YAFFS_ECC_RESULT_NO_ERROR)
++			tags->ecc_result = YAFFS_ECC_RESULT_FIXED;
++		dev->n_ecc_fixed++;
++	}
++
++	if (ecc_result < YAFFS_ECC_RESULT_UNFIXED)
++		return YAFFS_OK;
++	else
++		return YAFFS_FAIL;
++}
++
++static int yaffs_tags_marshall_query_block(struct yaffs_dev *dev, int block_no,
++			       enum yaffs_block_state *state,
++			       u32 *seq_number)
++{
++	int retval;
++
++	yaffs_trace(YAFFS_TRACE_MTD, "yaffs_tags_marshall_query_block %d",
++			block_no);
++
++	retval = dev->drv.drv_check_bad_fn(dev, block_no);
++
++	if (retval== YAFFS_FAIL) {
++		yaffs_trace(YAFFS_TRACE_MTD, "block is bad");
++
++		*state = YAFFS_BLOCK_STATE_DEAD;
++		*seq_number = 0;
++	} else {
++		struct yaffs_ext_tags t;
++
++		yaffs_tags_marshall_read(dev,
++				    block_no * dev->param.chunks_per_block,
++				    NULL, &t);
++
++		if (t.chunk_used) {
++			*seq_number = t.seq_number;
++			*state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
++		} else {
++			*seq_number = 0;
++			*state = YAFFS_BLOCK_STATE_EMPTY;
++		}
++	}
++
++	yaffs_trace(YAFFS_TRACE_MTD,
++		"block query returns  seq %d state %d",
++		*seq_number, *state);
++
++	if (retval == 0)
++		return YAFFS_OK;
++	else
++		return YAFFS_FAIL;
++}
++
++static int yaffs_tags_marshall_mark_bad(struct yaffs_dev *dev, int block_no)
++{
++	return dev->drv.drv_mark_bad_fn(dev, block_no);
++
++}
++
++
++void yaffs_tags_marshall_install(struct yaffs_dev *dev)
++{
++	if (!dev->param.is_yaffs2)
++		return;
++
++	if (!dev->tagger.write_chunk_tags_fn)
++		dev->tagger.write_chunk_tags_fn = yaffs_tags_marshall_write;
++
++	if (!dev->tagger.read_chunk_tags_fn)
++		dev->tagger.read_chunk_tags_fn = yaffs_tags_marshall_read;
++
++	if (!dev->tagger.query_block_fn)
++		dev->tagger.query_block_fn = yaffs_tags_marshall_query_block;
++
++	if (!dev->tagger.mark_bad_fn)
++		dev->tagger.mark_bad_fn = yaffs_tags_marshall_mark_bad;
++
++}
+diff --git a/fs/yaffs2/yaffs_tagsmarshall.h b/fs/yaffs2/yaffs_tagsmarshall.h
+new file mode 100644
+index 0000000..bf3e68a
+--- /dev/null
++++ b/fs/yaffs2/yaffs_tagsmarshall.h
+@@ -0,0 +1,22 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ *   for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_TAGSMARSHALL_H__
++#define __YAFFS_TAGSMARSHALL_H__
++
++#include "yaffs_guts.h"
++void yaffs_tags_marshall_install(struct yaffs_dev *dev);
++
++#endif
+diff --git a/fs/yaffs2/yaffs_trace.h b/fs/yaffs2/yaffs_trace.h
+new file mode 100644
+index 0000000..fd26054
+--- /dev/null
++++ b/fs/yaffs2/yaffs_trace.h
+@@ -0,0 +1,57 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ *   for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YTRACE_H__
++#define __YTRACE_H__
++
++extern unsigned int yaffs_trace_mask;
++extern unsigned int yaffs_wr_attempts;
++
++/*
++ * Tracing flags.
++ * The flags masked in YAFFS_TRACE_ALWAYS are always traced.
++ */
++
++#define YAFFS_TRACE_OS			0x00000002
++#define YAFFS_TRACE_ALLOCATE		0x00000004
++#define YAFFS_TRACE_SCAN		0x00000008
++#define YAFFS_TRACE_BAD_BLOCKS		0x00000010
++#define YAFFS_TRACE_ERASE		0x00000020
++#define YAFFS_TRACE_GC			0x00000040
++#define YAFFS_TRACE_WRITE		0x00000080
++#define YAFFS_TRACE_TRACING		0x00000100
++#define YAFFS_TRACE_DELETION		0x00000200
++#define YAFFS_TRACE_BUFFERS		0x00000400
++#define YAFFS_TRACE_NANDACCESS		0x00000800
++#define YAFFS_TRACE_GC_DETAIL		0x00001000
++#define YAFFS_TRACE_SCAN_DEBUG		0x00002000
++#define YAFFS_TRACE_MTD			0x00004000
++#define YAFFS_TRACE_CHECKPOINT		0x00008000
++
++#define YAFFS_TRACE_VERIFY		0x00010000
++#define YAFFS_TRACE_VERIFY_NAND		0x00020000
++#define YAFFS_TRACE_VERIFY_FULL		0x00040000
++#define YAFFS_TRACE_VERIFY_ALL		0x000f0000
++
++#define YAFFS_TRACE_SYNC		0x00100000
++#define YAFFS_TRACE_BACKGROUND		0x00200000
++#define YAFFS_TRACE_LOCK		0x00400000
++#define YAFFS_TRACE_MOUNT		0x00800000
++
++#define YAFFS_TRACE_ERROR		0x40000000
++#define YAFFS_TRACE_BUG			0x80000000
++#define YAFFS_TRACE_ALWAYS		0xf0000000
++
++#endif
+diff --git a/fs/yaffs2/yaffs_verify.c b/fs/yaffs2/yaffs_verify.c
+new file mode 100644
+index 0000000..e8f2f0a
+--- /dev/null
++++ b/fs/yaffs2/yaffs_verify.c
+@@ -0,0 +1,529 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ *   for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * 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 "yaffs_verify.h"
++#include "yaffs_trace.h"
++#include "yaffs_bitmap.h"
++#include "yaffs_getblockinfo.h"
++#include "yaffs_nand.h"
++
++int yaffs_skip_verification(struct yaffs_dev *dev)
++{
++	(void) dev;
++	return !(yaffs_trace_mask &
++		 (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL));
++}
++
++static int yaffs_skip_full_verification(struct yaffs_dev *dev)
++{
++	(void) dev;
++	return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_FULL));
++}
++
++static int yaffs_skip_nand_verification(struct yaffs_dev *dev)
++{
++	(void) dev;
++	return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_NAND));
++}
++
++static const char * const block_state_name[] = {
++	"Unknown",
++	"Needs scan",
++	"Scanning",
++	"Empty",
++	"Allocating",
++	"Full",
++	"Dirty",
++	"Checkpoint",
++	"Collecting",
++	"Dead"
++};
++
++void yaffs_verify_blk(struct yaffs_dev *dev, struct yaffs_block_info *bi, int n)
++{
++	int actually_used;
++	int in_use;
++
++	if (yaffs_skip_verification(dev))
++		return;
++
++	/* Report illegal runtime states */
++	if (bi->block_state >= YAFFS_NUMBER_OF_BLOCK_STATES)
++		yaffs_trace(YAFFS_TRACE_VERIFY,
++			"Block %d has undefined state %d",
++			n, bi->block_state);
++
++	switch (bi->block_state) {
++	case YAFFS_BLOCK_STATE_UNKNOWN:
++	case YAFFS_BLOCK_STATE_SCANNING:
++	case YAFFS_BLOCK_STATE_NEEDS_SCAN:
++		yaffs_trace(YAFFS_TRACE_VERIFY,
++			"Block %d has bad run-state %s",
++			n, block_state_name[bi->block_state]);
++	}
++
++	/* Check pages in use and soft deletions are legal */
++
++	actually_used = bi->pages_in_use - bi->soft_del_pages;
++
++	if (bi->pages_in_use < 0 ||
++	    bi->pages_in_use > dev->param.chunks_per_block ||
++	    bi->soft_del_pages < 0 ||
++	    bi->soft_del_pages > dev->param.chunks_per_block ||
++	    actually_used < 0 || actually_used > dev->param.chunks_per_block)
++		yaffs_trace(YAFFS_TRACE_VERIFY,
++			"Block %d has illegal values pages_in_used %d soft_del_pages %d",
++			n, bi->pages_in_use, bi->soft_del_pages);
++
++	/* Check chunk bitmap legal */
++	in_use = yaffs_count_chunk_bits(dev, n);
++	if (in_use != bi->pages_in_use)
++		yaffs_trace(YAFFS_TRACE_VERIFY,
++			"Block %d has inconsistent values pages_in_use %d counted chunk bits %d",
++			n, bi->pages_in_use, in_use);
++}
++
++void yaffs_verify_collected_blk(struct yaffs_dev *dev,
++				struct yaffs_block_info *bi, int n)
++{
++	yaffs_verify_blk(dev, bi, n);
++
++	/* After collection the block should be in the erased state */
++
++	if (bi->block_state != YAFFS_BLOCK_STATE_COLLECTING &&
++	    bi->block_state != YAFFS_BLOCK_STATE_EMPTY) {
++		yaffs_trace(YAFFS_TRACE_ERROR,
++			"Block %d is in state %d after gc, should be erased",
++			n, bi->block_state);
++	}
++}
++
++void yaffs_verify_blocks(struct yaffs_dev *dev)
++{
++	int i;
++	int state_count[YAFFS_NUMBER_OF_BLOCK_STATES];
++	int illegal_states = 0;
++
++	if (yaffs_skip_verification(dev))
++		return;
++
++	memset(state_count, 0, sizeof(state_count));
++
++	for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
++		struct yaffs_block_info *bi = yaffs_get_block_info(dev, i);
++		yaffs_verify_blk(dev, bi, i);
++
++		if (bi->block_state < YAFFS_NUMBER_OF_BLOCK_STATES)
++			state_count[bi->block_state]++;
++		else
++			illegal_states++;
++	}
++
++	yaffs_trace(YAFFS_TRACE_VERIFY,	"Block summary");
++
++	yaffs_trace(YAFFS_TRACE_VERIFY,
++		"%d blocks have illegal states",
++		illegal_states);
++	if (state_count[YAFFS_BLOCK_STATE_ALLOCATING] > 1)
++		yaffs_trace(YAFFS_TRACE_VERIFY,
++			"Too many allocating blocks");
++
++	for (i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++)
++		yaffs_trace(YAFFS_TRACE_VERIFY,
++			"%s %d blocks",
++			block_state_name[i], state_count[i]);
++
++	if (dev->blocks_in_checkpt != state_count[YAFFS_BLOCK_STATE_CHECKPOINT])
++		yaffs_trace(YAFFS_TRACE_VERIFY,
++			"Checkpoint block count wrong dev %d count %d",
++			dev->blocks_in_checkpt,
++			state_count[YAFFS_BLOCK_STATE_CHECKPOINT]);
++
++	if (dev->n_erased_blocks != state_count[YAFFS_BLOCK_STATE_EMPTY])
++		yaffs_trace(YAFFS_TRACE_VERIFY,
++			"Erased block count wrong dev %d count %d",
++			dev->n_erased_blocks,
++			state_count[YAFFS_BLOCK_STATE_EMPTY]);
++
++	if (state_count[YAFFS_BLOCK_STATE_COLLECTING] > 1)
++		yaffs_trace(YAFFS_TRACE_VERIFY,
++			"Too many collecting blocks %d (max is 1)",
++			state_count[YAFFS_BLOCK_STATE_COLLECTING]);
++}
++
++/*
++ * Verify the object header. oh must be valid, but obj and tags may be NULL in
++ * which case those tests will not be performed.
++ */
++void yaffs_verify_oh(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh,
++		     struct yaffs_ext_tags *tags, int parent_check)
++{
++	if (obj && yaffs_skip_verification(obj->my_dev))
++		return;
++
++	if (!(tags && obj && oh)) {
++		yaffs_trace(YAFFS_TRACE_VERIFY,
++			"Verifying object header tags %p obj %p oh %p",
++			tags, obj, oh);
++		return;
++	}
++
++	if (oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN ||
++	    oh->type > YAFFS_OBJECT_TYPE_MAX)
++		yaffs_trace(YAFFS_TRACE_VERIFY,
++			"Obj %d header type is illegal value 0x%x",
++			tags->obj_id, oh->type);
++
++	if (tags->obj_id != obj->obj_id)
++		yaffs_trace(YAFFS_TRACE_VERIFY,
++			"Obj %d header mismatch obj_id %d",
++			tags->obj_id, obj->obj_id);
++
++	/*
++	 * Check that the object's parent ids match if parent_check requested.
++	 *
++	 * Tests do not apply to the root object.
++	 */
++
++	if (parent_check && tags->obj_id > 1 && !obj->parent)
++		yaffs_trace(YAFFS_TRACE_VERIFY,
++			"Obj %d header mismatch parent_id %d obj->parent is NULL",
++			tags->obj_id, oh->parent_obj_id);
++
++	if (parent_check && obj->parent &&
++	    oh->parent_obj_id != obj->parent->obj_id &&
++	    (oh->parent_obj_id != YAFFS_OBJECTID_UNLINKED ||
++	     obj->parent->obj_id != YAFFS_OBJECTID_DELETED))
++		yaffs_trace(YAFFS_TRACE_VERIFY,
++			"Obj %d header mismatch parent_id %d parent_obj_id %d",
++			tags->obj_id, oh->parent_obj_id,
++			obj->parent->obj_id);
++
++	if (tags->obj_id > 1 && oh->name[0] == 0)	/* Null name */
++		yaffs_trace(YAFFS_TRACE_VERIFY,
++			"Obj %d header name is NULL",
++			obj->obj_id);
++
++	if (tags->obj_id > 1 && ((u8) (oh->name[0])) == 0xff)	/* Junk name */
++		yaffs_trace(YAFFS_TRACE_VERIFY,
++			"Obj %d header name is 0xff",
++			obj->obj_id);
++}
++
++void yaffs_verify_file(struct yaffs_obj *obj)
++{
++	u32 x;
++	int required_depth;
++	int actual_depth;
++	int last_chunk;
++	u32 offset_in_chunk;
++	u32 the_chunk;
++
++	u32 i;
++	struct yaffs_dev *dev;
++	struct yaffs_ext_tags tags;
++	struct yaffs_tnode *tn;
++	u32 obj_id;
++
++	if (!obj)
++		return;
++
++	if (yaffs_skip_verification(obj->my_dev))
++		return;
++
++	dev = obj->my_dev;
++	obj_id = obj->obj_id;
++
++
++	/* Check file size is consistent with tnode depth */
++	yaffs_addr_to_chunk(dev, obj->variant.file_variant.file_size,
++				&last_chunk, &offset_in_chunk);
++	last_chunk++;
++	x = last_chunk >> YAFFS_TNODES_LEVEL0_BITS;
++	required_depth = 0;
++	while (x > 0) {
++		x >>= YAFFS_TNODES_INTERNAL_BITS;
++		required_depth++;
++	}
++
++	actual_depth = obj->variant.file_variant.top_level;
++
++	/* Check that the chunks in the tnode tree are all correct.
++	 * We do this by scanning through the tnode tree and
++	 * checking the tags for every chunk match.
++	 */
++
++	if (yaffs_skip_nand_verification(dev))
++		return;
++
++	for (i = 1; i <= last_chunk; i++) {
++		tn = yaffs_find_tnode_0(dev, &obj->variant.file_variant, i);
++
++		if (!tn)
++			continue;
++
++		the_chunk = yaffs_get_group_base(dev, tn, i);
++		if (the_chunk > 0) {
++			yaffs_rd_chunk_tags_nand(dev, the_chunk, NULL,
++						 &tags);
++			if (tags.obj_id != obj_id || tags.chunk_id != i)
++				yaffs_trace(YAFFS_TRACE_VERIFY,
++					"Object %d chunk_id %d NAND mismatch chunk %d tags (%d:%d)",
++					obj_id, i, the_chunk,
++					tags.obj_id, tags.chunk_id);
++		}
++	}
++}
++
++void yaffs_verify_link(struct yaffs_obj *obj)
++{
++	if (obj && yaffs_skip_verification(obj->my_dev))
++		return;
++
++	/* Verify sane equivalent object */
++}
++
++void yaffs_verify_symlink(struct yaffs_obj *obj)
++{
++	if (obj && yaffs_skip_verification(obj->my_dev))
++		return;
++
++	/* Verify symlink string */
++}
++
++void yaffs_verify_special(struct yaffs_obj *obj)
++{
++	if (obj && yaffs_skip_verification(obj->my_dev))
++		return;
++}
++
++void yaffs_verify_obj(struct yaffs_obj *obj)
++{
++	struct yaffs_dev *dev;
++	u32 chunk_min;
++	u32 chunk_max;
++	u32 chunk_id_ok;
++	u32 chunk_in_range;
++	u32 chunk_wrongly_deleted;
++	u32 chunk_valid;
++
++	if (!obj)
++		return;
++
++	if (obj->being_created)
++		return;
++
++	dev = obj->my_dev;
++
++	if (yaffs_skip_verification(dev))
++		return;
++
++	/* Check sane object header chunk */
++
++	chunk_min = dev->internal_start_block * dev->param.chunks_per_block;
++	chunk_max =
++	    (dev->internal_end_block + 1) * dev->param.chunks_per_block - 1;
++
++	chunk_in_range = (((unsigned)(obj->hdr_chunk)) >= chunk_min &&
++			  ((unsigned)(obj->hdr_chunk)) <= chunk_max);
++	chunk_id_ok = chunk_in_range || (obj->hdr_chunk == 0);
++	chunk_valid = chunk_in_range &&
++	    yaffs_check_chunk_bit(dev,
++				  obj->hdr_chunk / dev->param.chunks_per_block,
++				  obj->hdr_chunk % dev->param.chunks_per_block);
++	chunk_wrongly_deleted = chunk_in_range && !chunk_valid;
++
++	if (!obj->fake && (!chunk_id_ok || chunk_wrongly_deleted))
++		yaffs_trace(YAFFS_TRACE_VERIFY,
++			"Obj %d has chunk_id %d %s %s",
++			obj->obj_id, obj->hdr_chunk,
++			chunk_id_ok ? "" : ",out of range",
++			chunk_wrongly_deleted ? ",marked as deleted" : "");
++
++	if (chunk_valid && !yaffs_skip_nand_verification(dev)) {
++		struct yaffs_ext_tags tags;
++		struct yaffs_obj_hdr *oh;
++		u8 *buffer = yaffs_get_temp_buffer(dev);
++
++		oh = (struct yaffs_obj_hdr *)buffer;
++
++		yaffs_rd_chunk_tags_nand(dev, obj->hdr_chunk, buffer, &tags);
++
++		yaffs_verify_oh(obj, oh, &tags, 1);
++
++		yaffs_release_temp_buffer(dev, buffer);
++	}
++
++	/* Verify it has a parent */
++	if (obj && !obj->fake && (!obj->parent || obj->parent->my_dev != dev)) {
++		yaffs_trace(YAFFS_TRACE_VERIFY,
++			"Obj %d has parent pointer %p which does not look like an object",
++			obj->obj_id, obj->parent);
++	}
++
++	/* Verify parent is a directory */
++	if (obj->parent &&
++	    obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
++		yaffs_trace(YAFFS_TRACE_VERIFY,
++			"Obj %d's parent is not a directory (type %d)",
++			obj->obj_id, obj->parent->variant_type);
++	}
++
++	switch (obj->variant_type) {
++	case YAFFS_OBJECT_TYPE_FILE:
++		yaffs_verify_file(obj);
++		break;
++	case YAFFS_OBJECT_TYPE_SYMLINK:
++		yaffs_verify_symlink(obj);
++		break;
++	case YAFFS_OBJECT_TYPE_DIRECTORY:
++		yaffs_verify_dir(obj);
++		break;
++	case YAFFS_OBJECT_TYPE_HARDLINK:
++		yaffs_verify_link(obj);
++		break;
++	case YAFFS_OBJECT_TYPE_SPECIAL:
++		yaffs_verify_special(obj);
++		break;
++	case YAFFS_OBJECT_TYPE_UNKNOWN:
++	default:
++		yaffs_trace(YAFFS_TRACE_VERIFY,
++			"Obj %d has illegaltype %d",
++		   obj->obj_id, obj->variant_type);
++		break;
++	}
++}
++
++void yaffs_verify_objects(struct yaffs_dev *dev)
++{
++	struct yaffs_obj *obj;
++	int i;
++	struct list_head *lh;
++
++	if (yaffs_skip_verification(dev))
++		return;
++
++	/* Iterate through the objects in each hash entry */
++
++	for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
++		list_for_each(lh, &dev->obj_bucket[i].list) {
++			obj = list_entry(lh, struct yaffs_obj, hash_link);
++			yaffs_verify_obj(obj);
++		}
++	}
++}
++
++void yaffs_verify_obj_in_dir(struct yaffs_obj *obj)
++{
++	struct list_head *lh;
++	struct yaffs_obj *list_obj;
++	int count = 0;
++
++	if (!obj) {
++		yaffs_trace(YAFFS_TRACE_ALWAYS, "No object to verify");
++		BUG();
++		return;
++	}
++
++	if (yaffs_skip_verification(obj->my_dev))
++		return;
++
++	if (!obj->parent) {
++		yaffs_trace(YAFFS_TRACE_ALWAYS, "Object does not have parent");
++		BUG();
++		return;
++	}
++
++	if (obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
++		yaffs_trace(YAFFS_TRACE_ALWAYS, "Parent is not directory");
++		BUG();
++	}
++
++	/* Iterate through the objects in each hash entry */
++
++	list_for_each(lh, &obj->parent->variant.dir_variant.children) {
++		list_obj = list_entry(lh, struct yaffs_obj, siblings);
++		yaffs_verify_obj(list_obj);
++		if (obj == list_obj)
++			count++;
++	}
++
++	if (count != 1) {
++		yaffs_trace(YAFFS_TRACE_ALWAYS,
++			"Object in directory %d times",
++			count);
++		BUG();
++	}
++}
++
++void yaffs_verify_dir(struct yaffs_obj *directory)
++{
++	struct list_head *lh;
++	struct yaffs_obj *list_obj;
++
++	if (!directory) {
++		BUG();
++		return;
++	}
++
++	if (yaffs_skip_full_verification(directory->my_dev))
++		return;
++
++	if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
++		yaffs_trace(YAFFS_TRACE_ALWAYS,
++			"Directory has wrong type: %d",
++			directory->variant_type);
++		BUG();
++	}
++
++	/* Iterate through the objects in each hash entry */
++
++	list_for_each(lh, &directory->variant.dir_variant.children) {
++		list_obj = list_entry(lh, struct yaffs_obj, siblings);
++		if (list_obj->parent != directory) {
++			yaffs_trace(YAFFS_TRACE_ALWAYS,
++				"Object in directory list has wrong parent %p",
++				list_obj->parent);
++			BUG();
++		}
++		yaffs_verify_obj_in_dir(list_obj);
++	}
++}
++
++static int yaffs_free_verification_failures;
++
++void yaffs_verify_free_chunks(struct yaffs_dev *dev)
++{
++	int counted;
++	int difference;
++
++	if (yaffs_skip_verification(dev))
++		return;
++
++	counted = yaffs_count_free_chunks(dev);
++
++	difference = dev->n_free_chunks - counted;
++
++	if (difference) {
++		yaffs_trace(YAFFS_TRACE_ALWAYS,
++			"Freechunks verification failure %d %d %d",
++			dev->n_free_chunks, counted, difference);
++		yaffs_free_verification_failures++;
++	}
++}
++
++int yaffs_verify_file_sane(struct yaffs_obj *in)
++{
++	(void) in;
++	return YAFFS_OK;
++}
+diff --git a/fs/yaffs2/yaffs_verify.h b/fs/yaffs2/yaffs_verify.h
+new file mode 100644
+index 0000000..4f4af8d
+--- /dev/null
++++ b/fs/yaffs2/yaffs_verify.h
+@@ -0,0 +1,43 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ *   for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_VERIFY_H__
++#define __YAFFS_VERIFY_H__
++
++#include "yaffs_guts.h"
++
++void yaffs_verify_blk(struct yaffs_dev *dev, struct yaffs_block_info *bi,
++		      int n);
++void yaffs_verify_collected_blk(struct yaffs_dev *dev,
++				struct yaffs_block_info *bi, int n);
++void yaffs_verify_blocks(struct yaffs_dev *dev);
++
++void yaffs_verify_oh(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh,
++		     struct yaffs_ext_tags *tags, int parent_check);
++void yaffs_verify_file(struct yaffs_obj *obj);
++void yaffs_verify_link(struct yaffs_obj *obj);
++void yaffs_verify_symlink(struct yaffs_obj *obj);
++void yaffs_verify_special(struct yaffs_obj *obj);
++void yaffs_verify_obj(struct yaffs_obj *obj);
++void yaffs_verify_objects(struct yaffs_dev *dev);
++void yaffs_verify_obj_in_dir(struct yaffs_obj *obj);
++void yaffs_verify_dir(struct yaffs_obj *directory);
++void yaffs_verify_free_chunks(struct yaffs_dev *dev);
++
++int yaffs_verify_file_sane(struct yaffs_obj *obj);
++
++int yaffs_skip_verification(struct yaffs_dev *dev);
++
++#endif
+diff --git a/fs/yaffs2/yaffs_vfs.c b/fs/yaffs2/yaffs_vfs.c
+new file mode 100644
+index 0000000..8b253ef
+--- /dev/null
++++ b/fs/yaffs2/yaffs_vfs.c
+@@ -0,0 +1,3664 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ *   for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ * Acknowledgements:
++ * Luc van OostenRyck for numerous patches.
++ * Nick Bane for numerous patches.
++ * Nick Bane for 2.5/2.6 integration.
++ * Andras Toth for mknod rdev issue.
++ * Michael Fischer for finding the problem with inode inconsistency.
++ * Some code bodily lifted from JFFS
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++/*
++ *
++ * This is the file system front-end to YAFFS that hooks it up to
++ * the VFS.
++ *
++ * Special notes:
++ * >> 2.4: sb->u.generic_sbp points to the struct yaffs_dev associated with
++ *         this superblock
++ * >> 2.6: sb->s_fs_info  points to the struct yaffs_dev associated with this
++ *         superblock
++ * >> inode->u.generic_ip points to the associated struct yaffs_obj.
++ */
++
++/*
++ * There are two variants of the VFS glue code. This variant should compile
++ * for any version of Linux.
++ */
++#include <linux/version.h>
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10))
++#define YAFFS_COMPILE_BACKGROUND
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23))
++#define YAFFS_COMPILE_FREEZER
++#endif
++#endif
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28))
++#define YAFFS_COMPILE_EXPORTFS
++#endif
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35))
++#define YAFFS_USE_SETATTR_COPY
++#define YAFFS_USE_TRUNCATE_SETSIZE
++#endif
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35))
++#define YAFFS_HAS_EVICT_INODE
++#endif
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
++#define YAFFS_NEW_FOLLOW_LINK 1
++#else
++#define YAFFS_NEW_FOLLOW_LINK 0
++#endif
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
++#define YAFFS_HAS_WRITE_SUPER
++#endif
++
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
++#include <linux/config.h>
++#endif
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/init.h>
++#include <linux/fs.h>
++#include <linux/proc_fs.h>
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39))
++#include <linux/smp_lock.h>
++#endif
++#include <linux/pagemap.h>
++#include <linux/mtd/mtd.h>
++#include <linux/interrupt.h>
++#include <linux/string.h>
++#include <linux/ctype.h>
++
++#if (YAFFS_NEW_FOLLOW_LINK == 1)
++#include <linux/namei.h>
++#endif
++
++#ifdef YAFFS_COMPILE_EXPORTFS
++#include <linux/exportfs.h>
++#endif
++
++#ifdef YAFFS_COMPILE_BACKGROUND
++#include <linux/kthread.h>
++#include <linux/delay.h>
++#endif
++#ifdef YAFFS_COMPILE_FREEZER
++#include <linux/freezer.h>
++#endif
++
++#include <asm/div64.h>
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++
++#include <linux/statfs.h>
++
++#define UnlockPage(p) unlock_page(p)
++#define Page_Uptodate(page)	test_bit(PG_uptodate, &(page)->flags)
++
++/* FIXME: use sb->s_id instead ? */
++#define yaffs_devname(sb, buf)	bdevname(sb->s_bdev, buf)
++
++#else
++
++#include <linux/locks.h>
++#define	BDEVNAME_SIZE		0
++#define	yaffs_devname(sb, buf)	kdevname(sb->s_dev)
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0))
++/* added NCB 26/5/2006 for 2.4.25-vrs2-tcl1 kernel */
++#define __user
++#endif
++
++#endif
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26))
++#define YPROC_ROOT  (&proc_root)
++#else
++#define YPROC_ROOT  NULL
++#endif
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26))
++#define Y_INIT_TIMER(a)	init_timer(a)
++#else
++#define Y_INIT_TIMER(a)	init_timer_on_stack(a)
++#endif
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 27))
++#define YAFFS_USE_WRITE_BEGIN_END 1
++#else
++#define YAFFS_USE_WRITE_BEGIN_END 0
++#endif
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
++#define YAFFS_SUPER_HAS_DIRTY
++#endif
++
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
++#define set_nlink(inode, count)  do { (inode)->i_nlink = (count); } while(0)
++#endif
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28))
++static uint32_t YCALCBLOCKS(uint64_t partition_size, uint32_t block_size)
++{
++	uint64_t result = partition_size;
++	do_div(result, block_size);
++	return (uint32_t) result;
++}
++#else
++#define YCALCBLOCKS(s, b) ((s)/(b))
++#endif
++
++#include <linux/uaccess.h>
++#include <linux/mtd/mtd.h>
++
++#include "yportenv.h"
++#include "yaffs_trace.h"
++#include "yaffs_guts.h"
++#include "yaffs_attribs.h"
++
++#include "yaffs_linux.h"
++
++#include "yaffs_mtdif.h"
++#include "yaffs_packedtags2.h"
++#include "yaffs_getblockinfo.h"
++
++unsigned int yaffs_trace_mask =
++		YAFFS_TRACE_BAD_BLOCKS |
++		YAFFS_TRACE_ALWAYS |
++		0;
++
++unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS;
++unsigned int yaffs_auto_checkpoint = 1;
++unsigned int yaffs_gc_control = 1;
++unsigned int yaffs_bg_enable = 1;
++unsigned int yaffs_auto_select = 1;
++/* Module Parameters */
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++module_param(yaffs_trace_mask, uint, 0644);
++module_param(yaffs_wr_attempts, uint, 0644);
++module_param(yaffs_auto_checkpoint, uint, 0644);
++module_param(yaffs_gc_control, uint, 0644);
++module_param(yaffs_bg_enable, uint, 0644);
++#else
++MODULE_PARM(yaffs_trace_mask, "i");
++MODULE_PARM(yaffs_wr_attempts, "i");
++MODULE_PARM(yaffs_auto_checkpoint, "i");
++MODULE_PARM(yaffs_gc_control, "i");
++#endif
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25))
++/* use iget and read_inode */
++#define Y_IGET(sb, inum) iget((sb), (inum))
++
++#else
++/* Call local equivalent */
++#define YAFFS_USE_OWN_IGET
++#define Y_IGET(sb, inum) yaffs_iget((sb), (inum))
++
++#endif
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
++#define yaffs_inode_to_obj_lv(iptr) ((iptr)->i_private)
++#else
++#define yaffs_inode_to_obj_lv(iptr) ((iptr)->u.generic_ip)
++#endif
++
++#define yaffs_inode_to_obj(iptr) \
++	((struct yaffs_obj *)(yaffs_inode_to_obj_lv(iptr)))
++#define yaffs_dentry_to_obj(dptr) yaffs_inode_to_obj((dptr)->d_inode)
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++#define yaffs_super_to_dev(sb)	((struct yaffs_dev *)sb->s_fs_info)
++#else
++#define yaffs_super_to_dev(sb)	((struct yaffs_dev *)sb->u.generic_sbp)
++#endif
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
++#define Y_CLEAR_INODE(i) clear_inode(i)
++#else
++#define Y_CLEAR_INODE(i) end_writeback(i)
++#endif
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
++#define YAFFS_USE_DIR_ITERATE
++#endif
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,12,0))
++#define YAFFS_NEW_PROCFS
++#include <linux/seq_file.h>
++#endif
++
++
++#define update_dir_time(dir) do {\
++			(dir)->i_ctime = (dir)->i_mtime = CURRENT_TIME; \
++		} while (0)
++
++static void yaffs_fill_inode_from_obj(struct inode *inode,
++				      struct yaffs_obj *obj);
++
++
++static void yaffs_gross_lock(struct yaffs_dev *dev)
++{
++	yaffs_trace(YAFFS_TRACE_LOCK, "yaffs locking %p", current);
++	mutex_lock(&(yaffs_dev_to_lc(dev)->gross_lock));
++	yaffs_trace(YAFFS_TRACE_LOCK, "yaffs locked %p", current);
++}
++
++static void yaffs_gross_unlock(struct yaffs_dev *dev)
++{
++	yaffs_trace(YAFFS_TRACE_LOCK, "yaffs unlocking %p", current);
++	mutex_unlock(&(yaffs_dev_to_lc(dev)->gross_lock));
++}
++
++
++static int yaffs_readpage_nolock(struct file *f, struct page *pg)
++{
++	/* Lifted from jffs2 */
++
++	struct yaffs_obj *obj;
++	unsigned char *pg_buf;
++	int ret;
++	loff_t pos = ((loff_t) pg->index) << PAGE_CACHE_SHIFT;
++	struct yaffs_dev *dev;
++
++	yaffs_trace(YAFFS_TRACE_OS,
++		"yaffs_readpage_nolock at %lld, size %08x",
++		(long long)pos,
++		(unsigned)PAGE_CACHE_SIZE);
++
++	obj = yaffs_dentry_to_obj(f->f_dentry);
++
++	dev = obj->my_dev;
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++	BUG_ON(!PageLocked(pg));
++#else
++	if (!PageLocked(pg))
++		PAGE_BUG(pg);
++#endif
++
++	pg_buf = kmap(pg);
++	/* FIXME: Can kmap fail? */
++
++	yaffs_gross_lock(dev);
++
++	ret = yaffs_file_rd(obj, pg_buf, pos, PAGE_CACHE_SIZE);
++
++	yaffs_gross_unlock(dev);
++
++	if (ret >= 0)
++		ret = 0;
++
++	if (ret) {
++		ClearPageUptodate(pg);
++		SetPageError(pg);
++	} else {
++		SetPageUptodate(pg);
++		ClearPageError(pg);
++	}
++
++	flush_dcache_page(pg);
++	kunmap(pg);
++
++	yaffs_trace(YAFFS_TRACE_OS, "yaffs_readpage_nolock done");
++	return ret;
++}
++
++static int yaffs_readpage_unlock(struct file *f, struct page *pg)
++{
++	int ret = yaffs_readpage_nolock(f, pg);
++	UnlockPage(pg);
++	return ret;
++}
++
++static int yaffs_readpage(struct file *f, struct page *pg)
++{
++	int ret;
++
++	yaffs_trace(YAFFS_TRACE_OS, "yaffs_readpage");
++	ret = yaffs_readpage_unlock(f, pg);
++	yaffs_trace(YAFFS_TRACE_OS, "yaffs_readpage done");
++	return ret;
++}
++
++
++static void yaffs_set_super_dirty_val(struct yaffs_dev *dev, int val)
++{
++	struct yaffs_linux_context *lc = yaffs_dev_to_lc(dev);
++
++	if (lc)
++		lc->dirty = val;
++
++# ifdef YAFFS_SUPER_HAS_DIRTY
++	{
++		struct super_block *sb = lc->super;
++
++		if (sb)
++			sb->s_dirt = val;
++	}
++#endif
++
++}
++
++static void yaffs_set_super_dirty(struct yaffs_dev *dev)
++{
++	yaffs_set_super_dirty_val(dev, 1);
++}
++
++static void yaffs_clear_super_dirty(struct yaffs_dev *dev)
++{
++	yaffs_set_super_dirty_val(dev, 0);
++}
++
++static int yaffs_check_super_dirty(struct yaffs_dev *dev)
++{
++	struct yaffs_linux_context *lc = yaffs_dev_to_lc(dev);
++
++	if (lc && lc->dirty)
++		return 1;
++
++# ifdef YAFFS_SUPER_HAS_DIRTY
++	{
++		struct super_block *sb = lc->super;
++
++		if (sb && sb->s_dirt)
++			return 1;
++	}
++#endif
++	return 0;
++
++}
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++static int yaffs_writepage(struct page *page, struct writeback_control *wbc)
++#else
++static int yaffs_writepage(struct page *page)
++#endif
++{
++	struct yaffs_dev *dev;
++	struct address_space *mapping = page->mapping;
++	struct inode *inode;
++	unsigned long end_index;
++	char *buffer;
++	struct yaffs_obj *obj;
++	int n_written = 0;
++	unsigned n_bytes;
++	loff_t i_size;
++
++	if (!mapping)
++		BUG();
++	inode = mapping->host;
++	if (!inode)
++		BUG();
++	i_size = i_size_read(inode);
++
++	end_index = i_size >> PAGE_CACHE_SHIFT;
++
++	if (page->index < end_index)
++		n_bytes = PAGE_CACHE_SIZE;
++	else {
++		n_bytes = i_size & (PAGE_CACHE_SIZE - 1);
++
++		if (page->index > end_index || !n_bytes) {
++			yaffs_trace(YAFFS_TRACE_OS,
++				"yaffs_writepage at %lld, inode size = %lld!!",
++				((loff_t)page->index) << PAGE_CACHE_SHIFT,
++				inode->i_size);
++			yaffs_trace(YAFFS_TRACE_OS,
++				"                -> don't care!!");
++
++			zero_user_segment(page, 0, PAGE_CACHE_SIZE);
++			set_page_writeback(page);
++			unlock_page(page);
++			end_page_writeback(page);
++			return 0;
++		}
++	}
++
++	if (n_bytes != PAGE_CACHE_SIZE)
++		zero_user_segment(page, n_bytes, PAGE_CACHE_SIZE);
++
++	get_page(page);
++
++	buffer = kmap(page);
++
++	obj = yaffs_inode_to_obj(inode);
++	dev = obj->my_dev;
++	yaffs_gross_lock(dev);
++
++	yaffs_trace(YAFFS_TRACE_OS,
++		"yaffs_writepage at %lld, size %08x",
++		((loff_t)page->index) << PAGE_CACHE_SHIFT, n_bytes);
++	yaffs_trace(YAFFS_TRACE_OS,
++		"writepag0: obj = %lld, ino = %lld",
++		obj->variant.file_variant.file_size, inode->i_size);
++
++	n_written = yaffs_wr_file(obj, buffer,
++				  ((loff_t)page->index) << PAGE_CACHE_SHIFT, n_bytes, 0);
++
++	yaffs_set_super_dirty(dev);
++
++	yaffs_trace(YAFFS_TRACE_OS,
++		"writepag1: obj = %lld, ino = %lld",
++		obj->variant.file_variant.file_size, inode->i_size);
++
++	yaffs_gross_unlock(dev);
++
++	kunmap(page);
++	set_page_writeback(page);
++	unlock_page(page);
++	end_page_writeback(page);
++	put_page(page);
++
++	return (n_written == n_bytes) ? 0 : -ENOSPC;
++}
++
++/* Space holding and freeing is done to ensure we have space available for write_begin/end */
++/* For now we just assume few parallel writes and check against a small number. */
++/* Todo: need to do this with a counter to handle parallel reads better */
++
++static ssize_t yaffs_hold_space(struct file *f)
++{
++	struct yaffs_obj *obj;
++	struct yaffs_dev *dev;
++
++	int n_free_chunks;
++
++	obj = yaffs_dentry_to_obj(f->f_dentry);
++
++	dev = obj->my_dev;
++
++	yaffs_gross_lock(dev);
++
++	n_free_chunks = yaffs_get_n_free_chunks(dev);
++
++	yaffs_gross_unlock(dev);
++
++	return (n_free_chunks > 20) ? 1 : 0;
++}
++
++static void yaffs_release_space(struct file *f)
++{
++	struct yaffs_obj *obj;
++	struct yaffs_dev *dev;
++
++	obj = yaffs_dentry_to_obj(f->f_dentry);
++
++	dev = obj->my_dev;
++
++	yaffs_gross_lock(dev);
++
++	yaffs_gross_unlock(dev);
++}
++
++#if (YAFFS_USE_WRITE_BEGIN_END > 0)
++static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
++			     loff_t pos, unsigned len, unsigned flags,
++			     struct page **pagep, void **fsdata)
++{
++	struct page *pg = NULL;
++	pgoff_t index = pos >> PAGE_CACHE_SHIFT;
++
++	int ret = 0;
++	int space_held = 0;
++
++	/* Get a page */
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
++	pg = grab_cache_page_write_begin(mapping, index, flags);
++#else
++	pg = __grab_cache_page(mapping, index);
++#endif
++
++	*pagep = pg;
++	if (!pg) {
++		ret = -ENOMEM;
++		goto out;
++	}
++	yaffs_trace(YAFFS_TRACE_OS,
++		"start yaffs_write_begin index %d(%x) uptodate %d",
++		(int)index, (int)index, Page_Uptodate(pg) ? 1 : 0);
++
++	/* Get fs space */
++	space_held = yaffs_hold_space(filp);
++
++	if (!space_held) {
++		ret = -ENOSPC;
++		goto out;
++	}
++
++	/* Update page if required */
++
++	if (!Page_Uptodate(pg))
++		ret = yaffs_readpage_nolock(filp, pg);
++
++	if (ret)
++		goto out;
++
++	/* Happy path return */
++	yaffs_trace(YAFFS_TRACE_OS, "end yaffs_write_begin - ok");
++
++	return 0;
++
++out:
++	yaffs_trace(YAFFS_TRACE_OS,
++		"end yaffs_write_begin fail returning %d", ret);
++	if (space_held)
++		yaffs_release_space(filp);
++	if (pg) {
++		unlock_page(pg);
++		page_cache_release(pg);
++	}
++	return ret;
++}
++
++#else
++
++static int yaffs_prepare_write(struct file *f, struct page *pg,
++			       unsigned offset, unsigned to)
++{
++	yaffs_trace(YAFFS_TRACE_OS, "yaffs_prepair_write");
++
++	if (!Page_Uptodate(pg))
++		return yaffs_readpage_nolock(f, pg);
++	return 0;
++}
++#endif
++
++
++static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
++				loff_t * pos)
++{
++	struct yaffs_obj *obj;
++	int n_written;
++	loff_t ipos;
++	struct inode *inode;
++	struct yaffs_dev *dev;
++
++	obj = yaffs_dentry_to_obj(f->f_dentry);
++
++	if (!obj) {
++		yaffs_trace(YAFFS_TRACE_OS,
++			"yaffs_file_write: hey obj is null!");
++                return -EINVAL;
++        }
++
++	dev = obj->my_dev;
++
++	yaffs_gross_lock(dev);
++
++	inode = f->f_dentry->d_inode;
++
++	if (!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND)
++		ipos = inode->i_size;
++	else
++		ipos = *pos;
++
++	yaffs_trace(YAFFS_TRACE_OS,
++		"yaffs_file_write about to write writing %u(%x) bytes to object %d at %lld",
++		(unsigned)n, (unsigned)n, obj->obj_id, ipos);
++
++	n_written = yaffs_wr_file(obj, buf, ipos, n, 0);
++
++	yaffs_set_super_dirty(dev);
++
++	yaffs_trace(YAFFS_TRACE_OS,
++		"yaffs_file_write: %d(%x) bytes written",
++		(unsigned)n, (unsigned)n);
++
++	if (n_written > 0) {
++		ipos += n_written;
++		*pos = ipos;
++		if (ipos > inode->i_size) {
++			inode->i_size = ipos;
++			inode->i_blocks = (ipos + 511) >> 9;
++
++			yaffs_trace(YAFFS_TRACE_OS,
++				"yaffs_file_write size updated to %lld bytes, %d blocks",
++				ipos, (int)(inode->i_blocks));
++		}
++
++	}
++	yaffs_gross_unlock(dev);
++	return (n_written == 0) && (n > 0) ? -ENOSPC : n_written;
++}
++
++
++#if (YAFFS_USE_WRITE_BEGIN_END > 0)
++static int yaffs_write_end(struct file *filp, struct address_space *mapping,
++			   loff_t pos, unsigned len, unsigned copied,
++			   struct page *pg, void *fsdadata)
++{
++	int ret = 0;
++	void *addr, *kva;
++	uint32_t offset_into_page = pos & (PAGE_CACHE_SIZE - 1);
++
++	kva = kmap(pg);
++	addr = kva + offset_into_page;
++
++	yaffs_trace(YAFFS_TRACE_OS,
++		"yaffs_write_end addr %p pos %lld n_bytes %d",
++		addr, pos, copied);
++
++	ret = yaffs_file_write(filp, addr, copied, &pos);
++
++	if (ret != copied) {
++		yaffs_trace(YAFFS_TRACE_OS,
++			"yaffs_write_end not same size ret %d  copied %d",
++			ret, copied);
++		SetPageError(pg);
++	}
++
++	kunmap(pg);
++
++	yaffs_release_space(filp);
++	unlock_page(pg);
++	page_cache_release(pg);
++	return ret;
++}
++#else
++
++static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
++			      unsigned to)
++{
++	void *addr, *kva;
++
++	loff_t pos = (((loff_t) pg->index) << PAGE_CACHE_SHIFT) + offset;
++	int n_bytes = to - offset;
++	int n_written;
++
++	kva = kmap(pg);
++	addr = kva + offset;
++
++	yaffs_trace(YAFFS_TRACE_OS,
++		"yaffs_commit_write addr %p pos %lld n_bytes %d",
++		addr, pos, n_bytes);
++
++	n_written = yaffs_file_write(f, addr, n_bytes, &pos);
++
++	if (n_written != n_bytes) {
++		yaffs_trace(YAFFS_TRACE_OS,
++			"yaffs_commit_write not same size n_written %d  n_bytes %d",
++			n_written, n_bytes);
++		SetPageError(pg);
++	}
++	kunmap(pg);
++
++	yaffs_trace(YAFFS_TRACE_OS,
++		"yaffs_commit_write returning %d",
++		n_written == n_bytes ? 0 : n_written);
++
++	return n_written == n_bytes ? 0 : n_written;
++}
++#endif
++
++static struct address_space_operations yaffs_file_address_operations = {
++	.readpage = yaffs_readpage,
++	.writepage = yaffs_writepage,
++#if (YAFFS_USE_WRITE_BEGIN_END > 0)
++	.write_begin = yaffs_write_begin,
++	.write_end = yaffs_write_end,
++#else
++	.prepare_write = yaffs_prepare_write,
++	.commit_write = yaffs_commit_write,
++#endif
++};
++
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
++static int yaffs_file_flush(struct file *file, fl_owner_t id)
++#else
++static int yaffs_file_flush(struct file *file)
++#endif
++{
++	struct yaffs_obj *obj = yaffs_dentry_to_obj(file->f_dentry);
++
++	struct yaffs_dev *dev = obj->my_dev;
++
++	yaffs_trace(YAFFS_TRACE_OS,
++		"yaffs_file_flush object %d (%s)",
++		obj->obj_id,
++		obj->dirty ? "dirty" : "clean");
++
++	yaffs_gross_lock(dev);
++
++	yaffs_flush_file(obj, 1, 0, 0);
++
++	yaffs_gross_unlock(dev);
++
++	return 0;
++}
++
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
++static int yaffs_sync_object(struct file *file, loff_t start, loff_t end, int datasync)
++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
++static int yaffs_sync_object(struct file *file, int datasync)
++#else
++static int yaffs_sync_object(struct file *file, struct dentry *dentry,
++			     int datasync)
++#endif
++{
++	struct yaffs_obj *obj;
++	struct yaffs_dev *dev;
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
++	struct dentry *dentry = file->f_path.dentry;
++#endif
++
++	obj = yaffs_dentry_to_obj(dentry);
++
++	dev = obj->my_dev;
++
++	yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC,
++		"yaffs_sync_object");
++	yaffs_gross_lock(dev);
++	yaffs_flush_file(obj, 1, datasync, 0);
++	yaffs_gross_unlock(dev);
++	return 0;
++}
++
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22))
++static const struct file_operations yaffs_file_operations = {
++	.read = new_sync_read,
++	.write = new_sync_write,
++	.read_iter = generic_file_read_iter,
++	.write_iter = generic_file_write_iter,
++	.mmap = generic_file_mmap,
++	.flush = yaffs_file_flush,
++	.fsync = yaffs_sync_object,
++	.splice_read = generic_file_splice_read,
++	.splice_write = iter_file_splice_write,
++	.llseek = generic_file_llseek,
++};
++
++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
++
++static const struct file_operations yaffs_file_operations = {
++	.read = do_sync_read,
++	.write = do_sync_write,
++	.aio_read = generic_file_aio_read,
++	.aio_write = generic_file_aio_write,
++	.mmap = generic_file_mmap,
++	.flush = yaffs_file_flush,
++	.fsync = yaffs_sync_object,
++	.sendfile = generic_file_sendfile,
++};
++
++#else
++
++static const struct file_operations yaffs_file_operations = {
++	.read = generic_file_read,
++	.write = generic_file_write,
++	.mmap = generic_file_mmap,
++	.flush = yaffs_file_flush,
++	.fsync = yaffs_sync_object,
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++	.sendfile = generic_file_sendfile,
++#endif
++};
++#endif
++
++
++
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25))
++static void zero_user_segment(struct page *page, unsigned start, unsigned end)
++{
++	void *kaddr = kmap_atomic(page, KM_USER0);
++	memset(kaddr + start, 0, end - start);
++	kunmap_atomic(kaddr, KM_USER0);
++	flush_dcache_page(page);
++}
++#endif
++
++
++static int yaffs_vfs_setsize(struct inode *inode, loff_t newsize)
++{
++#ifdef YAFFS_USE_TRUNCATE_SETSIZE
++	truncate_setsize(inode, newsize);
++	return 0;
++#else
++	truncate_inode_pages(&inode->i_data, newsize);
++	return 0;
++#endif
++
++}
++
++
++static int yaffs_vfs_setattr(struct inode *inode, struct iattr *attr)
++{
++#ifdef YAFFS_USE_SETATTR_COPY
++	setattr_copy(inode, attr);
++	return 0;
++#else
++	return inode_setattr(inode, attr);
++#endif
++
++}
++
++static int yaffs_setattr(struct dentry *dentry, struct iattr *attr)
++{
++	struct inode *inode = dentry->d_inode;
++	int error = 0;
++	struct yaffs_dev *dev;
++
++	yaffs_trace(YAFFS_TRACE_OS,
++		"yaffs_setattr of object %d",
++		yaffs_inode_to_obj(inode)->obj_id);
++#if 0
++	/* Fail if a requested resize >= 2GB */
++	if (attr->ia_valid & ATTR_SIZE && (attr->ia_size >> 31))
++		error = -EINVAL;
++#endif
++
++	if (error == 0)
++		error = inode_change_ok(inode, attr);
++	if (error == 0) {
++		int result;
++		if (!error) {
++			error = yaffs_vfs_setattr(inode, attr);
++			yaffs_trace(YAFFS_TRACE_OS, "inode_setattr called");
++			if (attr->ia_valid & ATTR_SIZE) {
++				yaffs_vfs_setsize(inode, attr->ia_size);
++				inode->i_blocks = (inode->i_size + 511) >> 9;
++			}
++		}
++		dev = yaffs_inode_to_obj(inode)->my_dev;
++		if (attr->ia_valid & ATTR_SIZE) {
++			yaffs_trace(YAFFS_TRACE_OS,
++				"resize to %d(%x)",
++				(int)(attr->ia_size),
++				(int)(attr->ia_size));
++		}
++		yaffs_gross_lock(dev);
++		result = yaffs_set_attribs(yaffs_inode_to_obj(inode), attr);
++		if (result == YAFFS_OK) {
++			error = 0;
++		} else {
++			error = -EPERM;
++		}
++		yaffs_gross_unlock(dev);
++
++	}
++
++	yaffs_trace(YAFFS_TRACE_OS, "yaffs_setattr done returning %d", error);
++
++	return error;
++}
++
++static int yaffs_setxattr(struct dentry *dentry, const char *name,
++		   const void *value, size_t size, int flags)
++{
++	struct inode *inode = dentry->d_inode;
++	int error = 0;
++	struct yaffs_dev *dev;
++	struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
++
++	yaffs_trace(YAFFS_TRACE_OS, "yaffs_setxattr of object %d", obj->obj_id);
++
++	if (error == 0) {
++		int result;
++		dev = obj->my_dev;
++		yaffs_gross_lock(dev);
++		result = yaffs_set_xattrib(obj, name, value, size, flags);
++		if (result == YAFFS_OK)
++			error = 0;
++		else if (result < 0)
++			error = result;
++		yaffs_gross_unlock(dev);
++
++	}
++	yaffs_trace(YAFFS_TRACE_OS, "yaffs_setxattr done returning %d", error);
++
++	return error;
++}
++
++static ssize_t yaffs_getxattr(struct dentry * dentry, const char *name,
++			void *buff, size_t size)
++{
++	struct inode *inode = dentry->d_inode;
++	int error = 0;
++	struct yaffs_dev *dev;
++	struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
++
++	yaffs_trace(YAFFS_TRACE_OS,
++		"yaffs_getxattr \"%s\" from object %d",
++		name, obj->obj_id);
++
++	if (error == 0) {
++		dev = obj->my_dev;
++		yaffs_gross_lock(dev);
++		error = yaffs_get_xattrib(obj, name, buff, size);
++		yaffs_gross_unlock(dev);
++
++	}
++	yaffs_trace(YAFFS_TRACE_OS, "yaffs_getxattr done returning %d", error);
++
++	return error;
++}
++
++static int yaffs_removexattr(struct dentry *dentry, const char *name)
++{
++	struct inode *inode = dentry->d_inode;
++	int error = 0;
++	struct yaffs_dev *dev;
++	struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
++
++	yaffs_trace(YAFFS_TRACE_OS,
++		"yaffs_removexattr of object %d", obj->obj_id);
++
++	if (error == 0) {
++		int result;
++		dev = obj->my_dev;
++		yaffs_gross_lock(dev);
++		result = yaffs_remove_xattrib(obj, name);
++		if (result == YAFFS_OK)
++			error = 0;
++		else if (result < 0)
++			error = result;
++		yaffs_gross_unlock(dev);
++
++	}
++	yaffs_trace(YAFFS_TRACE_OS,
++		"yaffs_removexattr done returning %d", error);
++
++	return error;
++}
++
++static ssize_t yaffs_listxattr(struct dentry * dentry, char *buff, size_t size)
++{
++	struct inode *inode = dentry->d_inode;
++	int error = 0;
++	struct yaffs_dev *dev;
++	struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
++
++	yaffs_trace(YAFFS_TRACE_OS,
++		"yaffs_listxattr of object %d", obj->obj_id);
++
++	if (error == 0) {
++		dev = obj->my_dev;
++		yaffs_gross_lock(dev);
++		error = yaffs_list_xattrib(obj, buff, size);
++		yaffs_gross_unlock(dev);
++
++	}
++	yaffs_trace(YAFFS_TRACE_OS,
++		"yaffs_listxattr done returning %d", error);
++
++	return error;
++}
++
++
++static const struct inode_operations yaffs_file_inode_operations = {
++	.setattr = yaffs_setattr,
++	.setxattr = yaffs_setxattr,
++	.getxattr = yaffs_getxattr,
++	.listxattr = yaffs_listxattr,
++	.removexattr = yaffs_removexattr,
++};
++
++
++static int yaffs_readlink(struct dentry *dentry, char __user * buffer,
++			  int buflen)
++{
++	unsigned char *alias;
++	int ret;
++
++	struct yaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev;
++
++	yaffs_gross_lock(dev);
++
++	alias = yaffs_get_symlink_alias(yaffs_dentry_to_obj(dentry));
++
++	yaffs_gross_unlock(dev);
++
++	if (!alias)
++		return -ENOMEM;
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 15, 0)
++	ret = vfs_readlink(dentry, buffer, buflen, alias);
++#else
++	ret = readlink_copy(buffer, buflen, alias);
++#endif
++	kfree(alias);
++	return ret;
++}
++
++#if (YAFFS_NEW_FOLLOW_LINK == 1)
++static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
++{
++	void *ret;
++#else
++static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
++{
++	int ret
++#endif
++	unsigned char *alias;
++	int ret_int = 0;
++	struct yaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev;
++
++	yaffs_gross_lock(dev);
++
++	alias = yaffs_get_symlink_alias(yaffs_dentry_to_obj(dentry));
++	yaffs_gross_unlock(dev);
++
++	if (!alias) {
++		ret_int = -ENOMEM;
++		goto out;
++	}
++#if (YAFFS_NEW_FOLLOW_LINK == 1)
++	nd_set_link(nd, alias);
++	ret = alias;
++out:
++	if (ret_int)
++		ret = ERR_PTR(ret_int);
++	return ret;
++#else
++	ret = vfs_follow_link(nd, alias);
++	kfree(alias);
++out:
++	if (ret_int)
++		ret = ret_int;
++	return ret;
++#endif
++}
++
++
++#ifdef YAFFS_HAS_PUT_INODE
++
++/* For now put inode is just for debugging
++ * Put inode is called when the inode **structure** is put.
++ */
++static void yaffs_put_inode(struct inode *inode)
++{
++	yaffs_trace(YAFFS_TRACE_OS,
++		"yaffs_put_inode: ino %d, count %d"),
++		(int)inode->i_ino, atomic_read(&inode->i_count);
++
++}
++#endif
++
++#if (YAFFS_NEW_FOLLOW_LINK == 1)
++void yaffs_put_link(struct dentry *dentry, struct nameidata *nd, void *alias)
++{
++	kfree(alias);
++}
++#endif
++
++static const struct inode_operations yaffs_symlink_inode_operations = {
++	.readlink = yaffs_readlink,
++	.follow_link = yaffs_follow_link,
++#if (YAFFS_NEW_FOLLOW_LINK == 1)
++	.put_link = yaffs_put_link,
++#endif
++	.setattr = yaffs_setattr,
++	.setxattr = yaffs_setxattr,
++	.getxattr = yaffs_getxattr,
++	.listxattr = yaffs_listxattr,
++	.removexattr = yaffs_removexattr,
++};
++
++#ifdef YAFFS_USE_OWN_IGET
++
++static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino)
++{
++	struct inode *inode;
++	struct yaffs_obj *obj;
++	struct yaffs_dev *dev = yaffs_super_to_dev(sb);
++
++	yaffs_trace(YAFFS_TRACE_OS, "yaffs_iget for %lu", ino);
++
++	inode = iget_locked(sb, ino);
++	if (!inode)
++		return ERR_PTR(-ENOMEM);
++	if (!(inode->i_state & I_NEW))
++		return inode;
++
++	/* NB This is called as a side effect of other functions, but
++	 * we had to release the lock to prevent deadlocks, so
++	 * need to lock again.
++	 */
++
++	yaffs_gross_lock(dev);
++
++	obj = yaffs_find_by_number(dev, inode->i_ino);
++
++	yaffs_fill_inode_from_obj(inode, obj);
++
++	yaffs_gross_unlock(dev);
++
++	unlock_new_inode(inode);
++	return inode;
++}
++
++#else
++
++static void yaffs_read_inode(struct inode *inode)
++{
++	/* NB This is called as a side effect of other functions, but
++	 * we had to release the lock to prevent deadlocks, so
++	 * need to lock again.
++	 */
++
++	struct yaffs_obj *obj;
++	struct yaffs_dev *dev = yaffs_super_to_dev(inode->i_sb);
++
++	yaffs_trace(YAFFS_TRACE_OS,
++		"yaffs_read_inode for %d", (int)inode->i_ino);
++
++	if (current != yaffs_dev_to_lc(dev)->readdir_process)
++		yaffs_gross_lock(dev);
++
++	obj = yaffs_find_by_number(dev, inode->i_ino);
++
++	yaffs_fill_inode_from_obj(inode, obj);
++
++	if (current != yaffs_dev_to_lc(dev)->readdir_process)
++		yaffs_gross_unlock(dev);
++}
++
++#endif
++
++
++
++struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
++			      struct yaffs_obj *obj)
++{
++	struct inode *inode;
++
++	if (!sb) {
++		yaffs_trace(YAFFS_TRACE_OS,
++			"yaffs_get_inode for NULL super_block!!");
++		return NULL;
++
++	}
++
++	if (!obj) {
++		yaffs_trace(YAFFS_TRACE_OS,
++			"yaffs_get_inode for NULL object!!");
++		return NULL;
++
++	}
++
++	yaffs_trace(YAFFS_TRACE_OS,
++		"yaffs_get_inode for object %d", obj->obj_id);
++
++	inode = Y_IGET(sb, obj->obj_id);
++	if (IS_ERR(inode))
++		return NULL;
++
++	/* NB Side effect: iget calls back to yaffs_read_inode(). */
++	/* iget also increments the inode's i_count */
++	/* NB You can't be holding gross_lock or deadlock will happen! */
++
++	return inode;
++}
++
++
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
++#define YCRED(x) x
++#else
++#define YCRED(x) (x->cred)
++#endif
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0)
++#define YPROC_uid(p) (YCRED(p)->fsuid)
++#define YPROC_gid(p) (YCRED(p)->fsgid)
++#define EXTRACT_gid(x) x
++#define EXTRACT_uid(x) x
++#define MAKE_gid(x) x
++#define MAKE_uid(x) x
++#else
++#define YPROC_uid(p) from_kuid(&init_user_ns, YCRED(p)->fsuid)
++#define YPROC_gid(p) from_kgid(&init_user_ns, YCRED(p)->fsgid)
++#define EXTRACT_gid(x) from_kgid(&init_user_ns, x)
++#define EXTRACT_uid(x) from_kuid(&init_user_ns, x)
++#define MAKE_gid(x) make_kgid(&init_user_ns, x)
++#define MAKE_uid(x) make_kuid(&init_user_ns, x)
++#endif
++
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
++static int yaffs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode,
++		       dev_t rdev)
++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
++		       dev_t rdev)
++#else
++static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
++		       int rdev)
++#endif
++{
++	struct inode *inode;
++
++	struct yaffs_obj *obj = NULL;
++	struct yaffs_dev *dev;
++
++	struct yaffs_obj *parent = yaffs_inode_to_obj(dir);
++
++	int error = -ENOSPC;
++	uid_t uid = YPROC_uid(current);
++	gid_t gid =
++	    (dir->i_mode & S_ISGID) ? EXTRACT_gid(dir->i_gid) : YPROC_gid(current);
++
++	if ((dir->i_mode & S_ISGID) && S_ISDIR(mode))
++		mode |= S_ISGID;
++
++	if (parent) {
++		yaffs_trace(YAFFS_TRACE_OS,
++			"yaffs_mknod: parent object %d type %d",
++			parent->obj_id, parent->variant_type);
++	} else {
++		yaffs_trace(YAFFS_TRACE_OS,
++			"yaffs_mknod: could not get parent object");
++		return -EPERM;
++	}
++
++	yaffs_trace(YAFFS_TRACE_OS,
++		"yaffs_mknod: making oject for %s, mode %x dev %x",
++		dentry->d_name.name, mode, rdev);
++
++	dev = parent->my_dev;
++
++	yaffs_gross_lock(dev);
++
++	switch (mode & S_IFMT) {
++	default:
++		/* Special (socket, fifo, device...) */
++		yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making special");
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++		obj =
++		    yaffs_create_special(parent, dentry->d_name.name, mode, uid,
++					 gid, old_encode_dev(rdev));
++#else
++		obj =
++		    yaffs_create_special(parent, dentry->d_name.name, mode, uid,
++					 gid, rdev);
++#endif
++		break;
++	case S_IFREG:		/* file          */
++		yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making file");
++		obj = yaffs_create_file(parent, dentry->d_name.name, mode, uid,
++					gid);
++		break;
++	case S_IFDIR:		/* directory */
++		yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making directory");
++		obj = yaffs_create_dir(parent, dentry->d_name.name, mode,
++				       uid, gid);
++		break;
++	case S_IFLNK:		/* symlink */
++		yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making symlink");
++		obj = NULL;	/* Do we ever get here? */
++		break;
++	}
++
++	/* Can not call yaffs_get_inode() with gross lock held */
++	yaffs_gross_unlock(dev);
++
++	if (obj) {
++		inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj);
++		d_instantiate(dentry, inode);
++		update_dir_time(dir);
++		yaffs_trace(YAFFS_TRACE_OS,
++			"yaffs_mknod created object %d count = %d",
++			obj->obj_id, atomic_read(&inode->i_count));
++		error = 0;
++		yaffs_fill_inode_from_obj(dir, parent);
++	} else {
++		yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod failed making object");
++		error = -ENOMEM;
++	}
++
++	return error;
++}
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
++static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
++#else
++static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
++#endif
++{
++	int ret_val;
++	yaffs_trace(YAFFS_TRACE_OS, "yaffs_mkdir");
++	ret_val = yaffs_mknod(dir, dentry, mode | S_IFDIR, 0);
++	return ret_val;
++}
++
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
++static int yaffs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
++			bool dummy)
++#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
++static int yaffs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
++			struct nameidata *n)
++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
++			struct nameidata *n)
++#else
++static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode)
++#endif
++{
++	yaffs_trace(YAFFS_TRACE_OS, "yaffs_create");
++	return yaffs_mknod(dir, dentry, mode | S_IFREG, 0);
++}
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
++static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
++				   unsigned int dummy)
++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
++				   struct nameidata *n)
++#else
++static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry)
++#endif
++{
++	struct yaffs_obj *obj;
++	struct inode *inode = NULL;	/* NCB 2.5/2.6 needs NULL here */
++
++	struct yaffs_dev *dev = yaffs_inode_to_obj(dir)->my_dev;
++
++	if (current != yaffs_dev_to_lc(dev)->readdir_process)
++		yaffs_gross_lock(dev);
++
++	yaffs_trace(YAFFS_TRACE_OS, "yaffs_lookup for %d:%s",
++		yaffs_inode_to_obj(dir)->obj_id, dentry->d_name.name);
++
++	obj = yaffs_find_by_name(yaffs_inode_to_obj(dir), dentry->d_name.name);
++
++	obj = yaffs_get_equivalent_obj(obj);	/* in case it was a hardlink */
++
++	/* Can't hold gross lock when calling yaffs_get_inode() */
++	if (current != yaffs_dev_to_lc(dev)->readdir_process)
++		yaffs_gross_unlock(dev);
++
++	if (obj) {
++		yaffs_trace(YAFFS_TRACE_OS,
++			"yaffs_lookup found %d", obj->obj_id);
++
++		inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
++	} else {
++		yaffs_trace(YAFFS_TRACE_OS, "yaffs_lookup not found");
++
++	}
++
++/* added NCB for 2.5/6 compatability - forces add even if inode is
++ * NULL which creates dentry hash */
++	d_add(dentry, inode);
++
++	return NULL;
++}
++
++/*
++ * Create a link...
++ */
++static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
++		      struct dentry *dentry)
++{
++	struct inode *inode = old_dentry->d_inode;
++	struct yaffs_obj *obj = NULL;
++	struct yaffs_obj *link = NULL;
++	struct yaffs_dev *dev;
++
++	yaffs_trace(YAFFS_TRACE_OS, "yaffs_link");
++
++	obj = yaffs_inode_to_obj(inode);
++	dev = obj->my_dev;
++
++	yaffs_gross_lock(dev);
++
++	if (!S_ISDIR(inode->i_mode))	/* Don't link directories */
++		link =
++		    yaffs_link_obj(yaffs_inode_to_obj(dir), dentry->d_name.name,
++				   obj);
++
++	if (link) {
++		set_nlink(old_dentry->d_inode, yaffs_get_obj_link_count(obj));
++		d_instantiate(dentry, old_dentry->d_inode);
++		atomic_inc(&old_dentry->d_inode->i_count);
++		yaffs_trace(YAFFS_TRACE_OS,
++			"yaffs_link link count %d i_count %d",
++			old_dentry->d_inode->i_nlink,
++			atomic_read(&old_dentry->d_inode->i_count));
++	}
++
++	yaffs_gross_unlock(dev);
++
++	if (link) {
++		update_dir_time(dir);
++		return 0;
++	}
++
++	return -EPERM;
++}
++
++static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
++			 const char *symname)
++{
++	struct yaffs_obj *obj;
++	struct yaffs_dev *dev;
++	uid_t uid = YPROC_uid(current);
++	gid_t gid =
++	    (dir->i_mode & S_ISGID) ? EXTRACT_gid(dir->i_gid) : YPROC_gid(current);
++
++	yaffs_trace(YAFFS_TRACE_OS, "yaffs_symlink");
++
++	if (strnlen(dentry->d_name.name, YAFFS_MAX_NAME_LENGTH + 1) >
++				YAFFS_MAX_NAME_LENGTH)
++		return -ENAMETOOLONG;
++
++	if (strnlen(symname, YAFFS_MAX_ALIAS_LENGTH + 1) >
++				YAFFS_MAX_ALIAS_LENGTH)
++		return -ENAMETOOLONG;
++
++	dev = yaffs_inode_to_obj(dir)->my_dev;
++	yaffs_gross_lock(dev);
++	obj = yaffs_create_symlink(yaffs_inode_to_obj(dir), dentry->d_name.name,
++				   S_IFLNK | S_IRWXUGO, uid, gid, symname);
++	yaffs_gross_unlock(dev);
++
++	if (obj) {
++		struct inode *inode;
++
++		inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
++		d_instantiate(dentry, inode);
++		update_dir_time(dir);
++		yaffs_trace(YAFFS_TRACE_OS, "symlink created OK");
++		return 0;
++	} else {
++		yaffs_trace(YAFFS_TRACE_OS, "symlink not created");
++	}
++
++	return -ENOMEM;
++}
++
++/*
++ * The VFS layer already does all the dentry stuff for rename.
++ *
++ * NB: POSIX says you can rename an object over an old object of the same name
++ */
++static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
++			struct inode *new_dir, struct dentry *new_dentry)
++{
++	struct yaffs_dev *dev;
++	int ret_val = YAFFS_FAIL;
++	struct yaffs_obj *target;
++
++	yaffs_trace(YAFFS_TRACE_OS, "yaffs_rename");
++	dev = yaffs_inode_to_obj(old_dir)->my_dev;
++
++	yaffs_gross_lock(dev);
++
++	/* Check if the target is an existing directory that is not empty. */
++	target = yaffs_find_by_name(yaffs_inode_to_obj(new_dir),
++				    new_dentry->d_name.name);
++
++	if (target && target->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY &&
++	    !list_empty(&target->variant.dir_variant.children)) {
++
++		yaffs_trace(YAFFS_TRACE_OS, "target is non-empty dir");
++
++		ret_val = YAFFS_FAIL;
++	} else {
++		/* Now does unlinking internally using shadowing mechanism */
++		yaffs_trace(YAFFS_TRACE_OS, "calling yaffs_rename_obj");
++
++		ret_val = yaffs_rename_obj(yaffs_inode_to_obj(old_dir),
++					   old_dentry->d_name.name,
++					   yaffs_inode_to_obj(new_dir),
++					   new_dentry->d_name.name);
++	}
++	yaffs_gross_unlock(dev);
++
++	if (ret_val == YAFFS_OK) {
++		if (target)
++			inode_dec_link_count(new_dentry->d_inode);
++
++		update_dir_time(old_dir);
++		if (old_dir != new_dir)
++			update_dir_time(new_dir);
++		return 0;
++	} else {
++		return -ENOTEMPTY;
++	}
++}
++
++
++
++
++static int yaffs_unlink(struct inode *dir, struct dentry *dentry)
++{
++	int ret_val;
++
++	struct yaffs_dev *dev;
++	struct yaffs_obj *obj;
++
++	yaffs_trace(YAFFS_TRACE_OS, "yaffs_unlink %d:%s",
++		(int)(dir->i_ino), dentry->d_name.name);
++	obj = yaffs_inode_to_obj(dir);
++	dev = obj->my_dev;
++
++	yaffs_gross_lock(dev);
++
++	ret_val = yaffs_unlinker(obj, dentry->d_name.name);
++
++	if (ret_val == YAFFS_OK) {
++		inode_dec_link_count(dentry->d_inode);
++		dir->i_version++;
++		yaffs_gross_unlock(dev);
++		update_dir_time(dir);
++		return 0;
++	}
++	yaffs_gross_unlock(dev);
++	return -ENOTEMPTY;
++}
++
++
++
++static const struct inode_operations yaffs_dir_inode_operations = {
++	.create = yaffs_create,
++	.lookup = yaffs_lookup,
++	.link = yaffs_link,
++	.unlink = yaffs_unlink,
++	.symlink = yaffs_symlink,
++	.mkdir = yaffs_mkdir,
++	.rmdir = yaffs_unlink,
++	.mknod = yaffs_mknod,
++	.rename = yaffs_rename,
++	.setattr = yaffs_setattr,
++	.setxattr = yaffs_setxattr,
++	.getxattr = yaffs_getxattr,
++	.listxattr = yaffs_listxattr,
++	.removexattr = yaffs_removexattr,
++};
++
++/*-----------------------------------------------------------------*/
++/* Directory search context allows us to unlock access to yaffs during
++ * filldir without causing problems with the directory being modified.
++ * This is similar to the tried and tested mechanism used in yaffs direct.
++ *
++ * A search context iterates along a doubly linked list of siblings in the
++ * directory. If the iterating object is deleted then this would corrupt
++ * the list iteration, likely causing a crash. The search context avoids
++ * this by using the remove_obj_fn to move the search context to the
++ * next object before the object is deleted.
++ *
++ * Many readdirs (and thus seach conexts) may be alive simulateously so
++ * each struct yaffs_dev has a list of these.
++ *
++ * A seach context lives for the duration of a readdir.
++ *
++ * All these functions must be called while yaffs is locked.
++ */
++
++struct yaffs_search_context {
++	struct yaffs_dev *dev;
++	struct yaffs_obj *dir_obj;
++	struct yaffs_obj *next_return;
++	struct list_head others;
++};
++
++/*
++ * yaffs_new_search() creates a new search context, initialises it and
++ * adds it to the device's search context list.
++ *
++ * Called at start of readdir.
++ */
++static struct yaffs_search_context *yaffs_new_search(struct yaffs_obj *dir)
++{
++	struct yaffs_dev *dev = dir->my_dev;
++	struct yaffs_search_context *sc =
++	    kmalloc(sizeof(struct yaffs_search_context), GFP_NOFS);
++	if (sc) {
++		sc->dir_obj = dir;
++		sc->dev = dev;
++		if (list_empty(&sc->dir_obj->variant.dir_variant.children))
++			sc->next_return = NULL;
++		else
++			sc->next_return =
++			    list_entry(dir->variant.dir_variant.children.next,
++				       struct yaffs_obj, siblings);
++		INIT_LIST_HEAD(&sc->others);
++		list_add(&sc->others, &(yaffs_dev_to_lc(dev)->search_contexts));
++	}
++	return sc;
++}
++
++/*
++ * yaffs_search_end() disposes of a search context and cleans up.
++ */
++static void yaffs_search_end(struct yaffs_search_context *sc)
++{
++	if (sc) {
++		list_del(&sc->others);
++		kfree(sc);
++	}
++}
++
++/*
++ * yaffs_search_advance() moves a search context to the next object.
++ * Called when the search iterates or when an object removal causes
++ * the search context to be moved to the next object.
++ */
++static void yaffs_search_advance(struct yaffs_search_context *sc)
++{
++	if (!sc)
++		return;
++
++	if (sc->next_return == NULL ||
++	    list_empty(&sc->dir_obj->variant.dir_variant.children))
++		sc->next_return = NULL;
++	else {
++		struct list_head *next = sc->next_return->siblings.next;
++
++		if (next == &sc->dir_obj->variant.dir_variant.children)
++			sc->next_return = NULL;	/* end of list */
++		else
++			sc->next_return =
++			    list_entry(next, struct yaffs_obj, siblings);
++	}
++}
++
++/*
++ * yaffs_remove_obj_callback() is called when an object is unlinked.
++ * We check open search contexts and advance any which are currently
++ * on the object being iterated.
++ */
++static void yaffs_remove_obj_callback(struct yaffs_obj *obj)
++{
++
++	struct list_head *i;
++	struct yaffs_search_context *sc;
++	struct list_head *search_contexts =
++	    &(yaffs_dev_to_lc(obj->my_dev)->search_contexts);
++
++	/* Iterate through the directory search contexts.
++	 * If any are currently on the object being removed, then advance
++	 * the search context to the next object to prevent a hanging pointer.
++	 */
++	list_for_each(i, search_contexts) {
++		sc = list_entry(i, struct yaffs_search_context, others);
++		if (sc->next_return == obj)
++			yaffs_search_advance(sc);
++	}
++
++}
++
++
++/*-----------------------------------------------------------------*/
++
++#ifdef YAFFS_USE_DIR_ITERATE
++static int yaffs_iterate(struct file *f, struct dir_context *dc)
++{
++	struct yaffs_obj *obj;
++	struct yaffs_dev *dev;
++	struct yaffs_search_context *sc;
++	unsigned long curoffs;
++	struct yaffs_obj *l;
++	int ret_val = 0;
++
++	char name[YAFFS_MAX_NAME_LENGTH + 1];
++
++	obj = yaffs_dentry_to_obj(f->f_dentry);
++	dev = obj->my_dev;
++
++	yaffs_gross_lock(dev);
++
++	yaffs_dev_to_lc(dev)->readdir_process = current;
++
++	sc = yaffs_new_search(obj);
++	if (!sc) {
++		ret_val = -ENOMEM;
++		goto out;
++	}
++
++	if (!dir_emit_dots(f, dc))
++		return 0;
++
++	curoffs = 1;
++
++	while (sc->next_return) {
++		curoffs++;
++		l = sc->next_return;
++		if (curoffs >= dc->pos) {
++			int this_inode = yaffs_get_obj_inode(l);
++			int this_type = yaffs_get_obj_type(l);
++
++			yaffs_get_obj_name(l, name, YAFFS_MAX_NAME_LENGTH + 1);
++			yaffs_trace(YAFFS_TRACE_OS,
++				"yaffs_readdir: %s inode %d",
++				name, yaffs_get_obj_inode(l));
++
++			yaffs_gross_unlock(dev);
++
++			if (!dir_emit(dc,
++				      name,
++				      strlen(name),
++				      this_inode,
++				      this_type)) {
++				yaffs_gross_lock(dev);
++				goto out;
++			}
++
++			yaffs_gross_lock(dev);
++
++			dc->pos++;
++			f->f_pos++;
++		}
++		yaffs_search_advance(sc);
++	}
++
++out:
++	yaffs_search_end(sc);
++	yaffs_dev_to_lc(dev)->readdir_process = NULL;
++	yaffs_gross_unlock(dev);
++
++	return ret_val;
++}
++
++#else
++
++static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
++{
++	struct yaffs_obj *obj;
++	struct yaffs_dev *dev;
++	struct yaffs_search_context *sc;
++	struct inode *inode = f->f_dentry->d_inode;
++	unsigned long offset, curoffs;
++	struct yaffs_obj *l;
++	int ret_val = 0;
++
++	char name[YAFFS_MAX_NAME_LENGTH + 1];
++
++	obj = yaffs_dentry_to_obj(f->f_dentry);
++	dev = obj->my_dev;
++
++	yaffs_gross_lock(dev);
++
++	yaffs_dev_to_lc(dev)->readdir_process = current;
++
++	offset = f->f_pos;
++
++	sc = yaffs_new_search(obj);
++	if (!sc) {
++		ret_val = -ENOMEM;
++		goto out;
++	}
++
++	yaffs_trace(YAFFS_TRACE_OS,
++		"yaffs_readdir: starting at %d", (int)offset);
++
++	if (offset == 0) {
++		yaffs_trace(YAFFS_TRACE_OS,
++			"yaffs_readdir: entry . ino %d",
++			(int)inode->i_ino);
++		yaffs_gross_unlock(dev);
++		if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0) {
++			yaffs_gross_lock(dev);
++			goto out;
++		}
++		yaffs_gross_lock(dev);
++		offset++;
++		f->f_pos++;
++	}
++	if (offset == 1) {
++		yaffs_trace(YAFFS_TRACE_OS,
++			"yaffs_readdir: entry .. ino %d",
++			(int)f->f_dentry->d_parent->d_inode->i_ino);
++		yaffs_gross_unlock(dev);
++		if (filldir(dirent, "..", 2, offset,
++			    f->f_dentry->d_parent->d_inode->i_ino,
++			    DT_DIR) < 0) {
++			yaffs_gross_lock(dev);
++			goto out;
++		}
++		yaffs_gross_lock(dev);
++		offset++;
++		f->f_pos++;
++	}
++
++	curoffs = 1;
++
++	/* If the directory has changed since the open or last call to
++	   readdir, rewind to after the 2 canned entries. */
++	if (f->f_version != inode->i_version) {
++		offset = 2;
++		f->f_pos = offset;
++		f->f_version = inode->i_version;
++	}
++
++	while (sc->next_return) {
++		curoffs++;
++		l = sc->next_return;
++		if (curoffs >= offset) {
++			int this_inode = yaffs_get_obj_inode(l);
++			int this_type = yaffs_get_obj_type(l);
++
++			yaffs_get_obj_name(l, name, YAFFS_MAX_NAME_LENGTH + 1);
++			yaffs_trace(YAFFS_TRACE_OS,
++				"yaffs_readdir: %s inode %d",
++				name, yaffs_get_obj_inode(l));
++
++			yaffs_gross_unlock(dev);
++
++			if (filldir(dirent,
++				    name,
++				    strlen(name),
++				    offset, this_inode, this_type) < 0) {
++				yaffs_gross_lock(dev);
++				goto out;
++			}
++
++			yaffs_gross_lock(dev);
++
++			offset++;
++			f->f_pos++;
++		}
++		yaffs_search_advance(sc);
++	}
++
++out:
++	yaffs_search_end(sc);
++	yaffs_dev_to_lc(dev)->readdir_process = NULL;
++	yaffs_gross_unlock(dev);
++
++	return ret_val;
++}
++
++#endif
++
++static const struct file_operations yaffs_dir_operations = {
++	.read = generic_read_dir,
++#ifdef YAFFS_USE_DIR_ITERATE
++	.iterate = yaffs_iterate,
++#else
++	.readdir = yaffs_readdir,
++#endif
++	.fsync = yaffs_sync_object,
++	.llseek = generic_file_llseek,
++};
++
++static void yaffs_fill_inode_from_obj(struct inode *inode,
++				      struct yaffs_obj *obj)
++{
++	if (inode && obj) {
++
++		/* Check mode against the variant type and attempt to repair if broken. */
++		u32 mode = obj->yst_mode;
++		switch (obj->variant_type) {
++		case YAFFS_OBJECT_TYPE_FILE:
++			if (!S_ISREG(mode)) {
++				obj->yst_mode &= ~S_IFMT;
++				obj->yst_mode |= S_IFREG;
++			}
++
++			break;
++		case YAFFS_OBJECT_TYPE_SYMLINK:
++			if (!S_ISLNK(mode)) {
++				obj->yst_mode &= ~S_IFMT;
++				obj->yst_mode |= S_IFLNK;
++			}
++
++			break;
++		case YAFFS_OBJECT_TYPE_DIRECTORY:
++			if (!S_ISDIR(mode)) {
++				obj->yst_mode &= ~S_IFMT;
++				obj->yst_mode |= S_IFDIR;
++			}
++
++			break;
++		case YAFFS_OBJECT_TYPE_UNKNOWN:
++		case YAFFS_OBJECT_TYPE_HARDLINK:
++		case YAFFS_OBJECT_TYPE_SPECIAL:
++		default:
++			/* TODO? */
++			break;
++		}
++
++		inode->i_flags |= S_NOATIME;
++
++		inode->i_ino = obj->obj_id;
++		inode->i_mode = obj->yst_mode;
++		inode->i_uid = MAKE_uid(obj->yst_uid);
++		inode->i_gid = MAKE_gid(obj->yst_gid);
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
++		inode->i_blksize = inode->i_sb->s_blocksize;
++#endif
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++
++		inode->i_rdev = old_decode_dev(obj->yst_rdev);
++		inode->i_atime.tv_sec = (time_t) (obj->yst_atime);
++		inode->i_atime.tv_nsec = 0;
++		inode->i_mtime.tv_sec = (time_t) obj->yst_mtime;
++		inode->i_mtime.tv_nsec = 0;
++		inode->i_ctime.tv_sec = (time_t) obj->yst_ctime;
++		inode->i_ctime.tv_nsec = 0;
++#else
++		inode->i_rdev = obj->yst_rdev;
++		inode->i_atime = obj->yst_atime;
++		inode->i_mtime = obj->yst_mtime;
++		inode->i_ctime = obj->yst_ctime;
++#endif
++		inode->i_size = yaffs_get_obj_length(obj);
++		inode->i_blocks = (inode->i_size + 511) >> 9;
++
++		set_nlink(inode, yaffs_get_obj_link_count(obj));
++
++		yaffs_trace(YAFFS_TRACE_OS,
++			"yaffs_fill_inode mode %x uid %d gid %d size %lld count %d",
++			inode->i_mode, obj->yst_uid, obj->yst_gid,
++			inode->i_size, atomic_read(&inode->i_count));
++
++		switch (obj->yst_mode & S_IFMT) {
++		default:	/* fifo, device or socket */
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++			init_special_inode(inode, obj->yst_mode,
++					   old_decode_dev(obj->yst_rdev));
++#else
++			init_special_inode(inode, obj->yst_mode,
++					   (dev_t) (obj->yst_rdev));
++#endif
++			break;
++		case S_IFREG:	/* file */
++			inode->i_op = &yaffs_file_inode_operations;
++			inode->i_fop = &yaffs_file_operations;
++			inode->i_mapping->a_ops =
++			    &yaffs_file_address_operations;
++			break;
++		case S_IFDIR:	/* directory */
++			inode->i_op = &yaffs_dir_inode_operations;
++			inode->i_fop = &yaffs_dir_operations;
++			break;
++		case S_IFLNK:	/* symlink */
++			inode->i_op = &yaffs_symlink_inode_operations;
++			break;
++		}
++
++		yaffs_inode_to_obj_lv(inode) = obj;
++
++		obj->my_inode = inode;
++
++	} else {
++		yaffs_trace(YAFFS_TRACE_OS,
++			"yaffs_fill_inode invalid parameters");
++	}
++
++}
++
++
++
++/*
++ * yaffs background thread functions .
++ * yaffs_bg_thread_fn() the thread function
++ * yaffs_bg_start() launches the background thread.
++ * yaffs_bg_stop() cleans up the background thread.
++ *
++ * NB:
++ * The thread should only run after the yaffs is initialised
++ * The thread should be stopped before yaffs is unmounted.
++ * The thread should not do any writing while the fs is in read only.
++ */
++
++static unsigned yaffs_bg_gc_urgency(struct yaffs_dev *dev)
++{
++	unsigned erased_chunks =
++	    dev->n_erased_blocks * dev->param.chunks_per_block;
++	struct yaffs_linux_context *context = yaffs_dev_to_lc(dev);
++	unsigned scattered = 0;	/* Free chunks not in an erased block */
++
++	if (erased_chunks < dev->n_free_chunks)
++		scattered = (dev->n_free_chunks - erased_chunks);
++
++	if (!context->bg_running)
++		return 0;
++	else if (scattered < (dev->param.chunks_per_block * 2))
++		return 0;
++	else if (erased_chunks > dev->n_free_chunks / 2)
++		return 0;
++	else if (erased_chunks > dev->n_free_chunks / 4)
++		return 1;
++	else
++		return 2;
++}
++
++#ifdef YAFFS_COMPILE_BACKGROUND
++
++void yaffs_background_waker(unsigned long data)
++{
++	wake_up_process((struct task_struct *)data);
++}
++
++static int yaffs_bg_thread_fn(void *data)
++{
++	struct yaffs_dev *dev = (struct yaffs_dev *)data;
++	struct yaffs_linux_context *context = yaffs_dev_to_lc(dev);
++	unsigned long now = jiffies;
++	unsigned long next_dir_update = now;
++	unsigned long next_gc = now;
++	unsigned long expires;
++	unsigned int urgency;
++
++	int gc_result;
++	struct timer_list timer;
++
++	yaffs_trace(YAFFS_TRACE_BACKGROUND,
++		"yaffs_background starting for dev %p", (void *)dev);
++
++#ifdef YAFFS_COMPILE_FREEZER
++	set_freezable();
++#endif
++	while (context->bg_running) {
++		yaffs_trace(YAFFS_TRACE_BACKGROUND, "yaffs_background");
++
++		if (kthread_should_stop())
++			break;
++
++#ifdef YAFFS_COMPILE_FREEZER
++		if (try_to_freeze())
++			continue;
++#endif
++		yaffs_gross_lock(dev);
++
++		now = jiffies;
++
++		if (time_after(now, next_dir_update) && yaffs_bg_enable) {
++			yaffs_update_dirty_dirs(dev);
++			next_dir_update = now + HZ;
++		}
++
++		if (time_after(now, next_gc) && yaffs_bg_enable) {
++			if (!dev->is_checkpointed) {
++				urgency = yaffs_bg_gc_urgency(dev);
++				gc_result = yaffs_bg_gc(dev, urgency);
++				if (urgency > 1)
++					next_gc = now + HZ / 20 + 1;
++				else if (urgency > 0)
++					next_gc = now + HZ / 10 + 1;
++				else
++					next_gc = now + HZ * 2;
++			} else	{
++			        /*
++				 * gc not running so set to next_dir_update
++				 * to cut down on wake ups
++				 */
++				next_gc = next_dir_update;
++                        }
++		}
++		yaffs_gross_unlock(dev);
++#if 1
++		expires = next_dir_update;
++		if (time_before(next_gc, expires))
++			expires = next_gc;
++		if (time_before(expires, now))
++			expires = now + HZ;
++
++		Y_INIT_TIMER(&timer);
++		timer.expires = expires + 1;
++		timer.data = (unsigned long)current;
++		timer.function = yaffs_background_waker;
++
++		set_current_state(TASK_INTERRUPTIBLE);
++		add_timer(&timer);
++		schedule();
++		del_timer_sync(&timer);
++#else
++		msleep(10);
++#endif
++	}
++
++	return 0;
++}
++
++static int yaffs_bg_start(struct yaffs_dev *dev)
++{
++	int retval = 0;
++	struct yaffs_linux_context *context = yaffs_dev_to_lc(dev);
++
++	if (dev->read_only)
++		return -1;
++
++	context->bg_running = 1;
++
++	context->bg_thread = kthread_run(yaffs_bg_thread_fn,
++					 (void *)dev, "yaffs-bg-%d",
++					 context->mount_id);
++
++	if (IS_ERR(context->bg_thread)) {
++		retval = PTR_ERR(context->bg_thread);
++		context->bg_thread = NULL;
++		context->bg_running = 0;
++	}
++	return retval;
++}
++
++static void yaffs_bg_stop(struct yaffs_dev *dev)
++{
++	struct yaffs_linux_context *ctxt = yaffs_dev_to_lc(dev);
++
++	ctxt->bg_running = 0;
++
++	if (ctxt->bg_thread) {
++		kthread_stop(ctxt->bg_thread);
++		ctxt->bg_thread = NULL;
++	}
++}
++#else
++static int yaffs_bg_thread_fn(void *data)
++{
++	return 0;
++}
++
++static int yaffs_bg_start(struct yaffs_dev *dev)
++{
++	return 0;
++}
++
++static void yaffs_bg_stop(struct yaffs_dev *dev)
++{
++}
++#endif
++
++
++static void yaffs_flush_inodes(struct super_block *sb)
++{
++	struct inode *iptr;
++	struct yaffs_obj *obj;
++
++	list_for_each_entry(iptr, &sb->s_inodes, i_sb_list) {
++		obj = yaffs_inode_to_obj(iptr);
++		if (obj) {
++			yaffs_trace(YAFFS_TRACE_OS,
++				"flushing obj %d",
++				obj->obj_id);
++			yaffs_flush_file(obj, 1, 0, 0);
++		}
++	}
++}
++
++static void yaffs_flush_super(struct super_block *sb, int do_checkpoint)
++{
++	struct yaffs_dev *dev = yaffs_super_to_dev(sb);
++	if (!dev)
++		return;
++
++	yaffs_flush_inodes(sb);
++	yaffs_update_dirty_dirs(dev);
++	yaffs_flush_whole_cache(dev, 1);
++	if (do_checkpoint)
++		yaffs_checkpoint_save(dev);
++}
++
++static LIST_HEAD(yaffs_context_list);
++struct mutex yaffs_context_lock;
++
++static void yaffs_put_super(struct super_block *sb)
++{
++	struct yaffs_dev *dev = yaffs_super_to_dev(sb);
++	struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
++
++	yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_ALWAYS,
++			"yaffs_put_super");
++
++	yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND,
++		"Shutting down yaffs background thread");
++	yaffs_bg_stop(dev);
++	yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND,
++		"yaffs background thread shut down");
++
++	yaffs_gross_lock(dev);
++
++	yaffs_flush_super(sb, 1);
++
++	yaffs_deinitialise(dev);
++
++	yaffs_gross_unlock(dev);
++
++	mutex_lock(&yaffs_context_lock);
++	list_del_init(&(yaffs_dev_to_lc(dev)->context_list));
++	mutex_unlock(&yaffs_context_lock);
++
++	if (yaffs_dev_to_lc(dev)->spare_buffer) {
++		kfree(yaffs_dev_to_lc(dev)->spare_buffer);
++		yaffs_dev_to_lc(dev)->spare_buffer = NULL;
++	}
++
++	kfree(dev);
++
++	yaffs_put_mtd_device(mtd);
++
++	yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_ALWAYS,
++			"yaffs_put_super done");
++}
++
++
++static unsigned yaffs_gc_control_callback(struct yaffs_dev *dev)
++{
++	return yaffs_gc_control;
++}
++
++
++#ifdef YAFFS_COMPILE_EXPORTFS
++
++static struct inode *yaffs2_nfs_get_inode(struct super_block *sb, uint64_t ino,
++					  uint32_t generation)
++{
++	return Y_IGET(sb, ino);
++}
++
++static struct dentry *yaffs2_fh_to_dentry(struct super_block *sb,
++					  struct fid *fid, int fh_len,
++					  int fh_type)
++{
++	return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
++				    yaffs2_nfs_get_inode);
++}
++
++static struct dentry *yaffs2_fh_to_parent(struct super_block *sb,
++					  struct fid *fid, int fh_len,
++					  int fh_type)
++{
++	return generic_fh_to_parent(sb, fid, fh_len, fh_type,
++				    yaffs2_nfs_get_inode);
++}
++
++struct dentry *yaffs2_get_parent(struct dentry *dentry)
++{
++
++	struct super_block *sb = dentry->d_inode->i_sb;
++	struct dentry *parent = ERR_PTR(-ENOENT);
++	struct inode *inode;
++	unsigned long parent_ino;
++	struct yaffs_obj *d_obj;
++	struct yaffs_obj *parent_obj;
++
++	d_obj = yaffs_inode_to_obj(dentry->d_inode);
++
++	if (d_obj) {
++		parent_obj = d_obj->parent;
++		if (parent_obj) {
++			parent_ino = yaffs_get_obj_inode(parent_obj);
++			inode = Y_IGET(sb, parent_ino);
++
++			if (IS_ERR(inode)) {
++				parent = ERR_CAST(inode);
++			} else {
++				parent = d_obtain_alias(inode);
++				if (!IS_ERR(parent)) {
++					parent = ERR_PTR(-ENOMEM);
++					iput(inode);
++				}
++			}
++		}
++	}
++
++	return parent;
++}
++
++/* Just declare a zero structure as a NULL value implies
++ * using the default functions of exportfs.
++ */
++
++static struct export_operations yaffs_export_ops = {
++	.fh_to_dentry = yaffs2_fh_to_dentry,
++	.fh_to_parent = yaffs2_fh_to_parent,
++	.get_parent = yaffs2_get_parent,
++};
++
++#endif
++
++static void yaffs_unstitch_obj(struct inode *inode, struct yaffs_obj *obj)
++{
++	/* Clear the association between the inode and
++	 * the struct yaffs_obj.
++	 */
++	obj->my_inode = NULL;
++	yaffs_inode_to_obj_lv(inode) = NULL;
++
++	/* If the object freeing was deferred, then the real
++	 * free happens now.
++	 * This should fix the inode inconsistency problem.
++	 */
++	yaffs_handle_defered_free(obj);
++}
++
++#ifdef YAFFS_HAS_EVICT_INODE
++/* yaffs_evict_inode combines into one operation what was previously done in
++ * yaffs_clear_inode() and yaffs_delete_inode()
++ *
++ */
++static void yaffs_evict_inode(struct inode *inode)
++{
++	struct yaffs_obj *obj;
++	struct yaffs_dev *dev;
++	int deleteme = 0;
++
++	obj = yaffs_inode_to_obj(inode);
++
++	yaffs_trace(YAFFS_TRACE_OS,
++		"yaffs_evict_inode: ino %d, count %d %s",
++		(int)inode->i_ino, atomic_read(&inode->i_count),
++		obj ? "object exists" : "null object");
++
++	if (!inode->i_nlink && !is_bad_inode(inode))
++		deleteme = 1;
++	truncate_inode_pages(&inode->i_data, 0);
++	Y_CLEAR_INODE(inode);
++
++	if (deleteme && obj) {
++		dev = obj->my_dev;
++		yaffs_gross_lock(dev);
++		yaffs_del_obj(obj);
++		yaffs_gross_unlock(dev);
++	}
++	if (obj) {
++		dev = obj->my_dev;
++		yaffs_gross_lock(dev);
++		yaffs_unstitch_obj(inode, obj);
++		yaffs_gross_unlock(dev);
++	}
++}
++#else
++
++/* clear is called to tell the fs to release any per-inode data it holds.
++ * The object might still exist on disk and is just being thrown out of the cache
++ * or else the object has actually been deleted and we're being called via
++ * the chain
++ *   yaffs_delete_inode() -> clear_inode()->yaffs_clear_inode()
++ */
++
++static void yaffs_clear_inode(struct inode *inode)
++{
++	struct yaffs_obj *obj;
++	struct yaffs_dev *dev;
++
++	obj = yaffs_inode_to_obj(inode);
++
++	yaffs_trace(YAFFS_TRACE_OS,
++		"yaffs_clear_inode: ino %d, count %d %s",
++		(int)inode->i_ino, atomic_read(&inode->i_count),
++		obj ? "object exists" : "null object");
++
++	if (obj) {
++		dev = obj->my_dev;
++		yaffs_gross_lock(dev);
++		yaffs_unstitch_obj(inode, obj);
++		yaffs_gross_unlock(dev);
++	}
++
++}
++
++/* delete is called when the link count is zero and the inode
++ * is put (ie. nobody wants to know about it anymore, time to
++ * delete the file).
++ * NB Must call clear_inode()
++ */
++static void yaffs_delete_inode(struct inode *inode)
++{
++	struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
++	struct yaffs_dev *dev;
++
++	yaffs_trace(YAFFS_TRACE_OS,
++		"yaffs_delete_inode: ino %d, count %d %s",
++		(int)inode->i_ino, atomic_read(&inode->i_count),
++		obj ? "object exists" : "null object");
++
++	if (obj) {
++		dev = obj->my_dev;
++		yaffs_gross_lock(dev);
++		yaffs_del_obj(obj);
++		yaffs_gross_unlock(dev);
++	}
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
++	truncate_inode_pages(&inode->i_data, 0);
++#endif
++	clear_inode(inode);
++}
++#endif
++
++
++
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
++static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf)
++{
++	struct yaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev;
++	struct super_block *sb = dentry->d_sb;
++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf)
++{
++	struct yaffs_dev *dev = yaffs_super_to_dev(sb);
++#else
++static int yaffs_statfs(struct super_block *sb, struct statfs *buf)
++{
++	struct yaffs_dev *dev = yaffs_super_to_dev(sb);
++#endif
++
++	yaffs_trace(YAFFS_TRACE_OS, "yaffs_statfs");
++
++	yaffs_gross_lock(dev);
++
++	buf->f_type = YAFFS_MAGIC;
++	buf->f_bsize = sb->s_blocksize;
++	buf->f_namelen = 255;
++
++	if (dev->data_bytes_per_chunk & (dev->data_bytes_per_chunk - 1)) {
++		/* Do this if chunk size is not a power of 2 */
++
++		uint64_t bytes_in_dev;
++		uint64_t bytes_free;
++
++		bytes_in_dev =
++		    ((uint64_t)
++		     ((dev->param.end_block - dev->param.start_block +
++		       1))) * ((uint64_t) (dev->param.chunks_per_block *
++					   dev->data_bytes_per_chunk));
++
++		do_div(bytes_in_dev, sb->s_blocksize);	/* bytes_in_dev becomes the number of blocks */
++		buf->f_blocks = bytes_in_dev;
++
++		bytes_free = ((uint64_t) (yaffs_get_n_free_chunks(dev))) *
++		    ((uint64_t) (dev->data_bytes_per_chunk));
++
++		do_div(bytes_free, sb->s_blocksize);
++
++		buf->f_bfree = bytes_free;
++
++	} else if (sb->s_blocksize > dev->data_bytes_per_chunk) {
++
++		buf->f_blocks =
++		    (dev->param.end_block - dev->param.start_block + 1) *
++		    dev->param.chunks_per_block /
++		    (sb->s_blocksize / dev->data_bytes_per_chunk);
++		buf->f_bfree =
++		    yaffs_get_n_free_chunks(dev) /
++		    (sb->s_blocksize / dev->data_bytes_per_chunk);
++	} else {
++		buf->f_blocks =
++		    (dev->param.end_block - dev->param.start_block + 1) *
++		    dev->param.chunks_per_block *
++		    (dev->data_bytes_per_chunk / sb->s_blocksize);
++
++		buf->f_bfree =
++		    yaffs_get_n_free_chunks(dev) *
++		    (dev->data_bytes_per_chunk / sb->s_blocksize);
++	}
++
++	buf->f_files = 0;
++	buf->f_ffree = 0;
++	buf->f_bavail = buf->f_bfree;
++
++	yaffs_gross_unlock(dev);
++	return 0;
++}
++
++
++
++static int yaffs_do_sync_fs(struct super_block *sb, int request_checkpoint)
++{
++
++	struct yaffs_dev *dev = yaffs_super_to_dev(sb);
++	unsigned int oneshot_checkpoint = (yaffs_auto_checkpoint & 4);
++	unsigned gc_urgent = yaffs_bg_gc_urgency(dev);
++	int do_checkpoint;
++	int dirty = yaffs_check_super_dirty(dev);
++
++	yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND,
++		"yaffs_do_sync_fs: gc-urgency %d %s %s%s",
++		gc_urgent,
++		dirty ? "dirty" : "clean",
++		request_checkpoint ? "checkpoint requested" : "no checkpoint",
++		oneshot_checkpoint ? " one-shot" : "");
++
++	yaffs_gross_lock(dev);
++	do_checkpoint = ((request_checkpoint && !gc_urgent) ||
++			 oneshot_checkpoint) && !dev->is_checkpointed;
++
++	if (dirty || do_checkpoint) {
++		yaffs_flush_super(sb, !dev->is_checkpointed && do_checkpoint);
++		yaffs_clear_super_dirty(dev);
++		if (oneshot_checkpoint)
++			yaffs_auto_checkpoint &= ~4;
++	}
++	yaffs_gross_unlock(dev);
++
++	return 0;
++}
++
++
++#ifdef YAFFS_HAS_WRITE_SUPER
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
++static void yaffs_write_super(struct super_block *sb)
++#else
++static int yaffs_write_super(struct super_block *sb)
++#endif
++{
++	unsigned request_checkpoint = (yaffs_auto_checkpoint >= 2);
++
++	yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND,
++		"yaffs_write_super %s",
++		request_checkpoint ? " checkpt" : "");
++
++	yaffs_do_sync_fs(sb, request_checkpoint);
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18))
++	return 0;
++#endif
++}
++#endif
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
++static int yaffs_sync_fs(struct super_block *sb, int wait)
++#else
++static int yaffs_sync_fs(struct super_block *sb)
++#endif
++{
++	unsigned request_checkpoint = (yaffs_auto_checkpoint >= 1);
++
++	yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC,
++		"yaffs_sync_fs%s", request_checkpoint ? " checkpt" : "");
++
++	yaffs_do_sync_fs(sb, request_checkpoint);
++
++	return 0;
++}
++
++/* the function only is used to change dev->read_only when this file system
++ * is remounted.
++ */
++static int yaffs_remount_fs(struct super_block *sb, int *flags, char *data)
++{
++	int read_only = 0;
++	struct mtd_info *mtd;
++	struct yaffs_dev *dev = 0;
++
++	/* Get the device */
++	mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
++	if (!mtd) {
++		yaffs_trace(YAFFS_TRACE_ALWAYS,
++			"MTD device #%u doesn't appear to exist",
++			MINOR(sb->s_dev));
++		return 1;
++	}
++
++	/* Check it's NAND */
++	if (mtd->type != MTD_NANDFLASH) {
++		yaffs_trace(YAFFS_TRACE_ALWAYS,
++			"MTD device is not NAND it's type %d",
++			mtd->type);
++		return 1;
++	}
++
++	read_only = ((*flags & MS_RDONLY) != 0);
++	if (!read_only && !(mtd->flags & MTD_WRITEABLE)) {
++		read_only = 1;
++		printk(KERN_INFO
++			"yaffs: mtd is read only, setting superblock read only");
++		*flags |= MS_RDONLY;
++	}
++
++	dev = sb->s_fs_info;
++	dev->read_only = read_only;
++
++	return 0;
++}
++
++static const struct super_operations yaffs_super_ops = {
++	.statfs = yaffs_statfs,
++
++#ifndef YAFFS_USE_OWN_IGET
++	.read_inode = yaffs_read_inode,
++#endif
++#ifdef YAFFS_HAS_PUT_INODE
++	.put_inode = yaffs_put_inode,
++#endif
++	.put_super = yaffs_put_super,
++#ifdef YAFFS_HAS_EVICT_INODE
++	.evict_inode = yaffs_evict_inode,
++#else
++	.delete_inode = yaffs_delete_inode,
++	.clear_inode = yaffs_clear_inode,
++#endif
++	.sync_fs = yaffs_sync_fs,
++#ifdef YAFFS_HAS_WRITE_SUPER
++	.write_super = yaffs_write_super,
++#endif
++	.remount_fs = yaffs_remount_fs,
++};
++
++struct yaffs_options {
++	int inband_tags;
++	int skip_checkpoint_read;
++	int skip_checkpoint_write;
++	int no_cache;
++	int tags_ecc_on;
++	int tags_ecc_overridden;
++	int lazy_loading_enabled;
++	int lazy_loading_overridden;
++	int empty_lost_and_found;
++	int empty_lost_and_found_overridden;
++	int disable_summary;
++};
++
++#define MAX_OPT_LEN 30
++static int yaffs_parse_options(struct yaffs_options *options,
++			       const char *options_str)
++{
++	char cur_opt[MAX_OPT_LEN + 1];
++	int p;
++	int error = 0;
++
++	/* Parse through the options which is a comma seperated list */
++
++	while (options_str && *options_str && !error) {
++		memset(cur_opt, 0, MAX_OPT_LEN + 1);
++		p = 0;
++
++		while (*options_str == ',')
++			options_str++;
++
++		while (*options_str && *options_str != ',') {
++			if (p < MAX_OPT_LEN) {
++				cur_opt[p] = *options_str;
++				p++;
++			}
++			options_str++;
++		}
++
++		if (!strcmp(cur_opt, "inband-tags")) {
++			options->inband_tags = 1;
++		} else if (!strcmp(cur_opt, "tags-ecc-off")) {
++			options->tags_ecc_on = 0;
++			options->tags_ecc_overridden = 1;
++		} else if (!strcmp(cur_opt, "tags-ecc-on")) {
++			options->tags_ecc_on = 1;
++			options->tags_ecc_overridden = 1;
++		} else if (!strcmp(cur_opt, "lazy-loading-off")) {
++			options->lazy_loading_enabled = 0;
++			options->lazy_loading_overridden = 1;
++		} else if (!strcmp(cur_opt, "lazy-loading-on")) {
++			options->lazy_loading_enabled = 1;
++			options->lazy_loading_overridden = 1;
++		} else if (!strcmp(cur_opt, "disable-summary")) {
++			options->disable_summary = 1;
++		} else if (!strcmp(cur_opt, "empty-lost-and-found-off")) {
++			options->empty_lost_and_found = 0;
++			options->empty_lost_and_found_overridden = 1;
++		} else if (!strcmp(cur_opt, "empty-lost-and-found-on")) {
++			options->empty_lost_and_found = 1;
++			options->empty_lost_and_found_overridden = 1;
++		} else if (!strcmp(cur_opt, "no-cache")) {
++			options->no_cache = 1;
++		} else if (!strcmp(cur_opt, "no-checkpoint-read")) {
++			options->skip_checkpoint_read = 1;
++		} else if (!strcmp(cur_opt, "no-checkpoint-write")) {
++			options->skip_checkpoint_write = 1;
++		} else if (!strcmp(cur_opt, "no-checkpoint")) {
++			options->skip_checkpoint_read = 1;
++			options->skip_checkpoint_write = 1;
++		} else {
++			printk(KERN_INFO "yaffs: Bad mount option \"%s\"\n",
++			       cur_opt);
++			error = 1;
++		}
++	}
++
++	return error;
++}
++
++
++static struct dentry *yaffs_make_root(struct inode *inode)
++{
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0))
++	struct dentry *root = d_alloc_root(inode);
++
++	if (!root)
++		iput(inode);
++
++        return root;
++#else
++        return d_make_root(inode);
++#endif
++}
++
++
++
++
++static struct super_block *yaffs_internal_read_super(int yaffs_version,
++						     struct super_block *sb,
++						     void *data, int silent)
++{
++	int n_blocks;
++	struct inode *inode = NULL;
++	struct dentry *root;
++	struct yaffs_dev *dev = 0;
++	char devname_buf[BDEVNAME_SIZE + 1];
++	struct mtd_info *mtd;
++	int err;
++	char *data_str = (char *)data;
++	struct yaffs_linux_context *context = NULL;
++	struct yaffs_param *param;
++
++	int read_only = 0;
++	int inband_tags = 0;
++
++	struct yaffs_options options;
++
++	unsigned mount_id;
++	int found;
++	struct yaffs_linux_context *context_iterator;
++	struct list_head *l;
++
++	if (!sb) {
++		printk(KERN_INFO "yaffs: sb is NULL\n");
++		return NULL;
++        }
++
++	sb->s_magic = YAFFS_MAGIC;
++	sb->s_op = &yaffs_super_ops;
++	sb->s_flags |= MS_NOATIME;
++
++	read_only = ((sb->s_flags & MS_RDONLY) != 0);
++
++#ifdef YAFFS_COMPILE_EXPORTFS
++	sb->s_export_op = &yaffs_export_ops;
++#endif
++
++	if (!sb->s_dev)
++		printk(KERN_INFO "yaffs: sb->s_dev is NULL\n");
++	else if (!yaffs_devname(sb, devname_buf))
++		printk(KERN_INFO "yaffs: devname is NULL\n");
++	else
++		printk(KERN_INFO "yaffs: dev is %d name is \"%s\" %s\n",
++		       sb->s_dev,
++		       yaffs_devname(sb, devname_buf), read_only ? "ro" : "rw");
++
++	if (!data_str)
++		data_str = "";
++
++	printk(KERN_INFO "yaffs: passed flags \"%s\"\n", data_str);
++
++	memset(&options, 0, sizeof(options));
++
++	if (yaffs_parse_options(&options, data_str)) {
++		/* Option parsing failed */
++		return NULL;
++	}
++
++	sb->s_blocksize = PAGE_CACHE_SIZE;
++	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
++
++	yaffs_trace(YAFFS_TRACE_OS,
++		"yaffs_read_super: Using yaffs%d", yaffs_version);
++	yaffs_trace(YAFFS_TRACE_OS,
++		"yaffs_read_super: block size %d", (int)(sb->s_blocksize));
++
++	yaffs_trace(YAFFS_TRACE_ALWAYS,
++		"yaffs: Attempting MTD mount of %u.%u,\"%s\"",
++		MAJOR(sb->s_dev), MINOR(sb->s_dev),
++		yaffs_devname(sb, devname_buf));
++
++	/* Get the device */
++	mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
++	if (IS_ERR(mtd)) {
++		yaffs_trace(YAFFS_TRACE_ALWAYS,
++			"yaffs: MTD device %u either not valid or unavailable",
++			MINOR(sb->s_dev));
++		return NULL;
++	}
++
++	if (yaffs_auto_select && yaffs_version == 1 && WRITE_SIZE(mtd) >= 2048) {
++		yaffs_trace(YAFFS_TRACE_ALWAYS, "auto selecting yaffs2");
++		yaffs_version = 2;
++	}
++
++	/* Added NCB 26/5/2006 for completeness */
++	if (yaffs_version == 2 && !options.inband_tags
++	    && WRITE_SIZE(mtd) == 512) {
++		yaffs_trace(YAFFS_TRACE_ALWAYS, "auto selecting yaffs1");
++		yaffs_version = 1;
++	}
++
++	if (mtd->oobavail < sizeof(struct yaffs_packed_tags2) ||
++	    options.inband_tags)
++		inband_tags = 1;
++
++	if(yaffs_verify_mtd(mtd, yaffs_version, inband_tags) < 0)
++		return NULL;
++
++	/* OK, so if we got here, we have an MTD that's NAND and looks
++	 * like it has the right capabilities
++	 * Set the struct yaffs_dev up for mtd
++	 */
++
++	if (!read_only && !(mtd->flags & MTD_WRITEABLE)) {
++		read_only = 1;
++		printk(KERN_INFO
++		       "yaffs: mtd is read only, setting superblock read only\n"
++		);
++		sb->s_flags |= MS_RDONLY;
++	}
++
++	dev = kmalloc(sizeof(struct yaffs_dev), GFP_KERNEL);
++	context = kmalloc(sizeof(struct yaffs_linux_context), GFP_KERNEL);
++
++	if (!dev || !context) {
++		kfree(dev);
++		kfree(context);
++		dev = NULL;
++		context = NULL;
++
++		/* Deep shit could not allocate device structure */
++		yaffs_trace(YAFFS_TRACE_ALWAYS,
++			"yaffs_read_super: Failed trying to allocate struct yaffs_dev."
++		);
++		return NULL;
++	}
++	memset(dev, 0, sizeof(struct yaffs_dev));
++	param = &(dev->param);
++
++	memset(context, 0, sizeof(struct yaffs_linux_context));
++	dev->os_context = context;
++	INIT_LIST_HEAD(&(context->context_list));
++	context->dev = dev;
++	context->super = sb;
++
++	dev->read_only = read_only;
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++	sb->s_fs_info = dev;
++#else
++	sb->u.generic_sbp = dev;
++#endif
++
++
++	dev->driver_context = mtd;
++	param->name = mtd->name;
++
++	/* Set up the memory size parameters.... */
++
++
++	param->n_reserved_blocks = 5;
++	param->n_caches = (options.no_cache) ? 0 : 10;
++	param->inband_tags = inband_tags;
++
++	param->enable_xattr = 1;
++	if (options.lazy_loading_overridden)
++		param->disable_lazy_load = !options.lazy_loading_enabled;
++
++	param->defered_dir_update = 1;
++
++	if (options.tags_ecc_overridden)
++		param->no_tags_ecc = !options.tags_ecc_on;
++
++	param->empty_lost_n_found = 1;
++	param->refresh_period = 500;
++	param->disable_summary = options.disable_summary;
++
++
++#ifdef CONFIG_YAFFS_DISABLE_BAD_BLOCK_MARKING
++	param->disable_bad_block_marking  = 1;
++#endif
++	if (options.empty_lost_and_found_overridden)
++		param->empty_lost_n_found = options.empty_lost_and_found;
++
++	/* ... and the functions. */
++	if (yaffs_version == 2) {
++		param->is_yaffs2 = 1;
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
++		param->total_bytes_per_chunk = mtd->writesize;
++		param->chunks_per_block = mtd->erasesize / mtd->writesize;
++#else
++		param->total_bytes_per_chunk = mtd->oobblock;
++		param->chunks_per_block = mtd->erasesize / mtd->oobblock;
++#endif
++		n_blocks = YCALCBLOCKS(mtd->size, mtd->erasesize);
++
++		param->start_block = 0;
++		param->end_block = n_blocks - 1;
++	} else {
++		param->is_yaffs2 = 0;
++		n_blocks = YCALCBLOCKS(mtd->size,
++			     YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK);
++
++		param->chunks_per_block = YAFFS_CHUNKS_PER_BLOCK;
++		param->total_bytes_per_chunk = YAFFS_BYTES_PER_CHUNK;
++	}
++
++	param->start_block = 0;
++	param->end_block = n_blocks - 1;
++
++	yaffs_mtd_drv_install(dev);
++
++	param->sb_dirty_fn = yaffs_set_super_dirty;
++	param->gc_control_fn = yaffs_gc_control_callback;
++
++	yaffs_dev_to_lc(dev)->super = sb;
++
++	param->use_nand_ecc = 1;
++
++	param->skip_checkpt_rd = options.skip_checkpoint_read;
++	param->skip_checkpt_wr = options.skip_checkpoint_write;
++
++	mutex_lock(&yaffs_context_lock);
++	/* Get a mount id */
++	found = 0;
++	for (mount_id = 0; !found; mount_id++) {
++		found = 1;
++		list_for_each(l, &yaffs_context_list) {
++			context_iterator =
++			    list_entry(l, struct yaffs_linux_context,
++				       context_list);
++			if (context_iterator->mount_id == mount_id)
++				found = 0;
++		}
++	}
++	context->mount_id = mount_id;
++
++	list_add_tail(&(yaffs_dev_to_lc(dev)->context_list),
++		      &yaffs_context_list);
++	mutex_unlock(&yaffs_context_lock);
++
++	/* Directory search handling... */
++	INIT_LIST_HEAD(&(yaffs_dev_to_lc(dev)->search_contexts));
++	param->remove_obj_fn = yaffs_remove_obj_callback;
++
++	mutex_init(&(yaffs_dev_to_lc(dev)->gross_lock));
++
++	yaffs_gross_lock(dev);
++
++	err = yaffs_guts_initialise(dev);
++
++	yaffs_trace(YAFFS_TRACE_OS,
++		"yaffs_read_super: guts initialised %s",
++		(err == YAFFS_OK) ? "OK" : "FAILED");
++
++	if (err == YAFFS_OK)
++		yaffs_bg_start(dev);
++
++	if (!context->bg_thread)
++		param->defered_dir_update = 0;
++
++	sb->s_maxbytes = yaffs_max_file_size(dev);
++
++	/* Release lock before yaffs_get_inode() */
++	yaffs_gross_unlock(dev);
++
++	/* Create root inode */
++	if (err == YAFFS_OK)
++		inode = yaffs_get_inode(sb, S_IFDIR | 0755, 0, yaffs_root(dev));
++
++	if (!inode)
++		return NULL;
++
++	inode->i_op = &yaffs_dir_inode_operations;
++	inode->i_fop = &yaffs_dir_operations;
++
++	yaffs_trace(YAFFS_TRACE_OS, "yaffs_read_super: got root inode");
++
++	root = yaffs_make_root(inode);
++
++	if (!root)
++		return NULL;
++
++	sb->s_root = root;
++	if(!dev->is_checkpointed)
++		yaffs_set_super_dirty(dev);
++
++	yaffs_trace(YAFFS_TRACE_ALWAYS,
++		"yaffs_read_super: is_checkpointed %d",
++		dev->is_checkpointed);
++
++	yaffs_trace(YAFFS_TRACE_OS, "yaffs_read_super: done");
++	return sb;
++}
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++static int yaffs_internal_read_super_mtd(struct super_block *sb, void *data,
++					 int silent)
++{
++	return yaffs_internal_read_super(1, sb, data, silent) ? 0 : -EINVAL;
++}
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
++static struct dentry *yaffs_mount(struct file_system_type *fs_type, int flags,
++        const char *dev_name, void *data)
++{
++    return mount_bdev(fs_type, flags, dev_name, data, yaffs_internal_read_super_mtd);
++}
++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
++static int yaffs_read_super(struct file_system_type *fs,
++			    int flags, const char *dev_name,
++			    void *data, struct vfsmount *mnt)
++{
++
++	return get_sb_bdev(fs, flags, dev_name, data,
++			   yaffs_internal_read_super_mtd, mnt);
++}
++#else
++static struct super_block *yaffs_read_super(struct file_system_type *fs,
++					    int flags, const char *dev_name,
++					    void *data)
++{
++
++	return get_sb_bdev(fs, flags, dev_name, data,
++			   yaffs_internal_read_super_mtd);
++}
++#endif
++
++static struct file_system_type yaffs_fs_type = {
++	.owner = THIS_MODULE,
++	.name = "yaffs",
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
++        .mount = yaffs_mount,
++#else
++        .get_sb = yaffs_read_super,
++#endif
++	.kill_sb = kill_block_super,
++	.fs_flags = FS_REQUIRES_DEV,
++};
++#else
++static struct super_block *yaffs_read_super(struct super_block *sb, void *data,
++					    int silent)
++{
++	return yaffs_internal_read_super(1, sb, data, silent);
++}
++
++static DECLARE_FSTYPE(yaffs_fs_type, "yaffs", yaffs_read_super,
++		      FS_REQUIRES_DEV);
++#endif
++
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++static int yaffs2_internal_read_super_mtd(struct super_block *sb, void *data,
++					  int silent)
++{
++	return yaffs_internal_read_super(2, sb, data, silent) ? 0 : -EINVAL;
++}
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
++static struct dentry *yaffs2_mount(struct file_system_type *fs_type, int flags,
++        const char *dev_name, void *data)
++{
++        return mount_bdev(fs_type, flags, dev_name, data, yaffs2_internal_read_super_mtd);
++}
++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
++static int yaffs2_read_super(struct file_system_type *fs,
++			     int flags, const char *dev_name, void *data,
++			     struct vfsmount *mnt)
++{
++	return get_sb_bdev(fs, flags, dev_name, data,
++			   yaffs2_internal_read_super_mtd, mnt);
++}
++#else
++static struct super_block *yaffs2_read_super(struct file_system_type *fs,
++					     int flags, const char *dev_name,
++					     void *data)
++{
++
++	return get_sb_bdev(fs, flags, dev_name, data,
++			   yaffs2_internal_read_super_mtd);
++}
++#endif
++
++static struct file_system_type yaffs2_fs_type = {
++	.owner = THIS_MODULE,
++	.name = "yaffs2",
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
++        .mount = yaffs2_mount,
++#else
++        .get_sb = yaffs2_read_super,
++#endif
++	.kill_sb = kill_block_super,
++	.fs_flags = FS_REQUIRES_DEV,
++};
++#else
++static struct super_block *yaffs2_read_super(struct super_block *sb,
++					     void *data, int silent)
++{
++	return yaffs_internal_read_super(2, sb, data, silent);
++}
++
++static DECLARE_FSTYPE(yaffs2_fs_type, "yaffs2", yaffs2_read_super,
++		      FS_REQUIRES_DEV);
++#endif
++
++
++static struct proc_dir_entry *my_proc_entry;
++
++static char *yaffs_dump_dev_part0(char *buf, struct yaffs_dev *dev)
++{
++	struct yaffs_param *param = &dev->param;
++	int bs[10];
++
++	yaffs_count_blocks_by_state(dev,bs);
++
++	buf += sprintf(buf, "start_block.......... %d\n", param->start_block);
++	buf += sprintf(buf, "end_block............ %d\n", param->end_block);
++	buf += sprintf(buf, "total_bytes_per_chunk %d\n",
++				param->total_bytes_per_chunk);
++	buf += sprintf(buf, "use_nand_ecc......... %d\n", param->use_nand_ecc);
++	buf += sprintf(buf, "no_tags_ecc.......... %d\n", param->no_tags_ecc);
++	buf += sprintf(buf, "is_yaffs2............ %d\n", param->is_yaffs2);
++	buf += sprintf(buf, "inband_tags.......... %d\n", param->inband_tags);
++	buf += sprintf(buf, "empty_lost_n_found... %d\n",
++				param->empty_lost_n_found);
++	buf += sprintf(buf, "disable_lazy_load.... %d\n",
++				param->disable_lazy_load);
++	buf += sprintf(buf, "disable_bad_block_mrk %d\n",
++				param->disable_bad_block_marking);
++	buf += sprintf(buf, "refresh_period....... %d\n",
++				param->refresh_period);
++	buf += sprintf(buf, "n_caches............. %d\n", param->n_caches);
++	buf += sprintf(buf, "n_reserved_blocks.... %d\n",
++				param->n_reserved_blocks);
++	buf += sprintf(buf, "always_check_erased.. %d\n",
++				param->always_check_erased);
++	buf += sprintf(buf, "\n");
++	buf += sprintf(buf, "block count by state\n");
++	buf += sprintf(buf, "0:%d 1:%d 2:%d 3:%d 4:%d\n",
++				bs[0], bs[1], bs[2], bs[3], bs[4]);
++	buf += sprintf(buf, "5:%d 6:%d 7:%d 8:%d 9:%d\n",
++				bs[5], bs[6], bs[7], bs[8], bs[9]);
++
++	return buf;
++}
++
++static char *yaffs_dump_dev_part1(char *buf, struct yaffs_dev *dev)
++{
++	buf += sprintf(buf, "max file size....... %lld\n",
++				(long long) yaffs_max_file_size(dev));
++	buf += sprintf(buf, "data_bytes_per_chunk. %d\n",
++				dev->data_bytes_per_chunk);
++	buf += sprintf(buf, "chunk_grp_bits....... %d\n", dev->chunk_grp_bits);
++	buf += sprintf(buf, "chunk_grp_size....... %d\n", dev->chunk_grp_size);
++	buf += sprintf(buf, "n_erased_blocks...... %d\n", dev->n_erased_blocks);
++	buf += sprintf(buf, "blocks_in_checkpt.... %d\n",
++				dev->blocks_in_checkpt);
++	buf += sprintf(buf, "\n");
++	buf += sprintf(buf, "n_tnodes............. %d\n", dev->n_tnodes);
++	buf += sprintf(buf, "n_obj................ %d\n", dev->n_obj);
++	buf += sprintf(buf, "n_free_chunks........ %d\n", dev->n_free_chunks);
++	buf += sprintf(buf, "\n");
++	buf += sprintf(buf, "n_page_writes........ %u\n", dev->n_page_writes);
++	buf += sprintf(buf, "n_page_reads......... %u\n", dev->n_page_reads);
++	buf += sprintf(buf, "n_erasures........... %u\n", dev->n_erasures);
++	buf += sprintf(buf, "n_gc_copies.......... %u\n", dev->n_gc_copies);
++	buf += sprintf(buf, "all_gcs.............. %u\n", dev->all_gcs);
++	buf += sprintf(buf, "passive_gc_count..... %u\n",
++				dev->passive_gc_count);
++	buf += sprintf(buf, "oldest_dirty_gc_count %u\n",
++				dev->oldest_dirty_gc_count);
++	buf += sprintf(buf, "n_gc_blocks.......... %u\n", dev->n_gc_blocks);
++	buf += sprintf(buf, "bg_gcs............... %u\n", dev->bg_gcs);
++	buf += sprintf(buf, "n_retried_writes..... %u\n",
++				dev->n_retried_writes);
++	buf += sprintf(buf, "n_retired_blocks..... %u\n",
++				dev->n_retired_blocks);
++	buf += sprintf(buf, "n_ecc_fixed.......... %u\n", dev->n_ecc_fixed);
++	buf += sprintf(buf, "n_ecc_unfixed........ %u\n", dev->n_ecc_unfixed);
++	buf += sprintf(buf, "n_tags_ecc_fixed..... %u\n",
++				dev->n_tags_ecc_fixed);
++	buf += sprintf(buf, "n_tags_ecc_unfixed... %u\n",
++				dev->n_tags_ecc_unfixed);
++	buf += sprintf(buf, "cache_hits........... %u\n", dev->cache_hits);
++	buf += sprintf(buf, "n_deleted_files...... %u\n", dev->n_deleted_files);
++	buf += sprintf(buf, "n_unlinked_files..... %u\n",
++				dev->n_unlinked_files);
++	buf += sprintf(buf, "refresh_count........ %u\n", dev->refresh_count);
++	buf += sprintf(buf, "n_bg_deletions....... %u\n", dev->n_bg_deletions);
++	buf += sprintf(buf, "tags_used............ %u\n", dev->tags_used);
++	buf += sprintf(buf, "summary_used......... %u\n", dev->summary_used);
++
++	return buf;
++}
++
++static int yaffs_proc_read(char *page,
++			   char **start,
++			   off_t offset, int count, int *eof, void *data)
++{
++	struct list_head *item;
++	char *buf = page;
++	int step = offset;
++	int n = 0;
++
++	/* Get proc_file_read() to step 'offset' by one on each sucessive call.
++	 * We use 'offset' (*ppos) to indicate where we are in dev_list.
++	 * This also assumes the user has posted a read buffer large
++	 * enough to hold the complete output; but that's life in /proc.
++	 */
++
++	*(int *)start = 1;
++
++	/* Print header first */
++	if (step == 0)
++		buf +=
++		    sprintf(buf,
++			    "Multi-version YAFFS built: \n");
++	else if (step == 1)
++		buf += sprintf(buf, "\n");
++	else {
++		step -= 2;
++
++		mutex_lock(&yaffs_context_lock);
++
++		/* Locate and print the Nth entry.  Order N-squared but N is small. */
++		list_for_each(item, &yaffs_context_list) {
++			struct yaffs_linux_context *dc =
++			    list_entry(item, struct yaffs_linux_context,
++				       context_list);
++			struct yaffs_dev *dev = dc->dev;
++
++			if (n < (step & ~1)) {
++				n += 2;
++				continue;
++			}
++			if ((step & 1) == 0) {
++				buf +=
++				    sprintf(buf, "\nDevice %d \"%s\"\n", n,
++					    dev->param.name);
++				buf = yaffs_dump_dev_part0(buf, dev);
++			} else {
++				buf = yaffs_dump_dev_part1(buf, dev);
++                        }
++
++			break;
++		}
++		mutex_unlock(&yaffs_context_lock);
++	}
++
++	return buf - page < count ? buf - page : count;
++}
++
++/**
++ * Set the verbosity of the warnings and error messages.
++ *
++ * Note that the names can only be a..z or _ with the current code.
++ */
++
++static struct {
++	char *mask_name;
++	unsigned mask_bitfield;
++} mask_flags[] = {
++	{"allocate", YAFFS_TRACE_ALLOCATE},
++	{"always", YAFFS_TRACE_ALWAYS},
++	{"background", YAFFS_TRACE_BACKGROUND},
++	{"bad_blocks", YAFFS_TRACE_BAD_BLOCKS},
++	{"buffers", YAFFS_TRACE_BUFFERS},
++	{"bug", YAFFS_TRACE_BUG},
++	{"checkpt", YAFFS_TRACE_CHECKPOINT},
++	{"deletion", YAFFS_TRACE_DELETION},
++	{"erase", YAFFS_TRACE_ERASE},
++	{"error", YAFFS_TRACE_ERROR},
++	{"gc_detail", YAFFS_TRACE_GC_DETAIL},
++	{"gc", YAFFS_TRACE_GC},
++	{"lock", YAFFS_TRACE_LOCK},
++	{"mtd", YAFFS_TRACE_MTD},
++	{"nandaccess", YAFFS_TRACE_NANDACCESS},
++	{"os", YAFFS_TRACE_OS},
++	{"scan_debug", YAFFS_TRACE_SCAN_DEBUG},
++	{"scan", YAFFS_TRACE_SCAN},
++	{"mount", YAFFS_TRACE_MOUNT},
++	{"tracing", YAFFS_TRACE_TRACING},
++	{"sync", YAFFS_TRACE_SYNC},
++	{"write", YAFFS_TRACE_WRITE},
++	{"verify", YAFFS_TRACE_VERIFY},
++	{"verify_nand", YAFFS_TRACE_VERIFY_NAND},
++	{"verify_full", YAFFS_TRACE_VERIFY_FULL},
++	{"verify_all", YAFFS_TRACE_VERIFY_ALL},
++	{"all", 0xffffffff},
++	{"none", 0},
++	{NULL, 0},
++};
++
++#define MAX_MASK_NAME_LENGTH 40
++static int yaffs_proc_write_trace_options(struct file *file, const char *buf,
++					  unsigned long count)
++{
++	unsigned rg = 0, mask_bitfield;
++	char *end;
++	char *mask_name;
++	const char *x;
++	char substring[MAX_MASK_NAME_LENGTH + 1];
++	int i;
++	int done = 0;
++	int add, len = 0;
++	int pos = 0;
++
++	rg = yaffs_trace_mask;
++
++	while (!done && (pos < count)) {
++		done = 1;
++		while ((pos < count) && isspace(buf[pos]))
++			pos++;
++
++		switch (buf[pos]) {
++		case '+':
++		case '-':
++		case '=':
++			add = buf[pos];
++			pos++;
++			break;
++
++		default:
++			add = ' ';
++			break;
++		}
++		mask_name = NULL;
++
++		mask_bitfield = simple_strtoul(buf + pos, &end, 0);
++
++		if (end > buf + pos) {
++			mask_name = "numeral";
++			len = end - (buf + pos);
++			pos += len;
++			done = 0;
++		} else {
++			for (x = buf + pos, i = 0;
++			     (*x == '_' || (*x >= 'a' && *x <= 'z')) &&
++			     i < MAX_MASK_NAME_LENGTH; x++, i++, pos++)
++				substring[i] = *x;
++			substring[i] = '\0';
++
++			for (i = 0; mask_flags[i].mask_name != NULL; i++) {
++				if (strcmp(substring, mask_flags[i].mask_name)
++				    == 0) {
++					mask_name = mask_flags[i].mask_name;
++					mask_bitfield =
++					    mask_flags[i].mask_bitfield;
++					done = 0;
++					break;
++				}
++			}
++		}
++
++		if (mask_name != NULL) {
++			done = 0;
++			switch (add) {
++			case '-':
++				rg &= ~mask_bitfield;
++				break;
++			case '+':
++				rg |= mask_bitfield;
++				break;
++			case '=':
++				rg = mask_bitfield;
++				break;
++			default:
++				rg |= mask_bitfield;
++				break;
++			}
++		}
++	}
++
++	yaffs_trace_mask = rg | YAFFS_TRACE_ALWAYS;
++
++	printk(KERN_DEBUG "new trace = 0x%08X\n", yaffs_trace_mask);
++
++	if (rg & YAFFS_TRACE_ALWAYS) {
++		for (i = 0; mask_flags[i].mask_name != NULL; i++) {
++			char flag;
++			flag = ((rg & mask_flags[i].mask_bitfield) ==
++				mask_flags[i].mask_bitfield) ? '+' : '-';
++			printk(KERN_DEBUG "%c%s\n", flag,
++			       mask_flags[i].mask_name);
++		}
++	}
++
++	return count;
++}
++
++/* Debug strings are of the form:
++ * .bnnn         print info on block n
++ * .cobjn,chunkn print nand chunk id for objn:chunkn
++ */
++
++static int yaffs_proc_debug_write(struct file *file, const char *buf,
++					  unsigned long count)
++{
++
++	char str[100];
++	char *p0;
++	char *p1;
++	long p1_val;
++	long p0_val;
++	char cmd;
++	struct list_head *item;
++
++	memset(str, 0, sizeof(str));
++	memcpy(str, buf, min((size_t)count, sizeof(str) -1));
++
++	cmd = str[1];
++
++	p0 = str + 2;
++
++	p1 = p0;
++
++	while (*p1 && *p1 != ',') {
++		p1++;
++	}
++	*p1 = '\0';
++	p1++;
++
++	p0_val = simple_strtol(p0, NULL, 0);
++	p1_val = simple_strtol(p1, NULL, 0);
++
++
++	mutex_lock(&yaffs_context_lock);
++
++	/* Locate and print the Nth entry.  Order N-squared but N is small. */
++	list_for_each(item, &yaffs_context_list) {
++		struct yaffs_linux_context *dc =
++		    list_entry(item, struct yaffs_linux_context,
++			       context_list);
++		struct yaffs_dev *dev = dc->dev;
++
++		if (cmd == 'b') {
++			struct yaffs_block_info *bi;
++
++			bi = yaffs_get_block_info(dev,p0_val);
++
++			if(bi) {
++				printk("Block %d: state %d, retire %d, use %d, seq %d\n",
++					(int)p0_val, bi->block_state,
++					bi->needs_retiring, bi->pages_in_use,
++					bi->seq_number);
++			}
++		} else if (cmd == 'c') {
++			struct yaffs_obj *obj;
++			int nand_chunk;
++
++			obj = yaffs_find_by_number(dev, p0_val);
++			if (!obj)
++				printk("No obj %d\n", (int)p0_val);
++			else {
++				if(p1_val == 0)
++					nand_chunk = obj->hdr_chunk;
++				else
++					nand_chunk =
++						yaffs_find_chunk_in_file(obj,
++							p1_val, NULL);
++				printk("Nand chunk for %d:%d is %d\n",
++					(int)p0_val, (int)p1_val, nand_chunk);
++			}
++		}
++	}
++
++	mutex_unlock(&yaffs_context_lock);
++
++	return count;
++}
++
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
++static int yaffs_proc_write(struct file *file, const char *buf,
++			    unsigned long count, void *ppos)
++#else
++static ssize_t yaffs_proc_write(struct file *file, const char __user *buf,
++			    size_t count, loff_t *ppos)
++#endif
++{
++	if (buf[0] == '.')
++		return yaffs_proc_debug_write(file, buf, count);
++	return yaffs_proc_write_trace_options(file, buf, count);
++}
++
++/* Stuff to handle installation of file systems */
++struct file_system_to_install {
++	struct file_system_type *fst;
++	int installed;
++};
++
++static struct file_system_to_install fs_to_install[] = {
++	{&yaffs_fs_type, 0},
++	{&yaffs2_fs_type, 0},
++	{NULL, 0}
++};
++
++
++#ifdef YAFFS_NEW_PROCFS
++static int yaffs_proc_show(struct seq_file *m, void *v)
++{
++	/* FIXME: Unify in a better way? */
++	char buffer[512];
++	char *start;
++	int len;
++
++	len = yaffs_proc_read(buffer, &start, 0, sizeof(buffer), NULL, NULL);
++	seq_puts(m, buffer);
++	return 0;
++}
++
++static int yaffs_proc_open(struct inode *inode, struct file *file)
++{
++	return single_open(file, yaffs_proc_show, NULL);
++}
++
++static struct file_operations procfs_ops = {
++	.owner = THIS_MODULE,
++	.open  = yaffs_proc_open,
++	.read  = seq_read,
++	.write = yaffs_proc_write,
++};
++
++static int yaffs_procfs_init(void)
++{
++	/* Install the proc_fs entries */
++	my_proc_entry = proc_create("yaffs",
++				    S_IRUGO | S_IFREG,
++				    YPROC_ROOT,
++				    &procfs_ops);
++
++	if (my_proc_entry) {
++		return 0;
++	} else {
++		return -ENOMEM;
++	}
++}
++
++#else
++
++
++static int yaffs_procfs_init(void)
++{
++	/* Install the proc_fs entries */
++	my_proc_entry = create_proc_entry("yaffs",
++					  S_IRUGO | S_IFREG, YPROC_ROOT);
++
++	if (my_proc_entry) {
++		my_proc_entry->write_proc = yaffs_proc_write;
++		my_proc_entry->read_proc = yaffs_proc_read;
++		my_proc_entry->data = NULL;
++		return 0;
++	} else {
++		return -ENOMEM;
++	}
++}
++
++#endif
++
++
++static int __init init_yaffs_fs(void)
++{
++	int error = 0;
++	struct file_system_to_install *fsinst;
++
++	yaffs_trace(YAFFS_TRACE_ALWAYS,
++		"yaffs built Installing.");
++
++	mutex_init(&yaffs_context_lock);
++
++	error = yaffs_procfs_init();
++	if (error)
++		return error;
++
++	/* Now add the file system entries */
++
++	fsinst = fs_to_install;
++
++	while (fsinst->fst && !error) {
++		error = register_filesystem(fsinst->fst);
++		if (!error)
++			fsinst->installed = 1;
++		fsinst++;
++	}
++
++	/* Any errors? uninstall  */
++	if (error) {
++		fsinst = fs_to_install;
++
++		while (fsinst->fst) {
++			if (fsinst->installed) {
++				unregister_filesystem(fsinst->fst);
++				fsinst->installed = 0;
++			}
++			fsinst++;
++		}
++	}
++
++	return error;
++}
++
++static void __exit exit_yaffs_fs(void)
++{
++
++	struct file_system_to_install *fsinst;
++
++	yaffs_trace(YAFFS_TRACE_ALWAYS,
++		"yaffs built removing.");
++
++	remove_proc_entry("yaffs", YPROC_ROOT);
++
++	fsinst = fs_to_install;
++
++	while (fsinst->fst) {
++		if (fsinst->installed) {
++			unregister_filesystem(fsinst->fst);
++			fsinst->installed = 0;
++		}
++		fsinst++;
++	}
++}
++
++module_init(init_yaffs_fs)
++module_exit(exit_yaffs_fs)
++
++MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system");
++MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2011");
++MODULE_LICENSE("GPL");
+diff --git a/fs/yaffs2/yaffs_yaffs1.c b/fs/yaffs2/yaffs_yaffs1.c
+new file mode 100644
+index 0000000..d277e20
+--- /dev/null
++++ b/fs/yaffs2/yaffs_yaffs1.c
+@@ -0,0 +1,422 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ *   for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * 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 "yaffs_yaffs1.h"
++#include "yportenv.h"
++#include "yaffs_trace.h"
++#include "yaffs_bitmap.h"
++#include "yaffs_getblockinfo.h"
++#include "yaffs_nand.h"
++#include "yaffs_attribs.h"
++
++int yaffs1_scan(struct yaffs_dev *dev)
++{
++	struct yaffs_ext_tags tags;
++	int blk;
++	int result;
++	int chunk;
++	int c;
++	int deleted;
++	enum yaffs_block_state state;
++	LIST_HEAD(hard_list);
++	struct yaffs_block_info *bi;
++	u32 seq_number;
++	struct yaffs_obj_hdr *oh;
++	struct yaffs_obj *in;
++	struct yaffs_obj *parent;
++	int alloc_failed = 0;
++	struct yaffs_shadow_fixer *shadow_fixers = NULL;
++	u8 *chunk_data;
++
++	yaffs_trace(YAFFS_TRACE_SCAN,
++		"yaffs1_scan starts  intstartblk %d intendblk %d...",
++		dev->internal_start_block, dev->internal_end_block);
++
++	chunk_data = yaffs_get_temp_buffer(dev);
++
++	dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER;
++
++	/* Scan all the blocks to determine their state */
++	bi = dev->block_info;
++	for (blk = dev->internal_start_block; blk <= dev->internal_end_block;
++	     blk++) {
++		yaffs_clear_chunk_bits(dev, blk);
++		bi->pages_in_use = 0;
++		bi->soft_del_pages = 0;
++
++		yaffs_query_init_block_state(dev, blk, &state, &seq_number);
++
++		bi->block_state = state;
++		bi->seq_number = seq_number;
++
++		if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK)
++			bi->block_state = state = YAFFS_BLOCK_STATE_DEAD;
++
++		yaffs_trace(YAFFS_TRACE_SCAN_DEBUG,
++			"Block scanning block %d state %d seq %d",
++			blk, state, seq_number);
++
++		if (state == YAFFS_BLOCK_STATE_DEAD) {
++			yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
++				"block %d is bad", blk);
++		} else if (state == YAFFS_BLOCK_STATE_EMPTY) {
++			yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "Block empty ");
++			dev->n_erased_blocks++;
++			dev->n_free_chunks += dev->param.chunks_per_block;
++		}
++		bi++;
++	}
++
++	/* For each block.... */
++	for (blk = dev->internal_start_block;
++	     !alloc_failed && blk <= dev->internal_end_block; blk++) {
++
++		cond_resched();
++
++		bi = yaffs_get_block_info(dev, blk);
++		state = bi->block_state;
++
++		deleted = 0;
++
++		/* For each chunk in each block that needs scanning.... */
++		for (c = 0;
++			!alloc_failed && c < dev->param.chunks_per_block &&
++			state == YAFFS_BLOCK_STATE_NEEDS_SCAN; c++) {
++			/* Read the tags and decide what to do */
++			chunk = blk * dev->param.chunks_per_block + c;
++
++			result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL,
++							  &tags);
++
++			/* Let's have a good look at this chunk... */
++
++			if (tags.ecc_result == YAFFS_ECC_RESULT_UNFIXED ||
++			    tags.is_deleted) {
++				/* YAFFS1 only...
++				 * A deleted chunk
++				 */
++				deleted++;
++				dev->n_free_chunks++;
++			} else if (!tags.chunk_used) {
++				/* An unassigned chunk in the block
++				 * This means that either the block is empty or
++				 * this is the one being allocated from
++				 */
++
++				if (c == 0) {
++					/* We're looking at the first chunk in
++					 *the block so the block is unused */
++					state = YAFFS_BLOCK_STATE_EMPTY;
++					dev->n_erased_blocks++;
++				} else {
++					/* this is the block being allocated */
++					yaffs_trace(YAFFS_TRACE_SCAN,
++						" Allocating from %d %d",
++						blk, c);
++					state = YAFFS_BLOCK_STATE_ALLOCATING;
++					dev->alloc_block = blk;
++					dev->alloc_page = c;
++					dev->alloc_block_finder = blk;
++
++				}
++
++				dev->n_free_chunks +=
++				    (dev->param.chunks_per_block - c);
++			} else if (tags.chunk_id > 0) {
++				/* chunk_id > 0 so it is a data chunk... */
++				unsigned int endpos;
++
++				yaffs_set_chunk_bit(dev, blk, c);
++				bi->pages_in_use++;
++
++				in = yaffs_find_or_create_by_number(dev,
++							tags.obj_id,
++							YAFFS_OBJECT_TYPE_FILE);
++				/* PutChunkIntoFile checks for a clash
++				 * (two data chunks with the same chunk_id).
++				 */
++
++				if (!in)
++					alloc_failed = 1;
++
++				if (in) {
++					if (!yaffs_put_chunk_in_file
++					    (in, tags.chunk_id, chunk, 1))
++						alloc_failed = 1;
++				}
++
++				endpos =
++				    (tags.chunk_id - 1) *
++				    dev->data_bytes_per_chunk +
++				    tags.n_bytes;
++				if (in &&
++				    in->variant_type ==
++				     YAFFS_OBJECT_TYPE_FILE &&
++				    in->variant.file_variant.scanned_size <
++				      endpos) {
++					in->variant.file_variant.scanned_size =
++					    endpos;
++					if (!dev->param.use_header_file_size) {
++						in->variant.
++						    file_variant.file_size =
++						    in->variant.
++						    file_variant.scanned_size;
++					}
++
++				}
++			} else {
++				/* chunk_id == 0, so it is an ObjectHeader.
++				 * Make the object
++				 */
++				yaffs_set_chunk_bit(dev, blk, c);
++				bi->pages_in_use++;
++
++				result = yaffs_rd_chunk_tags_nand(dev, chunk,
++								  chunk_data,
++								  NULL);
++
++				oh = (struct yaffs_obj_hdr *)chunk_data;
++
++				in = yaffs_find_by_number(dev, tags.obj_id);
++				if (in && in->variant_type != oh->type) {
++					/* This should not happen, but somehow
++					 * Wev'e ended up with an obj_id that
++					 * has been reused but not yet deleted,
++					 * and worse still it has changed type.
++					 * Delete the old object.
++					 */
++
++					yaffs_del_obj(in);
++					in = NULL;
++				}
++
++				in = yaffs_find_or_create_by_number(dev,
++								tags.obj_id,
++								oh->type);
++
++				if (!in)
++					alloc_failed = 1;
++
++				if (in && oh->shadows_obj > 0) {
++
++					struct yaffs_shadow_fixer *fixer;
++					fixer =
++						kmalloc(sizeof
++						(struct yaffs_shadow_fixer),
++						GFP_NOFS);
++					if (fixer) {
++						fixer->next = shadow_fixers;
++						shadow_fixers = fixer;
++						fixer->obj_id = tags.obj_id;
++						fixer->shadowed_id =
++						    oh->shadows_obj;
++						yaffs_trace(YAFFS_TRACE_SCAN,
++							" Shadow fixer: %d shadows %d",
++							fixer->obj_id,
++							fixer->shadowed_id);
++
++					}
++
++				}
++
++				if (in && in->valid) {
++					/* We have already filled this one.
++					 * We have a duplicate and need to
++					 * resolve it. */
++
++					unsigned existing_serial = in->serial;
++					unsigned new_serial =
++					    tags.serial_number;
++
++					if (((existing_serial + 1) & 3) ==
++					    new_serial) {
++						/* Use new one - destroy the
++						 * exisiting one */
++						yaffs_chunk_del(dev,
++								in->hdr_chunk,
++								1, __LINE__);
++						in->valid = 0;
++					} else {
++						/* Use existing - destroy
++						 * this one. */
++						yaffs_chunk_del(dev, chunk, 1,
++								__LINE__);
++					}
++				}
++
++				if (in && !in->valid &&
++				    (tags.obj_id == YAFFS_OBJECTID_ROOT ||
++				     tags.obj_id ==
++				     YAFFS_OBJECTID_LOSTNFOUND)) {
++					/* We only load some info, don't fiddle
++					 * with directory structure */
++					in->valid = 1;
++					in->variant_type = oh->type;
++
++					in->yst_mode = oh->yst_mode;
++					yaffs_load_attribs(in, oh);
++					in->hdr_chunk = chunk;
++					in->serial = tags.serial_number;
++
++				} else if (in && !in->valid) {
++					/* we need to load this info */
++
++					in->valid = 1;
++					in->variant_type = oh->type;
++
++					in->yst_mode = oh->yst_mode;
++					yaffs_load_attribs(in, oh);
++					in->hdr_chunk = chunk;
++					in->serial = tags.serial_number;
++
++					yaffs_set_obj_name_from_oh(in, oh);
++					in->dirty = 0;
++
++					/* directory stuff...
++					 * hook up to parent
++					 */
++
++					parent =
++					    yaffs_find_or_create_by_number
++					    (dev, oh->parent_obj_id,
++					     YAFFS_OBJECT_TYPE_DIRECTORY);
++					if (!parent)
++						alloc_failed = 1;
++					if (parent && parent->variant_type ==
++					    YAFFS_OBJECT_TYPE_UNKNOWN) {
++						/* Set up as a directory */
++						parent->variant_type =
++						    YAFFS_OBJECT_TYPE_DIRECTORY;
++						INIT_LIST_HEAD(&parent->
++							variant.dir_variant.
++							children);
++					} else if (!parent ||
++						parent->variant_type !=
++						YAFFS_OBJECT_TYPE_DIRECTORY) {
++						/* Hoosterman, a problem....
++						 * We're trying to use a
++						 * non-directory as a directory
++						 */
++
++						yaffs_trace(YAFFS_TRACE_ERROR,
++							"yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
++							);
++						parent = dev->lost_n_found;
++					}
++
++					yaffs_add_obj_to_dir(parent, in);
++
++					switch (in->variant_type) {
++					case YAFFS_OBJECT_TYPE_UNKNOWN:
++						/* Todo got a problem */
++						break;
++					case YAFFS_OBJECT_TYPE_FILE:
++						if (dev->param.
++						    use_header_file_size)
++							in->variant.
++							file_variant.file_size
++							= yaffs_oh_to_size(oh);
++						break;
++					case YAFFS_OBJECT_TYPE_HARDLINK:
++						in->variant.
++						    hardlink_variant.equiv_id =
++						    oh->equiv_id;
++						list_add(&in->hard_links,
++								&hard_list);
++						break;
++					case YAFFS_OBJECT_TYPE_DIRECTORY:
++						/* Do nothing */
++						break;
++					case YAFFS_OBJECT_TYPE_SPECIAL:
++						/* Do nothing */
++						break;
++					case YAFFS_OBJECT_TYPE_SYMLINK:
++						in->variant.symlink_variant.
++						    alias =
++						    yaffs_clone_str(oh->alias);
++						if (!in->variant.
++						    symlink_variant.alias)
++							alloc_failed = 1;
++						break;
++					}
++				}
++			}
++		}
++
++		if (state == YAFFS_BLOCK_STATE_NEEDS_SCAN) {
++			/* If we got this far while scanning,
++			 * then the block is fully allocated. */
++			state = YAFFS_BLOCK_STATE_FULL;
++		}
++
++		if (state == YAFFS_BLOCK_STATE_ALLOCATING) {
++			/* If the block was partially allocated then
++			 * treat it as fully allocated. */
++			state = YAFFS_BLOCK_STATE_FULL;
++			dev->alloc_block = -1;
++		}
++
++		bi->block_state = state;
++
++		/* Now let's see if it was dirty */
++		if (bi->pages_in_use == 0 &&
++		    !bi->has_shrink_hdr &&
++		    bi->block_state == YAFFS_BLOCK_STATE_FULL)
++			yaffs_block_became_dirty(dev, blk);
++	}
++
++	/* Ok, we've done all the scanning.
++	 * Fix up the hard link chains.
++	 * We should now have scanned all the objects, now it's time to add
++	 * these hardlinks.
++	 */
++
++	yaffs_link_fixup(dev, &hard_list);
++
++	/*
++	 * Fix up any shadowed objects.
++	 * There should not be more than one of these.
++	 */
++	{
++		struct yaffs_shadow_fixer *fixer;
++		struct yaffs_obj *obj;
++
++		while (shadow_fixers) {
++			fixer = shadow_fixers;
++			shadow_fixers = fixer->next;
++			/* Complete the rename transaction by deleting the
++			 * shadowed object then setting the object header
++			 to unshadowed.
++			 */
++			obj = yaffs_find_by_number(dev, fixer->shadowed_id);
++			if (obj)
++				yaffs_del_obj(obj);
++
++			obj = yaffs_find_by_number(dev, fixer->obj_id);
++
++			if (obj)
++				yaffs_update_oh(obj, NULL, 1, 0, 0, NULL);
++
++			kfree(fixer);
++		}
++	}
++
++	yaffs_release_temp_buffer(dev, chunk_data);
++
++	if (alloc_failed)
++		return YAFFS_FAIL;
++
++	yaffs_trace(YAFFS_TRACE_SCAN, "yaffs1_scan ends");
++
++	return YAFFS_OK;
++}
+diff --git a/fs/yaffs2/yaffs_yaffs1.h b/fs/yaffs2/yaffs_yaffs1.h
+new file mode 100644
+index 0000000..97e2fdd
+--- /dev/null
++++ b/fs/yaffs2/yaffs_yaffs1.h
+@@ -0,0 +1,22 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ *   for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_YAFFS1_H__
++#define __YAFFS_YAFFS1_H__
++
++#include "yaffs_guts.h"
++int yaffs1_scan(struct yaffs_dev *dev);
++
++#endif
+diff --git a/fs/yaffs2/yaffs_yaffs2.c b/fs/yaffs2/yaffs_yaffs2.c
+new file mode 100644
+index 0000000..9fb7c94
+--- /dev/null
++++ b/fs/yaffs2/yaffs_yaffs2.c
+@@ -0,0 +1,1532 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ *   for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * 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 "yaffs_guts.h"
++#include "yaffs_trace.h"
++#include "yaffs_yaffs2.h"
++#include "yaffs_checkptrw.h"
++#include "yaffs_bitmap.h"
++#include "yaffs_nand.h"
++#include "yaffs_getblockinfo.h"
++#include "yaffs_verify.h"
++#include "yaffs_attribs.h"
++#include "yaffs_summary.h"
++
++/*
++ * Checkpoints are really no benefit on very small partitions.
++ *
++ * To save space on small partitions don't bother with checkpoints unless
++ * the partition is at least this big.
++ */
++#define YAFFS_CHECKPOINT_MIN_BLOCKS 60
++#define YAFFS_SMALL_HOLE_THRESHOLD 4
++
++/*
++ * Oldest Dirty Sequence Number handling.
++ */
++
++/* yaffs_calc_oldest_dirty_seq()
++ * yaffs2_find_oldest_dirty_seq()
++ * Calculate the oldest dirty sequence number if we don't know it.
++ */
++void yaffs_calc_oldest_dirty_seq(struct yaffs_dev *dev)
++{
++	int i;
++	unsigned seq;
++	unsigned block_no = 0;
++	struct yaffs_block_info *b;
++
++	if (!dev->param.is_yaffs2)
++		return;
++
++	/* Find the oldest dirty sequence number. */
++	seq = dev->seq_number + 1;
++	b = dev->block_info;
++	for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
++		if (b->block_state == YAFFS_BLOCK_STATE_FULL &&
++		    (b->pages_in_use - b->soft_del_pages) <
++		    dev->param.chunks_per_block &&
++		    b->seq_number < seq) {
++			seq = b->seq_number;
++			block_no = i;
++		}
++		b++;
++	}
++
++	if (block_no) {
++		dev->oldest_dirty_seq = seq;
++		dev->oldest_dirty_block = block_no;
++	}
++}
++
++void yaffs2_find_oldest_dirty_seq(struct yaffs_dev *dev)
++{
++	if (!dev->param.is_yaffs2)
++		return;
++
++	if (!dev->oldest_dirty_seq)
++		yaffs_calc_oldest_dirty_seq(dev);
++}
++
++/*
++ * yaffs_clear_oldest_dirty_seq()
++ * Called when a block is erased or marked bad. (ie. when its seq_number
++ * becomes invalid). If the value matches the oldest then we clear
++ * dev->oldest_dirty_seq to force its recomputation.
++ */
++void yaffs2_clear_oldest_dirty_seq(struct yaffs_dev *dev,
++				   struct yaffs_block_info *bi)
++{
++
++	if (!dev->param.is_yaffs2)
++		return;
++
++	if (!bi || bi->seq_number == dev->oldest_dirty_seq) {
++		dev->oldest_dirty_seq = 0;
++		dev->oldest_dirty_block = 0;
++	}
++}
++
++/*
++ * yaffs2_update_oldest_dirty_seq()
++ * Update the oldest dirty sequence number whenever we dirty a block.
++ * Only do this if the oldest_dirty_seq is actually being tracked.
++ */
++void yaffs2_update_oldest_dirty_seq(struct yaffs_dev *dev, unsigned block_no,
++				    struct yaffs_block_info *bi)
++{
++	if (!dev->param.is_yaffs2)
++		return;
++
++	if (dev->oldest_dirty_seq) {
++		if (dev->oldest_dirty_seq > bi->seq_number) {
++			dev->oldest_dirty_seq = bi->seq_number;
++			dev->oldest_dirty_block = block_no;
++		}
++	}
++}
++
++int yaffs_block_ok_for_gc(struct yaffs_dev *dev, struct yaffs_block_info *bi)
++{
++
++	if (!dev->param.is_yaffs2)
++		return 1;	/* disqualification only applies to yaffs2. */
++
++	if (!bi->has_shrink_hdr)
++		return 1;	/* can gc */
++
++	yaffs2_find_oldest_dirty_seq(dev);
++
++	/* Can't do gc of this block if there are any blocks older than this
++	 * one that have discarded pages.
++	 */
++	return (bi->seq_number <= dev->oldest_dirty_seq);
++}
++
++/*
++ * yaffs2_find_refresh_block()
++ * periodically finds the oldest full block by sequence number for refreshing.
++ * Only for yaffs2.
++ */
++u32 yaffs2_find_refresh_block(struct yaffs_dev *dev)
++{
++	u32 b;
++	u32 oldest = 0;
++	u32 oldest_seq = 0;
++	struct yaffs_block_info *bi;
++
++	if (!dev->param.is_yaffs2)
++		return oldest;
++
++	/*
++	 * If refresh period < 10 then refreshing is disabled.
++	 */
++	if (dev->param.refresh_period < 10)
++		return oldest;
++
++	/*
++	 * Fix broken values.
++	 */
++	if (dev->refresh_skip > dev->param.refresh_period)
++		dev->refresh_skip = dev->param.refresh_period;
++
++	if (dev->refresh_skip > 0)
++		return oldest;
++
++	/*
++	 * Refresh skip is now zero.
++	 * We'll do a refresh this time around....
++	 * Update the refresh skip and find the oldest block.
++	 */
++	dev->refresh_skip = dev->param.refresh_period;
++	dev->refresh_count++;
++	bi = dev->block_info;
++	for (b = dev->internal_start_block; b <= dev->internal_end_block; b++) {
++
++		if (bi->block_state == YAFFS_BLOCK_STATE_FULL) {
++
++			if (oldest < 1 || bi->seq_number < oldest_seq) {
++				oldest = b;
++				oldest_seq = bi->seq_number;
++			}
++		}
++		bi++;
++	}
++
++	if (oldest > 0) {
++		yaffs_trace(YAFFS_TRACE_GC,
++			"GC refresh count %d selected block %d with seq_number %d",
++			dev->refresh_count, oldest, oldest_seq);
++	}
++
++	return oldest;
++}
++
++int yaffs2_checkpt_required(struct yaffs_dev *dev)
++{
++	int nblocks;
++
++	if (!dev->param.is_yaffs2)
++		return 0;
++
++	nblocks = dev->internal_end_block - dev->internal_start_block + 1;
++
++	return !dev->param.skip_checkpt_wr &&
++	    !dev->read_only && (nblocks >= YAFFS_CHECKPOINT_MIN_BLOCKS);
++}
++
++int yaffs_calc_checkpt_blocks_required(struct yaffs_dev *dev)
++{
++	int retval;
++	int n_bytes = 0;
++	int n_blocks;
++	int dev_blocks;
++
++	if (!dev->param.is_yaffs2)
++		return 0;
++
++	if (!dev->checkpoint_blocks_required && yaffs2_checkpt_required(dev)) {
++		/* Not a valid value so recalculate */
++		dev_blocks = dev->param.end_block - dev->param.start_block + 1;
++		n_bytes += sizeof(struct yaffs_checkpt_validity);
++		n_bytes += sizeof(struct yaffs_checkpt_dev);
++		n_bytes += dev_blocks * sizeof(struct yaffs_block_info);
++		n_bytes += dev_blocks * dev->chunk_bit_stride;
++		n_bytes +=
++		    (sizeof(struct yaffs_checkpt_obj) + sizeof(u32)) *
++		    dev->n_obj;
++		n_bytes += (dev->tnode_size + sizeof(u32)) * dev->n_tnodes;
++		n_bytes += sizeof(struct yaffs_checkpt_validity);
++		n_bytes += sizeof(u32);	/* checksum */
++
++		/* Round up and add 2 blocks to allow for some bad blocks,
++		 * so add 3 */
++
++		n_blocks =
++		    (n_bytes /
++		     (dev->data_bytes_per_chunk *
++		      dev->param.chunks_per_block)) + 3;
++
++		dev->checkpoint_blocks_required = n_blocks;
++	}
++
++	retval = dev->checkpoint_blocks_required - dev->blocks_in_checkpt;
++	if (retval < 0)
++		retval = 0;
++	return retval;
++}
++
++/*--------------------- Checkpointing --------------------*/
++
++static int yaffs2_wr_checkpt_validity_marker(struct yaffs_dev *dev, int head)
++{
++	struct yaffs_checkpt_validity cp;
++
++	memset(&cp, 0, sizeof(cp));
++
++	cp.struct_type = sizeof(cp);
++	cp.magic = YAFFS_MAGIC;
++	cp.version = YAFFS_CHECKPOINT_VERSION;
++	cp.head = (head) ? 1 : 0;
++
++	return (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp)) ? 1 : 0;
++}
++
++static int yaffs2_rd_checkpt_validity_marker(struct yaffs_dev *dev, int head)
++{
++	struct yaffs_checkpt_validity cp;
++	int ok;
++
++	ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));
++
++	if (ok)
++		ok = (cp.struct_type == sizeof(cp)) &&
++		    (cp.magic == YAFFS_MAGIC) &&
++		    (cp.version == YAFFS_CHECKPOINT_VERSION) &&
++		    (cp.head == ((head) ? 1 : 0));
++	return ok ? 1 : 0;
++}
++
++static void yaffs2_dev_to_checkpt_dev(struct yaffs_checkpt_dev *cp,
++				      struct yaffs_dev *dev)
++{
++	cp->n_erased_blocks = dev->n_erased_blocks;
++	cp->alloc_block = dev->alloc_block;
++	cp->alloc_page = dev->alloc_page;
++	cp->n_free_chunks = dev->n_free_chunks;
++
++	cp->n_deleted_files = dev->n_deleted_files;
++	cp->n_unlinked_files = dev->n_unlinked_files;
++	cp->n_bg_deletions = dev->n_bg_deletions;
++	cp->seq_number = dev->seq_number;
++
++}
++
++static void yaffs_checkpt_dev_to_dev(struct yaffs_dev *dev,
++				     struct yaffs_checkpt_dev *cp)
++{
++	dev->n_erased_blocks = cp->n_erased_blocks;
++	dev->alloc_block = cp->alloc_block;
++	dev->alloc_page = cp->alloc_page;
++	dev->n_free_chunks = cp->n_free_chunks;
++
++	dev->n_deleted_files = cp->n_deleted_files;
++	dev->n_unlinked_files = cp->n_unlinked_files;
++	dev->n_bg_deletions = cp->n_bg_deletions;
++	dev->seq_number = cp->seq_number;
++}
++
++static int yaffs2_wr_checkpt_dev(struct yaffs_dev *dev)
++{
++	struct yaffs_checkpt_dev cp;
++	u32 n_bytes;
++	u32 n_blocks = dev->internal_end_block - dev->internal_start_block + 1;
++	int ok;
++
++	/* Write device runtime values */
++	yaffs2_dev_to_checkpt_dev(&cp, dev);
++	cp.struct_type = sizeof(cp);
++
++	ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp));
++	if (!ok)
++		return 0;
++
++	/* Write block info */
++	n_bytes = n_blocks * sizeof(struct yaffs_block_info);
++	ok = (yaffs2_checkpt_wr(dev, dev->block_info, n_bytes) == n_bytes);
++	if (!ok)
++		return 0;
++
++	/* Write chunk bits */
++	n_bytes = n_blocks * dev->chunk_bit_stride;
++	ok = (yaffs2_checkpt_wr(dev, dev->chunk_bits, n_bytes) == n_bytes);
++
++	return ok ? 1 : 0;
++}
++
++static int yaffs2_rd_checkpt_dev(struct yaffs_dev *dev)
++{
++	struct yaffs_checkpt_dev cp;
++	u32 n_bytes;
++	u32 n_blocks =
++	    (dev->internal_end_block - dev->internal_start_block + 1);
++	int ok;
++
++	ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));
++	if (!ok)
++		return 0;
++
++	if (cp.struct_type != sizeof(cp))
++		return 0;
++
++	yaffs_checkpt_dev_to_dev(dev, &cp);
++
++	n_bytes = n_blocks * sizeof(struct yaffs_block_info);
++
++	ok = (yaffs2_checkpt_rd(dev, dev->block_info, n_bytes) == n_bytes);
++
++	if (!ok)
++		return 0;
++
++	n_bytes = n_blocks * dev->chunk_bit_stride;
++
++	ok = (yaffs2_checkpt_rd(dev, dev->chunk_bits, n_bytes) == n_bytes);
++
++	return ok ? 1 : 0;
++}
++
++static void yaffs2_obj_checkpt_obj(struct yaffs_checkpt_obj *cp,
++				   struct yaffs_obj *obj)
++{
++	cp->obj_id = obj->obj_id;
++	cp->parent_id = (obj->parent) ? obj->parent->obj_id : 0;
++	cp->hdr_chunk = obj->hdr_chunk;
++	cp->variant_type = obj->variant_type;
++	cp->deleted = obj->deleted;
++	cp->soft_del = obj->soft_del;
++	cp->unlinked = obj->unlinked;
++	cp->fake = obj->fake;
++	cp->rename_allowed = obj->rename_allowed;
++	cp->unlink_allowed = obj->unlink_allowed;
++	cp->serial = obj->serial;
++	cp->n_data_chunks = obj->n_data_chunks;
++
++	if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
++		cp->size_or_equiv_obj = obj->variant.file_variant.file_size;
++	else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK)
++		cp->size_or_equiv_obj = obj->variant.hardlink_variant.equiv_id;
++}
++
++static int yaffs2_checkpt_obj_to_obj(struct yaffs_obj *obj,
++				     struct yaffs_checkpt_obj *cp)
++{
++	struct yaffs_obj *parent;
++
++	if (obj->variant_type != cp->variant_type) {
++		yaffs_trace(YAFFS_TRACE_ERROR,
++			"Checkpoint read object %d type %d chunk %d does not match existing object type %d",
++			cp->obj_id, cp->variant_type, cp->hdr_chunk,
++			obj->variant_type);
++		return 0;
++	}
++
++	obj->obj_id = cp->obj_id;
++
++	if (cp->parent_id)
++		parent = yaffs_find_or_create_by_number(obj->my_dev,
++						cp->parent_id,
++						YAFFS_OBJECT_TYPE_DIRECTORY);
++	else
++		parent = NULL;
++
++	if (parent) {
++		if (parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
++			yaffs_trace(YAFFS_TRACE_ALWAYS,
++				"Checkpoint read object %d parent %d type %d chunk %d Parent type, %d, not directory",
++				cp->obj_id, cp->parent_id,
++				cp->variant_type, cp->hdr_chunk,
++				parent->variant_type);
++			return 0;
++		}
++		yaffs_add_obj_to_dir(parent, obj);
++	}
++
++	obj->hdr_chunk = cp->hdr_chunk;
++	obj->variant_type = cp->variant_type;
++	obj->deleted = cp->deleted;
++	obj->soft_del = cp->soft_del;
++	obj->unlinked = cp->unlinked;
++	obj->fake = cp->fake;
++	obj->rename_allowed = cp->rename_allowed;
++	obj->unlink_allowed = cp->unlink_allowed;
++	obj->serial = cp->serial;
++	obj->n_data_chunks = cp->n_data_chunks;
++
++	if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
++		obj->variant.file_variant.file_size = cp->size_or_equiv_obj;
++	else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK)
++		obj->variant.hardlink_variant.equiv_id = cp->size_or_equiv_obj;
++
++	if (obj->hdr_chunk > 0)
++		obj->lazy_loaded = 1;
++	return 1;
++}
++
++static int yaffs2_checkpt_tnode_worker(struct yaffs_obj *in,
++				       struct yaffs_tnode *tn, u32 level,
++				       int chunk_offset)
++{
++	int i;
++	struct yaffs_dev *dev = in->my_dev;
++	int ok = 1;
++	u32 base_offset;
++
++	if (!tn)
++		return 1;
++
++	if (level > 0) {
++		for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
++			if (!tn->internal[i])
++				continue;
++			ok = yaffs2_checkpt_tnode_worker(in,
++				 tn->internal[i],
++				 level - 1,
++				 (chunk_offset <<
++				  YAFFS_TNODES_INTERNAL_BITS) + i);
++		}
++		return ok;
++	}
++
++	/* Level 0 tnode */
++	base_offset = chunk_offset << YAFFS_TNODES_LEVEL0_BITS;
++	ok = (yaffs2_checkpt_wr(dev, &base_offset, sizeof(base_offset)) ==
++			sizeof(base_offset));
++	if (ok)
++		ok = (yaffs2_checkpt_wr(dev, tn, dev->tnode_size) ==
++			dev->tnode_size);
++
++	return ok;
++}
++
++static int yaffs2_wr_checkpt_tnodes(struct yaffs_obj *obj)
++{
++	u32 end_marker = ~0;
++	int ok = 1;
++
++	if (obj->variant_type != YAFFS_OBJECT_TYPE_FILE)
++		return ok;
++
++	ok = yaffs2_checkpt_tnode_worker(obj,
++					 obj->variant.file_variant.top,
++					 obj->variant.file_variant.
++					 top_level, 0);
++	if (ok)
++		ok = (yaffs2_checkpt_wr(obj->my_dev, &end_marker,
++				sizeof(end_marker)) == sizeof(end_marker));
++
++	return ok ? 1 : 0;
++}
++
++static int yaffs2_rd_checkpt_tnodes(struct yaffs_obj *obj)
++{
++	u32 base_chunk;
++	int ok = 1;
++	struct yaffs_dev *dev = obj->my_dev;
++	struct yaffs_file_var *file_stuct_ptr = &obj->variant.file_variant;
++	struct yaffs_tnode *tn;
++	int nread = 0;
++
++	ok = (yaffs2_checkpt_rd(dev, &base_chunk, sizeof(base_chunk)) ==
++	      sizeof(base_chunk));
++
++	while (ok && (~base_chunk)) {
++		nread++;
++		/* Read level 0 tnode */
++
++		tn = yaffs_get_tnode(dev);
++		if (tn)
++			ok = (yaffs2_checkpt_rd(dev, tn, dev->tnode_size) ==
++				dev->tnode_size);
++		else
++			ok = 0;
++
++		if (tn && ok)
++			ok = yaffs_add_find_tnode_0(dev,
++						    file_stuct_ptr,
++						    base_chunk, tn) ? 1 : 0;
++
++		if (ok)
++			ok = (yaffs2_checkpt_rd
++			      (dev, &base_chunk,
++			       sizeof(base_chunk)) == sizeof(base_chunk));
++	}
++
++	yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++		"Checkpoint read tnodes %d records, last %d. ok %d",
++		nread, base_chunk, ok);
++
++	return ok ? 1 : 0;
++}
++
++static int yaffs2_wr_checkpt_objs(struct yaffs_dev *dev)
++{
++	struct yaffs_obj *obj;
++	struct yaffs_checkpt_obj cp;
++	int i;
++	int ok = 1;
++	struct list_head *lh;
++
++	/* Iterate through the objects in each hash entry,
++	 * dumping them to the checkpointing stream.
++	 */
++
++	for (i = 0; ok && i < YAFFS_NOBJECT_BUCKETS; i++) {
++		list_for_each(lh, &dev->obj_bucket[i].list) {
++			obj = list_entry(lh, struct yaffs_obj, hash_link);
++			if (!obj->defered_free) {
++				yaffs2_obj_checkpt_obj(&cp, obj);
++				cp.struct_type = sizeof(cp);
++
++				yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++					"Checkpoint write object %d parent %d type %d chunk %d obj addr %p",
++					cp.obj_id, cp.parent_id,
++					cp.variant_type, cp.hdr_chunk, obj);
++
++				ok = (yaffs2_checkpt_wr(dev, &cp,
++						sizeof(cp)) == sizeof(cp));
++
++				if (ok &&
++					obj->variant_type ==
++					YAFFS_OBJECT_TYPE_FILE)
++					ok = yaffs2_wr_checkpt_tnodes(obj);
++			}
++		}
++	}
++
++	/* Dump end of list */
++	memset(&cp, 0xff, sizeof(struct yaffs_checkpt_obj));
++	cp.struct_type = sizeof(cp);
++
++	if (ok)
++		ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp));
++
++	return ok ? 1 : 0;
++}
++
++static int yaffs2_rd_checkpt_objs(struct yaffs_dev *dev)
++{
++	struct yaffs_obj *obj;
++	struct yaffs_checkpt_obj cp;
++	int ok = 1;
++	int done = 0;
++	LIST_HEAD(hard_list);
++
++
++	while (ok && !done) {
++		ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));
++		if (cp.struct_type != sizeof(cp)) {
++			yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++				"struct size %d instead of %d ok %d",
++				cp.struct_type, (int)sizeof(cp), ok);
++			ok = 0;
++		}
++
++		yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++			"Checkpoint read object %d parent %d type %d chunk %d ",
++			cp.obj_id, cp.parent_id, cp.variant_type,
++			cp.hdr_chunk);
++
++		if (ok && cp.obj_id == ~0) {
++			done = 1;
++		} else if (ok) {
++			obj =
++			    yaffs_find_or_create_by_number(dev, cp.obj_id,
++							   cp.variant_type);
++			if (obj) {
++				ok = yaffs2_checkpt_obj_to_obj(obj, &cp);
++				if (!ok)
++					break;
++				if (obj->variant_type ==
++					YAFFS_OBJECT_TYPE_FILE) {
++					ok = yaffs2_rd_checkpt_tnodes(obj);
++				} else if (obj->variant_type ==
++					YAFFS_OBJECT_TYPE_HARDLINK) {
++					list_add(&obj->hard_links, &hard_list);
++				}
++			} else {
++				ok = 0;
++			}
++		}
++	}
++
++	if (ok)
++		yaffs_link_fixup(dev, &hard_list);
++
++	return ok ? 1 : 0;
++}
++
++static int yaffs2_wr_checkpt_sum(struct yaffs_dev *dev)
++{
++	u32 checkpt_sum;
++	int ok;
++
++	yaffs2_get_checkpt_sum(dev, &checkpt_sum);
++
++	ok = (yaffs2_checkpt_wr(dev, &checkpt_sum, sizeof(checkpt_sum)) ==
++		sizeof(checkpt_sum));
++
++	if (!ok)
++		return 0;
++
++	return 1;
++}
++
++static int yaffs2_rd_checkpt_sum(struct yaffs_dev *dev)
++{
++	u32 checkpt_sum0;
++	u32 checkpt_sum1;
++	int ok;
++
++	yaffs2_get_checkpt_sum(dev, &checkpt_sum0);
++
++	ok = (yaffs2_checkpt_rd(dev, &checkpt_sum1, sizeof(checkpt_sum1)) ==
++		sizeof(checkpt_sum1));
++
++	if (!ok)
++		return 0;
++
++	if (checkpt_sum0 != checkpt_sum1)
++		return 0;
++
++	return 1;
++}
++
++static int yaffs2_wr_checkpt_data(struct yaffs_dev *dev)
++{
++	int ok = 1;
++
++	if (!yaffs2_checkpt_required(dev)) {
++		yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++			"skipping checkpoint write");
++		ok = 0;
++	}
++
++	if (ok)
++		ok = yaffs2_checkpt_open(dev, 1);
++
++	if (ok) {
++		yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++			"write checkpoint validity");
++		ok = yaffs2_wr_checkpt_validity_marker(dev, 1);
++	}
++	if (ok) {
++		yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++			"write checkpoint device");
++		ok = yaffs2_wr_checkpt_dev(dev);
++	}
++	if (ok) {
++		yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++			"write checkpoint objects");
++		ok = yaffs2_wr_checkpt_objs(dev);
++	}
++	if (ok) {
++		yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++			"write checkpoint validity");
++		ok = yaffs2_wr_checkpt_validity_marker(dev, 0);
++	}
++
++	if (ok)
++		ok = yaffs2_wr_checkpt_sum(dev);
++
++	if (!yaffs_checkpt_close(dev))
++		ok = 0;
++
++	if (ok)
++		dev->is_checkpointed = 1;
++	else
++		dev->is_checkpointed = 0;
++
++	return dev->is_checkpointed;
++}
++
++static int yaffs2_rd_checkpt_data(struct yaffs_dev *dev)
++{
++	int ok = 1;
++
++	if (!dev->param.is_yaffs2)
++		ok = 0;
++
++	if (ok && dev->param.skip_checkpt_rd) {
++		yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++			"skipping checkpoint read");
++		ok = 0;
++	}
++
++	if (ok)
++		ok = yaffs2_checkpt_open(dev, 0); /* open for read */
++
++	if (ok) {
++		yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++			"read checkpoint validity");
++		ok = yaffs2_rd_checkpt_validity_marker(dev, 1);
++	}
++	if (ok) {
++		yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++			"read checkpoint device");
++		ok = yaffs2_rd_checkpt_dev(dev);
++	}
++	if (ok) {
++		yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++			"read checkpoint objects");
++		ok = yaffs2_rd_checkpt_objs(dev);
++	}
++	if (ok) {
++		yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++			"read checkpoint validity");
++		ok = yaffs2_rd_checkpt_validity_marker(dev, 0);
++	}
++
++	if (ok) {
++		ok = yaffs2_rd_checkpt_sum(dev);
++		yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++			"read checkpoint checksum %d", ok);
++	}
++
++	if (!yaffs_checkpt_close(dev))
++		ok = 0;
++
++	if (ok)
++		dev->is_checkpointed = 1;
++	else
++		dev->is_checkpointed = 0;
++
++	return ok ? 1 : 0;
++}
++
++void yaffs2_checkpt_invalidate(struct yaffs_dev *dev)
++{
++	if (dev->is_checkpointed || dev->blocks_in_checkpt > 0) {
++		dev->is_checkpointed = 0;
++		yaffs2_checkpt_invalidate_stream(dev);
++	}
++	if (dev->param.sb_dirty_fn)
++		dev->param.sb_dirty_fn(dev);
++}
++
++int yaffs_checkpoint_save(struct yaffs_dev *dev)
++{
++	yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++		"save entry: is_checkpointed %d",
++		dev->is_checkpointed);
++
++	yaffs_verify_objects(dev);
++	yaffs_verify_blocks(dev);
++	yaffs_verify_free_chunks(dev);
++
++	if (!dev->is_checkpointed) {
++		yaffs2_checkpt_invalidate(dev);
++		yaffs2_wr_checkpt_data(dev);
++	}
++
++	yaffs_trace(YAFFS_TRACE_CHECKPOINT | YAFFS_TRACE_MOUNT,
++		"save exit: is_checkpointed %d",
++		dev->is_checkpointed);
++
++	return dev->is_checkpointed;
++}
++
++int yaffs2_checkpt_restore(struct yaffs_dev *dev)
++{
++	int retval;
++
++	yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++		"restore entry: is_checkpointed %d",
++		dev->is_checkpointed);
++
++	retval = yaffs2_rd_checkpt_data(dev);
++
++	if (dev->is_checkpointed) {
++		yaffs_verify_objects(dev);
++		yaffs_verify_blocks(dev);
++		yaffs_verify_free_chunks(dev);
++	}
++
++	yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++		"restore exit: is_checkpointed %d",
++		dev->is_checkpointed);
++
++	return retval;
++}
++
++int yaffs2_handle_hole(struct yaffs_obj *obj, loff_t new_size)
++{
++	/* if new_size > old_file_size.
++	 * We're going to be writing a hole.
++	 * If the hole is small then write zeros otherwise write a start
++	 * of hole marker.
++	 */
++	loff_t old_file_size;
++	loff_t increase;
++	int small_hole;
++	int result = YAFFS_OK;
++	struct yaffs_dev *dev = NULL;
++	u8 *local_buffer = NULL;
++	int small_increase_ok = 0;
++
++	if (!obj)
++		return YAFFS_FAIL;
++
++	if (obj->variant_type != YAFFS_OBJECT_TYPE_FILE)
++		return YAFFS_FAIL;
++
++	dev = obj->my_dev;
++
++	/* Bail out if not yaffs2 mode */
++	if (!dev->param.is_yaffs2)
++		return YAFFS_OK;
++
++	old_file_size = obj->variant.file_variant.file_size;
++
++	if (new_size <= old_file_size)
++		return YAFFS_OK;
++
++	increase = new_size - old_file_size;
++
++	if (increase < YAFFS_SMALL_HOLE_THRESHOLD * dev->data_bytes_per_chunk &&
++	    yaffs_check_alloc_available(dev, YAFFS_SMALL_HOLE_THRESHOLD + 1))
++		small_hole = 1;
++	else
++		small_hole = 0;
++
++	if (small_hole)
++		local_buffer = yaffs_get_temp_buffer(dev);
++
++	if (local_buffer) {
++		/* fill hole with zero bytes */
++		loff_t pos = old_file_size;
++		int this_write;
++		int written;
++		memset(local_buffer, 0, dev->data_bytes_per_chunk);
++		small_increase_ok = 1;
++
++		while (increase > 0 && small_increase_ok) {
++			this_write = increase;
++			if (this_write > dev->data_bytes_per_chunk)
++				this_write = dev->data_bytes_per_chunk;
++			written =
++			    yaffs_do_file_wr(obj, local_buffer, pos, this_write,
++					     0);
++			if (written == this_write) {
++				pos += this_write;
++				increase -= this_write;
++			} else {
++				small_increase_ok = 0;
++			}
++		}
++
++		yaffs_release_temp_buffer(dev, local_buffer);
++
++		/* If out of space then reverse any chunks we've added */
++		if (!small_increase_ok)
++			yaffs_resize_file_down(obj, old_file_size);
++	}
++
++	if (!small_increase_ok &&
++	    obj->parent &&
++	    obj->parent->obj_id != YAFFS_OBJECTID_UNLINKED &&
++	    obj->parent->obj_id != YAFFS_OBJECTID_DELETED) {
++		/* Write a hole start header with the old file size */
++		yaffs_update_oh(obj, NULL, 0, 1, 0, NULL);
++	}
++
++	return result;
++}
++
++struct yaffs_block_index {
++	int seq;
++	int block;
++};
++
++static int yaffs2_ybicmp(const void *a, const void *b)
++{
++	int aseq = ((struct yaffs_block_index *)a)->seq;
++	int bseq = ((struct yaffs_block_index *)b)->seq;
++	int ablock = ((struct yaffs_block_index *)a)->block;
++	int bblock = ((struct yaffs_block_index *)b)->block;
++
++	if (aseq == bseq)
++		return ablock - bblock;
++
++	return aseq - bseq;
++}
++
++static inline int yaffs2_scan_chunk(struct yaffs_dev *dev,
++		struct yaffs_block_info *bi,
++		int blk, int chunk_in_block,
++		int *found_chunks,
++		u8 *chunk_data,
++		struct list_head *hard_list,
++		int summary_available)
++{
++	struct yaffs_obj_hdr *oh;
++	struct yaffs_obj *in;
++	struct yaffs_obj *parent;
++	int equiv_id;
++	loff_t file_size;
++	int is_shrink;
++	int is_unlinked;
++	struct yaffs_ext_tags tags;
++	int result;
++	int alloc_failed = 0;
++	int chunk = blk * dev->param.chunks_per_block + chunk_in_block;
++	struct yaffs_file_var *file_var;
++	struct yaffs_hardlink_var *hl_var;
++	struct yaffs_symlink_var *sl_var;
++
++	if (summary_available) {
++		result = yaffs_summary_fetch(dev, &tags, chunk_in_block);
++		tags.seq_number = bi->seq_number;
++	}
++
++	if (!summary_available || tags.obj_id == 0) {
++		result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL, &tags);
++		dev->tags_used++;
++	} else {
++		dev->summary_used++;
++	}
++
++	/* Let's have a good look at this chunk... */
++
++	if (!tags.chunk_used) {
++		/* An unassigned chunk in the block.
++		 * If there are used chunks after this one, then
++		 * it is a chunk that was skipped due to failing
++		 * the erased check. Just skip it so that it can
++		 * be deleted.
++		 * But, more typically, We get here when this is
++		 * an unallocated chunk and his means that
++		 * either the block is empty or this is the one
++		 * being allocated from
++		 */
++
++		if (*found_chunks) {
++			/* This is a chunk that was skipped due
++			 * to failing the erased check */
++		} else if (chunk_in_block == 0) {
++			/* We're looking at the first chunk in
++			 * the block so the block is unused */
++			bi->block_state = YAFFS_BLOCK_STATE_EMPTY;
++			dev->n_erased_blocks++;
++		} else {
++			if (bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN ||
++			    bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING) {
++				if (dev->seq_number == bi->seq_number) {
++					/* Allocating from this block*/
++					yaffs_trace(YAFFS_TRACE_SCAN,
++					    " Allocating from %d %d",
++					    blk, chunk_in_block);
++
++					bi->block_state =
++						YAFFS_BLOCK_STATE_ALLOCATING;
++					dev->alloc_block = blk;
++					dev->alloc_page = chunk_in_block;
++					dev->alloc_block_finder = blk;
++				} else {
++					/* This is a partially written block
++					 * that is not the current
++					 * allocation block.
++					 */
++					yaffs_trace(YAFFS_TRACE_SCAN,
++						"Partially written block %d detected. gc will fix this.",
++						blk);
++				}
++			}
++		}
++
++		dev->n_free_chunks++;
++
++	} else if (tags.ecc_result ==
++		YAFFS_ECC_RESULT_UNFIXED) {
++		yaffs_trace(YAFFS_TRACE_SCAN,
++			" Unfixed ECC in chunk(%d:%d), chunk ignored",
++			blk, chunk_in_block);
++			dev->n_free_chunks++;
++	} else if (tags.obj_id > YAFFS_MAX_OBJECT_ID ||
++		   tags.chunk_id > YAFFS_MAX_CHUNK_ID ||
++		   tags.obj_id == YAFFS_OBJECTID_SUMMARY ||
++		   (tags.chunk_id > 0 &&
++		     tags.n_bytes > dev->data_bytes_per_chunk) ||
++		   tags.seq_number != bi->seq_number) {
++		yaffs_trace(YAFFS_TRACE_SCAN,
++			"Chunk (%d:%d) with bad tags:obj = %d, chunk_id = %d, n_bytes = %d, ignored",
++			blk, chunk_in_block, tags.obj_id,
++			tags.chunk_id, tags.n_bytes);
++		dev->n_free_chunks++;
++	} else if (tags.chunk_id > 0) {
++		/* chunk_id > 0 so it is a data chunk... */
++		loff_t endpos;
++		loff_t chunk_base = (tags.chunk_id - 1) *
++					dev->data_bytes_per_chunk;
++
++		*found_chunks = 1;
++
++		yaffs_set_chunk_bit(dev, blk, chunk_in_block);
++		bi->pages_in_use++;
++
++		in = yaffs_find_or_create_by_number(dev,
++					tags.obj_id,
++					YAFFS_OBJECT_TYPE_FILE);
++		if (!in)
++			/* Out of memory */
++			alloc_failed = 1;
++
++		if (in &&
++		    in->variant_type == YAFFS_OBJECT_TYPE_FILE &&
++		    chunk_base < in->variant.file_variant.shrink_size) {
++			/* This has not been invalidated by
++			 * a resize */
++			if (!yaffs_put_chunk_in_file(in, tags.chunk_id,
++								chunk, -1))
++				alloc_failed = 1;
++
++			/* File size is calculated by looking at
++			 * the data chunks if we have not
++			 * seen an object header yet.
++			 * Stop this practice once we find an
++			 * object header.
++			 */
++			endpos = chunk_base + tags.n_bytes;
++
++			if (!in->valid &&
++			    in->variant.file_variant.scanned_size < endpos) {
++				in->variant.file_variant.
++				    scanned_size = endpos;
++				in->variant.file_variant.
++				    file_size = endpos;
++			}
++		} else if (in) {
++			/* This chunk has been invalidated by a
++			 * resize, or a past file deletion
++			 * so delete the chunk*/
++			yaffs_chunk_del(dev, chunk, 1, __LINE__);
++		}
++	} else {
++		/* chunk_id == 0, so it is an ObjectHeader.
++		 * Thus, we read in the object header and make
++		 * the object
++		 */
++		*found_chunks = 1;
++
++		yaffs_set_chunk_bit(dev, blk, chunk_in_block);
++		bi->pages_in_use++;
++
++		oh = NULL;
++		in = NULL;
++
++		if (tags.extra_available) {
++			in = yaffs_find_or_create_by_number(dev,
++					tags.obj_id,
++					tags.extra_obj_type);
++			if (!in)
++				alloc_failed = 1;
++		}
++
++		if (!in ||
++		    (!in->valid && dev->param.disable_lazy_load) ||
++		    tags.extra_shadows ||
++		    (!in->valid && (tags.obj_id == YAFFS_OBJECTID_ROOT ||
++				 tags.obj_id == YAFFS_OBJECTID_LOSTNFOUND))) {
++
++			/* If we don't have  valid info then we
++			 * need to read the chunk
++			 * TODO In future we can probably defer
++			 * reading the chunk and living with
++			 * invalid data until needed.
++			 */
++
++			result = yaffs_rd_chunk_tags_nand(dev,
++						  chunk,
++						  chunk_data,
++						  NULL);
++
++			oh = (struct yaffs_obj_hdr *)chunk_data;
++
++			if (dev->param.inband_tags) {
++				/* Fix up the header if they got
++				 * corrupted by inband tags */
++				oh->shadows_obj =
++				    oh->inband_shadowed_obj_id;
++				oh->is_shrink =
++				    oh->inband_is_shrink;
++			}
++
++			if (!in) {
++				in = yaffs_find_or_create_by_number(dev,
++							tags.obj_id, oh->type);
++				if (!in)
++					alloc_failed = 1;
++			}
++		}
++
++		if (!in) {
++			/* TODO Hoosterman we have a problem! */
++			yaffs_trace(YAFFS_TRACE_ERROR,
++				"yaffs tragedy: Could not make object for object  %d at chunk %d during scan",
++				tags.obj_id, chunk);
++			return YAFFS_FAIL;
++		}
++
++		if (in->valid) {
++			/* We have already filled this one.
++			 * We have a duplicate that will be
++			 * discarded, but we first have to suck
++			 * out resize info if it is a file.
++			 */
++			if ((in->variant_type == YAFFS_OBJECT_TYPE_FILE) &&
++				((oh && oh->type == YAFFS_OBJECT_TYPE_FILE) ||
++				 (tags.extra_available &&
++				  tags.extra_obj_type == YAFFS_OBJECT_TYPE_FILE)
++				)) {
++				loff_t this_size = (oh) ?
++					yaffs_oh_to_size(oh) :
++					tags.extra_file_size;
++				u32 parent_obj_id = (oh) ?
++					oh->parent_obj_id :
++					tags.extra_parent_id;
++
++				is_shrink = (oh) ?
++					oh->is_shrink :
++					tags.extra_is_shrink;
++
++				/* If it is deleted (unlinked
++				 * at start also means deleted)
++				 * we treat the file size as
++				 * being zeroed at this point.
++				 */
++				if (parent_obj_id == YAFFS_OBJECTID_DELETED ||
++				    parent_obj_id == YAFFS_OBJECTID_UNLINKED) {
++					this_size = 0;
++					is_shrink = 1;
++				}
++
++				if (is_shrink &&
++				    in->variant.file_variant.shrink_size >
++				    this_size)
++					in->variant.file_variant.shrink_size =
++					this_size;
++
++				if (is_shrink)
++					bi->has_shrink_hdr = 1;
++			}
++			/* Use existing - destroy this one. */
++			yaffs_chunk_del(dev, chunk, 1, __LINE__);
++		}
++
++		if (!in->valid && in->variant_type !=
++		    (oh ? oh->type : tags.extra_obj_type)) {
++			yaffs_trace(YAFFS_TRACE_ERROR,
++				"yaffs tragedy: Bad type, %d != %d, for object %d at chunk %d during scan",
++				oh ? oh->type : tags.extra_obj_type,
++				in->variant_type, tags.obj_id,
++				chunk);
++			in = yaffs_retype_obj(in, oh ? oh->type : tags.extra_obj_type);
++		}
++
++		if (!in->valid &&
++		    (tags.obj_id == YAFFS_OBJECTID_ROOT ||
++		     tags.obj_id == YAFFS_OBJECTID_LOSTNFOUND)) {
++			/* We only load some info, don't fiddle
++			 * with directory structure */
++			in->valid = 1;
++
++			if (oh) {
++				in->yst_mode = oh->yst_mode;
++				yaffs_load_attribs(in, oh);
++				in->lazy_loaded = 0;
++			} else {
++				in->lazy_loaded = 1;
++			}
++			in->hdr_chunk = chunk;
++
++		} else if (!in->valid) {
++			/* we need to load this info */
++			in->valid = 1;
++			in->hdr_chunk = chunk;
++			if (oh) {
++				in->variant_type = oh->type;
++				in->yst_mode = oh->yst_mode;
++				yaffs_load_attribs(in, oh);
++
++				if (oh->shadows_obj > 0)
++					yaffs_handle_shadowed_obj(dev,
++					     oh->shadows_obj, 1);
++
++				yaffs_set_obj_name_from_oh(in, oh);
++				parent = yaffs_find_or_create_by_number(dev,
++						oh->parent_obj_id,
++						YAFFS_OBJECT_TYPE_DIRECTORY);
++				file_size = yaffs_oh_to_size(oh);
++				is_shrink = oh->is_shrink;
++				equiv_id = oh->equiv_id;
++			} else {
++				in->variant_type = tags.extra_obj_type;
++				parent = yaffs_find_or_create_by_number(dev,
++						tags.extra_parent_id,
++						YAFFS_OBJECT_TYPE_DIRECTORY);
++				file_size = tags.extra_file_size;
++				is_shrink = tags.extra_is_shrink;
++				equiv_id = tags.extra_equiv_id;
++				in->lazy_loaded = 1;
++			}
++			in->dirty = 0;
++
++			if (!parent)
++				alloc_failed = 1;
++
++			/* directory stuff...
++			 * hook up to parent
++			 */
++
++			if (parent &&
++			    parent->variant_type == YAFFS_OBJECT_TYPE_UNKNOWN) {
++				/* Set up as a directory */
++				parent->variant_type =
++					YAFFS_OBJECT_TYPE_DIRECTORY;
++				INIT_LIST_HEAD(&parent->
++						variant.dir_variant.children);
++			} else if (!parent ||
++				   parent->variant_type !=
++					YAFFS_OBJECT_TYPE_DIRECTORY) {
++				/* Hoosterman, another problem....
++				 * Trying to use a non-directory as a directory
++				 */
++
++				yaffs_trace(YAFFS_TRACE_ERROR,
++					"yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
++					);
++				parent = dev->lost_n_found;
++			}
++			yaffs_add_obj_to_dir(parent, in);
++
++			is_unlinked = (parent == dev->del_dir) ||
++					(parent == dev->unlinked_dir);
++
++			if (is_shrink)
++				/* Mark the block */
++				bi->has_shrink_hdr = 1;
++
++			/* Note re hardlinks.
++			 * Since we might scan a hardlink before its equivalent
++			 * object is scanned we put them all in a list.
++			 * After scanning is complete, we should have all the
++			 * objects, so we run through this list and fix up all
++			 * the chains.
++			 */
++
++			switch (in->variant_type) {
++			case YAFFS_OBJECT_TYPE_UNKNOWN:
++				/* Todo got a problem */
++				break;
++			case YAFFS_OBJECT_TYPE_FILE:
++				file_var = &in->variant.file_variant;
++				if (file_var->scanned_size < file_size) {
++					/* This covers the case where the file
++					 * size is greater than the data held.
++					 * This will happen if the file is
++					 * resized to be larger than its
++					 * current data extents.
++					 */
++					file_var->file_size = file_size;
++					file_var->scanned_size = file_size;
++				}
++
++				if (file_var->shrink_size > file_size)
++					file_var->shrink_size = file_size;
++
++				break;
++			case YAFFS_OBJECT_TYPE_HARDLINK:
++				hl_var = &in->variant.hardlink_variant;
++				if (!is_unlinked) {
++					hl_var->equiv_id = equiv_id;
++					list_add(&in->hard_links, hard_list);
++				}
++				break;
++			case YAFFS_OBJECT_TYPE_DIRECTORY:
++				/* Do nothing */
++				break;
++			case YAFFS_OBJECT_TYPE_SPECIAL:
++				/* Do nothing */
++				break;
++			case YAFFS_OBJECT_TYPE_SYMLINK:
++				sl_var = &in->variant.symlink_variant;
++				if (oh) {
++					sl_var->alias =
++					    yaffs_clone_str(oh->alias);
++					if (!sl_var->alias)
++						alloc_failed = 1;
++				}
++				break;
++			}
++		}
++	}
++	return alloc_failed ? YAFFS_FAIL : YAFFS_OK;
++}
++
++int yaffs2_scan_backwards(struct yaffs_dev *dev)
++{
++	int blk;
++	int block_iter;
++	int start_iter;
++	int end_iter;
++	int n_to_scan = 0;
++	enum yaffs_block_state state;
++	int c;
++	LIST_HEAD(hard_list);
++	struct yaffs_block_info *bi;
++	u32 seq_number;
++	int n_blocks = dev->internal_end_block - dev->internal_start_block + 1;
++	u8 *chunk_data;
++	int found_chunks;
++	int alloc_failed = 0;
++	struct yaffs_block_index *block_index = NULL;
++	int alt_block_index = 0;
++	int summary_available;
++
++	yaffs_trace(YAFFS_TRACE_SCAN,
++		"yaffs2_scan_backwards starts  intstartblk %d intendblk %d...",
++		dev->internal_start_block, dev->internal_end_block);
++
++	dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER;
++
++	block_index =
++		kmalloc(n_blocks * sizeof(struct yaffs_block_index), GFP_NOFS);
++
++	if (!block_index) {
++		block_index =
++		    vmalloc(n_blocks * sizeof(struct yaffs_block_index));
++		alt_block_index = 1;
++	}
++
++	if (!block_index) {
++		yaffs_trace(YAFFS_TRACE_SCAN,
++			"yaffs2_scan_backwards() could not allocate block index!"
++			);
++		return YAFFS_FAIL;
++	}
++
++	dev->blocks_in_checkpt = 0;
++
++	chunk_data = yaffs_get_temp_buffer(dev);
++
++	/* Scan all the blocks to determine their state */
++	bi = dev->block_info;
++	for (blk = dev->internal_start_block; blk <= dev->internal_end_block;
++	     blk++) {
++		yaffs_clear_chunk_bits(dev, blk);
++		bi->pages_in_use = 0;
++		bi->soft_del_pages = 0;
++
++		yaffs_query_init_block_state(dev, blk, &state, &seq_number);
++
++		bi->block_state = state;
++		bi->seq_number = seq_number;
++
++		if (bi->seq_number == YAFFS_SEQUENCE_CHECKPOINT_DATA)
++			bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;
++		if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK)
++			bi->block_state = YAFFS_BLOCK_STATE_DEAD;
++
++		yaffs_trace(YAFFS_TRACE_SCAN_DEBUG,
++			"Block scanning block %d state %d seq %d",
++			blk, bi->block_state, seq_number);
++
++		if (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT) {
++			dev->blocks_in_checkpt++;
++
++		} else if (bi->block_state == YAFFS_BLOCK_STATE_DEAD) {
++			yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
++				"block %d is bad", blk);
++		} else if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {
++			yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "Block empty ");
++			dev->n_erased_blocks++;
++			dev->n_free_chunks += dev->param.chunks_per_block;
++		} else if (bi->block_state ==
++				YAFFS_BLOCK_STATE_NEEDS_SCAN) {
++			/* Determine the highest sequence number */
++			if (seq_number >= YAFFS_LOWEST_SEQUENCE_NUMBER &&
++			    seq_number < YAFFS_HIGHEST_SEQUENCE_NUMBER) {
++				block_index[n_to_scan].seq = seq_number;
++				block_index[n_to_scan].block = blk;
++				n_to_scan++;
++				if (seq_number >= dev->seq_number)
++					dev->seq_number = seq_number;
++			} else {
++				/* TODO: Nasty sequence number! */
++				yaffs_trace(YAFFS_TRACE_SCAN,
++					"Block scanning block %d has bad sequence number %d",
++					blk, seq_number);
++			}
++		}
++		bi++;
++	}
++
++	yaffs_trace(YAFFS_TRACE_ALWAYS, "%d blocks to be sorted...", n_to_scan);
++
++	cond_resched();
++
++	/* Sort the blocks by sequence number */
++	sort(block_index, n_to_scan, sizeof(struct yaffs_block_index),
++		   yaffs2_ybicmp, NULL);
++
++	cond_resched();
++
++	yaffs_trace(YAFFS_TRACE_SCAN, "...done");
++
++	/* Now scan the blocks looking at the data. */
++	start_iter = 0;
++	end_iter = n_to_scan - 1;
++	yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "%d blocks to scan", n_to_scan);
++
++	/* For each block.... backwards */
++	for (block_iter = end_iter;
++	     !alloc_failed && block_iter >= start_iter;
++	     block_iter--) {
++		/* Cooperative multitasking! This loop can run for so
++		   long that watchdog timers expire. */
++		cond_resched();
++
++		/* get the block to scan in the correct order */
++		blk = block_index[block_iter].block;
++		bi = yaffs_get_block_info(dev, blk);
++
++		summary_available = yaffs_summary_read(dev, dev->sum_tags, blk);
++
++		/* For each chunk in each block that needs scanning.... */
++		found_chunks = 0;
++		if (summary_available)
++			c = dev->chunks_per_summary - 1;
++		else
++			c = dev->param.chunks_per_block - 1;
++
++		for (/* c is already initialised */;
++		     !alloc_failed && c >= 0 &&
++		     (bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN ||
++		      bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING);
++		      c--) {
++			/* Scan backwards...
++			 * Read the tags and decide what to do
++			 */
++			if (yaffs2_scan_chunk(dev, bi, blk, c,
++					&found_chunks, chunk_data,
++					&hard_list, summary_available) ==
++					YAFFS_FAIL)
++				alloc_failed = 1;
++		}
++
++		if (bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN) {
++			/* If we got this far while scanning, then the block
++			 * is fully allocated. */
++			bi->block_state = YAFFS_BLOCK_STATE_FULL;
++		}
++
++		/* Now let's see if it was dirty */
++		if (bi->pages_in_use == 0 &&
++		    !bi->has_shrink_hdr &&
++		    bi->block_state == YAFFS_BLOCK_STATE_FULL) {
++			yaffs_block_became_dirty(dev, blk);
++		}
++	}
++
++	yaffs_skip_rest_of_block(dev);
++
++	if (alt_block_index)
++		vfree(block_index);
++	else
++		kfree(block_index);
++
++	/* Ok, we've done all the scanning.
++	 * Fix up the hard link chains.
++	 * We have scanned all the objects, now it's time to add these
++	 * hardlinks.
++	 */
++	yaffs_link_fixup(dev, &hard_list);
++
++	yaffs_release_temp_buffer(dev, chunk_data);
++
++	if (alloc_failed)
++		return YAFFS_FAIL;
++
++	yaffs_trace(YAFFS_TRACE_SCAN, "yaffs2_scan_backwards ends");
++
++	return YAFFS_OK;
++}
+diff --git a/fs/yaffs2/yaffs_yaffs2.h b/fs/yaffs2/yaffs_yaffs2.h
+new file mode 100644
+index 0000000..2363bfd
+--- /dev/null
++++ b/fs/yaffs2/yaffs_yaffs2.h
+@@ -0,0 +1,39 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ *   for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_YAFFS2_H__
++#define __YAFFS_YAFFS2_H__
++
++#include "yaffs_guts.h"
++
++void yaffs_calc_oldest_dirty_seq(struct yaffs_dev *dev);
++void yaffs2_find_oldest_dirty_seq(struct yaffs_dev *dev);
++void yaffs2_clear_oldest_dirty_seq(struct yaffs_dev *dev,
++				   struct yaffs_block_info *bi);
++void yaffs2_update_oldest_dirty_seq(struct yaffs_dev *dev, unsigned block_no,
++				    struct yaffs_block_info *bi);
++int yaffs_block_ok_for_gc(struct yaffs_dev *dev, struct yaffs_block_info *bi);
++u32 yaffs2_find_refresh_block(struct yaffs_dev *dev);
++int yaffs2_checkpt_required(struct yaffs_dev *dev);
++int yaffs_calc_checkpt_blocks_required(struct yaffs_dev *dev);
++
++void yaffs2_checkpt_invalidate(struct yaffs_dev *dev);
++int yaffs2_checkpt_save(struct yaffs_dev *dev);
++int yaffs2_checkpt_restore(struct yaffs_dev *dev);
++
++int yaffs2_handle_hole(struct yaffs_obj *obj, loff_t new_size);
++int yaffs2_scan_backwards(struct yaffs_dev *dev);
++
++#endif
+diff --git a/fs/yaffs2/yportenv.h b/fs/yaffs2/yportenv.h
+new file mode 100644
+index 0000000..8975af3
+--- /dev/null
++++ b/fs/yaffs2/yportenv.h
+@@ -0,0 +1,85 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ *   for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YPORTENV_H__
++#define __YPORTENV_H__
++
++/*
++ * Define the MTD version in terms of Linux Kernel versions
++ * This allows yaffs to be used independantly of the kernel
++ * as well as with it.
++ */
++
++#define MTD_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c))
++
++#ifdef YAFFS_OUT_OF_TREE
++#include "moduleconfig.h"
++#endif
++
++#include <linux/version.h>
++#define MTD_VERSION_CODE LINUX_VERSION_CODE
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
++#include <linux/config.h>
++#endif
++#include <linux/version.h>
++#include <linux/kernel.h>
++#include <linux/mm.h>
++#include <linux/sched.h>
++#include <linux/string.h>
++#include <linux/slab.h>
++#include <linux/vmalloc.h>
++#include <linux/xattr.h>
++#include <linux/list.h>
++#include <linux/types.h>
++#include <linux/fs.h>
++#include <linux/stat.h>
++#include <linux/sort.h>
++#include <linux/bitops.h>
++
++/*  These type wrappings are used to support Unicode names in WinCE. */
++#define YCHAR char
++#define YUCHAR unsigned char
++#define _Y(x)     x
++
++#define YAFFS_LOSTNFOUND_NAME		"lost+found"
++#define YAFFS_LOSTNFOUND_PREFIX		"obj"
++
++
++#define YAFFS_ROOT_MODE			0755
++#define YAFFS_LOSTNFOUND_MODE		0700
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++#define Y_CURRENT_TIME CURRENT_TIME.tv_sec
++#define Y_TIME_CONVERT(x) (x).tv_sec
++#else
++#define Y_CURRENT_TIME CURRENT_TIME
++#define Y_TIME_CONVERT(x) (x)
++#endif
++
++#define compile_time_assertion(assertion) \
++	({ int x = __builtin_choose_expr(assertion, 0, (void)0); (void) x; })
++
++
++#define yaffs_printf(msk, fmt, ...) \
++	printk(KERN_DEBUG "yaffs: " fmt "\n", ##__VA_ARGS__)
++
++#define yaffs_trace(msk, fmt, ...) do { \
++	if (yaffs_trace_mask & (msk)) \
++		printk(KERN_DEBUG "yaffs: " fmt "\n", ##__VA_ARGS__); \
++} while (0)
++
++
++#endif
+diff --git a/include/asm-generic/seccomp.h b/include/asm-generic/seccomp.h
+new file mode 100644
+index 0000000..9fa1f65
+--- /dev/null
++++ b/include/asm-generic/seccomp.h
+@@ -0,0 +1,30 @@
++/*
++ * include/asm-generic/seccomp.h
++ *
++ * Copyright (C) 2014 Linaro Limited
++ * Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++#ifndef _ASM_GENERIC_SECCOMP_H
++#define _ASM_GENERIC_SECCOMP_H
++
++#include <linux/unistd.h>
++
++#if defined(CONFIG_COMPAT) && !defined(__NR_seccomp_read_32)
++#define __NR_seccomp_read_32		__NR_read
++#define __NR_seccomp_write_32		__NR_write
++#define __NR_seccomp_exit_32		__NR_exit
++#define __NR_seccomp_sigreturn_32	__NR_rt_sigreturn
++#endif /* CONFIG_COMPAT && ! already defined */
++
++#define __NR_seccomp_read		__NR_read
++#define __NR_seccomp_write		__NR_write
++#define __NR_seccomp_exit		__NR_exit
++#ifndef __NR_seccomp_sigreturn
++#define __NR_seccomp_sigreturn		__NR_rt_sigreturn
++#endif
++
++#endif /* _ASM_GENERIC_SECCOMP_H */
+diff --git a/include/dt-bindings/clock/hi3516av200-clock.h b/include/dt-bindings/clock/hi3516av200-clock.h
+new file mode 100644
+index 0000000..6389633
+--- /dev/null
++++ b/include/dt-bindings/clock/hi3516av200-clock.h
+@@ -0,0 +1,106 @@
++/*
++ * Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef __DTS_HI3516AV200_CLOCK_H
++#define __DTS_HI3516AV200_CLOCK_H
++
++/* fixed rate */
++#define HI3516AV200_FIXED_2376M		1
++#define HI3516AV200_FIXED_1188M		2
++#define HI3516AV200_FIXED_594M		3
++#define HI3516AV200_FIXED_297M		4
++#define HI3516AV200_FIXED_148P5M		5
++#define HI3516AV200_FIXED_74P25M		6
++#define HI3516AV200_FIXED_792M		7
++#define HI3516AV200_FIXED_475M		8
++#define HI3516AV200_FIXED_340M		9
++#define HI3516AV200_FIXED_72M		10
++#define HI3516AV200_FIXED_400M		11
++#define HI3516AV200_FIXED_200M		12
++#define HI3516AV200_FIXED_54M		13
++#define HI3516AV200_FIXED_27M		14
++#define HI3516AV200_FIXED_37P125M	        15
++#define HI3516AV200_FIXED_3000M		16
++#define HI3516AV200_FIXED_1500M		17
++#define HI3516AV200_FIXED_500M		18
++#define HI3516AV200_FIXED_250M		19
++#define HI3516AV200_FIXED_125M		20
++#define HI3516AV200_FIXED_1000M		21
++#define HI3516AV200_FIXED_600M		22
++#define HI3516AV200_FIXED_750M		23
++#define HI3516AV200_FIXED_150M		24
++#define HI3516AV200_FIXED_75M		25
++#define HI3516AV200_FIXED_300M		26
++#define HI3516AV200_FIXED_60M		27
++#define HI3516AV200_FIXED_214M		28
++#define HI3516AV200_FIXED_107M		29
++#define HI3516AV200_FIXED_100M		30
++#define HI3516AV200_FIXED_50M		31
++#define HI3516AV200_FIXED_25M		32
++#define HI3516AV200_FIXED_24M		33
++#define HI3516AV200_FIXED_3M                 34
++#define HI3516AV200_FIXED_198M               35
++#define HI3516AV200_FIXED_396M               36
++
++/* mux clocks */
++#define HI3516AV200_FMC_MUX			64
++#define HI3516AV200_I2C_MUX			65
++#define HI3516AV200_UART_MUX			66
++#define HI3516AV200_SYSAXI_MUX			67
++#define HI3516AV200_A17_MUX			68
++#define HI3516AV200_MMC0_MUX			69
++#define HI3516AV200_MMC1_MUX			70
++#define HI3516AV200_MMC2_MUX			71
++
++/*fixed factor clocks*/
++#define HI3516AV200_SYSAPB_CLK		97
++#define HI3516AV200_MMC0_FAC_CLK	98
++#define HI3516AV200_MMC1_FAC_CLK	99
++#define HI3516AV200_MMC2_FAC_CLK	100
++
++/* gate clocks */
++#define HI3516AV200_FMC_CLK			129
++#define HI3516AV200_MMC0_CLK			130
++#define HI3516AV200_MMC1_CLK			131
++#define HI3516AV200_MMC2_CLK			132
++#define HI3516AV200_UART0_CLK		153
++#define HI3516AV200_UART1_CLK		154
++#define HI3516AV200_UART2_CLK		155
++#define HI3516AV200_UART3_CLK		156
++#define HI3516AV200_UART4_CLK		157
++#define HI3516AV200_SPI0_CLK			160
++#define HI3516AV200_SPI1_CLK			161
++#define HI3516AV200_SPI2_CLK			162
++#define HI3516AV200_SPI3_CLK			163
++
++#define HI3516AV200_USB2_CTRL_UTMI0_REQ      183
++#define HI3516AV200_USB2_PHY_PORT0_TREQ      184
++#define HI3516AV200_USB2_PHY_REQ             185
++#define HI3516AV200_USB2_HRST_REQ            186
++#define HI3516AV200_USB2_CLK                 187
++#define HI3516AV200_USB3_CLK                 188
++
++#define HI3516AV200_ETH_CLK			192
++#define HI3516AV200_ETH_MACIF_CLK		193
++
++/* complex */
++#define HI3516AV200_USB_CLK		195
++#define HI3516AV200_APLL_CLK		196
++
++#define HI3516AV200_NR_CLKS		256
++#define HI3516AV200_NR_RSTS		256
++#endif	/* __DTS_HI3516AV200_CLOCK_H */
+diff --git a/include/dt-bindings/clock/hi3516cv300-clock.h b/include/dt-bindings/clock/hi3516cv300-clock.h
+new file mode 100644
+index 0000000..f37a59d
+--- /dev/null
++++ b/include/dt-bindings/clock/hi3516cv300-clock.h
+@@ -0,0 +1,113 @@
++/*
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#ifndef __DTS_HI3516CV300_CLOCK_H
++#define __DTS_HI3516CV300_CLOCK_H
++
++/* clk in hi3516cv300 CRG */
++/* fixed rate clocks */
++#define HI3516CV300_FIXED_3M		1
++#define HI3516CV300_FIXED_6M		2
++#define HI3516CV300_FIXED_12M		3
++#define HI3516CV300_FIXED_15M		4
++#define HI3516CV300_FIXED_24M		5
++#define HI3516CV300_FIXED_25M		6
++#define HI3516CV300_FIXED_27M		7
++#define HI3516CV300_FIXED_37P125M	8
++#define HI3516CV300_FIXED_44M		9
++#define HI3516CV300_FIXED_49P5M		10
++#define HI3516CV300_FIXED_50M		11
++#define HI3516CV300_FIXED_54M		12
++#define HI3516CV300_FIXED_74P25M	13
++#define HI3516CV300_FIXED_75M		14
++#define HI3516CV300_FIXED_83P3M		15
++#define HI3516CV300_FIXED_99M		16
++#define HI3516CV300_FIXED_100M		17
++#define HI3516CV300_FIXED_125M		18
++#define HI3516CV300_FIXED_148P5M	19
++#define HI3516CV300_FIXED_150M		20
++#define HI3516CV300_FIXED_166P6M	21
++#define HI3516CV300_FIXED_198M		22
++#define HI3516CV300_FIXED_200M		23
++#define HI3516CV300_FIXED_250M		24
++#define HI3516CV300_FIXED_297M		25
++#define HI3516CV300_FIXED_300M		26
++#define HI3516CV300_FIXED_396M		27
++#define HI3516CV300_FIXED_400M		28
++
++/* mux clocks */
++#define HI3516CV300_APB_CLK		30
++#define HI3516CV300_UART_MUX		31
++#define HI3516CV300_FMC_MUX		32
++#define HI3516CV300_MMC0_MUX		33
++#define HI3516CV300_MMC1_MUX		34
++#define HI3516CV300_MMC2_MUX		35
++#define HI3516CV300_MMC3_MUX		36
++#define HI3516CV300_SENSOR_MUX		37
++#define HI3516CV300_VIU_MUX		    38
++#define HI3516CV300_VEDU_MUX		39
++#define HI3516CV300_VPSS_MUX		40
++#define HI3516CV300_VGS_MUX		    41
++#define HI3516CV300_IVE_MUX		    42
++#define HI3516CV300_PWM_MUX		    43
++
++/* div clocks */
++#define HI3516CV300_ISP_DIV		    45
++
++/* gate clocks */
++#define HI3516CV300_UART0_CLK		50
++#define HI3516CV300_UART1_CLK		51
++#define HI3516CV300_UART2_CLK		52
++#define HI3516CV300_SPI0_CLK		53
++#define HI3516CV300_SPI1_CLK		54
++#define HI3516CV300_FMC_CLK			55
++#define HI3516CV300_MMC0_CLK		56
++#define HI3516CV300_MMC1_CLK		57
++#define HI3516CV300_MMC2_CLK		58
++#define HI3516CV300_MMC3_CLK		59
++#define HI3516CV300_ETH_CLK			60
++#define HI3516CV300_ETH_MACIF_CLK	61
++#define HI3516CV300_USB2_BUS_CLK	62
++#define HI3516CV300_UTMI0_CLK		63
++#define HI3516CV300_USB2_CLK		64
++#define HI3516CV300_DMAC_CLK		65
++#define HI3516CV300_SENSOR_CLK		66
++#define HI3516CV300_MIPI_CLK		67
++#define HI3516CV300_ISP_CLK			68
++#define HI3516CV300_VIU_CLK			69
++#define HI3516CV300_VEDU_CLK		70
++#define HI3516CV300_VPSS_CLK		71
++#define HI3516CV300_VGS_CLK			72
++#define HI3516CV300_JPGE_CLK		73
++#define HI3516CV300_IVE_CLK			74
++#define HI3516CV300_AIAO_CLK		75
++#define HI3516CV300_PWM_CLK			76
++
++#define HI3516CV300_CRG_NR_CLKS		80
++#define HI3516CV300_CRG_NR_RSTS		0x120
++
++/* clk in hi3518ev200 CRG */
++/* mux clocks */
++#define HI3516CV300_TIME00_CLK		1
++#define HI3516CV300_TIME01_CLK		2
++#define HI3516CV300_TIME10_CLK		3
++#define HI3516CV300_TIME11_CLK		4
++
++#define HI3516CV300_SYS_NR_CLKS		10
++#define HI3516CV300_SYS_NR_RSTS		0x10
++#endif	/* __DTS_HI3516CV300_CLOCK_H */
+diff --git a/include/dt-bindings/clock/hi3519-clock.h b/include/dt-bindings/clock/hi3519-clock.h
+new file mode 100644
+index 0000000..f18c94c
+--- /dev/null
++++ b/include/dt-bindings/clock/hi3519-clock.h
+@@ -0,0 +1,106 @@
++/*
++ * Copyright (c) 2015 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef __DTS_HI3519_CLOCK_H
++#define __DTS_HI3519_CLOCK_H
++
++/* fixed rate */
++#define HI3519_FIXED_2376M		1
++#define HI3519_FIXED_1188M		2
++#define HI3519_FIXED_594M		3
++#define HI3519_FIXED_297M		4
++#define HI3519_FIXED_148P5M		5
++#define HI3519_FIXED_74P25M		6
++#define HI3519_FIXED_792M		7
++#define HI3519_FIXED_475M		8
++#define HI3519_FIXED_340M		9
++#define HI3519_FIXED_72M		10
++#define HI3519_FIXED_400M		11
++#define HI3519_FIXED_200M		12
++#define HI3519_FIXED_54M		13
++#define HI3519_FIXED_27M		14
++#define HI3519_FIXED_37P125M	        15
++#define HI3519_FIXED_3000M		16
++#define HI3519_FIXED_1500M		17
++#define HI3519_FIXED_500M		18
++#define HI3519_FIXED_250M		19
++#define HI3519_FIXED_125M		20
++#define HI3519_FIXED_1000M		21
++#define HI3519_FIXED_600M		22
++#define HI3519_FIXED_750M		23
++#define HI3519_FIXED_150M		24
++#define HI3519_FIXED_75M		25
++#define HI3519_FIXED_300M		26
++#define HI3519_FIXED_60M		27
++#define HI3519_FIXED_214M		28
++#define HI3519_FIXED_107M		29
++#define HI3519_FIXED_100M		30
++#define HI3519_FIXED_50M		31
++#define HI3519_FIXED_25M		32
++#define HI3519_FIXED_24M		33
++#define HI3519_FIXED_3M                 34
++#define HI3519_FIXED_198M               35
++#define HI3519_FIXED_396M               36
++
++/* mux clocks */
++#define HI3519_FMC_MUX			64
++#define HI3519_I2C_MUX			65
++#define HI3519_UART_MUX			66
++#define HI3519_SYSAXI_MUX		67
++#define HI3519_A17_MUX			68
++#define HI3519_MMC0_MUX			69
++#define HI3519_MMC1_MUX			70
++#define HI3519_MMC2_MUX			71
++
++/*fixed factor clocks*/
++#define HI3519_SYSAPB_CLK		97
++#define HI3519_MMC0_FAC_CLK		98
++#define HI3519_MMC1_FAC_CLK		99
++#define HI3519_MMC2_FAC_CLK		100
++
++/* gate clocks */
++#define HI3519_FMC_CLK			129
++#define HI3519_MMC0_CLK			130
++#define HI3519_MMC1_CLK			131
++#define HI3519_MMC2_CLK			132
++#define HI3519_UART0_CLK		153
++#define HI3519_UART1_CLK		154
++#define HI3519_UART2_CLK		155
++#define HI3519_UART3_CLK		156
++#define HI3519_UART4_CLK		157
++#define HI3519_SPI0_CLK			160
++#define HI3519_SPI1_CLK			161
++#define HI3519_SPI2_CLK			162
++#define HI3519_SPI3_CLK			163
++
++#define HI3519_USB2_CTRL_UTMI0_REQ      183
++#define HI3519_USB2_PHY_PORT0_TREQ      184
++#define HI3519_USB2_PHY_REQ             185
++#define HI3519_USB2_HRST_REQ            186
++#define HI3519_USB2_CLK                 187
++#define HI3519_USB3_CLK                 188
++
++#define HI3519_ETH_CLK			192
++#define HI3519_ETH_MACIF_CLK		193
++
++/* complex */
++#define HI3519_USB_CLK		195
++#define HI3519_APLL_CLK		196
++
++#define HI3519_NR_CLKS		256
++#define HI3519_NR_RSTS		256
++#endif	/* __DTS_HI3519_CLOCK_H */
+diff --git a/include/dt-bindings/clock/hi3521d-clock.h b/include/dt-bindings/clock/hi3521d-clock.h
+new file mode 100644
+index 0000000..50d3b64
+--- /dev/null
++++ b/include/dt-bindings/clock/hi3521d-clock.h
+@@ -0,0 +1,86 @@
++/*
++ * Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#ifndef __DTS_HI3521D_CLOCK_H
++#define __DTS_HI3521D_CLOCK_H
++
++/* clk in hi3521D CRG */
++/* fixed rate clocks */
++#define HI3521D_FIXED_3M		1
++#define HI3521D_FIXED_6M		2
++#define HI3521D_FIXED_12M		3
++#define HI3521D_FIXED_24M		4
++#define HI3521D_FIXED_83P3M		5
++#define HI3521D_FIXED_100M		6
++#define HI3521D_FIXED_125M		7
++#define HI3521D_FIXED_148P5M	8
++#define HI3521D_FIXED_150M		9
++#define HI3521D_FIXED_200M		10
++#define HI3521D_FIXED_250M		11
++#define HI3521D_FIXED_300M		12
++#define HI3521D_FIXED_324M		13
++#define HI3521D_FIXED_342M		14
++#define HI3521D_FIXED_375M		15
++#define HI3521D_FIXED_400M		16
++#define HI3521D_FIXED_448M		17
++#define HI3521D_FIXED_500M		18
++#define HI3521D_FIXED_540M		19
++#define HI3521D_FIXED_600M		20
++#define HI3521D_FIXED_750M		21
++#define HI3521D_FIXED_1500M		22
++
++/* mux clocks */
++#define HI3521D_SYSAXI_CLK		25
++#define HI3521D_FMC_MUX			26
++#define HI3521D_UART_MUX		27
++#define HI3521D_VIU_MUX		    28
++
++/* gate clocks */
++#define HI3521D_UART0_CLK		35
++#define HI3521D_UART1_CLK		36
++#define HI3521D_UART2_CLK		37
++#define HI3521D_UART3_CLK		38
++#define HI3521D_SPI0_CLK		39
++#define HI3521D_FMC_CLK			40
++#define HI3521D_ETH_CLK			41
++#define HI3521D_ETH_MACIF_CLK	42
++#define HI3521D_USB2_BUS_CLK	43
++#define HI3521D_USB2_CLK		44
++#define HI3521D_SATA_CLK		45
++#define HI3521D_ETH_PUB_CLK		46
++#define HI3521D_ETH_PHY_CLK		47
++#define HI3521D_VIU_CLK         48
++#define HI3521D_DMAC_CLK		49
++
++#define HI3521D_CRG_NR_CLKS		50
++#define HI3521D_CRG_NR_RSTS		0x200
++
++/* clock in system control */
++/* mux clocks */
++#define HI3521D_TIME0_0_CLK		1
++#define HI3521D_TIME0_1_CLK		2
++#define HI3521D_TIME1_2_CLK		3
++#define HI3521D_TIME1_3_CLK		4
++#define HI3521D_TIME2_4_CLK		5
++#define HI3521D_TIME2_5_CLK		6
++#define HI3521D_TIME3_6_CLK		7
++#define HI3521D_TIME3_7_CLK		8
++
++#define HI3521D_SYS_NR_CLKS		10
++#define HI3521D_SYS_NR_RSTS		0x10
++#endif	/* __DTS_HI3521D_CLOCK_H */
+diff --git a/include/dt-bindings/clock/hi3531d-clock.h b/include/dt-bindings/clock/hi3531d-clock.h
+new file mode 100644
+index 0000000..008e53a
+--- /dev/null
++++ b/include/dt-bindings/clock/hi3531d-clock.h
+@@ -0,0 +1,99 @@
++/*
++ * Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#ifndef __DTS_HI3531D_CLOCK_H
++#define __DTS_HI3531D_CLOCK_H
++
++/* clk in hi3531D CRG */
++/* fixed rate clocks */
++#define HI3531D_FIXED_3M		1
++#define HI3531D_FIXED_6M		2
++#define HI3531D_FIXED_12M		3
++#define HI3531D_FIXED_15M		4
++#define HI3531D_FIXED_24M		5
++#define HI3531D_FIXED_44M		6
++#define HI3531D_FIXED_49P5		7
++#define HI3531D_FIXED_50M		8
++#define HI3531D_FIXED_54M		9
++#define HI3531D_FIXED_75M		10
++#define HI3531D_FIXED_83P3M		11
++#define HI3531D_FIXED_99M		12
++#define HI3531D_FIXED_100M		13
++#define HI3531D_FIXED_125M		14
++#define HI3531D_FIXED_148P5M	15
++#define HI3531D_FIXED_150M		16
++#define HI3531D_FIXED_200M		17
++#define HI3531D_FIXED_250M		18
++#define HI3531D_FIXED_300M		19
++#define HI3531D_FIXED_324M		20
++#define HI3531D_FIXED_342M		21
++#define HI3531D_FIXED_375M		22
++#define HI3531D_FIXED_400M		23
++#define HI3531D_FIXED_448M		24
++#define HI3531D_FIXED_500M		25
++#define HI3531D_FIXED_540M		26
++#define HI3531D_FIXED_600M		27
++#define HI3531D_FIXED_750M		28
++#define HI3531D_FIXED_1500M		29
++
++/* mux clocks */
++#define HI3531D_PERIAXI_CLK		30
++#define HI3531D_SYSAXI_CLK		31
++#define HI3531D_NFC_MUX			32
++#define HI3531D_FMC_MUX			33
++#define HI3531D_UART_MUX		34
++#define HI3531D_VIU_MUX		    58
++
++/* gate clocks */
++#define HI3531D_UART0_CLK		35
++#define HI3531D_UART1_CLK		36
++#define HI3531D_UART2_CLK		37
++#define HI3531D_UART3_CLK		38
++#define HI3531D_UART4_CLK		39
++#define HI3531D_SPI0_CLK		40
++#define HI3531D_I2C0_CLK		41
++#define HI3531D_I2C1_CLK		42
++#define HI3531D_NFC_CLK			43
++#define HI3531D_FMC_CLK			44
++#define HI3531D_ETH_CLK			50
++#define HI3531D_ETH_MACIF_CLK	51
++#define HI3531D_USB2_BUS_CLK	52
++#define HI3531D_UTMI0_CLK		53
++#define HI3531D_USB2_CLK		54
++#define HI3531D_DMAC_CLK		55
++#define HI3531D_SATA_CLK		56
++#define HI3531D_VIU_CLK         57
++/* #define HI3531D_VIU_MUX		58 */
++
++#define HI3531D_CRG_NR_CLKS		60
++#define HI3531D_CRG_NR_RSTS		0x250
++
++/* clock in system control */
++/* mux clocks */
++#define HI3531D_TIME0_0_CLK		1
++#define HI3531D_TIME0_1_CLK		2
++#define HI3531D_TIME1_2_CLK		3
++#define HI3531D_TIME1_3_CLK		4
++#define HI3531D_TIME2_4_CLK		5
++#define HI3531D_TIME2_5_CLK		6
++#define HI3531D_TIME3_6_CLK		7
++#define HI3531D_TIME3_7_CLK		8
++
++#define HI3531D_SYS_NR_CLKS		10
++#define HI3531D_SYS_NR_RSTS		0x10
++#endif	/* __DTS_HI3531D_CLOCK_H */
+diff --git a/include/dt-bindings/clock/hi3536c-clock.h b/include/dt-bindings/clock/hi3536c-clock.h
+new file mode 100644
+index 0000000..e2b1c62
+--- /dev/null
++++ b/include/dt-bindings/clock/hi3536c-clock.h
+@@ -0,0 +1,86 @@
++/*
++ * Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#ifndef __DTS_HI3536C_CLOCK_H
++#define __DTS_HI3536C_CLOCK_H
++
++/* clk in hi3536C CRG */
++/* fixed rate clocks */
++#define HI3536C_FIXED_3M		1
++#define HI3536C_FIXED_6M		2
++#define HI3536C_FIXED_12M		3
++#define HI3536C_FIXED_24M		4
++#define HI3536C_FIXED_83P3M		5
++#define HI3536C_FIXED_100M		6
++#define HI3536C_FIXED_125M		7
++#define HI3536C_FIXED_148P5M	8
++#define HI3536C_FIXED_150M		9
++#define HI3536C_FIXED_200M		10
++#define HI3536C_FIXED_250M		11
++#define HI3536C_FIXED_300M		12
++#define HI3536C_FIXED_324M		13
++#define HI3536C_FIXED_342M		14
++#define HI3536C_FIXED_375M		15
++#define HI3536C_FIXED_400M		16
++#define HI3536C_FIXED_448M		17
++#define HI3536C_FIXED_500M		18
++#define HI3536C_FIXED_540M		19
++#define HI3536C_FIXED_600M		20
++#define HI3536C_FIXED_750M		21
++#define HI3536C_FIXED_1500M		22
++
++/* mux clocks */
++#define HI3536C_SYSAXI_CLK		23
++#define HI3536C_FMC_MUX			24
++#define HI3536C_UART_MUX		25
++
++/* gate clocks */
++#define HI3536C_UART0_CLK		26
++#define HI3536C_UART1_CLK		27
++#define HI3536C_UART2_CLK		28
++#define HI3536C_SPI0_CLK		29
++#define HI3536C_FMC_CLK			30
++#define HI3536C_ETH_CLK			31
++#define HI3536C_ETH_MACIF_CLK	32
++#define HI3536C_USB2_BUS_CLK	33
++#define HI3536C_USB2_CLK		34
++#define HI3536C_SATA_CLK		35
++#define HI3536C_ETH_PUB_CLK		36
++#define HI3536C_ETH_PHY_CLK		37
++#define HI3536C_ETH1_PHY_CLK		38
++#define HI3536C_ETH1_CLK		39
++#define HI3536C_ETH_MACIF1_CLK		40
++#define HI3536C_DMAC_CLK		41
++
++#define HI3536C_CRG_NR_CLKS		50
++#define HI3536C_CRG_NR_RSTS		0x200
++
++/* clock in system control */
++/* mux clocks */
++#define HI3536C_TIME0_0_CLK		1
++#define HI3536C_TIME0_1_CLK		2
++#define HI3536C_TIME1_2_CLK		3
++#define HI3536C_TIME1_3_CLK		4
++#define HI3536C_TIME2_4_CLK		5
++#define HI3536C_TIME2_5_CLK		6
++#define HI3536C_TIME3_6_CLK		7
++#define HI3536C_TIME3_7_CLK		8
++
++#define HI3536C_SYS_NR_CLKS		10
++#define HI3536C_SYS_NR_RSTS		0x10
++#endif	/* __DTS_HI3536C_CLOCK_H */
+diff --git a/include/dt-bindings/clock/hi3556-clock.h b/include/dt-bindings/clock/hi3556-clock.h
+new file mode 100644
+index 0000000..f5103f8
+--- /dev/null
++++ b/include/dt-bindings/clock/hi3556-clock.h
+@@ -0,0 +1,106 @@
++/*
++ * Copyright (c) 2015 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef __DTS_HI3556_CLOCK_H
++#define __DTS_HI3556_CLOCK_H
++
++/* fixed rate */
++#define HI3556_FIXED_2376M		1
++#define HI3556_FIXED_1188M		2
++#define HI3556_FIXED_594M		3
++#define HI3556_FIXED_297M		4
++#define HI3556_FIXED_148P5M		5
++#define HI3556_FIXED_74P25M		6
++#define HI3556_FIXED_792M		7
++#define HI3556_FIXED_475M		8
++#define HI3556_FIXED_340M		9
++#define HI3556_FIXED_72M		10
++#define HI3556_FIXED_400M		11
++#define HI3556_FIXED_200M		12
++#define HI3556_FIXED_54M		13
++#define HI3556_FIXED_27M		14
++#define HI3556_FIXED_37P125M	15
++#define HI3556_FIXED_3000M		16
++#define HI3556_FIXED_1500M		17
++#define HI3556_FIXED_500M		18
++#define HI3556_FIXED_250M		19
++#define HI3556_FIXED_125M		20
++#define HI3556_FIXED_1000M		21
++#define HI3556_FIXED_600M		22
++#define HI3556_FIXED_750M		23
++#define HI3556_FIXED_150M		24
++#define HI3556_FIXED_75M		25
++#define HI3556_FIXED_300M		26
++#define HI3556_FIXED_60M		27
++#define HI3556_FIXED_214M		28
++#define HI3556_FIXED_107M		29
++#define HI3556_FIXED_100M		30
++#define HI3556_FIXED_50M		31
++#define HI3556_FIXED_25M		32
++#define HI3556_FIXED_24M		33
++#define HI3556_FIXED_3M                34
++#define HI3556_FIXED_198M               35
++#define HI3556_FIXED_396M               36
++
++/* mux clocks */
++#define HI3556_FMC_MUX			64
++#define HI3556_I2C_MUX			65
++#define HI3556_UART_MUX			66
++#define HI3556_SYSAXI_MUX		67
++#define HI3556_A17_MUX			68
++#define HI3556_MMC0_MUX			69
++#define HI3556_MMC1_MUX			70
++#define HI3556_MMC2_MUX			71
++
++/*fixed factor clocks*/
++#define HI3556_SYSAPB_CLK		97
++#define HI3556_MMC0_FAC_CLK		98
++#define HI3556_MMC1_FAC_CLK		99
++#define HI3556_MMC2_FAC_CLK		100
++
++/* gate clocks */
++#define HI3556_FMC_CLK			129
++#define HI3556_MMC0_CLK			130
++#define HI3556_MMC1_CLK			131
++#define HI3556_MMC2_CLK			132
++#define HI3556_UART0_CLK		153
++#define HI3556_UART1_CLK		154
++#define HI3556_UART2_CLK		155
++#define HI3556_UART3_CLK		156
++#define HI3556_UART4_CLK		157
++#define HI3556_SPI0_CLK			160
++#define HI3556_SPI1_CLK			161
++#define HI3556_SPI2_CLK			162
++#define HI3556_SPI3_CLK			163
++
++#define HI3556_USB2_CTRL_UTMI0_REQ      183
++#define HI3556_USB2_PHY_PORT0_TREQ      184
++#define HI3556_USB2_PHY_REQ             185
++#define HI3556_USB2_HRST_REQ            186
++#define HI3556_USB2_CLK                 187
++#define HI3556_USB3_CLK                 188
++
++#define HI3556_ETH_CLK			192
++#define HI3556_ETH_MACIF_CLK		193
++
++/* complex */
++#define HI3556_USB_CLK		195
++#define HI3556_APLL_CLK		196
++
++#define HI3556_NR_CLKS		256
++#define HI3556_NR_RSTS		256
++#endif	/* __DTS_HI3556_CLOCK_H */
+diff --git a/include/dt-bindings/clock/hi3559-clock.h b/include/dt-bindings/clock/hi3559-clock.h
+new file mode 100644
+index 0000000..661c15b
+--- /dev/null
++++ b/include/dt-bindings/clock/hi3559-clock.h
+@@ -0,0 +1,106 @@
++/*
++ * Copyright (c) 2015 HiSilicon Technologies Co., Ltd.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef __DTS_HI3559_CLOCK_H
++#define __DTS_HI3559_CLOCK_H
++
++/* fixed rate */
++#define HI3559_FIXED_2376M		1
++#define HI3559_FIXED_1188M		2
++#define HI3559_FIXED_594M		3
++#define HI3559_FIXED_297M		4
++#define HI3559_FIXED_148P5M		5
++#define HI3559_FIXED_74P25M		6
++#define HI3559_FIXED_792M		7
++#define HI3559_FIXED_475M		8
++#define HI3559_FIXED_340M		9
++#define HI3559_FIXED_72M		10
++#define HI3559_FIXED_400M		11
++#define HI3559_FIXED_200M		12
++#define HI3559_FIXED_54M		13
++#define HI3559_FIXED_27M		14
++#define HI3559_FIXED_37P125M	15
++#define HI3559_FIXED_3000M		16
++#define HI3559_FIXED_1500M		17
++#define HI3559_FIXED_500M		18
++#define HI3559_FIXED_250M		19
++#define HI3559_FIXED_125M		20
++#define HI3559_FIXED_1000M		21
++#define HI3559_FIXED_600M		22
++#define HI3559_FIXED_750M		23
++#define HI3559_FIXED_150M		24
++#define HI3559_FIXED_75M		25
++#define HI3559_FIXED_300M		26
++#define HI3559_FIXED_60M		27
++#define HI3559_FIXED_214M		28
++#define HI3559_FIXED_107M		29
++#define HI3559_FIXED_100M		30
++#define HI3559_FIXED_50M		31
++#define HI3559_FIXED_25M		32
++#define HI3559_FIXED_24M		33
++#define HI3559_FIXED_3M                34
++#define HI3559_FIXED_198M               35
++#define HI3559_FIXED_396M               36
++
++/* mux clocks */
++#define HI3559_FMC_MUX			64
++#define HI3559_I2C_MUX			65
++#define HI3559_UART_MUX			66
++#define HI3559_SYSAXI_MUX		67
++#define HI3559_A17_MUX			68
++#define HI3559_MMC0_MUX			69
++#define HI3559_MMC1_MUX			70
++#define HI3559_MMC2_MUX			71
++
++/*fixed factor clocks*/
++#define HI3559_SYSAPB_CLK		97
++#define HI3559_MMC0_FAC_CLK		98
++#define HI3559_MMC1_FAC_CLK		99
++#define HI3559_MMC2_FAC_CLK		100
++
++/* gate clocks */
++#define HI3559_FMC_CLK			129
++#define HI3559_MMC0_CLK			130
++#define HI3559_MMC1_CLK			131
++#define HI3559_MMC2_CLK			132
++#define HI3559_UART0_CLK		153
++#define HI3559_UART1_CLK		154
++#define HI3559_UART2_CLK		155
++#define HI3559_UART3_CLK		156
++#define HI3559_UART4_CLK		157
++#define HI3559_SPI0_CLK			160
++#define HI3559_SPI1_CLK			161
++#define HI3559_SPI2_CLK			162
++#define HI3559_SPI3_CLK			163
++
++#define HI3559_USB2_CTRL_UTMI0_REQ      183
++#define HI3559_USB2_PHY_PORT0_TREQ      184
++#define HI3559_USB2_PHY_REQ             185
++#define HI3559_USB2_HRST_REQ            186
++#define HI3559_USB2_CLK                 187
++#define HI3559_USB3_CLK                 188
++
++#define HI3559_ETH_CLK			192
++#define HI3559_ETH_MACIF_CLK		193
++
++/* complex */
++#define HI3559_USB_CLK		195
++#define HI3559_APLL_CLK		196
++
++#define HI3559_NR_CLKS		256
++#define HI3559_NR_RSTS		256
++#endif	/* __DTS_HI3559_CLOCK_H */
+diff --git a/include/dt-bindings/thermal/thermal.h b/include/dt-bindings/thermal/thermal.h
+index 59822a9..b5e6b00 100644
+--- a/include/dt-bindings/thermal/thermal.h
++++ b/include/dt-bindings/thermal/thermal.h
+@@ -11,7 +11,7 @@
+ #define _DT_BINDINGS_THERMAL_THERMAL_H
+ 
+ /* On cooling devices upper and lower limits */
+-#define THERMAL_NO_LIMIT		(-1UL)
++#define THERMAL_NO_LIMIT		(~0)
+ 
+ #endif
+ 
+diff --git a/include/linux/Kbuild b/include/linux/Kbuild
+new file mode 100644
+index 0000000..a460889
+--- /dev/null
++++ b/include/linux/Kbuild
+@@ -0,0 +1,2 @@
++header-y += if_pppolac.h
++header-y += if_pppopns.h
+diff --git a/include/linux/amba/bus.h b/include/linux/amba/bus.h
+index c324f57..d024bd9 100644
+--- a/include/linux/amba/bus.h
++++ b/include/linux/amba/bus.h
+@@ -23,6 +23,7 @@
+ 
+ #define AMBA_NR_IRQS	9
+ #define AMBA_CID	0xb105f00d
++#define CORESIGHT_CID	0xb105900d
+ 
+ struct clk;
+ 
+diff --git a/include/linux/amba/mmci.h b/include/linux/amba/mmci.h
+index 8c98113..8bfd21c 100644
+--- a/include/linux/amba/mmci.h
++++ b/include/linux/amba/mmci.h
+@@ -5,6 +5,15 @@
+ #define AMBA_MMCI_H
+ 
+ #include <linux/mmc/host.h>
++#include <linux/mmc/card.h>
++#include <linux/mmc/sdio_func.h>
++
++struct embedded_sdio_data {
++        struct sdio_cis cis;
++        struct sdio_cccr cccr;
++        struct sdio_embedded_func *funcs;
++        int num_funcs;
++};
+ 
+ /**
+  * struct mmci_platform_data - platform configuration for the MMCI
+@@ -31,6 +40,10 @@ struct mmci_platform_data {
+ 	int	gpio_wp;
+ 	int	gpio_cd;
+ 	bool	cd_invert;
++	unsigned int status_irq;
++	struct embedded_sdio_data *embedded_sdio;
++	int (*register_status_notify)(void (*callback)(int card_present, void *dev_id), void *dev_id);
++
+ };
+ 
+ #endif
+diff --git a/include/linux/amba/pl08x.h b/include/linux/amba/pl08x.h
+index 10fe2a2..27e9ec8 100644
+--- a/include/linux/amba/pl08x.h
++++ b/include/linux/amba/pl08x.h
+@@ -86,7 +86,7 @@ struct pl08x_channel_data {
+  * @mem_buses: buses which memory can be accessed from: PL08X_AHB1 | PL08X_AHB2
+  */
+ struct pl08x_platform_data {
+-	const struct pl08x_channel_data *slave_channels;
++	struct pl08x_channel_data *slave_channels;
+ 	unsigned int num_slave_channels;
+ 	struct pl08x_channel_data memcpy_channel;
+ 	int (*get_xfer_signal)(const struct pl08x_channel_data *);
+diff --git a/include/linux/android_aid.h b/include/linux/android_aid.h
+new file mode 100644
+index 0000000..6f1fa17
+--- /dev/null
++++ b/include/linux/android_aid.h
+@@ -0,0 +1,28 @@
++/* include/linux/android_aid.h
++ *
++ * Copyright (C) 2008 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#ifndef _LINUX_ANDROID_AID_H
++#define _LINUX_ANDROID_AID_H
++
++/* AIDs that the kernel treats differently */
++#define AID_OBSOLETE_000 KGIDT_INIT(3001)  /* was NET_BT_ADMIN */
++#define AID_OBSOLETE_001 KGIDT_INIT(3002)  /* was NET_BT */
++#define AID_INET         KGIDT_INIT(3003)
++#define AID_NET_RAW      KGIDT_INIT(3004)
++#define AID_NET_ADMIN    KGIDT_INIT(3005)
++#define AID_NET_BW_STATS KGIDT_INIT(3006)  /* read bandwidth statistics */
++#define AID_NET_BW_ACCT  KGIDT_INIT(3007)  /* change bandwidth statistics accounting */
++
++#endif
+diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
+index aac0f9e..bb2b01a 100644
+--- a/include/linux/blkdev.h
++++ b/include/linux/blkdev.h
+@@ -1185,7 +1185,11 @@ extern int blk_verify_command(unsigned char *cmd, fmode_t has_write_perm);
+ enum blk_default_limits {
+ 	BLK_MAX_SEGMENTS	= 128,
+ 	BLK_SAFE_MAX_SECTORS	= 255,
++#if defined(CONFIG_ARCH_HI3559) || defined(CONFIG_ARCH_HI3556)
++	BLK_DEF_MAX_SECTORS	= 8192,
++#else
+ 	BLK_DEF_MAX_SECTORS	= 1024,
++#endif
+ 	BLK_MAX_SEGMENT_SIZE	= 65536,
+ 	BLK_SEG_BOUNDARY_MASK	= 0xFFFFFFFFUL,
+ };
+diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
+index 1d51968..cbc8db1 100644
+--- a/include/linux/cgroup.h
++++ b/include/linux/cgroup.h
+@@ -615,6 +615,8 @@ struct cgroup_subsys {
+ 	void (*css_free)(struct cgroup_subsys_state *css);
+ 	void (*css_reset)(struct cgroup_subsys_state *css);
+ 
++	int (*allow_attach)(struct cgroup_subsys_state *css,
++			    struct cgroup_taskset *tset);
+ 	int (*can_attach)(struct cgroup_subsys_state *css,
+ 			  struct cgroup_taskset *tset);
+ 	void (*cancel_attach)(struct cgroup_subsys_state *css,
+@@ -911,6 +913,17 @@ int cgroup_transfer_tasks(struct cgroup *to, struct cgroup *from);
+ struct cgroup_subsys_state *css_tryget_online_from_dir(struct dentry *dentry,
+ 						       struct cgroup_subsys *ss);
+ 
++/*
++ * Default Android check for whether the current process is allowed to move a
++ * task across cgroups, either because CAP_SYS_NICE is set or because the uid
++ * of the calling process is the same as the moved task or because we are
++ * running as root.
++ * Returns 0 if this is allowed, or -EACCES otherwise.
++ */
++int subsys_cgroup_allow_attach(struct cgroup_subsys_state *css,
++			       struct cgroup_taskset *tset);
++
++
+ #else /* !CONFIG_CGROUPS */
+ 
+ static inline int cgroup_init_early(void) { return 0; }
+@@ -932,6 +945,11 @@ static inline int cgroup_attach_task_all(struct task_struct *from,
+ 	return 0;
+ }
+ 
++static inline int subsys_cgroup_allow_attach(struct cgroup_subsys_state *css,
++					     void *tset)
++{
++	return -EINVAL;
++}
+ #endif /* !CONFIG_CGROUPS */
+ 
+ #endif /* _LINUX_CGROUP_H */
+diff --git a/include/linux/clk-private.h b/include/linux/clk-private.h
+index 0ca5f60..228a987 100644
+--- a/include/linux/clk-private.h
++++ b/include/linux/clk-private.h
+@@ -13,7 +13,9 @@
+ 
+ #include <linux/clk-provider.h>
+ #include <linux/kref.h>
++#include <linux/ktime.h>
+ #include <linux/list.h>
++#include <linux/rbtree.h>
+ 
+ /*
+  * WARNING: Do not include clk-private.h from any file that implements struct
+@@ -28,6 +30,14 @@
+ 
+ struct module;
+ 
++#ifdef CONFIG_COMMON_CLK_FREQ_STATS_ACCOUNTING
++struct freq_stats {
++	ktime_t time_spent;
++	unsigned long rate;
++	struct rb_node node;
++};
++#endif /*CONFIG_COMMON_CLK_FREQ_STATS_ACCOUNTING*/
++
+ struct clk {
+ 	const char		*name;
+ 	const struct clk_ops	*ops;
+@@ -53,6 +63,13 @@ struct clk {
+ 	unsigned int		notifier_count;
+ #ifdef CONFIG_DEBUG_FS
+ 	struct dentry		*dentry;
++#ifdef CONFIG_COMMON_CLK_FREQ_STATS_ACCOUNTING
++	struct rb_root freq_stats_table;
++	struct freq_stats *current_freq_stats;
++	ktime_t default_freq_time;
++	ktime_t start_time;
++#endif /* CONFIG_COMMON_CLK_FREQ_STATS_ACCOUNTING*/
++
+ #endif
+ 	struct kref		ref;
+ };
+diff --git a/include/linux/clock_cooling.h b/include/linux/clock_cooling.h
+new file mode 100644
+index 0000000..4d1019d
+--- /dev/null
++++ b/include/linux/clock_cooling.h
+@@ -0,0 +1,65 @@
++/*
++ *  linux/include/linux/clock_cooling.h
++ *
++ *  Copyright (C) 2014 Eduardo Valentin <edubezval@gmail.com>
++ *
++ *  Copyright (C) 2013	Texas Instruments Inc.
++ *  Contact:  Eduardo Valentin <eduardo.valentin@ti.com>
++ *
++ *  Highly based on cpu_cooling.c.
++ *  Copyright (C) 2012	Samsung Electronics Co., Ltd(http://www.samsung.com)
++ *  Copyright (C) 2012  Amit Daniel <amit.kachhap@linaro.org>
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation; version 2 of the License.
++ *
++ *  This program is distributed in the hope that it will be useful, but
++ *  WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++ *  General Public License for more details.
++ */
++
++#ifndef __CPU_COOLING_H__
++#define __CPU_COOLING_H__
++
++#include <linux/of.h>
++#include <linux/thermal.h>
++#include <linux/cpumask.h>
++
++#ifdef CONFIG_CLOCK_THERMAL
++/**
++ * clock_cooling_register - function to create clock cooling device.
++ * @dev: struct device pointer to the device used as clock cooling device.
++ * @clock_name: string containing the clock used as cooling mechanism.
++ */
++struct thermal_cooling_device *
++clock_cooling_register(struct device *dev, const char *clock_name);
++
++/**
++ * clock_cooling_unregister - function to remove clock cooling device.
++ * @cdev: thermal cooling device pointer.
++ */
++void clock_cooling_unregister(struct thermal_cooling_device *cdev);
++
++unsigned long clock_cooling_get_level(struct thermal_cooling_device *cdev,
++				      unsigned long freq);
++#else /* !CONFIG_CLOCK_THERMAL */
++static inline struct thermal_cooling_device *
++clock_cooling_register(struct device *dev, const char *clock_name)
++{
++	return NULL;
++}
++static inline
++void clock_cooling_unregister(struct thermal_cooling_device *cdev)
++{
++}
++static inline
++unsigned long clock_cooling_get_level(struct thermal_cooling_device *cdev,
++				      unsigned long freq)
++{
++	return THERMAL_CSTATE_INVALID;
++}
++#endif	/* CONFIG_CLOCK_THERMAL */
++
++#endif /* __CPU_COOLING_H__ */
+diff --git a/include/linux/coresight.h b/include/linux/coresight.h
+new file mode 100644
+index 0000000..44c1597
+--- /dev/null
++++ b/include/linux/coresight.h
+@@ -0,0 +1,251 @@
++/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#ifndef _LINUX_CORESIGHT_H
++#define _LINUX_CORESIGHT_H
++
++#include <linux/device.h>
++
++/* Peripheral id registers (0xFD0-0xFEC) */
++#define CORESIGHT_PERIPHIDR4	0xfd0
++#define CORESIGHT_PERIPHIDR5	0xfd4
++#define CORESIGHT_PERIPHIDR6	0xfd8
++#define CORESIGHT_PERIPHIDR7	0xfdC
++#define CORESIGHT_PERIPHIDR0	0xfe0
++#define CORESIGHT_PERIPHIDR1	0xfe4
++#define CORESIGHT_PERIPHIDR2	0xfe8
++#define CORESIGHT_PERIPHIDR3	0xfeC
++/* Component id registers (0xFF0-0xFFC) */
++#define CORESIGHT_COMPIDR0	0xff0
++#define CORESIGHT_COMPIDR1	0xff4
++#define CORESIGHT_COMPIDR2	0xff8
++#define CORESIGHT_COMPIDR3	0xffC
++
++#define ETM_ARCH_V3_3		0x23
++#define ETM_ARCH_V3_5		0x25
++#define PFT_ARCH_V1_0		0x30
++#define PFT_ARCH_V1_1		0x31
++
++#define CORESIGHT_UNLOCK	0xc5acce55
++
++extern struct bus_type coresight_bustype;
++
++enum coresight_dev_type {
++	CORESIGHT_DEV_TYPE_NONE,
++	CORESIGHT_DEV_TYPE_SINK,
++	CORESIGHT_DEV_TYPE_LINK,
++	CORESIGHT_DEV_TYPE_LINKSINK,
++	CORESIGHT_DEV_TYPE_SOURCE,
++};
++
++enum coresight_dev_subtype_sink {
++	CORESIGHT_DEV_SUBTYPE_SINK_NONE,
++	CORESIGHT_DEV_SUBTYPE_SINK_PORT,
++	CORESIGHT_DEV_SUBTYPE_SINK_BUFFER,
++};
++
++enum coresight_dev_subtype_link {
++	CORESIGHT_DEV_SUBTYPE_LINK_NONE,
++	CORESIGHT_DEV_SUBTYPE_LINK_MERG,
++	CORESIGHT_DEV_SUBTYPE_LINK_SPLIT,
++	CORESIGHT_DEV_SUBTYPE_LINK_FIFO,
++};
++
++enum coresight_dev_subtype_source {
++	CORESIGHT_DEV_SUBTYPE_SOURCE_NONE,
++	CORESIGHT_DEV_SUBTYPE_SOURCE_PROC,
++	CORESIGHT_DEV_SUBTYPE_SOURCE_BUS,
++	CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE,
++};
++
++/**
++ * struct coresight_dev_subtype - further characterisation of a type
++ * @sink_subtype:	type of sink this component is, as defined
++			by @coresight_dev_subtype_sink.
++ * @link_subtype:	type of link this component is, as defined
++			by @coresight_dev_subtype_link.
++ * @source_subtype:	type of source this component is, as defined
++			by @coresight_dev_subtype_source.
++ */
++struct coresight_dev_subtype {
++	enum coresight_dev_subtype_sink sink_subtype;
++	enum coresight_dev_subtype_link link_subtype;
++	enum coresight_dev_subtype_source source_subtype;
++};
++
++/**
++ * struct coresight_platform_data - data harvested from the DT specification
++ * @cpu:	the CPU a source belongs to. Only applicable for ETM/PTMs.
++ * @name:	name of the component as shown under sysfs.
++ * @nr_inport:	number of input ports for this component.
++ * @outports:	list of remote enpoint port number.
++ * @child_names:name of all child components connected to this device.
++ * @child_ports:child component port number the current component is
++		connected  to.
++ * @nr_outport:	number of output ports for this component.
++ * @clk:	The clock this component is associated to.
++ */
++struct coresight_platform_data {
++	int cpu;
++	const char *name;
++	int nr_inport;
++	int *outports;
++	const char **child_names;
++	int *child_ports;
++	int nr_outport;
++	struct clk *clk;
++};
++
++/**
++ * struct coresight_desc - description of a component required from drivers
++ * @type:	as defined by @coresight_dev_type.
++ * @subtype:	as defined by @coresight_dev_subtype.
++ * @ops:	generic operations for this component, as defined
++		by @coresight_ops.
++ * @pdata:	platform data collected from DT.
++ * @dev:	The device entity associated to this component.
++ * @groups	:operations specific to this component. These will end up
++		in the component's sysfs sub-directory.
++ */
++struct coresight_desc {
++	enum coresight_dev_type type;
++	struct coresight_dev_subtype subtype;
++	const struct coresight_ops *ops;
++	struct coresight_platform_data *pdata;
++	struct device *dev;
++	const struct attribute_group **groups;
++};
++
++/**
++ * struct coresight_connection - representation of a single connection
++ * @ref_count:	keeping count a port' references.
++ * @outport:	a connection's output port number.
++ * @chid_name:	remote component's name.
++ * @child_port:	remote component's port number @output is connected to.
++ * @child_dev:	a @coresight_device representation of the component
++		connected to @outport.
++ */
++struct coresight_connection {
++	int outport;
++	const char *child_name;
++	int child_port;
++	struct coresight_device *child_dev;
++};
++
++/**
++ * struct coresight_device - representation of a device as used by the framework
++ * @nr_inport:	number of input port associated to this component.
++ * @nr_outport:	number of output port associated to this component.
++ * @type:	as defined by @coresight_dev_type.
++ * @subtype:	as defined by @coresight_dev_subtype.
++ * @ops:	generic operations for this component, as defined
++		by @coresight_ops.
++ * @dev:	The device entity associated to this component.
++ * @refcnt:	keep track of what is in use.
++ * @path_link:	link of current component into the path being enabled.
++ * @orphan:	true if the component has connections that haven't been linked.
++ * @enable:	'true' if component is currently part of an active path.
++ * @activated:	'true' only if a _sink_ has been activated.  A sink can be
++		activated but not yet enabled.  Enabling for a _sink_
++		happens when a source has been selected for that it.
++ */
++struct coresight_device {
++	struct coresight_connection *conns;
++	int nr_inport;
++	int nr_outport;
++	enum coresight_dev_type type;
++	struct coresight_dev_subtype subtype;
++	const struct coresight_ops *ops;
++	struct device dev;
++	atomic_t *refcnt;
++	struct list_head path_link;
++	bool orphan;
++	bool enable;	/* true only if configured as part of a path */
++	bool activated;	/* true only if a sink is part of a path */
++};
++
++#define to_coresight_device(d) container_of(d, struct coresight_device, dev)
++
++#define source_ops(csdev)	csdev->ops->source_ops
++#define sink_ops(csdev)		csdev->ops->sink_ops
++#define link_ops(csdev)		csdev->ops->link_ops
++
++/**
++ * struct coresight_ops_sink - basic operations for a sink
++ * Operations available for sinks
++ * @enable:	enables the sink.
++ * @disable:	disables the sink.
++ */
++struct coresight_ops_sink {
++	int (*enable)(struct coresight_device *csdev);
++	void (*disable)(struct coresight_device *csdev);
++};
++
++/**
++ * struct coresight_ops_link - basic operations for a link
++ * Operations available for links.
++ * @enable:	enables flow between iport and oport.
++ * @disable:	disables flow between iport and oport.
++ */
++struct coresight_ops_link {
++	int (*enable)(struct coresight_device *csdev, int iport, int oport);
++	void (*disable)(struct coresight_device *csdev, int iport, int oport);
++};
++
++/**
++ * struct coresight_ops_source - basic operations for a source
++ * Operations available for sources.
++ * @trace_id:	returns the value of the component's trace ID as known
++		to the HW.
++ * @enable:	enables tracing from a source.
++ * @disable:	disables tracing for a source.
++ */
++struct coresight_ops_source {
++	int (*trace_id)(struct coresight_device *csdev);
++	int (*enable)(struct coresight_device *csdev);
++	void (*disable)(struct coresight_device *csdev);
++};
++
++struct coresight_ops {
++	const struct coresight_ops_sink *sink_ops;
++	const struct coresight_ops_link *link_ops;
++	const struct coresight_ops_source *source_ops;
++};
++
++#ifdef CONFIG_CORESIGHT
++extern struct coresight_device *
++coresight_register(struct coresight_desc *desc);
++extern void coresight_unregister(struct coresight_device *csdev);
++extern int coresight_enable(struct coresight_device *csdev);
++extern void coresight_disable(struct coresight_device *csdev);
++extern int coresight_timeout(void __iomem *addr, u32 offset,
++			     int position, int value);
++#else
++static inline struct coresight_device *
++coresight_register(struct coresight_desc *desc) { return NULL; }
++static inline void coresight_unregister(struct coresight_device *csdev) {}
++static inline int
++coresight_enable(struct coresight_device *csdev) { return -ENOSYS; }
++static inline void coresight_disable(struct coresight_device *csdev) {}
++static inline int coresight_timeout(void __iomem *addr, u32 offset,
++				     int position, int value) { return 1; }
++#endif
++
++#ifdef CONFIG_OF
++extern struct coresight_platform_data *of_get_coresight_platform_data(
++				struct device *dev, struct device_node *node);
++#else
++static inline struct coresight_platform_data *of_get_coresight_platform_data(
++	struct device *dev, struct device_node *node) { return NULL; }
++#endif
++
++#endif
+diff --git a/include/linux/cpu.h b/include/linux/cpu.h
+index b2d9a43..10d981a 100644
+--- a/include/linux/cpu.h
++++ b/include/linux/cpu.h
+@@ -267,4 +267,11 @@ void arch_cpu_idle_enter(void);
+ void arch_cpu_idle_exit(void);
+ void arch_cpu_idle_dead(void);
+ 
++#define IDLE_START 1
++#define IDLE_END 2
++
++void idle_notifier_register(struct notifier_block *n);
++void idle_notifier_unregister(struct notifier_block *n);
++void idle_notifier_call_chain(unsigned long val);
++
+ #endif /* _LINUX_CPU_H_ */
+diff --git a/include/linux/cpu_cooling.h b/include/linux/cpu_cooling.h
+index c303d38..8ac0331 100644
+--- a/include/linux/cpu_cooling.h
++++ b/include/linux/cpu_cooling.h
+@@ -28,6 +28,9 @@
+ #include <linux/thermal.h>
+ #include <linux/cpumask.h>
+ 
++typedef int (*get_static_t)(cpumask_t *cpumask, int interval,
++			    unsigned long voltage, u32 *power);
++
+ #ifdef CONFIG_CPU_THERMAL
+ /**
+  * cpufreq_cooling_register - function to create cpufreq cooling device.
+@@ -36,6 +39,10 @@
+ struct thermal_cooling_device *
+ cpufreq_cooling_register(const struct cpumask *clip_cpus);
+ 
++struct thermal_cooling_device *
++cpufreq_power_cooling_register(const struct cpumask *clip_cpus,
++			       u32 capacitance, get_static_t plat_static_func);
++
+ /**
+  * of_cpufreq_cooling_register - create cpufreq cooling device based on DT.
+  * @np: a valid struct device_node to the cooling device device tree node.
+@@ -45,6 +52,12 @@ cpufreq_cooling_register(const struct cpumask *clip_cpus);
+ struct thermal_cooling_device *
+ of_cpufreq_cooling_register(struct device_node *np,
+ 			    const struct cpumask *clip_cpus);
++
++struct thermal_cooling_device *
++of_cpufreq_power_cooling_register(struct device_node *np,
++				  const struct cpumask *clip_cpus,
++				  u32 capacitance,
++				  get_static_t plat_static_func);
+ #else
+ static inline struct thermal_cooling_device *
+ of_cpufreq_cooling_register(struct device_node *np,
+@@ -52,6 +65,15 @@ of_cpufreq_cooling_register(struct device_node *np,
+ {
+ 	return NULL;
+ }
++
++static inline struct thermal_cooling_device *
++of_cpufreq_power_cooling_register(struct device_node *np,
++				  const struct cpumask *clip_cpus,
++				  u32 capacitance,
++				  get_static_t plat_static_func)
++{
++	return NULL;
++}
+ #endif
+ 
+ /**
+@@ -68,11 +90,28 @@ cpufreq_cooling_register(const struct cpumask *clip_cpus)
+ 	return NULL;
+ }
+ static inline struct thermal_cooling_device *
++cpufreq_power_cooling_register(const struct cpumask *clip_cpus,
++			       u32 capacitance, get_static_t plat_static_func)
++{
++	return NULL;
++}
++
++static inline struct thermal_cooling_device *
+ of_cpufreq_cooling_register(struct device_node *np,
+ 			    const struct cpumask *clip_cpus)
+ {
+ 	return NULL;
+ }
++
++static inline struct thermal_cooling_device *
++of_cpufreq_power_cooling_register(struct device_node *np,
++				  const struct cpumask *clip_cpus,
++				  u32 capacitance,
++				  get_static_t plat_static_func)
++{
++	return NULL;
++}
++
+ static inline
+ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
+ {
+diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
+index 503b085..56ea8a3 100644
+--- a/include/linux/cpufreq.h
++++ b/include/linux/cpufreq.h
+@@ -18,6 +18,8 @@
+ #include <linux/notifier.h>
+ #include <linux/spinlock.h>
+ #include <linux/sysfs.h>
++#include <asm/cputime.h>
++
+ 
+ /*********************************************************************
+  *                        CPUFREQ INTERFACE                          *
+@@ -481,6 +483,9 @@ extern struct cpufreq_governor cpufreq_gov_ondemand;
+ #elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE)
+ extern struct cpufreq_governor cpufreq_gov_conservative;
+ #define CPUFREQ_DEFAULT_GOVERNOR	(&cpufreq_gov_conservative)
++#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE)
++extern struct cpufreq_governor cpufreq_gov_interactive;
++#define CPUFREQ_DEFAULT_GOVERNOR	(&cpufreq_gov_interactive)
+ #endif
+ 
+ /*********************************************************************
+@@ -597,4 +602,11 @@ unsigned int cpufreq_generic_get(unsigned int cpu);
+ int cpufreq_generic_init(struct cpufreq_policy *policy,
+ 		struct cpufreq_frequency_table *table,
+ 		unsigned int transition_latency);
++
++/*********************************************************************
++ *                         CPUFREQ STATS                             *
++ *********************************************************************/
++
++void acct_update_power(struct task_struct *p, cputime_t cputime);
++
+ #endif /* _LINUX_CPUFREQ_H */
+diff --git a/include/linux/dcache.h b/include/linux/dcache.h
+index 1c2f1b8..af7410c 100644
+--- a/include/linux/dcache.h
++++ b/include/linux/dcache.h
+@@ -462,10 +462,39 @@ static inline bool d_is_positive(const struct dentry *dentry)
+ 	return !d_is_negative(dentry);
+ }
+ 
++/**
++ * d_really_is_positive - Determine if a dentry is really positive (ignoring fallthroughs)
++ * @dentry: The dentry in question
++ *
++ * Returns true if the dentry represents a name that maps to an inode
++ * (ie. ->d_inode is not NULL).  The dentry might still represent a whiteout if
++ * that is represented on medium as a 0,0 chardev.
++ *
++ * Note!  (1) This should be used *only* by a filesystem to examine its own
++ * dentries.  It should not be used to look at some other filesystem's
++ * dentries.  (2) It should also be used in combination with d_inode() to get
++ * the inode.
++ */
++static inline bool d_really_is_positive(const struct dentry *dentry)
++{
++	return dentry->d_inode != NULL;
++}
+ extern int sysctl_vfs_cache_pressure;
+ 
+ static inline unsigned long vfs_pressure_ratio(unsigned long val)
+ {
+ 	return mult_frac(val, sysctl_vfs_cache_pressure, 100);
+ }
++
++/**
++ * d_inode - Get the actual inode of this dentry
++ * @dentry: The dentry to query
++ *
++ * This is the helper normal filesystems should use to get at their own inodes
++ * in their own dentries and ignore the layering superimposed upon them.
++ */
++static inline struct inode *d_inode(const struct dentry *dentry)
++{
++	return dentry->d_inode;
++}
+ #endif	/* __LINUX_DCACHE_H */
+diff --git a/include/linux/falloc.h b/include/linux/falloc.h
+index 3159168..1f3b42c 100644
+--- a/include/linux/falloc.h
++++ b/include/linux/falloc.h
+@@ -21,4 +21,9 @@ struct space_resv {
+ #define FS_IOC_RESVSP		_IOW('X', 40, struct space_resv)
+ #define FS_IOC_RESVSP64		_IOW('X', 42, struct space_resv)
+ 
++#define	FALLOC_FL_SUPPORTED_MASK	(FALLOC_FL_KEEP_SIZE |		\
++					 FALLOC_FL_PUNCH_HOLE |		\
++					 FALLOC_FL_COLLAPSE_RANGE |	\
++					 FALLOC_FL_ZERO_RANGE |		\
++					 FALLOC_FL_INSERT_RANGE)
+ #endif /* _FALLOC_H_ */
+diff --git a/include/linux/filter.h b/include/linux/filter.h
+index ca95abd..c10500e 100644
+--- a/include/linux/filter.h
++++ b/include/linux/filter.h
+@@ -358,7 +358,11 @@ static inline void bpf_prog_unlock_ro(struct bpf_prog *fp)
+ }
+ #endif /* CONFIG_DEBUG_SET_MODULE_RONX */
+ 
+-int sk_filter(struct sock *sk, struct sk_buff *skb);
++int sk_filter_trim_cap(struct sock *sk, struct sk_buff *skb, unsigned int cap);
++static inline int sk_filter(struct sock *sk, struct sk_buff *skb)
++{
++	return sk_filter_trim_cap(sk, skb, 1);
++}
+ 
+ void bpf_prog_select_runtime(struct bpf_prog *fp);
+ void bpf_prog_free(struct bpf_prog *fp);
+diff --git a/include/linux/fs.h b/include/linux/fs.h
+index 84d6729..1260de3 100644
+--- a/include/linux/fs.h
++++ b/include/linux/fs.h
+@@ -402,6 +402,8 @@ struct address_space {
+ 	struct rb_root		i_mmap;		/* tree of private and shared mappings */
+ 	struct list_head	i_mmap_nonlinear;/*list VM_NONLINEAR mappings */
+ 	struct mutex		i_mmap_mutex;	/* protect tree, count, list */
++	struct rw_semaphore	i_mmap_rwsem;	/* protect tree, count, list */
++
+ 	/* Protected by tree_lock together with the radix tree */
+ 	unsigned long		nrpages;	/* number of total pages */
+ 	unsigned long		nrshadows;	/* number of shadow entries */
+@@ -467,6 +469,26 @@ struct block_device {
+ 
+ int mapping_tagged(struct address_space *mapping, int tag);
+ 
++static inline void i_mmap_lock_write(struct address_space *mapping)
++{
++	down_write(&mapping->i_mmap_rwsem);
++}
++
++static inline void i_mmap_unlock_write(struct address_space *mapping)
++{
++	up_write(&mapping->i_mmap_rwsem);
++}
++
++static inline void i_mmap_lock_read(struct address_space *mapping)
++{
++	down_read(&mapping->i_mmap_rwsem);
++}
++
++static inline void i_mmap_unlock_read(struct address_space *mapping)
++{
++	up_read(&mapping->i_mmap_rwsem);
++}
++
+ /*
+  * Might pages of this file be mapped into userspace?
+  */
+@@ -657,6 +679,31 @@ enum inode_i_mutex_lock_class
+ 	I_MUTEX_PARENT2,
+ };
+ 
++static inline void inode_lock(struct inode *inode)
++{
++	mutex_lock(&inode->i_mutex);
++}
++
++static inline void inode_unlock(struct inode *inode)
++{
++	mutex_unlock(&inode->i_mutex);
++}
++
++static inline int inode_trylock(struct inode *inode)
++{
++	return mutex_trylock(&inode->i_mutex);
++}
++
++static inline int inode_is_locked(struct inode *inode)
++{
++	return mutex_is_locked(&inode->i_mutex);
++}
++
++static inline void inode_lock_nested(struct inode *inode, unsigned subclass)
++{
++	mutex_lock_nested(&inode->i_mutex, subclass);
++}
++
+ void lock_two_nondirectories(struct inode *, struct inode*);
+ void unlock_two_nondirectories(struct inode *, struct inode*);
+ 
+@@ -790,6 +837,9 @@ struct file {
+ 	} f_u;
+ 	struct path		f_path;
+ #define f_dentry	f_path.dentry
++#ifdef CONFIG_HISI_SNAPSHOT_BOOT
++#define f_vfsmnt        f_path.mnt
++#endif
+ 	struct inode		*f_inode;	/* cached value */
+ 	const struct file_operations	*f_op;
+ 
+@@ -1219,6 +1269,15 @@ struct super_block {
+ 
+ 	struct list_head	s_inodes;	/* all inodes */
+ 	struct hlist_bl_head	s_anon;		/* anonymous dentries for (nfs) exporting */
++#ifdef CONFIG_HISI_SNAPSHOT_BOOT
++
++	/* fix me */
++/*#ifdef CONFIG_SMP
++	struct list_head __percpu *s_files;
++#else*/
++	struct list_head	s_files;
++/*#endif*/
++#endif
+ 	struct list_head	s_mounts;	/* list of mounts; _not_ for fs use */
+ 	struct block_device	*s_bdev;
+ 	struct backing_dev_info *s_bdi;
+@@ -2663,6 +2722,7 @@ extern int buffer_migrate_page(struct address_space *,
+ extern int inode_change_ok(const struct inode *, struct iattr *);
+ extern int inode_newsize_ok(const struct inode *, loff_t offset);
+ extern void setattr_copy(struct inode *inode, const struct iattr *attr);
++extern int setattr_killpriv(struct dentry *dentry, struct iattr *attr);
+ 
+ extern int file_update_time(struct file *file);
+ 
+diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h
+index 28672e8..cac1e80 100644
+--- a/include/linux/ftrace_event.h
++++ b/include/linux/ftrace_event.h
+@@ -44,6 +44,10 @@ const char *ftrace_print_bitmask_seq(struct trace_seq *p, void *bitmask_ptr,
+ const char *ftrace_print_hex_seq(struct trace_seq *p,
+ 				 const unsigned char *buf, int len);
+ 
++const char *ftrace_print_array_seq(struct trace_seq *p,
++				   const void *buf, int buf_len,
++				   size_t el_size);
++
+ struct trace_iterator;
+ struct trace_event;
+ 
+diff --git a/include/linux/gpio_event.h b/include/linux/gpio_event.h
+new file mode 100644
+index 0000000..2613fc5
+--- /dev/null
++++ b/include/linux/gpio_event.h
+@@ -0,0 +1,170 @@
++/* include/linux/gpio_event.h
++ *
++ * Copyright (C) 2007 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#ifndef _LINUX_GPIO_EVENT_H
++#define _LINUX_GPIO_EVENT_H
++
++#include <linux/input.h>
++
++struct gpio_event_input_devs {
++	int count;
++	struct input_dev *dev[];
++};
++enum {
++	GPIO_EVENT_FUNC_UNINIT  = 0x0,
++	GPIO_EVENT_FUNC_INIT    = 0x1,
++	GPIO_EVENT_FUNC_SUSPEND = 0x2,
++	GPIO_EVENT_FUNC_RESUME  = 0x3,
++};
++struct gpio_event_info {
++	int (*func)(struct gpio_event_input_devs *input_devs,
++		    struct gpio_event_info *info,
++		    void **data, int func);
++	int (*event)(struct gpio_event_input_devs *input_devs,
++		     struct gpio_event_info *info,
++		     void **data, unsigned int dev, unsigned int type,
++		     unsigned int code, int value); /* out events */
++	bool no_suspend;
++};
++
++struct gpio_event_platform_data {
++	const char *name;
++	struct gpio_event_info **info;
++	size_t info_count;
++	int (*power)(const struct gpio_event_platform_data *pdata, bool on);
++	const char *names[]; /* If name is NULL, names contain a NULL */
++			     /* terminated list of input devices to create */
++};
++
++#define GPIO_EVENT_DEV_NAME "gpio-event"
++
++/* Key matrix */
++
++enum gpio_event_matrix_flags {
++	/* unset: drive active output low, set: drive active output high */
++	GPIOKPF_ACTIVE_HIGH              = 1U << 0,
++	GPIOKPF_DEBOUNCE                 = 1U << 1,
++	GPIOKPF_REMOVE_SOME_PHANTOM_KEYS = 1U << 2,
++	GPIOKPF_REMOVE_PHANTOM_KEYS      = GPIOKPF_REMOVE_SOME_PHANTOM_KEYS |
++					   GPIOKPF_DEBOUNCE,
++	GPIOKPF_DRIVE_INACTIVE           = 1U << 3,
++	GPIOKPF_LEVEL_TRIGGERED_IRQ      = 1U << 4,
++	GPIOKPF_PRINT_UNMAPPED_KEYS      = 1U << 16,
++	GPIOKPF_PRINT_MAPPED_KEYS        = 1U << 17,
++	GPIOKPF_PRINT_PHANTOM_KEYS       = 1U << 18,
++};
++
++#define MATRIX_CODE_BITS (10)
++#define MATRIX_KEY_MASK ((1U << MATRIX_CODE_BITS) - 1)
++#define MATRIX_KEY(dev, code) \
++	(((dev) << MATRIX_CODE_BITS) | (code & MATRIX_KEY_MASK))
++
++extern int gpio_event_matrix_func(struct gpio_event_input_devs *input_devs,
++			struct gpio_event_info *info, void **data, int func);
++struct gpio_event_matrix_info {
++	/* initialize to gpio_event_matrix_func */
++	struct gpio_event_info info;
++	/* size must be ninputs * noutputs */
++	const unsigned short *keymap;
++	unsigned int *input_gpios;
++	unsigned int *output_gpios;
++	unsigned int ninputs;
++	unsigned int noutputs;
++	/* time to wait before reading inputs after driving each output */
++	ktime_t settle_time;
++	/* time to wait before scanning the keypad a second time */
++	ktime_t debounce_delay;
++	ktime_t poll_time;
++	unsigned flags;
++};
++
++/* Directly connected inputs and outputs */
++
++enum gpio_event_direct_flags {
++	GPIOEDF_ACTIVE_HIGH         = 1U << 0,
++/*	GPIOEDF_USE_DOWN_IRQ        = 1U << 1, */
++/*	GPIOEDF_USE_IRQ             = (1U << 2) | GPIOIDF_USE_DOWN_IRQ, */
++	GPIOEDF_PRINT_KEYS          = 1U << 8,
++	GPIOEDF_PRINT_KEY_DEBOUNCE  = 1U << 9,
++	GPIOEDF_PRINT_KEY_UNSTABLE  = 1U << 10,
++};
++
++struct gpio_event_direct_entry {
++	uint32_t gpio:16;
++	uint32_t code:10;
++	uint32_t dev:6;
++};
++
++/* inputs */
++extern int gpio_event_input_func(struct gpio_event_input_devs *input_devs,
++			struct gpio_event_info *info, void **data, int func);
++struct gpio_event_input_info {
++	/* initialize to gpio_event_input_func */
++	struct gpio_event_info info;
++	ktime_t debounce_time;
++	ktime_t poll_time;
++	uint16_t flags;
++	uint16_t type;
++	const struct gpio_event_direct_entry *keymap;
++	size_t keymap_size;
++};
++
++/* outputs */
++extern int gpio_event_output_func(struct gpio_event_input_devs *input_devs,
++			struct gpio_event_info *info, void **data, int func);
++extern int gpio_event_output_event(struct gpio_event_input_devs *input_devs,
++			struct gpio_event_info *info, void **data,
++			unsigned int dev, unsigned int type,
++			unsigned int code, int value);
++struct gpio_event_output_info {
++	/* initialize to gpio_event_output_func and gpio_event_output_event */
++	struct gpio_event_info info;
++	uint16_t flags;
++	uint16_t type;
++	const struct gpio_event_direct_entry *keymap;
++	size_t keymap_size;
++};
++
++
++/* axes */
++
++enum gpio_event_axis_flags {
++	GPIOEAF_PRINT_UNKNOWN_DIRECTION  = 1U << 16,
++	GPIOEAF_PRINT_RAW                = 1U << 17,
++	GPIOEAF_PRINT_EVENT              = 1U << 18,
++};
++
++extern int gpio_event_axis_func(struct gpio_event_input_devs *input_devs,
++			struct gpio_event_info *info, void **data, int func);
++struct gpio_event_axis_info {
++	/* initialize to gpio_event_axis_func */
++	struct gpio_event_info info;
++	uint8_t  count; /* number of gpios for this axis */
++	uint8_t  dev; /* device index when using multiple input devices */
++	uint8_t  type; /* EV_REL or EV_ABS */
++	uint16_t code;
++	uint16_t decoded_size;
++	uint16_t (*map)(struct gpio_event_axis_info *info, uint16_t in);
++	uint32_t *gpio;
++	uint32_t flags;
++};
++#define gpio_axis_2bit_gray_map gpio_axis_4bit_gray_map
++#define gpio_axis_3bit_gray_map gpio_axis_4bit_gray_map
++uint16_t gpio_axis_4bit_gray_map(
++			struct gpio_event_axis_info *info, uint16_t in);
++uint16_t gpio_axis_5bit_singletrack_map(
++			struct gpio_event_axis_info *info, uint16_t in);
++
++#endif
+diff --git a/include/linux/hid.h b/include/linux/hid.h
+index 78ea9bf..1568080 100644
+--- a/include/linux/hid.h
++++ b/include/linux/hid.h
+@@ -670,8 +670,8 @@ struct hid_driver {
+ 	int (*input_mapped)(struct hid_device *hdev,
+ 			struct hid_input *hidinput, struct hid_field *field,
+ 			struct hid_usage *usage, unsigned long **bit, int *max);
+-	void (*input_configured)(struct hid_device *hdev,
+-				 struct hid_input *hidinput);
++	int (*input_configured)(struct hid_device *hdev,
++				struct hid_input *hidinput);
+ 	void (*feature_mapping)(struct hid_device *hdev,
+ 			struct hid_field *field,
+ 			struct hid_usage *usage);
+diff --git a/include/linux/hidmac.h b/include/linux/hidmac.h
+new file mode 100644
+index 0000000..bf291be
+--- /dev/null
++++ b/include/linux/hidmac.h
+@@ -0,0 +1,135 @@
++/******************************************************************************
++ *    COPYRIGHT (C) 2013 Hisilicon
++ *    All rights reserved.
++ * ***
++ *    Create 2013-08-23
++ *
++ ******************************************************************************/
++#ifndef __DMAC_H__
++#define __DMAC_H__
++
++#define DMAC_ERROR_BASE		100
++#define DMAC_CHN_SUCCESS	(DMAC_ERROR_BASE+0x10)
++
++#ifdef CONFIG_HI_DMAC
++extern int dma_driver_init(void);
++extern int dmac_channelclose(unsigned int channel);
++extern int dmac_channelstart(unsigned int u32channel);
++extern int dmac_channel_allocate(void *pisr);
++
++extern int dmac_start_m2p(unsigned int channel, unsigned int pmemaddr,
++			unsigned int uwperipheralid,
++			unsigned int uwnumtransfers,
++			unsigned int next_lli_addr);
++extern int dmac_m2p_transfer(unsigned int memaddr,
++			unsigned int uwperipheralid, unsigned int length);
++extern int dmac_channel_free(unsigned int channel);
++extern int do_dma_m2p(unsigned int mem_addr, unsigned int peripheral_addr,
++		unsigned int length);
++extern int do_dma_p2m(unsigned int mem_addr, unsigned int peripheral_addr,
++		unsigned int length);
++extern int dmac_wait(int channel);
++extern int dmac_start_m2m(unsigned int channel, unsigned int psource,
++			unsigned int pdest, unsigned int uwnumtransfers);
++extern int dmac_m2m_transfer(unsigned int source,
++			unsigned int dest, unsigned int length);
++extern int dmac_register_isr(unsigned int channel, void *pisr);
++extern int free_dmalli_space(unsigned int *ppheadlli, unsigned int page_num);
++extern int dmac_start_llim2p(unsigned int channel, unsigned int *pfirst_lli,
++				unsigned int uwperipheralid);
++extern int dmac_buildllim2m(unsigned int *ppheadlli, unsigned int pdest,
++				unsigned int psource,
++				unsigned int totaltransfersize,
++				unsigned int uwnumtransfers);
++extern int dmac_start_llim2m(unsigned int channel, unsigned int *pfirst_lli);
++extern int allocate_dmalli_space(unsigned int *ppheadlli,
++					unsigned int page_num);
++
++extern int do_dma_llim2m_isp(unsigned int *source,
++		unsigned int *dest,
++		unsigned int *length,
++		unsigned int num);
++
++#else /* !CONFIG_HI_DMAC */
++static inline int dma_driver_init(void) { return 0; }
++static inline int dmac_channelclose(unsigned int channel) { return 0; }
++static inline int dmac_channelstart(unsigned int u32channel) { return 0; }
++static inline int dmac_channel_allocate(void *pisr) { return 0; }
++
++static inline int dmac_start_m2p(unsigned int channel, unsigned int pmemaddr,
++		unsigned int uwperipheralid,
++		unsigned int uwnumtransfers,
++		unsigned int next_lli_addr)
++{ return 0; }
++
++static inline int dmac_m2p_transfer(unsigned int memaddr,
++		unsigned int uwperipheralid, unsigned int length)
++{ return 0; }
++
++static inline int dmac_channel_free(unsigned int channel) { return 0; }
++
++int do_dma_m2p(unsigned int mem_addr, unsigned int peripheral_addr,
++		unsigned int length)
++{ return 0; }
++
++static inline int do_dma_p2m(unsigned int mem_addr,
++		unsigned int peripheral_addr,
++		unsigned int length)
++{ return 0; }
++
++static inline int dmac_wait(int channel) { return 0; }
++
++static inline int dmac_start_m2m(unsigned int channel, unsigned int psource,
++		unsigned int pdest, unsigned int uwnumtransfers)
++{ return 0; }
++
++static inline int dmac_m2m_transfer(unsigned int source,
++		unsigned int dest, unsigned int length)
++{ return 0; }
++
++static inline int dmac_register_isr(unsigned int channel, void *pisr)
++{ return 0; }
++
++static inline  int free_dmalli_space(unsigned int *ppheadlli,
++		unsigned int page_num)
++{ return 0; }
++
++static inline  int dmac_start_llim2p(unsigned int channel,
++		unsigned int *pfirst_lli,
++		unsigned int uwperipheralid)
++{ return 0; }
++
++static inline int dmac_buildllim2m(unsigned int *ppheadlli, unsigned int pdest,
++		unsigned int psource,
++		unsigned int totaltransfersize,
++		unsigned int uwnumtransfers)
++{ return 0; }
++
++static inline int dmac_start_llim2m(unsigned int channel,
++		unsigned int *pfirst_lli)
++{ return 0; }
++
++static inline int allocate_dmalli_space(unsigned int *ppheadlli,
++		unsigned int page_num)
++{ return 0; }
++
++static inline int do_dma_llim2m_isp(unsigned int *source,
++		unsigned int *dest,
++		unsigned int *length,
++		unsigned int num)
++{ return 0; }
++#endif /* CONFIG_HI_DMAC */
++
++/*structure for LLI*/
++typedef struct dmac_lli {
++	/*source address*/
++	unsigned int src_addr;
++	/*destination address*/
++	unsigned int dst_addr;
++	/*pointer to next LLI*/
++	unsigned int next_lli;
++	/*control word*/
++	unsigned int lli_transfer_ctrl;
++} dmac_lli;
++
++#endif
+diff --git a/include/linux/i2c.h b/include/linux/i2c.h
+index b556e0a..07e1ca8 100644
+--- a/include/linux/i2c.h
++++ b/include/linux/i2c.h
+@@ -66,6 +66,29 @@ extern int i2c_master_recv(const struct i2c_client *client, char *buf,
+  */
+ extern int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
+ 			int num);
++
++#ifdef CONFIG_ARCH_HISI
++#if defined(CONFIG_HI_I2C) || defined(CONFIG_I2C_HISI_V110)
++extern int hi_i2c_dma_read(const struct i2c_client *client,
++		unsigned int dma_buf, unsigned int reg_addr,
++		unsigned int reg_addr_num, unsigned int length);
++
++extern int hi_i2c_dma_write(const struct i2c_client *client,
++		unsigned int dma_buf, unsigned int reg_addr,
++		unsigned int reg_addr_num, unsigned int length);
++#endif
++
++extern int hi_i2c_master_send(const struct i2c_client *client, const char *buf,
++					int count);
++
++extern int hi_i2c_master_recv(const struct i2c_client *client, char *buf,
++					int count);
++
++extern int hi_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
++					int num);
++
++#endif
++
+ /* Unlocked flavor */
+ extern int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
+ 			  int num);
+diff --git a/include/linux/if_pppolac.h b/include/linux/if_pppolac.h
+new file mode 100644
+index 0000000..e40aa10
+--- /dev/null
++++ b/include/linux/if_pppolac.h
+@@ -0,0 +1,23 @@
++/* include/linux/if_pppolac.h
++ *
++ * Header for PPP on L2TP Access Concentrator / PPPoLAC Socket (RFC 2661)
++ *
++ * Copyright (C) 2009 Google, Inc.
++ * Author: Chia-chi Yeh <chiachi@android.com>
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#ifndef __LINUX_IF_PPPOLAC_H
++#define __LINUX_IF_PPPOLAC_H
++
++#include <uapi/linux/if_pppolac.h>
++
++#endif /* __LINUX_IF_PPPOLAC_H */
+diff --git a/include/linux/if_pppopns.h b/include/linux/if_pppopns.h
+new file mode 100644
+index 0000000..4ac621a
+--- /dev/null
++++ b/include/linux/if_pppopns.h
+@@ -0,0 +1,23 @@
++/* include/linux/if_pppopns.h
++ *
++ * Header for PPP on PPTP Network Server / PPPoPNS Socket (RFC 2637)
++ *
++ * Copyright (C) 2009 Google, Inc.
++ * Author: Chia-chi Yeh <chiachi@android.com>
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#ifndef __LINUX_IF_PPPOPNS_H
++#define __LINUX_IF_PPPOPNS_H
++
++#include <uapi/linux/if_pppopns.h>
++
++#endif /* __LINUX_IF_PPPOPNS_H */
+diff --git a/include/linux/if_pppox.h b/include/linux/if_pppox.h
+index aff7ad8..070ec7d 100644
+--- a/include/linux/if_pppox.h
++++ b/include/linux/if_pppox.h
+@@ -41,6 +41,25 @@ struct pptp_opt {
+ 	u32 seq_sent, seq_recv;
+ 	int ppp_flags;
+ };
++
++struct pppolac_opt {
++	__u32		local;
++	__u32		remote;
++	__u32		recv_sequence;
++	__u32		xmit_sequence;
++	atomic_t	sequencing;
++	int		(*backlog_rcv)(struct sock *sk_udp, struct sk_buff *skb);
++};
++
++struct pppopns_opt {
++	__u16		local;
++	__u16		remote;
++	__u32		recv_sequence;
++	__u32		xmit_sequence;
++	void		(*data_ready)(struct sock *sk_raw);
++	int		(*backlog_rcv)(struct sock *sk_raw, struct sk_buff *skb);
++};
++
+ #include <net/sock.h>
+ 
+ struct pppox_sock {
+@@ -51,6 +70,8 @@ struct pppox_sock {
+ 	union {
+ 		struct pppoe_opt pppoe;
+ 		struct pptp_opt  pptp;
++		struct pppolac_opt lac;
++		struct pppopns_opt pns;
+ 	} proto;
+ 	__be16			num;
+ };
+diff --git a/include/linux/initramfs.h b/include/linux/initramfs.h
+new file mode 100644
+index 0000000..fc7da63
+--- /dev/null
++++ b/include/linux/initramfs.h
+@@ -0,0 +1,32 @@
++/*
++ * include/linux/initramfs.h
++ *
++ * Copyright (C) 2015, Google
++ * Rom Lemarchand <romlem@android.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 of the License.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#ifndef _LINUX_INITRAMFS_H
++#define _LINUX_INITRAMFS_H
++
++#include <linux/kconfig.h>
++
++#if IS_BUILTIN(CONFIG_BLK_DEV_INITRD)
++
++int __init default_rootfs(void);
++
++#endif
++
++#endif /* _LINUX_INITRAMFS_H */
+diff --git a/include/linux/iopoll.h b/include/linux/iopoll.h
+new file mode 100644
+index 0000000..f72b358
+--- /dev/null
++++ b/include/linux/iopoll.h
+@@ -0,0 +1,144 @@
++/*
++ * Copyright (c) 2012-2014 The Linux Foundation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#ifndef _LINUX_IOPOLL_H
++#define _LINUX_IOPOLL_H
++
++#include <linux/kernel.h>
++#include <linux/types.h>
++#include <linux/hrtimer.h>
++#include <linux/delay.h>
++#include <linux/errno.h>
++#include <linux/io.h>
++
++/**
++ * readx_poll_timeout - Periodically poll an address until a condition is met or a timeout occurs
++ * @op: accessor function (takes @addr as its only argument)
++ * @addr: Address to poll
++ * @val: Variable to read the value into
++ * @cond: Break condition (usually involving @val)
++ * @sleep_us: Maximum time to sleep between reads in us (0
++ *            tight-loops).  Should be less than ~20ms since usleep_range
++ *            is used (see Documentation/timers/timers-howto.txt).
++ * @timeout_us: Timeout in us, 0 means never timeout
++ *
++ * Returns 0 on success and -ETIMEDOUT upon a timeout. In either
++ * case, the last read value at @addr is stored in @val. Must not
++ * be called from atomic context if sleep_us or timeout_us are used.
++ *
++ * When available, you'll probably want to use one of the specialized
++ * macros defined below rather than this macro directly.
++ */
++#define readx_poll_timeout(op, addr, val, cond, sleep_us, timeout_us)	\
++({ \
++	ktime_t timeout = ktime_add_us(ktime_get(), timeout_us); \
++	might_sleep_if(sleep_us); \
++	for (;;) { \
++		(val) = op(addr); \
++		if (cond) \
++			break; \
++		if (timeout_us && ktime_compare(ktime_get(), timeout) > 0) { \
++			(val) = op(addr); \
++			break; \
++		} \
++		if (sleep_us) \
++			usleep_range((sleep_us >> 2) + 1, sleep_us); \
++	} \
++	(cond) ? 0 : -ETIMEDOUT; \
++})
++
++/**
++ * readx_poll_timeout_atomic - Periodically poll an address until a condition is met or a timeout occurs
++ * @op: accessor function (takes @addr as its only argument)
++ * @addr: Address to poll
++ * @val: Variable to read the value into
++ * @cond: Break condition (usually involving @val)
++ * @delay_us: Time to udelay between reads in us (0 tight-loops).  Should
++ *            be less than ~10us since udelay is used (see
++ *            Documentation/timers/timers-howto.txt).
++ * @timeout_us: Timeout in us, 0 means never timeout
++ *
++ * Returns 0 on success and -ETIMEDOUT upon a timeout. In either
++ * case, the last read value at @addr is stored in @val.
++ *
++ * When available, you'll probably want to use one of the specialized
++ * macros defined below rather than this macro directly.
++ */
++#define readx_poll_timeout_atomic(op, addr, val, cond, delay_us, timeout_us) \
++({ \
++	ktime_t timeout = ktime_add_us(ktime_get(), timeout_us); \
++	for (;;) { \
++		(val) = op(addr); \
++		if (cond) \
++			break; \
++		if (timeout_us && ktime_compare(ktime_get(), timeout) > 0) { \
++			(val) = op(addr); \
++			break; \
++		} \
++		if (delay_us) \
++			udelay(delay_us);	\
++	} \
++	(cond) ? 0 : -ETIMEDOUT; \
++})
++
++
++#define readb_poll_timeout(addr, val, cond, delay_us, timeout_us) \
++	readx_poll_timeout(readb, addr, val, cond, delay_us, timeout_us)
++
++#define readb_poll_timeout_atomic(addr, val, cond, delay_us, timeout_us) \
++	readx_poll_timeout_atomic(readb, addr, val, cond, delay_us, timeout_us)
++
++#define readw_poll_timeout(addr, val, cond, delay_us, timeout_us) \
++	readx_poll_timeout(readw, addr, val, cond, delay_us, timeout_us)
++
++#define readw_poll_timeout_atomic(addr, val, cond, delay_us, timeout_us) \
++	readx_poll_timeout_atomic(readw, addr, val, cond, delay_us, timeout_us)
++
++#define readl_poll_timeout(addr, val, cond, delay_us, timeout_us) \
++	readx_poll_timeout(hi_readl, addr, val, cond, delay_us, timeout_us)
++
++#define readl_poll_timeout_atomic(addr, val, cond, delay_us, timeout_us) \
++	readx_poll_timeout_atomic(readl, addr, val, cond, delay_us, timeout_us)
++
++#define readq_poll_timeout(addr, val, cond, delay_us, timeout_us) \
++	readx_poll_timeout(readq, addr, val, cond, delay_us, timeout_us)
++
++#define readq_poll_timeout_atomic(addr, val, cond, delay_us, timeout_us) \
++	readx_poll_timeout_atomic(readq, addr, val, cond, delay_us, timeout_us)
++
++#define readb_relaxed_poll_timeout(addr, val, cond, delay_us, timeout_us) \
++	readx_poll_timeout(readb_relaxed, addr, val, cond, delay_us, timeout_us)
++
++#define readb_relaxed_poll_timeout_atomic(addr, val, cond, delay_us, timeout_us) \
++	readx_poll_timeout_atomic(readb_relaxed, addr, val, cond, delay_us, timeout_us)
++
++#define readw_relaxed_poll_timeout(addr, val, cond, delay_us, timeout_us) \
++	readx_poll_timeout(readw_relaxed, addr, val, cond, delay_us, timeout_us)
++
++#define readw_relaxed_poll_timeout_atomic(addr, val, cond, delay_us, timeout_us) \
++	readx_poll_timeout_atomic(readw_relaxed, addr, val, cond, delay_us, timeout_us)
++
++#define readl_relaxed_poll_timeout(addr, val, cond, delay_us, timeout_us) \
++	readx_poll_timeout(readl_relaxed, addr, val, cond, delay_us, timeout_us)
++
++#define readl_relaxed_poll_timeout_atomic(addr, val, cond, delay_us, timeout_us) \
++	readx_poll_timeout_atomic(readl_relaxed, addr, val, cond, delay_us, timeout_us)
++
++#define readq_relaxed_poll_timeout(addr, val, cond, delay_us, timeout_us) \
++	readx_poll_timeout(readq_relaxed, addr, val, cond, delay_us, timeout_us)
++
++#define readq_relaxed_poll_timeout_atomic(addr, val, cond, delay_us, timeout_us) \
++	readx_poll_timeout_atomic(readq_relaxed, addr, val, cond, delay_us, timeout_us)
++
++#endif /* _LINUX_IOPOLL_H */
+diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
+index ff56053..ee05d8b 100644
+--- a/include/linux/ipv6.h
++++ b/include/linux/ipv6.h
+@@ -37,11 +37,13 @@ struct ipv6_devconf {
+ 	__s32		accept_ra_rt_info_max_plen;
+ #endif
+ #endif
++	__s32		accept_ra_rt_table;
+ 	__s32		proxy_ndp;
+ 	__s32		accept_source_route;
+ 	__s32		accept_ra_from_local;
+ #ifdef CONFIG_IPV6_OPTIMISTIC_DAD
+ 	__s32		optimistic_dad;
++	__s32		use_optimistic;
+ #endif
+ #ifdef CONFIG_IPV6_MROUTE
+ 	__s32		mc_forwarding;
+@@ -123,6 +125,12 @@ struct ipv6_mc_socklist;
+ struct ipv6_ac_socklist;
+ struct ipv6_fl_socklist;
+ 
++struct inet6_cork {
++	struct ipv6_txoptions *opt;
++	u8 hop_limit;
++	u8 tclass;
++};
++
+ /**
+  * struct ipv6_pinfo - ipv6 private area
+  *
+@@ -212,14 +220,10 @@ struct ipv6_pinfo {
+ 	struct ipv6_ac_socklist	*ipv6_ac_list;
+ 	struct ipv6_fl_socklist __rcu *ipv6_fl_list;
+ 
+-	struct ipv6_txoptions	*opt;
++	struct ipv6_txoptions __rcu	*opt;
+ 	struct sk_buff		*pktoptions;
+ 	struct sk_buff		*rxpmtu;
+-	struct {
+-		struct ipv6_txoptions *opt;
+-		u8 hop_limit;
+-		u8 tclass;
+-	} cork;
++	struct inet6_cork	cork;
+ };
+ 
+ /* WARNING: don't change the layout of the members in {raw,udp,tcp}6_sock! */
+diff --git a/include/linux/kernel.h b/include/linux/kernel.h
+index 3d770f5..54c20a4 100644
+--- a/include/linux/kernel.h
++++ b/include/linux/kernel.h
+@@ -103,6 +103,18 @@
+ 		(((__x) - ((__d) / 2)) / (__d));	\
+ }							\
+ )
++/*
++ * Same as above but for u64 dividends. divisor must be a 32-bit
++ * number.
++ */
++#define DIV_ROUND_CLOSEST_ULL(x, divisor)(		\
++{							\
++	typeof(divisor) __d = divisor;			\
++	unsigned long long _tmp = (x) + (__d) / 2;	\
++	do_div(_tmp, __d);				\
++	_tmp;						\
++}							\
++)
+ 
+ /*
+  * Multiplies an integer by a fraction, while avoiding unnecessary
+@@ -814,4 +826,8 @@ static inline void ftrace_dump(enum ftrace_dump_mode oops_dump_mode) { }
+ 	 /* Other writable?  Generally considered a bad idea. */	\
+ 	 BUILD_BUG_ON_ZERO((perms) & 2) +				\
+ 	 (perms))
++
++/* To identify board information in panic logs, set this */
++extern char *mach_panic_string;
++
+ #endif
+diff --git a/include/linux/keychord.h b/include/linux/keychord.h
+new file mode 100644
+index 0000000..08cf540
+--- /dev/null
++++ b/include/linux/keychord.h
+@@ -0,0 +1,23 @@
++/*
++ *  Key chord input driver
++ *
++ * Copyright (C) 2008 Google, Inc.
++ * Author: Mike Lockwood <lockwood@android.com>
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++*/
++
++#ifndef __LINUX_KEYCHORD_H_
++#define __LINUX_KEYCHORD_H_
++
++#include <uapi/linux/keychord.h>
++
++#endif	/* __LINUX_KEYCHORD_H_ */
+diff --git a/include/linux/keycombo.h b/include/linux/keycombo.h
+new file mode 100644
+index 0000000..c6db262
+--- /dev/null
++++ b/include/linux/keycombo.h
+@@ -0,0 +1,36 @@
++/*
++ * include/linux/keycombo.h - platform data structure for keycombo driver
++ *
++ * Copyright (C) 2014 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#ifndef _LINUX_KEYCOMBO_H
++#define _LINUX_KEYCOMBO_H
++
++#define KEYCOMBO_NAME "keycombo"
++
++/*
++ * if key_down_fn and key_up_fn are both present, you are guaranteed that
++ * key_down_fn will return before key_up_fn is called, and that key_up_fn
++ * is called iff key_down_fn is called.
++ */
++struct keycombo_platform_data {
++	void (*key_down_fn)(void *);
++	void (*key_up_fn)(void *);
++	void *priv;
++	int key_down_delay; /* Time in ms */
++	int *keys_up;
++	int keys_down[]; /* 0 terminated */
++};
++
++#endif /* _LINUX_KEYCOMBO_H */
+diff --git a/include/linux/keyreset.h b/include/linux/keyreset.h
+new file mode 100644
+index 0000000..2e34afa
+--- /dev/null
++++ b/include/linux/keyreset.h
+@@ -0,0 +1,29 @@
++/*
++ * include/linux/keyreset.h - platform data structure for resetkeys driver
++ *
++ * Copyright (C) 2014 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#ifndef _LINUX_KEYRESET_H
++#define _LINUX_KEYRESET_H
++
++#define KEYRESET_NAME "keyreset"
++
++struct keyreset_platform_data {
++	int (*reset_fn)(void);
++	int key_down_delay;
++	int *keys_up;
++	int keys_down[]; /* 0 terminated */
++};
++
++#endif /* _LINUX_KEYRESET_H */
+diff --git a/include/linux/kmod.h b/include/linux/kmod.h
+index 0555cc6..1632757 100644
+--- a/include/linux/kmod.h
++++ b/include/linux/kmod.h
+@@ -73,6 +73,37 @@ extern struct subprocess_info *
+ call_usermodehelper_setup(char *path, char **argv, char **envp, gfp_t gfp_mask,
+ 			  int (*init)(struct subprocess_info *info, struct cred *new),
+ 			  void (*cleanup)(struct subprocess_info *), void *data);
++#ifdef	CONFIG_HISI_SNAPSHOT_BOOT
++int call_usermodehelper_exec_force(struct subprocess_info *info, int wait);
++#endif
++#ifdef	CONFIG_HISI_SNAPSHOT_BOOT
++static inline int
++call_usermodehelper_fns_force(char *path, char **argv, char **envp,
++	int wait, int (*init)(struct subprocess_info *info,
++	struct cred *new), void (*cleanup)(struct subprocess_info *),
++	void *data)
++{
++	struct subprocess_info *info;
++	gfp_t gfp_mask = (wait == UMH_NO_WAIT) ? GFP_ATOMIC : GFP_KERNEL;
++
++	info = call_usermodehelper_setup(path, argv, envp, gfp_mask, init,
++			cleanup, data);
++
++	if (info == NULL)
++		return -ENOMEM;
++
++	/*call_usermodehelper_setfns(info, init, cleanup, data);*/
++
++	return call_usermodehelper_exec_force(info, wait);
++}
++
++static inline int
++call_usermodehelper_force(char *path, char **argv, char **envp, int wait)
++{
++	return call_usermodehelper_fns_force(path, argv, envp, wait,
++			NULL, NULL, NULL);
++}
++#endif
+ 
+ extern int
+ call_usermodehelper_exec(struct subprocess_info *info, int wait);
+diff --git a/include/linux/lsm_audit.h b/include/linux/lsm_audit.h
+index 1cc89e9..ffb9c9d 100644
+--- a/include/linux/lsm_audit.h
++++ b/include/linux/lsm_audit.h
+@@ -40,6 +40,11 @@ struct lsm_network_audit {
+ 	} fam;
+ };
+ 
++struct lsm_ioctlop_audit {
++	struct path path;
++	u16 cmd;
++};
++
+ /* Auxiliary data to use in generating the audit record. */
+ struct common_audit_data {
+ 	char type;
+@@ -53,6 +58,7 @@ struct common_audit_data {
+ #define LSM_AUDIT_DATA_KMOD	8
+ #define LSM_AUDIT_DATA_INODE	9
+ #define LSM_AUDIT_DATA_DENTRY	10
++#define LSM_AUDIT_DATA_IOCTL_OP	11
+ 	union 	{
+ 		struct path path;
+ 		struct dentry *dentry;
+@@ -68,6 +74,7 @@ struct common_audit_data {
+ 		} key_struct;
+ #endif
+ 		char *kmod_name;
++		struct lsm_ioctlop_audit *op;
+ 	} u;
+ 	/* this union contains LSM specific data */
+ 	union {
+diff --git a/include/linux/mfd/hisi_fmc.h b/include/linux/mfd/hisi_fmc.h
+new file mode 100644
+index 0000000..ac94cd8
+--- /dev/null
++++ b/include/linux/mfd/hisi_fmc.h
+@@ -0,0 +1,503 @@
++/*
++ * Header file for HiSilicon Flash Memory Controller Driver
++ *
++ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#ifndef __HISI_FMC_H
++#define __HISI_FMC_H
++
++#include <linux/compiler.h>
++#include <linux/clk.h>
++#include <linux/mutex.h>
++#include <linux/bitops.h>
++
++/*****************************************************************************/
++#define _512B					(512)
++#define _1K					(1024)
++#define _2K					(2048)
++#define _4K					(4096)
++#define _8K					(8192)
++#define _16K					(16384)
++#define _32K					(32768)
++#define _64K					(0x10000UL)
++#define _128K					(0x20000UL)
++#define _256K					(0x40000UL)
++#define _512K					(0x80000UL)
++#define _1M					(0x100000UL)
++#define _2M					(0x200000UL)
++#define _4M					(0x400000UL)
++#define _8M					(0x800000UL)
++#define _16M					(0x1000000UL)
++#define _32M					(0x2000000UL)
++#define _64M					(0x4000000UL)
++#define _128M					(0x8000000UL)
++#define _256M					(0x10000000UL)
++#define _512M					(0x20000000UL)
++#define _1G					(0x40000000ULL)
++#define _2G					(0x80000000ULL)
++#define _4G					(0x100000000ULL)
++#define _8G					(0x200000000ULL)
++#define _16G					(0x400000000ULL)
++#define _64G					(0x1000000000ULL)
++
++/*****************************************************************************/
++/* HIFMC REG MAP */
++/*****************************************************************************/
++#define FMC_CFG					0x00
++#define FMC_CFG_SPI_NAND_SEL(_type)		(((_size) & 0x3) << 11)
++#define SPI_NOR_ADDR_MODE			BIT(10)
++#define FMC_CFG_OP_MODE_MASK			BIT_MASK(0)
++#define FMC_CFG_OP_MODE_BOOT			0
++#define FMC_CFG_OP_MODE_NORMAL			1
++#define SPI_NOR_ADDR_MODE_3BYTES		(0x0 << 10)
++#define SPI_NOR_ADDR_MODE_4BYTES		(0x1 << 10)
++
++#define FMC_CFG_BLOCK_SIZE(_size)		(((_size) & 0x3) << 8)
++#define FMC_CFG_ECC_TYPE(_type)			(((_type) & 0x7) << 5)
++#define FMC_CFG_PAGE_SIZE(_size)		(((_size) & 0x3) << 3)
++#define FMC_CFG_FLASH_SEL(_type)		(((_type) & 0x3) << 1)
++#define FMC_CFG_OP_MODE(_mode)			((_mode) & 0x1)
++
++#define SPI_NAND_MFR_OTHER			0x0
++#define SPI_NAND_MFR_WINBOND			0x1
++#define SPI_NAND_MFR_ESMT			0x2
++#define SPI_NAND_MFR_MICRON			0x3
++
++#define SPI_NAND_SEL_SHIFT			11
++#define SPI_NAND_SEL_MASK			(0x3 << SPI_NAND_SEL_SHIFT)
++
++#define SPI_NOR_ADDR_MODE_3_BYTES		0x0
++#define SPI_NOR_ADDR_MODE_4_BYTES		0x1
++
++#define SPI_NOR_ADDR_MODE_SHIFT			10
++#define SPI_NOR_ADDR_MODE_MASK			(0x1 << SPI_NOR_ADDR_MODE_SHIFT)
++
++#define BLOCK_SIZE_64_PAGE			0x0
++#define BLOCK_SIZE_128_PAGE			0x1
++#define BLOCK_SIZE_256_PAGE			0x2
++#define BLOCK_SIZE_512_PAGE			0x3
++
++#define BLOCK_SIZE_MASK				(0x3 << 8)
++
++#define ECC_TYPE_0BIT				0x0
++#define ECC_TYPE_8BIT				0x1
++#define ECC_TYPE_16BIT				0x2
++#define ECC_TYPE_24BIT				0x3
++#define ECC_TYPE_28BIT				0x4
++#define ECC_TYPE_40BIT				0x5
++#define ECC_TYPE_64BIT				0x6
++
++#define ECC_TYPE_SHIFT				5
++#define ECC_TYPE_MASK				(0x7 << ECC_TYPE_SHIFT)
++
++#define PAGE_SIZE_2KB				0x0
++#define PAGE_SIZE_4KB				0x1
++#define PAGE_SIZE_8KB				0x2
++#define PAGE_SIZE_16KB				0x3
++
++#define PAGE_SIZE_SHIFT				3
++#define PAGE_SIZE_MASK				(0x3 << PAGE_SIZE_SHIFT)
++
++#define FLASH_TYPE_SPI_NOR			0x0
++#define FLASH_TYPE_SPI_NAND			0x1
++#define FLASH_TYPE_NAND				0x2
++#define FLASH_TYPE_UNKNOWN			0x3
++
++#define FLASH_TYPE_SEL_MASK			(0x3 << 1)
++#define GET_SPI_FLASH_TYPE(_reg)		(((_reg) >> 1) & 0x3)
++
++/*****************************************************************************/
++#define FMC_GLOBAL_CFG				0x04
++#define FMC_GLOBAL_CFG_WP_ENABLE		BIT(6)
++#define FMC_GLOBAL_CFG_RANDOMIZER_EN		(1 << 2)
++#define FLASH_TYPE_SEL_MASK			(0x3 << 1)
++#define FMC_CFG_FLASH_SEL(_type)		(((_type) & 0x3) << 1)
++
++/*****************************************************************************/
++#define FMC_SPI_TIMING_CFG			0x08
++#define TIMING_CFG_TCSH(nr)			(((nr) & 0xf) << 8)
++#define TIMING_CFG_TCSS(nr)			(((nr) & 0xf) << 4)
++#define TIMING_CFG_TSHSL(nr)			((nr) & 0xf)
++
++#define CS_HOLD_TIME				0x6
++#define CS_SETUP_TIME				0x6
++#define CS_DESELECT_TIME			0xf
++
++/*****************************************************************************/
++#define FMC_PND_PWIDTH_CFG			0x0c
++#define PWIDTH_CFG_RW_HCNT(_n)			(((_n) & 0xf) << 8)
++#define PWIDTH_CFG_R_LCNT(_n)			(((_n) & 0xf) << 4)
++#define PWIDTH_CFG_W_LCNT(_n)			((_n) & 0xf)
++
++#define RW_H_WIDTH				(0xa)
++#define R_L_WIDTH				(0xa)
++#define W_L_WIDTH				(0xa)
++
++/*****************************************************************************/
++#define FMC_INT					0x18
++#define FMC_INT_AHB_OP				BIT(7)
++#define FMC_INT_WR_LOCK				BIT(6)
++#define FMC_INT_DMA_ERR				BIT(5)
++#define FMC_INT_ERR_ALARM			BIT(4)
++#define FMC_INT_ERR_INVALID			BIT(3)
++#define FMC_INT_ERR_INVALID_MASK		(0x8)
++#define FMC_INT_ERR_VALID			BIT(2)
++#define FMC_INT_ERR_VALID_MASK			(0x4)
++#define FMC_INT_OP_FAIL				BIT(1)
++#define FMC_INT_OP_DONE				BIT(0)
++
++/*****************************************************************************/
++#define FMC_INT_EN				0x1c
++#define FMC_INT_EN_AHB_OP			BIT(7)
++#define FMC_INT_EN_WR_LOCK			BIT(6)
++#define FMC_INT_EN_DMA_ERR			BIT(5)
++#define FMC_INT_EN_ERR_ALARM			BIT(4)
++#define FMC_INT_EN_ERR_INVALID			BIT(3)
++#define FMC_INT_EN_ERR_VALID			BIT(2)
++#define FMC_INT_EN_OP_FAIL			BIT(1)
++#define FMC_INT_EN_OP_DONE			BIT(0)
++
++/*****************************************************************************/
++#define FMC_INT_CLR				0x20
++#define FMC_INT_CLR_AHB_OP			BIT(7)
++#define FMC_INT_CLR_WR_LOCK			BIT(6)
++#define FMC_INT_CLR_DMA_ERR			BIT(5)
++#define FMC_INT_CLR_ERR_ALARM			BIT(4)
++#define FMC_INT_CLR_ERR_INVALID			BIT(3)
++#define FMC_INT_CLR_ERR_VALID			BIT(2)
++#define FMC_INT_CLR_OP_FAIL			BIT(1)
++#define FMC_INT_CLR_OP_DONE			BIT(0)
++
++#define FMC_INT_CLR_ALL				0xff
++
++/*****************************************************************************/
++#define FMC_CMD					0x24
++#define FMC_CMD_CMD2(_cmd)			(((_cmd) & 0xff) << 8)
++#define FMC_CMD_CMD1(_cmd)			((_cmd) & 0xff)
++
++/*****************************************************************************/
++#define FMC_ADDRH				0x28
++#define FMC_ADDRH_SET(_addr)			((_addr) & 0xff)
++
++/*****************************************************************************/
++#define FMC_ADDRL				0x2c
++#define FMC_ADDRL_BLOCK_MASK(_page)		((_page) & 0xffffffc0)
++#define FMC_ADDRL_BLOCK_H_MASK(_page)		(((_page) & 0xffff) << 16)
++#define FMC_ADDRL_BLOCK_L_MASK(_page)		((_page) & 0xffc0)
++
++#define READ_ID_ADDR				0x00
++#define PROTECT_ADDR				0xa0
++#define FEATURE_ADDR				0xb0
++#define STATUS_ADDR					0xc0
++/*****************************************************************************/
++#define FMC_OP_CFG				0x30
++#define OP_CFG_FM_CS(_cs)			((_cs) << 11)
++#define OP_CFG_FORCE_CS_EN(_en)			((_en) << 10)
++#define OP_CFG_MEM_IF_TYPE(_type)		(((_type) & 0x7) << 7)
++#define OP_CFG_ADDR_NUM(_addr)			(((_addr) & 0x7) << 4)
++#define OP_CFG_DUMMY_NUM(_dummy)		((_dummy) & 0xf)
++
++#define IF_TYPE_SHIFT				7
++#define IF_TYPE_MASK				(0x7 << IF_TYPE_SHIFT)
++
++#define READ_ID_ADDR_NUM			1
++#define FEATURES_OP_ADDR_NUM			1
++#define STD_OP_ADDR_NUM				3
++
++/*****************************************************************************/
++#define FMC_SPI_OP_ADDR				0x34
++
++/*****************************************************************************/
++#define FMC_DATA_NUM				0x38
++#define FMC_DATA_NUM_CNT(_n)			((_n) & 0x3fff)
++
++#define SPI_NOR_SR_LEN				1 /* Status Register length */
++#define SPI_NOR_CR_LEN				1 /* Config Register length */
++#define FEATURES_DATA_LEN			1
++#define READ_OOB_BB_LEN				1
++
++#define PROTECT_BRWD_MASK			BIT(7)
++#define PROTECT_BP3_MASK			BIT(6)
++#define PROTECT_BP2_MASK			BIT(5)
++#define PROTECT_BP1_MASK			BIT(4)
++#define PROTECT_BP0_MASK			BIT(3)
++
++#define ANY_BP_ENABLE(_val)			((PROTECT_BP3_MASK & _val) \
++						|| (PROTECT_BP2_MASK & _val) \
++						|| (PROTECT_BP1_MASK & _val) \
++						|| (PROTECT_BP0_MASK & _val))
++
++#define ALL_BP_MASK				(PROTECT_BP3_MASK \
++						| PROTECT_BP2_MASK \
++						| PROTECT_BP1_MASK \
++						| PROTECT_BP0_MASK)
++
++#define FEATURE_ECC_ENABLE		        (1 << 4)
++#define FEATURE_QE_ENABLE			(1 << 0)
++
++/*****************************************************************************/
++#define FMC_OP					0x3c
++#define FMC_OP_DUMMY_EN				BIT(8)
++#define FMC_OP_CMD1_EN				BIT(7)
++#define FMC_OP_ADDR_EN				BIT(6)
++#define FMC_OP_WRITE_DATA_EN			BIT(5)
++#define FMC_OP_CMD2_EN				BIT(4)
++#define FMC_OP_WAIT_READY_EN			BIT(3)
++#define FMC_OP_READ_DATA_EN			BIT(2)
++#define FMC_OP_READ_STATUS_EN			BIT(1)
++#define FMC_OP_REG_OP_START			BIT(0)
++
++/*****************************************************************************/
++#define FMC_DMA_LEN				0x40
++#define FMC_DMA_LEN_SET(_len)			((_len) & 0x0fffffff)
++
++/*****************************************************************************/
++#define FMC_DMA_AHB_CTRL			0x48
++#define FMC_DMA_AHB_CTRL_DMA_PP_EN		BIT(3)
++#define FMC_DMA_AHB_CTRL_BURST16_EN		BIT(2)
++#define FMC_DMA_AHB_CTRL_BURST8_EN		BIT(1)
++#define FMC_DMA_AHB_CTRL_BURST4_EN		BIT(0)
++
++#define ALL_BURST_ENABLE			(FMC_DMA_AHB_CTRL_BURST16_EN \
++						| FMC_DMA_AHB_CTRL_BURST8_EN \
++						| FMC_DMA_AHB_CTRL_BURST4_EN)
++
++#define FMC_DMA_ADDR_OFFSET			4096
++
++/*****************************************************************************/
++#define FMC_DMA_SADDR_D0			0x4c
++#define HIFMC_DMA_MAX_LEN			(4096)
++#define HIFMC_DMA_MASK				(HIFMC_DMA_MAX_LEN - 1)
++
++/*****************************************************************************/
++#define FMC_DMA_SADDR_D1			0x50
++
++/*****************************************************************************/
++#define FMC_DMA_SADDR_D2			0x54
++
++/*****************************************************************************/
++#define FMC_DMA_SADDR_D3			0x58
++
++/*****************************************************************************/
++#define FMC_DMA_SADDR_OOB			0x5c
++
++/*****************************************************************************/
++#define FMC_DMA_BLK_SADDR			0x60
++#define FMC_DMA_BLK_SADDR_SET(_addr)		((_addr) & 0xffffff)
++
++/*****************************************************************************/
++#define FMC_DMA_BLK_LEN				0x64
++#define FMC_DMA_BLK_LEN_SET(_len)		((_len) & 0xffff)
++
++/*****************************************************************************/
++#define FMC_OP_CTRL				0x68
++#define OP_CTRL_RD_OPCODE(_code)		(((_code) & 0xff) << 16)
++#define OP_CTRL_WR_OPCODE(_code)		(((_code) & 0xff) << 8)
++#define OP_CTRL_RD_OP_SEL(_op)			(((_op) & 0x3) << 4)
++#define OP_CTRL_DMA_OP(_type)			((_type) << 2)
++#define OP_CTRL_RW_OP(_op)			((_op) << 1)
++#define OP_CTRL_DMA_OP_READY			BIT(0)
++
++#define RD_OP_READ_ALL_PAGE			0x0
++#define RD_OP_READ_OOB				0x1
++#define RD_OP_BLOCK_READ			0x2
++
++#define RD_OP_SHIFT				4
++#define RD_OP_MASK				(0x3 << RD_OP_SHIFT)
++
++#define OP_TYPE_DMA				0x0
++#define OP_TYPE_REG				0x1
++
++#define FMC_OP_READ				0x0
++#define FMC_OP_WRITE				0x1
++#define RW_OP_READ				0x0
++#define RW_OP_WRITE				0x1
++
++/*****************************************************************************/
++#define FMC_OP_PARA				0x70
++#define FMC_OP_PARA_RD_OOB_ONLY			BIT(1)
++
++/*****************************************************************************/
++#define FMC_BOOT_SET				0x74
++#define FMC_BOOT_SET_DEVICE_ECC_EN		BIT(3)
++#define FMC_BOOT_SET_BOOT_QUAD_EN		BIT(1)
++
++/*****************************************************************************/
++#define FMC_STATUS				0xac
++
++/*****************************************************************************/
++#ifndef FMC_VERSION
++#define FMC_VERSION				0xbc
++#endif
++
++/* Hifmc IP version */
++#ifndef HIFMC_VER_100
++#define HIFMC_VER_100				(0x100)
++#endif
++
++/*****************************************************************************/
++/* DMA address align with 32 bytes. */
++#define FMC_DMA_ALIGN                           32
++
++#define FMC_CHIP_DELAY                          25
++/*****************************************************************************/
++#define HIFMC_ECC_ERR_NUM0_BUF0			0xc0
++#define GET_ECC_ERR_NUM(_i, _reg)		(((_reg) >> ((_i) * 8)) & 0xff)
++
++#define DISABLE               0
++#define ENABLE                1
++
++/*****************************************************************************/
++#define HIFMC_REG_ADDRESS_LEN			0x200
++
++/*****************************************************************************/
++#define FMC_MAX_READY_WAIT_JIFFIES		(HZ)
++
++#define MAX_SPI_NOR_ID_LEN			8
++#define MAX_NAND_ID_LEN				8
++#define MAX_SPI_NAND_ID_LEN			3
++
++#define GET_OP					0
++#define SET_OP					1
++
++#define STATUS_ECC_MASK				(0x3 << 4)
++#define STATUS_P_FAIL_MASK			(1 << 3)
++#define STATUS_E_FAIL_MASK			(1 << 2)
++#define STATUS_WEL_MASK				(1 << 1)
++#define STATUS_OIP_MASK				(1 << 0)
++
++/*****************************************************************************/
++#define FMC_VERSION				0xbc
++
++/* Hifmc IP version */
++#define HIFMC_VER_100				(0x100)
++
++/*****************************************************************************/
++#define GET_PAGE_INDEX(host) \
++	                ((host->addr_value[0] >> 16) | (host->addr_value[1] << 16))
++/*****************************************************************************/
++#define HIFMC_MAX_CHIP_NUM		2
++
++extern unsigned char hifmc_cs_user[];
++
++/*****************************************************************************/
++#define hifmc_readl(_host, _reg) \
++	(hi_readl((char *)_host->regbase + (_reg)))
++
++#define hifmc_readb( _addr) \
++	(hi_readb((void __iomem *)(_addr)))
++
++#define hifmc_readw( _addr) \
++	(hi_readw((void __iomem *)(_addr)))
++
++#define hifmc_writel(_host, _reg, _value) \
++	(hi_writel((u_int)(_value), ((char *)_host->regbase + (_reg))))
++
++#define hifmc_writeb(_val, _addr) \
++	(hi_writeb((u_int)(_val), ((char *)_addr)))
++
++/*****************************************************************************/
++#define FMC_WAIT_TIMEOUT 0x1000000
++
++#define FMC_CMD_WAIT_CPU_FINISH(_host) \
++	do { \
++		unsigned regval, timeout = FMC_WAIT_TIMEOUT * 2; \
++		do { \
++			regval = hifmc_readl((_host), FMC_OP); \
++			--timeout; \
++		} while ((regval & FMC_OP_REG_OP_START) && timeout); \
++		if (!timeout) \
++			pr_info("Error: Wait cmd cpu finish timeout!\n"); \
++	} while (0)
++
++/*****************************************************************************/
++#define FMC_DMA_WAIT_INT_FINISH(_host) \
++	do { \
++		unsigned regval, timeout = FMC_WAIT_TIMEOUT; \
++		do { \
++			regval = hifmc_readl((_host), FMC_INT); \
++			--timeout; \
++		} while ((!(regval & FMC_INT_OP_DONE) && timeout)); \
++		if (!timeout) \
++			pr_info("Error: Wait dma int finish timeout!\n"); \
++	} while (0)
++
++/*****************************************************************************/
++#define FMC_DMA_WAIT_CPU_FINISH(_host) \
++	do { \
++		unsigned regval, timeout = FMC_WAIT_TIMEOUT; \
++		do { \
++			regval = hifmc_readl((_host), FMC_OP_CTRL); \
++			--timeout; \
++		} while ((regval & OP_CTRL_DMA_OP_READY) && timeout); \
++		if (!timeout) \
++			pr_info("Error: Wait dma cpu finish timeout!\n"); \
++	} while (0)
++
++/*****************************************************************************/
++#define BT_DBG		0	/* Boot init debug print */
++#define ER_DBG		0	/* Erase debug print */
++#define WR_DBG		0	/* Write debug print */
++#define RD_DBG		0	/* Read debug print */
++#define QE_DBG		0	/* Quad Enable debug print */
++#define OP_DBG		0	/* OP command debug print */
++#define DMA_DB		0	/* DMA read or write debug print */
++#define AC_DBG		0	/* 3-4byte Address Cycle */
++#define SR_DBG		0	/* Status Register debug print */
++#define CR_DBG		0	/* Config Register debug print */
++#define FT_DBG		0	/* Features debug print */
++#define WE_DBG		0	/* Write Enable debug print */
++#define BP_DBG		0	/* Block Protection debug print */
++#define EC_DBG		0	/* enable/disable ecc0 and randomizer */
++#define PM_DBG		0	/* power management debug */
++
++#define FMC_PR(_type, _fmt, arg...) \
++	do { \
++		if (_type) \
++			DB_MSG(_fmt, ##arg) \
++	} while (0)
++
++#define DB_MSG(_fmt, arg...) \
++	pr_info("%s(%d): " _fmt, __func__, __LINE__, ##arg);
++
++#define DB_BUG(fmt, args...) \
++	do { \
++		pr_info("%s(%d): BUG: " fmt, __FILE__, __LINE__, ##args); \
++		while (1) \
++			; \
++	} while (0)
++
++/*****************************************************************************/
++enum hifmc_iftype {
++	IF_TYPE_STD,
++	IF_TYPE_DUAL,
++	IF_TYPE_DIO,
++	IF_TYPE_QUAD,
++	IF_TYPE_QIO,
++};
++struct hisi_fmc {
++	void __iomem *regbase;
++	void __iomem *iobase;
++	struct clk *clk;
++	struct mutex lock;
++};
++
++struct hifmc_cmd_op {
++	unsigned char cs;
++	unsigned char cmd;
++	unsigned char l_cmd;
++	unsigned char addr_h;
++	unsigned int addr_l;
++	unsigned int data_no;
++	unsigned short option;
++	unsigned short op_cfg;
++};
++
++extern struct mutex fmc_switch_mutex;
++
++#endif /*__HISI_FMC_H*/
+diff --git a/include/linux/mm.h b/include/linux/mm.h
+index 86a977b..0628a5f 100644
+--- a/include/linux/mm.h
++++ b/include/linux/mm.h
+@@ -1087,6 +1087,7 @@ extern void pagefault_out_of_memory(void);
+ extern void show_free_areas(unsigned int flags);
+ extern bool skip_free_areas_node(unsigned int flags, int nid);
+ 
++void shmem_set_file(struct vm_area_struct *vma, struct file *file);
+ int shmem_zero_setup(struct vm_area_struct *);
+ #ifdef CONFIG_SHMEM
+ bool shmem_mapping(struct address_space *mapping);
+@@ -1352,6 +1353,11 @@ static inline void update_hiwater_vm(struct mm_struct *mm)
+ 		mm->hiwater_vm = mm->total_vm;
+ }
+ 
++static inline void reset_mm_hiwater_rss(struct mm_struct *mm)
++{
++	mm->hiwater_rss = get_mm_rss(mm);
++}
++
+ static inline void setmax_mm_hiwater_rss(unsigned long *maxrss,
+ 					 struct mm_struct *mm)
+ {
+@@ -1739,6 +1745,9 @@ extern void zone_pcp_reset(struct zone *zone);
+ 
+ /* page_alloc.c */
+ extern int min_free_kbytes;
++#ifdef CONFIG_CMA_ADVANCE_SHARE
++extern int cma_watermark;
++#endif
+ 
+ /* nommu.c */
+ extern atomic_long_t mmap_pages_allocated;
+@@ -1790,7 +1799,7 @@ extern int vma_adjust(struct vm_area_struct *vma, unsigned long start,
+ extern struct vm_area_struct *vma_merge(struct mm_struct *,
+ 	struct vm_area_struct *prev, unsigned long addr, unsigned long end,
+ 	unsigned long vm_flags, struct anon_vma *, struct file *, pgoff_t,
+-	struct mempolicy *);
++	struct mempolicy *, const char __user *);
+ extern struct anon_vma *find_mergeable_anon_vma(struct vm_area_struct *);
+ extern int split_vma(struct mm_struct *,
+ 	struct vm_area_struct *, unsigned long addr, int new_below);
+@@ -2028,6 +2037,7 @@ static inline struct page *follow_page(struct vm_area_struct *vma,
+ #define FOLL_NUMA	0x200	/* force NUMA hinting page fault */
+ #define FOLL_MIGRATION	0x400	/* wait for page to replace migration entry */
+ #define FOLL_TRIED	0x800	/* a retry, previous pass started an IO */
++#define FOLL_COW	0x4000	/* internal GUP flag */
+ 
+ typedef int (*pte_fn_t)(pte_t *pte, pgtable_t token, unsigned long addr,
+ 			void *data);
+diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
+index 6e0b286..6c44170 100644
+--- a/include/linux/mm_types.h
++++ b/include/linux/mm_types.h
+@@ -274,6 +274,10 @@ struct vm_area_struct {
+ 	 * For areas with an address space and backing store,
+ 	 * linkage into the address_space->i_mmap interval tree, or
+ 	 * linkage of vma in the address_space->i_mmap_nonlinear list.
++	 *
++	 * For private anonymous mappings, a pointer to a null terminated string
++	 * in the user process containing the name given to the vma, or NULL
++	 * if unnamed.
+ 	 */
+ 	union {
+ 		struct {
+@@ -281,6 +285,7 @@ struct vm_area_struct {
+ 			unsigned long rb_subtree_last;
+ 		} linear;
+ 		struct list_head nonlinear;
++		const char __user *anon_name;
+ 	} shared;
+ 
+ 	/*
+@@ -525,4 +530,13 @@ enum tlb_flush_reason {
+ 	NR_TLB_FLUSH_REASONS,
+ };
+ 
++/* Return the name for an anonymous mapping or NULL for a file-backed mapping */
++static inline const char __user *vma_get_anon_name(struct vm_area_struct *vma)
++{
++	if (vma->vm_file)
++		return NULL;
++
++	return vma->shared.anon_name;
++}
++
+ #endif /* _LINUX_MM_TYPES_H */
+diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
+index b0692d2..b21b868 100644
+--- a/include/linux/mmc/card.h
++++ b/include/linux/mmc/card.h
+@@ -306,6 +306,7 @@ struct mmc_card {
+ 	struct dentry		*debugfs_root;
+ 	struct mmc_part	part[MMC_NUM_PHY_PARTITION]; /* physical partitions */
+ 	unsigned int    nr_parts;
++	u32			c_ssr[16];
+ };
+ 
+ /*
+diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
+index f206e29..23d66ba 100644
+--- a/include/linux/mmc/core.h
++++ b/include/linux/mmc/core.h
+@@ -40,6 +40,9 @@ struct mmc_command {
+ #define MMC_RSP_SPI_B4	(1 << 9)		/* four data bytes */
+ #define MMC_RSP_SPI_BUSY (1 << 10)		/* card may send busy */
+ 
++#define MMC_CMD_NON_BLOCKING	(1 << 11)	/* non-blocking cmd flag */
++#define MMC_CMD_TYPE_RW		(1 << 12)	/* general R/W cmd type */
++
+ /*
+  * These are the native response types, and correspond to valid bit
+  * patterns of the above flags.  One additional valid pattern
+@@ -135,6 +138,7 @@ struct mmc_request {
+ 	struct completion	completion;
+ 	void			(*done)(struct mmc_request *);/* completion function */
+ 	struct mmc_host		*host;
++	unsigned int		wr_pos;
+ };
+ 
+ struct mmc_card;
+@@ -154,7 +158,10 @@ extern void mmc_start_bkops(struct mmc_card *card, bool from_exception);
+ extern int __mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int, bool,
+ 			bool, bool);
+ extern int mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int);
++extern int mmc_send_tuning(struct mmc_host *host, u32 opcode, int *cmd_error);
+ extern int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd);
++extern int mmc_send_dll_tuning(struct mmc_host *host);
++extern int __mmc_start_data_req(struct mmc_host *, struct mmc_request *);
+ 
+ #define MMC_ERASE_ARG		0x00000000
+ #define MMC_SECURE_ERASE_ARG	0x80000000
+@@ -184,6 +191,8 @@ extern int mmc_hw_reset(struct mmc_host *host);
+ extern int mmc_hw_reset_check(struct mmc_host *host);
+ extern int mmc_can_reset(struct mmc_card *card);
+ 
++extern int mmc_sw_reset(struct mmc_host *host);
++
+ extern void mmc_set_data_timeout(struct mmc_data *, const struct mmc_card *);
+ extern unsigned int mmc_align_data_size(struct mmc_card *, unsigned int);
+ 
+diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
+index df0c153..46d5465 100644
+--- a/include/linux/mmc/host.h
++++ b/include/linux/mmc/host.h
+@@ -119,6 +119,7 @@ struct mmc_host_ops {
+ 	 *   or a negative errno value when something bad happened
+ 	 */
+ 	void	(*set_ios)(struct mmc_host *host, struct mmc_ios *ios);
++	unsigned int	(*get_rd)(struct mmc_host *host);
+ 	int	(*get_ro)(struct mmc_host *host);
+ 	int	(*get_cd)(struct mmc_host *host);
+ 
+@@ -139,6 +140,7 @@ struct mmc_host_ops {
+ 	int	(*prepare_hs400_tuning)(struct mmc_host *host, struct mmc_ios *ios);
+ 	int	(*select_drive_strength)(unsigned int max_dtr, int host_drv, int card_drv);
+ 	void	(*hw_reset)(struct mmc_host *host);
++	void	(*sw_reset)(struct mmc_host *host);
+ 	void	(*card_event)(struct mmc_host *host);
+ 
+ 	/*
+@@ -147,6 +149,7 @@ struct mmc_host_ops {
+ 	 */
+ 	int	(*multi_io_quirk)(struct mmc_card *card,
+ 				  unsigned int direction, int blk_size);
++	int	(*card_info_save)(struct mmc_host *host);
+ };
+ 
+ struct mmc_card;
+@@ -375,6 +378,17 @@ struct mmc_host {
+ 	int			dsr_req;	/* DSR value is valid */
+ 	u32			dsr;	/* optional driver stage (DSR) value */
+ 
++#ifdef CONFIG_MMC_EMBEDDED_SDIO
++	struct {
++		struct sdio_cis			*cis;
++		struct sdio_cccr		*cccr;
++		struct sdio_embedded_func	*funcs;
++		int				num_funcs;
++	} embedded_sdio_data;
++#endif
++#define MMC_HOST_OK		(0<<0)
++#define MMC_HOST_ERR		(1<<0)
++	u32			status;
+ 	unsigned long		private[0] ____cacheline_aligned;
+ };
+ 
+@@ -384,6 +398,14 @@ void mmc_remove_host(struct mmc_host *);
+ void mmc_free_host(struct mmc_host *);
+ int mmc_of_parse(struct mmc_host *host);
+ 
++#ifdef CONFIG_MMC_EMBEDDED_SDIO
++extern void mmc_set_embedded_sdio_data(struct mmc_host *host,
++				       struct sdio_cis *cis,
++				       struct sdio_cccr *cccr,
++				       struct sdio_embedded_func *funcs,
++				       int num_funcs);
++#endif
++
+ static inline void *mmc_priv(struct mmc_host *host)
+ {
+ 	return (void *)host->private;
+diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
+index 1cd00b3..469577a 100644
+--- a/include/linux/mmc/mmc.h
++++ b/include/linux/mmc/mmc.h
+@@ -24,6 +24,16 @@
+ #ifndef LINUX_MMC_MMC_H
+ #define LINUX_MMC_MMC_H
+ 
++#define MMC_DEBUG_LEVEL 5
++
++/* mmc block debug info */
++#define mmc_trace(level, msg...) do { \
++		if (level >= MMC_DEBUG_LEVEL) { \
++					printk(msg); \
++					printk("\n"); \
++				} \
++} while (0)
++
+ /* Standard MMC commands (4.1)           type  argument     response */
+    /* class 1 */
+ #define MMC_GO_IDLE_STATE         0   /* bc                          */
+@@ -53,11 +63,6 @@
+ #define MMC_SEND_TUNING_BLOCK    19   /* adtc                    R1  */
+ #define MMC_SEND_TUNING_BLOCK_HS200	21	/* adtc R1  */
+ 
+-#define MMC_TUNING_BLK_PATTERN_4BIT_SIZE	 64
+-#define MMC_TUNING_BLK_PATTERN_8BIT_SIZE	128
+-extern const u8 tuning_blk_pattern_4bit[MMC_TUNING_BLK_PATTERN_4BIT_SIZE];
+-extern const u8 tuning_blk_pattern_8bit[MMC_TUNING_BLK_PATTERN_8BIT_SIZE];
+-
+   /* class 3 */
+ #define MMC_WRITE_DAT_UNTIL_STOP 20   /* adtc [31:0] data addr   R1  */
+ 
+diff --git a/include/linux/mmc/pm.h b/include/linux/mmc/pm.h
+index 4a13920..6e2d6a1 100644
+--- a/include/linux/mmc/pm.h
++++ b/include/linux/mmc/pm.h
+@@ -26,5 +26,6 @@ typedef unsigned int mmc_pm_flag_t;
+ 
+ #define MMC_PM_KEEP_POWER	(1 << 0)	/* preserve card power during suspend */
+ #define MMC_PM_WAKE_SDIO_IRQ	(1 << 1)	/* wake up host system on SDIO IRQ assertion */
++#define MMC_PM_IGNORE_PM_NOTIFY	(1 << 2)	/* ignore mmc pm notify */
+ 
+ #endif /* LINUX_MMC_PM_H */
+diff --git a/include/linux/mmc/sdio_func.h b/include/linux/mmc/sdio_func.h
+old mode 100644
+new mode 100755
+index 50f0bc9..dc680c4
+--- a/include/linux/mmc/sdio_func.h
++++ b/include/linux/mmc/sdio_func.h
+@@ -23,6 +23,14 @@ struct sdio_func;
+ typedef void (sdio_irq_handler_t)(struct sdio_func *);
+ 
+ /*
++ * Structure used to hold embedded SDIO device data from platform layer
++ */
++struct sdio_embedded_func {
++	uint8_t f_class;
++	uint32_t f_maxblksize;
++};
++
++/*
+  * SDIO function CIS tuple (unknown to the core)
+  */
+ struct sdio_func_tuple {
+@@ -130,6 +138,8 @@ extern int sdio_release_irq(struct sdio_func *func);
+ extern unsigned int sdio_align_size(struct sdio_func *func, unsigned int sz);
+ 
+ extern u8 sdio_readb(struct sdio_func *func, unsigned int addr, int *err_ret);
++extern u8 sdio_readb_ext(struct sdio_func *func, unsigned int addr, int *err_ret,
++	unsigned in);
+ extern u16 sdio_readw(struct sdio_func *func, unsigned int addr, int *err_ret);
+ extern u32 sdio_readl(struct sdio_func *func, unsigned int addr, int *err_ret);
+ 
+diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
+index ffe66e3..74d793f 100644
+--- a/include/linux/mmzone.h
++++ b/include/linux/mmzone.h
+@@ -374,6 +374,12 @@ struct zone {
+ 	unsigned long		min_unmapped_pages;
+ 	unsigned long		min_slab_pages;
+ #endif /* CONFIG_NUMA */
++#ifdef CONFIG_CMA_ADVANCE_SHARE
++	int has_cma;
++	int nr_try_cma;
++	int nr_try_movable;
++	int cma_wmark;
++#endif
+ 
+ 	/* zone_start_pfn == zone_start_paddr >> PAGE_SHIFT */
+ 	unsigned long		zone_start_pfn;
+@@ -886,6 +892,10 @@ static inline int is_highmem(struct zone *zone)
+ struct ctl_table;
+ int min_free_kbytes_sysctl_handler(struct ctl_table *, int,
+ 					void __user *, size_t *, loff_t *);
++#ifdef CONFIG_CMA_ADVANCE_SHARE
++int cma_watermark_sysctl_handler(struct ctl_table *table, int write,
++			void __user *buffer, size_t *length, loff_t *ppos);
++#endif
+ extern int sysctl_lowmem_reserve_ratio[MAX_NR_ZONES-1];
+ int lowmem_reserve_ratio_sysctl_handler(struct ctl_table *, int,
+ 					void __user *, size_t *, loff_t *);
+diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
+index 031ff3a..db0430d 100644
+--- a/include/linux/mtd/mtd.h
++++ b/include/linux/mtd/mtd.h
+@@ -382,7 +382,6 @@ extern void __put_mtd_device(struct mtd_info *mtd);
+ extern struct mtd_info *get_mtd_device_nm(const char *name);
+ extern void put_mtd_device(struct mtd_info *mtd);
+ 
+-
+ struct mtd_notifier {
+ 	void (*add)(struct mtd_info *mtd);
+ 	void (*remove)(struct mtd_info *mtd);
+diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
+index e4d451e..08be617 100644
+--- a/include/linux/mtd/nand.h
++++ b/include/linux/mtd/nand.h
+@@ -78,6 +78,7 @@ extern int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
+ #define NAND_CMD_READOOB	0x50
+ #define NAND_CMD_ERASE1		0x60
+ #define NAND_CMD_STATUS		0x70
++#define NAND_CMD_STATUS_MULTI	0x71
+ #define NAND_CMD_SEQIN		0x80
+ #define NAND_CMD_RNDIN		0x85
+ #define NAND_CMD_READID		0x90
+@@ -85,6 +86,7 @@ extern int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
+ #define NAND_CMD_PARAM		0xec
+ #define NAND_CMD_GET_FEATURES	0xee
+ #define NAND_CMD_SET_FEATURES	0xef
++#define NAND_CMD_SYNC_RESET	0xfc
+ #define NAND_CMD_RESET		0xff
+ 
+ #define NAND_CMD_LOCK		0x2a
+@@ -135,6 +137,8 @@ typedef enum {
+  * Option constants for bizarre disfunctionality and real
+  * features.
+  */
++/* Chip can not auto increment pages */
++#define NAND_NO_AUTOINCR	0x00000001
+ /* Buswidth is 16 bit */
+ #define NAND_BUSWIDTH_16	0x00000002
+ /* Chip has cache program function */
+@@ -715,14 +719,20 @@ struct nand_chip {
+ #define NAND_MFR_FUJITSU	0x04
+ #define NAND_MFR_NATIONAL	0x8f
+ #define NAND_MFR_RENESAS	0x07
+-#define NAND_MFR_STMICRO	0x20
++#define NAND_MFR_ST_MICRO	0x20
+ #define NAND_MFR_HYNIX		0xad
+ #define NAND_MFR_MICRON		0x2c
+ #define NAND_MFR_AMD		0x01
+-#define NAND_MFR_MACRONIX	0xc2
++#define NAND_MFR_GD_ESMT	0xc8
+ #define NAND_MFR_EON		0x92
++#define NAND_MFR_WINBOND	0xef
++#define NAND_MFR_ATO		0x9b
++#define NAND_MFR_MXIC		0xc2
++#define NAND_MFR_ALL_FLASH	0xc1
++#define NAND_MFR_PARAGON	0xa1
+ #define NAND_MFR_SANDISK	0x45
+ #define NAND_MFR_INTEL		0x89
++#define NAND_MFR_HEYANGTEK	0xc9
+ 
+ /* The maximum expected count of bytes in the NAND ID sequence */
+ #define NAND_MAX_ID_LEN 8
+diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
+index 046a0a2..e2d0a59 100644
+--- a/include/linux/mtd/spi-nor.h
++++ b/include/linux/mtd/spi-nor.h
+@@ -10,6 +10,61 @@
+ #ifndef __LINUX_MTD_SPI_NOR_H
+ #define __LINUX_MTD_SPI_NOR_H
+ 
++#include <linux/bitops.h>
++#include <linux/mtd/cfi.h>
++
++/*
++ * Manufacturer IDs
++ *
++ * The first byte returned from the flash after sending opcode SPINOR_OP_RDID.
++ * Sometimes these are the same as CFI IDs, but sometimes they aren't.
++ */
++#define SNOR_MFR_ATMEL		CFI_MFR_ATMEL
++#define SNOR_MFR_INTEL		CFI_MFR_INTEL
++#define SNOR_MFR_MICRON		CFI_MFR_ST /* ST Micro <--> Micron */
++#define SNOR_MFR_MACRONIX	CFI_MFR_MACRONIX
++#define SNOR_MFR_SPANSION	CFI_MFR_AMD
++#define SNOR_MFR_SST		CFI_MFR_SST
++#define SNOR_MFR_EON		CFI_MFR_EON
++#define SNOR_MFR_WINBOND	0xef
++#define SNOR_MFR_ESMT		0x8c
++#define SNOR_MFR_GD		0xc8
++
++/* Flash set the RESET# from */
++#define SPI_NOR_SR_RST_MASK	BIT(7)
++#define SPI_NOR_GET_RST(val)	(((val) & SPI_NOR_SR_RST_MASK) >> 7)
++#define SPI_NOR_SET_RST(val)    ((val) | SPI_NOR_SR_RST_MASK)
++
++/* Flash block protect */
++#ifdef CONFIG_HISI_SPI_BLOCK_PROTECT
++#define _2M				(0x200000UL)
++#define _4M				(0x400000UL)
++#define _8M				(0x800000UL)
++#define _16M				(0x1000000UL)
++#define _32M				(0x2000000UL)
++
++#define BP_NUM_3                        3
++#define BP_NUM_4                        4
++
++#define DEBUG_SPI_NOR_BP	0
++
++#define SPI_NOR_SR_SRWD_SHIFT	7
++#define SPI_NOR_SR_SRWD_MASK	(1 << SPI_NOR_SR_SRWD_SHIFT)
++
++#define SPI_NOR_SR_BP0_SHIFT    2
++#define SPI_NOR_SR_BP_WIDTH_4   0xf
++#define SPI_NOR_SR_BP_MASK_4    (SPI_NOR_SR_BP_WIDTH_4 << SPI_NOR_SR_BP0_SHIFT)
++
++#define SPI_NOR_SR_BP_WIDTH_3   0x7
++#define SPI_NOR_SR_BP_MASK_3    (SPI_NOR_SR_BP_WIDTH_3 << SPI_NOR_SR_BP0_SHIFT)
++
++#define SPI_NOR_SR_TB_SHIFT	3
++#define SPI_NOR_SR_TB_MASK	(1 << SPI_NOR_SR_TB_SHIFT)
++
++#define LOCK_LEVEL_MAX(bp_num)	(((0x01) << bp_num) - 1)
++
++#endif /* CONFIG_SPI_BLOCK_PROTECT */
++
+ /*
+  * Note on opcode nomenclature: some opcodes have a format like
+  * SPINOR_OP_FUNCTION{4,}_x_y_z. The numbers x, y, and z stand for the number
+@@ -21,27 +76,42 @@
+ /* Flash opcodes. */
+ #define SPINOR_OP_WREN		0x06	/* Write enable */
+ #define SPINOR_OP_RDSR		0x05	/* Read status register */
++#define SPINOR_OP_RDSR2		0x35    /* Read Status Register-2 */
++#define SPINOR_OP_RDSR3		0x15    /* Read Status Register-3 */
+ #define SPINOR_OP_WRSR		0x01	/* Write status register 1 byte */
++#define SPINOR_OP_WRSR2		0x31    /* Write Status Register-2 1 byte*/
++#define SPINOR_OP_WRSR3		0x11    /* Write Status Register-3 1 byte*/
+ #define SPINOR_OP_READ		0x03	/* Read data bytes (low frequency) */
+ #define SPINOR_OP_READ_FAST	0x0b	/* Read data bytes (high frequency) */
+-#define SPINOR_OP_READ_1_1_2	0x3b	/* Read data bytes (Dual SPI) */
+-#define SPINOR_OP_READ_1_1_4	0x6b	/* Read data bytes (Quad SPI) */
++#define SPINOR_OP_READ_1_1_2	0x3b	/* Read data bytes (Dual Output SPI) */
++#define SPINOR_OP_READ_1_2_2	0xbb	/* Read data bytes (Dual I/O SPI) */
++#define SPINOR_OP_READ_1_1_4	0x6b	/* Read data bytes (Quad Output SPI) */
++#define SPINOR_OP_READ_1_4_4	0xeb	/* Read data bytes (Quad I/O SPI) */
+ #define SPINOR_OP_PP		0x02	/* Page program (up to 256 bytes) */
++#define SPINOR_OP_PP_1_1_4	0x32	/* Quad page program */
++#define SPINOR_OP_PP_1_4_4	0x38	/* Quad page program */
+ #define SPINOR_OP_BE_4K		0x20	/* Erase 4KiB block */
+ #define SPINOR_OP_BE_4K_PMC	0xd7	/* Erase 4KiB block on PMC chips */
+ #define SPINOR_OP_BE_32K	0x52	/* Erase 32KiB block */
+ #define SPINOR_OP_CHIP_ERASE	0xc7	/* Erase whole flash chip */
+ #define SPINOR_OP_SE		0xd8	/* Sector erase (usually 64KiB) */
+ #define SPINOR_OP_RDID		0x9f	/* Read JEDEC ID */
++#define SPINOR_OP_RDSFDP	0x5a	/* Read SFDP */
+ #define SPINOR_OP_RDCR		0x35	/* Read configuration register */
+ #define SPINOR_OP_RDFSR		0x70	/* Read flag status register */
+ 
+ /* 4-byte address opcodes - used on Spansion and some Macronix flashes. */
+-#define SPINOR_OP_READ4		0x13	/* Read data bytes (low frequency) */
+-#define SPINOR_OP_READ4_FAST	0x0c	/* Read data bytes (high frequency) */
+-#define SPINOR_OP_READ4_1_1_2	0x3c	/* Read data bytes (Dual SPI) */
+-#define SPINOR_OP_READ4_1_1_4	0x6c	/* Read data bytes (Quad SPI) */
++#define SPINOR_OP_READ_4B	0x13	/* Read data bytes (low frequency) */
++#define SPINOR_OP_READ_FAST_4B	0x0c	/* Read data bytes (high frequency) */
++#define SPINOR_OP_READ_1_1_2_4B	0x3c	/* Read data bytes (Dual Output SPI) */
++#define SPINOR_OP_READ_1_2_2_4B	0xbc	/* Read data bytes (Dual I/O SPI) */
++#define SPINOR_OP_READ_1_1_4_4B	0x6c	/* Read data bytes (Quad Output SPI) */
++#define SPINOR_OP_READ_1_4_4_4B	0xec	/* Read data bytes (Quad I/O SPI) */
+ #define SPINOR_OP_PP_4B		0x12	/* Page program (up to 256 bytes) */
++#define SPINOR_OP_PP_1_1_4_4B	0x34	/* Quad page program */
++#define SPINOR_OP_PP_1_4_4_4B	0x3e	/* Quad page program */
++#define SPINOR_OP_BE_4K_4B	0x21	/* Erase 4KiB block */
++#define SPINOR_OP_BE_32K_4B	0x5c	/* Erase 32KiB block */
+ #define SPINOR_OP_SE_4B		0xdc	/* Sector erase (usually 64KiB) */
+ 
+ /* Used for SST flashes only. */
+@@ -54,57 +124,141 @@
+ #define SPINOR_OP_EX4B		0xe9	/* Exit 4-byte mode */
+ 
+ /* Used for Spansion flashes only. */
++#define SPINOR_OP_BRRD		0x16	/* Bank register write */
+ #define SPINOR_OP_BRWR		0x17	/* Bank register write */
+ 
++/* Used for GigaDevice flashes only. */
++#define SPINOR_OP_WRCR		0x31	/* Config register write */
++
++/* Used for Micron flashes only. */
++#define SPINOR_OP_RD_EVCR      0x65    /* Read EVCR register */
++#define SPINOR_OP_WD_EVCR      0x61    /* Write EVCR register */
++
++/* Software reset code */
++#define SPINOR_ENABLE_RESET	0x66	/* Enable reset */
++#define SPINOR_OP_RESET		0x99	/* Reset */
++
+ /* Status Register bits. */
+-#define SR_WIP			1	/* Write in progress */
+-#define SR_WEL			2	/* Write enable latch */
++#define SR_WIP			BIT(0)	/* Write in progress */
++#define SR_WEL			BIT(1)	/* Write enable latch */
+ /* meaning of other SR_* bits may differ between vendors */
+-#define SR_BP0			4	/* Block protect 0 */
+-#define SR_BP1			8	/* Block protect 1 */
+-#define SR_BP2			0x10	/* Block protect 2 */
+-#define SR_SRWD			0x80	/* SR write protect */
++#define SR_BP0			BIT(2)	/* Block protect 0 */
++#define SR_BP1			BIT(3)	/* Block protect 1 */
++#define SR_BP2			BIT(4)	/* Block protect 2 */
++#define SR_TB			BIT(5)	/* Top/Bottom protect */
++#define SR_SRWD			BIT(7)	/* SR write protect */
++
++#define SR_QUAD_EN_MX		BIT(6)	/* Macronix Quad I/O */
+ 
+-#define SR_QUAD_EN_MX		0x40	/* Macronix Quad I/O */
++/* Enhanced Volatile Configuration Register bits */
++#define EVCR_DUAL_EN_MICRON	BIT(6)	/* Micron Dual I/O */
++#define EVCR_QUAD_EN_MICRON	BIT(7)	/* Micron Quad I/O */
+ 
+ /* Flag Status Register bits */
+-#define FSR_READY		0x80
++#define FSR_READY		BIT(7)
+ 
+ /* Configuration Register bits. */
+-#define CR_QUAD_EN_SPAN		0x2	/* Spansion Quad I/O */
++#define CR_QUAD_EN_SPAN		BIT(1)	/* Spansion Quad I/O */
+ 
+-enum read_mode {
+-	SPI_NOR_NORMAL = 0,
+-	SPI_NOR_FAST,
+-	SPI_NOR_DUAL,
+-	SPI_NOR_QUAD,
++/* Supported modes */
++enum spi_nor_mode_index {
++	/* Sorted by ascending priority order */
++	SNOR_MIDX_SLOW = 0,
++	SNOR_MIDX_1_1_1,
++	SNOR_MIDX_1_1_2,
++	SNOR_MIDX_1_2_2,
++	SNOR_MIDX_1_1_4,
++	SNOR_MIDX_1_4_4,
++
++	SNOR_MIDX_MAX
+ };
+ 
+-/**
+- * struct spi_nor_xfer_cfg - Structure for defining a Serial Flash transfer
+- * @wren:		command for "Write Enable", or 0x00 for not required
+- * @cmd:		command for operation
+- * @cmd_pins:		number of pins to send @cmd (1, 2, 4)
+- * @addr:		address for operation
+- * @addr_pins:		number of pins to send @addr (1, 2, 4)
+- * @addr_width:		number of address bytes
+- *			(3,4, or 0 for address not required)
+- * @mode:		mode data
+- * @mode_pins:		number of pins to send @mode (1, 2, 4)
+- * @mode_cycles:	number of mode cycles (0 for mode not required)
+- * @dummy_cycles:	number of dummy cycles (0 for dummy not required)
+- */
+-struct spi_nor_xfer_cfg {
+-	u8		wren;
+-	u8		cmd;
+-	u8		cmd_pins;
+-	u32		addr;
+-	u8		addr_pins;
+-	u8		addr_width;
+-	u8		mode;
+-	u8		mode_pins;
+-	u8		mode_cycles;
+-	u8		dummy_cycles;
++#define SNOR_MODE_SLOW		BIT(SNOR_MIDX_SLOW)
++#define SNOR_MODE_1_1_1		BIT(SNOR_MIDX_1_1_1)
++#define SNOR_MODE_1_1_2		BIT(SNOR_MIDX_1_1_2)
++#define SNOR_MODE_1_2_2		BIT(SNOR_MIDX_1_2_2)
++#define SNOR_MODE_1_1_4		BIT(SNOR_MIDX_1_1_4)
++#define SNOR_MODE_1_4_4		BIT(SNOR_MIDX_1_4_4)
++
++struct spi_nor_modes {
++	u32	rd_modes;	/* supported SPI modes for (Fast) Read */
++	u32	wr_modes;	/* supported SPI modes for Page Program */
++};
++
++struct spi_nor_read_op {
++	u8	num_mode_clocks;
++	u8	num_wait_states;
++	u8	opcode;
++};
++
++#define SNOR_OP_READ(_num_mode_clocks, _num_wait_states, _opcode) \
++	{							  \
++		.num_mode_clocks = _num_mode_clocks,		  \
++		.num_wait_states = _num_wait_states,		  \
++		.opcode = _opcode,				  \
++	}
++
++struct spi_nor_erase_type {
++	u8	size;	/* specifies 'N' so erase size = 2^N */
++	u8	opcode;
++};
++
++#define SNOR_OP_ERASE(_size, _opcode) { .size = _size, .opcode = _opcode }
++#define SNOR_OP_ERASE_64K(_opcode) SNOR_OP_ERASE(0x10, _opcode)
++#define SNOR_OP_ERASE_32K(_opcode) SNOR_OP_ERASE(0x0f, _opcode)
++#define SNOR_OP_ERASE_4K(_opcode)  SNOR_OP_ERASE(0x0c, _opcode)
++
++struct spi_nor;
++
++#define SNOR_MAX_ERASE_TYPES	4
++
++struct spi_nor_basic_flash_parameter {
++	/* Fast Read settings */
++	u32				rd_modes;
++	struct spi_nor_read_op		reads[SNOR_MIDX_MAX];
++
++	/* Page Program settings */
++	u32				wr_modes;
++	u8				page_programs[SNOR_MIDX_MAX];
++
++	/* Sector Erase settings */
++	struct spi_nor_erase_type	erase_types[SNOR_MAX_ERASE_TYPES];
++
++	int (*enable_quad_io)(struct spi_nor *nor);
++};
++
++#define SNOR_PROTO_CODE_OFF	8
++#define SNOR_PROTO_CODE_MASK	GENMASK(11, 8)
++#define SNOR_PROTO_CODE_TO_PROTO(code) \
++	(((code) << SNOR_PROTO_CODE_OFF) & SNOR_PROTO_CODE_MASK)
++#define SNOR_PROTO_CODE_FROM_PROTO(proto) \
++	((((u32)(proto)) & SNOR_PROTO_CODE_MASK) >> SNOR_PROTO_CODE_OFF)
++
++#define SNOR_PROTO_ADDR_OFF	4
++#define SNOR_PROTO_ADDR_MASK	GENMASK(7, 4)
++#define SNOR_PROTO_ADDR_TO_PROTO(addr) \
++	(((addr) << SNOR_PROTO_ADDR_OFF) & SNOR_PROTO_ADDR_MASK)
++#define SNOR_PROTO_ADDR_FROM_PROTO(proto) \
++	((((u32)(proto)) & SNOR_PROTO_ADDR_MASK) >> SNOR_PROTO_ADDR_OFF)
++
++#define SNOR_PROTO_DATA_OFF	0
++#define SNOR_PROTO_DATA_MASK	GENMASK(3, 0)
++#define SNOR_PROTO_DATA_TO_PROTO(data) \
++	(((data) << SNOR_PROTO_DATA_OFF) & SNOR_PROTO_DATA_MASK)
++#define SNOR_PROTO_DATA_FROM_PROTO(proto) \
++	((((u32)(proto)) & SNOR_PROTO_DATA_MASK) >> SNOR_PROTO_DATA_OFF)
++
++#define SNOR_PROTO(code, addr, data)	  \
++	(SNOR_PROTO_CODE_TO_PROTO(code) |   \
++	 SNOR_PROTO_ADDR_TO_PROTO(addr) | \
++	 SNOR_PROTO_DATA_TO_PROTO(data))
++
++enum spi_nor_protocol {
++	SNOR_PROTO_1_1_1 = SNOR_PROTO(1, 1, 1),	/* SPI */
++	SNOR_PROTO_1_1_2 = SNOR_PROTO(1, 1, 2),	/* Dual Output */
++	SNOR_PROTO_1_2_2 = SNOR_PROTO(1, 2, 2),	/* Dual IO */
++	SNOR_PROTO_1_1_4 = SNOR_PROTO(1, 1, 4),	/* Quad Output */
++	SNOR_PROTO_1_4_4 = SNOR_PROTO(1, 4, 4),	/* Quad IO */
+ };
+ 
+ #define SPI_NOR_MAX_CMD_SIZE	8
+@@ -116,64 +270,71 @@ enum spi_nor_ops {
+ 	SPI_NOR_OPS_UNLOCK,
+ };
+ 
++enum spi_nor_option_flags {
++	SNOR_F_USE_FSR		= BIT(0),
++	SNOR_F_HAS_SR_TB	= BIT(1),
++};
++
++struct mtd_info;
++
+ /**
+  * struct spi_nor - Structure for defining a the SPI NOR layer
+  * @mtd:		point to a mtd_info structure
+  * @lock:		the lock for the read/write/erase/lock/unlock operations
+  * @dev:		point to a spi device, or a spi nor controller device.
++ * @flash_node:		point to a device node describing this flash instance.
+  * @page_size:		the page size of the SPI NOR
+  * @addr_width:		number of address bytes
+  * @erase_opcode:	the opcode for erasing a sector
+  * @read_opcode:	the read opcode
+  * @read_dummy:		the dummy needed by the read operation
+  * @program_opcode:	the program opcode
+- * @flash_read:		the mode of the read
+  * @sst_write_second:	used by the SST write operation
+- * @cfg:		used by the read_xfer/write_xfer
++ * @flags:		flag options for the current SPI-NOR (SNOR_F_*)
++ * @erase_proto:	the SPI protocol used by erase operations
++ * @read_proto:		the SPI protocol used by read operations
++ * @write_proto:	the SPI protocol used by write operations
++ * @reg_proto		the SPI protocol used by read_reg/write_reg operations
+  * @cmd_buf:		used by the write_reg
+  * @prepare:		[OPTIONAL] do some preparations for the
+  *			read/write/erase/lock/unlock operations
+  * @unprepare:		[OPTIONAL] do some post work after the
+  *			read/write/erase/lock/unlock operations
+- * @read_xfer:		[OPTIONAL] the read fundamental primitive
+- * @write_xfer:		[OPTIONAL] the writefundamental primitive
+  * @read_reg:		[DRIVER-SPECIFIC] read out the register
+  * @write_reg:		[DRIVER-SPECIFIC] write data to the register
+- * @read_id:		[REPLACEABLE] read out the ID data, and find
+- *			the proper spi_device_id
+- * @wait_till_ready:	[REPLACEABLE] wait till the NOR becomes ready
+  * @read:		[DRIVER-SPECIFIC] read data from the SPI NOR
+  * @write:		[DRIVER-SPECIFIC] write data to the SPI NOR
+  * @erase:		[DRIVER-SPECIFIC] erase a sector of the SPI NOR
+- *			at the offset @offs
++ *			at the offset @offs; if not provided by the driver,
++ *			spi-nor will send the erase opcode via write_reg()
++ * @flash_lock:		[FLASH-SPECIFIC] lock a region of the SPI NOR
++ * @flash_unlock:	[FLASH-SPECIFIC] unlock a region of the SPI NOR
++ * @flash_is_locked:	[FLASH-SPECIFIC] check if a region of the SPI NOR is
++ *			completely locked
+  * @priv:		the private data
+  */
+ struct spi_nor {
+-	struct mtd_info		*mtd;
++	struct mtd_info		mtd;
+ 	struct mutex		lock;
+ 	struct device		*dev;
++	struct device_node	*flash_node;
+ 	u32			page_size;
+ 	u8			addr_width;
+ 	u8			erase_opcode;
+ 	u8			read_opcode;
+ 	u8			read_dummy;
+ 	u8			program_opcode;
+-	enum read_mode		flash_read;
++	enum spi_nor_protocol	erase_proto;
++	enum spi_nor_protocol	read_proto;
++	enum spi_nor_protocol	write_proto;
+ 	bool			sst_write_second;
+-	struct spi_nor_xfer_cfg	cfg;
++	u32			flags;
+ 	u8			cmd_buf[SPI_NOR_MAX_CMD_SIZE];
+ 
+ 	int (*prepare)(struct spi_nor *nor, enum spi_nor_ops ops);
+ 	void (*unprepare)(struct spi_nor *nor, enum spi_nor_ops ops);
+-	int (*read_xfer)(struct spi_nor *nor, struct spi_nor_xfer_cfg *cfg,
+-			 u8 *buf, size_t len);
+-	int (*write_xfer)(struct spi_nor *nor, struct spi_nor_xfer_cfg *cfg,
+-			  u8 *buf, size_t len);
+ 	int (*read_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len);
+-	int (*write_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len,
+-			int write_enable);
+-	const struct spi_device_id *(*read_id)(struct spi_nor *nor);
+-	int (*wait_till_ready)(struct spi_nor *nor);
++	int (*write_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len);
+ 
+ 	int (*read)(struct spi_nor *nor, loff_t from,
+ 			size_t len, size_t *retlen, u_char *read_buf);
+@@ -181,6 +342,16 @@ struct spi_nor {
+ 			size_t len, size_t *retlen, const u_char *write_buf);
+ 	int (*erase)(struct spi_nor *nor, loff_t offs);
+ 
++	int (*flash_lock)(struct spi_nor *nor, loff_t ofs, uint64_t len);
++	int (*flash_unlock)(struct spi_nor *nor, loff_t ofs, uint64_t len);
++	int (*flash_is_locked)(struct spi_nor *nor, loff_t ofs, uint64_t len);
++
++#ifdef CONFIG_HISI_SPI_BLOCK_PROTECT
++	unsigned int end_addr;
++	unsigned int lock_level_max;
++	unsigned char level;
++#endif
++	u32 clkrate;
+ 	void *priv;
+ };
+ 
+@@ -188,7 +359,7 @@ struct spi_nor {
+  * spi_nor_scan() - scan the SPI NOR
+  * @nor:	the spi_nor structure
+  * @name:	the chip type name
+- * @mode:	the read mode supported by the driver
++ * @modes:	the SPI modes supported by the controller driver
+  *
+  * The drivers can use this fuction to scan the SPI NOR.
+  * In the scanning, it will try to get all the necessary information to
+@@ -198,6 +369,12 @@ struct spi_nor {
+  *
+  * Return: 0 for success, others for failure.
+  */
+-int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode);
++int spi_nor_scan(struct spi_nor *nor, const char *name,
++		 struct spi_nor_modes *modes);
++void spi_nor_driver_shutdown(struct spi_nor *nor);
++#ifdef CONFIG_PM
++int spi_nor_suspend(struct spi_nor *nor, pm_message_t state);
++int spi_nor_resume(struct spi_nor *nor);
++#endif
+ 
+ #endif
+diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
+index c3fd34d..4d10fd1 100644
+--- a/include/linux/netdevice.h
++++ b/include/linux/netdevice.h
+@@ -1894,8 +1894,8 @@ struct napi_gro_cb {
+ 	/* Used in ipv6_gro_receive() and foo-over-udp */
+ 	u16	proto;
+ 
+-	/* Used in udp_gro_receive */
+-	u8	udp_mark:1;
++	/* Used in tunnel GRO receive */
++	u8      encap_mark:1;
+ 
+ 	/* GRO checksum is valid */
+ 	u8	csum_valid:1;
+diff --git a/include/linux/netfilter/xt_qtaguid.h b/include/linux/netfilter/xt_qtaguid.h
+new file mode 100644
+index 0000000..ca60fbd
+--- /dev/null
++++ b/include/linux/netfilter/xt_qtaguid.h
+@@ -0,0 +1,13 @@
++#ifndef _XT_QTAGUID_MATCH_H
++#define _XT_QTAGUID_MATCH_H
++
++/* For now we just replace the xt_owner.
++ * FIXME: make iptables aware of qtaguid. */
++#include <linux/netfilter/xt_owner.h>
++
++#define XT_QTAGUID_UID    XT_OWNER_UID
++#define XT_QTAGUID_GID    XT_OWNER_GID
++#define XT_QTAGUID_SOCKET XT_OWNER_SOCKET
++#define xt_qtaguid_match_info xt_owner_match_info
++
++#endif /* _XT_QTAGUID_MATCH_H */
+diff --git a/include/linux/netfilter/xt_quota2.h b/include/linux/netfilter/xt_quota2.h
+new file mode 100644
+index 0000000..eadc690
+--- /dev/null
++++ b/include/linux/netfilter/xt_quota2.h
+@@ -0,0 +1,25 @@
++#ifndef _XT_QUOTA_H
++#define _XT_QUOTA_H
++
++enum xt_quota_flags {
++	XT_QUOTA_INVERT    = 1 << 0,
++	XT_QUOTA_GROW      = 1 << 1,
++	XT_QUOTA_PACKET    = 1 << 2,
++	XT_QUOTA_NO_CHANGE = 1 << 3,
++	XT_QUOTA_MASK      = 0x0F,
++};
++
++struct xt_quota_counter;
++
++struct xt_quota_mtinfo2 {
++	char name[15];
++	u_int8_t flags;
++
++	/* Comparison-invariant */
++	aligned_u64 quota;
++
++	/* Used internally by the kernel */
++	struct xt_quota_counter *master __attribute__((aligned(8)));
++};
++
++#endif /* _XT_QUOTA_H */
+diff --git a/include/linux/nmi.h b/include/linux/nmi.h
+index 9b2022a..eeb54ae 100644
+--- a/include/linux/nmi.h
++++ b/include/linux/nmi.h
+@@ -14,8 +14,11 @@
+  * may be used to reset the timeout - for code which intentionally
+  * disables interrupts for a long time. This call is stateless.
+  */
+-#if defined(CONFIG_HAVE_NMI_WATCHDOG) || defined(CONFIG_HARDLOCKUP_DETECTOR)
++#if defined(CONFIG_HAVE_NMI_WATCHDOG) || defined(CONFIG_HARDLOCKUP_DETECTOR_NMI)
+ #include <asm/nmi.h>
++#endif
++
++#if defined(CONFIG_HAVE_NMI_WATCHDOG) || defined(CONFIG_HARDLOCKUP_DETECTOR)
+ extern void touch_nmi_watchdog(void);
+ #else
+ static inline void touch_nmi_watchdog(void)
+@@ -45,13 +48,23 @@ static inline bool watchdog_hardlockup_detector_is_enabled(void)
+ #ifdef arch_trigger_all_cpu_backtrace
+ static inline bool trigger_all_cpu_backtrace(void)
+ {
++	#if defined(CONFIG_ARM)
++	arch_trigger_all_cpu_backtrace();
++	#else
+ 	arch_trigger_all_cpu_backtrace(true);
++	#endif
+ 
+ 	return true;
+ }
+ static inline bool trigger_allbutself_cpu_backtrace(void)
+ {
++	#if defined(CONFIG_ARM)
++	arch_trigger_all_cpu_backtrace();
++	#else
+ 	arch_trigger_all_cpu_backtrace(false);
++	#endif
++
++
+ 	return true;
+ }
+ #else
+diff --git a/include/linux/of_fdt.h b/include/linux/of_fdt.h
+index 0ff360d..35feeca 100644
+--- a/include/linux/of_fdt.h
++++ b/include/linux/of_fdt.h
+@@ -57,6 +57,27 @@ extern int of_flat_dt_match(unsigned long node, const char *const *matches);
+ extern unsigned long of_get_flat_dt_root(void);
+ extern int of_get_flat_dt_size(void);
+ 
++/*
++ * early_init_dt_scan_chosen - scan the device tree for ramdisk and bootargs
++ *
++ * The boot arguments will be placed into the memory pointed to by @data.
++ * That memory should be COMMAND_LINE_SIZE big and initialized to be a valid
++ * (possibly empty) string.  Logic for what will be in @data after this
++ * function finishes:
++ *
++ * - CONFIG_CMDLINE_FORCE=true
++ *     CONFIG_CMDLINE
++ * - CONFIG_CMDLINE_EXTEND=true, @data is non-empty string
++ *     @data + dt bootargs (even if dt bootargs are empty)
++ * - CONFIG_CMDLINE_EXTEND=true, @data is empty string
++ *     CONFIG_CMDLINE + dt bootargs (even if dt bootargs are empty)
++ * - CMDLINE_FROM_BOOTLOADER=true, dt bootargs=non-empty:
++ *     dt bootargs
++ * - CMDLINE_FROM_BOOTLOADER=true, dt bootargs=empty, @data is non-empty string
++ *     @data is left unchanged
++ * - CMDLINE_FROM_BOOTLOADER=true, dt bootargs=empty, @data is empty string
++ *     CONFIG_CMDLINE (or "" if that's not defined)
++ */
+ extern int early_init_dt_scan_chosen(unsigned long node, const char *uname,
+ 				     int depth, void *data);
+ extern int early_init_dt_scan_memory(unsigned long node, const char *uname,
+diff --git a/include/linux/of_mdio.h b/include/linux/of_mdio.h
+index d449018..3c4d653 100644
+--- a/include/linux/of_mdio.h
++++ b/include/linux/of_mdio.h
+@@ -19,6 +19,9 @@ extern struct phy_device *of_phy_connect(struct net_device *dev,
+ 					 struct device_node *phy_np,
+ 					 void (*hndlr)(struct net_device *),
+ 					 u32 flags, phy_interface_t iface);
++extern struct phy_device *
++of_phy_get_and_connect(struct net_device *dev, struct device_node *np,
++		       void (*hndlr)(struct net_device *));
+ struct phy_device *of_phy_attach(struct net_device *dev,
+ 				 struct device_node *phy_np, u32 flags,
+ 				 phy_interface_t iface);
+@@ -49,6 +52,13 @@ static inline struct phy_device *of_phy_connect(struct net_device *dev,
+ 	return NULL;
+ }
+ 
++static inline struct phy_device *
++of_phy_get_and_connect(struct net_device *dev, struct device_node *np,
++		       void (*hndlr)(struct net_device *))
++{
++	return NULL;
++}
++
+ static inline struct phy_device *of_phy_attach(struct net_device *dev,
+ 					       struct device_node *phy_np,
+ 					       u32 flags, phy_interface_t iface)
+diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
+index 893a0d0..c36f339 100644
+--- a/include/linux/perf_event.h
++++ b/include/linux/perf_event.h
+@@ -455,11 +455,6 @@ struct perf_event {
+ #endif /* CONFIG_PERF_EVENTS */
+ };
+ 
+-enum perf_event_context_type {
+-	task_context,
+-	cpu_context,
+-};
+-
+ /**
+  * struct perf_event_context - event context structure
+  *
+@@ -467,7 +462,6 @@ enum perf_event_context_type {
+  */
+ struct perf_event_context {
+ 	struct pmu			*pmu;
+-	enum perf_event_context_type	type;
+ 	/*
+ 	 * Protect the states of the events in the list,
+ 	 * nr_active, and the list:
+diff --git a/include/linux/phy.h b/include/linux/phy.h
+index d090cfc..bd33e4b 100644
+--- a/include/linux/phy.h
++++ b/include/linux/phy.h
+@@ -760,6 +760,10 @@ int phy_register_fixup_for_id(const char *bus_id,
+ int phy_register_fixup_for_uid(u32 phy_uid, u32 phy_uid_mask,
+ 			       int (*run)(struct phy_device *));
+ 
++int phy_unregister_fixup(const char *bus_id, u32 phy_uid, u32 phy_uid_mask);
++int phy_unregister_fixup_for_id(const char *bus_id);
++int phy_unregister_fixup_for_uid(u32 phy_uid, u32 phy_uid_mask);
++
+ int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable);
+ int phy_get_eee_err(struct phy_device *phydev);
+ int phy_ethtool_set_eee(struct phy_device *phydev, struct ethtool_eee *data);
+diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h
+index 8cb6f81..5bf5d4c 100644
+--- a/include/linux/phy/phy.h
++++ b/include/linux/phy/phy.h
+@@ -153,6 +153,8 @@ struct phy *devm_phy_get(struct device *dev, const char *string);
+ struct phy *devm_phy_optional_get(struct device *dev, const char *string);
+ struct phy *devm_of_phy_get(struct device *dev, struct device_node *np,
+ 			    const char *con_id);
++struct phy *devm_of_phy_get_by_index(struct device *dev, struct device_node *np,
++				     int index);
+ void phy_put(struct phy *phy);
+ void devm_phy_put(struct device *dev, struct phy *phy);
+ struct phy *of_phy_get(struct device_node *np, const char *con_id);
+@@ -280,6 +282,13 @@ static inline struct phy *devm_of_phy_get(struct device *dev,
+ 	return ERR_PTR(-ENOSYS);
+ }
+ 
++static inline struct phy *devm_of_phy_get_by_index(struct device *dev,
++						   struct device_node *np,
++						   int index)
++{
++	return ERR_PTR(-ENOSYS);
++}
++
+ static inline void phy_put(struct phy *phy)
+ {
+ }
+diff --git a/include/linux/pipe_fs_i.h b/include/linux/pipe_fs_i.h
+index eb8b8ac..24f5470 100644
+--- a/include/linux/pipe_fs_i.h
++++ b/include/linux/pipe_fs_i.h
+@@ -42,6 +42,7 @@ struct pipe_buffer {
+  *	@fasync_readers: reader side fasync
+  *	@fasync_writers: writer side fasync
+  *	@bufs: the circular array of pipe buffers
++ *	@user: the user who created this pipe
+  **/
+ struct pipe_inode_info {
+ 	struct mutex mutex;
+@@ -57,6 +58,7 @@ struct pipe_inode_info {
+ 	struct fasync_struct *fasync_readers;
+ 	struct fasync_struct *fasync_writers;
+ 	struct pipe_buffer *bufs;
++	struct user_struct *user;
+ };
+ 
+ /*
+@@ -123,6 +125,8 @@ void pipe_unlock(struct pipe_inode_info *);
+ void pipe_double_lock(struct pipe_inode_info *, struct pipe_inode_info *);
+ 
+ extern unsigned int pipe_max_size, pipe_min_size;
++extern unsigned long pipe_user_pages_hard;
++extern unsigned long pipe_user_pages_soft;
+ int pipe_proc_fn(struct ctl_table *, int, void __user *, size_t *, loff_t *);
+ 
+ 
+diff --git a/include/linux/platform_data/ds2482.h b/include/linux/platform_data/ds2482.h
+new file mode 100644
+index 0000000..5a6879e
+--- /dev/null
++++ b/include/linux/platform_data/ds2482.h
+@@ -0,0 +1,21 @@
++/*
++ * Copyright (C) 2012 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#ifndef __PLATFORM_DATA_DS2482__
++#define __PLATFORM_DATA_DS2482__
++
++struct ds2482_platform_data {
++	int		slpz_gpio;
++};
++
++#endif /* __PLATFORM_DATA_DS2482__ */
+diff --git a/include/linux/poison.h b/include/linux/poison.h
+index 2110a81..253c9b4 100644
+--- a/include/linux/poison.h
++++ b/include/linux/poison.h
+@@ -19,8 +19,8 @@
+  * under normal circumstances, used to verify that nobody uses
+  * non-initialized list entries.
+  */
+-#define LIST_POISON1  ((void *) 0x00100100 + POISON_POINTER_DELTA)
+-#define LIST_POISON2  ((void *) 0x00200200 + POISON_POINTER_DELTA)
++#define LIST_POISON1  ((void *) 0x100 + POISON_POINTER_DELTA)
++#define LIST_POISON2  ((void *) 0x200 + POISON_POINTER_DELTA)
+ 
+ /********** include/linux/timer.h **********/
+ /*
+diff --git a/include/linux/posix_acl.h b/include/linux/posix_acl.h
+index 3e96a6a..d1a8ad7 100644
+--- a/include/linux/posix_acl.h
++++ b/include/linux/posix_acl.h
+@@ -95,6 +95,7 @@ extern int set_posix_acl(struct inode *, int, struct posix_acl *);
+ extern int posix_acl_chmod(struct inode *, umode_t);
+ extern int posix_acl_create(struct inode *, umode_t *, struct posix_acl **,
+ 		struct posix_acl **);
++extern int posix_acl_update_mode(struct inode *, umode_t *, struct posix_acl **);
+ 
+ extern int simple_set_acl(struct inode *, struct posix_acl *, int);
+ extern int simple_acl_create(struct inode *, struct inode *);
+diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
+index 096dbce..ec509ed 100644
+--- a/include/linux/power_supply.h
++++ b/include/linux/power_supply.h
+@@ -17,6 +17,7 @@
+ #include <linux/leds.h>
+ #include <linux/spinlock.h>
+ #include <linux/notifier.h>
++#include <linux/types.h>
+ 
+ /*
+  * All voltages, currents, charges, energies, time and temperatures in uV,
+@@ -147,6 +148,12 @@ enum power_supply_property {
+ 	POWER_SUPPLY_PROP_SCOPE,
+ 	POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT,
+ 	POWER_SUPPLY_PROP_CALIBRATE,
++	/* Local extensions */
++	POWER_SUPPLY_PROP_USB_HC,
++	POWER_SUPPLY_PROP_USB_OTG,
++	POWER_SUPPLY_PROP_CHARGE_ENABLED,
++	/* Local extensions of type int64_t */
++	POWER_SUPPLY_PROP_CHARGE_COUNTER_EXT,
+ 	/* Properties of type `const char *' */
+ 	POWER_SUPPLY_PROP_MODEL_NAME,
+ 	POWER_SUPPLY_PROP_MANUFACTURER,
+@@ -171,6 +178,7 @@ enum power_supply_notifier_events {
+ union power_supply_propval {
+ 	int intval;
+ 	const char *strval;
++	int64_t int64val;
+ };
+ 
+ struct device;
+diff --git a/include/linux/pstore.h b/include/linux/pstore.h
+index ece0c6b..8884f6e 100644
+--- a/include/linux/pstore.h
++++ b/include/linux/pstore.h
+@@ -39,6 +39,7 @@ enum pstore_type_id {
+ 	PSTORE_TYPE_PPC_RTAS	= 4,
+ 	PSTORE_TYPE_PPC_OF	= 5,
+ 	PSTORE_TYPE_PPC_COMMON	= 6,
++	PSTORE_TYPE_PMSG	= 7,
+ 	PSTORE_TYPE_UNKNOWN	= 255
+ };
+ 
+diff --git a/include/linux/pstore_ram.h b/include/linux/pstore_ram.h
+index 4af3fdc..712757f 100644
+--- a/include/linux/pstore_ram.h
++++ b/include/linux/pstore_ram.h
+@@ -68,6 +68,8 @@ void persistent_ram_free_old(struct persistent_ram_zone *prz);
+ ssize_t persistent_ram_ecc_string(struct persistent_ram_zone *prz,
+ 	char *str, size_t len);
+ 
++void ramoops_console_write_buf(const char *buf, size_t size);
++
+ /*
+  * Ramoops platform data
+  * @mem_size	memory size for ramoops
+@@ -81,6 +83,7 @@ struct ramoops_platform_data {
+ 	unsigned long	record_size;
+ 	unsigned long	console_size;
+ 	unsigned long	ftrace_size;
++	unsigned long	pmsg_size;
+ 	int		dump_oops;
+ 	struct persistent_ram_ecc_info ecc_info;
+ };
+diff --git a/include/linux/sched.h b/include/linux/sched.h
+index 5e344bb..b1bf96c 100644
+--- a/include/linux/sched.h
++++ b/include/linux/sched.h
+@@ -758,6 +758,8 @@ struct user_struct {
+ 	unsigned long mq_bytes;	/* How many bytes can be allocated to mqueue? */
+ #endif
+ 	unsigned long locked_shm; /* How many pages of mlocked shm ? */
++	unsigned long unix_inflight;	/* How many files in flight in unix sockets */
++	atomic_long_t pipe_bufs;  /* how many pages are allocated in pipe buffers */
+ 
+ #ifdef CONFIG_KEYS
+ 	struct key *uid_keyring;	/* UID specific keyring */
+@@ -1034,6 +1036,13 @@ extern void wake_up_if_idle(int cpu);
+ # define SD_INIT_NAME(type)
+ #endif
+ 
++#ifdef CONFIG_SCHED_HMP
++struct hmp_domain {
++	struct cpumask cpus;
++	struct cpumask possible_cpus;
++	struct list_head hmp_domains;
++};
++#endif /* CONFIG_SCHED_HMP */
+ #else /* CONFIG_SMP */
+ 
+ struct sched_domain_attr;
+@@ -1081,8 +1090,23 @@ struct sched_avg {
+ 	u64 last_runnable_update;
+ 	s64 decay_count;
+ 	unsigned long load_avg_contrib;
++	unsigned long load_avg_ratio;
++#ifdef CONFIG_SCHED_HMP
++	u64 hmp_last_up_migration;
++	u64 hmp_last_down_migration;
++#endif
++	u32 usage_avg_sum;
+ };
+ 
++#ifdef CONFIG_SCHED_HMP
++/*
++ * We want to avoid boosting any processes forked from init (PID 1)
++ * and kthreadd (assumed to be PID 2).
++ */
++#define hmp_task_should_forkboost(task) \
++	((task->parent && task->parent->pid > 2))
++#endif
++
+ #ifdef CONFIG_SCHEDSTATS
+ struct sched_statistics {
+ 	u64			wait_start;
+@@ -1367,6 +1391,7 @@ struct task_struct {
+ 
+ 	cputime_t utime, stime, utimescaled, stimescaled;
+ 	cputime_t gtime;
++	unsigned long long cpu_power;
+ #ifndef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
+ 	struct cputime prev_cputime;
+ #endif
+@@ -1895,6 +1920,9 @@ static inline cputime_t task_gtime(struct task_struct *t)
+ extern void task_cputime_adjusted(struct task_struct *p, cputime_t *ut, cputime_t *st);
+ extern void thread_group_cputime_adjusted(struct task_struct *p, cputime_t *ut, cputime_t *st);
+ 
++extern int task_free_register(struct notifier_block *n);
++extern int task_free_unregister(struct notifier_block *n);
++
+ /*
+  * Per process flags
+  */
+diff --git a/include/linux/security.h b/include/linux/security.h
+index ba96471..d3c02ee 100644
+--- a/include/linux/security.h
++++ b/include/linux/security.h
+@@ -1441,6 +1441,11 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
+ struct security_operations {
+ 	char name[SECURITY_NAME_MAX + 1];
+ 
++	int (*binder_set_context_mgr) (struct task_struct *mgr);
++	int (*binder_transaction) (struct task_struct *from, struct task_struct *to);
++	int (*binder_transfer_binder) (struct task_struct *from, struct task_struct *to);
++	int (*binder_transfer_file) (struct task_struct *from, struct task_struct *to, struct file *file);
++
+ 	int (*ptrace_access_check) (struct task_struct *child, unsigned int mode);
+ 	int (*ptrace_traceme) (struct task_struct *parent);
+ 	int (*capget) (struct task_struct *target,
+@@ -1739,6 +1744,10 @@ extern void __init security_fixup_ops(struct security_operations *ops);
+ 
+ 
+ /* Security operations */
++int security_binder_set_context_mgr(struct task_struct *mgr);
++int security_binder_transaction(struct task_struct *from, struct task_struct *to);
++int security_binder_transfer_binder(struct task_struct *from, struct task_struct *to);
++int security_binder_transfer_file(struct task_struct *from, struct task_struct *to, struct file *file);
+ int security_ptrace_access_check(struct task_struct *child, unsigned int mode);
+ int security_ptrace_traceme(struct task_struct *parent);
+ int security_capget(struct task_struct *target,
+@@ -1927,6 +1936,26 @@ static inline int security_init(void)
+ 	return 0;
+ }
+ 
++static inline int security_binder_set_context_mgr(struct task_struct *mgr)
++{
++	return 0;
++}
++
++static inline int security_binder_transaction(struct task_struct *from, struct task_struct *to)
++{
++	return 0;
++}
++
++static inline int security_binder_transfer_binder(struct task_struct *from, struct task_struct *to)
++{
++	return 0;
++}
++
++static inline int security_binder_transfer_file(struct task_struct *from, struct task_struct *to, struct file *file)
++{
++	return 0;
++}
++
+ static inline int security_ptrace_access_check(struct task_struct *child,
+ 					     unsigned int mode)
+ {
+diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
+index 21c2e05..219b6a3 100644
+--- a/include/linux/serial_core.h
++++ b/include/linux/serial_core.h
+@@ -66,6 +66,7 @@ struct uart_ops {
+ 	void		(*set_ldisc)(struct uart_port *, int new);
+ 	void		(*pm)(struct uart_port *, unsigned int state,
+ 			      unsigned int oldstate);
++	void		(*wake_peer)(struct uart_port *);
+ 
+ 	/*
+ 	 * Return a string describing the type of the port
+diff --git a/include/linux/slab.h b/include/linux/slab.h
+index c265bec..f7d4ab5 100644
+--- a/include/linux/slab.h
++++ b/include/linux/slab.h
+@@ -86,6 +86,11 @@
+ #else
+ # define SLAB_FAILSLAB		0x00000000UL
+ #endif
++#if defined(CONFIG_MEMCG) && !defined(CONFIG_SLOB)
++# define SLAB_ACCOUNT		0x04000000UL	/* Account to memcg */
++#else
++# define SLAB_ACCOUNT		0x00000000UL
++#endif
+ 
+ /* The following flags affect the page allocator grouping pages by mobility */
+ #define SLAB_RECLAIM_ACCOUNT	0x00020000UL		/* Objects are reclaimable */
+diff --git a/include/linux/suspend.h b/include/linux/suspend.h
+index 3388c1b..28d140d 100644
+--- a/include/linux/suspend.h
++++ b/include/linux/suspend.h
+@@ -321,6 +321,14 @@ static inline void __init register_nosave_region_late(unsigned long b, unsigned
+ {
+ 	__register_nosave_region(b, e, 1);
+ }
++#ifdef	CONFIG_HISI_SNAPSHOT_BOOT
++/*snapshot boot add*/
++extern void *register_save_region(unsigned long start_pfn, unsigned long);
++extern void unregister_save_region(void *);
++extern void *register_nosave_region_runtime(unsigned long start_pfn,
++		unsigned long);
++extern void unregister_nosave_region_runtime(void *);
++#endif
+ extern int swsusp_page_is_forbidden(struct page *);
+ extern void swsusp_set_page_free(struct page *);
+ extern void swsusp_unset_page_free(struct page *);
+@@ -338,7 +346,20 @@ static inline void register_nosave_region_late(unsigned long b, unsigned long e)
+ static inline int swsusp_page_is_forbidden(struct page *p) { return 0; }
+ static inline void swsusp_set_page_free(struct page *p) {}
+ static inline void swsusp_unset_page_free(struct page *p) {}
+-
++#ifdef	CONFIG_HISI_SNAPSHOT_BOOT
++/*snapshot boot add*/
++static inline void *register_save_region(unsigned long b, unsigned long e)
++{
++	return NULL;
++}
++static inline void unregister_save_region(void *mem) {}
++static inline void *register_nosave_region_runtime(unsigned long b,
++		unsigned long e)
++{
++	return NULL;
++}
++static inline void unregister_nosave_region_runtime(void *mem) {}
++#endif
+ static inline void hibernation_set_ops(const struct platform_hibernation_ops *ops) {}
+ static inline int hibernate(void) { return -ENOSYS; }
+ static inline bool system_entering_hibernation(void) { return false; }
+@@ -352,7 +373,13 @@ static inline bool hibernation_available(void) { return false; }
+ #define PM_POST_SUSPEND		0x0004 /* Suspend finished */
+ #define PM_RESTORE_PREPARE	0x0005 /* Going to restore a saved image */
+ #define PM_POST_RESTORE		0x0006 /* Restore failed */
+-
++#ifdef	CONFIG_HISI_SNAPSHOT_BOOT
++/*snapshot boot add*/
++#define PM_POST_FREEZE_PROCESS   0x0101
++#define PM_THAW_PROCESS_PREPARE  0x0102
++#define PM_POST_DEVICE_SUSPEND   0x0103
++#define PM_RESUME_DEVICE_PREPARE 0x0104
++#endif
+ extern struct mutex pm_mutex;
+ 
+ #ifdef CONFIG_PM_SLEEP
+@@ -379,6 +406,7 @@ extern bool pm_get_wakeup_count(unsigned int *count, bool block);
+ extern bool pm_save_wakeup_count(unsigned int count);
+ extern void pm_wakep_autosleep_enabled(bool set);
+ extern void pm_print_active_wakeup_sources(void);
++extern void pm_get_active_wakeup_sources(char *pending_sources, size_t max);
+ 
+ static inline void lock_system_sleep(void)
+ {
+diff --git a/include/linux/switch.h b/include/linux/switch.h
+new file mode 100644
+index 0000000..3e4c748
+--- /dev/null
++++ b/include/linux/switch.h
+@@ -0,0 +1,53 @@
++/*
++ *  Switch class driver
++ *
++ * Copyright (C) 2008 Google, Inc.
++ * Author: Mike Lockwood <lockwood@android.com>
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++*/
++
++#ifndef __LINUX_SWITCH_H__
++#define __LINUX_SWITCH_H__
++
++struct switch_dev {
++	const char	*name;
++	struct device	*dev;
++	int		index;
++	int		state;
++
++	ssize_t	(*print_name)(struct switch_dev *sdev, char *buf);
++	ssize_t	(*print_state)(struct switch_dev *sdev, char *buf);
++};
++
++struct gpio_switch_platform_data {
++	const char *name;
++	unsigned 	gpio;
++
++	/* if NULL, switch_dev.name will be printed */
++	const char *name_on;
++	const char *name_off;
++	/* if NULL, "0" or "1" will be printed */
++	const char *state_on;
++	const char *state_off;
++};
++
++extern int switch_dev_register(struct switch_dev *sdev);
++extern void switch_dev_unregister(struct switch_dev *sdev);
++
++static inline int switch_get_state(struct switch_dev *sdev)
++{
++	return sdev->state;
++}
++
++extern void switch_set_state(struct switch_dev *sdev, int state);
++
++#endif /* __LINUX_SWITCH_H__ */
+diff --git a/include/linux/thermal.h b/include/linux/thermal.h
+index ef90838..037e9df 100644
+--- a/include/linux/thermal.h
++++ b/include/linux/thermal.h
+@@ -29,16 +29,19 @@
+ #include <linux/idr.h>
+ #include <linux/device.h>
+ #include <linux/workqueue.h>
++#include <uapi/linux/thermal.h>
+ 
+ #define THERMAL_TRIPS_NONE	-1
+ #define THERMAL_MAX_TRIPS	12
+-#define THERMAL_NAME_LENGTH	20
+ 
+ /* invalid cooling state */
+ #define THERMAL_CSTATE_INVALID -1UL
+ 
+ /* No upper/lower limit requirement */
+-#define THERMAL_NO_LIMIT	THERMAL_CSTATE_INVALID
++#define THERMAL_NO_LIMIT	((u32)~0)
++
++/* Default weight of a bound cooling device */
++#define THERMAL_WEIGHT_DEFAULT 0
+ 
+ /* Unit conversion macros */
+ #define KELVIN_TO_CELSIUS(t)	(long)(((long)t-2732 >= 0) ?	\
+@@ -49,11 +52,6 @@
+ #define MILLICELSIUS_TO_DECI_KELVIN_WITH_OFFSET(t, off) (((t) / 100) + (off))
+ #define MILLICELSIUS_TO_DECI_KELVIN(t) MILLICELSIUS_TO_DECI_KELVIN_WITH_OFFSET(t, 2732)
+ 
+-/* Adding event notification support elements */
+-#define THERMAL_GENL_FAMILY_NAME                "thermal_event"
+-#define THERMAL_GENL_VERSION                    0x01
+-#define THERMAL_GENL_MCAST_GROUP_NAME           "thermal_mc_grp"
+-
+ /* Default Thermal Governor */
+ #if defined(CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE)
+ #define DEFAULT_THERMAL_GOVERNOR       "step_wise"
+@@ -61,10 +59,13 @@
+ #define DEFAULT_THERMAL_GOVERNOR       "fair_share"
+ #elif defined(CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE)
+ #define DEFAULT_THERMAL_GOVERNOR       "user_space"
++#elif defined(CONFIG_THERMAL_DEFAULT_GOV_POWER_ALLOCATOR)
++#define DEFAULT_THERMAL_GOVERNOR       "power_allocator"
+ #endif
+ 
+ struct thermal_zone_device;
+ struct thermal_cooling_device;
++struct thermal_instance;
+ 
+ enum thermal_device_mode {
+ 	THERMAL_DEVICE_DISABLED = 0,
+@@ -86,30 +87,6 @@ enum thermal_trend {
+ 	THERMAL_TREND_DROP_FULL, /* apply lowest cooling action */
+ };
+ 
+-/* Events supported by Thermal Netlink */
+-enum events {
+-	THERMAL_AUX0,
+-	THERMAL_AUX1,
+-	THERMAL_CRITICAL,
+-	THERMAL_DEV_FAULT,
+-};
+-
+-/* attributes of thermal_genl_family */
+-enum {
+-	THERMAL_GENL_ATTR_UNSPEC,
+-	THERMAL_GENL_ATTR_EVENT,
+-	__THERMAL_GENL_ATTR_MAX,
+-};
+-#define THERMAL_GENL_ATTR_MAX (__THERMAL_GENL_ATTR_MAX - 1)
+-
+-/* commands supported by the thermal_genl_family */
+-enum {
+-	THERMAL_GENL_CMD_UNSPEC,
+-	THERMAL_GENL_CMD_EVENT,
+-	__THERMAL_GENL_CMD_MAX,
+-};
+-#define THERMAL_GENL_CMD_MAX (__THERMAL_GENL_CMD_MAX - 1)
+-
+ struct thermal_zone_device_ops {
+ 	int (*bind) (struct thermal_zone_device *,
+ 		     struct thermal_cooling_device *);
+@@ -142,6 +119,12 @@ struct thermal_cooling_device_ops {
+ 	int (*get_max_state) (struct thermal_cooling_device *, unsigned long *);
+ 	int (*get_cur_state) (struct thermal_cooling_device *, unsigned long *);
+ 	int (*set_cur_state) (struct thermal_cooling_device *, unsigned long);
++	int (*get_requested_power)(struct thermal_cooling_device *,
++				   struct thermal_zone_device *, u32 *);
++	int (*state2power)(struct thermal_cooling_device *,
++			   struct thermal_zone_device *, unsigned long, u32 *);
++	int (*power2state)(struct thermal_cooling_device *,
++			   struct thermal_zone_device *, u32, unsigned long *);
+ };
+ 
+ struct thermal_cooling_device {
+@@ -173,8 +156,7 @@ struct thermal_attr {
+  * @devdata:	private pointer for device private data
+  * @trips:	number of trip points the thermal zone supports
+  * @passive_delay:	number of milliseconds to wait between polls when
+- *			performing passive cooling.  Currenty only used by the
+- *			step-wise governor
++ *			performing passive cooling.
+  * @polling_delay:	number of milliseconds to wait between polls when
+  *			checking whether trip points have been crossed (0 for
+  *			interrupt driven systems)
+@@ -184,13 +166,13 @@ struct thermal_attr {
+  * @last_temperature:	previous temperature read
+  * @emul_temperature:	emulated temperature when using CONFIG_THERMAL_EMULATION
+  * @passive:		1 if you've crossed a passive trip point, 0 otherwise.
+- *			Currenty only used by the step-wise governor.
+  * @forced_passive:	If > 0, temperature at which to switch on all ACPI
+  *			processor cooling devices.  Currently only used by the
+  *			step-wise governor.
+  * @ops:	operations this &thermal_zone_device supports
+  * @tzp:	thermal zone parameters
+  * @governor:	pointer to the governor for this thermal zone
++ * @governor_data:	private pointer for governor data
+  * @thermal_instances:	list of &struct thermal_instance of this thermal zone
+  * @idr:	&struct idr to generate unique id for this zone's cooling
+  *		devices
+@@ -215,8 +197,9 @@ struct thermal_zone_device {
+ 	int passive;
+ 	unsigned int forced_passive;
+ 	struct thermal_zone_device_ops *ops;
+-	const struct thermal_zone_params *tzp;
++	struct thermal_zone_params *tzp;
+ 	struct thermal_governor *governor;
++	void *governor_data;
+ 	struct list_head thermal_instances;
+ 	struct idr idr;
+ 	struct mutex lock;
+@@ -227,12 +210,19 @@ struct thermal_zone_device {
+ /**
+  * struct thermal_governor - structure that holds thermal governor information
+  * @name:	name of the governor
++ * @bind_to_tz: callback called when binding to a thermal zone.  If it
++ *		returns 0, the governor is bound to the thermal zone,
++ *		otherwise it fails.
++ * @unbind_from_tz:	callback called when a governor is unbound from a
++ *			thermal zone.
+  * @throttle:	callback called for every trip point even if temperature is
+  *		below the trip point temperature
+  * @governor_list:	node in thermal_governor_list (in thermal_core.c)
+  */
+ struct thermal_governor {
+ 	char name[THERMAL_NAME_LENGTH];
++	int (*bind_to_tz)(struct thermal_zone_device *tz);
++	void (*unbind_from_tz)(struct thermal_zone_device *tz);
+ 	int (*throttle)(struct thermal_zone_device *tz, int trip);
+ 	struct list_head	governor_list;
+ };
+@@ -243,9 +233,12 @@ struct thermal_bind_params {
+ 
+ 	/*
+ 	 * This is a measure of 'how effectively these devices can
+-	 * cool 'this' thermal zone. The shall be determined by platform
+-	 * characterization. This is on a 'percentage' scale.
+-	 * See Documentation/thermal/sysfs-api.txt for more information.
++	 * cool 'this' thermal zone. It shall be determined by
++	 * platform characterization. This value is relative to the
++	 * rest of the weights so a cooling device whose weight is
++	 * double that of another cooling device is twice as
++	 * effective. See Documentation/thermal/sysfs-api.txt for more
++	 * information.
+ 	 */
+ 	int weight;
+ 
+@@ -282,6 +275,44 @@ struct thermal_zone_params {
+ 
+ 	int num_tbps;	/* Number of tbp entries */
+ 	struct thermal_bind_params *tbp;
++
++	/*
++	 * Sustainable power (heat) that this thermal zone can dissipate in
++	 * mW
++	 */
++	u32 sustainable_power;
++
++	/*
++	 * Proportional parameter of the PID controller when
++	 * overshooting (i.e., when temperature is below the target)
++	 */
++	s32 k_po;
++
++	/*
++	 * Proportional parameter of the PID controller when
++	 * undershooting
++	 */
++	s32 k_pu;
++
++	/* Integral parameter of the PID controller */
++	s32 k_i;
++
++	/* Derivative parameter of the PID controller */
++	s32 k_d;
++
++	/* threshold below which the error is no longer accumulated */
++	s32 integral_cutoff;
++
++	/*
++	 * @slope:	slope of a linear temperature adjustment curve.
++	 * 		Used by thermal zone drivers.
++	 */
++	int slope;
++	/*
++	 * @offset:	offset of a linear temperature adjustment curve.
++	 * 		Used by thermal zone drivers (default 0).
++	 */
++	int offset;
+ };
+ 
+ struct thermal_genl_event {
+@@ -289,19 +320,49 @@ struct thermal_genl_event {
+ 	enum events event;
+ };
+ 
++/**
++ * struct thermal_zone_of_device_ops - scallbacks for handling DT based zones
++ *
++ * Mandatory:
++ * @get_temp: a pointer to a function that reads the sensor temperature.
++ *
++ * Optional:
++ * @get_trend: a pointer to a function that reads the sensor temperature trend.
++ * @set_emul_temp: a pointer to a function that sets sensor emulated
++ *		   temperature.
++ */
++struct thermal_zone_of_device_ops {
++	int (*get_temp)(void *, long *);
++	int (*get_trend)(void *, long *);
++	int (*set_emul_temp)(void *, unsigned long);
++};
++
++/**
++ * struct thermal_trip - representation of a point in temperature domain
++ * @np: pointer to struct device_node that this trip point was created from
++ * @temperature: temperature value in miliCelsius
++ * @hysteresis: relative hysteresis in miliCelsius
++ * @type: trip point type
++ */
++
++struct thermal_trip {
++	struct device_node *np;
++	unsigned long int temperature;
++	unsigned long int hysteresis;
++	enum thermal_trip_type type;
++};
++
+ /* Function declarations */
+ #ifdef CONFIG_THERMAL_OF
+ struct thermal_zone_device *
+-thermal_zone_of_sensor_register(struct device *dev, int id,
+-				void *data, int (*get_temp)(void *, long *),
+-				int (*get_trend)(void *, long *));
++thermal_zone_of_sensor_register(struct device *dev, int id, void *data,
++				const struct thermal_zone_of_device_ops *ops);
+ void thermal_zone_of_sensor_unregister(struct device *dev,
+ 				       struct thermal_zone_device *tz);
+ #else
+ static inline struct thermal_zone_device *
+-thermal_zone_of_sensor_register(struct device *dev, int id,
+-				void *data, int (*get_temp)(void *, long *),
+-				int (*get_trend)(void *, long *))
++thermal_zone_of_sensor_register(struct device *dev, int id, void *data,
++				const struct thermal_zone_of_device_ops *ops)
+ {
+ 	return NULL;
+ }
+@@ -313,14 +374,27 @@ void thermal_zone_of_sensor_unregister(struct device *dev,
+ }
+ 
+ #endif
++
++#if IS_ENABLED(CONFIG_THERMAL)
++static inline bool cdev_is_power_actor(struct thermal_cooling_device *cdev)
++{
++	return cdev->ops->get_requested_power && cdev->ops->state2power &&
++		cdev->ops->power2state;
++}
++
++int power_actor_get_max_power(struct thermal_cooling_device *,
++			      struct thermal_zone_device *tz, u32 *max_power);
++int power_actor_set_power(struct thermal_cooling_device *,
++			  struct thermal_instance *, u32);
+ struct thermal_zone_device *thermal_zone_device_register(const char *, int, int,
+ 		void *, struct thermal_zone_device_ops *,
+-		const struct thermal_zone_params *, int, int);
++		struct thermal_zone_params *, int, int);
+ void thermal_zone_device_unregister(struct thermal_zone_device *);
+ 
+ int thermal_zone_bind_cooling_device(struct thermal_zone_device *, int,
+ 				     struct thermal_cooling_device *,
+-				     unsigned long, unsigned long);
++				     unsigned long, unsigned long,
++				     unsigned int);
+ int thermal_zone_unbind_cooling_device(struct thermal_zone_device *, int,
+ 				       struct thermal_cooling_device *);
+ void thermal_zone_device_update(struct thermal_zone_device *);
+@@ -339,8 +413,66 @@ struct thermal_instance *get_thermal_instance(struct thermal_zone_device *,
+ 		struct thermal_cooling_device *, int);
+ void thermal_cdev_update(struct thermal_cooling_device *);
+ void thermal_notify_framework(struct thermal_zone_device *, int);
+-
+-#ifdef CONFIG_NET
++#else
++static inline bool cdev_is_power_actor(struct thermal_cooling_device *cdev)
++{ return false; }
++static inline int power_actor_get_max_power(struct thermal_cooling_device *cdev,
++			      struct thermal_zone_device *tz, u32 *max_power)
++{ return 0; }
++static inline int power_actor_set_power(struct thermal_cooling_device *cdev,
++			  struct thermal_instance *tz, u32 power)
++{ return 0; }
++static inline struct thermal_zone_device *thermal_zone_device_register(
++	const char *type, int trips, int mask, void *devdata,
++	struct thermal_zone_device_ops *ops,
++	const struct thermal_zone_params *tzp,
++	int passive_delay, int polling_delay)
++{ return ERR_PTR(-ENODEV); }
++static inline void thermal_zone_device_unregister(
++	struct thermal_zone_device *tz)
++{ }
++static inline int thermal_zone_bind_cooling_device(
++	struct thermal_zone_device *tz, int trip,
++	struct thermal_cooling_device *cdev,
++	unsigned long upper, unsigned long lower)
++{ return -ENODEV; }
++static inline int thermal_zone_unbind_cooling_device(
++	struct thermal_zone_device *tz, int trip,
++	struct thermal_cooling_device *cdev)
++{ return -ENODEV; }
++static inline void thermal_zone_device_update(struct thermal_zone_device *tz)
++{ }
++static inline struct thermal_cooling_device *
++thermal_cooling_device_register(char *type, void *devdata,
++	const struct thermal_cooling_device_ops *ops)
++{ return ERR_PTR(-ENODEV); }
++static inline struct thermal_cooling_device *
++thermal_of_cooling_device_register(struct device_node *np,
++	char *type, void *devdata, const struct thermal_cooling_device_ops *ops)
++{ return ERR_PTR(-ENODEV); }
++static inline void thermal_cooling_device_unregister(
++	struct thermal_cooling_device *cdev)
++{ }
++static inline struct thermal_zone_device *thermal_zone_get_zone_by_name(
++		const char *name)
++{ return ERR_PTR(-ENODEV); }
++static inline int thermal_zone_get_temp(
++		struct thermal_zone_device *tz, unsigned long *temp)
++{ return -ENODEV; }
++static inline int get_tz_trend(struct thermal_zone_device *tz, int trip)
++{ return -ENODEV; }
++static inline struct thermal_instance *
++get_thermal_instance(struct thermal_zone_device *tz,
++	struct thermal_cooling_device *cdev, int trip)
++{ return ERR_PTR(-ENODEV); }
++static inline void thermal_cdev_update(struct thermal_cooling_device *cdev)
++{ }
++static inline void thermal_notify_framework(struct thermal_zone_device *tz,
++	int trip)
++{ }
++#endif /* CONFIG_THERMAL */
++
++#if defined(CONFIG_NET) && IS_ENABLED(CONFIG_THERMAL)
+ extern int thermal_generate_netlink_event(struct thermal_zone_device *tz,
+ 						enum events event);
+ #else
+diff --git a/include/linux/uid_stat.h b/include/linux/uid_stat.h
+new file mode 100644
+index 0000000..6bd6c4e
+--- /dev/null
++++ b/include/linux/uid_stat.h
+@@ -0,0 +1,29 @@
++/* include/linux/uid_stat.h
++ *
++ * Copyright (C) 2008-2009 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#ifndef __uid_stat_h
++#define __uid_stat_h
++
++/* Contains definitions for resource tracking per uid. */
++
++#ifdef CONFIG_UID_STAT
++int uid_stat_tcp_snd(uid_t uid, int size);
++int uid_stat_tcp_rcv(uid_t uid, int size);
++#else
++#define uid_stat_tcp_snd(uid, size) do {} while (0);
++#define uid_stat_tcp_rcv(uid, size) do {} while (0);
++#endif
++
++#endif /* _LINUX_UID_STAT_H */
+diff --git a/include/linux/uio.h b/include/linux/uio.h
+index 9b15814..0a48eee 100644
+--- a/include/linux/uio.h
++++ b/include/linux/uio.h
+@@ -96,6 +96,13 @@ static inline size_t iov_iter_count(struct iov_iter *i)
+ {
+ 	return i->count;
+ }
++/*
++ * Get one of READ or WRITE out of iter->type without any other flags OR'd in
++ * with it.
++ *
++ * The ?: is just for type safety.
++ */
++#define iov_iter_rw(i) ((0 ? (struct iov_iter *)0 : (i))->type & RW_MASK)
+ 
+ /*
+  * Cap the iov_iter by given limit; note that the second argument is
+diff --git a/include/linux/usb/class-dual-role.h b/include/linux/usb/class-dual-role.h
+new file mode 100644
+index 0000000..af42ed3
+--- /dev/null
++++ b/include/linux/usb/class-dual-role.h
+@@ -0,0 +1,128 @@
++#ifndef __LINUX_CLASS_DUAL_ROLE_H__
++#define __LINUX_CLASS_DUAL_ROLE_H__
++
++#include <linux/workqueue.h>
++#include <linux/errno.h>
++#include <linux/types.h>
++
++struct device;
++
++enum dual_role_supported_modes {
++	DUAL_ROLE_SUPPORTED_MODES_DFP_AND_UFP = 0,
++	DUAL_ROLE_SUPPORTED_MODES_DFP,
++	DUAL_ROLE_SUPPORTED_MODES_UFP,
++/*The following should be the last element*/
++	DUAL_ROLE_PROP_SUPPORTED_MODES_TOTAL,
++};
++
++enum {
++	DUAL_ROLE_PROP_MODE_UFP = 0,
++	DUAL_ROLE_PROP_MODE_DFP,
++	DUAL_ROLE_PROP_MODE_NONE,
++/*The following should be the last element*/
++	DUAL_ROLE_PROP_MODE_TOTAL,
++};
++
++enum {
++	DUAL_ROLE_PROP_PR_SRC = 0,
++	DUAL_ROLE_PROP_PR_SNK,
++	DUAL_ROLE_PROP_PR_NONE,
++/*The following should be the last element*/
++	DUAL_ROLE_PROP_PR_TOTAL,
++
++};
++
++enum {
++	DUAL_ROLE_PROP_DR_HOST = 0,
++	DUAL_ROLE_PROP_DR_DEVICE,
++	DUAL_ROLE_PROP_DR_NONE,
++/*The following should be the last element*/
++	DUAL_ROLE_PROP_DR_TOTAL,
++};
++
++enum {
++	DUAL_ROLE_PROP_VCONN_SUPPLY_NO = 0,
++	DUAL_ROLE_PROP_VCONN_SUPPLY_YES,
++/*The following should be the last element*/
++	DUAL_ROLE_PROP_VCONN_SUPPLY_TOTAL,
++};
++
++enum dual_role_property {
++	DUAL_ROLE_PROP_SUPPORTED_MODES = 0,
++	DUAL_ROLE_PROP_MODE,
++	DUAL_ROLE_PROP_PR,
++	DUAL_ROLE_PROP_DR,
++	DUAL_ROLE_PROP_VCONN_SUPPLY,
++};
++
++struct dual_role_phy_instance;
++
++/* Description of typec port */
++struct dual_role_phy_desc {
++	/* /sys/class/dual_role_usb/<name>/ */
++	const char *name;
++	enum dual_role_supported_modes supported_modes;
++	enum dual_role_property *properties;
++	size_t num_properties;
++
++	/* Callback for "cat /sys/class/dual_role_usb/<name>/<property>" */
++	int (*get_property)(struct dual_role_phy_instance *dual_role,
++			     enum dual_role_property prop,
++			     unsigned int *val);
++	/* Callback for "echo <value> >
++	 *                      /sys/class/dual_role_usb/<name>/<property>" */
++	int (*set_property)(struct dual_role_phy_instance *dual_role,
++			     enum dual_role_property prop,
++			     const unsigned int *val);
++	/* Decides whether userspace can change a specific property */
++	int (*property_is_writeable)(struct dual_role_phy_instance *dual_role,
++				      enum dual_role_property prop);
++};
++
++struct dual_role_phy_instance {
++	const struct dual_role_phy_desc *desc;
++
++	/* Driver private data */
++	void *drv_data;
++
++	struct device dev;
++	struct work_struct changed_work;
++};
++
++#if IS_ENABLED(CONFIG_DUAL_ROLE_USB_INTF)
++extern void dual_role_instance_changed(struct dual_role_phy_instance
++				       *dual_role);
++extern struct dual_role_phy_instance *__must_check
++devm_dual_role_instance_register(struct device *parent,
++				 const struct dual_role_phy_desc *desc);
++extern void devm_dual_role_instance_unregister(struct device *dev,
++					       struct dual_role_phy_instance
++					       *dual_role);
++extern int dual_role_get_property(struct dual_role_phy_instance *dual_role,
++				  enum dual_role_property prop,
++				  unsigned int *val);
++extern int dual_role_set_property(struct dual_role_phy_instance *dual_role,
++				  enum dual_role_property prop,
++				  const unsigned int *val);
++extern int dual_role_property_is_writeable(struct dual_role_phy_instance
++					   *dual_role,
++					   enum dual_role_property prop);
++extern void *dual_role_get_drvdata(struct dual_role_phy_instance *dual_role);
++#else /* CONFIG_DUAL_ROLE_USB_INTF */
++static void dual_role_instance_changed(struct dual_role_phy_instance
++				       *dual_role){}
++static struct dual_role_phy_instance *__must_check
++devm_dual_role_instance_register(struct device *parent,
++				 const struct dual_role_phy_desc *desc)
++{
++	return ERR_PTR(-ENOSYS);
++}
++static void devm_dual_role_instance_unregister(struct device *dev,
++					       struct dual_role_phy_instance
++					       *dual_role){}
++static void *dual_role_get_drvdata(struct dual_role_phy_instance *dual_role)
++{
++	return ERR_PTR(-ENOSYS);
++}
++#endif /* CONFIG_DUAL_ROLE_USB_INTF */
++#endif /* __LINUX_CLASS_DUAL_ROLE_H__ */
+diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h
+index c330f5e..6380a0e 100644
+--- a/include/linux/usb/composite.h
++++ b/include/linux/usb/composite.h
+@@ -562,6 +562,7 @@ struct usb_function_instance {
+ 	struct config_group group;
+ 	struct list_head cfs_list;
+ 	struct usb_function_driver *fd;
++	struct usb_function *f;
+ 	int (*set_inst_name)(struct usb_function_instance *inst,
+ 			      const char *name);
+ 	void (*free_func_inst)(struct usb_function_instance *inst);
+diff --git a/include/linux/usb/f_accessory.h b/include/linux/usb/f_accessory.h
+new file mode 100644
+index 0000000..ebe3c4d
+--- /dev/null
++++ b/include/linux/usb/f_accessory.h
+@@ -0,0 +1,23 @@
++/*
++ * Gadget Function Driver for Android USB accessories
++ *
++ * Copyright (C) 2011 Google, Inc.
++ * Author: Mike Lockwood <lockwood@android.com>
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#ifndef __LINUX_USB_F_ACCESSORY_H
++#define __LINUX_USB_F_ACCESSORY_H
++
++#include <uapi/linux/usb/f_accessory.h>
++
++#endif /* __LINUX_USB_F_ACCESSORY_H */
+diff --git a/include/linux/usb/f_mtp.h b/include/linux/usb/f_mtp.h
+new file mode 100644
+index 0000000..4e84177
+--- /dev/null
++++ b/include/linux/usb/f_mtp.h
+@@ -0,0 +1,23 @@
++/*
++ * Gadget Function Driver for MTP
++ *
++ * Copyright (C) 2010 Google, Inc.
++ * Author: Mike Lockwood <lockwood@android.com>
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#ifndef __LINUX_USB_F_MTP_H
++#define __LINUX_USB_F_MTP_H
++
++#include <uapi/linux/usb/f_mtp.h>
++
++#endif /* __LINUX_USB_F_MTP_H */
+diff --git a/include/linux/wakelock.h b/include/linux/wakelock.h
+new file mode 100644
+index 0000000..f4a698a
+--- /dev/null
++++ b/include/linux/wakelock.h
+@@ -0,0 +1,67 @@
++/* include/linux/wakelock.h
++ *
++ * Copyright (C) 2007-2012 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#ifndef _LINUX_WAKELOCK_H
++#define _LINUX_WAKELOCK_H
++
++#include <linux/ktime.h>
++#include <linux/device.h>
++
++/* A wake_lock prevents the system from entering suspend or other low power
++ * states when active. If the type is set to WAKE_LOCK_SUSPEND, the wake_lock
++ * prevents a full system suspend.
++ */
++
++enum {
++	WAKE_LOCK_SUSPEND, /* Prevent suspend */
++	WAKE_LOCK_TYPE_COUNT
++};
++
++struct wake_lock {
++	struct wakeup_source ws;
++};
++
++static inline void wake_lock_init(struct wake_lock *lock, int type,
++				  const char *name)
++{
++	wakeup_source_init(&lock->ws, name);
++}
++
++static inline void wake_lock_destroy(struct wake_lock *lock)
++{
++	wakeup_source_trash(&lock->ws);
++}
++
++static inline void wake_lock(struct wake_lock *lock)
++{
++	__pm_stay_awake(&lock->ws);
++}
++
++static inline void wake_lock_timeout(struct wake_lock *lock, long timeout)
++{
++	__pm_wakeup_event(&lock->ws, jiffies_to_msecs(timeout));
++}
++
++static inline void wake_unlock(struct wake_lock *lock)
++{
++	__pm_relax(&lock->ws);
++}
++
++static inline int wake_lock_active(struct wake_lock *lock)
++{
++	return lock->ws.active;
++}
++
++#endif
+diff --git a/include/linux/wakeup_reason.h b/include/linux/wakeup_reason.h
+new file mode 100644
+index 0000000..ad8b769
+--- /dev/null
++++ b/include/linux/wakeup_reason.h
+@@ -0,0 +1,27 @@
++/*
++ * include/linux/wakeup_reason.h
++ *
++ * Logs the reason which caused the kernel to resume
++ * from the suspend mode.
++ *
++ * Copyright (C) 2014 Google, Inc.
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#ifndef _LINUX_WAKEUP_REASON_H
++#define _LINUX_WAKEUP_REASON_H
++
++#define MAX_SUSPEND_ABORT_LEN 256
++
++void log_wakeup_reason(int irq);
++void log_suspend_abort_reason(const char *fmt, ...);
++int check_wakeup_reason(int irq);
++
++#endif /* _LINUX_WAKEUP_REASON_H */
+diff --git a/include/linux/wifi_tiwlan.h b/include/linux/wifi_tiwlan.h
+new file mode 100644
+index 0000000..f07e067
+--- /dev/null
++++ b/include/linux/wifi_tiwlan.h
+@@ -0,0 +1,27 @@
++/* include/linux/wifi_tiwlan.h
++ *
++ * Copyright (C) 2008 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++#ifndef _LINUX_WIFI_TIWLAN_H_
++#define _LINUX_WIFI_TIWLAN_H_
++
++#include <linux/wlan_plat.h>
++
++#define WMPA_NUMBER_OF_SECTIONS	3
++#define WMPA_NUMBER_OF_BUFFERS	160
++#define WMPA_SECTION_HEADER	24
++#define WMPA_SECTION_SIZE_0	(WMPA_NUMBER_OF_BUFFERS * 64)
++#define WMPA_SECTION_SIZE_1	(WMPA_NUMBER_OF_BUFFERS * 256)
++#define WMPA_SECTION_SIZE_2	(WMPA_NUMBER_OF_BUFFERS * 2048)
++
++#endif
+diff --git a/include/linux/wlan_plat.h b/include/linux/wlan_plat.h
+new file mode 100644
+index 0000000..8e8b06f
+--- /dev/null
++++ b/include/linux/wlan_plat.h
+@@ -0,0 +1,30 @@
++/* include/linux/wlan_plat.h
++ *
++ * Copyright (C) 2010 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++#ifndef _LINUX_WLAN_PLAT_H_
++#define _LINUX_WLAN_PLAT_H_
++
++#define WLAN_PLAT_NODFS_FLAG	0x01
++
++struct wifi_platform_data {
++	int (*set_power)(int val);
++	int (*set_reset)(int val);
++	int (*set_carddetect)(int val);
++	void *(*mem_prealloc)(int section, unsigned long size);
++	int (*get_mac_addr)(unsigned char *buf);
++	int (*get_wake_irq)(void);
++	void *(*get_country_code)(char *ccode, u32 flags);
++};
++
++#endif
+diff --git a/include/net/activity_stats.h b/include/net/activity_stats.h
+new file mode 100644
+index 0000000..10e4c15
+--- /dev/null
++++ b/include/net/activity_stats.h
+@@ -0,0 +1,25 @@
++/*
++ * Copyright (C) 2010 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * 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.
++ *
++ * Author: Mike Chan (mike@android.com)
++ */
++
++#ifndef __activity_stats_h
++#define __activity_stats_h
++
++#ifdef CONFIG_NET_ACTIVITY_STATS
++void activity_stats_update(void);
++#else
++#define activity_stats_update(void) {}
++#endif
++
++#endif /* _NET_ACTIVITY_STATS_H */
+diff --git a/include/net/addrconf.h b/include/net/addrconf.h
+index d13573b..9828539 100644
+--- a/include/net/addrconf.h
++++ b/include/net/addrconf.h
+@@ -193,6 +193,8 @@ static inline bool ipv6_is_mld(struct sk_buff *skb, int nexthdr, int offset)
+ void addrconf_prefix_rcv(struct net_device *dev,
+ 			 u8 *opt, int len, bool sllao);
+ 
++u32 addrconf_rt_table(const struct net_device *dev, u32 default_table);
++
+ /*
+  *	anycast prototypes (anycast.c)
+  */
+diff --git a/include/net/af_unix.h b/include/net/af_unix.h
+index a175ba4..9cb6119 100644
+--- a/include/net/af_unix.h
++++ b/include/net/af_unix.h
+@@ -6,8 +6,8 @@
+ #include <linux/mutex.h>
+ #include <net/sock.h>
+ 
+-void unix_inflight(struct file *fp);
+-void unix_notinflight(struct file *fp);
++void unix_inflight(struct user_struct *user, struct file *fp);
++void unix_notinflight(struct user_struct *user, struct file *fp);
+ void unix_gc(void);
+ void wait_for_unix_gc(void);
+ struct sock *unix_get_socket(struct file *filp);
+@@ -63,6 +63,7 @@ struct unix_sock {
+ #define UNIX_GC_CANDIDATE	0
+ #define UNIX_GC_MAYBE_CYCLE	1
+ 	struct socket_wq	peer_wq;
++	wait_queue_t            peer_wake;
+ };
+ #define unix_sk(__sk) ((struct unix_sock *)__sk)
+ 
+diff --git a/include/net/fib_rules.h b/include/net/fib_rules.h
+index e584de1..c10c06f 100644
+--- a/include/net/fib_rules.h
++++ b/include/net/fib_rules.h
+@@ -28,6 +28,8 @@ struct fib_rule {
+ 	int			suppress_prefixlen;
+ 	char			iifname[IFNAMSIZ];
+ 	char			oifname[IFNAMSIZ];
++	kuid_t			uid_start;
++	kuid_t			uid_end;
+ 	struct rcu_head		rcu;
+ };
+ 
+@@ -86,9 +88,13 @@ struct fib_rules_ops {
+ 	[FRA_FWMARK]	= { .type = NLA_U32 }, \
+ 	[FRA_FWMASK]	= { .type = NLA_U32 }, \
+ 	[FRA_TABLE]     = { .type = NLA_U32 }, \
++	[FRA_GOTO]	= { .type = NLA_U32 }, \
++	[FRA_UID_START]	= { .type = NLA_U32 }, \
++	[FRA_UID_END]	= { .type = NLA_U32 }, \
+ 	[FRA_SUPPRESS_PREFIXLEN] = { .type = NLA_U32 }, \
+ 	[FRA_SUPPRESS_IFGROUP] = { .type = NLA_U32 }, \
+ 	[FRA_GOTO]	= { .type = NLA_U32 }
++	
+ 
+ static inline void fib_rule_get(struct fib_rule *rule)
+ {
+diff --git a/include/net/flow.h b/include/net/flow.h
+index 8109a15..da7743e 100644
+--- a/include/net/flow.h
++++ b/include/net/flow.h
+@@ -10,6 +10,7 @@
+ #include <linux/socket.h>
+ #include <linux/in6.h>
+ #include <linux/atomic.h>
++#include <linux/uidgid.h>
+ 
+ /*
+  * ifindex generation is per-net namespace, and loopback is
+@@ -30,6 +31,7 @@ struct flowi_common {
+ #define FLOWI_FLAG_ANYSRC		0x01
+ #define FLOWI_FLAG_KNOWN_NH		0x02
+ 	__u32	flowic_secid;
++	kuid_t	flowic_uid;
+ };
+ 
+ union flowi_uli {
+@@ -66,6 +68,7 @@ struct flowi4 {
+ #define flowi4_proto		__fl_common.flowic_proto
+ #define flowi4_flags		__fl_common.flowic_flags
+ #define flowi4_secid		__fl_common.flowic_secid
++#define flowi4_uid		__fl_common.flowic_uid
+ 
+ 	/* (saddr,daddr) must be grouped, same order as in IP header */
+ 	__be32			saddr;
+@@ -85,7 +88,8 @@ static inline void flowi4_init_output(struct flowi4 *fl4, int oif,
+ 				      __u32 mark, __u8 tos, __u8 scope,
+ 				      __u8 proto, __u8 flags,
+ 				      __be32 daddr, __be32 saddr,
+-				      __be16 dport, __be16 sport)
++				      __be16 dport, __be16 sport,
++				      kuid_t uid)
+ {
+ 	fl4->flowi4_oif = oif;
+ 	fl4->flowi4_iif = LOOPBACK_IFINDEX;
+@@ -95,6 +99,7 @@ static inline void flowi4_init_output(struct flowi4 *fl4, int oif,
+ 	fl4->flowi4_proto = proto;
+ 	fl4->flowi4_flags = flags;
+ 	fl4->flowi4_secid = 0;
++	fl4->flowi4_uid = uid;
+ 	fl4->daddr = daddr;
+ 	fl4->saddr = saddr;
+ 	fl4->fl4_dport = dport;
+@@ -122,6 +127,7 @@ struct flowi6 {
+ #define flowi6_proto		__fl_common.flowic_proto
+ #define flowi6_flags		__fl_common.flowic_flags
+ #define flowi6_secid		__fl_common.flowic_secid
++#define flowi6_uid		__fl_common.flowic_uid
+ 	struct in6_addr		daddr;
+ 	struct in6_addr		saddr;
+ 	__be32			flowlabel;
+@@ -165,6 +171,7 @@ struct flowi {
+ #define flowi_proto	u.__fl_common.flowic_proto
+ #define flowi_flags	u.__fl_common.flowic_flags
+ #define flowi_secid	u.__fl_common.flowic_secid
++#define flowi_uid	u.__fl_common.flowic_uid
+ } __attribute__((__aligned__(BITS_PER_LONG/8)));
+ 
+ static inline struct flowi *flowi4_to_flowi(struct flowi4 *fl4)
+diff --git a/include/net/ip.h b/include/net/ip.h
+index c0c26c3..3fce700 100644
+--- a/include/net/ip.h
++++ b/include/net/ip.h
+@@ -172,6 +172,7 @@ struct ip_reply_arg {
+ 				/* -1 if not needed */ 
+ 	int	    bound_dev_if;
+ 	u8  	    tos;
++	kuid_t	    uid;
+ }; 
+ 
+ #define IP_REPLY_ARG_NOSRCCHECK 1
+diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h
+index eda131d..d513308 100644
+--- a/include/net/ip6_route.h
++++ b/include/net/ip6_route.h
+@@ -108,7 +108,7 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
+ 		  const struct in6_addr *gwaddr);
+ 
+ void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu, int oif,
+-		     u32 mark);
++		     u32 mark, kuid_t uid);
+ void ip6_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, __be32 mtu);
+ void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark);
+ void ip6_redirect_no_header(struct sk_buff *skb, struct net *net, int oif,
+diff --git a/include/net/ipv6.h b/include/net/ipv6.h
+index 4292929..f804797 100644
+--- a/include/net/ipv6.h
++++ b/include/net/ipv6.h
+@@ -207,6 +207,7 @@ extern rwlock_t ip6_ra_lock;
+  */
+ 
+ struct ipv6_txoptions {
++	atomic_t		refcnt;
+ 	/* Length of this structure */
+ 	int			tot_len;
+ 
+@@ -219,7 +220,7 @@ struct ipv6_txoptions {
+ 	struct ipv6_opt_hdr	*dst0opt;
+ 	struct ipv6_rt_hdr	*srcrt;	/* Routing Header */
+ 	struct ipv6_opt_hdr	*dst1opt;
+-
++	struct rcu_head		rcu;
+ 	/* Option buffer, as read by IPV6_PKTOPTIONS, starts here. */
+ };
+ 
+@@ -252,6 +253,24 @@ struct ipv6_fl_socklist {
+ 	struct rcu_head			rcu;
+ };
+ 
++static inline struct ipv6_txoptions *txopt_get(const struct ipv6_pinfo *np)
++{
++	struct ipv6_txoptions *opt;
++
++	rcu_read_lock();
++	opt = rcu_dereference(np->opt);
++	if (opt && !atomic_inc_not_zero(&opt->refcnt))
++		opt = NULL;
++	rcu_read_unlock();
++	return opt;
++}
++
++static inline void txopt_put(struct ipv6_txoptions *opt)
++{
++	if (opt && atomic_dec_and_test(&opt->refcnt))
++		kfree_rcu(opt, rcu);
++}
++
+ struct ip6_flowlabel *fl6_sock_lookup(struct sock *sk, __be32 label);
+ struct ipv6_txoptions *fl6_merge_options(struct ipv6_txoptions *opt_space,
+ 					 struct ip6_flowlabel *fl,
+diff --git a/include/net/route.h b/include/net/route.h
+index b17cf28..41288e3 100644
+--- a/include/net/route.h
++++ b/include/net/route.h
+@@ -140,7 +140,7 @@ static inline struct rtable *ip_route_output_ports(struct net *net, struct flowi
+ 	flowi4_init_output(fl4, oif, sk ? sk->sk_mark : 0, tos,
+ 			   RT_SCOPE_UNIVERSE, proto,
+ 			   sk ? inet_sk_flowi_flags(sk) : 0,
+-			   daddr, saddr, dport, sport);
++			   daddr, saddr, dport, sport, sk ? sock_i_uid(sk) : GLOBAL_ROOT_UID);
+ 	if (sk)
+ 		security_sk_classify_flow(sk, flowi4_to_flowi(fl4));
+ 	return ip_route_output_flow(net, fl4, sk);
+@@ -249,7 +249,8 @@ static inline void ip_route_connect_init(struct flowi4 *fl4, __be32 dst, __be32
+ 		flow_flags |= FLOWI_FLAG_ANYSRC;
+ 
+ 	flowi4_init_output(fl4, oif, sk->sk_mark, tos, RT_SCOPE_UNIVERSE,
+-			   protocol, flow_flags, dst, src, dport, sport);
++			   protocol, flow_flags, dst, src, dport, sport,
++			   sock_i_uid(sk));
+ }
+ 
+ static inline struct rtable *ip_route_connect(struct flowi4 *fl4,
+diff --git a/include/net/scm.h b/include/net/scm.h
+index 262532d..59fa93c 100644
+--- a/include/net/scm.h
++++ b/include/net/scm.h
+@@ -21,6 +21,7 @@ struct scm_creds {
+ struct scm_fp_list {
+ 	short			count;
+ 	short			max;
++	struct user_struct	*user;
+ 	struct file		*fp[SCM_MAX_FD];
+ };
+ 
+diff --git a/include/net/sock.h b/include/net/sock.h
+index 4406dbe..b27b1ed 100644
+--- a/include/net/sock.h
++++ b/include/net/sock.h
+@@ -379,6 +379,7 @@ struct sock {
+ 				sk_no_check_rx : 1,
+ 				sk_userlocks : 4,
+ 				sk_protocol  : 8,
++#define SK_PROTOCOL_MAX U8_MAX
+ 				sk_type      : 16;
+ 	kmemcheck_bitfield_end(flags);
+ 	int			sk_wmem_queued;
+diff --git a/include/net/tcp.h b/include/net/tcp.h
+index 4062b4f..25d497d 100644
+--- a/include/net/tcp.h
++++ b/include/net/tcp.h
+@@ -276,6 +276,7 @@ extern int sysctl_tcp_challenge_ack_limit;
+ extern unsigned int sysctl_tcp_notsent_lowat;
+ extern int sysctl_tcp_min_tso_segs;
+ extern int sysctl_tcp_autocorking;
++extern int sysctl_tcp_default_init_rwnd;
+ 
+ extern atomic_long_t tcp_memory_allocated;
+ extern struct percpu_counter tcp_sockets_allocated;
+@@ -1070,6 +1071,7 @@ static inline void tcp_prequeue_init(struct tcp_sock *tp)
+ }
+ 
+ bool tcp_prequeue(struct sock *sk, struct sk_buff *skb);
++int tcp_filter(struct sock *sk, struct sk_buff *skb);
+ 
+ #undef STATE_TRACE
+ 
+@@ -1431,6 +1433,8 @@ static inline void tcp_check_send_head(struct sock *sk, struct sk_buff *skb_unli
+ {
+ 	if (sk->sk_send_head == skb_unlinked)
+ 		sk->sk_send_head = NULL;
++	if (tcp_sk(sk)->highest_sack == skb_unlinked)
++		tcp_sk(sk)->highest_sack = NULL;
+ }
+ 
+ static inline void tcp_init_send_head(struct sock *sk)
+@@ -1601,6 +1605,8 @@ static inline bool tcp_stream_memory_free(const struct sock *sk)
+ 	return notsent_bytes < tcp_notsent_lowat(tp);
+ }
+ 
++extern int tcp_nuke_addr(struct net *net, struct sockaddr *addr);
++
+ #ifdef CONFIG_PROC_FS
+ int tcp4_proc_init(void);
+ void tcp4_proc_exit(void);
+diff --git a/include/trace/events/cpufreq_interactive.h b/include/trace/events/cpufreq_interactive.h
+new file mode 100644
+index 0000000..951e6ca
+--- /dev/null
++++ b/include/trace/events/cpufreq_interactive.h
+@@ -0,0 +1,112 @@
++#undef TRACE_SYSTEM
++#define TRACE_SYSTEM cpufreq_interactive
++
++#if !defined(_TRACE_CPUFREQ_INTERACTIVE_H) || defined(TRACE_HEADER_MULTI_READ)
++#define _TRACE_CPUFREQ_INTERACTIVE_H
++
++#include <linux/tracepoint.h>
++
++DECLARE_EVENT_CLASS(set,
++	TP_PROTO(u32 cpu_id, unsigned long targfreq,
++	         unsigned long actualfreq),
++	TP_ARGS(cpu_id, targfreq, actualfreq),
++
++	TP_STRUCT__entry(
++	    __field(          u32, cpu_id    )
++	    __field(unsigned long, targfreq   )
++	    __field(unsigned long, actualfreq )
++	   ),
++
++	TP_fast_assign(
++	    __entry->cpu_id = (u32) cpu_id;
++	    __entry->targfreq = targfreq;
++	    __entry->actualfreq = actualfreq;
++	),
++
++	TP_printk("cpu=%u targ=%lu actual=%lu",
++	      __entry->cpu_id, __entry->targfreq,
++	      __entry->actualfreq)
++);
++
++DEFINE_EVENT(set, cpufreq_interactive_setspeed,
++	TP_PROTO(u32 cpu_id, unsigned long targfreq,
++	     unsigned long actualfreq),
++	TP_ARGS(cpu_id, targfreq, actualfreq)
++);
++
++DECLARE_EVENT_CLASS(loadeval,
++	    TP_PROTO(unsigned long cpu_id, unsigned long load,
++		     unsigned long curtarg, unsigned long curactual,
++		     unsigned long newtarg),
++		    TP_ARGS(cpu_id, load, curtarg, curactual, newtarg),
++
++	    TP_STRUCT__entry(
++		    __field(unsigned long, cpu_id    )
++		    __field(unsigned long, load      )
++		    __field(unsigned long, curtarg   )
++		    __field(unsigned long, curactual )
++		    __field(unsigned long, newtarg   )
++	    ),
++
++	    TP_fast_assign(
++		    __entry->cpu_id = cpu_id;
++		    __entry->load = load;
++		    __entry->curtarg = curtarg;
++		    __entry->curactual = curactual;
++		    __entry->newtarg = newtarg;
++	    ),
++
++	    TP_printk("cpu=%lu load=%lu cur=%lu actual=%lu targ=%lu",
++		      __entry->cpu_id, __entry->load, __entry->curtarg,
++		      __entry->curactual, __entry->newtarg)
++);
++
++DEFINE_EVENT(loadeval, cpufreq_interactive_target,
++	    TP_PROTO(unsigned long cpu_id, unsigned long load,
++		     unsigned long curtarg, unsigned long curactual,
++		     unsigned long newtarg),
++	    TP_ARGS(cpu_id, load, curtarg, curactual, newtarg)
++);
++
++DEFINE_EVENT(loadeval, cpufreq_interactive_already,
++	    TP_PROTO(unsigned long cpu_id, unsigned long load,
++		     unsigned long curtarg, unsigned long curactual,
++		     unsigned long newtarg),
++	    TP_ARGS(cpu_id, load, curtarg, curactual, newtarg)
++);
++
++DEFINE_EVENT(loadeval, cpufreq_interactive_notyet,
++	    TP_PROTO(unsigned long cpu_id, unsigned long load,
++		     unsigned long curtarg, unsigned long curactual,
++		     unsigned long newtarg),
++	    TP_ARGS(cpu_id, load, curtarg, curactual, newtarg)
++);
++
++TRACE_EVENT(cpufreq_interactive_boost,
++	    TP_PROTO(const char *s),
++	    TP_ARGS(s),
++	    TP_STRUCT__entry(
++		    __string(s, s)
++	    ),
++	    TP_fast_assign(
++		    __assign_str(s, s);
++	    ),
++	    TP_printk("%s", __get_str(s))
++);
++
++TRACE_EVENT(cpufreq_interactive_unboost,
++	    TP_PROTO(const char *s),
++	    TP_ARGS(s),
++	    TP_STRUCT__entry(
++		    __string(s, s)
++	    ),
++	    TP_fast_assign(
++		    __assign_str(s, s);
++	    ),
++	    TP_printk("%s", __get_str(s))
++);
++
++#endif /* _TRACE_CPUFREQ_INTERACTIVE_H */
++
++/* This part must be outside protection */
++#include <trace/define_trace.h>
+diff --git a/include/trace/events/gpu.h b/include/trace/events/gpu.h
+new file mode 100644
+index 0000000..7e15cdf
+--- /dev/null
++++ b/include/trace/events/gpu.h
+@@ -0,0 +1,143 @@
++#undef TRACE_SYSTEM
++#define TRACE_SYSTEM gpu
++
++#if !defined(_TRACE_GPU_H) || defined(TRACE_HEADER_MULTI_READ)
++#define _TRACE_GPU_H
++
++#include <linux/tracepoint.h>
++#include <linux/time.h>
++
++#define show_secs_from_ns(ns) \
++	({ \
++		u64 t = ns + (NSEC_PER_USEC / 2); \
++		do_div(t, NSEC_PER_SEC); \
++		t; \
++	})
++
++#define show_usecs_from_ns(ns) \
++	({ \
++		u64 t = ns + (NSEC_PER_USEC / 2) ; \
++		u32 rem; \
++		do_div(t, NSEC_PER_USEC); \
++		rem = do_div(t, USEC_PER_SEC); \
++	})
++
++/*
++ * The gpu_sched_switch event indicates that a switch from one GPU context to
++ * another occurred on one of the GPU hardware blocks.
++ *
++ * The gpu_name argument identifies the GPU hardware block.  Each independently
++ * scheduled GPU hardware block should have a different name.  This may be used
++ * in different ways for different GPUs.  For example, if a GPU includes
++ * multiple processing cores it may use names "GPU 0", "GPU 1", etc.  If a GPU
++ * includes a separately scheduled 2D and 3D hardware block, it might use the
++ * names "2D" and "3D".
++ *
++ * The timestamp argument is the timestamp at which the switch occurred on the
++ * GPU. These timestamps are in units of nanoseconds and must use
++ * approximately the same time as sched_clock, though they need not come from
++ * any CPU clock. The timestamps for a single hardware block must be
++ * monotonically nondecreasing.  This means that if a variable compensation
++ * offset is used to translate from some other clock to the sched_clock, then
++ * care must be taken when increasing that offset, and doing so may result in
++ * multiple events with the same timestamp.
++ *
++ * The next_ctx_id argument identifies the next context that was running on
++ * the GPU hardware block.  A value of 0 indicates that the hardware block
++ * will be idle.
++ *
++ * The next_prio argument indicates the priority of the next context at the
++ * time of the event.  The exact numeric values may mean different things for
++ * different GPUs, but they should follow the rule that lower values indicate a
++ * higher priority.
++ *
++ * The next_job_id argument identifies the batch of work that the GPU will be
++ * working on.  This should correspond to a job_id that was previously traced
++ * as a gpu_job_enqueue event when the batch of work was created.
++ */
++TRACE_EVENT(gpu_sched_switch,
++
++	TP_PROTO(const char *gpu_name, u64 timestamp,
++		u32 next_ctx_id, s32 next_prio, u32 next_job_id),
++
++	TP_ARGS(gpu_name, timestamp, next_ctx_id, next_prio, next_job_id),
++
++	TP_STRUCT__entry(
++		__string(       gpu_name,       gpu_name        )
++		__field(        u64,            timestamp       )
++		__field(        u32,            next_ctx_id     )
++		__field(        s32,            next_prio       )
++		__field(        u32,            next_job_id     )
++	),
++
++	TP_fast_assign(
++		__assign_str(gpu_name, gpu_name);
++		__entry->timestamp = timestamp;
++		__entry->next_ctx_id = next_ctx_id;
++		__entry->next_prio = next_prio;
++		__entry->next_job_id = next_job_id;
++	),
++
++	TP_printk("gpu_name=%s ts=%llu.%06lu next_ctx_id=%lu next_prio=%ld "
++		"next_job_id=%lu",
++		__get_str(gpu_name),
++		(unsigned long long)show_secs_from_ns(__entry->timestamp),
++		(unsigned long)show_usecs_from_ns(__entry->timestamp),
++		(unsigned long)__entry->next_ctx_id,
++		(long)__entry->next_prio,
++		(unsigned long)__entry->next_job_id)
++);
++
++/*
++ * The gpu_job_enqueue event indicates that a batch of work has been queued up
++ * to be processed by the GPU.  This event is not intended to indicate that
++ * the batch of work has been submitted to the GPU hardware, but rather that
++ * it has been submitted to the GPU kernel driver.
++ *
++ * This event should be traced on the thread that initiated the work being
++ * queued.  For example, if a batch of work is submitted to the kernel by a
++ * userland thread, the event should be traced on that thread.
++ *
++ * The ctx_id field identifies the GPU context in which the batch of work
++ * being queued is to be run.
++ *
++ * The job_id field identifies the batch of work being queued within the given
++ * GPU context.  The first batch of work submitted for a given GPU context
++ * should have a job_id of 0, and each subsequent batch of work should
++ * increment the job_id by 1.
++ *
++ * The type field identifies the type of the job being enqueued.  The job
++ * types may be different for different GPU hardware.  For example, a GPU may
++ * differentiate between "2D", "3D", and "compute" jobs.
++ */
++TRACE_EVENT(gpu_job_enqueue,
++
++	TP_PROTO(u32 ctx_id, u32 job_id, const char *type),
++
++	TP_ARGS(ctx_id, job_id, type),
++
++	TP_STRUCT__entry(
++		__field(        u32,            ctx_id          )
++		__field(        u32,            job_id          )
++		__string(       type,           type            )
++	),
++
++	TP_fast_assign(
++		__entry->ctx_id = ctx_id;
++		__entry->job_id = job_id;
++		__assign_str(type, type);
++	),
++
++	TP_printk("ctx_id=%lu job_id=%lu type=%s",
++		(unsigned long)__entry->ctx_id,
++		(unsigned long)__entry->job_id,
++		__get_str(type))
++);
++
++#undef show_secs_from_ns
++#undef show_usecs_from_ns
++
++#endif /* _TRACE_GPU_H */
++
++/* This part must be outside protection */
++#include <trace/define_trace.h>
+diff --git a/include/trace/events/mmc.h b/include/trace/events/mmc.h
+new file mode 100644
+index 0000000..82b368d
+--- /dev/null
++++ b/include/trace/events/mmc.h
+@@ -0,0 +1,91 @@
++/*
++ * Copyright (C) 2013 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * 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.
++ *
++ */
++
++#undef TRACE_SYSTEM
++#define TRACE_SYSTEM mmc
++
++#if !defined(_TRACE_MMC_H) || defined(TRACE_HEADER_MULTI_READ)
++#define _TRACE_MMC_H
++
++#include <linux/tracepoint.h>
++#include <linux/mmc/mmc.h>
++#include <linux/mmc/core.h>
++
++/*
++ * Unconditional logging of mmc block erase operations,
++ * including cmd, address, size
++ */
++DECLARE_EVENT_CLASS(mmc_blk_erase_class,
++	TP_PROTO(unsigned int cmd, unsigned int addr, unsigned int size),
++	TP_ARGS(cmd, addr, size),
++	TP_STRUCT__entry(
++		__field(unsigned int, cmd)
++		__field(unsigned int, addr)
++		__field(unsigned int, size)
++	),
++	TP_fast_assign(
++		__entry->cmd = cmd;
++		__entry->addr = addr;
++		__entry->size = size;
++	),
++	TP_printk("cmd=%u,addr=0x%08x,size=0x%08x",
++		  __entry->cmd, __entry->addr, __entry->size)
++);
++
++DEFINE_EVENT(mmc_blk_erase_class, mmc_blk_erase_start,
++	TP_PROTO(unsigned int cmd, unsigned int addr, unsigned int size),
++	TP_ARGS(cmd, addr, size));
++
++DEFINE_EVENT(mmc_blk_erase_class, mmc_blk_erase_end,
++	TP_PROTO(unsigned int cmd, unsigned int addr, unsigned int size),
++	TP_ARGS(cmd, addr, size));
++
++/*
++ * Logging of start of read or write mmc block operation,
++ * including cmd, address, size
++ */
++DECLARE_EVENT_CLASS(mmc_blk_rw_class,
++	TP_PROTO(unsigned int cmd, unsigned int addr, struct mmc_data *data),
++	TP_ARGS(cmd, addr, data),
++	TP_STRUCT__entry(
++		__field(unsigned int, cmd)
++		__field(unsigned int, addr)
++		__field(unsigned int, size)
++	),
++	TP_fast_assign(
++		__entry->cmd = cmd;
++		__entry->addr = addr;
++		__entry->size = data->blocks;
++	),
++	TP_printk("cmd=%u,addr=0x%08x,size=0x%08x",
++		  __entry->cmd, __entry->addr, __entry->size)
++);
++
++DEFINE_EVENT_CONDITION(mmc_blk_rw_class, mmc_blk_rw_start,
++	TP_PROTO(unsigned int cmd, unsigned int addr, struct mmc_data *data),
++	TP_ARGS(cmd, addr, data),
++	TP_CONDITION(((cmd == MMC_READ_MULTIPLE_BLOCK) ||
++		      (cmd == MMC_WRITE_MULTIPLE_BLOCK)) &&
++		      data));
++
++DEFINE_EVENT_CONDITION(mmc_blk_rw_class, mmc_blk_rw_end,
++	TP_PROTO(unsigned int cmd, unsigned int addr, struct mmc_data *data),
++	TP_ARGS(cmd, addr, data),
++	TP_CONDITION(((cmd == MMC_READ_MULTIPLE_BLOCK) ||
++		      (cmd == MMC_WRITE_MULTIPLE_BLOCK)) &&
++		      data));
++#endif /* _TRACE_MMC_H */
++
++/* This part must be outside protection */
++#include <trace/define_trace.h>
+diff --git a/include/trace/events/power.h b/include/trace/events/power.h
+index d19840b..2740212 100644
+--- a/include/trace/events/power.h
++++ b/include/trace/events/power.h
+@@ -264,6 +264,25 @@ DEFINE_EVENT(clock, clock_set_rate,
+ 	TP_ARGS(name, state, cpu_id)
+ );
+ 
++TRACE_EVENT(clock_set_parent,
++
++	TP_PROTO(const char *name, const char *parent_name),
++
++	TP_ARGS(name, parent_name),
++
++	TP_STRUCT__entry(
++		__string(       name,           name            )
++		__string(       parent_name,    parent_name     )
++	),
++
++	TP_fast_assign(
++		__assign_str(name, name);
++		__assign_str(parent_name, parent_name);
++	),
++
++	TP_printk("%s parent=%s", __get_str(name), __get_str(parent_name))
++);
++
+ /*
+  * The power domain events are used for power domains transitions
+  */
+diff --git a/include/trace/events/sched.h b/include/trace/events/sched.h
+index a7d67bc..41221f8 100644
+--- a/include/trace/events/sched.h
++++ b/include/trace/events/sched.h
+@@ -443,6 +443,156 @@ TRACE_EVENT(sched_process_hang,
+ );
+ #endif /* CONFIG_DETECT_HUNG_TASK */
+ 
++
++/*
++ * Tracepoint for showing tracked load contribution.
++ */
++TRACE_EVENT(sched_task_load_contrib,
++
++	TP_PROTO(struct task_struct *tsk, unsigned long load_contrib),
++
++	TP_ARGS(tsk, load_contrib),
++
++	TP_STRUCT__entry(
++		__array(char, comm, TASK_COMM_LEN)
++		__field(pid_t, pid)
++		__field(unsigned long, load_contrib)
++	),
++
++	TP_fast_assign(
++		memcpy(__entry->comm, tsk->comm, TASK_COMM_LEN);
++		__entry->pid            = tsk->pid;
++		__entry->load_contrib   = load_contrib;
++	),
++
++	TP_printk("comm=%s pid=%d load_contrib=%lu",
++			__entry->comm, __entry->pid,
++			__entry->load_contrib)
++);
++
++/*
++ * Tracepoint for showing tracked task runnable ratio [0..1023].
++ */
++TRACE_EVENT(sched_task_runnable_ratio,
++
++	TP_PROTO(struct task_struct *tsk, unsigned long ratio),
++
++	TP_ARGS(tsk, ratio),
++
++	TP_STRUCT__entry(
++		__array(char, comm, TASK_COMM_LEN)
++		__field(pid_t, pid)
++		__field(unsigned long, ratio)
++	),
++
++	TP_fast_assign(
++	memcpy(__entry->comm, tsk->comm, TASK_COMM_LEN);
++		__entry->pid   = tsk->pid;
++		__entry->ratio = ratio;
++	),
++
++	TP_printk("comm=%s pid=%d ratio=%lu",
++			__entry->comm, __entry->pid,
++			__entry->ratio)
++);
++
++/*
++ * Tracepoint for showing tracked rq runnable ratio [0..1023].
++ */
++TRACE_EVENT(sched_rq_runnable_ratio,
++
++	TP_PROTO(int cpu, unsigned long ratio),
++
++	TP_ARGS(cpu, ratio),
++
++	TP_STRUCT__entry(
++		__field(int, cpu)
++		__field(unsigned long, ratio)
++	),
++
++	TP_fast_assign(
++		__entry->cpu   = cpu;
++		__entry->ratio = ratio;
++	),
++
++	TP_printk("cpu=%d ratio=%lu",
++			__entry->cpu,
++			__entry->ratio)
++);
++
++/*
++ * Tracepoint for showing tracked rq runnable load.
++ */
++TRACE_EVENT(sched_rq_runnable_load,
++
++	TP_PROTO(int cpu, u64 load),
++
++	TP_ARGS(cpu, load),
++
++	TP_STRUCT__entry(
++		__field(int, cpu)
++		__field(u64, load)
++	),
++
++	TP_fast_assign(
++		__entry->cpu  = cpu;
++		__entry->load = load;
++	),
++
++	TP_printk("cpu=%d load=%llu",
++			__entry->cpu,
++			__entry->load)
++);
++
++TRACE_EVENT(sched_rq_nr_running,
++
++	TP_PROTO(int cpu, unsigned int nr_running, int nr_iowait),
++
++	TP_ARGS(cpu, nr_running, nr_iowait),
++
++	TP_STRUCT__entry(
++		__field(int, cpu)
++		__field(unsigned int, nr_running)
++		__field(int, nr_iowait)
++	),
++
++	TP_fast_assign(
++		__entry->cpu  = cpu;
++		__entry->nr_running = nr_running;
++		__entry->nr_iowait = nr_iowait;
++	),
++
++	TP_printk("cpu=%d nr_running=%u nr_iowait=%d",
++			__entry->cpu,
++			__entry->nr_running, __entry->nr_iowait)
++);
++
++/*
++ * Tracepoint for showing tracked task cpu usage ratio [0..1023].
++ */
++TRACE_EVENT(sched_task_usage_ratio,
++
++	TP_PROTO(struct task_struct *tsk, unsigned long ratio),
++
++	TP_ARGS(tsk, ratio),
++
++	TP_STRUCT__entry(
++		__array(char, comm, TASK_COMM_LEN)
++		__field(pid_t, pid)
++		__field(unsigned long, ratio)
++	),
++
++	TP_fast_assign(
++	memcpy(__entry->comm, tsk->comm, TASK_COMM_LEN);
++		__entry->pid   = tsk->pid;
++		__entry->ratio = ratio;
++	),
++
++	TP_printk("comm=%s pid=%d ratio=%lu",
++			__entry->comm, __entry->pid,
++			__entry->ratio)
++);
++
+ DECLARE_EVENT_CLASS(sched_move_task_template,
+ 
+ 	TP_PROTO(struct task_struct *tsk, int src_cpu, int dst_cpu),
+@@ -550,6 +700,132 @@ TRACE_EVENT(sched_wake_idle_without_ipi,
+ 
+ 	TP_printk("cpu=%d", __entry->cpu)
+ );
++
++/*
++ * Tracepoint for HMP (CONFIG_SCHED_HMP) task migrations,
++ * marking the forced transition of runnable or running tasks.
++ */
++TRACE_EVENT(sched_hmp_migrate_force_running,
++
++	TP_PROTO(struct task_struct *tsk, int running),
++
++	TP_ARGS(tsk, running),
++
++	TP_STRUCT__entry(
++		__array(char, comm, TASK_COMM_LEN)
++		__field(int, running)
++	),
++
++	TP_fast_assign(
++		memcpy(__entry->comm, tsk->comm, TASK_COMM_LEN);
++		__entry->running = running;
++	),
++
++	TP_printk("running=%d comm=%s",
++		__entry->running, __entry->comm)
++);
++
++/*
++ * Tracepoint for HMP (CONFIG_SCHED_HMP) task migrations,
++ * marking the forced transition of runnable or running
++ * tasks when a task is about to go idle.
++ */
++TRACE_EVENT(sched_hmp_migrate_idle_running,
++
++	TP_PROTO(struct task_struct *tsk, int running),
++
++	TP_ARGS(tsk, running),
++
++	TP_STRUCT__entry(
++		__array(char, comm, TASK_COMM_LEN)
++		__field(int, running)
++	),
++
++	TP_fast_assign(
++		memcpy(__entry->comm, tsk->comm, TASK_COMM_LEN);
++		__entry->running = running;
++	),
++
++	TP_printk("running=%d comm=%s",
++		__entry->running, __entry->comm)
++);
++
++/*
++ * Tracepoint for HMP (CONFIG_SCHED_HMP) task migrations.
++ */
++#define HMP_MIGRATE_WAKEUP 0
++#define HMP_MIGRATE_FORCE  1
++#define HMP_MIGRATE_OFFLOAD 2
++#define HMP_MIGRATE_IDLE_PULL 3
++TRACE_EVENT(sched_hmp_migrate,
++
++	TP_PROTO(struct task_struct *tsk, int dest, int force),
++
++	TP_ARGS(tsk, dest, force),
++
++	TP_STRUCT__entry(
++		__array(char, comm, TASK_COMM_LEN)
++		__field(pid_t, pid)
++		__field(int,  dest)
++		__field(int,  force)
++	),
++
++	TP_fast_assign(
++	memcpy(__entry->comm, tsk->comm, TASK_COMM_LEN);
++		__entry->pid   = tsk->pid;
++		__entry->dest  = dest;
++		__entry->force = force;
++	),
++
++	TP_printk("comm=%s pid=%d dest=%d force=%d",
++			__entry->comm, __entry->pid,
++			__entry->dest, __entry->force)
++);
++
++TRACE_EVENT(sched_hmp_offload_abort,
++
++	TP_PROTO(int cpu, int data, char *label),
++
++	TP_ARGS(cpu, data, label),
++
++	TP_STRUCT__entry(
++		__array(char, label, 64)
++		__field(int, cpu)
++		__field(int, data)
++	),
++
++	TP_fast_assign(
++		strncpy(__entry->label, label, 64);
++		__entry->cpu   = cpu;
++		__entry->data = data;
++	),
++
++	TP_printk("cpu=%d data=%d label=%63s",
++			__entry->cpu, __entry->data,
++			__entry->label)
++);
++
++TRACE_EVENT(sched_hmp_offload_succeed,
++
++	TP_PROTO(int cpu, int dest_cpu),
++
++	TP_ARGS(cpu, dest_cpu),
++
++	TP_STRUCT__entry(
++		__field(int, cpu)
++		__field(int, dest_cpu)
++	),
++
++	TP_fast_assign(
++		__entry->cpu   = cpu;
++		__entry->dest_cpu = dest_cpu;
++	),
++
++	TP_printk("cpu=%d dest=%d",
++			__entry->cpu,
++			__entry->dest_cpu)
++);
++
+ #endif /* _TRACE_SCHED_H */
+ 
+ /* This part must be outside protection */
+diff --git a/include/trace/events/thermal.h b/include/trace/events/thermal.h
+index 0f4f95d..8b1f806 100644
+--- a/include/trace/events/thermal.h
++++ b/include/trace/events/thermal.h
+@@ -77,6 +77,64 @@ TRACE_EVENT(thermal_zone_trip,
+ 		__entry->trip_type)
+ );
+ 
++TRACE_EVENT(thermal_power_cpu_get_power,
++	TP_PROTO(const struct cpumask *cpus, unsigned long freq, u32 *load,
++		size_t load_len, u32 dynamic_power, u32 static_power),
++
++	TP_ARGS(cpus, freq, load, load_len, dynamic_power, static_power),
++
++	TP_STRUCT__entry(
++		__bitmask(cpumask, num_possible_cpus())
++		__field(unsigned long, freq          )
++		__dynamic_array(u32,   load, load_len)
++		__field(size_t,        load_len      )
++		__field(u32,           dynamic_power )
++		__field(u32,           static_power  )
++	),
++
++	TP_fast_assign(
++		__assign_bitmask(cpumask, cpumask_bits(cpus),
++				num_possible_cpus());
++		__entry->freq = freq;
++		memcpy(__get_dynamic_array(load), load,
++			load_len * sizeof(*load));
++		__entry->load_len = load_len;
++		__entry->dynamic_power = dynamic_power;
++		__entry->static_power = static_power;
++	),
++
++	TP_printk("cpus=%s freq=%lu load={%s} dynamic_power=%d static_power=%d",
++		__get_bitmask(cpumask), __entry->freq,
++		__print_array(__get_dynamic_array(load), __entry->load_len, 4),
++		__entry->dynamic_power, __entry->static_power)
++);
++
++TRACE_EVENT(thermal_power_cpu_limit,
++	TP_PROTO(const struct cpumask *cpus, unsigned int freq,
++		unsigned long cdev_state, u32 power),
++
++	TP_ARGS(cpus, freq, cdev_state, power),
++
++	TP_STRUCT__entry(
++		__bitmask(cpumask, num_possible_cpus())
++		__field(unsigned int,  freq      )
++		__field(unsigned long, cdev_state)
++		__field(u32,           power     )
++	),
++
++	TP_fast_assign(
++		__assign_bitmask(cpumask, cpumask_bits(cpus),
++				num_possible_cpus());
++		__entry->freq = freq;
++		__entry->cdev_state = cdev_state;
++		__entry->power = power;
++	),
++
++	TP_printk("cpus=%s freq=%u cdev_state=%lu power=%u",
++		__get_bitmask(cpumask), __entry->freq, __entry->cdev_state,
++		__entry->power)
++);
++
+ #endif /* _TRACE_THERMAL_H */
+ 
+ /* This part must be outside protection */
+diff --git a/include/trace/events/thermal_power_allocator.h b/include/trace/events/thermal_power_allocator.h
+new file mode 100644
+index 0000000..12e1321
+--- /dev/null
++++ b/include/trace/events/thermal_power_allocator.h
+@@ -0,0 +1,87 @@
++#undef TRACE_SYSTEM
++#define TRACE_SYSTEM thermal_power_allocator
++
++#if !defined(_TRACE_THERMAL_POWER_ALLOCATOR_H) || defined(TRACE_HEADER_MULTI_READ)
++#define _TRACE_THERMAL_POWER_ALLOCATOR_H
++
++#include <linux/tracepoint.h>
++
++TRACE_EVENT(thermal_power_allocator,
++	TP_PROTO(struct thermal_zone_device *tz, u32 *req_power,
++		 u32 total_req_power, u32 *granted_power,
++		 u32 total_granted_power, size_t num_actors,
++		 u32 power_range, u32 max_allocatable_power,
++		 unsigned long current_temp, s32 delta_temp),
++	TP_ARGS(tz, req_power, total_req_power, granted_power,
++		total_granted_power, num_actors, power_range,
++		max_allocatable_power, current_temp, delta_temp),
++	TP_STRUCT__entry(
++		__field(int,           tz_id          )
++		__dynamic_array(u32,   req_power, num_actors    )
++		__field(u32,           total_req_power          )
++		__dynamic_array(u32,   granted_power, num_actors)
++		__field(u32,           total_granted_power      )
++		__field(size_t,        num_actors               )
++		__field(u32,           power_range              )
++		__field(u32,           max_allocatable_power    )
++		__field(unsigned long, current_temp             )
++		__field(s32,           delta_temp               )
++	),
++	TP_fast_assign(
++		__entry->tz_id = tz->id;
++		memcpy(__get_dynamic_array(req_power), req_power,
++			num_actors * sizeof(*req_power));
++		__entry->total_req_power = total_req_power;
++		memcpy(__get_dynamic_array(granted_power), granted_power,
++			num_actors * sizeof(*granted_power));
++		__entry->total_granted_power = total_granted_power;
++		__entry->num_actors = num_actors;
++		__entry->power_range = power_range;
++		__entry->max_allocatable_power = max_allocatable_power;
++		__entry->current_temp = current_temp;
++		__entry->delta_temp = delta_temp;
++	),
++
++	TP_printk("thermal_zone_id=%d req_power={%s} total_req_power=%u granted_power={%s} total_granted_power=%u power_range=%u max_allocatable_power=%u current_temperature=%lu delta_temperature=%d",
++		__entry->tz_id,
++		__print_array(__get_dynamic_array(req_power),
++                              __entry->num_actors, 4),
++		__entry->total_req_power,
++		__print_array(__get_dynamic_array(granted_power),
++                              __entry->num_actors, 4),
++		__entry->total_granted_power, __entry->power_range,
++		__entry->max_allocatable_power, __entry->current_temp,
++		__entry->delta_temp)
++);
++
++TRACE_EVENT(thermal_power_allocator_pid,
++	TP_PROTO(struct thermal_zone_device *tz, s32 err, s32 err_integral,
++		 s64 p, s64 i, s64 d, s32 output),
++	TP_ARGS(tz, err, err_integral, p, i, d, output),
++	TP_STRUCT__entry(
++		__field(int, tz_id       )
++		__field(s32, err         )
++		__field(s32, err_integral)
++		__field(s64, p           )
++		__field(s64, i           )
++		__field(s64, d           )
++		__field(s32, output      )
++	),
++	TP_fast_assign(
++		__entry->tz_id = tz->id;
++		__entry->err = err;
++		__entry->err_integral = err_integral;
++		__entry->p = p;
++		__entry->i = i;
++		__entry->d = d;
++		__entry->output = output;
++	),
++
++	TP_printk("thermal_zone_id=%d err=%d err_integral=%d p=%lld i=%lld d=%lld output=%d",
++		  __entry->tz_id, __entry->err, __entry->err_integral,
++		  __entry->p, __entry->i, __entry->d, __entry->output)
++);
++#endif /* _TRACE_THERMAL_POWER_ALLOCATOR_H */
++
++/* This part must be outside protection */
++#include <trace/define_trace.h>
+diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h
+index 26b4f2e..f5d9371 100644
+--- a/include/trace/ftrace.h
++++ b/include/trace/ftrace.h
+@@ -263,6 +263,14 @@
+ #undef __print_hex
+ #define __print_hex(buf, buf_len) ftrace_print_hex_seq(p, buf, buf_len)
+ 
++#undef __print_array
++#define __print_array(array, count, el_size)				\
++	({								\
++		BUILD_BUG_ON(el_size != 1 && el_size != 2 &&		\
++			     el_size != 4 && el_size != 8);		\
++		ftrace_print_array_seq(p, array, count, el_size);	\
++	})
++
+ #undef DECLARE_EVENT_CLASS
+ #define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print)	\
+ static notrace enum print_line_t					\
+@@ -676,6 +684,7 @@ static inline void ftrace_test_probe_##call(void)			\
+ #undef __get_dynamic_array_len
+ #undef __get_str
+ #undef __get_bitmask
++#undef __print_array
+ 
+ #undef TP_printk
+ #define TP_printk(fmt, args...) "\"" fmt "\", "  __stringify(args)
+diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild
+index 8523f9b..fe47395 100644
+--- a/include/uapi/linux/Kbuild
++++ b/include/uapi/linux/Kbuild
+@@ -383,6 +383,7 @@ header-y += tcp.h
+ header-y += tcp_metrics.h
+ header-y += telephony.h
+ header-y += termios.h
++header-y += thermal.h
+ header-y += time.h
+ header-y += times.h
+ header-y += timex.h
+diff --git a/include/uapi/linux/elf.h b/include/uapi/linux/elf.h
+index ea9bf25..71e1d0e 100644
+--- a/include/uapi/linux/elf.h
++++ b/include/uapi/linux/elf.h
+@@ -397,6 +397,7 @@ typedef struct elf64_shdr {
+ #define NT_ARM_TLS	0x401		/* ARM TLS register */
+ #define NT_ARM_HW_BREAK	0x402		/* ARM hardware breakpoint registers */
+ #define NT_ARM_HW_WATCH	0x403		/* ARM hardware watchpoint registers */
++#define NT_ARM_SYSTEM_CALL	0x404	/* ARM system call number */
+ #define NT_METAG_CBUF	0x500		/* Metag catch buffer registers */
+ #define NT_METAG_RPIPE	0x501		/* Metag read pipeline state */
+ #define NT_METAG_TLS	0x502		/* Metag TLS pointer */
+diff --git a/include/uapi/linux/falloc.h b/include/uapi/linux/falloc.h
+index d1197ae..3e445a7 100644
+--- a/include/uapi/linux/falloc.h
++++ b/include/uapi/linux/falloc.h
+@@ -41,4 +41,21 @@
+  */
+ #define FALLOC_FL_ZERO_RANGE		0x10
+ 
++/*
++ * FALLOC_FL_INSERT_RANGE is use to insert space within the file size without
++ * overwriting any existing data. The contents of the file beyond offset are
++ * shifted towards right by len bytes to create a hole.  As such, this
++ * operation will increase the size of the file by len bytes.
++ *
++ * Different filesystems may implement different limitations on the granularity
++ * of the operation. Most will limit operations to filesystem block size
++ * boundaries, but this boundary may be larger or smaller depending on
++ * the filesystem and/or the configuration of the filesystem or file.
++ *
++ * Attempting to insert space using this flag at OR beyond the end of
++ * the file is considered an illegal operation - just use ftruncate(2) or
++ * fallocate(2) with mode 0 for such type of operations.
++ */
++#define FALLOC_FL_INSERT_RANGE		0x20
++
+ #endif /* _UAPI_FALLOC_H_ */
+diff --git a/include/uapi/linux/fib_rules.h b/include/uapi/linux/fib_rules.h
+index 2b82d7e..743e300 100644
+--- a/include/uapi/linux/fib_rules.h
++++ b/include/uapi/linux/fib_rules.h
+@@ -49,6 +49,8 @@ enum {
+ 	FRA_TABLE,	/* Extended table id */
+ 	FRA_FWMASK,	/* mask for netfilter mark */
+ 	FRA_OIFNAME,
++	FRA_UID_START,	/* UID range */
++	FRA_UID_END,
+ 	__FRA_MAX
+ };
+ 
+diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h
+index 3735fa0..48e59f9 100644
+--- a/include/uapi/linux/fs.h
++++ b/include/uapi/linux/fs.h
+@@ -158,6 +158,8 @@ struct inodes_stat_t {
+ #define FITHAW		_IOWR('X', 120, int)	/* Thaw */
+ #define FITRIM		_IOWR('X', 121, struct fstrim_range)	/* Trim */
+ 
++#define FIDTRIM	_IOWR('f', 128, struct fstrim_range)	/* Deep discard trim */
++
+ #define	FS_IOC_GETFLAGS			_IOR('f', 1, long)
+ #define	FS_IOC_SETFLAGS			_IOW('f', 2, long)
+ #define	FS_IOC_GETVERSION		_IOR('v', 1, long)
+diff --git a/include/uapi/linux/i2c-dev.h b/include/uapi/linux/i2c-dev.h
+index 3f31155..f864909 100644
+--- a/include/uapi/linux/i2c-dev.h
++++ b/include/uapi/linux/i2c-dev.h
+@@ -50,7 +50,9 @@
+ 
+ #define I2C_PEC		0x0708	/* != 0 to use PEC with SMBus */
+ #define I2C_SMBUS	0x0720	/* SMBus transfer */
+-
++#define I2C_16BIT_REG   0x0709  /* 16BIT REG WIDTH */
++#define I2C_16BIT_DATA  0x070a  /* 16BIT DATA WIDTH */
++#define I2C_DMA     0x070b  /* DMA mode */
+ 
+ /* This is the structure as used in the I2C_SMBUS ioctl call */
+ struct i2c_smbus_ioctl_data {
+diff --git a/include/uapi/linux/i2c.h b/include/uapi/linux/i2c.h
+index 0e949cb..c48d3d2 100644
+--- a/include/uapi/linux/i2c.h
++++ b/include/uapi/linux/i2c.h
+@@ -76,6 +76,9 @@ struct i2c_msg {
+ #define I2C_M_IGNORE_NAK	0x1000	/* if I2C_FUNC_PROTOCOL_MANGLING */
+ #define I2C_M_NO_RD_ACK		0x0800	/* if I2C_FUNC_PROTOCOL_MANGLING */
+ #define I2C_M_RECV_LEN		0x0400	/* length will be first received byte */
++#define I2C_M_16BIT_REG		0x0002	/* indicate reg bit-width is 16bit */
++#define I2C_M_16BIT_DATA	0x0008	/* indicate data bit-width is 16bit */
++#define I2C_M_DMA			0x0004  /* indicate use dma mode */
+ 	__u16 len;		/* msg length				*/
+ 	__u8 *buf;		/* pointer to msg data			*/
+ };
+diff --git a/include/uapi/linux/if_pppolac.h b/include/uapi/linux/if_pppolac.h
+new file mode 100644
+index 0000000..b7eb815
+--- /dev/null
++++ b/include/uapi/linux/if_pppolac.h
+@@ -0,0 +1,33 @@
++/* include/uapi/linux/if_pppolac.h
++ *
++ * Header for PPP on L2TP Access Concentrator / PPPoLAC Socket (RFC 2661)
++ *
++ * Copyright (C) 2009 Google, Inc.
++ * Author: Chia-chi Yeh <chiachi@android.com>
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#ifndef _UAPI_LINUX_IF_PPPOLAC_H
++#define _UAPI_LINUX_IF_PPPOLAC_H
++
++#include <linux/socket.h>
++#include <linux/types.h>
++
++struct sockaddr_pppolac {
++	sa_family_t	sa_family;	/* AF_PPPOX */
++	unsigned int	sa_protocol;	/* PX_PROTO_OLAC */
++	int		udp_socket;
++	struct __attribute__((packed)) {
++		__u16	tunnel, session;
++	} local, remote;
++} __attribute__((packed));
++
++#endif /* _UAPI_LINUX_IF_PPPOLAC_H */
+diff --git a/include/uapi/linux/if_pppopns.h b/include/uapi/linux/if_pppopns.h
+new file mode 100644
+index 0000000..a392b52
+--- /dev/null
++++ b/include/uapi/linux/if_pppopns.h
+@@ -0,0 +1,32 @@
++/* include/uapi/linux/if_pppopns.h
++ *
++ * Header for PPP on PPTP Network Server / PPPoPNS Socket (RFC 2637)
++ *
++ * Copyright (C) 2009 Google, Inc.
++ * Author: Chia-chi Yeh <chiachi@android.com>
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#ifndef _UAPI_LINUX_IF_PPPOPNS_H
++#define _UAPI_LINUX_IF_PPPOPNS_H
++
++#include <linux/socket.h>
++#include <linux/types.h>
++
++struct sockaddr_pppopns {
++	sa_family_t	sa_family;	/* AF_PPPOX */
++	unsigned int	sa_protocol;	/* PX_PROTO_OPNS */
++	int		tcp_socket;
++	__u16		local;
++	__u16		remote;
++} __attribute__((packed));
++
++#endif /* _UAPI_LINUX_IF_PPPOPNS_H */
+diff --git a/include/uapi/linux/if_pppox.h b/include/uapi/linux/if_pppox.h
+index e128769..5861d45 100644
+--- a/include/uapi/linux/if_pppox.h
++++ b/include/uapi/linux/if_pppox.h
+@@ -23,6 +23,8 @@
+ #include <linux/socket.h>
+ #include <linux/if_ether.h>
+ #include <linux/if_pppol2tp.h>
++#include <linux/if_pppolac.h>
++#include <linux/if_pppopns.h>
+ 
+ /* For user-space programs to pick up these definitions
+  * which they wouldn't get otherwise without defining __KERNEL__
+@@ -56,7 +58,9 @@ struct pptp_addr {
+ #define PX_PROTO_OE    0 /* Currently just PPPoE */
+ #define PX_PROTO_OL2TP 1 /* Now L2TP also */
+ #define PX_PROTO_PPTP  2
+-#define PX_MAX_PROTO   3
++#define PX_PROTO_OLAC  3
++#define PX_PROTO_OPNS  4
++#define PX_MAX_PROTO   5
+ 
+ struct sockaddr_pppox {
+ 	__kernel_sa_family_t sa_family;       /* address family, AF_PPPOX */
+diff --git a/include/uapi/linux/input.h b/include/uapi/linux/input.h
+index a1d7e93..cc75b7b 100644
+--- a/include/uapi/linux/input.h
++++ b/include/uapi/linux/input.h
+@@ -152,7 +152,12 @@ struct input_keymap_entry {
+ #define EVIOCGEFFECTS		_IOR('E', 0x84, int)			/* Report number of effects playable at the same time */
+ 
+ #define EVIOCGRAB		_IOW('E', 0x90, int)			/* Grab/Release device */
+-#define EVIOCREVOKE		_IOW('E', 0x91, int)			/* Revoke device access */
++
++/* HACK: disable conflicting EVIOCREVOKE until Android userspace stops using EVIOCSSUSPENDBLOCK */
++/*#define EVIOCREVOKE		_IOW('E', 0x91, int)*/			/* Revoke device access */
++
++#define EVIOCGSUSPENDBLOCK	_IOR('E', 0x91, int)			/* get suspend block enable */
++#define EVIOCSSUSPENDBLOCK	_IOW('E', 0x91, int)			/* set suspend block enable */
+ 
+ #define EVIOCSCLOCKID		_IOW('E', 0xa0, int)			/* Set clockid to be used for timestamps */
+ 
+diff --git a/include/uapi/linux/ipv6.h b/include/uapi/linux/ipv6.h
+index efa2666..187d9f6 100644
+--- a/include/uapi/linux/ipv6.h
++++ b/include/uapi/linux/ipv6.h
+@@ -160,10 +160,12 @@ enum {
+ 	DEVCONF_ACCEPT_DAD,
+ 	DEVCONF_FORCE_TLLAO,
+ 	DEVCONF_NDISC_NOTIFY,
++	DEVCONF_ACCEPT_RA_RT_TABLE,
+ 	DEVCONF_MLDV1_UNSOLICITED_REPORT_INTERVAL,
+ 	DEVCONF_MLDV2_UNSOLICITED_REPORT_INTERVAL,
+ 	DEVCONF_SUPPRESS_FRAG_NDISC,
+ 	DEVCONF_ACCEPT_RA_FROM_LOCAL,
++	DEVCONF_USE_OPTIMISTIC,
+ 	DEVCONF_MAX
+ };
+ 
+diff --git a/include/uapi/linux/keychord.h b/include/uapi/linux/keychord.h
+new file mode 100644
+index 0000000..ea7cf4d
+--- /dev/null
++++ b/include/uapi/linux/keychord.h
+@@ -0,0 +1,52 @@
++/*
++ *  Key chord input driver
++ *
++ * Copyright (C) 2008 Google, Inc.
++ * Author: Mike Lockwood <lockwood@android.com>
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++*/
++
++#ifndef _UAPI_LINUX_KEYCHORD_H_
++#define _UAPI_LINUX_KEYCHORD_H_
++
++#include <linux/input.h>
++
++#define KEYCHORD_VERSION		1
++
++/*
++ * One or more input_keychord structs are written to /dev/keychord
++ * at once to specify the list of keychords to monitor.
++ * Reading /dev/keychord returns the id of a keychord when the
++ * keychord combination is pressed.  A keychord is signalled when
++ * all of the keys in the keycode list are in the pressed state.
++ * The order in which the keys are pressed does not matter.
++ * The keychord will not be signalled if keys not in the keycode
++ * list are pressed.
++ * Keychords will not be signalled on key release events.
++ */
++struct input_keychord {
++	/* should be KEYCHORD_VERSION */
++	__u16 version;
++	/*
++	 * client specified ID, returned from read()
++	 * when this keychord is pressed.
++	 */
++	__u16 id;
++
++	/* number of keycodes in this keychord */
++	__u16 count;
++
++	/* variable length array of keycodes */
++	__u16 keycodes[];
++};
++
++#endif	/* _UAPI_LINUX_KEYCHORD_H_ */
+diff --git a/include/uapi/linux/msdos_fs.h b/include/uapi/linux/msdos_fs.h
+index e284ff9..335004b 100644
+--- a/include/uapi/linux/msdos_fs.h
++++ b/include/uapi/linux/msdos_fs.h
+@@ -96,6 +96,22 @@ struct __fat_dirent {
+ 	char		d_name[256]; /* We must not include limits.h! */
+ };
+ 
++struct fat_direntall {
++	unsigned long   d_ino;
++	unsigned long   d_off;
++	unsigned char   d_type;
++	u64     d_size;
++	char    d_createtime[8];
++	unsigned short  d_reclen;
++	char        d_name[1];
++};
++
++struct fat_direntall_buf {
++	int d_count;
++	int d_usecount;
++	struct fat_direntall direntall;
++};
++
+ /*
+  * ioctl commands
+  */
+@@ -106,6 +122,7 @@ struct __fat_dirent {
+ #define FAT_IOCTL_SET_ATTRIBUTES	_IOW('r', 0x11, __u32)
+ /*Android kernel has used 0x12, so we use 0x13*/
+ #define FAT_IOCTL_GET_VOLUME_ID		_IOR('r', 0x13, __u32)
++#define VFAT_IOCTL_READDIR_ALL    _IOR('r', 0x14, struct fat_direntall_buf)
+ 
+ struct fat_boot_sector {
+ 	__u8	ignored[3];	/* Boot strap short or near jump */
+diff --git a/include/uapi/linux/netfilter/xt_IDLETIMER.h b/include/uapi/linux/netfilter/xt_IDLETIMER.h
+index 208ae93..faaa28b 100644
+--- a/include/uapi/linux/netfilter/xt_IDLETIMER.h
++++ b/include/uapi/linux/netfilter/xt_IDLETIMER.h
+@@ -4,6 +4,7 @@
+  * Header file for Xtables timer target module.
+  *
+  * Copyright (C) 2004, 2010 Nokia Corporation
++ *
+  * Written by Timo Teras <ext-timo.teras@nokia.com>
+  *
+  * Converted to x_tables and forward-ported to 2.6.34
+@@ -32,12 +33,19 @@
+ #include <linux/types.h>
+ 
+ #define MAX_IDLETIMER_LABEL_SIZE 28
++#define NLMSG_MAX_SIZE 64
++
++#define NL_EVENT_TYPE_INACTIVE 0
++#define NL_EVENT_TYPE_ACTIVE 1
+ 
+ struct idletimer_tg_info {
+ 	__u32 timeout;
+ 
+ 	char label[MAX_IDLETIMER_LABEL_SIZE];
+ 
++	/* Use netlink messages for notification in addition to sysfs */
++	__u8 send_nl_msg;
++
+ 	/* for kernel module internal use only */
+ 	struct idletimer_tg *timer __attribute__((aligned(8)));
+ };
+diff --git a/include/uapi/linux/netfilter/xt_dscp.h b/include/uapi/linux/netfilter/xt_dscp.h
+index 15f8932..648e0b3 100644
+--- a/include/uapi/linux/netfilter/xt_dscp.h
++++ b/include/uapi/linux/netfilter/xt_dscp.h
+@@ -1,31 +1,26 @@
+-/* x_tables module for matching the IPv4/IPv6 DSCP field
++/* x_tables module for setting the IPv4/IPv6 DSCP field
+  *
+  * (C) 2002 Harald Welte <laforge@gnumonks.org>
++ * based on ipt_FTOS.c (C) 2000 by Matthew G. Marsh <mgm@paktronix.com>
+  * This software is distributed under GNU GPL v2, 1991
+  *
+  * See RFC2474 for a description of the DSCP field within the IP Header.
+  *
+- * xt_dscp.h,v 1.3 2002/08/05 19:00:21 laforge Exp
++ * xt_DSCP.h,v 1.7 2002/03/14 12:03:13 laforge Exp
+ */
+-#ifndef _XT_DSCP_H
+-#define _XT_DSCP_H
+-
++#ifndef _XT_DSCP_TARGET_H
++#define _XT_DSCP_TARGET_H
++#include <linux/netfilter/xt_dscp.h>
+ #include <linux/types.h>
+ 
+-#define XT_DSCP_MASK	0xfc	/* 11111100 */
+-#define XT_DSCP_SHIFT	2
+-#define XT_DSCP_MAX	0x3f	/* 00111111 */
+-
+-/* match info */
+-struct xt_dscp_info {
++/* target info */
++struct xt_DSCP_info {
+ 	__u8 dscp;
+-	__u8 invert;
+ };
+ 
+-struct xt_tos_match_info {
+-	__u8 tos_mask;
++struct xt_tos_target_info {
+ 	__u8 tos_value;
+-	__u8 invert;
++	__u8 tos_mask;
+ };
+ 
+-#endif /* _XT_DSCP_H */
++#endif /* _XT_DSCP_TARGET_H */
+diff --git a/include/uapi/linux/netfilter/xt_rateest.h b/include/uapi/linux/netfilter/xt_rateest.h
+index d40a619..6605e20 100644
+--- a/include/uapi/linux/netfilter/xt_rateest.h
++++ b/include/uapi/linux/netfilter/xt_rateest.h
+@@ -1,37 +1,15 @@
+-#ifndef _XT_RATEEST_MATCH_H
+-#define _XT_RATEEST_MATCH_H
++#ifndef _XT_RATEEST_TARGET_H
++#define _XT_RATEEST_TARGET_H
+ 
+ #include <linux/types.h>
+ 
+-enum xt_rateest_match_flags {
+-	XT_RATEEST_MATCH_INVERT	= 1<<0,
+-	XT_RATEEST_MATCH_ABS	= 1<<1,
+-	XT_RATEEST_MATCH_REL	= 1<<2,
+-	XT_RATEEST_MATCH_DELTA	= 1<<3,
+-	XT_RATEEST_MATCH_BPS	= 1<<4,
+-	XT_RATEEST_MATCH_PPS	= 1<<5,
+-};
+-
+-enum xt_rateest_match_mode {
+-	XT_RATEEST_MATCH_NONE,
+-	XT_RATEEST_MATCH_EQ,
+-	XT_RATEEST_MATCH_LT,
+-	XT_RATEEST_MATCH_GT,
+-};
+-
+-struct xt_rateest_match_info {
+-	char			name1[IFNAMSIZ];
+-	char			name2[IFNAMSIZ];
+-	__u16		flags;
+-	__u16		mode;
+-	__u32		bps1;
+-	__u32		pps1;
+-	__u32		bps2;
+-	__u32		pps2;
++struct xt_rateest_target_info {
++	char			name[IFNAMSIZ];
++	__s8			interval;
++	__u8		ewma_log;
+ 
+ 	/* Used internally by the kernel */
+-	struct xt_rateest	*est1 __attribute__((aligned(8)));
+-	struct xt_rateest	*est2 __attribute__((aligned(8)));
++	struct xt_rateest	*est __attribute__((aligned(8)));
+ };
+ 
+-#endif /* _XT_RATEEST_MATCH_H */
++#endif /* _XT_RATEEST_TARGET_H */
+diff --git a/include/uapi/linux/netfilter/xt_socket.h b/include/uapi/linux/netfilter/xt_socket.h
+index 6315e2a..55076a3 100644
+--- a/include/uapi/linux/netfilter/xt_socket.h
++++ b/include/uapi/linux/netfilter/xt_socket.h
+@@ -18,4 +18,9 @@ struct xt_socket_mtinfo2 {
+ };
+ #define XT_SOCKET_FLAGS_V2 (XT_SOCKET_TRANSPARENT | XT_SOCKET_NOWILDCARD)
+ 
++struct sock *xt_socket_get4_sk(const struct sk_buff *skb,
++			       struct xt_action_param *par);
++struct sock *xt_socket_get6_sk(const struct sk_buff *skb,
++			       struct xt_action_param *par);
++
+ #endif /* _XT_SOCKET_H */
+diff --git a/include/uapi/linux/netfilter_ipv6/ip6t_hl.h b/include/uapi/linux/netfilter_ipv6/ip6t_hl.h
+index 6e76dbc..ebd8ead 100644
+--- a/include/uapi/linux/netfilter_ipv6/ip6t_hl.h
++++ b/include/uapi/linux/netfilter_ipv6/ip6t_hl.h
+@@ -1,6 +1,6 @@
+-/* ip6tables module for matching the Hop Limit value
++/* Hop Limit modification module for ip6tables
+  * Maciej Soltysiak <solt@dns.toxicfilms.tv>
+- * Based on HW's ttl module */
++ * Based on HW's TTL module */
+ 
+ #ifndef _IP6T_HL_H
+ #define _IP6T_HL_H
+@@ -8,14 +8,14 @@
+ #include <linux/types.h>
+ 
+ enum {
+-	IP6T_HL_EQ = 0,		/* equals */
+-	IP6T_HL_NE,		/* not equals */
+-	IP6T_HL_LT,		/* less than */
+-	IP6T_HL_GT,		/* greater than */
++	IP6T_HL_SET = 0,
++	IP6T_HL_INC,
++	IP6T_HL_DEC
+ };
+ 
++#define IP6T_HL_MAXMODE	IP6T_HL_DEC
+ 
+-struct ip6t_hl_info {
++struct ip6t_HL_info {
+ 	__u8	mode;
+ 	__u8	hop_limit;
+ };
+diff --git a/include/uapi/linux/prctl.h b/include/uapi/linux/prctl.h
+index 513df75..933ff2a 100644
+--- a/include/uapi/linux/prctl.h
++++ b/include/uapi/linux/prctl.h
+@@ -179,4 +179,13 @@ struct prctl_mm_map {
+ #define PR_SET_THP_DISABLE	41
+ #define PR_GET_THP_DISABLE	42
+ 
++/* Sets the timerslack for arbitrary threads
++ * arg2 slack value, 0 means "use default"
++ * arg3 pid of the thread whose timer slack needs to be set
++ */
++#define PR_SET_TIMERSLACK_PID 43
++
++#define PR_SET_VMA		0x53564d41
++# define PR_SET_VMA_ANON_NAME		0
++
+ #endif /* _LINUX_PRCTL_H */
+diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h
+index eb0f1a5..01757b7 100644
+--- a/include/uapi/linux/rtnetlink.h
++++ b/include/uapi/linux/rtnetlink.h
+@@ -297,6 +297,7 @@ enum rtattr_type_t {
+ 	RTA_TABLE,
+ 	RTA_MARK,
+ 	RTA_MFC_STATS,
++	RTA_UID,
+ 	__RTA_MAX
+ };
+ 
+diff --git a/include/uapi/linux/sockios.h b/include/uapi/linux/sockios.h
+index e888b1a..623e9aa 100644
+--- a/include/uapi/linux/sockios.h
++++ b/include/uapi/linux/sockios.h
+@@ -65,6 +65,7 @@
+ #define SIOCDIFADDR	0x8936		/* delete PA address		*/
+ #define	SIOCSIFHWBROADCAST	0x8937	/* set hardware broadcast addr	*/
+ #define SIOCGIFCOUNT	0x8938		/* get number of devices */
++#define SIOCKILLADDR	0x8939		/* kill sockets with this local addr */
+ 
+ #define SIOCGIFBR	0x8940		/* Bridging support		*/
+ #define SIOCSIFBR	0x8941		/* Set bridging options 	*/
+diff --git a/include/uapi/linux/thermal.h b/include/uapi/linux/thermal.h
+new file mode 100644
+index 0000000..ac55358
+--- /dev/null
++++ b/include/uapi/linux/thermal.h
+@@ -0,0 +1,35 @@
++#ifndef _UAPI_LINUX_THERMAL_H
++#define _UAPI_LINUX_THERMAL_H
++
++#define THERMAL_NAME_LENGTH	20
++
++/* Adding event notification support elements */
++#define THERMAL_GENL_FAMILY_NAME                "thermal_event"
++#define THERMAL_GENL_VERSION                    0x01
++#define THERMAL_GENL_MCAST_GROUP_NAME           "thermal_mc_grp"
++
++/* Events supported by Thermal Netlink */
++enum events {
++	THERMAL_AUX0,
++	THERMAL_AUX1,
++	THERMAL_CRITICAL,
++	THERMAL_DEV_FAULT,
++};
++
++/* attributes of thermal_genl_family */
++enum {
++	THERMAL_GENL_ATTR_UNSPEC,
++	THERMAL_GENL_ATTR_EVENT,
++	__THERMAL_GENL_ATTR_MAX,
++};
++#define THERMAL_GENL_ATTR_MAX (__THERMAL_GENL_ATTR_MAX - 1)
++
++/* commands supported by the thermal_genl_family */
++enum {
++	THERMAL_GENL_CMD_UNSPEC,
++	THERMAL_GENL_CMD_EVENT,
++	__THERMAL_GENL_CMD_MAX,
++};
++#define THERMAL_GENL_CMD_MAX (__THERMAL_GENL_CMD_MAX - 1)
++
++#endif /* _UAPI_LINUX_THERMAL_H */
+diff --git a/include/uapi/linux/usb/ch9.h b/include/uapi/linux/usb/ch9.h
+index aa33fd1..400196c 100644
+--- a/include/uapi/linux/usb/ch9.h
++++ b/include/uapi/linux/usb/ch9.h
+@@ -705,6 +705,7 @@ struct usb_interface_assoc_descriptor {
+ 	__u8  iFunction;
+ } __attribute__ ((packed));
+ 
++#define USB_DT_INTERFACE_ASSOCIATION_SIZE	8
+ 
+ /*-------------------------------------------------------------------------*/
+ 
+diff --git a/include/uapi/linux/usb/f_accessory.h b/include/uapi/linux/usb/f_accessory.h
+new file mode 100644
+index 0000000..0baeb7d
+--- /dev/null
++++ b/include/uapi/linux/usb/f_accessory.h
+@@ -0,0 +1,146 @@
++/*
++ * Gadget Function Driver for Android USB accessories
++ *
++ * Copyright (C) 2011 Google, Inc.
++ * Author: Mike Lockwood <lockwood@android.com>
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#ifndef _UAPI_LINUX_USB_F_ACCESSORY_H
++#define _UAPI_LINUX_USB_F_ACCESSORY_H
++
++/* Use Google Vendor ID when in accessory mode */
++#define USB_ACCESSORY_VENDOR_ID 0x18D1
++
++
++/* Product ID to use when in accessory mode */
++#define USB_ACCESSORY_PRODUCT_ID 0x2D00
++
++/* Product ID to use when in accessory mode and adb is enabled */
++#define USB_ACCESSORY_ADB_PRODUCT_ID 0x2D01
++
++/* Indexes for strings sent by the host via ACCESSORY_SEND_STRING */
++#define ACCESSORY_STRING_MANUFACTURER   0
++#define ACCESSORY_STRING_MODEL          1
++#define ACCESSORY_STRING_DESCRIPTION    2
++#define ACCESSORY_STRING_VERSION        3
++#define ACCESSORY_STRING_URI            4
++#define ACCESSORY_STRING_SERIAL         5
++
++/* Control request for retrieving device's protocol version
++ *
++ *	requestType:    USB_DIR_IN | USB_TYPE_VENDOR
++ *	request:        ACCESSORY_GET_PROTOCOL
++ *	value:          0
++ *	index:          0
++ *	data            version number (16 bits little endian)
++ *                     1 for original accessory support
++ *                     2 adds HID and device to host audio support
++ */
++#define ACCESSORY_GET_PROTOCOL  51
++
++/* Control request for host to send a string to the device
++ *
++ *	requestType:    USB_DIR_OUT | USB_TYPE_VENDOR
++ *	request:        ACCESSORY_SEND_STRING
++ *	value:          0
++ *	index:          string ID
++ *	data            zero terminated UTF8 string
++ *
++ *  The device can later retrieve these strings via the
++ *  ACCESSORY_GET_STRING_* ioctls
++ */
++#define ACCESSORY_SEND_STRING   52
++
++/* Control request for starting device in accessory mode.
++ * The host sends this after setting all its strings to the device.
++ *
++ *	requestType:    USB_DIR_OUT | USB_TYPE_VENDOR
++ *	request:        ACCESSORY_START
++ *	value:          0
++ *	index:          0
++ *	data            none
++ */
++#define ACCESSORY_START         53
++
++/* Control request for registering a HID device.
++ * Upon registering, a unique ID is sent by the accessory in the
++ * value parameter. This ID will be used for future commands for
++ * the device
++ *
++ *	requestType:    USB_DIR_OUT | USB_TYPE_VENDOR
++ *	request:        ACCESSORY_REGISTER_HID_DEVICE
++ *	value:          Accessory assigned ID for the HID device
++ *	index:          total length of the HID report descriptor
++ *	data            none
++ */
++#define ACCESSORY_REGISTER_HID         54
++
++/* Control request for unregistering a HID device.
++ *
++ *	requestType:    USB_DIR_OUT | USB_TYPE_VENDOR
++ *	request:        ACCESSORY_REGISTER_HID
++ *	value:          Accessory assigned ID for the HID device
++ *	index:          0
++ *	data            none
++ */
++#define ACCESSORY_UNREGISTER_HID         55
++
++/* Control request for sending the HID report descriptor.
++ * If the HID descriptor is longer than the endpoint zero max packet size,
++ * the descriptor will be sent in multiple ACCESSORY_SET_HID_REPORT_DESC
++ * commands. The data for the descriptor must be sent sequentially
++ * if multiple packets are needed.
++ *
++ *	requestType:    USB_DIR_OUT | USB_TYPE_VENDOR
++ *	request:        ACCESSORY_SET_HID_REPORT_DESC
++ *	value:          Accessory assigned ID for the HID device
++ *	index:          offset of data in descriptor
++ *                      (needed when HID descriptor is too big for one packet)
++ *	data            the HID report descriptor
++ */
++#define ACCESSORY_SET_HID_REPORT_DESC         56
++
++/* Control request for sending HID events.
++ *
++ *	requestType:    USB_DIR_OUT | USB_TYPE_VENDOR
++ *	request:        ACCESSORY_SEND_HID_EVENT
++ *	value:          Accessory assigned ID for the HID device
++ *	index:          0
++ *	data            the HID report for the event
++ */
++#define ACCESSORY_SEND_HID_EVENT         57
++
++/* Control request for setting the audio mode.
++ *
++ *	requestType:	USB_DIR_OUT | USB_TYPE_VENDOR
++ *	request:        ACCESSORY_SET_AUDIO_MODE
++ *	value:          0 - no audio
++ *                     1 - device to host, 44100 16-bit stereo PCM
++ *	index:          0
++ *	data            none
++ */
++#define ACCESSORY_SET_AUDIO_MODE         58
++
++/* ioctls for retrieving strings set by the host */
++#define ACCESSORY_GET_STRING_MANUFACTURER   _IOW('M', 1, char[256])
++#define ACCESSORY_GET_STRING_MODEL          _IOW('M', 2, char[256])
++#define ACCESSORY_GET_STRING_DESCRIPTION    _IOW('M', 3, char[256])
++#define ACCESSORY_GET_STRING_VERSION        _IOW('M', 4, char[256])
++#define ACCESSORY_GET_STRING_URI            _IOW('M', 5, char[256])
++#define ACCESSORY_GET_STRING_SERIAL         _IOW('M', 6, char[256])
++/* returns 1 if there is a start request pending */
++#define ACCESSORY_IS_START_REQUESTED        _IO('M', 7)
++/* returns audio mode (set via the ACCESSORY_SET_AUDIO_MODE control request) */
++#define ACCESSORY_GET_AUDIO_MODE            _IO('M', 8)
++
++#endif /* _UAPI_LINUX_USB_F_ACCESSORY_H */
+diff --git a/include/uapi/linux/usb/f_mtp.h b/include/uapi/linux/usb/f_mtp.h
+new file mode 100644
+index 0000000..5032918
+--- /dev/null
++++ b/include/uapi/linux/usb/f_mtp.h
+@@ -0,0 +1,61 @@
++/*
++ * Gadget Function Driver for MTP
++ *
++ * Copyright (C) 2010 Google, Inc.
++ * Author: Mike Lockwood <lockwood@android.com>
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#ifndef _UAPI_LINUX_USB_F_MTP_H
++#define _UAPI_LINUX_USB_F_MTP_H
++
++#include <linux/ioctl.h>
++#include <linux/types.h>
++
++struct mtp_file_range {
++	/* file descriptor for file to transfer */
++	int			fd;
++	/* offset in file for start of transfer */
++	loff_t		offset;
++	/* number of bytes to transfer */
++	int64_t		length;
++	/* MTP command ID for data header,
++	 * used only for MTP_SEND_FILE_WITH_HEADER
++	 */
++	uint16_t	command;
++	/* MTP transaction ID for data header,
++	 * used only for MTP_SEND_FILE_WITH_HEADER
++	 */
++	uint32_t	transaction_id;
++};
++
++struct mtp_event {
++	/* size of the event */
++	size_t		length;
++	/* event data to send */
++	void		*data;
++};
++
++/* Sends the specified file range to the host */
++#define MTP_SEND_FILE              _IOW('M', 0, struct mtp_file_range)
++/* Receives data from the host and writes it to a file.
++ * The file is created if it does not exist.
++ */
++#define MTP_RECEIVE_FILE           _IOW('M', 1, struct mtp_file_range)
++/* Sends an event to the host via the interrupt endpoint */
++#define MTP_SEND_EVENT             _IOW('M', 3, struct mtp_event)
++/* Sends the specified file range to the host,
++ * with a 12 byte MTP data packet header at the beginning.
++ */
++#define MTP_SEND_FILE_WITH_HEADER  _IOW('M', 4, struct mtp_file_range)
++
++#endif /* _UAPI_LINUX_USB_F_MTP_H */
+diff --git a/include/uapi/linux/usb/video.h b/include/uapi/linux/usb/video.h
+index 3b3b95e..192e753 100644
+--- a/include/uapi/linux/usb/video.h
++++ b/include/uapi/linux/usb/video.h
+@@ -53,6 +53,8 @@
+ #define UVC_VS_FORMAT_FRAME_BASED			0x10
+ #define UVC_VS_FRAME_FRAME_BASED			0x11
+ #define UVC_VS_FORMAT_STREAM_BASED			0x12
++#define UVC_VS_FORMAT_H264				0x13
++#define UVC_VS_FRAME_H264				0x14
+ 
+ /* A.7. Video Class-Specific Endpoint Descriptor Subtypes */
+ #define UVC_EP_UNDEFINED				0x00
+@@ -300,6 +302,7 @@ struct uvc_processing_unit_descriptor {
+ 	__u8  bControlSize;
+ 	__u8  bmControls[2];
+ 	__u8  iProcessing;
++	__u8  bmVideoStandards;
+ } __attribute__((__packed__));
+ 
+ #define UVC_DT_PROCESSING_UNIT_SIZE(n)			(9+(n))
+@@ -524,6 +527,39 @@ struct uvc_format_mjpeg {
+ } __attribute__((__packed__));
+ 
+ #define UVC_DT_FORMAT_MJPEG_SIZE			11
++#define UVC_DT_FORMAT_H264_SIZE			11
++
++struct uvc_format_h264 {
++	__u8  bLength;
++	__u8  bDescriptorType;
++	__u8  bDescriptorSubType;
++	__u8  bFormatIndex;
++	__u8  bNumFrameDescriptors;
++	__u8  bmFlags;
++	__u8  bDefaultFrameIndex;
++	__u8  bAspectRatioX;
++	__u8  bAspectRatioY;
++	__u8  bmInterfaceFlags;
++	__u8  bCopyProtect;
++} __attribute__((__packed__));
++
++struct uvc_format_h264_base {
++	__u8  bLength;
++	__u8  bDescriptorType;
++	__u8  bDescriptorSubType;
++	__u8  bFormatIndex;
++	__u8  bNumFrameDescriptors;
++	__u8  guidFormat[16];
++	__u8  bBitsPerPixel;
++	__u8  bDefaultFrameIndex;
++	__u8  bAspectRatioX;
++	__u8  bAspectRatioY;
++	__u8  bmInterfaceFlags;
++	__u8  bCopyProtect;
++	__u8  bVariableSize;
++} __attribute__((__packed__));
++
++
+ 
+ /* MJPEG Payload - 3.1.2. MJPEG Video Frame Descriptor */
+ struct uvc_frame_mjpeg {
+@@ -564,5 +600,47 @@ struct UVC_FRAME_MJPEG(n) {				\
+ 	__u32 dwFrameInterval[n];			\
+ } __attribute__ ((packed))
+ 
++#define UVC_DT_FRAME_H264_SIZE(n)			(26+4*(n))
++
++#define UVC_FRAME_H264(n) \
++	uvc_frame_h264_##n
++
++#define UVC_FRAME_H264_BASE(n) \
++	uvc_frame_h264_base##n
++
++#define DECLARE_UVC_FRAME_H264(n)			\
++struct UVC_FRAME_H264(n) {				\
++	__u8  bLength;					\
++	__u8  bDescriptorType;				\
++	__u8  bDescriptorSubType;			\
++	__u8  bFrameIndex;				\
++	__u8  bmCapabilities;				\
++	__u16 wWidth;					\
++	__u16 wHeight;					\
++	__u32 dwMinBitRate;				\
++	__u32 dwMaxBitRate;				\
++	__u32 dwMaxVideoFrameBufferSize;		\
++	__u32 dwDefaultFrameInterval;			\
++	__u8  bFrameIntervalType;			\
++	__u32 dwFrameInterval[n];			\
++} __attribute__ ((packed))
++
++#define DECLARE_UVC_FRAME_H264_BASE(n)			\
++struct UVC_FRAME_H264_BASE(n) {				\
++	__u8  bLength;					\
++	__u8  bDescriptorType;				\
++	__u8  bDescriptorSubType;			\
++	__u8  bFrameIndex;				\
++	__u8  bmCapabilities;				\
++	__u16 wWidth;					\
++	__u16 wHeight;					\
++	__u32 dwMinBitRate;				\
++	__u32 dwMaxBitRate;				\
++	__u32 dwDefaultFrameInterval;			\
++	__u8  bFrameIntervalType;			\
++	__u32 dwBytesPerLine;			\
++	__u32 dwFrameInterval[n];			\
++} __attribute__ ((packed))
++
+ #endif /* __LINUX_USB_VIDEO_H */
+ 
+diff --git a/include/uapi/video/adf.h b/include/uapi/video/adf.h
+new file mode 100644
+index 0000000..c5d2e62
+--- /dev/null
++++ b/include/uapi/video/adf.h
+@@ -0,0 +1,321 @@
++/*
++ * Copyright (C) 2013 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#ifndef _UAPI_VIDEO_ADF_H_
++#define _UAPI_VIDEO_ADF_H_
++
++#include <linux/ioctl.h>
++#include <linux/types.h>
++
++#include <drm/drm_fourcc.h>
++#include <drm/drm_mode.h>
++
++#define ADF_NAME_LEN 32
++#define ADF_MAX_CUSTOM_DATA_SIZE 4096
++
++enum adf_interface_type {
++	ADF_INTF_DSI = 0,
++	ADF_INTF_eDP = 1,
++	ADF_INTF_DPI = 2,
++	ADF_INTF_VGA = 3,
++	ADF_INTF_DVI = 4,
++	ADF_INTF_HDMI = 5,
++	ADF_INTF_MEMORY = 6,
++	ADF_INTF_TYPE_DEVICE_CUSTOM = 128,
++	ADF_INTF_TYPE_MAX = (~(__u32)0),
++};
++
++#define ADF_INTF_FLAG_PRIMARY (1 << 0)
++#define ADF_INTF_FLAG_EXTERNAL (1 << 1)
++
++enum adf_event_type {
++	ADF_EVENT_VSYNC = 0,
++	ADF_EVENT_HOTPLUG = 1,
++	ADF_EVENT_DEVICE_CUSTOM = 128,
++	ADF_EVENT_TYPE_MAX = 255,
++};
++
++/**
++ * struct adf_set_event - start or stop subscribing to ADF events
++ *
++ * @type: the type of event to (un)subscribe
++ * @enabled: subscribe or unsubscribe
++ *
++ * After subscribing to an event, userspace may poll() the ADF object's fd
++ * to wait for events or read() to consume the event's data.
++ *
++ * ADF reserves event types 0 to %ADF_EVENT_DEVICE_CUSTOM-1 for its own events.
++ * Devices may use event types %ADF_EVENT_DEVICE_CUSTOM to %ADF_EVENT_TYPE_MAX-1
++ * for driver-private events.
++ */
++struct adf_set_event {
++	__u8 type;
++	__u8 enabled;
++};
++
++/**
++ * struct adf_event - common header for ADF event data
++ *
++ * @type: event type
++ * @length: total size of event data, header inclusive
++ */
++struct adf_event {
++	__u8 type;
++	__u32 length;
++};
++
++/**
++ * struct adf_vsync_event - ADF vsync event
++ *
++ * @base: event header (see &struct adf_event)
++ * @timestamp: time of vsync event, in nanoseconds
++ */
++struct adf_vsync_event {
++	struct adf_event base;
++	__aligned_u64 timestamp;
++};
++
++/**
++ * struct adf_vsync_event - ADF display hotplug event
++ *
++ * @base: event header (see &struct adf_event)
++ * @connected: whether a display is now connected to the interface
++ */
++struct adf_hotplug_event {
++	struct adf_event base;
++	__u8 connected;
++};
++
++#define ADF_MAX_PLANES 4
++/**
++ * struct adf_buffer_config - description of buffer displayed by adf_post_config
++ *
++ * @overlay_engine: id of the target overlay engine
++ * @w: width of display region in pixels
++ * @h: height of display region in pixels
++ * @format: DRM-style fourcc, see drm_fourcc.h for standard formats
++ * @fd: dma_buf fd for each plane
++ * @offset: location of first pixel to scan out, in bytes
++ * @pitch: stride (i.e. length of a scanline including padding) in bytes
++ * @n_planes: number of planes in buffer
++ * @acquire_fence: sync_fence fd which will clear when the buffer is
++ *	ready for display, or <0 if the buffer is already ready
++ */
++struct adf_buffer_config {
++	__u32 overlay_engine;
++
++	__u32 w;
++	__u32 h;
++	__u32 format;
++
++	__s32 fd[ADF_MAX_PLANES];
++	__u32 offset[ADF_MAX_PLANES];
++	__u32 pitch[ADF_MAX_PLANES];
++	__u8 n_planes;
++
++	__s32 acquire_fence;
++};
++#define ADF_MAX_BUFFERS (4096 / sizeof(struct adf_buffer_config))
++
++/**
++ * struct adf_post_config - request to flip to a new set of buffers
++ *
++ * @n_interfaces: number of interfaces targeted by the flip (input)
++ * @interfaces: ids of interfaces targeted by the flip (input)
++ * @n_bufs: number of buffers displayed (input)
++ * @bufs: description of buffers displayed (input)
++ * @custom_data_size: size of driver-private data (input)
++ * @custom_data: driver-private data (input)
++ * @complete_fence: sync_fence fd which will clear when this
++ *	configuration has left the screen (output)
++ */
++struct adf_post_config {
++	size_t n_interfaces;
++	__u32 __user *interfaces;
++
++	size_t n_bufs;
++	struct adf_buffer_config __user *bufs;
++
++	size_t custom_data_size;
++	void __user *custom_data;
++
++	__s32 complete_fence;
++};
++#define ADF_MAX_INTERFACES (4096 / sizeof(__u32))
++
++/**
++ * struct adf_simple_buffer_allocate - request to allocate a "simple" buffer
++ *
++ * @w: width of buffer in pixels (input)
++ * @h: height of buffer in pixels (input)
++ * @format: DRM-style fourcc (input)
++ *
++ * @fd: dma_buf fd (output)
++ * @offset: location of first pixel, in bytes (output)
++ * @pitch: length of a scanline including padding, in bytes (output)
++ *
++ * Simple buffers are analogous to DRM's "dumb" buffers.  They have a single
++ * plane of linear RGB data which can be allocated and scanned out without
++ * any driver-private ioctls or data.
++ *
++ * @format must be a standard RGB format defined in drm_fourcc.h.
++ *
++ * ADF clients must NOT assume that an interface can scan out a simple buffer
++ * allocated by a different ADF interface, even if the two interfaces belong to
++ * the same ADF device.
++ */
++struct adf_simple_buffer_alloc {
++	__u16 w;
++	__u16 h;
++	__u32 format;
++
++	__s32 fd;
++	__u32 offset;
++	__u32 pitch;
++};
++
++/**
++ * struct adf_simple_post_config - request to flip to a single buffer without
++ * driver-private data
++ *
++ * @buf: description of buffer displayed (input)
++ * @complete_fence: sync_fence fd which will clear when this buffer has left the
++ * screen (output)
++ */
++struct adf_simple_post_config {
++	struct adf_buffer_config buf;
++	__s32 complete_fence;
++};
++
++/**
++ * struct adf_attachment_config - description of attachment between an overlay
++ * engine and an interface
++ *
++ * @overlay_engine: id of the overlay engine
++ * @interface: id of the interface
++ */
++struct adf_attachment_config {
++	__u32 overlay_engine;
++	__u32 interface;
++};
++
++/**
++ * struct adf_device_data - describes a display device
++ *
++ * @name: display device's name
++ * @n_attachments: the number of current attachments
++ * @attachments: list of current attachments
++ * @n_allowed_attachments: the number of allowed attachments
++ * @allowed_attachments: list of allowed attachments
++ * @custom_data_size: size of driver-private data
++ * @custom_data: driver-private data
++ */
++struct adf_device_data {
++	char name[ADF_NAME_LEN];
++
++	size_t n_attachments;
++	struct adf_attachment_config __user *attachments;
++
++	size_t n_allowed_attachments;
++	struct adf_attachment_config __user *allowed_attachments;
++
++	size_t custom_data_size;
++	void __user *custom_data;
++};
++#define ADF_MAX_ATTACHMENTS (4096 / sizeof(struct adf_attachment_config))
++
++/**
++ * struct adf_device_data - describes a display interface
++ *
++ * @name: display interface's name
++ * @type: interface type (see enum @adf_interface_type)
++ * @id: which interface of type @type;
++ *	e.g. interface DSI.1 -> @type=@ADF_INTF_TYPE_DSI, @id=1
++ * @flags: informational flags (bitmask of %ADF_INTF_FLAG_* values)
++ * @dpms_state: DPMS state (one of @DRM_MODE_DPMS_* defined in drm_mode.h)
++ * @hotplug_detect: whether a display is plugged in
++ * @width_mm: screen width in millimeters, or 0 if unknown
++ * @height_mm: screen height in millimeters, or 0 if unknown
++ * @current_mode: current display mode
++ * @n_available_modes: the number of hardware display modes
++ * @available_modes: list of hardware display modes
++ * @custom_data_size: size of driver-private data
++ * @custom_data: driver-private data
++ */
++struct adf_interface_data {
++	char name[ADF_NAME_LEN];
++
++	__u32 type;
++	__u32 id;
++	/* e.g. type=ADF_INTF_TYPE_DSI, id=1 => DSI.1 */
++	__u32 flags;
++
++	__u8 dpms_state;
++	__u8 hotplug_detect;
++	__u16 width_mm;
++	__u16 height_mm;
++
++	struct drm_mode_modeinfo current_mode;
++	size_t n_available_modes;
++	struct drm_mode_modeinfo __user *available_modes;
++
++	size_t custom_data_size;
++	void __user *custom_data;
++};
++#define ADF_MAX_MODES (4096 / sizeof(struct drm_mode_modeinfo))
++
++/**
++ * struct adf_overlay_engine_data - describes an overlay engine
++ *
++ * @name: overlay engine's name
++ * @n_supported_formats: number of supported formats
++ * @supported_formats: list of supported formats
++ * @custom_data_size: size of driver-private data
++ * @custom_data: driver-private data
++ */
++struct adf_overlay_engine_data {
++	char name[ADF_NAME_LEN];
++
++	size_t n_supported_formats;
++	__u32 __user *supported_formats;
++
++	size_t custom_data_size;
++	void __user *custom_data;
++};
++#define ADF_MAX_SUPPORTED_FORMATS (4096 / sizeof(__u32))
++
++#define ADF_IOCTL_TYPE		'D'
++#define ADF_IOCTL_NR_CUSTOM	128
++
++#define ADF_SET_EVENT		_IOW(ADF_IOCTL_TYPE, 0, struct adf_set_event)
++#define ADF_BLANK		_IOW(ADF_IOCTL_TYPE, 1, __u8)
++#define ADF_POST_CONFIG		_IOW(ADF_IOCTL_TYPE, 2, struct adf_post_config)
++#define ADF_SET_MODE		_IOW(ADF_IOCTL_TYPE, 3, \
++					struct drm_mode_modeinfo)
++#define ADF_GET_DEVICE_DATA	_IOR(ADF_IOCTL_TYPE, 4, struct adf_device_data)
++#define ADF_GET_INTERFACE_DATA	_IOR(ADF_IOCTL_TYPE, 5, \
++					struct adf_interface_data)
++#define ADF_GET_OVERLAY_ENGINE_DATA \
++				_IOR(ADF_IOCTL_TYPE, 6, \
++					struct adf_overlay_engine_data)
++#define ADF_SIMPLE_POST_CONFIG	_IOW(ADF_IOCTL_TYPE, 7, \
++					struct adf_simple_post_config)
++#define ADF_SIMPLE_BUFFER_ALLOC	_IOW(ADF_IOCTL_TYPE, 8, \
++					struct adf_simple_buffer_alloc)
++#define ADF_ATTACH		_IOW(ADF_IOCTL_TYPE, 9, \
++					struct adf_attachment_config)
++#define ADF_DETACH		_IOW(ADF_IOCTL_TYPE, 10, \
++					struct adf_attachment_config)
++
++#endif /* _UAPI_VIDEO_ADF_H_ */
+diff --git a/include/video/adf.h b/include/video/adf.h
+new file mode 100644
+index 0000000..34f10e5
+--- /dev/null
++++ b/include/video/adf.h
+@@ -0,0 +1,502 @@
++/*
++ * Copyright (C) 2013 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#ifndef _VIDEO_ADF_H
++#define _VIDEO_ADF_H
++
++#include <linux/device.h>
++#include <linux/dma-buf.h>
++#include <linux/idr.h>
++#include <linux/kref.h>
++#include <linux/kthread.h>
++#include <linux/ktime.h>
++#include <linux/list.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/scatterlist.h>
++#include <linux/sched.h>
++#include <linux/spinlock.h>
++#include <linux/wait.h>
++#include <linux/workqueue.h>
++#include <uapi/video/adf.h>
++#include "sync.h"
++
++struct adf_obj;
++struct adf_obj_ops;
++struct adf_device;
++struct adf_device_ops;
++struct adf_interface;
++struct adf_interface_ops;
++struct adf_overlay_engine;
++struct adf_overlay_engine_ops;
++
++/**
++ * struct adf_buffer - buffer displayed by adf_post
++ *
++ * @overlay_engine: target overlay engine
++ * @w: width of display region in pixels
++ * @h: height of display region in pixels
++ * @format: DRM-style fourcc, see drm_fourcc.h for standard formats
++ * @dma_bufs: dma_buf for each plane
++ * @offset: location of first pixel to scan out, in bytes
++ * @pitch: length of a scanline including padding, in bytes
++ * @n_planes: number of planes in buffer
++ * @acquire_fence: sync_fence which will clear when the buffer is
++ *	ready for display
++ *
++ * &struct adf_buffer is the in-kernel counterpart to the userspace-facing
++ * &struct adf_buffer_config.
++ */
++struct adf_buffer {
++	struct adf_overlay_engine *overlay_engine;
++
++	u32 w;
++	u32 h;
++	u32 format;
++
++	struct dma_buf *dma_bufs[ADF_MAX_PLANES];
++	u32 offset[ADF_MAX_PLANES];
++	u32 pitch[ADF_MAX_PLANES];
++	u8 n_planes;
++
++	struct sync_fence *acquire_fence;
++};
++
++/**
++ * struct adf_buffer_mapping - state for mapping a &struct adf_buffer into the
++ * display device
++ *
++ * @attachments: dma-buf attachment for each plane
++ * @sg_tables: SG tables for each plane
++ */
++struct adf_buffer_mapping {
++	struct dma_buf_attachment *attachments[ADF_MAX_PLANES];
++	struct sg_table *sg_tables[ADF_MAX_PLANES];
++};
++
++/**
++ * struct adf_post - request to flip to a new set of buffers
++ *
++ * @n_bufs: number of buffers displayed
++ * @bufs: buffers displayed
++ * @mappings: in-device mapping state for each buffer
++ * @custom_data_size: size of driver-private data
++ * @custom_data: driver-private data
++ *
++ * &struct adf_post is the in-kernel counterpart to the userspace-facing
++ * &struct adf_post_config.
++ */
++struct adf_post {
++	size_t n_bufs;
++	struct adf_buffer *bufs;
++	struct adf_buffer_mapping *mappings;
++
++	size_t custom_data_size;
++	void *custom_data;
++};
++
++/**
++ * struct adf_attachment - description of attachment between an overlay engine
++ * and an interface
++ *
++ * @overlay_engine: the overlay engine
++ * @interface: the interface
++ *
++ * &struct adf_attachment is the in-kernel counterpart to the userspace-facing
++ * &struct adf_attachment_config.
++ */
++struct adf_attachment {
++	struct adf_overlay_engine *overlay_engine;
++	struct adf_interface *interface;
++};
++
++struct adf_pending_post {
++	struct list_head head;
++	struct adf_post config;
++	void *state;
++};
++
++enum adf_obj_type {
++	ADF_OBJ_OVERLAY_ENGINE = 0,
++	ADF_OBJ_INTERFACE = 1,
++	ADF_OBJ_DEVICE = 2,
++};
++
++/**
++ * struct adf_obj_ops - common ADF object implementation ops
++ *
++ * @open: handle opening the object's device node
++ * @release: handle releasing an open file
++ * @ioctl: handle custom ioctls
++ *
++ * @supports_event: return whether the object supports generating events of type
++ *	@type
++ * @set_event: enable or disable events of type @type
++ * @event_type_str: return a string representation of custom event @type
++ *	(@type >= %ADF_EVENT_DEVICE_CUSTOM).
++ *
++ * @custom_data: copy up to %ADF_MAX_CUSTOM_DATA_SIZE bytes of driver-private
++ *	data into @data (allocated by ADF) and return the number of copied bytes
++ *	in @size.  Return 0 on success or an error code (<0) on failure.
++ */
++struct adf_obj_ops {
++	/* optional */
++	int (*open)(struct adf_obj *obj, struct inode *inode,
++			struct file *file);
++	/* optional */
++	void (*release)(struct adf_obj *obj, struct inode *inode,
++			struct file *file);
++	/* optional */
++	long (*ioctl)(struct adf_obj *obj, unsigned int cmd, unsigned long arg);
++
++	/* optional */
++	bool (*supports_event)(struct adf_obj *obj, enum adf_event_type type);
++	/* required if supports_event is implemented */
++	void (*set_event)(struct adf_obj *obj, enum adf_event_type type,
++			bool enabled);
++	/* optional */
++	const char *(*event_type_str)(struct adf_obj *obj,
++			enum adf_event_type type);
++
++	/* optional */
++	int (*custom_data)(struct adf_obj *obj, void *data, size_t *size);
++};
++
++struct adf_obj {
++	enum adf_obj_type type;
++	char name[ADF_NAME_LEN];
++	struct adf_device *parent;
++
++	const struct adf_obj_ops *ops;
++
++	struct device dev;
++
++	struct spinlock file_lock;
++	struct list_head file_list;
++
++	struct mutex event_lock;
++	struct rb_root event_refcount;
++
++	int id;
++	int minor;
++};
++
++/**
++ * struct adf_device_quirks - common display device quirks
++ *
++ * @buffer_padding: whether the last scanline of a buffer extends to the
++ * 	buffer's pitch (@ADF_BUFFER_PADDED_TO_PITCH) or just to the visible
++ * 	width (@ADF_BUFFER_UNPADDED)
++ */
++struct adf_device_quirks {
++	/* optional, defaults to ADF_BUFFER_PADDED_TO_PITCH */
++	enum {
++		ADF_BUFFER_PADDED_TO_PITCH = 0,
++		ADF_BUFFER_UNPADDED = 1,
++	} buffer_padding;
++};
++
++/**
++ * struct adf_device_ops - display device implementation ops
++ *
++ * @owner: device's module
++ * @base: common operations (see &struct adf_obj_ops)
++ * @quirks: device's quirks (see &struct adf_device_quirks)
++ *
++ * @attach: attach overlay engine @eng to interface @intf.  Return 0 on success
++ *	or error code (<0) on failure.
++ * @detach: detach overlay engine @eng from interface @intf.  Return 0 on
++ *	success or error code (<0) on failure.
++ *
++ * @validate_custom_format: validate the number and size of planes
++ *	in buffers with a custom format (i.e., not one of the @DRM_FORMAT_*
++ *	types defined in drm/drm_fourcc.h).  Return 0 if the buffer is valid or
++ *	an error code (<0) otherwise.
++ *
++ * @validate: validate that the proposed configuration @cfg is legal.  The
++ *	driver may optionally allocate and return some driver-private state in
++ *	@driver_state, which will be passed to the corresponding post().  The
++ *	driver may NOT commit any changes to hardware.  Return 0 if @cfg is
++ *	valid or an error code (<0) otherwise.
++ * @complete_fence: create a hardware-backed sync fence to be signaled when
++ *	@cfg is removed from the screen.  If unimplemented, ADF automatically
++ *	creates an sw_sync fence.  Return the sync fence on success or a
++ *	PTR_ERR() on failure.
++ * @post: flip @cfg onto the screen.  Wait for the display to begin scanning out
++ *	@cfg before returning.
++ * @advance_timeline: signal the sync fence for the last configuration to leave
++ *	the display.  If unimplemented, ADF automatically advances an sw_sync
++ *	timeline.
++ * @state_free: free driver-private state allocated during validate()
++ */
++struct adf_device_ops {
++	/* required */
++	struct module *owner;
++	const struct adf_obj_ops base;
++	/* optional */
++	const struct adf_device_quirks quirks;
++
++	/* optional */
++	int (*attach)(struct adf_device *dev, struct adf_overlay_engine *eng,
++			struct adf_interface *intf);
++	/* optional */
++	int (*detach)(struct adf_device *dev, struct adf_overlay_engine *eng,
++			struct adf_interface *intf);
++
++	/* required if any of the device's overlay engines supports at least one
++	   custom format */
++	int (*validate_custom_format)(struct adf_device *dev,
++			struct adf_buffer *buf);
++
++	/* required */
++	int (*validate)(struct adf_device *dev, struct adf_post *cfg,
++			void **driver_state);
++	/* optional */
++	struct sync_fence *(*complete_fence)(struct adf_device *dev,
++			struct adf_post *cfg, void *driver_state);
++	/* required */
++	void (*post)(struct adf_device *dev, struct adf_post *cfg,
++			void *driver_state);
++	/* required if complete_fence is implemented */
++	void (*advance_timeline)(struct adf_device *dev,
++			struct adf_post *cfg, void *driver_state);
++	/* required if validate allocates driver state */
++	void (*state_free)(struct adf_device *dev, void *driver_state);
++};
++
++struct adf_attachment_list {
++	struct adf_attachment attachment;
++	struct list_head head;
++};
++
++struct adf_device {
++	struct adf_obj base;
++	struct device *dev;
++
++	const struct adf_device_ops *ops;
++
++	struct mutex client_lock;
++
++	struct idr interfaces;
++	size_t n_interfaces;
++	struct idr overlay_engines;
++
++	struct list_head post_list;
++	struct mutex post_lock;
++	struct kthread_worker post_worker;
++	struct task_struct *post_thread;
++	struct kthread_work post_work;
++
++	struct list_head attached;
++	size_t n_attached;
++	struct list_head attach_allowed;
++	size_t n_attach_allowed;
++
++	struct adf_pending_post *onscreen;
++
++	struct sw_sync_timeline *timeline;
++	int timeline_max;
++};
++
++/**
++ * struct adf_interface_ops - display interface implementation ops
++ *
++ * @base: common operations (see &struct adf_obj_ops)
++ *
++ * @blank: change the display's DPMS state.  Return 0 on success or error
++ *	code (<0) on failure.
++ *
++ * @alloc_simple_buffer: allocate a buffer with the specified @w, @h, and
++ *	@format.  @format will be a standard RGB format (i.e.,
++ *	adf_format_is_rgb(@format) == true).  Return 0 on success or error code
++ *	(<0) on failure.  On success, return the buffer, offset, and pitch in
++ *	@dma_buf, @offset, and @pitch respectively.
++ * @describe_simple_post: provide driver-private data needed to post a single
++ *	buffer @buf.  Copy up to ADF_MAX_CUSTOM_DATA_SIZE bytes into @data
++ *	(allocated by ADF) and return the number of bytes in @size.  Return 0 on
++ *	success or error code (<0) on failure.
++ *
++ * @modeset: change the interface's mode.  @mode is not necessarily part of the
++ *	modelist passed to adf_hotplug_notify_connected(); the driver may
++ *	accept or reject custom modes at its discretion.  Return 0 on success or
++ *	error code (<0) if the mode could not be set.
++ *
++ * @screen_size: copy the screen dimensions in millimeters into @width_mm
++ *	and @height_mm.  Return 0 on success or error code (<0) if the display
++ *	dimensions are unknown.
++ *
++ * @type_str: return a string representation of custom @intf->type
++ *	(@intf->type >= @ADF_INTF_TYPE_DEVICE_CUSTOM).
++ */
++struct adf_interface_ops {
++	const struct adf_obj_ops base;
++
++	/* optional */
++	int (*blank)(struct adf_interface *intf, u8 state);
++
++	/* optional */
++	int (*alloc_simple_buffer)(struct adf_interface *intf,
++			u16 w, u16 h, u32 format,
++			struct dma_buf **dma_buf, u32 *offset, u32 *pitch);
++	/* optional */
++	int (*describe_simple_post)(struct adf_interface *intf,
++			struct adf_buffer *fb, void *data, size_t *size);
++
++	/* optional */
++	int (*modeset)(struct adf_interface *intf,
++			struct drm_mode_modeinfo *mode);
++
++	/* optional */
++	int (*screen_size)(struct adf_interface *intf, u16 *width_mm,
++			u16 *height_mm);
++
++	/* optional */
++	const char *(*type_str)(struct adf_interface *intf);
++};
++
++struct adf_interface {
++	struct adf_obj base;
++	const struct adf_interface_ops *ops;
++
++	struct drm_mode_modeinfo current_mode;
++
++	enum adf_interface_type type;
++	u32 idx;
++	u32 flags;
++
++	wait_queue_head_t vsync_wait;
++	ktime_t vsync_timestamp;
++	rwlock_t vsync_lock;
++
++	u8 dpms_state;
++
++	bool hotplug_detect;
++	struct drm_mode_modeinfo *modelist;
++	size_t n_modes;
++	rwlock_t hotplug_modelist_lock;
++};
++
++/**
++ * struct adf_interface_ops - overlay engine implementation ops
++ *
++ * @base: common operations (see &struct adf_obj_ops)
++ *
++ * @supported_formats: list of fourccs the overlay engine can scan out
++ * @n_supported_formats: length of supported_formats, up to
++ *	ADF_MAX_SUPPORTED_FORMATS
++ */
++struct adf_overlay_engine_ops {
++	const struct adf_obj_ops base;
++
++	/* required */
++	const u32 *supported_formats;
++	/* required */
++	const size_t n_supported_formats;
++};
++
++struct adf_overlay_engine {
++	struct adf_obj base;
++
++	const struct adf_overlay_engine_ops *ops;
++};
++
++#define adf_obj_to_device(ptr) \
++	container_of((ptr), struct adf_device, base)
++
++#define adf_obj_to_interface(ptr) \
++	container_of((ptr), struct adf_interface, base)
++
++#define adf_obj_to_overlay_engine(ptr) \
++	container_of((ptr), struct adf_overlay_engine, base)
++
++int __printf(4, 5) adf_device_init(struct adf_device *dev,
++		struct device *parent, const struct adf_device_ops *ops,
++		const char *fmt, ...);
++void adf_device_destroy(struct adf_device *dev);
++int __printf(7, 8) adf_interface_init(struct adf_interface *intf,
++		struct adf_device *dev, enum adf_interface_type type, u32 idx,
++		u32 flags, const struct adf_interface_ops *ops, const char *fmt,
++		...);
++void adf_interface_destroy(struct adf_interface *intf);
++static inline struct adf_device *adf_interface_parent(
++		struct adf_interface *intf)
++{
++	return intf->base.parent;
++}
++int __printf(4, 5) adf_overlay_engine_init(struct adf_overlay_engine *eng,
++		struct adf_device *dev,
++		const struct adf_overlay_engine_ops *ops, const char *fmt, ...);
++void adf_overlay_engine_destroy(struct adf_overlay_engine *eng);
++static inline struct adf_device *adf_overlay_engine_parent(
++		struct adf_overlay_engine *eng)
++{
++	return eng->base.parent;
++}
++
++int adf_attachment_allow(struct adf_device *dev, struct adf_overlay_engine *eng,
++		struct adf_interface *intf);
++
++const char *adf_obj_type_str(enum adf_obj_type type);
++const char *adf_interface_type_str(struct adf_interface *intf);
++const char *adf_event_type_str(struct adf_obj *obj, enum adf_event_type type);
++
++#define ADF_FORMAT_STR_SIZE 5
++void adf_format_str(u32 format, char buf[ADF_FORMAT_STR_SIZE]);
++int adf_format_validate_yuv(struct adf_device *dev, struct adf_buffer *buf,
++		u8 num_planes, u8 hsub, u8 vsub, u8 cpp[]);
++/**
++ * adf_format_validate_rgb - validate the number and size of planes in buffers
++ * with a custom RGB format.
++ *
++ * @dev: ADF device performing the validation
++ * @buf: buffer to validate
++ * @cpp: expected bytes per pixel
++ *
++ * adf_format_validate_rgb() is intended to be called as a helper from @dev's
++ * validate_custom_format() op.  @buf must have a single RGB plane.
++ *
++ * Returns 0 if @buf has a single plane with sufficient size, or -EINVAL
++ * otherwise.
++ */
++static inline int adf_format_validate_rgb(struct adf_device *dev,
++		struct adf_buffer *buf, u8 cpp)
++{
++	return adf_format_validate_yuv(dev, buf, 1, 1, 1, &cpp);
++}
++
++int adf_event_get(struct adf_obj *obj, enum adf_event_type type);
++int adf_event_put(struct adf_obj *obj, enum adf_event_type type);
++int adf_event_notify(struct adf_obj *obj, struct adf_event *event);
++
++static inline void adf_vsync_get(struct adf_interface *intf)
++{
++	adf_event_get(&intf->base, ADF_EVENT_VSYNC);
++}
++
++static inline void adf_vsync_put(struct adf_interface *intf)
++{
++	adf_event_put(&intf->base, ADF_EVENT_VSYNC);
++}
++
++int adf_vsync_wait(struct adf_interface *intf, long timeout);
++void adf_vsync_notify(struct adf_interface *intf, ktime_t timestamp);
++
++int adf_hotplug_notify_connected(struct adf_interface *intf,
++		struct drm_mode_modeinfo *modelist, size_t n_modes);
++void adf_hotplug_notify_disconnected(struct adf_interface *intf);
++
++void adf_modeinfo_set_name(struct drm_mode_modeinfo *mode);
++void adf_modeinfo_set_vrefresh(struct drm_mode_modeinfo *mode);
++
++#endif /* _VIDEO_ADF_H */
+diff --git a/include/video/adf_client.h b/include/video/adf_client.h
+new file mode 100644
+index 0000000..983f2b6
+--- /dev/null
++++ b/include/video/adf_client.h
+@@ -0,0 +1,61 @@
++/*
++ * Copyright (C) 2013 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#ifndef _VIDEO_ADF_CLIENT_H_
++#define _VIDEO_ADF_CLIENT_H_
++
++#include <video/adf.h>
++
++int adf_interface_blank(struct adf_interface *intf, u8 state);
++u8 adf_interface_dpms_state(struct adf_interface *intf);
++
++void adf_interface_current_mode(struct adf_interface *intf,
++		struct drm_mode_modeinfo *mode);
++size_t adf_interface_modelist(struct adf_interface *intf,
++		struct drm_mode_modeinfo *modelist, size_t n_modes);
++int adf_interface_set_mode(struct adf_interface *intf,
++		struct drm_mode_modeinfo *mode);
++int adf_interface_get_screen_size(struct adf_interface *intf, u16 *width,
++		u16 *height);
++int adf_interface_simple_buffer_alloc(struct adf_interface *intf, u16 w, u16 h,
++		u32 format, struct dma_buf **dma_buf, u32 *offset, u32 *pitch);
++struct sync_fence *adf_interface_simple_post(struct adf_interface *intf,
++		struct adf_buffer *buf);
++
++bool adf_overlay_engine_supports_format(struct adf_overlay_engine *eng,
++		u32 format);
++
++size_t adf_device_attachments(struct adf_device *dev,
++		struct adf_attachment *attachments, size_t n_attachments);
++size_t adf_device_attachments_allowed(struct adf_device *dev,
++		struct adf_attachment *attachments, size_t n_attachments);
++bool adf_device_attached(struct adf_device *dev, struct adf_overlay_engine *eng,
++		struct adf_interface *intf);
++bool adf_device_attach_allowed(struct adf_device *dev,
++		struct adf_overlay_engine *eng, struct adf_interface *intf);
++int adf_device_attach(struct adf_device *dev, struct adf_overlay_engine *eng,
++		struct adf_interface *intf);
++int adf_device_detach(struct adf_device *dev, struct adf_overlay_engine *eng,
++		struct adf_interface *intf);
++
++struct sync_fence *adf_device_post(struct adf_device *dev,
++		struct adf_interface **intfs, size_t n_intfs,
++		struct adf_buffer *bufs, size_t n_bufs, void *custom_data,
++		size_t custom_data_size);
++struct sync_fence *adf_device_post_nocopy(struct adf_device *dev,
++		struct adf_interface **intfs, size_t n_intfs,
++		struct adf_buffer *bufs, size_t n_bufs, void *custom_data,
++		size_t custom_data_size);
++
++#endif /* _VIDEO_ADF_CLIENT_H_ */
+diff --git a/include/video/adf_fbdev.h b/include/video/adf_fbdev.h
+new file mode 100644
+index 0000000..b722c6b
+--- /dev/null
++++ b/include/video/adf_fbdev.h
+@@ -0,0 +1,124 @@
++/*
++ * Copyright (C) 2013 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#ifndef _VIDEO_ADF_FBDEV_H_
++#define _VIDEO_ADF_FBDEV_H_
++
++#include <linux/fb.h>
++#include <linux/mutex.h>
++#include <video/adf.h>
++
++struct adf_fbdev {
++	struct adf_interface *intf;
++	struct adf_overlay_engine *eng;
++	struct fb_info *info;
++	u32 pseudo_palette[16];
++
++	unsigned int refcount;
++	struct mutex refcount_lock;
++
++	struct dma_buf *dma_buf;
++	u32 offset;
++	u32 pitch;
++	void *vaddr;
++	u32 format;
++
++	u16 default_xres_virtual;
++	u16 default_yres_virtual;
++	u32 default_format;
++};
++
++#if IS_ENABLED(CONFIG_ADF_FBDEV)
++void adf_modeinfo_to_fb_videomode(const struct drm_mode_modeinfo *mode,
++		struct fb_videomode *vmode);
++void adf_modeinfo_from_fb_videomode(const struct fb_videomode *vmode,
++		struct drm_mode_modeinfo *mode);
++
++int adf_fbdev_init(struct adf_fbdev *fbdev, struct adf_interface *interface,
++		struct adf_overlay_engine *eng,
++		u16 xres_virtual, u16 yres_virtual, u32 format,
++		struct fb_ops *fbops, const char *fmt, ...);
++void adf_fbdev_destroy(struct adf_fbdev *fbdev);
++
++int adf_fbdev_open(struct fb_info *info, int user);
++int adf_fbdev_release(struct fb_info *info, int user);
++int adf_fbdev_check_var(struct fb_var_screeninfo *var, struct fb_info *info);
++int adf_fbdev_set_par(struct fb_info *info);
++int adf_fbdev_blank(int blank, struct fb_info *info);
++int adf_fbdev_pan_display(struct fb_var_screeninfo *var, struct fb_info *info);
++int adf_fbdev_mmap(struct fb_info *info, struct vm_area_struct *vma);
++#else
++static inline void adf_modeinfo_to_fb_videomode(const struct drm_mode_modeinfo *mode,
++		struct fb_videomode *vmode)
++{
++	WARN_ONCE(1, "%s: CONFIG_ADF_FBDEV is disabled\n", __func__);
++}
++
++static inline void adf_modeinfo_from_fb_videomode(const struct fb_videomode *vmode,
++		struct drm_mode_modeinfo *mode)
++{
++	WARN_ONCE(1, "%s: CONFIG_ADF_FBDEV is disabled\n", __func__);
++}
++
++static inline int adf_fbdev_init(struct adf_fbdev *fbdev,
++		struct adf_interface *interface,
++		struct adf_overlay_engine *eng,
++		u16 xres_virtual, u16 yres_virtual, u32 format,
++		struct fb_ops *fbops, const char *fmt, ...)
++{
++	return -ENODEV;
++}
++
++static inline void adf_fbdev_destroy(struct adf_fbdev *fbdev) { }
++
++static inline int adf_fbdev_open(struct fb_info *info, int user)
++{
++	return -ENODEV;
++}
++
++static inline int adf_fbdev_release(struct fb_info *info, int user)
++{
++	return -ENODEV;
++}
++
++static inline int adf_fbdev_check_var(struct fb_var_screeninfo *var,
++		struct fb_info *info)
++{
++	return -ENODEV;
++}
++
++static inline int adf_fbdev_set_par(struct fb_info *info)
++{
++	return -ENODEV;
++}
++
++static inline int adf_fbdev_blank(int blank, struct fb_info *info)
++{
++	return -ENODEV;
++}
++
++static inline int adf_fbdev_pan_display(struct fb_var_screeninfo *var,
++		struct fb_info *info)
++{
++	return -ENODEV;
++}
++
++static inline int adf_fbdev_mmap(struct fb_info *info,
++		struct vm_area_struct *vma)
++{
++	return -ENODEV;
++}
++#endif
++
++#endif /* _VIDEO_ADF_FBDEV_H_ */
+diff --git a/include/video/adf_format.h b/include/video/adf_format.h
+new file mode 100644
+index 0000000..e03182c
+--- /dev/null
++++ b/include/video/adf_format.h
+@@ -0,0 +1,26 @@
++/*
++ * Copyright (C) 2013 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#ifndef _VIDEO_ADF_FORMAT_H
++#define _VIDEO_ADF_FORMAT_H
++
++bool adf_format_is_standard(u32 format);
++bool adf_format_is_rgb(u32 format);
++u8 adf_format_num_planes(u32 format);
++u8 adf_format_bpp(u32 format);
++u8 adf_format_plane_cpp(u32 format, int plane);
++u8 adf_format_horz_chroma_subsampling(u32 format);
++u8 adf_format_vert_chroma_subsampling(u32 format);
++
++#endif /* _VIDEO_ADF_FORMAT_H */
+diff --git a/include/video/adf_memblock.h b/include/video/adf_memblock.h
+new file mode 100644
+index 0000000..6256e0e
+--- /dev/null
++++ b/include/video/adf_memblock.h
+@@ -0,0 +1,20 @@
++/*
++ * Copyright (C) 2013 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#ifndef _VIDEO_ADF_MEMBLOCK_H_
++#define _VIDEO_ADF_MEMBLOCK_H_
++
++struct dma_buf *adf_memblock_export(phys_addr_t base, size_t size, int flags);
++
++#endif /* _VIDEO_ADF_MEMBLOCK_H_ */
+diff --git a/init/Kconfig b/init/Kconfig
+index 2081a4d..3265800 100644
+--- a/init/Kconfig
++++ b/init/Kconfig
+@@ -199,6 +199,20 @@ config KERNEL_LZ4
+ 
+ endchoice
+ 
++choice
++    prompt "Kernel decompress mode"
++    default SOFT_DECOMPRESS
++    depends on (ARCH_HI3559 || ARCH_HI3556) && HAVE_KERNEL_GZIP
++    help
++      select the decompress mode.
++config HW_DECOMPRESS
++    bool "hardware decompress"
++    help
++      select hardware decompress mode.
++config SOFT_DECOMPRESS
++    bool "soft decompress"
++endchoice
++
+ config DEFAULT_HOSTNAME
+ 	string "Default hostname"
+ 	default "(none)"
+diff --git a/init/Makefile b/init/Makefile
+index 7bc47ee..692b91f 100644
+--- a/init/Makefile
++++ b/init/Makefile
+@@ -3,11 +3,8 @@
+ #
+ 
+ obj-y                          := main.o version.o mounts.o
+-ifneq ($(CONFIG_BLK_DEV_INITRD),y)
+ obj-y                          += noinitramfs.o
+-else
+ obj-$(CONFIG_BLK_DEV_INITRD)   += initramfs.o
+-endif
+ obj-$(CONFIG_GENERIC_CALIBRATE_DELAY) += calibrate.o
+ 
+ ifneq ($(CONFIG_ARCH_INIT_TASK),y)
+diff --git a/init/initramfs.c b/init/initramfs.c
+index ad1bd77..d39079e 100644
+--- a/init/initramfs.c
++++ b/init/initramfs.c
+@@ -18,6 +18,7 @@
+ #include <linux/dirent.h>
+ #include <linux/syscalls.h>
+ #include <linux/utime.h>
++#include <linux/initramfs.h>
+ 
+ static ssize_t __init xwrite(int fd, const char *p, size_t count)
+ {
+@@ -605,9 +606,25 @@ static void __init clean_rootfs(void)
+ }
+ #endif
+ 
++static int __initdata do_skip_initramfs;
++
++static int __init skip_initramfs_param(char *str)
++{
++	if (*str)
++		return 0;
++	do_skip_initramfs = 1;
++	return 1;
++}
++__setup("skip_initramfs", skip_initramfs_param);
++
+ static int __init populate_rootfs(void)
+ {
+-	char *err = unpack_to_rootfs(__initramfs_start, __initramfs_size);
++	char *err;
++
++	if (do_skip_initramfs)
++		return default_rootfs();
++
++	err = unpack_to_rootfs(__initramfs_start, __initramfs_size);
+ 	if (err)
+ 		panic("%s", err); /* Failed to decompress INTERNAL initramfs */
+ 	if (initrd_start) {
+diff --git a/init/noinitramfs.c b/init/noinitramfs.c
+index 267739d..bcc8bcb 100644
+--- a/init/noinitramfs.c
++++ b/init/noinitramfs.c
+@@ -21,11 +21,16 @@
+ #include <linux/stat.h>
+ #include <linux/kdev_t.h>
+ #include <linux/syscalls.h>
++#include <linux/kconfig.h>
++#include <linux/initramfs.h>
+ 
+ /*
+  * Create a simple rootfs that is similar to the default initramfs
+  */
+-static int __init default_rootfs(void)
++#if !IS_BUILTIN(CONFIG_BLK_DEV_INITRD)
++static
++#endif
++int __init default_rootfs(void)
+ {
+ 	int err;
+ 
+@@ -49,4 +54,6 @@ out:
+ 	printk(KERN_WARNING "Failed to create a rootfs\n");
+ 	return err;
+ }
++#if !IS_BUILTIN(CONFIG_BLK_DEV_INITRD)
+ rootfs_initcall(default_rootfs);
++#endif
+diff --git a/ipc/mqueue.c b/ipc/mqueue.c
+index 4fcf39a..9c2d42c 100644
+--- a/ipc/mqueue.c
++++ b/ipc/mqueue.c
+@@ -1244,8 +1244,10 @@ retry:
+ 
+ 			timeo = MAX_SCHEDULE_TIMEOUT;
+ 			ret = netlink_attachskb(sock, nc, &timeo, NULL);
+-			if (ret == 1)
++			if (ret == 1) {
++				sock = NULL;
+ 				goto retry;
++			}
+ 			if (ret) {
+ 				sock = NULL;
+ 				nc = NULL;
+diff --git a/kernel/cgroup.c b/kernel/cgroup.c
+index 136ecea..30f1801 100644
+--- a/kernel/cgroup.c
++++ b/kernel/cgroup.c
+@@ -2327,6 +2327,44 @@ static int cgroup_attach_task(struct cgroup *dst_cgrp,
+ 	return ret;
+ }
+ 
++int subsys_cgroup_allow_attach(struct cgroup_subsys_state *css, struct cgroup_taskset *tset)
++{
++	const struct cred *cred = current_cred(), *tcred;
++	struct task_struct *task;
++
++	if (capable(CAP_SYS_NICE))
++		return 0;
++
++	cgroup_taskset_for_each(task, tset) {
++		tcred = __task_cred(task);
++
++		if (current != task && !uid_eq(cred->euid, tcred->uid) &&
++		    !uid_eq(cred->euid, tcred->suid))
++			return -EACCES;
++	}
++
++	return 0;
++}
++
++static int cgroup_allow_attach(struct cgroup *cgrp, struct cgroup_taskset *tset)
++{
++	struct cgroup_subsys_state *css;
++	int i;
++	int ret;
++
++	for_each_css(css, i, cgrp) {
++		if (css->ss->allow_attach) {
++			ret = css->ss->allow_attach(css, tset);
++			if (ret)
++				return ret;
++		} else {
++			return -EACCES;
++		}
++	}
++
++	return 0;
++}
++
+ /*
+  * Find the task_struct of the task to attach by vpid and pass it along to the
+  * function to attach either it or all tasks in its threadgroup. Will lock
+@@ -2365,9 +2403,24 @@ retry_find_task:
+ 		if (!uid_eq(cred->euid, GLOBAL_ROOT_UID) &&
+ 		    !uid_eq(cred->euid, tcred->uid) &&
+ 		    !uid_eq(cred->euid, tcred->suid)) {
+-			rcu_read_unlock();
+-			ret = -EACCES;
+-			goto out_unlock_cgroup;
++			/*
++			 * if the default permission check fails, give each
++			 * cgroup a chance to extend the permission check
++			 */
++			struct cgroup_taskset tset = {
++				.src_csets = LIST_HEAD_INIT(tset.src_csets),
++				.dst_csets = LIST_HEAD_INIT(tset.dst_csets),
++				.csets = &tset.src_csets,
++			};
++			struct css_set *cset;
++			cset = task_css_set(tsk);
++			list_add(&cset->mg_node, &tset.src_csets);
++			ret = cgroup_allow_attach(cgrp, &tset);
++			list_del(&tset.src_csets);
++			if (ret) {
++				rcu_read_unlock();
++				goto out_unlock_cgroup;
++			}
+ 		}
+ 	} else
+ 		tsk = current;
+diff --git a/kernel/cpu.c b/kernel/cpu.c
+index 90a3d01..2fb146b 100644
+--- a/kernel/cpu.c
++++ b/kernel/cpu.c
+@@ -791,3 +791,23 @@ void init_cpu_online(const struct cpumask *src)
+ {
+ 	cpumask_copy(to_cpumask(cpu_online_bits), src);
+ }
++
++static ATOMIC_NOTIFIER_HEAD(idle_notifier);
++
++void idle_notifier_register(struct notifier_block *n)
++{
++	atomic_notifier_chain_register(&idle_notifier, n);
++}
++EXPORT_SYMBOL_GPL(idle_notifier_register);
++
++void idle_notifier_unregister(struct notifier_block *n)
++{
++	atomic_notifier_chain_unregister(&idle_notifier, n);
++}
++EXPORT_SYMBOL_GPL(idle_notifier_unregister);
++
++void idle_notifier_call_chain(unsigned long val)
++{
++	atomic_notifier_call_chain(&idle_notifier, val, NULL);
++}
++EXPORT_SYMBOL_GPL(idle_notifier_call_chain);
+diff --git a/kernel/debug/debug_core.c b/kernel/debug/debug_core.c
+index 1adf62b..af06122 100644
+--- a/kernel/debug/debug_core.c
++++ b/kernel/debug/debug_core.c
+@@ -87,6 +87,10 @@ static int kgdb_use_con;
+ bool dbg_is_early = true;
+ /* Next cpu to become the master debug core */
+ int dbg_switch_cpu;
++/* Flag for entering kdb when a panic occurs */
++static bool break_on_panic = true;
++/* Flag for entering kdb when an exception occurs */
++static bool break_on_exception = true;
+ 
+ /* Use kdb or gdbserver mode */
+ int dbg_kdb_mode = 1;
+@@ -101,6 +105,8 @@ early_param("kgdbcon", opt_kgdb_con);
+ 
+ module_param(kgdb_use_con, int, 0644);
+ module_param(kgdbreboot, int, 0644);
++module_param(break_on_panic, bool, 0644);
++module_param(break_on_exception, bool, 0644);
+ 
+ /*
+  * Holds information about breakpoints in a kernel. These breakpoints are
+@@ -690,6 +696,9 @@ kgdb_handle_exception(int evector, int signo, int ecode, struct pt_regs *regs)
+ 	if (arch_kgdb_ops.enable_nmi)
+ 		arch_kgdb_ops.enable_nmi(0);
+ 
++	if (unlikely(signo != SIGTRAP && !break_on_exception))
++		return 1;
++
+ 	memset(ks, 0, sizeof(struct kgdb_state));
+ 	ks->cpu			= raw_smp_processor_id();
+ 	ks->ex_vector		= evector;
+@@ -821,6 +830,9 @@ static int kgdb_panic_event(struct notifier_block *self,
+ 			    unsigned long val,
+ 			    void *data)
+ {
++	if (!break_on_panic)
++		return NOTIFY_DONE;
++
+ 	if (dbg_kdb_mode)
+ 		kdb_printf("PANIC: %s\n", (char *)data);
+ 	kgdb_breakpoint();
+diff --git a/kernel/debug/kdb/kdb_io.c b/kernel/debug/kdb/kdb_io.c
+index 7c70812..13a1e6b 100644
+--- a/kernel/debug/kdb/kdb_io.c
++++ b/kernel/debug/kdb/kdb_io.c
+@@ -216,7 +216,7 @@ static char *kdb_read(char *buffer, size_t bufsize)
+ 	int i;
+ 	int diag, dtab_count;
+ 	int key;
+-
++	static int last_crlf;
+ 
+ 	diag = kdbgetintenv("DTABCOUNT", &dtab_count);
+ 	if (diag)
+@@ -237,6 +237,9 @@ poll_again:
+ 		return buffer;
+ 	if (key != 9)
+ 		tab = 0;
++	if (key != 10 && key != 13)
++		last_crlf = 0;
++
+ 	switch (key) {
+ 	case 8: /* backspace */
+ 		if (cp > buffer) {
+@@ -254,7 +257,12 @@ poll_again:
+ 			*cp = tmp;
+ 		}
+ 		break;
+-	case 13: /* enter */
++	case 10: /* new line */
++	case 13: /* carriage return */
++		/* handle \n after \r */
++		if (last_crlf && last_crlf != key)
++			break;
++		last_crlf = key;
+ 		*lastchar++ = '\n';
+ 		*lastchar++ = '\0';
+ 		if (!KDB_STATE(KGDB_TRANS)) {
+diff --git a/kernel/events/core.c b/kernel/events/core.c
+index cb86038..295c61b 100644
+--- a/kernel/events/core.c
++++ b/kernel/events/core.c
+@@ -6749,7 +6749,6 @@ skip_type:
+ 		__perf_event_init_context(&cpuctx->ctx);
+ 		lockdep_set_class(&cpuctx->ctx.mutex, &cpuctx_mutex);
+ 		lockdep_set_class(&cpuctx->ctx.lock, &cpuctx_lock);
+-		cpuctx->ctx.type = cpu_context;
+ 		cpuctx->ctx.pmu = pmu;
+ 
+ 		__perf_cpu_hrtimer_init(cpuctx, cpu);
+@@ -7391,7 +7390,19 @@ SYSCALL_DEFINE5(perf_event_open,
+ 		 * task or CPU context:
+ 		 */
+ 		if (move_group) {
+-			if (group_leader->ctx->type != ctx->type)
++			/*
++			 * Make sure we're both on the same task, or both
++			 * per-cpu events.
++			 */
++			if (group_leader->ctx->task != ctx->task)
++				goto err_context;
++
++			/*
++			 * Make sure we're both events for the same CPU;
++			 * grouping events for different CPUs is broken; since
++			 * you can never concurrently schedule them anyhow.
++			 */
++			if (group_leader->cpu != event->cpu)
+ 				goto err_context;
+ 		} else {
+ 			if (group_leader->ctx != ctx)
+diff --git a/kernel/fork.c b/kernel/fork.c
+index 9b7d746..d3a8141 100644
+--- a/kernel/fork.c
++++ b/kernel/fork.c
+@@ -201,6 +201,9 @@ struct kmem_cache *vm_area_cachep;
+ /* SLAB cache for mm_struct structures (tsk->mm) */
+ static struct kmem_cache *mm_cachep;
+ 
++/* Notifier list called when a task struct is freed */
++static ATOMIC_NOTIFIER_HEAD(task_free_notifier);
++
+ static void account_kernel_stack(struct thread_info *ti, int account)
+ {
+ 	struct zone *zone = page_zone(virt_to_page(ti));
+@@ -234,6 +237,18 @@ static inline void put_signal_struct(struct signal_struct *sig)
+ 		free_signal_struct(sig);
+ }
+ 
++int task_free_register(struct notifier_block *n)
++{
++	return atomic_notifier_chain_register(&task_free_notifier, n);
++}
++EXPORT_SYMBOL(task_free_register);
++
++int task_free_unregister(struct notifier_block *n)
++{
++	return atomic_notifier_chain_unregister(&task_free_notifier, n);
++}
++EXPORT_SYMBOL(task_free_unregister);
++
+ void __put_task_struct(struct task_struct *tsk)
+ {
+ 	WARN_ON(!tsk->exit_state);
+@@ -246,6 +261,7 @@ void __put_task_struct(struct task_struct *tsk)
+ 	delayacct_tsk_free(tsk);
+ 	put_signal_struct(tsk->signal);
+ 
++	atomic_notifier_call_chain(&task_free_notifier, 0, tsk);
+ 	if (!profile_handoff_task(tsk))
+ 		free_task(tsk);
+ }
+@@ -735,7 +751,8 @@ struct mm_struct *mm_access(struct task_struct *task, unsigned int mode)
+ 
+ 	mm = get_task_mm(task);
+ 	if (mm && mm != current->mm &&
+-			!ptrace_may_access(task, mode)) {
++			!ptrace_may_access(task, mode) &&
++			!capable(CAP_SYS_RESOURCE)) {
+ 		mmput(mm);
+ 		mm = ERR_PTR(-EACCES);
+ 	}
+@@ -1287,6 +1304,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
+ 
+ 	p->utime = p->stime = p->gtime = 0;
+ 	p->utimescaled = p->stimescaled = 0;
++	p->cpu_power = 0;
+ #ifndef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
+ 	p->prev_cputime.utime = p->prev_cputime.stime = 0;
+ #endif
+diff --git a/kernel/kmod.c b/kernel/kmod.c
+index 80f7a6d..784e4b1 100644
+--- a/kernel/kmod.c
++++ b/kernel/kmod.c
+@@ -496,7 +496,22 @@ static void helper_unlock(void)
+ 	if (atomic_dec_and_test(&running_helpers))
+ 		wake_up(&running_helpers_waitq);
+ }
++#ifdef	CONFIG_HISI_SNAPSHOT_BOOT
++static void helper_lock_force(void)
++{
++	atomic_inc(&running_helpers);
++	smp_mb();
++}
++
++static void helper_unlock_force(void)
++{
++	int tmp;
+ 
++	tmp = atomic_dec_and_test(&running_helpers);
++	if (tmp && (usermodehelper_disabled == 0))
++		wake_up(&running_helpers_waitq);
++}
++#endif
+ /**
+  * call_usermodehelper_setup - prepare to call a usermode helper
+  * @path: path to usermode executable
+@@ -615,6 +630,47 @@ unlock:
+ }
+ EXPORT_SYMBOL(call_usermodehelper_exec);
+ 
++#ifdef	CONFIG_HISI_SNAPSHOT_BOOT
++int call_usermodehelper_exec_force(struct subprocess_info *sub_info, int wait)
++{
++	DECLARE_COMPLETION_ONSTACK(done);
++	int retval = 0;
++
++	helper_lock_force();
++
++	if (sub_info->path[0] == '\0')
++		goto out;
++
++	if (!khelper_wq) {
++		retval = -EBUSY;
++		goto out;
++	}
++
++	sub_info->complete = &done;
++	sub_info->wait = wait;
++
++	queue_work(khelper_wq, &sub_info->work);
++	if (wait == UMH_NO_WAIT)    /* task has freed sub_info */
++		goto unlock;
++	wait_for_completion(&done);
++	retval = sub_info->retval;
++
++out:
++	call_usermodehelper_freeinfo(sub_info);
++unlock:
++	helper_unlock_force();
++
++	return retval;
++}
++#else
++int call_usermodehelper_exec_force(struct subprocess_info *sub_info, int wait)
++{
++	return 0;
++}
++
++#endif
++EXPORT_SYMBOL(call_usermodehelper_exec_force);
++
+ /**
+  * call_usermodehelper() - prepare and start a usermode application
+  * @path: path to usermode executable
+diff --git a/kernel/locking/mutex.c b/kernel/locking/mutex.c
+index dadbf88..4541951 100644
+--- a/kernel/locking/mutex.c
++++ b/kernel/locking/mutex.c
+@@ -378,8 +378,14 @@ done:
+ 	 * reschedule now, before we try-lock the mutex. This avoids getting
+ 	 * scheduled out right after we obtained the mutex.
+ 	 */
+-	if (need_resched())
++	if (need_resched()) {
++		/*
++		 * We _should_ have TASK_RUNNING here, but just in case
++		 * we do not, make it so, otherwise we might get stuck.
++		 */
++		__set_current_state(TASK_RUNNING);
+ 		schedule_preempt_disabled();
++	}
+ 
+ 	return false;
+ }
+diff --git a/kernel/panic.c b/kernel/panic.c
+index cf80672..8bba197 100644
+--- a/kernel/panic.c
++++ b/kernel/panic.c
+@@ -23,10 +23,14 @@
+ #include <linux/sysrq.h>
+ #include <linux/init.h>
+ #include <linux/nmi.h>
++#include <linux/console.h>
+ 
+ #define PANIC_TIMER_STEP 100
+ #define PANIC_BLINK_SPD 18
+ 
++/* Machine specific panic information string */
++char *mach_panic_string;
++
+ int panic_on_oops = CONFIG_PANIC_ON_OOPS_VALUE;
+ static unsigned long tainted_mask;
+ static int pause_on_oops;
+@@ -145,6 +149,15 @@ void panic(const char *fmt, ...)
+ 
+ 	bust_spinlocks(0);
+ 
++	/*
++	 * We may have ended up stopping the CPU holding the lock (in
++	 * smp_send_stop()) while still having some valuable data in the console
++	 * buffer.  Try to acquire the lock then release it regardless of the
++	 * result.  The release will also print the buffers out.
++	 */
++	console_trylock();
++	console_unlock();
++
+ 	if (!panic_blink)
+ 		panic_blink = no_blink;
+ 
+@@ -396,6 +409,11 @@ late_initcall(init_oops_id);
+ void print_oops_end_marker(void)
+ {
+ 	init_oops_id();
++
++	if (mach_panic_string)
++		printk(KERN_WARNING "Board Information: %s\n",
++		       mach_panic_string);
++
+ 	pr_warn("---[ end trace %016llx ]---\n", (unsigned long long)oops_id);
+ }
+ 
+diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
+index c2ae461..13f2f07 100644
+--- a/kernel/power/Kconfig
++++ b/kernel/power/Kconfig
+@@ -18,15 +18,76 @@ config SUSPEND_FREEZER
+ 
+ 	  Turning OFF this setting is NOT recommended! If in doubt, say Y.
+ 
++config WAKELOCK
++	bool "Android's method of preventing suspend"
++	default y
++	---help---
++	  This allows applications to prevent the CPU from suspending while
++	  they need it.
++
++	  Say Y if you are running an android userspace.
++
+ config HIBERNATE_CALLBACKS
+ 	bool
+ 
++config HISI_SNAPSHOT_BOOT
++	bool "snapshot fastboot Support"
++	select HIBERNATION
++	help
++	  Enable the suspend to disk (STD) functionality, which is usually
++	  called "hibernation" in user interfaces.  STD checkpoints the
++	  system and powers it off; and restores that checkpoint on reboot.
++
++	  You can suspend your machine with 'echo disk > /sys/power/state'
++	  after placing resume=/dev/swappartition on the kernel command line
++	  in your bootloader's configuration file.
++
++choice
++	prompt "image store type"
++	depends on HISI_SNAPSHOT_BOOT
++	default DEFAULT_DDR
++	help
++	  Select the I/O scheduler which will be used by default for all
++	  block devices.
++
++	config DEFAULT_MTD
++		bool "use MTD partition"
++		help
++		Note there is currently not a way to specify
++		which device to save the suspended image to.
++		It will simply pick the first available swap
++		device.
++
++	config DEFAULT_DDR
++		bool "use ddr memory"
++		help
++		Note there is currently not a way to specify
++		which device to save the suspended image to.
++		It will save imgae to ddr and then write to
++		mtdblock in uboot.
++
++endchoice
++
++
++if DEFAULT_DDR
++config SNAPSHOT_BUF_START
++	hex "snapshot buffer start addr"
++	default "0x8a000000"
++
++config SNAPSHOT_BUF_SIZE
++	hex "snapshot buffer size"
++	default "0x4000000"
++endif
++
++
++
+ config HIBERNATION
+ 	bool "Hibernation (aka 'suspend to disk')"
+-	depends on SWAP && ARCH_HIBERNATION_POSSIBLE
++	depends on SWAP && ARCH_HIBERNATION_POSSIBLE || HISI_SNAPSHOT_BOOT
+ 	select HIBERNATE_CALLBACKS
+ 	select LZO_COMPRESS
+ 	select LZO_DECOMPRESS
++	select GZIP_COMPRESS
+ 	select CRC32
+ 	---help---
+ 	  Enable the suspend to disk (STD) functionality, which is usually
+@@ -66,6 +127,14 @@ config HIBERNATION
+ 
+ 	  For more information take a look at <file:Documentation/power/swsusp.txt>.
+ 
++config GZIP_COMPRESS
++	bool
++	depends on HISI_SNAPSHOT_BOOT && HIBERNATION
++	---help---
++	Allow the system to compress the hibernation image by gzip method, so that
++	upon the next boot, the u-boot can use the hardware method to decompress the
++	saved image.
++
+ config ARCH_SAVE_PAGE_KEYS
+ 	bool
+ 
+@@ -83,7 +152,7 @@ config PM_STD_PARTITION
+ 
+ 	  The partition specified can be overridden by specifying:
+ 
+-		resume=/dev/<other device> 
++		hbcomp=/dev/<other device>
+ 
+ 	  which will set the resume partition to the device specified. 
+ 
+@@ -309,3 +378,10 @@ config PM_GENERIC_DOMAINS_OF
+ config CPU_PM
+ 	bool
+ 	depends on SUSPEND || CPU_IDLE
++
++config SUSPEND_TIME
++	bool "Log time spent in suspend"
++	---help---
++	  Prints the time spent in suspend in the kernel log, and
++	  keeps statistics on the time spent in suspend in
++	  /sys/kernel/debug/suspend_time
+diff --git a/kernel/power/Makefile b/kernel/power/Makefile
+index 29472bf..d08db66 100644
+--- a/kernel/power/Makefile
++++ b/kernel/power/Makefile
+@@ -8,8 +8,14 @@ obj-$(CONFIG_FREEZER)		+= process.o
+ obj-$(CONFIG_SUSPEND)		+= suspend.o
+ obj-$(CONFIG_PM_TEST_SUSPEND)	+= suspend_test.o
+ obj-$(CONFIG_HIBERNATION)	+= hibernate.o snapshot.o swap.o user.o \
+-				   block_io.o
++				   block_io.o crc_check.o
+ obj-$(CONFIG_PM_AUTOSLEEP)	+= autosleep.o
+ obj-$(CONFIG_PM_WAKELOCKS)	+= wakelock.o
++obj-$(CONFIG_SUSPEND_TIME)	+= suspend_time.o
+ 
+ obj-$(CONFIG_MAGIC_SYSRQ)	+= poweroff.o
++
++obj-$(CONFIG_SUSPEND)	+= wakeup_reason.o
++
++ccflags-$(CONFIG_HISI_SNAPSHOT_BOOT) += -DUSE_FIXED_SMALL_CHUNK
++obj-$(CONFIG_HISI_SNAPSHOT_BOOT) += compress.o compress_wrapper.o
+diff --git a/kernel/power/compress.c b/kernel/power/compress.c
+new file mode 100644
+index 0000000..48064be
+--- /dev/null
++++ b/kernel/power/compress.c
+@@ -0,0 +1,425 @@
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/fs.h>
++#include <linux/mount.h>
++#include <linux/genhd.h>
++#include <linux/lzo.h>
++#include <linux/vmalloc.h>
++#include <asm/io.h>
++#include <asm/cacheflush.h>
++#include <mach/io.h>
++#include <mach/platform.h>
++#include <linux/of_address.h>
++#include <linux/platform_device.h>
++
++#include "power.h"
++#include "compress.h"
++
++extern int
++find_bootmem(const char *name, unsigned int *ofs, unsigned int *sz);
++
++#define BOOTLOADER_ADMA_SIDE_JOB
++
++#define __ALIGN_UP(x,y) (((x)+(y)-1) & (~((y)-1)))
++#define PAGE_NR(x) (((x) + PAGE_SIZE - 1) / PAGE_SIZE)
++
++#ifdef BOOTLOADER_ADMA_SIDE_JOB
++/* guessing ratio started with (5+5)M:2M */
++#define COMP_SRC_SZ_DEFAULT (SZ_1M * 5U)
++#define COMP_DST_SZ_DEFAULT (SZ_1M * 2U)
++#else
++#define COMP_SRC_SZ_DEFAULT (SZ_1M * 9U)
++#define COMP_DST_SZ_DEFAULT (SZ_1M * 3U)
++#endif
++
++
++#ifdef CONFIG_DEFAULT_MTD
++
++#define SNAPSHOT_BUF_START (PLAT_PHYS_OFFSET + (128<<20UL))
++#define SNAPSHOT_BUF_SIZE  (2<<20UL)
++
++static int hbpart_read(struct compress_writer *writer,
++		sector_t page_i, sector_t page_nr, void *buf)
++{
++	struct block_device *bdev_orig = hib_resume_bdev;
++	sector_t p;
++	int ret;
++
++	bdev_orig = hib_resume_bdev;
++	hib_resume_bdev = writer->bdev;
++	for (p = 0; p < page_nr; p++, page_i++, buf += PAGE_SIZE) {
++		ret = hib_bio_read_page(page_i, writer->pagebuf, NULL);
++		if (ret < 0) {
++			hib_resume_bdev = bdev_orig;
++			return ret;
++		}
++		memcpy(buf, writer->pagebuf, PAGE_SIZE);
++	}
++	hib_resume_bdev = bdev_orig;
++	return (int)p;
++}
++
++static int hbpart_write(struct compress_writer *writer,
++		sector_t page_i, sector_t page_nr, const void *buf)
++{
++	struct block_device *bdev_orig = hib_resume_bdev;
++	sector_t p;
++	int ret;
++
++	bdev_orig = hib_resume_bdev;
++	hib_resume_bdev = writer->bdev;
++	for (p = 0; p < page_nr; p++, page_i++, buf += PAGE_SIZE) {
++		memcpy(writer->pagebuf, buf, PAGE_SIZE);
++		ret = hib_bio_write_page(page_i, writer->pagebuf, NULL);
++		if (ret < 0) {
++			hib_resume_bdev = bdev_orig;
++			return ret;
++		}
++	}
++	hib_resume_bdev = bdev_orig;
++	return (int)p;
++}
++
++static int susp_writer_finish(struct compress_writer *writer)
++{
++	/*do nothing*/
++	return 0;
++}
++
++#else
++
++#define SNAPSHOT_BUF_START (CONFIG_SNAPSHOT_BUF_START)
++#define SNAPSHOT_BUF_SIZE  (CONFIG_SNAPSHOT_BUF_SIZE)
++
++static void __iomem *g_reg_sysctrl_base = NULL;
++
++static int hbpart_read(struct compress_writer *writer,
++		sector_t page_i, sector_t page_nr, void *buf)
++{
++	sector_t p;
++
++	sector_t total_pages;
++
++	if (!writer)
++		return -EINVAL;
++
++	total_pages = writer->image_buf_sz/PAGE_SIZE;
++
++	if ((page_i + page_nr) > total_pages)
++		return -EINVAL;
++
++	for (p = 0; p < page_nr; p++, page_i++, buf += PAGE_SIZE)
++		memcpy(buf, (writer->image + page_i*PAGE_SIZE), PAGE_SIZE);
++
++	return (int)p;
++}
++
++static int hbpart_write(struct compress_writer *writer,
++		sector_t page_i, sector_t page_nr, const void *buf)
++{
++	sector_t p;
++
++	sector_t total_pages;
++
++	if (!writer)
++		return -EINVAL;
++
++	total_pages = writer->image_buf_sz/PAGE_SIZE;
++
++	if ((page_i + page_nr) > total_pages) {
++		printk(KERN_INFO "%s write data exceed!\n", __func__);
++		return -EINVAL;
++	}
++
++	for (p = 0; p < page_nr; p++, page_i++, buf += PAGE_SIZE)
++		memcpy((writer->image + page_i*PAGE_SIZE), buf, PAGE_SIZE);
++
++	flush_cache_all();
++
++	return (int)p;
++}
++
++static int susp_writer_finish(struct compress_writer *writer)
++{
++	unsigned long image_addr, image_sz;
++
++	union sscomp_header *sscomp = &writer->sscomp;
++	const struct sscomp_block *block = &sscomp->b.blocks[0];
++	int total_blocks = sscomp->info.meta_blocks + sscomp->info.data_blocks;
++	int total_org_size = 0;
++	int total_comp_size = 0;
++	int i;
++
++#define SNAPSHOT_MAGIC  0x53414e50  /*'S''N''A''P'*/
++
++	if (!g_reg_sysctrl_base) {
++		pr_err("%s: g_reg_sysctrl_base is NULL, error!\n", __func__);
++		WARN_ON(!g_reg_sysctrl_base);
++	}
++
++	writel(SNAPSHOT_MAGIC, g_reg_sysctrl_base + 0xa4);
++
++	image_addr = SNAPSHOT_BUF_START +
++			 ((unsigned long)writer->image - (unsigned long)writer);
++
++	writel(image_addr, g_reg_sysctrl_base + 0xa8);
++
++	for (i = 0; i < total_blocks; i++) {
++		unsigned int aligned_comp_size;
++		aligned_comp_size =
++			(block->comp_size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
++		total_org_size += block->org_size;
++		total_comp_size += aligned_comp_size;
++		printk(KERN_INFO "block[%2d]: %9d:%d(%d)\n", i,
++			  block->org_size, block->comp_size, aligned_comp_size);
++		block++;
++	}
++
++	printk(KERN_INFO "original:   %9d bytes\n", total_org_size);
++	printk(KERN_INFO "compressed: %9d bytes\n", total_comp_size);
++
++	image_sz = __ALIGN_UP(total_comp_size+sizeof(*sscomp), SZ_1M);
++	writel(image_sz, g_reg_sysctrl_base + 0xac);
++
++	return 0;
++}
++
++#endif
++
++static int do_compress(struct compress_writer *writer,
++		struct sscomp_block *block, unsigned int *src_len)
++{
++	void *src = (void*)writer->src;
++	void *dst = (void*)writer->dst;
++	size_t tmp_slen, tmp_dlen;
++	const unsigned int slen = *src_len;
++	int ret, nr_compressed_pages;
++	bool succeed = false;
++	struct compress_wrapper *compressor = writer->compressor;
++	void *work_mem = (void*)writer->work_mem;
++
++	unsigned int sb_len = COMP_SRC_SZ_DEFAULT;
++	unsigned int db_len = COMP_DST_SZ_DEFAULT;
++
++	do {
++		printk(KERN_DEBUG "[comp: guessing %u:%u]\n", sb_len, db_len);
++		tmp_slen = min_t(size_t, slen, sb_len);
++		ret = compressor->compress(
++			dst, &tmp_dlen, src, tmp_slen, 0, work_mem);
++		if (ret >= 0 && tmp_dlen <= db_len) {
++			succeed = true;
++			break;
++		}
++		sb_len -= SZ_1K * 512U;
++		db_len += SZ_1K * 512U;
++	} while (sb_len >= db_len);
++
++	if (!succeed)
++		return -EFAULT;
++
++	printk(KERN_INFO "[comp: %08u -> %08u]\n", tmp_slen, tmp_dlen);
++
++	block->org_size = tmp_slen;
++	block->comp_size = tmp_dlen;
++
++	nr_compressed_pages = (tmp_dlen + PAGE_SIZE - 1) / PAGE_SIZE;
++
++	*src_len = slen - tmp_slen;
++	/* backup before verifying */
++	if (*src_len)
++		memmove(dst + writer->dst_buf_sz - *src_len,
++				src + tmp_slen, *src_len);
++
++	/* restore after verifying */
++	if (*src_len)
++		memmove(src, dst + writer->dst_buf_sz - *src_len, *src_len);
++
++	return nr_compressed_pages;
++}
++
++void put_susp_compress_writer(struct compress_writer *writer)
++{
++	if (!writer)
++		return;
++
++	if (writer->pagebuf)
++		free_page((unsigned long)writer->pagebuf);
++	writer->pagebuf = NULL;
++
++	if (writer->bdev)
++		blkdev_put(writer->bdev, FMODE_WRITE);
++	writer->bdev = NULL;
++
++	iounmap(writer);
++}
++
++struct compress_writer *get_susp_compress_writer(const char *path)
++{
++	struct compress_writer *writer;
++	struct compress_wrapper *compressor;
++	struct block_device *bdev;
++	const char *d;
++	char spath[64], dname[BDEVNAME_SIZE];
++	dev_t device;
++	int ret;
++
++	BUILD_BUG_ON(sizeof(writer->sscomp.info) > sizeof(writer->sscomp.b.c));
++	BUILD_BUG_ON(sizeof(writer->sscomp.b) > sizeof(writer->sscomp.c));
++	BUILD_BUG_ON(sizeof(writer->sscomp) % PAGE_SIZE);
++
++	compressor = hb_bdev_find_compressor_by_name(compress_method);
++	if (!compressor) {
++		printk(KERN_ERR "%s: could not found compressor %s\n",
++				__func__, compress_method);
++		return NULL;
++	}
++
++	if (!path || path[0] == '\0') {
++		printk(KERN_ERR "%s: invalid backing device path.\n", __func__);
++		return NULL;
++	}
++
++	strncpy(spath, path, sizeof(spath));
++	if (strncmp(spath, "/dev/block/", 11) == 0)
++		strcpy(spath + 5, spath + 11);
++	device = name_to_dev_t(spath);
++	if (device == MKDEV(0, 0)) {
++		printk(KERN_ERR "%s: could not found %s.\n", __func__, path);
++		return NULL;
++	}
++
++	bdev = bdget(device);
++	if (!bdev) {
++		printk(KERN_ERR "%s: could not ref %s.\n", __func__, path);
++		return NULL;
++	}
++	bdev = bdgrab(bdev);
++	bdput(bdev);
++
++	ret = blkdev_get(bdev, FMODE_WRITE, NULL);
++	if (ret) {
++		printk(KERN_ERR "%s: could not get %s.\n", __func__, path);
++		bdput(bdev);
++		return NULL;
++	}
++
++	if (strncmp(spath, "/dev/", 5) == 0)
++		strcpy(spath, spath + 5);
++	d = bdevname(bdev, dname);
++	if (strcmp(spath, d)) {
++		printk(KERN_ERR "%s: something wrong %s != %s.\n", __func__,
++				spath, d);
++		blkdev_put(bdev, FMODE_WRITE);
++		return NULL;
++	}
++
++	ret = set_blocksize(bdev, PAGE_SIZE);
++	if (ret < 0) {
++		printk(KERN_ERR "%s: %s does not support PAGE_SIZE IO.\n",
++				__func__, path);
++		blkdev_put(bdev, FMODE_WRITE);
++		return NULL;
++	}
++
++	/* do not use kmalloc/vmalloc/etc. */
++	writer = ioremap_cache(SNAPSHOT_BUF_START, SNAPSHOT_BUF_SIZE);
++	if (!writer) {
++		blkdev_put(bdev, FMODE_WRITE);
++		return NULL;
++	}
++
++	printk(KERN_INFO "ioremap phys:0x%x to 0x%lx\n",
++			 SNAPSHOT_BUF_START , (unsigned long)writer);
++
++	memset(writer, 0, sizeof(*writer));
++
++	writer->compressor = compressor;
++
++	writer->work_mem = __ALIGN_UP(
++		(unsigned long)writer + sizeof(*writer), PAGE_SIZE);
++#ifdef USE_FIXED_SMALL_CHUNK
++	writer->src_buf_sz = SZ_1K * 512;
++	writer->dst_buf_sz = SZ_1K * 512;
++#else
++	/* it should be allocated as src:dst=10M:9M fixed. */
++	writer->src_buf_sz = SZ_1M * 10U;
++	writer->dst_buf_sz = SZ_1M * 9U;
++#endif
++
++	writer->src = __ALIGN_UP(writer->work_mem + 1U, SZ_1M);
++	writer->dst = writer->src + writer->src_buf_sz;
++
++#ifdef CONFIG_DEFAULT_MTD
++	if (writer->dst + writer->dst_buf_sz >
++			(unsigned long)writer + SNAPSHOT_BUF_SIZE) {
++		printk(KERN_ERR "%s: not enough space\n", __func__);
++		put_susp_compress_writer(writer);
++		return NULL;
++	}
++	printk(KERN_INFO "PM: compress: using dev %s(%u:%u)\n",
++			d, MAJOR(device), MINOR(device));
++#else
++	writer->image = (void *)__ALIGN_UP(
++			writer->dst + writer->dst_buf_sz + 1U, SZ_1M);
++	writer->image_buf_sz = SNAPSHOT_BUF_SIZE - (5<<20UL);
++
++	if ((unsigned long)writer->image + writer->image_buf_sz >
++			(unsigned long)writer + SNAPSHOT_BUF_SIZE) {
++		printk(KERN_ERR "%s: not enough space\n", __func__);
++		put_susp_compress_writer(writer);
++		return NULL;
++	}
++
++	printk(KERN_INFO "PM: compress: using ddr, image:0x%x, image_buf_size:%d\n",
++			(unsigned int)writer->image, writer->image_buf_sz);
++#endif
++	writer->bdev = bdev;
++	writer->device = device;
++	writer->compress = do_compress;
++	writer->write = hbpart_write;
++	writer->read = hbpart_read;
++	writer->finish = susp_writer_finish;
++	writer->pagebuf = (void*)get_zeroed_page(GFP_KERNEL);
++
++	writer->sscomp.info.comp_type = compressor->type;
++	writer->sscomp.info.image_ofs = PAGE_NR(sizeof(writer->sscomp));
++#ifndef USE_FIXED_SMALL_CHUNK
++	writer->sscomp.info.block_type = COMP_BLK_DYNAMIC;
++#else
++	writer->sscomp.info.decomp_block_size = writer->src_buf_sz;
++	writer->sscomp.info.block_type = COMP_BLK_FIXED;
++#endif
++
++	return writer;
++}
++
++static int hi_pm_hibernate_probe(struct platform_device *pdev)
++{
++	g_reg_sysctrl_base = of_iomap(pdev->dev.of_node, 0);
++	if (WARN_ON(!g_reg_sysctrl_base))
++		return -ENOMEM;
++
++	return 0;
++}
++
++static const struct of_device_id hi_pm_hibernate_match_table[] = {
++	{ .compatible = "hisilicon,hibvt-pm-hibernate" },
++	{ }
++};
++MODULE_DEVICE_TABLE(of, hi_pm_hibernate_match_table);
++
++static struct platform_driver hi_pm_hibernate_driver = {
++	.probe          = hi_pm_hibernate_probe,
++	.driver         = {
++		.name   = "hibvt-pm-hibernate",
++		.of_match_table = hi_pm_hibernate_match_table,
++	},
++};
++
++static int __init hi_pm_hibernate_init(void)
++{
++	return platform_driver_register(&hi_pm_hibernate_driver);
++}
++core_initcall(hi_pm_hibernate_init);
++
++MODULE_LICENSE("GPL v2");
+diff --git a/kernel/power/compress.h b/kernel/power/compress.h
+new file mode 100644
+index 0000000..3c8f8fa
+--- /dev/null
++++ b/kernel/power/compress.h
+@@ -0,0 +1,96 @@
++#ifndef __KEREL_POWER_COMPRESS_H_
++#define __KEREL_POWER_COMPRESS_H_
++
++struct sscomp_block {
++	unsigned int org_size;
++	unsigned int comp_size;
++};
++
++union sscomp_header {
++	struct {
++#define COMP_TYPE_LZF 1
++#define COMP_TYPE_LZO 2
++#define COMP_TYPE_LZMA 3
++#define COMP_TYPE_BZIP2 4
++#define COMP_TYPE_SNAPPY 5
++#define COMP_TYPE_QUICKLZ 6
++#define COMP_TYPE_GZIP	7
++		int comp_type;
++
++		int meta_blocks;
++		int meta_pages;
++		int data_blocks;
++		int data_pages;
++		unsigned int decomp_block_size;
++		int image_ofs;
++
++		int crc32;
++
++#define SSCOMP_MAGIC_4 "SSCOMP#4"
++		char magic[8];
++		unsigned char sha1sum[20];
++
++#define COMP_BLK_LEGACY 0
++#define COMP_BLK_FIXED 1
++#define COMP_BLK_DYNAMIC 2
++                int block_type;
++
++		unsigned long ctl_func;
++		unsigned long ctl_data;
++	} info __attribute__((packed));
++	struct {
++		unsigned char c[128];
++#define MAX_COMP_BLOCKS ((4096-128)/sizeof(struct sscomp_block))
++		struct sscomp_block blocks[MAX_COMP_BLOCKS];
++	} b __attribute__((packed));
++	unsigned char c[4096];
++};
++
++struct compress_wrapper {
++	const char *name;
++	int type;
++	int (*compress)(unsigned char *dst, int *dstlen,
++                unsigned char *src, int srclen, int factor, void *extra);
++	int (*decompress)(unsigned char *dst, int *dstlen,
++                unsigned char *src, int srclen, void *extra);
++};
++
++struct compress_writer {
++	union sscomp_header sscomp;
++
++	unsigned long work_mem;
++	unsigned long src;
++	unsigned long dst;
++	unsigned int src_buf_sz;
++	unsigned int dst_buf_sz;
++	unsigned int image_buf_sz;
++
++	struct block_device *bdev;
++	dev_t device;
++
++	void *image;
++	void *pagebuf;
++
++	struct compress_wrapper *compressor;
++
++	int (*compress)(struct compress_writer *, struct sscomp_block *,
++			unsigned int *);
++	int (*decompress)(struct compress_writer *, struct sscomp_block *,
++			unsigned int *);
++	int (*write)(struct compress_writer *, sector_t page_i,
++			sector_t page_nr, const void *);
++	int (*read)(struct compress_writer *, sector_t page_i,
++			sector_t page_nr, void *buf);
++	int (*finish)(struct compress_writer *);
++};
++
++struct compress_wrapper *hb_bdev_find_compressor_by_name(const char *name);
++
++extern void put_susp_compress_writer(struct compress_writer *);
++extern struct compress_writer *get_susp_compress_writer(const char *);
++
++extern int hb_bdev_sha1_init(void);
++extern int hb_bdev_sha1_update(const u8 *data, unsigned int len);
++extern int hb_bdev_sha1_final(u8 *out);
++
++#endif /* __KEREL_POWER_COMPRESS_H_ */
+diff --git a/kernel/power/compress_wrapper.c b/kernel/power/compress_wrapper.c
+new file mode 100644
+index 0000000..93fe8f7
+--- /dev/null
++++ b/kernel/power/compress_wrapper.c
+@@ -0,0 +1,164 @@
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/err.h>
++#include <linux/lzo.h>
++
++#include <crypto/hash.h>
++
++#include "compress.h"
++
++/* I do not want to concern about {k|v}malloc something. */
++#include <crypto/sha.h>
++#include "../../crypto/internal.h"
++#include <crypto/internal/hash.h>
++#ifdef USE_SHA1
++static union my_desc_s {
++	struct shash_desc desc;
++	struct {
++		unsigned char c[sizeof(struct shash_desc)];
++		struct sha1_state sha1_state;
++	} p;
++} my_desc;
++static struct shash_alg *sha1_hash;
++
++static void hb_bdev_find_hash_sha1(void)
++{
++	struct crypto_alg *hash_alg;
++	hash_alg = crypto_find_alg("sha1", &crypto_ahash_type,
++			CRYPTO_ALG_TYPE_HASH, CRYPTO_ALG_TYPE_AHASH_MASK);
++	if (IS_ERR_OR_NULL(hash_alg)) {
++		pr_err("%s: could not found sha1.\n", __func__);
++		sha1_hash = NULL;
++	}
++	sha1_hash = container_of(hash_alg, struct shash_alg, base);
++}
++
++int hb_bdev_sha1_init(void)
++{
++	if (!sha1_hash) {
++		pr_err("%s: could not found sha1.\n", __func__);
++		return -1;
++	}
++	return sha1_hash->init(&my_desc.desc);
++}
++
++int hb_bdev_sha1_update(const u8 *data, unsigned int len)
++{
++	if (!sha1_hash) {
++		pr_err("%s: could not found sha1.\n", __func__);
++		return -1;
++	}
++	return sha1_hash->update(&my_desc.desc, data, len);
++}
++
++int hb_bdev_sha1_final(u8 *out)
++{
++	if (!sha1_hash) {
++		pr_err("%s: could not found sha1.\n", __func__);
++		return -1;
++	}
++	return sha1_hash->final(&my_desc.desc, out);
++}
++#else
++
++static inline void hb_bdev_find_hash_sha1(void) {}
++
++inline int hb_bdev_sha1_init(void){return 0; }
++
++inline int hb_bdev_sha1_update(const u8 *data, unsigned int len) {return 0; }
++
++inline int hb_bdev_sha1_final(u8 *out) {return 0; }
++
++#endif
++
++
++#if defined(CONFIG_LZO_COMPRESS) && defined(CONFIG_LZO_DECOMPRESS)
++static int lzo_compress(unsigned char *dst, int *dstlen,
++		unsigned char *src, int srclen, int unused, void *wrkmem)
++{
++	size_t tmp_slen, tmp_dlen;
++	int ret;
++
++	tmp_slen = srclen;
++	tmp_dlen = *dstlen;
++	ret = lzo1x_1_compress(src, tmp_slen, dst, &tmp_dlen, wrkmem);
++	if (ret != LZO_E_OK) {
++		pr_err("lzo1x_compress(): failed %d\n", ret);
++		return -1;
++	}
++	*dstlen = tmp_dlen;
++	return 0;
++}
++
++static int lzo_decompress(unsigned char *dst, int *dstlen,
++		unsigned char *src, int srclen, void *unused)
++{
++	size_t tmp_slen, tmp_dlen;
++	int ret;
++	tmp_slen = srclen;
++	tmp_dlen = *dstlen;
++	ret = lzo1x_decompress_safe(src, tmp_slen, dst, &tmp_dlen);
++	if (ret != LZO_E_OK) {
++		pr_err("lzo1x_decompress(): failed %d\n", ret);
++		return -1;
++	}
++	*dstlen = tmp_dlen;
++	return 0;
++}
++#endif
++
++#ifdef CONFIG_GZIP_COMPRESS
++extern int gzip_defalte(void *dst, unsigned int *dst_len, const void *src, unsigned int len);
++
++static int gzip_compress(unsigned char *dst, int *dstlen,
++		unsigned char *src, int srclen, int unused, void *wrkmem)
++{
++	return gzip_defalte(dst, dstlen, src, srclen);
++}
++
++/*static int lzma_decompress(unsigned char *dst, int *dstlen,
++		unsigned char *src, int srclen, void *unused)
++{
++	return Lzma_Decode(dst, dstlen, src, srclen);
++}*/
++#endif
++
++static struct compress_wrapper compressor[] = {
++#if defined(CONFIG_LZO_COMPRESS) && defined(CONFIG_LZO_DECOMPRESS)
++	{
++		.name = "lzo",
++		.type = COMP_TYPE_LZO,
++		.compress = lzo_compress,
++		.decompress = lzo_decompress,
++	},
++#ifdef CONFIG_GZIP_COMPRESS
++	{
++		.name = "gzip",
++		.type = COMP_TYPE_GZIP,
++		.compress = gzip_compress,
++		/*.decompress = lzma_decompress,*/
++	},
++#endif
++
++#else
++#error "there is no compressor"
++#endif
++};
++
++struct compress_wrapper *hb_bdev_find_compressor_by_name(const char *name)
++{
++	int i;
++	struct compress_wrapper *compress_wrapper;
++
++	printk("%s:%d, compressor name = %s\n", __func__, __LINE__, name);
++
++	hb_bdev_find_hash_sha1();
++
++	for (i = 0; i < ARRAY_SIZE(compressor); i++) {
++		compress_wrapper = &compressor[i];
++		if (strcmp(name, compress_wrapper->name) == 0)
++			return compress_wrapper;
++	}
++
++	return NULL;
++}
+diff --git a/kernel/power/crc_check.c b/kernel/power/crc_check.c
+new file mode 100644
+index 0000000..8964c1c
+--- /dev/null
++++ b/kernel/power/crc_check.c
+@@ -0,0 +1,250 @@
++/*
++ * This file is derived from crc32.c from the zlib-1.1.3 distribution
++ * by Jean-loup Gailly and Mark Adler.
++ */
++
++/* crc32.c -- compute the CRC-32 of a data stream
++ * Copyright (C) 1995-1998 Mark Adler
++ * For conditions of distribution and use, see copyright notice in zlib.h
++ */
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/string.h>
++#include <linux/version.h>
++#include <linux/init.h>
++
++#define local static
++#define ZEXPORT	/* empty */
++
++#define tole(x) cpu_to_le32(x)
++
++#define __BYTE_ORDER __LITTLE_ENDIAN
++
++#undef DYNAMIC_CRC_TABLE
++
++#ifdef DYNAMIC_CRC_TABLE
++
++local int crc_table_empty = 1;
++local uint32_t crc_table[256];
++local void make_crc_table OF((void));
++
++/*
++  Generate a table for a byte-wise 32-bit CRC calculation on the polynomial:
++  x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1.
++
++  Polynomials over GF(2) are represented in binary, one bit per coefficient,
++  with the lowest powers in the most significant bit.  Then adding polynomials
++  is just exclusive-or, and multiplying a polynomial by x is a right shift by
++  one.  If we call the above polynomial p, and represent a byte as the
++  polynomial q, also with the lowest power in the most significant bit (so the
++  byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p,
++  where a mod b means the remainder after dividing a by b.
++
++  This calculation is done using the shift-register method of multiplying and
++  taking the remainder.  The register is initialized to zero, and for each
++  incoming bit, x^32 is added mod p to the register if the bit is a one (where
++  x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by
++  x (which is shifting right by one and adding x^32 mod p if the bit shifted
++  out is a one).  We start with the highest power (least significant bit) of
++  q and repeat for all eight bits of q.
++
++  The table is simply the CRC of all possible eight bit values.  This is all
++  the information needed to generate CRC's on data a byte at a time for all
++  combinations of CRC register values and incoming bytes.
++*/
++local void make_crc_table()
++{
++  uint32_t c;
++  int n, k;
++  uLong poly;		/* polynomial exclusive-or pattern */
++  /* terms of polynomial defining this crc (except x^32): */
++  static const Byte p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
++
++  /* make exclusive-or pattern from polynomial (0xedb88320L) */
++  poly = 0L;
++  for (n = 0; n < sizeof(p)/sizeof(Byte); n++)
++    poly |= 1L << (31 - p[n]);
++
++  for (n = 0; n < 256; n++)
++  {
++    c = (uLong)n;
++    for (k = 0; k < 8; k++)
++      c = c & 1 ? poly ^ (c >> 1) : c >> 1;
++    crc_table[n] = tole(c);
++  }
++  crc_table_empty = 0;
++}
++#else
++/* ========================================================================
++ * Table of CRC-32's of all single-byte values (made by make_crc_table)
++ */
++
++local const uint32_t crc_table[256] = {
++tole(0x00000000L), tole(0x77073096L), tole(0xee0e612cL), tole(0x990951baL),
++tole(0x076dc419L), tole(0x706af48fL), tole(0xe963a535L), tole(0x9e6495a3L),
++tole(0x0edb8832L), tole(0x79dcb8a4L), tole(0xe0d5e91eL), tole(0x97d2d988L),
++tole(0x09b64c2bL), tole(0x7eb17cbdL), tole(0xe7b82d07L), tole(0x90bf1d91L),
++tole(0x1db71064L), tole(0x6ab020f2L), tole(0xf3b97148L), tole(0x84be41deL),
++tole(0x1adad47dL), tole(0x6ddde4ebL), tole(0xf4d4b551L), tole(0x83d385c7L),
++tole(0x136c9856L), tole(0x646ba8c0L), tole(0xfd62f97aL), tole(0x8a65c9ecL),
++tole(0x14015c4fL), tole(0x63066cd9L), tole(0xfa0f3d63L), tole(0x8d080df5L),
++tole(0x3b6e20c8L), tole(0x4c69105eL), tole(0xd56041e4L), tole(0xa2677172L),
++tole(0x3c03e4d1L), tole(0x4b04d447L), tole(0xd20d85fdL), tole(0xa50ab56bL),
++tole(0x35b5a8faL), tole(0x42b2986cL), tole(0xdbbbc9d6L), tole(0xacbcf940L),
++tole(0x32d86ce3L), tole(0x45df5c75L), tole(0xdcd60dcfL), tole(0xabd13d59L),
++tole(0x26d930acL), tole(0x51de003aL), tole(0xc8d75180L), tole(0xbfd06116L),
++tole(0x21b4f4b5L), tole(0x56b3c423L), tole(0xcfba9599L), tole(0xb8bda50fL),
++tole(0x2802b89eL), tole(0x5f058808L), tole(0xc60cd9b2L), tole(0xb10be924L),
++tole(0x2f6f7c87L), tole(0x58684c11L), tole(0xc1611dabL), tole(0xb6662d3dL),
++tole(0x76dc4190L), tole(0x01db7106L), tole(0x98d220bcL), tole(0xefd5102aL),
++tole(0x71b18589L), tole(0x06b6b51fL), tole(0x9fbfe4a5L), tole(0xe8b8d433L),
++tole(0x7807c9a2L), tole(0x0f00f934L), tole(0x9609a88eL), tole(0xe10e9818L),
++tole(0x7f6a0dbbL), tole(0x086d3d2dL), tole(0x91646c97L), tole(0xe6635c01L),
++tole(0x6b6b51f4L), tole(0x1c6c6162L), tole(0x856530d8L), tole(0xf262004eL),
++tole(0x6c0695edL), tole(0x1b01a57bL), tole(0x8208f4c1L), tole(0xf50fc457L),
++tole(0x65b0d9c6L), tole(0x12b7e950L), tole(0x8bbeb8eaL), tole(0xfcb9887cL),
++tole(0x62dd1ddfL), tole(0x15da2d49L), tole(0x8cd37cf3L), tole(0xfbd44c65L),
++tole(0x4db26158L), tole(0x3ab551ceL), tole(0xa3bc0074L), tole(0xd4bb30e2L),
++tole(0x4adfa541L), tole(0x3dd895d7L), tole(0xa4d1c46dL), tole(0xd3d6f4fbL),
++tole(0x4369e96aL), tole(0x346ed9fcL), tole(0xad678846L), tole(0xda60b8d0L),
++tole(0x44042d73L), tole(0x33031de5L), tole(0xaa0a4c5fL), tole(0xdd0d7cc9L),
++tole(0x5005713cL), tole(0x270241aaL), tole(0xbe0b1010L), tole(0xc90c2086L),
++tole(0x5768b525L), tole(0x206f85b3L), tole(0xb966d409L), tole(0xce61e49fL),
++tole(0x5edef90eL), tole(0x29d9c998L), tole(0xb0d09822L), tole(0xc7d7a8b4L),
++tole(0x59b33d17L), tole(0x2eb40d81L), tole(0xb7bd5c3bL), tole(0xc0ba6cadL),
++tole(0xedb88320L), tole(0x9abfb3b6L), tole(0x03b6e20cL), tole(0x74b1d29aL),
++tole(0xead54739L), tole(0x9dd277afL), tole(0x04db2615L), tole(0x73dc1683L),
++tole(0xe3630b12L), tole(0x94643b84L), tole(0x0d6d6a3eL), tole(0x7a6a5aa8L),
++tole(0xe40ecf0bL), tole(0x9309ff9dL), tole(0x0a00ae27L), tole(0x7d079eb1L),
++tole(0xf00f9344L), tole(0x8708a3d2L), tole(0x1e01f268L), tole(0x6906c2feL),
++tole(0xf762575dL), tole(0x806567cbL), tole(0x196c3671L), tole(0x6e6b06e7L),
++tole(0xfed41b76L), tole(0x89d32be0L), tole(0x10da7a5aL), tole(0x67dd4accL),
++tole(0xf9b9df6fL), tole(0x8ebeeff9L), tole(0x17b7be43L), tole(0x60b08ed5L),
++tole(0xd6d6a3e8L), tole(0xa1d1937eL), tole(0x38d8c2c4L), tole(0x4fdff252L),
++tole(0xd1bb67f1L), tole(0xa6bc5767L), tole(0x3fb506ddL), tole(0x48b2364bL),
++tole(0xd80d2bdaL), tole(0xaf0a1b4cL), tole(0x36034af6L), tole(0x41047a60L),
++tole(0xdf60efc3L), tole(0xa867df55L), tole(0x316e8eefL), tole(0x4669be79L),
++tole(0xcb61b38cL), tole(0xbc66831aL), tole(0x256fd2a0L), tole(0x5268e236L),
++tole(0xcc0c7795L), tole(0xbb0b4703L), tole(0x220216b9L), tole(0x5505262fL),
++tole(0xc5ba3bbeL), tole(0xb2bd0b28L), tole(0x2bb45a92L), tole(0x5cb36a04L),
++tole(0xc2d7ffa7L), tole(0xb5d0cf31L), tole(0x2cd99e8bL), tole(0x5bdeae1dL),
++tole(0x9b64c2b0L), tole(0xec63f226L), tole(0x756aa39cL), tole(0x026d930aL),
++tole(0x9c0906a9L), tole(0xeb0e363fL), tole(0x72076785L), tole(0x05005713L),
++tole(0x95bf4a82L), tole(0xe2b87a14L), tole(0x7bb12baeL), tole(0x0cb61b38L),
++tole(0x92d28e9bL), tole(0xe5d5be0dL), tole(0x7cdcefb7L), tole(0x0bdbdf21L),
++tole(0x86d3d2d4L), tole(0xf1d4e242L), tole(0x68ddb3f8L), tole(0x1fda836eL),
++tole(0x81be16cdL), tole(0xf6b9265bL), tole(0x6fb077e1L), tole(0x18b74777L),
++tole(0x88085ae6L), tole(0xff0f6a70L), tole(0x66063bcaL), tole(0x11010b5cL),
++tole(0x8f659effL), tole(0xf862ae69L), tole(0x616bffd3L), tole(0x166ccf45L),
++tole(0xa00ae278L), tole(0xd70dd2eeL), tole(0x4e048354L), tole(0x3903b3c2L),
++tole(0xa7672661L), tole(0xd06016f7L), tole(0x4969474dL), tole(0x3e6e77dbL),
++tole(0xaed16a4aL), tole(0xd9d65adcL), tole(0x40df0b66L), tole(0x37d83bf0L),
++tole(0xa9bcae53L), tole(0xdebb9ec5L), tole(0x47b2cf7fL), tole(0x30b5ffe9L),
++tole(0xbdbdf21cL), tole(0xcabac28aL), tole(0x53b39330L), tole(0x24b4a3a6L),
++tole(0xbad03605L), tole(0xcdd70693L), tole(0x54de5729L), tole(0x23d967bfL),
++tole(0xb3667a2eL), tole(0xc4614ab8L), tole(0x5d681b02L), tole(0x2a6f2b94L),
++tole(0xb40bbe37L), tole(0xc30c8ea1L), tole(0x5a05df1bL), tole(0x2d02ef8dL)
++};
++#endif
++
++#if 0
++/* =========================================================================
++ * This function can be used by asm versions of crc32()
++ */
++const uint32_t * ZEXPORT get_crc_table()
++{
++#ifdef DYNAMIC_CRC_TABLE
++  if (crc_table_empty) make_crc_table();
++#endif
++  return (const uint32_t *)crc_table;
++}
++#endif
++
++/* ========================================================================= */
++
++# if __BYTE_ORDER == __LITTLE_ENDIAN
++#  define DO_CRC(x) crc = tab[(crc ^ (x)) & 255] ^ (crc >> 8)
++# else
++#  define DO_CRC(x) crc = tab[((crc >> 24) ^ (x)) & 255] ^ (crc << 8)
++# endif
++
++/* ========================================================================= */
++
++/* No ones complement version. JFFS2 (and other things ?)
++ * don't use ones compliment in their CRC calculations.
++ */
++uint32_t ZEXPORT crc32_no_comp(uint32_t crc, const unsigned char *buf, uint32_t len)
++{
++    const uint32_t *tab = crc_table;
++    const uint32_t *b =(const uint32_t *)buf;
++    size_t rem_len;
++#ifdef DYNAMIC_CRC_TABLE
++    if (crc_table_empty)
++      make_crc_table();
++#endif
++    crc = cpu_to_le32(crc);
++    /* Align it */
++    if (((long)b) & 3 && len) {
++	 uint8_t *p = (uint8_t *)b;
++	 do {
++	      DO_CRC(*p++);
++	 } while ((--len) && ((long)p)&3);
++	 b = (uint32_t *)p;
++    }
++
++    rem_len = len & 3;
++    len = len >> 2;
++    for (--b; len; --len) {
++	 /* load data 32 bits wide, xor data 32 bits wide. */
++	 crc ^= *++b; /* use pre increment for speed */
++	 DO_CRC(0);
++	 DO_CRC(0);
++	 DO_CRC(0);
++	 DO_CRC(0);
++    }
++    len = rem_len;
++    /* And the last few bytes */
++    if (len) {
++	 uint8_t *p = (uint8_t *)(b + 1) - 1;
++	 do {
++	      DO_CRC(*++p); /* use pre increment for speed */
++	 } while (--len);
++    }
++
++    return le32_to_cpu(crc);
++}
++#undef DO_CRC
++
++uint32_t ZEXPORT crc32_check(uint32_t crc, const unsigned char *p, uint32_t len)
++{
++     return crc32_no_comp(crc ^ 0xffffffffL, p, len) ^ 0xffffffffL;
++}
++
++/*
++ * Calculate the crc32 checksum triggering the watchdog every 'chunk_sz' bytes
++ * of input.
++ */
++uint32_t ZEXPORT crc32_wd (uint32_t crc,
++			   const unsigned char *buf,
++			   uint32_t len, uint32_t chunk_sz)
++{
++#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)
++	const unsigned char *end, *curr;
++	int chunk;
++
++	curr = buf;
++	end = buf + len;
++	while (curr < end) {
++		chunk = end - curr;
++		if (chunk > chunk_sz)
++			chunk = chunk_sz;
++		crc = crc32_check (crc, curr, chunk);
++		curr += chunk;
++		/*WATCHDOG_RESET ();*/
++	}
++#else
++	crc = crc32_check(crc, buf, len);
++#endif
++
++	return crc;
++}
+diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
+index 1f35a34..5016852 100644
+--- a/kernel/power/hibernate.c
++++ b/kernel/power/hibernate.c
+@@ -41,7 +41,16 @@ static unsigned int resume_delay;
+ static char resume_file[256] = CONFIG_PM_STD_PARTITION;
+ dev_t swsusp_resume_device;
+ sector_t swsusp_resume_block;
++
++#ifdef CONFIG_HISI_SNAPSHOT_BOOT
++int noshrink;
++char hb_bdev_file[64] = CONFIG_PM_STD_PARTITION;
++//char compress_method[16] = "lzo";
++char compress_method[16] = "gzip";
++volatile unsigned long in_suspend;
++#else
+ __visible int in_suspend __nosavedata;
++#endif
+ 
+ enum {
+ 	HIBERNATION_INVALID,
+@@ -668,8 +677,11 @@ int hibernate(void)
+ 	printk(KERN_INFO "PM: Syncing filesystems ... ");
+ 	sys_sync();
+ 	printk("done.\n");
+-
++#ifdef	CONFIG_HISI_SNAPSHOT_BOOT
++	error = suspend_freeze_processes();
++#else
+ 	error = freeze_processes();
++#endif
+ 	if (error)
+ 		goto Exit;
+ 
+@@ -708,7 +720,11 @@ int hibernate(void)
+ 	free_basic_memory_bitmaps();
+  Thaw:
+ 	unlock_device_hotplug();
++#ifdef	CONFIG_HISI_SNAPSHOT_BOOT
++	suspend_thaw_processes();
++#else
+ 	thaw_processes();
++#endif
+ 
+ 	/* Don't bother checking whether freezer_test_done is true */
+ 	freezer_test_done = false;
+@@ -831,7 +847,11 @@ static int software_resume(void)
+ 		goto Close_Finish;
+ 
+ 	pr_debug("PM: Preparing processes for restore.\n");
++#ifdef	CONFIG_HISI_SNAPSHOT_BOOT
++	error = suspend_freeze_processes();
++#else
+ 	error = freeze_processes();
++#endif
+ 	if (error)
+ 		goto Close_Finish;
+ 
+@@ -852,7 +872,11 @@ static int software_resume(void)
+ 	free_basic_memory_bitmaps();
+  Thaw:
+ 	unlock_device_hotplug();
++#ifdef	CONFIG_HISI_SNAPSHOT_BOOT
++	suspend_thaw_processes();
++#else
+ 	thaw_processes();
++#endif
+  Finish:
+ 	pm_notifier_call_chain(PM_POST_RESTORE);
+ 	pm_restore_console();
+@@ -866,9 +890,9 @@ static int software_resume(void)
+ 	swsusp_close(FMODE_READ);
+ 	goto Finish;
+ }
+-
++#ifndef CONFIG_HISI_SNAPSHOT_BOOT
+ late_initcall_sync(software_resume);
+-
++#endif
+ 
+ static const char * const hibernation_modes[] = {
+ 	[HIBERNATION_PLATFORM]	= "platform",
+@@ -1046,6 +1070,33 @@ static ssize_t image_size_store(struct kobject *kobj, struct kobj_attribute *att
+ 
+ power_attr(image_size);
+ 
++#ifdef CONFIG_HISI_SNAPSHOT_BOOT
++static ssize_t compress_method_show(struct kobject *kobj,
++		struct kobj_attribute *attr, char *buf)
++{
++	return sprintf(buf, "%s\n", compress_method);
++}
++static ssize_t compress_method_store(struct kobject *kobj,
++		struct kobj_attribute *attr,
++		const char *buf, size_t n)
++{
++	return -EINVAL;
++}
++power_attr(compress_method);
++static ssize_t hb_bdev_file_show(struct kobject *kobj,
++		struct kobj_attribute *attr, char *buf)
++{
++	return sprintf(buf, "%s\n", hb_bdev_file);
++}
++static ssize_t hb_bdev_file_store(struct kobject *kobj,
++		struct kobj_attribute *attr,
++		const char *buf, size_t n)
++{
++	return -EINVAL;
++}
++power_attr(hb_bdev_file);
++#endif
++
+ static ssize_t reserved_size_show(struct kobject *kobj,
+ 				  struct kobj_attribute *attr, char *buf)
+ {
+@@ -1073,6 +1124,10 @@ static struct attribute * g[] = {
+ 	&resume_attr.attr,
+ 	&image_size_attr.attr,
+ 	&reserved_size_attr.attr,
++#ifdef CONFIG_HISI_SNAPSHOT_BOOT
++	&compress_method_attr.attr,
++	&hb_bdev_file_attr.attr,
++#endif
+ 	NULL,
+ };
+ 
+@@ -1158,6 +1213,16 @@ static int __init kaslr_nohibernate_setup(char *str)
+ 	return nohibernate_setup(str);
+ }
+ 
++#ifdef	CONFIG_HISI_SNAPSHOT_BOOT
++static int __init hb_bdev_setup(char *str)
++{
++	strncpy(hb_bdev_file, str, sizeof(hb_bdev_file) - 1);
++	return 1;
++}
++
++__setup("hbcomp=", hb_bdev_setup);
++#endif
++
+ __setup("noresume", noresume_setup);
+ __setup("resume_offset=", resume_offset_setup);
+ __setup("resume=", resume_setup);
+diff --git a/kernel/power/power.h b/kernel/power/power.h
+index 2df883a..0e802b9 100644
+--- a/kernel/power/power.h
++++ b/kernel/power/power.h
+@@ -81,10 +81,21 @@ static struct kobj_attribute _name##_attr = {	\
+ extern unsigned long image_size;
+ /* Size of memory reserved for drivers (default SPARE_PAGES x PAGE_SIZE) */
+ extern unsigned long reserved_size;
++#ifndef	CONFIG_HISI_SNAPSHOT_BOOT
+ extern int in_suspend;
++#endif
+ extern dev_t swsusp_resume_device;
+ extern sector_t swsusp_resume_block;
+ 
++#ifdef CONFIG_HISI_SNAPSHOT_BOOT
++extern char hb_bdev_file[64];
++extern char compress_method[16];
++extern void *saved_processor_context;
++
++extern volatile unsigned long in_suspend;
++extern int noshrink;
++extern int swsusp_check_storage_all(void);
++#endif
+ extern asmlinkage int swsusp_arch_suspend(void);
+ extern asmlinkage int swsusp_arch_resume(void);
+ 
+@@ -243,7 +254,7 @@ static inline int suspend_freeze_processes(void)
+ 	 */
+ 	if (error)
+ 		return error;
+-
++#ifndef	CONFIG_HISI_SNAPSHOT_BOOT
+ 	error = freeze_kernel_threads();
+ 	/*
+ 	 * freeze_kernel_threads() thaws only kernel threads upon freezing
+@@ -252,11 +263,18 @@ static inline int suspend_freeze_processes(void)
+ 	if (error)
+ 		thaw_processes();
+ 
++#else
++	error = pm_notifier_call_chain(PM_POST_FREEZE_PROCESS);
++#endif
++
+ 	return error;
+ }
+ 
+ static inline void suspend_thaw_processes(void)
+ {
++#ifdef	CONFIG_HISI_SNAPSHOT_BOOT
++	pm_notifier_call_chain(PM_THAW_PROCESS_PREPARE);
++#endif
+ 	thaw_processes();
+ }
+ #else
+diff --git a/kernel/power/process.c b/kernel/power/process.c
+index 5a6ec86..7456dcb 100644
+--- a/kernel/power/process.c
++++ b/kernel/power/process.c
+@@ -18,6 +18,7 @@
+ #include <linux/workqueue.h>
+ #include <linux/kmod.h>
+ #include <trace/events/power.h>
++#include <linux/wakeup_reason.h>
+ 
+ /* 
+  * Timeout for stopping processes
+@@ -35,6 +36,9 @@ static int try_to_freeze_tasks(bool user_only)
+ 	unsigned int elapsed_msecs;
+ 	bool wakeup = false;
+ 	int sleep_usecs = USEC_PER_MSEC;
++#ifdef CONFIG_PM_SLEEP
++	char suspend_abort[MAX_SUSPEND_ABORT_LEN];
++#endif
+ 
+ 	do_gettimeofday(&start);
+ 
+@@ -64,6 +68,11 @@ static int try_to_freeze_tasks(bool user_only)
+ 			break;
+ 
+ 		if (pm_wakeup_pending()) {
++#ifdef CONFIG_PM_SLEEP
++			pm_get_active_wakeup_sources(suspend_abort,
++				MAX_SUSPEND_ABORT_LEN);
++			log_suspend_abort_reason(suspend_abort);
++#endif
+ 			wakeup = true;
+ 			break;
+ 		}
+@@ -83,15 +92,17 @@ static int try_to_freeze_tasks(bool user_only)
+ 	do_div(elapsed_msecs64, NSEC_PER_MSEC);
+ 	elapsed_msecs = elapsed_msecs64;
+ 
+-	if (todo) {
++	if (wakeup) {
+ 		printk("\n");
+-		printk(KERN_ERR "Freezing of tasks %s after %d.%03d seconds "
+-		       "(%d tasks refusing to freeze, wq_busy=%d):\n",
+-		       wakeup ? "aborted" : "failed",
++		printk(KERN_ERR "Freezing of tasks aborted after %d.%03d seconds",
++		       elapsed_msecs / 1000, elapsed_msecs % 1000);
++	} else if (todo) {
++		printk("\n");
++		printk(KERN_ERR "Freezing of tasks failed after %d.%03d seconds"
++		       " (%d tasks refusing to freeze, wq_busy=%d):\n",
+ 		       elapsed_msecs / 1000, elapsed_msecs % 1000,
+ 		       todo - wq_busy, wq_busy);
+ 
+-		if (!wakeup) {
+ 			read_lock(&tasklist_lock);
+ 			for_each_process_thread(g, p) {
+ 				if (p != current && !freezer_should_skip(p)
+@@ -99,7 +110,6 @@ static int try_to_freeze_tasks(bool user_only)
+ 					sched_show_task(p);
+ 			}
+ 			read_unlock(&tasklist_lock);
+-		}
+ 	} else {
+ 		printk("(elapsed %d.%03d seconds) ", elapsed_msecs / 1000,
+ 			elapsed_msecs % 1000);
+diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
+index 7325e35..7999fa0 100644
+--- a/kernel/power/snapshot.c
++++ b/kernel/power/snapshot.c
+@@ -28,6 +28,9 @@
+ #include <linux/list.h>
+ #include <linux/slab.h>
+ #include <linux/compiler.h>
++#ifdef	CONFIG_HISI_SNAPSHOT_BOOT
++#include <linux/writeback.h>
++#endif
+ 
+ #include <asm/uaccess.h>
+ #include <asm/mmu_context.h>
+@@ -733,6 +736,19 @@ static void memory_bm_clear_current(struct memory_bitmap *bm)
+ 	clear_bit(bit, bm->cur.node->data);
+ }
+ 
++#ifdef	CONFIG_HISI_SNAPSHOT_BOOT
++static int mem_bm_clear_bit_check(struct memory_bitmap *bm, unsigned long pfn)
++{
++	void *addr;
++	unsigned int bit;
++	int error;
++
++	error = memory_bm_find_bit(bm, pfn, &addr, &bit);
++	if (!error)
++		clear_bit(bit, addr);
++	return error;
++}
++#endif
+ static int memory_bm_test_bit(struct memory_bitmap *bm, unsigned long pfn)
+ {
+ 	void *addr;
+@@ -828,6 +844,73 @@ struct nosave_region {
+ 	unsigned long start_pfn;
+ 	unsigned long end_pfn;
+ };
++#ifdef	CONFIG_HISI_SNAPSHOT_BOOT
++/* used for pmem pfn save */
++static LIST_HEAD(save_regions);
++static DEFINE_SPINLOCK(save_spin);
++
++void *register_save_region(unsigned long start_pfn, unsigned long end_pfn)
++{
++	struct nosave_region *region;
++	region = kmalloc(sizeof(*region), GFP_KERNEL);
++	BUG_ON(!region);
++
++	region->start_pfn = start_pfn;
++	region->end_pfn = end_pfn;
++
++	spin_lock(&save_spin);
++	list_add_tail(&region->list, &save_regions);
++	spin_unlock(&save_spin);
++
++	return region;
++}
++EXPORT_SYMBOL(register_save_region);
++
++void unregister_save_region(void *mem)
++{
++	struct nosave_region *region = mem;
++
++	if (!region)
++		return;
++
++	spin_lock(&save_spin);
++	list_del(&region->list);
++	spin_unlock(&save_spin);
++
++	kfree(mem);
++}
++EXPORT_SYMBOL(unregister_save_region);
++
++static LIST_HEAD(nosave_regions_runtime);
++static DEFINE_SPINLOCK(nosave_spin);
++
++void *register_nosave_region_runtime(unsigned long start_pfn,
++		unsigned long end_pfn)
++{
++	struct nosave_region *region;
++	region = kmalloc(sizeof(struct nosave_region), GFP_KERNEL);
++	BUG_ON(!region);
++	region->start_pfn = start_pfn;
++	region->end_pfn = end_pfn;
++	spin_lock(&nosave_spin);
++	list_add_tail(&region->list, &nosave_regions_runtime);
++	spin_unlock(&nosave_spin);
++	return region;
++}
++EXPORT_SYMBOL(register_nosave_region_runtime);
++
++void unregister_nosave_region_runtime(void *mem)
++{
++	struct nosave_region *region = mem;
++	if (!region)
++		return;
++	spin_lock(&nosave_spin);
++	list_del(&region->list);
++	spin_unlock(&nosave_spin);
++	kfree(mem);
++}
++EXPORT_SYMBOL(unregister_nosave_region_runtime);
++#endif
+ 
+ static LIST_HEAD(nosave_regions);
+ 
+@@ -940,8 +1023,11 @@ static void mark_nosave_pages(struct memory_bitmap *bm)
+ 			 (unsigned long long) region->start_pfn << PAGE_SHIFT,
+ 			 ((unsigned long long) region->end_pfn << PAGE_SHIFT)
+ 				- 1);
+-
++#ifdef	CONFIG_HISI_SNAPSHOT_BOOT
++		for (pfn = region->start_pfn; pfn <= region->end_pfn; pfn++)
++#else
+ 		for (pfn = region->start_pfn; pfn < region->end_pfn; pfn++)
++#endif
+ 			if (pfn_valid(pfn)) {
+ 				/*
+ 				 * It is safe to ignore the result of
+@@ -953,7 +1039,49 @@ static void mark_nosave_pages(struct memory_bitmap *bm)
+ 			}
+ 	}
+ }
++#ifdef	CONFIG_HISI_SNAPSHOT_BOOT
++/*used for pmem pages mark. maybe useless for us*/
++static void mark_snapshot_pages_again(void)
++{
++	struct nosave_region *region;
++	struct memory_bitmap *bm = forbidden_pages_map;
++
++	if (list_empty(&save_regions))
++		goto proc_nosave;
++
++	spin_lock(&save_spin);
++	list_for_each_entry(region, &save_regions, list) {
++		unsigned long pfn;
++
++		pr_info("PM: Marking save pages: %016lx - %016lx\n",
++				region->start_pfn << PAGE_SHIFT,
++				region->end_pfn << PAGE_SHIFT);
++
++		for (pfn = region->start_pfn; pfn <= region->end_pfn; pfn++)
++			if (pfn_valid(pfn))
++				mem_bm_clear_bit_check(bm, pfn);
++	}
++	spin_unlock(&save_spin);
++
++proc_nosave:
++	if (list_empty(&nosave_regions_runtime))
++		return;
++
++	spin_lock(&nosave_spin);
++	list_for_each_entry(region, &nosave_regions_runtime, list) {
++		unsigned long pfn;
++
++		pr_info("PM: Marking runtime nosave pages: %016lx - %016lx\n",
++				region->start_pfn << PAGE_SHIFT,
++				region->end_pfn << PAGE_SHIFT);
+ 
++		for (pfn = region->start_pfn; pfn <= region->end_pfn; pfn++)
++			if (pfn_valid(pfn))
++				mem_bm_set_bit_check(bm, pfn);
++	}
++	spin_unlock(&nosave_spin);
++}
++#endif
+ /**
+  *	create_basic_memory_bitmaps - create bitmaps needed for marking page
+  *	frames that should not be saved and free page frames.  The pointers
+@@ -1070,6 +1198,11 @@ static unsigned int count_free_highmem_pages(void)
+ 	return cnt;
+ }
+ 
++#ifdef CONFIG_CMA
++#ifndef CONFIG_CMA_ADVANCE_SHARE
++extern int hicma_page_free(unsigned long pfn);
++#endif
++#endif
+ /**
+  *	saveable_highmem_page - Determine whether a highmem page should be
+  *	included in the suspend image.
+@@ -1096,7 +1229,13 @@ static struct page *saveable_highmem_page(struct zone *zone, unsigned long pfn)
+ 
+ 	if (page_is_guard(page))
+ 		return NULL;
++#ifdef CONFIG_CMA
++#ifndef CONFIG_CMA_ADVANCE_SHARE
++	if (hicma_page_free(pfn))
++		return NULL;
+ 
++#endif
++#endif
+ 	return page;
+ }
+ 
+@@ -1161,7 +1300,13 @@ static struct page *saveable_page(struct zone *zone, unsigned long pfn)
+ 
+ 	if (page_is_guard(page))
+ 		return NULL;
++#ifdef CONFIG_CMA
++#ifndef CONFIG_CMA_ADVANCE_SHARE
++	if (hicma_page_free(pfn))
++		return NULL;
+ 
++#endif
++#endif
+ 	return page;
+ }
+ 
+@@ -1452,9 +1597,9 @@ static inline unsigned long preallocate_highmem_fraction(unsigned long nr_pages,
+ /**
+  * free_unnecessary_pages - Release preallocated pages not needed for the image
+  */
+-static void free_unnecessary_pages(void)
++static unsigned long free_unnecessary_pages(void)
+ {
+-	unsigned long save, to_free_normal, to_free_highmem;
++	unsigned long save, to_free_normal, to_free_highmem, free;
+ 
+ 	save = count_data_pages();
+ 	if (alloc_normal >= save) {
+@@ -1476,6 +1621,8 @@ static void free_unnecessary_pages(void)
+ 			to_free_normal = 0;
+ 	}
+ 
++	free = to_free_normal + to_free_highmem;
++
+ 	memory_bm_position_reset(&copy_bm);
+ 
+ 	while (to_free_normal > 0 || to_free_highmem > 0) {
+@@ -1498,8 +1645,31 @@ static void free_unnecessary_pages(void)
+ 		swsusp_unset_page_free(page);
+ 		__free_page(page);
+ 	}
+-}
+ 
++	return free;
++}
++#ifdef	CONFIG_HISI_SNAPSHOT_BOOT
++/*
++ ** Kick the writeback threads then try to free up some ZONE_NORMAL memory.
++ **/
++static void free_more_memory(void)
++{
++	struct zone *zone;
++	int nid;
++
++	wakeup_flusher_threads(1024, WB_REASON_FREE_MORE_MEM);
++	yield();
++
++	for_each_online_node(nid) {
++		(void)first_zones_zonelist(node_zonelist(nid, GFP_NOFS),
++				gfp_zone(GFP_NOFS), NULL,
++				&zone);
++		if (zone)
++			try_to_free_pages(node_zonelist(nid, GFP_NOFS), 0,
++					GFP_NOFS, NULL);
++	}
++}
++#endif
+ /**
+  * minimum_image_size - Estimate the minimum acceptable size of an image
+  * @saveable: Number of saveable pages in the system.
+@@ -1559,7 +1729,15 @@ int hibernate_preallocate_memory(void)
+ 	unsigned long alloc, save_highmem, pages_highmem, avail_normal;
+ 	struct timeval start, stop;
+ 	int error;
++#ifdef	CONFIG_HISI_SNAPSHOT_BOOT
++	bool compress;
++	unsigned long min_image_size, prev_image_size;
+ 
++	/* this will try to free some pages in the normal zone */
++	free_more_memory();
++
++	mark_snapshot_pages_again();
++#endif
+ 	printk(KERN_INFO "PM: Preallocating image memory... ");
+ 	do_gettimeofday(&start);
+ 
+@@ -1573,7 +1751,52 @@ int hibernate_preallocate_memory(void)
+ 
+ 	alloc_normal = 0;
+ 	alloc_highmem = 0;
++#ifdef	CONFIG_HISI_SNAPSHOT_BOOT
++	compress = swsusp_check_storage_all() == 1 ? true : false;
++
++	if (noshrink)
++		goto skip_reclaim;
+ 
++	/* calculates the snapshot image size */
++	prev_image_size = min_image_size =
++		global_page_state(NR_SLAB_RECLAIMABLE)
++		+ global_page_state(NR_ACTIVE_ANON)
++		+ global_page_state(NR_INACTIVE_ANON)
++		+ global_page_state(NR_ACTIVE_FILE)
++		+ global_page_state(NR_INACTIVE_FILE)
++		- global_page_state(NR_FILE_MAPPED);
++
++	/* Count the number of saveable data pages.
++	 * Does page reclamation till min_image_size becomes constant
++	 */
++	do {
++		save_highmem = count_highmem_pages();
++		saveable = count_data_pages();
++		saveable += save_highmem;
++
++		shrink_all_memory(saveable);
++
++		min_image_size = global_page_state(NR_SLAB_RECLAIMABLE)
++			+ global_page_state(NR_ACTIVE_ANON)
++			+ global_page_state(NR_INACTIVE_ANON)
++			+ global_page_state(NR_ACTIVE_FILE)
++			+ global_page_state(NR_INACTIVE_FILE)
++			- global_page_state(NR_FILE_MAPPED);
++
++		if (prev_image_size == min_image_size)
++			break;
++		else
++			prev_image_size = min_image_size;
++	} while (saveable > min_image_size);
++
++skip_reclaim:
++	/*
++	 * Compute the total number of page frames we can use (count) and the
++	 * number of pages needed for image metadata (size).
++	 */
++	save_highmem = count_highmem_pages();
++	saveable = count_data_pages();
++#else
+ 	/* Count the number of saveable data pages. */
+ 	save_highmem = count_highmem_pages();
+ 	saveable = count_data_pages();
+@@ -1582,6 +1805,7 @@ int hibernate_preallocate_memory(void)
+ 	 * Compute the total number of page frames we can use (count) and the
+ 	 * number of pages needed for image metadata (size).
+ 	 */
++#endif
+ 	count = saveable;
+ 	saveable += save_highmem;
+ 	highmem = save_highmem;
+@@ -1604,6 +1828,12 @@ int hibernate_preallocate_memory(void)
+ 	max_size = (count - (size + PAGES_FOR_IO)) / 2
+ 			- 2 * DIV_ROUND_UP(reserved_size, PAGE_SIZE);
+ 	/* Compute the desired number of image pages specified by image_size. */
++#ifdef	CONFIG_HISI_SNAPSHOT_BOOT
++	if (compress)
++		/* very rough : may accomplish 40% of original */
++		size = DIV_ROUND_UP(image_size * 5 / 2, PAGE_SIZE);
++	else
++#endif
+ 	size = DIV_ROUND_UP(image_size, PAGE_SIZE);
+ 	if (size > max_size)
+ 		size = max_size;
+@@ -1638,8 +1868,16 @@ int hibernate_preallocate_memory(void)
+ 	 * NOTE: If this is not done, performance will be hurt badly in some
+ 	 * test cases.
+ 	 */
++#ifdef	CONFIG_HISI_SNAPSHOT_BOOT
++	/* REVISIT : fail-safe case.
++	 *   *    is this needed ? do you really want this ?
++	 *       *    it may try to free all of page-cache.
++	 *           */
++	if (!noshrink)
++		shrink_all_memory(saveable);
++#else
+ 	shrink_all_memory(saveable - size);
+-
++#endif
+ 	/*
+ 	 * The number of saveable pages in memory was too high, so apply some
+ 	 * pressure to decrease it.  First, make room for the largest possible
+@@ -1687,7 +1925,7 @@ int hibernate_preallocate_memory(void)
+ 	 * pages in memory, but we have allocated more.  Release the excessive
+ 	 * ones now.
+ 	 */
+-	free_unnecessary_pages();
++	pages -= free_unnecessary_pages();
+ 
+  out:
+ 	do_gettimeofday(&stop);
+diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c
+index c347e3c..a212348 100644
+--- a/kernel/power/suspend.c
++++ b/kernel/power/suspend.c
+@@ -26,8 +26,10 @@
+ #include <linux/suspend.h>
+ #include <linux/syscore_ops.h>
+ #include <linux/ftrace.h>
++#include <linux/rtc.h>
+ #include <trace/events/power.h>
+ #include <linux/compiler.h>
++#include <linux/wakeup_reason.h>
+ 
+ #include "power.h"
+ 
+@@ -271,7 +273,8 @@ void __weak arch_suspend_enable_irqs(void)
+  */
+ static int suspend_enter(suspend_state_t state, bool *wakeup)
+ {
+-	int error;
++	char suspend_abort[MAX_SUSPEND_ABORT_LEN];
++	int error, last_dev;
+ 
+ 	error = platform_suspend_prepare(state);
+ 	if (error)
+@@ -279,7 +282,11 @@ static int suspend_enter(suspend_state_t state, bool *wakeup)
+ 
+ 	error = dpm_suspend_late(PMSG_SUSPEND);
+ 	if (error) {
++		last_dev = suspend_stats.last_failed_dev + REC_FAILED_NUM - 1;
++		last_dev %= REC_FAILED_NUM;
+ 		printk(KERN_ERR "PM: late suspend of devices failed\n");
++		log_suspend_abort_reason("%s device failed to power down",
++			suspend_stats.failed_devs[last_dev]);
+ 		goto Platform_finish;
+ 	}
+ 	error = platform_suspend_prepare_late(state);
+@@ -288,7 +295,11 @@ static int suspend_enter(suspend_state_t state, bool *wakeup)
+ 
+ 	error = dpm_suspend_noirq(PMSG_SUSPEND);
+ 	if (error) {
++		last_dev = suspend_stats.last_failed_dev + REC_FAILED_NUM - 1;
++		last_dev %= REC_FAILED_NUM;
+ 		printk(KERN_ERR "PM: noirq suspend of devices failed\n");
++		log_suspend_abort_reason("noirq suspend of %s device failed",
++			suspend_stats.failed_devs[last_dev]);
+ 		goto Platform_early_resume;
+ 	}
+ 	error = platform_suspend_prepare_noirq(state);
+@@ -312,8 +323,10 @@ static int suspend_enter(suspend_state_t state, bool *wakeup)
+ 	}
+ 
+ 	error = disable_nonboot_cpus();
+-	if (error || suspend_test(TEST_CPUS))
++	if (error || suspend_test(TEST_CPUS)) {
++		log_suspend_abort_reason("Disabling non-boot cpus failed");
+ 		goto Enable_cpus;
++	}
+ 
+ 	arch_suspend_disable_irqs();
+ 	BUG_ON(!irqs_disabled());
+@@ -328,6 +341,11 @@ static int suspend_enter(suspend_state_t state, bool *wakeup)
+ 			trace_suspend_resume(TPS("machine_suspend"),
+ 				state, false);
+ 			events_check_enabled = false;
++		} else if (*wakeup) {
++			pm_get_active_wakeup_sources(suspend_abort,
++				MAX_SUSPEND_ABORT_LEN);
++			log_suspend_abort_reason(suspend_abort);
++			error = -EBUSY;
+ 		}
+ 		syscore_resume();
+ 	}
+@@ -374,6 +392,7 @@ int suspend_devices_and_enter(suspend_state_t state)
+ 	error = dpm_suspend_start(PMSG_SUSPEND);
+ 	if (error) {
+ 		pr_err("PM: Some devices failed to suspend, or early wake event detected\n");
++		log_suspend_abort_reason("Some devices failed to suspend, or early wake event detected");
+ 		goto Recover_platform;
+ 	}
+ 	suspend_test_finish("suspend devices");
+@@ -472,6 +491,18 @@ static int enter_state(suspend_state_t state)
+ 	return error;
+ }
+ 
++static void pm_suspend_marker(char *annotation)
++{
++	struct timespec ts;
++	struct rtc_time tm;
++
++	getnstimeofday(&ts);
++	rtc_time_to_tm(ts.tv_sec, &tm);
++	pr_info("PM: suspend %s %d-%02d-%02d %02d:%02d:%02d.%09lu UTC\n",
++		annotation, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
++		tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec);
++}
++
+ /**
+  * pm_suspend - Externally visible function for suspending the system.
+  * @state: System sleep state to enter.
+@@ -486,6 +517,7 @@ int pm_suspend(suspend_state_t state)
+ 	if (state <= PM_SUSPEND_ON || state >= PM_SUSPEND_MAX)
+ 		return -EINVAL;
+ 
++	pm_suspend_marker("entry");
+ 	error = enter_state(state);
+ 	if (error) {
+ 		suspend_stats.fail++;
+@@ -493,6 +525,7 @@ int pm_suspend(suspend_state_t state)
+ 	} else {
+ 		suspend_stats.success++;
+ 	}
++	pm_suspend_marker("exit");
+ 	return error;
+ }
+ EXPORT_SYMBOL(pm_suspend);
+diff --git a/kernel/power/suspend_time.c b/kernel/power/suspend_time.c
+new file mode 100644
+index 0000000..d2a65da
+--- /dev/null
++++ b/kernel/power/suspend_time.c
+@@ -0,0 +1,111 @@
++/*
++ * debugfs file to track time spent in suspend
++ *
++ * Copyright (c) 2011, Google, 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.
++ */
++
++#include <linux/debugfs.h>
++#include <linux/err.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/seq_file.h>
++#include <linux/syscore_ops.h>
++#include <linux/time.h>
++
++static struct timespec suspend_time_before;
++static unsigned int time_in_suspend_bins[32];
++
++#ifdef CONFIG_DEBUG_FS
++static int suspend_time_debug_show(struct seq_file *s, void *data)
++{
++	int bin;
++	seq_printf(s, "time (secs)  count\n");
++	seq_printf(s, "------------------\n");
++	for (bin = 0; bin < 32; bin++) {
++		if (time_in_suspend_bins[bin] == 0)
++			continue;
++		seq_printf(s, "%4d - %4d %4u\n",
++			bin ? 1 << (bin - 1) : 0, 1 << bin,
++				time_in_suspend_bins[bin]);
++	}
++	return 0;
++}
++
++static int suspend_time_debug_open(struct inode *inode, struct file *file)
++{
++	return single_open(file, suspend_time_debug_show, NULL);
++}
++
++static const struct file_operations suspend_time_debug_fops = {
++	.open		= suspend_time_debug_open,
++	.read		= seq_read,
++	.llseek		= seq_lseek,
++	.release	= single_release,
++};
++
++static int __init suspend_time_debug_init(void)
++{
++	struct dentry *d;
++
++	d = debugfs_create_file("suspend_time", 0755, NULL, NULL,
++		&suspend_time_debug_fops);
++	if (!d) {
++		pr_err("Failed to create suspend_time debug file\n");
++		return -ENOMEM;
++	}
++
++	return 0;
++}
++
++late_initcall(suspend_time_debug_init);
++#endif
++
++static int suspend_time_syscore_suspend(void)
++{
++	read_persistent_clock(&suspend_time_before);
++
++	return 0;
++}
++
++static void suspend_time_syscore_resume(void)
++{
++	struct timespec after;
++
++	read_persistent_clock(&after);
++
++	after = timespec_sub(after, suspend_time_before);
++
++	time_in_suspend_bins[fls(after.tv_sec)]++;
++
++	pr_info("Suspended for %lu.%03lu seconds\n", after.tv_sec,
++		after.tv_nsec / NSEC_PER_MSEC);
++}
++
++static struct syscore_ops suspend_time_syscore_ops = {
++	.suspend = suspend_time_syscore_suspend,
++	.resume = suspend_time_syscore_resume,
++};
++
++static int suspend_time_syscore_init(void)
++{
++	register_syscore_ops(&suspend_time_syscore_ops);
++
++	return 0;
++}
++
++static void suspend_time_syscore_exit(void)
++{
++	unregister_syscore_ops(&suspend_time_syscore_ops);
++}
++module_init(suspend_time_syscore_init);
++module_exit(suspend_time_syscore_exit);
+diff --git a/kernel/power/swap.c b/kernel/power/swap.c
+index aaa3261..681acde 100644
+--- a/kernel/power/swap.c
++++ b/kernel/power/swap.c
+@@ -30,7 +30,9 @@
+ #include <linux/atomic.h>
+ #include <linux/kthread.h>
+ #include <linux/crc32.h>
+-
++#ifdef	CONFIG_HISI_SNAPSHOT_BOOT
++#include <linux/mount.h>
++#endif
+ #include "power.h"
+ 
+ #define HIBERNATE_SIG	"S1SUSPEND"
+@@ -216,7 +218,9 @@ struct block_device *hib_resume_bdev;
+ /*
+  * Saving part
+  */
+-
++#ifdef	CONFIG_HISI_SNAPSHOT_BOOT
++static int flush_swap_writer(struct swap_map_handle *handle);
++#endif
+ static int mark_swapfiles(struct swap_map_handle *handle, unsigned int flags)
+ {
+ 	int error;
+@@ -230,8 +234,19 @@ static int mark_swapfiles(struct swap_map_handle *handle, unsigned int flags)
+ 		swsusp_header->flags = flags;
+ 		if (flags & SF_CRC32_MODE)
+ 			swsusp_header->crc32 = handle->crc32;
++#ifdef	CONFIG_HISI_SNAPSHOT_BOOT
++		/*store the resume address in the swsusp_header */
++		*(unsigned long *)((&swsusp_header->image) - 1) =
++			(unsigned long)swsusp_arch_resume;
++#endif
+ 		error = hib_bio_write_page(swsusp_resume_block,
+-					swsusp_header, NULL);
++				swsusp_header, NULL);
++#ifdef	CONFIG_HISI_SNAPSHOT_BOOT
++	/*
++	 * Make sure the mark has been writen to flash!
++	 */
++	flush_swap_writer(handle);
++#endif
+ 	} else {
+ 		printk(KERN_ERR "PM: Swap header not found!\n");
+ 		error = -ENODEV;
+@@ -266,6 +281,60 @@ static int swsusp_swap_check(void)
+ 	return res;
+ }
+ 
++#ifdef CONFIG_HISI_SNAPSHOT_BOOT
++static int swsusp_hb_bdev_check(void)
++{
++	char spath[64];
++	struct block_device *bdev = NULL;
++	dev_t device;
++
++	if (hb_bdev_file[0] == 0) {
++		printk("%s:%d\n", __func__, __LINE__);
++		return -1;
++	}
++
++
++	printk("hb_bdev_file = %s\n", hb_bdev_file);
++	strncpy(spath, hb_bdev_file, sizeof(spath));
++
++	if (strncmp(spath, "/dev/block/", 11) == 0)
++		strcpy(spath + 5, spath + 11);
++	printk("spath = %s\n", spath);
++
++	device = name_to_dev_t(spath);
++	if (device == MKDEV(0, 0)) {
++		printk("%s:%d\n", __func__, __LINE__);
++		return -1;
++	}
++
++	bdev = bdget(device);
++	if (!bdev) {
++		printk("%s:%d\n", __func__, __LINE__);
++		return -1;
++	}
++
++	bdput(bdev);
++
++	return 0;
++}
++
++int swsusp_check_storage_all(void)
++{
++	int ret;
++
++	ret = swsusp_hb_bdev_check();
++	if (ret >= 0)
++		return 1; /* use hb_bdev device */
++
++	return -1;
++}
++#else
++int swsusp_check_storage_all(void)
++{
++	return 0; /* use swap device always */
++}
++#endif /* CONFIG_HISI_SNAPSHOT_BOOT */
++
+ /**
+  *	write_page - Write one page to given swap location.
+  *	@buf:		Address we're writing.
+@@ -800,6 +869,307 @@ static int enough_swap(unsigned int nr_pages, unsigned int flags)
+ 	return free_swap > required;
+ }
+ 
++
++
++#ifdef CONFIG_HISI_SNAPSHOT_BOOT
++
++#define PAGE_NR(x) (((x) + PAGE_SIZE - 1) / PAGE_SIZE)
++
++#include "compress.h"
++
++static int hb_bdev_write_header(struct compress_writer *writer,
++		union sscomp_header *sscomp)
++{
++	int ret;
++
++	ret = writer->write(writer, 0, PAGE_NR(sizeof(*sscomp)), sscomp);
++	if (ret != PAGE_NR(sizeof(*sscomp))) {
++		printk(KERN_ERR "PM: %s: write() failed\n", __func__);
++		return -EFAULT;
++	}
++
++	return 0;
++}
++
++static int hb_bdev_write_data(struct compress_writer *writer,
++		struct sscomp_block *block,
++		unsigned int *src_len,
++		sector_t *write_offs_page_i)
++{
++	void *buf = (void *)writer->dst;
++	int ret;
++	sector_t page_nr;
++
++	ret = writer->compress(writer, block, src_len);
++	if (ret <= 0) {
++		printk(KERN_ERR "PM: %s: compress() failed\n", __func__);
++		return -EFAULT;
++	}
++
++	page_nr = ret;
++	ret = writer->write(writer, *write_offs_page_i, page_nr, buf);
++	if (ret != page_nr) {
++		printk(KERN_ERR "PM: %s: write() failed\n", __func__);
++		return -EFAULT;
++	}
++
++	*write_offs_page_i += page_nr;
++
++	return 0;
++}
++
++static inline int hb_bdev_write_finish(struct compress_writer *writer)
++{
++	return writer->finish(writer);
++}
++
++static inline void __hb_bdev_unpack_pfn(void *mem)
++{
++	unsigned long *pfn = mem;
++	while ((void *)pfn < mem + PAGE_SIZE) {
++		*pfn <<= PAGE_SHIFT;
++		pfn++;
++	}
++}
++
++
++extern unsigned int crc32_check(
++		unsigned int crc, const unsigned char *p, unsigned int len);
++
++static int hb_bdev_save_image(struct compress_writer *writer,
++		struct snapshot_handle *snapshot)
++{
++	union sscomp_header *sscomp = &writer->sscomp;
++	struct sscomp_block *block = &sscomp->b.blocks[0];
++	unsigned int nr_pages;
++	unsigned int filled_src = 0;
++	sector_t write_offs_page_i;
++	int ret;
++
++	write_offs_page_i = PAGE_NR(sizeof(*sscomp));
++
++	/* meta block(s) */
++	nr_pages = sscomp->info.meta_pages;
++	while (nr_pages) {
++		ret = snapshot_read_next(snapshot);
++		if (ret <= 0) {
++			printk(KERN_ERR "PM: snapshot_read_next() failed\n");
++			return -EFAULT;
++		}
++
++		memcpy((void *)writer->src + filled_src, data_of(*snapshot),
++				PAGE_SIZE);
++
++		__hb_bdev_unpack_pfn((void *)writer->src + filled_src);
++
++#ifdef USE_SHA1
++		hb_bdev_sha1_update((void *)writer->src + filled_src,
++				PAGE_SIZE);
++#else
++		sscomp->info.crc32 = crc32_check(sscomp->info.crc32,
++				(void *)writer->src + filled_src, PAGE_SIZE);
++#endif
++		filled_src += PAGE_SIZE;
++		if (filled_src >= writer->src_buf_sz) {
++			ret = hb_bdev_write_data(writer, block, &filled_src,
++					&write_offs_page_i);
++			if (ret)
++				return -EFAULT;
++			sscomp->info.meta_blocks++;
++			block++;
++		}
++		nr_pages--;
++	}
++
++	while (filled_src > 0) {
++		ret = hb_bdev_write_data(writer, block, &filled_src,
++				&write_offs_page_i);
++		if (ret)
++			return -EFAULT;
++		sscomp->info.meta_blocks++;
++		block++;
++	}
++
++	/* copy block(s) */
++	nr_pages = sscomp->info.data_pages;
++	while (nr_pages) {
++		ret = snapshot_read_next(snapshot);
++		if (ret <= 0) {
++			printk(KERN_ERR "PM: snapshot_read_next() failed\n");
++			return -EFAULT;
++		}
++
++		memcpy((void *)writer->src + filled_src, data_of(*snapshot),
++				PAGE_SIZE);
++
++#ifdef USE_SHA1
++		hb_bdev_sha1_update((void *)writer->src + filled_src,
++				PAGE_SIZE);
++#else
++		sscomp->info.crc32 = crc32_check(sscomp->info.crc32,
++				(void *)writer->src + filled_src, PAGE_SIZE);
++#endif
++		filled_src += PAGE_SIZE;
++		if (filled_src >= writer->src_buf_sz) {
++			ret = hb_bdev_write_data(writer, block, &filled_src,
++					&write_offs_page_i);
++			if (ret)
++				return -EFAULT;
++			sscomp->info.data_blocks++;
++			block++;
++		}
++		nr_pages--;
++	}
++
++	while (filled_src > 0) {
++		ret = hb_bdev_write_data(writer, block, &filled_src,
++				&write_offs_page_i);
++		if (ret)
++			return -EFAULT;
++		sscomp->info.data_blocks++;
++		block++;
++	}
++
++	printk(KERN_INFO "PM: compressed: %u pages to %llu pages.\n",
++			sscomp->info.meta_pages + sscomp->info.data_pages,
++			(unsigned long long)write_offs_page_i
++			- PAGE_NR(sizeof(*sscomp)));
++
++	printk(KERN_INFO "PM: written: %u meta blocks and %u data blocks\n",
++			sscomp->info.meta_blocks, sscomp->info.data_blocks);
++
++	return 0;
++}
++
++
++static int swsusp_compress_and_write(unsigned int flags)
++{
++	struct compress_writer *writer = get_susp_compress_writer(hb_bdev_file);
++	struct snapshot_handle snapshot;
++	struct swsusp_info *susp_info;
++	union sscomp_header *sscomp;
++	unsigned int meta_pages, copy_pages;
++	int error;
++
++	if (!writer) {
++		printk(KERN_ERR "PM: Cannot get compress-writer\n");
++		return -EFAULT;
++	}
++
++	sscomp = &writer->sscomp;
++
++	/* invalidate existing one */
++	memset(writer->pagebuf, 0, PAGE_SIZE);
++	error = hb_bdev_write_header(writer, writer->pagebuf);
++	if (error)
++		goto out_finish;
++
++	memset(&snapshot, 0, sizeof(struct snapshot_handle));
++	error = snapshot_read_next(&snapshot);
++	if (error < PAGE_SIZE) {
++		if (error >= 0)
++			error = -EFAULT;
++		goto out_error;
++	}
++
++	susp_info = (struct swsusp_info *)data_of(snapshot);
++	copy_pages = susp_info->image_pages;
++	meta_pages = susp_info->pages - susp_info->image_pages - 1;
++	if (!copy_pages && !meta_pages) {
++		error = -EINVAL;
++		goto out_error;
++	}
++
++	sscomp->info.meta_pages = meta_pages;
++	sscomp->info.data_pages = copy_pages;
++
++#ifdef USE_SHA1
++	hb_bdev_sha1_init();
++	strncpy(sscomp->info.sha1sum, "Not checked yet!",
++			sizeof(sscomp->info.sha1sum));
++#else
++	sscomp->info.crc32 = 0;
++#endif
++
++	error = hb_bdev_save_image(writer, &snapshot);
++	if (error)
++		goto out_finish;
++
++#ifdef USE_SHA1
++	hb_bdev_sha1_final(sscomp->info.sha1sum);
++#endif
++
++	/* update */
++	memcpy(sscomp->info.magic, SSCOMP_MAGIC_4, sizeof(sscomp->info.magic));
++	sscomp->info.ctl_func = (unsigned long)swsusp_arch_resume;
++	sscomp->info.ctl_data = (unsigned long)saved_processor_context;
++
++	error = hb_bdev_write_header(writer, sscomp);
++	if (error)
++		goto out_finish;
++
++	error = hb_bdev_write_finish(writer);
++
++#if 0
++	/** for test**/
++	int i;
++	mm_segment_t fs;
++	loff_t pos = 0;
++	struct file *fp_result;
++	struct file *fp_src;
++	fp_src = filp_open("/tmp/zlib_src.txt",
++			O_APPEND | O_CREAT,
++			777);
++	if (IS_ERR(fp_src)) {
++		printk("fp_drc is err!\n");
++		return -1;
++	}
++
++	fp_result = filp_open("/tmp/zlib_deflate.gz",
++			O_APPEND | O_CREAT,
++			777);
++	if (IS_ERR(fp_result)) {
++		printk("fp_result is err!\n");
++		return -1;
++	}
++
++	fs = get_fs();
++	set_fs(KERNEL_DS);
++
++	printk("writer->image = 0x%x, writer->image_buf_sz = 0x%x,  %s:%d\n",
++			writer->dst, writer->dst_buf_sz, __func__, __LINE__);
++	for (i = 0; i < 32; i++) {
++		printk("[0x%x]\n", *((int *)writer->dst + i));
++	}
++
++	pos = 0;
++	fp_result->f_op->write(fp_result, writer->dst, writer->dst_buf_sz, &pos);
++
++	pos = 0;
++	fp_result->f_op->write(fp_src, writer->src, writer->src_buf_sz, &pos);
++
++	printk("%s:%d\n", __func__, __LINE__);
++	set_fs(fs);
++	filp_close(fp_result, NULL);
++	filp_close(fp_src, NULL);
++	/** end test**/
++#endif
++
++out_finish:
++out_error:
++	put_susp_compress_writer(writer);
++	return error;
++}
++
++#else
++
++static inline swsusp_compress_and_write(unsigned int flags)
++{
++	return -RESTARTSYS;
++}
++
++#endif /* CONFIG_HISI_SNAPSHOT_BOOT */
++
+ /**
+  *	swsusp_write - Write entire image and metadata.
+  *	@flags: flags to pass to the "boot" kernel in the image header
+@@ -818,6 +1188,12 @@ int swsusp_write(unsigned int flags)
+ 	unsigned long pages;
+ 	int error;
+ 
++#ifdef CONFIG_HISI_SNAPSHOT_BOOT
++	error = swsusp_check_storage_all();
++	if (error == 1)
++		return swsusp_compress_and_write(flags);
++
++#endif
+ 	pages = snapshot_get_image_size();
+ 	error = get_swap_writer(&handle);
+ 	if (error) {
+@@ -1435,10 +1811,13 @@ int swsusp_check(void)
+ 			goto put;
+ 
+ 		if (!memcmp(HIBERNATE_SIG, swsusp_header->sig, 10)) {
++#ifndef	CONFIG_HISI_SNAPSHOT_BOOT
+ 			memcpy(swsusp_header->sig, swsusp_header->orig_sig, 10);
+ 			/* Reset swap signature now */
+ 			error = hib_bio_write_page(swsusp_resume_block,
+ 						swsusp_header, NULL);
++#endif
++
+ 		} else {
+ 			error = -EINVAL;
+ 		}
+diff --git a/kernel/power/wakeup_reason.c b/kernel/power/wakeup_reason.c
+new file mode 100644
+index 0000000..252611f
+--- /dev/null
++++ b/kernel/power/wakeup_reason.c
+@@ -0,0 +1,225 @@
++/*
++ * kernel/power/wakeup_reason.c
++ *
++ * Logs the reasons which caused the kernel to resume from
++ * the suspend mode.
++ *
++ * Copyright (C) 2014 Google, Inc.
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/wakeup_reason.h>
++#include <linux/kernel.h>
++#include <linux/irq.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/kobject.h>
++#include <linux/sysfs.h>
++#include <linux/init.h>
++#include <linux/spinlock.h>
++#include <linux/notifier.h>
++#include <linux/suspend.h>
++
++
++#define MAX_WAKEUP_REASON_IRQS 32
++static int irq_list[MAX_WAKEUP_REASON_IRQS];
++static int irqcount;
++static bool suspend_abort;
++static char abort_reason[MAX_SUSPEND_ABORT_LEN];
++static struct kobject *wakeup_reason;
++static DEFINE_SPINLOCK(resume_reason_lock);
++
++static ktime_t last_monotime; /* monotonic time before last suspend */
++static ktime_t curr_monotime; /* monotonic time after last suspend */
++static ktime_t last_stime; /* monotonic boottime offset before last suspend */
++static ktime_t curr_stime; /* monotonic boottime offset after last suspend */
++
++static ssize_t last_resume_reason_show(struct kobject *kobj, struct kobj_attribute *attr,
++		char *buf)
++{
++	int irq_no, buf_offset = 0;
++	struct irq_desc *desc;
++	spin_lock(&resume_reason_lock);
++	if (suspend_abort) {
++		buf_offset = sprintf(buf, "Abort: %s", abort_reason);
++	} else {
++		for (irq_no = 0; irq_no < irqcount; irq_no++) {
++			desc = irq_to_desc(irq_list[irq_no]);
++			if (desc && desc->action && desc->action->name)
++				buf_offset += sprintf(buf + buf_offset, "%d %s\n",
++						irq_list[irq_no], desc->action->name);
++			else
++				buf_offset += sprintf(buf + buf_offset, "%d\n",
++						irq_list[irq_no]);
++		}
++	}
++	spin_unlock(&resume_reason_lock);
++	return buf_offset;
++}
++
++static ssize_t last_suspend_time_show(struct kobject *kobj,
++			struct kobj_attribute *attr, char *buf)
++{
++	struct timespec sleep_time;
++	struct timespec total_time;
++	struct timespec suspend_resume_time;
++
++	/*
++	 * total_time is calculated from monotonic bootoffsets because
++	 * unlike CLOCK_MONOTONIC it include the time spent in suspend state.
++	 */
++	total_time = ktime_to_timespec(ktime_sub(curr_stime, last_stime));
++
++	/*
++	 * suspend_resume_time is calculated as monotonic (CLOCK_MONOTONIC)
++	 * time interval before entering suspend and post suspend.
++	 */
++	suspend_resume_time = ktime_to_timespec(ktime_sub(curr_monotime, last_monotime));
++
++	/* sleep_time = total_time - suspend_resume_time */
++	sleep_time = timespec_sub(total_time, suspend_resume_time);
++
++	/* Export suspend_resume_time and sleep_time in pair here. */
++	return sprintf(buf, "%lu.%09lu %lu.%09lu\n",
++				suspend_resume_time.tv_sec, suspend_resume_time.tv_nsec,
++				sleep_time.tv_sec, sleep_time.tv_nsec);
++}
++
++static struct kobj_attribute resume_reason = __ATTR_RO(last_resume_reason);
++static struct kobj_attribute suspend_time = __ATTR_RO(last_suspend_time);
++
++static struct attribute *attrs[] = {
++	&resume_reason.attr,
++	&suspend_time.attr,
++	NULL,
++};
++static struct attribute_group attr_group = {
++	.attrs = attrs,
++};
++
++/*
++ * logs all the wake up reasons to the kernel
++ * stores the irqs to expose them to the userspace via sysfs
++ */
++void log_wakeup_reason(int irq)
++{
++	struct irq_desc *desc;
++	desc = irq_to_desc(irq);
++	if (desc && desc->action && desc->action->name)
++		printk(KERN_INFO "Resume caused by IRQ %d, %s\n", irq,
++				desc->action->name);
++	else
++		printk(KERN_INFO "Resume caused by IRQ %d\n", irq);
++
++	spin_lock(&resume_reason_lock);
++	if (irqcount == MAX_WAKEUP_REASON_IRQS) {
++		spin_unlock(&resume_reason_lock);
++		printk(KERN_WARNING "Resume caused by more than %d IRQs\n",
++				MAX_WAKEUP_REASON_IRQS);
++		return;
++	}
++
++	irq_list[irqcount++] = irq;
++	spin_unlock(&resume_reason_lock);
++}
++
++int check_wakeup_reason(int irq)
++{
++	int irq_no;
++	int ret = false;
++
++	spin_lock(&resume_reason_lock);
++	for (irq_no = 0; irq_no < irqcount; irq_no++)
++		if (irq_list[irq_no] == irq) {
++			ret = true;
++			break;
++	}
++	spin_unlock(&resume_reason_lock);
++	return ret;
++}
++
++void log_suspend_abort_reason(const char *fmt, ...)
++{
++	va_list args;
++
++	spin_lock(&resume_reason_lock);
++
++	//Suspend abort reason has already been logged.
++	if (suspend_abort) {
++		spin_unlock(&resume_reason_lock);
++		return;
++	}
++
++	suspend_abort = true;
++	va_start(args, fmt);
++	vsnprintf(abort_reason, MAX_SUSPEND_ABORT_LEN, fmt, args);
++	va_end(args);
++	spin_unlock(&resume_reason_lock);
++}
++
++/* Detects a suspend and clears all the previous wake up reasons*/
++static int wakeup_reason_pm_event(struct notifier_block *notifier,
++		unsigned long pm_event, void *unused)
++{
++	switch (pm_event) {
++	case PM_SUSPEND_PREPARE:
++		spin_lock(&resume_reason_lock);
++		irqcount = 0;
++		suspend_abort = false;
++		spin_unlock(&resume_reason_lock);
++		/* monotonic time since boot */
++		last_monotime = ktime_get();
++		/* monotonic time since boot including the time spent in suspend */
++		last_stime = ktime_get_boottime();
++		break;
++	case PM_POST_SUSPEND:
++		/* monotonic time since boot */
++		curr_monotime = ktime_get();
++		/* monotonic time since boot including the time spent in suspend */
++		curr_stime = ktime_get_boottime();
++		break;
++	default:
++		break;
++	}
++	return NOTIFY_DONE;
++}
++
++static struct notifier_block wakeup_reason_pm_notifier_block = {
++	.notifier_call = wakeup_reason_pm_event,
++};
++
++/* Initializes the sysfs parameter
++ * registers the pm_event notifier
++ */
++int __init wakeup_reason_init(void)
++{
++	int retval;
++
++	retval = register_pm_notifier(&wakeup_reason_pm_notifier_block);
++	if (retval)
++		printk(KERN_WARNING "[%s] failed to register PM notifier %d\n",
++				__func__, retval);
++
++	wakeup_reason = kobject_create_and_add("wakeup_reasons", kernel_kobj);
++	if (!wakeup_reason) {
++		printk(KERN_WARNING "[%s] failed to create a sysfs kobject\n",
++				__func__);
++		return 1;
++	}
++	retval = sysfs_create_group(wakeup_reason, &attr_group);
++	if (retval) {
++		kobject_put(wakeup_reason);
++		printk(KERN_WARNING "[%s] failed to create a sysfs group %d\n",
++				__func__, retval);
++	}
++	return 0;
++}
++
++late_initcall(wakeup_reason_init);
+diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
+index 3b9f01b..dcee13f 100644
+--- a/kernel/printk/printk.c
++++ b/kernel/printk/printk.c
+@@ -2007,8 +2007,11 @@ int update_console_cmdline(char *name, int idx, char *name_new, int idx_new, cha
+ 	/* not found */
+ 	return -1;
+ }
+-
++#ifdef	CONFIG_HISI_SNAPSHOT_BOOT
++bool console_suspend_enabled;
++#else
+ bool console_suspend_enabled = true;
++#endif
+ EXPORT_SYMBOL(console_suspend_enabled);
+ 
+ static int __init console_suspend_disable(char *str)
+diff --git a/kernel/resource.c b/kernel/resource.c
+index 0bcebff..7528c3b 100644
+--- a/kernel/resource.c
++++ b/kernel/resource.c
+@@ -162,7 +162,7 @@ static const struct file_operations proc_iomem_operations = {
+ static int __init ioresources_init(void)
+ {
+ 	proc_create("ioports", 0, NULL, &proc_ioports_operations);
+-	proc_create("iomem", 0, NULL, &proc_iomem_operations);
++	proc_create("iomem", S_IRUSR, NULL, &proc_iomem_operations);
+ 	return 0;
+ }
+ __initcall(ioresources_init);
+diff --git a/kernel/sched/core.c b/kernel/sched/core.c
+index 6810e57..a800ea1 100644
+--- a/kernel/sched/core.c
++++ b/kernel/sched/core.c
+@@ -1582,7 +1582,12 @@ void scheduler_ipi(void)
+ 	 */
+ 	preempt_fold_need_resched();
+ 
+-	if (llist_empty(&this_rq()->wake_list) && !got_nohz_idle_kick())
++	if (llist_empty(&this_rq()->wake_list)
++			&& !got_nohz_idle_kick()
++#ifdef CONFIG_SCHED_HMP
++			&& !this_rq()->wake_for_idle_pull
++#endif
++			)
+ 		return;
+ 
+ 	/*
+@@ -1608,6 +1613,11 @@ void scheduler_ipi(void)
+ 		this_rq()->idle_balance = 1;
+ 		raise_softirq_irqoff(SCHED_SOFTIRQ);
+ 	}
++#ifdef CONFIG_SCHED_HMP
++	else if (unlikely(this_rq()->wake_for_idle_pull))
++		raise_softirq_irqoff(SCHED_SOFTIRQ);
++#endif
++
+ 	irq_exit();
+ }
+ 
+@@ -1617,6 +1627,7 @@ static void ttwu_queue_remote(struct task_struct *p, int cpu)
+ 
+ 	if (llist_add(&p->wake_entry, &cpu_rq(cpu)->wake_list)) {
+ 		if (!set_nr_if_polling(rq->idle))
++
+ 			smp_send_reschedule(cpu);
+ 		else
+ 			trace_sched_wake_idle_without_ipi(cpu);
+@@ -1816,6 +1827,7 @@ void __dl_clear_params(struct task_struct *p)
+ 	dl_se->dl_bw = 0;
+ }
+ 
++extern unsigned int task_fork_on_bigcore;
+ /*
+  * Perform scheduler related setup for a newly forked process p.
+  * p is forked by current.
+@@ -1833,6 +1845,29 @@ static void __sched_fork(unsigned long clone_flags, struct task_struct *p)
+ 	p->se.nr_migrations		= 0;
+ 	p->se.vruntime			= 0;
+ 	INIT_LIST_HEAD(&p->se.group_node);
++/*
++ * Load-tracking only depends on SMP, FAIR_GROUP_SCHED dependency below may be
++ * removed when useful for applications beyond shares distribution (e.g.
++ * load-balance).
++ */
++#if defined(CONFIG_SMP) && defined(CONFIG_FAIR_GROUP_SCHED)
++	p->se.avg.runnable_avg_period = 0;
++	p->se.avg.runnable_avg_sum = 0;
++#ifdef CONFIG_SCHED_HMP
++	/* keep LOAD_AVG_MAX in sync with fair.c if load avg series is changed */
++#define LOAD_AVG_MAX 47742
++	p->se.avg.hmp_last_up_migration = 0;
++	p->se.avg.hmp_last_down_migration = 0;
++	if (hmp_task_should_forkboost(p) && task_fork_on_bigcore) {
++		p->se.avg.load_avg_ratio = 1023;
++		p->se.avg.load_avg_contrib =
++			(1023 * scale_load_down(p->se.load.weight));
++		p->se.avg.runnable_avg_period = LOAD_AVG_MAX;
++		p->se.avg.runnable_avg_sum = LOAD_AVG_MAX;
++		p->se.avg.usage_avg_sum = LOAD_AVG_MAX;
++	}
++#endif
++#endif
+ 
+ #ifdef CONFIG_SCHEDSTATS
+ 	memset(&p->se.statistics, 0, sizeof(p->se.statistics));
+@@ -6174,7 +6209,11 @@ sd_init(struct sched_domain_topology_level *tl, int cpu)
+ 		.wake_idx		= 0,
+ 		.forkexec_idx		= 0,
+ 
+-		.flags			= 1*SD_LOAD_BALANCE
++#ifdef CONFIG_SCHED_HMP
++		.flags                  = 0*SD_LOAD_BALANCE
++#else
++		.flags                  = 1*SD_LOAD_BALANCE
++#endif
+ 					| 1*SD_BALANCE_NEWIDLE
+ 					| 1*SD_BALANCE_EXEC
+ 					| 1*SD_BALANCE_FORK
+@@ -7190,14 +7229,24 @@ static inline int preempt_count_equals(int preempt_offset)
+ 	return (nested == preempt_offset);
+ }
+ 
++static int __might_sleep_init_called;
++int __init __might_sleep_init(void)
++{
++	__might_sleep_init_called = 1;
++	return 0;
++}
++early_initcall(__might_sleep_init);
++
+ void __might_sleep(const char *file, int line, int preempt_offset)
+ {
+ 	static unsigned long prev_jiffy;	/* ratelimiting */
+ 
+ 	rcu_sleep_check(); /* WARN_ON_ONCE() by default, no rate limit reqd. */
+ 	if ((preempt_count_equals(preempt_offset) && !irqs_disabled() &&
+-	     !is_idle_task(current)) ||
+-	    system_state != SYSTEM_RUNNING || oops_in_progress)
++	     !is_idle_task(current)) || oops_in_progress)
++		return;
++	if (system_state != SYSTEM_RUNNING &&
++	    (!__might_sleep_init_called || system_state != SYSTEM_BOOTING))
+ 		return;
+ 	if (time_before(jiffies, prev_jiffy + HZ) && prev_jiffy)
+ 		return;
+@@ -8257,6 +8306,7 @@ struct cgroup_subsys cpu_cgrp_subsys = {
+ 	.fork		= cpu_cgroup_fork,
+ 	.can_attach	= cpu_cgroup_can_attach,
+ 	.attach		= cpu_cgroup_attach,
++	.allow_attach   = subsys_cgroup_allow_attach,
+ 	.exit		= cpu_cgroup_exit,
+ 	.legacy_cftypes	= cpu_files,
+ 	.early_init	= 1,
+diff --git a/kernel/sched/cputime.c b/kernel/sched/cputime.c
+index 8394b1e..b293203 100644
+--- a/kernel/sched/cputime.c
++++ b/kernel/sched/cputime.c
+@@ -1,3 +1,4 @@
++#include <linux/cpufreq.h>
+ #include <linux/export.h>
+ #include <linux/sched.h>
+ #include <linux/tsacct_kern.h>
+@@ -149,6 +150,11 @@ void account_user_time(struct task_struct *p, cputime_t cputime,
+ 
+ 	/* Account for user time used */
+ 	acct_account_cputime(p);
++
++#ifdef CONFIG_CPU_FREQ_STAT
++	/* Account power usage for user time */
++	acct_update_power(p, cputime);
++#endif
+ }
+ 
+ /*
+@@ -199,6 +205,11 @@ void __account_system_time(struct task_struct *p, cputime_t cputime,
+ 
+ 	/* Account for system time used */
+ 	acct_account_cputime(p);
++
++#ifdef CONFIG_CPU_FREQ_STAT
++	/* Account power usage for system time */
++	acct_update_power(p, cputime);
++#endif
+ }
+ 
+ /*
+diff --git a/kernel/sched/debug.c b/kernel/sched/debug.c
+index ce33780..3c2d558 100644
+--- a/kernel/sched/debug.c
++++ b/kernel/sched/debug.c
+@@ -95,6 +95,7 @@ static void print_cfs_group_stats(struct seq_file *m, int cpu, struct task_group
+ #ifdef CONFIG_SMP
+ 	P(se->avg.runnable_avg_sum);
+ 	P(se->avg.runnable_avg_period);
++	P(se->avg.usage_avg_sum);
+ 	P(se->avg.load_avg_contrib);
+ 	P(se->avg.decay_count);
+ #endif
+@@ -223,6 +224,8 @@ void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq)
+ 			atomic_long_read(&cfs_rq->tg->load_avg));
+ 	SEQ_printf(m, "  .%-30s: %d\n", "tg->runnable_avg",
+ 			atomic_read(&cfs_rq->tg->runnable_avg));
++	SEQ_printf(m, "  .%-30s: %d\n", "tg->usage_avg",
++			atomic_read(&cfs_rq->tg->usage_avg));
+ #endif
+ #endif
+ #ifdef CONFIG_CFS_BANDWIDTH
+@@ -566,6 +569,12 @@ void proc_sched_show_task(struct task_struct *p, struct seq_file *m)
+ 	PN(se.exec_start);
+ 	PN(se.vruntime);
+ 	PN(se.sum_exec_runtime);
++#if defined(CONFIG_SMP) && defined(CONFIG_FAIR_GROUP_SCHED)
++	P(se.avg.runnable_avg_sum);
++	P(se.avg.runnable_avg_period);
++	P(se.avg.load_avg_contrib);
++	P(se.avg.decay_count);
++#endif
+ 
+ 	nr_switches = p->nvcsw + p->nivcsw;
+ 
+diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
+index 2246a36..b14be25 100644
+--- a/kernel/sched/fair.c
++++ b/kernel/sched/fair.c
+@@ -32,9 +32,28 @@
+ #include <linux/task_work.h>
+ 
+ #include <trace/events/sched.h>
++#include <linux/sysfs.h>
++#include <linux/vmalloc.h>
++#ifdef CONFIG_HMP_FREQUENCY_INVARIANT_SCALE
++/* Include cpufreq header to add a notifier so that cpu frequency
++ * scaling can track the current CPU frequency
++ */
++#include <linux/cpufreq.h>
++#endif /* CONFIG_HMP_FREQUENCY_INVARIANT_SCALE */
++#ifdef CONFIG_SCHED_HMP
++#include <linux/cpuidle.h>
++#endif
+ 
+ #include "sched.h"
+ 
++
++/* Add apportunity to config how to placement the task
++ * when task fork.
++ * Default: Task fork on A7
++ */
++unsigned int task_fork_on_bigcore = 1;
++
++
+ /*
+  * Targeted preemption latency for CPU-bound tasks:
+  * (default: 6ms * (1 + ilog(ncpus)), units: nanoseconds)
+@@ -2001,6 +2020,13 @@ void task_numa_work(struct callback_head *work)
+ 		if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
+ 			continue;
+ 
++		/*
++		 * Skip inaccessible VMAs to avoid any confusion between
++		 * PROT_NONE and NUMA hinting ptes
++		 */
++		if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
++			continue;
++
+ 		do {
+ 			start = max(start, vma->vm_start);
+ 			end = ALIGN(start + (pages << PAGE_SHIFT), HPAGE_SIZE);
+@@ -2289,8 +2315,91 @@ static u32 __compute_runnable_contrib(u64 n)
+ 	return contrib + runnable_avg_yN_sum[n];
+ }
+ 
+-/*
+- * We can represent the historical contribution to runnable average as the
++#ifdef CONFIG_SCHED_HMP
++#define HMP_VARIABLE_SCALE_SHIFT 16ULL
++struct hmp_global_attr {
++	struct attribute attr;
++	ssize_t (*show)(struct kobject *kobj,
++			struct attribute *attr, char *buf);
++	ssize_t (*store)(struct kobject *a, struct attribute *b,
++			const char *c, size_t count);
++	int *value;
++	int (*to_sysfs)(int);
++	int (*from_sysfs)(int);
++	ssize_t (*to_sysfs_text)(char *buf, int buf_size);
++};
++
++#define HMP_DATA_SYSFS_MAX 8
++
++struct hmp_data_struct {
++#ifdef CONFIG_HMP_FREQUENCY_INVARIANT_SCALE
++	int freqinvar_load_scale_enabled;
++#endif
++	int multiplier; /* used to scale the time delta */
++	struct attribute_group attr_group;
++	struct attribute *attributes[HMP_DATA_SYSFS_MAX + 1];
++	struct hmp_global_attr attr[HMP_DATA_SYSFS_MAX];
++} hmp_data;
++
++static u64 hmp_variable_scale_convert(u64 delta);
++#ifdef CONFIG_HMP_FREQUENCY_INVARIANT_SCALE
++/* Frequency-Invariant Load Modification:
++ * Loads are calculated as in PJT's patch however we also scale the current
++ * contribution in line with the frequency of the CPU that the task was
++ * executed on.
++ * In this version, we use a simple linear scale derived from the maximum
++ * frequency reported by CPUFreq. As an example:
++ *
++ * Consider that we ran a task for 100% of the previous interval.
++ *
++ * Our CPU was under asynchronous frequency control through one of the
++ * CPUFreq governors.
++ *
++ * The CPUFreq governor reports that it is able to scale the CPU between
++ * 500MHz and 1GHz.
++ *
++ * During the period, the CPU was running at 1GHz.
++ *
++ * In this case, our load contribution for that period is calculated as
++ * 1 * (number_of_active_microseconds)
++ *
++ * This results in our task being able to accumulate maximum load as normal.
++ *
++ *
++ * Consider now that our CPU was executing at 500MHz.
++ *
++ * We now scale the load contribution such that it is calculated as
++ * 0.5 * (number_of_active_microseconds)
++ *
++ * Our task can only record 50% maximum load during this period.
++ *
++ * This represents the task consuming 50% of the CPU's *possible* compute
++ * capacity. However the task did consume 100% of the CPU's *available*
++ * compute capacity which is the value seen by the CPUFreq governor and
++ * user-side CPU Utilization tools.
++ *
++ * Restricting tracked load to be scaled by the CPU's frequency accurately
++ * represents the consumption of possible compute capacity and allows the
++ * HMP migration's simple threshold migration strategy to interact more
++ * predictably with CPUFreq's asynchronous compute capacity changes.
++ */
++#define SCHED_FREQSCALE_SHIFT 10
++struct cpufreq_extents {
++	u32 curr_scale;
++	u32 min;
++	u32 max;
++	u32 flags;
++};
++/* Flag set when the governor in use only allows one frequency.
++ * Disables scaling.
++ */
++#define SCHED_LOAD_FREQINVAR_SINGLEFREQ 0x01
++
++static struct cpufreq_extents freq_scale[CONFIG_NR_CPUS];
++#endif /* CONFIG_HMP_FREQUENCY_INVARIANT_SCALE */
++#endif /* CONFIG_SCHED_HMP */
++
++/* We can represent the historical contribution to runnable average as the
+  * coefficients of a geometric series.  To do this we sub-divide our runnable
+  * history into segments of approximately 1ms (1024us); label the segment that
+  * occurred N-ms ago p_N, with p_0 corresponding to the current period, e.g.
+@@ -2319,13 +2428,24 @@ static u32 __compute_runnable_contrib(u64 n)
+  */
+ static __always_inline int __update_entity_runnable_avg(u64 now,
+ 							struct sched_avg *sa,
+-							int runnable)
++							int runnable,
++							int running,
++							int cpu)
+ {
+ 	u64 delta, periods;
+ 	u32 runnable_contrib;
+ 	int delta_w, decayed = 0;
++#ifdef CONFIG_HMP_FREQUENCY_INVARIANT_SCALE
++	u64 scaled_delta;
++	u32 scaled_runnable_contrib;
++	int scaled_delta_w;
++	u32 curr_scale = 1024;
++#endif /* CONFIG_HMP_FREQUENCY_INVARIANT_SCALE */
+ 
+ 	delta = now - sa->last_runnable_update;
++#ifdef CONFIG_SCHED_HMP
++	delta = hmp_variable_scale_convert(delta);
++#endif
+ 	/*
+ 	 * This should only happen when time goes backwards, which it
+ 	 * unfortunately does during sched clock init when we swap over to TSC.
+@@ -2344,6 +2464,12 @@ static __always_inline int __update_entity_runnable_avg(u64 now,
+ 		return 0;
+ 	sa->last_runnable_update = now;
+ 
++#ifdef CONFIG_HMP_FREQUENCY_INVARIANT_SCALE
++	/* retrieve scale factor for load */
++	if (hmp_data.freqinvar_load_scale_enabled)
++		curr_scale = freq_scale[cpu].curr_scale;
++#endif /* CONFIG_HMP_FREQUENCY_INVARIANT_SCALE */
++
+ 	/* delta_w is the amount already accumulated against our next period */
+ 	delta_w = sa->runnable_avg_period % 1024;
+ 	if (delta + delta_w >= 1024) {
+@@ -2356,8 +2482,20 @@ static __always_inline int __update_entity_runnable_avg(u64 now,
+ 		 * period and accrue it.
+ 		 */
+ 		delta_w = 1024 - delta_w;
++		/* scale runnable time if necessary */
++#ifdef CONFIG_HMP_FREQUENCY_INVARIANT_SCALE
++		scaled_delta_w = (delta_w * curr_scale)
++				>> SCHED_FREQSCALE_SHIFT;
++		if (runnable)
++			sa->runnable_avg_sum += scaled_delta_w;
++		if (running)
++			sa->usage_avg_sum += scaled_delta_w;
++#else
+ 		if (runnable)
+ 			sa->runnable_avg_sum += delta_w;
++		if (running)
++			sa->usage_avg_sum += delta_w;
++#endif /* #ifdef CONFIG_HMP_FREQUENCY_INVARIANT_SCALE */
+ 		sa->runnable_avg_period += delta_w;
+ 
+ 		delta -= delta_w;
+@@ -2365,22 +2503,49 @@ static __always_inline int __update_entity_runnable_avg(u64 now,
+ 		/* Figure out how many additional periods this update spans */
+ 		periods = delta / 1024;
+ 		delta %= 1024;
+-
++		/* decay the load we have accumulated so far */
+ 		sa->runnable_avg_sum = decay_load(sa->runnable_avg_sum,
+ 						  periods + 1);
+ 		sa->runnable_avg_period = decay_load(sa->runnable_avg_period,
+ 						     periods + 1);
+-
++		sa->usage_avg_sum = decay_load(sa->usage_avg_sum, periods + 1);
++		/* add the contribution from this period */
+ 		/* Efficiently calculate \sum (1..n_period) 1024*y^i */
+ 		runnable_contrib = __compute_runnable_contrib(periods);
++		/* Apply load scaling if necessary.
++		 * Note that multiplying the whole series is same as
++		 * multiplying all terms
++		 */
++#ifdef CONFIG_HMP_FREQUENCY_INVARIANT_SCALE
++		scaled_runnable_contrib = (runnable_contrib * curr_scale)
++				>> SCHED_FREQSCALE_SHIFT;
++		if (runnable)
++			sa->runnable_avg_sum += scaled_runnable_contrib;
++		if (running)
++			sa->usage_avg_sum += scaled_runnable_contrib;
++#else
+ 		if (runnable)
+ 			sa->runnable_avg_sum += runnable_contrib;
++		if (running)
++			sa->usage_avg_sum += runnable_contrib;
++#endif /* CONFIG_HMP_FREQUENCY_INVARIANT_SCALE */
+ 		sa->runnable_avg_period += runnable_contrib;
+ 	}
+ 
+ 	/* Remainder of delta accrued against u_0` */
++	/* scale if necessary */
++#ifdef CONFIG_HMP_FREQUENCY_INVARIANT_SCALE
++	scaled_delta = ((delta * curr_scale) >> SCHED_FREQSCALE_SHIFT);
++	if (runnable)
++		sa->runnable_avg_sum += scaled_delta;
++	if (running)
++		sa->usage_avg_sum += scaled_delta;
++#else
+ 	if (runnable)
+ 		sa->runnable_avg_sum += delta;
++	if (running)
++		sa->usage_avg_sum += delta;
++#endif /* CONFIG_HMP_FREQUENCY_INVARIANT_SCALE */
+ 	sa->runnable_avg_period += delta;
+ 
+ 	return decayed;
+@@ -2393,12 +2558,10 @@ static inline u64 __synchronize_entity_decay(struct sched_entity *se)
+ 	u64 decays = atomic64_read(&cfs_rq->decay_counter);
+ 
+ 	decays -= se->avg.decay_count;
+-	if (!decays)
+-		return 0;
+-
+-	se->avg.load_avg_contrib = decay_load(se->avg.load_avg_contrib, decays);
++	if (decays)
++		se->avg.load_avg_contrib =
++			decay_load(se->avg.load_avg_contrib, decays);
+ 	se->avg.decay_count = 0;
+-
+ 	return decays;
+ }
+ 
+@@ -2429,16 +2592,28 @@ static inline void __update_tg_runnable_avg(struct sched_avg *sa,
+ 						  struct cfs_rq *cfs_rq)
+ {
+ 	struct task_group *tg = cfs_rq->tg;
+-	long contrib;
++	long contrib, usage_contrib;
+ 
+ 	/* The fraction of a cpu used by this cfs_rq */
+-	contrib = div_u64((u64)sa->runnable_avg_sum << NICE_0_SHIFT,
++	contrib = div_u64(sa->runnable_avg_sum << NICE_0_SHIFT,
+ 			  sa->runnable_avg_period + 1);
+ 	contrib -= cfs_rq->tg_runnable_contrib;
+ 
+-	if (abs(contrib) > cfs_rq->tg_runnable_contrib / 64) {
++	usage_contrib = div_u64(sa->usage_avg_sum << NICE_0_SHIFT,
++			sa->runnable_avg_period + 1);
++	usage_contrib -= cfs_rq->tg_usage_contrib;
++
++	/*
++	 * contrib/usage at this point represent deltas, only update if they
++	 * are substantive.
++	 */
++	if ((abs(contrib) > cfs_rq->tg_runnable_contrib / 64) ||
++	    (abs(usage_contrib) > cfs_rq->tg_usage_contrib / 64)) {
+ 		atomic_add(contrib, &tg->runnable_avg);
+ 		cfs_rq->tg_runnable_contrib += contrib;
++
++		atomic_add(usage_contrib, &tg->usage_avg);
++		cfs_rq->tg_usage_contrib += usage_contrib;
+ 	}
+ }
+ 
+@@ -2486,8 +2661,18 @@ static inline void __update_group_entity_contrib(struct sched_entity *se)
+ 
+ static inline void update_rq_runnable_avg(struct rq *rq, int runnable)
+ {
+-	__update_entity_runnable_avg(rq_clock_task(rq), &rq->avg, runnable);
++	int cpu = -1;	/* not used in normal case */
++
++#ifdef CONFIG_HMP_FREQUENCY_INVARIANT_SCALE
++	cpu = rq->cpu;
++#endif
++	__update_entity_runnable_avg(rq_clock_task(rq), &rq->avg, runnable,
++			runnable, cpu);
+ 	__update_tg_runnable_avg(&rq->avg, &rq->cfs);
++	trace_sched_rq_runnable_ratio(cpu_of(rq), rq->avg.load_avg_ratio);
++	trace_sched_rq_runnable_load(cpu_of(rq), rq->cfs.runnable_load_avg);
++	trace_sched_rq_nr_running(cpu_of(rq), rq->nr_running,
++			rq->nr_iowait.counter);
+ }
+ #else /* CONFIG_FAIR_GROUP_SCHED */
+ static inline void __update_cfs_rq_tg_load_contrib(struct cfs_rq *cfs_rq,
+@@ -2506,12 +2691,19 @@ static inline void __update_task_entity_contrib(struct sched_entity *se)
+ 	contrib = se->avg.runnable_avg_sum * scale_load_down(se->load.weight);
+ 	contrib /= (se->avg.runnable_avg_period + 1);
+ 	se->avg.load_avg_contrib = scale_load(contrib);
++	trace_sched_task_load_contrib(task_of(se), se->avg.load_avg_contrib);
++	contrib = se->avg.runnable_avg_sum * scale_load_down(NICE_0_LOAD);
++	contrib /= (se->avg.runnable_avg_period + 1);
++	se->avg.load_avg_ratio = scale_load(contrib);
++	trace_sched_task_runnable_ratio(task_of(se), se->avg.load_avg_ratio);
+ }
+ 
+ /* Compute the current contribution to load_avg by se, return any delta */
+-static long __update_entity_load_avg_contrib(struct sched_entity *se)
++static long __update_entity_load_avg_contrib(struct sched_entity *se,
++						long *ratio)
+ {
+ 	long old_contrib = se->avg.load_avg_contrib;
++	long old_ratio   = se->avg.load_avg_ratio;
+ 
+ 	if (entity_is_task(se)) {
+ 		__update_task_entity_contrib(se);
+@@ -2520,6 +2712,8 @@ static long __update_entity_load_avg_contrib(struct sched_entity *se)
+ 		__update_group_entity_contrib(se);
+ 	}
+ 
++	if (ratio)
++		*ratio = se->avg.load_avg_ratio - old_ratio;
+ 	return se->avg.load_avg_contrib - old_contrib;
+ }
+ 
+@@ -2539,9 +2733,13 @@ static inline void update_entity_load_avg(struct sched_entity *se,
+ 					  int update_cfs_rq)
+ {
+ 	struct cfs_rq *cfs_rq = cfs_rq_of(se);
+-	long contrib_delta;
++	long contrib_delta, ratio_delta;
+ 	u64 now;
++	int cpu = -1;   /* not used in normal case */
+ 
++#ifdef CONFIG_HMP_FREQUENCY_INVARIANT_SCALE
++	cpu = cfs_rq->rq->cpu;
++#endif
+ 	/*
+ 	 * For a group entity we need to use their owned cfs_rq_clock_task() in
+ 	 * case they are the parent of a throttled hierarchy.
+@@ -2551,18 +2749,21 @@ static inline void update_entity_load_avg(struct sched_entity *se,
+ 	else
+ 		now = cfs_rq_clock_task(group_cfs_rq(se));
+ 
+-	if (!__update_entity_runnable_avg(now, &se->avg, se->on_rq))
++	if (!__update_entity_runnable_avg(now, &se->avg, se->on_rq,
++			cfs_rq->curr == se, cpu))
+ 		return;
+ 
+-	contrib_delta = __update_entity_load_avg_contrib(se);
++	contrib_delta = __update_entity_load_avg_contrib(se, &ratio_delta);
+ 
+ 	if (!update_cfs_rq)
+ 		return;
+ 
+-	if (se->on_rq)
++	if (se->on_rq) {
+ 		cfs_rq->runnable_load_avg += contrib_delta;
+-	else
++		rq_of(cfs_rq)->avg.load_avg_ratio += ratio_delta;
++	} else {
+ 		subtract_blocked_load_contrib(cfs_rq, -contrib_delta);
++	}
+ }
+ 
+ /*
+@@ -2637,6 +2838,8 @@ static inline void enqueue_entity_load_avg(struct cfs_rq *cfs_rq,
+ 	}
+ 
+ 	cfs_rq->runnable_load_avg += se->avg.load_avg_contrib;
++	rq_of(cfs_rq)->avg.load_avg_ratio += se->avg.load_avg_ratio;
++
+ 	/* we force update consideration on load-balancer moves */
+ 	update_cfs_rq_blocked_load(cfs_rq, !wakeup);
+ }
+@@ -2655,6 +2858,8 @@ static inline void dequeue_entity_load_avg(struct cfs_rq *cfs_rq,
+ 	update_cfs_rq_blocked_load(cfs_rq, !sleep);
+ 
+ 	cfs_rq->runnable_load_avg -= se->avg.load_avg_contrib;
++	rq_of(cfs_rq)->avg.load_avg_ratio -= se->avg.load_avg_ratio;
++
+ 	if (sleep) {
+ 		cfs_rq->blocked_load_avg += se->avg.load_avg_contrib;
+ 		se->avg.decay_count = atomic64_read(&cfs_rq->decay_counter);
+@@ -2992,6 +3197,7 @@ set_next_entity(struct cfs_rq *cfs_rq, struct sched_entity *se)
+ 		 */
+ 		update_stats_wait_end(cfs_rq, se);
+ 		__dequeue_entity(cfs_rq, se);
++		update_entity_load_avg(se, 1);
+ 	}
+ 
+ 	update_stats_curr_start(cfs_rq, se);
+@@ -3331,6 +3537,7 @@ static inline int throttled_hierarchy(struct cfs_rq *cfs_rq)
+ 	return cfs_bandwidth_used() && cfs_rq->throttle_count;
+ }
+ 
++
+ /*
+  * Ensure that neither of the group entities corresponding to src_cpu or
+  * dest_cpu are members of a throttled hierarchy when performing group
+@@ -3959,7 +4166,6 @@ static inline void hrtick_update(struct rq *rq)
+ {
+ }
+ #endif
+-
+ /*
+  * The enqueue_task method is called before nr_running is
+  * increased. Here we update the fair scheduling stats and
+@@ -4167,6 +4373,16 @@ static void task_waking_fair(struct task_struct *p)
+ }
+ 
+ #ifdef CONFIG_FAIR_GROUP_SCHED
++
++#ifdef CONFIG_NO_HZ_COMMON
++static int nohz_test_cpu(int cpu);
++#else
++static inline int nohz_test_cpu(int cpu)
++{
++	return 0;
++}
++#endif
++
+ /*
+  * effective_load() calculates the load change as seen from the root_task_group
+  *
+@@ -4528,2529 +4744,4147 @@ done:
+ 	return target;
+ }
+ 
++#ifdef CONFIG_SCHED_HMP
+ /*
+- * select_task_rq_fair: Select target runqueue for the waking task in domains
+- * that have the 'sd_flag' flag set. In practice, this is SD_BALANCE_WAKE,
+- * SD_BALANCE_FORK, or SD_BALANCE_EXEC.
++ * Heterogenous multiprocessor (HMP) optimizations
+  *
+- * Balances load by selecting the idlest cpu in the idlest group, or under
+- * certain conditions an idle sibling cpu if the domain has SD_WAKE_AFFINE set.
++ * The cpu types are distinguished using a list of hmp_domains
++ * which each represent one cpu type using a cpumask.
++ * The list is assumed ordered by compute capacity with the
++ * fastest domain first.
++ */
++DEFINE_PER_CPU(struct hmp_domain *, hmp_cpu_domain);
++static const int hmp_max_tasks = 5;
++
++extern void __init arch_get_hmp_domains(struct list_head *hmp_domains_list);
++
++#ifdef CONFIG_CPU_IDLE
++/*
++ * hmp_idle_pull:
+  *
+- * Returns the target cpu number.
++ * In this version we have stopped using forced up migrations when we
++ * detect that a task running on a little CPU should be moved to a bigger
++ * CPU. In most cases, the bigger CPU is in a deep sleep state and a forced
++ * migration means we stop the task immediately but need to wait for the
++ * target CPU to wake up before we can restart the task which is being
++ *+ moved. Instead, we now wake a big CPU with an IPI and ask it to pull
++ *+ a task when ready. This allows the task to continue executing on its
++ *+ current CPU, reducing the amount of time that the task is stalled for.
+  *
+- * preempt must be disabled.
++ * keepalive timers:
++ *
++ * The keepalive timer is used as a way to keep a CPU engaged in an
++ * idle pull operation out of idle while waiting for the source
++ * CPU to stop and move the task. Ideally this would not be necessary
++ * and we could impose a temporary zero-latency requirement on the
++ * current CPU, but in the current QoS framework this will result in
++ * all CPUs in the system being unable to enter idle states which is
++ * not desirable. The timer does not perform any work when it expires.
+  */
+-static int
+-select_task_rq_fair(struct task_struct *p, int prev_cpu, int sd_flag, int wake_flags)
++struct hmp_keepalive {
++	bool init;
++	ktime_t delay;	/* if zero, no need for timer */
++	struct hrtimer timer;
++};
++DEFINE_PER_CPU(struct hmp_keepalive, hmp_cpu_keepalive);
++
++/* setup per-cpu keepalive timers */
++static enum hrtimer_restart hmp_cpu_keepalive_notify(struct hrtimer *hrtimer)
+ {
+-	struct sched_domain *tmp, *affine_sd = NULL, *sd = NULL;
+-	int cpu = smp_processor_id();
+-	int new_cpu = cpu;
+-	int want_affine = 0;
+-	int sync = wake_flags & WF_SYNC;
++	return HRTIMER_NORESTART;
++}
+ 
+-	if (p->nr_cpus_allowed == 1)
+-		return prev_cpu;
++/*
++ * Work out if any of the idle states have an exit latency too high for us.
++ * ns_delay is passed in containing the max we are willing to tolerate.
++ * If there are none, set ns_delay to zero.
++ * If there are any, set ns_delay to
++ * ('target_residency of state with shortest too-big latency' - 1) * 1000.
++ */
++static void hmp_keepalive_delay(int cpu, unsigned int *ns_delay)
++{
++	struct cpuidle_device *dev = per_cpu(cpuidle_devices, cpu);
++	struct cpuidle_driver *drv;
++
++	drv = cpuidle_get_cpu_driver(dev);
++	if (drv) {
++		unsigned int us_delay = UINT_MAX;
++		unsigned int us_max_delay = *ns_delay / 1000;
++		int idx;
++		/* if cpuidle states are guaranteed to be sorted we
++		 * could stop at the first match.
++		 */
++		for (idx = 0; idx < drv->state_count; idx++) {
++			if (drv->states[idx].exit_latency > us_max_delay &&
++				drv->states[idx].target_residency < us_delay) {
++				us_delay = drv->states[idx].target_residency;
++			}
++		}
++		if (us_delay == UINT_MAX)
++			*ns_delay = 0; /* no timer required */
++		else
++			*ns_delay = 1000 * (us_delay - 1);
++	}
++}
+ 
+-	if (sd_flag & SD_BALANCE_WAKE)
+-		want_affine = cpumask_test_cpu(cpu, tsk_cpus_allowed(p));
++static void hmp_cpu_keepalive_trigger(void)
++{
++	int cpu = smp_processor_id();
++	struct hmp_keepalive *keepalive = &per_cpu(hmp_cpu_keepalive, cpu);
+ 
+-	rcu_read_lock();
+-	for_each_domain(cpu, tmp) {
+-		if (!(tmp->flags & SD_LOAD_BALANCE))
+-			continue;
++	if (!keepalive->init) {
++		unsigned int ns_delay = 100000; /* tolerate 100usec delay */
+ 
+-		/*
+-		 * If both cpu and prev_cpu are part of this domain,
+-		 * cpu is a valid SD_WAKE_AFFINE target.
+-		 */
+-		if (want_affine && (tmp->flags & SD_WAKE_AFFINE) &&
+-		    cpumask_test_cpu(prev_cpu, sched_domain_span(tmp))) {
+-			affine_sd = tmp;
+-			break;
+-		}
++		hrtimer_init(&keepalive->timer,
++				CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED);
++		keepalive->timer.function = hmp_cpu_keepalive_notify;
+ 
+-		if (tmp->flags & sd_flag)
+-			sd = tmp;
++		hmp_keepalive_delay(cpu, &ns_delay);
++		keepalive->delay = ns_to_ktime(ns_delay);
++		keepalive->init = true;
+ 	}
++	if (ktime_to_ns(keepalive->delay))
++		hrtimer_start(&keepalive->timer,
++				keepalive->delay, HRTIMER_MODE_REL_PINNED);
++}
+ 
+-	if (affine_sd && cpu != prev_cpu && wake_affine(affine_sd, p, sync))
+-		prev_cpu = cpu;
++static void hmp_cpu_keepalive_cancel(int cpu)
++{
++	struct hmp_keepalive *keepalive = &per_cpu(hmp_cpu_keepalive, cpu);
+ 
+-	if (sd_flag & SD_BALANCE_WAKE) {
+-		new_cpu = select_idle_sibling(p, prev_cpu);
+-		goto unlock;
+-	}
++	if (keepalive->init)
++		hrtimer_cancel(&keepalive->timer);
++}
++#else /* !CONFIG_CPU_IDLE */
++static void hmp_cpu_keepalive_trigger(void)
++{
++}
+ 
+-	while (sd) {
+-		struct sched_group *group;
+-		int weight;
++static void hmp_cpu_keepalive_cancel(int cpu)
++{
++}
++#endif
+ 
+-		if (!(sd->flags & sd_flag)) {
+-			sd = sd->child;
+-			continue;
+-		}
++/* Setup hmp_domains */
++static int __init hmp_cpu_mask_setup(void)
++{
++	char buf[64];
++	struct hmp_domain *domain;
++	struct list_head *pos;
++	int dc, cpu;
+ 
+-		group = find_idlest_group(sd, p, cpu, sd_flag);
+-		if (!group) {
+-			sd = sd->child;
+-			continue;
+-		}
++	pr_debug("Initializing HMP scheduler:\n");
+ 
+-		new_cpu = find_idlest_cpu(group, p, cpu);
+-		if (new_cpu == -1 || new_cpu == cpu) {
+-			/* Now try balancing at a lower domain level of cpu */
+-			sd = sd->child;
+-			continue;
+-		}
++	/* Initialize hmp_domains using platform code */
++	arch_get_hmp_domains(&hmp_domains);
++	if (list_empty(&hmp_domains)) {
++		pr_debug("HMP domain list is empty!\n");
++		return 0;
++	}
+ 
+-		/* Now try balancing at a lower domain level of new_cpu */
+-		cpu = new_cpu;
+-		weight = sd->span_weight;
+-		sd = NULL;
+-		for_each_domain(cpu, tmp) {
+-			if (weight <= tmp->span_weight)
+-				break;
+-			if (tmp->flags & sd_flag)
+-				sd = tmp;
++	/* Print hmp_domains */
++	dc = 0;
++	list_for_each(pos, &hmp_domains) {
++		domain = list_entry(pos, struct hmp_domain, hmp_domains);
++		cpulist_scnprintf(buf, 64, &domain->possible_cpus);
++		pr_debug("  HMP domain %d: %s\n", dc, buf);
++
++		for_each_cpu_mask(cpu, domain->possible_cpus) {
++			per_cpu(hmp_cpu_domain, cpu) = domain;
+ 		}
+-		/* while loop will break here if sd == NULL */
++		dc++;
+ 	}
+-unlock:
+-	rcu_read_unlock();
+ 
+-	return new_cpu;
++	return 1;
+ }
+ 
+-/*
+- * Called immediately before a task is migrated to a new cpu; task_cpu(p) and
+- * cfs_rq_of(p) references at time of call are still valid and identify the
+- * previous cpu.  However, the caller only guarantees p->pi_lock is held; no
+- * other assumptions, including the state of rq->lock, should be made.
+- */
+-static void
+-migrate_task_rq_fair(struct task_struct *p, int next_cpu)
++static struct hmp_domain *hmp_get_hmp_domain_for_cpu(int cpu)
+ {
+-	struct sched_entity *se = &p->se;
+-	struct cfs_rq *cfs_rq = cfs_rq_of(se);
++	struct hmp_domain *domain;
++	struct list_head *pos;
+ 
+-	/*
+-	 * Load tracking: accumulate removed load so that it can be processed
+-	 * when we next update owning cfs_rq under rq->lock.  Tasks contribute
+-	 * to blocked load iff they have a positive decay-count.  It can never
+-	 * be negative here since on-rq tasks have decay-count == 0.
+-	 */
+-	if (se->avg.decay_count) {
+-		se->avg.decay_count = -__synchronize_entity_decay(se);
+-		atomic_long_add(se->avg.load_avg_contrib,
+-						&cfs_rq->removed_load);
++	list_for_each(pos, &hmp_domains) {
++		domain = list_entry(pos, struct hmp_domain, hmp_domains);
++		if (cpumask_test_cpu(cpu, &domain->possible_cpus))
++			return domain;
+ 	}
+-
+-	/* We have migrated, no longer consider this task hot */
+-	se->exec_start = 0;
++	return NULL;
+ }
+-#endif /* CONFIG_SMP */
+ 
+-static unsigned long
+-wakeup_gran(struct sched_entity *curr, struct sched_entity *se)
++static void hmp_online_cpu(int cpu)
+ {
+-	unsigned long gran = sysctl_sched_wakeup_granularity;
++	struct hmp_domain *domain = hmp_get_hmp_domain_for_cpu(cpu);
+ 
+-	/*
+-	 * Since its curr running now, convert the gran from real-time
+-	 * to virtual-time in his units.
+-	 *
+-	 * By using 'se' instead of 'curr' we penalize light tasks, so
+-	 * they get preempted easier. That is, if 'se' < 'curr' then
+-	 * the resulting gran will be larger, therefore penalizing the
+-	 * lighter, if otoh 'se' > 'curr' then the resulting gran will
+-	 * be smaller, again penalizing the lighter task.
+-	 *
+-	 * This is especially important for buddies when the leftmost
+-	 * task is higher priority than the buddy.
+-	 */
+-	return calc_delta_fair(gran, se);
++	if (domain)
++		cpumask_set_cpu(cpu, &domain->cpus);
+ }
+ 
+-/*
+- * Should 'se' preempt 'curr'.
+- *
+- *             |s1
+- *        |s2
+- *   |s3
+- *         g
+- *      |<--->|c
+- *
+- *  w(c, s1) = -1
+- *  w(c, s2) =  0
+- *  w(c, s3) =  1
+- *
+- */
+-static int
+-wakeup_preempt_entity(struct sched_entity *curr, struct sched_entity *se)
++static void hmp_offline_cpu(int cpu)
+ {
+-	s64 gran, vdiff = curr->vruntime - se->vruntime;
+-
+-	if (vdiff <= 0)
+-		return -1;
++	struct hmp_domain *domain = hmp_get_hmp_domain_for_cpu(cpu);
+ 
+-	gran = wakeup_gran(curr, se);
+-	if (vdiff > gran)
+-		return 1;
++	if (domain)
++		cpumask_clear_cpu(cpu, &domain->cpus);
+ 
+-	return 0;
++	hmp_cpu_keepalive_cancel(cpu);
++}
++/*
++ * Needed to determine heaviest tasks etc.
++ */
++static inline unsigned int hmp_cpu_is_fastest(int cpu);
++static inline unsigned int hmp_cpu_is_slowest(int cpu);
++static inline struct hmp_domain *hmp_slower_domain(int cpu);
++static inline struct hmp_domain *hmp_faster_domain(int cpu);
++
++/* must hold runqueue lock for queue se is currently on */
++static struct sched_entity *hmp_get_heaviest_task(
++				struct sched_entity *se, int target_cpu)
++{
++	int num_tasks = hmp_max_tasks;
++	struct sched_entity *max_se = se;
++	unsigned long int max_ratio = se->avg.load_avg_ratio;
++	const struct cpumask *hmp_target_mask = NULL;
++	struct hmp_domain *hmp;
++
++	if (hmp_cpu_is_fastest(cpu_of(se->cfs_rq->rq)))
++		return max_se;
++
++	hmp = hmp_faster_domain(cpu_of(se->cfs_rq->rq));
++	hmp_target_mask = &hmp->cpus;
++	if (target_cpu >= 0) {
++		/* idle_balance gets run on a CPU while
++		 * it is in the middle of being hotplugged
++		 * out. Bail early in that case.
++		 */
++		if (!cpumask_test_cpu(target_cpu, hmp_target_mask))
++			return NULL;
++		hmp_target_mask = cpumask_of(target_cpu);
++	}
++	/* The currently running task is not on the runqueue */
++	se = __pick_first_entity(cfs_rq_of(se));
++
++	while (num_tasks && se) {
++		if (entity_is_task(se) &&
++			se->avg.load_avg_ratio > max_ratio &&
++			cpumask_intersects(hmp_target_mask,
++				tsk_cpus_allowed(task_of(se)))) {
++			max_se = se;
++			max_ratio = se->avg.load_avg_ratio;
++		}
++		se = __pick_next_entity(se);
++		num_tasks--;
++	}
++	return max_se;
+ }
+ 
+-static void set_last_buddy(struct sched_entity *se)
++static struct sched_entity *hmp_get_lightest_task(
++				struct sched_entity *se, int migrate_down)
+ {
+-	if (entity_is_task(se) && unlikely(task_of(se)->policy == SCHED_IDLE))
+-		return;
++	int num_tasks = hmp_max_tasks;
++	struct sched_entity *min_se = se;
++	unsigned long int min_ratio = se->avg.load_avg_ratio;
++	const struct cpumask *hmp_target_mask = NULL;
+ 
+-	for_each_sched_entity(se)
+-		cfs_rq_of(se)->last = se;
+-}
++	if (migrate_down) {
++		struct hmp_domain *hmp;
+ 
+-static void set_next_buddy(struct sched_entity *se)
+-{
+-	if (entity_is_task(se) && unlikely(task_of(se)->policy == SCHED_IDLE))
+-		return;
++		if (hmp_cpu_is_slowest(cpu_of(se->cfs_rq->rq)))
++			return min_se;
++		hmp = hmp_slower_domain(cpu_of(se->cfs_rq->rq));
++		hmp_target_mask = &hmp->cpus;
++	}
++	/* The currently running task is not on the runqueue */
++	se = __pick_first_entity(cfs_rq_of(se));
+ 
+-	for_each_sched_entity(se)
+-		cfs_rq_of(se)->next = se;
++	while (num_tasks && se) {
++		if (entity_is_task(se) &&
++			(se->avg.load_avg_ratio < min_ratio &&
++			hmp_target_mask &&
++				cpumask_intersects(hmp_target_mask,
++				tsk_cpus_allowed(task_of(se))))) {
++			min_se = se;
++			min_ratio = se->avg.load_avg_ratio;
++		}
++		se = __pick_next_entity(se);
++		num_tasks--;
++	}
++	return min_se;
+ }
+ 
+-static void set_skip_buddy(struct sched_entity *se)
+-{
+-	for_each_sched_entity(se)
+-		cfs_rq_of(se)->skip = se;
+-}
++/*
++ * Migration thresholds should be in the range [0..1023]
++ * hmp_up_threshold: min. load required for migrating tasks to a faster cpu
++ * hmp_down_threshold: max. load allowed for tasks migrating to a slower cpu
++ *
++ * hmp_up_prio: Only up migrate task with high priority (<hmp_up_prio)
++ * hmp_next_up_threshold: Delay before next up migration (1024 ~= 1 ms)
++ * hmp_next_down_threshold: Delay before next down migration (1024 ~= 1 ms)
++ *
++ * Small Task Packing:
++ * We can choose to fill the littlest CPUs in an HMP system rather than
++ * the typical spreading mechanic. This behavior is controllable using
++ * two variables.
++ * hmp_packing_enabled: runtime control over pack/spread
++ * hmp_full_threshold: Consider a CPU with this much unweighted load full
++ */
++unsigned int hmp_up_threshold = 700;
++unsigned int hmp_down_threshold = 512;
++#ifdef CONFIG_SCHED_HMP_PRIO_FILTER
++unsigned int hmp_up_prio = NICE_TO_PRIO(CONFIG_SCHED_HMP_PRIO_FILTER_VAL);
++#endif
++unsigned int hmp_next_up_threshold = 4096;
++unsigned int hmp_next_down_threshold = 4096;
+ 
++#ifdef CONFIG_SCHED_HMP_LITTLE_PACKING
+ /*
+- * Preempt the current task with a newly woken task if needed:
++ * Set the default packing threshold to try to keep little
++ * CPUs at no more than 80% of their maximum frequency if only
++ * packing a small number of small tasks. Bigger tasks will
++ * raise frequency as normal.
++ * In order to pack a task onto a CPU, the sum of the
++ * unweighted runnable_avg load of existing tasks plus the
++ * load of the new task must be less than hmp_full_threshold.
++ *
++ * This works in conjunction with frequency-invariant load
++ * and DVFS governors. Since most DVFS governors aim for 80%
++ * utilisation, we arrive at (0.8*0.8*(max_load=1024))=655
++ * and use a value slightly lower to give a little headroom
++ * in the decision.
++ * Note that the most efficient frequency is different for
++ * each system so /sys/kernel/hmp/packing_limit should be
++ * configured at runtime for any given platform to achieve
++ * optimal energy usage. Some systems may not benefit from
++ * packing, so this feature can also be disabled at runtime
++ * with /sys/kernel/hmp/packing_enable
+  */
+-static void check_preempt_wakeup(struct rq *rq, struct task_struct *p, int wake_flags)
+-{
+-	struct task_struct *curr = rq->curr;
+-	struct sched_entity *se = &curr->se, *pse = &p->se;
+-	struct cfs_rq *cfs_rq = task_cfs_rq(curr);
+-	int scale = cfs_rq->nr_running >= sched_nr_latency;
+-	int next_buddy_marked = 0;
++unsigned int hmp_packing_enabled = 1;
++unsigned int hmp_full_threshold = 650;
++#endif
+ 
+-	if (unlikely(se == pse))
+-		return;
++static unsigned int hmp_up_migration(int cpu, int *target_cpu,
++					struct sched_entity *se);
++static unsigned int hmp_down_migration(int cpu, struct sched_entity *se);
++static inline unsigned int hmp_domain_min_load(struct hmp_domain *hmpd,
++						int *min_cpu,
++						struct cpumask *affinity);
+ 
+-	/*
+-	 * This is possible from callers such as attach_tasks(), in which we
+-	 * unconditionally check_prempt_curr() after an enqueue (which may have
+-	 * lead to a throttle).  This both saves work and prevents false
+-	 * next-buddy nomination below.
+-	 */
+-	if (unlikely(throttled_hierarchy(cfs_rq_of(pse))))
+-		return;
++static inline struct hmp_domain *hmp_smallest_domain(void)
++{
++	return list_entry(hmp_domains.prev, struct hmp_domain, hmp_domains);
++}
+ 
+-	if (sched_feat(NEXT_BUDDY) && scale && !(wake_flags & WF_FORK)) {
+-		set_next_buddy(pse);
+-		next_buddy_marked = 1;
+-	}
++/* Check if cpu is in fastest hmp_domain */
++static inline unsigned int hmp_cpu_is_fastest(int cpu)
++{
++	struct list_head *pos;
+ 
+-	/*
+-	 * We can come here with TIF_NEED_RESCHED already set from new task
+-	 * wake up path.
+-	 *
+-	 * Note: this also catches the edge-case of curr being in a throttled
+-	 * group (e.g. via set_curr_task), since update_curr() (in the
+-	 * enqueue of curr) will have resulted in resched being set.  This
+-	 * prevents us from potentially nominating it as a false LAST_BUDDY
+-	 * below.
+-	 */
+-	if (test_tsk_need_resched(curr))
+-		return;
++	pos = &hmp_cpu_domain(cpu)->hmp_domains;
++	return pos == hmp_domains.next;
++}
+ 
+-	/* Idle tasks are by definition preempted by non-idle tasks. */
+-	if (unlikely(curr->policy == SCHED_IDLE) &&
+-	    likely(p->policy != SCHED_IDLE))
+-		goto preempt;
++/* Check if cpu is in slowest hmp_domain */
++static inline unsigned int hmp_cpu_is_slowest(int cpu)
++{
++	struct list_head *pos;
+ 
+-	/*
+-	 * Batch and idle tasks do not preempt non-idle tasks (their preemption
+-	 * is driven by the tick):
+-	 */
+-	if (unlikely(p->policy != SCHED_NORMAL) || !sched_feat(WAKEUP_PREEMPTION))
+-		return;
++	pos = &hmp_cpu_domain(cpu)->hmp_domains;
++	return list_is_last(pos, &hmp_domains);
++}
+ 
+-	find_matching_se(&se, &pse);
+-	update_curr(cfs_rq_of(se));
+-	BUG_ON(!pse);
+-	if (wakeup_preempt_entity(se, pse) == 1) {
+-		/*
+-		 * Bias pick_next to pick the sched entity that is
+-		 * triggering this preemption.
+-		 */
+-		if (!next_buddy_marked)
+-			set_next_buddy(pse);
+-		goto preempt;
+-	}
++/* Next (slower) hmp_domain relative to cpu */
++static inline struct hmp_domain *hmp_slower_domain(int cpu)
++{
++	struct list_head *pos;
+ 
+-	return;
++	pos = &hmp_cpu_domain(cpu)->hmp_domains;
++	return list_entry(pos->next, struct hmp_domain, hmp_domains);
++}
+ 
+-preempt:
+-	resched_curr(rq);
+-	/*
+-	 * Only set the backward buddy when the current task is still
+-	 * on the rq. This can happen when a wakeup gets interleaved
+-	 * with schedule on the ->pre_schedule() or idle_balance()
+-	 * point, either of which can * drop the rq lock.
+-	 *
+-	 * Also, during early boot the idle thread is in the fair class,
+-	 * for obvious reasons its a bad idea to schedule back to it.
+-	 */
+-	if (unlikely(!se->on_rq || curr == rq->idle))
+-		return;
++/* Previous (faster) hmp_domain relative to cpu */
++static inline struct hmp_domain *hmp_faster_domain(int cpu)
++{
++	struct list_head *pos;
+ 
+-	if (sched_feat(LAST_BUDDY) && scale && entity_is_task(se))
+-		set_last_buddy(se);
++	pos = &hmp_cpu_domain(cpu)->hmp_domains;
++	return list_entry(pos->prev, struct hmp_domain, hmp_domains);
+ }
+ 
+-static struct task_struct *
+-pick_next_task_fair(struct rq *rq, struct task_struct *prev)
++/*
++ * Selects a cpu in previous (faster) hmp_domain
++ */
++static inline unsigned int hmp_select_faster_cpu(struct task_struct *tsk,
++							int cpu)
+ {
+-	struct cfs_rq *cfs_rq = &rq->cfs;
+-	struct sched_entity *se;
+-	struct task_struct *p;
+-	int new_tasks;
++	int lowest_cpu = NR_CPUS;
++	__always_unused int lowest_ratio;
++	struct hmp_domain *hmp;
+ 
+-again:
+-#ifdef CONFIG_FAIR_GROUP_SCHED
+-	if (!cfs_rq->nr_running)
+-		goto idle;
++	if (hmp_cpu_is_fastest(cpu))
++		hmp = hmp_cpu_domain(cpu);
++	else
++		hmp = hmp_faster_domain(cpu);
+ 
+-	if (prev->sched_class != &fair_sched_class)
+-		goto simple;
++	lowest_ratio = hmp_domain_min_load(hmp, &lowest_cpu,
++			tsk_cpus_allowed(tsk));
+ 
+-	/*
+-	 * Because of the set_next_buddy() in dequeue_task_fair() it is rather
+-	 * likely that a next task is from the same cgroup as the current.
+-	 *
+-	 * Therefore attempt to avoid putting and setting the entire cgroup
+-	 * hierarchy, only change the part that actually changes.
+-	 */
++	return lowest_cpu;
++}
+ 
+-	do {
+-		struct sched_entity *curr = cfs_rq->curr;
++/*
++ * Selects a cpu in next (slower) hmp_domain
++ * Note that cpumask_any_and() returns the first cpu in the cpumask
++ */
++static inline unsigned int hmp_select_slower_cpu(struct task_struct *tsk,
++							int cpu)
++{
++	int lowest_cpu = NR_CPUS;
++	struct hmp_domain *hmp;
++	__always_unused int lowest_ratio;
+ 
+-		/*
+-		 * Since we got here without doing put_prev_entity() we also
+-		 * have to consider cfs_rq->curr. If it is still a runnable
+-		 * entity, update_curr() will update its vruntime, otherwise
+-		 * forget we've ever seen it.
+-		 */
+-		if (curr && curr->on_rq)
+-			update_curr(cfs_rq);
+-		else
+-			curr = NULL;
++	if (hmp_cpu_is_slowest(cpu))
++		hmp = hmp_cpu_domain(cpu);
++	else
++		hmp = hmp_slower_domain(cpu);
+ 
+-		/*
+-		 * This call to check_cfs_rq_runtime() will do the throttle and
+-		 * dequeue its entity in the parent(s). Therefore the 'simple'
+-		 * nr_running test will indeed be correct.
+-		 */
+-		if (unlikely(check_cfs_rq_runtime(cfs_rq)))
+-			goto simple;
++	lowest_ratio = hmp_domain_min_load(hmp, &lowest_cpu,
++			tsk_cpus_allowed(tsk));
+ 
+-		se = pick_next_entity(cfs_rq, curr);
+-		cfs_rq = group_cfs_rq(se);
+-	} while (cfs_rq);
++	return lowest_cpu;
++}
++#ifdef CONFIG_SCHED_HMP_LITTLE_PACKING
++/*
++ * Select the 'best' candidate little CPU to wake up on.
++ * Implements a packing strategy which examines CPU in
++ * logical CPU order, and selects the first which will
++ * be loaded less than hmp_full_threshold according to
++ * the sum of the tracked load of the runqueue and the task.
++ */
++static inline unsigned int hmp_best_little_cpu(struct task_struct *tsk,
++		int cpu) {
++	int tmp_cpu;
++	unsigned long estimated_load;
++	struct hmp_domain *hmp;
++	struct sched_avg *avg;
++	struct cpumask allowed_hmp_cpus;
++
++	if (!hmp_packing_enabled ||
++			tsk->se.avg.load_avg_ratio > ((NICE_0_LOAD * 90)/100))
++		return hmp_select_slower_cpu(tsk, cpu);
++
++	if (hmp_cpu_is_slowest(cpu))
++		hmp = hmp_cpu_domain(cpu);
++	else
++		hmp = hmp_slower_domain(cpu);
++
++	/* respect affinity */
++	cpumask_and(&allowed_hmp_cpus, &hmp->cpus,
++			tsk_cpus_allowed(tsk));
++
++	for_each_cpu_mask(tmp_cpu, allowed_hmp_cpus) {
++		avg = &cpu_rq(tmp_cpu)->avg;
++		/* estimate new rq load if we add this task */
++		estimated_load = avg->load_avg_ratio +
++				tsk->se.avg.load_avg_ratio;
++		if (estimated_load <= hmp_full_threshold) {
++			cpu = tmp_cpu;
++			break;
++		}
++	}
++	/* if no match was found, the task uses the initial value */
++	return cpu;
++}
++#endif
+ 
+-	p = task_of(se);
++static inline void hmp_next_up_delay(struct sched_entity *se, int cpu)
++{
++	/* hack - always use clock from first online CPU */
++	u64 now = cpu_rq(cpumask_first(cpu_online_mask))->clock_task;
+ 
+-	/*
+-	 * Since we haven't yet done put_prev_entity and if the selected task
+-	 * is a different task than we started out with, try and touch the
+-	 * least amount of cfs_rqs.
+-	 */
+-	if (prev != p) {
+-		struct sched_entity *pse = &prev->se;
++	se->avg.hmp_last_up_migration = now;
++	se->avg.hmp_last_down_migration = 0;
++	cpu_rq(cpu)->avg.hmp_last_up_migration = now;
++	cpu_rq(cpu)->avg.hmp_last_down_migration = 0;
++}
+ 
+-		while (!(cfs_rq = is_same_group(se, pse))) {
+-			int se_depth = se->depth;
+-			int pse_depth = pse->depth;
++static inline void hmp_next_down_delay(struct sched_entity *se, int cpu)
++{
++	/* hack - always use clock from first online CPU */
++	u64 now = cpu_rq(cpumask_first(cpu_online_mask))->clock_task;
+ 
+-			if (se_depth <= pse_depth) {
+-				put_prev_entity(cfs_rq_of(pse), pse);
+-				pse = parent_entity(pse);
+-			}
+-			if (se_depth >= pse_depth) {
+-				set_next_entity(cfs_rq_of(se), se);
+-				se = parent_entity(se);
+-			}
+-		}
++	se->avg.hmp_last_down_migration = now;
++	se->avg.hmp_last_up_migration = 0;
++	cpu_rq(cpu)->avg.hmp_last_down_migration = now;
++	cpu_rq(cpu)->avg.hmp_last_up_migration = 0;
++}
+ 
+-		put_prev_entity(cfs_rq, pse);
+-		set_next_entity(cfs_rq, se);
+-	}
++/*
++ * Heterogenous multiprocessor (HMP) optimizations
++ *
++ * These functions allow to change the growing speed of the load_avg_ratio
++ * by default it goes from 0 to 0.5 in LOAD_AVG_PERIOD = 32ms
++ * This can now be changed with /sys/kernel/hmp/load_avg_period_ms.
++ *
++ * These functions also allow to change the up and down threshold of HMP
++ * using /sys/kernel/hmp/{up,down}_threshold.
++ * Both must be between 0 and 1023. The threshold that is compared
++ * to the load_avg_ratio is up_threshold/1024 and down_threshold/1024.
++ *
++ * For instance, if load_avg_period = 64 and up_threshold = 512, an idle
++ * task with a load of 0 will reach the threshold after 64ms of busy loop.
++ *
++ * Changing load_avg_periods_ms has the same effect than changing the
++ * default scaling factor Y=1002/1024 in the load_avg_ratio computation to
++ * (1002/1024.0)^(LOAD_AVG_PERIOD/load_avg_period_ms), but the last one
++ * could trigger overflows.
++ * For instance, with Y = 1023/1024 in __update_task_entity_contrib()
++ * "contrib = se->avg.runnable_avg_sum * scale_load_down(se->load.weight);"
++ * could be overflowed for a weight > 2^12 even is the load_avg_contrib
++ * should still be a 32bits result. This would not happen by multiplicating
++ * delta time by 1/22 and setting load_avg_period_ms = 706.
++ */
+ 
+-	if (hrtick_enabled(rq))
+-		hrtick_start_fair(rq, p);
++/*
++ * By scaling the delta time it end-up increasing or decrease the
++ * growing speed of the per entity load_avg_ratio
++ * The scale factor hmp_data.multiplier is a fixed point
++ * number: (32-HMP_VARIABLE_SCALE_SHIFT).HMP_VARIABLE_SCALE_SHIFT
++ */
++static inline u64 hmp_variable_scale_convert(u64 delta)
++{
++#ifdef CONFIG_HMP_VARIABLE_SCALE
++	u64 high = delta >> 32ULL;
++	u64 low = delta & 0xffffffffULL;
+ 
+-	return p;
+-simple:
+-	cfs_rq = &rq->cfs;
++	low *= hmp_data.multiplier;
++	high *= hmp_data.multiplier;
++	return (low >> HMP_VARIABLE_SCALE_SHIFT)
++			+ (high << (32ULL - HMP_VARIABLE_SCALE_SHIFT));
++#else
++	return delta;
+ #endif
++}
+ 
+-	if (!cfs_rq->nr_running)
+-		goto idle;
++static ssize_t hmp_show(struct kobject *kobj,
++				struct attribute *attr, char *buf)
++{
++	struct hmp_global_attr *hmp_attr =
++		container_of(attr, struct hmp_global_attr, attr);
++	int temp;
+ 
+-	put_prev_task(rq, prev);
++	if (hmp_attr->to_sysfs_text != NULL)
++		return hmp_attr->to_sysfs_text(buf, PAGE_SIZE);
+ 
+-	do {
+-		se = pick_next_entity(cfs_rq, NULL);
+-		set_next_entity(cfs_rq, se);
+-		cfs_rq = group_cfs_rq(se);
+-	} while (cfs_rq);
++	temp = *(hmp_attr->value);
++	if (hmp_attr->to_sysfs != NULL)
++		temp = hmp_attr->to_sysfs(temp);
+ 
+-	p = task_of(se);
++	return (ssize_t)sprintf(buf, "%d\n", temp);
++}
+ 
+-	if (hrtick_enabled(rq))
+-		hrtick_start_fair(rq, p);
++static ssize_t hmp_store(struct kobject *a, struct attribute *attr,
++				const char *buf, size_t count)
++{
++	int temp;
++	ssize_t ret = count;
++	struct hmp_global_attr *hmp_attr =
++		container_of(attr, struct hmp_global_attr, attr);
++	char *str = vmalloc(count + 1);
+ 
+-	return p;
++	if (str == NULL)
++		return -ENOMEM;
++	memcpy(str, buf, count);
++	str[count] = 0;
++	if (sscanf(str, "%d", &temp) < 1)
++		ret = -EINVAL;
++	else {
++		if (hmp_attr->from_sysfs != NULL)
++			temp = hmp_attr->from_sysfs(temp);
++		if (temp < 0)
++			ret = -EINVAL;
++		else
++			*(hmp_attr->value) = temp;
++	}
++	vfree(str);
++	return ret;
++}
+ 
+-idle:
+-	new_tasks = idle_balance(rq);
+-	/*
+-	 * Because idle_balance() releases (and re-acquires) rq->lock, it is
+-	 * possible for any higher priority task to appear. In that case we
+-	 * must re-start the pick_next_entity() loop.
+-	 */
+-	if (new_tasks < 0)
+-		return RETRY_TASK;
++static ssize_t hmp_print_domains(char *outbuf, int outbufsize)
++{
++	char buf[64];
++	const char nospace[] = "%s", space[] = " %s";
++	const char *fmt = nospace;
++	struct hmp_domain *domain;
++	struct list_head *pos;
++	int outpos = 0;
+ 
+-	if (new_tasks > 0)
+-		goto again;
++	list_for_each(pos, &hmp_domains) {
++		domain = list_entry(pos, struct hmp_domain, hmp_domains);
++		if (cpumask_scnprintf(buf, 64, &domain->possible_cpus)) {
++			outpos += sprintf(outbuf+outpos, fmt, buf);
++			fmt = space;
++		}
++	}
++	strcat(outbuf, "\n");
++	return outpos+1;
++}
+ 
+-	return NULL;
++#ifdef CONFIG_HMP_VARIABLE_SCALE
++static int hmp_period_tofrom_sysfs(int value)
++{
++	return (LOAD_AVG_PERIOD << HMP_VARIABLE_SCALE_SHIFT) / value;
+ }
++#endif
+ 
+-/*
+- * Account for a descheduled task:
+- */
+-static void put_prev_task_fair(struct rq *rq, struct task_struct *prev)
++/* max value for threshold is 1024 */
++static int hmp_theshold_from_sysfs(int value)
+ {
+-	struct sched_entity *se = &prev->se;
+-	struct cfs_rq *cfs_rq;
++	if (value > 1024)
++		return -1;
++	return value;
++}
+ 
+-	for_each_sched_entity(se) {
+-		cfs_rq = cfs_rq_of(se);
+-		put_prev_entity(cfs_rq, se);
+-	}
++/* toggle control is only 0,1 off/on */
++static int hmp_toggle_from_sysfs(int value)
++{
++	if (value < 0 || value > 1)
++		return -1;
++	return value;
+ }
+ 
+-/*
+- * sched_yield() is very simple
+- *
+- * The magic of dealing with the ->skip buddy is in pick_next_entity.
+- */
+-static void yield_task_fair(struct rq *rq)
++#ifdef CONFIG_SCHED_HMP_LITTLE_PACKING
++/* packing value must be non-negative */
++static int hmp_packing_from_sysfs(int value)
+ {
+-	struct task_struct *curr = rq->curr;
+-	struct cfs_rq *cfs_rq = task_cfs_rq(curr);
+-	struct sched_entity *se = &curr->se;
+-
+-	/*
+-	 * Are we the only task in the tree?
+-	 */
+-	if (unlikely(rq->nr_running == 1))
+-		return;
++	if (value < 0)
++		return -1;
++	return value;
++}
++#endif
+ 
+-	clear_buddies(cfs_rq, se);
++static void hmp_attr_add(
++	const char *name,
++	int *value,
++	int (*to_sysfs)(int),
++	int (*from_sysfs)(int),
++	ssize_t (*to_sysfs_text)(char *, int),
++	umode_t mode)
++{
++	int i = 0;
+ 
+-	if (curr->policy != SCHED_BATCH) {
+-		update_rq_clock(rq);
+-		/*
+-		 * Update run-time statistics of the 'current'.
+-		 */
+-		update_curr(cfs_rq);
+-		/*
+-		 * Tell update_rq_clock() that we've just updated,
+-		 * so we don't do microscopic update in schedule()
+-		 * and double the fastpath cost.
+-		 */
+-		 rq->skip_clock_update = 1;
++	while (hmp_data.attributes[i] != NULL) {
++		i++;
++		if (i >= HMP_DATA_SYSFS_MAX)
++			return;
+ 	}
+ 
+-	set_skip_buddy(se);
++	if (mode)
++		hmp_data.attr[i].attr.mode = mode;
++	else
++		hmp_data.attr[i].attr.mode = 0644;
++	hmp_data.attr[i].show = hmp_show;
++	hmp_data.attr[i].store = hmp_store;
++	hmp_data.attr[i].attr.name = name;
++	hmp_data.attr[i].value = value;
++	hmp_data.attr[i].to_sysfs = to_sysfs;
++	hmp_data.attr[i].from_sysfs = from_sysfs;
++	hmp_data.attr[i].to_sysfs_text = to_sysfs_text;
++	hmp_data.attributes[i] = &hmp_data.attr[i].attr;
++	hmp_data.attributes[i + 1] = NULL;
++}
++
++static int hmp_attr_init(void)
++{
++	int ret;
++
++	memset(&hmp_data, 0, sizeof(hmp_data));
++	hmp_attr_add("hmp_domains",
++		NULL,
++		NULL,
++		NULL,
++		hmp_print_domains,
++		0444);
++	hmp_attr_add("task_fork_on_bigcore",
++		&task_fork_on_bigcore,
++		NULL,
++		hmp_toggle_from_sysfs,
++		NULL,
++		0);
++	hmp_attr_add("up_threshold",
++		&hmp_up_threshold,
++		NULL,
++		hmp_theshold_from_sysfs,
++		NULL,
++		0);
++	hmp_attr_add("down_threshold",
++		&hmp_down_threshold,
++		NULL,
++		hmp_theshold_from_sysfs,
++		NULL,
++		0);
++#ifdef CONFIG_HMP_VARIABLE_SCALE
++	/* by default load_avg_period_ms == LOAD_AVG_PERIOD
++	 * meaning no change
++	 */
++	hmp_data.multiplier = hmp_period_tofrom_sysfs(LOAD_AVG_PERIOD);
++	hmp_attr_add("load_avg_period_ms",
++		&hmp_data.multiplier,
++		hmp_period_tofrom_sysfs,
++		hmp_period_tofrom_sysfs,
++		NULL,
++		0);
++#endif
++#ifdef CONFIG_HMP_FREQUENCY_INVARIANT_SCALE
++	/* default frequency-invariant scaling ON */
++	hmp_data.freqinvar_load_scale_enabled = 1;
++	hmp_attr_add("frequency_invariant_load_scale",
++		&hmp_data.freqinvar_load_scale_enabled,
++		NULL,
++		hmp_toggle_from_sysfs,
++		NULL,
++		0);
++#endif
++#ifdef CONFIG_SCHED_HMP_LITTLE_PACKING
++	hmp_attr_add("packing_enable",
++		&hmp_packing_enabled,
++		NULL,
++		hmp_toggle_from_sysfs,
++		NULL,
++		0);
++	hmp_attr_add("packing_limit",
++		&hmp_full_threshold,
++		NULL,
++		hmp_packing_from_sysfs,
++		NULL,
++		0);
++#endif
++	hmp_data.attr_group.name = "hmp";
++	hmp_data.attr_group.attrs = hmp_data.attributes;
++	ret = sysfs_create_group(kernel_kobj,
++		&hmp_data.attr_group);
++	return 0;
+ }
+-
+-static bool yield_to_task_fair(struct rq *rq, struct task_struct *p, bool preempt)
++late_initcall(hmp_attr_init);
++/*
++ * return the load of the lowest-loaded CPU in a given HMP domain
++ * min_cpu optionally points to an int to receive the CPU.
++ * affinity optionally points to a cpumask containing the
++ * CPUs to be considered. note:
++ *   + min_cpu = NR_CPUS only if no CPUs are in the set of
++ *     affinity && hmp_domain cpus
++ *   + min_cpu will always otherwise equal one of the CPUs in
++ *     the hmp domain
++ *   + when more than one CPU has the same load, the one which
++ *     is least-recently-disturbed by an HMP migration will be
++ *     selected
++ *   + if all CPUs are equally loaded or idle and the times are
++ *     all the same, the first in the set will be used
++ *   + if affinity is not set, cpu_online_mask is used
++ */
++static inline unsigned int hmp_domain_min_load(struct hmp_domain *hmpd,
++						int *min_cpu,
++						struct cpumask *affinity)
+ {
+-	struct sched_entity *se = &p->se;
+-
+-	/* throttled hierarchies are not runnable */
+-	if (!se->on_rq || throttled_hierarchy(cfs_rq_of(se)))
+-		return false;
++	int cpu;
++	int min_cpu_runnable_temp = NR_CPUS;
++	u64 min_target_last_migration = ULLONG_MAX;
++	u64 curr_last_migration;
++	unsigned long min_runnable_load = INT_MAX;
++	unsigned long contrib;
++	struct sched_avg *avg;
++	struct cpumask temp_cpumask;
++	/*
++	 * only look at CPUs allowed if specified,
++	 * otherwise look at all online CPUs in the
++	 * right HMP domain
++	 */
++	cpumask_and(&temp_cpumask, &hmpd->cpus,
++			affinity ? affinity : cpu_online_mask);
++
++	for_each_cpu_mask(cpu, temp_cpumask) {
++		avg = &cpu_rq(cpu)->avg;
++		/* used for both up and down migration */
++		curr_last_migration = avg->hmp_last_up_migration ?
++			avg->hmp_last_up_migration \
++			: avg->hmp_last_down_migration;
++
++		contrib = avg->load_avg_ratio;
++		/*
++		 * Consider a runqueue completely busy if there is any load
++		 * on it. Definitely not the best for overall fairness, but
++		 * does well in typical Android use cases.
++		 */
++		if (contrib)
++			contrib = 1023;
+ 
+-	/* Tell the scheduler that we'd really like pse to run next. */
+-	set_next_buddy(se);
++		if ((contrib < min_runnable_load) ||
++			(contrib == min_runnable_load &&
++			 curr_last_migration < min_target_last_migration)) {
++			/*
++			 * if the load is the same target the CPU with
++			 * the longest time since a migration.
++			 * This is to spread migration load between
++			 * members of a domain more evenly when the
++			 * domain is fully loaded
++			 */
++			min_runnable_load = contrib;
++			min_cpu_runnable_temp = cpu;
++			min_target_last_migration = curr_last_migration;
++		}
++	}
+ 
+-	yield_task_fair(rq);
++	if (min_cpu)
++		*min_cpu = min_cpu_runnable_temp;
+ 
+-	return true;
++	return min_runnable_load;
+ }
+ 
+-#ifdef CONFIG_SMP
+-/**************************************************
+- * Fair scheduling class load-balancing methods.
+- *
+- * BASICS
+- *
+- * The purpose of load-balancing is to achieve the same basic fairness the
+- * per-cpu scheduler provides, namely provide a proportional amount of compute
+- * time to each task. This is expressed in the following equation:
+- *
+- *   W_i,n/P_i == W_j,n/P_j for all i,j                               (1)
+- *
+- * Where W_i,n is the n-th weight average for cpu i. The instantaneous weight
+- * W_i,0 is defined as:
+- *
+- *   W_i,0 = \Sum_j w_i,j                                             (2)
+- *
+- * Where w_i,j is the weight of the j-th runnable task on cpu i. This weight
+- * is derived from the nice value as per prio_to_weight[].
+- *
+- * The weight average is an exponential decay average of the instantaneous
+- * weight:
+- *
+- *   W'_i,n = (2^n - 1) / 2^n * W_i,n + 1 / 2^n * W_i,0               (3)
+- *
+- * C_i is the compute capacity of cpu i, typically it is the
+- * fraction of 'recent' time available for SCHED_OTHER task execution. But it
+- * can also include other factors [XXX].
+- *
+- * To achieve this balance we define a measure of imbalance which follows
+- * directly from (1):
+- *
+- *   imb_i,j = max{ avg(W/C), W_i/C_i } - min{ avg(W/C), W_j/C_j }    (4)
+- *
+- * We them move tasks around to minimize the imbalance. In the continuous
+- * function space it is obvious this converges, in the discrete case we get
+- * a few fun cases generally called infeasible weight scenarios.
+- *
+- * [XXX expand on:
+- *     - infeasible weights;
+- *     - local vs global optima in the discrete case. ]
+- *
+- *
+- * SCHED DOMAINS
+- *
+- * In order to solve the imbalance equation (4), and avoid the obvious O(n^2)
+- * for all i,j solution, we create a tree of cpus that follows the hardware
+- * topology where each level pairs two lower groups (or better). This results
+- * in O(log n) layers. Furthermore we reduce the number of cpus going up the
+- * tree to only the first of the previous level and we decrease the frequency
+- * of load-balance at each level inv. proportional to the number of cpus in
+- * the groups.
+- *
+- * This yields:
+- *
+- *     log_2 n     1     n
+- *   \Sum       { --- * --- * 2^i } = O(n)                            (5)
+- *     i = 0      2^i   2^i
+- *                               `- size of each group
+- *         |         |     `- number of cpus doing load-balance
+- *         |         `- freq
+- *         `- sum over all levels
+- *
+- * Coupled with a limit on how many tasks we can migrate every balance pass,
+- * this makes (5) the runtime complexity of the balancer.
+- *
+- * An important property here is that each CPU is still (indirectly) connected
+- * to every other cpu in at most O(log n) steps:
+- *
+- * The adjacency matrix of the resulting graph is given by:
+- *
+- *             log_2 n     
+- *   A_i,j = \Union     (i % 2^k == 0) && i / 2^(k+1) == j / 2^(k+1)  (6)
+- *             k = 0
+- *
+- * And you'll find that:
+- *
+- *   A^(log_2 n)_i,j != 0  for all i,j                                (7)
+- *
+- * Showing there's indeed a path between every cpu in at most O(log n) steps.
+- * The task movement gives a factor of O(m), giving a convergence complexity
+- * of:
+- *
+- *   O(nm log n),  n := nr_cpus, m := nr_tasks                        (8)
+- *
+- *
+- * WORK CONSERVING
+- *
+- * In order to avoid CPUs going idle while there's still work to do, new idle
+- * balancing is more aggressive and has the newly idle cpu iterate up the domain
+- * tree itself instead of relying on other CPUs to bring it work.
+- *
+- * This adds some complexity to both (5) and (8) but it reduces the total idle
+- * time.
+- *
+- * [XXX more?]
+- *
+- *
+- * CGROUPS
+- *
+- * Cgroups make a horror show out of (2), instead of a simple sum we get:
+- *
+- *                                s_k,i
+- *   W_i,0 = \Sum_j \Prod_k w_k * -----                               (9)
+- *                                 S_k
+- *
+- * Where
+- *
+- *   s_k,i = \Sum_j w_i,j,k  and  S_k = \Sum_i s_k,i                 (10)
+- *
+- * w_i,j,k is the weight of the j-th runnable task in the k-th cgroup on cpu i.
+- *
+- * The big problem is S_k, its a global sum needed to compute a local (W_i)
+- * property.
+- *
+- * [XXX write more on how we solve this.. _after_ merging pjt's patches that
+- *      rewrite all of this once again.]
+- */ 
++/*
++ * Calculate the task starvation
++ * This is the ratio of actually running time vs. runnable time.
++ * If the two are equal the task is getting the cpu time it needs or
++ * it is alone on the cpu and the cpu is fully utilized.
++ */
++static inline unsigned int hmp_task_starvation(struct sched_entity *se)
++{
++	u32 starvation;
+ 
+-static unsigned long __read_mostly max_load_balance_interval = HZ/10;
++	starvation = se->avg.usage_avg_sum * scale_load_down(NICE_0_LOAD);
++	starvation /= (se->avg.runnable_avg_sum + 1);
+ 
+-enum fbq_type { regular, remote, all };
++	return scale_load(starvation);
++}
+ 
+-#define LBF_ALL_PINNED	0x01
+-#define LBF_NEED_BREAK	0x02
+-#define LBF_DST_PINNED  0x04
+-#define LBF_SOME_PINNED	0x08
++static inline unsigned int hmp_offload_down(int cpu, struct sched_entity *se)
++{
++	int min_usage;
++	int dest_cpu = NR_CPUS;
+ 
+-struct lb_env {
+-	struct sched_domain	*sd;
++	if (hmp_cpu_is_slowest(cpu))
++		return NR_CPUS;
+ 
+-	struct rq		*src_rq;
+-	int			src_cpu;
++	/* Is there an idle CPU in the current domain */
++	min_usage = hmp_domain_min_load(hmp_cpu_domain(cpu), NULL, NULL);
++	if (min_usage == 0) {
++		trace_sched_hmp_offload_abort(cpu, min_usage, "load");
++		return NR_CPUS;
++	}
+ 
+-	int			dst_cpu;
+-	struct rq		*dst_rq;
++	/* Is the task alone on the cpu? */
++	if (cpu_rq(cpu)->cfs.h_nr_running < 2) {
++		trace_sched_hmp_offload_abort(cpu,
++			cpu_rq(cpu)->cfs.h_nr_running, "nr_running");
++		return NR_CPUS;
++	}
+ 
+-	struct cpumask		*dst_grpmask;
+-	int			new_dst_cpu;
+-	enum cpu_idle_type	idle;
+-	long			imbalance;
+-	/* The set of CPUs under consideration for load-balancing */
+-	struct cpumask		*cpus;
++	/* Is the task actually starving? */
++	/* >=25% ratio running/runnable = starving */
++	if (hmp_task_starvation(se) > 768) {
++		trace_sched_hmp_offload_abort(cpu, hmp_task_starvation(se),
++			"starvation");
++		return NR_CPUS;
++	}
+ 
+-	unsigned int		flags;
++	/* Does the slower domain have any idle CPUs? */
++	min_usage = hmp_domain_min_load(hmp_slower_domain(cpu), &dest_cpu,
++			tsk_cpus_allowed(task_of(se)));
+ 
+-	unsigned int		loop;
+-	unsigned int		loop_break;
+-	unsigned int		loop_max;
++	if (min_usage == 0) {
++		trace_sched_hmp_offload_succeed(cpu, dest_cpu);
++		return dest_cpu;
++	} else
++		trace_sched_hmp_offload_abort(cpu, min_usage, "slowdomain");
++	return NR_CPUS;
++}
++#endif /* CONFIG_SCHED_HMP */
+ 
+-	enum fbq_type		fbq_type;
+-	struct list_head	tasks;
+-};
+ 
+ /*
+- * Is this task likely cache-hot:
++ * select_task_rq_fair: Select target runqueue for the waking task in domains
++ * that have the 'sd_flag' flag set. In practice, this is SD_BALANCE_WAKE,
++ * SD_BALANCE_FORK, or SD_BALANCE_EXEC.
++ *
++ * Balances load by selecting the idlest cpu in the idlest group, or under
++ * certain conditions an idle sibling cpu if the domain has SD_WAKE_AFFINE set.
++ *
++ * Returns the target cpu number.
++ *
++ * preempt must be disabled.
+  */
+-static int task_hot(struct task_struct *p, struct lb_env *env)
++static int
++select_task_rq_fair(struct task_struct *p, int prev_cpu, int sd_flag, int wake_flags)
+ {
+-	s64 delta;
+-
+-	lockdep_assert_held(&env->src_rq->lock);
++	struct sched_domain *tmp, *affine_sd = NULL, *sd = NULL;
++	int cpu = smp_processor_id();
++	int new_cpu = cpu;
++	int want_affine = 0;
++	int sync = wake_flags & WF_SYNC;
+ 
+-	if (p->sched_class != &fair_sched_class)
+-		return 0;
++	if (p->nr_cpus_allowed == 1)
++		return prev_cpu;
+ 
+-	if (unlikely(p->policy == SCHED_IDLE))
+-		return 0;
++	if (sd_flag & SD_BALANCE_WAKE)
++		want_affine = cpumask_test_cpu(cpu, tsk_cpus_allowed(p));
+ 
+-	/*
+-	 * Buddy candidates are cache hot:
+-	 */
+-	if (sched_feat(CACHE_HOT_BUDDY) && env->dst_rq->nr_running &&
+-			(&p->se == cfs_rq_of(&p->se)->next ||
+-			 &p->se == cfs_rq_of(&p->se)->last))
+-		return 1;
++	rcu_read_lock();
++	for_each_domain(cpu, tmp) {
++		if (!(tmp->flags & SD_LOAD_BALANCE))
++			continue;
+ 
+-	if (sysctl_sched_migration_cost == -1)
+-		return 1;
+-	if (sysctl_sched_migration_cost == 0)
+-		return 0;
++		/*
++		 * If both cpu and prev_cpu are part of this domain,
++		 * cpu is a valid SD_WAKE_AFFINE target.
++		 */
++		if (want_affine && (tmp->flags & SD_WAKE_AFFINE) &&
++		    cpumask_test_cpu(prev_cpu, sched_domain_span(tmp))) {
++			affine_sd = tmp;
++			break;
++		}
+ 
+-	delta = rq_clock_task(env->src_rq) - p->se.exec_start;
++		if (tmp->flags & sd_flag)
++			sd = tmp;
++	}
+ 
+-	return delta < (s64)sysctl_sched_migration_cost;
+-}
++	if (affine_sd && cpu != prev_cpu && wake_affine(affine_sd, p, sync))
++		prev_cpu = cpu;
+ 
+-#ifdef CONFIG_NUMA_BALANCING
+-/* Returns true if the destination node has incurred more faults */
+-static bool migrate_improves_locality(struct task_struct *p, struct lb_env *env)
+-{
+-	struct numa_group *numa_group = rcu_dereference(p->numa_group);
+-	int src_nid, dst_nid;
++#ifdef CONFIG_SCHED_HMP
++	/* always put non-kernel forking tasks on a big domain */
++	if (unlikely(sd_flag & SD_BALANCE_FORK)
++			&& hmp_task_should_forkboost(p)) {
++		new_cpu = hmp_select_faster_cpu(p, prev_cpu);
++		if (new_cpu != NR_CPUS) {
++			hmp_next_up_delay(&p->se, new_cpu);
++			return new_cpu;
++		}
++		/* failed to perform HMP fork balance, use normal balance */
++		new_cpu = cpu;
++	}
++#endif
+ 
+-	if (!sched_feat(NUMA_FAVOUR_HIGHER) || !p->numa_faults_memory ||
+-	    !(env->sd->flags & SD_NUMA)) {
+-		return false;
++	if (sd_flag & SD_BALANCE_WAKE) {
++		new_cpu = select_idle_sibling(p, prev_cpu);
++		goto unlock;
+ 	}
+ 
+-	src_nid = cpu_to_node(env->src_cpu);
+-	dst_nid = cpu_to_node(env->dst_cpu);
++	while (sd) {
++		struct sched_group *group;
++		int weight;
+ 
+-	if (src_nid == dst_nid)
+-		return false;
++		if (!(sd->flags & sd_flag)) {
++			sd = sd->child;
++			continue;
++		}
+ 
+-	if (numa_group) {
+-		/* Task is already in the group's interleave set. */
+-		if (node_isset(src_nid, numa_group->active_nodes))
+-			return false;
++		group = find_idlest_group(sd, p, cpu, sd_flag);
++		if (!group) {
++			sd = sd->child;
++			continue;
++		}
+ 
+-		/* Task is moving into the group's interleave set. */
+-		if (node_isset(dst_nid, numa_group->active_nodes))
+-			return true;
++		new_cpu = find_idlest_cpu(group, p, cpu);
++		if (new_cpu == -1 || new_cpu == cpu) {
++			/* Now try balancing at a lower domain level of cpu */
++			sd = sd->child;
++			continue;
++		}
+ 
+-		return group_faults(p, dst_nid) > group_faults(p, src_nid);
++		/* Now try balancing at a lower domain level of new_cpu */
++		cpu = new_cpu;
++		weight = sd->span_weight;
++		sd = NULL;
++		for_each_domain(cpu, tmp) {
++			if (weight <= tmp->span_weight)
++				break;
++			if (tmp->flags & sd_flag)
++				sd = tmp;
++		}
++		/* while loop will break here if sd == NULL */
+ 	}
++unlock:
++	rcu_read_unlock();
+ 
+-	/* Encourage migration to the preferred node. */
+-	if (dst_nid == p->numa_preferred_nid)
+-		return true;
++#ifdef CONFIG_SCHED_HMP
++	prev_cpu = task_cpu(p);
+ 
+-	return task_faults(p, dst_nid) > task_faults(p, src_nid);
+-}
++	if (hmp_up_migration(prev_cpu, &new_cpu, &p->se)) {
++		hmp_next_up_delay(&p->se, new_cpu);
++		trace_sched_hmp_migrate(p, new_cpu, HMP_MIGRATE_WAKEUP);
++		return new_cpu;
++	}
++	if (hmp_down_migration(prev_cpu, &p->se)) {
++#ifdef CONFIG_SCHED_HMP_LITTLE_PACKING
++		new_cpu = hmp_best_little_cpu(p, prev_cpu);
++#else
++		new_cpu = hmp_select_slower_cpu(p, prev_cpu);
++#endif
++		/*
++		 * we might have no suitable CPU
++		 * in which case new_cpu == NR_CPUS
++		 */
++		if (new_cpu < NR_CPUS && new_cpu != prev_cpu) {
++			hmp_next_down_delay(&p->se, new_cpu);
++			trace_sched_hmp_migrate(p, new_cpu, HMP_MIGRATE_WAKEUP);
++			return new_cpu;
++		}
++	}
++	/* Make sure that the task stays in its previous hmp domain */
++	if (!cpumask_test_cpu(new_cpu, &hmp_cpu_domain(prev_cpu)->cpus))
++		return prev_cpu;
++#endif
+ 
++	return new_cpu;
++}
+ 
+-static bool migrate_degrades_locality(struct task_struct *p, struct lb_env *env)
++/*
++ * Called immediately before a task is migrated to a new cpu; task_cpu(p) and
++ * cfs_rq_of(p) references at time of call are still valid and identify the
++ * previous cpu.  However, the caller only guarantees p->pi_lock is held; no
++ * other assumptions, including the state of rq->lock, should be made.
++ */
++static void
++migrate_task_rq_fair(struct task_struct *p, int next_cpu)
+ {
+-	struct numa_group *numa_group = rcu_dereference(p->numa_group);
+-	int src_nid, dst_nid;
++	struct sched_entity *se = &p->se;
++	struct cfs_rq *cfs_rq = cfs_rq_of(se);
+ 
+-	if (!sched_feat(NUMA) || !sched_feat(NUMA_RESIST_LOWER))
+-		return false;
++	/*
++	 * Load tracking: accumulate removed load so that it can be processed
++	 * when we next update owning cfs_rq under rq->lock.  Tasks contribute
++	 * to blocked load iff they have a positive decay-count.  It can never
++	 * be negative here since on-rq tasks have decay-count == 0.
++	 */
++	if (se->avg.decay_count) {
++		/*
++		 * If we migrate a sleeping task away from a CPU
++		 * which has the tick stopped, then both the clock_task
++		 * and decay_counter will be out of date for that CPU
++		 * and we will not decay load correctly.
++		 */
++		if (!se->on_rq && nohz_test_cpu(task_cpu(p))) {
++			struct rq *rq = cpu_rq(task_cpu(p));
++			unsigned long flags;
++			/*
++			 * Current CPU cannot be holding rq->lock in this
++			 * circumstance, but another might be. We must hold
++			 * rq->lock before we go poking around in its clocks
++			 */
++			raw_spin_lock_irqsave(&rq->lock, flags);
++			update_rq_clock(rq);
++			update_cfs_rq_blocked_load(cfs_rq, 0);
++			raw_spin_unlock_irqrestore(&rq->lock, flags);
++		}
++		se->avg.decay_count = -__synchronize_entity_decay(se);
++		atomic_long_add(se->avg.load_avg_contrib,
++						&cfs_rq->removed_load);
++	}
+ 
+-	if (!p->numa_faults_memory || !(env->sd->flags & SD_NUMA))
+-		return false;
++	/* We have migrated, no longer consider this task hot */
++	se->exec_start = 0;
++}
++#endif /* CONFIG_SMP */
+ 
+-	src_nid = cpu_to_node(env->src_cpu);
+-	dst_nid = cpu_to_node(env->dst_cpu);
++static unsigned long
++wakeup_gran(struct sched_entity *curr, struct sched_entity *se)
++{
++	unsigned long gran = sysctl_sched_wakeup_granularity;
+ 
+-	if (src_nid == dst_nid)
+-		return false;
++	/*
++	 * Since its curr running now, convert the gran from real-time
++	 * to virtual-time in his units.
++	 *
++	 * By using 'se' instead of 'curr' we penalize light tasks, so
++	 * they get preempted easier. That is, if 'se' < 'curr' then
++	 * the resulting gran will be larger, therefore penalizing the
++	 * lighter, if otoh 'se' > 'curr' then the resulting gran will
++	 * be smaller, again penalizing the lighter task.
++	 *
++	 * This is especially important for buddies when the leftmost
++	 * task is higher priority than the buddy.
++	 */
++	return calc_delta_fair(gran, se);
++}
+ 
+-	if (numa_group) {
+-		/* Task is moving within/into the group's interleave set. */
+-		if (node_isset(dst_nid, numa_group->active_nodes))
+-			return false;
++/*
++ * Should 'se' preempt 'curr'.
++ *
++ *             |s1
++ *        |s2
++ *   |s3
++ *         g
++ *      |<--->|c
++ *
++ *  w(c, s1) = -1
++ *  w(c, s2) =  0
++ *  w(c, s3) =  1
++ *
++ */
++static int
++wakeup_preempt_entity(struct sched_entity *curr, struct sched_entity *se)
++{
++	s64 gran, vdiff = curr->vruntime - se->vruntime;
+ 
+-		/* Task is moving out of the group's interleave set. */
+-		if (node_isset(src_nid, numa_group->active_nodes))
+-			return true;
++	if (vdiff <= 0)
++		return -1;
+ 
+-		return group_faults(p, dst_nid) < group_faults(p, src_nid);
+-	}
++	gran = wakeup_gran(curr, se);
++	if (vdiff > gran)
++		return 1;
+ 
+-	/* Migrating away from the preferred node is always bad. */
+-	if (src_nid == p->numa_preferred_nid)
+-		return true;
++	return 0;
++}
+ 
+-	return task_faults(p, dst_nid) < task_faults(p, src_nid);
++static void set_last_buddy(struct sched_entity *se)
++{
++	if (entity_is_task(se) && unlikely(task_of(se)->policy == SCHED_IDLE))
++		return;
++
++	for_each_sched_entity(se)
++		cfs_rq_of(se)->last = se;
+ }
+ 
+-#else
+-static inline bool migrate_improves_locality(struct task_struct *p,
+-					     struct lb_env *env)
++static void set_next_buddy(struct sched_entity *se)
+ {
+-	return false;
++	if (entity_is_task(se) && unlikely(task_of(se)->policy == SCHED_IDLE))
++		return;
++
++	for_each_sched_entity(se)
++		cfs_rq_of(se)->next = se;
+ }
+ 
+-static inline bool migrate_degrades_locality(struct task_struct *p,
+-					     struct lb_env *env)
++static void set_skip_buddy(struct sched_entity *se)
+ {
+-	return false;
++	for_each_sched_entity(se)
++		cfs_rq_of(se)->skip = se;
+ }
+-#endif
+ 
+ /*
+- * can_migrate_task - may task p from runqueue rq be migrated to this_cpu?
++ * Preempt the current task with a newly woken task if needed:
+  */
+-static
+-int can_migrate_task(struct task_struct *p, struct lb_env *env)
++static void check_preempt_wakeup(struct rq *rq, struct task_struct *p, int wake_flags)
+ {
+-	int tsk_cache_hot = 0;
++	struct task_struct *curr = rq->curr;
++	struct sched_entity *se = &curr->se, *pse = &p->se;
++	struct cfs_rq *cfs_rq = task_cfs_rq(curr);
++	int scale = cfs_rq->nr_running >= sched_nr_latency;
++	int next_buddy_marked = 0;
+ 
+-	lockdep_assert_held(&env->src_rq->lock);
++	if (unlikely(se == pse))
++		return;
+ 
+ 	/*
+-	 * We do not migrate tasks that are:
+-	 * 1) throttled_lb_pair, or
+-	 * 2) cannot be migrated to this CPU due to cpus_allowed, or
+-	 * 3) running (obviously), or
+-	 * 4) are cache-hot on their current CPU.
++	 * This is possible from callers such as attach_tasks(), in which we
++	 * unconditionally check_prempt_curr() after an enqueue (which may have
++	 * lead to a throttle).  This both saves work and prevents false
++	 * next-buddy nomination below.
+ 	 */
+-	if (throttled_lb_pair(task_group(p), env->src_cpu, env->dst_cpu))
+-		return 0;
+-
+-	if (!cpumask_test_cpu(env->dst_cpu, tsk_cpus_allowed(p))) {
+-		int cpu;
+-
+-		schedstat_inc(p, se.statistics.nr_failed_migrations_affine);
++	if (unlikely(throttled_hierarchy(cfs_rq_of(pse))))
++		return;
+ 
+-		env->flags |= LBF_SOME_PINNED;
++	if (sched_feat(NEXT_BUDDY) && scale && !(wake_flags & WF_FORK)) {
++		set_next_buddy(pse);
++		next_buddy_marked = 1;
++	}
+ 
+-		/*
+-		 * Remember if this task can be migrated to any other cpu in
+-		 * our sched_group. We may want to revisit it if we couldn't
+-		 * meet load balance goals by pulling other tasks on src_cpu.
+-		 *
+-		 * Also avoid computing new_dst_cpu if we have already computed
+-		 * one in current iteration.
+-		 */
+-		if (!env->dst_grpmask || (env->flags & LBF_DST_PINNED))
+-			return 0;
+-
+-		/* Prevent to re-select dst_cpu via env's cpus */
+-		for_each_cpu_and(cpu, env->dst_grpmask, env->cpus) {
+-			if (cpumask_test_cpu(cpu, tsk_cpus_allowed(p))) {
+-				env->flags |= LBF_DST_PINNED;
+-				env->new_dst_cpu = cpu;
+-				break;
+-			}
+-		}
+-
+-		return 0;
+-	}
+-
+-	/* Record that we found atleast one task that could run on dst_cpu */
+-	env->flags &= ~LBF_ALL_PINNED;
++	/*
++	 * We can come here with TIF_NEED_RESCHED already set from new task
++	 * wake up path.
++	 *
++	 * Note: this also catches the edge-case of curr being in a throttled
++	 * group (e.g. via set_curr_task), since update_curr() (in the
++	 * enqueue of curr) will have resulted in resched being set.  This
++	 * prevents us from potentially nominating it as a false LAST_BUDDY
++	 * below.
++	 */
++	if (test_tsk_need_resched(curr))
++		return;
+ 
+-	if (task_running(env->src_rq, p)) {
+-		schedstat_inc(p, se.statistics.nr_failed_migrations_running);
+-		return 0;
+-	}
++	/* Idle tasks are by definition preempted by non-idle tasks. */
++	if (unlikely(curr->policy == SCHED_IDLE) &&
++	    likely(p->policy != SCHED_IDLE))
++		goto preempt;
+ 
+ 	/*
+-	 * Aggressive migration if:
+-	 * 1) destination numa is preferred
+-	 * 2) task is cache cold, or
+-	 * 3) too many balance attempts have failed.
++	 * Batch and idle tasks do not preempt non-idle tasks (their preemption
++	 * is driven by the tick):
+ 	 */
+-	tsk_cache_hot = task_hot(p, env);
+-	if (!tsk_cache_hot)
+-		tsk_cache_hot = migrate_degrades_locality(p, env);
++	if (unlikely(p->policy != SCHED_NORMAL) || !sched_feat(WAKEUP_PREEMPTION))
++		return;
+ 
+-	if (migrate_improves_locality(p, env) || !tsk_cache_hot ||
+-	    env->sd->nr_balance_failed > env->sd->cache_nice_tries) {
+-		if (tsk_cache_hot) {
+-			schedstat_inc(env->sd, lb_hot_gained[env->idle]);
+-			schedstat_inc(p, se.statistics.nr_forced_migrations);
+-		}
+-		return 1;
++	find_matching_se(&se, &pse);
++	update_curr(cfs_rq_of(se));
++	BUG_ON(!pse);
++	if (wakeup_preempt_entity(se, pse) == 1) {
++		/*
++		 * Bias pick_next to pick the sched entity that is
++		 * triggering this preemption.
++		 */
++		if (!next_buddy_marked)
++			set_next_buddy(pse);
++		goto preempt;
+ 	}
+ 
+-	schedstat_inc(p, se.statistics.nr_failed_migrations_hot);
+-	return 0;
+-}
++	return;
+ 
+-/*
+- * detach_task() -- detach the task for the migration specified in env
+- */
+-static void detach_task(struct task_struct *p, struct lb_env *env)
+-{
+-	lockdep_assert_held(&env->src_rq->lock);
++preempt:
++	resched_curr(rq);
++	/*
++	 * Only set the backward buddy when the current task is still
++	 * on the rq. This can happen when a wakeup gets interleaved
++	 * with schedule on the ->pre_schedule() or idle_balance()
++	 * point, either of which can * drop the rq lock.
++	 *
++	 * Also, during early boot the idle thread is in the fair class,
++	 * for obvious reasons its a bad idea to schedule back to it.
++	 */
++	if (unlikely(!se->on_rq || curr == rq->idle))
++		return;
+ 
+-	deactivate_task(env->src_rq, p, 0);
+-	p->on_rq = TASK_ON_RQ_MIGRATING;
+-	set_task_cpu(p, env->dst_cpu);
++	if (sched_feat(LAST_BUDDY) && scale && entity_is_task(se))
++		set_last_buddy(se);
+ }
+ 
+-/*
+- * detach_one_task() -- tries to dequeue exactly one task from env->src_rq, as
+- * part of active balancing operations within "domain".
+- *
+- * Returns a task if successful and NULL otherwise.
+- */
+-static struct task_struct *detach_one_task(struct lb_env *env)
++static struct task_struct *
++pick_next_task_fair(struct rq *rq, struct task_struct *prev)
+ {
+-	struct task_struct *p, *n;
++	struct cfs_rq *cfs_rq = &rq->cfs;
++	struct sched_entity *se;
++	struct task_struct *p;
++	int new_tasks;
+ 
+-	lockdep_assert_held(&env->src_rq->lock);
++again:
++#ifdef CONFIG_FAIR_GROUP_SCHED
++	if (!cfs_rq->nr_running)
++		goto idle;
+ 
+-	list_for_each_entry_safe(p, n, &env->src_rq->cfs_tasks, se.group_node) {
+-		if (!can_migrate_task(p, env))
+-			continue;
++	if (prev->sched_class != &fair_sched_class)
++		goto simple;
+ 
+-		detach_task(p, env);
++	/*
++	 * Because of the set_next_buddy() in dequeue_task_fair() it is rather
++	 * likely that a next task is from the same cgroup as the current.
++	 *
++	 * Therefore attempt to avoid putting and setting the entire cgroup
++	 * hierarchy, only change the part that actually changes.
++	 */
++
++	do {
++		struct sched_entity *curr = cfs_rq->curr;
+ 
+ 		/*
+-		 * Right now, this is only the second place where
+-		 * lb_gained[env->idle] is updated (other is detach_tasks)
+-		 * so we can safely collect stats here rather than
+-		 * inside detach_tasks().
++		 * Since we got here without doing put_prev_entity() we also
++		 * have to consider cfs_rq->curr. If it is still a runnable
++		 * entity, update_curr() will update its vruntime, otherwise
++		 * forget we've ever seen it.
+ 		 */
+-		schedstat_inc(env->sd, lb_gained[env->idle]);
+-		return p;
+-	}
+-	return NULL;
+-}
+-
+-static const unsigned int sched_nr_migrate_break = 32;
++		if (curr && curr->on_rq)
++			update_curr(cfs_rq);
++		else
++			curr = NULL;
+ 
+-/*
+- * detach_tasks() -- tries to detach up to imbalance weighted load from
+- * busiest_rq, as part of a balancing operation within domain "sd".
+- *
+- * Returns number of detached tasks if successful and 0 otherwise.
+- */
+-static int detach_tasks(struct lb_env *env)
+-{
+-	struct list_head *tasks = &env->src_rq->cfs_tasks;
+-	struct task_struct *p;
+-	unsigned long load;
+-	int detached = 0;
++		/*
++		 * This call to check_cfs_rq_runtime() will do the throttle and
++		 * dequeue its entity in the parent(s). Therefore the 'simple'
++		 * nr_running test will indeed be correct.
++		 */
++		if (unlikely(check_cfs_rq_runtime(cfs_rq)))
++			goto simple;
+ 
+-	lockdep_assert_held(&env->src_rq->lock);
++		se = pick_next_entity(cfs_rq, curr);
++		cfs_rq = group_cfs_rq(se);
++	} while (cfs_rq);
+ 
+-	if (env->imbalance <= 0)
+-		return 0;
++	p = task_of(se);
+ 
+-	while (!list_empty(tasks)) {
+-		p = list_first_entry(tasks, struct task_struct, se.group_node);
++	/*
++	 * Since we haven't yet done put_prev_entity and if the selected task
++	 * is a different task than we started out with, try and touch the
++	 * least amount of cfs_rqs.
++	 */
++	if (prev != p) {
++		struct sched_entity *pse = &prev->se;
+ 
+-		env->loop++;
+-		/* We've more or less seen every task there is, call it quits */
+-		if (env->loop > env->loop_max)
+-			break;
++		while (!(cfs_rq = is_same_group(se, pse))) {
++			int se_depth = se->depth;
++			int pse_depth = pse->depth;
+ 
+-		/* take a breather every nr_migrate tasks */
+-		if (env->loop > env->loop_break) {
+-			env->loop_break += sched_nr_migrate_break;
+-			env->flags |= LBF_NEED_BREAK;
+-			break;
++			if (se_depth <= pse_depth) {
++				put_prev_entity(cfs_rq_of(pse), pse);
++				pse = parent_entity(pse);
++			}
++			if (se_depth >= pse_depth) {
++				set_next_entity(cfs_rq_of(se), se);
++				se = parent_entity(se);
++			}
+ 		}
+ 
+-		if (!can_migrate_task(p, env))
+-			goto next;
++		put_prev_entity(cfs_rq, pse);
++		set_next_entity(cfs_rq, se);
++	}
+ 
+-		load = task_h_load(p);
++	if (hrtick_enabled(rq))
++		hrtick_start_fair(rq, p);
+ 
+-		if (sched_feat(LB_MIN) && load < 16 && !env->sd->nr_balance_failed)
+-			goto next;
++	return p;
++simple:
++	cfs_rq = &rq->cfs;
++#endif
+ 
+-		if ((load / 2) > env->imbalance)
+-			goto next;
++	if (!cfs_rq->nr_running)
++		goto idle;
+ 
+-		detach_task(p, env);
+-		list_add(&p->se.group_node, &env->tasks);
++	put_prev_task(rq, prev);
+ 
+-		detached++;
+-		env->imbalance -= load;
++	do {
++		se = pick_next_entity(cfs_rq, NULL);
++		set_next_entity(cfs_rq, se);
++		cfs_rq = group_cfs_rq(se);
++	} while (cfs_rq);
+ 
+-#ifdef CONFIG_PREEMPT
+-		/*
+-		 * NEWIDLE balancing is a source of latency, so preemptible
+-		 * kernels will stop after the first task is detached to minimize
+-		 * the critical section.
+-		 */
+-		if (env->idle == CPU_NEWLY_IDLE)
+-			break;
+-#endif
++	p = task_of(se);
+ 
+-		/*
+-		 * We only want to steal up to the prescribed amount of
+-		 * weighted load.
+-		 */
+-		if (env->imbalance <= 0)
+-			break;
++	if (hrtick_enabled(rq))
++		hrtick_start_fair(rq, p);
+ 
+-		continue;
+-next:
+-		list_move_tail(&p->se.group_node, tasks);
+-	}
++	return p;
+ 
++idle:
++	new_tasks = idle_balance(rq);
+ 	/*
+-	 * Right now, this is one of only two places we collect this stat
+-	 * so we can safely collect detach_one_task() stats here rather
+-	 * than inside detach_one_task().
++	 * Because idle_balance() releases (and re-acquires) rq->lock, it is
++	 * possible for any higher priority task to appear. In that case we
++	 * must re-start the pick_next_entity() loop.
+ 	 */
+-	schedstat_add(env->sd, lb_gained[env->idle], detached);
+-
+-	return detached;
+-}
+-
+-/*
+- * attach_task() -- attach the task detached by detach_task() to its new rq.
+- */
+-static void attach_task(struct rq *rq, struct task_struct *p)
+-{
+-	lockdep_assert_held(&rq->lock);
++	if (new_tasks < 0)
++		return RETRY_TASK;
+ 
+-	BUG_ON(task_rq(p) != rq);
+-	p->on_rq = TASK_ON_RQ_QUEUED;
+-	activate_task(rq, p, 0);
+-	check_preempt_curr(rq, p, 0);
+-}
++	if (new_tasks > 0)
++		goto again;
+ 
+-/*
+- * attach_one_task() -- attaches the task returned from detach_one_task() to
+- * its new rq.
+- */
+-static void attach_one_task(struct rq *rq, struct task_struct *p)
+-{
+-	raw_spin_lock(&rq->lock);
+-	attach_task(rq, p);
+-	raw_spin_unlock(&rq->lock);
++	return NULL;
+ }
+ 
+ /*
+- * attach_tasks() -- attaches all tasks detached by detach_tasks() to their
+- * new rq.
++ * Account for a descheduled task:
+  */
+-static void attach_tasks(struct lb_env *env)
++static void put_prev_task_fair(struct rq *rq, struct task_struct *prev)
+ {
+-	struct list_head *tasks = &env->tasks;
+-	struct task_struct *p;
+-
+-	raw_spin_lock(&env->dst_rq->lock);
+-
+-	while (!list_empty(tasks)) {
+-		p = list_first_entry(tasks, struct task_struct, se.group_node);
+-		list_del_init(&p->se.group_node);
++	struct sched_entity *se = &prev->se;
++	struct cfs_rq *cfs_rq;
+ 
+-		attach_task(env->dst_rq, p);
++	for_each_sched_entity(se) {
++		cfs_rq = cfs_rq_of(se);
++		put_prev_entity(cfs_rq, se);
+ 	}
+-
+-	raw_spin_unlock(&env->dst_rq->lock);
+ }
+ 
+-#ifdef CONFIG_FAIR_GROUP_SCHED
+ /*
+- * update tg->load_weight by folding this cpu's load_avg
++ * sched_yield() is very simple
++ *
++ * The magic of dealing with the ->skip buddy is in pick_next_entity.
+  */
+-static void __update_blocked_averages_cpu(struct task_group *tg, int cpu)
++static void yield_task_fair(struct rq *rq)
+ {
+-	struct sched_entity *se = tg->se[cpu];
+-	struct cfs_rq *cfs_rq = tg->cfs_rq[cpu];
++	struct task_struct *curr = rq->curr;
++	struct cfs_rq *cfs_rq = task_cfs_rq(curr);
++	struct sched_entity *se = &curr->se;
+ 
+-	/* throttled entities do not contribute to load */
+-	if (throttled_hierarchy(cfs_rq))
++	/*
++	 * Are we the only task in the tree?
++	 */
++	if (unlikely(rq->nr_running == 1))
+ 		return;
+ 
+-	update_cfs_rq_blocked_load(cfs_rq, 1);
++	clear_buddies(cfs_rq, se);
+ 
+-	if (se) {
+-		update_entity_load_avg(se, 1);
++	if (curr->policy != SCHED_BATCH) {
++		update_rq_clock(rq);
+ 		/*
+-		 * We pivot on our runnable average having decayed to zero for
+-		 * list removal.  This generally implies that all our children
+-		 * have also been removed (modulo rounding error or bandwidth
+-		 * control); however, such cases are rare and we can fix these
+-		 * at enqueue.
+-		 *
+-		 * TODO: fix up out-of-order children on enqueue.
++		 * Update run-time statistics of the 'current'.
+ 		 */
+-		if (!se->avg.runnable_avg_sum && !cfs_rq->nr_running)
+-			list_del_leaf_cfs_rq(cfs_rq);
+-	} else {
+-		struct rq *rq = rq_of(cfs_rq);
+-		update_rq_runnable_avg(rq, rq->nr_running);
+-	}
+-}
+-
+-static void update_blocked_averages(int cpu)
+-{
+-	struct rq *rq = cpu_rq(cpu);
+-	struct cfs_rq *cfs_rq;
+-	unsigned long flags;
+-
+-	raw_spin_lock_irqsave(&rq->lock, flags);
+-	update_rq_clock(rq);
+-	/*
+-	 * Iterates the task_group tree in a bottom up fashion, see
+-	 * list_add_leaf_cfs_rq() for details.
+-	 */
+-	for_each_leaf_cfs_rq(rq, cfs_rq) {
++		update_curr(cfs_rq);
+ 		/*
+-		 * Note: We may want to consider periodically releasing
+-		 * rq->lock about these updates so that creating many task
+-		 * groups does not result in continually extending hold time.
++		 * Tell update_rq_clock() that we've just updated,
++		 * so we don't do microscopic update in schedule()
++		 * and double the fastpath cost.
+ 		 */
+-		__update_blocked_averages_cpu(cfs_rq->tg, rq->cpu);
+-	}
+-
+-	raw_spin_unlock_irqrestore(&rq->lock, flags);
+-}
+-
+-/*
+- * Compute the hierarchical load factor for cfs_rq and all its ascendants.
+- * This needs to be done in a top-down fashion because the load of a child
+- * group is a fraction of its parents load.
+- */
+-static void update_cfs_rq_h_load(struct cfs_rq *cfs_rq)
+-{
+-	struct rq *rq = rq_of(cfs_rq);
+-	struct sched_entity *se = cfs_rq->tg->se[cpu_of(rq)];
+-	unsigned long now = jiffies;
+-	unsigned long load;
+-
+-	if (cfs_rq->last_h_load_update == now)
+-		return;
+-
+-	cfs_rq->h_load_next = NULL;
+-	for_each_sched_entity(se) {
+-		cfs_rq = cfs_rq_of(se);
+-		cfs_rq->h_load_next = se;
+-		if (cfs_rq->last_h_load_update == now)
+-			break;
+-	}
+-
+-	if (!se) {
+-		cfs_rq->h_load = cfs_rq->runnable_load_avg;
+-		cfs_rq->last_h_load_update = now;
+-	}
+-
+-	while ((se = cfs_rq->h_load_next) != NULL) {
+-		load = cfs_rq->h_load;
+-		load = div64_ul(load * se->avg.load_avg_contrib,
+-				cfs_rq->runnable_load_avg + 1);
+-		cfs_rq = group_cfs_rq(se);
+-		cfs_rq->h_load = load;
+-		cfs_rq->last_h_load_update = now;
++		 rq->skip_clock_update = 1;
+ 	}
+-}
+-
+-static unsigned long task_h_load(struct task_struct *p)
+-{
+-	struct cfs_rq *cfs_rq = task_cfs_rq(p);
+ 
+-	update_cfs_rq_h_load(cfs_rq);
+-	return div64_ul(p->se.avg.load_avg_contrib * cfs_rq->h_load,
+-			cfs_rq->runnable_load_avg + 1);
+-}
+-#else
+-static inline void update_blocked_averages(int cpu)
+-{
++	set_skip_buddy(se);
+ }
+ 
+-static unsigned long task_h_load(struct task_struct *p)
++static bool yield_to_task_fair(struct rq *rq, struct task_struct *p, bool preempt)
+ {
+-	return p->se.avg.load_avg_contrib;
+-}
+-#endif
+-
+-/********** Helpers for find_busiest_group ************************/
+-
+-enum group_type {
+-	group_other = 0,
+-	group_imbalanced,
+-	group_overloaded,
+-};
++	struct sched_entity *se = &p->se;
+ 
+-/*
+- * sg_lb_stats - stats of a sched_group required for load_balancing
+- */
+-struct sg_lb_stats {
+-	unsigned long avg_load; /*Avg load across the CPUs of the group */
+-	unsigned long group_load; /* Total load over the CPUs of the group */
+-	unsigned long sum_weighted_load; /* Weighted load of group's tasks */
+-	unsigned long load_per_task;
+-	unsigned long group_capacity;
+-	unsigned int sum_nr_running; /* Nr tasks running in the group */
+-	unsigned int group_capacity_factor;
+-	unsigned int idle_cpus;
+-	unsigned int group_weight;
+-	enum group_type group_type;
+-	int group_has_free_capacity;
+-#ifdef CONFIG_NUMA_BALANCING
+-	unsigned int nr_numa_running;
+-	unsigned int nr_preferred_running;
+-#endif
+-};
++	/* throttled hierarchies are not runnable */
++	if (!se->on_rq || throttled_hierarchy(cfs_rq_of(se)))
++		return false;
+ 
+-/*
+- * sd_lb_stats - Structure to store the statistics of a sched_domain
+- *		 during load balancing.
+- */
+-struct sd_lb_stats {
+-	struct sched_group *busiest;	/* Busiest group in this sd */
+-	struct sched_group *local;	/* Local group in this sd */
+-	unsigned long total_load;	/* Total load of all groups in sd */
+-	unsigned long total_capacity;	/* Total capacity of all groups in sd */
+-	unsigned long avg_load;	/* Average load across all groups in sd */
++	/* Tell the scheduler that we'd really like pse to run next. */
++	set_next_buddy(se);
+ 
+-	struct sg_lb_stats busiest_stat;/* Statistics of the busiest group */
+-	struct sg_lb_stats local_stat;	/* Statistics of the local group */
+-};
++	yield_task_fair(rq);
+ 
+-static inline void init_sd_lb_stats(struct sd_lb_stats *sds)
+-{
+-	/*
+-	 * Skimp on the clearing to avoid duplicate work. We can avoid clearing
+-	 * local_stat because update_sg_lb_stats() does a full clear/assignment.
+-	 * We must however clear busiest_stat::avg_load because
+-	 * update_sd_pick_busiest() reads this before assignment.
+-	 */
+-	*sds = (struct sd_lb_stats){
+-		.busiest = NULL,
+-		.local = NULL,
+-		.total_load = 0UL,
+-		.total_capacity = 0UL,
+-		.busiest_stat = {
+-			.avg_load = 0UL,
+-			.sum_nr_running = 0,
+-			.group_type = group_other,
+-		},
+-	};
++	return true;
+ }
+ 
+-/**
+- * get_sd_load_idx - Obtain the load index for a given sched domain.
+- * @sd: The sched_domain whose load_idx is to be obtained.
+- * @idle: The idle status of the CPU for whose sd load_idx is obtained.
++#ifdef CONFIG_SMP
++/**************************************************
++ * Fair scheduling class load-balancing methods.
+  *
+- * Return: The load index.
+- */
+-static inline int get_sd_load_idx(struct sched_domain *sd,
+-					enum cpu_idle_type idle)
+-{
+-	int load_idx;
++ * BASICS
++ *
++ * The purpose of load-balancing is to achieve the same basic fairness the
++ * per-cpu scheduler provides, namely provide a proportional amount of compute
++ * time to each task. This is expressed in the following equation:
++ *
++ *   W_i,n/P_i == W_j,n/P_j for all i,j                               (1)
++ *
++ * Where W_i,n is the n-th weight average for cpu i. The instantaneous weight
++ * W_i,0 is defined as:
++ *
++ *   W_i,0 = \Sum_j w_i,j                                             (2)
++ *
++ * Where w_i,j is the weight of the j-th runnable task on cpu i. This weight
++ * is derived from the nice value as per prio_to_weight[].
++ *
++ * The weight average is an exponential decay average of the instantaneous
++ * weight:
++ *
++ *   W'_i,n = (2^n - 1) / 2^n * W_i,n + 1 / 2^n * W_i,0               (3)
++ *
++ * C_i is the compute capacity of cpu i, typically it is the
++ * fraction of 'recent' time available for SCHED_OTHER task execution. But it
++ * can also include other factors [XXX].
++ *
++ * To achieve this balance we define a measure of imbalance which follows
++ * directly from (1):
++ *
++ *   imb_i,j = max{ avg(W/C), W_i/C_i } - min{ avg(W/C), W_j/C_j }    (4)
++ *
++ * We them move tasks around to minimize the imbalance. In the continuous
++ * function space it is obvious this converges, in the discrete case we get
++ * a few fun cases generally called infeasible weight scenarios.
++ *
++ * [XXX expand on:
++ *     - infeasible weights;
++ *     - local vs global optima in the discrete case. ]
++ *
++ *
++ * SCHED DOMAINS
++ *
++ * In order to solve the imbalance equation (4), and avoid the obvious O(n^2)
++ * for all i,j solution, we create a tree of cpus that follows the hardware
++ * topology where each level pairs two lower groups (or better). This results
++ * in O(log n) layers. Furthermore we reduce the number of cpus going up the
++ * tree to only the first of the previous level and we decrease the frequency
++ * of load-balance at each level inv. proportional to the number of cpus in
++ * the groups.
++ *
++ * This yields:
++ *
++ *     log_2 n     1     n
++ *   \Sum       { --- * --- * 2^i } = O(n)                            (5)
++ *     i = 0      2^i   2^i
++ *                               `- size of each group
++ *         |         |     `- number of cpus doing load-balance
++ *         |         `- freq
++ *         `- sum over all levels
++ *
++ * Coupled with a limit on how many tasks we can migrate every balance pass,
++ * this makes (5) the runtime complexity of the balancer.
++ *
++ * An important property here is that each CPU is still (indirectly) connected
++ * to every other cpu in at most O(log n) steps:
++ *
++ * The adjacency matrix of the resulting graph is given by:
++ *
++ *             log_2 n     
++ *   A_i,j = \Union     (i % 2^k == 0) && i / 2^(k+1) == j / 2^(k+1)  (6)
++ *             k = 0
++ *
++ * And you'll find that:
++ *
++ *   A^(log_2 n)_i,j != 0  for all i,j                                (7)
++ *
++ * Showing there's indeed a path between every cpu in at most O(log n) steps.
++ * The task movement gives a factor of O(m), giving a convergence complexity
++ * of:
++ *
++ *   O(nm log n),  n := nr_cpus, m := nr_tasks                        (8)
++ *
++ *
++ * WORK CONSERVING
++ *
++ * In order to avoid CPUs going idle while there's still work to do, new idle
++ * balancing is more aggressive and has the newly idle cpu iterate up the domain
++ * tree itself instead of relying on other CPUs to bring it work.
++ *
++ * This adds some complexity to both (5) and (8) but it reduces the total idle
++ * time.
++ *
++ * [XXX more?]
++ *
++ *
++ * CGROUPS
++ *
++ * Cgroups make a horror show out of (2), instead of a simple sum we get:
++ *
++ *                                s_k,i
++ *   W_i,0 = \Sum_j \Prod_k w_k * -----                               (9)
++ *                                 S_k
++ *
++ * Where
++ *
++ *   s_k,i = \Sum_j w_i,j,k  and  S_k = \Sum_i s_k,i                 (10)
++ *
++ * w_i,j,k is the weight of the j-th runnable task in the k-th cgroup on cpu i.
++ *
++ * The big problem is S_k, its a global sum needed to compute a local (W_i)
++ * property.
++ *
++ * [XXX write more on how we solve this.. _after_ merging pjt's patches that
++ *      rewrite all of this once again.]
++ */ 
+ 
+-	switch (idle) {
+-	case CPU_NOT_IDLE:
+-		load_idx = sd->busy_idx;
+-		break;
++static unsigned long __read_mostly max_load_balance_interval = HZ/10;
+ 
+-	case CPU_NEWLY_IDLE:
+-		load_idx = sd->newidle_idx;
+-		break;
+-	default:
+-		load_idx = sd->idle_idx;
+-		break;
+-	}
++enum fbq_type { regular, remote, all };
+ 
+-	return load_idx;
+-}
++#define LBF_ALL_PINNED	0x01
++#define LBF_NEED_BREAK	0x02
++#define LBF_DST_PINNED  0x04
++#define LBF_SOME_PINNED	0x08
+ 
+-static unsigned long default_scale_capacity(struct sched_domain *sd, int cpu)
+-{
+-	return SCHED_CAPACITY_SCALE;
+-}
++struct lb_env {
++	struct sched_domain	*sd;
+ 
+-unsigned long __weak arch_scale_freq_capacity(struct sched_domain *sd, int cpu)
+-{
+-	return default_scale_capacity(sd, cpu);
+-}
++	struct rq		*src_rq;
++	int			src_cpu;
+ 
+-static unsigned long default_scale_cpu_capacity(struct sched_domain *sd, int cpu)
+-{
+-	if ((sd->flags & SD_SHARE_CPUCAPACITY) && (sd->span_weight > 1))
+-		return sd->smt_gain / sd->span_weight;
++	int			dst_cpu;
++	struct rq		*dst_rq;
+ 
+-	return SCHED_CAPACITY_SCALE;
+-}
++	struct cpumask		*dst_grpmask;
++	int			new_dst_cpu;
++	enum cpu_idle_type	idle;
++	long			imbalance;
++	/* The set of CPUs under consideration for load-balancing */
++	struct cpumask		*cpus;
+ 
+-unsigned long __weak arch_scale_cpu_capacity(struct sched_domain *sd, int cpu)
+-{
+-	return default_scale_cpu_capacity(sd, cpu);
+-}
++	unsigned int		flags;
+ 
+-static unsigned long scale_rt_capacity(int cpu)
++	unsigned int		loop;
++	unsigned int		loop_break;
++	unsigned int		loop_max;
++
++	enum fbq_type		fbq_type;
++	struct list_head	tasks;
++};
++
++/*
++ * Is this task likely cache-hot:
++ */
++static int task_hot(struct task_struct *p, struct lb_env *env)
+ {
+-	struct rq *rq = cpu_rq(cpu);
+-	u64 total, available, age_stamp, avg;
+ 	s64 delta;
+ 
+-	/*
+-	 * Since we're reading these variables without serialization make sure
+-	 * we read them once before doing sanity checks on them.
+-	 */
+-	age_stamp = ACCESS_ONCE(rq->age_stamp);
+-	avg = ACCESS_ONCE(rq->rt_avg);
++	lockdep_assert_held(&env->src_rq->lock);
+ 
+-	delta = rq_clock(rq) - age_stamp;
+-	if (unlikely(delta < 0))
+-		delta = 0;
++	if (p->sched_class != &fair_sched_class)
++		return 0;
+ 
+-	total = sched_avg_period() + delta;
++	if (unlikely(p->policy == SCHED_IDLE))
++		return 0;
+ 
+-	if (unlikely(total < avg)) {
+-		/* Ensures that capacity won't end up being negative */
+-		available = 0;
+-	} else {
+-		available = total - avg;
+-	}
++	/*
++	 * Buddy candidates are cache hot:
++	 */
++	if (sched_feat(CACHE_HOT_BUDDY) && env->dst_rq->nr_running &&
++			(&p->se == cfs_rq_of(&p->se)->next ||
++			 &p->se == cfs_rq_of(&p->se)->last))
++		return 1;
+ 
+-	if (unlikely((s64)total < SCHED_CAPACITY_SCALE))
+-		total = SCHED_CAPACITY_SCALE;
++	if (sysctl_sched_migration_cost == -1)
++		return 1;
++	if (sysctl_sched_migration_cost == 0)
++		return 0;
+ 
+-	total >>= SCHED_CAPACITY_SHIFT;
++	delta = rq_clock_task(env->src_rq) - p->se.exec_start;
+ 
+-	return div_u64(available, total);
++	return delta < (s64)sysctl_sched_migration_cost;
+ }
+ 
+-static void update_cpu_capacity(struct sched_domain *sd, int cpu)
++#ifdef CONFIG_NUMA_BALANCING
++/* Returns true if the destination node has incurred more faults */
++static bool migrate_improves_locality(struct task_struct *p, struct lb_env *env)
+ {
+-	unsigned long capacity = SCHED_CAPACITY_SCALE;
+-	struct sched_group *sdg = sd->groups;
+-
+-	if (sched_feat(ARCH_CAPACITY))
+-		capacity *= arch_scale_cpu_capacity(sd, cpu);
+-	else
+-		capacity *= default_scale_cpu_capacity(sd, cpu);
++	struct numa_group *numa_group = rcu_dereference(p->numa_group);
++	int src_nid, dst_nid;
+ 
+-	capacity >>= SCHED_CAPACITY_SHIFT;
++	if (!sched_feat(NUMA_FAVOUR_HIGHER) || !p->numa_faults_memory ||
++	    !(env->sd->flags & SD_NUMA)) {
++		return false;
++	}
+ 
+-	sdg->sgc->capacity_orig = capacity;
++	src_nid = cpu_to_node(env->src_cpu);
++	dst_nid = cpu_to_node(env->dst_cpu);
+ 
+-	if (sched_feat(ARCH_CAPACITY))
+-		capacity *= arch_scale_freq_capacity(sd, cpu);
+-	else
+-		capacity *= default_scale_capacity(sd, cpu);
++	if (src_nid == dst_nid)
++		return false;
+ 
+-	capacity >>= SCHED_CAPACITY_SHIFT;
++	if (numa_group) {
++		/* Task is already in the group's interleave set. */
++		if (node_isset(src_nid, numa_group->active_nodes))
++			return false;
+ 
+-	capacity *= scale_rt_capacity(cpu);
+-	capacity >>= SCHED_CAPACITY_SHIFT;
++		/* Task is moving into the group's interleave set. */
++		if (node_isset(dst_nid, numa_group->active_nodes))
++			return true;
+ 
+-	if (!capacity)
+-		capacity = 1;
++		return group_faults(p, dst_nid) > group_faults(p, src_nid);
++	}
+ 
+-	cpu_rq(cpu)->cpu_capacity = capacity;
+-	sdg->sgc->capacity = capacity;
++	/* Encourage migration to the preferred node. */
++	if (dst_nid == p->numa_preferred_nid)
++		return true;
++
++	return task_faults(p, dst_nid) > task_faults(p, src_nid);
+ }
+ 
+-void update_group_capacity(struct sched_domain *sd, int cpu)
+-{
+-	struct sched_domain *child = sd->child;
+-	struct sched_group *group, *sdg = sd->groups;
+-	unsigned long capacity, capacity_orig;
+-	unsigned long interval;
+ 
+-	interval = msecs_to_jiffies(sd->balance_interval);
+-	interval = clamp(interval, 1UL, max_load_balance_interval);
+-	sdg->sgc->next_update = jiffies + interval;
++static bool migrate_degrades_locality(struct task_struct *p, struct lb_env *env)
++{
++	struct numa_group *numa_group = rcu_dereference(p->numa_group);
++	int src_nid, dst_nid;
+ 
+-	if (!child) {
+-		update_cpu_capacity(sd, cpu);
+-		return;
+-	}
++	if (!sched_feat(NUMA) || !sched_feat(NUMA_RESIST_LOWER))
++		return false;
+ 
+-	capacity_orig = capacity = 0;
++	if (!p->numa_faults_memory || !(env->sd->flags & SD_NUMA))
++		return false;
+ 
+-	if (child->flags & SD_OVERLAP) {
+-		/*
+-		 * SD_OVERLAP domains cannot assume that child groups
+-		 * span the current group.
+-		 */
++	src_nid = cpu_to_node(env->src_cpu);
++	dst_nid = cpu_to_node(env->dst_cpu);
+ 
+-		for_each_cpu(cpu, sched_group_cpus(sdg)) {
+-			struct sched_group_capacity *sgc;
+-			struct rq *rq = cpu_rq(cpu);
++	if (src_nid == dst_nid)
++		return false;
+ 
+-			/*
+-			 * build_sched_domains() -> init_sched_groups_capacity()
+-			 * gets here before we've attached the domains to the
+-			 * runqueues.
+-			 *
+-			 * Use capacity_of(), which is set irrespective of domains
+-			 * in update_cpu_capacity().
+-			 *
+-			 * This avoids capacity/capacity_orig from being 0 and
+-			 * causing divide-by-zero issues on boot.
+-			 *
+-			 * Runtime updates will correct capacity_orig.
+-			 */
+-			if (unlikely(!rq->sd)) {
+-				capacity_orig += capacity_of(cpu);
+-				capacity += capacity_of(cpu);
+-				continue;
+-			}
++	if (numa_group) {
++		/* Task is moving within/into the group's interleave set. */
++		if (node_isset(dst_nid, numa_group->active_nodes))
++			return false;
+ 
+-			sgc = rq->sd->groups->sgc;
+-			capacity_orig += sgc->capacity_orig;
+-			capacity += sgc->capacity;
+-		}
+-	} else  {
+-		/*
+-		 * !SD_OVERLAP domains can assume that child groups
+-		 * span the current group.
+-		 */ 
++		/* Task is moving out of the group's interleave set. */
++		if (node_isset(src_nid, numa_group->active_nodes))
++			return true;
+ 
+-		group = child->groups;
+-		do {
+-			capacity_orig += group->sgc->capacity_orig;
+-			capacity += group->sgc->capacity;
+-			group = group->next;
+-		} while (group != child->groups);
++		return group_faults(p, dst_nid) < group_faults(p, src_nid);
+ 	}
+ 
+-	sdg->sgc->capacity_orig = capacity_orig;
+-	sdg->sgc->capacity = capacity;
++	/* Migrating away from the preferred node is always bad. */
++	if (src_nid == p->numa_preferred_nid)
++		return true;
++
++	return task_faults(p, dst_nid) < task_faults(p, src_nid);
++}
++
++#else
++static inline bool migrate_improves_locality(struct task_struct *p,
++					     struct lb_env *env)
++{
++	return false;
+ }
+ 
++static inline bool migrate_degrades_locality(struct task_struct *p,
++					     struct lb_env *env)
++{
++	return false;
++}
++#endif
++
+ /*
+- * Try and fix up capacity for tiny siblings, this is needed when
+- * things like SD_ASYM_PACKING need f_b_g to select another sibling
+- * which on its own isn't powerful enough.
+- *
+- * See update_sd_pick_busiest() and check_asym_packing().
++ * can_migrate_task - may task p from runqueue rq be migrated to this_cpu?
+  */
+-static inline int
+-fix_small_capacity(struct sched_domain *sd, struct sched_group *group)
++static
++int can_migrate_task(struct task_struct *p, struct lb_env *env)
+ {
++	int tsk_cache_hot = 0;
++
++	lockdep_assert_held(&env->src_rq->lock);
++
+ 	/*
+-	 * Only siblings can have significantly less than SCHED_CAPACITY_SCALE
++	 * We do not migrate tasks that are:
++	 * 1) throttled_lb_pair, or
++	 * 2) cannot be migrated to this CPU due to cpus_allowed, or
++	 * 3) running (obviously), or
++	 * 4) are cache-hot on their current CPU.
+ 	 */
+-	if (!(sd->flags & SD_SHARE_CPUCAPACITY))
++	if (throttled_lb_pair(task_group(p), env->src_cpu, env->dst_cpu))
++		return 0;
++
++	if (!cpumask_test_cpu(env->dst_cpu, tsk_cpus_allowed(p))) {
++		int cpu;
++
++		schedstat_inc(p, se.statistics.nr_failed_migrations_affine);
++
++		env->flags |= LBF_SOME_PINNED;
++
++		/*
++		 * Remember if this task can be migrated to any other cpu in
++		 * our sched_group. We may want to revisit it if we couldn't
++		 * meet load balance goals by pulling other tasks on src_cpu.
++		 *
++		 * Also avoid computing new_dst_cpu if we have already computed
++		 * one in current iteration.
++		 */
++		if (!env->dst_grpmask || (env->flags & LBF_DST_PINNED))
++			return 0;
++
++		/* Prevent to re-select dst_cpu via env's cpus */
++		for_each_cpu_and(cpu, env->dst_grpmask, env->cpus) {
++			if (cpumask_test_cpu(cpu, tsk_cpus_allowed(p))) {
++				env->flags |= LBF_DST_PINNED;
++				env->new_dst_cpu = cpu;
++				break;
++			}
++		}
++
++		return 0;
++	}
++
++	/* Record that we found atleast one task that could run on dst_cpu */
++	env->flags &= ~LBF_ALL_PINNED;
++
++	if (task_running(env->src_rq, p)) {
++		schedstat_inc(p, se.statistics.nr_failed_migrations_running);
+ 		return 0;
++	}
+ 
+ 	/*
+-	 * If ~90% of the cpu_capacity is still there, we're good.
++	 * Aggressive migration if:
++	 * 1) destination numa is preferred
++	 * 2) task is cache cold, or
++	 * 3) too many balance attempts have failed.
+ 	 */
+-	if (group->sgc->capacity * 32 > group->sgc->capacity_orig * 29)
++	tsk_cache_hot = task_hot(p, env);
++	if (!tsk_cache_hot)
++		tsk_cache_hot = migrate_degrades_locality(p, env);
++
++	if (migrate_improves_locality(p, env) || !tsk_cache_hot ||
++	    env->sd->nr_balance_failed > env->sd->cache_nice_tries) {
++		if (tsk_cache_hot) {
++			schedstat_inc(env->sd, lb_hot_gained[env->idle]);
++			schedstat_inc(p, se.statistics.nr_forced_migrations);
++		}
+ 		return 1;
++	}
+ 
++	schedstat_inc(p, se.statistics.nr_failed_migrations_hot);
+ 	return 0;
+ }
+-
++#ifdef CONFIG_SCHED_HMP
++static unsigned int hmp_idle_pull(int this_cpu);
++#endif
+ /*
+- * Group imbalance indicates (and tries to solve) the problem where balancing
+- * groups is inadequate due to tsk_cpus_allowed() constraints.
+- *
+- * Imagine a situation of two groups of 4 cpus each and 4 tasks each with a
+- * cpumask covering 1 cpu of the first group and 3 cpus of the second group.
+- * Something like:
+- *
+- * 	{ 0 1 2 3 } { 4 5 6 7 }
+- * 	        *     * * *
+- *
+- * If we were to balance group-wise we'd place two tasks in the first group and
+- * two tasks in the second group. Clearly this is undesired as it will overload
+- * cpu 3 and leave one of the cpus in the second group unused.
+- *
+- * The current solution to this issue is detecting the skew in the first group
+- * by noticing the lower domain failed to reach balance and had difficulty
+- * moving tasks due to affinity constraints.
+- *
+- * When this is so detected; this group becomes a candidate for busiest; see
+- * update_sd_pick_busiest(). And calculate_imbalance() and
+- * find_busiest_group() avoid some of the usual balance conditions to allow it
+- * to create an effective group imbalance.
+- *
+- * This is a somewhat tricky proposition since the next run might not find the
+- * group imbalance and decide the groups need to be balanced again. A most
+- * subtle and fragile situation.
++ * detach_task() -- detach the task for the migration specified in env
+  */
+-
+-static inline int sg_imbalanced(struct sched_group *group)
++static void detach_task(struct task_struct *p, struct lb_env *env)
+ {
+-	return group->sgc->imbalance;
++	lockdep_assert_held(&env->src_rq->lock);
++
++	deactivate_task(env->src_rq, p, 0);
++	p->on_rq = TASK_ON_RQ_MIGRATING;
++	set_task_cpu(p, env->dst_cpu);
+ }
+ 
+ /*
+- * Compute the group capacity factor.
++ * detach_one_task() -- tries to dequeue exactly one task from env->src_rq, as
++ * part of active balancing operations within "domain".
+  *
+- * Avoid the issue where N*frac(smt_capacity) >= 1 creates 'phantom' cores by
+- * first dividing out the smt factor and computing the actual number of cores
+- * and limit unit capacity with that.
++ * Returns a task if successful and NULL otherwise.
+  */
+-static inline int sg_capacity_factor(struct lb_env *env, struct sched_group *group)
++static struct task_struct *detach_one_task(struct lb_env *env)
+ {
+-	unsigned int capacity_factor, smt, cpus;
+-	unsigned int capacity, capacity_orig;
++	struct task_struct *p, *n;
+ 
+-	capacity = group->sgc->capacity;
+-	capacity_orig = group->sgc->capacity_orig;
+-	cpus = group->group_weight;
++	lockdep_assert_held(&env->src_rq->lock);
+ 
+-	/* smt := ceil(cpus / capacity), assumes: 1 < smt_capacity < 2 */
+-	smt = DIV_ROUND_UP(SCHED_CAPACITY_SCALE * cpus, capacity_orig);
+-	capacity_factor = cpus / smt; /* cores */
++	list_for_each_entry_safe(p, n, &env->src_rq->cfs_tasks, se.group_node) {
++		if (!can_migrate_task(p, env))
++			continue;
+ 
+-	capacity_factor = min_t(unsigned,
+-		capacity_factor, DIV_ROUND_CLOSEST(capacity, SCHED_CAPACITY_SCALE));
+-	if (!capacity_factor)
+-		capacity_factor = fix_small_capacity(env->sd, group);
++		detach_task(p, env);
+ 
+-	return capacity_factor;
+-}
+-
+-static enum group_type
+-group_classify(struct sched_group *group, struct sg_lb_stats *sgs)
+-{
+-	if (sgs->sum_nr_running > sgs->group_capacity_factor)
+-		return group_overloaded;
+-
+-	if (sg_imbalanced(group))
+-		return group_imbalanced;
+-
+-	return group_other;
++		/*
++		 * Right now, this is only the second place where
++		 * lb_gained[env->idle] is updated (other is detach_tasks)
++		 * so we can safely collect stats here rather than
++		 * inside detach_tasks().
++		 */
++		schedstat_inc(env->sd, lb_gained[env->idle]);
++		return p;
++	}
++	return NULL;
+ }
+ 
+-/**
+- * update_sg_lb_stats - Update sched_group's statistics for load balancing.
+- * @env: The load balancing environment.
+- * @group: sched_group whose statistics are to be updated.
+- * @load_idx: Load index of sched_domain of this_cpu for load calc.
+- * @local_group: Does group contain this_cpu.
+- * @sgs: variable to hold the statistics for this group.
+- * @overload: Indicate more than one runnable task for any CPU.
++static const unsigned int sched_nr_migrate_break = 32;
++
++/*
++ * detach_tasks() -- tries to detach up to imbalance weighted load from
++ * busiest_rq, as part of a balancing operation within domain "sd".
++ *
++ * Returns number of detached tasks if successful and 0 otherwise.
+  */
+-static inline void update_sg_lb_stats(struct lb_env *env,
+-			struct sched_group *group, int load_idx,
+-			int local_group, struct sg_lb_stats *sgs,
+-			bool *overload)
++static int detach_tasks(struct lb_env *env)
+ {
++	struct list_head *tasks = &env->src_rq->cfs_tasks;
++	struct task_struct *p;
+ 	unsigned long load;
+-	int i;
+-
+-	memset(sgs, 0, sizeof(*sgs));
++	int detached = 0;
+ 
+-	for_each_cpu_and(i, sched_group_cpus(group), env->cpus) {
+-		struct rq *rq = cpu_rq(i);
++	lockdep_assert_held(&env->src_rq->lock);
+ 
+-		/* Bias balancing toward cpus of our domain */
+-		if (local_group)
+-			load = target_load(i, load_idx);
+-		else
+-			load = source_load(i, load_idx);
++	if (env->imbalance <= 0)
++		return 0;
+ 
+-		sgs->group_load += load;
+-		sgs->sum_nr_running += rq->cfs.h_nr_running;
++	while (!list_empty(tasks)) {
++		p = list_first_entry(tasks, struct task_struct, se.group_node);
+ 
+-		if (rq->nr_running > 1)
+-			*overload = true;
++		env->loop++;
++		/* We've more or less seen every task there is, call it quits */
++		if (env->loop > env->loop_max)
++			break;
+ 
+-#ifdef CONFIG_NUMA_BALANCING
+-		sgs->nr_numa_running += rq->nr_numa_running;
+-		sgs->nr_preferred_running += rq->nr_preferred_running;
+-#endif
+-		sgs->sum_weighted_load += weighted_cpuload(i);
+-		if (idle_cpu(i))
+-			sgs->idle_cpus++;
+-	}
++		/* take a breather every nr_migrate tasks */
++		if (env->loop > env->loop_break) {
++			env->loop_break += sched_nr_migrate_break;
++			env->flags |= LBF_NEED_BREAK;
++			break;
++		}
+ 
+-	/* Adjust by relative CPU capacity of the group */
+-	sgs->group_capacity = group->sgc->capacity;
+-	sgs->avg_load = (sgs->group_load*SCHED_CAPACITY_SCALE) / sgs->group_capacity;
++		if (!can_migrate_task(p, env))
++			goto next;
+ 
+-	if (sgs->sum_nr_running)
+-		sgs->load_per_task = sgs->sum_weighted_load / sgs->sum_nr_running;
++		load = task_h_load(p);
+ 
+-	sgs->group_weight = group->group_weight;
+-	sgs->group_capacity_factor = sg_capacity_factor(env, group);
+-	sgs->group_type = group_classify(group, sgs);
++		if (sched_feat(LB_MIN) && load < 16 && !env->sd->nr_balance_failed)
++			goto next;
+ 
+-	if (sgs->group_capacity_factor > sgs->sum_nr_running)
+-		sgs->group_has_free_capacity = 1;
+-}
++		if ((load / 2) > env->imbalance)
++			goto next;
+ 
+-/**
+- * update_sd_pick_busiest - return 1 on busiest group
+- * @env: The load balancing environment.
+- * @sds: sched_domain statistics
+- * @sg: sched_group candidate to be checked for being the busiest
+- * @sgs: sched_group statistics
+- *
+- * Determine if @sg is a busier group than the previously selected
+- * busiest group.
+- *
+- * Return: %true if @sg is a busier group than the previously selected
+- * busiest group. %false otherwise.
+- */
+-static bool update_sd_pick_busiest(struct lb_env *env,
+-				   struct sd_lb_stats *sds,
+-				   struct sched_group *sg,
+-				   struct sg_lb_stats *sgs)
+-{
+-	struct sg_lb_stats *busiest = &sds->busiest_stat;
++		detach_task(p, env);
++		list_add(&p->se.group_node, &env->tasks);
+ 
+-	if (sgs->group_type > busiest->group_type)
+-		return true;
++		detached++;
++		env->imbalance -= load;
+ 
+-	if (sgs->group_type < busiest->group_type)
+-		return false;
++#ifdef CONFIG_PREEMPT
++		/*
++		 * NEWIDLE balancing is a source of latency, so preemptible
++		 * kernels will stop after the first task is detached to minimize
++		 * the critical section.
++		 */
++		if (env->idle == CPU_NEWLY_IDLE)
++			break;
++#endif
+ 
+-	if (sgs->avg_load <= busiest->avg_load)
+-		return false;
++		/*
++		 * We only want to steal up to the prescribed amount of
++		 * weighted load.
++		 */
++		if (env->imbalance <= 0)
++			break;
+ 
+-	/* This is the busiest node in its class. */
+-	if (!(env->sd->flags & SD_ASYM_PACKING))
+-		return true;
++		continue;
++next:
++		list_move_tail(&p->se.group_node, tasks);
++	}
+ 
+ 	/*
+-	 * ASYM_PACKING needs to move all the work to the lowest
+-	 * numbered CPUs in the group, therefore mark all groups
+-	 * higher than ourself as busy.
++	 * Right now, this is one of only two places we collect this stat
++	 * so we can safely collect detach_one_task() stats here rather
++	 * than inside detach_one_task().
+ 	 */
+-	if (sgs->sum_nr_running && env->dst_cpu < group_first_cpu(sg)) {
+-		if (!sds->busiest)
+-			return true;
+-
+-		if (group_first_cpu(sds->busiest) > group_first_cpu(sg))
+-			return true;
+-	}
++	schedstat_add(env->sd, lb_gained[env->idle], detached);
+ 
+-	return false;
++	return detached;
+ }
+ 
+-#ifdef CONFIG_NUMA_BALANCING
+-static inline enum fbq_type fbq_classify_group(struct sg_lb_stats *sgs)
++/*
++ * attach_task() -- attach the task detached by detach_task() to its new rq.
++ */
++static void attach_task(struct rq *rq, struct task_struct *p)
+ {
+-	if (sgs->sum_nr_running > sgs->nr_numa_running)
+-		return regular;
+-	if (sgs->sum_nr_running > sgs->nr_preferred_running)
+-		return remote;
+-	return all;
+-}
++	lockdep_assert_held(&rq->lock);
+ 
+-static inline enum fbq_type fbq_classify_rq(struct rq *rq)
+-{
+-	if (rq->nr_running > rq->nr_numa_running)
+-		return regular;
+-	if (rq->nr_running > rq->nr_preferred_running)
+-		return remote;
+-	return all;
++	BUG_ON(task_rq(p) != rq);
++	p->on_rq = TASK_ON_RQ_QUEUED;
++	activate_task(rq, p, 0);
++	check_preempt_curr(rq, p, 0);
+ }
+-#else
+-static inline enum fbq_type fbq_classify_group(struct sg_lb_stats *sgs)
++
++/*
++ * attach_one_task() -- attaches the task returned from detach_one_task() to
++ * its new rq.
++ */
++static void attach_one_task(struct rq *rq, struct task_struct *p)
+ {
+-	return all;
++	raw_spin_lock(&rq->lock);
++	attach_task(rq, p);
++	raw_spin_unlock(&rq->lock);
+ }
+ 
+-static inline enum fbq_type fbq_classify_rq(struct rq *rq)
++/*
++ * attach_tasks() -- attaches all tasks detached by detach_tasks() to their
++ * new rq.
++ */
++static void attach_tasks(struct lb_env *env)
+ {
+-	return regular;
++	struct list_head *tasks = &env->tasks;
++	struct task_struct *p;
++
++	raw_spin_lock(&env->dst_rq->lock);
++
++	while (!list_empty(tasks)) {
++		p = list_first_entry(tasks, struct task_struct, se.group_node);
++		list_del_init(&p->se.group_node);
++
++		attach_task(env->dst_rq, p);
++	}
++
++	raw_spin_unlock(&env->dst_rq->lock);
+ }
+-#endif /* CONFIG_NUMA_BALANCING */
+ 
+-/**
+- * update_sd_lb_stats - Update sched_domain's statistics for load balancing.
+- * @env: The load balancing environment.
+- * @sds: variable to hold the statistics for this sched_domain.
++#ifdef CONFIG_FAIR_GROUP_SCHED
++/*
++ * update tg->load_weight by folding this cpu's load_avg
+  */
+-static inline void update_sd_lb_stats(struct lb_env *env, struct sd_lb_stats *sds)
++static void __update_blocked_averages_cpu(struct task_group *tg, int cpu)
+ {
+-	struct sched_domain *child = env->sd->child;
+-	struct sched_group *sg = env->sd->groups;
+-	struct sg_lb_stats tmp_sgs;
+-	int load_idx, prefer_sibling = 0;
+-	bool overload = false;
++	struct sched_entity *se = tg->se[cpu];
++	struct cfs_rq *cfs_rq = tg->cfs_rq[cpu];
++
++	/* throttled entities do not contribute to load */
++	if (throttled_hierarchy(cfs_rq))
++		return;
++
++	update_cfs_rq_blocked_load(cfs_rq, 1);
++
++	if (se) {
++		update_entity_load_avg(se, 1);
++		/*
++		 * We pivot on our runnable average having decayed to zero for
++		 * list removal.  This generally implies that all our children
++		 * have also been removed (modulo rounding error or bandwidth
++		 * control); however, such cases are rare and we can fix these
++		 * at enqueue.
++		 *
++		 * TODO: fix up out-of-order children on enqueue.
++		 */
++		if (!se->avg.runnable_avg_sum && !cfs_rq->nr_running)
++			list_del_leaf_cfs_rq(cfs_rq);
++	} else {
++		struct rq *rq = rq_of(cfs_rq);
++		update_rq_runnable_avg(rq, rq->nr_running);
++	}
++}
++
++static void update_blocked_averages(int cpu)
++{
++	struct rq *rq = cpu_rq(cpu);
++	struct cfs_rq *cfs_rq;
++	unsigned long flags;
++
++	raw_spin_lock_irqsave(&rq->lock, flags);
++	update_rq_clock(rq);
++	/*
++	 * Iterates the task_group tree in a bottom up fashion, see
++	 * list_add_leaf_cfs_rq() for details.
++	 */
++	for_each_leaf_cfs_rq(rq, cfs_rq) {
++		/*
++		 * Note: We may want to consider periodically releasing
++		 * rq->lock about these updates so that creating many task
++		 * groups does not result in continually extending hold time.
++		 */
++		__update_blocked_averages_cpu(cfs_rq->tg, rq->cpu);
++	}
++
++	raw_spin_unlock_irqrestore(&rq->lock, flags);
++}
++
++/*
++ * Compute the hierarchical load factor for cfs_rq and all its ascendants.
++ * This needs to be done in a top-down fashion because the load of a child
++ * group is a fraction of its parents load.
++ */
++static void update_cfs_rq_h_load(struct cfs_rq *cfs_rq)
++{
++	struct rq *rq = rq_of(cfs_rq);
++	struct sched_entity *se = cfs_rq->tg->se[cpu_of(rq)];
++	unsigned long now = jiffies;
++	unsigned long load;
++
++	if (cfs_rq->last_h_load_update == now)
++		return;
++
++	cfs_rq->h_load_next = NULL;
++	for_each_sched_entity(se) {
++		cfs_rq = cfs_rq_of(se);
++		cfs_rq->h_load_next = se;
++		if (cfs_rq->last_h_load_update == now)
++			break;
++	}
++
++	if (!se) {
++		cfs_rq->h_load = cfs_rq->runnable_load_avg;
++		cfs_rq->last_h_load_update = now;
++	}
++
++	while ((se = cfs_rq->h_load_next) != NULL) {
++		load = cfs_rq->h_load;
++		load = div64_ul(load * se->avg.load_avg_contrib,
++				cfs_rq->runnable_load_avg + 1);
++		cfs_rq = group_cfs_rq(se);
++		cfs_rq->h_load = load;
++		cfs_rq->last_h_load_update = now;
++	}
++}
++
++static unsigned long task_h_load(struct task_struct *p)
++{
++	struct cfs_rq *cfs_rq = task_cfs_rq(p);
++
++	update_cfs_rq_h_load(cfs_rq);
++	return div64_ul(p->se.avg.load_avg_contrib * cfs_rq->h_load,
++			cfs_rq->runnable_load_avg + 1);
++}
++#else
++static inline void update_blocked_averages(int cpu)
++{
++}
++
++static unsigned long task_h_load(struct task_struct *p)
++{
++	return p->se.avg.load_avg_contrib;
++}
++#endif
++
++/********** Helpers for find_busiest_group ************************/
++
++enum group_type {
++	group_other = 0,
++	group_imbalanced,
++	group_overloaded,
++};
++
++/*
++ * sg_lb_stats - stats of a sched_group required for load_balancing
++ */
++struct sg_lb_stats {
++	unsigned long avg_load; /*Avg load across the CPUs of the group */
++	unsigned long group_load; /* Total load over the CPUs of the group */
++	unsigned long sum_weighted_load; /* Weighted load of group's tasks */
++	unsigned long load_per_task;
++	unsigned long group_capacity;
++	unsigned int sum_nr_running; /* Nr tasks running in the group */
++	unsigned int group_capacity_factor;
++	unsigned int idle_cpus;
++	unsigned int group_weight;
++	enum group_type group_type;
++	int group_has_free_capacity;
++#ifdef CONFIG_NUMA_BALANCING
++	unsigned int nr_numa_running;
++	unsigned int nr_preferred_running;
++#endif
++};
++
++/*
++ * sd_lb_stats - Structure to store the statistics of a sched_domain
++ *		 during load balancing.
++ */
++struct sd_lb_stats {
++	struct sched_group *busiest;	/* Busiest group in this sd */
++	struct sched_group *local;	/* Local group in this sd */
++	unsigned long total_load;	/* Total load of all groups in sd */
++	unsigned long total_capacity;	/* Total capacity of all groups in sd */
++	unsigned long avg_load;	/* Average load across all groups in sd */
++
++	struct sg_lb_stats busiest_stat;/* Statistics of the busiest group */
++	struct sg_lb_stats local_stat;	/* Statistics of the local group */
++};
++
++static inline void init_sd_lb_stats(struct sd_lb_stats *sds)
++{
++	/*
++	 * Skimp on the clearing to avoid duplicate work. We can avoid clearing
++	 * local_stat because update_sg_lb_stats() does a full clear/assignment.
++	 * We must however clear busiest_stat::avg_load because
++	 * update_sd_pick_busiest() reads this before assignment.
++	 */
++	*sds = (struct sd_lb_stats){
++		.busiest = NULL,
++		.local = NULL,
++		.total_load = 0UL,
++		.total_capacity = 0UL,
++		.busiest_stat = {
++			.avg_load = 0UL,
++			.sum_nr_running = 0,
++			.group_type = group_other,
++		},
++	};
++}
++
++/**
++ * get_sd_load_idx - Obtain the load index for a given sched domain.
++ * @sd: The sched_domain whose load_idx is to be obtained.
++ * @idle: The idle status of the CPU for whose sd load_idx is obtained.
++ *
++ * Return: The load index.
++ */
++static inline int get_sd_load_idx(struct sched_domain *sd,
++					enum cpu_idle_type idle)
++{
++	int load_idx;
++
++	switch (idle) {
++	case CPU_NOT_IDLE:
++		load_idx = sd->busy_idx;
++		break;
++
++	case CPU_NEWLY_IDLE:
++		load_idx = sd->newidle_idx;
++		break;
++	default:
++		load_idx = sd->idle_idx;
++		break;
++	}
++
++	return load_idx;
++}
++
++static unsigned long default_scale_capacity(struct sched_domain *sd, int cpu)
++{
++	return SCHED_CAPACITY_SCALE;
++}
++
++unsigned long __weak arch_scale_freq_capacity(struct sched_domain *sd, int cpu)
++{
++	return default_scale_capacity(sd, cpu);
++}
++
++static unsigned long default_scale_cpu_capacity(struct sched_domain *sd, int cpu)
++{
++	if ((sd->flags & SD_SHARE_CPUCAPACITY) && (sd->span_weight > 1))
++		return sd->smt_gain / sd->span_weight;
++
++	return SCHED_CAPACITY_SCALE;
++}
++
++unsigned long __weak arch_scale_cpu_capacity(struct sched_domain *sd, int cpu)
++{
++	return default_scale_cpu_capacity(sd, cpu);
++}
++
++static unsigned long scale_rt_capacity(int cpu)
++{
++	struct rq *rq = cpu_rq(cpu);
++	u64 total, available, age_stamp, avg;
++	s64 delta;
++
++	/*
++	 * Since we're reading these variables without serialization make sure
++	 * we read them once before doing sanity checks on them.
++	 */
++	age_stamp = ACCESS_ONCE(rq->age_stamp);
++	avg = ACCESS_ONCE(rq->rt_avg);
++
++	delta = rq_clock(rq) - age_stamp;
++	if (unlikely(delta < 0))
++		delta = 0;
++
++	total = sched_avg_period() + delta;
++
++	if (unlikely(total < avg)) {
++		/* Ensures that capacity won't end up being negative */
++		available = 0;
++	} else {
++		available = total - avg;
++	}
++
++	if (unlikely((s64)total < SCHED_CAPACITY_SCALE))
++		total = SCHED_CAPACITY_SCALE;
++
++	total >>= SCHED_CAPACITY_SHIFT;
++
++	return div_u64(available, total);
++}
++
++static void update_cpu_capacity(struct sched_domain *sd, int cpu)
++{
++	unsigned long capacity = SCHED_CAPACITY_SCALE;
++	struct sched_group *sdg = sd->groups;
++
++	if (sched_feat(ARCH_CAPACITY))
++		capacity *= arch_scale_cpu_capacity(sd, cpu);
++	else
++		capacity *= default_scale_cpu_capacity(sd, cpu);
++
++	capacity >>= SCHED_CAPACITY_SHIFT;
++
++	sdg->sgc->capacity_orig = capacity;
++
++	if (sched_feat(ARCH_CAPACITY))
++		capacity *= arch_scale_freq_capacity(sd, cpu);
++	else
++		capacity *= default_scale_capacity(sd, cpu);
++
++	capacity >>= SCHED_CAPACITY_SHIFT;
++
++	capacity *= scale_rt_capacity(cpu);
++	capacity >>= SCHED_CAPACITY_SHIFT;
++
++	if (!capacity)
++		capacity = 1;
++
++	cpu_rq(cpu)->cpu_capacity = capacity;
++	sdg->sgc->capacity = capacity;
++}
++
++void update_group_capacity(struct sched_domain *sd, int cpu)
++{
++	struct sched_domain *child = sd->child;
++	struct sched_group *group, *sdg = sd->groups;
++	unsigned long capacity, capacity_orig;
++	unsigned long interval;
++
++	interval = msecs_to_jiffies(sd->balance_interval);
++	interval = clamp(interval, 1UL, max_load_balance_interval);
++	sdg->sgc->next_update = jiffies + interval;
++
++	if (!child) {
++		update_cpu_capacity(sd, cpu);
++		return;
++	}
++
++	capacity_orig = capacity = 0;
++
++	if (child->flags & SD_OVERLAP) {
++		/*
++		 * SD_OVERLAP domains cannot assume that child groups
++		 * span the current group.
++		 */
++
++		for_each_cpu(cpu, sched_group_cpus(sdg)) {
++			struct sched_group_capacity *sgc;
++			struct rq *rq = cpu_rq(cpu);
++
++			/*
++			 * build_sched_domains() -> init_sched_groups_capacity()
++			 * gets here before we've attached the domains to the
++			 * runqueues.
++			 *
++			 * Use capacity_of(), which is set irrespective of domains
++			 * in update_cpu_capacity().
++			 *
++			 * This avoids capacity/capacity_orig from being 0 and
++			 * causing divide-by-zero issues on boot.
++			 *
++			 * Runtime updates will correct capacity_orig.
++			 */
++			if (unlikely(!rq->sd)) {
++				capacity_orig += capacity_of(cpu);
++				capacity += capacity_of(cpu);
++				continue;
++			}
++
++			sgc = rq->sd->groups->sgc;
++			capacity_orig += sgc->capacity_orig;
++			capacity += sgc->capacity;
++		}
++	} else  {
++		/*
++		 * !SD_OVERLAP domains can assume that child groups
++		 * span the current group.
++		 */ 
++
++		group = child->groups;
++		do {
++			capacity_orig += group->sgc->capacity_orig;
++			capacity += group->sgc->capacity;
++			group = group->next;
++		} while (group != child->groups);
++	}
++
++	sdg->sgc->capacity_orig = capacity_orig;
++	sdg->sgc->capacity = capacity;
++}
++
++/*
++ * Try and fix up capacity for tiny siblings, this is needed when
++ * things like SD_ASYM_PACKING need f_b_g to select another sibling
++ * which on its own isn't powerful enough.
++ *
++ * See update_sd_pick_busiest() and check_asym_packing().
++ */
++static inline int
++fix_small_capacity(struct sched_domain *sd, struct sched_group *group)
++{
++	/*
++	 * Only siblings can have significantly less than SCHED_CAPACITY_SCALE
++	 */
++	if (!(sd->flags & SD_SHARE_CPUCAPACITY))
++		return 0;
++
++	/*
++	 * If ~90% of the cpu_capacity is still there, we're good.
++	 */
++	if (group->sgc->capacity * 32 > group->sgc->capacity_orig * 29)
++		return 1;
++
++	return 0;
++}
++
++/*
++ * Group imbalance indicates (and tries to solve) the problem where balancing
++ * groups is inadequate due to tsk_cpus_allowed() constraints.
++ *
++ * Imagine a situation of two groups of 4 cpus each and 4 tasks each with a
++ * cpumask covering 1 cpu of the first group and 3 cpus of the second group.
++ * Something like:
++ *
++ * 	{ 0 1 2 3 } { 4 5 6 7 }
++ * 	        *     * * *
++ *
++ * If we were to balance group-wise we'd place two tasks in the first group and
++ * two tasks in the second group. Clearly this is undesired as it will overload
++ * cpu 3 and leave one of the cpus in the second group unused.
++ *
++ * The current solution to this issue is detecting the skew in the first group
++ * by noticing the lower domain failed to reach balance and had difficulty
++ * moving tasks due to affinity constraints.
++ *
++ * When this is so detected; this group becomes a candidate for busiest; see
++ * update_sd_pick_busiest(). And calculate_imbalance() and
++ * find_busiest_group() avoid some of the usual balance conditions to allow it
++ * to create an effective group imbalance.
++ *
++ * This is a somewhat tricky proposition since the next run might not find the
++ * group imbalance and decide the groups need to be balanced again. A most
++ * subtle and fragile situation.
++ */
++
++static inline int sg_imbalanced(struct sched_group *group)
++{
++	return group->sgc->imbalance;
++}
++
++/*
++ * Compute the group capacity factor.
++ *
++ * Avoid the issue where N*frac(smt_capacity) >= 1 creates 'phantom' cores by
++ * first dividing out the smt factor and computing the actual number of cores
++ * and limit unit capacity with that.
++ */
++static inline int sg_capacity_factor(struct lb_env *env, struct sched_group *group)
++{
++	unsigned int capacity_factor, smt, cpus;
++	unsigned int capacity, capacity_orig;
++
++	capacity = group->sgc->capacity;
++	capacity_orig = group->sgc->capacity_orig;
++	cpus = group->group_weight;
++
++	/* smt := ceil(cpus / capacity), assumes: 1 < smt_capacity < 2 */
++	smt = DIV_ROUND_UP(SCHED_CAPACITY_SCALE * cpus, capacity_orig);
++	capacity_factor = cpus / smt; /* cores */
++
++	capacity_factor = min_t(unsigned,
++		capacity_factor, DIV_ROUND_CLOSEST(capacity, SCHED_CAPACITY_SCALE));
++	if (!capacity_factor)
++		capacity_factor = fix_small_capacity(env->sd, group);
++
++	return capacity_factor;
++}
++
++static enum group_type
++group_classify(struct sched_group *group, struct sg_lb_stats *sgs)
++{
++	if (sgs->sum_nr_running > sgs->group_capacity_factor)
++		return group_overloaded;
++
++	if (sg_imbalanced(group))
++		return group_imbalanced;
++
++	return group_other;
++}
++
++/**
++ * update_sg_lb_stats - Update sched_group's statistics for load balancing.
++ * @env: The load balancing environment.
++ * @group: sched_group whose statistics are to be updated.
++ * @load_idx: Load index of sched_domain of this_cpu for load calc.
++ * @local_group: Does group contain this_cpu.
++ * @sgs: variable to hold the statistics for this group.
++ * @overload: Indicate more than one runnable task for any CPU.
++ */
++static inline void update_sg_lb_stats(struct lb_env *env,
++			struct sched_group *group, int load_idx,
++			int local_group, struct sg_lb_stats *sgs,
++			bool *overload)
++{
++	unsigned long load;
++	int i;
++
++	memset(sgs, 0, sizeof(*sgs));
++
++	for_each_cpu_and(i, sched_group_cpus(group), env->cpus) {
++		struct rq *rq = cpu_rq(i);
++
++		/* Bias balancing toward cpus of our domain */
++		if (local_group)
++			load = target_load(i, load_idx);
++		else
++			load = source_load(i, load_idx);
++
++		sgs->group_load += load;
++		sgs->sum_nr_running += rq->cfs.h_nr_running;
++
++		if (rq->nr_running > 1)
++			*overload = true;
++
++#ifdef CONFIG_NUMA_BALANCING
++		sgs->nr_numa_running += rq->nr_numa_running;
++		sgs->nr_preferred_running += rq->nr_preferred_running;
++#endif
++		sgs->sum_weighted_load += weighted_cpuload(i);
++		if (idle_cpu(i))
++			sgs->idle_cpus++;
++	}
++
++	/* Adjust by relative CPU capacity of the group */
++	sgs->group_capacity = group->sgc->capacity;
++	sgs->avg_load = (sgs->group_load*SCHED_CAPACITY_SCALE) / sgs->group_capacity;
++
++	if (sgs->sum_nr_running)
++		sgs->load_per_task = sgs->sum_weighted_load / sgs->sum_nr_running;
++
++	sgs->group_weight = group->group_weight;
++	sgs->group_capacity_factor = sg_capacity_factor(env, group);
++	sgs->group_type = group_classify(group, sgs);
++
++	if (sgs->group_capacity_factor > sgs->sum_nr_running)
++		sgs->group_has_free_capacity = 1;
++}
++
++/**
++ * update_sd_pick_busiest - return 1 on busiest group
++ * @env: The load balancing environment.
++ * @sds: sched_domain statistics
++ * @sg: sched_group candidate to be checked for being the busiest
++ * @sgs: sched_group statistics
++ *
++ * Determine if @sg is a busier group than the previously selected
++ * busiest group.
++ *
++ * Return: %true if @sg is a busier group than the previously selected
++ * busiest group. %false otherwise.
++ */
++static bool update_sd_pick_busiest(struct lb_env *env,
++				   struct sd_lb_stats *sds,
++				   struct sched_group *sg,
++				   struct sg_lb_stats *sgs)
++{
++	struct sg_lb_stats *busiest = &sds->busiest_stat;
++
++	if (sgs->group_type > busiest->group_type)
++		return true;
++
++	if (sgs->group_type < busiest->group_type)
++		return false;
++
++	if (sgs->avg_load <= busiest->avg_load)
++		return false;
++
++	/* This is the busiest node in its class. */
++	if (!(env->sd->flags & SD_ASYM_PACKING))
++		return true;
++
++	/*
++	 * ASYM_PACKING needs to move all the work to the lowest
++	 * numbered CPUs in the group, therefore mark all groups
++	 * higher than ourself as busy.
++	 */
++	if (sgs->sum_nr_running && env->dst_cpu < group_first_cpu(sg)) {
++		if (!sds->busiest)
++			return true;
++
++		if (group_first_cpu(sds->busiest) > group_first_cpu(sg))
++			return true;
++	}
++
++	return false;
++}
++
++#ifdef CONFIG_NUMA_BALANCING
++static inline enum fbq_type fbq_classify_group(struct sg_lb_stats *sgs)
++{
++	if (sgs->sum_nr_running > sgs->nr_numa_running)
++		return regular;
++	if (sgs->sum_nr_running > sgs->nr_preferred_running)
++		return remote;
++	return all;
++}
++
++static inline enum fbq_type fbq_classify_rq(struct rq *rq)
++{
++	if (rq->nr_running > rq->nr_numa_running)
++		return regular;
++	if (rq->nr_running > rq->nr_preferred_running)
++		return remote;
++	return all;
++}
++#else
++static inline enum fbq_type fbq_classify_group(struct sg_lb_stats *sgs)
++{
++	return all;
++}
++
++static inline enum fbq_type fbq_classify_rq(struct rq *rq)
++{
++	return regular;
++}
++#endif /* CONFIG_NUMA_BALANCING */
++
++/**
++ * update_sd_lb_stats - Update sched_domain's statistics for load balancing.
++ * @env: The load balancing environment.
++ * @sds: variable to hold the statistics for this sched_domain.
++ */
++static inline void update_sd_lb_stats(struct lb_env *env, struct sd_lb_stats *sds)
++{
++	struct sched_domain *child = env->sd->child;
++	struct sched_group *sg = env->sd->groups;
++	struct sg_lb_stats tmp_sgs;
++	int load_idx, prefer_sibling = 0;
++	bool overload = false;
++
++	if (child && child->flags & SD_PREFER_SIBLING)
++		prefer_sibling = 1;
++
++	load_idx = get_sd_load_idx(env->sd, env->idle);
++
++	do {
++		struct sg_lb_stats *sgs = &tmp_sgs;
++		int local_group;
++
++		local_group = cpumask_test_cpu(env->dst_cpu, sched_group_cpus(sg));
++		if (local_group) {
++			sds->local = sg;
++			sgs = &sds->local_stat;
++
++			if (env->idle != CPU_NEWLY_IDLE ||
++			    time_after_eq(jiffies, sg->sgc->next_update))
++				update_group_capacity(env->sd, env->dst_cpu);
++		}
++
++		update_sg_lb_stats(env, sg, load_idx, local_group, sgs,
++						&overload);
++
++		if (local_group)
++			goto next_group;
++
++		/*
++		 * In case the child domain prefers tasks go to siblings
++		 * first, lower the sg capacity factor to one so that we'll try
++		 * and move all the excess tasks away. We lower the capacity
++		 * of a group only if the local group has the capacity to fit
++		 * these excess tasks, i.e. nr_running < group_capacity_factor. The
++		 * extra check prevents the case where you always pull from the
++		 * heaviest group when it is already under-utilized (possible
++		 * with a large weight task outweighs the tasks on the system).
++		 */
++		if (prefer_sibling && sds->local &&
++		    sds->local_stat.group_has_free_capacity)
++			sgs->group_capacity_factor = min(sgs->group_capacity_factor, 1U);
++
++		if (update_sd_pick_busiest(env, sds, sg, sgs)) {
++			sds->busiest = sg;
++			sds->busiest_stat = *sgs;
++		}
++
++next_group:
++		/* Now, start updating sd_lb_stats */
++		sds->total_load += sgs->group_load;
++		sds->total_capacity += sgs->group_capacity;
++
++		sg = sg->next;
++	} while (sg != env->sd->groups);
++
++	if (env->sd->flags & SD_NUMA)
++		env->fbq_type = fbq_classify_group(&sds->busiest_stat);
++
++	if (!env->sd->parent) {
++		/* update overload indicator if we are at root domain */
++		if (env->dst_rq->rd->overload != overload)
++			env->dst_rq->rd->overload = overload;
++	}
++
++}
++
++/**
++ * check_asym_packing - Check to see if the group is packed into the
++ *			sched doman.
++ *
++ * This is primarily intended to used at the sibling level.  Some
++ * cores like POWER7 prefer to use lower numbered SMT threads.  In the
++ * case of POWER7, it can move to lower SMT modes only when higher
++ * threads are idle.  When in lower SMT modes, the threads will
++ * perform better since they share less core resources.  Hence when we
++ * have idle threads, we want them to be the higher ones.
++ *
++ * This packing function is run on idle threads.  It checks to see if
++ * the busiest CPU in this domain (core in the P7 case) has a higher
++ * CPU number than the packing function is being run on.  Here we are
++ * assuming lower CPU number will be equivalent to lower a SMT thread
++ * number.
++ *
++ * Return: 1 when packing is required and a task should be moved to
++ * this CPU.  The amount of the imbalance is returned in *imbalance.
++ *
++ * @env: The load balancing environment.
++ * @sds: Statistics of the sched_domain which is to be packed
++ */
++static int check_asym_packing(struct lb_env *env, struct sd_lb_stats *sds)
++{
++	int busiest_cpu;
++
++	if (!(env->sd->flags & SD_ASYM_PACKING))
++		return 0;
++
++	if (!sds->busiest)
++		return 0;
++
++	busiest_cpu = group_first_cpu(sds->busiest);
++	if (env->dst_cpu > busiest_cpu)
++		return 0;
++
++	env->imbalance = DIV_ROUND_CLOSEST(
++		sds->busiest_stat.avg_load * sds->busiest_stat.group_capacity,
++		SCHED_CAPACITY_SCALE);
++
++	return 1;
++}
++
++/**
++ * fix_small_imbalance - Calculate the minor imbalance that exists
++ *			amongst the groups of a sched_domain, during
++ *			load balancing.
++ * @env: The load balancing environment.
++ * @sds: Statistics of the sched_domain whose imbalance is to be calculated.
++ */
++static inline
++void fix_small_imbalance(struct lb_env *env, struct sd_lb_stats *sds)
++{
++	unsigned long tmp, capa_now = 0, capa_move = 0;
++	unsigned int imbn = 2;
++	unsigned long scaled_busy_load_per_task;
++	struct sg_lb_stats *local, *busiest;
++
++	local = &sds->local_stat;
++	busiest = &sds->busiest_stat;
++
++	if (!local->sum_nr_running)
++		local->load_per_task = cpu_avg_load_per_task(env->dst_cpu);
++	else if (busiest->load_per_task > local->load_per_task)
++		imbn = 1;
++
++	scaled_busy_load_per_task =
++		(busiest->load_per_task * SCHED_CAPACITY_SCALE) /
++		busiest->group_capacity;
++
++	if (busiest->avg_load + scaled_busy_load_per_task >=
++	    local->avg_load + (scaled_busy_load_per_task * imbn)) {
++		env->imbalance = busiest->load_per_task;
++		return;
++	}
++
++	/*
++	 * OK, we don't have enough imbalance to justify moving tasks,
++	 * however we may be able to increase total CPU capacity used by
++	 * moving them.
++	 */
++
++	capa_now += busiest->group_capacity *
++			min(busiest->load_per_task, busiest->avg_load);
++	capa_now += local->group_capacity *
++			min(local->load_per_task, local->avg_load);
++	capa_now /= SCHED_CAPACITY_SCALE;
++
++	/* Amount of load we'd subtract */
++	if (busiest->avg_load > scaled_busy_load_per_task) {
++		capa_move += busiest->group_capacity *
++			    min(busiest->load_per_task,
++				busiest->avg_load - scaled_busy_load_per_task);
++	}
++
++	/* Amount of load we'd add */
++	if (busiest->avg_load * busiest->group_capacity <
++	    busiest->load_per_task * SCHED_CAPACITY_SCALE) {
++		tmp = (busiest->avg_load * busiest->group_capacity) /
++		      local->group_capacity;
++	} else {
++		tmp = (busiest->load_per_task * SCHED_CAPACITY_SCALE) /
++		      local->group_capacity;
++	}
++	capa_move += local->group_capacity *
++		    min(local->load_per_task, local->avg_load + tmp);
++	capa_move /= SCHED_CAPACITY_SCALE;
++
++	/* Move if we gain throughput */
++	if (capa_move > capa_now)
++		env->imbalance = busiest->load_per_task;
++}
++
++/**
++ * calculate_imbalance - Calculate the amount of imbalance present within the
++ *			 groups of a given sched_domain during load balance.
++ * @env: load balance environment
++ * @sds: statistics of the sched_domain whose imbalance is to be calculated.
++ */
++static inline void calculate_imbalance(struct lb_env *env, struct sd_lb_stats *sds)
++{
++	unsigned long max_pull, load_above_capacity = ~0UL;
++	struct sg_lb_stats *local, *busiest;
++
++	local = &sds->local_stat;
++	busiest = &sds->busiest_stat;
++
++	if (busiest->group_type == group_imbalanced) {
++		/*
++		 * In the group_imb case we cannot rely on group-wide averages
++		 * to ensure cpu-load equilibrium, look at wider averages. XXX
++		 */
++		busiest->load_per_task =
++			min(busiest->load_per_task, sds->avg_load);
++	}
++
++	/*
++	 * In the presence of smp nice balancing, certain scenarios can have
++	 * max load less than avg load(as we skip the groups at or below
++	 * its cpu_capacity, while calculating max_load..)
++	 */
++	if (busiest->avg_load <= sds->avg_load ||
++	    local->avg_load >= sds->avg_load) {
++		env->imbalance = 0;
++		return fix_small_imbalance(env, sds);
++	}
++
++	/*
++	 * If there aren't any idle cpus, avoid creating some.
++	 */
++	if (busiest->group_type == group_overloaded &&
++	    local->group_type   == group_overloaded) {
++		load_above_capacity =
++			(busiest->sum_nr_running - busiest->group_capacity_factor);
++
++		load_above_capacity *= (SCHED_LOAD_SCALE * SCHED_CAPACITY_SCALE);
++		load_above_capacity /= busiest->group_capacity;
++	}
++
++	/*
++	 * We're trying to get all the cpus to the average_load, so we don't
++	 * want to push ourselves above the average load, nor do we wish to
++	 * reduce the max loaded cpu below the average load. At the same time,
++	 * we also don't want to reduce the group load below the group capacity
++	 * (so that we can implement power-savings policies etc). Thus we look
++	 * for the minimum possible imbalance.
++	 */
++	max_pull = min(busiest->avg_load - sds->avg_load, load_above_capacity);
++
++	/* How much load to actually move to equalise the imbalance */
++	env->imbalance = min(
++		max_pull * busiest->group_capacity,
++		(sds->avg_load - local->avg_load) * local->group_capacity
++	) / SCHED_CAPACITY_SCALE;
++
++	/*
++	 * if *imbalance is less than the average load per runnable task
++	 * there is no guarantee that any tasks will be moved so we'll have
++	 * a think about bumping its value to force at least one task to be
++	 * moved
++	 */
++	if (env->imbalance < busiest->load_per_task)
++		return fix_small_imbalance(env, sds);
++}
++
++/******* find_busiest_group() helpers end here *********************/
++
++/**
++ * find_busiest_group - Returns the busiest group within the sched_domain
++ * if there is an imbalance. If there isn't an imbalance, and
++ * the user has opted for power-savings, it returns a group whose
++ * CPUs can be put to idle by rebalancing those tasks elsewhere, if
++ * such a group exists.
++ *
++ * Also calculates the amount of weighted load which should be moved
++ * to restore balance.
++ *
++ * @env: The load balancing environment.
++ *
++ * Return:	- The busiest group if imbalance exists.
++ *		- If no imbalance and user has opted for power-savings balance,
++ *		   return the least loaded group whose CPUs can be
++ *		   put to idle by rebalancing its tasks onto our group.
++ */
++static struct sched_group *find_busiest_group(struct lb_env *env)
++{
++	struct sg_lb_stats *local, *busiest;
++	struct sd_lb_stats sds;
++
++	init_sd_lb_stats(&sds);
++
++	/*
++	 * Compute the various statistics relavent for load balancing at
++	 * this level.
++	 */
++	update_sd_lb_stats(env, &sds);
++	local = &sds.local_stat;
++	busiest = &sds.busiest_stat;
++
++	if ((env->idle == CPU_IDLE || env->idle == CPU_NEWLY_IDLE) &&
++	    check_asym_packing(env, &sds))
++		return sds.busiest;
++
++	/* There is no busy sibling group to pull tasks from */
++	if (!sds.busiest || busiest->sum_nr_running == 0)
++		goto out_balanced;
++
++	sds.avg_load = (SCHED_CAPACITY_SCALE * sds.total_load)
++						/ sds.total_capacity;
++
++	/*
++	 * If the busiest group is imbalanced the below checks don't
++	 * work because they assume all things are equal, which typically
++	 * isn't true due to cpus_allowed constraints and the like.
++	 */
++	if (busiest->group_type == group_imbalanced)
++		goto force_balance;
++
++	/* SD_BALANCE_NEWIDLE trumps SMP nice when underutilized */
++	if (env->idle == CPU_NEWLY_IDLE && local->group_has_free_capacity &&
++	    !busiest->group_has_free_capacity)
++		goto force_balance;
++
++	/*
++	 * If the local group is busier than the selected busiest group
++	 * don't try and pull any tasks.
++	 */
++	if (local->avg_load >= busiest->avg_load)
++		goto out_balanced;
++
++	/*
++	 * Don't pull any tasks if this group is already above the domain
++	 * average load.
++	 */
++	if (local->avg_load >= sds.avg_load)
++		goto out_balanced;
++
++	if (env->idle == CPU_IDLE) {
++		/*
++		 * This cpu is idle. If the busiest group is not overloaded
++		 * and there is no imbalance between this and busiest group
++		 * wrt idle cpus, it is balanced. The imbalance becomes
++		 * significant if the diff is greater than 1 otherwise we
++		 * might end up to just move the imbalance on another group
++		 */
++		if ((busiest->group_type != group_overloaded) &&
++				(local->idle_cpus <= (busiest->idle_cpus + 1)))
++			goto out_balanced;
++	} else {
++		/*
++		 * In the CPU_NEWLY_IDLE, CPU_NOT_IDLE cases, use
++		 * imbalance_pct to be conservative.
++		 */
++		if (100 * busiest->avg_load <=
++				env->sd->imbalance_pct * local->avg_load)
++			goto out_balanced;
++	}
++
++force_balance:
++	/* Looks like there is an imbalance. Compute it */
++	calculate_imbalance(env, &sds);
++	return sds.busiest;
++
++out_balanced:
++	env->imbalance = 0;
++	return NULL;
++}
++
++/*
++ * find_busiest_queue - find the busiest runqueue among the cpus in group.
++ */
++static struct rq *find_busiest_queue(struct lb_env *env,
++				     struct sched_group *group)
++{
++	struct rq *busiest = NULL, *rq;
++	unsigned long busiest_load = 0, busiest_capacity = 1;
++	int i;
++
++	for_each_cpu_and(i, sched_group_cpus(group), env->cpus) {
++		unsigned long capacity, capacity_factor, wl;
++		enum fbq_type rt;
++
++		rq = cpu_rq(i);
++		rt = fbq_classify_rq(rq);
++
++		/*
++		 * We classify groups/runqueues into three groups:
++		 *  - regular: there are !numa tasks
++		 *  - remote:  there are numa tasks that run on the 'wrong' node
++		 *  - all:     there is no distinction
++		 *
++		 * In order to avoid migrating ideally placed numa tasks,
++		 * ignore those when there's better options.
++		 *
++		 * If we ignore the actual busiest queue to migrate another
++		 * task, the next balance pass can still reduce the busiest
++		 * queue by moving tasks around inside the node.
++		 *
++		 * If we cannot move enough load due to this classification
++		 * the next pass will adjust the group classification and
++		 * allow migration of more tasks.
++		 *
++		 * Both cases only affect the total convergence complexity.
++		 */
++		if (rt > env->fbq_type)
++			continue;
++
++		capacity = capacity_of(i);
++		capacity_factor = DIV_ROUND_CLOSEST(capacity, SCHED_CAPACITY_SCALE);
++		if (!capacity_factor)
++			capacity_factor = fix_small_capacity(env->sd, group);
++
++		wl = weighted_cpuload(i);
++
++		/*
++		 * When comparing with imbalance, use weighted_cpuload()
++		 * which is not scaled with the cpu capacity.
++		 */
++		if (capacity_factor && rq->nr_running == 1 && wl > env->imbalance)
++			continue;
++
++		/*
++		 * For the load comparisons with the other cpu's, consider
++		 * the weighted_cpuload() scaled with the cpu capacity, so
++		 * that the load can be moved away from the cpu that is
++		 * potentially running at a lower capacity.
++		 *
++		 * Thus we're looking for max(wl_i / capacity_i), crosswise
++		 * multiplication to rid ourselves of the division works out
++		 * to: wl_i * capacity_j > wl_j * capacity_i;  where j is
++		 * our previous maximum.
++		 */
++		if (wl * busiest_capacity > busiest_load * capacity) {
++			busiest_load = wl;
++			busiest_capacity = capacity;
++			busiest = rq;
++		}
++	}
++
++	return busiest;
++}
++
++/*
++ * Max backoff if we encounter pinned tasks. Pretty arbitrary value, but
++ * so long as it is large enough.
++ */
++#define MAX_PINNED_INTERVAL	512
++
++/* Working cpumask for load_balance and load_balance_newidle. */
++DEFINE_PER_CPU(cpumask_var_t, load_balance_mask);
++
++static int need_active_balance(struct lb_env *env)
++{
++	struct sched_domain *sd = env->sd;
++
++	if (env->idle == CPU_NEWLY_IDLE) {
++
++		/*
++		 * ASYM_PACKING needs to force migrate tasks from busy but
++		 * higher numbered CPUs in order to pack all tasks in the
++		 * lowest numbered CPUs.
++		 */
++		if ((sd->flags & SD_ASYM_PACKING) && env->src_cpu > env->dst_cpu)
++			return 1;
++	}
++
++	return unlikely(sd->nr_balance_failed > sd->cache_nice_tries+2);
++}
++
++static int active_load_balance_cpu_stop(void *data);
++
++static int should_we_balance(struct lb_env *env)
++{
++	struct sched_group *sg = env->sd->groups;
++	struct cpumask *sg_cpus, *sg_mask;
++	int cpu, balance_cpu = -1;
++
++	/*
++	 * In the newly idle case, we will allow all the cpu's
++	 * to do the newly idle load balance.
++	 */
++	if (env->idle == CPU_NEWLY_IDLE)
++		return 1;
++
++	sg_cpus = sched_group_cpus(sg);
++	sg_mask = sched_group_mask(sg);
++	/* Try to find first idle cpu */
++	for_each_cpu_and(cpu, sg_cpus, env->cpus) {
++		if (!cpumask_test_cpu(cpu, sg_mask) || !idle_cpu(cpu))
++			continue;
++
++		balance_cpu = cpu;
++		break;
++	}
++
++	if (balance_cpu == -1)
++		balance_cpu = group_balance_cpu(sg);
++
++	/*
++	 * First idle cpu or the first cpu(busiest) in this sched group
++	 * is eligible for doing load balancing at this and above domains.
++	 */
++	return balance_cpu == env->dst_cpu;
++}
++
++/*
++ * Check this_cpu to ensure it is balanced within domain. Attempt to move
++ * tasks if there is an imbalance.
++ */
++static int load_balance(int this_cpu, struct rq *this_rq,
++			struct sched_domain *sd, enum cpu_idle_type idle,
++			int *continue_balancing)
++{
++	int ld_moved, cur_ld_moved, active_balance = 0;
++	struct sched_domain *sd_parent = sd->parent;
++	struct sched_group *group;
++	struct rq *busiest;
++	unsigned long flags;
++	struct cpumask *cpus = this_cpu_cpumask_var_ptr(load_balance_mask);
++
++	struct lb_env env = {
++		.sd		= sd,
++		.dst_cpu	= this_cpu,
++		.dst_rq		= this_rq,
++		.dst_grpmask    = sched_group_cpus(sd->groups),
++		.idle		= idle,
++		.loop_break	= sched_nr_migrate_break,
++		.cpus		= cpus,
++		.fbq_type	= all,
++		.tasks		= LIST_HEAD_INIT(env.tasks),
++	};
++
++	/*
++	 * For NEWLY_IDLE load_balancing, we don't need to consider
++	 * other cpus in our group
++	 */
++	if (idle == CPU_NEWLY_IDLE)
++		env.dst_grpmask = NULL;
++
++	cpumask_copy(cpus, cpu_active_mask);
++
++	schedstat_inc(sd, lb_count[idle]);
++
++redo:
++	if (!should_we_balance(&env)) {
++		*continue_balancing = 0;
++		goto out_balanced;
++	}
++
++	group = find_busiest_group(&env);
++	if (!group) {
++		schedstat_inc(sd, lb_nobusyg[idle]);
++		goto out_balanced;
++	}
++
++	busiest = find_busiest_queue(&env, group);
++	if (!busiest) {
++		schedstat_inc(sd, lb_nobusyq[idle]);
++		goto out_balanced;
++	}
++
++	BUG_ON(busiest == env.dst_rq);
++
++	schedstat_add(sd, lb_imbalance[idle], env.imbalance);
++
++	ld_moved = 0;
++	if (busiest->nr_running > 1) {
++		/*
++		 * Attempt to move tasks. If find_busiest_group has found
++		 * an imbalance but busiest->nr_running <= 1, the group is
++		 * still unbalanced. ld_moved simply stays zero, so it is
++		 * correctly treated as an imbalance.
++		 */
++		env.flags |= LBF_ALL_PINNED;
++		env.src_cpu   = busiest->cpu;
++		env.src_rq    = busiest;
++		env.loop_max  = min(sysctl_sched_nr_migrate, busiest->nr_running);
++
++more_balance:
++		raw_spin_lock_irqsave(&busiest->lock, flags);
++
++		/*
++		 * cur_ld_moved - load moved in current iteration
++		 * ld_moved     - cumulative load moved across iterations
++		 */
++		cur_ld_moved = detach_tasks(&env);
++
++		/*
++		 * We've detached some tasks from busiest_rq. Every
++		 * task is masked "TASK_ON_RQ_MIGRATING", so we can safely
++		 * unlock busiest->lock, and we are able to be sure
++		 * that nobody can manipulate the tasks in parallel.
++		 * See task_rq_lock() family for the details.
++		 */
++
++		raw_spin_unlock(&busiest->lock);
++
++		if (cur_ld_moved) {
++			attach_tasks(&env);
++			ld_moved += cur_ld_moved;
++		}
++
++		local_irq_restore(flags);
++
++		if (env.flags & LBF_NEED_BREAK) {
++			env.flags &= ~LBF_NEED_BREAK;
++			goto more_balance;
++		}
++
++		/*
++		 * Revisit (affine) tasks on src_cpu that couldn't be moved to
++		 * us and move them to an alternate dst_cpu in our sched_group
++		 * where they can run. The upper limit on how many times we
++		 * iterate on same src_cpu is dependent on number of cpus in our
++		 * sched_group.
++		 *
++		 * This changes load balance semantics a bit on who can move
++		 * load to a given_cpu. In addition to the given_cpu itself
++		 * (or a ilb_cpu acting on its behalf where given_cpu is
++		 * nohz-idle), we now have balance_cpu in a position to move
++		 * load to given_cpu. In rare situations, this may cause
++		 * conflicts (balance_cpu and given_cpu/ilb_cpu deciding
++		 * _independently_ and at _same_ time to move some load to
++		 * given_cpu) causing exceess load to be moved to given_cpu.
++		 * This however should not happen so much in practice and
++		 * moreover subsequent load balance cycles should correct the
++		 * excess load moved.
++		 */
++		if ((env.flags & LBF_DST_PINNED) && env.imbalance > 0) {
++
++			/* Prevent to re-select dst_cpu via env's cpus */
++			cpumask_clear_cpu(env.dst_cpu, env.cpus);
++
++			env.dst_rq	 = cpu_rq(env.new_dst_cpu);
++			env.dst_cpu	 = env.new_dst_cpu;
++			env.flags	&= ~LBF_DST_PINNED;
++			env.loop	 = 0;
++			env.loop_break	 = sched_nr_migrate_break;
++
++			/*
++			 * Go back to "more_balance" rather than "redo" since we
++			 * need to continue with same src_cpu.
++			 */
++			goto more_balance;
++		}
++
++		/*
++		 * We failed to reach balance because of affinity.
++		 */
++		if (sd_parent) {
++			int *group_imbalance = &sd_parent->groups->sgc->imbalance;
++
++			if ((env.flags & LBF_SOME_PINNED) && env.imbalance > 0)
++				*group_imbalance = 1;
++		}
++
++		/* All tasks on this runqueue were pinned by CPU affinity */
++		if (unlikely(env.flags & LBF_ALL_PINNED)) {
++			cpumask_clear_cpu(cpu_of(busiest), cpus);
++			if (!cpumask_empty(cpus)) {
++				env.loop = 0;
++				env.loop_break = sched_nr_migrate_break;
++				goto redo;
++			}
++			goto out_all_pinned;
++		}
++	}
++
++	if (!ld_moved) {
++		schedstat_inc(sd, lb_failed[idle]);
++		/*
++		 * Increment the failure counter only on periodic balance.
++		 * We do not want newidle balance, which can be very
++		 * frequent, pollute the failure counter causing
++		 * excessive cache_hot migrations and active balances.
++		 */
++		if (idle != CPU_NEWLY_IDLE)
++			sd->nr_balance_failed++;
+ 
+-	if (child && child->flags & SD_PREFER_SIBLING)
+-		prefer_sibling = 1;
++		if (need_active_balance(&env)) {
++			raw_spin_lock_irqsave(&busiest->lock, flags);
+ 
+-	load_idx = get_sd_load_idx(env->sd, env->idle);
++			/* don't kick the active_load_balance_cpu_stop,
++			 * if the curr task on busiest cpu can't be
++			 * moved to this_cpu
++			 */
++			if (!cpumask_test_cpu(this_cpu,
++					tsk_cpus_allowed(busiest->curr))) {
++				raw_spin_unlock_irqrestore(&busiest->lock,
++							    flags);
++				env.flags |= LBF_ALL_PINNED;
++				goto out_one_pinned;
++			}
+ 
+-	do {
+-		struct sg_lb_stats *sgs = &tmp_sgs;
+-		int local_group;
++			/*
++			 * ->active_balance synchronizes accesses to
++			 * ->active_balance_work.  Once set, it's cleared
++			 * only after active load balance is finished.
++			 */
++			if (!busiest->active_balance) {
++				busiest->active_balance = 1;
++				busiest->push_cpu = this_cpu;
++				active_balance = 1;
++			}
++			raw_spin_unlock_irqrestore(&busiest->lock, flags);
+ 
+-		local_group = cpumask_test_cpu(env->dst_cpu, sched_group_cpus(sg));
+-		if (local_group) {
+-			sds->local = sg;
+-			sgs = &sds->local_stat;
++			if (active_balance) {
++				stop_one_cpu_nowait(cpu_of(busiest),
++					active_load_balance_cpu_stop, busiest,
++					&busiest->active_balance_work);
++			}
+ 
+-			if (env->idle != CPU_NEWLY_IDLE ||
+-			    time_after_eq(jiffies, sg->sgc->next_update))
+-				update_group_capacity(env->sd, env->dst_cpu);
++			/*
++			 * We've kicked active balancing, reset the failure
++			 * counter.
++			 */
++			sd->nr_balance_failed = sd->cache_nice_tries+1;
+ 		}
++	} else
++		sd->nr_balance_failed = 0;
+ 
+-		update_sg_lb_stats(env, sg, load_idx, local_group, sgs,
+-						&overload);
+-
+-		if (local_group)
+-			goto next_group;
+-
++	if (likely(!active_balance)) {
++		/* We were unbalanced, so reset the balancing interval */
++		sd->balance_interval = sd->min_interval;
++	} else {
+ 		/*
+-		 * In case the child domain prefers tasks go to siblings
+-		 * first, lower the sg capacity factor to one so that we'll try
+-		 * and move all the excess tasks away. We lower the capacity
+-		 * of a group only if the local group has the capacity to fit
+-		 * these excess tasks, i.e. nr_running < group_capacity_factor. The
+-		 * extra check prevents the case where you always pull from the
+-		 * heaviest group when it is already under-utilized (possible
+-		 * with a large weight task outweighs the tasks on the system).
++		 * If we've begun active balancing, start to back off. This
++		 * case may not be covered by the all_pinned logic if there
++		 * is only 1 task on the busy runqueue (because we don't call
++		 * detach_tasks).
+ 		 */
+-		if (prefer_sibling && sds->local &&
+-		    sds->local_stat.group_has_free_capacity)
+-			sgs->group_capacity_factor = min(sgs->group_capacity_factor, 1U);
++		if (sd->balance_interval < sd->max_interval)
++			sd->balance_interval *= 2;
++	}
+ 
+-		if (update_sd_pick_busiest(env, sds, sg, sgs)) {
+-			sds->busiest = sg;
+-			sds->busiest_stat = *sgs;
+-		}
++	goto out;
+ 
+-next_group:
+-		/* Now, start updating sd_lb_stats */
+-		sds->total_load += sgs->group_load;
+-		sds->total_capacity += sgs->group_capacity;
++out_balanced:
++	/*
++	 * We reach balance although we may have faced some affinity
++	 * constraints. Clear the imbalance flag if it was set.
++	 */
++	if (sd_parent) {
++		int *group_imbalance = &sd_parent->groups->sgc->imbalance;
+ 
+-		sg = sg->next;
+-	} while (sg != env->sd->groups);
++		if (*group_imbalance)
++			*group_imbalance = 0;
++	}
+ 
+-	if (env->sd->flags & SD_NUMA)
+-		env->fbq_type = fbq_classify_group(&sds->busiest_stat);
++out_all_pinned:
++	/*
++	 * We reach balance because all tasks are pinned at this level so
++	 * we can't migrate them. Let the imbalance flag set so parent level
++	 * can try to migrate them.
++	 */
++	schedstat_inc(sd, lb_balanced[idle]);
+ 
+-	if (!env->sd->parent) {
+-		/* update overload indicator if we are at root domain */
+-		if (env->dst_rq->rd->overload != overload)
+-			env->dst_rq->rd->overload = overload;
+-	}
++	sd->nr_balance_failed = 0;
++
++out_one_pinned:
++	/* tune up the balancing interval */
++	if (((env.flags & LBF_ALL_PINNED) &&
++			sd->balance_interval < MAX_PINNED_INTERVAL) ||
++			(sd->balance_interval < sd->max_interval))
++		sd->balance_interval *= 2;
+ 
++	ld_moved = 0;
++out:
++	return ld_moved;
+ }
+ 
+-/**
+- * check_asym_packing - Check to see if the group is packed into the
+- *			sched doman.
+- *
+- * This is primarily intended to used at the sibling level.  Some
+- * cores like POWER7 prefer to use lower numbered SMT threads.  In the
+- * case of POWER7, it can move to lower SMT modes only when higher
+- * threads are idle.  When in lower SMT modes, the threads will
+- * perform better since they share less core resources.  Hence when we
+- * have idle threads, we want them to be the higher ones.
+- *
+- * This packing function is run on idle threads.  It checks to see if
+- * the busiest CPU in this domain (core in the P7 case) has a higher
+- * CPU number than the packing function is being run on.  Here we are
+- * assuming lower CPU number will be equivalent to lower a SMT thread
+- * number.
+- *
+- * Return: 1 when packing is required and a task should be moved to
+- * this CPU.  The amount of the imbalance is returned in *imbalance.
+- *
+- * @env: The load balancing environment.
+- * @sds: Statistics of the sched_domain which is to be packed
+- */
+-static int check_asym_packing(struct lb_env *env, struct sd_lb_stats *sds)
++static inline unsigned long
++get_sd_balance_interval(struct sched_domain *sd, int cpu_busy)
+ {
+-	int busiest_cpu;
++	unsigned long interval = sd->balance_interval;
+ 
+-	if (!(env->sd->flags & SD_ASYM_PACKING))
+-		return 0;
++	if (cpu_busy)
++		interval *= sd->busy_factor;
+ 
+-	if (!sds->busiest)
+-		return 0;
++	/* scale ms to jiffies */
++	interval = msecs_to_jiffies(interval);
++	interval = clamp(interval, 1UL, max_load_balance_interval);
+ 
+-	busiest_cpu = group_first_cpu(sds->busiest);
+-	if (env->dst_cpu > busiest_cpu)
+-		return 0;
++	return interval;
++}
+ 
+-	env->imbalance = DIV_ROUND_CLOSEST(
+-		sds->busiest_stat.avg_load * sds->busiest_stat.group_capacity,
+-		SCHED_CAPACITY_SCALE);
++static inline void
++update_next_balance(struct sched_domain *sd, int cpu_busy, unsigned long *next_balance)
++{
++	unsigned long interval, next;
+ 
+-	return 1;
++	interval = get_sd_balance_interval(sd, cpu_busy);
++	next = sd->last_balance + interval;
++
++	if (time_after(*next_balance, next))
++		*next_balance = next;
+ }
+ 
+-/**
+- * fix_small_imbalance - Calculate the minor imbalance that exists
+- *			amongst the groups of a sched_domain, during
+- *			load balancing.
+- * @env: The load balancing environment.
+- * @sds: Statistics of the sched_domain whose imbalance is to be calculated.
++/*
++ * idle_balance is called by schedule() if this_cpu is about to become
++ * idle. Attempts to pull tasks from other CPUs.
+  */
+-static inline
+-void fix_small_imbalance(struct lb_env *env, struct sd_lb_stats *sds)
++static int idle_balance(struct rq *this_rq)
+ {
+-	unsigned long tmp, capa_now = 0, capa_move = 0;
+-	unsigned int imbn = 2;
+-	unsigned long scaled_busy_load_per_task;
+-	struct sg_lb_stats *local, *busiest;
++	unsigned long next_balance = jiffies + HZ;
++	int this_cpu = this_rq->cpu;
++	struct sched_domain *sd;
++	int pulled_task = 0;
++	u64 curr_cost = 0;
+ 
+-	local = &sds->local_stat;
+-	busiest = &sds->busiest_stat;
++	idle_enter_fair(this_rq);
+ 
+-	if (!local->sum_nr_running)
+-		local->load_per_task = cpu_avg_load_per_task(env->dst_cpu);
+-	else if (busiest->load_per_task > local->load_per_task)
+-		imbn = 1;
++	/*
++	 * We must set idle_stamp _before_ calling idle_balance(), such that we
++	 * measure the duration of idle_balance() as idle time.
++	 */
++	this_rq->idle_stamp = rq_clock(this_rq);
+ 
+-	scaled_busy_load_per_task =
+-		(busiest->load_per_task * SCHED_CAPACITY_SCALE) /
+-		busiest->group_capacity;
++	if (this_rq->avg_idle < sysctl_sched_migration_cost ||
++	    !this_rq->rd->overload) {
++		rcu_read_lock();
++		sd = rcu_dereference_check_sched_domain(this_rq->sd);
++		if (sd)
++			update_next_balance(sd, 0, &next_balance);
++		rcu_read_unlock();
+ 
+-	if (busiest->avg_load + scaled_busy_load_per_task >=
+-	    local->avg_load + (scaled_busy_load_per_task * imbn)) {
+-		env->imbalance = busiest->load_per_task;
+-		return;
++		goto out;
+ 	}
+ 
+ 	/*
+-	 * OK, we don't have enough imbalance to justify moving tasks,
+-	 * however we may be able to increase total CPU capacity used by
+-	 * moving them.
++	 * Drop the rq->lock, but keep IRQ/preempt disabled.
+ 	 */
++	raw_spin_unlock(&this_rq->lock);
+ 
+-	capa_now += busiest->group_capacity *
+-			min(busiest->load_per_task, busiest->avg_load);
+-	capa_now += local->group_capacity *
+-			min(local->load_per_task, local->avg_load);
+-	capa_now /= SCHED_CAPACITY_SCALE;
++	update_blocked_averages(this_cpu);
++	rcu_read_lock();
++	for_each_domain(this_cpu, sd) {
++		int continue_balancing = 1;
++		u64 t0, domain_cost;
+ 
+-	/* Amount of load we'd subtract */
+-	if (busiest->avg_load > scaled_busy_load_per_task) {
+-		capa_move += busiest->group_capacity *
+-			    min(busiest->load_per_task,
+-				busiest->avg_load - scaled_busy_load_per_task);
+-	}
++		if (!(sd->flags & SD_LOAD_BALANCE))
++			continue;
++
++		if (this_rq->avg_idle < curr_cost + sd->max_newidle_lb_cost) {
++			update_next_balance(sd, 0, &next_balance);
++			break;
++		}
++
++		if (sd->flags & SD_BALANCE_NEWIDLE) {
++			t0 = sched_clock_cpu(this_cpu);
+ 
+-	/* Amount of load we'd add */
+-	if (busiest->avg_load * busiest->group_capacity <
+-	    busiest->load_per_task * SCHED_CAPACITY_SCALE) {
+-		tmp = (busiest->avg_load * busiest->group_capacity) /
+-		      local->group_capacity;
+-	} else {
+-		tmp = (busiest->load_per_task * SCHED_CAPACITY_SCALE) /
+-		      local->group_capacity;
+-	}
+-	capa_move += local->group_capacity *
+-		    min(local->load_per_task, local->avg_load + tmp);
+-	capa_move /= SCHED_CAPACITY_SCALE;
++			pulled_task = load_balance(this_cpu, this_rq,
++						   sd, CPU_NEWLY_IDLE,
++						   &continue_balancing);
+ 
+-	/* Move if we gain throughput */
+-	if (capa_move > capa_now)
+-		env->imbalance = busiest->load_per_task;
+-}
++			domain_cost = sched_clock_cpu(this_cpu) - t0;
++			if (domain_cost > sd->max_newidle_lb_cost)
++				sd->max_newidle_lb_cost = domain_cost;
+ 
+-/**
+- * calculate_imbalance - Calculate the amount of imbalance present within the
+- *			 groups of a given sched_domain during load balance.
+- * @env: load balance environment
+- * @sds: statistics of the sched_domain whose imbalance is to be calculated.
+- */
+-static inline void calculate_imbalance(struct lb_env *env, struct sd_lb_stats *sds)
+-{
+-	unsigned long max_pull, load_above_capacity = ~0UL;
+-	struct sg_lb_stats *local, *busiest;
++			curr_cost += domain_cost;
++		}
+ 
+-	local = &sds->local_stat;
+-	busiest = &sds->busiest_stat;
++		update_next_balance(sd, 0, &next_balance);
+ 
+-	if (busiest->group_type == group_imbalanced) {
+ 		/*
+-		 * In the group_imb case we cannot rely on group-wide averages
+-		 * to ensure cpu-load equilibrium, look at wider averages. XXX
++		 * Stop searching for tasks to pull if there are
++		 * now runnable tasks on this rq.
+ 		 */
+-		busiest->load_per_task =
+-			min(busiest->load_per_task, sds->avg_load);
++		if (pulled_task || this_rq->nr_running > 0)
++			break;
+ 	}
++	rcu_read_unlock();
++#ifdef CONFIG_SCHED_HMP
++	if (!pulled_task)
++		pulled_task = hmp_idle_pull(this_cpu);
++#endif
++	raw_spin_lock(&this_rq->lock);
+ 
+-	/*
+-	 * In the presence of smp nice balancing, certain scenarios can have
+-	 * max load less than avg load(as we skip the groups at or below
+-	 * its cpu_capacity, while calculating max_load..)
+-	 */
+-	if (busiest->avg_load <= sds->avg_load ||
+-	    local->avg_load >= sds->avg_load) {
+-		env->imbalance = 0;
+-		return fix_small_imbalance(env, sds);
+-	}
++	if (curr_cost > this_rq->max_idle_balance_cost)
++		this_rq->max_idle_balance_cost = curr_cost;
+ 
+ 	/*
+-	 * If there aren't any idle cpus, avoid creating some.
++	 * While browsing the domains, we released the rq lock, a task could
++	 * have been enqueued in the meantime. Since we're not going idle,
++	 * pretend we pulled a task.
+ 	 */
+-	if (busiest->group_type == group_overloaded &&
+-	    local->group_type   == group_overloaded) {
+-		load_above_capacity =
+-			(busiest->sum_nr_running - busiest->group_capacity_factor);
++	if (this_rq->cfs.h_nr_running && !pulled_task)
++		pulled_task = 1;
+ 
+-		load_above_capacity *= (SCHED_LOAD_SCALE * SCHED_CAPACITY_SCALE);
+-		load_above_capacity /= busiest->group_capacity;
+-	}
++out:
++	/* Move the next balance forward */
++	if (time_after(this_rq->next_balance, next_balance))
++		this_rq->next_balance = next_balance;
+ 
+-	/*
+-	 * We're trying to get all the cpus to the average_load, so we don't
+-	 * want to push ourselves above the average load, nor do we wish to
+-	 * reduce the max loaded cpu below the average load. At the same time,
+-	 * we also don't want to reduce the group load below the group capacity
+-	 * (so that we can implement power-savings policies etc). Thus we look
+-	 * for the minimum possible imbalance.
+-	 */
+-	max_pull = min(busiest->avg_load - sds->avg_load, load_above_capacity);
++	/* Is there a task of a high priority class? */
++	if (this_rq->nr_running != this_rq->cfs.h_nr_running)
++		pulled_task = -1;
+ 
+-	/* How much load to actually move to equalise the imbalance */
+-	env->imbalance = min(
+-		max_pull * busiest->group_capacity,
+-		(sds->avg_load - local->avg_load) * local->group_capacity
+-	) / SCHED_CAPACITY_SCALE;
++	if (pulled_task) {
++		idle_exit_fair(this_rq);
++		this_rq->idle_stamp = 0;
++	}
+ 
+-	/*
+-	 * if *imbalance is less than the average load per runnable task
+-	 * there is no guarantee that any tasks will be moved so we'll have
+-	 * a think about bumping its value to force at least one task to be
+-	 * moved
+-	 */
+-	if (env->imbalance < busiest->load_per_task)
+-		return fix_small_imbalance(env, sds);
++	return pulled_task;
+ }
+ 
+-/******* find_busiest_group() helpers end here *********************/
+-
+-/**
+- * find_busiest_group - Returns the busiest group within the sched_domain
+- * if there is an imbalance. If there isn't an imbalance, and
+- * the user has opted for power-savings, it returns a group whose
+- * CPUs can be put to idle by rebalancing those tasks elsewhere, if
+- * such a group exists.
+- *
+- * Also calculates the amount of weighted load which should be moved
+- * to restore balance.
+- *
+- * @env: The load balancing environment.
+- *
+- * Return:	- The busiest group if imbalance exists.
+- *		- If no imbalance and user has opted for power-savings balance,
+- *		   return the least loaded group whose CPUs can be
+- *		   put to idle by rebalancing its tasks onto our group.
++/*
++ * active_load_balance_cpu_stop is run by cpu stopper. It pushes
++ * running tasks off the busiest CPU onto idle CPUs. It requires at
++ * least 1 task to be running on each physical CPU where possible, and
++ * avoids physical / logical imbalances.
+  */
+-static struct sched_group *find_busiest_group(struct lb_env *env)
++static int active_load_balance_cpu_stop(void *data)
+ {
+-	struct sg_lb_stats *local, *busiest;
+-	struct sd_lb_stats sds;
++	struct rq *busiest_rq = data;
++	int busiest_cpu = cpu_of(busiest_rq);
++	int target_cpu = busiest_rq->push_cpu;
++	struct rq *target_rq = cpu_rq(target_cpu);
++	struct sched_domain *sd;
++	struct task_struct *p = NULL;
+ 
+-	init_sd_lb_stats(&sds);
++	raw_spin_lock_irq(&busiest_rq->lock);
++
++	/* make sure the requested cpu hasn't gone down in the meantime */
++	if (unlikely(busiest_cpu != smp_processor_id() ||
++		     !busiest_rq->active_balance))
++		goto out_unlock;
++
++	/* Is there any task to move? */
++	if (busiest_rq->nr_running <= 1)
++		goto out_unlock;
+ 
+ 	/*
+-	 * Compute the various statistics relavent for load balancing at
+-	 * this level.
++	 * This condition is "impossible", if it occurs
++	 * we need to fix it. Originally reported by
++	 * Bjorn Helgaas on a 128-cpu setup.
+ 	 */
+-	update_sd_lb_stats(env, &sds);
+-	local = &sds.local_stat;
+-	busiest = &sds.busiest_stat;
++	BUG_ON(busiest_rq == target_rq);
+ 
+-	if ((env->idle == CPU_IDLE || env->idle == CPU_NEWLY_IDLE) &&
+-	    check_asym_packing(env, &sds))
+-		return sds.busiest;
++	/* Search for an sd spanning us and the target CPU. */
++	rcu_read_lock();
++	for_each_domain(target_cpu, sd) {
++		if ((sd->flags & SD_LOAD_BALANCE) &&
++		    cpumask_test_cpu(busiest_cpu, sched_domain_span(sd)))
++				break;
++	}
+ 
+-	/* There is no busy sibling group to pull tasks from */
+-	if (!sds.busiest || busiest->sum_nr_running == 0)
+-		goto out_balanced;
++	if (likely(sd)) {
++		struct lb_env env = {
++			.sd		= sd,
++			.dst_cpu	= target_cpu,
++			.dst_rq		= target_rq,
++			.src_cpu	= busiest_rq->cpu,
++			.src_rq		= busiest_rq,
++			.idle		= CPU_IDLE,
++		};
+ 
+-	sds.avg_load = (SCHED_CAPACITY_SCALE * sds.total_load)
+-						/ sds.total_capacity;
++		schedstat_inc(sd, alb_count);
+ 
+-	/*
+-	 * If the busiest group is imbalanced the below checks don't
+-	 * work because they assume all things are equal, which typically
+-	 * isn't true due to cpus_allowed constraints and the like.
+-	 */
+-	if (busiest->group_type == group_imbalanced)
+-		goto force_balance;
++		p = detach_one_task(&env);
++		if (p)
++			schedstat_inc(sd, alb_pushed);
++		else
++			schedstat_inc(sd, alb_failed);
++	}
++	rcu_read_unlock();
++out_unlock:
++	busiest_rq->active_balance = 0;
++	raw_spin_unlock(&busiest_rq->lock);
+ 
+-	/* SD_BALANCE_NEWIDLE trumps SMP nice when underutilized */
+-	if (env->idle == CPU_NEWLY_IDLE && local->group_has_free_capacity &&
+-	    !busiest->group_has_free_capacity)
+-		goto force_balance;
++	if (p)
++		attach_one_task(target_rq, p);
+ 
+-	/*
+-	 * If the local group is busier than the selected busiest group
+-	 * don't try and pull any tasks.
+-	 */
+-	if (local->avg_load >= busiest->avg_load)
+-		goto out_balanced;
++	local_irq_enable();
+ 
+-	/*
+-	 * Don't pull any tasks if this group is already above the domain
+-	 * average load.
+-	 */
+-	if (local->avg_load >= sds.avg_load)
+-		goto out_balanced;
++	return 0;
++}
+ 
+-	if (env->idle == CPU_IDLE) {
+-		/*
+-		 * This cpu is idle. If the busiest group is not overloaded
+-		 * and there is no imbalance between this and busiest group
+-		 * wrt idle cpus, it is balanced. The imbalance becomes
+-		 * significant if the diff is greater than 1 otherwise we
+-		 * might end up to just move the imbalance on another group
+-		 */
+-		if ((busiest->group_type != group_overloaded) &&
+-				(local->idle_cpus <= (busiest->idle_cpus + 1)))
+-			goto out_balanced;
+-	} else {
+-		/*
+-		 * In the CPU_NEWLY_IDLE, CPU_NOT_IDLE cases, use
+-		 * imbalance_pct to be conservative.
+-		 */
+-		if (100 * busiest->avg_load <=
+-				env->sd->imbalance_pct * local->avg_load)
+-			goto out_balanced;
+-	}
++static inline int on_null_domain(struct rq *rq)
++{
++	return unlikely(!rcu_dereference_sched(rq->sd));
++}
+ 
+-force_balance:
+-	/* Looks like there is an imbalance. Compute it */
+-	calculate_imbalance(env, &sds);
+-	return sds.busiest;
++#ifdef CONFIG_NO_HZ_COMMON
++/*
++ * idle load balancing details
++ * - When one of the busy CPUs notice that there may be an idle rebalancing
++ *   needed, they will kick the idle load balancer, which then does idle
++ *   load balancing for all the idle CPUs.
++ */
++static struct {
++	cpumask_var_t idle_cpus_mask;
++	atomic_t nr_cpus;
++	unsigned long next_balance;     /* in jiffy units */
++} nohz ____cacheline_aligned;
+ 
+-out_balanced:
+-	env->imbalance = 0;
+-	return NULL;
++/*
++ * nohz_test_cpu used when load tracking is enabled. FAIR_GROUP_SCHED
++ * dependency below may be removed when load tracking guards are
++ * removed.
++ */
++#ifdef CONFIG_FAIR_GROUP_SCHED
++static int nohz_test_cpu(int cpu)
++{
++	return cpumask_test_cpu(cpu, nohz.idle_cpus_mask);
+ }
++#endif
+ 
++#ifdef CONFIG_SCHED_HMP_LITTLE_PACKING
+ /*
+- * find_busiest_queue - find the busiest runqueue among the cpus in group.
++ * Decide if the tasks on the busy CPUs in the
++ * littlest domain would benefit from an idle balance
+  */
+-static struct rq *find_busiest_queue(struct lb_env *env,
+-				     struct sched_group *group)
++static int hmp_packing_ilb_needed(int cpu, int ilb_needed)
+ {
+-	struct rq *busiest = NULL, *rq;
+-	unsigned long busiest_load = 0, busiest_capacity = 1;
+-	int i;
+-
+-	for_each_cpu_and(i, sched_group_cpus(group), env->cpus) {
+-		unsigned long capacity, capacity_factor, wl;
+-		enum fbq_type rt;
+-
+-		rq = cpu_rq(i);
+-		rt = fbq_classify_rq(rq);
+-
+-		/*
+-		 * We classify groups/runqueues into three groups:
+-		 *  - regular: there are !numa tasks
+-		 *  - remote:  there are numa tasks that run on the 'wrong' node
+-		 *  - all:     there is no distinction
+-		 *
+-		 * In order to avoid migrating ideally placed numa tasks,
+-		 * ignore those when there's better options.
+-		 *
+-		 * If we ignore the actual busiest queue to migrate another
+-		 * task, the next balance pass can still reduce the busiest
+-		 * queue by moving tasks around inside the node.
+-		 *
+-		 * If we cannot move enough load due to this classification
+-		 * the next pass will adjust the group classification and
+-		 * allow migration of more tasks.
+-		 *
+-		 * Both cases only affect the total convergence complexity.
+-		 */
+-		if (rt > env->fbq_type)
+-			continue;
+-
+-		capacity = capacity_of(i);
+-		capacity_factor = DIV_ROUND_CLOSEST(capacity, SCHED_CAPACITY_SCALE);
+-		if (!capacity_factor)
+-			capacity_factor = fix_small_capacity(env->sd, group);
++	struct hmp_domain *hmp;
++	/* allow previous decision on non-slowest domain */
++	if (!hmp_cpu_is_slowest(cpu))
++		return ilb_needed;
+ 
+-		wl = weighted_cpuload(i);
++	/* if disabled, use normal ILB behaviour */
++	if (!hmp_packing_enabled)
++		return ilb_needed;
+ 
+-		/*
+-		 * When comparing with imbalance, use weighted_cpuload()
+-		 * which is not scaled with the cpu capacity.
+-		 */
+-		if (capacity_factor && rq->nr_running == 1 && wl > env->imbalance)
+-			continue;
++	hmp = hmp_cpu_domain(cpu);
++	for_each_cpu_and(cpu, &hmp->cpus, nohz.idle_cpus_mask) {
++		/* only idle balance if a CPU is loaded over threshold */
++		if (cpu_rq(cpu)->avg.load_avg_ratio > hmp_full_threshold)
++			return 1;
++	}
++	return 0;
++}
++#endif
++DEFINE_PER_CPU(cpumask_var_t, ilb_tmpmask);
+ 
+-		/*
+-		 * For the load comparisons with the other cpu's, consider
+-		 * the weighted_cpuload() scaled with the cpu capacity, so
+-		 * that the load can be moved away from the cpu that is
+-		 * potentially running at a lower capacity.
+-		 *
+-		 * Thus we're looking for max(wl_i / capacity_i), crosswise
+-		 * multiplication to rid ourselves of the division works out
+-		 * to: wl_i * capacity_j > wl_j * capacity_i;  where j is
+-		 * our previous maximum.
+-		 */
+-		if (wl * busiest_capacity > busiest_load * capacity) {
+-			busiest_load = wl;
+-			busiest_capacity = capacity;
+-			busiest = rq;
++static inline int find_new_ilb(void)
++{
++	int ilb = cpumask_first(nohz.idle_cpus_mask);
++#ifdef CONFIG_SCHED_HMP
++	int ilb_needed = 0;
++	int call_cpu = smp_processor_id();
++	int cpu;
++	struct cpumask *tmp = per_cpu(ilb_tmpmask, smp_processor_id());
++
++	/* restrict nohz balancing to occur in the same hmp domain */
++	ilb = cpumask_first_and(nohz.idle_cpus_mask,
++			&((struct hmp_domain *)hmp_cpu_domain(call_cpu))->cpus);
++
++	/* check to see if it's necessary within this domain */
++	cpumask_andnot(tmp,
++			&((struct hmp_domain *)hmp_cpu_domain(call_cpu))->cpus,
++			nohz.idle_cpus_mask);
++	for_each_cpu(cpu, tmp) {
++		if (cpu_rq(cpu)->nr_running > 1) {
++			ilb_needed = 1;
++			break;
+ 		}
+ 	}
+ 
+-	return busiest;
++#ifdef CONFIG_SCHED_HMP_LITTLE_PACKING
++	if (ilb < nr_cpu_ids)
++		ilb_needed = hmp_packing_ilb_needed(ilb, ilb_needed);
++#endif
++
++	if (ilb_needed && ilb < nr_cpu_ids && idle_cpu(ilb))
++		return ilb;
++#else
++	if (ilb < nr_cpu_ids && idle_cpu(ilb))
++		return ilb;
++#endif
++	return nr_cpu_ids;
+ }
+ 
+ /*
+- * Max backoff if we encounter pinned tasks. Pretty arbitrary value, but
+- * so long as it is large enough.
++ * Kick a CPU to do the nohz balancing, if it is time for it. We pick the
++ * nohz_load_balancer CPU (if there is one) otherwise fallback to any idle
++ * CPU (if there is one).
+  */
+-#define MAX_PINNED_INTERVAL	512
++static void nohz_balancer_kick(void)
++{
++	int ilb_cpu;
+ 
+-/* Working cpumask for load_balance and load_balance_newidle. */
+-DEFINE_PER_CPU(cpumask_var_t, load_balance_mask);
++	nohz.next_balance++;
+ 
+-static int need_active_balance(struct lb_env *env)
+-{
+-	struct sched_domain *sd = env->sd;
++	ilb_cpu = find_new_ilb();
+ 
+-	if (env->idle == CPU_NEWLY_IDLE) {
++	if (ilb_cpu >= nr_cpu_ids)
++		return;
++
++	if (test_and_set_bit(NOHZ_BALANCE_KICK, nohz_flags(ilb_cpu)))
++		return;
++	/*
++	 * Use smp_send_reschedule() instead of resched_cpu().
++	 * This way we generate a sched IPI on the target cpu which
++	 * is idle. And the softirq performing nohz idle load balance
++	 * will be run before returning from the IPI.
++	 */
++	smp_send_reschedule(ilb_cpu);
++	return;
++}
+ 
++static inline void nohz_balance_exit_idle(int cpu)
++{
++	if (unlikely(test_bit(NOHZ_TICK_STOPPED, nohz_flags(cpu)))) {
+ 		/*
+-		 * ASYM_PACKING needs to force migrate tasks from busy but
+-		 * higher numbered CPUs in order to pack all tasks in the
+-		 * lowest numbered CPUs.
++		 * Completely isolated CPUs don't ever set, so we must test.
+ 		 */
+-		if ((sd->flags & SD_ASYM_PACKING) && env->src_cpu > env->dst_cpu)
+-			return 1;
++		if (likely(cpumask_test_cpu(cpu, nohz.idle_cpus_mask))) {
++			cpumask_clear_cpu(cpu, nohz.idle_cpus_mask);
++			atomic_dec(&nohz.nr_cpus);
++		}
++		clear_bit(NOHZ_TICK_STOPPED, nohz_flags(cpu));
+ 	}
+-
+-	return unlikely(sd->nr_balance_failed > sd->cache_nice_tries+2);
+ }
+ 
+-static int active_load_balance_cpu_stop(void *data);
+-
+-static int should_we_balance(struct lb_env *env)
++static inline void set_cpu_sd_state_busy(void)
+ {
+-	struct sched_group *sg = env->sd->groups;
+-	struct cpumask *sg_cpus, *sg_mask;
+-	int cpu, balance_cpu = -1;
++	struct sched_domain *sd;
++	int cpu = smp_processor_id();
+ 
+-	/*
+-	 * In the newly idle case, we will allow all the cpu's
+-	 * to do the newly idle load balance.
+-	 */
+-	if (env->idle == CPU_NEWLY_IDLE)
+-		return 1;
++	rcu_read_lock();
++	sd = rcu_dereference(per_cpu(sd_busy, cpu));
+ 
+-	sg_cpus = sched_group_cpus(sg);
+-	sg_mask = sched_group_mask(sg);
+-	/* Try to find first idle cpu */
+-	for_each_cpu_and(cpu, sg_cpus, env->cpus) {
+-		if (!cpumask_test_cpu(cpu, sg_mask) || !idle_cpu(cpu))
+-			continue;
++	if (!sd || !sd->nohz_idle)
++		goto unlock;
++	sd->nohz_idle = 0;
+ 
+-		balance_cpu = cpu;
+-		break;
+-	}
++	atomic_inc(&sd->groups->sgc->nr_busy_cpus);
++unlock:
++	rcu_read_unlock();
++}
+ 
+-	if (balance_cpu == -1)
+-		balance_cpu = group_balance_cpu(sg);
++void set_cpu_sd_state_idle(void)
++{
++	struct sched_domain *sd;
++	int cpu = smp_processor_id();
+ 
+-	/*
+-	 * First idle cpu or the first cpu(busiest) in this sched group
+-	 * is eligible for doing load balancing at this and above domains.
+-	 */
+-	return balance_cpu == env->dst_cpu;
++	rcu_read_lock();
++	sd = rcu_dereference(per_cpu(sd_busy, cpu));
++
++	if (!sd || sd->nohz_idle)
++		goto unlock;
++	sd->nohz_idle = 1;
++
++	atomic_dec(&sd->groups->sgc->nr_busy_cpus);
++unlock:
++	rcu_read_unlock();
+ }
+ 
+ /*
+- * Check this_cpu to ensure it is balanced within domain. Attempt to move
+- * tasks if there is an imbalance.
++ * This routine will record that the cpu is going idle with tick stopped.
++ * This info will be used in performing idle load balancing in the future.
+  */
+-static int load_balance(int this_cpu, struct rq *this_rq,
+-			struct sched_domain *sd, enum cpu_idle_type idle,
+-			int *continue_balancing)
++void nohz_balance_enter_idle(int cpu)
+ {
+-	int ld_moved, cur_ld_moved, active_balance = 0;
+-	struct sched_domain *sd_parent = sd->parent;
+-	struct sched_group *group;
+-	struct rq *busiest;
+-	unsigned long flags;
+-	struct cpumask *cpus = this_cpu_cpumask_var_ptr(load_balance_mask);
+-
+-	struct lb_env env = {
+-		.sd		= sd,
+-		.dst_cpu	= this_cpu,
+-		.dst_rq		= this_rq,
+-		.dst_grpmask    = sched_group_cpus(sd->groups),
+-		.idle		= idle,
+-		.loop_break	= sched_nr_migrate_break,
+-		.cpus		= cpus,
+-		.fbq_type	= all,
+-		.tasks		= LIST_HEAD_INIT(env.tasks),
+-	};
+-
+ 	/*
+-	 * For NEWLY_IDLE load_balancing, we don't need to consider
+-	 * other cpus in our group
++	 * If this cpu is going down, then nothing needs to be done.
+ 	 */
+-	if (idle == CPU_NEWLY_IDLE)
+-		env.dst_grpmask = NULL;
+-
+-	cpumask_copy(cpus, cpu_active_mask);
++	if (!cpu_active(cpu))
++		return;
+ 
+-	schedstat_inc(sd, lb_count[idle]);
++	if (test_bit(NOHZ_TICK_STOPPED, nohz_flags(cpu)))
++		return;
+ 
+-redo:
+-	if (!should_we_balance(&env)) {
+-		*continue_balancing = 0;
+-		goto out_balanced;
+-	}
++	/*
++	 * If we're a completely isolated CPU, we don't play.
++	 */
++	if (on_null_domain(cpu_rq(cpu)))
++		return;
+ 
+-	group = find_busiest_group(&env);
+-	if (!group) {
+-		schedstat_inc(sd, lb_nobusyg[idle]);
+-		goto out_balanced;
+-	}
++	cpumask_set_cpu(cpu, nohz.idle_cpus_mask);
++	atomic_inc(&nohz.nr_cpus);
++	set_bit(NOHZ_TICK_STOPPED, nohz_flags(cpu));
++}
+ 
+-	busiest = find_busiest_queue(&env, group);
+-	if (!busiest) {
+-		schedstat_inc(sd, lb_nobusyq[idle]);
+-		goto out_balanced;
++static int sched_ilb_notifier(struct notifier_block *nfb,
++					unsigned long action, void *hcpu)
++{
++	switch (action & ~CPU_TASKS_FROZEN) {
++	case CPU_DYING:
++		nohz_balance_exit_idle(smp_processor_id());
++		return NOTIFY_OK;
++	default:
++		return NOTIFY_DONE;
+ 	}
++}
++#endif
+ 
+-	BUG_ON(busiest == env.dst_rq);
+-
+-	schedstat_add(sd, lb_imbalance[idle], env.imbalance);
++static DEFINE_SPINLOCK(balancing);
+ 
+-	ld_moved = 0;
+-	if (busiest->nr_running > 1) {
+-		/*
+-		 * Attempt to move tasks. If find_busiest_group has found
+-		 * an imbalance but busiest->nr_running <= 1, the group is
+-		 * still unbalanced. ld_moved simply stays zero, so it is
+-		 * correctly treated as an imbalance.
+-		 */
+-		env.flags |= LBF_ALL_PINNED;
+-		env.src_cpu   = busiest->cpu;
+-		env.src_rq    = busiest;
+-		env.loop_max  = min(sysctl_sched_nr_migrate, busiest->nr_running);
++/*
++ * Scale the max load_balance interval with the number of CPUs in the system.
++ * This trades load-balance latency on larger machines for less cross talk.
++ */
++void update_max_interval(void)
++{
++	max_load_balance_interval = HZ*num_online_cpus()/10;
++}
+ 
+-more_balance:
+-		raw_spin_lock_irqsave(&busiest->lock, flags);
++/*
++ * It checks each scheduling domain to see if it is due to be balanced,
++ * and initiates a balancing operation if so.
++ *
++ * Balancing parameters are set up in init_sched_domains.
++ */
++static void rebalance_domains(struct rq *rq, enum cpu_idle_type idle)
++{
++	int continue_balancing = 1;
++	int cpu = rq->cpu;
++	unsigned long interval;
++	struct sched_domain *sd;
++	/* Earliest time when we have to do rebalance again */
++	unsigned long next_balance = jiffies + 60*HZ;
++	int update_next_balance = 0;
++	int need_serialize, need_decay = 0;
++	u64 max_cost = 0;
+ 
+-		/*
+-		 * cur_ld_moved - load moved in current iteration
+-		 * ld_moved     - cumulative load moved across iterations
+-		 */
+-		cur_ld_moved = detach_tasks(&env);
++	update_blocked_averages(cpu);
+ 
++	rcu_read_lock();
++	for_each_domain(cpu, sd) {
+ 		/*
+-		 * We've detached some tasks from busiest_rq. Every
+-		 * task is masked "TASK_ON_RQ_MIGRATING", so we can safely
+-		 * unlock busiest->lock, and we are able to be sure
+-		 * that nobody can manipulate the tasks in parallel.
+-		 * See task_rq_lock() family for the details.
++		 * Decay the newidle max times here because this is a regular
++		 * visit to all the domains. Decay ~1% per second.
+ 		 */
+-
+-		raw_spin_unlock(&busiest->lock);
+-
+-		if (cur_ld_moved) {
+-			attach_tasks(&env);
+-			ld_moved += cur_ld_moved;
++		if (time_after(jiffies, sd->next_decay_max_lb_cost)) {
++			sd->max_newidle_lb_cost =
++				(sd->max_newidle_lb_cost * 253) / 256;
++			sd->next_decay_max_lb_cost = jiffies + HZ;
++			need_decay = 1;
+ 		}
++		max_cost += sd->max_newidle_lb_cost;
+ 
+-		local_irq_restore(flags);
+-
+-		if (env.flags & LBF_NEED_BREAK) {
+-			env.flags &= ~LBF_NEED_BREAK;
+-			goto more_balance;
+-		}
++		if (!(sd->flags & SD_LOAD_BALANCE))
++			continue;
+ 
+ 		/*
+-		 * Revisit (affine) tasks on src_cpu that couldn't be moved to
+-		 * us and move them to an alternate dst_cpu in our sched_group
+-		 * where they can run. The upper limit on how many times we
+-		 * iterate on same src_cpu is dependent on number of cpus in our
+-		 * sched_group.
+-		 *
+-		 * This changes load balance semantics a bit on who can move
+-		 * load to a given_cpu. In addition to the given_cpu itself
+-		 * (or a ilb_cpu acting on its behalf where given_cpu is
+-		 * nohz-idle), we now have balance_cpu in a position to move
+-		 * load to given_cpu. In rare situations, this may cause
+-		 * conflicts (balance_cpu and given_cpu/ilb_cpu deciding
+-		 * _independently_ and at _same_ time to move some load to
+-		 * given_cpu) causing exceess load to be moved to given_cpu.
+-		 * This however should not happen so much in practice and
+-		 * moreover subsequent load balance cycles should correct the
+-		 * excess load moved.
++		 * Stop the load balance at this level. There is another
++		 * CPU in our sched group which is doing load balancing more
++		 * actively.
+ 		 */
+-		if ((env.flags & LBF_DST_PINNED) && env.imbalance > 0) {
+-
+-			/* Prevent to re-select dst_cpu via env's cpus */
+-			cpumask_clear_cpu(env.dst_cpu, env.cpus);
+-
+-			env.dst_rq	 = cpu_rq(env.new_dst_cpu);
+-			env.dst_cpu	 = env.new_dst_cpu;
+-			env.flags	&= ~LBF_DST_PINNED;
+-			env.loop	 = 0;
+-			env.loop_break	 = sched_nr_migrate_break;
+-
+-			/*
+-			 * Go back to "more_balance" rather than "redo" since we
+-			 * need to continue with same src_cpu.
+-			 */
+-			goto more_balance;
++		if (!continue_balancing) {
++			if (need_decay)
++				continue;
++			break;
+ 		}
+ 
+-		/*
+-		 * We failed to reach balance because of affinity.
+-		 */
+-		if (sd_parent) {
+-			int *group_imbalance = &sd_parent->groups->sgc->imbalance;
++		interval = get_sd_balance_interval(sd, idle != CPU_IDLE);
+ 
+-			if ((env.flags & LBF_SOME_PINNED) && env.imbalance > 0)
+-				*group_imbalance = 1;
++		need_serialize = sd->flags & SD_SERIALIZE;
++		if (need_serialize) {
++			if (!spin_trylock(&balancing))
++				goto out;
+ 		}
+ 
+-		/* All tasks on this runqueue were pinned by CPU affinity */
+-		if (unlikely(env.flags & LBF_ALL_PINNED)) {
+-			cpumask_clear_cpu(cpu_of(busiest), cpus);
+-			if (!cpumask_empty(cpus)) {
+-				env.loop = 0;
+-				env.loop_break = sched_nr_migrate_break;
+-				goto redo;
++		if (time_after_eq(jiffies, sd->last_balance + interval)) {
++			if (load_balance(cpu, rq, sd, idle, &continue_balancing)) {
++				/*
++				 * The LBF_DST_PINNED logic could have changed
++				 * env->dst_cpu, so we can't know our idle
++				 * state even if we migrated tasks. Update it.
++				 */
++				idle = idle_cpu(cpu) ? CPU_IDLE : CPU_NOT_IDLE;
+ 			}
+-			goto out_all_pinned;
++			sd->last_balance = jiffies;
++			interval = get_sd_balance_interval(sd, idle != CPU_IDLE);
++		}
++		if (need_serialize)
++			spin_unlock(&balancing);
++out:
++		if (time_after(next_balance, sd->last_balance + interval)) {
++			next_balance = sd->last_balance + interval;
++			update_next_balance = 1;
+ 		}
+ 	}
+-
+-	if (!ld_moved) {
+-		schedstat_inc(sd, lb_failed[idle]);
++	if (need_decay) {
+ 		/*
+-		 * Increment the failure counter only on periodic balance.
+-		 * We do not want newidle balance, which can be very
+-		 * frequent, pollute the failure counter causing
+-		 * excessive cache_hot migrations and active balances.
++		 * Ensure the rq-wide value also decays but keep it at a
++		 * reasonable floor to avoid funnies with rq->avg_idle.
+ 		 */
+-		if (idle != CPU_NEWLY_IDLE)
+-			sd->nr_balance_failed++;
++		rq->max_idle_balance_cost =
++			max((u64)sysctl_sched_migration_cost, max_cost);
++	}
++	rcu_read_unlock();
+ 
+-		if (need_active_balance(&env)) {
+-			raw_spin_lock_irqsave(&busiest->lock, flags);
++	/*
++	 * next_balance will be updated only when there is a need.
++	 * When the cpu is attached to null domain for ex, it will not be
++	 * updated.
++	 */
++	if (likely(update_next_balance))
++		rq->next_balance = next_balance;
++}
+ 
+-			/* don't kick the active_load_balance_cpu_stop,
+-			 * if the curr task on busiest cpu can't be
+-			 * moved to this_cpu
+-			 */
+-			if (!cpumask_test_cpu(this_cpu,
+-					tsk_cpus_allowed(busiest->curr))) {
+-				raw_spin_unlock_irqrestore(&busiest->lock,
+-							    flags);
+-				env.flags |= LBF_ALL_PINNED;
+-				goto out_one_pinned;
+-			}
++#ifdef CONFIG_NO_HZ_COMMON
++/*
++ * In CONFIG_NO_HZ_COMMON case, the idle balance kickee will do the
++ * rebalancing for all the cpus for whom scheduler ticks are stopped.
++ */
++static void nohz_idle_balance(struct rq *this_rq, enum cpu_idle_type idle)
++{
++	int this_cpu = this_rq->cpu;
++	struct rq *rq;
++	int balance_cpu;
+ 
+-			/*
+-			 * ->active_balance synchronizes accesses to
+-			 * ->active_balance_work.  Once set, it's cleared
+-			 * only after active load balance is finished.
+-			 */
+-			if (!busiest->active_balance) {
+-				busiest->active_balance = 1;
+-				busiest->push_cpu = this_cpu;
+-				active_balance = 1;
+-			}
+-			raw_spin_unlock_irqrestore(&busiest->lock, flags);
++	if (idle != CPU_IDLE ||
++	    !test_bit(NOHZ_BALANCE_KICK, nohz_flags(this_cpu)))
++		goto end;
+ 
+-			if (active_balance) {
+-				stop_one_cpu_nowait(cpu_of(busiest),
+-					active_load_balance_cpu_stop, busiest,
+-					&busiest->active_balance_work);
+-			}
++	for_each_cpu(balance_cpu, nohz.idle_cpus_mask) {
++		if (balance_cpu == this_cpu || !idle_cpu(balance_cpu))
++			continue;
+ 
+-			/*
+-			 * We've kicked active balancing, reset the failure
+-			 * counter.
+-			 */
+-			sd->nr_balance_failed = sd->cache_nice_tries+1;
+-		}
+-	} else
+-		sd->nr_balance_failed = 0;
++		/*
++		 * If this cpu gets work to do, stop the load balancing
++		 * work being done for other cpus. Next load
++		 * balancing owner will pick it up.
++		 */
++		if (need_resched())
++			break;
++
++		rq = cpu_rq(balance_cpu);
+ 
+-	if (likely(!active_balance)) {
+-		/* We were unbalanced, so reset the balancing interval */
+-		sd->balance_interval = sd->min_interval;
+-	} else {
+ 		/*
+-		 * If we've begun active balancing, start to back off. This
+-		 * case may not be covered by the all_pinned logic if there
+-		 * is only 1 task on the busy runqueue (because we don't call
+-		 * detach_tasks).
++		 * If time for next balance is due,
++		 * do the balance.
+ 		 */
+-		if (sd->balance_interval < sd->max_interval)
+-			sd->balance_interval *= 2;
++		if (time_after_eq(jiffies, rq->next_balance)) {
++			raw_spin_lock_irq(&rq->lock);
++			update_rq_clock(rq);
++			update_idle_cpu_load(rq);
++			raw_spin_unlock_irq(&rq->lock);
++			rebalance_domains(rq, CPU_IDLE);
++		}
++
++		if (time_after(this_rq->next_balance, rq->next_balance))
++			this_rq->next_balance = rq->next_balance;
+ 	}
++	nohz.next_balance = this_rq->next_balance;
++end:
++	clear_bit(NOHZ_BALANCE_KICK, nohz_flags(this_cpu));
++}
+ 
+-	goto out;
++/*
++ * Current heuristic for kicking the idle load balancer in the presence
++ * of an idle cpu is the system.
++ *   - This rq has more than one task.
++ *   - At any scheduler domain level, this cpu's scheduler group has multiple
++ *     busy cpu's exceeding the group's capacity.
++ *   - For SD_ASYM_PACKING, if the lower numbered cpu's in the scheduler
++ *     domain span are idle.
++ */
++static inline int nohz_kick_needed(struct rq *rq)
++{
++	unsigned long now = jiffies;
++	struct sched_domain *sd;
++	struct sched_group_capacity *sgc;
++	int nr_busy, cpu = rq->cpu;
++
++	if (unlikely(rq->idle_balance))
++		return 0;
++
++       /*
++	* We may be recently in ticked or tickless idle mode. At the first
++	* busy tick after returning from idle, we will update the busy stats.
++	*/
++	set_cpu_sd_state_busy();
++	nohz_balance_exit_idle(cpu);
+ 
+-out_balanced:
+ 	/*
+-	 * We reach balance although we may have faced some affinity
+-	 * constraints. Clear the imbalance flag if it was set.
++	 * None are in tickless mode and hence no need for NOHZ idle load
++	 * balancing.
+ 	 */
+-	if (sd_parent) {
+-		int *group_imbalance = &sd_parent->groups->sgc->imbalance;
++	if (likely(!atomic_read(&nohz.nr_cpus)))
++		return 0;
+ 
+-		if (*group_imbalance)
+-			*group_imbalance = 0;
+-	}
++	if (time_before(now, nohz.next_balance))
++		return 0;
+ 
+-out_all_pinned:
++#ifdef CONFIG_SCHED_HMP
+ 	/*
+-	 * We reach balance because all tasks are pinned at this level so
+-	 * we can't migrate them. Let the imbalance flag set so parent level
+-	 * can try to migrate them.
++	 * Bail out if there are no nohz CPUs in our
++	 * HMP domain, since we will move tasks between
++	 * domains through wakeup and force balancing
++	 * as necessary based upon task load.
+ 	 */
+-	schedstat_inc(sd, lb_balanced[idle]);
++	if (cpumask_first_and(nohz.idle_cpus_mask,
++			&((struct hmp_domain *)hmp_cpu_domain(cpu))->cpus) >= nr_cpu_ids)
++		return 0;
++#endif
+ 
+-	sd->nr_balance_failed = 0;
++	if (rq->nr_running >= 2)
++		goto need_kick;
+ 
+-out_one_pinned:
+-	/* tune up the balancing interval */
+-	if (((env.flags & LBF_ALL_PINNED) &&
+-			sd->balance_interval < MAX_PINNED_INTERVAL) ||
+-			(sd->balance_interval < sd->max_interval))
+-		sd->balance_interval *= 2;
++	rcu_read_lock();
++	sd = rcu_dereference(per_cpu(sd_busy, cpu));
+ 
+-	ld_moved = 0;
+-out:
+-	return ld_moved;
++	if (sd) {
++		sgc = sd->groups->sgc;
++		nr_busy = atomic_read(&sgc->nr_busy_cpus);
++
++		if (nr_busy > 1)
++			goto need_kick_unlock;
++	}
++
++	sd = rcu_dereference(per_cpu(sd_asym, cpu));
++
++	if (sd && (cpumask_first_and(nohz.idle_cpus_mask,
++				  sched_domain_span(sd)) < cpu))
++		goto need_kick_unlock;
++
++	rcu_read_unlock();
++	return 0;
++
++need_kick_unlock:
++	rcu_read_unlock();
++need_kick:
++	return 1;
+ }
++#else
++static void nohz_idle_balance(struct rq *this_rq, enum cpu_idle_type idle) { }
++#endif
+ 
+-static inline unsigned long
+-get_sd_balance_interval(struct sched_domain *sd, int cpu_busy)
++#ifdef CONFIG_SCHED_HMP
++static unsigned int hmp_task_eligible_for_up_migration(struct sched_entity *se)
+ {
+-	unsigned long interval = sd->balance_interval;
++	/* below hmp_up_threshold, never eligible */
++	if (se->avg.load_avg_ratio < hmp_up_threshold)
++		return 0;
++	return 1;
++}
+ 
+-	if (cpu_busy)
+-		interval *= sd->busy_factor;
++/* Check if task should migrate to a faster cpu */
++static unsigned int hmp_up_migration(int cpu,
++		int *target_cpu, struct sched_entity *se)
++{
++	struct task_struct *p = task_of(se);
++	int temp_target_cpu;
++	u64 now;
+ 
+-	/* scale ms to jiffies */
+-	interval = msecs_to_jiffies(interval);
+-	interval = clamp(interval, 1UL, max_load_balance_interval);
++	if (hmp_cpu_is_fastest(cpu))
++		return 0;
+ 
+-	return interval;
++#ifdef CONFIG_SCHED_HMP_PRIO_FILTER
++	/* Filter by task priority */
++	if (p->prio >= hmp_up_prio)
++		return 0;
++#endif
++	if (!hmp_task_eligible_for_up_migration(se))
++		return 0;
++
++	/* Let the task load settle before doing another up migration */
++	/* hack - always use clock from first online CPU */
++	now = cpu_rq(cpumask_first(cpu_online_mask))->clock_task;
++	if (((now - se->avg.hmp_last_up_migration) >> 10)
++					< hmp_next_up_threshold)
++		return 0;
++
++	/* hmp_domain_min_load only returns 0 for an
++	 * idle CPU or 1023 for any partly-busy one.
++	 * Be explicit about requirement for an idle CPU.
++	 */
++	if (hmp_domain_min_load(hmp_faster_domain(cpu), &temp_target_cpu,
++			tsk_cpus_allowed(p)) == 0
++			&& temp_target_cpu != NR_CPUS) {
++		if (target_cpu)
++			*target_cpu = temp_target_cpu;
++		return 1;
++	}
++	return 0;
+ }
+ 
+-static inline void
+-update_next_balance(struct sched_domain *sd, int cpu_busy, unsigned long *next_balance)
++/* Check if task should migrate to a slower cpu */
++static unsigned int hmp_down_migration(int cpu, struct sched_entity *se)
+ {
+-	unsigned long interval, next;
++	struct task_struct *p = task_of(se);
++	u64 now;
+ 
+-	interval = get_sd_balance_interval(sd, cpu_busy);
+-	next = sd->last_balance + interval;
++	if (hmp_cpu_is_slowest(cpu)) {
++#ifdef CONFIG_SCHED_HMP_LITTLE_PACKING
++		if (hmp_packing_enabled)
++			return 1;
++		else
++#endif
++		return 0;
++	}
+ 
+-	if (time_after(*next_balance, next))
+-		*next_balance = next;
++#ifdef CONFIG_SCHED_HMP_PRIO_FILTER
++	/* Filter by task priority */
++	if ((p->prio >= hmp_up_prio) &&
++		cpumask_intersects(&hmp_slower_domain(cpu)->cpus,
++					tsk_cpus_allowed(p))) {
++		return 1;
++	}
++#endif
++
++	/* Let the task load settle before doing another down migration */
++	/* hack - always use clock from first online CPU */
++	now = cpu_rq(cpumask_first(cpu_online_mask))->clock_task;
++	if (((now - se->avg.hmp_last_down_migration) >> 10)
++					< hmp_next_down_threshold)
++		return 0;
++
++	if (cpumask_intersects(&hmp_slower_domain(cpu)->cpus,
++					tsk_cpus_allowed(p))
++		&& se->avg.load_avg_ratio < hmp_down_threshold) {
++		return 1;
++	}
++	return 0;
+ }
+ 
+ /*
+- * idle_balance is called by schedule() if this_cpu is about to become
+- * idle. Attempts to pull tasks from other CPUs.
++ * hmp_can_migrate_task - may task p from runqueue rq be migrated to this_cpu?
++ * Ideally this function should be merged with can_migrate_task() to avoid
++ * redundant code.
+  */
+-static int idle_balance(struct rq *this_rq)
++static int hmp_can_migrate_task(struct task_struct *p, struct lb_env *env)
+ {
+-	unsigned long next_balance = jiffies + HZ;
+-	int this_cpu = this_rq->cpu;
+-	struct sched_domain *sd;
+-	int pulled_task = 0;
+-	u64 curr_cost = 0;
+-
+-	idle_enter_fair(this_rq);
++	int tsk_cache_hot = 0;
+ 
+ 	/*
+-	 * We must set idle_stamp _before_ calling idle_balance(), such that we
+-	 * measure the duration of idle_balance() as idle time.
++	 * We do not migrate tasks that are:
++	 * 1) running (obviously), or
++	 * 2) cannot be migrated to this CPU due to cpus_allowed
+ 	 */
+-	this_rq->idle_stamp = rq_clock(this_rq);
+-
+-	if (this_rq->avg_idle < sysctl_sched_migration_cost ||
+-	    !this_rq->rd->overload) {
+-		rcu_read_lock();
+-		sd = rcu_dereference_check_sched_domain(this_rq->sd);
+-		if (sd)
+-			update_next_balance(sd, 0, &next_balance);
+-		rcu_read_unlock();
++	if (!cpumask_test_cpu(env->dst_cpu, tsk_cpus_allowed(p))) {
++		schedstat_inc(p, se.statistics.nr_failed_migrations_affine);
++		return 0;
++	}
++	env->flags &= ~LBF_ALL_PINNED;
+ 
+-		goto out;
++	if (task_running(env->src_rq, p)) {
++		schedstat_inc(p, se.statistics.nr_failed_migrations_running);
++		return 0;
+ 	}
+ 
+ 	/*
+-	 * Drop the rq->lock, but keep IRQ/preempt disabled.
++	 * Aggressive migration if:
++	 * 1) task is cache cold, or
++	 * 2) too many balance attempts have failed.
+ 	 */
+-	raw_spin_unlock(&this_rq->lock);
+-
+-	update_blocked_averages(this_cpu);
+-	rcu_read_lock();
+-	for_each_domain(this_cpu, sd) {
+-		int continue_balancing = 1;
+-		u64 t0, domain_cost;
+-
+-		if (!(sd->flags & SD_LOAD_BALANCE))
+-			continue;
+-
+-		if (this_rq->avg_idle < curr_cost + sd->max_newidle_lb_cost) {
+-			update_next_balance(sd, 0, &next_balance);
+-			break;
+-		}
+-
+-		if (sd->flags & SD_BALANCE_NEWIDLE) {
+-			t0 = sched_clock_cpu(this_cpu);
+-
+-			pulled_task = load_balance(this_cpu, this_rq,
+-						   sd, CPU_NEWLY_IDLE,
+-						   &continue_balancing);
+-
+-			domain_cost = sched_clock_cpu(this_cpu) - t0;
+-			if (domain_cost > sd->max_newidle_lb_cost)
+-				sd->max_newidle_lb_cost = domain_cost;
+ 
+-			curr_cost += domain_cost;
++	tsk_cache_hot = task_hot(p, env);
++	if (!tsk_cache_hot ||
++		env->sd->nr_balance_failed > env->sd->cache_nice_tries) {
++#ifdef CONFIG_SCHEDSTATS
++		if (tsk_cache_hot) {
++			schedstat_inc(env->sd, lb_hot_gained[env->idle]);
++			schedstat_inc(p, se.statistics.nr_forced_migrations);
+ 		}
+-
+-		update_next_balance(sd, 0, &next_balance);
+-
+-		/*
+-		 * Stop searching for tasks to pull if there are
+-		 * now runnable tasks on this rq.
+-		 */
+-		if (pulled_task || this_rq->nr_running > 0)
+-			break;
++#endif
++		return 1;
+ 	}
+-	rcu_read_unlock();
+-
+-	raw_spin_lock(&this_rq->lock);
+ 
+-	if (curr_cost > this_rq->max_idle_balance_cost)
+-		this_rq->max_idle_balance_cost = curr_cost;
++	return 1;
++}
+ 
+-	/*
+-	 * While browsing the domains, we released the rq lock, a task could
+-	 * have been enqueued in the meantime. Since we're not going idle,
+-	 * pretend we pulled a task.
+-	 */
+-	if (this_rq->cfs.h_nr_running && !pulled_task)
+-		pulled_task = 1;
++/*
++ * move_task - move a task from one runqueue to another runqueue.
++ * Both runqueues must be locked.
++ */
++static void move_task(struct task_struct *p, struct lb_env *env)
++{
++	deactivate_task(env->src_rq, p, 0);
++	set_task_cpu(p, env->dst_cpu);
++	activate_task(env->dst_rq, p, 0);
++	check_preempt_curr(env->dst_rq, p, 0);
++}
+ 
+-out:
+-	/* Move the next balance forward */
+-	if (time_after(this_rq->next_balance, next_balance))
+-		this_rq->next_balance = next_balance;
++/*
++ * move_specific_task tries to move a specific task.
++ * Returns 1 if successful and 0 otherwise.
++ * Called with both runqueues locked.
++ */
++static int move_specific_task(struct lb_env *env, struct task_struct *pm)
++{
++	struct task_struct *p, *n;
+ 
+-	/* Is there a task of a high priority class? */
+-	if (this_rq->nr_running != this_rq->cfs.h_nr_running)
+-		pulled_task = -1;
++	list_for_each_entry_safe(p, n, &env->src_rq->cfs_tasks, se.group_node) {
++	if (throttled_lb_pair(task_group(p), env->src_rq->cpu,
++				env->dst_cpu))
++		continue;
+ 
+-	if (pulled_task) {
+-		idle_exit_fair(this_rq);
+-		this_rq->idle_stamp = 0;
+-	}
++		if (!hmp_can_migrate_task(p, env))
++			continue;
++		/* Check if we found the right task */
++		if (p != pm)
++			continue;
+ 
+-	return pulled_task;
++		move_task(p, env);
++		/*
++		 * Right now, this is only the third place move_task()
++		 * is called, so we can safely collect move_task()
++		 * stats here rather than inside move_task().
++		 */
++		schedstat_inc(env->sd, lb_gained[env->idle]);
++		return 1;
++	}
++	return 0;
+ }
+ 
+ /*
+- * active_load_balance_cpu_stop is run by cpu stopper. It pushes
+- * running tasks off the busiest CPU onto idle CPUs. It requires at
+- * least 1 task to be running on each physical CPU where possible, and
+- * avoids physical / logical imbalances.
++ * hmp_active_task_migration_cpu_stop is run by cpu stopper and used to
++ * migrate a specific task from one runqueue to another.
++ * hmp_force_up_migration uses this to push a currently running task
++ * off a runqueue.
++ * Based on active_load_balance_stop_cpu and can potentially be merged.
+  */
+-static int active_load_balance_cpu_stop(void *data)
++static int hmp_active_task_migration_cpu_stop(void *data)
+ {
+ 	struct rq *busiest_rq = data;
++	struct task_struct *p = busiest_rq->migrate_task;
+ 	int busiest_cpu = cpu_of(busiest_rq);
+ 	int target_cpu = busiest_rq->push_cpu;
+ 	struct rq *target_rq = cpu_rq(target_cpu);
+ 	struct sched_domain *sd;
+-	struct task_struct *p = NULL;
+ 
+ 	raw_spin_lock_irq(&busiest_rq->lock);
+-
+ 	/* make sure the requested cpu hasn't gone down in the meantime */
+ 	if (unlikely(busiest_cpu != smp_processor_id() ||
+-		     !busiest_rq->active_balance))
++		!busiest_rq->active_balance)) {
+ 		goto out_unlock;
+-
++	}
+ 	/* Is there any task to move? */
+ 	if (busiest_rq->nr_running <= 1)
+ 		goto out_unlock;
+-
++	/* Task has migrated meanwhile, abort forced migration */
++	if (task_rq(p) != busiest_rq)
++		goto out_unlock;
+ 	/*
+ 	 * This condition is "impossible", if it occurs
+ 	 * we need to fix it. Originally reported by
+@@ -7058,12 +8892,14 @@ static int active_load_balance_cpu_stop(void *data)
+ 	 */
+ 	BUG_ON(busiest_rq == target_rq);
+ 
++	/* move a task from busiest_rq to target_rq */
++	double_lock_balance(busiest_rq, target_rq);
++
+ 	/* Search for an sd spanning us and the target CPU. */
+ 	rcu_read_lock();
+ 	for_each_domain(target_cpu, sd) {
+-		if ((sd->flags & SD_LOAD_BALANCE) &&
+-		    cpumask_test_cpu(busiest_cpu, sched_domain_span(sd)))
+-				break;
++		if (cpumask_test_cpu(busiest_cpu, sched_domain_span(sd)))
++			break;
+ 	}
+ 
+ 	if (likely(sd)) {
+@@ -7078,390 +8914,354 @@ static int active_load_balance_cpu_stop(void *data)
+ 
+ 		schedstat_inc(sd, alb_count);
+ 
+-		p = detach_one_task(&env);
+-		if (p)
++		if (move_specific_task(&env, p))
+ 			schedstat_inc(sd, alb_pushed);
+ 		else
+ 			schedstat_inc(sd, alb_failed);
+ 	}
+ 	rcu_read_unlock();
++	double_unlock_balance(busiest_rq, target_rq);
+ out_unlock:
++	put_task_struct(p);
+ 	busiest_rq->active_balance = 0;
+-	raw_spin_unlock(&busiest_rq->lock);
+-
+-	if (p)
+-		attach_one_task(target_rq, p);
+-
+-	local_irq_enable();
+-
++	raw_spin_unlock_irq(&busiest_rq->lock);
+ 	return 0;
+ }
+ 
+-static inline int on_null_domain(struct rq *rq)
+-{
+-	return unlikely(!rcu_dereference_sched(rq->sd));
+-}
+-
+-#ifdef CONFIG_NO_HZ_COMMON
+-/*
+- * idle load balancing details
+- * - When one of the busy CPUs notice that there may be an idle rebalancing
+- *   needed, they will kick the idle load balancer, which then does idle
+- *   load balancing for all the idle CPUs.
+- */
+-static struct {
+-	cpumask_var_t idle_cpus_mask;
+-	atomic_t nr_cpus;
+-	unsigned long next_balance;     /* in jiffy units */
+-} nohz ____cacheline_aligned;
+-
+-static inline int find_new_ilb(void)
+-{
+-	int ilb = cpumask_first(nohz.idle_cpus_mask);
+-
+-	if (ilb < nr_cpu_ids && idle_cpu(ilb))
+-		return ilb;
+-
+-	return nr_cpu_ids;
+-}
+-
+ /*
+- * Kick a CPU to do the nohz balancing, if it is time for it. We pick the
+- * nohz_load_balancer CPU (if there is one) otherwise fallback to any idle
+- * CPU (if there is one).
++ * hmp_idle_pull_cpu_stop is run by cpu stopper and used to
++ * migrate a specific task from one runqueue to another.
++ * hmp_idle_pull uses this to push a currently running task
++ * off a runqueue to a faster CPU.
++ * Locking is slightly different than usual.
++ * Based on active_load_balance_stop_cpu and can potentially be merged.
+  */
+-static void nohz_balancer_kick(void)
+-{
+-	int ilb_cpu;
+-
+-	nohz.next_balance++;
+-
+-	ilb_cpu = find_new_ilb();
+-
+-	if (ilb_cpu >= nr_cpu_ids)
+-		return;
+-
+-	if (test_and_set_bit(NOHZ_BALANCE_KICK, nohz_flags(ilb_cpu)))
+-		return;
+-	/*
+-	 * Use smp_send_reschedule() instead of resched_cpu().
+-	 * This way we generate a sched IPI on the target cpu which
+-	 * is idle. And the softirq performing nohz idle load balance
+-	 * will be run before returning from the IPI.
+-	 */
+-	smp_send_reschedule(ilb_cpu);
+-	return;
+-}
+-
+-static inline void nohz_balance_exit_idle(int cpu)
+-{
+-	if (unlikely(test_bit(NOHZ_TICK_STOPPED, nohz_flags(cpu)))) {
+-		/*
+-		 * Completely isolated CPUs don't ever set, so we must test.
+-		 */
+-		if (likely(cpumask_test_cpu(cpu, nohz.idle_cpus_mask))) {
+-			cpumask_clear_cpu(cpu, nohz.idle_cpus_mask);
+-			atomic_dec(&nohz.nr_cpus);
+-		}
+-		clear_bit(NOHZ_TICK_STOPPED, nohz_flags(cpu));
+-	}
+-}
+-
+-static inline void set_cpu_sd_state_busy(void)
+-{
+-	struct sched_domain *sd;
+-	int cpu = smp_processor_id();
+-
+-	rcu_read_lock();
+-	sd = rcu_dereference(per_cpu(sd_busy, cpu));
+-
+-	if (!sd || !sd->nohz_idle)
+-		goto unlock;
+-	sd->nohz_idle = 0;
+-
+-	atomic_inc(&sd->groups->sgc->nr_busy_cpus);
+-unlock:
+-	rcu_read_unlock();
+-}
+-
+-void set_cpu_sd_state_idle(void)
++static int hmp_idle_pull_cpu_stop(void *data)
+ {
++	struct rq *busiest_rq = data;
++	struct task_struct *p = busiest_rq->migrate_task;
++	int busiest_cpu = cpu_of(busiest_rq);
++	int target_cpu = busiest_rq->push_cpu;
++	struct rq *target_rq = cpu_rq(target_cpu);
+ 	struct sched_domain *sd;
+-	int cpu = smp_processor_id();
+-
+-	rcu_read_lock();
+-	sd = rcu_dereference(per_cpu(sd_busy, cpu));
+ 
+-	if (!sd || sd->nohz_idle)
+-		goto unlock;
+-	sd->nohz_idle = 1;
++	raw_spin_lock_irq(&busiest_rq->lock);
+ 
+-	atomic_dec(&sd->groups->sgc->nr_busy_cpus);
+-unlock:
+-	rcu_read_unlock();
+-}
++	/* make sure the requested cpu hasn't gone down in the meantime */
++	if (unlikely(busiest_cpu != smp_processor_id() ||
++		!busiest_rq->active_balance))
++		goto out_unlock;
+ 
+-/*
+- * This routine will record that the cpu is going idle with tick stopped.
+- * This info will be used in performing idle load balancing in the future.
+- */
+-void nohz_balance_enter_idle(int cpu)
+-{
+-	/*
+-	 * If this cpu is going down, then nothing needs to be done.
+-	 */
+-	if (!cpu_active(cpu))
+-		return;
++	/* Is there any task to move? */
++	if (busiest_rq->nr_running <= 1)
++		goto out_unlock;
+ 
+-	if (test_bit(NOHZ_TICK_STOPPED, nohz_flags(cpu)))
+-		return;
++	/* Task has migrated meanwhile, abort forced migration */
++	if (task_rq(p) != busiest_rq)
++		goto out_unlock;
+ 
+ 	/*
+-	 * If we're a completely isolated CPU, we don't play.
++	 * This condition is "impossible", if it occurs
++	 * we need to fix it. Originally reported by
++	 * Bjorn Helgaas on a 128-cpu setup.
+ 	 */
+-	if (on_null_domain(cpu_rq(cpu)))
+-		return;
++	BUG_ON(busiest_rq == target_rq);
+ 
+-	cpumask_set_cpu(cpu, nohz.idle_cpus_mask);
+-	atomic_inc(&nohz.nr_cpus);
+-	set_bit(NOHZ_TICK_STOPPED, nohz_flags(cpu));
+-}
++	/* move a task from busiest_rq to target_rq */
++	double_lock_balance(busiest_rq, target_rq);
+ 
+-static int sched_ilb_notifier(struct notifier_block *nfb,
+-					unsigned long action, void *hcpu)
+-{
+-	switch (action & ~CPU_TASKS_FROZEN) {
+-	case CPU_DYING:
+-		nohz_balance_exit_idle(smp_processor_id());
+-		return NOTIFY_OK;
+-	default:
+-		return NOTIFY_DONE;
++	/* Search for an sd spanning us and the target CPU. */
++	rcu_read_lock();
++	for_each_domain(target_cpu, sd) {
++		if (cpumask_test_cpu(busiest_cpu, sched_domain_span(sd)))
++			break;
+ 	}
+-}
+-#endif
++	if (likely(sd)) {
++		struct lb_env env = {
++			.sd		= sd,
++			.dst_cpu	= target_cpu,
++			.dst_rq		= target_rq,
++			.src_cpu	= busiest_rq->cpu,
++			.src_rq		= busiest_rq,
++			.idle		= CPU_IDLE,
++		};
+ 
+-static DEFINE_SPINLOCK(balancing);
++		schedstat_inc(sd, alb_count);
+ 
+-/*
+- * Scale the max load_balance interval with the number of CPUs in the system.
+- * This trades load-balance latency on larger machines for less cross talk.
+- */
+-void update_max_interval(void)
+-{
+-	max_load_balance_interval = HZ*num_online_cpus()/10;
++		if (move_specific_task(&env, p))
++			schedstat_inc(sd, alb_pushed);
++		else
++			schedstat_inc(sd, alb_failed);
++	}
++	rcu_read_unlock();
++	double_unlock_balance(busiest_rq, target_rq);
++out_unlock:
++	put_task_struct(p);
++	busiest_rq->active_balance = 0;
++	raw_spin_unlock_irq(&busiest_rq->lock);
++	return 0;
+ }
+ 
+ /*
+- * It checks each scheduling domain to see if it is due to be balanced,
+- * and initiates a balancing operation if so.
++ * Move task in a runnable state to another CPU.
+  *
+- * Balancing parameters are set up in init_sched_domains.
++ * Tailored on 'active_load_balance_stop_cpu' with slight
++ * modification to locking and pre-transfer checks.  Note
++ * rq->lock must be held before calling.
+  */
+-static void rebalance_domains(struct rq *rq, enum cpu_idle_type idle)
++static void hmp_migrate_runnable_task(struct rq *rq)
+ {
+-	int continue_balancing = 1;
+-	int cpu = rq->cpu;
+-	unsigned long interval;
+ 	struct sched_domain *sd;
+-	/* Earliest time when we have to do rebalance again */
+-	unsigned long next_balance = jiffies + 60*HZ;
+-	int update_next_balance = 0;
+-	int need_serialize, need_decay = 0;
+-	u64 max_cost = 0;
+-
+-	update_blocked_averages(cpu);
+-
+-	rcu_read_lock();
+-	for_each_domain(cpu, sd) {
+-		/*
+-		 * Decay the newidle max times here because this is a regular
+-		 * visit to all the domains. Decay ~1% per second.
+-		 */
+-		if (time_after(jiffies, sd->next_decay_max_lb_cost)) {
+-			sd->max_newidle_lb_cost =
+-				(sd->max_newidle_lb_cost * 253) / 256;
+-			sd->next_decay_max_lb_cost = jiffies + HZ;
+-			need_decay = 1;
+-		}
+-		max_cost += sd->max_newidle_lb_cost;
++	int src_cpu = cpu_of(rq);
++	struct rq *src_rq = rq;
++	int dst_cpu = rq->push_cpu;
++	struct rq *dst_rq = cpu_rq(dst_cpu);
++	struct task_struct *p = rq->migrate_task;
++	/*
++	 * One last check to make sure nobody else is playing
++	 * with the source rq.
++	 */
++	if (src_rq->active_balance)
++		goto out;
+ 
+-		if (!(sd->flags & SD_LOAD_BALANCE))
+-			continue;
++	if (src_rq->nr_running <= 1)
++		goto out;
+ 
+-		/*
+-		 * Stop the load balance at this level. There is another
+-		 * CPU in our sched group which is doing load balancing more
+-		 * actively.
+-		 */
+-		if (!continue_balancing) {
+-			if (need_decay)
+-				continue;
++	if (task_rq(p) != src_rq)
++		goto out;
++	/*
++	 * Not sure if this applies here but one can never
++	 * be too cautious
++	 */
++	BUG_ON(src_rq == dst_rq);
++
++	double_lock_balance(src_rq, dst_rq);
++
++	rcu_read_lock();
++	for_each_domain(dst_cpu, sd) {
++		if (cpumask_test_cpu(src_cpu, sched_domain_span(sd)))
+ 			break;
+-		}
++	}
+ 
+-		interval = get_sd_balance_interval(sd, idle != CPU_IDLE);
++	if (likely(sd)) {
++		struct lb_env env = {
++			.sd             = sd,
++			.dst_cpu        = dst_cpu,
++			.dst_rq         = dst_rq,
++			.src_cpu        = src_cpu,
++			.src_rq         = src_rq,
++			.idle           = CPU_IDLE,
++		};
+ 
+-		need_serialize = sd->flags & SD_SERIALIZE;
+-		if (need_serialize) {
+-			if (!spin_trylock(&balancing))
+-				goto out;
+-		}
++		schedstat_inc(sd, alb_count);
+ 
+-		if (time_after_eq(jiffies, sd->last_balance + interval)) {
+-			if (load_balance(cpu, rq, sd, idle, &continue_balancing)) {
+-				/*
+-				 * The LBF_DST_PINNED logic could have changed
+-				 * env->dst_cpu, so we can't know our idle
+-				 * state even if we migrated tasks. Update it.
+-				 */
+-				idle = idle_cpu(cpu) ? CPU_IDLE : CPU_NOT_IDLE;
+-			}
+-			sd->last_balance = jiffies;
+-			interval = get_sd_balance_interval(sd, idle != CPU_IDLE);
+-		}
+-		if (need_serialize)
+-			spin_unlock(&balancing);
+-out:
+-		if (time_after(next_balance, sd->last_balance + interval)) {
+-			next_balance = sd->last_balance + interval;
+-			update_next_balance = 1;
+-		}
+-	}
+-	if (need_decay) {
+-		/*
+-		 * Ensure the rq-wide value also decays but keep it at a
+-		 * reasonable floor to avoid funnies with rq->avg_idle.
+-		 */
+-		rq->max_idle_balance_cost =
+-			max((u64)sysctl_sched_migration_cost, max_cost);
++		if (move_specific_task(&env, p))
++			schedstat_inc(sd, alb_pushed);
++		else
++			schedstat_inc(sd, alb_failed);
+ 	}
+-	rcu_read_unlock();
+ 
+-	/*
+-	 * next_balance will be updated only when there is a need.
+-	 * When the cpu is attached to null domain for ex, it will not be
+-	 * updated.
+-	 */
+-	if (likely(update_next_balance))
+-		rq->next_balance = next_balance;
++	rcu_read_unlock();
++	double_unlock_balance(src_rq, dst_rq);
++out:
++	put_task_struct(p);
+ }
+ 
+-#ifdef CONFIG_NO_HZ_COMMON
++static DEFINE_SPINLOCK(hmp_force_migration);
++
+ /*
+- * In CONFIG_NO_HZ_COMMON case, the idle balance kickee will do the
+- * rebalancing for all the cpus for whom scheduler ticks are stopped.
++ * hmp_force_up_migration checks runqueues for tasks that need to
++ * be actively migrated to a faster cpu.
+  */
+-static void nohz_idle_balance(struct rq *this_rq, enum cpu_idle_type idle)
++static void hmp_force_up_migration(int this_cpu)
+ {
+-	int this_cpu = this_rq->cpu;
+-	struct rq *rq;
+-	int balance_cpu;
+-
+-	if (idle != CPU_IDLE ||
+-	    !test_bit(NOHZ_BALANCE_KICK, nohz_flags(this_cpu)))
+-		goto end;
++	int cpu, target_cpu;
++	struct sched_entity *curr, *orig;
++	struct rq *target;
++	unsigned long flags;
++	unsigned int force, got_target;
++	struct task_struct *p;
+ 
+-	for_each_cpu(balance_cpu, nohz.idle_cpus_mask) {
+-		if (balance_cpu == this_cpu || !idle_cpu(balance_cpu))
++	if (!spin_trylock(&hmp_force_migration))
++		return;
++	for_each_online_cpu(cpu) {
++		force = 0;
++		got_target = 0;
++		target = cpu_rq(cpu);
++		raw_spin_lock_irqsave(&target->lock, flags);
++		curr = target->cfs.curr;
++		if (!curr || target->active_balance) {
++			raw_spin_unlock_irqrestore(&target->lock, flags);
+ 			continue;
++		}
++		if (!entity_is_task(curr)) {
++			struct cfs_rq *cfs_rq;
+ 
++			cfs_rq = group_cfs_rq(curr);
++			while (cfs_rq) {
++				curr = cfs_rq->curr;
++				cfs_rq = group_cfs_rq(curr);
++			}
++		}
++		orig = curr;
++		curr = hmp_get_heaviest_task(curr, -1);
++		if (!curr) {
++			raw_spin_unlock_irqrestore(&target->lock, flags);
++			continue;
++		}
++		p = task_of(curr);
++		if (hmp_up_migration(cpu, &target_cpu, curr)) {
++			cpu_rq(target_cpu)->wake_for_idle_pull = 1;
++			raw_spin_unlock_irqrestore(&target->lock, flags);
++			spin_unlock(&hmp_force_migration);
++			smp_send_reschedule(target_cpu);
++			return;
++		}
++		if (!got_target) {
++			/*
++			 * For now we just check the currently running task.
++			 * Selecting the lightest task for offloading will
++			 * require extensive book keeping.
++			 */
++			curr = hmp_get_lightest_task(orig, 1);
++			p = task_of(curr);
++			target->push_cpu = hmp_offload_down(cpu, curr);
++			if (target->push_cpu < NR_CPUS) {
++				get_task_struct(p);
++				target->migrate_task = p;
++				got_target = 1;
++				trace_sched_hmp_migrate(p, target->push_cpu,
++						HMP_MIGRATE_OFFLOAD);
++				hmp_next_down_delay(&p->se, target->push_cpu);
++			}
++		}
+ 		/*
+-		 * If this cpu gets work to do, stop the load balancing
+-		 * work being done for other cpus. Next load
+-		 * balancing owner will pick it up.
+-		 */
+-		if (need_resched())
+-			break;
+-
+-		rq = cpu_rq(balance_cpu);
+-
+-		/*
+-		 * If time for next balance is due,
+-		 * do the balance.
++		 * We have a target with no active_balance.  If the task
++		 * is not currently running move it, otherwise let the
++		 * CPU stopper take care of it.
+ 		 */
+-		if (time_after_eq(jiffies, rq->next_balance)) {
+-			raw_spin_lock_irq(&rq->lock);
+-			update_rq_clock(rq);
+-			update_idle_cpu_load(rq);
+-			raw_spin_unlock_irq(&rq->lock);
+-			rebalance_domains(rq, CPU_IDLE);
++		if (got_target) {
++			if (!task_running(target, p)) {
++				trace_sched_hmp_migrate_force_running(p, 0);
++				hmp_migrate_runnable_task(target);
++			} else {
++				target->active_balance = 1;
++				force = 1;
++			}
+ 		}
+ 
+-		if (time_after(this_rq->next_balance, rq->next_balance))
+-			this_rq->next_balance = rq->next_balance;
++		raw_spin_unlock_irqrestore(&target->lock, flags);
++
++		if (force)
++			stop_one_cpu_nowait(cpu_of(target),
++				hmp_active_task_migration_cpu_stop,
++				target, &target->active_balance_work);
+ 	}
+-	nohz.next_balance = this_rq->next_balance;
+-end:
+-	clear_bit(NOHZ_BALANCE_KICK, nohz_flags(this_cpu));
++	spin_unlock(&hmp_force_migration);
+ }
+-
+ /*
+- * Current heuristic for kicking the idle load balancer in the presence
+- * of an idle cpu is the system.
+- *   - This rq has more than one task.
+- *   - At any scheduler domain level, this cpu's scheduler group has multiple
+- *     busy cpu's exceeding the group's capacity.
+- *   - For SD_ASYM_PACKING, if the lower numbered cpu's in the scheduler
+- *     domain span are idle.
++ * hmp_idle_pull looks at little domain runqueues to see
++ * if a task should be pulled.
++ *
++ * Reuses hmp_force_migration spinlock.
++ *
+  */
+-static inline int nohz_kick_needed(struct rq *rq)
++static unsigned int hmp_idle_pull(int this_cpu)
+ {
+-	unsigned long now = jiffies;
+-	struct sched_domain *sd;
+-	struct sched_group_capacity *sgc;
+-	int nr_busy, cpu = rq->cpu;
+-
+-	if (unlikely(rq->idle_balance))
+-		return 0;
+-
+-       /*
+-	* We may be recently in ticked or tickless idle mode. At the first
+-	* busy tick after returning from idle, we will update the busy stats.
+-	*/
+-	set_cpu_sd_state_busy();
+-	nohz_balance_exit_idle(cpu);
++	int cpu;
++	struct sched_entity *curr, *orig;
++	struct hmp_domain *hmp_domain = NULL;
++	struct rq *target = NULL, *rq;
++	unsigned long flags, ratio = 0;
++	unsigned int force = 0;
++	struct task_struct *p = NULL;
+ 
+-	/*
+-	 * None are in tickless mode and hence no need for NOHZ idle load
+-	 * balancing.
+-	 */
+-	if (likely(!atomic_read(&nohz.nr_cpus)))
++	if (!hmp_cpu_is_slowest(this_cpu))
++		hmp_domain = hmp_slower_domain(this_cpu);
++	if (!hmp_domain)
+ 		return 0;
+ 
+-	if (time_before(now, nohz.next_balance))
++	if (!spin_trylock(&hmp_force_migration))
+ 		return 0;
+ 
+-	if (rq->nr_running >= 2)
+-		goto need_kick;
+-
+-	rcu_read_lock();
+-	sd = rcu_dereference(per_cpu(sd_busy, cpu));
+-
+-	if (sd) {
+-		sgc = sd->groups->sgc;
+-		nr_busy = atomic_read(&sgc->nr_busy_cpus);
+-
+-		if (nr_busy > 1)
+-			goto need_kick_unlock;
++	/* first select a task */
++	for_each_cpu(cpu, &hmp_domain->cpus) {
++		rq = cpu_rq(cpu);
++		raw_spin_lock_irqsave(&rq->lock, flags);
++		curr = rq->cfs.curr;
++		if (!curr) {
++			raw_spin_unlock_irqrestore(&rq->lock, flags);
++			continue;
++		}
++		if (!entity_is_task(curr)) {
++			struct cfs_rq *cfs_rq;
++
++			cfs_rq = group_cfs_rq(curr);
++			while (cfs_rq) {
++				curr = cfs_rq->curr;
++				if (!entity_is_task(curr))
++					cfs_rq = group_cfs_rq(curr);
++				else
++					cfs_rq = NULL;
++			}
++		}
++		orig = curr;
++		curr = hmp_get_heaviest_task(curr, this_cpu);
++		/* check if heaviest eligible task on this
++		 * CPU is heavier than previous task
++		 */
++		if (curr && hmp_task_eligible_for_up_migration(curr) &&
++			curr->avg.load_avg_ratio > ratio &&
++			cpumask_test_cpu(this_cpu,
++					tsk_cpus_allowed(task_of(curr)))) {
++			p = task_of(curr);
++			target = rq;
++			ratio = curr->avg.load_avg_ratio;
++		}
++		raw_spin_unlock_irqrestore(&rq->lock, flags);
+ 	}
+ 
+-	sd = rcu_dereference(per_cpu(sd_asym, cpu));
+-
+-	if (sd && (cpumask_first_and(nohz.idle_cpus_mask,
+-				  sched_domain_span(sd)) < cpu))
+-		goto need_kick_unlock;
++	if (!p)
++		goto done;
+ 
+-	rcu_read_unlock();
+-	return 0;
++	/* now we have a candidate */
++	raw_spin_lock_irqsave(&target->lock, flags);
++	if (!target->active_balance && task_rq(p) == target) {
++		get_task_struct(p);
++		target->push_cpu = this_cpu;
++		target->migrate_task = p;
++		trace_sched_hmp_migrate(p, target->push_cpu,
++				HMP_MIGRATE_IDLE_PULL);
++		hmp_next_up_delay(&p->se, target->push_cpu);
++		/*
++		 * if the task isn't running move it right away.
++		 * Otherwise setup the active_balance mechanic and let
++		 * the CPU stopper do its job.
++		 */
++		if (!task_running(target, p)) {
++			trace_sched_hmp_migrate_idle_running(p, 0);
++			hmp_migrate_runnable_task(target);
++		} else {
++			target->active_balance = 1;
++			force = 1;
++		}
++	}
++	raw_spin_unlock_irqrestore(&target->lock, flags);
+ 
+-need_kick_unlock:
+-	rcu_read_unlock();
+-need_kick:
+-	return 1;
++	if (force) {
++		/* start timer to keep us awake */
++		hmp_cpu_keepalive_trigger();
++		stop_one_cpu_nowait(cpu_of(target),
++			hmp_idle_pull_cpu_stop,
++			target, &target->active_balance_work);
++	}
++done:
++	spin_unlock(&hmp_force_migration);
++	return force;
+ }
+ #else
+-static void nohz_idle_balance(struct rq *this_rq, enum cpu_idle_type idle) { }
+-#endif
++static void hmp_force_up_migration(int this_cpu) { }
++#endif /* CONFIG_SCHED_HMP */
+ 
+ /*
+  * run_rebalance_domains is triggered when needed from the scheduler tick.
+@@ -7472,8 +9272,23 @@ static void run_rebalance_domains(struct softirq_action *h)
+ 	struct rq *this_rq = this_rq();
+ 	enum cpu_idle_type idle = this_rq->idle_balance ?
+ 						CPU_IDLE : CPU_NOT_IDLE;
++	int this_cpu = smp_processor_id();
+ 
+ 	rebalance_domains(this_rq, idle);
++#ifdef CONFIG_SCHED_HMP
++	/* shortcut for hmp idle pull wakeups */
++	if (unlikely(this_rq->wake_for_idle_pull)) {
++		this_rq->wake_for_idle_pull = 0;
++		if (hmp_idle_pull(this_cpu)) {
++			/* break out unless running nohz idle as well */
++			if (idle != CPU_IDLE)
++				return;
++		}
++	}
++#endif
++
++	hmp_force_up_migration(this_cpu);
++
+ 
+ 	/*
+ 	 * If this cpu has a pending nohz_balance_kick, then do the
+@@ -7502,6 +9317,9 @@ void trigger_load_balance(struct rq *rq)
+ 
+ static void rq_online_fair(struct rq *rq)
+ {
++#ifdef CONFIG_SCHED_HMP
++	hmp_online_cpu(rq->cpu);
++#endif
+ 	update_sysctl();
+ 
+ 	update_runtime_enabled(rq);
+@@ -7509,6 +9327,9 @@ static void rq_online_fair(struct rq *rq)
+ 
+ static void rq_offline_fair(struct rq *rq)
+ {
++#ifdef CONFIG_SCHED_HMP
++	hmp_offline_cpu(rq->cpu);
++#endif
+ 	update_sysctl();
+ 
+ 	/* Ensure any throttled groups are reachable by pick_next_task */
+@@ -7992,6 +9813,139 @@ __init void init_sched_fair_class(void)
+ 	zalloc_cpumask_var(&nohz.idle_cpus_mask, GFP_NOWAIT);
+ 	cpu_notifier(sched_ilb_notifier, 0);
+ #endif
++
++#ifdef CONFIG_SCHED_HMP
++	hmp_cpu_mask_setup();
++#endif
+ #endif /* SMP */
+ 
+ }
++
++#ifdef CONFIG_HMP_FREQUENCY_INVARIANT_SCALE
++static u32 cpufreq_calc_scale(u32 min, u32 max, u32 curr)
++{
++	u32 result = curr / max;
++	return result;
++}
++
++/* Called when the CPU Frequency is changed.
++ * Once for each CPU.
++ */
++static int cpufreq_callback(struct notifier_block *nb,
++					unsigned long val, void *data)
++{
++	struct cpufreq_freqs *freq = data;
++	int cpu = freq->cpu;
++	struct cpufreq_extents *extents;
++
++	if (freq->flags & CPUFREQ_CONST_LOOPS)
++		return NOTIFY_OK;
++
++	if (val != CPUFREQ_POSTCHANGE)
++		return NOTIFY_OK;
++
++	/* if dynamic load scale is disabled, set the load scale to 1.0 */
++	if (!hmp_data.freqinvar_load_scale_enabled) {
++		freq_scale[cpu].curr_scale = 1024;
++		return NOTIFY_OK;
++	}
++
++	extents = &freq_scale[cpu];
++	if (extents->flags & SCHED_LOAD_FREQINVAR_SINGLEFREQ) {
++		/* If our governor was recognised as a single-freq governor,
++		 * use 1.0
++		 */
++		extents->curr_scale = 1024;
++	} else {
++		extents->curr_scale = cpufreq_calc_scale(extents->min,
++				extents->max, freq->new);
++	}
++
++	return NOTIFY_OK;
++}
++
++/* Called when the CPUFreq governor is changed.
++ * Only called for the CPUs which are actually changed by the
++ * userspace.
++ */
++static int cpufreq_policy_callback(struct notifier_block *nb,
++				       unsigned long event, void *data)
++{
++	struct cpufreq_policy *policy = data;
++	struct cpufreq_extents *extents;
++	int cpu, singleFreq = 0;
++	static const char performance_governor[] = "performance";
++	static const char powersave_governor[] = "powersave";
++
++	if (event == CPUFREQ_START)
++		return 0;
++
++	if (event != CPUFREQ_INCOMPATIBLE)
++		return 0;
++
++	/* CPUFreq governors do not accurately report the range of
++	 * CPU Frequencies they will choose from.
++	 * We recognise performance and powersave governors as
++	 * single-frequency only.
++	 */
++	if (!strncmp(policy->governor->name, performance_governor,
++			strlen(performance_governor)) ||
++		!strncmp(policy->governor->name, powersave_governor,
++				strlen(powersave_governor)))
++		singleFreq = 1;
++
++	/* Make sure that all CPUs impacted by this policy are
++	 * updated since we will only get a notification when the
++	 * user explicitly changes the policy on a CPU.
++	 */
++	for_each_cpu(cpu, policy->cpus) {
++		extents = &freq_scale[cpu];
++		extents->max = policy->max >> SCHED_FREQSCALE_SHIFT;
++		extents->min = policy->min >> SCHED_FREQSCALE_SHIFT;
++		if (!hmp_data.freqinvar_load_scale_enabled) {
++			extents->curr_scale = 1024;
++		} else if (singleFreq) {
++			extents->flags |= SCHED_LOAD_FREQINVAR_SINGLEFREQ;
++			extents->curr_scale = 1024;
++		} else {
++			extents->flags &= ~SCHED_LOAD_FREQINVAR_SINGLEFREQ;
++			extents->curr_scale = cpufreq_calc_scale(extents->min,
++					extents->max, policy->cur);
++		}
++	}
++
++	return 0;
++}
++
++static struct notifier_block cpufreq_notifier = {
++	.notifier_call  = cpufreq_callback,
++};
++static struct notifier_block cpufreq_policy_notifier = {
++	.notifier_call  = cpufreq_policy_callback,
++};
++
++static int __init register_sched_cpufreq_notifier(void)
++{
++	int ret = 0;
++
++	/* init safe defaults since there are no policies at registration */
++	for (ret = 0; ret < CONFIG_NR_CPUS; ret++) {
++		/* safe defaults */
++		freq_scale[ret].max = 1024;
++		freq_scale[ret].min = 1024;
++		freq_scale[ret].curr_scale = 1024;
++	}
++
++	pr_info("sched: registering cpufreq notifiers for scale-invariant loads\n");
++	ret = cpufreq_register_notifier(&cpufreq_policy_notifier,
++			CPUFREQ_POLICY_NOTIFIER);
++
++	if (ret != -EINVAL)
++		ret = cpufreq_register_notifier(&cpufreq_notifier,
++			CPUFREQ_TRANSITION_NOTIFIER);
++
++	return ret;
++}
++
++core_initcall(register_sched_cpufreq_notifier);
++#endif /* CONFIG_HMP_FREQUENCY_INVARIANT_SCALE */
+diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
+index 2df8ef0..6455961 100644
+--- a/kernel/sched/sched.h
++++ b/kernel/sched/sched.h
+@@ -218,7 +218,7 @@ struct task_group {
+ 
+ #ifdef	CONFIG_SMP
+ 	atomic_long_t load_avg;
+-	atomic_t runnable_avg;
++	atomic_t runnable_avg, usage_avg;
+ #endif
+ #endif
+ 
+@@ -351,7 +351,7 @@ struct cfs_rq {
+ 
+ #ifdef CONFIG_FAIR_GROUP_SCHED
+ 	/* Required to track per-cpu representation of a task_group */
+-	u32 tg_runnable_contrib;
++	u32 tg_runnable_contrib, tg_usage_contrib;
+ 	unsigned long tg_load_contrib;
+ 
+ 	/*
+@@ -507,6 +507,12 @@ struct root_domain {
+ 
+ extern struct root_domain def_root_domain;
+ 
++#ifdef CONFIG_SCHED_HMP
++static LIST_HEAD(hmp_domains);
++DECLARE_PER_CPU(struct hmp_domain *, hmp_cpu_domain);
++#define hmp_cpu_domain(cpu)	(per_cpu(hmp_cpu_domain, (cpu)))
++#endif /* CONFIG_SCHED_HMP */
++
+ #endif /* CONFIG_SMP */
+ 
+ /*
+@@ -586,6 +592,10 @@ struct rq {
+ 	int active_balance;
+ 	int push_cpu;
+ 	struct cpu_stop_work active_balance_work;
++#ifdef CONFIG_SCHED_HMP
++	struct task_struct *migrate_task;
++	int wake_for_idle_pull;
++#endif
+ 	/* cpu of this runqueue: */
+ 	int cpu;
+ 	int online;
+diff --git a/kernel/sys.c b/kernel/sys.c
+index 1eaa2f0..38a2099 100644
+--- a/kernel/sys.c
++++ b/kernel/sys.c
+@@ -41,6 +41,9 @@
+ #include <linux/syscore_ops.h>
+ #include <linux/version.h>
+ #include <linux/ctype.h>
++#include <linux/mm.h>
++#include <linux/mempolicy.h>
++#include <linux/sched.h>
+ 
+ #include <linux/compat.h>
+ #include <linux/syscalls.h>
+@@ -2025,10 +2028,158 @@ static int prctl_get_tid_address(struct task_struct *me, int __user **tid_addr)
+ }
+ #endif
+ 
++#ifdef CONFIG_MMU
++static int prctl_update_vma_anon_name(struct vm_area_struct *vma,
++		struct vm_area_struct **prev,
++		unsigned long start, unsigned long end,
++		const char __user *name_addr)
++{
++	struct mm_struct * mm = vma->vm_mm;
++	int error = 0;
++	pgoff_t pgoff;
++
++	if (name_addr == vma_get_anon_name(vma)) {
++		*prev = vma;
++		goto out;
++	}
++
++	pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT);
++	*prev = vma_merge(mm, *prev, start, end, vma->vm_flags, vma->anon_vma,
++				vma->vm_file, pgoff, vma_policy(vma),
++				name_addr);
++	if (*prev) {
++		vma = *prev;
++		goto success;
++	}
++
++	*prev = vma;
++
++	if (start != vma->vm_start) {
++		error = split_vma(mm, vma, start, 1);
++		if (error)
++			goto out;
++	}
++
++	if (end != vma->vm_end) {
++		error = split_vma(mm, vma, end, 0);
++		if (error)
++			goto out;
++	}
++
++success:
++	if (!vma->vm_file)
++		vma->shared.anon_name = name_addr;
++
++out:
++	if (error == -ENOMEM)
++		error = -EAGAIN;
++	return error;
++}
++
++static int prctl_set_vma_anon_name(unsigned long start, unsigned long end,
++			unsigned long arg)
++{
++	unsigned long tmp;
++	struct vm_area_struct * vma, *prev;
++	int unmapped_error = 0;
++	int error = -EINVAL;
++
++	/*
++	 * If the interval [start,end) covers some unmapped address
++	 * ranges, just ignore them, but return -ENOMEM at the end.
++	 * - this matches the handling in madvise.
++	 */
++	vma = find_vma_prev(current->mm, start, &prev);
++	if (vma && start > vma->vm_start)
++		prev = vma;
++
++	for (;;) {
++		/* Still start < end. */
++		error = -ENOMEM;
++		if (!vma)
++			return error;
++
++		/* Here start < (end|vma->vm_end). */
++		if (start < vma->vm_start) {
++			unmapped_error = -ENOMEM;
++			start = vma->vm_start;
++			if (start >= end)
++				return error;
++		}
++
++		/* Here vma->vm_start <= start < (end|vma->vm_end) */
++		tmp = vma->vm_end;
++		if (end < tmp)
++			tmp = end;
++
++		/* Here vma->vm_start <= start < tmp <= (end|vma->vm_end). */
++		error = prctl_update_vma_anon_name(vma, &prev, start, tmp,
++				(const char __user *)arg);
++		if (error)
++			return error;
++		start = tmp;
++		if (prev && start < prev->vm_end)
++			start = prev->vm_end;
++		error = unmapped_error;
++		if (start >= end)
++			return error;
++		if (prev)
++			vma = prev->vm_next;
++		else	/* madvise_remove dropped mmap_sem */
++			vma = find_vma(current->mm, start);
++	}
++}
++
++static int prctl_set_vma(unsigned long opt, unsigned long start,
++		unsigned long len_in, unsigned long arg)
++{
++	struct mm_struct *mm = current->mm;
++	int error;
++	unsigned long len;
++	unsigned long end;
++
++	if (start & ~PAGE_MASK)
++		return -EINVAL;
++	len = (len_in + ~PAGE_MASK) & PAGE_MASK;
++
++	/* Check to see whether len was rounded up from small -ve to zero */
++	if (len_in && !len)
++		return -EINVAL;
++
++	end = start + len;
++	if (end < start)
++		return -EINVAL;
++
++	if (end == start)
++		return 0;
++
++	down_write(&mm->mmap_sem);
++
++	switch (opt) {
++	case PR_SET_VMA_ANON_NAME:
++		error = prctl_set_vma_anon_name(start, end, arg);
++		break;
++	default:
++		error = -EINVAL;
++	}
++
++	up_write(&mm->mmap_sem);
++
++	return error;
++}
++#else /* CONFIG_MMU */
++static int prctl_set_vma(unsigned long opt, unsigned long start,
++		unsigned long len_in, unsigned long arg)
++{
++	return -EINVAL;
++}
++#endif
++
+ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
+ 		unsigned long, arg4, unsigned long, arg5)
+ {
+ 	struct task_struct *me = current;
++	struct task_struct *tsk;
+ 	unsigned char comm[sizeof(me->comm)];
+ 	long error;
+ 
+@@ -2171,6 +2322,26 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
+ 	case PR_GET_TID_ADDRESS:
+ 		error = prctl_get_tid_address(me, (int __user **)arg2);
+ 		break;
++	case PR_SET_TIMERSLACK_PID:
++		if (task_pid_vnr(current) != (pid_t)arg3 &&
++				!capable(CAP_SYS_NICE))
++			return -EPERM;
++		rcu_read_lock();
++		tsk = find_task_by_vpid((pid_t)arg3);
++		if (tsk == NULL) {
++			rcu_read_unlock();
++			return -EINVAL;
++		}
++		get_task_struct(tsk);
++		rcu_read_unlock();
++		if (arg2 <= 0)
++			tsk->timer_slack_ns =
++				tsk->default_timer_slack_ns;
++		else
++			tsk->timer_slack_ns = arg2;
++		put_task_struct(tsk);
++		error = 0;
++		break;
+ 	case PR_SET_CHILD_SUBREAPER:
+ 		me->signal->is_child_subreaper = !!arg2;
+ 		break;
+@@ -2203,6 +2374,9 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
+ 			me->mm->def_flags &= ~VM_NOHUGEPAGE;
+ 		up_write(&me->mm->mmap_sem);
+ 		break;
++	case PR_SET_VMA:
++		error = prctl_set_vma(arg2, arg3, arg4, arg5);
++		break;
+ 	default:
+ 		error = -EINVAL;
+ 		break;
+diff --git a/kernel/sysctl.c b/kernel/sysctl.c
+index cd0e835..5ef8871 100644
+--- a/kernel/sysctl.c
++++ b/kernel/sysctl.c
+@@ -104,6 +104,8 @@ extern char core_pattern[];
+ extern unsigned int core_pipe_limit;
+ #endif
+ extern int pid_max;
++extern int extra_free_kbytes;
++extern int min_free_order_shift;
+ extern int pid_max_min, pid_max_max;
+ extern int percpu_pagelist_fraction;
+ extern int compat_log;
+@@ -1308,6 +1310,21 @@ static struct ctl_table vm_table[] = {
+ 		.extra1		= &zero,
+ 	},
+ 	{
++		.procname	= "extra_free_kbytes",
++		.data		= &extra_free_kbytes,
++		.maxlen		= sizeof(extra_free_kbytes),
++		.mode		= 0644,
++		.proc_handler	= min_free_kbytes_sysctl_handler,
++		.extra1		= &zero,
++	},
++	{
++		.procname	= "min_free_order_shift",
++		.data		= &min_free_order_shift,
++		.maxlen		= sizeof(min_free_order_shift),
++		.mode		= 0644,
++		.proc_handler	= &proc_dointvec
++	},
++	{
+ 		.procname	= "percpu_pagelist_fraction",
+ 		.data		= &percpu_pagelist_fraction,
+ 		.maxlen		= sizeof(percpu_pagelist_fraction),
+@@ -1483,6 +1500,15 @@ static struct ctl_table vm_table[] = {
+ 		.mode		= 0644,
+ 		.proc_handler	= proc_doulongvec_minmax,
+ 	},
++#ifdef CONFIG_CMA_ADVANCE_SHARE
++	{
++		.procname	= "cma_watermark",
++		.data		= &cma_watermark,
++		.maxlen		= sizeof(cma_watermark),
++		.mode		= 0644,
++		.proc_handler	= cma_watermark_sysctl_handler,
++	},
++#endif
+ 	{ }
+ };
+ 
+@@ -1656,6 +1682,20 @@ static struct ctl_table fs_table[] = {
+ 		.proc_handler	= &pipe_proc_fn,
+ 		.extra1		= &pipe_min_size,
+ 	},
++	{
++		.procname	= "pipe-user-pages-hard",
++		.data		= &pipe_user_pages_hard,
++		.maxlen		= sizeof(pipe_user_pages_hard),
++		.mode		= 0644,
++		.proc_handler	= proc_doulongvec_minmax,
++	},
++	{
++		.procname	= "pipe-user-pages-soft",
++		.data		= &pipe_user_pages_soft,
++		.maxlen		= sizeof(pipe_user_pages_soft),
++		.mode		= 0644,
++		.proc_handler	= proc_doulongvec_minmax,
++	},
+ 	{ }
+ };
+ 
+diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
+index a5da09c..37e1fb8 100644
+--- a/kernel/trace/Kconfig
++++ b/kernel/trace/Kconfig
+@@ -77,6 +77,9 @@ config EVENT_TRACING
+ 	select CONTEXT_SWITCH_TRACER
+ 	bool
+ 
++config GPU_TRACEPOINTS
++	bool
++
+ config CONTEXT_SWITCH_TRACER
+ 	bool
+ 
+diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile
+index 67d6369..5da3cfb 100644
+--- a/kernel/trace/Makefile
++++ b/kernel/trace/Makefile
+@@ -63,6 +63,7 @@ obj-$(CONFIG_KGDB_KDB) += trace_kdb.o
+ endif
+ obj-$(CONFIG_PROBE_EVENTS) += trace_probe.o
+ obj-$(CONFIG_UPROBE_EVENT) += trace_uprobe.o
++obj-$(CONFIG_GPU_TRACEPOINTS) += gpu-traces.o
+ 
+ obj-$(CONFIG_TRACEPOINT_BENCHMARK) += trace_benchmark.o
+ 
+diff --git a/kernel/trace/gpu-traces.c b/kernel/trace/gpu-traces.c
+new file mode 100644
+index 0000000..a4b3f00
+--- /dev/null
++++ b/kernel/trace/gpu-traces.c
+@@ -0,0 +1,23 @@
++/*
++ * GPU tracepoints
++ *
++ * Copyright (C) 2013 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#include <linux/module.h>
++
++#define CREATE_TRACE_POINTS
++#include <trace/events/gpu.h>
++
++EXPORT_TRACEPOINT_SYMBOL(gpu_sched_switch);
++EXPORT_TRACEPOINT_SYMBOL(gpu_job_enqueue);
+diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
+index 72c7134..637f572 100644
+--- a/kernel/trace/trace.c
++++ b/kernel/trace/trace.c
+@@ -812,6 +812,7 @@ static const char *trace_options[] = {
+ 	"irq-info",
+ 	"markers",
+ 	"function-trace",
++	"print-tgid",
+ 	NULL
+ };
+ 
+@@ -1279,6 +1280,7 @@ void tracing_reset_all_online_cpus(void)
+ 
+ #define SAVED_CMDLINES_DEFAULT 128
+ #define NO_CMDLINE_MAP UINT_MAX
++static unsigned saved_tgids[SAVED_CMDLINES_DEFAULT];
+ static arch_spinlock_t trace_cmdline_lock = __ARCH_SPIN_LOCK_UNLOCKED;
+ struct saved_cmdlines_buffer {
+ 	unsigned map_pid_to_cmdline[PID_MAX_DEFAULT+1];
+@@ -1517,7 +1519,7 @@ static int trace_save_cmdline(struct task_struct *tsk)
+ 	}
+ 
+ 	set_cmdline(idx, tsk->comm);
+-
++	saved_tgids[idx] = tsk->tgid;
+ 	arch_spin_unlock(&trace_cmdline_lock);
+ 
+ 	return 1;
+@@ -1560,6 +1562,25 @@ void trace_find_cmdline(int pid, char comm[])
+ 	preempt_enable();
+ }
+ 
++int trace_find_tgid(int pid)
++{
++	unsigned map;
++	int tgid;
++
++	preempt_disable();
++	arch_spin_lock(&trace_cmdline_lock);
++	map = savedcmd->map_pid_to_cmdline[pid];
++	if (map != NO_CMDLINE_MAP)
++		tgid = saved_tgids[map];
++	else
++		tgid = -1;
++
++	arch_spin_unlock(&trace_cmdline_lock);
++	preempt_enable();
++
++	return tgid;
++}
++
+ void tracing_record_cmdline(struct task_struct *tsk)
+ {
+ 	if (atomic_read(&trace_record_cmdline_disabled) || !tracing_is_on())
+@@ -2537,6 +2558,13 @@ static void print_func_help_header(struct trace_buffer *buf, struct seq_file *m)
+ 	seq_puts(m, "#              | |       |          |         |\n");
+ }
+ 
++static void print_func_help_header_tgid(struct trace_buffer *buf, struct seq_file *m)
++{
++	print_event_info(buf, m);
++	seq_puts(m, "#           TASK-PID    TGID   CPU#      TIMESTAMP  FUNCTION\n");
++	seq_puts(m, "#              | |        |      |          |         |\n");
++}
++
+ static void print_func_help_header_irq(struct trace_buffer *buf, struct seq_file *m)
+ {
+ 	print_event_info(buf, m);
+@@ -2549,6 +2577,18 @@ static void print_func_help_header_irq(struct trace_buffer *buf, struct seq_file
+ 	seq_puts(m, "#              | |       |   ||||       |         |\n");
+ }
+ 
++static void print_func_help_header_irq_tgid(struct trace_buffer *buf, struct seq_file *m)
++{
++	print_event_info(buf, m);
++	seq_puts(m, "#                                      _-----=> irqs-off\n");
++	seq_puts(m, "#                                     / _----=> need-resched\n");
++	seq_puts(m, "#                                    | / _---=> hardirq/softirq\n");
++	seq_puts(m, "#                                    || / _--=> preempt-depth\n");
++	seq_puts(m, "#                                    ||| /     delay\n");
++	seq_puts(m, "#           TASK-PID    TGID   CPU#  ||||    TIMESTAMP  FUNCTION\n");
++	seq_puts(m, "#              | |        |      |   ||||       |         |\n");
++}
++
+ void
+ print_trace_header(struct seq_file *m, struct trace_iterator *iter)
+ {
+@@ -2849,9 +2889,15 @@ void trace_default_header(struct seq_file *m)
+ 	} else {
+ 		if (!(trace_flags & TRACE_ITER_VERBOSE)) {
+ 			if (trace_flags & TRACE_ITER_IRQ_INFO)
+-				print_func_help_header_irq(iter->trace_buffer, m);
++				if (trace_flags & TRACE_ITER_TGID)
++					print_func_help_header_irq_tgid(iter->trace_buffer, m);
++				else
++					print_func_help_header_irq(iter->trace_buffer, m);
+ 			else
+-				print_func_help_header(iter->trace_buffer, m);
++				if (trace_flags & TRACE_ITER_TGID)
++					print_func_help_header_tgid(iter->trace_buffer, m);
++				else
++					print_func_help_header(iter->trace_buffer, m);
+ 		}
+ 	}
+ }
+@@ -3897,6 +3943,50 @@ static const struct file_operations tracing_saved_cmdlines_size_fops = {
+ };
+ 
+ static ssize_t
++tracing_saved_tgids_read(struct file *file, char __user *ubuf,
++				size_t cnt, loff_t *ppos)
++{
++	char *file_buf;
++	char *buf;
++	int len = 0;
++	int pid;
++	int i;
++
++	file_buf = kmalloc(SAVED_CMDLINES_DEFAULT*(16+1+16), GFP_KERNEL);
++	if (!file_buf)
++		return -ENOMEM;
++
++	buf = file_buf;
++
++	for (i = 0; i < SAVED_CMDLINES_DEFAULT; i++) {
++		int tgid;
++		int r;
++
++		pid = savedcmd->map_cmdline_to_pid[i];
++		if (pid == -1 || pid == NO_CMDLINE_MAP)
++			continue;
++
++		tgid = trace_find_tgid(pid);
++		r = sprintf(buf, "%d %d\n", pid, tgid);
++		buf += r;
++		len += r;
++	}
++
++	len = simple_read_from_buffer(ubuf, cnt, ppos,
++				      file_buf, len);
++
++	kfree(file_buf);
++
++	return len;
++}
++
++static const struct file_operations tracing_saved_tgids_fops = {
++	.open	= tracing_open_generic,
++	.read	= tracing_saved_tgids_read,
++	.llseek	= generic_file_llseek,
++};
++
++static ssize_t
+ tracing_set_trace_read(struct file *filp, char __user *ubuf,
+ 		       size_t cnt, loff_t *ppos)
+ {
+@@ -6520,6 +6610,9 @@ init_tracer_debugfs(struct trace_array *tr, struct dentry *d_tracer)
+ 	trace_create_file("trace_marker", 0220, d_tracer,
+ 			  tr, &tracing_mark_fops);
+ 
++	trace_create_file("saved_tgids", 0444, d_tracer,
++			  tr, &tracing_saved_tgids_fops);
++
+ 	trace_create_file("trace_clock", 0644, d_tracer, tr,
+ 			  &trace_clock_fops);
+ 
+diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
+index 5642436..0d2f587 100644
+--- a/kernel/trace/trace.h
++++ b/kernel/trace/trace.h
+@@ -659,6 +659,7 @@ static inline void __trace_stack(struct trace_array *tr, unsigned long flags,
+ extern cycle_t ftrace_now(int cpu);
+ 
+ extern void trace_find_cmdline(int pid, char comm[]);
++extern int trace_find_tgid(int pid);
+ 
+ #ifdef CONFIG_DYNAMIC_FTRACE
+ extern unsigned long ftrace_update_tot_cnt;
+@@ -939,6 +940,7 @@ enum trace_iterator_flags {
+ 	TRACE_ITER_IRQ_INFO		= 0x800000,
+ 	TRACE_ITER_MARKERS		= 0x1000000,
+ 	TRACE_ITER_FUNCTION		= 0x2000000,
++	TRACE_ITER_TGID 		= 0x4000000,
+ };
+ 
+ /*
+diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c
+index 2964333..70c2f41 100644
+--- a/kernel/trace/trace_functions_graph.c
++++ b/kernel/trace/trace_functions_graph.c
+@@ -65,6 +65,9 @@ struct fgraph_data {
+ 
+ #define TRACE_GRAPH_INDENT	2
+ 
++/* Flag options */
++#define TRACE_GRAPH_PRINT_FLAT		0x80
++
+ static unsigned int max_depth;
+ 
+ static struct tracer_opt trace_opts[] = {
+@@ -84,6 +87,8 @@ static struct tracer_opt trace_opts[] = {
+ 	{ TRACER_OPT(funcgraph-irqs, TRACE_GRAPH_PRINT_IRQS) },
+ 	/* Display function name after trailing } */
+ 	{ TRACER_OPT(funcgraph-tail, TRACE_GRAPH_PRINT_TAIL) },
++	/* Use standard trace formatting rather than hierarchical */
++	{ TRACER_OPT(funcgraph-flat, TRACE_GRAPH_PRINT_FLAT) },
+ 	{ } /* Empty entry */
+ };
+ 
+@@ -1314,6 +1319,9 @@ print_graph_function_flags(struct trace_iterator *iter, u32 flags)
+ 	int cpu = iter->cpu;
+ 	int ret;
+ 
++	if (flags & TRACE_GRAPH_PRINT_FLAT)
++		return TRACE_TYPE_UNHANDLED;
++
+ 	if (data && per_cpu_ptr(data->cpu_data, cpu)->ignore) {
+ 		per_cpu_ptr(data->cpu_data, cpu)->ignore = 0;
+ 		return TRACE_TYPE_HANDLED;
+@@ -1371,13 +1379,6 @@ print_graph_function(struct trace_iterator *iter)
+ 	return print_graph_function_flags(iter, tracer_flags.val);
+ }
+ 
+-static enum print_line_t
+-print_graph_function_event(struct trace_iterator *iter, int flags,
+-			   struct trace_event *event)
+-{
+-	return print_graph_function(iter);
+-}
+-
+ static void print_lat_header(struct seq_file *s, u32 flags)
+ {
+ 	static const char spaces[] = "                "	/* 16 spaces */
+@@ -1444,6 +1445,11 @@ void print_graph_headers_flags(struct seq_file *s, u32 flags)
+ {
+ 	struct trace_iterator *iter = s->private;
+ 
++	if (flags & TRACE_GRAPH_PRINT_FLAT) {
++		trace_default_header(s);
++		return;
++	}
++
+ 	if (!(trace_flags & TRACE_ITER_CONTEXT_INFO))
+ 		return;
+ 
+@@ -1519,19 +1525,6 @@ func_graph_set_flag(struct trace_array *tr, u32 old_flags, u32 bit, int set)
+ 	return 0;
+ }
+ 
+-static struct trace_event_functions graph_functions = {
+-	.trace		= print_graph_function_event,
+-};
+-
+-static struct trace_event graph_trace_entry_event = {
+-	.type		= TRACE_GRAPH_ENT,
+-	.funcs		= &graph_functions,
+-};
+-
+-static struct trace_event graph_trace_ret_event = {
+-	.type		= TRACE_GRAPH_RET,
+-	.funcs		= &graph_functions
+-};
+ 
+ static struct tracer graph_trace __tracer_data = {
+ 	.name		= "function_graph",
+@@ -1608,16 +1601,6 @@ static __init int init_graph_trace(void)
+ {
+ 	max_bytes_for_cpu = snprintf(NULL, 0, "%d", nr_cpu_ids - 1);
+ 
+-	if (!register_ftrace_event(&graph_trace_entry_event)) {
+-		pr_warning("Warning: could not register graph trace events\n");
+-		return 1;
+-	}
+-
+-	if (!register_ftrace_event(&graph_trace_ret_event)) {
+-		pr_warning("Warning: could not register graph trace events\n");
+-		return 1;
+-	}
+-
+ 	return register_tracer(&graph_trace);
+ }
+ 
+diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c
+index c6977d5..a2b8202 100644
+--- a/kernel/trace/trace_output.c
++++ b/kernel/trace/trace_output.c
+@@ -186,6 +186,50 @@ ftrace_print_hex_seq(struct trace_seq *p, const unsigned char *buf, int buf_len)
+ }
+ EXPORT_SYMBOL(ftrace_print_hex_seq);
+ 
++const char *
++ftrace_print_array_seq(struct trace_seq *p, const void *buf, int buf_len,
++		       size_t el_size)
++{
++	const char *ret = trace_seq_buffer_ptr(p);
++	const char *prefix = "";
++	void *ptr = (void *)buf;
++
++	trace_seq_putc(p, '{');
++
++	while (ptr < buf + buf_len) {
++		switch (el_size) {
++		case 1:
++			trace_seq_printf(p, "%s0x%x", prefix,
++					 *(u8 *)ptr);
++			break;
++		case 2:
++			trace_seq_printf(p, "%s0x%x", prefix,
++					 *(u16 *)ptr);
++			break;
++		case 4:
++			trace_seq_printf(p, "%s0x%x", prefix,
++					 *(u32 *)ptr);
++			break;
++		case 8:
++			trace_seq_printf(p, "%s0x%llx", prefix,
++					 *(u64 *)ptr);
++			break;
++		default:
++			trace_seq_printf(p, "BAD SIZE:%zu 0x%x", el_size,
++					 *(u8 *)ptr);
++			el_size = 1;
++		}
++		prefix = ",";
++		ptr += el_size;
++	}
++
++	trace_seq_putc(p, '}');
++	trace_seq_putc(p, 0);
++
++	return ret;
++}
++EXPORT_SYMBOL(ftrace_print_array_seq);
++
+ int ftrace_raw_output_prep(struct trace_iterator *iter,
+ 			   struct trace_event *trace_event)
+ {
+@@ -521,11 +565,25 @@ int trace_print_context(struct trace_iterator *iter)
+ 	unsigned long secs, usec_rem;
+ 	char comm[TASK_COMM_LEN];
+ 	int ret;
++	int tgid;
+ 
+ 	trace_find_cmdline(entry->pid, comm);
+ 
+-	ret = trace_seq_printf(s, "%16s-%-5d [%03d] ",
+-			       comm, entry->pid, iter->cpu);
++	ret = trace_seq_printf(s, "%16s-%-5d ", comm, entry->pid);
++	if (!ret)
++		return 0;
++
++	if (trace_flags & TRACE_ITER_TGID) {
++		tgid = trace_find_tgid(entry->pid);
++		if (tgid < 0)
++			ret = trace_seq_puts(s, "(-----) ");
++		else
++			ret = trace_seq_printf(s, "(%5d) ", tgid);
++		if (!ret)
++			return 0;
++	}
++
++	ret = trace_seq_printf(s, "[%03d] ", iter->cpu);
+ 	if (!ret)
+ 		return 0;
+ 
+@@ -854,6 +912,168 @@ static struct trace_event trace_fn_event = {
+ 	.funcs		= &trace_fn_funcs,
+ };
+ 
++/* TRACE_GRAPH_ENT */
++static enum print_line_t trace_graph_ent_trace(struct trace_iterator *iter, int flags,
++					struct trace_event *event)
++{
++	struct trace_seq *s = &iter->seq;
++	struct ftrace_graph_ent_entry *field;
++
++	trace_assign_type(field, iter->ent);
++
++	if (!trace_seq_puts(s, "graph_ent: func="))
++		return TRACE_TYPE_PARTIAL_LINE;
++
++	if (!seq_print_ip_sym(s, field->graph_ent.func, flags))
++		return TRACE_TYPE_PARTIAL_LINE;
++
++	if (!trace_seq_puts(s, "\n"))
++		return TRACE_TYPE_PARTIAL_LINE;
++
++	return TRACE_TYPE_HANDLED;
++}
++
++static enum print_line_t trace_graph_ent_raw(struct trace_iterator *iter, int flags,
++				      struct trace_event *event)
++{
++	struct ftrace_graph_ent_entry *field;
++
++	trace_assign_type(field, iter->ent);
++
++	if (!trace_seq_printf(&iter->seq, "%lx %d\n",
++			      field->graph_ent.func,
++			      field->graph_ent.depth))
++		return TRACE_TYPE_PARTIAL_LINE;
++
++	return TRACE_TYPE_HANDLED;
++}
++
++static enum print_line_t trace_graph_ent_hex(struct trace_iterator *iter, int flags,
++				      struct trace_event *event)
++{
++	struct ftrace_graph_ent_entry *field;
++	struct trace_seq *s = &iter->seq;
++
++	trace_assign_type(field, iter->ent);
++
++	SEQ_PUT_HEX_FIELD_RET(s, field->graph_ent.func);
++	SEQ_PUT_HEX_FIELD_RET(s, field->graph_ent.depth);
++
++	return TRACE_TYPE_HANDLED;
++}
++
++static enum print_line_t trace_graph_ent_bin(struct trace_iterator *iter, int flags,
++				      struct trace_event *event)
++{
++	struct ftrace_graph_ent_entry *field;
++	struct trace_seq *s = &iter->seq;
++
++	trace_assign_type(field, iter->ent);
++
++	SEQ_PUT_FIELD_RET(s, field->graph_ent.func);
++	SEQ_PUT_FIELD_RET(s, field->graph_ent.depth);
++
++	return TRACE_TYPE_HANDLED;
++}
++
++static struct trace_event_functions trace_graph_ent_funcs = {
++	.trace		= trace_graph_ent_trace,
++	.raw		= trace_graph_ent_raw,
++	.hex		= trace_graph_ent_hex,
++	.binary		= trace_graph_ent_bin,
++};
++
++static struct trace_event trace_graph_ent_event = {
++	.type		= TRACE_GRAPH_ENT,
++	.funcs		= &trace_graph_ent_funcs,
++};
++
++/* TRACE_GRAPH_RET */
++static enum print_line_t trace_graph_ret_trace(struct trace_iterator *iter, int flags,
++					struct trace_event *event)
++{
++	struct trace_seq *s = &iter->seq;
++	struct trace_entry *entry = iter->ent;
++	struct ftrace_graph_ret_entry *field;
++
++	trace_assign_type(field, entry);
++
++	if (!trace_seq_puts(s, "graph_ret: func="))
++		return TRACE_TYPE_PARTIAL_LINE;
++
++	if (!seq_print_ip_sym(s, field->ret.func, flags))
++		return TRACE_TYPE_PARTIAL_LINE;
++
++	if (!trace_seq_puts(s, "\n"))
++		return TRACE_TYPE_PARTIAL_LINE;
++
++	return TRACE_TYPE_HANDLED;
++}
++
++static enum print_line_t trace_graph_ret_raw(struct trace_iterator *iter, int flags,
++				      struct trace_event *event)
++{
++	struct ftrace_graph_ret_entry *field;
++
++	trace_assign_type(field, iter->ent);
++
++	if (!trace_seq_printf(&iter->seq, "%lx %lld %lld %ld %d\n",
++			      field->ret.func,
++			      field->ret.calltime,
++			      field->ret.rettime,
++			      field->ret.overrun,
++			      field->ret.depth));
++		return TRACE_TYPE_PARTIAL_LINE;
++
++	return TRACE_TYPE_HANDLED;
++}
++
++static enum print_line_t trace_graph_ret_hex(struct trace_iterator *iter, int flags,
++				      struct trace_event *event)
++{
++	struct ftrace_graph_ret_entry *field;
++	struct trace_seq *s = &iter->seq;
++
++	trace_assign_type(field, iter->ent);
++
++	SEQ_PUT_HEX_FIELD_RET(s, field->ret.func);
++	SEQ_PUT_HEX_FIELD_RET(s, field->ret.calltime);
++	SEQ_PUT_HEX_FIELD_RET(s, field->ret.rettime);
++	SEQ_PUT_HEX_FIELD_RET(s, field->ret.overrun);
++	SEQ_PUT_HEX_FIELD_RET(s, field->ret.depth);
++
++	return TRACE_TYPE_HANDLED;
++}
++
++static enum print_line_t trace_graph_ret_bin(struct trace_iterator *iter, int flags,
++				      struct trace_event *event)
++{
++	struct ftrace_graph_ret_entry *field;
++	struct trace_seq *s = &iter->seq;
++
++	trace_assign_type(field, iter->ent);
++
++	SEQ_PUT_FIELD_RET(s, field->ret.func);
++	SEQ_PUT_FIELD_RET(s, field->ret.calltime);
++	SEQ_PUT_FIELD_RET(s, field->ret.rettime);
++	SEQ_PUT_FIELD_RET(s, field->ret.overrun);
++	SEQ_PUT_FIELD_RET(s, field->ret.depth);
++
++	return TRACE_TYPE_HANDLED;
++}
++
++static struct trace_event_functions trace_graph_ret_funcs = {
++	.trace		= trace_graph_ret_trace,
++	.raw		= trace_graph_ret_raw,
++	.hex		= trace_graph_ret_hex,
++	.binary		= trace_graph_ret_bin,
++};
++
++static struct trace_event trace_graph_ret_event = {
++	.type		= TRACE_GRAPH_RET,
++	.funcs		= &trace_graph_ret_funcs,
++};
++
+ /* TRACE_CTX an TRACE_WAKE */
+ static enum print_line_t trace_ctxwake_print(struct trace_iterator *iter,
+ 					     char *delim)
+@@ -1244,6 +1464,8 @@ static struct trace_event trace_print_event = {
+ 
+ static struct trace_event *events[] __initdata = {
+ 	&trace_fn_event,
++	&trace_graph_ent_event,
++	&trace_graph_ret_event,
+ 	&trace_ctx_event,
+ 	&trace_wake_event,
+ 	&trace_stack_event,
+diff --git a/kernel/watchdog.c b/kernel/watchdog.c
+index 70bf118..7eccf9b 100644
+--- a/kernel/watchdog.c
++++ b/kernel/watchdog.c
+@@ -47,6 +47,11 @@ static DEFINE_PER_CPU(struct task_struct *, softlockup_task_ptr_saved);
+ static DEFINE_PER_CPU(bool, hard_watchdog_warn);
+ static DEFINE_PER_CPU(bool, watchdog_nmi_touch);
+ static DEFINE_PER_CPU(unsigned long, hrtimer_interrupts_saved);
++#endif
++#ifdef CONFIG_HARDLOCKUP_DETECTOR_OTHER_CPU
++static cpumask_t __read_mostly watchdog_cpus;
++#endif
++#ifdef CONFIG_HARDLOCKUP_DETECTOR_NMI
+ static DEFINE_PER_CPU(struct perf_event *, watchdog_ev);
+ #endif
+ static unsigned long soft_lockup_nmi_warn;
+@@ -221,7 +226,7 @@ void touch_softlockup_watchdog_sync(void)
+ 	__this_cpu_write(watchdog_touch_ts, 0);
+ }
+ 
+-#ifdef CONFIG_HARDLOCKUP_DETECTOR
++#ifdef CONFIG_HARDLOCKUP_DETECTOR_NMI
+ /* watchdog detector functions */
+ static int is_hardlockup(void)
+ {
+@@ -235,6 +240,76 @@ static int is_hardlockup(void)
+ }
+ #endif
+ 
++#ifdef CONFIG_HARDLOCKUP_DETECTOR_OTHER_CPU
++static unsigned int watchdog_next_cpu(unsigned int cpu)
++{
++	cpumask_t cpus = watchdog_cpus;
++	unsigned int next_cpu;
++
++	next_cpu = cpumask_next(cpu, &cpus);
++	if (next_cpu >= nr_cpu_ids)
++		next_cpu = cpumask_first(&cpus);
++
++	if (next_cpu == cpu)
++		return nr_cpu_ids;
++
++	return next_cpu;
++}
++
++static int is_hardlockup_other_cpu(unsigned int cpu)
++{
++	unsigned long hrint = per_cpu(hrtimer_interrupts, cpu);
++
++	if (per_cpu(hrtimer_interrupts_saved, cpu) == hrint)
++		return 1;
++
++	per_cpu(hrtimer_interrupts_saved, cpu) = hrint;
++	return 0;
++}
++
++static void watchdog_check_hardlockup_other_cpu(void)
++{
++	unsigned int next_cpu;
++
++	/*
++	 * Test for hardlockups every 3 samples.  The sample period is
++	 *  watchdog_thresh * 2 / 5, so 3 samples gets us back to slightly over
++	 *  watchdog_thresh (over by 20%).
++	 */
++	if (__this_cpu_read(hrtimer_interrupts) % 3 != 0)
++		return;
++
++	/* check for a hardlockup on the next cpu */
++	next_cpu = watchdog_next_cpu(smp_processor_id());
++	if (next_cpu >= nr_cpu_ids)
++		return;
++
++	smp_rmb();
++
++	if (per_cpu(watchdog_nmi_touch, next_cpu) == true) {
++		per_cpu(watchdog_nmi_touch, next_cpu) = false;
++		return;
++	}
++
++	if (is_hardlockup_other_cpu(next_cpu)) {
++		/* only warn once */
++		if (per_cpu(hard_watchdog_warn, next_cpu) == true)
++			return;
++
++		if (hardlockup_panic)
++			panic("Watchdog detected hard LOCKUP on cpu %u", next_cpu);
++		else
++			WARN(1, "Watchdog detected hard LOCKUP on cpu %u", next_cpu);
++
++		per_cpu(hard_watchdog_warn, next_cpu) = true;
++	} else {
++		per_cpu(hard_watchdog_warn, next_cpu) = false;
++	}
++}
++#else
++static inline void watchdog_check_hardlockup_other_cpu(void) { return; }
++#endif
++
+ static int is_softlockup(unsigned long touch_ts)
+ {
+ 	unsigned long now = get_timestamp();
+@@ -246,7 +321,7 @@ static int is_softlockup(unsigned long touch_ts)
+ 	return 0;
+ }
+ 
+-#ifdef CONFIG_HARDLOCKUP_DETECTOR
++#ifdef CONFIG_HARDLOCKUP_DETECTOR_NMI
+ 
+ static struct perf_event_attr wd_hw_attr = {
+ 	.type		= PERF_TYPE_HARDWARE,
+@@ -296,7 +371,7 @@ static void watchdog_overflow_callback(struct perf_event *event,
+ 	__this_cpu_write(hard_watchdog_warn, false);
+ 	return;
+ }
+-#endif /* CONFIG_HARDLOCKUP_DETECTOR */
++#endif /* CONFIG_HARDLOCKUP_DETECTOR_NMI */
+ 
+ static void watchdog_interrupt_count(void)
+ {
+@@ -317,6 +392,9 @@ static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer)
+ 	/* kick the hardlockup detector */
+ 	watchdog_interrupt_count();
+ 
++	/* test for hardlockups on the next cpu */
++	watchdog_check_hardlockup_other_cpu();
++
+ 	/* kick the softlockup detector */
+ 	wake_up_process(__this_cpu_read(softlockup_watchdog));
+ 
+@@ -479,7 +557,7 @@ static void watchdog(unsigned int cpu)
+ 	__touch_watchdog();
+ }
+ 
+-#ifdef CONFIG_HARDLOCKUP_DETECTOR
++#ifdef CONFIG_HARDLOCKUP_DETECTOR_NMI
+ /*
+  * People like the simple clean cpu node info on boot.
+  * Reduce the watchdog noise by only printing messages
+@@ -568,9 +646,44 @@ static void watchdog_nmi_disable(unsigned int cpu)
+ 	}
+ }
+ #else
++#ifdef CONFIG_HARDLOCKUP_DETECTOR_OTHER_CPU
++static int watchdog_nmi_enable(unsigned int cpu)
++{
++	/*
++	 * The new cpu will be marked online before the first hrtimer interrupt
++	 * runs on it.  If another cpu tests for a hardlockup on the new cpu
++	 * before it has run its first hrtimer, it will get a false positive.
++	 * Touch the watchdog on the new cpu to delay the first check for at
++	 * least 3 sampling periods to guarantee one hrtimer has run on the new
++	 * cpu.
++	 */
++	per_cpu(watchdog_nmi_touch, cpu) = true;
++	smp_wmb();
++	cpumask_set_cpu(cpu, &watchdog_cpus);
++	return 0;
++}
++
++static void watchdog_nmi_disable(unsigned int cpu)
++{
++	unsigned int next_cpu = watchdog_next_cpu(cpu);
++
++	/*
++	 * Offlining this cpu will cause the cpu before this one to start
++	 * checking the one after this one.  If this cpu just finished checking
++	 * the next cpu and updating hrtimer_interrupts_saved, and then the
++	 * previous cpu checks it within one sample period, it will trigger a
++	 * false positive.  Touch the watchdog on the next cpu to prevent it.
++	 */
++	if (next_cpu < nr_cpu_ids)
++		per_cpu(watchdog_nmi_touch, next_cpu) = true;
++	smp_wmb();
++	cpumask_clear_cpu(cpu, &watchdog_cpus);
++}
++#else
+ static int watchdog_nmi_enable(unsigned int cpu) { return 0; }
+ static void watchdog_nmi_disable(unsigned int cpu) { return; }
+-#endif /* CONFIG_HARDLOCKUP_DETECTOR */
++#endif /* CONFIG_HARDLOCKUP_DETECTOR_OTHER_CPU */
++#endif /* CONFIG_HARDLOCKUP_DETECTOR_NMI */
+ 
+ static struct smp_hotplug_thread watchdog_threads = {
+ 	.store			= &softlockup_watchdog,
+diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
+index 4e35a5d..95e5931 100644
+--- a/lib/Kconfig.debug
++++ b/lib/Kconfig.debug
+@@ -668,15 +668,27 @@ config LOCKUP_DETECTOR
+ 	  The overhead should be minimal.  A periodic hrtimer runs to
+ 	  generate interrupts and kick the watchdog task every 4 seconds.
+ 	  An NMI is generated every 10 seconds or so to check for hardlockups.
++	  If NMIs are not available on the platform, every 12 seconds the
++	  hrtimer interrupt on one cpu will be used to check for hardlockups
++	  on the next cpu.
+ 
+ 	  The frequency of hrtimer and NMI events and the soft and hard lockup
+ 	  thresholds can be controlled through the sysctl watchdog_thresh.
+ 
+-config HARDLOCKUP_DETECTOR
++config HARDLOCKUP_DETECTOR_NMI
+ 	def_bool y
+ 	depends on LOCKUP_DETECTOR && !HAVE_NMI_WATCHDOG
+ 	depends on PERF_EVENTS && HAVE_PERF_EVENTS_NMI
+ 
++config HARDLOCKUP_DETECTOR_OTHER_CPU
++	def_bool y
++	depends on LOCKUP_DETECTOR && SMP
++	depends on !HARDLOCKUP_DETECTOR_NMI && !HAVE_NMI_WATCHDOG
++
++config HARDLOCKUP_DETECTOR
++	def_bool y
++	depends on HARDLOCKUP_DETECTOR_NMI || HARDLOCKUP_DETECTOR_OTHER_CPU
++
+ config BOOTPARAM_HARDLOCKUP_PANIC
+ 	bool "Panic (Reboot) On Hard Lockups"
+ 	depends on HARDLOCKUP_DETECTOR
+diff --git a/lib/Makefile b/lib/Makefile
+index 0211d2b..3d49766 100644
+--- a/lib/Makefile
++++ b/lib/Makefile
+@@ -80,6 +80,7 @@ obj-$(CONFIG_REED_SOLOMON) += reed_solomon/
+ obj-$(CONFIG_BCH) += bch.o
+ obj-$(CONFIG_LZO_COMPRESS) += lzo/
+ obj-$(CONFIG_LZO_DECOMPRESS) += lzo/
++obj-$(CONFIG_GZIP_COMPRESS) += gzip/
+ obj-$(CONFIG_LZ4_COMPRESS) += lz4/
+ obj-$(CONFIG_LZ4HC_COMPRESS) += lz4/
+ obj-$(CONFIG_LZ4_DECOMPRESS) += lz4/
+diff --git a/lib/gzip/Makefile b/lib/gzip/Makefile
+new file mode 100644
+index 0000000..0d8bc8b
+--- /dev/null
++++ b/lib/gzip/Makefile
+@@ -0,0 +1,2 @@
++obj-$(CONFIG_GZIP_COMPRESS) += gzip_rm.o
++gzip_rm-y := util.o deflate.o zip.o bits.o trees.o gzip.o
+diff --git a/lib/gzip/bits.c b/lib/gzip/bits.c
+new file mode 100644
+index 0000000..e3a37d6
+--- /dev/null
++++ b/lib/gzip/bits.c
+@@ -0,0 +1,164 @@
++/* bits.c -- output variable-length bit strings
++* Copyright (C) 1992-1993 Jean-loup Gailly
++* This is free software; you can redistribute it and/or modify it under the
++* terms of the GNU General Public License, see the file COPYING.
++*/
++
++/*
++* PURPOSE
++*
++* Output variable-length bit strings. Compression can be done
++* to a file or to memory. (The latter is not supported in this version.)
++*
++* DISCUSSION
++*
++* The PKZIP "deflate" file format interprets compressed file data
++* as a sequence of bits. Multi-bit strings in the file may cross
++* byte boundaries without restriction.
++*
++* The first bit of each byte is the low-order bit.
++*
++* The routines in this file allow a variable-length bit value to
++* be output right-to-left (useful for literal values). For
++* left-to-right output (useful for code strings from the tree routines),
++* the bits must have been reversed first with bi_reverse().
++*
++* For in-memory compression, the compressed bit stream goes directly
++* into the requested output buffer. The input data is read in blocks
++* by the mem_read() function. The buffer is limited to 64K on 16 bit
++* machines.
++*
++* INTERFACE
++*
++* void bi_init (FILE *zipfile)
++* Initialize the bit string routines.
++*
++* void send_bits (int value, int length)
++* Write out a bit string, taking the source bits right to
++* left.
++*
++* int bi_reverse (int value, int length)
++* Reverse the bits of a bit string, taking the source bits left to
++* right and emitting them right to left.
++*
++* void bi_windup (void)
++* Write out any remaining bits in an incomplete byte.
++*
++* void copy_block(char *buf, unsigned len, int header)
++* Copy a stored block to the zip file, storing first the length and
++* its one's complement if requested.
++*
++*/
++
++#include "gzip.h"
++
++/* ===========================================================================
++* Local data used by the "bit string" routines.
++*/
++
++local unsigned short bi_buf = 0;
++/* Output buffer. bits are inserted starting at the bottom (least significant
++* bits).
++*/
++
++#define Buf_size (8 * 2*sizeof(char))
++/* Number of bits used within bi_buf. (bi_buf might be implemented on
++* more than 16 bits on some systems.)
++*/
++
++local int bi_valid = 0;
++/* Number of valid bits in bi_buf. All bits above the last valid bit
++* are always zero.
++*/
++
++int (* read_buf )( char * buf, unsigned size );
++/* Current input function. Set to mem_read for in-memory compression */
++
++/* ===========================================================================
++* Initialize the bit string routines.
++*/
++void bi_init ( void )
++{
++	bi_buf = 0;
++	bi_valid = 0;
++
++	/* Set the defaults for file compression. They are set by memcompress
++	* for in-memory compression.
++	*/
++	read_buf = mem_read;
++}
++
++/* ===========================================================================
++* Send a value on a given number of bits.
++* IN assertion: length <= 16 and value fits in length bits.
++*/
++void send_bits( value, length )
++int value; /* value to send */
++int length; /* number of bits */
++{
++	/* If not enough room in bi_buf, use (valid) bits from bi_buf and
++	* (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
++	* unused bits in value.
++	*/
++	if ( bi_valid > ( int )Buf_size - length ) {
++		bi_buf |= ( value << bi_valid );
++		put_short( bi_buf );
++		bi_buf = ( ush )value >> ( Buf_size - bi_valid );
++		bi_valid += length - Buf_size;
++	} else {
++		bi_buf |= value << bi_valid;
++		bi_valid += length;
++	}
++}
++
++/* ===========================================================================
++* Reverse the first len bits of a code, using straightforward code (a faster
++* method would use a table)
++* IN assertion: 1 <= len <= 15
++*/
++unsigned bi_reverse( unsigned code, int len )
++{
++	register unsigned res = 0;
++	do
++	{
++		res |= code & 1;
++		code >>= 1, res <<= 1;
++	} while (-- len > 0 );
++	return res >> 1;
++}
++
++/* ===========================================================================
++* Write out any remaining bits in an incomplete byte.
++*/
++void bi_windup()
++{
++	if ( bi_valid > 8 )/* �Ƿ����short���� */
++	{
++		put_short( bi_buf );
++	}
++	else if ( bi_valid > 0 )
++	{
++		put_byte( bi_buf );
++	}
++	bi_buf = 0;
++	bi_valid = 0;
++}
++
++/* ===========================================================================
++* Copy a stored block to the zip file, storing first the length and its
++* one's complement if requested.
++*/
++void copy_block( char * buf, unsigned len, int header )
++{
++	bi_windup(); /* align on byte boundary */
++
++	if ( header )
++	{
++		put_short(( ush )len );
++		put_short(( ush )~ len );
++	}
++	while ( len --)
++	{
++		put_byte(* buf ++);
++	}
++}
+diff --git a/lib/gzip/deflate.c b/lib/gzip/deflate.c
+new file mode 100644
+index 0000000..a074cd7
+--- /dev/null
++++ b/lib/gzip/deflate.c
+@@ -0,0 +1,553 @@
++/* deflate.c -- compress data using the deflation algorithm
++* Copyright (C) 1992-1993 Jean-loup Gailly
++* This is free software; you can redistribute it and/or modify it under the
++* terms of the GNU General Public License, see the file COPYING.
++*/
++
++/*
++* PURPOSE
++*
++* Identify new text as repetitions of old text within a fixed-
++* length sliding window trailing behind the new text.
++*
++* DISCUSSION
++*
++* The "deflation" process depends on being able to identify portions
++* of the input text which are identical to earlier input (within a
++* sliding window trailing behind the input currently being processed).
++*
++* The most straightforward technique turns out to be the fastest for
++* most input files: try all possible matches and select the longest.
++* The key feature of this algorithm is that insertions into the string
++* dictionary are very simple and thus fast, and deletions are avoided
++* completely. Insertions are performed at each input character, whereas
++* string matches are performed only when the previous match ends. So it
++* is preferable to spend more time in matches to allow very fast string
++* insertions and avoid deletions. The matching algorithm for small
++* strings is inspired from that of Rabin & Karp. A brute force approach
++* is used to find longer strings when a small match has been found.
++* A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
++* (by Leonid Broukhis).
++* A previous version of this file used a more sophisticated algorithm
++* (by Fiala and Greene) which is guaranteed to run in linear amortized
++* time, but has a larger average cost, uses more memory and is patented.
++* However the F&G algorithm may be faster for some highly redundant
++* files if the parameter max_chain_length (described below) is too large.
++*
++* ACKNOWLEDGEMENTS
++*
++* The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
++* I found it in 'freeze' written by Leonid Broukhis.
++* Thanks to many info-zippers for bug reports and testing.
++*
++* REFERENCES
++*
++* APPNOTE.TXT documentation file in PKZIP 1.93a distribution.
++*
++* A description of the Rabin and Karp algorithm is given in the book
++* "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
++*
++* Fiala,E.R., and Greene,D.H.
++* Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
++*
++* INTERFACE
++*
++* void lm_init (int pack_level, ush *flags)
++* Initialize the "longest match" routines for a new file
++*
++* ulg deflate (void)
++* Processes a new input file and return its compressed length. Sets
++* the compressed length, crc, deflate flags and internal file
++* attributes.
++*/
++
++#include <linux/unistd.h>
++#include "gzip.h"
++#include "lzw.h" /* just for consistency checking */
++
++/* ===========================================================================
++* Configuration parameters
++*/
++
++/* Compile with MEDIUM_MEM to reduce the memory requirements or
++* with SMALL_MEM to use as little memory as possible. Use BIG_MEM if the
++* entire input file can be held in memory (not possible on 16 bit systems).
++* Warning: defining these symbols affects HASH_BITS (see below) and thus
++* affects the compression ratio. The compressed output
++* is still correct, and might even be smaller in some cases.
++*/
++
++#ifndef HASH_BITS
++#define HASH_BITS 15 /* hash */
++/* For portability to 16 bit machines, do not use values above 15. */
++#endif
++
++/* To save space (see unlzw.c), we overlay prev+head with tab_prefix and
++* window with tab_suffix. Check that we can do this:
++*/
++#if (WSIZE<<1) > (1<<BITS) /* �����ж� */
++//error: cannot overlay window with tab_suffix and prev with tab_prefix0
++#endif
++#if HASH_BITS > BITS-1
++//error: cannot overlay head with tab_prefix1
++#endif
++
++#define HASH_SIZE (unsigned)(1<<HASH_BITS)
++#define HASH_MASK (HASH_SIZE-1)
++#define WMASK (WSIZE-1)
++	   /* HASH_SIZE and WSIZE must be powers of two */
++	   /* Tail of hash chains */
++#define NIL 0
++
++	   /* speed options for the general purpose bit flag */
++#define FAST 4
++	   /* speed options for the general purpose bit flag */
++#define SLOW 2
++
++#ifndef TOO_FAR
++#define TOO_FAR 4096 /* TOO FAR */
++#endif
++	   /* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
++
++	   /* ===========================================================================
++	   * Local data used by the "longest match" routines.
++	   */
++
++	   typedef ush Pos;
++	   typedef unsigned IPos;
++	   /* A Pos is an index in the character window. We use short instead of int to
++	   * save space in the various tables. IPos is used only for parameter passing.
++	   */
++
++	   /* DECLARE(uch, window, 2L*WSIZE); */
++	   /* Sliding window. Input bytes are read into the second half of the window,
++	   * and move to the first half later to keep a dictionary of at least WSIZE
++	   * bytes. With this organization, matches are limited to a distance of
++	   * WSIZE-MAX_MATCH bytes, but this ensures that IO is always
++	   * performed with a length multiple of the block size. Also, it limits
++	   * the window size to 64K, which is quite useful on MSDOS.
++	   * To do: limit the window size to WSIZE+BSZ if SMALL_MEM (the code would
++	   * be less efficient).
++	   */
++
++	   /* DECLARE(Pos, prev, WSIZE); */
++	   /* Link to older string with same hash index. To limit the size of this
++	   * array to 64K, this link is maintained only for the last 32K strings.
++	   * An index in this array is thus a window index modulo 32K.
++	   */
++
++	   /* DECLARE(Pos, head, 1<<HASH_BITS); */
++	   /* Heads of the hash chains or NIL. */
++
++	   ulg window_size = ( ulg )2 * WSIZE;
++	   /* window size, 2*WSIZE except for MMAP or BIG_MEM, where it is the
++	   * input file length plus MIN_LOOKAHEAD.
++	   */
++
++	   int block_start = 0;
++	   /* window position at the beginning of the current output block. Gets
++	   * negative when the window is moved backwards.
++	   */
++
++	   local unsigned ins_h = 0; /* hash index of string to be inserted */
++
++#define H_SHIFT ((HASH_BITS+MIN_MATCH-1)/MIN_MATCH)
++	   /* Number of bits by which ins_h and del_h must be shifted at each
++	   * input step. It must be such that after MIN_MATCH steps, the oldest
++	   * byte no longer takes part in the hash key, that is:
++	   * H_SHIFT * MIN_MATCH >= HASH_BITS
++	   */
++
++	   unsigned int near prev_length = 0;
++	   /* Length of the best match at previous step. Matches not greater than this
++	   * are discarded. This is used in the lazy match evaluation.
++	   */
++
++	   unsigned near strstart = 0; /* start of string to insert */
++	   unsigned near match_start = 0; /* start of matching string */
++	   local int eofile = 0; /* flag set at end of input file */
++	   local unsigned lookahead = 0; /* number of valid bytes ahead in window */
++
++	   unsigned near max_chain_length = 0;
++	   /* To speed up deflation, hash chains are never searched beyond this length.
++	   * A higher limit improves compression ratio but degrades the speed.
++	   */
++
++	   local unsigned int max_lazy_match = 0;
++	   /* Attempt to find a better match only when the current match is strictly
++	   * smaller than this value. This mechanism is used only for compression
++	   * levels >= 4.
++	   */
++#define max_insert_length max_lazy_match
++	   /* Insert new strings in the hash table only if the match length
++	   * is not greater than this length. This saves time but degrades compression.
++	   * max_insert_length is used only for compression levels <= 3.
++	   */
++	   /* compression level (1..9) */
++
++	   unsigned near good_match = 0;
++	   /* Use a faster search when the previous match is longer than this */
++
++	   /* Values for max_lazy_match, good_match and max_chain_length, depending on
++	   * the desired pack level (0..9). The values given below have been tuned to
++	   * exclude worst case performance for pathological files. Better values may be
++	   * found for specific files.
++	   */
++
++	   typedef struct config {
++		   ush good_length; /* reduce lazy search above this match length */
++		   ush max_lazy; /* do not perform lazy search above this match length */
++		   ush nice_length; /* quit search above this match length */
++		   ush max_chain;
++	   } config;
++
++	   int near nice_match = 0; /* Stop searching when current match exceeds this */
++
++	   /* good lazy nice chain */
++	   local config configuration_table[10] = {
++		   { 0, 0, 0, 0}, /* store only *//* 0 */
++		   { 4, 4, 8, 4}, /* maximum speed, no lazy matches */ /* 1 */
++		   { 4, 5, 16, 8}, /* 2 */
++		   { 4, 6, 32, 32}, /* 3 */
++
++		   { 4, 4, 16, 16}, /* lazy matches *//* 4 */
++		   { 8, 16, 32, 32},/* 5 */
++		   { 8, 16, 128, 128},/* 6 */
++		   { 8, 32, 128, 256},/* 7 */
++		   { 32, 128, 258, 1024},/* 8 */
++		   { 32, 258, 258, 4096}}; /* maximum compression *//* 9 */
++
++		   /* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
++		   * For deflate_fast() (levels <= 3) good is ignored and lazy has a different
++		   * meaning.
++		   */
++
++#define EQUAL 0
++		   /* result of memcmp for equal strings */
++
++		   /* ===========================================================================
++		   * Prototypes for local functions.
++		   */
++		   local void fill_window( void );
++
++		   int longest_match( IPos cur_match );
++
++		   /* ===========================================================================
++		   * Update a hash value with the given input byte
++		   * IN assertion: all calls to to UPDATE_HASH are made with consecutive
++		   * input characters, so that a running hash key can be computed from the
++		   * previous key instead of complete recalculation each time.
++		   */
++#define UPDATE_HASH(h,c) (h = (((h)<<H_SHIFT) ^ (c)) & HASH_MASK)
++
++		   /* ===========================================================================
++		   * Insert string s in the dictionary and set match_head to the previous head
++		   * of the hash chain (the most recent string with same hash key). Return
++		   * the previous length of the hash chain.
++		   * IN assertion: all calls to to INSERT_STRING are made with consecutive
++		   * input characters and the first MIN_MATCH bytes of s are valid
++		   * (except for the last MIN_MATCH-1 bytes of the input file).
++		   */
++#define INSERT_STRING(s, match_head) \
++	(UPDATE_HASH(ins_h, window[(s) + MIN_MATCH-1]), \
++	prev[(s) & WMASK] = match_head = head[ins_h], \
++	head[ins_h] = (s))
++
++		   /* ===========================================================================
++		   * Initialize the "longest match" routines for a new file
++		   */
++		   void lm_init ( int pack_level, ush * flags )
++		   {
++			   register unsigned j;
++
++			   /* Initialize the hash table. */
++			   memzero(( char *)head, HASH_SIZE * sizeof(* head ));
++			   /* prev will be initialized on the fly */
++
++			   /* Set the default configuration parameters:
++			   */
++			   max_lazy_match = configuration_table[pack_level].max_lazy;
++			   good_match = configuration_table[pack_level].good_length;
++
++			   nice_match = configuration_table[pack_level].nice_length;
++
++			   max_chain_length = configuration_table[pack_level].max_chain;
++			   /* ??? reduce max_chain_length for binary files */
++
++			   strstart = 0;
++			   block_start = 0L;
++
++			   lookahead = read_buf(( char *)window,
++				   sizeof( int ) <= 2 ? ( unsigned )WSIZE : 2 * WSIZE ); /* �������� */
++
++			   if ( lookahead == 0 || lookahead == ( unsigned )- 1 ) {
++				   eofile = 1, lookahead = 0;
++				   return;
++			   }
++			   eofile = 0;
++			   /* Make sure that we always have enough lookahead. This is important
++			   * if input comes from a device such as a tty.
++			   */
++			   while ( lookahead < MIN_LOOKAHEAD && ! eofile ) fill_window();
++
++			   ins_h = 0;
++			   for ( j = 0; j < MIN_MATCH - 1; j ++) UPDATE_HASH( ins_h, window[j] );
++			   /* If lookahead < MIN_MATCH, ins_h is garbage, but this is
++			   * not important since only literal bytes will be emitted.
++			   */
++		   }
++
++		   /* ===========================================================================
++		   * Set match_start to the longest match starting at the given string and
++		   * return its length. Matches shorter or equal to prev_length are discarded,
++		   * in which case the result is equal to prev_length and match_start is
++		   * garbage.
++		   * IN assertions: cur_match is the head of the hash chain for the current
++		   * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
++		   */
++		   /* For MSDOS, OS/2 and 386 Unix, an optimized version is in match.asm or
++		   * match.s. The code is functionally equivalent, so you can use the C version
++		   * if desired.
++		   */
++		   int longest_match( IPos cur_match )
++		   {
++			   unsigned chain_length = max_chain_length; /* max hash chain length */
++			   register uch * scan = window + strstart; /* current string */
++			   register uch * match; /* matched string */
++			   register int len; /* length of current match */
++			   int best_len = prev_length; /* best match length so far */
++			   IPos limit = strstart > ( IPos )MAX_DIST ? strstart - ( IPos )MAX_DIST : NIL;
++			   /* Stop when cur_match becomes <= limit. To simplify the code,
++			   * we prevent matches with the string of window index 0.
++			   */
++
++			   /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
++			   * It is easy to get rid of this optimization if necessary.
++			   */
++			   register uch * strend = window + strstart + MAX_MATCH;
++			   register uch scan_end1 = scan[best_len - 1];
++			   register uch scan_end = scan[best_len];
++
++			   if ( prev_length >= good_match ) {
++				   /* Do not waste too much time if we already have a good match: */
++				   chain_length >>= 2;
++			   }
++
++			   do
++			   {
++				   Assert( cur_match < strstart, "no future" );
++				   match = window + cur_match;
++
++				   /* Skip to next match if the match length cannot increase
++				   * or if the match length is less than 2:
++				   */
++
++				   if ( match[best_len] != scan_end ||
++					   match[best_len - 1] != scan_end1 ||
++					   * match != * scan ||
++					   *++ match != scan[1] ) continue;
++
++				   /* The check at best_len-1 can be removed because it will be made
++				   * again later. (This heuristic is not always a win.)
++				   * It is not necessary to compare scan[2] and match[2] since they
++				   * are always equal when the other bytes match, given that
++				   * the hash keys are equal and that HASH_BITS >= 8.
++				   */
++				   scan += 2, match ++;
++
++				   /* We check for insufficient lookahead only every 8th comparison;
++				   * the 256th check will be made at strstart+258.
++				   */
++				   do {
++				   } while (*++ scan == *++ match && *++ scan == *++ match &&
++					   *++ scan == *++ match && *++ scan == *++ match &&
++					   *++ scan == *++ match && *++ scan == *++ match &&
++					   *++ scan == *++ match && *++ scan == *++ match &&
++					   scan < strend );
++
++				   len = MAX_MATCH - ( int )( strend - scan );
++				   scan = strend - MAX_MATCH;
++
++				   if ( len > best_len ) {
++					   match_start = cur_match;
++					   best_len = len;
++					   if ( len >= nice_match ) break;
++					   scan_end1 = scan[best_len - 1];
++					   scan_end = scan[best_len];
++				   }
++			   } while (( cur_match = prev[cur_match & WMASK] ) > limit
++				   && -- chain_length != 0 );
++
++			   return best_len;
++		   }
++
++#define check_match(start, match, length)
++
++		   /* ===========================================================================
++		   * Fill the window when the lookahead becomes insufficient.
++		   * Updates strstart and lookahead, and sets eofile if end of input file.
++		   * IN assertion: lookahead < MIN_LOOKAHEAD && strstart + lookahead > 0
++		   * OUT assertions: at least one byte has been read, or eofile is set;
++		   * file reads are performed for at least two bytes (required for the
++		   * translate_eol option).
++		   */
++		   local void fill_window()
++		   {
++			   register unsigned n, m;
++			   unsigned more = ( unsigned )( window_size - ( ulg )lookahead - ( ulg )strstart );
++			   /* Amount of free space at the end of the window. */
++
++			   /* If the window is almost full and there is insufficient lookahead,
++			   * move the upper half to the lower one to make room in the upper half.
++			   */
++			   if ( more == ( unsigned )- 1 ) {
++				   /* Very unlikely, but possible on 16 bit machine if strstart == 0
++				   * and lookahead == 1 (input done one byte at time)
++				   */
++				   more --;
++			   } else if ( strstart >= WSIZE + MAX_DIST ) {
++				   /* By the IN assertion, the window is not empty so we can't confuse
++				   * more == 0 with more == 64K on a 16 bit machine.
++				   */
++				   Assert( window_size == ( ulg )2 * WSIZE, "no sliding with BIG_MEM" );
++
++				   memcpy(( char *)window, ( char *)window + WSIZE, ( unsigned )WSIZE );
++				   match_start -= WSIZE;
++				   strstart -= WSIZE; /* we now have strstart >= MAX_DIST: */
++
++				   block_start -= ( int ) WSIZE;
++
++				   for ( n = 0; n < HASH_SIZE; n ++) {
++					   m = head[n];
++					   head[n] = ( Pos )( m >= WSIZE ? m - WSIZE : NIL );
++				   }
++				   for ( n = 0; n < WSIZE; n ++) {
++					   m = prev[n];
++					   prev[n] = ( Pos )( m >= WSIZE ? m - WSIZE : NIL );
++					   /* If n is not on any hash chain, prev[n] is garbage but
++					   * its value will never be used.
++					   */
++				   }
++				   more += WSIZE;
++			   }
++			   /* At this point, more >= 2 */
++			   if (! eofile ) {
++				   n = read_buf(( char *)window + strstart + lookahead, more );
++				   if ( n == 0 || n == ( unsigned )- 1 ) {
++					   eofile = 1;
++				   } else {
++					   lookahead += n;
++				   }
++			   }
++		   }
++
++		   /* ===========================================================================
++		   * Flush the current block, with given end-of-file flag.
++		   * IN assertion: strstart is set to the end of the current match.
++		   */
++#define FLUSH_BLOCK(eof) \
++	flush_block(block_start >= 0L ? (char*)&window[(unsigned)block_start] : \
++	(char*)NULL, (long)strstart - block_start, (eof))
++
++		   /* ===========================================================================
++		   * Same as above, but achieves better compression. We use a lazy
++		   * evaluation for matches: a match is finally adopted only if there is
++		   * no better match at the next window position.
++		   */
++		   ulg deflate()
++		   {
++			   IPos hash_head; /* head of hash chain */
++			   IPos prev_match; /* previous match */
++			   int flush; /* set if current block must be flushed */
++			   int match_available = 0; /* set if previous match exists */
++			   register unsigned match_length = MIN_MATCH - 1; /* length of best match */
++
++			   /* Process the input block. */
++			   while ( lookahead != 0 ) {
++				   /* Insert the string window[strstart .. strstart+2] in the
++				   * dictionary, and set hash_head to the head of the hash chain:
++				   */
++				   INSERT_STRING( strstart, hash_head );
++
++				   /* Find the longest match, discarding those <= prev_length.
++				   */
++				   prev_length = match_length, prev_match = match_start;
++				   match_length = MIN_MATCH - 1;
++
++				   if ( hash_head != NIL && prev_length < max_lazy_match &&
++					   strstart - hash_head <= MAX_DIST ) {
++						   /* To simplify the code, we prevent matches with the string
++						   * of window index 0 (in particular we have to avoid a match
++						   * of the string with itself at the start of the input file).
++						   */
++						   match_length = longest_match ( hash_head );
++						   /* longest_match() sets match_start */
++						   if ( match_length > lookahead ) match_length = lookahead;
++
++						   /* Ignore a length 3 match if it is too distant: */
++						   if ( match_length == MIN_MATCH && strstart - match_start > TOO_FAR ){
++							   /* If prev_match is also MIN_MATCH, match_start is garbage
++							   * but we will ignore the current match anyway.
++							   */
++							   match_length --;
++						   }
++					   }
++					   /* If there was a match at the previous step and the current
++					   * match is not better, output the previous match:
++					   */
++					   if ( prev_length >= MIN_MATCH && match_length <= prev_length ) {
++
++						   check_match( strstart - 1, prev_match, prev_length );
++
++						   flush = ct_tally( strstart - 1 - prev_match, prev_length - MIN_MATCH );
++
++						   /* Insert in hash table all strings up to the end of the match.
++						   * strstart-1 and strstart are already inserted.
++						   */
++						   lookahead -= prev_length - 1;
++						   prev_length -= 2; /* -2 */
++						   do {
++							   strstart ++;
++							   INSERT_STRING( strstart, hash_head );
++							   /* strstart never exceeds WSIZE-MAX_MATCH, so there are
++							   * always MIN_MATCH bytes ahead. If lookahead < MIN_MATCH
++							   * these bytes are garbage, but it does not matter since the
++							   * next lookahead bytes will always be emitted as literals.
++							   */
++						   } while (-- prev_length != 0 );
++						   match_available = 0;
++						   match_length = MIN_MATCH - 1;
++						   strstart ++;
++						   if ( flush ) FLUSH_BLOCK( 0 ), block_start = strstart;
++					   } else if ( match_available ) {
++						   /* If there was no match at the previous position, output a
++						   * single literal. If there was a match but the current match
++						   * is longer, truncate the previous match to a single literal.
++						   */
++						   Tracevv(( stderr, "%c", window[strstart - 1] ));
++						   if ( ct_tally ( 0, window[strstart - 1] )) {
++							   FLUSH_BLOCK( 0 ), block_start = strstart;
++						   }
++						   strstart ++;
++						   lookahead --;
++					   } else {
++						   /* There is no previous match to compare with, wait for
++						   * the next step to decide.
++						   */
++						   match_available = 1;
++						   strstart ++;
++						   lookahead --;
++					   }
++					   Assert ( strstart <= isize && lookahead <= isize, "a bit too far" );
++
++					   /* Make sure that we always have enough lookahead, except
++					   * at the end of the input file. We need MAX_MATCH bytes
++					   * for the next match, plus MIN_MATCH bytes to insert the
++					   * string following the next match.
++					   */
++					   while ( lookahead < MIN_LOOKAHEAD && ! eofile ) fill_window();
++			   }
++			   if ( match_available ) ct_tally ( 0, window[strstart - 1] );
++
++			   return FLUSH_BLOCK( 1 ); /* eof */
++		   }
+diff --git a/lib/gzip/gzip.c b/lib/gzip/gzip.c
+new file mode 100644
+index 0000000..f229585
+--- /dev/null
++++ b/lib/gzip/gzip.c
+@@ -0,0 +1,156 @@
++/* gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
++* Copyright (C) 1992-1993 Jean-loup Gailly
++* The unzip code was written and put in the public domain by Mark Adler.
++* Portions of the lzw code are derived from the public domain 'compress'
++* written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies,
++* Ken Turkowski, Dave Mack and Peter Jannesen.
++*
++* See the license_msg below and the file COPYING for the software license.
++* See the file algorithm.doc for the compression algorithms and file formats.
++*/
++
++/* Compress files with zip algorithm and 'compress' interface.
++* See usage() and help() functions below for all options.
++* Outputs:
++* file.gz: compressed file with same mode, owner, and utimes
++* or stdout with -c option or if stdin used as input.
++* If the output file name had to be truncated, the original name is kept
++* in the compressed file.
++* On MSDOS, file.tmp -> file.tmz. On VMS, file.tmp -> file.tmp-gz.
++*
++* Using gz on MSDOS would create too many file name conflicts. For
++* example, foo.txt -> foo.tgz (.tgz must be reserved as shorthand for
++* tar.gz). Similarly, foo.dir and foo.doc would both be mapped to foo.dgz.
++* I also considered 12345678.txt -> 12345txt.gz but this truncates the name
++* too heavily. There is no ideal solution given the MSDOS 8+3 limitation.
++*
++* For the meaning of all compilation flags, see comments in Makefile.in.
++*/
++//#include <stdlib.h>
++#include "zipmem.h"
++#include "gzip.h"
++#include "lzw.h"
++
++/* global buffers */
++
++DECLARE( uch, inbuf, INBUFSIZ + INBUF_EXTRA );
++DECLARE( uch, outbuf, OUTBUFSIZ + OUTBUF_EXTRA );
++DECLARE( ush, d_buf, DIST_BUFSIZE );
++DECLARE( uch, window, 2L * WSIZE ); /* ���� */
++DECLARE( ush, tab_prefix, 1L << BITS );
++
++/* local variables */
++int quiet = 0; /* be very quiet (-q) */
++int maxbits = BITS; /* max bits per code for LZW */
++int method = DEFLATED;/* compression method */
++int level = 6; /* compression level */
++int exit_code = 0; /* program exit code */
++int time_stamp; /* original time stamp (modification time) */
++
++int bytes_in = 0; /* number of input bytes */
++int bytes_out = 0; /* number of output bytes */
++int total_in = 0; /* input bytes for all files */
++int total_out = 0; /* output bytes for all files */
++unsigned insize = 0; /* valid bytes in inbuf */
++unsigned inptr = 0; /* index of next byte to be processed in inbuf */
++unsigned outcnt = 0; /* bytes in output buffer */
++
++//local int get_method(void);
++
++int (* work )(void) = zip; /* function to call */
++
++/* ========================================================================
++* Compress
++*/
++int zipmem( char * mem_inptr, int mem_insize, char * mem_outptr )
++{
++	time_stamp = 0;
++	ALLOC( uch, inbuf, INBUFSIZ + INBUF_EXTRA );
++	ALLOC( uch, outbuf, OUTBUFSIZ + OUTBUF_EXTRA );
++	ALLOC( ush, d_buf, DIST_BUFSIZE );
++	ALLOC( uch, window, 2L * WSIZE ); /* ���� */
++	ALLOC( ush, tab_prefix, 1L << BITS );
++	clear_bufs(); /* clear input and output buffers */
++	zip_mem_outptr = mem_outptr; /* ������� */
++	zip_mem_outlen = 0; /* ��������С */
++	zip_mem_inptr = mem_inptr; /* ����ָ�� */
++	zip_mem_insize = mem_insize; /* ���뻺�泤�� */
++	zip_mem_inpos = 0; /* ���뻺�浱ǰλ�� */
++	zip();
++	FREE( inbuf );
++	FREE( outbuf );
++	FREE( d_buf );
++	FREE( window );
++	FREE( tab_prefix );
++	return zip_mem_outlen;
++}
++
++#if 0
++/* ========================================================================
++* deCompress
++*/
++int unzipmem( char * mem_inptr, int mem_insize, char * mem_outptr )
++{
++	time_stamp = 0;
++	ALLOC( uch, inbuf, INBUFSIZ + INBUF_EXTRA );
++	ALLOC( uch, outbuf, OUTBUFSIZ + OUTBUF_EXTRA );
++	ALLOC( ush, d_buf, DIST_BUFSIZE );
++	ALLOC( uch, window, 2L * WSIZE );/* ���� */
++	ALLOC( ush, tab_prefix, 1L << BITS );
++	clear_bufs(); /* clear input and output buffers */
++	zip_mem_outptr = mem_outptr; /* ������� */
++	zip_mem_outlen = 0; /* ��������С */
++	/* ��ѹ�� */
++	unzip_mem_inptr = mem_inptr; /* ����ָ�� */
++	unzip_mem_insize = mem_insize; /* ���뻺�泤�� */
++	unzip_mem_inpos = 0; /* ���뻺�浱ǰλ�� */
++	get_method();
++	unzip();
++	FREE( inbuf );
++	FREE( outbuf );
++	FREE( d_buf );
++	FREE( window );
++	FREE( tab_prefix );
++	return zip_mem_outlen;
++}
++
++/* ========================================================================
++* Check the magic number of the input file and update ofname if an
++* original name was given and to_stdout is not set.
++* Return the compression method, -1 for error, -2 for warning.
++* Set inptr to the offset of the next byte to be processed.
++* Updates time_stamp if there is one and --no-time is not used.
++* This function may be called repeatedly for an input file consisting
++* of several contiguous gzip'ed members.
++* IN assertions: there is at least one remaining compressed member.
++* If the member is a zip file, it must be the only one.
++*/
++local int get_method()
++{
++	/* If --force and --stdout, zcat == cat, so do not complain about
++	* premature end of file: use try_byte instead of get_byte.
++	*/
++	( char )get_byte();
++	( char )get_byte();
++	method = - 1; /* unknown yet */
++	/* assume multiple members in gzip file except for record oriented I/O */
++
++	method = ( int )get_byte();
++	work = unzip;
++	( uch )get_byte();
++	( ulg )get_byte();
++	(( ulg )get_byte());
++	(( ulg )get_byte());
++	(( ulg )get_byte());
++	( void )get_byte(); /* Ignore extra flags for the moment */
++	( void )get_byte(); /* Ignore OS type for the moment */
++
++	return method;
++}
++#endif
++
++int gzip_defalte(void *dst, unsigned int *dst_len, const void *src, unsigned int len)
++{
++	*dst_len = zipmem((char *)src, len, dst);
++	return 0;
++}
+diff --git a/lib/gzip/gzip.h b/lib/gzip/gzip.h
+new file mode 100644
+index 0000000..2e4a58e
+--- /dev/null
++++ b/lib/gzip/gzip.h
+@@ -0,0 +1,238 @@
++/* gzip.h -- common declarations for all gzip modules
++* Copyright (C) 1992-1993 Jean-loup Gailly.
++* This is free software; you can redistribute it and/or modify it under the
++* terms of the GNU General Public License, see the file COPYING.
++*/
++
++/* I don't like nested includes, but the string and io functions are used
++* too often
++*/
++#include <linux/unistd.h>
++#include <linux/string.h>
++#include <linux/vmalloc.h>
++
++//#define (args) args
++
++typedef char * voidp;
++
++#define memzero(s, n) memset ((voidp)(s), 0, (n))
++
++#ifndef RETSIGTYPE
++#define RETSIGTYPE void
++#endif
++
++#define local //static
++
++typedef unsigned char uch;
++typedef unsigned short ush;
++typedef unsigned int ulg;
++
++/* Return codes from gzip */
++
++/* Compression methods (see algorithm.doc) */
++#define STORED 0 /* stored */
++#define COMPRESSED 1 /* compressed */
++#define PACKED 2 /* packed */
++#define LZHED 3 /* lzwed */
++/* methods 4 to 7 reserved */
++#define DEFLATED 8 /* ȱʡ */
++#define MAX_METHODS 9 /* ���ѹ�� */
++extern int method; /* compression method */
++
++/* To save memory for 16 bit systems, some arrays are overlaid between
++* the various modules:
++* deflate: prev+head window d_buf l_buf outbuf
++* unlzw: tab_prefix tab_suffix stack inbuf outbuf
++* inflate: window inbuf
++* unpack: window inbuf prefix_len
++* unlzh: left+right window c_table inbuf c_len
++* For compression, input is done in window[]. For decompression, output
++* is done in window except for unlzw.
++*/
++#define INBUFSIZ 0x2000 /* input buffer size */
++#define INBUF_EXTRA 64 /* required by unlzw() */
++#define OUTBUFSIZ 8192 /* output buffer size */
++
++#define OUTBUF_EXTRA 2048 /* required by unlzw() */
++#define DIST_BUFSIZE 0x2000 /* buffer for distances, see trees.c */
++
++#define near
++
++#define EXTERN(type, array) extern type * near array
++#define DECLARE(type, array, size) type * near array
++
++#define fcalloc(items,size) vmalloc((size_t)(items)*(size_t)(size))
++#define fcfree(ptr) vfree(ptr)
++#define ALLOC(type, array, size) { \
++	array = (type*)fcalloc((size_t)(((size)+1L)/2), 2*sizeof(type));/* malloc */ \
++	if (array == NULL) error("insufficient memory"); \
++}
++#define FREE(array) {if (array != NULL) fcfree(array), array=NULL;}
++
++EXTERN( uch, inbuf ); /* input buffer */
++EXTERN( uch, outbuf ); /* output buffer */
++EXTERN( ush, d_buf ); /* buffer for distances, see trees.c */
++EXTERN( uch, window ); /* Sliding window and suffix table (unlzw) */
++#define tab_suffix window
++#define tab_prefix prev /* hash link (see deflate.c) */
++#define head (prev+WSIZE) /* hash head (see deflate.c) */
++EXTERN( ush, tab_prefix ); /* prefix code (see unlzw.c) */
++
++extern unsigned insize; /* valid bytes in inbuf */
++extern unsigned inptr; /* index of next byte to be processed in inbuf */
++extern unsigned outcnt; /* bytes in output buffer */
++
++extern int bytes_in; /* number of input bytes */
++extern int bytes_out; /* number of output bytes */
++extern int header_bytes;/* number of bytes in gzip header */
++
++#define isize bytes_in
++/* for compatibility with old zip sources (to be cleaned) */
++
++extern int time_stamp; /* original time stamp (modification time) */
++
++#define PACK_MAGIC "\037\036" /* Magic header for packed files */
++#define GZIP_MAGIC "\037\213" /* Magic header for gzip files, 1F 8B */
++#define OLD_GZIP_MAGIC "\037\236" /* Magic header for gzip 0.5 = freeze 1.x */
++#define LZH_MAGIC "\037\240" /* Magic header for SCO LZH Compress files*/
++#define PKZIP_MAGIC "\120\113\003\004" /* Magic header for pkzip files */
++
++/* gzip flag byte */
++#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
++#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
++#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
++#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
++#define COMMENT 0x10 /* bit 4 set: file comment present */
++#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */
++#define RESERVED 0xC0 /* bit 6,7: reserved */
++
++/* internal file attribute */
++#define UNKNOWN 0xffff /* δ֪ */
++#define BINARY 0 /* binary */
++#define ASCII 1 /* ascII */
++
++#ifndef WSIZE
++#ifdef CONFIG_ARCH_HI3516CV300
++#define WSIZE 0x2000	/* widow size for hi3516cv300 is 8k*/
++#else
++#define WSIZE 0x8000	/* window size--must be a power of two, and */
++			/* at least 32K for zip's deflate method */
++#endif
++#endif
++
++#define MIN_MATCH 3 /* min match */
++#define MAX_MATCH 258 /* max match*/
++/* The minimum and maximum match lengths */
++
++#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
++/* Minimum amount of lookahead, except at the end of the input file.
++* See deflate.c for comments about the MIN_MATCH+1.
++*/
++
++#define MAX_DIST (WSIZE-MIN_LOOKAHEAD)
++/* In order to simplify the code, particularly on 16 bit machines, match
++* distances are limited to MAX_DIST instead of WSIZE.
++*/
++
++extern int exit_code; /* program exit code */
++extern int quiet; /* be quiet (-q) */
++extern int level; /* compression level */
++
++#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf())
++#define try_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf())
++
++/* put_byte is used for the compressed output, put_ubyte for the
++* uncompressed output. However unlzw() uses window for its
++* suffix table instead of its output buffer, so it does not use put_ubyte
++* (to be cleaned up).
++*/
++#define put_byte(c) {outbuf[outcnt++]=(uch)(c); if (outcnt==OUTBUFSIZ)\
++	flush_outbuf();}
++#define put_ubyte(c) {window[outcnt++]=(uch)(c); if (outcnt==WSIZE)\
++	flush_window();}
++
++/* Output a 16 bit value, lsb first */
++#define put_short(w) \
++{ if (outcnt < OUTBUFSIZ-2) { /* compare */\
++	outbuf[outcnt++] = (uch) ((w) & 0xff);/* ��λ */ \
++	outbuf[outcnt++] = (uch) ((ush)(w) >> 8);/* ��λ */ \
++} else { \
++	put_byte((uch)((w) & 0xff)); /* ��λ */\
++	put_byte((uch)((ush)(w) >> 8));/* ��λ */ \
++} \
++}
++
++/* Output a 32 bit value to the bit stream, lsb first */
++#define put_long(n) { \
++	put_short((n) & 0xffff);/* ��λ */ \
++	put_short(((ulg)(n)) >> 16); /* ��λ */\
++}
++
++#define seekable() 0 /* force sequential output */
++#define translate_eol 0 /* no option -a yet */
++
++/* Macros for getting two-byte and four-byte header values */
++#define SH(p) ((ush)(uch)((p)[0]) | ((ush)(uch)((p)[1]) << 8))
++/* Macros for getting two-byte and four-byte header values */
++#define LG(p) ((ulg)(SH(p)) | ((ulg)(SH((p)+2)) << 16))
++
++/* Diagnostic functions */
++#define Assert(cond,msg)
++#define Trace(x)
++#define Tracev(x)
++#define Tracevv(x)
++#define Tracec(c,x)
++#define Tracecv(c,x)
++
++/*#define WARN(msg) {if (!quiet) fprintf msg ; \
++	if (exit_code == OK) exit_code = WARNING;}*/
++
++extern char * zip_mem_inptr;
++extern int zip_mem_insize;
++extern int zip_mem_inpos;
++
++extern char * unzip_mem_inptr ;
++extern int unzip_mem_insize ;
++extern int unzip_mem_inpos;
++
++extern char * zip_mem_outptr;
++extern int zip_mem_outlen ;
++
++/* in zip.c: */
++extern int zip ( void );
++extern int mem_read ( char * buf, unsigned size );
++/* in unzip.c */
++extern int unzip ( void );
++
++/* in deflate.c */
++void lm_init ( int pack_level, ush * flags );
++ulg deflate ( void );
++
++/* in trees.c */
++void ct_init ( ush * attr, int * method );
++int ct_tally ( int dist, int lc );
++ulg flush_block ( char * buf, ulg stored_len, int eof );
++
++/* in bits.c */
++void bi_init(void);
++void send_bits ( int value, int length );
++unsigned bi_reverse ( unsigned value, int length );
++void bi_windup ( void );
++void copy_block ( char * buf, unsigned len, int header );
++extern int (* read_buf ) ( char * buf, unsigned size );
++
++/* in util.c: */
++extern ulg updcrc ( uch * s, unsigned n );
++extern void clear_bufs ( void );
++extern int fill_inbuf ( void );
++extern void flush_outbuf ( void );
++extern void flush_window ( void );
++extern void write_buf ( voidp buf, unsigned cnt );
++extern void error ( char * m );
++extern void warn ( char * a, char * b );
++extern void read_error ( void );
++extern void write_error ( void );
++extern voidp xmalloc ( unsigned int size );
++
++/* in inflate.c */
++extern int inflate ( void );
+diff --git a/lib/gzip/inflate.c b/lib/gzip/inflate.c
+new file mode 100644
+index 0000000..228c2bb
+--- /dev/null
++++ b/lib/gzip/inflate.c
+@@ -0,0 +1,869 @@
++/* inflate.c -- Not copyrighted 1992 by Mark Adler
++version c10p1, 10 January 1993 */
++
++/* You can do whatever you like with this source file, though I would
++prefer that if you modify it and redistribute it that you include
++comments to that effect with your name and the date. Thank you.
++[The history has been moved to the file ChangeLog.]
++*/
++
++/*
++Inflate deflated (PKZIP's method 8 compressed) data. The compression
++method searches for as much of the current string of bytes (up to a
++length of 258) in the previous 32K bytes. If it doesn't find any
++matches (of at least length 3), it codes the next byte. Otherwise, it
++codes the length of the matched string and its distance backwards from
++the current position. There is a single Huffman code that codes both
++single bytes (called "literals") and match lengths. A second Huffman
++code codes the distance information, which follows a length code. Each
++length or distance code actually represents a base value and a number
++of "extra" (sometimes zero) bits to get to add to the base value. At
++the end of each deflated block is a special end-of-block (EOB) literal/
++length code. The decoding process is basically: get a literal/length
++code; if EOB then done; if a literal, emit the decoded byte; if a
++length then get the distance and emit the referred-to bytes from the
++sliding window of previously emitted data.
++
++There are (currently) three kinds of inflate blocks: stored, fixed, and
++dynamic. The compressor deals with some chunk of data at a time, and
++decides which method to use on a chunk-by-chunk basis. A chunk might
++typically be 32K or 64K. If the chunk is uncompressible, then the
++"stored" method is used. In this case, the bytes are simply stored as
++is, eight bits per byte, with none of the above coding. The bytes are
++preceded by a count, since there is no longer an EOB code.
++
++If the data is compressible, then either the fixed or dynamic methods
++are used. In the dynamic method, the compressed data is preceded by
++an encoding of the literal/length and distance Huffman codes that are
++to be used to decode this block. The representation is itself Huffman
++coded, and so is preceded by a description of that code. These code
++descriptions take up a little space, and so for small blocks, there is
++a predefined set of codes, called the fixed codes. The fixed method is
++used if the block codes up smaller that way (usually for quite small
++chunks), otherwise the dynamic method is used. In the latter case, the
++codes are customized to the probabilities in the current block, and so
++can code it much better than the pre-determined fixed codes.
++
++The Huffman codes themselves are decoded using a mutli-level table
++lookup, in order to maximize the speed of decoding plus the speed of
++building the decoding tables. See the comments below that precede the
++lbits and dbits tuning parameters.
++*/
++
++/*
++Notes beyond the 1.93a appnote.txt:
++
++1. Distance pointers never point before the beginning of the output
++stream.
++2. Distance pointers can point back across blocks, up to 32k away.
++3. There is an implied maximum of 7 bits for the bit length table and
++15 bits for the actual data.
++4. If only one code exists, then it is encoded using one bit. (Zero
++would be more efficient, but perhaps a little confusing.) If two
++codes exist, they are coded using one bit each (0 and 1).
++5. There is no way of sending zero distance codes--a dummy must be
++sent if there are none. (History: a pre 2.0 version of PKZIP would
++store blocks with no distance codes, but this was discovered to be
++too harsh a criterion.) Valid only for 1.93a. 2.04c does allow
++zero distance codes, which is sent as one code of zero bits in
++length.
++6. There are up to 286 literal/length codes. Code 256 represents the
++end-of-block. Note however that the static length tree defines
++288 codes just to fill out the Huffman codes. Codes 286 and 287
++cannot be used though, since there is no length base or extra bits
++defined for them. Similarly, there are up to 30 distance codes.
++However, static trees define 32 codes (all 5 bits) to fill out the
++Huffman codes, but the last two had better not show up in the data.
++7. Unzip can check dynamic Huffman blocks for complete code sets.
++The exception is that a single code would not be complete (see #4).
++8. The five bits following the block type is really the number of
++literal codes sent minus 257.
++9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits
++(1+6+6). Therefore, to output three times the length, you output
++three codes (1+1+1), whereas to output four times the same length,
++you only need two codes (1+3). Hmm.
++10. In the tree reconstruction algorithm, Code = Code + Increment
++only if BitLength(i) is not zero. (Pretty obvious.)
++11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19)
++12. Note: length code 284 can represent 227-258, but length code 285
++really is 258. The last length deserves its own, short code
++since it gets used a lot in very redundant files. The length
++258 is special since 258 - 3 (the min match length) is 255.
++13. The literal/length and distance code bit lengths are read as a
++single stream of lengths. It is possible (and advantageous) for
++a repeat code (16, 17, or 18) to go across the boundary between
++the two sets of lengths.
++*/
++//#include <stdlib.h>
++#include "gzip.h"
++#define slide window
++
++/* Huffman code lookup table entry--this entry is four bytes for machines
++that have 16-bit pointers (e.g. PC's in the small or medium model).
++Valid extra bits are 0..13. e == 15 is EOB (end of block), e == 16
++means that v is a literal, 16 < e < 32 means that v is a pointer to
++the next table, which codes e - 16 bits, and lastly e == 99 indicates
++an unused code. If a code with e == 99 is looked up, this implies an
++error in the data. */
++struct huft {
++	uch e; /* number of extra bits or operation */
++	uch b; /* number of bits in this code or subcode */
++	union {
++		ush n; /* literal, length base, or distance base */
++		struct huft * t; /* pointer to next level of table */
++	} v;
++};
++
++/* Function prototypes */
++int huft_build OF(( unsigned *, unsigned, unsigned, ush *, ush *,
++struct huft **, int *));
++int huft_free OF(( struct huft *));
++int inflate_codes OF(( struct huft *, struct huft *, int, int ));
++int inflate_stored OF(( void ));
++int inflate_fixed OF(( void ));
++int inflate_dynamic OF(( void ));
++int inflate_block OF(( int *));
++int inflate OF(( void ));
++
++/* The inflate algorithm uses a sliding 32K byte window on the uncompressed
++stream to find repeated byte strings. This is implemented here as a
++circular buffer. The index is updated simply by incrementing and then
++and'ing with 0x7fff (32K-1). */
++/* It is left to other modules to supply the 32K area. It is assumed
++to be usable as if it were declared "uch slide[32768];" or as just
++"uch *slide;" and then malloc'ed in the latter case. The definition
++must be in unzip.h, included above. */
++/* unsigned wp; current position in slide */
++#define wp outcnt
++#define flush_output(w) (wp=(w),flush_window())
++
++/* Tables for deflate from PKZIP's appnote.txt. */
++static unsigned border[] = {
++	/* Order of the bit length code lengths */
++	16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
++};
++static ush cplens[] = {
++	/* Copy lengths for literal codes 257..285 */
++	3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
++		/* Copy lengths for literal codes 257..285 */
++		35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0
++};
++/* note: see note #13 above about the 258 in this list. */
++static ush cplext[] = {
++	/* Extra bits for literal codes 257..285 */
++	0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
++		/* Extra bits for literal codes 257..285 */
++		3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99
++}; /* 99==invalid */
++static ush cpdist[] = {
++	/* Copy offsets for distance codes 0..29 */
++	1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
++		/* Copy offsets for distance codes 0..29 */
++		257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
++		/* Copy offsets for distance codes 0..29 */
++		8193, 12289, 16385, 24577
++};
++static ush cpdext[] = { /* Extra bits for distance codes */
++	0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,/* Extra bits for distance codes */
++		7, 7, 8, 8, 9, 9, 10, 10, 11, 11,/* Extra bits for distance codes */
++		12, 12, 13, 13 /* Extra bits for distance codes */
++};
++
++/* Macros for inflate() bit peeking and grabbing.
++The usage is:
++
++NEEDBITS(j)
++x = b & mask_bits[j];
++DUMPBITS(j)
++
++where NEEDBITS makes sure that b has at least j bits in it, and
++DUMPBITS removes the bits from b. The macros use the variable k
++for the number of bits in b. Normally, b and k are register
++variables for speed, and are initialized at the beginning of a
++routine that uses these macros from a global bit buffer and count.
++
++If we assume that EOB will be the longest code, then we will never
++ask for bits with NEEDBITS that are beyond the end of the stream.
++So, NEEDBITS should not read any more bytes than are needed to
++meet the request. Then no bytes need to be "returned" to the buffer
++at the end of the last block.
++
++However, this assumption is not true for fixed blocks--the EOB code
++is 7 bits, but the other literal/length codes can be 8 or 9 bits.
++(The EOB code is shorter than other codes because fixed blocks are
++generally short. So, while a block always has an EOB, many other
++literal/length codes have a significantly lower probability of
++showing up at all.) However, by making the first table have a
++lookup of seven bits, the EOB code will be found in that first
++lookup, and so will not require that too many bits be pulled from
++the stream.
++*/
++
++ulg bb = 0; /* bit buffer */
++unsigned bk = 0; /* bits in bit buffer */
++
++ush mask_bits[] = {
++	/* bits in mask bit buffer */
++	0x0000,
++		0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,/* bits in mask bit buffer */
++		0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff /* bits in mask bit buffer */
++};
++
++#define NEXTBYTE() (uch)get_byte()
++
++#define NEEDBITS(n) {while(k<(n)){b|=((ulg)NEXTBYTE())<<k;k+=8;}}
++#define DUMPBITS(n) {b>>=(n);k-=(n);}
++
++/*
++Huffman code decoding is performed using a multi-level table lookup.
++The fastest way to decode is to simply build a lookup table whose
++size is determined by the longest code. However, the time it takes
++to build this table can also be a factor if the data being decoded
++is not very long. The most common codes are necessarily the
++shortest codes, so those codes dominate the decoding time, and hence
++the speed. The idea is you can have a shorter table that decodes the
++shorter, more probable codes, and then point to subsidiary tables for
++the longer codes. The time it costs to decode the longer codes is
++then traded against the time it takes to make longer tables.
++
++This results of this trade are in the variables lbits and dbits
++below. lbits is the number of bits the first level table for literal/
++length codes can decode in one step, and dbits is the same thing for
++the distance codes. Subsequent tables are also less than or equal to
++those sizes. These values may be adjusted either when all of the
++codes are shorter than that, in which case the longest code length in
++bits is used, or when the shortest code is *longer* than the requested
++table size, in which case the length of the shortest code in bits is
++used.
++
++There are two different values for the two tables, since they code a
++different number of possibilities each. The literal/length table
++codes 286 possible values, or in a flat code, a little over eight
++bits. The distance table codes 30 possible values, or a little less
++than five bits, flat. The optimum values for speed end up being
++about one bit more than those, so lbits is 8+1 and dbits is 5+1.
++The optimum values may differ though from machine to machine, and
++possibly even between compilers. Your mileage may vary.
++*/
++
++int lbits = 9; /* bits in base literal/length lookup table */
++int dbits = 6; /* bits in base distance lookup table */
++
++/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */
++#define BMAX 16 /* maximum bit length of any code (16 for explode) */
++#define N_MAX 288 /* maximum number of codes in any set */
++
++unsigned hufts; /* track memory usage */
++
++int huft_build( unsigned * b, unsigned n, unsigned s, ush * d, ush * e, struct huft ** t, int * m )
++/* Given a list of code lengths and a maximum table size, make a set of
++tables to decode that set of codes. Return zero on success, one if
++the given code set is incomplete (the tables are still built in this
++case), two if the input is invalid (all zero length codes or an
++oversubscribed set of lengths), and three if not enough memory. */
++{
++	unsigned a; /* counter for codes of length k */
++	unsigned c[BMAX + 1]; /* bit length count table */
++	unsigned f; /* i repeats in table every f entries */
++	int g; /* maximum code length */
++	int h; /* table level */
++	register unsigned i; /* counter, current code */
++	register unsigned j; /* counter */
++	register int k; /* number of bits in current code */
++	int l; /* bits per table (returned in m) */
++	register unsigned * p; /* pointer into c[], b[], or v[] */
++	register struct huft * q; /* points to current table */
++	struct huft r; /* table entry for structure assignment */
++	struct huft * u[BMAX]; /* table stack */
++	unsigned v[N_MAX]; /* values in order of bit length */
++	register int w; /* bits before this table == (l * h) */
++	unsigned x[BMAX + 1]; /* bit offsets, then code stack */
++	unsigned * xp; /* pointer into x */
++	int y; /* number of dummy codes added */
++	unsigned z; /* number of entries in current table */
++
++	/* Generate counts for each bit length */
++	memzero( c, sizeof( c ));
++	p = b; i = n;
++	do {
++		Tracecv(* p, ( stderr, ( n - i >= ' ' && n - i <= '~' ? "%c %d\n" : "0x%x %d\n" ),
++			n - i, * p ));
++		c[ * p] ++; /* assume all entries <= BMAX */
++		p ++; /* Can't combine with above line (Solaris bug) */
++	} while (-- i );
++	if ( c[0] == n ) /* null input--all zero length codes */
++	{
++		* t = ( struct huft *)NULL;
++		* m = 0;
++		return 0;
++	}
++
++	/* Find minimum and maximum length, bound *m by those */
++	l = * m;
++	for ( j = 1; j <= BMAX; j ++)
++		if ( c[j] )
++			break;
++	k = j; /* minimum code length */
++	if (( unsigned )l < j )
++		l = j;
++	for ( i = BMAX; i; i --)
++		if ( c[i] )
++			break;
++	g = i; /* maximum code length */
++	if (( unsigned )l > i )
++		l = i;
++	* m = l;
++
++	/* Adjust last length count to fill out codes, if needed */
++	for ( y = 1 << j; j < i; j ++, y <<= 1 )
++		if (( y -= c[j] ) < 0 )
++			return 2; /* bad input: more codes than bits */
++	if (( y -= c[i] ) < 0 )
++		return 2;/* comment */
++	c[i] += y;
++
++	/* Generate starting offsets into the value table for each length */
++	x[1] = j = 0;
++	p = c + 1; xp = x + 2; /* comment */
++	while (-- i ) { /* note that i == g from above */
++		* xp ++ = ( j += * p ++);
++	}
++
++	/* Make a table of values in order of bit lengths */
++	p = b; i = 0;
++	do {
++		if (( j = * p ++) != 0 )
++			v[x[j] ++ ] = i;
++	} while (++ i < n );
++
++	/* Generate the Huffman codes and for each, make the table entries */
++	x[0] = i = 0; /* first Huffman code is zero */
++	p = v; /* grab values in bit order */
++	h = - 1; /* no tables yet--level -1 */
++	w = - l; /* bits decoded == (l * h) */
++	u[0] = ( struct huft *)NULL; /* just to keep compilers happy */
++	q = ( struct huft *)NULL; /* ditto */
++	z = 0; /* ditto */
++
++	/* go through the bit lengths (k already is bits in shortest code) */
++	for (; k <= g; k ++)
++	{
++		a = c[k];
++		while ( a --)
++		{
++			/* here i is the Huffman code of length k bits for value *p */
++			/* make tables up to required level */
++			while ( k > w + l )
++			{
++				h ++;
++				w += l; /* previous table always l bits */
++
++				/* compute minimum size table less than or equal to l bits */
++				z = ( z = g - w ) > ( unsigned )l ? l : z; /* upper limit on table size */
++				if (( f = 1 << ( j = k - w )) > a + 1 ) /* try a k-w bit table */
++				{ /* too few codes for k-w bit table */
++					f -= a + 1; /* deduct codes from patterns left */
++					xp = c + k;
++					while (++ j < z ) /* try smaller tables up to z bits */
++					{
++						if (( f <<= 1 ) <= *++ xp )
++							break; /* enough codes to use up j bits */
++						f -= * xp; /* else deduct codes from patterns */
++					}
++				}
++				z = 1 << j; /* table entries for j-bit table */
++
++				/* allocate and link in new table */
++				if (( q = ( struct huft *)malloc(( z + 1 )* sizeof( struct huft ))) ==
++					( struct huft *)NULL )
++				{
++					if ( h )
++						huft_free( u[0] );
++					return 3; /* not enough memory */
++				}
++				hufts += z + 1; /* track memory usage */
++				* t = q + 1; /* link to list for huft_free() */
++				*( t = &( q->v.t )) = ( struct huft *)NULL;
++				u[h] = ++ q; /* table starts after link */
++
++				/* connect to last table, if there is one */
++				if ( h )
++				{
++					x[h] = i; /* save pattern for backing up */
++					r.b = ( uch )l; /* bits to dump before this table */
++					r.e = ( uch )( 16 + j ); /* bits in this table */
++					r.v.t = q; /* pointer to this table */
++					j = i >> ( w - l ); /* (get around Turbo C bug) */
++					u[h - 1][j] = r; /* connect to last table */
++				}
++			}
++
++			/* set up table entry in r */
++			r.b = ( uch )( k - w );
++			if ( p >= v + n )
++				r.e = 99; /* out of values--invalid code */
++			else if (* p < s )
++			{
++				r.e = ( uch )(* p < 256 ? 16 : 15 ); /* 256 is end-of-block code */
++				r.v.n = ( ush )(* p ); /* simple code is just the value */
++				p ++; /* one compiler does not like *p++ */
++			}
++			else
++			{
++				r.e = ( uch )e[ * p - s]; /* non-simple--look up in lists */
++				r.v.n = d[ * p ++ - s];
++			}
++
++			/* fill code-like entries with r */
++			f = 1 << ( k - w );
++			for ( j = i >> w; j < z; j += f )
++				q[j] = r;
++
++			/* backwards increment the k-bit code i */
++			for ( j = 1 << ( k - 1 ); i & j; j >>= 1 )
++				i ^= j;
++			i ^= j;
++
++			/* backup over finished tables */
++			while (( i & (( 1 << w ) - 1 )) != x[h] )
++			{
++				h --; /* don't need to update q */
++				w -= l;
++			}
++		}
++	}
++
++	/* Return true (1) if we were given an incomplete table */
++	return y != 0 && g != 1;
++}
++
++int huft_free( struct huft * t )
++/* Free the malloc'ed tables built by huft_build(), which makes a linked
++list of the tables it made, with the links in a dummy first entry of
++each table. */
++{
++	register struct huft * p, * q;
++
++	/* Go through linked list, freeing from the malloced (t[-1]) address. */
++	p = t;
++	while ( p != ( struct huft *)NULL )
++	{
++		q = (-- p )->v.t;
++		free(( char *)p );
++		p = q;
++	}
++	return 0;
++}
++
++int inflate_codes( struct huft * tl, struct huft * td, int bl, int bd )
++/* inflate (decompress) the codes in a deflated (compressed) block.
++Return an error code or zero if it all goes ok. */
++{
++	register unsigned e; /* table entry flag/number of extra bits */
++	unsigned n, d; /* length and index for copy */
++	unsigned w; /* current window position */
++	struct huft * t; /* pointer to table entry */
++	unsigned ml, md; /* masks for bl and bd bits */
++	register ulg b; /* bit buffer */
++	register unsigned k; /* number of bits in bit buffer */
++
++	/* make local copies of globals */
++	b = bb; /* initialize bit buffer */
++	k = bk;
++	w = wp; /* initialize window position */
++
++	/* inflate the coded data */
++	ml = mask_bits[bl]; /* precompute masks for speed */
++	md = mask_bits[bd];
++	for (;;) /* do until end of block */
++	{
++		NEEDBITS(( unsigned )bl );
++		if (( e = ( t = tl + (( unsigned )b & ml ))->e ) > 16 ) /* bits */
++			do {
++				if ( e == 99 )/* comment */
++					return 1;
++				DUMPBITS( t->b );
++				e -= 16; /* bits */
++				NEEDBITS( e );
++			} while (( e = ( t = t->v.t + (( unsigned )b & mask_bits[e] ))->e ) > 16 ); /* judge */
++		DUMPBITS( t->b );
++		if ( e == 16 ) /* then it's a literal */
++		{
++			slide[w ++ ] = ( uch )t->v.n;
++			Tracevv(( stderr, "%c", slide[w - 1] ));
++			if ( w == WSIZE )
++			{
++				flush_output( w );
++				w = 0;
++			}
++		}
++		else /* it's an EOB or a length */
++		{
++			/* exit if end of block */
++			if ( e == 15 )
++				break;
++
++			/* get length of block to copy */
++			NEEDBITS( e );
++			n = t->v.n + (( unsigned )b & mask_bits[e] );
++			DUMPBITS( e );
++
++			/* decode distance of block to copy */
++			NEEDBITS(( unsigned )bd )
++				if (( e = ( t = td + (( unsigned )b & md ))->e ) > 16 )
++					do {
++						if ( e == 99 )/* comment */
++							return 1;
++						DUMPBITS( t->b );
++						e -= 16; /* bits */
++						NEEDBITS( e );
++					} while (( e = ( t = t->v.t + (( unsigned )b & mask_bits[e] ))->e ) > 16 ); /* bits */
++			DUMPBITS( t->b );
++			NEEDBITS( e )
++				d = w - t->v.n - (( unsigned )b & mask_bits[e] );
++			DUMPBITS( e )
++				Tracevv(( stderr, "\\[%d,%d]", w - d, n ));
++
++			/* do the copy */
++			do {
++				n -= ( e = ( e = WSIZE - (( d &= WSIZE - 1 ) > w ? d : w )) > n ? n : e );
++#if !defined(NOMEMCPY) && !defined(DEBUG)
++				if ( w - d >= e ) /* (this test assumes unsigned comparison) */
++				{
++					memcpy( slide + w, slide + d, e );
++					w += e;
++					d += e;
++				}
++				else /* do it slow to avoid memcpy() overlap */
++#endif /* !NOMEMCPY */
++					do {
++						slide[w ++ ] = slide[d ++ ];
++						Tracevv(( stderr, "%c", slide[w - 1] ));
++					} while (-- e );
++				if ( w == WSIZE )
++				{
++					flush_output( w );
++					w = 0;
++				}
++			} while ( n );
++		}
++	}
++
++	/* restore the globals from the locals */
++	wp = w; /* restore global window pointer */
++	bb = b; /* restore global bit buffer */
++	bk = k;
++
++	/* done */
++	return 0;
++}
++
++int inflate_stored()
++/* "decompress" an inflated type 0 (stored) block. */
++{
++	unsigned n; /* number of bytes in block */
++	unsigned w; /* current window position */
++	register ulg b; /* bit buffer */
++	register unsigned k; /* number of bits in bit buffer */
++
++	/* make local copies of globals */
++	b = bb; /* initialize bit buffer */
++	k = bk;
++	w = wp; /* initialize window position */
++
++	/* go to byte boundary */
++	n = k & 7;
++	DUMPBITS( n );
++
++	/* get the length and its complement */
++	NEEDBITS( 16 );
++	n = (( unsigned )b & 0xffff );/* n */
++	DUMPBITS( 16 ); /* dump bits */
++	NEEDBITS( 16 ); /* dump bits */
++	if ( n != ( unsigned )((~ b ) & 0xffff )) /* n */
++		return 1; /* error in compressed data */
++	DUMPBITS( 16 ); /* dump bits */
++
++	/* read and output the compressed data */
++	while ( n --)
++	{
++		NEEDBITS( 8 ); /* bits */
++		slide[w ++ ] = ( uch )b;
++		if ( w == WSIZE )
++		{
++			flush_output( w );
++			w = 0;
++		}
++		DUMPBITS( 8 ); /* bits */
++	}
++
++	/* restore the globals from the locals */
++	wp = w; /* restore global window pointer */
++	bb = b; /* restore global bit buffer */
++	bk = k;
++	return 0;
++}
++
++int inflate_fixed()
++/* decompress an inflated type 1 (fixed Huffman codes) block. We should
++either replace this with a custom decoder, or at least precompute the
++Huffman tables. */
++{
++	int i; /* temporary variable */
++	struct huft * tl; /* literal/length code table */
++	struct huft * td; /* distance code table */
++	int bl; /* lookup bits for tl */
++	int bd; /* lookup bits for td */
++	unsigned l[288]; /* length list for huft_build */
++
++	/* set up literal table */
++	for ( i = 0; i < 144; i ++)
++		l[i] = 8; /* 8 */
++	/* set up literal table */
++	for (; i < 256; i ++)
++		l[i] = 9; /* 9 */
++	/* set up literal table */
++	for (; i < 280; i ++)
++		l[i] = 7; /* 7 */
++	/* set up literal table */
++	for (; i < 288; i ++) /* make a complete, but wrong code set */
++		l[i] = 8; /* 8 */
++	bl = 7; /* bl */
++	if (( i = huft_build( l, 288, 257, cplens, cplext, & tl, & bl )) != 0 )/* comment */
++		return i;
++
++	/* set up distance table */
++	for ( i = 0; i < 30; i ++) /* make an incomplete code set */
++		l[i] = 5; /* 5 */
++	bd = 5; /* 5 */
++	/* huffman build tree */
++	if (( i = huft_build( l, 30, 0, cpdist, cpdext, & td, & bd )) > 1 )
++	{
++		huft_free( tl );
++		return i;
++	}
++
++	/* decompress until an end-of-block code */
++	if ( inflate_codes( tl, td, bl, bd ))
++		return 1;
++
++	/* free the decoding tables, return */
++	huft_free( tl );
++	huft_free( td );
++	return 0;
++}
++
++int inflate_dynamic()
++/* decompress an inflated type 2 (dynamic Huffman codes) block. */
++{
++	int i; /* temporary variables */
++	unsigned j;
++	unsigned l; /* last length */
++	unsigned m; /* mask for bit lengths table */
++	unsigned n; /* number of lengths to get */
++	struct huft * tl; /* literal/length code table */
++	struct huft * td; /* distance code table */
++	int bl; /* lookup bits for tl */
++	int bd; /* lookup bits for td */
++	unsigned nb; /* number of bit length codes */
++	unsigned nl; /* number of literal/length codes */
++	unsigned nd; /* number of distance codes */
++	unsigned ll[286 + 30]; /* literal/length and distance code lengths */
++	register ulg b; /* bit buffer */
++	register unsigned k; /* number of bits in bit buffer */
++
++	/* make local bit buffer */
++	b = bb;
++	k = bk;
++
++	/* read in table lengths */
++	NEEDBITS( 5 ); /* bits */
++	nl = 257 + (( unsigned )b & 0x1f ); /* number of literal/length codes */
++	DUMPBITS( 5 ); /* bits */
++	NEEDBITS( 5 ); /* bits */
++	nd = 1 + (( unsigned )b & 0x1f ); /* number of distance codes */
++	DUMPBITS( 5 ); /* bits */
++	NEEDBITS( 4 ); /* bits */
++	nb = 4 + (( unsigned )b & 0xf ); /* number of bit length codes */
++	DUMPBITS( 4 ); /* bits */
++
++	if ( nl > 286 || nd > 30 ) /* judge */
++		return 1; /* bad lengths */
++
++	/* read in bit-length-code lengths */
++	for ( j = 0; j < nb; j ++)
++	{
++		NEEDBITS( 3 ); /* bits */
++		ll[border[j]] = ( unsigned )b & 7; /* bits */
++		DUMPBITS( 3 ); /* bits */
++	}
++	for (; j < 19; j ++) /* bits */
++		ll[border[j]] = 0; /* bits */
++
++	/* build decoding table for trees--single level, 7 bit lookup */
++	bl = 7;
++	if (( i = huft_build( ll, 19, 19, NULL, NULL, & tl, & bl )) != 0 ) /* bits */
++	{
++		if ( i == 1 )
++			huft_free( tl );
++		return i; /* incomplete code set */
++	}
++
++	/* read in literal and distance code lengths */
++	n = nl + nd;
++	m = mask_bits[bl];
++	i = l = 0;
++	while (( unsigned )i < n )
++	{
++		NEEDBITS(( unsigned )bl );
++		j = ( td = tl + (( unsigned )b & m ))->b;
++		DUMPBITS( j );
++		j = td->v.n;
++		if ( j < 16 ) /* length of code in bits (0..15) */
++			ll[i ++ ] = l = j; /* save last length in l */
++		else if ( j == 16 ) /* repeat last length 3 to 6 times */
++		{
++			NEEDBITS( 2 ); /* bits */
++			j = 3 + (( unsigned )b & 3 );/* comment */
++			DUMPBITS( 2 ); /* bits */
++			if (( unsigned )i + j > n )
++				return 1;
++			while ( j --)
++				ll[i ++ ] = l;
++		}
++		else if ( j == 17 ) /* 3 to 10 zero length codes */
++		{
++			NEEDBITS( 3 ); /* bits */
++			j = 3 + (( unsigned )b & 7 );/* comment */
++			DUMPBITS( 3 ); /* bits */
++			if (( unsigned )i + j > n )
++				return 1;
++			while ( j --)
++				ll[i ++ ] = 0;
++			l = 0;
++		}
++		else /* j == 18: 11 to 138 zero length codes */
++		{
++			NEEDBITS( 7 ); /* bits */
++			j = 11 + (( unsigned )b & 0x7f ); /* j */
++			DUMPBITS( 7 ); /* bits */
++			if (( unsigned )i + j > n )
++				return 1;
++			while ( j --)
++				ll[i ++ ] = 0;
++			l = 0;
++		}
++	}
++
++	/* free decoding table for trees */
++	huft_free( tl );
++
++	/* restore the global bit buffer */
++	bb = b;
++	bk = k;
++
++	/* build the decoding tables for literal/length and distance codes */
++	bl = lbits;
++	if (( i = huft_build( ll, nl, 257, cplens, cplext, & tl, & bl )) != 0 )/* comment */
++	{
++		if ( i == 1 ) {
++			fprintf( stderr, " incomplete literal tree\n" );
++			huft_free( tl );
++		}
++		return i; /* incomplete code set */
++	}
++	bd = dbits;
++	if (( i = huft_build( ll + nl, nd, 0, cpdist, cpdext, & td, & bd )) != 0 )
++	{
++		if ( i == 1 )
++		{
++			fprintf( stderr, " incomplete distance tree\n" );
++			huft_free( td );
++		}
++		huft_free( tl );
++		return i; /* incomplete code set */
++	}
++
++	/* decompress until an end-of-block code */
++	if ( inflate_codes( tl, td, bl, bd ))
++		return 1;
++
++	/* free the decoding tables, return */
++	huft_free( tl );
++	huft_free( td );
++	return 0;
++}
++
++int inflate_block( int * e )
++/* decompress an inflated block */
++{
++	unsigned t; /* block type */
++	register ulg b; /* bit buffer */
++	register unsigned k; /* number of bits in bit buffer */
++
++	/* make local bit buffer */
++	b = bb;
++	k = bk;
++
++	/* read in last block bit */
++	NEEDBITS( 1 ); /* bits */
++	* e = ( int )b & 1;
++	DUMPBITS( 1 ); /* bits */
++
++	/* read in block type */
++	NEEDBITS( 2 ); /* bits */
++	t = ( unsigned )b & 3;/* comment */
++	DUMPBITS( 2 ); /* bits */
++
++	/* restore the global bit buffer */
++	bb = b;
++	bk = k;
++
++	/* inflate that block type */
++	if ( t == 2 )
++		return inflate_dynamic();
++	if ( t == 0 )
++		return inflate_stored();
++	if ( t == 1 )
++		return inflate_fixed();
++
++	/* bad block type */
++	return 2;
++}
++
++int inflate()
++/* decompress an inflated entry */
++{
++	int e; /* last block flag */
++	int r; /* result code */
++	unsigned h; /* maximum struct huft's malloc'ed */
++
++	/* initialize window, bit buffer */
++	wp = 0;
++	bk = 0;
++	bb = 0;
++
++	/* decompress until the last block */
++	h = 0;
++	do {
++		hufts = 0;
++		if (( r = inflate_block(& e )) != 0 )
++			return r;
++		if ( hufts > h )
++			h = hufts;
++	} while (! e );
++
++	/* Undo too much lookahead. The next read will be byte aligned so we
++	* can discard unused bits in the last meaningful byte.
++	*/
++	while ( bk >= 8 ) {
++		bk -= 8;/* comment */
++		inptr --;
++	}
++
++	/* flush out slide */
++	flush_output( wp );
++
++	/* return success */
++	return 0;
++}
+diff --git a/lib/gzip/lzw.h b/lib/gzip/lzw.h
+new file mode 100644
+index 0000000..d1b35a8
+--- /dev/null
++++ b/lib/gzip/lzw.h
+@@ -0,0 +1,32 @@
++/* lzw.h -- define the lzw functions.
++* Copyright (C) 1992-1993 Jean-loup Gailly.
++* This is free software; you can redistribute it and/or modify it under the
++* terms of the GNU General Public License, see the file COPYING.
++*/
++#if !defined( OF ) && defined( lint )
++#include "gzip.h"
++#endif
++#ifndef BITS
++#define BITS 16 /* bits len */
++#endif
++#define INIT_BITS 9 /* Initial number of bits per code */
++#define LZW_MAGIC "\037\235" /* Magic header for lzw files, 1F 9D */
++//#define BIT_MASK 0x1f /* Mask for 'number of compression bits' */
++/* Mask 0x20 is reserved to mean a fourth header byte, and 0x40 is free.
++* It's a pity that old uncompress does not check bit 0x20. That makes
++* extension of the format actually undesirable because old compress
++* would just crash on the new format instead of giving a meaningful
++* error message. It does check the number of bits, but it's more
++* helpful to say "unsupported format, get a new version" than
++* "can only handle 16 bits".
++*/
++#define BLOCK_MODE 0x80 /* Block compression: if table is full and compression rate is dropping,
++* clear the dictionary.
++*/
++#define LZW_RESERVED 0x60 /* reserved bits */
++#define CLEAR 256 /* flush the dictionary */
++#define FIRST ( CLEAR + 1 ) /* first free entry */
++extern int maxbits; /* max bits per code for LZW */
++extern int block_mode; /* block compress mode -C compatible with 2.0 */
++extern int lzw ( int in, int out );
++extern int unlzw ( int in, int out );
+diff --git a/lib/gzip/trees.c b/lib/gzip/trees.c
+new file mode 100644
+index 0000000..235a4e6
+--- /dev/null
++++ b/lib/gzip/trees.c
+@@ -0,0 +1,1006 @@
++/* trees.c -- output deflated data using Huffman coding
++* Copyright (C) 1992-1993 Jean-loup Gailly
++* This is free software; you can redistribute it and/or modify it under the
++* terms of the GNU General Public License, see the file COPYING.
++*/
++
++/*
++* PURPOSE
++*
++* Encode various sets of source values using variable-length
++* binary code trees.
++*
++* DISCUSSION
++*
++* The PKZIP "deflation" process uses several Huffman trees. The more
++* common source values are represented by shorter bit sequences.
++*
++* Each code tree is stored in the ZIP file in a compressed form
++* which is itself a Huffman encoding of the lengths of
++* all the code strings (in ascending order by source values).
++* The actual code strings are reconstructed from the lengths in
++* the UNZIP process, as described in the "application note"
++* (APPNOTE.TXT) distributed as part of PKWARE's PKZIP program.
++*
++* REFERENCES
++*
++* Lynch, Thomas J.
++* Data Compression: Techniques and Applications, pp. 53-55.
++* Lifetime Learning Publications, 1985. ISBN 0-534-03418-7.
++*
++* Storer, James A.
++* Data Compression: Methods and Theory, pp. 49-50.
++* Computer Science Press, 1988. ISBN 0-7167-8156-5.
++*
++* Sedgewick, R.
++* Algorithms, p290.
++* Addison-Wesley, 1983. ISBN 0-201-06672-6.
++*
++* INTERFACE
++*
++* void ct_init (ush *attr, int *methodp)
++* Allocate the match buffer, initialize the various tables and save
++* the location of the internal file attribute (ascii/binary) and
++* method (DEFLATE/STORE)
++*
++* void ct_tally (int dist, int lc);
++* Save the match info and tally the frequency counts.
++*
++* long flush_block (char *buf, ulg stored_len, int eof)
++* Determine the best encoding for the current block: dynamic trees,
++* static trees or store, and output the encoded block to the zip
++* file. Returns the total compressed length for the file so far.
++*
++*/
++
++#include "gzip.h"
++
++/* ===========================================================================
++* Constants
++*/
++/* All codes must not exceed MAX_BITS bits */
++#define MAX_BITS 15
++
++/* Bit length codes must not exceed MAX_BL_BITS bits */
++#define MAX_BL_BITS 7
++
++/* number of length codes, not counting the special END_BLOCK code */
++#define LENGTH_CODES 29
++
++/* number of literal bytes 0..255 */
++#define LITERALS 256
++
++/* end of block literal code */
++#define END_BLOCK 256
++
++/* number of Literal or Length codes, including the END_BLOCK code */
++#define L_CODES (LITERALS+1+LENGTH_CODES)
++
++/* number of distance codes */
++#define D_CODES 30
++
++/* number of codes used to transfer the bit lengths */
++#define BL_CODES 19
++
++local int near extra_lbits[LENGTH_CODES]
++/* extra bits for each length code */
++= {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0};
++
++local int near extra_dbits[D_CODES]
++/* extra bits for each distance code */
++= {0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13};
++
++local int near extra_blbits[BL_CODES]
++/* extra bits for each bit length code */
++= {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7};
++
++#define STORED_BLOCK 0
++/* The three kinds of block type */
++#define STATIC_TREES 1
++/* The three kinds of block type */
++#define DYN_TREES 2
++
++#define LIT_BUFSIZE 0x2000
++#ifndef DIST_BUFSIZE
++#define DIST_BUFSIZE LIT_BUFSIZE
++#endif
++/* Sizes of match buffers for literals/lengths and distances. There are
++* 4 reasons for limiting LIT_BUFSIZE to 64K:
++* - frequencies can be kept in 16 bit counters
++* - if compression is not successful for the first block, all input data is
++* still in the window so we can still emit a stored block even when input
++* comes from standard input. (This can also be done for all blocks if
++* LIT_BUFSIZE is not greater than 32K.)
++* - if compression is not successful for a file smaller than 64K, we can
++* even emit a stored file instead of a stored block (saving 5 bytes).
++* - creating new Huffman trees less frequently may not provide fast
++* adaptation to changes in the input data statistics. (Take for
++* example a binary file with poorly compressible code followed by
++* a highly compressible string table.) Smaller buffer sizes give
++* fast adaptation but have of course the overhead of transmitting trees
++* more frequently.
++* - I can't count above 4
++* The current code is general and allows DIST_BUFSIZE < LIT_BUFSIZE (to save
++* memory at the expense of compression). Some optimizations would be possible
++* if we rely on DIST_BUFSIZE == LIT_BUFSIZE.
++*/
++#if LIT_BUFSIZE > INBUFSIZ
++error cannot overlay l_buf and inbuf
++#endif
++/* repeat previous bit length 3-6 times (2 bits of repeat count) */
++#define REP_3_6 16
++
++/* repeat a zero length 3-10 times (3 bits of repeat count) */
++#define REPZ_3_10 17
++
++/* repeat a zero length 11-138 times (7 bits of repeat count) */
++#define REPZ_11_138 18
++
++/* ===========================================================================
++* Local data
++*/
++
++/* Data structure describing a single value and its code string. */
++typedef struct ct_data {
++	union {
++		ush freq; /* frequency count */
++		ush code; /* bit string */
++	} fc;
++	union {
++		ush dad; /* father node in Huffman tree */
++		ush len; /* length of bit string */
++	} dl;
++} ct_data;
++
++#define Freq fc.freq
++#define Code fc.code
++#define Dad dl.dad
++#define Len dl.len
++
++/* maximum heap size */
++#define HEAP_SIZE (2*L_CODES+1)
++
++local ct_data near dyn_ltree[HEAP_SIZE]; /* literal and length tree */
++local ct_data near dyn_dtree[2 * D_CODES + 1]; /* distance tree */
++
++/* The static literal tree. Since the bit lengths are imposed, there is no
++* need for the L_CODES extra codes used during heap construction. However
++* The codes 286 and 287 are needed to build a canonical tree (see ct_init
++* below).
++*/
++local ct_data near static_ltree[L_CODES + 2];
++
++local ct_data near static_dtree[D_CODES];
++/* The static distance tree. (Actually a trivial tree since all codes use
++* 5 bits.)
++*/
++
++/* Huffman tree for the bit lengths */
++local ct_data near bl_tree[2 * BL_CODES + 1];
++
++typedef struct tree_desc {
++	ct_data near * dyn_tree; /* the dynamic tree */
++	ct_data near * static_tree; /* corresponding static tree or NULL */
++	int near * extra_bits; /* extra bits for each code or NULL */
++	int extra_base; /* base index for extra_bits */
++	int elems; /* max number of elements in the tree */
++	int max_length; /* max bit length for the codes */
++	int max_code; /* largest code with non zero frequency */
++} tree_desc;
++
++local tree_desc near l_desc = {
++	dyn_ltree, static_ltree, extra_lbits, LITERALS + 1, L_CODES, MAX_BITS, 0
++};
++
++local tree_desc near d_desc = {
++	dyn_dtree, static_dtree, extra_dbits, 0, D_CODES, MAX_BITS, 0
++};
++
++local tree_desc near bl_desc = {
++	bl_tree, ( ct_data near *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS, 0
++};
++
++/* number of codes at each bit length for an optimal tree */
++local ush near bl_count[MAX_BITS + 1];
++
++/* The lengths of the bit length codes are sent in order of decreasing
++* probability, to avoid transmitting the lengths for unused bit length codes.
++*/
++local uch near bl_order[BL_CODES] = {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
++
++local int near heap[2 * L_CODES + 1]; /* heap used to build the Huffman trees */
++local int heap_len = 0; /* number of elements in the heap */
++local int heap_max = 0; /* element of largest frequency */
++/* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
++* The same heap array is used to build all trees.
++*/
++
++/* Depth of each subtree used as tie breaker for trees of equal frequency */
++local uch near depth[2 * L_CODES + 1];
++
++/* length code for each normalized match length (0 == MIN_MATCH) */
++local uch length_code[MAX_MATCH - MIN_MATCH + 1];
++
++/* distance codes. The first 256 values correspond to the distances
++* 3 .. 258, the last 256 values correspond to the top 8 bits of
++* the 15 bit distances.
++*/
++local uch dist_code[512];
++
++/* First normalized length for each code (0 = MIN_MATCH) */
++local int near base_length[LENGTH_CODES];
++
++/* First normalized distance for each code (0 = distance of 1) */
++local int near base_dist[D_CODES];
++
++/* DECLARE(uch, l_buf, LIT_BUFSIZE); buffer for literals or lengths */
++#define l_buf inbuf
++
++/* flag_buf is a bit array distinguishing literals from lengths in
++* l_buf, thus indicating the presence or absence of a distance.
++*/
++local uch near flag_buf[( LIT_BUFSIZE / 8 )];
++
++local unsigned last_lit = 0; /* running index in l_buf */
++local unsigned last_dist = 0; /* running index in d_buf */
++local unsigned last_flags = 0; /* running index in flag_buf */
++local uch trees_flags = 0; /* current flags not yet saved in flag_buf */
++local uch flag_bit = 0; /* current bit used in flags */
++/* bits are filled in flags starting at bit 0 (least significant).
++* Note: these flags are overkill in the current code since we don't
++* take advantage of DIST_BUFSIZE == LIT_BUFSIZE.
++*/
++
++local ulg opt_len = 0; /* bit length of current block with optimal trees */
++local ulg static_len = 0; /* bit length of current block with static trees */
++
++local ulg compressed_len = 0; /* total bit length of compressed file */
++
++local ulg input_len = 0; /* total byte length of input file */
++/* input_len is for debugging only since we can get it by other means. */
++
++ush * file_type; /* pointer to UNKNOWN, BINARY or ASCII */
++int * file_method; /* pointer to DEFLATE or STORE */
++
++#ifdef DEBUG
++extern ulg bits_sent; /* bit length of the compressed data */
++extern int isize; /* byte length of input file */
++#endif
++
++extern int block_start; /* window offset of current block */
++extern unsigned near strstart; /* window offset of current string */
++
++/* ===========================================================================
++* Local (static) routines in this file.
++*/
++
++local void init_block( void );
++local void pqdownheap( ct_data near * tree, int k );
++local void gen_bitlen( tree_desc near * desc );
++local void gen_codes( ct_data near * tree, int max_code );
++local void build_tree( tree_desc near * desc );
++local void scan_tree( ct_data near * tree, int max_code );
++local void send_tree( ct_data near * tree, int max_code );
++local int build_bl_tree( void );
++local void send_all_trees( int lcodes, int dcodes, int blcodes );
++local void compress_block( ct_data near * ltree, ct_data near * dtree );
++local void set_file_type( void );
++
++#ifndef DEBUG
++#define send_code(c, tree) send_bits(tree[c].Code, tree[c].Len)
++/* Send a code of the given tree. c and tree must not have side effects */
++
++#else /* DEBUG */
++#define send_code(c, tree) \
++{ if (verbose>1) fprintf(stderr,"\ncd %3d ",(c)); \
++	send_bits(tree[c].Code, tree[c].Len); }
++#endif
++
++/* Mapping from a distance to a distance code. dist is the distance - 1 and
++* must not have side effects. dist_code[256] and dist_code[257] are never
++* used.
++*/
++#define d_code(dist) ((dist) < 256 ? dist_code[dist] : dist_code[256+((dist)>>7)])
++
++#define MAX(a,b) (a >= b ? a : b)
++/* the arguments must not have side effects */
++
++/* ===========================================================================
++* Allocate the match buffer, initialize the various tables and save the
++* location of the internal file attribute (ascii/binary) and method
++* (DEFLATE/STORE).
++*/
++void ct_init( ush * attr, int * methodp )
++{
++	int n; /* iterates over tree elements */
++	int bits; /* bit counter */
++	int length; /* length value */
++	int code; /* code value */
++	int dist; /* distance index */
++
++	file_type = attr;
++	file_method = methodp;
++	compressed_len = input_len = 0L;
++
++	if ( static_dtree[0].Len != 0 ) return; /* ct_init already called */
++
++	/* Initialize the mapping length (0..255) -> length code (0..28) */
++	length = 0;
++	for ( code = 0; code < LENGTH_CODES - 1; code ++) {
++		base_length[code] = length;
++		for ( n = 0; n < ( 1 << extra_lbits[code] ); n ++) {
++			length_code[length ++ ] = ( uch )code;
++		}
++	}
++	/* Note that the length 255 (match length 258) can be represented
++	* in two different ways: code 284 + 5 bits or code 285, so we
++	* overwrite length_code[255] to use the best encoding:
++	*/
++	length_code[length - 1] = ( uch )code;
++
++	/* Initialize the mapping dist (0..32K) -> dist code (0..29) */
++	dist = 0;
++	for ( code = 0 ; code < 16; code ++) {
++		base_dist[code] = dist;
++		for ( n = 0; n < ( 1 << extra_dbits[code] ); n ++) {
++			dist_code[dist ++ ] = ( uch )code;
++		}
++	}
++	dist >>= 7; /* from now on, all distances are divided by 128 */
++	for ( ; code < D_CODES; code ++) {
++		base_dist[code] = dist << 7;/* base dist */
++		for ( n = 0; n < ( 1 <<( extra_dbits[code] - 7 )); n ++) {
++			dist_code[256 + dist ++ ] = ( uch )code; /* dist code */
++		}
++	}
++
++	/* Construct the codes of the static literal tree */
++	for ( bits = 0; bits <= MAX_BITS; bits ++) bl_count[bits] = 0;
++	n = 0;
++	while ( n <= 143 ) static_ltree[n ++ ].Len = 8, bl_count[8] ++; /* ��ʼ�� */
++	while ( n <= 255 ) static_ltree[n ++ ].Len = 9, bl_count[9] ++; /* ��ʼ�� */
++	while ( n <= 279 ) static_ltree[n ++ ].Len = 7, bl_count[7] ++; /* ��ʼ�� */
++	while ( n <= 287 ) static_ltree[n ++ ].Len = 8, bl_count[8] ++; /* ��ʼ�� */
++	/* Codes 286 and 287 do not exist, but we must include them in the
++	* tree construction to get a canonical Huffman tree (longest code
++	* all ones)
++	*/
++	gen_codes(( ct_data near *)static_ltree, L_CODES + 1 );
++
++	/* The static distance tree is trivial: */
++	for ( n = 0; n < D_CODES; n ++) {
++		static_dtree[n].Len = 5; /* ��ʼ�� */
++		static_dtree[n].Code = bi_reverse( n, 5 ); /* ��ʼ�� */
++	}
++
++	/* Initialize the first block of the first file: */
++	init_block();
++}
++
++/* ===========================================================================
++* Initialize a new block.
++*/
++local void init_block()
++{
++	int n; /* iterates over tree elements */
++
++	/* Initialize the trees. */
++	for ( n = 0; n < L_CODES; n ++) dyn_ltree[n].Freq = 0;
++	for ( n = 0; n < D_CODES; n ++) dyn_dtree[n].Freq = 0;
++	for ( n = 0; n < BL_CODES; n ++) bl_tree[n].Freq = 0;
++
++	dyn_ltree[END_BLOCK].Freq = 1;
++	opt_len = static_len = 0L;
++	last_lit = last_dist = last_flags = 0;
++	trees_flags = 0; flag_bit = 1;
++}
++
++#define SMALLEST 1
++/* Index within the heap array of least frequent node in the Huffman tree */
++
++/* ===========================================================================
++* Remove the smallest element from the heap and recreate the heap with
++* one less element. Updates heap and heap_len.
++*/
++#define pqremove(tree, top) \
++{\
++	top = heap[SMALLEST]; \
++	heap[SMALLEST] = heap[heap_len--]; \
++	pqdownheap(tree, SMALLEST); \
++}
++
++/* ===========================================================================
++* Compares to subtrees, using the tree depth as tie breaker when
++* the subtrees have equal frequency. This minimizes the worst case length.
++*/
++#define smaller(tree, n, m) \
++	(tree[n].Freq < tree[m].Freq || \
++	(tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))
++
++/* ===========================================================================
++* Restore the heap property by moving down the tree starting at node k,
++* exchanging a node with the smallest of its two sons if necessary, stopping
++* when the heap property is re-established (each father smaller than its
++* two sons).
++*/
++local void pqdownheap( ct_data near * tree, int k )
++{
++	int v = heap[k];
++	int j = k << 1; /* left son of k */
++	while ( j <= heap_len ) {
++		/* Set j to the smallest of the two sons: */
++		if ( j < heap_len && smaller( tree, heap[j + 1], heap[j] )) j ++;
++
++		/* Exit if v is smaller than both sons */
++		if ( smaller( tree, v, heap[j] )) break;
++
++		/* Exchange v with the smallest son */
++		heap[k] = heap[j]; k = j;
++
++		/* And continue down the tree, setting j to the left son of k */
++		j <<= 1;
++	}
++	heap[k] = v;
++}
++
++/* ===========================================================================
++* Compute the optimal bit lengths for a tree and update the total bit length
++* for the current block.
++* IN assertion: the fields freq and dad are set, heap[heap_max] and
++* above are the tree nodes sorted by increasing frequency.
++* OUT assertions: the field len is set to the optimal bit length, the
++* array bl_count contains the frequencies for each bit length.
++* The length opt_len is updated; static_len is also updated if stree is
++* not null.
++*/
++local void gen_bitlen( tree_desc near * desc )
++{
++	ct_data near * tree = desc->dyn_tree;
++	int near * extra = desc->extra_bits;
++	int base = desc->extra_base;
++	int max_code = desc->max_code;
++	int max_length = desc->max_length;
++	ct_data near * stree = desc->static_tree;
++	int h; /* heap index */
++	int n, m; /* iterate over the tree elements */
++	int bits; /* bit length */
++	int xbits; /* extra bits */
++	ush f; /* frequency */
++	int overflow = 0; /* number of elements with bit length too large */
++
++	for ( bits = 0; bits <= MAX_BITS; bits ++) bl_count[bits] = 0;
++
++	/* In a first pass, compute the optimal bit lengths (which may
++	* overflow in the case of the bit length tree).
++	*/
++	tree[heap[heap_max]].Len = 0; /* root of the heap */
++
++	for ( h = heap_max + 1; h < HEAP_SIZE; h ++) {
++		n = heap[h];
++		bits = tree[tree[n].Dad].Len + 1;
++		if ( bits > max_length ) bits = max_length, overflow ++;
++		tree[n].Len = ( ush )bits;
++		/* We overwrite tree[n].Dad which is no longer needed */
++
++		if ( n > max_code ) continue; /* not a leaf node */
++
++		bl_count[bits] ++;
++		xbits = 0;
++		if ( n >= base ) xbits = extra[n - base];
++		f = tree[n].Freq;
++		opt_len += ( ulg )f * ( bits + xbits );
++		if ( stree ) static_len += ( ulg )f * ( stree[n].Len + xbits );
++	}
++	if ( overflow == 0 ) return;
++
++	Trace(( stderr, "\nbit length overflow\n" ));
++	/* This happens for example on obj2 and pic of the Calgary corpus */
++
++	/* Find the first bit length which could increase: */
++	do {
++		bits = max_length - 1;
++		while ( bl_count[bits] == 0 ) bits --;
++		bl_count[bits] --; /* move one leaf down the tree */
++		bl_count[bits + 1] += 2; /* move one overflow item as its brother */
++		bl_count[max_length] --;
++		/* The brother of the overflow item also moves one step up,
++		* but this does not affect bl_count[max_length]
++		*/
++		overflow -= 2;
++	} while ( overflow > 0 );
++
++	/* Now recompute all bit lengths, scanning in increasing frequency.
++	* h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
++	* lengths instead of fixing only the wrong ones. This idea is taken
++	* from 'ar' written by Haruhiko Okumura.)
++	*/
++	for ( bits = max_length; bits != 0; bits --) {
++		n = bl_count[bits];
++		while ( n != 0 ) {
++			m = heap[ -- h];
++			if ( m > max_code ) continue;
++			if ( tree[m].Len != ( unsigned ) bits ) {
++				Trace(( stderr, "code %d bits %d->%d\n", m, tree[m].Len, bits ));
++				opt_len += (( int )bits -( int )tree[m].Len )*( int )tree[m].Freq;
++				tree[m].Len = ( ush )bits;
++			}
++			n --;
++		}
++	}
++}
++
++/* ===========================================================================
++* Generate the codes for a given tree and bit counts (which need not be
++* optimal).
++* IN assertion: the array bl_count contains the bit length statistics for
++* the given tree and the field len is set for all tree elements.
++* OUT assertion: the field code is set for all tree elements of non
++* zero code length.
++*/
++local void gen_codes ( ct_data near * tree, int max_code )
++{
++	ush next_code[MAX_BITS + 1]; /* next code value for each bit length */
++	ush code = 0; /* running code value */
++	int bits; /* bit index */
++	int n; /* code index */
++
++	/* The distribution counts are first used to generate the code values
++	* without bit reversal.
++	*/
++	for ( bits = 1; bits <= MAX_BITS; bits ++) {
++		next_code[bits] = code = ( code + bl_count[bits - 1] ) << 1;
++	}
++	/* Check that the bit counts in bl_count are consistent. The last code
++	* must be all ones.
++	*/
++	Assert ( code + bl_count[MAX_BITS] - 1 == ( 1 << MAX_BITS )- 1,
++		"inconsistent bit counts" );
++	Tracev(( stderr, "\ngen_codes: max_code %d ", max_code ));
++
++	for ( n = 0; n <= max_code; n ++) {
++		int len = tree[n].Len;
++		if ( len == 0 ) continue;
++		/* Now reverse the bits */
++		tree[n].Code = bi_reverse( next_code[len] ++, len );
++
++		Tracec( tree != static_ltree, ( stderr, "\nn %3d %c l %2d c %4x (%x) ",
++			n, ( isgraph( n ) ? n : ' ' ), len, tree[n].Code, next_code[len] - 1 ));
++	}
++}
++
++/* ===========================================================================
++* Construct one Huffman tree and assigns the code bit strings and lengths.
++* Update the total bit length for the current block.
++* IN assertion: the field freq is set for all tree elements.
++* OUT assertions: the fields len and code are set to the optimal bit length
++* and corresponding code. The length opt_len is updated; static_len is
++* also updated if stree is not null. The field max_code is set.
++*/
++local void build_tree( tree_desc near * desc )
++{
++	ct_data near * tree = desc->dyn_tree;
++	ct_data near * stree = desc->static_tree;
++	int elems = desc->elems;
++	int n, m; /* iterate over heap elements */
++	int max_code = - 1; /* largest code with non zero frequency */
++	int node = elems; /* next internal node of the tree */
++
++	/* Construct the initial heap, with least frequent element in
++	* heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
++	* heap[0] is not used.
++	*/
++	heap_len = 0, heap_max = HEAP_SIZE;
++
++	for ( n = 0; n < elems; n ++) {
++		if ( tree[n].Freq != 0 ) {
++			heap[ ++ heap_len] = max_code = n;
++			depth[n] = 0;
++		} else {
++			tree[n].Len = 0;
++		}
++	}
++
++	/* The pkzip format requires that at least one distance code exists,
++	* and that at least one bit should be sent even if there is only one
++	* possible code. So to avoid special checks later on we force at least
++	* two codes of non zero frequency.
++	*/
++	while ( heap_len < 2 ) {
++		int new = heap[ ++ heap_len] = ( max_code < 2 ? ++ max_code : 0 ); /* ��ʼ�� */
++		tree[new].Freq = 1;
++		depth[new] = 0;
++		opt_len --; if ( stree ) static_len -= stree[new].Len;
++		/* new is 0 or 1 so it does not have extra bits */
++	}
++	desc->max_code = max_code;
++
++	/* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
++	* establish sub-heaps of increasing lengths:
++	*/
++	for ( n = heap_len / 2; n >= 1; n --) pqdownheap( tree, n );
++
++	/* Construct the Huffman tree by repeatedly combining the least two
++	* frequent nodes.
++	*/
++	do {
++		pqremove( tree, n ); /* n = node of least frequency */
++		m = heap[SMALLEST]; /* m = node of next least frequency */
++
++		heap[ -- heap_max] = n; /* keep the nodes sorted by frequency */
++		heap[ -- heap_max] = m;
++
++		/* Create a new node father of n and m */
++		tree[node].Freq = tree[n].Freq + tree[m].Freq;
++		depth[node] = ( uch ) ( MAX( depth[n], depth[m] ) + 1 );
++		tree[n].Dad = tree[m].Dad = ( ush )node;
++#ifdef DUMP_BL_TREE
++		if ( tree == bl_tree ) {
++			1 fprintf( stderr, "\nnode %d(%d), sons %d(%d) %d(%d)",
++				node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq );
++		}
++#endif
++		/* and insert the new node in the heap */
++		heap[SMALLEST] = node ++;
++		pqdownheap( tree, SMALLEST );
++	} while ( heap_len >= 2 );/* ������ж� */
++
++	heap[ -- heap_max] = heap[SMALLEST];
++
++	/* At this point, the fields freq and dad are set. We can now
++	* generate the bit lengths.
++	*/
++	gen_bitlen(( tree_desc near *)desc );
++
++	/* The field len is now set, we can generate the bit codes */
++	gen_codes (( ct_data near *)tree, max_code );
++}
++
++/* ===========================================================================
++* Scan a literal or distance tree to determine the frequencies of the codes
++* in the bit length tree. Updates opt_len to take into account the repeat
++* counts. (The contribution of the bit length codes will be added later
++* during the construction of bl_tree.)
++*/
++local void scan_tree ( ct_data near * tree, int max_code )
++{
++	int n; /* iterates over all tree elements */
++	int prevlen = - 1; /* last emitted length */
++	int curlen; /* length of current code */
++	int nextlen = tree[0].Len; /* length of next code */
++	int count = 0; /* repeat count of the current code */
++	int max_count = 7; /* max repeat count */
++	int min_count = 4; /* min repeat count */
++
++	if ( nextlen == 0 ) max_count = 138, min_count = 3; /* ��ʼ�� */
++	tree[max_code + 1].Len = ( ush )0xffff; /* guard */
++
++	for ( n = 0; n <= max_code; n ++) {
++		curlen = nextlen; nextlen = tree[n + 1].Len;
++		if (++ count < max_count && curlen == nextlen ) {
++			continue;
++		} else if ( count < min_count ) {
++			bl_tree[curlen].Freq += count;
++		} else if ( curlen != 0 ) {
++			if ( curlen != prevlen ) bl_tree[curlen].Freq ++;
++			bl_tree[REP_3_6].Freq ++;
++		} else if ( count <= 10 ) { /* ���ȱȽ� */
++			bl_tree[REPZ_3_10].Freq ++;
++		} else {
++			bl_tree[REPZ_11_138].Freq ++;
++		}
++		count = 0; prevlen = curlen;
++		if ( nextlen == 0 ) {
++			max_count = 138, min_count = 3; /* ��ʼ�� */
++		} else if ( curlen == nextlen ) {
++			max_count = 6, min_count = 3; /* ��ʼ�� */
++		} else {
++			max_count = 7, min_count = 4; /* ��ʼ�� */
++		}
++	}
++}
++
++/* ===========================================================================
++* Send a literal or distance tree in compressed form, using the codes in
++* bl_tree.
++*/
++local void send_tree ( ct_data near * tree, int max_code )
++{
++	int n; /* iterates over all tree elements */
++	int prevlen = - 1; /* last emitted length */
++	int curlen; /* length of current code */
++	int nextlen = tree[0].Len; /* length of next code */
++	int count = 0; /* repeat count of the current code */
++	int max_count = 7; /* max repeat count */
++	int min_count = 4; /* min repeat count */
++
++	/* tree[max_code+1].Len = -1; */ /* guard already set */
++	if ( nextlen == 0 ) max_count = 138, min_count = 3;
++
++	for ( n = 0; n <= max_code; n ++) {
++		curlen = nextlen; nextlen = tree[n + 1].Len;
++		if (++ count < max_count && curlen == nextlen ) {
++			continue;
++		} else if ( count < min_count ) {
++			do { send_code( curlen, bl_tree ); } while (-- count != 0 );
++		} else if ( curlen != 0 ) {
++			if ( curlen != prevlen ) {
++				send_code( curlen, bl_tree ); count --;
++			}
++			send_code( REP_3_6, bl_tree ); send_bits( count - 3, 2 ); /* ���͵����� */
++		} else if ( count <= 10 ) { /* ���ݳ��� */
++			send_code( REPZ_3_10, bl_tree ); send_bits( count - 3, 3 ); /* ���͵����� */
++		} else {
++			send_code( REPZ_11_138, bl_tree ); send_bits( count - 11, 7 ); /* ���͵����� */
++		}
++		count = 0; prevlen = curlen;
++		if ( nextlen == 0 ) {
++			max_count = 138, min_count = 3; /* ��ʼ�� */
++		} else if ( curlen == nextlen ) {
++			max_count = 6, min_count = 3; /* ��ʼ�� */
++		} else {
++			max_count = 7, min_count = 4; /* ��ʼ�� */
++		}
++	}
++}
++
++/* ===========================================================================
++* Construct the Huffman tree for the bit lengths and return the index in
++* bl_order of the last bit length code to send.
++*/
++local int build_bl_tree()
++{
++	int max_blindex; /* index of last bit length code of non zero freq */
++
++	/* Determine the bit length frequencies for literal and distance trees */
++	scan_tree(( ct_data near *)dyn_ltree, l_desc.max_code );
++	scan_tree(( ct_data near *)dyn_dtree, d_desc.max_code );
++
++	/* Build the bit length tree: */
++	build_tree(( tree_desc near *)(& bl_desc ));
++	/* opt_len now includes the length of the tree representations, except
++	* the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
++	*/
++
++	/* Determine the number of bit length codes to send. The pkzip format
++	* requires that at least 4 bit length codes be sent. (appnote.txt says
++	* 3 but the actual value used is 4.)
++	*/
++	for ( max_blindex = BL_CODES - 1; max_blindex >= 3; max_blindex --) {
++		if ( bl_tree[bl_order[max_blindex]].Len != 0 ) break;
++	}
++	/* Update opt_len to include the bit length tree and counts */
++	opt_len += 3 *( max_blindex + 1 ) + 5 + 5 + 4; /* ��ʼ�� */
++	Tracev(( stderr, "\ndyn trees: dyn %ld, stat %ld", opt_len, static_len ));
++
++	return max_blindex;
++}
++
++/* ===========================================================================
++* Send the header for a block using dynamic Huffman trees: the counts, the
++* lengths of the bit length codes, the literal tree and the distance tree.
++* IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
++*/
++local void send_all_trees( int lcodes, int dcodes, int blcodes )
++{
++	int rank; /* index in bl_order */
++
++	Assert ( lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
++		"too many codes" );
++	Tracev(( stderr, "\nbl counts: " ));
++	send_bits( lcodes - 257, 5 ); /* not +255 as stated in appnote.txt */
++	send_bits( dcodes - 1, 5 ); /* д�뻺�� */
++	send_bits( blcodes - 4, 4 ); /* not -3 as stated in appnote.txt */
++	for ( rank = 0; rank < blcodes; rank ++) {
++		Tracev(( stderr, "\nbl code %2d ", bl_order[rank] ));
++		send_bits( bl_tree[bl_order[rank]].Len, 3 ); /* д�뻺�� */
++	}
++	Tracev(( stderr, "\nbl tree: sent %ld", bits_sent ));
++
++	send_tree(( ct_data near *)dyn_ltree, lcodes - 1 ); /* send the literal tree */
++	Tracev(( stderr, "\nlit tree: sent %ld", bits_sent ));
++
++	send_tree(( ct_data near *)dyn_dtree, dcodes - 1 ); /* send the distance tree */
++	Tracev(( stderr, "\ndist tree: sent %ld", bits_sent ));
++}
++
++/* ===========================================================================
++* Determine the best encoding for the current block: dynamic trees, static
++* trees or store, and output the encoded block to the zip file. This function
++* returns the total compressed length for the file so far.
++*/
++ulg flush_block( char * buf, ulg stored_len, int eof )
++{
++	ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
++	int max_blindex; /* index of last bit length code of non zero freq */
++
++	flag_buf[last_flags] = trees_flags; /* Save the flags for the last 8 items */
++
++	/* Check if the file is ascii or binary */
++	if (* file_type == ( ush )UNKNOWN ) set_file_type();
++
++	/* Construct the literal and distance trees */
++	build_tree(( tree_desc near *)(& l_desc ));
++	Tracev(( stderr, "\nlit data: dyn %ld, stat %ld", opt_len, static_len ));
++
++	build_tree(( tree_desc near *)(& d_desc ));
++	Tracev(( stderr, "\ndist data: dyn %ld, stat %ld", opt_len, static_len ));
++	/* At this point, opt_len and static_len are the total bit lengths of
++	* the compressed block data, excluding the tree representations.
++	*/
++
++	/* Build the bit length tree for the above two trees, and get the index
++	* in bl_order of the last bit length code to send.
++	*/
++	max_blindex = build_bl_tree();
++
++	/* Determine the best encoding. Compute first the block length in bytes */
++	opt_lenb = ( opt_len + 3 + 7 )>> 3; /* ��ʼ�� */
++	static_lenb = ( static_len + 3 + 7 )>> 3; /* ��ʼ�� */
++	input_len += stored_len; /* for debugging only */
++
++	Trace(( stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u dist %u ",
++		opt_lenb, opt_len, static_lenb, static_len, stored_len,
++		last_lit, last_dist ));
++
++	if ( static_lenb <= opt_lenb ) opt_lenb = static_lenb;
++
++	/* If compression failed and this is the first and last block,
++	* and if the zip file can be seeked (to rewrite the local header),
++	* the whole file is transformed into a stored file:
++	*/
++	if ( stored_len <= opt_lenb && eof && compressed_len == 0L && seekable()) {
++		/* Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: */
++		if ( buf == ( char *)0 ) error ( "block vanished" );
++
++		copy_block( buf, ( unsigned )stored_len, 0 ); /* without header */
++		compressed_len = stored_len << 3; /* ѹ������ */
++		* file_method = STORED;
++	} else if ( stored_len + 4 <= opt_lenb && buf != ( char *)0 ) { /* 4: two words for the lengths */
++		/* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
++		* Otherwise we can't have processed more than WSIZE input bytes since
++		* the last block flush, because compression would have been
++		* successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
++		* transform a block into a stored block.
++		*/
++		send_bits(( STORED_BLOCK << 1 )+ eof, 3 ); /* send block type */
++		compressed_len = ( compressed_len + 3 + 7 ) & ~ 7L; /* ѹ������ */
++		compressed_len += ( stored_len + 4 ) << 3; /* ѹ������ */
++
++		copy_block( buf, ( unsigned )stored_len, 1 ); /* with header */
++	} else if ( static_lenb == opt_lenb ) {
++		send_bits(( STATIC_TREES << 1 )+ eof, 3 ); /* ���͵����� */
++		compress_block(( ct_data near *)static_ltree, ( ct_data near *)static_dtree );
++		compressed_len += 3 + static_len;/* ��ѹ�� */
++	} else {
++		send_bits(( DYN_TREES << 1 )+ eof, 3 ); /* ���͵����� */
++		send_all_trees( l_desc.max_code + 1, d_desc.max_code + 1, max_blindex + 1 );
++		compress_block(( ct_data near *)dyn_ltree, ( ct_data near *)dyn_dtree );
++		compressed_len += 3 + opt_len; /* ѹ������ */
++	}
++	Assert ( compressed_len == bits_sent, "bad compressed size" );
++	init_block();
++
++	if ( eof ) {
++		Assert ( input_len == isize, "bad input size" );
++		bi_windup();
++		compressed_len += 7; /* align on byte boundary */
++	}
++
++	return compressed_len >> 3; /* ѹ������ */
++}
++
++/* ===========================================================================
++* Save the match info and tally the frequency counts. Return true if
++* the current block must be flushed.
++*/
++int ct_tally ( int dist, int lc )
++{
++	l_buf[last_lit ++ ] = ( uch )lc;
++	if ( dist == 0 ) {
++		/* lc is the unmatched char */
++		dyn_ltree[lc].Freq ++;
++	} else {
++		/* Here, lc is the match length - MIN_MATCH */
++		dist --; /* dist = match distance - 1 */
++		Assert(( ush )dist < ( ush )MAX_DIST &&
++			( ush )lc <= ( ush )( MAX_MATCH - MIN_MATCH ) &&
++			( ush )d_code( dist ) < ( ush )D_CODES, "ct_tally: bad match" );
++
++		dyn_ltree[length_code[lc] + LITERALS + 1].Freq ++;
++		dyn_dtree[d_code( dist )].Freq ++;
++
++		d_buf[last_dist ++ ] = ( ush )dist;
++		trees_flags |= flag_bit;
++	}
++	flag_bit <<= 1;
++
++	/* Output the flags if they fill a byte: */
++	if (( last_lit & 7 ) == 0 ) {
++		flag_buf[last_flags ++ ] = trees_flags;
++		trees_flags = 0, flag_bit = 1;
++	}
++	/* Try to guess if it is profitable to stop the current block here */
++	if ( level > 2 && ( last_lit & 0xfff ) == 0 ) {
++		/* Compute an upper bound for the compressed length */
++		ulg out_length = ( ulg )last_lit * 8L;
++		ulg in_length = ( ulg )strstart - block_start;
++		int dcode;
++		for ( dcode = 0; dcode < D_CODES; dcode ++) {
++			out_length += ( ulg )dyn_dtree[dcode].Freq *( 5L + extra_dbits[dcode] );/* ��ѯ */
++		}
++		out_length >>= 3; /* ������� */
++		if ( last_dist < last_lit / 2 && out_length < in_length / 2 ) return 1;/* �����ж� */
++	}
++	return ( last_lit == LIT_BUFSIZE - 1 || last_dist == DIST_BUFSIZE );
++	/* We avoid equality with LIT_BUFSIZE because of wraparound at 64K
++	* on 16 bit machines and because stored blocks are restricted to
++	* 64K-1 bytes.
++	*/
++}
++
++/* ===========================================================================
++* Send the block data compressed using the given Huffman trees
++*/
++local void compress_block( ct_data near * ltree, ct_data near * dtree )
++{
++	unsigned dist; /* distance of matched string */
++	int lc; /* match length or unmatched char (if dist == 0) */
++	unsigned lx = 0; /* running index in l_buf */
++	unsigned dx = 0; /* running index in d_buf */
++	unsigned fx = 0; /* running index in flag_buf */
++	uch flag = 0; /* current flags */
++	unsigned code; /* the code to send */
++	int extra; /* number of extra bits to send */
++
++	if ( last_lit != 0 ) do {
++		if (( lx & 7 ) == 0 ) flag = flag_buf[fx ++ ]; /* ��־ */
++		lc = l_buf[lx ++ ];
++		if (( flag & 1 ) == 0 ) {
++			send_code( lc, ltree ); /* send a literal byte */
++			Tracecv( isgraph( lc ), ( stderr, " '%c' ", lc ));
++		} else {
++			/* Here, lc is the match length - MIN_MATCH */
++			code = length_code[lc];
++			send_code( code + LITERALS + 1, ltree ); /* send the length code */
++			extra = extra_lbits[code];
++			if ( extra != 0 ) {
++				lc -= base_length[code];
++				send_bits( lc, extra ); /* send the extra length bits */
++			}
++			dist = d_buf[dx ++ ];
++			/* Here, dist is the match distance - 1 */
++			code = d_code( dist );
++			Assert ( code < D_CODES, "bad d_code" );
++
++			send_code( code, dtree ); /* send the distance code */
++			extra = extra_dbits[code];
++			if ( extra != 0 ) {
++				dist -= base_dist[code];
++				send_bits( dist, extra ); /* send the extra distance bits */
++			}
++		} /* literal or match pair ? */
++		flag >>= 1;
++	} while ( lx < last_lit );
++
++	send_code( END_BLOCK, ltree );
++}
++
++/* ===========================================================================
++* Set the file type to ASCII or BINARY, using a crude approximation:
++* binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise.
++* IN assertion: the fields freq of dyn_ltree are set and the total of all
++* frequencies does not exceed 64K (to fit in an int on 16 bit machines).
++*/
++local void set_file_type()
++{
++	int n = 0;
++	unsigned ascii_freq = 0;
++	unsigned bin_freq = 0;
++	while ( n < 7 ) bin_freq += dyn_ltree[n ++ ].Freq; /* ��ʼ�� */
++	while ( n < 128 ) ascii_freq += dyn_ltree[n ++ ].Freq; /* ��ʼ�� */
++	while ( n < LITERALS ) bin_freq += dyn_ltree[n ++ ].Freq;
++	* file_type = bin_freq > ( ascii_freq >> 2 ) ? BINARY : ASCII; /* �����ļ��򿪷�ʽ */
++	if (* file_type == BINARY && translate_eol ) {
++		warn( "-l used on binary file", "" );
++	}
++}
+diff --git a/lib/gzip/unzip.c b/lib/gzip/unzip.c
+new file mode 100644
+index 0000000..5f9ea66
+--- /dev/null
++++ b/lib/gzip/unzip.c
+@@ -0,0 +1,50 @@
++/* unzip.c -- decompress files in gzip or pkzip format.
++* Copyright (C) 1992-1993 Jean-loup Gailly
++* This is free software; you can redistribute it and/or modify it under the
++* terms of the GNU General Public License, see the file COPYING.
++*
++* The code in this file is derived from the file funzip.c written
++* and put in the public domain by Mark Adler.
++*/
++
++#include "gzip.h"
++
++/* ===========================================================================
++* Unzip in to out. This routine works on both gzip and pkzip files.
++*
++* IN assertions: the buffer inbuf contains already the beginning of
++* the compressed data, from offsets inptr to insize-1 included.
++* The magic header has already been checked. The output buffer is cleared.
++*/
++
++int unzip( void )
++{
++	ulg orig_crc = 0; /* original crc */
++	ulg orig_len = 0; /* original uncompressed length */
++	int n; uch buf[8]; /* extended local header */
++
++	updcrc( NULL, 0 ); /* initialize crc */
++
++	/* Decompress */
++	inflate();
++
++	for ( n = 0; n < 8; n ++) /* Get the crc and original length */
++	{
++		buf[n] = ( uch )get_byte(); /* may cause an error if EOF */
++	}
++
++	orig_crc = LG( buf );
++	orig_len = LG( buf + 4 ); /* Validate decompression */
++
++	if ( orig_crc != updcrc( outbuf, 0 ))
++	{
++		error( "invalid compressed data--crc error" );
++	}
++
++	if ( orig_len != ( ulg )bytes_out )
++	{
++		error( "invalid compressed data--length error" );
++	}
++
++	return 0;
++}
+diff --git a/lib/gzip/util.c b/lib/gzip/util.c
+new file mode 100644
+index 0000000..04395dc
+--- /dev/null
++++ b/lib/gzip/util.c
+@@ -0,0 +1,256 @@
++/* util.c -- utility functions for gzip support
++* Copyright (C) 1992-1993 Jean-loup Gailly
++* This is free software; you can redistribute it and/or modify it under the
++* terms of the GNU General Public License, see the file COPYING.
++*/
++
++//#include <stdlib.h>
++#include "gzip.h"
++
++extern ulg crc_32_tab[]; /* crc table, defined below */
++
++/* ===========================================================================
++* Run a set of bytes through the crc shift register. If s is a NULL
++* pointer, then initialize the crc shift register contents instead.
++* Return the current crc in either case.
++*/
++ulg updcrc( uch * s, unsigned n )
++{
++	register ulg c; /* temporary variable */
++
++	static ulg crc = ( ulg )0xffffffffL; /* shift register contents */
++
++	if ( s == NULL ) {
++		c = 0xffffffffL; /* ��ʼ��crc */
++	} else {
++		c = crc;
++		if ( n ) do {
++			c = crc_32_tab[(( int )c ^ (* s ++)) & 0xff] ^ ( c >> 8 ); /* ����crc */
++		} while (-- n );
++	}
++	crc = c;
++	return c ^ 0xffffffffL; /* (instead of ~c for 64-bit machines) */
++}
++
++/* ===========================================================================
++* Clear input and output buffers
++*/
++void clear_bufs()
++{
++	outcnt = 0;
++	insize = inptr = 0;
++	bytes_in = bytes_out = 0L;
++}
++
++char * unzip_mem_inptr = 0;
++int unzip_mem_insize = 0;
++int unzip_mem_inpos = 0;
++
++/* ===========================================================================
++* Fill the input buffer. This is called only when the buffer is empty.
++*/
++int fill_inbuf( void )
++{
++	int len;
++#undef min
++#define min(a,b) (((int)(a) < (int)(b)) ? (a) : (b))
++	/* Read as much as possible */
++	insize = 0;
++
++	do {
++		len = min( unzip_mem_insize - unzip_mem_inpos, INBUFSIZ - insize );
++		if( len > 0 )
++		{
++			memcpy(( char *)inbuf + insize, & unzip_mem_inptr[unzip_mem_inpos], len );
++			insize += len;
++			unzip_mem_inpos += len;
++		}
++		else
++			break;
++	} while ( insize < INBUFSIZ );
++
++	if ( insize == 0 ) {
++		read_error();
++	}
++	bytes_in += ( ulg )insize;
++	inptr = 1;
++	return inbuf[0];
++}
++
++/* ===========================================================================
++* Write the output buffer outbuf[0..outcnt-1] and update bytes_out.
++* (used for the compressed data only)
++*/
++void flush_outbuf()
++{
++	if ( outcnt == 0 ) return;
++
++	write_buf(( char *)outbuf, outcnt );
++	bytes_out += ( ulg )outcnt;
++	outcnt = 0;
++}
++
++/* ===========================================================================
++* Write the output window window[0..outcnt-1] and update crc and bytes_out.
++* (Used for the decompressed data only.)
++*/
++void flush_window()
++{
++	if ( outcnt == 0 ) return;
++	updcrc( window, outcnt );
++	write_buf(( char *)window, outcnt );
++	bytes_out += ( ulg )outcnt;
++	outcnt = 0;
++}
++
++/* ===========================================================================
++* Does the same as write(), but also handles partial pipe writes and checks
++* for error return.
++*/
++char * zip_mem_outptr;
++int zip_mem_outlen = 0;
++void write_buf( voidp buf, unsigned cnt )
++{
++	memcpy(& zip_mem_outptr[zip_mem_outlen], buf, cnt );
++	zip_mem_outlen += cnt;
++}
++
++/* ========================================================================
++* Error handlers.
++*/
++void error( char * m )
++{
++}
++
++void warn( char * a, char * b )
++{
++}
++
++void read_error()
++{
++}
++
++void write_error()
++{
++}
++
++/* ========================================================================
++* Semi-safe malloc -- never returns NULL.
++*/
++voidp xmalloc ( unsigned size )
++{
++	voidp cp = ( voidp )vmalloc ( size );
++
++	if ( cp == NULL ) error( "out of memory" );
++	return cp;
++}
++
++/* ========================================================================
++* Table of CRC-32's of all single-byte values (made by makecrc.c)
++*/
++ulg crc_32_tab[] = {
++	/* Table of CRC-32's of all single-byte values */
++	0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
++		/* Table of CRC-32's of all single-byte values */
++		0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
++		/* Table of CRC-32's of all single-byte values */
++		0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
++		/* Table of CRC-32's of all single-byte values */
++		0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
++		/* Table of CRC-32's of all single-byte values */
++		0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
++		/* Table of CRC-32's of all single-byte values */
++		0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
++		/* Table of CRC-32's of all single-byte values */
++		0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
++		/* Table of CRC-32's of all single-byte values */
++		0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
++		/* Table of CRC-32's of all single-byte values */
++		0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
++		/* Table of CRC-32's of all single-byte values */
++		0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
++		/* Table of CRC-32's of all single-byte values */
++		0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
++		/* Table of CRC-32's of all single-byte values */
++		0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
++		/* Table of CRC-32's of all single-byte values */
++		0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
++		/* Table of CRC-32's of all single-byte values */
++		0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
++		/* Table of CRC-32's of all single-byte values */
++		0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
++		/* Table of CRC-32's of all single-byte values */
++		0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
++		/* Table of CRC-32's of all single-byte values */
++		0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
++		/* Table of CRC-32's of all single-byte values */
++		0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
++		/* Table of CRC-32's of all single-byte values */
++		0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
++		/* Table of CRC-32's of all single-byte values */
++		0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
++		/* Table of CRC-32's of all single-byte values */
++		0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
++		/* Table of CRC-32's of all single-byte values */
++		0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
++		/* Table of CRC-32's of all single-byte values */
++		0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
++		/* Table of CRC-32's of all single-byte values */
++		0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
++		/* Table of CRC-32's of all single-byte values */
++		0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
++		/* Table of CRC-32's of all single-byte values */
++		0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
++		/* Table of CRC-32's of all single-byte values */
++		0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
++		/* Table of CRC-32's of all single-byte values */
++		0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
++		/* Table of CRC-32's of all single-byte values */
++		0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
++		/* Table of CRC-32's of all single-byte values */
++		0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
++		/* Table of CRC-32's of all single-byte values */
++		0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
++		/* Table of CRC-32's of all single-byte values */
++		0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
++		/* Table of CRC-32's of all single-byte values */
++		0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
++		/* Table of CRC-32's of all single-byte values */
++		0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
++		/* Table of CRC-32's of all single-byte values */
++		0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
++		/* Table of CRC-32's of all single-byte values */
++		0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
++		/* Table of CRC-32's of all single-byte values */
++		0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
++		/* Table of CRC-32's of all single-byte values */
++		0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
++		/* Table of CRC-32's of all single-byte values */
++		0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
++		/* Table of CRC-32's of all single-byte values */
++		0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
++		/* Table of CRC-32's of all single-byte values */
++		0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
++		/* Table of CRC-32's of all single-byte values */
++		0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
++		/* Table of CRC-32's of all single-byte values */
++		0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
++		/* Table of CRC-32's of all single-byte values */
++		0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
++		/* Table of CRC-32's of all single-byte values */
++		0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
++		/* Table of CRC-32's of all single-byte values */
++		0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
++		/* Table of CRC-32's of all single-byte values */
++		0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
++		/* Table of CRC-32's of all single-byte values */
++		0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
++		/* Table of CRC-32's of all single-byte values */
++		0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
++		/* Table of CRC-32's of all single-byte values */
++		0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
++		/* Table of CRC-32's of all single-byte values */
++		0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
++		/* Table of CRC-32's of all single-byte values */
++		0x2d02ef8dL
++};
+diff --git a/lib/gzip/zip.c b/lib/gzip/zip.c
+new file mode 100644
+index 0000000..e923bf8
+--- /dev/null
++++ b/lib/gzip/zip.c
+@@ -0,0 +1,57 @@
++/* zip.c -- compress files to the gzip or pkzip format
++* Copyright (C) 1992-1993 Jean-loup Gailly
++* This is free software; you can redistribute it and/or modify it under the
++* terms of the GNU General Public License, see the file COPYING.
++*/
++#include "gzip.h"
++local ulg crc = 0; /* crc on uncompressed file data */
++/* ===========================================================================
++* Deflate in to out.
++* IN assertions: the input and output buffers are cleared.
++* The variables time_stamp and save_orig_name are initialized.
++*/
++int zip( void )
++{
++	uch flags = 0; /* general purpose bit flags */
++	ush attr = 0; /* ascii/binary flag */
++	ush deflate_flags = 0; /* pkzip -es, -en or -ex equivalent */
++	outcnt = 0; /* Write the header to the gzip file. See algorithm.doc for the format */
++	method = DEFLATED;
++	put_byte( GZIP_MAGIC[0] ); /* magic header */
++	put_byte( GZIP_MAGIC[1] );
++	put_byte( DEFLATED ); /* compression method */
++	put_byte( flags ); /* general flags */
++	put_long( time_stamp ); /* Write deflated file to zip file */
++	crc = updcrc( 0, 0 );
++	bi_init();
++	ct_init(& attr, & method );
++	lm_init( level, & deflate_flags );
++	put_byte(( uch )deflate_flags ); /* extra flags */
++	put_byte( 0 ); /* OS identifier */
++	( void )deflate(); /* Write the crc and uncompressed size */
++	put_long( crc );
++	put_long( isize );
++	flush_outbuf();
++
++	return 0;
++}
++
++char * zip_mem_inptr = NULL;
++int zip_mem_insize = 0;
++int zip_mem_inpos = 0;
++int mem_read( char * buf, unsigned size )
++{
++	int len;
++#define min_1( a, b ) ((( int )( a ) < ( int )( b )) ? ( a ) : ( b ))
++	len = min_1( zip_mem_insize - zip_mem_inpos, size );
++	if( len > 0 )
++	{
++		memcpy( buf, & zip_mem_inptr[zip_mem_inpos], len );
++		crc = updcrc(( uch *)buf, len );
++		isize += ( ulg )len;
++		zip_mem_inpos += len;
++	}
++	else
++		len = - 1;
++	return ( int )len;
++}
+diff --git a/lib/gzip/zipmem.h b/lib/gzip/zipmem.h
+new file mode 100644
+index 0000000..345f892
+--- /dev/null
++++ b/lib/gzip/zipmem.h
+@@ -0,0 +1,9 @@
++#ifndef _ZIP_MEM_H_
++#define _ZIP_MEM_H_
++
++
++int zipmem( char * mem_inptr, int mem_insize, char * mem_outptr );
++
++int unzipmem( char * mem_inptr, int mem_insize, char * mem_outptr );
++
++#endif
+diff --git a/linaro/configs/arndale.conf b/linaro/configs/arndale.conf
+new file mode 100644
+index 0000000..109052f
+--- /dev/null
++++ b/linaro/configs/arndale.conf
+@@ -0,0 +1,66 @@
++CONFIG_KALLSYMS_ALL=y
++CONFIG_PARTITION_ADVANCED=y
++CONFIG_BSD_DISKLABEL=y
++CONFIG_SOLARIS_X86_PARTITION=y
++CONFIG_ARCH_EXYNOS=y
++CONFIG_S3C_LOWLEVEL_UART_PORT=2
++CONFIG_ARCH_EXYNOS5=y
++# CONFIG_EXYNOS_ATAGS is not set
++CONFIG_MACH_EXYNOS4_DT=y
++CONFIG_VMSPLIT_2G=y
++CONFIG_NR_CPUS=2
++CONFIG_HIGHMEM=y
++# CONFIG_COMPACTION is not set
++CONFIG_ARM_APPENDED_DTB=y
++CONFIG_ARM_ATAG_DTB_COMPAT=y
++CONFIG_CMDLINE="root=/dev/ram0 rw ramdisk=8192 initrd=0x41000000,8M console=ttySAC1,115200 init= mem=256M"
++CONFIG_CPU_FREQ_GOV_USERSPACE=y
++CONFIG_VFP=y
++CONFIG_NEON=y
++CONFIG_PM_RUNTIME=y
++CONFIG_BLK_DEV_LOOP=y
++CONFIG_BLK_DEV_SD=y
++CONFIG_CHR_DEV_SG=y
++CONFIG_ATA=y
++CONFIG_SATA_AHCI_PLATFORM=y
++CONFIG_SATA_EXYNOS=y
++CONFIG_AX88796=y
++CONFIG_AX88796_93CX6=y
++CONFIG_INPUT_EVDEV=y
++CONFIG_KEYBOARD_GPIO=y
++CONFIG_INPUT_TOUCHSCREEN=y
++CONFIG_SERIAL_8250=y
++CONFIG_SERIAL_SAMSUNG=y
++CONFIG_SERIAL_SAMSUNG_CONSOLE=y
++CONFIG_HW_RANDOM=y
++CONFIG_I2C=y
++CONFIG_I2C_S3C2410=y
++CONFIG_THERMAL=y
++CONFIG_CPU_THERMAL=y
++CONFIG_EXYNOS_THERMAL=y
++CONFIG_MFD_SEC_CORE=y
++CONFIG_REGULATOR=y
++CONFIG_REGULATOR_FIXED_VOLTAGE=y
++CONFIG_REGULATOR_S5M8767=y
++CONFIG_DRM=y
++CONFIG_DRM_LOAD_EDID_FIRMWARE=y
++CONFIG_DRM_EXYNOS=y
++CONFIG_DRM_EXYNOS_DMABUF=y
++CONFIG_DRM_EXYNOS_HDMI=y
++CONFIG_FRAMEBUFFER_CONSOLE=y
++CONFIG_LOGO=y
++CONFIG_MMC=y
++CONFIG_MMC_UNSAFE_RESUME=y
++CONFIG_MMC_DW=y
++CONFIG_MMC_DW_IDMAC=y
++CONFIG_MMC_DW_EXYNOS=y
++CONFIG_RTC_CLASS=y
++CONFIG_RTC_DRV_S3C=y
++CONFIG_DEBUG_KERNEL=y
++CONFIG_DETECT_HUNG_TASK=y
++CONFIG_DEBUG_RT_MUTEXES=y
++CONFIG_DEBUG_SPINLOCK=y
++CONFIG_DEBUG_INFO=y
++CONFIG_RCU_CPU_STALL_TIMEOUT=60
++CONFIG_DEBUG_USER=y
++CONFIG_TUN=y
+diff --git a/linaro/configs/big-LITTLE-IKS.conf b/linaro/configs/big-LITTLE-IKS.conf
+new file mode 100644
+index 0000000..b067fde
+--- /dev/null
++++ b/linaro/configs/big-LITTLE-IKS.conf
+@@ -0,0 +1,5 @@
++CONFIG_BIG_LITTLE=y
++CONFIG_BL_SWITCHER=y
++CONFIG_ARM_DT_BL_CPUFREQ=y
++CONFIG_ARM_VEXPRESS_BL_CPUFREQ=y
++CONFIG_CPU_FREQ_GOV_USERSPACE=y
+diff --git a/linaro/configs/bigendian.conf b/linaro/configs/bigendian.conf
+new file mode 100644
+index 0000000..6a10202
+--- /dev/null
++++ b/linaro/configs/bigendian.conf
+@@ -0,0 +1,4 @@
++CONFIG_CPU_BIG_ENDIAN=y
++CONFIG_CPU_ENDIAN_BE8=y
++# CONFIG_VIRTUALIZATION is not set
++# CONFIG_MMC_DW_IDMAC is not set
+diff --git a/linaro/configs/distribution.conf b/linaro/configs/distribution.conf
+new file mode 100644
+index 0000000..729b9b8
+--- /dev/null
++++ b/linaro/configs/distribution.conf
+@@ -0,0 +1,49 @@
++# CONFIG_LOCALVERSION_AUTO is not set
++CONFIG_CGROUPS=y
++# CONFIG_COMPAT_BRK is not set
++CONFIG_DEFAULT_MMAP_MIN_ADDR=32768
++CONFIG_SECCOMP=y
++CONFIG_CC_STACKPROTECTOR=y
++CONFIG_SYN_COOKIES=y
++CONFIG_IPV6=y
++CONFIG_NETLABEL=y
++CONFIG_BRIDGE_NETFILTER=y
++CONFIG_NF_CONNTRACK=m
++CONFIG_NETFILTER_XT_CONNMARK=m
++CONFIG_NETFILTER_XT_MARK=m
++CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
++CONFIG_NF_CONNTRACK_IPV4=m
++CONFIG_NF_NAT_IPV4=m
++CONFIG_IP_NF_IPTABLES=m
++CONFIG_IP_NF_FILTER=m
++CONFIG_IP_NF_MANGLE=m
++CONFIG_NF_CONNTRACK_IPV6=m
++CONFIG_NF_NAT_IPV6=m
++CONFIG_IP6_NF_IPTABLES=m
++CONFIG_IP6_NF_FILTER=m
++CONFIG_IP6_NF_MANGLE=m
++CONFIG_BRIDGE_NF_EBTABLES=m
++CONFIG_BRIDGE_EBT_MARK_T=m
++CONFIG_BRIDGE=m
++CONFIG_TUN=y
++CONFIG_DEVTMPFS=y
++CONFIG_DEVTMPFS_MOUNT=y
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_SIZE=65536
++CONFIG_INPUT_MISC=y
++CONFIG_INPUT_UINPUT=y
++# CONFIG_DEVKMEM is not set
++CONFIG_FRAMEBUFFER_CONSOLE=y
++CONFIG_AUTOFS4_FS=y
++CONFIG_TMPFS_POSIX_ACL=y
++CONFIG_STRICT_DEVMEM=y
++CONFIG_SECURITY=y
++CONFIG_LSM_MMAP_MIN_ADDR=0
++CONFIG_SECURITY_SELINUX=y
++CONFIG_SECURITY_SMACK=y
++CONFIG_SECURITY_APPARMOR=y
++CONFIG_DEFAULT_SECURITY_APPARMOR=y
++CONFIG_HUGETLBFS=y
++CONFIG_HUGETLB_PAGE=y
++CONFIG_TRANSPARENT_HUGEPAGE=y
++CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y
+diff --git a/linaro/configs/kvm-guest.conf b/linaro/configs/kvm-guest.conf
+new file mode 100644
+index 0000000..00e84a3
+--- /dev/null
++++ b/linaro/configs/kvm-guest.conf
+@@ -0,0 +1,11 @@
++CONFIG_BALLOON_COMPACTION=y
++CONFIG_VIRTIO_BLK=y
++CONFIG_VIRTIO_NET=y
++CONFIG_HVC_DRIVER=y
++CONFIG_VIRTIO_CONSOLE=y
++CONFIG_VIRTIO=y
++CONFIG_VIRTIO_BALLOON=y
++CONFIG_VIRTIO_MMIO=y
++CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y
++CONFIG_VIRTUALIZATION=y
++# CONFIG_THUMB2_KERNEL is not set
+diff --git a/linaro/configs/kvm-host.conf b/linaro/configs/kvm-host.conf
+new file mode 100644
+index 0000000..21a40e0
+--- /dev/null
++++ b/linaro/configs/kvm-host.conf
+@@ -0,0 +1,11 @@
++CONFIG_VIRTUALIZATION=y
++CONFIG_ARM_LPAE=y
++CONFIG_ARM_VIRT_EXT=y
++CONFIG_HAVE_KVM_IRQCHIP=y
++CONFIG_KVM_ARM_HOST=y
++CONFIG_KVM_ARM_MAX_VCPUS=4
++CONFIG_KVM_ARM_TIMER=y
++CONFIG_KVM_ARM_VGIC=y
++CONFIG_KVM_MMIO=y
++CONFIG_KVM=y
++CONFIG_BLK_DEV_NBD=m
+diff --git a/linaro/configs/linaro-base.conf b/linaro/configs/linaro-base.conf
+new file mode 100644
+index 0000000..0a1d7bc
+--- /dev/null
++++ b/linaro/configs/linaro-base.conf
+@@ -0,0 +1,129 @@
++CONFIG_SYSVIPC=y
++CONFIG_POSIX_MQUEUE=y
++CONFIG_BSD_PROCESS_ACCT=y
++CONFIG_IKCONFIG=y
++CONFIG_IKCONFIG_PROC=y
++CONFIG_LOG_BUF_SHIFT=16
++CONFIG_BLK_DEV_INITRD=y
++CONFIG_EMBEDDED=y
++CONFIG_HOTPLUG=y
++CONFIG_PERF_EVENTS=y
++CONFIG_SLAB=y
++CONFIG_PROFILING=y
++CONFIG_OPROFILE=y
++CONFIG_MODULES=y
++CONFIG_MODULE_UNLOAD=y
++CONFIG_NO_HZ=y
++CONFIG_HIGH_RES_TIMERS=y
++CONFIG_SMP=y
++CONFIG_SCHED_MC=y
++CONFIG_SCHED_SMT=y
++CONFIG_THUMB2_KERNEL=y
++CONFIG_AEABI=y
++# CONFIG_OABI_COMPAT is not set
++CONFIG_CPU_FREQ=y
++CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
++CONFIG_CPU_IDLE=y
++CONFIG_BINFMT_MISC=y
++CONFIG_MD=y
++CONFIG_BLK_DEV_DM=y
++CONFIG_NET=y
++CONFIG_PACKET=y
++CONFIG_UNIX=y
++CONFIG_XFRM_USER=y
++CONFIG_NET_KEY=y
++CONFIG_NET_KEY_MIGRATE=y
++CONFIG_INET=y
++CONFIG_IP_MULTICAST=y
++CONFIG_IP_PNP=y
++CONFIG_IP_PNP_DHCP=y
++CONFIG_IP_PNP_BOOTP=y
++CONFIG_IP_PNP_RARP=y
++# CONFIG_INET_LRO is not set
++CONFIG_NETFILTER=y
++CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
++CONFIG_CONNECTOR=y
++CONFIG_MTD=y
++CONFIG_MTD_CMDLINE_PARTS=y
++CONFIG_MTD_BLOCK=y
++CONFIG_MTD_OOPS=y
++CONFIG_MTD_CFI=y
++CONFIG_MTD_CFI_INTELEXT=y
++CONFIG_MTD_NAND=y
++CONFIG_NETDEVICES=y
++CONFIG_EXT2_FS=y
++CONFIG_EXT3_FS=y
++CONFIG_EXT4_FS=y
++CONFIG_BTRFS_FS=y
++CONFIG_QUOTA=y
++CONFIG_QFMT_V2=y
++CONFIG_MSDOS_FS=y
++CONFIG_VFAT_FS=y
++CONFIG_TMPFS=y
++CONFIG_ECRYPT_FS=y
++CONFIG_JFFS2_FS=y
++CONFIG_JFFS2_SUMMARY=y
++CONFIG_JFFS2_FS_XATTR=y
++CONFIG_JFFS2_COMPRESSION_OPTIONS=y
++CONFIG_JFFS2_LZO=y
++CONFIG_JFFS2_RUBIN=y
++CONFIG_CRAMFS=y
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++# CONFIG_NFS_V2 is not set
++CONFIG_NFS_V3=y
++CONFIG_NFS_V3_ACL=y
++CONFIG_NFS_V4=y
++CONFIG_ROOT_NFS=y
++CONFIG_NLS_CODEPAGE_437=y
++CONFIG_NLS_ISO8859_1=y
++CONFIG_PRINTK_TIME=y
++CONFIG_MAGIC_SYSRQ=y
++CONFIG_DEBUG_FS=y
++CONFIG_SCHEDSTATS=y
++CONFIG_TIMER_STATS=y
++CONFIG_KEYS=y
++CONFIG_CRYPTO_MICHAEL_MIC=y
++CONFIG_CRC_CCITT=y
++CONFIG_CRC_T10DIF=y
++CONFIG_CRC_ITU_T=y
++CONFIG_CRC7=y
++CONFIG_HW_PERF_EVENTS=y
++CONFIG_FUNCTION_TRACER=y
++CONFIG_ENABLE_DEFAULT_TRACERS=y
++CONFIG_PROC_DEVICETREE=y
++CONFIG_JUMP_LABEL=y
++CONFIG_STRICT_DEVMEM=y
++CONFIG_KGDB=y
++CONFIG_KGDB_TESTS=y
++CONFIG_OF_IDLE_STATES=y
++CONFIG_FTRACE=y
++CONFIG_FUNCTION_TRACER=y
++CONFIG_FTRACE_SYSCALLS=y
++CONFIG_STACK_TRACER=y
++CONFIG_FUNCTION_PROFILER=y
++CONFIG_MAILBOX=y
++CONFIG_AUDIT=y
++CONFIG_NF_CONNTRACK_SECMARK=y
++CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y
++CONFIG_NETFILTER_XT_TARGET_SECMARK=y
++CONFIG_IP_NF_SECURITY=y
++CONFIG_SECURITY=y
++CONFIG_SECURITY_NETWORK=y
++CONFIG_LSM_MMAP_MIN_ADDR=4096
++CONFIG_SECURITY_SELINUX=y
++CONFIG_EXT4_FS_SECURITY=y
++CONFIG_BLK_DEV_LOOP=y
++CONFIG_DEBUG_INFO=y
++CONFIG_FANOTIFY=y
++CONFIG_RCU_TORTURE_TEST=m
++CONFIG_RCU_TORTURE_TEST_RUNNABLE=n
++CONFIG_CORESIGHT=y
++CONFIG_CORESIGHT_LINKS_AND_SINKS=y
++CONFIG_CORESIGHT_SOURCE_ETM=y
++
++# enable ZRAM features
++CONFIG_ZPOOL=y
++CONFIG_ZSMALLOC=y
++CONFIG_ZRAM=y
++CONFIG_ZRAM_LZ4_COMPRESS=y
+diff --git a/linaro/configs/omap4.conf b/linaro/configs/omap4.conf
+new file mode 100644
+index 0000000..d0a2b80
+--- /dev/null
++++ b/linaro/configs/omap4.conf
+@@ -0,0 +1,196 @@
++CONFIG_EXPERT=y
++CONFIG_KPROBES=y
++CONFIG_MODULE_FORCE_LOAD=y
++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_GPIO_PCA953X=y
++CONFIG_OMAP_RESET_CLOCKS=y
++CONFIG_OMAP_MUX_DEBUG=y
++CONFIG_ARCH_OMAP3=y
++CONFIG_ARCH_OMAP4=y
++CONFIG_ARCH_OMAP2PLUS=y
++CONFIG_SOC_OMAP5=y
++# CONFIG_ARCH_OMAP2 is not set
++CONFIG_ARCH_VEXPRESS_CA9X4=y
++CONFIG_ARM_THUMBEE=y
++CONFIG_ARM_ERRATA_411920=y
++CONFIG_NR_CPUS=2
++CONFIG_ZBOOT_ROM_TEXT=0x0
++CONFIG_ZBOOT_ROM_BSS=0x0
++CONFIG_CMDLINE="root=/dev/mmcblk0p2 rootwait console=ttyO2,115200"
++CONFIG_KEXEC=y
++CONFIG_PM_DEBUG=y
++CONFIG_CAN=m
++CONFIG_CAN_C_CAN=m
++CONFIG_CAN_C_CAN_PLATFORM=m
++CONFIG_BT=m
++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_MAC80211_RC_PID=y
++CONFIG_MAC80211_RC_DEFAULT_PID=y
++CONFIG_CMA=y
++CONFIG_MTD_NAND_OMAP2=y
++CONFIG_MTD_ONENAND=y
++CONFIG_MTD_ONENAND_VERIFY_WRITE=y
++CONFIG_MTD_ONENAND_OMAP2=y
++CONFIG_MTD_UBI=y
++CONFIG_BLK_DEV_LOOP=y
++CONFIG_BLK_DEV_RAM_SIZE=16384
++CONFIG_SENSORS_TSL2550=m
++CONFIG_SENSORS_LIS3_I2C=m
++CONFIG_SCSI=y
++CONFIG_BLK_DEV_SD=y
++CONFIG_SCSI_MULTI_LUN=y
++CONFIG_SCSI_SCAN_ASYNC=y
++CONFIG_KS8851=y
++CONFIG_KS8851_MLL=y
++CONFIG_SMC91X=y
++CONFIG_SMSC911X=y
++CONFIG_TI_CPSW=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_LIBERTAS=m
++CONFIG_LIBERTAS_USB=m
++CONFIG_LIBERTAS_SDIO=m
++CONFIG_LIBERTAS_DEBUG=y
++CONFIG_INPUT_JOYDEV=y
++CONFIG_INPUT_EVDEV=y
++CONFIG_KEYBOARD_GPIO=y
++CONFIG_KEYBOARD_MATRIX=m
++CONFIG_KEYBOARD_TWL4030=y
++CONFIG_INPUT_TOUCHSCREEN=y
++CONFIG_TOUCHSCREEN_ADS7846=y
++CONFIG_INPUT_TWL4030_PWRBUTTON=y
++CONFIG_VT_HW_CONSOLE_BINDING=y
++# CONFIG_LEGACY_PTYS is not set
++CONFIG_SERIAL_8250=y
++CONFIG_SERIAL_8250_CONSOLE=y
++CONFIG_SERIAL_8250_NR_UARTS=32
++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_AMBA_PL011=y
++CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
++CONFIG_SERIAL_OMAP=y
++CONFIG_SERIAL_OMAP_CONSOLE=y
++CONFIG_HW_RANDOM=y
++CONFIG_I2C_CHARDEV=y
++CONFIG_SPI=y
++CONFIG_SPI_OMAP24XX=y
++CONFIG_PINCTRL_SINGLE=y
++CONFIG_DEBUG_GPIO=y
++CONFIG_GPIO_SYSFS=y
++CONFIG_GPIO_TWL4030=y
++CONFIG_W1=y
++CONFIG_SENSORS_LM75=m
++CONFIG_WATCHDOG=y
++CONFIG_OMAP_WATCHDOG=y
++CONFIG_TWL4030_WATCHDOG=y
++CONFIG_MFD_TPS65217=y
++CONFIG_MFD_TPS65910=y
++CONFIG_TWL6040_CORE=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_OMAP2_DSS=m
++CONFIG_OMAP2_DSS_RFBI=y
++CONFIG_OMAP2_DSS_SDI=y
++CONFIG_OMAP2_DSS_DSI=y
++CONFIG_FB_OMAP2=m
++CONFIG_PANEL_GENERIC_DPI=m
++CONFIG_PANEL_TFP410=m
++CONFIG_PANEL_SHARP_LS037V7DW01=m
++CONFIG_PANEL_NEC_NL8048HL11_01B=m
++CONFIG_PANEL_TAAL=m
++CONFIG_PANEL_TPO_TD043MTEA1=m
++CONFIG_PANEL_ACX565AKM=m
++CONFIG_BACKLIGHT_LCD_SUPPORT=y
++CONFIG_LCD_CLASS_DEVICE=y
++CONFIG_LCD_PLATFORM=y
++CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
++CONFIG_FONTS=y
++CONFIG_FONT_8x8=y
++CONFIG_FONT_8x16=y
++CONFIG_LOGO=y
++CONFIG_SOUND=m
++CONFIG_SND=m
++CONFIG_SND_VERBOSE_PRINTK=y
++CONFIG_SND_DEBUG=y
++CONFIG_SND_USB_AUDIO=m
++CONFIG_SND_SOC=m
++CONFIG_SND_OMAP_SOC=m
++CONFIG_SND_OMAP_SOC_OMAP_TWL4030=m
++CONFIG_SND_OMAP_SOC_OMAP_ABE_TWL6040=m
++CONFIG_SND_OMAP_SOC_OMAP3_PANDORA=m
++CONFIG_USB=y
++CONFIG_USB_DEBUG=y
++CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
++CONFIG_USB_MON=y
++CONFIG_USB_EHCI_HCD=y
++CONFIG_USB_OHCI_HCD=y
++CONFIG_USB_WDM=y
++CONFIG_USB_STORAGE=y
++CONFIG_USB_TEST=y
++CONFIG_USB_PHY=y
++CONFIG_NOP_USB_XCEIV=y
++CONFIG_USB_GADGET=y
++CONFIG_USB_GADGET_DEBUG=y
++CONFIG_USB_GADGET_DEBUG_FILES=y
++CONFIG_USB_GADGET_DEBUG_FS=y
++CONFIG_USB_ZERO=m
++CONFIG_MMC=y
++CONFIG_MMC_UNSAFE_RESUME=y
++CONFIG_SDIO_UART=y
++CONFIG_MMC_ARMMMCI=y
++CONFIG_MMC_OMAP=y
++CONFIG_MMC_OMAP_HS=y
++CONFIG_NEW_LEDS=y
++CONFIG_LEDS_CLASS=y
++CONFIG_LEDS_GPIO=y
++CONFIG_LEDS_TRIGGERS=y
++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
++CONFIG_RTC_CLASS=y
++CONFIG_RTC_DRV_TWL92330=y
++CONFIG_RTC_DRV_TWL4030=y
++CONFIG_RTC_DRV_OMAP=y
++CONFIG_DMADEVICES=y
++CONFIG_DMA_OMAP=y
++# CONFIG_EXT3_FS_XATTR is not set
++CONFIG_UBIFS_FS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V3_ACL=y
++CONFIG_NFS_V4=y
++CONFIG_ROOT_NFS=y
++# CONFIG_DEBUG_BUGVERBOSE is not set
++CONFIG_DEBUG_INFO=y
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++CONFIG_LIBCRC32C=y
++# CONFIG_CPU_FREQ is not set
+diff --git a/linaro/configs/preempt-rt.conf b/linaro/configs/preempt-rt.conf
+new file mode 100644
+index 0000000..7c6594f
+--- /dev/null
++++ b/linaro/configs/preempt-rt.conf
+@@ -0,0 +1,3 @@
++CONFIG_PREEMPT=y
++CONFIG_PREEMPT_RT_FULL=y
++# CONFIG_CPU_FREQ is not set
+diff --git a/linaro/configs/vexpress64.conf b/linaro/configs/vexpress64.conf
+new file mode 100644
+index 0000000..cb5d016
+--- /dev/null
++++ b/linaro/configs/vexpress64.conf
+@@ -0,0 +1,56 @@
++CONFIG_ARCH_VEXPRESS=y
++CONFIG_SMP=y
++CONFIG_NR_CPUS=8
++CONFIG_CMDLINE="console=ttyAMA0"
++CONFIG_COMPAT=y
++CONFIG_SMC91X=y
++CONFIG_INPUT_EVDEV=y
++CONFIG_SERIO_AMBAKMI=y
++CONFIG_SERIAL_AMBA_PL011=y
++CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
++# CONFIG_SERIO_I8042 is not set
++CONFIG_FB=y
++CONFIG_FB_ARMCLCD=y
++CONFIG_FRAMEBUFFER_CONSOLE=y
++# CONFIG_VGA_CONSOLE is not set
++CONFIG_LOGO=y
++# CONFIG_LOGO_LINUX_MONO is not set
++# CONFIG_LOGO_LINUX_VGA16 is not set
++CONFIG_MMC=y
++CONFIG_MMC_ARMMMCI=y
++CONFIG_RTC_CLASS=y
++CONFIG_RTC_DRV_PL031=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V3=y
++CONFIG_NFS_V3_ACL=y
++CONFIG_NFS_V4=y
++CONFIG_ROOT_NFS=y
++CONFIG_VIRTIO=y
++CONFIG_VIRTIO_BLK=y
++CONFIG_VIRTIO_MMIO=y
++CONFIG_REGULATOR=y
++CONFIG_REGULATOR_FIXED_VOLTAGE=y
++CONFIG_CMA=y
++CONFIG_DMA_CMA=y
++CONFIG_COMMON_CLK_SCPI=y
++CONFIG_SMSC911X=y
++CONFIG_I2C=y
++CONFIG_ARM_MHU_MBOX=y
++CONFIG_ARM_SCPI_PROTOCOL=y
++CONFIG_USB_HIDDEV=y
++CONFIG_SCSI=y
++CONFIG_BLK_DEV_SD=y
++CONFIG_USB_STORAGE=y
++CONFIG_USB=y
++CONFIG_USB_ULPI=y
++CONFIG_USB_EHCI_HCD=y
++CONFIG_USB_EHCI_HCD_SYNOPSYS=y
++CONFIG_USB_OHCI_HCD=y
++CONFIG_USB_PHY=y
++CONFIG_USB_ISP1301=y
++CONFIG_PM_OPP=y
++CONFIG_GENERIC_CPUFREQ_CPU0=y
++CONFIG_ARM_BIG_LITTLE_CPUFREQ=y
++CONFIG_ARM_DT_BL_CPUFREQ=y
++CONFIG_ARM64_CPUIDLE=y
++CONFIG_ARM64_CRYPTO=y
+diff --git a/mm/cma.c b/mm/cma.c
+index 8e9ec13..cc14aea 100644
+--- a/mm/cma.c
++++ b/mm/cma.c
+@@ -46,6 +46,9 @@ static struct cma cma_areas[MAX_CMA_AREAS];
+ static unsigned cma_area_count;
+ static DEFINE_MUTEX(cma_mutex);
+ 
++#define BITMAP_SIZE   16384
++static char bitmap_buf[BITMAP_SIZE];
++
+ phys_addr_t cma_get_base(struct cma *cma)
+ {
+ 	return PFN_PHYS(cma->base_pfn);
+@@ -89,15 +92,18 @@ static void cma_clear_bitmap(struct cma *cma, unsigned long pfn, int count)
+ static int __init cma_activate_area(struct cma *cma)
+ {
+ 	int bitmap_size = BITS_TO_LONGS(cma_bitmap_maxno(cma)) * sizeof(long);
++#ifdef CONFIG_CMA_MEM_SHARED
+ 	unsigned long base_pfn = cma->base_pfn, pfn = base_pfn;
+ 	unsigned i = cma->count >> pageblock_order;
+ 	struct zone *zone;
++#endif
+ 
+ 	cma->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
+ 
+ 	if (!cma->bitmap)
+ 		return -ENOMEM;
+ 
++#ifdef CONFIG_CMA_MEM_SHARED
+ 	WARN_ON_ONCE(!pfn_valid(pfn));
+ 	zone = page_zone(pfn_to_page(pfn));
+ 
+@@ -118,14 +124,16 @@ static int __init cma_activate_area(struct cma *cma)
+ 		}
+ 		init_cma_reserved_pageblock(pfn_to_page(base_pfn));
+ 	} while (--i);
+-
++#endif
+ 	mutex_init(&cma->lock);
+ 	return 0;
+ 
++#ifdef CONFIG_CMA_MEM_SHARED
+ err:
+ 	kfree(cma->bitmap);
+ 	cma->count = 0;
+ 	return -EINVAL;
++#endif
+ }
+ 
+ static int __init cma_init_reserved_areas(void)
+@@ -329,6 +337,95 @@ err:
+ 	return ret;
+ }
+ 
++int hicma_saveable_page(unsigned long pfn)
++{
++	int i;
++	int bitmap_no;
++
++	for (i = 0; i < cma_area_count; i++) {
++		if ((pfn >= cma_areas[i].base_pfn) &&
++			(pfn < (cma_areas[i].base_pfn + cma_areas[i].count))) {
++			bitmap_no = (pfn - cma_areas[i].base_pfn) >> cma_areas[i].order_per_bit;
++			if (test_bit(bitmap_no, cma_areas[i].bitmap)) {
++				return 1;
++			}
++		}
++	}
++	return 0;
++}
++
++int hicma_page_free(unsigned long pfn)
++{
++	int i;
++	int bitmap_no;
++
++	for (i = 0; i < cma_area_count; i++) {
++		if ((pfn >= cma_areas[i].base_pfn) &&
++			(pfn < (cma_areas[i].base_pfn + cma_areas[i].count))) {
++			bitmap_no = (pfn - cma_areas[i].base_pfn) >> cma_areas[i].order_per_bit;
++			if (test_bit(bitmap_no, cma_areas[i].bitmap)) {
++				return 0;
++			} else {
++				return 1;
++			}
++		}
++	}
++	return 0;
++}
++
++EXPORT_SYMBOL(hicma_page_free);
++/*
++ ** bitmap_find_next_zero_area_best - find a contiguous aligned zero area closest
++ ** to nr
++ ** @map: The address to base the search on
++ ** @size: The bitmap size in bits
++ ** @start: The bitnumber to start searching at
++ ** @nr: The number of zeroed bits we're looking for
++ ** @align_mask: Alignment mask for zero area
++ **
++ ** The @align_mask should be one less than a power of 2; the effect is that
++ ** the bit offset of all zero areas this function finds is multiples of that
++ ** power of 2. A @align_mask of 0 means no alignment is required.
++ **/
++unsigned long bitmap_find_next_zero_area_best(unsigned long *map,
++					      unsigned long size,
++					      unsigned long start,
++					      unsigned int nr,
++					      unsigned long align_mask)
++{
++	unsigned long index, end, i;
++	unsigned long best = size + 1, len = -1;
++
++again:
++	index = find_next_zero_bit(map, size, start);
++
++	/* Align allocation */
++	index = __ALIGN_MASK(index, align_mask);
++	end = index + nr;
++	if (end > size)
++		goto out;
++	i = find_next_bit(map, size, index);
++	if (i < end) {
++		start = i + 1;
++		goto again;
++	}
++
++	/*  more suitable than last  */
++	if ((i - index) < len) {
++		len = i - index;
++		best = index;
++	}
++
++	/* traverse all the bitmap */
++	if (i < size) {
++		start = i + 1;
++		goto again;
++	}
++
++out:
++	return best;
++}
++
+ /**
+  * cma_alloc() - allocate pages from contiguous area
+  * @cma:   Contiguous memory region for which the allocation is performed.
+@@ -342,8 +439,17 @@ struct page *cma_alloc(struct cma *cma, int count, unsigned int align)
+ {
+ 	unsigned long mask, pfn, start = 0;
+ 	unsigned long bitmap_maxno, bitmap_no, bitmap_count;
++#ifdef CONFIG_CMA_MEM_SHARED
+ 	struct page *page = NULL;
++#endif
+ 	int ret;
++	int len;
++
++	/*
++	 * force align to 4KBtytes start, to minimize cma fragmentation
++	 * but needs to fix later.
++	 */
++	align = 0;
+ 
+ 	if (!cma || !cma->count)
+ 		return NULL;
+@@ -360,11 +466,19 @@ struct page *cma_alloc(struct cma *cma, int count, unsigned int align)
+ 
+ 	for (;;) {
+ 		mutex_lock(&cma->lock);
++#ifdef CONFIG_CMA_MEM_SHARED
+ 		bitmap_no = bitmap_find_next_zero_area(cma->bitmap,
+ 				bitmap_maxno, start, bitmap_count, mask);
++#else
++		bitmap_no = bitmap_find_next_zero_area_best(cma->bitmap,
++				bitmap_maxno, start, bitmap_count, mask);
++#endif
+ 		if (bitmap_no >= bitmap_maxno) {
+ 			mutex_unlock(&cma->lock);
+-			break;
++#ifndef CONFIG_CMA_MEM_SHARED
++			ret = -ENOMEM;
++#endif
++			goto error;
+ 		}
+ 		bitmap_set(cma->bitmap, bitmap_no, bitmap_count);
+ 		/*
+@@ -375,6 +489,7 @@ struct page *cma_alloc(struct cma *cma, int count, unsigned int align)
+ 		mutex_unlock(&cma->lock);
+ 
+ 		pfn = cma->base_pfn + (bitmap_no << cma->order_per_bit);
++#ifdef CONFIG_CMA_MEM_SHARED
+ 		mutex_lock(&cma_mutex);
+ 		ret = alloc_contig_range(pfn, pfn + count, MIGRATE_CMA);
+ 		mutex_unlock(&cma_mutex);
+@@ -385,16 +500,36 @@ struct page *cma_alloc(struct cma *cma, int count, unsigned int align)
+ 
+ 		cma_clear_bitmap(cma, pfn, count);
+ 		if (ret != -EBUSY)
+-			break;
+-
++			goto error;
++#else
++		break;
++#endif
+ 		pr_debug("%s(): memory range at %p is busy, retrying\n",
+ 			 __func__, pfn_to_page(pfn));
+ 		/* try again with a bit different memory target */
+ 		start = bitmap_no + mask + 1;
+ 	}
+-
++#ifdef CONFIG_CMA_MEM_SHARED
+ 	pr_debug("%s(): returned %p\n", __func__, page);
+ 	return page;
++#else
++	pr_debug("%s(): returned %p\n", __func__, pfn_to_page(pfn));
++	return pfn_to_page(pfn);
++#endif
++error:
++	if (ret != -EINTR) {
++		memset(bitmap_buf, 0, sizeof(bitmap_buf));
++		len = bitmap_scnlistprintf(bitmap_buf, 16384 - 2, cma->bitmap,
++			cma->count);
++		bitmap_buf[len++] = '\n';
++		bitmap_buf[len] = '\0';
++		pr_warn("cma area total:%lu pages\n", cma->count);
++		pr_warn("alloc %d failed: %d\n", count, ret);
++		pr_warn("bitmap: %s\n", bitmap_buf);
++	} else {
++		pr_warn("Interrupted system call!\n");
++	}
++	return NULL;
+ }
+ 
+ /**
+@@ -423,7 +558,11 @@ bool cma_release(struct cma *cma, struct page *pages, int count)
+ 
+ 	VM_BUG_ON(pfn + count > cma->base_pfn + cma->count);
+ 
++#ifdef CONFIG_CMA_MEM_SHARED
++	mutex_lock(&cma_mutex);
+ 	free_contig_range(pfn, count);
++	mutex_unlock(&cma_mutex);
++#endif
+ 	cma_clear_bitmap(cma, pfn, count);
+ 
+ 	return true;
+diff --git a/mm/gup.c b/mm/gup.c
+index 377a5a7..bef4bb0 100644
+--- a/mm/gup.c
++++ b/mm/gup.c
+@@ -32,6 +32,16 @@ static struct page *no_page_table(struct vm_area_struct *vma,
+ 	return NULL;
+ }
+ 
++/*
++ * FOLL_FORCE can write to even unwritable pte's, but only
++ * after we've gone through a COW cycle and they are dirty.
++ */
++static inline bool can_follow_write_pte(pte_t pte, unsigned int flags)
++{
++	return pte_write(pte) ||
++		((flags & FOLL_FORCE) && (flags & FOLL_COW) && pte_dirty(pte));
++}
++
+ static struct page *follow_page_pte(struct vm_area_struct *vma,
+ 		unsigned long address, pmd_t *pmd, unsigned int flags)
+ {
+@@ -66,7 +76,7 @@ retry:
+ 	}
+ 	if ((flags & FOLL_NUMA) && pte_numa(pte))
+ 		goto no_page;
+-	if ((flags & FOLL_WRITE) && !pte_write(pte)) {
++	if ((flags & FOLL_WRITE) && !can_follow_write_pte(pte, flags)) {
+ 		pte_unmap_unlock(ptep, ptl);
+ 		return NULL;
+ 	}
+@@ -315,7 +325,7 @@ static int faultin_page(struct task_struct *tsk, struct vm_area_struct *vma,
+ 	 * reCOWed by userspace write).
+ 	 */
+ 	if ((ret & VM_FAULT_WRITE) && !(vma->vm_flags & VM_WRITE))
+-		*flags &= ~FOLL_WRITE;
++		*flags |= FOLL_COW;
+ 	return 0;
+ }
+ 
+diff --git a/mm/hugetlb.c b/mm/hugetlb.c
+index da8fa4e..77c8d03 100644
+--- a/mm/hugetlb.c
++++ b/mm/hugetlb.c
+@@ -855,6 +855,31 @@ struct hstate *size_to_hstate(unsigned long size)
+ 	return NULL;
+ }
+ 
++/*
++ * Test to determine whether the hugepage is "active/in-use" (i.e. being linked
++ * to hstate->hugepage_activelist.)
++ *
++ * This function can be called for tail pages, but never returns true for them.
++ */
++bool page_huge_active(struct page *page)
++{
++	VM_BUG_ON_PAGE(!PageHuge(page), page);
++	return PageHead(page) && PagePrivate(&page[1]);
++}
++
++/* never called for tail page */
++static void set_page_huge_active(struct page *page)
++{
++	VM_BUG_ON_PAGE(!PageHeadHuge(page), page);
++	SetPagePrivate(&page[1]);
++}
++
++static void clear_page_huge_active(struct page *page)
++{
++	VM_BUG_ON_PAGE(!PageHeadHuge(page), page);
++	ClearPagePrivate(&page[1]);
++}
++
+ void free_huge_page(struct page *page)
+ {
+ 	/*
+@@ -875,6 +900,7 @@ void free_huge_page(struct page *page)
+ 	ClearPagePrivate(page);
+ 
+ 	spin_lock(&hugetlb_lock);
++	clear_page_huge_active(page);
+ 	hugetlb_cgroup_uncharge_page(hstate_index(h),
+ 				     pages_per_huge_page(h), page);
+ 	if (restore_reserve)
+@@ -2780,6 +2806,14 @@ static void unmap_ref_private(struct mm_struct *mm, struct vm_area_struct *vma,
+ 			continue;
+ 
+ 		/*
++		 * Shared VMAs have their own reserves and do not affect
++		 * MAP_PRIVATE accounting but it is possible that a shared
++		 * VMA is using the same page so check and skip such VMAs.
++		 */
++		if (iter_vma->vm_flags & VM_MAYSHARE)
++			continue;
++
++		/*
+ 		 * Unmap the page from other VMAs without their own reserves.
+ 		 * They get marked to be SIGKILLed if they fault in these
+ 		 * areas. This is because a future no-page fault on this VMA
+@@ -2884,6 +2918,7 @@ retry_avoidcopy:
+ 	copy_user_huge_page(new_page, old_page, address, vma,
+ 			    pages_per_huge_page(h));
+ 	__SetPageUptodate(new_page);
++	set_page_huge_active(new_page);
+ 
+ 	mmun_start = address & huge_page_mask(h);
+ 	mmun_end = mmun_start + huge_page_size(h);
+@@ -2995,6 +3030,7 @@ retry:
+ 		}
+ 		clear_huge_page(page, address, pages_per_huge_page(h));
+ 		__SetPageUptodate(page);
++		set_page_huge_active(page);
+ 
+ 		if (vma->vm_flags & VM_MAYSHARE) {
+ 			int err;
+@@ -3799,19 +3835,26 @@ int dequeue_hwpoisoned_huge_page(struct page *hpage)
+ 
+ bool isolate_huge_page(struct page *page, struct list_head *list)
+ {
++	bool ret = true;
++
+ 	VM_BUG_ON_PAGE(!PageHead(page), page);
+-	if (!get_page_unless_zero(page))
+-		return false;
+ 	spin_lock(&hugetlb_lock);
++	if (!page_huge_active(page) || !get_page_unless_zero(page)) {
++		ret = false;
++		goto unlock;
++	}
++	clear_page_huge_active(page);
+ 	list_move_tail(&page->lru, list);
++unlock:
+ 	spin_unlock(&hugetlb_lock);
+-	return true;
++	return ret;
+ }
+ 
+ void putback_active_hugepage(struct page *page)
+ {
+ 	VM_BUG_ON_PAGE(!PageHead(page), page);
+ 	spin_lock(&hugetlb_lock);
++	set_page_huge_active(page);
+ 	list_move_tail(&page->lru, &(page_hstate(page))->hugepage_activelist);
+ 	spin_unlock(&hugetlb_lock);
+ 	put_page(page);
+diff --git a/mm/init-mm.c b/mm/init-mm.c
+index a56a851..e1567c3 100644
+--- a/mm/init-mm.c
++++ b/mm/init-mm.c
+@@ -23,3 +23,4 @@ struct mm_struct init_mm = {
+ 	.mmlist		= LIST_HEAD_INIT(init_mm.mmlist),
+ 	INIT_MM_CONTEXT(init_mm)
+ };
++EXPORT_SYMBOL(init_mm);
+diff --git a/mm/madvise.c b/mm/madvise.c
+index 0938b30..dd7d354 100644
+--- a/mm/madvise.c
++++ b/mm/madvise.c
+@@ -102,7 +102,8 @@ static long madvise_behavior(struct vm_area_struct *vma,
+ 
+ 	pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT);
+ 	*prev = vma_merge(mm, *prev, start, end, new_flags, vma->anon_vma,
+-				vma->vm_file, pgoff, vma_policy(vma));
++				vma->vm_file, pgoff, vma_policy(vma),
++				vma_get_anon_name(vma));
+ 	if (*prev) {
+ 		vma = *prev;
+ 		goto success;
+diff --git a/mm/memcontrol.c b/mm/memcontrol.c
+index d72bdc3..ee15ae6 100644
+--- a/mm/memcontrol.c
++++ b/mm/memcontrol.c
+@@ -6001,6 +6001,12 @@ static int mem_cgroup_can_attach(struct cgroup_subsys_state *css,
+ 	return ret;
+ }
+ 
++static int mem_cgroup_allow_attach(struct cgroup_subsys_state *css,
++				   struct cgroup_taskset *tset)
++{
++	return subsys_cgroup_allow_attach(css, tset);
++}
++
+ static void mem_cgroup_cancel_attach(struct cgroup_subsys_state *css,
+ 				     struct cgroup_taskset *tset)
+ {
+@@ -6169,6 +6175,11 @@ static int mem_cgroup_can_attach(struct cgroup_subsys_state *css,
+ {
+ 	return 0;
+ }
++static int mem_cgroup_allow_attach(struct cgroup_subsys_state *css,
++				   struct cgroup_taskset *tset)
++{
++	return 0;
++}
+ static void mem_cgroup_cancel_attach(struct cgroup_subsys_state *css,
+ 				     struct cgroup_taskset *tset)
+ {
+@@ -6204,6 +6215,7 @@ struct cgroup_subsys memory_cgrp_subsys = {
+ 	.can_attach = mem_cgroup_can_attach,
+ 	.cancel_attach = mem_cgroup_cancel_attach,
+ 	.attach = mem_cgroup_move_task,
++	.allow_attach = mem_cgroup_allow_attach,
+ 	.bind = mem_cgroup_bind,
+ 	.legacy_cftypes = mem_cgroup_files,
+ 	.early_init = 0,
+diff --git a/mm/memory-failure.c b/mm/memory-failure.c
+index 22f047f..1b69b9c 100644
+--- a/mm/memory-failure.c
++++ b/mm/memory-failure.c
+@@ -1552,8 +1552,18 @@ static int soft_offline_huge_page(struct page *page, int flags)
+ 	}
+ 	unlock_page(hpage);
+ 
+-	/* Keep page count to indicate a given hugepage is isolated. */
+-	list_move(&hpage->lru, &pagelist);
++	ret = isolate_huge_page(hpage, &pagelist);
++	if (ret) {
++		/*
++		 * get_any_page() and isolate_huge_page() takes a refcount each,
++		 * so need to drop one here.
++		 */
++		put_page(hpage);
++	} else {
++		pr_info("soft offline: %#lx hugepage failed to isolate\n", pfn);
++		return -EBUSY;
++	}
++
+ 	ret = migrate_pages(&pagelist, new_page, NULL, MPOL_MF_MOVE_ALL,
+ 				MIGRATE_SYNC, MR_MEMORY_FAILURE);
+ 	if (ret) {
+diff --git a/mm/memory.c b/mm/memory.c
+index 90fb265..df30feb 100644
+--- a/mm/memory.c
++++ b/mm/memory.c
+@@ -2629,6 +2629,10 @@ static int do_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma,
+ 
+ 	pte_unmap(page_table);
+ 
++	/* File mapping without ->vm_ops ? */
++	if (vma->vm_flags & VM_SHARED)
++		return VM_FAULT_SIGBUS;
++
+ 	/* Check if we need to add a guard page to the stack */
+ 	if (check_stack_guard_page(vma, address) < 0)
+ 		return VM_FAULT_SIGSEGV;
+@@ -3033,6 +3037,10 @@ static int do_linear_fault(struct mm_struct *mm, struct vm_area_struct *vma,
+ 			- vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
+ 
+ 	pte_unmap(page_table);
++
++	/* The VMA was not fully populated on mmap() or missing VM_DONTEXPAND */
++	if (!vma->vm_ops->fault)
++		return VM_FAULT_SIGBUS;
+ 	if (!(flags & FAULT_FLAG_WRITE))
+ 		return do_read_fault(mm, vma, address, pmd, pgoff, flags,
+ 				orig_pte);
+@@ -3198,13 +3206,12 @@ static int handle_pte_fault(struct mm_struct *mm,
+ 	entry = ACCESS_ONCE(*pte);
+ 	if (!pte_present(entry)) {
+ 		if (pte_none(entry)) {
+-			if (vma->vm_ops) {
+-				if (likely(vma->vm_ops->fault))
+-					return do_linear_fault(mm, vma, address,
+-						pte, pmd, flags, entry);
+-			}
+-			return do_anonymous_page(mm, vma, address,
+-						 pte, pmd, flags);
++			if (vma->vm_ops)
++				return do_linear_fault(mm, vma, address, pte, pmd,
++						flags, entry);
++
++			return do_anonymous_page(mm, vma, address, pte, pmd,
++					flags);
+ 		}
+ 		if (pte_file(entry))
+ 			return do_nonlinear_fault(mm, vma, address,
+diff --git a/mm/mempolicy.c b/mm/mempolicy.c
+index 39198cb..30d683e 100644
+--- a/mm/mempolicy.c
++++ b/mm/mempolicy.c
+@@ -770,7 +770,7 @@ static int mbind_range(struct mm_struct *mm, unsigned long start,
+ 			((vmstart - vma->vm_start) >> PAGE_SHIFT);
+ 		prev = vma_merge(mm, prev, vmstart, vmend, vma->vm_flags,
+ 				  vma->anon_vma, vma->vm_file, pgoff,
+-				  new_pol);
++				  new_pol, vma_get_anon_name(vma));
+ 		if (prev) {
+ 			vma = prev;
+ 			next = vma->vm_next;
+diff --git a/mm/migrate.c b/mm/migrate.c
+index cd4fd10..d858da3 100644
+--- a/mm/migrate.c
++++ b/mm/migrate.c
+@@ -39,6 +39,7 @@
+ #include <linux/mmu_notifier.h>
+ 
+ #include <asm/tlbflush.h>
++#include <linux/ptrace.h>
+ 
+ #define CREATE_TRACE_POINTS
+ #include <trace/events/migrate.h>
+@@ -1490,14 +1491,9 @@ SYSCALL_DEFINE6(move_pages, pid_t, pid, unsigned long, nr_pages,
+ 
+ 	/*
+ 	 * Check if this process has the right to modify the specified
+-	 * process. The right exists if the process has administrative
+-	 * capabilities, superuser privileges or the same
+-	 * userid as the target process.
++	 * process. Use the regular "ptrace_may_access()" checks.
+ 	 */
+-	tcred = __task_cred(task);
+-	if (!uid_eq(cred->euid, tcred->suid) && !uid_eq(cred->euid, tcred->uid) &&
+-	    !uid_eq(cred->uid,  tcred->suid) && !uid_eq(cred->uid,  tcred->uid) &&
+-	    !capable(CAP_SYS_NICE)) {
++	if (!ptrace_may_access(task, PTRACE_MODE_READ_REALCREDS)) {	
+ 		rcu_read_unlock();
+ 		err = -EPERM;
+ 		goto out;
+diff --git a/mm/mlock.c b/mm/mlock.c
+index 73cf098..1d0d239 100644
+--- a/mm/mlock.c
++++ b/mm/mlock.c
+@@ -566,7 +566,8 @@ static int mlock_fixup(struct vm_area_struct *vma, struct vm_area_struct **prev,
+ 
+ 	pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT);
+ 	*prev = vma_merge(mm, *prev, start, end, newflags, vma->anon_vma,
+-			  vma->vm_file, pgoff, vma_policy(vma));
++			  vma->vm_file, pgoff, vma_policy(vma),
++			  vma_get_anon_name(vma));
+ 	if (*prev) {
+ 		vma = *prev;
+ 		goto success;
+diff --git a/mm/mmap.c b/mm/mmap.c
+index f88b4f9..f73ff5b 100644
+--- a/mm/mmap.c
++++ b/mm/mmap.c
+@@ -928,7 +928,8 @@ again:			remove_next = 1 + (end > next->vm_end);
+  * per-vma resources, so we don't attempt to merge those.
+  */
+ static inline int is_mergeable_vma(struct vm_area_struct *vma,
+-			struct file *file, unsigned long vm_flags)
++			struct file *file, unsigned long vm_flags,
++			const char __user *anon_name)
+ {
+ 	/*
+ 	 * VM_SOFTDIRTY should not prevent from VMA merging, if we
+@@ -944,6 +945,8 @@ static inline int is_mergeable_vma(struct vm_area_struct *vma,
+ 		return 0;
+ 	if (vma->vm_ops && vma->vm_ops->close)
+ 		return 0;
++	if (vma_get_anon_name(vma) != anon_name)
++		return 0;
+ 	return 1;
+ }
+ 
+@@ -974,9 +977,10 @@ static inline int is_mergeable_anon_vma(struct anon_vma *anon_vma1,
+  */
+ static int
+ can_vma_merge_before(struct vm_area_struct *vma, unsigned long vm_flags,
+-	struct anon_vma *anon_vma, struct file *file, pgoff_t vm_pgoff)
++	struct anon_vma *anon_vma, struct file *file, pgoff_t vm_pgoff,
++	const char __user *anon_name)
+ {
+-	if (is_mergeable_vma(vma, file, vm_flags) &&
++	if (is_mergeable_vma(vma, file, vm_flags, anon_name) &&
+ 	    is_mergeable_anon_vma(anon_vma, vma->anon_vma, vma)) {
+ 		if (vma->vm_pgoff == vm_pgoff)
+ 			return 1;
+@@ -993,9 +997,10 @@ can_vma_merge_before(struct vm_area_struct *vma, unsigned long vm_flags,
+  */
+ static int
+ can_vma_merge_after(struct vm_area_struct *vma, unsigned long vm_flags,
+-	struct anon_vma *anon_vma, struct file *file, pgoff_t vm_pgoff)
++	struct anon_vma *anon_vma, struct file *file, pgoff_t vm_pgoff,
++	const char __user *anon_name)
+ {
+-	if (is_mergeable_vma(vma, file, vm_flags) &&
++	if (is_mergeable_vma(vma, file, vm_flags, anon_name) &&
+ 	    is_mergeable_anon_vma(anon_vma, vma->anon_vma, vma)) {
+ 		pgoff_t vm_pglen;
+ 		vm_pglen = vma_pages(vma);
+@@ -1006,9 +1011,9 @@ can_vma_merge_after(struct vm_area_struct *vma, unsigned long vm_flags,
+ }
+ 
+ /*
+- * Given a mapping request (addr,end,vm_flags,file,pgoff), figure out
+- * whether that can be merged with its predecessor or its successor.
+- * Or both (it neatly fills a hole).
++ * Given a mapping request (addr,end,vm_flags,file,pgoff,anon_name),
++ * figure out whether that can be merged with its predecessor or its
++ * successor.  Or both (it neatly fills a hole).
+  *
+  * In most cases - when called for mmap, brk or mremap - [addr,end) is
+  * certain not to be mapped by the time vma_merge is called; but when
+@@ -1037,8 +1042,9 @@ can_vma_merge_after(struct vm_area_struct *vma, unsigned long vm_flags,
+ struct vm_area_struct *vma_merge(struct mm_struct *mm,
+ 			struct vm_area_struct *prev, unsigned long addr,
+ 			unsigned long end, unsigned long vm_flags,
+-			struct anon_vma *anon_vma, struct file *file,
+-			pgoff_t pgoff, struct mempolicy *policy)
++		    struct anon_vma *anon_vma, struct file *file,
++			pgoff_t pgoff, struct mempolicy *policy,
++			const char __user *anon_name)
+ {
+ 	pgoff_t pglen = (end - addr) >> PAGE_SHIFT;
+ 	struct vm_area_struct *area, *next;
+@@ -1063,16 +1069,16 @@ struct vm_area_struct *vma_merge(struct mm_struct *mm,
+ 	 * Can it merge with the predecessor?
+ 	 */
+ 	if (prev && prev->vm_end == addr &&
+-			mpol_equal(vma_policy(prev), policy) &&
+-			can_vma_merge_after(prev, vm_flags,
+-						anon_vma, file, pgoff)) {
++  			mpol_equal(vma_policy(prev), policy) &&
++			can_vma_merge_after(prev, vm_flags, anon_vma,
++						file, pgoff, anon_name)) {
+ 		/*
+ 		 * OK, it can.  Can we now merge in the successor as well?
+ 		 */
+ 		if (next && end == next->vm_start &&
+ 				mpol_equal(policy, vma_policy(next)) &&
+-				can_vma_merge_before(next, vm_flags,
+-					anon_vma, file, pgoff+pglen) &&
++				can_vma_merge_before(next, vm_flags, anon_vma,
++						file, pgoff+pglen, anon_name) &&
+ 				is_mergeable_anon_vma(prev->anon_vma,
+ 						      next->anon_vma, NULL)) {
+ 							/* cases 1, 6 */
+@@ -1091,9 +1097,9 @@ struct vm_area_struct *vma_merge(struct mm_struct *mm,
+ 	 * Can this new request be merged in front of next?
+ 	 */
+ 	if (next && end == next->vm_start &&
+-			mpol_equal(policy, vma_policy(next)) &&
+-			can_vma_merge_before(next, vm_flags,
+-					anon_vma, file, pgoff+pglen)) {
++ 			mpol_equal(policy, vma_policy(next)) &&
++			can_vma_merge_before(next, vm_flags, anon_vma,
++					file, pgoff+pglen, anon_name)) {
+ 		if (prev && addr < prev->vm_end)	/* case 4 */
+ 			err = vma_adjust(prev, prev->vm_start,
+ 				addr, prev->vm_pgoff, NULL);
+@@ -1580,7 +1586,8 @@ munmap_back:
+ 	/*
+ 	 * Can we just expand an old mapping?
+ 	 */
+-	vma = vma_merge(mm, prev, addr, addr + len, vm_flags, NULL, file, pgoff, NULL);
++	vma = vma_merge(mm, prev, addr, addr + len, vm_flags, NULL, file, pgoff,
++			NULL, NULL);
+ 	if (vma)
+ 		goto out;
+ 
+@@ -2694,7 +2701,7 @@ static unsigned long do_brk(unsigned long addr, unsigned long len)
+ 
+ 	/* Can we just expand an old private anonymous mapping? */
+ 	vma = vma_merge(mm, prev, addr, addr + len, flags,
+-					NULL, NULL, pgoff, NULL);
++					NULL, NULL, pgoff, NULL, NULL);
+ 	if (vma)
+ 		goto out;
+ 
+@@ -2853,7 +2860,8 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap,
+ 	if (find_vma_links(mm, addr, addr + len, &prev, &rb_link, &rb_parent))
+ 		return NULL;	/* should never get here */
+ 	new_vma = vma_merge(mm, prev, addr, addr + len, vma->vm_flags,
+-			vma->anon_vma, vma->vm_file, pgoff, vma_policy(vma));
++			vma->anon_vma, vma->vm_file, pgoff, vma_policy(vma),
++			vma_get_anon_name(vma));
+ 	if (new_vma) {
+ 		/*
+ 		 * Source vma may have been merged into new_vma
+diff --git a/mm/mprotect.c b/mm/mprotect.c
+index ace9345..5911e60 100644
+--- a/mm/mprotect.c
++++ b/mm/mprotect.c
+@@ -289,7 +289,8 @@ mprotect_fixup(struct vm_area_struct *vma, struct vm_area_struct **pprev,
+ 	 */
+ 	pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT);
+ 	*pprev = vma_merge(mm, *pprev, start, end, newflags,
+-			vma->anon_vma, vma->vm_file, pgoff, vma_policy(vma));
++			vma->anon_vma, vma->vm_file, pgoff, vma_policy(vma),
++			vma_get_anon_name(vma));
+ 	if (*pprev) {
+ 		vma = *pprev;
+ 		goto success;
+diff --git a/mm/page_alloc.c b/mm/page_alloc.c
+index c32cb64..87732e5 100644
+--- a/mm/page_alloc.c
++++ b/mm/page_alloc.c
+@@ -204,8 +204,28 @@ static char * const zone_names[MAX_NR_ZONES] = {
+ 	 "Movable",
+ };
+ 
++/*
++ * Try to keep at least this much lowmem free.  Do not allow normal
++ * allocations below this point, only high priority ones. Automatically
++ * tuned according to the amount of memory in the system.
++ */
+ int min_free_kbytes = 1024;
+ int user_min_free_kbytes = -1;
++int min_free_order_shift = 1;
++#ifdef CONFIG_CMA_ADVANCE_SHARE
++/*
++ * Try to set water mark of cma when  cma is used by system.
++ */
++int cma_watermark;
++static bool is_cma_wmark_set = false;
++#endif
++
++/*
++ * Extra memory for the system to try freeing. Used to temporarily
++ * free memory, to make space for new workloads. Anyone can allocate
++ * down to the min watermarks controlled by min_free_kbytes above.
++ */
++int extra_free_kbytes = 0;
+ 
+ static unsigned long __meminitdata nr_kernel_pages;
+ static unsigned long __meminitdata nr_all_pages;
+@@ -801,6 +821,18 @@ void __init __free_pages_bootmem(struct page *page, unsigned int order)
+ }
+ 
+ #ifdef CONFIG_CMA
++
++#ifdef CONFIG_CMA_ADVANCE_SHARE
++void __init init_alloc_ratio_counter(struct zone *zone)
++{
++	if (zone->has_cma)
++		return;
++	zone->has_cma = 1;
++	zone->nr_try_movable = 0;
++	zone->nr_try_cma = 0;
++}
++#endif /* CONFIG_CMA_ADVANCE_SHARE
++ */
+ /* Free whole pageblock and set its migration type to MIGRATE_CMA. */
+ void __init init_cma_reserved_pageblock(struct page *page)
+ {
+@@ -828,6 +860,9 @@ void __init init_cma_reserved_pageblock(struct page *page)
+ 	}
+ 
+ 	adjust_managed_page_count(page, pageblock_nr_pages);
++#ifdef CONFIG_CMA_ADVANCE_SHARE
++	init_alloc_ratio_counter(page_zone(page));
++#endif /* CONFIG_CMA_ADVANCE_SHARE */
+ }
+ #endif
+ 
+@@ -1169,6 +1204,105 @@ __rmqueue_fallback(struct zone *zone, unsigned int order, int start_migratetype)
+ 	return NULL;
+ }
+ 
++#ifdef CONFIG_CMA_ADVANCE_SHARE
++static struct page *__rmqueue_cma(struct zone *zone, unsigned int order,
++				  int migratetype)
++{
++#ifdef CONFIG_CMA_MEM_SHARED
++	long free , free_cma , free_wmark;
++	struct page *page;
++	long cma_multiplex;
++	long cma_wm;
++
++	if (migratetype != MIGRATE_MOVABLE || !zone->has_cma)
++		return NULL;
++
++	if (is_cma_wmark_set) {
++		cma_wm = cma_watermark >> (PAGE_SHIFT - 10);
++		if (cma_wm < (low_wmark_pages(zone))) {
++			/*
++			 * The parameter is illegal and set default value: high_wmark_pages(zone).
++			 * The parameter should be larger than high water mark of the zone!
++			 */
++			cma_watermark = (high_wmark_pages(zone)) << (PAGE_SHIFT - 10);
++			cma_wm = cma_watermark >> (PAGE_SHIFT - 10);
++			is_cma_wmark_set = false;
++		}
++	} else {
++		cma_watermark = (high_wmark_pages(zone)) << (PAGE_SHIFT - 10);
++		cma_wm = cma_watermark >> (PAGE_SHIFT - 10);
++	}
++
++	zone->cma_wmark = cma_watermark;
++	cma_multiplex = cma_wm - low_wmark_pages(zone);
++
++	/* Reset ratio counter */
++	free_cma = zone_page_state(zone, NR_FREE_CMA_PAGES);
++
++	free = zone_page_state(zone, NR_FREE_PAGES);
++	free_wmark = free - free_cma - low_wmark_pages(zone);
++
++	/*
++	 * No cma free pages or there is more sys mem which means there is more
++	 * mem then cma_watermark,so recharge only movable allocation
++	 */
++	if ((free_cma <= 0) || (free_wmark - cma_multiplex > 0)) {
++		zone->nr_try_movable = 1;
++		zone->nr_try_cma = 0;
++		goto alloc_movable;
++	}
++
++	/*
++	 *free_wmark is below than 0, and it means that normal pages
++	 *are under the pressure, so we recharge only cma allocation.
++	 */
++	if (free_wmark <= 0) {
++		zone->nr_try_cma = 1;
++		zone->nr_try_movable = 0;
++		goto alloc_cma;
++	}
++
++	/*
++	 * when free sys mem between high_wmark_pages(zone) and low_wmark_pages(zone),
++	 * sys mem and cma mem could be allocated by turns
++	 */
++	if (zone->nr_try_movable)
++		goto alloc_movable;
++
++	if (zone->nr_try_cma)
++		goto alloc_cma;
++
++	if (free_wmark > free_cma) {
++		zone->nr_try_movable =
++			(free_wmark * pageblock_nr_pages) / free_cma;
++		zone->nr_try_cma = pageblock_nr_pages;
++	} else {
++		zone->nr_try_movable = pageblock_nr_pages;
++		zone->nr_try_cma = free_cma * pageblock_nr_pages / free_wmark;
++	}
++
++	/* Reset complete, start on movable first */
++alloc_movable:
++	zone->nr_try_movable--;
++	return NULL;
++
++alloc_cma:
++	if (zone->nr_try_cma) {
++		/* Okay. Now, we can try to allocate the page from cma region */
++		zone->nr_try_cma--;
++		page = __rmqueue_smallest(zone, order, MIGRATE_CMA);
++
++		/* CMA pages can vanish through CMA allocation */
++		if (unlikely(!page && order == 0))
++			zone->nr_try_cma = 0;
++
++		return page;
++	}
++#endif
++	return NULL;
++}
++#endif /* CONFIG_CMA_ADVANCE_SHARE */
++
+ /*
+  * Do the hard work of removing an element from the buddy allocator.
+  * Call me with the zone->lock already held.
+@@ -1176,10 +1310,16 @@ __rmqueue_fallback(struct zone *zone, unsigned int order, int start_migratetype)
+ static struct page *__rmqueue(struct zone *zone, unsigned int order,
+ 						int migratetype)
+ {
+-	struct page *page;
++	struct page *page = NULL;
++
++#ifdef CONFIG_CMA_ADVANCE_SHARE
++	if (IS_ENABLED(CONFIG_CMA))
++		page = __rmqueue_cma(zone, order, migratetype);
++#endif /* CONFIG_CMA_ADVANCE_SHARE */
+ 
+ retry_reserve:
+-	page = __rmqueue_smallest(zone, order, migratetype);
++	if (!page)
++		page = __rmqueue_smallest(zone, order, migratetype);
+ 
+ 	if (unlikely(!page) && migratetype != MIGRATE_RESERVE) {
+ 		page = __rmqueue_fallback(zone, order, migratetype);
+@@ -1408,7 +1548,8 @@ void free_hot_cold_page(struct page *page, bool cold)
+ 	 * excessively into the page allocator
+ 	 */
+ 	if (migratetype >= MIGRATE_PCPTYPES) {
+-		if (unlikely(is_migrate_isolate(migratetype))) {
++		if (unlikely(is_migrate_isolate(migratetype))
++			|| is_migrate_cma(migratetype)) {
+ 			free_one_page(zone, page, pfn, 0, migratetype);
+ 			goto out;
+ 		}
+@@ -1726,7 +1867,7 @@ static bool __zone_watermark_ok(struct zone *z, unsigned int order,
+ 		free_pages -= z->free_area[o].nr_free << o;
+ 
+ 		/* Require fewer higher order pages to be free */
+-		min >>= 1;
++		min >>= min_free_order_shift;
+ 
+ 		if (free_pages <= min)
+ 			return false;
+@@ -3228,7 +3369,11 @@ void show_free_areas(unsigned int filter)
+ 
+ 	for_each_populated_zone(zone) {
+ 		int i;
+-
++#ifdef CONFIG_CMA_ADVANCE_SHARE
++		unsigned long cma_wm = zone->cma_wmark;
++#else
++		unsigned long cma_wm = 0;
++#endif
+ 		if (skip_free_areas_node(filter, zone_to_nid(zone)))
+ 			continue;
+ 		show_node(zone);
+@@ -3261,6 +3406,7 @@ void show_free_areas(unsigned int filter)
+ 			" writeback_tmp:%lukB"
+ 			" pages_scanned:%lu"
+ 			" all_unreclaimable? %s"
++			" cma_watermark:%lukB"
+ 			"\n",
+ 			zone->name,
+ 			K(zone_page_state(zone, NR_FREE_PAGES)),
+@@ -3291,7 +3437,8 @@ void show_free_areas(unsigned int filter)
+ 			K(zone_page_state(zone, NR_FREE_CMA_PAGES)),
+ 			K(zone_page_state(zone, NR_WRITEBACK_TEMP)),
+ 			K(zone_page_state(zone, NR_PAGES_SCANNED)),
+-			(!zone_reclaimable(zone) ? "yes" : "no")
++			(!zone_reclaimable(zone) ? "yes" : "no"),
++			cma_wm
+ 			);
+ 		printk("lowmem_reserve[]:");
+ 		for (i = 0; i < MAX_NR_ZONES; i++)
+@@ -4894,6 +5041,10 @@ static void __paginginit free_area_init_core(struct pglist_data *pgdat,
+ 		zone_seqlock_init(zone);
+ 		zone->zone_pgdat = pgdat;
+ 		zone_pcp_init(zone);
++#ifdef CONFIG_CMA_ADVANCE_SHARE
++		if (IS_ENABLED(CONFIG_CMA))
++			zone->has_cma = 0;
++#endif
+ 
+ 		/* For bootup, initialized properly in watermark setup */
+ 		mod_zone_page_state(zone, NR_ALLOC_BATCH, zone->managed_pages);
+@@ -5652,6 +5803,7 @@ static void setup_per_zone_lowmem_reserve(void)
+ static void __setup_per_zone_wmarks(void)
+ {
+ 	unsigned long pages_min = min_free_kbytes >> (PAGE_SHIFT - 10);
++	unsigned long pages_low = extra_free_kbytes >> (PAGE_SHIFT - 10);
+ 	unsigned long lowmem_pages = 0;
+ 	struct zone *zone;
+ 	unsigned long flags;
+@@ -5663,11 +5815,14 @@ static void __setup_per_zone_wmarks(void)
+ 	}
+ 
+ 	for_each_zone(zone) {
+-		u64 tmp;
++		u64 min, low;
+ 
+ 		spin_lock_irqsave(&zone->lock, flags);
+-		tmp = (u64)pages_min * zone->managed_pages;
+-		do_div(tmp, lowmem_pages);
++		min = (u64)pages_min * zone->managed_pages;
++		do_div(min, lowmem_pages);
++		low = (u64)pages_low * zone->managed_pages;
++		do_div(low, vm_total_pages);
++
+ 		if (is_highmem(zone)) {
+ 			/*
+ 			 * __GFP_HIGH and PF_MEMALLOC allocations usually don't
+@@ -5688,11 +5843,13 @@ static void __setup_per_zone_wmarks(void)
+ 			 * If it's a lowmem zone, reserve a number of pages
+ 			 * proportionate to the zone's size.
+ 			 */
+-			zone->watermark[WMARK_MIN] = tmp;
++			zone->watermark[WMARK_MIN] = min;
+ 		}
+ 
+-		zone->watermark[WMARK_LOW]  = min_wmark_pages(zone) + (tmp >> 2);
+-		zone->watermark[WMARK_HIGH] = min_wmark_pages(zone) + (tmp >> 1);
++		zone->watermark[WMARK_LOW]  = min_wmark_pages(zone) +
++					low + (min >> 2);
++		zone->watermark[WMARK_HIGH] = min_wmark_pages(zone) +
++					low + (min >> 1);
+ 
+ 		__mod_zone_page_state(zone, NR_ALLOC_BATCH,
+ 			high_wmark_pages(zone) - low_wmark_pages(zone) -
+@@ -5816,7 +5973,7 @@ module_init(init_per_zone_wmark_min)
+ /*
+  * min_free_kbytes_sysctl_handler - just a wrapper around proc_dointvec() so
+  *	that we can call two helper functions whenever min_free_kbytes
+- *	changes.
++ *	or extra_free_kbytes changes.
+  */
+ int min_free_kbytes_sysctl_handler(struct ctl_table *table, int write,
+ 	void __user *buffer, size_t *length, loff_t *ppos)
+@@ -5834,6 +5991,17 @@ int min_free_kbytes_sysctl_handler(struct ctl_table *table, int write,
+ 	return 0;
+ }
+ 
++#ifdef CONFIG_CMA_ADVANCE_SHARE
++int cma_watermark_sysctl_handler(struct ctl_table *table, int write,
++				 void __user *buffer, size_t *length, loff_t *ppos)
++{
++	proc_dointvec(table, write, buffer, length, ppos);
++	if (write)
++		is_cma_wmark_set = true;
++	return 0;
++}
++#endif /* CONFIG_CMA_ADVANCE_SHARE */
++
+ #ifdef CONFIG_NUMA
+ int sysctl_min_unmapped_ratio_sysctl_handler(struct ctl_table *table, int write,
+ 	void __user *buffer, size_t *length, loff_t *ppos)
+@@ -6397,7 +6565,7 @@ int alloc_contig_range(unsigned long start, unsigned long end,
+ 
+ 	/* Make sure the range is really isolated. */
+ 	if (test_pages_isolated(outer_start, end, false)) {
+-		pr_info("%s: [%lx, %lx) PFNs busy\n",
++		pr_warn_once("%s: [%lx, %lx) PFNs busy\n",
+ 			__func__, outer_start, end);
+ 		ret = -EBUSY;
+ 		goto done;
+diff --git a/mm/percpu.c b/mm/percpu.c
+index 88bb6c9..fe72f81 100644
+--- a/mm/percpu.c
++++ b/mm/percpu.c
+@@ -110,7 +110,7 @@ struct pcpu_chunk {
+ 	int			map_used;	/* # of map entries used before the sentry */
+ 	int			map_alloc;	/* # of map entries allocated */
+ 	int			*map;		/* allocation map */
+-	struct work_struct	map_extend_work;/* async ->map[] extension */
++	struct list_head	map_extend_list;/* on pcpu_map_extend_chunks */
+ 
+ 	void			*data;		/* chunk data */
+ 	int			first_free;	/* no free below this */
+@@ -160,10 +160,13 @@ static struct pcpu_chunk *pcpu_reserved_chunk;
+ static int pcpu_reserved_chunk_limit;
+ 
+ static DEFINE_SPINLOCK(pcpu_lock);	/* all internal data structures */
+-static DEFINE_MUTEX(pcpu_alloc_mutex);	/* chunk create/destroy, [de]pop */
++static DEFINE_MUTEX(pcpu_alloc_mutex);	/* chunk create/destroy, [de]pop, map ext */
+ 
+ static struct list_head *pcpu_slot __read_mostly; /* chunk list slots */
+ 
++/* chunks which need their map areas extended, protected by pcpu_lock */
++static LIST_HEAD(pcpu_map_extend_chunks);
++
+ /*
+  * The number of empty populated pages, protected by pcpu_lock.  The
+  * reserved chunk doesn't contribute to the count.
+@@ -401,9 +404,13 @@ static int pcpu_need_to_extend(struct pcpu_chunk *chunk, bool is_atomic)
+ 		margin = 3;
+ 
+ 		if (chunk->map_alloc <
+-		    chunk->map_used + PCPU_ATOMIC_MAP_MARGIN_LOW &&
+-		    pcpu_async_enabled)
+-			schedule_work(&chunk->map_extend_work);
++			chunk->map_used + PCPU_ATOMIC_MAP_MARGIN_LOW) {
++			if (list_empty(&chunk->map_extend_list)) {
++				list_add_tail(&chunk->map_extend_list,
++						&pcpu_map_extend_chunks);
++				pcpu_schedule_balance_work();
++			}
++		}
+ 	} else {
+ 		margin = PCPU_ATOMIC_MAP_MARGIN_HIGH;
+ 	}
+@@ -437,6 +444,8 @@ static int pcpu_extend_area_map(struct pcpu_chunk *chunk, int new_alloc)
+ 	size_t old_size = 0, new_size = new_alloc * sizeof(new[0]);
+ 	unsigned long flags;
+ 
++	lockdep_assert_held(&pcpu_alloc_mutex);
++
+ 	new = pcpu_mem_zalloc(new_size);
+ 	if (!new)
+ 		return -ENOMEM;
+@@ -469,20 +478,6 @@ out_unlock:
+ 	return 0;
+ }
+ 
+-static void pcpu_map_extend_workfn(struct work_struct *work)
+-{
+-	struct pcpu_chunk *chunk = container_of(work, struct pcpu_chunk,
+-						map_extend_work);
+-	int new_alloc;
+-
+-	spin_lock_irq(&pcpu_lock);
+-	new_alloc = pcpu_need_to_extend(chunk, false);
+-	spin_unlock_irq(&pcpu_lock);
+-
+-	if (new_alloc)
+-		pcpu_extend_area_map(chunk, new_alloc);
+-}
+-
+ /**
+  * pcpu_fit_in_area - try to fit the requested allocation in a candidate area
+  * @chunk: chunk the candidate area belongs to
+@@ -742,7 +737,7 @@ static struct pcpu_chunk *pcpu_alloc_chunk(void)
+ 	chunk->map_used = 1;
+ 
+ 	INIT_LIST_HEAD(&chunk->list);
+-	INIT_WORK(&chunk->map_extend_work, pcpu_map_extend_workfn);
++	INIT_LIST_HEAD(&chunk->map_extend_list);
+ 	chunk->free_size = pcpu_unit_size;
+ 	chunk->contig_hint = pcpu_unit_size;
+ 
+@@ -897,6 +892,9 @@ static void __percpu *pcpu_alloc(size_t size, size_t align, bool reserved,
+ 		return NULL;
+ 	}
+ 
++	if (!is_atomic)
++		mutex_lock(&pcpu_alloc_mutex);
++
+ 	spin_lock_irqsave(&pcpu_lock, flags);
+ 
+ 	/* serve reserved allocations from the reserved chunk if available */
+@@ -974,7 +972,6 @@ restart:
+ 	if (list_empty(&pcpu_slot[pcpu_nr_slots - 1])) {
+ 		chunk = pcpu_create_chunk();
+ 		if (!chunk) {
+-			mutex_unlock(&pcpu_alloc_mutex);
+ 			err = "failed to allocate new chunk";
+ 			goto fail;
+ 		}
+@@ -985,7 +982,6 @@ restart:
+ 		spin_lock_irqsave(&pcpu_lock, flags);
+ 	}
+ 
+-	mutex_unlock(&pcpu_alloc_mutex);
+ 	goto restart;
+ 
+ area_found:
+@@ -995,8 +991,6 @@ area_found:
+ 	if (!is_atomic) {
+ 		int page_start, page_end, rs, re;
+ 
+-		mutex_lock(&pcpu_alloc_mutex);
+-
+ 		page_start = PFN_DOWN(off);
+ 		page_end = PFN_UP(off + size);
+ 
+@@ -1007,7 +1001,6 @@ area_found:
+ 
+ 			spin_lock_irqsave(&pcpu_lock, flags);
+ 			if (ret) {
+-				mutex_unlock(&pcpu_alloc_mutex);
+ 				pcpu_free_area(chunk, off, &occ_pages);
+ 				err = "failed to populate";
+ 				goto fail_unlock;
+@@ -1047,6 +1040,8 @@ fail:
+ 		/* see the flag handling in pcpu_blance_workfn() */
+ 		pcpu_atomic_alloc_failed = true;
+ 		pcpu_schedule_balance_work();
++	} else {
++		mutex_unlock(&pcpu_alloc_mutex);
+ 	}
+ 	return NULL;
+ }
+@@ -1131,6 +1126,7 @@ static void pcpu_balance_workfn(struct work_struct *work)
+ 		if (chunk == list_first_entry(free_head, struct pcpu_chunk, list))
+ 			continue;
+ 
++		list_del_init(&chunk->map_extend_list);
+ 		list_move(&chunk->list, &to_free);
+ 	}
+ 
+@@ -1148,6 +1144,25 @@ static void pcpu_balance_workfn(struct work_struct *work)
+ 		pcpu_destroy_chunk(chunk);
+ 	}
+ 
++	/* service chunks which requested async area map extension */
++	do {
++		int new_alloc = 0;
++
++		spin_lock_irq(&pcpu_lock);
++
++		chunk = list_first_entry_or_null(&pcpu_map_extend_chunks,
++				struct pcpu_chunk, map_extend_list);
++		if (chunk) {
++			list_del_init(&chunk->map_extend_list);
++			new_alloc = pcpu_need_to_extend(chunk, false);
++		}
++
++		spin_unlock_irq(&pcpu_lock);
++
++		if (new_alloc)
++			pcpu_extend_area_map(chunk, new_alloc);
++	} while (chunk);
++
+ 	/*
+ 	 * Ensure there are certain number of free populated pages for
+ 	 * atomic allocs.  Fill up from the most packed so that atomic
+@@ -1648,7 +1663,7 @@ int __init pcpu_setup_first_chunk(const struct pcpu_alloc_info *ai,
+ 	 */
+ 	schunk = memblock_virt_alloc(pcpu_chunk_struct_size, 0);
+ 	INIT_LIST_HEAD(&schunk->list);
+-	INIT_WORK(&schunk->map_extend_work, pcpu_map_extend_workfn);
++	INIT_LIST_HEAD(&schunk->map_extend_list);
+ 	schunk->base_addr = base_addr;
+ 	schunk->map = smap;
+ 	schunk->map_alloc = ARRAY_SIZE(smap);
+@@ -1678,7 +1693,7 @@ int __init pcpu_setup_first_chunk(const struct pcpu_alloc_info *ai,
+ 	if (dyn_size) {
+ 		dchunk = memblock_virt_alloc(pcpu_chunk_struct_size, 0);
+ 		INIT_LIST_HEAD(&dchunk->list);
+-		INIT_WORK(&dchunk->map_extend_work, pcpu_map_extend_workfn);
++		INIT_LIST_HEAD(&dchunk->map_extend_list);
+ 		dchunk->base_addr = base_addr;
+ 		dchunk->map = dmap;
+ 		dchunk->map_alloc = ARRAY_SIZE(dmap);
+diff --git a/mm/shmem.c b/mm/shmem.c
+index 0b4ba55..5830599 100644
+--- a/mm/shmem.c
++++ b/mm/shmem.c
+@@ -557,6 +557,10 @@ static int shmem_setattr(struct dentry *dentry, struct iattr *attr)
+ 	if (error)
+ 		return error;
+ 
++	error = setattr_killpriv(dentry, attr);
++	if (error)
++		return error;
++
+ 	if (S_ISREG(inode->i_mode) && (attr->ia_valid & ATTR_SIZE)) {
+ 		loff_t oldsize = inode->i_size;
+ 		loff_t newsize = attr->ia_size;
+@@ -3404,6 +3408,14 @@ struct file *shmem_file_setup(const char *name, loff_t size, unsigned long flags
+ }
+ EXPORT_SYMBOL_GPL(shmem_file_setup);
+ 
++void shmem_set_file(struct vm_area_struct *vma, struct file *file)
++{
++	if (vma->vm_file)
++		fput(vma->vm_file);
++	vma->vm_file = file;
++	vma->vm_ops = &shmem_vm_ops;
++}
++
+ /**
+  * shmem_zero_setup - setup a shared anonymous mapping
+  * @vma: the vma to be mmapped is prepared by do_mmap_pgoff
+@@ -3417,10 +3429,7 @@ int shmem_zero_setup(struct vm_area_struct *vma)
+ 	if (IS_ERR(file))
+ 		return PTR_ERR(file);
+ 
+-	if (vma->vm_file)
+-		fput(vma->vm_file);
+-	vma->vm_file = file;
+-	vma->vm_ops = &shmem_vm_ops;
++	shmem_set_file(vma, file);
+ 	return 0;
+ }
+ 
+diff --git a/mm/vmscan.c b/mm/vmscan.c
+index e3b0a54..e9d4059 100644
+--- a/mm/vmscan.c
++++ b/mm/vmscan.c
+@@ -46,6 +46,7 @@
+ #include <linux/oom.h>
+ #include <linux/prefetch.h>
+ #include <linux/printk.h>
++#include <linux/debugfs.h>
+ 
+ #include <asm/tlbflush.h>
+ #include <asm/div64.h>
+@@ -186,6 +187,39 @@ static unsigned long get_lru_size(struct lruvec *lruvec, enum lru_list lru)
+ 	return zone_page_state(lruvec_zone(lruvec), NR_LRU_BASE + lru);
+ }
+ 
++struct dentry *debug_file;
++
++static int debug_shrinker_show(struct seq_file *s, void *unused)
++{
++	struct shrinker *shrinker;
++	struct shrink_control sc;
++
++	sc.gfp_mask = -1;
++	sc.nr_to_scan = 0;
++
++	down_read(&shrinker_rwsem);
++	list_for_each_entry(shrinker, &shrinker_list, list) {
++		int num_objs;
++
++		num_objs = shrinker->count_objects(shrinker, &sc);
++		seq_printf(s, "%pf %d\n", shrinker->scan_objects, num_objs);
++	}
++	up_read(&shrinker_rwsem);
++	return 0;
++}
++
++static int debug_shrinker_open(struct inode *inode, struct file *file)
++{
++        return single_open(file, debug_shrinker_show, inode->i_private);
++}
++
++static const struct file_operations debug_shrinker_fops = {
++        .open = debug_shrinker_open,
++        .read = seq_read,
++        .llseek = seq_lseek,
++        .release = single_release,
++};
++
+ /*
+  * Add a shrinker callback to be called from the vm.
+  */
+@@ -215,6 +249,15 @@ int register_shrinker(struct shrinker *shrinker)
+ }
+ EXPORT_SYMBOL(register_shrinker);
+ 
++static int __init add_shrinker_debug(void)
++{
++	debugfs_create_file("shrinker", 0644, NULL, NULL,
++			    &debug_shrinker_fops);
++	return 0;
++}
++
++late_initcall(add_shrinker_debug);
++
+ /*
+  * Remove one
+  */
+@@ -926,7 +969,7 @@ static unsigned long shrink_page_list(struct list_head *page_list,
+ 
+ 			/* Case 2 above */
+ 			} else if (global_reclaim(sc) ||
+-			    !PageReclaim(page) || !(sc->gfp_mask & __GFP_IO)) {
++			    !PageReclaim(page) || !may_enter_fs) {
+ 				/*
+ 				 * This is slightly racy - end_page_writeback()
+ 				 * might have just cleared PageReclaim, then
+@@ -1115,7 +1158,7 @@ cull_mlocked:
+ 		if (PageSwapCache(page))
+ 			try_to_free_swap(page);
+ 		unlock_page(page);
+-		putback_lru_page(page);
++		list_add(&page->lru, &ret_pages);
+ 		continue;
+ 
+ activate_locked:
+diff --git a/net/Kconfig b/net/Kconfig
+index 99815b5..15a2d76 100644
+--- a/net/Kconfig
++++ b/net/Kconfig
+@@ -83,6 +83,20 @@ source "net/netlabel/Kconfig"
+ 
+ endif # if INET
+ 
++config ANDROID_PARANOID_NETWORK
++	bool "Only allow certain groups to create sockets"
++	default ANDROID
++	help
++		none
++
++config NET_ACTIVITY_STATS
++	bool "Network activity statistics tracking"
++	default y
++	help
++	 Network activity statistics are useful for tracking wireless
++	 modem activity on 2G, 3G, 4G wireless networks. Counts number of
++	 transmissions and groups them in specified time buckets.
++
+ config NETWORK_SECMARK
+ 	bool "Security Marking"
+ 	help
+@@ -230,7 +244,7 @@ source "net/mpls/Kconfig"
+ source "net/hsr/Kconfig"
+ 
+ config RPS
+-	boolean
++	boolean "RPS"
+ 	depends on SMP && SYSFS
+ 	default y
+ 
+diff --git a/net/Makefile b/net/Makefile
+index 7ed1970..550c112 100644
+--- a/net/Makefile
++++ b/net/Makefile
+@@ -73,3 +73,4 @@ obj-$(CONFIG_OPENVSWITCH)	+= openvswitch/
+ obj-$(CONFIG_VSOCKETS)	+= vmw_vsock/
+ obj-$(CONFIG_NET_MPLS_GSO)	+= mpls/
+ obj-$(CONFIG_HSR)		+= hsr/
++obj-$(CONFIG_NET_ACTIVITY_STATS)		+= activity_stats.o
+diff --git a/net/activity_stats.c b/net/activity_stats.c
+new file mode 100644
+index 0000000..4609ce2
+--- /dev/null
++++ b/net/activity_stats.c
+@@ -0,0 +1,119 @@
++/* net/activity_stats.c
++ *
++ * Copyright (C) 2010 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * 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.
++ *
++ * Author: Mike Chan (mike@android.com)
++ */
++
++#include <linux/proc_fs.h>
++#include <linux/seq_file.h>
++#include <linux/suspend.h>
++#include <net/net_namespace.h>
++
++/*
++ * Track transmission rates in buckets (power of 2).
++ * 1,2,4,8...512 seconds.
++ *
++ * Buckets represent the count of network transmissions at least
++ * N seconds apart, where N is 1 << bucket index.
++ */
++#define BUCKET_MAX 10
++
++/* Track network activity frequency */
++static unsigned long activity_stats[BUCKET_MAX];
++static ktime_t last_transmit;
++static ktime_t suspend_time;
++static DEFINE_SPINLOCK(activity_lock);
++
++void activity_stats_update(void)
++{
++	int i;
++	unsigned long flags;
++	ktime_t now;
++	s64 delta;
++
++	spin_lock_irqsave(&activity_lock, flags);
++	now = ktime_get();
++	delta = ktime_to_ns(ktime_sub(now, last_transmit));
++
++	for (i = BUCKET_MAX - 1; i >= 0; i--) {
++		/*
++		 * Check if the time delta between network activity is within the
++		 * minimum bucket range.
++		 */
++		if (delta < (1000000000ULL << i))
++			continue;
++
++		activity_stats[i]++;
++		last_transmit = now;
++		break;
++	}
++	spin_unlock_irqrestore(&activity_lock, flags);
++}
++
++static int activity_stats_show(struct seq_file *m, void *v)
++{
++	int i;
++	int ret;
++
++	seq_printf(m, "Min Bucket(sec) Count\n");
++
++	for (i = 0; i < BUCKET_MAX; i++) {
++		ret = seq_printf(m, "%15d %lu\n", 1 << i, activity_stats[i]);
++		if (ret)
++			return ret;
++	}
++
++	return 0;
++}
++
++static int activity_stats_notifier(struct notifier_block *nb,
++					unsigned long event, void *dummy)
++{
++	switch (event) {
++		case PM_SUSPEND_PREPARE:
++			suspend_time = ktime_get_real();
++			break;
++
++		case PM_POST_SUSPEND:
++			suspend_time = ktime_sub(ktime_get_real(), suspend_time);
++			last_transmit = ktime_sub(last_transmit, suspend_time);
++	}
++
++	return 0;
++}
++
++static int activity_stats_open(struct inode *inode, struct file *file)
++{
++	return single_open(file, activity_stats_show, PDE_DATA(inode));
++}
++
++static const struct file_operations activity_stats_fops = {
++	.open		= activity_stats_open,
++	.read		= seq_read,
++	.llseek		= seq_lseek,
++	.release	= seq_release,
++};
++
++static struct notifier_block activity_stats_notifier_block = {
++	.notifier_call = activity_stats_notifier,
++};
++
++static int  __init activity_stats_init(void)
++{
++	proc_create("activity", S_IRUGO,
++		    init_net.proc_net_stat, &activity_stats_fops);
++	return register_pm_notifier(&activity_stats_notifier_block);
++}
++
++subsys_initcall(activity_stats_init);
++
+diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c
+index c35c3f4..1428c3f 100644
+--- a/net/ax25/af_ax25.c
++++ b/net/ax25/af_ax25.c
+@@ -806,6 +806,9 @@ static int ax25_create(struct net *net, struct socket *sock, int protocol,
+ 	struct sock *sk;
+ 	ax25_cb *ax25;
+ 
++	if (protocol < 0 || protocol > SK_PROTOCOL_MAX)
++		return -EINVAL;
++
+ 	if (!net_eq(net, &init_net))
+ 		return -EAFNOSUPPORT;
+ 
+diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
+index 339c74a..6ad3468 100644
+--- a/net/bluetooth/af_bluetooth.c
++++ b/net/bluetooth/af_bluetooth.c
+@@ -104,11 +104,40 @@ void bt_sock_unregister(int proto)
+ }
+ EXPORT_SYMBOL(bt_sock_unregister);
+ 
++#ifdef CONFIG_PARANOID_NETWORK
++static inline int current_has_bt_admin(void)
++{
++	return !current_euid();
++}
++
++static inline int current_has_bt(void)
++{
++	return current_has_bt_admin();
++}
++# else
++static inline int current_has_bt_admin(void)
++{
++	return 1;
++}
++
++static inline int current_has_bt(void)
++{
++	return 1;
++}
++#endif
++
+ static int bt_sock_create(struct net *net, struct socket *sock, int proto,
+ 			  int kern)
+ {
+ 	int err;
+ 
++	if (proto == BTPROTO_RFCOMM || proto == BTPROTO_SCO ||
++			proto == BTPROTO_L2CAP) {
++		if (!current_has_bt())
++			return -EPERM;
++	} else if (!current_has_bt_admin())
++		return -EPERM;
++
+ 	if (net != &init_net)
+ 		return -EAFNOSUPPORT;
+ 
+diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
+index ffd379d..b8919d0 100644
+--- a/net/bridge/br_device.c
++++ b/net/bridge/br_device.c
+@@ -44,16 +44,17 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
+ 	}
+ #endif
+ 
+-	u64_stats_update_begin(&brstats->syncp);
+-	brstats->tx_packets++;
+-	brstats->tx_bytes += skb->len;
+-	u64_stats_update_end(&brstats->syncp);
+-
+ 	BR_INPUT_SKB_CB(skb)->brdev = dev;
+ 
+ 	skb_reset_mac_header(skb);
+ 	skb_pull(skb, ETH_HLEN);
+ 
++	u64_stats_update_begin(&brstats->syncp);
++	brstats->tx_packets++;
++	/* Exclude ETH_HLEN from byte stats for consistency with Rx chain */
++	brstats->tx_bytes += skb->len;
++	u64_stats_update_end(&brstats->syncp);
++
+ 	if (!br_allowed_ingress(br, br_get_vlan_info(br), skb, &vid))
+ 		goto out;
+ 
+diff --git a/net/core/dev.c b/net/core/dev.c
+index fb96258..ecc1d4b 100644
+--- a/net/core/dev.c
++++ b/net/core/dev.c
+@@ -4019,7 +4019,7 @@ static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff
+ 		NAPI_GRO_CB(skb)->same_flow = 0;
+ 		NAPI_GRO_CB(skb)->flush = 0;
+ 		NAPI_GRO_CB(skb)->free = 0;
+-		NAPI_GRO_CB(skb)->udp_mark = 0;
++		NAPI_GRO_CB(skb)->encap_mark = 0;
+ 
+ 		/* Setup for GRO checksum validation */
+ 		switch (skb->ip_summed) {
+diff --git a/net/core/ethtool.c b/net/core/ethtool.c
+index 06dfb29..e61a94f 100644
+--- a/net/core/ethtool.c
++++ b/net/core/ethtool.c
+@@ -900,11 +900,13 @@ static int ethtool_reset(struct net_device *dev, char __user *useraddr)
+ 
+ static int ethtool_get_wol(struct net_device *dev, char __user *useraddr)
+ {
+-	struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL };
++	struct ethtool_wolinfo wol;;
+ 
+ 	if (!dev->ethtool_ops->get_wol)
+ 		return -EOPNOTSUPP;
+ 
++	memset(&wol, 0, sizeof(struct ethtool_wolinfo));
++	wol.cmd = ETHTOOL_GWOL;
+ 	dev->ethtool_ops->get_wol(dev, &wol);
+ 
+ 	if (copy_to_user(useraddr, &wol, sizeof(wol)))
+diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c
+index 185c341..5cbcdfd 100644
+--- a/net/core/fib_rules.c
++++ b/net/core/fib_rules.c
+@@ -31,6 +31,8 @@ int fib_default_rule_add(struct fib_rules_ops *ops,
+ 	r->pref = pref;
+ 	r->table = table;
+ 	r->flags = flags;
++	r->uid_start = INVALID_UID;
++	r->uid_end = INVALID_UID;
+ 	r->fr_net = hold_net(ops->fro_net);
+ 
+ 	r->suppress_prefixlen = -1;
+@@ -182,6 +184,23 @@ void fib_rules_unregister(struct fib_rules_ops *ops)
+ }
+ EXPORT_SYMBOL_GPL(fib_rules_unregister);
+ 
++static inline kuid_t fib_nl_uid(struct nlattr *nla)
++{
++	return make_kuid(current_user_ns(), nla_get_u32(nla));
++}
++
++static int nla_put_uid(struct sk_buff *skb, int idx, kuid_t uid)
++{
++	return nla_put_u32(skb, idx, from_kuid_munged(current_user_ns(), uid));
++}
++
++static int fib_uid_range_match(struct flowi *fl, struct fib_rule *rule)
++{
++	return (!uid_valid(rule->uid_start) && !uid_valid(rule->uid_end)) ||
++	       (uid_gte(fl->flowi_uid, rule->uid_start) &&
++		uid_lte(fl->flowi_uid, rule->uid_end));
++}
++
+ static int fib_rule_match(struct fib_rule *rule, struct fib_rules_ops *ops,
+ 			  struct flowi *fl, int flags)
+ {
+@@ -196,6 +215,9 @@ static int fib_rule_match(struct fib_rule *rule, struct fib_rules_ops *ops,
+ 	if ((rule->mark ^ fl->flowi_mark) & rule->mark_mask)
+ 		goto out;
+ 
++	if (!fib_uid_range_match(fl, rule))
++		goto out;
++
+ 	ret = ops->match(rule, fl, flags);
+ out:
+ 	return (rule->flags & FIB_RULE_INVERT) ? !ret : ret;
+@@ -378,6 +400,19 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh)
+ 	} else if (rule->action == FR_ACT_GOTO)
+ 		goto errout_free;
+ 
++	/* UID start and end must either both be valid or both unspecified. */
++	rule->uid_start = rule->uid_end = INVALID_UID;
++	if (tb[FRA_UID_START] || tb[FRA_UID_END]) {
++		if (tb[FRA_UID_START] && tb[FRA_UID_END]) {
++			rule->uid_start = fib_nl_uid(tb[FRA_UID_START]);
++			rule->uid_end = fib_nl_uid(tb[FRA_UID_END]);
++		}
++		if (!uid_valid(rule->uid_start) ||
++		    !uid_valid(rule->uid_end) ||
++		    !uid_lte(rule->uid_start, rule->uid_end))
++		goto errout_free;
++	}
++
+ 	err = ops->configure(rule, skb, frh, tb);
+ 	if (err < 0)
+ 		goto errout_free;
+@@ -484,6 +519,14 @@ static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh)
+ 		    (rule->mark_mask != nla_get_u32(tb[FRA_FWMASK])))
+ 			continue;
+ 
++		if (tb[FRA_UID_START] &&
++		    !uid_eq(rule->uid_start, fib_nl_uid(tb[FRA_UID_START])))
++			continue;
++
++		if (tb[FRA_UID_END] &&
++		    !uid_eq(rule->uid_end, fib_nl_uid(tb[FRA_UID_END])))
++			continue;
++
+ 		if (!ops->compare(rule, frh, tb))
+ 			continue;
+ 
+@@ -542,7 +585,9 @@ static inline size_t fib_rule_nlmsg_size(struct fib_rules_ops *ops,
+ 			 + nla_total_size(4) /* FRA_SUPPRESS_PREFIXLEN */
+ 			 + nla_total_size(4) /* FRA_SUPPRESS_IFGROUP */
+ 			 + nla_total_size(4) /* FRA_FWMARK */
+-			 + nla_total_size(4); /* FRA_FWMASK */
++			 + nla_total_size(4) /* FRA_FWMASK */
++			 + nla_total_size(4) /* FRA_UID_START */
++			 + nla_total_size(4); /* FRA_UID_END */
+ 
+ 	if (ops->nlmsg_payload)
+ 		payload += ops->nlmsg_payload(rule);
+@@ -598,7 +643,11 @@ static int fib_nl_fill_rule(struct sk_buff *skb, struct fib_rule *rule,
+ 	    ((rule->mark_mask || rule->mark) &&
+ 	     nla_put_u32(skb, FRA_FWMASK, rule->mark_mask)) ||
+ 	    (rule->target &&
+-	     nla_put_u32(skb, FRA_GOTO, rule->target)))
++	     nla_put_u32(skb, FRA_GOTO, rule->target)) ||
++	    (uid_valid(rule->uid_start) &&
++	     nla_put_uid(skb, FRA_UID_START, rule->uid_start)) ||
++	    (uid_valid(rule->uid_end) &&
++	     nla_put_uid(skb, FRA_UID_END, rule->uid_end)))
+ 		goto nla_put_failure;
+ 
+ 	if (rule->suppress_ifgroup != -1) {
+diff --git a/net/core/filter.c b/net/core/filter.c
+index 647b122..14b0959 100644
+--- a/net/core/filter.c
++++ b/net/core/filter.c
+@@ -46,9 +46,10 @@
+ #include <linux/if_vlan.h>
+ 
+ /**
+- *	sk_filter - run a packet through a socket filter
++ *	sk_filter_trim_cap - run a packet through a socket filter
+  *	@sk: sock associated with &sk_buff
+  *	@skb: buffer to filter
++ *	@cap: limit on how short the eBPF program may trim the packet
+  *
+  * Run the filter code and then cut skb->data to correct size returned by
+  * SK_RUN_FILTER. If pkt_len is 0 we toss packet. If skb->len is smaller
+@@ -57,7 +58,7 @@
+  * be accepted or -EPERM if the packet should be tossed.
+  *
+  */
+-int sk_filter(struct sock *sk, struct sk_buff *skb)
++int sk_filter_trim_cap(struct sock *sk, struct sk_buff *skb, unsigned int cap)
+ {
+ 	int err;
+ 	struct sk_filter *filter;
+@@ -78,14 +79,13 @@ int sk_filter(struct sock *sk, struct sk_buff *skb)
+ 	filter = rcu_dereference(sk->sk_filter);
+ 	if (filter) {
+ 		unsigned int pkt_len = SK_RUN_FILTER(filter, skb);
+-
+-		err = pkt_len ? pskb_trim(skb, pkt_len) : -EPERM;
++		err = pkt_len ? pskb_trim(skb, max(cap, pkt_len)) : -EPERM;
+ 	}
+ 	rcu_read_unlock();
+ 
+ 	return err;
+ }
+-EXPORT_SYMBOL(sk_filter);
++EXPORT_SYMBOL(sk_filter_trim_cap);
+ 
+ static u64 __skb_get_pay_offset(u64 ctx, u64 a, u64 x, u64 r4, u64 r5)
+ {
+diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
+index c522f7a..8bc4e3b 100644
+--- a/net/core/rtnetlink.c
++++ b/net/core/rtnetlink.c
+@@ -1018,14 +1018,16 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
+ 		goto nla_put_failure;
+ 
+ 	if (1) {
+-		struct rtnl_link_ifmap map = {
+-			.mem_start   = dev->mem_start,
+-			.mem_end     = dev->mem_end,
+-			.base_addr   = dev->base_addr,
+-			.irq         = dev->irq,
+-			.dma         = dev->dma,
+-			.port        = dev->if_port,
+-		};
++		struct rtnl_link_ifmap map;
++
++		memset(&map, 0, sizeof(map));
++		map.mem_start   = dev->mem_start;
++		map.mem_end     = dev->mem_end;
++		map.base_addr   = dev->base_addr;
++		map.irq         = dev->irq;
++		map.dma         = dev->dma;
++		map.port        = dev->if_port;
++
+ 		if (nla_put(skb, IFLA_MAP, sizeof(map), &map))
+ 			goto nla_put_failure;
+ 	}
+diff --git a/net/core/scm.c b/net/core/scm.c
+index b442e7e..47a5515 100644
+--- a/net/core/scm.c
++++ b/net/core/scm.c
+@@ -87,6 +87,7 @@ static int scm_fp_copy(struct cmsghdr *cmsg, struct scm_fp_list **fplp)
+ 		*fplp = fpl;
+ 		fpl->count = 0;
+ 		fpl->max = SCM_MAX_FD;
++		fpl->user = NULL;
+ 	}
+ 	fpp = &fpl->fp[fpl->count];
+ 
+@@ -107,6 +108,10 @@ static int scm_fp_copy(struct cmsghdr *cmsg, struct scm_fp_list **fplp)
+ 		*fpp++ = file;
+ 		fpl->count++;
+ 	}
++
++	if (!fpl->user)
++		fpl->user = get_uid(current_user());
++
+ 	return num;
+ }
+ 
+@@ -119,6 +124,7 @@ void __scm_destroy(struct scm_cookie *scm)
+ 		scm->fp = NULL;
+ 		for (i=fpl->count-1; i>=0; i--)
+ 			fput(fpl->fp[i]);
++		free_uid(fpl->user);
+ 		kfree(fpl);
+ 	}
+ }
+@@ -335,6 +341,7 @@ struct scm_fp_list *scm_fp_dup(struct scm_fp_list *fpl)
+ 		for (i = 0; i < fpl->count; i++)
+ 			get_file(fpl->fp[i]);
+ 		new_fpl->max = new_fpl->count;
++		new_fpl->user = get_uid(fpl->user);
+ 	}
+ 	return new_fpl;
+ }
+diff --git a/net/core/sock.c b/net/core/sock.c
+index 1e5130d..ef07173 100644
+--- a/net/core/sock.c
++++ b/net/core/sock.c
+@@ -735,7 +735,7 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
+ 		val = min_t(u32, val, sysctl_wmem_max);
+ set_sndbuf:
+ 		sk->sk_userlocks |= SOCK_SNDBUF_LOCK;
+-		sk->sk_sndbuf = max_t(u32, val * 2, SOCK_MIN_SNDBUF);
++		sk->sk_sndbuf = max_t(int, val * 2, SOCK_MIN_SNDBUF);
+ 		/* Wake up sending tasks if we upped the value. */
+ 		sk->sk_write_space(sk);
+ 		break;
+@@ -771,7 +771,7 @@ set_rcvbuf:
+ 		 * returning the value we actually used in getsockopt
+ 		 * is the most desirable behavior.
+ 		 */
+-		sk->sk_rcvbuf = max_t(u32, val * 2, SOCK_MIN_RCVBUF);
++		sk->sk_rcvbuf = max_t(int, val * 2, SOCK_MIN_RCVBUF);
+ 		break;
+ 
+ 	case SO_RCVBUFFORCE:
+diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c
+index e731c96..8725b91 100644
+--- a/net/core/sysctl_net_core.c
++++ b/net/core/sysctl_net_core.c
+@@ -23,7 +23,6 @@
+ #include <net/pkt_sched.h>
+ 
+ static int zero = 0;
+-static int one = 1;
+ static int ushort_max = USHRT_MAX;
+ static int min_sndbuf = SOCK_MIN_SNDBUF;
+ static int min_rcvbuf = SOCK_MIN_RCVBUF;
+diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
+index 6bcaa33..568f9b3 100644
+--- a/net/dccp/ipv6.c
++++ b/net/dccp/ipv6.c
+@@ -238,7 +238,9 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req)
+ 	security_req_classify_flow(req, flowi6_to_flowi(&fl6));
+ 
+ 
+-	final_p = fl6_update_dst(&fl6, np->opt, &final);
++	rcu_read_lock();
++	final_p = fl6_update_dst(&fl6, rcu_dereference(np->opt), &final);
++	rcu_read_unlock();
+ 
+ 	dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
+ 	if (IS_ERR(dst)) {
+@@ -255,7 +257,10 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req)
+ 							 &ireq->ir_v6_loc_addr,
+ 							 &ireq->ir_v6_rmt_addr);
+ 		fl6.daddr = ireq->ir_v6_rmt_addr;
+-		err = ip6_xmit(sk, skb, &fl6, np->opt, np->tclass);
++		rcu_read_lock();
++		err = ip6_xmit(sk, skb, &fl6, rcu_dereference(np->opt),
++			       np->tclass);
++		rcu_read_unlock();
+ 		err = net_xmit_eval(err);
+ 	}
+ 
+@@ -450,6 +455,7 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
+ {
+ 	struct inet_request_sock *ireq = inet_rsk(req);
+ 	struct ipv6_pinfo *newnp, *np = inet6_sk(sk);
++	struct ipv6_txoptions *opt;
+ 	struct inet_sock *newinet;
+ 	struct dccp6_sock *newdp6;
+ 	struct sock *newsk;
+@@ -479,6 +485,9 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
+ 		newsk->sk_backlog_rcv = dccp_v4_do_rcv;
+ 		newnp->pktoptions  = NULL;
+ 		newnp->opt	   = NULL;
++		newnp->ipv6_mc_list = NULL;
++		newnp->ipv6_ac_list = NULL;
++		newnp->ipv6_fl_list = NULL;
+ 		newnp->mcast_oif   = inet6_iif(skb);
+ 		newnp->mcast_hops  = ipv6_hdr(skb)->hop_limit;
+ 
+@@ -554,6 +563,9 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
+ 	/* Clone RX bits */
+ 	newnp->rxopt.all = np->rxopt.all;
+ 
++	newnp->ipv6_mc_list = NULL;
++	newnp->ipv6_ac_list = NULL;
++	newnp->ipv6_fl_list = NULL;
+ 	/* Clone pktoptions received with SYN */
+ 	newnp->pktoptions = NULL;
+ 	if (ireq->pktopts != NULL) {
+@@ -573,13 +585,15 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
+ 	 * Yes, keeping reference count would be much more clever, but we make
+ 	 * one more one thing there: reattach optmem to newsk.
+ 	 */
+-	if (np->opt != NULL)
+-		newnp->opt = ipv6_dup_options(newsk, np->opt);
+-
++	opt = rcu_dereference(np->opt);
++	if (opt) {
++		opt = ipv6_dup_options(newsk, opt);
++		RCU_INIT_POINTER(newnp->opt, opt);
++	}
+ 	inet_csk(newsk)->icsk_ext_hdr_len = 0;
+-	if (newnp->opt != NULL)
+-		inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen +
+-						     newnp->opt->opt_flen);
++	if (opt)
++		inet_csk(newsk)->icsk_ext_hdr_len = opt->opt_nflen +
++						    opt->opt_flen;
+ 
+ 	dccp_sync_mss(newsk, dst_mtu(dst));
+ 
+@@ -832,6 +846,7 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
+ 	struct ipv6_pinfo *np = inet6_sk(sk);
+ 	struct dccp_sock *dp = dccp_sk(sk);
+ 	struct in6_addr *saddr = NULL, *final_p, final;
++	struct ipv6_txoptions *opt;
+ 	struct flowi6 fl6;
+ 	struct dst_entry *dst;
+ 	int addr_type;
+@@ -933,7 +948,8 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
+ 	fl6.fl6_sport = inet->inet_sport;
+ 	security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
+ 
+-	final_p = fl6_update_dst(&fl6, np->opt, &final);
++	opt = rcu_dereference_protected(np->opt, sock_owned_by_user(sk));
++	final_p = fl6_update_dst(&fl6, opt, &final);
+ 
+ 	dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
+ 	if (IS_ERR(dst)) {
+@@ -953,9 +969,8 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
+ 	__ip6_dst_store(sk, dst, NULL, NULL);
+ 
+ 	icsk->icsk_ext_hdr_len = 0;
+-	if (np->opt != NULL)
+-		icsk->icsk_ext_hdr_len = (np->opt->opt_flen +
+-					  np->opt->opt_nflen);
++	if (opt)
++		icsk->icsk_ext_hdr_len = opt->opt_flen + opt->opt_nflen;
+ 
+ 	inet->inet_dport = usin->sin6_port;
+ 
+diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c
+index 25733d5..2aeeb4f 100644
+--- a/net/decnet/af_decnet.c
++++ b/net/decnet/af_decnet.c
+@@ -678,6 +678,9 @@ static int dn_create(struct net *net, struct socket *sock, int protocol,
+ {
+ 	struct sock *sk;
+ 
++	if (protocol < 0 || protocol > SK_PROTOCOL_MAX)
++		return -EINVAL;
++
+ 	if (!net_eq(net, &init_net))
+ 		return -EAFNOSUPPORT;
+ 
+diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile
+index 518c04e..591745d 100644
+--- a/net/ipv4/Makefile
++++ b/net/ipv4/Makefile
+@@ -15,6 +15,7 @@ obj-y     := route.o inetpeer.o protocol.o \
+ 
+ obj-$(CONFIG_NET_IP_TUNNEL) += ip_tunnel.o
+ obj-$(CONFIG_SYSCTL) += sysctl_net_ipv4.o
++obj-$(CONFIG_SYSFS) += sysfs_net_ipv4.o
+ obj-$(CONFIG_PROC_FS) += proc.o
+ obj-$(CONFIG_IP_MULTIPLE_TABLES) += fib_rules.o
+ obj-$(CONFIG_IP_MROUTE) += ipmr.o
+diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
+index 9a17357..20a113a 100644
+--- a/net/ipv4/af_inet.c
++++ b/net/ipv4/af_inet.c
+@@ -119,6 +119,19 @@
+ #include <linux/mroute.h>
+ #endif
+ 
++#ifdef CONFIG_ANDROID_PARANOID_NETWORK
++#include <linux/android_aid.h>
++
++static inline int current_has_network(void)
++{
++	return in_egroup_p(AID_INET) || capable(CAP_NET_RAW);
++}
++#else
++static inline int current_has_network(void)
++{
++	return 1;
++}
++#endif
+ 
+ /* The inetsw table contains everything that inet_create needs to
+  * build a new socket.
+@@ -259,6 +272,12 @@ static int inet_create(struct net *net, struct socket *sock, int protocol,
+ 	int try_loading_module = 0;
+ 	int err;
+ 
++	if (protocol < 0 || protocol >= IPPROTO_MAX)
++		return -EINVAL;
++
++	if (!current_has_network())
++		return -EACCES;
++
+ 	sock->state = SS_UNCONNECTED;
+ 
+ 	/* Look for the requested type/protocol pair. */
+@@ -307,8 +326,7 @@ lookup_protocol:
+ 	}
+ 
+ 	err = -EPERM;
+-	if (sock->type == SOCK_RAW && !kern &&
+-	    !ns_capable(net->user_ns, CAP_NET_RAW))
++	if (sock->type == SOCK_RAW && !kern && !capable(CAP_NET_RAW))
+ 		goto out_rcu_unlock;
+ 
+ 	sock->ops = answer->ops;
+@@ -870,6 +888,7 @@ int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+ 	case SIOCSIFPFLAGS:
+ 	case SIOCGIFPFLAGS:
+ 	case SIOCSIFFLAGS:
++	case SIOCKILLADDR:
+ 		err = devinet_ioctl(net, cmd, (void __user *)arg);
+ 		break;
+ 	default:
+@@ -1388,6 +1407,19 @@ out:
+ 	return pp;
+ }
+ 
++static struct sk_buff **ipip_gro_receive(struct sk_buff **head,
++					 struct sk_buff *skb)
++{
++	if (NAPI_GRO_CB(skb)->encap_mark) {
++		NAPI_GRO_CB(skb)->flush = 1;
++		return NULL;
++	}
++
++	NAPI_GRO_CB(skb)->encap_mark = 1;
++
++	return inet_gro_receive(head, skb);
++}
++
+ int inet_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
+ {
+ 	if (sk->sk_family == AF_INET)
+@@ -1646,7 +1678,7 @@ static struct packet_offload ip_packet_offload __read_mostly = {
+ static const struct net_offload ipip_offload = {
+ 	.callbacks = {
+ 		.gso_segment	= inet_gso_segment,
+-		.gro_receive	= inet_gro_receive,
++		.gro_receive	= ipip_gro_receive,
+ 		.gro_complete	= inet_gro_complete,
+ 	},
+ };
+diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
+index 214882e..ac854e3 100644
+--- a/net/ipv4/devinet.c
++++ b/net/ipv4/devinet.c
+@@ -59,6 +59,7 @@
+ 
+ #include <net/arp.h>
+ #include <net/ip.h>
++#include <net/tcp.h>
+ #include <net/route.h>
+ #include <net/ip_fib.h>
+ #include <net/rtnetlink.h>
+@@ -334,6 +335,9 @@ static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
+ 
+ 	ASSERT_RTNL();
+ 
++	if (in_dev->dead)
++		goto no_promotions;
++
+ 	/* 1. Deleting primary ifaddr forces deletion all secondaries
+ 	 * unless alias promotion is set
+ 	 **/
+@@ -380,6 +384,7 @@ static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
+ 			fib_del_ifaddr(ifa, ifa1);
+ 	}
+ 
++no_promotions:
+ 	/* 2. Unlink it */
+ 
+ 	*ifap = ifa1->ifa_next;
+@@ -934,6 +939,7 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg)
+ 	case SIOCSIFBRDADDR:	/* Set the broadcast address */
+ 	case SIOCSIFDSTADDR:	/* Set the destination address */
+ 	case SIOCSIFNETMASK: 	/* Set the netmask for the interface */
++	case SIOCKILLADDR:	/* Nuke all sockets on this address */
+ 		ret = -EPERM;
+ 		if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
+ 			goto out;
+@@ -985,7 +991,8 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg)
+ 	}
+ 
+ 	ret = -EADDRNOTAVAIL;
+-	if (!ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS)
++	if (!ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS
++	    && cmd != SIOCKILLADDR)
+ 		goto done;
+ 
+ 	switch (cmd) {
+@@ -1112,6 +1119,9 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg)
+ 			inet_insert_ifa(ifa);
+ 		}
+ 		break;
++	case SIOCKILLADDR:	/* Nuke all connections on this address */
++		ret = tcp_nuke_addr(net, (struct sockaddr *) sin);
++		break;
+ 	}
+ done:
+ 	rtnl_unlock();
+diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
+index 23104a3..4a84e85 100644
+--- a/net/ipv4/fib_frontend.c
++++ b/net/ipv4/fib_frontend.c
+@@ -533,6 +533,7 @@ const struct nla_policy rtm_ipv4_policy[RTA_MAX + 1] = {
+ 	[RTA_METRICS]		= { .type = NLA_NESTED },
+ 	[RTA_MULTIPATH]		= { .len = sizeof(struct rtnexthop) },
+ 	[RTA_FLOW]		= { .type = NLA_U32 },
++	[RTA_UID]		= { .type = NLA_U32 },
+ };
+ 
+ static int rtm_to_fib_config(struct net *net, struct sk_buff *skb,
+@@ -814,6 +815,9 @@ void fib_del_ifaddr(struct in_ifaddr *ifa, struct in_ifaddr *iprim)
+ 		subnet = 1;
+ 	}
+ 
++	if (in_dev->dead)
++		goto no_promotions;
++
+ 	/* Deletion is more complicated than add.
+ 	 * We should take care of not to delete too much :-)
+ 	 *
+@@ -889,6 +893,7 @@ void fib_del_ifaddr(struct in_ifaddr *ifa, struct in_ifaddr *iprim)
+ 		}
+ 	}
+ 
++no_promotions:
+ 	if (!(ok & BRD_OK))
+ 		fib_magic(RTM_DELROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, prim);
+ 	if (subnet && ifa->ifa_prefixlen < 31) {
+diff --git a/net/ipv4/gre_offload.c b/net/ipv4/gre_offload.c
+index 51973dd..3c84285 100644
+--- a/net/ipv4/gre_offload.c
++++ b/net/ipv4/gre_offload.c
+@@ -127,6 +127,11 @@ static struct sk_buff **gre_gro_receive(struct sk_buff **head,
+ 	struct packet_offload *ptype;
+ 	__be16 type;
+ 
++	if (NAPI_GRO_CB(skb)->encap_mark)
++		goto out;
++
++	NAPI_GRO_CB(skb)->encap_mark = 1;
++
+ 	off = skb_gro_offset(skb);
+ 	hlen = off + sizeof(*greh);
+ 	greh = skb_gro_header_fast(skb, off);
+diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
+index 14d02ea..59270b7 100644
+--- a/net/ipv4/inet_connection_sock.c
++++ b/net/ipv4/inet_connection_sock.c
+@@ -410,7 +410,8 @@ struct dst_entry *inet_csk_route_req(struct sock *sk,
+ 			   sk->sk_protocol,
+ 			   flags,
+ 			   (opt && opt->opt.srr) ? opt->opt.faddr : ireq->ir_rmt_addr,
+-			   ireq->ir_loc_addr, ireq->ir_rmt_port, inet_sk(sk)->inet_sport);
++			   ireq->ir_loc_addr, ireq->ir_rmt_port, inet_sk(sk)->inet_sport,
++			   sock_i_uid(sk));
+ 	security_req_classify_flow(req, flowi4_to_flowi(fl4));
+ 	rt = ip_route_output_flow(net, fl4, sk);
+ 	if (IS_ERR(rt))
+@@ -446,7 +447,8 @@ struct dst_entry *inet_csk_route_child_sock(struct sock *sk,
+ 			   RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE,
+ 			   sk->sk_protocol, inet_sk_flowi_flags(sk),
+ 			   (opt && opt->opt.srr) ? opt->opt.faddr : ireq->ir_rmt_addr,
+-			   ireq->ir_loc_addr, ireq->ir_rmt_port, inet_sk(sk)->inet_sport);
++			   ireq->ir_loc_addr, ireq->ir_rmt_port, inet_sk(sk)->inet_sport,
++			   sock_i_uid(sk));
+ 	security_req_classify_flow(req, flowi4_to_flowi(fl4));
+ 	rt = ip_route_output_flow(net, fl4, sk);
+ 	if (IS_ERR(rt))
+@@ -677,6 +679,8 @@ struct sock *inet_csk_clone_lock(const struct sock *sk,
+ 		inet_sk(newsk)->inet_sport = htons(inet_rsk(req)->ir_num);
+ 		newsk->sk_write_space = sk_stream_write_space;
+ 
++		inet_sk(newsk)->mc_list = NULL;
++
+ 		newsk->sk_mark = inet_rsk(req)->ir_mark;
+ 
+ 		newicsk->icsk_retransmits = 0;
+diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
+index 357c2a9..a02b2d8 100644
+--- a/net/ipv4/ip_output.c
++++ b/net/ipv4/ip_output.c
+@@ -888,10 +888,12 @@ static int __ip_append_data(struct sock *sk,
+ 		csummode = CHECKSUM_PARTIAL;
+ 
+ 	cork->length += length;
+-	if (((length > mtu) || (skb && skb_is_gso(skb))) &&
++	if ((skb && skb_is_gso(skb)) ||
++	    (((length + (skb ? skb->len : fragheaderlen)) > mtu) &&
++	    (skb_queue_len(queue) <= 1) &&
+ 	    (sk->sk_protocol == IPPROTO_UDP) &&
+ 	    (rt->dst.dev->features & NETIF_F_UFO) && !rt->dst.header_len &&
+-	    (sk->sk_type == SOCK_DGRAM)) {
++	    (sk->sk_type == SOCK_DGRAM))) {
+ 		err = ip_ufo_append_data(sk, queue, getfrag, from, length,
+ 					 hh_len, fragheaderlen, transhdrlen,
+ 					 maxfraglen, flags);
+@@ -1207,6 +1209,7 @@ ssize_t	ip_append_page(struct sock *sk, struct flowi4 *fl4, struct page *page,
+ 
+ 	cork->length += size;
+ 	if ((size + skb->len > mtu) &&
++	    (skb_queue_len(&sk->sk_write_queue) == 1) &&
+ 	    (sk->sk_protocol == IPPROTO_UDP) &&
+ 	    (rt->dst.dev->features & NETIF_F_UFO)) {
+ 		skb_shinfo(skb)->gso_size = mtu - fragheaderlen;
+@@ -1544,7 +1547,8 @@ void ip_send_unicast_reply(struct sock *sk, struct sk_buff *skb,
+ 			   RT_SCOPE_UNIVERSE, ip_hdr(skb)->protocol,
+ 			   ip_reply_arg_flowi_flags(arg),
+ 			   daddr, saddr,
+-			   tcp_hdr(skb)->source, tcp_hdr(skb)->dest);
++			   tcp_hdr(skb)->source, tcp_hdr(skb)->dest,
++			   arg->uid);
+ 	security_skb_classify_flow(skb, flowi4_to_flowi(&fl4));
+ 	rt = ip_route_output_key(net, &fl4);
+ 	if (IS_ERR(rt))
+diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
+index 046fce0..8839b55 100644
+--- a/net/ipv4/ip_sockglue.c
++++ b/net/ipv4/ip_sockglue.c
+@@ -1066,7 +1066,14 @@ void ipv4_pktinfo_prepare(const struct sock *sk, struct sk_buff *skb)
+ 		pktinfo->ipi_ifindex = 0;
+ 		pktinfo->ipi_spec_dst.s_addr = 0;
+ 	}
+-	skb_dst_drop(skb);
++	/* We need to keep the dst for __ip_options_echo()
++	 * We could restrict the test to opt.ts_needtime || opt.srr,
++	 * but the following is good enough as IP options are not often used.
++	 */
++	if (unlikely(IPCB(skb)->opt.optlen))
++		skb_dst_force(skb);
++	else
++		skb_dst_drop(skb);
+ }
+ 
+ int ip_setsockopt(struct sock *sk, int level,
+diff --git a/net/ipv4/netfilter/nf_nat_masquerade_ipv4.c b/net/ipv4/netfilter/nf_nat_masquerade_ipv4.c
+index c6eb421..ea91058 100644
+--- a/net/ipv4/netfilter/nf_nat_masquerade_ipv4.c
++++ b/net/ipv4/netfilter/nf_nat_masquerade_ipv4.c
+@@ -108,10 +108,18 @@ static int masq_inet_event(struct notifier_block *this,
+ 			   unsigned long event,
+ 			   void *ptr)
+ {
+-	struct net_device *dev = ((struct in_ifaddr *)ptr)->ifa_dev->dev;
++	struct in_device *idev = ((struct in_ifaddr *)ptr)->ifa_dev;
+ 	struct netdev_notifier_info info;
+ 
+-	netdev_notifier_info_init(&info, dev);
++	/* The masq_dev_notifier will catch the case of the device going
++	 * down.  So if the inetdev is dead and being destroyed we have
++	 * no work to do.  Otherwise this is an individual address removal
++	 * and we have to perform the flush.
++	 */
++	if (idev->dead)
++		return NOTIFY_DONE;
++
++	netdev_notifier_info_init(&info, idev->dev);
+ 	return masq_device_event(this, event, &info);
+ }
+ 
+diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c
+index 64f4edb..ecda491 100644
+--- a/net/ipv4/ping.c
++++ b/net/ipv4/ping.c
+@@ -154,17 +154,18 @@ void ping_hash(struct sock *sk)
+ void ping_unhash(struct sock *sk)
+ {
+ 	struct inet_sock *isk = inet_sk(sk);
++
+ 	pr_debug("ping_unhash(isk=%p,isk->num=%u)\n", isk, isk->inet_num);
++	write_lock_bh(&ping_table.lock);
+ 	if (sk_hashed(sk)) {
+-		write_lock_bh(&ping_table.lock);
+ 		hlist_nulls_del(&sk->sk_nulls_node);
+ 		sk_nulls_node_init(&sk->sk_nulls_node);
+ 		sock_put(sk);
+ 		isk->inet_num = 0;
+ 		isk->inet_sport = 0;
+ 		sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
+-		write_unlock_bh(&ping_table.lock);
+ 	}
++	write_unlock_bh(&ping_table.lock);
+ }
+ EXPORT_SYMBOL_GPL(ping_unhash);
+ 
+@@ -789,7 +790,8 @@ static int ping_v4_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *m
+ 
+ 	flowi4_init_output(&fl4, ipc.oif, sk->sk_mark, tos,
+ 			   RT_SCOPE_UNIVERSE, sk->sk_protocol,
+-			   inet_sk_flowi_flags(sk), faddr, saddr, 0, 0);
++			   inet_sk_flowi_flags(sk), faddr, saddr, 0, 0,
++			   sock_i_uid(sk));
+ 
+ 	security_sk_classify_flow(sk, flowi4_to_flowi(&fl4));
+ 	rt = ip_route_output_flow(net, &fl4, sk);
+diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
+index 739db31..6167b55 100644
+--- a/net/ipv4/raw.c
++++ b/net/ipv4/raw.c
+@@ -582,7 +582,8 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
+ 			   inet->hdrincl ? IPPROTO_RAW : sk->sk_protocol,
+ 			   inet_sk_flowi_flags(sk) |
+ 			    (inet->hdrincl ? FLOWI_FLAG_KNOWN_NH : 0),
+-			   daddr, saddr, 0, 0);
++			   daddr, saddr, 0, 0,
++			   sock_i_uid(sk));
+ 
+ 	if (!inet->hdrincl) {
+ 		err = raw_probe_proto_opt(&fl4, msg);
+diff --git a/net/ipv4/route.c b/net/ipv4/route.c
+index b7ac498..f5174c8 100644
+--- a/net/ipv4/route.c
++++ b/net/ipv4/route.c
+@@ -499,7 +499,7 @@ void __ip_select_ident(struct iphdr *iph, int segs)
+ }
+ EXPORT_SYMBOL(__ip_select_ident);
+ 
+-static void __build_flow_key(struct flowi4 *fl4, const struct sock *sk,
++static void __build_flow_key(struct flowi4 *fl4, struct sock *sk,
+ 			     const struct iphdr *iph,
+ 			     int oif, u8 tos,
+ 			     u8 prot, u32 mark, int flow_flags)
+@@ -515,11 +515,12 @@ static void __build_flow_key(struct flowi4 *fl4, const struct sock *sk,
+ 	flowi4_init_output(fl4, oif, mark, tos,
+ 			   RT_SCOPE_UNIVERSE, prot,
+ 			   flow_flags,
+-			   iph->daddr, iph->saddr, 0, 0);
++			   iph->daddr, iph->saddr, 0, 0,
++			   sk ? sock_i_uid(sk) : GLOBAL_ROOT_UID);
+ }
+ 
+ static void build_skb_flow_key(struct flowi4 *fl4, const struct sk_buff *skb,
+-			       const struct sock *sk)
++			       struct sock *sk)
+ {
+ 	const struct iphdr *iph = ip_hdr(skb);
+ 	int oif = skb->dev->ifindex;
+@@ -530,7 +531,7 @@ static void build_skb_flow_key(struct flowi4 *fl4, const struct sk_buff *skb,
+ 	__build_flow_key(fl4, sk, iph, oif, tos, prot, mark, 0);
+ }
+ 
+-static void build_sk_flow_key(struct flowi4 *fl4, const struct sock *sk)
++static void build_sk_flow_key(struct flowi4 *fl4, struct sock *sk)
+ {
+ 	const struct inet_sock *inet = inet_sk(sk);
+ 	const struct ip_options_rcu *inet_opt;
+@@ -544,11 +545,12 @@ static void build_sk_flow_key(struct flowi4 *fl4, const struct sock *sk)
+ 			   RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE,
+ 			   inet->hdrincl ? IPPROTO_RAW : sk->sk_protocol,
+ 			   inet_sk_flowi_flags(sk),
+-			   daddr, inet->inet_saddr, 0, 0);
++			   daddr, inet->inet_saddr, 0, 0,
++			   sock_i_uid(sk));
+ 	rcu_read_unlock();
+ }
+ 
+-static void ip_rt_build_flow_key(struct flowi4 *fl4, const struct sock *sk,
++static void ip_rt_build_flow_key(struct flowi4 *fl4, struct sock *sk,
+ 				 const struct sk_buff *skb)
+ {
+ 	if (skb)
+@@ -2353,6 +2355,11 @@ static int rt_fill_info(struct net *net,  __be32 dst, __be32 src,
+ 	    nla_put_u32(skb, RTA_MARK, fl4->flowi4_mark))
+ 		goto nla_put_failure;
+ 
++	if (!uid_eq(fl4->flowi4_uid, INVALID_UID) &&
++	    nla_put_u32(skb, RTA_UID,
++			from_kuid_munged(current_user_ns(), fl4->flowi4_uid)))
++		goto nla_put_failure;
++
+ 	error = rt->dst.error;
+ 
+ 	if (rt_is_input_route(rt)) {
+@@ -2402,6 +2409,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh)
+ 	int err;
+ 	int mark;
+ 	struct sk_buff *skb;
++	kuid_t uid;
+ 
+ 	err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv4_policy);
+ 	if (err < 0)
+@@ -2429,6 +2437,10 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh)
+ 	dst = tb[RTA_DST] ? nla_get_be32(tb[RTA_DST]) : 0;
+ 	iif = tb[RTA_IIF] ? nla_get_u32(tb[RTA_IIF]) : 0;
+ 	mark = tb[RTA_MARK] ? nla_get_u32(tb[RTA_MARK]) : 0;
++	if (tb[RTA_UID])
++		uid = make_kuid(current_user_ns(), nla_get_u32(tb[RTA_UID]));
++	else
++		uid = (iif ? INVALID_UID : current_uid());
+ 
+ 	memset(&fl4, 0, sizeof(fl4));
+ 	fl4.daddr = dst;
+@@ -2436,6 +2448,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh)
+ 	fl4.flowi4_tos = rtm->rtm_tos;
+ 	fl4.flowi4_oif = tb[RTA_OIF] ? nla_get_u32(tb[RTA_OIF]) : 0;
+ 	fl4.flowi4_mark = mark;
++	fl4.flowi4_uid = uid;
+ 
+ 	if (iif) {
+ 		struct net_device *dev;
+diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c
+index 32b98d0..088b6ab 100644
+--- a/net/ipv4/syncookies.c
++++ b/net/ipv4/syncookies.c
+@@ -336,8 +336,9 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb)
+ 	flowi4_init_output(&fl4, sk->sk_bound_dev_if, ireq->ir_mark,
+ 			   RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE, IPPROTO_TCP,
+ 			   inet_sk_flowi_flags(sk),
+-			   opt->srr ? opt->faddr : ireq->ir_rmt_addr,
+-			   ireq->ir_loc_addr, th->source, th->dest);
++			   (opt && opt->srr) ? opt->faddr : ireq->ir_rmt_addr,
++			   ireq->ir_loc_addr, th->source, th->dest,
++			   sock_i_uid(sk));
+ 	security_req_classify_flow(req, flowi4_to_flowi(&fl4));
+ 	rt = ip_route_output_key(sock_net(sk), &fl4);
+ 	if (IS_ERR(rt)) {
+diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
+index b3c53c8..6aae73f 100644
+--- a/net/ipv4/sysctl_net_ipv4.c
++++ b/net/ipv4/sysctl_net_ipv4.c
+@@ -145,6 +145,21 @@ static int ipv4_ping_group_range(struct ctl_table *table, int write,
+ 	return ret;
+ }
+ 
++/* Validate changes from /proc interface. */
++static int proc_tcp_default_init_rwnd(struct ctl_table *ctl, int write,
++				      void __user *buffer,
++				      size_t *lenp, loff_t *ppos)
++{
++	int old_value = *(int *)ctl->data;
++	int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
++	int new_value = *(int *)ctl->data;
++
++	if (write && ret == 0 && (new_value < 3 || new_value > 100))
++		*(int *)ctl->data = old_value;
++
++	return ret;
++}
++
+ static int proc_tcp_congestion_control(struct ctl_table *ctl, int write,
+ 				       void __user *buffer, size_t *lenp, loff_t *ppos)
+ {
+@@ -722,6 +737,13 @@ static struct ctl_table ipv4_table[] = {
+ 		.extra2		= &one,
+ 	},
+ 	{
++		.procname       = "tcp_default_init_rwnd",
++		.data           = &sysctl_tcp_default_init_rwnd,
++		.maxlen         = sizeof(int),
++		.mode           = 0644,
++		.proc_handler   = proc_tcp_default_init_rwnd
++	},
++	{
+ 		.procname	= "icmp_msgs_per_sec",
+ 		.data		= &sysctl_icmp_msgs_per_sec,
+ 		.maxlen		= sizeof(int),
+diff --git a/net/ipv4/sysfs_net_ipv4.c b/net/ipv4/sysfs_net_ipv4.c
+new file mode 100644
+index 0000000..0cbbf10
+--- /dev/null
++++ b/net/ipv4/sysfs_net_ipv4.c
+@@ -0,0 +1,88 @@
++/*
++ * net/ipv4/sysfs_net_ipv4.c
++ *
++ * sysfs-based networking knobs (so we can, unlike with sysctl, control perms)
++ *
++ * Copyright (C) 2008 Google, Inc.
++ *
++ * Robert Love <rlove@google.com>
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/kobject.h>
++#include <linux/string.h>
++#include <linux/sysfs.h>
++#include <linux/init.h>
++#include <net/tcp.h>
++
++#define CREATE_IPV4_FILE(_name, _var) \
++static ssize_t _name##_show(struct kobject *kobj, \
++			    struct kobj_attribute *attr, char *buf) \
++{ \
++	return sprintf(buf, "%d\n", _var); \
++} \
++static ssize_t _name##_store(struct kobject *kobj, \
++			     struct kobj_attribute *attr, \
++			     const char *buf, size_t count) \
++{ \
++	int val, ret; \
++	ret = sscanf(buf, "%d", &val); \
++	if (ret != 1) \
++		return -EINVAL; \
++	if (val < 0) \
++		return -EINVAL; \
++	_var = val; \
++	return count; \
++} \
++static struct kobj_attribute _name##_attr = \
++	__ATTR(_name, 0644, _name##_show, _name##_store)
++
++CREATE_IPV4_FILE(tcp_wmem_min, sysctl_tcp_wmem[0]);
++CREATE_IPV4_FILE(tcp_wmem_def, sysctl_tcp_wmem[1]);
++CREATE_IPV4_FILE(tcp_wmem_max, sysctl_tcp_wmem[2]);
++
++CREATE_IPV4_FILE(tcp_rmem_min, sysctl_tcp_rmem[0]);
++CREATE_IPV4_FILE(tcp_rmem_def, sysctl_tcp_rmem[1]);
++CREATE_IPV4_FILE(tcp_rmem_max, sysctl_tcp_rmem[2]);
++
++static struct attribute *ipv4_attrs[] = {
++	&tcp_wmem_min_attr.attr,
++	&tcp_wmem_def_attr.attr,
++	&tcp_wmem_max_attr.attr,
++	&tcp_rmem_min_attr.attr,
++	&tcp_rmem_def_attr.attr,
++	&tcp_rmem_max_attr.attr,
++	NULL
++};
++
++static struct attribute_group ipv4_attr_group = {
++	.attrs = ipv4_attrs,
++};
++
++static __init int sysfs_ipv4_init(void)
++{
++	struct kobject *ipv4_kobject;
++	int ret;
++
++	ipv4_kobject = kobject_create_and_add("ipv4", kernel_kobj);
++	if (!ipv4_kobject)
++		return -ENOMEM;
++
++	ret = sysfs_create_group(ipv4_kobject, &ipv4_attr_group);
++	if (ret) {
++		kobject_put(ipv4_kobject);
++		return ret;
++	}
++
++	return 0;
++}
++
++subsys_initcall(sysfs_ipv4_init);
+diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
+index 32b25cc..5b1f544 100644
+--- a/net/ipv4/tcp.c
++++ b/net/ipv4/tcp.c
+@@ -268,12 +268,16 @@
+ #include <linux/crypto.h>
+ #include <linux/time.h>
+ #include <linux/slab.h>
++#include <linux/uid_stat.h>
+ 
+ #include <net/icmp.h>
+ #include <net/inet_common.h>
+ #include <net/tcp.h>
+ #include <net/xfrm.h>
+ #include <net/ip.h>
++#include <net/ip6_route.h>
++#include <net/ipv6.h>
++#include <net/transp_v6.h>
+ #include <net/sock.h>
+ 
+ #include <asm/uaccess.h>
+@@ -775,6 +779,12 @@ ssize_t tcp_splice_read(struct socket *sock, loff_t *ppos,
+ 				ret = -EAGAIN;
+ 				break;
+ 			}
++			/* if __tcp_splice_read() got nothing while we have
++			 * an skb in receive queue, we do not want to loop.
++			 * This might happen with URG data.
++			 */
++			if (!skb_queue_empty(&sk->sk_receive_queue))
++				break;
+ 			sk_wait_data(sk, &timeo);
+ 			if (signal_pending(current)) {
+ 				ret = sock_intr_errno(timeo);
+@@ -1298,6 +1308,10 @@ out:
+ 		tcp_push(sk, flags, mss_now, tp->nonagle, size_goal);
+ out_nopush:
+ 	release_sock(sk);
++
++	if (copied + copied_syn)
++		uid_stat_tcp_snd(from_kuid(&init_user_ns, current_uid()),
++				 copied + copied_syn);
+ 	return copied + copied_syn;
+ 
+ do_fault:
+@@ -1569,6 +1583,8 @@ int tcp_read_sock(struct sock *sk, read_descriptor_t *desc,
+ 	if (copied > 0) {
+ 		tcp_recv_skb(sk, seq, &offset);
+ 		tcp_cleanup_rbuf(sk, copied);
++		uid_stat_tcp_rcv(from_kuid(&init_user_ns, current_uid()),
++				 copied);
+ 	}
+ 	return copied;
+ }
+@@ -1898,6 +1914,10 @@ skip_copy:
+ 	tcp_cleanup_rbuf(sk, copied);
+ 
+ 	release_sock(sk);
++
++	if (copied > 0)
++		uid_stat_tcp_rcv(from_kuid(&init_user_ns, current_uid()),
++				 copied);
+ 	return copied;
+ 
+ out:
+@@ -1906,6 +1926,9 @@ out:
+ 
+ recv_urg:
+ 	err = tcp_recv_urg(sk, msg, len, flags);
++	if (err > 0)
++		uid_stat_tcp_rcv(from_kuid(&init_user_ns, current_uid()),
++				 err);
+ 	goto out;
+ 
+ recv_sndq:
+@@ -2256,6 +2279,10 @@ int tcp_disconnect(struct sock *sk, int flags)
+ 	tcp_set_ca_state(sk, TCP_CA_Open);
+ 	tcp_clear_retrans(tp);
+ 	inet_csk_delack_init(sk);
++	/* Initialize rcv_mss to TCP_MIN_MSS to avoid division by 0
++	 * issue in __tcp_select_window()
++	 */
++	icsk->icsk_ack.rcv_mss = TCP_MIN_MSS;
+ 	tcp_init_send_head(sk);
+ 	memset(&tp->rx_opt, 0, sizeof(tp->rx_opt));
+ 	__sk_dst_reset(sk);
+@@ -3128,3 +3155,117 @@ void __init tcp_init(void)
+ 	BUG_ON(tcp_register_congestion_control(&tcp_reno) != 0);
+ 	tcp_tasklet_init();
+ }
++
++static int tcp_is_local(struct net *net, __be32 addr) {
++	struct rtable *rt;
++	struct flowi4 fl4 = { .daddr = addr };
++	rt = ip_route_output_key(net, &fl4);
++	if (IS_ERR_OR_NULL(rt))
++		return 0;
++	return rt->dst.dev && (rt->dst.dev->flags & IFF_LOOPBACK);
++}
++
++#if defined(CONFIG_IPV6)
++static int tcp_is_local6(struct net *net, struct in6_addr *addr) {
++	struct rt6_info *rt6 = rt6_lookup(net, addr, addr, 0, 0);
++	return rt6 && rt6->dst.dev && (rt6->dst.dev->flags & IFF_LOOPBACK);
++}
++#endif
++
++/*
++ * tcp_nuke_addr - destroy all sockets on the given local address
++ * if local address is the unspecified address (0.0.0.0 or ::), destroy all
++ * sockets with local addresses that are not configured.
++ */
++int tcp_nuke_addr(struct net *net, struct sockaddr *addr)
++{
++	int family = addr->sa_family;
++	unsigned int bucket;
++
++	struct in_addr *in = NULL;
++#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
++	struct in6_addr *in6 = NULL;
++#endif
++	if (family == AF_INET) {
++		in = &((struct sockaddr_in *)addr)->sin_addr;
++#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
++	} else if (family == AF_INET6) {
++		in6 = &((struct sockaddr_in6 *)addr)->sin6_addr;
++#endif
++	} else {
++		return -EAFNOSUPPORT;
++	}
++
++	for (bucket = 0; bucket <= tcp_hashinfo.ehash_mask; bucket++) {
++		struct hlist_nulls_node *node;
++		struct sock *sk;
++		spinlock_t *lock = inet_ehash_lockp(&tcp_hashinfo, bucket);
++
++restart:
++		spin_lock_bh(lock);
++		sk_nulls_for_each(sk, node, &tcp_hashinfo.ehash[bucket].chain) {
++			struct inet_sock *inet = inet_sk(sk);
++
++			if (sk->sk_state == TCP_TIME_WAIT) {
++				/*
++				 * Sockets that are in TIME_WAIT state are
++				 * instances of lightweight inet_timewait_sock,
++				 * we should simply skip them (or we'll try to
++				 * access non-existing fields and crash).
++				 */
++				continue;
++			}
++
++			if (sysctl_ip_dynaddr && sk->sk_state == TCP_SYN_SENT)
++				continue;
++
++			if (sock_flag(sk, SOCK_DEAD))
++				continue;
++
++			if (family == AF_INET) {
++				__be32 s4 = inet->inet_rcv_saddr;
++				if (s4 == LOOPBACK4_IPV6)
++					continue;
++
++				if (in->s_addr != s4 &&
++				    !(in->s_addr == INADDR_ANY &&
++				      !tcp_is_local(net, s4)))
++					continue;
++			}
++
++#if defined(CONFIG_IPV6)
++			if (family == AF_INET6) {
++				struct in6_addr *s6;
++
++				s6 = &sk->sk_v6_rcv_saddr;
++				if (ipv6_addr_type(s6) == IPV6_ADDR_MAPPED)
++					continue;
++
++				if (!ipv6_addr_equal(in6, s6) &&
++				    !(ipv6_addr_equal(in6, &in6addr_any) &&
++				      !tcp_is_local6(net, s6)))
++				continue;
++			}
++#endif
++
++			sock_hold(sk);
++			spin_unlock_bh(lock);
++
++			local_bh_disable();
++			bh_lock_sock(sk);
++			sk->sk_err = ETIMEDOUT;
++			sk->sk_error_report(sk);
++
++			tcp_done(sk);
++			bh_unlock_sock(sk);
++			local_bh_enable();
++			sock_put(sk);
++
++			goto restart;
++		}
++		spin_unlock_bh(lock);
++	}
++
++	return 0;
++}
++EXPORT_SYMBOL_GPL(tcp_nuke_addr);
+diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
+index 6f46cde..7503171 100644
+--- a/net/ipv4/tcp_input.c
++++ b/net/ipv4/tcp_input.c
+@@ -88,7 +88,7 @@ int sysctl_tcp_adv_win_scale __read_mostly = 1;
+ EXPORT_SYMBOL(sysctl_tcp_adv_win_scale);
+ 
+ /* rfc5961 challenge ack rate limiting */
+-int sysctl_tcp_challenge_ack_limit = 100;
++int sysctl_tcp_challenge_ack_limit = 1000;
+ 
+ int sysctl_tcp_stdurg __read_mostly;
+ int sysctl_tcp_rfc1337 __read_mostly;
+@@ -99,6 +99,7 @@ int sysctl_tcp_thin_dupack __read_mostly;
+ 
+ int sysctl_tcp_moderate_rcvbuf __read_mostly = 1;
+ int sysctl_tcp_early_retrans __read_mostly = 3;
++int sysctl_tcp_default_init_rwnd __read_mostly = TCP_INIT_CWND * 2;
+ 
+ #define FLAG_DATA		0x01 /* Incoming frame contained data.		*/
+ #define FLAG_WIN_UPDATE		0x02 /* Incoming ACK was a window update.	*/
+@@ -2515,6 +2516,9 @@ static void tcp_cwnd_reduction(struct sock *sk, const int prior_unsacked,
+ 	int newly_acked_sacked = prior_unsacked -
+ 				 (tp->packets_out - tp->sacked_out);
+ 
++	if (newly_acked_sacked <= 0 || WARN_ON_ONCE(!tp->prior_cwnd))
++		return;
++
+ 	tp->prr_delivered += newly_acked_sacked;
+ 	if (tcp_packets_in_flight(tp) > tp->snd_ssthresh) {
+ 		u64 dividend = (u64)tp->snd_ssthresh * tp->prr_delivered +
+@@ -3324,13 +3328,18 @@ static void tcp_send_challenge_ack(struct sock *sk)
+ 	/* unprotected vars, we dont care of overwrites */
+ 	static u32 challenge_timestamp;
+ 	static unsigned int challenge_count;
+-	u32 now = jiffies / HZ;
++	u32 count, now = jiffies / HZ;
+ 
+ 	if (now != challenge_timestamp) {
++		u32 half = (sysctl_tcp_challenge_ack_limit + 1) >> 1;
++
+ 		challenge_timestamp = now;
+-		challenge_count = 0;
++		WRITE_ONCE(challenge_count, half +
++			   prandom_u32_max(sysctl_tcp_challenge_ack_limit));
+ 	}
+-	if (++challenge_count <= sysctl_tcp_challenge_ack_limit) {
++	count = READ_ONCE(challenge_count);
++	if (count > 0) {
++		WRITE_ONCE(challenge_count, count - 1);
+ 		NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPCHALLENGEACK);
+ 		tcp_send_ack(sk);
+ 	}
+diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
+index a5fdfe9..f7f2387 100644
+--- a/net/ipv4/tcp_ipv4.c
++++ b/net/ipv4/tcp_ipv4.c
+@@ -1580,6 +1580,21 @@ bool tcp_prequeue(struct sock *sk, struct sk_buff *skb)
+ }
+ EXPORT_SYMBOL(tcp_prequeue);
+ 
++int tcp_filter(struct sock *sk, struct sk_buff *skb)
++{
++	struct tcphdr *th = (struct tcphdr *)skb->data;
++	unsigned int eaten = skb->len;
++	int err;
++
++	err = sk_filter_trim_cap(sk, skb, th->doff * 4);
++	if (!err) {
++		eaten -= skb->len;
++		TCP_SKB_CB(skb)->end_seq -= eaten;
++	}
++	return err;
++}
++EXPORT_SYMBOL(tcp_filter);
++
+ /*
+  *	From tcp_input.c
+  */
+@@ -1663,8 +1678,10 @@ process:
+ 
+ 	nf_reset(skb);
+ 
+-	if (sk_filter(sk, skb))
++	if (tcp_filter(sk, skb))
+ 		goto discard_and_relse;
++	th = (const struct tcphdr *)skb->data;
++	iph = ip_hdr(skb);
+ 
+ 	sk_mark_napi_id(sk, skb);
+ 	skb->dev = NULL;
+diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
+index dc9f925..c07062b 100644
+--- a/net/ipv4/tcp_output.c
++++ b/net/ipv4/tcp_output.c
+@@ -197,7 +197,7 @@ u32 tcp_default_init_rwnd(u32 mss)
+ 	 * (RFC 3517, Section 4, NextSeg() rule (2)). Further place a
+ 	 * limit when mss is larger than 1460.
+ 	 */
+-	u32 init_rwnd = TCP_INIT_CWND * 2;
++	u32 init_rwnd = sysctl_tcp_default_init_rwnd;
+ 
+ 	if (mss > 1460)
+ 		init_rwnd = max((1460 * init_rwnd) / mss, 2U);
+diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
+index c5e3194..68ed1ab 100644
+--- a/net/ipv4/udp.c
++++ b/net/ipv4/udp.c
+@@ -804,7 +804,7 @@ static int udp_send_skb(struct sk_buff *skb, struct flowi4 *fl4)
+ 	if (is_udplite)  				 /*     UDP-Lite      */
+ 		csum = udplite_csum(skb);
+ 
+-	else if (sk->sk_no_check_tx) {   /* UDP csum disabled */
++	else if (sk->sk_no_check_tx && !skb_is_gso(skb)) {   /* UDP csum off */
+ 
+ 		skb->ip_summed = CHECKSUM_NONE;
+ 		goto send;
+@@ -1007,7 +1007,8 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
+ 		flowi4_init_output(fl4, ipc.oif, sk->sk_mark, tos,
+ 				   RT_SCOPE_UNIVERSE, sk->sk_protocol,
+ 				   inet_sk_flowi_flags(sk),
+-				   faddr, saddr, dport, inet->inet_sport);
++				   faddr, saddr, dport, inet->inet_sport,
++				   sock_i_uid(sk));
+ 
+ 		security_sk_classify_flow(sk, flowi4_to_flowi(fl4));
+ 		rt = ip_route_output_flow(net, fl4, sk);
+@@ -1252,6 +1253,7 @@ int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
+ 	int peeked, off = 0;
+ 	int err;
+ 	int is_udplite = IS_UDPLITE(sk);
++	bool checksum_valid = false;
+ 	bool slow;
+ 
+ 	if (flags & MSG_ERRQUEUE)
+@@ -1277,11 +1279,12 @@ try_again:
+ 	 */
+ 
+ 	if (copied < ulen || UDP_SKB_CB(skb)->partial_cov) {
+-		if (udp_lib_checksum_complete(skb))
++		checksum_valid = !udp_lib_checksum_complete(skb);
++		if (!checksum_valid)
+ 			goto csum_copy_err;
+ 	}
+ 
+-	if (skb_csum_unnecessary(skb))
++	if (checksum_valid || skb_csum_unnecessary(skb))
+ 		err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr),
+ 					      msg->msg_iov, copied);
+ 	else {
+diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c
+index 6480cea..e6d05ae 100644
+--- a/net/ipv4/udp_offload.c
++++ b/net/ipv4/udp_offload.c
+@@ -266,14 +266,14 @@ struct sk_buff **udp_gro_receive(struct sk_buff **head, struct sk_buff *skb,
+ 	unsigned int off = skb_gro_offset(skb);
+ 	int flush = 1;
+ 
+-	if (NAPI_GRO_CB(skb)->udp_mark ||
++	if (NAPI_GRO_CB(skb)->encap_mark ||
+ 	    (skb->ip_summed != CHECKSUM_PARTIAL &&
+ 	     NAPI_GRO_CB(skb)->csum_cnt == 0 &&
+ 	     !NAPI_GRO_CB(skb)->csum_valid))
+ 		goto out;
+ 
+-	/* mark that this skb passed once through the udp gro layer */
+-	NAPI_GRO_CB(skb)->udp_mark = 1;
++	/* mark that this skb passed once through the tunnel gro layer */
++	NAPI_GRO_CB(skb)->encap_mark = 1;
+ 
+ 	rcu_read_lock();
+ 	uo_priv = rcu_dereference(udp_offload_base);
+diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
+index 17a0258..0bd85d0 100644
+--- a/net/ipv6/addrconf.c
++++ b/net/ipv6/addrconf.c
+@@ -196,6 +196,7 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = {
+ 	.accept_ra_rt_info_max_plen = 0,
+ #endif
+ #endif
++	.accept_ra_rt_table	= 0,
+ 	.proxy_ndp		= 0,
+ 	.accept_source_route	= 0,	/* we do not accept RH0 by default. */
+ 	.disable_ipv6		= 0,
+@@ -233,6 +234,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
+ 	.accept_ra_rt_info_max_plen = 0,
+ #endif
+ #endif
++	.accept_ra_rt_table	= 0,
+ 	.proxy_ndp		= 0,
+ 	.accept_source_route	= 0,	/* we do not accept RH0 by default. */
+ 	.disable_ipv6		= 0,
+@@ -1170,6 +1172,9 @@ enum {
+ 	IPV6_SADDR_RULE_PRIVACY,
+ 	IPV6_SADDR_RULE_ORCHID,
+ 	IPV6_SADDR_RULE_PREFIX,
++#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
++	IPV6_SADDR_RULE_NOT_OPTIMISTIC,
++#endif
+ 	IPV6_SADDR_RULE_MAX
+ };
+ 
+@@ -1197,6 +1202,15 @@ static inline int ipv6_saddr_preferred(int type)
+ 	return 0;
+ }
+ 
++static inline bool ipv6_use_optimistic_addr(struct inet6_dev *idev)
++{
++#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
++	return idev && idev->cnf.optimistic_dad && idev->cnf.use_optimistic;
++#else
++	return false;
++#endif
++}
++
+ static int ipv6_get_saddr_eval(struct net *net,
+ 			       struct ipv6_saddr_score *score,
+ 			       struct ipv6_saddr_dst *dst,
+@@ -1257,10 +1271,16 @@ static int ipv6_get_saddr_eval(struct net *net,
+ 		score->scopedist = ret;
+ 		break;
+ 	case IPV6_SADDR_RULE_PREFERRED:
++	    {
+ 		/* Rule 3: Avoid deprecated and optimistic addresses */
++		u8 avoid = IFA_F_DEPRECATED;
++
++		if (!ipv6_use_optimistic_addr(score->ifa->idev))
++			avoid |= IFA_F_OPTIMISTIC;
+ 		ret = ipv6_saddr_preferred(score->addr_type) ||
+-		      !(score->ifa->flags & (IFA_F_DEPRECATED|IFA_F_OPTIMISTIC));
++		      !(score->ifa->flags & avoid);
+ 		break;
++	    }
+ #ifdef CONFIG_IPV6_MIP6
+ 	case IPV6_SADDR_RULE_HOA:
+ 	    {
+@@ -1306,6 +1326,14 @@ static int ipv6_get_saddr_eval(struct net *net,
+ 			ret = score->ifa->prefix_len;
+ 		score->matchlen = ret;
+ 		break;
++#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
++	case IPV6_SADDR_RULE_NOT_OPTIMISTIC:
++		/* Optimistic addresses still have lower precedence than other
++		 * preferred addresses.
++		 */
++		ret = !(score->ifa->flags & IFA_F_OPTIMISTIC);
++		break;
++#endif
+ 	default:
+ 		ret = 0;
+ 	}
+@@ -1503,7 +1531,9 @@ int ipv6_chk_addr(struct net *net, const struct in6_addr *addr,
+ 		if (!net_eq(dev_net(ifp->idev->dev), net))
+ 			continue;
+ 		if (ipv6_addr_equal(&ifp->addr, addr) &&
+-		    !(ifp->flags&IFA_F_TENTATIVE) &&
++		    (!(ifp->flags&IFA_F_TENTATIVE) ||
++		     (ipv6_use_optimistic_addr(ifp->idev) &&
++		      ifp->flags&IFA_F_OPTIMISTIC)) &&
+ 		    (dev == NULL || ifp->idev->dev == dev ||
+ 		     !(ifp->scope&(IFA_LINK|IFA_HOST) || strict))) {
+ 			rcu_read_unlock_bh();
+@@ -1966,6 +1996,31 @@ static void  __ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmp
+ 		__ipv6_regen_rndid(idev);
+ }
+ 
++u32 addrconf_rt_table(const struct net_device *dev, u32 default_table) {
++	/* Determines into what table to put autoconf PIO/RIO/default routes
++	 * learned on this device.
++	 *
++	 * - If 0, use the same table for every device. This puts routes into
++	 *   one of RT_TABLE_{PREFIX,INFO,DFLT} depending on the type of route
++	 *   (but note that these three are currently all equal to
++	 *   RT6_TABLE_MAIN).
++	 * - If > 0, use the specified table.
++	 * - If < 0, put routes into table dev->ifindex + (-rt_table).
++	 */
++	struct inet6_dev *idev = in6_dev_get(dev);
++	u32 table;
++	int sysctl = idev->cnf.accept_ra_rt_table;
++	if (sysctl == 0) {
++		table = default_table;
++	} else if (sysctl > 0) {
++		table = (u32) sysctl;
++	} else {
++		table = (unsigned) dev->ifindex + (-sysctl);
++	}
++	in6_dev_put(idev);
++	return table;
++}
++
+ /*
+  *	Add prefix route.
+  */
+@@ -1975,7 +2030,7 @@ addrconf_prefix_route(struct in6_addr *pfx, int plen, struct net_device *dev,
+ 		      unsigned long expires, u32 flags)
+ {
+ 	struct fib6_config cfg = {
+-		.fc_table = RT6_TABLE_PREFIX,
++		.fc_table = addrconf_rt_table(dev, RT6_TABLE_PREFIX),
+ 		.fc_metric = IP6_RT_PRIO_ADDRCONF,
+ 		.fc_ifindex = dev->ifindex,
+ 		.fc_expires = expires,
+@@ -2009,7 +2064,8 @@ static struct rt6_info *addrconf_get_prefix_route(const struct in6_addr *pfx,
+ 	struct rt6_info *rt = NULL;
+ 	struct fib6_table *table;
+ 
+-	table = fib6_get_table(dev_net(dev), RT6_TABLE_PREFIX);
++	table = fib6_get_table(dev_net(dev),
++			       addrconf_rt_table(dev, RT6_TABLE_PREFIX));
+ 	if (table == NULL)
+ 		return NULL;
+ 
+@@ -3222,8 +3278,15 @@ static void addrconf_dad_begin(struct inet6_ifaddr *ifp)
+ 	 * Optimistic nodes can start receiving
+ 	 * Frames right away
+ 	 */
+-	if (ifp->flags & IFA_F_OPTIMISTIC)
++	if (ifp->flags & IFA_F_OPTIMISTIC) {
+ 		ip6_ins_rt(ifp->rt);
++		if (ipv6_use_optimistic_addr(idev)) {
++			/* Because optimistic nodes can use this address,
++			 * notify listeners. If DAD fails, RTM_DELADDR is sent.
++			 */
++			ipv6_ifa_notify(RTM_NEWADDR, ifp);
++		}
++	}
+ 
+ 	addrconf_dad_kick(ifp);
+ out:
+@@ -4326,10 +4389,12 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
+ 	array[DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN] = cnf->accept_ra_rt_info_max_plen;
+ #endif
+ #endif
++	array[DEVCONF_ACCEPT_RA_RT_TABLE] = cnf->accept_ra_rt_table;
+ 	array[DEVCONF_PROXY_NDP] = cnf->proxy_ndp;
+ 	array[DEVCONF_ACCEPT_SOURCE_ROUTE] = cnf->accept_source_route;
+ #ifdef CONFIG_IPV6_OPTIMISTIC_DAD
+ 	array[DEVCONF_OPTIMISTIC_DAD] = cnf->optimistic_dad;
++	array[DEVCONF_USE_OPTIMISTIC] = cnf->use_optimistic;
+ #endif
+ #ifdef CONFIG_IPV6_MROUTE
+ 	array[DEVCONF_MC_FORWARDING] = cnf->mc_forwarding;
+@@ -4843,6 +4908,21 @@ int addrconf_sysctl_forward(struct ctl_table *ctl, int write,
+ 	return ret;
+ }
+ 
++static
++int addrconf_sysctl_mtu(struct ctl_table *ctl, int write,
++			void __user *buffer, size_t *lenp, loff_t *ppos)
++{
++	struct inet6_dev *idev = ctl->extra1;
++	int min_mtu = IPV6_MIN_MTU;
++	struct ctl_table lctl;
++	
++	lctl = *ctl;
++	lctl.extra1 = &min_mtu;
++	lctl.extra2 = idev ? &idev->dev->mtu : NULL;
++	
++	return proc_dointvec_minmax(&lctl, write, buffer, lenp, ppos);
++}
++
+ static void dev_disable_change(struct inet6_dev *idev)
+ {
+ 	struct netdev_notifier_info info;
+@@ -4994,7 +5074,7 @@ static struct addrconf_sysctl_table
+ 			.data		= &ipv6_devconf.mtu6,
+ 			.maxlen		= sizeof(int),
+ 			.mode		= 0644,
+-			.proc_handler	= proc_dointvec,
++			.proc_handler	= addrconf_sysctl_mtu,
+ 		},
+ 		{
+ 			.procname	= "accept_ra",
+@@ -5150,6 +5230,13 @@ static struct addrconf_sysctl_table
+ #endif
+ #endif
+ 		{
++			.procname	= "accept_ra_rt_table",
++			.data		= &ipv6_devconf.accept_ra_rt_table,
++			.maxlen		= sizeof(int),
++			.mode		= 0644,
++			.proc_handler	= proc_dointvec,
++		},
++		{
+ 			.procname	= "proxy_ndp",
+ 			.data		= &ipv6_devconf.proxy_ndp,
+ 			.maxlen		= sizeof(int),
+@@ -5172,6 +5259,14 @@ static struct addrconf_sysctl_table
+ 			.proc_handler   = proc_dointvec,
+ 
+ 		},
++		{
++			.procname       = "use_optimistic",
++			.data           = &ipv6_devconf.use_optimistic,
++			.maxlen         = sizeof(int),
++			.mode           = 0644,
++			.proc_handler   = proc_dointvec,
++
++		},
+ #endif
+ #ifdef CONFIG_IPV6_MROUTE
+ 		{
+diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
+index e8c4400..5615dde 100644
+--- a/net/ipv6/af_inet6.c
++++ b/net/ipv6/af_inet6.c
+@@ -64,6 +64,20 @@
+ #include <asm/uaccess.h>
+ #include <linux/mroute6.h>
+ 
++#ifdef CONFIG_ANDROID_PARANOID_NETWORK
++#include <linux/android_aid.h>
++
++static inline int current_has_network(void)
++{
++	return in_egroup_p(AID_INET) || capable(CAP_NET_RAW);
++}
++#else
++static inline int current_has_network(void)
++{
++	return 1;
++}
++#endif
++
+ MODULE_AUTHOR("Cast of dozens");
+ MODULE_DESCRIPTION("IPv6 protocol stack for Linux");
+ MODULE_LICENSE("GPL");
+@@ -109,6 +123,12 @@ static int inet6_create(struct net *net, struct socket *sock, int protocol,
+ 	int try_loading_module = 0;
+ 	int err;
+ 
++	if (protocol < 0 || protocol >= IPPROTO_MAX)
++		return -EINVAL;
++
++	if (!current_has_network())
++		return -EACCES;
++
+ 	/* Look for the requested type/protocol pair. */
+ lookup_protocol:
+ 	err = -ESOCKTNOSUPPORT;
+@@ -155,8 +175,7 @@ lookup_protocol:
+ 	}
+ 
+ 	err = -EPERM;
+-	if (sock->type == SOCK_RAW && !kern &&
+-	    !ns_capable(net->user_ns, CAP_NET_RAW))
++	if (sock->type == SOCK_RAW && !kern && !capable(CAP_NET_RAW))
+ 		goto out_rcu_unlock;
+ 
+ 	sock->ops = answer->ops;
+@@ -425,9 +444,11 @@ void inet6_destroy_sock(struct sock *sk)
+ 
+ 	/* Free tx options */
+ 
+-	opt = xchg(&np->opt, NULL);
+-	if (opt != NULL)
+-		sock_kfree_s(sk, opt, opt->tot_len);
++	opt = xchg((__force struct ipv6_txoptions **)&np->opt, NULL);
++	if (opt) {
++		atomic_sub(opt->tot_len, &sk->sk_omem_alloc);
++		txopt_put(opt);
++	}
+ }
+ EXPORT_SYMBOL_GPL(inet6_destroy_sock);
+ 
+@@ -471,6 +492,21 @@ int inet6_getname(struct socket *sock, struct sockaddr *uaddr,
+ }
+ EXPORT_SYMBOL(inet6_getname);
+ 
++int inet6_killaddr_ioctl(struct net *net, void __user *arg) {
++	struct in6_ifreq ireq;
++	struct sockaddr_in6 sin6;
++
++	if (!capable(CAP_NET_ADMIN))
++		return -EACCES;
++
++	if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq)))
++		return -EFAULT;
++
++	sin6.sin6_family = AF_INET6;
++	sin6.sin6_addr = ireq.ifr6_addr;
++	return tcp_nuke_addr(net, (struct sockaddr *) &sin6);
++}
++
+ int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+ {
+ 	struct sock *sk = sock->sk;
+@@ -494,6 +530,8 @@ int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+ 		return addrconf_del_ifaddr(net, (void __user *) arg);
+ 	case SIOCSIFDSTADDR:
+ 		return addrconf_set_dstaddr(net, (void __user *) arg);
++	case SIOCKILLADDR:
++		return inet6_killaddr_ioctl(net, (void __user *) arg);
+ 	default:
+ 		if (!sk->sk_prot->ioctl)
+ 			return -ENOIOCTLCMD;
+@@ -654,9 +692,13 @@ int inet6_sk_rebuild_header(struct sock *sk)
+ 		fl6.flowi6_mark = sk->sk_mark;
+ 		fl6.fl6_dport = inet->inet_dport;
+ 		fl6.fl6_sport = inet->inet_sport;
++		fl6.flowi6_uid = sock_i_uid(sk);
+ 		security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
+ 
+-		final_p = fl6_update_dst(&fl6, np->opt, &final);
++		rcu_read_lock();
++		final_p = fl6_update_dst(&fl6, rcu_dereference(np->opt),
++					 &final);
++		rcu_read_unlock();
+ 
+ 		dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
+ 		if (IS_ERR(dst)) {
+diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c
+index 6d16eb0..bb93d3b 100644
+--- a/net/ipv6/ah6.c
++++ b/net/ipv6/ah6.c
+@@ -662,7 +662,7 @@ static int ah6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+ 	if (type == NDISC_REDIRECT)
+ 		ip6_redirect(skb, net, skb->dev->ifindex, 0);
+ 	else
+-		ip6_update_pmtu(skb, net, info, 0, 0);
++		ip6_update_pmtu(skb, net, info, 0, 0, INVALID_UID);
+ 	xfrm_state_put(x);
+ 
+ 	return 0;
+diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
+index 11e3945..7626716 100644
+--- a/net/ipv6/datagram.c
++++ b/net/ipv6/datagram.c
+@@ -161,14 +161,17 @@ ipv4_connected:
+ 	fl6.flowi6_mark = sk->sk_mark;
+ 	fl6.fl6_dport = inet->inet_dport;
+ 	fl6.fl6_sport = inet->inet_sport;
++	fl6.flowi6_uid = sock_i_uid(sk);
+ 
+ 	if (!fl6.flowi6_oif && (addr_type&IPV6_ADDR_MULTICAST))
+ 		fl6.flowi6_oif = np->mcast_oif;
+ 
+ 	security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
+ 
+-	opt = flowlabel ? flowlabel->opt : np->opt;
++	rcu_read_lock();
++	opt = flowlabel ? flowlabel->opt : rcu_dereference(np->opt);
+ 	final_p = fl6_update_dst(&fl6, opt, &final);
++	rcu_read_unlock();
+ 
+ 	dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
+ 	err = 0;
+diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c
+index 83fc3a3..0958354 100644
+--- a/net/ipv6/esp6.c
++++ b/net/ipv6/esp6.c
+@@ -441,7 +441,7 @@ static int esp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+ 	if (type == NDISC_REDIRECT)
+ 		ip6_redirect(skb, net, skb->dev->ifindex, 0);
+ 	else
+-		ip6_update_pmtu(skb, net, info, 0, 0);
++		ip6_update_pmtu(skb, net, info, 0, 0, INVALID_UID);
+ 	xfrm_state_put(x);
+ 
+ 	return 0;
+diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
+index bfde361..4f08a0f 100644
+--- a/net/ipv6/exthdrs.c
++++ b/net/ipv6/exthdrs.c
+@@ -727,6 +727,7 @@ ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt)
+ 			*((char **)&opt2->dst1opt) += dif;
+ 		if (opt2->srcrt)
+ 			*((char **)&opt2->srcrt) += dif;
++		atomic_set(&opt2->refcnt, 1);
+ 	}
+ 	return opt2;
+ }
+@@ -790,7 +791,7 @@ ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt,
+ 		return ERR_PTR(-ENOBUFS);
+ 
+ 	memset(opt2, 0, tot_len);
+-
++	atomic_set(&opt2->refcnt, 1);
+ 	opt2->tot_len = tot_len;
+ 	p = (char *)(opt2 + 1);
+ 
+diff --git a/net/ipv6/exthdrs_core.c b/net/ipv6/exthdrs_core.c
+index 8af3eb5..958a187 100644
+--- a/net/ipv6/exthdrs_core.c
++++ b/net/ipv6/exthdrs_core.c
+@@ -166,15 +166,15 @@ EXPORT_SYMBOL_GPL(ipv6_find_tlv);
+  * to explore inner IPv6 header, eg. ICMPv6 error messages.
+  *
+  * If target header is found, its offset is set in *offset and return protocol
+- * number. Otherwise, return -1.
++ * number. Otherwise, return -ENOENT or -EBADMSG.
+  *
+  * If the first fragment doesn't contain the final protocol header or
+  * NEXTHDR_NONE it is considered invalid.
+  *
+  * Note that non-1st fragment is special case that "the protocol number
+  * of last header" is "next header" field in Fragment header. In this case,
+- * *offset is meaningless and fragment offset is stored in *fragoff if fragoff
+- * isn't NULL.
++ * *offset is meaningless. If fragoff is not NULL, the fragment offset is
++ * stored in *fragoff; if it is NULL, return -EINVAL.
+  *
+  * if flags is not NULL and it's a fragment, then the frag flag
+  * IP6_FH_F_FRAG will be set. If it's an AH header, the
+@@ -253,9 +253,12 @@ int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
+ 				if (target < 0 &&
+ 				    ((!ipv6_ext_hdr(hp->nexthdr)) ||
+ 				     hp->nexthdr == NEXTHDR_NONE)) {
+-					if (fragoff)
++					if (fragoff) {
+ 						*fragoff = _frag_off;
+-					return hp->nexthdr;
++						return hp->nexthdr;
++					} else {
++						return -EINVAL;
++					}
+ 				}
+ 				return -ENOENT;
+ 			}
+diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
+index 97ae700..070d591 100644
+--- a/net/ipv6/icmp.c
++++ b/net/ipv6/icmp.c
+@@ -91,7 +91,7 @@ static void icmpv6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+ 	struct net *net = dev_net(skb->dev);
+ 
+ 	if (type == ICMPV6_PKT_TOOBIG)
+-		ip6_update_pmtu(skb, net, info, 0, 0);
++		ip6_update_pmtu(skb, net, info, 0, 0, INVALID_UID);
+ 	else if (type == NDISC_REDIRECT)
+ 		ip6_redirect(skb, net, skb->dev->ifindex, 0);
+ 
+diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c
+index 29b3220..ca655c9 100644
+--- a/net/ipv6/inet6_connection_sock.c
++++ b/net/ipv6/inet6_connection_sock.c
+@@ -77,12 +77,15 @@ struct dst_entry *inet6_csk_route_req(struct sock *sk,
+ 	memset(fl6, 0, sizeof(*fl6));
+ 	fl6->flowi6_proto = IPPROTO_TCP;
+ 	fl6->daddr = ireq->ir_v6_rmt_addr;
+-	final_p = fl6_update_dst(fl6, np->opt, &final);
++	rcu_read_lock();
++	final_p = fl6_update_dst(fl6, rcu_dereference(np->opt), &final);
++	rcu_read_unlock();
+ 	fl6->saddr = ireq->ir_v6_loc_addr;
+ 	fl6->flowi6_oif = ireq->ir_iif;
+ 	fl6->flowi6_mark = ireq->ir_mark;
+ 	fl6->fl6_dport = ireq->ir_rmt_port;
+ 	fl6->fl6_sport = htons(ireq->ir_num);
++	fl6->flowi6_uid = sock_i_uid(sk);
+ 	security_req_classify_flow(req, flowi6_to_flowi(fl6));
+ 
+ 	dst = ip6_dst_lookup_flow(sk, fl6, final_p);
+@@ -206,9 +209,12 @@ static struct dst_entry *inet6_csk_route_socket(struct sock *sk,
+ 	fl6->flowi6_mark = sk->sk_mark;
+ 	fl6->fl6_sport = inet->inet_sport;
+ 	fl6->fl6_dport = inet->inet_dport;
++	fl6->flowi6_uid = sock_i_uid(sk);
+ 	security_sk_classify_flow(sk, flowi6_to_flowi(fl6));
+ 
+-	final_p = fl6_update_dst(fl6, np->opt, &final);
++	rcu_read_lock();
++	final_p = fl6_update_dst(fl6, rcu_dereference(np->opt), &final);
++	rcu_read_unlock();
+ 
+ 	dst = __inet6_csk_dst_check(sk, np->dst_cookie);
+ 	if (!dst) {
+@@ -241,7 +247,8 @@ int inet6_csk_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl_unused
+ 	/* Restore final destination back after routing done */
+ 	fl6.daddr = sk->sk_v6_daddr;
+ 
+-	res = ip6_xmit(sk, skb, &fl6, np->opt, np->tclass);
++	res = ip6_xmit(sk, skb, &fl6, rcu_dereference(np->opt),
++		       np->tclass);
+ 	rcu_read_unlock();
+ 	return res;
+ }
+diff --git a/net/ipv6/ip6_offload.c b/net/ipv6/ip6_offload.c
+index 01e12d0..bb39292 100644
+--- a/net/ipv6/ip6_offload.c
++++ b/net/ipv6/ip6_offload.c
+@@ -122,6 +122,8 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb,
+ 
+ 		if (udpfrag) {
+ 			unfrag_ip6hlen = ip6_find_1stfragopt(skb, &prevhdr);
++			if (unfrag_ip6hlen < 0)
++				return ERR_PTR(unfrag_ip6hlen);
+ 			fptr = (struct frag_hdr *)((u8 *)ipv6h + unfrag_ip6hlen);
+ 			fptr->frag_off = htons(offset);
+ 			if (skb->next != NULL)
+@@ -258,6 +260,19 @@ out:
+ 	return pp;
+ }
+ 
++static struct sk_buff **sit_gro_receive(struct sk_buff **head,
++					struct sk_buff *skb)
++{
++	if (NAPI_GRO_CB(skb)->encap_mark) {
++		NAPI_GRO_CB(skb)->flush = 1;
++		return NULL;
++	}
++
++	NAPI_GRO_CB(skb)->encap_mark = 1;
++
++	return ipv6_gro_receive(head, skb);
++}
++
+ static int ipv6_gro_complete(struct sk_buff *skb, int nhoff)
+ {
+ 	const struct net_offload *ops;
+@@ -292,7 +307,7 @@ static struct packet_offload ipv6_packet_offload __read_mostly = {
+ static const struct net_offload sit_offload = {
+ 	.callbacks = {
+ 		.gso_segment	= ipv6_gso_segment,
+-		.gro_receive	= ipv6_gro_receive,
++		.gro_receive	= sit_gro_receive,
+ 		.gro_complete	= ipv6_gro_complete,
+ 	},
+ };
+diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
+index 7b5cb00..3a48040 100644
+--- a/net/ipv6/ip6_output.c
++++ b/net/ipv6/ip6_output.c
+@@ -567,6 +567,10 @@ int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
+ 	struct net *net = dev_net(skb_dst(skb)->dev);
+ 
+ 	hlen = ip6_find_1stfragopt(skb, &prevhdr);
++	if (hlen < 0) {
++		err = hlen;
++		goto fail;
++	}
+ 	nexthdr = *prevhdr;
+ 
+ 	mtu = ip6_skb_dst_mtu(skb);
+@@ -1042,6 +1046,7 @@ struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6,
+ EXPORT_SYMBOL_GPL(ip6_sk_dst_lookup_flow);
+ 
+ static inline int ip6_ufo_append_data(struct sock *sk,
++			struct sk_buff_head *queue,
+ 			int getfrag(void *from, char *to, int offset, int len,
+ 			int odd, struct sk_buff *skb),
+ 			void *from, int length, int hh_len, int fragheaderlen,
+@@ -1057,7 +1062,8 @@ static inline int ip6_ufo_append_data(struct sock *sk,
+ 	 * device, so create one single skb packet containing complete
+ 	 * udp datagram
+ 	 */
+-	if ((skb = skb_peek_tail(&sk->sk_write_queue)) == NULL) {
++	skb = skb_peek_tail(queue);
++	if (skb == NULL) {
+ 		skb = sock_alloc_send_skb(sk,
+ 			hh_len + fragheaderlen + transhdrlen + 20,
+ 			(flags & MSG_DONTWAIT), &err);
+@@ -1079,7 +1085,7 @@ static inline int ip6_ufo_append_data(struct sock *sk,
+ 		skb->protocol = htons(ETH_P_IPV6);
+ 		skb->csum = 0;
+ 
+-		__skb_queue_tail(&sk->sk_write_queue, skb);
++		__skb_queue_tail(queue, skb);
+ 	} else if (skb_is_gso(skb)) {
+ 		goto append;
+ 	}
+@@ -1135,99 +1141,107 @@ static void ip6_append_data_mtu(unsigned int *mtu,
+ 	}
+ }
+ 
+-int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
+-	int offset, int len, int odd, struct sk_buff *skb),
+-	void *from, int length, int transhdrlen,
+-	int hlimit, int tclass, struct ipv6_txoptions *opt, struct flowi6 *fl6,
+-	struct rt6_info *rt, unsigned int flags, int dontfrag)
++static int ip6_setup_cork(struct sock *sk, struct inet_cork_full *cork,
++			  struct inet6_cork *v6_cork,
++			  int hlimit, int tclass, struct ipv6_txoptions *opt,
++			  struct rt6_info *rt, struct flowi6 *fl6)
+ {
+-	struct inet_sock *inet = inet_sk(sk);
+ 	struct ipv6_pinfo *np = inet6_sk(sk);
+-	struct inet_cork *cork;
++	unsigned int mtu;
++
++	/*
++	 * setup for corking
++	 */
++	if (opt) {
++		if (WARN_ON(v6_cork->opt))
++			return -EINVAL;
++
++		v6_cork->opt = kzalloc(opt->tot_len, sk->sk_allocation);
++		if (unlikely(v6_cork->opt == NULL))
++			return -ENOBUFS;
++
++		v6_cork->opt->tot_len = opt->tot_len;
++		v6_cork->opt->opt_flen = opt->opt_flen;
++		v6_cork->opt->opt_nflen = opt->opt_nflen;
++
++		v6_cork->opt->dst0opt = ip6_opt_dup(opt->dst0opt,
++						    sk->sk_allocation);
++		if (opt->dst0opt && !v6_cork->opt->dst0opt)
++			return -ENOBUFS;
++
++		v6_cork->opt->dst1opt = ip6_opt_dup(opt->dst1opt,
++						    sk->sk_allocation);
++		if (opt->dst1opt && !v6_cork->opt->dst1opt)
++			return -ENOBUFS;
++
++		v6_cork->opt->hopopt = ip6_opt_dup(opt->hopopt,
++						   sk->sk_allocation);
++		if (opt->hopopt && !v6_cork->opt->hopopt)
++			return -ENOBUFS;
++
++		v6_cork->opt->srcrt = ip6_rthdr_dup(opt->srcrt,
++						    sk->sk_allocation);
++		if (opt->srcrt && !v6_cork->opt->srcrt)
++			return -ENOBUFS;
++
++		/* need source address above miyazawa*/
++	}
++	dst_hold(&rt->dst);
++	cork->base.dst = &rt->dst;
++	cork->fl.u.ip6 = *fl6;
++	v6_cork->hop_limit = hlimit;
++	v6_cork->tclass = tclass;
++	if (rt->dst.flags & DST_XFRM_TUNNEL)
++		mtu = np->pmtudisc >= IPV6_PMTUDISC_PROBE ?
++		      rt->dst.dev->mtu : dst_mtu(&rt->dst);
++	else
++		mtu = np->pmtudisc >= IPV6_PMTUDISC_PROBE ?
++		      rt->dst.dev->mtu : dst_mtu(rt->dst.path);
++	if (np->frag_size < mtu) {
++		if (np->frag_size)
++			mtu = np->frag_size;
++	}
++	cork->base.fragsize = mtu;
++	if (dst_allfrag(rt->dst.path))
++		cork->base.flags |= IPCORK_ALLFRAG;
++	cork->base.length = 0;
++
++	return 0;
++}
++
++static int __ip6_append_data(struct sock *sk,
++			     struct flowi6 *fl6,
++			     struct sk_buff_head *queue,
++			     struct inet_cork *cork,
++			     struct inet6_cork *v6_cork,
++			     struct page_frag *pfrag,
++			     int getfrag(void *from, char *to, int offset,
++					 int len, int odd, struct sk_buff *skb),
++			     void *from, int length, int transhdrlen,
++			     unsigned int flags, int dontfrag)
++{
+ 	struct sk_buff *skb, *skb_prev = NULL;
+ 	unsigned int maxfraglen, fragheaderlen, mtu, orig_mtu;
+-	int exthdrlen;
+-	int dst_exthdrlen;
++	int exthdrlen = 0;
++	int dst_exthdrlen = 0;
+ 	int hh_len;
+ 	int copy;
+ 	int err;
+ 	int offset = 0;
+ 	__u8 tx_flags = 0;
+ 	u32 tskey = 0;
+-
+-	if (flags&MSG_PROBE)
+-		return 0;
+-	cork = &inet->cork.base;
+-	if (skb_queue_empty(&sk->sk_write_queue)) {
+-		/*
+-		 * setup for corking
+-		 */
+-		if (opt) {
+-			if (WARN_ON(np->cork.opt))
+-				return -EINVAL;
+-
+-			np->cork.opt = kzalloc(opt->tot_len, sk->sk_allocation);
+-			if (unlikely(np->cork.opt == NULL))
+-				return -ENOBUFS;
+-
+-			np->cork.opt->tot_len = opt->tot_len;
+-			np->cork.opt->opt_flen = opt->opt_flen;
+-			np->cork.opt->opt_nflen = opt->opt_nflen;
+-
+-			np->cork.opt->dst0opt = ip6_opt_dup(opt->dst0opt,
+-							    sk->sk_allocation);
+-			if (opt->dst0opt && !np->cork.opt->dst0opt)
+-				return -ENOBUFS;
+-
+-			np->cork.opt->dst1opt = ip6_opt_dup(opt->dst1opt,
+-							    sk->sk_allocation);
+-			if (opt->dst1opt && !np->cork.opt->dst1opt)
+-				return -ENOBUFS;
+-
+-			np->cork.opt->hopopt = ip6_opt_dup(opt->hopopt,
+-							   sk->sk_allocation);
+-			if (opt->hopopt && !np->cork.opt->hopopt)
+-				return -ENOBUFS;
+-
+-			np->cork.opt->srcrt = ip6_rthdr_dup(opt->srcrt,
+-							    sk->sk_allocation);
+-			if (opt->srcrt && !np->cork.opt->srcrt)
+-				return -ENOBUFS;
+-
+-			/* need source address above miyazawa*/
+-		}
+-		dst_hold(&rt->dst);
+-		cork->dst = &rt->dst;
+-		inet->cork.fl.u.ip6 = *fl6;
+-		np->cork.hop_limit = hlimit;
+-		np->cork.tclass = tclass;
+-		if (rt->dst.flags & DST_XFRM_TUNNEL)
+-			mtu = np->pmtudisc >= IPV6_PMTUDISC_PROBE ?
+-			      rt->dst.dev->mtu : dst_mtu(&rt->dst);
+-		else
+-			mtu = np->pmtudisc >= IPV6_PMTUDISC_PROBE ?
+-			      rt->dst.dev->mtu : dst_mtu(rt->dst.path);
+-		if (np->frag_size < mtu) {
+-			if (np->frag_size)
+-				mtu = np->frag_size;
+-		}
+-		cork->fragsize = mtu;
+-		if (dst_allfrag(rt->dst.path))
+-			cork->flags |= IPCORK_ALLFRAG;
+-		cork->length = 0;
+-		exthdrlen = (opt ? opt->opt_flen : 0);
+-		length += exthdrlen;
+-		transhdrlen += exthdrlen;
++	struct rt6_info *rt = (struct rt6_info *)cork->dst;
++	struct ipv6_txoptions *opt = v6_cork->opt;
++	int csummode = CHECKSUM_NONE;
++	unsigned int maxnonfragsize, headersize;
++
++	skb = skb_peek_tail(queue);
++	if (!skb) {
++		exthdrlen = opt ? opt->opt_flen : 0;
+ 		dst_exthdrlen = rt->dst.header_len - rt->rt6i_nfheader_len;
+-	} else {
+-		rt = (struct rt6_info *)cork->dst;
+-		fl6 = &inet->cork.fl.u.ip6;
+-		opt = np->cork.opt;
+-		transhdrlen = 0;
+-		exthdrlen = 0;
+-		dst_exthdrlen = 0;
+-		mtu = cork->fragsize;
+ 	}
++
++	mtu = cork->fragsize;
+ 	orig_mtu = mtu;
+ 
+ 	hh_len = LL_RESERVED_SPACE(rt->dst.dev);
+@@ -1237,38 +1251,43 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
+ 	maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen -
+ 		     sizeof(struct frag_hdr);
+ 
+-	if (mtu <= sizeof(struct ipv6hdr) + IPV6_MAXPLEN) {
+-		unsigned int maxnonfragsize, headersize;
+-
+-		headersize = sizeof(struct ipv6hdr) +
+-			     (opt ? opt->opt_flen + opt->opt_nflen : 0) +
+-			     (dst_allfrag(&rt->dst) ?
+-			      sizeof(struct frag_hdr) : 0) +
+-			     rt->rt6i_nfheader_len;
+-
+-		if (ip6_sk_ignore_df(sk))
+-			maxnonfragsize = sizeof(struct ipv6hdr) + IPV6_MAXPLEN;
+-		else
+-			maxnonfragsize = mtu;
++	headersize = sizeof(struct ipv6hdr) +
++		     (opt ? opt->opt_flen + opt->opt_nflen : 0) +
++		     (dst_allfrag(&rt->dst) ?
++		      sizeof(struct frag_hdr) : 0) +
++		     rt->rt6i_nfheader_len;
++
++	if (cork->length + length > mtu - headersize && dontfrag &&
++	    (sk->sk_protocol == IPPROTO_UDP ||
++	     sk->sk_protocol == IPPROTO_RAW)) {
++		ipv6_local_rxpmtu(sk, fl6, mtu - headersize +
++				sizeof(struct ipv6hdr));
++		goto emsgsize;
++	}
+ 
+-		/* dontfrag active */
+-		if ((cork->length + length > mtu - headersize) && dontfrag &&
+-		    (sk->sk_protocol == IPPROTO_UDP ||
+-		     sk->sk_protocol == IPPROTO_RAW)) {
+-			ipv6_local_rxpmtu(sk, fl6, mtu - headersize +
+-						   sizeof(struct ipv6hdr));
+-			goto emsgsize;
+-		}
++	if (ip6_sk_ignore_df(sk))
++		maxnonfragsize = sizeof(struct ipv6hdr) + IPV6_MAXPLEN;
++	else
++		maxnonfragsize = mtu;
+ 
+-		if (cork->length + length > maxnonfragsize - headersize) {
++	if (cork->length + length > maxnonfragsize - headersize) {
+ emsgsize:
+-			ipv6_local_error(sk, EMSGSIZE, fl6,
+-					 mtu - headersize +
+-					 sizeof(struct ipv6hdr));
+-			return -EMSGSIZE;
+-		}
++		ipv6_local_error(sk, EMSGSIZE, fl6,
++				 mtu - headersize +
++				 sizeof(struct ipv6hdr));
++		return -EMSGSIZE;
+ 	}
+ 
++	/* CHECKSUM_PARTIAL only with no extension headers and when
++	 * we are not going to fragment
++	 */
++	if (transhdrlen && sk->sk_protocol == IPPROTO_UDP &&
++	    headersize == sizeof(struct ipv6hdr) &&
++	    length < mtu - headersize &&
++	    !(flags & MSG_MORE) &&
++	    rt->dst.dev->features & NETIF_F_V6_CSUM)
++		csummode = CHECKSUM_PARTIAL;
++
+ 	if (sk->sk_type == SOCK_DGRAM || sk->sk_type == SOCK_RAW) {
+ 		sock_tx_timestamp(sk, &tx_flags);
+ 		if (tx_flags & SKBTX_ANY_SW_TSTAMP &&
+@@ -1292,14 +1311,14 @@ emsgsize:
+ 	 * --yoshfuji
+ 	 */
+ 
+-	skb = skb_peek_tail(&sk->sk_write_queue);
+ 	cork->length += length;
+-	if (((length > mtu) ||
+-	     (skb && skb_is_gso(skb))) &&
++	if ((skb && skb_is_gso(skb)) ||
++	    (((length + (skb ? skb->len : headersize)) > mtu) &&
++	    (skb_queue_len(queue) <= 1) &&
+ 	    (sk->sk_protocol == IPPROTO_UDP) &&
+-	    (rt->dst.dev->features & NETIF_F_UFO) &&
+-	    (sk->sk_type == SOCK_DGRAM)) {
+-		err = ip6_ufo_append_data(sk, getfrag, from, length,
++	    (rt->dst.dev->features & NETIF_F_UFO) && !rt->dst.header_len &&
++	    (sk->sk_type == SOCK_DGRAM))) {
++		err = ip6_ufo_append_data(sk, queue, getfrag, from, length,
+ 					  hh_len, fragheaderlen,
+ 					  transhdrlen, mtu, flags, rt);
+ 		if (err)
+@@ -1370,6 +1389,11 @@ alloc_new_skb:
+ 			 */
+ 			alloclen += sizeof(struct frag_hdr);
+ 
++			copy = datalen - transhdrlen - fraggap;
++			if (copy < 0) {
++				err = -EINVAL;
++				goto error;
++			}
+ 			if (transhdrlen) {
+ 				skb = sock_alloc_send_skb(sk,
+ 						alloclen + hh_len,
+@@ -1390,7 +1414,7 @@ alloc_new_skb:
+ 			 *	Fill in the control structures
+ 			 */
+ 			skb->protocol = htons(ETH_P_IPV6);
+-			skb->ip_summed = CHECKSUM_NONE;
++			skb->ip_summed = csummode;
+ 			skb->csum = 0;
+ 			/* reserve for fragmentation and ipsec header */
+ 			skb_reserve(skb, hh_len + sizeof(struct frag_hdr) +
+@@ -1419,13 +1443,9 @@ alloc_new_skb:
+ 				data += fraggap;
+ 				pskb_trim_unique(skb_prev, maxfraglen);
+ 			}
+-			copy = datalen - transhdrlen - fraggap;
+-
+-			if (copy < 0) {
+-				err = -EINVAL;
+-				kfree_skb(skb);
+-				goto error;
+-			} else if (copy > 0 && getfrag(from, data + transhdrlen, offset, copy, fraggap, skb) < 0) {
++			if (copy > 0 &&
++				getfrag(from, data + transhdrlen, offset,
++					copy, fraggap, skb) < 0) {
+ 				err = -EFAULT;
+ 				kfree_skb(skb);
+ 				goto error;
+@@ -1440,7 +1460,7 @@ alloc_new_skb:
+ 			/*
+ 			 * Put the packet on the pending queue
+ 			 */
+-			__skb_queue_tail(&sk->sk_write_queue, skb);
++			__skb_queue_tail(queue, skb);
+ 			continue;
+ 		}
+ 
+@@ -1459,7 +1479,6 @@ alloc_new_skb:
+ 			}
+ 		} else {
+ 			int i = skb_shinfo(skb)->nr_frags;
+-			struct page_frag *pfrag = sk_page_frag(sk);
+ 
+ 			err = -ENOMEM;
+ 			if (!sk_page_frag_refill(sk, pfrag))
+@@ -1502,25 +1521,62 @@ error:
+ 	IP6_INC_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS);
+ 	return err;
+ }
++
++int ip6_append_data(struct sock *sk,
++		    int getfrag(void *from, char *to, int offset, int len,
++				int odd, struct sk_buff *skb),
++		    void *from, int length, int transhdrlen, int hlimit,
++		    int tclass, struct ipv6_txoptions *opt, struct flowi6 *fl6,
++		    struct rt6_info *rt, unsigned int flags, int dontfrag)
++{
++	struct inet_sock *inet = inet_sk(sk);
++	struct ipv6_pinfo *np = inet6_sk(sk);
++	int exthdrlen;
++	int err;
++
++	if (flags&MSG_PROBE)
++		return 0;
++	if (skb_queue_empty(&sk->sk_write_queue)) {
++		/*
++		 * setup for corking
++		 */
++		err = ip6_setup_cork(sk, &inet->cork, &np->cork, hlimit,
++				     tclass, opt, rt, fl6);
++		if (err)
++			return err;
++
++		exthdrlen = (opt ? opt->opt_flen : 0);
++		length += exthdrlen;
++		transhdrlen += exthdrlen;
++	} else {
++		fl6 = &inet->cork.fl.u.ip6;
++		transhdrlen = 0;
++	}
++
++	return __ip6_append_data(sk, fl6, &sk->sk_write_queue, &inet->cork.base,
++				 &np->cork, sk_page_frag(sk), getfrag,
++				 from, length, transhdrlen, flags, dontfrag);
++}
+ EXPORT_SYMBOL_GPL(ip6_append_data);
+ 
+-static void ip6_cork_release(struct inet_sock *inet, struct ipv6_pinfo *np)
++static void ip6_cork_release(struct inet_cork_full *cork,
++			     struct inet6_cork *v6_cork)
+ {
+-	if (np->cork.opt) {
+-		kfree(np->cork.opt->dst0opt);
+-		kfree(np->cork.opt->dst1opt);
+-		kfree(np->cork.opt->hopopt);
+-		kfree(np->cork.opt->srcrt);
+-		kfree(np->cork.opt);
+-		np->cork.opt = NULL;
++	if (v6_cork->opt) {
++		kfree(v6_cork->opt->dst0opt);
++		kfree(v6_cork->opt->dst1opt);
++		kfree(v6_cork->opt->hopopt);
++		kfree(v6_cork->opt->srcrt);
++		kfree(v6_cork->opt);
++		v6_cork->opt = NULL;
+ 	}
+ 
+-	if (inet->cork.base.dst) {
+-		dst_release(inet->cork.base.dst);
+-		inet->cork.base.dst = NULL;
+-		inet->cork.base.flags &= ~IPCORK_ALLFRAG;
++	if (cork->base.dst) {
++		dst_release(cork->base.dst);
++		cork->base.dst = NULL;
++		cork->base.flags &= ~IPCORK_ALLFRAG;
+ 	}
+-	memset(&inet->cork.fl, 0, sizeof(inet->cork.fl));
++	memset(&cork->fl, 0, sizeof(cork->fl));
+ }
+ 
+ int ip6_push_pending_frames(struct sock *sk)
+@@ -1599,7 +1655,7 @@ int ip6_push_pending_frames(struct sock *sk)
+ 	}
+ 
+ out:
+-	ip6_cork_release(inet, np);
++	ip6_cork_release(&inet->cork, &np->cork);
+ 	return err;
+ error:
+ 	IP6_INC_STATS(net, rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS);
+@@ -1607,17 +1663,23 @@ error:
+ }
+ EXPORT_SYMBOL_GPL(ip6_push_pending_frames);
+ 
+-void ip6_flush_pending_frames(struct sock *sk)
++static void __ip6_flush_pending_frames(struct sock *sk,
++				       struct sk_buff_head *queue)
+ {
+ 	struct sk_buff *skb;
+ 
+-	while ((skb = __skb_dequeue_tail(&sk->sk_write_queue)) != NULL) {
++	while ((skb = __skb_dequeue_tail(queue)) != NULL) {
+ 		if (skb_dst(skb))
+ 			IP6_INC_STATS(sock_net(sk), ip6_dst_idev(skb_dst(skb)),
+ 				      IPSTATS_MIB_OUTDISCARDS);
+ 		kfree_skb(skb);
+ 	}
+ 
+-	ip6_cork_release(inet_sk(sk), inet6_sk(sk));
++	ip6_cork_release(&inet_sk(sk)->cork, &inet6_sk(sk)->cork);
++}
++
++void ip6_flush_pending_frames(struct sock *sk)
++{
++	__ip6_flush_pending_frames(sk, &sk->sk_write_queue);
+ }
+ EXPORT_SYMBOL_GPL(ip6_flush_pending_frames);
+diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c
+index 2459b7b..8d12faa 100644
+--- a/net/ipv6/ip6_vti.c
++++ b/net/ipv6/ip6_vti.c
+@@ -555,7 +555,7 @@ static int vti6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+ 	if (type == NDISC_REDIRECT)
+ 		ip6_redirect(skb, net, skb->dev->ifindex, 0);
+ 	else
+-		ip6_update_pmtu(skb, net, info, 0, 0);
++		ip6_update_pmtu(skb, net, info, 0, 0, INVALID_UID);
+ 	xfrm_state_put(x);
+ 
+ 	return 0;
+diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c
+index 1b9316e..b247bac 100644
+--- a/net/ipv6/ipcomp6.c
++++ b/net/ipv6/ipcomp6.c
+@@ -76,7 +76,7 @@ static int ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+ 	if (type == NDISC_REDIRECT)
+ 		ip6_redirect(skb, net, skb->dev->ifindex, 0);
+ 	else
+-		ip6_update_pmtu(skb, net, info, 0, 0);
++		ip6_update_pmtu(skb, net, info, 0, 0, INVALID_UID);
+ 	xfrm_state_put(x);
+ 
+ 	return 0;
+diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
+index e1a9583..7f42cd7 100644
+--- a/net/ipv6/ipv6_sockglue.c
++++ b/net/ipv6/ipv6_sockglue.c
+@@ -104,16 +104,18 @@ struct ipv6_txoptions *ipv6_update_options(struct sock *sk,
+ {
+ 	if (inet_sk(sk)->is_icsk) {
+ 		if (opt &&
+-		    !((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE)) &&
+-		    inet_sk(sk)->inet_daddr != LOOPBACK4_IPV6) {
++			!((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE)) &&
++			inet_sk(sk)->inet_daddr != LOOPBACK4_IPV6) {
+ 			struct inet_connection_sock *icsk = inet_csk(sk);
+ 			icsk->icsk_ext_hdr_len = opt->opt_flen + opt->opt_nflen;
+ 			icsk->icsk_sync_mss(sk, icsk->icsk_pmtu_cookie);
+ 		}
+-		opt = xchg(&inet6_sk(sk)->opt, opt);
++		opt = xchg((__force struct ipv6_txoptions **)&inet6_sk(sk)->opt,
++				opt);
+ 	} else {
+ 		spin_lock(&sk->sk_dst_lock);
+-		opt = xchg(&inet6_sk(sk)->opt, opt);
++		opt = xchg((__force struct ipv6_txoptions **)&inet6_sk(sk)->opt,
++				opt);
+ 		spin_unlock(&sk->sk_dst_lock);
+ 	}
+ 	sk_dst_reset(sk);
+@@ -213,9 +215,12 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
+ 				sk->sk_socket->ops = &inet_dgram_ops;
+ 				sk->sk_family = PF_INET;
+ 			}
+-			opt = xchg(&np->opt, NULL);
+-			if (opt)
+-				sock_kfree_s(sk, opt, opt->tot_len);
++			opt = xchg((__force struct ipv6_txoptions **)&np->opt,
++				   NULL);
++			if (opt) {
++				atomic_sub(opt->tot_len, &sk->sk_omem_alloc);
++				txopt_put(opt);
++			}
+ 			pktopt = xchg(&np->pktoptions, NULL);
+ 			kfree_skb(pktopt);
+ 
+@@ -385,7 +390,8 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
+ 		if (optname != IPV6_RTHDR && !ns_capable(net->user_ns, CAP_NET_RAW))
+ 			break;
+ 
+-		opt = ipv6_renew_options(sk, np->opt, optname,
++		opt = rcu_dereference_protected(np->opt, sock_owned_by_user(sk));
++		opt = ipv6_renew_options(sk, opt, optname,
+ 					 (struct ipv6_opt_hdr __user *)optval,
+ 					 optlen);
+ 		if (IS_ERR(opt)) {
+@@ -414,8 +420,10 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
+ 		retv = 0;
+ 		opt = ipv6_update_options(sk, opt);
+ sticky_done:
+-		if (opt)
+-			sock_kfree_s(sk, opt, opt->tot_len);
++		if (opt) {
++			atomic_sub(opt->tot_len, &sk->sk_omem_alloc);
++			txopt_put(opt);
++		}
+ 		break;
+ 	}
+ 
+@@ -468,6 +476,7 @@ sticky_done:
+ 			break;
+ 
+ 		memset(opt, 0, sizeof(*opt));
++		atomic_set(&opt->refcnt, 1);
+ 		opt->tot_len = sizeof(*opt) + optlen;
+ 		retv = -EFAULT;
+ 		if (copy_from_user(opt+1, optval, optlen))
+@@ -484,8 +493,10 @@ update:
+ 		retv = 0;
+ 		opt = ipv6_update_options(sk, opt);
+ done:
+-		if (opt)
+-			sock_kfree_s(sk, opt, opt->tot_len);
++		if (opt) {
++			atomic_sub(opt->tot_len, &sk->sk_omem_alloc);
++			txopt_put(opt);
++		}
+ 		break;
+ 	}
+ 	case IPV6_UNICAST_HOPS:
+@@ -1092,10 +1103,11 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
+ 	case IPV6_RTHDR:
+ 	case IPV6_DSTOPTS:
+ 	{
++		struct ipv6_txoptions *opt;
+ 
+ 		lock_sock(sk);
+-		len = ipv6_getsockopt_sticky(sk, np->opt,
+-					     optname, optval, len);
++		opt = rcu_dereference_protected(np->opt, sock_owned_by_user(sk));
++		len = ipv6_getsockopt_sticky(sk, opt, optname, optval, len);
+ 		release_sock(sk);
+ 		/* check if ipv6_getsockopt_sticky() returns err code */
+ 		if (len < 0)
+diff --git a/net/ipv6/output_core.c b/net/ipv6/output_core.c
+index 97f41a3..c471baa 100644
+--- a/net/ipv6/output_core.c
++++ b/net/ipv6/output_core.c
+@@ -44,15 +44,15 @@ EXPORT_SYMBOL_GPL(ipv6_proxy_select_ident);
+ 
+ int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
+ {
+-	u16 offset = sizeof(struct ipv6hdr);
+-	struct ipv6_opt_hdr *exthdr =
+-				(struct ipv6_opt_hdr *)(ipv6_hdr(skb) + 1);
++	unsigned int offset = sizeof(struct ipv6hdr);
+ 	unsigned int packet_len = skb_tail_pointer(skb) -
+ 		skb_network_header(skb);
+ 	int found_rhdr = 0;
+ 	*nexthdr = &ipv6_hdr(skb)->nexthdr;
+ 
+-	while (offset + 1 <= packet_len) {
++	while (offset <= packet_len) {
++		struct ipv6_opt_hdr *exthdr;
++		unsigned int len;
+ 
+ 		switch (**nexthdr) {
+ 
+@@ -73,13 +73,19 @@ int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
+ 			return offset;
+ 		}
+ 
+-		offset += ipv6_optlen(exthdr);
+-		*nexthdr = &exthdr->nexthdr;
++		if (offset + sizeof(struct ipv6_opt_hdr) > packet_len)
++			return -EINVAL;
++
+ 		exthdr = (struct ipv6_opt_hdr *)(skb_network_header(skb) +
+ 						 offset);
++		len = ipv6_optlen(exthdr);
++		if (len + offset >= IPV6_MAXPLEN)
++			return -EINVAL;
++		offset += len;
++		*nexthdr = &exthdr->nexthdr;
+ 	}
+ 
+-	return offset;
++	return -EINVAL;
+ }
+ EXPORT_SYMBOL(ip6_find_1stfragopt);
+ 
+diff --git a/net/ipv6/ping.c b/net/ipv6/ping.c
+index 2d452a3..75aa8c1 100644
+--- a/net/ipv6/ping.c
++++ b/net/ipv6/ping.c
+@@ -136,6 +136,7 @@ int ping_v6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
+ 	fl6.saddr = np->saddr;
+ 	fl6.daddr = *daddr;
+ 	fl6.flowi6_mark = sk->sk_mark;
++	fl6.flowi6_uid = sock_i_uid(sk);
+ 	fl6.fl6_icmp_type = user_icmph.icmp6_type;
+ 	fl6.fl6_icmp_code = user_icmph.icmp6_code;
+ 	security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
+diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
+index 896af88..bc3459d 100644
+--- a/net/ipv6/raw.c
++++ b/net/ipv6/raw.c
+@@ -735,6 +735,7 @@ static int rawv6_probe_proto_opt(struct flowi6 *fl6, struct msghdr *msg)
+ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
+ 		   struct msghdr *msg, size_t len)
+ {
++	struct ipv6_txoptions *opt_to_free = NULL;
+ 	struct ipv6_txoptions opt_space;
+ 	DECLARE_SOCKADDR(struct sockaddr_in6 *, sin6, msg->msg_name);
+ 	struct in6_addr *daddr, *final_p, final;
+@@ -768,6 +769,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
+ 	memset(&fl6, 0, sizeof(fl6));
+ 
+ 	fl6.flowi6_mark = sk->sk_mark;
++	fl6.flowi6_uid = sock_i_uid(sk);
+ 
+ 	if (sin6) {
+ 		if (addr_len < SIN6_LEN_RFC2133)
+@@ -840,8 +842,10 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
+ 		if (!(opt->opt_nflen|opt->opt_flen))
+ 			opt = NULL;
+ 	}
+-	if (opt == NULL)
+-		opt = np->opt;
++	if (!opt) {
++		opt = txopt_get(np);
++		opt_to_free = opt;
++	}
+ 	if (flowlabel)
+ 		opt = fl6_merge_options(&opt_space, flowlabel, opt);
+ 	opt = ipv6_fixup_options(&opt_space, opt);
+@@ -902,6 +906,7 @@ done:
+ 	dst_release(dst);
+ out:
+ 	fl6_sock_release(flowlabel);
++	txopt_put(opt_to_free);
+ 	return err < 0 ? err : len;
+ do_confirm:
+ 	dst_confirm(dst);
+diff --git a/net/ipv6/route.c b/net/ipv6/route.c
+index 2d9aca5..babc601 100644
+--- a/net/ipv6/route.c
++++ b/net/ipv6/route.c
+@@ -95,13 +95,12 @@ static void		rt6_do_redirect(struct dst_entry *dst, struct sock *sk,
+ static int rt6_score_route(struct rt6_info *rt, int oif, int strict);
+ 
+ #ifdef CONFIG_IPV6_ROUTE_INFO
+-static struct rt6_info *rt6_add_route_info(struct net *net,
++static struct rt6_info *rt6_add_route_info(struct net_device *dev,
+ 					   const struct in6_addr *prefix, int prefixlen,
+-					   const struct in6_addr *gwaddr, int ifindex,
+-					   unsigned int pref);
+-static struct rt6_info *rt6_get_route_info(struct net *net,
++					   const struct in6_addr *gwaddr, unsigned int pref);
++static struct rt6_info *rt6_get_route_info(struct net_device *dev,
+ 					   const struct in6_addr *prefix, int prefixlen,
+-					   const struct in6_addr *gwaddr, int ifindex);
++					   const struct in6_addr *gwaddr);
+ #endif
+ 
+ static void rt6_bind_peer(struct rt6_info *rt, int create)
+@@ -700,7 +699,6 @@ static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict)
+ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
+ 		  const struct in6_addr *gwaddr)
+ {
+-	struct net *net = dev_net(dev);
+ 	struct route_info *rinfo = (struct route_info *) opt;
+ 	struct in6_addr prefix_buf, *prefix;
+ 	unsigned int pref;
+@@ -745,8 +743,7 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
+ 	if (rinfo->prefix_len == 0)
+ 		rt = rt6_get_dflt_router(gwaddr, dev);
+ 	else
+-		rt = rt6_get_route_info(net, prefix, rinfo->prefix_len,
+-					gwaddr, dev->ifindex);
++		rt = rt6_get_route_info(dev, prefix, rinfo->prefix_len,	gwaddr);
+ 
+ 	if (rt && !lifetime) {
+ 		ip6_del_rt(rt);
+@@ -754,8 +751,7 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
+ 	}
+ 
+ 	if (!rt && lifetime)
+-		rt = rt6_add_route_info(net, prefix, rinfo->prefix_len, gwaddr, dev->ifindex,
+-					pref);
++		rt = rt6_add_route_info(dev, prefix, rinfo->prefix_len, gwaddr, pref);
+ 	else if (rt)
+ 		rt->rt6i_flags = RTF_ROUTEINFO |
+ 				 (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
+@@ -1159,7 +1155,7 @@ static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
+ }
+ 
+ void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu,
+-		     int oif, u32 mark)
++		     int oif, u32 mark, kuid_t uid)
+ {
+ 	const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
+ 	struct dst_entry *dst;
+@@ -1171,6 +1167,7 @@ void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu,
+ 	fl6.daddr = iph->daddr;
+ 	fl6.saddr = iph->saddr;
+ 	fl6.flowlabel = ip6_flowinfo(iph);
++	fl6.flowi6_uid = uid;
+ 
+ 	dst = ip6_route_output(net, NULL, &fl6);
+ 	if (!dst->error)
+@@ -1182,7 +1179,7 @@ EXPORT_SYMBOL_GPL(ip6_update_pmtu);
+ void ip6_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, __be32 mtu)
+ {
+ 	ip6_update_pmtu(skb, sock_net(sk), mtu,
+-			sk->sk_bound_dev_if, sk->sk_mark);
++			sk->sk_bound_dev_if, sk->sk_mark, sock_i_uid(sk));
+ }
+ EXPORT_SYMBOL_GPL(ip6_sk_update_pmtu);
+ 
+@@ -1902,15 +1899,16 @@ static struct rt6_info *ip6_rt_copy(struct rt6_info *ort,
+ }
+ 
+ #ifdef CONFIG_IPV6_ROUTE_INFO
+-static struct rt6_info *rt6_get_route_info(struct net *net,
++static struct rt6_info *rt6_get_route_info(struct net_device *dev,
+ 					   const struct in6_addr *prefix, int prefixlen,
+-					   const struct in6_addr *gwaddr, int ifindex)
++					   const struct in6_addr *gwaddr)
+ {
+ 	struct fib6_node *fn;
+ 	struct rt6_info *rt = NULL;
+ 	struct fib6_table *table;
+ 
+-	table = fib6_get_table(net, RT6_TABLE_INFO);
++	table = fib6_get_table(dev_net(dev),
++			       addrconf_rt_table(dev, RT6_TABLE_INFO));
+ 	if (!table)
+ 		return NULL;
+ 
+@@ -1920,7 +1918,7 @@ static struct rt6_info *rt6_get_route_info(struct net *net,
+ 		goto out;
+ 
+ 	for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
+-		if (rt->dst.dev->ifindex != ifindex)
++		if (rt->dst.dev->ifindex != dev->ifindex)
+ 			continue;
+ 		if ((rt->rt6i_flags & (RTF_ROUTEINFO|RTF_GATEWAY)) != (RTF_ROUTEINFO|RTF_GATEWAY))
+ 			continue;
+@@ -1934,21 +1932,20 @@ out:
+ 	return rt;
+ }
+ 
+-static struct rt6_info *rt6_add_route_info(struct net *net,
++static struct rt6_info *rt6_add_route_info(struct net_device *dev,
+ 					   const struct in6_addr *prefix, int prefixlen,
+-					   const struct in6_addr *gwaddr, int ifindex,
+-					   unsigned int pref)
++					   const struct in6_addr *gwaddr, unsigned int pref)
+ {
+ 	struct fib6_config cfg = {
+-		.fc_table	= RT6_TABLE_INFO,
++		.fc_table	= addrconf_rt_table(dev, RT6_TABLE_INFO),
+ 		.fc_metric	= IP6_RT_PRIO_USER,
+-		.fc_ifindex	= ifindex,
++		.fc_ifindex	= dev->ifindex,
+ 		.fc_dst_len	= prefixlen,
+ 		.fc_flags	= RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO |
+ 				  RTF_UP | RTF_PREF(pref),
+ 		.fc_nlinfo.portid = 0,
+ 		.fc_nlinfo.nlh = NULL,
+-		.fc_nlinfo.nl_net = net,
++		.fc_nlinfo.nl_net = dev_net(dev),
+ 	};
+ 
+ 	cfg.fc_dst = *prefix;
+@@ -1960,7 +1957,7 @@ static struct rt6_info *rt6_add_route_info(struct net *net,
+ 
+ 	ip6_route_add(&cfg);
+ 
+-	return rt6_get_route_info(net, prefix, prefixlen, gwaddr, ifindex);
++	return rt6_get_route_info(dev, prefix, prefixlen, gwaddr);
+ }
+ #endif
+ 
+@@ -1969,7 +1966,8 @@ struct rt6_info *rt6_get_dflt_router(const struct in6_addr *addr, struct net_dev
+ 	struct rt6_info *rt;
+ 	struct fib6_table *table;
+ 
+-	table = fib6_get_table(dev_net(dev), RT6_TABLE_DFLT);
++	table = fib6_get_table(dev_net(dev),
++			       addrconf_rt_table(dev, RT6_TABLE_MAIN));
+ 	if (!table)
+ 		return NULL;
+ 
+@@ -1991,7 +1989,7 @@ struct rt6_info *rt6_add_dflt_router(const struct in6_addr *gwaddr,
+ 				     unsigned int pref)
+ {
+ 	struct fib6_config cfg = {
+-		.fc_table	= RT6_TABLE_DFLT,
++		.fc_table	= addrconf_rt_table(dev, RT6_TABLE_DFLT),
+ 		.fc_metric	= IP6_RT_PRIO_USER,
+ 		.fc_ifindex	= dev->ifindex,
+ 		.fc_flags	= RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT |
+@@ -2008,28 +2006,17 @@ struct rt6_info *rt6_add_dflt_router(const struct in6_addr *gwaddr,
+ 	return rt6_get_dflt_router(gwaddr, dev);
+ }
+ 
+-void rt6_purge_dflt_routers(struct net *net)
+-{
+-	struct rt6_info *rt;
+-	struct fib6_table *table;
+ 
+-	/* NOTE: Keep consistent with rt6_get_dflt_router */
+-	table = fib6_get_table(net, RT6_TABLE_DFLT);
+-	if (!table)
+-		return;
++int rt6_addrconf_purge(struct rt6_info *rt, void *arg) {
++	if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF) &&
++	    (!rt->rt6i_idev || rt->rt6i_idev->cnf.accept_ra != 2))
++		return -1;
++	return 0;
++}
+ 
+-restart:
+-	read_lock_bh(&table->tb6_lock);
+-	for (rt = table->tb6_root.leaf; rt; rt = rt->dst.rt6_next) {
+-		if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF) &&
+-		    (!rt->rt6i_idev || rt->rt6i_idev->cnf.accept_ra != 2)) {
+-			dst_hold(&rt->dst);
+-			read_unlock_bh(&table->tb6_lock);
+-			ip6_del_rt(rt);
+-			goto restart;
+-		}
+-	}
+-	read_unlock_bh(&table->tb6_lock);
++void rt6_purge_dflt_routers(struct net *net)
++{
++	fib6_clean_all(net, rt6_addrconf_purge, NULL);
+ }
+ 
+ static void rtmsg_to_fib6_config(struct net *net,
+@@ -2335,6 +2322,7 @@ static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = {
+ 	[RTA_PRIORITY]          = { .type = NLA_U32 },
+ 	[RTA_METRICS]           = { .type = NLA_NESTED },
+ 	[RTA_MULTIPATH]		= { .len = sizeof(struct rtnexthop) },
++	[RTA_UID]		= { .type = NLA_U32 },
+ };
+ 
+ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
+@@ -2724,6 +2712,11 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh)
+ 	if (tb[RTA_MARK])
+ 		fl6.flowi6_mark = nla_get_u32(tb[RTA_MARK]);
+ 
++	if (tb[RTA_UID])
++		fl6.flowi6_uid = make_kuid(current_user_ns(),
++					   nla_get_u32(tb[RTA_UID]));
++	else
++		fl6.flowi6_uid = iif ? INVALID_UID : current_uid();
+ 	if (iif) {
+ 		struct net_device *dev;
+ 		int flags = 0;
+diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c
+index 2f25cb6..b52a246 100644
+--- a/net/ipv6/syncookies.c
++++ b/net/ipv6/syncookies.c
+@@ -241,12 +241,13 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
+ 		memset(&fl6, 0, sizeof(fl6));
+ 		fl6.flowi6_proto = IPPROTO_TCP;
+ 		fl6.daddr = ireq->ir_v6_rmt_addr;
+-		final_p = fl6_update_dst(&fl6, np->opt, &final);
++		final_p = fl6_update_dst(&fl6, rcu_dereference(np->opt), &final);
+ 		fl6.saddr = ireq->ir_v6_loc_addr;
+ 		fl6.flowi6_oif = sk->sk_bound_dev_if;
+ 		fl6.flowi6_mark = ireq->ir_mark;
+ 		fl6.fl6_dport = ireq->ir_rmt_port;
+ 		fl6.fl6_sport = inet_sk(sk)->inet_sport;
++		fl6.flowi6_uid = sock_i_uid(sk);
+ 		security_req_classify_flow(req, flowi6_to_flowi(&fl6));
+ 
+ 		dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
+diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
+index a3f9f11..b8b9ad2 100644
+--- a/net/ipv6/tcp_ipv6.c
++++ b/net/ipv6/tcp_ipv6.c
+@@ -134,6 +134,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
+ 	struct ipv6_pinfo *np = inet6_sk(sk);
+ 	struct tcp_sock *tp = tcp_sk(sk);
+ 	struct in6_addr *saddr = NULL, *final_p, final;
++	struct ipv6_txoptions *opt;
+ 	struct rt6_info *rt;
+ 	struct flowi6 fl6;
+ 	struct dst_entry *dst;
+@@ -252,8 +253,10 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
+ 	fl6.flowi6_mark = sk->sk_mark;
+ 	fl6.fl6_dport = usin->sin6_port;
+ 	fl6.fl6_sport = inet->inet_sport;
++	fl6.flowi6_uid = sock_i_uid(sk);
+ 
+-	final_p = fl6_update_dst(&fl6, np->opt, &final);
++	opt = rcu_dereference_protected(np->opt, sock_owned_by_user(sk));
++	final_p = fl6_update_dst(&fl6, opt, &final);
+ 
+ 	security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
+ 
+@@ -282,9 +285,9 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
+ 		tcp_fetch_timewait_stamp(sk, dst);
+ 
+ 	icsk->icsk_ext_hdr_len = 0;
+-	if (np->opt)
+-		icsk->icsk_ext_hdr_len = (np->opt->opt_flen +
+-					  np->opt->opt_nflen);
++	if (opt)
++		icsk->icsk_ext_hdr_len = opt->opt_flen +
++					 opt->opt_nflen;
+ 
+ 	tp->rx_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
+ 
+@@ -501,7 +504,8 @@ static int tcp_v6_send_synack(struct sock *sk, struct dst_entry *dst,
+ 			fl6->flowlabel = ip6_flowlabel(ipv6_hdr(ireq->pktopts));
+ 
+ 		skb_set_queue_mapping(skb, queue_mapping);
+-		err = ip6_xmit(sk, skb, fl6, np->opt, np->tclass);
++		err = ip6_xmit(sk, skb, fl6, rcu_dereference(np->opt),
++			       np->tclass);
+ 		err = net_xmit_eval(err);
+ 	}
+ 
+@@ -1052,6 +1056,7 @@ static struct sock *tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
+ 	struct inet_request_sock *ireq;
+ 	struct ipv6_pinfo *newnp, *np = inet6_sk(sk);
+ 	struct tcp6_sock *newtcp6sk;
++	struct ipv6_txoptions *opt;
+ 	struct inet_sock *newinet;
+ 	struct tcp_sock *newtp;
+ 	struct sock *newsk;
+@@ -1091,6 +1096,7 @@ static struct sock *tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
+ 		newtp->af_specific = &tcp_sock_ipv6_mapped_specific;
+ #endif
+ 
++		newnp->ipv6_mc_list = NULL;
+ 		newnp->ipv6_ac_list = NULL;
+ 		newnp->ipv6_fl_list = NULL;
+ 		newnp->pktoptions  = NULL;
+@@ -1162,6 +1168,7 @@ static struct sock *tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
+ 	   First: no IPv4 options.
+ 	 */
+ 	newinet->inet_opt = NULL;
++	newnp->ipv6_mc_list = NULL;
+ 	newnp->ipv6_ac_list = NULL;
+ 	newnp->ipv6_fl_list = NULL;
+ 
+@@ -1191,13 +1198,15 @@ static struct sock *tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
+ 	   but we make one more one thing there: reattach optmem
+ 	   to newsk.
+ 	 */
+-	if (np->opt)
+-		newnp->opt = ipv6_dup_options(newsk, np->opt);
+-
++	opt = rcu_dereference(np->opt);
++	if (opt) {
++		opt = ipv6_dup_options(newsk, opt);
++		RCU_INIT_POINTER(newnp->opt, opt);
++	}
+ 	inet_csk(newsk)->icsk_ext_hdr_len = 0;
+-	if (newnp->opt)
+-		inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen +
+-						     newnp->opt->opt_flen);
++	if (opt)
++		inet_csk(newsk)->icsk_ext_hdr_len = opt->opt_nflen +
++						    opt->opt_flen;
+ 
+ 	tcp_sync_mss(newsk, dst_mtu(dst));
+ 	newtp->advmss = dst_metric_advmss(dst);
+@@ -1268,7 +1277,7 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
+ 	if (skb->protocol == htons(ETH_P_IP))
+ 		return tcp_v4_do_rcv(sk, skb);
+ 
+-	if (sk_filter(sk, skb))
++	if (tcp_filter(sk, skb))
+ 		goto discard;
+ 
+ 	/*
+@@ -1472,8 +1481,10 @@ process:
+ 		goto discard_and_relse;
+ #endif
+ 
+-	if (sk_filter(sk, skb))
++	if (tcp_filter(sk, skb))
+ 		goto discard_and_relse;
++	th = (const struct tcphdr *)skb->data;
++	hdr = ipv6_hdr(skb);
+ 
+ 	sk_mark_napi_id(sk, skb);
+ 	skb->dev = NULL;
+diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
+index dd530f0..3e2ff3d 100644
+--- a/net/ipv6/udp.c
++++ b/net/ipv6/udp.c
+@@ -388,6 +388,7 @@ int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk,
+ 	int peeked, off = 0;
+ 	int err;
+ 	int is_udplite = IS_UDPLITE(sk);
++	bool checksum_valid = false;
+ 	int is_udp4;
+ 	bool slow;
+ 
+@@ -419,11 +420,12 @@ try_again:
+ 	 */
+ 
+ 	if (copied < ulen || UDP_SKB_CB(skb)->partial_cov) {
+-		if (udp_lib_checksum_complete(skb))
++		checksum_valid = !udp_lib_checksum_complete(skb);
++		if (!checksum_valid)
+ 			goto csum_copy_err;
+ 	}
+ 
+-	if (skb_csum_unnecessary(skb))
++	if (checksum_valid || skb_csum_unnecessary(skb))
+ 		err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr),
+ 					      msg->msg_iov, copied);
+ 	else {
+@@ -1082,6 +1084,7 @@ int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk,
+ 	DECLARE_SOCKADDR(struct sockaddr_in6 *, sin6, msg->msg_name);
+ 	struct in6_addr *daddr, *final_p, final;
+ 	struct ipv6_txoptions *opt = NULL;
++	struct ipv6_txoptions *opt_to_free = NULL;
+ 	struct ip6_flowlabel *flowlabel = NULL;
+ 	struct flowi6 fl6;
+ 	struct dst_entry *dst;
+@@ -1213,6 +1216,7 @@ do_udp_sendmsg:
+ 		fl6.flowi6_oif = np->sticky_pktinfo.ipi6_ifindex;
+ 
+ 	fl6.flowi6_mark = sk->sk_mark;
++	fl6.flowi6_uid = sock_i_uid(sk);
+ 
+ 	if (msg->msg_controllen) {
+ 		opt = &opt_space;
+@@ -1234,8 +1238,10 @@ do_udp_sendmsg:
+ 			opt = NULL;
+ 		connected = 0;
+ 	}
+-	if (opt == NULL)
+-		opt = np->opt;
++	if (!opt) {
++		opt = txopt_get(np);
++		opt_to_free = opt;
++	}
+ 	if (flowlabel)
+ 		opt = fl6_merge_options(&opt_space, flowlabel, opt);
+ 	opt = ipv6_fixup_options(&opt_space, opt);
+@@ -1329,6 +1335,7 @@ do_append_data:
+ out:
+ 	dst_release(dst);
+ 	fl6_sock_release(flowlabel);
++	txopt_put(opt_to_free);
+ 	if (!err)
+ 		return len;
+ 	/*
+diff --git a/net/ipv6/udp_offload.c b/net/ipv6/udp_offload.c
+index 6b8f543..b032886 100644
+--- a/net/ipv6/udp_offload.c
++++ b/net/ipv6/udp_offload.c
+@@ -94,6 +94,8 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb,
+ 		 * bytes to insert fragment header.
+ 		 */
+ 		unfrag_ip6hlen = ip6_find_1stfragopt(skb, &prevhdr);
++		if (unfrag_ip6hlen < 0)
++			return ERR_PTR(unfrag_ip6hlen);
+ 		nexthdr = *prevhdr;
+ 		*prevhdr = NEXTHDR_FRAGMENT;
+ 		unfrag_len = (skb_network_header(skb) - skb_mac_header(skb)) +
+diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c
+index 3f3a6cb..b3f6ec0 100644
+--- a/net/irda/af_irda.c
++++ b/net/irda/af_irda.c
+@@ -1100,6 +1100,9 @@ static int irda_create(struct net *net, struct socket *sock, int protocol,
+ 
+ 	IRDA_DEBUG(2, "%s()\n", __func__);
+ 
++	if (protocol < 0 || protocol > SK_PROTOCOL_MAX)
++		return -EINVAL;
++
+ 	if (net != &init_net)
+ 		return -EAFNOSUPPORT;
+ 
+diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c
+index 0edb263..3865882 100644
+--- a/net/l2tp/l2tp_ip6.c
++++ b/net/l2tp/l2tp_ip6.c
+@@ -487,6 +487,7 @@ static int l2tp_ip6_sendmsg(struct kiocb *iocb, struct sock *sk,
+ 	DECLARE_SOCKADDR(struct sockaddr_l2tpip6 *, lsa, msg->msg_name);
+ 	struct in6_addr *daddr, *final_p, final;
+ 	struct ipv6_pinfo *np = inet6_sk(sk);
++	struct ipv6_txoptions *opt_to_free = NULL;
+ 	struct ipv6_txoptions *opt = NULL;
+ 	struct ip6_flowlabel *flowlabel = NULL;
+ 	struct dst_entry *dst = NULL;
+@@ -576,8 +577,10 @@ static int l2tp_ip6_sendmsg(struct kiocb *iocb, struct sock *sk,
+ 			opt = NULL;
+ 	}
+ 
+-	if (opt == NULL)
+-		opt = np->opt;
++	if (!opt) {
++		opt = txopt_get(np);
++		opt_to_free = opt;
++	}
+ 	if (flowlabel)
+ 		opt = fl6_merge_options(&opt_space, flowlabel, opt);
+ 	opt = ipv6_fixup_options(&opt_space, opt);
+@@ -632,6 +635,7 @@ done:
+ 	dst_release(dst);
+ out:
+ 	fl6_sock_release(flowlabel);
++	txopt_put(opt_to_free);
+ 
+ 	return err < 0 ? err : len;
+ 
+diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
+index ae5096a..6b099d1 100644
+--- a/net/netfilter/Kconfig
++++ b/net/netfilter/Kconfig
+@@ -1255,6 +1255,8 @@ config NETFILTER_XT_MATCH_OWNER
+ 	based on who created the socket: the user or group. It is also
+ 	possible to check whether a socket actually exists.
+ 
++	Conflicts with '"quota, tag, uid" match'
++
+ config NETFILTER_XT_MATCH_POLICY
+ 	tristate 'IPsec "policy" match support'
+ 	depends on XFRM
+@@ -1288,6 +1290,22 @@ config NETFILTER_XT_MATCH_PKTTYPE
+ 
+ 	  To compile it as a module, choose M here.  If unsure, say N.
+ 
++config NETFILTER_XT_MATCH_QTAGUID
++	bool '"quota, tag, owner" match and stats support'
++        depends on NETFILTER_XT_MATCH_SOCKET
++	depends on NETFILTER_XT_MATCH_OWNER=n
++	help
++	  This option replaces the `owner' match. In addition to matching
++	  on uid, it keeps stats based on a tag assigned to a socket.
++	  The full tag is comprised of a UID and an accounting tag.
++	  The tags are assignable to sockets from user space (e.g. a download
++	  manager can assign the socket to another UID for accounting).
++	  Stats and control are done via /proc/net/xt_qtaguid/.
++	  It replaces owner as it takes the same arguments, but should
++	  really be recognized by the iptables tool.
++
++	  If unsure, say `N'.
++
+ config NETFILTER_XT_MATCH_QUOTA
+ 	tristate '"quota" match support'
+ 	depends on NETFILTER_ADVANCED
+@@ -1298,6 +1316,30 @@ config NETFILTER_XT_MATCH_QUOTA
+ 	  If you want to compile it as a module, say M here and read
+ 	  <file:Documentation/kbuild/modules.txt>.  If unsure, say `N'.
+ 
++config NETFILTER_XT_MATCH_QUOTA2
++	tristate '"quota2" match support'
++	depends on NETFILTER_ADVANCED
++	help
++	  This option adds a `quota2' match, which allows to match on a
++	  byte counter correctly and not per CPU.
++	  It allows naming the quotas.
++	  This is based on http://xtables-addons.git.sourceforge.net
++
++	  If you want to compile it as a module, say M here and read
++	  <file:Documentation/kbuild/modules.txt>.  If unsure, say `N'.
++
++config NETFILTER_XT_MATCH_QUOTA2_LOG
++	bool '"quota2" Netfilter LOG support'
++	depends on NETFILTER_XT_MATCH_QUOTA2
++	depends on IP_NF_TARGET_ULOG=n    # not yes, not module, just no
++	default n
++	help
++	  This option allows `quota2' to log ONCE when a quota limit
++	  is passed. It logs via NETLINK using the NETLINK_NFLOG family.
++	  It logs similarly to how ipt_ULOG would without data.
++
++	  If unsure, say `N'.
++
+ config NETFILTER_XT_MATCH_RATEEST
+ 	tristate '"rateest" match support'
+ 	depends on NETFILTER_ADVANCED
+diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
+index a9571be..c07bfc8 100644
+--- a/net/netfilter/Makefile
++++ b/net/netfilter/Makefile
+@@ -155,7 +155,9 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_CGROUP) += xt_cgroup.o
+ obj-$(CONFIG_NETFILTER_XT_MATCH_PHYSDEV) += xt_physdev.o
+ obj-$(CONFIG_NETFILTER_XT_MATCH_PKTTYPE) += xt_pkttype.o
+ obj-$(CONFIG_NETFILTER_XT_MATCH_POLICY) += xt_policy.o
++obj-$(CONFIG_NETFILTER_XT_MATCH_QTAGUID) += xt_qtaguid_print.o xt_qtaguid.o
+ obj-$(CONFIG_NETFILTER_XT_MATCH_QUOTA) += xt_quota.o
++obj-$(CONFIG_NETFILTER_XT_MATCH_QUOTA2) += xt_quota2.o
+ obj-$(CONFIG_NETFILTER_XT_MATCH_RATEEST) += xt_rateest.o
+ obj-$(CONFIG_NETFILTER_XT_MATCH_REALM) += xt_realm.o
+ obj-$(CONFIG_NETFILTER_XT_MATCH_RECENT) += xt_recent.o
+diff --git a/net/netfilter/xt_IDLETIMER.c b/net/netfilter/xt_IDLETIMER.c
+index f407ebc..0975c99 100644
+--- a/net/netfilter/xt_IDLETIMER.c
++++ b/net/netfilter/xt_IDLETIMER.c
+@@ -5,6 +5,7 @@
+  * After timer expires a kevent will be sent.
+  *
+  * Copyright (C) 2004, 2010 Nokia Corporation
++ *
+  * Written by Timo Teras <ext-timo.teras@nokia.com>
+  *
+  * Converted to x_tables and reworked for upstream inclusion
+@@ -38,8 +39,16 @@
+ #include <linux/netfilter/xt_IDLETIMER.h>
+ #include <linux/kdev_t.h>
+ #include <linux/kobject.h>
++#include <linux/skbuff.h>
+ #include <linux/workqueue.h>
+ #include <linux/sysfs.h>
++#include <linux/rtc.h>
++#include <linux/time.h>
++#include <linux/math64.h>
++#include <linux/suspend.h>
++#include <linux/notifier.h>
++#include <net/net_namespace.h>
++#include <net/sock.h>
+ 
+ struct idletimer_tg_attr {
+ 	struct attribute attr;
+@@ -55,14 +64,110 @@ struct idletimer_tg {
+ 	struct kobject *kobj;
+ 	struct idletimer_tg_attr attr;
+ 
++	struct timespec delayed_timer_trigger;
++	struct timespec last_modified_timer;
++	struct timespec last_suspend_time;
++	struct notifier_block pm_nb;
++
++	int timeout;
+ 	unsigned int refcnt;
++	bool work_pending;
++	bool send_nl_msg;
++	bool active;
++	uid_t uid;
+ };
+ 
+ static LIST_HEAD(idletimer_tg_list);
+ static DEFINE_MUTEX(list_mutex);
++static DEFINE_SPINLOCK(timestamp_lock);
+ 
+ static struct kobject *idletimer_tg_kobj;
+ 
++static bool check_for_delayed_trigger(struct idletimer_tg *timer,
++		struct timespec *ts)
++{
++	bool state;
++	struct timespec temp;
++	spin_lock_bh(&timestamp_lock);
++	timer->work_pending = false;
++	if ((ts->tv_sec - timer->last_modified_timer.tv_sec) > timer->timeout ||
++			timer->delayed_timer_trigger.tv_sec != 0) {
++		state = false;
++		temp.tv_sec = timer->timeout;
++		temp.tv_nsec = 0;
++		if (timer->delayed_timer_trigger.tv_sec != 0) {
++			temp = timespec_add(timer->delayed_timer_trigger, temp);
++			ts->tv_sec = temp.tv_sec;
++			ts->tv_nsec = temp.tv_nsec;
++			timer->delayed_timer_trigger.tv_sec = 0;
++			timer->work_pending = true;
++			schedule_work(&timer->work);
++		} else {
++			temp = timespec_add(timer->last_modified_timer, temp);
++			ts->tv_sec = temp.tv_sec;
++			ts->tv_nsec = temp.tv_nsec;
++		}
++	} else {
++		state = timer->active;
++	}
++	spin_unlock_bh(&timestamp_lock);
++	return state;
++}
++
++static void notify_netlink_uevent(const char *iface, struct idletimer_tg *timer)
++{
++	char iface_msg[NLMSG_MAX_SIZE];
++	char state_msg[NLMSG_MAX_SIZE];
++	char timestamp_msg[NLMSG_MAX_SIZE];
++	char uid_msg[NLMSG_MAX_SIZE];
++	char *envp[] = { iface_msg, state_msg, timestamp_msg, uid_msg, NULL };
++	int res;
++	struct timespec ts;
++	uint64_t time_ns;
++	bool state;
++
++	res = snprintf(iface_msg, NLMSG_MAX_SIZE, "INTERFACE=%s",
++		       iface);
++	if (NLMSG_MAX_SIZE <= res) {
++		pr_err("message too long (%d)", res);
++		return;
++	}
++
++	get_monotonic_boottime(&ts);
++	state = check_for_delayed_trigger(timer, &ts);
++	res = snprintf(state_msg, NLMSG_MAX_SIZE, "STATE=%s",
++			state ? "active" : "inactive");
++
++	if (NLMSG_MAX_SIZE <= res) {
++		pr_err("message too long (%d)", res);
++		return;
++	}
++
++	if (state) {
++		res = snprintf(uid_msg, NLMSG_MAX_SIZE, "UID=%u", timer->uid);
++		if (NLMSG_MAX_SIZE <= res)
++			pr_err("message too long (%d)", res);
++	} else {
++		res = snprintf(uid_msg, NLMSG_MAX_SIZE, "UID=");
++		if (NLMSG_MAX_SIZE <= res)
++			pr_err("message too long (%d)", res);
++	}
++
++	time_ns = timespec_to_ns(&ts);
++	res = snprintf(timestamp_msg, NLMSG_MAX_SIZE, "TIME_NS=%llu", time_ns);
++	if (NLMSG_MAX_SIZE <= res) {
++		timestamp_msg[0] = '\0';
++		pr_err("message too long (%d)", res);
++	}
++
++	pr_debug("putting nlmsg: <%s> <%s> <%s> <%s>\n", iface_msg, state_msg,
++		 timestamp_msg, uid_msg);
++	kobject_uevent_env(idletimer_tg_kobj, KOBJ_CHANGE, envp);
++	return;
++
++
++}
++
+ static
+ struct idletimer_tg *__idletimer_tg_find_by_label(const char *label)
+ {
+@@ -83,6 +188,7 @@ static ssize_t idletimer_tg_show(struct kobject *kobj, struct attribute *attr,
+ {
+ 	struct idletimer_tg *timer;
+ 	unsigned long expires = 0;
++	unsigned long now = jiffies;
+ 
+ 	mutex_lock(&list_mutex);
+ 
+@@ -92,11 +198,15 @@ static ssize_t idletimer_tg_show(struct kobject *kobj, struct attribute *attr,
+ 
+ 	mutex_unlock(&list_mutex);
+ 
+-	if (time_after(expires, jiffies))
++	if (time_after(expires, now))
+ 		return sprintf(buf, "%u\n",
+-			       jiffies_to_msecs(expires - jiffies) / 1000);
++			       jiffies_to_msecs(expires - now) / 1000);
+ 
+-	return sprintf(buf, "0\n");
++	if (timer->send_nl_msg)
++		return sprintf(buf, "0 %d\n",
++			jiffies_to_msecs(now - expires) / 1000);
++	else
++		return sprintf(buf, "0\n");
+ }
+ 
+ static void idletimer_tg_work(struct work_struct *work)
+@@ -105,6 +215,9 @@ static void idletimer_tg_work(struct work_struct *work)
+ 						  work);
+ 
+ 	sysfs_notify(idletimer_tg_kobj, NULL, timer->attr.attr.name);
++
++	if (timer->send_nl_msg)
++		notify_netlink_uevent(timer->attr.attr.name, timer);
+ }
+ 
+ static void idletimer_tg_expired(unsigned long data)
+@@ -112,8 +225,55 @@ static void idletimer_tg_expired(unsigned long data)
+ 	struct idletimer_tg *timer = (struct idletimer_tg *) data;
+ 
+ 	pr_debug("timer %s expired\n", timer->attr.attr.name);
+-
++	spin_lock_bh(&timestamp_lock);
++	timer->active = false;
++	timer->work_pending = true;
+ 	schedule_work(&timer->work);
++	spin_unlock_bh(&timestamp_lock);
++}
++
++static int idletimer_resume(struct notifier_block *notifier,
++		unsigned long pm_event, void *unused)
++{
++	struct timespec ts;
++	unsigned long time_diff, now = jiffies;
++	struct idletimer_tg *timer = container_of(notifier,
++			struct idletimer_tg, pm_nb);
++	if (!timer)
++		return NOTIFY_DONE;
++	switch (pm_event) {
++	case PM_SUSPEND_PREPARE:
++		get_monotonic_boottime(&timer->last_suspend_time);
++		break;
++	case PM_POST_SUSPEND:
++		spin_lock_bh(&timestamp_lock);
++		if (!timer->active) {
++			spin_unlock_bh(&timestamp_lock);
++			break;
++		}
++		/* since jiffies are not updated when suspended now represents
++		 * the time it would have suspended */
++		if (time_after(timer->timer.expires, now)) {
++			get_monotonic_boottime(&ts);
++			ts = timespec_sub(ts, timer->last_suspend_time);
++			time_diff = timespec_to_jiffies(&ts);
++			if (timer->timer.expires > (time_diff + now)) {
++				mod_timer_pending(&timer->timer,
++						(timer->timer.expires - time_diff));
++			} else {
++				del_timer(&timer->timer);
++				timer->timer.expires = 0;
++				timer->active = false;
++				timer->work_pending = true;
++				schedule_work(&timer->work);
++			}
++		}
++		spin_unlock_bh(&timestamp_lock);
++		break;
++	default:
++		break;
++	}
++	return NOTIFY_DONE;
+ }
+ 
+ static int idletimer_tg_create(struct idletimer_tg_info *info)
+@@ -126,6 +286,7 @@ static int idletimer_tg_create(struct idletimer_tg_info *info)
+ 		goto out;
+ 	}
+ 
++	sysfs_attr_init(&info->timer->attr.attr);
+ 	info->timer->attr.attr.name = kstrdup(info->label, GFP_KERNEL);
+ 	if (!info->timer->attr.attr.name) {
+ 		ret = -ENOMEM;
+@@ -145,6 +306,21 @@ static int idletimer_tg_create(struct idletimer_tg_info *info)
+ 	setup_timer(&info->timer->timer, idletimer_tg_expired,
+ 		    (unsigned long) info->timer);
+ 	info->timer->refcnt = 1;
++	info->timer->send_nl_msg = (info->send_nl_msg == 0) ? false : true;
++	info->timer->active = true;
++	info->timer->timeout = info->timeout;
++
++	info->timer->delayed_timer_trigger.tv_sec = 0;
++	info->timer->delayed_timer_trigger.tv_nsec = 0;
++	info->timer->work_pending = false;
++	info->timer->uid = 0;
++	get_monotonic_boottime(&info->timer->last_modified_timer);
++
++	info->timer->pm_nb.notifier_call = idletimer_resume;
++	ret = register_pm_notifier(&info->timer->pm_nb);
++	if (ret)
++		printk(KERN_WARNING "[%s] Failed to register pm notifier %d\n",
++				__func__, ret);
+ 
+ 	mod_timer(&info->timer->timer,
+ 		  msecs_to_jiffies(info->timeout * 1000) + jiffies);
+@@ -161,6 +337,42 @@ out:
+ 	return ret;
+ }
+ 
++static void reset_timer(const struct idletimer_tg_info *info,
++			struct sk_buff *skb)
++{
++	unsigned long now = jiffies;
++	struct idletimer_tg *timer = info->timer;
++	bool timer_prev;
++
++	spin_lock_bh(&timestamp_lock);
++	timer_prev = timer->active;
++	timer->active = true;
++	/* timer_prev is used to guard overflow problem in time_before*/
++	if (!timer_prev || time_before(timer->timer.expires, now)) {
++		pr_debug("Starting Checkentry timer (Expired, Jiffies): %lu, %lu\n",
++				timer->timer.expires, now);
++
++		/* Stores the uid resposible for waking up the radio */
++		if (skb && (skb->sk)) {
++			timer->uid = from_kuid_munged(current_user_ns(),
++						sock_i_uid(skb->sk));
++		}
++
++		/* checks if there is a pending inactive notification*/
++		if (timer->work_pending)
++			timer->delayed_timer_trigger = timer->last_modified_timer;
++		else {
++			timer->work_pending = true;
++			schedule_work(&timer->work);
++		}
++	}
++
++	get_monotonic_boottime(&timer->last_modified_timer);
++	mod_timer(&timer->timer,
++			msecs_to_jiffies(info->timeout * 1000) + now);
++	spin_unlock_bh(&timestamp_lock);
++}
++
+ /*
+  * The actual xt_tables plugin.
+  */
+@@ -168,15 +380,23 @@ static unsigned int idletimer_tg_target(struct sk_buff *skb,
+ 					 const struct xt_action_param *par)
+ {
+ 	const struct idletimer_tg_info *info = par->targinfo;
++	unsigned long now = jiffies;
+ 
+ 	pr_debug("resetting timer %s, timeout period %u\n",
+ 		 info->label, info->timeout);
+ 
+ 	BUG_ON(!info->timer);
+ 
+-	mod_timer(&info->timer->timer,
+-		  msecs_to_jiffies(info->timeout * 1000) + jiffies);
++	info->timer->active = true;
+ 
++	if (time_before(info->timer->timer.expires, now)) {
++		schedule_work(&info->timer->work);
++		pr_debug("Starting timer %s (Expired, Jiffies): %lu, %lu\n",
++			 info->label, info->timer->timer.expires, now);
++	}
++
++	/* TODO: Avoid modifying timers on each packet */
++	reset_timer(info, skb);
+ 	return XT_CONTINUE;
+ }
+ 
+@@ -185,7 +405,7 @@ static int idletimer_tg_checkentry(const struct xt_tgchk_param *par)
+ 	struct idletimer_tg_info *info = par->targinfo;
+ 	int ret;
+ 
+-	pr_debug("checkentry targinfo%s\n", info->label);
++	pr_debug("checkentry targinfo %s\n", info->label);
+ 
+ 	if (info->timeout == 0) {
+ 		pr_debug("timeout value is zero\n");
+@@ -204,9 +424,7 @@ static int idletimer_tg_checkentry(const struct xt_tgchk_param *par)
+ 	info->timer = __idletimer_tg_find_by_label(info->label);
+ 	if (info->timer) {
+ 		info->timer->refcnt++;
+-		mod_timer(&info->timer->timer,
+-			  msecs_to_jiffies(info->timeout * 1000) + jiffies);
+-
++		reset_timer(info, NULL);
+ 		pr_debug("increased refcnt of timer %s to %u\n",
+ 			 info->label, info->timer->refcnt);
+ 	} else {
+@@ -219,6 +437,7 @@ static int idletimer_tg_checkentry(const struct xt_tgchk_param *par)
+ 	}
+ 
+ 	mutex_unlock(&list_mutex);
++
+ 	return 0;
+ }
+ 
+@@ -236,11 +455,12 @@ static void idletimer_tg_destroy(const struct xt_tgdtor_param *par)
+ 		list_del(&info->timer->entry);
+ 		del_timer_sync(&info->timer->timer);
+ 		sysfs_remove_file(idletimer_tg_kobj, &info->timer->attr.attr);
++		unregister_pm_notifier(&info->timer->pm_nb);
+ 		kfree(info->timer->attr.attr.name);
+ 		kfree(info->timer);
+ 	} else {
+ 		pr_debug("decreased refcnt of timer %s to %u\n",
+-			 info->label, info->timer->refcnt);
++		info->label, info->timer->refcnt);
+ 	}
+ 
+ 	mutex_unlock(&list_mutex);
+@@ -248,6 +468,7 @@ static void idletimer_tg_destroy(const struct xt_tgdtor_param *par)
+ 
+ static struct xt_target idletimer_tg __read_mostly = {
+ 	.name		= "IDLETIMER",
++	.revision	= 1,
+ 	.family		= NFPROTO_UNSPEC,
+ 	.target		= idletimer_tg_target,
+ 	.targetsize     = sizeof(struct idletimer_tg_info),
+@@ -313,3 +534,4 @@ MODULE_DESCRIPTION("Xtables: idle time monitor");
+ MODULE_LICENSE("GPL v2");
+ MODULE_ALIAS("ipt_IDLETIMER");
+ MODULE_ALIAS("ip6t_IDLETIMER");
++MODULE_ALIAS("arpt_IDLETIMER");
+diff --git a/net/netfilter/xt_hl.c b/net/netfilter/xt_hl.c
+index 0039511..1535e87 100644
+--- a/net/netfilter/xt_hl.c
++++ b/net/netfilter/xt_hl.c
+@@ -1,96 +1,169 @@
+ /*
+- * IP tables module for matching the value of the TTL
+- * (C) 2000,2001 by Harald Welte <laforge@netfilter.org>
++ * TTL modification target for IP tables
++ * (C) 2000,2005 by Harald Welte <laforge@netfilter.org>
+  *
+- * Hop Limit matching module
+- * (C) 2001-2002 Maciej Soltysiak <solt@dns.toxicfilms.tv>
++ * Hop Limit modification target for ip6tables
++ * Maciej Soltysiak <solt@dns.toxicfilms.tv>
+  *
+  * 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/ip.h>
+-#include <linux/ipv6.h>
++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+ #include <linux/module.h>
+ #include <linux/skbuff.h>
++#include <linux/ip.h>
++#include <linux/ipv6.h>
++#include <net/checksum.h>
+ 
+ #include <linux/netfilter/x_tables.h>
+-#include <linux/netfilter_ipv4/ipt_ttl.h>
+-#include <linux/netfilter_ipv6/ip6t_hl.h>
++#include <linux/netfilter_ipv4/ipt_TTL.h>
++#include <linux/netfilter_ipv6/ip6t_HL.h>
+ 
++MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
+ MODULE_AUTHOR("Maciej Soltysiak <solt@dns.toxicfilms.tv>");
+-MODULE_DESCRIPTION("Xtables: Hoplimit/TTL field match");
++MODULE_DESCRIPTION("Xtables: Hoplimit/TTL Limit field modification target");
+ MODULE_LICENSE("GPL");
+-MODULE_ALIAS("ipt_ttl");
+-MODULE_ALIAS("ip6t_hl");
+ 
+-static bool ttl_mt(const struct sk_buff *skb, struct xt_action_param *par)
++static unsigned int
++ttl_tg(struct sk_buff *skb, const struct xt_action_param *par)
+ {
+-	const struct ipt_ttl_info *info = par->matchinfo;
+-	const u8 ttl = ip_hdr(skb)->ttl;
++	struct iphdr *iph;
++	const struct ipt_TTL_info *info = par->targinfo;
++	int new_ttl;
++
++	if (!skb_make_writable(skb, skb->len))
++		return NF_DROP;
++
++	iph = ip_hdr(skb);
+ 
+ 	switch (info->mode) {
+-	case IPT_TTL_EQ:
+-		return ttl == info->ttl;
+-	case IPT_TTL_NE:
+-		return ttl != info->ttl;
+-	case IPT_TTL_LT:
+-		return ttl < info->ttl;
+-	case IPT_TTL_GT:
+-		return ttl > info->ttl;
++	case IPT_TTL_SET:
++		new_ttl = info->ttl;
++		break;
++	case IPT_TTL_INC:
++		new_ttl = iph->ttl + info->ttl;
++		if (new_ttl > 255)
++			new_ttl = 255;
++		break;
++	case IPT_TTL_DEC:
++		new_ttl = iph->ttl - info->ttl;
++		if (new_ttl < 0)
++			new_ttl = 0;
++		break;
++	default:
++		new_ttl = iph->ttl;
++		break;
++	}
++
++	if (new_ttl != iph->ttl) {
++		csum_replace2(&iph->check, htons(iph->ttl << 8),
++					   htons(new_ttl << 8));
++		iph->ttl = new_ttl;
+ 	}
+ 
+-	return false;
++	return XT_CONTINUE;
+ }
+ 
+-static bool hl_mt6(const struct sk_buff *skb, struct xt_action_param *par)
++static unsigned int
++hl_tg6(struct sk_buff *skb, const struct xt_action_param *par)
+ {
+-	const struct ip6t_hl_info *info = par->matchinfo;
+-	const struct ipv6hdr *ip6h = ipv6_hdr(skb);
++	struct ipv6hdr *ip6h;
++	const struct ip6t_HL_info *info = par->targinfo;
++	int new_hl;
++
++	if (!skb_make_writable(skb, skb->len))
++		return NF_DROP;
++
++	ip6h = ipv6_hdr(skb);
+ 
+ 	switch (info->mode) {
+-	case IP6T_HL_EQ:
+-		return ip6h->hop_limit == info->hop_limit;
+-	case IP6T_HL_NE:
+-		return ip6h->hop_limit != info->hop_limit;
+-	case IP6T_HL_LT:
+-		return ip6h->hop_limit < info->hop_limit;
+-	case IP6T_HL_GT:
+-		return ip6h->hop_limit > info->hop_limit;
++	case IP6T_HL_SET:
++		new_hl = info->hop_limit;
++		break;
++	case IP6T_HL_INC:
++		new_hl = ip6h->hop_limit + info->hop_limit;
++		if (new_hl > 255)
++			new_hl = 255;
++		break;
++	case IP6T_HL_DEC:
++		new_hl = ip6h->hop_limit - info->hop_limit;
++		if (new_hl < 0)
++			new_hl = 0;
++		break;
++	default:
++		new_hl = ip6h->hop_limit;
++		break;
+ 	}
+ 
+-	return false;
++	ip6h->hop_limit = new_hl;
++
++	return XT_CONTINUE;
++}
++
++static int ttl_tg_check(const struct xt_tgchk_param *par)
++{
++	const struct ipt_TTL_info *info = par->targinfo;
++
++	if (info->mode > IPT_TTL_MAXMODE) {
++		pr_info("TTL: invalid or unknown mode %u\n", info->mode);
++		return -EINVAL;
++	}
++	if (info->mode != IPT_TTL_SET && info->ttl == 0)
++		return -EINVAL;
++	return 0;
++}
++
++static int hl_tg6_check(const struct xt_tgchk_param *par)
++{
++	const struct ip6t_HL_info *info = par->targinfo;
++
++	if (info->mode > IP6T_HL_MAXMODE) {
++		pr_info("invalid or unknown mode %u\n", info->mode);
++		return -EINVAL;
++	}
++	if (info->mode != IP6T_HL_SET && info->hop_limit == 0) {
++		pr_info("increment/decrement does not "
++			"make sense with value 0\n");
++		return -EINVAL;
++	}
++	return 0;
+ }
+ 
+-static struct xt_match hl_mt_reg[] __read_mostly = {
++static struct xt_target hl_tg_reg[] __read_mostly = {
+ 	{
+-		.name       = "ttl",
++		.name       = "TTL",
+ 		.revision   = 0,
+ 		.family     = NFPROTO_IPV4,
+-		.match      = ttl_mt,
+-		.matchsize  = sizeof(struct ipt_ttl_info),
++		.target     = ttl_tg,
++		.targetsize = sizeof(struct ipt_TTL_info),
++		.table      = "mangle",
++		.checkentry = ttl_tg_check,
+ 		.me         = THIS_MODULE,
+ 	},
+ 	{
+-		.name       = "hl",
++		.name       = "HL",
+ 		.revision   = 0,
+ 		.family     = NFPROTO_IPV6,
+-		.match      = hl_mt6,
+-		.matchsize  = sizeof(struct ip6t_hl_info),
++		.target     = hl_tg6,
++		.targetsize = sizeof(struct ip6t_HL_info),
++		.table      = "mangle",
++		.checkentry = hl_tg6_check,
+ 		.me         = THIS_MODULE,
+ 	},
+ };
+ 
+-static int __init hl_mt_init(void)
++static int __init hl_tg_init(void)
+ {
+-	return xt_register_matches(hl_mt_reg, ARRAY_SIZE(hl_mt_reg));
++	return xt_register_targets(hl_tg_reg, ARRAY_SIZE(hl_tg_reg));
+ }
+ 
+-static void __exit hl_mt_exit(void)
++static void __exit hl_tg_exit(void)
+ {
+-	xt_unregister_matches(hl_mt_reg, ARRAY_SIZE(hl_mt_reg));
++	xt_unregister_targets(hl_tg_reg, ARRAY_SIZE(hl_tg_reg));
+ }
+ 
+-module_init(hl_mt_init);
+-module_exit(hl_mt_exit);
++module_init(hl_tg_init);
++module_exit(hl_tg_exit);
++MODULE_ALIAS("ipt_TTL");
++MODULE_ALIAS("ip6t_HL");
+diff --git a/net/netfilter/xt_qtaguid.c b/net/netfilter/xt_qtaguid.c
+new file mode 100644
+index 0000000..87603f6
+--- /dev/null
++++ b/net/netfilter/xt_qtaguid.c
+@@ -0,0 +1,3033 @@
++/*
++ * Kernel iptables module to track stats for packets based on user tags.
++ *
++ * (C) 2011 Google, 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.
++ */
++
++/*
++ * There are run-time debug flags enabled via the debug_mask module param, or
++ * via the DEFAULT_DEBUG_MASK. See xt_qtaguid_internal.h.
++ */
++#define DEBUG
++
++#include <linux/file.h>
++#include <linux/inetdevice.h>
++#include <linux/module.h>
++#include <linux/netfilter/x_tables.h>
++#include <linux/netfilter/xt_qtaguid.h>
++#include <linux/ratelimit.h>
++#include <linux/seq_file.h>
++#include <linux/skbuff.h>
++#include <linux/workqueue.h>
++#include <net/addrconf.h>
++#include <net/sock.h>
++#include <net/tcp.h>
++#include <net/udp.h>
++
++#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
++#include <linux/netfilter_ipv6/ip6_tables.h>
++#endif
++
++#include <linux/netfilter/xt_socket.h>
++#include "xt_qtaguid_internal.h"
++#include "xt_qtaguid_print.h"
++#include "../../fs/proc/internal.h"
++
++/*
++ * We only use the xt_socket funcs within a similar context to avoid unexpected
++ * return values.
++ */
++#define XT_SOCKET_SUPPORTED_HOOKS \
++	((1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_IN))
++
++
++static const char *module_procdirname = "xt_qtaguid";
++static struct proc_dir_entry *xt_qtaguid_procdir;
++
++static unsigned int proc_iface_perms = S_IRUGO;
++module_param_named(iface_perms, proc_iface_perms, uint, S_IRUGO | S_IWUSR);
++
++static struct proc_dir_entry *xt_qtaguid_stats_file;
++static unsigned int proc_stats_perms = S_IRUGO;
++module_param_named(stats_perms, proc_stats_perms, uint, S_IRUGO | S_IWUSR);
++
++static struct proc_dir_entry *xt_qtaguid_ctrl_file;
++
++/* Everybody can write. But proc_ctrl_write_limited is true by default which
++ * limits what can be controlled. See the can_*() functions.
++ */
++static unsigned int proc_ctrl_perms = S_IRUGO | S_IWUGO;
++module_param_named(ctrl_perms, proc_ctrl_perms, uint, S_IRUGO | S_IWUSR);
++
++/* Limited by default, so the gid of the ctrl and stats proc entries
++ * will limit what can be done. See the can_*() functions.
++ */
++static bool proc_stats_readall_limited = true;
++static bool proc_ctrl_write_limited = true;
++
++module_param_named(stats_readall_limited, proc_stats_readall_limited, bool,
++		   S_IRUGO | S_IWUSR);
++module_param_named(ctrl_write_limited, proc_ctrl_write_limited, bool,
++		   S_IRUGO | S_IWUSR);
++
++/*
++ * Limit the number of active tags (via socket tags) for a given UID.
++ * Multiple processes could share the UID.
++ */
++static int max_sock_tags = DEFAULT_MAX_SOCK_TAGS;
++module_param(max_sock_tags, int, S_IRUGO | S_IWUSR);
++
++/*
++ * After the kernel has initiallized this module, it is still possible
++ * to make it passive.
++ * Setting passive to Y:
++ *  - the iface stats handling will not act on notifications.
++ *  - iptables matches will never match.
++ *  - ctrl commands silently succeed.
++ *  - stats are always empty.
++ * This is mostly usefull when a bug is suspected.
++ */
++static bool module_passive;
++module_param_named(passive, module_passive, bool, S_IRUGO | S_IWUSR);
++
++/*
++ * Control how qtaguid data is tracked per proc/uid.
++ * Setting tag_tracking_passive to Y:
++ *  - don't create proc specific structs to track tags
++ *  - don't check that active tag stats exceed some limits.
++ *  - don't clean up socket tags on process exits.
++ * This is mostly usefull when a bug is suspected.
++ */
++static bool qtu_proc_handling_passive;
++module_param_named(tag_tracking_passive, qtu_proc_handling_passive, bool,
++		   S_IRUGO | S_IWUSR);
++
++#define QTU_DEV_NAME "xt_qtaguid"
++
++uint qtaguid_debug_mask = DEFAULT_DEBUG_MASK;
++module_param_named(debug_mask, qtaguid_debug_mask, uint, S_IRUGO | S_IWUSR);
++
++/*---------------------------------------------------------------------------*/
++static const char *iface_stat_procdirname = "iface_stat";
++static struct proc_dir_entry *iface_stat_procdir;
++/*
++ * The iface_stat_all* will go away once userspace gets use to the new fields
++ * that have a format line.
++ */
++static const char *iface_stat_all_procfilename = "iface_stat_all";
++static struct proc_dir_entry *iface_stat_all_procfile;
++static const char *iface_stat_fmt_procfilename = "iface_stat_fmt";
++static struct proc_dir_entry *iface_stat_fmt_procfile;
++
++
++static LIST_HEAD(iface_stat_list);
++static DEFINE_SPINLOCK(iface_stat_list_lock);
++
++static struct rb_root sock_tag_tree = RB_ROOT;
++static DEFINE_SPINLOCK(sock_tag_list_lock);
++
++static struct rb_root tag_counter_set_tree = RB_ROOT;
++static DEFINE_SPINLOCK(tag_counter_set_list_lock);
++
++static struct rb_root uid_tag_data_tree = RB_ROOT;
++static DEFINE_SPINLOCK(uid_tag_data_tree_lock);
++
++static struct rb_root proc_qtu_data_tree = RB_ROOT;
++/* No proc_qtu_data_tree_lock; use uid_tag_data_tree_lock */
++
++static struct qtaguid_event_counts qtu_events;
++/*----------------------------------------------*/
++static bool can_manipulate_uids(void)
++{
++	/* root pwnd */
++	return in_egroup_p(xt_qtaguid_ctrl_file->gid)
++		|| unlikely(!from_kuid(&init_user_ns, current_fsuid())) || unlikely(!proc_ctrl_write_limited)
++		|| unlikely(uid_eq(current_fsuid(), xt_qtaguid_ctrl_file->uid));
++}
++
++static bool can_impersonate_uid(kuid_t uid)
++{
++	return uid_eq(uid, current_fsuid()) || can_manipulate_uids();
++}
++
++static bool can_read_other_uid_stats(kuid_t uid)
++{
++	/* root pwnd */
++	return in_egroup_p(xt_qtaguid_stats_file->gid)
++		|| unlikely(!from_kuid(&init_user_ns, current_fsuid())) || uid_eq(uid, current_fsuid())
++		|| unlikely(!proc_stats_readall_limited)
++		|| unlikely(uid_eq(current_fsuid(), xt_qtaguid_ctrl_file->uid));
++}
++
++static inline void dc_add_byte_packets(struct data_counters *counters, int set,
++				  enum ifs_tx_rx direction,
++				  enum ifs_proto ifs_proto,
++				  int bytes,
++				  int packets)
++{
++	counters->bpc[set][direction][ifs_proto].bytes += bytes;
++	counters->bpc[set][direction][ifs_proto].packets += packets;
++}
++
++static struct tag_node *tag_node_tree_search(struct rb_root *root, tag_t tag)
++{
++	struct rb_node *node = root->rb_node;
++
++	while (node) {
++		struct tag_node *data = rb_entry(node, struct tag_node, node);
++		int result;
++		RB_DEBUG("qtaguid: tag_node_tree_search(0x%llx): "
++			 " node=%p data=%p\n", tag, node, data);
++		result = tag_compare(tag, data->tag);
++		RB_DEBUG("qtaguid: tag_node_tree_search(0x%llx): "
++			 " data.tag=0x%llx (uid=%u) res=%d\n",
++			 tag, data->tag, get_uid_from_tag(data->tag), result);
++		if (result < 0)
++			node = node->rb_left;
++		else if (result > 0)
++			node = node->rb_right;
++		else
++			return data;
++	}
++	return NULL;
++}
++
++static void tag_node_tree_insert(struct tag_node *data, struct rb_root *root)
++{
++	struct rb_node **new = &(root->rb_node), *parent = NULL;
++
++	/* Figure out where to put new node */
++	while (*new) {
++		struct tag_node *this = rb_entry(*new, struct tag_node,
++						 node);
++		int result = tag_compare(data->tag, this->tag);
++		RB_DEBUG("qtaguid: %s(): tag=0x%llx"
++			 " (uid=%u)\n", __func__,
++			 this->tag,
++			 get_uid_from_tag(this->tag));
++		parent = *new;
++		if (result < 0)
++			new = &((*new)->rb_left);
++		else if (result > 0)
++			new = &((*new)->rb_right);
++		else
++			BUG();
++	}
++
++	/* Add new node and rebalance tree. */
++	rb_link_node(&data->node, parent, new);
++	rb_insert_color(&data->node, root);
++}
++
++static void tag_stat_tree_insert(struct tag_stat *data, struct rb_root *root)
++{
++	tag_node_tree_insert(&data->tn, root);
++}
++
++static struct tag_stat *tag_stat_tree_search(struct rb_root *root, tag_t tag)
++{
++	struct tag_node *node = tag_node_tree_search(root, tag);
++	if (!node)
++		return NULL;
++	return rb_entry(&node->node, struct tag_stat, tn.node);
++}
++
++static void tag_counter_set_tree_insert(struct tag_counter_set *data,
++					struct rb_root *root)
++{
++	tag_node_tree_insert(&data->tn, root);
++}
++
++static struct tag_counter_set *tag_counter_set_tree_search(struct rb_root *root,
++							   tag_t tag)
++{
++	struct tag_node *node = tag_node_tree_search(root, tag);
++	if (!node)
++		return NULL;
++	return rb_entry(&node->node, struct tag_counter_set, tn.node);
++
++}
++
++static void tag_ref_tree_insert(struct tag_ref *data, struct rb_root *root)
++{
++	tag_node_tree_insert(&data->tn, root);
++}
++
++static struct tag_ref *tag_ref_tree_search(struct rb_root *root, tag_t tag)
++{
++	struct tag_node *node = tag_node_tree_search(root, tag);
++	if (!node)
++		return NULL;
++	return rb_entry(&node->node, struct tag_ref, tn.node);
++}
++
++static struct sock_tag *sock_tag_tree_search(struct rb_root *root,
++					     const struct sock *sk)
++{
++	struct rb_node *node = root->rb_node;
++
++	while (node) {
++		struct sock_tag *data = rb_entry(node, struct sock_tag,
++						 sock_node);
++		if (sk < data->sk)
++			node = node->rb_left;
++		else if (sk > data->sk)
++			node = node->rb_right;
++		else
++			return data;
++	}
++	return NULL;
++}
++
++static void sock_tag_tree_insert(struct sock_tag *data, struct rb_root *root)
++{
++	struct rb_node **new = &(root->rb_node), *parent = NULL;
++
++	/* Figure out where to put new node */
++	while (*new) {
++		struct sock_tag *this = rb_entry(*new, struct sock_tag,
++						 sock_node);
++		parent = *new;
++		if (data->sk < this->sk)
++			new = &((*new)->rb_left);
++		else if (data->sk > this->sk)
++			new = &((*new)->rb_right);
++		else
++			BUG();
++	}
++
++	/* Add new node and rebalance tree. */
++	rb_link_node(&data->sock_node, parent, new);
++	rb_insert_color(&data->sock_node, root);
++}
++
++static void sock_tag_tree_erase(struct rb_root *st_to_free_tree)
++{
++	struct rb_node *node;
++	struct sock_tag *st_entry;
++
++	node = rb_first(st_to_free_tree);
++	while (node) {
++		st_entry = rb_entry(node, struct sock_tag, sock_node);
++		node = rb_next(node);
++		CT_DEBUG("qtaguid: %s(): "
++			 "erase st: sk=%p tag=0x%llx (uid=%u)\n", __func__,
++			 st_entry->sk,
++			 st_entry->tag,
++			 get_uid_from_tag(st_entry->tag));
++		rb_erase(&st_entry->sock_node, st_to_free_tree);
++		sockfd_put(st_entry->socket);
++		kfree(st_entry);
++	}
++}
++
++static struct proc_qtu_data *proc_qtu_data_tree_search(struct rb_root *root,
++						       const pid_t pid)
++{
++	struct rb_node *node = root->rb_node;
++
++	while (node) {
++		struct proc_qtu_data *data = rb_entry(node,
++						      struct proc_qtu_data,
++						      node);
++		if (pid < data->pid)
++			node = node->rb_left;
++		else if (pid > data->pid)
++			node = node->rb_right;
++		else
++			return data;
++	}
++	return NULL;
++}
++
++static void proc_qtu_data_tree_insert(struct proc_qtu_data *data,
++				      struct rb_root *root)
++{
++	struct rb_node **new = &(root->rb_node), *parent = NULL;
++
++	/* Figure out where to put new node */
++	while (*new) {
++		struct proc_qtu_data *this = rb_entry(*new,
++						      struct proc_qtu_data,
++						      node);
++		parent = *new;
++		if (data->pid < this->pid)
++			new = &((*new)->rb_left);
++		else if (data->pid > this->pid)
++			new = &((*new)->rb_right);
++		else
++			BUG();
++	}
++
++	/* Add new node and rebalance tree. */
++	rb_link_node(&data->node, parent, new);
++	rb_insert_color(&data->node, root);
++}
++
++static void uid_tag_data_tree_insert(struct uid_tag_data *data,
++				     struct rb_root *root)
++{
++	struct rb_node **new = &(root->rb_node), *parent = NULL;
++
++	/* Figure out where to put new node */
++	while (*new) {
++		struct uid_tag_data *this = rb_entry(*new,
++						     struct uid_tag_data,
++						     node);
++		parent = *new;
++		if (data->uid < this->uid)
++			new = &((*new)->rb_left);
++		else if (data->uid > this->uid)
++			new = &((*new)->rb_right);
++		else
++			BUG();
++	}
++
++	/* Add new node and rebalance tree. */
++	rb_link_node(&data->node, parent, new);
++	rb_insert_color(&data->node, root);
++}
++
++static struct uid_tag_data *uid_tag_data_tree_search(struct rb_root *root,
++						     uid_t uid)
++{
++	struct rb_node *node = root->rb_node;
++
++	while (node) {
++		struct uid_tag_data *data = rb_entry(node,
++						     struct uid_tag_data,
++						     node);
++		if (uid < data->uid)
++			node = node->rb_left;
++		else if (uid > data->uid)
++			node = node->rb_right;
++		else
++			return data;
++	}
++	return NULL;
++}
++
++/*
++ * Allocates a new uid_tag_data struct if needed.
++ * Returns a pointer to the found or allocated uid_tag_data.
++ * Returns a PTR_ERR on failures, and lock is not held.
++ * If found is not NULL:
++ *   sets *found to true if not allocated.
++ *   sets *found to false if allocated.
++ */
++struct uid_tag_data *get_uid_data(uid_t uid, bool *found_res)
++{
++	struct uid_tag_data *utd_entry;
++
++	/* Look for top level uid_tag_data for the UID */
++	utd_entry = uid_tag_data_tree_search(&uid_tag_data_tree, uid);
++	DR_DEBUG("qtaguid: get_uid_data(%u) utd=%p\n", uid, utd_entry);
++
++	if (found_res)
++		*found_res = utd_entry;
++	if (utd_entry)
++		return utd_entry;
++
++	utd_entry = kzalloc(sizeof(*utd_entry), GFP_ATOMIC);
++	if (!utd_entry) {
++		pr_err("qtaguid: get_uid_data(%u): "
++		       "tag data alloc failed\n", uid);
++		return ERR_PTR(-ENOMEM);
++	}
++
++	utd_entry->uid = uid;
++	utd_entry->tag_ref_tree = RB_ROOT;
++	uid_tag_data_tree_insert(utd_entry, &uid_tag_data_tree);
++	DR_DEBUG("qtaguid: get_uid_data(%u) new utd=%p\n", uid, utd_entry);
++	return utd_entry;
++}
++
++/* Never returns NULL. Either PTR_ERR or a valid ptr. */
++static struct tag_ref *new_tag_ref(tag_t new_tag,
++				   struct uid_tag_data *utd_entry)
++{
++	struct tag_ref *tr_entry;
++	int res;
++
++	if (utd_entry->num_active_tags + 1 > max_sock_tags) {
++		pr_info("qtaguid: new_tag_ref(0x%llx): "
++			"tag ref alloc quota exceeded. max=%d\n",
++			new_tag, max_sock_tags);
++		res = -EMFILE;
++		goto err_res;
++
++	}
++
++	tr_entry = kzalloc(sizeof(*tr_entry), GFP_ATOMIC);
++	if (!tr_entry) {
++		pr_err("qtaguid: new_tag_ref(0x%llx): "
++		       "tag ref alloc failed\n",
++		       new_tag);
++		res = -ENOMEM;
++		goto err_res;
++	}
++	tr_entry->tn.tag = new_tag;
++	/* tr_entry->num_sock_tags  handled by caller */
++	utd_entry->num_active_tags++;
++	tag_ref_tree_insert(tr_entry, &utd_entry->tag_ref_tree);
++	DR_DEBUG("qtaguid: new_tag_ref(0x%llx): "
++		 " inserted new tag ref %p\n",
++		 new_tag, tr_entry);
++	return tr_entry;
++
++err_res:
++	return ERR_PTR(res);
++}
++
++static struct tag_ref *lookup_tag_ref(tag_t full_tag,
++				      struct uid_tag_data **utd_res)
++{
++	struct uid_tag_data *utd_entry;
++	struct tag_ref *tr_entry;
++	bool found_utd;
++	uid_t uid = get_uid_from_tag(full_tag);
++
++	DR_DEBUG("qtaguid: lookup_tag_ref(tag=0x%llx (uid=%u))\n",
++		 full_tag, uid);
++
++	utd_entry = get_uid_data(uid, &found_utd);
++	if (IS_ERR_OR_NULL(utd_entry)) {
++		if (utd_res)
++			*utd_res = utd_entry;
++		return NULL;
++	}
++
++	tr_entry = tag_ref_tree_search(&utd_entry->tag_ref_tree, full_tag);
++	if (utd_res)
++		*utd_res = utd_entry;
++	DR_DEBUG("qtaguid: lookup_tag_ref(0x%llx) utd_entry=%p tr_entry=%p\n",
++		 full_tag, utd_entry, tr_entry);
++	return tr_entry;
++}
++
++/* Never returns NULL. Either PTR_ERR or a valid ptr. */
++static struct tag_ref *get_tag_ref(tag_t full_tag,
++				   struct uid_tag_data **utd_res)
++{
++	struct uid_tag_data *utd_entry;
++	struct tag_ref *tr_entry;
++
++	DR_DEBUG("qtaguid: get_tag_ref(0x%llx)\n",
++		 full_tag);
++	spin_lock_bh(&uid_tag_data_tree_lock);
++	tr_entry = lookup_tag_ref(full_tag, &utd_entry);
++	BUG_ON(IS_ERR_OR_NULL(utd_entry));
++	if (!tr_entry)
++		tr_entry = new_tag_ref(full_tag, utd_entry);
++
++	spin_unlock_bh(&uid_tag_data_tree_lock);
++	if (utd_res)
++		*utd_res = utd_entry;
++	DR_DEBUG("qtaguid: get_tag_ref(0x%llx) utd=%p tr=%p\n",
++		 full_tag, utd_entry, tr_entry);
++	return tr_entry;
++}
++
++/* Checks and maybe frees the UID Tag Data entry */
++static void put_utd_entry(struct uid_tag_data *utd_entry)
++{
++	/* Are we done with the UID tag data entry? */
++	if (RB_EMPTY_ROOT(&utd_entry->tag_ref_tree) &&
++		!utd_entry->num_pqd) {
++		DR_DEBUG("qtaguid: %s(): "
++			 "erase utd_entry=%p uid=%u "
++			 "by pid=%u tgid=%u uid=%u\n", __func__,
++			 utd_entry, utd_entry->uid,
++			 current->pid, current->tgid, from_kuid(&init_user_ns, current_fsuid()));
++		BUG_ON(utd_entry->num_active_tags);
++		rb_erase(&utd_entry->node, &uid_tag_data_tree);
++		kfree(utd_entry);
++	} else {
++		DR_DEBUG("qtaguid: %s(): "
++			 "utd_entry=%p still has %d tags %d proc_qtu_data\n",
++			 __func__, utd_entry, utd_entry->num_active_tags,
++			 utd_entry->num_pqd);
++		BUG_ON(!(utd_entry->num_active_tags ||
++			 utd_entry->num_pqd));
++	}
++}
++
++/*
++ * If no sock_tags are using this tag_ref,
++ * decrements refcount of utd_entry, removes tr_entry
++ * from utd_entry->tag_ref_tree and frees.
++ */
++static void free_tag_ref_from_utd_entry(struct tag_ref *tr_entry,
++					struct uid_tag_data *utd_entry)
++{
++	DR_DEBUG("qtaguid: %s(): %p tag=0x%llx (uid=%u)\n", __func__,
++		 tr_entry, tr_entry->tn.tag,
++		 get_uid_from_tag(tr_entry->tn.tag));
++	if (!tr_entry->num_sock_tags) {
++		BUG_ON(!utd_entry->num_active_tags);
++		utd_entry->num_active_tags--;
++		rb_erase(&tr_entry->tn.node, &utd_entry->tag_ref_tree);
++		DR_DEBUG("qtaguid: %s(): erased %p\n", __func__, tr_entry);
++		kfree(tr_entry);
++	}
++}
++
++static void put_tag_ref_tree(tag_t full_tag, struct uid_tag_data *utd_entry)
++{
++	struct rb_node *node;
++	struct tag_ref *tr_entry;
++	tag_t acct_tag;
++
++	DR_DEBUG("qtaguid: %s(tag=0x%llx (uid=%u))\n", __func__,
++		 full_tag, get_uid_from_tag(full_tag));
++	acct_tag = get_atag_from_tag(full_tag);
++	node = rb_first(&utd_entry->tag_ref_tree);
++	while (node) {
++		tr_entry = rb_entry(node, struct tag_ref, tn.node);
++		node = rb_next(node);
++		if (!acct_tag || tr_entry->tn.tag == full_tag)
++			free_tag_ref_from_utd_entry(tr_entry, utd_entry);
++	}
++}
++
++static ssize_t read_proc_u64(struct file *file, char __user *buf,
++			 size_t size, loff_t *ppos)
++{
++	uint64_t *valuep = PDE_DATA(file_inode(file));
++	char tmp[24];
++	size_t tmp_size;
++
++	tmp_size = scnprintf(tmp, sizeof(tmp), "%llu\n", *valuep);
++	return simple_read_from_buffer(buf, size, ppos, tmp, tmp_size);
++}
++
++static ssize_t read_proc_bool(struct file *file, char __user *buf,
++			  size_t size, loff_t *ppos)
++{
++	bool *valuep = PDE_DATA(file_inode(file));
++	char tmp[24];
++	size_t tmp_size;
++
++	tmp_size = scnprintf(tmp, sizeof(tmp), "%u\n", *valuep);
++	return simple_read_from_buffer(buf, size, ppos, tmp, tmp_size);
++}
++
++static int get_active_counter_set(tag_t tag)
++{
++	int active_set = 0;
++	struct tag_counter_set *tcs;
++
++	MT_DEBUG("qtaguid: get_active_counter_set(tag=0x%llx)"
++		 " (uid=%u)\n",
++		 tag, get_uid_from_tag(tag));
++	/* For now we only handle UID tags for active sets */
++	tag = get_utag_from_tag(tag);
++	spin_lock_bh(&tag_counter_set_list_lock);
++	tcs = tag_counter_set_tree_search(&tag_counter_set_tree, tag);
++	if (tcs)
++		active_set = tcs->active_set;
++	spin_unlock_bh(&tag_counter_set_list_lock);
++	return active_set;
++}
++
++/*
++ * Find the entry for tracking the specified interface.
++ * Caller must hold iface_stat_list_lock
++ */
++static struct iface_stat *get_iface_entry(const char *ifname)
++{
++	struct iface_stat *iface_entry;
++
++	/* Find the entry for tracking the specified tag within the interface */
++	if (ifname == NULL) {
++		pr_info("qtaguid: iface_stat: get() NULL device name\n");
++		return NULL;
++	}
++
++	/* Iterate over interfaces */
++	list_for_each_entry(iface_entry, &iface_stat_list, list) {
++		if (!strcmp(ifname, iface_entry->ifname))
++			goto done;
++	}
++	iface_entry = NULL;
++done:
++	return iface_entry;
++}
++
++/* This is for fmt2 only */
++static void pp_iface_stat_header(struct seq_file *m)
++{
++	seq_puts(m,
++		 "ifname "
++		 "total_skb_rx_bytes total_skb_rx_packets "
++		 "total_skb_tx_bytes total_skb_tx_packets "
++		 "rx_tcp_bytes rx_tcp_packets "
++		 "rx_udp_bytes rx_udp_packets "
++		 "rx_other_bytes rx_other_packets "
++		 "tx_tcp_bytes tx_tcp_packets "
++		 "tx_udp_bytes tx_udp_packets "
++		 "tx_other_bytes tx_other_packets\n"
++	);
++}
++
++static void pp_iface_stat_line(struct seq_file *m,
++			       struct iface_stat *iface_entry)
++{
++	struct data_counters *cnts;
++	int cnt_set = 0;   /* We only use one set for the device */
++	cnts = &iface_entry->totals_via_skb;
++	seq_printf(m, "%s %llu %llu %llu %llu %llu %llu %llu %llu "
++		   "%llu %llu %llu %llu %llu %llu %llu %llu\n",
++		   iface_entry->ifname,
++		   dc_sum_bytes(cnts, cnt_set, IFS_RX),
++		   dc_sum_packets(cnts, cnt_set, IFS_RX),
++		   dc_sum_bytes(cnts, cnt_set, IFS_TX),
++		   dc_sum_packets(cnts, cnt_set, IFS_TX),
++		   cnts->bpc[cnt_set][IFS_RX][IFS_TCP].bytes,
++		   cnts->bpc[cnt_set][IFS_RX][IFS_TCP].packets,
++		   cnts->bpc[cnt_set][IFS_RX][IFS_UDP].bytes,
++		   cnts->bpc[cnt_set][IFS_RX][IFS_UDP].packets,
++		   cnts->bpc[cnt_set][IFS_RX][IFS_PROTO_OTHER].bytes,
++		   cnts->bpc[cnt_set][IFS_RX][IFS_PROTO_OTHER].packets,
++		   cnts->bpc[cnt_set][IFS_TX][IFS_TCP].bytes,
++		   cnts->bpc[cnt_set][IFS_TX][IFS_TCP].packets,
++		   cnts->bpc[cnt_set][IFS_TX][IFS_UDP].bytes,
++		   cnts->bpc[cnt_set][IFS_TX][IFS_UDP].packets,
++		   cnts->bpc[cnt_set][IFS_TX][IFS_PROTO_OTHER].bytes,
++		   cnts->bpc[cnt_set][IFS_TX][IFS_PROTO_OTHER].packets);
++}
++
++struct proc_iface_stat_fmt_info {
++	int fmt;
++};
++
++static void *iface_stat_fmt_proc_start(struct seq_file *m, loff_t *pos)
++{
++	struct proc_iface_stat_fmt_info *p = m->private;
++	loff_t n = *pos;
++
++	/*
++	 * This lock will prevent iface_stat_update() from changing active,
++	 * and in turn prevent an interface from unregistering itself.
++	 */
++	spin_lock_bh(&iface_stat_list_lock);
++
++	if (unlikely(module_passive))
++		return NULL;
++
++	if (!n && p->fmt == 2)
++		pp_iface_stat_header(m);
++
++	return seq_list_start(&iface_stat_list, n);
++}
++
++static void *iface_stat_fmt_proc_next(struct seq_file *m, void *p, loff_t *pos)
++{
++	return seq_list_next(p, &iface_stat_list, pos);
++}
++
++static void iface_stat_fmt_proc_stop(struct seq_file *m, void *p)
++{
++	spin_unlock_bh(&iface_stat_list_lock);
++}
++
++static int iface_stat_fmt_proc_show(struct seq_file *m, void *v)
++{
++	struct proc_iface_stat_fmt_info *p = m->private;
++	struct iface_stat *iface_entry;
++	struct rtnl_link_stats64 dev_stats, *stats;
++	struct rtnl_link_stats64 no_dev_stats = {0};
++
++
++	CT_DEBUG("qtaguid:proc iface_stat_fmt pid=%u tgid=%u uid=%u\n",
++		 current->pid, current->tgid, from_kuid(&init_user_ns, current_fsuid()));
++
++	iface_entry = list_entry(v, struct iface_stat, list);
++
++	if (iface_entry->active) {
++		stats = dev_get_stats(iface_entry->net_dev,
++				      &dev_stats);
++	} else {
++		stats = &no_dev_stats;
++	}
++	/*
++	 * If the meaning of the data changes, then update the fmtX
++	 * string.
++	 */
++	if (p->fmt == 1) {
++		seq_printf(m, "%s %d %llu %llu %llu %llu %llu %llu %llu %llu\n",
++			   iface_entry->ifname,
++			   iface_entry->active,
++			   iface_entry->totals_via_dev[IFS_RX].bytes,
++			   iface_entry->totals_via_dev[IFS_RX].packets,
++			   iface_entry->totals_via_dev[IFS_TX].bytes,
++			   iface_entry->totals_via_dev[IFS_TX].packets,
++			   stats->rx_bytes, stats->rx_packets,
++			   stats->tx_bytes, stats->tx_packets
++			   );
++	} else {
++		pp_iface_stat_line(m, iface_entry);
++	}
++	return 0;
++}
++
++static const struct file_operations read_u64_fops = {
++	.read		= read_proc_u64,
++	.llseek		= default_llseek,
++};
++
++static const struct file_operations read_bool_fops = {
++	.read		= read_proc_bool,
++	.llseek		= default_llseek,
++};
++
++static void iface_create_proc_worker(struct work_struct *work)
++{
++	struct proc_dir_entry *proc_entry;
++	struct iface_stat_work *isw = container_of(work, struct iface_stat_work,
++						   iface_work);
++	struct iface_stat *new_iface  = isw->iface_entry;
++
++	/* iface_entries are not deleted, so safe to manipulate. */
++	proc_entry = proc_mkdir(new_iface->ifname, iface_stat_procdir);
++	if (IS_ERR_OR_NULL(proc_entry)) {
++		pr_err("qtaguid: iface_stat: create_proc(): alloc failed.\n");
++		kfree(isw);
++		return;
++	}
++
++	new_iface->proc_ptr = proc_entry;
++
++	proc_create_data("tx_bytes", proc_iface_perms, proc_entry,
++			 &read_u64_fops,
++			 &new_iface->totals_via_dev[IFS_TX].bytes);
++	proc_create_data("rx_bytes", proc_iface_perms, proc_entry,
++			 &read_u64_fops,
++			 &new_iface->totals_via_dev[IFS_RX].bytes);
++	proc_create_data("tx_packets", proc_iface_perms, proc_entry,
++			 &read_u64_fops,
++			 &new_iface->totals_via_dev[IFS_TX].packets);
++	proc_create_data("rx_packets", proc_iface_perms, proc_entry,
++			 &read_u64_fops,
++			 &new_iface->totals_via_dev[IFS_RX].packets);
++	proc_create_data("active", proc_iface_perms, proc_entry,
++			 &read_bool_fops, &new_iface->active);
++
++	IF_DEBUG("qtaguid: iface_stat: create_proc(): done "
++		 "entry=%p dev=%s\n", new_iface, new_iface->ifname);
++	kfree(isw);
++}
++
++/*
++ * Will set the entry's active state, and
++ * update the net_dev accordingly also.
++ */
++static void _iface_stat_set_active(struct iface_stat *entry,
++				   struct net_device *net_dev,
++				   bool activate)
++{
++	if (activate) {
++		entry->net_dev = net_dev;
++		entry->active = true;
++		IF_DEBUG("qtaguid: %s(%s): "
++			 "enable tracking. rfcnt=%d\n", __func__,
++			 entry->ifname,
++			 __this_cpu_read(*net_dev->pcpu_refcnt));
++	} else {
++		entry->active = false;
++		entry->net_dev = NULL;
++		IF_DEBUG("qtaguid: %s(%s): "
++			 "disable tracking. rfcnt=%d\n", __func__,
++			 entry->ifname,
++			 __this_cpu_read(*net_dev->pcpu_refcnt));
++
++	}
++}
++
++/* Caller must hold iface_stat_list_lock */
++static struct iface_stat *iface_alloc(struct net_device *net_dev)
++{
++	struct iface_stat *new_iface;
++	struct iface_stat_work *isw;
++
++	new_iface = kzalloc(sizeof(*new_iface), GFP_ATOMIC);
++	if (new_iface == NULL) {
++		pr_err("qtaguid: iface_stat: create(%s): "
++		       "iface_stat alloc failed\n", net_dev->name);
++		return NULL;
++	}
++	new_iface->ifname = kstrdup(net_dev->name, GFP_ATOMIC);
++	if (new_iface->ifname == NULL) {
++		pr_err("qtaguid: iface_stat: create(%s): "
++		       "ifname alloc failed\n", net_dev->name);
++		kfree(new_iface);
++		return NULL;
++	}
++	spin_lock_init(&new_iface->tag_stat_list_lock);
++	new_iface->tag_stat_tree = RB_ROOT;
++	_iface_stat_set_active(new_iface, net_dev, true);
++
++	/*
++	 * ipv6 notifier chains are atomic :(
++	 * No create_proc_read_entry() for you!
++	 */
++	isw = kmalloc(sizeof(*isw), GFP_ATOMIC);
++	if (!isw) {
++		pr_err("qtaguid: iface_stat: create(%s): "
++		       "work alloc failed\n", new_iface->ifname);
++		_iface_stat_set_active(new_iface, net_dev, false);
++		kfree(new_iface->ifname);
++		kfree(new_iface);
++		return NULL;
++	}
++	isw->iface_entry = new_iface;
++	INIT_WORK(&isw->iface_work, iface_create_proc_worker);
++	schedule_work(&isw->iface_work);
++	list_add(&new_iface->list, &iface_stat_list);
++	return new_iface;
++}
++
++static void iface_check_stats_reset_and_adjust(struct net_device *net_dev,
++					       struct iface_stat *iface)
++{
++	struct rtnl_link_stats64 dev_stats, *stats;
++	bool stats_rewound;
++
++	stats = dev_get_stats(net_dev, &dev_stats);
++	/* No empty packets */
++	stats_rewound =
++		(stats->rx_bytes < iface->last_known[IFS_RX].bytes)
++		|| (stats->tx_bytes < iface->last_known[IFS_TX].bytes);
++
++	IF_DEBUG("qtaguid: %s(%s): iface=%p netdev=%p "
++		 "bytes rx/tx=%llu/%llu "
++		 "active=%d last_known=%d "
++		 "stats_rewound=%d\n", __func__,
++		 net_dev ? net_dev->name : "?",
++		 iface, net_dev,
++		 stats->rx_bytes, stats->tx_bytes,
++		 iface->active, iface->last_known_valid, stats_rewound);
++
++	if (iface->active && iface->last_known_valid && stats_rewound) {
++		pr_warn_once("qtaguid: iface_stat: %s(%s): "
++			     "iface reset its stats unexpectedly\n", __func__,
++			     net_dev->name);
++
++		iface->totals_via_dev[IFS_TX].bytes +=
++			iface->last_known[IFS_TX].bytes;
++		iface->totals_via_dev[IFS_TX].packets +=
++			iface->last_known[IFS_TX].packets;
++		iface->totals_via_dev[IFS_RX].bytes +=
++			iface->last_known[IFS_RX].bytes;
++		iface->totals_via_dev[IFS_RX].packets +=
++			iface->last_known[IFS_RX].packets;
++		iface->last_known_valid = false;
++		IF_DEBUG("qtaguid: %s(%s): iface=%p "
++			 "used last known bytes rx/tx=%llu/%llu\n", __func__,
++			 iface->ifname, iface, iface->last_known[IFS_RX].bytes,
++			 iface->last_known[IFS_TX].bytes);
++	}
++}
++
++/*
++ * Create a new entry for tracking the specified interface.
++ * Do nothing if the entry already exists.
++ * Called when an interface is configured with a valid IP address.
++ */
++static void iface_stat_create(struct net_device *net_dev,
++			      struct in_ifaddr *ifa)
++{
++	struct in_device *in_dev = NULL;
++	const char *ifname;
++	struct iface_stat *entry;
++	__be32 ipaddr = 0;
++	struct iface_stat *new_iface;
++
++	IF_DEBUG("qtaguid: iface_stat: create(%s): ifa=%p netdev=%p\n",
++		 net_dev ? net_dev->name : "?",
++		 ifa, net_dev);
++	if (!net_dev) {
++		pr_err("qtaguid: iface_stat: create(): no net dev\n");
++		return;
++	}
++
++	ifname = net_dev->name;
++	if (!ifa) {
++		in_dev = in_dev_get(net_dev);
++		if (!in_dev) {
++			pr_err("qtaguid: iface_stat: create(%s): no inet dev\n",
++			       ifname);
++			return;
++		}
++		IF_DEBUG("qtaguid: iface_stat: create(%s): in_dev=%p\n",
++			 ifname, in_dev);
++		for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
++			IF_DEBUG("qtaguid: iface_stat: create(%s): "
++				 "ifa=%p ifa_label=%s\n",
++				 ifname, ifa,
++				 ifa->ifa_label ? ifa->ifa_label : "(null)");
++			if (ifa->ifa_label && !strcmp(ifname, ifa->ifa_label))
++				break;
++		}
++	}
++
++	if (!ifa) {
++		IF_DEBUG("qtaguid: iface_stat: create(%s): no matching IP\n",
++			 ifname);
++		goto done_put;
++	}
++	ipaddr = ifa->ifa_local;
++
++	spin_lock_bh(&iface_stat_list_lock);
++	entry = get_iface_entry(ifname);
++	if (entry != NULL) {
++		IF_DEBUG("qtaguid: iface_stat: create(%s): entry=%p\n",
++			 ifname, entry);
++		iface_check_stats_reset_and_adjust(net_dev, entry);
++		_iface_stat_set_active(entry, net_dev, true);
++		IF_DEBUG("qtaguid: %s(%s): "
++			 "tracking now %d on ip=%pI4\n", __func__,
++			 entry->ifname, true, &ipaddr);
++		goto done_unlock_put;
++	}
++
++	new_iface = iface_alloc(net_dev);
++	IF_DEBUG("qtaguid: iface_stat: create(%s): done "
++		 "entry=%p ip=%pI4\n", ifname, new_iface, &ipaddr);
++done_unlock_put:
++	spin_unlock_bh(&iface_stat_list_lock);
++done_put:
++	if (in_dev)
++		in_dev_put(in_dev);
++}
++
++static void iface_stat_create_ipv6(struct net_device *net_dev,
++				   struct inet6_ifaddr *ifa)
++{
++	struct in_device *in_dev;
++	const char *ifname;
++	struct iface_stat *entry;
++	struct iface_stat *new_iface;
++	int addr_type;
++
++	IF_DEBUG("qtaguid: iface_stat: create6(): ifa=%p netdev=%p->name=%s\n",
++		 ifa, net_dev, net_dev ? net_dev->name : "");
++	if (!net_dev) {
++		pr_err("qtaguid: iface_stat: create6(): no net dev!\n");
++		return;
++	}
++	ifname = net_dev->name;
++
++	in_dev = in_dev_get(net_dev);
++	if (!in_dev) {
++		pr_err("qtaguid: iface_stat: create6(%s): no inet dev\n",
++		       ifname);
++		return;
++	}
++
++	IF_DEBUG("qtaguid: iface_stat: create6(%s): in_dev=%p\n",
++		 ifname, in_dev);
++
++	if (!ifa) {
++		IF_DEBUG("qtaguid: iface_stat: create6(%s): no matching IP\n",
++			 ifname);
++		goto done_put;
++	}
++	addr_type = ipv6_addr_type(&ifa->addr);
++
++	spin_lock_bh(&iface_stat_list_lock);
++	entry = get_iface_entry(ifname);
++	if (entry != NULL) {
++		IF_DEBUG("qtaguid: %s(%s): entry=%p\n", __func__,
++			 ifname, entry);
++		iface_check_stats_reset_and_adjust(net_dev, entry);
++		_iface_stat_set_active(entry, net_dev, true);
++		IF_DEBUG("qtaguid: %s(%s): "
++			 "tracking now %d on ip=%pI6c\n", __func__,
++			 entry->ifname, true, &ifa->addr);
++		goto done_unlock_put;
++	}
++
++	new_iface = iface_alloc(net_dev);
++	IF_DEBUG("qtaguid: iface_stat: create6(%s): done "
++		 "entry=%p ip=%pI6c\n", ifname, new_iface, &ifa->addr);
++
++done_unlock_put:
++	spin_unlock_bh(&iface_stat_list_lock);
++done_put:
++	in_dev_put(in_dev);
++}
++
++static struct sock_tag *get_sock_stat_nl(const struct sock *sk)
++{
++	MT_DEBUG("qtaguid: get_sock_stat_nl(sk=%p)\n", sk);
++	return sock_tag_tree_search(&sock_tag_tree, sk);
++}
++
++static struct sock_tag *get_sock_stat(const struct sock *sk)
++{
++	struct sock_tag *sock_tag_entry;
++	MT_DEBUG("qtaguid: get_sock_stat(sk=%p)\n", sk);
++	if (!sk)
++		return NULL;
++	spin_lock_bh(&sock_tag_list_lock);
++	sock_tag_entry = get_sock_stat_nl(sk);
++	spin_unlock_bh(&sock_tag_list_lock);
++	return sock_tag_entry;
++}
++
++static int ipx_proto(const struct sk_buff *skb,
++		     struct xt_action_param *par)
++{
++	int thoff = 0, tproto;
++
++	switch (par->family) {
++	case NFPROTO_IPV6:
++		tproto = ipv6_find_hdr(skb, &thoff, -1, NULL, NULL);
++		if (tproto < 0)
++			MT_DEBUG("%s(): transport header not found in ipv6"
++				 " skb=%p\n", __func__, skb);
++		break;
++	case NFPROTO_IPV4:
++		tproto = ip_hdr(skb)->protocol;
++		break;
++	default:
++		tproto = IPPROTO_RAW;
++	}
++	return tproto;
++}
++
++static void
++data_counters_update(struct data_counters *dc, int set,
++		     enum ifs_tx_rx direction, int proto, int bytes)
++{
++	switch (proto) {
++	case IPPROTO_TCP:
++		dc_add_byte_packets(dc, set, direction, IFS_TCP, bytes, 1);
++		break;
++	case IPPROTO_UDP:
++		dc_add_byte_packets(dc, set, direction, IFS_UDP, bytes, 1);
++		break;
++	case IPPROTO_IP:
++	default:
++		dc_add_byte_packets(dc, set, direction, IFS_PROTO_OTHER, bytes,
++				    1);
++		break;
++	}
++}
++
++/*
++ * Update stats for the specified interface. Do nothing if the entry
++ * does not exist (when a device was never configured with an IP address).
++ * Called when an device is being unregistered.
++ */
++static void iface_stat_update(struct net_device *net_dev, bool stash_only)
++{
++	struct rtnl_link_stats64 dev_stats, *stats;
++	struct iface_stat *entry;
++
++	stats = dev_get_stats(net_dev, &dev_stats);
++	spin_lock_bh(&iface_stat_list_lock);
++	entry = get_iface_entry(net_dev->name);
++	if (entry == NULL) {
++		IF_DEBUG("qtaguid: iface_stat: update(%s): not tracked\n",
++			 net_dev->name);
++		spin_unlock_bh(&iface_stat_list_lock);
++		return;
++	}
++
++	IF_DEBUG("qtaguid: %s(%s): entry=%p\n", __func__,
++		 net_dev->name, entry);
++	if (!entry->active) {
++		IF_DEBUG("qtaguid: %s(%s): already disabled\n", __func__,
++			 net_dev->name);
++		spin_unlock_bh(&iface_stat_list_lock);
++		return;
++	}
++
++	if (stash_only) {
++		entry->last_known[IFS_TX].bytes = stats->tx_bytes;
++		entry->last_known[IFS_TX].packets = stats->tx_packets;
++		entry->last_known[IFS_RX].bytes = stats->rx_bytes;
++		entry->last_known[IFS_RX].packets = stats->rx_packets;
++		entry->last_known_valid = true;
++		IF_DEBUG("qtaguid: %s(%s): "
++			 "dev stats stashed rx/tx=%llu/%llu\n", __func__,
++			 net_dev->name, stats->rx_bytes, stats->tx_bytes);
++		spin_unlock_bh(&iface_stat_list_lock);
++		return;
++	}
++	entry->totals_via_dev[IFS_TX].bytes += stats->tx_bytes;
++	entry->totals_via_dev[IFS_TX].packets += stats->tx_packets;
++	entry->totals_via_dev[IFS_RX].bytes += stats->rx_bytes;
++	entry->totals_via_dev[IFS_RX].packets += stats->rx_packets;
++	/* We don't need the last_known[] anymore */
++	entry->last_known_valid = false;
++	_iface_stat_set_active(entry, net_dev, false);
++	IF_DEBUG("qtaguid: %s(%s): "
++		 "disable tracking. rx/tx=%llu/%llu\n", __func__,
++		 net_dev->name, stats->rx_bytes, stats->tx_bytes);
++	spin_unlock_bh(&iface_stat_list_lock);
++}
++
++/*
++ * Update stats for the specified interface from the skb.
++ * Do nothing if the entry
++ * does not exist (when a device was never configured with an IP address).
++ * Called on each sk.
++ */
++static void iface_stat_update_from_skb(const struct sk_buff *skb,
++				       struct xt_action_param *par)
++{
++	struct iface_stat *entry;
++	const struct net_device *el_dev;
++	enum ifs_tx_rx direction = par->in ? IFS_RX : IFS_TX;
++	int bytes = skb->len;
++	int proto;
++
++	if (!skb->dev) {
++		MT_DEBUG("qtaguid[%d]: no skb->dev\n", par->hooknum);
++		el_dev = par->in ? : par->out;
++	} else {
++		const struct net_device *other_dev;
++		el_dev = skb->dev;
++		other_dev = par->in ? : par->out;
++		if (el_dev != other_dev) {
++			MT_DEBUG("qtaguid[%d]: skb->dev=%p %s vs "
++				 "par->(in/out)=%p %s\n",
++				 par->hooknum, el_dev, el_dev->name, other_dev,
++				 other_dev->name);
++		}
++	}
++
++	if (unlikely(!el_dev)) {
++		pr_err_ratelimited("qtaguid[%d]: %s(): no par->in/out?!!\n",
++				   par->hooknum, __func__);
++		BUG();
++	} else if (unlikely(!el_dev->name)) {
++		pr_err_ratelimited("qtaguid[%d]: %s(): no dev->name?!!\n",
++				   par->hooknum, __func__);
++		BUG();
++	} else {
++		proto = ipx_proto(skb, par);
++		MT_DEBUG("qtaguid[%d]: dev name=%s type=%d fam=%d proto=%d\n",
++			 par->hooknum, el_dev->name, el_dev->type,
++			 par->family, proto);
++	}
++
++	spin_lock_bh(&iface_stat_list_lock);
++	entry = get_iface_entry(el_dev->name);
++	if (entry == NULL) {
++		IF_DEBUG("qtaguid: iface_stat: %s(%s): not tracked\n",
++			 __func__, el_dev->name);
++		spin_unlock_bh(&iface_stat_list_lock);
++		return;
++	}
++
++	IF_DEBUG("qtaguid: %s(%s): entry=%p\n", __func__,
++		 el_dev->name, entry);
++
++	data_counters_update(&entry->totals_via_skb, 0, direction, proto,
++			     bytes);
++	spin_unlock_bh(&iface_stat_list_lock);
++}
++
++static void tag_stat_update(struct tag_stat *tag_entry,
++			enum ifs_tx_rx direction, int proto, int bytes)
++{
++	int active_set;
++	active_set = get_active_counter_set(tag_entry->tn.tag);
++	MT_DEBUG("qtaguid: tag_stat_update(tag=0x%llx (uid=%u) set=%d "
++		 "dir=%d proto=%d bytes=%d)\n",
++		 tag_entry->tn.tag, get_uid_from_tag(tag_entry->tn.tag),
++		 active_set, direction, proto, bytes);
++	data_counters_update(&tag_entry->counters, active_set, direction,
++			     proto, bytes);
++	if (tag_entry->parent_counters)
++		data_counters_update(tag_entry->parent_counters, active_set,
++				     direction, proto, bytes);
++}
++
++/*
++ * Create a new entry for tracking the specified {acct_tag,uid_tag} within
++ * the interface.
++ * iface_entry->tag_stat_list_lock should be held.
++ */
++static struct tag_stat *create_if_tag_stat(struct iface_stat *iface_entry,
++					   tag_t tag)
++{
++	struct tag_stat *new_tag_stat_entry = NULL;
++	IF_DEBUG("qtaguid: iface_stat: %s(): ife=%p tag=0x%llx"
++		 " (uid=%u)\n", __func__,
++		 iface_entry, tag, get_uid_from_tag(tag));
++	new_tag_stat_entry = kzalloc(sizeof(*new_tag_stat_entry), GFP_ATOMIC);
++	if (!new_tag_stat_entry) {
++		pr_err("qtaguid: iface_stat: tag stat alloc failed\n");
++		goto done;
++	}
++	new_tag_stat_entry->tn.tag = tag;
++	tag_stat_tree_insert(new_tag_stat_entry, &iface_entry->tag_stat_tree);
++done:
++	return new_tag_stat_entry;
++}
++
++static void if_tag_stat_update(const char *ifname, uid_t uid,
++			       const struct sock *sk, enum ifs_tx_rx direction,
++			       int proto, int bytes)
++{
++	struct tag_stat *tag_stat_entry;
++	tag_t tag, acct_tag;
++	tag_t uid_tag;
++	struct data_counters *uid_tag_counters;
++	struct sock_tag *sock_tag_entry;
++	struct iface_stat *iface_entry;
++	struct tag_stat *new_tag_stat = NULL;
++	MT_DEBUG("qtaguid: if_tag_stat_update(ifname=%s "
++		"uid=%u sk=%p dir=%d proto=%d bytes=%d)\n",
++		 ifname, uid, sk, direction, proto, bytes);
++
++
++	iface_entry = get_iface_entry(ifname);
++	if (!iface_entry) {
++		pr_err_ratelimited("qtaguid: iface_stat: stat_update() "
++				   "%s not found\n", ifname);
++		return;
++	}
++	/* It is ok to process data when an iface_entry is inactive */
++
++	MT_DEBUG("qtaguid: iface_stat: stat_update() dev=%s entry=%p\n",
++		 ifname, iface_entry);
++
++	/*
++	 * Look for a tagged sock.
++	 * It will have an acct_uid.
++	 */
++	sock_tag_entry = get_sock_stat(sk);
++	if (sock_tag_entry) {
++		tag = sock_tag_entry->tag;
++		acct_tag = get_atag_from_tag(tag);
++		uid_tag = get_utag_from_tag(tag);
++	} else {
++		acct_tag = make_atag_from_value(0);
++		tag = combine_atag_with_uid(acct_tag, uid);
++		uid_tag = make_tag_from_uid(uid);
++	}
++	MT_DEBUG("qtaguid: iface_stat: stat_update(): "
++		 " looking for tag=0x%llx (uid=%u) in ife=%p\n",
++		 tag, get_uid_from_tag(tag), iface_entry);
++	/* Loop over tag list under this interface for {acct_tag,uid_tag} */
++	spin_lock_bh(&iface_entry->tag_stat_list_lock);
++
++	tag_stat_entry = tag_stat_tree_search(&iface_entry->tag_stat_tree,
++					      tag);
++	if (tag_stat_entry) {
++		/*
++		 * Updating the {acct_tag, uid_tag} entry handles both stats:
++		 * {0, uid_tag} will also get updated.
++		 */
++		tag_stat_update(tag_stat_entry, direction, proto, bytes);
++		spin_unlock_bh(&iface_entry->tag_stat_list_lock);
++		return;
++	}
++
++	/* Loop over tag list under this interface for {0,uid_tag} */
++	tag_stat_entry = tag_stat_tree_search(&iface_entry->tag_stat_tree,
++					      uid_tag);
++	if (!tag_stat_entry) {
++		/* Here: the base uid_tag did not exist */
++		/*
++		 * No parent counters. So
++		 *  - No {0, uid_tag} stats and no {acc_tag, uid_tag} stats.
++		 */
++		new_tag_stat = create_if_tag_stat(iface_entry, uid_tag);
++		if (!new_tag_stat)
++			goto unlock;
++		uid_tag_counters = &new_tag_stat->counters;
++	} else {
++		uid_tag_counters = &tag_stat_entry->counters;
++	}
++
++	if (acct_tag) {
++		/* Create the child {acct_tag, uid_tag} and hook up parent. */
++		new_tag_stat = create_if_tag_stat(iface_entry, tag);
++		if (!new_tag_stat)
++			goto unlock;
++		new_tag_stat->parent_counters = uid_tag_counters;
++	} else {
++		/*
++		 * For new_tag_stat to be still NULL here would require:
++		 *  {0, uid_tag} exists
++		 *  and {acct_tag, uid_tag} doesn't exist
++		 *  AND acct_tag == 0.
++		 * Impossible. This reassures us that new_tag_stat
++		 * below will always be assigned.
++		 */
++		BUG_ON(!new_tag_stat);
++	}
++	tag_stat_update(new_tag_stat, direction, proto, bytes);
++unlock:
++	spin_unlock_bh(&iface_entry->tag_stat_list_lock);
++}
++
++static int iface_netdev_event_handler(struct notifier_block *nb,
++				      unsigned long event, void *ptr) {
++	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
++
++	if (unlikely(module_passive))
++		return NOTIFY_DONE;
++
++	IF_DEBUG("qtaguid: iface_stat: netdev_event(): "
++		 "ev=0x%lx/%s netdev=%p->name=%s\n",
++		 event, netdev_evt_str(event), dev, dev ? dev->name : "");
++
++	switch (event) {
++	case NETDEV_UP:
++		iface_stat_create(dev, NULL);
++		atomic64_inc(&qtu_events.iface_events);
++		break;
++	case NETDEV_DOWN:
++	case NETDEV_UNREGISTER:
++		iface_stat_update(dev, event == NETDEV_DOWN);
++		atomic64_inc(&qtu_events.iface_events);
++		break;
++	}
++	return NOTIFY_DONE;
++}
++
++static int iface_inet6addr_event_handler(struct notifier_block *nb,
++					 unsigned long event, void *ptr)
++{
++	struct inet6_ifaddr *ifa = ptr;
++	struct net_device *dev;
++
++	if (unlikely(module_passive))
++		return NOTIFY_DONE;
++
++	IF_DEBUG("qtaguid: iface_stat: inet6addr_event(): "
++		 "ev=0x%lx/%s ifa=%p\n",
++		 event, netdev_evt_str(event), ifa);
++
++	switch (event) {
++	case NETDEV_UP:
++		BUG_ON(!ifa || !ifa->idev);
++		dev = (struct net_device *)ifa->idev->dev;
++		iface_stat_create_ipv6(dev, ifa);
++		atomic64_inc(&qtu_events.iface_events);
++		break;
++	case NETDEV_DOWN:
++	case NETDEV_UNREGISTER:
++		BUG_ON(!ifa || !ifa->idev);
++		dev = (struct net_device *)ifa->idev->dev;
++		iface_stat_update(dev, event == NETDEV_DOWN);
++		atomic64_inc(&qtu_events.iface_events);
++		break;
++	}
++	return NOTIFY_DONE;
++}
++
++static int iface_inetaddr_event_handler(struct notifier_block *nb,
++					unsigned long event, void *ptr)
++{
++	struct in_ifaddr *ifa = ptr;
++	struct net_device *dev;
++
++	if (unlikely(module_passive))
++		return NOTIFY_DONE;
++
++	IF_DEBUG("qtaguid: iface_stat: inetaddr_event(): "
++		 "ev=0x%lx/%s ifa=%p\n",
++		 event, netdev_evt_str(event), ifa);
++
++	switch (event) {
++	case NETDEV_UP:
++		BUG_ON(!ifa || !ifa->ifa_dev);
++		dev = ifa->ifa_dev->dev;
++		iface_stat_create(dev, ifa);
++		atomic64_inc(&qtu_events.iface_events);
++		break;
++	case NETDEV_DOWN:
++	case NETDEV_UNREGISTER:
++		BUG_ON(!ifa || !ifa->ifa_dev);
++		dev = ifa->ifa_dev->dev;
++		iface_stat_update(dev, event == NETDEV_DOWN);
++		atomic64_inc(&qtu_events.iface_events);
++		break;
++	}
++	return NOTIFY_DONE;
++}
++
++static struct notifier_block iface_netdev_notifier_blk = {
++	.notifier_call = iface_netdev_event_handler,
++};
++
++static struct notifier_block iface_inetaddr_notifier_blk = {
++	.notifier_call = iface_inetaddr_event_handler,
++};
++
++static struct notifier_block iface_inet6addr_notifier_blk = {
++	.notifier_call = iface_inet6addr_event_handler,
++};
++
++static const struct seq_operations iface_stat_fmt_proc_seq_ops = {
++	.start	= iface_stat_fmt_proc_start,
++	.next	= iface_stat_fmt_proc_next,
++	.stop	= iface_stat_fmt_proc_stop,
++	.show	= iface_stat_fmt_proc_show,
++};
++
++static int proc_iface_stat_fmt_open(struct inode *inode, struct file *file)
++{
++	struct proc_iface_stat_fmt_info *s;
++
++	s = __seq_open_private(file, &iface_stat_fmt_proc_seq_ops,
++			sizeof(struct proc_iface_stat_fmt_info));
++	if (!s)
++		return -ENOMEM;
++
++	s->fmt = (uintptr_t)PDE_DATA(inode);
++	return 0;
++}
++
++static const struct file_operations proc_iface_stat_fmt_fops = {
++	.open		= proc_iface_stat_fmt_open,
++	.read		= seq_read,
++	.llseek		= seq_lseek,
++	.release	= seq_release_private,
++};
++
++static int __init iface_stat_init(struct proc_dir_entry *parent_procdir)
++{
++	int err;
++
++	iface_stat_procdir = proc_mkdir(iface_stat_procdirname, parent_procdir);
++	if (!iface_stat_procdir) {
++		pr_err("qtaguid: iface_stat: init failed to create proc entry\n");
++		err = -1;
++		goto err;
++	}
++
++	iface_stat_all_procfile = proc_create_data(iface_stat_all_procfilename,
++						   proc_iface_perms,
++						   parent_procdir,
++						   &proc_iface_stat_fmt_fops,
++						   (void *)1 /* fmt1 */);
++	if (!iface_stat_all_procfile) {
++		pr_err("qtaguid: iface_stat: init "
++		       " failed to create stat_old proc entry\n");
++		err = -1;
++		goto err_zap_entry;
++	}
++
++	iface_stat_fmt_procfile = proc_create_data(iface_stat_fmt_procfilename,
++						   proc_iface_perms,
++						   parent_procdir,
++						   &proc_iface_stat_fmt_fops,
++						   (void *)2 /* fmt2 */);
++	if (!iface_stat_fmt_procfile) {
++		pr_err("qtaguid: iface_stat: init "
++		       " failed to create stat_all proc entry\n");
++		err = -1;
++		goto err_zap_all_stats_entry;
++	}
++
++
++	err = register_netdevice_notifier(&iface_netdev_notifier_blk);
++	if (err) {
++		pr_err("qtaguid: iface_stat: init "
++		       "failed to register dev event handler\n");
++		goto err_zap_all_stats_entries;
++	}
++	err = register_inetaddr_notifier(&iface_inetaddr_notifier_blk);
++	if (err) {
++		pr_err("qtaguid: iface_stat: init "
++		       "failed to register ipv4 dev event handler\n");
++		goto err_unreg_nd;
++	}
++
++	err = register_inet6addr_notifier(&iface_inet6addr_notifier_blk);
++	if (err) {
++		pr_err("qtaguid: iface_stat: init "
++		       "failed to register ipv6 dev event handler\n");
++		goto err_unreg_ip4_addr;
++	}
++	return 0;
++
++err_unreg_ip4_addr:
++	unregister_inetaddr_notifier(&iface_inetaddr_notifier_blk);
++err_unreg_nd:
++	unregister_netdevice_notifier(&iface_netdev_notifier_blk);
++err_zap_all_stats_entries:
++	remove_proc_entry(iface_stat_fmt_procfilename, parent_procdir);
++err_zap_all_stats_entry:
++	remove_proc_entry(iface_stat_all_procfilename, parent_procdir);
++err_zap_entry:
++	remove_proc_entry(iface_stat_procdirname, parent_procdir);
++err:
++	return err;
++}
++
++static struct sock *qtaguid_find_sk(const struct sk_buff *skb,
++				    struct xt_action_param *par)
++{
++	struct sock *sk;
++	unsigned int hook_mask = (1 << par->hooknum);
++
++	MT_DEBUG("qtaguid: find_sk(skb=%p) hooknum=%d family=%d\n", skb,
++		 par->hooknum, par->family);
++
++	/*
++	 * Let's not abuse the the xt_socket_get*_sk(), or else it will
++	 * return garbage SKs.
++	 */
++	if (!(hook_mask & XT_SOCKET_SUPPORTED_HOOKS))
++		return NULL;
++
++	switch (par->family) {
++	case NFPROTO_IPV6:
++		sk = xt_socket_get6_sk(skb, par);
++		break;
++	case NFPROTO_IPV4:
++		sk = xt_socket_get4_sk(skb, par);
++		break;
++	default:
++		return NULL;
++	}
++
++	if (sk) {
++		MT_DEBUG("qtaguid: %p->sk_proto=%u "
++			 "->sk_state=%d\n", sk, sk->sk_protocol, sk->sk_state);
++		/*
++		 * When in TCP_TIME_WAIT the sk is not a "struct sock" but
++		 * "struct inet_timewait_sock" which is missing fields.
++		 */
++		if (sk->sk_state  == TCP_TIME_WAIT) {
++			if (sk != skb->sk)
++				sock_gen_put(sk);
++			sk = NULL;
++		}
++	}
++	return sk;
++}
++
++static void account_for_uid(const struct sk_buff *skb,
++			    const struct sock *alternate_sk, uid_t uid,
++			    struct xt_action_param *par)
++{
++	const struct net_device *el_dev;
++
++	if (!skb->dev) {
++		MT_DEBUG("qtaguid[%d]: no skb->dev\n", par->hooknum);
++		el_dev = par->in ? : par->out;
++	} else {
++		const struct net_device *other_dev;
++		el_dev = skb->dev;
++		other_dev = par->in ? : par->out;
++		if (el_dev != other_dev) {
++			MT_DEBUG("qtaguid[%d]: skb->dev=%p %s vs "
++				"par->(in/out)=%p %s\n",
++				par->hooknum, el_dev, el_dev->name, other_dev,
++				other_dev->name);
++		}
++	}
++
++	if (unlikely(!el_dev)) {
++		pr_info("qtaguid[%d]: no par->in/out?!!\n", par->hooknum);
++	} else if (unlikely(!el_dev->name)) {
++		pr_info("qtaguid[%d]: no dev->name?!!\n", par->hooknum);
++	} else {
++		int proto = ipx_proto(skb, par);
++		MT_DEBUG("qtaguid[%d]: dev name=%s type=%d fam=%d proto=%d\n",
++			 par->hooknum, el_dev->name, el_dev->type,
++			 par->family, proto);
++
++		if_tag_stat_update(el_dev->name, uid,
++				skb->sk ? skb->sk : alternate_sk,
++				par->in ? IFS_RX : IFS_TX,
++				proto, skb->len);
++	}
++}
++
++static bool qtaguid_mt(const struct sk_buff *skb, struct xt_action_param *par)
++{
++	const struct xt_qtaguid_match_info *info = par->matchinfo;
++	const struct file *filp;
++	bool got_sock = false;
++	struct sock *sk;
++	kuid_t sock_uid;
++	bool res;
++	bool set_sk_callback_lock = false;
++
++	if (unlikely(module_passive))
++		return (info->match ^ info->invert) == 0;
++
++	MT_DEBUG("qtaguid[%d]: entered skb=%p par->in=%p/out=%p fam=%d\n",
++		 par->hooknum, skb, par->in, par->out, par->family);
++
++	atomic64_inc(&qtu_events.match_calls);
++	if (skb == NULL) {
++		res = (info->match ^ info->invert) == 0;
++		goto ret_res;
++	}
++
++	switch (par->hooknum) {
++	case NF_INET_PRE_ROUTING:
++	case NF_INET_POST_ROUTING:
++		atomic64_inc(&qtu_events.match_calls_prepost);
++		iface_stat_update_from_skb(skb, par);
++		/*
++		 * We are done in pre/post. The skb will get processed
++		 * further alter.
++		 */
++		res = (info->match ^ info->invert);
++		goto ret_res;
++		break;
++	/* default: Fall through and do UID releated work */
++	}
++
++	sk = skb->sk;
++	/*
++	 * When in TCP_TIME_WAIT the sk is not a "struct sock" but
++	 * "struct inet_timewait_sock" which is missing fields.
++	 * So we ignore it.
++	 */
++	if (sk && sk->sk_state == TCP_TIME_WAIT)
++		sk = NULL;
++	if (sk == NULL) {
++		/*
++		 * A missing sk->sk_socket happens when packets are in-flight
++		 * and the matching socket is already closed and gone.
++		 */
++		sk = qtaguid_find_sk(skb, par);
++		/*
++		 * If we got the socket from the find_sk(), we will need to put
++		 * it back, as nf_tproxy_get_sock_v4() got it.
++		 */
++		got_sock = sk;
++		if (sk)
++			atomic64_inc(&qtu_events.match_found_sk_in_ct);
++		else
++			atomic64_inc(&qtu_events.match_found_no_sk_in_ct);
++	} else {
++		atomic64_inc(&qtu_events.match_found_sk);
++	}
++	MT_DEBUG("qtaguid[%d]: sk=%p got_sock=%d fam=%d proto=%d\n",
++		 par->hooknum, sk, got_sock, par->family, ipx_proto(skb, par));
++	if (sk != NULL) {
++		set_sk_callback_lock = true;
++		read_lock_bh(&sk->sk_callback_lock);
++		MT_DEBUG("qtaguid[%d]: sk=%p->sk_socket=%p->file=%p\n",
++			par->hooknum, sk, sk->sk_socket,
++			sk->sk_socket ? sk->sk_socket->file : (void *)-1LL);
++		filp = sk->sk_socket ? sk->sk_socket->file : NULL;
++		MT_DEBUG("qtaguid[%d]: filp...uid=%u\n",
++			par->hooknum, filp ? from_kuid(&init_user_ns, filp->f_cred->fsuid) : -1);
++	}
++
++	if (sk == NULL || sk->sk_socket == NULL) {
++		/*
++		 * Here, the qtaguid_find_sk() using connection tracking
++		 * couldn't find the owner, so for now we just count them
++		 * against the system.
++		 */
++		/*
++		 * TODO: unhack how to force just accounting.
++		 * For now we only do iface stats when the uid-owner is not
++		 * requested.
++		 */
++		if (!(info->match & XT_QTAGUID_UID))
++			account_for_uid(skb, sk, 0, par);
++		MT_DEBUG("qtaguid[%d]: leaving (sk?sk->sk_socket)=%p\n",
++			par->hooknum,
++			sk ? sk->sk_socket : NULL);
++		res = (info->match ^ info->invert) == 0;
++		atomic64_inc(&qtu_events.match_no_sk);
++		goto put_sock_ret_res;
++	} else if (info->match & info->invert & XT_QTAGUID_SOCKET) {
++		res = false;
++		goto put_sock_ret_res;
++	}
++	filp = sk->sk_socket->file;
++	if (filp == NULL) {
++		MT_DEBUG("qtaguid[%d]: leaving filp=NULL\n", par->hooknum);
++		account_for_uid(skb, sk, 0, par);
++		res = ((info->match ^ info->invert) &
++			(XT_QTAGUID_UID | XT_QTAGUID_GID)) == 0;
++		atomic64_inc(&qtu_events.match_no_sk_file);
++		goto put_sock_ret_res;
++	}
++	sock_uid = filp->f_cred->fsuid;
++	/*
++	 * TODO: unhack how to force just accounting.
++	 * For now we only do iface stats when the uid-owner is not requested
++	 */
++	if (!(info->match & XT_QTAGUID_UID))
++		account_for_uid(skb, sk, from_kuid(&init_user_ns, sock_uid), par);
++
++	/*
++	 * The following two tests fail the match when:
++	 *    id not in range AND no inverted condition requested
++	 * or id     in range AND    inverted condition requested
++	 * Thus (!a && b) || (a && !b) == a ^ b
++	 */
++	if (info->match & XT_QTAGUID_UID) {
++		kuid_t uid_min = make_kuid(&init_user_ns, info->uid_min);
++		kuid_t uid_max = make_kuid(&init_user_ns, info->uid_max);
++
++		if ((uid_gte(filp->f_cred->fsuid, uid_min) &&
++		     uid_lte(filp->f_cred->fsuid, uid_max)) ^
++		    !(info->invert & XT_QTAGUID_UID)) {
++			MT_DEBUG("qtaguid[%d]: leaving uid not matching\n",
++				 par->hooknum);
++			res = false;
++			goto put_sock_ret_res;
++		}
++	}
++	if (info->match & XT_QTAGUID_GID) {
++		kgid_t gid_min = make_kgid(&init_user_ns, info->gid_min);
++		kgid_t gid_max = make_kgid(&init_user_ns, info->gid_max);
++
++		if ((gid_gte(filp->f_cred->fsgid, gid_min) &&
++				gid_lte(filp->f_cred->fsgid, gid_max)) ^
++			!(info->invert & XT_QTAGUID_GID)) {
++			MT_DEBUG("qtaguid[%d]: leaving gid not matching\n",
++				par->hooknum);
++			res = false;
++			goto put_sock_ret_res;
++		}
++	}
++	MT_DEBUG("qtaguid[%d]: leaving matched\n", par->hooknum);
++	res = true;
++
++put_sock_ret_res:
++	if (got_sock)
++		sock_gen_put(sk);
++	if (set_sk_callback_lock)
++		read_unlock_bh(&sk->sk_callback_lock);
++ret_res:
++	MT_DEBUG("qtaguid[%d]: left %d\n", par->hooknum, res);
++	return res;
++}
++
++#ifdef DDEBUG
++/* This function is not in xt_qtaguid_print.c because of locks visibility */
++static void prdebug_full_state(int indent_level, const char *fmt, ...)
++{
++	va_list args;
++	char *fmt_buff;
++	char *buff;
++
++	if (!unlikely(qtaguid_debug_mask & DDEBUG_MASK))
++		return;
++
++	fmt_buff = kasprintf(GFP_ATOMIC,
++			     "qtaguid: %s(): %s {\n", __func__, fmt);
++	BUG_ON(!fmt_buff);
++	va_start(args, fmt);
++	buff = kvasprintf(GFP_ATOMIC,
++			  fmt_buff, args);
++	BUG_ON(!buff);
++	pr_debug("%s", buff);
++	kfree(fmt_buff);
++	kfree(buff);
++	va_end(args);
++
++	spin_lock_bh(&sock_tag_list_lock);
++	prdebug_sock_tag_tree(indent_level, &sock_tag_tree);
++	spin_unlock_bh(&sock_tag_list_lock);
++
++	spin_lock_bh(&sock_tag_list_lock);
++	spin_lock_bh(&uid_tag_data_tree_lock);
++	prdebug_uid_tag_data_tree(indent_level, &uid_tag_data_tree);
++	prdebug_proc_qtu_data_tree(indent_level, &proc_qtu_data_tree);
++	spin_unlock_bh(&uid_tag_data_tree_lock);
++	spin_unlock_bh(&sock_tag_list_lock);
++
++	spin_lock_bh(&iface_stat_list_lock);
++	prdebug_iface_stat_list(indent_level, &iface_stat_list);
++	spin_unlock_bh(&iface_stat_list_lock);
++
++	pr_debug("qtaguid: %s(): }\n", __func__);
++}
++#else
++static void prdebug_full_state(int indent_level, const char *fmt, ...) {}
++#endif
++
++struct proc_ctrl_print_info {
++	struct sock *sk; /* socket found by reading to sk_pos */
++	loff_t sk_pos;
++};
++
++static void *qtaguid_ctrl_proc_next(struct seq_file *m, void *v, loff_t *pos)
++{
++	struct proc_ctrl_print_info *pcpi = m->private;
++	struct sock_tag *sock_tag_entry = v;
++	struct rb_node *node;
++
++	(*pos)++;
++
++	if (!v || v  == SEQ_START_TOKEN)
++		return NULL;
++
++	node = rb_next(&sock_tag_entry->sock_node);
++	if (!node) {
++		pcpi->sk = NULL;
++		sock_tag_entry = SEQ_START_TOKEN;
++	} else {
++		sock_tag_entry = rb_entry(node, struct sock_tag, sock_node);
++		pcpi->sk = sock_tag_entry->sk;
++	}
++	pcpi->sk_pos = *pos;
++	return sock_tag_entry;
++}
++
++static void *qtaguid_ctrl_proc_start(struct seq_file *m, loff_t *pos)
++{
++	struct proc_ctrl_print_info *pcpi = m->private;
++	struct sock_tag *sock_tag_entry;
++	struct rb_node *node;
++
++	spin_lock_bh(&sock_tag_list_lock);
++
++	if (unlikely(module_passive))
++		return NULL;
++
++	if (*pos == 0) {
++		pcpi->sk_pos = 0;
++		node = rb_first(&sock_tag_tree);
++		if (!node) {
++			pcpi->sk = NULL;
++			return SEQ_START_TOKEN;
++		}
++		sock_tag_entry = rb_entry(node, struct sock_tag, sock_node);
++		pcpi->sk = sock_tag_entry->sk;
++	} else {
++		sock_tag_entry = (pcpi->sk ? get_sock_stat_nl(pcpi->sk) :
++						NULL) ?: SEQ_START_TOKEN;
++		if (*pos != pcpi->sk_pos) {
++			/* seq_read skipped a next call */
++			*pos = pcpi->sk_pos;
++			return qtaguid_ctrl_proc_next(m, sock_tag_entry, pos);
++		}
++	}
++	return sock_tag_entry;
++}
++
++static void qtaguid_ctrl_proc_stop(struct seq_file *m, void *v)
++{
++	spin_unlock_bh(&sock_tag_list_lock);
++}
++
++/*
++ * Procfs reader to get all active socket tags using style "1)" as described in
++ * fs/proc/generic.c
++ */
++static int qtaguid_ctrl_proc_show(struct seq_file *m, void *v)
++{
++	struct sock_tag *sock_tag_entry = v;
++	uid_t uid;
++	long f_count;
++
++	CT_DEBUG("qtaguid: proc ctrl pid=%u tgid=%u uid=%u\n",
++		 current->pid, current->tgid, from_kuid(&init_user_ns, current_fsuid()));
++
++	if (sock_tag_entry != SEQ_START_TOKEN) {
++		uid = get_uid_from_tag(sock_tag_entry->tag);
++		CT_DEBUG("qtaguid: proc_read(): sk=%p tag=0x%llx (uid=%u) "
++			 "pid=%u\n",
++			 sock_tag_entry->sk,
++			 sock_tag_entry->tag,
++			 uid,
++			 sock_tag_entry->pid
++			);
++		f_count = atomic_long_read(
++			&sock_tag_entry->socket->file->f_count);
++		seq_printf(m, "sock=%p tag=0x%llx (uid=%u) pid=%u "
++			   "f_count=%lu\n",
++			   sock_tag_entry->sk,
++			   sock_tag_entry->tag, uid,
++			   sock_tag_entry->pid, f_count);
++	} else {
++		seq_printf(m, "events: sockets_tagged=%llu "
++			   "sockets_untagged=%llu "
++			   "counter_set_changes=%llu "
++			   "delete_cmds=%llu "
++			   "iface_events=%llu "
++			   "match_calls=%llu "
++			   "match_calls_prepost=%llu "
++			   "match_found_sk=%llu "
++			   "match_found_sk_in_ct=%llu "
++			   "match_found_no_sk_in_ct=%llu "
++			   "match_no_sk=%llu "
++			   "match_no_sk_file=%llu\n",
++			   (u64)atomic64_read(&qtu_events.sockets_tagged),
++			   (u64)atomic64_read(&qtu_events.sockets_untagged),
++			   (u64)atomic64_read(&qtu_events.counter_set_changes),
++			   (u64)atomic64_read(&qtu_events.delete_cmds),
++			   (u64)atomic64_read(&qtu_events.iface_events),
++			   (u64)atomic64_read(&qtu_events.match_calls),
++			   (u64)atomic64_read(&qtu_events.match_calls_prepost),
++			   (u64)atomic64_read(&qtu_events.match_found_sk),
++			   (u64)atomic64_read(&qtu_events.match_found_sk_in_ct),
++			   (u64)atomic64_read(&qtu_events.match_found_no_sk_in_ct),
++			   (u64)atomic64_read(&qtu_events.match_no_sk),
++			   (u64)atomic64_read(&qtu_events.match_no_sk_file));
++
++		/* Count the following as part of the last item_index */
++		prdebug_full_state(0, "proc ctrl");
++	}
++
++	return 0;
++}
++
++/*
++ * Delete socket tags, and stat tags associated with a given
++ * accouting tag and uid.
++ */
++static int ctrl_cmd_delete(const char *input)
++{
++	char cmd;
++	int uid_int;
++	kuid_t uid;
++	uid_t entry_uid;
++	tag_t acct_tag;
++	tag_t tag;
++	int res, argc;
++	struct iface_stat *iface_entry;
++	struct rb_node *node;
++	struct sock_tag *st_entry;
++	struct rb_root st_to_free_tree = RB_ROOT;
++	struct tag_stat *ts_entry;
++	struct tag_counter_set *tcs_entry;
++	struct tag_ref *tr_entry;
++	struct uid_tag_data *utd_entry;
++
++	argc = sscanf(input, "%c %llu %u", &cmd, &acct_tag, &uid_int);
++	uid = make_kuid(&init_user_ns, uid_int);
++	CT_DEBUG("qtaguid: ctrl_delete(%s): argc=%d cmd=%c "
++		 "user_tag=0x%llx uid=%u\n", input, argc, cmd,
++		 acct_tag, uid_int);
++	if (argc < 2) {
++		res = -EINVAL;
++		goto err;
++	}
++	if (!valid_atag(acct_tag)) {
++		pr_info("qtaguid: ctrl_delete(%s): invalid tag\n", input);
++		res = -EINVAL;
++		goto err;
++	}
++	if (argc < 3) {
++		uid = current_fsuid();
++		uid_int = from_kuid(&init_user_ns, uid);
++	} else if (!can_impersonate_uid(uid)) {
++		pr_info("qtaguid: ctrl_delete(%s): "
++			"insufficient priv from pid=%u tgid=%u uid=%u\n",
++			input, current->pid, current->tgid, from_kuid(&init_user_ns, current_fsuid()));
++		res = -EPERM;
++		goto err;
++	}
++
++	tag = combine_atag_with_uid(acct_tag, uid_int);
++	CT_DEBUG("qtaguid: ctrl_delete(%s): "
++		 "looking for tag=0x%llx (uid=%u)\n",
++		 input, tag, uid_int);
++
++	/* Delete socket tags */
++	spin_lock_bh(&sock_tag_list_lock);
++	node = rb_first(&sock_tag_tree);
++	while (node) {
++		st_entry = rb_entry(node, struct sock_tag, sock_node);
++		entry_uid = get_uid_from_tag(st_entry->tag);
++		node = rb_next(node);
++		if (entry_uid != uid_int)
++			continue;
++
++		CT_DEBUG("qtaguid: ctrl_delete(%s): st tag=0x%llx (uid=%u)\n",
++			 input, st_entry->tag, entry_uid);
++
++		if (!acct_tag || st_entry->tag == tag) {
++			rb_erase(&st_entry->sock_node, &sock_tag_tree);
++			/* Can't sockfd_put() within spinlock, do it later. */
++			sock_tag_tree_insert(st_entry, &st_to_free_tree);
++			tr_entry = lookup_tag_ref(st_entry->tag, NULL);
++			BUG_ON(tr_entry->num_sock_tags <= 0);
++			tr_entry->num_sock_tags--;
++			/*
++			 * TODO: remove if, and start failing.
++			 * This is a hack to work around the fact that in some
++			 * places we have "if (IS_ERR_OR_NULL(pqd_entry))"
++			 * and are trying to work around apps
++			 * that didn't open the /dev/xt_qtaguid.
++			 */
++			if (st_entry->list.next && st_entry->list.prev)
++				list_del(&st_entry->list);
++		}
++	}
++	spin_unlock_bh(&sock_tag_list_lock);
++
++	sock_tag_tree_erase(&st_to_free_tree);
++
++	/* Delete tag counter-sets */
++	spin_lock_bh(&tag_counter_set_list_lock);
++	/* Counter sets are only on the uid tag, not full tag */
++	tcs_entry = tag_counter_set_tree_search(&tag_counter_set_tree, tag);
++	if (tcs_entry) {
++		CT_DEBUG("qtaguid: ctrl_delete(%s): "
++			 "erase tcs: tag=0x%llx (uid=%u) set=%d\n",
++			 input,
++			 tcs_entry->tn.tag,
++			 get_uid_from_tag(tcs_entry->tn.tag),
++			 tcs_entry->active_set);
++		rb_erase(&tcs_entry->tn.node, &tag_counter_set_tree);
++		kfree(tcs_entry);
++	}
++	spin_unlock_bh(&tag_counter_set_list_lock);
++
++	/*
++	 * If acct_tag is 0, then all entries belonging to uid are
++	 * erased.
++	 */
++	spin_lock_bh(&iface_stat_list_lock);
++	list_for_each_entry(iface_entry, &iface_stat_list, list) {
++		spin_lock_bh(&iface_entry->tag_stat_list_lock);
++		node = rb_first(&iface_entry->tag_stat_tree);
++		while (node) {
++			ts_entry = rb_entry(node, struct tag_stat, tn.node);
++			entry_uid = get_uid_from_tag(ts_entry->tn.tag);
++			node = rb_next(node);
++
++			CT_DEBUG("qtaguid: ctrl_delete(%s): "
++				 "ts tag=0x%llx (uid=%u)\n",
++				 input, ts_entry->tn.tag, entry_uid);
++
++			if (entry_uid != uid_int)
++				continue;
++			if (!acct_tag || ts_entry->tn.tag == tag) {
++				CT_DEBUG("qtaguid: ctrl_delete(%s): "
++					 "erase ts: %s 0x%llx %u\n",
++					 input, iface_entry->ifname,
++					 get_atag_from_tag(ts_entry->tn.tag),
++					 entry_uid);
++				rb_erase(&ts_entry->tn.node,
++					 &iface_entry->tag_stat_tree);
++				kfree(ts_entry);
++			}
++		}
++		spin_unlock_bh(&iface_entry->tag_stat_list_lock);
++	}
++	spin_unlock_bh(&iface_stat_list_lock);
++
++	/* Cleanup the uid_tag_data */
++	spin_lock_bh(&uid_tag_data_tree_lock);
++	node = rb_first(&uid_tag_data_tree);
++	while (node) {
++		utd_entry = rb_entry(node, struct uid_tag_data, node);
++		entry_uid = utd_entry->uid;
++		node = rb_next(node);
++
++		CT_DEBUG("qtaguid: ctrl_delete(%s): "
++			 "utd uid=%u\n",
++			 input, entry_uid);
++
++		if (entry_uid != uid_int)
++			continue;
++		/*
++		 * Go over the tag_refs, and those that don't have
++		 * sock_tags using them are freed.
++		 */
++		put_tag_ref_tree(tag, utd_entry);
++		put_utd_entry(utd_entry);
++	}
++	spin_unlock_bh(&uid_tag_data_tree_lock);
++
++	atomic64_inc(&qtu_events.delete_cmds);
++	res = 0;
++
++err:
++	return res;
++}
++
++static int ctrl_cmd_counter_set(const char *input)
++{
++	char cmd;
++	uid_t uid = 0;
++	tag_t tag;
++	int res, argc;
++	struct tag_counter_set *tcs;
++	int counter_set;
++
++	argc = sscanf(input, "%c %d %u", &cmd, &counter_set, &uid);
++	CT_DEBUG("qtaguid: ctrl_counterset(%s): argc=%d cmd=%c "
++		 "set=%d uid=%u\n", input, argc, cmd,
++		 counter_set, uid);
++	if (argc != 3) {
++		res = -EINVAL;
++		goto err;
++	}
++	if (counter_set < 0 || counter_set >= IFS_MAX_COUNTER_SETS) {
++		pr_info("qtaguid: ctrl_counterset(%s): invalid counter_set range\n",
++			input);
++		res = -EINVAL;
++		goto err;
++	}
++	if (!can_manipulate_uids()) {
++		pr_info("qtaguid: ctrl_counterset(%s): "
++			"insufficient priv from pid=%u tgid=%u uid=%u\n",
++			input, current->pid, current->tgid, from_kuid(&init_user_ns, current_fsuid()));
++		res = -EPERM;
++		goto err;
++	}
++
++	tag = make_tag_from_uid(uid);
++	spin_lock_bh(&tag_counter_set_list_lock);
++	tcs = tag_counter_set_tree_search(&tag_counter_set_tree, tag);
++	if (!tcs) {
++		tcs = kzalloc(sizeof(*tcs), GFP_ATOMIC);
++		if (!tcs) {
++			spin_unlock_bh(&tag_counter_set_list_lock);
++			pr_err("qtaguid: ctrl_counterset(%s): "
++			       "failed to alloc counter set\n",
++			       input);
++			res = -ENOMEM;
++			goto err;
++		}
++		tcs->tn.tag = tag;
++		tag_counter_set_tree_insert(tcs, &tag_counter_set_tree);
++		CT_DEBUG("qtaguid: ctrl_counterset(%s): added tcs tag=0x%llx "
++			 "(uid=%u) set=%d\n",
++			 input, tag, get_uid_from_tag(tag), counter_set);
++	}
++	tcs->active_set = counter_set;
++	spin_unlock_bh(&tag_counter_set_list_lock);
++	atomic64_inc(&qtu_events.counter_set_changes);
++	res = 0;
++
++err:
++	return res;
++}
++
++static int ctrl_cmd_tag(const char *input)
++{
++	char cmd;
++	int sock_fd = 0;
++	kuid_t uid;
++	unsigned int uid_int = 0;
++	tag_t acct_tag = make_atag_from_value(0);
++	tag_t full_tag;
++	struct socket *el_socket;
++	int res, argc;
++	struct sock_tag *sock_tag_entry;
++	struct tag_ref *tag_ref_entry;
++	struct uid_tag_data *uid_tag_data_entry;
++	struct proc_qtu_data *pqd_entry;
++
++	/* Unassigned args will get defaulted later. */
++	argc = sscanf(input, "%c %d %llu %u", &cmd, &sock_fd, &acct_tag, &uid_int);
++	uid = make_kuid(&init_user_ns, uid_int);
++	CT_DEBUG("qtaguid: ctrl_tag(%s): argc=%d cmd=%c sock_fd=%d "
++		 "acct_tag=0x%llx uid=%u\n", input, argc, cmd, sock_fd,
++		 acct_tag, uid_int);
++	if (argc < 2) {
++		res = -EINVAL;
++		goto err;
++	}
++	el_socket = sockfd_lookup(sock_fd, &res);  /* This locks the file */
++	if (!el_socket) {
++		pr_info("qtaguid: ctrl_tag(%s): failed to lookup"
++			" sock_fd=%d err=%d pid=%u tgid=%u uid=%u\n",
++			input, sock_fd, res, current->pid, current->tgid,
++			from_kuid(&init_user_ns, current_fsuid()));
++		goto err;
++	}
++	CT_DEBUG("qtaguid: ctrl_tag(%s): socket->...->f_count=%ld ->sk=%p\n",
++		 input, atomic_long_read(&el_socket->file->f_count),
++		 el_socket->sk);
++	if (argc < 3) {
++		acct_tag = make_atag_from_value(0);
++	} else if (!valid_atag(acct_tag)) {
++		pr_info("qtaguid: ctrl_tag(%s): invalid tag\n", input);
++		res = -EINVAL;
++		goto err_put;
++	}
++	CT_DEBUG("qtaguid: ctrl_tag(%s): "
++		 "pid=%u tgid=%u uid=%u euid=%u fsuid=%u "
++		 "ctrl.gid=%u in_group()=%d in_egroup()=%d\n",
++		 input, current->pid, current->tgid,
++		 from_kuid(&init_user_ns, current_uid()),
++		 from_kuid(&init_user_ns, current_euid()),
++		 from_kuid(&init_user_ns, current_fsuid()),
++		 from_kgid(&init_user_ns, xt_qtaguid_ctrl_file->gid),
++		 in_group_p(xt_qtaguid_ctrl_file->gid),
++		 in_egroup_p(xt_qtaguid_ctrl_file->gid));
++	if (argc < 4) {
++		uid = current_fsuid();
++		uid_int = from_kuid(&init_user_ns, uid);
++	} else if (!can_impersonate_uid(uid)) {
++		pr_info("qtaguid: ctrl_tag(%s): "
++			"insufficient priv from pid=%u tgid=%u uid=%u\n",
++			input, current->pid, current->tgid, from_kuid(&init_user_ns, current_fsuid()));
++		res = -EPERM;
++		goto err_put;
++	}
++	full_tag = combine_atag_with_uid(acct_tag, uid_int);
++
++	spin_lock_bh(&sock_tag_list_lock);
++	sock_tag_entry = get_sock_stat_nl(el_socket->sk);
++	tag_ref_entry = get_tag_ref(full_tag, &uid_tag_data_entry);
++	if (IS_ERR(tag_ref_entry)) {
++		res = PTR_ERR(tag_ref_entry);
++		spin_unlock_bh(&sock_tag_list_lock);
++		goto err_put;
++	}
++	tag_ref_entry->num_sock_tags++;
++	if (sock_tag_entry) {
++		struct tag_ref *prev_tag_ref_entry;
++
++		CT_DEBUG("qtaguid: ctrl_tag(%s): retag for sk=%p "
++			 "st@%p ...->f_count=%ld\n",
++			 input, el_socket->sk, sock_tag_entry,
++			 atomic_long_read(&el_socket->file->f_count));
++		/*
++		 * This is a re-tagging, so release the sock_fd that was
++		 * locked at the time of the 1st tagging.
++		 * There is still the ref from this call's sockfd_lookup() so
++		 * it can be done within the spinlock.
++		 */
++		sockfd_put(sock_tag_entry->socket);
++		prev_tag_ref_entry = lookup_tag_ref(sock_tag_entry->tag,
++						    &uid_tag_data_entry);
++		BUG_ON(IS_ERR_OR_NULL(prev_tag_ref_entry));
++		BUG_ON(prev_tag_ref_entry->num_sock_tags <= 0);
++		prev_tag_ref_entry->num_sock_tags--;
++		sock_tag_entry->tag = full_tag;
++	} else {
++		CT_DEBUG("qtaguid: ctrl_tag(%s): newtag for sk=%p\n",
++			 input, el_socket->sk);
++		sock_tag_entry = kzalloc(sizeof(*sock_tag_entry),
++					 GFP_ATOMIC);
++		if (!sock_tag_entry) {
++			pr_err("qtaguid: ctrl_tag(%s): "
++			       "socket tag alloc failed\n",
++			       input);
++			spin_unlock_bh(&sock_tag_list_lock);
++			res = -ENOMEM;
++			goto err_tag_unref_put;
++		}
++		sock_tag_entry->sk = el_socket->sk;
++		sock_tag_entry->socket = el_socket;
++		sock_tag_entry->pid = current->tgid;
++		sock_tag_entry->tag = combine_atag_with_uid(acct_tag, uid_int);
++		spin_lock_bh(&uid_tag_data_tree_lock);
++		pqd_entry = proc_qtu_data_tree_search(
++			&proc_qtu_data_tree, current->tgid);
++		/*
++		 * TODO: remove if, and start failing.
++		 * At first, we want to catch user-space code that is not
++		 * opening the /dev/xt_qtaguid.
++		 */
++		if (IS_ERR_OR_NULL(pqd_entry))
++			pr_warn_once(
++				"qtaguid: %s(): "
++				"User space forgot to open /dev/xt_qtaguid? "
++				"pid=%u tgid=%u uid=%u\n", __func__,
++				current->pid, current->tgid,
++				from_kuid(&init_user_ns, current_fsuid()));
++		else
++			list_add(&sock_tag_entry->list,
++				 &pqd_entry->sock_tag_list);
++		spin_unlock_bh(&uid_tag_data_tree_lock);
++
++		sock_tag_tree_insert(sock_tag_entry, &sock_tag_tree);
++		atomic64_inc(&qtu_events.sockets_tagged);
++	}
++	spin_unlock_bh(&sock_tag_list_lock);
++	/* We keep the ref to the socket (file) until it is untagged */
++	CT_DEBUG("qtaguid: ctrl_tag(%s): done st@%p ...->f_count=%ld\n",
++		 input, sock_tag_entry,
++		 atomic_long_read(&el_socket->file->f_count));
++	return 0;
++
++err_tag_unref_put:
++	BUG_ON(tag_ref_entry->num_sock_tags <= 0);
++	tag_ref_entry->num_sock_tags--;
++	free_tag_ref_from_utd_entry(tag_ref_entry, uid_tag_data_entry);
++err_put:
++	CT_DEBUG("qtaguid: ctrl_tag(%s): done. ...->f_count=%ld\n",
++		 input, atomic_long_read(&el_socket->file->f_count) - 1);
++	/* Release the sock_fd that was grabbed by sockfd_lookup(). */
++	sockfd_put(el_socket);
++	return res;
++
++err:
++	CT_DEBUG("qtaguid: ctrl_tag(%s): done.\n", input);
++	return res;
++}
++
++static int ctrl_cmd_untag(const char *input)
++{
++	char cmd;
++	int sock_fd = 0;
++	struct socket *el_socket;
++	int res, argc;
++	struct sock_tag *sock_tag_entry;
++	struct tag_ref *tag_ref_entry;
++	struct uid_tag_data *utd_entry;
++	struct proc_qtu_data *pqd_entry;
++
++	argc = sscanf(input, "%c %d", &cmd, &sock_fd);
++	CT_DEBUG("qtaguid: ctrl_untag(%s): argc=%d cmd=%c sock_fd=%d\n",
++		 input, argc, cmd, sock_fd);
++	if (argc < 2) {
++		res = -EINVAL;
++		goto err;
++	}
++	el_socket = sockfd_lookup(sock_fd, &res);  /* This locks the file */
++	if (!el_socket) {
++		pr_info("qtaguid: ctrl_untag(%s): failed to lookup"
++			" sock_fd=%d err=%d pid=%u tgid=%u uid=%u\n",
++			input, sock_fd, res, current->pid, current->tgid,
++			from_kuid(&init_user_ns, current_fsuid()));
++		goto err;
++	}
++	CT_DEBUG("qtaguid: ctrl_untag(%s): socket->...->f_count=%ld ->sk=%p\n",
++		 input, atomic_long_read(&el_socket->file->f_count),
++		 el_socket->sk);
++	spin_lock_bh(&sock_tag_list_lock);
++	sock_tag_entry = get_sock_stat_nl(el_socket->sk);
++	if (!sock_tag_entry) {
++		spin_unlock_bh(&sock_tag_list_lock);
++		res = -EINVAL;
++		goto err_put;
++	}
++	/*
++	 * The socket already belongs to the current process
++	 * so it can do whatever it wants to it.
++	 */
++	rb_erase(&sock_tag_entry->sock_node, &sock_tag_tree);
++
++	tag_ref_entry = lookup_tag_ref(sock_tag_entry->tag, &utd_entry);
++	BUG_ON(!tag_ref_entry);
++	BUG_ON(tag_ref_entry->num_sock_tags <= 0);
++	spin_lock_bh(&uid_tag_data_tree_lock);
++	pqd_entry = proc_qtu_data_tree_search(
++		&proc_qtu_data_tree, current->tgid);
++	/*
++	 * TODO: remove if, and start failing.
++	 * At first, we want to catch user-space code that is not
++	 * opening the /dev/xt_qtaguid.
++	 */
++	if (IS_ERR_OR_NULL(pqd_entry))
++		pr_warn_once("qtaguid: %s(): "
++			     "User space forgot to open /dev/xt_qtaguid? "
++			     "pid=%u tgid=%u uid=%u\n", __func__,
++			     current->pid, current->tgid, from_kuid(&init_user_ns, current_fsuid()));
++	else
++		list_del(&sock_tag_entry->list);
++	spin_unlock_bh(&uid_tag_data_tree_lock);
++	/*
++	 * We don't free tag_ref from the utd_entry here,
++	 * only during a cmd_delete().
++	 */
++	tag_ref_entry->num_sock_tags--;
++	spin_unlock_bh(&sock_tag_list_lock);
++	/*
++	 * Release the sock_fd that was grabbed at tag time,
++	 * and once more for the sockfd_lookup() here.
++	 */
++	sockfd_put(sock_tag_entry->socket);
++	CT_DEBUG("qtaguid: ctrl_untag(%s): done. st@%p ...->f_count=%ld\n",
++		 input, sock_tag_entry,
++		 atomic_long_read(&el_socket->file->f_count) - 1);
++	sockfd_put(el_socket);
++
++	kfree(sock_tag_entry);
++	atomic64_inc(&qtu_events.sockets_untagged);
++
++	return 0;
++
++err_put:
++	CT_DEBUG("qtaguid: ctrl_untag(%s): done. socket->...->f_count=%ld\n",
++		 input, atomic_long_read(&el_socket->file->f_count) - 1);
++	/* Release the sock_fd that was grabbed by sockfd_lookup(). */
++	sockfd_put(el_socket);
++	return res;
++
++err:
++	CT_DEBUG("qtaguid: ctrl_untag(%s): done.\n", input);
++	return res;
++}
++
++static ssize_t qtaguid_ctrl_parse(const char *input, size_t count)
++{
++	char cmd;
++	ssize_t res;
++
++	CT_DEBUG("qtaguid: ctrl(%s): pid=%u tgid=%u uid=%u\n",
++		 input, current->pid, current->tgid, from_kuid(&init_user_ns, current_fsuid()));
++
++	cmd = input[0];
++	/* Collect params for commands */
++	switch (cmd) {
++	case 'd':
++		res = ctrl_cmd_delete(input);
++		break;
++
++	case 's':
++		res = ctrl_cmd_counter_set(input);
++		break;
++
++	case 't':
++		res = ctrl_cmd_tag(input);
++		break;
++
++	case 'u':
++		res = ctrl_cmd_untag(input);
++		break;
++
++	default:
++		res = -EINVAL;
++		goto err;
++	}
++	if (!res)
++		res = count;
++err:
++	CT_DEBUG("qtaguid: ctrl(%s): res=%zd\n", input, res);
++	return res;
++}
++
++#define MAX_QTAGUID_CTRL_INPUT_LEN 255
++static ssize_t qtaguid_ctrl_proc_write(struct file *file, const char __user *buffer,
++				   size_t count, loff_t *offp)
++{
++	char input_buf[MAX_QTAGUID_CTRL_INPUT_LEN];
++
++	if (unlikely(module_passive))
++		return count;
++
++	if (count >= MAX_QTAGUID_CTRL_INPUT_LEN)
++		return -EINVAL;
++
++	if (copy_from_user(input_buf, buffer, count))
++		return -EFAULT;
++
++	input_buf[count] = '\0';
++	return qtaguid_ctrl_parse(input_buf, count);
++}
++
++struct proc_print_info {
++	struct iface_stat *iface_entry;
++	int item_index;
++	tag_t tag; /* tag found by reading to tag_pos */
++	off_t tag_pos;
++	int tag_item_index;
++};
++
++static void pp_stats_header(struct seq_file *m)
++{
++	seq_puts(m,
++		 "idx iface acct_tag_hex uid_tag_int cnt_set "
++		 "rx_bytes rx_packets "
++		 "tx_bytes tx_packets "
++		 "rx_tcp_bytes rx_tcp_packets "
++		 "rx_udp_bytes rx_udp_packets "
++		 "rx_other_bytes rx_other_packets "
++		 "tx_tcp_bytes tx_tcp_packets "
++		 "tx_udp_bytes tx_udp_packets "
++		 "tx_other_bytes tx_other_packets\n");
++}
++
++static int pp_stats_line(struct seq_file *m, struct tag_stat *ts_entry,
++			 int cnt_set)
++{
++	int ret;
++	struct data_counters *cnts;
++	tag_t tag = ts_entry->tn.tag;
++	uid_t stat_uid = get_uid_from_tag(tag);
++	struct proc_print_info *ppi = m->private;
++	/* Detailed tags are not available to everybody */
++	if (get_atag_from_tag(tag) && !can_read_other_uid_stats(
++						make_kuid(&init_user_ns,stat_uid))) {
++		CT_DEBUG("qtaguid: stats line: "
++			 "%s 0x%llx %u: insufficient priv "
++			 "from pid=%u tgid=%u uid=%u stats.gid=%u\n",
++			 ppi->iface_entry->ifname,
++			 get_atag_from_tag(tag), stat_uid,
++			 current->pid, current->tgid, from_kuid(&init_user_ns, current_fsuid()),
++			 from_kgid(&init_user_ns,xt_qtaguid_stats_file->gid));
++		return 0;
++	}
++	ppi->item_index++;
++	cnts = &ts_entry->counters;
++	ret = seq_printf(m, "%d %s 0x%llx %u %u "
++		"%llu %llu "
++		"%llu %llu "
++		"%llu %llu "
++		"%llu %llu "
++		"%llu %llu "
++		"%llu %llu "
++		"%llu %llu "
++		"%llu %llu\n",
++		ppi->item_index,
++		ppi->iface_entry->ifname,
++		get_atag_from_tag(tag),
++		stat_uid,
++		cnt_set,
++		dc_sum_bytes(cnts, cnt_set, IFS_RX),
++		dc_sum_packets(cnts, cnt_set, IFS_RX),
++		dc_sum_bytes(cnts, cnt_set, IFS_TX),
++		dc_sum_packets(cnts, cnt_set, IFS_TX),
++		cnts->bpc[cnt_set][IFS_RX][IFS_TCP].bytes,
++		cnts->bpc[cnt_set][IFS_RX][IFS_TCP].packets,
++		cnts->bpc[cnt_set][IFS_RX][IFS_UDP].bytes,
++		cnts->bpc[cnt_set][IFS_RX][IFS_UDP].packets,
++		cnts->bpc[cnt_set][IFS_RX][IFS_PROTO_OTHER].bytes,
++		cnts->bpc[cnt_set][IFS_RX][IFS_PROTO_OTHER].packets,
++		cnts->bpc[cnt_set][IFS_TX][IFS_TCP].bytes,
++		cnts->bpc[cnt_set][IFS_TX][IFS_TCP].packets,
++		cnts->bpc[cnt_set][IFS_TX][IFS_UDP].bytes,
++		cnts->bpc[cnt_set][IFS_TX][IFS_UDP].packets,
++		cnts->bpc[cnt_set][IFS_TX][IFS_PROTO_OTHER].bytes,
++		cnts->bpc[cnt_set][IFS_TX][IFS_PROTO_OTHER].packets);
++	return ret ?: 1;
++}
++
++static bool pp_sets(struct seq_file *m, struct tag_stat *ts_entry)
++{
++	int ret;
++	int counter_set;
++	for (counter_set = 0; counter_set < IFS_MAX_COUNTER_SETS;
++	     counter_set++) {
++		ret = pp_stats_line(m, ts_entry, counter_set);
++		if (ret < 0)
++			return false;
++	}
++	return true;
++}
++
++static int qtaguid_stats_proc_iface_stat_ptr_valid(struct iface_stat *ptr)
++{
++	struct iface_stat *iface_entry;
++
++	if (!ptr)
++		return false;
++
++	list_for_each_entry(iface_entry, &iface_stat_list, list)
++		if (iface_entry == ptr)
++			return true;
++	return false;
++}
++
++static void qtaguid_stats_proc_next_iface_entry(struct proc_print_info *ppi)
++{
++	spin_unlock_bh(&ppi->iface_entry->tag_stat_list_lock);
++	list_for_each_entry_continue(ppi->iface_entry, &iface_stat_list, list) {
++		spin_lock_bh(&ppi->iface_entry->tag_stat_list_lock);
++		return;
++	}
++	ppi->iface_entry = NULL;
++}
++
++static void *qtaguid_stats_proc_next(struct seq_file *m, void *v, loff_t *pos)
++{
++	struct proc_print_info *ppi = m->private;
++	struct tag_stat *ts_entry;
++	struct rb_node *node;
++
++	if (!v) {
++		pr_err("qtaguid: %s(): unexpected v: NULL\n", __func__);
++		return NULL;
++	}
++
++	(*pos)++;
++
++	if (!ppi->iface_entry || unlikely(module_passive))
++		return NULL;
++
++	if (v == SEQ_START_TOKEN)
++		node = rb_first(&ppi->iface_entry->tag_stat_tree);
++	else
++		node = rb_next(&((struct tag_stat *)v)->tn.node);
++
++	while (!node) {
++		qtaguid_stats_proc_next_iface_entry(ppi);
++		if (!ppi->iface_entry)
++			return NULL;
++		node = rb_first(&ppi->iface_entry->tag_stat_tree);
++	}
++
++	ts_entry = rb_entry(node, struct tag_stat, tn.node);
++	ppi->tag = ts_entry->tn.tag;
++	ppi->tag_pos = *pos;
++	ppi->tag_item_index = ppi->item_index;
++	return ts_entry;
++}
++
++static void *qtaguid_stats_proc_start(struct seq_file *m, loff_t *pos)
++{
++	struct proc_print_info *ppi = m->private;
++	struct tag_stat *ts_entry = NULL;
++
++	spin_lock_bh(&iface_stat_list_lock);
++
++	if (*pos == 0) {
++		ppi->item_index = 1;
++		ppi->tag_pos = 0;
++		if (list_empty(&iface_stat_list)) {
++			ppi->iface_entry = NULL;
++		} else {
++			ppi->iface_entry = list_first_entry(&iface_stat_list,
++							    struct iface_stat,
++							    list);
++			spin_lock_bh(&ppi->iface_entry->tag_stat_list_lock);
++		}
++		return SEQ_START_TOKEN;
++	}
++	if (!qtaguid_stats_proc_iface_stat_ptr_valid(ppi->iface_entry)) {
++		if (ppi->iface_entry) {
++			pr_err("qtaguid: %s(): iface_entry %p not found\n",
++			       __func__, ppi->iface_entry);
++			ppi->iface_entry = NULL;
++		}
++		return NULL;
++	}
++
++	spin_lock_bh(&ppi->iface_entry->tag_stat_list_lock);
++
++	if (!ppi->tag_pos) {
++		/* seq_read skipped first next call */
++		ts_entry = SEQ_START_TOKEN;
++	} else {
++		ts_entry = tag_stat_tree_search(
++				&ppi->iface_entry->tag_stat_tree, ppi->tag);
++		if (!ts_entry) {
++			pr_info("qtaguid: %s(): tag_stat.tag 0x%llx not found. Abort.\n",
++				__func__, ppi->tag);
++			return NULL;
++		}
++	}
++
++	if (*pos == ppi->tag_pos) { /* normal resume */
++		ppi->item_index = ppi->tag_item_index;
++	} else {
++		/* seq_read skipped a next call */
++		*pos = ppi->tag_pos;
++		ts_entry = qtaguid_stats_proc_next(m, ts_entry, pos);
++	}
++
++	return ts_entry;
++}
++
++static void qtaguid_stats_proc_stop(struct seq_file *m, void *v)
++{
++	struct proc_print_info *ppi = m->private;
++	if (ppi->iface_entry)
++		spin_unlock_bh(&ppi->iface_entry->tag_stat_list_lock);
++	spin_unlock_bh(&iface_stat_list_lock);
++}
++
++/*
++ * Procfs reader to get all tag stats using style "1)" as described in
++ * fs/proc/generic.c
++ * Groups all protocols tx/rx bytes.
++ */
++static int qtaguid_stats_proc_show(struct seq_file *m, void *v)
++{
++	struct tag_stat *ts_entry = v;
++
++	if (v == SEQ_START_TOKEN)
++		pp_stats_header(m);
++	else
++		pp_sets(m, ts_entry);
++
++	return 0;
++}
++
++/*------------------------------------------*/
++static int qtudev_open(struct inode *inode, struct file *file)
++{
++	struct uid_tag_data *utd_entry;
++	struct proc_qtu_data  *pqd_entry;
++	struct proc_qtu_data  *new_pqd_entry;
++	int res;
++	bool utd_entry_found;
++
++	if (unlikely(qtu_proc_handling_passive))
++		return 0;
++
++	DR_DEBUG("qtaguid: qtudev_open(): pid=%u tgid=%u uid=%u\n",
++		 current->pid, current->tgid, from_kuid(&init_user_ns, current_fsuid()));
++
++	spin_lock_bh(&uid_tag_data_tree_lock);
++
++	/* Look for existing uid data, or alloc one. */
++	utd_entry = get_uid_data(from_kuid(&init_user_ns, current_fsuid()), &utd_entry_found);
++	if (IS_ERR_OR_NULL(utd_entry)) {
++		res = PTR_ERR(utd_entry);
++		goto err_unlock;
++	}
++
++	/* Look for existing PID based proc_data */
++	pqd_entry = proc_qtu_data_tree_search(&proc_qtu_data_tree,
++					      current->tgid);
++	if (pqd_entry) {
++		pr_err("qtaguid: qtudev_open(): %u/%u %u "
++		       "%s already opened\n",
++		       current->pid, current->tgid, from_kuid(&init_user_ns, current_fsuid()),
++		       QTU_DEV_NAME);
++		res = -EBUSY;
++		goto err_unlock_free_utd;
++	}
++
++	new_pqd_entry = kzalloc(sizeof(*new_pqd_entry), GFP_ATOMIC);
++	if (!new_pqd_entry) {
++		pr_err("qtaguid: qtudev_open(): %u/%u %u: "
++		       "proc data alloc failed\n",
++		       current->pid, current->tgid, from_kuid(&init_user_ns, current_fsuid()));
++		res = -ENOMEM;
++		goto err_unlock_free_utd;
++	}
++	new_pqd_entry->pid = current->tgid;
++	INIT_LIST_HEAD(&new_pqd_entry->sock_tag_list);
++	new_pqd_entry->parent_tag_data = utd_entry;
++	utd_entry->num_pqd++;
++
++	proc_qtu_data_tree_insert(new_pqd_entry,
++				  &proc_qtu_data_tree);
++
++	spin_unlock_bh(&uid_tag_data_tree_lock);
++	DR_DEBUG("qtaguid: tracking data for uid=%u in pqd=%p\n",
++		 from_kuid(&init_user_ns, current_fsuid()), new_pqd_entry);
++	file->private_data = new_pqd_entry;
++	return 0;
++
++err_unlock_free_utd:
++	if (!utd_entry_found) {
++		rb_erase(&utd_entry->node, &uid_tag_data_tree);
++		kfree(utd_entry);
++	}
++err_unlock:
++	spin_unlock_bh(&uid_tag_data_tree_lock);
++	return res;
++}
++
++static int qtudev_release(struct inode *inode, struct file *file)
++{
++	struct proc_qtu_data  *pqd_entry = file->private_data;
++	struct uid_tag_data  *utd_entry = pqd_entry->parent_tag_data;
++	struct sock_tag *st_entry;
++	struct rb_root st_to_free_tree = RB_ROOT;
++	struct list_head *entry, *next;
++	struct tag_ref *tr;
++
++	if (unlikely(qtu_proc_handling_passive))
++		return 0;
++
++	/*
++	 * Do not trust the current->pid, it might just be a kworker cleaning
++	 * up after a dead proc.
++	 */
++	DR_DEBUG("qtaguid: qtudev_release(): "
++		 "pid=%u tgid=%u uid=%u "
++		 "pqd_entry=%p->pid=%u utd_entry=%p->active_tags=%d\n",
++		 current->pid, current->tgid, pqd_entry->parent_tag_data->uid,
++		 pqd_entry, pqd_entry->pid, utd_entry,
++		 utd_entry->num_active_tags);
++
++	spin_lock_bh(&sock_tag_list_lock);
++	spin_lock_bh(&uid_tag_data_tree_lock);
++
++	list_for_each_safe(entry, next, &pqd_entry->sock_tag_list) {
++		st_entry = list_entry(entry, struct sock_tag, list);
++		DR_DEBUG("qtaguid: %s(): "
++			 "erase sock_tag=%p->sk=%p pid=%u tgid=%u uid=%u\n",
++			 __func__,
++			 st_entry, st_entry->sk,
++			 current->pid, current->tgid,
++			 pqd_entry->parent_tag_data->uid);
++
++		utd_entry = uid_tag_data_tree_search(
++			&uid_tag_data_tree,
++			get_uid_from_tag(st_entry->tag));
++		BUG_ON(IS_ERR_OR_NULL(utd_entry));
++		DR_DEBUG("qtaguid: %s(): "
++			 "looking for tag=0x%llx in utd_entry=%p\n", __func__,
++			 st_entry->tag, utd_entry);
++		tr = tag_ref_tree_search(&utd_entry->tag_ref_tree,
++					 st_entry->tag);
++		BUG_ON(!tr);
++		BUG_ON(tr->num_sock_tags <= 0);
++		tr->num_sock_tags--;
++		free_tag_ref_from_utd_entry(tr, utd_entry);
++
++		rb_erase(&st_entry->sock_node, &sock_tag_tree);
++		list_del(&st_entry->list);
++		/* Can't sockfd_put() within spinlock, do it later. */
++		sock_tag_tree_insert(st_entry, &st_to_free_tree);
++
++		/*
++		 * Try to free the utd_entry if no other proc_qtu_data is
++		 * using it (num_pqd is 0) and it doesn't have active tags
++		 * (num_active_tags is 0).
++		 */
++		put_utd_entry(utd_entry);
++	}
++
++	rb_erase(&pqd_entry->node, &proc_qtu_data_tree);
++	BUG_ON(pqd_entry->parent_tag_data->num_pqd < 1);
++	pqd_entry->parent_tag_data->num_pqd--;
++	put_utd_entry(pqd_entry->parent_tag_data);
++	kfree(pqd_entry);
++	file->private_data = NULL;
++
++	spin_unlock_bh(&uid_tag_data_tree_lock);
++	spin_unlock_bh(&sock_tag_list_lock);
++
++
++	sock_tag_tree_erase(&st_to_free_tree);
++
++	prdebug_full_state(0, "%s(): pid=%u tgid=%u", __func__,
++			   current->pid, current->tgid);
++	return 0;
++}
++
++/*------------------------------------------*/
++static const struct file_operations qtudev_fops = {
++	.owner = THIS_MODULE,
++	.open = qtudev_open,
++	.release = qtudev_release,
++};
++
++static struct miscdevice qtu_device = {
++	.minor = MISC_DYNAMIC_MINOR,
++	.name = QTU_DEV_NAME,
++	.fops = &qtudev_fops,
++	/* How sad it doesn't allow for defaults: .mode = S_IRUGO | S_IWUSR */
++};
++
++static const struct seq_operations proc_qtaguid_ctrl_seqops = {
++	.start = qtaguid_ctrl_proc_start,
++	.next = qtaguid_ctrl_proc_next,
++	.stop = qtaguid_ctrl_proc_stop,
++	.show = qtaguid_ctrl_proc_show,
++};
++
++static int proc_qtaguid_ctrl_open(struct inode *inode, struct file *file)
++{
++	return seq_open_private(file, &proc_qtaguid_ctrl_seqops,
++				sizeof(struct proc_ctrl_print_info));
++}
++
++static const struct file_operations proc_qtaguid_ctrl_fops = {
++	.open		= proc_qtaguid_ctrl_open,
++	.read		= seq_read,
++	.write		= qtaguid_ctrl_proc_write,
++	.llseek		= seq_lseek,
++	.release	= seq_release_private,
++};
++
++static const struct seq_operations proc_qtaguid_stats_seqops = {
++	.start = qtaguid_stats_proc_start,
++	.next = qtaguid_stats_proc_next,
++	.stop = qtaguid_stats_proc_stop,
++	.show = qtaguid_stats_proc_show,
++};
++
++static int proc_qtaguid_stats_open(struct inode *inode, struct file *file)
++{
++	return seq_open_private(file, &proc_qtaguid_stats_seqops,
++				sizeof(struct proc_print_info));
++}
++
++static const struct file_operations proc_qtaguid_stats_fops = {
++	.open		= proc_qtaguid_stats_open,
++	.read		= seq_read,
++	.llseek		= seq_lseek,
++	.release	= seq_release_private,
++};
++
++/*------------------------------------------*/
++static int __init qtaguid_proc_register(struct proc_dir_entry **res_procdir)
++{
++	int ret;
++	*res_procdir = proc_mkdir(module_procdirname, init_net.proc_net);
++	if (!*res_procdir) {
++		pr_err("qtaguid: failed to create proc/.../xt_qtaguid\n");
++		ret = -ENOMEM;
++		goto no_dir;
++	}
++
++	xt_qtaguid_ctrl_file = proc_create_data("ctrl", proc_ctrl_perms,
++						*res_procdir,
++						&proc_qtaguid_ctrl_fops,
++						NULL);
++	if (!xt_qtaguid_ctrl_file) {
++		pr_err("qtaguid: failed to create xt_qtaguid/ctrl "
++			" file\n");
++		ret = -ENOMEM;
++		goto no_ctrl_entry;
++	}
++
++	xt_qtaguid_stats_file = proc_create_data("stats", proc_stats_perms,
++						 *res_procdir,
++						 &proc_qtaguid_stats_fops,
++						 NULL);
++	if (!xt_qtaguid_stats_file) {
++		pr_err("qtaguid: failed to create xt_qtaguid/stats "
++			"file\n");
++		ret = -ENOMEM;
++		goto no_stats_entry;
++	}
++	/*
++	 * TODO: add support counter hacking
++	 * xt_qtaguid_stats_file->write_proc = qtaguid_stats_proc_write;
++	 */
++	return 0;
++
++no_stats_entry:
++	remove_proc_entry("ctrl", *res_procdir);
++no_ctrl_entry:
++	remove_proc_entry("xt_qtaguid", NULL);
++no_dir:
++	return ret;
++}
++
++static struct xt_match qtaguid_mt_reg __read_mostly = {
++	/*
++	 * This module masquerades as the "owner" module so that iptables
++	 * tools can deal with it.
++	 */
++	.name       = "owner",
++	.revision   = 1,
++	.family     = NFPROTO_UNSPEC,
++	.match      = qtaguid_mt,
++	.matchsize  = sizeof(struct xt_qtaguid_match_info),
++	.me         = THIS_MODULE,
++};
++
++static int __init qtaguid_mt_init(void)
++{
++	if (qtaguid_proc_register(&xt_qtaguid_procdir)
++	    || iface_stat_init(xt_qtaguid_procdir)
++	    || xt_register_match(&qtaguid_mt_reg)
++	    || misc_register(&qtu_device))
++		return -1;
++	return 0;
++}
++
++/*
++ * TODO: allow unloading of the module.
++ * For now stats are permanent.
++ * Kconfig forces'y/n' and never an 'm'.
++ */
++
++module_init(qtaguid_mt_init);
++MODULE_AUTHOR("jpa <jpa@google.com>");
++MODULE_DESCRIPTION("Xtables: socket owner+tag matching and associated stats");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("ipt_owner");
++MODULE_ALIAS("ip6t_owner");
++MODULE_ALIAS("ipt_qtaguid");
++MODULE_ALIAS("ip6t_qtaguid");
+diff --git a/net/netfilter/xt_qtaguid_internal.h b/net/netfilter/xt_qtaguid_internal.h
+new file mode 100644
+index 0000000..6dc14a9
+--- /dev/null
++++ b/net/netfilter/xt_qtaguid_internal.h
+@@ -0,0 +1,352 @@
++/*
++ * Kernel iptables module to track stats for packets based on user tags.
++ *
++ * (C) 2011 Google, 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.
++ */
++#ifndef __XT_QTAGUID_INTERNAL_H__
++#define __XT_QTAGUID_INTERNAL_H__
++
++#include <linux/types.h>
++#include <linux/rbtree.h>
++#include <linux/spinlock_types.h>
++#include <linux/workqueue.h>
++
++/* Iface handling */
++#define IDEBUG_MASK (1<<0)
++/* Iptable Matching. Per packet. */
++#define MDEBUG_MASK (1<<1)
++/* Red-black tree handling. Per packet. */
++#define RDEBUG_MASK (1<<2)
++/* procfs ctrl/stats handling */
++#define CDEBUG_MASK (1<<3)
++/* dev and resource tracking */
++#define DDEBUG_MASK (1<<4)
++
++/* E.g (IDEBUG_MASK | CDEBUG_MASK | DDEBUG_MASK) */
++#define DEFAULT_DEBUG_MASK 0
++
++/*
++ * (Un)Define these *DEBUG to compile out/in the pr_debug calls.
++ * All undef: text size ~ 0x3030; all def: ~ 0x4404.
++ */
++#define IDEBUG
++#define MDEBUG
++#define RDEBUG
++#define CDEBUG
++#define DDEBUG
++
++#define MSK_DEBUG(mask, ...) do {                           \
++		if (unlikely(qtaguid_debug_mask & (mask)))  \
++			pr_debug(__VA_ARGS__);              \
++	} while (0)
++#ifdef IDEBUG
++#define IF_DEBUG(...) MSK_DEBUG(IDEBUG_MASK, __VA_ARGS__)
++#else
++#define IF_DEBUG(...) no_printk(__VA_ARGS__)
++#endif
++#ifdef MDEBUG
++#define MT_DEBUG(...) MSK_DEBUG(MDEBUG_MASK, __VA_ARGS__)
++#else
++#define MT_DEBUG(...) no_printk(__VA_ARGS__)
++#endif
++#ifdef RDEBUG
++#define RB_DEBUG(...) MSK_DEBUG(RDEBUG_MASK, __VA_ARGS__)
++#else
++#define RB_DEBUG(...) no_printk(__VA_ARGS__)
++#endif
++#ifdef CDEBUG
++#define CT_DEBUG(...) MSK_DEBUG(CDEBUG_MASK, __VA_ARGS__)
++#else
++#define CT_DEBUG(...) no_printk(__VA_ARGS__)
++#endif
++#ifdef DDEBUG
++#define DR_DEBUG(...) MSK_DEBUG(DDEBUG_MASK, __VA_ARGS__)
++#else
++#define DR_DEBUG(...) no_printk(__VA_ARGS__)
++#endif
++
++extern uint qtaguid_debug_mask;
++
++/*---------------------------------------------------------------------------*/
++/*
++ * Tags:
++ *
++ * They represent what the data usage counters will be tracked against.
++ * By default a tag is just based on the UID.
++ * The UID is used as the base for policing, and can not be ignored.
++ * So a tag will always at least represent a UID (uid_tag).
++ *
++ * A tag can be augmented with an "accounting tag" which is associated
++ * with a UID.
++ * User space can set the acct_tag portion of the tag which is then used
++ * with sockets: all data belonging to that socket will be counted against the
++ * tag. The policing is then based on the tag's uid_tag portion,
++ * and stats are collected for the acct_tag portion separately.
++ *
++ * There could be
++ * a:  {acct_tag=1, uid_tag=10003}
++ * b:  {acct_tag=2, uid_tag=10003}
++ * c:  {acct_tag=3, uid_tag=10003}
++ * d:  {acct_tag=0, uid_tag=10003}
++ * a, b, and c represent tags associated with specific sockets.
++ * d is for the totals for that uid, including all untagged traffic.
++ * Typically d is used with policing/quota rules.
++ *
++ * We want tag_t big enough to distinguish uid_t and acct_tag.
++ * It might become a struct if needed.
++ * Nothing should be using it as an int.
++ */
++typedef uint64_t tag_t;  /* Only used via accessors */
++
++#define TAG_UID_MASK 0xFFFFFFFFULL
++#define TAG_ACCT_MASK (~0xFFFFFFFFULL)
++
++static inline int tag_compare(tag_t t1, tag_t t2)
++{
++	return t1 < t2 ? -1 : t1 == t2 ? 0 : 1;
++}
++
++static inline tag_t combine_atag_with_uid(tag_t acct_tag, uid_t uid)
++{
++	return acct_tag | uid;
++}
++static inline tag_t make_tag_from_uid(uid_t uid)
++{
++	return uid;
++}
++static inline uid_t get_uid_from_tag(tag_t tag)
++{
++	return tag & TAG_UID_MASK;
++}
++static inline tag_t get_utag_from_tag(tag_t tag)
++{
++	return tag & TAG_UID_MASK;
++}
++static inline tag_t get_atag_from_tag(tag_t tag)
++{
++	return tag & TAG_ACCT_MASK;
++}
++
++static inline bool valid_atag(tag_t tag)
++{
++	return !(tag & TAG_UID_MASK);
++}
++static inline tag_t make_atag_from_value(uint32_t value)
++{
++	return (uint64_t)value << 32;
++}
++/*---------------------------------------------------------------------------*/
++
++/*
++ * Maximum number of socket tags that a UID is allowed to have active.
++ * Multiple processes belonging to the same UID contribute towards this limit.
++ * Special UIDs that can impersonate a UID also contribute (e.g. download
++ * manager, ...)
++ */
++#define DEFAULT_MAX_SOCK_TAGS 1024
++
++/*
++ * For now we only track 2 sets of counters.
++ * The default set is 0.
++ * Userspace can activate another set for a given uid being tracked.
++ */
++#define IFS_MAX_COUNTER_SETS 2
++
++enum ifs_tx_rx {
++	IFS_TX,
++	IFS_RX,
++	IFS_MAX_DIRECTIONS
++};
++
++/* For now, TCP, UDP, the rest */
++enum ifs_proto {
++	IFS_TCP,
++	IFS_UDP,
++	IFS_PROTO_OTHER,
++	IFS_MAX_PROTOS
++};
++
++struct byte_packet_counters {
++	uint64_t bytes;
++	uint64_t packets;
++};
++
++struct data_counters {
++	struct byte_packet_counters bpc[IFS_MAX_COUNTER_SETS][IFS_MAX_DIRECTIONS][IFS_MAX_PROTOS];
++};
++
++static inline uint64_t dc_sum_bytes(struct data_counters *counters,
++				    int set,
++				    enum ifs_tx_rx direction)
++{
++	return counters->bpc[set][direction][IFS_TCP].bytes
++		+ counters->bpc[set][direction][IFS_UDP].bytes
++		+ counters->bpc[set][direction][IFS_PROTO_OTHER].bytes;
++}
++
++static inline uint64_t dc_sum_packets(struct data_counters *counters,
++				      int set,
++				      enum ifs_tx_rx direction)
++{
++	return counters->bpc[set][direction][IFS_TCP].packets
++		+ counters->bpc[set][direction][IFS_UDP].packets
++		+ counters->bpc[set][direction][IFS_PROTO_OTHER].packets;
++}
++
++
++/* Generic X based nodes used as a base for rb_tree ops */
++struct tag_node {
++	struct rb_node node;
++	tag_t tag;
++};
++
++struct tag_stat {
++	struct tag_node tn;
++	struct data_counters counters;
++	/*
++	 * If this tag is acct_tag based, we need to count against the
++	 * matching parent uid_tag.
++	 */
++	struct data_counters *parent_counters;
++};
++
++struct iface_stat {
++	struct list_head list;  /* in iface_stat_list */
++	char *ifname;
++	bool active;
++	/* net_dev is only valid for active iface_stat */
++	struct net_device *net_dev;
++
++	struct byte_packet_counters totals_via_dev[IFS_MAX_DIRECTIONS];
++	struct data_counters totals_via_skb;
++	/*
++	 * We keep the last_known, because some devices reset their counters
++	 * just before NETDEV_UP, while some will reset just before
++	 * NETDEV_REGISTER (which is more normal).
++	 * So now, if the device didn't do a NETDEV_UNREGISTER and we see
++	 * its current dev stats smaller that what was previously known, we
++	 * assume an UNREGISTER and just use the last_known.
++	 */
++	struct byte_packet_counters last_known[IFS_MAX_DIRECTIONS];
++	/* last_known is usable when last_known_valid is true */
++	bool last_known_valid;
++
++	struct proc_dir_entry *proc_ptr;
++
++	struct rb_root tag_stat_tree;
++	spinlock_t tag_stat_list_lock;
++};
++
++/* This is needed to create proc_dir_entries from atomic context. */
++struct iface_stat_work {
++	struct work_struct iface_work;
++	struct iface_stat *iface_entry;
++};
++
++/*
++ * Track tag that this socket is transferring data for, and not necessarily
++ * the uid that owns the socket.
++ * This is the tag against which tag_stat.counters will be billed.
++ * These structs need to be looked up by sock and pid.
++ */
++struct sock_tag {
++	struct rb_node sock_node;
++	struct sock *sk;  /* Only used as a number, never dereferenced */
++	/* The socket is needed for sockfd_put() */
++	struct socket *socket;
++	/* Used to associate with a given pid */
++	struct list_head list;   /* in proc_qtu_data.sock_tag_list */
++	pid_t pid;
++
++	tag_t tag;
++};
++
++struct qtaguid_event_counts {
++	/* Various successful events */
++	atomic64_t sockets_tagged;
++	atomic64_t sockets_untagged;
++	atomic64_t counter_set_changes;
++	atomic64_t delete_cmds;
++	atomic64_t iface_events;  /* Number of NETDEV_* events handled */
++
++	atomic64_t match_calls;   /* Number of times iptables called mt */
++	/* Number of times iptables called mt from pre or post routing hooks */
++	atomic64_t match_calls_prepost;
++	/*
++	 * match_found_sk_*: numbers related to the netfilter matching
++	 * function finding a sock for the sk_buff.
++	 * Total skbs processed is sum(match_found*).
++	 */
++	atomic64_t match_found_sk;   /* An sk was already in the sk_buff. */
++	/* The connection tracker had or didn't have the sk. */
++	atomic64_t match_found_sk_in_ct;
++	atomic64_t match_found_no_sk_in_ct;
++	/*
++	 * No sk could be found. No apparent owner. Could happen with
++	 * unsolicited traffic.
++	 */
++	atomic64_t match_no_sk;
++	/*
++	 * The file ptr in the sk_socket wasn't there.
++	 * This might happen for traffic while the socket is being closed.
++	 */
++	atomic64_t match_no_sk_file;
++};
++
++/* Track the set active_set for the given tag. */
++struct tag_counter_set {
++	struct tag_node tn;
++	int active_set;
++};
++
++/*----------------------------------------------*/
++/*
++ * The qtu uid data is used to track resources that are created directly or
++ * indirectly by processes (uid tracked).
++ * It is shared by the processes with the same uid.
++ * Some of the resource will be counted to prevent further rogue allocations,
++ * some will need freeing once the owner process (uid) exits.
++ */
++struct uid_tag_data {
++	struct rb_node node;
++	uid_t uid;
++
++	/*
++	 * For the uid, how many accounting tags have been set.
++	 */
++	int num_active_tags;
++	/* Track the number of proc_qtu_data that reference it */
++	int num_pqd;
++	struct rb_root tag_ref_tree;
++	/* No tag_node_tree_lock; use uid_tag_data_tree_lock */
++};
++
++struct tag_ref {
++	struct tag_node tn;
++
++	/*
++	 * This tracks the number of active sockets that have a tag on them
++	 * which matches this tag_ref.tn.tag.
++	 * A tag ref can live on after the sockets are untagged.
++	 * A tag ref can only be removed during a tag delete command.
++	 */
++	int num_sock_tags;
++};
++
++struct proc_qtu_data {
++	struct rb_node node;
++	pid_t pid;
++
++	struct uid_tag_data *parent_tag_data;
++
++	/* Tracks the sock_tags that need freeing upon this proc's death */
++	struct list_head sock_tag_list;
++	/* No spinlock_t sock_tag_list_lock; use the global one. */
++};
++
++/*----------------------------------------------*/
++#endif  /* ifndef __XT_QTAGUID_INTERNAL_H__ */
+diff --git a/net/netfilter/xt_qtaguid_print.c b/net/netfilter/xt_qtaguid_print.c
+new file mode 100644
+index 0000000..f6a00a3
+--- /dev/null
++++ b/net/netfilter/xt_qtaguid_print.c
+@@ -0,0 +1,566 @@
++/*
++ * Pretty printing Support for iptables xt_qtaguid module.
++ *
++ * (C) 2011 Google, 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.
++ */
++
++/*
++ * Most of the functions in this file just waste time if DEBUG is not defined.
++ * The matching xt_qtaguid_print.h will static inline empty funcs if the needed
++ * debug flags ore not defined.
++ * Those funcs that fail to allocate memory will panic as there is no need to
++ * hobble allong just pretending to do the requested work.
++ */
++
++#define DEBUG
++
++#include <linux/fs.h>
++#include <linux/gfp.h>
++#include <linux/net.h>
++#include <linux/rbtree.h>
++#include <linux/slab.h>
++#include <linux/spinlock_types.h>
++
++
++#include "xt_qtaguid_internal.h"
++#include "xt_qtaguid_print.h"
++
++#ifdef DDEBUG
++
++static void _bug_on_err_or_null(void *ptr)
++{
++	if (IS_ERR_OR_NULL(ptr)) {
++		pr_err("qtaguid: kmalloc failed\n");
++		BUG();
++	}
++}
++
++char *pp_tag_t(tag_t *tag)
++{
++	char *res;
++
++	if (!tag)
++		res = kasprintf(GFP_ATOMIC, "tag_t@null{}");
++	else
++		res = kasprintf(GFP_ATOMIC,
++				"tag_t@%p{tag=0x%llx, uid=%u}",
++				tag, *tag, get_uid_from_tag(*tag));
++	_bug_on_err_or_null(res);
++	return res;
++}
++
++char *pp_data_counters(struct data_counters *dc, bool showValues)
++{
++	char *res;
++
++	if (!dc)
++		res = kasprintf(GFP_ATOMIC, "data_counters@null{}");
++	else if (showValues)
++		res = kasprintf(
++			GFP_ATOMIC, "data_counters@%p{"
++			"set0{"
++			"rx{"
++			"tcp{b=%llu, p=%llu}, "
++			"udp{b=%llu, p=%llu},"
++			"other{b=%llu, p=%llu}}, "
++			"tx{"
++			"tcp{b=%llu, p=%llu}, "
++			"udp{b=%llu, p=%llu},"
++			"other{b=%llu, p=%llu}}}, "
++			"set1{"
++			"rx{"
++			"tcp{b=%llu, p=%llu}, "
++			"udp{b=%llu, p=%llu},"
++			"other{b=%llu, p=%llu}}, "
++			"tx{"
++			"tcp{b=%llu, p=%llu}, "
++			"udp{b=%llu, p=%llu},"
++			"other{b=%llu, p=%llu}}}}",
++			dc,
++			dc->bpc[0][IFS_RX][IFS_TCP].bytes,
++			dc->bpc[0][IFS_RX][IFS_TCP].packets,
++			dc->bpc[0][IFS_RX][IFS_UDP].bytes,
++			dc->bpc[0][IFS_RX][IFS_UDP].packets,
++			dc->bpc[0][IFS_RX][IFS_PROTO_OTHER].bytes,
++			dc->bpc[0][IFS_RX][IFS_PROTO_OTHER].packets,
++			dc->bpc[0][IFS_TX][IFS_TCP].bytes,
++			dc->bpc[0][IFS_TX][IFS_TCP].packets,
++			dc->bpc[0][IFS_TX][IFS_UDP].bytes,
++			dc->bpc[0][IFS_TX][IFS_UDP].packets,
++			dc->bpc[0][IFS_TX][IFS_PROTO_OTHER].bytes,
++			dc->bpc[0][IFS_TX][IFS_PROTO_OTHER].packets,
++			dc->bpc[1][IFS_RX][IFS_TCP].bytes,
++			dc->bpc[1][IFS_RX][IFS_TCP].packets,
++			dc->bpc[1][IFS_RX][IFS_UDP].bytes,
++			dc->bpc[1][IFS_RX][IFS_UDP].packets,
++			dc->bpc[1][IFS_RX][IFS_PROTO_OTHER].bytes,
++			dc->bpc[1][IFS_RX][IFS_PROTO_OTHER].packets,
++			dc->bpc[1][IFS_TX][IFS_TCP].bytes,
++			dc->bpc[1][IFS_TX][IFS_TCP].packets,
++			dc->bpc[1][IFS_TX][IFS_UDP].bytes,
++			dc->bpc[1][IFS_TX][IFS_UDP].packets,
++			dc->bpc[1][IFS_TX][IFS_PROTO_OTHER].bytes,
++			dc->bpc[1][IFS_TX][IFS_PROTO_OTHER].packets);
++	else
++		res = kasprintf(GFP_ATOMIC, "data_counters@%p{...}", dc);
++	_bug_on_err_or_null(res);
++	return res;
++}
++
++char *pp_tag_node(struct tag_node *tn)
++{
++	char *tag_str;
++	char *res;
++
++	if (!tn) {
++		res = kasprintf(GFP_ATOMIC, "tag_node@null{}");
++		_bug_on_err_or_null(res);
++		return res;
++	}
++	tag_str = pp_tag_t(&tn->tag);
++	res = kasprintf(GFP_ATOMIC,
++			"tag_node@%p{tag=%s}",
++			tn, tag_str);
++	_bug_on_err_or_null(res);
++	kfree(tag_str);
++	return res;
++}
++
++char *pp_tag_ref(struct tag_ref *tr)
++{
++	char *tn_str;
++	char *res;
++
++	if (!tr) {
++		res = kasprintf(GFP_ATOMIC, "tag_ref@null{}");
++		_bug_on_err_or_null(res);
++		return res;
++	}
++	tn_str = pp_tag_node(&tr->tn);
++	res = kasprintf(GFP_ATOMIC,
++			"tag_ref@%p{%s, num_sock_tags=%d}",
++			tr, tn_str, tr->num_sock_tags);
++	_bug_on_err_or_null(res);
++	kfree(tn_str);
++	return res;
++}
++
++char *pp_tag_stat(struct tag_stat *ts)
++{
++	char *tn_str;
++	char *counters_str;
++	char *parent_counters_str;
++	char *res;
++
++	if (!ts) {
++		res = kasprintf(GFP_ATOMIC, "tag_stat@null{}");
++		_bug_on_err_or_null(res);
++		return res;
++	}
++	tn_str = pp_tag_node(&ts->tn);
++	counters_str = pp_data_counters(&ts->counters, true);
++	parent_counters_str = pp_data_counters(ts->parent_counters, false);
++	res = kasprintf(GFP_ATOMIC,
++			"tag_stat@%p{%s, counters=%s, parent_counters=%s}",
++			ts, tn_str, counters_str, parent_counters_str);
++	_bug_on_err_or_null(res);
++	kfree(tn_str);
++	kfree(counters_str);
++	kfree(parent_counters_str);
++	return res;
++}
++
++char *pp_iface_stat(struct iface_stat *is)
++{
++	char *res;
++	if (!is) {
++		res = kasprintf(GFP_ATOMIC, "iface_stat@null{}");
++	} else {
++		struct data_counters *cnts = &is->totals_via_skb;
++		res = kasprintf(GFP_ATOMIC, "iface_stat@%p{"
++				"list=list_head{...}, "
++				"ifname=%s, "
++				"total_dev={rx={bytes=%llu, "
++				"packets=%llu}, "
++				"tx={bytes=%llu, "
++				"packets=%llu}}, "
++				"total_skb={rx={bytes=%llu, "
++				"packets=%llu}, "
++				"tx={bytes=%llu, "
++				"packets=%llu}}, "
++				"last_known_valid=%d, "
++				"last_known={rx={bytes=%llu, "
++				"packets=%llu}, "
++				"tx={bytes=%llu, "
++				"packets=%llu}}, "
++				"active=%d, "
++				"net_dev=%p, "
++				"proc_ptr=%p, "
++				"tag_stat_tree=rb_root{...}}",
++				is,
++				is->ifname,
++				is->totals_via_dev[IFS_RX].bytes,
++				is->totals_via_dev[IFS_RX].packets,
++				is->totals_via_dev[IFS_TX].bytes,
++				is->totals_via_dev[IFS_TX].packets,
++				dc_sum_bytes(cnts, 0, IFS_RX),
++				dc_sum_packets(cnts, 0, IFS_RX),
++				dc_sum_bytes(cnts, 0, IFS_TX),
++				dc_sum_packets(cnts, 0, IFS_TX),
++				is->last_known_valid,
++				is->last_known[IFS_RX].bytes,
++				is->last_known[IFS_RX].packets,
++				is->last_known[IFS_TX].bytes,
++				is->last_known[IFS_TX].packets,
++				is->active,
++				is->net_dev,
++				is->proc_ptr);
++	}
++	_bug_on_err_or_null(res);
++	return res;
++}
++
++char *pp_sock_tag(struct sock_tag *st)
++{
++	char *tag_str;
++	char *res;
++
++	if (!st) {
++		res = kasprintf(GFP_ATOMIC, "sock_tag@null{}");
++		_bug_on_err_or_null(res);
++		return res;
++	}
++	tag_str = pp_tag_t(&st->tag);
++	res = kasprintf(GFP_ATOMIC, "sock_tag@%p{"
++			"sock_node=rb_node{...}, "
++			"sk=%p socket=%p (f_count=%lu), list=list_head{...}, "
++			"pid=%u, tag=%s}",
++			st, st->sk, st->socket, atomic_long_read(
++				&st->socket->file->f_count),
++			st->pid, tag_str);
++	_bug_on_err_or_null(res);
++	kfree(tag_str);
++	return res;
++}
++
++char *pp_uid_tag_data(struct uid_tag_data *utd)
++{
++	char *res;
++
++	if (!utd)
++		res = kasprintf(GFP_ATOMIC, "uid_tag_data@null{}");
++	else
++		res = kasprintf(GFP_ATOMIC, "uid_tag_data@%p{"
++				"uid=%u, num_active_acct_tags=%d, "
++				"num_pqd=%d, "
++				"tag_node_tree=rb_root{...}, "
++				"proc_qtu_data_tree=rb_root{...}}",
++				utd, utd->uid,
++				utd->num_active_tags, utd->num_pqd);
++	_bug_on_err_or_null(res);
++	return res;
++}
++
++char *pp_proc_qtu_data(struct proc_qtu_data *pqd)
++{
++	char *parent_tag_data_str;
++	char *res;
++
++	if (!pqd) {
++		res = kasprintf(GFP_ATOMIC, "proc_qtu_data@null{}");
++		_bug_on_err_or_null(res);
++		return res;
++	}
++	parent_tag_data_str = pp_uid_tag_data(pqd->parent_tag_data);
++	res = kasprintf(GFP_ATOMIC, "proc_qtu_data@%p{"
++			"node=rb_node{...}, pid=%u, "
++			"parent_tag_data=%s, "
++			"sock_tag_list=list_head{...}}",
++			pqd, pqd->pid, parent_tag_data_str
++		);
++	_bug_on_err_or_null(res);
++	kfree(parent_tag_data_str);
++	return res;
++}
++
++/*------------------------------------------*/
++void prdebug_sock_tag_tree(int indent_level,
++			   struct rb_root *sock_tag_tree)
++{
++	struct rb_node *node;
++	struct sock_tag *sock_tag_entry;
++	char *str;
++
++	if (!unlikely(qtaguid_debug_mask & DDEBUG_MASK))
++		return;
++
++	if (RB_EMPTY_ROOT(sock_tag_tree)) {
++		str = "sock_tag_tree=rb_root{}";
++		pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
++		return;
++	}
++
++	str = "sock_tag_tree=rb_root{";
++	pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
++	indent_level++;
++	for (node = rb_first(sock_tag_tree);
++	     node;
++	     node = rb_next(node)) {
++		sock_tag_entry = rb_entry(node, struct sock_tag, sock_node);
++		str = pp_sock_tag(sock_tag_entry);
++		pr_debug("%*d: %s,\n", indent_level*2, indent_level, str);
++		kfree(str);
++	}
++	indent_level--;
++	str = "}";
++	pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
++}
++
++void prdebug_sock_tag_list(int indent_level,
++			   struct list_head *sock_tag_list)
++{
++	struct sock_tag *sock_tag_entry;
++	char *str;
++
++	if (!unlikely(qtaguid_debug_mask & DDEBUG_MASK))
++		return;
++
++	if (list_empty(sock_tag_list)) {
++		str = "sock_tag_list=list_head{}";
++		pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
++		return;
++	}
++
++	str = "sock_tag_list=list_head{";
++	pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
++	indent_level++;
++	list_for_each_entry(sock_tag_entry, sock_tag_list, list) {
++		str = pp_sock_tag(sock_tag_entry);
++		pr_debug("%*d: %s,\n", indent_level*2, indent_level, str);
++		kfree(str);
++	}
++	indent_level--;
++	str = "}";
++	pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
++}
++
++void prdebug_proc_qtu_data_tree(int indent_level,
++				struct rb_root *proc_qtu_data_tree)
++{
++	char *str;
++	struct rb_node *node;
++	struct proc_qtu_data *proc_qtu_data_entry;
++
++	if (!unlikely(qtaguid_debug_mask & DDEBUG_MASK))
++		return;
++
++	if (RB_EMPTY_ROOT(proc_qtu_data_tree)) {
++		str = "proc_qtu_data_tree=rb_root{}";
++		pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
++		return;
++	}
++
++	str = "proc_qtu_data_tree=rb_root{";
++	pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
++	indent_level++;
++	for (node = rb_first(proc_qtu_data_tree);
++	     node;
++	     node = rb_next(node)) {
++		proc_qtu_data_entry = rb_entry(node,
++					       struct proc_qtu_data,
++					       node);
++		str = pp_proc_qtu_data(proc_qtu_data_entry);
++		pr_debug("%*d: %s,\n", indent_level*2, indent_level,
++			 str);
++		kfree(str);
++		indent_level++;
++		prdebug_sock_tag_list(indent_level,
++				      &proc_qtu_data_entry->sock_tag_list);
++		indent_level--;
++
++	}
++	indent_level--;
++	str = "}";
++	pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
++}
++
++void prdebug_tag_ref_tree(int indent_level, struct rb_root *tag_ref_tree)
++{
++	char *str;
++	struct rb_node *node;
++	struct tag_ref *tag_ref_entry;
++
++	if (!unlikely(qtaguid_debug_mask & DDEBUG_MASK))
++		return;
++
++	if (RB_EMPTY_ROOT(tag_ref_tree)) {
++		str = "tag_ref_tree{}";
++		pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
++		return;
++	}
++
++	str = "tag_ref_tree{";
++	pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
++	indent_level++;
++	for (node = rb_first(tag_ref_tree);
++	     node;
++	     node = rb_next(node)) {
++		tag_ref_entry = rb_entry(node,
++					 struct tag_ref,
++					 tn.node);
++		str = pp_tag_ref(tag_ref_entry);
++		pr_debug("%*d: %s,\n", indent_level*2, indent_level,
++			 str);
++		kfree(str);
++	}
++	indent_level--;
++	str = "}";
++	pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
++}
++
++void prdebug_uid_tag_data_tree(int indent_level,
++			       struct rb_root *uid_tag_data_tree)
++{
++	char *str;
++	struct rb_node *node;
++	struct uid_tag_data *uid_tag_data_entry;
++
++	if (!unlikely(qtaguid_debug_mask & DDEBUG_MASK))
++		return;
++
++	if (RB_EMPTY_ROOT(uid_tag_data_tree)) {
++		str = "uid_tag_data_tree=rb_root{}";
++		pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
++		return;
++	}
++
++	str = "uid_tag_data_tree=rb_root{";
++	pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
++	indent_level++;
++	for (node = rb_first(uid_tag_data_tree);
++	     node;
++	     node = rb_next(node)) {
++		uid_tag_data_entry = rb_entry(node, struct uid_tag_data,
++					      node);
++		str = pp_uid_tag_data(uid_tag_data_entry);
++		pr_debug("%*d: %s,\n", indent_level*2, indent_level, str);
++		kfree(str);
++		if (!RB_EMPTY_ROOT(&uid_tag_data_entry->tag_ref_tree)) {
++			indent_level++;
++			prdebug_tag_ref_tree(indent_level,
++					     &uid_tag_data_entry->tag_ref_tree);
++			indent_level--;
++		}
++	}
++	indent_level--;
++	str = "}";
++	pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
++}
++
++void prdebug_tag_stat_tree(int indent_level,
++				  struct rb_root *tag_stat_tree)
++{
++	char *str;
++	struct rb_node *node;
++	struct tag_stat *ts_entry;
++
++	if (!unlikely(qtaguid_debug_mask & DDEBUG_MASK))
++		return;
++
++	if (RB_EMPTY_ROOT(tag_stat_tree)) {
++		str = "tag_stat_tree{}";
++		pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
++		return;
++	}
++
++	str = "tag_stat_tree{";
++	pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
++	indent_level++;
++	for (node = rb_first(tag_stat_tree);
++	     node;
++	     node = rb_next(node)) {
++		ts_entry = rb_entry(node, struct tag_stat, tn.node);
++		str = pp_tag_stat(ts_entry);
++		pr_debug("%*d: %s\n", indent_level*2, indent_level,
++			 str);
++		kfree(str);
++	}
++	indent_level--;
++	str = "}";
++	pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
++}
++
++void prdebug_iface_stat_list(int indent_level,
++			     struct list_head *iface_stat_list)
++{
++	char *str;
++	struct iface_stat *iface_entry;
++
++	if (!unlikely(qtaguid_debug_mask & DDEBUG_MASK))
++		return;
++
++	if (list_empty(iface_stat_list)) {
++		str = "iface_stat_list=list_head{}";
++		pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
++		return;
++	}
++
++	str = "iface_stat_list=list_head{";
++	pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
++	indent_level++;
++	list_for_each_entry(iface_entry, iface_stat_list, list) {
++		str = pp_iface_stat(iface_entry);
++		pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
++		kfree(str);
++
++		spin_lock_bh(&iface_entry->tag_stat_list_lock);
++		if (!RB_EMPTY_ROOT(&iface_entry->tag_stat_tree)) {
++			indent_level++;
++			prdebug_tag_stat_tree(indent_level,
++					      &iface_entry->tag_stat_tree);
++			indent_level--;
++		}
++		spin_unlock_bh(&iface_entry->tag_stat_list_lock);
++	}
++	indent_level--;
++	str = "}";
++	pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
++}
++
++#endif  /* ifdef DDEBUG */
++/*------------------------------------------*/
++static const char * const netdev_event_strings[] = {
++	"netdev_unknown",
++	"NETDEV_UP",
++	"NETDEV_DOWN",
++	"NETDEV_REBOOT",
++	"NETDEV_CHANGE",
++	"NETDEV_REGISTER",
++	"NETDEV_UNREGISTER",
++	"NETDEV_CHANGEMTU",
++	"NETDEV_CHANGEADDR",
++	"NETDEV_GOING_DOWN",
++	"NETDEV_CHANGENAME",
++	"NETDEV_FEAT_CHANGE",
++	"NETDEV_BONDING_FAILOVER",
++	"NETDEV_PRE_UP",
++	"NETDEV_PRE_TYPE_CHANGE",
++	"NETDEV_POST_TYPE_CHANGE",
++	"NETDEV_POST_INIT",
++	"NETDEV_UNREGISTER_BATCH",
++	"NETDEV_RELEASE",
++	"NETDEV_NOTIFY_PEERS",
++	"NETDEV_JOIN",
++};
++
++const char *netdev_evt_str(int netdev_event)
++{
++	if (netdev_event < 0
++	    || netdev_event >= ARRAY_SIZE(netdev_event_strings))
++		return "bad event num";
++	return netdev_event_strings[netdev_event];
++}
+diff --git a/net/netfilter/xt_qtaguid_print.h b/net/netfilter/xt_qtaguid_print.h
+new file mode 100644
+index 0000000..b63871a
+--- /dev/null
++++ b/net/netfilter/xt_qtaguid_print.h
+@@ -0,0 +1,120 @@
++/*
++ * Pretty printing Support for iptables xt_qtaguid module.
++ *
++ * (C) 2011 Google, 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.
++ */
++#ifndef __XT_QTAGUID_PRINT_H__
++#define __XT_QTAGUID_PRINT_H__
++
++#include "xt_qtaguid_internal.h"
++
++#ifdef DDEBUG
++
++char *pp_tag_t(tag_t *tag);
++char *pp_data_counters(struct data_counters *dc, bool showValues);
++char *pp_tag_node(struct tag_node *tn);
++char *pp_tag_ref(struct tag_ref *tr);
++char *pp_tag_stat(struct tag_stat *ts);
++char *pp_iface_stat(struct iface_stat *is);
++char *pp_sock_tag(struct sock_tag *st);
++char *pp_uid_tag_data(struct uid_tag_data *qtd);
++char *pp_proc_qtu_data(struct proc_qtu_data *pqd);
++
++/*------------------------------------------*/
++void prdebug_sock_tag_list(int indent_level,
++			   struct list_head *sock_tag_list);
++void prdebug_sock_tag_tree(int indent_level,
++			   struct rb_root *sock_tag_tree);
++void prdebug_proc_qtu_data_tree(int indent_level,
++				struct rb_root *proc_qtu_data_tree);
++void prdebug_tag_ref_tree(int indent_level, struct rb_root *tag_ref_tree);
++void prdebug_uid_tag_data_tree(int indent_level,
++			       struct rb_root *uid_tag_data_tree);
++void prdebug_tag_stat_tree(int indent_level,
++			   struct rb_root *tag_stat_tree);
++void prdebug_iface_stat_list(int indent_level,
++			     struct list_head *iface_stat_list);
++
++#else
++
++/*------------------------------------------*/
++static inline char *pp_tag_t(tag_t *tag)
++{
++	return NULL;
++}
++static inline char *pp_data_counters(struct data_counters *dc, bool showValues)
++{
++	return NULL;
++}
++static inline char *pp_tag_node(struct tag_node *tn)
++{
++	return NULL;
++}
++static inline char *pp_tag_ref(struct tag_ref *tr)
++{
++	return NULL;
++}
++static inline char *pp_tag_stat(struct tag_stat *ts)
++{
++	return NULL;
++}
++static inline char *pp_iface_stat(struct iface_stat *is)
++{
++	return NULL;
++}
++static inline char *pp_sock_tag(struct sock_tag *st)
++{
++	return NULL;
++}
++static inline char *pp_uid_tag_data(struct uid_tag_data *qtd)
++{
++	return NULL;
++}
++static inline char *pp_proc_qtu_data(struct proc_qtu_data *pqd)
++{
++	return NULL;
++}
++
++/*------------------------------------------*/
++static inline
++void prdebug_sock_tag_list(int indent_level,
++			   struct list_head *sock_tag_list)
++{
++}
++static inline
++void prdebug_sock_tag_tree(int indent_level,
++			   struct rb_root *sock_tag_tree)
++{
++}
++static inline
++void prdebug_proc_qtu_data_tree(int indent_level,
++				struct rb_root *proc_qtu_data_tree)
++{
++}
++static inline
++void prdebug_tag_ref_tree(int indent_level, struct rb_root *tag_ref_tree)
++{
++}
++static inline
++void prdebug_uid_tag_data_tree(int indent_level,
++			       struct rb_root *uid_tag_data_tree)
++{
++}
++static inline
++void prdebug_tag_stat_tree(int indent_level,
++			   struct rb_root *tag_stat_tree)
++{
++}
++static inline
++void prdebug_iface_stat_list(int indent_level,
++			     struct list_head *iface_stat_list)
++{
++}
++#endif
++/*------------------------------------------*/
++const char *netdev_evt_str(int netdev_event);
++#endif  /* ifndef __XT_QTAGUID_PRINT_H__ */
+diff --git a/net/netfilter/xt_quota2.c b/net/netfilter/xt_quota2.c
+new file mode 100644
+index 0000000..99592ae
+--- /dev/null
++++ b/net/netfilter/xt_quota2.c
+@@ -0,0 +1,382 @@
++/*
++ * xt_quota2 - enhanced xt_quota that can count upwards and in packets
++ * as a minimal accounting match.
++ * by Jan Engelhardt <jengelh@medozas.de>, 2008
++ *
++ * Originally based on xt_quota.c:
++ * 	netfilter module to enforce network quotas
++ * 	Sam Johnston <samj@samj.net>
++ *
++ *	This program is free software; you can redistribute it and/or modify
++ *	it under the terms of the GNU General Public License; either
++ *	version 2 of the License, as published by the Free Software Foundation.
++ */
++#include <linux/list.h>
++#include <linux/module.h>
++#include <linux/proc_fs.h>
++#include <linux/skbuff.h>
++#include <linux/spinlock.h>
++#include <asm/atomic.h>
++#include <net/netlink.h>
++
++#include <linux/netfilter/x_tables.h>
++#include <linux/netfilter/xt_quota2.h>
++#ifdef CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG
++#include <linux/netfilter_ipv4/ipt_ULOG.h>
++#endif
++
++/**
++ * @lock:	lock to protect quota writers from each other
++ */
++struct xt_quota_counter {
++	u_int64_t quota;
++	spinlock_t lock;
++	struct list_head list;
++	atomic_t ref;
++	char name[sizeof(((struct xt_quota_mtinfo2 *)NULL)->name)];
++	struct proc_dir_entry *procfs_entry;
++};
++
++#ifdef CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG
++/* Harald's favorite number +1 :D From ipt_ULOG.C */
++static int qlog_nl_event = 112;
++module_param_named(event_num, qlog_nl_event, uint, S_IRUGO | S_IWUSR);
++MODULE_PARM_DESC(event_num,
++		 "Event number for NETLINK_NFLOG message. 0 disables log."
++		 "111 is what ipt_ULOG uses.");
++static struct sock *nflognl;
++#endif
++
++static LIST_HEAD(counter_list);
++static DEFINE_SPINLOCK(counter_list_lock);
++
++static struct proc_dir_entry *proc_xt_quota;
++static unsigned int quota_list_perms = S_IRUGO | S_IWUSR;
++static kuid_t quota_list_uid = KUIDT_INIT(0);
++static kgid_t quota_list_gid = KGIDT_INIT(0);
++module_param_named(perms, quota_list_perms, uint, S_IRUGO | S_IWUSR);
++
++#ifdef CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG
++static void quota2_log(unsigned int hooknum,
++		       const struct sk_buff *skb,
++		       const struct net_device *in,
++		       const struct net_device *out,
++		       const char *prefix)
++{
++	ulog_packet_msg_t *pm;
++	struct sk_buff *log_skb;
++	size_t size;
++	struct nlmsghdr *nlh;
++
++	if (!qlog_nl_event)
++		return;
++
++	size = NLMSG_SPACE(sizeof(*pm));
++	size = max(size, (size_t)NLMSG_GOODSIZE);
++	log_skb = alloc_skb(size, GFP_ATOMIC);
++	if (!log_skb) {
++		pr_err("xt_quota2: cannot alloc skb for logging\n");
++		return;
++	}
++
++	nlh = nlmsg_put(log_skb, /*pid*/0, /*seq*/0, qlog_nl_event,
++			sizeof(*pm), 0);
++	if (!nlh) {
++		pr_err("xt_quota2: nlmsg_put failed\n");
++		kfree_skb(log_skb);
++		return;
++	}
++	pm = nlmsg_data(nlh);
++	if (skb->tstamp.tv64 == 0)
++		__net_timestamp((struct sk_buff *)skb);
++	pm->data_len = 0;
++	pm->hook = hooknum;
++	if (prefix != NULL)
++		strlcpy(pm->prefix, prefix, sizeof(pm->prefix));
++	else
++		*(pm->prefix) = '\0';
++	if (in)
++		strlcpy(pm->indev_name, in->name, sizeof(pm->indev_name));
++	else
++		pm->indev_name[0] = '\0';
++
++	if (out)
++		strlcpy(pm->outdev_name, out->name, sizeof(pm->outdev_name));
++	else
++		pm->outdev_name[0] = '\0';
++
++	NETLINK_CB(log_skb).dst_group = 1;
++	pr_debug("throwing 1 packets to netlink group 1\n");
++	netlink_broadcast(nflognl, log_skb, 0, 1, GFP_ATOMIC);
++}
++#else
++static void quota2_log(unsigned int hooknum,
++		       const struct sk_buff *skb,
++		       const struct net_device *in,
++		       const struct net_device *out,
++		       const char *prefix)
++{
++}
++#endif  /* if+else CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG */
++
++static ssize_t quota_proc_read(struct file *file, char __user *buf,
++			   size_t size, loff_t *ppos)
++{
++	struct xt_quota_counter *e = PDE_DATA(file_inode(file));
++	char tmp[24];
++	size_t tmp_size;
++
++	spin_lock_bh(&e->lock);
++	tmp_size = scnprintf(tmp, sizeof(tmp), "%llu\n", e->quota);
++	spin_unlock_bh(&e->lock);
++	return simple_read_from_buffer(buf, size, ppos, tmp, tmp_size);
++}
++
++static ssize_t quota_proc_write(struct file *file, const char __user *input,
++                            size_t size, loff_t *ppos)
++{
++	struct xt_quota_counter *e = PDE_DATA(file_inode(file));
++	char buf[sizeof("18446744073709551616")];
++
++	if (size > sizeof(buf))
++		size = sizeof(buf);
++	if (copy_from_user(buf, input, size) != 0)
++		return -EFAULT;
++	buf[sizeof(buf)-1] = '\0';
++
++	spin_lock_bh(&e->lock);
++	e->quota = simple_strtoull(buf, NULL, 0);
++	spin_unlock_bh(&e->lock);
++	return size;
++}
++
++static const struct file_operations q2_counter_fops = {
++	.read		= quota_proc_read,
++	.write		= quota_proc_write,
++	.llseek		= default_llseek,
++};
++
++static struct xt_quota_counter *
++q2_new_counter(const struct xt_quota_mtinfo2 *q, bool anon)
++{
++	struct xt_quota_counter *e;
++	unsigned int size;
++
++	/* Do not need all the procfs things for anonymous counters. */
++	size = anon ? offsetof(typeof(*e), list) : sizeof(*e);
++	e = kmalloc(size, GFP_KERNEL);
++	if (e == NULL)
++		return NULL;
++
++	e->quota = q->quota;
++	spin_lock_init(&e->lock);
++	if (!anon) {
++		INIT_LIST_HEAD(&e->list);
++		atomic_set(&e->ref, 1);
++		strlcpy(e->name, q->name, sizeof(e->name));
++	}
++	return e;
++}
++
++/**
++ * q2_get_counter - get ref to counter or create new
++ * @name:	name of counter
++ */
++static struct xt_quota_counter *
++q2_get_counter(const struct xt_quota_mtinfo2 *q)
++{
++	struct proc_dir_entry *p;
++	struct xt_quota_counter *e = NULL;
++	struct xt_quota_counter *new_e;
++
++	if (*q->name == '\0')
++		return q2_new_counter(q, true);
++
++	/* No need to hold a lock while getting a new counter */
++	new_e = q2_new_counter(q, false);
++	if (new_e == NULL)
++		goto out;
++
++	spin_lock_bh(&counter_list_lock);
++	list_for_each_entry(e, &counter_list, list)
++		if (strcmp(e->name, q->name) == 0) {
++			atomic_inc(&e->ref);
++			spin_unlock_bh(&counter_list_lock);
++			kfree(new_e);
++			pr_debug("xt_quota2: old counter name=%s", e->name);
++			return e;
++		}
++	e = new_e;
++	pr_debug("xt_quota2: new_counter name=%s", e->name);
++	list_add_tail(&e->list, &counter_list);
++	/* The entry having a refcount of 1 is not directly destructible.
++	 * This func has not yet returned the new entry, thus iptables
++	 * has not references for destroying this entry.
++	 * For another rule to try to destroy it, it would 1st need for this
++	 * func* to be re-invoked, acquire a new ref for the same named quota.
++	 * Nobody will access the e->procfs_entry either.
++	 * So release the lock. */
++	spin_unlock_bh(&counter_list_lock);
++
++	/* create_proc_entry() is not spin_lock happy */
++	p = e->procfs_entry = proc_create_data(e->name, quota_list_perms,
++	                      proc_xt_quota, &q2_counter_fops, e);
++
++	if (IS_ERR_OR_NULL(p)) {
++		spin_lock_bh(&counter_list_lock);
++		list_del(&e->list);
++		spin_unlock_bh(&counter_list_lock);
++		goto out;
++	}
++	proc_set_user(p, quota_list_uid, quota_list_gid);
++	return e;
++
++ out:
++	kfree(e);
++	return NULL;
++}
++
++static int quota_mt2_check(const struct xt_mtchk_param *par)
++{
++	struct xt_quota_mtinfo2 *q = par->matchinfo;
++
++	pr_debug("xt_quota2: check() flags=0x%04x", q->flags);
++
++	if (q->flags & ~XT_QUOTA_MASK)
++		return -EINVAL;
++
++	q->name[sizeof(q->name)-1] = '\0';
++	if (*q->name == '.' || strchr(q->name, '/') != NULL) {
++		printk(KERN_ERR "xt_quota.3: illegal name\n");
++		return -EINVAL;
++	}
++
++	q->master = q2_get_counter(q);
++	if (q->master == NULL) {
++		printk(KERN_ERR "xt_quota.3: memory alloc failure\n");
++		return -ENOMEM;
++	}
++
++	return 0;
++}
++
++static void quota_mt2_destroy(const struct xt_mtdtor_param *par)
++{
++	struct xt_quota_mtinfo2 *q = par->matchinfo;
++	struct xt_quota_counter *e = q->master;
++
++	if (*q->name == '\0') {
++		kfree(e);
++		return;
++	}
++
++	spin_lock_bh(&counter_list_lock);
++	if (!atomic_dec_and_test(&e->ref)) {
++		spin_unlock_bh(&counter_list_lock);
++		return;
++	}
++
++	list_del(&e->list);
++	remove_proc_entry(e->name, proc_xt_quota);
++	spin_unlock_bh(&counter_list_lock);
++	kfree(e);
++}
++
++static bool
++quota_mt2(const struct sk_buff *skb, struct xt_action_param *par)
++{
++	struct xt_quota_mtinfo2 *q = (void *)par->matchinfo;
++	struct xt_quota_counter *e = q->master;
++	bool ret = q->flags & XT_QUOTA_INVERT;
++
++	spin_lock_bh(&e->lock);
++	if (q->flags & XT_QUOTA_GROW) {
++		/*
++		 * While no_change is pointless in "grow" mode, we will
++		 * implement it here simply to have a consistent behavior.
++		 */
++		if (!(q->flags & XT_QUOTA_NO_CHANGE)) {
++			e->quota += (q->flags & XT_QUOTA_PACKET) ? 1 : skb->len;
++		}
++		ret = true;
++	} else {
++		if (e->quota >= skb->len) {
++			if (!(q->flags & XT_QUOTA_NO_CHANGE))
++				e->quota -= (q->flags & XT_QUOTA_PACKET) ? 1 : skb->len;
++			ret = !ret;
++		} else {
++			/* We are transitioning, log that fact. */
++			if (e->quota) {
++				quota2_log(par->hooknum,
++					   skb,
++					   par->in,
++					   par->out,
++					   q->name);
++			}
++			/* we do not allow even small packets from now on */
++			e->quota = 0;
++		}
++	}
++	spin_unlock_bh(&e->lock);
++	return ret;
++}
++
++static struct xt_match quota_mt2_reg[] __read_mostly = {
++	{
++		.name       = "quota2",
++		.revision   = 3,
++		.family     = NFPROTO_IPV4,
++		.checkentry = quota_mt2_check,
++		.match      = quota_mt2,
++		.destroy    = quota_mt2_destroy,
++		.matchsize  = sizeof(struct xt_quota_mtinfo2),
++		.me         = THIS_MODULE,
++	},
++	{
++		.name       = "quota2",
++		.revision   = 3,
++		.family     = NFPROTO_IPV6,
++		.checkentry = quota_mt2_check,
++		.match      = quota_mt2,
++		.destroy    = quota_mt2_destroy,
++		.matchsize  = sizeof(struct xt_quota_mtinfo2),
++		.me         = THIS_MODULE,
++	},
++};
++
++static int __init quota_mt2_init(void)
++{
++	int ret;
++	pr_debug("xt_quota2: init()");
++
++#ifdef CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG
++	nflognl = netlink_kernel_create(&init_net, NETLINK_NFLOG, NULL);
++	if (!nflognl)
++		return -ENOMEM;
++#endif
++
++	proc_xt_quota = proc_mkdir("xt_quota", init_net.proc_net);
++	if (proc_xt_quota == NULL)
++		return -EACCES;
++
++	ret = xt_register_matches(quota_mt2_reg, ARRAY_SIZE(quota_mt2_reg));
++	if (ret < 0)
++		remove_proc_entry("xt_quota", init_net.proc_net);
++	pr_debug("xt_quota2: init() %d", ret);
++	return ret;
++}
++
++static void __exit quota_mt2_exit(void)
++{
++	xt_unregister_matches(quota_mt2_reg, ARRAY_SIZE(quota_mt2_reg));
++	remove_proc_entry("xt_quota", init_net.proc_net);
++}
++
++module_init(quota_mt2_init);
++module_exit(quota_mt2_exit);
++MODULE_DESCRIPTION("Xtables: countdown quota match; up counter");
++MODULE_AUTHOR("Sam Johnston <samj@samj.net>");
++MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("ipt_quota2");
++MODULE_ALIAS("ip6t_quota2");
+diff --git a/net/netfilter/xt_rateest.c b/net/netfilter/xt_rateest.c
+index 7720b03..604df6f 100644
+--- a/net/netfilter/xt_rateest.c
++++ b/net/netfilter/xt_rateest.c
+@@ -8,150 +8,187 @@
+ #include <linux/module.h>
+ #include <linux/skbuff.h>
+ #include <linux/gen_stats.h>
++#include <linux/jhash.h>
++#include <linux/rtnetlink.h>
++#include <linux/random.h>
++#include <linux/slab.h>
++#include <net/gen_stats.h>
++#include <net/netlink.h>
+ 
+ #include <linux/netfilter/x_tables.h>
+-#include <linux/netfilter/xt_rateest.h>
++#include <linux/netfilter/xt_RATEEST.h>
+ #include <net/netfilter/xt_rateest.h>
+ 
++static DEFINE_MUTEX(xt_rateest_mutex);
+ 
+-static bool
+-xt_rateest_mt(const struct sk_buff *skb, struct xt_action_param *par)
++#define RATEEST_HSIZE	16
++static struct hlist_head rateest_hash[RATEEST_HSIZE] __read_mostly;
++static unsigned int jhash_rnd __read_mostly;
++static bool rnd_inited __read_mostly;
++
++static unsigned int xt_rateest_hash(const char *name)
+ {
+-	const struct xt_rateest_match_info *info = par->matchinfo;
+-	struct gnet_stats_rate_est64 *r;
+-	u_int32_t bps1, bps2, pps1, pps2;
+-	bool ret = true;
+-
+-	spin_lock_bh(&info->est1->lock);
+-	r = &info->est1->rstats;
+-	if (info->flags & XT_RATEEST_MATCH_DELTA) {
+-		bps1 = info->bps1 >= r->bps ? info->bps1 - r->bps : 0;
+-		pps1 = info->pps1 >= r->pps ? info->pps1 - r->pps : 0;
+-	} else {
+-		bps1 = r->bps;
+-		pps1 = r->pps;
+-	}
+-	spin_unlock_bh(&info->est1->lock);
+-
+-	if (info->flags & XT_RATEEST_MATCH_ABS) {
+-		bps2 = info->bps2;
+-		pps2 = info->pps2;
+-	} else {
+-		spin_lock_bh(&info->est2->lock);
+-		r = &info->est2->rstats;
+-		if (info->flags & XT_RATEEST_MATCH_DELTA) {
+-			bps2 = info->bps2 >= r->bps ? info->bps2 - r->bps : 0;
+-			pps2 = info->pps2 >= r->pps ? info->pps2 - r->pps : 0;
+-		} else {
+-			bps2 = r->bps;
+-			pps2 = r->pps;
++	return jhash(name, FIELD_SIZEOF(struct xt_rateest, name), jhash_rnd) &
++	       (RATEEST_HSIZE - 1);
++}
++
++static void xt_rateest_hash_insert(struct xt_rateest *est)
++{
++	unsigned int h;
++
++	h = xt_rateest_hash(est->name);
++	hlist_add_head(&est->list, &rateest_hash[h]);
++}
++
++struct xt_rateest *xt_rateest_lookup(const char *name)
++{
++	struct xt_rateest *est;
++	unsigned int h;
++
++	h = xt_rateest_hash(name);
++	mutex_lock(&xt_rateest_mutex);
++	hlist_for_each_entry(est, &rateest_hash[h], list) {
++		if (strcmp(est->name, name) == 0) {
++			est->refcnt++;
++			mutex_unlock(&xt_rateest_mutex);
++			return est;
+ 		}
+-		spin_unlock_bh(&info->est2->lock);
+ 	}
++	mutex_unlock(&xt_rateest_mutex);
++	return NULL;
++}
++EXPORT_SYMBOL_GPL(xt_rateest_lookup);
+ 
+-	switch (info->mode) {
+-	case XT_RATEEST_MATCH_LT:
+-		if (info->flags & XT_RATEEST_MATCH_BPS)
+-			ret &= bps1 < bps2;
+-		if (info->flags & XT_RATEEST_MATCH_PPS)
+-			ret &= pps1 < pps2;
+-		break;
+-	case XT_RATEEST_MATCH_GT:
+-		if (info->flags & XT_RATEEST_MATCH_BPS)
+-			ret &= bps1 > bps2;
+-		if (info->flags & XT_RATEEST_MATCH_PPS)
+-			ret &= pps1 > pps2;
+-		break;
+-	case XT_RATEEST_MATCH_EQ:
+-		if (info->flags & XT_RATEEST_MATCH_BPS)
+-			ret &= bps1 == bps2;
+-		if (info->flags & XT_RATEEST_MATCH_PPS)
+-			ret &= pps1 == pps2;
+-		break;
++void xt_rateest_put(struct xt_rateest *est)
++{
++	mutex_lock(&xt_rateest_mutex);
++	if (--est->refcnt == 0) {
++		hlist_del(&est->list);
++		gen_kill_estimator(&est->bstats, &est->rstats);
++		/*
++		 * gen_estimator est_timer() might access est->lock or bstats,
++		 * wait a RCU grace period before freeing 'est'
++		 */
++		kfree_rcu(est, rcu);
+ 	}
+-
+-	ret ^= info->flags & XT_RATEEST_MATCH_INVERT ? true : false;
+-	return ret;
++	mutex_unlock(&xt_rateest_mutex);
+ }
++EXPORT_SYMBOL_GPL(xt_rateest_put);
+ 
+-static int xt_rateest_mt_checkentry(const struct xt_mtchk_param *par)
++static unsigned int
++xt_rateest_tg(struct sk_buff *skb, const struct xt_action_param *par)
+ {
+-	struct xt_rateest_match_info *info = par->matchinfo;
+-	struct xt_rateest *est1, *est2;
+-	int ret = -EINVAL;
++	const struct xt_rateest_target_info *info = par->targinfo;
++	struct gnet_stats_basic_packed *stats = &info->est->bstats;
+ 
+-	if (hweight32(info->flags & (XT_RATEEST_MATCH_ABS |
+-				     XT_RATEEST_MATCH_REL)) != 1)
+-		goto err1;
++	spin_lock_bh(&info->est->lock);
++	stats->bytes += skb->len;
++	stats->packets++;
++	spin_unlock_bh(&info->est->lock);
+ 
+-	if (!(info->flags & (XT_RATEEST_MATCH_BPS | XT_RATEEST_MATCH_PPS)))
+-		goto err1;
++	return XT_CONTINUE;
++}
+ 
+-	switch (info->mode) {
+-	case XT_RATEEST_MATCH_EQ:
+-	case XT_RATEEST_MATCH_LT:
+-	case XT_RATEEST_MATCH_GT:
+-		break;
+-	default:
+-		goto err1;
++static int xt_rateest_tg_checkentry(const struct xt_tgchk_param *par)
++{
++	struct xt_rateest_target_info *info = par->targinfo;
++	struct xt_rateest *est;
++	struct {
++		struct nlattr		opt;
++		struct gnet_estimator	est;
++	} cfg;
++	int ret;
++
++	if (unlikely(!rnd_inited)) {
++		get_random_bytes(&jhash_rnd, sizeof(jhash_rnd));
++		rnd_inited = true;
++	}
++
++	est = xt_rateest_lookup(info->name);
++	if (est) {
++		/*
++		 * If estimator parameters are specified, they must match the
++		 * existing estimator.
++		 */
++		if ((!info->interval && !info->ewma_log) ||
++		    (info->interval != est->params.interval ||
++		     info->ewma_log != est->params.ewma_log)) {
++			xt_rateest_put(est);
++			return -EINVAL;
++		}
++		info->est = est;
++		return 0;
+ 	}
+ 
+-	ret  = -ENOENT;
+-	est1 = xt_rateest_lookup(info->name1);
+-	if (!est1)
++	ret = -ENOMEM;
++	est = kzalloc(sizeof(*est), GFP_KERNEL);
++	if (!est)
+ 		goto err1;
+ 
+-	est2 = NULL;
+-	if (info->flags & XT_RATEEST_MATCH_REL) {
+-		est2 = xt_rateest_lookup(info->name2);
+-		if (!est2)
+-			goto err2;
+-	}
++	strlcpy(est->name, info->name, sizeof(est->name));
++	spin_lock_init(&est->lock);
++	est->refcnt		= 1;
++	est->params.interval	= info->interval;
++	est->params.ewma_log	= info->ewma_log;
++
++	cfg.opt.nla_len		= nla_attr_size(sizeof(cfg.est));
++	cfg.opt.nla_type	= TCA_STATS_RATE_EST;
++	cfg.est.interval	= info->interval;
++	cfg.est.ewma_log	= info->ewma_log;
++
++	ret = gen_new_estimator(&est->bstats, NULL, &est->rstats,
++				&est->lock, &cfg.opt);
++	if (ret < 0)
++		goto err2;
+ 
+-	info->est1 = est1;
+-	info->est2 = est2;
++	info->est = est;
++	xt_rateest_hash_insert(est);
+ 	return 0;
+ 
+ err2:
+-	xt_rateest_put(est1);
++	kfree(est);
+ err1:
+ 	return ret;
+ }
+ 
+-static void xt_rateest_mt_destroy(const struct xt_mtdtor_param *par)
++static void xt_rateest_tg_destroy(const struct xt_tgdtor_param *par)
+ {
+-	struct xt_rateest_match_info *info = par->matchinfo;
++	struct xt_rateest_target_info *info = par->targinfo;
+ 
+-	xt_rateest_put(info->est1);
+-	if (info->est2)
+-		xt_rateest_put(info->est2);
++	xt_rateest_put(info->est);
+ }
+ 
+-static struct xt_match xt_rateest_mt_reg __read_mostly = {
+-	.name       = "rateest",
++static struct xt_target xt_rateest_tg_reg __read_mostly = {
++	.name       = "RATEEST",
+ 	.revision   = 0,
+ 	.family     = NFPROTO_UNSPEC,
+-	.match      = xt_rateest_mt,
+-	.checkentry = xt_rateest_mt_checkentry,
+-	.destroy    = xt_rateest_mt_destroy,
+-	.matchsize  = sizeof(struct xt_rateest_match_info),
++	.target     = xt_rateest_tg,
++	.checkentry = xt_rateest_tg_checkentry,
++	.destroy    = xt_rateest_tg_destroy,
++	.targetsize = sizeof(struct xt_rateest_target_info),
+ 	.me         = THIS_MODULE,
+ };
+ 
+-static int __init xt_rateest_mt_init(void)
++static int __init xt_rateest_tg_init(void)
+ {
+-	return xt_register_match(&xt_rateest_mt_reg);
++	unsigned int i;
++
++	for (i = 0; i < ARRAY_SIZE(rateest_hash); i++)
++		INIT_HLIST_HEAD(&rateest_hash[i]);
++
++	return xt_register_target(&xt_rateest_tg_reg);
+ }
+ 
+-static void __exit xt_rateest_mt_fini(void)
++static void __exit xt_rateest_tg_fini(void)
+ {
+-	xt_unregister_match(&xt_rateest_mt_reg);
++	xt_unregister_target(&xt_rateest_tg_reg);
+ }
+ 
++
+ MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
+ MODULE_LICENSE("GPL");
+-MODULE_DESCRIPTION("xtables rate estimator match");
+-MODULE_ALIAS("ipt_rateest");
+-MODULE_ALIAS("ip6t_rateest");
+-module_init(xt_rateest_mt_init);
+-module_exit(xt_rateest_mt_fini);
++MODULE_DESCRIPTION("Xtables: packet rate estimator");
++MODULE_ALIAS("ipt_RATEEST");
++MODULE_ALIAS("ip6t_RATEEST");
++module_init(xt_rateest_tg_init);
++module_exit(xt_rateest_tg_fini);
+diff --git a/net/netfilter/xt_socket.c b/net/netfilter/xt_socket.c
+index 1ba6793..a3b25b2 100644
+--- a/net/netfilter/xt_socket.c
++++ b/net/netfilter/xt_socket.c
+@@ -129,9 +129,10 @@ xt_socket_get_sock_v4(struct net *net, const u8 protocol,
+ 	return NULL;
+ }
+ 
+-static bool
+-socket_match(const struct sk_buff *skb, struct xt_action_param *par,
+-	     const struct xt_socket_mtinfo1 *info)
++
++
++struct sock*
++xt_socket_get4_sk(const struct sk_buff *skb, struct xt_action_param *par)
+ {
+ 	const struct iphdr *iph = ip_hdr(skb);
+ 	struct udphdr _hdr, *hp = NULL;
+@@ -148,7 +149,7 @@ socket_match(const struct sk_buff *skb, struct xt_action_param *par,
+ 		hp = skb_header_pointer(skb, ip_hdrlen(skb),
+ 					sizeof(_hdr), &_hdr);
+ 		if (hp == NULL)
+-			return false;
++			return NULL;
+ 
+ 		protocol = iph->protocol;
+ 		saddr = iph->saddr;
+@@ -159,9 +160,9 @@ socket_match(const struct sk_buff *skb, struct xt_action_param *par,
+ 	} else if (iph->protocol == IPPROTO_ICMP) {
+ 		if (extract_icmp4_fields(skb, &protocol, &saddr, &daddr,
+ 					&sport, &dport))
+-			return false;
++			return NULL;
+ 	} else {
+-		return false;
++		return NULL;
+ 	}
+ 
+ #ifdef XT_SOCKET_HAVE_CONNTRACK
+@@ -183,10 +184,30 @@ socket_match(const struct sk_buff *skb, struct xt_action_param *par,
+ 	}
+ #endif
+ 
+-	if (!sk)
++	if (sk)
++		atomic_inc(&sk->sk_refcnt);
++	else
+ 		sk = xt_socket_get_sock_v4(dev_net(skb->dev), protocol,
+ 					   saddr, daddr, sport, dport,
+ 					   par->in);
++
++	pr_debug("proto %hhu %pI4:%hu -> %pI4:%hu (orig %pI4:%hu) sock %p\n",
++		 protocol, &saddr, ntohs(sport),
++		 &daddr, ntohs(dport),
++		 &iph->daddr, hp ? ntohs(hp->dest) : 0, sk);
++
++	return sk;
++}
++EXPORT_SYMBOL(xt_socket_get4_sk);
++
++static bool
++socket_match(const struct sk_buff *skb, struct xt_action_param *par,
++	     const struct xt_socket_mtinfo1 *info)
++{
++	struct sock *sk;
++
++	sk = xt_socket_get4_sk(skb, par);
++
+ 	if (sk) {
+ 		bool wildcard;
+ 		bool transparent = true;
+@@ -206,18 +227,12 @@ socket_match(const struct sk_buff *skb, struct xt_action_param *par,
+ 				       (sk->sk_state == TCP_TIME_WAIT &&
+ 					inet_twsk(sk)->tw_transparent));
+ 
+-		if (sk != skb->sk)
+-			sock_gen_put(sk);
++		sock_gen_put(sk);
+ 
+ 		if (wildcard || !transparent)
+ 			sk = NULL;
+ 	}
+ 
+-	pr_debug("proto %hhu %pI4:%hu -> %pI4:%hu (orig %pI4:%hu) sock %p\n",
+-		 protocol, &saddr, ntohs(sport),
+-		 &daddr, ntohs(dport),
+-		 &iph->daddr, hp ? ntohs(hp->dest) : 0, sk);
+-
+ 	return (sk != NULL);
+ }
+ 
+@@ -312,8 +327,8 @@ xt_socket_get_sock_v6(struct net *net, const u8 protocol,
+ 	return NULL;
+ }
+ 
+-static bool
+-socket_mt6_v1_v2(const struct sk_buff *skb, struct xt_action_param *par)
++struct sock*
++xt_socket_get6_sk(const struct sk_buff *skb, struct xt_action_param *par)
+ {
+ 	struct ipv6hdr *iph = ipv6_hdr(skb);
+ 	struct udphdr _hdr, *hp = NULL;
+@@ -321,7 +336,6 @@ socket_mt6_v1_v2(const struct sk_buff *skb, struct xt_action_param *par)
+ 	struct in6_addr *daddr = NULL, *saddr = NULL;
+ 	__be16 uninitialized_var(dport), uninitialized_var(sport);
+ 	int thoff = 0, uninitialized_var(tproto);
+-	const struct xt_socket_mtinfo1 *info = (struct xt_socket_mtinfo1 *) par->matchinfo;
+ 
+ 	tproto = ipv6_find_hdr(skb, &thoff, -1, NULL, NULL);
+ 	if (tproto < 0) {
+@@ -333,7 +347,7 @@ socket_mt6_v1_v2(const struct sk_buff *skb, struct xt_action_param *par)
+ 		hp = skb_header_pointer(skb, thoff,
+ 					sizeof(_hdr), &_hdr);
+ 		if (hp == NULL)
+-			return false;
++			return NULL;
+ 
+ 		saddr = &iph->saddr;
+ 		sport = hp->source;
+@@ -343,15 +357,37 @@ socket_mt6_v1_v2(const struct sk_buff *skb, struct xt_action_param *par)
+ 	} else if (tproto == IPPROTO_ICMPV6) {
+ 		if (extract_icmp6_fields(skb, thoff, &tproto, &saddr, &daddr,
+ 					 &sport, &dport))
+-			return false;
++			return NULL;
+ 	} else {
+-		return false;
++		return NULL;
+ 	}
+ 
+-	if (!sk)
++	if (sk)
++		atomic_inc(&sk->sk_refcnt);
++	else
+ 		sk = xt_socket_get_sock_v6(dev_net(skb->dev), tproto,
+ 					   saddr, daddr, sport, dport,
+ 					   par->in);
++
++	pr_debug("proto %hhd %pI6:%hu -> %pI6:%hu "
++		 "(orig %pI6:%hu) sock %p\n",
++		 tproto, saddr, ntohs(sport),
++		 daddr, ntohs(dport),
++		 &iph->daddr, hp ? ntohs(hp->dest) : 0, sk);
++	return sk;
++}
++EXPORT_SYMBOL(xt_socket_get6_sk);
++
++static bool
++socket_mt6_v1_v2(const struct sk_buff *skb, struct xt_action_param *par)
++{
++	struct sock *sk;
++	const struct xt_socket_mtinfo1 *info;
++
++	info = (struct xt_socket_mtinfo1 *) par->matchinfo;
++
++	sk = xt_socket_get6_sk(skb, par);
++
+ 	if (sk) {
+ 		bool wildcard;
+ 		bool transparent = true;
+@@ -378,12 +414,6 @@ socket_mt6_v1_v2(const struct sk_buff *skb, struct xt_action_param *par)
+ 			sk = NULL;
+ 	}
+ 
+-	pr_debug("proto %hhd %pI6:%hu -> %pI6:%hu "
+-		 "(orig %pI6:%hu) sock %p\n",
+-		 tproto, saddr, ntohs(sport),
+-		 daddr, ntohs(dport),
+-		 &iph->daddr, hp ? ntohs(hp->dest) : 0, sk);
+-
+ 	return (sk != NULL);
+ }
+ #endif
+diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
+index c82b2e3..84d9476 100644
+--- a/net/netlink/af_netlink.c
++++ b/net/netlink/af_netlink.c
+@@ -2599,6 +2599,7 @@ static int netlink_dump(struct sock *sk)
+ 	struct netlink_callback *cb;
+ 	struct sk_buff *skb = NULL;
+ 	struct nlmsghdr *nlh;
++	struct module *module;
+ 	int len, err = -ENOBUFS;
+ 	int alloc_size;
+ 
+@@ -2668,9 +2669,11 @@ static int netlink_dump(struct sock *sk)
+ 		cb->done(cb);
+ 
+ 	nlk->cb_running = false;
++	module = cb->module;
++	skb = cb->skb;
+ 	mutex_unlock(nlk->cb_mutex);
+-	module_put(cb->module);
+-	consume_skb(cb->skb);
++	module_put(module);
++	consume_skb(skb);
+ 	return 0;
+ 
+ errout_skb:
+diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
+index 5dcfe05..9ef5ba6 100644
+--- a/net/packet/af_packet.c
++++ b/net/packet/af_packet.c
+@@ -3261,19 +3261,25 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
+ 
+ 		if (optlen != sizeof(val))
+ 			return -EINVAL;
+-		if (po->rx_ring.pg_vec || po->tx_ring.pg_vec)
+-			return -EBUSY;
+ 		if (copy_from_user(&val, optval, sizeof(val)))
+ 			return -EFAULT;
+ 		switch (val) {
+ 		case TPACKET_V1:
+ 		case TPACKET_V2:
+ 		case TPACKET_V3:
+-			po->tp_version = val;
+-			return 0;
++			break;
+ 		default:
+ 			return -EINVAL;
+ 		}
++		lock_sock(sk);
++		if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) {
++			ret = -EBUSY;
++		} else {
++			po->tp_version = val;
++			ret = 0;
++		}
++		release_sock(sk);
++		return ret;
+ 	}
+ 	case PACKET_RESERVE:
+ 	{
+@@ -3281,12 +3287,19 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
+ 
+ 		if (optlen != sizeof(val))
+ 			return -EINVAL;
+-		if (po->rx_ring.pg_vec || po->tx_ring.pg_vec)
+-			return -EBUSY;
+ 		if (copy_from_user(&val, optval, sizeof(val)))
+ 			return -EFAULT;
+-		po->tp_reserve = val;
+-		return 0;
++		if (val > INT_MAX)
++			return -EINVAL;
++		lock_sock(sk);
++		if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) {
++			ret = -EBUSY;
++		} else {
++			po->tp_reserve = val;
++			ret = 0;
++		}
++		release_sock(sk);
++		return ret;
+ 	}
+ 	case PACKET_LOSS:
+ 	{
+@@ -3736,6 +3749,7 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
+ 	/* Added to avoid minimal code churn */
+ 	struct tpacket_req *req = &req_u->req;
+ 
++	lock_sock(sk);
+ 	/* Opening a Tx-ring is NOT supported in TPACKET_V3 */
+ 	if (!closing && tx_ring && (po->tp_version > TPACKET_V2)) {
+ 		WARN(1, "Tx-ring is not supported.\n");
+@@ -3777,8 +3791,8 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
+ 		if (unlikely(req->tp_block_size & (PAGE_SIZE - 1)))
+ 			goto out;
+ 		if (po->tp_version >= TPACKET_V3 &&
+-		    (int)(req->tp_block_size -
+-			  BLK_PLUS_PRIV(req_u->req3.tp_sizeof_priv)) <= 0)
++		    req->tp_block_size <=
++			  BLK_PLUS_PRIV((u64)req_u->req3.tp_sizeof_priv))
+ 			goto out;
+ 		if (unlikely(req->tp_frame_size < po->tp_hdrlen +
+ 					po->tp_reserve))
+@@ -3817,8 +3831,6 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
+ 			goto out;
+ 	}
+ 
+-	lock_sock(sk);
+-
+ 	/* Detach socket from network */
+ 	spin_lock(&po->bind_lock);
+ 	was_running = po->running;
+@@ -3866,11 +3878,11 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
+ 		if (!tx_ring)
+ 			prb_shutdown_retire_blk_timer(po, tx_ring, rb_queue);
+ 	}
+-	release_sock(sk);
+ 
+ 	if (pg_vec)
+ 		free_pg_vec(pg_vec, order, req->tp_block_nr);
+ out:
++	release_sock(sk);
+ 	return err;
+ }
+ 
+diff --git a/net/rfkill/Kconfig b/net/rfkill/Kconfig
+index 4c10e7e..77aa1df 100644
+--- a/net/rfkill/Kconfig
++++ b/net/rfkill/Kconfig
+@@ -10,6 +10,11 @@ menuconfig RFKILL
+ 	  To compile this driver as a module, choose M here: the
+ 	  module will be called rfkill.
+ 
++config RFKILL_PM
++	bool "Power off on suspend"
++	depends on RFKILL && PM
++	default y
++
+ # LED trigger support
+ config RFKILL_LEDS
+ 	bool
+diff --git a/net/rfkill/core.c b/net/rfkill/core.c
+index fa7cd79..c22df40 100644
+--- a/net/rfkill/core.c
++++ b/net/rfkill/core.c
+@@ -782,6 +782,7 @@ void rfkill_pause_polling(struct rfkill *rfkill)
+ }
+ EXPORT_SYMBOL(rfkill_pause_polling);
+ 
++#ifdef CONFIG_RFKILL_PM
+ void rfkill_resume_polling(struct rfkill *rfkill)
+ {
+ 	BUG_ON(!rfkill);
+@@ -817,14 +818,17 @@ static int rfkill_resume(struct device *dev)
+ 
+ 	return 0;
+ }
++#endif
+ 
+ static struct class rfkill_class = {
+ 	.name		= "rfkill",
+ 	.dev_release	= rfkill_release,
+ 	.dev_groups	= rfkill_dev_groups,
+ 	.dev_uevent	= rfkill_dev_uevent,
++#ifdef CONFIG_RFKILL_PM
+ 	.suspend	= rfkill_suspend,
+ 	.resume		= rfkill_resume,
++#endif
+ };
+ 
+ bool rfkill_blocked(struct rfkill *rfkill)
+diff --git a/net/rose/rose_in.c b/net/rose/rose_in.c
+index 79c4abc..0a63947 100644
+--- a/net/rose/rose_in.c
++++ b/net/rose/rose_in.c
+@@ -164,7 +164,8 @@ static int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int framety
+ 		rose_frames_acked(sk, nr);
+ 		if (ns == rose->vr) {
+ 			rose_start_idletimer(sk);
+-			if (sock_queue_rcv_skb(sk, skb) == 0) {
++			if (sk_filter_trim_cap(sk, skb, ROSE_MIN_LEN) == 0 &&
++			    __sock_queue_rcv_skb(sk, skb) == 0) {
+ 				rose->vr = (rose->vr + 1) % ROSE_MODULUS;
+ 				queued = 1;
+ 			} else {
+diff --git a/net/socket.c b/net/socket.c
+index 02fc7c8..7f61789 100644
+--- a/net/socket.c
++++ b/net/socket.c
+@@ -2410,31 +2410,31 @@ int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
+ 			break;
+ 	}
+ 
+-out_put:
+-	fput_light(sock->file, fput_needed);
+-
+ 	if (err == 0)
+-		return datagrams;
++		goto out_put;
+ 
+-	if (datagrams != 0) {
++	if (datagrams == 0) {
++		datagrams = err;
++		goto out_put;
++	}
++
++	/*
++	 * We may return less entries than requested (vlen) if the
++	 * sock is non block and there aren't enough datagrams...
++	 */
++	if (err != -EAGAIN) {
+ 		/*
+-		 * We may return less entries than requested (vlen) if the
+-		 * sock is non block and there aren't enough datagrams...
++		 * ... or  if recvmsg returns an error after we
++		 * received some datagrams, where we record the
++		 * error to return on the next call or if the
++		 * app asks about it using getsockopt(SO_ERROR).
+ 		 */
+-		if (err != -EAGAIN) {
+-			/*
+-			 * ... or  if recvmsg returns an error after we
+-			 * received some datagrams, where we record the
+-			 * error to return on the next call or if the
+-			 * app asks about it using getsockopt(SO_ERROR).
+-			 */
+-			sock->sk->sk_err = -err;
+-		}
+-
+-		return datagrams;
++		sock->sk->sk_err = -err;
+ 	}
++out_put:
++	fput_light(sock->file, fput_needed);
+ 
+-	return err;
++	return datagrams;
+ }
+ 
+ SYSCALL_DEFINE5(recvmmsg, int, fd, struct mmsghdr __user *, mmsg,
+diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
+index 8232118..2852bb7 100644
+--- a/net/unix/af_unix.c
++++ b/net/unix/af_unix.c
+@@ -316,6 +316,118 @@ found:
+ 	return s;
+ }
+ 
++/* Support code for asymmetrically connected dgram sockets
++ *
++ * If a datagram socket is connected to a socket not itself connected
++ * to the first socket (eg, /dev/log), clients may only enqueue more
++ * messages if the present receive queue of the server socket is not
++ * "too large". This means there's a second writeability condition
++ * poll and sendmsg need to test. The dgram recv code will do a wake
++ * up on the peer_wait wait queue of a socket upon reception of a
++ * datagram which needs to be propagated to sleeping would-be writers
++ * since these might not have sent anything so far. This can't be
++ * accomplished via poll_wait because the lifetime of the server
++ * socket might be less than that of its clients if these break their
++ * association with it or if the server socket is closed while clients
++ * are still connected to it and there's no way to inform "a polling
++ * implementation" that it should let go of a certain wait queue
++ *
++ * In order to propagate a wake up, a wait_queue_t of the client
++ * socket is enqueued on the peer_wait queue of the server socket
++ * whose wake function does a wake_up on the ordinary client socket
++ * wait queue. This connection is established whenever a write (or
++ * poll for write) hit the flow control condition and broken when the
++ * association to the server socket is dissolved or after a wake up
++ * was relayed.
++ */
++
++static int unix_dgram_peer_wake_relay(wait_queue_t *q, unsigned mode, int flags,
++				      void *key)
++{
++	struct unix_sock *u;
++	wait_queue_head_t *u_sleep;
++
++	u = container_of(q, struct unix_sock, peer_wake);
++
++	__remove_wait_queue(&unix_sk(u->peer_wake.private)->peer_wait,
++			    q);
++	u->peer_wake.private = NULL;
++
++	/* relaying can only happen while the wq still exists */
++	u_sleep = sk_sleep(&u->sk);
++	if (u_sleep)
++		wake_up_interruptible_poll(u_sleep, key);
++
++	return 0;
++}
++
++static int unix_dgram_peer_wake_connect(struct sock *sk, struct sock *other)
++{
++	struct unix_sock *u, *u_other;
++	int rc;
++
++	u = unix_sk(sk);
++	u_other = unix_sk(other);
++	rc = 0;
++	spin_lock(&u_other->peer_wait.lock);
++
++	if (!u->peer_wake.private) {
++		u->peer_wake.private = other;
++		__add_wait_queue(&u_other->peer_wait, &u->peer_wake);
++
++		rc = 1;
++	}
++
++	spin_unlock(&u_other->peer_wait.lock);
++	return rc;
++}
++
++static void unix_dgram_peer_wake_disconnect(struct sock *sk,
++					    struct sock *other)
++{
++	struct unix_sock *u, *u_other;
++
++	u = unix_sk(sk);
++	u_other = unix_sk(other);
++	spin_lock(&u_other->peer_wait.lock);
++
++	if (u->peer_wake.private == other) {
++		__remove_wait_queue(&u_other->peer_wait, &u->peer_wake);
++		u->peer_wake.private = NULL;
++	}
++
++	spin_unlock(&u_other->peer_wait.lock);
++}
++
++static void unix_dgram_peer_wake_disconnect_wakeup(struct sock *sk,
++						   struct sock *other)
++{
++	unix_dgram_peer_wake_disconnect(sk, other);
++	wake_up_interruptible_poll(sk_sleep(sk),
++				   POLLOUT |
++				   POLLWRNORM |
++				   POLLWRBAND);
++}
++
++/* preconditions:
++ *	- unix_peer(sk) == other
++ *	- association is stable
++ */
++static int unix_dgram_peer_wake_me(struct sock *sk, struct sock *other)
++{
++	int connected;
++
++	connected = unix_dgram_peer_wake_connect(sk, other);
++
++	if (unix_recvq_full(other))
++		return 1;
++
++	if (connected)
++		unix_dgram_peer_wake_disconnect(sk, other);
++
++	return 0;
++}
++
+ static inline int unix_writable(struct sock *sk)
+ {
+ 	return (atomic_read(&sk->sk_wmem_alloc) << 2) <= sk->sk_sndbuf;
+@@ -420,6 +532,8 @@ static void unix_release_sock(struct sock *sk, int embrion)
+ 			skpair->sk_state_change(skpair);
+ 			sk_wake_async(skpair, SOCK_WAKE_WAITD, POLL_HUP);
+ 		}
++
++		unix_dgram_peer_wake_disconnect(sk, skpair);
+ 		sock_put(skpair); /* It may now die */
+ 		unix_peer(sk) = NULL;
+ 	}
+@@ -653,6 +767,7 @@ static struct sock *unix_create1(struct net *net, struct socket *sock)
+ 	INIT_LIST_HEAD(&u->link);
+ 	mutex_init(&u->readlock); /* single task reading lock */
+ 	init_waitqueue_head(&u->peer_wait);
++	init_waitqueue_func_entry(&u->peer_wake, unix_dgram_peer_wake_relay);
+ 	unix_insert_socket(unix_sockets_unbound(sk), sk);
+ out:
+ 	if (sk == NULL)
+@@ -1020,6 +1135,8 @@ restart:
+ 	if (unix_peer(sk)) {
+ 		struct sock *old_peer = unix_peer(sk);
+ 		unix_peer(sk) = other;
++		unix_dgram_peer_wake_disconnect_wakeup(sk, old_peer);
++
+ 		unix_state_double_unlock(sk, other);
+ 
+ 		if (other != old_peer)
+@@ -1352,7 +1469,7 @@ static void unix_detach_fds(struct scm_cookie *scm, struct sk_buff *skb)
+ 	UNIXCB(skb).fp = NULL;
+ 
+ 	for (i = scm->fp->count-1; i >= 0; i--)
+-		unix_notinflight(scm->fp->fp[i]);
++		unix_notinflight(scm->fp->user, scm->fp->fp[i]);
+ }
+ 
+ static void unix_destruct_scm(struct sk_buff *skb)
+@@ -1369,6 +1486,21 @@ static void unix_destruct_scm(struct sk_buff *skb)
+ 	sock_wfree(skb);
+ }
+ 
++/*
++ * The "user->unix_inflight" variable is protected by the garbage
++ * collection lock, and we just read it locklessly here. If you go
++ * over the limit, there might be a tiny race in actually noticing
++ * it across threads. Tough.
++ */
++static inline bool too_many_unix_fds(struct task_struct *p)
++{
++	struct user_struct *user = current_user();
++
++	if (unlikely(user->unix_inflight > task_rlimit(p, RLIMIT_NOFILE)))
++		return !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN);
++	return false;
++}
++
+ #define MAX_RECURSION_LEVEL 4
+ 
+ static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb)
+@@ -1377,6 +1509,9 @@ static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb)
+ 	unsigned char max_level = 0;
+ 	int unix_sock_count = 0;
+ 
++	if (too_many_unix_fds(current))
++		return -ETOOMANYREFS;
++
+ 	for (i = scm->fp->count - 1; i >= 0; i--) {
+ 		struct sock *sk = unix_get_socket(scm->fp->fp[i]);
+ 
+@@ -1398,10 +1533,8 @@ static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb)
+ 	if (!UNIXCB(skb).fp)
+ 		return -ENOMEM;
+ 
+-	if (unix_sock_count) {
+-		for (i = scm->fp->count - 1; i >= 0; i--)
+-			unix_inflight(scm->fp->fp[i]);
+-	}
++	for (i = scm->fp->count - 1; i >= 0; i--)
++		unix_inflight(scm->fp->user, scm->fp->fp[i]);
+ 	return max_level;
+ }
+ 
+@@ -1459,6 +1592,7 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock,
+ 	struct scm_cookie tmp_scm;
+ 	int max_level;
+ 	int data_len = 0;
++	int sk_locked;
+ 
+ 	if (NULL == siocb->scm)
+ 		siocb->scm = &tmp_scm;
+@@ -1540,12 +1674,14 @@ restart:
+ 		goto out_free;
+ 	}
+ 
++	sk_locked = 0;
+ 	unix_state_lock(other);
++restart_locked:
+ 	err = -EPERM;
+ 	if (!unix_may_send(sk, other))
+ 		goto out_unlock;
+ 
+-	if (sock_flag(other, SOCK_DEAD)) {
++	if (unlikely(sock_flag(other, SOCK_DEAD))) {
+ 		/*
+ 		 *	Check with 1003.1g - what should
+ 		 *	datagram error
+@@ -1553,10 +1689,14 @@ restart:
+ 		unix_state_unlock(other);
+ 		sock_put(other);
+ 
++		if (!sk_locked)
++			unix_state_lock(sk);
++
+ 		err = 0;
+-		unix_state_lock(sk);
+ 		if (unix_peer(sk) == other) {
+ 			unix_peer(sk) = NULL;
++			unix_dgram_peer_wake_disconnect_wakeup(sk, other);
++
+ 			unix_state_unlock(sk);
+ 
+ 			unix_dgram_disconnected(sk, other);
+@@ -1582,21 +1722,43 @@ restart:
+ 			goto out_unlock;
+ 	}
+ 
+-	if (unix_peer(other) != sk && unix_recvq_full(other)) {
+-		if (!timeo) {
+-			err = -EAGAIN;
+-			goto out_unlock;
++	/* other == sk && unix_peer(other) != sk if
++	 * - unix_peer(sk) == NULL, destination address bound to sk
++	 * - unix_peer(sk) == sk by time of get but disconnected before lock
++	 */
++	if (other != sk &&
++	    unlikely(unix_peer(other) != sk && unix_recvq_full(other))) {
++		if (timeo) {
++			timeo = unix_wait_for_peer(other, timeo);
++
++			err = sock_intr_errno(timeo);
++			if (signal_pending(current))
++				goto out_free;
++
++			goto restart;
+ 		}
+ 
+-		timeo = unix_wait_for_peer(other, timeo);
++		if (!sk_locked) {
++			unix_state_unlock(other);
++			unix_state_double_lock(sk, other);
++		}
+ 
+-		err = sock_intr_errno(timeo);
+-		if (signal_pending(current))
+-			goto out_free;
++		if (unix_peer(sk) != other ||
++		    unix_dgram_peer_wake_me(sk, other)) {
++			err = -EAGAIN;
++			sk_locked = 1;
++			goto out_unlock;
++		}
+ 
+-		goto restart;
++		if (!sk_locked) {
++			sk_locked = 1;
++			goto restart_locked;
++		}
+ 	}
+ 
++	if (unlikely(sk_locked))
++		unix_state_unlock(sk);
++
+ 	if (sock_flag(other, SOCK_RCVTSTAMP))
+ 		__net_timestamp(skb);
+ 	maybe_add_creds(skb, sock, other);
+@@ -1610,6 +1772,8 @@ restart:
+ 	return len;
+ 
+ out_unlock:
++	if (sk_locked)
++		unix_state_unlock(sk);
+ 	unix_state_unlock(other);
+ out_free:
+ 	kfree_skb(skb);
+@@ -2255,14 +2419,16 @@ static unsigned int unix_dgram_poll(struct file *file, struct socket *sock,
+ 		return mask;
+ 
+ 	writable = unix_writable(sk);
+-	other = unix_peer_get(sk);
+-	if (other) {
+-		if (unix_peer(other) != sk) {
+-			sock_poll_wait(file, &unix_sk(other)->peer_wait, wait);
+-			if (unix_recvq_full(other))
+-				writable = 0;
+-		}
+-		sock_put(other);
++	if (writable) {
++		unix_state_lock(sk);
++
++		other = unix_peer(sk);
++		if (other && unix_peer(other) != sk &&
++		    unix_recvq_full(other) &&
++		    unix_dgram_peer_wake_me(sk, other))
++			writable = 0;
++
++		unix_state_unlock(sk);
+ 	}
+ 
+ 	if (writable)
+diff --git a/net/unix/garbage.c b/net/unix/garbage.c
+index 99f7012..a5385af 100644
+--- a/net/unix/garbage.c
++++ b/net/unix/garbage.c
+@@ -122,12 +122,15 @@ struct sock *unix_get_socket(struct file *filp)
+  *	descriptor if it is for an AF_UNIX socket.
+  */
+ 
+-void unix_inflight(struct file *fp)
++void unix_inflight(struct user_struct *user, struct file *fp)
+ {
+ 	struct sock *s = unix_get_socket(fp);
++
++	spin_lock(&unix_gc_lock);
++
+ 	if (s) {
+ 		struct unix_sock *u = unix_sk(s);
+-		spin_lock(&unix_gc_lock);
++
+ 		if (atomic_long_inc_return(&u->inflight) == 1) {
+ 			BUG_ON(!list_empty(&u->link));
+ 			list_add_tail(&u->link, &gc_inflight_list);
+@@ -135,22 +138,27 @@ void unix_inflight(struct file *fp)
+ 			BUG_ON(list_empty(&u->link));
+ 		}
+ 		unix_tot_inflight++;
+-		spin_unlock(&unix_gc_lock);
+ 	}
++	user->unix_inflight++;
++	spin_unlock(&unix_gc_lock);
+ }
+ 
+-void unix_notinflight(struct file *fp)
++void unix_notinflight(struct user_struct *user, struct file *fp)
+ {
+ 	struct sock *s = unix_get_socket(fp);
++
++	spin_lock(&unix_gc_lock);
++
+ 	if (s) {
+ 		struct unix_sock *u = unix_sk(s);
+-		spin_lock(&unix_gc_lock);
++
+ 		BUG_ON(list_empty(&u->link));
+ 		if (atomic_long_dec_and_test(&u->inflight))
+ 			list_del_init(&u->link);
+ 		unix_tot_inflight--;
+-		spin_unlock(&unix_gc_lock);
+ 	}
++	user->unix_inflight--;
++	spin_unlock(&unix_gc_lock);
+ }
+ 
+ static void scan_inflight(struct sock *x, void (*func)(struct unix_sock *),
+diff --git a/net/wireless/scan.c b/net/wireless/scan.c
+index bda39f1..9e62e9c 100644
+--- a/net/wireless/scan.c
++++ b/net/wireless/scan.c
+@@ -56,7 +56,7 @@
+  * also linked into the probe response struct.
+  */
+ 
+-#define IEEE80211_SCAN_RESULT_EXPIRE	(30 * HZ)
++#define IEEE80211_SCAN_RESULT_EXPIRE	(7 * HZ)
+ 
+ static void bss_free(struct cfg80211_internal_bss *bss)
+ {
+diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include
+index 65e7b08..5374b1b 100644
+--- a/scripts/Kbuild.include
++++ b/scripts/Kbuild.include
+@@ -179,6 +179,12 @@ build := -f $(srctree)/scripts/Makefile.build obj
+ # $(Q)$(MAKE) $(modbuiltin)=dir
+ modbuiltin := -f $(srctree)/scripts/Makefile.modbuiltin obj
+ 
++###
++# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.dtbinst obj=
++# Usage:
++# $(Q)$(MAKE) $(dtbinst)=dir
++dtbinst := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.dtbinst obj
++
+ # Prefix -I with $(srctree) if it is not an absolute path.
+ # skip if -I has no parameter
+ addtree = $(if $(patsubst -I%,%,$(1)), \
+diff --git a/scripts/Makefile.dtbinst b/scripts/Makefile.dtbinst
+new file mode 100644
+index 0000000..909ed7a
+--- /dev/null
++++ b/scripts/Makefile.dtbinst
+@@ -0,0 +1,51 @@
++# ==========================================================================
++# Installing dtb files
++#
++# Installs all dtb files listed in $(dtb-y) either in the
++# INSTALL_DTBS_PATH directory or the default location:
++#
++#   $INSTALL_PATH/dtbs/$KERNELRELEASE
++#
++# Traverse through subdirectories listed in $(dts-dirs).
++# ==========================================================================
++
++src := $(obj)
++
++PHONY := __dtbs_install
++__dtbs_install:
++
++export dtbinst-root ?= $(obj)
++
++include include/config/auto.conf
++include scripts/Kbuild.include
++include $(srctree)/$(obj)/Makefile
++
++PHONY += __dtbs_install_prep
++__dtbs_install_prep:
++ifeq ("$(dtbinst-root)", "$(obj)")
++	$(Q)if [ -d $(INSTALL_DTBS_PATH).old ]; then rm -rf $(INSTALL_DTBS_PATH).old; fi
++	$(Q)if [ -d $(INSTALL_DTBS_PATH) ]; then mv $(INSTALL_DTBS_PATH) $(INSTALL_DTBS_PATH).old; fi
++	$(Q)mkdir -p $(INSTALL_DTBS_PATH)
++endif
++
++dtbinst-files	:= $(dtb-y)
++dtbinst-dirs	:= $(dts-dirs)
++
++# Helper targets for Installing DTBs into the boot directory
++quiet_cmd_dtb_install =	INSTALL $<
++      cmd_dtb_install =	mkdir -p $(2); cp $< $(2)
++
++install-dir = $(patsubst $(dtbinst-root)%,$(INSTALL_DTBS_PATH)%,$(obj))
++
++$(dtbinst-files) $(dtbinst-dirs): | __dtbs_install_prep
++
++$(dtbinst-files): %.dtb: $(obj)/%.dtb
++	$(call cmd,dtb_install,$(install-dir))
++
++$(dtbinst-dirs):
++	$(Q)$(MAKE) $(dtbinst)=$(obj)/$@
++
++PHONY += $(dtbinst-files) $(dtbinst-dirs)
++__dtbs_install: $(dtbinst-files) $(dtbinst-dirs)
++
++.PHONY: $(PHONY)
+diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
+index 54be19a..bb65833 100644
+--- a/scripts/Makefile.lib
++++ b/scripts/Makefile.lib
+@@ -283,17 +283,11 @@ $(obj)/%.dtb: $(src)/%.dts FORCE
+ 
+ dtc-tmp = $(subst $(comma),_,$(dot-target).dts.tmp)
+ 
+-# Helper targets for Installing DTBs into the boot directory
+-quiet_cmd_dtb_install =	INSTALL $<
+-      cmd_dtb_install =	cp $< $(2)
+-
+-_dtbinst_pre_:
+-	$(Q)if [ -d $(INSTALL_DTBS_PATH).old ]; then rm -rf $(INSTALL_DTBS_PATH).old; fi
+-	$(Q)if [ -d $(INSTALL_DTBS_PATH) ]; then mv $(INSTALL_DTBS_PATH) $(INSTALL_DTBS_PATH).old; fi
+-	$(Q)mkdir -p $(INSTALL_DTBS_PATH)
+-
+-%.dtb_dtbinst_: $(obj)/%.dtb _dtbinst_pre_
+-	$(call cmd,dtb_install,$(INSTALL_DTBS_PATH))
++# cat
++# ---------------------------------------------------------------------------
++# Concatentate multiple files together
++quiet_cmd_cat = CAT     $@
++cmd_cat = (cat $(filter-out FORCE,$^) > $@) || (rm -f $@; false)
+ 
+ # Bzip2
+ # ---------------------------------------------------------------------------
+diff --git a/scripts/Makefile.modinst b/scripts/Makefile.modinst
+index e48a4e9..9b7b280 100644
+--- a/scripts/Makefile.modinst
++++ b/scripts/Makefile.modinst
+@@ -29,7 +29,7 @@ quiet_cmd_modules_install = INSTALL $@
+ INSTALL_MOD_DIR ?= extra
+ ext-mod-dir = $(INSTALL_MOD_DIR)$(subst $(patsubst %/,%,$(KBUILD_EXTMOD)),,$(@D))
+ 
+-modinst_dir = $(if $(KBUILD_EXTMOD),$(ext-mod-dir),kernel/$(@D))
++modinst_dir ?= $(if $(KBUILD_EXTMOD),$(ext-mod-dir),kernel/$(@D))
+ 
+ $(modules):
+ 	$(call cmd,modules_install,$(MODLIB)/$(modinst_dir))
+diff --git a/scripts/setlocalversion b/scripts/setlocalversion
+index 63d91e2..186cb46 100755
+--- a/scripts/setlocalversion
++++ b/scripts/setlocalversion
+@@ -1,4 +1,4 @@
+-#!/bin/sh
++#/bin/sh
+ #
+ # This scripts adds local version information from the version
+ # control systems git, mercurial (hg) and subversion (svn).
+@@ -153,6 +153,7 @@ if test ! "$srctree" -ef .; then
+ 	res="$res$(collect_files "$srctree"/localversion*)"
+ fi
+ 
++LOCALVERSION=
+ # CONFIG_LOCALVERSION and LOCALVERSION (if set)
+ res="${res}${CONFIG_LOCALVERSION}${LOCALVERSION}"
+ 
+diff --git a/security/capability.c b/security/capability.c
+index d68c57a..ef951b0 100644
+--- a/security/capability.c
++++ b/security/capability.c
+@@ -12,6 +12,26 @@
+ 
+ #include <linux/security.h>
+ 
++static int cap_binder_set_context_mgr(struct task_struct *mgr)
++{
++	return 0;
++}
++
++static int cap_binder_transaction(struct task_struct *from, struct task_struct *to)
++{
++	return 0;
++}
++
++static int cap_binder_transfer_binder(struct task_struct *from, struct task_struct *to)
++{
++	return 0;
++}
++
++static int cap_binder_transfer_file(struct task_struct *from, struct task_struct *to, struct file *file)
++{
++	return 0;
++}
++
+ static int cap_syslog(int type)
+ {
+ 	return 0;
+@@ -930,6 +950,10 @@ static void cap_audit_rule_free(void *lsmrule)
+ 
+ void __init security_fixup_ops(struct security_operations *ops)
+ {
++	set_to_cap_if_null(ops, binder_set_context_mgr);
++	set_to_cap_if_null(ops, binder_transaction);
++	set_to_cap_if_null(ops, binder_transfer_binder);
++	set_to_cap_if_null(ops, binder_transfer_file);
+ 	set_to_cap_if_null(ops, ptrace_access_check);
+ 	set_to_cap_if_null(ops, ptrace_traceme);
+ 	set_to_cap_if_null(ops, capget);
+diff --git a/security/commoncap.c b/security/commoncap.c
+index bab0611..7ae2519 100644
+--- a/security/commoncap.c
++++ b/security/commoncap.c
+@@ -31,6 +31,10 @@
+ #include <linux/binfmts.h>
+ #include <linux/personality.h>
+ 
++#ifdef CONFIG_ANDROID_PARANOID_NETWORK
++#include <linux/android_aid.h>
++#endif
++
+ /*
+  * If a non-root user executes a setuid-root binary in
+  * !secure(SECURE_NOROOT) mode, then we raise capabilities.
+@@ -78,6 +82,13 @@ int cap_capable(const struct cred *cred, struct user_namespace *targ_ns,
+ {
+ 	struct user_namespace *ns = targ_ns;
+ 
++#ifdef CONFIG_ANDROID_PARANOID_NETWORK
++	if (cap == CAP_NET_RAW && in_egroup_p(AID_NET_RAW))
++		return 0;
++	if (cap == CAP_NET_ADMIN && in_egroup_p(AID_NET_ADMIN))
++		return 0;
++#endif
++
+ 	/* See if cred has the capability in the target user namespace
+ 	 * by examining the target user namespace and all of the target
+ 	 * user namespace's parents.
+diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
+index bd536cb..db91639 100644
+--- a/security/keys/process_keys.c
++++ b/security/keys/process_keys.c
+@@ -794,6 +794,7 @@ long join_session_keyring(const char *name)
+ 		ret = PTR_ERR(keyring);
+ 		goto error2;
+ 	} else if (keyring == new->session_keyring) {
++		key_put(keyring);
+ 		ret = 0;
+ 		goto error2;
+ 	}
+diff --git a/security/lsm_audit.c b/security/lsm_audit.c
+index 69fdf3b..7147c17 100644
+--- a/security/lsm_audit.c
++++ b/security/lsm_audit.c
+@@ -245,6 +245,21 @@ static void dump_common_audit_data(struct audit_buffer *ab,
+ 		}
+ 		break;
+ 	}
++	case LSM_AUDIT_DATA_IOCTL_OP: {
++		struct inode *inode;
++
++		audit_log_d_path(ab, " path=", &a->u.op->path);
++
++		inode = a->u.op->path.dentry->d_inode;
++		if (inode) {
++			audit_log_format(ab, " dev=");
++			audit_log_untrustedstring(ab, inode->i_sb->s_id);
++			audit_log_format(ab, " ino=%lu", inode->i_ino);
++		}
++
++		audit_log_format(ab, " ioctlcmd=%hx", a->u.op->cmd);
++		break;
++	}
+ 	case LSM_AUDIT_DATA_DENTRY: {
+ 		struct inode *inode;
+ 
+diff --git a/security/security.c b/security/security.c
+index 18b35c6..6ad484c 100644
+--- a/security/security.c
++++ b/security/security.c
+@@ -135,6 +135,26 @@ int __init register_security(struct security_operations *ops)
+ 
+ /* Security operations */
+ 
++int security_binder_set_context_mgr(struct task_struct *mgr)
++{
++	return security_ops->binder_set_context_mgr(mgr);
++}
++
++int security_binder_transaction(struct task_struct *from, struct task_struct *to)
++{
++	return security_ops->binder_transaction(from, to);
++}
++
++int security_binder_transfer_binder(struct task_struct *from, struct task_struct *to)
++{
++	return security_ops->binder_transfer_binder(from, to);
++}
++
++int security_binder_transfer_file(struct task_struct *from, struct task_struct *to, struct file *file)
++{
++	return security_ops->binder_transfer_file(from, to, file);
++}
++
+ int security_ptrace_access_check(struct task_struct *child, unsigned int mode)
+ {
+ #ifdef CONFIG_SECURITY_YAMA_STACKED
+diff --git a/security/selinux/avc.c b/security/selinux/avc.c
+index a18f1fa..21a3415 100644
+--- a/security/selinux/avc.c
++++ b/security/selinux/avc.c
+@@ -22,6 +22,7 @@
+ #include <linux/init.h>
+ #include <linux/skbuff.h>
+ #include <linux/percpu.h>
++#include <linux/list.h>
+ #include <net/sock.h>
+ #include <linux/un.h>
+ #include <net/af_unix.h>
+@@ -48,6 +49,7 @@ struct avc_entry {
+ 	u32			tsid;
+ 	u16			tclass;
+ 	struct av_decision	avd;
++	struct avc_operation_node *ops_node;
+ };
+ 
+ struct avc_node {
+@@ -64,6 +66,16 @@ struct avc_cache {
+ 	u32			latest_notif;	/* latest revocation notification */
+ };
+ 
++struct avc_operation_decision_node {
++	struct operation_decision od;
++	struct list_head od_list;
++};
++
++struct avc_operation_node {
++	struct operation ops;
++	struct list_head od_head; /* list of operation_decision_node */
++};
++
+ struct avc_callback_node {
+ 	int (*callback) (u32 event);
+ 	u32 events;
+@@ -80,6 +92,9 @@ DEFINE_PER_CPU(struct avc_cache_stats, avc_cache_stats) = { 0 };
+ static struct avc_cache avc_cache;
+ static struct avc_callback_node *avc_callbacks;
+ static struct kmem_cache *avc_node_cachep;
++static struct kmem_cache *avc_operation_decision_node_cachep;
++static struct kmem_cache *avc_operation_node_cachep;
++static struct kmem_cache *avc_operation_perm_cachep;
+ 
+ static inline int avc_hash(u32 ssid, u32 tsid, u16 tclass)
+ {
+@@ -171,6 +186,16 @@ void __init avc_init(void)
+ 
+ 	avc_node_cachep = kmem_cache_create("avc_node", sizeof(struct avc_node),
+ 					     0, SLAB_PANIC, NULL);
++	avc_operation_node_cachep = kmem_cache_create("avc_operation_node",
++				sizeof(struct avc_operation_node),
++				0, SLAB_PANIC, NULL);
++	avc_operation_decision_node_cachep = kmem_cache_create(
++				"avc_operation_decision_node",
++				sizeof(struct avc_operation_decision_node),
++				0, SLAB_PANIC, NULL);
++	avc_operation_perm_cachep = kmem_cache_create("avc_operation_perm",
++				sizeof(struct operation_perm),
++				0, SLAB_PANIC, NULL);
+ 
+ 	audit_log(current->audit_context, GFP_KERNEL, AUDIT_KERNEL, "AVC INITIALIZED\n");
+ }
+@@ -205,9 +230,271 @@ int avc_get_hash_stats(char *page)
+ 			 slots_used, AVC_CACHE_SLOTS, max_chain_len);
+ }
+ 
++/*
++ * using a linked list for operation_decision lookup because the list is
++ * always small. i.e. less than 5, typically 1
++ */
++static struct operation_decision *avc_operation_lookup(u8 type,
++					struct avc_operation_node *ops_node)
++{
++	struct avc_operation_decision_node *od_node;
++	struct operation_decision *od = NULL;
++
++	list_for_each_entry(od_node, &ops_node->od_head, od_list) {
++		if (od_node->od.type != type)
++			continue;
++		od = &od_node->od;
++		break;
++	}
++	return od;
++}
++
++static inline unsigned int avc_operation_has_perm(struct operation_decision *od,
++						u16 cmd, u8 specified)
++{
++	unsigned int rc = 0;
++	u8 num = cmd & 0xff;
++
++	if ((specified == OPERATION_ALLOWED) &&
++			(od->specified & OPERATION_ALLOWED))
++		rc = security_operation_test(od->allowed->perms, num);
++	else if ((specified == OPERATION_AUDITALLOW) &&
++			(od->specified & OPERATION_AUDITALLOW))
++		rc = security_operation_test(od->auditallow->perms, num);
++	else if ((specified == OPERATION_DONTAUDIT) &&
++			(od->specified & OPERATION_DONTAUDIT))
++		rc = security_operation_test(od->dontaudit->perms, num);
++	return rc;
++}
++
++static void avc_operation_allow_perm(struct avc_operation_node *node, u16 cmd)
++{
++	struct operation_decision *od;
++	u8 type;
++	u8 num;
++
++	type = cmd >> 8;
++	num = cmd & 0xff;
++	security_operation_set(node->ops.type, type);
++	od = avc_operation_lookup(type, node);
++	if (od && od->allowed)
++		security_operation_set(od->allowed->perms, num);
++}
++
++static void avc_operation_decision_free(
++				struct avc_operation_decision_node *od_node)
++{
++	struct operation_decision *od;
++
++	od = &od_node->od;
++	if (od->allowed)
++		kmem_cache_free(avc_operation_perm_cachep, od->allowed);
++	if (od->auditallow)
++		kmem_cache_free(avc_operation_perm_cachep, od->auditallow);
++	if (od->dontaudit)
++		kmem_cache_free(avc_operation_perm_cachep, od->dontaudit);
++	kmem_cache_free(avc_operation_decision_node_cachep, od_node);
++}
++
++static void avc_operation_free(struct avc_operation_node *ops_node)
++{
++	struct avc_operation_decision_node *od_node, *tmp;
++
++	if (!ops_node)
++		return;
++
++	list_for_each_entry_safe(od_node, tmp, &ops_node->od_head, od_list) {
++		list_del(&od_node->od_list);
++		avc_operation_decision_free(od_node);
++	}
++	kmem_cache_free(avc_operation_node_cachep, ops_node);
++}
++
++static void avc_copy_operation_decision(struct operation_decision *dest,
++					struct operation_decision *src)
++{
++	dest->type = src->type;
++	dest->specified = src->specified;
++	if (dest->specified & OPERATION_ALLOWED)
++		memcpy(dest->allowed->perms, src->allowed->perms,
++				sizeof(src->allowed->perms));
++	if (dest->specified & OPERATION_AUDITALLOW)
++		memcpy(dest->auditallow->perms, src->auditallow->perms,
++				sizeof(src->auditallow->perms));
++	if (dest->specified & OPERATION_DONTAUDIT)
++		memcpy(dest->dontaudit->perms, src->dontaudit->perms,
++				sizeof(src->dontaudit->perms));
++}
++
++/*
++ * similar to avc_copy_operation_decision, but only copy decision
++ * information relevant to this command
++ */
++static inline void avc_quick_copy_operation_decision(u16 cmd,
++			struct operation_decision *dest,
++			struct operation_decision *src)
++{
++	/*
++	 * compute index of the u32 of the 256 bits (8 u32s) that contain this
++	 * command permission
++	 */
++	u8 i = (0xff & cmd) >> 5;
++
++	dest->specified = src->specified;
++	if (dest->specified & OPERATION_ALLOWED)
++		dest->allowed->perms[i] = src->allowed->perms[i];
++	if (dest->specified & OPERATION_AUDITALLOW)
++		dest->auditallow->perms[i] = src->auditallow->perms[i];
++	if (dest->specified & OPERATION_DONTAUDIT)
++		dest->dontaudit->perms[i] = src->dontaudit->perms[i];
++}
++
++static struct avc_operation_decision_node
++		*avc_operation_decision_alloc(u8 specified)
++{
++	struct avc_operation_decision_node *node;
++	struct operation_decision *od;
++
++	node = kmem_cache_zalloc(avc_operation_decision_node_cachep,
++				GFP_ATOMIC | __GFP_NOMEMALLOC);
++	if (!node)
++		return NULL;
++
++	od = &node->od;
++	if (specified & OPERATION_ALLOWED) {
++		od->allowed = kmem_cache_zalloc(avc_operation_perm_cachep,
++						GFP_ATOMIC | __GFP_NOMEMALLOC);
++		if (!od->allowed)
++			goto error;
++	}
++	if (specified & OPERATION_AUDITALLOW) {
++		od->auditallow = kmem_cache_zalloc(avc_operation_perm_cachep,
++						GFP_ATOMIC | __GFP_NOMEMALLOC);
++		if (!od->auditallow)
++			goto error;
++	}
++	if (specified & OPERATION_DONTAUDIT) {
++		od->dontaudit = kmem_cache_zalloc(avc_operation_perm_cachep,
++						GFP_ATOMIC | __GFP_NOMEMALLOC);
++		if (!od->dontaudit)
++			goto error;
++	}
++	return node;
++error:
++	avc_operation_decision_free(node);
++	return NULL;
++}
++
++static int avc_add_operation(struct avc_node *node,
++			struct operation_decision *od)
++{
++	struct avc_operation_decision_node *dest_od;
++
++	node->ae.ops_node->ops.len++;
++	dest_od = avc_operation_decision_alloc(od->specified);
++	if (!dest_od)
++		return -ENOMEM;
++	avc_copy_operation_decision(&dest_od->od, od);
++	list_add(&dest_od->od_list, &node->ae.ops_node->od_head);
++	return 0;
++}
++
++static struct avc_operation_node *avc_operation_alloc(void)
++{
++	struct avc_operation_node *ops;
++
++	ops = kmem_cache_zalloc(avc_operation_node_cachep,
++				GFP_ATOMIC|__GFP_NOMEMALLOC);
++	if (!ops)
++		return ops;
++	INIT_LIST_HEAD(&ops->od_head);
++	return ops;
++}
++
++static int avc_operation_populate(struct avc_node *node,
++				struct avc_operation_node *src)
++{
++	struct avc_operation_node *dest;
++	struct avc_operation_decision_node *dest_od;
++	struct avc_operation_decision_node *src_od;
++
++	if (src->ops.len == 0)
++		return 0;
++	dest = avc_operation_alloc();
++	if (!dest)
++		return -ENOMEM;
++
++	memcpy(dest->ops.type, &src->ops.type, sizeof(dest->ops.type));
++	dest->ops.len = src->ops.len;
++
++	/* for each source od allocate a destination od and copy */
++	list_for_each_entry(src_od, &src->od_head, od_list) {
++		dest_od = avc_operation_decision_alloc(src_od->od.specified);
++		if (!dest_od)
++			goto error;
++		avc_copy_operation_decision(&dest_od->od, &src_od->od);
++		list_add(&dest_od->od_list, &dest->od_head);
++	}
++	node->ae.ops_node = dest;
++	return 0;
++error:
++	avc_operation_free(dest);
++	return -ENOMEM;
++
++}
++
++static inline u32 avc_operation_audit_required(u32 requested,
++					struct av_decision *avd,
++					struct operation_decision *od,
++					u16 cmd,
++					int result,
++					u32 *deniedp)
++{
++	u32 denied, audited;
++
++	denied = requested & ~avd->allowed;
++	if (unlikely(denied)) {
++		audited = denied & avd->auditdeny;
++		if (audited && od) {
++			if (avc_operation_has_perm(od, cmd,
++						OPERATION_DONTAUDIT))
++				audited &= ~requested;
++		}
++	} else if (result) {
++		audited = denied = requested;
++	} else {
++		audited = requested & avd->auditallow;
++		if (audited && od) {
++			if (!avc_operation_has_perm(od, cmd,
++						OPERATION_AUDITALLOW))
++				audited &= ~requested;
++		}
++	}
++
++	*deniedp = denied;
++	return audited;
++}
++
++static inline int avc_operation_audit(u32 ssid, u32 tsid, u16 tclass,
++				u32 requested, struct av_decision *avd,
++				struct operation_decision *od,
++				u16 cmd, int result,
++				struct common_audit_data *ad)
++{
++	u32 audited, denied;
++
++	audited = avc_operation_audit_required(
++			requested, avd, od, cmd, result, &denied);
++	if (likely(!audited))
++		return 0;
++	return slow_avc_audit(ssid, tsid, tclass, requested,
++			audited, denied, result, ad, 0);
++}
++
+ static void avc_node_free(struct rcu_head *rhead)
+ {
+ 	struct avc_node *node = container_of(rhead, struct avc_node, rhead);
++	avc_operation_free(node->ae.ops_node);
+ 	kmem_cache_free(avc_node_cachep, node);
+ 	avc_cache_stats_incr(frees);
+ }
+@@ -221,6 +508,7 @@ static void avc_node_delete(struct avc_node *node)
+ 
+ static void avc_node_kill(struct avc_node *node)
+ {
++	avc_operation_free(node->ae.ops_node);
+ 	kmem_cache_free(avc_node_cachep, node);
+ 	avc_cache_stats_incr(frees);
+ 	atomic_dec(&avc_cache.active_nodes);
+@@ -367,6 +655,7 @@ static int avc_latest_notif_update(int seqno, int is_insert)
+  * @tsid: target security identifier
+  * @tclass: target security class
+  * @avd: resulting av decision
++ * @ops: resulting operation decisions
+  *
+  * Insert an AVC entry for the SID pair
+  * (@ssid, @tsid) and class @tclass.
+@@ -378,7 +667,9 @@ static int avc_latest_notif_update(int seqno, int is_insert)
+  * the access vectors into a cache entry, returns
+  * avc_node inserted. Otherwise, this function returns NULL.
+  */
+-static struct avc_node *avc_insert(u32 ssid, u32 tsid, u16 tclass, struct av_decision *avd)
++static struct avc_node *avc_insert(u32 ssid, u32 tsid, u16 tclass,
++				struct av_decision *avd,
++				struct avc_operation_node *ops_node)
+ {
+ 	struct avc_node *pos, *node = NULL;
+ 	int hvalue;
+@@ -391,10 +682,15 @@ static struct avc_node *avc_insert(u32 ssid, u32 tsid, u16 tclass, struct av_dec
+ 	if (node) {
+ 		struct hlist_head *head;
+ 		spinlock_t *lock;
++		int rc = 0;
+ 
+ 		hvalue = avc_hash(ssid, tsid, tclass);
+ 		avc_node_populate(node, ssid, tsid, tclass, avd);
+-
++		rc = avc_operation_populate(node, ops_node);
++		if (rc) {
++			kmem_cache_free(avc_node_cachep, node);
++			return NULL;
++		}
+ 		head = &avc_cache.slots[hvalue];
+ 		lock = &avc_cache.slots_lock[hvalue];
+ 
+@@ -528,14 +824,17 @@ static inline int avc_sidcmp(u32 x, u32 y)
+  * @perms : Permission mask bits
+  * @ssid,@tsid,@tclass : identifier of an AVC entry
+  * @seqno : sequence number when decision was made
++ * @od: operation_decision to be added to the node
+  *
+  * if a valid AVC entry doesn't exist,this function returns -ENOENT.
+  * if kmalloc() called internal returns NULL, this function returns -ENOMEM.
+  * otherwise, this function updates the AVC entry. The original AVC-entry object
+  * will release later by RCU.
+  */
+-static int avc_update_node(u32 event, u32 perms, u32 ssid, u32 tsid, u16 tclass,
+-			   u32 seqno)
++static int avc_update_node(u32 event, u32 perms, u16 cmd, u32 ssid, u32 tsid,
++			u16 tclass, u32 seqno,
++			struct operation_decision *od,
++			u32 flags)
+ {
+ 	int hvalue, rc = 0;
+ 	unsigned long flag;
+@@ -579,9 +878,19 @@ static int avc_update_node(u32 event, u32 perms, u32 ssid, u32 tsid, u16 tclass,
+ 
+ 	avc_node_populate(node, ssid, tsid, tclass, &orig->ae.avd);
+ 
++	if (orig->ae.ops_node) {
++		rc = avc_operation_populate(node, orig->ae.ops_node);
++		if (rc) {
++			kmem_cache_free(avc_node_cachep, node);
++			goto out_unlock;
++		}
++	}
++
+ 	switch (event) {
+ 	case AVC_CALLBACK_GRANT:
+ 		node->ae.avd.allowed |= perms;
++		if (node->ae.ops_node && (flags & AVC_OPERATION_CMD))
++			avc_operation_allow_perm(node->ae.ops_node, cmd);
+ 		break;
+ 	case AVC_CALLBACK_TRY_REVOKE:
+ 	case AVC_CALLBACK_REVOKE:
+@@ -599,6 +908,9 @@ static int avc_update_node(u32 event, u32 perms, u32 ssid, u32 tsid, u16 tclass,
+ 	case AVC_CALLBACK_AUDITDENY_DISABLE:
+ 		node->ae.avd.auditdeny &= ~perms;
+ 		break;
++	case AVC_CALLBACK_ADD_OPERATION:
++		avc_add_operation(node, od);
++		break;
+ 	}
+ 	avc_node_replace(node, orig);
+ out_unlock:
+@@ -670,18 +982,20 @@ int avc_ss_reset(u32 seqno)
+  * results in a bigger stack frame.
+  */
+ static noinline struct avc_node *avc_compute_av(u32 ssid, u32 tsid,
+-			 u16 tclass, struct av_decision *avd)
++			 u16 tclass, struct av_decision *avd,
++			 struct avc_operation_node *ops_node)
+ {
+ 	rcu_read_unlock();
+-	security_compute_av(ssid, tsid, tclass, avd);
++	INIT_LIST_HEAD(&ops_node->od_head);
++	security_compute_av(ssid, tsid, tclass, avd, &ops_node->ops);
+ 	rcu_read_lock();
+-	return avc_insert(ssid, tsid, tclass, avd);
++	return avc_insert(ssid, tsid, tclass, avd, ops_node);
+ }
+ 
+ static noinline int avc_denied(u32 ssid, u32 tsid,
+-			 u16 tclass, u32 requested,
+-			 unsigned flags,
+-			 struct av_decision *avd)
++				u16 tclass, u32 requested,
++				u16 cmd, unsigned flags,
++				struct av_decision *avd)
+ {
+ 	if (flags & AVC_STRICT)
+ 		return -EACCES;
+@@ -689,11 +1003,92 @@ static noinline int avc_denied(u32 ssid, u32 tsid,
+ 	if (selinux_enforcing && !(avd->flags & AVD_FLAGS_PERMISSIVE))
+ 		return -EACCES;
+ 
+-	avc_update_node(AVC_CALLBACK_GRANT, requested, ssid,
+-				tsid, tclass, avd->seqno);
++	avc_update_node(AVC_CALLBACK_GRANT, requested, cmd, ssid,
++				tsid, tclass, avd->seqno, NULL, flags);
+ 	return 0;
+ }
+ 
++/*
++ * ioctl commands are comprised of four fields, direction, size, type, and
++ * number. The avc operation logic filters based on two of them:
++ *
++ * type: or code, typically unique to each driver
++ * number: or function
++ *
++ * For example, 0x89 is a socket type, and number 0x27 is the get hardware
++ * address function.
++ */
++int avc_has_operation(u32 ssid, u32 tsid, u16 tclass, u32 requested,
++			u16 cmd, struct common_audit_data *ad)
++{
++	struct avc_node *node;
++	struct av_decision avd;
++	u32 denied;
++	struct operation_decision *od = NULL;
++	struct operation_decision od_local;
++	struct operation_perm allowed;
++	struct operation_perm auditallow;
++	struct operation_perm dontaudit;
++	struct avc_operation_node local_ops_node;
++	struct avc_operation_node *ops_node;
++	u8 type = cmd >> 8;
++	int rc = 0, rc2;
++
++	ops_node = &local_ops_node;
++	BUG_ON(!requested);
++
++	rcu_read_lock();
++
++	node = avc_lookup(ssid, tsid, tclass);
++	if (unlikely(!node)) {
++		node = avc_compute_av(ssid, tsid, tclass, &avd, ops_node);
++	} else {
++		memcpy(&avd, &node->ae.avd, sizeof(avd));
++		ops_node = node->ae.ops_node;
++	}
++	/* if operations are not defined, only consider av_decision */
++	if (!ops_node || !ops_node->ops.len)
++		goto decision;
++
++	od_local.allowed = &allowed;
++	od_local.auditallow = &auditallow;
++	od_local.dontaudit = &dontaudit;
++
++	/* lookup operation decision */
++	od = avc_operation_lookup(type, ops_node);
++	if (unlikely(!od)) {
++		/* Compute operation decision if type is flagged */
++		if (!security_operation_test(ops_node->ops.type, type)) {
++			avd.allowed &= ~requested;
++			goto decision;
++		}
++		rcu_read_unlock();
++		security_compute_operation(ssid, tsid, tclass, type, &od_local);
++		rcu_read_lock();
++		avc_update_node(AVC_CALLBACK_ADD_OPERATION, requested, cmd,
++				ssid, tsid, tclass, avd.seqno, &od_local, 0);
++	} else {
++		avc_quick_copy_operation_decision(cmd, &od_local, od);
++	}
++	od = &od_local;
++
++	if (!avc_operation_has_perm(od, cmd, OPERATION_ALLOWED))
++		avd.allowed &= ~requested;
++
++decision:
++	denied = requested & ~(avd.allowed);
++	if (unlikely(denied))
++		rc = avc_denied(ssid, tsid, tclass, requested, cmd,
++				AVC_OPERATION_CMD, &avd);
++
++	rcu_read_unlock();
++
++	rc2 = avc_operation_audit(ssid, tsid, tclass, requested,
++			&avd, od, cmd, rc, ad);
++	if (rc2)
++		return rc2;
++	return rc;
++}
+ 
+ /**
+  * avc_has_perm_noaudit - Check permissions but perform no auditing.
+@@ -721,6 +1116,7 @@ inline int avc_has_perm_noaudit(u32 ssid, u32 tsid,
+ 			 struct av_decision *avd)
+ {
+ 	struct avc_node *node;
++	struct avc_operation_node ops_node;
+ 	int rc = 0;
+ 	u32 denied;
+ 
+@@ -729,16 +1125,14 @@ inline int avc_has_perm_noaudit(u32 ssid, u32 tsid,
+ 	rcu_read_lock();
+ 
+ 	node = avc_lookup(ssid, tsid, tclass);
+-	if (unlikely(!node)) {
+-		node = avc_compute_av(ssid, tsid, tclass, avd);
+-	} else {
++	if (unlikely(!node))
++		node = avc_compute_av(ssid, tsid, tclass, avd, &ops_node);
++	else
+ 		memcpy(avd, &node->ae.avd, sizeof(*avd));
+-		avd = &node->ae.avd;
+-	}
+ 
+ 	denied = requested & ~(avd->allowed);
+ 	if (unlikely(denied))
+-		rc = avc_denied(ssid, tsid, tclass, requested, flags, avd);
++		rc = avc_denied(ssid, tsid, tclass, requested, 0, flags, avd);
+ 
+ 	rcu_read_unlock();
+ 	return rc;
+diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
+index b1e455b..cdce494 100644
+--- a/security/selinux/hooks.c
++++ b/security/selinux/hooks.c
+@@ -403,24 +403,15 @@ static int selinux_is_sblabel_mnt(struct super_block *sb)
+ {
+ 	struct superblock_security_struct *sbsec = sb->s_security;
+ 
+-	if (sbsec->behavior == SECURITY_FS_USE_XATTR ||
+-	    sbsec->behavior == SECURITY_FS_USE_TRANS ||
+-	    sbsec->behavior == SECURITY_FS_USE_TASK ||
+-	    sbsec->behavior == SECURITY_FS_USE_NATIVE)
+-		return 1;
+-
+-	/* Special handling for sysfs. Is genfs but also has setxattr handler*/
+-	if (strncmp(sb->s_type->name, "sysfs", sizeof("sysfs")) == 0)
+-		return 1;
+-
+-	/*
+-	 * Special handling for rootfs. Is genfs but supports
+-	 * setting SELinux context on in-core inodes.
+-	 */
+-	if (strncmp(sb->s_type->name, "rootfs", sizeof("rootfs")) == 0)
+-		return 1;
+-
+-	return 0;
++	return sbsec->behavior == SECURITY_FS_USE_XATTR ||
++		sbsec->behavior == SECURITY_FS_USE_TRANS ||
++		sbsec->behavior == SECURITY_FS_USE_TASK ||
++		sbsec->behavior == SECURITY_FS_USE_NATIVE ||
++		/* Special handling. Genfs but also in-core setxattr handler */
++		!strcmp(sb->s_type->name, "sysfs") ||
++		!strcmp(sb->s_type->name, "pstore") ||
++		!strcmp(sb->s_type->name, "debugfs") ||
++		!strcmp(sb->s_type->name, "rootfs");
+ }
+ 
+ static int sb_finish_set_opts(struct super_block *sb)
+@@ -741,7 +732,12 @@ static int selinux_set_mnt_opts(struct super_block *sb,
+ 	}
+ 
+ 	if (strcmp(sb->s_type->name, "proc") == 0)
+-		sbsec->flags |= SE_SBPROC;
++		sbsec->flags |= SE_SBPROC | SE_SBGENFS;
++
++	if (!strcmp(sb->s_type->name, "debugfs") ||
++	    !strcmp(sb->s_type->name, "sysfs") ||
++	    !strcmp(sb->s_type->name, "pstore"))
++		sbsec->flags |= SE_SBGENFS;
+ 
+ 	if (!sbsec->behavior) {
+ 		/*
+@@ -1237,12 +1233,13 @@ static inline u16 socket_type_to_security_class(int family, int type, int protoc
+ 	return SECCLASS_SOCKET;
+ }
+ 
+-#ifdef CONFIG_PROC_FS
+-static int selinux_proc_get_sid(struct dentry *dentry,
+-				u16 tclass,
+-				u32 *sid)
++static int selinux_genfs_get_sid(struct dentry *dentry,
++				 u16 tclass,
++				 u16 flags,
++				 u32 *sid)
+ {
+ 	int rc;
++	struct super_block *sb = dentry->d_inode->i_sb;
+ 	char *buffer, *path;
+ 
+ 	buffer = (char *)__get_free_page(GFP_KERNEL);
+@@ -1253,26 +1250,20 @@ static int selinux_proc_get_sid(struct dentry *dentry,
+ 	if (IS_ERR(path))
+ 		rc = PTR_ERR(path);
+ 	else {
+-		/* each process gets a /proc/PID/ entry. Strip off the
+-		 * PID part to get a valid selinux labeling.
+-		 * e.g. /proc/1/net/rpc/nfs -> /net/rpc/nfs */
+-		while (path[1] >= '0' && path[1] <= '9') {
+-			path[1] = '/';
+-			path++;
++		if (flags & SE_SBPROC) {
++			/* each process gets a /proc/PID/ entry. Strip off the
++			 * PID part to get a valid selinux labeling.
++			 * e.g. /proc/1/net/rpc/nfs -> /net/rpc/nfs */
++			while (path[1] >= '0' && path[1] <= '9') {
++				path[1] = '/';
++				path++;
++			}
+ 		}
+-		rc = security_genfs_sid("proc", path, tclass, sid);
++		rc = security_genfs_sid(sb->s_type->name, path, tclass, sid);
+ 	}
+ 	free_page((unsigned long)buffer);
+ 	return rc;
+ }
+-#else
+-static int selinux_proc_get_sid(struct dentry *dentry,
+-				u16 tclass,
+-				u32 *sid)
+-{
+-	return -EINVAL;
+-}
+-#endif
+ 
+ /* The inode's security attributes must be initialized before first use. */
+ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry)
+@@ -1429,7 +1420,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
+ 		/* Default to the fs superblock SID. */
+ 		isec->sid = sbsec->sid;
+ 
+-		if ((sbsec->flags & SE_SBPROC) && !S_ISLNK(inode->i_mode)) {
++		if ((sbsec->flags & SE_SBGENFS) && !S_ISLNK(inode->i_mode)) {
+ 			/* We must have a dentry to determine the label on
+ 			 * procfs inodes */
+ 			if (opt_dentry)
+@@ -1452,7 +1443,8 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
+ 			if (!dentry)
+ 				goto out_unlock;
+ 			isec->sclass = inode_mode_to_security_class(inode->i_mode);
+-			rc = selinux_proc_get_sid(dentry, isec->sclass, &sid);
++			rc = selinux_genfs_get_sid(dentry, isec->sclass,
++						   sbsec->flags, &sid);
+ 			dput(dentry);
+ 			if (rc)
+ 				goto out_unlock;
+@@ -1936,6 +1928,65 @@ static inline u32 open_file_to_av(struct file *file)
+ 
+ /* Hook functions begin here. */
+ 
++static int selinux_binder_set_context_mgr(struct task_struct *mgr)
++{
++	u32 mysid = current_sid();
++	u32 mgrsid = task_sid(mgr);
++
++	return avc_has_perm(mysid, mgrsid, SECCLASS_BINDER, BINDER__SET_CONTEXT_MGR, NULL);
++}
++
++static int selinux_binder_transaction(struct task_struct *from, struct task_struct *to)
++{
++	u32 mysid = current_sid();
++	u32 fromsid = task_sid(from);
++	u32 tosid = task_sid(to);
++	int rc;
++
++	if (mysid != fromsid) {
++		rc = avc_has_perm(mysid, fromsid, SECCLASS_BINDER, BINDER__IMPERSONATE, NULL);
++		if (rc)
++			return rc;
++	}
++
++	return avc_has_perm(fromsid, tosid, SECCLASS_BINDER, BINDER__CALL, NULL);
++}
++
++static int selinux_binder_transfer_binder(struct task_struct *from, struct task_struct *to)
++{
++	u32 fromsid = task_sid(from);
++	u32 tosid = task_sid(to);
++	return avc_has_perm(fromsid, tosid, SECCLASS_BINDER, BINDER__TRANSFER, NULL);
++}
++
++static int selinux_binder_transfer_file(struct task_struct *from, struct task_struct *to, struct file *file)
++{
++	u32 sid = task_sid(to);
++	struct file_security_struct *fsec = file->f_security;
++	struct inode *inode = file->f_path.dentry->d_inode;
++	struct inode_security_struct *isec = inode->i_security;
++	struct common_audit_data ad;
++	int rc;
++
++	ad.type = LSM_AUDIT_DATA_PATH;
++	ad.u.path = file->f_path;
++
++	if (sid != fsec->sid) {
++		rc = avc_has_perm(sid, fsec->sid,
++				  SECCLASS_FD,
++				  FD__USE,
++				  &ad);
++		if (rc)
++			return rc;
++	}
++
++	if (unlikely(IS_PRIVATE(inode)))
++		return 0;
++
++	return avc_has_perm(sid, isec->sid, isec->sclass, file_to_av(file),
++			    &ad);
++}
++
+ static int selinux_ptrace_access_check(struct task_struct *child,
+ 				     unsigned int mode)
+ {
+@@ -3187,6 +3238,44 @@ static void selinux_file_free_security(struct file *file)
+ 	file_free_security(file);
+ }
+ 
++/*
++ * Check whether a task has the ioctl permission and cmd
++ * operation to an inode.
++ */
++int ioctl_has_perm(const struct cred *cred, struct file *file,
++		u32 requested, u16 cmd)
++{
++	struct common_audit_data ad;
++	struct file_security_struct *fsec = file->f_security;
++	struct inode *inode = file_inode(file);
++	struct inode_security_struct *isec = inode->i_security;
++	struct lsm_ioctlop_audit ioctl;
++	u32 ssid = cred_sid(cred);
++	int rc;
++
++	ad.type = LSM_AUDIT_DATA_IOCTL_OP;
++	ad.u.op = &ioctl;
++	ad.u.op->cmd = cmd;
++	ad.u.op->path = file->f_path;
++
++	if (ssid != fsec->sid) {
++		rc = avc_has_perm(ssid, fsec->sid,
++				SECCLASS_FD,
++				FD__USE,
++				&ad);
++		if (rc)
++			goto out;
++	}
++
++	if (unlikely(IS_PRIVATE(inode)))
++		return 0;
++
++	rc = avc_has_operation(ssid, isec->sid, isec->sclass,
++			requested, cmd, &ad);
++out:
++	return rc;
++}
++
+ static int selinux_file_ioctl(struct file *file, unsigned int cmd,
+ 			      unsigned long arg)
+ {
+@@ -3229,7 +3318,7 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd,
+ 	 * to the file's ioctl() function.
+ 	 */
+ 	default:
+-		error = file_has_perm(cred, file, FILE__IOCTL);
++		error = ioctl_has_perm(cred, file, FILE__IOCTL, (u16) cmd);
+ 	}
+ 	return error;
+ }
+@@ -5813,6 +5902,11 @@ static int selinux_key_getsecurity(struct key *key, char **_buffer)
+ static struct security_operations selinux_ops = {
+ 	.name =				"selinux",
+ 
++	.binder_set_context_mgr =	selinux_binder_set_context_mgr,
++	.binder_transaction =		selinux_binder_transaction,
++	.binder_transfer_binder =	selinux_binder_transfer_binder,
++	.binder_transfer_file =		selinux_binder_transfer_file,
++
+ 	.ptrace_access_check =		selinux_ptrace_access_check,
+ 	.ptrace_traceme =		selinux_ptrace_traceme,
+ 	.capget =			selinux_capget,
+diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h
+index ddf8eec..3165d4e 100644
+--- a/security/selinux/include/avc.h
++++ b/security/selinux/include/avc.h
+@@ -142,6 +142,7 @@ static inline int avc_audit(u32 ssid, u32 tsid,
+ }
+ 
+ #define AVC_STRICT 1 /* Ignore permissive mode. */
++#define AVC_OPERATION_CMD 2	/* ignore command when updating operations */
+ int avc_has_perm_noaudit(u32 ssid, u32 tsid,
+ 			 u16 tclass, u32 requested,
+ 			 unsigned flags,
+@@ -151,6 +152,9 @@ int avc_has_perm(u32 ssid, u32 tsid,
+ 		 u16 tclass, u32 requested,
+ 		 struct common_audit_data *auditdata);
+ 
++int avc_has_operation(u32 ssid, u32 tsid, u16 tclass, u32 requested,
++		u16 cmd, struct common_audit_data *ad);
++
+ u32 avc_policy_seqno(void);
+ 
+ #define AVC_CALLBACK_GRANT		1
+@@ -161,6 +165,7 @@ u32 avc_policy_seqno(void);
+ #define AVC_CALLBACK_AUDITALLOW_DISABLE	32
+ #define AVC_CALLBACK_AUDITDENY_ENABLE	64
+ #define AVC_CALLBACK_AUDITDENY_DISABLE	128
++#define AVC_CALLBACK_ADD_OPERATION	256
+ 
+ int avc_add_callback(int (*callback)(u32 event), u32 events);
+ 
+diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h
+index be491a7..bdc9325 100644
+--- a/security/selinux/include/classmap.h
++++ b/security/selinux/include/classmap.h
+@@ -151,5 +151,6 @@ struct security_class_mapping secclass_map[] = {
+ 	{ "kernel_service", { "use_as_override", "create_files_as", NULL } },
+ 	{ "tun_socket",
+ 	  { COMMON_SOCK_PERMS, "attach_queue", NULL } },
++	{ "binder", { "impersonate", "call", "set_context_mgr", "transfer", NULL } },
+ 	{ NULL }
+   };
+diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
+index d1e0b23..8d50683 100644
+--- a/security/selinux/include/security.h
++++ b/security/selinux/include/security.h
+@@ -35,13 +35,14 @@
+ #define POLICYDB_VERSION_NEW_OBJECT_DEFAULTS	27
+ #define POLICYDB_VERSION_DEFAULT_TYPE	28
+ #define POLICYDB_VERSION_CONSTRAINT_NAMES	29
++#define POLICYDB_VERSION_IOCTL_OPERATIONS	30
+ 
+ /* Range of policy versions we understand*/
+ #define POLICYDB_VERSION_MIN   POLICYDB_VERSION_BASE
+ #ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX
+ #define POLICYDB_VERSION_MAX	CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE
+ #else
+-#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_CONSTRAINT_NAMES
++#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_IOCTL_OPERATIONS
+ #endif
+ 
+ /* Mask for just the mount related flags */
+@@ -56,6 +57,7 @@
+ /* Non-mount related flags */
+ #define SE_SBINITIALIZED	0x0100
+ #define SE_SBPROC		0x0200
++#define SE_SBGENFS		0x0400
+ 
+ #define CONTEXT_STR	"context="
+ #define FSCONTEXT_STR	"fscontext="
+@@ -108,11 +110,40 @@ struct av_decision {
+ 	u32 flags;
+ };
+ 
++#define security_operation_set(perms, x) (perms[x >> 5] |= 1 << (x & 0x1f))
++#define security_operation_test(perms, x) (1 & (perms[x >> 5] >> (x & 0x1f)))
++
++struct operation_perm {
++	u32 perms[8];
++};
++
++struct operation_decision {
++	u8 type;
++	u8 specified;
++	struct operation_perm *allowed;
++	struct operation_perm *auditallow;
++	struct operation_perm *dontaudit;
++};
++
++#define OPERATION_ALLOWED 1
++#define OPERATION_AUDITALLOW 2
++#define OPERATION_DONTAUDIT 4
++#define OPERATION_ALL (OPERATION_ALLOWED | OPERATION_AUDITALLOW |\
++			OPERATION_DONTAUDIT)
++struct operation {
++	u16 len;	/* length of operation decision chain */
++	u32 type[8];	/* 256 types */
++};
++
+ /* definitions of av_decision.flags */
+ #define AVD_FLAGS_PERMISSIVE	0x0001
+ 
+ void security_compute_av(u32 ssid, u32 tsid,
+-			 u16 tclass, struct av_decision *avd);
++			 u16 tclass, struct av_decision *avd,
++			 struct operation *ops);
++
++void security_compute_operation(u32 ssid, u32 tsid, u16 tclass,
++			 u8 type, struct operation_decision *od);
+ 
+ void security_compute_av_user(u32 ssid, u32 tsid,
+ 			     u16 tclass, struct av_decision *avd);
+diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c
+index a3dd9fa..dd7466c 100644
+--- a/security/selinux/ss/avtab.c
++++ b/security/selinux/ss/avtab.c
+@@ -24,6 +24,7 @@
+ #include "policydb.h"
+ 
+ static struct kmem_cache *avtab_node_cachep;
++static struct kmem_cache *avtab_operation_cachep;
+ 
+ static inline int avtab_hash(struct avtab_key *keyp, u16 mask)
+ {
+@@ -37,11 +38,24 @@ avtab_insert_node(struct avtab *h, int hvalue,
+ 		  struct avtab_key *key, struct avtab_datum *datum)
+ {
+ 	struct avtab_node *newnode;
++	struct avtab_operation *ops;
+ 	newnode = kmem_cache_zalloc(avtab_node_cachep, GFP_KERNEL);
+ 	if (newnode == NULL)
+ 		return NULL;
+ 	newnode->key = *key;
+-	newnode->datum = *datum;
++
++	if (key->specified & AVTAB_OP) {
++		ops = kmem_cache_zalloc(avtab_operation_cachep, GFP_KERNEL);
++		if (ops == NULL) {
++			kmem_cache_free(avtab_node_cachep, newnode);
++			return NULL;
++		}
++		*ops = *(datum->u.ops);
++		newnode->datum.u.ops = ops;
++	} else {
++		newnode->datum.u.data = datum->u.data;
++	}
++
+ 	if (prev) {
+ 		newnode->next = prev->next;
+ 		prev->next = newnode;
+@@ -70,8 +84,11 @@ static int avtab_insert(struct avtab *h, struct avtab_key *key, struct avtab_dat
+ 		if (key->source_type == cur->key.source_type &&
+ 		    key->target_type == cur->key.target_type &&
+ 		    key->target_class == cur->key.target_class &&
+-		    (specified & cur->key.specified))
++		    (specified & cur->key.specified)) {
++			if (specified & AVTAB_OPNUM)
++				break;
+ 			return -EEXIST;
++		}
+ 		if (key->source_type < cur->key.source_type)
+ 			break;
+ 		if (key->source_type == cur->key.source_type &&
+@@ -232,6 +249,9 @@ void avtab_destroy(struct avtab *h)
+ 		while (cur) {
+ 			temp = cur;
+ 			cur = cur->next;
++			if (temp->key.specified & AVTAB_OP)
++				kmem_cache_free(avtab_operation_cachep,
++							temp->datum.u.ops);
+ 			kmem_cache_free(avtab_node_cachep, temp);
+ 		}
+ 		h->htable[i] = NULL;
+@@ -320,7 +340,13 @@ static uint16_t spec_order[] = {
+ 	AVTAB_AUDITALLOW,
+ 	AVTAB_TRANSITION,
+ 	AVTAB_CHANGE,
+-	AVTAB_MEMBER
++	AVTAB_MEMBER,
++	AVTAB_OPNUM_ALLOWED,
++	AVTAB_OPNUM_AUDITALLOW,
++	AVTAB_OPNUM_DONTAUDIT,
++	AVTAB_OPTYPE_ALLOWED,
++	AVTAB_OPTYPE_AUDITALLOW,
++	AVTAB_OPTYPE_DONTAUDIT
+ };
+ 
+ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol,
+@@ -330,10 +356,11 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol,
+ {
+ 	__le16 buf16[4];
+ 	u16 enabled;
+-	__le32 buf32[7];
+ 	u32 items, items2, val, vers = pol->policyvers;
+ 	struct avtab_key key;
+ 	struct avtab_datum datum;
++	struct avtab_operation ops;
++	__le32 buf32[ARRAY_SIZE(ops.op.perms)];
+ 	int i, rc;
+ 	unsigned set;
+ 
+@@ -390,11 +417,15 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol,
+ 			printk(KERN_ERR "SELinux: avtab: entry has both access vectors and types\n");
+ 			return -EINVAL;
+ 		}
++		if (val & AVTAB_OP) {
++			printk(KERN_ERR "SELinux: avtab: entry has operations\n");
++			return -EINVAL;
++		}
+ 
+ 		for (i = 0; i < ARRAY_SIZE(spec_order); i++) {
+ 			if (val & spec_order[i]) {
+ 				key.specified = spec_order[i] | enabled;
+-				datum.data = le32_to_cpu(buf32[items++]);
++				datum.u.data = le32_to_cpu(buf32[items++]);
+ 				rc = insertf(a, &key, &datum, p);
+ 				if (rc)
+ 					return rc;
+@@ -413,7 +444,6 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol,
+ 		printk(KERN_ERR "SELinux: avtab: truncated entry\n");
+ 		return rc;
+ 	}
+-
+ 	items = 0;
+ 	key.source_type = le16_to_cpu(buf16[items++]);
+ 	key.target_type = le16_to_cpu(buf16[items++]);
+@@ -437,14 +467,32 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol,
+ 		return -EINVAL;
+ 	}
+ 
+-	rc = next_entry(buf32, fp, sizeof(u32));
+-	if (rc) {
+-		printk(KERN_ERR "SELinux: avtab: truncated entry\n");
+-		return rc;
++	if ((vers < POLICYDB_VERSION_IOCTL_OPERATIONS)
++			|| !(key.specified & AVTAB_OP)) {
++		rc = next_entry(buf32, fp, sizeof(u32));
++		if (rc) {
++			printk(KERN_ERR "SELinux: avtab: truncated entry\n");
++			return rc;
++		}
++		datum.u.data = le32_to_cpu(*buf32);
++	} else {
++		memset(&ops, 0, sizeof(struct avtab_operation));
++		rc = next_entry(&ops.type, fp, sizeof(u8));
++		if (rc) {
++			printk(KERN_ERR "SELinux: avtab: truncated entry\n");
++			return rc;
++		}
++		rc = next_entry(buf32, fp, sizeof(u32)*ARRAY_SIZE(ops.op.perms));
++		if (rc) {
++			printk(KERN_ERR "SELinux: avtab: truncated entry\n");
++			return rc;
++		}
++		for (i = 0; i < ARRAY_SIZE(ops.op.perms); i++)
++			ops.op.perms[i] = le32_to_cpu(buf32[i]);
++		datum.u.ops = &ops;
+ 	}
+-	datum.data = le32_to_cpu(*buf32);
+ 	if ((key.specified & AVTAB_TYPE) &&
+-	    !policydb_type_isvalid(pol, datum.data)) {
++	    !policydb_type_isvalid(pol, datum.u.data)) {
+ 		printk(KERN_ERR "SELinux: avtab: invalid type\n");
+ 		return -EINVAL;
+ 	}
+@@ -504,8 +552,9 @@ bad:
+ int avtab_write_item(struct policydb *p, struct avtab_node *cur, void *fp)
+ {
+ 	__le16 buf16[4];
+-	__le32 buf32[1];
++	__le32 buf32[ARRAY_SIZE(cur->datum.u.ops->op.perms)];
+ 	int rc;
++	unsigned int i;
+ 
+ 	buf16[0] = cpu_to_le16(cur->key.source_type);
+ 	buf16[1] = cpu_to_le16(cur->key.target_type);
+@@ -514,8 +563,19 @@ int avtab_write_item(struct policydb *p, struct avtab_node *cur, void *fp)
+ 	rc = put_entry(buf16, sizeof(u16), 4, fp);
+ 	if (rc)
+ 		return rc;
+-	buf32[0] = cpu_to_le32(cur->datum.data);
+-	rc = put_entry(buf32, sizeof(u32), 1, fp);
++
++	if (cur->key.specified & AVTAB_OP) {
++		rc = put_entry(&cur->datum.u.ops->type, sizeof(u8), 1, fp);
++		if (rc)
++			return rc;
++		for (i = 0; i < ARRAY_SIZE(cur->datum.u.ops->op.perms); i++)
++			buf32[i] = cpu_to_le32(cur->datum.u.ops->op.perms[i]);
++		rc = put_entry(buf32, sizeof(u32),
++				ARRAY_SIZE(cur->datum.u.ops->op.perms), fp);
++	} else {
++		buf32[0] = cpu_to_le32(cur->datum.u.data);
++		rc = put_entry(buf32, sizeof(u32), 1, fp);
++	}
+ 	if (rc)
+ 		return rc;
+ 	return 0;
+@@ -548,9 +608,13 @@ void avtab_cache_init(void)
+ 	avtab_node_cachep = kmem_cache_create("avtab_node",
+ 					      sizeof(struct avtab_node),
+ 					      0, SLAB_PANIC, NULL);
++	avtab_operation_cachep = kmem_cache_create("avtab_operation",
++					      sizeof(struct avtab_operation),
++					      0, SLAB_PANIC, NULL);
+ }
+ 
+ void avtab_cache_destroy(void)
+ {
+ 	kmem_cache_destroy(avtab_node_cachep);
++	kmem_cache_destroy(avtab_operation_cachep);
+ }
+diff --git a/security/selinux/ss/avtab.h b/security/selinux/ss/avtab.h
+index 63ce2f9..97acd6f 100644
+--- a/security/selinux/ss/avtab.h
++++ b/security/selinux/ss/avtab.h
+@@ -23,6 +23,8 @@
+ #ifndef _SS_AVTAB_H_
+ #define _SS_AVTAB_H_
+ 
++#include "security.h"
++
+ struct avtab_key {
+ 	u16 source_type;	/* source type */
+ 	u16 target_type;	/* target type */
+@@ -35,13 +37,34 @@ struct avtab_key {
+ #define AVTAB_MEMBER		0x0020
+ #define AVTAB_CHANGE		0x0040
+ #define AVTAB_TYPE		(AVTAB_TRANSITION | AVTAB_MEMBER | AVTAB_CHANGE)
++#define AVTAB_OPNUM_ALLOWED	0x0100
++#define AVTAB_OPNUM_AUDITALLOW	0x0200
++#define AVTAB_OPNUM_DONTAUDIT	0x0400
++#define AVTAB_OPNUM		(AVTAB_OPNUM_ALLOWED | \
++				AVTAB_OPNUM_AUDITALLOW | \
++				AVTAB_OPNUM_DONTAUDIT)
++#define AVTAB_OPTYPE_ALLOWED	0x1000
++#define AVTAB_OPTYPE_AUDITALLOW	0x2000
++#define AVTAB_OPTYPE_DONTAUDIT	0x4000
++#define AVTAB_OPTYPE		(AVTAB_OPTYPE_ALLOWED | \
++				AVTAB_OPTYPE_AUDITALLOW | \
++				AVTAB_OPTYPE_DONTAUDIT)
++#define AVTAB_OP		(AVTAB_OPNUM | AVTAB_OPTYPE)
+ #define AVTAB_ENABLED_OLD   0x80000000 /* reserved for used in cond_avtab */
+ #define AVTAB_ENABLED		0x8000 /* reserved for used in cond_avtab */
+ 	u16 specified;	/* what field is specified */
+ };
+ 
++struct avtab_operation {
++	u8 type;
++	struct operation_perm op;
++};
++
+ struct avtab_datum {
+-	u32 data; /* access vector or type value */
++	union {
++		u32 data; /* access vector or type value */
++		struct avtab_operation *ops; /* ioctl operations */
++	} u;
+ };
+ 
+ struct avtab_node {
+diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c
+index 62c6773..c4cd20a 100644
+--- a/security/selinux/ss/conditional.c
++++ b/security/selinux/ss/conditional.c
+@@ -15,6 +15,7 @@
+ 
+ #include "security.h"
+ #include "conditional.h"
++#include "services.h"
+ 
+ /*
+  * cond_evaluate_expr evaluates a conditional expr
+@@ -612,21 +613,39 @@ int cond_write_list(struct policydb *p, struct cond_node *list, void *fp)
+ 
+ 	return 0;
+ }
++
++void cond_compute_operation(struct avtab *ctab, struct avtab_key *key,
++		struct operation_decision *od)
++{
++	struct avtab_node *node;
++
++	if (!ctab || !key || !od)
++		return;
++
++	for (node = avtab_search_node(ctab, key); node;
++			node = avtab_search_node_next(node, key->specified)) {
++		if (node->key.specified & AVTAB_ENABLED)
++			services_compute_operation_num(od, node);
++	}
++	return;
++
++}
+ /* Determine whether additional permissions are granted by the conditional
+  * av table, and if so, add them to the result
+  */
+-void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decision *avd)
++void cond_compute_av(struct avtab *ctab, struct avtab_key *key,
++		struct av_decision *avd, struct operation *ops)
+ {
+ 	struct avtab_node *node;
+ 
+-	if (!ctab || !key || !avd)
++	if (!ctab || !key || !avd || !ops)
+ 		return;
+ 
+ 	for (node = avtab_search_node(ctab, key); node;
+ 				node = avtab_search_node_next(node, key->specified)) {
+ 		if ((u16)(AVTAB_ALLOWED|AVTAB_ENABLED) ==
+ 		    (node->key.specified & (AVTAB_ALLOWED|AVTAB_ENABLED)))
+-			avd->allowed |= node->datum.data;
++			avd->allowed |= node->datum.u.data;
+ 		if ((u16)(AVTAB_AUDITDENY|AVTAB_ENABLED) ==
+ 		    (node->key.specified & (AVTAB_AUDITDENY|AVTAB_ENABLED)))
+ 			/* Since a '0' in an auditdeny mask represents a
+@@ -634,10 +653,13 @@ void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decisi
+ 			 * the '&' operand to ensure that all '0's in the mask
+ 			 * are retained (much unlike the allow and auditallow cases).
+ 			 */
+-			avd->auditdeny &= node->datum.data;
++			avd->auditdeny &= node->datum.u.data;
+ 		if ((u16)(AVTAB_AUDITALLOW|AVTAB_ENABLED) ==
+ 		    (node->key.specified & (AVTAB_AUDITALLOW|AVTAB_ENABLED)))
+-			avd->auditallow |= node->datum.data;
++			avd->auditallow |= node->datum.u.data;
++		if ((node->key.specified & AVTAB_ENABLED) &&
++				(node->key.specified & AVTAB_OP))
++			services_compute_operation_type(ops, node);
+ 	}
+ 	return;
+ }
+diff --git a/security/selinux/ss/conditional.h b/security/selinux/ss/conditional.h
+index 4d1f874..80ee2bb 100644
+--- a/security/selinux/ss/conditional.h
++++ b/security/selinux/ss/conditional.h
+@@ -73,8 +73,10 @@ int cond_read_list(struct policydb *p, void *fp);
+ int cond_write_bool(void *key, void *datum, void *ptr);
+ int cond_write_list(struct policydb *p, struct cond_node *list, void *fp);
+ 
+-void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decision *avd);
+-
++void cond_compute_av(struct avtab *ctab, struct avtab_key *key,
++		struct av_decision *avd, struct operation *ops);
++void cond_compute_operation(struct avtab *ctab, struct avtab_key *key,
++		struct operation_decision *od);
+ int evaluate_cond_node(struct policydb *p, struct cond_node *node);
+ 
+ #endif /* _CONDITIONAL_H_ */
+diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
+index bc2a586..1c7daf2 100644
+--- a/security/selinux/ss/policydb.c
++++ b/security/selinux/ss/policydb.c
+@@ -148,6 +148,11 @@ static struct policydb_compat_info policydb_compat[] = {
+ 		.sym_num	= SYM_NUM,
+ 		.ocon_num	= OCON_NUM,
+ 	},
++	{
++		.version	= POLICYDB_VERSION_IOCTL_OPERATIONS,
++		.sym_num	= SYM_NUM,
++		.ocon_num	= OCON_NUM,
++	},
+ };
+ 
+ static struct policydb_compat_info *policydb_lookup_compat(int version)
+diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
+index a1d3944..4eba19f 100644
+--- a/security/selinux/ss/services.c
++++ b/security/selinux/ss/services.c
+@@ -93,9 +93,10 @@ static int context_struct_to_string(struct context *context, char **scontext,
+ 				    u32 *scontext_len);
+ 
+ static void context_struct_compute_av(struct context *scontext,
+-				      struct context *tcontext,
+-				      u16 tclass,
+-				      struct av_decision *avd);
++					struct context *tcontext,
++					u16 tclass,
++					struct av_decision *avd,
++					struct operation *ops);
+ 
+ struct selinux_mapping {
+ 	u16 value; /* policy value */
+@@ -565,7 +566,8 @@ static void type_attribute_bounds_av(struct context *scontext,
+ 		context_struct_compute_av(&lo_scontext,
+ 					  tcontext,
+ 					  tclass,
+-					  &lo_avd);
++					  &lo_avd,
++					  NULL);
+ 		if ((lo_avd.allowed & avd->allowed) == avd->allowed)
+ 			return;		/* no masked permission */
+ 		masked = ~lo_avd.allowed & avd->allowed;
+@@ -580,7 +582,8 @@ static void type_attribute_bounds_av(struct context *scontext,
+ 		context_struct_compute_av(scontext,
+ 					  &lo_tcontext,
+ 					  tclass,
+-					  &lo_avd);
++					  &lo_avd,
++					  NULL);
+ 		if ((lo_avd.allowed & avd->allowed) == avd->allowed)
+ 			return;		/* no masked permission */
+ 		masked = ~lo_avd.allowed & avd->allowed;
+@@ -596,7 +599,8 @@ static void type_attribute_bounds_av(struct context *scontext,
+ 		context_struct_compute_av(&lo_scontext,
+ 					  &lo_tcontext,
+ 					  tclass,
+-					  &lo_avd);
++					  &lo_avd,
++					  NULL);
+ 		if ((lo_avd.allowed & avd->allowed) == avd->allowed)
+ 			return;		/* no masked permission */
+ 		masked = ~lo_avd.allowed & avd->allowed;
+@@ -612,14 +616,39 @@ static void type_attribute_bounds_av(struct context *scontext,
+ 	}
+ }
+ 
++/* flag ioctl types that have operation permissions */
++void services_compute_operation_type(
++		struct operation *ops,
++		struct avtab_node *node)
++{
++	u8 type;
++	unsigned int i;
++
++	if (node->key.specified & AVTAB_OPTYPE) {
++		/* if allowing one or more complete types */
++		for (i = 0; i < ARRAY_SIZE(ops->type); i++)
++			ops->type[i] |= node->datum.u.ops->op.perms[i];
++	} else {
++		/* if allowing operations within a type */
++		type = node->datum.u.ops->type;
++		security_operation_set(ops->type, type);
++	}
++
++	/* If no ioctl commands are allowed, ignore auditallow and auditdeny */
++	if (node->key.specified & AVTAB_OPTYPE_ALLOWED ||
++			node->key.specified & AVTAB_OPNUM_ALLOWED)
++		ops->len = 1;
++}
++
+ /*
+- * Compute access vectors based on a context structure pair for
+- * the permissions in a particular class.
++ * Compute access vectors and operations ranges based on a context
++ * structure pair for the permissions in a particular class.
+  */
+ static void context_struct_compute_av(struct context *scontext,
+-				      struct context *tcontext,
+-				      u16 tclass,
+-				      struct av_decision *avd)
++					struct context *tcontext,
++					u16 tclass,
++					struct av_decision *avd,
++					struct operation *ops)
+ {
+ 	struct constraint_node *constraint;
+ 	struct role_allow *ra;
+@@ -633,6 +662,10 @@ static void context_struct_compute_av(struct context *scontext,
+ 	avd->allowed = 0;
+ 	avd->auditallow = 0;
+ 	avd->auditdeny = 0xffffffff;
++	if (ops) {
++		memset(&ops->type, 0, sizeof(ops->type));
++		ops->len = 0;
++	}
+ 
+ 	if (unlikely(!tclass || tclass > policydb.p_classes.nprim)) {
+ 		if (printk_ratelimit())
+@@ -647,7 +680,7 @@ static void context_struct_compute_av(struct context *scontext,
+ 	 * this permission check, then use it.
+ 	 */
+ 	avkey.target_class = tclass;
+-	avkey.specified = AVTAB_AV;
++	avkey.specified = AVTAB_AV | AVTAB_OP;
+ 	sattr = flex_array_get(policydb.type_attr_map_array, scontext->type - 1);
+ 	BUG_ON(!sattr);
+ 	tattr = flex_array_get(policydb.type_attr_map_array, tcontext->type - 1);
+@@ -660,15 +693,17 @@ static void context_struct_compute_av(struct context *scontext,
+ 			     node;
+ 			     node = avtab_search_node_next(node, avkey.specified)) {
+ 				if (node->key.specified == AVTAB_ALLOWED)
+-					avd->allowed |= node->datum.data;
++					avd->allowed |= node->datum.u.data;
+ 				else if (node->key.specified == AVTAB_AUDITALLOW)
+-					avd->auditallow |= node->datum.data;
++					avd->auditallow |= node->datum.u.data;
+ 				else if (node->key.specified == AVTAB_AUDITDENY)
+-					avd->auditdeny &= node->datum.data;
++					avd->auditdeny &= node->datum.u.data;
++				else if (ops && (node->key.specified & AVTAB_OP))
++					services_compute_operation_type(ops, node);
+ 			}
+ 
+ 			/* Check conditional av table for additional permissions */
+-			cond_compute_av(&policydb.te_cond_avtab, &avkey, avd);
++			cond_compute_av(&policydb.te_cond_avtab, &avkey, avd, ops);
+ 
+ 		}
+ 	}
+@@ -899,13 +934,138 @@ static void avd_init(struct av_decision *avd)
+ 	avd->flags = 0;
+ }
+ 
++void services_compute_operation_num(struct operation_decision *od,
++					struct avtab_node *node)
++{
++	unsigned int i;
+ 
++	if (node->key.specified & AVTAB_OPNUM) {
++		if (od->type != node->datum.u.ops->type)
++			return;
++	} else {
++		if (!security_operation_test(node->datum.u.ops->op.perms,
++					od->type))
++			return;
++	}
++
++	if (node->key.specified == AVTAB_OPTYPE_ALLOWED) {
++		od->specified |= OPERATION_ALLOWED;
++		memset(od->allowed->perms, 0xff,
++				sizeof(od->allowed->perms));
++	} else if (node->key.specified == AVTAB_OPTYPE_AUDITALLOW) {
++		od->specified |= OPERATION_AUDITALLOW;
++		memset(od->auditallow->perms, 0xff,
++				sizeof(od->auditallow->perms));
++	} else if (node->key.specified == AVTAB_OPTYPE_DONTAUDIT) {
++		od->specified |= OPERATION_DONTAUDIT;
++		memset(od->dontaudit->perms, 0xff,
++				sizeof(od->dontaudit->perms));
++	} else if (node->key.specified == AVTAB_OPNUM_ALLOWED) {
++		od->specified |= OPERATION_ALLOWED;
++		for (i = 0; i < ARRAY_SIZE(od->allowed->perms); i++)
++			od->allowed->perms[i] |=
++					node->datum.u.ops->op.perms[i];
++	} else if (node->key.specified == AVTAB_OPNUM_AUDITALLOW) {
++		od->specified |= OPERATION_AUDITALLOW;
++		for (i = 0; i < ARRAY_SIZE(od->auditallow->perms); i++)
++			od->auditallow->perms[i] |=
++					node->datum.u.ops->op.perms[i];
++	} else if (node->key.specified == AVTAB_OPNUM_DONTAUDIT) {
++		od->specified |= OPERATION_DONTAUDIT;
++		for (i = 0; i < ARRAY_SIZE(od->dontaudit->perms); i++)
++			od->dontaudit->perms[i] |=
++					node->datum.u.ops->op.perms[i];
++	} else {
++		BUG();
++	}
++}
++
++void security_compute_operation(u32 ssid,
++				u32 tsid,
++				u16 orig_tclass,
++				u8 type,
++				struct operation_decision *od)
++{
++	u16 tclass;
++	struct context *scontext, *tcontext;
++	struct avtab_key avkey;
++	struct avtab_node *node;
++	struct ebitmap *sattr, *tattr;
++	struct ebitmap_node *snode, *tnode;
++	unsigned int i, j;
++
++	od->type = type;
++	od->specified = 0;
++	memset(od->allowed->perms, 0, sizeof(od->allowed->perms));
++	memset(od->auditallow->perms, 0, sizeof(od->auditallow->perms));
++	memset(od->dontaudit->perms, 0, sizeof(od->dontaudit->perms));
++
++	read_lock(&policy_rwlock);
++	if (!ss_initialized)
++		goto allow;
++
++	scontext = sidtab_search(&sidtab, ssid);
++	if (!scontext) {
++		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
++		       __func__, ssid);
++		goto out;
++	}
++
++	tcontext = sidtab_search(&sidtab, tsid);
++	if (!tcontext) {
++		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
++		       __func__, tsid);
++		goto out;
++	}
++
++	tclass = unmap_class(orig_tclass);
++	if (unlikely(orig_tclass && !tclass)) {
++		if (policydb.allow_unknown)
++			goto allow;
++		goto out;
++	}
++
++
++	if (unlikely(!tclass || tclass > policydb.p_classes.nprim)) {
++		pr_warn_ratelimited("SELinux:  Invalid class %hu\n", tclass);
++		goto out;
++	}
++
++	avkey.target_class = tclass;
++	avkey.specified = AVTAB_OP;
++	sattr = flex_array_get(policydb.type_attr_map_array,
++				scontext->type - 1);
++	BUG_ON(!sattr);
++	tattr = flex_array_get(policydb.type_attr_map_array,
++				tcontext->type - 1);
++	BUG_ON(!tattr);
++	ebitmap_for_each_positive_bit(sattr, snode, i) {
++		ebitmap_for_each_positive_bit(tattr, tnode, j) {
++			avkey.source_type = i + 1;
++			avkey.target_type = j + 1;
++			for (node = avtab_search_node(&policydb.te_avtab, &avkey);
++			     node;
++			     node = avtab_search_node_next(node, avkey.specified))
++				services_compute_operation_num(od, node);
++
++			cond_compute_operation(&policydb.te_cond_avtab,
++						&avkey, od);
++		}
++	}
++out:
++	read_unlock(&policy_rwlock);
++	return;
++allow:
++	memset(od->allowed->perms, 0xff, sizeof(od->allowed->perms));
++	goto out;
++}
+ /**
+  * security_compute_av - Compute access vector decisions.
+  * @ssid: source security identifier
+  * @tsid: target security identifier
+  * @tclass: target security class
+  * @avd: access vector decisions
++ * @od: operation decisions
+  *
+  * Compute a set of access vector decisions based on the
+  * SID pair (@ssid, @tsid) for the permissions in @tclass.
+@@ -913,13 +1073,15 @@ static void avd_init(struct av_decision *avd)
+ void security_compute_av(u32 ssid,
+ 			 u32 tsid,
+ 			 u16 orig_tclass,
+-			 struct av_decision *avd)
++			 struct av_decision *avd,
++			 struct operation *ops)
+ {
+ 	u16 tclass;
+ 	struct context *scontext = NULL, *tcontext = NULL;
+ 
+ 	read_lock(&policy_rwlock);
+ 	avd_init(avd);
++	ops->len = 0;
+ 	if (!ss_initialized)
+ 		goto allow;
+ 
+@@ -947,7 +1109,7 @@ void security_compute_av(u32 ssid,
+ 			goto allow;
+ 		goto out;
+ 	}
+-	context_struct_compute_av(scontext, tcontext, tclass, avd);
++	context_struct_compute_av(scontext, tcontext, tclass, avd, ops);
+ 	map_decision(orig_tclass, avd, policydb.allow_unknown);
+ out:
+ 	read_unlock(&policy_rwlock);
+@@ -993,7 +1155,7 @@ void security_compute_av_user(u32 ssid,
+ 		goto out;
+ 	}
+ 
+-	context_struct_compute_av(scontext, tcontext, tclass, avd);
++	context_struct_compute_av(scontext, tcontext, tclass, avd, NULL);
+  out:
+ 	read_unlock(&policy_rwlock);
+ 	return;
+@@ -1515,7 +1677,7 @@ static int security_compute_sid(u32 ssid,
+ 
+ 	if (avdatum) {
+ 		/* Use the type from the type transition/member/change rule. */
+-		newcontext.type = avdatum->data;
++		newcontext.type = avdatum->u.data;
+ 	}
+ 
+ 	/* if we have a objname this is a file trans check so check those rules */
+diff --git a/security/selinux/ss/services.h b/security/selinux/ss/services.h
+index e8d907e..5697574 100644
+--- a/security/selinux/ss/services.h
++++ b/security/selinux/ss/services.h
+@@ -11,5 +11,11 @@
+ 
+ extern struct policydb policydb;
+ 
++void services_compute_operation_type(struct operation *ops,
++				struct avtab_node *node);
++
++void services_compute_operation_num(struct operation_decision *od,
++					struct avtab_node *node);
++
+ #endif	/* _SS_SERVICES_H_ */
+ 
diff --git a/br-ext-chip-hisilicon/board/unknown_unknown_hi3536cv100_unknown/config b/br-ext-chip-hisilicon/board/unknown_unknown_hi3536cv100_unknown/config
new file mode 100644
index 00000000..ff46642c
--- /dev/null
+++ b/br-ext-chip-hisilicon/board/unknown_unknown_hi3536cv100_unknown/config
@@ -0,0 +1,10 @@
+VENDOR=unknown
+MODEL=unknown
+FAMILY=hi3536cv100
+CHIP=hi3536cv100
+RAM_SIZE=1024M
+RAM_LINUX_SIZE=1024M
+RAM_MPP_SIZE=0M
+ROM_SIZE=?
+CMOS=unknown
+UBOOT_SIZE=256K
diff --git a/br-ext-chip-hisilicon/board/unknown_unknown_hi3536cv100_unknown/kernel/.gitkeep b/br-ext-chip-hisilicon/board/unknown_unknown_hi3536cv100_unknown/kernel/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/br-ext-chip-hisilicon/configs/unknown_unknown_hi3536cv100_openipc_defconfig b/br-ext-chip-hisilicon/configs/unknown_unknown_hi3536cv100_openipc_defconfig
new file mode 100644
index 00000000..7e77942c
--- /dev/null
+++ b/br-ext-chip-hisilicon/configs/unknown_unknown_hi3536cv100_openipc_defconfig
@@ -0,0 +1,95 @@
+# Architecture
+BR2_arm=y
+BR2_cortex_a7=y
+BR2_ARM_EABI=y
+BR2_ARM_FPU_NEON_VFPV4=y
+BR2_ARM_INSTRUCTIONS_THUMB2=y
+BR2_KERNEL_HEADERS_VERSION=y
+BR2_DEFAULT_KERNEL_VERSION="3.18.20"
+BR2_PACKAGE_HOST_LINUX_HEADERS_CUSTOM_3_18=y
+
+# Toolchain
+BR2_PER_PACKAGE_DIRECTORIES=y
+BR2_GCC_VERSION_7_X=y
+# BR2_TOOLCHAIN_USES_UCLIBC is not set
+# BR2_TOOLCHAIN_BUILDROOT_UCLIBC is not set
+# BR2_TOOLCHAIN_BUILDROOT_LIBC="uclibc"
+BR2_TOOLCHAIN_USES_MUSL=y
+BR2_TOOLCHAIN_BUILDROOT_MUSL=y
+BR2_TOOLCHAIN_BUILDROOT_LIBC="musl"
+# BR2_TOOLCHAIN_BUILDROOT_CXX is not set
+BR2_TOOLCHAIN_BUILDROOT_LOCALE=y
+BR2_TOOLCHAIN_BUILDROOT_USE_SSP=y
+
+# Kernel
+BR2_LINUX_KERNEL=y
+BR2_LINUX_KERNEL_CUSTOM_VERSION=y
+BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="3.18.20"
+BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y
+BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="$(BR2_EXTERNAL_HISILICON_PATH)/board/hi3536cv100/kernel/hi3536cv100.generic.config"
+BR2_LINUX_KERNEL_UIMAGE=y
+BR2_LINUX_KERNEL_UIMAGE_LOADADDR="0x80008000"
+BR2_LINUX_KERNEL_XZ=y
+BR2_LINUX_KERNEL_EXT_HISI_PATCHER=y
+BR2_LINUX_KERNEL_EXT_HISI_PATCHER_LIST="$(BR2_EXTERNAL_HISILICON_PATH)/board/hi3536cv100/kernel/patches/ $(BR2_EXTERNAL_HISILICON_PATH)/board/hi3536cv100/kernel/overlay"
+
+# Filesystem
+# BR2_TARGET_TZ_INFO is not set
+BR2_TARGET_ROOTFS_CPIO=y
+BR2_TARGET_ROOTFS_SQUASHFS=y
+BR2_TARGET_ROOTFS_SQUASHFS4_XZ=y
+BR2_ROOTFS_OVERLAY="$(TOPDIR)/../general/overlay"
+BR2_ROOTFS_POST_BUILD_SCRIPT="$(TOPDIR)/../scripts/executing_commands_for_$(BR2_TOOLCHAIN_BUILDROOT_LIBC).sh"
+
+# OpenIPC configuration
+BR2_TOOLCHAIN_BUILDROOT_VENDOR="openipc"
+BR2_TARGET_GENERIC_ISSUE="Welcome to OpenIPC v2.1"
+BR2_TARGET_GENERIC_HOSTNAME="openipc-hi3536cv100"
+BR2_GLOBAL_PATCH_DIR="$(TOPDIR)/../general/package/all-patches"
+
+# OpenIPC packages
+BR2_PACKAGE_BUSYBOX_CONFIG="$(TOPDIR)/../general/package/busybox/busybox.config"
+BR2_PACKAGE_DROPBEAR=y
+# BR2_PACKAGE_FDK_AAC_OPENIPC is not set
+BR2_PACKAGE_FWPRINTENV_OPENIPC=y
+BR2_PACKAGE_HASERL=y
+BR2_PACKAGE_HISI_GPIO=y
+BR2_PACKAGE_IPCTOOL=y
+BR2_PACKAGE_JSON_C=y
+BR2_PACKAGE_LAME_OPENIPC=y
+BR2_PACKAGE_LIBCURL_OPENIPC=y
+BR2_PACKAGE_LIBCURL_OPENIPC_CURL=y
+# BR2_PACKAGE_LIBCURL_OPENIPC_VERBOSE is not set
+# BR2_PACKAGE_LIBCURL_OPENIPC_PROXY_SUPPORT is not set
+# BR2_PACKAGE_LIBCURL_OPENIPC_COOKIES_SUPPORT is not set
+# BR2_PACKAGE_LIBCURL_OPENIPC_EXTRA_PROTOCOLS_FEATURES is not set
+BR2_PACKAGE_LIBCURL_OPENIPC_MBEDTLS=y
+BR2_PACKAGE_LIBEVENT_OPENIPC=y
+BR2_PACKAGE_LIBEVENT_OPENIPC_REMOVE_PYSCRIPT=y
+BR2_PACKAGE_LIBOGG_OPENIPC=y
+BR2_PACKAGE_LIBYAML=y
+BR2_PACKAGE_MBEDTLS_OPENIPC=y
+# BR2_PACKAGE_MBEDTLS_OPENIPC_PROGRAMS is not set
+# BR2_PACKAGE_MBEDTLS_OPENIPC_COMPRESSION is not set
+BR2_PACKAGE_MICROBE_WEB=y
+# BR2_PACKAGE_MINI_SNMPD is not set
+BR2_PACKAGE_OPUS_OPENIPC=y
+BR2_PACKAGE_OPUS_OPENIPC_FIXED_POINT=y
+# BR2_PACKAGE_SSHPASS is not set
+BR2_PACKAGE_UACME_OPENIPC=y
+BR2_PACKAGE_VTUND_OPENIPC=y
+BR2_PACKAGE_YAML_CLI=y
+
+# WiFi
+BR2_PACKAGE_WIRELESS_TOOLS=y
+BR2_PACKAGE_WPA_SUPPLICANT=y
+BR2_PACKAGE_WPA_SUPPLICANT_CLI=y
+BR2_PACKAGE_WPA_SUPPLICANT_NL80211=y
+BR2_PACKAGE_WPA_SUPPLICANT_PASSPHRASE=y
+BR2_PACKAGE_LINUX_FIRMWARE=y
+BR2_PACKAGE_LINUX_FIRMWARE_MEDIATEK_MT7601U=y
+# BR2_PACKAGE_RTL8188EU is not set
+
+# WIREGUARD
+BR2_PACKAGE_WIREGUARD_LINUX_COMPAT=y
+BR2_PACKAGE_WIREGUARD_TOOLS=y
diff --git a/building.sh b/building.sh
index 6a4e09f8..5cccbbe9 100755
--- a/building.sh
+++ b/building.sh
@@ -165,6 +165,11 @@ hi3518ev300() {
   fresh && make PLATFORM=hisilicon BOARD=unknown_unknown_${soc}_openipc all && rename
 }
 
+hi3536cv100() {
+  soc="hi3536cv100"
+  fresh && make PLATFORM=hisilicon BOARD=unknown_unknown_${soc}_openipc all && rename
+}
+
 hi3536dv100() {
   soc="hi3536dv100"
   fresh && make PLATFORM=hisilicon BOARD=unknown_unknown_${soc}_openipc all && rename